tx · 65h9jMSDss9uoEqpqvyFJ16hSrWBEKSRySNhHQAGPMuk

3MpjMveMjHs97n26f8QdyN8i3Csx379uswG:  -0.07500000 Waves

2023.08.04 11:15 [2695585] smart account 3MpjMveMjHs97n26f8QdyN8i3Csx379uswG > SELF 0.00000000 Waves

{ "type": 13, "id": "65h9jMSDss9uoEqpqvyFJ16hSrWBEKSRySNhHQAGPMuk", "fee": 7500000, "feeAssetId": null, "timestamp": 1691136954669, "version": 2, "chainId": 84, "sender": "3MpjMveMjHs97n26f8QdyN8i3Csx379uswG", "senderPublicKey": "7yXUpfDsaJbPTTdmfjwoT8UnaUpTf61azAA8NGbkRxSM", "proofs": [ "2yRGuSd23qZARfamnw5Y3jtGuvRRd7m38ixsHGRi4uNKi2dXaP1J8juLcceCtbTAPyg6uhBgnsxNCynCiuUGrHFk" ], "script": "base64:BgKUAQgCEgASABIAEgASAwoBARIVChMBAQEBAQEBAQEBAQEBAQEICAEBEhgKFgEBAQEBAQEICAgBAQEBAQEBAQEBAQESBwoFAQEBCAgSBAoCAQgSBQoDAQEIEgcKBQEBAQQIEgUKAwgBCBIDCgEIEgMKAQgSABIAEgMKAQgSBQoDCAEIEgMKAQESABIDCgEIEgASBAoCCAi/AQAMa19iYXNlT3JhY2xlAgxrX2Jhc2VPcmFjbGUADWtfcXVvdGVPcmFjbGUCDWtfcXVvdGVPcmFjbGUACWtfYmFsYW5jZQIJa19iYWxhbmNlAAprX3NlcXVlbmNlAgprX3NlcXVlbmNlAA5rX3Bvc2l0aW9uU2l6ZQIOa19wb3NpdGlvblNpemUAEGtfcG9zaXRpb25NYXJnaW4CEGtfcG9zaXRpb25NYXJnaW4AFmtfcG9zaXRpb25PcGVuTm90aW9uYWwCFmtfcG9zaXRpb25PcGVuTm90aW9uYWwALmtfcG9zaXRpb25MYXN0VXBkYXRlZEN1bXVsYXRpdmVQcmVtaXVtRnJhY3Rpb24CEmtfcG9zaXRpb25GcmFjdGlvbgASa19wb3NpdGlvblNlcXVlbmNlAhJrX3Bvc2l0aW9uU2VxdWVuY2UADWtfcG9zaXRpb25GZWUCDWtfcG9zaXRpb25GZWUAHmtfcG9zaXRpb25MYXN0VXBkYXRlZFRpbWVzdGFtcAITa19wb3NpdGlvblRpbWVzdGFtcAANa19pbml0aWFsaXplZAINa19pbml0aWFsaXplZAAIa19wYXVzZWQCCGtfcGF1c2VkAAtrX2Nsb3NlT25seQILa19jbG9zZU9ubHkABWtfZmVlAgVrX2ZlZQANa19yb2xsb3ZlckZlZQIOa19yb2xsb3Zlcl9mZWUAD2tfZnVuZGluZ1BlcmlvZAIPa19mdW5kaW5nUGVyaW9kABFrX2luaXRNYXJnaW5SYXRpbwIRa19pbml0TWFyZ2luUmF0aW8AFGtfbWluSW5pdE1hcmdpblJhdGlvAhRrX21pbkluaXRNYXJnaW5SYXRpbwAYa19tYWludGVuYW5jZU1hcmdpblJhdGlvAgVrX21tcgAVa19saXF1aWRhdGlvbkZlZVJhdGlvAhVrX2xpcXVpZGF0aW9uRmVlUmF0aW8AGWtfcGFydGlhbExpcXVpZGF0aW9uUmF0aW8CFmtfcGFydExpcXVpZGF0aW9uUmF0aW8ADWtfc3ByZWFkTGltaXQCDWtfc3ByZWFkTGltaXQAEGtfbWF4UHJpY2VJbXBhY3QCEGtfbWF4UHJpY2VJbXBhY3QAEGtfbWF4UHJpY2VTcHJlYWQCEGtfbWF4UHJpY2VTcHJlYWQAEWtfbWF4T3Blbk5vdGlvbmFsAhFrX21heE9wZW5Ob3Rpb25hbAAVa19mZWVUb1N0YWtlcnNQZXJjZW50AhVrX2ZlZVRvU3Rha2Vyc1BlcmNlbnQAEGtfbWF4T3JhY2xlRGVsYXkCEGtfbWF4T3JhY2xlRGVsYXkADWtfZnVuZGluZ01vZGUCDWtfZnVuZGluZ01vZGUADGtfb3JhY2xlTW9kZQIMa19vcmFjbGVNb2RlAA5rX3Bvc2l0aW9uTW9kZQIOa19wb3NpdGlvbk1vZGUAGGtfbWluTGlxdWlkYXRpb25Ob3Rpb25hbAIYa19taW5MaXF1aWRhdGlvbk5vdGlvbmFsACVrX2xhdGVzdExvbmdDdW11bGF0aXZlUHJlbWl1bUZyYWN0aW9uAhtrX2xhdGVzdExvbmdQcmVtaXVtRnJhY3Rpb24AJmtfbGF0ZXN0U2hvcnRDdW11bGF0aXZlUHJlbWl1bUZyYWN0aW9uAhxrX2xhdGVzdFNob3J0UHJlbWl1bUZyYWN0aW9uABJrX25leHRGdW5kaW5nQmxvY2sCHmtfbmV4dEZ1bmRpbmdCbG9ja01pblRpbWVzdGFtcAARa19sb25nRnVuZGluZ1JhdGUCEWtfbG9uZ0Z1bmRpbmdSYXRlABJrX3Nob3J0RnVuZGluZ1JhdGUCEmtfc2hvcnRGdW5kaW5nUmF0ZQATa19xdW90ZUFzc2V0UmVzZXJ2ZQIIa19xdEFzdFIAEmtfYmFzZUFzc2V0UmVzZXJ2ZQIIa19ic0FzdFIAEmtfcXVvdGVBc3NldFdlaWdodAIIa19xdEFzdFcAEWtfYmFzZUFzc2V0V2VpZ2h0AghrX2JzQXN0VwATa190b3RhbFBvc2l0aW9uU2l6ZQITa190b3RhbFBvc2l0aW9uU2l6ZQAXa190b3RhbExvbmdQb3NpdGlvblNpemUCF2tfdG90YWxMb25nUG9zaXRpb25TaXplABhrX3RvdGFsU2hvcnRQb3NpdGlvblNpemUCGGtfdG90YWxTaG9ydFBvc2l0aW9uU2l6ZQAWa19vcGVuSW50ZXJlc3ROb3Rpb25hbAIWa19vcGVuSW50ZXJlc3ROb3Rpb25hbAATa19vcGVuSW50ZXJlc3RTaG9ydAITa19vcGVuSW50ZXJlc3RTaG9ydAASa19vcGVuSW50ZXJlc3RMb25nAhJrX29wZW5JbnRlcmVzdExvbmcACGtfbGFzdFR4AghrX2xhc3RUeAAUa19jb29yZGluYXRvckFkZHJlc3MCFGtfY29vcmRpbmF0b3JBZGRyZXNzAA9rX3ZhdWx0X2FkZHJlc3MCD2tfdmF1bHRfYWRkcmVzcwAPa19hZG1pbl9hZGRyZXNzAg9rX2FkbWluX2FkZHJlc3MADWtfcXVvdGVfYXNzZXQCDWtfcXVvdGVfYXNzZXQAEWtfc3Rha2luZ19hZGRyZXNzAhFrX3N0YWtpbmdfYWRkcmVzcwAPa19taW5lcl9hZGRyZXNzAg9rX21pbmVyX2FkZHJlc3MAEGtfb3JkZXJzX2FkZHJlc3MCEGtfb3JkZXJzX2FkZHJlc3MAEmtfcmVmZXJyYWxfYWRkcmVzcwISa19yZWZlcnJhbF9hZGRyZXNzABVrX25mdF9tYW5hZ2VyX2FkZHJlc3MCFWtfbmZ0X21hbmFnZXJfYWRkcmVzcwEOdG9Db21wb3NpdGVLZXkCBF9rZXkIX2FkZHJlc3MJAKwCAgkArAICBQRfa2V5AgFfBQhfYWRkcmVzcwELY29vcmRpbmF0b3IACQETdmFsdWVPckVycm9yTWVzc2FnZQIJAKYIAQkBEUBleHRyTmF0aXZlKDEwNTMpAgUEdGhpcwUUa19jb29yZGluYXRvckFkZHJlc3MCE0Nvb3JkaW5hdG9yIG5vdCBzZXQBDGFkbWluQWRkcmVzcwAJAKYIAQkBEUBleHRyTmF0aXZlKDEwNTMpAgkBC2Nvb3JkaW5hdG9yAAUPa19hZG1pbl9hZGRyZXNzAQpxdW90ZUFzc2V0AAkA2QQBCQERQGV4dHJOYXRpdmUoMTA1MykCCQELY29vcmRpbmF0b3IABQ1rX3F1b3RlX2Fzc2V0AQ5zdGFraW5nQWRkcmVzcwAJARN2YWx1ZU9yRXJyb3JNZXNzYWdlAgkApggBCQERQGV4dHJOYXRpdmUoMTA1MykCCQELY29vcmRpbmF0b3IABRFrX3N0YWtpbmdfYWRkcmVzcwIPU3Rha2luZyBub3Qgc2V0AQx2YXVsdEFkZHJlc3MACQETdmFsdWVPckVycm9yTWVzc2FnZQIJAKYIAQkBEUBleHRyTmF0aXZlKDEwNTMpAgkBC2Nvb3JkaW5hdG9yAAUPa192YXVsdF9hZGRyZXNzAg1WYXVsdCBub3Qgc2V0AQxtaW5lckFkZHJlc3MACQETdmFsdWVPckVycm9yTWVzc2FnZQIJAKYIAQkBEUBleHRyTmF0aXZlKDEwNTMpAgkBC2Nvb3JkaW5hdG9yAAUPa19taW5lcl9hZGRyZXNzAg1NaW5lciBub3Qgc2V0AQ1vcmRlcnNBZGRyZXNzAAkBE3ZhbHVlT3JFcnJvck1lc3NhZ2UCCQCmCAEJARFAZXh0ck5hdGl2ZSgxMDUzKQIJAQtjb29yZGluYXRvcgAFEGtfb3JkZXJzX2FkZHJlc3MCDk9yZGVycyBub3Qgc2V0AQ9yZWZlcnJhbEFkZHJlc3MACQETdmFsdWVPckVycm9yTWVzc2FnZQIJAKYIAQkBEUBleHRyTmF0aXZlKDEwNTMpAgkBC2Nvb3JkaW5hdG9yAAUSa19yZWZlcnJhbF9hZGRyZXNzAhBSZWZlcnJhbCBub3Qgc2V0ARFuZnRNYW5hZ2VyQWRkcmVzcwAJARN2YWx1ZU9yRXJyb3JNZXNzYWdlAgkApggBCQERQGV4dHJOYXRpdmUoMTA1MykCCQELY29vcmRpbmF0b3IABRVrX25mdF9tYW5hZ2VyX2FkZHJlc3MCE05GVCBNYW5hZ2VyIG5vdCBzZXQADWtfdG9rZW5fcGFyYW0CDWtfdG9rZW5fcGFyYW0ADGtfdG9rZW5fdHlwZQIMa190b2tlbl90eXBlABhGRUVfUkVEVUNUSU9OX1RPS0VOX1RZUEUCDWZlZV9yZWR1Y3Rpb24ACERJUl9MT05HAAEACURJUl9TSE9SVAACAAdTRUNPTkRTAOgHAA9ERUNJTUFMX05VTUJFUlMABgAMREVDSU1BTF9VTklUCQBoAgABCQBoAgkAaAIJAGgCCQBoAgkAaAIACgAKAAoACgAKAAoAD01JTlVURVNfSU5fWUVBUgkAaAIAoIogBQxERUNJTUFMX1VOSVQAB09ORV9EQVkJAGgCAICjBQUMREVDSU1BTF9VTklUAA9QTkxfT1BUSU9OX1NQT1QAAQARUE5MX09QVElPTl9PUkFDTEUAAgASRlVORElOR19BU1lNTUVUUklDAAEAEUZVTkRJTkdfU1lNTUVUUklDAAIADE9SQUNMRV9QTEFJTgABAApPUkFDTEVfSklUAAIAD1BPU0lUSU9OX0RJUkVDVAABAA5QT1NJVElPTl9PUkRFUgACAQFzAQJfeAkArAICCQCkAwEFAl94AgEsAQRkaXZkAgJfeAJfeQkAbgQFAl94BQxERUNJTUFMX1VOSVQFAl95BQhIQUxGRVZFTgEEbXVsZAICX3gCX3kJAG4EBQJfeAUCX3kFDERFQ0lNQUxfVU5JVAUISEFMRkVWRU4BBWJkaXZkAgJfeAJfeQkAvQIEBQJfeAkAtgIBBQxERUNJTUFMX1VOSVQFAl95BQhIQUxGRVZFTgEFYm11bGQCAl94Al95CQC9AgQFAl94BQJfeQkAtgIBBQxERUNJTUFMX1VOSVQFCEhBTEZFVkVOAQNhYnMBAl94AwkAZgIFAl94AAAFAl94CQEBLQEFAl94AQR2bWF4AgJfeAJfeQMJAGcCBQJfeAUCX3kFAl94BQJfeQEDaW50AQFrCQETdmFsdWVPckVycm9yTWVzc2FnZQIJAJoIAgUEdGhpcwUBawkArAICAg1ubyB2YWx1ZSBmb3IgBQFrAQVpbnRPcgIBawNkZWYJAQt2YWx1ZU9yRWxzZQIJAJoIAgUEdGhpcwUBawUDZGVmAQRzdHJBAghfYWRkcmVzcwRfa2V5BAN2YWwJARN2YWx1ZU9yRXJyb3JNZXNzYWdlAgkAnQgCBQhfYWRkcmVzcwUEX2tleQkArAICAhFObyB2YWx1ZSBmb3Iga2V5IAUEX2tleQUDdmFsAQRpbnRBAghfYWRkcmVzcwRfa2V5BAN2YWwJARN2YWx1ZU9yRXJyb3JNZXNzYWdlAgkAmggCBQhfYWRkcmVzcwUEX2tleQkArAICAhFObyB2YWx1ZSBmb3Iga2V5IAUEX2tleQUDdmFsAQhjYmFsYW5jZQAJAQNpbnQBBQlrX2JhbGFuY2UBCWNiYWxhbmNlMAAJAQVpbnRPcgIFCWtfYmFsYW5jZQAAAQNmZWUACQEDaW50AQUFa19mZWUBD3JvbGxvdmVyRmVlUmF0ZQAJAQNpbnQBBQ1rX3JvbGxvdmVyRmVlAQ9pbml0TWFyZ2luUmF0aW8ACQEDaW50AQURa19pbml0TWFyZ2luUmF0aW8BEm1pbkluaXRNYXJnaW5SYXRpbwAJAQVpbnRPcgIFFGtfbWluSW5pdE1hcmdpblJhdGlvCQBoAgAKBQxERUNJTUFMX1VOSVQBBnF0QXN0UgAJAQNpbnQBBRNrX3F1b3RlQXNzZXRSZXNlcnZlAQdxdEFzdFIwAAkBBWludE9yAgUTa19xdW90ZUFzc2V0UmVzZXJ2ZQAAAQZic0FzdFIACQEDaW50AQUSa19iYXNlQXNzZXRSZXNlcnZlAQdic0FzdFIwAAkBBWludE9yAgUSa19iYXNlQXNzZXRSZXNlcnZlAAABBnF0QXN0VwAJAQVpbnRPcgIFEmtfcXVvdGVBc3NldFdlaWdodAUMREVDSU1BTF9VTklUAQZic0FzdFcACQEFaW50T3ICBRFrX2Jhc2VBc3NldFdlaWdodAUMREVDSU1BTF9VTklUARF0b3RhbFBvc2l0aW9uU2l6ZQAJAQNpbnQBBRNrX3RvdGFsUG9zaXRpb25TaXplARRvcGVuSW50ZXJlc3ROb3Rpb25hbAAJAQNpbnQBBRZrX29wZW5JbnRlcmVzdE5vdGlvbmFsARFvcGVuSW50ZXJlc3RTaG9ydAAJAQNpbnQBBRNrX29wZW5JbnRlcmVzdFNob3J0ARBvcGVuSW50ZXJlc3RMb25nAAkBA2ludAEFEmtfb3BlbkludGVyZXN0TG9uZwEZbmV4dEZ1bmRpbmdCbG9ja1RpbWVzdGFtcAAJAQNpbnQBBRJrX25leHRGdW5kaW5nQmxvY2sBEGZ1bmRpbmdQZXJpb2RSYXcACQEDaW50AQUPa19mdW5kaW5nUGVyaW9kARRmdW5kaW5nUGVyaW9kRGVjaW1hbAAJAGgCCQEQZnVuZGluZ1BlcmlvZFJhdwAFDERFQ0lNQUxfVU5JVAEUZnVuZGluZ1BlcmlvZFNlY29uZHMACQBoAgkBEGZ1bmRpbmdQZXJpb2RSYXcABQdTRUNPTkRTARZtYWludGVuYW5jZU1hcmdpblJhdGlvAAkBA2ludAEFGGtfbWFpbnRlbmFuY2VNYXJnaW5SYXRpbwETbGlxdWlkYXRpb25GZWVSYXRpbwAJAQNpbnQBBRVrX2xpcXVpZGF0aW9uRmVlUmF0aW8BF3BhcnRpYWxMaXF1aWRhdGlvblJhdGlvAAkBA2ludAEFGWtfcGFydGlhbExpcXVpZGF0aW9uUmF0aW8BC3NwcmVhZExpbWl0AAkBA2ludAEFDWtfc3ByZWFkTGltaXQBDm1heFByaWNlSW1wYWN0AAkBA2ludAEFEGtfbWF4UHJpY2VJbXBhY3QBDm1heFByaWNlU3ByZWFkAAkBA2ludAEFEGtfbWF4UHJpY2VTcHJlYWQBD21heE9wZW5Ob3Rpb25hbAAJAQNpbnQBBRFrX21heE9wZW5Ob3Rpb25hbAEjbGF0ZXN0TG9uZ0N1bXVsYXRpdmVQcmVtaXVtRnJhY3Rpb24ACQEDaW50AQUla19sYXRlc3RMb25nQ3VtdWxhdGl2ZVByZW1pdW1GcmFjdGlvbgEkbGF0ZXN0U2hvcnRDdW11bGF0aXZlUHJlbWl1bUZyYWN0aW9uAAkBA2ludAEFJmtfbGF0ZXN0U2hvcnRDdW11bGF0aXZlUHJlbWl1bUZyYWN0aW9uARZ0b3RhbFNob3J0UG9zaXRpb25TaXplAAkBA2ludAEFGGtfdG90YWxTaG9ydFBvc2l0aW9uU2l6ZQEVdG90YWxMb25nUG9zaXRpb25TaXplAAkBA2ludAEFF2tfdG90YWxMb25nUG9zaXRpb25TaXplAQxsYXN0U2VxdWVuY2UACQEFaW50T3ICBQprX3NlcXVlbmNlAAABE2ZlZVRvU3Rha2Vyc1BlcmNlbnQACQEDaW50AQUVa19mZWVUb1N0YWtlcnNQZXJjZW50AQ5tYXhPcmFjbGVEZWxheQAJAQNpbnQBBRBrX21heE9yYWNsZURlbGF5AQtmdW5kaW5nTW9kZQAJAQVpbnRPcgIFDWtfZnVuZGluZ01vZGUFEkZVTkRJTkdfQVNZTU1FVFJJQwEKb3JhY2xlTW9kZQAJAQVpbnRPcgIFDGtfb3JhY2xlTW9kZQUMT1JBQ0xFX1BMQUlOAQxwb3NpdGlvbk1vZGUACQEFaW50T3ICBQ5rX3Bvc2l0aW9uTW9kZQUPUE9TSVRJT05fRElSRUNUAR1taW5QYXJ0aWFsTGlxdWlkYXRpb25Ob3Rpb25hbAAJAQVpbnRPcgIFGGtfbWluTGlxdWlkYXRpb25Ob3Rpb25hbAkAaAIACgUMREVDSU1BTF9VTklUAQ1sYXN0VGltZXN0YW1wAAgFCWxhc3RCbG9jawl0aW1lc3RhbXABD2dldEFjdHVhbENhbGxlcgEBaQkBC3ZhbHVlT3JFbHNlAgkAnQgCCQENb3JkZXJzQWRkcmVzcwACCGtfc2VuZGVyCQClCAEIBQFpBmNhbGxlcgEWcmVxdWlyZU1vcmVNYXJnaW5SYXRpbwMMX21hcmdpblJhdGlvEF9iYXNlTWFyZ2luUmF0aW8UX2xhcmdlclRoYW5PckVxdWFsVG8EFHJlbWFpbmluZ01hcmdpblJhdGlvCQBlAgUMX21hcmdpblJhdGlvBRBfYmFzZU1hcmdpblJhdGlvAwMFFF9sYXJnZXJUaGFuT3JFcXVhbFRvCQBmAgAABRRyZW1haW5pbmdNYXJnaW5SYXRpbwcJAAIBCQCsAgIJAKwCAgkArAICAhBJbnZhbGlkIG1hcmdpbjogCQCkAwEFDF9tYXJnaW5SYXRpbwIDIDwgCQCkAwEFEF9iYXNlTWFyZ2luUmF0aW8DAwkBASEBBRRfbGFyZ2VyVGhhbk9yRXF1YWxUbwkAZwIFFHJlbWFpbmluZ01hcmdpblJhdGlvAAAHCQACAQkArAICCQCsAgIJAKwCAgIQSW52YWxpZCBtYXJnaW46IAkApAMBBQxfbWFyZ2luUmF0aW8CAyA+IAkApAMBBRBfYmFzZU1hcmdpblJhdGlvBgEfbGF0ZXN0Q3VtdWxhdGl2ZVByZW1pdW1GcmFjdGlvbgENX3Bvc2l0aW9uU2l6ZQMJAAACBQ1fcG9zaXRpb25TaXplAAAJAAIBAixTaG91bGQgbm90IGJlIGNhbGxlZCB3aXRoIF9wb3NpdGlvblNpemUgPT0gMAMJAGYCBQ1fcG9zaXRpb25TaXplAAAJASNsYXRlc3RMb25nQ3VtdWxhdGl2ZVByZW1pdW1GcmFjdGlvbgAJASRsYXRlc3RTaG9ydEN1bXVsYXRpdmVQcmVtaXVtRnJhY3Rpb24AAQtnZXRQb3NpdGlvbgIHX3RyYWRlcgpfZGlyZWN0aW9uBAtwb3NpdGlvbktleQkArAICCQCsAgIFB190cmFkZXICAV8JAKQDAQUKX2RpcmVjdGlvbgQPcG9zaXRpb25TaXplT3B0CQCaCAIFBHRoaXMJAQ50b0NvbXBvc2l0ZUtleQIFDmtfcG9zaXRpb25TaXplBQtwb3NpdGlvbktleQQHJG1hdGNoMAUPcG9zaXRpb25TaXplT3B0AwkAAQIFByRtYXRjaDACA0ludAQMcG9zaXRpb25TaXplBQckbWF0Y2gwCQCXCgUFDHBvc2l0aW9uU2l6ZQkBEUBleHRyTmF0aXZlKDEwNTApAgUEdGhpcwkBDnRvQ29tcG9zaXRlS2V5AgUQa19wb3NpdGlvbk1hcmdpbgULcG9zaXRpb25LZXkJARFAZXh0ck5hdGl2ZSgxMDUwKQIFBHRoaXMJAQ50b0NvbXBvc2l0ZUtleQIFFmtfcG9zaXRpb25PcGVuTm90aW9uYWwFC3Bvc2l0aW9uS2V5CQERQGV4dHJOYXRpdmUoMTA1MCkCBQR0aGlzCQEOdG9Db21wb3NpdGVLZXkCBS5rX3Bvc2l0aW9uTGFzdFVwZGF0ZWRDdW11bGF0aXZlUHJlbWl1bUZyYWN0aW9uBQtwb3NpdGlvbktleQkBEUBleHRyTmF0aXZlKDEwNTApAgUEdGhpcwkBDnRvQ29tcG9zaXRlS2V5AgUea19wb3NpdGlvbkxhc3RVcGRhdGVkVGltZXN0YW1wBQtwb3NpdGlvbktleQkAlwoFAAAAAAAAAAAAAAEMZ2V0RGlyZWN0aW9uAQ1fcG9zaXRpb25TaXplAwkAZgIAAAUNX3Bvc2l0aW9uU2l6ZQUJRElSX1NIT1JUBQhESVJfTE9ORwEOZ2V0UG9zaXRpb25GZWUCB190cmFkZXIKX2RpcmVjdGlvbgQLcG9zaXRpb25LZXkJAKwCAgkArAICBQdfdHJhZGVyAgFfCQCkAwEFCl9kaXJlY3Rpb24EDnBvc2l0aW9uRmVlT3B0CQCaCAIFBHRoaXMJAQ50b0NvbXBvc2l0ZUtleQIFDWtfcG9zaXRpb25GZWUFC3Bvc2l0aW9uS2V5BAckbWF0Y2gwBQ5wb3NpdGlvbkZlZU9wdAMJAAECBQckbWF0Y2gwAgNJbnQEC3Bvc2l0aW9uRmVlBQckbWF0Y2gwBQtwb3NpdGlvbkZlZQkBA2ZlZQABE3JlcXVpcmVPcGVuUG9zaXRpb24CB190cmFkZXIKX2RpcmVjdGlvbgMJAAACCAkBC2dldFBvc2l0aW9uAgUHX3RyYWRlcgUKX2RpcmVjdGlvbgJfMQAACQACAQIQTm8gb3BlbiBwb3NpdGlvbgYBDWdldE9yYWNsZURhdGEBA2tleQQNb3JhY2xlRGF0YVN0cgkAnQgCBQR0aGlzBQNrZXkDAwkBCWlzRGVmaW5lZAEFDW9yYWNsZURhdGFTdHIJAQIhPQIJAQV2YWx1ZQEFDW9yYWNsZURhdGFTdHICAAcECm9yYWNsZURhdGEJALUJAgkBBXZhbHVlAQUNb3JhY2xlRGF0YVN0cgIBLAQNb3JhY2xlQWRkcmVzcwkBE3ZhbHVlT3JFcnJvck1lc3NhZ2UCCQCmCAEJAJEDAgUKb3JhY2xlRGF0YQAACQCsAgICG0ludmFsaWQgb3JhY2xlIGFkZHJlc3MgaW46IAkBBXZhbHVlAQUNb3JhY2xlRGF0YVN0cgQIcHJpY2VLZXkJAJEDAgUKb3JhY2xlRGF0YQABBAhibG9ja0tleQkAkQMCBQpvcmFjbGVEYXRhAAIEB29wZW5LZXkJAJEDAgUKb3JhY2xlRGF0YQADCQCWCgQFDW9yYWNsZUFkZHJlc3MFCHByaWNlS2V5BQhibG9ja0tleQUHb3BlbktleQUEdW5pdAELaW5pdGlhbGl6ZWQACQELdmFsdWVPckVsc2UCCQCbCAIFBHRoaXMFDWtfaW5pdGlhbGl6ZWQHAQZwYXVzZWQACQELdmFsdWVPckVsc2UCCQCbCAIFBHRoaXMFCGtfcGF1c2VkBwEJY2xvc2VPbmx5AAkBC3ZhbHVlT3JFbHNlAgkAmwgCBQR0aGlzBQtrX2Nsb3NlT25seQcBDXVwZGF0ZVJlc2VydmUDBl9pc0FkZBFfcXVvdGVBc3NldEFtb3VudBBfYmFzZUFzc2V0QW1vdW50AwUGX2lzQWRkBAduZXdCYXNlCQBlAgkBBmJzQXN0UgAFEF9iYXNlQXNzZXRBbW91bnQDCQBnAgAABQduZXdCYXNlCQACAQIqVHggbGVhZCB0byBiYXNlIGFzc2V0IHJlc2VydmUgPD0gMCwgcmV2ZXJ0CQCVCgMJAGQCCQEGcXRBc3RSAAURX3F1b3RlQXNzZXRBbW91bnQFB25ld0Jhc2UJAGQCCQERdG90YWxQb3NpdGlvblNpemUABRBfYmFzZUFzc2V0QW1vdW50BAhuZXdRdW90ZQkAZQIJAQZxdEFzdFIABRFfcXVvdGVBc3NldEFtb3VudAMJAGcCAAAFCG5ld1F1b3RlCQACAQIqVHggbGVhZCB0byBiYXNlIHF1b3RlIHJlc2VydmUgPD0gMCwgcmV2ZXJ0CQCVCgMFCG5ld1F1b3RlCQBkAgkBBmJzQXN0UgAFEF9iYXNlQXNzZXRBbW91bnQJAGUCCQERdG90YWxQb3NpdGlvblNpemUABRBfYmFzZUFzc2V0QW1vdW50AQ1jYWxjSW52YXJpYW50AgdfcXRBc3RSB19ic0FzdFIEB2JxdEFzdFIJALYCAQUHX3F0QXN0UgQHYmJzQXN0UgkAtgIBBQdfYnNBc3RSCQEFYm11bGQCBQdicXRBc3RSBQdiYnNBc3RSAQlzd2FwSW5wdXQCBl9pc0FkZBFfcXVvdGVBc3NldEFtb3VudAQHX3F0QXN0UgkBBnF0QXN0UgAEB19ic0FzdFIJAQZic0FzdFIABAdfcXRBc3RXCQEGcXRBc3RXAAQHX2JzQXN0VwkBBmJzQXN0VwAEGHF1b3RlQXNzZXRBbW91bnRBZGp1c3RlZAkBBGRpdmQCBRFfcXVvdGVBc3NldEFtb3VudAUHX3F0QXN0VwQBawkBDWNhbGNJbnZhcmlhbnQCBQdfcXRBc3RSBQdfYnNBc3RSBBZxdW90ZUFzc2V0UmVzZXJ2ZUFmdGVyAwUGX2lzQWRkCQBkAgUHX3F0QXN0UgUYcXVvdGVBc3NldEFtb3VudEFkanVzdGVkCQBlAgUHX3F0QXN0UgUYcXVvdGVBc3NldEFtb3VudEFkanVzdGVkBBViYXNlQXNzZXRSZXNlcnZlQWZ0ZXIJAKADAQkBBWJkaXZkAgUBawkAtgIBBRZxdW90ZUFzc2V0UmVzZXJ2ZUFmdGVyBBhhbW91bnRCYXNlQXNzZXRCb3VnaHRBYnMJAQNhYnMBCQBlAgUVYmFzZUFzc2V0UmVzZXJ2ZUFmdGVyBQdfYnNBc3RSBBVhbW91bnRCYXNlQXNzZXRCb3VnaHQDBQZfaXNBZGQFGGFtb3VudEJhc2VBc3NldEJvdWdodEFicwkBAS0BBRhhbW91bnRCYXNlQXNzZXRCb3VnaHRBYnMEDSR0MDE2NTkwMTY3NjAJAQ11cGRhdGVSZXNlcnZlAwUGX2lzQWRkBRhxdW90ZUFzc2V0QW1vdW50QWRqdXN0ZWQFGGFtb3VudEJhc2VBc3NldEJvdWdodEFicwQXcXVvdGVBc3NldFJlc2VydmVBZnRlcjEIBQ0kdDAxNjU5MDE2NzYwAl8xBBZiYXNlQXNzZXRSZXNlcnZlQWZ0ZXIxCAUNJHQwMTY1OTAxNjc2MAJfMgQXdG90YWxQb3NpdGlvblNpemVBZnRlcjEIBQ0kdDAxNjU5MDE2NzYwAl8zBAtwcmljZUJlZm9yZQkBBGRpdmQCCQEEbXVsZAIFB19xdEFzdFIFB19xdEFzdFcJAQRtdWxkAgUHX2JzQXN0UgUHX2JzQXN0VwQLbWFya2V0UHJpY2UJAQRkaXZkAgURX3F1b3RlQXNzZXRBbW91bnQFGGFtb3VudEJhc2VBc3NldEJvdWdodEFicwQJcHJpY2VEaWZmCQEDYWJzAQkAZQIFC3ByaWNlQmVmb3JlBQttYXJrZXRQcmljZQQLcHJpY2VJbXBhY3QJAGUCBQxERUNJTUFMX1VOSVQJAQRkaXZkAgULcHJpY2VCZWZvcmUJAGQCBQtwcmljZUJlZm9yZQUJcHJpY2VEaWZmBBNtYXhQcmljZUltcGFjdFZhbHVlCQEObWF4UHJpY2VJbXBhY3QAAwkAZgIFC3ByaWNlSW1wYWN0BRNtYXhQcmljZUltcGFjdFZhbHVlCQACAQkArAICCQCsAgIJAKwCAgkArAICCQCsAgIJAKwCAgkArAICCQCsAgIJAKwCAgkArAICCQCsAgIJAKwCAgkArAICAg1QcmljZSBpbXBhY3QgCQCkAwEFC3ByaWNlSW1wYWN0AhQgPiBtYXggcHJpY2UgaW1wYWN0IAkApAMBBRNtYXhQcmljZUltcGFjdFZhbHVlAhUgYmVmb3JlIHF1b3RlIGFzc2V0OiAJAKQDAQUHX3F0QXN0UgIUIGJlZm9yZSBiYXNlIGFzc2V0OiAJAKQDAQUHX2JzQXN0UgIhIHF1b3RlIGFzc2V0IGFtb3VudCB0byBleGNoYW5nZTogCQCkAwEFEV9xdW90ZUFzc2V0QW1vdW50Ag8gcHJpY2UgYmVmb3JlOiAJAKQDAQULcHJpY2VCZWZvcmUCDiBtYXJrZXRQcmljZTogCQCkAwEFC21hcmtldFByaWNlCQCWCgQFFWFtb3VudEJhc2VBc3NldEJvdWdodAUXcXVvdGVBc3NldFJlc2VydmVBZnRlcjEFFmJhc2VBc3NldFJlc2VydmVBZnRlcjEFF3RvdGFsUG9zaXRpb25TaXplQWZ0ZXIxAQ9jYWxjUm9sbG92ZXJGZWUCEl9vbGRQb3NpdGlvbk1hcmdpbiBfb2xkUG9zaXRpb25MYXN0VXBkYXRlZFRpbWVzdGFtcAQPcG9zaXRpb25NaW51dGVzCQBoAgkAaQIJAGkCCQBlAgkBDWxhc3RUaW1lc3RhbXAABSBfb2xkUG9zaXRpb25MYXN0VXBkYXRlZFRpbWVzdGFtcADoBwA8BQxERUNJTUFMX1VOSVQEC3JvbGxvdmVyRmVlCQEEZGl2ZAIJAQRtdWxkAgkBBG11bGQCBRJfb2xkUG9zaXRpb25NYXJnaW4FD3Bvc2l0aW9uTWludXRlcwkBD3JvbGxvdmVyRmVlUmF0ZQAFD01JTlVURVNfSU5fWUVBUgULcm9sbG92ZXJGZWUBMGNhbGNSZW1haW5NYXJnaW5XaXRoRnVuZGluZ1BheW1lbnRBbmRSb2xsb3ZlckZlZQUQX29sZFBvc2l0aW9uU2l6ZRJfb2xkUG9zaXRpb25NYXJnaW4lX29sZFBvc2l0aW9uQ3VtdWxhdGl2ZVByZW1pdW1GcmFjdGlvbiBfb2xkUG9zaXRpb25MYXN0VXBkYXRlZFRpbWVzdGFtcAxfbWFyZ2luRGVsdGEEDmZ1bmRpbmdQYXltZW50AwkBAiE9AgUQX29sZFBvc2l0aW9uU2l6ZQAABCBfbGF0ZXN0Q3VtdWxhdGl2ZVByZW1pdW1GcmFjdGlvbgkBH2xhdGVzdEN1bXVsYXRpdmVQcmVtaXVtRnJhY3Rpb24BBRBfb2xkUG9zaXRpb25TaXplCQEEbXVsZAIJAGUCBSBfbGF0ZXN0Q3VtdWxhdGl2ZVByZW1pdW1GcmFjdGlvbgUlX29sZFBvc2l0aW9uQ3VtdWxhdGl2ZVByZW1pdW1GcmFjdGlvbgUQX29sZFBvc2l0aW9uU2l6ZQAABAtyb2xsb3ZlckZlZQkBD2NhbGNSb2xsb3ZlckZlZQIFEl9vbGRQb3NpdGlvbk1hcmdpbgUgX29sZFBvc2l0aW9uTGFzdFVwZGF0ZWRUaW1lc3RhbXAEDHNpZ25lZE1hcmdpbgkAZAIJAGUCCQBlAgUMX21hcmdpbkRlbHRhBQtyb2xsb3ZlckZlZQUOZnVuZGluZ1BheW1lbnQFEl9vbGRQb3NpdGlvbk1hcmdpbgQNJHQwMTk0MjcxOTU1NAMJAGYCAAAFDHNpZ25lZE1hcmdpbgkAlAoCAAAJAQNhYnMBBQxzaWduZWRNYXJnaW4JAJQKAgkBA2FicwEFDHNpZ25lZE1hcmdpbgAABAxyZW1haW5NYXJnaW4IBQ0kdDAxOTQyNzE5NTU0Al8xBAdiYWREZWJ0CAUNJHQwMTk0MjcxOTU1NAJfMgkAlgoEBQxyZW1haW5NYXJnaW4FB2JhZERlYnQFDmZ1bmRpbmdQYXltZW50BQtyb2xsb3ZlckZlZQEWc3dhcE91dHB1dFdpdGhSZXNlcnZlcwcGX2lzQWRkEF9iYXNlQXNzZXRBbW91bnQUX2NoZWNrTWF4UHJpY2VJbXBhY3QSX3F1b3RlQXNzZXRSZXNlcnZlEV9xdW90ZUFzc2V0V2VpZ2h0EV9iYXNlQXNzZXRSZXNlcnZlEF9iYXNlQXNzZXRXZWlnaHQEC3ByaWNlQmVmb3JlCQEEZGl2ZAIJAQRtdWxkAgUSX3F1b3RlQXNzZXRSZXNlcnZlBRFfcXVvdGVBc3NldFdlaWdodAkBBG11bGQCBRFfYmFzZUFzc2V0UmVzZXJ2ZQUQX2Jhc2VBc3NldFdlaWdodAMJAAACBRBfYmFzZUFzc2V0QW1vdW50AAAJAAIBAhlJbnZhbGlkIGJhc2UgYXNzZXQgYW1vdW50BAFrCQENY2FsY0ludmFyaWFudAIFEl9xdW90ZUFzc2V0UmVzZXJ2ZQURX2Jhc2VBc3NldFJlc2VydmUEGGJhc2VBc3NldFBvb2xBbW91bnRBZnRlcgMFBl9pc0FkZAkAZAIFEV9iYXNlQXNzZXRSZXNlcnZlBRBfYmFzZUFzc2V0QW1vdW50CQBlAgURX2Jhc2VBc3NldFJlc2VydmUFEF9iYXNlQXNzZXRBbW91bnQED3F1b3RlQXNzZXRBZnRlcgkAoAMBCQEFYmRpdmQCBQFrCQC2AgEFGGJhc2VBc3NldFBvb2xBbW91bnRBZnRlcgQPcXVvdGVBc3NldERlbHRhCQEDYWJzAQkAZQIFD3F1b3RlQXNzZXRBZnRlcgUSX3F1b3RlQXNzZXRSZXNlcnZlBA5xdW90ZUFzc2V0U29sZAkBBG11bGQCBQ9xdW90ZUFzc2V0RGVsdGEFEV9xdW90ZUFzc2V0V2VpZ2h0BBNtYXhQcmljZUltcGFjdFZhbHVlCQEObWF4UHJpY2VJbXBhY3QABA0kdDAyMDgxNjIwOTc4CQENdXBkYXRlUmVzZXJ2ZQMJAQEhAQUGX2lzQWRkBQ9xdW90ZUFzc2V0RGVsdGEFEF9iYXNlQXNzZXRBbW91bnQEF3F1b3RlQXNzZXRSZXNlcnZlQWZ0ZXIxCAUNJHQwMjA4MTYyMDk3OAJfMQQWYmFzZUFzc2V0UmVzZXJ2ZUFmdGVyMQgFDSR0MDIwODE2MjA5NzgCXzIEF3RvdGFsUG9zaXRpb25TaXplQWZ0ZXIxCAUNJHQwMjA4MTYyMDk3OAJfMwQLbWFya2V0UHJpY2UJAQRkaXZkAgUOcXVvdGVBc3NldFNvbGQFEF9iYXNlQXNzZXRBbW91bnQECXByaWNlRGlmZgkBA2FicwEJAGUCBQtwcmljZUJlZm9yZQULbWFya2V0UHJpY2UEC3ByaWNlSW1wYWN0CQBlAgUMREVDSU1BTF9VTklUCQEEZGl2ZAIFC3ByaWNlQmVmb3JlCQBkAgULcHJpY2VCZWZvcmUFCXByaWNlRGlmZgMDCQBmAgULcHJpY2VJbXBhY3QFE21heFByaWNlSW1wYWN0VmFsdWUFFF9jaGVja01heFByaWNlSW1wYWN0BwkAAgEJAKwCAgkArAICCQCsAgIJAKwCAgkArAICCQCsAgIJAKwCAgkArAICCQCsAgIJAKwCAgkArAICCQCsAgIJAKwCAgINUHJpY2UgaW1wYWN0IAkApAMBBQtwcmljZUltcGFjdAIUID4gbWF4IHByaWNlIGltcGFjdCAJAKQDAQUTbWF4UHJpY2VJbXBhY3RWYWx1ZQIVIGJlZm9yZSBxdW90ZSBhc3NldDogCQCkAwEFEl9xdW90ZUFzc2V0UmVzZXJ2ZQIUIGJlZm9yZSBiYXNlIGFzc2V0OiAJAKQDAQURX2Jhc2VBc3NldFJlc2VydmUCICBiYXNlIGFzc2V0IGFtb3VudCB0byBleGNoYW5nZTogCQCkAwEFEF9iYXNlQXNzZXRBbW91bnQCDyBwcmljZSBiZWZvcmU6IAkApAMBBQtwcmljZUJlZm9yZQIPIG1hcmtldCBwcmljZTogCQCkAwEFC21hcmtldFByaWNlCQCZCgcFDnF1b3RlQXNzZXRTb2xkBRdxdW90ZUFzc2V0UmVzZXJ2ZUFmdGVyMQUWYmFzZUFzc2V0UmVzZXJ2ZUFmdGVyMQUXdG90YWxQb3NpdGlvblNpemVBZnRlcjEJAGUCCQEVdG90YWxMb25nUG9zaXRpb25TaXplAAMFBl9pc0FkZAkBA2FicwEFEF9iYXNlQXNzZXRBbW91bnQAAAkAZQIJARZ0b3RhbFNob3J0UG9zaXRpb25TaXplAAMJAQEhAQUGX2lzQWRkCQEDYWJzAQUQX2Jhc2VBc3NldEFtb3VudAAABQtwcmljZUltcGFjdAEKc3dhcE91dHB1dAMGX2lzQWRkEF9iYXNlQXNzZXRBbW91bnQUX2NoZWNrTWF4UHJpY2VJbXBhY3QJARZzd2FwT3V0cHV0V2l0aFJlc2VydmVzBwUGX2lzQWRkBRBfYmFzZUFzc2V0QW1vdW50BRRfY2hlY2tNYXhQcmljZUltcGFjdAkBBnF0QXN0UgAJAQZxdEFzdFcACQEGYnNBc3RSAAkBBmJzQXN0VwABE2dldE9yYWNsZVByaWNlVmFsdWUDBm9yYWNsZQhwcmljZUtleQhibG9ja0tleQQJbGFzdFZhbHVlCQETdmFsdWVPckVycm9yTWVzc2FnZQIJAJoIAgUGb3JhY2xlBQhwcmljZUtleQkArAICCQCsAgIJAKwCAgIiQ2FuIG5vdCBnZXQgb3JhY2xlIHByaWNlLiBPcmFjbGU6IAkApQgBBQZvcmFjbGUCBiBrZXk6IAUIcHJpY2VLZXkDCQECIT0CBQhibG9ja0tleQIABAxjdXJyZW50QmxvY2sFBmhlaWdodAQPbGFzdE9yYWNsZUJsb2NrCQETdmFsdWVPckVycm9yTWVzc2FnZQIJAJoIAgUGb3JhY2xlBQhibG9ja0tleQkArAICCQCsAgIJAKwCAgIiQ2FuIG5vdCBnZXQgb3JhY2xlIGJsb2NrLiBPcmFjbGU6IAkApQgBBQZvcmFjbGUCBiBrZXk6IAUIYmxvY2tLZXkDCQBmAgkAZQIFDGN1cnJlbnRCbG9jawUPbGFzdE9yYWNsZUJsb2NrCQEObWF4T3JhY2xlRGVsYXkACQACAQkArAICCQCsAgIJAKwCAgImT3JhY2xlIHN0YWxlIGRhdGEuIExhc3Qgb3JhY2xlIGJsb2NrOiAJAKQDAQUPbGFzdE9yYWNsZUJsb2NrAhAgY3VycmVudCBibG9jazogCQCkAwEFDGN1cnJlbnRCbG9jawUJbGFzdFZhbHVlBQlsYXN0VmFsdWUBDmdldE9yYWNsZVByaWNlAAQKYmFzZU9yYWNsZQkBE3ZhbHVlT3JFcnJvck1lc3NhZ2UCCQENZ2V0T3JhY2xlRGF0YQEFDGtfYmFzZU9yYWNsZQIZTm8gYmFzZSBhc3NldCBvcmFjbGUgZGF0YQQPYmFzZU9yYWNsZVByaWNlCQETZ2V0T3JhY2xlUHJpY2VWYWx1ZQMIBQpiYXNlT3JhY2xlAl8xCAUKYmFzZU9yYWNsZQJfMggFCmJhc2VPcmFjbGUCXzMEC3F1b3RlT3JhY2xlCQENZ2V0T3JhY2xlRGF0YQEFDWtfcXVvdGVPcmFjbGUEEHF1b3RlT3JhY2xlUHJpY2UDCQEJaXNEZWZpbmVkAQULcXVvdGVPcmFjbGUEDHF1b3RlT3JhY2xlVgkBBXZhbHVlAQULcXVvdGVPcmFjbGUJARNnZXRPcmFjbGVQcmljZVZhbHVlAwgFDHF1b3RlT3JhY2xlVgJfMQgFDHF1b3RlT3JhY2xlVgJfMggFDHF1b3RlT3JhY2xlVgJfMwUMREVDSU1BTF9VTklUCQEEZGl2ZAIFD2Jhc2VPcmFjbGVQcmljZQUQcXVvdGVPcmFjbGVQcmljZQEOaXNNYXJrZXRDbG9zZWQABApiYXNlT3JhY2xlCQETdmFsdWVPckVycm9yTWVzc2FnZQIJAQ1nZXRPcmFjbGVEYXRhAQUMa19iYXNlT3JhY2xlAhlObyBiYXNlIGFzc2V0IG9yYWNsZSBkYXRhBAZvcmFjbGUIBQpiYXNlT3JhY2xlAl8xBAdvcGVuS2V5CAUKYmFzZU9yYWNsZQJfNAMJAQIhPQIFB29wZW5LZXkCAAQGaXNPcGVuCQETdmFsdWVPckVycm9yTWVzc2FnZQIJAJsIAgUGb3JhY2xlBQdvcGVuS2V5CQCsAgIJAKwCAgkArAICAitDYW4gbm90IGdldCBvcmFjbGUgaXMgb3Blbi9jbG9zZWQuIE9yYWNsZTogCQClCAEFBm9yYWNsZQIGIGtleTogBQdvcGVuS2V5CQEBIQEFBmlzT3BlbgcBDGFic1ByaWNlRGlmZgUMX29yYWNsZVByaWNlEl9xdW90ZUFzc2V0UmVzZXJ2ZRFfYmFzZUFzc2V0UmVzZXJ2ZQdfcXRBc3RXB19ic0FzdFcECnByaWNlQWZ0ZXIJAQRkaXZkAgkBBG11bGQCBRJfcXVvdGVBc3NldFJlc2VydmUFB19xdEFzdFcJAQRtdWxkAgURX2Jhc2VBc3NldFJlc2VydmUFB19ic0FzdFcEDGF2ZXJhZ2VQcmljZQkBBGRpdmQCCQBkAgUMX29yYWNsZVByaWNlBQpwcmljZUFmdGVyCQBoAgACBQxERUNJTUFMX1VOSVQEDGFic1ByaWNlRGlmZgkBBGRpdmQCCQEDYWJzAQkAZQIFDF9vcmFjbGVQcmljZQUKcHJpY2VBZnRlcgUMYXZlcmFnZVByaWNlBQxhYnNQcmljZURpZmYBGXJlcXVpcmVOb3RPdmVyU3ByZWFkTGltaXQCEl9xdW90ZUFzc2V0UmVzZXJ2ZRFfYmFzZUFzc2V0UmVzZXJ2ZQQLb3JhY2xlUHJpY2UJAQ5nZXRPcmFjbGVQcmljZQAEB19xdEFzdFcJAQZxdEFzdFcABAdfYnNBc3RXCQEGYnNBc3RXAAQSYWJzUHJpY2VEaWZmQmVmb3JlCQEMYWJzUHJpY2VEaWZmBQULb3JhY2xlUHJpY2UJAQZxdEFzdFIACQEGYnNBc3RSAAUHX3F0QXN0VwUHX2JzQXN0VwQRYWJzUHJpY2VEaWZmQWZ0ZXIJAQxhYnNQcmljZURpZmYFBQtvcmFjbGVQcmljZQUSX3F1b3RlQXNzZXRSZXNlcnZlBRFfYmFzZUFzc2V0UmVzZXJ2ZQUHX3F0QXN0VwUHX2JzQXN0VwMDCQBmAgURYWJzUHJpY2VEaWZmQWZ0ZXIJAQ5tYXhQcmljZVNwcmVhZAAJAGYCBRFhYnNQcmljZURpZmZBZnRlcgUSYWJzUHJpY2VEaWZmQmVmb3JlBwkAAgEJAKwCAgkArAICCQCsAgICDVByaWNlIHNwcmVhZCAJAKQDAQURYWJzUHJpY2VEaWZmQWZ0ZXICFCA+IG1heCBwcmljZSBzcHJlYWQgCQCkAwEJAQ5tYXhQcmljZVNwcmVhZAAGAR1yZXF1aXJlTm90T3Zlck1heE9wZW5Ob3Rpb25hbAIRX2xvbmdPcGVuTm90aW9uYWwSX3Nob3J0T3Blbk5vdGlvbmFsBBBfbWF4T3Blbk5vdGlvbmFsCQEPbWF4T3Blbk5vdGlvbmFsAAMJAGYCBRFfbG9uZ09wZW5Ob3Rpb25hbAUQX21heE9wZW5Ob3Rpb25hbAkAAgEJAKwCAgkArAICCQCsAgICE0xvbmcgb3BlbiBub3Rpb25hbCAJAKQDAQURX2xvbmdPcGVuTm90aW9uYWwCFSA+IG1heCBvcGVuIG5vdGlvbmFsIAkApAMBBRBfbWF4T3Blbk5vdGlvbmFsAwkAZgIFEl9zaG9ydE9wZW5Ob3Rpb25hbAUQX21heE9wZW5Ob3Rpb25hbAkAAgEJAKwCAgkArAICCQCsAgICFFNob3J0IG9wZW4gbm90aW9uYWwgCQCkAwEFEl9zaG9ydE9wZW5Ob3Rpb25hbAIVID4gbWF4IG9wZW4gbm90aW9uYWwgCQCkAwEFEF9tYXhPcGVuTm90aW9uYWwGASFyZXF1aXJlU2VuZGVyQ2FuV29ya1dpdGhQb3NpdGlvbnMBB19jYWxsZXIDCQAAAgkBDHBvc2l0aW9uTW9kZQAFDlBPU0lUSU9OX09SREVSCQAAAgUHX2NhbGxlcgkBDW9yZGVyc0FkZHJlc3MABgEMZ2V0U3BvdFByaWNlAAQSX3F1b3RlQXNzZXRSZXNlcnZlCQEGcXRBc3RSAAQRX2Jhc2VBc3NldFJlc2VydmUJAQZic0FzdFIABAdfcXRBc3RXCQEGcXRBc3RXAAQHX2JzQXN0VwkBBmJzQXN0VwAJAQRkaXZkAgkBBG11bGQCBRJfcXVvdGVBc3NldFJlc2VydmUFB19xdEFzdFcJAQRtdWxkAgURX2Jhc2VBc3NldFJlc2VydmUFB19ic0FzdFcBFmlzT3ZlckZsdWN0dWF0aW9uTGltaXQABAtvcmFjbGVQcmljZQkBDmdldE9yYWNsZVByaWNlAAQMY3VycmVudFByaWNlCQEMZ2V0U3BvdFByaWNlAAkAZgIJAQRkaXZkAgkBA2FicwEJAGUCBQtvcmFjbGVQcmljZQUMY3VycmVudFByaWNlBQtvcmFjbGVQcmljZQkBC3NwcmVhZExpbWl0AAEfZ2V0UG9zaXRpb25BZGp1c3RlZE9wZW5Ob3Rpb25hbAYNX3Bvc2l0aW9uU2l6ZQdfb3B0aW9uEl9xdW90ZUFzc2V0UmVzZXJ2ZRFfcXVvdGVBc3NldFdlaWdodBFfYmFzZUFzc2V0UmVzZXJ2ZRBfYmFzZUFzc2V0V2VpZ2h0BA9wb3NpdGlvblNpemVBYnMJAQNhYnMBBQ1fcG9zaXRpb25TaXplBAdpc1Nob3J0CQBmAgAABQ1fcG9zaXRpb25TaXplBBBwb3NpdGlvbk5vdGlvbmFsAwkAAAIFB19vcHRpb24FD1BOTF9PUFRJT05fU1BPVAQTb3V0UG9zaXRpb25Ob3Rpb25hbAgJARZzd2FwT3V0cHV0V2l0aFJlc2VydmVzBwkBASEBBQdpc1Nob3J0BQ9wb3NpdGlvblNpemVBYnMHBRJfcXVvdGVBc3NldFJlc2VydmUFEV9xdW90ZUFzc2V0V2VpZ2h0BRFfYmFzZUFzc2V0UmVzZXJ2ZQUQX2Jhc2VBc3NldFdlaWdodAJfMQUTb3V0UG9zaXRpb25Ob3Rpb25hbAkBBG11bGQCBQ9wb3NpdGlvblNpemVBYnMJAQ5nZXRPcmFjbGVQcmljZQAFEHBvc2l0aW9uTm90aW9uYWwBK2dldFBvc2l0aW9uTm90aW9uYWxBbmRVbnJlYWxpemVkUG5sQnlWYWx1ZXMHDV9wb3NpdGlvblNpemUVX3Bvc2l0aW9uT3Blbk5vdGlvbmFsEl9xdW90ZUFzc2V0UmVzZXJ2ZRFfcXVvdGVBc3NldFdlaWdodBFfYmFzZUFzc2V0UmVzZXJ2ZRBfYmFzZUFzc2V0V2VpZ2h0B19vcHRpb24DCQAAAgUNX3Bvc2l0aW9uU2l6ZQAACQACAQIVSW52YWxpZCBwb3NpdGlvbiBzaXplBAdpc1Nob3J0CQBmAgAABQ1fcG9zaXRpb25TaXplBBBwb3NpdGlvbk5vdGlvbmFsCQEfZ2V0UG9zaXRpb25BZGp1c3RlZE9wZW5Ob3Rpb25hbAYFDV9wb3NpdGlvblNpemUFB19vcHRpb24FEl9xdW90ZUFzc2V0UmVzZXJ2ZQURX3F1b3RlQXNzZXRXZWlnaHQFEV9iYXNlQXNzZXRSZXNlcnZlBRBfYmFzZUFzc2V0V2VpZ2h0BA11bnJlYWxpemVkUG5sAwUHaXNTaG9ydAkAZQIFFV9wb3NpdGlvbk9wZW5Ob3Rpb25hbAUQcG9zaXRpb25Ob3Rpb25hbAkAZQIFEHBvc2l0aW9uTm90aW9uYWwFFV9wb3NpdGlvbk9wZW5Ob3Rpb25hbAkAlAoCBRBwb3NpdGlvbk5vdGlvbmFsBQ11bnJlYWxpemVkUG5sASNnZXRQb3NpdGlvbk5vdGlvbmFsQW5kVW5yZWFsaXplZFBubAMHX3RyYWRlcgpfZGlyZWN0aW9uB19vcHRpb24EDSR0MDI5MTE5MjkyNTkJAQtnZXRQb3NpdGlvbgIFB190cmFkZXIFCl9kaXJlY3Rpb24EDHBvc2l0aW9uU2l6ZQgFDSR0MDI5MTE5MjkyNTkCXzEEDnBvc2l0aW9uTWFyZ2luCAUNJHQwMjkxMTkyOTI1OQJfMgQUcG9zaXRpb25PcGVuTm90aW9uYWwIBQ0kdDAyOTExOTI5MjU5Al8zBBFwb3NpdGlvbkxzdFVwZENQRggFDSR0MDI5MTE5MjkyNTkCXzQJAStnZXRQb3NpdGlvbk5vdGlvbmFsQW5kVW5yZWFsaXplZFBubEJ5VmFsdWVzBwUMcG9zaXRpb25TaXplBRRwb3NpdGlvbk9wZW5Ob3Rpb25hbAkBBnF0QXN0UgAJAQZxdEFzdFcACQEGYnNBc3RSAAkBBmJzQXN0VwAFB19vcHRpb24BD2NhbGNNYXJnaW5SYXRpbwMNX3JlbWFpbk1hcmdpbghfYmFkRGVidBFfcG9zaXRpb25Ob3Rpb25hbAkBBGRpdmQCCQBlAgUNX3JlbWFpbk1hcmdpbgUIX2JhZERlYnQFEV9wb3NpdGlvbk5vdGlvbmFsARZnZXRNYXJnaW5SYXRpb0J5T3B0aW9uAwdfdHJhZGVyCl9kaXJlY3Rpb24HX29wdGlvbgQNJHQwMjk3OTEyOTk0NAkBC2dldFBvc2l0aW9uAgUHX3RyYWRlcgUKX2RpcmVjdGlvbgQMcG9zaXRpb25TaXplCAUNJHQwMjk3OTEyOTk0NAJfMQQOcG9zaXRpb25NYXJnaW4IBQ0kdDAyOTc5MTI5OTQ0Al8yBANwb24IBQ0kdDAyOTc5MTI5OTQ0Al8zBBZwb3NpdGlvbkxhc3RVcGRhdGVkQ1BGCAUNJHQwMjk3OTEyOTk0NAJfNAQRcG9zaXRpb25UaW1lc3RhbXAIBQ0kdDAyOTc5MTI5OTQ0Al81BA0kdDAyOTk1MDMwMDU1CQEjZ2V0UG9zaXRpb25Ob3Rpb25hbEFuZFVucmVhbGl6ZWRQbmwDBQdfdHJhZGVyBQpfZGlyZWN0aW9uBQdfb3B0aW9uBBBwb3NpdGlvbk5vdGlvbmFsCAUNJHQwMjk5NTAzMDA1NQJfMQQNdW5yZWFsaXplZFBubAgFDSR0MDI5OTUwMzAwNTUCXzIEDSR0MDMwMDYwMzAyNzIJATBjYWxjUmVtYWluTWFyZ2luV2l0aEZ1bmRpbmdQYXltZW50QW5kUm9sbG92ZXJGZWUFBQxwb3NpdGlvblNpemUFDnBvc2l0aW9uTWFyZ2luBRZwb3NpdGlvbkxhc3RVcGRhdGVkQ1BGBRFwb3NpdGlvblRpbWVzdGFtcAUNdW5yZWFsaXplZFBubAQMcmVtYWluTWFyZ2luCAUNJHQwMzAwNjAzMDI3MgJfMQQHYmFkRGVidAgFDSR0MDMwMDYwMzAyNzICXzIJAQ9jYWxjTWFyZ2luUmF0aW8DBQxyZW1haW5NYXJnaW4FB2JhZERlYnQFEHBvc2l0aW9uTm90aW9uYWwBDmdldE1hcmdpblJhdGlvAgdfdHJhZGVyCl9kaXJlY3Rpb24JARZnZXRNYXJnaW5SYXRpb0J5T3B0aW9uAwUHX3RyYWRlcgUKX2RpcmVjdGlvbgUPUE5MX09QVElPTl9TUE9UARtnZXRQYXJ0aWFsTGlxdWlkYXRpb25BbW91bnQCB190cmFkZXINX3Bvc2l0aW9uU2l6ZQQMbWF4aW11bVJhdGlvCQEEdm1heAIJARdwYXJ0aWFsTGlxdWlkYXRpb25SYXRpbwAJAGUCBQxERUNJTUFMX1VOSVQJAQRkaXZkAgkBDmdldE1hcmdpblJhdGlvAgUHX3RyYWRlcgkBDGdldERpcmVjdGlvbgEFDV9wb3NpdGlvblNpemUJARZtYWludGVuYW5jZU1hcmdpblJhdGlvAAQYbWF4RXhjaGFuZ2VkUG9zaXRpb25TaXplCQEEbXVsZAIJAQNhYnMBBQ1fcG9zaXRpb25TaXplBQxtYXhpbXVtUmF0aW8ECnN3YXBSZXN1bHQJAQpzd2FwT3V0cHV0AwkAZgIFDV9wb3NpdGlvblNpemUAAAUYbWF4RXhjaGFuZ2VkUG9zaXRpb25TaXplBwQcbWF4RXhjaGFuZ2VkUXVvdGVBc3NldEFtb3VudAgFCnN3YXBSZXN1bHQCXzEEC3ByaWNlSW1wYWN0CAUKc3dhcFJlc3VsdAJfNwMJAGYCCQEObWF4UHJpY2VJbXBhY3QABQtwcmljZUltcGFjdAUYbWF4RXhjaGFuZ2VkUG9zaXRpb25TaXplCQEEbXVsZAIJAQNhYnMBBQ1fcG9zaXRpb25TaXplCQEXcGFydGlhbExpcXVpZGF0aW9uUmF0aW8AARVpbnRlcm5hbENsb3NlUG9zaXRpb24IB190cmFkZXIKX2RpcmVjdGlvbgVfc2l6ZQRfZmVlFF9taW5RdW90ZUFzc2V0QW1vdW50DF9hZGRUb01hcmdpbhRfY2hlY2tNYXhQcmljZUltcGFjdApfbGlxdWlkYXRlBA0kdDAzMTQzNTMxNjAzCQELZ2V0UG9zaXRpb24CBQdfdHJhZGVyBQpfZGlyZWN0aW9uBA9vbGRQb3NpdGlvblNpemUIBQ0kdDAzMTQzNTMxNjAzAl8xBBFvbGRQb3NpdGlvbk1hcmdpbggFDSR0MDMxNDM1MzE2MDMCXzIEF29sZFBvc2l0aW9uT3Blbk5vdGlvbmFsCAUNJHQwMzE0MzUzMTYwMwJfMwQUb2xkUG9zaXRpb25Mc3RVcGRDUEYIBQ0kdDAzMTQzNTMxNjAzAl80BBRvbGRQb3NpdGlvblRpbWVzdGFtcAgFDSR0MDMxNDM1MzE2MDMCXzUEDmlzTG9uZ1Bvc2l0aW9uCQBmAgUPb2xkUG9zaXRpb25TaXplAAAEEmFic09sZFBvc2l0aW9uU2l6ZQkBA2FicwEFD29sZFBvc2l0aW9uU2l6ZQMDCQBnAgUSYWJzT2xkUG9zaXRpb25TaXplBQVfc2l6ZQkAZgIFBV9zaXplAAAHBA5pc1BhcnRpYWxDbG9zZQkAZgIFEmFic09sZFBvc2l0aW9uU2l6ZQUFX3NpemUEDSR0MDMxODk1MzIzNDYJAQpzd2FwT3V0cHV0AwkAZgIFD29sZFBvc2l0aW9uU2l6ZQAABQVfc2l6ZQUUX2NoZWNrTWF4UHJpY2VJbXBhY3QEGWV4Y2hhbmdlZFF1b3RlQXNzZXRBbW91bnQIBQ0kdDAzMTg5NTMyMzQ2Al8xBBZxdW90ZUFzc2V0UmVzZXJ2ZUFmdGVyCAUNJHQwMzE4OTUzMjM0NgJfMgQVYmFzZUFzc2V0UmVzZXJ2ZUFmdGVyCAUNJHQwMzE4OTUzMjM0NgJfMwQWdG90YWxQb3NpdGlvblNpemVBZnRlcggFDSR0MDMxODk1MzIzNDYCXzQEFWV4Y2hhbmdlZFBvc2l0aW9uU2l6ZQMJAGYCBQ9vbGRQb3NpdGlvblNpemUAAAkBAS0BBQVfc2l6ZQUFX3NpemUEDSR0MDMyNTYxMzI3ODUJASNnZXRQb3NpdGlvbk5vdGlvbmFsQW5kVW5yZWFsaXplZFBubAMFB190cmFkZXIFCl9kaXJlY3Rpb24FD1BOTF9PUFRJT05fU1BPVAQTb2xkUG9zaXRpb25Ob3Rpb25hbAgFDSR0MDMyNTYxMzI3ODUCXzEEDXVucmVhbGl6ZWRQbmwIBQ0kdDAzMjU2MTMyNzg1Al8yBA1yZWFsaXplZFJhdGlvCQEEZGl2ZAIJAQNhYnMBBRVleGNoYW5nZWRQb3NpdGlvblNpemUFEmFic09sZFBvc2l0aW9uU2l6ZQQLcmVhbGl6ZWRQbmwJAQRtdWxkAgUNdW5yZWFsaXplZFBubAUNcmVhbGl6ZWRSYXRpbwQNJHQwMzMxMjYzMzM3MgkBMGNhbGNSZW1haW5NYXJnaW5XaXRoRnVuZGluZ1BheW1lbnRBbmRSb2xsb3ZlckZlZQUFD29sZFBvc2l0aW9uU2l6ZQURb2xkUG9zaXRpb25NYXJnaW4FFG9sZFBvc2l0aW9uTHN0VXBkQ1BGBRRvbGRQb3NpdGlvblRpbWVzdGFtcAUNdW5yZWFsaXplZFBubAQScmVtYWluTWFyZ2luQmVmb3JlCAUNJHQwMzMxMjYzMzM3MgJfMQQCeDEIBQ0kdDAzMzEyNjMzMzcyAl8yBAJ4MggFDSR0MDMzMTI2MzMzNzICXzMEC3JvbGxvdmVyRmVlCAUNJHQwMzMxMjYzMzM3MgJfNAQPcG9zaXRpb25CYWREZWJ0CAkBMGNhbGNSZW1haW5NYXJnaW5XaXRoRnVuZGluZ1BheW1lbnRBbmRSb2xsb3ZlckZlZQUFD29sZFBvc2l0aW9uU2l6ZQURb2xkUG9zaXRpb25NYXJnaW4FFG9sZFBvc2l0aW9uTHN0VXBkQ1BGBRRvbGRQb3NpdGlvblRpbWVzdGFtcAULcmVhbGl6ZWRQbmwCXzIEEHJlYWxpemVkQ2xvc2VGZWUJAQRtdWxkAgkBBG11bGQCBRNvbGRQb3NpdGlvbk5vdGlvbmFsBQ1yZWFsaXplZFJhdGlvBQRfZmVlBBJ1bnJlYWxpemVkUG5sQWZ0ZXIJAGUCBQ11bnJlYWxpemVkUG5sBQtyZWFsaXplZFBubAQScmVtYWluT3Blbk5vdGlvbmFsAwkAZgIFD29sZFBvc2l0aW9uU2l6ZQAACQBlAgkAZQIFE29sZFBvc2l0aW9uTm90aW9uYWwFGWV4Y2hhbmdlZFF1b3RlQXNzZXRBbW91bnQFEnVucmVhbGl6ZWRQbmxBZnRlcgkAZQIJAGQCBRJ1bnJlYWxpemVkUG5sQWZ0ZXIFE29sZFBvc2l0aW9uTm90aW9uYWwFGWV4Y2hhbmdlZFF1b3RlQXNzZXRBbW91bnQED25ld1Bvc2l0aW9uU2l6ZQkAZAIFD29sZFBvc2l0aW9uU2l6ZQUVZXhjaGFuZ2VkUG9zaXRpb25TaXplBA0kdDAzNDc3ODM1MTY0AwkAAAIFD25ld1Bvc2l0aW9uU2l6ZQAACQCUCgIAAAAACQCUCgIJAQNhYnMBBRJyZW1haW5PcGVuTm90aW9uYWwJAR9sYXRlc3RDdW11bGF0aXZlUHJlbWl1bUZyYWN0aW9uAQUPbmV3UG9zaXRpb25TaXplBBduZXdQb3NpdGlvbk9wZW5Ob3Rpb25hbAgFDSR0MDM0Nzc4MzUxNjQCXzEEFG5ld1Bvc2l0aW9uTHN0VXBkQ1BGCAUNJHQwMzQ3NzgzNTE2NAJfMgQRb3Blbk5vdGlvbmFsRGVsdGEJAGUCBRdvbGRQb3NpdGlvbk9wZW5Ob3Rpb25hbAUXbmV3UG9zaXRpb25PcGVuTm90aW9uYWwEC21hcmdpblJhdGlvCQEWZ2V0TWFyZ2luUmF0aW9CeU9wdGlvbgMFB190cmFkZXIFCl9kaXJlY3Rpb24FD1BOTF9PUFRJT05fU1BPVAQebmV3UG9zaXRpb25NYXJnaW5XaXRoU2FtZVJhdGlvAwkAZgIFD29sZFBvc2l0aW9uU2l6ZQAACQBlAgkBBG11bGQCCQBkAgUXbmV3UG9zaXRpb25PcGVuTm90aW9uYWwFEnVucmVhbGl6ZWRQbmxBZnRlcgULbWFyZ2luUmF0aW8FEnVucmVhbGl6ZWRQbmxBZnRlcgkAZQIJAQRtdWxkAgkAZQIFF25ld1Bvc2l0aW9uT3Blbk5vdGlvbmFsBRJ1bnJlYWxpemVkUG5sQWZ0ZXIFC21hcmdpblJhdGlvBRJ1bnJlYWxpemVkUG5sQWZ0ZXIEEW1hcmdpblRvVHJhZGVyUmF3CQBlAgkAZQIFEnJlbWFpbk1hcmdpbkJlZm9yZQkAZAIFHm5ld1Bvc2l0aW9uTWFyZ2luV2l0aFNhbWVSYXRpbwUSdW5yZWFsaXplZFBubEFmdGVyBRByZWFsaXplZENsb3NlRmVlBA5tYXJnaW5Ub1RyYWRlcgMJAGYCAAAFEW1hcmdpblRvVHJhZGVyUmF3AwUKX2xpcXVpZGF0ZQAACQACAQI3SW52YWxpZCBpbnRlcm5hbENsb3NlUG9zaXRpb24gcGFyYW1zOiB1bmFibGUgdG8gcGF5IGZlZQURbWFyZ2luVG9UcmFkZXJSYXcEEW5ld1Bvc2l0aW9uTWFyZ2luAwUMX2FkZFRvTWFyZ2luCQBkAgUebmV3UG9zaXRpb25NYXJnaW5XaXRoU2FtZVJhdGlvBQ5tYXJnaW5Ub1RyYWRlcgUebmV3UG9zaXRpb25NYXJnaW5XaXRoU2FtZVJhdGlvAwMJAQIhPQIFFF9taW5RdW90ZUFzc2V0QW1vdW50AAAJAGYCBRRfbWluUXVvdGVBc3NldEFtb3VudAUZZXhjaGFuZ2VkUXVvdGVBc3NldEFtb3VudAcJAAIBCQCsAgIJAKwCAgkArAICAg1MaW1pdCBlcnJvcjogCQCkAwEFGWV4Y2hhbmdlZFF1b3RlQXNzZXRBbW91bnQCAyA8IAkApAMBBRRfbWluUXVvdGVBc3NldEFtb3VudAkAowoRBQ9uZXdQb3NpdGlvblNpemUFEW5ld1Bvc2l0aW9uTWFyZ2luBRduZXdQb3NpdGlvbk9wZW5Ob3Rpb25hbAUUbmV3UG9zaXRpb25Mc3RVcGRDUEYFD3Bvc2l0aW9uQmFkRGVidAULcmVhbGl6ZWRQbmwDAwUMX2FkZFRvTWFyZ2luBQ5pc1BhcnRpYWxDbG9zZQcAAAUObWFyZ2luVG9UcmFkZXIFFnF1b3RlQXNzZXRSZXNlcnZlQWZ0ZXIFFWJhc2VBc3NldFJlc2VydmVBZnRlcgUWdG90YWxQb3NpdGlvblNpemVBZnRlcgkAZQIJARRvcGVuSW50ZXJlc3ROb3Rpb25hbAAFEW9wZW5Ob3Rpb25hbERlbHRhCQBlAgkBFXRvdGFsTG9uZ1Bvc2l0aW9uU2l6ZQADBQ5pc0xvbmdQb3NpdGlvbgkBA2FicwEFFWV4Y2hhbmdlZFBvc2l0aW9uU2l6ZQAACQBlAgkBFnRvdGFsU2hvcnRQb3NpdGlvblNpemUAAwkBASEBBQ5pc0xvbmdQb3NpdGlvbgkBA2FicwEFFWV4Y2hhbmdlZFBvc2l0aW9uU2l6ZQAACQBlAgkBEG9wZW5JbnRlcmVzdExvbmcAAwUOaXNMb25nUG9zaXRpb24FEW9wZW5Ob3Rpb25hbERlbHRhAAAJAGUCCQERb3BlbkludGVyZXN0U2hvcnQAAwkBASEBBQ5pc0xvbmdQb3NpdGlvbgURb3Blbk5vdGlvbmFsRGVsdGEAAAkAZAIFEHJlYWxpemVkQ2xvc2VGZWUFC3JvbGxvdmVyRmVlBRlleGNoYW5nZWRRdW90ZUFzc2V0QW1vdW50CQACAQkArAICCQCsAgIJAKwCAgI9SW52YWxpZCBpbnRlcm5hbENsb3NlUG9zaXRpb24gcGFyYW1zOiBpbnZhbGlkIHBvc2l0aW9uIHNpemU6IAkApAMBBQVfc2l6ZQIGIG1heDogCQCkAwEFEmFic09sZFBvc2l0aW9uU2l6ZQETZ2V0VGVybWluYWxBbW1TdGF0ZQAEDV9wb3NpdGlvblNpemUJARF0b3RhbFBvc2l0aW9uU2l6ZQADCQAAAgUNX3Bvc2l0aW9uU2l6ZQAACQCUCgIJAQZxdEFzdFIACQEGYnNBc3RSAAQJZGlyZWN0aW9uCQBmAgUNX3Bvc2l0aW9uU2l6ZQAABA0kdDAzODQxMTM4NTkwCQEKc3dhcE91dHB1dAMFCWRpcmVjdGlvbgkBA2FicwEFDV9wb3NpdGlvblNpemUHBBVjdXJyZW50TmV0TWFya2V0VmFsdWUIBQ0kdDAzODQxMTM4NTkwAl8xBBl0ZXJtaW5hbFF1b3RlQXNzZXRSZXNlcnZlCAUNJHQwMzg0MTEzODU5MAJfMgQYdGVybWluYWxCYXNlQXNzZXRSZXNlcnZlCAUNJHQwMzg0MTEzODU5MAJfMwkAlAoCBRl0ZXJtaW5hbFF1b3RlQXNzZXRSZXNlcnZlBRh0ZXJtaW5hbEJhc2VBc3NldFJlc2VydmUBE2dldFF1b3RlQXNzZXRXZWlnaHQEEGJhc2VBc3NldFJlc2VydmURdG90YWxQb3NpdGlvblNpemURcXVvdGVBc3NldFJlc2VydmULdGFyZ2V0UHJpY2UEAWIJALYCAQUQYmFzZUFzc2V0UmVzZXJ2ZQQCc3oJALYCAQURdG90YWxQb3NpdGlvblNpemUEAXEJALYCAQURcXVvdGVBc3NldFJlc2VydmUEAXAJALYCAQULdGFyZ2V0UHJpY2UEAWsJAQVibXVsZAIFAXEFAWIEBG5ld0IJALcCAgUBYgUCc3oEBG5ld1EJAQViZGl2ZAIFAWsFBG5ld0IEAXoJAQViZGl2ZAIFBG5ld1EFBG5ld0IEBnJlc3VsdAkBBWJkaXZkAgUBcAUBegkAoAMBBQZyZXN1bHQBFGdldFN5bmNUZXJtaW5hbFByaWNlAw5fdGVybWluYWxQcmljZQdfcXRBc3RSB19ic0FzdFIEDV9wb3NpdGlvblNpemUJARF0b3RhbFBvc2l0aW9uU2l6ZQADCQAAAgUNX3Bvc2l0aW9uU2l6ZQAABAluZXdRdEFzdFcJAQRkaXZkAgkBBG11bGQCBQ5fdGVybWluYWxQcmljZQUHX2JzQXN0UgUHX3F0QXN0UgkAlQoDBQluZXdRdEFzdFcFDERFQ0lNQUxfVU5JVAAABAlkaXJlY3Rpb24JAGYCBQ1fcG9zaXRpb25TaXplAAAEFWN1cnJlbnROZXRNYXJrZXRWYWx1ZQgJAQpzd2FwT3V0cHV0AwUJZGlyZWN0aW9uCQEDYWJzAQUNX3Bvc2l0aW9uU2l6ZQcCXzEECW5ld1F0QXN0VwkBE2dldFF1b3RlQXNzZXRXZWlnaHQEBQdfYnNBc3RSBQ1fcG9zaXRpb25TaXplBQdfcXRBc3RSBQ5fdGVybWluYWxQcmljZQQJbmV3QnNBc3RXBQxERUNJTUFMX1VOSVQEDW1hcmdpblRvVmF1bHQICQErZ2V0UG9zaXRpb25Ob3Rpb25hbEFuZFVucmVhbGl6ZWRQbmxCeVZhbHVlcwcFDV9wb3NpdGlvblNpemUFFWN1cnJlbnROZXRNYXJrZXRWYWx1ZQUHX3F0QXN0UgUJbmV3UXRBc3RXBQdfYnNBc3RSBQluZXdCc0FzdFcFD1BOTF9PUFRJT05fU1BPVAJfMgkAlQoDBQluZXdRdEFzdFcFCW5ld0JzQXN0VwUNbWFyZ2luVG9WYXVsdAEKZ2V0RnVuZGluZwAED3VuZGVybHlpbmdQcmljZQkBDmdldE9yYWNsZVByaWNlAAQJc3BvdFByaWNlCQEMZ2V0U3BvdFByaWNlAAQHcHJlbWl1bQkAZQIFCXNwb3RQcmljZQUPdW5kZXJseWluZ1ByaWNlAwMJAQ5pc01hcmtldENsb3NlZAAGAwkAAAIJAQtmdW5kaW5nTW9kZQAFEkZVTkRJTkdfQVNZTU1FVFJJQwMJAAACCQEWdG90YWxTaG9ydFBvc2l0aW9uU2l6ZQAAAAYJAAACCQEVdG90YWxMb25nUG9zaXRpb25TaXplAAAABwkAlQoDAAAAAAAAAwkAZgIAAAUHcHJlbWl1bQQUc2hvcnRQcmVtaXVtRnJhY3Rpb24JAQRkaXZkAgkBBG11bGQCBQdwcmVtaXVtCQEUZnVuZGluZ1BlcmlvZERlY2ltYWwABQdPTkVfREFZAwkAAAIJAQtmdW5kaW5nTW9kZQAFEkZVTkRJTkdfQVNZTU1FVFJJQwQTbG9uZ1ByZW1pdW1GcmFjdGlvbgkBBGRpdmQCCQEEbXVsZAIFFHNob3J0UHJlbWl1bUZyYWN0aW9uCQEWdG90YWxTaG9ydFBvc2l0aW9uU2l6ZQAJARV0b3RhbExvbmdQb3NpdGlvblNpemUACQCVCgMFFHNob3J0UHJlbWl1bUZyYWN0aW9uBRNsb25nUHJlbWl1bUZyYWN0aW9uAAAEGXNob3J0VG90YWxQcmVtaXVtRnJhY3Rpb24JAQNhYnMBCQEEbXVsZAIFFHNob3J0UHJlbWl1bUZyYWN0aW9uCQEWdG90YWxTaG9ydFBvc2l0aW9uU2l6ZQAEGGxvbmdUb3RhbFByZW1pdW1GcmFjdGlvbgkBA2FicwEJAQRtdWxkAgUUc2hvcnRQcmVtaXVtRnJhY3Rpb24JARV0b3RhbExvbmdQb3NpdGlvblNpemUABA5wcmVtaXVtVG9WYXVsdAkAZQIFGXNob3J0VG90YWxQcmVtaXVtRnJhY3Rpb24FGGxvbmdUb3RhbFByZW1pdW1GcmFjdGlvbgkAlQoDBRRzaG9ydFByZW1pdW1GcmFjdGlvbgUUc2hvcnRQcmVtaXVtRnJhY3Rpb24FDnByZW1pdW1Ub1ZhdWx0BBNsb25nUHJlbWl1bUZyYWN0aW9uCQEEZGl2ZAIJAQRtdWxkAgUHcHJlbWl1bQkBFGZ1bmRpbmdQZXJpb2REZWNpbWFsAAUHT05FX0RBWQMJAAACCQELZnVuZGluZ01vZGUABRJGVU5ESU5HX0FTWU1NRVRSSUMEFHNob3J0UHJlbWl1bUZyYWN0aW9uCQEEZGl2ZAIJAQRtdWxkAgUTbG9uZ1ByZW1pdW1GcmFjdGlvbgkBFXRvdGFsTG9uZ1Bvc2l0aW9uU2l6ZQAJARZ0b3RhbFNob3J0UG9zaXRpb25TaXplAAkAlQoDBRRzaG9ydFByZW1pdW1GcmFjdGlvbgUTbG9uZ1ByZW1pdW1GcmFjdGlvbgAABBhsb25nVG90YWxQcmVtaXVtRnJhY3Rpb24JAQNhYnMBCQEEbXVsZAIFE2xvbmdQcmVtaXVtRnJhY3Rpb24JARV0b3RhbExvbmdQb3NpdGlvblNpemUABBlzaG9ydFRvdGFsUHJlbWl1bUZyYWN0aW9uCQEDYWJzAQkBBG11bGQCBRNsb25nUHJlbWl1bUZyYWN0aW9uCQEWdG90YWxTaG9ydFBvc2l0aW9uU2l6ZQAEDnByZW1pdW1Ub1ZhdWx0CQBlAgUYbG9uZ1RvdGFsUHJlbWl1bUZyYWN0aW9uBRlzaG9ydFRvdGFsUHJlbWl1bUZyYWN0aW9uCQCVCgMFE2xvbmdQcmVtaXVtRnJhY3Rpb24FE2xvbmdQcmVtaXVtRnJhY3Rpb24FDnByZW1pdW1Ub1ZhdWx0AQ5nZXRBZGp1c3RlZEZlZQILX2FydGlmYWN0SWQQX2Jhc2VGZWVEaXNjb3VudAQKYmFzZUZlZVJhdwkBA2ZlZQAEB2Jhc2VGZWUJAQRtdWxkAgUKYmFzZUZlZVJhdwUQX2Jhc2VGZWVEaXNjb3VudAQNJHQwNDMyNTQ0Mzc0OQMJAQIhPQIFC19hcnRpZmFjdElkAgAEDGFydGlmYWN0S2luZAkBBHN0ckECCQERbmZ0TWFuYWdlckFkZHJlc3MACQEOdG9Db21wb3NpdGVLZXkCBQxrX3Rva2VuX3R5cGUFC19hcnRpZmFjdElkAwkAAAIFDGFydGlmYWN0S2luZAUYRkVFX1JFRFVDVElPTl9UT0tFTl9UWVBFBAlyZWR1Y3Rpb24JAQRpbnRBAgkBEW5mdE1hbmFnZXJBZGRyZXNzAAkBDnRvQ29tcG9zaXRlS2V5AgUNa190b2tlbl9wYXJhbQULX2FydGlmYWN0SWQEC2FkanVzdGVkRmVlCQEEbXVsZAIFB2Jhc2VGZWUFCXJlZHVjdGlvbgkAlAoCBQthZGp1c3RlZEZlZQYJAAIBAhlJbnZhbGlkIGF0dGFjaGVkIGFydGlmYWN0CQCUCgIFB2Jhc2VGZWUHBAthZGp1c3RlZEZlZQgFDSR0MDQzMjU0NDM3NDkCXzEEDGJ1cm5BcnRpZmFjdAgFDSR0MDQzMjU0NDM3NDkCXzIJAJQKAgULYWRqdXN0ZWRGZWUFDGJ1cm5BcnRpZmFjdAEYZ2V0Rm9yVHJhZGVyV2l0aEFydGlmYWN0AgdfdHJhZGVyC19hcnRpZmFjdElkBBBkb0dldEZlZURpc2NvdW50CQD8BwQJAQxtaW5lckFkZHJlc3MAAhJjb21wdXRlRmVlRGlzY291bnQJAMwIAgUHX3RyYWRlcgUDbmlsBQNuaWwDCQAAAgUQZG9HZXRGZWVEaXNjb3VudAUQZG9HZXRGZWVEaXNjb3VudAQLZmVlRGlzY291bnQEByRtYXRjaDAFEGRvR2V0RmVlRGlzY291bnQDCQABAgUHJG1hdGNoMAIDSW50BAF4BQckbWF0Y2gwBQF4CQACAQIhSW52YWxpZCBjb21wdXRlRmVlRGlzY291bnQgcmVzdWx0BA0kdDA0NDA5NTQ0MTY5CQEOZ2V0QWRqdXN0ZWRGZWUCBQtfYXJ0aWZhY3RJZAULZmVlRGlzY291bnQEC2FkanVzdGVkRmVlCAUNJHQwNDQwOTU0NDE2OQJfMQQMYnVybkFydGlmYWN0CAUNJHQwNDQwOTU0NDE2OQJfMgkAlAoCBQthZGp1c3RlZEZlZQUMYnVybkFydGlmYWN0CQACAQIkU3RyaWN0IHZhbHVlIGlzIG5vdCBlcXVhbCB0byBpdHNlbGYuAQ1nZXRBcnRpZmFjdElkAQFpBAphcnRpZmFjdElkAwkAZgIJAJADAQgFAWkIcGF5bWVudHMAAQkA2AQBCQETdmFsdWVPckVycm9yTWVzc2FnZQIICQCRAwIIBQFpCHBheW1lbnRzAAEHYXNzZXRJZAISSW52YWxpZCBhcnRpZmFjdElkAgAFCmFydGlmYWN0SWQBDWRpc3RyaWJ1dGVGZWUBCl9mZWVBbW91bnQEDGZlZVRvU3Rha2VycwkBBG11bGQCBQpfZmVlQW1vdW50CQETZmVlVG9TdGFrZXJzUGVyY2VudAAECmZlZVRvVmF1bHQJAGUCBQpfZmVlQW1vdW50BQxmZWVUb1N0YWtlcnMJAJQKAgUMZmVlVG9TdGFrZXJzBQpmZWVUb1ZhdWx0AQ51cGRhdGVTZXR0aW5ncxEQX2luaXRNYXJnaW5SYXRpbwRfbW1yFF9saXF1aWRhdGlvbkZlZVJhdGlvDl9mdW5kaW5nUGVyaW9kBF9mZWUMX3NwcmVhZExpbWl0D19tYXhQcmljZUltcGFjdBhfcGFydGlhbExpcXVpZGF0aW9uUmF0aW8PX21heFByaWNlU3ByZWFkEF9tYXhPcGVuTm90aW9uYWwUX2ZlZVRvU3Rha2Vyc1BlcmNlbnQPX21heE9yYWNsZURlbGF5DF9yb2xsb3ZlckZlZQxfZnVuZGluZ01vZGULX29yYWNsZU1vZGUTX21pbkluaXRNYXJnaW5SYXRpbw1fcG9zaXRpb25Nb2RlCQDMCAIJAQxJbnRlZ2VyRW50cnkCBRFrX2luaXRNYXJnaW5SYXRpbwUQX2luaXRNYXJnaW5SYXRpbwkAzAgCCQEMSW50ZWdlckVudHJ5AgUUa19taW5Jbml0TWFyZ2luUmF0aW8FE19taW5Jbml0TWFyZ2luUmF0aW8JAMwIAgkBDEludGVnZXJFbnRyeQIFGGtfbWFpbnRlbmFuY2VNYXJnaW5SYXRpbwUEX21tcgkAzAgCCQEMSW50ZWdlckVudHJ5AgUVa19saXF1aWRhdGlvbkZlZVJhdGlvBRRfbGlxdWlkYXRpb25GZWVSYXRpbwkAzAgCCQEMSW50ZWdlckVudHJ5AgUPa19mdW5kaW5nUGVyaW9kBQ5fZnVuZGluZ1BlcmlvZAkAzAgCCQEMSW50ZWdlckVudHJ5AgUFa19mZWUFBF9mZWUJAMwIAgkBDEludGVnZXJFbnRyeQIFDWtfc3ByZWFkTGltaXQFDF9zcHJlYWRMaW1pdAkAzAgCCQEMSW50ZWdlckVudHJ5AgUQa19tYXhQcmljZUltcGFjdAUPX21heFByaWNlSW1wYWN0CQDMCAIJAQxJbnRlZ2VyRW50cnkCBRlrX3BhcnRpYWxMaXF1aWRhdGlvblJhdGlvBRhfcGFydGlhbExpcXVpZGF0aW9uUmF0aW8JAMwIAgkBDEludGVnZXJFbnRyeQIFEGtfbWF4UHJpY2VTcHJlYWQFD19tYXhQcmljZVNwcmVhZAkAzAgCCQEMSW50ZWdlckVudHJ5AgURa19tYXhPcGVuTm90aW9uYWwFEF9tYXhPcGVuTm90aW9uYWwJAMwIAgkBDEludGVnZXJFbnRyeQIFFWtfZmVlVG9TdGFrZXJzUGVyY2VudAUUX2ZlZVRvU3Rha2Vyc1BlcmNlbnQJAMwIAgkBDEludGVnZXJFbnRyeQIFEGtfbWF4T3JhY2xlRGVsYXkFD19tYXhPcmFjbGVEZWxheQkAzAgCCQEMSW50ZWdlckVudHJ5AgUNa19yb2xsb3ZlckZlZQUMX3JvbGxvdmVyRmVlCQDMCAIJAQxJbnRlZ2VyRW50cnkCBQ1rX2Z1bmRpbmdNb2RlBQxfZnVuZGluZ01vZGUJAMwIAgkBDEludGVnZXJFbnRyeQIFDGtfb3JhY2xlTW9kZQULX29yYWNsZU1vZGUJAMwIAgkBDEludGVnZXJFbnRyeQIFDmtfcG9zaXRpb25Nb2RlBQ1fcG9zaXRpb25Nb2RlBQNuaWwBDXVwZGF0ZUZ1bmRpbmcFEV9uZXh0RnVuZGluZ0Jsb2NrJF9sYXRlc3RMb25nQ3VtdWxhdGl2ZVByZW1pdW1GcmFjdGlvbiVfbGF0ZXN0U2hvcnRDdW11bGF0aXZlUHJlbWl1bUZyYWN0aW9uEF9sb25nRnVuZGluZ1JhdGURX3Nob3J0RnVuZGluZ1JhdGUJAMwIAgkBDEludGVnZXJFbnRyeQIFEmtfbmV4dEZ1bmRpbmdCbG9jawURX25leHRGdW5kaW5nQmxvY2sJAMwIAgkBDEludGVnZXJFbnRyeQIFJWtfbGF0ZXN0TG9uZ0N1bXVsYXRpdmVQcmVtaXVtRnJhY3Rpb24FJF9sYXRlc3RMb25nQ3VtdWxhdGl2ZVByZW1pdW1GcmFjdGlvbgkAzAgCCQEMSW50ZWdlckVudHJ5AgUma19sYXRlc3RTaG9ydEN1bXVsYXRpdmVQcmVtaXVtRnJhY3Rpb24FJV9sYXRlc3RTaG9ydEN1bXVsYXRpdmVQcmVtaXVtRnJhY3Rpb24JAMwIAgkBDEludGVnZXJFbnRyeQIFEWtfbG9uZ0Z1bmRpbmdSYXRlBRBfbG9uZ0Z1bmRpbmdSYXRlCQDMCAIJAQxJbnRlZ2VyRW50cnkCBRJrX3Nob3J0RnVuZGluZ1JhdGUFEV9zaG9ydEZ1bmRpbmdSYXRlBQNuaWwBH2luY3JlbWVudFBvc2l0aW9uU2VxdWVuY2VOdW1iZXIDDl9pc05ld1Bvc2l0aW9uB190cmFkZXIKX2RpcmVjdGlvbgQLcG9zaXRpb25LZXkJAKwCAgkArAICBQdfdHJhZGVyAgFfCQCkAwEFCl9kaXJlY3Rpb24DBQ5faXNOZXdQb3NpdGlvbgQPY3VycmVudFNlcXVlbmNlCQEMbGFzdFNlcXVlbmNlAAkAzAgCCQEMSW50ZWdlckVudHJ5AgkBDnRvQ29tcG9zaXRlS2V5AgUSa19wb3NpdGlvblNlcXVlbmNlBQtwb3NpdGlvbktleQkAZAIFD2N1cnJlbnRTZXF1ZW5jZQABCQDMCAIJAQxJbnRlZ2VyRW50cnkCBQprX3NlcXVlbmNlCQBkAgUPY3VycmVudFNlcXVlbmNlAAEFA25pbAUDbmlsARF1cGRhdGVQb3NpdGlvbkZlZQQOX2lzTmV3UG9zaXRpb24HX3RyYWRlcgpfZGlyZWN0aW9uBF9mZWUEC3Bvc2l0aW9uS2V5CQCsAgIJAKwCAgUHX3RyYWRlcgIBXwkApAMBBQpfZGlyZWN0aW9uAwUOX2lzTmV3UG9zaXRpb24JAMwIAgkBDEludGVnZXJFbnRyeQIJAQ50b0NvbXBvc2l0ZUtleQIFDWtfcG9zaXRpb25GZWUFC3Bvc2l0aW9uS2V5BQRfZmVlBQNuaWwFA25pbAEOdXBkYXRlUG9zaXRpb24GB190cmFkZXIFX3NpemUHX21hcmdpbg1fb3Blbk5vdGlvbmFsIF9sYXRlc3RDdW11bGF0aXZlUHJlbWl1bUZyYWN0aW9uEF9sYXRlc3RUaW1lc3RhbXAECWRpcmVjdGlvbgkBDGdldERpcmVjdGlvbgEFBV9zaXplBAtwb3NpdGlvbktleQkArAICCQCsAgIFB190cmFkZXICAV8JAKQDAQUJZGlyZWN0aW9uCQDMCAIJAQxJbnRlZ2VyRW50cnkCCQEOdG9Db21wb3NpdGVLZXkCBQ5rX3Bvc2l0aW9uU2l6ZQULcG9zaXRpb25LZXkFBV9zaXplCQDMCAIJAQxJbnRlZ2VyRW50cnkCCQEOdG9Db21wb3NpdGVLZXkCBRBrX3Bvc2l0aW9uTWFyZ2luBQtwb3NpdGlvbktleQUHX21hcmdpbgkAzAgCCQEMSW50ZWdlckVudHJ5AgkBDnRvQ29tcG9zaXRlS2V5AgUWa19wb3NpdGlvbk9wZW5Ob3Rpb25hbAULcG9zaXRpb25LZXkFDV9vcGVuTm90aW9uYWwJAMwIAgkBDEludGVnZXJFbnRyeQIJAQ50b0NvbXBvc2l0ZUtleQIFLmtfcG9zaXRpb25MYXN0VXBkYXRlZEN1bXVsYXRpdmVQcmVtaXVtRnJhY3Rpb24FC3Bvc2l0aW9uS2V5BSBfbGF0ZXN0Q3VtdWxhdGl2ZVByZW1pdW1GcmFjdGlvbgkAzAgCCQEMSW50ZWdlckVudHJ5AgkBDnRvQ29tcG9zaXRlS2V5AgUea19wb3NpdGlvbkxhc3RVcGRhdGVkVGltZXN0YW1wBQtwb3NpdGlvbktleQUQX2xhdGVzdFRpbWVzdGFtcAUDbmlsARF1cGRhdGVBbW1SZXNlcnZlcwIHX3F0QXN0UgdfYnNBc3RSAwMJAGYCAAAFB19xdEFzdFIGCQBmAgAABQdfYnNBc3RSCQACAQIhSW52YWxpZCBhbW91bnQgdG8gdXBkYXRlIHJlc2VydmVzAwMJAQIhPQIFB19xdEFzdFIJAQdxdEFzdFIwAAYJAQIhPQIFB19ic0FzdFIJAQdic0FzdFIwAAkAzAgCCQEMSW50ZWdlckVudHJ5AgUTa19xdW90ZUFzc2V0UmVzZXJ2ZQUHX3F0QXN0UgkAzAgCCQEMSW50ZWdlckVudHJ5AgUSa19iYXNlQXNzZXRSZXNlcnZlBQdfYnNBc3RSBQNuaWwFA25pbAEQdXBkYXRlQW1tV2VpZ2h0cwIHX3F0QXN0VwdfYnNBc3RXAwMJAQIhPQIFB19xdEFzdFcJAQZxdEFzdFcABgkBAiE9AgUHX2JzQXN0VwkBBmJzQXN0VwAJAMwIAgkBDEludGVnZXJFbnRyeQIFEmtfcXVvdGVBc3NldFdlaWdodAUHX3F0QXN0VwkAzAgCCQEMSW50ZWdlckVudHJ5AgURa19iYXNlQXNzZXRXZWlnaHQFB19ic0FzdFcFA25pbAUDbmlsAQl1cGRhdGVBbW0IB19xdEFzdFIHX2JzQXN0UhdfdG90YWxQb3NpdGlvblNpemVBZnRlchVfb3BlbkludGVyZXN0Tm90aW9uYWwWX3RvdGFsTG9uZ1Bvc2l0aW9uU2l6ZRdfdG90YWxTaG9ydFBvc2l0aW9uU2l6ZRZfdG90YWxMb25nT3Blbk5vdGlvbmFsF190b3RhbFNob3J0T3Blbk5vdGlvbmFsBAdfcXRBc3RXCQEGcXRBc3RXAAQHX2JzQXN0VwkBBmJzQXN0VwADCQECIT0CCQBlAgUWX3RvdGFsTG9uZ1Bvc2l0aW9uU2l6ZQUXX3RvdGFsU2hvcnRQb3NpdGlvblNpemUFF190b3RhbFBvc2l0aW9uU2l6ZUFmdGVyCQACAQkArAICCQCsAgIJAKwCAgkArAICCQCsAgICGEludmFsaWQgQU1NIHN0YXRlIGRhdGE6IAkApAMBBRZfdG90YWxMb25nUG9zaXRpb25TaXplAgQgLSAgCQCkAwEFF190b3RhbFNob3J0UG9zaXRpb25TaXplAgQgIT0gCQCkAwEFF190b3RhbFBvc2l0aW9uU2l6ZUFmdGVyCQDOCAIJARF1cGRhdGVBbW1SZXNlcnZlcwIFB19xdEFzdFIFB19ic0FzdFIJAMwIAgkBDEludGVnZXJFbnRyeQIFE2tfdG90YWxQb3NpdGlvblNpemUFF190b3RhbFBvc2l0aW9uU2l6ZUFmdGVyCQDMCAIJAQxJbnRlZ2VyRW50cnkCBRZrX29wZW5JbnRlcmVzdE5vdGlvbmFsBRVfb3BlbkludGVyZXN0Tm90aW9uYWwJAMwIAgkBDEludGVnZXJFbnRyeQIFF2tfdG90YWxMb25nUG9zaXRpb25TaXplBRZfdG90YWxMb25nUG9zaXRpb25TaXplCQDMCAIJAQxJbnRlZ2VyRW50cnkCBRhrX3RvdGFsU2hvcnRQb3NpdGlvblNpemUFF190b3RhbFNob3J0UG9zaXRpb25TaXplCQDMCAIJAQxJbnRlZ2VyRW50cnkCBRJrX29wZW5JbnRlcmVzdExvbmcFFl90b3RhbExvbmdPcGVuTm90aW9uYWwJAMwIAgkBDEludGVnZXJFbnRyeQIFE2tfb3BlbkludGVyZXN0U2hvcnQFF190b3RhbFNob3J0T3Blbk5vdGlvbmFsBQNuaWwBDmRlbGV0ZVBvc2l0aW9uAgdfdHJhZGVyCl9kaXJlY3Rpb24EC3Bvc2l0aW9uS2V5CQCsAgIJAKwCAgUHX3RyYWRlcgIBXwkApAMBBQpfZGlyZWN0aW9uCQDMCAIJAQtEZWxldGVFbnRyeQEJAQ50b0NvbXBvc2l0ZUtleQIFDmtfcG9zaXRpb25TaXplBQtwb3NpdGlvbktleQkAzAgCCQELRGVsZXRlRW50cnkBCQEOdG9Db21wb3NpdGVLZXkCBRBrX3Bvc2l0aW9uTWFyZ2luBQtwb3NpdGlvbktleQkAzAgCCQELRGVsZXRlRW50cnkBCQEOdG9Db21wb3NpdGVLZXkCBRZrX3Bvc2l0aW9uT3Blbk5vdGlvbmFsBQtwb3NpdGlvbktleQkAzAgCCQELRGVsZXRlRW50cnkBCQEOdG9Db21wb3NpdGVLZXkCBS5rX3Bvc2l0aW9uTGFzdFVwZGF0ZWRDdW11bGF0aXZlUHJlbWl1bUZyYWN0aW9uBQtwb3NpdGlvbktleQkAzAgCCQELRGVsZXRlRW50cnkBCQEOdG9Db21wb3NpdGVLZXkCBQ1rX3Bvc2l0aW9uRmVlBQtwb3NpdGlvbktleQkAzAgCCQELRGVsZXRlRW50cnkBCQEOdG9Db21wb3NpdGVLZXkCBR5rX3Bvc2l0aW9uTGFzdFVwZGF0ZWRUaW1lc3RhbXAFC3Bvc2l0aW9uS2V5BQNuaWwBCHdpdGhkcmF3AghfYWRkcmVzcwdfYW1vdW50BAdiYWxhbmNlCQDwBwIFBHRoaXMJAQpxdW90ZUFzc2V0AAMJAGYCBQdfYW1vdW50BQdiYWxhbmNlCQACAQkArAICCQCsAgIJAKwCAgITVW5hYmxlIHRvIHdpdGhkcmF3IAkApAMBBQdfYW1vdW50AhcgZnJvbSBjb250cmFjdCBiYWxhbmNlIAkApAMBBQdiYWxhbmNlCQDMCAIJAQ5TY3JpcHRUcmFuc2ZlcgMFCF9hZGRyZXNzBQdfYW1vdW50CQEKcXVvdGVBc3NldAAFA25pbAENdXBkYXRlQmFsYW5jZQEIX2JhbGFuY2UDCQBmAgAABQhfYmFsYW5jZQkAAgECB0JhbGFuY2UDAwkAAAIJAQljYmFsYW5jZTAAAAAGCQECIT0CCQEJY2JhbGFuY2UwAAUIX2JhbGFuY2UJAMwIAgkBDEludGVnZXJFbnRyeQIFCWtfYmFsYW5jZQUIX2JhbGFuY2UFA25pbAUDbmlsAQt0cmFuc2ZlckZlZQEBaQkAzAgCCQEOU2NyaXB0VHJhbnNmZXIDCQEOc3Rha2luZ0FkZHJlc3MABQFpCQEKcXVvdGVBc3NldAAFA25pbAEOZG9CdXJuQXJ0aWZhY3QCDV9idXJuQXJ0aWZhY3QBaQMFDV9idXJuQXJ0aWZhY3QJAMwIAgkBBEJ1cm4CCQETdmFsdWVPckVycm9yTWVzc2FnZQIICQCRAwIIBQFpCHBheW1lbnRzAAEHYXNzZXRJZAIQSW52YWxpZCBhcnRpZmFjdAABBQNuaWwFA25pbBcBaQEFcGF1c2UAAwkBAiE9AggFAWkGY2FsbGVyCQEMYWRtaW5BZGRyZXNzAAkAAgECFEludmFsaWQgcGF1c2UgcGFyYW1zCQDMCAIJAQxCb29sZWFuRW50cnkCBQhrX3BhdXNlZAYFA25pbAFpAQd1bnBhdXNlAAMJAQIhPQIIBQFpBmNhbGxlcgkBDGFkbWluQWRkcmVzcwAJAAIBAhZJbnZhbGlkIHVucGF1c2UgcGFyYW1zCQDMCAIJAQxCb29sZWFuRW50cnkCBQhrX3BhdXNlZAcFA25pbAFpAQxzZXRDbG9zZU9ubHkAAwkBAiE9AggFAWkGY2FsbGVyCQEMYWRtaW5BZGRyZXNzAAkAAgECG0ludmFsaWQgc2V0Q2xvc2VPbmx5IHBhcmFtcwkAzAgCCQEMQm9vbGVhbkVudHJ5AgULa19jbG9zZU9ubHkGBQNuaWwBaQEOdW5zZXRDbG9zZU9ubHkAAwkBAiE9AggFAWkGY2FsbGVyCQEMYWRtaW5BZGRyZXNzAAkAAgECHUludmFsaWQgdW5zZXRDbG9zZU9ubHkgcGFyYW1zCQDMCAIJAQxCb29sZWFuRW50cnkCBQtrX2Nsb3NlT25seQcFA25pbAFpAQ9jaGFuZ2VMaXF1aWRpdHkBEV9xdW90ZUFzc2V0QW1vdW50AwMJAQIhPQIIBQFpBmNhbGxlcgkBDGFkbWluQWRkcmVzcwAGCQAAAgURX3F1b3RlQXNzZXRBbW91bnQAAAkAAgECHkludmFsaWQgY2hhbmdlTGlxdWlkaXR5IHBhcmFtcwQHX3F0QXN0UgkBBnF0QXN0UgAEB19ic0FzdFIJAQZic0FzdFIABAdfcXRBc3RXCQEGcXRBc3RXAAQHX2JzQXN0VwkBBmJzQXN0VwAEBXByaWNlCQEEZGl2ZAIJAQRtdWxkAgUHX3F0QXN0UgUHX3F0QXN0VwkBBG11bGQCBQdfYnNBc3RSBQdfYnNBc3RXBAtxdEFzdFJBZnRlcgkAZAIFB19xdEFzdFIFEV9xdW90ZUFzc2V0QW1vdW50BBRiYXNlQXNzZXRBbW91bnRUb0FkZAkAZQIJAQRkaXZkAgkBBG11bGQCBQtxdEFzdFJBZnRlcgUHX3F0QXN0VwUFcHJpY2UFB19ic0FzdFIEC2JzQXN0UkFmdGVyCQBkAgUHX2JzQXN0UgUUYmFzZUFzc2V0QW1vdW50VG9BZGQEDSR0MDUzMDU0NTMyMDUJARRnZXRTeW5jVGVybWluYWxQcmljZQMJAQ5nZXRPcmFjbGVQcmljZQAFC3F0QXN0UkFmdGVyBQtic0FzdFJBZnRlcgQTbmV3UXVvdGVBc3NldFdlaWdodAgFDSR0MDUzMDU0NTMyMDUCXzEEEm5ld0Jhc2VBc3NldFdlaWdodAgFDSR0MDUzMDU0NTMyMDUCXzIEDW1hcmdpblRvVmF1bHQIBQ0kdDA1MzA1NDUzMjA1Al8zBA1kb0V4Y2hhbmdlUG5MAwkBAiE9AgUNbWFyZ2luVG9WYXVsdAAABA1kb0V4Y2hhbmdlUG5MCQD8BwQJAQx2YXVsdEFkZHJlc3MAAhVleGNoYW5nZUZyZWVBbmRMb2NrZWQJAMwIAgUNbWFyZ2luVG9WYXVsdAUDbmlsBQNuaWwDCQAAAgUNZG9FeGNoYW5nZVBuTAUNZG9FeGNoYW5nZVBuTAUDbmlsCQACAQIkU3RyaWN0IHZhbHVlIGlzIG5vdCBlcXVhbCB0byBpdHNlbGYuBQNuaWwDCQAAAgUNZG9FeGNoYW5nZVBuTAUNZG9FeGNoYW5nZVBuTAkAzggCCQERdXBkYXRlQW1tUmVzZXJ2ZXMCBQtxdEFzdFJBZnRlcgULYnNBc3RSQWZ0ZXIJARB1cGRhdGVBbW1XZWlnaHRzAgUTbmV3UXVvdGVBc3NldFdlaWdodAUSbmV3QmFzZUFzc2V0V2VpZ2h0CQACAQIkU3RyaWN0IHZhbHVlIGlzIG5vdCBlcXVhbCB0byBpdHNlbGYuAWkBDmNoYW5nZVNldHRpbmdzExBfaW5pdE1hcmdpblJhdGlvBF9tbXIUX2xpcXVpZGF0aW9uRmVlUmF0aW8OX2Z1bmRpbmdQZXJpb2QEX2ZlZQxfc3ByZWFkTGltaXQPX21heFByaWNlSW1wYWN0GF9wYXJ0aWFsTGlxdWlkYXRpb25SYXRpbw9fbWF4UHJpY2VTcHJlYWQQX21heE9wZW5Ob3Rpb25hbBRfZmVlVG9TdGFrZXJzUGVyY2VudA9fbWF4T3JhY2xlRGVsYXkMX3JvbGxvdmVyRmVlDF9mdW5kaW5nTW9kZQtfb3JhY2xlTW9kZQ9fYmFzZU9yYWNsZURhdGEQX3F1b3RlT3JhY2xlRGF0YRNfbWluSW5pdE1hcmdpblJhdGlvDV9wb3NpdGlvbk1vZGUDAwMDAwMDAwMDAwMDAwMDAwMDAwMDCQBnAgAABQ5fZnVuZGluZ1BlcmlvZAYJAGcCAAAFEF9pbml0TWFyZ2luUmF0aW8GCQBmAgUQX2luaXRNYXJnaW5SYXRpbwUMREVDSU1BTF9VTklUBgkAZwIAAAUTX21pbkluaXRNYXJnaW5SYXRpbwYJAGYCBRBfaW5pdE1hcmdpblJhdGlvBRNfbWluSW5pdE1hcmdpblJhdGlvBgkAZwIAAAUEX21tcgYJAGcCAAAFFF9saXF1aWRhdGlvbkZlZVJhdGlvBgkAZwIAAAUEX2ZlZQYJAGcCAAAFDF9zcHJlYWRMaW1pdAYJAGcCAAAFD19tYXhQcmljZUltcGFjdAYJAGcCAAAFGF9wYXJ0aWFsTGlxdWlkYXRpb25SYXRpbwYJAGcCAAAFD19tYXhQcmljZVNwcmVhZAYJAGcCAAAFEF9tYXhPcGVuTm90aW9uYWwGCQBnAgAABRRfZmVlVG9TdGFrZXJzUGVyY2VudAYJAGYCBRRfZmVlVG9TdGFrZXJzUGVyY2VudAUMREVDSU1BTF9VTklUBgkAZgIAAAUPX21heE9yYWNsZURlbGF5BgkAZwIAAAUMX3JvbGxvdmVyRmVlBgMJAQIhPQIFDF9mdW5kaW5nTW9kZQURRlVORElOR19TWU1NRVRSSUMJAQIhPQIFDF9mdW5kaW5nTW9kZQUSRlVORElOR19BU1lNTUVUUklDBwYDCQECIT0CBQtfb3JhY2xlTW9kZQUMT1JBQ0xFX1BMQUlOCQECIT0CBQtfb3JhY2xlTW9kZQUKT1JBQ0xFX0pJVAcGAwkBAiE9AgUNX3Bvc2l0aW9uTW9kZQUPUE9TSVRJT05fRElSRUNUCQECIT0CBQ1fcG9zaXRpb25Nb2RlBQ5QT1NJVElPTl9PUkRFUgcGCQEBIQEJAQtpbml0aWFsaXplZAAGCQECIT0CCAUBaQZjYWxsZXIJAQxhZG1pbkFkZHJlc3MACQACAQIdSW52YWxpZCBjaGFuZ2VTZXR0aW5ncyBwYXJhbXMJAM4IAgkBDnVwZGF0ZVNldHRpbmdzEQUQX2luaXRNYXJnaW5SYXRpbwUEX21tcgUUX2xpcXVpZGF0aW9uRmVlUmF0aW8FDl9mdW5kaW5nUGVyaW9kBQRfZmVlBQxfc3ByZWFkTGltaXQFD19tYXhQcmljZUltcGFjdAUYX3BhcnRpYWxMaXF1aWRhdGlvblJhdGlvBQ9fbWF4UHJpY2VTcHJlYWQFEF9tYXhPcGVuTm90aW9uYWwFFF9mZWVUb1N0YWtlcnNQZXJjZW50BQ9fbWF4T3JhY2xlRGVsYXkFDF9yb2xsb3ZlckZlZQUMX2Z1bmRpbmdNb2RlBQtfb3JhY2xlTW9kZQUTX21pbkluaXRNYXJnaW5SYXRpbwUNX3Bvc2l0aW9uTW9kZQkAzAgCCQELU3RyaW5nRW50cnkCBQxrX2Jhc2VPcmFjbGUFD19iYXNlT3JhY2xlRGF0YQkAzAgCCQELU3RyaW5nRW50cnkCBQ1rX3F1b3RlT3JhY2xlBRBfcXVvdGVPcmFjbGVEYXRhBQNuaWwBaQEKaW5pdGlhbGl6ZRYHX3F0QXN0UgdfYnNBc3RSDl9mdW5kaW5nUGVyaW9kEF9pbml0TWFyZ2luUmF0aW8EX21tchRfbGlxdWlkYXRpb25GZWVSYXRpbwRfZmVlD19iYXNlT3JhY2xlRGF0YRBfcXVvdGVPcmFjbGVEYXRhDF9jb29yZGluYXRvcgxfc3ByZWFkTGltaXQPX21heFByaWNlSW1wYWN0GF9wYXJ0aWFsTGlxdWlkYXRpb25SYXRpbw9fbWF4UHJpY2VTcHJlYWQQX21heE9wZW5Ob3Rpb25hbBRfZmVlVG9TdGFrZXJzUGVyY2VudA9fbWF4T3JhY2xlRGVsYXkMX3JvbGxvdmVyRmVlDF9mdW5kaW5nTW9kZQtfb3JhY2xlTW9kZRNfbWluSW5pdE1hcmdpblJhdGlvDV9wb3NpdGlvbk1vZGUDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMJAGcCAAAFB19xdEFzdFIGCQBnAgAABQdfYnNBc3RSBgkAZwIAAAUOX2Z1bmRpbmdQZXJpb2QGCQBnAgAABRBfaW5pdE1hcmdpblJhdGlvBgkAZgIFEF9pbml0TWFyZ2luUmF0aW8FDERFQ0lNQUxfVU5JVAYJAGcCAAAFE19taW5Jbml0TWFyZ2luUmF0aW8GCQBmAgUQX2luaXRNYXJnaW5SYXRpbwUTX21pbkluaXRNYXJnaW5SYXRpbwYJAGcCAAAFBF9tbXIGCQBnAgAABRRfbGlxdWlkYXRpb25GZWVSYXRpbwYJAGcCAAAFBF9mZWUGCQBnAgAABQxfc3ByZWFkTGltaXQGCQBnAgAABQ9fbWF4UHJpY2VJbXBhY3QGCQBnAgAABRhfcGFydGlhbExpcXVpZGF0aW9uUmF0aW8GCQBnAgAABQ9fbWF4UHJpY2VTcHJlYWQGCQBnAgAABRBfbWF4T3Blbk5vdGlvbmFsBgkAZwIAAAUUX2ZlZVRvU3Rha2Vyc1BlcmNlbnQGCQBmAgUUX2ZlZVRvU3Rha2Vyc1BlcmNlbnQFDERFQ0lNQUxfVU5JVAYJAGYCAAAFD19tYXhPcmFjbGVEZWxheQYJAGcCAAAFDF9yb2xsb3ZlckZlZQYDCQECIT0CBQxfZnVuZGluZ01vZGUFEUZVTkRJTkdfU1lNTUVUUklDCQECIT0CBQxfZnVuZGluZ01vZGUFEkZVTkRJTkdfQVNZTU1FVFJJQwcGAwkBAiE9AgULX29yYWNsZU1vZGUFDE9SQUNMRV9QTEFJTgkBAiE9AgULX29yYWNsZU1vZGUFCk9SQUNMRV9KSVQHBgMJAQIhPQIFDV9wb3NpdGlvbk1vZGUFD1BPU0lUSU9OX0RJUkVDVAkBAiE9AgUNX3Bvc2l0aW9uTW9kZQUOUE9TSVRJT05fT1JERVIHBgkBC2luaXRpYWxpemVkAAYJAQIhPQIIBQFpBmNhbGxlcgUEdGhpcwkAAgECHUludmFsaWQgaW5pdGlhbGl6ZSBwYXJhbWV0ZXJzCQDOCAIJAM4IAgkAzggCCQDOCAIJAQl1cGRhdGVBbW0IBQdfcXRBc3RSBQdfYnNBc3RSAAAAAAAAAAAAAAAACQEOdXBkYXRlU2V0dGluZ3MRBRBfaW5pdE1hcmdpblJhdGlvBQRfbW1yBRRfbGlxdWlkYXRpb25GZWVSYXRpbwUOX2Z1bmRpbmdQZXJpb2QFBF9mZWUFDF9zcHJlYWRMaW1pdAUPX21heFByaWNlSW1wYWN0BRhfcGFydGlhbExpcXVpZGF0aW9uUmF0aW8FD19tYXhQcmljZVNwcmVhZAUQX21heE9wZW5Ob3Rpb25hbAUUX2ZlZVRvU3Rha2Vyc1BlcmNlbnQFD19tYXhPcmFjbGVEZWxheQUMX3JvbGxvdmVyRmVlBQxfZnVuZGluZ01vZGUFC19vcmFjbGVNb2RlBRNfbWluSW5pdE1hcmdpblJhdGlvBQ1fcG9zaXRpb25Nb2RlCQENdXBkYXRlRnVuZGluZwUJAGQCCQENbGFzdFRpbWVzdGFtcAAFDl9mdW5kaW5nUGVyaW9kAAAAAAAAAAAJAQ11cGRhdGVCYWxhbmNlAQAACQDMCAIJAQxCb29sZWFuRW50cnkCBQ1rX2luaXRpYWxpemVkBgkAzAgCCQELU3RyaW5nRW50cnkCBQxrX2Jhc2VPcmFjbGUFD19iYXNlT3JhY2xlRGF0YQkAzAgCCQELU3RyaW5nRW50cnkCBQ1rX3F1b3RlT3JhY2xlBRBfcXVvdGVPcmFjbGVEYXRhCQDMCAIJAQtTdHJpbmdFbnRyeQIFFGtfY29vcmRpbmF0b3JBZGRyZXNzCQClCAEJARFAZXh0ck5hdGl2ZSgxMDYyKQEFDF9jb29yZGluYXRvcgUDbmlsAWkBEGluY3JlYXNlUG9zaXRpb24FCl9kaXJlY3Rpb24JX2xldmVyYWdlE19taW5CYXNlQXNzZXRBbW91bnQIX3JlZkxpbmsMX3ByaWNlVXBkYXRlBAx1cGRhdGVPcmFjbGUJAPwHBAUEdGhpcwIMdXBkYXRlT3JhY2xlCQDMCAIFDF9wcmljZVVwZGF0ZQUDbmlsBQNuaWwDCQAAAgUMdXBkYXRlT3JhY2xlBQx1cGRhdGVPcmFjbGUEBHN5bmMJAPwHBAUEdGhpcwIZc3luY1Rlcm1pbmFsUHJpY2VUb09yYWNsZQUDbmlsBQNuaWwDCQAAAgUEc3luYwUEc3luYwQQZW5zdXJlQ2FsbGVkT25jZQkA/AcEBQR0aGlzAhBlbnN1cmVDYWxsZWRPbmNlBQNuaWwFA25pbAMJAAACBRBlbnN1cmVDYWxsZWRPbmNlBRBlbnN1cmVDYWxsZWRPbmNlBAdfdHJhZGVyCQEPZ2V0QWN0dWFsQ2FsbGVyAQUBaQQKX3Jhd0Ftb3VudAgJAJEDAggFAWkIcGF5bWVudHMAAAZhbW91bnQECF9hc3NldElkCAkAkQMCCAUBaQhwYXltZW50cwAAB2Fzc2V0SWQEC19hc3NldElkU3RyCQDYBAEJAQV2YWx1ZQEFCF9hc3NldElkBAxpc1F1b3RlQXNzZXQJAAACBQhfYXNzZXRJZAkBCnF1b3RlQXNzZXQAAwMDAwMDAwMDAwMJAQIhPQIFCl9kaXJlY3Rpb24FCERJUl9MT05HCQECIT0CBQpfZGlyZWN0aW9uBQlESVJfU0hPUlQHBgkAZwIAAAUKX3Jhd0Ftb3VudAYJAQEhAQkBC2luaXRpYWxpemVkAAYJAQEhAQUMaXNRdW90ZUFzc2V0BgkBASEBCQEWcmVxdWlyZU1vcmVNYXJnaW5SYXRpbwMJAQRkaXZkAgUMREVDSU1BTF9VTklUBQlfbGV2ZXJhZ2UJAQ9pbml0TWFyZ2luUmF0aW8ABgYJAQEhAQkBFnJlcXVpcmVNb3JlTWFyZ2luUmF0aW8DCQEEZGl2ZAIFDERFQ0lNQUxfVU5JVAUJX2xldmVyYWdlCQESbWluSW5pdE1hcmdpblJhdGlvAAcGCQEBIQEJASFyZXF1aXJlU2VuZGVyQ2FuV29ya1dpdGhQb3NpdGlvbnMBCAUBaQZjYWxsZXIGCQEGcGF1c2VkAAYJAQljbG9zZU9ubHkABgkBDmlzTWFya2V0Q2xvc2VkAAkAAgECI0ludmFsaWQgaW5jcmVhc2VQb3NpdGlvbiBwYXJhbWV0ZXJzBA0kdDA2MDQ2ODYwNjE3CQEYZ2V0Rm9yVHJhZGVyV2l0aEFydGlmYWN0AgUHX3RyYWRlcgkBDWdldEFydGlmYWN0SWQBBQFpBAthZGp1c3RlZEZlZQgFDSR0MDYwNDY4NjA2MTcCXzEEDGJ1cm5BcnRpZmFjdAgFDSR0MDYwNDY4NjA2MTcCXzIEB19hbW91bnQJAQRkaXZkAgUKX3Jhd0Ftb3VudAkAZAIJAQRtdWxkAgULYWRqdXN0ZWRGZWUFCV9sZXZlcmFnZQUMREVDSU1BTF9VTklUBBNkaXN0cmlidXRlRmVlQW1vdW50CQBlAgUKX3Jhd0Ftb3VudAUHX2Ftb3VudAQOcmVmZXJyZXJGZWVBbnkJAPwHBAkBD3JlZmVycmFsQWRkcmVzcwACFWFjY2VwdFBheW1lbnRXaXRoTGluawkAzAgCBQdfdHJhZGVyCQDMCAIFCF9yZWZMaW5rBQNuaWwJAMwIAgkBD0F0dGFjaGVkUGF5bWVudAIJAQpxdW90ZUFzc2V0AAUTZGlzdHJpYnV0ZUZlZUFtb3VudAUDbmlsAwkAAAIFDnJlZmVycmVyRmVlQW55BQ5yZWZlcnJlckZlZUFueQQLcmVmZXJyZXJGZWUEByRtYXRjaDAFDnJlZmVycmVyRmVlQW55AwkAAQIFByRtYXRjaDACA0ludAQBeAUHJG1hdGNoMAUBeAkAAgECE0ludmFsaWQgcmVmZXJyZXJGZWUECWZlZUFtb3VudAkAZQIFE2Rpc3RyaWJ1dGVGZWVBbW91bnQFC3JlZmVycmVyRmVlBA0kdDA2MTExMzYxMjkzCQELZ2V0UG9zaXRpb24CBQdfdHJhZGVyBQpfZGlyZWN0aW9uBA9vbGRQb3NpdGlvblNpemUIBQ0kdDA2MTExMzYxMjkzAl8xBBFvbGRQb3NpdGlvbk1hcmdpbggFDSR0MDYxMTEzNjEyOTMCXzIEF29sZFBvc2l0aW9uT3Blbk5vdGlvbmFsCAUNJHQwNjExMTM2MTI5MwJfMwQUb2xkUG9zaXRpb25Mc3RVcGRDUEYIBQ0kdDA2MTExMzYxMjkzAl80BBRvbGRQb3NpdGlvblRpbWVzdGFtcAgFDSR0MDYxMTEzNjEyOTMCXzUEDWlzTmV3UG9zaXRpb24JAAACBQ9vbGRQb3NpdGlvblNpemUAAAQPaXNTYW1lRGlyZWN0aW9uAwkAZgIFD29sZFBvc2l0aW9uU2l6ZQAACQAAAgUKX2RpcmVjdGlvbgUIRElSX0xPTkcJAAACBQpfZGlyZWN0aW9uBQlESVJfU0hPUlQEDmV4cGFuZEV4aXN0aW5nAwkBASEBBQ1pc05ld1Bvc2l0aW9uBQ9pc1NhbWVEaXJlY3Rpb24HBAVpc0FkZAkAAAIFCl9kaXJlY3Rpb24FCERJUl9MT05HBA0kdDA2MTU4MjY0NzE1AwMFDWlzTmV3UG9zaXRpb24GBQ5leHBhbmRFeGlzdGluZwQMb3Blbk5vdGlvbmFsCQEEbXVsZAIFB19hbW91bnQFCV9sZXZlcmFnZQQNJHQwNjIwOTE2MjI2NAkBCXN3YXBJbnB1dAIFBWlzQWRkBQxvcGVuTm90aW9uYWwEFWFtb3VudEJhc2VBc3NldEJvdWdodAgFDSR0MDYyMDkxNjIyNjQCXzEEFnF1b3RlQXNzZXRSZXNlcnZlQWZ0ZXIIBQ0kdDA2MjA5MTYyMjY0Al8yBBViYXNlQXNzZXRSZXNlcnZlQWZ0ZXIIBQ0kdDA2MjA5MTYyMjY0Al8zBBZ0b3RhbFBvc2l0aW9uU2l6ZUFmdGVyCAUNJHQwNjIwOTE2MjI2NAJfNAMDCQECIT0CBRNfbWluQmFzZUFzc2V0QW1vdW50AAAJAGYCBRNfbWluQmFzZUFzc2V0QW1vdW50CQEDYWJzAQUVYW1vdW50QmFzZUFzc2V0Qm91Z2h0BwkAAgEJAKwCAgkArAICCQCsAgICDUxpbWl0IGVycm9yOiAJAKQDAQkBA2FicwEFFWFtb3VudEJhc2VBc3NldEJvdWdodAIDIDwgCQCkAwEFE19taW5CYXNlQXNzZXRBbW91bnQED25ld1Bvc2l0aW9uU2l6ZQkAZAIFD29sZFBvc2l0aW9uU2l6ZQUVYW1vdW50QmFzZUFzc2V0Qm91Z2h0BBp0b3RhbExvbmdPcGVuSW50ZXJlc3RBZnRlcgkAZAIJARBvcGVuSW50ZXJlc3RMb25nAAMJAGYCBQ9uZXdQb3NpdGlvblNpemUAAAUMb3Blbk5vdGlvbmFsAAAEG3RvdGFsU2hvcnRPcGVuSW50ZXJlc3RBZnRlcgkAZAIJARFvcGVuSW50ZXJlc3RTaG9ydAADCQBmAgAABQ9uZXdQb3NpdGlvblNpemUFDG9wZW5Ob3Rpb25hbAAABA0kdDA2MjgxMDYzMDg1CQEwY2FsY1JlbWFpbk1hcmdpbldpdGhGdW5kaW5nUGF5bWVudEFuZFJvbGxvdmVyRmVlBQUPb2xkUG9zaXRpb25TaXplBRFvbGRQb3NpdGlvbk1hcmdpbgUUb2xkUG9zaXRpb25Mc3RVcGRDUEYFFG9sZFBvc2l0aW9uVGltZXN0YW1wBQdfYW1vdW50BAxyZW1haW5NYXJnaW4IBQ0kdDA2MjgxMDYzMDg1Al8xBAJ4MQgFDSR0MDYyODEwNjMwODUCXzIEAngyCAUNJHQwNjI4MTA2MzA4NQJfMwQLcm9sbG92ZXJGZWUIBQ0kdDA2MjgxMDYzMDg1Al80AwkBASEBCQEZcmVxdWlyZU5vdE92ZXJTcHJlYWRMaW1pdAIFFnF1b3RlQXNzZXRSZXNlcnZlQWZ0ZXIFFWJhc2VBc3NldFJlc2VydmVBZnRlcgkAAgECFU92ZXIgbWF4IHNwcmVhZCBsaW1pdAMJAQEhAQkBHXJlcXVpcmVOb3RPdmVyTWF4T3Blbk5vdGlvbmFsAgUadG90YWxMb25nT3BlbkludGVyZXN0QWZ0ZXIFG3RvdGFsU2hvcnRPcGVuSW50ZXJlc3RBZnRlcgkAAgECFk92ZXIgbWF4IG9wZW4gbm90aW9uYWwJAKAKDgUPbmV3UG9zaXRpb25TaXplBQxyZW1haW5NYXJnaW4JAGQCBRdvbGRQb3NpdGlvbk9wZW5Ob3Rpb25hbAUMb3Blbk5vdGlvbmFsCQEfbGF0ZXN0Q3VtdWxhdGl2ZVByZW1pdW1GcmFjdGlvbgEFD25ld1Bvc2l0aW9uU2l6ZQkBDWxhc3RUaW1lc3RhbXAABRViYXNlQXNzZXRSZXNlcnZlQWZ0ZXIFFnF1b3RlQXNzZXRSZXNlcnZlQWZ0ZXIFFnRvdGFsUG9zaXRpb25TaXplQWZ0ZXIJAGQCCQEUb3BlbkludGVyZXN0Tm90aW9uYWwABQxvcGVuTm90aW9uYWwJAGQCCQEVdG90YWxMb25nUG9zaXRpb25TaXplAAMJAGYCBQ9uZXdQb3NpdGlvblNpemUAAAkBA2FicwEFFWFtb3VudEJhc2VBc3NldEJvdWdodAAACQBkAgkBFnRvdGFsU2hvcnRQb3NpdGlvblNpemUAAwkAZgIAAAUPbmV3UG9zaXRpb25TaXplCQEDYWJzAQUVYW1vdW50QmFzZUFzc2V0Qm91Z2h0AAAFGnRvdGFsTG9uZ09wZW5JbnRlcmVzdEFmdGVyBRt0b3RhbFNob3J0T3BlbkludGVyZXN0QWZ0ZXIFC3JvbGxvdmVyRmVlBAxvcGVuTm90aW9uYWwJAQRtdWxkAgUHX2Ftb3VudAUJX2xldmVyYWdlBA0kdDA2NDQwMzY0NTMxCQEjZ2V0UG9zaXRpb25Ob3Rpb25hbEFuZFVucmVhbGl6ZWRQbmwDCQClCAEIBQFpBmNhbGxlcgUKX2RpcmVjdGlvbgUPUE5MX09QVElPTl9TUE9UBBNvbGRQb3NpdGlvbk5vdGlvbmFsCAUNJHQwNjQ0MDM2NDUzMQJfMQQNdW5yZWFsaXplZFBubAgFDSR0MDY0NDAzNjQ1MzECXzIDCQBmAgUTb2xkUG9zaXRpb25Ob3Rpb25hbAUMb3Blbk5vdGlvbmFsCQACAQIuVXNlIGRlY3JlYXNlUG9zaXRpb24gdG8gZGVjcmVhc2UgcG9zaXRpb24gc2l6ZQkAAgECFENsb3NlIHBvc2l0aW9uIGZpcnN0BA9uZXdQb3NpdGlvblNpemUIBQ0kdDA2MTU4MjY0NzE1Al8xBBduZXdQb3NpdGlvblJlbWFpbk1hcmdpbggFDSR0MDYxNTgyNjQ3MTUCXzIEF25ld1Bvc2l0aW9uT3Blbk5vdGlvbmFsCAUNJHQwNjE1ODI2NDcxNQJfMwQUbmV3UG9zaXRpb25MYXRlc3RDUEYIBQ0kdDA2MTU4MjY0NzE1Al80BBRuZXdQb3NpdGlvblRpbWVzdGFtcAgFDSR0MDYxNTgyNjQ3MTUCXzUEFWJhc2VBc3NldFJlc2VydmVBZnRlcggFDSR0MDYxNTgyNjQ3MTUCXzYEFnF1b3RlQXNzZXRSZXNlcnZlQWZ0ZXIIBQ0kdDA2MTU4MjY0NzE1Al83BBZ0b3RhbFBvc2l0aW9uU2l6ZUFmdGVyCAUNJHQwNjE1ODI2NDcxNQJfOAQZb3BlbkludGVyZXN0Tm90aW9uYWxBZnRlcggFDSR0MDYxNTgyNjQ3MTUCXzkEDnRvdGFsTG9uZ0FmdGVyCAUNJHQwNjE1ODI2NDcxNQNfMTAED3RvdGFsU2hvcnRBZnRlcggFDSR0MDYxNTgyNjQ3MTUDXzExBBp0b3RhbExvbmdPcGVuSW50ZXJlc3RBZnRlcggFDSR0MDYxNTgyNjQ3MTUDXzEyBBt0b3RhbFNob3J0T3BlbkludGVyZXN0QWZ0ZXIIBQ0kdDA2MTU4MjY0NzE1A18xMwQLcm9sbG92ZXJGZWUIBQ0kdDA2MTU4MjY0NzE1A18xNAQNJHQwNjQ3MjE2NDc5MgkBDWRpc3RyaWJ1dGVGZWUBCQBkAgUJZmVlQW1vdW50BQtyb2xsb3ZlckZlZQQMZmVlVG9TdGFrZXJzCAUNJHQwNjQ3MjE2NDc5MgJfMQQKZmVlVG9WYXVsdAgFDSR0MDY0NzIxNjQ3OTICXzIEBXN0YWtlAwkAZwIFB19hbW91bnQFC3JvbGxvdmVyRmVlCQD8BwQJAQx2YXVsdEFkZHJlc3MAAglhZGRMb2NrZWQFA25pbAkAzAgCCQEPQXR0YWNoZWRQYXltZW50AgkBCnF1b3RlQXNzZXQACQBlAgUHX2Ftb3VudAULcm9sbG92ZXJGZWUFA25pbAkA/AcECQEMdmF1bHRBZGRyZXNzAAIOd2l0aGRyYXdMb2NrZWQJAMwIAgkAZQIFC3JvbGxvdmVyRmVlBQdfYW1vdW50BQNuaWwFA25pbAMJAAACBQVzdGFrZQUFc3Rha2UEDGRlcG9zaXRWYXVsdAkA/AcECQEMdmF1bHRBZGRyZXNzAAIHYWRkRnJlZQUDbmlsCQDMCAIJAQ9BdHRhY2hlZFBheW1lbnQCCQEKcXVvdGVBc3NldAAFCmZlZVRvVmF1bHQFA25pbAMJAAACBQxkZXBvc2l0VmF1bHQFDGRlcG9zaXRWYXVsdAQJbm90aWZ5RmVlCQD8BwQJAQxtaW5lckFkZHJlc3MAAgpub3RpZnlGZWVzCQDMCAIFB190cmFkZXIJAMwIAgUJZmVlQW1vdW50BQNuaWwFA25pbAMJAAACBQlub3RpZnlGZWUFCW5vdGlmeUZlZQQObm90aWZ5Tm90aW9uYWwJAPwHBAkBDG1pbmVyQWRkcmVzcwACDm5vdGlmeU5vdGlvbmFsCQDMCAIFB190cmFkZXIJAMwIAgUXbmV3UG9zaXRpb25PcGVuTm90aW9uYWwFA25pbAUDbmlsAwkAAAIFDm5vdGlmeU5vdGlvbmFsBQ5ub3RpZnlOb3Rpb25hbAkAzggCCQDOCAIJAM4IAgkAzggCCQDOCAIJAM4IAgkBDnVwZGF0ZVBvc2l0aW9uBgUHX3RyYWRlcgUPbmV3UG9zaXRpb25TaXplBRduZXdQb3NpdGlvblJlbWFpbk1hcmdpbgUXbmV3UG9zaXRpb25PcGVuTm90aW9uYWwFFG5ld1Bvc2l0aW9uTGF0ZXN0Q1BGBRRuZXdQb3NpdGlvblRpbWVzdGFtcAkBH2luY3JlbWVudFBvc2l0aW9uU2VxdWVuY2VOdW1iZXIDBQ1pc05ld1Bvc2l0aW9uBQdfdHJhZGVyBQpfZGlyZWN0aW9uCQERdXBkYXRlUG9zaXRpb25GZWUEBQ1pc05ld1Bvc2l0aW9uBQdfdHJhZGVyBQpfZGlyZWN0aW9uBQthZGp1c3RlZEZlZQkBCXVwZGF0ZUFtbQgFFnF1b3RlQXNzZXRSZXNlcnZlQWZ0ZXIFFWJhc2VBc3NldFJlc2VydmVBZnRlcgUWdG90YWxQb3NpdGlvblNpemVBZnRlcgUZb3BlbkludGVyZXN0Tm90aW9uYWxBZnRlcgUOdG90YWxMb25nQWZ0ZXIFD3RvdGFsU2hvcnRBZnRlcgUadG90YWxMb25nT3BlbkludGVyZXN0QWZ0ZXIFG3RvdGFsU2hvcnRPcGVuSW50ZXJlc3RBZnRlcgkBC3RyYW5zZmVyRmVlAQUMZmVlVG9TdGFrZXJzCQENdXBkYXRlQmFsYW5jZQEJAGUCCQBkAgkBCGNiYWxhbmNlAAUHX2Ftb3VudAULcm9sbG92ZXJGZWUJAQ5kb0J1cm5BcnRpZmFjdAIFDGJ1cm5BcnRpZmFjdAUBaQkAAgECJFN0cmljdCB2YWx1ZSBpcyBub3QgZXF1YWwgdG8gaXRzZWxmLgkAAgECJFN0cmljdCB2YWx1ZSBpcyBub3QgZXF1YWwgdG8gaXRzZWxmLgkAAgECJFN0cmljdCB2YWx1ZSBpcyBub3QgZXF1YWwgdG8gaXRzZWxmLgkAAgECJFN0cmljdCB2YWx1ZSBpcyBub3QgZXF1YWwgdG8gaXRzZWxmLgkAAgECJFN0cmljdCB2YWx1ZSBpcyBub3QgZXF1YWwgdG8gaXRzZWxmLgkAAgECJFN0cmljdCB2YWx1ZSBpcyBub3QgZXF1YWwgdG8gaXRzZWxmLgkAAgECJFN0cmljdCB2YWx1ZSBpcyBub3QgZXF1YWwgdG8gaXRzZWxmLgkAAgECJFN0cmljdCB2YWx1ZSBpcyBub3QgZXF1YWwgdG8gaXRzZWxmLgFpAQlhZGRNYXJnaW4CCl9kaXJlY3Rpb24MX3ByaWNlVXBkYXRlBAx1cGRhdGVPcmFjbGUJAPwHBAUEdGhpcwIMdXBkYXRlT3JhY2xlCQDMCAIFDF9wcmljZVVwZGF0ZQUDbmlsBQNuaWwDCQAAAgUMdXBkYXRlT3JhY2xlBQx1cGRhdGVPcmFjbGUEBHN5bmMJAPwHBAUEdGhpcwIZc3luY1Rlcm1pbmFsUHJpY2VUb09yYWNsZQUDbmlsBQNuaWwDCQAAAgUEc3luYwUEc3luYwQQZW5zdXJlQ2FsbGVkT25jZQkA/AcEBQR0aGlzAhBlbnN1cmVDYWxsZWRPbmNlBQNuaWwFA25pbAMJAAACBRBlbnN1cmVDYWxsZWRPbmNlBRBlbnN1cmVDYWxsZWRPbmNlBAdfdHJhZGVyCQClCAEIBQFpBmNhbGxlcgQHX2Ftb3VudAgJAJEDAggFAWkIcGF5bWVudHMAAAZhbW91bnQECF9hc3NldElkCAkAkQMCCAUBaQhwYXltZW50cwAAB2Fzc2V0SWQEC19hc3NldElkU3RyCQDYBAEJAQV2YWx1ZQEFCF9hc3NldElkBAxpc1F1b3RlQXNzZXQJAAACBQhfYXNzZXRJZAkBCnF1b3RlQXNzZXQAAwMDAwMJAQEhAQUMaXNRdW90ZUFzc2V0BgkBASEBCQETcmVxdWlyZU9wZW5Qb3NpdGlvbgIJAKUIAQgFAWkGY2FsbGVyBQpfZGlyZWN0aW9uBgkBASEBCQELaW5pdGlhbGl6ZWQABgkBBnBhdXNlZAAGCQEOaXNNYXJrZXRDbG9zZWQACQACAQIcSW52YWxpZCBhZGRNYXJnaW4gcGFyYW1ldGVycwQNJHQwNjcxMzQ2NzMxNAkBC2dldFBvc2l0aW9uAgUHX3RyYWRlcgUKX2RpcmVjdGlvbgQPb2xkUG9zaXRpb25TaXplCAUNJHQwNjcxMzQ2NzMxNAJfMQQRb2xkUG9zaXRpb25NYXJnaW4IBQ0kdDA2NzEzNDY3MzE0Al8yBBdvbGRQb3NpdGlvbk9wZW5Ob3Rpb25hbAgFDSR0MDY3MTM0NjczMTQCXzMEFG9sZFBvc2l0aW9uTHN0VXBkQ1BGCAUNJHQwNjcxMzQ2NzMxNAJfNAQUb2xkUG9zaXRpb25UaW1lc3RhbXAIBQ0kdDA2NzEzNDY3MzE0Al81BAVzdGFrZQkA/AcECQEMdmF1bHRBZGRyZXNzAAIJYWRkTG9ja2VkBQNuaWwJAMwIAgkBD0F0dGFjaGVkUGF5bWVudAIJAQpxdW90ZUFzc2V0AAUHX2Ftb3VudAUDbmlsAwkAAAIFBXN0YWtlBQVzdGFrZQQNJHQwNjc0NTQ2NzY5NgkBMGNhbGNSZW1haW5NYXJnaW5XaXRoRnVuZGluZ1BheW1lbnRBbmRSb2xsb3ZlckZlZQUFD29sZFBvc2l0aW9uU2l6ZQURb2xkUG9zaXRpb25NYXJnaW4FFG9sZFBvc2l0aW9uTHN0VXBkQ1BGBRRvbGRQb3NpdGlvblRpbWVzdGFtcAUHX2Ftb3VudAQMcmVtYWluTWFyZ2luCAUNJHQwNjc0NTQ2NzY5NgJfMQQHYmFkRGVidAgFDSR0MDY3NDU0Njc2OTYCXzIEDmZ1bmRpbmdQYXltZW50CAUNJHQwNjc0NTQ2NzY5NgJfMwQLcm9sbG92ZXJGZWUIBQ0kdDA2NzQ1NDY3Njk2Al80BAttYXJnaW5SYXRpbwkBD2NhbGNNYXJnaW5SYXRpbwMFDHJlbWFpbk1hcmdpbgUHYmFkRGVidAUXb2xkUG9zaXRpb25PcGVuTm90aW9uYWwEDmNoZWNrTWluTWFyZ2luCQEWcmVxdWlyZU1vcmVNYXJnaW5SYXRpbwMFC21hcmdpblJhdGlvCQESbWluSW5pdE1hcmdpblJhdGlvAAcDCQAAAgUOY2hlY2tNaW5NYXJnaW4FDmNoZWNrTWluTWFyZ2luBBZkb1RyYW5zZmVyRmVlVG9TdGFrZXJzAwkAZgIFC3JvbGxvdmVyRmVlAAAEDSR0MDY3OTUyNjgwMTEJAQ1kaXN0cmlidXRlRmVlAQULcm9sbG92ZXJGZWUEDGZlZVRvU3Rha2VycwgFDSR0MDY3OTUyNjgwMTECXzEECmZlZVRvVmF1bHQIBQ0kdDA2Nzk1MjY4MDExAl8yBAd1bnN0YWtlCQD8BwQJAQx2YXVsdEFkZHJlc3MAAg53aXRoZHJhd0xvY2tlZAkAzAgCBQxmZWVUb1N0YWtlcnMFA25pbAUDbmlsAwkAAAIFB3Vuc3Rha2UFB3Vuc3Rha2UEC2xvY2tCYWREZWJ0CQD8BwQJAQx2YXVsdEFkZHJlc3MAAhVleGNoYW5nZUZyZWVBbmRMb2NrZWQJAMwIAgkBAS0BBQpmZWVUb1ZhdWx0BQNuaWwFA25pbAMJAAACBQtsb2NrQmFkRGVidAULbG9ja0JhZERlYnQJAQt0cmFuc2ZlckZlZQEFDGZlZVRvU3Rha2VycwkAAgECJFN0cmljdCB2YWx1ZSBpcyBub3QgZXF1YWwgdG8gaXRzZWxmLgkAAgECJFN0cmljdCB2YWx1ZSBpcyBub3QgZXF1YWwgdG8gaXRzZWxmLgUDbmlsAwkAAAIFFmRvVHJhbnNmZXJGZWVUb1N0YWtlcnMFFmRvVHJhbnNmZXJGZWVUb1N0YWtlcnMJAM4IAgkAzggCCQEOdXBkYXRlUG9zaXRpb24GBQdfdHJhZGVyBQ9vbGRQb3NpdGlvblNpemUJAGQCCQBlAgURb2xkUG9zaXRpb25NYXJnaW4FC3JvbGxvdmVyRmVlBQdfYW1vdW50BRdvbGRQb3NpdGlvbk9wZW5Ob3Rpb25hbAUUb2xkUG9zaXRpb25Mc3RVcGRDUEYJAQ1sYXN0VGltZXN0YW1wAAkBDXVwZGF0ZUJhbGFuY2UBCQBlAgkAZAIJAQhjYmFsYW5jZQAFB19hbW91bnQFC3JvbGxvdmVyRmVlBRZkb1RyYW5zZmVyRmVlVG9TdGFrZXJzCQACAQIkU3RyaWN0IHZhbHVlIGlzIG5vdCBlcXVhbCB0byBpdHNlbGYuCQACAQIkU3RyaWN0IHZhbHVlIGlzIG5vdCBlcXVhbCB0byBpdHNlbGYuCQACAQIkU3RyaWN0IHZhbHVlIGlzIG5vdCBlcXVhbCB0byBpdHNlbGYuCQACAQIkU3RyaWN0IHZhbHVlIGlzIG5vdCBlcXVhbCB0byBpdHNlbGYuCQACAQIkU3RyaWN0IHZhbHVlIGlzIG5vdCBlcXVhbCB0byBpdHNlbGYuCQACAQIkU3RyaWN0IHZhbHVlIGlzIG5vdCBlcXVhbCB0byBpdHNlbGYuAWkBDHJlbW92ZU1hcmdpbgMHX2Ftb3VudApfZGlyZWN0aW9uDF9wcmljZVVwZGF0ZQQMdXBkYXRlT3JhY2xlCQD8BwQFBHRoaXMCDHVwZGF0ZU9yYWNsZQkAzAgCBQxfcHJpY2VVcGRhdGUFA25pbAUDbmlsAwkAAAIFDHVwZGF0ZU9yYWNsZQUMdXBkYXRlT3JhY2xlBARzeW5jCQD8BwQFBHRoaXMCGXN5bmNUZXJtaW5hbFByaWNlVG9PcmFjbGUFA25pbAUDbmlsAwkAAAIFBHN5bmMFBHN5bmMEEGVuc3VyZUNhbGxlZE9uY2UJAPwHBAUEdGhpcwIQZW5zdXJlQ2FsbGVkT25jZQUDbmlsBQNuaWwDCQAAAgUQZW5zdXJlQ2FsbGVkT25jZQUQZW5zdXJlQ2FsbGVkT25jZQQHX3RyYWRlcgkApQgBCAUBaQZjYWxsZXIDAwMDAwkAZwIAAAUHX2Ftb3VudAYJAQEhAQkBE3JlcXVpcmVPcGVuUG9zaXRpb24CBQdfdHJhZGVyBQpfZGlyZWN0aW9uBgkBASEBCQELaW5pdGlhbGl6ZWQABgkBBnBhdXNlZAAGCQEOaXNNYXJrZXRDbG9zZWQACQACAQIfSW52YWxpZCByZW1vdmVNYXJnaW4gcGFyYW1ldGVycwQNJHQwNjk1MTI2OTY5MgkBC2dldFBvc2l0aW9uAgUHX3RyYWRlcgUKX2RpcmVjdGlvbgQPb2xkUG9zaXRpb25TaXplCAUNJHQwNjk1MTI2OTY5MgJfMQQRb2xkUG9zaXRpb25NYXJnaW4IBQ0kdDA2OTUxMjY5NjkyAl8yBBdvbGRQb3NpdGlvbk9wZW5Ob3Rpb25hbAgFDSR0MDY5NTEyNjk2OTICXzMEFG9sZFBvc2l0aW9uTHN0VXBkQ1BGCAUNJHQwNjk1MTI2OTY5MgJfNAQUb2xkUG9zaXRpb25UaW1lc3RhbXAIBQ0kdDA2OTUxMjY5NjkyAl81BA0kdDA2OTY5ODY5OTQ3CQEwY2FsY1JlbWFpbk1hcmdpbldpdGhGdW5kaW5nUGF5bWVudEFuZFJvbGxvdmVyRmVlBQUPb2xkUG9zaXRpb25TaXplBRFvbGRQb3NpdGlvbk1hcmdpbgUUb2xkUG9zaXRpb25Mc3RVcGRDUEYFFG9sZFBvc2l0aW9uVGltZXN0YW1wCQEBLQEFB19hbW91bnQEDHJlbWFpbk1hcmdpbggFDSR0MDY5Njk4Njk5NDcCXzEEB2JhZERlYnQIBQ0kdDA2OTY5ODY5OTQ3Al8yBA5mdW5kaW5nUGF5bWVudAgFDSR0MDY5Njk4Njk5NDcCXzMEC3JvbGxvdmVyRmVlCAUNJHQwNjk2OTg2OTk0NwJfNAMJAQIhPQIFB2JhZERlYnQAAAkAAgECHUludmFsaWQgcmVtb3ZlZCBtYXJnaW4gYW1vdW50BAttYXJnaW5SYXRpbwkBD2NhbGNNYXJnaW5SYXRpbwMFDHJlbWFpbk1hcmdpbgUHYmFkRGVidAUXb2xkUG9zaXRpb25PcGVuTm90aW9uYWwDCQEBIQEJARZyZXF1aXJlTW9yZU1hcmdpblJhdGlvAwULbWFyZ2luUmF0aW8JAQ9pbml0TWFyZ2luUmF0aW8ABgkAAgEJAKwCAgkArAICCQCsAgICGVRvbyBtdWNoIG1hcmdpbiByZW1vdmVkOiAJAKQDAQULbWFyZ2luUmF0aW8CAyA8IAkApAMBCQEPaW5pdE1hcmdpblJhdGlvAAQNJHQwNzAzMzM3MDM5MgkBDWRpc3RyaWJ1dGVGZWUBBQtyb2xsb3ZlckZlZQQMZmVlVG9TdGFrZXJzCAUNJHQwNzAzMzM3MDM5MgJfMQQKZmVlVG9WYXVsdAgFDSR0MDcwMzMzNzAzOTICXzIEFmRvVHJhbnNmZXJGZWVUb1N0YWtlcnMDCQBmAgULcm9sbG92ZXJGZWUAAAQLbG9ja0JhZERlYnQJAPwHBAkBDHZhdWx0QWRkcmVzcwACFWV4Y2hhbmdlRnJlZUFuZExvY2tlZAkAzAgCCQEBLQEFCmZlZVRvVmF1bHQFA25pbAUDbmlsAwkAAAIFC2xvY2tCYWREZWJ0BQtsb2NrQmFkRGVidAkBC3RyYW5zZmVyRmVlAQUMZmVlVG9TdGFrZXJzCQACAQIkU3RyaWN0IHZhbHVlIGlzIG5vdCBlcXVhbCB0byBpdHNlbGYuBQNuaWwDCQAAAgUWZG9UcmFuc2ZlckZlZVRvU3Rha2VycwUWZG9UcmFuc2ZlckZlZVRvU3Rha2VycwQHdW5zdGFrZQkA/AcECQEMdmF1bHRBZGRyZXNzAAIOd2l0aGRyYXdMb2NrZWQJAMwIAgkAZAIFB19hbW91bnQFDGZlZVRvU3Rha2VycwUDbmlsBQNuaWwDCQAAAgUHdW5zdGFrZQUHdW5zdGFrZQkAzggCCQDOCAIJAM4IAgkBDnVwZGF0ZVBvc2l0aW9uBgUHX3RyYWRlcgUPb2xkUG9zaXRpb25TaXplBQxyZW1haW5NYXJnaW4FF29sZFBvc2l0aW9uT3Blbk5vdGlvbmFsCQEfbGF0ZXN0Q3VtdWxhdGl2ZVByZW1pdW1GcmFjdGlvbgEFD29sZFBvc2l0aW9uU2l6ZQkBDWxhc3RUaW1lc3RhbXAACQEId2l0aGRyYXcCCAUBaQZjYWxsZXIFB19hbW91bnQJAQ11cGRhdGVCYWxhbmNlAQkAZQIJAGUCCQEIY2JhbGFuY2UABQdfYW1vdW50BQtyb2xsb3ZlckZlZQUWZG9UcmFuc2ZlckZlZVRvU3Rha2VycwkAAgECJFN0cmljdCB2YWx1ZSBpcyBub3QgZXF1YWwgdG8gaXRzZWxmLgkAAgECJFN0cmljdCB2YWx1ZSBpcyBub3QgZXF1YWwgdG8gaXRzZWxmLgkAAgECJFN0cmljdCB2YWx1ZSBpcyBub3QgZXF1YWwgdG8gaXRzZWxmLgkAAgECJFN0cmljdCB2YWx1ZSBpcyBub3QgZXF1YWwgdG8gaXRzZWxmLgkAAgECJFN0cmljdCB2YWx1ZSBpcyBub3QgZXF1YWwgdG8gaXRzZWxmLgFpAQ1jbG9zZVBvc2l0aW9uBQVfc2l6ZQpfZGlyZWN0aW9uFF9taW5RdW90ZUFzc2V0QW1vdW50DF9hZGRUb01hcmdpbgxfcHJpY2VVcGRhdGUEDHVwZGF0ZU9yYWNsZQkA/AcEBQR0aGlzAgx1cGRhdGVPcmFjbGUJAMwIAgUMX3ByaWNlVXBkYXRlBQNuaWwFA25pbAMJAAACBQx1cGRhdGVPcmFjbGUFDHVwZGF0ZU9yYWNsZQQEc3luYwkA/AcEBQR0aGlzAhlzeW5jVGVybWluYWxQcmljZVRvT3JhY2xlBQNuaWwFA25pbAMJAAACBQRzeW5jBQRzeW5jBBBlbnN1cmVDYWxsZWRPbmNlCQD8BwQFBHRoaXMCEGVuc3VyZUNhbGxlZE9uY2UFA25pbAUDbmlsAwkAAAIFEGVuc3VyZUNhbGxlZE9uY2UFEGVuc3VyZUNhbGxlZE9uY2UEB190cmFkZXIJAQ9nZXRBY3R1YWxDYWxsZXIBBQFpBA5fdHJhZGVyQWRkcmVzcwkBE3ZhbHVlT3JFcnJvck1lc3NhZ2UCCQCmCAEFB190cmFkZXICDkludmFsaWQgY2FsbGVyBAtwb3NpdGlvbkZlZQkBDmdldFBvc2l0aW9uRmVlAgUHX3RyYWRlcgUKX2RpcmVjdGlvbgMDAwMDAwkBASEBCQETcmVxdWlyZU9wZW5Qb3NpdGlvbgIFB190cmFkZXIFCl9kaXJlY3Rpb24GCQEBIQEJAQtpbml0aWFsaXplZAAGCQEGcGF1c2VkAAYJAGcCAAAFBV9zaXplBgkAZgIAAAUUX21pblF1b3RlQXNzZXRBbW91bnQGCQEOaXNNYXJrZXRDbG9zZWQACQACAQIgSW52YWxpZCBjbG9zZVBvc2l0aW9uIHBhcmFtZXRlcnMEFG9sZFBvc2l0aW9uVGltZXN0YW1wCAkBC2dldFBvc2l0aW9uAgUHX3RyYWRlcgUKX2RpcmVjdGlvbgJfNQQNJHQwNzI3Mjc3MzMzMAkBFWludGVybmFsQ2xvc2VQb3NpdGlvbggFB190cmFkZXIFCl9kaXJlY3Rpb24FBV9zaXplBQtwb3NpdGlvbkZlZQUUX21pblF1b3RlQXNzZXRBbW91bnQFDF9hZGRUb01hcmdpbgYGBA9uZXdQb3NpdGlvblNpemUIBQ0kdDA3MjcyNzczMzMwAl8xBBFuZXdQb3NpdGlvbk1hcmdpbggFDSR0MDcyNzI3NzMzMzACXzIEF25ld1Bvc2l0aW9uT3Blbk5vdGlvbmFsCAUNJHQwNzI3Mjc3MzMzMAJfMwQUbmV3UG9zaXRpb25Mc3RVcGRDUEYIBQ0kdDA3MjcyNzczMzMwAl80BA9wb3NpdGlvbkJhZERlYnQIBQ0kdDA3MjcyNzczMzMwAl81BAtyZWFsaXplZFBubAgFDSR0MDcyNzI3NzMzMzACXzYEDm1hcmdpblRvVHJhZGVyCAUNJHQwNzI3Mjc3MzMzMAJfNwQWcXVvdGVBc3NldFJlc2VydmVBZnRlcggFDSR0MDcyNzI3NzMzMzACXzgEFWJhc2VBc3NldFJlc2VydmVBZnRlcggFDSR0MDcyNzI3NzMzMzACXzkEFnRvdGFsUG9zaXRpb25TaXplQWZ0ZXIIBQ0kdDA3MjcyNzczMzMwA18xMAQZb3BlbkludGVyZXN0Tm90aW9uYWxBZnRlcggFDSR0MDcyNzI3NzMzMzADXzExBA50b3RhbExvbmdBZnRlcggFDSR0MDcyNzI3NzMzMzADXzEyBA90b3RhbFNob3J0QWZ0ZXIIBQ0kdDA3MjcyNzczMzMwA18xMwQadG90YWxMb25nT3BlbkludGVyZXN0QWZ0ZXIIBQ0kdDA3MjcyNzczMzMwA18xNAQbdG90YWxTaG9ydE9wZW5JbnRlcmVzdEFmdGVyCAUNJHQwNzI3Mjc3MzMzMANfMTUEC3JlYWxpemVkRmVlCAUNJHQwNzI3Mjc3MzMzMANfMTYDCQBmAgUPcG9zaXRpb25CYWREZWJ0AAAJAAIBAipJbnZhbGlkIGNsb3NlUG9zaXRpb24gcGFyYW1ldGVyczogYmFkIGRlYnQDCQBnAgUUb2xkUG9zaXRpb25UaW1lc3RhbXAJAQ1sYXN0VGltZXN0YW1wAAkAAgECU0ludmFsaWQgY2xvc2VQb3NpdGlvbiBwYXJhbWV0ZXJzOiB3YWl0IGF0IGxlYXN0IDEgYmxvY2sgYmVmb3JlIGNsb3NpbmcgdGhlIHBvc2l0aW9uBA5pc1BhcnRpYWxDbG9zZQkBAiE9AgUPbmV3UG9zaXRpb25TaXplAAAEDndpdGhkcmF3QW1vdW50CQBkAgUObWFyZ2luVG9UcmFkZXIFC3JlYWxpemVkRmVlBAphbW1CYWxhbmNlCQBlAgkBCGNiYWxhbmNlAAUOd2l0aGRyYXdBbW91bnQEDWFtbU5ld0JhbGFuY2UDCQBmAgAABQphbW1CYWxhbmNlAAAFCmFtbUJhbGFuY2UEB3Vuc3Rha2UJAPwHBAkBDHZhdWx0QWRkcmVzcwACDndpdGhkcmF3TG9ja2VkCQDMCAIFDndpdGhkcmF3QW1vdW50BQNuaWwFA25pbAMJAAACBQd1bnN0YWtlBQd1bnN0YWtlBA5yZWZlcnJlckZlZUFueQkA/AcECQEPcmVmZXJyYWxBZGRyZXNzAAINYWNjZXB0UGF5bWVudAkAzAgCBQdfdHJhZGVyBQNuaWwJAMwIAgkBD0F0dGFjaGVkUGF5bWVudAIJAQpxdW90ZUFzc2V0AAULcmVhbGl6ZWRGZWUFA25pbAMJAAACBQ5yZWZlcnJlckZlZUFueQUOcmVmZXJyZXJGZWVBbnkEC3JlZmVycmVyRmVlBAckbWF0Y2gwBQ5yZWZlcnJlckZlZUFueQMJAAECBQckbWF0Y2gwAgNJbnQEAXgFByRtYXRjaDAFAXgJAAIBAhNJbnZhbGlkIHJlZmVycmVyRmVlBA0kdDA3NDMwMjc0Mzc1CQENZGlzdHJpYnV0ZUZlZQEJAGUCBQtyZWFsaXplZEZlZQULcmVmZXJyZXJGZWUEDGZlZVRvU3Rha2VycwgFDSR0MDc0MzAyNzQzNzUCXzEECmZlZVRvVmF1bHQIBQ0kdDA3NDMwMjc0Mzc1Al8yBAxkZXBvc2l0VmF1bHQJAPwHBAkBDHZhdWx0QWRkcmVzcwACB2FkZEZyZWUFA25pbAkAzAgCCQEPQXR0YWNoZWRQYXltZW50AgkBCnF1b3RlQXNzZXQABQpmZWVUb1ZhdWx0BQNuaWwDCQAAAgUMZGVwb3NpdFZhdWx0BQxkZXBvc2l0VmF1bHQECW5vdGlmeUZlZQkA/AcECQEMbWluZXJBZGRyZXNzAAIKbm90aWZ5RmVlcwkAzAgCBQdfdHJhZGVyCQDMCAIFC3JlYWxpemVkRmVlBQNuaWwFA25pbAMJAAACBQlub3RpZnlGZWUFCW5vdGlmeUZlZQQObm90aWZ5Tm90aW9uYWwJAPwHBAkBDG1pbmVyQWRkcmVzcwACDm5vdGlmeU5vdGlvbmFsCQDMCAIFB190cmFkZXIJAMwIAgUXbmV3UG9zaXRpb25PcGVuTm90aW9uYWwFA25pbAUDbmlsAwkAAAIFDm5vdGlmeU5vdGlvbmFsBQ5ub3RpZnlOb3Rpb25hbAkAzggCCQDOCAIJAM4IAgkAzggCAwUOaXNQYXJ0aWFsQ2xvc2UJAQ51cGRhdGVQb3NpdGlvbgYFB190cmFkZXIFD25ld1Bvc2l0aW9uU2l6ZQURbmV3UG9zaXRpb25NYXJnaW4FF25ld1Bvc2l0aW9uT3Blbk5vdGlvbmFsBRRuZXdQb3NpdGlvbkxzdFVwZENQRgkBDWxhc3RUaW1lc3RhbXAACQEOZGVsZXRlUG9zaXRpb24CBQdfdHJhZGVyBQpfZGlyZWN0aW9uCQEJdXBkYXRlQW1tCAUWcXVvdGVBc3NldFJlc2VydmVBZnRlcgUVYmFzZUFzc2V0UmVzZXJ2ZUFmdGVyBRZ0b3RhbFBvc2l0aW9uU2l6ZUFmdGVyBRlvcGVuSW50ZXJlc3ROb3Rpb25hbEFmdGVyBQ50b3RhbExvbmdBZnRlcgUPdG90YWxTaG9ydEFmdGVyBRp0b3RhbExvbmdPcGVuSW50ZXJlc3RBZnRlcgUbdG90YWxTaG9ydE9wZW5JbnRlcmVzdEFmdGVyAwkAZgIFDm1hcmdpblRvVHJhZGVyAAAJAQh3aXRoZHJhdwIFDl90cmFkZXJBZGRyZXNzBQ5tYXJnaW5Ub1RyYWRlcgUDbmlsCQENdXBkYXRlQmFsYW5jZQEFDWFtbU5ld0JhbGFuY2UJAQt0cmFuc2ZlckZlZQEFDGZlZVRvU3Rha2VycwkAAgECJFN0cmljdCB2YWx1ZSBpcyBub3QgZXF1YWwgdG8gaXRzZWxmLgkAAgECJFN0cmljdCB2YWx1ZSBpcyBub3QgZXF1YWwgdG8gaXRzZWxmLgkAAgECJFN0cmljdCB2YWx1ZSBpcyBub3QgZXF1YWwgdG8gaXRzZWxmLgkAAgECJFN0cmljdCB2YWx1ZSBpcyBub3QgZXF1YWwgdG8gaXRzZWxmLgkAAgECJFN0cmljdCB2YWx1ZSBpcyBub3QgZXF1YWwgdG8gaXRzZWxmLgkAAgECJFN0cmljdCB2YWx1ZSBpcyBub3QgZXF1YWwgdG8gaXRzZWxmLgkAAgECJFN0cmljdCB2YWx1ZSBpcyBub3QgZXF1YWwgdG8gaXRzZWxmLgkAAgECJFN0cmljdCB2YWx1ZSBpcyBub3QgZXF1YWwgdG8gaXRzZWxmLgFpAQlsaXF1aWRhdGUDB190cmFkZXIKX2RpcmVjdGlvbgxfcHJpY2VVcGRhdGUEDHVwZGF0ZU9yYWNsZQkA/AcEBQR0aGlzAgx1cGRhdGVPcmFjbGUJAMwIAgUMX3ByaWNlVXBkYXRlBQNuaWwFA25pbAMJAAACBQx1cGRhdGVPcmFjbGUFDHVwZGF0ZU9yYWNsZQQEc3luYwkA/AcEBQR0aGlzAhlzeW5jVGVybWluYWxQcmljZVRvT3JhY2xlBQNuaWwFA25pbAMJAAACBQRzeW5jBQRzeW5jBA9zcG90TWFyZ2luUmF0aW8JARZnZXRNYXJnaW5SYXRpb0J5T3B0aW9uAwUHX3RyYWRlcgUKX2RpcmVjdGlvbgUPUE5MX09QVElPTl9TUE9UBBZsaXF1aWRhdGlvbk1hcmdpblJhdGlvAwkBFmlzT3ZlckZsdWN0dWF0aW9uTGltaXQABBFvcmFjbGVNYXJnaW5SYXRpbwkBFmdldE1hcmdpblJhdGlvQnlPcHRpb24DBQdfdHJhZGVyBQpfZGlyZWN0aW9uBRFQTkxfT1BUSU9OX09SQUNMRQkBBHZtYXgCBQ9zcG90TWFyZ2luUmF0aW8FEW9yYWNsZU1hcmdpblJhdGlvBQ9zcG90TWFyZ2luUmF0aW8DAwMDAwkBASEBCQEWcmVxdWlyZU1vcmVNYXJnaW5SYXRpbwMFFmxpcXVpZGF0aW9uTWFyZ2luUmF0aW8JARZtYWludGVuYW5jZU1hcmdpblJhdGlvAAcGCQEBIQEJARNyZXF1aXJlT3BlblBvc2l0aW9uAgUHX3RyYWRlcgUKX2RpcmVjdGlvbgYJAQEhAQkBC2luaXRpYWxpemVkAAYJAQZwYXVzZWQABgkBDmlzTWFya2V0Q2xvc2VkAAkAAgECE1VuYWJsZSB0byBsaXF1aWRhdGUED29sZFBvc2l0aW9uU2l6ZQgJAQtnZXRQb3NpdGlvbgIFB190cmFkZXIFCl9kaXJlY3Rpb24CXzEED3Bvc2l0aW9uU2l6ZUFicwkBA2FicwEFD29sZFBvc2l0aW9uU2l6ZQQUaXNQYXJ0aWFsTGlxdWlkYXRpb24DAwMJAGYCBQ9zcG90TWFyZ2luUmF0aW8JARNsaXF1aWRhdGlvbkZlZVJhdGlvAAkAZgIJARdwYXJ0aWFsTGlxdWlkYXRpb25SYXRpbwAAAAcJAGYCBQxERUNJTUFMX1VOSVQJARdwYXJ0aWFsTGlxdWlkYXRpb25SYXRpbwAHCQBmAgkBBG11bGQCBQ9wb3NpdGlvblNpemVBYnMJAQxnZXRTcG90UHJpY2UACQEdbWluUGFydGlhbExpcXVpZGF0aW9uTm90aW9uYWwABwQNJHQwNzcwNDk3NzQzNgMFFGlzUGFydGlhbExpcXVpZGF0aW9uBA9saXF1aWRhdGlvblNpemUJAQNhYnMBCQEbZ2V0UGFydGlhbExpcXVpZGF0aW9uQW1vdW50AgUHX3RyYWRlcgUPb2xkUG9zaXRpb25TaXplBBBsaXF1aWRhdGlvblJhdGlvCQEEZGl2ZAIFD2xpcXVpZGF0aW9uU2l6ZQUPcG9zaXRpb25TaXplQWJzBBNsaXF1aWRhdGlvbk5vdGlvbmFsCQEEbXVsZAIFD2xpcXVpZGF0aW9uU2l6ZQkBDGdldFNwb3RQcmljZQAJAJQKAgUQbGlxdWlkYXRpb25SYXRpbwUPbGlxdWlkYXRpb25TaXplCQCUCgIAAAUPcG9zaXRpb25TaXplQWJzBBBsaXF1aWRhdGlvblJhdGlvCAUNJHQwNzcwNDk3NzQzNgJfMQQPbGlxdWlkYXRpb25TaXplCAUNJHQwNzcwNDk3NzQzNgJfMgQNJHQwNzc0NDI3ODA5OAkBFWludGVybmFsQ2xvc2VQb3NpdGlvbggFB190cmFkZXIFCl9kaXJlY3Rpb24DBRRpc1BhcnRpYWxMaXF1aWRhdGlvbgUPbGlxdWlkYXRpb25TaXplBQ9wb3NpdGlvblNpemVBYnMJARNsaXF1aWRhdGlvbkZlZVJhdGlvAAAABgcGBA9uZXdQb3NpdGlvblNpemUIBQ0kdDA3NzQ0Mjc4MDk4Al8xBBFuZXdQb3NpdGlvbk1hcmdpbggFDSR0MDc3NDQyNzgwOTgCXzIEF25ld1Bvc2l0aW9uT3Blbk5vdGlvbmFsCAUNJHQwNzc0NDI3ODA5OAJfMwQUbmV3UG9zaXRpb25Mc3RVcGRDUEYIBQ0kdDA3NzQ0Mjc4MDk4Al80BA9wb3NpdGlvbkJhZERlYnQIBQ0kdDA3NzQ0Mjc4MDk4Al81BAtyZWFsaXplZFBubAgFDSR0MDc3NDQyNzgwOTgCXzYEDm1hcmdpblRvVHJhZGVyCAUNJHQwNzc0NDI3ODA5OAJfNwQWcXVvdGVBc3NldFJlc2VydmVBZnRlcggFDSR0MDc3NDQyNzgwOTgCXzgEFWJhc2VBc3NldFJlc2VydmVBZnRlcggFDSR0MDc3NDQyNzgwOTgCXzkEFnRvdGFsUG9zaXRpb25TaXplQWZ0ZXIIBQ0kdDA3NzQ0Mjc4MDk4A18xMAQZb3BlbkludGVyZXN0Tm90aW9uYWxBZnRlcggFDSR0MDc3NDQyNzgwOTgDXzExBA50b3RhbExvbmdBZnRlcggFDSR0MDc3NDQyNzgwOTgDXzEyBA90b3RhbFNob3J0QWZ0ZXIIBQ0kdDA3NzQ0Mjc4MDk4A18xMwQadG90YWxMb25nT3BlbkludGVyZXN0QWZ0ZXIIBQ0kdDA3NzQ0Mjc4MDk4A18xNAQbdG90YWxTaG9ydE9wZW5JbnRlcmVzdEFmdGVyCAUNJHQwNzc0NDI3ODA5OANfMTUEEmxpcXVpZGF0aW9uUGVuYWx0eQgFDSR0MDc3NDQyNzgwOTgDXzE2BA9mZWVUb0xpcXVpZGF0b3IJAGkCBRJsaXF1aWRhdGlvblBlbmFsdHkAAgQKZmVlVG9WYXVsdAkAZQIFEmxpcXVpZGF0aW9uUGVuYWx0eQUPZmVlVG9MaXF1aWRhdG9yBAphbW1CYWxhbmNlCQBlAgkBCGNiYWxhbmNlAAUSbGlxdWlkYXRpb25QZW5hbHR5BA1uZXdBbW1CYWxhbmNlAwkAZgIAAAUKYW1tQmFsYW5jZQAABQphbW1CYWxhbmNlBAtsb2NrQmFkRGVidAMJAGYCBQ9wb3NpdGlvbkJhZERlYnQAAAQLbG9ja0JhZERlYnQJAPwHBAkBDHZhdWx0QWRkcmVzcwACFWV4Y2hhbmdlRnJlZUFuZExvY2tlZAkAzAgCCQBkAgUPcG9zaXRpb25CYWREZWJ0BRJsaXF1aWRhdGlvblBlbmFsdHkFA25pbAUDbmlsAwkAAAIFC2xvY2tCYWREZWJ0BQtsb2NrQmFkRGVidAUDbmlsCQACAQIkU3RyaWN0IHZhbHVlIGlzIG5vdCBlcXVhbCB0byBpdHNlbGYuBQNuaWwDCQAAAgULbG9ja0JhZERlYnQFC2xvY2tCYWREZWJ0BAd1bnN0YWtlCQD8BwQJAQx2YXVsdEFkZHJlc3MAAg53aXRoZHJhd0xvY2tlZAkAzAgCBRJsaXF1aWRhdGlvblBlbmFsdHkFA25pbAUDbmlsAwkAAAIFB3Vuc3Rha2UFB3Vuc3Rha2UEEGRlcG9zaXRJbnN1cmFuY2UJAPwHBAkBDHZhdWx0QWRkcmVzcwACB2FkZEZyZWUFA25pbAkAzAgCCQEPQXR0YWNoZWRQYXltZW50AgkBCnF1b3RlQXNzZXQABQpmZWVUb1ZhdWx0BQNuaWwDCQAAAgUQZGVwb3NpdEluc3VyYW5jZQUQZGVwb3NpdEluc3VyYW5jZQQObm90aWZ5Tm90aW9uYWwJAPwHBAkBDG1pbmVyQWRkcmVzcwACDm5vdGlmeU5vdGlvbmFsCQDMCAIFB190cmFkZXIJAMwIAgUXbmV3UG9zaXRpb25PcGVuTm90aW9uYWwFA25pbAUDbmlsAwkAAAIFDm5vdGlmeU5vdGlvbmFsBQ5ub3RpZnlOb3Rpb25hbAkAzggCCQDOCAIJAM4IAgMFFGlzUGFydGlhbExpcXVpZGF0aW9uCQEOdXBkYXRlUG9zaXRpb24GBQdfdHJhZGVyBQ9uZXdQb3NpdGlvblNpemUFEW5ld1Bvc2l0aW9uTWFyZ2luBRduZXdQb3NpdGlvbk9wZW5Ob3Rpb25hbAUUbmV3UG9zaXRpb25Mc3RVcGRDUEYJAQ1sYXN0VGltZXN0YW1wAAkBDmRlbGV0ZVBvc2l0aW9uAgUHX3RyYWRlcgUKX2RpcmVjdGlvbgkBCXVwZGF0ZUFtbQgFFnF1b3RlQXNzZXRSZXNlcnZlQWZ0ZXIFFWJhc2VBc3NldFJlc2VydmVBZnRlcgUWdG90YWxQb3NpdGlvblNpemVBZnRlcgUZb3BlbkludGVyZXN0Tm90aW9uYWxBZnRlcgUOdG90YWxMb25nQWZ0ZXIFD3RvdGFsU2hvcnRBZnRlcgUadG90YWxMb25nT3BlbkludGVyZXN0QWZ0ZXIFG3RvdGFsU2hvcnRPcGVuSW50ZXJlc3RBZnRlcgkBCHdpdGhkcmF3AggFAWkGY2FsbGVyBQ9mZWVUb0xpcXVpZGF0b3IJAQ11cGRhdGVCYWxhbmNlAQUNbmV3QW1tQmFsYW5jZQkAAgECJFN0cmljdCB2YWx1ZSBpcyBub3QgZXF1YWwgdG8gaXRzZWxmLgkAAgECJFN0cmljdCB2YWx1ZSBpcyBub3QgZXF1YWwgdG8gaXRzZWxmLgkAAgECJFN0cmljdCB2YWx1ZSBpcyBub3QgZXF1YWwgdG8gaXRzZWxmLgkAAgECJFN0cmljdCB2YWx1ZSBpcyBub3QgZXF1YWwgdG8gaXRzZWxmLgkAAgECJFN0cmljdCB2YWx1ZSBpcyBub3QgZXF1YWwgdG8gaXRzZWxmLgkAAgECJFN0cmljdCB2YWx1ZSBpcyBub3QgZXF1YWwgdG8gaXRzZWxmLgFpAQpwYXlGdW5kaW5nAQxfcHJpY2VVcGRhdGUEDHVwZGF0ZU9yYWNsZQkA/AcEBQR0aGlzAgx1cGRhdGVPcmFjbGUJAMwIAgUMX3ByaWNlVXBkYXRlBQNuaWwFA25pbAMJAAACBQx1cGRhdGVPcmFjbGUFDHVwZGF0ZU9yYWNsZQQEc3luYwkA/AcEBQR0aGlzAhlzeW5jVGVybWluYWxQcmljZVRvT3JhY2xlBQNuaWwFA25pbAMJAAACBQRzeW5jBQRzeW5jBBVmdW5kaW5nQmxvY2tUaW1lc3RhbXAJARluZXh0RnVuZGluZ0Jsb2NrVGltZXN0YW1wAAMDAwkAZgIFFWZ1bmRpbmdCbG9ja1RpbWVzdGFtcAkBDWxhc3RUaW1lc3RhbXAABgkBASEBCQELaW5pdGlhbGl6ZWQABgkBBnBhdXNlZAAJAAIBCQCsAgIJAKwCAgkArAICAiFJbnZhbGlkIGZ1bmRpbmcgYmxvY2sgdGltZXN0YW1wOiAJAKQDAQkBDWxhc3RUaW1lc3RhbXAAAgMgPCAJAKQDAQUVZnVuZGluZ0Jsb2NrVGltZXN0YW1wBA91bmRlcmx5aW5nUHJpY2UJAQ5nZXRPcmFjbGVQcmljZQAEDSR0MDgwMzE2ODAzOTQJAQpnZXRGdW5kaW5nAAQUc2hvcnRQcmVtaXVtRnJhY3Rpb24IBQ0kdDA4MDMxNjgwMzk0Al8xBBNsb25nUHJlbWl1bUZyYWN0aW9uCAUNJHQwODAzMTY4MDM5NAJfMgQOcHJlbWl1bVRvVmF1bHQIBQ0kdDA4MDMxNjgwMzk0Al8zBBNkb1BheUZ1bmRpbmdUb1ZhdWx0AwkAZgIFDnByZW1pdW1Ub1ZhdWx0AAAEDSR0MDgwNDY2ODA1MjgJAQ1kaXN0cmlidXRlRmVlAQUOcHJlbWl1bVRvVmF1bHQEDGZlZVRvU3Rha2VycwgFDSR0MDgwNDY2ODA1MjgCXzEECmZlZVRvVmF1bHQIBQ0kdDA4MDQ2NjgwNTI4Al8yBAd1bnN0YWtlCQD8BwQJAQx2YXVsdEFkZHJlc3MAAg53aXRoZHJhd0xvY2tlZAkAzAgCBQxmZWVUb1N0YWtlcnMFA25pbAUDbmlsAwkAAAIFB3Vuc3Rha2UFB3Vuc3Rha2UEGGFkZEZ1bmRpbmdQYXltZW50VG9WYXVsdAkA/AcECQEMdmF1bHRBZGRyZXNzAAIVZXhjaGFuZ2VGcmVlQW5kTG9ja2VkCQDMCAIJAQEtAQUKZmVlVG9WYXVsdAUDbmlsBQNuaWwDCQAAAgUYYWRkRnVuZGluZ1BheW1lbnRUb1ZhdWx0BRhhZGRGdW5kaW5nUGF5bWVudFRvVmF1bHQJAQt0cmFuc2ZlckZlZQEFDGZlZVRvU3Rha2VycwkAAgECJFN0cmljdCB2YWx1ZSBpcyBub3QgZXF1YWwgdG8gaXRzZWxmLgkAAgECJFN0cmljdCB2YWx1ZSBpcyBub3QgZXF1YWwgdG8gaXRzZWxmLgUDbmlsAwkAAAIFE2RvUGF5RnVuZGluZ1RvVmF1bHQFE2RvUGF5RnVuZGluZ1RvVmF1bHQJAM4IAgkBDXVwZGF0ZUZ1bmRpbmcFCQBkAgUVZnVuZGluZ0Jsb2NrVGltZXN0YW1wCQEUZnVuZGluZ1BlcmlvZFNlY29uZHMACQBkAgkBI2xhdGVzdExvbmdDdW11bGF0aXZlUHJlbWl1bUZyYWN0aW9uAAUTbG9uZ1ByZW1pdW1GcmFjdGlvbgkAZAIJASRsYXRlc3RTaG9ydEN1bXVsYXRpdmVQcmVtaXVtRnJhY3Rpb24ABRRzaG9ydFByZW1pdW1GcmFjdGlvbgkBBGRpdmQCBRNsb25nUHJlbWl1bUZyYWN0aW9uBQ91bmRlcmx5aW5nUHJpY2UJAQRkaXZkAgUUc2hvcnRQcmVtaXVtRnJhY3Rpb24FD3VuZGVybHlpbmdQcmljZQUTZG9QYXlGdW5kaW5nVG9WYXVsdAkAAgECJFN0cmljdCB2YWx1ZSBpcyBub3QgZXF1YWwgdG8gaXRzZWxmLgkAAgECJFN0cmljdCB2YWx1ZSBpcyBub3QgZXF1YWwgdG8gaXRzZWxmLgkAAgECJFN0cmljdCB2YWx1ZSBpcyBub3QgZXF1YWwgdG8gaXRzZWxmLgFpAQx1cGRhdGVPcmFjbGUBDF9wcmljZVVwZGF0ZQMJAAACCQEKb3JhY2xlTW9kZQAFDE9SQUNMRV9QTEFJTgUDbmlsBAxwcmljZVVwZGF0ZXMJALwJAgUMX3ByaWNlVXBkYXRlAgI6OgQKYmFzZU9yYWNsZQkBE3ZhbHVlT3JFcnJvck1lc3NhZ2UCCQENZ2V0T3JhY2xlRGF0YQEFDGtfYmFzZU9yYWNsZQIZTm8gYmFzZSBhc3NldCBvcmFjbGUgZGF0YQQRYmFzZU9yYWNsZUFkZHJlc3MIBQpiYXNlT3JhY2xlAl8xBBJkb1VwZGF0ZUJhc2VPcmFjbGUJAPwHBAURYmFzZU9yYWNsZUFkZHJlc3MCCnVwZGF0ZURhdGEJAMwIAgkAkQMCBQxwcmljZVVwZGF0ZXMAAAUDbmlsBQNuaWwDCQAAAgUSZG9VcGRhdGVCYXNlT3JhY2xlBRJkb1VwZGF0ZUJhc2VPcmFjbGUEC3F1b3RlT3JhY2xlCQENZ2V0T3JhY2xlRGF0YQEFDWtfcXVvdGVPcmFjbGUEE2RvVXBkYXRlUXVvdGVPcmFjbGUDCQEJaXNEZWZpbmVkAQULcXVvdGVPcmFjbGUEDHF1b3RlT3JhY2xlVgkBBXZhbHVlAQULcXVvdGVPcmFjbGUEEnF1b3RlT3JhY2xlQWRkcmVzcwgFDHF1b3RlT3JhY2xlVgJfMQQTZG9VcGRhdGVRdW90ZU9yYWNsZQkA/AcEBRJxdW90ZU9yYWNsZUFkZHJlc3MCCnVwZGF0ZURhdGEJAMwIAgkAkQMCBQxwcmljZVVwZGF0ZXMAAQUDbmlsBQNuaWwDCQAAAgUTZG9VcGRhdGVRdW90ZU9yYWNsZQUTZG9VcGRhdGVRdW90ZU9yYWNsZQUDbmlsCQACAQIkU3RyaWN0IHZhbHVlIGlzIG5vdCBlcXVhbCB0byBpdHNlbGYuBQNuaWwDCQAAAgUTZG9VcGRhdGVRdW90ZU9yYWNsZQUTZG9VcGRhdGVRdW90ZU9yYWNsZQUDbmlsCQACAQIkU3RyaWN0IHZhbHVlIGlzIG5vdCBlcXVhbCB0byBpdHNlbGYuCQACAQIkU3RyaWN0IHZhbHVlIGlzIG5vdCBlcXVhbCB0byBpdHNlbGYuAWkBGXN5bmNUZXJtaW5hbFByaWNlVG9PcmFjbGUABAdfcXRBc3RSCQEGcXRBc3RSAAQHX2JzQXN0UgkBBmJzQXN0UgAEDSR0MDgyNDU0ODI4MjAJARRnZXRTeW5jVGVybWluYWxQcmljZQMJAQ5nZXRPcmFjbGVQcmljZQAFB19xdEFzdFIFB19ic0FzdFIEE25ld1F1b3RlQXNzZXRXZWlnaHQIBQ0kdDA4MjQ1NDgyODIwAl8xBBJuZXdCYXNlQXNzZXRXZWlnaHQIBQ0kdDA4MjQ1NDgyODIwAl8yBA1tYXJnaW5Ub1ZhdWx0CAUNJHQwODI0NTQ4MjgyMAJfMwQQbWFyZ2luVG9WYXVsdEFkagMDCQBmAgAABQ1tYXJnaW5Ub1ZhdWx0CQBmAgkBA2FicwEFDW1hcmdpblRvVmF1bHQJAQhjYmFsYW5jZQAHCQEBLQEJAQhjYmFsYW5jZQAFDW1hcmdpblRvVmF1bHQEDWRvRXhjaGFuZ2VQbkwDCQECIT0CBRBtYXJnaW5Ub1ZhdWx0QWRqAAAEDWRvRXhjaGFuZ2VQbkwJAPwHBAkBDHZhdWx0QWRkcmVzcwACFWV4Y2hhbmdlRnJlZUFuZExvY2tlZAkAzAgCBRBtYXJnaW5Ub1ZhdWx0QWRqBQNuaWwFA25pbAMJAAACBQ1kb0V4Y2hhbmdlUG5MBQ1kb0V4Y2hhbmdlUG5MBQNuaWwJAAIBAiRTdHJpY3QgdmFsdWUgaXMgbm90IGVxdWFsIHRvIGl0c2VsZi4FA25pbAMJAAACBQ1kb0V4Y2hhbmdlUG5MBQ1kb0V4Y2hhbmdlUG5MCQDOCAIJAQ11cGRhdGVCYWxhbmNlAQkAZAIJAQhjYmFsYW5jZQAFEG1hcmdpblRvVmF1bHRBZGoJARB1cGRhdGVBbW1XZWlnaHRzAgUTbmV3UXVvdGVBc3NldFdlaWdodAUSbmV3QmFzZUFzc2V0V2VpZ2h0CQACAQIkU3RyaWN0IHZhbHVlIGlzIG5vdCBlcXVhbCB0byBpdHNlbGYuAWkBEGVuc3VyZUNhbGxlZE9uY2UAAwkBAiE9AggFAWkGY2FsbGVyBQR0aGlzCQACAQIiSW52YWxpZCBzYXZlQ3VycmVudFR4SWQgcGFyYW1ldGVycwQEdHhJZAkA2AQBCAUBaQ10cmFuc2FjdGlvbklkBAZsYXN0VHgJAQt2YWx1ZU9yRWxzZQIJAJ0IAgUEdGhpcwUIa19sYXN0VHgCAAMJAQIhPQIFBmxhc3RUeAUEdHhJZAkAzAgCCQELU3RyaW5nRW50cnkCBQhrX2xhc3RUeAUEdHhJZAUDbmlsCQACAQIpQ2FuIG5vdCBjYWxsIHZBTU0gbWV0aG9kcyB0d2ljZSBpbiBvbmUgdHgBaQEPbWlncmF0ZVBvc2l0aW9uAQdfdHJhZGVyBA9wb3NpdGlvblNpemVPcHQJAJoIAgUEdGhpcwkBDnRvQ29tcG9zaXRlS2V5AgUOa19wb3NpdGlvblNpemUFB190cmFkZXIDAwkBCWlzRGVmaW5lZAEFD3Bvc2l0aW9uU2l6ZU9wdAkBCWlzRGVmaW5lZAEJAKYIAQUHX3RyYWRlcgcEBXBTaXplCQERQGV4dHJOYXRpdmUoMTA1MCkCBQR0aGlzCQEOdG9Db21wb3NpdGVLZXkCBQ5rX3Bvc2l0aW9uU2l6ZQUHX3RyYWRlcgQHcE1hcmdpbgkBEUBleHRyTmF0aXZlKDEwNTApAgUEdGhpcwkBDnRvQ29tcG9zaXRlS2V5AgUQa19wb3NpdGlvbk1hcmdpbgUHX3RyYWRlcgQJcE5vdGlvbmFsCQERQGV4dHJOYXRpdmUoMTA1MCkCBQR0aGlzCQEOdG9Db21wb3NpdGVLZXkCBRZrX3Bvc2l0aW9uT3Blbk5vdGlvbmFsBQdfdHJhZGVyBAlwRnJhY3Rpb24JARFAZXh0ck5hdGl2ZSgxMDUwKQIFBHRoaXMJAQ50b0NvbXBvc2l0ZUtleQIFLmtfcG9zaXRpb25MYXN0VXBkYXRlZEN1bXVsYXRpdmVQcmVtaXVtRnJhY3Rpb24FB190cmFkZXIECnBUaW1lc3RhbXAJAQt2YWx1ZU9yRWxzZQIJAJoIAgUEdGhpcwkBDnRvQ29tcG9zaXRlS2V5AgUea19wb3NpdGlvbkxhc3RVcGRhdGVkVGltZXN0YW1wBQdfdHJhZGVyCAUJbGFzdEJsb2NrCXRpbWVzdGFtcAQEcEZlZQkBC3ZhbHVlT3JFbHNlAgkAmggCBQR0aGlzCQEOdG9Db21wb3NpdGVLZXkCBQ1rX3Bvc2l0aW9uRmVlBQdfdHJhZGVyCQEDZmVlAAQJcFNlcXVlbmNlCQERQGV4dHJOYXRpdmUoMTA1MCkCBQR0aGlzCQEOdG9Db21wb3NpdGVLZXkCBRJrX3Bvc2l0aW9uU2VxdWVuY2UFB190cmFkZXIECnBEaXJlY3Rpb24JAQxnZXREaXJlY3Rpb24BBQVwU2l6ZQQLcG9zaXRpb25LZXkJAKwCAgkArAICBQdfdHJhZGVyAgFfCQCkAwEFCnBEaXJlY3Rpb24JAMwIAgkBC0RlbGV0ZUVudHJ5AQkBDnRvQ29tcG9zaXRlS2V5AgUOa19wb3NpdGlvblNpemUFB190cmFkZXIJAMwIAgkBC0RlbGV0ZUVudHJ5AQkBDnRvQ29tcG9zaXRlS2V5AgUQa19wb3NpdGlvbk1hcmdpbgUHX3RyYWRlcgkAzAgCCQELRGVsZXRlRW50cnkBCQEOdG9Db21wb3NpdGVLZXkCBRZrX3Bvc2l0aW9uT3Blbk5vdGlvbmFsBQdfdHJhZGVyCQDMCAIJAQtEZWxldGVFbnRyeQEJAQ50b0NvbXBvc2l0ZUtleQIFLmtfcG9zaXRpb25MYXN0VXBkYXRlZEN1bXVsYXRpdmVQcmVtaXVtRnJhY3Rpb24FB190cmFkZXIJAMwIAgkBC0RlbGV0ZUVudHJ5AQkBDnRvQ29tcG9zaXRlS2V5AgUea19wb3NpdGlvbkxhc3RVcGRhdGVkVGltZXN0YW1wBQdfdHJhZGVyCQDMCAIJAQtEZWxldGVFbnRyeQEJAQ50b0NvbXBvc2l0ZUtleQIFDWtfcG9zaXRpb25GZWUFB190cmFkZXIJAMwIAgkBC0RlbGV0ZUVudHJ5AQkBDnRvQ29tcG9zaXRlS2V5AgUSa19wb3NpdGlvblNlcXVlbmNlBQdfdHJhZGVyCQDMCAIJAQxJbnRlZ2VyRW50cnkCCQEOdG9Db21wb3NpdGVLZXkCBQ5rX3Bvc2l0aW9uU2l6ZQULcG9zaXRpb25LZXkFBXBTaXplCQDMCAIJAQxJbnRlZ2VyRW50cnkCCQEOdG9Db21wb3NpdGVLZXkCBRBrX3Bvc2l0aW9uTWFyZ2luBQtwb3NpdGlvbktleQUHcE1hcmdpbgkAzAgCCQEMSW50ZWdlckVudHJ5AgkBDnRvQ29tcG9zaXRlS2V5AgUWa19wb3NpdGlvbk9wZW5Ob3Rpb25hbAULcG9zaXRpb25LZXkFCXBOb3Rpb25hbAkAzAgCCQEMSW50ZWdlckVudHJ5AgkBDnRvQ29tcG9zaXRlS2V5AgUua19wb3NpdGlvbkxhc3RVcGRhdGVkQ3VtdWxhdGl2ZVByZW1pdW1GcmFjdGlvbgULcG9zaXRpb25LZXkFCXBGcmFjdGlvbgkAzAgCCQEMSW50ZWdlckVudHJ5AgkBDnRvQ29tcG9zaXRlS2V5AgUea19wb3NpdGlvbkxhc3RVcGRhdGVkVGltZXN0YW1wBQtwb3NpdGlvbktleQUKcFRpbWVzdGFtcAkAzAgCCQEMSW50ZWdlckVudHJ5AgkBDnRvQ29tcG9zaXRlS2V5AgUNa19wb3NpdGlvbkZlZQULcG9zaXRpb25LZXkFBHBGZWUJAMwIAgkBDEludGVnZXJFbnRyeQIJAQ50b0NvbXBvc2l0ZUtleQIFEmtfcG9zaXRpb25TZXF1ZW5jZQULcG9zaXRpb25LZXkFCXBTZXF1ZW5jZQUDbmlsCQACAQkArAICAhdOb3RoaW5nIHRvIG1pZ3JhdGUgZm9yIAUHX3RyYWRlcgFpASd2aWV3X2NhbGNSZW1haW5NYXJnaW5XaXRoRnVuZGluZ1BheW1lbnQDB190cmFkZXIKX2RpcmVjdGlvbgxfcHJpY2VVcGRhdGUEDHVwZGF0ZU9yYWNsZQkA/AcEBQR0aGlzAgx1cGRhdGVPcmFjbGUJAMwIAgUMX3ByaWNlVXBkYXRlBQNuaWwFA25pbAMJAAACBQx1cGRhdGVPcmFjbGUFDHVwZGF0ZU9yYWNsZQQEc3luYwkA/AcEBQR0aGlzAhlzeW5jVGVybWluYWxQcmljZVRvT3JhY2xlBQNuaWwFA25pbAMJAAACBQRzeW5jBQRzeW5jBA0kdDA4NjYxNDg2NzUwCQELZ2V0UG9zaXRpb24CBQdfdHJhZGVyBQpfZGlyZWN0aW9uBAxwb3NpdGlvblNpemUIBQ0kdDA4NjYxNDg2NzUwAl8xBA5wb3NpdGlvbk1hcmdpbggFDSR0MDg2NjE0ODY3NTACXzIEA3BvbggFDSR0MDg2NjE0ODY3NTACXzMEEXBvc2l0aW9uTHN0VXBkQ1BGCAUNJHQwODY2MTQ4Njc1MAJfNAQRcG9zaXRpb25UaW1lc3RhbXAIBQ0kdDA4NjYxNDg2NzUwAl81BA0kdDA4Njc1Mzg2ODY2CQEjZ2V0UG9zaXRpb25Ob3Rpb25hbEFuZFVucmVhbGl6ZWRQbmwDBQdfdHJhZGVyBQpfZGlyZWN0aW9uBQ9QTkxfT1BUSU9OX1NQT1QEEHBvc2l0aW9uTm90aW9uYWwIBQ0kdDA4Njc1Mzg2ODY2Al8xBA11bnJlYWxpemVkUG5sCAUNJHQwODY3NTM4Njg2NgJfMgQNJHQwODY4Njk4NzA5MwkBMGNhbGNSZW1haW5NYXJnaW5XaXRoRnVuZGluZ1BheW1lbnRBbmRSb2xsb3ZlckZlZQUFDHBvc2l0aW9uU2l6ZQUOcG9zaXRpb25NYXJnaW4FEXBvc2l0aW9uTHN0VXBkQ1BGBRFwb3NpdGlvblRpbWVzdGFtcAUNdW5yZWFsaXplZFBubAQMcmVtYWluTWFyZ2luCAUNJHQwODY4Njk4NzA5MwJfMQQHYmFkRGVidAgFDSR0MDg2ODY5ODcwOTMCXzIEDmZ1bmRpbmdQYXltZW50CAUNJHQwODY4Njk4NzA5MwJfMwQLcm9sbG92ZXJGZWUIBQ0kdDA4Njg2OTg3MDkzAl80BA91bmRlcmx5aW5nUHJpY2UJAQ5nZXRPcmFjbGVQcmljZQAECXNwb3RQcmljZQkBDGdldFNwb3RQcmljZQAJAAIBCQCsAgIJAKwCAgkArAICCQCsAgIJAKwCAgkArAICCQCsAgIJAKwCAgkBAXMBBQxyZW1haW5NYXJnaW4JAQFzAQUOZnVuZGluZ1BheW1lbnQJAQFzAQkBDmdldE1hcmdpblJhdGlvAgUHX3RyYWRlcgUKX2RpcmVjdGlvbgkBAXMBBQ11bnJlYWxpemVkUG5sCQEBcwEFB2JhZERlYnQJAQFzAQUQcG9zaXRpb25Ob3Rpb25hbAkBAXMBBQtyb2xsb3ZlckZlZQkBAXMBBQ91bmRlcmx5aW5nUHJpY2UJAQFzAQUJc3BvdFByaWNlCQACAQIkU3RyaWN0IHZhbHVlIGlzIG5vdCBlcXVhbCB0byBpdHNlbGYuCQACAQIkU3RyaWN0IHZhbHVlIGlzIG5vdCBlcXVhbCB0byBpdHNlbGYuAWkBFXZpZXdfZ2V0UGVnQWRqdXN0Q29zdAEGX3ByaWNlBAdfcXRBc3RSCQEGcXRBc3RSAAQHX2JzQXN0UgkBBmJzQXN0UgAEBnJlc3VsdAkBFGdldFN5bmNUZXJtaW5hbFByaWNlAwUGX3ByaWNlBQdfcXRBc3RSBQdfYnNBc3RSCQACAQkApAMBCAUGcmVzdWx0Al8zAWkBGHZpZXdfZ2V0VGVybWluYWxBbW1QcmljZQAEDSR0MDg3OTQ2ODgwMjcJARNnZXRUZXJtaW5hbEFtbVN0YXRlAAQZdGVybWluYWxRdW90ZUFzc2V0UmVzZXJ2ZQgFDSR0MDg3OTQ2ODgwMjcCXzEEGHRlcm1pbmFsQmFzZUFzc2V0UmVzZXJ2ZQgFDSR0MDg3OTQ2ODgwMjcCXzIEBXByaWNlCQEEZGl2ZAIJAQRtdWxkAgUZdGVybWluYWxRdW90ZUFzc2V0UmVzZXJ2ZQkBBnF0QXN0VwAJAQRtdWxkAgUYdGVybWluYWxCYXNlQXNzZXRSZXNlcnZlCQEGYnNBc3RXAAkAAgEJAKQDAQUFcHJpY2UBaQEPdmlld19nZXRGdW5kaW5nAQxfcHJpY2VVcGRhdGUEDHVwZGF0ZU9yYWNsZQkA/AcEBQR0aGlzAgx1cGRhdGVPcmFjbGUJAMwIAgUMX3ByaWNlVXBkYXRlBQNuaWwFA25pbAMJAAACBQx1cGRhdGVPcmFjbGUFDHVwZGF0ZU9yYWNsZQQEc3luYwkA/AcEBQR0aGlzAhlzeW5jVGVybWluYWxQcmljZVRvT3JhY2xlBQNuaWwFA25pbAMJAAACBQRzeW5jBQRzeW5jBA91bmRlcmx5aW5nUHJpY2UJAQ5nZXRPcmFjbGVQcmljZQAEDSR0MDg4Njc5ODg3NTcJAQpnZXRGdW5kaW5nAAQUc2hvcnRQcmVtaXVtRnJhY3Rpb24IBQ0kdDA4ODY3OTg4NzU3Al8xBBNsb25nUHJlbWl1bUZyYWN0aW9uCAUNJHQwODg2Nzk4ODc1NwJfMgQOcHJlbWl1bVRvVmF1bHQIBQ0kdDA4ODY3OTg4NzU3Al8zBAtsb25nRnVuZGluZwkBBGRpdmQCBRNsb25nUHJlbWl1bUZyYWN0aW9uBQ91bmRlcmx5aW5nUHJpY2UEDHNob3J0RnVuZGluZwkBBGRpdmQCBRRzaG9ydFByZW1pdW1GcmFjdGlvbgUPdW5kZXJseWluZ1ByaWNlCQACAQkArAICCQCsAgIJAKwCAgkArAICCQEBcwEFC2xvbmdGdW5kaW5nCQEBcwEFDHNob3J0RnVuZGluZwkBAXMBCQEMZ2V0U3BvdFByaWNlAAkBAXMBCQEOZ2V0T3JhY2xlUHJpY2UACQEBcwEFDnByZW1pdW1Ub1ZhdWx0CQACAQIkU3RyaWN0IHZhbHVlIGlzIG5vdCBlcXVhbCB0byBpdHNlbGYuCQACAQIkU3RyaWN0IHZhbHVlIGlzIG5vdCBlcXVhbCB0byBpdHNlbGYuAWkBEGNvbXB1dGVTcG90UHJpY2UABARzeW5jCQD8BwQFBHRoaXMCGXN5bmNUZXJtaW5hbFByaWNlVG9PcmFjbGUFA25pbAUDbmlsAwkAAAIFBHN5bmMFBHN5bmMEBnJlc3VsdAkBDGdldFNwb3RQcmljZQAJAJQKAgUDbmlsBQZyZXN1bHQJAAIBAiRTdHJpY3QgdmFsdWUgaXMgbm90IGVxdWFsIHRvIGl0c2VsZi4BaQEfY29tcHV0ZUZlZUZvclRyYWRlcldpdGhBcnRpZmFjdAIHX3RyYWRlcgtfYXJ0aWZhY3RJZAQGcmVzdWx0CQEYZ2V0Rm9yVHJhZGVyV2l0aEFydGlmYWN0AgUHX3RyYWRlcgULX2FydGlmYWN0SWQJAJQKAgUDbmlsBQZyZXN1bHQBAnR4AQZ2ZXJpZnkABA5jb29yZGluYXRvclN0cgkAnQgCBQR0aGlzBRRrX2Nvb3JkaW5hdG9yQWRkcmVzcwMJAQlpc0RlZmluZWQBBQ5jb29yZGluYXRvclN0cgQFYWRtaW4JAJ0IAgkBEUBleHRyTmF0aXZlKDEwNjIpAQkBBXZhbHVlAQUOY29vcmRpbmF0b3JTdHIFD2tfYWRtaW5fYWRkcmVzcwMJAQlpc0RlZmluZWQBBQVhZG1pbgkBC3ZhbHVlT3JFbHNlAgkAmwgCCQERQGV4dHJOYXRpdmUoMTA2MikBCQEFdmFsdWUBBQVhZG1pbgkArAICCQCsAgIJAKwCAgIHc3RhdHVzXwkApQgBBQR0aGlzAgFfCQDYBAEIBQJ0eAJpZAcJAAIBAi51bmFibGUgdG8gdmVyaWZ5OiBhZG1pbiBub3Qgc2V0IGluIGNvb3JkaW5hdG9yCQD0AwMIBQJ0eAlib2R5Qnl0ZXMJAJEDAggFAnR4BnByb29mcwAACAUCdHgPc2VuZGVyUHVibGljS2V5K7Oapw==", "height": 2695585, "applicationStatus": "succeeded", "spentComplexity": 0 } View: original | compacted Prev: 9gEMF5QXnHct6m6815nheTrbedDAQaqS6Aqq7cbGzAr4 Next: none Diff:
OldNewDifferences
17461746 let premiumToVault = $t08031680394._3
17471747 let doPayFundingToVault = if ((premiumToVault > 0))
17481748 then {
1749- let doPayFundingToVault = invoke(vaultAddress(), "exchangeFreeAndLocked", [-(premiumToVault)], nil)
1750- if ((doPayFundingToVault == doPayFundingToVault))
1751- then nil
1749+ let $t08046680528 = distributeFee(premiumToVault)
1750+ let feeToStakers = $t08046680528._1
1751+ let feeToVault = $t08046680528._2
1752+ let unstake = invoke(vaultAddress(), "withdrawLocked", [feeToStakers], nil)
1753+ if ((unstake == unstake))
1754+ then {
1755+ let addFundingPaymentToVault = invoke(vaultAddress(), "exchangeFreeAndLocked", [-(feeToVault)], nil)
1756+ if ((addFundingPaymentToVault == addFundingPaymentToVault))
1757+ then transferFee(feeToStakers)
1758+ else throw("Strict value is not equal to itself.")
1759+ }
17521760 else throw("Strict value is not equal to itself.")
17531761 }
17541762 else nil
17551763 if ((doPayFundingToVault == doPayFundingToVault))
1756- then updateFunding((fundingBlockTimestamp + fundingPeriodSeconds()), (latestLongCumulativePremiumFraction() + longPremiumFraction), (latestShortCumulativePremiumFraction() + shortPremiumFraction), divd(longPremiumFraction, underlyingPrice), divd(shortPremiumFraction, underlyingPrice))
1764+ then (updateFunding((fundingBlockTimestamp + fundingPeriodSeconds()), (latestLongCumulativePremiumFraction() + longPremiumFraction), (latestShortCumulativePremiumFraction() + shortPremiumFraction), divd(longPremiumFraction, underlyingPrice), divd(shortPremiumFraction, underlyingPrice)) ++ doPayFundingToVault)
17571765 else throw("Strict value is not equal to itself.")
17581766 }
17591767 }
17981806 func syncTerminalPriceToOracle () = {
17991807 let _qtAstR = qtAstR()
18001808 let _bsAstR = bsAstR()
1801- let $t08221182577 = getSyncTerminalPrice(getOraclePrice(), _qtAstR, _bsAstR)
1802- let newQuoteAssetWeight = $t08221182577._1
1803- let newBaseAssetWeight = $t08221182577._2
1804- let marginToVault = $t08221182577._3
1809+ let $t08245482820 = getSyncTerminalPrice(getOraclePrice(), _qtAstR, _bsAstR)
1810+ let newQuoteAssetWeight = $t08245482820._1
1811+ let newBaseAssetWeight = $t08245482820._2
1812+ let marginToVault = $t08245482820._3
18051813 let marginToVaultAdj = if (if ((0 > marginToVault))
18061814 then (abs(marginToVault) > cbalance())
18071815 else false)
18661874 let sync = invoke(this, "syncTerminalPriceToOracle", nil, nil)
18671875 if ((sync == sync))
18681876 then {
1869- let $t08637186507 = getPosition(_trader, _direction)
1870- let positionSize = $t08637186507._1
1871- let positionMargin = $t08637186507._2
1872- let pon = $t08637186507._3
1873- let positionLstUpdCPF = $t08637186507._4
1874- let positionTimestamp = $t08637186507._5
1875- let $t08651086623 = getPositionNotionalAndUnrealizedPnl(_trader, _direction, PNL_OPTION_SPOT)
1876- let positionNotional = $t08651086623._1
1877- let unrealizedPnl = $t08651086623._2
1878- let $t08662686850 = calcRemainMarginWithFundingPaymentAndRolloverFee(positionSize, positionMargin, positionLstUpdCPF, positionTimestamp, unrealizedPnl)
1879- let remainMargin = $t08662686850._1
1880- let badDebt = $t08662686850._2
1881- let fundingPayment = $t08662686850._3
1882- let rolloverFee = $t08662686850._4
1877+ let $t08661486750 = getPosition(_trader, _direction)
1878+ let positionSize = $t08661486750._1
1879+ let positionMargin = $t08661486750._2
1880+ let pon = $t08661486750._3
1881+ let positionLstUpdCPF = $t08661486750._4
1882+ let positionTimestamp = $t08661486750._5
1883+ let $t08675386866 = getPositionNotionalAndUnrealizedPnl(_trader, _direction, PNL_OPTION_SPOT)
1884+ let positionNotional = $t08675386866._1
1885+ let unrealizedPnl = $t08675386866._2
1886+ let $t08686987093 = calcRemainMarginWithFundingPaymentAndRolloverFee(positionSize, positionMargin, positionLstUpdCPF, positionTimestamp, unrealizedPnl)
1887+ let remainMargin = $t08686987093._1
1888+ let badDebt = $t08686987093._2
1889+ let fundingPayment = $t08686987093._3
1890+ let rolloverFee = $t08686987093._4
18831891 let underlyingPrice = getOraclePrice()
18841892 let spotPrice = getSpotPrice()
18851893 throw(((((((((s(remainMargin) + s(fundingPayment)) + s(getMarginRatio(_trader, _direction))) + s(unrealizedPnl)) + s(badDebt)) + s(positionNotional)) + s(rolloverFee)) + s(underlyingPrice)) + s(spotPrice)))
19031911
19041912 @Callable(i)
19051913 func view_getTerminalAmmPrice () = {
1906- let $t08770387784 = getTerminalAmmState()
1907- let terminalQuoteAssetReserve = $t08770387784._1
1908- let terminalBaseAssetReserve = $t08770387784._2
1914+ let $t08794688027 = getTerminalAmmState()
1915+ let terminalQuoteAssetReserve = $t08794688027._1
1916+ let terminalBaseAssetReserve = $t08794688027._2
19091917 let price = divd(muld(terminalQuoteAssetReserve, qtAstW()), muld(terminalBaseAssetReserve, bsAstW()))
19101918 throw(toString(price))
19111919 }
19211929 if ((sync == sync))
19221930 then {
19231931 let underlyingPrice = getOraclePrice()
1924- let $t08843688514 = getFunding()
1925- let shortPremiumFraction = $t08843688514._1
1926- let longPremiumFraction = $t08843688514._2
1927- let premiumToVault = $t08843688514._3
1932+ let $t08867988757 = getFunding()
1933+ let shortPremiumFraction = $t08867988757._1
1934+ let longPremiumFraction = $t08867988757._2
1935+ let premiumToVault = $t08867988757._3
19281936 let longFunding = divd(longPremiumFraction, underlyingPrice)
19291937 let shortFunding = divd(shortPremiumFraction, underlyingPrice)
19301938 throw(((((s(longFunding) + s(shortFunding)) + s(getSpotPrice())) + s(getOraclePrice())) + s(premiumToVault)))
Full:
OldNewDifferences
11 {-# STDLIB_VERSION 6 #-}
22 {-# SCRIPT_TYPE ACCOUNT #-}
33 {-# CONTENT_TYPE DAPP #-}
44 let k_baseOracle = "k_baseOracle"
55
66 let k_quoteOracle = "k_quoteOracle"
77
88 let k_balance = "k_balance"
99
1010 let k_sequence = "k_sequence"
1111
1212 let k_positionSize = "k_positionSize"
1313
1414 let k_positionMargin = "k_positionMargin"
1515
1616 let k_positionOpenNotional = "k_positionOpenNotional"
1717
1818 let k_positionLastUpdatedCumulativePremiumFraction = "k_positionFraction"
1919
2020 let k_positionSequence = "k_positionSequence"
2121
2222 let k_positionFee = "k_positionFee"
2323
2424 let k_positionLastUpdatedTimestamp = "k_positionTimestamp"
2525
2626 let k_initialized = "k_initialized"
2727
2828 let k_paused = "k_paused"
2929
3030 let k_closeOnly = "k_closeOnly"
3131
3232 let k_fee = "k_fee"
3333
3434 let k_rolloverFee = "k_rollover_fee"
3535
3636 let k_fundingPeriod = "k_fundingPeriod"
3737
3838 let k_initMarginRatio = "k_initMarginRatio"
3939
4040 let k_minInitMarginRatio = "k_minInitMarginRatio"
4141
4242 let k_maintenanceMarginRatio = "k_mmr"
4343
4444 let k_liquidationFeeRatio = "k_liquidationFeeRatio"
4545
4646 let k_partialLiquidationRatio = "k_partLiquidationRatio"
4747
4848 let k_spreadLimit = "k_spreadLimit"
4949
5050 let k_maxPriceImpact = "k_maxPriceImpact"
5151
5252 let k_maxPriceSpread = "k_maxPriceSpread"
5353
5454 let k_maxOpenNotional = "k_maxOpenNotional"
5555
5656 let k_feeToStakersPercent = "k_feeToStakersPercent"
5757
5858 let k_maxOracleDelay = "k_maxOracleDelay"
5959
6060 let k_fundingMode = "k_fundingMode"
6161
6262 let k_oracleMode = "k_oracleMode"
6363
6464 let k_positionMode = "k_positionMode"
6565
6666 let k_minLiquidationNotional = "k_minLiquidationNotional"
6767
6868 let k_latestLongCumulativePremiumFraction = "k_latestLongPremiumFraction"
6969
7070 let k_latestShortCumulativePremiumFraction = "k_latestShortPremiumFraction"
7171
7272 let k_nextFundingBlock = "k_nextFundingBlockMinTimestamp"
7373
7474 let k_longFundingRate = "k_longFundingRate"
7575
7676 let k_shortFundingRate = "k_shortFundingRate"
7777
7878 let k_quoteAssetReserve = "k_qtAstR"
7979
8080 let k_baseAssetReserve = "k_bsAstR"
8181
8282 let k_quoteAssetWeight = "k_qtAstW"
8383
8484 let k_baseAssetWeight = "k_bsAstW"
8585
8686 let k_totalPositionSize = "k_totalPositionSize"
8787
8888 let k_totalLongPositionSize = "k_totalLongPositionSize"
8989
9090 let k_totalShortPositionSize = "k_totalShortPositionSize"
9191
9292 let k_openInterestNotional = "k_openInterestNotional"
9393
9494 let k_openInterestShort = "k_openInterestShort"
9595
9696 let k_openInterestLong = "k_openInterestLong"
9797
9898 let k_lastTx = "k_lastTx"
9999
100100 let k_coordinatorAddress = "k_coordinatorAddress"
101101
102102 let k_vault_address = "k_vault_address"
103103
104104 let k_admin_address = "k_admin_address"
105105
106106 let k_quote_asset = "k_quote_asset"
107107
108108 let k_staking_address = "k_staking_address"
109109
110110 let k_miner_address = "k_miner_address"
111111
112112 let k_orders_address = "k_orders_address"
113113
114114 let k_referral_address = "k_referral_address"
115115
116116 let k_nft_manager_address = "k_nft_manager_address"
117117
118118 func toCompositeKey (_key,_address) = ((_key + "_") + _address)
119119
120120
121121 func coordinator () = valueOrErrorMessage(addressFromString(getStringValue(this, k_coordinatorAddress)), "Coordinator not set")
122122
123123
124124 func adminAddress () = addressFromString(getStringValue(coordinator(), k_admin_address))
125125
126126
127127 func quoteAsset () = fromBase58String(getStringValue(coordinator(), k_quote_asset))
128128
129129
130130 func stakingAddress () = valueOrErrorMessage(addressFromString(getStringValue(coordinator(), k_staking_address)), "Staking not set")
131131
132132
133133 func vaultAddress () = valueOrErrorMessage(addressFromString(getStringValue(coordinator(), k_vault_address)), "Vault not set")
134134
135135
136136 func minerAddress () = valueOrErrorMessage(addressFromString(getStringValue(coordinator(), k_miner_address)), "Miner not set")
137137
138138
139139 func ordersAddress () = valueOrErrorMessage(addressFromString(getStringValue(coordinator(), k_orders_address)), "Orders not set")
140140
141141
142142 func referralAddress () = valueOrErrorMessage(addressFromString(getStringValue(coordinator(), k_referral_address)), "Referral not set")
143143
144144
145145 func nftManagerAddress () = valueOrErrorMessage(addressFromString(getStringValue(coordinator(), k_nft_manager_address)), "NFT Manager not set")
146146
147147
148148 let k_token_param = "k_token_param"
149149
150150 let k_token_type = "k_token_type"
151151
152152 let FEE_REDUCTION_TOKEN_TYPE = "fee_reduction"
153153
154154 let DIR_LONG = 1
155155
156156 let DIR_SHORT = 2
157157
158158 let SECONDS = 1000
159159
160160 let DECIMAL_NUMBERS = 6
161161
162162 let DECIMAL_UNIT = (1 * (((((10 * 10) * 10) * 10) * 10) * 10))
163163
164164 let MINUTES_IN_YEAR = (525600 * DECIMAL_UNIT)
165165
166166 let ONE_DAY = (86400 * DECIMAL_UNIT)
167167
168168 let PNL_OPTION_SPOT = 1
169169
170170 let PNL_OPTION_ORACLE = 2
171171
172172 let FUNDING_ASYMMETRIC = 1
173173
174174 let FUNDING_SYMMETRIC = 2
175175
176176 let ORACLE_PLAIN = 1
177177
178178 let ORACLE_JIT = 2
179179
180180 let POSITION_DIRECT = 1
181181
182182 let POSITION_ORDER = 2
183183
184184 func s (_x) = (toString(_x) + ",")
185185
186186
187187 func divd (_x,_y) = fraction(_x, DECIMAL_UNIT, _y, HALFEVEN)
188188
189189
190190 func muld (_x,_y) = fraction(_x, _y, DECIMAL_UNIT, HALFEVEN)
191191
192192
193193 func bdivd (_x,_y) = fraction(_x, toBigInt(DECIMAL_UNIT), _y, HALFEVEN)
194194
195195
196196 func bmuld (_x,_y) = fraction(_x, _y, toBigInt(DECIMAL_UNIT), HALFEVEN)
197197
198198
199199 func abs (_x) = if ((_x > 0))
200200 then _x
201201 else -(_x)
202202
203203
204204 func vmax (_x,_y) = if ((_x >= _y))
205205 then _x
206206 else _y
207207
208208
209209 func int (k) = valueOrErrorMessage(getInteger(this, k), ("no value for " + k))
210210
211211
212212 func intOr (k,def) = valueOrElse(getInteger(this, k), def)
213213
214214
215215 func strA (_address,_key) = {
216216 let val = valueOrErrorMessage(getString(_address, _key), ("No value for key " + _key))
217217 val
218218 }
219219
220220
221221 func intA (_address,_key) = {
222222 let val = valueOrErrorMessage(getInteger(_address, _key), ("No value for key " + _key))
223223 val
224224 }
225225
226226
227227 func cbalance () = int(k_balance)
228228
229229
230230 func cbalance0 () = intOr(k_balance, 0)
231231
232232
233233 func fee () = int(k_fee)
234234
235235
236236 func rolloverFeeRate () = int(k_rolloverFee)
237237
238238
239239 func initMarginRatio () = int(k_initMarginRatio)
240240
241241
242242 func minInitMarginRatio () = intOr(k_minInitMarginRatio, (10 * DECIMAL_UNIT))
243243
244244
245245 func qtAstR () = int(k_quoteAssetReserve)
246246
247247
248248 func qtAstR0 () = intOr(k_quoteAssetReserve, 0)
249249
250250
251251 func bsAstR () = int(k_baseAssetReserve)
252252
253253
254254 func bsAstR0 () = intOr(k_baseAssetReserve, 0)
255255
256256
257257 func qtAstW () = intOr(k_quoteAssetWeight, DECIMAL_UNIT)
258258
259259
260260 func bsAstW () = intOr(k_baseAssetWeight, DECIMAL_UNIT)
261261
262262
263263 func totalPositionSize () = int(k_totalPositionSize)
264264
265265
266266 func openInterestNotional () = int(k_openInterestNotional)
267267
268268
269269 func openInterestShort () = int(k_openInterestShort)
270270
271271
272272 func openInterestLong () = int(k_openInterestLong)
273273
274274
275275 func nextFundingBlockTimestamp () = int(k_nextFundingBlock)
276276
277277
278278 func fundingPeriodRaw () = int(k_fundingPeriod)
279279
280280
281281 func fundingPeriodDecimal () = (fundingPeriodRaw() * DECIMAL_UNIT)
282282
283283
284284 func fundingPeriodSeconds () = (fundingPeriodRaw() * SECONDS)
285285
286286
287287 func maintenanceMarginRatio () = int(k_maintenanceMarginRatio)
288288
289289
290290 func liquidationFeeRatio () = int(k_liquidationFeeRatio)
291291
292292
293293 func partialLiquidationRatio () = int(k_partialLiquidationRatio)
294294
295295
296296 func spreadLimit () = int(k_spreadLimit)
297297
298298
299299 func maxPriceImpact () = int(k_maxPriceImpact)
300300
301301
302302 func maxPriceSpread () = int(k_maxPriceSpread)
303303
304304
305305 func maxOpenNotional () = int(k_maxOpenNotional)
306306
307307
308308 func latestLongCumulativePremiumFraction () = int(k_latestLongCumulativePremiumFraction)
309309
310310
311311 func latestShortCumulativePremiumFraction () = int(k_latestShortCumulativePremiumFraction)
312312
313313
314314 func totalShortPositionSize () = int(k_totalShortPositionSize)
315315
316316
317317 func totalLongPositionSize () = int(k_totalLongPositionSize)
318318
319319
320320 func lastSequence () = intOr(k_sequence, 0)
321321
322322
323323 func feeToStakersPercent () = int(k_feeToStakersPercent)
324324
325325
326326 func maxOracleDelay () = int(k_maxOracleDelay)
327327
328328
329329 func fundingMode () = intOr(k_fundingMode, FUNDING_ASYMMETRIC)
330330
331331
332332 func oracleMode () = intOr(k_oracleMode, ORACLE_PLAIN)
333333
334334
335335 func positionMode () = intOr(k_positionMode, POSITION_DIRECT)
336336
337337
338338 func minPartialLiquidationNotional () = intOr(k_minLiquidationNotional, (10 * DECIMAL_UNIT))
339339
340340
341341 func lastTimestamp () = lastBlock.timestamp
342342
343343
344344 func getActualCaller (i) = valueOrElse(getString(ordersAddress(), "k_sender"), toString(i.caller))
345345
346346
347347 func requireMoreMarginRatio (_marginRatio,_baseMarginRatio,_largerThanOrEqualTo) = {
348348 let remainingMarginRatio = (_marginRatio - _baseMarginRatio)
349349 if (if (_largerThanOrEqualTo)
350350 then (0 > remainingMarginRatio)
351351 else false)
352352 then throw(((("Invalid margin: " + toString(_marginRatio)) + " < ") + toString(_baseMarginRatio)))
353353 else if (if (!(_largerThanOrEqualTo))
354354 then (remainingMarginRatio >= 0)
355355 else false)
356356 then throw(((("Invalid margin: " + toString(_marginRatio)) + " > ") + toString(_baseMarginRatio)))
357357 else true
358358 }
359359
360360
361361 func latestCumulativePremiumFraction (_positionSize) = if ((_positionSize == 0))
362362 then throw("Should not be called with _positionSize == 0")
363363 else if ((_positionSize > 0))
364364 then latestLongCumulativePremiumFraction()
365365 else latestShortCumulativePremiumFraction()
366366
367367
368368 func getPosition (_trader,_direction) = {
369369 let positionKey = ((_trader + "_") + toString(_direction))
370370 let positionSizeOpt = getInteger(this, toCompositeKey(k_positionSize, positionKey))
371371 match positionSizeOpt {
372372 case positionSize: Int =>
373373 $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)))
374374 case _ =>
375375 $Tuple5(0, 0, 0, 0, 0)
376376 }
377377 }
378378
379379
380380 func getDirection (_positionSize) = if ((0 > _positionSize))
381381 then DIR_SHORT
382382 else DIR_LONG
383383
384384
385385 func getPositionFee (_trader,_direction) = {
386386 let positionKey = ((_trader + "_") + toString(_direction))
387387 let positionFeeOpt = getInteger(this, toCompositeKey(k_positionFee, positionKey))
388388 match positionFeeOpt {
389389 case positionFee: Int =>
390390 positionFee
391391 case _ =>
392392 fee()
393393 }
394394 }
395395
396396
397397 func requireOpenPosition (_trader,_direction) = if ((getPosition(_trader, _direction)._1 == 0))
398398 then throw("No open position")
399399 else true
400400
401401
402402 func getOracleData (key) = {
403403 let oracleDataStr = getString(this, key)
404404 if (if (isDefined(oracleDataStr))
405405 then (value(oracleDataStr) != "")
406406 else false)
407407 then {
408408 let oracleData = split(value(oracleDataStr), ",")
409409 let oracleAddress = valueOrErrorMessage(addressFromString(oracleData[0]), ("Invalid oracle address in: " + value(oracleDataStr)))
410410 let priceKey = oracleData[1]
411411 let blockKey = oracleData[2]
412412 let openKey = oracleData[3]
413413 $Tuple4(oracleAddress, priceKey, blockKey, openKey)
414414 }
415415 else unit
416416 }
417417
418418
419419 func initialized () = valueOrElse(getBoolean(this, k_initialized), false)
420420
421421
422422 func paused () = valueOrElse(getBoolean(this, k_paused), false)
423423
424424
425425 func closeOnly () = valueOrElse(getBoolean(this, k_closeOnly), false)
426426
427427
428428 func updateReserve (_isAdd,_quoteAssetAmount,_baseAssetAmount) = if (_isAdd)
429429 then {
430430 let newBase = (bsAstR() - _baseAssetAmount)
431431 if ((0 >= newBase))
432432 then throw("Tx lead to base asset reserve <= 0, revert")
433433 else $Tuple3((qtAstR() + _quoteAssetAmount), newBase, (totalPositionSize() + _baseAssetAmount))
434434 }
435435 else {
436436 let newQuote = (qtAstR() - _quoteAssetAmount)
437437 if ((0 >= newQuote))
438438 then throw("Tx lead to base quote reserve <= 0, revert")
439439 else $Tuple3(newQuote, (bsAstR() + _baseAssetAmount), (totalPositionSize() - _baseAssetAmount))
440440 }
441441
442442
443443 func calcInvariant (_qtAstR,_bsAstR) = {
444444 let bqtAstR = toBigInt(_qtAstR)
445445 let bbsAstR = toBigInt(_bsAstR)
446446 bmuld(bqtAstR, bbsAstR)
447447 }
448448
449449
450450 func swapInput (_isAdd,_quoteAssetAmount) = {
451451 let _qtAstR = qtAstR()
452452 let _bsAstR = bsAstR()
453453 let _qtAstW = qtAstW()
454454 let _bsAstW = bsAstW()
455455 let quoteAssetAmountAdjusted = divd(_quoteAssetAmount, _qtAstW)
456456 let k = calcInvariant(_qtAstR, _bsAstR)
457457 let quoteAssetReserveAfter = if (_isAdd)
458458 then (_qtAstR + quoteAssetAmountAdjusted)
459459 else (_qtAstR - quoteAssetAmountAdjusted)
460460 let baseAssetReserveAfter = toInt(bdivd(k, toBigInt(quoteAssetReserveAfter)))
461461 let amountBaseAssetBoughtAbs = abs((baseAssetReserveAfter - _bsAstR))
462462 let amountBaseAssetBought = if (_isAdd)
463463 then amountBaseAssetBoughtAbs
464464 else -(amountBaseAssetBoughtAbs)
465465 let $t01659016760 = updateReserve(_isAdd, quoteAssetAmountAdjusted, amountBaseAssetBoughtAbs)
466466 let quoteAssetReserveAfter1 = $t01659016760._1
467467 let baseAssetReserveAfter1 = $t01659016760._2
468468 let totalPositionSizeAfter1 = $t01659016760._3
469469 let priceBefore = divd(muld(_qtAstR, _qtAstW), muld(_bsAstR, _bsAstW))
470470 let marketPrice = divd(_quoteAssetAmount, amountBaseAssetBoughtAbs)
471471 let priceDiff = abs((priceBefore - marketPrice))
472472 let priceImpact = (DECIMAL_UNIT - divd(priceBefore, (priceBefore + priceDiff)))
473473 let maxPriceImpactValue = maxPriceImpact()
474474 if ((priceImpact > maxPriceImpactValue))
475475 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)))
476476 else $Tuple4(amountBaseAssetBought, quoteAssetReserveAfter1, baseAssetReserveAfter1, totalPositionSizeAfter1)
477477 }
478478
479479
480480 func calcRolloverFee (_oldPositionMargin,_oldPositionLastUpdatedTimestamp) = {
481481 let positionMinutes = ((((lastTimestamp() - _oldPositionLastUpdatedTimestamp) / 1000) / 60) * DECIMAL_UNIT)
482482 let rolloverFee = divd(muld(muld(_oldPositionMargin, positionMinutes), rolloverFeeRate()), MINUTES_IN_YEAR)
483483 rolloverFee
484484 }
485485
486486
487487 func calcRemainMarginWithFundingPaymentAndRolloverFee (_oldPositionSize,_oldPositionMargin,_oldPositionCumulativePremiumFraction,_oldPositionLastUpdatedTimestamp,_marginDelta) = {
488488 let fundingPayment = if ((_oldPositionSize != 0))
489489 then {
490490 let _latestCumulativePremiumFraction = latestCumulativePremiumFraction(_oldPositionSize)
491491 muld((_latestCumulativePremiumFraction - _oldPositionCumulativePremiumFraction), _oldPositionSize)
492492 }
493493 else 0
494494 let rolloverFee = calcRolloverFee(_oldPositionMargin, _oldPositionLastUpdatedTimestamp)
495495 let signedMargin = (((_marginDelta - rolloverFee) - fundingPayment) + _oldPositionMargin)
496496 let $t01942719554 = if ((0 > signedMargin))
497497 then $Tuple2(0, abs(signedMargin))
498498 else $Tuple2(abs(signedMargin), 0)
499499 let remainMargin = $t01942719554._1
500500 let badDebt = $t01942719554._2
501501 $Tuple4(remainMargin, badDebt, fundingPayment, rolloverFee)
502502 }
503503
504504
505505 func swapOutputWithReserves (_isAdd,_baseAssetAmount,_checkMaxPriceImpact,_quoteAssetReserve,_quoteAssetWeight,_baseAssetReserve,_baseAssetWeight) = {
506506 let priceBefore = divd(muld(_quoteAssetReserve, _quoteAssetWeight), muld(_baseAssetReserve, _baseAssetWeight))
507507 if ((_baseAssetAmount == 0))
508508 then throw("Invalid base asset amount")
509509 else {
510510 let k = calcInvariant(_quoteAssetReserve, _baseAssetReserve)
511511 let baseAssetPoolAmountAfter = if (_isAdd)
512512 then (_baseAssetReserve + _baseAssetAmount)
513513 else (_baseAssetReserve - _baseAssetAmount)
514514 let quoteAssetAfter = toInt(bdivd(k, toBigInt(baseAssetPoolAmountAfter)))
515515 let quoteAssetDelta = abs((quoteAssetAfter - _quoteAssetReserve))
516516 let quoteAssetSold = muld(quoteAssetDelta, _quoteAssetWeight)
517517 let maxPriceImpactValue = maxPriceImpact()
518518 let $t02081620978 = updateReserve(!(_isAdd), quoteAssetDelta, _baseAssetAmount)
519519 let quoteAssetReserveAfter1 = $t02081620978._1
520520 let baseAssetReserveAfter1 = $t02081620978._2
521521 let totalPositionSizeAfter1 = $t02081620978._3
522522 let marketPrice = divd(quoteAssetSold, _baseAssetAmount)
523523 let priceDiff = abs((priceBefore - marketPrice))
524524 let priceImpact = (DECIMAL_UNIT - divd(priceBefore, (priceBefore + priceDiff)))
525525 if (if ((priceImpact > maxPriceImpactValue))
526526 then _checkMaxPriceImpact
527527 else false)
528528 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)))
529529 else $Tuple7(quoteAssetSold, quoteAssetReserveAfter1, baseAssetReserveAfter1, totalPositionSizeAfter1, (totalLongPositionSize() - (if (_isAdd)
530530 then abs(_baseAssetAmount)
531531 else 0)), (totalShortPositionSize() - (if (!(_isAdd))
532532 then abs(_baseAssetAmount)
533533 else 0)), priceImpact)
534534 }
535535 }
536536
537537
538538 func swapOutput (_isAdd,_baseAssetAmount,_checkMaxPriceImpact) = swapOutputWithReserves(_isAdd, _baseAssetAmount, _checkMaxPriceImpact, qtAstR(), qtAstW(), bsAstR(), bsAstW())
539539
540540
541541 func getOraclePriceValue (oracle,priceKey,blockKey) = {
542542 let lastValue = valueOrErrorMessage(getInteger(oracle, priceKey), ((("Can not get oracle price. Oracle: " + toString(oracle)) + " key: ") + priceKey))
543543 if ((blockKey != ""))
544544 then {
545545 let currentBlock = height
546546 let lastOracleBlock = valueOrErrorMessage(getInteger(oracle, blockKey), ((("Can not get oracle block. Oracle: " + toString(oracle)) + " key: ") + blockKey))
547547 if (((currentBlock - lastOracleBlock) > maxOracleDelay()))
548548 then throw(((("Oracle stale data. Last oracle block: " + toString(lastOracleBlock)) + " current block: ") + toString(currentBlock)))
549549 else lastValue
550550 }
551551 else lastValue
552552 }
553553
554554
555555 func getOraclePrice () = {
556556 let baseOracle = valueOrErrorMessage(getOracleData(k_baseOracle), "No base asset oracle data")
557557 let baseOraclePrice = getOraclePriceValue(baseOracle._1, baseOracle._2, baseOracle._3)
558558 let quoteOracle = getOracleData(k_quoteOracle)
559559 let quoteOraclePrice = if (isDefined(quoteOracle))
560560 then {
561561 let quoteOracleV = value(quoteOracle)
562562 getOraclePriceValue(quoteOracleV._1, quoteOracleV._2, quoteOracleV._3)
563563 }
564564 else DECIMAL_UNIT
565565 divd(baseOraclePrice, quoteOraclePrice)
566566 }
567567
568568
569569 func isMarketClosed () = {
570570 let baseOracle = valueOrErrorMessage(getOracleData(k_baseOracle), "No base asset oracle data")
571571 let oracle = baseOracle._1
572572 let openKey = baseOracle._4
573573 if ((openKey != ""))
574574 then {
575575 let isOpen = valueOrErrorMessage(getBoolean(oracle, openKey), ((("Can not get oracle is open/closed. Oracle: " + toString(oracle)) + " key: ") + openKey))
576576 !(isOpen)
577577 }
578578 else false
579579 }
580580
581581
582582 func absPriceDiff (_oraclePrice,_quoteAssetReserve,_baseAssetReserve,_qtAstW,_bsAstW) = {
583583 let priceAfter = divd(muld(_quoteAssetReserve, _qtAstW), muld(_baseAssetReserve, _bsAstW))
584584 let averagePrice = divd((_oraclePrice + priceAfter), (2 * DECIMAL_UNIT))
585585 let absPriceDiff = divd(abs((_oraclePrice - priceAfter)), averagePrice)
586586 absPriceDiff
587587 }
588588
589589
590590 func requireNotOverSpreadLimit (_quoteAssetReserve,_baseAssetReserve) = {
591591 let oraclePrice = getOraclePrice()
592592 let _qtAstW = qtAstW()
593593 let _bsAstW = bsAstW()
594594 let absPriceDiffBefore = absPriceDiff(oraclePrice, qtAstR(), bsAstR(), _qtAstW, _bsAstW)
595595 let absPriceDiffAfter = absPriceDiff(oraclePrice, _quoteAssetReserve, _baseAssetReserve, _qtAstW, _bsAstW)
596596 if (if ((absPriceDiffAfter > maxPriceSpread()))
597597 then (absPriceDiffAfter > absPriceDiffBefore)
598598 else false)
599599 then throw(((("Price spread " + toString(absPriceDiffAfter)) + " > max price spread ") + toString(maxPriceSpread())))
600600 else true
601601 }
602602
603603
604604 func requireNotOverMaxOpenNotional (_longOpenNotional,_shortOpenNotional) = {
605605 let _maxOpenNotional = maxOpenNotional()
606606 if ((_longOpenNotional > _maxOpenNotional))
607607 then throw(((("Long open notional " + toString(_longOpenNotional)) + " > max open notional ") + toString(_maxOpenNotional)))
608608 else if ((_shortOpenNotional > _maxOpenNotional))
609609 then throw(((("Short open notional " + toString(_shortOpenNotional)) + " > max open notional ") + toString(_maxOpenNotional)))
610610 else true
611611 }
612612
613613
614614 func requireSenderCanWorkWithPositions (_caller) = if ((positionMode() == POSITION_ORDER))
615615 then (_caller == ordersAddress())
616616 else true
617617
618618
619619 func getSpotPrice () = {
620620 let _quoteAssetReserve = qtAstR()
621621 let _baseAssetReserve = bsAstR()
622622 let _qtAstW = qtAstW()
623623 let _bsAstW = bsAstW()
624624 divd(muld(_quoteAssetReserve, _qtAstW), muld(_baseAssetReserve, _bsAstW))
625625 }
626626
627627
628628 func isOverFluctuationLimit () = {
629629 let oraclePrice = getOraclePrice()
630630 let currentPrice = getSpotPrice()
631631 (divd(abs((oraclePrice - currentPrice)), oraclePrice) > spreadLimit())
632632 }
633633
634634
635635 func getPositionAdjustedOpenNotional (_positionSize,_option,_quoteAssetReserve,_quoteAssetWeight,_baseAssetReserve,_baseAssetWeight) = {
636636 let positionSizeAbs = abs(_positionSize)
637637 let isShort = (0 > _positionSize)
638638 let positionNotional = if ((_option == PNL_OPTION_SPOT))
639639 then {
640640 let outPositionNotional = swapOutputWithReserves(!(isShort), positionSizeAbs, false, _quoteAssetReserve, _quoteAssetWeight, _baseAssetReserve, _baseAssetWeight)._1
641641 outPositionNotional
642642 }
643643 else muld(positionSizeAbs, getOraclePrice())
644644 positionNotional
645645 }
646646
647647
648648 func getPositionNotionalAndUnrealizedPnlByValues (_positionSize,_positionOpenNotional,_quoteAssetReserve,_quoteAssetWeight,_baseAssetReserve,_baseAssetWeight,_option) = if ((_positionSize == 0))
649649 then throw("Invalid position size")
650650 else {
651651 let isShort = (0 > _positionSize)
652652 let positionNotional = getPositionAdjustedOpenNotional(_positionSize, _option, _quoteAssetReserve, _quoteAssetWeight, _baseAssetReserve, _baseAssetWeight)
653653 let unrealizedPnl = if (isShort)
654654 then (_positionOpenNotional - positionNotional)
655655 else (positionNotional - _positionOpenNotional)
656656 $Tuple2(positionNotional, unrealizedPnl)
657657 }
658658
659659
660660 func getPositionNotionalAndUnrealizedPnl (_trader,_direction,_option) = {
661661 let $t02911929259 = getPosition(_trader, _direction)
662662 let positionSize = $t02911929259._1
663663 let positionMargin = $t02911929259._2
664664 let positionOpenNotional = $t02911929259._3
665665 let positionLstUpdCPF = $t02911929259._4
666666 getPositionNotionalAndUnrealizedPnlByValues(positionSize, positionOpenNotional, qtAstR(), qtAstW(), bsAstR(), bsAstW(), _option)
667667 }
668668
669669
670670 func calcMarginRatio (_remainMargin,_badDebt,_positionNotional) = divd((_remainMargin - _badDebt), _positionNotional)
671671
672672
673673 func getMarginRatioByOption (_trader,_direction,_option) = {
674674 let $t02979129944 = getPosition(_trader, _direction)
675675 let positionSize = $t02979129944._1
676676 let positionMargin = $t02979129944._2
677677 let pon = $t02979129944._3
678678 let positionLastUpdatedCPF = $t02979129944._4
679679 let positionTimestamp = $t02979129944._5
680680 let $t02995030055 = getPositionNotionalAndUnrealizedPnl(_trader, _direction, _option)
681681 let positionNotional = $t02995030055._1
682682 let unrealizedPnl = $t02995030055._2
683683 let $t03006030272 = calcRemainMarginWithFundingPaymentAndRolloverFee(positionSize, positionMargin, positionLastUpdatedCPF, positionTimestamp, unrealizedPnl)
684684 let remainMargin = $t03006030272._1
685685 let badDebt = $t03006030272._2
686686 calcMarginRatio(remainMargin, badDebt, positionNotional)
687687 }
688688
689689
690690 func getMarginRatio (_trader,_direction) = getMarginRatioByOption(_trader, _direction, PNL_OPTION_SPOT)
691691
692692
693693 func getPartialLiquidationAmount (_trader,_positionSize) = {
694694 let maximumRatio = vmax(partialLiquidationRatio(), (DECIMAL_UNIT - divd(getMarginRatio(_trader, getDirection(_positionSize)), maintenanceMarginRatio())))
695695 let maxExchangedPositionSize = muld(abs(_positionSize), maximumRatio)
696696 let swapResult = swapOutput((_positionSize > 0), maxExchangedPositionSize, false)
697697 let maxExchangedQuoteAssetAmount = swapResult._1
698698 let priceImpact = swapResult._7
699699 if ((maxPriceImpact() > priceImpact))
700700 then maxExchangedPositionSize
701701 else muld(abs(_positionSize), partialLiquidationRatio())
702702 }
703703
704704
705705 func internalClosePosition (_trader,_direction,_size,_fee,_minQuoteAssetAmount,_addToMargin,_checkMaxPriceImpact,_liquidate) = {
706706 let $t03143531603 = getPosition(_trader, _direction)
707707 let oldPositionSize = $t03143531603._1
708708 let oldPositionMargin = $t03143531603._2
709709 let oldPositionOpenNotional = $t03143531603._3
710710 let oldPositionLstUpdCPF = $t03143531603._4
711711 let oldPositionTimestamp = $t03143531603._5
712712 let isLongPosition = (oldPositionSize > 0)
713713 let absOldPositionSize = abs(oldPositionSize)
714714 if (if ((absOldPositionSize >= _size))
715715 then (_size > 0)
716716 else false)
717717 then {
718718 let isPartialClose = (absOldPositionSize > _size)
719719 let $t03189532346 = swapOutput((oldPositionSize > 0), _size, _checkMaxPriceImpact)
720720 let exchangedQuoteAssetAmount = $t03189532346._1
721721 let quoteAssetReserveAfter = $t03189532346._2
722722 let baseAssetReserveAfter = $t03189532346._3
723723 let totalPositionSizeAfter = $t03189532346._4
724724 let exchangedPositionSize = if ((oldPositionSize > 0))
725725 then -(_size)
726726 else _size
727727 let $t03256132785 = getPositionNotionalAndUnrealizedPnl(_trader, _direction, PNL_OPTION_SPOT)
728728 let oldPositionNotional = $t03256132785._1
729729 let unrealizedPnl = $t03256132785._2
730730 let realizedRatio = divd(abs(exchangedPositionSize), absOldPositionSize)
731731 let realizedPnl = muld(unrealizedPnl, realizedRatio)
732732 let $t03312633372 = calcRemainMarginWithFundingPaymentAndRolloverFee(oldPositionSize, oldPositionMargin, oldPositionLstUpdCPF, oldPositionTimestamp, unrealizedPnl)
733733 let remainMarginBefore = $t03312633372._1
734734 let x1 = $t03312633372._2
735735 let x2 = $t03312633372._3
736736 let rolloverFee = $t03312633372._4
737737 let positionBadDebt = calcRemainMarginWithFundingPaymentAndRolloverFee(oldPositionSize, oldPositionMargin, oldPositionLstUpdCPF, oldPositionTimestamp, realizedPnl)._2
738738 let realizedCloseFee = muld(muld(oldPositionNotional, realizedRatio), _fee)
739739 let unrealizedPnlAfter = (unrealizedPnl - realizedPnl)
740740 let remainOpenNotional = if ((oldPositionSize > 0))
741741 then ((oldPositionNotional - exchangedQuoteAssetAmount) - unrealizedPnlAfter)
742742 else ((unrealizedPnlAfter + oldPositionNotional) - exchangedQuoteAssetAmount)
743743 let newPositionSize = (oldPositionSize + exchangedPositionSize)
744744 let $t03477835164 = if ((newPositionSize == 0))
745745 then $Tuple2(0, 0)
746746 else $Tuple2(abs(remainOpenNotional), latestCumulativePremiumFraction(newPositionSize))
747747 let newPositionOpenNotional = $t03477835164._1
748748 let newPositionLstUpdCPF = $t03477835164._2
749749 let openNotionalDelta = (oldPositionOpenNotional - newPositionOpenNotional)
750750 let marginRatio = getMarginRatioByOption(_trader, _direction, PNL_OPTION_SPOT)
751751 let newPositionMarginWithSameRatio = if ((oldPositionSize > 0))
752752 then (muld((newPositionOpenNotional + unrealizedPnlAfter), marginRatio) - unrealizedPnlAfter)
753753 else (muld((newPositionOpenNotional - unrealizedPnlAfter), marginRatio) - unrealizedPnlAfter)
754754 let marginToTraderRaw = ((remainMarginBefore - (newPositionMarginWithSameRatio + unrealizedPnlAfter)) - realizedCloseFee)
755755 let marginToTrader = if ((0 > marginToTraderRaw))
756756 then if (_liquidate)
757757 then 0
758758 else throw("Invalid internalClosePosition params: unable to pay fee")
759759 else marginToTraderRaw
760760 let newPositionMargin = if (_addToMargin)
761761 then (newPositionMarginWithSameRatio + marginToTrader)
762762 else newPositionMarginWithSameRatio
763763 if (if ((_minQuoteAssetAmount != 0))
764764 then (_minQuoteAssetAmount > exchangedQuoteAssetAmount)
765765 else false)
766766 then throw(((("Limit error: " + toString(exchangedQuoteAssetAmount)) + " < ") + toString(_minQuoteAssetAmount)))
767767 else $Tuple17(newPositionSize, newPositionMargin, newPositionOpenNotional, newPositionLstUpdCPF, positionBadDebt, realizedPnl, if (if (_addToMargin)
768768 then isPartialClose
769769 else false)
770770 then 0
771771 else marginToTrader, quoteAssetReserveAfter, baseAssetReserveAfter, totalPositionSizeAfter, (openInterestNotional() - openNotionalDelta), (totalLongPositionSize() - (if (isLongPosition)
772772 then abs(exchangedPositionSize)
773773 else 0)), (totalShortPositionSize() - (if (!(isLongPosition))
774774 then abs(exchangedPositionSize)
775775 else 0)), (openInterestLong() - (if (isLongPosition)
776776 then openNotionalDelta
777777 else 0)), (openInterestShort() - (if (!(isLongPosition))
778778 then openNotionalDelta
779779 else 0)), (realizedCloseFee + rolloverFee), exchangedQuoteAssetAmount)
780780 }
781781 else throw(((("Invalid internalClosePosition params: invalid position size: " + toString(_size)) + " max: ") + toString(absOldPositionSize)))
782782 }
783783
784784
785785 func getTerminalAmmState () = {
786786 let _positionSize = totalPositionSize()
787787 if ((_positionSize == 0))
788788 then $Tuple2(qtAstR(), bsAstR())
789789 else {
790790 let direction = (_positionSize > 0)
791791 let $t03841138590 = swapOutput(direction, abs(_positionSize), false)
792792 let currentNetMarketValue = $t03841138590._1
793793 let terminalQuoteAssetReserve = $t03841138590._2
794794 let terminalBaseAssetReserve = $t03841138590._3
795795 $Tuple2(terminalQuoteAssetReserve, terminalBaseAssetReserve)
796796 }
797797 }
798798
799799
800800 func getQuoteAssetWeight (baseAssetReserve,totalPositionSize,quoteAssetReserve,targetPrice) = {
801801 let b = toBigInt(baseAssetReserve)
802802 let sz = toBigInt(totalPositionSize)
803803 let q = toBigInt(quoteAssetReserve)
804804 let p = toBigInt(targetPrice)
805805 let k = bmuld(q, b)
806806 let newB = (b + sz)
807807 let newQ = bdivd(k, newB)
808808 let z = bdivd(newQ, newB)
809809 let result = bdivd(p, z)
810810 toInt(result)
811811 }
812812
813813
814814 func getSyncTerminalPrice (_terminalPrice,_qtAstR,_bsAstR) = {
815815 let _positionSize = totalPositionSize()
816816 if ((_positionSize == 0))
817817 then {
818818 let newQtAstW = divd(muld(_terminalPrice, _bsAstR), _qtAstR)
819819 $Tuple3(newQtAstW, DECIMAL_UNIT, 0)
820820 }
821821 else {
822822 let direction = (_positionSize > 0)
823823 let currentNetMarketValue = swapOutput(direction, abs(_positionSize), false)._1
824824 let newQtAstW = getQuoteAssetWeight(_bsAstR, _positionSize, _qtAstR, _terminalPrice)
825825 let newBsAstW = DECIMAL_UNIT
826826 let marginToVault = getPositionNotionalAndUnrealizedPnlByValues(_positionSize, currentNetMarketValue, _qtAstR, newQtAstW, _bsAstR, newBsAstW, PNL_OPTION_SPOT)._2
827827 $Tuple3(newQtAstW, newBsAstW, marginToVault)
828828 }
829829 }
830830
831831
832832 func getFunding () = {
833833 let underlyingPrice = getOraclePrice()
834834 let spotPrice = getSpotPrice()
835835 let premium = (spotPrice - underlyingPrice)
836836 if (if (isMarketClosed())
837837 then true
838838 else if ((fundingMode() == FUNDING_ASYMMETRIC))
839839 then if ((totalShortPositionSize() == 0))
840840 then true
841841 else (totalLongPositionSize() == 0)
842842 else false)
843843 then $Tuple3(0, 0, 0)
844844 else if ((0 > premium))
845845 then {
846846 let shortPremiumFraction = divd(muld(premium, fundingPeriodDecimal()), ONE_DAY)
847847 if ((fundingMode() == FUNDING_ASYMMETRIC))
848848 then {
849849 let longPremiumFraction = divd(muld(shortPremiumFraction, totalShortPositionSize()), totalLongPositionSize())
850850 $Tuple3(shortPremiumFraction, longPremiumFraction, 0)
851851 }
852852 else {
853853 let shortTotalPremiumFraction = abs(muld(shortPremiumFraction, totalShortPositionSize()))
854854 let longTotalPremiumFraction = abs(muld(shortPremiumFraction, totalLongPositionSize()))
855855 let premiumToVault = (shortTotalPremiumFraction - longTotalPremiumFraction)
856856 $Tuple3(shortPremiumFraction, shortPremiumFraction, premiumToVault)
857857 }
858858 }
859859 else {
860860 let longPremiumFraction = divd(muld(premium, fundingPeriodDecimal()), ONE_DAY)
861861 if ((fundingMode() == FUNDING_ASYMMETRIC))
862862 then {
863863 let shortPremiumFraction = divd(muld(longPremiumFraction, totalLongPositionSize()), totalShortPositionSize())
864864 $Tuple3(shortPremiumFraction, longPremiumFraction, 0)
865865 }
866866 else {
867867 let longTotalPremiumFraction = abs(muld(longPremiumFraction, totalLongPositionSize()))
868868 let shortTotalPremiumFraction = abs(muld(longPremiumFraction, totalShortPositionSize()))
869869 let premiumToVault = (longTotalPremiumFraction - shortTotalPremiumFraction)
870870 $Tuple3(longPremiumFraction, longPremiumFraction, premiumToVault)
871871 }
872872 }
873873 }
874874
875875
876876 func getAdjustedFee (_artifactId,_baseFeeDiscount) = {
877877 let baseFeeRaw = fee()
878878 let baseFee = muld(baseFeeRaw, _baseFeeDiscount)
879879 let $t04325443749 = if ((_artifactId != ""))
880880 then {
881881 let artifactKind = strA(nftManagerAddress(), toCompositeKey(k_token_type, _artifactId))
882882 if ((artifactKind == FEE_REDUCTION_TOKEN_TYPE))
883883 then {
884884 let reduction = intA(nftManagerAddress(), toCompositeKey(k_token_param, _artifactId))
885885 let adjustedFee = muld(baseFee, reduction)
886886 $Tuple2(adjustedFee, true)
887887 }
888888 else throw("Invalid attached artifact")
889889 }
890890 else $Tuple2(baseFee, false)
891891 let adjustedFee = $t04325443749._1
892892 let burnArtifact = $t04325443749._2
893893 $Tuple2(adjustedFee, burnArtifact)
894894 }
895895
896896
897897 func getForTraderWithArtifact (_trader,_artifactId) = {
898898 let doGetFeeDiscount = invoke(minerAddress(), "computeFeeDiscount", [_trader], nil)
899899 if ((doGetFeeDiscount == doGetFeeDiscount))
900900 then {
901901 let feeDiscount = match doGetFeeDiscount {
902902 case x: Int =>
903903 x
904904 case _ =>
905905 throw("Invalid computeFeeDiscount result")
906906 }
907907 let $t04409544169 = getAdjustedFee(_artifactId, feeDiscount)
908908 let adjustedFee = $t04409544169._1
909909 let burnArtifact = $t04409544169._2
910910 $Tuple2(adjustedFee, burnArtifact)
911911 }
912912 else throw("Strict value is not equal to itself.")
913913 }
914914
915915
916916 func getArtifactId (i) = {
917917 let artifactId = if ((size(i.payments) > 1))
918918 then toBase58String(valueOrErrorMessage(i.payments[1].assetId, "Invalid artifactId"))
919919 else ""
920920 artifactId
921921 }
922922
923923
924924 func distributeFee (_feeAmount) = {
925925 let feeToStakers = muld(_feeAmount, feeToStakersPercent())
926926 let feeToVault = (_feeAmount - feeToStakers)
927927 $Tuple2(feeToStakers, feeToVault)
928928 }
929929
930930
931931 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)]
932932
933933
934934 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)]
935935
936936
937937 func incrementPositionSequenceNumber (_isNewPosition,_trader,_direction) = {
938938 let positionKey = ((_trader + "_") + toString(_direction))
939939 if (_isNewPosition)
940940 then {
941941 let currentSequence = lastSequence()
942942 [IntegerEntry(toCompositeKey(k_positionSequence, positionKey), (currentSequence + 1)), IntegerEntry(k_sequence, (currentSequence + 1))]
943943 }
944944 else nil
945945 }
946946
947947
948948 func updatePositionFee (_isNewPosition,_trader,_direction,_fee) = {
949949 let positionKey = ((_trader + "_") + toString(_direction))
950950 if (_isNewPosition)
951951 then [IntegerEntry(toCompositeKey(k_positionFee, positionKey), _fee)]
952952 else nil
953953 }
954954
955955
956956 func updatePosition (_trader,_size,_margin,_openNotional,_latestCumulativePremiumFraction,_latestTimestamp) = {
957957 let direction = getDirection(_size)
958958 let positionKey = ((_trader + "_") + toString(direction))
959959 [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)]
960960 }
961961
962962
963963 func updateAmmReserves (_qtAstR,_bsAstR) = if (if ((0 > _qtAstR))
964964 then true
965965 else (0 > _bsAstR))
966966 then throw("Invalid amount to update reserves")
967967 else if (if ((_qtAstR != qtAstR0()))
968968 then true
969969 else (_bsAstR != bsAstR0()))
970970 then [IntegerEntry(k_quoteAssetReserve, _qtAstR), IntegerEntry(k_baseAssetReserve, _bsAstR)]
971971 else nil
972972
973973
974974 func updateAmmWeights (_qtAstW,_bsAstW) = if (if ((_qtAstW != qtAstW()))
975975 then true
976976 else (_bsAstW != bsAstW()))
977977 then [IntegerEntry(k_quoteAssetWeight, _qtAstW), IntegerEntry(k_baseAssetWeight, _bsAstW)]
978978 else nil
979979
980980
981981 func updateAmm (_qtAstR,_bsAstR,_totalPositionSizeAfter,_openInterestNotional,_totalLongPositionSize,_totalShortPositionSize,_totalLongOpenNotional,_totalShortOpenNotional) = {
982982 let _qtAstW = qtAstW()
983983 let _bsAstW = bsAstW()
984984 if (((_totalLongPositionSize - _totalShortPositionSize) != _totalPositionSizeAfter))
985985 then throw(((((("Invalid AMM state data: " + toString(_totalLongPositionSize)) + " - ") + toString(_totalShortPositionSize)) + " != ") + toString(_totalPositionSizeAfter)))
986986 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)])
987987 }
988988
989989
990990 func deletePosition (_trader,_direction) = {
991991 let positionKey = ((_trader + "_") + toString(_direction))
992992 [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))]
993993 }
994994
995995
996996 func withdraw (_address,_amount) = {
997997 let balance = assetBalance(this, quoteAsset())
998998 if ((_amount > balance))
999999 then throw(((("Unable to withdraw " + toString(_amount)) + " from contract balance ") + toString(balance)))
10001000 else [ScriptTransfer(_address, _amount, quoteAsset())]
10011001 }
10021002
10031003
10041004 func updateBalance (_balance) = if ((0 > _balance))
10051005 then throw("Balance")
10061006 else if (if ((cbalance0() == 0))
10071007 then true
10081008 else (cbalance0() != _balance))
10091009 then [IntegerEntry(k_balance, _balance)]
10101010 else nil
10111011
10121012
10131013 func transferFee (i) = [ScriptTransfer(stakingAddress(), i, quoteAsset())]
10141014
10151015
10161016 func doBurnArtifact (_burnArtifact,i) = if (_burnArtifact)
10171017 then [Burn(valueOrErrorMessage(i.payments[1].assetId, "Invalid artifact"), 1)]
10181018 else nil
10191019
10201020
10211021 @Callable(i)
10221022 func pause () = if ((i.caller != adminAddress()))
10231023 then throw("Invalid pause params")
10241024 else [BooleanEntry(k_paused, true)]
10251025
10261026
10271027
10281028 @Callable(i)
10291029 func unpause () = if ((i.caller != adminAddress()))
10301030 then throw("Invalid unpause params")
10311031 else [BooleanEntry(k_paused, false)]
10321032
10331033
10341034
10351035 @Callable(i)
10361036 func setCloseOnly () = if ((i.caller != adminAddress()))
10371037 then throw("Invalid setCloseOnly params")
10381038 else [BooleanEntry(k_closeOnly, true)]
10391039
10401040
10411041
10421042 @Callable(i)
10431043 func unsetCloseOnly () = if ((i.caller != adminAddress()))
10441044 then throw("Invalid unsetCloseOnly params")
10451045 else [BooleanEntry(k_closeOnly, false)]
10461046
10471047
10481048
10491049 @Callable(i)
10501050 func changeLiquidity (_quoteAssetAmount) = if (if ((i.caller != adminAddress()))
10511051 then true
10521052 else (_quoteAssetAmount == 0))
10531053 then throw("Invalid changeLiquidity params")
10541054 else {
10551055 let _qtAstR = qtAstR()
10561056 let _bsAstR = bsAstR()
10571057 let _qtAstW = qtAstW()
10581058 let _bsAstW = bsAstW()
10591059 let price = divd(muld(_qtAstR, _qtAstW), muld(_bsAstR, _bsAstW))
10601060 let qtAstRAfter = (_qtAstR + _quoteAssetAmount)
10611061 let baseAssetAmountToAdd = (divd(muld(qtAstRAfter, _qtAstW), price) - _bsAstR)
10621062 let bsAstRAfter = (_bsAstR + baseAssetAmountToAdd)
10631063 let $t05305453205 = getSyncTerminalPrice(getOraclePrice(), qtAstRAfter, bsAstRAfter)
10641064 let newQuoteAssetWeight = $t05305453205._1
10651065 let newBaseAssetWeight = $t05305453205._2
10661066 let marginToVault = $t05305453205._3
10671067 let doExchangePnL = if ((marginToVault != 0))
10681068 then {
10691069 let doExchangePnL = invoke(vaultAddress(), "exchangeFreeAndLocked", [marginToVault], nil)
10701070 if ((doExchangePnL == doExchangePnL))
10711071 then nil
10721072 else throw("Strict value is not equal to itself.")
10731073 }
10741074 else nil
10751075 if ((doExchangePnL == doExchangePnL))
10761076 then (updateAmmReserves(qtAstRAfter, bsAstRAfter) ++ updateAmmWeights(newQuoteAssetWeight, newBaseAssetWeight))
10771077 else throw("Strict value is not equal to itself.")
10781078 }
10791079
10801080
10811081
10821082 @Callable(i)
10831083 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 ((0 >= _fundingPeriod))
10841084 then true
10851085 else (0 >= _initMarginRatio))
10861086 then true
10871087 else (_initMarginRatio > DECIMAL_UNIT))
10881088 then true
10891089 else (0 >= _minInitMarginRatio))
10901090 then true
10911091 else (_initMarginRatio > _minInitMarginRatio))
10921092 then true
10931093 else (0 >= _mmr))
10941094 then true
10951095 else (0 >= _liquidationFeeRatio))
10961096 then true
10971097 else (0 >= _fee))
10981098 then true
10991099 else (0 >= _spreadLimit))
11001100 then true
11011101 else (0 >= _maxPriceImpact))
11021102 then true
11031103 else (0 >= _partialLiquidationRatio))
11041104 then true
11051105 else (0 >= _maxPriceSpread))
11061106 then true
11071107 else (0 >= _maxOpenNotional))
11081108 then true
11091109 else (0 >= _feeToStakersPercent))
11101110 then true
11111111 else (_feeToStakersPercent > DECIMAL_UNIT))
11121112 then true
11131113 else (0 > _maxOracleDelay))
11141114 then true
11151115 else (0 >= _rolloverFee))
11161116 then true
11171117 else if ((_fundingMode != FUNDING_SYMMETRIC))
11181118 then (_fundingMode != FUNDING_ASYMMETRIC)
11191119 else false)
11201120 then true
11211121 else if ((_oracleMode != ORACLE_PLAIN))
11221122 then (_oracleMode != ORACLE_JIT)
11231123 else false)
11241124 then true
11251125 else if ((_positionMode != POSITION_DIRECT))
11261126 then (_positionMode != POSITION_ORDER)
11271127 else false)
11281128 then true
11291129 else !(initialized()))
11301130 then true
11311131 else (i.caller != adminAddress()))
11321132 then throw("Invalid changeSettings params")
11331133 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)])
11341134
11351135
11361136
11371137 @Callable(i)
11381138 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))
11391139 then true
11401140 else (0 >= _bsAstR))
11411141 then true
11421142 else (0 >= _fundingPeriod))
11431143 then true
11441144 else (0 >= _initMarginRatio))
11451145 then true
11461146 else (_initMarginRatio > DECIMAL_UNIT))
11471147 then true
11481148 else (0 >= _minInitMarginRatio))
11491149 then true
11501150 else (_initMarginRatio > _minInitMarginRatio))
11511151 then true
11521152 else (0 >= _mmr))
11531153 then true
11541154 else (0 >= _liquidationFeeRatio))
11551155 then true
11561156 else (0 >= _fee))
11571157 then true
11581158 else (0 >= _spreadLimit))
11591159 then true
11601160 else (0 >= _maxPriceImpact))
11611161 then true
11621162 else (0 >= _partialLiquidationRatio))
11631163 then true
11641164 else (0 >= _maxPriceSpread))
11651165 then true
11661166 else (0 >= _maxOpenNotional))
11671167 then true
11681168 else (0 >= _feeToStakersPercent))
11691169 then true
11701170 else (_feeToStakersPercent > DECIMAL_UNIT))
11711171 then true
11721172 else (0 > _maxOracleDelay))
11731173 then true
11741174 else (0 >= _rolloverFee))
11751175 then true
11761176 else if ((_fundingMode != FUNDING_SYMMETRIC))
11771177 then (_fundingMode != FUNDING_ASYMMETRIC)
11781178 else false)
11791179 then true
11801180 else if ((_oracleMode != ORACLE_PLAIN))
11811181 then (_oracleMode != ORACLE_JIT)
11821182 else false)
11831183 then true
11841184 else if ((_positionMode != POSITION_DIRECT))
11851185 then (_positionMode != POSITION_ORDER)
11861186 else false)
11871187 then true
11881188 else initialized())
11891189 then true
11901190 else (i.caller != this))
11911191 then throw("Invalid initialize parameters")
11921192 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)))])
11931193
11941194
11951195
11961196 @Callable(i)
11971197 func increasePosition (_direction,_leverage,_minBaseAssetAmount,_refLink,_priceUpdate) = {
11981198 let updateOracle = invoke(this, "updateOracle", [_priceUpdate], nil)
11991199 if ((updateOracle == updateOracle))
12001200 then {
12011201 let sync = invoke(this, "syncTerminalPriceToOracle", nil, nil)
12021202 if ((sync == sync))
12031203 then {
12041204 let ensureCalledOnce = invoke(this, "ensureCalledOnce", nil, nil)
12051205 if ((ensureCalledOnce == ensureCalledOnce))
12061206 then {
12071207 let _trader = getActualCaller(i)
12081208 let _rawAmount = i.payments[0].amount
12091209 let _assetId = i.payments[0].assetId
12101210 let _assetIdStr = toBase58String(value(_assetId))
12111211 let isQuoteAsset = (_assetId == quoteAsset())
12121212 if (if (if (if (if (if (if (if (if (if (if ((_direction != DIR_LONG))
12131213 then (_direction != DIR_SHORT)
12141214 else false)
12151215 then true
12161216 else (0 >= _rawAmount))
12171217 then true
12181218 else !(initialized()))
12191219 then true
12201220 else !(isQuoteAsset))
12211221 then true
12221222 else !(requireMoreMarginRatio(divd(DECIMAL_UNIT, _leverage), initMarginRatio(), true)))
12231223 then true
12241224 else !(requireMoreMarginRatio(divd(DECIMAL_UNIT, _leverage), minInitMarginRatio(), false)))
12251225 then true
12261226 else !(requireSenderCanWorkWithPositions(i.caller)))
12271227 then true
12281228 else paused())
12291229 then true
12301230 else closeOnly())
12311231 then true
12321232 else isMarketClosed())
12331233 then throw("Invalid increasePosition parameters")
12341234 else {
12351235 let $t06046860617 = getForTraderWithArtifact(_trader, getArtifactId(i))
12361236 let adjustedFee = $t06046860617._1
12371237 let burnArtifact = $t06046860617._2
12381238 let _amount = divd(_rawAmount, (muld(adjustedFee, _leverage) + DECIMAL_UNIT))
12391239 let distributeFeeAmount = (_rawAmount - _amount)
12401240 let referrerFeeAny = invoke(referralAddress(), "acceptPaymentWithLink", [_trader, _refLink], [AttachedPayment(quoteAsset(), distributeFeeAmount)])
12411241 if ((referrerFeeAny == referrerFeeAny))
12421242 then {
12431243 let referrerFee = match referrerFeeAny {
12441244 case x: Int =>
12451245 x
12461246 case _ =>
12471247 throw("Invalid referrerFee")
12481248 }
12491249 let feeAmount = (distributeFeeAmount - referrerFee)
12501250 let $t06111361293 = getPosition(_trader, _direction)
12511251 let oldPositionSize = $t06111361293._1
12521252 let oldPositionMargin = $t06111361293._2
12531253 let oldPositionOpenNotional = $t06111361293._3
12541254 let oldPositionLstUpdCPF = $t06111361293._4
12551255 let oldPositionTimestamp = $t06111361293._5
12561256 let isNewPosition = (oldPositionSize == 0)
12571257 let isSameDirection = if ((oldPositionSize > 0))
12581258 then (_direction == DIR_LONG)
12591259 else (_direction == DIR_SHORT)
12601260 let expandExisting = if (!(isNewPosition))
12611261 then isSameDirection
12621262 else false
12631263 let isAdd = (_direction == DIR_LONG)
12641264 let $t06158264715 = if (if (isNewPosition)
12651265 then true
12661266 else expandExisting)
12671267 then {
12681268 let openNotional = muld(_amount, _leverage)
12691269 let $t06209162264 = swapInput(isAdd, openNotional)
12701270 let amountBaseAssetBought = $t06209162264._1
12711271 let quoteAssetReserveAfter = $t06209162264._2
12721272 let baseAssetReserveAfter = $t06209162264._3
12731273 let totalPositionSizeAfter = $t06209162264._4
12741274 if (if ((_minBaseAssetAmount != 0))
12751275 then (_minBaseAssetAmount > abs(amountBaseAssetBought))
12761276 else false)
12771277 then throw(((("Limit error: " + toString(abs(amountBaseAssetBought))) + " < ") + toString(_minBaseAssetAmount)))
12781278 else {
12791279 let newPositionSize = (oldPositionSize + amountBaseAssetBought)
12801280 let totalLongOpenInterestAfter = (openInterestLong() + (if ((newPositionSize > 0))
12811281 then openNotional
12821282 else 0))
12831283 let totalShortOpenInterestAfter = (openInterestShort() + (if ((0 > newPositionSize))
12841284 then openNotional
12851285 else 0))
12861286 let $t06281063085 = calcRemainMarginWithFundingPaymentAndRolloverFee(oldPositionSize, oldPositionMargin, oldPositionLstUpdCPF, oldPositionTimestamp, _amount)
12871287 let remainMargin = $t06281063085._1
12881288 let x1 = $t06281063085._2
12891289 let x2 = $t06281063085._3
12901290 let rolloverFee = $t06281063085._4
12911291 if (!(requireNotOverSpreadLimit(quoteAssetReserveAfter, baseAssetReserveAfter)))
12921292 then throw("Over max spread limit")
12931293 else if (!(requireNotOverMaxOpenNotional(totalLongOpenInterestAfter, totalShortOpenInterestAfter)))
12941294 then throw("Over max open notional")
12951295 else $Tuple14(newPositionSize, remainMargin, (oldPositionOpenNotional + openNotional), latestCumulativePremiumFraction(newPositionSize), lastTimestamp(), baseAssetReserveAfter, quoteAssetReserveAfter, totalPositionSizeAfter, (openInterestNotional() + openNotional), (totalLongPositionSize() + (if ((newPositionSize > 0))
12961296 then abs(amountBaseAssetBought)
12971297 else 0)), (totalShortPositionSize() + (if ((0 > newPositionSize))
12981298 then abs(amountBaseAssetBought)
12991299 else 0)), totalLongOpenInterestAfter, totalShortOpenInterestAfter, rolloverFee)
13001300 }
13011301 }
13021302 else {
13031303 let openNotional = muld(_amount, _leverage)
13041304 let $t06440364531 = getPositionNotionalAndUnrealizedPnl(toString(i.caller), _direction, PNL_OPTION_SPOT)
13051305 let oldPositionNotional = $t06440364531._1
13061306 let unrealizedPnl = $t06440364531._2
13071307 if ((oldPositionNotional > openNotional))
13081308 then throw("Use decreasePosition to decrease position size")
13091309 else throw("Close position first")
13101310 }
13111311 let newPositionSize = $t06158264715._1
13121312 let newPositionRemainMargin = $t06158264715._2
13131313 let newPositionOpenNotional = $t06158264715._3
13141314 let newPositionLatestCPF = $t06158264715._4
13151315 let newPositionTimestamp = $t06158264715._5
13161316 let baseAssetReserveAfter = $t06158264715._6
13171317 let quoteAssetReserveAfter = $t06158264715._7
13181318 let totalPositionSizeAfter = $t06158264715._8
13191319 let openInterestNotionalAfter = $t06158264715._9
13201320 let totalLongAfter = $t06158264715._10
13211321 let totalShortAfter = $t06158264715._11
13221322 let totalLongOpenInterestAfter = $t06158264715._12
13231323 let totalShortOpenInterestAfter = $t06158264715._13
13241324 let rolloverFee = $t06158264715._14
13251325 let $t06472164792 = distributeFee((feeAmount + rolloverFee))
13261326 let feeToStakers = $t06472164792._1
13271327 let feeToVault = $t06472164792._2
13281328 let stake = if ((_amount >= rolloverFee))
13291329 then invoke(vaultAddress(), "addLocked", nil, [AttachedPayment(quoteAsset(), (_amount - rolloverFee))])
13301330 else invoke(vaultAddress(), "withdrawLocked", [(rolloverFee - _amount)], nil)
13311331 if ((stake == stake))
13321332 then {
13331333 let depositVault = invoke(vaultAddress(), "addFree", nil, [AttachedPayment(quoteAsset(), feeToVault)])
13341334 if ((depositVault == depositVault))
13351335 then {
13361336 let notifyFee = invoke(minerAddress(), "notifyFees", [_trader, feeAmount], nil)
13371337 if ((notifyFee == notifyFee))
13381338 then {
13391339 let notifyNotional = invoke(minerAddress(), "notifyNotional", [_trader, newPositionOpenNotional], nil)
13401340 if ((notifyNotional == notifyNotional))
13411341 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))
13421342 else throw("Strict value is not equal to itself.")
13431343 }
13441344 else throw("Strict value is not equal to itself.")
13451345 }
13461346 else throw("Strict value is not equal to itself.")
13471347 }
13481348 else throw("Strict value is not equal to itself.")
13491349 }
13501350 else throw("Strict value is not equal to itself.")
13511351 }
13521352 }
13531353 else throw("Strict value is not equal to itself.")
13541354 }
13551355 else throw("Strict value is not equal to itself.")
13561356 }
13571357 else throw("Strict value is not equal to itself.")
13581358 }
13591359
13601360
13611361
13621362 @Callable(i)
13631363 func addMargin (_direction,_priceUpdate) = {
13641364 let updateOracle = invoke(this, "updateOracle", [_priceUpdate], nil)
13651365 if ((updateOracle == updateOracle))
13661366 then {
13671367 let sync = invoke(this, "syncTerminalPriceToOracle", nil, nil)
13681368 if ((sync == sync))
13691369 then {
13701370 let ensureCalledOnce = invoke(this, "ensureCalledOnce", nil, nil)
13711371 if ((ensureCalledOnce == ensureCalledOnce))
13721372 then {
13731373 let _trader = toString(i.caller)
13741374 let _amount = i.payments[0].amount
13751375 let _assetId = i.payments[0].assetId
13761376 let _assetIdStr = toBase58String(value(_assetId))
13771377 let isQuoteAsset = (_assetId == quoteAsset())
13781378 if (if (if (if (if (!(isQuoteAsset))
13791379 then true
13801380 else !(requireOpenPosition(toString(i.caller), _direction)))
13811381 then true
13821382 else !(initialized()))
13831383 then true
13841384 else paused())
13851385 then true
13861386 else isMarketClosed())
13871387 then throw("Invalid addMargin parameters")
13881388 else {
13891389 let $t06713467314 = getPosition(_trader, _direction)
13901390 let oldPositionSize = $t06713467314._1
13911391 let oldPositionMargin = $t06713467314._2
13921392 let oldPositionOpenNotional = $t06713467314._3
13931393 let oldPositionLstUpdCPF = $t06713467314._4
13941394 let oldPositionTimestamp = $t06713467314._5
13951395 let stake = invoke(vaultAddress(), "addLocked", nil, [AttachedPayment(quoteAsset(), _amount)])
13961396 if ((stake == stake))
13971397 then {
13981398 let $t06745467696 = calcRemainMarginWithFundingPaymentAndRolloverFee(oldPositionSize, oldPositionMargin, oldPositionLstUpdCPF, oldPositionTimestamp, _amount)
13991399 let remainMargin = $t06745467696._1
14001400 let badDebt = $t06745467696._2
14011401 let fundingPayment = $t06745467696._3
14021402 let rolloverFee = $t06745467696._4
14031403 let marginRatio = calcMarginRatio(remainMargin, badDebt, oldPositionOpenNotional)
14041404 let checkMinMargin = requireMoreMarginRatio(marginRatio, minInitMarginRatio(), false)
14051405 if ((checkMinMargin == checkMinMargin))
14061406 then {
14071407 let doTransferFeeToStakers = if ((rolloverFee > 0))
14081408 then {
14091409 let $t06795268011 = distributeFee(rolloverFee)
14101410 let feeToStakers = $t06795268011._1
14111411 let feeToVault = $t06795268011._2
14121412 let unstake = invoke(vaultAddress(), "withdrawLocked", [feeToStakers], nil)
14131413 if ((unstake == unstake))
14141414 then {
14151415 let lockBadDebt = invoke(vaultAddress(), "exchangeFreeAndLocked", [-(feeToVault)], nil)
14161416 if ((lockBadDebt == lockBadDebt))
14171417 then transferFee(feeToStakers)
14181418 else throw("Strict value is not equal to itself.")
14191419 }
14201420 else throw("Strict value is not equal to itself.")
14211421 }
14221422 else nil
14231423 if ((doTransferFeeToStakers == doTransferFeeToStakers))
14241424 then ((updatePosition(_trader, oldPositionSize, ((oldPositionMargin - rolloverFee) + _amount), oldPositionOpenNotional, oldPositionLstUpdCPF, lastTimestamp()) ++ updateBalance(((cbalance() + _amount) - rolloverFee))) ++ doTransferFeeToStakers)
14251425 else throw("Strict value is not equal to itself.")
14261426 }
14271427 else throw("Strict value is not equal to itself.")
14281428 }
14291429 else throw("Strict value is not equal to itself.")
14301430 }
14311431 }
14321432 else throw("Strict value is not equal to itself.")
14331433 }
14341434 else throw("Strict value is not equal to itself.")
14351435 }
14361436 else throw("Strict value is not equal to itself.")
14371437 }
14381438
14391439
14401440
14411441 @Callable(i)
14421442 func removeMargin (_amount,_direction,_priceUpdate) = {
14431443 let updateOracle = invoke(this, "updateOracle", [_priceUpdate], nil)
14441444 if ((updateOracle == updateOracle))
14451445 then {
14461446 let sync = invoke(this, "syncTerminalPriceToOracle", nil, nil)
14471447 if ((sync == sync))
14481448 then {
14491449 let ensureCalledOnce = invoke(this, "ensureCalledOnce", nil, nil)
14501450 if ((ensureCalledOnce == ensureCalledOnce))
14511451 then {
14521452 let _trader = toString(i.caller)
14531453 if (if (if (if (if ((0 >= _amount))
14541454 then true
14551455 else !(requireOpenPosition(_trader, _direction)))
14561456 then true
14571457 else !(initialized()))
14581458 then true
14591459 else paused())
14601460 then true
14611461 else isMarketClosed())
14621462 then throw("Invalid removeMargin parameters")
14631463 else {
14641464 let $t06951269692 = getPosition(_trader, _direction)
14651465 let oldPositionSize = $t06951269692._1
14661466 let oldPositionMargin = $t06951269692._2
14671467 let oldPositionOpenNotional = $t06951269692._3
14681468 let oldPositionLstUpdCPF = $t06951269692._4
14691469 let oldPositionTimestamp = $t06951269692._5
14701470 let $t06969869947 = calcRemainMarginWithFundingPaymentAndRolloverFee(oldPositionSize, oldPositionMargin, oldPositionLstUpdCPF, oldPositionTimestamp, -(_amount))
14711471 let remainMargin = $t06969869947._1
14721472 let badDebt = $t06969869947._2
14731473 let fundingPayment = $t06969869947._3
14741474 let rolloverFee = $t06969869947._4
14751475 if ((badDebt != 0))
14761476 then throw("Invalid removed margin amount")
14771477 else {
14781478 let marginRatio = calcMarginRatio(remainMargin, badDebt, oldPositionOpenNotional)
14791479 if (!(requireMoreMarginRatio(marginRatio, initMarginRatio(), true)))
14801480 then throw(((("Too much margin removed: " + toString(marginRatio)) + " < ") + toString(initMarginRatio())))
14811481 else {
14821482 let $t07033370392 = distributeFee(rolloverFee)
14831483 let feeToStakers = $t07033370392._1
14841484 let feeToVault = $t07033370392._2
14851485 let doTransferFeeToStakers = if ((rolloverFee > 0))
14861486 then {
14871487 let lockBadDebt = invoke(vaultAddress(), "exchangeFreeAndLocked", [-(feeToVault)], nil)
14881488 if ((lockBadDebt == lockBadDebt))
14891489 then transferFee(feeToStakers)
14901490 else throw("Strict value is not equal to itself.")
14911491 }
14921492 else nil
14931493 if ((doTransferFeeToStakers == doTransferFeeToStakers))
14941494 then {
14951495 let unstake = invoke(vaultAddress(), "withdrawLocked", [(_amount + feeToStakers)], nil)
14961496 if ((unstake == unstake))
14971497 then (((updatePosition(_trader, oldPositionSize, remainMargin, oldPositionOpenNotional, latestCumulativePremiumFraction(oldPositionSize), lastTimestamp()) ++ withdraw(i.caller, _amount)) ++ updateBalance(((cbalance() - _amount) - rolloverFee))) ++ doTransferFeeToStakers)
14981498 else throw("Strict value is not equal to itself.")
14991499 }
15001500 else throw("Strict value is not equal to itself.")
15011501 }
15021502 }
15031503 }
15041504 }
15051505 else throw("Strict value is not equal to itself.")
15061506 }
15071507 else throw("Strict value is not equal to itself.")
15081508 }
15091509 else throw("Strict value is not equal to itself.")
15101510 }
15111511
15121512
15131513
15141514 @Callable(i)
15151515 func closePosition (_size,_direction,_minQuoteAssetAmount,_addToMargin,_priceUpdate) = {
15161516 let updateOracle = invoke(this, "updateOracle", [_priceUpdate], nil)
15171517 if ((updateOracle == updateOracle))
15181518 then {
15191519 let sync = invoke(this, "syncTerminalPriceToOracle", nil, nil)
15201520 if ((sync == sync))
15211521 then {
15221522 let ensureCalledOnce = invoke(this, "ensureCalledOnce", nil, nil)
15231523 if ((ensureCalledOnce == ensureCalledOnce))
15241524 then {
15251525 let _trader = getActualCaller(i)
15261526 let _traderAddress = valueOrErrorMessage(addressFromString(_trader), "Invalid caller")
15271527 let positionFee = getPositionFee(_trader, _direction)
15281528 if (if (if (if (if (if (!(requireOpenPosition(_trader, _direction)))
15291529 then true
15301530 else !(initialized()))
15311531 then true
15321532 else paused())
15331533 then true
15341534 else (0 >= _size))
15351535 then true
15361536 else (0 > _minQuoteAssetAmount))
15371537 then true
15381538 else isMarketClosed())
15391539 then throw("Invalid closePosition parameters")
15401540 else {
15411541 let oldPositionTimestamp = getPosition(_trader, _direction)._5
15421542 let $t07272773330 = internalClosePosition(_trader, _direction, _size, positionFee, _minQuoteAssetAmount, _addToMargin, true, true)
15431543 let newPositionSize = $t07272773330._1
15441544 let newPositionMargin = $t07272773330._2
15451545 let newPositionOpenNotional = $t07272773330._3
15461546 let newPositionLstUpdCPF = $t07272773330._4
15471547 let positionBadDebt = $t07272773330._5
15481548 let realizedPnl = $t07272773330._6
15491549 let marginToTrader = $t07272773330._7
15501550 let quoteAssetReserveAfter = $t07272773330._8
15511551 let baseAssetReserveAfter = $t07272773330._9
15521552 let totalPositionSizeAfter = $t07272773330._10
15531553 let openInterestNotionalAfter = $t07272773330._11
15541554 let totalLongAfter = $t07272773330._12
15551555 let totalShortAfter = $t07272773330._13
15561556 let totalLongOpenInterestAfter = $t07272773330._14
15571557 let totalShortOpenInterestAfter = $t07272773330._15
15581558 let realizedFee = $t07272773330._16
15591559 if ((positionBadDebt > 0))
15601560 then throw("Invalid closePosition parameters: bad debt")
15611561 else if ((oldPositionTimestamp >= lastTimestamp()))
15621562 then throw("Invalid closePosition parameters: wait at least 1 block before closing the position")
15631563 else {
15641564 let isPartialClose = (newPositionSize != 0)
15651565 let withdrawAmount = (marginToTrader + realizedFee)
15661566 let ammBalance = (cbalance() - withdrawAmount)
15671567 let ammNewBalance = if ((0 > ammBalance))
15681568 then 0
15691569 else ammBalance
15701570 let unstake = invoke(vaultAddress(), "withdrawLocked", [withdrawAmount], nil)
15711571 if ((unstake == unstake))
15721572 then {
15731573 let referrerFeeAny = invoke(referralAddress(), "acceptPayment", [_trader], [AttachedPayment(quoteAsset(), realizedFee)])
15741574 if ((referrerFeeAny == referrerFeeAny))
15751575 then {
15761576 let referrerFee = match referrerFeeAny {
15771577 case x: Int =>
15781578 x
15791579 case _ =>
15801580 throw("Invalid referrerFee")
15811581 }
15821582 let $t07430274375 = distributeFee((realizedFee - referrerFee))
15831583 let feeToStakers = $t07430274375._1
15841584 let feeToVault = $t07430274375._2
15851585 let depositVault = invoke(vaultAddress(), "addFree", nil, [AttachedPayment(quoteAsset(), feeToVault)])
15861586 if ((depositVault == depositVault))
15871587 then {
15881588 let notifyFee = invoke(minerAddress(), "notifyFees", [_trader, realizedFee], nil)
15891589 if ((notifyFee == notifyFee))
15901590 then {
15911591 let notifyNotional = invoke(minerAddress(), "notifyNotional", [_trader, newPositionOpenNotional], nil)
15921592 if ((notifyNotional == notifyNotional))
15931593 then (((((if (isPartialClose)
15941594 then updatePosition(_trader, newPositionSize, newPositionMargin, newPositionOpenNotional, newPositionLstUpdCPF, lastTimestamp())
15951595 else deletePosition(_trader, _direction)) ++ updateAmm(quoteAssetReserveAfter, baseAssetReserveAfter, totalPositionSizeAfter, openInterestNotionalAfter, totalLongAfter, totalShortAfter, totalLongOpenInterestAfter, totalShortOpenInterestAfter)) ++ (if ((marginToTrader > 0))
15961596 then withdraw(_traderAddress, marginToTrader)
15971597 else nil)) ++ updateBalance(ammNewBalance)) ++ transferFee(feeToStakers))
15981598 else throw("Strict value is not equal to itself.")
15991599 }
16001600 else throw("Strict value is not equal to itself.")
16011601 }
16021602 else throw("Strict value is not equal to itself.")
16031603 }
16041604 else throw("Strict value is not equal to itself.")
16051605 }
16061606 else throw("Strict value is not equal to itself.")
16071607 }
16081608 }
16091609 }
16101610 else throw("Strict value is not equal to itself.")
16111611 }
16121612 else throw("Strict value is not equal to itself.")
16131613 }
16141614 else throw("Strict value is not equal to itself.")
16151615 }
16161616
16171617
16181618
16191619 @Callable(i)
16201620 func liquidate (_trader,_direction,_priceUpdate) = {
16211621 let updateOracle = invoke(this, "updateOracle", [_priceUpdate], nil)
16221622 if ((updateOracle == updateOracle))
16231623 then {
16241624 let sync = invoke(this, "syncTerminalPriceToOracle", nil, nil)
16251625 if ((sync == sync))
16261626 then {
16271627 let spotMarginRatio = getMarginRatioByOption(_trader, _direction, PNL_OPTION_SPOT)
16281628 let liquidationMarginRatio = if (isOverFluctuationLimit())
16291629 then {
16301630 let oracleMarginRatio = getMarginRatioByOption(_trader, _direction, PNL_OPTION_ORACLE)
16311631 vmax(spotMarginRatio, oracleMarginRatio)
16321632 }
16331633 else spotMarginRatio
16341634 if (if (if (if (if (!(requireMoreMarginRatio(liquidationMarginRatio, maintenanceMarginRatio(), false)))
16351635 then true
16361636 else !(requireOpenPosition(_trader, _direction)))
16371637 then true
16381638 else !(initialized()))
16391639 then true
16401640 else paused())
16411641 then true
16421642 else isMarketClosed())
16431643 then throw("Unable to liquidate")
16441644 else {
16451645 let oldPositionSize = getPosition(_trader, _direction)._1
16461646 let positionSizeAbs = abs(oldPositionSize)
16471647 let isPartialLiquidation = if (if (if ((spotMarginRatio > liquidationFeeRatio()))
16481648 then (partialLiquidationRatio() > 0)
16491649 else false)
16501650 then (DECIMAL_UNIT > partialLiquidationRatio())
16511651 else false)
16521652 then (muld(positionSizeAbs, getSpotPrice()) > minPartialLiquidationNotional())
16531653 else false
16541654 let $t07704977436 = if (isPartialLiquidation)
16551655 then {
16561656 let liquidationSize = abs(getPartialLiquidationAmount(_trader, oldPositionSize))
16571657 let liquidationRatio = divd(liquidationSize, positionSizeAbs)
16581658 let liquidationNotional = muld(liquidationSize, getSpotPrice())
16591659 $Tuple2(liquidationRatio, liquidationSize)
16601660 }
16611661 else $Tuple2(0, positionSizeAbs)
16621662 let liquidationRatio = $t07704977436._1
16631663 let liquidationSize = $t07704977436._2
16641664 let $t07744278098 = internalClosePosition(_trader, _direction, if (isPartialLiquidation)
16651665 then liquidationSize
16661666 else positionSizeAbs, liquidationFeeRatio(), 0, true, false, true)
16671667 let newPositionSize = $t07744278098._1
16681668 let newPositionMargin = $t07744278098._2
16691669 let newPositionOpenNotional = $t07744278098._3
16701670 let newPositionLstUpdCPF = $t07744278098._4
16711671 let positionBadDebt = $t07744278098._5
16721672 let realizedPnl = $t07744278098._6
16731673 let marginToTrader = $t07744278098._7
16741674 let quoteAssetReserveAfter = $t07744278098._8
16751675 let baseAssetReserveAfter = $t07744278098._9
16761676 let totalPositionSizeAfter = $t07744278098._10
16771677 let openInterestNotionalAfter = $t07744278098._11
16781678 let totalLongAfter = $t07744278098._12
16791679 let totalShortAfter = $t07744278098._13
16801680 let totalLongOpenInterestAfter = $t07744278098._14
16811681 let totalShortOpenInterestAfter = $t07744278098._15
16821682 let liquidationPenalty = $t07744278098._16
16831683 let feeToLiquidator = (liquidationPenalty / 2)
16841684 let feeToVault = (liquidationPenalty - feeToLiquidator)
16851685 let ammBalance = (cbalance() - liquidationPenalty)
16861686 let newAmmBalance = if ((0 > ammBalance))
16871687 then 0
16881688 else ammBalance
16891689 let lockBadDebt = if ((positionBadDebt > 0))
16901690 then {
16911691 let lockBadDebt = invoke(vaultAddress(), "exchangeFreeAndLocked", [(positionBadDebt + liquidationPenalty)], nil)
16921692 if ((lockBadDebt == lockBadDebt))
16931693 then nil
16941694 else throw("Strict value is not equal to itself.")
16951695 }
16961696 else nil
16971697 if ((lockBadDebt == lockBadDebt))
16981698 then {
16991699 let unstake = invoke(vaultAddress(), "withdrawLocked", [liquidationPenalty], nil)
17001700 if ((unstake == unstake))
17011701 then {
17021702 let depositInsurance = invoke(vaultAddress(), "addFree", nil, [AttachedPayment(quoteAsset(), feeToVault)])
17031703 if ((depositInsurance == depositInsurance))
17041704 then {
17051705 let notifyNotional = invoke(minerAddress(), "notifyNotional", [_trader, newPositionOpenNotional], nil)
17061706 if ((notifyNotional == notifyNotional))
17071707 then ((((if (isPartialLiquidation)
17081708 then updatePosition(_trader, newPositionSize, newPositionMargin, newPositionOpenNotional, newPositionLstUpdCPF, lastTimestamp())
17091709 else deletePosition(_trader, _direction)) ++ updateAmm(quoteAssetReserveAfter, baseAssetReserveAfter, totalPositionSizeAfter, openInterestNotionalAfter, totalLongAfter, totalShortAfter, totalLongOpenInterestAfter, totalShortOpenInterestAfter)) ++ withdraw(i.caller, feeToLiquidator)) ++ updateBalance(newAmmBalance))
17101710 else throw("Strict value is not equal to itself.")
17111711 }
17121712 else throw("Strict value is not equal to itself.")
17131713 }
17141714 else throw("Strict value is not equal to itself.")
17151715 }
17161716 else throw("Strict value is not equal to itself.")
17171717 }
17181718 }
17191719 else throw("Strict value is not equal to itself.")
17201720 }
17211721 else throw("Strict value is not equal to itself.")
17221722 }
17231723
17241724
17251725
17261726 @Callable(i)
17271727 func payFunding (_priceUpdate) = {
17281728 let updateOracle = invoke(this, "updateOracle", [_priceUpdate], nil)
17291729 if ((updateOracle == updateOracle))
17301730 then {
17311731 let sync = invoke(this, "syncTerminalPriceToOracle", nil, nil)
17321732 if ((sync == sync))
17331733 then {
17341734 let fundingBlockTimestamp = nextFundingBlockTimestamp()
17351735 if (if (if ((fundingBlockTimestamp > lastTimestamp()))
17361736 then true
17371737 else !(initialized()))
17381738 then true
17391739 else paused())
17401740 then throw(((("Invalid funding block timestamp: " + toString(lastTimestamp())) + " < ") + toString(fundingBlockTimestamp)))
17411741 else {
17421742 let underlyingPrice = getOraclePrice()
17431743 let $t08031680394 = getFunding()
17441744 let shortPremiumFraction = $t08031680394._1
17451745 let longPremiumFraction = $t08031680394._2
17461746 let premiumToVault = $t08031680394._3
17471747 let doPayFundingToVault = if ((premiumToVault > 0))
17481748 then {
1749- let doPayFundingToVault = invoke(vaultAddress(), "exchangeFreeAndLocked", [-(premiumToVault)], nil)
1750- if ((doPayFundingToVault == doPayFundingToVault))
1751- then nil
1749+ let $t08046680528 = distributeFee(premiumToVault)
1750+ let feeToStakers = $t08046680528._1
1751+ let feeToVault = $t08046680528._2
1752+ let unstake = invoke(vaultAddress(), "withdrawLocked", [feeToStakers], nil)
1753+ if ((unstake == unstake))
1754+ then {
1755+ let addFundingPaymentToVault = invoke(vaultAddress(), "exchangeFreeAndLocked", [-(feeToVault)], nil)
1756+ if ((addFundingPaymentToVault == addFundingPaymentToVault))
1757+ then transferFee(feeToStakers)
1758+ else throw("Strict value is not equal to itself.")
1759+ }
17521760 else throw("Strict value is not equal to itself.")
17531761 }
17541762 else nil
17551763 if ((doPayFundingToVault == doPayFundingToVault))
1756- then updateFunding((fundingBlockTimestamp + fundingPeriodSeconds()), (latestLongCumulativePremiumFraction() + longPremiumFraction), (latestShortCumulativePremiumFraction() + shortPremiumFraction), divd(longPremiumFraction, underlyingPrice), divd(shortPremiumFraction, underlyingPrice))
1764+ then (updateFunding((fundingBlockTimestamp + fundingPeriodSeconds()), (latestLongCumulativePremiumFraction() + longPremiumFraction), (latestShortCumulativePremiumFraction() + shortPremiumFraction), divd(longPremiumFraction, underlyingPrice), divd(shortPremiumFraction, underlyingPrice)) ++ doPayFundingToVault)
17571765 else throw("Strict value is not equal to itself.")
17581766 }
17591767 }
17601768 else throw("Strict value is not equal to itself.")
17611769 }
17621770 else throw("Strict value is not equal to itself.")
17631771 }
17641772
17651773
17661774
17671775 @Callable(i)
17681776 func updateOracle (_priceUpdate) = if ((oracleMode() == ORACLE_PLAIN))
17691777 then nil
17701778 else {
17711779 let priceUpdates = split_4C(_priceUpdate, "::")
17721780 let baseOracle = valueOrErrorMessage(getOracleData(k_baseOracle), "No base asset oracle data")
17731781 let baseOracleAddress = baseOracle._1
17741782 let doUpdateBaseOracle = invoke(baseOracleAddress, "updateData", [priceUpdates[0]], nil)
17751783 if ((doUpdateBaseOracle == doUpdateBaseOracle))
17761784 then {
17771785 let quoteOracle = getOracleData(k_quoteOracle)
17781786 let doUpdateQuoteOracle = if (isDefined(quoteOracle))
17791787 then {
17801788 let quoteOracleV = value(quoteOracle)
17811789 let quoteOracleAddress = quoteOracleV._1
17821790 let doUpdateQuoteOracle = invoke(quoteOracleAddress, "updateData", [priceUpdates[1]], nil)
17831791 if ((doUpdateQuoteOracle == doUpdateQuoteOracle))
17841792 then nil
17851793 else throw("Strict value is not equal to itself.")
17861794 }
17871795 else nil
17881796 if ((doUpdateQuoteOracle == doUpdateQuoteOracle))
17891797 then nil
17901798 else throw("Strict value is not equal to itself.")
17911799 }
17921800 else throw("Strict value is not equal to itself.")
17931801 }
17941802
17951803
17961804
17971805 @Callable(i)
17981806 func syncTerminalPriceToOracle () = {
17991807 let _qtAstR = qtAstR()
18001808 let _bsAstR = bsAstR()
1801- let $t08221182577 = getSyncTerminalPrice(getOraclePrice(), _qtAstR, _bsAstR)
1802- let newQuoteAssetWeight = $t08221182577._1
1803- let newBaseAssetWeight = $t08221182577._2
1804- let marginToVault = $t08221182577._3
1809+ let $t08245482820 = getSyncTerminalPrice(getOraclePrice(), _qtAstR, _bsAstR)
1810+ let newQuoteAssetWeight = $t08245482820._1
1811+ let newBaseAssetWeight = $t08245482820._2
1812+ let marginToVault = $t08245482820._3
18051813 let marginToVaultAdj = if (if ((0 > marginToVault))
18061814 then (abs(marginToVault) > cbalance())
18071815 else false)
18081816 then -(cbalance())
18091817 else marginToVault
18101818 let doExchangePnL = if ((marginToVaultAdj != 0))
18111819 then {
18121820 let doExchangePnL = invoke(vaultAddress(), "exchangeFreeAndLocked", [marginToVaultAdj], nil)
18131821 if ((doExchangePnL == doExchangePnL))
18141822 then nil
18151823 else throw("Strict value is not equal to itself.")
18161824 }
18171825 else nil
18181826 if ((doExchangePnL == doExchangePnL))
18191827 then (updateBalance((cbalance() + marginToVaultAdj)) ++ updateAmmWeights(newQuoteAssetWeight, newBaseAssetWeight))
18201828 else throw("Strict value is not equal to itself.")
18211829 }
18221830
18231831
18241832
18251833 @Callable(i)
18261834 func ensureCalledOnce () = if ((i.caller != this))
18271835 then throw("Invalid saveCurrentTxId parameters")
18281836 else {
18291837 let txId = toBase58String(i.transactionId)
18301838 let lastTx = valueOrElse(getString(this, k_lastTx), "")
18311839 if ((lastTx != txId))
18321840 then [StringEntry(k_lastTx, txId)]
18331841 else throw("Can not call vAMM methods twice in one tx")
18341842 }
18351843
18361844
18371845
18381846 @Callable(i)
18391847 func migratePosition (_trader) = {
18401848 let positionSizeOpt = getInteger(this, toCompositeKey(k_positionSize, _trader))
18411849 if (if (isDefined(positionSizeOpt))
18421850 then isDefined(addressFromString(_trader))
18431851 else false)
18441852 then {
18451853 let pSize = getIntegerValue(this, toCompositeKey(k_positionSize, _trader))
18461854 let pMargin = getIntegerValue(this, toCompositeKey(k_positionMargin, _trader))
18471855 let pNotional = getIntegerValue(this, toCompositeKey(k_positionOpenNotional, _trader))
18481856 let pFraction = getIntegerValue(this, toCompositeKey(k_positionLastUpdatedCumulativePremiumFraction, _trader))
18491857 let pTimestamp = valueOrElse(getInteger(this, toCompositeKey(k_positionLastUpdatedTimestamp, _trader)), lastBlock.timestamp)
18501858 let pFee = valueOrElse(getInteger(this, toCompositeKey(k_positionFee, _trader)), fee())
18511859 let pSequence = getIntegerValue(this, toCompositeKey(k_positionSequence, _trader))
18521860 let pDirection = getDirection(pSize)
18531861 let positionKey = ((_trader + "_") + toString(pDirection))
18541862 [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)]
18551863 }
18561864 else throw(("Nothing to migrate for " + _trader))
18571865 }
18581866
18591867
18601868
18611869 @Callable(i)
18621870 func view_calcRemainMarginWithFundingPayment (_trader,_direction,_priceUpdate) = {
18631871 let updateOracle = invoke(this, "updateOracle", [_priceUpdate], nil)
18641872 if ((updateOracle == updateOracle))
18651873 then {
18661874 let sync = invoke(this, "syncTerminalPriceToOracle", nil, nil)
18671875 if ((sync == sync))
18681876 then {
1869- let $t08637186507 = getPosition(_trader, _direction)
1870- let positionSize = $t08637186507._1
1871- let positionMargin = $t08637186507._2
1872- let pon = $t08637186507._3
1873- let positionLstUpdCPF = $t08637186507._4
1874- let positionTimestamp = $t08637186507._5
1875- let $t08651086623 = getPositionNotionalAndUnrealizedPnl(_trader, _direction, PNL_OPTION_SPOT)
1876- let positionNotional = $t08651086623._1
1877- let unrealizedPnl = $t08651086623._2
1878- let $t08662686850 = calcRemainMarginWithFundingPaymentAndRolloverFee(positionSize, positionMargin, positionLstUpdCPF, positionTimestamp, unrealizedPnl)
1879- let remainMargin = $t08662686850._1
1880- let badDebt = $t08662686850._2
1881- let fundingPayment = $t08662686850._3
1882- let rolloverFee = $t08662686850._4
1877+ let $t08661486750 = getPosition(_trader, _direction)
1878+ let positionSize = $t08661486750._1
1879+ let positionMargin = $t08661486750._2
1880+ let pon = $t08661486750._3
1881+ let positionLstUpdCPF = $t08661486750._4
1882+ let positionTimestamp = $t08661486750._5
1883+ let $t08675386866 = getPositionNotionalAndUnrealizedPnl(_trader, _direction, PNL_OPTION_SPOT)
1884+ let positionNotional = $t08675386866._1
1885+ let unrealizedPnl = $t08675386866._2
1886+ let $t08686987093 = calcRemainMarginWithFundingPaymentAndRolloverFee(positionSize, positionMargin, positionLstUpdCPF, positionTimestamp, unrealizedPnl)
1887+ let remainMargin = $t08686987093._1
1888+ let badDebt = $t08686987093._2
1889+ let fundingPayment = $t08686987093._3
1890+ let rolloverFee = $t08686987093._4
18831891 let underlyingPrice = getOraclePrice()
18841892 let spotPrice = getSpotPrice()
18851893 throw(((((((((s(remainMargin) + s(fundingPayment)) + s(getMarginRatio(_trader, _direction))) + s(unrealizedPnl)) + s(badDebt)) + s(positionNotional)) + s(rolloverFee)) + s(underlyingPrice)) + s(spotPrice)))
18861894 }
18871895 else throw("Strict value is not equal to itself.")
18881896 }
18891897 else throw("Strict value is not equal to itself.")
18901898 }
18911899
18921900
18931901
18941902 @Callable(i)
18951903 func view_getPegAdjustCost (_price) = {
18961904 let _qtAstR = qtAstR()
18971905 let _bsAstR = bsAstR()
18981906 let result = getSyncTerminalPrice(_price, _qtAstR, _bsAstR)
18991907 throw(toString(result._3))
19001908 }
19011909
19021910
19031911
19041912 @Callable(i)
19051913 func view_getTerminalAmmPrice () = {
1906- let $t08770387784 = getTerminalAmmState()
1907- let terminalQuoteAssetReserve = $t08770387784._1
1908- let terminalBaseAssetReserve = $t08770387784._2
1914+ let $t08794688027 = getTerminalAmmState()
1915+ let terminalQuoteAssetReserve = $t08794688027._1
1916+ let terminalBaseAssetReserve = $t08794688027._2
19091917 let price = divd(muld(terminalQuoteAssetReserve, qtAstW()), muld(terminalBaseAssetReserve, bsAstW()))
19101918 throw(toString(price))
19111919 }
19121920
19131921
19141922
19151923 @Callable(i)
19161924 func view_getFunding (_priceUpdate) = {
19171925 let updateOracle = invoke(this, "updateOracle", [_priceUpdate], nil)
19181926 if ((updateOracle == updateOracle))
19191927 then {
19201928 let sync = invoke(this, "syncTerminalPriceToOracle", nil, nil)
19211929 if ((sync == sync))
19221930 then {
19231931 let underlyingPrice = getOraclePrice()
1924- let $t08843688514 = getFunding()
1925- let shortPremiumFraction = $t08843688514._1
1926- let longPremiumFraction = $t08843688514._2
1927- let premiumToVault = $t08843688514._3
1932+ let $t08867988757 = getFunding()
1933+ let shortPremiumFraction = $t08867988757._1
1934+ let longPremiumFraction = $t08867988757._2
1935+ let premiumToVault = $t08867988757._3
19281936 let longFunding = divd(longPremiumFraction, underlyingPrice)
19291937 let shortFunding = divd(shortPremiumFraction, underlyingPrice)
19301938 throw(((((s(longFunding) + s(shortFunding)) + s(getSpotPrice())) + s(getOraclePrice())) + s(premiumToVault)))
19311939 }
19321940 else throw("Strict value is not equal to itself.")
19331941 }
19341942 else throw("Strict value is not equal to itself.")
19351943 }
19361944
19371945
19381946
19391947 @Callable(i)
19401948 func computeSpotPrice () = {
19411949 let sync = invoke(this, "syncTerminalPriceToOracle", nil, nil)
19421950 if ((sync == sync))
19431951 then {
19441952 let result = getSpotPrice()
19451953 $Tuple2(nil, result)
19461954 }
19471955 else throw("Strict value is not equal to itself.")
19481956 }
19491957
19501958
19511959
19521960 @Callable(i)
19531961 func computeFeeForTraderWithArtifact (_trader,_artifactId) = {
19541962 let result = getForTraderWithArtifact(_trader, _artifactId)
19551963 $Tuple2(nil, result)
19561964 }
19571965
19581966
19591967 @Verifier(tx)
19601968 func verify () = {
19611969 let coordinatorStr = getString(this, k_coordinatorAddress)
19621970 if (isDefined(coordinatorStr))
19631971 then {
19641972 let admin = getString(addressFromStringValue(value(coordinatorStr)), k_admin_address)
19651973 if (isDefined(admin))
19661974 then valueOrElse(getBoolean(addressFromStringValue(value(admin)), ((("status_" + toString(this)) + "_") + toBase58String(tx.id))), false)
19671975 else throw("unable to verify: admin not set in coordinator")
19681976 }
19691977 else sigVerify(tx.bodyBytes, tx.proofs[0], tx.senderPublicKey)
19701978 }
19711979

github/deemru/w8io/026f985 
189.62 ms