tx · 4gny6JBpvGbWFEX6H3VSAZqrHBtXukAdT6EvK1RKCnzi

3MvFniLyQZ5zy1JY4TWucwuYM9JPsUVqFp4:  -0.08000000 Waves

2023.08.25 18:21 [2726343] smart account 3MvFniLyQZ5zy1JY4TWucwuYM9JPsUVqFp4 > SELF 0.00000000 Waves

{ "type": 13, "id": "4gny6JBpvGbWFEX6H3VSAZqrHBtXukAdT6EvK1RKCnzi", "fee": 8000000, "feeAssetId": null, "timestamp": 1692976920191, "version": 2, "chainId": 84, "sender": "3MvFniLyQZ5zy1JY4TWucwuYM9JPsUVqFp4", "senderPublicKey": "BrFTmLLyLB5h9L5BC4ca35HwPzPC8uTREyMExAeqErZc", "proofs": [ "2wy8jEb6a8GEcaAXYNPyYdDKXBWJV9QBtzCdwAAYmZwyK43WTVzyM7MBF5HJg72fL541Kedvinc4o9JCqoMhXfiy" ], "script": "base64:BgKUAQgCEgASABIAEgASAwoBARIVChMBAQEBAQEBAQEBAQEBAQEICAEBEhgKFgEBAQEBAQEICAgBAQEBAQEBAQEBAQESBwoFAQEBCAgSBAoCAQgSBQoDAQEIEgcKBQEBAQQIEgUKAwgBCBIDCgEIEgMKAQgSABIAEgMKAQgSBQoDCAEIEgMKAQESABIDCgEIEgASBAoCCAi/AQAMa19iYXNlT3JhY2xlAgxrX2Jhc2VPcmFjbGUADWtfcXVvdGVPcmFjbGUCDWtfcXVvdGVPcmFjbGUACWtfYmFsYW5jZQIJa19iYWxhbmNlAAprX3NlcXVlbmNlAgprX3NlcXVlbmNlAA5rX3Bvc2l0aW9uU2l6ZQIOa19wb3NpdGlvblNpemUAEGtfcG9zaXRpb25NYXJnaW4CEGtfcG9zaXRpb25NYXJnaW4AFmtfcG9zaXRpb25PcGVuTm90aW9uYWwCFmtfcG9zaXRpb25PcGVuTm90aW9uYWwALmtfcG9zaXRpb25MYXN0VXBkYXRlZEN1bXVsYXRpdmVQcmVtaXVtRnJhY3Rpb24CEmtfcG9zaXRpb25GcmFjdGlvbgASa19wb3NpdGlvblNlcXVlbmNlAhJrX3Bvc2l0aW9uU2VxdWVuY2UADWtfcG9zaXRpb25GZWUCDWtfcG9zaXRpb25GZWUAHmtfcG9zaXRpb25MYXN0VXBkYXRlZFRpbWVzdGFtcAITa19wb3NpdGlvblRpbWVzdGFtcAANa19pbml0aWFsaXplZAINa19pbml0aWFsaXplZAAIa19wYXVzZWQCCGtfcGF1c2VkAAtrX2Nsb3NlT25seQILa19jbG9zZU9ubHkABWtfZmVlAgVrX2ZlZQANa19yb2xsb3ZlckZlZQIOa19yb2xsb3Zlcl9mZWUAD2tfZnVuZGluZ1BlcmlvZAIPa19mdW5kaW5nUGVyaW9kABFrX2luaXRNYXJnaW5SYXRpbwIRa19pbml0TWFyZ2luUmF0aW8AFGtfbWluSW5pdE1hcmdpblJhdGlvAhRrX21pbkluaXRNYXJnaW5SYXRpbwAYa19tYWludGVuYW5jZU1hcmdpblJhdGlvAgVrX21tcgAVa19saXF1aWRhdGlvbkZlZVJhdGlvAhVrX2xpcXVpZGF0aW9uRmVlUmF0aW8AGWtfcGFydGlhbExpcXVpZGF0aW9uUmF0aW8CFmtfcGFydExpcXVpZGF0aW9uUmF0aW8ADWtfc3ByZWFkTGltaXQCDWtfc3ByZWFkTGltaXQAEGtfbWF4UHJpY2VJbXBhY3QCEGtfbWF4UHJpY2VJbXBhY3QAEGtfbWF4UHJpY2VTcHJlYWQCEGtfbWF4UHJpY2VTcHJlYWQAEWtfbWF4T3Blbk5vdGlvbmFsAhFrX21heE9wZW5Ob3Rpb25hbAAVa19mZWVUb1N0YWtlcnNQZXJjZW50AhVrX2ZlZVRvU3Rha2Vyc1BlcmNlbnQAEGtfbWF4T3JhY2xlRGVsYXkCEGtfbWF4T3JhY2xlRGVsYXkADWtfZnVuZGluZ01vZGUCDWtfZnVuZGluZ01vZGUADGtfb3JhY2xlTW9kZQIMa19vcmFjbGVNb2RlAA5rX3Bvc2l0aW9uTW9kZQIOa19wb3NpdGlvbk1vZGUAGGtfbWluTGlxdWlkYXRpb25Ob3Rpb25hbAIYa19taW5MaXF1aWRhdGlvbk5vdGlvbmFsACVrX2xhdGVzdExvbmdDdW11bGF0aXZlUHJlbWl1bUZyYWN0aW9uAhtrX2xhdGVzdExvbmdQcmVtaXVtRnJhY3Rpb24AJmtfbGF0ZXN0U2hvcnRDdW11bGF0aXZlUHJlbWl1bUZyYWN0aW9uAhxrX2xhdGVzdFNob3J0UHJlbWl1bUZyYWN0aW9uABJrX25leHRGdW5kaW5nQmxvY2sCHmtfbmV4dEZ1bmRpbmdCbG9ja01pblRpbWVzdGFtcAARa19sb25nRnVuZGluZ1JhdGUCEWtfbG9uZ0Z1bmRpbmdSYXRlABJrX3Nob3J0RnVuZGluZ1JhdGUCEmtfc2hvcnRGdW5kaW5nUmF0ZQATa19xdW90ZUFzc2V0UmVzZXJ2ZQIIa19xdEFzdFIAEmtfYmFzZUFzc2V0UmVzZXJ2ZQIIa19ic0FzdFIAEmtfcXVvdGVBc3NldFdlaWdodAIIa19xdEFzdFcAEWtfYmFzZUFzc2V0V2VpZ2h0AghrX2JzQXN0VwATa190b3RhbFBvc2l0aW9uU2l6ZQITa190b3RhbFBvc2l0aW9uU2l6ZQAXa190b3RhbExvbmdQb3NpdGlvblNpemUCF2tfdG90YWxMb25nUG9zaXRpb25TaXplABhrX3RvdGFsU2hvcnRQb3NpdGlvblNpemUCGGtfdG90YWxTaG9ydFBvc2l0aW9uU2l6ZQAWa19vcGVuSW50ZXJlc3ROb3Rpb25hbAIWa19vcGVuSW50ZXJlc3ROb3Rpb25hbAATa19vcGVuSW50ZXJlc3RTaG9ydAITa19vcGVuSW50ZXJlc3RTaG9ydAASa19vcGVuSW50ZXJlc3RMb25nAhJrX29wZW5JbnRlcmVzdExvbmcACGtfbGFzdFR4AghrX2xhc3RUeAAUa19jb29yZGluYXRvckFkZHJlc3MCFGtfY29vcmRpbmF0b3JBZGRyZXNzAA9rX3ZhdWx0X2FkZHJlc3MCD2tfdmF1bHRfYWRkcmVzcwAPa19hZG1pbl9hZGRyZXNzAg9rX2FkbWluX2FkZHJlc3MADWtfcXVvdGVfYXNzZXQCDWtfcXVvdGVfYXNzZXQAEWtfc3Rha2luZ19hZGRyZXNzAhFrX3N0YWtpbmdfYWRkcmVzcwAPa19taW5lcl9hZGRyZXNzAg9rX21pbmVyX2FkZHJlc3MAEGtfb3JkZXJzX2FkZHJlc3MCEGtfb3JkZXJzX2FkZHJlc3MAEmtfcmVmZXJyYWxfYWRkcmVzcwISa19yZWZlcnJhbF9hZGRyZXNzABVrX25mdF9tYW5hZ2VyX2FkZHJlc3MCFWtfbmZ0X21hbmFnZXJfYWRkcmVzcwEOdG9Db21wb3NpdGVLZXkCBF9rZXkIX2FkZHJlc3MJAKwCAgkArAICBQRfa2V5AgFfBQhfYWRkcmVzcwELY29vcmRpbmF0b3IACQETdmFsdWVPckVycm9yTWVzc2FnZQIJAKYIAQkBEUBleHRyTmF0aXZlKDEwNTMpAgUEdGhpcwUUa19jb29yZGluYXRvckFkZHJlc3MCE0Nvb3JkaW5hdG9yIG5vdCBzZXQBDGFkbWluQWRkcmVzcwAJAKYIAQkBEUBleHRyTmF0aXZlKDEwNTMpAgkBC2Nvb3JkaW5hdG9yAAUPa19hZG1pbl9hZGRyZXNzAQpxdW90ZUFzc2V0AAkA2QQBCQERQGV4dHJOYXRpdmUoMTA1MykCCQELY29vcmRpbmF0b3IABQ1rX3F1b3RlX2Fzc2V0AQ5zdGFraW5nQWRkcmVzcwAJARN2YWx1ZU9yRXJyb3JNZXNzYWdlAgkApggBCQERQGV4dHJOYXRpdmUoMTA1MykCCQELY29vcmRpbmF0b3IABRFrX3N0YWtpbmdfYWRkcmVzcwIPU3Rha2luZyBub3Qgc2V0AQx2YXVsdEFkZHJlc3MACQETdmFsdWVPckVycm9yTWVzc2FnZQIJAKYIAQkBEUBleHRyTmF0aXZlKDEwNTMpAgkBC2Nvb3JkaW5hdG9yAAUPa192YXVsdF9hZGRyZXNzAg1WYXVsdCBub3Qgc2V0AQxtaW5lckFkZHJlc3MACQETdmFsdWVPckVycm9yTWVzc2FnZQIJAKYIAQkBEUBleHRyTmF0aXZlKDEwNTMpAgkBC2Nvb3JkaW5hdG9yAAUPa19taW5lcl9hZGRyZXNzAg1NaW5lciBub3Qgc2V0AQ1vcmRlcnNBZGRyZXNzAAkBE3ZhbHVlT3JFcnJvck1lc3NhZ2UCCQCmCAEJARFAZXh0ck5hdGl2ZSgxMDUzKQIJAQtjb29yZGluYXRvcgAFEGtfb3JkZXJzX2FkZHJlc3MCDk9yZGVycyBub3Qgc2V0AQ9yZWZlcnJhbEFkZHJlc3MACQETdmFsdWVPckVycm9yTWVzc2FnZQIJAKYIAQkBEUBleHRyTmF0aXZlKDEwNTMpAgkBC2Nvb3JkaW5hdG9yAAUSa19yZWZlcnJhbF9hZGRyZXNzAhBSZWZlcnJhbCBub3Qgc2V0ARFuZnRNYW5hZ2VyQWRkcmVzcwAJARN2YWx1ZU9yRXJyb3JNZXNzYWdlAgkApggBCQERQGV4dHJOYXRpdmUoMTA1MykCCQELY29vcmRpbmF0b3IABRVrX25mdF9tYW5hZ2VyX2FkZHJlc3MCE05GVCBNYW5hZ2VyIG5vdCBzZXQADWtfdG9rZW5fcGFyYW0CDWtfdG9rZW5fcGFyYW0ADGtfdG9rZW5fdHlwZQIMa190b2tlbl90eXBlABhGRUVfUkVEVUNUSU9OX1RPS0VOX1RZUEUCDWZlZV9yZWR1Y3Rpb24ACERJUl9MT05HAAEACURJUl9TSE9SVAACAAdTRUNPTkRTAOgHAA9ERUNJTUFMX05VTUJFUlMABgAMREVDSU1BTF9VTklUCQBoAgABCQBoAgkAaAIJAGgCCQBoAgkAaAIACgAKAAoACgAKAAoAD01JTlVURVNfSU5fWUVBUgkAaAIAoIogBQxERUNJTUFMX1VOSVQAB09ORV9EQVkJAGgCAICjBQUMREVDSU1BTF9VTklUAA9QTkxfT1BUSU9OX1NQT1QAAQARUE5MX09QVElPTl9PUkFDTEUAAgASRlVORElOR19BU1lNTUVUUklDAAEAEUZVTkRJTkdfU1lNTUVUUklDAAIADE9SQUNMRV9QTEFJTgABAApPUkFDTEVfSklUAAIAD1BPU0lUSU9OX0RJUkVDVAABAA5QT1NJVElPTl9PUkRFUgACAQFzAQJfeAkArAICCQCkAwEFAl94AgEsAQRkaXZkAgJfeAJfeQkAbgQFAl94BQxERUNJTUFMX1VOSVQFAl95BQhIQUxGRVZFTgEEbXVsZAICX3gCX3kJAG4EBQJfeAUCX3kFDERFQ0lNQUxfVU5JVAUISEFMRkVWRU4BBWJkaXZkAgJfeAJfeQkAvQIEBQJfeAkAtgIBBQxERUNJTUFMX1VOSVQFAl95BQhIQUxGRVZFTgEFYm11bGQCAl94Al95CQC9AgQFAl94BQJfeQkAtgIBBQxERUNJTUFMX1VOSVQFCEhBTEZFVkVOAQNhYnMBAl94AwkAZgIFAl94AAAFAl94CQEBLQEFAl94AQR2bWF4AgJfeAJfeQMJAGcCBQJfeAUCX3kFAl94BQJfeQEDaW50AQFrCQETdmFsdWVPckVycm9yTWVzc2FnZQIJAJoIAgUEdGhpcwUBawkArAICAg1ubyB2YWx1ZSBmb3IgBQFrAQVpbnRPcgIBawNkZWYJAQt2YWx1ZU9yRWxzZQIJAJoIAgUEdGhpcwUBawUDZGVmAQRzdHJBAghfYWRkcmVzcwRfa2V5BAN2YWwJARN2YWx1ZU9yRXJyb3JNZXNzYWdlAgkAnQgCBQhfYWRkcmVzcwUEX2tleQkArAICAhFObyB2YWx1ZSBmb3Iga2V5IAUEX2tleQUDdmFsAQRpbnRBAghfYWRkcmVzcwRfa2V5BAN2YWwJARN2YWx1ZU9yRXJyb3JNZXNzYWdlAgkAmggCBQhfYWRkcmVzcwUEX2tleQkArAICAhFObyB2YWx1ZSBmb3Iga2V5IAUEX2tleQUDdmFsAQhjYmFsYW5jZQAJAQNpbnQBBQlrX2JhbGFuY2UBCWNiYWxhbmNlMAAJAQVpbnRPcgIFCWtfYmFsYW5jZQAAAQNmZWUACQEDaW50AQUFa19mZWUBD3JvbGxvdmVyRmVlUmF0ZQAJAQNpbnQBBQ1rX3JvbGxvdmVyRmVlAQ9pbml0TWFyZ2luUmF0aW8ACQEDaW50AQURa19pbml0TWFyZ2luUmF0aW8BEm1pbkluaXRNYXJnaW5SYXRpbwAJAQVpbnRPcgIFFGtfbWluSW5pdE1hcmdpblJhdGlvBQxERUNJTUFMX1VOSVQBBnF0QXN0UgAJAQNpbnQBBRNrX3F1b3RlQXNzZXRSZXNlcnZlAQdxdEFzdFIwAAkBBWludE9yAgUTa19xdW90ZUFzc2V0UmVzZXJ2ZQAAAQZic0FzdFIACQEDaW50AQUSa19iYXNlQXNzZXRSZXNlcnZlAQdic0FzdFIwAAkBBWludE9yAgUSa19iYXNlQXNzZXRSZXNlcnZlAAABBnF0QXN0VwAJAQVpbnRPcgIFEmtfcXVvdGVBc3NldFdlaWdodAUMREVDSU1BTF9VTklUAQZic0FzdFcACQEFaW50T3ICBRFrX2Jhc2VBc3NldFdlaWdodAUMREVDSU1BTF9VTklUARF0b3RhbFBvc2l0aW9uU2l6ZQAJAQNpbnQBBRNrX3RvdGFsUG9zaXRpb25TaXplARRvcGVuSW50ZXJlc3ROb3Rpb25hbAAJAQNpbnQBBRZrX29wZW5JbnRlcmVzdE5vdGlvbmFsARFvcGVuSW50ZXJlc3RTaG9ydAAJAQNpbnQBBRNrX29wZW5JbnRlcmVzdFNob3J0ARBvcGVuSW50ZXJlc3RMb25nAAkBA2ludAEFEmtfb3BlbkludGVyZXN0TG9uZwEZbmV4dEZ1bmRpbmdCbG9ja1RpbWVzdGFtcAAJAQNpbnQBBRJrX25leHRGdW5kaW5nQmxvY2sBEGZ1bmRpbmdQZXJpb2RSYXcACQEDaW50AQUPa19mdW5kaW5nUGVyaW9kARRmdW5kaW5nUGVyaW9kRGVjaW1hbAAJAGgCCQEQZnVuZGluZ1BlcmlvZFJhdwAFDERFQ0lNQUxfVU5JVAEUZnVuZGluZ1BlcmlvZFNlY29uZHMACQBoAgkBEGZ1bmRpbmdQZXJpb2RSYXcABQdTRUNPTkRTARZtYWludGVuYW5jZU1hcmdpblJhdGlvAAkBA2ludAEFGGtfbWFpbnRlbmFuY2VNYXJnaW5SYXRpbwETbGlxdWlkYXRpb25GZWVSYXRpbwAJAQNpbnQBBRVrX2xpcXVpZGF0aW9uRmVlUmF0aW8BF3BhcnRpYWxMaXF1aWRhdGlvblJhdGlvAAkBA2ludAEFGWtfcGFydGlhbExpcXVpZGF0aW9uUmF0aW8BC3NwcmVhZExpbWl0AAkBA2ludAEFDWtfc3ByZWFkTGltaXQBDm1heFByaWNlSW1wYWN0AAkBA2ludAEFEGtfbWF4UHJpY2VJbXBhY3QBDm1heFByaWNlU3ByZWFkAAkBA2ludAEFEGtfbWF4UHJpY2VTcHJlYWQBD21heE9wZW5Ob3Rpb25hbAAJAQNpbnQBBRFrX21heE9wZW5Ob3Rpb25hbAEjbGF0ZXN0TG9uZ0N1bXVsYXRpdmVQcmVtaXVtRnJhY3Rpb24ACQEDaW50AQUla19sYXRlc3RMb25nQ3VtdWxhdGl2ZVByZW1pdW1GcmFjdGlvbgEkbGF0ZXN0U2hvcnRDdW11bGF0aXZlUHJlbWl1bUZyYWN0aW9uAAkBA2ludAEFJmtfbGF0ZXN0U2hvcnRDdW11bGF0aXZlUHJlbWl1bUZyYWN0aW9uARZ0b3RhbFNob3J0UG9zaXRpb25TaXplAAkBA2ludAEFGGtfdG90YWxTaG9ydFBvc2l0aW9uU2l6ZQEVdG90YWxMb25nUG9zaXRpb25TaXplAAkBA2ludAEFF2tfdG90YWxMb25nUG9zaXRpb25TaXplAQxsYXN0U2VxdWVuY2UACQEFaW50T3ICBQprX3NlcXVlbmNlAAABE2ZlZVRvU3Rha2Vyc1BlcmNlbnQACQEDaW50AQUVa19mZWVUb1N0YWtlcnNQZXJjZW50AQ5tYXhPcmFjbGVEZWxheQAJAQNpbnQBBRBrX21heE9yYWNsZURlbGF5AQtmdW5kaW5nTW9kZQAJAQVpbnRPcgIFDWtfZnVuZGluZ01vZGUFEkZVTkRJTkdfQVNZTU1FVFJJQwEKb3JhY2xlTW9kZQAJAQVpbnRPcgIFDGtfb3JhY2xlTW9kZQUMT1JBQ0xFX1BMQUlOAQxwb3NpdGlvbk1vZGUACQEFaW50T3ICBQ5rX3Bvc2l0aW9uTW9kZQUPUE9TSVRJT05fRElSRUNUAR1taW5QYXJ0aWFsTGlxdWlkYXRpb25Ob3Rpb25hbAAJAQVpbnRPcgIFGGtfbWluTGlxdWlkYXRpb25Ob3Rpb25hbAkAaAIACgUMREVDSU1BTF9VTklUAQ1sYXN0VGltZXN0YW1wAAgFCWxhc3RCbG9jawl0aW1lc3RhbXABD2dldEFjdHVhbENhbGxlcgEBaQkBC3ZhbHVlT3JFbHNlAgkAnQgCCQENb3JkZXJzQWRkcmVzcwACCGtfc2VuZGVyCQClCAEIBQFpBmNhbGxlcgEWcmVxdWlyZU1vcmVNYXJnaW5SYXRpbwMMX21hcmdpblJhdGlvEF9iYXNlTWFyZ2luUmF0aW8UX2xhcmdlclRoYW5PckVxdWFsVG8EFHJlbWFpbmluZ01hcmdpblJhdGlvCQBlAgUMX21hcmdpblJhdGlvBRBfYmFzZU1hcmdpblJhdGlvAwMFFF9sYXJnZXJUaGFuT3JFcXVhbFRvCQBmAgAABRRyZW1haW5pbmdNYXJnaW5SYXRpbwcJAAIBCQCsAgIJAKwCAgkArAICAhBJbnZhbGlkIG1hcmdpbjogCQCkAwEFDF9tYXJnaW5SYXRpbwIDIDwgCQCkAwEFEF9iYXNlTWFyZ2luUmF0aW8DAwkBASEBBRRfbGFyZ2VyVGhhbk9yRXF1YWxUbwkAZwIFFHJlbWFpbmluZ01hcmdpblJhdGlvAAAHCQACAQkArAICCQCsAgIJAKwCAgIQSW52YWxpZCBtYXJnaW46IAkApAMBBQxfbWFyZ2luUmF0aW8CAyA+IAkApAMBBRBfYmFzZU1hcmdpblJhdGlvBgEfbGF0ZXN0Q3VtdWxhdGl2ZVByZW1pdW1GcmFjdGlvbgENX3Bvc2l0aW9uU2l6ZQMJAAACBQ1fcG9zaXRpb25TaXplAAAJAAIBAixTaG91bGQgbm90IGJlIGNhbGxlZCB3aXRoIF9wb3NpdGlvblNpemUgPT0gMAMJAGYCBQ1fcG9zaXRpb25TaXplAAAJASNsYXRlc3RMb25nQ3VtdWxhdGl2ZVByZW1pdW1GcmFjdGlvbgAJASRsYXRlc3RTaG9ydEN1bXVsYXRpdmVQcmVtaXVtRnJhY3Rpb24AAQtnZXRQb3NpdGlvbgIHX3RyYWRlcgpfZGlyZWN0aW9uBAtwb3NpdGlvbktleQkArAICCQCsAgIFB190cmFkZXICAV8JAKQDAQUKX2RpcmVjdGlvbgQPcG9zaXRpb25TaXplT3B0CQCaCAIFBHRoaXMJAQ50b0NvbXBvc2l0ZUtleQIFDmtfcG9zaXRpb25TaXplBQtwb3NpdGlvbktleQQHJG1hdGNoMAUPcG9zaXRpb25TaXplT3B0AwkAAQIFByRtYXRjaDACA0ludAQMcG9zaXRpb25TaXplBQckbWF0Y2gwCQCXCgUFDHBvc2l0aW9uU2l6ZQkBEUBleHRyTmF0aXZlKDEwNTApAgUEdGhpcwkBDnRvQ29tcG9zaXRlS2V5AgUQa19wb3NpdGlvbk1hcmdpbgULcG9zaXRpb25LZXkJARFAZXh0ck5hdGl2ZSgxMDUwKQIFBHRoaXMJAQ50b0NvbXBvc2l0ZUtleQIFFmtfcG9zaXRpb25PcGVuTm90aW9uYWwFC3Bvc2l0aW9uS2V5CQERQGV4dHJOYXRpdmUoMTA1MCkCBQR0aGlzCQEOdG9Db21wb3NpdGVLZXkCBS5rX3Bvc2l0aW9uTGFzdFVwZGF0ZWRDdW11bGF0aXZlUHJlbWl1bUZyYWN0aW9uBQtwb3NpdGlvbktleQkBEUBleHRyTmF0aXZlKDEwNTApAgUEdGhpcwkBDnRvQ29tcG9zaXRlS2V5AgUea19wb3NpdGlvbkxhc3RVcGRhdGVkVGltZXN0YW1wBQtwb3NpdGlvbktleQkAlwoFAAAAAAAAAAAAAAEMZ2V0RGlyZWN0aW9uAQ1fcG9zaXRpb25TaXplAwkAZgIAAAUNX3Bvc2l0aW9uU2l6ZQUJRElSX1NIT1JUBQhESVJfTE9ORwEOZ2V0UG9zaXRpb25GZWUCB190cmFkZXIKX2RpcmVjdGlvbgQLcG9zaXRpb25LZXkJAKwCAgkArAICBQdfdHJhZGVyAgFfCQCkAwEFCl9kaXJlY3Rpb24EDnBvc2l0aW9uRmVlT3B0CQCaCAIFBHRoaXMJAQ50b0NvbXBvc2l0ZUtleQIFDWtfcG9zaXRpb25GZWUFC3Bvc2l0aW9uS2V5BAckbWF0Y2gwBQ5wb3NpdGlvbkZlZU9wdAMJAAECBQckbWF0Y2gwAgNJbnQEC3Bvc2l0aW9uRmVlBQckbWF0Y2gwBQtwb3NpdGlvbkZlZQkBA2ZlZQABE3JlcXVpcmVPcGVuUG9zaXRpb24CB190cmFkZXIKX2RpcmVjdGlvbgMJAAACCAkBC2dldFBvc2l0aW9uAgUHX3RyYWRlcgUKX2RpcmVjdGlvbgJfMQAACQACAQIQTm8gb3BlbiBwb3NpdGlvbgYBDWdldE9yYWNsZURhdGEBA2tleQQNb3JhY2xlRGF0YVN0cgkAnQgCBQR0aGlzBQNrZXkDAwkBCWlzRGVmaW5lZAEFDW9yYWNsZURhdGFTdHIJAQIhPQIJAQV2YWx1ZQEFDW9yYWNsZURhdGFTdHICAAcECm9yYWNsZURhdGEJALUJAgkBBXZhbHVlAQUNb3JhY2xlRGF0YVN0cgIBLAQNb3JhY2xlQWRkcmVzcwkBE3ZhbHVlT3JFcnJvck1lc3NhZ2UCCQCmCAEJAJEDAgUKb3JhY2xlRGF0YQAACQCsAgICG0ludmFsaWQgb3JhY2xlIGFkZHJlc3MgaW46IAkBBXZhbHVlAQUNb3JhY2xlRGF0YVN0cgQIcHJpY2VLZXkJAJEDAgUKb3JhY2xlRGF0YQABBAhibG9ja0tleQkAkQMCBQpvcmFjbGVEYXRhAAIEB29wZW5LZXkJAJEDAgUKb3JhY2xlRGF0YQADCQCWCgQFDW9yYWNsZUFkZHJlc3MFCHByaWNlS2V5BQhibG9ja0tleQUHb3BlbktleQUEdW5pdAELaW5pdGlhbGl6ZWQACQELdmFsdWVPckVsc2UCCQCbCAIFBHRoaXMFDWtfaW5pdGlhbGl6ZWQHAQZwYXVzZWQACQELdmFsdWVPckVsc2UCCQCbCAIFBHRoaXMFCGtfcGF1c2VkBwEJY2xvc2VPbmx5AAkBC3ZhbHVlT3JFbHNlAgkAmwgCBQR0aGlzBQtrX2Nsb3NlT25seQcBDXVwZGF0ZVJlc2VydmUDBl9pc0FkZBFfcXVvdGVBc3NldEFtb3VudBBfYmFzZUFzc2V0QW1vdW50AwUGX2lzQWRkBAduZXdCYXNlCQBlAgkBBmJzQXN0UgAFEF9iYXNlQXNzZXRBbW91bnQDCQBnAgAABQduZXdCYXNlCQACAQIqVHggbGVhZCB0byBiYXNlIGFzc2V0IHJlc2VydmUgPD0gMCwgcmV2ZXJ0CQCVCgMJAGQCCQEGcXRBc3RSAAURX3F1b3RlQXNzZXRBbW91bnQFB25ld0Jhc2UJAGQCCQERdG90YWxQb3NpdGlvblNpemUABRBfYmFzZUFzc2V0QW1vdW50BAhuZXdRdW90ZQkAZQIJAQZxdEFzdFIABRFfcXVvdGVBc3NldEFtb3VudAMJAGcCAAAFCG5ld1F1b3RlCQACAQIqVHggbGVhZCB0byBiYXNlIHF1b3RlIHJlc2VydmUgPD0gMCwgcmV2ZXJ0CQCVCgMFCG5ld1F1b3RlCQBkAgkBBmJzQXN0UgAFEF9iYXNlQXNzZXRBbW91bnQJAGUCCQERdG90YWxQb3NpdGlvblNpemUABRBfYmFzZUFzc2V0QW1vdW50AQ1jYWxjSW52YXJpYW50AgdfcXRBc3RSB19ic0FzdFIEB2JxdEFzdFIJALYCAQUHX3F0QXN0UgQHYmJzQXN0UgkAtgIBBQdfYnNBc3RSCQEFYm11bGQCBQdicXRBc3RSBQdiYnNBc3RSAQlzd2FwSW5wdXQCBl9pc0FkZBFfcXVvdGVBc3NldEFtb3VudAQHX3F0QXN0UgkBBnF0QXN0UgAEB19ic0FzdFIJAQZic0FzdFIABAdfcXRBc3RXCQEGcXRBc3RXAAQHX2JzQXN0VwkBBmJzQXN0VwAEGHF1b3RlQXNzZXRBbW91bnRBZGp1c3RlZAkBBGRpdmQCBRFfcXVvdGVBc3NldEFtb3VudAUHX3F0QXN0VwQBawkBDWNhbGNJbnZhcmlhbnQCBQdfcXRBc3RSBQdfYnNBc3RSBBZxdW90ZUFzc2V0UmVzZXJ2ZUFmdGVyAwUGX2lzQWRkCQBkAgUHX3F0QXN0UgUYcXVvdGVBc3NldEFtb3VudEFkanVzdGVkCQBlAgUHX3F0QXN0UgUYcXVvdGVBc3NldEFtb3VudEFkanVzdGVkBBViYXNlQXNzZXRSZXNlcnZlQWZ0ZXIJAKADAQkBBWJkaXZkAgUBawkAtgIBBRZxdW90ZUFzc2V0UmVzZXJ2ZUFmdGVyBBhhbW91bnRCYXNlQXNzZXRCb3VnaHRBYnMJAQNhYnMBCQBlAgUVYmFzZUFzc2V0UmVzZXJ2ZUFmdGVyBQdfYnNBc3RSBBVhbW91bnRCYXNlQXNzZXRCb3VnaHQDBQZfaXNBZGQFGGFtb3VudEJhc2VBc3NldEJvdWdodEFicwkBAS0BBRhhbW91bnRCYXNlQXNzZXRCb3VnaHRBYnMEDSR0MDE2NTg1MTY3NTUJAQ11cGRhdGVSZXNlcnZlAwUGX2lzQWRkBRhxdW90ZUFzc2V0QW1vdW50QWRqdXN0ZWQFGGFtb3VudEJhc2VBc3NldEJvdWdodEFicwQXcXVvdGVBc3NldFJlc2VydmVBZnRlcjEIBQ0kdDAxNjU4NTE2NzU1Al8xBBZiYXNlQXNzZXRSZXNlcnZlQWZ0ZXIxCAUNJHQwMTY1ODUxNjc1NQJfMgQXdG90YWxQb3NpdGlvblNpemVBZnRlcjEIBQ0kdDAxNjU4NTE2NzU1Al8zBAtwcmljZUJlZm9yZQkBBGRpdmQCCQEEbXVsZAIFB19xdEFzdFIFB19xdEFzdFcJAQRtdWxkAgUHX2JzQXN0UgUHX2JzQXN0VwQLbWFya2V0UHJpY2UJAQRkaXZkAgURX3F1b3RlQXNzZXRBbW91bnQFGGFtb3VudEJhc2VBc3NldEJvdWdodEFicwQJcHJpY2VEaWZmCQEDYWJzAQkAZQIFC3ByaWNlQmVmb3JlBQttYXJrZXRQcmljZQQLcHJpY2VJbXBhY3QJAGUCBQxERUNJTUFMX1VOSVQJAQRkaXZkAgULcHJpY2VCZWZvcmUJAGQCBQtwcmljZUJlZm9yZQUJcHJpY2VEaWZmBBNtYXhQcmljZUltcGFjdFZhbHVlCQEObWF4UHJpY2VJbXBhY3QAAwkAZgIFC3ByaWNlSW1wYWN0BRNtYXhQcmljZUltcGFjdFZhbHVlCQACAQkArAICCQCsAgIJAKwCAgkArAICCQCsAgIJAKwCAgkArAICCQCsAgIJAKwCAgkArAICCQCsAgIJAKwCAgkArAICAg1QcmljZSBpbXBhY3QgCQCkAwEFC3ByaWNlSW1wYWN0AhQgPiBtYXggcHJpY2UgaW1wYWN0IAkApAMBBRNtYXhQcmljZUltcGFjdFZhbHVlAhUgYmVmb3JlIHF1b3RlIGFzc2V0OiAJAKQDAQUHX3F0QXN0UgIUIGJlZm9yZSBiYXNlIGFzc2V0OiAJAKQDAQUHX2JzQXN0UgIhIHF1b3RlIGFzc2V0IGFtb3VudCB0byBleGNoYW5nZTogCQCkAwEFEV9xdW90ZUFzc2V0QW1vdW50Ag8gcHJpY2UgYmVmb3JlOiAJAKQDAQULcHJpY2VCZWZvcmUCDiBtYXJrZXRQcmljZTogCQCkAwEFC21hcmtldFByaWNlCQCWCgQFFWFtb3VudEJhc2VBc3NldEJvdWdodAUXcXVvdGVBc3NldFJlc2VydmVBZnRlcjEFFmJhc2VBc3NldFJlc2VydmVBZnRlcjEFF3RvdGFsUG9zaXRpb25TaXplQWZ0ZXIxAQ9jYWxjUm9sbG92ZXJGZWUCEl9vbGRQb3NpdGlvbk1hcmdpbiBfb2xkUG9zaXRpb25MYXN0VXBkYXRlZFRpbWVzdGFtcAQPcG9zaXRpb25NaW51dGVzCQBoAgkAaQIJAGkCCQBlAgkBDWxhc3RUaW1lc3RhbXAABSBfb2xkUG9zaXRpb25MYXN0VXBkYXRlZFRpbWVzdGFtcADoBwA8BQxERUNJTUFMX1VOSVQEC3JvbGxvdmVyRmVlCQEEZGl2ZAIJAQRtdWxkAgkBBG11bGQCBRJfb2xkUG9zaXRpb25NYXJnaW4FD3Bvc2l0aW9uTWludXRlcwkBD3JvbGxvdmVyRmVlUmF0ZQAFD01JTlVURVNfSU5fWUVBUgULcm9sbG92ZXJGZWUBMGNhbGNSZW1haW5NYXJnaW5XaXRoRnVuZGluZ1BheW1lbnRBbmRSb2xsb3ZlckZlZQUQX29sZFBvc2l0aW9uU2l6ZRJfb2xkUG9zaXRpb25NYXJnaW4lX29sZFBvc2l0aW9uQ3VtdWxhdGl2ZVByZW1pdW1GcmFjdGlvbiBfb2xkUG9zaXRpb25MYXN0VXBkYXRlZFRpbWVzdGFtcAxfbWFyZ2luRGVsdGEEDmZ1bmRpbmdQYXltZW50AwkBAiE9AgUQX29sZFBvc2l0aW9uU2l6ZQAABCBfbGF0ZXN0Q3VtdWxhdGl2ZVByZW1pdW1GcmFjdGlvbgkBH2xhdGVzdEN1bXVsYXRpdmVQcmVtaXVtRnJhY3Rpb24BBRBfb2xkUG9zaXRpb25TaXplCQEEbXVsZAIJAGUCBSBfbGF0ZXN0Q3VtdWxhdGl2ZVByZW1pdW1GcmFjdGlvbgUlX29sZFBvc2l0aW9uQ3VtdWxhdGl2ZVByZW1pdW1GcmFjdGlvbgUQX29sZFBvc2l0aW9uU2l6ZQAABAtyb2xsb3ZlckZlZQkBD2NhbGNSb2xsb3ZlckZlZQIFEl9vbGRQb3NpdGlvbk1hcmdpbgUgX29sZFBvc2l0aW9uTGFzdFVwZGF0ZWRUaW1lc3RhbXAEDHNpZ25lZE1hcmdpbgkAZAIJAGUCCQBlAgUMX21hcmdpbkRlbHRhBQtyb2xsb3ZlckZlZQUOZnVuZGluZ1BheW1lbnQFEl9vbGRQb3NpdGlvbk1hcmdpbgQNJHQwMTk0MjIxOTU0OQMJAGYCAAAFDHNpZ25lZE1hcmdpbgkAlAoCAAAJAQNhYnMBBQxzaWduZWRNYXJnaW4JAJQKAgkBA2FicwEFDHNpZ25lZE1hcmdpbgAABAxyZW1haW5NYXJnaW4IBQ0kdDAxOTQyMjE5NTQ5Al8xBAdiYWREZWJ0CAUNJHQwMTk0MjIxOTU0OQJfMgkAlgoEBQxyZW1haW5NYXJnaW4FB2JhZERlYnQFDmZ1bmRpbmdQYXltZW50BQtyb2xsb3ZlckZlZQEWc3dhcE91dHB1dFdpdGhSZXNlcnZlcwcGX2lzQWRkEF9iYXNlQXNzZXRBbW91bnQUX2NoZWNrTWF4UHJpY2VJbXBhY3QSX3F1b3RlQXNzZXRSZXNlcnZlEV9xdW90ZUFzc2V0V2VpZ2h0EV9iYXNlQXNzZXRSZXNlcnZlEF9iYXNlQXNzZXRXZWlnaHQEC3ByaWNlQmVmb3JlCQEEZGl2ZAIJAQRtdWxkAgUSX3F1b3RlQXNzZXRSZXNlcnZlBRFfcXVvdGVBc3NldFdlaWdodAkBBG11bGQCBRFfYmFzZUFzc2V0UmVzZXJ2ZQUQX2Jhc2VBc3NldFdlaWdodAMJAAACBRBfYmFzZUFzc2V0QW1vdW50AAAJAAIBAhlJbnZhbGlkIGJhc2UgYXNzZXQgYW1vdW50BAFrCQENY2FsY0ludmFyaWFudAIFEl9xdW90ZUFzc2V0UmVzZXJ2ZQURX2Jhc2VBc3NldFJlc2VydmUEGGJhc2VBc3NldFBvb2xBbW91bnRBZnRlcgMFBl9pc0FkZAkAZAIFEV9iYXNlQXNzZXRSZXNlcnZlBRBfYmFzZUFzc2V0QW1vdW50CQBlAgURX2Jhc2VBc3NldFJlc2VydmUFEF9iYXNlQXNzZXRBbW91bnQED3F1b3RlQXNzZXRBZnRlcgkAoAMBCQEFYmRpdmQCBQFrCQC2AgEFGGJhc2VBc3NldFBvb2xBbW91bnRBZnRlcgQPcXVvdGVBc3NldERlbHRhCQEDYWJzAQkAZQIFD3F1b3RlQXNzZXRBZnRlcgUSX3F1b3RlQXNzZXRSZXNlcnZlBA5xdW90ZUFzc2V0U29sZAkBBG11bGQCBQ9xdW90ZUFzc2V0RGVsdGEFEV9xdW90ZUFzc2V0V2VpZ2h0BBNtYXhQcmljZUltcGFjdFZhbHVlCQEObWF4UHJpY2VJbXBhY3QABA0kdDAyMDgxMTIwOTczCQENdXBkYXRlUmVzZXJ2ZQMJAQEhAQUGX2lzQWRkBQ9xdW90ZUFzc2V0RGVsdGEFEF9iYXNlQXNzZXRBbW91bnQEF3F1b3RlQXNzZXRSZXNlcnZlQWZ0ZXIxCAUNJHQwMjA4MTEyMDk3MwJfMQQWYmFzZUFzc2V0UmVzZXJ2ZUFmdGVyMQgFDSR0MDIwODExMjA5NzMCXzIEF3RvdGFsUG9zaXRpb25TaXplQWZ0ZXIxCAUNJHQwMjA4MTEyMDk3MwJfMwQLbWFya2V0UHJpY2UJAQRkaXZkAgUOcXVvdGVBc3NldFNvbGQFEF9iYXNlQXNzZXRBbW91bnQECXByaWNlRGlmZgkBA2FicwEJAGUCBQtwcmljZUJlZm9yZQULbWFya2V0UHJpY2UEC3ByaWNlSW1wYWN0CQBlAgUMREVDSU1BTF9VTklUCQEEZGl2ZAIFC3ByaWNlQmVmb3JlCQBkAgULcHJpY2VCZWZvcmUFCXByaWNlRGlmZgMDCQBmAgULcHJpY2VJbXBhY3QFE21heFByaWNlSW1wYWN0VmFsdWUFFF9jaGVja01heFByaWNlSW1wYWN0BwkAAgEJAKwCAgkArAICCQCsAgIJAKwCAgkArAICCQCsAgIJAKwCAgkArAICCQCsAgIJAKwCAgkArAICCQCsAgIJAKwCAgINUHJpY2UgaW1wYWN0IAkApAMBBQtwcmljZUltcGFjdAIUID4gbWF4IHByaWNlIGltcGFjdCAJAKQDAQUTbWF4UHJpY2VJbXBhY3RWYWx1ZQIVIGJlZm9yZSBxdW90ZSBhc3NldDogCQCkAwEFEl9xdW90ZUFzc2V0UmVzZXJ2ZQIUIGJlZm9yZSBiYXNlIGFzc2V0OiAJAKQDAQURX2Jhc2VBc3NldFJlc2VydmUCICBiYXNlIGFzc2V0IGFtb3VudCB0byBleGNoYW5nZTogCQCkAwEFEF9iYXNlQXNzZXRBbW91bnQCDyBwcmljZSBiZWZvcmU6IAkApAMBBQtwcmljZUJlZm9yZQIPIG1hcmtldCBwcmljZTogCQCkAwEFC21hcmtldFByaWNlCQCZCgcFDnF1b3RlQXNzZXRTb2xkBRdxdW90ZUFzc2V0UmVzZXJ2ZUFmdGVyMQUWYmFzZUFzc2V0UmVzZXJ2ZUFmdGVyMQUXdG90YWxQb3NpdGlvblNpemVBZnRlcjEJAGUCCQEVdG90YWxMb25nUG9zaXRpb25TaXplAAMFBl9pc0FkZAkBA2FicwEFEF9iYXNlQXNzZXRBbW91bnQAAAkAZQIJARZ0b3RhbFNob3J0UG9zaXRpb25TaXplAAMJAQEhAQUGX2lzQWRkCQEDYWJzAQUQX2Jhc2VBc3NldEFtb3VudAAABQtwcmljZUltcGFjdAEKc3dhcE91dHB1dAMGX2lzQWRkEF9iYXNlQXNzZXRBbW91bnQUX2NoZWNrTWF4UHJpY2VJbXBhY3QJARZzd2FwT3V0cHV0V2l0aFJlc2VydmVzBwUGX2lzQWRkBRBfYmFzZUFzc2V0QW1vdW50BRRfY2hlY2tNYXhQcmljZUltcGFjdAkBBnF0QXN0UgAJAQZxdEFzdFcACQEGYnNBc3RSAAkBBmJzQXN0VwABE2dldE9yYWNsZVByaWNlVmFsdWUDBm9yYWNsZQhwcmljZUtleQhibG9ja0tleQQJbGFzdFZhbHVlCQETdmFsdWVPckVycm9yTWVzc2FnZQIJAJoIAgUGb3JhY2xlBQhwcmljZUtleQkArAICCQCsAgIJAKwCAgIiQ2FuIG5vdCBnZXQgb3JhY2xlIHByaWNlLiBPcmFjbGU6IAkApQgBBQZvcmFjbGUCBiBrZXk6IAUIcHJpY2VLZXkDCQECIT0CBQhibG9ja0tleQIABAxjdXJyZW50QmxvY2sFBmhlaWdodAQPbGFzdE9yYWNsZUJsb2NrCQETdmFsdWVPckVycm9yTWVzc2FnZQIJAJoIAgUGb3JhY2xlBQhibG9ja0tleQkArAICCQCsAgIJAKwCAgIiQ2FuIG5vdCBnZXQgb3JhY2xlIGJsb2NrLiBPcmFjbGU6IAkApQgBBQZvcmFjbGUCBiBrZXk6IAUIYmxvY2tLZXkDCQBmAgkAZQIFDGN1cnJlbnRCbG9jawUPbGFzdE9yYWNsZUJsb2NrCQEObWF4T3JhY2xlRGVsYXkACQACAQkArAICCQCsAgIJAKwCAgImT3JhY2xlIHN0YWxlIGRhdGEuIExhc3Qgb3JhY2xlIGJsb2NrOiAJAKQDAQUPbGFzdE9yYWNsZUJsb2NrAhAgY3VycmVudCBibG9jazogCQCkAwEFDGN1cnJlbnRCbG9jawUJbGFzdFZhbHVlBQlsYXN0VmFsdWUBDmdldE9yYWNsZVByaWNlAAQKYmFzZU9yYWNsZQkBE3ZhbHVlT3JFcnJvck1lc3NhZ2UCCQENZ2V0T3JhY2xlRGF0YQEFDGtfYmFzZU9yYWNsZQIZTm8gYmFzZSBhc3NldCBvcmFjbGUgZGF0YQQPYmFzZU9yYWNsZVByaWNlCQETZ2V0T3JhY2xlUHJpY2VWYWx1ZQMIBQpiYXNlT3JhY2xlAl8xCAUKYmFzZU9yYWNsZQJfMggFCmJhc2VPcmFjbGUCXzMEC3F1b3RlT3JhY2xlCQENZ2V0T3JhY2xlRGF0YQEFDWtfcXVvdGVPcmFjbGUEEHF1b3RlT3JhY2xlUHJpY2UDCQEJaXNEZWZpbmVkAQULcXVvdGVPcmFjbGUEDHF1b3RlT3JhY2xlVgkBBXZhbHVlAQULcXVvdGVPcmFjbGUJARNnZXRPcmFjbGVQcmljZVZhbHVlAwgFDHF1b3RlT3JhY2xlVgJfMQgFDHF1b3RlT3JhY2xlVgJfMggFDHF1b3RlT3JhY2xlVgJfMwUMREVDSU1BTF9VTklUCQEEZGl2ZAIFD2Jhc2VPcmFjbGVQcmljZQUQcXVvdGVPcmFjbGVQcmljZQEOaXNNYXJrZXRDbG9zZWQABApiYXNlT3JhY2xlCQETdmFsdWVPckVycm9yTWVzc2FnZQIJAQ1nZXRPcmFjbGVEYXRhAQUMa19iYXNlT3JhY2xlAhlObyBiYXNlIGFzc2V0IG9yYWNsZSBkYXRhBAZvcmFjbGUIBQpiYXNlT3JhY2xlAl8xBAdvcGVuS2V5CAUKYmFzZU9yYWNsZQJfNAMJAQIhPQIFB29wZW5LZXkCAAQGaXNPcGVuCQETdmFsdWVPckVycm9yTWVzc2FnZQIJAJsIAgUGb3JhY2xlBQdvcGVuS2V5CQCsAgIJAKwCAgkArAICAitDYW4gbm90IGdldCBvcmFjbGUgaXMgb3Blbi9jbG9zZWQuIE9yYWNsZTogCQClCAEFBm9yYWNsZQIGIGtleTogBQdvcGVuS2V5CQEBIQEFBmlzT3BlbgcBDGFic1ByaWNlRGlmZgUMX29yYWNsZVByaWNlEl9xdW90ZUFzc2V0UmVzZXJ2ZRFfYmFzZUFzc2V0UmVzZXJ2ZQdfcXRBc3RXB19ic0FzdFcECnByaWNlQWZ0ZXIJAQRkaXZkAgkBBG11bGQCBRJfcXVvdGVBc3NldFJlc2VydmUFB19xdEFzdFcJAQRtdWxkAgURX2Jhc2VBc3NldFJlc2VydmUFB19ic0FzdFcEDGF2ZXJhZ2VQcmljZQkBBGRpdmQCCQBkAgUMX29yYWNsZVByaWNlBQpwcmljZUFmdGVyCQBoAgACBQxERUNJTUFMX1VOSVQEDGFic1ByaWNlRGlmZgkBBGRpdmQCCQEDYWJzAQkAZQIFDF9vcmFjbGVQcmljZQUKcHJpY2VBZnRlcgUMYXZlcmFnZVByaWNlBQxhYnNQcmljZURpZmYBGXJlcXVpcmVOb3RPdmVyU3ByZWFkTGltaXQCEl9xdW90ZUFzc2V0UmVzZXJ2ZRFfYmFzZUFzc2V0UmVzZXJ2ZQQLb3JhY2xlUHJpY2UJAQ5nZXRPcmFjbGVQcmljZQAEB19xdEFzdFcJAQZxdEFzdFcABAdfYnNBc3RXCQEGYnNBc3RXAAQSYWJzUHJpY2VEaWZmQmVmb3JlCQEMYWJzUHJpY2VEaWZmBQULb3JhY2xlUHJpY2UJAQZxdEFzdFIACQEGYnNBc3RSAAUHX3F0QXN0VwUHX2JzQXN0VwQRYWJzUHJpY2VEaWZmQWZ0ZXIJAQxhYnNQcmljZURpZmYFBQtvcmFjbGVQcmljZQUSX3F1b3RlQXNzZXRSZXNlcnZlBRFfYmFzZUFzc2V0UmVzZXJ2ZQUHX3F0QXN0VwUHX2JzQXN0VwMDCQBmAgURYWJzUHJpY2VEaWZmQWZ0ZXIJAQ5tYXhQcmljZVNwcmVhZAAJAGYCBRFhYnNQcmljZURpZmZBZnRlcgUSYWJzUHJpY2VEaWZmQmVmb3JlBwkAAgEJAKwCAgkArAICCQCsAgICDVByaWNlIHNwcmVhZCAJAKQDAQURYWJzUHJpY2VEaWZmQWZ0ZXICFCA+IG1heCBwcmljZSBzcHJlYWQgCQCkAwEJAQ5tYXhQcmljZVNwcmVhZAAGAR1yZXF1aXJlTm90T3Zlck1heE9wZW5Ob3Rpb25hbAIRX2xvbmdPcGVuTm90aW9uYWwSX3Nob3J0T3Blbk5vdGlvbmFsBBBfbWF4T3Blbk5vdGlvbmFsCQEPbWF4T3Blbk5vdGlvbmFsAAMJAGYCBRFfbG9uZ09wZW5Ob3Rpb25hbAUQX21heE9wZW5Ob3Rpb25hbAkAAgEJAKwCAgkArAICCQCsAgICE0xvbmcgb3BlbiBub3Rpb25hbCAJAKQDAQURX2xvbmdPcGVuTm90aW9uYWwCFSA+IG1heCBvcGVuIG5vdGlvbmFsIAkApAMBBRBfbWF4T3Blbk5vdGlvbmFsAwkAZgIFEl9zaG9ydE9wZW5Ob3Rpb25hbAUQX21heE9wZW5Ob3Rpb25hbAkAAgEJAKwCAgkArAICCQCsAgICFFNob3J0IG9wZW4gbm90aW9uYWwgCQCkAwEFEl9zaG9ydE9wZW5Ob3Rpb25hbAIVID4gbWF4IG9wZW4gbm90aW9uYWwgCQCkAwEFEF9tYXhPcGVuTm90aW9uYWwGASFyZXF1aXJlU2VuZGVyQ2FuV29ya1dpdGhQb3NpdGlvbnMBB19jYWxsZXIDCQAAAgkBDHBvc2l0aW9uTW9kZQAFDlBPU0lUSU9OX09SREVSCQAAAgUHX2NhbGxlcgkBDW9yZGVyc0FkZHJlc3MABgEMZ2V0U3BvdFByaWNlAAQSX3F1b3RlQXNzZXRSZXNlcnZlCQEGcXRBc3RSAAQRX2Jhc2VBc3NldFJlc2VydmUJAQZic0FzdFIABAdfcXRBc3RXCQEGcXRBc3RXAAQHX2JzQXN0VwkBBmJzQXN0VwAJAQRkaXZkAgkBBG11bGQCBRJfcXVvdGVBc3NldFJlc2VydmUFB19xdEFzdFcJAQRtdWxkAgURX2Jhc2VBc3NldFJlc2VydmUFB19ic0FzdFcBFmlzT3ZlckZsdWN0dWF0aW9uTGltaXQABAtvcmFjbGVQcmljZQkBDmdldE9yYWNsZVByaWNlAAQMY3VycmVudFByaWNlCQEMZ2V0U3BvdFByaWNlAAkAZgIJAQRkaXZkAgkBA2FicwEJAGUCBQtvcmFjbGVQcmljZQUMY3VycmVudFByaWNlBQtvcmFjbGVQcmljZQkBC3NwcmVhZExpbWl0AAEfZ2V0UG9zaXRpb25BZGp1c3RlZE9wZW5Ob3Rpb25hbAYNX3Bvc2l0aW9uU2l6ZQdfb3B0aW9uEl9xdW90ZUFzc2V0UmVzZXJ2ZRFfcXVvdGVBc3NldFdlaWdodBFfYmFzZUFzc2V0UmVzZXJ2ZRBfYmFzZUFzc2V0V2VpZ2h0BA9wb3NpdGlvblNpemVBYnMJAQNhYnMBBQ1fcG9zaXRpb25TaXplBAdpc1Nob3J0CQBmAgAABQ1fcG9zaXRpb25TaXplBBBwb3NpdGlvbk5vdGlvbmFsAwkAAAIFB19vcHRpb24FD1BOTF9PUFRJT05fU1BPVAQTb3V0UG9zaXRpb25Ob3Rpb25hbAgJARZzd2FwT3V0cHV0V2l0aFJlc2VydmVzBwkBASEBBQdpc1Nob3J0BQ9wb3NpdGlvblNpemVBYnMHBRJfcXVvdGVBc3NldFJlc2VydmUFEV9xdW90ZUFzc2V0V2VpZ2h0BRFfYmFzZUFzc2V0UmVzZXJ2ZQUQX2Jhc2VBc3NldFdlaWdodAJfMQUTb3V0UG9zaXRpb25Ob3Rpb25hbAkBBG11bGQCBQ9wb3NpdGlvblNpemVBYnMJAQ5nZXRPcmFjbGVQcmljZQAFEHBvc2l0aW9uTm90aW9uYWwBK2dldFBvc2l0aW9uTm90aW9uYWxBbmRVbnJlYWxpemVkUG5sQnlWYWx1ZXMHDV9wb3NpdGlvblNpemUVX3Bvc2l0aW9uT3Blbk5vdGlvbmFsEl9xdW90ZUFzc2V0UmVzZXJ2ZRFfcXVvdGVBc3NldFdlaWdodBFfYmFzZUFzc2V0UmVzZXJ2ZRBfYmFzZUFzc2V0V2VpZ2h0B19vcHRpb24DCQAAAgUNX3Bvc2l0aW9uU2l6ZQAACQACAQIVSW52YWxpZCBwb3NpdGlvbiBzaXplBAdpc1Nob3J0CQBmAgAABQ1fcG9zaXRpb25TaXplBBBwb3NpdGlvbk5vdGlvbmFsCQEfZ2V0UG9zaXRpb25BZGp1c3RlZE9wZW5Ob3Rpb25hbAYFDV9wb3NpdGlvblNpemUFB19vcHRpb24FEl9xdW90ZUFzc2V0UmVzZXJ2ZQURX3F1b3RlQXNzZXRXZWlnaHQFEV9iYXNlQXNzZXRSZXNlcnZlBRBfYmFzZUFzc2V0V2VpZ2h0BA11bnJlYWxpemVkUG5sAwUHaXNTaG9ydAkAZQIFFV9wb3NpdGlvbk9wZW5Ob3Rpb25hbAUQcG9zaXRpb25Ob3Rpb25hbAkAZQIFEHBvc2l0aW9uTm90aW9uYWwFFV9wb3NpdGlvbk9wZW5Ob3Rpb25hbAkAlAoCBRBwb3NpdGlvbk5vdGlvbmFsBQ11bnJlYWxpemVkUG5sASNnZXRQb3NpdGlvbk5vdGlvbmFsQW5kVW5yZWFsaXplZFBubAMHX3RyYWRlcgpfZGlyZWN0aW9uB19vcHRpb24EDSR0MDI5MTE0MjkyNTQJAQtnZXRQb3NpdGlvbgIFB190cmFkZXIFCl9kaXJlY3Rpb24EDHBvc2l0aW9uU2l6ZQgFDSR0MDI5MTE0MjkyNTQCXzEEDnBvc2l0aW9uTWFyZ2luCAUNJHQwMjkxMTQyOTI1NAJfMgQUcG9zaXRpb25PcGVuTm90aW9uYWwIBQ0kdDAyOTExNDI5MjU0Al8zBBFwb3NpdGlvbkxzdFVwZENQRggFDSR0MDI5MTE0MjkyNTQCXzQJAStnZXRQb3NpdGlvbk5vdGlvbmFsQW5kVW5yZWFsaXplZFBubEJ5VmFsdWVzBwUMcG9zaXRpb25TaXplBRRwb3NpdGlvbk9wZW5Ob3Rpb25hbAkBBnF0QXN0UgAJAQZxdEFzdFcACQEGYnNBc3RSAAkBBmJzQXN0VwAFB19vcHRpb24BD2NhbGNNYXJnaW5SYXRpbwMNX3JlbWFpbk1hcmdpbghfYmFkRGVidBFfcG9zaXRpb25Ob3Rpb25hbAkBBGRpdmQCCQBlAgUNX3JlbWFpbk1hcmdpbgUIX2JhZERlYnQFEV9wb3NpdGlvbk5vdGlvbmFsARZnZXRNYXJnaW5SYXRpb0J5T3B0aW9uAwdfdHJhZGVyCl9kaXJlY3Rpb24HX29wdGlvbgQNJHQwMjk3ODYyOTkzOQkBC2dldFBvc2l0aW9uAgUHX3RyYWRlcgUKX2RpcmVjdGlvbgQMcG9zaXRpb25TaXplCAUNJHQwMjk3ODYyOTkzOQJfMQQOcG9zaXRpb25NYXJnaW4IBQ0kdDAyOTc4NjI5OTM5Al8yBANwb24IBQ0kdDAyOTc4NjI5OTM5Al8zBBZwb3NpdGlvbkxhc3RVcGRhdGVkQ1BGCAUNJHQwMjk3ODYyOTkzOQJfNAQRcG9zaXRpb25UaW1lc3RhbXAIBQ0kdDAyOTc4NjI5OTM5Al81BA0kdDAyOTk0NTMwMDUwCQEjZ2V0UG9zaXRpb25Ob3Rpb25hbEFuZFVucmVhbGl6ZWRQbmwDBQdfdHJhZGVyBQpfZGlyZWN0aW9uBQdfb3B0aW9uBBBwb3NpdGlvbk5vdGlvbmFsCAUNJHQwMjk5NDUzMDA1MAJfMQQNdW5yZWFsaXplZFBubAgFDSR0MDI5OTQ1MzAwNTACXzIEDSR0MDMwMDU1MzAyNjcJATBjYWxjUmVtYWluTWFyZ2luV2l0aEZ1bmRpbmdQYXltZW50QW5kUm9sbG92ZXJGZWUFBQxwb3NpdGlvblNpemUFDnBvc2l0aW9uTWFyZ2luBRZwb3NpdGlvbkxhc3RVcGRhdGVkQ1BGBRFwb3NpdGlvblRpbWVzdGFtcAUNdW5yZWFsaXplZFBubAQMcmVtYWluTWFyZ2luCAUNJHQwMzAwNTUzMDI2NwJfMQQHYmFkRGVidAgFDSR0MDMwMDU1MzAyNjcCXzIJAQ9jYWxjTWFyZ2luUmF0aW8DBQxyZW1haW5NYXJnaW4FB2JhZERlYnQFEHBvc2l0aW9uTm90aW9uYWwBDmdldE1hcmdpblJhdGlvAgdfdHJhZGVyCl9kaXJlY3Rpb24JARZnZXRNYXJnaW5SYXRpb0J5T3B0aW9uAwUHX3RyYWRlcgUKX2RpcmVjdGlvbgUPUE5MX09QVElPTl9TUE9UARtnZXRQYXJ0aWFsTGlxdWlkYXRpb25BbW91bnQCB190cmFkZXINX3Bvc2l0aW9uU2l6ZQQMbWF4aW11bVJhdGlvCQEEdm1heAIJARdwYXJ0aWFsTGlxdWlkYXRpb25SYXRpbwAJAGUCBQxERUNJTUFMX1VOSVQJAQRkaXZkAgkBDmdldE1hcmdpblJhdGlvAgUHX3RyYWRlcgkBDGdldERpcmVjdGlvbgEFDV9wb3NpdGlvblNpemUJARZtYWludGVuYW5jZU1hcmdpblJhdGlvAAQYbWF4RXhjaGFuZ2VkUG9zaXRpb25TaXplCQEEbXVsZAIJAQNhYnMBBQ1fcG9zaXRpb25TaXplBQxtYXhpbXVtUmF0aW8ECnN3YXBSZXN1bHQJAQpzd2FwT3V0cHV0AwkAZgIFDV9wb3NpdGlvblNpemUAAAUYbWF4RXhjaGFuZ2VkUG9zaXRpb25TaXplBwQcbWF4RXhjaGFuZ2VkUXVvdGVBc3NldEFtb3VudAgFCnN3YXBSZXN1bHQCXzEEC3ByaWNlSW1wYWN0CAUKc3dhcFJlc3VsdAJfNwMJAGYCCQEObWF4UHJpY2VJbXBhY3QABQtwcmljZUltcGFjdAUYbWF4RXhjaGFuZ2VkUG9zaXRpb25TaXplCQEEbXVsZAIJAQNhYnMBBQ1fcG9zaXRpb25TaXplCQEXcGFydGlhbExpcXVpZGF0aW9uUmF0aW8AARVpbnRlcm5hbENsb3NlUG9zaXRpb24IB190cmFkZXIKX2RpcmVjdGlvbgVfc2l6ZQRfZmVlFF9taW5RdW90ZUFzc2V0QW1vdW50DF9hZGRUb01hcmdpbhRfY2hlY2tNYXhQcmljZUltcGFjdApfbGlxdWlkYXRlBA0kdDAzMTQzMDMxNTk4CQELZ2V0UG9zaXRpb24CBQdfdHJhZGVyBQpfZGlyZWN0aW9uBA9vbGRQb3NpdGlvblNpemUIBQ0kdDAzMTQzMDMxNTk4Al8xBBFvbGRQb3NpdGlvbk1hcmdpbggFDSR0MDMxNDMwMzE1OTgCXzIEF29sZFBvc2l0aW9uT3Blbk5vdGlvbmFsCAUNJHQwMzE0MzAzMTU5OAJfMwQUb2xkUG9zaXRpb25Mc3RVcGRDUEYIBQ0kdDAzMTQzMDMxNTk4Al80BBRvbGRQb3NpdGlvblRpbWVzdGFtcAgFDSR0MDMxNDMwMzE1OTgCXzUEDmlzTG9uZ1Bvc2l0aW9uCQBmAgUPb2xkUG9zaXRpb25TaXplAAAEEmFic09sZFBvc2l0aW9uU2l6ZQkBA2FicwEFD29sZFBvc2l0aW9uU2l6ZQMDCQBnAgUSYWJzT2xkUG9zaXRpb25TaXplBQVfc2l6ZQkAZgIFBV9zaXplAAAHBA5pc1BhcnRpYWxDbG9zZQkAZgIFEmFic09sZFBvc2l0aW9uU2l6ZQUFX3NpemUEDSR0MDMxODkwMzIzNDEJAQpzd2FwT3V0cHV0AwkAZgIFD29sZFBvc2l0aW9uU2l6ZQAABQVfc2l6ZQUUX2NoZWNrTWF4UHJpY2VJbXBhY3QEGWV4Y2hhbmdlZFF1b3RlQXNzZXRBbW91bnQIBQ0kdDAzMTg5MDMyMzQxAl8xBBZxdW90ZUFzc2V0UmVzZXJ2ZUFmdGVyCAUNJHQwMzE4OTAzMjM0MQJfMgQVYmFzZUFzc2V0UmVzZXJ2ZUFmdGVyCAUNJHQwMzE4OTAzMjM0MQJfMwQWdG90YWxQb3NpdGlvblNpemVBZnRlcggFDSR0MDMxODkwMzIzNDECXzQEFWV4Y2hhbmdlZFBvc2l0aW9uU2l6ZQMJAGYCBQ9vbGRQb3NpdGlvblNpemUAAAkBAS0BBQVfc2l6ZQUFX3NpemUEDSR0MDMyNTU2MzI3ODAJASNnZXRQb3NpdGlvbk5vdGlvbmFsQW5kVW5yZWFsaXplZFBubAMFB190cmFkZXIFCl9kaXJlY3Rpb24FD1BOTF9PUFRJT05fU1BPVAQTb2xkUG9zaXRpb25Ob3Rpb25hbAgFDSR0MDMyNTU2MzI3ODACXzEEDXVucmVhbGl6ZWRQbmwIBQ0kdDAzMjU1NjMyNzgwAl8yBA1yZWFsaXplZFJhdGlvCQEEZGl2ZAIJAQNhYnMBBRVleGNoYW5nZWRQb3NpdGlvblNpemUFEmFic09sZFBvc2l0aW9uU2l6ZQQLcmVhbGl6ZWRQbmwJAQRtdWxkAgUNdW5yZWFsaXplZFBubAUNcmVhbGl6ZWRSYXRpbwQNJHQwMzMxMjEzMzM2NwkBMGNhbGNSZW1haW5NYXJnaW5XaXRoRnVuZGluZ1BheW1lbnRBbmRSb2xsb3ZlckZlZQUFD29sZFBvc2l0aW9uU2l6ZQURb2xkUG9zaXRpb25NYXJnaW4FFG9sZFBvc2l0aW9uTHN0VXBkQ1BGBRRvbGRQb3NpdGlvblRpbWVzdGFtcAUNdW5yZWFsaXplZFBubAQScmVtYWluTWFyZ2luQmVmb3JlCAUNJHQwMzMxMjEzMzM2NwJfMQQCeDEIBQ0kdDAzMzEyMTMzMzY3Al8yBAJ4MggFDSR0MDMzMTIxMzMzNjcCXzMEC3JvbGxvdmVyRmVlCAUNJHQwMzMxMjEzMzM2NwJfNAQPcG9zaXRpb25CYWREZWJ0CAkBMGNhbGNSZW1haW5NYXJnaW5XaXRoRnVuZGluZ1BheW1lbnRBbmRSb2xsb3ZlckZlZQUFD29sZFBvc2l0aW9uU2l6ZQURb2xkUG9zaXRpb25NYXJnaW4FFG9sZFBvc2l0aW9uTHN0VXBkQ1BGBRRvbGRQb3NpdGlvblRpbWVzdGFtcAULcmVhbGl6ZWRQbmwCXzIEEHJlYWxpemVkQ2xvc2VGZWUJAQRtdWxkAgkBBG11bGQCBRNvbGRQb3NpdGlvbk5vdGlvbmFsBQ1yZWFsaXplZFJhdGlvBQRfZmVlBBJ1bnJlYWxpemVkUG5sQWZ0ZXIJAGUCBQ11bnJlYWxpemVkUG5sBQtyZWFsaXplZFBubAQScmVtYWluT3Blbk5vdGlvbmFsAwkAZgIFD29sZFBvc2l0aW9uU2l6ZQAACQBlAgkAZQIFE29sZFBvc2l0aW9uTm90aW9uYWwFGWV4Y2hhbmdlZFF1b3RlQXNzZXRBbW91bnQFEnVucmVhbGl6ZWRQbmxBZnRlcgkAZQIJAGQCBRJ1bnJlYWxpemVkUG5sQWZ0ZXIFE29sZFBvc2l0aW9uTm90aW9uYWwFGWV4Y2hhbmdlZFF1b3RlQXNzZXRBbW91bnQED25ld1Bvc2l0aW9uU2l6ZQkAZAIFD29sZFBvc2l0aW9uU2l6ZQUVZXhjaGFuZ2VkUG9zaXRpb25TaXplBA0kdDAzNDc3MzM1MTU5AwkAAAIFD25ld1Bvc2l0aW9uU2l6ZQAACQCUCgIAAAAACQCUCgIJAQNhYnMBBRJyZW1haW5PcGVuTm90aW9uYWwJAR9sYXRlc3RDdW11bGF0aXZlUHJlbWl1bUZyYWN0aW9uAQUPbmV3UG9zaXRpb25TaXplBBduZXdQb3NpdGlvbk9wZW5Ob3Rpb25hbAgFDSR0MDM0NzczMzUxNTkCXzEEFG5ld1Bvc2l0aW9uTHN0VXBkQ1BGCAUNJHQwMzQ3NzMzNTE1OQJfMgQRb3Blbk5vdGlvbmFsRGVsdGEJAGUCBRdvbGRQb3NpdGlvbk9wZW5Ob3Rpb25hbAUXbmV3UG9zaXRpb25PcGVuTm90aW9uYWwEC21hcmdpblJhdGlvCQEWZ2V0TWFyZ2luUmF0aW9CeU9wdGlvbgMFB190cmFkZXIFCl9kaXJlY3Rpb24FD1BOTF9PUFRJT05fU1BPVAQebmV3UG9zaXRpb25NYXJnaW5XaXRoU2FtZVJhdGlvAwkAZgIFD29sZFBvc2l0aW9uU2l6ZQAACQBlAgkBBG11bGQCCQBkAgUXbmV3UG9zaXRpb25PcGVuTm90aW9uYWwFEnVucmVhbGl6ZWRQbmxBZnRlcgULbWFyZ2luUmF0aW8FEnVucmVhbGl6ZWRQbmxBZnRlcgkAZQIJAQRtdWxkAgkAZQIFF25ld1Bvc2l0aW9uT3Blbk5vdGlvbmFsBRJ1bnJlYWxpemVkUG5sQWZ0ZXIFC21hcmdpblJhdGlvBRJ1bnJlYWxpemVkUG5sQWZ0ZXIEEW1hcmdpblRvVHJhZGVyUmF3CQBlAgkAZQIFEnJlbWFpbk1hcmdpbkJlZm9yZQkAZAIFHm5ld1Bvc2l0aW9uTWFyZ2luV2l0aFNhbWVSYXRpbwUSdW5yZWFsaXplZFBubEFmdGVyBRByZWFsaXplZENsb3NlRmVlBA5tYXJnaW5Ub1RyYWRlcgMJAGYCAAAFEW1hcmdpblRvVHJhZGVyUmF3AwUKX2xpcXVpZGF0ZQAACQACAQI3SW52YWxpZCBpbnRlcm5hbENsb3NlUG9zaXRpb24gcGFyYW1zOiB1bmFibGUgdG8gcGF5IGZlZQURbWFyZ2luVG9UcmFkZXJSYXcEEW5ld1Bvc2l0aW9uTWFyZ2luAwUMX2FkZFRvTWFyZ2luCQBkAgUebmV3UG9zaXRpb25NYXJnaW5XaXRoU2FtZVJhdGlvBQ5tYXJnaW5Ub1RyYWRlcgUebmV3UG9zaXRpb25NYXJnaW5XaXRoU2FtZVJhdGlvAwMJAQIhPQIFFF9taW5RdW90ZUFzc2V0QW1vdW50AAAJAGYCBRRfbWluUXVvdGVBc3NldEFtb3VudAUZZXhjaGFuZ2VkUXVvdGVBc3NldEFtb3VudAcJAAIBCQCsAgIJAKwCAgkArAICAg1MaW1pdCBlcnJvcjogCQCkAwEFGWV4Y2hhbmdlZFF1b3RlQXNzZXRBbW91bnQCAyA8IAkApAMBBRRfbWluUXVvdGVBc3NldEFtb3VudAkAowoRBQ9uZXdQb3NpdGlvblNpemUFEW5ld1Bvc2l0aW9uTWFyZ2luBRduZXdQb3NpdGlvbk9wZW5Ob3Rpb25hbAUUbmV3UG9zaXRpb25Mc3RVcGRDUEYFD3Bvc2l0aW9uQmFkRGVidAULcmVhbGl6ZWRQbmwDAwUMX2FkZFRvTWFyZ2luBQ5pc1BhcnRpYWxDbG9zZQcAAAUObWFyZ2luVG9UcmFkZXIFFnF1b3RlQXNzZXRSZXNlcnZlQWZ0ZXIFFWJhc2VBc3NldFJlc2VydmVBZnRlcgUWdG90YWxQb3NpdGlvblNpemVBZnRlcgkAZQIJARRvcGVuSW50ZXJlc3ROb3Rpb25hbAAFEW9wZW5Ob3Rpb25hbERlbHRhCQBlAgkBFXRvdGFsTG9uZ1Bvc2l0aW9uU2l6ZQADBQ5pc0xvbmdQb3NpdGlvbgkBA2FicwEFFWV4Y2hhbmdlZFBvc2l0aW9uU2l6ZQAACQBlAgkBFnRvdGFsU2hvcnRQb3NpdGlvblNpemUAAwkBASEBBQ5pc0xvbmdQb3NpdGlvbgkBA2FicwEFFWV4Y2hhbmdlZFBvc2l0aW9uU2l6ZQAACQBlAgkBEG9wZW5JbnRlcmVzdExvbmcAAwUOaXNMb25nUG9zaXRpb24FEW9wZW5Ob3Rpb25hbERlbHRhAAAJAGUCCQERb3BlbkludGVyZXN0U2hvcnQAAwkBASEBBQ5pc0xvbmdQb3NpdGlvbgURb3Blbk5vdGlvbmFsRGVsdGEAAAkAZAIFEHJlYWxpemVkQ2xvc2VGZWUFC3JvbGxvdmVyRmVlBRlleGNoYW5nZWRRdW90ZUFzc2V0QW1vdW50CQACAQkArAICCQCsAgIJAKwCAgI9SW52YWxpZCBpbnRlcm5hbENsb3NlUG9zaXRpb24gcGFyYW1zOiBpbnZhbGlkIHBvc2l0aW9uIHNpemU6IAkApAMBBQVfc2l6ZQIGIG1heDogCQCkAwEFEmFic09sZFBvc2l0aW9uU2l6ZQETZ2V0VGVybWluYWxBbW1TdGF0ZQAEDV9wb3NpdGlvblNpemUJARF0b3RhbFBvc2l0aW9uU2l6ZQADCQAAAgUNX3Bvc2l0aW9uU2l6ZQAACQCUCgIJAQZxdEFzdFIACQEGYnNBc3RSAAQJZGlyZWN0aW9uCQBmAgUNX3Bvc2l0aW9uU2l6ZQAABA0kdDAzODQwNjM4NTg1CQEKc3dhcE91dHB1dAMFCWRpcmVjdGlvbgkBA2FicwEFDV9wb3NpdGlvblNpemUHBBVjdXJyZW50TmV0TWFya2V0VmFsdWUIBQ0kdDAzODQwNjM4NTg1Al8xBBl0ZXJtaW5hbFF1b3RlQXNzZXRSZXNlcnZlCAUNJHQwMzg0MDYzODU4NQJfMgQYdGVybWluYWxCYXNlQXNzZXRSZXNlcnZlCAUNJHQwMzg0MDYzODU4NQJfMwkAlAoCBRl0ZXJtaW5hbFF1b3RlQXNzZXRSZXNlcnZlBRh0ZXJtaW5hbEJhc2VBc3NldFJlc2VydmUBE2dldFF1b3RlQXNzZXRXZWlnaHQEEGJhc2VBc3NldFJlc2VydmURdG90YWxQb3NpdGlvblNpemURcXVvdGVBc3NldFJlc2VydmULdGFyZ2V0UHJpY2UEAWIJALYCAQUQYmFzZUFzc2V0UmVzZXJ2ZQQCc3oJALYCAQURdG90YWxQb3NpdGlvblNpemUEAXEJALYCAQURcXVvdGVBc3NldFJlc2VydmUEAXAJALYCAQULdGFyZ2V0UHJpY2UEAWsJAQVibXVsZAIFAXEFAWIEBG5ld0IJALcCAgUBYgUCc3oEBG5ld1EJAQViZGl2ZAIFAWsFBG5ld0IEAXoJAQViZGl2ZAIFBG5ld1EFBG5ld0IEBnJlc3VsdAkBBWJkaXZkAgUBcAUBegkAoAMBBQZyZXN1bHQBFGdldFN5bmNUZXJtaW5hbFByaWNlAw5fdGVybWluYWxQcmljZQdfcXRBc3RSB19ic0FzdFIEDV9wb3NpdGlvblNpemUJARF0b3RhbFBvc2l0aW9uU2l6ZQADCQAAAgUNX3Bvc2l0aW9uU2l6ZQAABAluZXdRdEFzdFcJAQRkaXZkAgkBBG11bGQCBQ5fdGVybWluYWxQcmljZQUHX2JzQXN0UgUHX3F0QXN0UgkAlQoDBQluZXdRdEFzdFcFDERFQ0lNQUxfVU5JVAAABAlkaXJlY3Rpb24JAGYCBQ1fcG9zaXRpb25TaXplAAAEFWN1cnJlbnROZXRNYXJrZXRWYWx1ZQgJAQpzd2FwT3V0cHV0AwUJZGlyZWN0aW9uCQEDYWJzAQUNX3Bvc2l0aW9uU2l6ZQcCXzEECW5ld1F0QXN0VwkBE2dldFF1b3RlQXNzZXRXZWlnaHQEBQdfYnNBc3RSBQ1fcG9zaXRpb25TaXplBQdfcXRBc3RSBQ5fdGVybWluYWxQcmljZQQJbmV3QnNBc3RXBQxERUNJTUFMX1VOSVQEDW1hcmdpblRvVmF1bHQICQErZ2V0UG9zaXRpb25Ob3Rpb25hbEFuZFVucmVhbGl6ZWRQbmxCeVZhbHVlcwcFDV9wb3NpdGlvblNpemUFFWN1cnJlbnROZXRNYXJrZXRWYWx1ZQUHX3F0QXN0UgUJbmV3UXRBc3RXBQdfYnNBc3RSBQluZXdCc0FzdFcFD1BOTF9PUFRJT05fU1BPVAJfMgkAlQoDBQluZXdRdEFzdFcFCW5ld0JzQXN0VwUNbWFyZ2luVG9WYXVsdAEKZ2V0RnVuZGluZwAED3VuZGVybHlpbmdQcmljZQkBDmdldE9yYWNsZVByaWNlAAQJc3BvdFByaWNlCQEMZ2V0U3BvdFByaWNlAAQHcHJlbWl1bQkAZQIFCXNwb3RQcmljZQUPdW5kZXJseWluZ1ByaWNlAwMJAQ5pc01hcmtldENsb3NlZAAGAwkAAAIJAQtmdW5kaW5nTW9kZQAFEkZVTkRJTkdfQVNZTU1FVFJJQwMJAAACCQEWdG90YWxTaG9ydFBvc2l0aW9uU2l6ZQAAAAYJAAACCQEVdG90YWxMb25nUG9zaXRpb25TaXplAAAABwkAlQoDAAAAAAAAAwkAZgIAAAUHcHJlbWl1bQQUc2hvcnRQcmVtaXVtRnJhY3Rpb24JAQRkaXZkAgkBBG11bGQCBQdwcmVtaXVtCQEUZnVuZGluZ1BlcmlvZERlY2ltYWwABQdPTkVfREFZAwkAAAIJAQtmdW5kaW5nTW9kZQAFEkZVTkRJTkdfQVNZTU1FVFJJQwQTbG9uZ1ByZW1pdW1GcmFjdGlvbgkBBGRpdmQCCQEEbXVsZAIFFHNob3J0UHJlbWl1bUZyYWN0aW9uCQEWdG90YWxTaG9ydFBvc2l0aW9uU2l6ZQAJARV0b3RhbExvbmdQb3NpdGlvblNpemUACQCVCgMFFHNob3J0UHJlbWl1bUZyYWN0aW9uBRNsb25nUHJlbWl1bUZyYWN0aW9uAAAEGXNob3J0VG90YWxQcmVtaXVtRnJhY3Rpb24JAQNhYnMBCQEEbXVsZAIFFHNob3J0UHJlbWl1bUZyYWN0aW9uCQEWdG90YWxTaG9ydFBvc2l0aW9uU2l6ZQAEGGxvbmdUb3RhbFByZW1pdW1GcmFjdGlvbgkBA2FicwEJAQRtdWxkAgUUc2hvcnRQcmVtaXVtRnJhY3Rpb24JARV0b3RhbExvbmdQb3NpdGlvblNpemUABA5wcmVtaXVtVG9WYXVsdAkAZQIFGXNob3J0VG90YWxQcmVtaXVtRnJhY3Rpb24FGGxvbmdUb3RhbFByZW1pdW1GcmFjdGlvbgkAlQoDBRRzaG9ydFByZW1pdW1GcmFjdGlvbgUUc2hvcnRQcmVtaXVtRnJhY3Rpb24FDnByZW1pdW1Ub1ZhdWx0BBNsb25nUHJlbWl1bUZyYWN0aW9uCQEEZGl2ZAIJAQRtdWxkAgUHcHJlbWl1bQkBFGZ1bmRpbmdQZXJpb2REZWNpbWFsAAUHT05FX0RBWQMJAAACCQELZnVuZGluZ01vZGUABRJGVU5ESU5HX0FTWU1NRVRSSUMEFHNob3J0UHJlbWl1bUZyYWN0aW9uCQEEZGl2ZAIJAQRtdWxkAgUTbG9uZ1ByZW1pdW1GcmFjdGlvbgkBFXRvdGFsTG9uZ1Bvc2l0aW9uU2l6ZQAJARZ0b3RhbFNob3J0UG9zaXRpb25TaXplAAkAlQoDBRRzaG9ydFByZW1pdW1GcmFjdGlvbgUTbG9uZ1ByZW1pdW1GcmFjdGlvbgAABBhsb25nVG90YWxQcmVtaXVtRnJhY3Rpb24JAQNhYnMBCQEEbXVsZAIFE2xvbmdQcmVtaXVtRnJhY3Rpb24JARV0b3RhbExvbmdQb3NpdGlvblNpemUABBlzaG9ydFRvdGFsUHJlbWl1bUZyYWN0aW9uCQEDYWJzAQkBBG11bGQCBRNsb25nUHJlbWl1bUZyYWN0aW9uCQEWdG90YWxTaG9ydFBvc2l0aW9uU2l6ZQAEDnByZW1pdW1Ub1ZhdWx0CQBlAgUYbG9uZ1RvdGFsUHJlbWl1bUZyYWN0aW9uBRlzaG9ydFRvdGFsUHJlbWl1bUZyYWN0aW9uCQCVCgMFE2xvbmdQcmVtaXVtRnJhY3Rpb24FE2xvbmdQcmVtaXVtRnJhY3Rpb24FDnByZW1pdW1Ub1ZhdWx0AQ5nZXRBZGp1c3RlZEZlZQILX2FydGlmYWN0SWQQX2Jhc2VGZWVEaXNjb3VudAQKYmFzZUZlZVJhdwkBA2ZlZQAEB2Jhc2VGZWUJAQRtdWxkAgUKYmFzZUZlZVJhdwUQX2Jhc2VGZWVEaXNjb3VudAQNJHQwNDMyNDk0Mzc0NAMJAQIhPQIFC19hcnRpZmFjdElkAgAEDGFydGlmYWN0S2luZAkBBHN0ckECCQERbmZ0TWFuYWdlckFkZHJlc3MACQEOdG9Db21wb3NpdGVLZXkCBQxrX3Rva2VuX3R5cGUFC19hcnRpZmFjdElkAwkAAAIFDGFydGlmYWN0S2luZAUYRkVFX1JFRFVDVElPTl9UT0tFTl9UWVBFBAlyZWR1Y3Rpb24JAQRpbnRBAgkBEW5mdE1hbmFnZXJBZGRyZXNzAAkBDnRvQ29tcG9zaXRlS2V5AgUNa190b2tlbl9wYXJhbQULX2FydGlmYWN0SWQEC2FkanVzdGVkRmVlCQEEbXVsZAIFB2Jhc2VGZWUFCXJlZHVjdGlvbgkAlAoCBQthZGp1c3RlZEZlZQYJAAIBAhlJbnZhbGlkIGF0dGFjaGVkIGFydGlmYWN0CQCUCgIFB2Jhc2VGZWUHBAthZGp1c3RlZEZlZQgFDSR0MDQzMjQ5NDM3NDQCXzEEDGJ1cm5BcnRpZmFjdAgFDSR0MDQzMjQ5NDM3NDQCXzIJAJQKAgULYWRqdXN0ZWRGZWUFDGJ1cm5BcnRpZmFjdAEYZ2V0Rm9yVHJhZGVyV2l0aEFydGlmYWN0AgdfdHJhZGVyC19hcnRpZmFjdElkBBBkb0dldEZlZURpc2NvdW50CQD8BwQJAQxtaW5lckFkZHJlc3MAAhJjb21wdXRlRmVlRGlzY291bnQJAMwIAgUHX3RyYWRlcgUDbmlsBQNuaWwDCQAAAgUQZG9HZXRGZWVEaXNjb3VudAUQZG9HZXRGZWVEaXNjb3VudAQLZmVlRGlzY291bnQEByRtYXRjaDAFEGRvR2V0RmVlRGlzY291bnQDCQABAgUHJG1hdGNoMAIDSW50BAF4BQckbWF0Y2gwBQF4CQACAQIhSW52YWxpZCBjb21wdXRlRmVlRGlzY291bnQgcmVzdWx0BA0kdDA0NDA5MDQ0MTY0CQEOZ2V0QWRqdXN0ZWRGZWUCBQtfYXJ0aWZhY3RJZAULZmVlRGlzY291bnQEC2FkanVzdGVkRmVlCAUNJHQwNDQwOTA0NDE2NAJfMQQMYnVybkFydGlmYWN0CAUNJHQwNDQwOTA0NDE2NAJfMgkAlAoCBQthZGp1c3RlZEZlZQUMYnVybkFydGlmYWN0CQACAQIkU3RyaWN0IHZhbHVlIGlzIG5vdCBlcXVhbCB0byBpdHNlbGYuAQ1nZXRBcnRpZmFjdElkAQFpBAphcnRpZmFjdElkAwkAZgIJAJADAQgFAWkIcGF5bWVudHMAAQkA2AQBCQETdmFsdWVPckVycm9yTWVzc2FnZQIICQCRAwIIBQFpCHBheW1lbnRzAAEHYXNzZXRJZAISSW52YWxpZCBhcnRpZmFjdElkAgAFCmFydGlmYWN0SWQBDWRpc3RyaWJ1dGVGZWUBCl9mZWVBbW91bnQEDGZlZVRvU3Rha2VycwkBBG11bGQCBQpfZmVlQW1vdW50CQETZmVlVG9TdGFrZXJzUGVyY2VudAAECmZlZVRvVmF1bHQJAGUCBQpfZmVlQW1vdW50BQxmZWVUb1N0YWtlcnMJAJQKAgUMZmVlVG9TdGFrZXJzBQpmZWVUb1ZhdWx0AQ51cGRhdGVTZXR0aW5ncxEQX2luaXRNYXJnaW5SYXRpbwRfbW1yFF9saXF1aWRhdGlvbkZlZVJhdGlvDl9mdW5kaW5nUGVyaW9kBF9mZWUMX3NwcmVhZExpbWl0D19tYXhQcmljZUltcGFjdBhfcGFydGlhbExpcXVpZGF0aW9uUmF0aW8PX21heFByaWNlU3ByZWFkEF9tYXhPcGVuTm90aW9uYWwUX2ZlZVRvU3Rha2Vyc1BlcmNlbnQPX21heE9yYWNsZURlbGF5DF9yb2xsb3ZlckZlZQxfZnVuZGluZ01vZGULX29yYWNsZU1vZGUTX21pbkluaXRNYXJnaW5SYXRpbw1fcG9zaXRpb25Nb2RlCQDMCAIJAQxJbnRlZ2VyRW50cnkCBRFrX2luaXRNYXJnaW5SYXRpbwUQX2luaXRNYXJnaW5SYXRpbwkAzAgCCQEMSW50ZWdlckVudHJ5AgUUa19taW5Jbml0TWFyZ2luUmF0aW8FE19taW5Jbml0TWFyZ2luUmF0aW8JAMwIAgkBDEludGVnZXJFbnRyeQIFGGtfbWFpbnRlbmFuY2VNYXJnaW5SYXRpbwUEX21tcgkAzAgCCQEMSW50ZWdlckVudHJ5AgUVa19saXF1aWRhdGlvbkZlZVJhdGlvBRRfbGlxdWlkYXRpb25GZWVSYXRpbwkAzAgCCQEMSW50ZWdlckVudHJ5AgUPa19mdW5kaW5nUGVyaW9kBQ5fZnVuZGluZ1BlcmlvZAkAzAgCCQEMSW50ZWdlckVudHJ5AgUFa19mZWUFBF9mZWUJAMwIAgkBDEludGVnZXJFbnRyeQIFDWtfc3ByZWFkTGltaXQFDF9zcHJlYWRMaW1pdAkAzAgCCQEMSW50ZWdlckVudHJ5AgUQa19tYXhQcmljZUltcGFjdAUPX21heFByaWNlSW1wYWN0CQDMCAIJAQxJbnRlZ2VyRW50cnkCBRlrX3BhcnRpYWxMaXF1aWRhdGlvblJhdGlvBRhfcGFydGlhbExpcXVpZGF0aW9uUmF0aW8JAMwIAgkBDEludGVnZXJFbnRyeQIFEGtfbWF4UHJpY2VTcHJlYWQFD19tYXhQcmljZVNwcmVhZAkAzAgCCQEMSW50ZWdlckVudHJ5AgURa19tYXhPcGVuTm90aW9uYWwFEF9tYXhPcGVuTm90aW9uYWwJAMwIAgkBDEludGVnZXJFbnRyeQIFFWtfZmVlVG9TdGFrZXJzUGVyY2VudAUUX2ZlZVRvU3Rha2Vyc1BlcmNlbnQJAMwIAgkBDEludGVnZXJFbnRyeQIFEGtfbWF4T3JhY2xlRGVsYXkFD19tYXhPcmFjbGVEZWxheQkAzAgCCQEMSW50ZWdlckVudHJ5AgUNa19yb2xsb3ZlckZlZQUMX3JvbGxvdmVyRmVlCQDMCAIJAQxJbnRlZ2VyRW50cnkCBQ1rX2Z1bmRpbmdNb2RlBQxfZnVuZGluZ01vZGUJAMwIAgkBDEludGVnZXJFbnRyeQIFDGtfb3JhY2xlTW9kZQULX29yYWNsZU1vZGUJAMwIAgkBDEludGVnZXJFbnRyeQIFDmtfcG9zaXRpb25Nb2RlBQ1fcG9zaXRpb25Nb2RlBQNuaWwBDXVwZGF0ZUZ1bmRpbmcFEV9uZXh0RnVuZGluZ0Jsb2NrJF9sYXRlc3RMb25nQ3VtdWxhdGl2ZVByZW1pdW1GcmFjdGlvbiVfbGF0ZXN0U2hvcnRDdW11bGF0aXZlUHJlbWl1bUZyYWN0aW9uEF9sb25nRnVuZGluZ1JhdGURX3Nob3J0RnVuZGluZ1JhdGUJAMwIAgkBDEludGVnZXJFbnRyeQIFEmtfbmV4dEZ1bmRpbmdCbG9jawURX25leHRGdW5kaW5nQmxvY2sJAMwIAgkBDEludGVnZXJFbnRyeQIFJWtfbGF0ZXN0TG9uZ0N1bXVsYXRpdmVQcmVtaXVtRnJhY3Rpb24FJF9sYXRlc3RMb25nQ3VtdWxhdGl2ZVByZW1pdW1GcmFjdGlvbgkAzAgCCQEMSW50ZWdlckVudHJ5AgUma19sYXRlc3RTaG9ydEN1bXVsYXRpdmVQcmVtaXVtRnJhY3Rpb24FJV9sYXRlc3RTaG9ydEN1bXVsYXRpdmVQcmVtaXVtRnJhY3Rpb24JAMwIAgkBDEludGVnZXJFbnRyeQIFEWtfbG9uZ0Z1bmRpbmdSYXRlBRBfbG9uZ0Z1bmRpbmdSYXRlCQDMCAIJAQxJbnRlZ2VyRW50cnkCBRJrX3Nob3J0RnVuZGluZ1JhdGUFEV9zaG9ydEZ1bmRpbmdSYXRlBQNuaWwBH2luY3JlbWVudFBvc2l0aW9uU2VxdWVuY2VOdW1iZXIDDl9pc05ld1Bvc2l0aW9uB190cmFkZXIKX2RpcmVjdGlvbgQLcG9zaXRpb25LZXkJAKwCAgkArAICBQdfdHJhZGVyAgFfCQCkAwEFCl9kaXJlY3Rpb24DBQ5faXNOZXdQb3NpdGlvbgQPY3VycmVudFNlcXVlbmNlCQEMbGFzdFNlcXVlbmNlAAkAzAgCCQEMSW50ZWdlckVudHJ5AgkBDnRvQ29tcG9zaXRlS2V5AgUSa19wb3NpdGlvblNlcXVlbmNlBQtwb3NpdGlvbktleQkAZAIFD2N1cnJlbnRTZXF1ZW5jZQABCQDMCAIJAQxJbnRlZ2VyRW50cnkCBQprX3NlcXVlbmNlCQBkAgUPY3VycmVudFNlcXVlbmNlAAEFA25pbAUDbmlsARF1cGRhdGVQb3NpdGlvbkZlZQQOX2lzTmV3UG9zaXRpb24HX3RyYWRlcgpfZGlyZWN0aW9uBF9mZWUEC3Bvc2l0aW9uS2V5CQCsAgIJAKwCAgUHX3RyYWRlcgIBXwkApAMBBQpfZGlyZWN0aW9uAwUOX2lzTmV3UG9zaXRpb24JAMwIAgkBDEludGVnZXJFbnRyeQIJAQ50b0NvbXBvc2l0ZUtleQIFDWtfcG9zaXRpb25GZWUFC3Bvc2l0aW9uS2V5BQRfZmVlBQNuaWwFA25pbAEOdXBkYXRlUG9zaXRpb24GB190cmFkZXIFX3NpemUHX21hcmdpbg1fb3Blbk5vdGlvbmFsIF9sYXRlc3RDdW11bGF0aXZlUHJlbWl1bUZyYWN0aW9uEF9sYXRlc3RUaW1lc3RhbXAECWRpcmVjdGlvbgkBDGdldERpcmVjdGlvbgEFBV9zaXplBAtwb3NpdGlvbktleQkArAICCQCsAgIFB190cmFkZXICAV8JAKQDAQUJZGlyZWN0aW9uCQDMCAIJAQxJbnRlZ2VyRW50cnkCCQEOdG9Db21wb3NpdGVLZXkCBQ5rX3Bvc2l0aW9uU2l6ZQULcG9zaXRpb25LZXkFBV9zaXplCQDMCAIJAQxJbnRlZ2VyRW50cnkCCQEOdG9Db21wb3NpdGVLZXkCBRBrX3Bvc2l0aW9uTWFyZ2luBQtwb3NpdGlvbktleQUHX21hcmdpbgkAzAgCCQEMSW50ZWdlckVudHJ5AgkBDnRvQ29tcG9zaXRlS2V5AgUWa19wb3NpdGlvbk9wZW5Ob3Rpb25hbAULcG9zaXRpb25LZXkFDV9vcGVuTm90aW9uYWwJAMwIAgkBDEludGVnZXJFbnRyeQIJAQ50b0NvbXBvc2l0ZUtleQIFLmtfcG9zaXRpb25MYXN0VXBkYXRlZEN1bXVsYXRpdmVQcmVtaXVtRnJhY3Rpb24FC3Bvc2l0aW9uS2V5BSBfbGF0ZXN0Q3VtdWxhdGl2ZVByZW1pdW1GcmFjdGlvbgkAzAgCCQEMSW50ZWdlckVudHJ5AgkBDnRvQ29tcG9zaXRlS2V5AgUea19wb3NpdGlvbkxhc3RVcGRhdGVkVGltZXN0YW1wBQtwb3NpdGlvbktleQUQX2xhdGVzdFRpbWVzdGFtcAUDbmlsARF1cGRhdGVBbW1SZXNlcnZlcwIHX3F0QXN0UgdfYnNBc3RSAwMJAGYCAAAFB19xdEFzdFIGCQBmAgAABQdfYnNBc3RSCQACAQIhSW52YWxpZCBhbW91bnQgdG8gdXBkYXRlIHJlc2VydmVzAwMJAQIhPQIFB19xdEFzdFIJAQdxdEFzdFIwAAYJAQIhPQIFB19ic0FzdFIJAQdic0FzdFIwAAkAzAgCCQEMSW50ZWdlckVudHJ5AgUTa19xdW90ZUFzc2V0UmVzZXJ2ZQUHX3F0QXN0UgkAzAgCCQEMSW50ZWdlckVudHJ5AgUSa19iYXNlQXNzZXRSZXNlcnZlBQdfYnNBc3RSBQNuaWwFA25pbAEQdXBkYXRlQW1tV2VpZ2h0cwIHX3F0QXN0VwdfYnNBc3RXAwMJAQIhPQIFB19xdEFzdFcJAQZxdEFzdFcABgkBAiE9AgUHX2JzQXN0VwkBBmJzQXN0VwAJAMwIAgkBDEludGVnZXJFbnRyeQIFEmtfcXVvdGVBc3NldFdlaWdodAUHX3F0QXN0VwkAzAgCCQEMSW50ZWdlckVudHJ5AgURa19iYXNlQXNzZXRXZWlnaHQFB19ic0FzdFcFA25pbAUDbmlsAQl1cGRhdGVBbW0IB19xdEFzdFIHX2JzQXN0UhdfdG90YWxQb3NpdGlvblNpemVBZnRlchVfb3BlbkludGVyZXN0Tm90aW9uYWwWX3RvdGFsTG9uZ1Bvc2l0aW9uU2l6ZRdfdG90YWxTaG9ydFBvc2l0aW9uU2l6ZRZfdG90YWxMb25nT3Blbk5vdGlvbmFsF190b3RhbFNob3J0T3Blbk5vdGlvbmFsBAdfcXRBc3RXCQEGcXRBc3RXAAQHX2JzQXN0VwkBBmJzQXN0VwADCQECIT0CCQBlAgUWX3RvdGFsTG9uZ1Bvc2l0aW9uU2l6ZQUXX3RvdGFsU2hvcnRQb3NpdGlvblNpemUFF190b3RhbFBvc2l0aW9uU2l6ZUFmdGVyCQACAQkArAICCQCsAgIJAKwCAgkArAICCQCsAgICGEludmFsaWQgQU1NIHN0YXRlIGRhdGE6IAkApAMBBRZfdG90YWxMb25nUG9zaXRpb25TaXplAgQgLSAgCQCkAwEFF190b3RhbFNob3J0UG9zaXRpb25TaXplAgQgIT0gCQCkAwEFF190b3RhbFBvc2l0aW9uU2l6ZUFmdGVyCQDOCAIJARF1cGRhdGVBbW1SZXNlcnZlcwIFB19xdEFzdFIFB19ic0FzdFIJAMwIAgkBDEludGVnZXJFbnRyeQIFE2tfdG90YWxQb3NpdGlvblNpemUFF190b3RhbFBvc2l0aW9uU2l6ZUFmdGVyCQDMCAIJAQxJbnRlZ2VyRW50cnkCBRZrX29wZW5JbnRlcmVzdE5vdGlvbmFsBRVfb3BlbkludGVyZXN0Tm90aW9uYWwJAMwIAgkBDEludGVnZXJFbnRyeQIFF2tfdG90YWxMb25nUG9zaXRpb25TaXplBRZfdG90YWxMb25nUG9zaXRpb25TaXplCQDMCAIJAQxJbnRlZ2VyRW50cnkCBRhrX3RvdGFsU2hvcnRQb3NpdGlvblNpemUFF190b3RhbFNob3J0UG9zaXRpb25TaXplCQDMCAIJAQxJbnRlZ2VyRW50cnkCBRJrX29wZW5JbnRlcmVzdExvbmcFFl90b3RhbExvbmdPcGVuTm90aW9uYWwJAMwIAgkBDEludGVnZXJFbnRyeQIFE2tfb3BlbkludGVyZXN0U2hvcnQFF190b3RhbFNob3J0T3Blbk5vdGlvbmFsBQNuaWwBDmRlbGV0ZVBvc2l0aW9uAgdfdHJhZGVyCl9kaXJlY3Rpb24EC3Bvc2l0aW9uS2V5CQCsAgIJAKwCAgUHX3RyYWRlcgIBXwkApAMBBQpfZGlyZWN0aW9uCQDMCAIJAQtEZWxldGVFbnRyeQEJAQ50b0NvbXBvc2l0ZUtleQIFDmtfcG9zaXRpb25TaXplBQtwb3NpdGlvbktleQkAzAgCCQELRGVsZXRlRW50cnkBCQEOdG9Db21wb3NpdGVLZXkCBRBrX3Bvc2l0aW9uTWFyZ2luBQtwb3NpdGlvbktleQkAzAgCCQELRGVsZXRlRW50cnkBCQEOdG9Db21wb3NpdGVLZXkCBRZrX3Bvc2l0aW9uT3Blbk5vdGlvbmFsBQtwb3NpdGlvbktleQkAzAgCCQELRGVsZXRlRW50cnkBCQEOdG9Db21wb3NpdGVLZXkCBS5rX3Bvc2l0aW9uTGFzdFVwZGF0ZWRDdW11bGF0aXZlUHJlbWl1bUZyYWN0aW9uBQtwb3NpdGlvbktleQkAzAgCCQELRGVsZXRlRW50cnkBCQEOdG9Db21wb3NpdGVLZXkCBQ1rX3Bvc2l0aW9uRmVlBQtwb3NpdGlvbktleQkAzAgCCQELRGVsZXRlRW50cnkBCQEOdG9Db21wb3NpdGVLZXkCBR5rX3Bvc2l0aW9uTGFzdFVwZGF0ZWRUaW1lc3RhbXAFC3Bvc2l0aW9uS2V5BQNuaWwBCHdpdGhkcmF3AghfYWRkcmVzcwdfYW1vdW50BAdiYWxhbmNlCQDwBwIFBHRoaXMJAQpxdW90ZUFzc2V0AAMJAGYCBQdfYW1vdW50BQdiYWxhbmNlCQACAQkArAICCQCsAgIJAKwCAgITVW5hYmxlIHRvIHdpdGhkcmF3IAkApAMBBQdfYW1vdW50AhcgZnJvbSBjb250cmFjdCBiYWxhbmNlIAkApAMBBQdiYWxhbmNlCQDMCAIJAQ5TY3JpcHRUcmFuc2ZlcgMFCF9hZGRyZXNzBQdfYW1vdW50CQEKcXVvdGVBc3NldAAFA25pbAENdXBkYXRlQmFsYW5jZQEIX2JhbGFuY2UDCQBmAgAABQhfYmFsYW5jZQkAAgECB0JhbGFuY2UDAwkAAAIJAQljYmFsYW5jZTAAAAAGCQECIT0CCQEJY2JhbGFuY2UwAAUIX2JhbGFuY2UJAMwIAgkBDEludGVnZXJFbnRyeQIFCWtfYmFsYW5jZQUIX2JhbGFuY2UFA25pbAUDbmlsAQt0cmFuc2ZlckZlZQEBaQkAzAgCCQEOU2NyaXB0VHJhbnNmZXIDCQEOc3Rha2luZ0FkZHJlc3MABQFpCQEKcXVvdGVBc3NldAAFA25pbAEOZG9CdXJuQXJ0aWZhY3QCDV9idXJuQXJ0aWZhY3QBaQMFDV9idXJuQXJ0aWZhY3QJAMwIAgkBBEJ1cm4CCQETdmFsdWVPckVycm9yTWVzc2FnZQIICQCRAwIIBQFpCHBheW1lbnRzAAEHYXNzZXRJZAIQSW52YWxpZCBhcnRpZmFjdAABBQNuaWwFA25pbBcBaQEFcGF1c2UAAwkBAiE9AggFAWkGY2FsbGVyCQEMYWRtaW5BZGRyZXNzAAkAAgECFEludmFsaWQgcGF1c2UgcGFyYW1zCQDMCAIJAQxCb29sZWFuRW50cnkCBQhrX3BhdXNlZAYFA25pbAFpAQd1bnBhdXNlAAMJAQIhPQIIBQFpBmNhbGxlcgkBDGFkbWluQWRkcmVzcwAJAAIBAhZJbnZhbGlkIHVucGF1c2UgcGFyYW1zCQDMCAIJAQxCb29sZWFuRW50cnkCBQhrX3BhdXNlZAcFA25pbAFpAQxzZXRDbG9zZU9ubHkAAwkBAiE9AggFAWkGY2FsbGVyCQEMYWRtaW5BZGRyZXNzAAkAAgECG0ludmFsaWQgc2V0Q2xvc2VPbmx5IHBhcmFtcwkAzAgCCQEMQm9vbGVhbkVudHJ5AgULa19jbG9zZU9ubHkGBQNuaWwBaQEOdW5zZXRDbG9zZU9ubHkAAwkBAiE9AggFAWkGY2FsbGVyCQEMYWRtaW5BZGRyZXNzAAkAAgECHUludmFsaWQgdW5zZXRDbG9zZU9ubHkgcGFyYW1zCQDMCAIJAQxCb29sZWFuRW50cnkCBQtrX2Nsb3NlT25seQcFA25pbAFpAQ9jaGFuZ2VMaXF1aWRpdHkBEV9xdW90ZUFzc2V0QW1vdW50AwMJAQIhPQIIBQFpBmNhbGxlcgkBDGFkbWluQWRkcmVzcwAGCQAAAgURX3F1b3RlQXNzZXRBbW91bnQAAAkAAgECHkludmFsaWQgY2hhbmdlTGlxdWlkaXR5IHBhcmFtcwQHX3F0QXN0UgkBBnF0QXN0UgAEB19ic0FzdFIJAQZic0FzdFIABAdfcXRBc3RXCQEGcXRBc3RXAAQHX2JzQXN0VwkBBmJzQXN0VwAEBXByaWNlCQEEZGl2ZAIJAQRtdWxkAgUHX3F0QXN0UgUHX3F0QXN0VwkBBG11bGQCBQdfYnNBc3RSBQdfYnNBc3RXBAtxdEFzdFJBZnRlcgkAZAIFB19xdEFzdFIFEV9xdW90ZUFzc2V0QW1vdW50BBRiYXNlQXNzZXRBbW91bnRUb0FkZAkAZQIJAQRkaXZkAgkBBG11bGQCBQtxdEFzdFJBZnRlcgUHX3F0QXN0VwUFcHJpY2UFB19ic0FzdFIEC2JzQXN0UkFmdGVyCQBkAgUHX2JzQXN0UgUUYmFzZUFzc2V0QW1vdW50VG9BZGQEDSR0MDUzMDQ5NTMyMDAJARRnZXRTeW5jVGVybWluYWxQcmljZQMJAQ5nZXRPcmFjbGVQcmljZQAFC3F0QXN0UkFmdGVyBQtic0FzdFJBZnRlcgQTbmV3UXVvdGVBc3NldFdlaWdodAgFDSR0MDUzMDQ5NTMyMDACXzEEEm5ld0Jhc2VBc3NldFdlaWdodAgFDSR0MDUzMDQ5NTMyMDACXzIEDW1hcmdpblRvVmF1bHQIBQ0kdDA1MzA0OTUzMjAwAl8zBA1kb0V4Y2hhbmdlUG5MAwkBAiE9AgUNbWFyZ2luVG9WYXVsdAAABA1kb0V4Y2hhbmdlUG5MCQD8BwQJAQx2YXVsdEFkZHJlc3MAAhVleGNoYW5nZUZyZWVBbmRMb2NrZWQJAMwIAgUNbWFyZ2luVG9WYXVsdAUDbmlsBQNuaWwDCQAAAgUNZG9FeGNoYW5nZVBuTAUNZG9FeGNoYW5nZVBuTAUDbmlsCQACAQIkU3RyaWN0IHZhbHVlIGlzIG5vdCBlcXVhbCB0byBpdHNlbGYuBQNuaWwDCQAAAgUNZG9FeGNoYW5nZVBuTAUNZG9FeGNoYW5nZVBuTAkAzggCCQERdXBkYXRlQW1tUmVzZXJ2ZXMCBQtxdEFzdFJBZnRlcgULYnNBc3RSQWZ0ZXIJARB1cGRhdGVBbW1XZWlnaHRzAgUTbmV3UXVvdGVBc3NldFdlaWdodAUSbmV3QmFzZUFzc2V0V2VpZ2h0CQACAQIkU3RyaWN0IHZhbHVlIGlzIG5vdCBlcXVhbCB0byBpdHNlbGYuAWkBDmNoYW5nZVNldHRpbmdzExBfaW5pdE1hcmdpblJhdGlvBF9tbXIUX2xpcXVpZGF0aW9uRmVlUmF0aW8OX2Z1bmRpbmdQZXJpb2QEX2ZlZQxfc3ByZWFkTGltaXQPX21heFByaWNlSW1wYWN0GF9wYXJ0aWFsTGlxdWlkYXRpb25SYXRpbw9fbWF4UHJpY2VTcHJlYWQQX21heE9wZW5Ob3Rpb25hbBRfZmVlVG9TdGFrZXJzUGVyY2VudA9fbWF4T3JhY2xlRGVsYXkMX3JvbGxvdmVyRmVlDF9mdW5kaW5nTW9kZQtfb3JhY2xlTW9kZQ9fYmFzZU9yYWNsZURhdGEQX3F1b3RlT3JhY2xlRGF0YRNfbWluSW5pdE1hcmdpblJhdGlvDV9wb3NpdGlvbk1vZGUDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwkAZwIAAAUOX2Z1bmRpbmdQZXJpb2QGCQBnAgAABRBfaW5pdE1hcmdpblJhdGlvBgkAZgIFEF9pbml0TWFyZ2luUmF0aW8FDERFQ0lNQUxfVU5JVAYJAGcCAAAFE19taW5Jbml0TWFyZ2luUmF0aW8GCQBmAgUTX21pbkluaXRNYXJnaW5SYXRpbwUMREVDSU1BTF9VTklUBgkAZgIFEF9pbml0TWFyZ2luUmF0aW8FE19taW5Jbml0TWFyZ2luUmF0aW8GCQBnAgAABQRfbW1yBgkAZwIAAAUUX2xpcXVpZGF0aW9uRmVlUmF0aW8GCQBnAgAABQRfZmVlBgkAZwIAAAUMX3NwcmVhZExpbWl0BgkAZwIAAAUPX21heFByaWNlSW1wYWN0BgkAZwIAAAUYX3BhcnRpYWxMaXF1aWRhdGlvblJhdGlvBgkAZwIAAAUPX21heFByaWNlU3ByZWFkBgkAZwIAAAUQX21heE9wZW5Ob3Rpb25hbAYJAGcCAAAFFF9mZWVUb1N0YWtlcnNQZXJjZW50BgkAZgIFFF9mZWVUb1N0YWtlcnNQZXJjZW50BQxERUNJTUFMX1VOSVQGCQBmAgAABQ9fbWF4T3JhY2xlRGVsYXkGCQBnAgAABQxfcm9sbG92ZXJGZWUGAwkBAiE9AgUMX2Z1bmRpbmdNb2RlBRFGVU5ESU5HX1NZTU1FVFJJQwkBAiE9AgUMX2Z1bmRpbmdNb2RlBRJGVU5ESU5HX0FTWU1NRVRSSUMHBgMJAQIhPQIFC19vcmFjbGVNb2RlBQxPUkFDTEVfUExBSU4JAQIhPQIFC19vcmFjbGVNb2RlBQpPUkFDTEVfSklUBwYDCQECIT0CBQ1fcG9zaXRpb25Nb2RlBQ9QT1NJVElPTl9ESVJFQ1QJAQIhPQIFDV9wb3NpdGlvbk1vZGUFDlBPU0lUSU9OX09SREVSBwYJAQEhAQkBC2luaXRpYWxpemVkAAYJAQIhPQIIBQFpBmNhbGxlcgkBDGFkbWluQWRkcmVzcwAJAAIBAh1JbnZhbGlkIGNoYW5nZVNldHRpbmdzIHBhcmFtcwkAzggCCQEOdXBkYXRlU2V0dGluZ3MRBRBfaW5pdE1hcmdpblJhdGlvBQRfbW1yBRRfbGlxdWlkYXRpb25GZWVSYXRpbwUOX2Z1bmRpbmdQZXJpb2QFBF9mZWUFDF9zcHJlYWRMaW1pdAUPX21heFByaWNlSW1wYWN0BRhfcGFydGlhbExpcXVpZGF0aW9uUmF0aW8FD19tYXhQcmljZVNwcmVhZAUQX21heE9wZW5Ob3Rpb25hbAUUX2ZlZVRvU3Rha2Vyc1BlcmNlbnQFD19tYXhPcmFjbGVEZWxheQUMX3JvbGxvdmVyRmVlBQxfZnVuZGluZ01vZGUFC19vcmFjbGVNb2RlBRNfbWluSW5pdE1hcmdpblJhdGlvBQ1fcG9zaXRpb25Nb2RlCQDMCAIJAQtTdHJpbmdFbnRyeQIFDGtfYmFzZU9yYWNsZQUPX2Jhc2VPcmFjbGVEYXRhCQDMCAIJAQtTdHJpbmdFbnRyeQIFDWtfcXVvdGVPcmFjbGUFEF9xdW90ZU9yYWNsZURhdGEFA25pbAFpAQppbml0aWFsaXplFgdfcXRBc3RSB19ic0FzdFIOX2Z1bmRpbmdQZXJpb2QQX2luaXRNYXJnaW5SYXRpbwRfbW1yFF9saXF1aWRhdGlvbkZlZVJhdGlvBF9mZWUPX2Jhc2VPcmFjbGVEYXRhEF9xdW90ZU9yYWNsZURhdGEMX2Nvb3JkaW5hdG9yDF9zcHJlYWRMaW1pdA9fbWF4UHJpY2VJbXBhY3QYX3BhcnRpYWxMaXF1aWRhdGlvblJhdGlvD19tYXhQcmljZVNwcmVhZBBfbWF4T3Blbk5vdGlvbmFsFF9mZWVUb1N0YWtlcnNQZXJjZW50D19tYXhPcmFjbGVEZWxheQxfcm9sbG92ZXJGZWUMX2Z1bmRpbmdNb2RlC19vcmFjbGVNb2RlE19taW5Jbml0TWFyZ2luUmF0aW8NX3Bvc2l0aW9uTW9kZQMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwkAZwIAAAUHX3F0QXN0UgYJAGcCAAAFB19ic0FzdFIGCQBnAgAABQ5fZnVuZGluZ1BlcmlvZAYJAGcCAAAFEF9pbml0TWFyZ2luUmF0aW8GCQBmAgUQX2luaXRNYXJnaW5SYXRpbwUMREVDSU1BTF9VTklUBgkAZwIAAAUTX21pbkluaXRNYXJnaW5SYXRpbwYJAGYCBRBfaW5pdE1hcmdpblJhdGlvBRNfbWluSW5pdE1hcmdpblJhdGlvBgkAZwIAAAUEX21tcgYJAGcCAAAFFF9saXF1aWRhdGlvbkZlZVJhdGlvBgkAZwIAAAUEX2ZlZQYJAGcCAAAFDF9zcHJlYWRMaW1pdAYJAGcCAAAFD19tYXhQcmljZUltcGFjdAYJAGcCAAAFGF9wYXJ0aWFsTGlxdWlkYXRpb25SYXRpbwYJAGcCAAAFD19tYXhQcmljZVNwcmVhZAYJAGcCAAAFEF9tYXhPcGVuTm90aW9uYWwGCQBnAgAABRRfZmVlVG9TdGFrZXJzUGVyY2VudAYJAGYCBRRfZmVlVG9TdGFrZXJzUGVyY2VudAUMREVDSU1BTF9VTklUBgkAZgIAAAUPX21heE9yYWNsZURlbGF5BgkAZwIAAAUMX3JvbGxvdmVyRmVlBgMJAQIhPQIFDF9mdW5kaW5nTW9kZQURRlVORElOR19TWU1NRVRSSUMJAQIhPQIFDF9mdW5kaW5nTW9kZQUSRlVORElOR19BU1lNTUVUUklDBwYDCQECIT0CBQtfb3JhY2xlTW9kZQUMT1JBQ0xFX1BMQUlOCQECIT0CBQtfb3JhY2xlTW9kZQUKT1JBQ0xFX0pJVAcGAwkBAiE9AgUNX3Bvc2l0aW9uTW9kZQUPUE9TSVRJT05fRElSRUNUCQECIT0CBQ1fcG9zaXRpb25Nb2RlBQ5QT1NJVElPTl9PUkRFUgcGCQELaW5pdGlhbGl6ZWQABgkBAiE9AggFAWkGY2FsbGVyBQR0aGlzCQACAQIdSW52YWxpZCBpbml0aWFsaXplIHBhcmFtZXRlcnMJAM4IAgkAzggCCQDOCAIJAM4IAgkBCXVwZGF0ZUFtbQgFB19xdEFzdFIFB19ic0FzdFIAAAAAAAAAAAAAAAAJAQ51cGRhdGVTZXR0aW5ncxEFEF9pbml0TWFyZ2luUmF0aW8FBF9tbXIFFF9saXF1aWRhdGlvbkZlZVJhdGlvBQ5fZnVuZGluZ1BlcmlvZAUEX2ZlZQUMX3NwcmVhZExpbWl0BQ9fbWF4UHJpY2VJbXBhY3QFGF9wYXJ0aWFsTGlxdWlkYXRpb25SYXRpbwUPX21heFByaWNlU3ByZWFkBRBfbWF4T3Blbk5vdGlvbmFsBRRfZmVlVG9TdGFrZXJzUGVyY2VudAUPX21heE9yYWNsZURlbGF5BQxfcm9sbG92ZXJGZWUFDF9mdW5kaW5nTW9kZQULX29yYWNsZU1vZGUFE19taW5Jbml0TWFyZ2luUmF0aW8FDV9wb3NpdGlvbk1vZGUJAQ11cGRhdGVGdW5kaW5nBQkAZAIJAQ1sYXN0VGltZXN0YW1wAAUOX2Z1bmRpbmdQZXJpb2QAAAAAAAAAAAkBDXVwZGF0ZUJhbGFuY2UBAAAJAMwIAgkBDEJvb2xlYW5FbnRyeQIFDWtfaW5pdGlhbGl6ZWQGCQDMCAIJAQtTdHJpbmdFbnRyeQIFDGtfYmFzZU9yYWNsZQUPX2Jhc2VPcmFjbGVEYXRhCQDMCAIJAQtTdHJpbmdFbnRyeQIFDWtfcXVvdGVPcmFjbGUFEF9xdW90ZU9yYWNsZURhdGEJAMwIAgkBC1N0cmluZ0VudHJ5AgUUa19jb29yZGluYXRvckFkZHJlc3MJAKUIAQkBEUBleHRyTmF0aXZlKDEwNjIpAQUMX2Nvb3JkaW5hdG9yBQNuaWwBaQEQaW5jcmVhc2VQb3NpdGlvbgUKX2RpcmVjdGlvbglfbGV2ZXJhZ2UTX21pbkJhc2VBc3NldEFtb3VudAhfcmVmTGluawxfcHJpY2VVcGRhdGUEDHVwZGF0ZU9yYWNsZQkA/AcEBQR0aGlzAgx1cGRhdGVPcmFjbGUJAMwIAgUMX3ByaWNlVXBkYXRlBQNuaWwFA25pbAMJAAACBQx1cGRhdGVPcmFjbGUFDHVwZGF0ZU9yYWNsZQQEc3luYwkA/AcEBQR0aGlzAhlzeW5jVGVybWluYWxQcmljZVRvT3JhY2xlBQNuaWwFA25pbAMJAAACBQRzeW5jBQRzeW5jBBBlbnN1cmVDYWxsZWRPbmNlCQD8BwQFBHRoaXMCEGVuc3VyZUNhbGxlZE9uY2UFA25pbAUDbmlsAwkAAAIFEGVuc3VyZUNhbGxlZE9uY2UFEGVuc3VyZUNhbGxlZE9uY2UEB190cmFkZXIJAQ9nZXRBY3R1YWxDYWxsZXIBBQFpBApfcmF3QW1vdW50CAkAkQMCCAUBaQhwYXltZW50cwAABmFtb3VudAQIX2Fzc2V0SWQICQCRAwIIBQFpCHBheW1lbnRzAAAHYXNzZXRJZAQLX2Fzc2V0SWRTdHIJANgEAQkBBXZhbHVlAQUIX2Fzc2V0SWQEDGlzUXVvdGVBc3NldAkAAAIFCF9hc3NldElkCQEKcXVvdGVBc3NldAADAwMDAwMDAwMDAwkBAiE9AgUKX2RpcmVjdGlvbgUIRElSX0xPTkcJAQIhPQIFCl9kaXJlY3Rpb24FCURJUl9TSE9SVAcGCQBnAgAABQpfcmF3QW1vdW50BgkBASEBCQELaW5pdGlhbGl6ZWQABgkBASEBBQxpc1F1b3RlQXNzZXQGCQEBIQEJARZyZXF1aXJlTW9yZU1hcmdpblJhdGlvAwkBBGRpdmQCBQxERUNJTUFMX1VOSVQFCV9sZXZlcmFnZQkBD2luaXRNYXJnaW5SYXRpbwAGBgkBASEBCQEWcmVxdWlyZU1vcmVNYXJnaW5SYXRpbwMJAQRkaXZkAgUMREVDSU1BTF9VTklUBQlfbGV2ZXJhZ2UJARJtaW5Jbml0TWFyZ2luUmF0aW8ABwYJAQEhAQkBIXJlcXVpcmVTZW5kZXJDYW5Xb3JrV2l0aFBvc2l0aW9ucwEIBQFpBmNhbGxlcgYJAQZwYXVzZWQABgkBCWNsb3NlT25seQAGCQEOaXNNYXJrZXRDbG9zZWQACQACAQIjSW52YWxpZCBpbmNyZWFzZVBvc2l0aW9uIHBhcmFtZXRlcnMEDSR0MDYwNTAxNjA2NTAJARhnZXRGb3JUcmFkZXJXaXRoQXJ0aWZhY3QCBQdfdHJhZGVyCQENZ2V0QXJ0aWZhY3RJZAEFAWkEC2FkanVzdGVkRmVlCAUNJHQwNjA1MDE2MDY1MAJfMQQMYnVybkFydGlmYWN0CAUNJHQwNjA1MDE2MDY1MAJfMgQHX2Ftb3VudAkBBGRpdmQCBQpfcmF3QW1vdW50CQBkAgkBBG11bGQCBQthZGp1c3RlZEZlZQUJX2xldmVyYWdlBQxERUNJTUFMX1VOSVQEE2Rpc3RyaWJ1dGVGZWVBbW91bnQJAGUCBQpfcmF3QW1vdW50BQdfYW1vdW50BA5yZWZlcnJlckZlZUFueQkA/AcECQEPcmVmZXJyYWxBZGRyZXNzAAIVYWNjZXB0UGF5bWVudFdpdGhMaW5rCQDMCAIFB190cmFkZXIJAMwIAgUIX3JlZkxpbmsFA25pbAkAzAgCCQEPQXR0YWNoZWRQYXltZW50AgkBCnF1b3RlQXNzZXQABRNkaXN0cmlidXRlRmVlQW1vdW50BQNuaWwDCQAAAgUOcmVmZXJyZXJGZWVBbnkFDnJlZmVycmVyRmVlQW55BAtyZWZlcnJlckZlZQQHJG1hdGNoMAUOcmVmZXJyZXJGZWVBbnkDCQABAgUHJG1hdGNoMAIDSW50BAF4BQckbWF0Y2gwBQF4CQACAQITSW52YWxpZCByZWZlcnJlckZlZQQJZmVlQW1vdW50CQBlAgUTZGlzdHJpYnV0ZUZlZUFtb3VudAULcmVmZXJyZXJGZWUEDSR0MDYxMTQ2NjEzMjYJAQtnZXRQb3NpdGlvbgIFB190cmFkZXIFCl9kaXJlY3Rpb24ED29sZFBvc2l0aW9uU2l6ZQgFDSR0MDYxMTQ2NjEzMjYCXzEEEW9sZFBvc2l0aW9uTWFyZ2luCAUNJHQwNjExNDY2MTMyNgJfMgQXb2xkUG9zaXRpb25PcGVuTm90aW9uYWwIBQ0kdDA2MTE0NjYxMzI2Al8zBBRvbGRQb3NpdGlvbkxzdFVwZENQRggFDSR0MDYxMTQ2NjEzMjYCXzQEFG9sZFBvc2l0aW9uVGltZXN0YW1wCAUNJHQwNjExNDY2MTMyNgJfNQQNaXNOZXdQb3NpdGlvbgkAAAIFD29sZFBvc2l0aW9uU2l6ZQAABA9pc1NhbWVEaXJlY3Rpb24DCQBmAgUPb2xkUG9zaXRpb25TaXplAAAJAAACBQpfZGlyZWN0aW9uBQhESVJfTE9ORwkAAAIFCl9kaXJlY3Rpb24FCURJUl9TSE9SVAQOZXhwYW5kRXhpc3RpbmcDCQEBIQEFDWlzTmV3UG9zaXRpb24FD2lzU2FtZURpcmVjdGlvbgcEBWlzQWRkCQAAAgUKX2RpcmVjdGlvbgUIRElSX0xPTkcEDSR0MDYxNjE1NjQ3NDgDAwUNaXNOZXdQb3NpdGlvbgYFDmV4cGFuZEV4aXN0aW5nBAxvcGVuTm90aW9uYWwJAQRtdWxkAgUHX2Ftb3VudAUJX2xldmVyYWdlBA0kdDA2MjEyNDYyMjk3CQEJc3dhcElucHV0AgUFaXNBZGQFDG9wZW5Ob3Rpb25hbAQVYW1vdW50QmFzZUFzc2V0Qm91Z2h0CAUNJHQwNjIxMjQ2MjI5NwJfMQQWcXVvdGVBc3NldFJlc2VydmVBZnRlcggFDSR0MDYyMTI0NjIyOTcCXzIEFWJhc2VBc3NldFJlc2VydmVBZnRlcggFDSR0MDYyMTI0NjIyOTcCXzMEFnRvdGFsUG9zaXRpb25TaXplQWZ0ZXIIBQ0kdDA2MjEyNDYyMjk3Al80AwMJAQIhPQIFE19taW5CYXNlQXNzZXRBbW91bnQAAAkAZgIFE19taW5CYXNlQXNzZXRBbW91bnQJAQNhYnMBBRVhbW91bnRCYXNlQXNzZXRCb3VnaHQHCQACAQkArAICCQCsAgIJAKwCAgINTGltaXQgZXJyb3I6IAkApAMBCQEDYWJzAQUVYW1vdW50QmFzZUFzc2V0Qm91Z2h0AgMgPCAJAKQDAQUTX21pbkJhc2VBc3NldEFtb3VudAQPbmV3UG9zaXRpb25TaXplCQBkAgUPb2xkUG9zaXRpb25TaXplBRVhbW91bnRCYXNlQXNzZXRCb3VnaHQEGnRvdGFsTG9uZ09wZW5JbnRlcmVzdEFmdGVyCQBkAgkBEG9wZW5JbnRlcmVzdExvbmcAAwkAZgIFD25ld1Bvc2l0aW9uU2l6ZQAABQxvcGVuTm90aW9uYWwAAAQbdG90YWxTaG9ydE9wZW5JbnRlcmVzdEFmdGVyCQBkAgkBEW9wZW5JbnRlcmVzdFNob3J0AAMJAGYCAAAFD25ld1Bvc2l0aW9uU2l6ZQUMb3Blbk5vdGlvbmFsAAAEDSR0MDYyODQzNjMxMTgJATBjYWxjUmVtYWluTWFyZ2luV2l0aEZ1bmRpbmdQYXltZW50QW5kUm9sbG92ZXJGZWUFBQ9vbGRQb3NpdGlvblNpemUFEW9sZFBvc2l0aW9uTWFyZ2luBRRvbGRQb3NpdGlvbkxzdFVwZENQRgUUb2xkUG9zaXRpb25UaW1lc3RhbXAFB19hbW91bnQEDHJlbWFpbk1hcmdpbggFDSR0MDYyODQzNjMxMTgCXzEEAngxCAUNJHQwNjI4NDM2MzExOAJfMgQCeDIIBQ0kdDA2Mjg0MzYzMTE4Al8zBAtyb2xsb3ZlckZlZQgFDSR0MDYyODQzNjMxMTgCXzQDCQEBIQEJARlyZXF1aXJlTm90T3ZlclNwcmVhZExpbWl0AgUWcXVvdGVBc3NldFJlc2VydmVBZnRlcgUVYmFzZUFzc2V0UmVzZXJ2ZUFmdGVyCQACAQIVT3ZlciBtYXggc3ByZWFkIGxpbWl0AwkBASEBCQEdcmVxdWlyZU5vdE92ZXJNYXhPcGVuTm90aW9uYWwCBRp0b3RhbExvbmdPcGVuSW50ZXJlc3RBZnRlcgUbdG90YWxTaG9ydE9wZW5JbnRlcmVzdEFmdGVyCQACAQIWT3ZlciBtYXggb3BlbiBub3Rpb25hbAkAoAoOBQ9uZXdQb3NpdGlvblNpemUFDHJlbWFpbk1hcmdpbgkAZAIFF29sZFBvc2l0aW9uT3Blbk5vdGlvbmFsBQxvcGVuTm90aW9uYWwJAR9sYXRlc3RDdW11bGF0aXZlUHJlbWl1bUZyYWN0aW9uAQUPbmV3UG9zaXRpb25TaXplCQENbGFzdFRpbWVzdGFtcAAFFWJhc2VBc3NldFJlc2VydmVBZnRlcgUWcXVvdGVBc3NldFJlc2VydmVBZnRlcgUWdG90YWxQb3NpdGlvblNpemVBZnRlcgkAZAIJARRvcGVuSW50ZXJlc3ROb3Rpb25hbAAFDG9wZW5Ob3Rpb25hbAkAZAIJARV0b3RhbExvbmdQb3NpdGlvblNpemUAAwkAZgIFD25ld1Bvc2l0aW9uU2l6ZQAACQEDYWJzAQUVYW1vdW50QmFzZUFzc2V0Qm91Z2h0AAAJAGQCCQEWdG90YWxTaG9ydFBvc2l0aW9uU2l6ZQADCQBmAgAABQ9uZXdQb3NpdGlvblNpemUJAQNhYnMBBRVhbW91bnRCYXNlQXNzZXRCb3VnaHQAAAUadG90YWxMb25nT3BlbkludGVyZXN0QWZ0ZXIFG3RvdGFsU2hvcnRPcGVuSW50ZXJlc3RBZnRlcgULcm9sbG92ZXJGZWUEDG9wZW5Ob3Rpb25hbAkBBG11bGQCBQdfYW1vdW50BQlfbGV2ZXJhZ2UEDSR0MDY0NDM2NjQ1NjQJASNnZXRQb3NpdGlvbk5vdGlvbmFsQW5kVW5yZWFsaXplZFBubAMJAKUIAQgFAWkGY2FsbGVyBQpfZGlyZWN0aW9uBQ9QTkxfT1BUSU9OX1NQT1QEE29sZFBvc2l0aW9uTm90aW9uYWwIBQ0kdDA2NDQzNjY0NTY0Al8xBA11bnJlYWxpemVkUG5sCAUNJHQwNjQ0MzY2NDU2NAJfMgMJAGYCBRNvbGRQb3NpdGlvbk5vdGlvbmFsBQxvcGVuTm90aW9uYWwJAAIBAi5Vc2UgZGVjcmVhc2VQb3NpdGlvbiB0byBkZWNyZWFzZSBwb3NpdGlvbiBzaXplCQACAQIUQ2xvc2UgcG9zaXRpb24gZmlyc3QED25ld1Bvc2l0aW9uU2l6ZQgFDSR0MDYxNjE1NjQ3NDgCXzEEF25ld1Bvc2l0aW9uUmVtYWluTWFyZ2luCAUNJHQwNjE2MTU2NDc0OAJfMgQXbmV3UG9zaXRpb25PcGVuTm90aW9uYWwIBQ0kdDA2MTYxNTY0NzQ4Al8zBBRuZXdQb3NpdGlvbkxhdGVzdENQRggFDSR0MDYxNjE1NjQ3NDgCXzQEFG5ld1Bvc2l0aW9uVGltZXN0YW1wCAUNJHQwNjE2MTU2NDc0OAJfNQQVYmFzZUFzc2V0UmVzZXJ2ZUFmdGVyCAUNJHQwNjE2MTU2NDc0OAJfNgQWcXVvdGVBc3NldFJlc2VydmVBZnRlcggFDSR0MDYxNjE1NjQ3NDgCXzcEFnRvdGFsUG9zaXRpb25TaXplQWZ0ZXIIBQ0kdDA2MTYxNTY0NzQ4Al84BBlvcGVuSW50ZXJlc3ROb3Rpb25hbEFmdGVyCAUNJHQwNjE2MTU2NDc0OAJfOQQOdG90YWxMb25nQWZ0ZXIIBQ0kdDA2MTYxNTY0NzQ4A18xMAQPdG90YWxTaG9ydEFmdGVyCAUNJHQwNjE2MTU2NDc0OANfMTEEGnRvdGFsTG9uZ09wZW5JbnRlcmVzdEFmdGVyCAUNJHQwNjE2MTU2NDc0OANfMTIEG3RvdGFsU2hvcnRPcGVuSW50ZXJlc3RBZnRlcggFDSR0MDYxNjE1NjQ3NDgDXzEzBAtyb2xsb3ZlckZlZQgFDSR0MDYxNjE1NjQ3NDgDXzE0BA0kdDA2NDc1NDY0ODI1CQENZGlzdHJpYnV0ZUZlZQEJAGQCBQlmZWVBbW91bnQFC3JvbGxvdmVyRmVlBAxmZWVUb1N0YWtlcnMIBQ0kdDA2NDc1NDY0ODI1Al8xBApmZWVUb1ZhdWx0CAUNJHQwNjQ3NTQ2NDgyNQJfMgQFc3Rha2UDCQBnAgUHX2Ftb3VudAULcm9sbG92ZXJGZWUJAPwHBAkBDHZhdWx0QWRkcmVzcwACCWFkZExvY2tlZAUDbmlsCQDMCAIJAQ9BdHRhY2hlZFBheW1lbnQCCQEKcXVvdGVBc3NldAAJAGUCBQdfYW1vdW50BQtyb2xsb3ZlckZlZQUDbmlsCQD8BwQJAQx2YXVsdEFkZHJlc3MAAg53aXRoZHJhd0xvY2tlZAkAzAgCCQBlAgULcm9sbG92ZXJGZWUFB19hbW91bnQFA25pbAUDbmlsAwkAAAIFBXN0YWtlBQVzdGFrZQQMZGVwb3NpdFZhdWx0CQD8BwQJAQx2YXVsdEFkZHJlc3MAAgdhZGRGcmVlBQNuaWwJAMwIAgkBD0F0dGFjaGVkUGF5bWVudAIJAQpxdW90ZUFzc2V0AAUKZmVlVG9WYXVsdAUDbmlsAwkAAAIFDGRlcG9zaXRWYXVsdAUMZGVwb3NpdFZhdWx0BAlub3RpZnlGZWUJAPwHBAkBDG1pbmVyQWRkcmVzcwACCm5vdGlmeUZlZXMJAMwIAgUHX3RyYWRlcgkAzAgCBQlmZWVBbW91bnQFA25pbAUDbmlsAwkAAAIFCW5vdGlmeUZlZQUJbm90aWZ5RmVlBA5ub3RpZnlOb3Rpb25hbAkA/AcECQEMbWluZXJBZGRyZXNzAAIObm90aWZ5Tm90aW9uYWwJAMwIAgUHX3RyYWRlcgkAzAgCBRduZXdQb3NpdGlvbk9wZW5Ob3Rpb25hbAUDbmlsBQNuaWwDCQAAAgUObm90aWZ5Tm90aW9uYWwFDm5vdGlmeU5vdGlvbmFsCQDOCAIJAM4IAgkAzggCCQDOCAIJAM4IAgkAzggCCQEOdXBkYXRlUG9zaXRpb24GBQdfdHJhZGVyBQ9uZXdQb3NpdGlvblNpemUFF25ld1Bvc2l0aW9uUmVtYWluTWFyZ2luBRduZXdQb3NpdGlvbk9wZW5Ob3Rpb25hbAUUbmV3UG9zaXRpb25MYXRlc3RDUEYFFG5ld1Bvc2l0aW9uVGltZXN0YW1wCQEfaW5jcmVtZW50UG9zaXRpb25TZXF1ZW5jZU51bWJlcgMFDWlzTmV3UG9zaXRpb24FB190cmFkZXIFCl9kaXJlY3Rpb24JARF1cGRhdGVQb3NpdGlvbkZlZQQFDWlzTmV3UG9zaXRpb24FB190cmFkZXIFCl9kaXJlY3Rpb24FC2FkanVzdGVkRmVlCQEJdXBkYXRlQW1tCAUWcXVvdGVBc3NldFJlc2VydmVBZnRlcgUVYmFzZUFzc2V0UmVzZXJ2ZUFmdGVyBRZ0b3RhbFBvc2l0aW9uU2l6ZUFmdGVyBRlvcGVuSW50ZXJlc3ROb3Rpb25hbEFmdGVyBQ50b3RhbExvbmdBZnRlcgUPdG90YWxTaG9ydEFmdGVyBRp0b3RhbExvbmdPcGVuSW50ZXJlc3RBZnRlcgUbdG90YWxTaG9ydE9wZW5JbnRlcmVzdEFmdGVyCQELdHJhbnNmZXJGZWUBBQxmZWVUb1N0YWtlcnMJAQ11cGRhdGVCYWxhbmNlAQkAZQIJAGQCCQEIY2JhbGFuY2UABQdfYW1vdW50BQtyb2xsb3ZlckZlZQkBDmRvQnVybkFydGlmYWN0AgUMYnVybkFydGlmYWN0BQFpCQACAQIkU3RyaWN0IHZhbHVlIGlzIG5vdCBlcXVhbCB0byBpdHNlbGYuCQACAQIkU3RyaWN0IHZhbHVlIGlzIG5vdCBlcXVhbCB0byBpdHNlbGYuCQACAQIkU3RyaWN0IHZhbHVlIGlzIG5vdCBlcXVhbCB0byBpdHNlbGYuCQACAQIkU3RyaWN0IHZhbHVlIGlzIG5vdCBlcXVhbCB0byBpdHNlbGYuCQACAQIkU3RyaWN0IHZhbHVlIGlzIG5vdCBlcXVhbCB0byBpdHNlbGYuCQACAQIkU3RyaWN0IHZhbHVlIGlzIG5vdCBlcXVhbCB0byBpdHNlbGYuCQACAQIkU3RyaWN0IHZhbHVlIGlzIG5vdCBlcXVhbCB0byBpdHNlbGYuCQACAQIkU3RyaWN0IHZhbHVlIGlzIG5vdCBlcXVhbCB0byBpdHNlbGYuAWkBCWFkZE1hcmdpbgIKX2RpcmVjdGlvbgxfcHJpY2VVcGRhdGUEDHVwZGF0ZU9yYWNsZQkA/AcEBQR0aGlzAgx1cGRhdGVPcmFjbGUJAMwIAgUMX3ByaWNlVXBkYXRlBQNuaWwFA25pbAMJAAACBQx1cGRhdGVPcmFjbGUFDHVwZGF0ZU9yYWNsZQQEc3luYwkA/AcEBQR0aGlzAhlzeW5jVGVybWluYWxQcmljZVRvT3JhY2xlBQNuaWwFA25pbAMJAAACBQRzeW5jBQRzeW5jBBBlbnN1cmVDYWxsZWRPbmNlCQD8BwQFBHRoaXMCEGVuc3VyZUNhbGxlZE9uY2UFA25pbAUDbmlsAwkAAAIFEGVuc3VyZUNhbGxlZE9uY2UFEGVuc3VyZUNhbGxlZE9uY2UEB190cmFkZXIJAKUIAQgFAWkGY2FsbGVyBAdfYW1vdW50CAkAkQMCCAUBaQhwYXltZW50cwAABmFtb3VudAQIX2Fzc2V0SWQICQCRAwIIBQFpCHBheW1lbnRzAAAHYXNzZXRJZAQLX2Fzc2V0SWRTdHIJANgEAQkBBXZhbHVlAQUIX2Fzc2V0SWQEDGlzUXVvdGVBc3NldAkAAAIFCF9hc3NldElkCQEKcXVvdGVBc3NldAADAwMDAwkBASEBBQxpc1F1b3RlQXNzZXQGCQEBIQEJARNyZXF1aXJlT3BlblBvc2l0aW9uAgkApQgBCAUBaQZjYWxsZXIFCl9kaXJlY3Rpb24GCQEBIQEJAQtpbml0aWFsaXplZAAGCQEGcGF1c2VkAAYJAQ5pc01hcmtldENsb3NlZAAJAAIBAhxJbnZhbGlkIGFkZE1hcmdpbiBwYXJhbWV0ZXJzBA0kdDA2NzE2NzY3MzQ3CQELZ2V0UG9zaXRpb24CBQdfdHJhZGVyBQpfZGlyZWN0aW9uBA9vbGRQb3NpdGlvblNpemUIBQ0kdDA2NzE2NzY3MzQ3Al8xBBFvbGRQb3NpdGlvbk1hcmdpbggFDSR0MDY3MTY3NjczNDcCXzIEF29sZFBvc2l0aW9uT3Blbk5vdGlvbmFsCAUNJHQwNjcxNjc2NzM0NwJfMwQUb2xkUG9zaXRpb25Mc3RVcGRDUEYIBQ0kdDA2NzE2NzY3MzQ3Al80BBRvbGRQb3NpdGlvblRpbWVzdGFtcAgFDSR0MDY3MTY3NjczNDcCXzUEBXN0YWtlCQD8BwQJAQx2YXVsdEFkZHJlc3MAAglhZGRMb2NrZWQFA25pbAkAzAgCCQEPQXR0YWNoZWRQYXltZW50AgkBCnF1b3RlQXNzZXQABQdfYW1vdW50BQNuaWwDCQAAAgUFc3Rha2UFBXN0YWtlBA0kdDA2NzQ4NzY3NzEzCQEwY2FsY1JlbWFpbk1hcmdpbldpdGhGdW5kaW5nUGF5bWVudEFuZFJvbGxvdmVyRmVlBQUPb2xkUG9zaXRpb25TaXplBRFvbGRQb3NpdGlvbk1hcmdpbgUUb2xkUG9zaXRpb25Mc3RVcGRDUEYFFG9sZFBvc2l0aW9uVGltZXN0YW1wBQdfYW1vdW50BAxyZW1haW5NYXJnaW4IBQ0kdDA2NzQ4NzY3NzEzAl8xBAdiYWREZWJ0CAUNJHQwNjc0ODc2NzcxMwJfMgQLcm9sbG92ZXJGZWUIBQ0kdDA2NzQ4NzY3NzEzAl8zBAttYXJnaW5SYXRpbwkBD2NhbGNNYXJnaW5SYXRpbwMFDHJlbWFpbk1hcmdpbgUHYmFkRGVidAUXb2xkUG9zaXRpb25PcGVuTm90aW9uYWwEDmNoZWNrTWluTWFyZ2luCQEWcmVxdWlyZU1vcmVNYXJnaW5SYXRpbwMFC21hcmdpblJhdGlvCQESbWluSW5pdE1hcmdpblJhdGlvAAcDCQAAAgUOY2hlY2tNaW5NYXJnaW4FDmNoZWNrTWluTWFyZ2luBBZkb1RyYW5zZmVyRmVlVG9TdGFrZXJzAwkAZgIFC3JvbGxvdmVyRmVlAAAEDSR0MDY3OTY5NjgwMjgJAQ1kaXN0cmlidXRlRmVlAQULcm9sbG92ZXJGZWUEDGZlZVRvU3Rha2VycwgFDSR0MDY3OTY5NjgwMjgCXzEECmZlZVRvVmF1bHQIBQ0kdDA2Nzk2OTY4MDI4Al8yBAd1bnN0YWtlCQD8BwQJAQx2YXVsdEFkZHJlc3MAAg53aXRoZHJhd0xvY2tlZAkAzAgCBQxmZWVUb1N0YWtlcnMFA25pbAUDbmlsAwkAAAIFB3Vuc3Rha2UFB3Vuc3Rha2UEC2xvY2tCYWREZWJ0CQD8BwQJAQx2YXVsdEFkZHJlc3MAAhVleGNoYW5nZUZyZWVBbmRMb2NrZWQJAMwIAgkBAS0BBQpmZWVUb1ZhdWx0BQNuaWwFA25pbAMJAAACBQtsb2NrQmFkRGVidAULbG9ja0JhZERlYnQJAQt0cmFuc2ZlckZlZQEFDGZlZVRvU3Rha2VycwkAAgECJFN0cmljdCB2YWx1ZSBpcyBub3QgZXF1YWwgdG8gaXRzZWxmLgkAAgECJFN0cmljdCB2YWx1ZSBpcyBub3QgZXF1YWwgdG8gaXRzZWxmLgUDbmlsAwkAAAIFFmRvVHJhbnNmZXJGZWVUb1N0YWtlcnMFFmRvVHJhbnNmZXJGZWVUb1N0YWtlcnMJAM4IAgkAzggCCQEOdXBkYXRlUG9zaXRpb24GBQdfdHJhZGVyBQ9vbGRQb3NpdGlvblNpemUJAGQCCQBlAgURb2xkUG9zaXRpb25NYXJnaW4FC3JvbGxvdmVyRmVlBQdfYW1vdW50BRdvbGRQb3NpdGlvbk9wZW5Ob3Rpb25hbAUUb2xkUG9zaXRpb25Mc3RVcGRDUEYJAQ1sYXN0VGltZXN0YW1wAAkBDXVwZGF0ZUJhbGFuY2UBCQBlAgkAZAIJAQhjYmFsYW5jZQAFB19hbW91bnQFC3JvbGxvdmVyRmVlBRZkb1RyYW5zZmVyRmVlVG9TdGFrZXJzCQACAQIkU3RyaWN0IHZhbHVlIGlzIG5vdCBlcXVhbCB0byBpdHNlbGYuCQACAQIkU3RyaWN0IHZhbHVlIGlzIG5vdCBlcXVhbCB0byBpdHNlbGYuCQACAQIkU3RyaWN0IHZhbHVlIGlzIG5vdCBlcXVhbCB0byBpdHNlbGYuCQACAQIkU3RyaWN0IHZhbHVlIGlzIG5vdCBlcXVhbCB0byBpdHNlbGYuCQACAQIkU3RyaWN0IHZhbHVlIGlzIG5vdCBlcXVhbCB0byBpdHNlbGYuCQACAQIkU3RyaWN0IHZhbHVlIGlzIG5vdCBlcXVhbCB0byBpdHNlbGYuAWkBDHJlbW92ZU1hcmdpbgMHX2Ftb3VudApfZGlyZWN0aW9uDF9wcmljZVVwZGF0ZQQMdXBkYXRlT3JhY2xlCQD8BwQFBHRoaXMCDHVwZGF0ZU9yYWNsZQkAzAgCBQxfcHJpY2VVcGRhdGUFA25pbAUDbmlsAwkAAAIFDHVwZGF0ZU9yYWNsZQUMdXBkYXRlT3JhY2xlBARzeW5jCQD8BwQFBHRoaXMCGXN5bmNUZXJtaW5hbFByaWNlVG9PcmFjbGUFA25pbAUDbmlsAwkAAAIFBHN5bmMFBHN5bmMEEGVuc3VyZUNhbGxlZE9uY2UJAPwHBAUEdGhpcwIQZW5zdXJlQ2FsbGVkT25jZQUDbmlsBQNuaWwDCQAAAgUQZW5zdXJlQ2FsbGVkT25jZQUQZW5zdXJlQ2FsbGVkT25jZQQHX3RyYWRlcgkApQgBCAUBaQZjYWxsZXIDAwMDAwkAZwIAAAUHX2Ftb3VudAYJAQEhAQkBE3JlcXVpcmVPcGVuUG9zaXRpb24CBQdfdHJhZGVyBQpfZGlyZWN0aW9uBgkBASEBCQELaW5pdGlhbGl6ZWQABgkBBnBhdXNlZAAGCQEOaXNNYXJrZXRDbG9zZWQACQACAQIfSW52YWxpZCByZW1vdmVNYXJnaW4gcGFyYW1ldGVycwQNJHQwNjk1Mjk2OTcwOQkBC2dldFBvc2l0aW9uAgUHX3RyYWRlcgUKX2RpcmVjdGlvbgQPb2xkUG9zaXRpb25TaXplCAUNJHQwNjk1Mjk2OTcwOQJfMQQRb2xkUG9zaXRpb25NYXJnaW4IBQ0kdDA2OTUyOTY5NzA5Al8yBBdvbGRQb3NpdGlvbk9wZW5Ob3Rpb25hbAgFDSR0MDY5NTI5Njk3MDkCXzMEFG9sZFBvc2l0aW9uTHN0VXBkQ1BGCAUNJHQwNjk1Mjk2OTcwOQJfNAQUb2xkUG9zaXRpb25UaW1lc3RhbXAIBQ0kdDA2OTUyOTY5NzA5Al81BA0kdDA2OTcxNTY5OTY0CQEwY2FsY1JlbWFpbk1hcmdpbldpdGhGdW5kaW5nUGF5bWVudEFuZFJvbGxvdmVyRmVlBQUPb2xkUG9zaXRpb25TaXplBRFvbGRQb3NpdGlvbk1hcmdpbgUUb2xkUG9zaXRpb25Mc3RVcGRDUEYFFG9sZFBvc2l0aW9uVGltZXN0YW1wCQEBLQEFB19hbW91bnQEDHJlbWFpbk1hcmdpbggFDSR0MDY5NzE1Njk5NjQCXzEEB2JhZERlYnQIBQ0kdDA2OTcxNTY5OTY0Al8yBA5mdW5kaW5nUGF5bWVudAgFDSR0MDY5NzE1Njk5NjQCXzMEC3JvbGxvdmVyRmVlCAUNJHQwNjk3MTU2OTk2NAJfNAMJAQIhPQIFB2JhZERlYnQAAAkAAgECHUludmFsaWQgcmVtb3ZlZCBtYXJnaW4gYW1vdW50BAttYXJnaW5SYXRpbwkBD2NhbGNNYXJnaW5SYXRpbwMFDHJlbWFpbk1hcmdpbgUHYmFkRGVidAUXb2xkUG9zaXRpb25PcGVuTm90aW9uYWwDCQEBIQEJARZyZXF1aXJlTW9yZU1hcmdpblJhdGlvAwULbWFyZ2luUmF0aW8JAQ9pbml0TWFyZ2luUmF0aW8ABgkAAgEJAKwCAgkArAICCQCsAgICGVRvbyBtdWNoIG1hcmdpbiByZW1vdmVkOiAJAKQDAQULbWFyZ2luUmF0aW8CAyA8IAkApAMBCQEPaW5pdE1hcmdpblJhdGlvAAQNJHQwNzAzNTA3MDQwOQkBDWRpc3RyaWJ1dGVGZWUBBQtyb2xsb3ZlckZlZQQMZmVlVG9TdGFrZXJzCAUNJHQwNzAzNTA3MDQwOQJfMQQKZmVlVG9WYXVsdAgFDSR0MDcwMzUwNzA0MDkCXzIEFmRvVHJhbnNmZXJGZWVUb1N0YWtlcnMDCQBmAgULcm9sbG92ZXJGZWUAAAQLbG9ja0JhZERlYnQJAPwHBAkBDHZhdWx0QWRkcmVzcwACFWV4Y2hhbmdlRnJlZUFuZExvY2tlZAkAzAgCCQEBLQEFCmZlZVRvVmF1bHQFA25pbAUDbmlsAwkAAAIFC2xvY2tCYWREZWJ0BQtsb2NrQmFkRGVidAkBC3RyYW5zZmVyRmVlAQUMZmVlVG9TdGFrZXJzCQACAQIkU3RyaWN0IHZhbHVlIGlzIG5vdCBlcXVhbCB0byBpdHNlbGYuBQNuaWwDCQAAAgUWZG9UcmFuc2ZlckZlZVRvU3Rha2VycwUWZG9UcmFuc2ZlckZlZVRvU3Rha2VycwQHdW5zdGFrZQkA/AcECQEMdmF1bHRBZGRyZXNzAAIOd2l0aGRyYXdMb2NrZWQJAMwIAgkAZAIFB19hbW91bnQFDGZlZVRvU3Rha2VycwUDbmlsBQNuaWwDCQAAAgUHdW5zdGFrZQUHdW5zdGFrZQkAzggCCQDOCAIJAM4IAgkBDnVwZGF0ZVBvc2l0aW9uBgUHX3RyYWRlcgUPb2xkUG9zaXRpb25TaXplBQxyZW1haW5NYXJnaW4FF29sZFBvc2l0aW9uT3Blbk5vdGlvbmFsCQEfbGF0ZXN0Q3VtdWxhdGl2ZVByZW1pdW1GcmFjdGlvbgEFD29sZFBvc2l0aW9uU2l6ZQkBDWxhc3RUaW1lc3RhbXAACQEId2l0aGRyYXcCCAUBaQZjYWxsZXIFB19hbW91bnQJAQ11cGRhdGVCYWxhbmNlAQkAZQIJAGUCCQEIY2JhbGFuY2UABQdfYW1vdW50BQtyb2xsb3ZlckZlZQUWZG9UcmFuc2ZlckZlZVRvU3Rha2VycwkAAgECJFN0cmljdCB2YWx1ZSBpcyBub3QgZXF1YWwgdG8gaXRzZWxmLgkAAgECJFN0cmljdCB2YWx1ZSBpcyBub3QgZXF1YWwgdG8gaXRzZWxmLgkAAgECJFN0cmljdCB2YWx1ZSBpcyBub3QgZXF1YWwgdG8gaXRzZWxmLgkAAgECJFN0cmljdCB2YWx1ZSBpcyBub3QgZXF1YWwgdG8gaXRzZWxmLgkAAgECJFN0cmljdCB2YWx1ZSBpcyBub3QgZXF1YWwgdG8gaXRzZWxmLgFpAQ1jbG9zZVBvc2l0aW9uBQVfc2l6ZQpfZGlyZWN0aW9uFF9taW5RdW90ZUFzc2V0QW1vdW50DF9hZGRUb01hcmdpbgxfcHJpY2VVcGRhdGUEDHVwZGF0ZU9yYWNsZQkA/AcEBQR0aGlzAgx1cGRhdGVPcmFjbGUJAMwIAgUMX3ByaWNlVXBkYXRlBQNuaWwFA25pbAMJAAACBQx1cGRhdGVPcmFjbGUFDHVwZGF0ZU9yYWNsZQQEc3luYwkA/AcEBQR0aGlzAhlzeW5jVGVybWluYWxQcmljZVRvT3JhY2xlBQNuaWwFA25pbAMJAAACBQRzeW5jBQRzeW5jBBBlbnN1cmVDYWxsZWRPbmNlCQD8BwQFBHRoaXMCEGVuc3VyZUNhbGxlZE9uY2UFA25pbAUDbmlsAwkAAAIFEGVuc3VyZUNhbGxlZE9uY2UFEGVuc3VyZUNhbGxlZE9uY2UEB190cmFkZXIJAQ9nZXRBY3R1YWxDYWxsZXIBBQFpBA5fdHJhZGVyQWRkcmVzcwkBE3ZhbHVlT3JFcnJvck1lc3NhZ2UCCQCmCAEFB190cmFkZXICDkludmFsaWQgY2FsbGVyBAtwb3NpdGlvbkZlZQkBDmdldFBvc2l0aW9uRmVlAgUHX3RyYWRlcgUKX2RpcmVjdGlvbgMDAwMDAwkBASEBCQETcmVxdWlyZU9wZW5Qb3NpdGlvbgIFB190cmFkZXIFCl9kaXJlY3Rpb24GCQEBIQEJAQtpbml0aWFsaXplZAAGCQEGcGF1c2VkAAYJAGcCAAAFBV9zaXplBgkAZgIAAAUUX21pblF1b3RlQXNzZXRBbW91bnQGCQEOaXNNYXJrZXRDbG9zZWQACQACAQIgSW52YWxpZCBjbG9zZVBvc2l0aW9uIHBhcmFtZXRlcnMEFG9sZFBvc2l0aW9uVGltZXN0YW1wCAkBC2dldFBvc2l0aW9uAgUHX3RyYWRlcgUKX2RpcmVjdGlvbgJfNQQNJHQwNzI3NDQ3MzM0NwkBFWludGVybmFsQ2xvc2VQb3NpdGlvbggFB190cmFkZXIFCl9kaXJlY3Rpb24FBV9zaXplBQtwb3NpdGlvbkZlZQUUX21pblF1b3RlQXNzZXRBbW91bnQFDF9hZGRUb01hcmdpbgYGBA9uZXdQb3NpdGlvblNpemUIBQ0kdDA3Mjc0NDczMzQ3Al8xBBFuZXdQb3NpdGlvbk1hcmdpbggFDSR0MDcyNzQ0NzMzNDcCXzIEF25ld1Bvc2l0aW9uT3Blbk5vdGlvbmFsCAUNJHQwNzI3NDQ3MzM0NwJfMwQUbmV3UG9zaXRpb25Mc3RVcGRDUEYIBQ0kdDA3Mjc0NDczMzQ3Al80BA9wb3NpdGlvbkJhZERlYnQIBQ0kdDA3Mjc0NDczMzQ3Al81BAtyZWFsaXplZFBubAgFDSR0MDcyNzQ0NzMzNDcCXzYEDm1hcmdpblRvVHJhZGVyCAUNJHQwNzI3NDQ3MzM0NwJfNwQWcXVvdGVBc3NldFJlc2VydmVBZnRlcggFDSR0MDcyNzQ0NzMzNDcCXzgEFWJhc2VBc3NldFJlc2VydmVBZnRlcggFDSR0MDcyNzQ0NzMzNDcCXzkEFnRvdGFsUG9zaXRpb25TaXplQWZ0ZXIIBQ0kdDA3Mjc0NDczMzQ3A18xMAQZb3BlbkludGVyZXN0Tm90aW9uYWxBZnRlcggFDSR0MDcyNzQ0NzMzNDcDXzExBA50b3RhbExvbmdBZnRlcggFDSR0MDcyNzQ0NzMzNDcDXzEyBA90b3RhbFNob3J0QWZ0ZXIIBQ0kdDA3Mjc0NDczMzQ3A18xMwQadG90YWxMb25nT3BlbkludGVyZXN0QWZ0ZXIIBQ0kdDA3Mjc0NDczMzQ3A18xNAQbdG90YWxTaG9ydE9wZW5JbnRlcmVzdEFmdGVyCAUNJHQwNzI3NDQ3MzM0NwNfMTUEC3JlYWxpemVkRmVlCAUNJHQwNzI3NDQ3MzM0NwNfMTYDCQBmAgUPcG9zaXRpb25CYWREZWJ0AAAJAAIBAipJbnZhbGlkIGNsb3NlUG9zaXRpb24gcGFyYW1ldGVyczogYmFkIGRlYnQDCQBnAgUUb2xkUG9zaXRpb25UaW1lc3RhbXAJAQ1sYXN0VGltZXN0YW1wAAkAAgECU0ludmFsaWQgY2xvc2VQb3NpdGlvbiBwYXJhbWV0ZXJzOiB3YWl0IGF0IGxlYXN0IDEgYmxvY2sgYmVmb3JlIGNsb3NpbmcgdGhlIHBvc2l0aW9uBA5pc1BhcnRpYWxDbG9zZQkBAiE9AgUPbmV3UG9zaXRpb25TaXplAAAEDndpdGhkcmF3QW1vdW50CQBkAgUObWFyZ2luVG9UcmFkZXIFC3JlYWxpemVkRmVlBAphbW1CYWxhbmNlCQBlAgkBCGNiYWxhbmNlAAUOd2l0aGRyYXdBbW91bnQEDWFtbU5ld0JhbGFuY2UDCQBmAgAABQphbW1CYWxhbmNlAAAFCmFtbUJhbGFuY2UEB3Vuc3Rha2UJAPwHBAkBDHZhdWx0QWRkcmVzcwACDndpdGhkcmF3TG9ja2VkCQDMCAIFDndpdGhkcmF3QW1vdW50BQNuaWwFA25pbAMJAAACBQd1bnN0YWtlBQd1bnN0YWtlBA5yZWZlcnJlckZlZUFueQkA/AcECQEPcmVmZXJyYWxBZGRyZXNzAAINYWNjZXB0UGF5bWVudAkAzAgCBQdfdHJhZGVyBQNuaWwJAMwIAgkBD0F0dGFjaGVkUGF5bWVudAIJAQpxdW90ZUFzc2V0AAULcmVhbGl6ZWRGZWUFA25pbAMJAAACBQ5yZWZlcnJlckZlZUFueQUOcmVmZXJyZXJGZWVBbnkEC3JlZmVycmVyRmVlBAckbWF0Y2gwBQ5yZWZlcnJlckZlZUFueQMJAAECBQckbWF0Y2gwAgNJbnQEAXgFByRtYXRjaDAFAXgJAAIBAhNJbnZhbGlkIHJlZmVycmVyRmVlBA0kdDA3NDMxOTc0MzkyCQENZGlzdHJpYnV0ZUZlZQEJAGUCBQtyZWFsaXplZEZlZQULcmVmZXJyZXJGZWUEDGZlZVRvU3Rha2VycwgFDSR0MDc0MzE5NzQzOTICXzEECmZlZVRvVmF1bHQIBQ0kdDA3NDMxOTc0MzkyAl8yBAxkZXBvc2l0VmF1bHQJAPwHBAkBDHZhdWx0QWRkcmVzcwACB2FkZEZyZWUFA25pbAkAzAgCCQEPQXR0YWNoZWRQYXltZW50AgkBCnF1b3RlQXNzZXQABQpmZWVUb1ZhdWx0BQNuaWwDCQAAAgUMZGVwb3NpdFZhdWx0BQxkZXBvc2l0VmF1bHQECW5vdGlmeUZlZQkA/AcECQEMbWluZXJBZGRyZXNzAAIKbm90aWZ5RmVlcwkAzAgCBQdfdHJhZGVyCQDMCAIFC3JlYWxpemVkRmVlBQNuaWwFA25pbAMJAAACBQlub3RpZnlGZWUFCW5vdGlmeUZlZQQObm90aWZ5Tm90aW9uYWwJAPwHBAkBDG1pbmVyQWRkcmVzcwACDm5vdGlmeU5vdGlvbmFsCQDMCAIFB190cmFkZXIJAMwIAgUXbmV3UG9zaXRpb25PcGVuTm90aW9uYWwFA25pbAUDbmlsAwkAAAIFDm5vdGlmeU5vdGlvbmFsBQ5ub3RpZnlOb3Rpb25hbAkAzggCCQDOCAIJAM4IAgkAzggCAwUOaXNQYXJ0aWFsQ2xvc2UJAQ51cGRhdGVQb3NpdGlvbgYFB190cmFkZXIFD25ld1Bvc2l0aW9uU2l6ZQURbmV3UG9zaXRpb25NYXJnaW4FF25ld1Bvc2l0aW9uT3Blbk5vdGlvbmFsBRRuZXdQb3NpdGlvbkxzdFVwZENQRgkBDWxhc3RUaW1lc3RhbXAACQEOZGVsZXRlUG9zaXRpb24CBQdfdHJhZGVyBQpfZGlyZWN0aW9uCQEJdXBkYXRlQW1tCAUWcXVvdGVBc3NldFJlc2VydmVBZnRlcgUVYmFzZUFzc2V0UmVzZXJ2ZUFmdGVyBRZ0b3RhbFBvc2l0aW9uU2l6ZUFmdGVyBRlvcGVuSW50ZXJlc3ROb3Rpb25hbEFmdGVyBQ50b3RhbExvbmdBZnRlcgUPdG90YWxTaG9ydEFmdGVyBRp0b3RhbExvbmdPcGVuSW50ZXJlc3RBZnRlcgUbdG90YWxTaG9ydE9wZW5JbnRlcmVzdEFmdGVyAwkAZgIFDm1hcmdpblRvVHJhZGVyAAAJAQh3aXRoZHJhdwIFDl90cmFkZXJBZGRyZXNzBQ5tYXJnaW5Ub1RyYWRlcgUDbmlsCQENdXBkYXRlQmFsYW5jZQEFDWFtbU5ld0JhbGFuY2UJAQt0cmFuc2ZlckZlZQEFDGZlZVRvU3Rha2VycwkAAgECJFN0cmljdCB2YWx1ZSBpcyBub3QgZXF1YWwgdG8gaXRzZWxmLgkAAgECJFN0cmljdCB2YWx1ZSBpcyBub3QgZXF1YWwgdG8gaXRzZWxmLgkAAgECJFN0cmljdCB2YWx1ZSBpcyBub3QgZXF1YWwgdG8gaXRzZWxmLgkAAgECJFN0cmljdCB2YWx1ZSBpcyBub3QgZXF1YWwgdG8gaXRzZWxmLgkAAgECJFN0cmljdCB2YWx1ZSBpcyBub3QgZXF1YWwgdG8gaXRzZWxmLgkAAgECJFN0cmljdCB2YWx1ZSBpcyBub3QgZXF1YWwgdG8gaXRzZWxmLgkAAgECJFN0cmljdCB2YWx1ZSBpcyBub3QgZXF1YWwgdG8gaXRzZWxmLgkAAgECJFN0cmljdCB2YWx1ZSBpcyBub3QgZXF1YWwgdG8gaXRzZWxmLgFpAQlsaXF1aWRhdGUDB190cmFkZXIKX2RpcmVjdGlvbgxfcHJpY2VVcGRhdGUEDHVwZGF0ZU9yYWNsZQkA/AcEBQR0aGlzAgx1cGRhdGVPcmFjbGUJAMwIAgUMX3ByaWNlVXBkYXRlBQNuaWwFA25pbAMJAAACBQx1cGRhdGVPcmFjbGUFDHVwZGF0ZU9yYWNsZQQEc3luYwkA/AcEBQR0aGlzAhlzeW5jVGVybWluYWxQcmljZVRvT3JhY2xlBQNuaWwFA25pbAMJAAACBQRzeW5jBQRzeW5jBA9zcG90TWFyZ2luUmF0aW8JARZnZXRNYXJnaW5SYXRpb0J5T3B0aW9uAwUHX3RyYWRlcgUKX2RpcmVjdGlvbgUPUE5MX09QVElPTl9TUE9UBBZsaXF1aWRhdGlvbk1hcmdpblJhdGlvAwkBFmlzT3ZlckZsdWN0dWF0aW9uTGltaXQABBFvcmFjbGVNYXJnaW5SYXRpbwkBFmdldE1hcmdpblJhdGlvQnlPcHRpb24DBQdfdHJhZGVyBQpfZGlyZWN0aW9uBRFQTkxfT1BUSU9OX09SQUNMRQkBBHZtYXgCBQ9zcG90TWFyZ2luUmF0aW8FEW9yYWNsZU1hcmdpblJhdGlvBQ9zcG90TWFyZ2luUmF0aW8DAwMDAwkBASEBCQEWcmVxdWlyZU1vcmVNYXJnaW5SYXRpbwMFFmxpcXVpZGF0aW9uTWFyZ2luUmF0aW8JARZtYWludGVuYW5jZU1hcmdpblJhdGlvAAcGCQEBIQEJARNyZXF1aXJlT3BlblBvc2l0aW9uAgUHX3RyYWRlcgUKX2RpcmVjdGlvbgYJAQEhAQkBC2luaXRpYWxpemVkAAYJAQZwYXVzZWQABgkBDmlzTWFya2V0Q2xvc2VkAAkAAgECE1VuYWJsZSB0byBsaXF1aWRhdGUED29sZFBvc2l0aW9uU2l6ZQgJAQtnZXRQb3NpdGlvbgIFB190cmFkZXIFCl9kaXJlY3Rpb24CXzEED3Bvc2l0aW9uU2l6ZUFicwkBA2FicwEFD29sZFBvc2l0aW9uU2l6ZQQUaXNQYXJ0aWFsTGlxdWlkYXRpb24DAwMJAGYCBQ9zcG90TWFyZ2luUmF0aW8JARNsaXF1aWRhdGlvbkZlZVJhdGlvAAkAZgIJARdwYXJ0aWFsTGlxdWlkYXRpb25SYXRpbwAAAAcJAGYCBQxERUNJTUFMX1VOSVQJARdwYXJ0aWFsTGlxdWlkYXRpb25SYXRpbwAHCQBmAgkBBG11bGQCBQ9wb3NpdGlvblNpemVBYnMJAQxnZXRTcG90UHJpY2UACQEdbWluUGFydGlhbExpcXVpZGF0aW9uTm90aW9uYWwABwQNJHQwNzcwNjY3NzQ1MwMFFGlzUGFydGlhbExpcXVpZGF0aW9uBA9saXF1aWRhdGlvblNpemUJAQNhYnMBCQEbZ2V0UGFydGlhbExpcXVpZGF0aW9uQW1vdW50AgUHX3RyYWRlcgUPb2xkUG9zaXRpb25TaXplBBBsaXF1aWRhdGlvblJhdGlvCQEEZGl2ZAIFD2xpcXVpZGF0aW9uU2l6ZQUPcG9zaXRpb25TaXplQWJzBBNsaXF1aWRhdGlvbk5vdGlvbmFsCQEEbXVsZAIFD2xpcXVpZGF0aW9uU2l6ZQkBDGdldFNwb3RQcmljZQAJAJQKAgUQbGlxdWlkYXRpb25SYXRpbwUPbGlxdWlkYXRpb25TaXplCQCUCgIAAAUPcG9zaXRpb25TaXplQWJzBBBsaXF1aWRhdGlvblJhdGlvCAUNJHQwNzcwNjY3NzQ1MwJfMQQPbGlxdWlkYXRpb25TaXplCAUNJHQwNzcwNjY3NzQ1MwJfMgQNJHQwNzc0NTk3ODExNQkBFWludGVybmFsQ2xvc2VQb3NpdGlvbggFB190cmFkZXIFCl9kaXJlY3Rpb24DBRRpc1BhcnRpYWxMaXF1aWRhdGlvbgUPbGlxdWlkYXRpb25TaXplBQ9wb3NpdGlvblNpemVBYnMJARNsaXF1aWRhdGlvbkZlZVJhdGlvAAAABgcGBA9uZXdQb3NpdGlvblNpemUIBQ0kdDA3NzQ1OTc4MTE1Al8xBBFuZXdQb3NpdGlvbk1hcmdpbggFDSR0MDc3NDU5NzgxMTUCXzIEF25ld1Bvc2l0aW9uT3Blbk5vdGlvbmFsCAUNJHQwNzc0NTk3ODExNQJfMwQUbmV3UG9zaXRpb25Mc3RVcGRDUEYIBQ0kdDA3NzQ1OTc4MTE1Al80BA9wb3NpdGlvbkJhZERlYnQIBQ0kdDA3NzQ1OTc4MTE1Al81BAtyZWFsaXplZFBubAgFDSR0MDc3NDU5NzgxMTUCXzYEDm1hcmdpblRvVHJhZGVyCAUNJHQwNzc0NTk3ODExNQJfNwQWcXVvdGVBc3NldFJlc2VydmVBZnRlcggFDSR0MDc3NDU5NzgxMTUCXzgEFWJhc2VBc3NldFJlc2VydmVBZnRlcggFDSR0MDc3NDU5NzgxMTUCXzkEFnRvdGFsUG9zaXRpb25TaXplQWZ0ZXIIBQ0kdDA3NzQ1OTc4MTE1A18xMAQZb3BlbkludGVyZXN0Tm90aW9uYWxBZnRlcggFDSR0MDc3NDU5NzgxMTUDXzExBA50b3RhbExvbmdBZnRlcggFDSR0MDc3NDU5NzgxMTUDXzEyBA90b3RhbFNob3J0QWZ0ZXIIBQ0kdDA3NzQ1OTc4MTE1A18xMwQadG90YWxMb25nT3BlbkludGVyZXN0QWZ0ZXIIBQ0kdDA3NzQ1OTc4MTE1A18xNAQbdG90YWxTaG9ydE9wZW5JbnRlcmVzdEFmdGVyCAUNJHQwNzc0NTk3ODExNQNfMTUEEmxpcXVpZGF0aW9uUGVuYWx0eQgFDSR0MDc3NDU5NzgxMTUDXzE2BA9mZWVUb0xpcXVpZGF0b3IJAGkCBRJsaXF1aWRhdGlvblBlbmFsdHkAAgQKZmVlVG9WYXVsdAkAZQIFEmxpcXVpZGF0aW9uUGVuYWx0eQUPZmVlVG9MaXF1aWRhdG9yBAphbW1CYWxhbmNlCQBlAgkBCGNiYWxhbmNlAAUSbGlxdWlkYXRpb25QZW5hbHR5BA1uZXdBbW1CYWxhbmNlAwkAZgIAAAUKYW1tQmFsYW5jZQAABQphbW1CYWxhbmNlBAtsb2NrQmFkRGVidAMJAGYCBQ9wb3NpdGlvbkJhZERlYnQAAAQLbG9ja0JhZERlYnQJAPwHBAkBDHZhdWx0QWRkcmVzcwACFWV4Y2hhbmdlRnJlZUFuZExvY2tlZAkAzAgCCQBkAgUPcG9zaXRpb25CYWREZWJ0BRJsaXF1aWRhdGlvblBlbmFsdHkFA25pbAUDbmlsAwkAAAIFC2xvY2tCYWREZWJ0BQtsb2NrQmFkRGVidAUDbmlsCQACAQIkU3RyaWN0IHZhbHVlIGlzIG5vdCBlcXVhbCB0byBpdHNlbGYuBQNuaWwDCQAAAgULbG9ja0JhZERlYnQFC2xvY2tCYWREZWJ0BAd1bnN0YWtlCQD8BwQJAQx2YXVsdEFkZHJlc3MAAg53aXRoZHJhd0xvY2tlZAkAzAgCBRJsaXF1aWRhdGlvblBlbmFsdHkFA25pbAUDbmlsAwkAAAIFB3Vuc3Rha2UFB3Vuc3Rha2UEEGRlcG9zaXRJbnN1cmFuY2UJAPwHBAkBDHZhdWx0QWRkcmVzcwACB2FkZEZyZWUFA25pbAkAzAgCCQEPQXR0YWNoZWRQYXltZW50AgkBCnF1b3RlQXNzZXQABQpmZWVUb1ZhdWx0BQNuaWwDCQAAAgUQZGVwb3NpdEluc3VyYW5jZQUQZGVwb3NpdEluc3VyYW5jZQQObm90aWZ5Tm90aW9uYWwJAPwHBAkBDG1pbmVyQWRkcmVzcwACDm5vdGlmeU5vdGlvbmFsCQDMCAIFB190cmFkZXIJAMwIAgUXbmV3UG9zaXRpb25PcGVuTm90aW9uYWwFA25pbAUDbmlsAwkAAAIFDm5vdGlmeU5vdGlvbmFsBQ5ub3RpZnlOb3Rpb25hbAkAzggCCQDOCAIJAM4IAgMFFGlzUGFydGlhbExpcXVpZGF0aW9uCQEOdXBkYXRlUG9zaXRpb24GBQdfdHJhZGVyBQ9uZXdQb3NpdGlvblNpemUFEW5ld1Bvc2l0aW9uTWFyZ2luBRduZXdQb3NpdGlvbk9wZW5Ob3Rpb25hbAUUbmV3UG9zaXRpb25Mc3RVcGRDUEYJAQ1sYXN0VGltZXN0YW1wAAkBDmRlbGV0ZVBvc2l0aW9uAgUHX3RyYWRlcgUKX2RpcmVjdGlvbgkBCXVwZGF0ZUFtbQgFFnF1b3RlQXNzZXRSZXNlcnZlQWZ0ZXIFFWJhc2VBc3NldFJlc2VydmVBZnRlcgUWdG90YWxQb3NpdGlvblNpemVBZnRlcgUZb3BlbkludGVyZXN0Tm90aW9uYWxBZnRlcgUOdG90YWxMb25nQWZ0ZXIFD3RvdGFsU2hvcnRBZnRlcgUadG90YWxMb25nT3BlbkludGVyZXN0QWZ0ZXIFG3RvdGFsU2hvcnRPcGVuSW50ZXJlc3RBZnRlcgkBCHdpdGhkcmF3AggFAWkGY2FsbGVyBQ9mZWVUb0xpcXVpZGF0b3IJAQ11cGRhdGVCYWxhbmNlAQUNbmV3QW1tQmFsYW5jZQkAAgECJFN0cmljdCB2YWx1ZSBpcyBub3QgZXF1YWwgdG8gaXRzZWxmLgkAAgECJFN0cmljdCB2YWx1ZSBpcyBub3QgZXF1YWwgdG8gaXRzZWxmLgkAAgECJFN0cmljdCB2YWx1ZSBpcyBub3QgZXF1YWwgdG8gaXRzZWxmLgkAAgECJFN0cmljdCB2YWx1ZSBpcyBub3QgZXF1YWwgdG8gaXRzZWxmLgkAAgECJFN0cmljdCB2YWx1ZSBpcyBub3QgZXF1YWwgdG8gaXRzZWxmLgkAAgECJFN0cmljdCB2YWx1ZSBpcyBub3QgZXF1YWwgdG8gaXRzZWxmLgFpAQpwYXlGdW5kaW5nAQxfcHJpY2VVcGRhdGUEDHVwZGF0ZU9yYWNsZQkA/AcEBQR0aGlzAgx1cGRhdGVPcmFjbGUJAMwIAgUMX3ByaWNlVXBkYXRlBQNuaWwFA25pbAMJAAACBQx1cGRhdGVPcmFjbGUFDHVwZGF0ZU9yYWNsZQQEc3luYwkA/AcEBQR0aGlzAhlzeW5jVGVybWluYWxQcmljZVRvT3JhY2xlBQNuaWwFA25pbAMJAAACBQRzeW5jBQRzeW5jBBVmdW5kaW5nQmxvY2tUaW1lc3RhbXAJARluZXh0RnVuZGluZ0Jsb2NrVGltZXN0YW1wAAMDAwkAZgIFFWZ1bmRpbmdCbG9ja1RpbWVzdGFtcAkBDWxhc3RUaW1lc3RhbXAABgkBASEBCQELaW5pdGlhbGl6ZWQABgkBBnBhdXNlZAAJAAIBCQCsAgIJAKwCAgkArAICAiFJbnZhbGlkIGZ1bmRpbmcgYmxvY2sgdGltZXN0YW1wOiAJAKQDAQkBDWxhc3RUaW1lc3RhbXAAAgMgPCAJAKQDAQUVZnVuZGluZ0Jsb2NrVGltZXN0YW1wBA91bmRlcmx5aW5nUHJpY2UJAQ5nZXRPcmFjbGVQcmljZQAEDSR0MDgwMzMzODA0MTEJAQpnZXRGdW5kaW5nAAQUc2hvcnRQcmVtaXVtRnJhY3Rpb24IBQ0kdDA4MDMzMzgwNDExAl8xBBNsb25nUHJlbWl1bUZyYWN0aW9uCAUNJHQwODAzMzM4MDQxMQJfMgQOcHJlbWl1bVRvVmF1bHQIBQ0kdDA4MDMzMzgwNDExAl8zBBNkb1BheUZ1bmRpbmdUb1ZhdWx0AwkAZgIFDnByZW1pdW1Ub1ZhdWx0AAAEE2RvUGF5RnVuZGluZ1RvVmF1bHQJAPwHBAkBDHZhdWx0QWRkcmVzcwACFWV4Y2hhbmdlRnJlZUFuZExvY2tlZAkAzAgCCQEBLQEFDnByZW1pdW1Ub1ZhdWx0BQNuaWwFA25pbAMJAAACBRNkb1BheUZ1bmRpbmdUb1ZhdWx0BRNkb1BheUZ1bmRpbmdUb1ZhdWx0BQNuaWwJAAIBAiRTdHJpY3QgdmFsdWUgaXMgbm90IGVxdWFsIHRvIGl0c2VsZi4FA25pbAMJAAACBRNkb1BheUZ1bmRpbmdUb1ZhdWx0BRNkb1BheUZ1bmRpbmdUb1ZhdWx0CQENdXBkYXRlRnVuZGluZwUJAGQCBRVmdW5kaW5nQmxvY2tUaW1lc3RhbXAJARRmdW5kaW5nUGVyaW9kU2Vjb25kcwAJAGQCCQEjbGF0ZXN0TG9uZ0N1bXVsYXRpdmVQcmVtaXVtRnJhY3Rpb24ABRNsb25nUHJlbWl1bUZyYWN0aW9uCQBkAgkBJGxhdGVzdFNob3J0Q3VtdWxhdGl2ZVByZW1pdW1GcmFjdGlvbgAFFHNob3J0UHJlbWl1bUZyYWN0aW9uCQEEZGl2ZAIFE2xvbmdQcmVtaXVtRnJhY3Rpb24FD3VuZGVybHlpbmdQcmljZQkBBGRpdmQCBRRzaG9ydFByZW1pdW1GcmFjdGlvbgUPdW5kZXJseWluZ1ByaWNlCQACAQIkU3RyaWN0IHZhbHVlIGlzIG5vdCBlcXVhbCB0byBpdHNlbGYuCQACAQIkU3RyaWN0IHZhbHVlIGlzIG5vdCBlcXVhbCB0byBpdHNlbGYuCQACAQIkU3RyaWN0IHZhbHVlIGlzIG5vdCBlcXVhbCB0byBpdHNlbGYuAWkBDHVwZGF0ZU9yYWNsZQEMX3ByaWNlVXBkYXRlAwkAAAIJAQpvcmFjbGVNb2RlAAUMT1JBQ0xFX1BMQUlOBQNuaWwEDHByaWNlVXBkYXRlcwkAvAkCBQxfcHJpY2VVcGRhdGUCAjo6BApiYXNlT3JhY2xlCQETdmFsdWVPckVycm9yTWVzc2FnZQIJAQ1nZXRPcmFjbGVEYXRhAQUMa19iYXNlT3JhY2xlAhlObyBiYXNlIGFzc2V0IG9yYWNsZSBkYXRhBBFiYXNlT3JhY2xlQWRkcmVzcwgFCmJhc2VPcmFjbGUCXzEEEmRvVXBkYXRlQmFzZU9yYWNsZQkA/AcEBRFiYXNlT3JhY2xlQWRkcmVzcwIKdXBkYXRlRGF0YQkAzAgCCQCRAwIFDHByaWNlVXBkYXRlcwAABQNuaWwFA25pbAMJAAACBRJkb1VwZGF0ZUJhc2VPcmFjbGUFEmRvVXBkYXRlQmFzZU9yYWNsZQQLcXVvdGVPcmFjbGUJAQ1nZXRPcmFjbGVEYXRhAQUNa19xdW90ZU9yYWNsZQQTZG9VcGRhdGVRdW90ZU9yYWNsZQMJAQlpc0RlZmluZWQBBQtxdW90ZU9yYWNsZQQMcXVvdGVPcmFjbGVWCQEFdmFsdWUBBQtxdW90ZU9yYWNsZQQScXVvdGVPcmFjbGVBZGRyZXNzCAUMcXVvdGVPcmFjbGVWAl8xBBNkb1VwZGF0ZVF1b3RlT3JhY2xlCQD8BwQFEnF1b3RlT3JhY2xlQWRkcmVzcwIKdXBkYXRlRGF0YQkAzAgCCQCRAwIFDHByaWNlVXBkYXRlcwABBQNuaWwFA25pbAMJAAACBRNkb1VwZGF0ZVF1b3RlT3JhY2xlBRNkb1VwZGF0ZVF1b3RlT3JhY2xlBQNuaWwJAAIBAiRTdHJpY3QgdmFsdWUgaXMgbm90IGVxdWFsIHRvIGl0c2VsZi4FA25pbAMJAAACBRNkb1VwZGF0ZVF1b3RlT3JhY2xlBRNkb1VwZGF0ZVF1b3RlT3JhY2xlBQNuaWwJAAIBAiRTdHJpY3QgdmFsdWUgaXMgbm90IGVxdWFsIHRvIGl0c2VsZi4JAAIBAiRTdHJpY3QgdmFsdWUgaXMgbm90IGVxdWFsIHRvIGl0c2VsZi4BaQEZc3luY1Rlcm1pbmFsUHJpY2VUb09yYWNsZQAEB19xdEFzdFIJAQZxdEFzdFIABAdfYnNBc3RSCQEGYnNBc3RSAAQNJHQwODIyMjg4MjU5NAkBFGdldFN5bmNUZXJtaW5hbFByaWNlAwkBDmdldE9yYWNsZVByaWNlAAUHX3F0QXN0UgUHX2JzQXN0UgQTbmV3UXVvdGVBc3NldFdlaWdodAgFDSR0MDgyMjI4ODI1OTQCXzEEEm5ld0Jhc2VBc3NldFdlaWdodAgFDSR0MDgyMjI4ODI1OTQCXzIEDW1hcmdpblRvVmF1bHQIBQ0kdDA4MjIyODgyNTk0Al8zBBBtYXJnaW5Ub1ZhdWx0QWRqAwMJAGYCAAAFDW1hcmdpblRvVmF1bHQJAGYCCQEDYWJzAQUNbWFyZ2luVG9WYXVsdAkBCGNiYWxhbmNlAAcJAQEtAQkBCGNiYWxhbmNlAAUNbWFyZ2luVG9WYXVsdAQNZG9FeGNoYW5nZVBuTAMJAQIhPQIFEG1hcmdpblRvVmF1bHRBZGoAAAQNZG9FeGNoYW5nZVBuTAkA/AcECQEMdmF1bHRBZGRyZXNzAAIVZXhjaGFuZ2VGcmVlQW5kTG9ja2VkCQDMCAIFEG1hcmdpblRvVmF1bHRBZGoFA25pbAUDbmlsAwkAAAIFDWRvRXhjaGFuZ2VQbkwFDWRvRXhjaGFuZ2VQbkwFA25pbAkAAgECJFN0cmljdCB2YWx1ZSBpcyBub3QgZXF1YWwgdG8gaXRzZWxmLgUDbmlsAwkAAAIFDWRvRXhjaGFuZ2VQbkwFDWRvRXhjaGFuZ2VQbkwJAM4IAgkBDXVwZGF0ZUJhbGFuY2UBCQBkAgkBCGNiYWxhbmNlAAUQbWFyZ2luVG9WYXVsdEFkagkBEHVwZGF0ZUFtbVdlaWdodHMCBRNuZXdRdW90ZUFzc2V0V2VpZ2h0BRJuZXdCYXNlQXNzZXRXZWlnaHQJAAIBAiRTdHJpY3QgdmFsdWUgaXMgbm90IGVxdWFsIHRvIGl0c2VsZi4BaQEQZW5zdXJlQ2FsbGVkT25jZQADCQECIT0CCAUBaQZjYWxsZXIFBHRoaXMJAAIBAiJJbnZhbGlkIHNhdmVDdXJyZW50VHhJZCBwYXJhbWV0ZXJzBAR0eElkCQDYBAEIBQFpDXRyYW5zYWN0aW9uSWQEBmxhc3RUeAkBC3ZhbHVlT3JFbHNlAgkAnQgCBQR0aGlzBQhrX2xhc3RUeAIAAwkBAiE9AgUGbGFzdFR4BQR0eElkCQDMCAIJAQtTdHJpbmdFbnRyeQIFCGtfbGFzdFR4BQR0eElkBQNuaWwJAAIBAilDYW4gbm90IGNhbGwgdkFNTSBtZXRob2RzIHR3aWNlIGluIG9uZSB0eAFpAQ9taWdyYXRlUG9zaXRpb24BB190cmFkZXIED3Bvc2l0aW9uU2l6ZU9wdAkAmggCBQR0aGlzCQEOdG9Db21wb3NpdGVLZXkCBQ5rX3Bvc2l0aW9uU2l6ZQUHX3RyYWRlcgMDCQEJaXNEZWZpbmVkAQUPcG9zaXRpb25TaXplT3B0CQEJaXNEZWZpbmVkAQkApggBBQdfdHJhZGVyBwQFcFNpemUJARFAZXh0ck5hdGl2ZSgxMDUwKQIFBHRoaXMJAQ50b0NvbXBvc2l0ZUtleQIFDmtfcG9zaXRpb25TaXplBQdfdHJhZGVyBAdwTWFyZ2luCQERQGV4dHJOYXRpdmUoMTA1MCkCBQR0aGlzCQEOdG9Db21wb3NpdGVLZXkCBRBrX3Bvc2l0aW9uTWFyZ2luBQdfdHJhZGVyBAlwTm90aW9uYWwJARFAZXh0ck5hdGl2ZSgxMDUwKQIFBHRoaXMJAQ50b0NvbXBvc2l0ZUtleQIFFmtfcG9zaXRpb25PcGVuTm90aW9uYWwFB190cmFkZXIECXBGcmFjdGlvbgkBEUBleHRyTmF0aXZlKDEwNTApAgUEdGhpcwkBDnRvQ29tcG9zaXRlS2V5AgUua19wb3NpdGlvbkxhc3RVcGRhdGVkQ3VtdWxhdGl2ZVByZW1pdW1GcmFjdGlvbgUHX3RyYWRlcgQKcFRpbWVzdGFtcAkBC3ZhbHVlT3JFbHNlAgkAmggCBQR0aGlzCQEOdG9Db21wb3NpdGVLZXkCBR5rX3Bvc2l0aW9uTGFzdFVwZGF0ZWRUaW1lc3RhbXAFB190cmFkZXIIBQlsYXN0QmxvY2sJdGltZXN0YW1wBARwRmVlCQELdmFsdWVPckVsc2UCCQCaCAIFBHRoaXMJAQ50b0NvbXBvc2l0ZUtleQIFDWtfcG9zaXRpb25GZWUFB190cmFkZXIJAQNmZWUABAlwU2VxdWVuY2UJARFAZXh0ck5hdGl2ZSgxMDUwKQIFBHRoaXMJAQ50b0NvbXBvc2l0ZUtleQIFEmtfcG9zaXRpb25TZXF1ZW5jZQUHX3RyYWRlcgQKcERpcmVjdGlvbgkBDGdldERpcmVjdGlvbgEFBXBTaXplBAtwb3NpdGlvbktleQkArAICCQCsAgIFB190cmFkZXICAV8JAKQDAQUKcERpcmVjdGlvbgkAzAgCCQELRGVsZXRlRW50cnkBCQEOdG9Db21wb3NpdGVLZXkCBQ5rX3Bvc2l0aW9uU2l6ZQUHX3RyYWRlcgkAzAgCCQELRGVsZXRlRW50cnkBCQEOdG9Db21wb3NpdGVLZXkCBRBrX3Bvc2l0aW9uTWFyZ2luBQdfdHJhZGVyCQDMCAIJAQtEZWxldGVFbnRyeQEJAQ50b0NvbXBvc2l0ZUtleQIFFmtfcG9zaXRpb25PcGVuTm90aW9uYWwFB190cmFkZXIJAMwIAgkBC0RlbGV0ZUVudHJ5AQkBDnRvQ29tcG9zaXRlS2V5AgUua19wb3NpdGlvbkxhc3RVcGRhdGVkQ3VtdWxhdGl2ZVByZW1pdW1GcmFjdGlvbgUHX3RyYWRlcgkAzAgCCQELRGVsZXRlRW50cnkBCQEOdG9Db21wb3NpdGVLZXkCBR5rX3Bvc2l0aW9uTGFzdFVwZGF0ZWRUaW1lc3RhbXAFB190cmFkZXIJAMwIAgkBC0RlbGV0ZUVudHJ5AQkBDnRvQ29tcG9zaXRlS2V5AgUNa19wb3NpdGlvbkZlZQUHX3RyYWRlcgkAzAgCCQELRGVsZXRlRW50cnkBCQEOdG9Db21wb3NpdGVLZXkCBRJrX3Bvc2l0aW9uU2VxdWVuY2UFB190cmFkZXIJAMwIAgkBDEludGVnZXJFbnRyeQIJAQ50b0NvbXBvc2l0ZUtleQIFDmtfcG9zaXRpb25TaXplBQtwb3NpdGlvbktleQUFcFNpemUJAMwIAgkBDEludGVnZXJFbnRyeQIJAQ50b0NvbXBvc2l0ZUtleQIFEGtfcG9zaXRpb25NYXJnaW4FC3Bvc2l0aW9uS2V5BQdwTWFyZ2luCQDMCAIJAQxJbnRlZ2VyRW50cnkCCQEOdG9Db21wb3NpdGVLZXkCBRZrX3Bvc2l0aW9uT3Blbk5vdGlvbmFsBQtwb3NpdGlvbktleQUJcE5vdGlvbmFsCQDMCAIJAQxJbnRlZ2VyRW50cnkCCQEOdG9Db21wb3NpdGVLZXkCBS5rX3Bvc2l0aW9uTGFzdFVwZGF0ZWRDdW11bGF0aXZlUHJlbWl1bUZyYWN0aW9uBQtwb3NpdGlvbktleQUJcEZyYWN0aW9uCQDMCAIJAQxJbnRlZ2VyRW50cnkCCQEOdG9Db21wb3NpdGVLZXkCBR5rX3Bvc2l0aW9uTGFzdFVwZGF0ZWRUaW1lc3RhbXAFC3Bvc2l0aW9uS2V5BQpwVGltZXN0YW1wCQDMCAIJAQxJbnRlZ2VyRW50cnkCCQEOdG9Db21wb3NpdGVLZXkCBQ1rX3Bvc2l0aW9uRmVlBQtwb3NpdGlvbktleQUEcEZlZQkAzAgCCQEMSW50ZWdlckVudHJ5AgkBDnRvQ29tcG9zaXRlS2V5AgUSa19wb3NpdGlvblNlcXVlbmNlBQtwb3NpdGlvbktleQUJcFNlcXVlbmNlBQNuaWwJAAIBCQCsAgICF05vdGhpbmcgdG8gbWlncmF0ZSBmb3IgBQdfdHJhZGVyAWkBJ3ZpZXdfY2FsY1JlbWFpbk1hcmdpbldpdGhGdW5kaW5nUGF5bWVudAMHX3RyYWRlcgpfZGlyZWN0aW9uDF9wcmljZVVwZGF0ZQQMdXBkYXRlT3JhY2xlCQD8BwQFBHRoaXMCDHVwZGF0ZU9yYWNsZQkAzAgCBQxfcHJpY2VVcGRhdGUFA25pbAUDbmlsAwkAAAIFDHVwZGF0ZU9yYWNsZQUMdXBkYXRlT3JhY2xlBARzeW5jCQD8BwQFBHRoaXMCGXN5bmNUZXJtaW5hbFByaWNlVG9PcmFjbGUFA25pbAUDbmlsAwkAAAIFBHN5bmMFBHN5bmMEDSR0MDg2Mzg4ODY1MjQJAQtnZXRQb3NpdGlvbgIFB190cmFkZXIFCl9kaXJlY3Rpb24EDHBvc2l0aW9uU2l6ZQgFDSR0MDg2Mzg4ODY1MjQCXzEEDnBvc2l0aW9uTWFyZ2luCAUNJHQwODYzODg4NjUyNAJfMgQDcG9uCAUNJHQwODYzODg4NjUyNAJfMwQRcG9zaXRpb25Mc3RVcGRDUEYIBQ0kdDA4NjM4ODg2NTI0Al80BBFwb3NpdGlvblRpbWVzdGFtcAgFDSR0MDg2Mzg4ODY1MjQCXzUEDSR0MDg2NTI3ODY2NDAJASNnZXRQb3NpdGlvbk5vdGlvbmFsQW5kVW5yZWFsaXplZFBubAMFB190cmFkZXIFCl9kaXJlY3Rpb24FD1BOTF9PUFRJT05fU1BPVAQQcG9zaXRpb25Ob3Rpb25hbAgFDSR0MDg2NTI3ODY2NDACXzEEDXVucmVhbGl6ZWRQbmwIBQ0kdDA4NjUyNzg2NjQwAl8yBA0kdDA4NjY0Mzg2ODY3CQEwY2FsY1JlbWFpbk1hcmdpbldpdGhGdW5kaW5nUGF5bWVudEFuZFJvbGxvdmVyRmVlBQUMcG9zaXRpb25TaXplBQ5wb3NpdGlvbk1hcmdpbgURcG9zaXRpb25Mc3RVcGRDUEYFEXBvc2l0aW9uVGltZXN0YW1wBQ11bnJlYWxpemVkUG5sBAxyZW1haW5NYXJnaW4IBQ0kdDA4NjY0Mzg2ODY3Al8xBAdiYWREZWJ0CAUNJHQwODY2NDM4Njg2NwJfMgQOZnVuZGluZ1BheW1lbnQIBQ0kdDA4NjY0Mzg2ODY3Al8zBAtyb2xsb3ZlckZlZQgFDSR0MDg2NjQzODY4NjcCXzQED3VuZGVybHlpbmdQcmljZQkBDmdldE9yYWNsZVByaWNlAAQJc3BvdFByaWNlCQEMZ2V0U3BvdFByaWNlAAkAAgEJAKwCAgkArAICCQCsAgIJAKwCAgkArAICCQCsAgIJAKwCAgkArAICCQEBcwEFDHJlbWFpbk1hcmdpbgkBAXMBBQ5mdW5kaW5nUGF5bWVudAkBAXMBCQEOZ2V0TWFyZ2luUmF0aW8CBQdfdHJhZGVyBQpfZGlyZWN0aW9uCQEBcwEFDXVucmVhbGl6ZWRQbmwJAQFzAQUHYmFkRGVidAkBAXMBBRBwb3NpdGlvbk5vdGlvbmFsCQEBcwEFC3JvbGxvdmVyRmVlCQEBcwEFD3VuZGVybHlpbmdQcmljZQkBAXMBBQlzcG90UHJpY2UJAAIBAiRTdHJpY3QgdmFsdWUgaXMgbm90IGVxdWFsIHRvIGl0c2VsZi4JAAIBAiRTdHJpY3QgdmFsdWUgaXMgbm90IGVxdWFsIHRvIGl0c2VsZi4BaQEVdmlld19nZXRQZWdBZGp1c3RDb3N0AQZfcHJpY2UEB19xdEFzdFIJAQZxdEFzdFIABAdfYnNBc3RSCQEGYnNBc3RSAAQGcmVzdWx0CQEUZ2V0U3luY1Rlcm1pbmFsUHJpY2UDBQZfcHJpY2UFB19xdEFzdFIFB19ic0FzdFIJAAIBCQCkAwEIBQZyZXN1bHQCXzMBaQEYdmlld19nZXRUZXJtaW5hbEFtbVByaWNlAAQNJHQwODc3MjA4NzgwMQkBE2dldFRlcm1pbmFsQW1tU3RhdGUABBl0ZXJtaW5hbFF1b3RlQXNzZXRSZXNlcnZlCAUNJHQwODc3MjA4NzgwMQJfMQQYdGVybWluYWxCYXNlQXNzZXRSZXNlcnZlCAUNJHQwODc3MjA4NzgwMQJfMgQFcHJpY2UJAQRkaXZkAgkBBG11bGQCBRl0ZXJtaW5hbFF1b3RlQXNzZXRSZXNlcnZlCQEGcXRBc3RXAAkBBG11bGQCBRh0ZXJtaW5hbEJhc2VBc3NldFJlc2VydmUJAQZic0FzdFcACQACAQkApAMBBQVwcmljZQFpAQ92aWV3X2dldEZ1bmRpbmcBDF9wcmljZVVwZGF0ZQQMdXBkYXRlT3JhY2xlCQD8BwQFBHRoaXMCDHVwZGF0ZU9yYWNsZQkAzAgCBQxfcHJpY2VVcGRhdGUFA25pbAUDbmlsAwkAAAIFDHVwZGF0ZU9yYWNsZQUMdXBkYXRlT3JhY2xlBARzeW5jCQD8BwQFBHRoaXMCGXN5bmNUZXJtaW5hbFByaWNlVG9PcmFjbGUFA25pbAUDbmlsAwkAAAIFBHN5bmMFBHN5bmMED3VuZGVybHlpbmdQcmljZQkBDmdldE9yYWNsZVByaWNlAAQNJHQwODg0NTM4ODUzMQkBCmdldEZ1bmRpbmcABBRzaG9ydFByZW1pdW1GcmFjdGlvbggFDSR0MDg4NDUzODg1MzECXzEEE2xvbmdQcmVtaXVtRnJhY3Rpb24IBQ0kdDA4ODQ1Mzg4NTMxAl8yBA5wcmVtaXVtVG9WYXVsdAgFDSR0MDg4NDUzODg1MzECXzMEC2xvbmdGdW5kaW5nCQEEZGl2ZAIFE2xvbmdQcmVtaXVtRnJhY3Rpb24FD3VuZGVybHlpbmdQcmljZQQMc2hvcnRGdW5kaW5nCQEEZGl2ZAIFFHNob3J0UHJlbWl1bUZyYWN0aW9uBQ91bmRlcmx5aW5nUHJpY2UJAAIBCQCsAgIJAKwCAgkArAICCQCsAgIJAQFzAQULbG9uZ0Z1bmRpbmcJAQFzAQUMc2hvcnRGdW5kaW5nCQEBcwEJAQxnZXRTcG90UHJpY2UACQEBcwEJAQ5nZXRPcmFjbGVQcmljZQAJAQFzAQUOcHJlbWl1bVRvVmF1bHQJAAIBAiRTdHJpY3QgdmFsdWUgaXMgbm90IGVxdWFsIHRvIGl0c2VsZi4JAAIBAiRTdHJpY3QgdmFsdWUgaXMgbm90IGVxdWFsIHRvIGl0c2VsZi4BaQEQY29tcHV0ZVNwb3RQcmljZQAEBHN5bmMJAPwHBAUEdGhpcwIZc3luY1Rlcm1pbmFsUHJpY2VUb09yYWNsZQUDbmlsBQNuaWwDCQAAAgUEc3luYwUEc3luYwQGcmVzdWx0CQEMZ2V0U3BvdFByaWNlAAkAlAoCBQNuaWwFBnJlc3VsdAkAAgECJFN0cmljdCB2YWx1ZSBpcyBub3QgZXF1YWwgdG8gaXRzZWxmLgFpAR9jb21wdXRlRmVlRm9yVHJhZGVyV2l0aEFydGlmYWN0AgdfdHJhZGVyC19hcnRpZmFjdElkBAZyZXN1bHQJARhnZXRGb3JUcmFkZXJXaXRoQXJ0aWZhY3QCBQdfdHJhZGVyBQtfYXJ0aWZhY3RJZAkAlAoCBQNuaWwFBnJlc3VsdAECdHgBBnZlcmlmeQAEDmNvb3JkaW5hdG9yU3RyCQCdCAIFBHRoaXMFFGtfY29vcmRpbmF0b3JBZGRyZXNzAwkBCWlzRGVmaW5lZAEFDmNvb3JkaW5hdG9yU3RyBAVhZG1pbgkAnQgCCQERQGV4dHJOYXRpdmUoMTA2MikBCQEFdmFsdWUBBQ5jb29yZGluYXRvclN0cgUPa19hZG1pbl9hZGRyZXNzAwkBCWlzRGVmaW5lZAEFBWFkbWluCQELdmFsdWVPckVsc2UCCQCbCAIJARFAZXh0ck5hdGl2ZSgxMDYyKQEJAQV2YWx1ZQEFBWFkbWluCQCsAgIJAKwCAgkArAICAgdzdGF0dXNfCQClCAEFBHRoaXMCAV8JANgEAQgFAnR4AmlkBwkAAgECLnVuYWJsZSB0byB2ZXJpZnk6IGFkbWluIG5vdCBzZXQgaW4gY29vcmRpbmF0b3IJAPQDAwgFAnR4CWJvZHlCeXRlcwkAkQMCCAUCdHgGcHJvb2ZzAAAIBQJ0eA9zZW5kZXJQdWJsaWNLZXmCEnZd", "height": 2726343, "applicationStatus": "succeeded", "spentComplexity": 0 } View: original | compacted Prev: none Next: none Full:
OldNewDifferences
1-# no script
1+{-# STDLIB_VERSION 6 #-}
2+{-# SCRIPT_TYPE ACCOUNT #-}
3+{-# CONTENT_TYPE DAPP #-}
4+let k_baseOracle = "k_baseOracle"
5+
6+let k_quoteOracle = "k_quoteOracle"
7+
8+let k_balance = "k_balance"
9+
10+let k_sequence = "k_sequence"
11+
12+let k_positionSize = "k_positionSize"
13+
14+let k_positionMargin = "k_positionMargin"
15+
16+let k_positionOpenNotional = "k_positionOpenNotional"
17+
18+let k_positionLastUpdatedCumulativePremiumFraction = "k_positionFraction"
19+
20+let k_positionSequence = "k_positionSequence"
21+
22+let k_positionFee = "k_positionFee"
23+
24+let k_positionLastUpdatedTimestamp = "k_positionTimestamp"
25+
26+let k_initialized = "k_initialized"
27+
28+let k_paused = "k_paused"
29+
30+let k_closeOnly = "k_closeOnly"
31+
32+let k_fee = "k_fee"
33+
34+let k_rolloverFee = "k_rollover_fee"
35+
36+let k_fundingPeriod = "k_fundingPeriod"
37+
38+let k_initMarginRatio = "k_initMarginRatio"
39+
40+let k_minInitMarginRatio = "k_minInitMarginRatio"
41+
42+let k_maintenanceMarginRatio = "k_mmr"
43+
44+let k_liquidationFeeRatio = "k_liquidationFeeRatio"
45+
46+let k_partialLiquidationRatio = "k_partLiquidationRatio"
47+
48+let k_spreadLimit = "k_spreadLimit"
49+
50+let k_maxPriceImpact = "k_maxPriceImpact"
51+
52+let k_maxPriceSpread = "k_maxPriceSpread"
53+
54+let k_maxOpenNotional = "k_maxOpenNotional"
55+
56+let k_feeToStakersPercent = "k_feeToStakersPercent"
57+
58+let k_maxOracleDelay = "k_maxOracleDelay"
59+
60+let k_fundingMode = "k_fundingMode"
61+
62+let k_oracleMode = "k_oracleMode"
63+
64+let k_positionMode = "k_positionMode"
65+
66+let k_minLiquidationNotional = "k_minLiquidationNotional"
67+
68+let k_latestLongCumulativePremiumFraction = "k_latestLongPremiumFraction"
69+
70+let k_latestShortCumulativePremiumFraction = "k_latestShortPremiumFraction"
71+
72+let k_nextFundingBlock = "k_nextFundingBlockMinTimestamp"
73+
74+let k_longFundingRate = "k_longFundingRate"
75+
76+let k_shortFundingRate = "k_shortFundingRate"
77+
78+let k_quoteAssetReserve = "k_qtAstR"
79+
80+let k_baseAssetReserve = "k_bsAstR"
81+
82+let k_quoteAssetWeight = "k_qtAstW"
83+
84+let k_baseAssetWeight = "k_bsAstW"
85+
86+let k_totalPositionSize = "k_totalPositionSize"
87+
88+let k_totalLongPositionSize = "k_totalLongPositionSize"
89+
90+let k_totalShortPositionSize = "k_totalShortPositionSize"
91+
92+let k_openInterestNotional = "k_openInterestNotional"
93+
94+let k_openInterestShort = "k_openInterestShort"
95+
96+let k_openInterestLong = "k_openInterestLong"
97+
98+let k_lastTx = "k_lastTx"
99+
100+let k_coordinatorAddress = "k_coordinatorAddress"
101+
102+let k_vault_address = "k_vault_address"
103+
104+let k_admin_address = "k_admin_address"
105+
106+let k_quote_asset = "k_quote_asset"
107+
108+let k_staking_address = "k_staking_address"
109+
110+let k_miner_address = "k_miner_address"
111+
112+let k_orders_address = "k_orders_address"
113+
114+let k_referral_address = "k_referral_address"
115+
116+let k_nft_manager_address = "k_nft_manager_address"
117+
118+func toCompositeKey (_key,_address) = ((_key + "_") + _address)
119+
120+
121+func coordinator () = valueOrErrorMessage(addressFromString(getStringValue(this, k_coordinatorAddress)), "Coordinator not set")
122+
123+
124+func adminAddress () = addressFromString(getStringValue(coordinator(), k_admin_address))
125+
126+
127+func quoteAsset () = fromBase58String(getStringValue(coordinator(), k_quote_asset))
128+
129+
130+func stakingAddress () = valueOrErrorMessage(addressFromString(getStringValue(coordinator(), k_staking_address)), "Staking not set")
131+
132+
133+func vaultAddress () = valueOrErrorMessage(addressFromString(getStringValue(coordinator(), k_vault_address)), "Vault not set")
134+
135+
136+func minerAddress () = valueOrErrorMessage(addressFromString(getStringValue(coordinator(), k_miner_address)), "Miner not set")
137+
138+
139+func ordersAddress () = valueOrErrorMessage(addressFromString(getStringValue(coordinator(), k_orders_address)), "Orders not set")
140+
141+
142+func referralAddress () = valueOrErrorMessage(addressFromString(getStringValue(coordinator(), k_referral_address)), "Referral not set")
143+
144+
145+func nftManagerAddress () = valueOrErrorMessage(addressFromString(getStringValue(coordinator(), k_nft_manager_address)), "NFT Manager not set")
146+
147+
148+let k_token_param = "k_token_param"
149+
150+let k_token_type = "k_token_type"
151+
152+let FEE_REDUCTION_TOKEN_TYPE = "fee_reduction"
153+
154+let DIR_LONG = 1
155+
156+let DIR_SHORT = 2
157+
158+let SECONDS = 1000
159+
160+let DECIMAL_NUMBERS = 6
161+
162+let DECIMAL_UNIT = (1 * (((((10 * 10) * 10) * 10) * 10) * 10))
163+
164+let MINUTES_IN_YEAR = (525600 * DECIMAL_UNIT)
165+
166+let ONE_DAY = (86400 * DECIMAL_UNIT)
167+
168+let PNL_OPTION_SPOT = 1
169+
170+let PNL_OPTION_ORACLE = 2
171+
172+let FUNDING_ASYMMETRIC = 1
173+
174+let FUNDING_SYMMETRIC = 2
175+
176+let ORACLE_PLAIN = 1
177+
178+let ORACLE_JIT = 2
179+
180+let POSITION_DIRECT = 1
181+
182+let POSITION_ORDER = 2
183+
184+func s (_x) = (toString(_x) + ",")
185+
186+
187+func divd (_x,_y) = fraction(_x, DECIMAL_UNIT, _y, HALFEVEN)
188+
189+
190+func muld (_x,_y) = fraction(_x, _y, DECIMAL_UNIT, HALFEVEN)
191+
192+
193+func bdivd (_x,_y) = fraction(_x, toBigInt(DECIMAL_UNIT), _y, HALFEVEN)
194+
195+
196+func bmuld (_x,_y) = fraction(_x, _y, toBigInt(DECIMAL_UNIT), HALFEVEN)
197+
198+
199+func abs (_x) = if ((_x > 0))
200+ then _x
201+ else -(_x)
202+
203+
204+func vmax (_x,_y) = if ((_x >= _y))
205+ then _x
206+ else _y
207+
208+
209+func int (k) = valueOrErrorMessage(getInteger(this, k), ("no value for " + k))
210+
211+
212+func intOr (k,def) = valueOrElse(getInteger(this, k), def)
213+
214+
215+func strA (_address,_key) = {
216+ let val = valueOrErrorMessage(getString(_address, _key), ("No value for key " + _key))
217+ val
218+ }
219+
220+
221+func intA (_address,_key) = {
222+ let val = valueOrErrorMessage(getInteger(_address, _key), ("No value for key " + _key))
223+ val
224+ }
225+
226+
227+func cbalance () = int(k_balance)
228+
229+
230+func cbalance0 () = intOr(k_balance, 0)
231+
232+
233+func fee () = int(k_fee)
234+
235+
236+func rolloverFeeRate () = int(k_rolloverFee)
237+
238+
239+func initMarginRatio () = int(k_initMarginRatio)
240+
241+
242+func minInitMarginRatio () = intOr(k_minInitMarginRatio, DECIMAL_UNIT)
243+
244+
245+func qtAstR () = int(k_quoteAssetReserve)
246+
247+
248+func qtAstR0 () = intOr(k_quoteAssetReserve, 0)
249+
250+
251+func bsAstR () = int(k_baseAssetReserve)
252+
253+
254+func bsAstR0 () = intOr(k_baseAssetReserve, 0)
255+
256+
257+func qtAstW () = intOr(k_quoteAssetWeight, DECIMAL_UNIT)
258+
259+
260+func bsAstW () = intOr(k_baseAssetWeight, DECIMAL_UNIT)
261+
262+
263+func totalPositionSize () = int(k_totalPositionSize)
264+
265+
266+func openInterestNotional () = int(k_openInterestNotional)
267+
268+
269+func openInterestShort () = int(k_openInterestShort)
270+
271+
272+func openInterestLong () = int(k_openInterestLong)
273+
274+
275+func nextFundingBlockTimestamp () = int(k_nextFundingBlock)
276+
277+
278+func fundingPeriodRaw () = int(k_fundingPeriod)
279+
280+
281+func fundingPeriodDecimal () = (fundingPeriodRaw() * DECIMAL_UNIT)
282+
283+
284+func fundingPeriodSeconds () = (fundingPeriodRaw() * SECONDS)
285+
286+
287+func maintenanceMarginRatio () = int(k_maintenanceMarginRatio)
288+
289+
290+func liquidationFeeRatio () = int(k_liquidationFeeRatio)
291+
292+
293+func partialLiquidationRatio () = int(k_partialLiquidationRatio)
294+
295+
296+func spreadLimit () = int(k_spreadLimit)
297+
298+
299+func maxPriceImpact () = int(k_maxPriceImpact)
300+
301+
302+func maxPriceSpread () = int(k_maxPriceSpread)
303+
304+
305+func maxOpenNotional () = int(k_maxOpenNotional)
306+
307+
308+func latestLongCumulativePremiumFraction () = int(k_latestLongCumulativePremiumFraction)
309+
310+
311+func latestShortCumulativePremiumFraction () = int(k_latestShortCumulativePremiumFraction)
312+
313+
314+func totalShortPositionSize () = int(k_totalShortPositionSize)
315+
316+
317+func totalLongPositionSize () = int(k_totalLongPositionSize)
318+
319+
320+func lastSequence () = intOr(k_sequence, 0)
321+
322+
323+func feeToStakersPercent () = int(k_feeToStakersPercent)
324+
325+
326+func maxOracleDelay () = int(k_maxOracleDelay)
327+
328+
329+func fundingMode () = intOr(k_fundingMode, FUNDING_ASYMMETRIC)
330+
331+
332+func oracleMode () = intOr(k_oracleMode, ORACLE_PLAIN)
333+
334+
335+func positionMode () = intOr(k_positionMode, POSITION_DIRECT)
336+
337+
338+func minPartialLiquidationNotional () = intOr(k_minLiquidationNotional, (10 * DECIMAL_UNIT))
339+
340+
341+func lastTimestamp () = lastBlock.timestamp
342+
343+
344+func getActualCaller (i) = valueOrElse(getString(ordersAddress(), "k_sender"), toString(i.caller))
345+
346+
347+func requireMoreMarginRatio (_marginRatio,_baseMarginRatio,_largerThanOrEqualTo) = {
348+ let remainingMarginRatio = (_marginRatio - _baseMarginRatio)
349+ if (if (_largerThanOrEqualTo)
350+ then (0 > remainingMarginRatio)
351+ else false)
352+ then throw(((("Invalid margin: " + toString(_marginRatio)) + " < ") + toString(_baseMarginRatio)))
353+ else if (if (!(_largerThanOrEqualTo))
354+ then (remainingMarginRatio >= 0)
355+ else false)
356+ then throw(((("Invalid margin: " + toString(_marginRatio)) + " > ") + toString(_baseMarginRatio)))
357+ else true
358+ }
359+
360+
361+func latestCumulativePremiumFraction (_positionSize) = if ((_positionSize == 0))
362+ then throw("Should not be called with _positionSize == 0")
363+ else if ((_positionSize > 0))
364+ then latestLongCumulativePremiumFraction()
365+ else latestShortCumulativePremiumFraction()
366+
367+
368+func getPosition (_trader,_direction) = {
369+ let positionKey = ((_trader + "_") + toString(_direction))
370+ let positionSizeOpt = getInteger(this, toCompositeKey(k_positionSize, positionKey))
371+ match positionSizeOpt {
372+ case positionSize: Int =>
373+ $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)))
374+ case _ =>
375+ $Tuple5(0, 0, 0, 0, 0)
376+ }
377+ }
378+
379+
380+func getDirection (_positionSize) = if ((0 > _positionSize))
381+ then DIR_SHORT
382+ else DIR_LONG
383+
384+
385+func getPositionFee (_trader,_direction) = {
386+ let positionKey = ((_trader + "_") + toString(_direction))
387+ let positionFeeOpt = getInteger(this, toCompositeKey(k_positionFee, positionKey))
388+ match positionFeeOpt {
389+ case positionFee: Int =>
390+ positionFee
391+ case _ =>
392+ fee()
393+ }
394+ }
395+
396+
397+func requireOpenPosition (_trader,_direction) = if ((getPosition(_trader, _direction)._1 == 0))
398+ then throw("No open position")
399+ else true
400+
401+
402+func getOracleData (key) = {
403+ let oracleDataStr = getString(this, key)
404+ if (if (isDefined(oracleDataStr))
405+ then (value(oracleDataStr) != "")
406+ else false)
407+ then {
408+ let oracleData = split(value(oracleDataStr), ",")
409+ let oracleAddress = valueOrErrorMessage(addressFromString(oracleData[0]), ("Invalid oracle address in: " + value(oracleDataStr)))
410+ let priceKey = oracleData[1]
411+ let blockKey = oracleData[2]
412+ let openKey = oracleData[3]
413+ $Tuple4(oracleAddress, priceKey, blockKey, openKey)
414+ }
415+ else unit
416+ }
417+
418+
419+func initialized () = valueOrElse(getBoolean(this, k_initialized), false)
420+
421+
422+func paused () = valueOrElse(getBoolean(this, k_paused), false)
423+
424+
425+func closeOnly () = valueOrElse(getBoolean(this, k_closeOnly), false)
426+
427+
428+func updateReserve (_isAdd,_quoteAssetAmount,_baseAssetAmount) = if (_isAdd)
429+ then {
430+ let newBase = (bsAstR() - _baseAssetAmount)
431+ if ((0 >= newBase))
432+ then throw("Tx lead to base asset reserve <= 0, revert")
433+ else $Tuple3((qtAstR() + _quoteAssetAmount), newBase, (totalPositionSize() + _baseAssetAmount))
434+ }
435+ else {
436+ let newQuote = (qtAstR() - _quoteAssetAmount)
437+ if ((0 >= newQuote))
438+ then throw("Tx lead to base quote reserve <= 0, revert")
439+ else $Tuple3(newQuote, (bsAstR() + _baseAssetAmount), (totalPositionSize() - _baseAssetAmount))
440+ }
441+
442+
443+func calcInvariant (_qtAstR,_bsAstR) = {
444+ let bqtAstR = toBigInt(_qtAstR)
445+ let bbsAstR = toBigInt(_bsAstR)
446+ bmuld(bqtAstR, bbsAstR)
447+ }
448+
449+
450+func swapInput (_isAdd,_quoteAssetAmount) = {
451+ let _qtAstR = qtAstR()
452+ let _bsAstR = bsAstR()
453+ let _qtAstW = qtAstW()
454+ let _bsAstW = bsAstW()
455+ let quoteAssetAmountAdjusted = divd(_quoteAssetAmount, _qtAstW)
456+ let k = calcInvariant(_qtAstR, _bsAstR)
457+ let quoteAssetReserveAfter = if (_isAdd)
458+ then (_qtAstR + quoteAssetAmountAdjusted)
459+ else (_qtAstR - quoteAssetAmountAdjusted)
460+ let baseAssetReserveAfter = toInt(bdivd(k, toBigInt(quoteAssetReserveAfter)))
461+ let amountBaseAssetBoughtAbs = abs((baseAssetReserveAfter - _bsAstR))
462+ let amountBaseAssetBought = if (_isAdd)
463+ then amountBaseAssetBoughtAbs
464+ else -(amountBaseAssetBoughtAbs)
465+ let $t01658516755 = updateReserve(_isAdd, quoteAssetAmountAdjusted, amountBaseAssetBoughtAbs)
466+ let quoteAssetReserveAfter1 = $t01658516755._1
467+ let baseAssetReserveAfter1 = $t01658516755._2
468+ let totalPositionSizeAfter1 = $t01658516755._3
469+ let priceBefore = divd(muld(_qtAstR, _qtAstW), muld(_bsAstR, _bsAstW))
470+ let marketPrice = divd(_quoteAssetAmount, amountBaseAssetBoughtAbs)
471+ let priceDiff = abs((priceBefore - marketPrice))
472+ let priceImpact = (DECIMAL_UNIT - divd(priceBefore, (priceBefore + priceDiff)))
473+ let maxPriceImpactValue = maxPriceImpact()
474+ if ((priceImpact > maxPriceImpactValue))
475+ 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)))
476+ else $Tuple4(amountBaseAssetBought, quoteAssetReserveAfter1, baseAssetReserveAfter1, totalPositionSizeAfter1)
477+ }
478+
479+
480+func calcRolloverFee (_oldPositionMargin,_oldPositionLastUpdatedTimestamp) = {
481+ let positionMinutes = ((((lastTimestamp() - _oldPositionLastUpdatedTimestamp) / 1000) / 60) * DECIMAL_UNIT)
482+ let rolloverFee = divd(muld(muld(_oldPositionMargin, positionMinutes), rolloverFeeRate()), MINUTES_IN_YEAR)
483+ rolloverFee
484+ }
485+
486+
487+func calcRemainMarginWithFundingPaymentAndRolloverFee (_oldPositionSize,_oldPositionMargin,_oldPositionCumulativePremiumFraction,_oldPositionLastUpdatedTimestamp,_marginDelta) = {
488+ let fundingPayment = if ((_oldPositionSize != 0))
489+ then {
490+ let _latestCumulativePremiumFraction = latestCumulativePremiumFraction(_oldPositionSize)
491+ muld((_latestCumulativePremiumFraction - _oldPositionCumulativePremiumFraction), _oldPositionSize)
492+ }
493+ else 0
494+ let rolloverFee = calcRolloverFee(_oldPositionMargin, _oldPositionLastUpdatedTimestamp)
495+ let signedMargin = (((_marginDelta - rolloverFee) - fundingPayment) + _oldPositionMargin)
496+ let $t01942219549 = if ((0 > signedMargin))
497+ then $Tuple2(0, abs(signedMargin))
498+ else $Tuple2(abs(signedMargin), 0)
499+ let remainMargin = $t01942219549._1
500+ let badDebt = $t01942219549._2
501+ $Tuple4(remainMargin, badDebt, fundingPayment, rolloverFee)
502+ }
503+
504+
505+func swapOutputWithReserves (_isAdd,_baseAssetAmount,_checkMaxPriceImpact,_quoteAssetReserve,_quoteAssetWeight,_baseAssetReserve,_baseAssetWeight) = {
506+ let priceBefore = divd(muld(_quoteAssetReserve, _quoteAssetWeight), muld(_baseAssetReserve, _baseAssetWeight))
507+ if ((_baseAssetAmount == 0))
508+ then throw("Invalid base asset amount")
509+ else {
510+ let k = calcInvariant(_quoteAssetReserve, _baseAssetReserve)
511+ let baseAssetPoolAmountAfter = if (_isAdd)
512+ then (_baseAssetReserve + _baseAssetAmount)
513+ else (_baseAssetReserve - _baseAssetAmount)
514+ let quoteAssetAfter = toInt(bdivd(k, toBigInt(baseAssetPoolAmountAfter)))
515+ let quoteAssetDelta = abs((quoteAssetAfter - _quoteAssetReserve))
516+ let quoteAssetSold = muld(quoteAssetDelta, _quoteAssetWeight)
517+ let maxPriceImpactValue = maxPriceImpact()
518+ let $t02081120973 = updateReserve(!(_isAdd), quoteAssetDelta, _baseAssetAmount)
519+ let quoteAssetReserveAfter1 = $t02081120973._1
520+ let baseAssetReserveAfter1 = $t02081120973._2
521+ let totalPositionSizeAfter1 = $t02081120973._3
522+ let marketPrice = divd(quoteAssetSold, _baseAssetAmount)
523+ let priceDiff = abs((priceBefore - marketPrice))
524+ let priceImpact = (DECIMAL_UNIT - divd(priceBefore, (priceBefore + priceDiff)))
525+ if (if ((priceImpact > maxPriceImpactValue))
526+ then _checkMaxPriceImpact
527+ else false)
528+ 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)))
529+ else $Tuple7(quoteAssetSold, quoteAssetReserveAfter1, baseAssetReserveAfter1, totalPositionSizeAfter1, (totalLongPositionSize() - (if (_isAdd)
530+ then abs(_baseAssetAmount)
531+ else 0)), (totalShortPositionSize() - (if (!(_isAdd))
532+ then abs(_baseAssetAmount)
533+ else 0)), priceImpact)
534+ }
535+ }
536+
537+
538+func swapOutput (_isAdd,_baseAssetAmount,_checkMaxPriceImpact) = swapOutputWithReserves(_isAdd, _baseAssetAmount, _checkMaxPriceImpact, qtAstR(), qtAstW(), bsAstR(), bsAstW())
539+
540+
541+func getOraclePriceValue (oracle,priceKey,blockKey) = {
542+ let lastValue = valueOrErrorMessage(getInteger(oracle, priceKey), ((("Can not get oracle price. Oracle: " + toString(oracle)) + " key: ") + priceKey))
543+ if ((blockKey != ""))
544+ then {
545+ let currentBlock = height
546+ let lastOracleBlock = valueOrErrorMessage(getInteger(oracle, blockKey), ((("Can not get oracle block. Oracle: " + toString(oracle)) + " key: ") + blockKey))
547+ if (((currentBlock - lastOracleBlock) > maxOracleDelay()))
548+ then throw(((("Oracle stale data. Last oracle block: " + toString(lastOracleBlock)) + " current block: ") + toString(currentBlock)))
549+ else lastValue
550+ }
551+ else lastValue
552+ }
553+
554+
555+func getOraclePrice () = {
556+ let baseOracle = valueOrErrorMessage(getOracleData(k_baseOracle), "No base asset oracle data")
557+ let baseOraclePrice = getOraclePriceValue(baseOracle._1, baseOracle._2, baseOracle._3)
558+ let quoteOracle = getOracleData(k_quoteOracle)
559+ let quoteOraclePrice = if (isDefined(quoteOracle))
560+ then {
561+ let quoteOracleV = value(quoteOracle)
562+ getOraclePriceValue(quoteOracleV._1, quoteOracleV._2, quoteOracleV._3)
563+ }
564+ else DECIMAL_UNIT
565+ divd(baseOraclePrice, quoteOraclePrice)
566+ }
567+
568+
569+func isMarketClosed () = {
570+ let baseOracle = valueOrErrorMessage(getOracleData(k_baseOracle), "No base asset oracle data")
571+ let oracle = baseOracle._1
572+ let openKey = baseOracle._4
573+ if ((openKey != ""))
574+ then {
575+ let isOpen = valueOrErrorMessage(getBoolean(oracle, openKey), ((("Can not get oracle is open/closed. Oracle: " + toString(oracle)) + " key: ") + openKey))
576+ !(isOpen)
577+ }
578+ else false
579+ }
580+
581+
582+func absPriceDiff (_oraclePrice,_quoteAssetReserve,_baseAssetReserve,_qtAstW,_bsAstW) = {
583+ let priceAfter = divd(muld(_quoteAssetReserve, _qtAstW), muld(_baseAssetReserve, _bsAstW))
584+ let averagePrice = divd((_oraclePrice + priceAfter), (2 * DECIMAL_UNIT))
585+ let absPriceDiff = divd(abs((_oraclePrice - priceAfter)), averagePrice)
586+ absPriceDiff
587+ }
588+
589+
590+func requireNotOverSpreadLimit (_quoteAssetReserve,_baseAssetReserve) = {
591+ let oraclePrice = getOraclePrice()
592+ let _qtAstW = qtAstW()
593+ let _bsAstW = bsAstW()
594+ let absPriceDiffBefore = absPriceDiff(oraclePrice, qtAstR(), bsAstR(), _qtAstW, _bsAstW)
595+ let absPriceDiffAfter = absPriceDiff(oraclePrice, _quoteAssetReserve, _baseAssetReserve, _qtAstW, _bsAstW)
596+ if (if ((absPriceDiffAfter > maxPriceSpread()))
597+ then (absPriceDiffAfter > absPriceDiffBefore)
598+ else false)
599+ then throw(((("Price spread " + toString(absPriceDiffAfter)) + " > max price spread ") + toString(maxPriceSpread())))
600+ else true
601+ }
602+
603+
604+func requireNotOverMaxOpenNotional (_longOpenNotional,_shortOpenNotional) = {
605+ let _maxOpenNotional = maxOpenNotional()
606+ if ((_longOpenNotional > _maxOpenNotional))
607+ then throw(((("Long open notional " + toString(_longOpenNotional)) + " > max open notional ") + toString(_maxOpenNotional)))
608+ else if ((_shortOpenNotional > _maxOpenNotional))
609+ then throw(((("Short open notional " + toString(_shortOpenNotional)) + " > max open notional ") + toString(_maxOpenNotional)))
610+ else true
611+ }
612+
613+
614+func requireSenderCanWorkWithPositions (_caller) = if ((positionMode() == POSITION_ORDER))
615+ then (_caller == ordersAddress())
616+ else true
617+
618+
619+func getSpotPrice () = {
620+ let _quoteAssetReserve = qtAstR()
621+ let _baseAssetReserve = bsAstR()
622+ let _qtAstW = qtAstW()
623+ let _bsAstW = bsAstW()
624+ divd(muld(_quoteAssetReserve, _qtAstW), muld(_baseAssetReserve, _bsAstW))
625+ }
626+
627+
628+func isOverFluctuationLimit () = {
629+ let oraclePrice = getOraclePrice()
630+ let currentPrice = getSpotPrice()
631+ (divd(abs((oraclePrice - currentPrice)), oraclePrice) > spreadLimit())
632+ }
633+
634+
635+func getPositionAdjustedOpenNotional (_positionSize,_option,_quoteAssetReserve,_quoteAssetWeight,_baseAssetReserve,_baseAssetWeight) = {
636+ let positionSizeAbs = abs(_positionSize)
637+ let isShort = (0 > _positionSize)
638+ let positionNotional = if ((_option == PNL_OPTION_SPOT))
639+ then {
640+ let outPositionNotional = swapOutputWithReserves(!(isShort), positionSizeAbs, false, _quoteAssetReserve, _quoteAssetWeight, _baseAssetReserve, _baseAssetWeight)._1
641+ outPositionNotional
642+ }
643+ else muld(positionSizeAbs, getOraclePrice())
644+ positionNotional
645+ }
646+
647+
648+func getPositionNotionalAndUnrealizedPnlByValues (_positionSize,_positionOpenNotional,_quoteAssetReserve,_quoteAssetWeight,_baseAssetReserve,_baseAssetWeight,_option) = if ((_positionSize == 0))
649+ then throw("Invalid position size")
650+ else {
651+ let isShort = (0 > _positionSize)
652+ let positionNotional = getPositionAdjustedOpenNotional(_positionSize, _option, _quoteAssetReserve, _quoteAssetWeight, _baseAssetReserve, _baseAssetWeight)
653+ let unrealizedPnl = if (isShort)
654+ then (_positionOpenNotional - positionNotional)
655+ else (positionNotional - _positionOpenNotional)
656+ $Tuple2(positionNotional, unrealizedPnl)
657+ }
658+
659+
660+func getPositionNotionalAndUnrealizedPnl (_trader,_direction,_option) = {
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
666+ getPositionNotionalAndUnrealizedPnlByValues(positionSize, positionOpenNotional, qtAstR(), qtAstW(), bsAstR(), bsAstW(), _option)
667+ }
668+
669+
670+func calcMarginRatio (_remainMargin,_badDebt,_positionNotional) = divd((_remainMargin - _badDebt), _positionNotional)
671+
672+
673+func getMarginRatioByOption (_trader,_direction,_option) = {
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
686+ calcMarginRatio(remainMargin, badDebt, positionNotional)
687+ }
688+
689+
690+func getMarginRatio (_trader,_direction) = getMarginRatioByOption(_trader, _direction, PNL_OPTION_SPOT)
691+
692+
693+func getPartialLiquidationAmount (_trader,_positionSize) = {
694+ let maximumRatio = vmax(partialLiquidationRatio(), (DECIMAL_UNIT - divd(getMarginRatio(_trader, getDirection(_positionSize)), maintenanceMarginRatio())))
695+ let maxExchangedPositionSize = muld(abs(_positionSize), maximumRatio)
696+ let swapResult = swapOutput((_positionSize > 0), maxExchangedPositionSize, false)
697+ let maxExchangedQuoteAssetAmount = swapResult._1
698+ let priceImpact = swapResult._7
699+ if ((maxPriceImpact() > priceImpact))
700+ then maxExchangedPositionSize
701+ else muld(abs(_positionSize), partialLiquidationRatio())
702+ }
703+
704+
705+func internalClosePosition (_trader,_direction,_size,_fee,_minQuoteAssetAmount,_addToMargin,_checkMaxPriceImpact,_liquidate) = {
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
712+ let isLongPosition = (oldPositionSize > 0)
713+ let absOldPositionSize = abs(oldPositionSize)
714+ if (if ((absOldPositionSize >= _size))
715+ then (_size > 0)
716+ else false)
717+ then {
718+ let isPartialClose = (absOldPositionSize > _size)
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
724+ let exchangedPositionSize = if ((oldPositionSize > 0))
725+ then -(_size)
726+ else _size
727+ let $t03255632780 = getPositionNotionalAndUnrealizedPnl(_trader, _direction, PNL_OPTION_SPOT)
728+ let oldPositionNotional = $t03255632780._1
729+ let unrealizedPnl = $t03255632780._2
730+ let realizedRatio = divd(abs(exchangedPositionSize), absOldPositionSize)
731+ let realizedPnl = muld(unrealizedPnl, realizedRatio)
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
737+ let positionBadDebt = calcRemainMarginWithFundingPaymentAndRolloverFee(oldPositionSize, oldPositionMargin, oldPositionLstUpdCPF, oldPositionTimestamp, realizedPnl)._2
738+ let realizedCloseFee = muld(muld(oldPositionNotional, realizedRatio), _fee)
739+ let unrealizedPnlAfter = (unrealizedPnl - realizedPnl)
740+ let remainOpenNotional = if ((oldPositionSize > 0))
741+ then ((oldPositionNotional - exchangedQuoteAssetAmount) - unrealizedPnlAfter)
742+ else ((unrealizedPnlAfter + oldPositionNotional) - exchangedQuoteAssetAmount)
743+ let newPositionSize = (oldPositionSize + exchangedPositionSize)
744+ let $t03477335159 = if ((newPositionSize == 0))
745+ then $Tuple2(0, 0)
746+ else $Tuple2(abs(remainOpenNotional), latestCumulativePremiumFraction(newPositionSize))
747+ let newPositionOpenNotional = $t03477335159._1
748+ let newPositionLstUpdCPF = $t03477335159._2
749+ let openNotionalDelta = (oldPositionOpenNotional - newPositionOpenNotional)
750+ let marginRatio = getMarginRatioByOption(_trader, _direction, PNL_OPTION_SPOT)
751+ let newPositionMarginWithSameRatio = if ((oldPositionSize > 0))
752+ then (muld((newPositionOpenNotional + unrealizedPnlAfter), marginRatio) - unrealizedPnlAfter)
753+ else (muld((newPositionOpenNotional - unrealizedPnlAfter), marginRatio) - unrealizedPnlAfter)
754+ let marginToTraderRaw = ((remainMarginBefore - (newPositionMarginWithSameRatio + unrealizedPnlAfter)) - realizedCloseFee)
755+ let marginToTrader = if ((0 > marginToTraderRaw))
756+ then if (_liquidate)
757+ then 0
758+ else throw("Invalid internalClosePosition params: unable to pay fee")
759+ else marginToTraderRaw
760+ let newPositionMargin = if (_addToMargin)
761+ then (newPositionMarginWithSameRatio + marginToTrader)
762+ else newPositionMarginWithSameRatio
763+ if (if ((_minQuoteAssetAmount != 0))
764+ then (_minQuoteAssetAmount > exchangedQuoteAssetAmount)
765+ else false)
766+ then throw(((("Limit error: " + toString(exchangedQuoteAssetAmount)) + " < ") + toString(_minQuoteAssetAmount)))
767+ else $Tuple17(newPositionSize, newPositionMargin, newPositionOpenNotional, newPositionLstUpdCPF, positionBadDebt, realizedPnl, if (if (_addToMargin)
768+ then isPartialClose
769+ else false)
770+ then 0
771+ else marginToTrader, quoteAssetReserveAfter, baseAssetReserveAfter, totalPositionSizeAfter, (openInterestNotional() - openNotionalDelta), (totalLongPositionSize() - (if (isLongPosition)
772+ then abs(exchangedPositionSize)
773+ else 0)), (totalShortPositionSize() - (if (!(isLongPosition))
774+ then abs(exchangedPositionSize)
775+ else 0)), (openInterestLong() - (if (isLongPosition)
776+ then openNotionalDelta
777+ else 0)), (openInterestShort() - (if (!(isLongPosition))
778+ then openNotionalDelta
779+ else 0)), (realizedCloseFee + rolloverFee), exchangedQuoteAssetAmount)
780+ }
781+ else throw(((("Invalid internalClosePosition params: invalid position size: " + toString(_size)) + " max: ") + toString(absOldPositionSize)))
782+ }
783+
784+
785+func getTerminalAmmState () = {
786+ let _positionSize = totalPositionSize()
787+ if ((_positionSize == 0))
788+ then $Tuple2(qtAstR(), bsAstR())
789+ else {
790+ let direction = (_positionSize > 0)
791+ let $t03840638585 = swapOutput(direction, abs(_positionSize), false)
792+ let currentNetMarketValue = $t03840638585._1
793+ let terminalQuoteAssetReserve = $t03840638585._2
794+ let terminalBaseAssetReserve = $t03840638585._3
795+ $Tuple2(terminalQuoteAssetReserve, terminalBaseAssetReserve)
796+ }
797+ }
798+
799+
800+func getQuoteAssetWeight (baseAssetReserve,totalPositionSize,quoteAssetReserve,targetPrice) = {
801+ let b = toBigInt(baseAssetReserve)
802+ let sz = toBigInt(totalPositionSize)
803+ let q = toBigInt(quoteAssetReserve)
804+ let p = toBigInt(targetPrice)
805+ let k = bmuld(q, b)
806+ let newB = (b + sz)
807+ let newQ = bdivd(k, newB)
808+ let z = bdivd(newQ, newB)
809+ let result = bdivd(p, z)
810+ toInt(result)
811+ }
812+
813+
814+func getSyncTerminalPrice (_terminalPrice,_qtAstR,_bsAstR) = {
815+ let _positionSize = totalPositionSize()
816+ if ((_positionSize == 0))
817+ then {
818+ let newQtAstW = divd(muld(_terminalPrice, _bsAstR), _qtAstR)
819+ $Tuple3(newQtAstW, DECIMAL_UNIT, 0)
820+ }
821+ else {
822+ let direction = (_positionSize > 0)
823+ let currentNetMarketValue = swapOutput(direction, abs(_positionSize), false)._1
824+ let newQtAstW = getQuoteAssetWeight(_bsAstR, _positionSize, _qtAstR, _terminalPrice)
825+ let newBsAstW = DECIMAL_UNIT
826+ let marginToVault = getPositionNotionalAndUnrealizedPnlByValues(_positionSize, currentNetMarketValue, _qtAstR, newQtAstW, _bsAstR, newBsAstW, PNL_OPTION_SPOT)._2
827+ $Tuple3(newQtAstW, newBsAstW, marginToVault)
828+ }
829+ }
830+
831+
832+func getFunding () = {
833+ let underlyingPrice = getOraclePrice()
834+ let spotPrice = getSpotPrice()
835+ let premium = (spotPrice - underlyingPrice)
836+ if (if (isMarketClosed())
837+ then true
838+ else if ((fundingMode() == FUNDING_ASYMMETRIC))
839+ then if ((totalShortPositionSize() == 0))
840+ then true
841+ else (totalLongPositionSize() == 0)
842+ else false)
843+ then $Tuple3(0, 0, 0)
844+ else if ((0 > premium))
845+ then {
846+ let shortPremiumFraction = divd(muld(premium, fundingPeriodDecimal()), ONE_DAY)
847+ if ((fundingMode() == FUNDING_ASYMMETRIC))
848+ then {
849+ let longPremiumFraction = divd(muld(shortPremiumFraction, totalShortPositionSize()), totalLongPositionSize())
850+ $Tuple3(shortPremiumFraction, longPremiumFraction, 0)
851+ }
852+ else {
853+ let shortTotalPremiumFraction = abs(muld(shortPremiumFraction, totalShortPositionSize()))
854+ let longTotalPremiumFraction = abs(muld(shortPremiumFraction, totalLongPositionSize()))
855+ let premiumToVault = (shortTotalPremiumFraction - longTotalPremiumFraction)
856+ $Tuple3(shortPremiumFraction, shortPremiumFraction, premiumToVault)
857+ }
858+ }
859+ else {
860+ let longPremiumFraction = divd(muld(premium, fundingPeriodDecimal()), ONE_DAY)
861+ if ((fundingMode() == FUNDING_ASYMMETRIC))
862+ then {
863+ let shortPremiumFraction = divd(muld(longPremiumFraction, totalLongPositionSize()), totalShortPositionSize())
864+ $Tuple3(shortPremiumFraction, longPremiumFraction, 0)
865+ }
866+ else {
867+ let longTotalPremiumFraction = abs(muld(longPremiumFraction, totalLongPositionSize()))
868+ let shortTotalPremiumFraction = abs(muld(longPremiumFraction, totalShortPositionSize()))
869+ let premiumToVault = (longTotalPremiumFraction - shortTotalPremiumFraction)
870+ $Tuple3(longPremiumFraction, longPremiumFraction, premiumToVault)
871+ }
872+ }
873+ }
874+
875+
876+func getAdjustedFee (_artifactId,_baseFeeDiscount) = {
877+ let baseFeeRaw = fee()
878+ let baseFee = muld(baseFeeRaw, _baseFeeDiscount)
879+ let $t04324943744 = if ((_artifactId != ""))
880+ then {
881+ let artifactKind = strA(nftManagerAddress(), toCompositeKey(k_token_type, _artifactId))
882+ if ((artifactKind == FEE_REDUCTION_TOKEN_TYPE))
883+ then {
884+ let reduction = intA(nftManagerAddress(), toCompositeKey(k_token_param, _artifactId))
885+ let adjustedFee = muld(baseFee, reduction)
886+ $Tuple2(adjustedFee, true)
887+ }
888+ else throw("Invalid attached artifact")
889+ }
890+ else $Tuple2(baseFee, false)
891+ let adjustedFee = $t04324943744._1
892+ let burnArtifact = $t04324943744._2
893+ $Tuple2(adjustedFee, burnArtifact)
894+ }
895+
896+
897+func getForTraderWithArtifact (_trader,_artifactId) = {
898+ let doGetFeeDiscount = invoke(minerAddress(), "computeFeeDiscount", [_trader], nil)
899+ if ((doGetFeeDiscount == doGetFeeDiscount))
900+ then {
901+ let feeDiscount = match doGetFeeDiscount {
902+ case x: Int =>
903+ x
904+ case _ =>
905+ throw("Invalid computeFeeDiscount result")
906+ }
907+ let $t04409044164 = getAdjustedFee(_artifactId, feeDiscount)
908+ let adjustedFee = $t04409044164._1
909+ let burnArtifact = $t04409044164._2
910+ $Tuple2(adjustedFee, burnArtifact)
911+ }
912+ else throw("Strict value is not equal to itself.")
913+ }
914+
915+
916+func getArtifactId (i) = {
917+ let artifactId = if ((size(i.payments) > 1))
918+ then toBase58String(valueOrErrorMessage(i.payments[1].assetId, "Invalid artifactId"))
919+ else ""
920+ artifactId
921+ }
922+
923+
924+func distributeFee (_feeAmount) = {
925+ let feeToStakers = muld(_feeAmount, feeToStakersPercent())
926+ let feeToVault = (_feeAmount - feeToStakers)
927+ $Tuple2(feeToStakers, feeToVault)
928+ }
929+
930+
931+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)]
932+
933+
934+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)]
935+
936+
937+func incrementPositionSequenceNumber (_isNewPosition,_trader,_direction) = {
938+ let positionKey = ((_trader + "_") + toString(_direction))
939+ if (_isNewPosition)
940+ then {
941+ let currentSequence = lastSequence()
942+[IntegerEntry(toCompositeKey(k_positionSequence, positionKey), (currentSequence + 1)), IntegerEntry(k_sequence, (currentSequence + 1))]
943+ }
944+ else nil
945+ }
946+
947+
948+func updatePositionFee (_isNewPosition,_trader,_direction,_fee) = {
949+ let positionKey = ((_trader + "_") + toString(_direction))
950+ if (_isNewPosition)
951+ then [IntegerEntry(toCompositeKey(k_positionFee, positionKey), _fee)]
952+ else nil
953+ }
954+
955+
956+func updatePosition (_trader,_size,_margin,_openNotional,_latestCumulativePremiumFraction,_latestTimestamp) = {
957+ let direction = getDirection(_size)
958+ let positionKey = ((_trader + "_") + toString(direction))
959+[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)]
960+ }
961+
962+
963+func updateAmmReserves (_qtAstR,_bsAstR) = if (if ((0 > _qtAstR))
964+ then true
965+ else (0 > _bsAstR))
966+ then throw("Invalid amount to update reserves")
967+ else if (if ((_qtAstR != qtAstR0()))
968+ then true
969+ else (_bsAstR != bsAstR0()))
970+ then [IntegerEntry(k_quoteAssetReserve, _qtAstR), IntegerEntry(k_baseAssetReserve, _bsAstR)]
971+ else nil
972+
973+
974+func updateAmmWeights (_qtAstW,_bsAstW) = if (if ((_qtAstW != qtAstW()))
975+ then true
976+ else (_bsAstW != bsAstW()))
977+ then [IntegerEntry(k_quoteAssetWeight, _qtAstW), IntegerEntry(k_baseAssetWeight, _bsAstW)]
978+ else nil
979+
980+
981+func updateAmm (_qtAstR,_bsAstR,_totalPositionSizeAfter,_openInterestNotional,_totalLongPositionSize,_totalShortPositionSize,_totalLongOpenNotional,_totalShortOpenNotional) = {
982+ let _qtAstW = qtAstW()
983+ let _bsAstW = bsAstW()
984+ if (((_totalLongPositionSize - _totalShortPositionSize) != _totalPositionSizeAfter))
985+ then throw(((((("Invalid AMM state data: " + toString(_totalLongPositionSize)) + " - ") + toString(_totalShortPositionSize)) + " != ") + toString(_totalPositionSizeAfter)))
986+ 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)])
987+ }
988+
989+
990+func deletePosition (_trader,_direction) = {
991+ let positionKey = ((_trader + "_") + toString(_direction))
992+[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))]
993+ }
994+
995+
996+func withdraw (_address,_amount) = {
997+ let balance = assetBalance(this, quoteAsset())
998+ if ((_amount > balance))
999+ then throw(((("Unable to withdraw " + toString(_amount)) + " from contract balance ") + toString(balance)))
1000+ else [ScriptTransfer(_address, _amount, quoteAsset())]
1001+ }
1002+
1003+
1004+func updateBalance (_balance) = if ((0 > _balance))
1005+ then throw("Balance")
1006+ else if (if ((cbalance0() == 0))
1007+ then true
1008+ else (cbalance0() != _balance))
1009+ then [IntegerEntry(k_balance, _balance)]
1010+ else nil
1011+
1012+
1013+func transferFee (i) = [ScriptTransfer(stakingAddress(), i, quoteAsset())]
1014+
1015+
1016+func doBurnArtifact (_burnArtifact,i) = if (_burnArtifact)
1017+ then [Burn(valueOrErrorMessage(i.payments[1].assetId, "Invalid artifact"), 1)]
1018+ else nil
1019+
1020+
1021+@Callable(i)
1022+func pause () = if ((i.caller != adminAddress()))
1023+ then throw("Invalid pause params")
1024+ else [BooleanEntry(k_paused, true)]
1025+
1026+
1027+
1028+@Callable(i)
1029+func unpause () = if ((i.caller != adminAddress()))
1030+ then throw("Invalid unpause params")
1031+ else [BooleanEntry(k_paused, false)]
1032+
1033+
1034+
1035+@Callable(i)
1036+func setCloseOnly () = if ((i.caller != adminAddress()))
1037+ then throw("Invalid setCloseOnly params")
1038+ else [BooleanEntry(k_closeOnly, true)]
1039+
1040+
1041+
1042+@Callable(i)
1043+func unsetCloseOnly () = if ((i.caller != adminAddress()))
1044+ then throw("Invalid unsetCloseOnly params")
1045+ else [BooleanEntry(k_closeOnly, false)]
1046+
1047+
1048+
1049+@Callable(i)
1050+func changeLiquidity (_quoteAssetAmount) = if (if ((i.caller != adminAddress()))
1051+ then true
1052+ else (_quoteAssetAmount == 0))
1053+ then throw("Invalid changeLiquidity params")
1054+ else {
1055+ let _qtAstR = qtAstR()
1056+ let _bsAstR = bsAstR()
1057+ let _qtAstW = qtAstW()
1058+ let _bsAstW = bsAstW()
1059+ let price = divd(muld(_qtAstR, _qtAstW), muld(_bsAstR, _bsAstW))
1060+ let qtAstRAfter = (_qtAstR + _quoteAssetAmount)
1061+ let baseAssetAmountToAdd = (divd(muld(qtAstRAfter, _qtAstW), price) - _bsAstR)
1062+ let bsAstRAfter = (_bsAstR + baseAssetAmountToAdd)
1063+ let $t05304953200 = getSyncTerminalPrice(getOraclePrice(), qtAstRAfter, bsAstRAfter)
1064+ let newQuoteAssetWeight = $t05304953200._1
1065+ let newBaseAssetWeight = $t05304953200._2
1066+ let marginToVault = $t05304953200._3
1067+ let doExchangePnL = if ((marginToVault != 0))
1068+ then {
1069+ let doExchangePnL = invoke(vaultAddress(), "exchangeFreeAndLocked", [marginToVault], nil)
1070+ if ((doExchangePnL == doExchangePnL))
1071+ then nil
1072+ else throw("Strict value is not equal to itself.")
1073+ }
1074+ else nil
1075+ if ((doExchangePnL == doExchangePnL))
1076+ then (updateAmmReserves(qtAstRAfter, bsAstRAfter) ++ updateAmmWeights(newQuoteAssetWeight, newBaseAssetWeight))
1077+ else throw("Strict value is not equal to itself.")
1078+ }
1079+
1080+
1081+
1082+@Callable(i)
1083+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))
1084+ then true
1085+ else (0 >= _initMarginRatio))
1086+ then true
1087+ else (_initMarginRatio > DECIMAL_UNIT))
1088+ then true
1089+ else (0 >= _minInitMarginRatio))
1090+ then true
1091+ else (_minInitMarginRatio > DECIMAL_UNIT))
1092+ then true
1093+ else (_initMarginRatio > _minInitMarginRatio))
1094+ then true
1095+ else (0 >= _mmr))
1096+ then true
1097+ else (0 >= _liquidationFeeRatio))
1098+ then true
1099+ else (0 >= _fee))
1100+ then true
1101+ else (0 >= _spreadLimit))
1102+ then true
1103+ else (0 >= _maxPriceImpact))
1104+ then true
1105+ else (0 >= _partialLiquidationRatio))
1106+ then true
1107+ else (0 >= _maxPriceSpread))
1108+ then true
1109+ else (0 >= _maxOpenNotional))
1110+ then true
1111+ else (0 >= _feeToStakersPercent))
1112+ then true
1113+ else (_feeToStakersPercent > DECIMAL_UNIT))
1114+ then true
1115+ else (0 > _maxOracleDelay))
1116+ then true
1117+ else (0 >= _rolloverFee))
1118+ then true
1119+ else if ((_fundingMode != FUNDING_SYMMETRIC))
1120+ then (_fundingMode != FUNDING_ASYMMETRIC)
1121+ else false)
1122+ then true
1123+ else if ((_oracleMode != ORACLE_PLAIN))
1124+ then (_oracleMode != ORACLE_JIT)
1125+ else false)
1126+ then true
1127+ else if ((_positionMode != POSITION_DIRECT))
1128+ then (_positionMode != POSITION_ORDER)
1129+ else false)
1130+ then true
1131+ else !(initialized()))
1132+ then true
1133+ else (i.caller != adminAddress()))
1134+ then throw("Invalid changeSettings params")
1135+ 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)])
1136+
1137+
1138+
1139+@Callable(i)
1140+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 ((0 >= _qtAstR))
1141+ then true
1142+ else (0 >= _bsAstR))
1143+ then true
1144+ else (0 >= _fundingPeriod))
1145+ then true
1146+ else (0 >= _initMarginRatio))
1147+ then true
1148+ else (_initMarginRatio > DECIMAL_UNIT))
1149+ then true
1150+ else (0 >= _minInitMarginRatio))
1151+ then true
1152+ else (_initMarginRatio > _minInitMarginRatio))
1153+ then true
1154+ else (0 >= _mmr))
1155+ then true
1156+ else (0 >= _liquidationFeeRatio))
1157+ then true
1158+ else (0 >= _fee))
1159+ then true
1160+ else (0 >= _spreadLimit))
1161+ then true
1162+ else (0 >= _maxPriceImpact))
1163+ then true
1164+ else (0 >= _partialLiquidationRatio))
1165+ then true
1166+ else (0 >= _maxPriceSpread))
1167+ then true
1168+ else (0 >= _maxOpenNotional))
1169+ then true
1170+ else (0 >= _feeToStakersPercent))
1171+ then true
1172+ else (_feeToStakersPercent > DECIMAL_UNIT))
1173+ then true
1174+ else (0 > _maxOracleDelay))
1175+ then true
1176+ else (0 >= _rolloverFee))
1177+ then true
1178+ else if ((_fundingMode != FUNDING_SYMMETRIC))
1179+ then (_fundingMode != FUNDING_ASYMMETRIC)
1180+ else false)
1181+ then true
1182+ else if ((_oracleMode != ORACLE_PLAIN))
1183+ then (_oracleMode != ORACLE_JIT)
1184+ else false)
1185+ then true
1186+ else if ((_positionMode != POSITION_DIRECT))
1187+ then (_positionMode != POSITION_ORDER)
1188+ else false)
1189+ then true
1190+ else initialized())
1191+ then true
1192+ else (i.caller != this))
1193+ then throw("Invalid initialize parameters")
1194+ 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)))])
1195+
1196+
1197+
1198+@Callable(i)
1199+func increasePosition (_direction,_leverage,_minBaseAssetAmount,_refLink,_priceUpdate) = {
1200+ let updateOracle = invoke(this, "updateOracle", [_priceUpdate], nil)
1201+ if ((updateOracle == updateOracle))
1202+ then {
1203+ let sync = invoke(this, "syncTerminalPriceToOracle", nil, nil)
1204+ if ((sync == sync))
1205+ then {
1206+ let ensureCalledOnce = invoke(this, "ensureCalledOnce", nil, nil)
1207+ if ((ensureCalledOnce == ensureCalledOnce))
1208+ then {
1209+ let _trader = getActualCaller(i)
1210+ let _rawAmount = i.payments[0].amount
1211+ let _assetId = i.payments[0].assetId
1212+ let _assetIdStr = toBase58String(value(_assetId))
1213+ let isQuoteAsset = (_assetId == quoteAsset())
1214+ if (if (if (if (if (if (if (if (if (if (if ((_direction != DIR_LONG))
1215+ then (_direction != DIR_SHORT)
1216+ else false)
1217+ then true
1218+ else (0 >= _rawAmount))
1219+ then true
1220+ else !(initialized()))
1221+ then true
1222+ else !(isQuoteAsset))
1223+ then true
1224+ else !(requireMoreMarginRatio(divd(DECIMAL_UNIT, _leverage), initMarginRatio(), true)))
1225+ then true
1226+ else !(requireMoreMarginRatio(divd(DECIMAL_UNIT, _leverage), minInitMarginRatio(), false)))
1227+ then true
1228+ else !(requireSenderCanWorkWithPositions(i.caller)))
1229+ then true
1230+ else paused())
1231+ then true
1232+ else closeOnly())
1233+ then true
1234+ else isMarketClosed())
1235+ then throw("Invalid increasePosition parameters")
1236+ else {
1237+ let $t06050160650 = getForTraderWithArtifact(_trader, getArtifactId(i))
1238+ let adjustedFee = $t06050160650._1
1239+ let burnArtifact = $t06050160650._2
1240+ let _amount = divd(_rawAmount, (muld(adjustedFee, _leverage) + DECIMAL_UNIT))
1241+ let distributeFeeAmount = (_rawAmount - _amount)
1242+ let referrerFeeAny = invoke(referralAddress(), "acceptPaymentWithLink", [_trader, _refLink], [AttachedPayment(quoteAsset(), distributeFeeAmount)])
1243+ if ((referrerFeeAny == referrerFeeAny))
1244+ then {
1245+ let referrerFee = match referrerFeeAny {
1246+ case x: Int =>
1247+ x
1248+ case _ =>
1249+ throw("Invalid referrerFee")
1250+ }
1251+ let feeAmount = (distributeFeeAmount - referrerFee)
1252+ let $t06114661326 = getPosition(_trader, _direction)
1253+ let oldPositionSize = $t06114661326._1
1254+ let oldPositionMargin = $t06114661326._2
1255+ let oldPositionOpenNotional = $t06114661326._3
1256+ let oldPositionLstUpdCPF = $t06114661326._4
1257+ let oldPositionTimestamp = $t06114661326._5
1258+ let isNewPosition = (oldPositionSize == 0)
1259+ let isSameDirection = if ((oldPositionSize > 0))
1260+ then (_direction == DIR_LONG)
1261+ else (_direction == DIR_SHORT)
1262+ let expandExisting = if (!(isNewPosition))
1263+ then isSameDirection
1264+ else false
1265+ let isAdd = (_direction == DIR_LONG)
1266+ let $t06161564748 = if (if (isNewPosition)
1267+ then true
1268+ else expandExisting)
1269+ then {
1270+ let openNotional = muld(_amount, _leverage)
1271+ let $t06212462297 = swapInput(isAdd, openNotional)
1272+ let amountBaseAssetBought = $t06212462297._1
1273+ let quoteAssetReserveAfter = $t06212462297._2
1274+ let baseAssetReserveAfter = $t06212462297._3
1275+ let totalPositionSizeAfter = $t06212462297._4
1276+ if (if ((_minBaseAssetAmount != 0))
1277+ then (_minBaseAssetAmount > abs(amountBaseAssetBought))
1278+ else false)
1279+ then throw(((("Limit error: " + toString(abs(amountBaseAssetBought))) + " < ") + toString(_minBaseAssetAmount)))
1280+ else {
1281+ let newPositionSize = (oldPositionSize + amountBaseAssetBought)
1282+ let totalLongOpenInterestAfter = (openInterestLong() + (if ((newPositionSize > 0))
1283+ then openNotional
1284+ else 0))
1285+ let totalShortOpenInterestAfter = (openInterestShort() + (if ((0 > newPositionSize))
1286+ then openNotional
1287+ else 0))
1288+ let $t06284363118 = calcRemainMarginWithFundingPaymentAndRolloverFee(oldPositionSize, oldPositionMargin, oldPositionLstUpdCPF, oldPositionTimestamp, _amount)
1289+ let remainMargin = $t06284363118._1
1290+ let x1 = $t06284363118._2
1291+ let x2 = $t06284363118._3
1292+ let rolloverFee = $t06284363118._4
1293+ if (!(requireNotOverSpreadLimit(quoteAssetReserveAfter, baseAssetReserveAfter)))
1294+ then throw("Over max spread limit")
1295+ else if (!(requireNotOverMaxOpenNotional(totalLongOpenInterestAfter, totalShortOpenInterestAfter)))
1296+ then throw("Over max open notional")
1297+ else $Tuple14(newPositionSize, remainMargin, (oldPositionOpenNotional + openNotional), latestCumulativePremiumFraction(newPositionSize), lastTimestamp(), baseAssetReserveAfter, quoteAssetReserveAfter, totalPositionSizeAfter, (openInterestNotional() + openNotional), (totalLongPositionSize() + (if ((newPositionSize > 0))
1298+ then abs(amountBaseAssetBought)
1299+ else 0)), (totalShortPositionSize() + (if ((0 > newPositionSize))
1300+ then abs(amountBaseAssetBought)
1301+ else 0)), totalLongOpenInterestAfter, totalShortOpenInterestAfter, rolloverFee)
1302+ }
1303+ }
1304+ else {
1305+ let openNotional = muld(_amount, _leverage)
1306+ let $t06443664564 = getPositionNotionalAndUnrealizedPnl(toString(i.caller), _direction, PNL_OPTION_SPOT)
1307+ let oldPositionNotional = $t06443664564._1
1308+ let unrealizedPnl = $t06443664564._2
1309+ if ((oldPositionNotional > openNotional))
1310+ then throw("Use decreasePosition to decrease position size")
1311+ else throw("Close position first")
1312+ }
1313+ let newPositionSize = $t06161564748._1
1314+ let newPositionRemainMargin = $t06161564748._2
1315+ let newPositionOpenNotional = $t06161564748._3
1316+ let newPositionLatestCPF = $t06161564748._4
1317+ let newPositionTimestamp = $t06161564748._5
1318+ let baseAssetReserveAfter = $t06161564748._6
1319+ let quoteAssetReserveAfter = $t06161564748._7
1320+ let totalPositionSizeAfter = $t06161564748._8
1321+ let openInterestNotionalAfter = $t06161564748._9
1322+ let totalLongAfter = $t06161564748._10
1323+ let totalShortAfter = $t06161564748._11
1324+ let totalLongOpenInterestAfter = $t06161564748._12
1325+ let totalShortOpenInterestAfter = $t06161564748._13
1326+ let rolloverFee = $t06161564748._14
1327+ let $t06475464825 = distributeFee((feeAmount + rolloverFee))
1328+ let feeToStakers = $t06475464825._1
1329+ let feeToVault = $t06475464825._2
1330+ let stake = if ((_amount >= rolloverFee))
1331+ then invoke(vaultAddress(), "addLocked", nil, [AttachedPayment(quoteAsset(), (_amount - rolloverFee))])
1332+ else invoke(vaultAddress(), "withdrawLocked", [(rolloverFee - _amount)], nil)
1333+ if ((stake == stake))
1334+ then {
1335+ let depositVault = invoke(vaultAddress(), "addFree", nil, [AttachedPayment(quoteAsset(), feeToVault)])
1336+ if ((depositVault == depositVault))
1337+ then {
1338+ let notifyFee = invoke(minerAddress(), "notifyFees", [_trader, feeAmount], nil)
1339+ if ((notifyFee == notifyFee))
1340+ then {
1341+ let notifyNotional = invoke(minerAddress(), "notifyNotional", [_trader, newPositionOpenNotional], nil)
1342+ if ((notifyNotional == notifyNotional))
1343+ 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))
1344+ else throw("Strict value is not equal to itself.")
1345+ }
1346+ else throw("Strict value is not equal to itself.")
1347+ }
1348+ else throw("Strict value is not equal to itself.")
1349+ }
1350+ else throw("Strict value is not equal to itself.")
1351+ }
1352+ else throw("Strict value is not equal to itself.")
1353+ }
1354+ }
1355+ else throw("Strict value is not equal to itself.")
1356+ }
1357+ else throw("Strict value is not equal to itself.")
1358+ }
1359+ else throw("Strict value is not equal to itself.")
1360+ }
1361+
1362+
1363+
1364+@Callable(i)
1365+func addMargin (_direction,_priceUpdate) = {
1366+ let updateOracle = invoke(this, "updateOracle", [_priceUpdate], nil)
1367+ if ((updateOracle == updateOracle))
1368+ then {
1369+ let sync = invoke(this, "syncTerminalPriceToOracle", nil, nil)
1370+ if ((sync == sync))
1371+ then {
1372+ let ensureCalledOnce = invoke(this, "ensureCalledOnce", nil, nil)
1373+ if ((ensureCalledOnce == ensureCalledOnce))
1374+ then {
1375+ let _trader = toString(i.caller)
1376+ let _amount = i.payments[0].amount
1377+ let _assetId = i.payments[0].assetId
1378+ let _assetIdStr = toBase58String(value(_assetId))
1379+ let isQuoteAsset = (_assetId == quoteAsset())
1380+ if (if (if (if (if (!(isQuoteAsset))
1381+ then true
1382+ else !(requireOpenPosition(toString(i.caller), _direction)))
1383+ then true
1384+ else !(initialized()))
1385+ then true
1386+ else paused())
1387+ then true
1388+ else isMarketClosed())
1389+ then throw("Invalid addMargin parameters")
1390+ else {
1391+ let $t06716767347 = getPosition(_trader, _direction)
1392+ let oldPositionSize = $t06716767347._1
1393+ let oldPositionMargin = $t06716767347._2
1394+ let oldPositionOpenNotional = $t06716767347._3
1395+ let oldPositionLstUpdCPF = $t06716767347._4
1396+ let oldPositionTimestamp = $t06716767347._5
1397+ let stake = invoke(vaultAddress(), "addLocked", nil, [AttachedPayment(quoteAsset(), _amount)])
1398+ if ((stake == stake))
1399+ then {
1400+ let $t06748767713 = calcRemainMarginWithFundingPaymentAndRolloverFee(oldPositionSize, oldPositionMargin, oldPositionLstUpdCPF, oldPositionTimestamp, _amount)
1401+ let remainMargin = $t06748767713._1
1402+ let badDebt = $t06748767713._2
1403+ let rolloverFee = $t06748767713._3
1404+ let marginRatio = calcMarginRatio(remainMargin, badDebt, oldPositionOpenNotional)
1405+ let checkMinMargin = requireMoreMarginRatio(marginRatio, minInitMarginRatio(), false)
1406+ if ((checkMinMargin == checkMinMargin))
1407+ then {
1408+ let doTransferFeeToStakers = if ((rolloverFee > 0))
1409+ then {
1410+ let $t06796968028 = distributeFee(rolloverFee)
1411+ let feeToStakers = $t06796968028._1
1412+ let feeToVault = $t06796968028._2
1413+ let unstake = invoke(vaultAddress(), "withdrawLocked", [feeToStakers], nil)
1414+ if ((unstake == unstake))
1415+ then {
1416+ let lockBadDebt = invoke(vaultAddress(), "exchangeFreeAndLocked", [-(feeToVault)], nil)
1417+ if ((lockBadDebt == lockBadDebt))
1418+ then transferFee(feeToStakers)
1419+ else throw("Strict value is not equal to itself.")
1420+ }
1421+ else throw("Strict value is not equal to itself.")
1422+ }
1423+ else nil
1424+ if ((doTransferFeeToStakers == doTransferFeeToStakers))
1425+ then ((updatePosition(_trader, oldPositionSize, ((oldPositionMargin - rolloverFee) + _amount), oldPositionOpenNotional, oldPositionLstUpdCPF, lastTimestamp()) ++ updateBalance(((cbalance() + _amount) - rolloverFee))) ++ doTransferFeeToStakers)
1426+ else throw("Strict value is not equal to itself.")
1427+ }
1428+ else throw("Strict value is not equal to itself.")
1429+ }
1430+ else throw("Strict value is not equal to itself.")
1431+ }
1432+ }
1433+ else throw("Strict value is not equal to itself.")
1434+ }
1435+ else throw("Strict value is not equal to itself.")
1436+ }
1437+ else throw("Strict value is not equal to itself.")
1438+ }
1439+
1440+
1441+
1442+@Callable(i)
1443+func removeMargin (_amount,_direction,_priceUpdate) = {
1444+ let updateOracle = invoke(this, "updateOracle", [_priceUpdate], nil)
1445+ if ((updateOracle == updateOracle))
1446+ then {
1447+ let sync = invoke(this, "syncTerminalPriceToOracle", nil, nil)
1448+ if ((sync == sync))
1449+ then {
1450+ let ensureCalledOnce = invoke(this, "ensureCalledOnce", nil, nil)
1451+ if ((ensureCalledOnce == ensureCalledOnce))
1452+ then {
1453+ let _trader = toString(i.caller)
1454+ if (if (if (if (if ((0 >= _amount))
1455+ then true
1456+ else !(requireOpenPosition(_trader, _direction)))
1457+ then true
1458+ else !(initialized()))
1459+ then true
1460+ else paused())
1461+ then true
1462+ else isMarketClosed())
1463+ then throw("Invalid removeMargin parameters")
1464+ else {
1465+ let $t06952969709 = getPosition(_trader, _direction)
1466+ let oldPositionSize = $t06952969709._1
1467+ let oldPositionMargin = $t06952969709._2
1468+ let oldPositionOpenNotional = $t06952969709._3
1469+ let oldPositionLstUpdCPF = $t06952969709._4
1470+ let oldPositionTimestamp = $t06952969709._5
1471+ let $t06971569964 = calcRemainMarginWithFundingPaymentAndRolloverFee(oldPositionSize, oldPositionMargin, oldPositionLstUpdCPF, oldPositionTimestamp, -(_amount))
1472+ let remainMargin = $t06971569964._1
1473+ let badDebt = $t06971569964._2
1474+ let fundingPayment = $t06971569964._3
1475+ let rolloverFee = $t06971569964._4
1476+ if ((badDebt != 0))
1477+ then throw("Invalid removed margin amount")
1478+ else {
1479+ let marginRatio = calcMarginRatio(remainMargin, badDebt, oldPositionOpenNotional)
1480+ if (!(requireMoreMarginRatio(marginRatio, initMarginRatio(), true)))
1481+ then throw(((("Too much margin removed: " + toString(marginRatio)) + " < ") + toString(initMarginRatio())))
1482+ else {
1483+ let $t07035070409 = distributeFee(rolloverFee)
1484+ let feeToStakers = $t07035070409._1
1485+ let feeToVault = $t07035070409._2
1486+ let doTransferFeeToStakers = if ((rolloverFee > 0))
1487+ then {
1488+ let lockBadDebt = invoke(vaultAddress(), "exchangeFreeAndLocked", [-(feeToVault)], nil)
1489+ if ((lockBadDebt == lockBadDebt))
1490+ then transferFee(feeToStakers)
1491+ else throw("Strict value is not equal to itself.")
1492+ }
1493+ else nil
1494+ if ((doTransferFeeToStakers == doTransferFeeToStakers))
1495+ then {
1496+ let unstake = invoke(vaultAddress(), "withdrawLocked", [(_amount + feeToStakers)], nil)
1497+ if ((unstake == unstake))
1498+ then (((updatePosition(_trader, oldPositionSize, remainMargin, oldPositionOpenNotional, latestCumulativePremiumFraction(oldPositionSize), lastTimestamp()) ++ withdraw(i.caller, _amount)) ++ updateBalance(((cbalance() - _amount) - rolloverFee))) ++ doTransferFeeToStakers)
1499+ else throw("Strict value is not equal to itself.")
1500+ }
1501+ else throw("Strict value is not equal to itself.")
1502+ }
1503+ }
1504+ }
1505+ }
1506+ else throw("Strict value is not equal to itself.")
1507+ }
1508+ else throw("Strict value is not equal to itself.")
1509+ }
1510+ else throw("Strict value is not equal to itself.")
1511+ }
1512+
1513+
1514+
1515+@Callable(i)
1516+func closePosition (_size,_direction,_minQuoteAssetAmount,_addToMargin,_priceUpdate) = {
1517+ let updateOracle = invoke(this, "updateOracle", [_priceUpdate], nil)
1518+ if ((updateOracle == updateOracle))
1519+ then {
1520+ let sync = invoke(this, "syncTerminalPriceToOracle", nil, nil)
1521+ if ((sync == sync))
1522+ then {
1523+ let ensureCalledOnce = invoke(this, "ensureCalledOnce", nil, nil)
1524+ if ((ensureCalledOnce == ensureCalledOnce))
1525+ then {
1526+ let _trader = getActualCaller(i)
1527+ let _traderAddress = valueOrErrorMessage(addressFromString(_trader), "Invalid caller")
1528+ let positionFee = getPositionFee(_trader, _direction)
1529+ if (if (if (if (if (if (!(requireOpenPosition(_trader, _direction)))
1530+ then true
1531+ else !(initialized()))
1532+ then true
1533+ else paused())
1534+ then true
1535+ else (0 >= _size))
1536+ then true
1537+ else (0 > _minQuoteAssetAmount))
1538+ then true
1539+ else isMarketClosed())
1540+ then throw("Invalid closePosition parameters")
1541+ else {
1542+ let oldPositionTimestamp = getPosition(_trader, _direction)._5
1543+ let $t07274473347 = internalClosePosition(_trader, _direction, _size, positionFee, _minQuoteAssetAmount, _addToMargin, true, true)
1544+ let newPositionSize = $t07274473347._1
1545+ let newPositionMargin = $t07274473347._2
1546+ let newPositionOpenNotional = $t07274473347._3
1547+ let newPositionLstUpdCPF = $t07274473347._4
1548+ let positionBadDebt = $t07274473347._5
1549+ let realizedPnl = $t07274473347._6
1550+ let marginToTrader = $t07274473347._7
1551+ let quoteAssetReserveAfter = $t07274473347._8
1552+ let baseAssetReserveAfter = $t07274473347._9
1553+ let totalPositionSizeAfter = $t07274473347._10
1554+ let openInterestNotionalAfter = $t07274473347._11
1555+ let totalLongAfter = $t07274473347._12
1556+ let totalShortAfter = $t07274473347._13
1557+ let totalLongOpenInterestAfter = $t07274473347._14
1558+ let totalShortOpenInterestAfter = $t07274473347._15
1559+ let realizedFee = $t07274473347._16
1560+ if ((positionBadDebt > 0))
1561+ then throw("Invalid closePosition parameters: bad debt")
1562+ else if ((oldPositionTimestamp >= lastTimestamp()))
1563+ then throw("Invalid closePosition parameters: wait at least 1 block before closing the position")
1564+ else {
1565+ let isPartialClose = (newPositionSize != 0)
1566+ let withdrawAmount = (marginToTrader + realizedFee)
1567+ let ammBalance = (cbalance() - withdrawAmount)
1568+ let ammNewBalance = if ((0 > ammBalance))
1569+ then 0
1570+ else ammBalance
1571+ let unstake = invoke(vaultAddress(), "withdrawLocked", [withdrawAmount], nil)
1572+ if ((unstake == unstake))
1573+ then {
1574+ let referrerFeeAny = invoke(referralAddress(), "acceptPayment", [_trader], [AttachedPayment(quoteAsset(), realizedFee)])
1575+ if ((referrerFeeAny == referrerFeeAny))
1576+ then {
1577+ let referrerFee = match referrerFeeAny {
1578+ case x: Int =>
1579+ x
1580+ case _ =>
1581+ throw("Invalid referrerFee")
1582+ }
1583+ let $t07431974392 = distributeFee((realizedFee - referrerFee))
1584+ let feeToStakers = $t07431974392._1
1585+ let feeToVault = $t07431974392._2
1586+ let depositVault = invoke(vaultAddress(), "addFree", nil, [AttachedPayment(quoteAsset(), feeToVault)])
1587+ if ((depositVault == depositVault))
1588+ then {
1589+ let notifyFee = invoke(minerAddress(), "notifyFees", [_trader, realizedFee], nil)
1590+ if ((notifyFee == notifyFee))
1591+ then {
1592+ let notifyNotional = invoke(minerAddress(), "notifyNotional", [_trader, newPositionOpenNotional], nil)
1593+ if ((notifyNotional == notifyNotional))
1594+ then (((((if (isPartialClose)
1595+ then updatePosition(_trader, newPositionSize, newPositionMargin, newPositionOpenNotional, newPositionLstUpdCPF, lastTimestamp())
1596+ else deletePosition(_trader, _direction)) ++ updateAmm(quoteAssetReserveAfter, baseAssetReserveAfter, totalPositionSizeAfter, openInterestNotionalAfter, totalLongAfter, totalShortAfter, totalLongOpenInterestAfter, totalShortOpenInterestAfter)) ++ (if ((marginToTrader > 0))
1597+ then withdraw(_traderAddress, marginToTrader)
1598+ else nil)) ++ updateBalance(ammNewBalance)) ++ transferFee(feeToStakers))
1599+ else throw("Strict value is not equal to itself.")
1600+ }
1601+ else throw("Strict value is not equal to itself.")
1602+ }
1603+ else throw("Strict value is not equal to itself.")
1604+ }
1605+ else throw("Strict value is not equal to itself.")
1606+ }
1607+ else throw("Strict value is not equal to itself.")
1608+ }
1609+ }
1610+ }
1611+ else throw("Strict value is not equal to itself.")
1612+ }
1613+ else throw("Strict value is not equal to itself.")
1614+ }
1615+ else throw("Strict value is not equal to itself.")
1616+ }
1617+
1618+
1619+
1620+@Callable(i)
1621+func liquidate (_trader,_direction,_priceUpdate) = {
1622+ let updateOracle = invoke(this, "updateOracle", [_priceUpdate], nil)
1623+ if ((updateOracle == updateOracle))
1624+ then {
1625+ let sync = invoke(this, "syncTerminalPriceToOracle", nil, nil)
1626+ if ((sync == sync))
1627+ then {
1628+ let spotMarginRatio = getMarginRatioByOption(_trader, _direction, PNL_OPTION_SPOT)
1629+ let liquidationMarginRatio = if (isOverFluctuationLimit())
1630+ then {
1631+ let oracleMarginRatio = getMarginRatioByOption(_trader, _direction, PNL_OPTION_ORACLE)
1632+ vmax(spotMarginRatio, oracleMarginRatio)
1633+ }
1634+ else spotMarginRatio
1635+ if (if (if (if (if (!(requireMoreMarginRatio(liquidationMarginRatio, maintenanceMarginRatio(), false)))
1636+ then true
1637+ else !(requireOpenPosition(_trader, _direction)))
1638+ then true
1639+ else !(initialized()))
1640+ then true
1641+ else paused())
1642+ then true
1643+ else isMarketClosed())
1644+ then throw("Unable to liquidate")
1645+ else {
1646+ let oldPositionSize = getPosition(_trader, _direction)._1
1647+ let positionSizeAbs = abs(oldPositionSize)
1648+ let isPartialLiquidation = if (if (if ((spotMarginRatio > liquidationFeeRatio()))
1649+ then (partialLiquidationRatio() > 0)
1650+ else false)
1651+ then (DECIMAL_UNIT > partialLiquidationRatio())
1652+ else false)
1653+ then (muld(positionSizeAbs, getSpotPrice()) > minPartialLiquidationNotional())
1654+ else false
1655+ let $t07706677453 = if (isPartialLiquidation)
1656+ then {
1657+ let liquidationSize = abs(getPartialLiquidationAmount(_trader, oldPositionSize))
1658+ let liquidationRatio = divd(liquidationSize, positionSizeAbs)
1659+ let liquidationNotional = muld(liquidationSize, getSpotPrice())
1660+ $Tuple2(liquidationRatio, liquidationSize)
1661+ }
1662+ else $Tuple2(0, positionSizeAbs)
1663+ let liquidationRatio = $t07706677453._1
1664+ let liquidationSize = $t07706677453._2
1665+ let $t07745978115 = internalClosePosition(_trader, _direction, if (isPartialLiquidation)
1666+ then liquidationSize
1667+ else positionSizeAbs, liquidationFeeRatio(), 0, true, false, true)
1668+ let newPositionSize = $t07745978115._1
1669+ let newPositionMargin = $t07745978115._2
1670+ let newPositionOpenNotional = $t07745978115._3
1671+ let newPositionLstUpdCPF = $t07745978115._4
1672+ let positionBadDebt = $t07745978115._5
1673+ let realizedPnl = $t07745978115._6
1674+ let marginToTrader = $t07745978115._7
1675+ let quoteAssetReserveAfter = $t07745978115._8
1676+ let baseAssetReserveAfter = $t07745978115._9
1677+ let totalPositionSizeAfter = $t07745978115._10
1678+ let openInterestNotionalAfter = $t07745978115._11
1679+ let totalLongAfter = $t07745978115._12
1680+ let totalShortAfter = $t07745978115._13
1681+ let totalLongOpenInterestAfter = $t07745978115._14
1682+ let totalShortOpenInterestAfter = $t07745978115._15
1683+ let liquidationPenalty = $t07745978115._16
1684+ let feeToLiquidator = (liquidationPenalty / 2)
1685+ let feeToVault = (liquidationPenalty - feeToLiquidator)
1686+ let ammBalance = (cbalance() - liquidationPenalty)
1687+ let newAmmBalance = if ((0 > ammBalance))
1688+ then 0
1689+ else ammBalance
1690+ let lockBadDebt = if ((positionBadDebt > 0))
1691+ then {
1692+ let lockBadDebt = invoke(vaultAddress(), "exchangeFreeAndLocked", [(positionBadDebt + liquidationPenalty)], nil)
1693+ if ((lockBadDebt == lockBadDebt))
1694+ then nil
1695+ else throw("Strict value is not equal to itself.")
1696+ }
1697+ else nil
1698+ if ((lockBadDebt == lockBadDebt))
1699+ then {
1700+ let unstake = invoke(vaultAddress(), "withdrawLocked", [liquidationPenalty], nil)
1701+ if ((unstake == unstake))
1702+ then {
1703+ let depositInsurance = invoke(vaultAddress(), "addFree", nil, [AttachedPayment(quoteAsset(), feeToVault)])
1704+ if ((depositInsurance == depositInsurance))
1705+ then {
1706+ let notifyNotional = invoke(minerAddress(), "notifyNotional", [_trader, newPositionOpenNotional], nil)
1707+ if ((notifyNotional == notifyNotional))
1708+ then ((((if (isPartialLiquidation)
1709+ then updatePosition(_trader, newPositionSize, newPositionMargin, newPositionOpenNotional, newPositionLstUpdCPF, lastTimestamp())
1710+ else deletePosition(_trader, _direction)) ++ updateAmm(quoteAssetReserveAfter, baseAssetReserveAfter, totalPositionSizeAfter, openInterestNotionalAfter, totalLongAfter, totalShortAfter, totalLongOpenInterestAfter, totalShortOpenInterestAfter)) ++ withdraw(i.caller, feeToLiquidator)) ++ updateBalance(newAmmBalance))
1711+ else throw("Strict value is not equal to itself.")
1712+ }
1713+ else throw("Strict value is not equal to itself.")
1714+ }
1715+ else throw("Strict value is not equal to itself.")
1716+ }
1717+ else throw("Strict value is not equal to itself.")
1718+ }
1719+ }
1720+ else throw("Strict value is not equal to itself.")
1721+ }
1722+ else throw("Strict value is not equal to itself.")
1723+ }
1724+
1725+
1726+
1727+@Callable(i)
1728+func payFunding (_priceUpdate) = {
1729+ let updateOracle = invoke(this, "updateOracle", [_priceUpdate], nil)
1730+ if ((updateOracle == updateOracle))
1731+ then {
1732+ let sync = invoke(this, "syncTerminalPriceToOracle", nil, nil)
1733+ if ((sync == sync))
1734+ then {
1735+ let fundingBlockTimestamp = nextFundingBlockTimestamp()
1736+ if (if (if ((fundingBlockTimestamp > lastTimestamp()))
1737+ then true
1738+ else !(initialized()))
1739+ then true
1740+ else paused())
1741+ then throw(((("Invalid funding block timestamp: " + toString(lastTimestamp())) + " < ") + toString(fundingBlockTimestamp)))
1742+ else {
1743+ let underlyingPrice = getOraclePrice()
1744+ let $t08033380411 = getFunding()
1745+ let shortPremiumFraction = $t08033380411._1
1746+ let longPremiumFraction = $t08033380411._2
1747+ let premiumToVault = $t08033380411._3
1748+ let doPayFundingToVault = if ((premiumToVault > 0))
1749+ then {
1750+ let doPayFundingToVault = invoke(vaultAddress(), "exchangeFreeAndLocked", [-(premiumToVault)], nil)
1751+ if ((doPayFundingToVault == doPayFundingToVault))
1752+ then nil
1753+ else throw("Strict value is not equal to itself.")
1754+ }
1755+ else nil
1756+ if ((doPayFundingToVault == doPayFundingToVault))
1757+ then updateFunding((fundingBlockTimestamp + fundingPeriodSeconds()), (latestLongCumulativePremiumFraction() + longPremiumFraction), (latestShortCumulativePremiumFraction() + shortPremiumFraction), divd(longPremiumFraction, underlyingPrice), divd(shortPremiumFraction, underlyingPrice))
1758+ else throw("Strict value is not equal to itself.")
1759+ }
1760+ }
1761+ else throw("Strict value is not equal to itself.")
1762+ }
1763+ else throw("Strict value is not equal to itself.")
1764+ }
1765+
1766+
1767+
1768+@Callable(i)
1769+func updateOracle (_priceUpdate) = if ((oracleMode() == ORACLE_PLAIN))
1770+ then nil
1771+ else {
1772+ let priceUpdates = split_4C(_priceUpdate, "::")
1773+ let baseOracle = valueOrErrorMessage(getOracleData(k_baseOracle), "No base asset oracle data")
1774+ let baseOracleAddress = baseOracle._1
1775+ let doUpdateBaseOracle = invoke(baseOracleAddress, "updateData", [priceUpdates[0]], nil)
1776+ if ((doUpdateBaseOracle == doUpdateBaseOracle))
1777+ then {
1778+ let quoteOracle = getOracleData(k_quoteOracle)
1779+ let doUpdateQuoteOracle = if (isDefined(quoteOracle))
1780+ then {
1781+ let quoteOracleV = value(quoteOracle)
1782+ let quoteOracleAddress = quoteOracleV._1
1783+ let doUpdateQuoteOracle = invoke(quoteOracleAddress, "updateData", [priceUpdates[1]], nil)
1784+ if ((doUpdateQuoteOracle == doUpdateQuoteOracle))
1785+ then nil
1786+ else throw("Strict value is not equal to itself.")
1787+ }
1788+ else nil
1789+ if ((doUpdateQuoteOracle == doUpdateQuoteOracle))
1790+ then nil
1791+ else throw("Strict value is not equal to itself.")
1792+ }
1793+ else throw("Strict value is not equal to itself.")
1794+ }
1795+
1796+
1797+
1798+@Callable(i)
1799+func syncTerminalPriceToOracle () = {
1800+ let _qtAstR = qtAstR()
1801+ let _bsAstR = bsAstR()
1802+ let $t08222882594 = getSyncTerminalPrice(getOraclePrice(), _qtAstR, _bsAstR)
1803+ let newQuoteAssetWeight = $t08222882594._1
1804+ let newBaseAssetWeight = $t08222882594._2
1805+ let marginToVault = $t08222882594._3
1806+ let marginToVaultAdj = if (if ((0 > marginToVault))
1807+ then (abs(marginToVault) > cbalance())
1808+ else false)
1809+ then -(cbalance())
1810+ else marginToVault
1811+ let doExchangePnL = if ((marginToVaultAdj != 0))
1812+ then {
1813+ let doExchangePnL = invoke(vaultAddress(), "exchangeFreeAndLocked", [marginToVaultAdj], nil)
1814+ if ((doExchangePnL == doExchangePnL))
1815+ then nil
1816+ else throw("Strict value is not equal to itself.")
1817+ }
1818+ else nil
1819+ if ((doExchangePnL == doExchangePnL))
1820+ then (updateBalance((cbalance() + marginToVaultAdj)) ++ updateAmmWeights(newQuoteAssetWeight, newBaseAssetWeight))
1821+ else throw("Strict value is not equal to itself.")
1822+ }
1823+
1824+
1825+
1826+@Callable(i)
1827+func ensureCalledOnce () = if ((i.caller != this))
1828+ then throw("Invalid saveCurrentTxId parameters")
1829+ else {
1830+ let txId = toBase58String(i.transactionId)
1831+ let lastTx = valueOrElse(getString(this, k_lastTx), "")
1832+ if ((lastTx != txId))
1833+ then [StringEntry(k_lastTx, txId)]
1834+ else throw("Can not call vAMM methods twice in one tx")
1835+ }
1836+
1837+
1838+
1839+@Callable(i)
1840+func migratePosition (_trader) = {
1841+ let positionSizeOpt = getInteger(this, toCompositeKey(k_positionSize, _trader))
1842+ if (if (isDefined(positionSizeOpt))
1843+ then isDefined(addressFromString(_trader))
1844+ else false)
1845+ then {
1846+ let pSize = getIntegerValue(this, toCompositeKey(k_positionSize, _trader))
1847+ let pMargin = getIntegerValue(this, toCompositeKey(k_positionMargin, _trader))
1848+ let pNotional = getIntegerValue(this, toCompositeKey(k_positionOpenNotional, _trader))
1849+ let pFraction = getIntegerValue(this, toCompositeKey(k_positionLastUpdatedCumulativePremiumFraction, _trader))
1850+ let pTimestamp = valueOrElse(getInteger(this, toCompositeKey(k_positionLastUpdatedTimestamp, _trader)), lastBlock.timestamp)
1851+ let pFee = valueOrElse(getInteger(this, toCompositeKey(k_positionFee, _trader)), fee())
1852+ let pSequence = getIntegerValue(this, toCompositeKey(k_positionSequence, _trader))
1853+ let pDirection = getDirection(pSize)
1854+ let positionKey = ((_trader + "_") + toString(pDirection))
1855+[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)]
1856+ }
1857+ else throw(("Nothing to migrate for " + _trader))
1858+ }
1859+
1860+
1861+
1862+@Callable(i)
1863+func view_calcRemainMarginWithFundingPayment (_trader,_direction,_priceUpdate) = {
1864+ let updateOracle = invoke(this, "updateOracle", [_priceUpdate], nil)
1865+ if ((updateOracle == updateOracle))
1866+ then {
1867+ let sync = invoke(this, "syncTerminalPriceToOracle", nil, nil)
1868+ if ((sync == sync))
1869+ then {
1870+ let $t08638886524 = getPosition(_trader, _direction)
1871+ let positionSize = $t08638886524._1
1872+ let positionMargin = $t08638886524._2
1873+ let pon = $t08638886524._3
1874+ let positionLstUpdCPF = $t08638886524._4
1875+ let positionTimestamp = $t08638886524._5
1876+ let $t08652786640 = getPositionNotionalAndUnrealizedPnl(_trader, _direction, PNL_OPTION_SPOT)
1877+ let positionNotional = $t08652786640._1
1878+ let unrealizedPnl = $t08652786640._2
1879+ let $t08664386867 = calcRemainMarginWithFundingPaymentAndRolloverFee(positionSize, positionMargin, positionLstUpdCPF, positionTimestamp, unrealizedPnl)
1880+ let remainMargin = $t08664386867._1
1881+ let badDebt = $t08664386867._2
1882+ let fundingPayment = $t08664386867._3
1883+ let rolloverFee = $t08664386867._4
1884+ let underlyingPrice = getOraclePrice()
1885+ let spotPrice = getSpotPrice()
1886+ throw(((((((((s(remainMargin) + s(fundingPayment)) + s(getMarginRatio(_trader, _direction))) + s(unrealizedPnl)) + s(badDebt)) + s(positionNotional)) + s(rolloverFee)) + s(underlyingPrice)) + s(spotPrice)))
1887+ }
1888+ else throw("Strict value is not equal to itself.")
1889+ }
1890+ else throw("Strict value is not equal to itself.")
1891+ }
1892+
1893+
1894+
1895+@Callable(i)
1896+func view_getPegAdjustCost (_price) = {
1897+ let _qtAstR = qtAstR()
1898+ let _bsAstR = bsAstR()
1899+ let result = getSyncTerminalPrice(_price, _qtAstR, _bsAstR)
1900+ throw(toString(result._3))
1901+ }
1902+
1903+
1904+
1905+@Callable(i)
1906+func view_getTerminalAmmPrice () = {
1907+ let $t08772087801 = getTerminalAmmState()
1908+ let terminalQuoteAssetReserve = $t08772087801._1
1909+ let terminalBaseAssetReserve = $t08772087801._2
1910+ let price = divd(muld(terminalQuoteAssetReserve, qtAstW()), muld(terminalBaseAssetReserve, bsAstW()))
1911+ throw(toString(price))
1912+ }
1913+
1914+
1915+
1916+@Callable(i)
1917+func view_getFunding (_priceUpdate) = {
1918+ let updateOracle = invoke(this, "updateOracle", [_priceUpdate], nil)
1919+ if ((updateOracle == updateOracle))
1920+ then {
1921+ let sync = invoke(this, "syncTerminalPriceToOracle", nil, nil)
1922+ if ((sync == sync))
1923+ then {
1924+ let underlyingPrice = getOraclePrice()
1925+ let $t08845388531 = getFunding()
1926+ let shortPremiumFraction = $t08845388531._1
1927+ let longPremiumFraction = $t08845388531._2
1928+ let premiumToVault = $t08845388531._3
1929+ let longFunding = divd(longPremiumFraction, underlyingPrice)
1930+ let shortFunding = divd(shortPremiumFraction, underlyingPrice)
1931+ throw(((((s(longFunding) + s(shortFunding)) + s(getSpotPrice())) + s(getOraclePrice())) + s(premiumToVault)))
1932+ }
1933+ else throw("Strict value is not equal to itself.")
1934+ }
1935+ else throw("Strict value is not equal to itself.")
1936+ }
1937+
1938+
1939+
1940+@Callable(i)
1941+func computeSpotPrice () = {
1942+ let sync = invoke(this, "syncTerminalPriceToOracle", nil, nil)
1943+ if ((sync == sync))
1944+ then {
1945+ let result = getSpotPrice()
1946+ $Tuple2(nil, result)
1947+ }
1948+ else throw("Strict value is not equal to itself.")
1949+ }
1950+
1951+
1952+
1953+@Callable(i)
1954+func computeFeeForTraderWithArtifact (_trader,_artifactId) = {
1955+ let result = getForTraderWithArtifact(_trader, _artifactId)
1956+ $Tuple2(nil, result)
1957+ }
1958+
1959+
1960+@Verifier(tx)
1961+func verify () = {
1962+ let coordinatorStr = getString(this, k_coordinatorAddress)
1963+ if (isDefined(coordinatorStr))
1964+ then {
1965+ let admin = getString(addressFromStringValue(value(coordinatorStr)), k_admin_address)
1966+ if (isDefined(admin))
1967+ then valueOrElse(getBoolean(addressFromStringValue(value(admin)), ((("status_" + toString(this)) + "_") + toBase58String(tx.id))), false)
1968+ else throw("unable to verify: admin not set in coordinator")
1969+ }
1970+ else sigVerify(tx.bodyBytes, tx.proofs[0], tx.senderPublicKey)
1971+ }
1972+

github/deemru/w8io/169f3d6 
88.32 ms