tx · EKwSsGao7Q9g5SQjyAqESnKtazdjozYyzr53WRrYrBWp

3NC3GcwFK9knYYKT2SRc7nWxc5SXc2aKBQ6:  -0.07500000 Waves

2023.01.24 17:05 [2419147] smart account 3NC3GcwFK9knYYKT2SRc7nWxc5SXc2aKBQ6 > SELF 0.00000000 Waves

{ "type": 13, "id": "EKwSsGao7Q9g5SQjyAqESnKtazdjozYyzr53WRrYrBWp", "fee": 7500000, "feeAssetId": null, "timestamp": 1674569206967, "version": 2, "chainId": 84, "sender": "3NC3GcwFK9knYYKT2SRc7nWxc5SXc2aKBQ6", "senderPublicKey": "5GAkpjTakesSgVm3A22kYMBvNpM8C1KpqWfyC7YyB84y", "proofs": [ "WVGuHfDbYr8P4A9Z24Yc1V7Qx93JGoYi4H2GuSNso5Bbzw9zNdExrertm1BySgeK5B5nnNLhj5YfE5D9YB3xLU7" ], "script": "base64:BgJxCAISABIAEgASABIDCgEBEgMKAQESDwoNAQEBAQEBAQEBAQEBARIVChMBAQEBAQEBCAgICAEBAQEBAQEBEgYKBAEBAQgSABIDCgEBEgUKAwEBBBIDCgEIEgASABIDCgEIEgMKAQESABIAEgASBAoCCAjEAQAJa19vcmFfa2V5AglrX29yYV9rZXkAD2tfb3JhX2Jsb2NrX2tleQIPa19vcmFfYmxvY2tfa2V5AA5rX29yYV9vcGVuX2tleQIOa19vcmFfb3Blbl9rZXkABWtfb3JhAgVrX29yYQAJa19iYWxhbmNlAglrX2JhbGFuY2UACmtfc2VxdWVuY2UCCmtfc2VxdWVuY2UADmtfcG9zaXRpb25TaXplAg5rX3Bvc2l0aW9uU2l6ZQAQa19wb3NpdGlvbk1hcmdpbgIQa19wb3NpdGlvbk1hcmdpbgAWa19wb3NpdGlvbk9wZW5Ob3Rpb25hbAIWa19wb3NpdGlvbk9wZW5Ob3Rpb25hbAAua19wb3NpdGlvbkxhc3RVcGRhdGVkQ3VtdWxhdGl2ZVByZW1pdW1GcmFjdGlvbgISa19wb3NpdGlvbkZyYWN0aW9uABJrX3Bvc2l0aW9uU2VxdWVuY2UCEmtfcG9zaXRpb25TZXF1ZW5jZQAPa19wb3NpdGlvbkFzc2V0Ag9rX3Bvc2l0aW9uQXNzZXQADWtfcG9zaXRpb25GZWUCDWtfcG9zaXRpb25GZWUAHmtfcG9zaXRpb25MYXN0VXBkYXRlZFRpbWVzdGFtcAITa19wb3NpdGlvblRpbWVzdGFtcAANa19pbml0aWFsaXplZAINa19pbml0aWFsaXplZAAIa19wYXVzZWQCCGtfcGF1c2VkAAtrX2Nsb3NlT25seQILa19jbG9zZU9ubHkABWtfZmVlAgVrX2ZlZQANa19yb2xsb3ZlckZlZQIOa19yb2xsb3Zlcl9mZWUAD2tfZnVuZGluZ1BlcmlvZAIPa19mdW5kaW5nUGVyaW9kABFrX2luaXRNYXJnaW5SYXRpbwIRa19pbml0TWFyZ2luUmF0aW8AGGtfbWFpbnRlbmFuY2VNYXJnaW5SYXRpbwIFa19tbXIAFWtfbGlxdWlkYXRpb25GZWVSYXRpbwIVa19saXF1aWRhdGlvbkZlZVJhdGlvABlrX3BhcnRpYWxMaXF1aWRhdGlvblJhdGlvAhZrX3BhcnRMaXF1aWRhdGlvblJhdGlvAA1rX3NwcmVhZExpbWl0Ag1rX3NwcmVhZExpbWl0ABBrX21heFByaWNlSW1wYWN0AhBrX21heFByaWNlSW1wYWN0ABBrX21heFByaWNlU3ByZWFkAhBrX21heFByaWNlU3ByZWFkABFrX21heE9wZW5Ob3Rpb25hbAIRa19tYXhPcGVuTm90aW9uYWwAFWtfZmVlVG9TdGFrZXJzUGVyY2VudAIVa19mZWVUb1N0YWtlcnNQZXJjZW50ABBrX21heE9yYWNsZURlbGF5AhBrX21heE9yYWNsZURlbGF5AA1rX2xhc3REYXRhU3RyAg1rX2xhc3REYXRhU3RyAA5rX2xhc3RNaW51dGVJZAIOa19sYXN0TWludXRlSWQAHWtfdHdhcERhdGFMYXN0Q3VtdWxhdGl2ZVByaWNlAh1rX3R3YXBEYXRhTGFzdEN1bXVsYXRpdmVQcmljZQATa190d2FwRGF0YUxhc3RQcmljZQITa190d2FwRGF0YUxhc3RQcmljZQAaa190d2FwRGF0YVByZXZpb3VzTWludXRlSWQCGmtfdHdhcERhdGFQcmV2aW91c01pbnV0ZUlkACVrX2xhdGVzdExvbmdDdW11bGF0aXZlUHJlbWl1bUZyYWN0aW9uAhtrX2xhdGVzdExvbmdQcmVtaXVtRnJhY3Rpb24AJmtfbGF0ZXN0U2hvcnRDdW11bGF0aXZlUHJlbWl1bUZyYWN0aW9uAhxrX2xhdGVzdFNob3J0UHJlbWl1bUZyYWN0aW9uABJrX25leHRGdW5kaW5nQmxvY2sCHmtfbmV4dEZ1bmRpbmdCbG9ja01pblRpbWVzdGFtcAARa19sb25nRnVuZGluZ1JhdGUCEWtfbG9uZ0Z1bmRpbmdSYXRlABJrX3Nob3J0RnVuZGluZ1JhdGUCEmtfc2hvcnRGdW5kaW5nUmF0ZQATa19xdW90ZUFzc2V0UmVzZXJ2ZQIIa19xdEFzdFIAEmtfYmFzZUFzc2V0UmVzZXJ2ZQIIa19ic0FzdFIAEmtfcXVvdGVBc3NldFdlaWdodAIIa19xdEFzdFcAEWtfYmFzZUFzc2V0V2VpZ2h0AghrX2JzQXN0VwATa190b3RhbFBvc2l0aW9uU2l6ZQITa190b3RhbFBvc2l0aW9uU2l6ZQAXa190b3RhbExvbmdQb3NpdGlvblNpemUCF2tfdG90YWxMb25nUG9zaXRpb25TaXplABhrX3RvdGFsU2hvcnRQb3NpdGlvblNpemUCGGtfdG90YWxTaG9ydFBvc2l0aW9uU2l6ZQAWa19vcGVuSW50ZXJlc3ROb3Rpb25hbAIWa19vcGVuSW50ZXJlc3ROb3Rpb25hbAATa19vcGVuSW50ZXJlc3RTaG9ydAITa19vcGVuSW50ZXJlc3RTaG9ydAASa19vcGVuSW50ZXJlc3RMb25nAhJrX29wZW5JbnRlcmVzdExvbmcAFGtfY29vcmRpbmF0b3JBZGRyZXNzAhRrX2Nvb3JkaW5hdG9yQWRkcmVzcwAPa192YXVsdF9hZGRyZXNzAg9rX3ZhdWx0X2FkZHJlc3MAD2tfYWRtaW5fYWRkcmVzcwIPa19hZG1pbl9hZGRyZXNzABJrX2FkbWluX3B1YmxpY19rZXkCEmtfYWRtaW5fcHVibGljX2tleQANa19xdW90ZV9hc3NldAINa19xdW90ZV9hc3NldAAPa19xdW90ZV9zdGFraW5nAg9rX3F1b3RlX3N0YWtpbmcAEWtfc3Rha2luZ19hZGRyZXNzAhFrX3N0YWtpbmdfYWRkcmVzcwAPa19taW5lcl9hZGRyZXNzAg9rX21pbmVyX2FkZHJlc3MAEGtfb3JkZXJzX2FkZHJlc3MCEGtfb3JkZXJzX2FkZHJlc3MAEmtfcmVmZXJyYWxfYWRkcmVzcwISa19yZWZlcnJhbF9hZGRyZXNzABJrX2V4Y2hhbmdlX2FkZHJlc3MCEmtfZXhjaGFuZ2VfYWRkcmVzcwAVa19uZnRfbWFuYWdlcl9hZGRyZXNzAhVrX25mdF9tYW5hZ2VyX2FkZHJlc3MBDnRvQ29tcG9zaXRlS2V5AgRfa2V5CF9hZGRyZXNzCQCsAgIJAKwCAgUEX2tleQIBXwUIX2FkZHJlc3MBC2Nvb3JkaW5hdG9yAAkBE3ZhbHVlT3JFcnJvck1lc3NhZ2UCCQCmCAEJARFAZXh0ck5hdGl2ZSgxMDUzKQIFBHRoaXMFFGtfY29vcmRpbmF0b3JBZGRyZXNzAhNDb29yZGluYXRvciBub3Qgc2V0AQxhZG1pbkFkZHJlc3MACQCmCAEJARFAZXh0ck5hdGl2ZSgxMDUzKQIJAQtjb29yZGluYXRvcgAFD2tfYWRtaW5fYWRkcmVzcwEOYWRtaW5QdWJsaWNLZXkACQDZBAEJARFAZXh0ck5hdGl2ZSgxMDUzKQIJAQtjb29yZGluYXRvcgAFEmtfYWRtaW5fcHVibGljX2tleQEKcXVvdGVBc3NldAAJANkEAQkBEUBleHRyTmF0aXZlKDEwNTMpAgkBC2Nvb3JkaW5hdG9yAAUNa19xdW90ZV9hc3NldAERcXVvdGVBc3NldFN0YWtpbmcACQETdmFsdWVPckVycm9yTWVzc2FnZQIJAKYIAQkBEUBleHRyTmF0aXZlKDEwNTMpAgkBC2Nvb3JkaW5hdG9yAAUPa19xdW90ZV9zdGFraW5nAhtRdW90ZSBhc3NldCBzdGFraW5nIG5vdCBzZXQBDnN0YWtpbmdBZGRyZXNzAAkBE3ZhbHVlT3JFcnJvck1lc3NhZ2UCCQCmCAEJARFAZXh0ck5hdGl2ZSgxMDUzKQIJAQtjb29yZGluYXRvcgAFEWtfc3Rha2luZ19hZGRyZXNzAg9TdGFraW5nIG5vdCBzZXQBDHZhdWx0QWRkcmVzcwAJARN2YWx1ZU9yRXJyb3JNZXNzYWdlAgkApggBCQERQGV4dHJOYXRpdmUoMTA1MykCCQELY29vcmRpbmF0b3IABQ9rX3ZhdWx0X2FkZHJlc3MCDVZhdWx0IG5vdCBzZXQBDG1pbmVyQWRkcmVzcwAJARN2YWx1ZU9yRXJyb3JNZXNzYWdlAgkApggBCQERQGV4dHJOYXRpdmUoMTA1MykCCQELY29vcmRpbmF0b3IABQ9rX21pbmVyX2FkZHJlc3MCDU1pbmVyIG5vdCBzZXQBDW9yZGVyc0FkZHJlc3MACQETdmFsdWVPckVycm9yTWVzc2FnZQIJAKYIAQkBEUBleHRyTmF0aXZlKDEwNTMpAgkBC2Nvb3JkaW5hdG9yAAUQa19vcmRlcnNfYWRkcmVzcwIOT3JkZXJzIG5vdCBzZXQBD3JlZmVycmFsQWRkcmVzcwAJARN2YWx1ZU9yRXJyb3JNZXNzYWdlAgkApggBCQERQGV4dHJOYXRpdmUoMTA1MykCCQELY29vcmRpbmF0b3IABRJrX3JlZmVycmFsX2FkZHJlc3MCEFJlZmVycmFsIG5vdCBzZXQBEW5mdE1hbmFnZXJBZGRyZXNzAAkBE3ZhbHVlT3JFcnJvck1lc3NhZ2UCCQCmCAEJARFAZXh0ck5hdGl2ZSgxMDUzKQIJAQtjb29yZGluYXRvcgAFFWtfbmZ0X21hbmFnZXJfYWRkcmVzcwITTkZUIE1hbmFnZXIgbm90IHNldAELc3dhcEFkZHJlc3MACQETdmFsdWVPckVycm9yTWVzc2FnZQIJAKYIAQkBE3ZhbHVlT3JFcnJvck1lc3NhZ2UCCQCdCAIJAQtjb29yZGluYXRvcgAFEmtfZXhjaGFuZ2VfYWRkcmVzcwIPTm8gc3dhcCBhZGRyZXNzAhRJbnZhbGlkIHN3YXAgYWRkcmVzcwANa190b2tlbl9wYXJhbQINa190b2tlbl9wYXJhbQAMa190b2tlbl90eXBlAgxrX3Rva2VuX3R5cGUAGEZFRV9SRURVQ1RJT05fVE9LRU5fVFlQRQINZmVlX3JlZHVjdGlvbgAIRElSX0xPTkcAAQAJRElSX1NIT1JUAAIADVRXQVBfSU5URVJWQUwADwAPT1JBQ0xFX0lOVEVSVkFMAA8AB1NFQ09ORFMA6AcAD0RFQ0lNQUxfTlVNQkVSUwAGAAxERUNJTUFMX1VOSVQJAGgCAAEJAGgCCQBoAgkAaAIJAGgCCQBoAgAKAAoACgAKAAoACgAPTUlOVVRFU19JTl9ZRUFSCQBoAgCgiiAFDERFQ0lNQUxfVU5JVAAHT05FX0RBWQkAaAIAgKMFBQxERUNJTUFMX1VOSVQACEFMTF9GRUVTAGQAD1BOTF9PUFRJT05fU1BPVAABABFQTkxfT1BUSU9OX09SQUNMRQACAQFzAQJfeAkArAICCQCkAwEFAl94AgEsAQRkaXZkAgJfeAJfeQkAbgQFAl94BQxERUNJTUFMX1VOSVQFAl95BQhIQUxGRVZFTgEEbXVsZAICX3gCX3kJAG4EBQJfeAUCX3kFDERFQ0lNQUxfVU5JVAUISEFMRkVWRU4BBXNxcnRkAQJfeAkBBHNxcnQEBQJfeAUPREVDSU1BTF9OVU1CRVJTBQ9ERUNJTUFMX05VTUJFUlMFCEhBTEZFVkVOAQRwb3dkAgJfeAJfeQkAbAYFAl94BQ9ERUNJTUFMX05VTUJFUlMFAl95BQ9ERUNJTUFMX05VTUJFUlMFD0RFQ0lNQUxfTlVNQkVSUwUISEFMRkVWRU4BBWJkaXZkAgJfeAJfeQkAvQIEBQJfeAkAtgIBBQxERUNJTUFMX1VOSVQFAl95BQhIQUxGRVZFTgEFYm11bGQCAl94Al95CQC9AgQFAl94BQJfeQkAtgIBBQxERUNJTUFMX1VOSVQFCEhBTEZFVkVOAQZic3FydGQBAl94CQEKc3FydEJpZ0ludAQFAl94BQ9ERUNJTUFMX05VTUJFUlMFD0RFQ0lNQUxfTlVNQkVSUwUISEFMRkVWRU4BBWJwb3dkAgJfeAJfeQkAdgYFAl94BQ9ERUNJTUFMX05VTUJFUlMFAl95BQ9ERUNJTUFMX05VTUJFUlMFD0RFQ0lNQUxfTlVNQkVSUwUISEFMRkVWRU4BA2FicwECX3gDCQBmAgUCX3gAAAUCX3gJAQEtAQUCX3gBBHZtYXgCAl94Al95AwkAZwIFAl94BQJfeQUCX3gFAl95AQlsaXN0VG9TdHIBBV9saXN0AwkAAAIJAJADAQUFX2xpc3QAAAIACQC5CQIFBV9saXN0AgEsAQlzdHJUb0xpc3QBBF9zdHIDCQAAAgUEX3N0cgIABQNuaWwJALUJAgUEX3N0cgIBLAELcHVzaFRvUXVldWUDBV9saXN0CF9tYXhTaXplBl92YWx1ZQMJAGYCCQCQAwEFBV9saXN0BQhfbWF4U2l6ZQkAzQgCCQDRCAIFBV9saXN0AAAFBl92YWx1ZQkAzQgCBQVfbGlzdAUGX3ZhbHVlAQNpbnQBAWsJARN2YWx1ZU9yRXJyb3JNZXNzYWdlAgkAmggCBQR0aGlzBQFrCQCsAgICDW5vIHZhbHVlIGZvciAFAWsBBWludE9yAgFrA2RlZgkBC3ZhbHVlT3JFbHNlAgkAmggCBQR0aGlzBQFrBQNkZWYBBHN0ckECCF9hZGRyZXNzBF9rZXkEA3ZhbAkBE3ZhbHVlT3JFcnJvck1lc3NhZ2UCCQCdCAIFCF9hZGRyZXNzBQRfa2V5CQCsAgICEU5vIHZhbHVlIGZvciBrZXkgBQRfa2V5BQN2YWwBBGludEECCF9hZGRyZXNzBF9rZXkEA3ZhbAkBE3ZhbHVlT3JFcnJvck1lc3NhZ2UCCQCaCAIFCF9hZGRyZXNzBQRfa2V5CQCsAgICEU5vIHZhbHVlIGZvciBrZXkgBQRfa2V5BQN2YWwBCGNiYWxhbmNlAAkBA2ludAEFCWtfYmFsYW5jZQEDZmVlAAkBA2ludAEFBWtfZmVlAQ9yb2xsb3ZlckZlZVJhdGUACQEDaW50AQUNa19yb2xsb3ZlckZlZQEPaW5pdE1hcmdpblJhdGlvAAkBA2ludAEFEWtfaW5pdE1hcmdpblJhdGlvAQZxdEFzdFIACQEDaW50AQUTa19xdW90ZUFzc2V0UmVzZXJ2ZQEGYnNBc3RSAAkBA2ludAEFEmtfYmFzZUFzc2V0UmVzZXJ2ZQEGcXRBc3RXAAkBBWludE9yAgUSa19xdW90ZUFzc2V0V2VpZ2h0BQxERUNJTUFMX1VOSVQBBmJzQXN0VwAJAQVpbnRPcgIFEWtfYmFzZUFzc2V0V2VpZ2h0BQxERUNJTUFMX1VOSVQBEXRvdGFsUG9zaXRpb25TaXplAAkBA2ludAEFE2tfdG90YWxQb3NpdGlvblNpemUBFG9wZW5JbnRlcmVzdE5vdGlvbmFsAAkBA2ludAEFFmtfb3BlbkludGVyZXN0Tm90aW9uYWwBEW9wZW5JbnRlcmVzdFNob3J0AAkBA2ludAEFE2tfb3BlbkludGVyZXN0U2hvcnQBEG9wZW5JbnRlcmVzdExvbmcACQEDaW50AQUSa19vcGVuSW50ZXJlc3RMb25nARluZXh0RnVuZGluZ0Jsb2NrVGltZXN0YW1wAAkBA2ludAEFEmtfbmV4dEZ1bmRpbmdCbG9jawEQZnVuZGluZ1BlcmlvZFJhdwAJAQNpbnQBBQ9rX2Z1bmRpbmdQZXJpb2QBFGZ1bmRpbmdQZXJpb2REZWNpbWFsAAkAaAIJARBmdW5kaW5nUGVyaW9kUmF3AAUMREVDSU1BTF9VTklUARRmdW5kaW5nUGVyaW9kU2Vjb25kcwAJAGgCCQEQZnVuZGluZ1BlcmlvZFJhdwAFB1NFQ09ORFMBFm1haW50ZW5hbmNlTWFyZ2luUmF0aW8ACQEDaW50AQUYa19tYWludGVuYW5jZU1hcmdpblJhdGlvARNsaXF1aWRhdGlvbkZlZVJhdGlvAAkBA2ludAEFFWtfbGlxdWlkYXRpb25GZWVSYXRpbwEXcGFydGlhbExpcXVpZGF0aW9uUmF0aW8ACQEDaW50AQUZa19wYXJ0aWFsTGlxdWlkYXRpb25SYXRpbwELc3ByZWFkTGltaXQACQEDaW50AQUNa19zcHJlYWRMaW1pdAEObWF4UHJpY2VJbXBhY3QACQEDaW50AQUQa19tYXhQcmljZUltcGFjdAEObWF4UHJpY2VTcHJlYWQACQEDaW50AQUQa19tYXhQcmljZVNwcmVhZAEPbWF4T3Blbk5vdGlvbmFsAAkBA2ludAEFEWtfbWF4T3Blbk5vdGlvbmFsASNsYXRlc3RMb25nQ3VtdWxhdGl2ZVByZW1pdW1GcmFjdGlvbgAJAQNpbnQBBSVrX2xhdGVzdExvbmdDdW11bGF0aXZlUHJlbWl1bUZyYWN0aW9uASRsYXRlc3RTaG9ydEN1bXVsYXRpdmVQcmVtaXVtRnJhY3Rpb24ACQEDaW50AQUma19sYXRlc3RTaG9ydEN1bXVsYXRpdmVQcmVtaXVtRnJhY3Rpb24BFnRvdGFsU2hvcnRQb3NpdGlvblNpemUACQEDaW50AQUYa190b3RhbFNob3J0UG9zaXRpb25TaXplARV0b3RhbExvbmdQb3NpdGlvblNpemUACQEDaW50AQUXa190b3RhbExvbmdQb3NpdGlvblNpemUBDGxhc3RTZXF1ZW5jZQAJAQVpbnRPcgIFCmtfc2VxdWVuY2UAAAETZmVlVG9TdGFrZXJzUGVyY2VudAAJAQNpbnQBBRVrX2ZlZVRvU3Rha2Vyc1BlcmNlbnQBDm1heE9yYWNsZURlbGF5AAkBA2ludAEFEGtfbWF4T3JhY2xlRGVsYXkBDWxhc3RUaW1lc3RhbXAACAUJbGFzdEJsb2NrCXRpbWVzdGFtcAEPZ2V0QWN0dWFsQ2FsbGVyAQFpCQELdmFsdWVPckVsc2UCCQCdCAIJAQ1vcmRlcnNBZGRyZXNzAAIIa19zZW5kZXIJAKUIAQgFAWkGY2FsbGVyARZyZXF1aXJlTW9yZU1hcmdpblJhdGlvAwxfbWFyZ2luUmF0aW8QX2Jhc2VNYXJnaW5SYXRpbxRfbGFyZ2VyVGhhbk9yRXF1YWxUbwQUcmVtYWluaW5nTWFyZ2luUmF0aW8JAGUCBQxfbWFyZ2luUmF0aW8FEF9iYXNlTWFyZ2luUmF0aW8DAwUUX2xhcmdlclRoYW5PckVxdWFsVG8JAGYCAAAFFHJlbWFpbmluZ01hcmdpblJhdGlvBwkAAgEJAKwCAgkArAICCQCsAgICEEludmFsaWQgbWFyZ2luOiAJAKQDAQUMX21hcmdpblJhdGlvAgMgPCAJAKQDAQUQX2Jhc2VNYXJnaW5SYXRpbwMDCQEBIQEFFF9sYXJnZXJUaGFuT3JFcXVhbFRvCQBnAgUUcmVtYWluaW5nTWFyZ2luUmF0aW8AAAcJAAIBCQCsAgIJAKwCAgkArAICAhBJbnZhbGlkIG1hcmdpbjogCQCkAwEFDF9tYXJnaW5SYXRpbwIDID4gCQCkAwEFEF9iYXNlTWFyZ2luUmF0aW8GAR9sYXRlc3RDdW11bGF0aXZlUHJlbWl1bUZyYWN0aW9uAQ1fcG9zaXRpb25TaXplAwkAAAIFDV9wb3NpdGlvblNpemUAAAkAAgECLFNob3VsZCBub3QgYmUgY2FsbGVkIHdpdGggX3Bvc2l0aW9uU2l6ZSA9PSAwAwkAZgIFDV9wb3NpdGlvblNpemUAAAkBI2xhdGVzdExvbmdDdW11bGF0aXZlUHJlbWl1bUZyYWN0aW9uAAkBJGxhdGVzdFNob3J0Q3VtdWxhdGl2ZVByZW1pdW1GcmFjdGlvbgABC2dldFBvc2l0aW9uAQdfdHJhZGVyBA9wb3NpdGlvblNpemVPcHQJAJoIAgUEdGhpcwkBDnRvQ29tcG9zaXRlS2V5AgUOa19wb3NpdGlvblNpemUFB190cmFkZXIEByRtYXRjaDAFD3Bvc2l0aW9uU2l6ZU9wdAMJAAECBQckbWF0Y2gwAgNJbnQEDHBvc2l0aW9uU2l6ZQUHJG1hdGNoMAkAlwoFBQxwb3NpdGlvblNpemUJARFAZXh0ck5hdGl2ZSgxMDUwKQIFBHRoaXMJAQ50b0NvbXBvc2l0ZUtleQIFEGtfcG9zaXRpb25NYXJnaW4FB190cmFkZXIJARFAZXh0ck5hdGl2ZSgxMDUwKQIFBHRoaXMJAQ50b0NvbXBvc2l0ZUtleQIFFmtfcG9zaXRpb25PcGVuTm90aW9uYWwFB190cmFkZXIJARFAZXh0ck5hdGl2ZSgxMDUwKQIFBHRoaXMJAQ50b0NvbXBvc2l0ZUtleQIFLmtfcG9zaXRpb25MYXN0VXBkYXRlZEN1bXVsYXRpdmVQcmVtaXVtRnJhY3Rpb24FB190cmFkZXIJARFAZXh0ck5hdGl2ZSgxMDUwKQIFBHRoaXMJAQ50b0NvbXBvc2l0ZUtleQIFHmtfcG9zaXRpb25MYXN0VXBkYXRlZFRpbWVzdGFtcAUHX3RyYWRlcgkAlwoFAAAAAAAAAAAAAAEQZ2V0UG9zaXRpb25Bc3NldAEHX3RyYWRlcgQQcG9zaXRpb25Bc3NldE9wdAkAnQgCBQR0aGlzCQEOdG9Db21wb3NpdGVLZXkCBQ9rX3Bvc2l0aW9uQXNzZXQFB190cmFkZXIEByRtYXRjaDAFEHBvc2l0aW9uQXNzZXRPcHQDCQABAgUHJG1hdGNoMAIGU3RyaW5nBA1wb3NpdGlvbkFzc2V0BQckbWF0Y2gwBQ1wb3NpdGlvbkFzc2V0CQDYBAEJAQpxdW90ZUFzc2V0AAEOZ2V0UG9zaXRpb25GZWUBB190cmFkZXIEDnBvc2l0aW9uRmVlT3B0CQCaCAIFBHRoaXMJAQ50b0NvbXBvc2l0ZUtleQIFDWtfcG9zaXRpb25GZWUFB190cmFkZXIEByRtYXRjaDAFDnBvc2l0aW9uRmVlT3B0AwkAAQIFByRtYXRjaDACA0ludAQLcG9zaXRpb25GZWUFByRtYXRjaDAFC3Bvc2l0aW9uRmVlCQEDZmVlAAETcmVxdWlyZU9wZW5Qb3NpdGlvbgEHX3RyYWRlcgMJAAACCAkBC2dldFBvc2l0aW9uAQUHX3RyYWRlcgJfMQAACQACAQIQTm8gb3BlbiBwb3NpdGlvbgYBC2luaXRpYWxpemVkAAkBC3ZhbHVlT3JFbHNlAgkAmwgCBQR0aGlzBQ1rX2luaXRpYWxpemVkBwEGcGF1c2VkAAkBC3ZhbHVlT3JFbHNlAgkAmwgCBQR0aGlzBQhrX3BhdXNlZAcBCWNsb3NlT25seQAJAQt2YWx1ZU9yRWxzZQIJAJsIAgUEdGhpcwULa19jbG9zZU9ubHkHAQ11cGRhdGVSZXNlcnZlAwZfaXNBZGQRX3F1b3RlQXNzZXRBbW91bnQQX2Jhc2VBc3NldEFtb3VudAMFBl9pc0FkZAQHbmV3QmFzZQkAZQIJAQZic0FzdFIABRBfYmFzZUFzc2V0QW1vdW50AwkAZwIAAAUHbmV3QmFzZQkAAgECKlR4IGxlYWQgdG8gYmFzZSBhc3NldCByZXNlcnZlIDw9IDAsIHJldmVydAkAlQoDCQBkAgkBBnF0QXN0UgAFEV9xdW90ZUFzc2V0QW1vdW50BQduZXdCYXNlCQBkAgkBEXRvdGFsUG9zaXRpb25TaXplAAUQX2Jhc2VBc3NldEFtb3VudAQIbmV3UXVvdGUJAGUCCQEGcXRBc3RSAAURX3F1b3RlQXNzZXRBbW91bnQDCQBnAgAABQhuZXdRdW90ZQkAAgECKlR4IGxlYWQgdG8gYmFzZSBxdW90ZSByZXNlcnZlIDw9IDAsIHJldmVydAkAlQoDBQhuZXdRdW90ZQkAZAIJAQZic0FzdFIABRBfYmFzZUFzc2V0QW1vdW50CQBlAgkBEXRvdGFsUG9zaXRpb25TaXplAAUQX2Jhc2VBc3NldEFtb3VudAENY2FsY0ludmFyaWFudAIHX3F0QXN0UgdfYnNBc3RSBAdicXRBc3RSCQC2AgEFB19xdEFzdFIEB2Jic0FzdFIJALYCAQUHX2JzQXN0UgkBBWJtdWxkAgUHYnF0QXN0UgUHYmJzQXN0UgEJc3dhcElucHV0AgZfaXNBZGQRX3F1b3RlQXNzZXRBbW91bnQEB19xdEFzdFIJAQZxdEFzdFIABAdfYnNBc3RSCQEGYnNBc3RSAAQHX3F0QXN0VwkBBnF0QXN0VwAEB19ic0FzdFcJAQZic0FzdFcABBhxdW90ZUFzc2V0QW1vdW50QWRqdXN0ZWQJAQRkaXZkAgURX3F1b3RlQXNzZXRBbW91bnQFB19xdEFzdFcEAWsJAQ1jYWxjSW52YXJpYW50AgUHX3F0QXN0UgUHX2JzQXN0UgQWcXVvdGVBc3NldFJlc2VydmVBZnRlcgMFBl9pc0FkZAkAZAIFB19xdEFzdFIFGHF1b3RlQXNzZXRBbW91bnRBZGp1c3RlZAkAZQIFB19xdEFzdFIFGHF1b3RlQXNzZXRBbW91bnRBZGp1c3RlZAQVYmFzZUFzc2V0UmVzZXJ2ZUFmdGVyCQCgAwEJAQViZGl2ZAIFAWsJALYCAQUWcXVvdGVBc3NldFJlc2VydmVBZnRlcgQYYW1vdW50QmFzZUFzc2V0Qm91Z2h0QWJzCQEDYWJzAQkAZQIFFWJhc2VBc3NldFJlc2VydmVBZnRlcgUHX2JzQXN0UgQVYW1vdW50QmFzZUFzc2V0Qm91Z2h0AwUGX2lzQWRkBRhhbW91bnRCYXNlQXNzZXRCb3VnaHRBYnMJAQEtAQUYYW1vdW50QmFzZUFzc2V0Qm91Z2h0QWJzBA0kdDAxNzAzNjE3MjA2CQENdXBkYXRlUmVzZXJ2ZQMFBl9pc0FkZAUYcXVvdGVBc3NldEFtb3VudEFkanVzdGVkBRhhbW91bnRCYXNlQXNzZXRCb3VnaHRBYnMEF3F1b3RlQXNzZXRSZXNlcnZlQWZ0ZXIxCAUNJHQwMTcwMzYxNzIwNgJfMQQWYmFzZUFzc2V0UmVzZXJ2ZUFmdGVyMQgFDSR0MDE3MDM2MTcyMDYCXzIEF3RvdGFsUG9zaXRpb25TaXplQWZ0ZXIxCAUNJHQwMTcwMzYxNzIwNgJfMwQLcHJpY2VCZWZvcmUJAQRkaXZkAgkBBG11bGQCBQdfcXRBc3RSBQdfcXRBc3RXCQEEbXVsZAIFB19ic0FzdFIFB19ic0FzdFcEC21hcmtldFByaWNlCQEEZGl2ZAIFEV9xdW90ZUFzc2V0QW1vdW50BRhhbW91bnRCYXNlQXNzZXRCb3VnaHRBYnMECXByaWNlRGlmZgkBA2FicwEJAGUCBQtwcmljZUJlZm9yZQULbWFya2V0UHJpY2UEC3ByaWNlSW1wYWN0CQBlAgUMREVDSU1BTF9VTklUCQEEZGl2ZAIFC3ByaWNlQmVmb3JlCQBkAgULcHJpY2VCZWZvcmUFCXByaWNlRGlmZgQTbWF4UHJpY2VJbXBhY3RWYWx1ZQkBDm1heFByaWNlSW1wYWN0AAMJAGYCBQtwcmljZUltcGFjdAUTbWF4UHJpY2VJbXBhY3RWYWx1ZQkAAgEJAKwCAgkArAICCQCsAgIJAKwCAgkArAICCQCsAgIJAKwCAgkArAICCQCsAgIJAKwCAgkArAICCQCsAgIJAKwCAgINUHJpY2UgaW1wYWN0IAkApAMBBQtwcmljZUltcGFjdAIUID4gbWF4IHByaWNlIGltcGFjdCAJAKQDAQUTbWF4UHJpY2VJbXBhY3RWYWx1ZQIVIGJlZm9yZSBxdW90ZSBhc3NldDogCQCkAwEFB19xdEFzdFICFCBiZWZvcmUgYmFzZSBhc3NldDogCQCkAwEFB19ic0FzdFICISBxdW90ZSBhc3NldCBhbW91bnQgdG8gZXhjaGFuZ2U6IAkApAMBBRFfcXVvdGVBc3NldEFtb3VudAIPIHByaWNlIGJlZm9yZTogCQCkAwEFC3ByaWNlQmVmb3JlAg4gbWFya2V0UHJpY2U6IAkApAMBBQttYXJrZXRQcmljZQkAlgoEBRVhbW91bnRCYXNlQXNzZXRCb3VnaHQFF3F1b3RlQXNzZXRSZXNlcnZlQWZ0ZXIxBRZiYXNlQXNzZXRSZXNlcnZlQWZ0ZXIxBRd0b3RhbFBvc2l0aW9uU2l6ZUFmdGVyMQEPY2FsY1JvbGxvdmVyRmVlAhJfb2xkUG9zaXRpb25NYXJnaW4gX29sZFBvc2l0aW9uTGFzdFVwZGF0ZWRUaW1lc3RhbXAED3Bvc2l0aW9uTWludXRlcwkAaAIJAGkCCQBpAgkAZQIJAQ1sYXN0VGltZXN0YW1wAAUgX29sZFBvc2l0aW9uTGFzdFVwZGF0ZWRUaW1lc3RhbXAA6AcAPAUMREVDSU1BTF9VTklUBAtyb2xsb3ZlckZlZQkBBGRpdmQCCQEEbXVsZAIJAQRtdWxkAgUSX29sZFBvc2l0aW9uTWFyZ2luBQ9wb3NpdGlvbk1pbnV0ZXMJAQ9yb2xsb3ZlckZlZVJhdGUABQ9NSU5VVEVTX0lOX1lFQVIFC3JvbGxvdmVyRmVlATBjYWxjUmVtYWluTWFyZ2luV2l0aEZ1bmRpbmdQYXltZW50QW5kUm9sbG92ZXJGZWUFEF9vbGRQb3NpdGlvblNpemUSX29sZFBvc2l0aW9uTWFyZ2luJV9vbGRQb3NpdGlvbkN1bXVsYXRpdmVQcmVtaXVtRnJhY3Rpb24gX29sZFBvc2l0aW9uTGFzdFVwZGF0ZWRUaW1lc3RhbXAMX21hcmdpbkRlbHRhBA5mdW5kaW5nUGF5bWVudAMJAQIhPQIFEF9vbGRQb3NpdGlvblNpemUAAAQgX2xhdGVzdEN1bXVsYXRpdmVQcmVtaXVtRnJhY3Rpb24JAR9sYXRlc3RDdW11bGF0aXZlUHJlbWl1bUZyYWN0aW9uAQUQX29sZFBvc2l0aW9uU2l6ZQkBBG11bGQCCQBlAgUgX2xhdGVzdEN1bXVsYXRpdmVQcmVtaXVtRnJhY3Rpb24FJV9vbGRQb3NpdGlvbkN1bXVsYXRpdmVQcmVtaXVtRnJhY3Rpb24FEF9vbGRQb3NpdGlvblNpemUAAAQLcm9sbG92ZXJGZWUJAQ9jYWxjUm9sbG92ZXJGZWUCBRJfb2xkUG9zaXRpb25NYXJnaW4FIF9vbGRQb3NpdGlvbkxhc3RVcGRhdGVkVGltZXN0YW1wBAxzaWduZWRNYXJnaW4JAGQCCQBlAgkAZQIFDF9tYXJnaW5EZWx0YQULcm9sbG92ZXJGZWUFDmZ1bmRpbmdQYXltZW50BRJfb2xkUG9zaXRpb25NYXJnaW4EDSR0MDE5NDYxMTk1ODgDCQBmAgAABQxzaWduZWRNYXJnaW4JAJQKAgAACQEDYWJzAQUMc2lnbmVkTWFyZ2luCQCUCgIJAQNhYnMBBQxzaWduZWRNYXJnaW4AAAQMcmVtYWluTWFyZ2luCAUNJHQwMTk0NjExOTU4OAJfMQQHYmFkRGVidAgFDSR0MDE5NDYxMTk1ODgCXzIJAJYKBAUMcmVtYWluTWFyZ2luBQdiYWREZWJ0BQ5mdW5kaW5nUGF5bWVudAULcm9sbG92ZXJGZWUBFnN3YXBPdXRwdXRXaXRoUmVzZXJ2ZXMHBl9pc0FkZBBfYmFzZUFzc2V0QW1vdW50FF9jaGVja01heFByaWNlSW1wYWN0El9xdW90ZUFzc2V0UmVzZXJ2ZRFfcXVvdGVBc3NldFdlaWdodBFfYmFzZUFzc2V0UmVzZXJ2ZRBfYmFzZUFzc2V0V2VpZ2h0BAtwcmljZUJlZm9yZQkBBGRpdmQCCQEEbXVsZAIFEl9xdW90ZUFzc2V0UmVzZXJ2ZQURX3F1b3RlQXNzZXRXZWlnaHQJAQRtdWxkAgURX2Jhc2VBc3NldFJlc2VydmUFEF9iYXNlQXNzZXRXZWlnaHQDCQAAAgUQX2Jhc2VBc3NldEFtb3VudAAACQACAQIZSW52YWxpZCBiYXNlIGFzc2V0IGFtb3VudAQBawkBDWNhbGNJbnZhcmlhbnQCBRJfcXVvdGVBc3NldFJlc2VydmUFEV9iYXNlQXNzZXRSZXNlcnZlBBhiYXNlQXNzZXRQb29sQW1vdW50QWZ0ZXIDBQZfaXNBZGQJAGQCBRFfYmFzZUFzc2V0UmVzZXJ2ZQUQX2Jhc2VBc3NldEFtb3VudAkAZQIFEV9iYXNlQXNzZXRSZXNlcnZlBRBfYmFzZUFzc2V0QW1vdW50BA9xdW90ZUFzc2V0QWZ0ZXIJAKADAQkBBWJkaXZkAgUBawkAtgIBBRhiYXNlQXNzZXRQb29sQW1vdW50QWZ0ZXIED3F1b3RlQXNzZXREZWx0YQkBA2FicwEJAGUCBQ9xdW90ZUFzc2V0QWZ0ZXIFEl9xdW90ZUFzc2V0UmVzZXJ2ZQQOcXVvdGVBc3NldFNvbGQJAQRtdWxkAgUPcXVvdGVBc3NldERlbHRhBRFfcXVvdGVBc3NldFdlaWdodAQTbWF4UHJpY2VJbXBhY3RWYWx1ZQkBDm1heFByaWNlSW1wYWN0AAQNJHQwMjA4NTAyMTAxMgkBDXVwZGF0ZVJlc2VydmUDCQEBIQEFBl9pc0FkZAUPcXVvdGVBc3NldERlbHRhBRBfYmFzZUFzc2V0QW1vdW50BBdxdW90ZUFzc2V0UmVzZXJ2ZUFmdGVyMQgFDSR0MDIwODUwMjEwMTICXzEEFmJhc2VBc3NldFJlc2VydmVBZnRlcjEIBQ0kdDAyMDg1MDIxMDEyAl8yBBd0b3RhbFBvc2l0aW9uU2l6ZUFmdGVyMQgFDSR0MDIwODUwMjEwMTICXzMEC21hcmtldFByaWNlCQEEZGl2ZAIFDnF1b3RlQXNzZXRTb2xkBRBfYmFzZUFzc2V0QW1vdW50BAlwcmljZURpZmYJAQNhYnMBCQBlAgULcHJpY2VCZWZvcmUFC21hcmtldFByaWNlBAtwcmljZUltcGFjdAkAZQIFDERFQ0lNQUxfVU5JVAkBBGRpdmQCBQtwcmljZUJlZm9yZQkAZAIFC3ByaWNlQmVmb3JlBQlwcmljZURpZmYDAwkAZgIFC3ByaWNlSW1wYWN0BRNtYXhQcmljZUltcGFjdFZhbHVlBRRfY2hlY2tNYXhQcmljZUltcGFjdAcJAAIBCQCsAgIJAKwCAgkArAICCQCsAgIJAKwCAgkArAICCQCsAgIJAKwCAgkArAICCQCsAgIJAKwCAgkArAICCQCsAgICDVByaWNlIGltcGFjdCAJAKQDAQULcHJpY2VJbXBhY3QCFCA+IG1heCBwcmljZSBpbXBhY3QgCQCkAwEFE21heFByaWNlSW1wYWN0VmFsdWUCFSBiZWZvcmUgcXVvdGUgYXNzZXQ6IAkApAMBBRJfcXVvdGVBc3NldFJlc2VydmUCFCBiZWZvcmUgYmFzZSBhc3NldDogCQCkAwEFEV9iYXNlQXNzZXRSZXNlcnZlAiAgYmFzZSBhc3NldCBhbW91bnQgdG8gZXhjaGFuZ2U6IAkApAMBBRBfYmFzZUFzc2V0QW1vdW50Ag8gcHJpY2UgYmVmb3JlOiAJAKQDAQULcHJpY2VCZWZvcmUCDyBtYXJrZXQgcHJpY2U6IAkApAMBBQttYXJrZXRQcmljZQkAmQoHBQ5xdW90ZUFzc2V0U29sZAUXcXVvdGVBc3NldFJlc2VydmVBZnRlcjEFFmJhc2VBc3NldFJlc2VydmVBZnRlcjEFF3RvdGFsUG9zaXRpb25TaXplQWZ0ZXIxCQBlAgkBFXRvdGFsTG9uZ1Bvc2l0aW9uU2l6ZQADBQZfaXNBZGQJAQNhYnMBBRBfYmFzZUFzc2V0QW1vdW50AAAJAGUCCQEWdG90YWxTaG9ydFBvc2l0aW9uU2l6ZQADCQEBIQEFBl9pc0FkZAkBA2FicwEFEF9iYXNlQXNzZXRBbW91bnQAAAULcHJpY2VJbXBhY3QBCnN3YXBPdXRwdXQDBl9pc0FkZBBfYmFzZUFzc2V0QW1vdW50FF9jaGVja01heFByaWNlSW1wYWN0CQEWc3dhcE91dHB1dFdpdGhSZXNlcnZlcwcFBl9pc0FkZAUQX2Jhc2VBc3NldEFtb3VudAUUX2NoZWNrTWF4UHJpY2VJbXBhY3QJAQZxdEFzdFIACQEGcXRBc3RXAAkBBmJzQXN0UgAJAQZic0FzdFcAAQ5nZXRPcmFjbGVQcmljZQAEBm9yYWNsZQkBE3ZhbHVlT3JFcnJvck1lc3NhZ2UCCQCmCAEJARN2YWx1ZU9yRXJyb3JNZXNzYWdlAgkAnQgCBQR0aGlzBQVrX29yYQkArAICAgpObyB2YWx1ZTogBQVrX29yYQIABAhwcmljZUtleQkBC3ZhbHVlT3JFbHNlAgkAnQgCBQR0aGlzBQlrX29yYV9rZXkJAKwCAgIKTm8gdmFsdWU6IAUJa19vcmFfa2V5BAlsYXN0VmFsdWUJARN2YWx1ZU9yRXJyb3JNZXNzYWdlAgkAmggCBQZvcmFjbGUFCHByaWNlS2V5CQCsAgIJAKwCAgkArAICAiJDYW4gbm90IGdldCBvcmFjbGUgcHJpY2UuIE9yYWNsZTogCQClCAEFBm9yYWNsZQIGIGtleTogBQhwcmljZUtleQQIYmxvY2tLZXkJAQt2YWx1ZU9yRWxzZQIJAJ0IAgUEdGhpcwUPa19vcmFfYmxvY2tfa2V5AgADCQECIT0CBQhibG9ja0tleQIABAxjdXJyZW50QmxvY2sIBQlsYXN0QmxvY2sGaGVpZ2h0BA9sYXN0T3JhY2xlQmxvY2sJARN2YWx1ZU9yRXJyb3JNZXNzYWdlAgkAmggCBQZvcmFjbGUFCGJsb2NrS2V5CQCsAgIJAKwCAgkArAICAiJDYW4gbm90IGdldCBvcmFjbGUgYmxvY2suIE9yYWNsZTogCQClCAEFBm9yYWNsZQIGIGtleTogBQhibG9ja0tleQMJAGYCCQBlAgUMY3VycmVudEJsb2NrBQ9sYXN0T3JhY2xlQmxvY2sJAQ5tYXhPcmFjbGVEZWxheQAJAAIBCQCsAgIJAKwCAgkArAICAiZPcmFjbGUgc3RhbGUgZGF0YS4gTGFzdCBvcmFjbGUgYmxvY2s6IAkApAMBBQ9sYXN0T3JhY2xlQmxvY2sCECBjdXJyZW50IGJsb2NrOiAJAKQDAQUMY3VycmVudEJsb2NrBQlsYXN0VmFsdWUFCWxhc3RWYWx1ZQEOaXNNYXJrZXRDbG9zZWQABAZvcmFjbGUJARN2YWx1ZU9yRXJyb3JNZXNzYWdlAgkApggBCQERQGV4dHJOYXRpdmUoMTA1MykCBQR0aGlzBQVrX29yYQIABAdvcGVuS2V5CQELdmFsdWVPckVsc2UCCQCdCAIFBHRoaXMFDmtfb3JhX29wZW5fa2V5AgADCQECIT0CBQdvcGVuS2V5AgAEBmlzT3BlbgkBE3ZhbHVlT3JFcnJvck1lc3NhZ2UCCQCbCAIFBm9yYWNsZQUHb3BlbktleQkArAICCQCsAgIJAKwCAgIrQ2FuIG5vdCBnZXQgb3JhY2xlIGlzIG9wZW4vY2xvc2VkLiBPcmFjbGU6IAkApQgBBQZvcmFjbGUCBiBrZXk6IAUHb3BlbktleQkBASEBBQZpc09wZW4HAQxhYnNQcmljZURpZmYFDF9vcmFjbGVQcmljZRJfcXVvdGVBc3NldFJlc2VydmURX2Jhc2VBc3NldFJlc2VydmUHX3F0QXN0VwdfYnNBc3RXBApwcmljZUFmdGVyCQEEZGl2ZAIJAQRtdWxkAgUSX3F1b3RlQXNzZXRSZXNlcnZlBQdfcXRBc3RXCQEEbXVsZAIFEV9iYXNlQXNzZXRSZXNlcnZlBQdfYnNBc3RXBAxhdmVyYWdlUHJpY2UJAQRkaXZkAgkAZAIFDF9vcmFjbGVQcmljZQUKcHJpY2VBZnRlcgkAaAIAAgUMREVDSU1BTF9VTklUBAxhYnNQcmljZURpZmYJAQRkaXZkAgkBA2FicwEJAGUCBQxfb3JhY2xlUHJpY2UFCnByaWNlQWZ0ZXIFDGF2ZXJhZ2VQcmljZQUMYWJzUHJpY2VEaWZmARlyZXF1aXJlTm90T3ZlclNwcmVhZExpbWl0AhJfcXVvdGVBc3NldFJlc2VydmURX2Jhc2VBc3NldFJlc2VydmUEC29yYWNsZVByaWNlCQEOZ2V0T3JhY2xlUHJpY2UABAdfcXRBc3RXCQEGcXRBc3RXAAQHX2JzQXN0VwkBBmJzQXN0VwAEEmFic1ByaWNlRGlmZkJlZm9yZQkBDGFic1ByaWNlRGlmZgUFC29yYWNsZVByaWNlCQEGcXRBc3RSAAkBBmJzQXN0UgAFB19xdEFzdFcFB19ic0FzdFcEEWFic1ByaWNlRGlmZkFmdGVyCQEMYWJzUHJpY2VEaWZmBQULb3JhY2xlUHJpY2UFEl9xdW90ZUFzc2V0UmVzZXJ2ZQURX2Jhc2VBc3NldFJlc2VydmUFB19xdEFzdFcFB19ic0FzdFcDAwkAZgIFEWFic1ByaWNlRGlmZkFmdGVyCQEObWF4UHJpY2VTcHJlYWQACQBmAgURYWJzUHJpY2VEaWZmQWZ0ZXIFEmFic1ByaWNlRGlmZkJlZm9yZQcJAAIBCQCsAgIJAKwCAgkArAICAg1QcmljZSBzcHJlYWQgCQCkAwEFEWFic1ByaWNlRGlmZkFmdGVyAhQgPiBtYXggcHJpY2Ugc3ByZWFkIAkApAMBCQEObWF4UHJpY2VTcHJlYWQABgEdcmVxdWlyZU5vdE92ZXJNYXhPcGVuTm90aW9uYWwCEV9sb25nT3Blbk5vdGlvbmFsEl9zaG9ydE9wZW5Ob3Rpb25hbAQQX21heE9wZW5Ob3Rpb25hbAkBD21heE9wZW5Ob3Rpb25hbAADCQBmAgURX2xvbmdPcGVuTm90aW9uYWwFEF9tYXhPcGVuTm90aW9uYWwJAAIBCQCsAgIJAKwCAgkArAICAhNMb25nIG9wZW4gbm90aW9uYWwgCQCkAwEFEV9sb25nT3Blbk5vdGlvbmFsAhUgPiBtYXggb3BlbiBub3Rpb25hbCAJAKQDAQUQX21heE9wZW5Ob3Rpb25hbAMJAGYCBRJfc2hvcnRPcGVuTm90aW9uYWwFEF9tYXhPcGVuTm90aW9uYWwJAAIBCQCsAgIJAKwCAgkArAICAhRTaG9ydCBvcGVuIG5vdGlvbmFsIAkApAMBBRJfc2hvcnRPcGVuTm90aW9uYWwCFSA+IG1heCBvcGVuIG5vdGlvbmFsIAkApAMBBRBfbWF4T3Blbk5vdGlvbmFsBgEMZ2V0U3BvdFByaWNlAAQSX3F1b3RlQXNzZXRSZXNlcnZlCQEGcXRBc3RSAAQRX2Jhc2VBc3NldFJlc2VydmUJAQZic0FzdFIABAdfcXRBc3RXCQEGcXRBc3RXAAQHX2JzQXN0VwkBBmJzQXN0VwAJAQRkaXZkAgkBBG11bGQCBRJfcXVvdGVBc3NldFJlc2VydmUFB19xdEFzdFcJAQRtdWxkAgURX2Jhc2VBc3NldFJlc2VydmUFB19ic0FzdFcBFmlzT3ZlckZsdWN0dWF0aW9uTGltaXQABAtvcmFjbGVQcmljZQkBDmdldE9yYWNsZVByaWNlAAQMY3VycmVudFByaWNlCQEMZ2V0U3BvdFByaWNlAAkAZgIJAQRkaXZkAgkBA2FicwEJAGUCBQtvcmFjbGVQcmljZQUMY3VycmVudFByaWNlBQtvcmFjbGVQcmljZQkBC3NwcmVhZExpbWl0AAEfZ2V0UG9zaXRpb25BZGp1c3RlZE9wZW5Ob3Rpb25hbAYNX3Bvc2l0aW9uU2l6ZQdfb3B0aW9uEl9xdW90ZUFzc2V0UmVzZXJ2ZRFfcXVvdGVBc3NldFdlaWdodBFfYmFzZUFzc2V0UmVzZXJ2ZRBfYmFzZUFzc2V0V2VpZ2h0BA9wb3NpdGlvblNpemVBYnMJAQNhYnMBBQ1fcG9zaXRpb25TaXplBAdpc1Nob3J0CQBmAgAABQ1fcG9zaXRpb25TaXplBBBwb3NpdGlvbk5vdGlvbmFsAwkAAAIFB19vcHRpb24FD1BOTF9PUFRJT05fU1BPVAQTb3V0UG9zaXRpb25Ob3Rpb25hbAgJARZzd2FwT3V0cHV0V2l0aFJlc2VydmVzBwkBASEBBQdpc1Nob3J0BQ9wb3NpdGlvblNpemVBYnMHBRJfcXVvdGVBc3NldFJlc2VydmUFEV9xdW90ZUFzc2V0V2VpZ2h0BRFfYmFzZUFzc2V0UmVzZXJ2ZQUQX2Jhc2VBc3NldFdlaWdodAJfMQUTb3V0UG9zaXRpb25Ob3Rpb25hbAkBBG11bGQCBQ9wb3NpdGlvblNpemVBYnMJAQ5nZXRPcmFjbGVQcmljZQAFEHBvc2l0aW9uTm90aW9uYWwBK2dldFBvc2l0aW9uTm90aW9uYWxBbmRVbnJlYWxpemVkUG5sQnlWYWx1ZXMHDV9wb3NpdGlvblNpemUVX3Bvc2l0aW9uT3Blbk5vdGlvbmFsEl9xdW90ZUFzc2V0UmVzZXJ2ZRFfcXVvdGVBc3NldFdlaWdodBFfYmFzZUFzc2V0UmVzZXJ2ZRBfYmFzZUFzc2V0V2VpZ2h0B19vcHRpb24DCQAAAgUNX3Bvc2l0aW9uU2l6ZQAACQACAQIVSW52YWxpZCBwb3NpdGlvbiBzaXplBAdpc1Nob3J0CQBmAgAABQ1fcG9zaXRpb25TaXplBBBwb3NpdGlvbk5vdGlvbmFsCQEfZ2V0UG9zaXRpb25BZGp1c3RlZE9wZW5Ob3Rpb25hbAYFDV9wb3NpdGlvblNpemUFB19vcHRpb24FEl9xdW90ZUFzc2V0UmVzZXJ2ZQURX3F1b3RlQXNzZXRXZWlnaHQFEV9iYXNlQXNzZXRSZXNlcnZlBRBfYmFzZUFzc2V0V2VpZ2h0BA11bnJlYWxpemVkUG5sAwUHaXNTaG9ydAkAZQIFFV9wb3NpdGlvbk9wZW5Ob3Rpb25hbAUQcG9zaXRpb25Ob3Rpb25hbAkAZQIFEHBvc2l0aW9uTm90aW9uYWwFFV9wb3NpdGlvbk9wZW5Ob3Rpb25hbAkAlAoCBRBwb3NpdGlvbk5vdGlvbmFsBQ11bnJlYWxpemVkUG5sASNnZXRQb3NpdGlvbk5vdGlvbmFsQW5kVW5yZWFsaXplZFBubAIHX3RyYWRlcgdfb3B0aW9uBA0kdDAyODU3NzI4NzA1CQELZ2V0UG9zaXRpb24BBQdfdHJhZGVyBAxwb3NpdGlvblNpemUIBQ0kdDAyODU3NzI4NzA1Al8xBA5wb3NpdGlvbk1hcmdpbggFDSR0MDI4NTc3Mjg3MDUCXzIEFHBvc2l0aW9uT3Blbk5vdGlvbmFsCAUNJHQwMjg1NzcyODcwNQJfMwQRcG9zaXRpb25Mc3RVcGRDUEYIBQ0kdDAyODU3NzI4NzA1Al80CQErZ2V0UG9zaXRpb25Ob3Rpb25hbEFuZFVucmVhbGl6ZWRQbmxCeVZhbHVlcwcFDHBvc2l0aW9uU2l6ZQUUcG9zaXRpb25PcGVuTm90aW9uYWwJAQZxdEFzdFIACQEGcXRBc3RXAAkBBmJzQXN0UgAJAQZic0FzdFcABQdfb3B0aW9uAQ9jYWxjTWFyZ2luUmF0aW8DDV9yZW1haW5NYXJnaW4IX2JhZERlYnQRX3Bvc2l0aW9uTm90aW9uYWwJAQRkaXZkAgkAZQIFDV9yZW1haW5NYXJnaW4FCF9iYWREZWJ0BRFfcG9zaXRpb25Ob3Rpb25hbAEWZ2V0TWFyZ2luUmF0aW9CeU9wdGlvbgIHX3RyYWRlcgdfb3B0aW9uBA0kdDAyOTIyMDI5MzYxCQELZ2V0UG9zaXRpb24BBQdfdHJhZGVyBAxwb3NpdGlvblNpemUIBQ0kdDAyOTIyMDI5MzYxAl8xBA5wb3NpdGlvbk1hcmdpbggFDSR0MDI5MjIwMjkzNjECXzIEA3BvbggFDSR0MDI5MjIwMjkzNjECXzMEFnBvc2l0aW9uTGFzdFVwZGF0ZWRDUEYIBQ0kdDAyOTIyMDI5MzYxAl80BBFwb3NpdGlvblRpbWVzdGFtcAgFDSR0MDI5MjIwMjkzNjECXzUEDSR0MDI5MzY3Mjk0NjAJASNnZXRQb3NpdGlvbk5vdGlvbmFsQW5kVW5yZWFsaXplZFBubAIFB190cmFkZXIFB19vcHRpb24EEHBvc2l0aW9uTm90aW9uYWwIBQ0kdDAyOTM2NzI5NDYwAl8xBA11bnJlYWxpemVkUG5sCAUNJHQwMjkzNjcyOTQ2MAJfMgQNJHQwMjk0NjUyOTY3NwkBMGNhbGNSZW1haW5NYXJnaW5XaXRoRnVuZGluZ1BheW1lbnRBbmRSb2xsb3ZlckZlZQUFDHBvc2l0aW9uU2l6ZQUOcG9zaXRpb25NYXJnaW4FFnBvc2l0aW9uTGFzdFVwZGF0ZWRDUEYFEXBvc2l0aW9uVGltZXN0YW1wBQ11bnJlYWxpemVkUG5sBAxyZW1haW5NYXJnaW4IBQ0kdDAyOTQ2NTI5Njc3Al8xBAdiYWREZWJ0CAUNJHQwMjk0NjUyOTY3NwJfMgkBD2NhbGNNYXJnaW5SYXRpbwMFDHJlbWFpbk1hcmdpbgUHYmFkRGVidAUQcG9zaXRpb25Ob3Rpb25hbAEOZ2V0TWFyZ2luUmF0aW8BB190cmFkZXIJARZnZXRNYXJnaW5SYXRpb0J5T3B0aW9uAgUHX3RyYWRlcgUPUE5MX09QVElPTl9TUE9UARtnZXRQYXJ0aWFsTGlxdWlkYXRpb25BbW91bnQCB190cmFkZXINX3Bvc2l0aW9uU2l6ZQQMbWF4aW11bVJhdGlvCQEEdm1heAIJARdwYXJ0aWFsTGlxdWlkYXRpb25SYXRpbwAJAGUCBQxERUNJTUFMX1VOSVQJAQRkaXZkAgkBDmdldE1hcmdpblJhdGlvAQUHX3RyYWRlcgkBFm1haW50ZW5hbmNlTWFyZ2luUmF0aW8ABBhtYXhFeGNoYW5nZWRQb3NpdGlvblNpemUJAQRtdWxkAgkBA2FicwEFDV9wb3NpdGlvblNpemUFDG1heGltdW1SYXRpbwQKc3dhcFJlc3VsdAkBCnN3YXBPdXRwdXQDCQBmAgUNX3Bvc2l0aW9uU2l6ZQAABRhtYXhFeGNoYW5nZWRQb3NpdGlvblNpemUHBBxtYXhFeGNoYW5nZWRRdW90ZUFzc2V0QW1vdW50CAUKc3dhcFJlc3VsdAJfMQQLcHJpY2VJbXBhY3QIBQpzd2FwUmVzdWx0Al83AwkAZgIJAQ5tYXhQcmljZUltcGFjdAAFC3ByaWNlSW1wYWN0BRhtYXhFeGNoYW5nZWRQb3NpdGlvblNpemUJAQRtdWxkAgkBA2FicwEFDV9wb3NpdGlvblNpemUJARdwYXJ0aWFsTGlxdWlkYXRpb25SYXRpbwABFWludGVybmFsQ2xvc2VQb3NpdGlvbgYHX3RyYWRlcgVfc2l6ZQRfZmVlFF9taW5RdW90ZUFzc2V0QW1vdW50DF9hZGRUb01hcmdpbhRfY2hlY2tNYXhQcmljZUltcGFjdAQNJHQwMzA3MjEzMDg3NwkBC2dldFBvc2l0aW9uAQUHX3RyYWRlcgQPb2xkUG9zaXRpb25TaXplCAUNJHQwMzA3MjEzMDg3NwJfMQQRb2xkUG9zaXRpb25NYXJnaW4IBQ0kdDAzMDcyMTMwODc3Al8yBBdvbGRQb3NpdGlvbk9wZW5Ob3Rpb25hbAgFDSR0MDMwNzIxMzA4NzcCXzMEFG9sZFBvc2l0aW9uTHN0VXBkQ1BGCAUNJHQwMzA3MjEzMDg3NwJfNAQUb2xkUG9zaXRpb25UaW1lc3RhbXAIBQ0kdDAzMDcyMTMwODc3Al81BA5pc0xvbmdQb3NpdGlvbgkAZgIFD29sZFBvc2l0aW9uU2l6ZQAABBJhYnNPbGRQb3NpdGlvblNpemUJAQNhYnMBBQ9vbGRQb3NpdGlvblNpemUDAwkAZwIFEmFic09sZFBvc2l0aW9uU2l6ZQUFX3NpemUJAGYCBQVfc2l6ZQAABwQOaXNQYXJ0aWFsQ2xvc2UJAGYCBRJhYnNPbGRQb3NpdGlvblNpemUFBV9zaXplBA0kdDAzMTE2OTMxNjIwCQEKc3dhcE91dHB1dAMJAGYCBQ9vbGRQb3NpdGlvblNpemUAAAUFX3NpemUFFF9jaGVja01heFByaWNlSW1wYWN0BBlleGNoYW5nZWRRdW90ZUFzc2V0QW1vdW50CAUNJHQwMzExNjkzMTYyMAJfMQQWcXVvdGVBc3NldFJlc2VydmVBZnRlcggFDSR0MDMxMTY5MzE2MjACXzIEFWJhc2VBc3NldFJlc2VydmVBZnRlcggFDSR0MDMxMTY5MzE2MjACXzMEFnRvdGFsUG9zaXRpb25TaXplQWZ0ZXIIBQ0kdDAzMTE2OTMxNjIwAl80BBVleGNoYW5nZWRQb3NpdGlvblNpemUDCQBmAgUPb2xkUG9zaXRpb25TaXplAAAJAQEtAQUFX3NpemUFBV9zaXplBA0kdDAzMTgzNTMyMDQyCQEjZ2V0UG9zaXRpb25Ob3Rpb25hbEFuZFVucmVhbGl6ZWRQbmwCBQdfdHJhZGVyBQ9QTkxfT1BUSU9OX1NQT1QEE29sZFBvc2l0aW9uTm90aW9uYWwIBQ0kdDAzMTgzNTMyMDQyAl8xBA11bnJlYWxpemVkUG5sCAUNJHQwMzE4MzUzMjA0MgJfMgQNcmVhbGl6ZWRSYXRpbwkBBGRpdmQCCQEDYWJzAQUVZXhjaGFuZ2VkUG9zaXRpb25TaXplBRJhYnNPbGRQb3NpdGlvblNpemUEC3JlYWxpemVkUG5sCQEEbXVsZAIFDXVucmVhbGl6ZWRQbmwFDXJlYWxpemVkUmF0aW8EDSR0MDMyMzgzMzI2MjkJATBjYWxjUmVtYWluTWFyZ2luV2l0aEZ1bmRpbmdQYXltZW50QW5kUm9sbG92ZXJGZWUFBQ9vbGRQb3NpdGlvblNpemUFEW9sZFBvc2l0aW9uTWFyZ2luBRRvbGRQb3NpdGlvbkxzdFVwZENQRgUUb2xkUG9zaXRpb25UaW1lc3RhbXAFDXVucmVhbGl6ZWRQbmwEEnJlbWFpbk1hcmdpbkJlZm9yZQgFDSR0MDMyMzgzMzI2MjkCXzEEAngxCAUNJHQwMzIzODMzMjYyOQJfMgQCeDIIBQ0kdDAzMjM4MzMyNjI5Al8zBAtyb2xsb3ZlckZlZQgFDSR0MDMyMzgzMzI2MjkCXzQED3Bvc2l0aW9uQmFkRGVidAgJATBjYWxjUmVtYWluTWFyZ2luV2l0aEZ1bmRpbmdQYXltZW50QW5kUm9sbG92ZXJGZWUFBQ9vbGRQb3NpdGlvblNpemUFEW9sZFBvc2l0aW9uTWFyZ2luBRRvbGRQb3NpdGlvbkxzdFVwZENQRgUUb2xkUG9zaXRpb25UaW1lc3RhbXAFC3JlYWxpemVkUG5sAl8yBBByZWFsaXplZENsb3NlRmVlCQEEbXVsZAIJAQRtdWxkAgUTb2xkUG9zaXRpb25Ob3Rpb25hbAUNcmVhbGl6ZWRSYXRpbwUEX2ZlZQQSdW5yZWFsaXplZFBubEFmdGVyCQBlAgUNdW5yZWFsaXplZFBubAULcmVhbGl6ZWRQbmwEEnJlbWFpbk9wZW5Ob3Rpb25hbAMJAGYCBQ9vbGRQb3NpdGlvblNpemUAAAkAZQIJAGUCBRNvbGRQb3NpdGlvbk5vdGlvbmFsBRlleGNoYW5nZWRRdW90ZUFzc2V0QW1vdW50BRJ1bnJlYWxpemVkUG5sQWZ0ZXIJAGUCCQBkAgUSdW5yZWFsaXplZFBubEFmdGVyBRNvbGRQb3NpdGlvbk5vdGlvbmFsBRlleGNoYW5nZWRRdW90ZUFzc2V0QW1vdW50BA9uZXdQb3NpdGlvblNpemUJAGQCBQ9vbGRQb3NpdGlvblNpemUFFWV4Y2hhbmdlZFBvc2l0aW9uU2l6ZQQNJHQwMzQwMzUzNDQyMQMJAAACBQ9uZXdQb3NpdGlvblNpemUAAAkAlAoCAAAAAAkAlAoCCQEDYWJzAQUScmVtYWluT3Blbk5vdGlvbmFsCQEfbGF0ZXN0Q3VtdWxhdGl2ZVByZW1pdW1GcmFjdGlvbgEFD25ld1Bvc2l0aW9uU2l6ZQQXbmV3UG9zaXRpb25PcGVuTm90aW9uYWwIBQ0kdDAzNDAzNTM0NDIxAl8xBBRuZXdQb3NpdGlvbkxzdFVwZENQRggFDSR0MDM0MDM1MzQ0MjECXzIEEW9wZW5Ob3Rpb25hbERlbHRhCQBlAgUXb2xkUG9zaXRpb25PcGVuTm90aW9uYWwFF25ld1Bvc2l0aW9uT3Blbk5vdGlvbmFsBAttYXJnaW5SYXRpbwkBFmdldE1hcmdpblJhdGlvQnlPcHRpb24CBQdfdHJhZGVyBQ9QTkxfT1BUSU9OX1NQT1QEHm5ld1Bvc2l0aW9uTWFyZ2luV2l0aFNhbWVSYXRpbwMJAGYCBQ9vbGRQb3NpdGlvblNpemUAAAkAZQIJAQRtdWxkAgkAZAIFF25ld1Bvc2l0aW9uT3Blbk5vdGlvbmFsBRJ1bnJlYWxpemVkUG5sQWZ0ZXIFC21hcmdpblJhdGlvBRJ1bnJlYWxpemVkUG5sQWZ0ZXIJAGUCCQEEbXVsZAIJAGUCBRduZXdQb3NpdGlvbk9wZW5Ob3Rpb25hbAUSdW5yZWFsaXplZFBubEFmdGVyBQttYXJnaW5SYXRpbwUSdW5yZWFsaXplZFBubEFmdGVyBBFtYXJnaW5Ub1RyYWRlclJhdwkAZQIJAGUCBRJyZW1haW5NYXJnaW5CZWZvcmUJAGQCBR5uZXdQb3NpdGlvbk1hcmdpbldpdGhTYW1lUmF0aW8FEnVucmVhbGl6ZWRQbmxBZnRlcgUQcmVhbGl6ZWRDbG9zZUZlZQQObWFyZ2luVG9UcmFkZXIDCQBmAgAABRFtYXJnaW5Ub1RyYWRlclJhdwkAAgECN0ludmFsaWQgaW50ZXJuYWxDbG9zZVBvc2l0aW9uIHBhcmFtczogdW5hYmxlIHRvIHBheSBmZWUFEW1hcmdpblRvVHJhZGVyUmF3BBFuZXdQb3NpdGlvbk1hcmdpbgMFDF9hZGRUb01hcmdpbgkAZAIFHm5ld1Bvc2l0aW9uTWFyZ2luV2l0aFNhbWVSYXRpbwUObWFyZ2luVG9UcmFkZXIFHm5ld1Bvc2l0aW9uTWFyZ2luV2l0aFNhbWVSYXRpbwMDCQECIT0CBRRfbWluUXVvdGVBc3NldEFtb3VudAAACQBmAgUUX21pblF1b3RlQXNzZXRBbW91bnQFGWV4Y2hhbmdlZFF1b3RlQXNzZXRBbW91bnQHCQACAQkArAICCQCsAgIJAKwCAgINTGltaXQgZXJyb3I6IAkApAMBBRlleGNoYW5nZWRRdW90ZUFzc2V0QW1vdW50AgMgPCAJAKQDAQUUX21pblF1b3RlQXNzZXRBbW91bnQJAKMKEQUPbmV3UG9zaXRpb25TaXplBRFuZXdQb3NpdGlvbk1hcmdpbgUXbmV3UG9zaXRpb25PcGVuTm90aW9uYWwFFG5ld1Bvc2l0aW9uTHN0VXBkQ1BGBQ9wb3NpdGlvbkJhZERlYnQFC3JlYWxpemVkUG5sAwMFDF9hZGRUb01hcmdpbgUOaXNQYXJ0aWFsQ2xvc2UHAAAFDm1hcmdpblRvVHJhZGVyBRZxdW90ZUFzc2V0UmVzZXJ2ZUFmdGVyBRViYXNlQXNzZXRSZXNlcnZlQWZ0ZXIFFnRvdGFsUG9zaXRpb25TaXplQWZ0ZXIJAGUCCQEUb3BlbkludGVyZXN0Tm90aW9uYWwABRFvcGVuTm90aW9uYWxEZWx0YQkAZQIJARV0b3RhbExvbmdQb3NpdGlvblNpemUAAwUOaXNMb25nUG9zaXRpb24JAQNhYnMBBRVleGNoYW5nZWRQb3NpdGlvblNpemUAAAkAZQIJARZ0b3RhbFNob3J0UG9zaXRpb25TaXplAAMJAQEhAQUOaXNMb25nUG9zaXRpb24JAQNhYnMBBRVleGNoYW5nZWRQb3NpdGlvblNpemUAAAkAZQIJARBvcGVuSW50ZXJlc3RMb25nAAMFDmlzTG9uZ1Bvc2l0aW9uBRFvcGVuTm90aW9uYWxEZWx0YQAACQBlAgkBEW9wZW5JbnRlcmVzdFNob3J0AAMJAQEhAQUOaXNMb25nUG9zaXRpb24FEW9wZW5Ob3Rpb25hbERlbHRhAAAJAGQCBRByZWFsaXplZENsb3NlRmVlBQtyb2xsb3ZlckZlZQUZZXhjaGFuZ2VkUXVvdGVBc3NldEFtb3VudAkAAgECO0ludmFsaWQgaW50ZXJuYWxDbG9zZVBvc2l0aW9uIHBhcmFtczogaW52YWxpZCBwb3NpdGlvbiBzaXplARBnZXRUd2FwU3BvdFByaWNlAAQIbWludXRlSWQJAGkCCQBpAgkBDWxhc3RUaW1lc3RhbXAAAOgHADwEDXN0YXJ0TWludXRlSWQJAGUCBQhtaW51dGVJZAUNVFdBUF9JTlRFUlZBTAQHbGlzdFN0cgkBC3ZhbHVlT3JFbHNlAgkAnQgCBQR0aGlzBQ1rX2xhc3REYXRhU3RyAgAEBGxpc3QJALUJAgUHbGlzdFN0cgIBLAoBCGZpbHRlckZuAgthY2N1bXVsYXRvcgRuZXh0AwkAZwIFDXN0YXJ0TWludXRlSWQJARN2YWx1ZU9yRXJyb3JNZXNzYWdlAgkAtgkBBQRuZXh0CQCsAgICH2dldFR3YXBTcG90UHJpY2U6IGludmFsaWQgaW50OiAFB2xpc3RTdHIJAM0IAgULYWNjdW11bGF0b3IJAQ1wYXJzZUludFZhbHVlAQUEbmV4dAULYWNjdW11bGF0b3IEBWxpc3RGCgACJGwFBGxpc3QKAAIkcwkAkAMBBQIkbAoABSRhY2MwBQNuaWwKAQUkZjBfMQICJGECJGkDCQBnAgUCJGkFAiRzBQIkYQkBCGZpbHRlckZuAgUCJGEJAJEDAgUCJGwFAiRpCgEFJGYwXzICAiRhAiRpAwkAZwIFAiRpBQIkcwUCJGEJAAIBAhRMaXN0IHNpemUgZXhjZWVkcyAyMAkBBSRmMF8yAgkBBSRmMF8xAgkBBSRmMF8xAgkBBSRmMF8xAgkBBSRmMF8xAgkBBSRmMF8xAgkBBSRmMF8xAgkBBSRmMF8xAgkBBSRmMF8xAgkBBSRmMF8xAgkBBSRmMF8xAgkBBSRmMF8xAgkBBSRmMF8xAgkBBSRmMF8xAgkBBSRmMF8xAgkBBSRmMF8xAgkBBSRmMF8xAgkBBSRmMF8xAgkBBSRmMF8xAgkBBSRmMF8xAgkBBSRmMF8xAgUFJGFjYzAAAAABAAIAAwAEAAUABgAHAAgACQAKAAsADAANAA4ADwAQABEAEgATABQECG1heEluZGV4AwkAZgIJAJADAQUFbGlzdEYAAAkAlgMBBQVsaXN0RgkBE3ZhbHVlT3JFcnJvck1lc3NhZ2UCCQC2CQEJAJEDAgUEbGlzdAAACQCsAgICH2dldFR3YXBTcG90UHJpY2U6IGludmFsaWQgaW50OiAFB2xpc3RTdHIEDGxhc3RNaW51dGVJZAkBC3ZhbHVlT3JFbHNlAgkAmggCBQR0aGlzBQ5rX2xhc3RNaW51dGVJZAAABBZlbmRMYXN0Q3VtdWxhdGl2ZVByaWNlCQELdmFsdWVPckVsc2UCCQCaCAIFBHRoaXMJAKwCAgkArAICBR1rX3R3YXBEYXRhTGFzdEN1bXVsYXRpdmVQcmljZQIBXwkApAMBBQxsYXN0TWludXRlSWQAAAQMZW5kTGFzdFByaWNlCQELdmFsdWVPckVsc2UCCQCaCAIFBHRoaXMJAKwCAgkArAICBRNrX3R3YXBEYXRhTGFzdFByaWNlAgFfCQCkAwEFDGxhc3RNaW51dGVJZAAABBJub3dDdW11bGF0aXZlUHJpY2UJAGQCBRZlbmRMYXN0Q3VtdWxhdGl2ZVByaWNlCQBoAgkAZQIFCG1pbnV0ZUlkBQxsYXN0TWludXRlSWQFDGVuZExhc3RQcmljZQQYc3RhcnRMYXN0Q3VtdWxhdGl2ZVByaWNlCQELdmFsdWVPckVsc2UCCQCaCAIFBHRoaXMJAKwCAgkArAICBR1rX3R3YXBEYXRhTGFzdEN1bXVsYXRpdmVQcmljZQIBXwkApAMBBQhtYXhJbmRleAAABA5zdGFydExhc3RQcmljZQkBC3ZhbHVlT3JFbHNlAgkAmggCBQR0aGlzCQCsAgIJAKwCAgUTa190d2FwRGF0YUxhc3RQcmljZQIBXwkApAMBBQhtYXhJbmRleAAABBRzdGFydEN1bXVsYXRpdmVQcmljZQkAZAIFGHN0YXJ0TGFzdEN1bXVsYXRpdmVQcmljZQkAaAIJAGUCBQ1zdGFydE1pbnV0ZUlkBQhtYXhJbmRleAUOc3RhcnRMYXN0UHJpY2UJAGkCCQBlAgUSbm93Q3VtdWxhdGl2ZVByaWNlBRRzdGFydEN1bXVsYXRpdmVQcmljZQUNVFdBUF9JTlRFUlZBTAETZ2V0VGVybWluYWxBbW1TdGF0ZQAEDV9wb3NpdGlvblNpemUJARF0b3RhbFBvc2l0aW9uU2l6ZQADCQAAAgUNX3Bvc2l0aW9uU2l6ZQAACQCUCgIJAQZxdEFzdFIACQEGYnNBc3RSAAQJZGlyZWN0aW9uCQBmAgUNX3Bvc2l0aW9uU2l6ZQAABA0kdDAzOTAyNDM5MjAzCQEKc3dhcE91dHB1dAMFCWRpcmVjdGlvbgkBA2FicwEFDV9wb3NpdGlvblNpemUHBBVjdXJyZW50TmV0TWFya2V0VmFsdWUIBQ0kdDAzOTAyNDM5MjAzAl8xBBl0ZXJtaW5hbFF1b3RlQXNzZXRSZXNlcnZlCAUNJHQwMzkwMjQzOTIwMwJfMgQYdGVybWluYWxCYXNlQXNzZXRSZXNlcnZlCAUNJHQwMzkwMjQzOTIwMwJfMwkAlAoCBRl0ZXJtaW5hbFF1b3RlQXNzZXRSZXNlcnZlBRh0ZXJtaW5hbEJhc2VBc3NldFJlc2VydmUBE2dldFF1b3RlQXNzZXRXZWlnaHQEEGJhc2VBc3NldFJlc2VydmURdG90YWxQb3NpdGlvblNpemURcXVvdGVBc3NldFJlc2VydmULdGFyZ2V0UHJpY2UEAWIJALYCAQUQYmFzZUFzc2V0UmVzZXJ2ZQQCc3oJALYCAQURdG90YWxQb3NpdGlvblNpemUEAXEJALYCAQURcXVvdGVBc3NldFJlc2VydmUEAXAJALYCAQULdGFyZ2V0UHJpY2UEAWsJAQVibXVsZAIFAXEFAWIEBG5ld0IJALcCAgUBYgUCc3oEBG5ld1EJAQViZGl2ZAIFAWsFBG5ld0IEAXoJAQViZGl2ZAIFBG5ld1EFBG5ld0IEBnJlc3VsdAkBBWJkaXZkAgUBcAUBegkAoAMBBQZyZXN1bHQBFGdldFN5bmNUZXJtaW5hbFByaWNlAw5fdGVybWluYWxQcmljZQdfcXRBc3RSB19ic0FzdFIEDV9wb3NpdGlvblNpemUJARF0b3RhbFBvc2l0aW9uU2l6ZQADCQAAAgUNX3Bvc2l0aW9uU2l6ZQAABAluZXdRdEFzdFcJAQRkaXZkAgkBBG11bGQCBQ5fdGVybWluYWxQcmljZQUHX2JzQXN0UgUHX3F0QXN0UgkAlQoDBQluZXdRdEFzdFcFDERFQ0lNQUxfVU5JVAAABAlkaXJlY3Rpb24JAGYCBQ1fcG9zaXRpb25TaXplAAAEFWN1cnJlbnROZXRNYXJrZXRWYWx1ZQgJAQpzd2FwT3V0cHV0AwUJZGlyZWN0aW9uCQEDYWJzAQUNX3Bvc2l0aW9uU2l6ZQcCXzEECW5ld1F0QXN0VwkBE2dldFF1b3RlQXNzZXRXZWlnaHQEBQdfYnNBc3RSBQ1fcG9zaXRpb25TaXplBQdfcXRBc3RSBQ5fdGVybWluYWxQcmljZQQJbmV3QnNBc3RXBQxERUNJTUFMX1VOSVQEDW1hcmdpblRvVmF1bHQICQErZ2V0UG9zaXRpb25Ob3Rpb25hbEFuZFVucmVhbGl6ZWRQbmxCeVZhbHVlcwcFDV9wb3NpdGlvblNpemUFFWN1cnJlbnROZXRNYXJrZXRWYWx1ZQUHX3F0QXN0UgUJbmV3UXRBc3RXBQdfYnNBc3RSBQluZXdCc0FzdFcFD1BOTF9PUFRJT05fU1BPVAJfMgkAlQoDBQluZXdRdEFzdFcFCW5ld0JzQXN0VwUNbWFyZ2luVG9WYXVsdAEKZ2V0RnVuZGluZwAED3VuZGVybHlpbmdQcmljZQkBDmdldE9yYWNsZVByaWNlAAQNc3BvdFR3YXBQcmljZQkBEGdldFR3YXBTcG90UHJpY2UABAdwcmVtaXVtCQBlAgUNc3BvdFR3YXBQcmljZQUPdW5kZXJseWluZ1ByaWNlAwMDCQAAAgkBFnRvdGFsU2hvcnRQb3NpdGlvblNpemUAAAAGCQAAAgkBFXRvdGFsTG9uZ1Bvc2l0aW9uU2l6ZQAAAAYJAQ5pc01hcmtldENsb3NlZAAJAJQKAgAAAAADCQBmAgAABQdwcmVtaXVtBBRzaG9ydFByZW1pdW1GcmFjdGlvbgkBBGRpdmQCCQEEbXVsZAIFB3ByZW1pdW0JARRmdW5kaW5nUGVyaW9kRGVjaW1hbAAFB09ORV9EQVkEE2xvbmdQcmVtaXVtRnJhY3Rpb24JAQRkaXZkAgkBBG11bGQCBRRzaG9ydFByZW1pdW1GcmFjdGlvbgkBFnRvdGFsU2hvcnRQb3NpdGlvblNpemUACQEVdG90YWxMb25nUG9zaXRpb25TaXplAAkAlAoCBRRzaG9ydFByZW1pdW1GcmFjdGlvbgUTbG9uZ1ByZW1pdW1GcmFjdGlvbgQTbG9uZ1ByZW1pdW1GcmFjdGlvbgkBBGRpdmQCCQEEbXVsZAIFB3ByZW1pdW0JARRmdW5kaW5nUGVyaW9kRGVjaW1hbAAFB09ORV9EQVkEFHNob3J0UHJlbWl1bUZyYWN0aW9uCQEEZGl2ZAIJAQRtdWxkAgUTbG9uZ1ByZW1pdW1GcmFjdGlvbgkBFXRvdGFsTG9uZ1Bvc2l0aW9uU2l6ZQAJARZ0b3RhbFNob3J0UG9zaXRpb25TaXplAAkAlAoCBRRzaG9ydFByZW1pdW1GcmFjdGlvbgUTbG9uZ1ByZW1pdW1GcmFjdGlvbgEOZ2V0QWRqdXN0ZWRGZWUCC19hcnRpZmFjdElkEF9iYXNlRmVlRGlzY291bnQECmJhc2VGZWVSYXcJAQNmZWUABAdiYXNlRmVlCQEEbXVsZAIFCmJhc2VGZWVSYXcFEF9iYXNlRmVlRGlzY291bnQEDSR0MDQyMDY0NDI1NTkDCQECIT0CBQtfYXJ0aWZhY3RJZAIABAxhcnRpZmFjdEtpbmQJAQRzdHJBAgkBEW5mdE1hbmFnZXJBZGRyZXNzAAkBDnRvQ29tcG9zaXRlS2V5AgUMa190b2tlbl90eXBlBQtfYXJ0aWZhY3RJZAMJAAACBQxhcnRpZmFjdEtpbmQFGEZFRV9SRURVQ1RJT05fVE9LRU5fVFlQRQQJcmVkdWN0aW9uCQEEaW50QQIJARFuZnRNYW5hZ2VyQWRkcmVzcwAJAQ50b0NvbXBvc2l0ZUtleQIFDWtfdG9rZW5fcGFyYW0FC19hcnRpZmFjdElkBAthZGp1c3RlZEZlZQkBBG11bGQCBQdiYXNlRmVlBQlyZWR1Y3Rpb24JAJQKAgULYWRqdXN0ZWRGZWUGCQACAQIZSW52YWxpZCBhdHRhY2hlZCBhcnRpZmFjdAkAlAoCBQdiYXNlRmVlBwQLYWRqdXN0ZWRGZWUIBQ0kdDA0MjA2NDQyNTU5Al8xBAxidXJuQXJ0aWZhY3QIBQ0kdDA0MjA2NDQyNTU5Al8yCQCUCgIFC2FkanVzdGVkRmVlBQxidXJuQXJ0aWZhY3QBF2lzU2FtZUFzc2V0T3JOb1Bvc2l0aW9uAgdfdHJhZGVyCF9hc3NldElkBA9vbGRQb3NpdGlvblNpemUICQELZ2V0UG9zaXRpb24BBQdfdHJhZGVyAl8xAwkAAAIFD29sZFBvc2l0aW9uU2l6ZQAABgkAAAIJARBnZXRQb3NpdGlvbkFzc2V0AQUHX3RyYWRlcgUIX2Fzc2V0SWQBC2lzU2FtZUFzc2V0AgdfdHJhZGVyCF9hc3NldElkCQAAAgkBEGdldFBvc2l0aW9uQXNzZXQBBQdfdHJhZGVyBQhfYXNzZXRJZAEYZ2V0Rm9yVHJhZGVyV2l0aEFydGlmYWN0AgdfdHJhZGVyC19hcnRpZmFjdElkBBBkb0dldEZlZURpc2NvdW50CQD8BwQJAQxtaW5lckFkZHJlc3MAAhJjb21wdXRlRmVlRGlzY291bnQJAMwIAgUHX3RyYWRlcgUDbmlsBQNuaWwDCQAAAgUQZG9HZXRGZWVEaXNjb3VudAUQZG9HZXRGZWVEaXNjb3VudAQLZmVlRGlzY291bnQEByRtYXRjaDAFEGRvR2V0RmVlRGlzY291bnQDCQABAgUHJG1hdGNoMAIDSW50BAF4BQckbWF0Y2gwBQF4CQACAQIhSW52YWxpZCBjb21wdXRlRmVlRGlzY291bnQgcmVzdWx0BA0kdDA0MzIzOTQzMzEzCQEOZ2V0QWRqdXN0ZWRGZWUCBQtfYXJ0aWZhY3RJZAULZmVlRGlzY291bnQEC2FkanVzdGVkRmVlCAUNJHQwNDMyMzk0MzMxMwJfMQQMYnVybkFydGlmYWN0CAUNJHQwNDMyMzk0MzMxMwJfMgkAlAoCBQthZGp1c3RlZEZlZQUMYnVybkFydGlmYWN0CQACAQIkU3RyaWN0IHZhbHVlIGlzIG5vdCBlcXVhbCB0byBpdHNlbGYuAQ1nZXRBcnRpZmFjdElkAQFpBAphcnRpZmFjdElkAwkAZgIJAJADAQgFAWkIcGF5bWVudHMAAQkA2AQBCQETdmFsdWVPckVycm9yTWVzc2FnZQIICQCRAwIIBQFpCHBheW1lbnRzAAEHYXNzZXRJZAISSW52YWxpZCBhcnRpZmFjdElkAgAFCmFydGlmYWN0SWQBDWRpc3RyaWJ1dGVGZWUBCl9mZWVBbW91bnQEDGZlZVRvU3Rha2VycwkBBG11bGQCBQpfZmVlQW1vdW50CQETZmVlVG9TdGFrZXJzUGVyY2VudAAECmZlZVRvVmF1bHQJAGUCBQpfZmVlQW1vdW50BQxmZWVUb1N0YWtlcnMJAJQKAgUMZmVlVG9TdGFrZXJzBQpmZWVUb1ZhdWx0AQ51cGRhdGVTZXR0aW5ncw0QX2luaXRNYXJnaW5SYXRpbwRfbW1yFF9saXF1aWRhdGlvbkZlZVJhdGlvDl9mdW5kaW5nUGVyaW9kBF9mZWUMX3NwcmVhZExpbWl0D19tYXhQcmljZUltcGFjdBhfcGFydGlhbExpcXVpZGF0aW9uUmF0aW8PX21heFByaWNlU3ByZWFkEF9tYXhPcGVuTm90aW9uYWwUX2ZlZVRvU3Rha2Vyc1BlcmNlbnQPX21heE9yYWNsZURlbGF5DF9yb2xsb3ZlckZlZQkAzAgCCQEMSW50ZWdlckVudHJ5AgURa19pbml0TWFyZ2luUmF0aW8FEF9pbml0TWFyZ2luUmF0aW8JAMwIAgkBDEludGVnZXJFbnRyeQIFGGtfbWFpbnRlbmFuY2VNYXJnaW5SYXRpbwUEX21tcgkAzAgCCQEMSW50ZWdlckVudHJ5AgUVa19saXF1aWRhdGlvbkZlZVJhdGlvBRRfbGlxdWlkYXRpb25GZWVSYXRpbwkAzAgCCQEMSW50ZWdlckVudHJ5AgUPa19mdW5kaW5nUGVyaW9kBQ5fZnVuZGluZ1BlcmlvZAkAzAgCCQEMSW50ZWdlckVudHJ5AgUFa19mZWUFBF9mZWUJAMwIAgkBDEludGVnZXJFbnRyeQIFDWtfc3ByZWFkTGltaXQFDF9zcHJlYWRMaW1pdAkAzAgCCQEMSW50ZWdlckVudHJ5AgUQa19tYXhQcmljZUltcGFjdAUPX21heFByaWNlSW1wYWN0CQDMCAIJAQxJbnRlZ2VyRW50cnkCBRlrX3BhcnRpYWxMaXF1aWRhdGlvblJhdGlvBRhfcGFydGlhbExpcXVpZGF0aW9uUmF0aW8JAMwIAgkBDEludGVnZXJFbnRyeQIFEGtfbWF4UHJpY2VTcHJlYWQFD19tYXhQcmljZVNwcmVhZAkAzAgCCQEMSW50ZWdlckVudHJ5AgURa19tYXhPcGVuTm90aW9uYWwFEF9tYXhPcGVuTm90aW9uYWwJAMwIAgkBDEludGVnZXJFbnRyeQIFFWtfZmVlVG9TdGFrZXJzUGVyY2VudAUUX2ZlZVRvU3Rha2Vyc1BlcmNlbnQJAMwIAgkBDEludGVnZXJFbnRyeQIFEGtfbWF4T3JhY2xlRGVsYXkFFF9mZWVUb1N0YWtlcnNQZXJjZW50CQDMCAIJAQxJbnRlZ2VyRW50cnkCBQ1rX3JvbGxvdmVyRmVlBQxfcm9sbG92ZXJGZWUFA25pbAENdXBkYXRlRnVuZGluZwURX25leHRGdW5kaW5nQmxvY2skX2xhdGVzdExvbmdDdW11bGF0aXZlUHJlbWl1bUZyYWN0aW9uJV9sYXRlc3RTaG9ydEN1bXVsYXRpdmVQcmVtaXVtRnJhY3Rpb24QX2xvbmdGdW5kaW5nUmF0ZRFfc2hvcnRGdW5kaW5nUmF0ZQkAzAgCCQEMSW50ZWdlckVudHJ5AgUSa19uZXh0RnVuZGluZ0Jsb2NrBRFfbmV4dEZ1bmRpbmdCbG9jawkAzAgCCQEMSW50ZWdlckVudHJ5AgUla19sYXRlc3RMb25nQ3VtdWxhdGl2ZVByZW1pdW1GcmFjdGlvbgUkX2xhdGVzdExvbmdDdW11bGF0aXZlUHJlbWl1bUZyYWN0aW9uCQDMCAIJAQxJbnRlZ2VyRW50cnkCBSZrX2xhdGVzdFNob3J0Q3VtdWxhdGl2ZVByZW1pdW1GcmFjdGlvbgUlX2xhdGVzdFNob3J0Q3VtdWxhdGl2ZVByZW1pdW1GcmFjdGlvbgkAzAgCCQEMSW50ZWdlckVudHJ5AgURa19sb25nRnVuZGluZ1JhdGUFEF9sb25nRnVuZGluZ1JhdGUJAMwIAgkBDEludGVnZXJFbnRyeQIFEmtfc2hvcnRGdW5kaW5nUmF0ZQURX3Nob3J0RnVuZGluZ1JhdGUFA25pbAEfaW5jcmVtZW50UG9zaXRpb25TZXF1ZW5jZU51bWJlcgIOX2lzTmV3UG9zaXRpb24IX2FkZHJlc3MDBQ5faXNOZXdQb3NpdGlvbgQPY3VycmVudFNlcXVlbmNlCQEMbGFzdFNlcXVlbmNlAAkAzAgCCQEMSW50ZWdlckVudHJ5AgkBDnRvQ29tcG9zaXRlS2V5AgUSa19wb3NpdGlvblNlcXVlbmNlBQhfYWRkcmVzcwkAZAIFD2N1cnJlbnRTZXF1ZW5jZQABCQDMCAIJAQxJbnRlZ2VyRW50cnkCBQprX3NlcXVlbmNlCQBkAgUPY3VycmVudFNlcXVlbmNlAAEFA25pbAUDbmlsARF1cGRhdGVQb3NpdGlvbkZlZQMOX2lzTmV3UG9zaXRpb24IX2FkZHJlc3MEX2ZlZQMFDl9pc05ld1Bvc2l0aW9uCQDMCAIJAQxJbnRlZ2VyRW50cnkCCQEOdG9Db21wb3NpdGVLZXkCBQ1rX3Bvc2l0aW9uRmVlBQhfYWRkcmVzcwUEX2ZlZQUDbmlsBQNuaWwBDnVwZGF0ZVBvc2l0aW9uBghfYWRkcmVzcwVfc2l6ZQdfbWFyZ2luDV9vcGVuTm90aW9uYWwgX2xhdGVzdEN1bXVsYXRpdmVQcmVtaXVtRnJhY3Rpb24QX2xhdGVzdFRpbWVzdGFtcAkAzAgCCQEMSW50ZWdlckVudHJ5AgkBDnRvQ29tcG9zaXRlS2V5AgUOa19wb3NpdGlvblNpemUFCF9hZGRyZXNzBQVfc2l6ZQkAzAgCCQEMSW50ZWdlckVudHJ5AgkBDnRvQ29tcG9zaXRlS2V5AgUQa19wb3NpdGlvbk1hcmdpbgUIX2FkZHJlc3MFB19tYXJnaW4JAMwIAgkBDEludGVnZXJFbnRyeQIJAQ50b0NvbXBvc2l0ZUtleQIFFmtfcG9zaXRpb25PcGVuTm90aW9uYWwFCF9hZGRyZXNzBQ1fb3Blbk5vdGlvbmFsCQDMCAIJAQxJbnRlZ2VyRW50cnkCCQEOdG9Db21wb3NpdGVLZXkCBS5rX3Bvc2l0aW9uTGFzdFVwZGF0ZWRDdW11bGF0aXZlUHJlbWl1bUZyYWN0aW9uBQhfYWRkcmVzcwUgX2xhdGVzdEN1bXVsYXRpdmVQcmVtaXVtRnJhY3Rpb24JAMwIAgkBDEludGVnZXJFbnRyeQIJAQ50b0NvbXBvc2l0ZUtleQIFHmtfcG9zaXRpb25MYXN0VXBkYXRlZFRpbWVzdGFtcAUIX2FkZHJlc3MFEF9sYXRlc3RUaW1lc3RhbXAFA25pbAEKYXBwZW5kVHdhcAEGX3ByaWNlBAhtaW51dGVJZAkAaQIJAGkCCQENbGFzdFRpbWVzdGFtcAAA6AcAPAQQcHJldmlvdXNNaW51dGVJZAkBC3ZhbHVlT3JFbHNlAgkAmggCBQR0aGlzBQ5rX2xhc3RNaW51dGVJZAAAAwkAZgIFEHByZXZpb3VzTWludXRlSWQFCG1pbnV0ZUlkCQACAQIRVFdBUCBvdXQtb2Ytb3JkZXIEDGxhc3RNaW51dGVJZAMJAAACBRBwcmV2aW91c01pbnV0ZUlkAAAFCG1pbnV0ZUlkBRBwcmV2aW91c01pbnV0ZUlkAwkAZgIFCG1pbnV0ZUlkBRBwcmV2aW91c01pbnV0ZUlkBBNwcmV2Q3VtdWxhdGl2ZVByaWNlCQELdmFsdWVPckVsc2UCCQCaCAIFBHRoaXMJAKwCAgkArAICBR1rX3R3YXBEYXRhTGFzdEN1bXVsYXRpdmVQcmljZQIBXwkApAMBBRBwcmV2aW91c01pbnV0ZUlkAAAECXByZXZQcmljZQkBC3ZhbHVlT3JFbHNlAgkAmggCBQR0aGlzCQCsAgIJAKwCAgUTa190d2FwRGF0YUxhc3RQcmljZQIBXwkApAMBBRBwcmV2aW91c01pbnV0ZUlkBQZfcHJpY2UEE2xhc3RDdW11bGF0aXZlUHJpY2UJAGQCBRNwcmV2Q3VtdWxhdGl2ZVByaWNlCQBoAgkAZQIFCG1pbnV0ZUlkBQxsYXN0TWludXRlSWQFCXByZXZQcmljZQQEbGlzdAkBC3B1c2hUb1F1ZXVlAwkBCXN0clRvTGlzdAEJAQt2YWx1ZU9yRWxzZQIJAJ0IAgUEdGhpcwUNa19sYXN0RGF0YVN0cgIABQ1UV0FQX0lOVEVSVkFMCQCkAwEFCG1pbnV0ZUlkCQDMCAIJAQxJbnRlZ2VyRW50cnkCCQEOdG9Db21wb3NpdGVLZXkCBR1rX3R3YXBEYXRhTGFzdEN1bXVsYXRpdmVQcmljZQkApAMBBQhtaW51dGVJZAUTbGFzdEN1bXVsYXRpdmVQcmljZQkAzAgCCQEMSW50ZWdlckVudHJ5AgkBDnRvQ29tcG9zaXRlS2V5AgUTa190d2FwRGF0YUxhc3RQcmljZQkApAMBBQhtaW51dGVJZAUGX3ByaWNlCQDMCAIJAQxJbnRlZ2VyRW50cnkCCQEOdG9Db21wb3NpdGVLZXkCBRprX3R3YXBEYXRhUHJldmlvdXNNaW51dGVJZAkApAMBBQhtaW51dGVJZAUQcHJldmlvdXNNaW51dGVJZAkAzAgCCQEMSW50ZWdlckVudHJ5AgUOa19sYXN0TWludXRlSWQFCG1pbnV0ZUlkCQDMCAIJAQtTdHJpbmdFbnRyeQIFDWtfbGFzdERhdGFTdHIJAQlsaXN0VG9TdHIBBQRsaXN0BQNuaWwEGHR3YXBEYXRhUHJldmlvdXNNaW51dGVJZAkBC3ZhbHVlT3JFbHNlAgkAmggCBQR0aGlzCQEOdG9Db21wb3NpdGVLZXkCBRprX3R3YXBEYXRhUHJldmlvdXNNaW51dGVJZAkApAMBBQhtaW51dGVJZAAABBNwcmV2Q3VtdWxhdGl2ZVByaWNlCQELdmFsdWVPckVsc2UCCQCaCAIFBHRoaXMJAQ50b0NvbXBvc2l0ZUtleQIFHWtfdHdhcERhdGFMYXN0Q3VtdWxhdGl2ZVByaWNlCQCkAwEFGHR3YXBEYXRhUHJldmlvdXNNaW51dGVJZAAABAlwcmV2UHJpY2UJAQt2YWx1ZU9yRWxzZQIJAJoIAgUEdGhpcwkBDnRvQ29tcG9zaXRlS2V5AgUTa190d2FwRGF0YUxhc3RQcmljZQkApAMBBRh0d2FwRGF0YVByZXZpb3VzTWludXRlSWQFBl9wcmljZQQTbGFzdEN1bXVsYXRpdmVQcmljZQkAZAIFE3ByZXZDdW11bGF0aXZlUHJpY2UJAGgCCQBlAgUIbWludXRlSWQFGHR3YXBEYXRhUHJldmlvdXNNaW51dGVJZAUJcHJldlByaWNlCQDMCAIJAQxJbnRlZ2VyRW50cnkCCQEOdG9Db21wb3NpdGVLZXkCBR1rX3R3YXBEYXRhTGFzdEN1bXVsYXRpdmVQcmljZQkApAMBBQhtaW51dGVJZAUTbGFzdEN1bXVsYXRpdmVQcmljZQkAzAgCCQEMSW50ZWdlckVudHJ5AgkBDnRvQ29tcG9zaXRlS2V5AgUTa190d2FwRGF0YUxhc3RQcmljZQkApAMBBQhtaW51dGVJZAUGX3ByaWNlBQNuaWwBEXVwZGF0ZUFtbVJlc2VydmVzAgdfcXRBc3RSB19ic0FzdFIJAMwIAgkBDEludGVnZXJFbnRyeQIFE2tfcXVvdGVBc3NldFJlc2VydmUFB19xdEFzdFIJAMwIAgkBDEludGVnZXJFbnRyeQIFEmtfYmFzZUFzc2V0UmVzZXJ2ZQUHX2JzQXN0UgUDbmlsARB1cGRhdGVBbW1XZWlnaHRzAgdfcXRBc3RXB19ic0FzdFcJAMwIAgkBDEludGVnZXJFbnRyeQIFEmtfcXVvdGVBc3NldFdlaWdodAUHX3F0QXN0VwkAzAgCCQEMSW50ZWdlckVudHJ5AgURa19iYXNlQXNzZXRXZWlnaHQFB19ic0FzdFcFA25pbAEJdXBkYXRlQW1tCAdfcXRBc3RSB19ic0FzdFIXX3RvdGFsUG9zaXRpb25TaXplQWZ0ZXIVX29wZW5JbnRlcmVzdE5vdGlvbmFsFl90b3RhbExvbmdQb3NpdGlvblNpemUXX3RvdGFsU2hvcnRQb3NpdGlvblNpemUWX3RvdGFsTG9uZ09wZW5Ob3Rpb25hbBdfdG90YWxTaG9ydE9wZW5Ob3Rpb25hbAQHX3F0QXN0VwkBBnF0QXN0VwAEB19ic0FzdFcJAQZic0FzdFcAAwkBAiE9AgkAZQIFFl90b3RhbExvbmdQb3NpdGlvblNpemUFF190b3RhbFNob3J0UG9zaXRpb25TaXplBRdfdG90YWxQb3NpdGlvblNpemVBZnRlcgkAAgEJAKwCAgkArAICCQCsAgIJAKwCAgkArAICAhhJbnZhbGlkIEFNTSBzdGF0ZSBkYXRhOiAJAKQDAQUWX3RvdGFsTG9uZ1Bvc2l0aW9uU2l6ZQIEICsgIAkApAMBBRdfdG90YWxTaG9ydFBvc2l0aW9uU2l6ZQIEICE9IAkApAMBBRdfdG90YWxQb3NpdGlvblNpemVBZnRlcgkAzggCCQDOCAIJARF1cGRhdGVBbW1SZXNlcnZlcwIFB19xdEFzdFIFB19ic0FzdFIJAMwIAgkBDEludGVnZXJFbnRyeQIFE2tfdG90YWxQb3NpdGlvblNpemUFF190b3RhbFBvc2l0aW9uU2l6ZUFmdGVyCQDMCAIJAQxJbnRlZ2VyRW50cnkCBRZrX29wZW5JbnRlcmVzdE5vdGlvbmFsBRVfb3BlbkludGVyZXN0Tm90aW9uYWwJAMwIAgkBDEludGVnZXJFbnRyeQIFF2tfdG90YWxMb25nUG9zaXRpb25TaXplBRZfdG90YWxMb25nUG9zaXRpb25TaXplCQDMCAIJAQxJbnRlZ2VyRW50cnkCBRhrX3RvdGFsU2hvcnRQb3NpdGlvblNpemUFF190b3RhbFNob3J0UG9zaXRpb25TaXplCQDMCAIJAQxJbnRlZ2VyRW50cnkCBRJrX29wZW5JbnRlcmVzdExvbmcFFl90b3RhbExvbmdPcGVuTm90aW9uYWwJAMwIAgkBDEludGVnZXJFbnRyeQIFE2tfb3BlbkludGVyZXN0U2hvcnQFF190b3RhbFNob3J0T3Blbk5vdGlvbmFsBQNuaWwJAQphcHBlbmRUd2FwAQkBBGRpdmQCCQEEbXVsZAIFB19xdEFzdFIFB19xdEFzdFcJAQRtdWxkAgUHX2JzQXN0UgUHX2JzQXN0VwEOZGVsZXRlUG9zaXRpb24BCF9hZGRyZXNzCQDMCAIJAQtEZWxldGVFbnRyeQEJAQ50b0NvbXBvc2l0ZUtleQIFDmtfcG9zaXRpb25TaXplBQhfYWRkcmVzcwkAzAgCCQELRGVsZXRlRW50cnkBCQEOdG9Db21wb3NpdGVLZXkCBRBrX3Bvc2l0aW9uTWFyZ2luBQhfYWRkcmVzcwkAzAgCCQELRGVsZXRlRW50cnkBCQEOdG9Db21wb3NpdGVLZXkCBRZrX3Bvc2l0aW9uT3Blbk5vdGlvbmFsBQhfYWRkcmVzcwkAzAgCCQELRGVsZXRlRW50cnkBCQEOdG9Db21wb3NpdGVLZXkCBS5rX3Bvc2l0aW9uTGFzdFVwZGF0ZWRDdW11bGF0aXZlUHJlbWl1bUZyYWN0aW9uBQhfYWRkcmVzcwkAzAgCCQELRGVsZXRlRW50cnkBCQEOdG9Db21wb3NpdGVLZXkCBQ9rX3Bvc2l0aW9uQXNzZXQFCF9hZGRyZXNzCQDMCAIJAQtEZWxldGVFbnRyeQEJAQ50b0NvbXBvc2l0ZUtleQIFDWtfcG9zaXRpb25GZWUFCF9hZGRyZXNzCQDMCAIJAQtEZWxldGVFbnRyeQEJAQ50b0NvbXBvc2l0ZUtleQIFHmtfcG9zaXRpb25MYXN0VXBkYXRlZFRpbWVzdGFtcAUIX2FkZHJlc3MFA25pbAEId2l0aGRyYXcCCF9hZGRyZXNzB19hbW91bnQEB2JhbGFuY2UJAPAHAgUEdGhpcwkBCnF1b3RlQXNzZXQAAwkAZgIFB19hbW91bnQFB2JhbGFuY2UJAAIBCQCsAgIJAKwCAgkArAICAhNVbmFibGUgdG8gd2l0aGRyYXcgCQCkAwEFB19hbW91bnQCFyBmcm9tIGNvbnRyYWN0IGJhbGFuY2UgCQCkAwEFB2JhbGFuY2UJAMwIAgkBDlNjcmlwdFRyYW5zZmVyAwUIX2FkZHJlc3MFB19hbW91bnQJAQpxdW90ZUFzc2V0AAUDbmlsAQ11cGRhdGVCYWxhbmNlAQFpAwkAZgIAAAUBaQkAAgECB0JhbGFuY2UJAMwIAgkBDEludGVnZXJFbnRyeQIFCWtfYmFsYW5jZQUBaQUDbmlsAQt0cmFuc2ZlckZlZQEBaQkAzAgCCQEOU2NyaXB0VHJhbnNmZXIDCQEOc3Rha2luZ0FkZHJlc3MABQFpCQEKcXVvdGVBc3NldAAFA25pbAEOZG9CdXJuQXJ0aWZhY3QCDV9idXJuQXJ0aWZhY3QBaQMFDV9idXJuQXJ0aWZhY3QJAMwIAgkBBEJ1cm4CCQETdmFsdWVPckVycm9yTWVzc2FnZQIICQCRAwIIBQFpCHBheW1lbnRzAAEHYXNzZXRJZAIQSW52YWxpZCBhcnRpZmFjdAABBQNuaWwFA25pbBUBaQEFcGF1c2UAAwkBAiE9AggFAWkGY2FsbGVyCQEMYWRtaW5BZGRyZXNzAAkAAgECFEludmFsaWQgcGF1c2UgcGFyYW1zCQDMCAIJAQxCb29sZWFuRW50cnkCBQhrX3BhdXNlZAYFA25pbAFpAQd1bnBhdXNlAAMJAQIhPQIIBQFpBmNhbGxlcgkBDGFkbWluQWRkcmVzcwAJAAIBAhZJbnZhbGlkIHVucGF1c2UgcGFyYW1zCQDMCAIJAQxCb29sZWFuRW50cnkCBQhrX3BhdXNlZAcFA25pbAFpAQxzZXRDbG9zZU9ubHkAAwkBAiE9AggFAWkGY2FsbGVyCQEMYWRtaW5BZGRyZXNzAAkAAgECG0ludmFsaWQgc2V0Q2xvc2VPbmx5IHBhcmFtcwkAzAgCCQEMQm9vbGVhbkVudHJ5AgULa19jbG9zZU9ubHkGBQNuaWwBaQEOdW5zZXRDbG9zZU9ubHkAAwkBAiE9AggFAWkGY2FsbGVyCQEMYWRtaW5BZGRyZXNzAAkAAgECHUludmFsaWQgdW5zZXRDbG9zZU9ubHkgcGFyYW1zCQDMCAIJAQxCb29sZWFuRW50cnkCBQtrX2Nsb3NlT25seQcFA25pbAFpAQxhZGRMaXF1aWRpdHkBEV9xdW90ZUFzc2V0QW1vdW50AwMJAQIhPQIIBQFpBmNhbGxlcgkBDGFkbWluQWRkcmVzcwAGCQBnAgAABRFfcXVvdGVBc3NldEFtb3VudAkAAgECG0ludmFsaWQgYWRkTGlxdWlkaXR5IHBhcmFtcwQHX3F0QXN0UgkBBnF0QXN0UgAEB19ic0FzdFIJAQZic0FzdFIABAdfcXRBc3RXCQEGcXRBc3RXAAQHX2JzQXN0VwkBBmJzQXN0VwAEBXByaWNlCQEEZGl2ZAIJAQRtdWxkAgUHX3F0QXN0UgUHX3F0QXN0VwkBBG11bGQCBQdfYnNBc3RSBQdfYnNBc3RXBAtxdEFzdFJBZnRlcgkAZAIFB19xdEFzdFIFEV9xdW90ZUFzc2V0QW1vdW50BBRiYXNlQXNzZXRBbW91bnRUb0FkZAkAZQIJAQRkaXZkAgkBBG11bGQCBQtxdEFzdFJBZnRlcgUHX3F0QXN0VwUFcHJpY2UFB19ic0FzdFIEC2JzQXN0UkFmdGVyCQBkAgUHX2JzQXN0UgUUYmFzZUFzc2V0QW1vdW50VG9BZGQEDSR0MDUyNzIwNTI4NzEJARRnZXRTeW5jVGVybWluYWxQcmljZQMJAQ5nZXRPcmFjbGVQcmljZQAFC3F0QXN0UkFmdGVyBQtic0FzdFJBZnRlcgQTbmV3UXVvdGVBc3NldFdlaWdodAgFDSR0MDUyNzIwNTI4NzECXzEEEm5ld0Jhc2VBc3NldFdlaWdodAgFDSR0MDUyNzIwNTI4NzECXzIEDW1hcmdpblRvVmF1bHQIBQ0kdDA1MjcyMDUyODcxAl8zBA1kb0V4Y2hhbmdlUG5MAwkBAiE9AgUNbWFyZ2luVG9WYXVsdAAABA1kb0V4Y2hhbmdlUG5MCQD8BwQJAQx2YXVsdEFkZHJlc3MAAhVleGNoYW5nZUZyZWVBbmRMb2NrZWQJAMwIAgUNbWFyZ2luVG9WYXVsdAUDbmlsBQNuaWwDCQAAAgUNZG9FeGNoYW5nZVBuTAUNZG9FeGNoYW5nZVBuTAUDbmlsCQACAQIkU3RyaWN0IHZhbHVlIGlzIG5vdCBlcXVhbCB0byBpdHNlbGYuBQNuaWwDCQAAAgUNZG9FeGNoYW5nZVBuTAUNZG9FeGNoYW5nZVBuTAkAzggCCQERdXBkYXRlQW1tUmVzZXJ2ZXMCBQtxdEFzdFJBZnRlcgULYnNBc3RSQWZ0ZXIJARB1cGRhdGVBbW1XZWlnaHRzAgUTbmV3UXVvdGVBc3NldFdlaWdodAUSbmV3QmFzZUFzc2V0V2VpZ2h0CQACAQIkU3RyaWN0IHZhbHVlIGlzIG5vdCBlcXVhbCB0byBpdHNlbGYuAWkBD3JlbW92ZUxpcXVpZGl0eQERX3F1b3RlQXNzZXRBbW91bnQDAwkBAiE9AggFAWkGY2FsbGVyCQEMYWRtaW5BZGRyZXNzAAYJAGcCBRFfcXVvdGVBc3NldEFtb3VudAAACQACAQIeSW52YWxpZCByZW1vdmVMaXF1aWRpdHkgcGFyYW1zBAdfcXRBc3RSCQEGcXRBc3RSAAQHX2JzQXN0UgkBBmJzQXN0UgAEB19xdEFzdFcJAQZxdEFzdFcABAdfYnNBc3RXCQEGYnNBc3RXAAQFcHJpY2UJAQRkaXZkAgkBBG11bGQCBQdfcXRBc3RSBQdfcXRBc3RXCQEEbXVsZAIFB19ic0FzdFIFB19ic0FzdFcEC3F0QXN0UkFmdGVyCQBlAgUHX3F0QXN0UgURX3F1b3RlQXNzZXRBbW91bnQEF2Jhc2VBc3NldEFtb3VudFRvUmVtb3ZlCQEDYWJzAQkAZQIJAQRkaXZkAgkBBG11bGQCBQtxdEFzdFJBZnRlcgUHX3F0QXN0VwUFcHJpY2UFB19ic0FzdFIEC2JzQXN0UkFmdGVyCQBlAgUHX2JzQXN0UgUXYmFzZUFzc2V0QW1vdW50VG9SZW1vdmUEDSR0MDUzODAzNTM5NTQJARRnZXRTeW5jVGVybWluYWxQcmljZQMJAQ5nZXRPcmFjbGVQcmljZQAFC3F0QXN0UkFmdGVyBQtic0FzdFJBZnRlcgQTbmV3UXVvdGVBc3NldFdlaWdodAgFDSR0MDUzODAzNTM5NTQCXzEEEm5ld0Jhc2VBc3NldFdlaWdodAgFDSR0MDUzODAzNTM5NTQCXzIEDW1hcmdpblRvVmF1bHQIBQ0kdDA1MzgwMzUzOTU0Al8zBA1kb0V4Y2hhbmdlUG5MAwkBAiE9AgUNbWFyZ2luVG9WYXVsdAAABA1kb0V4Y2hhbmdlUG5MCQD8BwQJAQx2YXVsdEFkZHJlc3MAAhVleGNoYW5nZUZyZWVBbmRMb2NrZWQJAMwIAgUNbWFyZ2luVG9WYXVsdAUDbmlsBQNuaWwDCQAAAgUNZG9FeGNoYW5nZVBuTAUNZG9FeGNoYW5nZVBuTAUDbmlsCQACAQIkU3RyaWN0IHZhbHVlIGlzIG5vdCBlcXVhbCB0byBpdHNlbGYuBQNuaWwDCQAAAgUNZG9FeGNoYW5nZVBuTAUNZG9FeGNoYW5nZVBuTAkAzggCCQERdXBkYXRlQW1tUmVzZXJ2ZXMCBQtxdEFzdFJBZnRlcgULYnNBc3RSQWZ0ZXIJARB1cGRhdGVBbW1XZWlnaHRzAgUTbmV3UXVvdGVBc3NldFdlaWdodAUSbmV3QmFzZUFzc2V0V2VpZ2h0CQACAQIkU3RyaWN0IHZhbHVlIGlzIG5vdCBlcXVhbCB0byBpdHNlbGYuAWkBDmNoYW5nZVNldHRpbmdzDRBfaW5pdE1hcmdpblJhdGlvBF9tbXIUX2xpcXVpZGF0aW9uRmVlUmF0aW8OX2Z1bmRpbmdQZXJpb2QEX2ZlZQxfc3ByZWFkTGltaXQPX21heFByaWNlSW1wYWN0GF9wYXJ0aWFsTGlxdWlkYXRpb25SYXRpbw9fbWF4UHJpY2VTcHJlYWQQX21heE9wZW5Ob3Rpb25hbBRfZmVlVG9TdGFrZXJzUGVyY2VudA9fbWF4T3JhY2xlRGVsYXkMX3JvbGxvdmVyRmVlAwkBAiE9AggFAWkGY2FsbGVyCQEMYWRtaW5BZGRyZXNzAAkAAgECHUludmFsaWQgY2hhbmdlU2V0dGluZ3MgcGFyYW1zCQEOdXBkYXRlU2V0dGluZ3MNBRBfaW5pdE1hcmdpblJhdGlvBQRfbW1yBRRfbGlxdWlkYXRpb25GZWVSYXRpbwUOX2Z1bmRpbmdQZXJpb2QFBF9mZWUFDF9zcHJlYWRMaW1pdAUPX21heFByaWNlSW1wYWN0BRhfcGFydGlhbExpcXVpZGF0aW9uUmF0aW8FD19tYXhQcmljZVNwcmVhZAUQX21heE9wZW5Ob3Rpb25hbAUUX2ZlZVRvU3Rha2Vyc1BlcmNlbnQFD19tYXhPcmFjbGVEZWxheQUMX3JvbGxvdmVyRmVlAWkBCmluaXRpYWxpemUTB19xdEFzdFIHX2JzQXN0Ug5fZnVuZGluZ1BlcmlvZBBfaW5pdE1hcmdpblJhdGlvBF9tbXIUX2xpcXVpZGF0aW9uRmVlUmF0aW8EX2ZlZQdfb3JhY2xlCl9vcmFjbGVLZXkPX29yYWNsZUJsb2NrS2V5DF9jb29yZGluYXRvcgxfc3ByZWFkTGltaXQPX21heFByaWNlSW1wYWN0GF9wYXJ0aWFsTGlxdWlkYXRpb25SYXRpbw9fbWF4UHJpY2VTcHJlYWQQX21heE9wZW5Ob3Rpb25hbBRfZmVlVG9TdGFrZXJzUGVyY2VudA9fbWF4T3JhY2xlRGVsYXkMX3JvbGxvdmVyRmVlAwMDAwMDAwMDAwMDAwMDAwMJAGcCAAAFB19xdEFzdFIGCQBnAgAABQdfYnNBc3RSBgkAZwIAAAUOX2Z1bmRpbmdQZXJpb2QGCQBnAgAABRBfaW5pdE1hcmdpblJhdGlvBgkAZwIAAAUEX21tcgYJAGcCAAAFFF9saXF1aWRhdGlvbkZlZVJhdGlvBgkAZwIAAAUEX2ZlZQYJAGcCAAAFDF9zcHJlYWRMaW1pdAYJAGcCAAAFD19tYXhQcmljZUltcGFjdAYJAGcCAAAFGF9wYXJ0aWFsTGlxdWlkYXRpb25SYXRpbwYJAGcCAAAFD19tYXhQcmljZVNwcmVhZAYJAGcCAAAFEF9tYXhPcGVuTm90aW9uYWwGCQBnAgAABRRfZmVlVG9TdGFrZXJzUGVyY2VudAYJAGYCBRRfZmVlVG9TdGFrZXJzUGVyY2VudAUMREVDSU1BTF9VTklUBgkAZwIAAAUPX21heE9yYWNsZURlbGF5BgkAZwIAAAUMX3JvbGxvdmVyRmVlBgkBC2luaXRpYWxpemVkAAkAAgECHUludmFsaWQgaW5pdGlhbGl6ZSBwYXJhbWV0ZXJzCQDOCAIJAM4IAgkAzggCCQDOCAIJAQl1cGRhdGVBbW0IBQdfcXRBc3RSBQdfYnNBc3RSAAAAAAAAAAAAAAAACQEOdXBkYXRlU2V0dGluZ3MNBRBfaW5pdE1hcmdpblJhdGlvBQRfbW1yBRRfbGlxdWlkYXRpb25GZWVSYXRpbwUOX2Z1bmRpbmdQZXJpb2QFBF9mZWUFDF9zcHJlYWRMaW1pdAUPX21heFByaWNlSW1wYWN0BRhfcGFydGlhbExpcXVpZGF0aW9uUmF0aW8FD19tYXhQcmljZVNwcmVhZAUQX21heE9wZW5Ob3Rpb25hbAUUX2ZlZVRvU3Rha2Vyc1BlcmNlbnQFD19tYXhPcmFjbGVEZWxheQUMX3JvbGxvdmVyRmVlCQENdXBkYXRlRnVuZGluZwUJAGQCCQENbGFzdFRpbWVzdGFtcAAFDl9mdW5kaW5nUGVyaW9kAAAAAAAAAAAJAQ11cGRhdGVCYWxhbmNlAQAACQDMCAIJAQxCb29sZWFuRW50cnkCBQ1rX2luaXRpYWxpemVkBgkAzAgCCQELU3RyaW5nRW50cnkCBQVrX29yYQUHX29yYWNsZQkAzAgCCQELU3RyaW5nRW50cnkCBQlrX29yYV9rZXkFCl9vcmFjbGVLZXkJAMwIAgkBC1N0cmluZ0VudHJ5AgUPa19vcmFfYmxvY2tfa2V5BQ9fb3JhY2xlQmxvY2tLZXkJAMwIAgkBC1N0cmluZ0VudHJ5AgUUa19jb29yZGluYXRvckFkZHJlc3MFDF9jb29yZGluYXRvcgUDbmlsAWkBEGluY3JlYXNlUG9zaXRpb24ECl9kaXJlY3Rpb24JX2xldmVyYWdlE19taW5CYXNlQXNzZXRBbW91bnQIX3JlZkxpbmsEBHN5bmMJAPwHBAUEdGhpcwIZc3luY1Rlcm1pbmFsUHJpY2VUb09yYWNsZQUDbmlsBQNuaWwDCQAAAgUEc3luYwUEc3luYwQHX3RyYWRlcgkBD2dldEFjdHVhbENhbGxlcgEFAWkECl9yYXdBbW91bnQICQCRAwIIBQFpCHBheW1lbnRzAAAGYW1vdW50BAhfYXNzZXRJZAgJAJEDAggFAWkIcGF5bWVudHMAAAdhc3NldElkBAtfYXNzZXRJZFN0cgkA2AQBCQEFdmFsdWUBBQhfYXNzZXRJZAQMaXNRdW90ZUFzc2V0CQAAAgUIX2Fzc2V0SWQJAQpxdW90ZUFzc2V0AAMDAwMDAwMDAwMJAQIhPQIFCl9kaXJlY3Rpb24FCERJUl9MT05HCQECIT0CBQpfZGlyZWN0aW9uBQlESVJfU0hPUlQHBgkAZwIAAAUKX3Jhd0Ftb3VudAYJAQEhAQkBC2luaXRpYWxpemVkAAYJAQEhAQUMaXNRdW90ZUFzc2V0BgkBASEBCQEXaXNTYW1lQXNzZXRPck5vUG9zaXRpb24CBQdfdHJhZGVyBQtfYXNzZXRJZFN0cgYJAQEhAQkBFnJlcXVpcmVNb3JlTWFyZ2luUmF0aW8DCQEEZGl2ZAIFDERFQ0lNQUxfVU5JVAUJX2xldmVyYWdlCQEPaW5pdE1hcmdpblJhdGlvAAYGCQEGcGF1c2VkAAYJAQljbG9zZU9ubHkABgkBDmlzTWFya2V0Q2xvc2VkAAkAAgECI0ludmFsaWQgaW5jcmVhc2VQb3NpdGlvbiBwYXJhbWV0ZXJzBA0kdDA1NzY0NTU3Nzk0CQEYZ2V0Rm9yVHJhZGVyV2l0aEFydGlmYWN0AgUHX3RyYWRlcgkBDWdldEFydGlmYWN0SWQBBQFpBAthZGp1c3RlZEZlZQgFDSR0MDU3NjQ1NTc3OTQCXzEEDGJ1cm5BcnRpZmFjdAgFDSR0MDU3NjQ1NTc3OTQCXzIEB19hbW91bnQJAQRkaXZkAgUKX3Jhd0Ftb3VudAkAZAIJAQRtdWxkAgULYWRqdXN0ZWRGZWUFCV9sZXZlcmFnZQUMREVDSU1BTF9VTklUBBNkaXN0cmlidXRlRmVlQW1vdW50CQBlAgUKX3Jhd0Ftb3VudAUHX2Ftb3VudAQOcmVmZXJyZXJGZWVBbnkJAPwHBAkBD3JlZmVycmFsQWRkcmVzcwACFWFjY2VwdFBheW1lbnRXaXRoTGluawkAzAgCBQdfdHJhZGVyCQDMCAIFCF9yZWZMaW5rBQNuaWwJAMwIAgkBD0F0dGFjaGVkUGF5bWVudAIJAQpxdW90ZUFzc2V0AAUTZGlzdHJpYnV0ZUZlZUFtb3VudAUDbmlsAwkAAAIFDnJlZmVycmVyRmVlQW55BQ5yZWZlcnJlckZlZUFueQQLcmVmZXJyZXJGZWUEByRtYXRjaDAFDnJlZmVycmVyRmVlQW55AwkAAQIFByRtYXRjaDACA0ludAQBeAUHJG1hdGNoMAUBeAkAAgECE0ludmFsaWQgcmVmZXJyZXJGZWUECWZlZUFtb3VudAkAZQIFE2Rpc3RyaWJ1dGVGZWVBbW91bnQFC3JlZmVycmVyRmVlBA0kdDA1ODI5MDU4NDU4CQELZ2V0UG9zaXRpb24BBQdfdHJhZGVyBA9vbGRQb3NpdGlvblNpemUIBQ0kdDA1ODI5MDU4NDU4Al8xBBFvbGRQb3NpdGlvbk1hcmdpbggFDSR0MDU4MjkwNTg0NTgCXzIEF29sZFBvc2l0aW9uT3Blbk5vdGlvbmFsCAUNJHQwNTgyOTA1ODQ1OAJfMwQUb2xkUG9zaXRpb25Mc3RVcGRDUEYIBQ0kdDA1ODI5MDU4NDU4Al80BBRvbGRQb3NpdGlvblRpbWVzdGFtcAgFDSR0MDU4MjkwNTg0NTgCXzUEDWlzTmV3UG9zaXRpb24JAAACBQ9vbGRQb3NpdGlvblNpemUAAAQPaXNTYW1lRGlyZWN0aW9uAwkAZgIFD29sZFBvc2l0aW9uU2l6ZQAACQAAAgUKX2RpcmVjdGlvbgUIRElSX0xPTkcJAAACBQpfZGlyZWN0aW9uBQlESVJfU0hPUlQEDmV4cGFuZEV4aXN0aW5nAwkBASEBBQ1pc05ld1Bvc2l0aW9uBQ9pc1NhbWVEaXJlY3Rpb24HBAVpc0FkZAkAAAIFCl9kaXJlY3Rpb24FCERJUl9MT05HBA0kdDA1ODc0NzYxODY4AwMFDWlzTmV3UG9zaXRpb24GBQ5leHBhbmRFeGlzdGluZwQMb3Blbk5vdGlvbmFsCQEEbXVsZAIFB19hbW91bnQFCV9sZXZlcmFnZQQNJHQwNTkyNTY1OTQyOQkBCXN3YXBJbnB1dAIFBWlzQWRkBQxvcGVuTm90aW9uYWwEFWFtb3VudEJhc2VBc3NldEJvdWdodAgFDSR0MDU5MjU2NTk0MjkCXzEEFnF1b3RlQXNzZXRSZXNlcnZlQWZ0ZXIIBQ0kdDA1OTI1NjU5NDI5Al8yBBViYXNlQXNzZXRSZXNlcnZlQWZ0ZXIIBQ0kdDA1OTI1NjU5NDI5Al8zBBZ0b3RhbFBvc2l0aW9uU2l6ZUFmdGVyCAUNJHQwNTkyNTY1OTQyOQJfNAMDCQECIT0CBRNfbWluQmFzZUFzc2V0QW1vdW50AAAJAGYCBRNfbWluQmFzZUFzc2V0QW1vdW50CQEDYWJzAQUVYW1vdW50QmFzZUFzc2V0Qm91Z2h0BwkAAgEJAKwCAgkArAICCQCsAgICDUxpbWl0IGVycm9yOiAJAKQDAQkBA2FicwEFFWFtb3VudEJhc2VBc3NldEJvdWdodAIDIDwgCQCkAwEFE19taW5CYXNlQXNzZXRBbW91bnQED25ld1Bvc2l0aW9uU2l6ZQkAZAIFD29sZFBvc2l0aW9uU2l6ZQUVYW1vdW50QmFzZUFzc2V0Qm91Z2h0BBp0b3RhbExvbmdPcGVuSW50ZXJlc3RBZnRlcgkAZAIJARBvcGVuSW50ZXJlc3RMb25nAAMJAGYCBQ9uZXdQb3NpdGlvblNpemUAAAUMb3Blbk5vdGlvbmFsAAAEG3RvdGFsU2hvcnRPcGVuSW50ZXJlc3RBZnRlcgkAZAIJARFvcGVuSW50ZXJlc3RTaG9ydAADCQBmAgAABQ9uZXdQb3NpdGlvblNpemUFDG9wZW5Ob3Rpb25hbAAABA0kdDA1OTk3NTYwMjUwCQEwY2FsY1JlbWFpbk1hcmdpbldpdGhGdW5kaW5nUGF5bWVudEFuZFJvbGxvdmVyRmVlBQUPb2xkUG9zaXRpb25TaXplBRFvbGRQb3NpdGlvbk1hcmdpbgUUb2xkUG9zaXRpb25Mc3RVcGRDUEYFFG9sZFBvc2l0aW9uVGltZXN0YW1wBQdfYW1vdW50BAxyZW1haW5NYXJnaW4IBQ0kdDA1OTk3NTYwMjUwAl8xBAJ4MQgFDSR0MDU5OTc1NjAyNTACXzIEAngyCAUNJHQwNTk5NzU2MDI1MAJfMwQLcm9sbG92ZXJGZWUIBQ0kdDA1OTk3NTYwMjUwAl80AwkBASEBCQEZcmVxdWlyZU5vdE92ZXJTcHJlYWRMaW1pdAIFFnF1b3RlQXNzZXRSZXNlcnZlQWZ0ZXIFFWJhc2VBc3NldFJlc2VydmVBZnRlcgkAAgECFU92ZXIgbWF4IHNwcmVhZCBsaW1pdAMJAQEhAQkBHXJlcXVpcmVOb3RPdmVyTWF4T3Blbk5vdGlvbmFsAgUadG90YWxMb25nT3BlbkludGVyZXN0QWZ0ZXIFG3RvdGFsU2hvcnRPcGVuSW50ZXJlc3RBZnRlcgkAAgECFk92ZXIgbWF4IG9wZW4gbm90aW9uYWwJAKAKDgUPbmV3UG9zaXRpb25TaXplBQxyZW1haW5NYXJnaW4JAGQCBRdvbGRQb3NpdGlvbk9wZW5Ob3Rpb25hbAUMb3Blbk5vdGlvbmFsCQEfbGF0ZXN0Q3VtdWxhdGl2ZVByZW1pdW1GcmFjdGlvbgEFD25ld1Bvc2l0aW9uU2l6ZQkBDWxhc3RUaW1lc3RhbXAABRViYXNlQXNzZXRSZXNlcnZlQWZ0ZXIFFnF1b3RlQXNzZXRSZXNlcnZlQWZ0ZXIFFnRvdGFsUG9zaXRpb25TaXplQWZ0ZXIJAGQCCQEUb3BlbkludGVyZXN0Tm90aW9uYWwABQxvcGVuTm90aW9uYWwJAGQCCQEVdG90YWxMb25nUG9zaXRpb25TaXplAAMJAGYCBQ9uZXdQb3NpdGlvblNpemUAAAkBA2FicwEFFWFtb3VudEJhc2VBc3NldEJvdWdodAAACQBkAgkBFnRvdGFsU2hvcnRQb3NpdGlvblNpemUAAwkAZgIAAAUPbmV3UG9zaXRpb25TaXplCQEDYWJzAQUVYW1vdW50QmFzZUFzc2V0Qm91Z2h0AAAFGnRvdGFsTG9uZ09wZW5JbnRlcmVzdEFmdGVyBRt0b3RhbFNob3J0T3BlbkludGVyZXN0QWZ0ZXIFC3JvbGxvdmVyRmVlBAxvcGVuTm90aW9uYWwJAQRtdWxkAgUHX2Ftb3VudAUJX2xldmVyYWdlBA0kdDA2MTU2ODYxNjg0CQEjZ2V0UG9zaXRpb25Ob3Rpb25hbEFuZFVucmVhbGl6ZWRQbmwCCQClCAEIBQFpBmNhbGxlcgUPUE5MX09QVElPTl9TUE9UBBNvbGRQb3NpdGlvbk5vdGlvbmFsCAUNJHQwNjE1Njg2MTY4NAJfMQQNdW5yZWFsaXplZFBubAgFDSR0MDYxNTY4NjE2ODQCXzIDCQBmAgUTb2xkUG9zaXRpb25Ob3Rpb25hbAUMb3Blbk5vdGlvbmFsCQACAQIuVXNlIGRlY3JlYXNlUG9zaXRpb24gdG8gZGVjcmVhc2UgcG9zaXRpb24gc2l6ZQkAAgECFENsb3NlIHBvc2l0aW9uIGZpcnN0BA9uZXdQb3NpdGlvblNpemUIBQ0kdDA1ODc0NzYxODY4Al8xBBduZXdQb3NpdGlvblJlbWFpbk1hcmdpbggFDSR0MDU4NzQ3NjE4NjgCXzIEF25ld1Bvc2l0aW9uT3Blbk5vdGlvbmFsCAUNJHQwNTg3NDc2MTg2OAJfMwQUbmV3UG9zaXRpb25MYXRlc3RDUEYIBQ0kdDA1ODc0NzYxODY4Al80BBRuZXdQb3NpdGlvblRpbWVzdGFtcAgFDSR0MDU4NzQ3NjE4NjgCXzUEFWJhc2VBc3NldFJlc2VydmVBZnRlcggFDSR0MDU4NzQ3NjE4NjgCXzYEFnF1b3RlQXNzZXRSZXNlcnZlQWZ0ZXIIBQ0kdDA1ODc0NzYxODY4Al83BBZ0b3RhbFBvc2l0aW9uU2l6ZUFmdGVyCAUNJHQwNTg3NDc2MTg2OAJfOAQZb3BlbkludGVyZXN0Tm90aW9uYWxBZnRlcggFDSR0MDU4NzQ3NjE4NjgCXzkEDnRvdGFsTG9uZ0FmdGVyCAUNJHQwNTg3NDc2MTg2OANfMTAED3RvdGFsU2hvcnRBZnRlcggFDSR0MDU4NzQ3NjE4NjgDXzExBBp0b3RhbExvbmdPcGVuSW50ZXJlc3RBZnRlcggFDSR0MDU4NzQ3NjE4NjgDXzEyBBt0b3RhbFNob3J0T3BlbkludGVyZXN0QWZ0ZXIIBQ0kdDA1ODc0NzYxODY4A18xMwQLcm9sbG92ZXJGZWUIBQ0kdDA1ODc0NzYxODY4A18xNAQNJHQwNjE4NzQ2MTk0NQkBDWRpc3RyaWJ1dGVGZWUBCQBkAgUJZmVlQW1vdW50BQtyb2xsb3ZlckZlZQQMZmVlVG9TdGFrZXJzCAUNJHQwNjE4NzQ2MTk0NQJfMQQKZmVlVG9WYXVsdAgFDSR0MDYxODc0NjE5NDUCXzIEBXN0YWtlAwkAZwIFB19hbW91bnQFC3JvbGxvdmVyRmVlCQD8BwQJAQx2YXVsdEFkZHJlc3MAAglhZGRMb2NrZWQFA25pbAkAzAgCCQEPQXR0YWNoZWRQYXltZW50AgkBCnF1b3RlQXNzZXQACQBlAgUHX2Ftb3VudAULcm9sbG92ZXJGZWUFA25pbAkA/AcECQEMdmF1bHRBZGRyZXNzAAIOd2l0aGRyYXdMb2NrZWQJAMwIAgkAZQIFC3JvbGxvdmVyRmVlBQdfYW1vdW50BQNuaWwFA25pbAMJAAACBQVzdGFrZQUFc3Rha2UEDGRlcG9zaXRWYXVsdAkA/AcECQEMdmF1bHRBZGRyZXNzAAIHYWRkRnJlZQUDbmlsCQDMCAIJAQ9BdHRhY2hlZFBheW1lbnQCCQEKcXVvdGVBc3NldAAFCmZlZVRvVmF1bHQFA25pbAMJAAACBQxkZXBvc2l0VmF1bHQFDGRlcG9zaXRWYXVsdAQJbm90aWZ5RmVlCQD8BwQJAQxtaW5lckFkZHJlc3MAAgpub3RpZnlGZWVzCQDMCAIFB190cmFkZXIJAMwIAgUJZmVlQW1vdW50BQNuaWwFA25pbAMJAAACBQlub3RpZnlGZWUFCW5vdGlmeUZlZQQObm90aWZ5Tm90aW9uYWwJAPwHBAkBDG1pbmVyQWRkcmVzcwACDm5vdGlmeU5vdGlvbmFsCQDMCAIFB190cmFkZXIJAMwIAgUXbmV3UG9zaXRpb25PcGVuTm90aW9uYWwFA25pbAUDbmlsAwkAAAIFDm5vdGlmeU5vdGlvbmFsBQ5ub3RpZnlOb3Rpb25hbAkAzggCCQDOCAIJAM4IAgkAzggCCQDOCAIJAM4IAgkBDnVwZGF0ZVBvc2l0aW9uBgUHX3RyYWRlcgUPbmV3UG9zaXRpb25TaXplBRduZXdQb3NpdGlvblJlbWFpbk1hcmdpbgUXbmV3UG9zaXRpb25PcGVuTm90aW9uYWwFFG5ld1Bvc2l0aW9uTGF0ZXN0Q1BGBRRuZXdQb3NpdGlvblRpbWVzdGFtcAkBH2luY3JlbWVudFBvc2l0aW9uU2VxdWVuY2VOdW1iZXICBQ1pc05ld1Bvc2l0aW9uBQdfdHJhZGVyCQERdXBkYXRlUG9zaXRpb25GZWUDBQ1pc05ld1Bvc2l0aW9uBQdfdHJhZGVyBQthZGp1c3RlZEZlZQkBCXVwZGF0ZUFtbQgFFnF1b3RlQXNzZXRSZXNlcnZlQWZ0ZXIFFWJhc2VBc3NldFJlc2VydmVBZnRlcgUWdG90YWxQb3NpdGlvblNpemVBZnRlcgUZb3BlbkludGVyZXN0Tm90aW9uYWxBZnRlcgUOdG90YWxMb25nQWZ0ZXIFD3RvdGFsU2hvcnRBZnRlcgUadG90YWxMb25nT3BlbkludGVyZXN0QWZ0ZXIFG3RvdGFsU2hvcnRPcGVuSW50ZXJlc3RBZnRlcgkBC3RyYW5zZmVyRmVlAQUMZmVlVG9TdGFrZXJzCQENdXBkYXRlQmFsYW5jZQEJAGUCCQBkAgkBCGNiYWxhbmNlAAUHX2Ftb3VudAULcm9sbG92ZXJGZWUJAQ5kb0J1cm5BcnRpZmFjdAIFDGJ1cm5BcnRpZmFjdAUBaQkAAgECJFN0cmljdCB2YWx1ZSBpcyBub3QgZXF1YWwgdG8gaXRzZWxmLgkAAgECJFN0cmljdCB2YWx1ZSBpcyBub3QgZXF1YWwgdG8gaXRzZWxmLgkAAgECJFN0cmljdCB2YWx1ZSBpcyBub3QgZXF1YWwgdG8gaXRzZWxmLgkAAgECJFN0cmljdCB2YWx1ZSBpcyBub3QgZXF1YWwgdG8gaXRzZWxmLgkAAgECJFN0cmljdCB2YWx1ZSBpcyBub3QgZXF1YWwgdG8gaXRzZWxmLgkAAgECJFN0cmljdCB2YWx1ZSBpcyBub3QgZXF1YWwgdG8gaXRzZWxmLgFpAQlhZGRNYXJnaW4ABARzeW5jCQD8BwQFBHRoaXMCGXN5bmNUZXJtaW5hbFByaWNlVG9PcmFjbGUFA25pbAUDbmlsAwkAAAIFBHN5bmMFBHN5bmMEB190cmFkZXIJAKUIAQgFAWkGY2FsbGVyBAdfYW1vdW50CAkAkQMCCAUBaQhwYXltZW50cwAABmFtb3VudAQIX2Fzc2V0SWQICQCRAwIIBQFpCHBheW1lbnRzAAAHYXNzZXRJZAQLX2Fzc2V0SWRTdHIJANgEAQkBBXZhbHVlAQUIX2Fzc2V0SWQEDGlzUXVvdGVBc3NldAkAAAIFCF9hc3NldElkCQEKcXVvdGVBc3NldAADAwMDAwMDCQEBIQEFDGlzUXVvdGVBc3NldAYJAQEhAQkBE3JlcXVpcmVPcGVuUG9zaXRpb24BCQClCAEIBQFpBmNhbGxlcgYJAQEhAQkBC2lzU2FtZUFzc2V0AgUHX3RyYWRlcgULX2Fzc2V0SWRTdHIGCQEBIQEJAQtpbml0aWFsaXplZAAGCQEGcGF1c2VkAAYJAQljbG9zZU9ubHkABgkBDmlzTWFya2V0Q2xvc2VkAAkAAgECHEludmFsaWQgYWRkTWFyZ2luIHBhcmFtZXRlcnMEDSR0MDYzOTg3NjQxNTUJAQtnZXRQb3NpdGlvbgEFB190cmFkZXIED29sZFBvc2l0aW9uU2l6ZQgFDSR0MDYzOTg3NjQxNTUCXzEEEW9sZFBvc2l0aW9uTWFyZ2luCAUNJHQwNjM5ODc2NDE1NQJfMgQXb2xkUG9zaXRpb25PcGVuTm90aW9uYWwIBQ0kdDA2Mzk4NzY0MTU1Al8zBBRvbGRQb3NpdGlvbkxzdFVwZENQRggFDSR0MDYzOTg3NjQxNTUCXzQEFG9sZFBvc2l0aW9uVGltZXN0YW1wCAUNJHQwNjM5ODc2NDE1NQJfNQQFc3Rha2UJAPwHBAkBDHZhdWx0QWRkcmVzcwACCWFkZExvY2tlZAUDbmlsCQDMCAIJAQ9BdHRhY2hlZFBheW1lbnQCCQEKcXVvdGVBc3NldAAFB19hbW91bnQFA25pbAMJAAACBQVzdGFrZQUFc3Rha2UEC3JvbGxvdmVyRmVlCQEPY2FsY1JvbGxvdmVyRmVlAgURb2xkUG9zaXRpb25NYXJnaW4FFG9sZFBvc2l0aW9uVGltZXN0YW1wBBZkb1RyYW5zZmVyRmVlVG9TdGFrZXJzAwkAZgIFC3JvbGxvdmVyRmVlAAAEDSR0MDY0NDQwNjQ0OTkJAQ1kaXN0cmlidXRlRmVlAQULcm9sbG92ZXJGZWUEDGZlZVRvU3Rha2VycwgFDSR0MDY0NDQwNjQ0OTkCXzEECmZlZVRvVmF1bHQIBQ0kdDA2NDQ0MDY0NDk5Al8yBAd1bnN0YWtlCQD8BwQJAQx2YXVsdEFkZHJlc3MAAg53aXRoZHJhd0xvY2tlZAkAzAgCBQxmZWVUb1N0YWtlcnMFA25pbAUDbmlsAwkAAAIFB3Vuc3Rha2UFB3Vuc3Rha2UEC2xvY2tCYWREZWJ0CQD8BwQJAQx2YXVsdEFkZHJlc3MAAhVleGNoYW5nZUZyZWVBbmRMb2NrZWQJAMwIAgkBAS0BBQpmZWVUb1ZhdWx0BQNuaWwFA25pbAMJAAACBQtsb2NrQmFkRGVidAULbG9ja0JhZERlYnQJAQt0cmFuc2ZlckZlZQEFDGZlZVRvU3Rha2VycwkAAgECJFN0cmljdCB2YWx1ZSBpcyBub3QgZXF1YWwgdG8gaXRzZWxmLgkAAgECJFN0cmljdCB2YWx1ZSBpcyBub3QgZXF1YWwgdG8gaXRzZWxmLgUDbmlsAwkAAAIFFmRvVHJhbnNmZXJGZWVUb1N0YWtlcnMFFmRvVHJhbnNmZXJGZWVUb1N0YWtlcnMJAM4IAgkAzggCCQEOdXBkYXRlUG9zaXRpb24GBQdfdHJhZGVyBQ9vbGRQb3NpdGlvblNpemUJAGQCCQBlAgURb2xkUG9zaXRpb25NYXJnaW4FC3JvbGxvdmVyRmVlBQdfYW1vdW50BRdvbGRQb3NpdGlvbk9wZW5Ob3Rpb25hbAUUb2xkUG9zaXRpb25Mc3RVcGRDUEYJAQ1sYXN0VGltZXN0YW1wAAkBDXVwZGF0ZUJhbGFuY2UBCQBlAgkAZAIJAQhjYmFsYW5jZQAFB19hbW91bnQFC3JvbGxvdmVyRmVlBRZkb1RyYW5zZmVyRmVlVG9TdGFrZXJzCQACAQIkU3RyaWN0IHZhbHVlIGlzIG5vdCBlcXVhbCB0byBpdHNlbGYuCQACAQIkU3RyaWN0IHZhbHVlIGlzIG5vdCBlcXVhbCB0byBpdHNlbGYuCQACAQIkU3RyaWN0IHZhbHVlIGlzIG5vdCBlcXVhbCB0byBpdHNlbGYuAWkBDHJlbW92ZU1hcmdpbgEHX2Ftb3VudAQEc3luYwkA/AcEBQR0aGlzAhlzeW5jVGVybWluYWxQcmljZVRvT3JhY2xlBQNuaWwFA25pbAMJAAACBQRzeW5jBQRzeW5jBAdfdHJhZGVyCQClCAEIBQFpBmNhbGxlcgMDAwMDCQBnAgAABQdfYW1vdW50BgkBASEBCQETcmVxdWlyZU9wZW5Qb3NpdGlvbgEFB190cmFkZXIGCQEBIQEJAQtpbml0aWFsaXplZAAGCQEGcGF1c2VkAAYJAQ5pc01hcmtldENsb3NlZAAJAAIBAh9JbnZhbGlkIHJlbW92ZU1hcmdpbiBwYXJhbWV0ZXJzBA0kdDA2NTU0MjY1NzEwCQELZ2V0UG9zaXRpb24BBQdfdHJhZGVyBA9vbGRQb3NpdGlvblNpemUIBQ0kdDA2NTU0MjY1NzEwAl8xBBFvbGRQb3NpdGlvbk1hcmdpbggFDSR0MDY1NTQyNjU3MTACXzIEF29sZFBvc2l0aW9uT3Blbk5vdGlvbmFsCAUNJHQwNjU1NDI2NTcxMAJfMwQUb2xkUG9zaXRpb25Mc3RVcGRDUEYIBQ0kdDA2NTU0MjY1NzEwAl80BBRvbGRQb3NpdGlvblRpbWVzdGFtcAgFDSR0MDY1NTQyNjU3MTACXzUEDSR0MDY1NzE2NjU5NjUJATBjYWxjUmVtYWluTWFyZ2luV2l0aEZ1bmRpbmdQYXltZW50QW5kUm9sbG92ZXJGZWUFBQ9vbGRQb3NpdGlvblNpemUFEW9sZFBvc2l0aW9uTWFyZ2luBRRvbGRQb3NpdGlvbkxzdFVwZENQRgUUb2xkUG9zaXRpb25UaW1lc3RhbXAJAQEtAQUHX2Ftb3VudAQMcmVtYWluTWFyZ2luCAUNJHQwNjU3MTY2NTk2NQJfMQQHYmFkRGVidAgFDSR0MDY1NzE2NjU5NjUCXzIEDmZ1bmRpbmdQYXltZW50CAUNJHQwNjU3MTY2NTk2NQJfMwQLcm9sbG92ZXJGZWUIBQ0kdDA2NTcxNjY1OTY1Al80AwkBAiE9AgUHYmFkRGVidAAACQACAQIdSW52YWxpZCByZW1vdmVkIG1hcmdpbiBhbW91bnQEC21hcmdpblJhdGlvCQEPY2FsY01hcmdpblJhdGlvAwUMcmVtYWluTWFyZ2luBQdiYWREZWJ0BRdvbGRQb3NpdGlvbk9wZW5Ob3Rpb25hbAMJAQEhAQkBFnJlcXVpcmVNb3JlTWFyZ2luUmF0aW8DBQttYXJnaW5SYXRpbwkBD2luaXRNYXJnaW5SYXRpbwAGCQACAQkArAICCQCsAgIJAKwCAgIZVG9vIG11Y2ggbWFyZ2luIHJlbW92ZWQ6IAkApAMBBQttYXJnaW5SYXRpbwIDIDwgCQCkAwEJAQ9pbml0TWFyZ2luUmF0aW8ABA0kdDA2NjM1MTY2NDEwCQENZGlzdHJpYnV0ZUZlZQEFC3JvbGxvdmVyRmVlBAxmZWVUb1N0YWtlcnMIBQ0kdDA2NjM1MTY2NDEwAl8xBApmZWVUb1ZhdWx0CAUNJHQwNjYzNTE2NjQxMAJfMgQWZG9UcmFuc2ZlckZlZVRvU3Rha2VycwMJAGYCBQtyb2xsb3ZlckZlZQAABAtsb2NrQmFkRGVidAkA/AcECQEMdmF1bHRBZGRyZXNzAAIVZXhjaGFuZ2VGcmVlQW5kTG9ja2VkCQDMCAIJAQEtAQUKZmVlVG9WYXVsdAUDbmlsBQNuaWwDCQAAAgULbG9ja0JhZERlYnQFC2xvY2tCYWREZWJ0CQELdHJhbnNmZXJGZWUBBQxmZWVUb1N0YWtlcnMJAAIBAiRTdHJpY3QgdmFsdWUgaXMgbm90IGVxdWFsIHRvIGl0c2VsZi4FA25pbAMJAAACBRZkb1RyYW5zZmVyRmVlVG9TdGFrZXJzBRZkb1RyYW5zZmVyRmVlVG9TdGFrZXJzBAd1bnN0YWtlCQD8BwQJAQx2YXVsdEFkZHJlc3MAAg53aXRoZHJhd0xvY2tlZAkAzAgCCQBkAgUHX2Ftb3VudAUMZmVlVG9TdGFrZXJzBQNuaWwFA25pbAMJAAACBQd1bnN0YWtlBQd1bnN0YWtlCQDOCAIJAM4IAgkAzggCCQEOdXBkYXRlUG9zaXRpb24GBQdfdHJhZGVyBQ9vbGRQb3NpdGlvblNpemUFDHJlbWFpbk1hcmdpbgUXb2xkUG9zaXRpb25PcGVuTm90aW9uYWwJAR9sYXRlc3RDdW11bGF0aXZlUHJlbWl1bUZyYWN0aW9uAQUPb2xkUG9zaXRpb25TaXplCQENbGFzdFRpbWVzdGFtcAAJAQh3aXRoZHJhdwIIBQFpBmNhbGxlcgUHX2Ftb3VudAkBDXVwZGF0ZUJhbGFuY2UBCQBlAgkAZQIJAQhjYmFsYW5jZQAFB19hbW91bnQFC3JvbGxvdmVyRmVlBRZkb1RyYW5zZmVyRmVlVG9TdGFrZXJzCQACAQIkU3RyaWN0IHZhbHVlIGlzIG5vdCBlcXVhbCB0byBpdHNlbGYuCQACAQIkU3RyaWN0IHZhbHVlIGlzIG5vdCBlcXVhbCB0byBpdHNlbGYuCQACAQIkU3RyaWN0IHZhbHVlIGlzIG5vdCBlcXVhbCB0byBpdHNlbGYuAWkBDWNsb3NlUG9zaXRpb24DBV9zaXplFF9taW5RdW90ZUFzc2V0QW1vdW50DF9hZGRUb01hcmdpbgQEc3luYwkA/AcEBQR0aGlzAhlzeW5jVGVybWluYWxQcmljZVRvT3JhY2xlBQNuaWwFA25pbAMJAAACBQRzeW5jBQRzeW5jBAdfdHJhZGVyCQEPZ2V0QWN0dWFsQ2FsbGVyAQUBaQQOX3RyYWRlckFkZHJlc3MJARN2YWx1ZU9yRXJyb3JNZXNzYWdlAgkApggBBQdfdHJhZGVyAg5JbnZhbGlkIGNhbGxlcgQLcG9zaXRpb25GZWUJAQ5nZXRQb3NpdGlvbkZlZQEFB190cmFkZXIDAwMDAwMJAQEhAQkBE3JlcXVpcmVPcGVuUG9zaXRpb24BBQdfdHJhZGVyBgkBASEBCQELaW5pdGlhbGl6ZWQABgkBBnBhdXNlZAAGCQBnAgAABQVfc2l6ZQYJAGYCAAAFFF9taW5RdW90ZUFzc2V0QW1vdW50BgkBDmlzTWFya2V0Q2xvc2VkAAkAAgECIEludmFsaWQgY2xvc2VQb3NpdGlvbiBwYXJhbWV0ZXJzBA0kdDA2Nzk0MjY4MDgyCQELZ2V0UG9zaXRpb24BBQdfdHJhZGVyBA9vbGRQb3NpdGlvblNpemUIBQ0kdDA2Nzk0MjY4MDgyAl8xBBFvbGRQb3NpdGlvbk1hcmdpbggFDSR0MDY3OTQyNjgwODICXzIEF29sZFBvc2l0aW9uT3Blbk5vdGlvbmFsCAUNJHQwNjc5NDI2ODA4MgJfMwQUb2xkUG9zaXRpb25Mc3RVcGRDUEYIBQ0kdDA2Nzk0MjY4MDgyAl80BA0kdDA2ODA4ODY4NjYxCQEVaW50ZXJuYWxDbG9zZVBvc2l0aW9uBgUHX3RyYWRlcgUFX3NpemUFC3Bvc2l0aW9uRmVlBRRfbWluUXVvdGVBc3NldEFtb3VudAUMX2FkZFRvTWFyZ2luBgQPbmV3UG9zaXRpb25TaXplCAUNJHQwNjgwODg2ODY2MQJfMQQRbmV3UG9zaXRpb25NYXJnaW4IBQ0kdDA2ODA4ODY4NjYxAl8yBBduZXdQb3NpdGlvbk9wZW5Ob3Rpb25hbAgFDSR0MDY4MDg4Njg2NjECXzMEFG5ld1Bvc2l0aW9uTHN0VXBkQ1BGCAUNJHQwNjgwODg2ODY2MQJfNAQPcG9zaXRpb25CYWREZWJ0CAUNJHQwNjgwODg2ODY2MQJfNQQLcmVhbGl6ZWRQbmwIBQ0kdDA2ODA4ODY4NjYxAl82BA5tYXJnaW5Ub1RyYWRlcggFDSR0MDY4MDg4Njg2NjECXzcEFnF1b3RlQXNzZXRSZXNlcnZlQWZ0ZXIIBQ0kdDA2ODA4ODY4NjYxAl84BBViYXNlQXNzZXRSZXNlcnZlQWZ0ZXIIBQ0kdDA2ODA4ODY4NjYxAl85BBZ0b3RhbFBvc2l0aW9uU2l6ZUFmdGVyCAUNJHQwNjgwODg2ODY2MQNfMTAEGW9wZW5JbnRlcmVzdE5vdGlvbmFsQWZ0ZXIIBQ0kdDA2ODA4ODY4NjYxA18xMQQOdG90YWxMb25nQWZ0ZXIIBQ0kdDA2ODA4ODY4NjYxA18xMgQPdG90YWxTaG9ydEFmdGVyCAUNJHQwNjgwODg2ODY2MQNfMTMEGnRvdGFsTG9uZ09wZW5JbnRlcmVzdEFmdGVyCAUNJHQwNjgwODg2ODY2MQNfMTQEG3RvdGFsU2hvcnRPcGVuSW50ZXJlc3RBZnRlcggFDSR0MDY4MDg4Njg2NjEDXzE1BAtyZWFsaXplZEZlZQgFDSR0MDY4MDg4Njg2NjEDXzE2AwkAZgIFD3Bvc2l0aW9uQmFkRGVidAAACQACAQIqSW52YWxpZCBjbG9zZVBvc2l0aW9uIHBhcmFtZXRlcnM6IGJhZCBkZWJ0BA5pc1BhcnRpYWxDbG9zZQkBAiE9AgUPbmV3UG9zaXRpb25TaXplAAAEDndpdGhkcmF3QW1vdW50CQBkAgUObWFyZ2luVG9UcmFkZXIFC3JlYWxpemVkRmVlBAphbW1CYWxhbmNlCQBlAgkBCGNiYWxhbmNlAAUOd2l0aGRyYXdBbW91bnQEDWFtbU5ld0JhbGFuY2UDCQBmAgAABQphbW1CYWxhbmNlAAAFCmFtbUJhbGFuY2UEB3Vuc3Rha2UJAPwHBAkBDHZhdWx0QWRkcmVzcwACDndpdGhkcmF3TG9ja2VkCQDMCAIFDndpdGhkcmF3QW1vdW50BQNuaWwFA25pbAMJAAACBQd1bnN0YWtlBQd1bnN0YWtlBA0kdDA2OTE3MTY5MjMwCQENZGlzdHJpYnV0ZUZlZQEFC3JlYWxpemVkRmVlBAxmZWVUb1N0YWtlcnMIBQ0kdDA2OTE3MTY5MjMwAl8xBApmZWVUb1ZhdWx0CAUNJHQwNjkxNzE2OTIzMAJfMgQMZGVwb3NpdFZhdWx0CQD8BwQJAQx2YXVsdEFkZHJlc3MAAgdhZGRGcmVlBQNuaWwJAMwIAgkBD0F0dGFjaGVkUGF5bWVudAIJAQpxdW90ZUFzc2V0AAUKZmVlVG9WYXVsdAUDbmlsAwkAAAIFDGRlcG9zaXRWYXVsdAUMZGVwb3NpdFZhdWx0BAlub3RpZnlGZWUJAPwHBAkBDG1pbmVyQWRkcmVzcwACCm5vdGlmeUZlZXMJAMwIAgUHX3RyYWRlcgkAzAgCBQtyZWFsaXplZEZlZQUDbmlsBQNuaWwDCQAAAgUJbm90aWZ5RmVlBQlub3RpZnlGZWUEDm5vdGlmeU5vdGlvbmFsCQD8BwQJAQxtaW5lckFkZHJlc3MAAg5ub3RpZnlOb3Rpb25hbAkAzAgCBQdfdHJhZGVyCQDMCAIFF25ld1Bvc2l0aW9uT3Blbk5vdGlvbmFsBQNuaWwFA25pbAMJAAACBQ5ub3RpZnlOb3Rpb25hbAUObm90aWZ5Tm90aW9uYWwJAM4IAgkAzggCCQDOCAIJAM4IAgMFDmlzUGFydGlhbENsb3NlCQEOdXBkYXRlUG9zaXRpb24GBQdfdHJhZGVyBQ9uZXdQb3NpdGlvblNpemUFEW5ld1Bvc2l0aW9uTWFyZ2luBRduZXdQb3NpdGlvbk9wZW5Ob3Rpb25hbAUUbmV3UG9zaXRpb25Mc3RVcGRDUEYJAQ1sYXN0VGltZXN0YW1wAAkBDmRlbGV0ZVBvc2l0aW9uAQUHX3RyYWRlcgkBCXVwZGF0ZUFtbQgFFnF1b3RlQXNzZXRSZXNlcnZlQWZ0ZXIFFWJhc2VBc3NldFJlc2VydmVBZnRlcgUWdG90YWxQb3NpdGlvblNpemVBZnRlcgUZb3BlbkludGVyZXN0Tm90aW9uYWxBZnRlcgUOdG90YWxMb25nQWZ0ZXIFD3RvdGFsU2hvcnRBZnRlcgUadG90YWxMb25nT3BlbkludGVyZXN0QWZ0ZXIFG3RvdGFsU2hvcnRPcGVuSW50ZXJlc3RBZnRlcgMJAGYCBQ5tYXJnaW5Ub1RyYWRlcgAACQEId2l0aGRyYXcCBQ5fdHJhZGVyQWRkcmVzcwUObWFyZ2luVG9UcmFkZXIFA25pbAkBDXVwZGF0ZUJhbGFuY2UBBQ1hbW1OZXdCYWxhbmNlCQELdHJhbnNmZXJGZWUBBQxmZWVUb1N0YWtlcnMJAAIBAiRTdHJpY3QgdmFsdWUgaXMgbm90IGVxdWFsIHRvIGl0c2VsZi4JAAIBAiRTdHJpY3QgdmFsdWUgaXMgbm90IGVxdWFsIHRvIGl0c2VsZi4JAAIBAiRTdHJpY3QgdmFsdWUgaXMgbm90IGVxdWFsIHRvIGl0c2VsZi4JAAIBAiRTdHJpY3QgdmFsdWUgaXMgbm90IGVxdWFsIHRvIGl0c2VsZi4JAAIBAiRTdHJpY3QgdmFsdWUgaXMgbm90IGVxdWFsIHRvIGl0c2VsZi4BaQEJbGlxdWlkYXRlAQdfdHJhZGVyBARzeW5jCQD8BwQFBHRoaXMCGXN5bmNUZXJtaW5hbFByaWNlVG9PcmFjbGUFA25pbAUDbmlsAwkAAAIFBHN5bmMFBHN5bmMED3Nwb3RNYXJnaW5SYXRpbwkBFmdldE1hcmdpblJhdGlvQnlPcHRpb24CBQdfdHJhZGVyBQ9QTkxfT1BUSU9OX1NQT1QEFmxpcXVpZGF0aW9uTWFyZ2luUmF0aW8DCQEWaXNPdmVyRmx1Y3R1YXRpb25MaW1pdAAEEW9yYWNsZU1hcmdpblJhdGlvCQEWZ2V0TWFyZ2luUmF0aW9CeU9wdGlvbgIFB190cmFkZXIFEVBOTF9PUFRJT05fT1JBQ0xFCQEEdm1heAIFD3Nwb3RNYXJnaW5SYXRpbwURb3JhY2xlTWFyZ2luUmF0aW8FD3Nwb3RNYXJnaW5SYXRpbwMDAwMDCQEBIQEJARZyZXF1aXJlTW9yZU1hcmdpblJhdGlvAwUWbGlxdWlkYXRpb25NYXJnaW5SYXRpbwkBFm1haW50ZW5hbmNlTWFyZ2luUmF0aW8ABwYJAQEhAQkBE3JlcXVpcmVPcGVuUG9zaXRpb24BBQdfdHJhZGVyBgkBASEBCQELaW5pdGlhbGl6ZWQABgkBBnBhdXNlZAAGCQEOaXNNYXJrZXRDbG9zZWQACQACAQITVW5hYmxlIHRvIGxpcXVpZGF0ZQQUaXNQYXJ0aWFsTGlxdWlkYXRpb24DAwkAZgIFD3Nwb3RNYXJnaW5SYXRpbwkBE2xpcXVpZGF0aW9uRmVlUmF0aW8ABgkAZgIJARdwYXJ0aWFsTGlxdWlkYXRpb25SYXRpbwAAAAYJAGYCBQxERUNJTUFMX1VOSVQJARdwYXJ0aWFsTGlxdWlkYXRpb25SYXRpbwAED29sZFBvc2l0aW9uU2l6ZQgJAQtnZXRQb3NpdGlvbgEFB190cmFkZXICXzEED3Bvc2l0aW9uU2l6ZUFicwkBA2FicwEFD29sZFBvc2l0aW9uU2l6ZQQNJHQwNzE1NDM3MTg2NgMFFGlzUGFydGlhbExpcXVpZGF0aW9uBA9saXF1aWRhdGlvblNpemUJARtnZXRQYXJ0aWFsTGlxdWlkYXRpb25BbW91bnQCBQdfdHJhZGVyBQ9vbGRQb3NpdGlvblNpemUEEGxpcXVpZGF0aW9uUmF0aW8JAQRkaXZkAgkBA2FicwEFD2xpcXVpZGF0aW9uU2l6ZQUPcG9zaXRpb25TaXplQWJzCQCUCgIFEGxpcXVpZGF0aW9uUmF0aW8JAQNhYnMBBQ9saXF1aWRhdGlvblNpemUJAJQKAgAABQ9wb3NpdGlvblNpemVBYnMEEGxpcXVpZGF0aW9uUmF0aW8IBQ0kdDA3MTU0MzcxODY2Al8xBA9saXF1aWRhdGlvblNpemUIBQ0kdDA3MTU0MzcxODY2Al8yBA0kdDA3MTg3MjcyNDk4CQEVaW50ZXJuYWxDbG9zZVBvc2l0aW9uBgUHX3RyYWRlcgMFFGlzUGFydGlhbExpcXVpZGF0aW9uBQ9saXF1aWRhdGlvblNpemUFD3Bvc2l0aW9uU2l6ZUFicwkBE2xpcXVpZGF0aW9uRmVlUmF0aW8AAAAGBwQPbmV3UG9zaXRpb25TaXplCAUNJHQwNzE4NzI3MjQ5OAJfMQQRbmV3UG9zaXRpb25NYXJnaW4IBQ0kdDA3MTg3MjcyNDk4Al8yBBduZXdQb3NpdGlvbk9wZW5Ob3Rpb25hbAgFDSR0MDcxODcyNzI0OTgCXzMEFG5ld1Bvc2l0aW9uTHN0VXBkQ1BGCAUNJHQwNzE4NzI3MjQ5OAJfNAQPcG9zaXRpb25CYWREZWJ0CAUNJHQwNzE4NzI3MjQ5OAJfNQQLcmVhbGl6ZWRQbmwIBQ0kdDA3MTg3MjcyNDk4Al82BA5tYXJnaW5Ub1RyYWRlcggFDSR0MDcxODcyNzI0OTgCXzcEFnF1b3RlQXNzZXRSZXNlcnZlQWZ0ZXIIBQ0kdDA3MTg3MjcyNDk4Al84BBViYXNlQXNzZXRSZXNlcnZlQWZ0ZXIIBQ0kdDA3MTg3MjcyNDk4Al85BBZ0b3RhbFBvc2l0aW9uU2l6ZUFmdGVyCAUNJHQwNzE4NzI3MjQ5OANfMTAEGW9wZW5JbnRlcmVzdE5vdGlvbmFsQWZ0ZXIIBQ0kdDA3MTg3MjcyNDk4A18xMQQOdG90YWxMb25nQWZ0ZXIIBQ0kdDA3MTg3MjcyNDk4A18xMgQPdG90YWxTaG9ydEFmdGVyCAUNJHQwNzE4NzI3MjQ5OANfMTMEGnRvdGFsTG9uZ09wZW5JbnRlcmVzdEFmdGVyCAUNJHQwNzE4NzI3MjQ5OANfMTQEG3RvdGFsU2hvcnRPcGVuSW50ZXJlc3RBZnRlcggFDSR0MDcxODcyNzI0OTgDXzE1BBJsaXF1aWRhdGlvblBlbmFsdHkIBQ0kdDA3MTg3MjcyNDk4A18xNgQPZmVlVG9MaXF1aWRhdG9yCQBpAgUSbGlxdWlkYXRpb25QZW5hbHR5AAIECmZlZVRvVmF1bHQJAGUCBRJsaXF1aWRhdGlvblBlbmFsdHkFD2ZlZVRvTGlxdWlkYXRvcgQKYW1tQmFsYW5jZQkAZQIJAQhjYmFsYW5jZQAFEmxpcXVpZGF0aW9uUGVuYWx0eQQNbmV3QW1tQmFsYW5jZQMJAGYCAAAFCmFtbUJhbGFuY2UAAAUKYW1tQmFsYW5jZQQLbG9ja0JhZERlYnQDCQBmAgUPcG9zaXRpb25CYWREZWJ0AAAEC2xvY2tCYWREZWJ0CQD8BwQJAQx2YXVsdEFkZHJlc3MAAhVleGNoYW5nZUZyZWVBbmRMb2NrZWQJAMwIAgUPcG9zaXRpb25CYWREZWJ0BQNuaWwFA25pbAMJAAACBQtsb2NrQmFkRGVidAULbG9ja0JhZERlYnQFA25pbAkAAgECJFN0cmljdCB2YWx1ZSBpcyBub3QgZXF1YWwgdG8gaXRzZWxmLgUDbmlsAwkAAAIFC2xvY2tCYWREZWJ0BQtsb2NrQmFkRGVidAQHdW5zdGFrZQkA/AcECQEMdmF1bHRBZGRyZXNzAAIOd2l0aGRyYXdMb2NrZWQJAMwIAgUSbGlxdWlkYXRpb25QZW5hbHR5BQNuaWwFA25pbAMJAAACBQd1bnN0YWtlBQd1bnN0YWtlBBBkZXBvc2l0SW5zdXJhbmNlCQD8BwQJAQx2YXVsdEFkZHJlc3MAAgdhZGRGcmVlBQNuaWwJAMwIAgkBD0F0dGFjaGVkUGF5bWVudAIJAQpxdW90ZUFzc2V0AAUKZmVlVG9WYXVsdAUDbmlsAwkAAAIFEGRlcG9zaXRJbnN1cmFuY2UFEGRlcG9zaXRJbnN1cmFuY2UEDm5vdGlmeU5vdGlvbmFsCQD8BwQJAQxtaW5lckFkZHJlc3MAAg5ub3RpZnlOb3Rpb25hbAkAzAgCBQdfdHJhZGVyCQDMCAIFF25ld1Bvc2l0aW9uT3Blbk5vdGlvbmFsBQNuaWwFA25pbAMJAAACBQ5ub3RpZnlOb3Rpb25hbAUObm90aWZ5Tm90aW9uYWwJAM4IAgkAzggCCQDOCAIDBRRpc1BhcnRpYWxMaXF1aWRhdGlvbgkBDnVwZGF0ZVBvc2l0aW9uBgUHX3RyYWRlcgUPbmV3UG9zaXRpb25TaXplBRFuZXdQb3NpdGlvbk1hcmdpbgUXbmV3UG9zaXRpb25PcGVuTm90aW9uYWwFFG5ld1Bvc2l0aW9uTHN0VXBkQ1BGCQENbGFzdFRpbWVzdGFtcAAJAQ5kZWxldGVQb3NpdGlvbgEFB190cmFkZXIJAQl1cGRhdGVBbW0IBRZxdW90ZUFzc2V0UmVzZXJ2ZUFmdGVyBRViYXNlQXNzZXRSZXNlcnZlQWZ0ZXIFFnRvdGFsUG9zaXRpb25TaXplQWZ0ZXIFGW9wZW5JbnRlcmVzdE5vdGlvbmFsQWZ0ZXIFDnRvdGFsTG9uZ0FmdGVyBQ90b3RhbFNob3J0QWZ0ZXIFGnRvdGFsTG9uZ09wZW5JbnRlcmVzdEFmdGVyBRt0b3RhbFNob3J0T3BlbkludGVyZXN0QWZ0ZXIJAQh3aXRoZHJhdwIIBQFpBmNhbGxlcgUPZmVlVG9MaXF1aWRhdG9yCQENdXBkYXRlQmFsYW5jZQEFDW5ld0FtbUJhbGFuY2UJAAIBAiRTdHJpY3QgdmFsdWUgaXMgbm90IGVxdWFsIHRvIGl0c2VsZi4JAAIBAiRTdHJpY3QgdmFsdWUgaXMgbm90IGVxdWFsIHRvIGl0c2VsZi4JAAIBAiRTdHJpY3QgdmFsdWUgaXMgbm90IGVxdWFsIHRvIGl0c2VsZi4JAAIBAiRTdHJpY3QgdmFsdWUgaXMgbm90IGVxdWFsIHRvIGl0c2VsZi4JAAIBAiRTdHJpY3QgdmFsdWUgaXMgbm90IGVxdWFsIHRvIGl0c2VsZi4BaQEKcGF5RnVuZGluZwAEBHN5bmMJAPwHBAUEdGhpcwIZc3luY1Rlcm1pbmFsUHJpY2VUb09yYWNsZQUDbmlsBQNuaWwDCQAAAgUEc3luYwUEc3luYwQVZnVuZGluZ0Jsb2NrVGltZXN0YW1wCQEZbmV4dEZ1bmRpbmdCbG9ja1RpbWVzdGFtcAADAwMJAGYCBRVmdW5kaW5nQmxvY2tUaW1lc3RhbXAJAQ1sYXN0VGltZXN0YW1wAAYJAQEhAQkBC2luaXRpYWxpemVkAAYJAQZwYXVzZWQACQACAQkArAICCQCsAgIJAKwCAgIhSW52YWxpZCBmdW5kaW5nIGJsb2NrIHRpbWVzdGFtcDogCQCkAwEJAQ1sYXN0VGltZXN0YW1wAAIDIDwgCQCkAwEFFWZ1bmRpbmdCbG9ja1RpbWVzdGFtcAQPdW5kZXJseWluZ1ByaWNlCQEOZ2V0T3JhY2xlUHJpY2UABA0kdDA3NDQ2NDc0NTI2CQEKZ2V0RnVuZGluZwAEFHNob3J0UHJlbWl1bUZyYWN0aW9uCAUNJHQwNzQ0NjQ3NDUyNgJfMQQTbG9uZ1ByZW1pdW1GcmFjdGlvbggFDSR0MDc0NDY0NzQ1MjYCXzIJAQ11cGRhdGVGdW5kaW5nBQkAZAIFFWZ1bmRpbmdCbG9ja1RpbWVzdGFtcAkBFGZ1bmRpbmdQZXJpb2RTZWNvbmRzAAkAZAIJASNsYXRlc3RMb25nQ3VtdWxhdGl2ZVByZW1pdW1GcmFjdGlvbgAFE2xvbmdQcmVtaXVtRnJhY3Rpb24JAGQCCQEkbGF0ZXN0U2hvcnRDdW11bGF0aXZlUHJlbWl1bUZyYWN0aW9uAAUUc2hvcnRQcmVtaXVtRnJhY3Rpb24JAQRkaXZkAgUTbG9uZ1ByZW1pdW1GcmFjdGlvbgUPdW5kZXJseWluZ1ByaWNlCQEEZGl2ZAIFFHNob3J0UHJlbWl1bUZyYWN0aW9uBQ91bmRlcmx5aW5nUHJpY2UJAAIBAiRTdHJpY3QgdmFsdWUgaXMgbm90IGVxdWFsIHRvIGl0c2VsZi4BaQEZc3luY1Rlcm1pbmFsUHJpY2VUb09yYWNsZQAEB19xdEFzdFIJAQZxdEFzdFIABAdfYnNBc3RSCQEGYnNBc3RSAAQNJHQwNzQ5NTg3NTA5MwkBFGdldFN5bmNUZXJtaW5hbFByaWNlAwkBDmdldE9yYWNsZVByaWNlAAUHX3F0QXN0UgUHX2JzQXN0UgQTbmV3UXVvdGVBc3NldFdlaWdodAgFDSR0MDc0OTU4NzUwOTMCXzEEEm5ld0Jhc2VBc3NldFdlaWdodAgFDSR0MDc0OTU4NzUwOTMCXzIEDW1hcmdpblRvVmF1bHQIBQ0kdDA3NDk1ODc1MDkzAl8zBA1kb0V4Y2hhbmdlUG5MAwkBAiE9AgUNbWFyZ2luVG9WYXVsdAAABA1kb0V4Y2hhbmdlUG5MCQD8BwQJAQx2YXVsdEFkZHJlc3MAAhVleGNoYW5nZUZyZWVBbmRMb2NrZWQJAMwIAgUNbWFyZ2luVG9WYXVsdAUDbmlsBQNuaWwDCQAAAgUNZG9FeGNoYW5nZVBuTAUNZG9FeGNoYW5nZVBuTAUDbmlsCQACAQIkU3RyaWN0IHZhbHVlIGlzIG5vdCBlcXVhbCB0byBpdHNlbGYuBQNuaWwDCQAAAgUNZG9FeGNoYW5nZVBuTAUNZG9FeGNoYW5nZVBuTAkAzggCCQDOCAIJAQ11cGRhdGVCYWxhbmNlAQkAZAIJAQhjYmFsYW5jZQAFDW1hcmdpblRvVmF1bHQJARB1cGRhdGVBbW1XZWlnaHRzAgUTbmV3UXVvdGVBc3NldFdlaWdodAUSbmV3QmFzZUFzc2V0V2VpZ2h0CQEKYXBwZW5kVHdhcAEJAQRkaXZkAgkBBG11bGQCBQdfcXRBc3RSBRNuZXdRdW90ZUFzc2V0V2VpZ2h0CQEEbXVsZAIFB19ic0FzdFIFEm5ld0Jhc2VBc3NldFdlaWdodAkAAgECJFN0cmljdCB2YWx1ZSBpcyBub3QgZXF1YWwgdG8gaXRzZWxmLgFpASd2aWV3X2NhbGNSZW1haW5NYXJnaW5XaXRoRnVuZGluZ1BheW1lbnQBB190cmFkZXIEBHN5bmMJAPwHBAUEdGhpcwIZc3luY1Rlcm1pbmFsUHJpY2VUb09yYWNsZQUDbmlsBQNuaWwDCQAAAgUEc3luYwUEc3luYwQNJHQwNzU3MTE3NTgzNQkBC2dldFBvc2l0aW9uAQUHX3RyYWRlcgQMcG9zaXRpb25TaXplCAUNJHQwNzU3MTE3NTgzNQJfMQQOcG9zaXRpb25NYXJnaW4IBQ0kdDA3NTcxMTc1ODM1Al8yBANwb24IBQ0kdDA3NTcxMTc1ODM1Al8zBBFwb3NpdGlvbkxzdFVwZENQRggFDSR0MDc1NzExNzU4MzUCXzQEEXBvc2l0aW9uVGltZXN0YW1wCAUNJHQwNzU3MTE3NTgzNQJfNQQNJHQwNzU4Mzg3NTkzOQkBI2dldFBvc2l0aW9uTm90aW9uYWxBbmRVbnJlYWxpemVkUG5sAgUHX3RyYWRlcgUPUE5MX09QVElPTl9TUE9UBBBwb3NpdGlvbk5vdGlvbmFsCAUNJHQwNzU4Mzg3NTkzOQJfMQQNdW5yZWFsaXplZFBubAgFDSR0MDc1ODM4NzU5MzkCXzIEDSR0MDc1OTQyNzYxNjYJATBjYWxjUmVtYWluTWFyZ2luV2l0aEZ1bmRpbmdQYXltZW50QW5kUm9sbG92ZXJGZWUFBQxwb3NpdGlvblNpemUFDnBvc2l0aW9uTWFyZ2luBRFwb3NpdGlvbkxzdFVwZENQRgURcG9zaXRpb25UaW1lc3RhbXAFDXVucmVhbGl6ZWRQbmwEDHJlbWFpbk1hcmdpbggFDSR0MDc1OTQyNzYxNjYCXzEEB2JhZERlYnQIBQ0kdDA3NTk0Mjc2MTY2Al8yBA5mdW5kaW5nUGF5bWVudAgFDSR0MDc1OTQyNzYxNjYCXzMEC3JvbGxvdmVyRmVlCAUNJHQwNzU5NDI3NjE2NgJfNAkAAgEJAKwCAgkArAICCQCsAgIJAKwCAgkArAICCQCsAgIJAQFzAQUMcmVtYWluTWFyZ2luCQEBcwEFDmZ1bmRpbmdQYXltZW50CQEBcwEJAQ5nZXRNYXJnaW5SYXRpbwEFB190cmFkZXIJAQFzAQUNdW5yZWFsaXplZFBubAkBAXMBBQdiYWREZWJ0CQEBcwEFEHBvc2l0aW9uTm90aW9uYWwJAQFzAQULcm9sbG92ZXJGZWUJAAIBAiRTdHJpY3QgdmFsdWUgaXMgbm90IGVxdWFsIHRvIGl0c2VsZi4BaQEVdmlld19nZXRQZWdBZGp1c3RDb3N0AQZfcHJpY2UEB19xdEFzdFIJAQZxdEFzdFIABAdfYnNBc3RSCQEGYnNBc3RSAAQGcmVzdWx0CQEUZ2V0U3luY1Rlcm1pbmFsUHJpY2UDBQZfcHJpY2UFB19xdEFzdFIFB19ic0FzdFIJAAIBCQCkAwEIBQZyZXN1bHQCXzMBaQEYdmlld19nZXRUZXJtaW5hbEFtbVByaWNlAAQNJHQwNzY2MDI3NjY4MwkBE2dldFRlcm1pbmFsQW1tU3RhdGUABBl0ZXJtaW5hbFF1b3RlQXNzZXRSZXNlcnZlCAUNJHQwNzY2MDI3NjY4MwJfMQQYdGVybWluYWxCYXNlQXNzZXRSZXNlcnZlCAUNJHQwNzY2MDI3NjY4MwJfMgQFcHJpY2UJAQRkaXZkAgkBBG11bGQCBRl0ZXJtaW5hbFF1b3RlQXNzZXRSZXNlcnZlCQEGcXRBc3RXAAkBBG11bGQCBRh0ZXJtaW5hbEJhc2VBc3NldFJlc2VydmUJAQZic0FzdFcACQACAQkApAMBBQVwcmljZQFpAQ92aWV3X2dldEZ1bmRpbmcABA91bmRlcmx5aW5nUHJpY2UJAQ5nZXRPcmFjbGVQcmljZQAEDSR0MDc2ODk4NzY5NjAJAQpnZXRGdW5kaW5nAAQUc2hvcnRQcmVtaXVtRnJhY3Rpb24IBQ0kdDA3Njg5ODc2OTYwAl8xBBNsb25nUHJlbWl1bUZyYWN0aW9uCAUNJHQwNzY4OTg3Njk2MAJfMgQLbG9uZ0Z1bmRpbmcJAQRkaXZkAgUTbG9uZ1ByZW1pdW1GcmFjdGlvbgUPdW5kZXJseWluZ1ByaWNlBAxzaG9ydEZ1bmRpbmcJAQRkaXZkAgUUc2hvcnRQcmVtaXVtRnJhY3Rpb24FD3VuZGVybHlpbmdQcmljZQkAAgEJAKwCAgkArAICCQCsAgIJAQFzAQULbG9uZ0Z1bmRpbmcJAQFzAQUMc2hvcnRGdW5kaW5nCQEBcwEJARBnZXRUd2FwU3BvdFByaWNlAAkBAXMBCQEOZ2V0T3JhY2xlUHJpY2UAAWkBEGNvbXB1dGVTcG90UHJpY2UABAZyZXN1bHQJAQxnZXRTcG90UHJpY2UACQCUCgIFA25pbAUGcmVzdWx0AWkBH2NvbXB1dGVGZWVGb3JUcmFkZXJXaXRoQXJ0aWZhY3QCB190cmFkZXILX2FydGlmYWN0SWQEBnJlc3VsdAkBGGdldEZvclRyYWRlcldpdGhBcnRpZmFjdAIFB190cmFkZXIFC19hcnRpZmFjdElkCQCUCgIFA25pbAUGcmVzdWx0AQJ0eAEGdmVyaWZ5AAkA9AMDCAUCdHgJYm9keUJ5dGVzCQCRAwIIBQJ0eAZwcm9vZnMAAAkBDmFkbWluUHVibGljS2V5AERHxGQ=", "height": 2419147, "applicationStatus": "succeeded", "spentComplexity": 0 } View: original | compacted Prev: 55a9BMiBtVZw1LcNSVCNgmPnqSwbnVDoS2VJij6DDpUd Next: 6xqywtqazTsapZYHsX25FKBj9MqVodqsrugPa7aFaXrn Diff:
OldNewDifferences
12931293 let $t06187461945 = distributeFee((feeAmount + rolloverFee))
12941294 let feeToStakers = $t06187461945._1
12951295 let feeToVault = $t06187461945._2
1296- let stake = if (isQuoteAsset)
1297- then {
1298- let stake = invoke(vaultAddress(), "addLocked", [false], [AttachedPayment(quoteAsset(), _amount)])
1299- if ((stake == stake))
1300- then nil
1301- else throw("Strict value is not equal to itself.")
1302- }
1303- else nil
1296+ let stake = if ((_amount >= rolloverFee))
1297+ then invoke(vaultAddress(), "addLocked", nil, [AttachedPayment(quoteAsset(), (_amount - rolloverFee))])
1298+ else invoke(vaultAddress(), "withdrawLocked", [(rolloverFee - _amount)], nil)
13041299 if ((stake == stake))
13051300 then {
13061301 let depositVault = invoke(vaultAddress(), "addFree", nil, [AttachedPayment(quoteAsset(), feeToVault)])
13111306 then {
13121307 let notifyNotional = invoke(minerAddress(), "notifyNotional", [_trader, newPositionOpenNotional], nil)
13131308 if ((notifyNotional == notifyNotional))
1314- 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))) ++ doBurnArtifact(burnArtifact, i))
1309+ 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))
13151310 else throw("Strict value is not equal to itself.")
13161311 }
13171312 else throw("Strict value is not equal to itself.")
13531348 else isMarketClosed())
13541349 then throw("Invalid addMargin parameters")
13551350 else {
1356- let $t06387164039 = getPosition(_trader)
1357- let oldPositionSize = $t06387164039._1
1358- let oldPositionMargin = $t06387164039._2
1359- let oldPositionOpenNotional = $t06387164039._3
1360- let oldPositionLstUpdCPF = $t06387164039._4
1361- let oldPositionTimestamp = $t06387164039._5
1362- let stake = invoke(vaultAddress(), "addLocked", [false], [AttachedPayment(quoteAsset(), _amount)])
1351+ let $t06398764155 = getPosition(_trader)
1352+ let oldPositionSize = $t06398764155._1
1353+ let oldPositionMargin = $t06398764155._2
1354+ let oldPositionOpenNotional = $t06398764155._3
1355+ let oldPositionLstUpdCPF = $t06398764155._4
1356+ let oldPositionTimestamp = $t06398764155._5
1357+ let stake = invoke(vaultAddress(), "addLocked", nil, [AttachedPayment(quoteAsset(), _amount)])
13631358 if ((stake == stake))
13641359 then {
13651360 let rolloverFee = calcRolloverFee(oldPositionMargin, oldPositionTimestamp)
13661361 let doTransferFeeToStakers = if ((rolloverFee > 0))
13671362 then {
1368- let $t06432964388 = distributeFee(rolloverFee)
1369- let feeToStakers = $t06432964388._1
1370- let feeToVault = $t06432964388._2
1363+ let $t06444064499 = distributeFee(rolloverFee)
1364+ let feeToStakers = $t06444064499._1
1365+ let feeToVault = $t06444064499._2
13711366 let unstake = invoke(vaultAddress(), "withdrawLocked", [feeToStakers], nil)
13721367 if ((unstake == unstake))
13731368 then {
14081403 else isMarketClosed())
14091404 then throw("Invalid removeMargin parameters")
14101405 else {
1411- let $t06543165599 = getPosition(_trader)
1412- let oldPositionSize = $t06543165599._1
1413- let oldPositionMargin = $t06543165599._2
1414- let oldPositionOpenNotional = $t06543165599._3
1415- let oldPositionLstUpdCPF = $t06543165599._4
1416- let oldPositionTimestamp = $t06543165599._5
1417- let $t06560565854 = calcRemainMarginWithFundingPaymentAndRolloverFee(oldPositionSize, oldPositionMargin, oldPositionLstUpdCPF, oldPositionTimestamp, -(_amount))
1418- let remainMargin = $t06560565854._1
1419- let badDebt = $t06560565854._2
1420- let fundingPayment = $t06560565854._3
1421- let rolloverFee = $t06560565854._4
1406+ let $t06554265710 = getPosition(_trader)
1407+ let oldPositionSize = $t06554265710._1
1408+ let oldPositionMargin = $t06554265710._2
1409+ let oldPositionOpenNotional = $t06554265710._3
1410+ let oldPositionLstUpdCPF = $t06554265710._4
1411+ let oldPositionTimestamp = $t06554265710._5
1412+ let $t06571665965 = calcRemainMarginWithFundingPaymentAndRolloverFee(oldPositionSize, oldPositionMargin, oldPositionLstUpdCPF, oldPositionTimestamp, -(_amount))
1413+ let remainMargin = $t06571665965._1
1414+ let badDebt = $t06571665965._2
1415+ let fundingPayment = $t06571665965._3
1416+ let rolloverFee = $t06571665965._4
14221417 if ((badDebt != 0))
14231418 then throw("Invalid removed margin amount")
14241419 else {
14261421 if (!(requireMoreMarginRatio(marginRatio, initMarginRatio(), true)))
14271422 then throw(((("Too much margin removed: " + toString(marginRatio)) + " < ") + toString(initMarginRatio())))
14281423 else {
1429- let $t06624066299 = distributeFee(rolloverFee)
1430- let feeToStakers = $t06624066299._1
1431- let feeToVault = $t06624066299._2
1424+ let $t06635166410 = distributeFee(rolloverFee)
1425+ let feeToStakers = $t06635166410._1
1426+ let feeToVault = $t06635166410._2
14321427 let doTransferFeeToStakers = if ((rolloverFee > 0))
14331428 then {
14341429 let lockBadDebt = invoke(vaultAddress(), "exchangeFreeAndLocked", [-(feeToVault)], nil)
14751470 else isMarketClosed())
14761471 then throw("Invalid closePosition parameters")
14771472 else {
1478- let $t06783167971 = getPosition(_trader)
1479- let oldPositionSize = $t06783167971._1
1480- let oldPositionMargin = $t06783167971._2
1481- let oldPositionOpenNotional = $t06783167971._3
1482- let oldPositionLstUpdCPF = $t06783167971._4
1483- let $t06797768550 = internalClosePosition(_trader, _size, positionFee, _minQuoteAssetAmount, _addToMargin, true)
1484- let newPositionSize = $t06797768550._1
1485- let newPositionMargin = $t06797768550._2
1486- let newPositionOpenNotional = $t06797768550._3
1487- let newPositionLstUpdCPF = $t06797768550._4
1488- let positionBadDebt = $t06797768550._5
1489- let realizedPnl = $t06797768550._6
1490- let marginToTrader = $t06797768550._7
1491- let quoteAssetReserveAfter = $t06797768550._8
1492- let baseAssetReserveAfter = $t06797768550._9
1493- let totalPositionSizeAfter = $t06797768550._10
1494- let openInterestNotionalAfter = $t06797768550._11
1495- let totalLongAfter = $t06797768550._12
1496- let totalShortAfter = $t06797768550._13
1497- let totalLongOpenInterestAfter = $t06797768550._14
1498- let totalShortOpenInterestAfter = $t06797768550._15
1499- let realizedFee = $t06797768550._16
1473+ let $t06794268082 = getPosition(_trader)
1474+ let oldPositionSize = $t06794268082._1
1475+ let oldPositionMargin = $t06794268082._2
1476+ let oldPositionOpenNotional = $t06794268082._3
1477+ let oldPositionLstUpdCPF = $t06794268082._4
1478+ let $t06808868661 = internalClosePosition(_trader, _size, positionFee, _minQuoteAssetAmount, _addToMargin, true)
1479+ let newPositionSize = $t06808868661._1
1480+ let newPositionMargin = $t06808868661._2
1481+ let newPositionOpenNotional = $t06808868661._3
1482+ let newPositionLstUpdCPF = $t06808868661._4
1483+ let positionBadDebt = $t06808868661._5
1484+ let realizedPnl = $t06808868661._6
1485+ let marginToTrader = $t06808868661._7
1486+ let quoteAssetReserveAfter = $t06808868661._8
1487+ let baseAssetReserveAfter = $t06808868661._9
1488+ let totalPositionSizeAfter = $t06808868661._10
1489+ let openInterestNotionalAfter = $t06808868661._11
1490+ let totalLongAfter = $t06808868661._12
1491+ let totalShortAfter = $t06808868661._13
1492+ let totalLongOpenInterestAfter = $t06808868661._14
1493+ let totalShortOpenInterestAfter = $t06808868661._15
1494+ let realizedFee = $t06808868661._16
15001495 if ((positionBadDebt > 0))
15011496 then throw("Invalid closePosition parameters: bad debt")
15021497 else {
15091504 let unstake = invoke(vaultAddress(), "withdrawLocked", [withdrawAmount], nil)
15101505 if ((unstake == unstake))
15111506 then {
1512- let $t06906069119 = distributeFee(realizedFee)
1513- let feeToStakers = $t06906069119._1
1514- let feeToVault = $t06906069119._2
1507+ let $t06917169230 = distributeFee(realizedFee)
1508+ let feeToStakers = $t06917169230._1
1509+ let feeToVault = $t06917169230._2
15151510 let depositVault = invoke(vaultAddress(), "addFree", nil, [AttachedPayment(quoteAsset(), feeToVault)])
15161511 if ((depositVault == depositVault))
15171512 then {
15701565 else (DECIMAL_UNIT > partialLiquidationRatio())
15711566 let oldPositionSize = getPosition(_trader)._1
15721567 let positionSizeAbs = abs(oldPositionSize)
1573- let $t07143271755 = if (isPartialLiquidation)
1568+ let $t07154371866 = if (isPartialLiquidation)
15741569 then {
15751570 let liquidationSize = getPartialLiquidationAmount(_trader, oldPositionSize)
15761571 let liquidationRatio = divd(abs(liquidationSize), positionSizeAbs)
15771572 $Tuple2(liquidationRatio, abs(liquidationSize))
15781573 }
15791574 else $Tuple2(0, positionSizeAbs)
1580- let liquidationRatio = $t07143271755._1
1581- let liquidationSize = $t07143271755._2
1582- let $t07176172387 = internalClosePosition(_trader, if (isPartialLiquidation)
1575+ let liquidationRatio = $t07154371866._1
1576+ let liquidationSize = $t07154371866._2
1577+ let $t07187272498 = internalClosePosition(_trader, if (isPartialLiquidation)
15831578 then liquidationSize
15841579 else positionSizeAbs, liquidationFeeRatio(), 0, true, false)
1585- let newPositionSize = $t07176172387._1
1586- let newPositionMargin = $t07176172387._2
1587- let newPositionOpenNotional = $t07176172387._3
1588- let newPositionLstUpdCPF = $t07176172387._4
1589- let positionBadDebt = $t07176172387._5
1590- let realizedPnl = $t07176172387._6
1591- let marginToTrader = $t07176172387._7
1592- let quoteAssetReserveAfter = $t07176172387._8
1593- let baseAssetReserveAfter = $t07176172387._9
1594- let totalPositionSizeAfter = $t07176172387._10
1595- let openInterestNotionalAfter = $t07176172387._11
1596- let totalLongAfter = $t07176172387._12
1597- let totalShortAfter = $t07176172387._13
1598- let totalLongOpenInterestAfter = $t07176172387._14
1599- let totalShortOpenInterestAfter = $t07176172387._15
1600- let liquidationPenalty = $t07176172387._16
1580+ let newPositionSize = $t07187272498._1
1581+ let newPositionMargin = $t07187272498._2
1582+ let newPositionOpenNotional = $t07187272498._3
1583+ let newPositionLstUpdCPF = $t07187272498._4
1584+ let positionBadDebt = $t07187272498._5
1585+ let realizedPnl = $t07187272498._6
1586+ let marginToTrader = $t07187272498._7
1587+ let quoteAssetReserveAfter = $t07187272498._8
1588+ let baseAssetReserveAfter = $t07187272498._9
1589+ let totalPositionSizeAfter = $t07187272498._10
1590+ let openInterestNotionalAfter = $t07187272498._11
1591+ let totalLongAfter = $t07187272498._12
1592+ let totalShortAfter = $t07187272498._13
1593+ let totalLongOpenInterestAfter = $t07187272498._14
1594+ let totalShortOpenInterestAfter = $t07187272498._15
1595+ let liquidationPenalty = $t07187272498._16
16011596 let feeToLiquidator = (liquidationPenalty / 2)
16021597 let feeToVault = (liquidationPenalty - feeToLiquidator)
16031598 let ammBalance = (cbalance() - liquidationPenalty)
16531648 then throw(((("Invalid funding block timestamp: " + toString(lastTimestamp())) + " < ") + toString(fundingBlockTimestamp)))
16541649 else {
16551650 let underlyingPrice = getOraclePrice()
1656- let $t07435374415 = getFunding()
1657- let shortPremiumFraction = $t07435374415._1
1658- let longPremiumFraction = $t07435374415._2
1651+ let $t07446474526 = getFunding()
1652+ let shortPremiumFraction = $t07446474526._1
1653+ let longPremiumFraction = $t07446474526._2
16591654 updateFunding((fundingBlockTimestamp + fundingPeriodSeconds()), (latestLongCumulativePremiumFraction() + longPremiumFraction), (latestShortCumulativePremiumFraction() + shortPremiumFraction), divd(longPremiumFraction, underlyingPrice), divd(shortPremiumFraction, underlyingPrice))
16601655 }
16611656 }
16681663 func syncTerminalPriceToOracle () = {
16691664 let _qtAstR = qtAstR()
16701665 let _bsAstR = bsAstR()
1671- let $t07484774982 = getSyncTerminalPrice(getOraclePrice(), _qtAstR, _bsAstR)
1672- let newQuoteAssetWeight = $t07484774982._1
1673- let newBaseAssetWeight = $t07484774982._2
1674- let marginToVault = $t07484774982._3
1666+ let $t07495875093 = getSyncTerminalPrice(getOraclePrice(), _qtAstR, _bsAstR)
1667+ let newQuoteAssetWeight = $t07495875093._1
1668+ let newBaseAssetWeight = $t07495875093._2
1669+ let marginToVault = $t07495875093._3
16751670 let doExchangePnL = if ((marginToVault != 0))
16761671 then {
16771672 let doExchangePnL = invoke(vaultAddress(), "exchangeFreeAndLocked", [marginToVault], nil)
16811676 }
16821677 else nil
16831678 if ((doExchangePnL == doExchangePnL))
1684- then (updateAmmWeights(newQuoteAssetWeight, newBaseAssetWeight) ++ appendTwap(divd(muld(_qtAstR, newQuoteAssetWeight), muld(_bsAstR, newBaseAssetWeight))))
1679+ then ((updateBalance((cbalance() + marginToVault)) ++ updateAmmWeights(newQuoteAssetWeight, newBaseAssetWeight)) ++ appendTwap(divd(muld(_qtAstR, newQuoteAssetWeight), muld(_bsAstR, newBaseAssetWeight))))
16851680 else throw("Strict value is not equal to itself.")
16861681 }
16871682
16921687 let sync = invoke(this, "syncTerminalPriceToOracle", nil, nil)
16931688 if ((sync == sync))
16941689 then {
1695- let $t07555175675 = getPosition(_trader)
1696- let positionSize = $t07555175675._1
1697- let positionMargin = $t07555175675._2
1698- let pon = $t07555175675._3
1699- let positionLstUpdCPF = $t07555175675._4
1700- let positionTimestamp = $t07555175675._5
1701- let $t07567875779 = getPositionNotionalAndUnrealizedPnl(_trader, PNL_OPTION_SPOT)
1702- let positionNotional = $t07567875779._1
1703- let unrealizedPnl = $t07567875779._2
1704- let $t07578276006 = calcRemainMarginWithFundingPaymentAndRolloverFee(positionSize, positionMargin, positionLstUpdCPF, positionTimestamp, unrealizedPnl)
1705- let remainMargin = $t07578276006._1
1706- let badDebt = $t07578276006._2
1707- let fundingPayment = $t07578276006._3
1708- let rolloverFee = $t07578276006._4
1690+ let $t07571175835 = getPosition(_trader)
1691+ let positionSize = $t07571175835._1
1692+ let positionMargin = $t07571175835._2
1693+ let pon = $t07571175835._3
1694+ let positionLstUpdCPF = $t07571175835._4
1695+ let positionTimestamp = $t07571175835._5
1696+ let $t07583875939 = getPositionNotionalAndUnrealizedPnl(_trader, PNL_OPTION_SPOT)
1697+ let positionNotional = $t07583875939._1
1698+ let unrealizedPnl = $t07583875939._2
1699+ let $t07594276166 = calcRemainMarginWithFundingPaymentAndRolloverFee(positionSize, positionMargin, positionLstUpdCPF, positionTimestamp, unrealizedPnl)
1700+ let remainMargin = $t07594276166._1
1701+ let badDebt = $t07594276166._2
1702+ let fundingPayment = $t07594276166._3
1703+ let rolloverFee = $t07594276166._4
17091704 throw(((((((s(remainMargin) + s(fundingPayment)) + s(getMarginRatio(_trader))) + s(unrealizedPnl)) + s(badDebt)) + s(positionNotional)) + s(rolloverFee)))
17101705 }
17111706 else throw("Strict value is not equal to itself.")
17251720
17261721 @Callable(i)
17271722 func view_getTerminalAmmPrice () = {
1728- let $t07644276523 = getTerminalAmmState()
1729- let terminalQuoteAssetReserve = $t07644276523._1
1730- let terminalBaseAssetReserve = $t07644276523._2
1723+ let $t07660276683 = getTerminalAmmState()
1724+ let terminalQuoteAssetReserve = $t07660276683._1
1725+ let terminalBaseAssetReserve = $t07660276683._2
17311726 let price = divd(muld(terminalQuoteAssetReserve, qtAstW()), muld(terminalBaseAssetReserve, bsAstW()))
17321727 throw(toString(price))
17331728 }
17371732 @Callable(i)
17381733 func view_getFunding () = {
17391734 let underlyingPrice = getOraclePrice()
1740- let $t07673876800 = getFunding()
1741- let shortPremiumFraction = $t07673876800._1
1742- let longPremiumFraction = $t07673876800._2
1735+ let $t07689876960 = getFunding()
1736+ let shortPremiumFraction = $t07689876960._1
1737+ let longPremiumFraction = $t07689876960._2
17431738 let longFunding = divd(longPremiumFraction, underlyingPrice)
17441739 let shortFunding = divd(shortPremiumFraction, underlyingPrice)
17451740 throw((((s(longFunding) + s(shortFunding)) + s(getTwapSpotPrice())) + s(getOraclePrice())))
Full:
OldNewDifferences
11 {-# STDLIB_VERSION 6 #-}
22 {-# SCRIPT_TYPE ACCOUNT #-}
33 {-# CONTENT_TYPE DAPP #-}
44 let k_ora_key = "k_ora_key"
55
66 let k_ora_block_key = "k_ora_block_key"
77
88 let k_ora_open_key = "k_ora_open_key"
99
1010 let k_ora = "k_ora"
1111
1212 let k_balance = "k_balance"
1313
1414 let k_sequence = "k_sequence"
1515
1616 let k_positionSize = "k_positionSize"
1717
1818 let k_positionMargin = "k_positionMargin"
1919
2020 let k_positionOpenNotional = "k_positionOpenNotional"
2121
2222 let k_positionLastUpdatedCumulativePremiumFraction = "k_positionFraction"
2323
2424 let k_positionSequence = "k_positionSequence"
2525
2626 let k_positionAsset = "k_positionAsset"
2727
2828 let k_positionFee = "k_positionFee"
2929
3030 let k_positionLastUpdatedTimestamp = "k_positionTimestamp"
3131
3232 let k_initialized = "k_initialized"
3333
3434 let k_paused = "k_paused"
3535
3636 let k_closeOnly = "k_closeOnly"
3737
3838 let k_fee = "k_fee"
3939
4040 let k_rolloverFee = "k_rollover_fee"
4141
4242 let k_fundingPeriod = "k_fundingPeriod"
4343
4444 let k_initMarginRatio = "k_initMarginRatio"
4545
4646 let k_maintenanceMarginRatio = "k_mmr"
4747
4848 let k_liquidationFeeRatio = "k_liquidationFeeRatio"
4949
5050 let k_partialLiquidationRatio = "k_partLiquidationRatio"
5151
5252 let k_spreadLimit = "k_spreadLimit"
5353
5454 let k_maxPriceImpact = "k_maxPriceImpact"
5555
5656 let k_maxPriceSpread = "k_maxPriceSpread"
5757
5858 let k_maxOpenNotional = "k_maxOpenNotional"
5959
6060 let k_feeToStakersPercent = "k_feeToStakersPercent"
6161
6262 let k_maxOracleDelay = "k_maxOracleDelay"
6363
6464 let k_lastDataStr = "k_lastDataStr"
6565
6666 let k_lastMinuteId = "k_lastMinuteId"
6767
6868 let k_twapDataLastCumulativePrice = "k_twapDataLastCumulativePrice"
6969
7070 let k_twapDataLastPrice = "k_twapDataLastPrice"
7171
7272 let k_twapDataPreviousMinuteId = "k_twapDataPreviousMinuteId"
7373
7474 let k_latestLongCumulativePremiumFraction = "k_latestLongPremiumFraction"
7575
7676 let k_latestShortCumulativePremiumFraction = "k_latestShortPremiumFraction"
7777
7878 let k_nextFundingBlock = "k_nextFundingBlockMinTimestamp"
7979
8080 let k_longFundingRate = "k_longFundingRate"
8181
8282 let k_shortFundingRate = "k_shortFundingRate"
8383
8484 let k_quoteAssetReserve = "k_qtAstR"
8585
8686 let k_baseAssetReserve = "k_bsAstR"
8787
8888 let k_quoteAssetWeight = "k_qtAstW"
8989
9090 let k_baseAssetWeight = "k_bsAstW"
9191
9292 let k_totalPositionSize = "k_totalPositionSize"
9393
9494 let k_totalLongPositionSize = "k_totalLongPositionSize"
9595
9696 let k_totalShortPositionSize = "k_totalShortPositionSize"
9797
9898 let k_openInterestNotional = "k_openInterestNotional"
9999
100100 let k_openInterestShort = "k_openInterestShort"
101101
102102 let k_openInterestLong = "k_openInterestLong"
103103
104104 let k_coordinatorAddress = "k_coordinatorAddress"
105105
106106 let k_vault_address = "k_vault_address"
107107
108108 let k_admin_address = "k_admin_address"
109109
110110 let k_admin_public_key = "k_admin_public_key"
111111
112112 let k_quote_asset = "k_quote_asset"
113113
114114 let k_quote_staking = "k_quote_staking"
115115
116116 let k_staking_address = "k_staking_address"
117117
118118 let k_miner_address = "k_miner_address"
119119
120120 let k_orders_address = "k_orders_address"
121121
122122 let k_referral_address = "k_referral_address"
123123
124124 let k_exchange_address = "k_exchange_address"
125125
126126 let k_nft_manager_address = "k_nft_manager_address"
127127
128128 func toCompositeKey (_key,_address) = ((_key + "_") + _address)
129129
130130
131131 func coordinator () = valueOrErrorMessage(addressFromString(getStringValue(this, k_coordinatorAddress)), "Coordinator not set")
132132
133133
134134 func adminAddress () = addressFromString(getStringValue(coordinator(), k_admin_address))
135135
136136
137137 func adminPublicKey () = fromBase58String(getStringValue(coordinator(), k_admin_public_key))
138138
139139
140140 func quoteAsset () = fromBase58String(getStringValue(coordinator(), k_quote_asset))
141141
142142
143143 func quoteAssetStaking () = valueOrErrorMessage(addressFromString(getStringValue(coordinator(), k_quote_staking)), "Quote asset staking not set")
144144
145145
146146 func stakingAddress () = valueOrErrorMessage(addressFromString(getStringValue(coordinator(), k_staking_address)), "Staking not set")
147147
148148
149149 func vaultAddress () = valueOrErrorMessage(addressFromString(getStringValue(coordinator(), k_vault_address)), "Vault not set")
150150
151151
152152 func minerAddress () = valueOrErrorMessage(addressFromString(getStringValue(coordinator(), k_miner_address)), "Miner not set")
153153
154154
155155 func ordersAddress () = valueOrErrorMessage(addressFromString(getStringValue(coordinator(), k_orders_address)), "Orders not set")
156156
157157
158158 func referralAddress () = valueOrErrorMessage(addressFromString(getStringValue(coordinator(), k_referral_address)), "Referral not set")
159159
160160
161161 func nftManagerAddress () = valueOrErrorMessage(addressFromString(getStringValue(coordinator(), k_nft_manager_address)), "NFT Manager not set")
162162
163163
164164 func swapAddress () = valueOrErrorMessage(addressFromString(valueOrErrorMessage(getString(coordinator(), k_exchange_address), "No swap address")), "Invalid swap address")
165165
166166
167167 let k_token_param = "k_token_param"
168168
169169 let k_token_type = "k_token_type"
170170
171171 let FEE_REDUCTION_TOKEN_TYPE = "fee_reduction"
172172
173173 let DIR_LONG = 1
174174
175175 let DIR_SHORT = 2
176176
177177 let TWAP_INTERVAL = 15
178178
179179 let ORACLE_INTERVAL = 15
180180
181181 let SECONDS = 1000
182182
183183 let DECIMAL_NUMBERS = 6
184184
185185 let DECIMAL_UNIT = (1 * (((((10 * 10) * 10) * 10) * 10) * 10))
186186
187187 let MINUTES_IN_YEAR = (525600 * DECIMAL_UNIT)
188188
189189 let ONE_DAY = (86400 * DECIMAL_UNIT)
190190
191191 let ALL_FEES = 100
192192
193193 let PNL_OPTION_SPOT = 1
194194
195195 let PNL_OPTION_ORACLE = 2
196196
197197 func s (_x) = (toString(_x) + ",")
198198
199199
200200 func divd (_x,_y) = fraction(_x, DECIMAL_UNIT, _y, HALFEVEN)
201201
202202
203203 func muld (_x,_y) = fraction(_x, _y, DECIMAL_UNIT, HALFEVEN)
204204
205205
206206 func sqrtd (_x) = sqrt(_x, DECIMAL_NUMBERS, DECIMAL_NUMBERS, HALFEVEN)
207207
208208
209209 func powd (_x,_y) = pow(_x, DECIMAL_NUMBERS, _y, DECIMAL_NUMBERS, DECIMAL_NUMBERS, HALFEVEN)
210210
211211
212212 func bdivd (_x,_y) = fraction(_x, toBigInt(DECIMAL_UNIT), _y, HALFEVEN)
213213
214214
215215 func bmuld (_x,_y) = fraction(_x, _y, toBigInt(DECIMAL_UNIT), HALFEVEN)
216216
217217
218218 func bsqrtd (_x) = sqrtBigInt(_x, DECIMAL_NUMBERS, DECIMAL_NUMBERS, HALFEVEN)
219219
220220
221221 func bpowd (_x,_y) = pow(_x, DECIMAL_NUMBERS, _y, DECIMAL_NUMBERS, DECIMAL_NUMBERS, HALFEVEN)
222222
223223
224224 func abs (_x) = if ((_x > 0))
225225 then _x
226226 else -(_x)
227227
228228
229229 func vmax (_x,_y) = if ((_x >= _y))
230230 then _x
231231 else _y
232232
233233
234234 func listToStr (_list) = if ((size(_list) == 0))
235235 then ""
236236 else makeString(_list, ",")
237237
238238
239239 func strToList (_str) = if ((_str == ""))
240240 then nil
241241 else split(_str, ",")
242242
243243
244244 func pushToQueue (_list,_maxSize,_value) = if ((size(_list) > _maxSize))
245245 then (removeByIndex(_list, 0) :+ _value)
246246 else (_list :+ _value)
247247
248248
249249 func int (k) = valueOrErrorMessage(getInteger(this, k), ("no value for " + k))
250250
251251
252252 func intOr (k,def) = valueOrElse(getInteger(this, k), def)
253253
254254
255255 func strA (_address,_key) = {
256256 let val = valueOrErrorMessage(getString(_address, _key), ("No value for key " + _key))
257257 val
258258 }
259259
260260
261261 func intA (_address,_key) = {
262262 let val = valueOrErrorMessage(getInteger(_address, _key), ("No value for key " + _key))
263263 val
264264 }
265265
266266
267267 func cbalance () = int(k_balance)
268268
269269
270270 func fee () = int(k_fee)
271271
272272
273273 func rolloverFeeRate () = int(k_rolloverFee)
274274
275275
276276 func initMarginRatio () = int(k_initMarginRatio)
277277
278278
279279 func qtAstR () = int(k_quoteAssetReserve)
280280
281281
282282 func bsAstR () = int(k_baseAssetReserve)
283283
284284
285285 func qtAstW () = intOr(k_quoteAssetWeight, DECIMAL_UNIT)
286286
287287
288288 func bsAstW () = intOr(k_baseAssetWeight, DECIMAL_UNIT)
289289
290290
291291 func totalPositionSize () = int(k_totalPositionSize)
292292
293293
294294 func openInterestNotional () = int(k_openInterestNotional)
295295
296296
297297 func openInterestShort () = int(k_openInterestShort)
298298
299299
300300 func openInterestLong () = int(k_openInterestLong)
301301
302302
303303 func nextFundingBlockTimestamp () = int(k_nextFundingBlock)
304304
305305
306306 func fundingPeriodRaw () = int(k_fundingPeriod)
307307
308308
309309 func fundingPeriodDecimal () = (fundingPeriodRaw() * DECIMAL_UNIT)
310310
311311
312312 func fundingPeriodSeconds () = (fundingPeriodRaw() * SECONDS)
313313
314314
315315 func maintenanceMarginRatio () = int(k_maintenanceMarginRatio)
316316
317317
318318 func liquidationFeeRatio () = int(k_liquidationFeeRatio)
319319
320320
321321 func partialLiquidationRatio () = int(k_partialLiquidationRatio)
322322
323323
324324 func spreadLimit () = int(k_spreadLimit)
325325
326326
327327 func maxPriceImpact () = int(k_maxPriceImpact)
328328
329329
330330 func maxPriceSpread () = int(k_maxPriceSpread)
331331
332332
333333 func maxOpenNotional () = int(k_maxOpenNotional)
334334
335335
336336 func latestLongCumulativePremiumFraction () = int(k_latestLongCumulativePremiumFraction)
337337
338338
339339 func latestShortCumulativePremiumFraction () = int(k_latestShortCumulativePremiumFraction)
340340
341341
342342 func totalShortPositionSize () = int(k_totalShortPositionSize)
343343
344344
345345 func totalLongPositionSize () = int(k_totalLongPositionSize)
346346
347347
348348 func lastSequence () = intOr(k_sequence, 0)
349349
350350
351351 func feeToStakersPercent () = int(k_feeToStakersPercent)
352352
353353
354354 func maxOracleDelay () = int(k_maxOracleDelay)
355355
356356
357357 func lastTimestamp () = lastBlock.timestamp
358358
359359
360360 func getActualCaller (i) = valueOrElse(getString(ordersAddress(), "k_sender"), toString(i.caller))
361361
362362
363363 func requireMoreMarginRatio (_marginRatio,_baseMarginRatio,_largerThanOrEqualTo) = {
364364 let remainingMarginRatio = (_marginRatio - _baseMarginRatio)
365365 if (if (_largerThanOrEqualTo)
366366 then (0 > remainingMarginRatio)
367367 else false)
368368 then throw(((("Invalid margin: " + toString(_marginRatio)) + " < ") + toString(_baseMarginRatio)))
369369 else if (if (!(_largerThanOrEqualTo))
370370 then (remainingMarginRatio >= 0)
371371 else false)
372372 then throw(((("Invalid margin: " + toString(_marginRatio)) + " > ") + toString(_baseMarginRatio)))
373373 else true
374374 }
375375
376376
377377 func latestCumulativePremiumFraction (_positionSize) = if ((_positionSize == 0))
378378 then throw("Should not be called with _positionSize == 0")
379379 else if ((_positionSize > 0))
380380 then latestLongCumulativePremiumFraction()
381381 else latestShortCumulativePremiumFraction()
382382
383383
384384 func getPosition (_trader) = {
385385 let positionSizeOpt = getInteger(this, toCompositeKey(k_positionSize, _trader))
386386 match positionSizeOpt {
387387 case positionSize: Int =>
388388 $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)))
389389 case _ =>
390390 $Tuple5(0, 0, 0, 0, 0)
391391 }
392392 }
393393
394394
395395 func getPositionAsset (_trader) = {
396396 let positionAssetOpt = getString(this, toCompositeKey(k_positionAsset, _trader))
397397 match positionAssetOpt {
398398 case positionAsset: String =>
399399 positionAsset
400400 case _ =>
401401 toBase58String(quoteAsset())
402402 }
403403 }
404404
405405
406406 func getPositionFee (_trader) = {
407407 let positionFeeOpt = getInteger(this, toCompositeKey(k_positionFee, _trader))
408408 match positionFeeOpt {
409409 case positionFee: Int =>
410410 positionFee
411411 case _ =>
412412 fee()
413413 }
414414 }
415415
416416
417417 func requireOpenPosition (_trader) = if ((getPosition(_trader)._1 == 0))
418418 then throw("No open position")
419419 else true
420420
421421
422422 func initialized () = valueOrElse(getBoolean(this, k_initialized), false)
423423
424424
425425 func paused () = valueOrElse(getBoolean(this, k_paused), false)
426426
427427
428428 func closeOnly () = valueOrElse(getBoolean(this, k_closeOnly), false)
429429
430430
431431 func updateReserve (_isAdd,_quoteAssetAmount,_baseAssetAmount) = if (_isAdd)
432432 then {
433433 let newBase = (bsAstR() - _baseAssetAmount)
434434 if ((0 >= newBase))
435435 then throw("Tx lead to base asset reserve <= 0, revert")
436436 else $Tuple3((qtAstR() + _quoteAssetAmount), newBase, (totalPositionSize() + _baseAssetAmount))
437437 }
438438 else {
439439 let newQuote = (qtAstR() - _quoteAssetAmount)
440440 if ((0 >= newQuote))
441441 then throw("Tx lead to base quote reserve <= 0, revert")
442442 else $Tuple3(newQuote, (bsAstR() + _baseAssetAmount), (totalPositionSize() - _baseAssetAmount))
443443 }
444444
445445
446446 func calcInvariant (_qtAstR,_bsAstR) = {
447447 let bqtAstR = toBigInt(_qtAstR)
448448 let bbsAstR = toBigInt(_bsAstR)
449449 bmuld(bqtAstR, bbsAstR)
450450 }
451451
452452
453453 func swapInput (_isAdd,_quoteAssetAmount) = {
454454 let _qtAstR = qtAstR()
455455 let _bsAstR = bsAstR()
456456 let _qtAstW = qtAstW()
457457 let _bsAstW = bsAstW()
458458 let quoteAssetAmountAdjusted = divd(_quoteAssetAmount, _qtAstW)
459459 let k = calcInvariant(_qtAstR, _bsAstR)
460460 let quoteAssetReserveAfter = if (_isAdd)
461461 then (_qtAstR + quoteAssetAmountAdjusted)
462462 else (_qtAstR - quoteAssetAmountAdjusted)
463463 let baseAssetReserveAfter = toInt(bdivd(k, toBigInt(quoteAssetReserveAfter)))
464464 let amountBaseAssetBoughtAbs = abs((baseAssetReserveAfter - _bsAstR))
465465 let amountBaseAssetBought = if (_isAdd)
466466 then amountBaseAssetBoughtAbs
467467 else -(amountBaseAssetBoughtAbs)
468468 let $t01703617206 = updateReserve(_isAdd, quoteAssetAmountAdjusted, amountBaseAssetBoughtAbs)
469469 let quoteAssetReserveAfter1 = $t01703617206._1
470470 let baseAssetReserveAfter1 = $t01703617206._2
471471 let totalPositionSizeAfter1 = $t01703617206._3
472472 let priceBefore = divd(muld(_qtAstR, _qtAstW), muld(_bsAstR, _bsAstW))
473473 let marketPrice = divd(_quoteAssetAmount, amountBaseAssetBoughtAbs)
474474 let priceDiff = abs((priceBefore - marketPrice))
475475 let priceImpact = (DECIMAL_UNIT - divd(priceBefore, (priceBefore + priceDiff)))
476476 let maxPriceImpactValue = maxPriceImpact()
477477 if ((priceImpact > maxPriceImpactValue))
478478 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)))
479479 else $Tuple4(amountBaseAssetBought, quoteAssetReserveAfter1, baseAssetReserveAfter1, totalPositionSizeAfter1)
480480 }
481481
482482
483483 func calcRolloverFee (_oldPositionMargin,_oldPositionLastUpdatedTimestamp) = {
484484 let positionMinutes = ((((lastTimestamp() - _oldPositionLastUpdatedTimestamp) / 1000) / 60) * DECIMAL_UNIT)
485485 let rolloverFee = divd(muld(muld(_oldPositionMargin, positionMinutes), rolloverFeeRate()), MINUTES_IN_YEAR)
486486 rolloverFee
487487 }
488488
489489
490490 func calcRemainMarginWithFundingPaymentAndRolloverFee (_oldPositionSize,_oldPositionMargin,_oldPositionCumulativePremiumFraction,_oldPositionLastUpdatedTimestamp,_marginDelta) = {
491491 let fundingPayment = if ((_oldPositionSize != 0))
492492 then {
493493 let _latestCumulativePremiumFraction = latestCumulativePremiumFraction(_oldPositionSize)
494494 muld((_latestCumulativePremiumFraction - _oldPositionCumulativePremiumFraction), _oldPositionSize)
495495 }
496496 else 0
497497 let rolloverFee = calcRolloverFee(_oldPositionMargin, _oldPositionLastUpdatedTimestamp)
498498 let signedMargin = (((_marginDelta - rolloverFee) - fundingPayment) + _oldPositionMargin)
499499 let $t01946119588 = if ((0 > signedMargin))
500500 then $Tuple2(0, abs(signedMargin))
501501 else $Tuple2(abs(signedMargin), 0)
502502 let remainMargin = $t01946119588._1
503503 let badDebt = $t01946119588._2
504504 $Tuple4(remainMargin, badDebt, fundingPayment, rolloverFee)
505505 }
506506
507507
508508 func swapOutputWithReserves (_isAdd,_baseAssetAmount,_checkMaxPriceImpact,_quoteAssetReserve,_quoteAssetWeight,_baseAssetReserve,_baseAssetWeight) = {
509509 let priceBefore = divd(muld(_quoteAssetReserve, _quoteAssetWeight), muld(_baseAssetReserve, _baseAssetWeight))
510510 if ((_baseAssetAmount == 0))
511511 then throw("Invalid base asset amount")
512512 else {
513513 let k = calcInvariant(_quoteAssetReserve, _baseAssetReserve)
514514 let baseAssetPoolAmountAfter = if (_isAdd)
515515 then (_baseAssetReserve + _baseAssetAmount)
516516 else (_baseAssetReserve - _baseAssetAmount)
517517 let quoteAssetAfter = toInt(bdivd(k, toBigInt(baseAssetPoolAmountAfter)))
518518 let quoteAssetDelta = abs((quoteAssetAfter - _quoteAssetReserve))
519519 let quoteAssetSold = muld(quoteAssetDelta, _quoteAssetWeight)
520520 let maxPriceImpactValue = maxPriceImpact()
521521 let $t02085021012 = updateReserve(!(_isAdd), quoteAssetDelta, _baseAssetAmount)
522522 let quoteAssetReserveAfter1 = $t02085021012._1
523523 let baseAssetReserveAfter1 = $t02085021012._2
524524 let totalPositionSizeAfter1 = $t02085021012._3
525525 let marketPrice = divd(quoteAssetSold, _baseAssetAmount)
526526 let priceDiff = abs((priceBefore - marketPrice))
527527 let priceImpact = (DECIMAL_UNIT - divd(priceBefore, (priceBefore + priceDiff)))
528528 if (if ((priceImpact > maxPriceImpactValue))
529529 then _checkMaxPriceImpact
530530 else false)
531531 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)))
532532 else $Tuple7(quoteAssetSold, quoteAssetReserveAfter1, baseAssetReserveAfter1, totalPositionSizeAfter1, (totalLongPositionSize() - (if (_isAdd)
533533 then abs(_baseAssetAmount)
534534 else 0)), (totalShortPositionSize() - (if (!(_isAdd))
535535 then abs(_baseAssetAmount)
536536 else 0)), priceImpact)
537537 }
538538 }
539539
540540
541541 func swapOutput (_isAdd,_baseAssetAmount,_checkMaxPriceImpact) = swapOutputWithReserves(_isAdd, _baseAssetAmount, _checkMaxPriceImpact, qtAstR(), qtAstW(), bsAstR(), bsAstW())
542542
543543
544544 func getOraclePrice () = {
545545 let oracle = valueOrErrorMessage(addressFromString(valueOrErrorMessage(getString(this, k_ora), ("No value: " + k_ora))), "")
546546 let priceKey = valueOrElse(getString(this, k_ora_key), ("No value: " + k_ora_key))
547547 let lastValue = valueOrErrorMessage(getInteger(oracle, priceKey), ((("Can not get oracle price. Oracle: " + toString(oracle)) + " key: ") + priceKey))
548548 let blockKey = valueOrElse(getString(this, k_ora_block_key), "")
549549 if ((blockKey != ""))
550550 then {
551551 let currentBlock = lastBlock.height
552552 let lastOracleBlock = valueOrErrorMessage(getInteger(oracle, blockKey), ((("Can not get oracle block. Oracle: " + toString(oracle)) + " key: ") + blockKey))
553553 if (((currentBlock - lastOracleBlock) > maxOracleDelay()))
554554 then throw(((("Oracle stale data. Last oracle block: " + toString(lastOracleBlock)) + " current block: ") + toString(currentBlock)))
555555 else lastValue
556556 }
557557 else lastValue
558558 }
559559
560560
561561 func isMarketClosed () = {
562562 let oracle = valueOrErrorMessage(addressFromString(getStringValue(this, k_ora)), "")
563563 let openKey = valueOrElse(getString(this, k_ora_open_key), "")
564564 if ((openKey != ""))
565565 then {
566566 let isOpen = valueOrErrorMessage(getBoolean(oracle, openKey), ((("Can not get oracle is open/closed. Oracle: " + toString(oracle)) + " key: ") + openKey))
567567 !(isOpen)
568568 }
569569 else false
570570 }
571571
572572
573573 func absPriceDiff (_oraclePrice,_quoteAssetReserve,_baseAssetReserve,_qtAstW,_bsAstW) = {
574574 let priceAfter = divd(muld(_quoteAssetReserve, _qtAstW), muld(_baseAssetReserve, _bsAstW))
575575 let averagePrice = divd((_oraclePrice + priceAfter), (2 * DECIMAL_UNIT))
576576 let absPriceDiff = divd(abs((_oraclePrice - priceAfter)), averagePrice)
577577 absPriceDiff
578578 }
579579
580580
581581 func requireNotOverSpreadLimit (_quoteAssetReserve,_baseAssetReserve) = {
582582 let oraclePrice = getOraclePrice()
583583 let _qtAstW = qtAstW()
584584 let _bsAstW = bsAstW()
585585 let absPriceDiffBefore = absPriceDiff(oraclePrice, qtAstR(), bsAstR(), _qtAstW, _bsAstW)
586586 let absPriceDiffAfter = absPriceDiff(oraclePrice, _quoteAssetReserve, _baseAssetReserve, _qtAstW, _bsAstW)
587587 if (if ((absPriceDiffAfter > maxPriceSpread()))
588588 then (absPriceDiffAfter > absPriceDiffBefore)
589589 else false)
590590 then throw(((("Price spread " + toString(absPriceDiffAfter)) + " > max price spread ") + toString(maxPriceSpread())))
591591 else true
592592 }
593593
594594
595595 func requireNotOverMaxOpenNotional (_longOpenNotional,_shortOpenNotional) = {
596596 let _maxOpenNotional = maxOpenNotional()
597597 if ((_longOpenNotional > _maxOpenNotional))
598598 then throw(((("Long open notional " + toString(_longOpenNotional)) + " > max open notional ") + toString(_maxOpenNotional)))
599599 else if ((_shortOpenNotional > _maxOpenNotional))
600600 then throw(((("Short open notional " + toString(_shortOpenNotional)) + " > max open notional ") + toString(_maxOpenNotional)))
601601 else true
602602 }
603603
604604
605605 func getSpotPrice () = {
606606 let _quoteAssetReserve = qtAstR()
607607 let _baseAssetReserve = bsAstR()
608608 let _qtAstW = qtAstW()
609609 let _bsAstW = bsAstW()
610610 divd(muld(_quoteAssetReserve, _qtAstW), muld(_baseAssetReserve, _bsAstW))
611611 }
612612
613613
614614 func isOverFluctuationLimit () = {
615615 let oraclePrice = getOraclePrice()
616616 let currentPrice = getSpotPrice()
617617 (divd(abs((oraclePrice - currentPrice)), oraclePrice) > spreadLimit())
618618 }
619619
620620
621621 func getPositionAdjustedOpenNotional (_positionSize,_option,_quoteAssetReserve,_quoteAssetWeight,_baseAssetReserve,_baseAssetWeight) = {
622622 let positionSizeAbs = abs(_positionSize)
623623 let isShort = (0 > _positionSize)
624624 let positionNotional = if ((_option == PNL_OPTION_SPOT))
625625 then {
626626 let outPositionNotional = swapOutputWithReserves(!(isShort), positionSizeAbs, false, _quoteAssetReserve, _quoteAssetWeight, _baseAssetReserve, _baseAssetWeight)._1
627627 outPositionNotional
628628 }
629629 else muld(positionSizeAbs, getOraclePrice())
630630 positionNotional
631631 }
632632
633633
634634 func getPositionNotionalAndUnrealizedPnlByValues (_positionSize,_positionOpenNotional,_quoteAssetReserve,_quoteAssetWeight,_baseAssetReserve,_baseAssetWeight,_option) = if ((_positionSize == 0))
635635 then throw("Invalid position size")
636636 else {
637637 let isShort = (0 > _positionSize)
638638 let positionNotional = getPositionAdjustedOpenNotional(_positionSize, _option, _quoteAssetReserve, _quoteAssetWeight, _baseAssetReserve, _baseAssetWeight)
639639 let unrealizedPnl = if (isShort)
640640 then (_positionOpenNotional - positionNotional)
641641 else (positionNotional - _positionOpenNotional)
642642 $Tuple2(positionNotional, unrealizedPnl)
643643 }
644644
645645
646646 func getPositionNotionalAndUnrealizedPnl (_trader,_option) = {
647647 let $t02857728705 = getPosition(_trader)
648648 let positionSize = $t02857728705._1
649649 let positionMargin = $t02857728705._2
650650 let positionOpenNotional = $t02857728705._3
651651 let positionLstUpdCPF = $t02857728705._4
652652 getPositionNotionalAndUnrealizedPnlByValues(positionSize, positionOpenNotional, qtAstR(), qtAstW(), bsAstR(), bsAstW(), _option)
653653 }
654654
655655
656656 func calcMarginRatio (_remainMargin,_badDebt,_positionNotional) = divd((_remainMargin - _badDebt), _positionNotional)
657657
658658
659659 func getMarginRatioByOption (_trader,_option) = {
660660 let $t02922029361 = getPosition(_trader)
661661 let positionSize = $t02922029361._1
662662 let positionMargin = $t02922029361._2
663663 let pon = $t02922029361._3
664664 let positionLastUpdatedCPF = $t02922029361._4
665665 let positionTimestamp = $t02922029361._5
666666 let $t02936729460 = getPositionNotionalAndUnrealizedPnl(_trader, _option)
667667 let positionNotional = $t02936729460._1
668668 let unrealizedPnl = $t02936729460._2
669669 let $t02946529677 = calcRemainMarginWithFundingPaymentAndRolloverFee(positionSize, positionMargin, positionLastUpdatedCPF, positionTimestamp, unrealizedPnl)
670670 let remainMargin = $t02946529677._1
671671 let badDebt = $t02946529677._2
672672 calcMarginRatio(remainMargin, badDebt, positionNotional)
673673 }
674674
675675
676676 func getMarginRatio (_trader) = getMarginRatioByOption(_trader, PNL_OPTION_SPOT)
677677
678678
679679 func getPartialLiquidationAmount (_trader,_positionSize) = {
680680 let maximumRatio = vmax(partialLiquidationRatio(), (DECIMAL_UNIT - divd(getMarginRatio(_trader), maintenanceMarginRatio())))
681681 let maxExchangedPositionSize = muld(abs(_positionSize), maximumRatio)
682682 let swapResult = swapOutput((_positionSize > 0), maxExchangedPositionSize, false)
683683 let maxExchangedQuoteAssetAmount = swapResult._1
684684 let priceImpact = swapResult._7
685685 if ((maxPriceImpact() > priceImpact))
686686 then maxExchangedPositionSize
687687 else muld(abs(_positionSize), partialLiquidationRatio())
688688 }
689689
690690
691691 func internalClosePosition (_trader,_size,_fee,_minQuoteAssetAmount,_addToMargin,_checkMaxPriceImpact) = {
692692 let $t03072130877 = getPosition(_trader)
693693 let oldPositionSize = $t03072130877._1
694694 let oldPositionMargin = $t03072130877._2
695695 let oldPositionOpenNotional = $t03072130877._3
696696 let oldPositionLstUpdCPF = $t03072130877._4
697697 let oldPositionTimestamp = $t03072130877._5
698698 let isLongPosition = (oldPositionSize > 0)
699699 let absOldPositionSize = abs(oldPositionSize)
700700 if (if ((absOldPositionSize >= _size))
701701 then (_size > 0)
702702 else false)
703703 then {
704704 let isPartialClose = (absOldPositionSize > _size)
705705 let $t03116931620 = swapOutput((oldPositionSize > 0), _size, _checkMaxPriceImpact)
706706 let exchangedQuoteAssetAmount = $t03116931620._1
707707 let quoteAssetReserveAfter = $t03116931620._2
708708 let baseAssetReserveAfter = $t03116931620._3
709709 let totalPositionSizeAfter = $t03116931620._4
710710 let exchangedPositionSize = if ((oldPositionSize > 0))
711711 then -(_size)
712712 else _size
713713 let $t03183532042 = getPositionNotionalAndUnrealizedPnl(_trader, PNL_OPTION_SPOT)
714714 let oldPositionNotional = $t03183532042._1
715715 let unrealizedPnl = $t03183532042._2
716716 let realizedRatio = divd(abs(exchangedPositionSize), absOldPositionSize)
717717 let realizedPnl = muld(unrealizedPnl, realizedRatio)
718718 let $t03238332629 = calcRemainMarginWithFundingPaymentAndRolloverFee(oldPositionSize, oldPositionMargin, oldPositionLstUpdCPF, oldPositionTimestamp, unrealizedPnl)
719719 let remainMarginBefore = $t03238332629._1
720720 let x1 = $t03238332629._2
721721 let x2 = $t03238332629._3
722722 let rolloverFee = $t03238332629._4
723723 let positionBadDebt = calcRemainMarginWithFundingPaymentAndRolloverFee(oldPositionSize, oldPositionMargin, oldPositionLstUpdCPF, oldPositionTimestamp, realizedPnl)._2
724724 let realizedCloseFee = muld(muld(oldPositionNotional, realizedRatio), _fee)
725725 let unrealizedPnlAfter = (unrealizedPnl - realizedPnl)
726726 let remainOpenNotional = if ((oldPositionSize > 0))
727727 then ((oldPositionNotional - exchangedQuoteAssetAmount) - unrealizedPnlAfter)
728728 else ((unrealizedPnlAfter + oldPositionNotional) - exchangedQuoteAssetAmount)
729729 let newPositionSize = (oldPositionSize + exchangedPositionSize)
730730 let $t03403534421 = if ((newPositionSize == 0))
731731 then $Tuple2(0, 0)
732732 else $Tuple2(abs(remainOpenNotional), latestCumulativePremiumFraction(newPositionSize))
733733 let newPositionOpenNotional = $t03403534421._1
734734 let newPositionLstUpdCPF = $t03403534421._2
735735 let openNotionalDelta = (oldPositionOpenNotional - newPositionOpenNotional)
736736 let marginRatio = getMarginRatioByOption(_trader, PNL_OPTION_SPOT)
737737 let newPositionMarginWithSameRatio = if ((oldPositionSize > 0))
738738 then (muld((newPositionOpenNotional + unrealizedPnlAfter), marginRatio) - unrealizedPnlAfter)
739739 else (muld((newPositionOpenNotional - unrealizedPnlAfter), marginRatio) - unrealizedPnlAfter)
740740 let marginToTraderRaw = ((remainMarginBefore - (newPositionMarginWithSameRatio + unrealizedPnlAfter)) - realizedCloseFee)
741741 let marginToTrader = if ((0 > marginToTraderRaw))
742742 then throw("Invalid internalClosePosition params: unable to pay fee")
743743 else marginToTraderRaw
744744 let newPositionMargin = if (_addToMargin)
745745 then (newPositionMarginWithSameRatio + marginToTrader)
746746 else newPositionMarginWithSameRatio
747747 if (if ((_minQuoteAssetAmount != 0))
748748 then (_minQuoteAssetAmount > exchangedQuoteAssetAmount)
749749 else false)
750750 then throw(((("Limit error: " + toString(exchangedQuoteAssetAmount)) + " < ") + toString(_minQuoteAssetAmount)))
751751 else $Tuple17(newPositionSize, newPositionMargin, newPositionOpenNotional, newPositionLstUpdCPF, positionBadDebt, realizedPnl, if (if (_addToMargin)
752752 then isPartialClose
753753 else false)
754754 then 0
755755 else marginToTrader, quoteAssetReserveAfter, baseAssetReserveAfter, totalPositionSizeAfter, (openInterestNotional() - openNotionalDelta), (totalLongPositionSize() - (if (isLongPosition)
756756 then abs(exchangedPositionSize)
757757 else 0)), (totalShortPositionSize() - (if (!(isLongPosition))
758758 then abs(exchangedPositionSize)
759759 else 0)), (openInterestLong() - (if (isLongPosition)
760760 then openNotionalDelta
761761 else 0)), (openInterestShort() - (if (!(isLongPosition))
762762 then openNotionalDelta
763763 else 0)), (realizedCloseFee + rolloverFee), exchangedQuoteAssetAmount)
764764 }
765765 else throw("Invalid internalClosePosition params: invalid position size")
766766 }
767767
768768
769769 func getTwapSpotPrice () = {
770770 let minuteId = ((lastTimestamp() / 1000) / 60)
771771 let startMinuteId = (minuteId - TWAP_INTERVAL)
772772 let listStr = valueOrElse(getString(this, k_lastDataStr), "")
773773 let list = split(listStr, ",")
774774 func filterFn (accumulator,next) = if ((startMinuteId >= valueOrErrorMessage(parseInt(next), ("getTwapSpotPrice: invalid int: " + listStr))))
775775 then (accumulator :+ parseIntValue(next))
776776 else accumulator
777777
778778 let listF = {
779779 let $l = list
780780 let $s = size($l)
781781 let $acc0 = nil
782782 func $f0_1 ($a,$i) = if (($i >= $s))
783783 then $a
784784 else filterFn($a, $l[$i])
785785
786786 func $f0_2 ($a,$i) = if (($i >= $s))
787787 then $a
788788 else throw("List size exceeds 20")
789789
790790 $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)
791791 }
792792 let maxIndex = if ((size(listF) > 0))
793793 then max(listF)
794794 else valueOrErrorMessage(parseInt(list[0]), ("getTwapSpotPrice: invalid int: " + listStr))
795795 let lastMinuteId = valueOrElse(getInteger(this, k_lastMinuteId), 0)
796796 let endLastCumulativePrice = valueOrElse(getInteger(this, ((k_twapDataLastCumulativePrice + "_") + toString(lastMinuteId))), 0)
797797 let endLastPrice = valueOrElse(getInteger(this, ((k_twapDataLastPrice + "_") + toString(lastMinuteId))), 0)
798798 let nowCumulativePrice = (endLastCumulativePrice + ((minuteId - lastMinuteId) * endLastPrice))
799799 let startLastCumulativePrice = valueOrElse(getInteger(this, ((k_twapDataLastCumulativePrice + "_") + toString(maxIndex))), 0)
800800 let startLastPrice = valueOrElse(getInteger(this, ((k_twapDataLastPrice + "_") + toString(maxIndex))), 0)
801801 let startCumulativePrice = (startLastCumulativePrice + ((startMinuteId - maxIndex) * startLastPrice))
802802 ((nowCumulativePrice - startCumulativePrice) / TWAP_INTERVAL)
803803 }
804804
805805
806806 func getTerminalAmmState () = {
807807 let _positionSize = totalPositionSize()
808808 if ((_positionSize == 0))
809809 then $Tuple2(qtAstR(), bsAstR())
810810 else {
811811 let direction = (_positionSize > 0)
812812 let $t03902439203 = swapOutput(direction, abs(_positionSize), false)
813813 let currentNetMarketValue = $t03902439203._1
814814 let terminalQuoteAssetReserve = $t03902439203._2
815815 let terminalBaseAssetReserve = $t03902439203._3
816816 $Tuple2(terminalQuoteAssetReserve, terminalBaseAssetReserve)
817817 }
818818 }
819819
820820
821821 func getQuoteAssetWeight (baseAssetReserve,totalPositionSize,quoteAssetReserve,targetPrice) = {
822822 let b = toBigInt(baseAssetReserve)
823823 let sz = toBigInt(totalPositionSize)
824824 let q = toBigInt(quoteAssetReserve)
825825 let p = toBigInt(targetPrice)
826826 let k = bmuld(q, b)
827827 let newB = (b + sz)
828828 let newQ = bdivd(k, newB)
829829 let z = bdivd(newQ, newB)
830830 let result = bdivd(p, z)
831831 toInt(result)
832832 }
833833
834834
835835 func getSyncTerminalPrice (_terminalPrice,_qtAstR,_bsAstR) = {
836836 let _positionSize = totalPositionSize()
837837 if ((_positionSize == 0))
838838 then {
839839 let newQtAstW = divd(muld(_terminalPrice, _bsAstR), _qtAstR)
840840 $Tuple3(newQtAstW, DECIMAL_UNIT, 0)
841841 }
842842 else {
843843 let direction = (_positionSize > 0)
844844 let currentNetMarketValue = swapOutput(direction, abs(_positionSize), false)._1
845845 let newQtAstW = getQuoteAssetWeight(_bsAstR, _positionSize, _qtAstR, _terminalPrice)
846846 let newBsAstW = DECIMAL_UNIT
847847 let marginToVault = getPositionNotionalAndUnrealizedPnlByValues(_positionSize, currentNetMarketValue, _qtAstR, newQtAstW, _bsAstR, newBsAstW, PNL_OPTION_SPOT)._2
848848 $Tuple3(newQtAstW, newBsAstW, marginToVault)
849849 }
850850 }
851851
852852
853853 func getFunding () = {
854854 let underlyingPrice = getOraclePrice()
855855 let spotTwapPrice = getTwapSpotPrice()
856856 let premium = (spotTwapPrice - underlyingPrice)
857857 if (if (if ((totalShortPositionSize() == 0))
858858 then true
859859 else (totalLongPositionSize() == 0))
860860 then true
861861 else isMarketClosed())
862862 then $Tuple2(0, 0)
863863 else if ((0 > premium))
864864 then {
865865 let shortPremiumFraction = divd(muld(premium, fundingPeriodDecimal()), ONE_DAY)
866866 let longPremiumFraction = divd(muld(shortPremiumFraction, totalShortPositionSize()), totalLongPositionSize())
867867 $Tuple2(shortPremiumFraction, longPremiumFraction)
868868 }
869869 else {
870870 let longPremiumFraction = divd(muld(premium, fundingPeriodDecimal()), ONE_DAY)
871871 let shortPremiumFraction = divd(muld(longPremiumFraction, totalLongPositionSize()), totalShortPositionSize())
872872 $Tuple2(shortPremiumFraction, longPremiumFraction)
873873 }
874874 }
875875
876876
877877 func getAdjustedFee (_artifactId,_baseFeeDiscount) = {
878878 let baseFeeRaw = fee()
879879 let baseFee = muld(baseFeeRaw, _baseFeeDiscount)
880880 let $t04206442559 = if ((_artifactId != ""))
881881 then {
882882 let artifactKind = strA(nftManagerAddress(), toCompositeKey(k_token_type, _artifactId))
883883 if ((artifactKind == FEE_REDUCTION_TOKEN_TYPE))
884884 then {
885885 let reduction = intA(nftManagerAddress(), toCompositeKey(k_token_param, _artifactId))
886886 let adjustedFee = muld(baseFee, reduction)
887887 $Tuple2(adjustedFee, true)
888888 }
889889 else throw("Invalid attached artifact")
890890 }
891891 else $Tuple2(baseFee, false)
892892 let adjustedFee = $t04206442559._1
893893 let burnArtifact = $t04206442559._2
894894 $Tuple2(adjustedFee, burnArtifact)
895895 }
896896
897897
898898 func isSameAssetOrNoPosition (_trader,_assetId) = {
899899 let oldPositionSize = getPosition(_trader)._1
900900 if ((oldPositionSize == 0))
901901 then true
902902 else (getPositionAsset(_trader) == _assetId)
903903 }
904904
905905
906906 func isSameAsset (_trader,_assetId) = (getPositionAsset(_trader) == _assetId)
907907
908908
909909 func getForTraderWithArtifact (_trader,_artifactId) = {
910910 let doGetFeeDiscount = invoke(minerAddress(), "computeFeeDiscount", [_trader], nil)
911911 if ((doGetFeeDiscount == doGetFeeDiscount))
912912 then {
913913 let feeDiscount = match doGetFeeDiscount {
914914 case x: Int =>
915915 x
916916 case _ =>
917917 throw("Invalid computeFeeDiscount result")
918918 }
919919 let $t04323943313 = getAdjustedFee(_artifactId, feeDiscount)
920920 let adjustedFee = $t04323943313._1
921921 let burnArtifact = $t04323943313._2
922922 $Tuple2(adjustedFee, burnArtifact)
923923 }
924924 else throw("Strict value is not equal to itself.")
925925 }
926926
927927
928928 func getArtifactId (i) = {
929929 let artifactId = if ((size(i.payments) > 1))
930930 then toBase58String(valueOrErrorMessage(i.payments[1].assetId, "Invalid artifactId"))
931931 else ""
932932 artifactId
933933 }
934934
935935
936936 func distributeFee (_feeAmount) = {
937937 let feeToStakers = muld(_feeAmount, feeToStakersPercent())
938938 let feeToVault = (_feeAmount - feeToStakers)
939939 $Tuple2(feeToStakers, feeToVault)
940940 }
941941
942942
943943 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)]
944944
945945
946946 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)]
947947
948948
949949 func incrementPositionSequenceNumber (_isNewPosition,_address) = if (_isNewPosition)
950950 then {
951951 let currentSequence = lastSequence()
952952 [IntegerEntry(toCompositeKey(k_positionSequence, _address), (currentSequence + 1)), IntegerEntry(k_sequence, (currentSequence + 1))]
953953 }
954954 else nil
955955
956956
957957 func updatePositionFee (_isNewPosition,_address,_fee) = if (_isNewPosition)
958958 then [IntegerEntry(toCompositeKey(k_positionFee, _address), _fee)]
959959 else nil
960960
961961
962962 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)]
963963
964964
965965 func appendTwap (_price) = {
966966 let minuteId = ((lastTimestamp() / 1000) / 60)
967967 let previousMinuteId = valueOrElse(getInteger(this, k_lastMinuteId), 0)
968968 if ((previousMinuteId > minuteId))
969969 then throw("TWAP out-of-order")
970970 else {
971971 let lastMinuteId = if ((previousMinuteId == 0))
972972 then minuteId
973973 else previousMinuteId
974974 if ((minuteId > previousMinuteId))
975975 then {
976976 let prevCumulativePrice = valueOrElse(getInteger(this, ((k_twapDataLastCumulativePrice + "_") + toString(previousMinuteId))), 0)
977977 let prevPrice = valueOrElse(getInteger(this, ((k_twapDataLastPrice + "_") + toString(previousMinuteId))), _price)
978978 let lastCumulativePrice = (prevCumulativePrice + ((minuteId - lastMinuteId) * prevPrice))
979979 let list = pushToQueue(strToList(valueOrElse(getString(this, k_lastDataStr), "")), TWAP_INTERVAL, toString(minuteId))
980980 [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))]
981981 }
982982 else {
983983 let twapDataPreviousMinuteId = valueOrElse(getInteger(this, toCompositeKey(k_twapDataPreviousMinuteId, toString(minuteId))), 0)
984984 let prevCumulativePrice = valueOrElse(getInteger(this, toCompositeKey(k_twapDataLastCumulativePrice, toString(twapDataPreviousMinuteId))), 0)
985985 let prevPrice = valueOrElse(getInteger(this, toCompositeKey(k_twapDataLastPrice, toString(twapDataPreviousMinuteId))), _price)
986986 let lastCumulativePrice = (prevCumulativePrice + ((minuteId - twapDataPreviousMinuteId) * prevPrice))
987987 [IntegerEntry(toCompositeKey(k_twapDataLastCumulativePrice, toString(minuteId)), lastCumulativePrice), IntegerEntry(toCompositeKey(k_twapDataLastPrice, toString(minuteId)), _price)]
988988 }
989989 }
990990 }
991991
992992
993993 func updateAmmReserves (_qtAstR,_bsAstR) = [IntegerEntry(k_quoteAssetReserve, _qtAstR), IntegerEntry(k_baseAssetReserve, _bsAstR)]
994994
995995
996996 func updateAmmWeights (_qtAstW,_bsAstW) = [IntegerEntry(k_quoteAssetWeight, _qtAstW), IntegerEntry(k_baseAssetWeight, _bsAstW)]
997997
998998
999999 func updateAmm (_qtAstR,_bsAstR,_totalPositionSizeAfter,_openInterestNotional,_totalLongPositionSize,_totalShortPositionSize,_totalLongOpenNotional,_totalShortOpenNotional) = {
10001000 let _qtAstW = qtAstW()
10011001 let _bsAstW = bsAstW()
10021002 if (((_totalLongPositionSize - _totalShortPositionSize) != _totalPositionSizeAfter))
10031003 then throw(((((("Invalid AMM state data: " + toString(_totalLongPositionSize)) + " + ") + toString(_totalShortPositionSize)) + " != ") + toString(_totalPositionSizeAfter)))
10041004 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))))
10051005 }
10061006
10071007
10081008 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))]
10091009
10101010
10111011 func withdraw (_address,_amount) = {
10121012 let balance = assetBalance(this, quoteAsset())
10131013 if ((_amount > balance))
10141014 then throw(((("Unable to withdraw " + toString(_amount)) + " from contract balance ") + toString(balance)))
10151015 else [ScriptTransfer(_address, _amount, quoteAsset())]
10161016 }
10171017
10181018
10191019 func updateBalance (i) = if ((0 > i))
10201020 then throw("Balance")
10211021 else [IntegerEntry(k_balance, i)]
10221022
10231023
10241024 func transferFee (i) = [ScriptTransfer(stakingAddress(), i, quoteAsset())]
10251025
10261026
10271027 func doBurnArtifact (_burnArtifact,i) = if (_burnArtifact)
10281028 then [Burn(valueOrErrorMessage(i.payments[1].assetId, "Invalid artifact"), 1)]
10291029 else nil
10301030
10311031
10321032 @Callable(i)
10331033 func pause () = if ((i.caller != adminAddress()))
10341034 then throw("Invalid pause params")
10351035 else [BooleanEntry(k_paused, true)]
10361036
10371037
10381038
10391039 @Callable(i)
10401040 func unpause () = if ((i.caller != adminAddress()))
10411041 then throw("Invalid unpause params")
10421042 else [BooleanEntry(k_paused, false)]
10431043
10441044
10451045
10461046 @Callable(i)
10471047 func setCloseOnly () = if ((i.caller != adminAddress()))
10481048 then throw("Invalid setCloseOnly params")
10491049 else [BooleanEntry(k_closeOnly, true)]
10501050
10511051
10521052
10531053 @Callable(i)
10541054 func unsetCloseOnly () = if ((i.caller != adminAddress()))
10551055 then throw("Invalid unsetCloseOnly params")
10561056 else [BooleanEntry(k_closeOnly, false)]
10571057
10581058
10591059
10601060 @Callable(i)
10611061 func addLiquidity (_quoteAssetAmount) = if (if ((i.caller != adminAddress()))
10621062 then true
10631063 else (0 >= _quoteAssetAmount))
10641064 then throw("Invalid addLiquidity params")
10651065 else {
10661066 let _qtAstR = qtAstR()
10671067 let _bsAstR = bsAstR()
10681068 let _qtAstW = qtAstW()
10691069 let _bsAstW = bsAstW()
10701070 let price = divd(muld(_qtAstR, _qtAstW), muld(_bsAstR, _bsAstW))
10711071 let qtAstRAfter = (_qtAstR + _quoteAssetAmount)
10721072 let baseAssetAmountToAdd = (divd(muld(qtAstRAfter, _qtAstW), price) - _bsAstR)
10731073 let bsAstRAfter = (_bsAstR + baseAssetAmountToAdd)
10741074 let $t05272052871 = getSyncTerminalPrice(getOraclePrice(), qtAstRAfter, bsAstRAfter)
10751075 let newQuoteAssetWeight = $t05272052871._1
10761076 let newBaseAssetWeight = $t05272052871._2
10771077 let marginToVault = $t05272052871._3
10781078 let doExchangePnL = if ((marginToVault != 0))
10791079 then {
10801080 let doExchangePnL = invoke(vaultAddress(), "exchangeFreeAndLocked", [marginToVault], nil)
10811081 if ((doExchangePnL == doExchangePnL))
10821082 then nil
10831083 else throw("Strict value is not equal to itself.")
10841084 }
10851085 else nil
10861086 if ((doExchangePnL == doExchangePnL))
10871087 then (updateAmmReserves(qtAstRAfter, bsAstRAfter) ++ updateAmmWeights(newQuoteAssetWeight, newBaseAssetWeight))
10881088 else throw("Strict value is not equal to itself.")
10891089 }
10901090
10911091
10921092
10931093 @Callable(i)
10941094 func removeLiquidity (_quoteAssetAmount) = if (if ((i.caller != adminAddress()))
10951095 then true
10961096 else (_quoteAssetAmount >= 0))
10971097 then throw("Invalid removeLiquidity params")
10981098 else {
10991099 let _qtAstR = qtAstR()
11001100 let _bsAstR = bsAstR()
11011101 let _qtAstW = qtAstW()
11021102 let _bsAstW = bsAstW()
11031103 let price = divd(muld(_qtAstR, _qtAstW), muld(_bsAstR, _bsAstW))
11041104 let qtAstRAfter = (_qtAstR - _quoteAssetAmount)
11051105 let baseAssetAmountToRemove = abs((divd(muld(qtAstRAfter, _qtAstW), price) - _bsAstR))
11061106 let bsAstRAfter = (_bsAstR - baseAssetAmountToRemove)
11071107 let $t05380353954 = getSyncTerminalPrice(getOraclePrice(), qtAstRAfter, bsAstRAfter)
11081108 let newQuoteAssetWeight = $t05380353954._1
11091109 let newBaseAssetWeight = $t05380353954._2
11101110 let marginToVault = $t05380353954._3
11111111 let doExchangePnL = if ((marginToVault != 0))
11121112 then {
11131113 let doExchangePnL = invoke(vaultAddress(), "exchangeFreeAndLocked", [marginToVault], nil)
11141114 if ((doExchangePnL == doExchangePnL))
11151115 then nil
11161116 else throw("Strict value is not equal to itself.")
11171117 }
11181118 else nil
11191119 if ((doExchangePnL == doExchangePnL))
11201120 then (updateAmmReserves(qtAstRAfter, bsAstRAfter) ++ updateAmmWeights(newQuoteAssetWeight, newBaseAssetWeight))
11211121 else throw("Strict value is not equal to itself.")
11221122 }
11231123
11241124
11251125
11261126 @Callable(i)
11271127 func changeSettings (_initMarginRatio,_mmr,_liquidationFeeRatio,_fundingPeriod,_fee,_spreadLimit,_maxPriceImpact,_partialLiquidationRatio,_maxPriceSpread,_maxOpenNotional,_feeToStakersPercent,_maxOracleDelay,_rolloverFee) = if ((i.caller != adminAddress()))
11281128 then throw("Invalid changeSettings params")
11291129 else updateSettings(_initMarginRatio, _mmr, _liquidationFeeRatio, _fundingPeriod, _fee, _spreadLimit, _maxPriceImpact, _partialLiquidationRatio, _maxPriceSpread, _maxOpenNotional, _feeToStakersPercent, _maxOracleDelay, _rolloverFee)
11301130
11311131
11321132
11331133 @Callable(i)
11341134 func initialize (_qtAstR,_bsAstR,_fundingPeriod,_initMarginRatio,_mmr,_liquidationFeeRatio,_fee,_oracle,_oracleKey,_oracleBlockKey,_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 ((0 >= _qtAstR))
11351135 then true
11361136 else (0 >= _bsAstR))
11371137 then true
11381138 else (0 >= _fundingPeriod))
11391139 then true
11401140 else (0 >= _initMarginRatio))
11411141 then true
11421142 else (0 >= _mmr))
11431143 then true
11441144 else (0 >= _liquidationFeeRatio))
11451145 then true
11461146 else (0 >= _fee))
11471147 then true
11481148 else (0 >= _spreadLimit))
11491149 then true
11501150 else (0 >= _maxPriceImpact))
11511151 then true
11521152 else (0 >= _partialLiquidationRatio))
11531153 then true
11541154 else (0 >= _maxPriceSpread))
11551155 then true
11561156 else (0 >= _maxOpenNotional))
11571157 then true
11581158 else (0 >= _feeToStakersPercent))
11591159 then true
11601160 else (_feeToStakersPercent > DECIMAL_UNIT))
11611161 then true
11621162 else (0 >= _maxOracleDelay))
11631163 then true
11641164 else (0 >= _rolloverFee))
11651165 then true
11661166 else initialized())
11671167 then throw("Invalid initialize parameters")
11681168 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_ora, _oracle), StringEntry(k_ora_key, _oracleKey), StringEntry(k_ora_block_key, _oracleBlockKey), StringEntry(k_coordinatorAddress, _coordinator)])
11691169
11701170
11711171
11721172 @Callable(i)
11731173 func increasePosition (_direction,_leverage,_minBaseAssetAmount,_refLink) = {
11741174 let sync = invoke(this, "syncTerminalPriceToOracle", nil, nil)
11751175 if ((sync == sync))
11761176 then {
11771177 let _trader = getActualCaller(i)
11781178 let _rawAmount = i.payments[0].amount
11791179 let _assetId = i.payments[0].assetId
11801180 let _assetIdStr = toBase58String(value(_assetId))
11811181 let isQuoteAsset = (_assetId == quoteAsset())
11821182 if (if (if (if (if (if (if (if (if (if ((_direction != DIR_LONG))
11831183 then (_direction != DIR_SHORT)
11841184 else false)
11851185 then true
11861186 else (0 >= _rawAmount))
11871187 then true
11881188 else !(initialized()))
11891189 then true
11901190 else !(isQuoteAsset))
11911191 then true
11921192 else !(isSameAssetOrNoPosition(_trader, _assetIdStr)))
11931193 then true
11941194 else !(requireMoreMarginRatio(divd(DECIMAL_UNIT, _leverage), initMarginRatio(), true)))
11951195 then true
11961196 else paused())
11971197 then true
11981198 else closeOnly())
11991199 then true
12001200 else isMarketClosed())
12011201 then throw("Invalid increasePosition parameters")
12021202 else {
12031203 let $t05764557794 = getForTraderWithArtifact(_trader, getArtifactId(i))
12041204 let adjustedFee = $t05764557794._1
12051205 let burnArtifact = $t05764557794._2
12061206 let _amount = divd(_rawAmount, (muld(adjustedFee, _leverage) + DECIMAL_UNIT))
12071207 let distributeFeeAmount = (_rawAmount - _amount)
12081208 let referrerFeeAny = invoke(referralAddress(), "acceptPaymentWithLink", [_trader, _refLink], [AttachedPayment(quoteAsset(), distributeFeeAmount)])
12091209 if ((referrerFeeAny == referrerFeeAny))
12101210 then {
12111211 let referrerFee = match referrerFeeAny {
12121212 case x: Int =>
12131213 x
12141214 case _ =>
12151215 throw("Invalid referrerFee")
12161216 }
12171217 let feeAmount = (distributeFeeAmount - referrerFee)
12181218 let $t05829058458 = getPosition(_trader)
12191219 let oldPositionSize = $t05829058458._1
12201220 let oldPositionMargin = $t05829058458._2
12211221 let oldPositionOpenNotional = $t05829058458._3
12221222 let oldPositionLstUpdCPF = $t05829058458._4
12231223 let oldPositionTimestamp = $t05829058458._5
12241224 let isNewPosition = (oldPositionSize == 0)
12251225 let isSameDirection = if ((oldPositionSize > 0))
12261226 then (_direction == DIR_LONG)
12271227 else (_direction == DIR_SHORT)
12281228 let expandExisting = if (!(isNewPosition))
12291229 then isSameDirection
12301230 else false
12311231 let isAdd = (_direction == DIR_LONG)
12321232 let $t05874761868 = if (if (isNewPosition)
12331233 then true
12341234 else expandExisting)
12351235 then {
12361236 let openNotional = muld(_amount, _leverage)
12371237 let $t05925659429 = swapInput(isAdd, openNotional)
12381238 let amountBaseAssetBought = $t05925659429._1
12391239 let quoteAssetReserveAfter = $t05925659429._2
12401240 let baseAssetReserveAfter = $t05925659429._3
12411241 let totalPositionSizeAfter = $t05925659429._4
12421242 if (if ((_minBaseAssetAmount != 0))
12431243 then (_minBaseAssetAmount > abs(amountBaseAssetBought))
12441244 else false)
12451245 then throw(((("Limit error: " + toString(abs(amountBaseAssetBought))) + " < ") + toString(_minBaseAssetAmount)))
12461246 else {
12471247 let newPositionSize = (oldPositionSize + amountBaseAssetBought)
12481248 let totalLongOpenInterestAfter = (openInterestLong() + (if ((newPositionSize > 0))
12491249 then openNotional
12501250 else 0))
12511251 let totalShortOpenInterestAfter = (openInterestShort() + (if ((0 > newPositionSize))
12521252 then openNotional
12531253 else 0))
12541254 let $t05997560250 = calcRemainMarginWithFundingPaymentAndRolloverFee(oldPositionSize, oldPositionMargin, oldPositionLstUpdCPF, oldPositionTimestamp, _amount)
12551255 let remainMargin = $t05997560250._1
12561256 let x1 = $t05997560250._2
12571257 let x2 = $t05997560250._3
12581258 let rolloverFee = $t05997560250._4
12591259 if (!(requireNotOverSpreadLimit(quoteAssetReserveAfter, baseAssetReserveAfter)))
12601260 then throw("Over max spread limit")
12611261 else if (!(requireNotOverMaxOpenNotional(totalLongOpenInterestAfter, totalShortOpenInterestAfter)))
12621262 then throw("Over max open notional")
12631263 else $Tuple14(newPositionSize, remainMargin, (oldPositionOpenNotional + openNotional), latestCumulativePremiumFraction(newPositionSize), lastTimestamp(), baseAssetReserveAfter, quoteAssetReserveAfter, totalPositionSizeAfter, (openInterestNotional() + openNotional), (totalLongPositionSize() + (if ((newPositionSize > 0))
12641264 then abs(amountBaseAssetBought)
12651265 else 0)), (totalShortPositionSize() + (if ((0 > newPositionSize))
12661266 then abs(amountBaseAssetBought)
12671267 else 0)), totalLongOpenInterestAfter, totalShortOpenInterestAfter, rolloverFee)
12681268 }
12691269 }
12701270 else {
12711271 let openNotional = muld(_amount, _leverage)
12721272 let $t06156861684 = getPositionNotionalAndUnrealizedPnl(toString(i.caller), PNL_OPTION_SPOT)
12731273 let oldPositionNotional = $t06156861684._1
12741274 let unrealizedPnl = $t06156861684._2
12751275 if ((oldPositionNotional > openNotional))
12761276 then throw("Use decreasePosition to decrease position size")
12771277 else throw("Close position first")
12781278 }
12791279 let newPositionSize = $t05874761868._1
12801280 let newPositionRemainMargin = $t05874761868._2
12811281 let newPositionOpenNotional = $t05874761868._3
12821282 let newPositionLatestCPF = $t05874761868._4
12831283 let newPositionTimestamp = $t05874761868._5
12841284 let baseAssetReserveAfter = $t05874761868._6
12851285 let quoteAssetReserveAfter = $t05874761868._7
12861286 let totalPositionSizeAfter = $t05874761868._8
12871287 let openInterestNotionalAfter = $t05874761868._9
12881288 let totalLongAfter = $t05874761868._10
12891289 let totalShortAfter = $t05874761868._11
12901290 let totalLongOpenInterestAfter = $t05874761868._12
12911291 let totalShortOpenInterestAfter = $t05874761868._13
12921292 let rolloverFee = $t05874761868._14
12931293 let $t06187461945 = distributeFee((feeAmount + rolloverFee))
12941294 let feeToStakers = $t06187461945._1
12951295 let feeToVault = $t06187461945._2
1296- let stake = if (isQuoteAsset)
1297- then {
1298- let stake = invoke(vaultAddress(), "addLocked", [false], [AttachedPayment(quoteAsset(), _amount)])
1299- if ((stake == stake))
1300- then nil
1301- else throw("Strict value is not equal to itself.")
1302- }
1303- else nil
1296+ let stake = if ((_amount >= rolloverFee))
1297+ then invoke(vaultAddress(), "addLocked", nil, [AttachedPayment(quoteAsset(), (_amount - rolloverFee))])
1298+ else invoke(vaultAddress(), "withdrawLocked", [(rolloverFee - _amount)], nil)
13041299 if ((stake == stake))
13051300 then {
13061301 let depositVault = invoke(vaultAddress(), "addFree", nil, [AttachedPayment(quoteAsset(), feeToVault)])
13071302 if ((depositVault == depositVault))
13081303 then {
13091304 let notifyFee = invoke(minerAddress(), "notifyFees", [_trader, feeAmount], nil)
13101305 if ((notifyFee == notifyFee))
13111306 then {
13121307 let notifyNotional = invoke(minerAddress(), "notifyNotional", [_trader, newPositionOpenNotional], nil)
13131308 if ((notifyNotional == notifyNotional))
1314- 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))) ++ doBurnArtifact(burnArtifact, i))
1309+ 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))
13151310 else throw("Strict value is not equal to itself.")
13161311 }
13171312 else throw("Strict value is not equal to itself.")
13181313 }
13191314 else throw("Strict value is not equal to itself.")
13201315 }
13211316 else throw("Strict value is not equal to itself.")
13221317 }
13231318 else throw("Strict value is not equal to itself.")
13241319 }
13251320 }
13261321 else throw("Strict value is not equal to itself.")
13271322 }
13281323
13291324
13301325
13311326 @Callable(i)
13321327 func addMargin () = {
13331328 let sync = invoke(this, "syncTerminalPriceToOracle", nil, nil)
13341329 if ((sync == sync))
13351330 then {
13361331 let _trader = toString(i.caller)
13371332 let _amount = i.payments[0].amount
13381333 let _assetId = i.payments[0].assetId
13391334 let _assetIdStr = toBase58String(value(_assetId))
13401335 let isQuoteAsset = (_assetId == quoteAsset())
13411336 if (if (if (if (if (if (if (!(isQuoteAsset))
13421337 then true
13431338 else !(requireOpenPosition(toString(i.caller))))
13441339 then true
13451340 else !(isSameAsset(_trader, _assetIdStr)))
13461341 then true
13471342 else !(initialized()))
13481343 then true
13491344 else paused())
13501345 then true
13511346 else closeOnly())
13521347 then true
13531348 else isMarketClosed())
13541349 then throw("Invalid addMargin parameters")
13551350 else {
1356- let $t06387164039 = getPosition(_trader)
1357- let oldPositionSize = $t06387164039._1
1358- let oldPositionMargin = $t06387164039._2
1359- let oldPositionOpenNotional = $t06387164039._3
1360- let oldPositionLstUpdCPF = $t06387164039._4
1361- let oldPositionTimestamp = $t06387164039._5
1362- let stake = invoke(vaultAddress(), "addLocked", [false], [AttachedPayment(quoteAsset(), _amount)])
1351+ let $t06398764155 = getPosition(_trader)
1352+ let oldPositionSize = $t06398764155._1
1353+ let oldPositionMargin = $t06398764155._2
1354+ let oldPositionOpenNotional = $t06398764155._3
1355+ let oldPositionLstUpdCPF = $t06398764155._4
1356+ let oldPositionTimestamp = $t06398764155._5
1357+ let stake = invoke(vaultAddress(), "addLocked", nil, [AttachedPayment(quoteAsset(), _amount)])
13631358 if ((stake == stake))
13641359 then {
13651360 let rolloverFee = calcRolloverFee(oldPositionMargin, oldPositionTimestamp)
13661361 let doTransferFeeToStakers = if ((rolloverFee > 0))
13671362 then {
1368- let $t06432964388 = distributeFee(rolloverFee)
1369- let feeToStakers = $t06432964388._1
1370- let feeToVault = $t06432964388._2
1363+ let $t06444064499 = distributeFee(rolloverFee)
1364+ let feeToStakers = $t06444064499._1
1365+ let feeToVault = $t06444064499._2
13711366 let unstake = invoke(vaultAddress(), "withdrawLocked", [feeToStakers], nil)
13721367 if ((unstake == unstake))
13731368 then {
13741369 let lockBadDebt = invoke(vaultAddress(), "exchangeFreeAndLocked", [-(feeToVault)], nil)
13751370 if ((lockBadDebt == lockBadDebt))
13761371 then transferFee(feeToStakers)
13771372 else throw("Strict value is not equal to itself.")
13781373 }
13791374 else throw("Strict value is not equal to itself.")
13801375 }
13811376 else nil
13821377 if ((doTransferFeeToStakers == doTransferFeeToStakers))
13831378 then ((updatePosition(_trader, oldPositionSize, ((oldPositionMargin - rolloverFee) + _amount), oldPositionOpenNotional, oldPositionLstUpdCPF, lastTimestamp()) ++ updateBalance(((cbalance() + _amount) - rolloverFee))) ++ doTransferFeeToStakers)
13841379 else throw("Strict value is not equal to itself.")
13851380 }
13861381 else throw("Strict value is not equal to itself.")
13871382 }
13881383 }
13891384 else throw("Strict value is not equal to itself.")
13901385 }
13911386
13921387
13931388
13941389 @Callable(i)
13951390 func removeMargin (_amount) = {
13961391 let sync = invoke(this, "syncTerminalPriceToOracle", nil, nil)
13971392 if ((sync == sync))
13981393 then {
13991394 let _trader = toString(i.caller)
14001395 if (if (if (if (if ((0 >= _amount))
14011396 then true
14021397 else !(requireOpenPosition(_trader)))
14031398 then true
14041399 else !(initialized()))
14051400 then true
14061401 else paused())
14071402 then true
14081403 else isMarketClosed())
14091404 then throw("Invalid removeMargin parameters")
14101405 else {
1411- let $t06543165599 = getPosition(_trader)
1412- let oldPositionSize = $t06543165599._1
1413- let oldPositionMargin = $t06543165599._2
1414- let oldPositionOpenNotional = $t06543165599._3
1415- let oldPositionLstUpdCPF = $t06543165599._4
1416- let oldPositionTimestamp = $t06543165599._5
1417- let $t06560565854 = calcRemainMarginWithFundingPaymentAndRolloverFee(oldPositionSize, oldPositionMargin, oldPositionLstUpdCPF, oldPositionTimestamp, -(_amount))
1418- let remainMargin = $t06560565854._1
1419- let badDebt = $t06560565854._2
1420- let fundingPayment = $t06560565854._3
1421- let rolloverFee = $t06560565854._4
1406+ let $t06554265710 = getPosition(_trader)
1407+ let oldPositionSize = $t06554265710._1
1408+ let oldPositionMargin = $t06554265710._2
1409+ let oldPositionOpenNotional = $t06554265710._3
1410+ let oldPositionLstUpdCPF = $t06554265710._4
1411+ let oldPositionTimestamp = $t06554265710._5
1412+ let $t06571665965 = calcRemainMarginWithFundingPaymentAndRolloverFee(oldPositionSize, oldPositionMargin, oldPositionLstUpdCPF, oldPositionTimestamp, -(_amount))
1413+ let remainMargin = $t06571665965._1
1414+ let badDebt = $t06571665965._2
1415+ let fundingPayment = $t06571665965._3
1416+ let rolloverFee = $t06571665965._4
14221417 if ((badDebt != 0))
14231418 then throw("Invalid removed margin amount")
14241419 else {
14251420 let marginRatio = calcMarginRatio(remainMargin, badDebt, oldPositionOpenNotional)
14261421 if (!(requireMoreMarginRatio(marginRatio, initMarginRatio(), true)))
14271422 then throw(((("Too much margin removed: " + toString(marginRatio)) + " < ") + toString(initMarginRatio())))
14281423 else {
1429- let $t06624066299 = distributeFee(rolloverFee)
1430- let feeToStakers = $t06624066299._1
1431- let feeToVault = $t06624066299._2
1424+ let $t06635166410 = distributeFee(rolloverFee)
1425+ let feeToStakers = $t06635166410._1
1426+ let feeToVault = $t06635166410._2
14321427 let doTransferFeeToStakers = if ((rolloverFee > 0))
14331428 then {
14341429 let lockBadDebt = invoke(vaultAddress(), "exchangeFreeAndLocked", [-(feeToVault)], nil)
14351430 if ((lockBadDebt == lockBadDebt))
14361431 then transferFee(feeToStakers)
14371432 else throw("Strict value is not equal to itself.")
14381433 }
14391434 else nil
14401435 if ((doTransferFeeToStakers == doTransferFeeToStakers))
14411436 then {
14421437 let unstake = invoke(vaultAddress(), "withdrawLocked", [(_amount + feeToStakers)], nil)
14431438 if ((unstake == unstake))
14441439 then (((updatePosition(_trader, oldPositionSize, remainMargin, oldPositionOpenNotional, latestCumulativePremiumFraction(oldPositionSize), lastTimestamp()) ++ withdraw(i.caller, _amount)) ++ updateBalance(((cbalance() - _amount) - rolloverFee))) ++ doTransferFeeToStakers)
14451440 else throw("Strict value is not equal to itself.")
14461441 }
14471442 else throw("Strict value is not equal to itself.")
14481443 }
14491444 }
14501445 }
14511446 }
14521447 else throw("Strict value is not equal to itself.")
14531448 }
14541449
14551450
14561451
14571452 @Callable(i)
14581453 func closePosition (_size,_minQuoteAssetAmount,_addToMargin) = {
14591454 let sync = invoke(this, "syncTerminalPriceToOracle", nil, nil)
14601455 if ((sync == sync))
14611456 then {
14621457 let _trader = getActualCaller(i)
14631458 let _traderAddress = valueOrErrorMessage(addressFromString(_trader), "Invalid caller")
14641459 let positionFee = getPositionFee(_trader)
14651460 if (if (if (if (if (if (!(requireOpenPosition(_trader)))
14661461 then true
14671462 else !(initialized()))
14681463 then true
14691464 else paused())
14701465 then true
14711466 else (0 >= _size))
14721467 then true
14731468 else (0 > _minQuoteAssetAmount))
14741469 then true
14751470 else isMarketClosed())
14761471 then throw("Invalid closePosition parameters")
14771472 else {
1478- let $t06783167971 = getPosition(_trader)
1479- let oldPositionSize = $t06783167971._1
1480- let oldPositionMargin = $t06783167971._2
1481- let oldPositionOpenNotional = $t06783167971._3
1482- let oldPositionLstUpdCPF = $t06783167971._4
1483- let $t06797768550 = internalClosePosition(_trader, _size, positionFee, _minQuoteAssetAmount, _addToMargin, true)
1484- let newPositionSize = $t06797768550._1
1485- let newPositionMargin = $t06797768550._2
1486- let newPositionOpenNotional = $t06797768550._3
1487- let newPositionLstUpdCPF = $t06797768550._4
1488- let positionBadDebt = $t06797768550._5
1489- let realizedPnl = $t06797768550._6
1490- let marginToTrader = $t06797768550._7
1491- let quoteAssetReserveAfter = $t06797768550._8
1492- let baseAssetReserveAfter = $t06797768550._9
1493- let totalPositionSizeAfter = $t06797768550._10
1494- let openInterestNotionalAfter = $t06797768550._11
1495- let totalLongAfter = $t06797768550._12
1496- let totalShortAfter = $t06797768550._13
1497- let totalLongOpenInterestAfter = $t06797768550._14
1498- let totalShortOpenInterestAfter = $t06797768550._15
1499- let realizedFee = $t06797768550._16
1473+ let $t06794268082 = getPosition(_trader)
1474+ let oldPositionSize = $t06794268082._1
1475+ let oldPositionMargin = $t06794268082._2
1476+ let oldPositionOpenNotional = $t06794268082._3
1477+ let oldPositionLstUpdCPF = $t06794268082._4
1478+ let $t06808868661 = internalClosePosition(_trader, _size, positionFee, _minQuoteAssetAmount, _addToMargin, true)
1479+ let newPositionSize = $t06808868661._1
1480+ let newPositionMargin = $t06808868661._2
1481+ let newPositionOpenNotional = $t06808868661._3
1482+ let newPositionLstUpdCPF = $t06808868661._4
1483+ let positionBadDebt = $t06808868661._5
1484+ let realizedPnl = $t06808868661._6
1485+ let marginToTrader = $t06808868661._7
1486+ let quoteAssetReserveAfter = $t06808868661._8
1487+ let baseAssetReserveAfter = $t06808868661._9
1488+ let totalPositionSizeAfter = $t06808868661._10
1489+ let openInterestNotionalAfter = $t06808868661._11
1490+ let totalLongAfter = $t06808868661._12
1491+ let totalShortAfter = $t06808868661._13
1492+ let totalLongOpenInterestAfter = $t06808868661._14
1493+ let totalShortOpenInterestAfter = $t06808868661._15
1494+ let realizedFee = $t06808868661._16
15001495 if ((positionBadDebt > 0))
15011496 then throw("Invalid closePosition parameters: bad debt")
15021497 else {
15031498 let isPartialClose = (newPositionSize != 0)
15041499 let withdrawAmount = (marginToTrader + realizedFee)
15051500 let ammBalance = (cbalance() - withdrawAmount)
15061501 let ammNewBalance = if ((0 > ammBalance))
15071502 then 0
15081503 else ammBalance
15091504 let unstake = invoke(vaultAddress(), "withdrawLocked", [withdrawAmount], nil)
15101505 if ((unstake == unstake))
15111506 then {
1512- let $t06906069119 = distributeFee(realizedFee)
1513- let feeToStakers = $t06906069119._1
1514- let feeToVault = $t06906069119._2
1507+ let $t06917169230 = distributeFee(realizedFee)
1508+ let feeToStakers = $t06917169230._1
1509+ let feeToVault = $t06917169230._2
15151510 let depositVault = invoke(vaultAddress(), "addFree", nil, [AttachedPayment(quoteAsset(), feeToVault)])
15161511 if ((depositVault == depositVault))
15171512 then {
15181513 let notifyFee = invoke(minerAddress(), "notifyFees", [_trader, realizedFee], nil)
15191514 if ((notifyFee == notifyFee))
15201515 then {
15211516 let notifyNotional = invoke(minerAddress(), "notifyNotional", [_trader, newPositionOpenNotional], nil)
15221517 if ((notifyNotional == notifyNotional))
15231518 then (((((if (isPartialClose)
15241519 then updatePosition(_trader, newPositionSize, newPositionMargin, newPositionOpenNotional, newPositionLstUpdCPF, lastTimestamp())
15251520 else deletePosition(_trader)) ++ updateAmm(quoteAssetReserveAfter, baseAssetReserveAfter, totalPositionSizeAfter, openInterestNotionalAfter, totalLongAfter, totalShortAfter, totalLongOpenInterestAfter, totalShortOpenInterestAfter)) ++ (if ((marginToTrader > 0))
15261521 then withdraw(_traderAddress, marginToTrader)
15271522 else nil)) ++ updateBalance(ammNewBalance)) ++ transferFee(feeToStakers))
15281523 else throw("Strict value is not equal to itself.")
15291524 }
15301525 else throw("Strict value is not equal to itself.")
15311526 }
15321527 else throw("Strict value is not equal to itself.")
15331528 }
15341529 else throw("Strict value is not equal to itself.")
15351530 }
15361531 }
15371532 }
15381533 else throw("Strict value is not equal to itself.")
15391534 }
15401535
15411536
15421537
15431538 @Callable(i)
15441539 func liquidate (_trader) = {
15451540 let sync = invoke(this, "syncTerminalPriceToOracle", nil, nil)
15461541 if ((sync == sync))
15471542 then {
15481543 let spotMarginRatio = getMarginRatioByOption(_trader, PNL_OPTION_SPOT)
15491544 let liquidationMarginRatio = if (isOverFluctuationLimit())
15501545 then {
15511546 let oracleMarginRatio = getMarginRatioByOption(_trader, PNL_OPTION_ORACLE)
15521547 vmax(spotMarginRatio, oracleMarginRatio)
15531548 }
15541549 else spotMarginRatio
15551550 if (if (if (if (if (!(requireMoreMarginRatio(liquidationMarginRatio, maintenanceMarginRatio(), false)))
15561551 then true
15571552 else !(requireOpenPosition(_trader)))
15581553 then true
15591554 else !(initialized()))
15601555 then true
15611556 else paused())
15621557 then true
15631558 else isMarketClosed())
15641559 then throw("Unable to liquidate")
15651560 else {
15661561 let isPartialLiquidation = if (if ((spotMarginRatio > liquidationFeeRatio()))
15671562 then true
15681563 else (partialLiquidationRatio() > 0))
15691564 then true
15701565 else (DECIMAL_UNIT > partialLiquidationRatio())
15711566 let oldPositionSize = getPosition(_trader)._1
15721567 let positionSizeAbs = abs(oldPositionSize)
1573- let $t07143271755 = if (isPartialLiquidation)
1568+ let $t07154371866 = if (isPartialLiquidation)
15741569 then {
15751570 let liquidationSize = getPartialLiquidationAmount(_trader, oldPositionSize)
15761571 let liquidationRatio = divd(abs(liquidationSize), positionSizeAbs)
15771572 $Tuple2(liquidationRatio, abs(liquidationSize))
15781573 }
15791574 else $Tuple2(0, positionSizeAbs)
1580- let liquidationRatio = $t07143271755._1
1581- let liquidationSize = $t07143271755._2
1582- let $t07176172387 = internalClosePosition(_trader, if (isPartialLiquidation)
1575+ let liquidationRatio = $t07154371866._1
1576+ let liquidationSize = $t07154371866._2
1577+ let $t07187272498 = internalClosePosition(_trader, if (isPartialLiquidation)
15831578 then liquidationSize
15841579 else positionSizeAbs, liquidationFeeRatio(), 0, true, false)
1585- let newPositionSize = $t07176172387._1
1586- let newPositionMargin = $t07176172387._2
1587- let newPositionOpenNotional = $t07176172387._3
1588- let newPositionLstUpdCPF = $t07176172387._4
1589- let positionBadDebt = $t07176172387._5
1590- let realizedPnl = $t07176172387._6
1591- let marginToTrader = $t07176172387._7
1592- let quoteAssetReserveAfter = $t07176172387._8
1593- let baseAssetReserveAfter = $t07176172387._9
1594- let totalPositionSizeAfter = $t07176172387._10
1595- let openInterestNotionalAfter = $t07176172387._11
1596- let totalLongAfter = $t07176172387._12
1597- let totalShortAfter = $t07176172387._13
1598- let totalLongOpenInterestAfter = $t07176172387._14
1599- let totalShortOpenInterestAfter = $t07176172387._15
1600- let liquidationPenalty = $t07176172387._16
1580+ let newPositionSize = $t07187272498._1
1581+ let newPositionMargin = $t07187272498._2
1582+ let newPositionOpenNotional = $t07187272498._3
1583+ let newPositionLstUpdCPF = $t07187272498._4
1584+ let positionBadDebt = $t07187272498._5
1585+ let realizedPnl = $t07187272498._6
1586+ let marginToTrader = $t07187272498._7
1587+ let quoteAssetReserveAfter = $t07187272498._8
1588+ let baseAssetReserveAfter = $t07187272498._9
1589+ let totalPositionSizeAfter = $t07187272498._10
1590+ let openInterestNotionalAfter = $t07187272498._11
1591+ let totalLongAfter = $t07187272498._12
1592+ let totalShortAfter = $t07187272498._13
1593+ let totalLongOpenInterestAfter = $t07187272498._14
1594+ let totalShortOpenInterestAfter = $t07187272498._15
1595+ let liquidationPenalty = $t07187272498._16
16011596 let feeToLiquidator = (liquidationPenalty / 2)
16021597 let feeToVault = (liquidationPenalty - feeToLiquidator)
16031598 let ammBalance = (cbalance() - liquidationPenalty)
16041599 let newAmmBalance = if ((0 > ammBalance))
16051600 then 0
16061601 else ammBalance
16071602 let lockBadDebt = if ((positionBadDebt > 0))
16081603 then {
16091604 let lockBadDebt = invoke(vaultAddress(), "exchangeFreeAndLocked", [positionBadDebt], nil)
16101605 if ((lockBadDebt == lockBadDebt))
16111606 then nil
16121607 else throw("Strict value is not equal to itself.")
16131608 }
16141609 else nil
16151610 if ((lockBadDebt == lockBadDebt))
16161611 then {
16171612 let unstake = invoke(vaultAddress(), "withdrawLocked", [liquidationPenalty], nil)
16181613 if ((unstake == unstake))
16191614 then {
16201615 let depositInsurance = invoke(vaultAddress(), "addFree", nil, [AttachedPayment(quoteAsset(), feeToVault)])
16211616 if ((depositInsurance == depositInsurance))
16221617 then {
16231618 let notifyNotional = invoke(minerAddress(), "notifyNotional", [_trader, newPositionOpenNotional], nil)
16241619 if ((notifyNotional == notifyNotional))
16251620 then ((((if (isPartialLiquidation)
16261621 then updatePosition(_trader, newPositionSize, newPositionMargin, newPositionOpenNotional, newPositionLstUpdCPF, lastTimestamp())
16271622 else deletePosition(_trader)) ++ updateAmm(quoteAssetReserveAfter, baseAssetReserveAfter, totalPositionSizeAfter, openInterestNotionalAfter, totalLongAfter, totalShortAfter, totalLongOpenInterestAfter, totalShortOpenInterestAfter)) ++ withdraw(i.caller, feeToLiquidator)) ++ updateBalance(newAmmBalance))
16281623 else throw("Strict value is not equal to itself.")
16291624 }
16301625 else throw("Strict value is not equal to itself.")
16311626 }
16321627 else throw("Strict value is not equal to itself.")
16331628 }
16341629 else throw("Strict value is not equal to itself.")
16351630 }
16361631 }
16371632 else throw("Strict value is not equal to itself.")
16381633 }
16391634
16401635
16411636
16421637 @Callable(i)
16431638 func payFunding () = {
16441639 let sync = invoke(this, "syncTerminalPriceToOracle", nil, nil)
16451640 if ((sync == sync))
16461641 then {
16471642 let fundingBlockTimestamp = nextFundingBlockTimestamp()
16481643 if (if (if ((fundingBlockTimestamp > lastTimestamp()))
16491644 then true
16501645 else !(initialized()))
16511646 then true
16521647 else paused())
16531648 then throw(((("Invalid funding block timestamp: " + toString(lastTimestamp())) + " < ") + toString(fundingBlockTimestamp)))
16541649 else {
16551650 let underlyingPrice = getOraclePrice()
1656- let $t07435374415 = getFunding()
1657- let shortPremiumFraction = $t07435374415._1
1658- let longPremiumFraction = $t07435374415._2
1651+ let $t07446474526 = getFunding()
1652+ let shortPremiumFraction = $t07446474526._1
1653+ let longPremiumFraction = $t07446474526._2
16591654 updateFunding((fundingBlockTimestamp + fundingPeriodSeconds()), (latestLongCumulativePremiumFraction() + longPremiumFraction), (latestShortCumulativePremiumFraction() + shortPremiumFraction), divd(longPremiumFraction, underlyingPrice), divd(shortPremiumFraction, underlyingPrice))
16601655 }
16611656 }
16621657 else throw("Strict value is not equal to itself.")
16631658 }
16641659
16651660
16661661
16671662 @Callable(i)
16681663 func syncTerminalPriceToOracle () = {
16691664 let _qtAstR = qtAstR()
16701665 let _bsAstR = bsAstR()
1671- let $t07484774982 = getSyncTerminalPrice(getOraclePrice(), _qtAstR, _bsAstR)
1672- let newQuoteAssetWeight = $t07484774982._1
1673- let newBaseAssetWeight = $t07484774982._2
1674- let marginToVault = $t07484774982._3
1666+ let $t07495875093 = getSyncTerminalPrice(getOraclePrice(), _qtAstR, _bsAstR)
1667+ let newQuoteAssetWeight = $t07495875093._1
1668+ let newBaseAssetWeight = $t07495875093._2
1669+ let marginToVault = $t07495875093._3
16751670 let doExchangePnL = if ((marginToVault != 0))
16761671 then {
16771672 let doExchangePnL = invoke(vaultAddress(), "exchangeFreeAndLocked", [marginToVault], nil)
16781673 if ((doExchangePnL == doExchangePnL))
16791674 then nil
16801675 else throw("Strict value is not equal to itself.")
16811676 }
16821677 else nil
16831678 if ((doExchangePnL == doExchangePnL))
1684- then (updateAmmWeights(newQuoteAssetWeight, newBaseAssetWeight) ++ appendTwap(divd(muld(_qtAstR, newQuoteAssetWeight), muld(_bsAstR, newBaseAssetWeight))))
1679+ then ((updateBalance((cbalance() + marginToVault)) ++ updateAmmWeights(newQuoteAssetWeight, newBaseAssetWeight)) ++ appendTwap(divd(muld(_qtAstR, newQuoteAssetWeight), muld(_bsAstR, newBaseAssetWeight))))
16851680 else throw("Strict value is not equal to itself.")
16861681 }
16871682
16881683
16891684
16901685 @Callable(i)
16911686 func view_calcRemainMarginWithFundingPayment (_trader) = {
16921687 let sync = invoke(this, "syncTerminalPriceToOracle", nil, nil)
16931688 if ((sync == sync))
16941689 then {
1695- let $t07555175675 = getPosition(_trader)
1696- let positionSize = $t07555175675._1
1697- let positionMargin = $t07555175675._2
1698- let pon = $t07555175675._3
1699- let positionLstUpdCPF = $t07555175675._4
1700- let positionTimestamp = $t07555175675._5
1701- let $t07567875779 = getPositionNotionalAndUnrealizedPnl(_trader, PNL_OPTION_SPOT)
1702- let positionNotional = $t07567875779._1
1703- let unrealizedPnl = $t07567875779._2
1704- let $t07578276006 = calcRemainMarginWithFundingPaymentAndRolloverFee(positionSize, positionMargin, positionLstUpdCPF, positionTimestamp, unrealizedPnl)
1705- let remainMargin = $t07578276006._1
1706- let badDebt = $t07578276006._2
1707- let fundingPayment = $t07578276006._3
1708- let rolloverFee = $t07578276006._4
1690+ let $t07571175835 = getPosition(_trader)
1691+ let positionSize = $t07571175835._1
1692+ let positionMargin = $t07571175835._2
1693+ let pon = $t07571175835._3
1694+ let positionLstUpdCPF = $t07571175835._4
1695+ let positionTimestamp = $t07571175835._5
1696+ let $t07583875939 = getPositionNotionalAndUnrealizedPnl(_trader, PNL_OPTION_SPOT)
1697+ let positionNotional = $t07583875939._1
1698+ let unrealizedPnl = $t07583875939._2
1699+ let $t07594276166 = calcRemainMarginWithFundingPaymentAndRolloverFee(positionSize, positionMargin, positionLstUpdCPF, positionTimestamp, unrealizedPnl)
1700+ let remainMargin = $t07594276166._1
1701+ let badDebt = $t07594276166._2
1702+ let fundingPayment = $t07594276166._3
1703+ let rolloverFee = $t07594276166._4
17091704 throw(((((((s(remainMargin) + s(fundingPayment)) + s(getMarginRatio(_trader))) + s(unrealizedPnl)) + s(badDebt)) + s(positionNotional)) + s(rolloverFee)))
17101705 }
17111706 else throw("Strict value is not equal to itself.")
17121707 }
17131708
17141709
17151710
17161711 @Callable(i)
17171712 func view_getPegAdjustCost (_price) = {
17181713 let _qtAstR = qtAstR()
17191714 let _bsAstR = bsAstR()
17201715 let result = getSyncTerminalPrice(_price, _qtAstR, _bsAstR)
17211716 throw(toString(result._3))
17221717 }
17231718
17241719
17251720
17261721 @Callable(i)
17271722 func view_getTerminalAmmPrice () = {
1728- let $t07644276523 = getTerminalAmmState()
1729- let terminalQuoteAssetReserve = $t07644276523._1
1730- let terminalBaseAssetReserve = $t07644276523._2
1723+ let $t07660276683 = getTerminalAmmState()
1724+ let terminalQuoteAssetReserve = $t07660276683._1
1725+ let terminalBaseAssetReserve = $t07660276683._2
17311726 let price = divd(muld(terminalQuoteAssetReserve, qtAstW()), muld(terminalBaseAssetReserve, bsAstW()))
17321727 throw(toString(price))
17331728 }
17341729
17351730
17361731
17371732 @Callable(i)
17381733 func view_getFunding () = {
17391734 let underlyingPrice = getOraclePrice()
1740- let $t07673876800 = getFunding()
1741- let shortPremiumFraction = $t07673876800._1
1742- let longPremiumFraction = $t07673876800._2
1735+ let $t07689876960 = getFunding()
1736+ let shortPremiumFraction = $t07689876960._1
1737+ let longPremiumFraction = $t07689876960._2
17431738 let longFunding = divd(longPremiumFraction, underlyingPrice)
17441739 let shortFunding = divd(shortPremiumFraction, underlyingPrice)
17451740 throw((((s(longFunding) + s(shortFunding)) + s(getTwapSpotPrice())) + s(getOraclePrice())))
17461741 }
17471742
17481743
17491744
17501745 @Callable(i)
17511746 func computeSpotPrice () = {
17521747 let result = getSpotPrice()
17531748 $Tuple2(nil, result)
17541749 }
17551750
17561751
17571752
17581753 @Callable(i)
17591754 func computeFeeForTraderWithArtifact (_trader,_artifactId) = {
17601755 let result = getForTraderWithArtifact(_trader, _artifactId)
17611756 $Tuple2(nil, result)
17621757 }
17631758
17641759
17651760 @Verifier(tx)
17661761 func verify () = sigVerify(tx.bodyBytes, tx.proofs[0], adminPublicKey())
17671762

github/deemru/w8io/c3f4982 
194.96 ms