tx · FKtdRqem2rnVWqXUhHcwEbvAEKM8GPZGLiYWQK4SLhLh

3NC3GcwFK9knYYKT2SRc7nWxc5SXc2aKBQ6:  -0.07500000 Waves

2023.07.11 14:48 [2661199] smart account 3NC3GcwFK9knYYKT2SRc7nWxc5SXc2aKBQ6 > SELF 0.00000000 Waves

{ "type": 13, "id": "FKtdRqem2rnVWqXUhHcwEbvAEKM8GPZGLiYWQK4SLhLh", "fee": 7500000, "feeAssetId": null, "timestamp": 1689076082994, "version": 2, "chainId": 84, "sender": "3NC3GcwFK9knYYKT2SRc7nWxc5SXc2aKBQ6", "senderPublicKey": "5GAkpjTakesSgVm3A22kYMBvNpM8C1KpqWfyC7YyB84y", "proofs": [ "2EiQqC9ZX5mg7DWPRSStupZDsJZHn9LRTL9FNEfaUPerJ6oeTvt6GZH1zboSEfrxguURya9SnjCJDMXdxC5pigDw" ], "script": "base64:BgKUAQgCEgASABIAEgASAwoBARIVChMBAQEBAQEBAQEBAQEBAQEICAEBEhgKFgEBAQEBAQEICAgBAQEBAQEBAQEBAQESBwoFAQEBCAgSBAoCAQgSBQoDAQEIEgcKBQEBAQQIEgUKAwgBCBIDCgEIEgMKAQgSABIAEgMKAQgSBQoDCAEIEgMKAQESABIDCgEIEgASBAoCCAi/AQAMa19iYXNlT3JhY2xlAgxrX2Jhc2VPcmFjbGUADWtfcXVvdGVPcmFjbGUCDWtfcXVvdGVPcmFjbGUACWtfYmFsYW5jZQIJa19iYWxhbmNlAAprX3NlcXVlbmNlAgprX3NlcXVlbmNlAA5rX3Bvc2l0aW9uU2l6ZQIOa19wb3NpdGlvblNpemUAEGtfcG9zaXRpb25NYXJnaW4CEGtfcG9zaXRpb25NYXJnaW4AFmtfcG9zaXRpb25PcGVuTm90aW9uYWwCFmtfcG9zaXRpb25PcGVuTm90aW9uYWwALmtfcG9zaXRpb25MYXN0VXBkYXRlZEN1bXVsYXRpdmVQcmVtaXVtRnJhY3Rpb24CEmtfcG9zaXRpb25GcmFjdGlvbgASa19wb3NpdGlvblNlcXVlbmNlAhJrX3Bvc2l0aW9uU2VxdWVuY2UADWtfcG9zaXRpb25GZWUCDWtfcG9zaXRpb25GZWUAHmtfcG9zaXRpb25MYXN0VXBkYXRlZFRpbWVzdGFtcAITa19wb3NpdGlvblRpbWVzdGFtcAANa19pbml0aWFsaXplZAINa19pbml0aWFsaXplZAAIa19wYXVzZWQCCGtfcGF1c2VkAAtrX2Nsb3NlT25seQILa19jbG9zZU9ubHkABWtfZmVlAgVrX2ZlZQANa19yb2xsb3ZlckZlZQIOa19yb2xsb3Zlcl9mZWUAD2tfZnVuZGluZ1BlcmlvZAIPa19mdW5kaW5nUGVyaW9kABFrX2luaXRNYXJnaW5SYXRpbwIRa19pbml0TWFyZ2luUmF0aW8AFGtfbWluSW5pdE1hcmdpblJhdGlvAhRrX21pbkluaXRNYXJnaW5SYXRpbwAYa19tYWludGVuYW5jZU1hcmdpblJhdGlvAgVrX21tcgAVa19saXF1aWRhdGlvbkZlZVJhdGlvAhVrX2xpcXVpZGF0aW9uRmVlUmF0aW8AGWtfcGFydGlhbExpcXVpZGF0aW9uUmF0aW8CFmtfcGFydExpcXVpZGF0aW9uUmF0aW8ADWtfc3ByZWFkTGltaXQCDWtfc3ByZWFkTGltaXQAEGtfbWF4UHJpY2VJbXBhY3QCEGtfbWF4UHJpY2VJbXBhY3QAEGtfbWF4UHJpY2VTcHJlYWQCEGtfbWF4UHJpY2VTcHJlYWQAEWtfbWF4T3Blbk5vdGlvbmFsAhFrX21heE9wZW5Ob3Rpb25hbAAVa19mZWVUb1N0YWtlcnNQZXJjZW50AhVrX2ZlZVRvU3Rha2Vyc1BlcmNlbnQAEGtfbWF4T3JhY2xlRGVsYXkCEGtfbWF4T3JhY2xlRGVsYXkADWtfZnVuZGluZ01vZGUCDWtfZnVuZGluZ01vZGUADGtfb3JhY2xlTW9kZQIMa19vcmFjbGVNb2RlAA5rX3Bvc2l0aW9uTW9kZQIOa19wb3NpdGlvbk1vZGUAGGtfbWluTGlxdWlkYXRpb25Ob3Rpb25hbAIYa19taW5MaXF1aWRhdGlvbk5vdGlvbmFsACVrX2xhdGVzdExvbmdDdW11bGF0aXZlUHJlbWl1bUZyYWN0aW9uAhtrX2xhdGVzdExvbmdQcmVtaXVtRnJhY3Rpb24AJmtfbGF0ZXN0U2hvcnRDdW11bGF0aXZlUHJlbWl1bUZyYWN0aW9uAhxrX2xhdGVzdFNob3J0UHJlbWl1bUZyYWN0aW9uABJrX25leHRGdW5kaW5nQmxvY2sCHmtfbmV4dEZ1bmRpbmdCbG9ja01pblRpbWVzdGFtcAARa19sb25nRnVuZGluZ1JhdGUCEWtfbG9uZ0Z1bmRpbmdSYXRlABJrX3Nob3J0RnVuZGluZ1JhdGUCEmtfc2hvcnRGdW5kaW5nUmF0ZQATa19xdW90ZUFzc2V0UmVzZXJ2ZQIIa19xdEFzdFIAEmtfYmFzZUFzc2V0UmVzZXJ2ZQIIa19ic0FzdFIAEmtfcXVvdGVBc3NldFdlaWdodAIIa19xdEFzdFcAEWtfYmFzZUFzc2V0V2VpZ2h0AghrX2JzQXN0VwATa190b3RhbFBvc2l0aW9uU2l6ZQITa190b3RhbFBvc2l0aW9uU2l6ZQAXa190b3RhbExvbmdQb3NpdGlvblNpemUCF2tfdG90YWxMb25nUG9zaXRpb25TaXplABhrX3RvdGFsU2hvcnRQb3NpdGlvblNpemUCGGtfdG90YWxTaG9ydFBvc2l0aW9uU2l6ZQAWa19vcGVuSW50ZXJlc3ROb3Rpb25hbAIWa19vcGVuSW50ZXJlc3ROb3Rpb25hbAATa19vcGVuSW50ZXJlc3RTaG9ydAITa19vcGVuSW50ZXJlc3RTaG9ydAASa19vcGVuSW50ZXJlc3RMb25nAhJrX29wZW5JbnRlcmVzdExvbmcACGtfbGFzdFR4AghrX2xhc3RUeAAUa19jb29yZGluYXRvckFkZHJlc3MCFGtfY29vcmRpbmF0b3JBZGRyZXNzAA9rX3ZhdWx0X2FkZHJlc3MCD2tfdmF1bHRfYWRkcmVzcwAPa19hZG1pbl9hZGRyZXNzAg9rX2FkbWluX2FkZHJlc3MADWtfcXVvdGVfYXNzZXQCDWtfcXVvdGVfYXNzZXQAEWtfc3Rha2luZ19hZGRyZXNzAhFrX3N0YWtpbmdfYWRkcmVzcwAPa19taW5lcl9hZGRyZXNzAg9rX21pbmVyX2FkZHJlc3MAEGtfb3JkZXJzX2FkZHJlc3MCEGtfb3JkZXJzX2FkZHJlc3MAEmtfcmVmZXJyYWxfYWRkcmVzcwISa19yZWZlcnJhbF9hZGRyZXNzABVrX25mdF9tYW5hZ2VyX2FkZHJlc3MCFWtfbmZ0X21hbmFnZXJfYWRkcmVzcwEOdG9Db21wb3NpdGVLZXkCBF9rZXkIX2FkZHJlc3MJAKwCAgkArAICBQRfa2V5AgFfBQhfYWRkcmVzcwELY29vcmRpbmF0b3IACQETdmFsdWVPckVycm9yTWVzc2FnZQIJAKYIAQkBEUBleHRyTmF0aXZlKDEwNTMpAgUEdGhpcwUUa19jb29yZGluYXRvckFkZHJlc3MCE0Nvb3JkaW5hdG9yIG5vdCBzZXQBDGFkbWluQWRkcmVzcwAJAKYIAQkBEUBleHRyTmF0aXZlKDEwNTMpAgkBC2Nvb3JkaW5hdG9yAAUPa19hZG1pbl9hZGRyZXNzAQpxdW90ZUFzc2V0AAkA2QQBCQERQGV4dHJOYXRpdmUoMTA1MykCCQELY29vcmRpbmF0b3IABQ1rX3F1b3RlX2Fzc2V0AQ5zdGFraW5nQWRkcmVzcwAJARN2YWx1ZU9yRXJyb3JNZXNzYWdlAgkApggBCQERQGV4dHJOYXRpdmUoMTA1MykCCQELY29vcmRpbmF0b3IABRFrX3N0YWtpbmdfYWRkcmVzcwIPU3Rha2luZyBub3Qgc2V0AQx2YXVsdEFkZHJlc3MACQETdmFsdWVPckVycm9yTWVzc2FnZQIJAKYIAQkBEUBleHRyTmF0aXZlKDEwNTMpAgkBC2Nvb3JkaW5hdG9yAAUPa192YXVsdF9hZGRyZXNzAg1WYXVsdCBub3Qgc2V0AQxtaW5lckFkZHJlc3MACQETdmFsdWVPckVycm9yTWVzc2FnZQIJAKYIAQkBEUBleHRyTmF0aXZlKDEwNTMpAgkBC2Nvb3JkaW5hdG9yAAUPa19taW5lcl9hZGRyZXNzAg1NaW5lciBub3Qgc2V0AQ1vcmRlcnNBZGRyZXNzAAkBE3ZhbHVlT3JFcnJvck1lc3NhZ2UCCQCmCAEJARFAZXh0ck5hdGl2ZSgxMDUzKQIJAQtjb29yZGluYXRvcgAFEGtfb3JkZXJzX2FkZHJlc3MCDk9yZGVycyBub3Qgc2V0AQ9yZWZlcnJhbEFkZHJlc3MACQETdmFsdWVPckVycm9yTWVzc2FnZQIJAKYIAQkBEUBleHRyTmF0aXZlKDEwNTMpAgkBC2Nvb3JkaW5hdG9yAAUSa19yZWZlcnJhbF9hZGRyZXNzAhBSZWZlcnJhbCBub3Qgc2V0ARFuZnRNYW5hZ2VyQWRkcmVzcwAJARN2YWx1ZU9yRXJyb3JNZXNzYWdlAgkApggBCQERQGV4dHJOYXRpdmUoMTA1MykCCQELY29vcmRpbmF0b3IABRVrX25mdF9tYW5hZ2VyX2FkZHJlc3MCE05GVCBNYW5hZ2VyIG5vdCBzZXQADWtfdG9rZW5fcGFyYW0CDWtfdG9rZW5fcGFyYW0ADGtfdG9rZW5fdHlwZQIMa190b2tlbl90eXBlABhGRUVfUkVEVUNUSU9OX1RPS0VOX1RZUEUCDWZlZV9yZWR1Y3Rpb24ACERJUl9MT05HAAEACURJUl9TSE9SVAACAAdTRUNPTkRTAOgHAA9ERUNJTUFMX05VTUJFUlMABgAMREVDSU1BTF9VTklUCQBoAgABCQBoAgkAaAIJAGgCCQBoAgkAaAIACgAKAAoACgAKAAoAD01JTlVURVNfSU5fWUVBUgkAaAIAoIogBQxERUNJTUFMX1VOSVQAB09ORV9EQVkJAGgCAICjBQUMREVDSU1BTF9VTklUAA9QTkxfT1BUSU9OX1NQT1QAAQARUE5MX09QVElPTl9PUkFDTEUAAgASRlVORElOR19BU1lNTUVUUklDAAEAEUZVTkRJTkdfU1lNTUVUUklDAAIADE9SQUNMRV9QTEFJTgABAApPUkFDTEVfSklUAAIAD1BPU0lUSU9OX0RJUkVDVAABAA5QT1NJVElPTl9PUkRFUgACAQFzAQJfeAkArAICCQCkAwEFAl94AgEsAQRkaXZkAgJfeAJfeQkAbgQFAl94BQxERUNJTUFMX1VOSVQFAl95BQhIQUxGRVZFTgEEbXVsZAICX3gCX3kJAG4EBQJfeAUCX3kFDERFQ0lNQUxfVU5JVAUISEFMRkVWRU4BBWJkaXZkAgJfeAJfeQkAvQIEBQJfeAkAtgIBBQxERUNJTUFMX1VOSVQFAl95BQhIQUxGRVZFTgEFYm11bGQCAl94Al95CQC9AgQFAl94BQJfeQkAtgIBBQxERUNJTUFMX1VOSVQFCEhBTEZFVkVOAQNhYnMBAl94AwkAZgIFAl94AAAFAl94CQEBLQEFAl94AQR2bWF4AgJfeAJfeQMJAGcCBQJfeAUCX3kFAl94BQJfeQEDaW50AQFrCQETdmFsdWVPckVycm9yTWVzc2FnZQIJAJoIAgUEdGhpcwUBawkArAICAg1ubyB2YWx1ZSBmb3IgBQFrAQVpbnRPcgIBawNkZWYJAQt2YWx1ZU9yRWxzZQIJAJoIAgUEdGhpcwUBawUDZGVmAQRzdHJBAghfYWRkcmVzcwRfa2V5BAN2YWwJARN2YWx1ZU9yRXJyb3JNZXNzYWdlAgkAnQgCBQhfYWRkcmVzcwUEX2tleQkArAICAhFObyB2YWx1ZSBmb3Iga2V5IAUEX2tleQUDdmFsAQRpbnRBAghfYWRkcmVzcwRfa2V5BAN2YWwJARN2YWx1ZU9yRXJyb3JNZXNzYWdlAgkAmggCBQhfYWRkcmVzcwUEX2tleQkArAICAhFObyB2YWx1ZSBmb3Iga2V5IAUEX2tleQUDdmFsAQhjYmFsYW5jZQAJAQNpbnQBBQlrX2JhbGFuY2UBCWNiYWxhbmNlMAAJAQVpbnRPcgIFCWtfYmFsYW5jZQAAAQNmZWUACQEDaW50AQUFa19mZWUBD3JvbGxvdmVyRmVlUmF0ZQAJAQNpbnQBBQ1rX3JvbGxvdmVyRmVlAQ9pbml0TWFyZ2luUmF0aW8ACQEDaW50AQURa19pbml0TWFyZ2luUmF0aW8BEm1pbkluaXRNYXJnaW5SYXRpbwAJAQVpbnRPcgIFFGtfbWluSW5pdE1hcmdpblJhdGlvBQxERUNJTUFMX1VOSVQBBnF0QXN0UgAJAQNpbnQBBRNrX3F1b3RlQXNzZXRSZXNlcnZlAQdxdEFzdFIwAAkBBWludE9yAgUTa19xdW90ZUFzc2V0UmVzZXJ2ZQAAAQZic0FzdFIACQEDaW50AQUSa19iYXNlQXNzZXRSZXNlcnZlAQdic0FzdFIwAAkBBWludE9yAgUSa19iYXNlQXNzZXRSZXNlcnZlAAABBnF0QXN0VwAJAQVpbnRPcgIFEmtfcXVvdGVBc3NldFdlaWdodAUMREVDSU1BTF9VTklUAQZic0FzdFcACQEFaW50T3ICBRFrX2Jhc2VBc3NldFdlaWdodAUMREVDSU1BTF9VTklUARF0b3RhbFBvc2l0aW9uU2l6ZQAJAQNpbnQBBRNrX3RvdGFsUG9zaXRpb25TaXplARRvcGVuSW50ZXJlc3ROb3Rpb25hbAAJAQNpbnQBBRZrX29wZW5JbnRlcmVzdE5vdGlvbmFsARFvcGVuSW50ZXJlc3RTaG9ydAAJAQNpbnQBBRNrX29wZW5JbnRlcmVzdFNob3J0ARBvcGVuSW50ZXJlc3RMb25nAAkBA2ludAEFEmtfb3BlbkludGVyZXN0TG9uZwEZbmV4dEZ1bmRpbmdCbG9ja1RpbWVzdGFtcAAJAQNpbnQBBRJrX25leHRGdW5kaW5nQmxvY2sBEGZ1bmRpbmdQZXJpb2RSYXcACQEDaW50AQUPa19mdW5kaW5nUGVyaW9kARRmdW5kaW5nUGVyaW9kRGVjaW1hbAAJAGgCCQEQZnVuZGluZ1BlcmlvZFJhdwAFDERFQ0lNQUxfVU5JVAEUZnVuZGluZ1BlcmlvZFNlY29uZHMACQBoAgkBEGZ1bmRpbmdQZXJpb2RSYXcABQdTRUNPTkRTARZtYWludGVuYW5jZU1hcmdpblJhdGlvAAkBA2ludAEFGGtfbWFpbnRlbmFuY2VNYXJnaW5SYXRpbwETbGlxdWlkYXRpb25GZWVSYXRpbwAJAQNpbnQBBRVrX2xpcXVpZGF0aW9uRmVlUmF0aW8BF3BhcnRpYWxMaXF1aWRhdGlvblJhdGlvAAkBA2ludAEFGWtfcGFydGlhbExpcXVpZGF0aW9uUmF0aW8BC3NwcmVhZExpbWl0AAkBA2ludAEFDWtfc3ByZWFkTGltaXQBDm1heFByaWNlSW1wYWN0AAkBA2ludAEFEGtfbWF4UHJpY2VJbXBhY3QBDm1heFByaWNlU3ByZWFkAAkBA2ludAEFEGtfbWF4UHJpY2VTcHJlYWQBD21heE9wZW5Ob3Rpb25hbAAJAQNpbnQBBRFrX21heE9wZW5Ob3Rpb25hbAEjbGF0ZXN0TG9uZ0N1bXVsYXRpdmVQcmVtaXVtRnJhY3Rpb24ACQEDaW50AQUla19sYXRlc3RMb25nQ3VtdWxhdGl2ZVByZW1pdW1GcmFjdGlvbgEkbGF0ZXN0U2hvcnRDdW11bGF0aXZlUHJlbWl1bUZyYWN0aW9uAAkBA2ludAEFJmtfbGF0ZXN0U2hvcnRDdW11bGF0aXZlUHJlbWl1bUZyYWN0aW9uARZ0b3RhbFNob3J0UG9zaXRpb25TaXplAAkBA2ludAEFGGtfdG90YWxTaG9ydFBvc2l0aW9uU2l6ZQEVdG90YWxMb25nUG9zaXRpb25TaXplAAkBA2ludAEFF2tfdG90YWxMb25nUG9zaXRpb25TaXplAQxsYXN0U2VxdWVuY2UACQEFaW50T3ICBQprX3NlcXVlbmNlAAABE2ZlZVRvU3Rha2Vyc1BlcmNlbnQACQEDaW50AQUVa19mZWVUb1N0YWtlcnNQZXJjZW50AQ5tYXhPcmFjbGVEZWxheQAJAQNpbnQBBRBrX21heE9yYWNsZURlbGF5AQtmdW5kaW5nTW9kZQAJAQVpbnRPcgIFDWtfZnVuZGluZ01vZGUFEkZVTkRJTkdfQVNZTU1FVFJJQwEKb3JhY2xlTW9kZQAJAQVpbnRPcgIFDGtfb3JhY2xlTW9kZQUMT1JBQ0xFX1BMQUlOAQxwb3NpdGlvbk1vZGUACQEFaW50T3ICBQ5rX3Bvc2l0aW9uTW9kZQUPUE9TSVRJT05fRElSRUNUAR1taW5QYXJ0aWFsTGlxdWlkYXRpb25Ob3Rpb25hbAAJAQVpbnRPcgIFGGtfbWluTGlxdWlkYXRpb25Ob3Rpb25hbAkAaAIACgUMREVDSU1BTF9VTklUAQ1sYXN0VGltZXN0YW1wAAgFCWxhc3RCbG9jawl0aW1lc3RhbXABD2dldEFjdHVhbENhbGxlcgEBaQkBC3ZhbHVlT3JFbHNlAgkAnQgCCQENb3JkZXJzQWRkcmVzcwACCGtfc2VuZGVyCQClCAEIBQFpBmNhbGxlcgEWcmVxdWlyZU1vcmVNYXJnaW5SYXRpbwMMX21hcmdpblJhdGlvEF9iYXNlTWFyZ2luUmF0aW8UX2xhcmdlclRoYW5PckVxdWFsVG8EFHJlbWFpbmluZ01hcmdpblJhdGlvCQBlAgUMX21hcmdpblJhdGlvBRBfYmFzZU1hcmdpblJhdGlvAwMFFF9sYXJnZXJUaGFuT3JFcXVhbFRvCQBmAgAABRRyZW1haW5pbmdNYXJnaW5SYXRpbwcJAAIBCQCsAgIJAKwCAgkArAICAhBJbnZhbGlkIG1hcmdpbjogCQCkAwEFDF9tYXJnaW5SYXRpbwIDIDwgCQCkAwEFEF9iYXNlTWFyZ2luUmF0aW8DAwkBASEBBRRfbGFyZ2VyVGhhbk9yRXF1YWxUbwkAZwIFFHJlbWFpbmluZ01hcmdpblJhdGlvAAAHCQACAQkArAICCQCsAgIJAKwCAgIQSW52YWxpZCBtYXJnaW46IAkApAMBBQxfbWFyZ2luUmF0aW8CAyA+IAkApAMBBRBfYmFzZU1hcmdpblJhdGlvBgEfbGF0ZXN0Q3VtdWxhdGl2ZVByZW1pdW1GcmFjdGlvbgENX3Bvc2l0aW9uU2l6ZQMJAAACBQ1fcG9zaXRpb25TaXplAAAJAAIBAixTaG91bGQgbm90IGJlIGNhbGxlZCB3aXRoIF9wb3NpdGlvblNpemUgPT0gMAMJAGYCBQ1fcG9zaXRpb25TaXplAAAJASNsYXRlc3RMb25nQ3VtdWxhdGl2ZVByZW1pdW1GcmFjdGlvbgAJASRsYXRlc3RTaG9ydEN1bXVsYXRpdmVQcmVtaXVtRnJhY3Rpb24AAQtnZXRQb3NpdGlvbgIHX3RyYWRlcgpfZGlyZWN0aW9uBAtwb3NpdGlvbktleQkArAICCQCsAgIFB190cmFkZXICAV8JAKQDAQUKX2RpcmVjdGlvbgQPcG9zaXRpb25TaXplT3B0CQCaCAIFBHRoaXMJAQ50b0NvbXBvc2l0ZUtleQIFDmtfcG9zaXRpb25TaXplBQtwb3NpdGlvbktleQQHJG1hdGNoMAUPcG9zaXRpb25TaXplT3B0AwkAAQIFByRtYXRjaDACA0ludAQMcG9zaXRpb25TaXplBQckbWF0Y2gwCQCXCgUFDHBvc2l0aW9uU2l6ZQkBEUBleHRyTmF0aXZlKDEwNTApAgUEdGhpcwkBDnRvQ29tcG9zaXRlS2V5AgUQa19wb3NpdGlvbk1hcmdpbgULcG9zaXRpb25LZXkJARFAZXh0ck5hdGl2ZSgxMDUwKQIFBHRoaXMJAQ50b0NvbXBvc2l0ZUtleQIFFmtfcG9zaXRpb25PcGVuTm90aW9uYWwFC3Bvc2l0aW9uS2V5CQERQGV4dHJOYXRpdmUoMTA1MCkCBQR0aGlzCQEOdG9Db21wb3NpdGVLZXkCBS5rX3Bvc2l0aW9uTGFzdFVwZGF0ZWRDdW11bGF0aXZlUHJlbWl1bUZyYWN0aW9uBQtwb3NpdGlvbktleQkBEUBleHRyTmF0aXZlKDEwNTApAgUEdGhpcwkBDnRvQ29tcG9zaXRlS2V5AgUea19wb3NpdGlvbkxhc3RVcGRhdGVkVGltZXN0YW1wBQtwb3NpdGlvbktleQkAlwoFAAAAAAAAAAAAAAEMZ2V0RGlyZWN0aW9uAQ1fcG9zaXRpb25TaXplAwkAZgIAAAUNX3Bvc2l0aW9uU2l6ZQUJRElSX1NIT1JUBQhESVJfTE9ORwEOZ2V0UG9zaXRpb25GZWUCB190cmFkZXIKX2RpcmVjdGlvbgQLcG9zaXRpb25LZXkJAKwCAgkArAICBQdfdHJhZGVyAgFfCQCkAwEFCl9kaXJlY3Rpb24EDnBvc2l0aW9uRmVlT3B0CQCaCAIFBHRoaXMJAQ50b0NvbXBvc2l0ZUtleQIFDWtfcG9zaXRpb25GZWUFC3Bvc2l0aW9uS2V5BAckbWF0Y2gwBQ5wb3NpdGlvbkZlZU9wdAMJAAECBQckbWF0Y2gwAgNJbnQEC3Bvc2l0aW9uRmVlBQckbWF0Y2gwBQtwb3NpdGlvbkZlZQkBA2ZlZQABE3JlcXVpcmVPcGVuUG9zaXRpb24CB190cmFkZXIKX2RpcmVjdGlvbgMJAAACCAkBC2dldFBvc2l0aW9uAgUHX3RyYWRlcgUKX2RpcmVjdGlvbgJfMQAACQACAQIQTm8gb3BlbiBwb3NpdGlvbgYBDWdldE9yYWNsZURhdGEBA2tleQQNb3JhY2xlRGF0YVN0cgkAnQgCBQR0aGlzBQNrZXkDAwkBCWlzRGVmaW5lZAEFDW9yYWNsZURhdGFTdHIJAQIhPQIJAQV2YWx1ZQEFDW9yYWNsZURhdGFTdHICAAcECm9yYWNsZURhdGEJALUJAgkBBXZhbHVlAQUNb3JhY2xlRGF0YVN0cgIBLAQNb3JhY2xlQWRkcmVzcwkBE3ZhbHVlT3JFcnJvck1lc3NhZ2UCCQCmCAEJAJEDAgUKb3JhY2xlRGF0YQAACQCsAgICG0ludmFsaWQgb3JhY2xlIGFkZHJlc3MgaW46IAkBBXZhbHVlAQUNb3JhY2xlRGF0YVN0cgQIcHJpY2VLZXkJAJEDAgUKb3JhY2xlRGF0YQABBAhibG9ja0tleQkAkQMCBQpvcmFjbGVEYXRhAAIEB29wZW5LZXkJAJEDAgUKb3JhY2xlRGF0YQADCQCWCgQFDW9yYWNsZUFkZHJlc3MFCHByaWNlS2V5BQhibG9ja0tleQUHb3BlbktleQUEdW5pdAELaW5pdGlhbGl6ZWQACQELdmFsdWVPckVsc2UCCQCbCAIFBHRoaXMFDWtfaW5pdGlhbGl6ZWQHAQZwYXVzZWQACQELdmFsdWVPckVsc2UCCQCbCAIFBHRoaXMFCGtfcGF1c2VkBwEJY2xvc2VPbmx5AAkBC3ZhbHVlT3JFbHNlAgkAmwgCBQR0aGlzBQtrX2Nsb3NlT25seQcBDXVwZGF0ZVJlc2VydmUDBl9pc0FkZBFfcXVvdGVBc3NldEFtb3VudBBfYmFzZUFzc2V0QW1vdW50AwUGX2lzQWRkBAduZXdCYXNlCQBlAgkBBmJzQXN0UgAFEF9iYXNlQXNzZXRBbW91bnQDCQBnAgAABQduZXdCYXNlCQACAQIqVHggbGVhZCB0byBiYXNlIGFzc2V0IHJlc2VydmUgPD0gMCwgcmV2ZXJ0CQCVCgMJAGQCCQEGcXRBc3RSAAURX3F1b3RlQXNzZXRBbW91bnQFB25ld0Jhc2UJAGQCCQERdG90YWxQb3NpdGlvblNpemUABRBfYmFzZUFzc2V0QW1vdW50BAhuZXdRdW90ZQkAZQIJAQZxdEFzdFIABRFfcXVvdGVBc3NldEFtb3VudAMJAGcCAAAFCG5ld1F1b3RlCQACAQIqVHggbGVhZCB0byBiYXNlIHF1b3RlIHJlc2VydmUgPD0gMCwgcmV2ZXJ0CQCVCgMFCG5ld1F1b3RlCQBkAgkBBmJzQXN0UgAFEF9iYXNlQXNzZXRBbW91bnQJAGUCCQERdG90YWxQb3NpdGlvblNpemUABRBfYmFzZUFzc2V0QW1vdW50AQ1jYWxjSW52YXJpYW50AgdfcXRBc3RSB19ic0FzdFIEB2JxdEFzdFIJALYCAQUHX3F0QXN0UgQHYmJzQXN0UgkAtgIBBQdfYnNBc3RSCQEFYm11bGQCBQdicXRBc3RSBQdiYnNBc3RSAQlzd2FwSW5wdXQCBl9pc0FkZBFfcXVvdGVBc3NldEFtb3VudAQHX3F0QXN0UgkBBnF0QXN0UgAEB19ic0FzdFIJAQZic0FzdFIABAdfcXRBc3RXCQEGcXRBc3RXAAQHX2JzQXN0VwkBBmJzQXN0VwAEGHF1b3RlQXNzZXRBbW91bnRBZGp1c3RlZAkBBGRpdmQCBRFfcXVvdGVBc3NldEFtb3VudAUHX3F0QXN0VwQBawkBDWNhbGNJbnZhcmlhbnQCBQdfcXRBc3RSBQdfYnNBc3RSBBZxdW90ZUFzc2V0UmVzZXJ2ZUFmdGVyAwUGX2lzQWRkCQBkAgUHX3F0QXN0UgUYcXVvdGVBc3NldEFtb3VudEFkanVzdGVkCQBlAgUHX3F0QXN0UgUYcXVvdGVBc3NldEFtb3VudEFkanVzdGVkBBViYXNlQXNzZXRSZXNlcnZlQWZ0ZXIJAKADAQkBBWJkaXZkAgUBawkAtgIBBRZxdW90ZUFzc2V0UmVzZXJ2ZUFmdGVyBBhhbW91bnRCYXNlQXNzZXRCb3VnaHRBYnMJAQNhYnMBCQBlAgUVYmFzZUFzc2V0UmVzZXJ2ZUFmdGVyBQdfYnNBc3RSBBVhbW91bnRCYXNlQXNzZXRCb3VnaHQDBQZfaXNBZGQFGGFtb3VudEJhc2VBc3NldEJvdWdodEFicwkBAS0BBRhhbW91bnRCYXNlQXNzZXRCb3VnaHRBYnMEDSR0MDE2NTg1MTY3NTUJAQ11cGRhdGVSZXNlcnZlAwUGX2lzQWRkBRhxdW90ZUFzc2V0QW1vdW50QWRqdXN0ZWQFGGFtb3VudEJhc2VBc3NldEJvdWdodEFicwQXcXVvdGVBc3NldFJlc2VydmVBZnRlcjEIBQ0kdDAxNjU4NTE2NzU1Al8xBBZiYXNlQXNzZXRSZXNlcnZlQWZ0ZXIxCAUNJHQwMTY1ODUxNjc1NQJfMgQXdG90YWxQb3NpdGlvblNpemVBZnRlcjEIBQ0kdDAxNjU4NTE2NzU1Al8zBAtwcmljZUJlZm9yZQkBBGRpdmQCCQEEbXVsZAIFB19xdEFzdFIFB19xdEFzdFcJAQRtdWxkAgUHX2JzQXN0UgUHX2JzQXN0VwQLbWFya2V0UHJpY2UJAQRkaXZkAgURX3F1b3RlQXNzZXRBbW91bnQFGGFtb3VudEJhc2VBc3NldEJvdWdodEFicwQJcHJpY2VEaWZmCQEDYWJzAQkAZQIFC3ByaWNlQmVmb3JlBQttYXJrZXRQcmljZQQLcHJpY2VJbXBhY3QJAGUCBQxERUNJTUFMX1VOSVQJAQRkaXZkAgULcHJpY2VCZWZvcmUJAGQCBQtwcmljZUJlZm9yZQUJcHJpY2VEaWZmBBNtYXhQcmljZUltcGFjdFZhbHVlCQEObWF4UHJpY2VJbXBhY3QAAwkAZgIFC3ByaWNlSW1wYWN0BRNtYXhQcmljZUltcGFjdFZhbHVlCQACAQkArAICCQCsAgIJAKwCAgkArAICCQCsAgIJAKwCAgkArAICCQCsAgIJAKwCAgkArAICCQCsAgIJAKwCAgkArAICAg1QcmljZSBpbXBhY3QgCQCkAwEFC3ByaWNlSW1wYWN0AhQgPiBtYXggcHJpY2UgaW1wYWN0IAkApAMBBRNtYXhQcmljZUltcGFjdFZhbHVlAhUgYmVmb3JlIHF1b3RlIGFzc2V0OiAJAKQDAQUHX3F0QXN0UgIUIGJlZm9yZSBiYXNlIGFzc2V0OiAJAKQDAQUHX2JzQXN0UgIhIHF1b3RlIGFzc2V0IGFtb3VudCB0byBleGNoYW5nZTogCQCkAwEFEV9xdW90ZUFzc2V0QW1vdW50Ag8gcHJpY2UgYmVmb3JlOiAJAKQDAQULcHJpY2VCZWZvcmUCDiBtYXJrZXRQcmljZTogCQCkAwEFC21hcmtldFByaWNlCQCWCgQFFWFtb3VudEJhc2VBc3NldEJvdWdodAUXcXVvdGVBc3NldFJlc2VydmVBZnRlcjEFFmJhc2VBc3NldFJlc2VydmVBZnRlcjEFF3RvdGFsUG9zaXRpb25TaXplQWZ0ZXIxAQ9jYWxjUm9sbG92ZXJGZWUCEl9vbGRQb3NpdGlvbk1hcmdpbiBfb2xkUG9zaXRpb25MYXN0VXBkYXRlZFRpbWVzdGFtcAQPcG9zaXRpb25NaW51dGVzCQBoAgkAaQIJAGkCCQBlAgkBDWxhc3RUaW1lc3RhbXAABSBfb2xkUG9zaXRpb25MYXN0VXBkYXRlZFRpbWVzdGFtcADoBwA8BQxERUNJTUFMX1VOSVQEC3JvbGxvdmVyRmVlCQEEZGl2ZAIJAQRtdWxkAgkBBG11bGQCBRJfb2xkUG9zaXRpb25NYXJnaW4FD3Bvc2l0aW9uTWludXRlcwkBD3JvbGxvdmVyRmVlUmF0ZQAFD01JTlVURVNfSU5fWUVBUgULcm9sbG92ZXJGZWUBMGNhbGNSZW1haW5NYXJnaW5XaXRoRnVuZGluZ1BheW1lbnRBbmRSb2xsb3ZlckZlZQUQX29sZFBvc2l0aW9uU2l6ZRJfb2xkUG9zaXRpb25NYXJnaW4lX29sZFBvc2l0aW9uQ3VtdWxhdGl2ZVByZW1pdW1GcmFjdGlvbiBfb2xkUG9zaXRpb25MYXN0VXBkYXRlZFRpbWVzdGFtcAxfbWFyZ2luRGVsdGEEDmZ1bmRpbmdQYXltZW50AwkBAiE9AgUQX29sZFBvc2l0aW9uU2l6ZQAABCBfbGF0ZXN0Q3VtdWxhdGl2ZVByZW1pdW1GcmFjdGlvbgkBH2xhdGVzdEN1bXVsYXRpdmVQcmVtaXVtRnJhY3Rpb24BBRBfb2xkUG9zaXRpb25TaXplCQEEbXVsZAIJAGUCBSBfbGF0ZXN0Q3VtdWxhdGl2ZVByZW1pdW1GcmFjdGlvbgUlX29sZFBvc2l0aW9uQ3VtdWxhdGl2ZVByZW1pdW1GcmFjdGlvbgUQX29sZFBvc2l0aW9uU2l6ZQAABAtyb2xsb3ZlckZlZQkBD2NhbGNSb2xsb3ZlckZlZQIFEl9vbGRQb3NpdGlvbk1hcmdpbgUgX29sZFBvc2l0aW9uTGFzdFVwZGF0ZWRUaW1lc3RhbXAEDHNpZ25lZE1hcmdpbgkAZAIJAGUCCQBlAgUMX21hcmdpbkRlbHRhBQtyb2xsb3ZlckZlZQUOZnVuZGluZ1BheW1lbnQFEl9vbGRQb3NpdGlvbk1hcmdpbgQNJHQwMTk0MjIxOTU0OQMJAGYCAAAFDHNpZ25lZE1hcmdpbgkAlAoCAAAJAQNhYnMBBQxzaWduZWRNYXJnaW4JAJQKAgkBA2FicwEFDHNpZ25lZE1hcmdpbgAABAxyZW1haW5NYXJnaW4IBQ0kdDAxOTQyMjE5NTQ5Al8xBAdiYWREZWJ0CAUNJHQwMTk0MjIxOTU0OQJfMgkAlgoEBQxyZW1haW5NYXJnaW4FB2JhZERlYnQFDmZ1bmRpbmdQYXltZW50BQtyb2xsb3ZlckZlZQEWc3dhcE91dHB1dFdpdGhSZXNlcnZlcwcGX2lzQWRkEF9iYXNlQXNzZXRBbW91bnQUX2NoZWNrTWF4UHJpY2VJbXBhY3QSX3F1b3RlQXNzZXRSZXNlcnZlEV9xdW90ZUFzc2V0V2VpZ2h0EV9iYXNlQXNzZXRSZXNlcnZlEF9iYXNlQXNzZXRXZWlnaHQEC3ByaWNlQmVmb3JlCQEEZGl2ZAIJAQRtdWxkAgUSX3F1b3RlQXNzZXRSZXNlcnZlBRFfcXVvdGVBc3NldFdlaWdodAkBBG11bGQCBRFfYmFzZUFzc2V0UmVzZXJ2ZQUQX2Jhc2VBc3NldFdlaWdodAMJAAACBRBfYmFzZUFzc2V0QW1vdW50AAAJAAIBAhlJbnZhbGlkIGJhc2UgYXNzZXQgYW1vdW50BAFrCQENY2FsY0ludmFyaWFudAIFEl9xdW90ZUFzc2V0UmVzZXJ2ZQURX2Jhc2VBc3NldFJlc2VydmUEGGJhc2VBc3NldFBvb2xBbW91bnRBZnRlcgMFBl9pc0FkZAkAZAIFEV9iYXNlQXNzZXRSZXNlcnZlBRBfYmFzZUFzc2V0QW1vdW50CQBlAgURX2Jhc2VBc3NldFJlc2VydmUFEF9iYXNlQXNzZXRBbW91bnQED3F1b3RlQXNzZXRBZnRlcgkAoAMBCQEFYmRpdmQCBQFrCQC2AgEFGGJhc2VBc3NldFBvb2xBbW91bnRBZnRlcgQPcXVvdGVBc3NldERlbHRhCQEDYWJzAQkAZQIFD3F1b3RlQXNzZXRBZnRlcgUSX3F1b3RlQXNzZXRSZXNlcnZlBA5xdW90ZUFzc2V0U29sZAkBBG11bGQCBQ9xdW90ZUFzc2V0RGVsdGEFEV9xdW90ZUFzc2V0V2VpZ2h0BBNtYXhQcmljZUltcGFjdFZhbHVlCQEObWF4UHJpY2VJbXBhY3QABA0kdDAyMDgxMTIwOTczCQENdXBkYXRlUmVzZXJ2ZQMJAQEhAQUGX2lzQWRkBQ9xdW90ZUFzc2V0RGVsdGEFEF9iYXNlQXNzZXRBbW91bnQEF3F1b3RlQXNzZXRSZXNlcnZlQWZ0ZXIxCAUNJHQwMjA4MTEyMDk3MwJfMQQWYmFzZUFzc2V0UmVzZXJ2ZUFmdGVyMQgFDSR0MDIwODExMjA5NzMCXzIEF3RvdGFsUG9zaXRpb25TaXplQWZ0ZXIxCAUNJHQwMjA4MTEyMDk3MwJfMwQLbWFya2V0UHJpY2UJAQRkaXZkAgUOcXVvdGVBc3NldFNvbGQFEF9iYXNlQXNzZXRBbW91bnQECXByaWNlRGlmZgkBA2FicwEJAGUCBQtwcmljZUJlZm9yZQULbWFya2V0UHJpY2UEC3ByaWNlSW1wYWN0CQBlAgUMREVDSU1BTF9VTklUCQEEZGl2ZAIFC3ByaWNlQmVmb3JlCQBkAgULcHJpY2VCZWZvcmUFCXByaWNlRGlmZgMDCQBmAgULcHJpY2VJbXBhY3QFE21heFByaWNlSW1wYWN0VmFsdWUFFF9jaGVja01heFByaWNlSW1wYWN0BwkAAgEJAKwCAgkArAICCQCsAgIJAKwCAgkArAICCQCsAgIJAKwCAgkArAICCQCsAgIJAKwCAgkArAICCQCsAgIJAKwCAgINUHJpY2UgaW1wYWN0IAkApAMBBQtwcmljZUltcGFjdAIUID4gbWF4IHByaWNlIGltcGFjdCAJAKQDAQUTbWF4UHJpY2VJbXBhY3RWYWx1ZQIVIGJlZm9yZSBxdW90ZSBhc3NldDogCQCkAwEFEl9xdW90ZUFzc2V0UmVzZXJ2ZQIUIGJlZm9yZSBiYXNlIGFzc2V0OiAJAKQDAQURX2Jhc2VBc3NldFJlc2VydmUCICBiYXNlIGFzc2V0IGFtb3VudCB0byBleGNoYW5nZTogCQCkAwEFEF9iYXNlQXNzZXRBbW91bnQCDyBwcmljZSBiZWZvcmU6IAkApAMBBQtwcmljZUJlZm9yZQIPIG1hcmtldCBwcmljZTogCQCkAwEFC21hcmtldFByaWNlCQCZCgcFDnF1b3RlQXNzZXRTb2xkBRdxdW90ZUFzc2V0UmVzZXJ2ZUFmdGVyMQUWYmFzZUFzc2V0UmVzZXJ2ZUFmdGVyMQUXdG90YWxQb3NpdGlvblNpemVBZnRlcjEJAGUCCQEVdG90YWxMb25nUG9zaXRpb25TaXplAAMFBl9pc0FkZAkBA2FicwEFEF9iYXNlQXNzZXRBbW91bnQAAAkAZQIJARZ0b3RhbFNob3J0UG9zaXRpb25TaXplAAMJAQEhAQUGX2lzQWRkCQEDYWJzAQUQX2Jhc2VBc3NldEFtb3VudAAABQtwcmljZUltcGFjdAEKc3dhcE91dHB1dAMGX2lzQWRkEF9iYXNlQXNzZXRBbW91bnQUX2NoZWNrTWF4UHJpY2VJbXBhY3QJARZzd2FwT3V0cHV0V2l0aFJlc2VydmVzBwUGX2lzQWRkBRBfYmFzZUFzc2V0QW1vdW50BRRfY2hlY2tNYXhQcmljZUltcGFjdAkBBnF0QXN0UgAJAQZxdEFzdFcACQEGYnNBc3RSAAkBBmJzQXN0VwABE2dldE9yYWNsZVByaWNlVmFsdWUDBm9yYWNsZQhwcmljZUtleQhibG9ja0tleQQJbGFzdFZhbHVlCQETdmFsdWVPckVycm9yTWVzc2FnZQIJAJoIAgUGb3JhY2xlBQhwcmljZUtleQkArAICCQCsAgIJAKwCAgIiQ2FuIG5vdCBnZXQgb3JhY2xlIHByaWNlLiBPcmFjbGU6IAkApQgBBQZvcmFjbGUCBiBrZXk6IAUIcHJpY2VLZXkDCQECIT0CBQhibG9ja0tleQIABAxjdXJyZW50QmxvY2sFBmhlaWdodAQPbGFzdE9yYWNsZUJsb2NrCQETdmFsdWVPckVycm9yTWVzc2FnZQIJAJoIAgUGb3JhY2xlBQhibG9ja0tleQkArAICCQCsAgIJAKwCAgIiQ2FuIG5vdCBnZXQgb3JhY2xlIGJsb2NrLiBPcmFjbGU6IAkApQgBBQZvcmFjbGUCBiBrZXk6IAUIYmxvY2tLZXkDCQBmAgkAZQIFDGN1cnJlbnRCbG9jawUPbGFzdE9yYWNsZUJsb2NrCQEObWF4T3JhY2xlRGVsYXkACQACAQkArAICCQCsAgIJAKwCAgImT3JhY2xlIHN0YWxlIGRhdGEuIExhc3Qgb3JhY2xlIGJsb2NrOiAJAKQDAQUPbGFzdE9yYWNsZUJsb2NrAhAgY3VycmVudCBibG9jazogCQCkAwEFDGN1cnJlbnRCbG9jawUJbGFzdFZhbHVlBQlsYXN0VmFsdWUBDmdldE9yYWNsZVByaWNlAAQKYmFzZU9yYWNsZQkBE3ZhbHVlT3JFcnJvck1lc3NhZ2UCCQENZ2V0T3JhY2xlRGF0YQEFDGtfYmFzZU9yYWNsZQIZTm8gYmFzZSBhc3NldCBvcmFjbGUgZGF0YQQPYmFzZU9yYWNsZVByaWNlCQETZ2V0T3JhY2xlUHJpY2VWYWx1ZQMIBQpiYXNlT3JhY2xlAl8xCAUKYmFzZU9yYWNsZQJfMggFCmJhc2VPcmFjbGUCXzMEC3F1b3RlT3JhY2xlCQENZ2V0T3JhY2xlRGF0YQEFDWtfcXVvdGVPcmFjbGUEEHF1b3RlT3JhY2xlUHJpY2UDCQEJaXNEZWZpbmVkAQULcXVvdGVPcmFjbGUEDHF1b3RlT3JhY2xlVgkBBXZhbHVlAQULcXVvdGVPcmFjbGUJARNnZXRPcmFjbGVQcmljZVZhbHVlAwgFDHF1b3RlT3JhY2xlVgJfMQgFDHF1b3RlT3JhY2xlVgJfMggFDHF1b3RlT3JhY2xlVgJfMwUMREVDSU1BTF9VTklUCQEEZGl2ZAIFD2Jhc2VPcmFjbGVQcmljZQUQcXVvdGVPcmFjbGVQcmljZQEOaXNNYXJrZXRDbG9zZWQABApiYXNlT3JhY2xlCQETdmFsdWVPckVycm9yTWVzc2FnZQIJAQ1nZXRPcmFjbGVEYXRhAQUMa19iYXNlT3JhY2xlAhlObyBiYXNlIGFzc2V0IG9yYWNsZSBkYXRhBAZvcmFjbGUIBQpiYXNlT3JhY2xlAl8xBAdvcGVuS2V5CAUKYmFzZU9yYWNsZQJfNAMJAQIhPQIFB29wZW5LZXkCAAQGaXNPcGVuCQETdmFsdWVPckVycm9yTWVzc2FnZQIJAJsIAgUGb3JhY2xlBQdvcGVuS2V5CQCsAgIJAKwCAgkArAICAitDYW4gbm90IGdldCBvcmFjbGUgaXMgb3Blbi9jbG9zZWQuIE9yYWNsZTogCQClCAEFBm9yYWNsZQIGIGtleTogBQdvcGVuS2V5CQEBIQEFBmlzT3BlbgcBDGFic1ByaWNlRGlmZgUMX29yYWNsZVByaWNlEl9xdW90ZUFzc2V0UmVzZXJ2ZRFfYmFzZUFzc2V0UmVzZXJ2ZQdfcXRBc3RXB19ic0FzdFcECnByaWNlQWZ0ZXIJAQRkaXZkAgkBBG11bGQCBRJfcXVvdGVBc3NldFJlc2VydmUFB19xdEFzdFcJAQRtdWxkAgURX2Jhc2VBc3NldFJlc2VydmUFB19ic0FzdFcEDGF2ZXJhZ2VQcmljZQkBBGRpdmQCCQBkAgUMX29yYWNsZVByaWNlBQpwcmljZUFmdGVyCQBoAgACBQxERUNJTUFMX1VOSVQEDGFic1ByaWNlRGlmZgkBBGRpdmQCCQEDYWJzAQkAZQIFDF9vcmFjbGVQcmljZQUKcHJpY2VBZnRlcgUMYXZlcmFnZVByaWNlBQxhYnNQcmljZURpZmYBGXJlcXVpcmVOb3RPdmVyU3ByZWFkTGltaXQCEl9xdW90ZUFzc2V0UmVzZXJ2ZRFfYmFzZUFzc2V0UmVzZXJ2ZQQLb3JhY2xlUHJpY2UJAQ5nZXRPcmFjbGVQcmljZQAEB19xdEFzdFcJAQZxdEFzdFcABAdfYnNBc3RXCQEGYnNBc3RXAAQSYWJzUHJpY2VEaWZmQmVmb3JlCQEMYWJzUHJpY2VEaWZmBQULb3JhY2xlUHJpY2UJAQZxdEFzdFIACQEGYnNBc3RSAAUHX3F0QXN0VwUHX2JzQXN0VwQRYWJzUHJpY2VEaWZmQWZ0ZXIJAQxhYnNQcmljZURpZmYFBQtvcmFjbGVQcmljZQUSX3F1b3RlQXNzZXRSZXNlcnZlBRFfYmFzZUFzc2V0UmVzZXJ2ZQUHX3F0QXN0VwUHX2JzQXN0VwMDCQBmAgURYWJzUHJpY2VEaWZmQWZ0ZXIJAQ5tYXhQcmljZVNwcmVhZAAJAGYCBRFhYnNQcmljZURpZmZBZnRlcgUSYWJzUHJpY2VEaWZmQmVmb3JlBwkAAgEJAKwCAgkArAICCQCsAgICDVByaWNlIHNwcmVhZCAJAKQDAQURYWJzUHJpY2VEaWZmQWZ0ZXICFCA+IG1heCBwcmljZSBzcHJlYWQgCQCkAwEJAQ5tYXhQcmljZVNwcmVhZAAGAR1yZXF1aXJlTm90T3Zlck1heE9wZW5Ob3Rpb25hbAIRX2xvbmdPcGVuTm90aW9uYWwSX3Nob3J0T3Blbk5vdGlvbmFsBBBfbWF4T3Blbk5vdGlvbmFsCQEPbWF4T3Blbk5vdGlvbmFsAAMJAGYCBRFfbG9uZ09wZW5Ob3Rpb25hbAUQX21heE9wZW5Ob3Rpb25hbAkAAgEJAKwCAgkArAICCQCsAgICE0xvbmcgb3BlbiBub3Rpb25hbCAJAKQDAQURX2xvbmdPcGVuTm90aW9uYWwCFSA+IG1heCBvcGVuIG5vdGlvbmFsIAkApAMBBRBfbWF4T3Blbk5vdGlvbmFsAwkAZgIFEl9zaG9ydE9wZW5Ob3Rpb25hbAUQX21heE9wZW5Ob3Rpb25hbAkAAgEJAKwCAgkArAICCQCsAgICFFNob3J0IG9wZW4gbm90aW9uYWwgCQCkAwEFEl9zaG9ydE9wZW5Ob3Rpb25hbAIVID4gbWF4IG9wZW4gbm90aW9uYWwgCQCkAwEFEF9tYXhPcGVuTm90aW9uYWwGASFyZXF1aXJlU2VuZGVyQ2FuV29ya1dpdGhQb3NpdGlvbnMBB19jYWxsZXIDCQAAAgkBDHBvc2l0aW9uTW9kZQAFDlBPU0lUSU9OX09SREVSCQAAAgUHX2NhbGxlcgkBDW9yZGVyc0FkZHJlc3MABgEMZ2V0U3BvdFByaWNlAAQSX3F1b3RlQXNzZXRSZXNlcnZlCQEGcXRBc3RSAAQRX2Jhc2VBc3NldFJlc2VydmUJAQZic0FzdFIABAdfcXRBc3RXCQEGcXRBc3RXAAQHX2JzQXN0VwkBBmJzQXN0VwAJAQRkaXZkAgkBBG11bGQCBRJfcXVvdGVBc3NldFJlc2VydmUFB19xdEFzdFcJAQRtdWxkAgURX2Jhc2VBc3NldFJlc2VydmUFB19ic0FzdFcBFmlzT3ZlckZsdWN0dWF0aW9uTGltaXQABAtvcmFjbGVQcmljZQkBDmdldE9yYWNsZVByaWNlAAQMY3VycmVudFByaWNlCQEMZ2V0U3BvdFByaWNlAAkAZgIJAQRkaXZkAgkBA2FicwEJAGUCBQtvcmFjbGVQcmljZQUMY3VycmVudFByaWNlBQtvcmFjbGVQcmljZQkBC3NwcmVhZExpbWl0AAEfZ2V0UG9zaXRpb25BZGp1c3RlZE9wZW5Ob3Rpb25hbAYNX3Bvc2l0aW9uU2l6ZQdfb3B0aW9uEl9xdW90ZUFzc2V0UmVzZXJ2ZRFfcXVvdGVBc3NldFdlaWdodBFfYmFzZUFzc2V0UmVzZXJ2ZRBfYmFzZUFzc2V0V2VpZ2h0BA9wb3NpdGlvblNpemVBYnMJAQNhYnMBBQ1fcG9zaXRpb25TaXplBAdpc1Nob3J0CQBmAgAABQ1fcG9zaXRpb25TaXplBBBwb3NpdGlvbk5vdGlvbmFsAwkAAAIFB19vcHRpb24FD1BOTF9PUFRJT05fU1BPVAQTb3V0UG9zaXRpb25Ob3Rpb25hbAgJARZzd2FwT3V0cHV0V2l0aFJlc2VydmVzBwkBASEBBQdpc1Nob3J0BQ9wb3NpdGlvblNpemVBYnMHBRJfcXVvdGVBc3NldFJlc2VydmUFEV9xdW90ZUFzc2V0V2VpZ2h0BRFfYmFzZUFzc2V0UmVzZXJ2ZQUQX2Jhc2VBc3NldFdlaWdodAJfMQUTb3V0UG9zaXRpb25Ob3Rpb25hbAkBBG11bGQCBQ9wb3NpdGlvblNpemVBYnMJAQ5nZXRPcmFjbGVQcmljZQAFEHBvc2l0aW9uTm90aW9uYWwBK2dldFBvc2l0aW9uTm90aW9uYWxBbmRVbnJlYWxpemVkUG5sQnlWYWx1ZXMHDV9wb3NpdGlvblNpemUVX3Bvc2l0aW9uT3Blbk5vdGlvbmFsEl9xdW90ZUFzc2V0UmVzZXJ2ZRFfcXVvdGVBc3NldFdlaWdodBFfYmFzZUFzc2V0UmVzZXJ2ZRBfYmFzZUFzc2V0V2VpZ2h0B19vcHRpb24DCQAAAgUNX3Bvc2l0aW9uU2l6ZQAACQACAQIVSW52YWxpZCBwb3NpdGlvbiBzaXplBAdpc1Nob3J0CQBmAgAABQ1fcG9zaXRpb25TaXplBBBwb3NpdGlvbk5vdGlvbmFsCQEfZ2V0UG9zaXRpb25BZGp1c3RlZE9wZW5Ob3Rpb25hbAYFDV9wb3NpdGlvblNpemUFB19vcHRpb24FEl9xdW90ZUFzc2V0UmVzZXJ2ZQURX3F1b3RlQXNzZXRXZWlnaHQFEV9iYXNlQXNzZXRSZXNlcnZlBRBfYmFzZUFzc2V0V2VpZ2h0BA11bnJlYWxpemVkUG5sAwUHaXNTaG9ydAkAZQIFFV9wb3NpdGlvbk9wZW5Ob3Rpb25hbAUQcG9zaXRpb25Ob3Rpb25hbAkAZQIFEHBvc2l0aW9uTm90aW9uYWwFFV9wb3NpdGlvbk9wZW5Ob3Rpb25hbAkAlAoCBRBwb3NpdGlvbk5vdGlvbmFsBQ11bnJlYWxpemVkUG5sASNnZXRQb3NpdGlvbk5vdGlvbmFsQW5kVW5yZWFsaXplZFBubAMHX3RyYWRlcgpfZGlyZWN0aW9uB19vcHRpb24EDSR0MDI5MTE0MjkyNTQJAQtnZXRQb3NpdGlvbgIFB190cmFkZXIFCl9kaXJlY3Rpb24EDHBvc2l0aW9uU2l6ZQgFDSR0MDI5MTE0MjkyNTQCXzEEDnBvc2l0aW9uTWFyZ2luCAUNJHQwMjkxMTQyOTI1NAJfMgQUcG9zaXRpb25PcGVuTm90aW9uYWwIBQ0kdDAyOTExNDI5MjU0Al8zBBFwb3NpdGlvbkxzdFVwZENQRggFDSR0MDI5MTE0MjkyNTQCXzQJAStnZXRQb3NpdGlvbk5vdGlvbmFsQW5kVW5yZWFsaXplZFBubEJ5VmFsdWVzBwUMcG9zaXRpb25TaXplBRRwb3NpdGlvbk9wZW5Ob3Rpb25hbAkBBnF0QXN0UgAJAQZxdEFzdFcACQEGYnNBc3RSAAkBBmJzQXN0VwAFB19vcHRpb24BD2NhbGNNYXJnaW5SYXRpbwMNX3JlbWFpbk1hcmdpbghfYmFkRGVidBFfcG9zaXRpb25Ob3Rpb25hbAkBBGRpdmQCCQBlAgUNX3JlbWFpbk1hcmdpbgUIX2JhZERlYnQFEV9wb3NpdGlvbk5vdGlvbmFsARZnZXRNYXJnaW5SYXRpb0J5T3B0aW9uAwdfdHJhZGVyCl9kaXJlY3Rpb24HX29wdGlvbgQNJHQwMjk3ODYyOTkzOQkBC2dldFBvc2l0aW9uAgUHX3RyYWRlcgUKX2RpcmVjdGlvbgQMcG9zaXRpb25TaXplCAUNJHQwMjk3ODYyOTkzOQJfMQQOcG9zaXRpb25NYXJnaW4IBQ0kdDAyOTc4NjI5OTM5Al8yBANwb24IBQ0kdDAyOTc4NjI5OTM5Al8zBBZwb3NpdGlvbkxhc3RVcGRhdGVkQ1BGCAUNJHQwMjk3ODYyOTkzOQJfNAQRcG9zaXRpb25UaW1lc3RhbXAIBQ0kdDAyOTc4NjI5OTM5Al81BA0kdDAyOTk0NTMwMDUwCQEjZ2V0UG9zaXRpb25Ob3Rpb25hbEFuZFVucmVhbGl6ZWRQbmwDBQdfdHJhZGVyBQpfZGlyZWN0aW9uBQdfb3B0aW9uBBBwb3NpdGlvbk5vdGlvbmFsCAUNJHQwMjk5NDUzMDA1MAJfMQQNdW5yZWFsaXplZFBubAgFDSR0MDI5OTQ1MzAwNTACXzIEDSR0MDMwMDU1MzAyNjcJATBjYWxjUmVtYWluTWFyZ2luV2l0aEZ1bmRpbmdQYXltZW50QW5kUm9sbG92ZXJGZWUFBQxwb3NpdGlvblNpemUFDnBvc2l0aW9uTWFyZ2luBRZwb3NpdGlvbkxhc3RVcGRhdGVkQ1BGBRFwb3NpdGlvblRpbWVzdGFtcAUNdW5yZWFsaXplZFBubAQMcmVtYWluTWFyZ2luCAUNJHQwMzAwNTUzMDI2NwJfMQQHYmFkRGVidAgFDSR0MDMwMDU1MzAyNjcCXzIJAQ9jYWxjTWFyZ2luUmF0aW8DBQxyZW1haW5NYXJnaW4FB2JhZERlYnQFEHBvc2l0aW9uTm90aW9uYWwBDmdldE1hcmdpblJhdGlvAgdfdHJhZGVyCl9kaXJlY3Rpb24JARZnZXRNYXJnaW5SYXRpb0J5T3B0aW9uAwUHX3RyYWRlcgUKX2RpcmVjdGlvbgUPUE5MX09QVElPTl9TUE9UARtnZXRQYXJ0aWFsTGlxdWlkYXRpb25BbW91bnQCB190cmFkZXINX3Bvc2l0aW9uU2l6ZQQMbWF4aW11bVJhdGlvCQEEdm1heAIJARdwYXJ0aWFsTGlxdWlkYXRpb25SYXRpbwAJAGUCBQxERUNJTUFMX1VOSVQJAQRkaXZkAgkBDmdldE1hcmdpblJhdGlvAgUHX3RyYWRlcgkBDGdldERpcmVjdGlvbgEFDV9wb3NpdGlvblNpemUJARZtYWludGVuYW5jZU1hcmdpblJhdGlvAAQYbWF4RXhjaGFuZ2VkUG9zaXRpb25TaXplCQEEbXVsZAIJAQNhYnMBBQ1fcG9zaXRpb25TaXplBQxtYXhpbXVtUmF0aW8ECnN3YXBSZXN1bHQJAQpzd2FwT3V0cHV0AwkAZgIFDV9wb3NpdGlvblNpemUAAAUYbWF4RXhjaGFuZ2VkUG9zaXRpb25TaXplBwQcbWF4RXhjaGFuZ2VkUXVvdGVBc3NldEFtb3VudAgFCnN3YXBSZXN1bHQCXzEEC3ByaWNlSW1wYWN0CAUKc3dhcFJlc3VsdAJfNwMJAGYCCQEObWF4UHJpY2VJbXBhY3QABQtwcmljZUltcGFjdAUYbWF4RXhjaGFuZ2VkUG9zaXRpb25TaXplCQEEbXVsZAIJAQNhYnMBBQ1fcG9zaXRpb25TaXplCQEXcGFydGlhbExpcXVpZGF0aW9uUmF0aW8AARVpbnRlcm5hbENsb3NlUG9zaXRpb24IB190cmFkZXIKX2RpcmVjdGlvbgVfc2l6ZQRfZmVlFF9taW5RdW90ZUFzc2V0QW1vdW50DF9hZGRUb01hcmdpbhRfY2hlY2tNYXhQcmljZUltcGFjdApfbGlxdWlkYXRlBA0kdDAzMTQzMDMxNTk4CQELZ2V0UG9zaXRpb24CBQdfdHJhZGVyBQpfZGlyZWN0aW9uBA9vbGRQb3NpdGlvblNpemUIBQ0kdDAzMTQzMDMxNTk4Al8xBBFvbGRQb3NpdGlvbk1hcmdpbggFDSR0MDMxNDMwMzE1OTgCXzIEF29sZFBvc2l0aW9uT3Blbk5vdGlvbmFsCAUNJHQwMzE0MzAzMTU5OAJfMwQUb2xkUG9zaXRpb25Mc3RVcGRDUEYIBQ0kdDAzMTQzMDMxNTk4Al80BBRvbGRQb3NpdGlvblRpbWVzdGFtcAgFDSR0MDMxNDMwMzE1OTgCXzUEDmlzTG9uZ1Bvc2l0aW9uCQBmAgUPb2xkUG9zaXRpb25TaXplAAAEEmFic09sZFBvc2l0aW9uU2l6ZQkBA2FicwEFD29sZFBvc2l0aW9uU2l6ZQMDCQBnAgUSYWJzT2xkUG9zaXRpb25TaXplBQVfc2l6ZQkAZgIFBV9zaXplAAAHBA5pc1BhcnRpYWxDbG9zZQkAZgIFEmFic09sZFBvc2l0aW9uU2l6ZQUFX3NpemUEDSR0MDMxODkwMzIzNDEJAQpzd2FwT3V0cHV0AwkAZgIFD29sZFBvc2l0aW9uU2l6ZQAABQVfc2l6ZQUUX2NoZWNrTWF4UHJpY2VJbXBhY3QEGWV4Y2hhbmdlZFF1b3RlQXNzZXRBbW91bnQIBQ0kdDAzMTg5MDMyMzQxAl8xBBZxdW90ZUFzc2V0UmVzZXJ2ZUFmdGVyCAUNJHQwMzE4OTAzMjM0MQJfMgQVYmFzZUFzc2V0UmVzZXJ2ZUFmdGVyCAUNJHQwMzE4OTAzMjM0MQJfMwQWdG90YWxQb3NpdGlvblNpemVBZnRlcggFDSR0MDMxODkwMzIzNDECXzQEFWV4Y2hhbmdlZFBvc2l0aW9uU2l6ZQMJAGYCBQ9vbGRQb3NpdGlvblNpemUAAAkBAS0BBQVfc2l6ZQUFX3NpemUEDSR0MDMyNTU2MzI3ODAJASNnZXRQb3NpdGlvbk5vdGlvbmFsQW5kVW5yZWFsaXplZFBubAMFB190cmFkZXIFCl9kaXJlY3Rpb24FD1BOTF9PUFRJT05fU1BPVAQTb2xkUG9zaXRpb25Ob3Rpb25hbAgFDSR0MDMyNTU2MzI3ODACXzEEDXVucmVhbGl6ZWRQbmwIBQ0kdDAzMjU1NjMyNzgwAl8yBA1yZWFsaXplZFJhdGlvCQEEZGl2ZAIJAQNhYnMBBRVleGNoYW5nZWRQb3NpdGlvblNpemUFEmFic09sZFBvc2l0aW9uU2l6ZQQLcmVhbGl6ZWRQbmwJAQRtdWxkAgUNdW5yZWFsaXplZFBubAUNcmVhbGl6ZWRSYXRpbwQNJHQwMzMxMjEzMzM2NwkBMGNhbGNSZW1haW5NYXJnaW5XaXRoRnVuZGluZ1BheW1lbnRBbmRSb2xsb3ZlckZlZQUFD29sZFBvc2l0aW9uU2l6ZQURb2xkUG9zaXRpb25NYXJnaW4FFG9sZFBvc2l0aW9uTHN0VXBkQ1BGBRRvbGRQb3NpdGlvblRpbWVzdGFtcAUNdW5yZWFsaXplZFBubAQScmVtYWluTWFyZ2luQmVmb3JlCAUNJHQwMzMxMjEzMzM2NwJfMQQCeDEIBQ0kdDAzMzEyMTMzMzY3Al8yBAJ4MggFDSR0MDMzMTIxMzMzNjcCXzMEC3JvbGxvdmVyRmVlCAUNJHQwMzMxMjEzMzM2NwJfNAQPcG9zaXRpb25CYWREZWJ0CAkBMGNhbGNSZW1haW5NYXJnaW5XaXRoRnVuZGluZ1BheW1lbnRBbmRSb2xsb3ZlckZlZQUFD29sZFBvc2l0aW9uU2l6ZQURb2xkUG9zaXRpb25NYXJnaW4FFG9sZFBvc2l0aW9uTHN0VXBkQ1BGBRRvbGRQb3NpdGlvblRpbWVzdGFtcAULcmVhbGl6ZWRQbmwCXzIEEHJlYWxpemVkQ2xvc2VGZWUJAQRtdWxkAgkBBG11bGQCBRNvbGRQb3NpdGlvbk5vdGlvbmFsBQ1yZWFsaXplZFJhdGlvBQRfZmVlBBJ1bnJlYWxpemVkUG5sQWZ0ZXIJAGUCBQ11bnJlYWxpemVkUG5sBQtyZWFsaXplZFBubAQScmVtYWluT3Blbk5vdGlvbmFsAwkAZgIFD29sZFBvc2l0aW9uU2l6ZQAACQBlAgkAZQIFE29sZFBvc2l0aW9uTm90aW9uYWwFGWV4Y2hhbmdlZFF1b3RlQXNzZXRBbW91bnQFEnVucmVhbGl6ZWRQbmxBZnRlcgkAZQIJAGQCBRJ1bnJlYWxpemVkUG5sQWZ0ZXIFE29sZFBvc2l0aW9uTm90aW9uYWwFGWV4Y2hhbmdlZFF1b3RlQXNzZXRBbW91bnQED25ld1Bvc2l0aW9uU2l6ZQkAZAIFD29sZFBvc2l0aW9uU2l6ZQUVZXhjaGFuZ2VkUG9zaXRpb25TaXplBA0kdDAzNDc3MzM1MTU5AwkAAAIFD25ld1Bvc2l0aW9uU2l6ZQAACQCUCgIAAAAACQCUCgIJAQNhYnMBBRJyZW1haW5PcGVuTm90aW9uYWwJAR9sYXRlc3RDdW11bGF0aXZlUHJlbWl1bUZyYWN0aW9uAQUPbmV3UG9zaXRpb25TaXplBBduZXdQb3NpdGlvbk9wZW5Ob3Rpb25hbAgFDSR0MDM0NzczMzUxNTkCXzEEFG5ld1Bvc2l0aW9uTHN0VXBkQ1BGCAUNJHQwMzQ3NzMzNTE1OQJfMgQRb3Blbk5vdGlvbmFsRGVsdGEJAGUCBRdvbGRQb3NpdGlvbk9wZW5Ob3Rpb25hbAUXbmV3UG9zaXRpb25PcGVuTm90aW9uYWwEC21hcmdpblJhdGlvCQEWZ2V0TWFyZ2luUmF0aW9CeU9wdGlvbgMFB190cmFkZXIFCl9kaXJlY3Rpb24FD1BOTF9PUFRJT05fU1BPVAQebmV3UG9zaXRpb25NYXJnaW5XaXRoU2FtZVJhdGlvAwkAZgIFD29sZFBvc2l0aW9uU2l6ZQAACQBlAgkBBG11bGQCCQBkAgUXbmV3UG9zaXRpb25PcGVuTm90aW9uYWwFEnVucmVhbGl6ZWRQbmxBZnRlcgULbWFyZ2luUmF0aW8FEnVucmVhbGl6ZWRQbmxBZnRlcgkAZQIJAQRtdWxkAgkAZQIFF25ld1Bvc2l0aW9uT3Blbk5vdGlvbmFsBRJ1bnJlYWxpemVkUG5sQWZ0ZXIFC21hcmdpblJhdGlvBRJ1bnJlYWxpemVkUG5sQWZ0ZXIEEW1hcmdpblRvVHJhZGVyUmF3CQBlAgkAZQIFEnJlbWFpbk1hcmdpbkJlZm9yZQkAZAIFHm5ld1Bvc2l0aW9uTWFyZ2luV2l0aFNhbWVSYXRpbwUSdW5yZWFsaXplZFBubEFmdGVyBRByZWFsaXplZENsb3NlRmVlBA5tYXJnaW5Ub1RyYWRlcgMJAGYCAAAFEW1hcmdpblRvVHJhZGVyUmF3AwUKX2xpcXVpZGF0ZQAACQACAQI3SW52YWxpZCBpbnRlcm5hbENsb3NlUG9zaXRpb24gcGFyYW1zOiB1bmFibGUgdG8gcGF5IGZlZQURbWFyZ2luVG9UcmFkZXJSYXcEEW5ld1Bvc2l0aW9uTWFyZ2luAwUMX2FkZFRvTWFyZ2luCQBkAgUebmV3UG9zaXRpb25NYXJnaW5XaXRoU2FtZVJhdGlvBQ5tYXJnaW5Ub1RyYWRlcgUebmV3UG9zaXRpb25NYXJnaW5XaXRoU2FtZVJhdGlvAwMJAQIhPQIFFF9taW5RdW90ZUFzc2V0QW1vdW50AAAJAGYCBRRfbWluUXVvdGVBc3NldEFtb3VudAUZZXhjaGFuZ2VkUXVvdGVBc3NldEFtb3VudAcJAAIBCQCsAgIJAKwCAgkArAICAg1MaW1pdCBlcnJvcjogCQCkAwEFGWV4Y2hhbmdlZFF1b3RlQXNzZXRBbW91bnQCAyA8IAkApAMBBRRfbWluUXVvdGVBc3NldEFtb3VudAkAowoRBQ9uZXdQb3NpdGlvblNpemUFEW5ld1Bvc2l0aW9uTWFyZ2luBRduZXdQb3NpdGlvbk9wZW5Ob3Rpb25hbAUUbmV3UG9zaXRpb25Mc3RVcGRDUEYFD3Bvc2l0aW9uQmFkRGVidAULcmVhbGl6ZWRQbmwDAwUMX2FkZFRvTWFyZ2luBQ5pc1BhcnRpYWxDbG9zZQcAAAUObWFyZ2luVG9UcmFkZXIFFnF1b3RlQXNzZXRSZXNlcnZlQWZ0ZXIFFWJhc2VBc3NldFJlc2VydmVBZnRlcgUWdG90YWxQb3NpdGlvblNpemVBZnRlcgkAZQIJARRvcGVuSW50ZXJlc3ROb3Rpb25hbAAFEW9wZW5Ob3Rpb25hbERlbHRhCQBlAgkBFXRvdGFsTG9uZ1Bvc2l0aW9uU2l6ZQADBQ5pc0xvbmdQb3NpdGlvbgkBA2FicwEFFWV4Y2hhbmdlZFBvc2l0aW9uU2l6ZQAACQBlAgkBFnRvdGFsU2hvcnRQb3NpdGlvblNpemUAAwkBASEBBQ5pc0xvbmdQb3NpdGlvbgkBA2FicwEFFWV4Y2hhbmdlZFBvc2l0aW9uU2l6ZQAACQBlAgkBEG9wZW5JbnRlcmVzdExvbmcAAwUOaXNMb25nUG9zaXRpb24FEW9wZW5Ob3Rpb25hbERlbHRhAAAJAGUCCQERb3BlbkludGVyZXN0U2hvcnQAAwkBASEBBQ5pc0xvbmdQb3NpdGlvbgURb3Blbk5vdGlvbmFsRGVsdGEAAAkAZAIFEHJlYWxpemVkQ2xvc2VGZWUFC3JvbGxvdmVyRmVlBRlleGNoYW5nZWRRdW90ZUFzc2V0QW1vdW50CQACAQkArAICCQCsAgIJAKwCAgI9SW52YWxpZCBpbnRlcm5hbENsb3NlUG9zaXRpb24gcGFyYW1zOiBpbnZhbGlkIHBvc2l0aW9uIHNpemU6IAkApAMBBQVfc2l6ZQIGIG1heDogCQCkAwEFEmFic09sZFBvc2l0aW9uU2l6ZQETZ2V0VGVybWluYWxBbW1TdGF0ZQAEDV9wb3NpdGlvblNpemUJARF0b3RhbFBvc2l0aW9uU2l6ZQADCQAAAgUNX3Bvc2l0aW9uU2l6ZQAACQCUCgIJAQZxdEFzdFIACQEGYnNBc3RSAAQJZGlyZWN0aW9uCQBmAgUNX3Bvc2l0aW9uU2l6ZQAABA0kdDAzODQwNjM4NTg1CQEKc3dhcE91dHB1dAMFCWRpcmVjdGlvbgkBA2FicwEFDV9wb3NpdGlvblNpemUHBBVjdXJyZW50TmV0TWFya2V0VmFsdWUIBQ0kdDAzODQwNjM4NTg1Al8xBBl0ZXJtaW5hbFF1b3RlQXNzZXRSZXNlcnZlCAUNJHQwMzg0MDYzODU4NQJfMgQYdGVybWluYWxCYXNlQXNzZXRSZXNlcnZlCAUNJHQwMzg0MDYzODU4NQJfMwkAlAoCBRl0ZXJtaW5hbFF1b3RlQXNzZXRSZXNlcnZlBRh0ZXJtaW5hbEJhc2VBc3NldFJlc2VydmUBE2dldFF1b3RlQXNzZXRXZWlnaHQEEGJhc2VBc3NldFJlc2VydmURdG90YWxQb3NpdGlvblNpemURcXVvdGVBc3NldFJlc2VydmULdGFyZ2V0UHJpY2UEAWIJALYCAQUQYmFzZUFzc2V0UmVzZXJ2ZQQCc3oJALYCAQURdG90YWxQb3NpdGlvblNpemUEAXEJALYCAQURcXVvdGVBc3NldFJlc2VydmUEAXAJALYCAQULdGFyZ2V0UHJpY2UEAWsJAQVibXVsZAIFAXEFAWIEBG5ld0IJALcCAgUBYgUCc3oEBG5ld1EJAQViZGl2ZAIFAWsFBG5ld0IEAXoJAQViZGl2ZAIFBG5ld1EFBG5ld0IEBnJlc3VsdAkBBWJkaXZkAgUBcAUBegkAoAMBBQZyZXN1bHQBFGdldFN5bmNUZXJtaW5hbFByaWNlAw5fdGVybWluYWxQcmljZQdfcXRBc3RSB19ic0FzdFIEDV9wb3NpdGlvblNpemUJARF0b3RhbFBvc2l0aW9uU2l6ZQADCQAAAgUNX3Bvc2l0aW9uU2l6ZQAABAluZXdRdEFzdFcJAQRkaXZkAgkBBG11bGQCBQ5fdGVybWluYWxQcmljZQUHX2JzQXN0UgUHX3F0QXN0UgkAlQoDBQluZXdRdEFzdFcFDERFQ0lNQUxfVU5JVAAABAlkaXJlY3Rpb24JAGYCBQ1fcG9zaXRpb25TaXplAAAEFWN1cnJlbnROZXRNYXJrZXRWYWx1ZQgJAQpzd2FwT3V0cHV0AwUJZGlyZWN0aW9uCQEDYWJzAQUNX3Bvc2l0aW9uU2l6ZQcCXzEECW5ld1F0QXN0VwkBE2dldFF1b3RlQXNzZXRXZWlnaHQEBQdfYnNBc3RSBQ1fcG9zaXRpb25TaXplBQdfcXRBc3RSBQ5fdGVybWluYWxQcmljZQQJbmV3QnNBc3RXBQxERUNJTUFMX1VOSVQEDW1hcmdpblRvVmF1bHQICQErZ2V0UG9zaXRpb25Ob3Rpb25hbEFuZFVucmVhbGl6ZWRQbmxCeVZhbHVlcwcFDV9wb3NpdGlvblNpemUFFWN1cnJlbnROZXRNYXJrZXRWYWx1ZQUHX3F0QXN0UgUJbmV3UXRBc3RXBQdfYnNBc3RSBQluZXdCc0FzdFcFD1BOTF9PUFRJT05fU1BPVAJfMgkAlQoDBQluZXdRdEFzdFcFCW5ld0JzQXN0VwUNbWFyZ2luVG9WYXVsdAEKZ2V0RnVuZGluZwAED3VuZGVybHlpbmdQcmljZQkBDmdldE9yYWNsZVByaWNlAAQJc3BvdFByaWNlCQEMZ2V0U3BvdFByaWNlAAQHcHJlbWl1bQkAZQIFCXNwb3RQcmljZQUPdW5kZXJseWluZ1ByaWNlAwMJAQ5pc01hcmtldENsb3NlZAAGAwkAAAIJAQtmdW5kaW5nTW9kZQAFEkZVTkRJTkdfQVNZTU1FVFJJQwMJAAACCQEWdG90YWxTaG9ydFBvc2l0aW9uU2l6ZQAAAAYJAAACCQEVdG90YWxMb25nUG9zaXRpb25TaXplAAAABwkAlQoDAAAAAAAAAwkAZgIAAAUHcHJlbWl1bQQUc2hvcnRQcmVtaXVtRnJhY3Rpb24JAQRkaXZkAgkBBG11bGQCBQdwcmVtaXVtCQEUZnVuZGluZ1BlcmlvZERlY2ltYWwABQdPTkVfREFZAwkAAAIJAQtmdW5kaW5nTW9kZQAFEkZVTkRJTkdfQVNZTU1FVFJJQwQTbG9uZ1ByZW1pdW1GcmFjdGlvbgkBBGRpdmQCCQEEbXVsZAIFFHNob3J0UHJlbWl1bUZyYWN0aW9uCQEWdG90YWxTaG9ydFBvc2l0aW9uU2l6ZQAJARV0b3RhbExvbmdQb3NpdGlvblNpemUACQCVCgMFFHNob3J0UHJlbWl1bUZyYWN0aW9uBRNsb25nUHJlbWl1bUZyYWN0aW9uAAAEGXNob3J0VG90YWxQcmVtaXVtRnJhY3Rpb24JAQNhYnMBCQEEbXVsZAIFFHNob3J0UHJlbWl1bUZyYWN0aW9uCQEWdG90YWxTaG9ydFBvc2l0aW9uU2l6ZQAEGGxvbmdUb3RhbFByZW1pdW1GcmFjdGlvbgkBA2FicwEJAQRtdWxkAgUUc2hvcnRQcmVtaXVtRnJhY3Rpb24JARV0b3RhbExvbmdQb3NpdGlvblNpemUABA5wcmVtaXVtVG9WYXVsdAkAZQIFGXNob3J0VG90YWxQcmVtaXVtRnJhY3Rpb24FGGxvbmdUb3RhbFByZW1pdW1GcmFjdGlvbgkAlQoDBRRzaG9ydFByZW1pdW1GcmFjdGlvbgUUc2hvcnRQcmVtaXVtRnJhY3Rpb24FDnByZW1pdW1Ub1ZhdWx0BBNsb25nUHJlbWl1bUZyYWN0aW9uCQEEZGl2ZAIJAQRtdWxkAgUHcHJlbWl1bQkBFGZ1bmRpbmdQZXJpb2REZWNpbWFsAAUHT05FX0RBWQMJAAACCQELZnVuZGluZ01vZGUABRJGVU5ESU5HX0FTWU1NRVRSSUMEFHNob3J0UHJlbWl1bUZyYWN0aW9uCQEEZGl2ZAIJAQRtdWxkAgUTbG9uZ1ByZW1pdW1GcmFjdGlvbgkBFXRvdGFsTG9uZ1Bvc2l0aW9uU2l6ZQAJARZ0b3RhbFNob3J0UG9zaXRpb25TaXplAAkAlQoDBRRzaG9ydFByZW1pdW1GcmFjdGlvbgUTbG9uZ1ByZW1pdW1GcmFjdGlvbgAABBhsb25nVG90YWxQcmVtaXVtRnJhY3Rpb24JAQNhYnMBCQEEbXVsZAIFE2xvbmdQcmVtaXVtRnJhY3Rpb24JARV0b3RhbExvbmdQb3NpdGlvblNpemUABBlzaG9ydFRvdGFsUHJlbWl1bUZyYWN0aW9uCQEDYWJzAQkBBG11bGQCBRNsb25nUHJlbWl1bUZyYWN0aW9uCQEWdG90YWxTaG9ydFBvc2l0aW9uU2l6ZQAEDnByZW1pdW1Ub1ZhdWx0CQBlAgUYbG9uZ1RvdGFsUHJlbWl1bUZyYWN0aW9uBRlzaG9ydFRvdGFsUHJlbWl1bUZyYWN0aW9uCQCVCgMFE2xvbmdQcmVtaXVtRnJhY3Rpb24FE2xvbmdQcmVtaXVtRnJhY3Rpb24FDnByZW1pdW1Ub1ZhdWx0AQ5nZXRBZGp1c3RlZEZlZQILX2FydGlmYWN0SWQQX2Jhc2VGZWVEaXNjb3VudAQKYmFzZUZlZVJhdwkBA2ZlZQAEB2Jhc2VGZWUJAQRtdWxkAgUKYmFzZUZlZVJhdwUQX2Jhc2VGZWVEaXNjb3VudAQNJHQwNDMyNDk0Mzc0NAMJAQIhPQIFC19hcnRpZmFjdElkAgAEDGFydGlmYWN0S2luZAkBBHN0ckECCQERbmZ0TWFuYWdlckFkZHJlc3MACQEOdG9Db21wb3NpdGVLZXkCBQxrX3Rva2VuX3R5cGUFC19hcnRpZmFjdElkAwkAAAIFDGFydGlmYWN0S2luZAUYRkVFX1JFRFVDVElPTl9UT0tFTl9UWVBFBAlyZWR1Y3Rpb24JAQRpbnRBAgkBEW5mdE1hbmFnZXJBZGRyZXNzAAkBDnRvQ29tcG9zaXRlS2V5AgUNa190b2tlbl9wYXJhbQULX2FydGlmYWN0SWQEC2FkanVzdGVkRmVlCQEEbXVsZAIFB2Jhc2VGZWUFCXJlZHVjdGlvbgkAlAoCBQthZGp1c3RlZEZlZQYJAAIBAhlJbnZhbGlkIGF0dGFjaGVkIGFydGlmYWN0CQCUCgIFB2Jhc2VGZWUHBAthZGp1c3RlZEZlZQgFDSR0MDQzMjQ5NDM3NDQCXzEEDGJ1cm5BcnRpZmFjdAgFDSR0MDQzMjQ5NDM3NDQCXzIJAJQKAgULYWRqdXN0ZWRGZWUFDGJ1cm5BcnRpZmFjdAEYZ2V0Rm9yVHJhZGVyV2l0aEFydGlmYWN0AgdfdHJhZGVyC19hcnRpZmFjdElkBBBkb0dldEZlZURpc2NvdW50CQD8BwQJAQxtaW5lckFkZHJlc3MAAhJjb21wdXRlRmVlRGlzY291bnQJAMwIAgUHX3RyYWRlcgUDbmlsBQNuaWwDCQAAAgUQZG9HZXRGZWVEaXNjb3VudAUQZG9HZXRGZWVEaXNjb3VudAQLZmVlRGlzY291bnQEByRtYXRjaDAFEGRvR2V0RmVlRGlzY291bnQDCQABAgUHJG1hdGNoMAIDSW50BAF4BQckbWF0Y2gwBQF4CQACAQIhSW52YWxpZCBjb21wdXRlRmVlRGlzY291bnQgcmVzdWx0BA0kdDA0NDA5MDQ0MTY0CQEOZ2V0QWRqdXN0ZWRGZWUCBQtfYXJ0aWZhY3RJZAULZmVlRGlzY291bnQEC2FkanVzdGVkRmVlCAUNJHQwNDQwOTA0NDE2NAJfMQQMYnVybkFydGlmYWN0CAUNJHQwNDQwOTA0NDE2NAJfMgkAlAoCBQthZGp1c3RlZEZlZQUMYnVybkFydGlmYWN0CQACAQIkU3RyaWN0IHZhbHVlIGlzIG5vdCBlcXVhbCB0byBpdHNlbGYuAQ1nZXRBcnRpZmFjdElkAQFpBAphcnRpZmFjdElkAwkAZgIJAJADAQgFAWkIcGF5bWVudHMAAQkA2AQBCQETdmFsdWVPckVycm9yTWVzc2FnZQIICQCRAwIIBQFpCHBheW1lbnRzAAEHYXNzZXRJZAISSW52YWxpZCBhcnRpZmFjdElkAgAFCmFydGlmYWN0SWQBDWRpc3RyaWJ1dGVGZWUBCl9mZWVBbW91bnQEDGZlZVRvU3Rha2VycwkBBG11bGQCBQpfZmVlQW1vdW50CQETZmVlVG9TdGFrZXJzUGVyY2VudAAECmZlZVRvVmF1bHQJAGUCBQpfZmVlQW1vdW50BQxmZWVUb1N0YWtlcnMJAJQKAgUMZmVlVG9TdGFrZXJzBQpmZWVUb1ZhdWx0AQ51cGRhdGVTZXR0aW5ncxEQX2luaXRNYXJnaW5SYXRpbwRfbW1yFF9saXF1aWRhdGlvbkZlZVJhdGlvDl9mdW5kaW5nUGVyaW9kBF9mZWUMX3NwcmVhZExpbWl0D19tYXhQcmljZUltcGFjdBhfcGFydGlhbExpcXVpZGF0aW9uUmF0aW8PX21heFByaWNlU3ByZWFkEF9tYXhPcGVuTm90aW9uYWwUX2ZlZVRvU3Rha2Vyc1BlcmNlbnQPX21heE9yYWNsZURlbGF5DF9yb2xsb3ZlckZlZQxfZnVuZGluZ01vZGULX29yYWNsZU1vZGUTX21pbkluaXRNYXJnaW5SYXRpbw1fcG9zaXRpb25Nb2RlCQDMCAIJAQxJbnRlZ2VyRW50cnkCBRFrX2luaXRNYXJnaW5SYXRpbwUQX2luaXRNYXJnaW5SYXRpbwkAzAgCCQEMSW50ZWdlckVudHJ5AgUUa19taW5Jbml0TWFyZ2luUmF0aW8FE19taW5Jbml0TWFyZ2luUmF0aW8JAMwIAgkBDEludGVnZXJFbnRyeQIFGGtfbWFpbnRlbmFuY2VNYXJnaW5SYXRpbwUEX21tcgkAzAgCCQEMSW50ZWdlckVudHJ5AgUVa19saXF1aWRhdGlvbkZlZVJhdGlvBRRfbGlxdWlkYXRpb25GZWVSYXRpbwkAzAgCCQEMSW50ZWdlckVudHJ5AgUPa19mdW5kaW5nUGVyaW9kBQ5fZnVuZGluZ1BlcmlvZAkAzAgCCQEMSW50ZWdlckVudHJ5AgUFa19mZWUFBF9mZWUJAMwIAgkBDEludGVnZXJFbnRyeQIFDWtfc3ByZWFkTGltaXQFDF9zcHJlYWRMaW1pdAkAzAgCCQEMSW50ZWdlckVudHJ5AgUQa19tYXhQcmljZUltcGFjdAUPX21heFByaWNlSW1wYWN0CQDMCAIJAQxJbnRlZ2VyRW50cnkCBRlrX3BhcnRpYWxMaXF1aWRhdGlvblJhdGlvBRhfcGFydGlhbExpcXVpZGF0aW9uUmF0aW8JAMwIAgkBDEludGVnZXJFbnRyeQIFEGtfbWF4UHJpY2VTcHJlYWQFD19tYXhQcmljZVNwcmVhZAkAzAgCCQEMSW50ZWdlckVudHJ5AgURa19tYXhPcGVuTm90aW9uYWwFEF9tYXhPcGVuTm90aW9uYWwJAMwIAgkBDEludGVnZXJFbnRyeQIFFWtfZmVlVG9TdGFrZXJzUGVyY2VudAUUX2ZlZVRvU3Rha2Vyc1BlcmNlbnQJAMwIAgkBDEludGVnZXJFbnRyeQIFEGtfbWF4T3JhY2xlRGVsYXkFD19tYXhPcmFjbGVEZWxheQkAzAgCCQEMSW50ZWdlckVudHJ5AgUNa19yb2xsb3ZlckZlZQUMX3JvbGxvdmVyRmVlCQDMCAIJAQxJbnRlZ2VyRW50cnkCBQ1rX2Z1bmRpbmdNb2RlBQxfZnVuZGluZ01vZGUJAMwIAgkBDEludGVnZXJFbnRyeQIFDGtfb3JhY2xlTW9kZQULX29yYWNsZU1vZGUJAMwIAgkBDEludGVnZXJFbnRyeQIFDmtfcG9zaXRpb25Nb2RlBQ1fcG9zaXRpb25Nb2RlBQNuaWwBDXVwZGF0ZUZ1bmRpbmcFEV9uZXh0RnVuZGluZ0Jsb2NrJF9sYXRlc3RMb25nQ3VtdWxhdGl2ZVByZW1pdW1GcmFjdGlvbiVfbGF0ZXN0U2hvcnRDdW11bGF0aXZlUHJlbWl1bUZyYWN0aW9uEF9sb25nRnVuZGluZ1JhdGURX3Nob3J0RnVuZGluZ1JhdGUJAMwIAgkBDEludGVnZXJFbnRyeQIFEmtfbmV4dEZ1bmRpbmdCbG9jawURX25leHRGdW5kaW5nQmxvY2sJAMwIAgkBDEludGVnZXJFbnRyeQIFJWtfbGF0ZXN0TG9uZ0N1bXVsYXRpdmVQcmVtaXVtRnJhY3Rpb24FJF9sYXRlc3RMb25nQ3VtdWxhdGl2ZVByZW1pdW1GcmFjdGlvbgkAzAgCCQEMSW50ZWdlckVudHJ5AgUma19sYXRlc3RTaG9ydEN1bXVsYXRpdmVQcmVtaXVtRnJhY3Rpb24FJV9sYXRlc3RTaG9ydEN1bXVsYXRpdmVQcmVtaXVtRnJhY3Rpb24JAMwIAgkBDEludGVnZXJFbnRyeQIFEWtfbG9uZ0Z1bmRpbmdSYXRlBRBfbG9uZ0Z1bmRpbmdSYXRlCQDMCAIJAQxJbnRlZ2VyRW50cnkCBRJrX3Nob3J0RnVuZGluZ1JhdGUFEV9zaG9ydEZ1bmRpbmdSYXRlBQNuaWwBH2luY3JlbWVudFBvc2l0aW9uU2VxdWVuY2VOdW1iZXIDDl9pc05ld1Bvc2l0aW9uB190cmFkZXIKX2RpcmVjdGlvbgQLcG9zaXRpb25LZXkJAKwCAgkArAICBQdfdHJhZGVyAgFfCQCkAwEFCl9kaXJlY3Rpb24DBQ5faXNOZXdQb3NpdGlvbgQPY3VycmVudFNlcXVlbmNlCQEMbGFzdFNlcXVlbmNlAAkAzAgCCQEMSW50ZWdlckVudHJ5AgkBDnRvQ29tcG9zaXRlS2V5AgUSa19wb3NpdGlvblNlcXVlbmNlBQtwb3NpdGlvbktleQkAZAIFD2N1cnJlbnRTZXF1ZW5jZQABCQDMCAIJAQxJbnRlZ2VyRW50cnkCBQprX3NlcXVlbmNlCQBkAgUPY3VycmVudFNlcXVlbmNlAAEFA25pbAUDbmlsARF1cGRhdGVQb3NpdGlvbkZlZQQOX2lzTmV3UG9zaXRpb24HX3RyYWRlcgpfZGlyZWN0aW9uBF9mZWUEC3Bvc2l0aW9uS2V5CQCsAgIJAKwCAgUHX3RyYWRlcgIBXwkApAMBBQpfZGlyZWN0aW9uAwUOX2lzTmV3UG9zaXRpb24JAMwIAgkBDEludGVnZXJFbnRyeQIJAQ50b0NvbXBvc2l0ZUtleQIFDWtfcG9zaXRpb25GZWUFC3Bvc2l0aW9uS2V5BQRfZmVlBQNuaWwFA25pbAEOdXBkYXRlUG9zaXRpb24GB190cmFkZXIFX3NpemUHX21hcmdpbg1fb3Blbk5vdGlvbmFsIF9sYXRlc3RDdW11bGF0aXZlUHJlbWl1bUZyYWN0aW9uEF9sYXRlc3RUaW1lc3RhbXAECWRpcmVjdGlvbgkBDGdldERpcmVjdGlvbgEFBV9zaXplBAtwb3NpdGlvbktleQkArAICCQCsAgIFB190cmFkZXICAV8JAKQDAQUJZGlyZWN0aW9uCQDMCAIJAQxJbnRlZ2VyRW50cnkCCQEOdG9Db21wb3NpdGVLZXkCBQ5rX3Bvc2l0aW9uU2l6ZQULcG9zaXRpb25LZXkFBV9zaXplCQDMCAIJAQxJbnRlZ2VyRW50cnkCCQEOdG9Db21wb3NpdGVLZXkCBRBrX3Bvc2l0aW9uTWFyZ2luBQtwb3NpdGlvbktleQUHX21hcmdpbgkAzAgCCQEMSW50ZWdlckVudHJ5AgkBDnRvQ29tcG9zaXRlS2V5AgUWa19wb3NpdGlvbk9wZW5Ob3Rpb25hbAULcG9zaXRpb25LZXkFDV9vcGVuTm90aW9uYWwJAMwIAgkBDEludGVnZXJFbnRyeQIJAQ50b0NvbXBvc2l0ZUtleQIFLmtfcG9zaXRpb25MYXN0VXBkYXRlZEN1bXVsYXRpdmVQcmVtaXVtRnJhY3Rpb24FC3Bvc2l0aW9uS2V5BSBfbGF0ZXN0Q3VtdWxhdGl2ZVByZW1pdW1GcmFjdGlvbgkAzAgCCQEMSW50ZWdlckVudHJ5AgkBDnRvQ29tcG9zaXRlS2V5AgUea19wb3NpdGlvbkxhc3RVcGRhdGVkVGltZXN0YW1wBQtwb3NpdGlvbktleQUQX2xhdGVzdFRpbWVzdGFtcAUDbmlsARF1cGRhdGVBbW1SZXNlcnZlcwIHX3F0QXN0UgdfYnNBc3RSAwMJAGYCAAAFB19xdEFzdFIGCQBmAgAABQdfYnNBc3RSCQACAQIhSW52YWxpZCBhbW91bnQgdG8gdXBkYXRlIHJlc2VydmVzAwMJAQIhPQIFB19xdEFzdFIJAQdxdEFzdFIwAAYJAQIhPQIFB19ic0FzdFIJAQdic0FzdFIwAAkAzAgCCQEMSW50ZWdlckVudHJ5AgUTa19xdW90ZUFzc2V0UmVzZXJ2ZQUHX3F0QXN0UgkAzAgCCQEMSW50ZWdlckVudHJ5AgUSa19iYXNlQXNzZXRSZXNlcnZlBQdfYnNBc3RSBQNuaWwFA25pbAEQdXBkYXRlQW1tV2VpZ2h0cwIHX3F0QXN0VwdfYnNBc3RXAwMJAQIhPQIFB19xdEFzdFcJAQZxdEFzdFcABgkBAiE9AgUHX2JzQXN0VwkBBmJzQXN0VwAJAMwIAgkBDEludGVnZXJFbnRyeQIFEmtfcXVvdGVBc3NldFdlaWdodAUHX3F0QXN0VwkAzAgCCQEMSW50ZWdlckVudHJ5AgURa19iYXNlQXNzZXRXZWlnaHQFB19ic0FzdFcFA25pbAUDbmlsAQl1cGRhdGVBbW0IB19xdEFzdFIHX2JzQXN0UhdfdG90YWxQb3NpdGlvblNpemVBZnRlchVfb3BlbkludGVyZXN0Tm90aW9uYWwWX3RvdGFsTG9uZ1Bvc2l0aW9uU2l6ZRdfdG90YWxTaG9ydFBvc2l0aW9uU2l6ZRZfdG90YWxMb25nT3Blbk5vdGlvbmFsF190b3RhbFNob3J0T3Blbk5vdGlvbmFsBAdfcXRBc3RXCQEGcXRBc3RXAAQHX2JzQXN0VwkBBmJzQXN0VwADCQECIT0CCQBlAgUWX3RvdGFsTG9uZ1Bvc2l0aW9uU2l6ZQUXX3RvdGFsU2hvcnRQb3NpdGlvblNpemUFF190b3RhbFBvc2l0aW9uU2l6ZUFmdGVyCQACAQkArAICCQCsAgIJAKwCAgkArAICCQCsAgICGEludmFsaWQgQU1NIHN0YXRlIGRhdGE6IAkApAMBBRZfdG90YWxMb25nUG9zaXRpb25TaXplAgQgLSAgCQCkAwEFF190b3RhbFNob3J0UG9zaXRpb25TaXplAgQgIT0gCQCkAwEFF190b3RhbFBvc2l0aW9uU2l6ZUFmdGVyCQDOCAIJARF1cGRhdGVBbW1SZXNlcnZlcwIFB19xdEFzdFIFB19ic0FzdFIJAMwIAgkBDEludGVnZXJFbnRyeQIFE2tfdG90YWxQb3NpdGlvblNpemUFF190b3RhbFBvc2l0aW9uU2l6ZUFmdGVyCQDMCAIJAQxJbnRlZ2VyRW50cnkCBRZrX29wZW5JbnRlcmVzdE5vdGlvbmFsBRVfb3BlbkludGVyZXN0Tm90aW9uYWwJAMwIAgkBDEludGVnZXJFbnRyeQIFF2tfdG90YWxMb25nUG9zaXRpb25TaXplBRZfdG90YWxMb25nUG9zaXRpb25TaXplCQDMCAIJAQxJbnRlZ2VyRW50cnkCBRhrX3RvdGFsU2hvcnRQb3NpdGlvblNpemUFF190b3RhbFNob3J0UG9zaXRpb25TaXplCQDMCAIJAQxJbnRlZ2VyRW50cnkCBRJrX29wZW5JbnRlcmVzdExvbmcFFl90b3RhbExvbmdPcGVuTm90aW9uYWwJAMwIAgkBDEludGVnZXJFbnRyeQIFE2tfb3BlbkludGVyZXN0U2hvcnQFF190b3RhbFNob3J0T3Blbk5vdGlvbmFsBQNuaWwBDmRlbGV0ZVBvc2l0aW9uAgdfdHJhZGVyCl9kaXJlY3Rpb24EC3Bvc2l0aW9uS2V5CQCsAgIJAKwCAgUHX3RyYWRlcgIBXwkApAMBBQpfZGlyZWN0aW9uCQDMCAIJAQtEZWxldGVFbnRyeQEJAQ50b0NvbXBvc2l0ZUtleQIFDmtfcG9zaXRpb25TaXplBQtwb3NpdGlvbktleQkAzAgCCQELRGVsZXRlRW50cnkBCQEOdG9Db21wb3NpdGVLZXkCBRBrX3Bvc2l0aW9uTWFyZ2luBQtwb3NpdGlvbktleQkAzAgCCQELRGVsZXRlRW50cnkBCQEOdG9Db21wb3NpdGVLZXkCBRZrX3Bvc2l0aW9uT3Blbk5vdGlvbmFsBQtwb3NpdGlvbktleQkAzAgCCQELRGVsZXRlRW50cnkBCQEOdG9Db21wb3NpdGVLZXkCBS5rX3Bvc2l0aW9uTGFzdFVwZGF0ZWRDdW11bGF0aXZlUHJlbWl1bUZyYWN0aW9uBQtwb3NpdGlvbktleQkAzAgCCQELRGVsZXRlRW50cnkBCQEOdG9Db21wb3NpdGVLZXkCBQ1rX3Bvc2l0aW9uRmVlBQtwb3NpdGlvbktleQkAzAgCCQELRGVsZXRlRW50cnkBCQEOdG9Db21wb3NpdGVLZXkCBR5rX3Bvc2l0aW9uTGFzdFVwZGF0ZWRUaW1lc3RhbXAFC3Bvc2l0aW9uS2V5BQNuaWwBCHdpdGhkcmF3AghfYWRkcmVzcwdfYW1vdW50BAdiYWxhbmNlCQDwBwIFBHRoaXMJAQpxdW90ZUFzc2V0AAMJAGYCBQdfYW1vdW50BQdiYWxhbmNlCQACAQkArAICCQCsAgIJAKwCAgITVW5hYmxlIHRvIHdpdGhkcmF3IAkApAMBBQdfYW1vdW50AhcgZnJvbSBjb250cmFjdCBiYWxhbmNlIAkApAMBBQdiYWxhbmNlCQDMCAIJAQ5TY3JpcHRUcmFuc2ZlcgMFCF9hZGRyZXNzBQdfYW1vdW50CQEKcXVvdGVBc3NldAAFA25pbAENdXBkYXRlQmFsYW5jZQEIX2JhbGFuY2UDCQBmAgAABQhfYmFsYW5jZQkAAgECB0JhbGFuY2UDAwkAAAIJAQljYmFsYW5jZTAAAAAGCQECIT0CCQEJY2JhbGFuY2UwAAUIX2JhbGFuY2UJAMwIAgkBDEludGVnZXJFbnRyeQIFCWtfYmFsYW5jZQUIX2JhbGFuY2UFA25pbAUDbmlsAQt0cmFuc2ZlckZlZQEBaQkAzAgCCQEOU2NyaXB0VHJhbnNmZXIDCQEOc3Rha2luZ0FkZHJlc3MABQFpCQEKcXVvdGVBc3NldAAFA25pbAEOZG9CdXJuQXJ0aWZhY3QCDV9idXJuQXJ0aWZhY3QBaQMFDV9idXJuQXJ0aWZhY3QJAMwIAgkBBEJ1cm4CCQETdmFsdWVPckVycm9yTWVzc2FnZQIICQCRAwIIBQFpCHBheW1lbnRzAAEHYXNzZXRJZAIQSW52YWxpZCBhcnRpZmFjdAABBQNuaWwFA25pbBcBaQEFcGF1c2UAAwkBAiE9AggFAWkGY2FsbGVyCQEMYWRtaW5BZGRyZXNzAAkAAgECFEludmFsaWQgcGF1c2UgcGFyYW1zCQDMCAIJAQxCb29sZWFuRW50cnkCBQhrX3BhdXNlZAYFA25pbAFpAQd1bnBhdXNlAAMJAQIhPQIIBQFpBmNhbGxlcgkBDGFkbWluQWRkcmVzcwAJAAIBAhZJbnZhbGlkIHVucGF1c2UgcGFyYW1zCQDMCAIJAQxCb29sZWFuRW50cnkCBQhrX3BhdXNlZAcFA25pbAFpAQxzZXRDbG9zZU9ubHkAAwkBAiE9AggFAWkGY2FsbGVyCQEMYWRtaW5BZGRyZXNzAAkAAgECG0ludmFsaWQgc2V0Q2xvc2VPbmx5IHBhcmFtcwkAzAgCCQEMQm9vbGVhbkVudHJ5AgULa19jbG9zZU9ubHkGBQNuaWwBaQEOdW5zZXRDbG9zZU9ubHkAAwkBAiE9AggFAWkGY2FsbGVyCQEMYWRtaW5BZGRyZXNzAAkAAgECHUludmFsaWQgdW5zZXRDbG9zZU9ubHkgcGFyYW1zCQDMCAIJAQxCb29sZWFuRW50cnkCBQtrX2Nsb3NlT25seQcFA25pbAFpAQ9jaGFuZ2VMaXF1aWRpdHkBEV9xdW90ZUFzc2V0QW1vdW50AwMJAQIhPQIIBQFpBmNhbGxlcgkBDGFkbWluQWRkcmVzcwAGCQAAAgURX3F1b3RlQXNzZXRBbW91bnQAAAkAAgECHkludmFsaWQgY2hhbmdlTGlxdWlkaXR5IHBhcmFtcwQHX3F0QXN0UgkBBnF0QXN0UgAEB19ic0FzdFIJAQZic0FzdFIABAdfcXRBc3RXCQEGcXRBc3RXAAQHX2JzQXN0VwkBBmJzQXN0VwAEBXByaWNlCQEEZGl2ZAIJAQRtdWxkAgUHX3F0QXN0UgUHX3F0QXN0VwkBBG11bGQCBQdfYnNBc3RSBQdfYnNBc3RXBAtxdEFzdFJBZnRlcgkAZAIFB19xdEFzdFIFEV9xdW90ZUFzc2V0QW1vdW50BBRiYXNlQXNzZXRBbW91bnRUb0FkZAkAZQIJAQRkaXZkAgkBBG11bGQCBQtxdEFzdFJBZnRlcgUHX3F0QXN0VwUFcHJpY2UFB19ic0FzdFIEC2JzQXN0UkFmdGVyCQBkAgUHX2JzQXN0UgUUYmFzZUFzc2V0QW1vdW50VG9BZGQEDSR0MDUzMDQ5NTMyMDAJARRnZXRTeW5jVGVybWluYWxQcmljZQMJAQ5nZXRPcmFjbGVQcmljZQAFC3F0QXN0UkFmdGVyBQtic0FzdFJBZnRlcgQTbmV3UXVvdGVBc3NldFdlaWdodAgFDSR0MDUzMDQ5NTMyMDACXzEEEm5ld0Jhc2VBc3NldFdlaWdodAgFDSR0MDUzMDQ5NTMyMDACXzIEDW1hcmdpblRvVmF1bHQIBQ0kdDA1MzA0OTUzMjAwAl8zBA1kb0V4Y2hhbmdlUG5MAwkBAiE9AgUNbWFyZ2luVG9WYXVsdAAABA1kb0V4Y2hhbmdlUG5MCQD8BwQJAQx2YXVsdEFkZHJlc3MAAhVleGNoYW5nZUZyZWVBbmRMb2NrZWQJAMwIAgUNbWFyZ2luVG9WYXVsdAUDbmlsBQNuaWwDCQAAAgUNZG9FeGNoYW5nZVBuTAUNZG9FeGNoYW5nZVBuTAUDbmlsCQACAQIkU3RyaWN0IHZhbHVlIGlzIG5vdCBlcXVhbCB0byBpdHNlbGYuBQNuaWwDCQAAAgUNZG9FeGNoYW5nZVBuTAUNZG9FeGNoYW5nZVBuTAkAzggCCQERdXBkYXRlQW1tUmVzZXJ2ZXMCBQtxdEFzdFJBZnRlcgULYnNBc3RSQWZ0ZXIJARB1cGRhdGVBbW1XZWlnaHRzAgUTbmV3UXVvdGVBc3NldFdlaWdodAUSbmV3QmFzZUFzc2V0V2VpZ2h0CQACAQIkU3RyaWN0IHZhbHVlIGlzIG5vdCBlcXVhbCB0byBpdHNlbGYuAWkBDmNoYW5nZVNldHRpbmdzExBfaW5pdE1hcmdpblJhdGlvBF9tbXIUX2xpcXVpZGF0aW9uRmVlUmF0aW8OX2Z1bmRpbmdQZXJpb2QEX2ZlZQxfc3ByZWFkTGltaXQPX21heFByaWNlSW1wYWN0GF9wYXJ0aWFsTGlxdWlkYXRpb25SYXRpbw9fbWF4UHJpY2VTcHJlYWQQX21heE9wZW5Ob3Rpb25hbBRfZmVlVG9TdGFrZXJzUGVyY2VudA9fbWF4T3JhY2xlRGVsYXkMX3JvbGxvdmVyRmVlDF9mdW5kaW5nTW9kZQtfb3JhY2xlTW9kZQ9fYmFzZU9yYWNsZURhdGEQX3F1b3RlT3JhY2xlRGF0YRNfbWluSW5pdE1hcmdpblJhdGlvDV9wb3NpdGlvbk1vZGUDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwkAZwIAAAUOX2Z1bmRpbmdQZXJpb2QGCQBnAgAABRBfaW5pdE1hcmdpblJhdGlvBgkAZgIFEF9pbml0TWFyZ2luUmF0aW8FDERFQ0lNQUxfVU5JVAYJAGcCAAAFE19taW5Jbml0TWFyZ2luUmF0aW8GCQBmAgUTX21pbkluaXRNYXJnaW5SYXRpbwUMREVDSU1BTF9VTklUBgkAZgIFEF9pbml0TWFyZ2luUmF0aW8FE19taW5Jbml0TWFyZ2luUmF0aW8GCQBnAgAABQRfbW1yBgkAZwIAAAUUX2xpcXVpZGF0aW9uRmVlUmF0aW8GCQBnAgAABQRfZmVlBgkAZwIAAAUMX3NwcmVhZExpbWl0BgkAZwIAAAUPX21heFByaWNlSW1wYWN0BgkAZwIAAAUYX3BhcnRpYWxMaXF1aWRhdGlvblJhdGlvBgkAZwIAAAUPX21heFByaWNlU3ByZWFkBgkAZwIAAAUQX21heE9wZW5Ob3Rpb25hbAYJAGcCAAAFFF9mZWVUb1N0YWtlcnNQZXJjZW50BgkAZgIFFF9mZWVUb1N0YWtlcnNQZXJjZW50BQxERUNJTUFMX1VOSVQGCQBmAgAABQ9fbWF4T3JhY2xlRGVsYXkGCQBnAgAABQxfcm9sbG92ZXJGZWUGAwkBAiE9AgUMX2Z1bmRpbmdNb2RlBRFGVU5ESU5HX1NZTU1FVFJJQwkBAiE9AgUMX2Z1bmRpbmdNb2RlBRJGVU5ESU5HX0FTWU1NRVRSSUMHBgMJAQIhPQIFC19vcmFjbGVNb2RlBQxPUkFDTEVfUExBSU4JAQIhPQIFC19vcmFjbGVNb2RlBQpPUkFDTEVfSklUBwYDCQECIT0CBQ1fcG9zaXRpb25Nb2RlBQ9QT1NJVElPTl9ESVJFQ1QJAQIhPQIFDV9wb3NpdGlvbk1vZGUFDlBPU0lUSU9OX09SREVSBwYJAQEhAQkBC2luaXRpYWxpemVkAAYJAQIhPQIIBQFpBmNhbGxlcgkBDGFkbWluQWRkcmVzcwAJAAIBAh1JbnZhbGlkIGNoYW5nZVNldHRpbmdzIHBhcmFtcwkAzggCCQEOdXBkYXRlU2V0dGluZ3MRBRBfaW5pdE1hcmdpblJhdGlvBQRfbW1yBRRfbGlxdWlkYXRpb25GZWVSYXRpbwUOX2Z1bmRpbmdQZXJpb2QFBF9mZWUFDF9zcHJlYWRMaW1pdAUPX21heFByaWNlSW1wYWN0BRhfcGFydGlhbExpcXVpZGF0aW9uUmF0aW8FD19tYXhQcmljZVNwcmVhZAUQX21heE9wZW5Ob3Rpb25hbAUUX2ZlZVRvU3Rha2Vyc1BlcmNlbnQFD19tYXhPcmFjbGVEZWxheQUMX3JvbGxvdmVyRmVlBQxfZnVuZGluZ01vZGUFC19vcmFjbGVNb2RlBRNfbWluSW5pdE1hcmdpblJhdGlvBQ1fcG9zaXRpb25Nb2RlCQDMCAIJAQtTdHJpbmdFbnRyeQIFDGtfYmFzZU9yYWNsZQUPX2Jhc2VPcmFjbGVEYXRhCQDMCAIJAQtTdHJpbmdFbnRyeQIFDWtfcXVvdGVPcmFjbGUFEF9xdW90ZU9yYWNsZURhdGEFA25pbAFpAQppbml0aWFsaXplFgdfcXRBc3RSB19ic0FzdFIOX2Z1bmRpbmdQZXJpb2QQX2luaXRNYXJnaW5SYXRpbwRfbW1yFF9saXF1aWRhdGlvbkZlZVJhdGlvBF9mZWUPX2Jhc2VPcmFjbGVEYXRhEF9xdW90ZU9yYWNsZURhdGEMX2Nvb3JkaW5hdG9yDF9zcHJlYWRMaW1pdA9fbWF4UHJpY2VJbXBhY3QYX3BhcnRpYWxMaXF1aWRhdGlvblJhdGlvD19tYXhQcmljZVNwcmVhZBBfbWF4T3Blbk5vdGlvbmFsFF9mZWVUb1N0YWtlcnNQZXJjZW50D19tYXhPcmFjbGVEZWxheQxfcm9sbG92ZXJGZWUMX2Z1bmRpbmdNb2RlC19vcmFjbGVNb2RlE19taW5Jbml0TWFyZ2luUmF0aW8NX3Bvc2l0aW9uTW9kZQMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMJAGcCAAAFB19xdEFzdFIGCQBnAgAABQdfYnNBc3RSBgkAZwIAAAUOX2Z1bmRpbmdQZXJpb2QGCQBnAgAABRBfaW5pdE1hcmdpblJhdGlvBgkAZgIFEF9pbml0TWFyZ2luUmF0aW8FDERFQ0lNQUxfVU5JVAYJAGcCAAAFE19taW5Jbml0TWFyZ2luUmF0aW8GCQBmAgUTX21pbkluaXRNYXJnaW5SYXRpbwUMREVDSU1BTF9VTklUBgkAZgIFEF9pbml0TWFyZ2luUmF0aW8FE19taW5Jbml0TWFyZ2luUmF0aW8GCQBnAgAABQRfbW1yBgkAZwIAAAUUX2xpcXVpZGF0aW9uRmVlUmF0aW8GCQBnAgAABQRfZmVlBgkAZwIAAAUMX3NwcmVhZExpbWl0BgkAZwIAAAUPX21heFByaWNlSW1wYWN0BgkAZwIAAAUYX3BhcnRpYWxMaXF1aWRhdGlvblJhdGlvBgkAZwIAAAUPX21heFByaWNlU3ByZWFkBgkAZwIAAAUQX21heE9wZW5Ob3Rpb25hbAYJAGcCAAAFFF9mZWVUb1N0YWtlcnNQZXJjZW50BgkAZgIFFF9mZWVUb1N0YWtlcnNQZXJjZW50BQxERUNJTUFMX1VOSVQGCQBmAgAABQ9fbWF4T3JhY2xlRGVsYXkGCQBnAgAABQxfcm9sbG92ZXJGZWUGAwkBAiE9AgUMX2Z1bmRpbmdNb2RlBRFGVU5ESU5HX1NZTU1FVFJJQwkBAiE9AgUMX2Z1bmRpbmdNb2RlBRJGVU5ESU5HX0FTWU1NRVRSSUMHBgMJAQIhPQIFC19vcmFjbGVNb2RlBQxPUkFDTEVfUExBSU4JAQIhPQIFC19vcmFjbGVNb2RlBQpPUkFDTEVfSklUBwYDCQECIT0CBQ1fcG9zaXRpb25Nb2RlBQ9QT1NJVElPTl9ESVJFQ1QJAQIhPQIFDV9wb3NpdGlvbk1vZGUFDlBPU0lUSU9OX09SREVSBwYJAQtpbml0aWFsaXplZAAGCQECIT0CCAUBaQZjYWxsZXIFBHRoaXMJAAIBAh1JbnZhbGlkIGluaXRpYWxpemUgcGFyYW1ldGVycwkAzggCCQDOCAIJAM4IAgkAzggCCQEJdXBkYXRlQW1tCAUHX3F0QXN0UgUHX2JzQXN0UgAAAAAAAAAAAAAAAAkBDnVwZGF0ZVNldHRpbmdzEQUQX2luaXRNYXJnaW5SYXRpbwUEX21tcgUUX2xpcXVpZGF0aW9uRmVlUmF0aW8FDl9mdW5kaW5nUGVyaW9kBQRfZmVlBQxfc3ByZWFkTGltaXQFD19tYXhQcmljZUltcGFjdAUYX3BhcnRpYWxMaXF1aWRhdGlvblJhdGlvBQ9fbWF4UHJpY2VTcHJlYWQFEF9tYXhPcGVuTm90aW9uYWwFFF9mZWVUb1N0YWtlcnNQZXJjZW50BQ9fbWF4T3JhY2xlRGVsYXkFDF9yb2xsb3ZlckZlZQUMX2Z1bmRpbmdNb2RlBQtfb3JhY2xlTW9kZQUTX21pbkluaXRNYXJnaW5SYXRpbwUNX3Bvc2l0aW9uTW9kZQkBDXVwZGF0ZUZ1bmRpbmcFCQBkAgkBDWxhc3RUaW1lc3RhbXAABQ5fZnVuZGluZ1BlcmlvZAAAAAAAAAAACQENdXBkYXRlQmFsYW5jZQEAAAkAzAgCCQEMQm9vbGVhbkVudHJ5AgUNa19pbml0aWFsaXplZAYJAMwIAgkBC1N0cmluZ0VudHJ5AgUMa19iYXNlT3JhY2xlBQ9fYmFzZU9yYWNsZURhdGEJAMwIAgkBC1N0cmluZ0VudHJ5AgUNa19xdW90ZU9yYWNsZQUQX3F1b3RlT3JhY2xlRGF0YQkAzAgCCQELU3RyaW5nRW50cnkCBRRrX2Nvb3JkaW5hdG9yQWRkcmVzcwkApQgBCQERQGV4dHJOYXRpdmUoMTA2MikBBQxfY29vcmRpbmF0b3IFA25pbAFpARBpbmNyZWFzZVBvc2l0aW9uBQpfZGlyZWN0aW9uCV9sZXZlcmFnZRNfbWluQmFzZUFzc2V0QW1vdW50CF9yZWZMaW5rDF9wcmljZVVwZGF0ZQQMdXBkYXRlT3JhY2xlCQD8BwQFBHRoaXMCDHVwZGF0ZU9yYWNsZQkAzAgCBQxfcHJpY2VVcGRhdGUFA25pbAUDbmlsAwkAAAIFDHVwZGF0ZU9yYWNsZQUMdXBkYXRlT3JhY2xlBARzeW5jCQD8BwQFBHRoaXMCGXN5bmNUZXJtaW5hbFByaWNlVG9PcmFjbGUFA25pbAUDbmlsAwkAAAIFBHN5bmMFBHN5bmMEEGVuc3VyZUNhbGxlZE9uY2UJAPwHBAUEdGhpcwIQZW5zdXJlQ2FsbGVkT25jZQUDbmlsBQNuaWwDCQAAAgUQZW5zdXJlQ2FsbGVkT25jZQUQZW5zdXJlQ2FsbGVkT25jZQQHX3RyYWRlcgkBD2dldEFjdHVhbENhbGxlcgEFAWkECl9yYXdBbW91bnQICQCRAwIIBQFpCHBheW1lbnRzAAAGYW1vdW50BAhfYXNzZXRJZAgJAJEDAggFAWkIcGF5bWVudHMAAAdhc3NldElkBAtfYXNzZXRJZFN0cgkA2AQBCQEFdmFsdWUBBQhfYXNzZXRJZAQMaXNRdW90ZUFzc2V0CQAAAgUIX2Fzc2V0SWQJAQpxdW90ZUFzc2V0AAMDAwMDAwMDAwMDCQECIT0CBQpfZGlyZWN0aW9uBQhESVJfTE9ORwkBAiE9AgUKX2RpcmVjdGlvbgUJRElSX1NIT1JUBwYJAGcCAAAFCl9yYXdBbW91bnQGCQEBIQEJAQtpbml0aWFsaXplZAAGCQEBIQEFDGlzUXVvdGVBc3NldAYJAQEhAQkBFnJlcXVpcmVNb3JlTWFyZ2luUmF0aW8DCQEEZGl2ZAIFDERFQ0lNQUxfVU5JVAUJX2xldmVyYWdlCQEPaW5pdE1hcmdpblJhdGlvAAYGCQEBIQEJARZyZXF1aXJlTW9yZU1hcmdpblJhdGlvAwkBBGRpdmQCBQxERUNJTUFMX1VOSVQFCV9sZXZlcmFnZQkBEm1pbkluaXRNYXJnaW5SYXRpbwAHBgkBASEBCQEhcmVxdWlyZVNlbmRlckNhbldvcmtXaXRoUG9zaXRpb25zAQgFAWkGY2FsbGVyBgkBBnBhdXNlZAAGCQEJY2xvc2VPbmx5AAYJAQ5pc01hcmtldENsb3NlZAAJAAIBAiNJbnZhbGlkIGluY3JlYXNlUG9zaXRpb24gcGFyYW1ldGVycwQNJHQwNjA1Mzk2MDY4OAkBGGdldEZvclRyYWRlcldpdGhBcnRpZmFjdAIFB190cmFkZXIJAQ1nZXRBcnRpZmFjdElkAQUBaQQLYWRqdXN0ZWRGZWUIBQ0kdDA2MDUzOTYwNjg4Al8xBAxidXJuQXJ0aWZhY3QIBQ0kdDA2MDUzOTYwNjg4Al8yBAdfYW1vdW50CQEEZGl2ZAIFCl9yYXdBbW91bnQJAGQCCQEEbXVsZAIFC2FkanVzdGVkRmVlBQlfbGV2ZXJhZ2UFDERFQ0lNQUxfVU5JVAQTZGlzdHJpYnV0ZUZlZUFtb3VudAkAZQIFCl9yYXdBbW91bnQFB19hbW91bnQEDnJlZmVycmVyRmVlQW55CQD8BwQJAQ9yZWZlcnJhbEFkZHJlc3MAAhVhY2NlcHRQYXltZW50V2l0aExpbmsJAMwIAgUHX3RyYWRlcgkAzAgCBQhfcmVmTGluawUDbmlsCQDMCAIJAQ9BdHRhY2hlZFBheW1lbnQCCQEKcXVvdGVBc3NldAAFE2Rpc3RyaWJ1dGVGZWVBbW91bnQFA25pbAMJAAACBQ5yZWZlcnJlckZlZUFueQUOcmVmZXJyZXJGZWVBbnkEC3JlZmVycmVyRmVlBAckbWF0Y2gwBQ5yZWZlcnJlckZlZUFueQMJAAECBQckbWF0Y2gwAgNJbnQEAXgFByRtYXRjaDAFAXgJAAIBAhNJbnZhbGlkIHJlZmVycmVyRmVlBAlmZWVBbW91bnQJAGUCBRNkaXN0cmlidXRlRmVlQW1vdW50BQtyZWZlcnJlckZlZQQNJHQwNjExODQ2MTM2NAkBC2dldFBvc2l0aW9uAgUHX3RyYWRlcgUKX2RpcmVjdGlvbgQPb2xkUG9zaXRpb25TaXplCAUNJHQwNjExODQ2MTM2NAJfMQQRb2xkUG9zaXRpb25NYXJnaW4IBQ0kdDA2MTE4NDYxMzY0Al8yBBdvbGRQb3NpdGlvbk9wZW5Ob3Rpb25hbAgFDSR0MDYxMTg0NjEzNjQCXzMEFG9sZFBvc2l0aW9uTHN0VXBkQ1BGCAUNJHQwNjExODQ2MTM2NAJfNAQUb2xkUG9zaXRpb25UaW1lc3RhbXAIBQ0kdDA2MTE4NDYxMzY0Al81BA1pc05ld1Bvc2l0aW9uCQAAAgUPb2xkUG9zaXRpb25TaXplAAAED2lzU2FtZURpcmVjdGlvbgMJAGYCBQ9vbGRQb3NpdGlvblNpemUAAAkAAAIFCl9kaXJlY3Rpb24FCERJUl9MT05HCQAAAgUKX2RpcmVjdGlvbgUJRElSX1NIT1JUBA5leHBhbmRFeGlzdGluZwMJAQEhAQUNaXNOZXdQb3NpdGlvbgUPaXNTYW1lRGlyZWN0aW9uBwQFaXNBZGQJAAACBQpfZGlyZWN0aW9uBQhESVJfTE9ORwQNJHQwNjE2NTM2NDc4NgMDBQ1pc05ld1Bvc2l0aW9uBgUOZXhwYW5kRXhpc3RpbmcEDG9wZW5Ob3Rpb25hbAkBBG11bGQCBQdfYW1vdW50BQlfbGV2ZXJhZ2UEDSR0MDYyMTYyNjIzMzUJAQlzd2FwSW5wdXQCBQVpc0FkZAUMb3Blbk5vdGlvbmFsBBVhbW91bnRCYXNlQXNzZXRCb3VnaHQIBQ0kdDA2MjE2MjYyMzM1Al8xBBZxdW90ZUFzc2V0UmVzZXJ2ZUFmdGVyCAUNJHQwNjIxNjI2MjMzNQJfMgQVYmFzZUFzc2V0UmVzZXJ2ZUFmdGVyCAUNJHQwNjIxNjI2MjMzNQJfMwQWdG90YWxQb3NpdGlvblNpemVBZnRlcggFDSR0MDYyMTYyNjIzMzUCXzQDAwkBAiE9AgUTX21pbkJhc2VBc3NldEFtb3VudAAACQBmAgUTX21pbkJhc2VBc3NldEFtb3VudAkBA2FicwEFFWFtb3VudEJhc2VBc3NldEJvdWdodAcJAAIBCQCsAgIJAKwCAgkArAICAg1MaW1pdCBlcnJvcjogCQCkAwEJAQNhYnMBBRVhbW91bnRCYXNlQXNzZXRCb3VnaHQCAyA8IAkApAMBBRNfbWluQmFzZUFzc2V0QW1vdW50BA9uZXdQb3NpdGlvblNpemUJAGQCBQ9vbGRQb3NpdGlvblNpemUFFWFtb3VudEJhc2VBc3NldEJvdWdodAQadG90YWxMb25nT3BlbkludGVyZXN0QWZ0ZXIJAGQCCQEQb3BlbkludGVyZXN0TG9uZwADCQBmAgUPbmV3UG9zaXRpb25TaXplAAAFDG9wZW5Ob3Rpb25hbAAABBt0b3RhbFNob3J0T3BlbkludGVyZXN0QWZ0ZXIJAGQCCQERb3BlbkludGVyZXN0U2hvcnQAAwkAZgIAAAUPbmV3UG9zaXRpb25TaXplBQxvcGVuTm90aW9uYWwAAAQNJHQwNjI4ODE2MzE1NgkBMGNhbGNSZW1haW5NYXJnaW5XaXRoRnVuZGluZ1BheW1lbnRBbmRSb2xsb3ZlckZlZQUFD29sZFBvc2l0aW9uU2l6ZQURb2xkUG9zaXRpb25NYXJnaW4FFG9sZFBvc2l0aW9uTHN0VXBkQ1BGBRRvbGRQb3NpdGlvblRpbWVzdGFtcAUHX2Ftb3VudAQMcmVtYWluTWFyZ2luCAUNJHQwNjI4ODE2MzE1NgJfMQQCeDEIBQ0kdDA2Mjg4MTYzMTU2Al8yBAJ4MggFDSR0MDYyODgxNjMxNTYCXzMEC3JvbGxvdmVyRmVlCAUNJHQwNjI4ODE2MzE1NgJfNAMJAQEhAQkBGXJlcXVpcmVOb3RPdmVyU3ByZWFkTGltaXQCBRZxdW90ZUFzc2V0UmVzZXJ2ZUFmdGVyBRViYXNlQXNzZXRSZXNlcnZlQWZ0ZXIJAAIBAhVPdmVyIG1heCBzcHJlYWQgbGltaXQDCQEBIQEJAR1yZXF1aXJlTm90T3Zlck1heE9wZW5Ob3Rpb25hbAIFGnRvdGFsTG9uZ09wZW5JbnRlcmVzdEFmdGVyBRt0b3RhbFNob3J0T3BlbkludGVyZXN0QWZ0ZXIJAAIBAhZPdmVyIG1heCBvcGVuIG5vdGlvbmFsCQCgCg4FD25ld1Bvc2l0aW9uU2l6ZQUMcmVtYWluTWFyZ2luCQBkAgUXb2xkUG9zaXRpb25PcGVuTm90aW9uYWwFDG9wZW5Ob3Rpb25hbAkBH2xhdGVzdEN1bXVsYXRpdmVQcmVtaXVtRnJhY3Rpb24BBQ9uZXdQb3NpdGlvblNpemUJAQ1sYXN0VGltZXN0YW1wAAUVYmFzZUFzc2V0UmVzZXJ2ZUFmdGVyBRZxdW90ZUFzc2V0UmVzZXJ2ZUFmdGVyBRZ0b3RhbFBvc2l0aW9uU2l6ZUFmdGVyCQBkAgkBFG9wZW5JbnRlcmVzdE5vdGlvbmFsAAUMb3Blbk5vdGlvbmFsCQBkAgkBFXRvdGFsTG9uZ1Bvc2l0aW9uU2l6ZQADCQBmAgUPbmV3UG9zaXRpb25TaXplAAAJAQNhYnMBBRVhbW91bnRCYXNlQXNzZXRCb3VnaHQAAAkAZAIJARZ0b3RhbFNob3J0UG9zaXRpb25TaXplAAMJAGYCAAAFD25ld1Bvc2l0aW9uU2l6ZQkBA2FicwEFFWFtb3VudEJhc2VBc3NldEJvdWdodAAABRp0b3RhbExvbmdPcGVuSW50ZXJlc3RBZnRlcgUbdG90YWxTaG9ydE9wZW5JbnRlcmVzdEFmdGVyBQtyb2xsb3ZlckZlZQQMb3Blbk5vdGlvbmFsCQEEbXVsZAIFB19hbW91bnQFCV9sZXZlcmFnZQQNJHQwNjQ0NzQ2NDYwMgkBI2dldFBvc2l0aW9uTm90aW9uYWxBbmRVbnJlYWxpemVkUG5sAwkApQgBCAUBaQZjYWxsZXIFCl9kaXJlY3Rpb24FD1BOTF9PUFRJT05fU1BPVAQTb2xkUG9zaXRpb25Ob3Rpb25hbAgFDSR0MDY0NDc0NjQ2MDICXzEEDXVucmVhbGl6ZWRQbmwIBQ0kdDA2NDQ3NDY0NjAyAl8yAwkAZgIFE29sZFBvc2l0aW9uTm90aW9uYWwFDG9wZW5Ob3Rpb25hbAkAAgECLlVzZSBkZWNyZWFzZVBvc2l0aW9uIHRvIGRlY3JlYXNlIHBvc2l0aW9uIHNpemUJAAIBAhRDbG9zZSBwb3NpdGlvbiBmaXJzdAQPbmV3UG9zaXRpb25TaXplCAUNJHQwNjE2NTM2NDc4NgJfMQQXbmV3UG9zaXRpb25SZW1haW5NYXJnaW4IBQ0kdDA2MTY1MzY0Nzg2Al8yBBduZXdQb3NpdGlvbk9wZW5Ob3Rpb25hbAgFDSR0MDYxNjUzNjQ3ODYCXzMEFG5ld1Bvc2l0aW9uTGF0ZXN0Q1BGCAUNJHQwNjE2NTM2NDc4NgJfNAQUbmV3UG9zaXRpb25UaW1lc3RhbXAIBQ0kdDA2MTY1MzY0Nzg2Al81BBViYXNlQXNzZXRSZXNlcnZlQWZ0ZXIIBQ0kdDA2MTY1MzY0Nzg2Al82BBZxdW90ZUFzc2V0UmVzZXJ2ZUFmdGVyCAUNJHQwNjE2NTM2NDc4NgJfNwQWdG90YWxQb3NpdGlvblNpemVBZnRlcggFDSR0MDYxNjUzNjQ3ODYCXzgEGW9wZW5JbnRlcmVzdE5vdGlvbmFsQWZ0ZXIIBQ0kdDA2MTY1MzY0Nzg2Al85BA50b3RhbExvbmdBZnRlcggFDSR0MDYxNjUzNjQ3ODYDXzEwBA90b3RhbFNob3J0QWZ0ZXIIBQ0kdDA2MTY1MzY0Nzg2A18xMQQadG90YWxMb25nT3BlbkludGVyZXN0QWZ0ZXIIBQ0kdDA2MTY1MzY0Nzg2A18xMgQbdG90YWxTaG9ydE9wZW5JbnRlcmVzdEFmdGVyCAUNJHQwNjE2NTM2NDc4NgNfMTMEC3JvbGxvdmVyRmVlCAUNJHQwNjE2NTM2NDc4NgNfMTQEDSR0MDY0NzkyNjQ4NjMJAQ1kaXN0cmlidXRlRmVlAQkAZAIFCWZlZUFtb3VudAULcm9sbG92ZXJGZWUEDGZlZVRvU3Rha2VycwgFDSR0MDY0NzkyNjQ4NjMCXzEECmZlZVRvVmF1bHQIBQ0kdDA2NDc5MjY0ODYzAl8yBAVzdGFrZQMJAGcCBQdfYW1vdW50BQtyb2xsb3ZlckZlZQkA/AcECQEMdmF1bHRBZGRyZXNzAAIJYWRkTG9ja2VkBQNuaWwJAMwIAgkBD0F0dGFjaGVkUGF5bWVudAIJAQpxdW90ZUFzc2V0AAkAZQIFB19hbW91bnQFC3JvbGxvdmVyRmVlBQNuaWwJAPwHBAkBDHZhdWx0QWRkcmVzcwACDndpdGhkcmF3TG9ja2VkCQDMCAIJAGUCBQtyb2xsb3ZlckZlZQUHX2Ftb3VudAUDbmlsBQNuaWwDCQAAAgUFc3Rha2UFBXN0YWtlBAxkZXBvc2l0VmF1bHQJAPwHBAkBDHZhdWx0QWRkcmVzcwACB2FkZEZyZWUFA25pbAkAzAgCCQEPQXR0YWNoZWRQYXltZW50AgkBCnF1b3RlQXNzZXQABQpmZWVUb1ZhdWx0BQNuaWwDCQAAAgUMZGVwb3NpdFZhdWx0BQxkZXBvc2l0VmF1bHQECW5vdGlmeUZlZQkA/AcECQEMbWluZXJBZGRyZXNzAAIKbm90aWZ5RmVlcwkAzAgCBQdfdHJhZGVyCQDMCAIFCWZlZUFtb3VudAUDbmlsBQNuaWwDCQAAAgUJbm90aWZ5RmVlBQlub3RpZnlGZWUEDm5vdGlmeU5vdGlvbmFsCQD8BwQJAQxtaW5lckFkZHJlc3MAAg5ub3RpZnlOb3Rpb25hbAkAzAgCBQdfdHJhZGVyCQDMCAIFF25ld1Bvc2l0aW9uT3Blbk5vdGlvbmFsBQNuaWwFA25pbAMJAAACBQ5ub3RpZnlOb3Rpb25hbAUObm90aWZ5Tm90aW9uYWwJAM4IAgkAzggCCQDOCAIJAM4IAgkAzggCCQDOCAIJAQ51cGRhdGVQb3NpdGlvbgYFB190cmFkZXIFD25ld1Bvc2l0aW9uU2l6ZQUXbmV3UG9zaXRpb25SZW1haW5NYXJnaW4FF25ld1Bvc2l0aW9uT3Blbk5vdGlvbmFsBRRuZXdQb3NpdGlvbkxhdGVzdENQRgUUbmV3UG9zaXRpb25UaW1lc3RhbXAJAR9pbmNyZW1lbnRQb3NpdGlvblNlcXVlbmNlTnVtYmVyAwUNaXNOZXdQb3NpdGlvbgUHX3RyYWRlcgUKX2RpcmVjdGlvbgkBEXVwZGF0ZVBvc2l0aW9uRmVlBAUNaXNOZXdQb3NpdGlvbgUHX3RyYWRlcgUKX2RpcmVjdGlvbgULYWRqdXN0ZWRGZWUJAQl1cGRhdGVBbW0IBRZxdW90ZUFzc2V0UmVzZXJ2ZUFmdGVyBRViYXNlQXNzZXRSZXNlcnZlQWZ0ZXIFFnRvdGFsUG9zaXRpb25TaXplQWZ0ZXIFGW9wZW5JbnRlcmVzdE5vdGlvbmFsQWZ0ZXIFDnRvdGFsTG9uZ0FmdGVyBQ90b3RhbFNob3J0QWZ0ZXIFGnRvdGFsTG9uZ09wZW5JbnRlcmVzdEFmdGVyBRt0b3RhbFNob3J0T3BlbkludGVyZXN0QWZ0ZXIJAQt0cmFuc2ZlckZlZQEFDGZlZVRvU3Rha2VycwkBDXVwZGF0ZUJhbGFuY2UBCQBlAgkAZAIJAQhjYmFsYW5jZQAFB19hbW91bnQFC3JvbGxvdmVyRmVlCQEOZG9CdXJuQXJ0aWZhY3QCBQxidXJuQXJ0aWZhY3QFAWkJAAIBAiRTdHJpY3QgdmFsdWUgaXMgbm90IGVxdWFsIHRvIGl0c2VsZi4JAAIBAiRTdHJpY3QgdmFsdWUgaXMgbm90IGVxdWFsIHRvIGl0c2VsZi4JAAIBAiRTdHJpY3QgdmFsdWUgaXMgbm90IGVxdWFsIHRvIGl0c2VsZi4JAAIBAiRTdHJpY3QgdmFsdWUgaXMgbm90IGVxdWFsIHRvIGl0c2VsZi4JAAIBAiRTdHJpY3QgdmFsdWUgaXMgbm90IGVxdWFsIHRvIGl0c2VsZi4JAAIBAiRTdHJpY3QgdmFsdWUgaXMgbm90IGVxdWFsIHRvIGl0c2VsZi4JAAIBAiRTdHJpY3QgdmFsdWUgaXMgbm90IGVxdWFsIHRvIGl0c2VsZi4JAAIBAiRTdHJpY3QgdmFsdWUgaXMgbm90IGVxdWFsIHRvIGl0c2VsZi4BaQEJYWRkTWFyZ2luAgpfZGlyZWN0aW9uDF9wcmljZVVwZGF0ZQQMdXBkYXRlT3JhY2xlCQD8BwQFBHRoaXMCDHVwZGF0ZU9yYWNsZQkAzAgCBQxfcHJpY2VVcGRhdGUFA25pbAUDbmlsAwkAAAIFDHVwZGF0ZU9yYWNsZQUMdXBkYXRlT3JhY2xlBARzeW5jCQD8BwQFBHRoaXMCGXN5bmNUZXJtaW5hbFByaWNlVG9PcmFjbGUFA25pbAUDbmlsAwkAAAIFBHN5bmMFBHN5bmMEEGVuc3VyZUNhbGxlZE9uY2UJAPwHBAUEdGhpcwIQZW5zdXJlQ2FsbGVkT25jZQUDbmlsBQNuaWwDCQAAAgUQZW5zdXJlQ2FsbGVkT25jZQUQZW5zdXJlQ2FsbGVkT25jZQQHX3RyYWRlcgkApQgBCAUBaQZjYWxsZXIEB19hbW91bnQICQCRAwIIBQFpCHBheW1lbnRzAAAGYW1vdW50BAhfYXNzZXRJZAgJAJEDAggFAWkIcGF5bWVudHMAAAdhc3NldElkBAtfYXNzZXRJZFN0cgkA2AQBCQEFdmFsdWUBBQhfYXNzZXRJZAQMaXNRdW90ZUFzc2V0CQAAAgUIX2Fzc2V0SWQJAQpxdW90ZUFzc2V0AAMDAwMDCQEBIQEFDGlzUXVvdGVBc3NldAYJAQEhAQkBE3JlcXVpcmVPcGVuUG9zaXRpb24CCQClCAEIBQFpBmNhbGxlcgUKX2RpcmVjdGlvbgYJAQEhAQkBC2luaXRpYWxpemVkAAYJAQZwYXVzZWQABgkBDmlzTWFya2V0Q2xvc2VkAAkAAgECHEludmFsaWQgYWRkTWFyZ2luIHBhcmFtZXRlcnMEDSR0MDY3MjA1NjczODUJAQtnZXRQb3NpdGlvbgIFB190cmFkZXIFCl9kaXJlY3Rpb24ED29sZFBvc2l0aW9uU2l6ZQgFDSR0MDY3MjA1NjczODUCXzEEEW9sZFBvc2l0aW9uTWFyZ2luCAUNJHQwNjcyMDU2NzM4NQJfMgQXb2xkUG9zaXRpb25PcGVuTm90aW9uYWwIBQ0kdDA2NzIwNTY3Mzg1Al8zBBRvbGRQb3NpdGlvbkxzdFVwZENQRggFDSR0MDY3MjA1NjczODUCXzQEFG9sZFBvc2l0aW9uVGltZXN0YW1wCAUNJHQwNjcyMDU2NzM4NQJfNQQFc3Rha2UJAPwHBAkBDHZhdWx0QWRkcmVzcwACCWFkZExvY2tlZAUDbmlsCQDMCAIJAQ9BdHRhY2hlZFBheW1lbnQCCQEKcXVvdGVBc3NldAAFB19hbW91bnQFA25pbAMJAAACBQVzdGFrZQUFc3Rha2UEDSR0MDY3NTI1Njc3NTEJATBjYWxjUmVtYWluTWFyZ2luV2l0aEZ1bmRpbmdQYXltZW50QW5kUm9sbG92ZXJGZWUFBQ9vbGRQb3NpdGlvblNpemUFEW9sZFBvc2l0aW9uTWFyZ2luBRRvbGRQb3NpdGlvbkxzdFVwZENQRgUUb2xkUG9zaXRpb25UaW1lc3RhbXAFB19hbW91bnQEDHJlbWFpbk1hcmdpbggFDSR0MDY3NTI1Njc3NTECXzEEB2JhZERlYnQIBQ0kdDA2NzUyNTY3NzUxAl8yBAtyb2xsb3ZlckZlZQgFDSR0MDY3NTI1Njc3NTECXzMEC21hcmdpblJhdGlvCQEPY2FsY01hcmdpblJhdGlvAwUMcmVtYWluTWFyZ2luBQdiYWREZWJ0BRdvbGRQb3NpdGlvbk9wZW5Ob3Rpb25hbAQOY2hlY2tNaW5NYXJnaW4JARZyZXF1aXJlTW9yZU1hcmdpblJhdGlvAwULbWFyZ2luUmF0aW8JARJtaW5Jbml0TWFyZ2luUmF0aW8ABwMJAAACBQ5jaGVja01pbk1hcmdpbgUOY2hlY2tNaW5NYXJnaW4EFmRvVHJhbnNmZXJGZWVUb1N0YWtlcnMDCQBmAgULcm9sbG92ZXJGZWUAAAQNJHQwNjgwMDc2ODA2NgkBDWRpc3RyaWJ1dGVGZWUBBQtyb2xsb3ZlckZlZQQMZmVlVG9TdGFrZXJzCAUNJHQwNjgwMDc2ODA2NgJfMQQKZmVlVG9WYXVsdAgFDSR0MDY4MDA3NjgwNjYCXzIEB3Vuc3Rha2UJAPwHBAkBDHZhdWx0QWRkcmVzcwACDndpdGhkcmF3TG9ja2VkCQDMCAIFDGZlZVRvU3Rha2VycwUDbmlsBQNuaWwDCQAAAgUHdW5zdGFrZQUHdW5zdGFrZQQLbG9ja0JhZERlYnQJAPwHBAkBDHZhdWx0QWRkcmVzcwACFWV4Y2hhbmdlRnJlZUFuZExvY2tlZAkAzAgCCQEBLQEFCmZlZVRvVmF1bHQFA25pbAUDbmlsAwkAAAIFC2xvY2tCYWREZWJ0BQtsb2NrQmFkRGVidAkBC3RyYW5zZmVyRmVlAQUMZmVlVG9TdGFrZXJzCQACAQIkU3RyaWN0IHZhbHVlIGlzIG5vdCBlcXVhbCB0byBpdHNlbGYuCQACAQIkU3RyaWN0IHZhbHVlIGlzIG5vdCBlcXVhbCB0byBpdHNlbGYuBQNuaWwDCQAAAgUWZG9UcmFuc2ZlckZlZVRvU3Rha2VycwUWZG9UcmFuc2ZlckZlZVRvU3Rha2VycwkAzggCCQDOCAIJAQ51cGRhdGVQb3NpdGlvbgYFB190cmFkZXIFD29sZFBvc2l0aW9uU2l6ZQkAZAIJAGUCBRFvbGRQb3NpdGlvbk1hcmdpbgULcm9sbG92ZXJGZWUFB19hbW91bnQFF29sZFBvc2l0aW9uT3Blbk5vdGlvbmFsBRRvbGRQb3NpdGlvbkxzdFVwZENQRgkBDWxhc3RUaW1lc3RhbXAACQENdXBkYXRlQmFsYW5jZQEJAGUCCQBkAgkBCGNiYWxhbmNlAAUHX2Ftb3VudAULcm9sbG92ZXJGZWUFFmRvVHJhbnNmZXJGZWVUb1N0YWtlcnMJAAIBAiRTdHJpY3QgdmFsdWUgaXMgbm90IGVxdWFsIHRvIGl0c2VsZi4JAAIBAiRTdHJpY3QgdmFsdWUgaXMgbm90IGVxdWFsIHRvIGl0c2VsZi4JAAIBAiRTdHJpY3QgdmFsdWUgaXMgbm90IGVxdWFsIHRvIGl0c2VsZi4JAAIBAiRTdHJpY3QgdmFsdWUgaXMgbm90IGVxdWFsIHRvIGl0c2VsZi4JAAIBAiRTdHJpY3QgdmFsdWUgaXMgbm90IGVxdWFsIHRvIGl0c2VsZi4JAAIBAiRTdHJpY3QgdmFsdWUgaXMgbm90IGVxdWFsIHRvIGl0c2VsZi4BaQEMcmVtb3ZlTWFyZ2luAwdfYW1vdW50Cl9kaXJlY3Rpb24MX3ByaWNlVXBkYXRlBAx1cGRhdGVPcmFjbGUJAPwHBAUEdGhpcwIMdXBkYXRlT3JhY2xlCQDMCAIFDF9wcmljZVVwZGF0ZQUDbmlsBQNuaWwDCQAAAgUMdXBkYXRlT3JhY2xlBQx1cGRhdGVPcmFjbGUEBHN5bmMJAPwHBAUEdGhpcwIZc3luY1Rlcm1pbmFsUHJpY2VUb09yYWNsZQUDbmlsBQNuaWwDCQAAAgUEc3luYwUEc3luYwQQZW5zdXJlQ2FsbGVkT25jZQkA/AcEBQR0aGlzAhBlbnN1cmVDYWxsZWRPbmNlBQNuaWwFA25pbAMJAAACBRBlbnN1cmVDYWxsZWRPbmNlBRBlbnN1cmVDYWxsZWRPbmNlBAdfdHJhZGVyCQClCAEIBQFpBmNhbGxlcgMDAwMDCQBnAgAABQdfYW1vdW50BgkBASEBCQETcmVxdWlyZU9wZW5Qb3NpdGlvbgIFB190cmFkZXIFCl9kaXJlY3Rpb24GCQEBIQEJAQtpbml0aWFsaXplZAAGCQEGcGF1c2VkAAYJAQ5pc01hcmtldENsb3NlZAAJAAIBAh9JbnZhbGlkIHJlbW92ZU1hcmdpbiBwYXJhbWV0ZXJzBA0kdDA2OTU2NzY5NzQ3CQELZ2V0UG9zaXRpb24CBQdfdHJhZGVyBQpfZGlyZWN0aW9uBA9vbGRQb3NpdGlvblNpemUIBQ0kdDA2OTU2NzY5NzQ3Al8xBBFvbGRQb3NpdGlvbk1hcmdpbggFDSR0MDY5NTY3Njk3NDcCXzIEF29sZFBvc2l0aW9uT3Blbk5vdGlvbmFsCAUNJHQwNjk1Njc2OTc0NwJfMwQUb2xkUG9zaXRpb25Mc3RVcGRDUEYIBQ0kdDA2OTU2NzY5NzQ3Al80BBRvbGRQb3NpdGlvblRpbWVzdGFtcAgFDSR0MDY5NTY3Njk3NDcCXzUEDSR0MDY5NzUzNzAwMDIJATBjYWxjUmVtYWluTWFyZ2luV2l0aEZ1bmRpbmdQYXltZW50QW5kUm9sbG92ZXJGZWUFBQ9vbGRQb3NpdGlvblNpemUFEW9sZFBvc2l0aW9uTWFyZ2luBRRvbGRQb3NpdGlvbkxzdFVwZENQRgUUb2xkUG9zaXRpb25UaW1lc3RhbXAJAQEtAQUHX2Ftb3VudAQMcmVtYWluTWFyZ2luCAUNJHQwNjk3NTM3MDAwMgJfMQQHYmFkRGVidAgFDSR0MDY5NzUzNzAwMDICXzIEDmZ1bmRpbmdQYXltZW50CAUNJHQwNjk3NTM3MDAwMgJfMwQLcm9sbG92ZXJGZWUIBQ0kdDA2OTc1MzcwMDAyAl80AwkBAiE9AgUHYmFkRGVidAAACQACAQIdSW52YWxpZCByZW1vdmVkIG1hcmdpbiBhbW91bnQEC21hcmdpblJhdGlvCQEPY2FsY01hcmdpblJhdGlvAwUMcmVtYWluTWFyZ2luBQdiYWREZWJ0BRdvbGRQb3NpdGlvbk9wZW5Ob3Rpb25hbAMJAQEhAQkBFnJlcXVpcmVNb3JlTWFyZ2luUmF0aW8DBQttYXJnaW5SYXRpbwkBD2luaXRNYXJnaW5SYXRpbwAGCQACAQkArAICCQCsAgIJAKwCAgIZVG9vIG11Y2ggbWFyZ2luIHJlbW92ZWQ6IAkApAMBBQttYXJnaW5SYXRpbwIDIDwgCQCkAwEJAQ9pbml0TWFyZ2luUmF0aW8ABA0kdDA3MDM4ODcwNDQ3CQENZGlzdHJpYnV0ZUZlZQEFC3JvbGxvdmVyRmVlBAxmZWVUb1N0YWtlcnMIBQ0kdDA3MDM4ODcwNDQ3Al8xBApmZWVUb1ZhdWx0CAUNJHQwNzAzODg3MDQ0NwJfMgQWZG9UcmFuc2ZlckZlZVRvU3Rha2VycwMJAGYCBQtyb2xsb3ZlckZlZQAABAtsb2NrQmFkRGVidAkA/AcECQEMdmF1bHRBZGRyZXNzAAIVZXhjaGFuZ2VGcmVlQW5kTG9ja2VkCQDMCAIJAQEtAQUKZmVlVG9WYXVsdAUDbmlsBQNuaWwDCQAAAgULbG9ja0JhZERlYnQFC2xvY2tCYWREZWJ0CQELdHJhbnNmZXJGZWUBBQxmZWVUb1N0YWtlcnMJAAIBAiRTdHJpY3QgdmFsdWUgaXMgbm90IGVxdWFsIHRvIGl0c2VsZi4FA25pbAMJAAACBRZkb1RyYW5zZmVyRmVlVG9TdGFrZXJzBRZkb1RyYW5zZmVyRmVlVG9TdGFrZXJzBAd1bnN0YWtlCQD8BwQJAQx2YXVsdEFkZHJlc3MAAg53aXRoZHJhd0xvY2tlZAkAzAgCCQBkAgUHX2Ftb3VudAUMZmVlVG9TdGFrZXJzBQNuaWwFA25pbAMJAAACBQd1bnN0YWtlBQd1bnN0YWtlCQDOCAIJAM4IAgkAzggCCQEOdXBkYXRlUG9zaXRpb24GBQdfdHJhZGVyBQ9vbGRQb3NpdGlvblNpemUFDHJlbWFpbk1hcmdpbgUXb2xkUG9zaXRpb25PcGVuTm90aW9uYWwJAR9sYXRlc3RDdW11bGF0aXZlUHJlbWl1bUZyYWN0aW9uAQUPb2xkUG9zaXRpb25TaXplCQENbGFzdFRpbWVzdGFtcAAJAQh3aXRoZHJhdwIIBQFpBmNhbGxlcgUHX2Ftb3VudAkBDXVwZGF0ZUJhbGFuY2UBCQBlAgkAZQIJAQhjYmFsYW5jZQAFB19hbW91bnQFC3JvbGxvdmVyRmVlBRZkb1RyYW5zZmVyRmVlVG9TdGFrZXJzCQACAQIkU3RyaWN0IHZhbHVlIGlzIG5vdCBlcXVhbCB0byBpdHNlbGYuCQACAQIkU3RyaWN0IHZhbHVlIGlzIG5vdCBlcXVhbCB0byBpdHNlbGYuCQACAQIkU3RyaWN0IHZhbHVlIGlzIG5vdCBlcXVhbCB0byBpdHNlbGYuCQACAQIkU3RyaWN0IHZhbHVlIGlzIG5vdCBlcXVhbCB0byBpdHNlbGYuCQACAQIkU3RyaWN0IHZhbHVlIGlzIG5vdCBlcXVhbCB0byBpdHNlbGYuAWkBDWNsb3NlUG9zaXRpb24FBV9zaXplCl9kaXJlY3Rpb24UX21pblF1b3RlQXNzZXRBbW91bnQMX2FkZFRvTWFyZ2luDF9wcmljZVVwZGF0ZQQMdXBkYXRlT3JhY2xlCQD8BwQFBHRoaXMCDHVwZGF0ZU9yYWNsZQkAzAgCBQxfcHJpY2VVcGRhdGUFA25pbAUDbmlsAwkAAAIFDHVwZGF0ZU9yYWNsZQUMdXBkYXRlT3JhY2xlBARzeW5jCQD8BwQFBHRoaXMCGXN5bmNUZXJtaW5hbFByaWNlVG9PcmFjbGUFA25pbAUDbmlsAwkAAAIFBHN5bmMFBHN5bmMEEGVuc3VyZUNhbGxlZE9uY2UJAPwHBAUEdGhpcwIQZW5zdXJlQ2FsbGVkT25jZQUDbmlsBQNuaWwDCQAAAgUQZW5zdXJlQ2FsbGVkT25jZQUQZW5zdXJlQ2FsbGVkT25jZQQHX3RyYWRlcgkBD2dldEFjdHVhbENhbGxlcgEFAWkEDl90cmFkZXJBZGRyZXNzCQETdmFsdWVPckVycm9yTWVzc2FnZQIJAKYIAQUHX3RyYWRlcgIOSW52YWxpZCBjYWxsZXIEC3Bvc2l0aW9uRmVlCQEOZ2V0UG9zaXRpb25GZWUCBQdfdHJhZGVyBQpfZGlyZWN0aW9uAwMDAwMDCQEBIQEJARNyZXF1aXJlT3BlblBvc2l0aW9uAgUHX3RyYWRlcgUKX2RpcmVjdGlvbgYJAQEhAQkBC2luaXRpYWxpemVkAAYJAQZwYXVzZWQABgkAZwIAAAUFX3NpemUGCQBmAgAABRRfbWluUXVvdGVBc3NldEFtb3VudAYJAQ5pc01hcmtldENsb3NlZAAJAAIBAiBJbnZhbGlkIGNsb3NlUG9zaXRpb24gcGFyYW1ldGVycwQUb2xkUG9zaXRpb25UaW1lc3RhbXAICQELZ2V0UG9zaXRpb24CBQdfdHJhZGVyBQpfZGlyZWN0aW9uAl81BA0kdDA3Mjc4MjczMzg1CQEVaW50ZXJuYWxDbG9zZVBvc2l0aW9uCAUHX3RyYWRlcgUKX2RpcmVjdGlvbgUFX3NpemUFC3Bvc2l0aW9uRmVlBRRfbWluUXVvdGVBc3NldEFtb3VudAUMX2FkZFRvTWFyZ2luBgYED25ld1Bvc2l0aW9uU2l6ZQgFDSR0MDcyNzgyNzMzODUCXzEEEW5ld1Bvc2l0aW9uTWFyZ2luCAUNJHQwNzI3ODI3MzM4NQJfMgQXbmV3UG9zaXRpb25PcGVuTm90aW9uYWwIBQ0kdDA3Mjc4MjczMzg1Al8zBBRuZXdQb3NpdGlvbkxzdFVwZENQRggFDSR0MDcyNzgyNzMzODUCXzQED3Bvc2l0aW9uQmFkRGVidAgFDSR0MDcyNzgyNzMzODUCXzUEC3JlYWxpemVkUG5sCAUNJHQwNzI3ODI3MzM4NQJfNgQObWFyZ2luVG9UcmFkZXIIBQ0kdDA3Mjc4MjczMzg1Al83BBZxdW90ZUFzc2V0UmVzZXJ2ZUFmdGVyCAUNJHQwNzI3ODI3MzM4NQJfOAQVYmFzZUFzc2V0UmVzZXJ2ZUFmdGVyCAUNJHQwNzI3ODI3MzM4NQJfOQQWdG90YWxQb3NpdGlvblNpemVBZnRlcggFDSR0MDcyNzgyNzMzODUDXzEwBBlvcGVuSW50ZXJlc3ROb3Rpb25hbEFmdGVyCAUNJHQwNzI3ODI3MzM4NQNfMTEEDnRvdGFsTG9uZ0FmdGVyCAUNJHQwNzI3ODI3MzM4NQNfMTIED3RvdGFsU2hvcnRBZnRlcggFDSR0MDcyNzgyNzMzODUDXzEzBBp0b3RhbExvbmdPcGVuSW50ZXJlc3RBZnRlcggFDSR0MDcyNzgyNzMzODUDXzE0BBt0b3RhbFNob3J0T3BlbkludGVyZXN0QWZ0ZXIIBQ0kdDA3Mjc4MjczMzg1A18xNQQLcmVhbGl6ZWRGZWUIBQ0kdDA3Mjc4MjczMzg1A18xNgMJAGYCBQ9wb3NpdGlvbkJhZERlYnQAAAkAAgECKkludmFsaWQgY2xvc2VQb3NpdGlvbiBwYXJhbWV0ZXJzOiBiYWQgZGVidAMJAGcCBRRvbGRQb3NpdGlvblRpbWVzdGFtcAkBDWxhc3RUaW1lc3RhbXAACQACAQJTSW52YWxpZCBjbG9zZVBvc2l0aW9uIHBhcmFtZXRlcnM6IHdhaXQgYXQgbGVhc3QgMSBibG9jayBiZWZvcmUgY2xvc2luZyB0aGUgcG9zaXRpb24EDmlzUGFydGlhbENsb3NlCQECIT0CBQ9uZXdQb3NpdGlvblNpemUAAAQOd2l0aGRyYXdBbW91bnQJAGQCBQ5tYXJnaW5Ub1RyYWRlcgULcmVhbGl6ZWRGZWUECmFtbUJhbGFuY2UJAGUCCQEIY2JhbGFuY2UABQ53aXRoZHJhd0Ftb3VudAQNYW1tTmV3QmFsYW5jZQMJAGYCAAAFCmFtbUJhbGFuY2UAAAUKYW1tQmFsYW5jZQQHdW5zdGFrZQkA/AcECQEMdmF1bHRBZGRyZXNzAAIOd2l0aGRyYXdMb2NrZWQJAMwIAgUOd2l0aGRyYXdBbW91bnQFA25pbAUDbmlsAwkAAAIFB3Vuc3Rha2UFB3Vuc3Rha2UEDnJlZmVycmVyRmVlQW55CQD8BwQJAQ9yZWZlcnJhbEFkZHJlc3MAAg1hY2NlcHRQYXltZW50CQDMCAIFB190cmFkZXIFA25pbAkAzAgCCQEPQXR0YWNoZWRQYXltZW50AgkBCnF1b3RlQXNzZXQABQtyZWFsaXplZEZlZQUDbmlsAwkAAAIFDnJlZmVycmVyRmVlQW55BQ5yZWZlcnJlckZlZUFueQQLcmVmZXJyZXJGZWUEByRtYXRjaDAFDnJlZmVycmVyRmVlQW55AwkAAQIFByRtYXRjaDACA0ludAQBeAUHJG1hdGNoMAUBeAkAAgECE0ludmFsaWQgcmVmZXJyZXJGZWUEDSR0MDc0MzU3NzQ0MzAJAQ1kaXN0cmlidXRlRmVlAQkAZQIFC3JlYWxpemVkRmVlBQtyZWZlcnJlckZlZQQMZmVlVG9TdGFrZXJzCAUNJHQwNzQzNTc3NDQzMAJfMQQKZmVlVG9WYXVsdAgFDSR0MDc0MzU3NzQ0MzACXzIEDGRlcG9zaXRWYXVsdAkA/AcECQEMdmF1bHRBZGRyZXNzAAIHYWRkRnJlZQUDbmlsCQDMCAIJAQ9BdHRhY2hlZFBheW1lbnQCCQEKcXVvdGVBc3NldAAFCmZlZVRvVmF1bHQFA25pbAMJAAACBQxkZXBvc2l0VmF1bHQFDGRlcG9zaXRWYXVsdAQJbm90aWZ5RmVlCQD8BwQJAQxtaW5lckFkZHJlc3MAAgpub3RpZnlGZWVzCQDMCAIFB190cmFkZXIJAMwIAgULcmVhbGl6ZWRGZWUFA25pbAUDbmlsAwkAAAIFCW5vdGlmeUZlZQUJbm90aWZ5RmVlBA5ub3RpZnlOb3Rpb25hbAkA/AcECQEMbWluZXJBZGRyZXNzAAIObm90aWZ5Tm90aW9uYWwJAMwIAgUHX3RyYWRlcgkAzAgCBRduZXdQb3NpdGlvbk9wZW5Ob3Rpb25hbAUDbmlsBQNuaWwDCQAAAgUObm90aWZ5Tm90aW9uYWwFDm5vdGlmeU5vdGlvbmFsCQDOCAIJAM4IAgkAzggCCQDOCAIDBQ5pc1BhcnRpYWxDbG9zZQkBDnVwZGF0ZVBvc2l0aW9uBgUHX3RyYWRlcgUPbmV3UG9zaXRpb25TaXplBRFuZXdQb3NpdGlvbk1hcmdpbgUXbmV3UG9zaXRpb25PcGVuTm90aW9uYWwFFG5ld1Bvc2l0aW9uTHN0VXBkQ1BGCQENbGFzdFRpbWVzdGFtcAAJAQ5kZWxldGVQb3NpdGlvbgIFB190cmFkZXIFCl9kaXJlY3Rpb24JAQl1cGRhdGVBbW0IBRZxdW90ZUFzc2V0UmVzZXJ2ZUFmdGVyBRViYXNlQXNzZXRSZXNlcnZlQWZ0ZXIFFnRvdGFsUG9zaXRpb25TaXplQWZ0ZXIFGW9wZW5JbnRlcmVzdE5vdGlvbmFsQWZ0ZXIFDnRvdGFsTG9uZ0FmdGVyBQ90b3RhbFNob3J0QWZ0ZXIFGnRvdGFsTG9uZ09wZW5JbnRlcmVzdEFmdGVyBRt0b3RhbFNob3J0T3BlbkludGVyZXN0QWZ0ZXIDCQBmAgUObWFyZ2luVG9UcmFkZXIAAAkBCHdpdGhkcmF3AgUOX3RyYWRlckFkZHJlc3MFDm1hcmdpblRvVHJhZGVyBQNuaWwJAQ11cGRhdGVCYWxhbmNlAQUNYW1tTmV3QmFsYW5jZQkBC3RyYW5zZmVyRmVlAQUMZmVlVG9TdGFrZXJzCQACAQIkU3RyaWN0IHZhbHVlIGlzIG5vdCBlcXVhbCB0byBpdHNlbGYuCQACAQIkU3RyaWN0IHZhbHVlIGlzIG5vdCBlcXVhbCB0byBpdHNlbGYuCQACAQIkU3RyaWN0IHZhbHVlIGlzIG5vdCBlcXVhbCB0byBpdHNlbGYuCQACAQIkU3RyaWN0IHZhbHVlIGlzIG5vdCBlcXVhbCB0byBpdHNlbGYuCQACAQIkU3RyaWN0IHZhbHVlIGlzIG5vdCBlcXVhbCB0byBpdHNlbGYuCQACAQIkU3RyaWN0IHZhbHVlIGlzIG5vdCBlcXVhbCB0byBpdHNlbGYuCQACAQIkU3RyaWN0IHZhbHVlIGlzIG5vdCBlcXVhbCB0byBpdHNlbGYuCQACAQIkU3RyaWN0IHZhbHVlIGlzIG5vdCBlcXVhbCB0byBpdHNlbGYuAWkBCWxpcXVpZGF0ZQMHX3RyYWRlcgpfZGlyZWN0aW9uDF9wcmljZVVwZGF0ZQQMdXBkYXRlT3JhY2xlCQD8BwQFBHRoaXMCDHVwZGF0ZU9yYWNsZQkAzAgCBQxfcHJpY2VVcGRhdGUFA25pbAUDbmlsAwkAAAIFDHVwZGF0ZU9yYWNsZQUMdXBkYXRlT3JhY2xlBARzeW5jCQD8BwQFBHRoaXMCGXN5bmNUZXJtaW5hbFByaWNlVG9PcmFjbGUFA25pbAUDbmlsAwkAAAIFBHN5bmMFBHN5bmMED3Nwb3RNYXJnaW5SYXRpbwkBFmdldE1hcmdpblJhdGlvQnlPcHRpb24DBQdfdHJhZGVyBQpfZGlyZWN0aW9uBQ9QTkxfT1BUSU9OX1NQT1QEFmxpcXVpZGF0aW9uTWFyZ2luUmF0aW8DCQEWaXNPdmVyRmx1Y3R1YXRpb25MaW1pdAAEEW9yYWNsZU1hcmdpblJhdGlvCQEWZ2V0TWFyZ2luUmF0aW9CeU9wdGlvbgMFB190cmFkZXIFCl9kaXJlY3Rpb24FEVBOTF9PUFRJT05fT1JBQ0xFCQEEdm1heAIFD3Nwb3RNYXJnaW5SYXRpbwURb3JhY2xlTWFyZ2luUmF0aW8FD3Nwb3RNYXJnaW5SYXRpbwMDAwMDCQEBIQEJARZyZXF1aXJlTW9yZU1hcmdpblJhdGlvAwUWbGlxdWlkYXRpb25NYXJnaW5SYXRpbwkBFm1haW50ZW5hbmNlTWFyZ2luUmF0aW8ABwYJAQEhAQkBE3JlcXVpcmVPcGVuUG9zaXRpb24CBQdfdHJhZGVyBQpfZGlyZWN0aW9uBgkBASEBCQELaW5pdGlhbGl6ZWQABgkBBnBhdXNlZAAGCQEOaXNNYXJrZXRDbG9zZWQACQACAQITVW5hYmxlIHRvIGxpcXVpZGF0ZQQPb2xkUG9zaXRpb25TaXplCAkBC2dldFBvc2l0aW9uAgUHX3RyYWRlcgUKX2RpcmVjdGlvbgJfMQQPcG9zaXRpb25TaXplQWJzCQEDYWJzAQUPb2xkUG9zaXRpb25TaXplBBRpc1BhcnRpYWxMaXF1aWRhdGlvbgMDAwkAZgIFD3Nwb3RNYXJnaW5SYXRpbwkBE2xpcXVpZGF0aW9uRmVlUmF0aW8ACQBmAgkBF3BhcnRpYWxMaXF1aWRhdGlvblJhdGlvAAAABwkAZgIFDERFQ0lNQUxfVU5JVAkBF3BhcnRpYWxMaXF1aWRhdGlvblJhdGlvAAcJAGYCCQEEbXVsZAIFD3Bvc2l0aW9uU2l6ZUFicwkBDGdldFNwb3RQcmljZQAJAR1taW5QYXJ0aWFsTGlxdWlkYXRpb25Ob3Rpb25hbAAHBA0kdDA3NzEwNDc3NDkxAwUUaXNQYXJ0aWFsTGlxdWlkYXRpb24ED2xpcXVpZGF0aW9uU2l6ZQkBA2FicwEJARtnZXRQYXJ0aWFsTGlxdWlkYXRpb25BbW91bnQCBQdfdHJhZGVyBQ9vbGRQb3NpdGlvblNpemUEEGxpcXVpZGF0aW9uUmF0aW8JAQRkaXZkAgUPbGlxdWlkYXRpb25TaXplBQ9wb3NpdGlvblNpemVBYnMEE2xpcXVpZGF0aW9uTm90aW9uYWwJAQRtdWxkAgUPbGlxdWlkYXRpb25TaXplCQEMZ2V0U3BvdFByaWNlAAkAlAoCBRBsaXF1aWRhdGlvblJhdGlvBQ9saXF1aWRhdGlvblNpemUJAJQKAgAABQ9wb3NpdGlvblNpemVBYnMEEGxpcXVpZGF0aW9uUmF0aW8IBQ0kdDA3NzEwNDc3NDkxAl8xBA9saXF1aWRhdGlvblNpemUIBQ0kdDA3NzEwNDc3NDkxAl8yBA0kdDA3NzQ5Nzc4MTUzCQEVaW50ZXJuYWxDbG9zZVBvc2l0aW9uCAUHX3RyYWRlcgUKX2RpcmVjdGlvbgMFFGlzUGFydGlhbExpcXVpZGF0aW9uBQ9saXF1aWRhdGlvblNpemUFD3Bvc2l0aW9uU2l6ZUFicwkBE2xpcXVpZGF0aW9uRmVlUmF0aW8AAAAGBwYED25ld1Bvc2l0aW9uU2l6ZQgFDSR0MDc3NDk3NzgxNTMCXzEEEW5ld1Bvc2l0aW9uTWFyZ2luCAUNJHQwNzc0OTc3ODE1MwJfMgQXbmV3UG9zaXRpb25PcGVuTm90aW9uYWwIBQ0kdDA3NzQ5Nzc4MTUzAl8zBBRuZXdQb3NpdGlvbkxzdFVwZENQRggFDSR0MDc3NDk3NzgxNTMCXzQED3Bvc2l0aW9uQmFkRGVidAgFDSR0MDc3NDk3NzgxNTMCXzUEC3JlYWxpemVkUG5sCAUNJHQwNzc0OTc3ODE1MwJfNgQObWFyZ2luVG9UcmFkZXIIBQ0kdDA3NzQ5Nzc4MTUzAl83BBZxdW90ZUFzc2V0UmVzZXJ2ZUFmdGVyCAUNJHQwNzc0OTc3ODE1MwJfOAQVYmFzZUFzc2V0UmVzZXJ2ZUFmdGVyCAUNJHQwNzc0OTc3ODE1MwJfOQQWdG90YWxQb3NpdGlvblNpemVBZnRlcggFDSR0MDc3NDk3NzgxNTMDXzEwBBlvcGVuSW50ZXJlc3ROb3Rpb25hbEFmdGVyCAUNJHQwNzc0OTc3ODE1MwNfMTEEDnRvdGFsTG9uZ0FmdGVyCAUNJHQwNzc0OTc3ODE1MwNfMTIED3RvdGFsU2hvcnRBZnRlcggFDSR0MDc3NDk3NzgxNTMDXzEzBBp0b3RhbExvbmdPcGVuSW50ZXJlc3RBZnRlcggFDSR0MDc3NDk3NzgxNTMDXzE0BBt0b3RhbFNob3J0T3BlbkludGVyZXN0QWZ0ZXIIBQ0kdDA3NzQ5Nzc4MTUzA18xNQQSbGlxdWlkYXRpb25QZW5hbHR5CAUNJHQwNzc0OTc3ODE1MwNfMTYED2ZlZVRvTGlxdWlkYXRvcgkAaQIFEmxpcXVpZGF0aW9uUGVuYWx0eQACBApmZWVUb1ZhdWx0CQBlAgUSbGlxdWlkYXRpb25QZW5hbHR5BQ9mZWVUb0xpcXVpZGF0b3IECmFtbUJhbGFuY2UJAGUCCQEIY2JhbGFuY2UABRJsaXF1aWRhdGlvblBlbmFsdHkEDW5ld0FtbUJhbGFuY2UDCQBmAgAABQphbW1CYWxhbmNlAAAFCmFtbUJhbGFuY2UEC2xvY2tCYWREZWJ0AwkAZgIFD3Bvc2l0aW9uQmFkRGVidAAABAtsb2NrQmFkRGVidAkA/AcECQEMdmF1bHRBZGRyZXNzAAIVZXhjaGFuZ2VGcmVlQW5kTG9ja2VkCQDMCAIJAGQCBQ9wb3NpdGlvbkJhZERlYnQFEmxpcXVpZGF0aW9uUGVuYWx0eQUDbmlsBQNuaWwDCQAAAgULbG9ja0JhZERlYnQFC2xvY2tCYWREZWJ0BQNuaWwJAAIBAiRTdHJpY3QgdmFsdWUgaXMgbm90IGVxdWFsIHRvIGl0c2VsZi4FA25pbAMJAAACBQtsb2NrQmFkRGVidAULbG9ja0JhZERlYnQEB3Vuc3Rha2UJAPwHBAkBDHZhdWx0QWRkcmVzcwACDndpdGhkcmF3TG9ja2VkCQDMCAIFEmxpcXVpZGF0aW9uUGVuYWx0eQUDbmlsBQNuaWwDCQAAAgUHdW5zdGFrZQUHdW5zdGFrZQQQZGVwb3NpdEluc3VyYW5jZQkA/AcECQEMdmF1bHRBZGRyZXNzAAIHYWRkRnJlZQUDbmlsCQDMCAIJAQ9BdHRhY2hlZFBheW1lbnQCCQEKcXVvdGVBc3NldAAFCmZlZVRvVmF1bHQFA25pbAMJAAACBRBkZXBvc2l0SW5zdXJhbmNlBRBkZXBvc2l0SW5zdXJhbmNlBA5ub3RpZnlOb3Rpb25hbAkA/AcECQEMbWluZXJBZGRyZXNzAAIObm90aWZ5Tm90aW9uYWwJAMwIAgUHX3RyYWRlcgkAzAgCBRduZXdQb3NpdGlvbk9wZW5Ob3Rpb25hbAUDbmlsBQNuaWwDCQAAAgUObm90aWZ5Tm90aW9uYWwFDm5vdGlmeU5vdGlvbmFsCQDOCAIJAM4IAgkAzggCAwUUaXNQYXJ0aWFsTGlxdWlkYXRpb24JAQ51cGRhdGVQb3NpdGlvbgYFB190cmFkZXIFD25ld1Bvc2l0aW9uU2l6ZQURbmV3UG9zaXRpb25NYXJnaW4FF25ld1Bvc2l0aW9uT3Blbk5vdGlvbmFsBRRuZXdQb3NpdGlvbkxzdFVwZENQRgkBDWxhc3RUaW1lc3RhbXAACQEOZGVsZXRlUG9zaXRpb24CBQdfdHJhZGVyBQpfZGlyZWN0aW9uCQEJdXBkYXRlQW1tCAUWcXVvdGVBc3NldFJlc2VydmVBZnRlcgUVYmFzZUFzc2V0UmVzZXJ2ZUFmdGVyBRZ0b3RhbFBvc2l0aW9uU2l6ZUFmdGVyBRlvcGVuSW50ZXJlc3ROb3Rpb25hbEFmdGVyBQ50b3RhbExvbmdBZnRlcgUPdG90YWxTaG9ydEFmdGVyBRp0b3RhbExvbmdPcGVuSW50ZXJlc3RBZnRlcgUbdG90YWxTaG9ydE9wZW5JbnRlcmVzdEFmdGVyCQEId2l0aGRyYXcCCAUBaQZjYWxsZXIFD2ZlZVRvTGlxdWlkYXRvcgkBDXVwZGF0ZUJhbGFuY2UBBQ1uZXdBbW1CYWxhbmNlCQACAQIkU3RyaWN0IHZhbHVlIGlzIG5vdCBlcXVhbCB0byBpdHNlbGYuCQACAQIkU3RyaWN0IHZhbHVlIGlzIG5vdCBlcXVhbCB0byBpdHNlbGYuCQACAQIkU3RyaWN0IHZhbHVlIGlzIG5vdCBlcXVhbCB0byBpdHNlbGYuCQACAQIkU3RyaWN0IHZhbHVlIGlzIG5vdCBlcXVhbCB0byBpdHNlbGYuCQACAQIkU3RyaWN0IHZhbHVlIGlzIG5vdCBlcXVhbCB0byBpdHNlbGYuCQACAQIkU3RyaWN0IHZhbHVlIGlzIG5vdCBlcXVhbCB0byBpdHNlbGYuAWkBCnBheUZ1bmRpbmcBDF9wcmljZVVwZGF0ZQQMdXBkYXRlT3JhY2xlCQD8BwQFBHRoaXMCDHVwZGF0ZU9yYWNsZQkAzAgCBQxfcHJpY2VVcGRhdGUFA25pbAUDbmlsAwkAAAIFDHVwZGF0ZU9yYWNsZQUMdXBkYXRlT3JhY2xlBARzeW5jCQD8BwQFBHRoaXMCGXN5bmNUZXJtaW5hbFByaWNlVG9PcmFjbGUFA25pbAUDbmlsAwkAAAIFBHN5bmMFBHN5bmMEFWZ1bmRpbmdCbG9ja1RpbWVzdGFtcAkBGW5leHRGdW5kaW5nQmxvY2tUaW1lc3RhbXAAAwMDCQBmAgUVZnVuZGluZ0Jsb2NrVGltZXN0YW1wCQENbGFzdFRpbWVzdGFtcAAGCQEBIQEJAQtpbml0aWFsaXplZAAGCQEGcGF1c2VkAAkAAgEJAKwCAgkArAICCQCsAgICIUludmFsaWQgZnVuZGluZyBibG9jayB0aW1lc3RhbXA6IAkApAMBCQENbGFzdFRpbWVzdGFtcAACAyA8IAkApAMBBRVmdW5kaW5nQmxvY2tUaW1lc3RhbXAED3VuZGVybHlpbmdQcmljZQkBDmdldE9yYWNsZVByaWNlAAQNJHQwODAzNzE4MDQ0OQkBCmdldEZ1bmRpbmcABBRzaG9ydFByZW1pdW1GcmFjdGlvbggFDSR0MDgwMzcxODA0NDkCXzEEE2xvbmdQcmVtaXVtRnJhY3Rpb24IBQ0kdDA4MDM3MTgwNDQ5Al8yBA5wcmVtaXVtVG9WYXVsdAgFDSR0MDgwMzcxODA0NDkCXzMEE2RvUGF5RnVuZGluZ1RvVmF1bHQDCQBmAgUOcHJlbWl1bVRvVmF1bHQAAAQTZG9QYXlGdW5kaW5nVG9WYXVsdAkA/AcECQEMdmF1bHRBZGRyZXNzAAIVZXhjaGFuZ2VGcmVlQW5kTG9ja2VkCQDMCAIJAQEtAQUOcHJlbWl1bVRvVmF1bHQFA25pbAUDbmlsAwkAAAIFE2RvUGF5RnVuZGluZ1RvVmF1bHQFE2RvUGF5RnVuZGluZ1RvVmF1bHQFA25pbAkAAgECJFN0cmljdCB2YWx1ZSBpcyBub3QgZXF1YWwgdG8gaXRzZWxmLgUDbmlsAwkAAAIFE2RvUGF5RnVuZGluZ1RvVmF1bHQFE2RvUGF5RnVuZGluZ1RvVmF1bHQJAQ11cGRhdGVGdW5kaW5nBQkAZAIFFWZ1bmRpbmdCbG9ja1RpbWVzdGFtcAkBFGZ1bmRpbmdQZXJpb2RTZWNvbmRzAAkAZAIJASNsYXRlc3RMb25nQ3VtdWxhdGl2ZVByZW1pdW1GcmFjdGlvbgAFE2xvbmdQcmVtaXVtRnJhY3Rpb24JAGQCCQEkbGF0ZXN0U2hvcnRDdW11bGF0aXZlUHJlbWl1bUZyYWN0aW9uAAUUc2hvcnRQcmVtaXVtRnJhY3Rpb24JAQRkaXZkAgUTbG9uZ1ByZW1pdW1GcmFjdGlvbgUPdW5kZXJseWluZ1ByaWNlCQEEZGl2ZAIFFHNob3J0UHJlbWl1bUZyYWN0aW9uBQ91bmRlcmx5aW5nUHJpY2UJAAIBAiRTdHJpY3QgdmFsdWUgaXMgbm90IGVxdWFsIHRvIGl0c2VsZi4JAAIBAiRTdHJpY3QgdmFsdWUgaXMgbm90IGVxdWFsIHRvIGl0c2VsZi4JAAIBAiRTdHJpY3QgdmFsdWUgaXMgbm90IGVxdWFsIHRvIGl0c2VsZi4BaQEMdXBkYXRlT3JhY2xlAQxfcHJpY2VVcGRhdGUDCQAAAgkBCm9yYWNsZU1vZGUABQxPUkFDTEVfUExBSU4FA25pbAQMcHJpY2VVcGRhdGVzCQC8CQIFDF9wcmljZVVwZGF0ZQICOjoECmJhc2VPcmFjbGUJARN2YWx1ZU9yRXJyb3JNZXNzYWdlAgkBDWdldE9yYWNsZURhdGEBBQxrX2Jhc2VPcmFjbGUCGU5vIGJhc2UgYXNzZXQgb3JhY2xlIGRhdGEEEWJhc2VPcmFjbGVBZGRyZXNzCAUKYmFzZU9yYWNsZQJfMQQSZG9VcGRhdGVCYXNlT3JhY2xlCQD8BwQFEWJhc2VPcmFjbGVBZGRyZXNzAgp1cGRhdGVEYXRhCQDMCAIJAJEDAgUMcHJpY2VVcGRhdGVzAAAFA25pbAUDbmlsAwkAAAIFEmRvVXBkYXRlQmFzZU9yYWNsZQUSZG9VcGRhdGVCYXNlT3JhY2xlBAtxdW90ZU9yYWNsZQkBDWdldE9yYWNsZURhdGEBBQ1rX3F1b3RlT3JhY2xlBBNkb1VwZGF0ZVF1b3RlT3JhY2xlAwkBCWlzRGVmaW5lZAEFC3F1b3RlT3JhY2xlBAxxdW90ZU9yYWNsZVYJAQV2YWx1ZQEFC3F1b3RlT3JhY2xlBBJxdW90ZU9yYWNsZUFkZHJlc3MIBQxxdW90ZU9yYWNsZVYCXzEEE2RvVXBkYXRlUXVvdGVPcmFjbGUJAPwHBAUScXVvdGVPcmFjbGVBZGRyZXNzAgp1cGRhdGVEYXRhCQDMCAIJAJEDAgUMcHJpY2VVcGRhdGVzAAEFA25pbAUDbmlsAwkAAAIFE2RvVXBkYXRlUXVvdGVPcmFjbGUFE2RvVXBkYXRlUXVvdGVPcmFjbGUFA25pbAkAAgECJFN0cmljdCB2YWx1ZSBpcyBub3QgZXF1YWwgdG8gaXRzZWxmLgUDbmlsAwkAAAIFE2RvVXBkYXRlUXVvdGVPcmFjbGUFE2RvVXBkYXRlUXVvdGVPcmFjbGUFA25pbAkAAgECJFN0cmljdCB2YWx1ZSBpcyBub3QgZXF1YWwgdG8gaXRzZWxmLgkAAgECJFN0cmljdCB2YWx1ZSBpcyBub3QgZXF1YWwgdG8gaXRzZWxmLgFpARlzeW5jVGVybWluYWxQcmljZVRvT3JhY2xlAAQHX3F0QXN0UgkBBnF0QXN0UgAEB19ic0FzdFIJAQZic0FzdFIABA0kdDA4MjI2NjgyNjMyCQEUZ2V0U3luY1Rlcm1pbmFsUHJpY2UDCQEOZ2V0T3JhY2xlUHJpY2UABQdfcXRBc3RSBQdfYnNBc3RSBBNuZXdRdW90ZUFzc2V0V2VpZ2h0CAUNJHQwODIyNjY4MjYzMgJfMQQSbmV3QmFzZUFzc2V0V2VpZ2h0CAUNJHQwODIyNjY4MjYzMgJfMgQNbWFyZ2luVG9WYXVsdAgFDSR0MDgyMjY2ODI2MzICXzMEEG1hcmdpblRvVmF1bHRBZGoDAwkAZgIAAAUNbWFyZ2luVG9WYXVsdAkAZgIJAQNhYnMBBQ1tYXJnaW5Ub1ZhdWx0CQEIY2JhbGFuY2UABwkBAS0BCQEIY2JhbGFuY2UABQ1tYXJnaW5Ub1ZhdWx0BA1kb0V4Y2hhbmdlUG5MAwkBAiE9AgUQbWFyZ2luVG9WYXVsdEFkagAABA1kb0V4Y2hhbmdlUG5MCQD8BwQJAQx2YXVsdEFkZHJlc3MAAhVleGNoYW5nZUZyZWVBbmRMb2NrZWQJAMwIAgUQbWFyZ2luVG9WYXVsdEFkagUDbmlsBQNuaWwDCQAAAgUNZG9FeGNoYW5nZVBuTAUNZG9FeGNoYW5nZVBuTAUDbmlsCQACAQIkU3RyaWN0IHZhbHVlIGlzIG5vdCBlcXVhbCB0byBpdHNlbGYuBQNuaWwDCQAAAgUNZG9FeGNoYW5nZVBuTAUNZG9FeGNoYW5nZVBuTAkAzggCCQENdXBkYXRlQmFsYW5jZQEJAGQCCQEIY2JhbGFuY2UABRBtYXJnaW5Ub1ZhdWx0QWRqCQEQdXBkYXRlQW1tV2VpZ2h0cwIFE25ld1F1b3RlQXNzZXRXZWlnaHQFEm5ld0Jhc2VBc3NldFdlaWdodAkAAgECJFN0cmljdCB2YWx1ZSBpcyBub3QgZXF1YWwgdG8gaXRzZWxmLgFpARBlbnN1cmVDYWxsZWRPbmNlAAMJAQIhPQIIBQFpBmNhbGxlcgUEdGhpcwkAAgECIkludmFsaWQgc2F2ZUN1cnJlbnRUeElkIHBhcmFtZXRlcnMEBHR4SWQJANgEAQgFAWkNdHJhbnNhY3Rpb25JZAQGbGFzdFR4CQELdmFsdWVPckVsc2UCCQCdCAIFBHRoaXMFCGtfbGFzdFR4AgADCQECIT0CBQZsYXN0VHgFBHR4SWQJAMwIAgkBC1N0cmluZ0VudHJ5AgUIa19sYXN0VHgFBHR4SWQFA25pbAkAAgECKUNhbiBub3QgY2FsbCB2QU1NIG1ldGhvZHMgdHdpY2UgaW4gb25lIHR4AWkBD21pZ3JhdGVQb3NpdGlvbgEHX3RyYWRlcgQPcG9zaXRpb25TaXplT3B0CQCaCAIFBHRoaXMJAQ50b0NvbXBvc2l0ZUtleQIFDmtfcG9zaXRpb25TaXplBQdfdHJhZGVyAwMJAQlpc0RlZmluZWQBBQ9wb3NpdGlvblNpemVPcHQJAQlpc0RlZmluZWQBCQCmCAEFB190cmFkZXIHBAVwU2l6ZQkBEUBleHRyTmF0aXZlKDEwNTApAgUEdGhpcwkBDnRvQ29tcG9zaXRlS2V5AgUOa19wb3NpdGlvblNpemUFB190cmFkZXIEB3BNYXJnaW4JARFAZXh0ck5hdGl2ZSgxMDUwKQIFBHRoaXMJAQ50b0NvbXBvc2l0ZUtleQIFEGtfcG9zaXRpb25NYXJnaW4FB190cmFkZXIECXBOb3Rpb25hbAkBEUBleHRyTmF0aXZlKDEwNTApAgUEdGhpcwkBDnRvQ29tcG9zaXRlS2V5AgUWa19wb3NpdGlvbk9wZW5Ob3Rpb25hbAUHX3RyYWRlcgQJcEZyYWN0aW9uCQERQGV4dHJOYXRpdmUoMTA1MCkCBQR0aGlzCQEOdG9Db21wb3NpdGVLZXkCBS5rX3Bvc2l0aW9uTGFzdFVwZGF0ZWRDdW11bGF0aXZlUHJlbWl1bUZyYWN0aW9uBQdfdHJhZGVyBApwVGltZXN0YW1wCQELdmFsdWVPckVsc2UCCQCaCAIFBHRoaXMJAQ50b0NvbXBvc2l0ZUtleQIFHmtfcG9zaXRpb25MYXN0VXBkYXRlZFRpbWVzdGFtcAUHX3RyYWRlcggFCWxhc3RCbG9jawl0aW1lc3RhbXAEBHBGZWUJAQt2YWx1ZU9yRWxzZQIJAJoIAgUEdGhpcwkBDnRvQ29tcG9zaXRlS2V5AgUNa19wb3NpdGlvbkZlZQUHX3RyYWRlcgkBA2ZlZQAECXBTZXF1ZW5jZQkBEUBleHRyTmF0aXZlKDEwNTApAgUEdGhpcwkBDnRvQ29tcG9zaXRlS2V5AgUSa19wb3NpdGlvblNlcXVlbmNlBQdfdHJhZGVyBApwRGlyZWN0aW9uCQEMZ2V0RGlyZWN0aW9uAQUFcFNpemUEC3Bvc2l0aW9uS2V5CQCsAgIJAKwCAgUHX3RyYWRlcgIBXwkApAMBBQpwRGlyZWN0aW9uCQDMCAIJAQtEZWxldGVFbnRyeQEJAQ50b0NvbXBvc2l0ZUtleQIFDmtfcG9zaXRpb25TaXplBQdfdHJhZGVyCQDMCAIJAQtEZWxldGVFbnRyeQEJAQ50b0NvbXBvc2l0ZUtleQIFEGtfcG9zaXRpb25NYXJnaW4FB190cmFkZXIJAMwIAgkBC0RlbGV0ZUVudHJ5AQkBDnRvQ29tcG9zaXRlS2V5AgUWa19wb3NpdGlvbk9wZW5Ob3Rpb25hbAUHX3RyYWRlcgkAzAgCCQELRGVsZXRlRW50cnkBCQEOdG9Db21wb3NpdGVLZXkCBS5rX3Bvc2l0aW9uTGFzdFVwZGF0ZWRDdW11bGF0aXZlUHJlbWl1bUZyYWN0aW9uBQdfdHJhZGVyCQDMCAIJAQtEZWxldGVFbnRyeQEJAQ50b0NvbXBvc2l0ZUtleQIFHmtfcG9zaXRpb25MYXN0VXBkYXRlZFRpbWVzdGFtcAUHX3RyYWRlcgkAzAgCCQELRGVsZXRlRW50cnkBCQEOdG9Db21wb3NpdGVLZXkCBQ1rX3Bvc2l0aW9uRmVlBQdfdHJhZGVyCQDMCAIJAQtEZWxldGVFbnRyeQEJAQ50b0NvbXBvc2l0ZUtleQIFEmtfcG9zaXRpb25TZXF1ZW5jZQUHX3RyYWRlcgkAzAgCCQEMSW50ZWdlckVudHJ5AgkBDnRvQ29tcG9zaXRlS2V5AgUOa19wb3NpdGlvblNpemUFC3Bvc2l0aW9uS2V5BQVwU2l6ZQkAzAgCCQEMSW50ZWdlckVudHJ5AgkBDnRvQ29tcG9zaXRlS2V5AgUQa19wb3NpdGlvbk1hcmdpbgULcG9zaXRpb25LZXkFB3BNYXJnaW4JAMwIAgkBDEludGVnZXJFbnRyeQIJAQ50b0NvbXBvc2l0ZUtleQIFFmtfcG9zaXRpb25PcGVuTm90aW9uYWwFC3Bvc2l0aW9uS2V5BQlwTm90aW9uYWwJAMwIAgkBDEludGVnZXJFbnRyeQIJAQ50b0NvbXBvc2l0ZUtleQIFLmtfcG9zaXRpb25MYXN0VXBkYXRlZEN1bXVsYXRpdmVQcmVtaXVtRnJhY3Rpb24FC3Bvc2l0aW9uS2V5BQlwRnJhY3Rpb24JAMwIAgkBDEludGVnZXJFbnRyeQIJAQ50b0NvbXBvc2l0ZUtleQIFHmtfcG9zaXRpb25MYXN0VXBkYXRlZFRpbWVzdGFtcAULcG9zaXRpb25LZXkFCnBUaW1lc3RhbXAJAMwIAgkBDEludGVnZXJFbnRyeQIJAQ50b0NvbXBvc2l0ZUtleQIFDWtfcG9zaXRpb25GZWUFC3Bvc2l0aW9uS2V5BQRwRmVlCQDMCAIJAQxJbnRlZ2VyRW50cnkCCQEOdG9Db21wb3NpdGVLZXkCBRJrX3Bvc2l0aW9uU2VxdWVuY2UFC3Bvc2l0aW9uS2V5BQlwU2VxdWVuY2UFA25pbAkAAgEJAKwCAgIXTm90aGluZyB0byBtaWdyYXRlIGZvciAFB190cmFkZXIBaQEndmlld19jYWxjUmVtYWluTWFyZ2luV2l0aEZ1bmRpbmdQYXltZW50AwdfdHJhZGVyCl9kaXJlY3Rpb24MX3ByaWNlVXBkYXRlBAx1cGRhdGVPcmFjbGUJAPwHBAUEdGhpcwIMdXBkYXRlT3JhY2xlCQDMCAIFDF9wcmljZVVwZGF0ZQUDbmlsBQNuaWwDCQAAAgUMdXBkYXRlT3JhY2xlBQx1cGRhdGVPcmFjbGUEBHN5bmMJAPwHBAUEdGhpcwIZc3luY1Rlcm1pbmFsUHJpY2VUb09yYWNsZQUDbmlsBQNuaWwDCQAAAgUEc3luYwUEc3luYwQNJHQwODY0MjY4NjU2MgkBC2dldFBvc2l0aW9uAgUHX3RyYWRlcgUKX2RpcmVjdGlvbgQMcG9zaXRpb25TaXplCAUNJHQwODY0MjY4NjU2MgJfMQQOcG9zaXRpb25NYXJnaW4IBQ0kdDA4NjQyNjg2NTYyAl8yBANwb24IBQ0kdDA4NjQyNjg2NTYyAl8zBBFwb3NpdGlvbkxzdFVwZENQRggFDSR0MDg2NDI2ODY1NjICXzQEEXBvc2l0aW9uVGltZXN0YW1wCAUNJHQwODY0MjY4NjU2MgJfNQQNJHQwODY1NjU4NjY3OAkBI2dldFBvc2l0aW9uTm90aW9uYWxBbmRVbnJlYWxpemVkUG5sAwUHX3RyYWRlcgUKX2RpcmVjdGlvbgUPUE5MX09QVElPTl9TUE9UBBBwb3NpdGlvbk5vdGlvbmFsCAUNJHQwODY1NjU4NjY3OAJfMQQNdW5yZWFsaXplZFBubAgFDSR0MDg2NTY1ODY2NzgCXzIEDSR0MDg2NjgxODY5MDUJATBjYWxjUmVtYWluTWFyZ2luV2l0aEZ1bmRpbmdQYXltZW50QW5kUm9sbG92ZXJGZWUFBQxwb3NpdGlvblNpemUFDnBvc2l0aW9uTWFyZ2luBRFwb3NpdGlvbkxzdFVwZENQRgURcG9zaXRpb25UaW1lc3RhbXAFDXVucmVhbGl6ZWRQbmwEDHJlbWFpbk1hcmdpbggFDSR0MDg2NjgxODY5MDUCXzEEB2JhZERlYnQIBQ0kdDA4NjY4MTg2OTA1Al8yBA5mdW5kaW5nUGF5bWVudAgFDSR0MDg2NjgxODY5MDUCXzMEC3JvbGxvdmVyRmVlCAUNJHQwODY2ODE4NjkwNQJfNAQPdW5kZXJseWluZ1ByaWNlCQEOZ2V0T3JhY2xlUHJpY2UABAlzcG90UHJpY2UJAQxnZXRTcG90UHJpY2UACQACAQkArAICCQCsAgIJAKwCAgkArAICCQCsAgIJAKwCAgkArAICCQCsAgIJAQFzAQUMcmVtYWluTWFyZ2luCQEBcwEFDmZ1bmRpbmdQYXltZW50CQEBcwEJAQ5nZXRNYXJnaW5SYXRpbwIFB190cmFkZXIFCl9kaXJlY3Rpb24JAQFzAQUNdW5yZWFsaXplZFBubAkBAXMBBQdiYWREZWJ0CQEBcwEFEHBvc2l0aW9uTm90aW9uYWwJAQFzAQULcm9sbG92ZXJGZWUJAQFzAQUPdW5kZXJseWluZ1ByaWNlCQEBcwEFCXNwb3RQcmljZQkAAgECJFN0cmljdCB2YWx1ZSBpcyBub3QgZXF1YWwgdG8gaXRzZWxmLgkAAgECJFN0cmljdCB2YWx1ZSBpcyBub3QgZXF1YWwgdG8gaXRzZWxmLgFpARV2aWV3X2dldFBlZ0FkanVzdENvc3QBBl9wcmljZQQHX3F0QXN0UgkBBnF0QXN0UgAEB19ic0FzdFIJAQZic0FzdFIABAZyZXN1bHQJARRnZXRTeW5jVGVybWluYWxQcmljZQMFBl9wcmljZQUHX3F0QXN0UgUHX2JzQXN0UgkAAgEJAKQDAQgFBnJlc3VsdAJfMwFpARh2aWV3X2dldFRlcm1pbmFsQW1tUHJpY2UABA0kdDA4Nzc1ODg3ODM5CQETZ2V0VGVybWluYWxBbW1TdGF0ZQAEGXRlcm1pbmFsUXVvdGVBc3NldFJlc2VydmUIBQ0kdDA4Nzc1ODg3ODM5Al8xBBh0ZXJtaW5hbEJhc2VBc3NldFJlc2VydmUIBQ0kdDA4Nzc1ODg3ODM5Al8yBAVwcmljZQkBBGRpdmQCCQEEbXVsZAIFGXRlcm1pbmFsUXVvdGVBc3NldFJlc2VydmUJAQZxdEFzdFcACQEEbXVsZAIFGHRlcm1pbmFsQmFzZUFzc2V0UmVzZXJ2ZQkBBmJzQXN0VwAJAAIBCQCkAwEFBXByaWNlAWkBD3ZpZXdfZ2V0RnVuZGluZwEMX3ByaWNlVXBkYXRlBAx1cGRhdGVPcmFjbGUJAPwHBAUEdGhpcwIMdXBkYXRlT3JhY2xlCQDMCAIFDF9wcmljZVVwZGF0ZQUDbmlsBQNuaWwDCQAAAgUMdXBkYXRlT3JhY2xlBQx1cGRhdGVPcmFjbGUEBHN5bmMJAPwHBAUEdGhpcwIZc3luY1Rlcm1pbmFsUHJpY2VUb09yYWNsZQUDbmlsBQNuaWwDCQAAAgUEc3luYwUEc3luYwQPdW5kZXJseWluZ1ByaWNlCQEOZ2V0T3JhY2xlUHJpY2UABA0kdDA4ODQ5MTg4NTY5CQEKZ2V0RnVuZGluZwAEFHNob3J0UHJlbWl1bUZyYWN0aW9uCAUNJHQwODg0OTE4ODU2OQJfMQQTbG9uZ1ByZW1pdW1GcmFjdGlvbggFDSR0MDg4NDkxODg1NjkCXzIEDnByZW1pdW1Ub1ZhdWx0CAUNJHQwODg0OTE4ODU2OQJfMwQLbG9uZ0Z1bmRpbmcJAQRkaXZkAgUTbG9uZ1ByZW1pdW1GcmFjdGlvbgUPdW5kZXJseWluZ1ByaWNlBAxzaG9ydEZ1bmRpbmcJAQRkaXZkAgUUc2hvcnRQcmVtaXVtRnJhY3Rpb24FD3VuZGVybHlpbmdQcmljZQkAAgEJAKwCAgkArAICCQCsAgIJAKwCAgkBAXMBBQtsb25nRnVuZGluZwkBAXMBBQxzaG9ydEZ1bmRpbmcJAQFzAQkBDGdldFNwb3RQcmljZQAJAQFzAQkBDmdldE9yYWNsZVByaWNlAAkBAXMBBQ5wcmVtaXVtVG9WYXVsdAkAAgECJFN0cmljdCB2YWx1ZSBpcyBub3QgZXF1YWwgdG8gaXRzZWxmLgkAAgECJFN0cmljdCB2YWx1ZSBpcyBub3QgZXF1YWwgdG8gaXRzZWxmLgFpARBjb21wdXRlU3BvdFByaWNlAAQEc3luYwkA/AcEBQR0aGlzAhlzeW5jVGVybWluYWxQcmljZVRvT3JhY2xlBQNuaWwFA25pbAMJAAACBQRzeW5jBQRzeW5jBAZyZXN1bHQJAQxnZXRTcG90UHJpY2UACQCUCgIFA25pbAUGcmVzdWx0CQACAQIkU3RyaWN0IHZhbHVlIGlzIG5vdCBlcXVhbCB0byBpdHNlbGYuAWkBH2NvbXB1dGVGZWVGb3JUcmFkZXJXaXRoQXJ0aWZhY3QCB190cmFkZXILX2FydGlmYWN0SWQEBnJlc3VsdAkBGGdldEZvclRyYWRlcldpdGhBcnRpZmFjdAIFB190cmFkZXIFC19hcnRpZmFjdElkCQCUCgIFA25pbAUGcmVzdWx0AQJ0eAEGdmVyaWZ5AAQOY29vcmRpbmF0b3JTdHIJAJ0IAgUEdGhpcwUUa19jb29yZGluYXRvckFkZHJlc3MDCQEJaXNEZWZpbmVkAQUOY29vcmRpbmF0b3JTdHIEBWFkbWluCQCdCAIJARFAZXh0ck5hdGl2ZSgxMDYyKQEJAQV2YWx1ZQEFDmNvb3JkaW5hdG9yU3RyBQ9rX2FkbWluX2FkZHJlc3MDCQEJaXNEZWZpbmVkAQUFYWRtaW4JAQt2YWx1ZU9yRWxzZQIJAJsIAgkBEUBleHRyTmF0aXZlKDEwNjIpAQkBBXZhbHVlAQUFYWRtaW4JAKwCAgkArAICCQCsAgICB3N0YXR1c18JAKUIAQUEdGhpcwIBXwkA2AQBCAUCdHgCaWQHCQACAQIudW5hYmxlIHRvIHZlcmlmeTogYWRtaW4gbm90IHNldCBpbiBjb29yZGluYXRvcgkA9AMDCAUCdHgJYm9keUJ5dGVzCQCRAwIIBQJ0eAZwcm9vZnMAAAgFAnR4D3NlbmRlclB1YmxpY0tledwKBzM=", "height": 2661199, "applicationStatus": "succeeded", "spentComplexity": 0 } View: original | compacted Prev: 2AdqEynwJEqWSdrtPvm4jSghz286rzrHk1c8665jShvy Next: none Diff:
OldNewDifferences
6262 let k_oracleMode = "k_oracleMode"
6363
6464 let k_positionMode = "k_positionMode"
65+
66+let k_minLiquidationNotional = "k_minLiquidationNotional"
6567
6668 let k_latestLongCumulativePremiumFraction = "k_latestLongPremiumFraction"
6769
333335 func positionMode () = intOr(k_positionMode, POSITION_DIRECT)
334336
335337
338+func minPartialLiquidationNotional () = intOr(k_minLiquidationNotional, (10 * DECIMAL_UNIT))
339+
340+
336341 func lastTimestamp () = lastBlock.timestamp
337342
338343
457462 let amountBaseAssetBought = if (_isAdd)
458463 then amountBaseAssetBoughtAbs
459464 else -(amountBaseAssetBoughtAbs)
460- let $t01636716537 = updateReserve(_isAdd, quoteAssetAmountAdjusted, amountBaseAssetBoughtAbs)
461- let quoteAssetReserveAfter1 = $t01636716537._1
462- let baseAssetReserveAfter1 = $t01636716537._2
463- let totalPositionSizeAfter1 = $t01636716537._3
465+ let $t01658516755 = updateReserve(_isAdd, quoteAssetAmountAdjusted, amountBaseAssetBoughtAbs)
466+ let quoteAssetReserveAfter1 = $t01658516755._1
467+ let baseAssetReserveAfter1 = $t01658516755._2
468+ let totalPositionSizeAfter1 = $t01658516755._3
464469 let priceBefore = divd(muld(_qtAstR, _qtAstW), muld(_bsAstR, _bsAstW))
465470 let marketPrice = divd(_quoteAssetAmount, amountBaseAssetBoughtAbs)
466471 let priceDiff = abs((priceBefore - marketPrice))
488493 else 0
489494 let rolloverFee = calcRolloverFee(_oldPositionMargin, _oldPositionLastUpdatedTimestamp)
490495 let signedMargin = (((_marginDelta - rolloverFee) - fundingPayment) + _oldPositionMargin)
491- let $t01920419331 = if ((0 > signedMargin))
496+ let $t01942219549 = if ((0 > signedMargin))
492497 then $Tuple2(0, abs(signedMargin))
493498 else $Tuple2(abs(signedMargin), 0)
494- let remainMargin = $t01920419331._1
495- let badDebt = $t01920419331._2
499+ let remainMargin = $t01942219549._1
500+ let badDebt = $t01942219549._2
496501 $Tuple4(remainMargin, badDebt, fundingPayment, rolloverFee)
497502 }
498503
510515 let quoteAssetDelta = abs((quoteAssetAfter - _quoteAssetReserve))
511516 let quoteAssetSold = muld(quoteAssetDelta, _quoteAssetWeight)
512517 let maxPriceImpactValue = maxPriceImpact()
513- let $t02059320755 = updateReserve(!(_isAdd), quoteAssetDelta, _baseAssetAmount)
514- let quoteAssetReserveAfter1 = $t02059320755._1
515- let baseAssetReserveAfter1 = $t02059320755._2
516- let totalPositionSizeAfter1 = $t02059320755._3
518+ let $t02081120973 = updateReserve(!(_isAdd), quoteAssetDelta, _baseAssetAmount)
519+ let quoteAssetReserveAfter1 = $t02081120973._1
520+ let baseAssetReserveAfter1 = $t02081120973._2
521+ let totalPositionSizeAfter1 = $t02081120973._3
517522 let marketPrice = divd(quoteAssetSold, _baseAssetAmount)
518523 let priceDiff = abs((priceBefore - marketPrice))
519524 let priceImpact = (DECIMAL_UNIT - divd(priceBefore, (priceBefore + priceDiff)))
653658
654659
655660 func getPositionNotionalAndUnrealizedPnl (_trader,_direction,_option) = {
656- let $t02889629036 = getPosition(_trader, _direction)
657- let positionSize = $t02889629036._1
658- let positionMargin = $t02889629036._2
659- let positionOpenNotional = $t02889629036._3
660- let positionLstUpdCPF = $t02889629036._4
661+ let $t02911429254 = getPosition(_trader, _direction)
662+ let positionSize = $t02911429254._1
663+ let positionMargin = $t02911429254._2
664+ let positionOpenNotional = $t02911429254._3
665+ let positionLstUpdCPF = $t02911429254._4
661666 getPositionNotionalAndUnrealizedPnlByValues(positionSize, positionOpenNotional, qtAstR(), qtAstW(), bsAstR(), bsAstW(), _option)
662667 }
663668
666671
667672
668673 func getMarginRatioByOption (_trader,_direction,_option) = {
669- let $t02956829721 = getPosition(_trader, _direction)
670- let positionSize = $t02956829721._1
671- let positionMargin = $t02956829721._2
672- let pon = $t02956829721._3
673- let positionLastUpdatedCPF = $t02956829721._4
674- let positionTimestamp = $t02956829721._5
675- let $t02972729832 = getPositionNotionalAndUnrealizedPnl(_trader, _direction, _option)
676- let positionNotional = $t02972729832._1
677- let unrealizedPnl = $t02972729832._2
678- let $t02983730049 = calcRemainMarginWithFundingPaymentAndRolloverFee(positionSize, positionMargin, positionLastUpdatedCPF, positionTimestamp, unrealizedPnl)
679- let remainMargin = $t02983730049._1
680- let badDebt = $t02983730049._2
674+ let $t02978629939 = getPosition(_trader, _direction)
675+ let positionSize = $t02978629939._1
676+ let positionMargin = $t02978629939._2
677+ let pon = $t02978629939._3
678+ let positionLastUpdatedCPF = $t02978629939._4
679+ let positionTimestamp = $t02978629939._5
680+ let $t02994530050 = getPositionNotionalAndUnrealizedPnl(_trader, _direction, _option)
681+ let positionNotional = $t02994530050._1
682+ let unrealizedPnl = $t02994530050._2
683+ let $t03005530267 = calcRemainMarginWithFundingPaymentAndRolloverFee(positionSize, positionMargin, positionLastUpdatedCPF, positionTimestamp, unrealizedPnl)
684+ let remainMargin = $t03005530267._1
685+ let badDebt = $t03005530267._2
681686 calcMarginRatio(remainMargin, badDebt, positionNotional)
682687 }
683688
698703
699704
700705 func internalClosePosition (_trader,_direction,_size,_fee,_minQuoteAssetAmount,_addToMargin,_checkMaxPriceImpact,_liquidate) = {
701- let $t03121231380 = getPosition(_trader, _direction)
702- let oldPositionSize = $t03121231380._1
703- let oldPositionMargin = $t03121231380._2
704- let oldPositionOpenNotional = $t03121231380._3
705- let oldPositionLstUpdCPF = $t03121231380._4
706- let oldPositionTimestamp = $t03121231380._5
706+ let $t03143031598 = getPosition(_trader, _direction)
707+ let oldPositionSize = $t03143031598._1
708+ let oldPositionMargin = $t03143031598._2
709+ let oldPositionOpenNotional = $t03143031598._3
710+ let oldPositionLstUpdCPF = $t03143031598._4
711+ let oldPositionTimestamp = $t03143031598._5
707712 let isLongPosition = (oldPositionSize > 0)
708713 let absOldPositionSize = abs(oldPositionSize)
709714 if (if ((absOldPositionSize >= _size))
711716 else false)
712717 then {
713718 let isPartialClose = (absOldPositionSize > _size)
714- let $t03167232123 = swapOutput((oldPositionSize > 0), _size, _checkMaxPriceImpact)
715- let exchangedQuoteAssetAmount = $t03167232123._1
716- let quoteAssetReserveAfter = $t03167232123._2
717- let baseAssetReserveAfter = $t03167232123._3
718- let totalPositionSizeAfter = $t03167232123._4
719+ let $t03189032341 = swapOutput((oldPositionSize > 0), _size, _checkMaxPriceImpact)
720+ let exchangedQuoteAssetAmount = $t03189032341._1
721+ let quoteAssetReserveAfter = $t03189032341._2
722+ let baseAssetReserveAfter = $t03189032341._3
723+ let totalPositionSizeAfter = $t03189032341._4
719724 let exchangedPositionSize = if ((oldPositionSize > 0))
720725 then -(_size)
721726 else _size
722- let $t03233832562 = getPositionNotionalAndUnrealizedPnl(_trader, _direction, PNL_OPTION_SPOT)
723- let oldPositionNotional = $t03233832562._1
724- let unrealizedPnl = $t03233832562._2
727+ let $t03255632780 = getPositionNotionalAndUnrealizedPnl(_trader, _direction, PNL_OPTION_SPOT)
728+ let oldPositionNotional = $t03255632780._1
729+ let unrealizedPnl = $t03255632780._2
725730 let realizedRatio = divd(abs(exchangedPositionSize), absOldPositionSize)
726731 let realizedPnl = muld(unrealizedPnl, realizedRatio)
727- let $t03290333149 = calcRemainMarginWithFundingPaymentAndRolloverFee(oldPositionSize, oldPositionMargin, oldPositionLstUpdCPF, oldPositionTimestamp, unrealizedPnl)
728- let remainMarginBefore = $t03290333149._1
729- let x1 = $t03290333149._2
730- let x2 = $t03290333149._3
731- let rolloverFee = $t03290333149._4
732+ let $t03312133367 = calcRemainMarginWithFundingPaymentAndRolloverFee(oldPositionSize, oldPositionMargin, oldPositionLstUpdCPF, oldPositionTimestamp, unrealizedPnl)
733+ let remainMarginBefore = $t03312133367._1
734+ let x1 = $t03312133367._2
735+ let x2 = $t03312133367._3
736+ let rolloverFee = $t03312133367._4
732737 let positionBadDebt = calcRemainMarginWithFundingPaymentAndRolloverFee(oldPositionSize, oldPositionMargin, oldPositionLstUpdCPF, oldPositionTimestamp, realizedPnl)._2
733738 let realizedCloseFee = muld(muld(oldPositionNotional, realizedRatio), _fee)
734739 let unrealizedPnlAfter = (unrealizedPnl - realizedPnl)
736741 then ((oldPositionNotional - exchangedQuoteAssetAmount) - unrealizedPnlAfter)
737742 else ((unrealizedPnlAfter + oldPositionNotional) - exchangedQuoteAssetAmount)
738743 let newPositionSize = (oldPositionSize + exchangedPositionSize)
739- let $t03455534941 = if ((newPositionSize == 0))
744+ let $t03477335159 = if ((newPositionSize == 0))
740745 then $Tuple2(0, 0)
741746 else $Tuple2(abs(remainOpenNotional), latestCumulativePremiumFraction(newPositionSize))
742- let newPositionOpenNotional = $t03455534941._1
743- let newPositionLstUpdCPF = $t03455534941._2
747+ let newPositionOpenNotional = $t03477335159._1
748+ let newPositionLstUpdCPF = $t03477335159._2
744749 let openNotionalDelta = (oldPositionOpenNotional - newPositionOpenNotional)
745750 let marginRatio = getMarginRatioByOption(_trader, _direction, PNL_OPTION_SPOT)
746751 let newPositionMarginWithSameRatio = if ((oldPositionSize > 0))
783788 then $Tuple2(qtAstR(), bsAstR())
784789 else {
785790 let direction = (_positionSize > 0)
786- let $t03818838367 = swapOutput(direction, abs(_positionSize), false)
787- let currentNetMarketValue = $t03818838367._1
788- let terminalQuoteAssetReserve = $t03818838367._2
789- let terminalBaseAssetReserve = $t03818838367._3
791+ let $t03840638585 = swapOutput(direction, abs(_positionSize), false)
792+ let currentNetMarketValue = $t03840638585._1
793+ let terminalQuoteAssetReserve = $t03840638585._2
794+ let terminalBaseAssetReserve = $t03840638585._3
790795 $Tuple2(terminalQuoteAssetReserve, terminalBaseAssetReserve)
791796 }
792797 }
871876 func getAdjustedFee (_artifactId,_baseFeeDiscount) = {
872877 let baseFeeRaw = fee()
873878 let baseFee = muld(baseFeeRaw, _baseFeeDiscount)
874- let $t04303143526 = if ((_artifactId != ""))
879+ let $t04324943744 = if ((_artifactId != ""))
875880 then {
876881 let artifactKind = strA(nftManagerAddress(), toCompositeKey(k_token_type, _artifactId))
877882 if ((artifactKind == FEE_REDUCTION_TOKEN_TYPE))
883888 else throw("Invalid attached artifact")
884889 }
885890 else $Tuple2(baseFee, false)
886- let adjustedFee = $t04303143526._1
887- let burnArtifact = $t04303143526._2
891+ let adjustedFee = $t04324943744._1
892+ let burnArtifact = $t04324943744._2
888893 $Tuple2(adjustedFee, burnArtifact)
889894 }
890895
899904 case _ =>
900905 throw("Invalid computeFeeDiscount result")
901906 }
902- let $t04387243946 = getAdjustedFee(_artifactId, feeDiscount)
903- let adjustedFee = $t04387243946._1
904- let burnArtifact = $t04387243946._2
907+ let $t04409044164 = getAdjustedFee(_artifactId, feeDiscount)
908+ let adjustedFee = $t04409044164._1
909+ let burnArtifact = $t04409044164._2
905910 $Tuple2(adjustedFee, burnArtifact)
906911 }
907912 else throw("Strict value is not equal to itself.")
10551060 let qtAstRAfter = (_qtAstR + _quoteAssetAmount)
10561061 let baseAssetAmountToAdd = (divd(muld(qtAstRAfter, _qtAstW), price) - _bsAstR)
10571062 let bsAstRAfter = (_bsAstR + baseAssetAmountToAdd)
1058- let $t05283152982 = getSyncTerminalPrice(getOraclePrice(), qtAstRAfter, bsAstRAfter)
1059- let newQuoteAssetWeight = $t05283152982._1
1060- let newBaseAssetWeight = $t05283152982._2
1061- let marginToVault = $t05283152982._3
1063+ let $t05304953200 = getSyncTerminalPrice(getOraclePrice(), qtAstRAfter, bsAstRAfter)
1064+ let newQuoteAssetWeight = $t05304953200._1
1065+ let newBaseAssetWeight = $t05304953200._2
1066+ let marginToVault = $t05304953200._3
10621067 let doExchangePnL = if ((marginToVault != 0))
10631068 then {
10641069 let doExchangePnL = invoke(vaultAddress(), "exchangeFreeAndLocked", [marginToVault], nil)
12311236 else isMarketClosed())
12321237 then throw("Invalid increasePosition parameters")
12331238 else {
1234- let $t06032160470 = getForTraderWithArtifact(_trader, getArtifactId(i))
1235- let adjustedFee = $t06032160470._1
1236- let burnArtifact = $t06032160470._2
1239+ let $t06053960688 = getForTraderWithArtifact(_trader, getArtifactId(i))
1240+ let adjustedFee = $t06053960688._1
1241+ let burnArtifact = $t06053960688._2
12371242 let _amount = divd(_rawAmount, (muld(adjustedFee, _leverage) + DECIMAL_UNIT))
12381243 let distributeFeeAmount = (_rawAmount - _amount)
12391244 let referrerFeeAny = invoke(referralAddress(), "acceptPaymentWithLink", [_trader, _refLink], [AttachedPayment(quoteAsset(), distributeFeeAmount)])
12461251 throw("Invalid referrerFee")
12471252 }
12481253 let feeAmount = (distributeFeeAmount - referrerFee)
1249- let $t06096661146 = getPosition(_trader, _direction)
1250- let oldPositionSize = $t06096661146._1
1251- let oldPositionMargin = $t06096661146._2
1252- let oldPositionOpenNotional = $t06096661146._3
1253- let oldPositionLstUpdCPF = $t06096661146._4
1254- let oldPositionTimestamp = $t06096661146._5
1254+ let $t06118461364 = getPosition(_trader, _direction)
1255+ let oldPositionSize = $t06118461364._1
1256+ let oldPositionMargin = $t06118461364._2
1257+ let oldPositionOpenNotional = $t06118461364._3
1258+ let oldPositionLstUpdCPF = $t06118461364._4
1259+ let oldPositionTimestamp = $t06118461364._5
12551260 let isNewPosition = (oldPositionSize == 0)
12561261 let isSameDirection = if ((oldPositionSize > 0))
12571262 then (_direction == DIR_LONG)
12601265 then isSameDirection
12611266 else false
12621267 let isAdd = (_direction == DIR_LONG)
1263- let $t06143564568 = if (if (isNewPosition)
1268+ let $t06165364786 = if (if (isNewPosition)
12641269 then true
12651270 else expandExisting)
12661271 then {
12671272 let openNotional = muld(_amount, _leverage)
1268- let $t06194462117 = swapInput(isAdd, openNotional)
1269- let amountBaseAssetBought = $t06194462117._1
1270- let quoteAssetReserveAfter = $t06194462117._2
1271- let baseAssetReserveAfter = $t06194462117._3
1272- let totalPositionSizeAfter = $t06194462117._4
1273+ let $t06216262335 = swapInput(isAdd, openNotional)
1274+ let amountBaseAssetBought = $t06216262335._1
1275+ let quoteAssetReserveAfter = $t06216262335._2
1276+ let baseAssetReserveAfter = $t06216262335._3
1277+ let totalPositionSizeAfter = $t06216262335._4
12731278 if (if ((_minBaseAssetAmount != 0))
12741279 then (_minBaseAssetAmount > abs(amountBaseAssetBought))
12751280 else false)
12821287 let totalShortOpenInterestAfter = (openInterestShort() + (if ((0 > newPositionSize))
12831288 then openNotional
12841289 else 0))
1285- let $t06266362938 = calcRemainMarginWithFundingPaymentAndRolloverFee(oldPositionSize, oldPositionMargin, oldPositionLstUpdCPF, oldPositionTimestamp, _amount)
1286- let remainMargin = $t06266362938._1
1287- let x1 = $t06266362938._2
1288- let x2 = $t06266362938._3
1289- let rolloverFee = $t06266362938._4
1290+ let $t06288163156 = calcRemainMarginWithFundingPaymentAndRolloverFee(oldPositionSize, oldPositionMargin, oldPositionLstUpdCPF, oldPositionTimestamp, _amount)
1291+ let remainMargin = $t06288163156._1
1292+ let x1 = $t06288163156._2
1293+ let x2 = $t06288163156._3
1294+ let rolloverFee = $t06288163156._4
12901295 if (!(requireNotOverSpreadLimit(quoteAssetReserveAfter, baseAssetReserveAfter)))
12911296 then throw("Over max spread limit")
12921297 else if (!(requireNotOverMaxOpenNotional(totalLongOpenInterestAfter, totalShortOpenInterestAfter)))
13001305 }
13011306 else {
13021307 let openNotional = muld(_amount, _leverage)
1303- let $t06425664384 = getPositionNotionalAndUnrealizedPnl(toString(i.caller), _direction, PNL_OPTION_SPOT)
1304- let oldPositionNotional = $t06425664384._1
1305- let unrealizedPnl = $t06425664384._2
1308+ let $t06447464602 = getPositionNotionalAndUnrealizedPnl(toString(i.caller), _direction, PNL_OPTION_SPOT)
1309+ let oldPositionNotional = $t06447464602._1
1310+ let unrealizedPnl = $t06447464602._2
13061311 if ((oldPositionNotional > openNotional))
13071312 then throw("Use decreasePosition to decrease position size")
13081313 else throw("Close position first")
13091314 }
1310- let newPositionSize = $t06143564568._1
1311- let newPositionRemainMargin = $t06143564568._2
1312- let newPositionOpenNotional = $t06143564568._3
1313- let newPositionLatestCPF = $t06143564568._4
1314- let newPositionTimestamp = $t06143564568._5
1315- let baseAssetReserveAfter = $t06143564568._6
1316- let quoteAssetReserveAfter = $t06143564568._7
1317- let totalPositionSizeAfter = $t06143564568._8
1318- let openInterestNotionalAfter = $t06143564568._9
1319- let totalLongAfter = $t06143564568._10
1320- let totalShortAfter = $t06143564568._11
1321- let totalLongOpenInterestAfter = $t06143564568._12
1322- let totalShortOpenInterestAfter = $t06143564568._13
1323- let rolloverFee = $t06143564568._14
1324- let $t06457464645 = distributeFee((feeAmount + rolloverFee))
1325- let feeToStakers = $t06457464645._1
1326- let feeToVault = $t06457464645._2
1315+ let newPositionSize = $t06165364786._1
1316+ let newPositionRemainMargin = $t06165364786._2
1317+ let newPositionOpenNotional = $t06165364786._3
1318+ let newPositionLatestCPF = $t06165364786._4
1319+ let newPositionTimestamp = $t06165364786._5
1320+ let baseAssetReserveAfter = $t06165364786._6
1321+ let quoteAssetReserveAfter = $t06165364786._7
1322+ let totalPositionSizeAfter = $t06165364786._8
1323+ let openInterestNotionalAfter = $t06165364786._9
1324+ let totalLongAfter = $t06165364786._10
1325+ let totalShortAfter = $t06165364786._11
1326+ let totalLongOpenInterestAfter = $t06165364786._12
1327+ let totalShortOpenInterestAfter = $t06165364786._13
1328+ let rolloverFee = $t06165364786._14
1329+ let $t06479264863 = distributeFee((feeAmount + rolloverFee))
1330+ let feeToStakers = $t06479264863._1
1331+ let feeToVault = $t06479264863._2
13271332 let stake = if ((_amount >= rolloverFee))
13281333 then invoke(vaultAddress(), "addLocked", nil, [AttachedPayment(quoteAsset(), (_amount - rolloverFee))])
13291334 else invoke(vaultAddress(), "withdrawLocked", [(rolloverFee - _amount)], nil)
13851390 else isMarketClosed())
13861391 then throw("Invalid addMargin parameters")
13871392 else {
1388- let $t06698767167 = getPosition(_trader, _direction)
1389- let oldPositionSize = $t06698767167._1
1390- let oldPositionMargin = $t06698767167._2
1391- let oldPositionOpenNotional = $t06698767167._3
1392- let oldPositionLstUpdCPF = $t06698767167._4
1393- let oldPositionTimestamp = $t06698767167._5
1393+ let $t06720567385 = getPosition(_trader, _direction)
1394+ let oldPositionSize = $t06720567385._1
1395+ let oldPositionMargin = $t06720567385._2
1396+ let oldPositionOpenNotional = $t06720567385._3
1397+ let oldPositionLstUpdCPF = $t06720567385._4
1398+ let oldPositionTimestamp = $t06720567385._5
13941399 let stake = invoke(vaultAddress(), "addLocked", nil, [AttachedPayment(quoteAsset(), _amount)])
13951400 if ((stake == stake))
13961401 then {
1397- let $t06730767533 = calcRemainMarginWithFundingPaymentAndRolloverFee(oldPositionSize, oldPositionMargin, oldPositionLstUpdCPF, oldPositionTimestamp, _amount)
1398- let remainMargin = $t06730767533._1
1399- let badDebt = $t06730767533._2
1400- let rolloverFee = $t06730767533._3
1402+ let $t06752567751 = calcRemainMarginWithFundingPaymentAndRolloverFee(oldPositionSize, oldPositionMargin, oldPositionLstUpdCPF, oldPositionTimestamp, _amount)
1403+ let remainMargin = $t06752567751._1
1404+ let badDebt = $t06752567751._2
1405+ let rolloverFee = $t06752567751._3
14011406 let marginRatio = calcMarginRatio(remainMargin, badDebt, oldPositionOpenNotional)
14021407 let checkMinMargin = requireMoreMarginRatio(marginRatio, minInitMarginRatio(), false)
14031408 if ((checkMinMargin == checkMinMargin))
14041409 then {
14051410 let doTransferFeeToStakers = if ((rolloverFee > 0))
14061411 then {
1407- let $t06778967848 = distributeFee(rolloverFee)
1408- let feeToStakers = $t06778967848._1
1409- let feeToVault = $t06778967848._2
1412+ let $t06800768066 = distributeFee(rolloverFee)
1413+ let feeToStakers = $t06800768066._1
1414+ let feeToVault = $t06800768066._2
14101415 let unstake = invoke(vaultAddress(), "withdrawLocked", [feeToStakers], nil)
14111416 if ((unstake == unstake))
14121417 then {
14591464 else isMarketClosed())
14601465 then throw("Invalid removeMargin parameters")
14611466 else {
1462- let $t06934969529 = getPosition(_trader, _direction)
1463- let oldPositionSize = $t06934969529._1
1464- let oldPositionMargin = $t06934969529._2
1465- let oldPositionOpenNotional = $t06934969529._3
1466- let oldPositionLstUpdCPF = $t06934969529._4
1467- let oldPositionTimestamp = $t06934969529._5
1468- let $t06953569784 = calcRemainMarginWithFundingPaymentAndRolloverFee(oldPositionSize, oldPositionMargin, oldPositionLstUpdCPF, oldPositionTimestamp, -(_amount))
1469- let remainMargin = $t06953569784._1
1470- let badDebt = $t06953569784._2
1471- let fundingPayment = $t06953569784._3
1472- let rolloverFee = $t06953569784._4
1467+ let $t06956769747 = getPosition(_trader, _direction)
1468+ let oldPositionSize = $t06956769747._1
1469+ let oldPositionMargin = $t06956769747._2
1470+ let oldPositionOpenNotional = $t06956769747._3
1471+ let oldPositionLstUpdCPF = $t06956769747._4
1472+ let oldPositionTimestamp = $t06956769747._5
1473+ let $t06975370002 = calcRemainMarginWithFundingPaymentAndRolloverFee(oldPositionSize, oldPositionMargin, oldPositionLstUpdCPF, oldPositionTimestamp, -(_amount))
1474+ let remainMargin = $t06975370002._1
1475+ let badDebt = $t06975370002._2
1476+ let fundingPayment = $t06975370002._3
1477+ let rolloverFee = $t06975370002._4
14731478 if ((badDebt != 0))
14741479 then throw("Invalid removed margin amount")
14751480 else {
14771482 if (!(requireMoreMarginRatio(marginRatio, initMarginRatio(), true)))
14781483 then throw(((("Too much margin removed: " + toString(marginRatio)) + " < ") + toString(initMarginRatio())))
14791484 else {
1480- let $t07017070229 = distributeFee(rolloverFee)
1481- let feeToStakers = $t07017070229._1
1482- let feeToVault = $t07017070229._2
1485+ let $t07038870447 = distributeFee(rolloverFee)
1486+ let feeToStakers = $t07038870447._1
1487+ let feeToVault = $t07038870447._2
14831488 let doTransferFeeToStakers = if ((rolloverFee > 0))
14841489 then {
14851490 let lockBadDebt = invoke(vaultAddress(), "exchangeFreeAndLocked", [-(feeToVault)], nil)
15371542 then throw("Invalid closePosition parameters")
15381543 else {
15391544 let oldPositionTimestamp = getPosition(_trader, _direction)._5
1540- let $t07256473167 = internalClosePosition(_trader, _direction, _size, positionFee, _minQuoteAssetAmount, _addToMargin, true, true)
1541- let newPositionSize = $t07256473167._1
1542- let newPositionMargin = $t07256473167._2
1543- let newPositionOpenNotional = $t07256473167._3
1544- let newPositionLstUpdCPF = $t07256473167._4
1545- let positionBadDebt = $t07256473167._5
1546- let realizedPnl = $t07256473167._6
1547- let marginToTrader = $t07256473167._7
1548- let quoteAssetReserveAfter = $t07256473167._8
1549- let baseAssetReserveAfter = $t07256473167._9
1550- let totalPositionSizeAfter = $t07256473167._10
1551- let openInterestNotionalAfter = $t07256473167._11
1552- let totalLongAfter = $t07256473167._12
1553- let totalShortAfter = $t07256473167._13
1554- let totalLongOpenInterestAfter = $t07256473167._14
1555- let totalShortOpenInterestAfter = $t07256473167._15
1556- let realizedFee = $t07256473167._16
1545+ let $t07278273385 = internalClosePosition(_trader, _direction, _size, positionFee, _minQuoteAssetAmount, _addToMargin, true, true)
1546+ let newPositionSize = $t07278273385._1
1547+ let newPositionMargin = $t07278273385._2
1548+ let newPositionOpenNotional = $t07278273385._3
1549+ let newPositionLstUpdCPF = $t07278273385._4
1550+ let positionBadDebt = $t07278273385._5
1551+ let realizedPnl = $t07278273385._6
1552+ let marginToTrader = $t07278273385._7
1553+ let quoteAssetReserveAfter = $t07278273385._8
1554+ let baseAssetReserveAfter = $t07278273385._9
1555+ let totalPositionSizeAfter = $t07278273385._10
1556+ let openInterestNotionalAfter = $t07278273385._11
1557+ let totalLongAfter = $t07278273385._12
1558+ let totalShortAfter = $t07278273385._13
1559+ let totalLongOpenInterestAfter = $t07278273385._14
1560+ let totalShortOpenInterestAfter = $t07278273385._15
1561+ let realizedFee = $t07278273385._16
15571562 if ((positionBadDebt > 0))
15581563 then throw("Invalid closePosition parameters: bad debt")
15591564 else if ((oldPositionTimestamp >= lastTimestamp()))
15771582 case _ =>
15781583 throw("Invalid referrerFee")
15791584 }
1580- let $t07413974212 = distributeFee((realizedFee - referrerFee))
1581- let feeToStakers = $t07413974212._1
1582- let feeToVault = $t07413974212._2
1585+ let $t07435774430 = distributeFee((realizedFee - referrerFee))
1586+ let feeToStakers = $t07435774430._1
1587+ let feeToVault = $t07435774430._2
15831588 let depositVault = invoke(vaultAddress(), "addFree", nil, [AttachedPayment(quoteAsset(), feeToVault)])
15841589 if ((depositVault == depositVault))
15851590 then {
16401645 else isMarketClosed())
16411646 then throw("Unable to liquidate")
16421647 else {
1643- let isPartialLiquidation = if (if ((spotMarginRatio > liquidationFeeRatio()))
1648+ let oldPositionSize = getPosition(_trader, _direction)._1
1649+ let positionSizeAbs = abs(oldPositionSize)
1650+ let isPartialLiquidation = if (if (if ((spotMarginRatio > liquidationFeeRatio()))
16441651 then (partialLiquidationRatio() > 0)
16451652 else false)
16461653 then (DECIMAL_UNIT > partialLiquidationRatio())
1654+ else false)
1655+ then (muld(positionSizeAbs, getSpotPrice()) > minPartialLiquidationNotional())
16471656 else false
1648- let oldPositionSize = getPosition(_trader, _direction)._1
1649- let positionSizeAbs = abs(oldPositionSize)
1650- let $t07680577128 = if (isPartialLiquidation)
1657+ let $t07710477491 = if (isPartialLiquidation)
16511658 then {
1652- let liquidationSize = getPartialLiquidationAmount(_trader, oldPositionSize)
1653- let liquidationRatio = divd(abs(liquidationSize), positionSizeAbs)
1654- $Tuple2(liquidationRatio, abs(liquidationSize))
1659+ let liquidationSize = abs(getPartialLiquidationAmount(_trader, oldPositionSize))
1660+ let liquidationRatio = divd(liquidationSize, positionSizeAbs)
1661+ let liquidationNotional = muld(liquidationSize, getSpotPrice())
1662+ $Tuple2(liquidationRatio, liquidationSize)
16551663 }
16561664 else $Tuple2(0, positionSizeAbs)
1657- let liquidationRatio = $t07680577128._1
1658- let liquidationSize = $t07680577128._2
1659- let $t07713477790 = internalClosePosition(_trader, _direction, if (isPartialLiquidation)
1665+ let liquidationRatio = $t07710477491._1
1666+ let liquidationSize = $t07710477491._2
1667+ let $t07749778153 = internalClosePosition(_trader, _direction, if (isPartialLiquidation)
16601668 then liquidationSize
16611669 else positionSizeAbs, liquidationFeeRatio(), 0, true, false, true)
1662- let newPositionSize = $t07713477790._1
1663- let newPositionMargin = $t07713477790._2
1664- let newPositionOpenNotional = $t07713477790._3
1665- let newPositionLstUpdCPF = $t07713477790._4
1666- let positionBadDebt = $t07713477790._5
1667- let realizedPnl = $t07713477790._6
1668- let marginToTrader = $t07713477790._7
1669- let quoteAssetReserveAfter = $t07713477790._8
1670- let baseAssetReserveAfter = $t07713477790._9
1671- let totalPositionSizeAfter = $t07713477790._10
1672- let openInterestNotionalAfter = $t07713477790._11
1673- let totalLongAfter = $t07713477790._12
1674- let totalShortAfter = $t07713477790._13
1675- let totalLongOpenInterestAfter = $t07713477790._14
1676- let totalShortOpenInterestAfter = $t07713477790._15
1677- let liquidationPenalty = $t07713477790._16
1670+ let newPositionSize = $t07749778153._1
1671+ let newPositionMargin = $t07749778153._2
1672+ let newPositionOpenNotional = $t07749778153._3
1673+ let newPositionLstUpdCPF = $t07749778153._4
1674+ let positionBadDebt = $t07749778153._5
1675+ let realizedPnl = $t07749778153._6
1676+ let marginToTrader = $t07749778153._7
1677+ let quoteAssetReserveAfter = $t07749778153._8
1678+ let baseAssetReserveAfter = $t07749778153._9
1679+ let totalPositionSizeAfter = $t07749778153._10
1680+ let openInterestNotionalAfter = $t07749778153._11
1681+ let totalLongAfter = $t07749778153._12
1682+ let totalShortAfter = $t07749778153._13
1683+ let totalLongOpenInterestAfter = $t07749778153._14
1684+ let totalShortOpenInterestAfter = $t07749778153._15
1685+ let liquidationPenalty = $t07749778153._16
16781686 let feeToLiquidator = (liquidationPenalty / 2)
16791687 let feeToVault = (liquidationPenalty - feeToLiquidator)
16801688 let ammBalance = (cbalance() - liquidationPenalty)
17351743 then throw(((("Invalid funding block timestamp: " + toString(lastTimestamp())) + " < ") + toString(fundingBlockTimestamp)))
17361744 else {
17371745 let underlyingPrice = getOraclePrice()
1738- let $t08000880086 = getFunding()
1739- let shortPremiumFraction = $t08000880086._1
1740- let longPremiumFraction = $t08000880086._2
1741- let premiumToVault = $t08000880086._3
1746+ let $t08037180449 = getFunding()
1747+ let shortPremiumFraction = $t08037180449._1
1748+ let longPremiumFraction = $t08037180449._2
1749+ let premiumToVault = $t08037180449._3
17421750 let doPayFundingToVault = if ((premiumToVault > 0))
17431751 then {
17441752 let doPayFundingToVault = invoke(vaultAddress(), "exchangeFreeAndLocked", [-(premiumToVault)], nil)
17931801 func syncTerminalPriceToOracle () = {
17941802 let _qtAstR = qtAstR()
17951803 let _bsAstR = bsAstR()
1796- let $t08190382269 = getSyncTerminalPrice(getOraclePrice(), _qtAstR, _bsAstR)
1797- let newQuoteAssetWeight = $t08190382269._1
1798- let newBaseAssetWeight = $t08190382269._2
1799- let marginToVault = $t08190382269._3
1804+ let $t08226682632 = getSyncTerminalPrice(getOraclePrice(), _qtAstR, _bsAstR)
1805+ let newQuoteAssetWeight = $t08226682632._1
1806+ let newBaseAssetWeight = $t08226682632._2
1807+ let marginToVault = $t08226682632._3
18001808 let marginToVaultAdj = if (if ((0 > marginToVault))
18011809 then (abs(marginToVault) > cbalance())
18021810 else false)
18611869 let sync = invoke(this, "syncTerminalPriceToOracle", nil, nil)
18621870 if ((sync == sync))
18631871 then {
1864- let $t08606386199 = getPosition(_trader, _direction)
1865- let positionSize = $t08606386199._1
1866- let positionMargin = $t08606386199._2
1867- let pon = $t08606386199._3
1868- let positionLstUpdCPF = $t08606386199._4
1869- let positionTimestamp = $t08606386199._5
1870- let $t08620286315 = getPositionNotionalAndUnrealizedPnl(_trader, _direction, PNL_OPTION_SPOT)
1871- let positionNotional = $t08620286315._1
1872- let unrealizedPnl = $t08620286315._2
1873- let $t08631886542 = calcRemainMarginWithFundingPaymentAndRolloverFee(positionSize, positionMargin, positionLstUpdCPF, positionTimestamp, unrealizedPnl)
1874- let remainMargin = $t08631886542._1
1875- let badDebt = $t08631886542._2
1876- let fundingPayment = $t08631886542._3
1877- let rolloverFee = $t08631886542._4
1878- throw(((((((s(remainMargin) + s(fundingPayment)) + s(getMarginRatio(_trader, _direction))) + s(unrealizedPnl)) + s(badDebt)) + s(positionNotional)) + s(rolloverFee)))
1872+ let $t08642686562 = getPosition(_trader, _direction)
1873+ let positionSize = $t08642686562._1
1874+ let positionMargin = $t08642686562._2
1875+ let pon = $t08642686562._3
1876+ let positionLstUpdCPF = $t08642686562._4
1877+ let positionTimestamp = $t08642686562._5
1878+ let $t08656586678 = getPositionNotionalAndUnrealizedPnl(_trader, _direction, PNL_OPTION_SPOT)
1879+ let positionNotional = $t08656586678._1
1880+ let unrealizedPnl = $t08656586678._2
1881+ let $t08668186905 = calcRemainMarginWithFundingPaymentAndRolloverFee(positionSize, positionMargin, positionLstUpdCPF, positionTimestamp, unrealizedPnl)
1882+ let remainMargin = $t08668186905._1
1883+ let badDebt = $t08668186905._2
1884+ let fundingPayment = $t08668186905._3
1885+ let rolloverFee = $t08668186905._4
1886+ let underlyingPrice = getOraclePrice()
1887+ let spotPrice = getSpotPrice()
1888+ throw(((((((((s(remainMargin) + s(fundingPayment)) + s(getMarginRatio(_trader, _direction))) + s(unrealizedPnl)) + s(badDebt)) + s(positionNotional)) + s(rolloverFee)) + s(underlyingPrice)) + s(spotPrice)))
18791889 }
18801890 else throw("Strict value is not equal to itself.")
18811891 }
18961906
18971907 @Callable(i)
18981908 func view_getTerminalAmmPrice () = {
1899- let $t08727787358 = getTerminalAmmState()
1900- let terminalQuoteAssetReserve = $t08727787358._1
1901- let terminalBaseAssetReserve = $t08727787358._2
1909+ let $t08775887839 = getTerminalAmmState()
1910+ let terminalQuoteAssetReserve = $t08775887839._1
1911+ let terminalBaseAssetReserve = $t08775887839._2
19021912 let price = divd(muld(terminalQuoteAssetReserve, qtAstW()), muld(terminalBaseAssetReserve, bsAstW()))
19031913 throw(toString(price))
19041914 }
19141924 if ((sync == sync))
19151925 then {
19161926 let underlyingPrice = getOraclePrice()
1917- let $t08801088088 = getFunding()
1918- let shortPremiumFraction = $t08801088088._1
1919- let longPremiumFraction = $t08801088088._2
1920- let premiumToVault = $t08801088088._3
1927+ let $t08849188569 = getFunding()
1928+ let shortPremiumFraction = $t08849188569._1
1929+ let longPremiumFraction = $t08849188569._2
1930+ let premiumToVault = $t08849188569._3
19211931 let longFunding = divd(longPremiumFraction, underlyingPrice)
19221932 let shortFunding = divd(shortPremiumFraction, underlyingPrice)
19231933 throw(((((s(longFunding) + s(shortFunding)) + s(getSpotPrice())) + s(getOraclePrice())) + s(premiumToVault)))
Full:
OldNewDifferences
11 {-# STDLIB_VERSION 6 #-}
22 {-# SCRIPT_TYPE ACCOUNT #-}
33 {-# CONTENT_TYPE DAPP #-}
44 let k_baseOracle = "k_baseOracle"
55
66 let k_quoteOracle = "k_quoteOracle"
77
88 let k_balance = "k_balance"
99
1010 let k_sequence = "k_sequence"
1111
1212 let k_positionSize = "k_positionSize"
1313
1414 let k_positionMargin = "k_positionMargin"
1515
1616 let k_positionOpenNotional = "k_positionOpenNotional"
1717
1818 let k_positionLastUpdatedCumulativePremiumFraction = "k_positionFraction"
1919
2020 let k_positionSequence = "k_positionSequence"
2121
2222 let k_positionFee = "k_positionFee"
2323
2424 let k_positionLastUpdatedTimestamp = "k_positionTimestamp"
2525
2626 let k_initialized = "k_initialized"
2727
2828 let k_paused = "k_paused"
2929
3030 let k_closeOnly = "k_closeOnly"
3131
3232 let k_fee = "k_fee"
3333
3434 let k_rolloverFee = "k_rollover_fee"
3535
3636 let k_fundingPeriod = "k_fundingPeriod"
3737
3838 let k_initMarginRatio = "k_initMarginRatio"
3939
4040 let k_minInitMarginRatio = "k_minInitMarginRatio"
4141
4242 let k_maintenanceMarginRatio = "k_mmr"
4343
4444 let k_liquidationFeeRatio = "k_liquidationFeeRatio"
4545
4646 let k_partialLiquidationRatio = "k_partLiquidationRatio"
4747
4848 let k_spreadLimit = "k_spreadLimit"
4949
5050 let k_maxPriceImpact = "k_maxPriceImpact"
5151
5252 let k_maxPriceSpread = "k_maxPriceSpread"
5353
5454 let k_maxOpenNotional = "k_maxOpenNotional"
5555
5656 let k_feeToStakersPercent = "k_feeToStakersPercent"
5757
5858 let k_maxOracleDelay = "k_maxOracleDelay"
5959
6060 let k_fundingMode = "k_fundingMode"
6161
6262 let k_oracleMode = "k_oracleMode"
6363
6464 let k_positionMode = "k_positionMode"
65+
66+let k_minLiquidationNotional = "k_minLiquidationNotional"
6567
6668 let k_latestLongCumulativePremiumFraction = "k_latestLongPremiumFraction"
6769
6870 let k_latestShortCumulativePremiumFraction = "k_latestShortPremiumFraction"
6971
7072 let k_nextFundingBlock = "k_nextFundingBlockMinTimestamp"
7173
7274 let k_longFundingRate = "k_longFundingRate"
7375
7476 let k_shortFundingRate = "k_shortFundingRate"
7577
7678 let k_quoteAssetReserve = "k_qtAstR"
7779
7880 let k_baseAssetReserve = "k_bsAstR"
7981
8082 let k_quoteAssetWeight = "k_qtAstW"
8183
8284 let k_baseAssetWeight = "k_bsAstW"
8385
8486 let k_totalPositionSize = "k_totalPositionSize"
8587
8688 let k_totalLongPositionSize = "k_totalLongPositionSize"
8789
8890 let k_totalShortPositionSize = "k_totalShortPositionSize"
8991
9092 let k_openInterestNotional = "k_openInterestNotional"
9193
9294 let k_openInterestShort = "k_openInterestShort"
9395
9496 let k_openInterestLong = "k_openInterestLong"
9597
9698 let k_lastTx = "k_lastTx"
9799
98100 let k_coordinatorAddress = "k_coordinatorAddress"
99101
100102 let k_vault_address = "k_vault_address"
101103
102104 let k_admin_address = "k_admin_address"
103105
104106 let k_quote_asset = "k_quote_asset"
105107
106108 let k_staking_address = "k_staking_address"
107109
108110 let k_miner_address = "k_miner_address"
109111
110112 let k_orders_address = "k_orders_address"
111113
112114 let k_referral_address = "k_referral_address"
113115
114116 let k_nft_manager_address = "k_nft_manager_address"
115117
116118 func toCompositeKey (_key,_address) = ((_key + "_") + _address)
117119
118120
119121 func coordinator () = valueOrErrorMessage(addressFromString(getStringValue(this, k_coordinatorAddress)), "Coordinator not set")
120122
121123
122124 func adminAddress () = addressFromString(getStringValue(coordinator(), k_admin_address))
123125
124126
125127 func quoteAsset () = fromBase58String(getStringValue(coordinator(), k_quote_asset))
126128
127129
128130 func stakingAddress () = valueOrErrorMessage(addressFromString(getStringValue(coordinator(), k_staking_address)), "Staking not set")
129131
130132
131133 func vaultAddress () = valueOrErrorMessage(addressFromString(getStringValue(coordinator(), k_vault_address)), "Vault not set")
132134
133135
134136 func minerAddress () = valueOrErrorMessage(addressFromString(getStringValue(coordinator(), k_miner_address)), "Miner not set")
135137
136138
137139 func ordersAddress () = valueOrErrorMessage(addressFromString(getStringValue(coordinator(), k_orders_address)), "Orders not set")
138140
139141
140142 func referralAddress () = valueOrErrorMessage(addressFromString(getStringValue(coordinator(), k_referral_address)), "Referral not set")
141143
142144
143145 func nftManagerAddress () = valueOrErrorMessage(addressFromString(getStringValue(coordinator(), k_nft_manager_address)), "NFT Manager not set")
144146
145147
146148 let k_token_param = "k_token_param"
147149
148150 let k_token_type = "k_token_type"
149151
150152 let FEE_REDUCTION_TOKEN_TYPE = "fee_reduction"
151153
152154 let DIR_LONG = 1
153155
154156 let DIR_SHORT = 2
155157
156158 let SECONDS = 1000
157159
158160 let DECIMAL_NUMBERS = 6
159161
160162 let DECIMAL_UNIT = (1 * (((((10 * 10) * 10) * 10) * 10) * 10))
161163
162164 let MINUTES_IN_YEAR = (525600 * DECIMAL_UNIT)
163165
164166 let ONE_DAY = (86400 * DECIMAL_UNIT)
165167
166168 let PNL_OPTION_SPOT = 1
167169
168170 let PNL_OPTION_ORACLE = 2
169171
170172 let FUNDING_ASYMMETRIC = 1
171173
172174 let FUNDING_SYMMETRIC = 2
173175
174176 let ORACLE_PLAIN = 1
175177
176178 let ORACLE_JIT = 2
177179
178180 let POSITION_DIRECT = 1
179181
180182 let POSITION_ORDER = 2
181183
182184 func s (_x) = (toString(_x) + ",")
183185
184186
185187 func divd (_x,_y) = fraction(_x, DECIMAL_UNIT, _y, HALFEVEN)
186188
187189
188190 func muld (_x,_y) = fraction(_x, _y, DECIMAL_UNIT, HALFEVEN)
189191
190192
191193 func bdivd (_x,_y) = fraction(_x, toBigInt(DECIMAL_UNIT), _y, HALFEVEN)
192194
193195
194196 func bmuld (_x,_y) = fraction(_x, _y, toBigInt(DECIMAL_UNIT), HALFEVEN)
195197
196198
197199 func abs (_x) = if ((_x > 0))
198200 then _x
199201 else -(_x)
200202
201203
202204 func vmax (_x,_y) = if ((_x >= _y))
203205 then _x
204206 else _y
205207
206208
207209 func int (k) = valueOrErrorMessage(getInteger(this, k), ("no value for " + k))
208210
209211
210212 func intOr (k,def) = valueOrElse(getInteger(this, k), def)
211213
212214
213215 func strA (_address,_key) = {
214216 let val = valueOrErrorMessage(getString(_address, _key), ("No value for key " + _key))
215217 val
216218 }
217219
218220
219221 func intA (_address,_key) = {
220222 let val = valueOrErrorMessage(getInteger(_address, _key), ("No value for key " + _key))
221223 val
222224 }
223225
224226
225227 func cbalance () = int(k_balance)
226228
227229
228230 func cbalance0 () = intOr(k_balance, 0)
229231
230232
231233 func fee () = int(k_fee)
232234
233235
234236 func rolloverFeeRate () = int(k_rolloverFee)
235237
236238
237239 func initMarginRatio () = int(k_initMarginRatio)
238240
239241
240242 func minInitMarginRatio () = intOr(k_minInitMarginRatio, DECIMAL_UNIT)
241243
242244
243245 func qtAstR () = int(k_quoteAssetReserve)
244246
245247
246248 func qtAstR0 () = intOr(k_quoteAssetReserve, 0)
247249
248250
249251 func bsAstR () = int(k_baseAssetReserve)
250252
251253
252254 func bsAstR0 () = intOr(k_baseAssetReserve, 0)
253255
254256
255257 func qtAstW () = intOr(k_quoteAssetWeight, DECIMAL_UNIT)
256258
257259
258260 func bsAstW () = intOr(k_baseAssetWeight, DECIMAL_UNIT)
259261
260262
261263 func totalPositionSize () = int(k_totalPositionSize)
262264
263265
264266 func openInterestNotional () = int(k_openInterestNotional)
265267
266268
267269 func openInterestShort () = int(k_openInterestShort)
268270
269271
270272 func openInterestLong () = int(k_openInterestLong)
271273
272274
273275 func nextFundingBlockTimestamp () = int(k_nextFundingBlock)
274276
275277
276278 func fundingPeriodRaw () = int(k_fundingPeriod)
277279
278280
279281 func fundingPeriodDecimal () = (fundingPeriodRaw() * DECIMAL_UNIT)
280282
281283
282284 func fundingPeriodSeconds () = (fundingPeriodRaw() * SECONDS)
283285
284286
285287 func maintenanceMarginRatio () = int(k_maintenanceMarginRatio)
286288
287289
288290 func liquidationFeeRatio () = int(k_liquidationFeeRatio)
289291
290292
291293 func partialLiquidationRatio () = int(k_partialLiquidationRatio)
292294
293295
294296 func spreadLimit () = int(k_spreadLimit)
295297
296298
297299 func maxPriceImpact () = int(k_maxPriceImpact)
298300
299301
300302 func maxPriceSpread () = int(k_maxPriceSpread)
301303
302304
303305 func maxOpenNotional () = int(k_maxOpenNotional)
304306
305307
306308 func latestLongCumulativePremiumFraction () = int(k_latestLongCumulativePremiumFraction)
307309
308310
309311 func latestShortCumulativePremiumFraction () = int(k_latestShortCumulativePremiumFraction)
310312
311313
312314 func totalShortPositionSize () = int(k_totalShortPositionSize)
313315
314316
315317 func totalLongPositionSize () = int(k_totalLongPositionSize)
316318
317319
318320 func lastSequence () = intOr(k_sequence, 0)
319321
320322
321323 func feeToStakersPercent () = int(k_feeToStakersPercent)
322324
323325
324326 func maxOracleDelay () = int(k_maxOracleDelay)
325327
326328
327329 func fundingMode () = intOr(k_fundingMode, FUNDING_ASYMMETRIC)
328330
329331
330332 func oracleMode () = intOr(k_oracleMode, ORACLE_PLAIN)
331333
332334
333335 func positionMode () = intOr(k_positionMode, POSITION_DIRECT)
334336
335337
338+func minPartialLiquidationNotional () = intOr(k_minLiquidationNotional, (10 * DECIMAL_UNIT))
339+
340+
336341 func lastTimestamp () = lastBlock.timestamp
337342
338343
339344 func getActualCaller (i) = valueOrElse(getString(ordersAddress(), "k_sender"), toString(i.caller))
340345
341346
342347 func requireMoreMarginRatio (_marginRatio,_baseMarginRatio,_largerThanOrEqualTo) = {
343348 let remainingMarginRatio = (_marginRatio - _baseMarginRatio)
344349 if (if (_largerThanOrEqualTo)
345350 then (0 > remainingMarginRatio)
346351 else false)
347352 then throw(((("Invalid margin: " + toString(_marginRatio)) + " < ") + toString(_baseMarginRatio)))
348353 else if (if (!(_largerThanOrEqualTo))
349354 then (remainingMarginRatio >= 0)
350355 else false)
351356 then throw(((("Invalid margin: " + toString(_marginRatio)) + " > ") + toString(_baseMarginRatio)))
352357 else true
353358 }
354359
355360
356361 func latestCumulativePremiumFraction (_positionSize) = if ((_positionSize == 0))
357362 then throw("Should not be called with _positionSize == 0")
358363 else if ((_positionSize > 0))
359364 then latestLongCumulativePremiumFraction()
360365 else latestShortCumulativePremiumFraction()
361366
362367
363368 func getPosition (_trader,_direction) = {
364369 let positionKey = ((_trader + "_") + toString(_direction))
365370 let positionSizeOpt = getInteger(this, toCompositeKey(k_positionSize, positionKey))
366371 match positionSizeOpt {
367372 case positionSize: Int =>
368373 $Tuple5(positionSize, getIntegerValue(this, toCompositeKey(k_positionMargin, positionKey)), getIntegerValue(this, toCompositeKey(k_positionOpenNotional, positionKey)), getIntegerValue(this, toCompositeKey(k_positionLastUpdatedCumulativePremiumFraction, positionKey)), getIntegerValue(this, toCompositeKey(k_positionLastUpdatedTimestamp, positionKey)))
369374 case _ =>
370375 $Tuple5(0, 0, 0, 0, 0)
371376 }
372377 }
373378
374379
375380 func getDirection (_positionSize) = if ((0 > _positionSize))
376381 then DIR_SHORT
377382 else DIR_LONG
378383
379384
380385 func getPositionFee (_trader,_direction) = {
381386 let positionKey = ((_trader + "_") + toString(_direction))
382387 let positionFeeOpt = getInteger(this, toCompositeKey(k_positionFee, positionKey))
383388 match positionFeeOpt {
384389 case positionFee: Int =>
385390 positionFee
386391 case _ =>
387392 fee()
388393 }
389394 }
390395
391396
392397 func requireOpenPosition (_trader,_direction) = if ((getPosition(_trader, _direction)._1 == 0))
393398 then throw("No open position")
394399 else true
395400
396401
397402 func getOracleData (key) = {
398403 let oracleDataStr = getString(this, key)
399404 if (if (isDefined(oracleDataStr))
400405 then (value(oracleDataStr) != "")
401406 else false)
402407 then {
403408 let oracleData = split(value(oracleDataStr), ",")
404409 let oracleAddress = valueOrErrorMessage(addressFromString(oracleData[0]), ("Invalid oracle address in: " + value(oracleDataStr)))
405410 let priceKey = oracleData[1]
406411 let blockKey = oracleData[2]
407412 let openKey = oracleData[3]
408413 $Tuple4(oracleAddress, priceKey, blockKey, openKey)
409414 }
410415 else unit
411416 }
412417
413418
414419 func initialized () = valueOrElse(getBoolean(this, k_initialized), false)
415420
416421
417422 func paused () = valueOrElse(getBoolean(this, k_paused), false)
418423
419424
420425 func closeOnly () = valueOrElse(getBoolean(this, k_closeOnly), false)
421426
422427
423428 func updateReserve (_isAdd,_quoteAssetAmount,_baseAssetAmount) = if (_isAdd)
424429 then {
425430 let newBase = (bsAstR() - _baseAssetAmount)
426431 if ((0 >= newBase))
427432 then throw("Tx lead to base asset reserve <= 0, revert")
428433 else $Tuple3((qtAstR() + _quoteAssetAmount), newBase, (totalPositionSize() + _baseAssetAmount))
429434 }
430435 else {
431436 let newQuote = (qtAstR() - _quoteAssetAmount)
432437 if ((0 >= newQuote))
433438 then throw("Tx lead to base quote reserve <= 0, revert")
434439 else $Tuple3(newQuote, (bsAstR() + _baseAssetAmount), (totalPositionSize() - _baseAssetAmount))
435440 }
436441
437442
438443 func calcInvariant (_qtAstR,_bsAstR) = {
439444 let bqtAstR = toBigInt(_qtAstR)
440445 let bbsAstR = toBigInt(_bsAstR)
441446 bmuld(bqtAstR, bbsAstR)
442447 }
443448
444449
445450 func swapInput (_isAdd,_quoteAssetAmount) = {
446451 let _qtAstR = qtAstR()
447452 let _bsAstR = bsAstR()
448453 let _qtAstW = qtAstW()
449454 let _bsAstW = bsAstW()
450455 let quoteAssetAmountAdjusted = divd(_quoteAssetAmount, _qtAstW)
451456 let k = calcInvariant(_qtAstR, _bsAstR)
452457 let quoteAssetReserveAfter = if (_isAdd)
453458 then (_qtAstR + quoteAssetAmountAdjusted)
454459 else (_qtAstR - quoteAssetAmountAdjusted)
455460 let baseAssetReserveAfter = toInt(bdivd(k, toBigInt(quoteAssetReserveAfter)))
456461 let amountBaseAssetBoughtAbs = abs((baseAssetReserveAfter - _bsAstR))
457462 let amountBaseAssetBought = if (_isAdd)
458463 then amountBaseAssetBoughtAbs
459464 else -(amountBaseAssetBoughtAbs)
460- let $t01636716537 = updateReserve(_isAdd, quoteAssetAmountAdjusted, amountBaseAssetBoughtAbs)
461- let quoteAssetReserveAfter1 = $t01636716537._1
462- let baseAssetReserveAfter1 = $t01636716537._2
463- let totalPositionSizeAfter1 = $t01636716537._3
465+ let $t01658516755 = updateReserve(_isAdd, quoteAssetAmountAdjusted, amountBaseAssetBoughtAbs)
466+ let quoteAssetReserveAfter1 = $t01658516755._1
467+ let baseAssetReserveAfter1 = $t01658516755._2
468+ let totalPositionSizeAfter1 = $t01658516755._3
464469 let priceBefore = divd(muld(_qtAstR, _qtAstW), muld(_bsAstR, _bsAstW))
465470 let marketPrice = divd(_quoteAssetAmount, amountBaseAssetBoughtAbs)
466471 let priceDiff = abs((priceBefore - marketPrice))
467472 let priceImpact = (DECIMAL_UNIT - divd(priceBefore, (priceBefore + priceDiff)))
468473 let maxPriceImpactValue = maxPriceImpact()
469474 if ((priceImpact > maxPriceImpactValue))
470475 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)))
471476 else $Tuple4(amountBaseAssetBought, quoteAssetReserveAfter1, baseAssetReserveAfter1, totalPositionSizeAfter1)
472477 }
473478
474479
475480 func calcRolloverFee (_oldPositionMargin,_oldPositionLastUpdatedTimestamp) = {
476481 let positionMinutes = ((((lastTimestamp() - _oldPositionLastUpdatedTimestamp) / 1000) / 60) * DECIMAL_UNIT)
477482 let rolloverFee = divd(muld(muld(_oldPositionMargin, positionMinutes), rolloverFeeRate()), MINUTES_IN_YEAR)
478483 rolloverFee
479484 }
480485
481486
482487 func calcRemainMarginWithFundingPaymentAndRolloverFee (_oldPositionSize,_oldPositionMargin,_oldPositionCumulativePremiumFraction,_oldPositionLastUpdatedTimestamp,_marginDelta) = {
483488 let fundingPayment = if ((_oldPositionSize != 0))
484489 then {
485490 let _latestCumulativePremiumFraction = latestCumulativePremiumFraction(_oldPositionSize)
486491 muld((_latestCumulativePremiumFraction - _oldPositionCumulativePremiumFraction), _oldPositionSize)
487492 }
488493 else 0
489494 let rolloverFee = calcRolloverFee(_oldPositionMargin, _oldPositionLastUpdatedTimestamp)
490495 let signedMargin = (((_marginDelta - rolloverFee) - fundingPayment) + _oldPositionMargin)
491- let $t01920419331 = if ((0 > signedMargin))
496+ let $t01942219549 = if ((0 > signedMargin))
492497 then $Tuple2(0, abs(signedMargin))
493498 else $Tuple2(abs(signedMargin), 0)
494- let remainMargin = $t01920419331._1
495- let badDebt = $t01920419331._2
499+ let remainMargin = $t01942219549._1
500+ let badDebt = $t01942219549._2
496501 $Tuple4(remainMargin, badDebt, fundingPayment, rolloverFee)
497502 }
498503
499504
500505 func swapOutputWithReserves (_isAdd,_baseAssetAmount,_checkMaxPriceImpact,_quoteAssetReserve,_quoteAssetWeight,_baseAssetReserve,_baseAssetWeight) = {
501506 let priceBefore = divd(muld(_quoteAssetReserve, _quoteAssetWeight), muld(_baseAssetReserve, _baseAssetWeight))
502507 if ((_baseAssetAmount == 0))
503508 then throw("Invalid base asset amount")
504509 else {
505510 let k = calcInvariant(_quoteAssetReserve, _baseAssetReserve)
506511 let baseAssetPoolAmountAfter = if (_isAdd)
507512 then (_baseAssetReserve + _baseAssetAmount)
508513 else (_baseAssetReserve - _baseAssetAmount)
509514 let quoteAssetAfter = toInt(bdivd(k, toBigInt(baseAssetPoolAmountAfter)))
510515 let quoteAssetDelta = abs((quoteAssetAfter - _quoteAssetReserve))
511516 let quoteAssetSold = muld(quoteAssetDelta, _quoteAssetWeight)
512517 let maxPriceImpactValue = maxPriceImpact()
513- let $t02059320755 = updateReserve(!(_isAdd), quoteAssetDelta, _baseAssetAmount)
514- let quoteAssetReserveAfter1 = $t02059320755._1
515- let baseAssetReserveAfter1 = $t02059320755._2
516- let totalPositionSizeAfter1 = $t02059320755._3
518+ let $t02081120973 = updateReserve(!(_isAdd), quoteAssetDelta, _baseAssetAmount)
519+ let quoteAssetReserveAfter1 = $t02081120973._1
520+ let baseAssetReserveAfter1 = $t02081120973._2
521+ let totalPositionSizeAfter1 = $t02081120973._3
517522 let marketPrice = divd(quoteAssetSold, _baseAssetAmount)
518523 let priceDiff = abs((priceBefore - marketPrice))
519524 let priceImpact = (DECIMAL_UNIT - divd(priceBefore, (priceBefore + priceDiff)))
520525 if (if ((priceImpact > maxPriceImpactValue))
521526 then _checkMaxPriceImpact
522527 else false)
523528 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)))
524529 else $Tuple7(quoteAssetSold, quoteAssetReserveAfter1, baseAssetReserveAfter1, totalPositionSizeAfter1, (totalLongPositionSize() - (if (_isAdd)
525530 then abs(_baseAssetAmount)
526531 else 0)), (totalShortPositionSize() - (if (!(_isAdd))
527532 then abs(_baseAssetAmount)
528533 else 0)), priceImpact)
529534 }
530535 }
531536
532537
533538 func swapOutput (_isAdd,_baseAssetAmount,_checkMaxPriceImpact) = swapOutputWithReserves(_isAdd, _baseAssetAmount, _checkMaxPriceImpact, qtAstR(), qtAstW(), bsAstR(), bsAstW())
534539
535540
536541 func getOraclePriceValue (oracle,priceKey,blockKey) = {
537542 let lastValue = valueOrErrorMessage(getInteger(oracle, priceKey), ((("Can not get oracle price. Oracle: " + toString(oracle)) + " key: ") + priceKey))
538543 if ((blockKey != ""))
539544 then {
540545 let currentBlock = height
541546 let lastOracleBlock = valueOrErrorMessage(getInteger(oracle, blockKey), ((("Can not get oracle block. Oracle: " + toString(oracle)) + " key: ") + blockKey))
542547 if (((currentBlock - lastOracleBlock) > maxOracleDelay()))
543548 then throw(((("Oracle stale data. Last oracle block: " + toString(lastOracleBlock)) + " current block: ") + toString(currentBlock)))
544549 else lastValue
545550 }
546551 else lastValue
547552 }
548553
549554
550555 func getOraclePrice () = {
551556 let baseOracle = valueOrErrorMessage(getOracleData(k_baseOracle), "No base asset oracle data")
552557 let baseOraclePrice = getOraclePriceValue(baseOracle._1, baseOracle._2, baseOracle._3)
553558 let quoteOracle = getOracleData(k_quoteOracle)
554559 let quoteOraclePrice = if (isDefined(quoteOracle))
555560 then {
556561 let quoteOracleV = value(quoteOracle)
557562 getOraclePriceValue(quoteOracleV._1, quoteOracleV._2, quoteOracleV._3)
558563 }
559564 else DECIMAL_UNIT
560565 divd(baseOraclePrice, quoteOraclePrice)
561566 }
562567
563568
564569 func isMarketClosed () = {
565570 let baseOracle = valueOrErrorMessage(getOracleData(k_baseOracle), "No base asset oracle data")
566571 let oracle = baseOracle._1
567572 let openKey = baseOracle._4
568573 if ((openKey != ""))
569574 then {
570575 let isOpen = valueOrErrorMessage(getBoolean(oracle, openKey), ((("Can not get oracle is open/closed. Oracle: " + toString(oracle)) + " key: ") + openKey))
571576 !(isOpen)
572577 }
573578 else false
574579 }
575580
576581
577582 func absPriceDiff (_oraclePrice,_quoteAssetReserve,_baseAssetReserve,_qtAstW,_bsAstW) = {
578583 let priceAfter = divd(muld(_quoteAssetReserve, _qtAstW), muld(_baseAssetReserve, _bsAstW))
579584 let averagePrice = divd((_oraclePrice + priceAfter), (2 * DECIMAL_UNIT))
580585 let absPriceDiff = divd(abs((_oraclePrice - priceAfter)), averagePrice)
581586 absPriceDiff
582587 }
583588
584589
585590 func requireNotOverSpreadLimit (_quoteAssetReserve,_baseAssetReserve) = {
586591 let oraclePrice = getOraclePrice()
587592 let _qtAstW = qtAstW()
588593 let _bsAstW = bsAstW()
589594 let absPriceDiffBefore = absPriceDiff(oraclePrice, qtAstR(), bsAstR(), _qtAstW, _bsAstW)
590595 let absPriceDiffAfter = absPriceDiff(oraclePrice, _quoteAssetReserve, _baseAssetReserve, _qtAstW, _bsAstW)
591596 if (if ((absPriceDiffAfter > maxPriceSpread()))
592597 then (absPriceDiffAfter > absPriceDiffBefore)
593598 else false)
594599 then throw(((("Price spread " + toString(absPriceDiffAfter)) + " > max price spread ") + toString(maxPriceSpread())))
595600 else true
596601 }
597602
598603
599604 func requireNotOverMaxOpenNotional (_longOpenNotional,_shortOpenNotional) = {
600605 let _maxOpenNotional = maxOpenNotional()
601606 if ((_longOpenNotional > _maxOpenNotional))
602607 then throw(((("Long open notional " + toString(_longOpenNotional)) + " > max open notional ") + toString(_maxOpenNotional)))
603608 else if ((_shortOpenNotional > _maxOpenNotional))
604609 then throw(((("Short open notional " + toString(_shortOpenNotional)) + " > max open notional ") + toString(_maxOpenNotional)))
605610 else true
606611 }
607612
608613
609614 func requireSenderCanWorkWithPositions (_caller) = if ((positionMode() == POSITION_ORDER))
610615 then (_caller == ordersAddress())
611616 else true
612617
613618
614619 func getSpotPrice () = {
615620 let _quoteAssetReserve = qtAstR()
616621 let _baseAssetReserve = bsAstR()
617622 let _qtAstW = qtAstW()
618623 let _bsAstW = bsAstW()
619624 divd(muld(_quoteAssetReserve, _qtAstW), muld(_baseAssetReserve, _bsAstW))
620625 }
621626
622627
623628 func isOverFluctuationLimit () = {
624629 let oraclePrice = getOraclePrice()
625630 let currentPrice = getSpotPrice()
626631 (divd(abs((oraclePrice - currentPrice)), oraclePrice) > spreadLimit())
627632 }
628633
629634
630635 func getPositionAdjustedOpenNotional (_positionSize,_option,_quoteAssetReserve,_quoteAssetWeight,_baseAssetReserve,_baseAssetWeight) = {
631636 let positionSizeAbs = abs(_positionSize)
632637 let isShort = (0 > _positionSize)
633638 let positionNotional = if ((_option == PNL_OPTION_SPOT))
634639 then {
635640 let outPositionNotional = swapOutputWithReserves(!(isShort), positionSizeAbs, false, _quoteAssetReserve, _quoteAssetWeight, _baseAssetReserve, _baseAssetWeight)._1
636641 outPositionNotional
637642 }
638643 else muld(positionSizeAbs, getOraclePrice())
639644 positionNotional
640645 }
641646
642647
643648 func getPositionNotionalAndUnrealizedPnlByValues (_positionSize,_positionOpenNotional,_quoteAssetReserve,_quoteAssetWeight,_baseAssetReserve,_baseAssetWeight,_option) = if ((_positionSize == 0))
644649 then throw("Invalid position size")
645650 else {
646651 let isShort = (0 > _positionSize)
647652 let positionNotional = getPositionAdjustedOpenNotional(_positionSize, _option, _quoteAssetReserve, _quoteAssetWeight, _baseAssetReserve, _baseAssetWeight)
648653 let unrealizedPnl = if (isShort)
649654 then (_positionOpenNotional - positionNotional)
650655 else (positionNotional - _positionOpenNotional)
651656 $Tuple2(positionNotional, unrealizedPnl)
652657 }
653658
654659
655660 func getPositionNotionalAndUnrealizedPnl (_trader,_direction,_option) = {
656- let $t02889629036 = getPosition(_trader, _direction)
657- let positionSize = $t02889629036._1
658- let positionMargin = $t02889629036._2
659- let positionOpenNotional = $t02889629036._3
660- let positionLstUpdCPF = $t02889629036._4
661+ let $t02911429254 = getPosition(_trader, _direction)
662+ let positionSize = $t02911429254._1
663+ let positionMargin = $t02911429254._2
664+ let positionOpenNotional = $t02911429254._3
665+ let positionLstUpdCPF = $t02911429254._4
661666 getPositionNotionalAndUnrealizedPnlByValues(positionSize, positionOpenNotional, qtAstR(), qtAstW(), bsAstR(), bsAstW(), _option)
662667 }
663668
664669
665670 func calcMarginRatio (_remainMargin,_badDebt,_positionNotional) = divd((_remainMargin - _badDebt), _positionNotional)
666671
667672
668673 func getMarginRatioByOption (_trader,_direction,_option) = {
669- let $t02956829721 = getPosition(_trader, _direction)
670- let positionSize = $t02956829721._1
671- let positionMargin = $t02956829721._2
672- let pon = $t02956829721._3
673- let positionLastUpdatedCPF = $t02956829721._4
674- let positionTimestamp = $t02956829721._5
675- let $t02972729832 = getPositionNotionalAndUnrealizedPnl(_trader, _direction, _option)
676- let positionNotional = $t02972729832._1
677- let unrealizedPnl = $t02972729832._2
678- let $t02983730049 = calcRemainMarginWithFundingPaymentAndRolloverFee(positionSize, positionMargin, positionLastUpdatedCPF, positionTimestamp, unrealizedPnl)
679- let remainMargin = $t02983730049._1
680- let badDebt = $t02983730049._2
674+ let $t02978629939 = getPosition(_trader, _direction)
675+ let positionSize = $t02978629939._1
676+ let positionMargin = $t02978629939._2
677+ let pon = $t02978629939._3
678+ let positionLastUpdatedCPF = $t02978629939._4
679+ let positionTimestamp = $t02978629939._5
680+ let $t02994530050 = getPositionNotionalAndUnrealizedPnl(_trader, _direction, _option)
681+ let positionNotional = $t02994530050._1
682+ let unrealizedPnl = $t02994530050._2
683+ let $t03005530267 = calcRemainMarginWithFundingPaymentAndRolloverFee(positionSize, positionMargin, positionLastUpdatedCPF, positionTimestamp, unrealizedPnl)
684+ let remainMargin = $t03005530267._1
685+ let badDebt = $t03005530267._2
681686 calcMarginRatio(remainMargin, badDebt, positionNotional)
682687 }
683688
684689
685690 func getMarginRatio (_trader,_direction) = getMarginRatioByOption(_trader, _direction, PNL_OPTION_SPOT)
686691
687692
688693 func getPartialLiquidationAmount (_trader,_positionSize) = {
689694 let maximumRatio = vmax(partialLiquidationRatio(), (DECIMAL_UNIT - divd(getMarginRatio(_trader, getDirection(_positionSize)), maintenanceMarginRatio())))
690695 let maxExchangedPositionSize = muld(abs(_positionSize), maximumRatio)
691696 let swapResult = swapOutput((_positionSize > 0), maxExchangedPositionSize, false)
692697 let maxExchangedQuoteAssetAmount = swapResult._1
693698 let priceImpact = swapResult._7
694699 if ((maxPriceImpact() > priceImpact))
695700 then maxExchangedPositionSize
696701 else muld(abs(_positionSize), partialLiquidationRatio())
697702 }
698703
699704
700705 func internalClosePosition (_trader,_direction,_size,_fee,_minQuoteAssetAmount,_addToMargin,_checkMaxPriceImpact,_liquidate) = {
701- let $t03121231380 = getPosition(_trader, _direction)
702- let oldPositionSize = $t03121231380._1
703- let oldPositionMargin = $t03121231380._2
704- let oldPositionOpenNotional = $t03121231380._3
705- let oldPositionLstUpdCPF = $t03121231380._4
706- let oldPositionTimestamp = $t03121231380._5
706+ let $t03143031598 = getPosition(_trader, _direction)
707+ let oldPositionSize = $t03143031598._1
708+ let oldPositionMargin = $t03143031598._2
709+ let oldPositionOpenNotional = $t03143031598._3
710+ let oldPositionLstUpdCPF = $t03143031598._4
711+ let oldPositionTimestamp = $t03143031598._5
707712 let isLongPosition = (oldPositionSize > 0)
708713 let absOldPositionSize = abs(oldPositionSize)
709714 if (if ((absOldPositionSize >= _size))
710715 then (_size > 0)
711716 else false)
712717 then {
713718 let isPartialClose = (absOldPositionSize > _size)
714- let $t03167232123 = swapOutput((oldPositionSize > 0), _size, _checkMaxPriceImpact)
715- let exchangedQuoteAssetAmount = $t03167232123._1
716- let quoteAssetReserveAfter = $t03167232123._2
717- let baseAssetReserveAfter = $t03167232123._3
718- let totalPositionSizeAfter = $t03167232123._4
719+ let $t03189032341 = swapOutput((oldPositionSize > 0), _size, _checkMaxPriceImpact)
720+ let exchangedQuoteAssetAmount = $t03189032341._1
721+ let quoteAssetReserveAfter = $t03189032341._2
722+ let baseAssetReserveAfter = $t03189032341._3
723+ let totalPositionSizeAfter = $t03189032341._4
719724 let exchangedPositionSize = if ((oldPositionSize > 0))
720725 then -(_size)
721726 else _size
722- let $t03233832562 = getPositionNotionalAndUnrealizedPnl(_trader, _direction, PNL_OPTION_SPOT)
723- let oldPositionNotional = $t03233832562._1
724- let unrealizedPnl = $t03233832562._2
727+ let $t03255632780 = getPositionNotionalAndUnrealizedPnl(_trader, _direction, PNL_OPTION_SPOT)
728+ let oldPositionNotional = $t03255632780._1
729+ let unrealizedPnl = $t03255632780._2
725730 let realizedRatio = divd(abs(exchangedPositionSize), absOldPositionSize)
726731 let realizedPnl = muld(unrealizedPnl, realizedRatio)
727- let $t03290333149 = calcRemainMarginWithFundingPaymentAndRolloverFee(oldPositionSize, oldPositionMargin, oldPositionLstUpdCPF, oldPositionTimestamp, unrealizedPnl)
728- let remainMarginBefore = $t03290333149._1
729- let x1 = $t03290333149._2
730- let x2 = $t03290333149._3
731- let rolloverFee = $t03290333149._4
732+ let $t03312133367 = calcRemainMarginWithFundingPaymentAndRolloverFee(oldPositionSize, oldPositionMargin, oldPositionLstUpdCPF, oldPositionTimestamp, unrealizedPnl)
733+ let remainMarginBefore = $t03312133367._1
734+ let x1 = $t03312133367._2
735+ let x2 = $t03312133367._3
736+ let rolloverFee = $t03312133367._4
732737 let positionBadDebt = calcRemainMarginWithFundingPaymentAndRolloverFee(oldPositionSize, oldPositionMargin, oldPositionLstUpdCPF, oldPositionTimestamp, realizedPnl)._2
733738 let realizedCloseFee = muld(muld(oldPositionNotional, realizedRatio), _fee)
734739 let unrealizedPnlAfter = (unrealizedPnl - realizedPnl)
735740 let remainOpenNotional = if ((oldPositionSize > 0))
736741 then ((oldPositionNotional - exchangedQuoteAssetAmount) - unrealizedPnlAfter)
737742 else ((unrealizedPnlAfter + oldPositionNotional) - exchangedQuoteAssetAmount)
738743 let newPositionSize = (oldPositionSize + exchangedPositionSize)
739- let $t03455534941 = if ((newPositionSize == 0))
744+ let $t03477335159 = if ((newPositionSize == 0))
740745 then $Tuple2(0, 0)
741746 else $Tuple2(abs(remainOpenNotional), latestCumulativePremiumFraction(newPositionSize))
742- let newPositionOpenNotional = $t03455534941._1
743- let newPositionLstUpdCPF = $t03455534941._2
747+ let newPositionOpenNotional = $t03477335159._1
748+ let newPositionLstUpdCPF = $t03477335159._2
744749 let openNotionalDelta = (oldPositionOpenNotional - newPositionOpenNotional)
745750 let marginRatio = getMarginRatioByOption(_trader, _direction, PNL_OPTION_SPOT)
746751 let newPositionMarginWithSameRatio = if ((oldPositionSize > 0))
747752 then (muld((newPositionOpenNotional + unrealizedPnlAfter), marginRatio) - unrealizedPnlAfter)
748753 else (muld((newPositionOpenNotional - unrealizedPnlAfter), marginRatio) - unrealizedPnlAfter)
749754 let marginToTraderRaw = ((remainMarginBefore - (newPositionMarginWithSameRatio + unrealizedPnlAfter)) - realizedCloseFee)
750755 let marginToTrader = if ((0 > marginToTraderRaw))
751756 then if (_liquidate)
752757 then 0
753758 else throw("Invalid internalClosePosition params: unable to pay fee")
754759 else marginToTraderRaw
755760 let newPositionMargin = if (_addToMargin)
756761 then (newPositionMarginWithSameRatio + marginToTrader)
757762 else newPositionMarginWithSameRatio
758763 if (if ((_minQuoteAssetAmount != 0))
759764 then (_minQuoteAssetAmount > exchangedQuoteAssetAmount)
760765 else false)
761766 then throw(((("Limit error: " + toString(exchangedQuoteAssetAmount)) + " < ") + toString(_minQuoteAssetAmount)))
762767 else $Tuple17(newPositionSize, newPositionMargin, newPositionOpenNotional, newPositionLstUpdCPF, positionBadDebt, realizedPnl, if (if (_addToMargin)
763768 then isPartialClose
764769 else false)
765770 then 0
766771 else marginToTrader, quoteAssetReserveAfter, baseAssetReserveAfter, totalPositionSizeAfter, (openInterestNotional() - openNotionalDelta), (totalLongPositionSize() - (if (isLongPosition)
767772 then abs(exchangedPositionSize)
768773 else 0)), (totalShortPositionSize() - (if (!(isLongPosition))
769774 then abs(exchangedPositionSize)
770775 else 0)), (openInterestLong() - (if (isLongPosition)
771776 then openNotionalDelta
772777 else 0)), (openInterestShort() - (if (!(isLongPosition))
773778 then openNotionalDelta
774779 else 0)), (realizedCloseFee + rolloverFee), exchangedQuoteAssetAmount)
775780 }
776781 else throw(((("Invalid internalClosePosition params: invalid position size: " + toString(_size)) + " max: ") + toString(absOldPositionSize)))
777782 }
778783
779784
780785 func getTerminalAmmState () = {
781786 let _positionSize = totalPositionSize()
782787 if ((_positionSize == 0))
783788 then $Tuple2(qtAstR(), bsAstR())
784789 else {
785790 let direction = (_positionSize > 0)
786- let $t03818838367 = swapOutput(direction, abs(_positionSize), false)
787- let currentNetMarketValue = $t03818838367._1
788- let terminalQuoteAssetReserve = $t03818838367._2
789- let terminalBaseAssetReserve = $t03818838367._3
791+ let $t03840638585 = swapOutput(direction, abs(_positionSize), false)
792+ let currentNetMarketValue = $t03840638585._1
793+ let terminalQuoteAssetReserve = $t03840638585._2
794+ let terminalBaseAssetReserve = $t03840638585._3
790795 $Tuple2(terminalQuoteAssetReserve, terminalBaseAssetReserve)
791796 }
792797 }
793798
794799
795800 func getQuoteAssetWeight (baseAssetReserve,totalPositionSize,quoteAssetReserve,targetPrice) = {
796801 let b = toBigInt(baseAssetReserve)
797802 let sz = toBigInt(totalPositionSize)
798803 let q = toBigInt(quoteAssetReserve)
799804 let p = toBigInt(targetPrice)
800805 let k = bmuld(q, b)
801806 let newB = (b + sz)
802807 let newQ = bdivd(k, newB)
803808 let z = bdivd(newQ, newB)
804809 let result = bdivd(p, z)
805810 toInt(result)
806811 }
807812
808813
809814 func getSyncTerminalPrice (_terminalPrice,_qtAstR,_bsAstR) = {
810815 let _positionSize = totalPositionSize()
811816 if ((_positionSize == 0))
812817 then {
813818 let newQtAstW = divd(muld(_terminalPrice, _bsAstR), _qtAstR)
814819 $Tuple3(newQtAstW, DECIMAL_UNIT, 0)
815820 }
816821 else {
817822 let direction = (_positionSize > 0)
818823 let currentNetMarketValue = swapOutput(direction, abs(_positionSize), false)._1
819824 let newQtAstW = getQuoteAssetWeight(_bsAstR, _positionSize, _qtAstR, _terminalPrice)
820825 let newBsAstW = DECIMAL_UNIT
821826 let marginToVault = getPositionNotionalAndUnrealizedPnlByValues(_positionSize, currentNetMarketValue, _qtAstR, newQtAstW, _bsAstR, newBsAstW, PNL_OPTION_SPOT)._2
822827 $Tuple3(newQtAstW, newBsAstW, marginToVault)
823828 }
824829 }
825830
826831
827832 func getFunding () = {
828833 let underlyingPrice = getOraclePrice()
829834 let spotPrice = getSpotPrice()
830835 let premium = (spotPrice - underlyingPrice)
831836 if (if (isMarketClosed())
832837 then true
833838 else if ((fundingMode() == FUNDING_ASYMMETRIC))
834839 then if ((totalShortPositionSize() == 0))
835840 then true
836841 else (totalLongPositionSize() == 0)
837842 else false)
838843 then $Tuple3(0, 0, 0)
839844 else if ((0 > premium))
840845 then {
841846 let shortPremiumFraction = divd(muld(premium, fundingPeriodDecimal()), ONE_DAY)
842847 if ((fundingMode() == FUNDING_ASYMMETRIC))
843848 then {
844849 let longPremiumFraction = divd(muld(shortPremiumFraction, totalShortPositionSize()), totalLongPositionSize())
845850 $Tuple3(shortPremiumFraction, longPremiumFraction, 0)
846851 }
847852 else {
848853 let shortTotalPremiumFraction = abs(muld(shortPremiumFraction, totalShortPositionSize()))
849854 let longTotalPremiumFraction = abs(muld(shortPremiumFraction, totalLongPositionSize()))
850855 let premiumToVault = (shortTotalPremiumFraction - longTotalPremiumFraction)
851856 $Tuple3(shortPremiumFraction, shortPremiumFraction, premiumToVault)
852857 }
853858 }
854859 else {
855860 let longPremiumFraction = divd(muld(premium, fundingPeriodDecimal()), ONE_DAY)
856861 if ((fundingMode() == FUNDING_ASYMMETRIC))
857862 then {
858863 let shortPremiumFraction = divd(muld(longPremiumFraction, totalLongPositionSize()), totalShortPositionSize())
859864 $Tuple3(shortPremiumFraction, longPremiumFraction, 0)
860865 }
861866 else {
862867 let longTotalPremiumFraction = abs(muld(longPremiumFraction, totalLongPositionSize()))
863868 let shortTotalPremiumFraction = abs(muld(longPremiumFraction, totalShortPositionSize()))
864869 let premiumToVault = (longTotalPremiumFraction - shortTotalPremiumFraction)
865870 $Tuple3(longPremiumFraction, longPremiumFraction, premiumToVault)
866871 }
867872 }
868873 }
869874
870875
871876 func getAdjustedFee (_artifactId,_baseFeeDiscount) = {
872877 let baseFeeRaw = fee()
873878 let baseFee = muld(baseFeeRaw, _baseFeeDiscount)
874- let $t04303143526 = if ((_artifactId != ""))
879+ let $t04324943744 = if ((_artifactId != ""))
875880 then {
876881 let artifactKind = strA(nftManagerAddress(), toCompositeKey(k_token_type, _artifactId))
877882 if ((artifactKind == FEE_REDUCTION_TOKEN_TYPE))
878883 then {
879884 let reduction = intA(nftManagerAddress(), toCompositeKey(k_token_param, _artifactId))
880885 let adjustedFee = muld(baseFee, reduction)
881886 $Tuple2(adjustedFee, true)
882887 }
883888 else throw("Invalid attached artifact")
884889 }
885890 else $Tuple2(baseFee, false)
886- let adjustedFee = $t04303143526._1
887- let burnArtifact = $t04303143526._2
891+ let adjustedFee = $t04324943744._1
892+ let burnArtifact = $t04324943744._2
888893 $Tuple2(adjustedFee, burnArtifact)
889894 }
890895
891896
892897 func getForTraderWithArtifact (_trader,_artifactId) = {
893898 let doGetFeeDiscount = invoke(minerAddress(), "computeFeeDiscount", [_trader], nil)
894899 if ((doGetFeeDiscount == doGetFeeDiscount))
895900 then {
896901 let feeDiscount = match doGetFeeDiscount {
897902 case x: Int =>
898903 x
899904 case _ =>
900905 throw("Invalid computeFeeDiscount result")
901906 }
902- let $t04387243946 = getAdjustedFee(_artifactId, feeDiscount)
903- let adjustedFee = $t04387243946._1
904- let burnArtifact = $t04387243946._2
907+ let $t04409044164 = getAdjustedFee(_artifactId, feeDiscount)
908+ let adjustedFee = $t04409044164._1
909+ let burnArtifact = $t04409044164._2
905910 $Tuple2(adjustedFee, burnArtifact)
906911 }
907912 else throw("Strict value is not equal to itself.")
908913 }
909914
910915
911916 func getArtifactId (i) = {
912917 let artifactId = if ((size(i.payments) > 1))
913918 then toBase58String(valueOrErrorMessage(i.payments[1].assetId, "Invalid artifactId"))
914919 else ""
915920 artifactId
916921 }
917922
918923
919924 func distributeFee (_feeAmount) = {
920925 let feeToStakers = muld(_feeAmount, feeToStakersPercent())
921926 let feeToVault = (_feeAmount - feeToStakers)
922927 $Tuple2(feeToStakers, feeToVault)
923928 }
924929
925930
926931 func updateSettings (_initMarginRatio,_mmr,_liquidationFeeRatio,_fundingPeriod,_fee,_spreadLimit,_maxPriceImpact,_partialLiquidationRatio,_maxPriceSpread,_maxOpenNotional,_feeToStakersPercent,_maxOracleDelay,_rolloverFee,_fundingMode,_oracleMode,_minInitMarginRatio,_positionMode) = [IntegerEntry(k_initMarginRatio, _initMarginRatio), IntegerEntry(k_minInitMarginRatio, _minInitMarginRatio), 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, _maxOracleDelay), IntegerEntry(k_rolloverFee, _rolloverFee), IntegerEntry(k_fundingMode, _fundingMode), IntegerEntry(k_oracleMode, _oracleMode), IntegerEntry(k_positionMode, _positionMode)]
927932
928933
929934 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)]
930935
931936
932937 func incrementPositionSequenceNumber (_isNewPosition,_trader,_direction) = {
933938 let positionKey = ((_trader + "_") + toString(_direction))
934939 if (_isNewPosition)
935940 then {
936941 let currentSequence = lastSequence()
937942 [IntegerEntry(toCompositeKey(k_positionSequence, positionKey), (currentSequence + 1)), IntegerEntry(k_sequence, (currentSequence + 1))]
938943 }
939944 else nil
940945 }
941946
942947
943948 func updatePositionFee (_isNewPosition,_trader,_direction,_fee) = {
944949 let positionKey = ((_trader + "_") + toString(_direction))
945950 if (_isNewPosition)
946951 then [IntegerEntry(toCompositeKey(k_positionFee, positionKey), _fee)]
947952 else nil
948953 }
949954
950955
951956 func updatePosition (_trader,_size,_margin,_openNotional,_latestCumulativePremiumFraction,_latestTimestamp) = {
952957 let direction = getDirection(_size)
953958 let positionKey = ((_trader + "_") + toString(direction))
954959 [IntegerEntry(toCompositeKey(k_positionSize, positionKey), _size), IntegerEntry(toCompositeKey(k_positionMargin, positionKey), _margin), IntegerEntry(toCompositeKey(k_positionOpenNotional, positionKey), _openNotional), IntegerEntry(toCompositeKey(k_positionLastUpdatedCumulativePremiumFraction, positionKey), _latestCumulativePremiumFraction), IntegerEntry(toCompositeKey(k_positionLastUpdatedTimestamp, positionKey), _latestTimestamp)]
955960 }
956961
957962
958963 func updateAmmReserves (_qtAstR,_bsAstR) = if (if ((0 > _qtAstR))
959964 then true
960965 else (0 > _bsAstR))
961966 then throw("Invalid amount to update reserves")
962967 else if (if ((_qtAstR != qtAstR0()))
963968 then true
964969 else (_bsAstR != bsAstR0()))
965970 then [IntegerEntry(k_quoteAssetReserve, _qtAstR), IntegerEntry(k_baseAssetReserve, _bsAstR)]
966971 else nil
967972
968973
969974 func updateAmmWeights (_qtAstW,_bsAstW) = if (if ((_qtAstW != qtAstW()))
970975 then true
971976 else (_bsAstW != bsAstW()))
972977 then [IntegerEntry(k_quoteAssetWeight, _qtAstW), IntegerEntry(k_baseAssetWeight, _bsAstW)]
973978 else nil
974979
975980
976981 func updateAmm (_qtAstR,_bsAstR,_totalPositionSizeAfter,_openInterestNotional,_totalLongPositionSize,_totalShortPositionSize,_totalLongOpenNotional,_totalShortOpenNotional) = {
977982 let _qtAstW = qtAstW()
978983 let _bsAstW = bsAstW()
979984 if (((_totalLongPositionSize - _totalShortPositionSize) != _totalPositionSizeAfter))
980985 then throw(((((("Invalid AMM state data: " + toString(_totalLongPositionSize)) + " - ") + toString(_totalShortPositionSize)) + " != ") + toString(_totalPositionSizeAfter)))
981986 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)])
982987 }
983988
984989
985990 func deletePosition (_trader,_direction) = {
986991 let positionKey = ((_trader + "_") + toString(_direction))
987992 [DeleteEntry(toCompositeKey(k_positionSize, positionKey)), DeleteEntry(toCompositeKey(k_positionMargin, positionKey)), DeleteEntry(toCompositeKey(k_positionOpenNotional, positionKey)), DeleteEntry(toCompositeKey(k_positionLastUpdatedCumulativePremiumFraction, positionKey)), DeleteEntry(toCompositeKey(k_positionFee, positionKey)), DeleteEntry(toCompositeKey(k_positionLastUpdatedTimestamp, positionKey))]
988993 }
989994
990995
991996 func withdraw (_address,_amount) = {
992997 let balance = assetBalance(this, quoteAsset())
993998 if ((_amount > balance))
994999 then throw(((("Unable to withdraw " + toString(_amount)) + " from contract balance ") + toString(balance)))
9951000 else [ScriptTransfer(_address, _amount, quoteAsset())]
9961001 }
9971002
9981003
9991004 func updateBalance (_balance) = if ((0 > _balance))
10001005 then throw("Balance")
10011006 else if (if ((cbalance0() == 0))
10021007 then true
10031008 else (cbalance0() != _balance))
10041009 then [IntegerEntry(k_balance, _balance)]
10051010 else nil
10061011
10071012
10081013 func transferFee (i) = [ScriptTransfer(stakingAddress(), i, quoteAsset())]
10091014
10101015
10111016 func doBurnArtifact (_burnArtifact,i) = if (_burnArtifact)
10121017 then [Burn(valueOrErrorMessage(i.payments[1].assetId, "Invalid artifact"), 1)]
10131018 else nil
10141019
10151020
10161021 @Callable(i)
10171022 func pause () = if ((i.caller != adminAddress()))
10181023 then throw("Invalid pause params")
10191024 else [BooleanEntry(k_paused, true)]
10201025
10211026
10221027
10231028 @Callable(i)
10241029 func unpause () = if ((i.caller != adminAddress()))
10251030 then throw("Invalid unpause params")
10261031 else [BooleanEntry(k_paused, false)]
10271032
10281033
10291034
10301035 @Callable(i)
10311036 func setCloseOnly () = if ((i.caller != adminAddress()))
10321037 then throw("Invalid setCloseOnly params")
10331038 else [BooleanEntry(k_closeOnly, true)]
10341039
10351040
10361041
10371042 @Callable(i)
10381043 func unsetCloseOnly () = if ((i.caller != adminAddress()))
10391044 then throw("Invalid unsetCloseOnly params")
10401045 else [BooleanEntry(k_closeOnly, false)]
10411046
10421047
10431048
10441049 @Callable(i)
10451050 func changeLiquidity (_quoteAssetAmount) = if (if ((i.caller != adminAddress()))
10461051 then true
10471052 else (_quoteAssetAmount == 0))
10481053 then throw("Invalid changeLiquidity params")
10491054 else {
10501055 let _qtAstR = qtAstR()
10511056 let _bsAstR = bsAstR()
10521057 let _qtAstW = qtAstW()
10531058 let _bsAstW = bsAstW()
10541059 let price = divd(muld(_qtAstR, _qtAstW), muld(_bsAstR, _bsAstW))
10551060 let qtAstRAfter = (_qtAstR + _quoteAssetAmount)
10561061 let baseAssetAmountToAdd = (divd(muld(qtAstRAfter, _qtAstW), price) - _bsAstR)
10571062 let bsAstRAfter = (_bsAstR + baseAssetAmountToAdd)
1058- let $t05283152982 = getSyncTerminalPrice(getOraclePrice(), qtAstRAfter, bsAstRAfter)
1059- let newQuoteAssetWeight = $t05283152982._1
1060- let newBaseAssetWeight = $t05283152982._2
1061- let marginToVault = $t05283152982._3
1063+ let $t05304953200 = getSyncTerminalPrice(getOraclePrice(), qtAstRAfter, bsAstRAfter)
1064+ let newQuoteAssetWeight = $t05304953200._1
1065+ let newBaseAssetWeight = $t05304953200._2
1066+ let marginToVault = $t05304953200._3
10621067 let doExchangePnL = if ((marginToVault != 0))
10631068 then {
10641069 let doExchangePnL = invoke(vaultAddress(), "exchangeFreeAndLocked", [marginToVault], nil)
10651070 if ((doExchangePnL == doExchangePnL))
10661071 then nil
10671072 else throw("Strict value is not equal to itself.")
10681073 }
10691074 else nil
10701075 if ((doExchangePnL == doExchangePnL))
10711076 then (updateAmmReserves(qtAstRAfter, bsAstRAfter) ++ updateAmmWeights(newQuoteAssetWeight, newBaseAssetWeight))
10721077 else throw("Strict value is not equal to itself.")
10731078 }
10741079
10751080
10761081
10771082 @Callable(i)
10781083 func changeSettings (_initMarginRatio,_mmr,_liquidationFeeRatio,_fundingPeriod,_fee,_spreadLimit,_maxPriceImpact,_partialLiquidationRatio,_maxPriceSpread,_maxOpenNotional,_feeToStakersPercent,_maxOracleDelay,_rolloverFee,_fundingMode,_oracleMode,_baseOracleData,_quoteOracleData,_minInitMarginRatio,_positionMode) = if (if (if (if (if (if (if (if (if (if (if (if (if (if (if (if (if (if (if (if (if (if (if ((0 >= _fundingPeriod))
10791084 then true
10801085 else (0 >= _initMarginRatio))
10811086 then true
10821087 else (_initMarginRatio > DECIMAL_UNIT))
10831088 then true
10841089 else (0 >= _minInitMarginRatio))
10851090 then true
10861091 else (_minInitMarginRatio > DECIMAL_UNIT))
10871092 then true
10881093 else (_initMarginRatio > _minInitMarginRatio))
10891094 then true
10901095 else (0 >= _mmr))
10911096 then true
10921097 else (0 >= _liquidationFeeRatio))
10931098 then true
10941099 else (0 >= _fee))
10951100 then true
10961101 else (0 >= _spreadLimit))
10971102 then true
10981103 else (0 >= _maxPriceImpact))
10991104 then true
11001105 else (0 >= _partialLiquidationRatio))
11011106 then true
11021107 else (0 >= _maxPriceSpread))
11031108 then true
11041109 else (0 >= _maxOpenNotional))
11051110 then true
11061111 else (0 >= _feeToStakersPercent))
11071112 then true
11081113 else (_feeToStakersPercent > DECIMAL_UNIT))
11091114 then true
11101115 else (0 > _maxOracleDelay))
11111116 then true
11121117 else (0 >= _rolloverFee))
11131118 then true
11141119 else if ((_fundingMode != FUNDING_SYMMETRIC))
11151120 then (_fundingMode != FUNDING_ASYMMETRIC)
11161121 else false)
11171122 then true
11181123 else if ((_oracleMode != ORACLE_PLAIN))
11191124 then (_oracleMode != ORACLE_JIT)
11201125 else false)
11211126 then true
11221127 else if ((_positionMode != POSITION_DIRECT))
11231128 then (_positionMode != POSITION_ORDER)
11241129 else false)
11251130 then true
11261131 else !(initialized()))
11271132 then true
11281133 else (i.caller != adminAddress()))
11291134 then throw("Invalid changeSettings params")
11301135 else (updateSettings(_initMarginRatio, _mmr, _liquidationFeeRatio, _fundingPeriod, _fee, _spreadLimit, _maxPriceImpact, _partialLiquidationRatio, _maxPriceSpread, _maxOpenNotional, _feeToStakersPercent, _maxOracleDelay, _rolloverFee, _fundingMode, _oracleMode, _minInitMarginRatio, _positionMode) ++ [StringEntry(k_baseOracle, _baseOracleData), StringEntry(k_quoteOracle, _quoteOracleData)])
11311136
11321137
11331138
11341139 @Callable(i)
11351140 func initialize (_qtAstR,_bsAstR,_fundingPeriod,_initMarginRatio,_mmr,_liquidationFeeRatio,_fee,_baseOracleData,_quoteOracleData,_coordinator,_spreadLimit,_maxPriceImpact,_partialLiquidationRatio,_maxPriceSpread,_maxOpenNotional,_feeToStakersPercent,_maxOracleDelay,_rolloverFee,_fundingMode,_oracleMode,_minInitMarginRatio,_positionMode) = if (if (if (if (if (if (if (if (if (if (if (if (if (if (if (if (if (if (if (if (if (if (if (if (if ((0 >= _qtAstR))
11361141 then true
11371142 else (0 >= _bsAstR))
11381143 then true
11391144 else (0 >= _fundingPeriod))
11401145 then true
11411146 else (0 >= _initMarginRatio))
11421147 then true
11431148 else (_initMarginRatio > DECIMAL_UNIT))
11441149 then true
11451150 else (0 >= _minInitMarginRatio))
11461151 then true
11471152 else (_minInitMarginRatio > DECIMAL_UNIT))
11481153 then true
11491154 else (_initMarginRatio > _minInitMarginRatio))
11501155 then true
11511156 else (0 >= _mmr))
11521157 then true
11531158 else (0 >= _liquidationFeeRatio))
11541159 then true
11551160 else (0 >= _fee))
11561161 then true
11571162 else (0 >= _spreadLimit))
11581163 then true
11591164 else (0 >= _maxPriceImpact))
11601165 then true
11611166 else (0 >= _partialLiquidationRatio))
11621167 then true
11631168 else (0 >= _maxPriceSpread))
11641169 then true
11651170 else (0 >= _maxOpenNotional))
11661171 then true
11671172 else (0 >= _feeToStakersPercent))
11681173 then true
11691174 else (_feeToStakersPercent > DECIMAL_UNIT))
11701175 then true
11711176 else (0 > _maxOracleDelay))
11721177 then true
11731178 else (0 >= _rolloverFee))
11741179 then true
11751180 else if ((_fundingMode != FUNDING_SYMMETRIC))
11761181 then (_fundingMode != FUNDING_ASYMMETRIC)
11771182 else false)
11781183 then true
11791184 else if ((_oracleMode != ORACLE_PLAIN))
11801185 then (_oracleMode != ORACLE_JIT)
11811186 else false)
11821187 then true
11831188 else if ((_positionMode != POSITION_DIRECT))
11841189 then (_positionMode != POSITION_ORDER)
11851190 else false)
11861191 then true
11871192 else initialized())
11881193 then true
11891194 else (i.caller != this))
11901195 then throw("Invalid initialize parameters")
11911196 else ((((updateAmm(_qtAstR, _bsAstR, 0, 0, 0, 0, 0, 0) ++ updateSettings(_initMarginRatio, _mmr, _liquidationFeeRatio, _fundingPeriod, _fee, _spreadLimit, _maxPriceImpact, _partialLiquidationRatio, _maxPriceSpread, _maxOpenNotional, _feeToStakersPercent, _maxOracleDelay, _rolloverFee, _fundingMode, _oracleMode, _minInitMarginRatio, _positionMode)) ++ updateFunding((lastTimestamp() + _fundingPeriod), 0, 0, 0, 0)) ++ updateBalance(0)) ++ [BooleanEntry(k_initialized, true), StringEntry(k_baseOracle, _baseOracleData), StringEntry(k_quoteOracle, _quoteOracleData), StringEntry(k_coordinatorAddress, toString(addressFromStringValue(_coordinator)))])
11921197
11931198
11941199
11951200 @Callable(i)
11961201 func increasePosition (_direction,_leverage,_minBaseAssetAmount,_refLink,_priceUpdate) = {
11971202 let updateOracle = invoke(this, "updateOracle", [_priceUpdate], nil)
11981203 if ((updateOracle == updateOracle))
11991204 then {
12001205 let sync = invoke(this, "syncTerminalPriceToOracle", nil, nil)
12011206 if ((sync == sync))
12021207 then {
12031208 let ensureCalledOnce = invoke(this, "ensureCalledOnce", nil, nil)
12041209 if ((ensureCalledOnce == ensureCalledOnce))
12051210 then {
12061211 let _trader = getActualCaller(i)
12071212 let _rawAmount = i.payments[0].amount
12081213 let _assetId = i.payments[0].assetId
12091214 let _assetIdStr = toBase58String(value(_assetId))
12101215 let isQuoteAsset = (_assetId == quoteAsset())
12111216 if (if (if (if (if (if (if (if (if (if (if ((_direction != DIR_LONG))
12121217 then (_direction != DIR_SHORT)
12131218 else false)
12141219 then true
12151220 else (0 >= _rawAmount))
12161221 then true
12171222 else !(initialized()))
12181223 then true
12191224 else !(isQuoteAsset))
12201225 then true
12211226 else !(requireMoreMarginRatio(divd(DECIMAL_UNIT, _leverage), initMarginRatio(), true)))
12221227 then true
12231228 else !(requireMoreMarginRatio(divd(DECIMAL_UNIT, _leverage), minInitMarginRatio(), false)))
12241229 then true
12251230 else !(requireSenderCanWorkWithPositions(i.caller)))
12261231 then true
12271232 else paused())
12281233 then true
12291234 else closeOnly())
12301235 then true
12311236 else isMarketClosed())
12321237 then throw("Invalid increasePosition parameters")
12331238 else {
1234- let $t06032160470 = getForTraderWithArtifact(_trader, getArtifactId(i))
1235- let adjustedFee = $t06032160470._1
1236- let burnArtifact = $t06032160470._2
1239+ let $t06053960688 = getForTraderWithArtifact(_trader, getArtifactId(i))
1240+ let adjustedFee = $t06053960688._1
1241+ let burnArtifact = $t06053960688._2
12371242 let _amount = divd(_rawAmount, (muld(adjustedFee, _leverage) + DECIMAL_UNIT))
12381243 let distributeFeeAmount = (_rawAmount - _amount)
12391244 let referrerFeeAny = invoke(referralAddress(), "acceptPaymentWithLink", [_trader, _refLink], [AttachedPayment(quoteAsset(), distributeFeeAmount)])
12401245 if ((referrerFeeAny == referrerFeeAny))
12411246 then {
12421247 let referrerFee = match referrerFeeAny {
12431248 case x: Int =>
12441249 x
12451250 case _ =>
12461251 throw("Invalid referrerFee")
12471252 }
12481253 let feeAmount = (distributeFeeAmount - referrerFee)
1249- let $t06096661146 = getPosition(_trader, _direction)
1250- let oldPositionSize = $t06096661146._1
1251- let oldPositionMargin = $t06096661146._2
1252- let oldPositionOpenNotional = $t06096661146._3
1253- let oldPositionLstUpdCPF = $t06096661146._4
1254- let oldPositionTimestamp = $t06096661146._5
1254+ let $t06118461364 = getPosition(_trader, _direction)
1255+ let oldPositionSize = $t06118461364._1
1256+ let oldPositionMargin = $t06118461364._2
1257+ let oldPositionOpenNotional = $t06118461364._3
1258+ let oldPositionLstUpdCPF = $t06118461364._4
1259+ let oldPositionTimestamp = $t06118461364._5
12551260 let isNewPosition = (oldPositionSize == 0)
12561261 let isSameDirection = if ((oldPositionSize > 0))
12571262 then (_direction == DIR_LONG)
12581263 else (_direction == DIR_SHORT)
12591264 let expandExisting = if (!(isNewPosition))
12601265 then isSameDirection
12611266 else false
12621267 let isAdd = (_direction == DIR_LONG)
1263- let $t06143564568 = if (if (isNewPosition)
1268+ let $t06165364786 = if (if (isNewPosition)
12641269 then true
12651270 else expandExisting)
12661271 then {
12671272 let openNotional = muld(_amount, _leverage)
1268- let $t06194462117 = swapInput(isAdd, openNotional)
1269- let amountBaseAssetBought = $t06194462117._1
1270- let quoteAssetReserveAfter = $t06194462117._2
1271- let baseAssetReserveAfter = $t06194462117._3
1272- let totalPositionSizeAfter = $t06194462117._4
1273+ let $t06216262335 = swapInput(isAdd, openNotional)
1274+ let amountBaseAssetBought = $t06216262335._1
1275+ let quoteAssetReserveAfter = $t06216262335._2
1276+ let baseAssetReserveAfter = $t06216262335._3
1277+ let totalPositionSizeAfter = $t06216262335._4
12731278 if (if ((_minBaseAssetAmount != 0))
12741279 then (_minBaseAssetAmount > abs(amountBaseAssetBought))
12751280 else false)
12761281 then throw(((("Limit error: " + toString(abs(amountBaseAssetBought))) + " < ") + toString(_minBaseAssetAmount)))
12771282 else {
12781283 let newPositionSize = (oldPositionSize + amountBaseAssetBought)
12791284 let totalLongOpenInterestAfter = (openInterestLong() + (if ((newPositionSize > 0))
12801285 then openNotional
12811286 else 0))
12821287 let totalShortOpenInterestAfter = (openInterestShort() + (if ((0 > newPositionSize))
12831288 then openNotional
12841289 else 0))
1285- let $t06266362938 = calcRemainMarginWithFundingPaymentAndRolloverFee(oldPositionSize, oldPositionMargin, oldPositionLstUpdCPF, oldPositionTimestamp, _amount)
1286- let remainMargin = $t06266362938._1
1287- let x1 = $t06266362938._2
1288- let x2 = $t06266362938._3
1289- let rolloverFee = $t06266362938._4
1290+ let $t06288163156 = calcRemainMarginWithFundingPaymentAndRolloverFee(oldPositionSize, oldPositionMargin, oldPositionLstUpdCPF, oldPositionTimestamp, _amount)
1291+ let remainMargin = $t06288163156._1
1292+ let x1 = $t06288163156._2
1293+ let x2 = $t06288163156._3
1294+ let rolloverFee = $t06288163156._4
12901295 if (!(requireNotOverSpreadLimit(quoteAssetReserveAfter, baseAssetReserveAfter)))
12911296 then throw("Over max spread limit")
12921297 else if (!(requireNotOverMaxOpenNotional(totalLongOpenInterestAfter, totalShortOpenInterestAfter)))
12931298 then throw("Over max open notional")
12941299 else $Tuple14(newPositionSize, remainMargin, (oldPositionOpenNotional + openNotional), latestCumulativePremiumFraction(newPositionSize), lastTimestamp(), baseAssetReserveAfter, quoteAssetReserveAfter, totalPositionSizeAfter, (openInterestNotional() + openNotional), (totalLongPositionSize() + (if ((newPositionSize > 0))
12951300 then abs(amountBaseAssetBought)
12961301 else 0)), (totalShortPositionSize() + (if ((0 > newPositionSize))
12971302 then abs(amountBaseAssetBought)
12981303 else 0)), totalLongOpenInterestAfter, totalShortOpenInterestAfter, rolloverFee)
12991304 }
13001305 }
13011306 else {
13021307 let openNotional = muld(_amount, _leverage)
1303- let $t06425664384 = getPositionNotionalAndUnrealizedPnl(toString(i.caller), _direction, PNL_OPTION_SPOT)
1304- let oldPositionNotional = $t06425664384._1
1305- let unrealizedPnl = $t06425664384._2
1308+ let $t06447464602 = getPositionNotionalAndUnrealizedPnl(toString(i.caller), _direction, PNL_OPTION_SPOT)
1309+ let oldPositionNotional = $t06447464602._1
1310+ let unrealizedPnl = $t06447464602._2
13061311 if ((oldPositionNotional > openNotional))
13071312 then throw("Use decreasePosition to decrease position size")
13081313 else throw("Close position first")
13091314 }
1310- let newPositionSize = $t06143564568._1
1311- let newPositionRemainMargin = $t06143564568._2
1312- let newPositionOpenNotional = $t06143564568._3
1313- let newPositionLatestCPF = $t06143564568._4
1314- let newPositionTimestamp = $t06143564568._5
1315- let baseAssetReserveAfter = $t06143564568._6
1316- let quoteAssetReserveAfter = $t06143564568._7
1317- let totalPositionSizeAfter = $t06143564568._8
1318- let openInterestNotionalAfter = $t06143564568._9
1319- let totalLongAfter = $t06143564568._10
1320- let totalShortAfter = $t06143564568._11
1321- let totalLongOpenInterestAfter = $t06143564568._12
1322- let totalShortOpenInterestAfter = $t06143564568._13
1323- let rolloverFee = $t06143564568._14
1324- let $t06457464645 = distributeFee((feeAmount + rolloverFee))
1325- let feeToStakers = $t06457464645._1
1326- let feeToVault = $t06457464645._2
1315+ let newPositionSize = $t06165364786._1
1316+ let newPositionRemainMargin = $t06165364786._2
1317+ let newPositionOpenNotional = $t06165364786._3
1318+ let newPositionLatestCPF = $t06165364786._4
1319+ let newPositionTimestamp = $t06165364786._5
1320+ let baseAssetReserveAfter = $t06165364786._6
1321+ let quoteAssetReserveAfter = $t06165364786._7
1322+ let totalPositionSizeAfter = $t06165364786._8
1323+ let openInterestNotionalAfter = $t06165364786._9
1324+ let totalLongAfter = $t06165364786._10
1325+ let totalShortAfter = $t06165364786._11
1326+ let totalLongOpenInterestAfter = $t06165364786._12
1327+ let totalShortOpenInterestAfter = $t06165364786._13
1328+ let rolloverFee = $t06165364786._14
1329+ let $t06479264863 = distributeFee((feeAmount + rolloverFee))
1330+ let feeToStakers = $t06479264863._1
1331+ let feeToVault = $t06479264863._2
13271332 let stake = if ((_amount >= rolloverFee))
13281333 then invoke(vaultAddress(), "addLocked", nil, [AttachedPayment(quoteAsset(), (_amount - rolloverFee))])
13291334 else invoke(vaultAddress(), "withdrawLocked", [(rolloverFee - _amount)], nil)
13301335 if ((stake == stake))
13311336 then {
13321337 let depositVault = invoke(vaultAddress(), "addFree", nil, [AttachedPayment(quoteAsset(), feeToVault)])
13331338 if ((depositVault == depositVault))
13341339 then {
13351340 let notifyFee = invoke(minerAddress(), "notifyFees", [_trader, feeAmount], nil)
13361341 if ((notifyFee == notifyFee))
13371342 then {
13381343 let notifyNotional = invoke(minerAddress(), "notifyNotional", [_trader, newPositionOpenNotional], nil)
13391344 if ((notifyNotional == notifyNotional))
13401345 then ((((((updatePosition(_trader, newPositionSize, newPositionRemainMargin, newPositionOpenNotional, newPositionLatestCPF, newPositionTimestamp) ++ incrementPositionSequenceNumber(isNewPosition, _trader, _direction)) ++ updatePositionFee(isNewPosition, _trader, _direction, adjustedFee)) ++ updateAmm(quoteAssetReserveAfter, baseAssetReserveAfter, totalPositionSizeAfter, openInterestNotionalAfter, totalLongAfter, totalShortAfter, totalLongOpenInterestAfter, totalShortOpenInterestAfter)) ++ transferFee(feeToStakers)) ++ updateBalance(((cbalance() + _amount) - rolloverFee))) ++ doBurnArtifact(burnArtifact, i))
13411346 else throw("Strict value is not equal to itself.")
13421347 }
13431348 else throw("Strict value is not equal to itself.")
13441349 }
13451350 else throw("Strict value is not equal to itself.")
13461351 }
13471352 else throw("Strict value is not equal to itself.")
13481353 }
13491354 else throw("Strict value is not equal to itself.")
13501355 }
13511356 }
13521357 else throw("Strict value is not equal to itself.")
13531358 }
13541359 else throw("Strict value is not equal to itself.")
13551360 }
13561361 else throw("Strict value is not equal to itself.")
13571362 }
13581363
13591364
13601365
13611366 @Callable(i)
13621367 func addMargin (_direction,_priceUpdate) = {
13631368 let updateOracle = invoke(this, "updateOracle", [_priceUpdate], nil)
13641369 if ((updateOracle == updateOracle))
13651370 then {
13661371 let sync = invoke(this, "syncTerminalPriceToOracle", nil, nil)
13671372 if ((sync == sync))
13681373 then {
13691374 let ensureCalledOnce = invoke(this, "ensureCalledOnce", nil, nil)
13701375 if ((ensureCalledOnce == ensureCalledOnce))
13711376 then {
13721377 let _trader = toString(i.caller)
13731378 let _amount = i.payments[0].amount
13741379 let _assetId = i.payments[0].assetId
13751380 let _assetIdStr = toBase58String(value(_assetId))
13761381 let isQuoteAsset = (_assetId == quoteAsset())
13771382 if (if (if (if (if (!(isQuoteAsset))
13781383 then true
13791384 else !(requireOpenPosition(toString(i.caller), _direction)))
13801385 then true
13811386 else !(initialized()))
13821387 then true
13831388 else paused())
13841389 then true
13851390 else isMarketClosed())
13861391 then throw("Invalid addMargin parameters")
13871392 else {
1388- let $t06698767167 = getPosition(_trader, _direction)
1389- let oldPositionSize = $t06698767167._1
1390- let oldPositionMargin = $t06698767167._2
1391- let oldPositionOpenNotional = $t06698767167._3
1392- let oldPositionLstUpdCPF = $t06698767167._4
1393- let oldPositionTimestamp = $t06698767167._5
1393+ let $t06720567385 = getPosition(_trader, _direction)
1394+ let oldPositionSize = $t06720567385._1
1395+ let oldPositionMargin = $t06720567385._2
1396+ let oldPositionOpenNotional = $t06720567385._3
1397+ let oldPositionLstUpdCPF = $t06720567385._4
1398+ let oldPositionTimestamp = $t06720567385._5
13941399 let stake = invoke(vaultAddress(), "addLocked", nil, [AttachedPayment(quoteAsset(), _amount)])
13951400 if ((stake == stake))
13961401 then {
1397- let $t06730767533 = calcRemainMarginWithFundingPaymentAndRolloverFee(oldPositionSize, oldPositionMargin, oldPositionLstUpdCPF, oldPositionTimestamp, _amount)
1398- let remainMargin = $t06730767533._1
1399- let badDebt = $t06730767533._2
1400- let rolloverFee = $t06730767533._3
1402+ let $t06752567751 = calcRemainMarginWithFundingPaymentAndRolloverFee(oldPositionSize, oldPositionMargin, oldPositionLstUpdCPF, oldPositionTimestamp, _amount)
1403+ let remainMargin = $t06752567751._1
1404+ let badDebt = $t06752567751._2
1405+ let rolloverFee = $t06752567751._3
14011406 let marginRatio = calcMarginRatio(remainMargin, badDebt, oldPositionOpenNotional)
14021407 let checkMinMargin = requireMoreMarginRatio(marginRatio, minInitMarginRatio(), false)
14031408 if ((checkMinMargin == checkMinMargin))
14041409 then {
14051410 let doTransferFeeToStakers = if ((rolloverFee > 0))
14061411 then {
1407- let $t06778967848 = distributeFee(rolloverFee)
1408- let feeToStakers = $t06778967848._1
1409- let feeToVault = $t06778967848._2
1412+ let $t06800768066 = distributeFee(rolloverFee)
1413+ let feeToStakers = $t06800768066._1
1414+ let feeToVault = $t06800768066._2
14101415 let unstake = invoke(vaultAddress(), "withdrawLocked", [feeToStakers], nil)
14111416 if ((unstake == unstake))
14121417 then {
14131418 let lockBadDebt = invoke(vaultAddress(), "exchangeFreeAndLocked", [-(feeToVault)], nil)
14141419 if ((lockBadDebt == lockBadDebt))
14151420 then transferFee(feeToStakers)
14161421 else throw("Strict value is not equal to itself.")
14171422 }
14181423 else throw("Strict value is not equal to itself.")
14191424 }
14201425 else nil
14211426 if ((doTransferFeeToStakers == doTransferFeeToStakers))
14221427 then ((updatePosition(_trader, oldPositionSize, ((oldPositionMargin - rolloverFee) + _amount), oldPositionOpenNotional, oldPositionLstUpdCPF, lastTimestamp()) ++ updateBalance(((cbalance() + _amount) - rolloverFee))) ++ doTransferFeeToStakers)
14231428 else throw("Strict value is not equal to itself.")
14241429 }
14251430 else throw("Strict value is not equal to itself.")
14261431 }
14271432 else throw("Strict value is not equal to itself.")
14281433 }
14291434 }
14301435 else throw("Strict value is not equal to itself.")
14311436 }
14321437 else throw("Strict value is not equal to itself.")
14331438 }
14341439 else throw("Strict value is not equal to itself.")
14351440 }
14361441
14371442
14381443
14391444 @Callable(i)
14401445 func removeMargin (_amount,_direction,_priceUpdate) = {
14411446 let updateOracle = invoke(this, "updateOracle", [_priceUpdate], nil)
14421447 if ((updateOracle == updateOracle))
14431448 then {
14441449 let sync = invoke(this, "syncTerminalPriceToOracle", nil, nil)
14451450 if ((sync == sync))
14461451 then {
14471452 let ensureCalledOnce = invoke(this, "ensureCalledOnce", nil, nil)
14481453 if ((ensureCalledOnce == ensureCalledOnce))
14491454 then {
14501455 let _trader = toString(i.caller)
14511456 if (if (if (if (if ((0 >= _amount))
14521457 then true
14531458 else !(requireOpenPosition(_trader, _direction)))
14541459 then true
14551460 else !(initialized()))
14561461 then true
14571462 else paused())
14581463 then true
14591464 else isMarketClosed())
14601465 then throw("Invalid removeMargin parameters")
14611466 else {
1462- let $t06934969529 = getPosition(_trader, _direction)
1463- let oldPositionSize = $t06934969529._1
1464- let oldPositionMargin = $t06934969529._2
1465- let oldPositionOpenNotional = $t06934969529._3
1466- let oldPositionLstUpdCPF = $t06934969529._4
1467- let oldPositionTimestamp = $t06934969529._5
1468- let $t06953569784 = calcRemainMarginWithFundingPaymentAndRolloverFee(oldPositionSize, oldPositionMargin, oldPositionLstUpdCPF, oldPositionTimestamp, -(_amount))
1469- let remainMargin = $t06953569784._1
1470- let badDebt = $t06953569784._2
1471- let fundingPayment = $t06953569784._3
1472- let rolloverFee = $t06953569784._4
1467+ let $t06956769747 = getPosition(_trader, _direction)
1468+ let oldPositionSize = $t06956769747._1
1469+ let oldPositionMargin = $t06956769747._2
1470+ let oldPositionOpenNotional = $t06956769747._3
1471+ let oldPositionLstUpdCPF = $t06956769747._4
1472+ let oldPositionTimestamp = $t06956769747._5
1473+ let $t06975370002 = calcRemainMarginWithFundingPaymentAndRolloverFee(oldPositionSize, oldPositionMargin, oldPositionLstUpdCPF, oldPositionTimestamp, -(_amount))
1474+ let remainMargin = $t06975370002._1
1475+ let badDebt = $t06975370002._2
1476+ let fundingPayment = $t06975370002._3
1477+ let rolloverFee = $t06975370002._4
14731478 if ((badDebt != 0))
14741479 then throw("Invalid removed margin amount")
14751480 else {
14761481 let marginRatio = calcMarginRatio(remainMargin, badDebt, oldPositionOpenNotional)
14771482 if (!(requireMoreMarginRatio(marginRatio, initMarginRatio(), true)))
14781483 then throw(((("Too much margin removed: " + toString(marginRatio)) + " < ") + toString(initMarginRatio())))
14791484 else {
1480- let $t07017070229 = distributeFee(rolloverFee)
1481- let feeToStakers = $t07017070229._1
1482- let feeToVault = $t07017070229._2
1485+ let $t07038870447 = distributeFee(rolloverFee)
1486+ let feeToStakers = $t07038870447._1
1487+ let feeToVault = $t07038870447._2
14831488 let doTransferFeeToStakers = if ((rolloverFee > 0))
14841489 then {
14851490 let lockBadDebt = invoke(vaultAddress(), "exchangeFreeAndLocked", [-(feeToVault)], nil)
14861491 if ((lockBadDebt == lockBadDebt))
14871492 then transferFee(feeToStakers)
14881493 else throw("Strict value is not equal to itself.")
14891494 }
14901495 else nil
14911496 if ((doTransferFeeToStakers == doTransferFeeToStakers))
14921497 then {
14931498 let unstake = invoke(vaultAddress(), "withdrawLocked", [(_amount + feeToStakers)], nil)
14941499 if ((unstake == unstake))
14951500 then (((updatePosition(_trader, oldPositionSize, remainMargin, oldPositionOpenNotional, latestCumulativePremiumFraction(oldPositionSize), lastTimestamp()) ++ withdraw(i.caller, _amount)) ++ updateBalance(((cbalance() - _amount) - rolloverFee))) ++ doTransferFeeToStakers)
14961501 else throw("Strict value is not equal to itself.")
14971502 }
14981503 else throw("Strict value is not equal to itself.")
14991504 }
15001505 }
15011506 }
15021507 }
15031508 else throw("Strict value is not equal to itself.")
15041509 }
15051510 else throw("Strict value is not equal to itself.")
15061511 }
15071512 else throw("Strict value is not equal to itself.")
15081513 }
15091514
15101515
15111516
15121517 @Callable(i)
15131518 func closePosition (_size,_direction,_minQuoteAssetAmount,_addToMargin,_priceUpdate) = {
15141519 let updateOracle = invoke(this, "updateOracle", [_priceUpdate], nil)
15151520 if ((updateOracle == updateOracle))
15161521 then {
15171522 let sync = invoke(this, "syncTerminalPriceToOracle", nil, nil)
15181523 if ((sync == sync))
15191524 then {
15201525 let ensureCalledOnce = invoke(this, "ensureCalledOnce", nil, nil)
15211526 if ((ensureCalledOnce == ensureCalledOnce))
15221527 then {
15231528 let _trader = getActualCaller(i)
15241529 let _traderAddress = valueOrErrorMessage(addressFromString(_trader), "Invalid caller")
15251530 let positionFee = getPositionFee(_trader, _direction)
15261531 if (if (if (if (if (if (!(requireOpenPosition(_trader, _direction)))
15271532 then true
15281533 else !(initialized()))
15291534 then true
15301535 else paused())
15311536 then true
15321537 else (0 >= _size))
15331538 then true
15341539 else (0 > _minQuoteAssetAmount))
15351540 then true
15361541 else isMarketClosed())
15371542 then throw("Invalid closePosition parameters")
15381543 else {
15391544 let oldPositionTimestamp = getPosition(_trader, _direction)._5
1540- let $t07256473167 = internalClosePosition(_trader, _direction, _size, positionFee, _minQuoteAssetAmount, _addToMargin, true, true)
1541- let newPositionSize = $t07256473167._1
1542- let newPositionMargin = $t07256473167._2
1543- let newPositionOpenNotional = $t07256473167._3
1544- let newPositionLstUpdCPF = $t07256473167._4
1545- let positionBadDebt = $t07256473167._5
1546- let realizedPnl = $t07256473167._6
1547- let marginToTrader = $t07256473167._7
1548- let quoteAssetReserveAfter = $t07256473167._8
1549- let baseAssetReserveAfter = $t07256473167._9
1550- let totalPositionSizeAfter = $t07256473167._10
1551- let openInterestNotionalAfter = $t07256473167._11
1552- let totalLongAfter = $t07256473167._12
1553- let totalShortAfter = $t07256473167._13
1554- let totalLongOpenInterestAfter = $t07256473167._14
1555- let totalShortOpenInterestAfter = $t07256473167._15
1556- let realizedFee = $t07256473167._16
1545+ let $t07278273385 = internalClosePosition(_trader, _direction, _size, positionFee, _minQuoteAssetAmount, _addToMargin, true, true)
1546+ let newPositionSize = $t07278273385._1
1547+ let newPositionMargin = $t07278273385._2
1548+ let newPositionOpenNotional = $t07278273385._3
1549+ let newPositionLstUpdCPF = $t07278273385._4
1550+ let positionBadDebt = $t07278273385._5
1551+ let realizedPnl = $t07278273385._6
1552+ let marginToTrader = $t07278273385._7
1553+ let quoteAssetReserveAfter = $t07278273385._8
1554+ let baseAssetReserveAfter = $t07278273385._9
1555+ let totalPositionSizeAfter = $t07278273385._10
1556+ let openInterestNotionalAfter = $t07278273385._11
1557+ let totalLongAfter = $t07278273385._12
1558+ let totalShortAfter = $t07278273385._13
1559+ let totalLongOpenInterestAfter = $t07278273385._14
1560+ let totalShortOpenInterestAfter = $t07278273385._15
1561+ let realizedFee = $t07278273385._16
15571562 if ((positionBadDebt > 0))
15581563 then throw("Invalid closePosition parameters: bad debt")
15591564 else if ((oldPositionTimestamp >= lastTimestamp()))
15601565 then throw("Invalid closePosition parameters: wait at least 1 block before closing the position")
15611566 else {
15621567 let isPartialClose = (newPositionSize != 0)
15631568 let withdrawAmount = (marginToTrader + realizedFee)
15641569 let ammBalance = (cbalance() - withdrawAmount)
15651570 let ammNewBalance = if ((0 > ammBalance))
15661571 then 0
15671572 else ammBalance
15681573 let unstake = invoke(vaultAddress(), "withdrawLocked", [withdrawAmount], nil)
15691574 if ((unstake == unstake))
15701575 then {
15711576 let referrerFeeAny = invoke(referralAddress(), "acceptPayment", [_trader], [AttachedPayment(quoteAsset(), realizedFee)])
15721577 if ((referrerFeeAny == referrerFeeAny))
15731578 then {
15741579 let referrerFee = match referrerFeeAny {
15751580 case x: Int =>
15761581 x
15771582 case _ =>
15781583 throw("Invalid referrerFee")
15791584 }
1580- let $t07413974212 = distributeFee((realizedFee - referrerFee))
1581- let feeToStakers = $t07413974212._1
1582- let feeToVault = $t07413974212._2
1585+ let $t07435774430 = distributeFee((realizedFee - referrerFee))
1586+ let feeToStakers = $t07435774430._1
1587+ let feeToVault = $t07435774430._2
15831588 let depositVault = invoke(vaultAddress(), "addFree", nil, [AttachedPayment(quoteAsset(), feeToVault)])
15841589 if ((depositVault == depositVault))
15851590 then {
15861591 let notifyFee = invoke(minerAddress(), "notifyFees", [_trader, realizedFee], nil)
15871592 if ((notifyFee == notifyFee))
15881593 then {
15891594 let notifyNotional = invoke(minerAddress(), "notifyNotional", [_trader, newPositionOpenNotional], nil)
15901595 if ((notifyNotional == notifyNotional))
15911596 then (((((if (isPartialClose)
15921597 then updatePosition(_trader, newPositionSize, newPositionMargin, newPositionOpenNotional, newPositionLstUpdCPF, lastTimestamp())
15931598 else deletePosition(_trader, _direction)) ++ updateAmm(quoteAssetReserveAfter, baseAssetReserveAfter, totalPositionSizeAfter, openInterestNotionalAfter, totalLongAfter, totalShortAfter, totalLongOpenInterestAfter, totalShortOpenInterestAfter)) ++ (if ((marginToTrader > 0))
15941599 then withdraw(_traderAddress, marginToTrader)
15951600 else nil)) ++ updateBalance(ammNewBalance)) ++ transferFee(feeToStakers))
15961601 else throw("Strict value is not equal to itself.")
15971602 }
15981603 else throw("Strict value is not equal to itself.")
15991604 }
16001605 else throw("Strict value is not equal to itself.")
16011606 }
16021607 else throw("Strict value is not equal to itself.")
16031608 }
16041609 else throw("Strict value is not equal to itself.")
16051610 }
16061611 }
16071612 }
16081613 else throw("Strict value is not equal to itself.")
16091614 }
16101615 else throw("Strict value is not equal to itself.")
16111616 }
16121617 else throw("Strict value is not equal to itself.")
16131618 }
16141619
16151620
16161621
16171622 @Callable(i)
16181623 func liquidate (_trader,_direction,_priceUpdate) = {
16191624 let updateOracle = invoke(this, "updateOracle", [_priceUpdate], nil)
16201625 if ((updateOracle == updateOracle))
16211626 then {
16221627 let sync = invoke(this, "syncTerminalPriceToOracle", nil, nil)
16231628 if ((sync == sync))
16241629 then {
16251630 let spotMarginRatio = getMarginRatioByOption(_trader, _direction, PNL_OPTION_SPOT)
16261631 let liquidationMarginRatio = if (isOverFluctuationLimit())
16271632 then {
16281633 let oracleMarginRatio = getMarginRatioByOption(_trader, _direction, PNL_OPTION_ORACLE)
16291634 vmax(spotMarginRatio, oracleMarginRatio)
16301635 }
16311636 else spotMarginRatio
16321637 if (if (if (if (if (!(requireMoreMarginRatio(liquidationMarginRatio, maintenanceMarginRatio(), false)))
16331638 then true
16341639 else !(requireOpenPosition(_trader, _direction)))
16351640 then true
16361641 else !(initialized()))
16371642 then true
16381643 else paused())
16391644 then true
16401645 else isMarketClosed())
16411646 then throw("Unable to liquidate")
16421647 else {
1643- let isPartialLiquidation = if (if ((spotMarginRatio > liquidationFeeRatio()))
1648+ let oldPositionSize = getPosition(_trader, _direction)._1
1649+ let positionSizeAbs = abs(oldPositionSize)
1650+ let isPartialLiquidation = if (if (if ((spotMarginRatio > liquidationFeeRatio()))
16441651 then (partialLiquidationRatio() > 0)
16451652 else false)
16461653 then (DECIMAL_UNIT > partialLiquidationRatio())
1654+ else false)
1655+ then (muld(positionSizeAbs, getSpotPrice()) > minPartialLiquidationNotional())
16471656 else false
1648- let oldPositionSize = getPosition(_trader, _direction)._1
1649- let positionSizeAbs = abs(oldPositionSize)
1650- let $t07680577128 = if (isPartialLiquidation)
1657+ let $t07710477491 = if (isPartialLiquidation)
16511658 then {
1652- let liquidationSize = getPartialLiquidationAmount(_trader, oldPositionSize)
1653- let liquidationRatio = divd(abs(liquidationSize), positionSizeAbs)
1654- $Tuple2(liquidationRatio, abs(liquidationSize))
1659+ let liquidationSize = abs(getPartialLiquidationAmount(_trader, oldPositionSize))
1660+ let liquidationRatio = divd(liquidationSize, positionSizeAbs)
1661+ let liquidationNotional = muld(liquidationSize, getSpotPrice())
1662+ $Tuple2(liquidationRatio, liquidationSize)
16551663 }
16561664 else $Tuple2(0, positionSizeAbs)
1657- let liquidationRatio = $t07680577128._1
1658- let liquidationSize = $t07680577128._2
1659- let $t07713477790 = internalClosePosition(_trader, _direction, if (isPartialLiquidation)
1665+ let liquidationRatio = $t07710477491._1
1666+ let liquidationSize = $t07710477491._2
1667+ let $t07749778153 = internalClosePosition(_trader, _direction, if (isPartialLiquidation)
16601668 then liquidationSize
16611669 else positionSizeAbs, liquidationFeeRatio(), 0, true, false, true)
1662- let newPositionSize = $t07713477790._1
1663- let newPositionMargin = $t07713477790._2
1664- let newPositionOpenNotional = $t07713477790._3
1665- let newPositionLstUpdCPF = $t07713477790._4
1666- let positionBadDebt = $t07713477790._5
1667- let realizedPnl = $t07713477790._6
1668- let marginToTrader = $t07713477790._7
1669- let quoteAssetReserveAfter = $t07713477790._8
1670- let baseAssetReserveAfter = $t07713477790._9
1671- let totalPositionSizeAfter = $t07713477790._10
1672- let openInterestNotionalAfter = $t07713477790._11
1673- let totalLongAfter = $t07713477790._12
1674- let totalShortAfter = $t07713477790._13
1675- let totalLongOpenInterestAfter = $t07713477790._14
1676- let totalShortOpenInterestAfter = $t07713477790._15
1677- let liquidationPenalty = $t07713477790._16
1670+ let newPositionSize = $t07749778153._1
1671+ let newPositionMargin = $t07749778153._2
1672+ let newPositionOpenNotional = $t07749778153._3
1673+ let newPositionLstUpdCPF = $t07749778153._4
1674+ let positionBadDebt = $t07749778153._5
1675+ let realizedPnl = $t07749778153._6
1676+ let marginToTrader = $t07749778153._7
1677+ let quoteAssetReserveAfter = $t07749778153._8
1678+ let baseAssetReserveAfter = $t07749778153._9
1679+ let totalPositionSizeAfter = $t07749778153._10
1680+ let openInterestNotionalAfter = $t07749778153._11
1681+ let totalLongAfter = $t07749778153._12
1682+ let totalShortAfter = $t07749778153._13
1683+ let totalLongOpenInterestAfter = $t07749778153._14
1684+ let totalShortOpenInterestAfter = $t07749778153._15
1685+ let liquidationPenalty = $t07749778153._16
16781686 let feeToLiquidator = (liquidationPenalty / 2)
16791687 let feeToVault = (liquidationPenalty - feeToLiquidator)
16801688 let ammBalance = (cbalance() - liquidationPenalty)
16811689 let newAmmBalance = if ((0 > ammBalance))
16821690 then 0
16831691 else ammBalance
16841692 let lockBadDebt = if ((positionBadDebt > 0))
16851693 then {
16861694 let lockBadDebt = invoke(vaultAddress(), "exchangeFreeAndLocked", [(positionBadDebt + liquidationPenalty)], nil)
16871695 if ((lockBadDebt == lockBadDebt))
16881696 then nil
16891697 else throw("Strict value is not equal to itself.")
16901698 }
16911699 else nil
16921700 if ((lockBadDebt == lockBadDebt))
16931701 then {
16941702 let unstake = invoke(vaultAddress(), "withdrawLocked", [liquidationPenalty], nil)
16951703 if ((unstake == unstake))
16961704 then {
16971705 let depositInsurance = invoke(vaultAddress(), "addFree", nil, [AttachedPayment(quoteAsset(), feeToVault)])
16981706 if ((depositInsurance == depositInsurance))
16991707 then {
17001708 let notifyNotional = invoke(minerAddress(), "notifyNotional", [_trader, newPositionOpenNotional], nil)
17011709 if ((notifyNotional == notifyNotional))
17021710 then ((((if (isPartialLiquidation)
17031711 then updatePosition(_trader, newPositionSize, newPositionMargin, newPositionOpenNotional, newPositionLstUpdCPF, lastTimestamp())
17041712 else deletePosition(_trader, _direction)) ++ updateAmm(quoteAssetReserveAfter, baseAssetReserveAfter, totalPositionSizeAfter, openInterestNotionalAfter, totalLongAfter, totalShortAfter, totalLongOpenInterestAfter, totalShortOpenInterestAfter)) ++ withdraw(i.caller, feeToLiquidator)) ++ updateBalance(newAmmBalance))
17051713 else throw("Strict value is not equal to itself.")
17061714 }
17071715 else throw("Strict value is not equal to itself.")
17081716 }
17091717 else throw("Strict value is not equal to itself.")
17101718 }
17111719 else throw("Strict value is not equal to itself.")
17121720 }
17131721 }
17141722 else throw("Strict value is not equal to itself.")
17151723 }
17161724 else throw("Strict value is not equal to itself.")
17171725 }
17181726
17191727
17201728
17211729 @Callable(i)
17221730 func payFunding (_priceUpdate) = {
17231731 let updateOracle = invoke(this, "updateOracle", [_priceUpdate], nil)
17241732 if ((updateOracle == updateOracle))
17251733 then {
17261734 let sync = invoke(this, "syncTerminalPriceToOracle", nil, nil)
17271735 if ((sync == sync))
17281736 then {
17291737 let fundingBlockTimestamp = nextFundingBlockTimestamp()
17301738 if (if (if ((fundingBlockTimestamp > lastTimestamp()))
17311739 then true
17321740 else !(initialized()))
17331741 then true
17341742 else paused())
17351743 then throw(((("Invalid funding block timestamp: " + toString(lastTimestamp())) + " < ") + toString(fundingBlockTimestamp)))
17361744 else {
17371745 let underlyingPrice = getOraclePrice()
1738- let $t08000880086 = getFunding()
1739- let shortPremiumFraction = $t08000880086._1
1740- let longPremiumFraction = $t08000880086._2
1741- let premiumToVault = $t08000880086._3
1746+ let $t08037180449 = getFunding()
1747+ let shortPremiumFraction = $t08037180449._1
1748+ let longPremiumFraction = $t08037180449._2
1749+ let premiumToVault = $t08037180449._3
17421750 let doPayFundingToVault = if ((premiumToVault > 0))
17431751 then {
17441752 let doPayFundingToVault = invoke(vaultAddress(), "exchangeFreeAndLocked", [-(premiumToVault)], nil)
17451753 if ((doPayFundingToVault == doPayFundingToVault))
17461754 then nil
17471755 else throw("Strict value is not equal to itself.")
17481756 }
17491757 else nil
17501758 if ((doPayFundingToVault == doPayFundingToVault))
17511759 then updateFunding((fundingBlockTimestamp + fundingPeriodSeconds()), (latestLongCumulativePremiumFraction() + longPremiumFraction), (latestShortCumulativePremiumFraction() + shortPremiumFraction), divd(longPremiumFraction, underlyingPrice), divd(shortPremiumFraction, underlyingPrice))
17521760 else throw("Strict value is not equal to itself.")
17531761 }
17541762 }
17551763 else throw("Strict value is not equal to itself.")
17561764 }
17571765 else throw("Strict value is not equal to itself.")
17581766 }
17591767
17601768
17611769
17621770 @Callable(i)
17631771 func updateOracle (_priceUpdate) = if ((oracleMode() == ORACLE_PLAIN))
17641772 then nil
17651773 else {
17661774 let priceUpdates = split_4C(_priceUpdate, "::")
17671775 let baseOracle = valueOrErrorMessage(getOracleData(k_baseOracle), "No base asset oracle data")
17681776 let baseOracleAddress = baseOracle._1
17691777 let doUpdateBaseOracle = invoke(baseOracleAddress, "updateData", [priceUpdates[0]], nil)
17701778 if ((doUpdateBaseOracle == doUpdateBaseOracle))
17711779 then {
17721780 let quoteOracle = getOracleData(k_quoteOracle)
17731781 let doUpdateQuoteOracle = if (isDefined(quoteOracle))
17741782 then {
17751783 let quoteOracleV = value(quoteOracle)
17761784 let quoteOracleAddress = quoteOracleV._1
17771785 let doUpdateQuoteOracle = invoke(quoteOracleAddress, "updateData", [priceUpdates[1]], nil)
17781786 if ((doUpdateQuoteOracle == doUpdateQuoteOracle))
17791787 then nil
17801788 else throw("Strict value is not equal to itself.")
17811789 }
17821790 else nil
17831791 if ((doUpdateQuoteOracle == doUpdateQuoteOracle))
17841792 then nil
17851793 else throw("Strict value is not equal to itself.")
17861794 }
17871795 else throw("Strict value is not equal to itself.")
17881796 }
17891797
17901798
17911799
17921800 @Callable(i)
17931801 func syncTerminalPriceToOracle () = {
17941802 let _qtAstR = qtAstR()
17951803 let _bsAstR = bsAstR()
1796- let $t08190382269 = getSyncTerminalPrice(getOraclePrice(), _qtAstR, _bsAstR)
1797- let newQuoteAssetWeight = $t08190382269._1
1798- let newBaseAssetWeight = $t08190382269._2
1799- let marginToVault = $t08190382269._3
1804+ let $t08226682632 = getSyncTerminalPrice(getOraclePrice(), _qtAstR, _bsAstR)
1805+ let newQuoteAssetWeight = $t08226682632._1
1806+ let newBaseAssetWeight = $t08226682632._2
1807+ let marginToVault = $t08226682632._3
18001808 let marginToVaultAdj = if (if ((0 > marginToVault))
18011809 then (abs(marginToVault) > cbalance())
18021810 else false)
18031811 then -(cbalance())
18041812 else marginToVault
18051813 let doExchangePnL = if ((marginToVaultAdj != 0))
18061814 then {
18071815 let doExchangePnL = invoke(vaultAddress(), "exchangeFreeAndLocked", [marginToVaultAdj], nil)
18081816 if ((doExchangePnL == doExchangePnL))
18091817 then nil
18101818 else throw("Strict value is not equal to itself.")
18111819 }
18121820 else nil
18131821 if ((doExchangePnL == doExchangePnL))
18141822 then (updateBalance((cbalance() + marginToVaultAdj)) ++ updateAmmWeights(newQuoteAssetWeight, newBaseAssetWeight))
18151823 else throw("Strict value is not equal to itself.")
18161824 }
18171825
18181826
18191827
18201828 @Callable(i)
18211829 func ensureCalledOnce () = if ((i.caller != this))
18221830 then throw("Invalid saveCurrentTxId parameters")
18231831 else {
18241832 let txId = toBase58String(i.transactionId)
18251833 let lastTx = valueOrElse(getString(this, k_lastTx), "")
18261834 if ((lastTx != txId))
18271835 then [StringEntry(k_lastTx, txId)]
18281836 else throw("Can not call vAMM methods twice in one tx")
18291837 }
18301838
18311839
18321840
18331841 @Callable(i)
18341842 func migratePosition (_trader) = {
18351843 let positionSizeOpt = getInteger(this, toCompositeKey(k_positionSize, _trader))
18361844 if (if (isDefined(positionSizeOpt))
18371845 then isDefined(addressFromString(_trader))
18381846 else false)
18391847 then {
18401848 let pSize = getIntegerValue(this, toCompositeKey(k_positionSize, _trader))
18411849 let pMargin = getIntegerValue(this, toCompositeKey(k_positionMargin, _trader))
18421850 let pNotional = getIntegerValue(this, toCompositeKey(k_positionOpenNotional, _trader))
18431851 let pFraction = getIntegerValue(this, toCompositeKey(k_positionLastUpdatedCumulativePremiumFraction, _trader))
18441852 let pTimestamp = valueOrElse(getInteger(this, toCompositeKey(k_positionLastUpdatedTimestamp, _trader)), lastBlock.timestamp)
18451853 let pFee = valueOrElse(getInteger(this, toCompositeKey(k_positionFee, _trader)), fee())
18461854 let pSequence = getIntegerValue(this, toCompositeKey(k_positionSequence, _trader))
18471855 let pDirection = getDirection(pSize)
18481856 let positionKey = ((_trader + "_") + toString(pDirection))
18491857 [DeleteEntry(toCompositeKey(k_positionSize, _trader)), DeleteEntry(toCompositeKey(k_positionMargin, _trader)), DeleteEntry(toCompositeKey(k_positionOpenNotional, _trader)), DeleteEntry(toCompositeKey(k_positionLastUpdatedCumulativePremiumFraction, _trader)), DeleteEntry(toCompositeKey(k_positionLastUpdatedTimestamp, _trader)), DeleteEntry(toCompositeKey(k_positionFee, _trader)), DeleteEntry(toCompositeKey(k_positionSequence, _trader)), IntegerEntry(toCompositeKey(k_positionSize, positionKey), pSize), IntegerEntry(toCompositeKey(k_positionMargin, positionKey), pMargin), IntegerEntry(toCompositeKey(k_positionOpenNotional, positionKey), pNotional), IntegerEntry(toCompositeKey(k_positionLastUpdatedCumulativePremiumFraction, positionKey), pFraction), IntegerEntry(toCompositeKey(k_positionLastUpdatedTimestamp, positionKey), pTimestamp), IntegerEntry(toCompositeKey(k_positionFee, positionKey), pFee), IntegerEntry(toCompositeKey(k_positionSequence, positionKey), pSequence)]
18501858 }
18511859 else throw(("Nothing to migrate for " + _trader))
18521860 }
18531861
18541862
18551863
18561864 @Callable(i)
18571865 func view_calcRemainMarginWithFundingPayment (_trader,_direction,_priceUpdate) = {
18581866 let updateOracle = invoke(this, "updateOracle", [_priceUpdate], nil)
18591867 if ((updateOracle == updateOracle))
18601868 then {
18611869 let sync = invoke(this, "syncTerminalPriceToOracle", nil, nil)
18621870 if ((sync == sync))
18631871 then {
1864- let $t08606386199 = getPosition(_trader, _direction)
1865- let positionSize = $t08606386199._1
1866- let positionMargin = $t08606386199._2
1867- let pon = $t08606386199._3
1868- let positionLstUpdCPF = $t08606386199._4
1869- let positionTimestamp = $t08606386199._5
1870- let $t08620286315 = getPositionNotionalAndUnrealizedPnl(_trader, _direction, PNL_OPTION_SPOT)
1871- let positionNotional = $t08620286315._1
1872- let unrealizedPnl = $t08620286315._2
1873- let $t08631886542 = calcRemainMarginWithFundingPaymentAndRolloverFee(positionSize, positionMargin, positionLstUpdCPF, positionTimestamp, unrealizedPnl)
1874- let remainMargin = $t08631886542._1
1875- let badDebt = $t08631886542._2
1876- let fundingPayment = $t08631886542._3
1877- let rolloverFee = $t08631886542._4
1878- throw(((((((s(remainMargin) + s(fundingPayment)) + s(getMarginRatio(_trader, _direction))) + s(unrealizedPnl)) + s(badDebt)) + s(positionNotional)) + s(rolloverFee)))
1872+ let $t08642686562 = getPosition(_trader, _direction)
1873+ let positionSize = $t08642686562._1
1874+ let positionMargin = $t08642686562._2
1875+ let pon = $t08642686562._3
1876+ let positionLstUpdCPF = $t08642686562._4
1877+ let positionTimestamp = $t08642686562._5
1878+ let $t08656586678 = getPositionNotionalAndUnrealizedPnl(_trader, _direction, PNL_OPTION_SPOT)
1879+ let positionNotional = $t08656586678._1
1880+ let unrealizedPnl = $t08656586678._2
1881+ let $t08668186905 = calcRemainMarginWithFundingPaymentAndRolloverFee(positionSize, positionMargin, positionLstUpdCPF, positionTimestamp, unrealizedPnl)
1882+ let remainMargin = $t08668186905._1
1883+ let badDebt = $t08668186905._2
1884+ let fundingPayment = $t08668186905._3
1885+ let rolloverFee = $t08668186905._4
1886+ let underlyingPrice = getOraclePrice()
1887+ let spotPrice = getSpotPrice()
1888+ throw(((((((((s(remainMargin) + s(fundingPayment)) + s(getMarginRatio(_trader, _direction))) + s(unrealizedPnl)) + s(badDebt)) + s(positionNotional)) + s(rolloverFee)) + s(underlyingPrice)) + s(spotPrice)))
18791889 }
18801890 else throw("Strict value is not equal to itself.")
18811891 }
18821892 else throw("Strict value is not equal to itself.")
18831893 }
18841894
18851895
18861896
18871897 @Callable(i)
18881898 func view_getPegAdjustCost (_price) = {
18891899 let _qtAstR = qtAstR()
18901900 let _bsAstR = bsAstR()
18911901 let result = getSyncTerminalPrice(_price, _qtAstR, _bsAstR)
18921902 throw(toString(result._3))
18931903 }
18941904
18951905
18961906
18971907 @Callable(i)
18981908 func view_getTerminalAmmPrice () = {
1899- let $t08727787358 = getTerminalAmmState()
1900- let terminalQuoteAssetReserve = $t08727787358._1
1901- let terminalBaseAssetReserve = $t08727787358._2
1909+ let $t08775887839 = getTerminalAmmState()
1910+ let terminalQuoteAssetReserve = $t08775887839._1
1911+ let terminalBaseAssetReserve = $t08775887839._2
19021912 let price = divd(muld(terminalQuoteAssetReserve, qtAstW()), muld(terminalBaseAssetReserve, bsAstW()))
19031913 throw(toString(price))
19041914 }
19051915
19061916
19071917
19081918 @Callable(i)
19091919 func view_getFunding (_priceUpdate) = {
19101920 let updateOracle = invoke(this, "updateOracle", [_priceUpdate], nil)
19111921 if ((updateOracle == updateOracle))
19121922 then {
19131923 let sync = invoke(this, "syncTerminalPriceToOracle", nil, nil)
19141924 if ((sync == sync))
19151925 then {
19161926 let underlyingPrice = getOraclePrice()
1917- let $t08801088088 = getFunding()
1918- let shortPremiumFraction = $t08801088088._1
1919- let longPremiumFraction = $t08801088088._2
1920- let premiumToVault = $t08801088088._3
1927+ let $t08849188569 = getFunding()
1928+ let shortPremiumFraction = $t08849188569._1
1929+ let longPremiumFraction = $t08849188569._2
1930+ let premiumToVault = $t08849188569._3
19211931 let longFunding = divd(longPremiumFraction, underlyingPrice)
19221932 let shortFunding = divd(shortPremiumFraction, underlyingPrice)
19231933 throw(((((s(longFunding) + s(shortFunding)) + s(getSpotPrice())) + s(getOraclePrice())) + s(premiumToVault)))
19241934 }
19251935 else throw("Strict value is not equal to itself.")
19261936 }
19271937 else throw("Strict value is not equal to itself.")
19281938 }
19291939
19301940
19311941
19321942 @Callable(i)
19331943 func computeSpotPrice () = {
19341944 let sync = invoke(this, "syncTerminalPriceToOracle", nil, nil)
19351945 if ((sync == sync))
19361946 then {
19371947 let result = getSpotPrice()
19381948 $Tuple2(nil, result)
19391949 }
19401950 else throw("Strict value is not equal to itself.")
19411951 }
19421952
19431953
19441954
19451955 @Callable(i)
19461956 func computeFeeForTraderWithArtifact (_trader,_artifactId) = {
19471957 let result = getForTraderWithArtifact(_trader, _artifactId)
19481958 $Tuple2(nil, result)
19491959 }
19501960
19511961
19521962 @Verifier(tx)
19531963 func verify () = {
19541964 let coordinatorStr = getString(this, k_coordinatorAddress)
19551965 if (isDefined(coordinatorStr))
19561966 then {
19571967 let admin = getString(addressFromStringValue(value(coordinatorStr)), k_admin_address)
19581968 if (isDefined(admin))
19591969 then valueOrElse(getBoolean(addressFromStringValue(value(admin)), ((("status_" + toString(this)) + "_") + toBase58String(tx.id))), false)
19601970 else throw("unable to verify: admin not set in coordinator")
19611971 }
19621972 else sigVerify(tx.bodyBytes, tx.proofs[0], tx.senderPublicKey)
19631973 }
19641974

github/deemru/w8io/3ef1775 
424.85 ms