tx · 2SGwKQ3avUMFqQe6fFiYTDKwjkqNWXudart7NJZjvLLh

3MqvpsUpcaFXP5TcBUGxshpD4nRDSMEkYn6:  -0.08000000 Waves

2023.07.11 18:18 [2661418] smart account 3MqvpsUpcaFXP5TcBUGxshpD4nRDSMEkYn6 > SELF 0.00000000 Waves

{ "type": 13, "id": "2SGwKQ3avUMFqQe6fFiYTDKwjkqNWXudart7NJZjvLLh", "fee": 8000000, "feeAssetId": null, "timestamp": 1689088784239, "version": 2, "chainId": 84, "sender": "3MqvpsUpcaFXP5TcBUGxshpD4nRDSMEkYn6", "senderPublicKey": "9bdt1eKejUnTYnGPv3nSedCkRobiQ3EAzWkr4diiX1uN", "proofs": [ "4m1t7iTb7x1KRRTgSwiB8Nt9i3KZgWV1T57TU7XEMMt12NvPajr4Pt7AaRaevAaquwAM44NyjEogqtBDB5ZHq9gD" ], "script": "base64:BgKUAQgCEgASABIAEgASAwoBARIVChMBAQEBAQEBAQEBAQEBAQEICAEBEhgKFgEBAQEBAQEICAgBAQEBAQEBAQEBAQESBwoFAQEBCAgSBAoCAQgSBQoDAQEIEgcKBQEBAQQIEgUKAwgBCBIDCgEIEgMKAQgSABIAEgMKAQgSBQoDCAEIEgMKAQESABIDCgEIEgASBAoCCAi/AQAMa19iYXNlT3JhY2xlAgxrX2Jhc2VPcmFjbGUADWtfcXVvdGVPcmFjbGUCDWtfcXVvdGVPcmFjbGUACWtfYmFsYW5jZQIJa19iYWxhbmNlAAprX3NlcXVlbmNlAgprX3NlcXVlbmNlAA5rX3Bvc2l0aW9uU2l6ZQIOa19wb3NpdGlvblNpemUAEGtfcG9zaXRpb25NYXJnaW4CEGtfcG9zaXRpb25NYXJnaW4AFmtfcG9zaXRpb25PcGVuTm90aW9uYWwCFmtfcG9zaXRpb25PcGVuTm90aW9uYWwALmtfcG9zaXRpb25MYXN0VXBkYXRlZEN1bXVsYXRpdmVQcmVtaXVtRnJhY3Rpb24CEmtfcG9zaXRpb25GcmFjdGlvbgASa19wb3NpdGlvblNlcXVlbmNlAhJrX3Bvc2l0aW9uU2VxdWVuY2UADWtfcG9zaXRpb25GZWUCDWtfcG9zaXRpb25GZWUAHmtfcG9zaXRpb25MYXN0VXBkYXRlZFRpbWVzdGFtcAITa19wb3NpdGlvblRpbWVzdGFtcAANa19pbml0aWFsaXplZAINa19pbml0aWFsaXplZAAIa19wYXVzZWQCCGtfcGF1c2VkAAtrX2Nsb3NlT25seQILa19jbG9zZU9ubHkABWtfZmVlAgVrX2ZlZQANa19yb2xsb3ZlckZlZQIOa19yb2xsb3Zlcl9mZWUAD2tfZnVuZGluZ1BlcmlvZAIPa19mdW5kaW5nUGVyaW9kABFrX2luaXRNYXJnaW5SYXRpbwIRa19pbml0TWFyZ2luUmF0aW8AFGtfbWluSW5pdE1hcmdpblJhdGlvAhRrX21pbkluaXRNYXJnaW5SYXRpbwAYa19tYWludGVuYW5jZU1hcmdpblJhdGlvAgVrX21tcgAVa19saXF1aWRhdGlvbkZlZVJhdGlvAhVrX2xpcXVpZGF0aW9uRmVlUmF0aW8AGWtfcGFydGlhbExpcXVpZGF0aW9uUmF0aW8CFmtfcGFydExpcXVpZGF0aW9uUmF0aW8ADWtfc3ByZWFkTGltaXQCDWtfc3ByZWFkTGltaXQAEGtfbWF4UHJpY2VJbXBhY3QCEGtfbWF4UHJpY2VJbXBhY3QAEGtfbWF4UHJpY2VTcHJlYWQCEGtfbWF4UHJpY2VTcHJlYWQAEWtfbWF4T3Blbk5vdGlvbmFsAhFrX21heE9wZW5Ob3Rpb25hbAAVa19mZWVUb1N0YWtlcnNQZXJjZW50AhVrX2ZlZVRvU3Rha2Vyc1BlcmNlbnQAEGtfbWF4T3JhY2xlRGVsYXkCEGtfbWF4T3JhY2xlRGVsYXkADWtfZnVuZGluZ01vZGUCDWtfZnVuZGluZ01vZGUADGtfb3JhY2xlTW9kZQIMa19vcmFjbGVNb2RlAA5rX3Bvc2l0aW9uTW9kZQIOa19wb3NpdGlvbk1vZGUAGGtfbWluTGlxdWlkYXRpb25Ob3Rpb25hbAIYa19taW5MaXF1aWRhdGlvbk5vdGlvbmFsACVrX2xhdGVzdExvbmdDdW11bGF0aXZlUHJlbWl1bUZyYWN0aW9uAhtrX2xhdGVzdExvbmdQcmVtaXVtRnJhY3Rpb24AJmtfbGF0ZXN0U2hvcnRDdW11bGF0aXZlUHJlbWl1bUZyYWN0aW9uAhxrX2xhdGVzdFNob3J0UHJlbWl1bUZyYWN0aW9uABJrX25leHRGdW5kaW5nQmxvY2sCHmtfbmV4dEZ1bmRpbmdCbG9ja01pblRpbWVzdGFtcAARa19sb25nRnVuZGluZ1JhdGUCEWtfbG9uZ0Z1bmRpbmdSYXRlABJrX3Nob3J0RnVuZGluZ1JhdGUCEmtfc2hvcnRGdW5kaW5nUmF0ZQATa19xdW90ZUFzc2V0UmVzZXJ2ZQIIa19xdEFzdFIAEmtfYmFzZUFzc2V0UmVzZXJ2ZQIIa19ic0FzdFIAEmtfcXVvdGVBc3NldFdlaWdodAIIa19xdEFzdFcAEWtfYmFzZUFzc2V0V2VpZ2h0AghrX2JzQXN0VwATa190b3RhbFBvc2l0aW9uU2l6ZQITa190b3RhbFBvc2l0aW9uU2l6ZQAXa190b3RhbExvbmdQb3NpdGlvblNpemUCF2tfdG90YWxMb25nUG9zaXRpb25TaXplABhrX3RvdGFsU2hvcnRQb3NpdGlvblNpemUCGGtfdG90YWxTaG9ydFBvc2l0aW9uU2l6ZQAWa19vcGVuSW50ZXJlc3ROb3Rpb25hbAIWa19vcGVuSW50ZXJlc3ROb3Rpb25hbAATa19vcGVuSW50ZXJlc3RTaG9ydAITa19vcGVuSW50ZXJlc3RTaG9ydAASa19vcGVuSW50ZXJlc3RMb25nAhJrX29wZW5JbnRlcmVzdExvbmcACGtfbGFzdFR4AghrX2xhc3RUeAAUa19jb29yZGluYXRvckFkZHJlc3MCFGtfY29vcmRpbmF0b3JBZGRyZXNzAA9rX3ZhdWx0X2FkZHJlc3MCD2tfdmF1bHRfYWRkcmVzcwAPa19hZG1pbl9hZGRyZXNzAg9rX2FkbWluX2FkZHJlc3MADWtfcXVvdGVfYXNzZXQCDWtfcXVvdGVfYXNzZXQAEWtfc3Rha2luZ19hZGRyZXNzAhFrX3N0YWtpbmdfYWRkcmVzcwAPa19taW5lcl9hZGRyZXNzAg9rX21pbmVyX2FkZHJlc3MAEGtfb3JkZXJzX2FkZHJlc3MCEGtfb3JkZXJzX2FkZHJlc3MAEmtfcmVmZXJyYWxfYWRkcmVzcwISa19yZWZlcnJhbF9hZGRyZXNzABVrX25mdF9tYW5hZ2VyX2FkZHJlc3MCFWtfbmZ0X21hbmFnZXJfYWRkcmVzcwEOdG9Db21wb3NpdGVLZXkCBF9rZXkIX2FkZHJlc3MJAKwCAgkArAICBQRfa2V5AgFfBQhfYWRkcmVzcwELY29vcmRpbmF0b3IACQETdmFsdWVPckVycm9yTWVzc2FnZQIJAKYIAQkBEUBleHRyTmF0aXZlKDEwNTMpAgUEdGhpcwUUa19jb29yZGluYXRvckFkZHJlc3MCE0Nvb3JkaW5hdG9yIG5vdCBzZXQBDGFkbWluQWRkcmVzcwAJAKYIAQkBEUBleHRyTmF0aXZlKDEwNTMpAgkBC2Nvb3JkaW5hdG9yAAUPa19hZG1pbl9hZGRyZXNzAQpxdW90ZUFzc2V0AAkA2QQBCQERQGV4dHJOYXRpdmUoMTA1MykCCQELY29vcmRpbmF0b3IABQ1rX3F1b3RlX2Fzc2V0AQ5zdGFraW5nQWRkcmVzcwAJARN2YWx1ZU9yRXJyb3JNZXNzYWdlAgkApggBCQERQGV4dHJOYXRpdmUoMTA1MykCCQELY29vcmRpbmF0b3IABRFrX3N0YWtpbmdfYWRkcmVzcwIPU3Rha2luZyBub3Qgc2V0AQx2YXVsdEFkZHJlc3MACQETdmFsdWVPckVycm9yTWVzc2FnZQIJAKYIAQkBEUBleHRyTmF0aXZlKDEwNTMpAgkBC2Nvb3JkaW5hdG9yAAUPa192YXVsdF9hZGRyZXNzAg1WYXVsdCBub3Qgc2V0AQxtaW5lckFkZHJlc3MACQETdmFsdWVPckVycm9yTWVzc2FnZQIJAKYIAQkBEUBleHRyTmF0aXZlKDEwNTMpAgkBC2Nvb3JkaW5hdG9yAAUPa19taW5lcl9hZGRyZXNzAg1NaW5lciBub3Qgc2V0AQ1vcmRlcnNBZGRyZXNzAAkBE3ZhbHVlT3JFcnJvck1lc3NhZ2UCCQCmCAEJARFAZXh0ck5hdGl2ZSgxMDUzKQIJAQtjb29yZGluYXRvcgAFEGtfb3JkZXJzX2FkZHJlc3MCDk9yZGVycyBub3Qgc2V0AQ9yZWZlcnJhbEFkZHJlc3MACQETdmFsdWVPckVycm9yTWVzc2FnZQIJAKYIAQkBEUBleHRyTmF0aXZlKDEwNTMpAgkBC2Nvb3JkaW5hdG9yAAUSa19yZWZlcnJhbF9hZGRyZXNzAhBSZWZlcnJhbCBub3Qgc2V0ARFuZnRNYW5hZ2VyQWRkcmVzcwAJARN2YWx1ZU9yRXJyb3JNZXNzYWdlAgkApggBCQERQGV4dHJOYXRpdmUoMTA1MykCCQELY29vcmRpbmF0b3IABRVrX25mdF9tYW5hZ2VyX2FkZHJlc3MCE05GVCBNYW5hZ2VyIG5vdCBzZXQADWtfdG9rZW5fcGFyYW0CDWtfdG9rZW5fcGFyYW0ADGtfdG9rZW5fdHlwZQIMa190b2tlbl90eXBlABhGRUVfUkVEVUNUSU9OX1RPS0VOX1RZUEUCDWZlZV9yZWR1Y3Rpb24ACERJUl9MT05HAAEACURJUl9TSE9SVAACAAdTRUNPTkRTAOgHAA9ERUNJTUFMX05VTUJFUlMABgAMREVDSU1BTF9VTklUCQBoAgABCQBoAgkAaAIJAGgCCQBoAgkAaAIACgAKAAoACgAKAAoAD01JTlVURVNfSU5fWUVBUgkAaAIAoIogBQxERUNJTUFMX1VOSVQAB09ORV9EQVkJAGgCAICjBQUMREVDSU1BTF9VTklUAA9QTkxfT1BUSU9OX1NQT1QAAQARUE5MX09QVElPTl9PUkFDTEUAAgASRlVORElOR19BU1lNTUVUUklDAAEAEUZVTkRJTkdfU1lNTUVUUklDAAIADE9SQUNMRV9QTEFJTgABAApPUkFDTEVfSklUAAIAD1BPU0lUSU9OX0RJUkVDVAABAA5QT1NJVElPTl9PUkRFUgACAQFzAQJfeAkArAICCQCkAwEFAl94AgEsAQRkaXZkAgJfeAJfeQkAbgQFAl94BQxERUNJTUFMX1VOSVQFAl95BQhIQUxGRVZFTgEEbXVsZAICX3gCX3kJAG4EBQJfeAUCX3kFDERFQ0lNQUxfVU5JVAUISEFMRkVWRU4BBWJkaXZkAgJfeAJfeQkAvQIEBQJfeAkAtgIBBQxERUNJTUFMX1VOSVQFAl95BQhIQUxGRVZFTgEFYm11bGQCAl94Al95CQC9AgQFAl94BQJfeQkAtgIBBQxERUNJTUFMX1VOSVQFCEhBTEZFVkVOAQNhYnMBAl94AwkAZgIFAl94AAAFAl94CQEBLQEFAl94AQR2bWF4AgJfeAJfeQMJAGcCBQJfeAUCX3kFAl94BQJfeQEDaW50AQFrCQETdmFsdWVPckVycm9yTWVzc2FnZQIJAJoIAgUEdGhpcwUBawkArAICAg1ubyB2YWx1ZSBmb3IgBQFrAQVpbnRPcgIBawNkZWYJAQt2YWx1ZU9yRWxzZQIJAJoIAgUEdGhpcwUBawUDZGVmAQRzdHJBAghfYWRkcmVzcwRfa2V5BAN2YWwJARN2YWx1ZU9yRXJyb3JNZXNzYWdlAgkAnQgCBQhfYWRkcmVzcwUEX2tleQkArAICAhFObyB2YWx1ZSBmb3Iga2V5IAUEX2tleQUDdmFsAQRpbnRBAghfYWRkcmVzcwRfa2V5BAN2YWwJARN2YWx1ZU9yRXJyb3JNZXNzYWdlAgkAmggCBQhfYWRkcmVzcwUEX2tleQkArAICAhFObyB2YWx1ZSBmb3Iga2V5IAUEX2tleQUDdmFsAQhjYmFsYW5jZQAJAQNpbnQBBQlrX2JhbGFuY2UBCWNiYWxhbmNlMAAJAQVpbnRPcgIFCWtfYmFsYW5jZQAAAQNmZWUACQEDaW50AQUFa19mZWUBD3JvbGxvdmVyRmVlUmF0ZQAJAQNpbnQBBQ1rX3JvbGxvdmVyRmVlAQ9pbml0TWFyZ2luUmF0aW8ACQEDaW50AQURa19pbml0TWFyZ2luUmF0aW8BEm1pbkluaXRNYXJnaW5SYXRpbwAJAQVpbnRPcgIFFGtfbWluSW5pdE1hcmdpblJhdGlvBQxERUNJTUFMX1VOSVQBBnF0QXN0UgAJAQNpbnQBBRNrX3F1b3RlQXNzZXRSZXNlcnZlAQdxdEFzdFIwAAkBBWludE9yAgUTa19xdW90ZUFzc2V0UmVzZXJ2ZQAAAQZic0FzdFIACQEDaW50AQUSa19iYXNlQXNzZXRSZXNlcnZlAQdic0FzdFIwAAkBBWludE9yAgUSa19iYXNlQXNzZXRSZXNlcnZlAAABBnF0QXN0VwAJAQVpbnRPcgIFEmtfcXVvdGVBc3NldFdlaWdodAUMREVDSU1BTF9VTklUAQZic0FzdFcACQEFaW50T3ICBRFrX2Jhc2VBc3NldFdlaWdodAUMREVDSU1BTF9VTklUARF0b3RhbFBvc2l0aW9uU2l6ZQAJAQNpbnQBBRNrX3RvdGFsUG9zaXRpb25TaXplARRvcGVuSW50ZXJlc3ROb3Rpb25hbAAJAQNpbnQBBRZrX29wZW5JbnRlcmVzdE5vdGlvbmFsARFvcGVuSW50ZXJlc3RTaG9ydAAJAQNpbnQBBRNrX29wZW5JbnRlcmVzdFNob3J0ARBvcGVuSW50ZXJlc3RMb25nAAkBA2ludAEFEmtfb3BlbkludGVyZXN0TG9uZwEZbmV4dEZ1bmRpbmdCbG9ja1RpbWVzdGFtcAAJAQNpbnQBBRJrX25leHRGdW5kaW5nQmxvY2sBEGZ1bmRpbmdQZXJpb2RSYXcACQEDaW50AQUPa19mdW5kaW5nUGVyaW9kARRmdW5kaW5nUGVyaW9kRGVjaW1hbAAJAGgCCQEQZnVuZGluZ1BlcmlvZFJhdwAFDERFQ0lNQUxfVU5JVAEUZnVuZGluZ1BlcmlvZFNlY29uZHMACQBoAgkBEGZ1bmRpbmdQZXJpb2RSYXcABQdTRUNPTkRTARZtYWludGVuYW5jZU1hcmdpblJhdGlvAAkBA2ludAEFGGtfbWFpbnRlbmFuY2VNYXJnaW5SYXRpbwETbGlxdWlkYXRpb25GZWVSYXRpbwAJAQNpbnQBBRVrX2xpcXVpZGF0aW9uRmVlUmF0aW8BF3BhcnRpYWxMaXF1aWRhdGlvblJhdGlvAAkBA2ludAEFGWtfcGFydGlhbExpcXVpZGF0aW9uUmF0aW8BC3NwcmVhZExpbWl0AAkBA2ludAEFDWtfc3ByZWFkTGltaXQBDm1heFByaWNlSW1wYWN0AAkBA2ludAEFEGtfbWF4UHJpY2VJbXBhY3QBDm1heFByaWNlU3ByZWFkAAkBA2ludAEFEGtfbWF4UHJpY2VTcHJlYWQBD21heE9wZW5Ob3Rpb25hbAAJAQNpbnQBBRFrX21heE9wZW5Ob3Rpb25hbAEjbGF0ZXN0TG9uZ0N1bXVsYXRpdmVQcmVtaXVtRnJhY3Rpb24ACQEDaW50AQUla19sYXRlc3RMb25nQ3VtdWxhdGl2ZVByZW1pdW1GcmFjdGlvbgEkbGF0ZXN0U2hvcnRDdW11bGF0aXZlUHJlbWl1bUZyYWN0aW9uAAkBA2ludAEFJmtfbGF0ZXN0U2hvcnRDdW11bGF0aXZlUHJlbWl1bUZyYWN0aW9uARZ0b3RhbFNob3J0UG9zaXRpb25TaXplAAkBA2ludAEFGGtfdG90YWxTaG9ydFBvc2l0aW9uU2l6ZQEVdG90YWxMb25nUG9zaXRpb25TaXplAAkBA2ludAEFF2tfdG90YWxMb25nUG9zaXRpb25TaXplAQxsYXN0U2VxdWVuY2UACQEFaW50T3ICBQprX3NlcXVlbmNlAAABE2ZlZVRvU3Rha2Vyc1BlcmNlbnQACQEDaW50AQUVa19mZWVUb1N0YWtlcnNQZXJjZW50AQ5tYXhPcmFjbGVEZWxheQAJAQNpbnQBBRBrX21heE9yYWNsZURlbGF5AQtmdW5kaW5nTW9kZQAJAQVpbnRPcgIFDWtfZnVuZGluZ01vZGUFEkZVTkRJTkdfQVNZTU1FVFJJQwEKb3JhY2xlTW9kZQAJAQVpbnRPcgIFDGtfb3JhY2xlTW9kZQUMT1JBQ0xFX1BMQUlOAQxwb3NpdGlvbk1vZGUACQEFaW50T3ICBQ5rX3Bvc2l0aW9uTW9kZQUPUE9TSVRJT05fRElSRUNUAR1taW5QYXJ0aWFsTGlxdWlkYXRpb25Ob3Rpb25hbAAJAQVpbnRPcgIFGGtfbWluTGlxdWlkYXRpb25Ob3Rpb25hbAkAaAIACgUMREVDSU1BTF9VTklUAQ1sYXN0VGltZXN0YW1wAAgFCWxhc3RCbG9jawl0aW1lc3RhbXABD2dldEFjdHVhbENhbGxlcgEBaQkBC3ZhbHVlT3JFbHNlAgkAnQgCCQENb3JkZXJzQWRkcmVzcwACCGtfc2VuZGVyCQClCAEIBQFpBmNhbGxlcgEWcmVxdWlyZU1vcmVNYXJnaW5SYXRpbwMMX21hcmdpblJhdGlvEF9iYXNlTWFyZ2luUmF0aW8UX2xhcmdlclRoYW5PckVxdWFsVG8EFHJlbWFpbmluZ01hcmdpblJhdGlvCQBlAgUMX21hcmdpblJhdGlvBRBfYmFzZU1hcmdpblJhdGlvAwMFFF9sYXJnZXJUaGFuT3JFcXVhbFRvCQBmAgAABRRyZW1haW5pbmdNYXJnaW5SYXRpbwcJAAIBCQCsAgIJAKwCAgkArAICAhBJbnZhbGlkIG1hcmdpbjogCQCkAwEFDF9tYXJnaW5SYXRpbwIDIDwgCQCkAwEFEF9iYXNlTWFyZ2luUmF0aW8DAwkBASEBBRRfbGFyZ2VyVGhhbk9yRXF1YWxUbwkAZwIFFHJlbWFpbmluZ01hcmdpblJhdGlvAAAHCQACAQkArAICCQCsAgIJAKwCAgIQSW52YWxpZCBtYXJnaW46IAkApAMBBQxfbWFyZ2luUmF0aW8CAyA+IAkApAMBBRBfYmFzZU1hcmdpblJhdGlvBgEfbGF0ZXN0Q3VtdWxhdGl2ZVByZW1pdW1GcmFjdGlvbgENX3Bvc2l0aW9uU2l6ZQMJAAACBQ1fcG9zaXRpb25TaXplAAAJAAIBAixTaG91bGQgbm90IGJlIGNhbGxlZCB3aXRoIF9wb3NpdGlvblNpemUgPT0gMAMJAGYCBQ1fcG9zaXRpb25TaXplAAAJASNsYXRlc3RMb25nQ3VtdWxhdGl2ZVByZW1pdW1GcmFjdGlvbgAJASRsYXRlc3RTaG9ydEN1bXVsYXRpdmVQcmVtaXVtRnJhY3Rpb24AAQtnZXRQb3NpdGlvbgIHX3RyYWRlcgpfZGlyZWN0aW9uBAtwb3NpdGlvbktleQkArAICCQCsAgIFB190cmFkZXICAV8JAKQDAQUKX2RpcmVjdGlvbgQPcG9zaXRpb25TaXplT3B0CQCaCAIFBHRoaXMJAQ50b0NvbXBvc2l0ZUtleQIFDmtfcG9zaXRpb25TaXplBQtwb3NpdGlvbktleQQHJG1hdGNoMAUPcG9zaXRpb25TaXplT3B0AwkAAQIFByRtYXRjaDACA0ludAQMcG9zaXRpb25TaXplBQckbWF0Y2gwCQCXCgUFDHBvc2l0aW9uU2l6ZQkBEUBleHRyTmF0aXZlKDEwNTApAgUEdGhpcwkBDnRvQ29tcG9zaXRlS2V5AgUQa19wb3NpdGlvbk1hcmdpbgULcG9zaXRpb25LZXkJARFAZXh0ck5hdGl2ZSgxMDUwKQIFBHRoaXMJAQ50b0NvbXBvc2l0ZUtleQIFFmtfcG9zaXRpb25PcGVuTm90aW9uYWwFC3Bvc2l0aW9uS2V5CQERQGV4dHJOYXRpdmUoMTA1MCkCBQR0aGlzCQEOdG9Db21wb3NpdGVLZXkCBS5rX3Bvc2l0aW9uTGFzdFVwZGF0ZWRDdW11bGF0aXZlUHJlbWl1bUZyYWN0aW9uBQtwb3NpdGlvbktleQkBEUBleHRyTmF0aXZlKDEwNTApAgUEdGhpcwkBDnRvQ29tcG9zaXRlS2V5AgUea19wb3NpdGlvbkxhc3RVcGRhdGVkVGltZXN0YW1wBQtwb3NpdGlvbktleQkAlwoFAAAAAAAAAAAAAAEMZ2V0RGlyZWN0aW9uAQ1fcG9zaXRpb25TaXplAwkAZgIAAAUNX3Bvc2l0aW9uU2l6ZQUJRElSX1NIT1JUBQhESVJfTE9ORwEOZ2V0UG9zaXRpb25GZWUCB190cmFkZXIKX2RpcmVjdGlvbgQLcG9zaXRpb25LZXkJAKwCAgkArAICBQdfdHJhZGVyAgFfCQCkAwEFCl9kaXJlY3Rpb24EDnBvc2l0aW9uRmVlT3B0CQCaCAIFBHRoaXMJAQ50b0NvbXBvc2l0ZUtleQIFDWtfcG9zaXRpb25GZWUFC3Bvc2l0aW9uS2V5BAckbWF0Y2gwBQ5wb3NpdGlvbkZlZU9wdAMJAAECBQckbWF0Y2gwAgNJbnQEC3Bvc2l0aW9uRmVlBQckbWF0Y2gwBQtwb3NpdGlvbkZlZQkBA2ZlZQABE3JlcXVpcmVPcGVuUG9zaXRpb24CB190cmFkZXIKX2RpcmVjdGlvbgMJAAACCAkBC2dldFBvc2l0aW9uAgUHX3RyYWRlcgUKX2RpcmVjdGlvbgJfMQAACQACAQIQTm8gb3BlbiBwb3NpdGlvbgYBDWdldE9yYWNsZURhdGEBA2tleQQNb3JhY2xlRGF0YVN0cgkAnQgCBQR0aGlzBQNrZXkDAwkBCWlzRGVmaW5lZAEFDW9yYWNsZURhdGFTdHIJAQIhPQIJAQV2YWx1ZQEFDW9yYWNsZURhdGFTdHICAAcECm9yYWNsZURhdGEJALUJAgkBBXZhbHVlAQUNb3JhY2xlRGF0YVN0cgIBLAQNb3JhY2xlQWRkcmVzcwkBE3ZhbHVlT3JFcnJvck1lc3NhZ2UCCQCmCAEJAJEDAgUKb3JhY2xlRGF0YQAACQCsAgICG0ludmFsaWQgb3JhY2xlIGFkZHJlc3MgaW46IAkBBXZhbHVlAQUNb3JhY2xlRGF0YVN0cgQIcHJpY2VLZXkJAJEDAgUKb3JhY2xlRGF0YQABBAhibG9ja0tleQkAkQMCBQpvcmFjbGVEYXRhAAIEB29wZW5LZXkJAJEDAgUKb3JhY2xlRGF0YQADCQCWCgQFDW9yYWNsZUFkZHJlc3MFCHByaWNlS2V5BQhibG9ja0tleQUHb3BlbktleQUEdW5pdAELaW5pdGlhbGl6ZWQACQELdmFsdWVPckVsc2UCCQCbCAIFBHRoaXMFDWtfaW5pdGlhbGl6ZWQHAQZwYXVzZWQACQELdmFsdWVPckVsc2UCCQCbCAIFBHRoaXMFCGtfcGF1c2VkBwEJY2xvc2VPbmx5AAkBC3ZhbHVlT3JFbHNlAgkAmwgCBQR0aGlzBQtrX2Nsb3NlT25seQcBDXVwZGF0ZVJlc2VydmUDBl9pc0FkZBFfcXVvdGVBc3NldEFtb3VudBBfYmFzZUFzc2V0QW1vdW50AwUGX2lzQWRkBAduZXdCYXNlCQBlAgkBBmJzQXN0UgAFEF9iYXNlQXNzZXRBbW91bnQDCQBnAgAABQduZXdCYXNlCQACAQIqVHggbGVhZCB0byBiYXNlIGFzc2V0IHJlc2VydmUgPD0gMCwgcmV2ZXJ0CQCVCgMJAGQCCQEGcXRBc3RSAAURX3F1b3RlQXNzZXRBbW91bnQFB25ld0Jhc2UJAGQCCQERdG90YWxQb3NpdGlvblNpemUABRBfYmFzZUFzc2V0QW1vdW50BAhuZXdRdW90ZQkAZQIJAQZxdEFzdFIABRFfcXVvdGVBc3NldEFtb3VudAMJAGcCAAAFCG5ld1F1b3RlCQACAQIqVHggbGVhZCB0byBiYXNlIHF1b3RlIHJlc2VydmUgPD0gMCwgcmV2ZXJ0CQCVCgMFCG5ld1F1b3RlCQBkAgkBBmJzQXN0UgAFEF9iYXNlQXNzZXRBbW91bnQJAGUCCQERdG90YWxQb3NpdGlvblNpemUABRBfYmFzZUFzc2V0QW1vdW50AQ1jYWxjSW52YXJpYW50AgdfcXRBc3RSB19ic0FzdFIEB2JxdEFzdFIJALYCAQUHX3F0QXN0UgQHYmJzQXN0UgkAtgIBBQdfYnNBc3RSCQEFYm11bGQCBQdicXRBc3RSBQdiYnNBc3RSAQlzd2FwSW5wdXQCBl9pc0FkZBFfcXVvdGVBc3NldEFtb3VudAQHX3F0QXN0UgkBBnF0QXN0UgAEB19ic0FzdFIJAQZic0FzdFIABAdfcXRBc3RXCQEGcXRBc3RXAAQHX2JzQXN0VwkBBmJzQXN0VwAEGHF1b3RlQXNzZXRBbW91bnRBZGp1c3RlZAkBBGRpdmQCBRFfcXVvdGVBc3NldEFtb3VudAUHX3F0QXN0VwQBawkBDWNhbGNJbnZhcmlhbnQCBQdfcXRBc3RSBQdfYnNBc3RSBBZxdW90ZUFzc2V0UmVzZXJ2ZUFmdGVyAwUGX2lzQWRkCQBkAgUHX3F0QXN0UgUYcXVvdGVBc3NldEFtb3VudEFkanVzdGVkCQBlAgUHX3F0QXN0UgUYcXVvdGVBc3NldEFtb3VudEFkanVzdGVkBBViYXNlQXNzZXRSZXNlcnZlQWZ0ZXIJAKADAQkBBWJkaXZkAgUBawkAtgIBBRZxdW90ZUFzc2V0UmVzZXJ2ZUFmdGVyBBhhbW91bnRCYXNlQXNzZXRCb3VnaHRBYnMJAQNhYnMBCQBlAgUVYmFzZUFzc2V0UmVzZXJ2ZUFmdGVyBQdfYnNBc3RSBBVhbW91bnRCYXNlQXNzZXRCb3VnaHQDBQZfaXNBZGQFGGFtb3VudEJhc2VBc3NldEJvdWdodEFicwkBAS0BBRhhbW91bnRCYXNlQXNzZXRCb3VnaHRBYnMEDSR0MDE2NTg1MTY3NTUJAQ11cGRhdGVSZXNlcnZlAwUGX2lzQWRkBRhxdW90ZUFzc2V0QW1vdW50QWRqdXN0ZWQFGGFtb3VudEJhc2VBc3NldEJvdWdodEFicwQXcXVvdGVBc3NldFJlc2VydmVBZnRlcjEIBQ0kdDAxNjU4NTE2NzU1Al8xBBZiYXNlQXNzZXRSZXNlcnZlQWZ0ZXIxCAUNJHQwMTY1ODUxNjc1NQJfMgQXdG90YWxQb3NpdGlvblNpemVBZnRlcjEIBQ0kdDAxNjU4NTE2NzU1Al8zBAtwcmljZUJlZm9yZQkBBGRpdmQCCQEEbXVsZAIFB19xdEFzdFIFB19xdEFzdFcJAQRtdWxkAgUHX2JzQXN0UgUHX2JzQXN0VwQLbWFya2V0UHJpY2UJAQRkaXZkAgURX3F1b3RlQXNzZXRBbW91bnQFGGFtb3VudEJhc2VBc3NldEJvdWdodEFicwQJcHJpY2VEaWZmCQEDYWJzAQkAZQIFC3ByaWNlQmVmb3JlBQttYXJrZXRQcmljZQQLcHJpY2VJbXBhY3QJAGUCBQxERUNJTUFMX1VOSVQJAQRkaXZkAgULcHJpY2VCZWZvcmUJAGQCBQtwcmljZUJlZm9yZQUJcHJpY2VEaWZmBBNtYXhQcmljZUltcGFjdFZhbHVlCQEObWF4UHJpY2VJbXBhY3QAAwkAZgIFC3ByaWNlSW1wYWN0BRNtYXhQcmljZUltcGFjdFZhbHVlCQACAQkArAICCQCsAgIJAKwCAgkArAICCQCsAgIJAKwCAgkArAICCQCsAgIJAKwCAgkArAICCQCsAgIJAKwCAgkArAICAg1QcmljZSBpbXBhY3QgCQCkAwEFC3ByaWNlSW1wYWN0AhQgPiBtYXggcHJpY2UgaW1wYWN0IAkApAMBBRNtYXhQcmljZUltcGFjdFZhbHVlAhUgYmVmb3JlIHF1b3RlIGFzc2V0OiAJAKQDAQUHX3F0QXN0UgIUIGJlZm9yZSBiYXNlIGFzc2V0OiAJAKQDAQUHX2JzQXN0UgIhIHF1b3RlIGFzc2V0IGFtb3VudCB0byBleGNoYW5nZTogCQCkAwEFEV9xdW90ZUFzc2V0QW1vdW50Ag8gcHJpY2UgYmVmb3JlOiAJAKQDAQULcHJpY2VCZWZvcmUCDiBtYXJrZXRQcmljZTogCQCkAwEFC21hcmtldFByaWNlCQCWCgQFFWFtb3VudEJhc2VBc3NldEJvdWdodAUXcXVvdGVBc3NldFJlc2VydmVBZnRlcjEFFmJhc2VBc3NldFJlc2VydmVBZnRlcjEFF3RvdGFsUG9zaXRpb25TaXplQWZ0ZXIxAQ9jYWxjUm9sbG92ZXJGZWUCEl9vbGRQb3NpdGlvbk1hcmdpbiBfb2xkUG9zaXRpb25MYXN0VXBkYXRlZFRpbWVzdGFtcAQPcG9zaXRpb25NaW51dGVzCQBoAgkAaQIJAGkCCQBlAgkBDWxhc3RUaW1lc3RhbXAABSBfb2xkUG9zaXRpb25MYXN0VXBkYXRlZFRpbWVzdGFtcADoBwA8BQxERUNJTUFMX1VOSVQEC3JvbGxvdmVyRmVlCQEEZGl2ZAIJAQRtdWxkAgkBBG11bGQCBRJfb2xkUG9zaXRpb25NYXJnaW4FD3Bvc2l0aW9uTWludXRlcwkBD3JvbGxvdmVyRmVlUmF0ZQAFD01JTlVURVNfSU5fWUVBUgULcm9sbG92ZXJGZWUBMGNhbGNSZW1haW5NYXJnaW5XaXRoRnVuZGluZ1BheW1lbnRBbmRSb2xsb3ZlckZlZQUQX29sZFBvc2l0aW9uU2l6ZRJfb2xkUG9zaXRpb25NYXJnaW4lX29sZFBvc2l0aW9uQ3VtdWxhdGl2ZVByZW1pdW1GcmFjdGlvbiBfb2xkUG9zaXRpb25MYXN0VXBkYXRlZFRpbWVzdGFtcAxfbWFyZ2luRGVsdGEEDmZ1bmRpbmdQYXltZW50AwkBAiE9AgUQX29sZFBvc2l0aW9uU2l6ZQAABCBfbGF0ZXN0Q3VtdWxhdGl2ZVByZW1pdW1GcmFjdGlvbgkBH2xhdGVzdEN1bXVsYXRpdmVQcmVtaXVtRnJhY3Rpb24BBRBfb2xkUG9zaXRpb25TaXplCQEEbXVsZAIJAGUCBSBfbGF0ZXN0Q3VtdWxhdGl2ZVByZW1pdW1GcmFjdGlvbgUlX29sZFBvc2l0aW9uQ3VtdWxhdGl2ZVByZW1pdW1GcmFjdGlvbgUQX29sZFBvc2l0aW9uU2l6ZQAABAtyb2xsb3ZlckZlZQkBD2NhbGNSb2xsb3ZlckZlZQIFEl9vbGRQb3NpdGlvbk1hcmdpbgUgX29sZFBvc2l0aW9uTGFzdFVwZGF0ZWRUaW1lc3RhbXAEDHNpZ25lZE1hcmdpbgkAZAIJAGUCCQBlAgUMX21hcmdpbkRlbHRhBQtyb2xsb3ZlckZlZQUOZnVuZGluZ1BheW1lbnQFEl9vbGRQb3NpdGlvbk1hcmdpbgQNJHQwMTk0MjIxOTU0OQMJAGYCAAAFDHNpZ25lZE1hcmdpbgkAlAoCAAAJAQNhYnMBBQxzaWduZWRNYXJnaW4JAJQKAgkBA2FicwEFDHNpZ25lZE1hcmdpbgAABAxyZW1haW5NYXJnaW4IBQ0kdDAxOTQyMjE5NTQ5Al8xBAdiYWREZWJ0CAUNJHQwMTk0MjIxOTU0OQJfMgkAlgoEBQxyZW1haW5NYXJnaW4FB2JhZERlYnQFDmZ1bmRpbmdQYXltZW50BQtyb2xsb3ZlckZlZQEWc3dhcE91dHB1dFdpdGhSZXNlcnZlcwcGX2lzQWRkEF9iYXNlQXNzZXRBbW91bnQUX2NoZWNrTWF4UHJpY2VJbXBhY3QSX3F1b3RlQXNzZXRSZXNlcnZlEV9xdW90ZUFzc2V0V2VpZ2h0EV9iYXNlQXNzZXRSZXNlcnZlEF9iYXNlQXNzZXRXZWlnaHQEC3ByaWNlQmVmb3JlCQEEZGl2ZAIJAQRtdWxkAgUSX3F1b3RlQXNzZXRSZXNlcnZlBRFfcXVvdGVBc3NldFdlaWdodAkBBG11bGQCBRFfYmFzZUFzc2V0UmVzZXJ2ZQUQX2Jhc2VBc3NldFdlaWdodAMJAAACBRBfYmFzZUFzc2V0QW1vdW50AAAJAAIBAhlJbnZhbGlkIGJhc2UgYXNzZXQgYW1vdW50BAFrCQENY2FsY0ludmFyaWFudAIFEl9xdW90ZUFzc2V0UmVzZXJ2ZQURX2Jhc2VBc3NldFJlc2VydmUEGGJhc2VBc3NldFBvb2xBbW91bnRBZnRlcgMFBl9pc0FkZAkAZAIFEV9iYXNlQXNzZXRSZXNlcnZlBRBfYmFzZUFzc2V0QW1vdW50CQBlAgURX2Jhc2VBc3NldFJlc2VydmUFEF9iYXNlQXNzZXRBbW91bnQED3F1b3RlQXNzZXRBZnRlcgkAoAMBCQEFYmRpdmQCBQFrCQC2AgEFGGJhc2VBc3NldFBvb2xBbW91bnRBZnRlcgQPcXVvdGVBc3NldERlbHRhCQEDYWJzAQkAZQIFD3F1b3RlQXNzZXRBZnRlcgUSX3F1b3RlQXNzZXRSZXNlcnZlBA5xdW90ZUFzc2V0U29sZAkBBG11bGQCBQ9xdW90ZUFzc2V0RGVsdGEFEV9xdW90ZUFzc2V0V2VpZ2h0BBNtYXhQcmljZUltcGFjdFZhbHVlCQEObWF4UHJpY2VJbXBhY3QABA0kdDAyMDgxMTIwOTczCQENdXBkYXRlUmVzZXJ2ZQMJAQEhAQUGX2lzQWRkBQ9xdW90ZUFzc2V0RGVsdGEFEF9iYXNlQXNzZXRBbW91bnQEF3F1b3RlQXNzZXRSZXNlcnZlQWZ0ZXIxCAUNJHQwMjA4MTEyMDk3MwJfMQQWYmFzZUFzc2V0UmVzZXJ2ZUFmdGVyMQgFDSR0MDIwODExMjA5NzMCXzIEF3RvdGFsUG9zaXRpb25TaXplQWZ0ZXIxCAUNJHQwMjA4MTEyMDk3MwJfMwQLbWFya2V0UHJpY2UJAQRkaXZkAgUOcXVvdGVBc3NldFNvbGQFEF9iYXNlQXNzZXRBbW91bnQECXByaWNlRGlmZgkBA2FicwEJAGUCBQtwcmljZUJlZm9yZQULbWFya2V0UHJpY2UEC3ByaWNlSW1wYWN0CQBlAgUMREVDSU1BTF9VTklUCQEEZGl2ZAIFC3ByaWNlQmVmb3JlCQBkAgULcHJpY2VCZWZvcmUFCXByaWNlRGlmZgMDCQBmAgULcHJpY2VJbXBhY3QFE21heFByaWNlSW1wYWN0VmFsdWUFFF9jaGVja01heFByaWNlSW1wYWN0BwkAAgEJAKwCAgkArAICCQCsAgIJAKwCAgkArAICCQCsAgIJAKwCAgkArAICCQCsAgIJAKwCAgkArAICCQCsAgIJAKwCAgINUHJpY2UgaW1wYWN0IAkApAMBBQtwcmljZUltcGFjdAIUID4gbWF4IHByaWNlIGltcGFjdCAJAKQDAQUTbWF4UHJpY2VJbXBhY3RWYWx1ZQIVIGJlZm9yZSBxdW90ZSBhc3NldDogCQCkAwEFEl9xdW90ZUFzc2V0UmVzZXJ2ZQIUIGJlZm9yZSBiYXNlIGFzc2V0OiAJAKQDAQURX2Jhc2VBc3NldFJlc2VydmUCICBiYXNlIGFzc2V0IGFtb3VudCB0byBleGNoYW5nZTogCQCkAwEFEF9iYXNlQXNzZXRBbW91bnQCDyBwcmljZSBiZWZvcmU6IAkApAMBBQtwcmljZUJlZm9yZQIPIG1hcmtldCBwcmljZTogCQCkAwEFC21hcmtldFByaWNlCQCZCgcFDnF1b3RlQXNzZXRTb2xkBRdxdW90ZUFzc2V0UmVzZXJ2ZUFmdGVyMQUWYmFzZUFzc2V0UmVzZXJ2ZUFmdGVyMQUXdG90YWxQb3NpdGlvblNpemVBZnRlcjEJAGUCCQEVdG90YWxMb25nUG9zaXRpb25TaXplAAMFBl9pc0FkZAkBA2FicwEFEF9iYXNlQXNzZXRBbW91bnQAAAkAZQIJARZ0b3RhbFNob3J0UG9zaXRpb25TaXplAAMJAQEhAQUGX2lzQWRkCQEDYWJzAQUQX2Jhc2VBc3NldEFtb3VudAAABQtwcmljZUltcGFjdAEKc3dhcE91dHB1dAMGX2lzQWRkEF9iYXNlQXNzZXRBbW91bnQUX2NoZWNrTWF4UHJpY2VJbXBhY3QJARZzd2FwT3V0cHV0V2l0aFJlc2VydmVzBwUGX2lzQWRkBRBfYmFzZUFzc2V0QW1vdW50BRRfY2hlY2tNYXhQcmljZUltcGFjdAkBBnF0QXN0UgAJAQZxdEFzdFcACQEGYnNBc3RSAAkBBmJzQXN0VwABE2dldE9yYWNsZVByaWNlVmFsdWUDBm9yYWNsZQhwcmljZUtleQhibG9ja0tleQQJbGFzdFZhbHVlCQETdmFsdWVPckVycm9yTWVzc2FnZQIJAJoIAgUGb3JhY2xlBQhwcmljZUtleQkArAICCQCsAgIJAKwCAgIiQ2FuIG5vdCBnZXQgb3JhY2xlIHByaWNlLiBPcmFjbGU6IAkApQgBBQZvcmFjbGUCBiBrZXk6IAUIcHJpY2VLZXkDCQECIT0CBQhibG9ja0tleQIABAxjdXJyZW50QmxvY2sFBmhlaWdodAQPbGFzdE9yYWNsZUJsb2NrCQETdmFsdWVPckVycm9yTWVzc2FnZQIJAJoIAgUGb3JhY2xlBQhibG9ja0tleQkArAICCQCsAgIJAKwCAgIiQ2FuIG5vdCBnZXQgb3JhY2xlIGJsb2NrLiBPcmFjbGU6IAkApQgBBQZvcmFjbGUCBiBrZXk6IAUIYmxvY2tLZXkDCQBmAgkAZQIFDGN1cnJlbnRCbG9jawUPbGFzdE9yYWNsZUJsb2NrCQEObWF4T3JhY2xlRGVsYXkACQACAQkArAICCQCsAgIJAKwCAgImT3JhY2xlIHN0YWxlIGRhdGEuIExhc3Qgb3JhY2xlIGJsb2NrOiAJAKQDAQUPbGFzdE9yYWNsZUJsb2NrAhAgY3VycmVudCBibG9jazogCQCkAwEFDGN1cnJlbnRCbG9jawUJbGFzdFZhbHVlBQlsYXN0VmFsdWUBDmdldE9yYWNsZVByaWNlAAQKYmFzZU9yYWNsZQkBE3ZhbHVlT3JFcnJvck1lc3NhZ2UCCQENZ2V0T3JhY2xlRGF0YQEFDGtfYmFzZU9yYWNsZQIZTm8gYmFzZSBhc3NldCBvcmFjbGUgZGF0YQQPYmFzZU9yYWNsZVByaWNlCQETZ2V0T3JhY2xlUHJpY2VWYWx1ZQMIBQpiYXNlT3JhY2xlAl8xCAUKYmFzZU9yYWNsZQJfMggFCmJhc2VPcmFjbGUCXzMEC3F1b3RlT3JhY2xlCQENZ2V0T3JhY2xlRGF0YQEFDWtfcXVvdGVPcmFjbGUEEHF1b3RlT3JhY2xlUHJpY2UDCQEJaXNEZWZpbmVkAQULcXVvdGVPcmFjbGUEDHF1b3RlT3JhY2xlVgkBBXZhbHVlAQULcXVvdGVPcmFjbGUJARNnZXRPcmFjbGVQcmljZVZhbHVlAwgFDHF1b3RlT3JhY2xlVgJfMQgFDHF1b3RlT3JhY2xlVgJfMggFDHF1b3RlT3JhY2xlVgJfMwUMREVDSU1BTF9VTklUCQEEZGl2ZAIFD2Jhc2VPcmFjbGVQcmljZQUQcXVvdGVPcmFjbGVQcmljZQEOaXNNYXJrZXRDbG9zZWQABApiYXNlT3JhY2xlCQETdmFsdWVPckVycm9yTWVzc2FnZQIJAQ1nZXRPcmFjbGVEYXRhAQUMa19iYXNlT3JhY2xlAhlObyBiYXNlIGFzc2V0IG9yYWNsZSBkYXRhBAZvcmFjbGUIBQpiYXNlT3JhY2xlAl8xBAdvcGVuS2V5CAUKYmFzZU9yYWNsZQJfNAMJAQIhPQIFB29wZW5LZXkCAAQGaXNPcGVuCQETdmFsdWVPckVycm9yTWVzc2FnZQIJAJsIAgUGb3JhY2xlBQdvcGVuS2V5CQCsAgIJAKwCAgkArAICAitDYW4gbm90IGdldCBvcmFjbGUgaXMgb3Blbi9jbG9zZWQuIE9yYWNsZTogCQClCAEFBm9yYWNsZQIGIGtleTogBQdvcGVuS2V5CQEBIQEFBmlzT3BlbgcBDGFic1ByaWNlRGlmZgUMX29yYWNsZVByaWNlEl9xdW90ZUFzc2V0UmVzZXJ2ZRFfYmFzZUFzc2V0UmVzZXJ2ZQdfcXRBc3RXB19ic0FzdFcECnByaWNlQWZ0ZXIJAQRkaXZkAgkBBG11bGQCBRJfcXVvdGVBc3NldFJlc2VydmUFB19xdEFzdFcJAQRtdWxkAgURX2Jhc2VBc3NldFJlc2VydmUFB19ic0FzdFcEDGF2ZXJhZ2VQcmljZQkBBGRpdmQCCQBkAgUMX29yYWNsZVByaWNlBQpwcmljZUFmdGVyCQBoAgACBQxERUNJTUFMX1VOSVQEDGFic1ByaWNlRGlmZgkBBGRpdmQCCQEDYWJzAQkAZQIFDF9vcmFjbGVQcmljZQUKcHJpY2VBZnRlcgUMYXZlcmFnZVByaWNlBQxhYnNQcmljZURpZmYBGXJlcXVpcmVOb3RPdmVyU3ByZWFkTGltaXQCEl9xdW90ZUFzc2V0UmVzZXJ2ZRFfYmFzZUFzc2V0UmVzZXJ2ZQQLb3JhY2xlUHJpY2UJAQ5nZXRPcmFjbGVQcmljZQAEB19xdEFzdFcJAQZxdEFzdFcABAdfYnNBc3RXCQEGYnNBc3RXAAQSYWJzUHJpY2VEaWZmQmVmb3JlCQEMYWJzUHJpY2VEaWZmBQULb3JhY2xlUHJpY2UJAQZxdEFzdFIACQEGYnNBc3RSAAUHX3F0QXN0VwUHX2JzQXN0VwQRYWJzUHJpY2VEaWZmQWZ0ZXIJAQxhYnNQcmljZURpZmYFBQtvcmFjbGVQcmljZQUSX3F1b3RlQXNzZXRSZXNlcnZlBRFfYmFzZUFzc2V0UmVzZXJ2ZQUHX3F0QXN0VwUHX2JzQXN0VwMDCQBmAgURYWJzUHJpY2VEaWZmQWZ0ZXIJAQ5tYXhQcmljZVNwcmVhZAAJAGYCBRFhYnNQcmljZURpZmZBZnRlcgUSYWJzUHJpY2VEaWZmQmVmb3JlBwkAAgEJAKwCAgkArAICCQCsAgICDVByaWNlIHNwcmVhZCAJAKQDAQURYWJzUHJpY2VEaWZmQWZ0ZXICFCA+IG1heCBwcmljZSBzcHJlYWQgCQCkAwEJAQ5tYXhQcmljZVNwcmVhZAAGAR1yZXF1aXJlTm90T3Zlck1heE9wZW5Ob3Rpb25hbAIRX2xvbmdPcGVuTm90aW9uYWwSX3Nob3J0T3Blbk5vdGlvbmFsBBBfbWF4T3Blbk5vdGlvbmFsCQEPbWF4T3Blbk5vdGlvbmFsAAMJAGYCBRFfbG9uZ09wZW5Ob3Rpb25hbAUQX21heE9wZW5Ob3Rpb25hbAkAAgEJAKwCAgkArAICCQCsAgICE0xvbmcgb3BlbiBub3Rpb25hbCAJAKQDAQURX2xvbmdPcGVuTm90aW9uYWwCFSA+IG1heCBvcGVuIG5vdGlvbmFsIAkApAMBBRBfbWF4T3Blbk5vdGlvbmFsAwkAZgIFEl9zaG9ydE9wZW5Ob3Rpb25hbAUQX21heE9wZW5Ob3Rpb25hbAkAAgEJAKwCAgkArAICCQCsAgICFFNob3J0IG9wZW4gbm90aW9uYWwgCQCkAwEFEl9zaG9ydE9wZW5Ob3Rpb25hbAIVID4gbWF4IG9wZW4gbm90aW9uYWwgCQCkAwEFEF9tYXhPcGVuTm90aW9uYWwGASFyZXF1aXJlU2VuZGVyQ2FuV29ya1dpdGhQb3NpdGlvbnMBB19jYWxsZXIDCQAAAgkBDHBvc2l0aW9uTW9kZQAFDlBPU0lUSU9OX09SREVSCQAAAgUHX2NhbGxlcgkBDW9yZGVyc0FkZHJlc3MABgEMZ2V0U3BvdFByaWNlAAQSX3F1b3RlQXNzZXRSZXNlcnZlCQEGcXRBc3RSAAQRX2Jhc2VBc3NldFJlc2VydmUJAQZic0FzdFIABAdfcXRBc3RXCQEGcXRBc3RXAAQHX2JzQXN0VwkBBmJzQXN0VwAJAQRkaXZkAgkBBG11bGQCBRJfcXVvdGVBc3NldFJlc2VydmUFB19xdEFzdFcJAQRtdWxkAgURX2Jhc2VBc3NldFJlc2VydmUFB19ic0FzdFcBFmlzT3ZlckZsdWN0dWF0aW9uTGltaXQABAtvcmFjbGVQcmljZQkBDmdldE9yYWNsZVByaWNlAAQMY3VycmVudFByaWNlCQEMZ2V0U3BvdFByaWNlAAkAZgIJAQRkaXZkAgkBA2FicwEJAGUCBQtvcmFjbGVQcmljZQUMY3VycmVudFByaWNlBQtvcmFjbGVQcmljZQkBC3NwcmVhZExpbWl0AAEfZ2V0UG9zaXRpb25BZGp1c3RlZE9wZW5Ob3Rpb25hbAYNX3Bvc2l0aW9uU2l6ZQdfb3B0aW9uEl9xdW90ZUFzc2V0UmVzZXJ2ZRFfcXVvdGVBc3NldFdlaWdodBFfYmFzZUFzc2V0UmVzZXJ2ZRBfYmFzZUFzc2V0V2VpZ2h0BA9wb3NpdGlvblNpemVBYnMJAQNhYnMBBQ1fcG9zaXRpb25TaXplBAdpc1Nob3J0CQBmAgAABQ1fcG9zaXRpb25TaXplBBBwb3NpdGlvbk5vdGlvbmFsAwkAAAIFB19vcHRpb24FD1BOTF9PUFRJT05fU1BPVAQTb3V0UG9zaXRpb25Ob3Rpb25hbAgJARZzd2FwT3V0cHV0V2l0aFJlc2VydmVzBwkBASEBBQdpc1Nob3J0BQ9wb3NpdGlvblNpemVBYnMHBRJfcXVvdGVBc3NldFJlc2VydmUFEV9xdW90ZUFzc2V0V2VpZ2h0BRFfYmFzZUFzc2V0UmVzZXJ2ZQUQX2Jhc2VBc3NldFdlaWdodAJfMQUTb3V0UG9zaXRpb25Ob3Rpb25hbAkBBG11bGQCBQ9wb3NpdGlvblNpemVBYnMJAQ5nZXRPcmFjbGVQcmljZQAFEHBvc2l0aW9uTm90aW9uYWwBK2dldFBvc2l0aW9uTm90aW9uYWxBbmRVbnJlYWxpemVkUG5sQnlWYWx1ZXMHDV9wb3NpdGlvblNpemUVX3Bvc2l0aW9uT3Blbk5vdGlvbmFsEl9xdW90ZUFzc2V0UmVzZXJ2ZRFfcXVvdGVBc3NldFdlaWdodBFfYmFzZUFzc2V0UmVzZXJ2ZRBfYmFzZUFzc2V0V2VpZ2h0B19vcHRpb24DCQAAAgUNX3Bvc2l0aW9uU2l6ZQAACQACAQIVSW52YWxpZCBwb3NpdGlvbiBzaXplBAdpc1Nob3J0CQBmAgAABQ1fcG9zaXRpb25TaXplBBBwb3NpdGlvbk5vdGlvbmFsCQEfZ2V0UG9zaXRpb25BZGp1c3RlZE9wZW5Ob3Rpb25hbAYFDV9wb3NpdGlvblNpemUFB19vcHRpb24FEl9xdW90ZUFzc2V0UmVzZXJ2ZQURX3F1b3RlQXNzZXRXZWlnaHQFEV9iYXNlQXNzZXRSZXNlcnZlBRBfYmFzZUFzc2V0V2VpZ2h0BA11bnJlYWxpemVkUG5sAwUHaXNTaG9ydAkAZQIFFV9wb3NpdGlvbk9wZW5Ob3Rpb25hbAUQcG9zaXRpb25Ob3Rpb25hbAkAZQIFEHBvc2l0aW9uTm90aW9uYWwFFV9wb3NpdGlvbk9wZW5Ob3Rpb25hbAkAlAoCBRBwb3NpdGlvbk5vdGlvbmFsBQ11bnJlYWxpemVkUG5sASNnZXRQb3NpdGlvbk5vdGlvbmFsQW5kVW5yZWFsaXplZFBubAMHX3RyYWRlcgpfZGlyZWN0aW9uB19vcHRpb24EDSR0MDI5MTE0MjkyNTQJAQtnZXRQb3NpdGlvbgIFB190cmFkZXIFCl9kaXJlY3Rpb24EDHBvc2l0aW9uU2l6ZQgFDSR0MDI5MTE0MjkyNTQCXzEEDnBvc2l0aW9uTWFyZ2luCAUNJHQwMjkxMTQyOTI1NAJfMgQUcG9zaXRpb25PcGVuTm90aW9uYWwIBQ0kdDAyOTExNDI5MjU0Al8zBBFwb3NpdGlvbkxzdFVwZENQRggFDSR0MDI5MTE0MjkyNTQCXzQJAStnZXRQb3NpdGlvbk5vdGlvbmFsQW5kVW5yZWFsaXplZFBubEJ5VmFsdWVzBwUMcG9zaXRpb25TaXplBRRwb3NpdGlvbk9wZW5Ob3Rpb25hbAkBBnF0QXN0UgAJAQZxdEFzdFcACQEGYnNBc3RSAAkBBmJzQXN0VwAFB19vcHRpb24BD2NhbGNNYXJnaW5SYXRpbwMNX3JlbWFpbk1hcmdpbghfYmFkRGVidBFfcG9zaXRpb25Ob3Rpb25hbAkBBGRpdmQCCQBlAgUNX3JlbWFpbk1hcmdpbgUIX2JhZERlYnQFEV9wb3NpdGlvbk5vdGlvbmFsARZnZXRNYXJnaW5SYXRpb0J5T3B0aW9uAwdfdHJhZGVyCl9kaXJlY3Rpb24HX29wdGlvbgQNJHQwMjk3ODYyOTkzOQkBC2dldFBvc2l0aW9uAgUHX3RyYWRlcgUKX2RpcmVjdGlvbgQMcG9zaXRpb25TaXplCAUNJHQwMjk3ODYyOTkzOQJfMQQOcG9zaXRpb25NYXJnaW4IBQ0kdDAyOTc4NjI5OTM5Al8yBANwb24IBQ0kdDAyOTc4NjI5OTM5Al8zBBZwb3NpdGlvbkxhc3RVcGRhdGVkQ1BGCAUNJHQwMjk3ODYyOTkzOQJfNAQRcG9zaXRpb25UaW1lc3RhbXAIBQ0kdDAyOTc4NjI5OTM5Al81BA0kdDAyOTk0NTMwMDUwCQEjZ2V0UG9zaXRpb25Ob3Rpb25hbEFuZFVucmVhbGl6ZWRQbmwDBQdfdHJhZGVyBQpfZGlyZWN0aW9uBQdfb3B0aW9uBBBwb3NpdGlvbk5vdGlvbmFsCAUNJHQwMjk5NDUzMDA1MAJfMQQNdW5yZWFsaXplZFBubAgFDSR0MDI5OTQ1MzAwNTACXzIEDSR0MDMwMDU1MzAyNjcJATBjYWxjUmVtYWluTWFyZ2luV2l0aEZ1bmRpbmdQYXltZW50QW5kUm9sbG92ZXJGZWUFBQxwb3NpdGlvblNpemUFDnBvc2l0aW9uTWFyZ2luBRZwb3NpdGlvbkxhc3RVcGRhdGVkQ1BGBRFwb3NpdGlvblRpbWVzdGFtcAUNdW5yZWFsaXplZFBubAQMcmVtYWluTWFyZ2luCAUNJHQwMzAwNTUzMDI2NwJfMQQHYmFkRGVidAgFDSR0MDMwMDU1MzAyNjcCXzIJAQ9jYWxjTWFyZ2luUmF0aW8DBQxyZW1haW5NYXJnaW4FB2JhZERlYnQFEHBvc2l0aW9uTm90aW9uYWwBDmdldE1hcmdpblJhdGlvAgdfdHJhZGVyCl9kaXJlY3Rpb24JARZnZXRNYXJnaW5SYXRpb0J5T3B0aW9uAwUHX3RyYWRlcgUKX2RpcmVjdGlvbgUPUE5MX09QVElPTl9TUE9UARtnZXRQYXJ0aWFsTGlxdWlkYXRpb25BbW91bnQCB190cmFkZXINX3Bvc2l0aW9uU2l6ZQQMbWF4aW11bVJhdGlvCQEEdm1heAIJARdwYXJ0aWFsTGlxdWlkYXRpb25SYXRpbwAJAGUCBQxERUNJTUFMX1VOSVQJAQRkaXZkAgkBDmdldE1hcmdpblJhdGlvAgUHX3RyYWRlcgkBDGdldERpcmVjdGlvbgEFDV9wb3NpdGlvblNpemUJARZtYWludGVuYW5jZU1hcmdpblJhdGlvAAQYbWF4RXhjaGFuZ2VkUG9zaXRpb25TaXplCQEEbXVsZAIJAQNhYnMBBQ1fcG9zaXRpb25TaXplBQxtYXhpbXVtUmF0aW8ECnN3YXBSZXN1bHQJAQpzd2FwT3V0cHV0AwkAZgIFDV9wb3NpdGlvblNpemUAAAUYbWF4RXhjaGFuZ2VkUG9zaXRpb25TaXplBwQcbWF4RXhjaGFuZ2VkUXVvdGVBc3NldEFtb3VudAgFCnN3YXBSZXN1bHQCXzEEC3ByaWNlSW1wYWN0CAUKc3dhcFJlc3VsdAJfNwMJAGYCCQEObWF4UHJpY2VJbXBhY3QABQtwcmljZUltcGFjdAUYbWF4RXhjaGFuZ2VkUG9zaXRpb25TaXplCQEEbXVsZAIJAQNhYnMBBQ1fcG9zaXRpb25TaXplCQEXcGFydGlhbExpcXVpZGF0aW9uUmF0aW8AARVpbnRlcm5hbENsb3NlUG9zaXRpb24IB190cmFkZXIKX2RpcmVjdGlvbgVfc2l6ZQRfZmVlFF9taW5RdW90ZUFzc2V0QW1vdW50DF9hZGRUb01hcmdpbhRfY2hlY2tNYXhQcmljZUltcGFjdApfbGlxdWlkYXRlBA0kdDAzMTQzMDMxNTk4CQELZ2V0UG9zaXRpb24CBQdfdHJhZGVyBQpfZGlyZWN0aW9uBA9vbGRQb3NpdGlvblNpemUIBQ0kdDAzMTQzMDMxNTk4Al8xBBFvbGRQb3NpdGlvbk1hcmdpbggFDSR0MDMxNDMwMzE1OTgCXzIEF29sZFBvc2l0aW9uT3Blbk5vdGlvbmFsCAUNJHQwMzE0MzAzMTU5OAJfMwQUb2xkUG9zaXRpb25Mc3RVcGRDUEYIBQ0kdDAzMTQzMDMxNTk4Al80BBRvbGRQb3NpdGlvblRpbWVzdGFtcAgFDSR0MDMxNDMwMzE1OTgCXzUEDmlzTG9uZ1Bvc2l0aW9uCQBmAgUPb2xkUG9zaXRpb25TaXplAAAEEmFic09sZFBvc2l0aW9uU2l6ZQkBA2FicwEFD29sZFBvc2l0aW9uU2l6ZQMDCQBnAgUSYWJzT2xkUG9zaXRpb25TaXplBQVfc2l6ZQkAZgIFBV9zaXplAAAHBA5pc1BhcnRpYWxDbG9zZQkAZgIFEmFic09sZFBvc2l0aW9uU2l6ZQUFX3NpemUEDSR0MDMxODkwMzIzNDEJAQpzd2FwT3V0cHV0AwkAZgIFD29sZFBvc2l0aW9uU2l6ZQAABQVfc2l6ZQUUX2NoZWNrTWF4UHJpY2VJbXBhY3QEGWV4Y2hhbmdlZFF1b3RlQXNzZXRBbW91bnQIBQ0kdDAzMTg5MDMyMzQxAl8xBBZxdW90ZUFzc2V0UmVzZXJ2ZUFmdGVyCAUNJHQwMzE4OTAzMjM0MQJfMgQVYmFzZUFzc2V0UmVzZXJ2ZUFmdGVyCAUNJHQwMzE4OTAzMjM0MQJfMwQWdG90YWxQb3NpdGlvblNpemVBZnRlcggFDSR0MDMxODkwMzIzNDECXzQEFWV4Y2hhbmdlZFBvc2l0aW9uU2l6ZQMJAGYCBQ9vbGRQb3NpdGlvblNpemUAAAkBAS0BBQVfc2l6ZQUFX3NpemUEDSR0MDMyNTU2MzI3ODAJASNnZXRQb3NpdGlvbk5vdGlvbmFsQW5kVW5yZWFsaXplZFBubAMFB190cmFkZXIFCl9kaXJlY3Rpb24FD1BOTF9PUFRJT05fU1BPVAQTb2xkUG9zaXRpb25Ob3Rpb25hbAgFDSR0MDMyNTU2MzI3ODACXzEEDXVucmVhbGl6ZWRQbmwIBQ0kdDAzMjU1NjMyNzgwAl8yBA1yZWFsaXplZFJhdGlvCQEEZGl2ZAIJAQNhYnMBBRVleGNoYW5nZWRQb3NpdGlvblNpemUFEmFic09sZFBvc2l0aW9uU2l6ZQQLcmVhbGl6ZWRQbmwJAQRtdWxkAgUNdW5yZWFsaXplZFBubAUNcmVhbGl6ZWRSYXRpbwQNJHQwMzMxMjEzMzM2NwkBMGNhbGNSZW1haW5NYXJnaW5XaXRoRnVuZGluZ1BheW1lbnRBbmRSb2xsb3ZlckZlZQUFD29sZFBvc2l0aW9uU2l6ZQURb2xkUG9zaXRpb25NYXJnaW4FFG9sZFBvc2l0aW9uTHN0VXBkQ1BGBRRvbGRQb3NpdGlvblRpbWVzdGFtcAUNdW5yZWFsaXplZFBubAQScmVtYWluTWFyZ2luQmVmb3JlCAUNJHQwMzMxMjEzMzM2NwJfMQQCeDEIBQ0kdDAzMzEyMTMzMzY3Al8yBAJ4MggFDSR0MDMzMTIxMzMzNjcCXzMEC3JvbGxvdmVyRmVlCAUNJHQwMzMxMjEzMzM2NwJfNAQPcG9zaXRpb25CYWREZWJ0CAkBMGNhbGNSZW1haW5NYXJnaW5XaXRoRnVuZGluZ1BheW1lbnRBbmRSb2xsb3ZlckZlZQUFD29sZFBvc2l0aW9uU2l6ZQURb2xkUG9zaXRpb25NYXJnaW4FFG9sZFBvc2l0aW9uTHN0VXBkQ1BGBRRvbGRQb3NpdGlvblRpbWVzdGFtcAULcmVhbGl6ZWRQbmwCXzIEEHJlYWxpemVkQ2xvc2VGZWUJAQRtdWxkAgkBBG11bGQCBRNvbGRQb3NpdGlvbk5vdGlvbmFsBQ1yZWFsaXplZFJhdGlvBQRfZmVlBBJ1bnJlYWxpemVkUG5sQWZ0ZXIJAGUCBQ11bnJlYWxpemVkUG5sBQtyZWFsaXplZFBubAQScmVtYWluT3Blbk5vdGlvbmFsAwkAZgIFD29sZFBvc2l0aW9uU2l6ZQAACQBlAgkAZQIFE29sZFBvc2l0aW9uTm90aW9uYWwFGWV4Y2hhbmdlZFF1b3RlQXNzZXRBbW91bnQFEnVucmVhbGl6ZWRQbmxBZnRlcgkAZQIJAGQCBRJ1bnJlYWxpemVkUG5sQWZ0ZXIFE29sZFBvc2l0aW9uTm90aW9uYWwFGWV4Y2hhbmdlZFF1b3RlQXNzZXRBbW91bnQED25ld1Bvc2l0aW9uU2l6ZQkAZAIFD29sZFBvc2l0aW9uU2l6ZQUVZXhjaGFuZ2VkUG9zaXRpb25TaXplBA0kdDAzNDc3MzM1MTU5AwkAAAIFD25ld1Bvc2l0aW9uU2l6ZQAACQCUCgIAAAAACQCUCgIJAQNhYnMBBRJyZW1haW5PcGVuTm90aW9uYWwJAR9sYXRlc3RDdW11bGF0aXZlUHJlbWl1bUZyYWN0aW9uAQUPbmV3UG9zaXRpb25TaXplBBduZXdQb3NpdGlvbk9wZW5Ob3Rpb25hbAgFDSR0MDM0NzczMzUxNTkCXzEEFG5ld1Bvc2l0aW9uTHN0VXBkQ1BGCAUNJHQwMzQ3NzMzNTE1OQJfMgQRb3Blbk5vdGlvbmFsRGVsdGEJAGUCBRdvbGRQb3NpdGlvbk9wZW5Ob3Rpb25hbAUXbmV3UG9zaXRpb25PcGVuTm90aW9uYWwEC21hcmdpblJhdGlvCQEWZ2V0TWFyZ2luUmF0aW9CeU9wdGlvbgMFB190cmFkZXIFCl9kaXJlY3Rpb24FD1BOTF9PUFRJT05fU1BPVAQebmV3UG9zaXRpb25NYXJnaW5XaXRoU2FtZVJhdGlvAwkAZgIFD29sZFBvc2l0aW9uU2l6ZQAACQBlAgkBBG11bGQCCQBkAgUXbmV3UG9zaXRpb25PcGVuTm90aW9uYWwFEnVucmVhbGl6ZWRQbmxBZnRlcgULbWFyZ2luUmF0aW8FEnVucmVhbGl6ZWRQbmxBZnRlcgkAZQIJAQRtdWxkAgkAZQIFF25ld1Bvc2l0aW9uT3Blbk5vdGlvbmFsBRJ1bnJlYWxpemVkUG5sQWZ0ZXIFC21hcmdpblJhdGlvBRJ1bnJlYWxpemVkUG5sQWZ0ZXIEEW1hcmdpblRvVHJhZGVyUmF3CQBlAgkAZQIFEnJlbWFpbk1hcmdpbkJlZm9yZQkAZAIFHm5ld1Bvc2l0aW9uTWFyZ2luV2l0aFNhbWVSYXRpbwUSdW5yZWFsaXplZFBubEFmdGVyBRByZWFsaXplZENsb3NlRmVlBA5tYXJnaW5Ub1RyYWRlcgMJAGYCAAAFEW1hcmdpblRvVHJhZGVyUmF3AwUKX2xpcXVpZGF0ZQAACQACAQI3SW52YWxpZCBpbnRlcm5hbENsb3NlUG9zaXRpb24gcGFyYW1zOiB1bmFibGUgdG8gcGF5IGZlZQURbWFyZ2luVG9UcmFkZXJSYXcEEW5ld1Bvc2l0aW9uTWFyZ2luAwUMX2FkZFRvTWFyZ2luCQBkAgUebmV3UG9zaXRpb25NYXJnaW5XaXRoU2FtZVJhdGlvBQ5tYXJnaW5Ub1RyYWRlcgUebmV3UG9zaXRpb25NYXJnaW5XaXRoU2FtZVJhdGlvAwMJAQIhPQIFFF9taW5RdW90ZUFzc2V0QW1vdW50AAAJAGYCBRRfbWluUXVvdGVBc3NldEFtb3VudAUZZXhjaGFuZ2VkUXVvdGVBc3NldEFtb3VudAcJAAIBCQCsAgIJAKwCAgkArAICAg1MaW1pdCBlcnJvcjogCQCkAwEFGWV4Y2hhbmdlZFF1b3RlQXNzZXRBbW91bnQCAyA8IAkApAMBBRRfbWluUXVvdGVBc3NldEFtb3VudAkAowoRBQ9uZXdQb3NpdGlvblNpemUFEW5ld1Bvc2l0aW9uTWFyZ2luBRduZXdQb3NpdGlvbk9wZW5Ob3Rpb25hbAUUbmV3UG9zaXRpb25Mc3RVcGRDUEYFD3Bvc2l0aW9uQmFkRGVidAULcmVhbGl6ZWRQbmwDAwUMX2FkZFRvTWFyZ2luBQ5pc1BhcnRpYWxDbG9zZQcAAAUObWFyZ2luVG9UcmFkZXIFFnF1b3RlQXNzZXRSZXNlcnZlQWZ0ZXIFFWJhc2VBc3NldFJlc2VydmVBZnRlcgUWdG90YWxQb3NpdGlvblNpemVBZnRlcgkAZQIJARRvcGVuSW50ZXJlc3ROb3Rpb25hbAAFEW9wZW5Ob3Rpb25hbERlbHRhCQBlAgkBFXRvdGFsTG9uZ1Bvc2l0aW9uU2l6ZQADBQ5pc0xvbmdQb3NpdGlvbgkBA2FicwEFFWV4Y2hhbmdlZFBvc2l0aW9uU2l6ZQAACQBlAgkBFnRvdGFsU2hvcnRQb3NpdGlvblNpemUAAwkBASEBBQ5pc0xvbmdQb3NpdGlvbgkBA2FicwEFFWV4Y2hhbmdlZFBvc2l0aW9uU2l6ZQAACQBlAgkBEG9wZW5JbnRlcmVzdExvbmcAAwUOaXNMb25nUG9zaXRpb24FEW9wZW5Ob3Rpb25hbERlbHRhAAAJAGUCCQERb3BlbkludGVyZXN0U2hvcnQAAwkBASEBBQ5pc0xvbmdQb3NpdGlvbgURb3Blbk5vdGlvbmFsRGVsdGEAAAkAZAIFEHJlYWxpemVkQ2xvc2VGZWUFC3JvbGxvdmVyRmVlBRlleGNoYW5nZWRRdW90ZUFzc2V0QW1vdW50CQACAQkArAICCQCsAgIJAKwCAgI9SW52YWxpZCBpbnRlcm5hbENsb3NlUG9zaXRpb24gcGFyYW1zOiBpbnZhbGlkIHBvc2l0aW9uIHNpemU6IAkApAMBBQVfc2l6ZQIGIG1heDogCQCkAwEFEmFic09sZFBvc2l0aW9uU2l6ZQETZ2V0VGVybWluYWxBbW1TdGF0ZQAEDV9wb3NpdGlvblNpemUJARF0b3RhbFBvc2l0aW9uU2l6ZQADCQAAAgUNX3Bvc2l0aW9uU2l6ZQAACQCUCgIJAQZxdEFzdFIACQEGYnNBc3RSAAQJZGlyZWN0aW9uCQBmAgUNX3Bvc2l0aW9uU2l6ZQAABA0kdDAzODQwNjM4NTg1CQEKc3dhcE91dHB1dAMFCWRpcmVjdGlvbgkBA2FicwEFDV9wb3NpdGlvblNpemUHBBVjdXJyZW50TmV0TWFya2V0VmFsdWUIBQ0kdDAzODQwNjM4NTg1Al8xBBl0ZXJtaW5hbFF1b3RlQXNzZXRSZXNlcnZlCAUNJHQwMzg0MDYzODU4NQJfMgQYdGVybWluYWxCYXNlQXNzZXRSZXNlcnZlCAUNJHQwMzg0MDYzODU4NQJfMwkAlAoCBRl0ZXJtaW5hbFF1b3RlQXNzZXRSZXNlcnZlBRh0ZXJtaW5hbEJhc2VBc3NldFJlc2VydmUBE2dldFF1b3RlQXNzZXRXZWlnaHQEEGJhc2VBc3NldFJlc2VydmURdG90YWxQb3NpdGlvblNpemURcXVvdGVBc3NldFJlc2VydmULdGFyZ2V0UHJpY2UEAWIJALYCAQUQYmFzZUFzc2V0UmVzZXJ2ZQQCc3oJALYCAQURdG90YWxQb3NpdGlvblNpemUEAXEJALYCAQURcXVvdGVBc3NldFJlc2VydmUEAXAJALYCAQULdGFyZ2V0UHJpY2UEAWsJAQVibXVsZAIFAXEFAWIEBG5ld0IJALcCAgUBYgUCc3oEBG5ld1EJAQViZGl2ZAIFAWsFBG5ld0IEAXoJAQViZGl2ZAIFBG5ld1EFBG5ld0IEBnJlc3VsdAkBBWJkaXZkAgUBcAUBegkAoAMBBQZyZXN1bHQBFGdldFN5bmNUZXJtaW5hbFByaWNlAw5fdGVybWluYWxQcmljZQdfcXRBc3RSB19ic0FzdFIEDV9wb3NpdGlvblNpemUJARF0b3RhbFBvc2l0aW9uU2l6ZQADCQAAAgUNX3Bvc2l0aW9uU2l6ZQAABAluZXdRdEFzdFcJAQRkaXZkAgkBBG11bGQCBQ5fdGVybWluYWxQcmljZQUHX2JzQXN0UgUHX3F0QXN0UgkAlQoDBQluZXdRdEFzdFcFDERFQ0lNQUxfVU5JVAAABAlkaXJlY3Rpb24JAGYCBQ1fcG9zaXRpb25TaXplAAAEFWN1cnJlbnROZXRNYXJrZXRWYWx1ZQgJAQpzd2FwT3V0cHV0AwUJZGlyZWN0aW9uCQEDYWJzAQUNX3Bvc2l0aW9uU2l6ZQcCXzEECW5ld1F0QXN0VwkBE2dldFF1b3RlQXNzZXRXZWlnaHQEBQdfYnNBc3RSBQ1fcG9zaXRpb25TaXplBQdfcXRBc3RSBQ5fdGVybWluYWxQcmljZQQJbmV3QnNBc3RXBQxERUNJTUFMX1VOSVQEDW1hcmdpblRvVmF1bHQICQErZ2V0UG9zaXRpb25Ob3Rpb25hbEFuZFVucmVhbGl6ZWRQbmxCeVZhbHVlcwcFDV9wb3NpdGlvblNpemUFFWN1cnJlbnROZXRNYXJrZXRWYWx1ZQUHX3F0QXN0UgUJbmV3UXRBc3RXBQdfYnNBc3RSBQluZXdCc0FzdFcFD1BOTF9PUFRJT05fU1BPVAJfMgkAlQoDBQluZXdRdEFzdFcFCW5ld0JzQXN0VwUNbWFyZ2luVG9WYXVsdAEKZ2V0RnVuZGluZwAED3VuZGVybHlpbmdQcmljZQkBDmdldE9yYWNsZVByaWNlAAQJc3BvdFByaWNlCQEMZ2V0U3BvdFByaWNlAAQHcHJlbWl1bQkAZQIFCXNwb3RQcmljZQUPdW5kZXJseWluZ1ByaWNlAwMJAQ5pc01hcmtldENsb3NlZAAGAwkAAAIJAQtmdW5kaW5nTW9kZQAFEkZVTkRJTkdfQVNZTU1FVFJJQwMJAAACCQEWdG90YWxTaG9ydFBvc2l0aW9uU2l6ZQAAAAYJAAACCQEVdG90YWxMb25nUG9zaXRpb25TaXplAAAABwkAlQoDAAAAAAAAAwkAZgIAAAUHcHJlbWl1bQQUc2hvcnRQcmVtaXVtRnJhY3Rpb24JAQRkaXZkAgkBBG11bGQCBQdwcmVtaXVtCQEUZnVuZGluZ1BlcmlvZERlY2ltYWwABQdPTkVfREFZAwkAAAIJAQtmdW5kaW5nTW9kZQAFEkZVTkRJTkdfQVNZTU1FVFJJQwQTbG9uZ1ByZW1pdW1GcmFjdGlvbgkBBGRpdmQCCQEEbXVsZAIFFHNob3J0UHJlbWl1bUZyYWN0aW9uCQEWdG90YWxTaG9ydFBvc2l0aW9uU2l6ZQAJARV0b3RhbExvbmdQb3NpdGlvblNpemUACQCVCgMFFHNob3J0UHJlbWl1bUZyYWN0aW9uBRNsb25nUHJlbWl1bUZyYWN0aW9uAAAEGXNob3J0VG90YWxQcmVtaXVtRnJhY3Rpb24JAQNhYnMBCQEEbXVsZAIFFHNob3J0UHJlbWl1bUZyYWN0aW9uCQEWdG90YWxTaG9ydFBvc2l0aW9uU2l6ZQAEGGxvbmdUb3RhbFByZW1pdW1GcmFjdGlvbgkBA2FicwEJAQRtdWxkAgUUc2hvcnRQcmVtaXVtRnJhY3Rpb24JARV0b3RhbExvbmdQb3NpdGlvblNpemUABA5wcmVtaXVtVG9WYXVsdAkAZQIFGXNob3J0VG90YWxQcmVtaXVtRnJhY3Rpb24FGGxvbmdUb3RhbFByZW1pdW1GcmFjdGlvbgkAlQoDBRRzaG9ydFByZW1pdW1GcmFjdGlvbgUUc2hvcnRQcmVtaXVtRnJhY3Rpb24FDnByZW1pdW1Ub1ZhdWx0BBNsb25nUHJlbWl1bUZyYWN0aW9uCQEEZGl2ZAIJAQRtdWxkAgUHcHJlbWl1bQkBFGZ1bmRpbmdQZXJpb2REZWNpbWFsAAUHT05FX0RBWQMJAAACCQELZnVuZGluZ01vZGUABRJGVU5ESU5HX0FTWU1NRVRSSUMEFHNob3J0UHJlbWl1bUZyYWN0aW9uCQEEZGl2ZAIJAQRtdWxkAgUTbG9uZ1ByZW1pdW1GcmFjdGlvbgkBFXRvdGFsTG9uZ1Bvc2l0aW9uU2l6ZQAJARZ0b3RhbFNob3J0UG9zaXRpb25TaXplAAkAlQoDBRRzaG9ydFByZW1pdW1GcmFjdGlvbgUTbG9uZ1ByZW1pdW1GcmFjdGlvbgAABBhsb25nVG90YWxQcmVtaXVtRnJhY3Rpb24JAQNhYnMBCQEEbXVsZAIFE2xvbmdQcmVtaXVtRnJhY3Rpb24JARV0b3RhbExvbmdQb3NpdGlvblNpemUABBlzaG9ydFRvdGFsUHJlbWl1bUZyYWN0aW9uCQEDYWJzAQkBBG11bGQCBRNsb25nUHJlbWl1bUZyYWN0aW9uCQEWdG90YWxTaG9ydFBvc2l0aW9uU2l6ZQAEDnByZW1pdW1Ub1ZhdWx0CQBlAgUYbG9uZ1RvdGFsUHJlbWl1bUZyYWN0aW9uBRlzaG9ydFRvdGFsUHJlbWl1bUZyYWN0aW9uCQCVCgMFE2xvbmdQcmVtaXVtRnJhY3Rpb24FE2xvbmdQcmVtaXVtRnJhY3Rpb24FDnByZW1pdW1Ub1ZhdWx0AQ5nZXRBZGp1c3RlZEZlZQILX2FydGlmYWN0SWQQX2Jhc2VGZWVEaXNjb3VudAQKYmFzZUZlZVJhdwkBA2ZlZQAEB2Jhc2VGZWUJAQRtdWxkAgUKYmFzZUZlZVJhdwUQX2Jhc2VGZWVEaXNjb3VudAQNJHQwNDMyNDk0Mzc0NAMJAQIhPQIFC19hcnRpZmFjdElkAgAEDGFydGlmYWN0S2luZAkBBHN0ckECCQERbmZ0TWFuYWdlckFkZHJlc3MACQEOdG9Db21wb3NpdGVLZXkCBQxrX3Rva2VuX3R5cGUFC19hcnRpZmFjdElkAwkAAAIFDGFydGlmYWN0S2luZAUYRkVFX1JFRFVDVElPTl9UT0tFTl9UWVBFBAlyZWR1Y3Rpb24JAQRpbnRBAgkBEW5mdE1hbmFnZXJBZGRyZXNzAAkBDnRvQ29tcG9zaXRlS2V5AgUNa190b2tlbl9wYXJhbQULX2FydGlmYWN0SWQEC2FkanVzdGVkRmVlCQEEbXVsZAIFB2Jhc2VGZWUFCXJlZHVjdGlvbgkAlAoCBQthZGp1c3RlZEZlZQYJAAIBAhlJbnZhbGlkIGF0dGFjaGVkIGFydGlmYWN0CQCUCgIFB2Jhc2VGZWUHBAthZGp1c3RlZEZlZQgFDSR0MDQzMjQ5NDM3NDQCXzEEDGJ1cm5BcnRpZmFjdAgFDSR0MDQzMjQ5NDM3NDQCXzIJAJQKAgULYWRqdXN0ZWRGZWUFDGJ1cm5BcnRpZmFjdAEYZ2V0Rm9yVHJhZGVyV2l0aEFydGlmYWN0AgdfdHJhZGVyC19hcnRpZmFjdElkBBBkb0dldEZlZURpc2NvdW50CQD8BwQJAQxtaW5lckFkZHJlc3MAAhJjb21wdXRlRmVlRGlzY291bnQJAMwIAgUHX3RyYWRlcgUDbmlsBQNuaWwDCQAAAgUQZG9HZXRGZWVEaXNjb3VudAUQZG9HZXRGZWVEaXNjb3VudAQLZmVlRGlzY291bnQEByRtYXRjaDAFEGRvR2V0RmVlRGlzY291bnQDCQABAgUHJG1hdGNoMAIDSW50BAF4BQckbWF0Y2gwBQF4CQACAQIhSW52YWxpZCBjb21wdXRlRmVlRGlzY291bnQgcmVzdWx0BA0kdDA0NDA5MDQ0MTY0CQEOZ2V0QWRqdXN0ZWRGZWUCBQtfYXJ0aWZhY3RJZAULZmVlRGlzY291bnQEC2FkanVzdGVkRmVlCAUNJHQwNDQwOTA0NDE2NAJfMQQMYnVybkFydGlmYWN0CAUNJHQwNDQwOTA0NDE2NAJfMgkAlAoCBQthZGp1c3RlZEZlZQUMYnVybkFydGlmYWN0CQACAQIkU3RyaWN0IHZhbHVlIGlzIG5vdCBlcXVhbCB0byBpdHNlbGYuAQ1nZXRBcnRpZmFjdElkAQFpBAphcnRpZmFjdElkAwkAZgIJAJADAQgFAWkIcGF5bWVudHMAAQkA2AQBCQETdmFsdWVPckVycm9yTWVzc2FnZQIICQCRAwIIBQFpCHBheW1lbnRzAAEHYXNzZXRJZAISSW52YWxpZCBhcnRpZmFjdElkAgAFCmFydGlmYWN0SWQBDWRpc3RyaWJ1dGVGZWUBCl9mZWVBbW91bnQEDGZlZVRvU3Rha2VycwkBBG11bGQCBQpfZmVlQW1vdW50CQETZmVlVG9TdGFrZXJzUGVyY2VudAAECmZlZVRvVmF1bHQJAGUCBQpfZmVlQW1vdW50BQxmZWVUb1N0YWtlcnMJAJQKAgUMZmVlVG9TdGFrZXJzBQpmZWVUb1ZhdWx0AQ51cGRhdGVTZXR0aW5ncxEQX2luaXRNYXJnaW5SYXRpbwRfbW1yFF9saXF1aWRhdGlvbkZlZVJhdGlvDl9mdW5kaW5nUGVyaW9kBF9mZWUMX3NwcmVhZExpbWl0D19tYXhQcmljZUltcGFjdBhfcGFydGlhbExpcXVpZGF0aW9uUmF0aW8PX21heFByaWNlU3ByZWFkEF9tYXhPcGVuTm90aW9uYWwUX2ZlZVRvU3Rha2Vyc1BlcmNlbnQPX21heE9yYWNsZURlbGF5DF9yb2xsb3ZlckZlZQxfZnVuZGluZ01vZGULX29yYWNsZU1vZGUTX21pbkluaXRNYXJnaW5SYXRpbw1fcG9zaXRpb25Nb2RlCQDMCAIJAQxJbnRlZ2VyRW50cnkCBRFrX2luaXRNYXJnaW5SYXRpbwUQX2luaXRNYXJnaW5SYXRpbwkAzAgCCQEMSW50ZWdlckVudHJ5AgUUa19taW5Jbml0TWFyZ2luUmF0aW8FE19taW5Jbml0TWFyZ2luUmF0aW8JAMwIAgkBDEludGVnZXJFbnRyeQIFGGtfbWFpbnRlbmFuY2VNYXJnaW5SYXRpbwUEX21tcgkAzAgCCQEMSW50ZWdlckVudHJ5AgUVa19saXF1aWRhdGlvbkZlZVJhdGlvBRRfbGlxdWlkYXRpb25GZWVSYXRpbwkAzAgCCQEMSW50ZWdlckVudHJ5AgUPa19mdW5kaW5nUGVyaW9kBQ5fZnVuZGluZ1BlcmlvZAkAzAgCCQEMSW50ZWdlckVudHJ5AgUFa19mZWUFBF9mZWUJAMwIAgkBDEludGVnZXJFbnRyeQIFDWtfc3ByZWFkTGltaXQFDF9zcHJlYWRMaW1pdAkAzAgCCQEMSW50ZWdlckVudHJ5AgUQa19tYXhQcmljZUltcGFjdAUPX21heFByaWNlSW1wYWN0CQDMCAIJAQxJbnRlZ2VyRW50cnkCBRlrX3BhcnRpYWxMaXF1aWRhdGlvblJhdGlvBRhfcGFydGlhbExpcXVpZGF0aW9uUmF0aW8JAMwIAgkBDEludGVnZXJFbnRyeQIFEGtfbWF4UHJpY2VTcHJlYWQFD19tYXhQcmljZVNwcmVhZAkAzAgCCQEMSW50ZWdlckVudHJ5AgURa19tYXhPcGVuTm90aW9uYWwFEF9tYXhPcGVuTm90aW9uYWwJAMwIAgkBDEludGVnZXJFbnRyeQIFFWtfZmVlVG9TdGFrZXJzUGVyY2VudAUUX2ZlZVRvU3Rha2Vyc1BlcmNlbnQJAMwIAgkBDEludGVnZXJFbnRyeQIFEGtfbWF4T3JhY2xlRGVsYXkFD19tYXhPcmFjbGVEZWxheQkAzAgCCQEMSW50ZWdlckVudHJ5AgUNa19yb2xsb3ZlckZlZQUMX3JvbGxvdmVyRmVlCQDMCAIJAQxJbnRlZ2VyRW50cnkCBQ1rX2Z1bmRpbmdNb2RlBQxfZnVuZGluZ01vZGUJAMwIAgkBDEludGVnZXJFbnRyeQIFDGtfb3JhY2xlTW9kZQULX29yYWNsZU1vZGUJAMwIAgkBDEludGVnZXJFbnRyeQIFDmtfcG9zaXRpb25Nb2RlBQ1fcG9zaXRpb25Nb2RlBQNuaWwBDXVwZGF0ZUZ1bmRpbmcFEV9uZXh0RnVuZGluZ0Jsb2NrJF9sYXRlc3RMb25nQ3VtdWxhdGl2ZVByZW1pdW1GcmFjdGlvbiVfbGF0ZXN0U2hvcnRDdW11bGF0aXZlUHJlbWl1bUZyYWN0aW9uEF9sb25nRnVuZGluZ1JhdGURX3Nob3J0RnVuZGluZ1JhdGUJAMwIAgkBDEludGVnZXJFbnRyeQIFEmtfbmV4dEZ1bmRpbmdCbG9jawURX25leHRGdW5kaW5nQmxvY2sJAMwIAgkBDEludGVnZXJFbnRyeQIFJWtfbGF0ZXN0TG9uZ0N1bXVsYXRpdmVQcmVtaXVtRnJhY3Rpb24FJF9sYXRlc3RMb25nQ3VtdWxhdGl2ZVByZW1pdW1GcmFjdGlvbgkAzAgCCQEMSW50ZWdlckVudHJ5AgUma19sYXRlc3RTaG9ydEN1bXVsYXRpdmVQcmVtaXVtRnJhY3Rpb24FJV9sYXRlc3RTaG9ydEN1bXVsYXRpdmVQcmVtaXVtRnJhY3Rpb24JAMwIAgkBDEludGVnZXJFbnRyeQIFEWtfbG9uZ0Z1bmRpbmdSYXRlBRBfbG9uZ0Z1bmRpbmdSYXRlCQDMCAIJAQxJbnRlZ2VyRW50cnkCBRJrX3Nob3J0RnVuZGluZ1JhdGUFEV9zaG9ydEZ1bmRpbmdSYXRlBQNuaWwBH2luY3JlbWVudFBvc2l0aW9uU2VxdWVuY2VOdW1iZXIDDl9pc05ld1Bvc2l0aW9uB190cmFkZXIKX2RpcmVjdGlvbgQLcG9zaXRpb25LZXkJAKwCAgkArAICBQdfdHJhZGVyAgFfCQCkAwEFCl9kaXJlY3Rpb24DBQ5faXNOZXdQb3NpdGlvbgQPY3VycmVudFNlcXVlbmNlCQEMbGFzdFNlcXVlbmNlAAkAzAgCCQEMSW50ZWdlckVudHJ5AgkBDnRvQ29tcG9zaXRlS2V5AgUSa19wb3NpdGlvblNlcXVlbmNlBQtwb3NpdGlvbktleQkAZAIFD2N1cnJlbnRTZXF1ZW5jZQABCQDMCAIJAQxJbnRlZ2VyRW50cnkCBQprX3NlcXVlbmNlCQBkAgUPY3VycmVudFNlcXVlbmNlAAEFA25pbAUDbmlsARF1cGRhdGVQb3NpdGlvbkZlZQQOX2lzTmV3UG9zaXRpb24HX3RyYWRlcgpfZGlyZWN0aW9uBF9mZWUEC3Bvc2l0aW9uS2V5CQCsAgIJAKwCAgUHX3RyYWRlcgIBXwkApAMBBQpfZGlyZWN0aW9uAwUOX2lzTmV3UG9zaXRpb24JAMwIAgkBDEludGVnZXJFbnRyeQIJAQ50b0NvbXBvc2l0ZUtleQIFDWtfcG9zaXRpb25GZWUFC3Bvc2l0aW9uS2V5BQRfZmVlBQNuaWwFA25pbAEOdXBkYXRlUG9zaXRpb24GB190cmFkZXIFX3NpemUHX21hcmdpbg1fb3Blbk5vdGlvbmFsIF9sYXRlc3RDdW11bGF0aXZlUHJlbWl1bUZyYWN0aW9uEF9sYXRlc3RUaW1lc3RhbXAECWRpcmVjdGlvbgkBDGdldERpcmVjdGlvbgEFBV9zaXplBAtwb3NpdGlvbktleQkArAICCQCsAgIFB190cmFkZXICAV8JAKQDAQUJZGlyZWN0aW9uCQDMCAIJAQxJbnRlZ2VyRW50cnkCCQEOdG9Db21wb3NpdGVLZXkCBQ5rX3Bvc2l0aW9uU2l6ZQULcG9zaXRpb25LZXkFBV9zaXplCQDMCAIJAQxJbnRlZ2VyRW50cnkCCQEOdG9Db21wb3NpdGVLZXkCBRBrX3Bvc2l0aW9uTWFyZ2luBQtwb3NpdGlvbktleQUHX21hcmdpbgkAzAgCCQEMSW50ZWdlckVudHJ5AgkBDnRvQ29tcG9zaXRlS2V5AgUWa19wb3NpdGlvbk9wZW5Ob3Rpb25hbAULcG9zaXRpb25LZXkFDV9vcGVuTm90aW9uYWwJAMwIAgkBDEludGVnZXJFbnRyeQIJAQ50b0NvbXBvc2l0ZUtleQIFLmtfcG9zaXRpb25MYXN0VXBkYXRlZEN1bXVsYXRpdmVQcmVtaXVtRnJhY3Rpb24FC3Bvc2l0aW9uS2V5BSBfbGF0ZXN0Q3VtdWxhdGl2ZVByZW1pdW1GcmFjdGlvbgkAzAgCCQEMSW50ZWdlckVudHJ5AgkBDnRvQ29tcG9zaXRlS2V5AgUea19wb3NpdGlvbkxhc3RVcGRhdGVkVGltZXN0YW1wBQtwb3NpdGlvbktleQUQX2xhdGVzdFRpbWVzdGFtcAUDbmlsARF1cGRhdGVBbW1SZXNlcnZlcwIHX3F0QXN0UgdfYnNBc3RSAwMJAGYCAAAFB19xdEFzdFIGCQBmAgAABQdfYnNBc3RSCQACAQIhSW52YWxpZCBhbW91bnQgdG8gdXBkYXRlIHJlc2VydmVzAwMJAQIhPQIFB19xdEFzdFIJAQdxdEFzdFIwAAYJAQIhPQIFB19ic0FzdFIJAQdic0FzdFIwAAkAzAgCCQEMSW50ZWdlckVudHJ5AgUTa19xdW90ZUFzc2V0UmVzZXJ2ZQUHX3F0QXN0UgkAzAgCCQEMSW50ZWdlckVudHJ5AgUSa19iYXNlQXNzZXRSZXNlcnZlBQdfYnNBc3RSBQNuaWwFA25pbAEQdXBkYXRlQW1tV2VpZ2h0cwIHX3F0QXN0VwdfYnNBc3RXAwMJAQIhPQIFB19xdEFzdFcJAQZxdEFzdFcABgkBAiE9AgUHX2JzQXN0VwkBBmJzQXN0VwAJAMwIAgkBDEludGVnZXJFbnRyeQIFEmtfcXVvdGVBc3NldFdlaWdodAUHX3F0QXN0VwkAzAgCCQEMSW50ZWdlckVudHJ5AgURa19iYXNlQXNzZXRXZWlnaHQFB19ic0FzdFcFA25pbAUDbmlsAQl1cGRhdGVBbW0IB19xdEFzdFIHX2JzQXN0UhdfdG90YWxQb3NpdGlvblNpemVBZnRlchVfb3BlbkludGVyZXN0Tm90aW9uYWwWX3RvdGFsTG9uZ1Bvc2l0aW9uU2l6ZRdfdG90YWxTaG9ydFBvc2l0aW9uU2l6ZRZfdG90YWxMb25nT3Blbk5vdGlvbmFsF190b3RhbFNob3J0T3Blbk5vdGlvbmFsBAdfcXRBc3RXCQEGcXRBc3RXAAQHX2JzQXN0VwkBBmJzQXN0VwADCQECIT0CCQBlAgUWX3RvdGFsTG9uZ1Bvc2l0aW9uU2l6ZQUXX3RvdGFsU2hvcnRQb3NpdGlvblNpemUFF190b3RhbFBvc2l0aW9uU2l6ZUFmdGVyCQACAQkArAICCQCsAgIJAKwCAgkArAICCQCsAgICGEludmFsaWQgQU1NIHN0YXRlIGRhdGE6IAkApAMBBRZfdG90YWxMb25nUG9zaXRpb25TaXplAgQgLSAgCQCkAwEFF190b3RhbFNob3J0UG9zaXRpb25TaXplAgQgIT0gCQCkAwEFF190b3RhbFBvc2l0aW9uU2l6ZUFmdGVyCQDOCAIJARF1cGRhdGVBbW1SZXNlcnZlcwIFB19xdEFzdFIFB19ic0FzdFIJAMwIAgkBDEludGVnZXJFbnRyeQIFE2tfdG90YWxQb3NpdGlvblNpemUFF190b3RhbFBvc2l0aW9uU2l6ZUFmdGVyCQDMCAIJAQxJbnRlZ2VyRW50cnkCBRZrX29wZW5JbnRlcmVzdE5vdGlvbmFsBRVfb3BlbkludGVyZXN0Tm90aW9uYWwJAMwIAgkBDEludGVnZXJFbnRyeQIFF2tfdG90YWxMb25nUG9zaXRpb25TaXplBRZfdG90YWxMb25nUG9zaXRpb25TaXplCQDMCAIJAQxJbnRlZ2VyRW50cnkCBRhrX3RvdGFsU2hvcnRQb3NpdGlvblNpemUFF190b3RhbFNob3J0UG9zaXRpb25TaXplCQDMCAIJAQxJbnRlZ2VyRW50cnkCBRJrX29wZW5JbnRlcmVzdExvbmcFFl90b3RhbExvbmdPcGVuTm90aW9uYWwJAMwIAgkBDEludGVnZXJFbnRyeQIFE2tfb3BlbkludGVyZXN0U2hvcnQFF190b3RhbFNob3J0T3Blbk5vdGlvbmFsBQNuaWwBDmRlbGV0ZVBvc2l0aW9uAgdfdHJhZGVyCl9kaXJlY3Rpb24EC3Bvc2l0aW9uS2V5CQCsAgIJAKwCAgUHX3RyYWRlcgIBXwkApAMBBQpfZGlyZWN0aW9uCQDMCAIJAQtEZWxldGVFbnRyeQEJAQ50b0NvbXBvc2l0ZUtleQIFDmtfcG9zaXRpb25TaXplBQtwb3NpdGlvbktleQkAzAgCCQELRGVsZXRlRW50cnkBCQEOdG9Db21wb3NpdGVLZXkCBRBrX3Bvc2l0aW9uTWFyZ2luBQtwb3NpdGlvbktleQkAzAgCCQELRGVsZXRlRW50cnkBCQEOdG9Db21wb3NpdGVLZXkCBRZrX3Bvc2l0aW9uT3Blbk5vdGlvbmFsBQtwb3NpdGlvbktleQkAzAgCCQELRGVsZXRlRW50cnkBCQEOdG9Db21wb3NpdGVLZXkCBS5rX3Bvc2l0aW9uTGFzdFVwZGF0ZWRDdW11bGF0aXZlUHJlbWl1bUZyYWN0aW9uBQtwb3NpdGlvbktleQkAzAgCCQELRGVsZXRlRW50cnkBCQEOdG9Db21wb3NpdGVLZXkCBQ1rX3Bvc2l0aW9uRmVlBQtwb3NpdGlvbktleQkAzAgCCQELRGVsZXRlRW50cnkBCQEOdG9Db21wb3NpdGVLZXkCBR5rX3Bvc2l0aW9uTGFzdFVwZGF0ZWRUaW1lc3RhbXAFC3Bvc2l0aW9uS2V5BQNuaWwBCHdpdGhkcmF3AghfYWRkcmVzcwdfYW1vdW50BAdiYWxhbmNlCQDwBwIFBHRoaXMJAQpxdW90ZUFzc2V0AAMJAGYCBQdfYW1vdW50BQdiYWxhbmNlCQACAQkArAICCQCsAgIJAKwCAgITVW5hYmxlIHRvIHdpdGhkcmF3IAkApAMBBQdfYW1vdW50AhcgZnJvbSBjb250cmFjdCBiYWxhbmNlIAkApAMBBQdiYWxhbmNlCQDMCAIJAQ5TY3JpcHRUcmFuc2ZlcgMFCF9hZGRyZXNzBQdfYW1vdW50CQEKcXVvdGVBc3NldAAFA25pbAENdXBkYXRlQmFsYW5jZQEIX2JhbGFuY2UDCQBmAgAABQhfYmFsYW5jZQkAAgECB0JhbGFuY2UDAwkAAAIJAQljYmFsYW5jZTAAAAAGCQECIT0CCQEJY2JhbGFuY2UwAAUIX2JhbGFuY2UJAMwIAgkBDEludGVnZXJFbnRyeQIFCWtfYmFsYW5jZQUIX2JhbGFuY2UFA25pbAUDbmlsAQt0cmFuc2ZlckZlZQEBaQkAzAgCCQEOU2NyaXB0VHJhbnNmZXIDCQEOc3Rha2luZ0FkZHJlc3MABQFpCQEKcXVvdGVBc3NldAAFA25pbAEOZG9CdXJuQXJ0aWZhY3QCDV9idXJuQXJ0aWZhY3QBaQMFDV9idXJuQXJ0aWZhY3QJAMwIAgkBBEJ1cm4CCQETdmFsdWVPckVycm9yTWVzc2FnZQIICQCRAwIIBQFpCHBheW1lbnRzAAEHYXNzZXRJZAIQSW52YWxpZCBhcnRpZmFjdAABBQNuaWwFA25pbBcBaQEFcGF1c2UAAwkBAiE9AggFAWkGY2FsbGVyCQEMYWRtaW5BZGRyZXNzAAkAAgECFEludmFsaWQgcGF1c2UgcGFyYW1zCQDMCAIJAQxCb29sZWFuRW50cnkCBQhrX3BhdXNlZAYFA25pbAFpAQd1bnBhdXNlAAMJAQIhPQIIBQFpBmNhbGxlcgkBDGFkbWluQWRkcmVzcwAJAAIBAhZJbnZhbGlkIHVucGF1c2UgcGFyYW1zCQDMCAIJAQxCb29sZWFuRW50cnkCBQhrX3BhdXNlZAcFA25pbAFpAQxzZXRDbG9zZU9ubHkAAwkBAiE9AggFAWkGY2FsbGVyCQEMYWRtaW5BZGRyZXNzAAkAAgECG0ludmFsaWQgc2V0Q2xvc2VPbmx5IHBhcmFtcwkAzAgCCQEMQm9vbGVhbkVudHJ5AgULa19jbG9zZU9ubHkGBQNuaWwBaQEOdW5zZXRDbG9zZU9ubHkAAwkBAiE9AggFAWkGY2FsbGVyCQEMYWRtaW5BZGRyZXNzAAkAAgECHUludmFsaWQgdW5zZXRDbG9zZU9ubHkgcGFyYW1zCQDMCAIJAQxCb29sZWFuRW50cnkCBQtrX2Nsb3NlT25seQcFA25pbAFpAQ9jaGFuZ2VMaXF1aWRpdHkBEV9xdW90ZUFzc2V0QW1vdW50AwMJAQIhPQIIBQFpBmNhbGxlcgkBDGFkbWluQWRkcmVzcwAGCQAAAgURX3F1b3RlQXNzZXRBbW91bnQAAAkAAgECHkludmFsaWQgY2hhbmdlTGlxdWlkaXR5IHBhcmFtcwQHX3F0QXN0UgkBBnF0QXN0UgAEB19ic0FzdFIJAQZic0FzdFIABAdfcXRBc3RXCQEGcXRBc3RXAAQHX2JzQXN0VwkBBmJzQXN0VwAEBXByaWNlCQEEZGl2ZAIJAQRtdWxkAgUHX3F0QXN0UgUHX3F0QXN0VwkBBG11bGQCBQdfYnNBc3RSBQdfYnNBc3RXBAtxdEFzdFJBZnRlcgkAZAIFB19xdEFzdFIFEV9xdW90ZUFzc2V0QW1vdW50BBRiYXNlQXNzZXRBbW91bnRUb0FkZAkAZQIJAQRkaXZkAgkBBG11bGQCBQtxdEFzdFJBZnRlcgUHX3F0QXN0VwUFcHJpY2UFB19ic0FzdFIEC2JzQXN0UkFmdGVyCQBkAgUHX2JzQXN0UgUUYmFzZUFzc2V0QW1vdW50VG9BZGQEDSR0MDUzMDQ5NTMyMDAJARRnZXRTeW5jVGVybWluYWxQcmljZQMJAQ5nZXRPcmFjbGVQcmljZQAFC3F0QXN0UkFmdGVyBQtic0FzdFJBZnRlcgQTbmV3UXVvdGVBc3NldFdlaWdodAgFDSR0MDUzMDQ5NTMyMDACXzEEEm5ld0Jhc2VBc3NldFdlaWdodAgFDSR0MDUzMDQ5NTMyMDACXzIEDW1hcmdpblRvVmF1bHQIBQ0kdDA1MzA0OTUzMjAwAl8zBA1kb0V4Y2hhbmdlUG5MAwkBAiE9AgUNbWFyZ2luVG9WYXVsdAAABA1kb0V4Y2hhbmdlUG5MCQD8BwQJAQx2YXVsdEFkZHJlc3MAAhVleGNoYW5nZUZyZWVBbmRMb2NrZWQJAMwIAgUNbWFyZ2luVG9WYXVsdAUDbmlsBQNuaWwDCQAAAgUNZG9FeGNoYW5nZVBuTAUNZG9FeGNoYW5nZVBuTAUDbmlsCQACAQIkU3RyaWN0IHZhbHVlIGlzIG5vdCBlcXVhbCB0byBpdHNlbGYuBQNuaWwDCQAAAgUNZG9FeGNoYW5nZVBuTAUNZG9FeGNoYW5nZVBuTAkAzggCCQERdXBkYXRlQW1tUmVzZXJ2ZXMCBQtxdEFzdFJBZnRlcgULYnNBc3RSQWZ0ZXIJARB1cGRhdGVBbW1XZWlnaHRzAgUTbmV3UXVvdGVBc3NldFdlaWdodAUSbmV3QmFzZUFzc2V0V2VpZ2h0CQACAQIkU3RyaWN0IHZhbHVlIGlzIG5vdCBlcXVhbCB0byBpdHNlbGYuAWkBDmNoYW5nZVNldHRpbmdzExBfaW5pdE1hcmdpblJhdGlvBF9tbXIUX2xpcXVpZGF0aW9uRmVlUmF0aW8OX2Z1bmRpbmdQZXJpb2QEX2ZlZQxfc3ByZWFkTGltaXQPX21heFByaWNlSW1wYWN0GF9wYXJ0aWFsTGlxdWlkYXRpb25SYXRpbw9fbWF4UHJpY2VTcHJlYWQQX21heE9wZW5Ob3Rpb25hbBRfZmVlVG9TdGFrZXJzUGVyY2VudA9fbWF4T3JhY2xlRGVsYXkMX3JvbGxvdmVyRmVlDF9mdW5kaW5nTW9kZQtfb3JhY2xlTW9kZQ9fYmFzZU9yYWNsZURhdGEQX3F1b3RlT3JhY2xlRGF0YRNfbWluSW5pdE1hcmdpblJhdGlvDV9wb3NpdGlvbk1vZGUDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwkAZwIAAAUOX2Z1bmRpbmdQZXJpb2QGCQBnAgAABRBfaW5pdE1hcmdpblJhdGlvBgkAZgIFEF9pbml0TWFyZ2luUmF0aW8FDERFQ0lNQUxfVU5JVAYJAGcCAAAFE19taW5Jbml0TWFyZ2luUmF0aW8GCQBmAgUTX21pbkluaXRNYXJnaW5SYXRpbwUMREVDSU1BTF9VTklUBgkAZgIFEF9pbml0TWFyZ2luUmF0aW8FE19taW5Jbml0TWFyZ2luUmF0aW8GCQBnAgAABQRfbW1yBgkAZwIAAAUUX2xpcXVpZGF0aW9uRmVlUmF0aW8GCQBnAgAABQRfZmVlBgkAZwIAAAUMX3NwcmVhZExpbWl0BgkAZwIAAAUPX21heFByaWNlSW1wYWN0BgkAZwIAAAUYX3BhcnRpYWxMaXF1aWRhdGlvblJhdGlvBgkAZwIAAAUPX21heFByaWNlU3ByZWFkBgkAZwIAAAUQX21heE9wZW5Ob3Rpb25hbAYJAGcCAAAFFF9mZWVUb1N0YWtlcnNQZXJjZW50BgkAZgIFFF9mZWVUb1N0YWtlcnNQZXJjZW50BQxERUNJTUFMX1VOSVQGCQBmAgAABQ9fbWF4T3JhY2xlRGVsYXkGCQBnAgAABQxfcm9sbG92ZXJGZWUGAwkBAiE9AgUMX2Z1bmRpbmdNb2RlBRFGVU5ESU5HX1NZTU1FVFJJQwkBAiE9AgUMX2Z1bmRpbmdNb2RlBRJGVU5ESU5HX0FTWU1NRVRSSUMHBgMJAQIhPQIFC19vcmFjbGVNb2RlBQxPUkFDTEVfUExBSU4JAQIhPQIFC19vcmFjbGVNb2RlBQpPUkFDTEVfSklUBwYDCQECIT0CBQ1fcG9zaXRpb25Nb2RlBQ9QT1NJVElPTl9ESVJFQ1QJAQIhPQIFDV9wb3NpdGlvbk1vZGUFDlBPU0lUSU9OX09SREVSBwYJAQEhAQkBC2luaXRpYWxpemVkAAYJAQIhPQIIBQFpBmNhbGxlcgkBDGFkbWluQWRkcmVzcwAJAAIBAh1JbnZhbGlkIGNoYW5nZVNldHRpbmdzIHBhcmFtcwkAzggCCQEOdXBkYXRlU2V0dGluZ3MRBRBfaW5pdE1hcmdpblJhdGlvBQRfbW1yBRRfbGlxdWlkYXRpb25GZWVSYXRpbwUOX2Z1bmRpbmdQZXJpb2QFBF9mZWUFDF9zcHJlYWRMaW1pdAUPX21heFByaWNlSW1wYWN0BRhfcGFydGlhbExpcXVpZGF0aW9uUmF0aW8FD19tYXhQcmljZVNwcmVhZAUQX21heE9wZW5Ob3Rpb25hbAUUX2ZlZVRvU3Rha2Vyc1BlcmNlbnQFD19tYXhPcmFjbGVEZWxheQUMX3JvbGxvdmVyRmVlBQxfZnVuZGluZ01vZGUFC19vcmFjbGVNb2RlBRNfbWluSW5pdE1hcmdpblJhdGlvBQ1fcG9zaXRpb25Nb2RlCQDMCAIJAQtTdHJpbmdFbnRyeQIFDGtfYmFzZU9yYWNsZQUPX2Jhc2VPcmFjbGVEYXRhCQDMCAIJAQtTdHJpbmdFbnRyeQIFDWtfcXVvdGVPcmFjbGUFEF9xdW90ZU9yYWNsZURhdGEFA25pbAFpAQppbml0aWFsaXplFgdfcXRBc3RSB19ic0FzdFIOX2Z1bmRpbmdQZXJpb2QQX2luaXRNYXJnaW5SYXRpbwRfbW1yFF9saXF1aWRhdGlvbkZlZVJhdGlvBF9mZWUPX2Jhc2VPcmFjbGVEYXRhEF9xdW90ZU9yYWNsZURhdGEMX2Nvb3JkaW5hdG9yDF9zcHJlYWRMaW1pdA9fbWF4UHJpY2VJbXBhY3QYX3BhcnRpYWxMaXF1aWRhdGlvblJhdGlvD19tYXhQcmljZVNwcmVhZBBfbWF4T3Blbk5vdGlvbmFsFF9mZWVUb1N0YWtlcnNQZXJjZW50D19tYXhPcmFjbGVEZWxheQxfcm9sbG92ZXJGZWUMX2Z1bmRpbmdNb2RlC19vcmFjbGVNb2RlE19taW5Jbml0TWFyZ2luUmF0aW8NX3Bvc2l0aW9uTW9kZQMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMJAGcCAAAFB19xdEFzdFIGCQBnAgAABQdfYnNBc3RSBgkAZwIAAAUOX2Z1bmRpbmdQZXJpb2QGCQBnAgAABRBfaW5pdE1hcmdpblJhdGlvBgkAZgIFEF9pbml0TWFyZ2luUmF0aW8FDERFQ0lNQUxfVU5JVAYJAGcCAAAFE19taW5Jbml0TWFyZ2luUmF0aW8GCQBmAgUTX21pbkluaXRNYXJnaW5SYXRpbwUMREVDSU1BTF9VTklUBgkAZgIFEF9pbml0TWFyZ2luUmF0aW8FE19taW5Jbml0TWFyZ2luUmF0aW8GCQBnAgAABQRfbW1yBgkAZwIAAAUUX2xpcXVpZGF0aW9uRmVlUmF0aW8GCQBnAgAABQRfZmVlBgkAZwIAAAUMX3NwcmVhZExpbWl0BgkAZwIAAAUPX21heFByaWNlSW1wYWN0BgkAZwIAAAUYX3BhcnRpYWxMaXF1aWRhdGlvblJhdGlvBgkAZwIAAAUPX21heFByaWNlU3ByZWFkBgkAZwIAAAUQX21heE9wZW5Ob3Rpb25hbAYJAGcCAAAFFF9mZWVUb1N0YWtlcnNQZXJjZW50BgkAZgIFFF9mZWVUb1N0YWtlcnNQZXJjZW50BQxERUNJTUFMX1VOSVQGCQBmAgAABQ9fbWF4T3JhY2xlRGVsYXkGCQBnAgAABQxfcm9sbG92ZXJGZWUGAwkBAiE9AgUMX2Z1bmRpbmdNb2RlBRFGVU5ESU5HX1NZTU1FVFJJQwkBAiE9AgUMX2Z1bmRpbmdNb2RlBRJGVU5ESU5HX0FTWU1NRVRSSUMHBgMJAQIhPQIFC19vcmFjbGVNb2RlBQxPUkFDTEVfUExBSU4JAQIhPQIFC19vcmFjbGVNb2RlBQpPUkFDTEVfSklUBwYDCQECIT0CBQ1fcG9zaXRpb25Nb2RlBQ9QT1NJVElPTl9ESVJFQ1QJAQIhPQIFDV9wb3NpdGlvbk1vZGUFDlBPU0lUSU9OX09SREVSBwYJAQtpbml0aWFsaXplZAAGCQECIT0CCAUBaQZjYWxsZXIFBHRoaXMJAAIBAh1JbnZhbGlkIGluaXRpYWxpemUgcGFyYW1ldGVycwkAzggCCQDOCAIJAM4IAgkAzggCCQEJdXBkYXRlQW1tCAUHX3F0QXN0UgUHX2JzQXN0UgAAAAAAAAAAAAAAAAkBDnVwZGF0ZVNldHRpbmdzEQUQX2luaXRNYXJnaW5SYXRpbwUEX21tcgUUX2xpcXVpZGF0aW9uRmVlUmF0aW8FDl9mdW5kaW5nUGVyaW9kBQRfZmVlBQxfc3ByZWFkTGltaXQFD19tYXhQcmljZUltcGFjdAUYX3BhcnRpYWxMaXF1aWRhdGlvblJhdGlvBQ9fbWF4UHJpY2VTcHJlYWQFEF9tYXhPcGVuTm90aW9uYWwFFF9mZWVUb1N0YWtlcnNQZXJjZW50BQ9fbWF4T3JhY2xlRGVsYXkFDF9yb2xsb3ZlckZlZQUMX2Z1bmRpbmdNb2RlBQtfb3JhY2xlTW9kZQUTX21pbkluaXRNYXJnaW5SYXRpbwUNX3Bvc2l0aW9uTW9kZQkBDXVwZGF0ZUZ1bmRpbmcFCQBkAgkBDWxhc3RUaW1lc3RhbXAABQ5fZnVuZGluZ1BlcmlvZAAAAAAAAAAACQENdXBkYXRlQmFsYW5jZQEAAAkAzAgCCQEMQm9vbGVhbkVudHJ5AgUNa19pbml0aWFsaXplZAYJAMwIAgkBC1N0cmluZ0VudHJ5AgUMa19iYXNlT3JhY2xlBQ9fYmFzZU9yYWNsZURhdGEJAMwIAgkBC1N0cmluZ0VudHJ5AgUNa19xdW90ZU9yYWNsZQUQX3F1b3RlT3JhY2xlRGF0YQkAzAgCCQELU3RyaW5nRW50cnkCBRRrX2Nvb3JkaW5hdG9yQWRkcmVzcwkApQgBCQERQGV4dHJOYXRpdmUoMTA2MikBBQxfY29vcmRpbmF0b3IFA25pbAFpARBpbmNyZWFzZVBvc2l0aW9uBQpfZGlyZWN0aW9uCV9sZXZlcmFnZRNfbWluQmFzZUFzc2V0QW1vdW50CF9yZWZMaW5rDF9wcmljZVVwZGF0ZQQMdXBkYXRlT3JhY2xlCQD8BwQFBHRoaXMCDHVwZGF0ZU9yYWNsZQkAzAgCBQxfcHJpY2VVcGRhdGUFA25pbAUDbmlsAwkAAAIFDHVwZGF0ZU9yYWNsZQUMdXBkYXRlT3JhY2xlBARzeW5jCQD8BwQFBHRoaXMCGXN5bmNUZXJtaW5hbFByaWNlVG9PcmFjbGUFA25pbAUDbmlsAwkAAAIFBHN5bmMFBHN5bmMEEGVuc3VyZUNhbGxlZE9uY2UJAPwHBAUEdGhpcwIQZW5zdXJlQ2FsbGVkT25jZQUDbmlsBQNuaWwDCQAAAgUQZW5zdXJlQ2FsbGVkT25jZQUQZW5zdXJlQ2FsbGVkT25jZQQHX3RyYWRlcgkBD2dldEFjdHVhbENhbGxlcgEFAWkECl9yYXdBbW91bnQICQCRAwIIBQFpCHBheW1lbnRzAAAGYW1vdW50BAhfYXNzZXRJZAgJAJEDAggFAWkIcGF5bWVudHMAAAdhc3NldElkBAtfYXNzZXRJZFN0cgkA2AQBCQEFdmFsdWUBBQhfYXNzZXRJZAQMaXNRdW90ZUFzc2V0CQAAAgUIX2Fzc2V0SWQJAQpxdW90ZUFzc2V0AAMDAwMDAwMDAwMDCQECIT0CBQpfZGlyZWN0aW9uBQhESVJfTE9ORwkBAiE9AgUKX2RpcmVjdGlvbgUJRElSX1NIT1JUBwYJAGcCAAAFCl9yYXdBbW91bnQGCQEBIQEJAQtpbml0aWFsaXplZAAGCQEBIQEFDGlzUXVvdGVBc3NldAYJAQEhAQkBFnJlcXVpcmVNb3JlTWFyZ2luUmF0aW8DCQEEZGl2ZAIFDERFQ0lNQUxfVU5JVAUJX2xldmVyYWdlCQEPaW5pdE1hcmdpblJhdGlvAAYGCQEBIQEJARZyZXF1aXJlTW9yZU1hcmdpblJhdGlvAwkBBGRpdmQCBQxERUNJTUFMX1VOSVQFCV9sZXZlcmFnZQkBEm1pbkluaXRNYXJnaW5SYXRpbwAHBgkBASEBCQEhcmVxdWlyZVNlbmRlckNhbldvcmtXaXRoUG9zaXRpb25zAQgFAWkGY2FsbGVyBgkBBnBhdXNlZAAGCQEJY2xvc2VPbmx5AAYJAQ5pc01hcmtldENsb3NlZAAJAAIBAiNJbnZhbGlkIGluY3JlYXNlUG9zaXRpb24gcGFyYW1ldGVycwQNJHQwNjA1Mzk2MDY4OAkBGGdldEZvclRyYWRlcldpdGhBcnRpZmFjdAIFB190cmFkZXIJAQ1nZXRBcnRpZmFjdElkAQUBaQQLYWRqdXN0ZWRGZWUIBQ0kdDA2MDUzOTYwNjg4Al8xBAxidXJuQXJ0aWZhY3QIBQ0kdDA2MDUzOTYwNjg4Al8yBAdfYW1vdW50CQEEZGl2ZAIFCl9yYXdBbW91bnQJAGQCCQEEbXVsZAIFC2FkanVzdGVkRmVlBQlfbGV2ZXJhZ2UFDERFQ0lNQUxfVU5JVAQTZGlzdHJpYnV0ZUZlZUFtb3VudAkAZQIFCl9yYXdBbW91bnQFB19hbW91bnQEDnJlZmVycmVyRmVlQW55CQD8BwQJAQ9yZWZlcnJhbEFkZHJlc3MAAhVhY2NlcHRQYXltZW50V2l0aExpbmsJAMwIAgUHX3RyYWRlcgkAzAgCBQhfcmVmTGluawUDbmlsCQDMCAIJAQ9BdHRhY2hlZFBheW1lbnQCCQEKcXVvdGVBc3NldAAFE2Rpc3RyaWJ1dGVGZWVBbW91bnQFA25pbAMJAAACBQ5yZWZlcnJlckZlZUFueQUOcmVmZXJyZXJGZWVBbnkEC3JlZmVycmVyRmVlBAckbWF0Y2gwBQ5yZWZlcnJlckZlZUFueQMJAAECBQckbWF0Y2gwAgNJbnQEAXgFByRtYXRjaDAFAXgJAAIBAhNJbnZhbGlkIHJlZmVycmVyRmVlBAlmZWVBbW91bnQJAGUCBRNkaXN0cmlidXRlRmVlQW1vdW50BQtyZWZlcnJlckZlZQQNJHQwNjExODQ2MTM2NAkBC2dldFBvc2l0aW9uAgUHX3RyYWRlcgUKX2RpcmVjdGlvbgQPb2xkUG9zaXRpb25TaXplCAUNJHQwNjExODQ2MTM2NAJfMQQRb2xkUG9zaXRpb25NYXJnaW4IBQ0kdDA2MTE4NDYxMzY0Al8yBBdvbGRQb3NpdGlvbk9wZW5Ob3Rpb25hbAgFDSR0MDYxMTg0NjEzNjQCXzMEFG9sZFBvc2l0aW9uTHN0VXBkQ1BGCAUNJHQwNjExODQ2MTM2NAJfNAQUb2xkUG9zaXRpb25UaW1lc3RhbXAIBQ0kdDA2MTE4NDYxMzY0Al81BA1pc05ld1Bvc2l0aW9uCQAAAgUPb2xkUG9zaXRpb25TaXplAAAED2lzU2FtZURpcmVjdGlvbgMJAGYCBQ9vbGRQb3NpdGlvblNpemUAAAkAAAIFCl9kaXJlY3Rpb24FCERJUl9MT05HCQAAAgUKX2RpcmVjdGlvbgUJRElSX1NIT1JUBA5leHBhbmRFeGlzdGluZwMJAQEhAQUNaXNOZXdQb3NpdGlvbgUPaXNTYW1lRGlyZWN0aW9uBwQFaXNBZGQJAAACBQpfZGlyZWN0aW9uBQhESVJfTE9ORwQNJHQwNjE2NTM2NDc4NgMDBQ1pc05ld1Bvc2l0aW9uBgUOZXhwYW5kRXhpc3RpbmcEDG9wZW5Ob3Rpb25hbAkBBG11bGQCBQdfYW1vdW50BQlfbGV2ZXJhZ2UEDSR0MDYyMTYyNjIzMzUJAQlzd2FwSW5wdXQCBQVpc0FkZAUMb3Blbk5vdGlvbmFsBBVhbW91bnRCYXNlQXNzZXRCb3VnaHQIBQ0kdDA2MjE2MjYyMzM1Al8xBBZxdW90ZUFzc2V0UmVzZXJ2ZUFmdGVyCAUNJHQwNjIxNjI2MjMzNQJfMgQVYmFzZUFzc2V0UmVzZXJ2ZUFmdGVyCAUNJHQwNjIxNjI2MjMzNQJfMwQWdG90YWxQb3NpdGlvblNpemVBZnRlcggFDSR0MDYyMTYyNjIzMzUCXzQDAwkBAiE9AgUTX21pbkJhc2VBc3NldEFtb3VudAAACQBmAgUTX21pbkJhc2VBc3NldEFtb3VudAkBA2FicwEFFWFtb3VudEJhc2VBc3NldEJvdWdodAcJAAIBCQCsAgIJAKwCAgkArAICAg1MaW1pdCBlcnJvcjogCQCkAwEJAQNhYnMBBRVhbW91bnRCYXNlQXNzZXRCb3VnaHQCAyA8IAkApAMBBRNfbWluQmFzZUFzc2V0QW1vdW50BA9uZXdQb3NpdGlvblNpemUJAGQCBQ9vbGRQb3NpdGlvblNpemUFFWFtb3VudEJhc2VBc3NldEJvdWdodAQadG90YWxMb25nT3BlbkludGVyZXN0QWZ0ZXIJAGQCCQEQb3BlbkludGVyZXN0TG9uZwADCQBmAgUPbmV3UG9zaXRpb25TaXplAAAFDG9wZW5Ob3Rpb25hbAAABBt0b3RhbFNob3J0T3BlbkludGVyZXN0QWZ0ZXIJAGQCCQERb3BlbkludGVyZXN0U2hvcnQAAwkAZgIAAAUPbmV3UG9zaXRpb25TaXplBQxvcGVuTm90aW9uYWwAAAQNJHQwNjI4ODE2MzE1NgkBMGNhbGNSZW1haW5NYXJnaW5XaXRoRnVuZGluZ1BheW1lbnRBbmRSb2xsb3ZlckZlZQUFD29sZFBvc2l0aW9uU2l6ZQURb2xkUG9zaXRpb25NYXJnaW4FFG9sZFBvc2l0aW9uTHN0VXBkQ1BGBRRvbGRQb3NpdGlvblRpbWVzdGFtcAUHX2Ftb3VudAQMcmVtYWluTWFyZ2luCAUNJHQwNjI4ODE2MzE1NgJfMQQCeDEIBQ0kdDA2Mjg4MTYzMTU2Al8yBAJ4MggFDSR0MDYyODgxNjMxNTYCXzMEC3JvbGxvdmVyRmVlCAUNJHQwNjI4ODE2MzE1NgJfNAMJAQEhAQkBGXJlcXVpcmVOb3RPdmVyU3ByZWFkTGltaXQCBRZxdW90ZUFzc2V0UmVzZXJ2ZUFmdGVyBRViYXNlQXNzZXRSZXNlcnZlQWZ0ZXIJAAIBAhVPdmVyIG1heCBzcHJlYWQgbGltaXQDCQEBIQEJAR1yZXF1aXJlTm90T3Zlck1heE9wZW5Ob3Rpb25hbAIFGnRvdGFsTG9uZ09wZW5JbnRlcmVzdEFmdGVyBRt0b3RhbFNob3J0T3BlbkludGVyZXN0QWZ0ZXIJAAIBAhZPdmVyIG1heCBvcGVuIG5vdGlvbmFsCQCgCg4FD25ld1Bvc2l0aW9uU2l6ZQUMcmVtYWluTWFyZ2luCQBkAgUXb2xkUG9zaXRpb25PcGVuTm90aW9uYWwFDG9wZW5Ob3Rpb25hbAkBH2xhdGVzdEN1bXVsYXRpdmVQcmVtaXVtRnJhY3Rpb24BBQ9uZXdQb3NpdGlvblNpemUJAQ1sYXN0VGltZXN0YW1wAAUVYmFzZUFzc2V0UmVzZXJ2ZUFmdGVyBRZxdW90ZUFzc2V0UmVzZXJ2ZUFmdGVyBRZ0b3RhbFBvc2l0aW9uU2l6ZUFmdGVyCQBkAgkBFG9wZW5JbnRlcmVzdE5vdGlvbmFsAAUMb3Blbk5vdGlvbmFsCQBkAgkBFXRvdGFsTG9uZ1Bvc2l0aW9uU2l6ZQADCQBmAgUPbmV3UG9zaXRpb25TaXplAAAJAQNhYnMBBRVhbW91bnRCYXNlQXNzZXRCb3VnaHQAAAkAZAIJARZ0b3RhbFNob3J0UG9zaXRpb25TaXplAAMJAGYCAAAFD25ld1Bvc2l0aW9uU2l6ZQkBA2FicwEFFWFtb3VudEJhc2VBc3NldEJvdWdodAAABRp0b3RhbExvbmdPcGVuSW50ZXJlc3RBZnRlcgUbdG90YWxTaG9ydE9wZW5JbnRlcmVzdEFmdGVyBQtyb2xsb3ZlckZlZQQMb3Blbk5vdGlvbmFsCQEEbXVsZAIFB19hbW91bnQFCV9sZXZlcmFnZQQNJHQwNjQ0NzQ2NDYwMgkBI2dldFBvc2l0aW9uTm90aW9uYWxBbmRVbnJlYWxpemVkUG5sAwkApQgBCAUBaQZjYWxsZXIFCl9kaXJlY3Rpb24FD1BOTF9PUFRJT05fU1BPVAQTb2xkUG9zaXRpb25Ob3Rpb25hbAgFDSR0MDY0NDc0NjQ2MDICXzEEDXVucmVhbGl6ZWRQbmwIBQ0kdDA2NDQ3NDY0NjAyAl8yAwkAZgIFE29sZFBvc2l0aW9uTm90aW9uYWwFDG9wZW5Ob3Rpb25hbAkAAgECLlVzZSBkZWNyZWFzZVBvc2l0aW9uIHRvIGRlY3JlYXNlIHBvc2l0aW9uIHNpemUJAAIBAhRDbG9zZSBwb3NpdGlvbiBmaXJzdAQPbmV3UG9zaXRpb25TaXplCAUNJHQwNjE2NTM2NDc4NgJfMQQXbmV3UG9zaXRpb25SZW1haW5NYXJnaW4IBQ0kdDA2MTY1MzY0Nzg2Al8yBBduZXdQb3NpdGlvbk9wZW5Ob3Rpb25hbAgFDSR0MDYxNjUzNjQ3ODYCXzMEFG5ld1Bvc2l0aW9uTGF0ZXN0Q1BGCAUNJHQwNjE2NTM2NDc4NgJfNAQUbmV3UG9zaXRpb25UaW1lc3RhbXAIBQ0kdDA2MTY1MzY0Nzg2Al81BBViYXNlQXNzZXRSZXNlcnZlQWZ0ZXIIBQ0kdDA2MTY1MzY0Nzg2Al82BBZxdW90ZUFzc2V0UmVzZXJ2ZUFmdGVyCAUNJHQwNjE2NTM2NDc4NgJfNwQWdG90YWxQb3NpdGlvblNpemVBZnRlcggFDSR0MDYxNjUzNjQ3ODYCXzgEGW9wZW5JbnRlcmVzdE5vdGlvbmFsQWZ0ZXIIBQ0kdDA2MTY1MzY0Nzg2Al85BA50b3RhbExvbmdBZnRlcggFDSR0MDYxNjUzNjQ3ODYDXzEwBA90b3RhbFNob3J0QWZ0ZXIIBQ0kdDA2MTY1MzY0Nzg2A18xMQQadG90YWxMb25nT3BlbkludGVyZXN0QWZ0ZXIIBQ0kdDA2MTY1MzY0Nzg2A18xMgQbdG90YWxTaG9ydE9wZW5JbnRlcmVzdEFmdGVyCAUNJHQwNjE2NTM2NDc4NgNfMTMEC3JvbGxvdmVyRmVlCAUNJHQwNjE2NTM2NDc4NgNfMTQEDSR0MDY0NzkyNjQ4NjMJAQ1kaXN0cmlidXRlRmVlAQkAZAIFCWZlZUFtb3VudAULcm9sbG92ZXJGZWUEDGZlZVRvU3Rha2VycwgFDSR0MDY0NzkyNjQ4NjMCXzEECmZlZVRvVmF1bHQIBQ0kdDA2NDc5MjY0ODYzAl8yBAVzdGFrZQMJAGcCBQdfYW1vdW50BQtyb2xsb3ZlckZlZQkA/AcECQEMdmF1bHRBZGRyZXNzAAIJYWRkTG9ja2VkBQNuaWwJAMwIAgkBD0F0dGFjaGVkUGF5bWVudAIJAQpxdW90ZUFzc2V0AAkAZQIFB19hbW91bnQFC3JvbGxvdmVyRmVlBQNuaWwJAPwHBAkBDHZhdWx0QWRkcmVzcwACDndpdGhkcmF3TG9ja2VkCQDMCAIJAGUCBQtyb2xsb3ZlckZlZQUHX2Ftb3VudAUDbmlsBQNuaWwDCQAAAgUFc3Rha2UFBXN0YWtlBAxkZXBvc2l0VmF1bHQJAPwHBAkBDHZhdWx0QWRkcmVzcwACB2FkZEZyZWUFA25pbAkAzAgCCQEPQXR0YWNoZWRQYXltZW50AgkBCnF1b3RlQXNzZXQABQpmZWVUb1ZhdWx0BQNuaWwDCQAAAgUMZGVwb3NpdFZhdWx0BQxkZXBvc2l0VmF1bHQECW5vdGlmeUZlZQkA/AcECQEMbWluZXJBZGRyZXNzAAIKbm90aWZ5RmVlcwkAzAgCBQdfdHJhZGVyCQDMCAIFCWZlZUFtb3VudAUDbmlsBQNuaWwDCQAAAgUJbm90aWZ5RmVlBQlub3RpZnlGZWUEDm5vdGlmeU5vdGlvbmFsCQD8BwQJAQxtaW5lckFkZHJlc3MAAg5ub3RpZnlOb3Rpb25hbAkAzAgCBQdfdHJhZGVyCQDMCAIFF25ld1Bvc2l0aW9uT3Blbk5vdGlvbmFsBQNuaWwFA25pbAMJAAACBQ5ub3RpZnlOb3Rpb25hbAUObm90aWZ5Tm90aW9uYWwJAM4IAgkAzggCCQDOCAIJAM4IAgkAzggCCQDOCAIJAQ51cGRhdGVQb3NpdGlvbgYFB190cmFkZXIFD25ld1Bvc2l0aW9uU2l6ZQUXbmV3UG9zaXRpb25SZW1haW5NYXJnaW4FF25ld1Bvc2l0aW9uT3Blbk5vdGlvbmFsBRRuZXdQb3NpdGlvbkxhdGVzdENQRgUUbmV3UG9zaXRpb25UaW1lc3RhbXAJAR9pbmNyZW1lbnRQb3NpdGlvblNlcXVlbmNlTnVtYmVyAwUNaXNOZXdQb3NpdGlvbgUHX3RyYWRlcgUKX2RpcmVjdGlvbgkBEXVwZGF0ZVBvc2l0aW9uRmVlBAUNaXNOZXdQb3NpdGlvbgUHX3RyYWRlcgUKX2RpcmVjdGlvbgULYWRqdXN0ZWRGZWUJAQl1cGRhdGVBbW0IBRZxdW90ZUFzc2V0UmVzZXJ2ZUFmdGVyBRViYXNlQXNzZXRSZXNlcnZlQWZ0ZXIFFnRvdGFsUG9zaXRpb25TaXplQWZ0ZXIFGW9wZW5JbnRlcmVzdE5vdGlvbmFsQWZ0ZXIFDnRvdGFsTG9uZ0FmdGVyBQ90b3RhbFNob3J0QWZ0ZXIFGnRvdGFsTG9uZ09wZW5JbnRlcmVzdEFmdGVyBRt0b3RhbFNob3J0T3BlbkludGVyZXN0QWZ0ZXIJAQt0cmFuc2ZlckZlZQEFDGZlZVRvU3Rha2VycwkBDXVwZGF0ZUJhbGFuY2UBCQBlAgkAZAIJAQhjYmFsYW5jZQAFB19hbW91bnQFC3JvbGxvdmVyRmVlCQEOZG9CdXJuQXJ0aWZhY3QCBQxidXJuQXJ0aWZhY3QFAWkJAAIBAiRTdHJpY3QgdmFsdWUgaXMgbm90IGVxdWFsIHRvIGl0c2VsZi4JAAIBAiRTdHJpY3QgdmFsdWUgaXMgbm90IGVxdWFsIHRvIGl0c2VsZi4JAAIBAiRTdHJpY3QgdmFsdWUgaXMgbm90IGVxdWFsIHRvIGl0c2VsZi4JAAIBAiRTdHJpY3QgdmFsdWUgaXMgbm90IGVxdWFsIHRvIGl0c2VsZi4JAAIBAiRTdHJpY3QgdmFsdWUgaXMgbm90IGVxdWFsIHRvIGl0c2VsZi4JAAIBAiRTdHJpY3QgdmFsdWUgaXMgbm90IGVxdWFsIHRvIGl0c2VsZi4JAAIBAiRTdHJpY3QgdmFsdWUgaXMgbm90IGVxdWFsIHRvIGl0c2VsZi4JAAIBAiRTdHJpY3QgdmFsdWUgaXMgbm90IGVxdWFsIHRvIGl0c2VsZi4BaQEJYWRkTWFyZ2luAgpfZGlyZWN0aW9uDF9wcmljZVVwZGF0ZQQMdXBkYXRlT3JhY2xlCQD8BwQFBHRoaXMCDHVwZGF0ZU9yYWNsZQkAzAgCBQxfcHJpY2VVcGRhdGUFA25pbAUDbmlsAwkAAAIFDHVwZGF0ZU9yYWNsZQUMdXBkYXRlT3JhY2xlBARzeW5jCQD8BwQFBHRoaXMCGXN5bmNUZXJtaW5hbFByaWNlVG9PcmFjbGUFA25pbAUDbmlsAwkAAAIFBHN5bmMFBHN5bmMEEGVuc3VyZUNhbGxlZE9uY2UJAPwHBAUEdGhpcwIQZW5zdXJlQ2FsbGVkT25jZQUDbmlsBQNuaWwDCQAAAgUQZW5zdXJlQ2FsbGVkT25jZQUQZW5zdXJlQ2FsbGVkT25jZQQHX3RyYWRlcgkApQgBCAUBaQZjYWxsZXIEB19hbW91bnQICQCRAwIIBQFpCHBheW1lbnRzAAAGYW1vdW50BAhfYXNzZXRJZAgJAJEDAggFAWkIcGF5bWVudHMAAAdhc3NldElkBAtfYXNzZXRJZFN0cgkA2AQBCQEFdmFsdWUBBQhfYXNzZXRJZAQMaXNRdW90ZUFzc2V0CQAAAgUIX2Fzc2V0SWQJAQpxdW90ZUFzc2V0AAMDAwMDCQEBIQEFDGlzUXVvdGVBc3NldAYJAQEhAQkBE3JlcXVpcmVPcGVuUG9zaXRpb24CCQClCAEIBQFpBmNhbGxlcgUKX2RpcmVjdGlvbgYJAQEhAQkBC2luaXRpYWxpemVkAAYJAQZwYXVzZWQABgkBDmlzTWFya2V0Q2xvc2VkAAkAAgECHEludmFsaWQgYWRkTWFyZ2luIHBhcmFtZXRlcnMEDSR0MDY3MjA1NjczODUJAQtnZXRQb3NpdGlvbgIFB190cmFkZXIFCl9kaXJlY3Rpb24ED29sZFBvc2l0aW9uU2l6ZQgFDSR0MDY3MjA1NjczODUCXzEEEW9sZFBvc2l0aW9uTWFyZ2luCAUNJHQwNjcyMDU2NzM4NQJfMgQXb2xkUG9zaXRpb25PcGVuTm90aW9uYWwIBQ0kdDA2NzIwNTY3Mzg1Al8zBBRvbGRQb3NpdGlvbkxzdFVwZENQRggFDSR0MDY3MjA1NjczODUCXzQEFG9sZFBvc2l0aW9uVGltZXN0YW1wCAUNJHQwNjcyMDU2NzM4NQJfNQQFc3Rha2UJAPwHBAkBDHZhdWx0QWRkcmVzcwACCWFkZExvY2tlZAUDbmlsCQDMCAIJAQ9BdHRhY2hlZFBheW1lbnQCCQEKcXVvdGVBc3NldAAFB19hbW91bnQFA25pbAMJAAACBQVzdGFrZQUFc3Rha2UEDSR0MDY3NTI1Njc3NTEJATBjYWxjUmVtYWluTWFyZ2luV2l0aEZ1bmRpbmdQYXltZW50QW5kUm9sbG92ZXJGZWUFBQ9vbGRQb3NpdGlvblNpemUFEW9sZFBvc2l0aW9uTWFyZ2luBRRvbGRQb3NpdGlvbkxzdFVwZENQRgUUb2xkUG9zaXRpb25UaW1lc3RhbXAFB19hbW91bnQEDHJlbWFpbk1hcmdpbggFDSR0MDY3NTI1Njc3NTECXzEEB2JhZERlYnQIBQ0kdDA2NzUyNTY3NzUxAl8yBAtyb2xsb3ZlckZlZQgFDSR0MDY3NTI1Njc3NTECXzMEC21hcmdpblJhdGlvCQEPY2FsY01hcmdpblJhdGlvAwUMcmVtYWluTWFyZ2luBQdiYWREZWJ0BRdvbGRQb3NpdGlvbk9wZW5Ob3Rpb25hbAQOY2hlY2tNaW5NYXJnaW4JARZyZXF1aXJlTW9yZU1hcmdpblJhdGlvAwULbWFyZ2luUmF0aW8JARJtaW5Jbml0TWFyZ2luUmF0aW8ABwMJAAACBQ5jaGVja01pbk1hcmdpbgUOY2hlY2tNaW5NYXJnaW4EFmRvVHJhbnNmZXJGZWVUb1N0YWtlcnMDCQBmAgULcm9sbG92ZXJGZWUAAAQNJHQwNjgwMDc2ODA2NgkBDWRpc3RyaWJ1dGVGZWUBBQtyb2xsb3ZlckZlZQQMZmVlVG9TdGFrZXJzCAUNJHQwNjgwMDc2ODA2NgJfMQQKZmVlVG9WYXVsdAgFDSR0MDY4MDA3NjgwNjYCXzIEB3Vuc3Rha2UJAPwHBAkBDHZhdWx0QWRkcmVzcwACDndpdGhkcmF3TG9ja2VkCQDMCAIFDGZlZVRvU3Rha2VycwUDbmlsBQNuaWwDCQAAAgUHdW5zdGFrZQUHdW5zdGFrZQQLbG9ja0JhZERlYnQJAPwHBAkBDHZhdWx0QWRkcmVzcwACFWV4Y2hhbmdlRnJlZUFuZExvY2tlZAkAzAgCCQEBLQEFCmZlZVRvVmF1bHQFA25pbAUDbmlsAwkAAAIFC2xvY2tCYWREZWJ0BQtsb2NrQmFkRGVidAkBC3RyYW5zZmVyRmVlAQUMZmVlVG9TdGFrZXJzCQACAQIkU3RyaWN0IHZhbHVlIGlzIG5vdCBlcXVhbCB0byBpdHNlbGYuCQACAQIkU3RyaWN0IHZhbHVlIGlzIG5vdCBlcXVhbCB0byBpdHNlbGYuBQNuaWwDCQAAAgUWZG9UcmFuc2ZlckZlZVRvU3Rha2VycwUWZG9UcmFuc2ZlckZlZVRvU3Rha2VycwkAzggCCQDOCAIJAQ51cGRhdGVQb3NpdGlvbgYFB190cmFkZXIFD29sZFBvc2l0aW9uU2l6ZQkAZAIJAGUCBRFvbGRQb3NpdGlvbk1hcmdpbgULcm9sbG92ZXJGZWUFB19hbW91bnQFF29sZFBvc2l0aW9uT3Blbk5vdGlvbmFsBRRvbGRQb3NpdGlvbkxzdFVwZENQRgkBDWxhc3RUaW1lc3RhbXAACQENdXBkYXRlQmFsYW5jZQEJAGUCCQBkAgkBCGNiYWxhbmNlAAUHX2Ftb3VudAULcm9sbG92ZXJGZWUFFmRvVHJhbnNmZXJGZWVUb1N0YWtlcnMJAAIBAiRTdHJpY3QgdmFsdWUgaXMgbm90IGVxdWFsIHRvIGl0c2VsZi4JAAIBAiRTdHJpY3QgdmFsdWUgaXMgbm90IGVxdWFsIHRvIGl0c2VsZi4JAAIBAiRTdHJpY3QgdmFsdWUgaXMgbm90IGVxdWFsIHRvIGl0c2VsZi4JAAIBAiRTdHJpY3QgdmFsdWUgaXMgbm90IGVxdWFsIHRvIGl0c2VsZi4JAAIBAiRTdHJpY3QgdmFsdWUgaXMgbm90IGVxdWFsIHRvIGl0c2VsZi4JAAIBAiRTdHJpY3QgdmFsdWUgaXMgbm90IGVxdWFsIHRvIGl0c2VsZi4BaQEMcmVtb3ZlTWFyZ2luAwdfYW1vdW50Cl9kaXJlY3Rpb24MX3ByaWNlVXBkYXRlBAx1cGRhdGVPcmFjbGUJAPwHBAUEdGhpcwIMdXBkYXRlT3JhY2xlCQDMCAIFDF9wcmljZVVwZGF0ZQUDbmlsBQNuaWwDCQAAAgUMdXBkYXRlT3JhY2xlBQx1cGRhdGVPcmFjbGUEBHN5bmMJAPwHBAUEdGhpcwIZc3luY1Rlcm1pbmFsUHJpY2VUb09yYWNsZQUDbmlsBQNuaWwDCQAAAgUEc3luYwUEc3luYwQQZW5zdXJlQ2FsbGVkT25jZQkA/AcEBQR0aGlzAhBlbnN1cmVDYWxsZWRPbmNlBQNuaWwFA25pbAMJAAACBRBlbnN1cmVDYWxsZWRPbmNlBRBlbnN1cmVDYWxsZWRPbmNlBAdfdHJhZGVyCQClCAEIBQFpBmNhbGxlcgMDAwMDCQBnAgAABQdfYW1vdW50BgkBASEBCQETcmVxdWlyZU9wZW5Qb3NpdGlvbgIFB190cmFkZXIFCl9kaXJlY3Rpb24GCQEBIQEJAQtpbml0aWFsaXplZAAGCQEGcGF1c2VkAAYJAQ5pc01hcmtldENsb3NlZAAJAAIBAh9JbnZhbGlkIHJlbW92ZU1hcmdpbiBwYXJhbWV0ZXJzBA0kdDA2OTU2NzY5NzQ3CQELZ2V0UG9zaXRpb24CBQdfdHJhZGVyBQpfZGlyZWN0aW9uBA9vbGRQb3NpdGlvblNpemUIBQ0kdDA2OTU2NzY5NzQ3Al8xBBFvbGRQb3NpdGlvbk1hcmdpbggFDSR0MDY5NTY3Njk3NDcCXzIEF29sZFBvc2l0aW9uT3Blbk5vdGlvbmFsCAUNJHQwNjk1Njc2OTc0NwJfMwQUb2xkUG9zaXRpb25Mc3RVcGRDUEYIBQ0kdDA2OTU2NzY5NzQ3Al80BBRvbGRQb3NpdGlvblRpbWVzdGFtcAgFDSR0MDY5NTY3Njk3NDcCXzUEDSR0MDY5NzUzNzAwMDIJATBjYWxjUmVtYWluTWFyZ2luV2l0aEZ1bmRpbmdQYXltZW50QW5kUm9sbG92ZXJGZWUFBQ9vbGRQb3NpdGlvblNpemUFEW9sZFBvc2l0aW9uTWFyZ2luBRRvbGRQb3NpdGlvbkxzdFVwZENQRgUUb2xkUG9zaXRpb25UaW1lc3RhbXAJAQEtAQUHX2Ftb3VudAQMcmVtYWluTWFyZ2luCAUNJHQwNjk3NTM3MDAwMgJfMQQHYmFkRGVidAgFDSR0MDY5NzUzNzAwMDICXzIEDmZ1bmRpbmdQYXltZW50CAUNJHQwNjk3NTM3MDAwMgJfMwQLcm9sbG92ZXJGZWUIBQ0kdDA2OTc1MzcwMDAyAl80AwkBAiE9AgUHYmFkRGVidAAACQACAQIdSW52YWxpZCByZW1vdmVkIG1hcmdpbiBhbW91bnQEC21hcmdpblJhdGlvCQEPY2FsY01hcmdpblJhdGlvAwUMcmVtYWluTWFyZ2luBQdiYWREZWJ0BRdvbGRQb3NpdGlvbk9wZW5Ob3Rpb25hbAMJAQEhAQkBFnJlcXVpcmVNb3JlTWFyZ2luUmF0aW8DBQttYXJnaW5SYXRpbwkBD2luaXRNYXJnaW5SYXRpbwAGCQACAQkArAICCQCsAgIJAKwCAgIZVG9vIG11Y2ggbWFyZ2luIHJlbW92ZWQ6IAkApAMBBQttYXJnaW5SYXRpbwIDIDwgCQCkAwEJAQ9pbml0TWFyZ2luUmF0aW8ABA0kdDA3MDM4ODcwNDQ3CQENZGlzdHJpYnV0ZUZlZQEFC3JvbGxvdmVyRmVlBAxmZWVUb1N0YWtlcnMIBQ0kdDA3MDM4ODcwNDQ3Al8xBApmZWVUb1ZhdWx0CAUNJHQwNzAzODg3MDQ0NwJfMgQWZG9UcmFuc2ZlckZlZVRvU3Rha2VycwMJAGYCBQtyb2xsb3ZlckZlZQAABAtsb2NrQmFkRGVidAkA/AcECQEMdmF1bHRBZGRyZXNzAAIVZXhjaGFuZ2VGcmVlQW5kTG9ja2VkCQDMCAIJAQEtAQUKZmVlVG9WYXVsdAUDbmlsBQNuaWwDCQAAAgULbG9ja0JhZERlYnQFC2xvY2tCYWREZWJ0CQELdHJhbnNmZXJGZWUBBQxmZWVUb1N0YWtlcnMJAAIBAiRTdHJpY3QgdmFsdWUgaXMgbm90IGVxdWFsIHRvIGl0c2VsZi4FA25pbAMJAAACBRZkb1RyYW5zZmVyRmVlVG9TdGFrZXJzBRZkb1RyYW5zZmVyRmVlVG9TdGFrZXJzBAd1bnN0YWtlCQD8BwQJAQx2YXVsdEFkZHJlc3MAAg53aXRoZHJhd0xvY2tlZAkAzAgCCQBkAgUHX2Ftb3VudAUMZmVlVG9TdGFrZXJzBQNuaWwFA25pbAMJAAACBQd1bnN0YWtlBQd1bnN0YWtlCQDOCAIJAM4IAgkAzggCCQEOdXBkYXRlUG9zaXRpb24GBQdfdHJhZGVyBQ9vbGRQb3NpdGlvblNpemUFDHJlbWFpbk1hcmdpbgUXb2xkUG9zaXRpb25PcGVuTm90aW9uYWwJAR9sYXRlc3RDdW11bGF0aXZlUHJlbWl1bUZyYWN0aW9uAQUPb2xkUG9zaXRpb25TaXplCQENbGFzdFRpbWVzdGFtcAAJAQh3aXRoZHJhdwIIBQFpBmNhbGxlcgUHX2Ftb3VudAkBDXVwZGF0ZUJhbGFuY2UBCQBlAgkAZQIJAQhjYmFsYW5jZQAFB19hbW91bnQFC3JvbGxvdmVyRmVlBRZkb1RyYW5zZmVyRmVlVG9TdGFrZXJzCQACAQIkU3RyaWN0IHZhbHVlIGlzIG5vdCBlcXVhbCB0byBpdHNlbGYuCQACAQIkU3RyaWN0IHZhbHVlIGlzIG5vdCBlcXVhbCB0byBpdHNlbGYuCQACAQIkU3RyaWN0IHZhbHVlIGlzIG5vdCBlcXVhbCB0byBpdHNlbGYuCQACAQIkU3RyaWN0IHZhbHVlIGlzIG5vdCBlcXVhbCB0byBpdHNlbGYuCQACAQIkU3RyaWN0IHZhbHVlIGlzIG5vdCBlcXVhbCB0byBpdHNlbGYuAWkBDWNsb3NlUG9zaXRpb24FBV9zaXplCl9kaXJlY3Rpb24UX21pblF1b3RlQXNzZXRBbW91bnQMX2FkZFRvTWFyZ2luDF9wcmljZVVwZGF0ZQQMdXBkYXRlT3JhY2xlCQD8BwQFBHRoaXMCDHVwZGF0ZU9yYWNsZQkAzAgCBQxfcHJpY2VVcGRhdGUFA25pbAUDbmlsAwkAAAIFDHVwZGF0ZU9yYWNsZQUMdXBkYXRlT3JhY2xlBARzeW5jCQD8BwQFBHRoaXMCGXN5bmNUZXJtaW5hbFByaWNlVG9PcmFjbGUFA25pbAUDbmlsAwkAAAIFBHN5bmMFBHN5bmMEEGVuc3VyZUNhbGxlZE9uY2UJAPwHBAUEdGhpcwIQZW5zdXJlQ2FsbGVkT25jZQUDbmlsBQNuaWwDCQAAAgUQZW5zdXJlQ2FsbGVkT25jZQUQZW5zdXJlQ2FsbGVkT25jZQQHX3RyYWRlcgkBD2dldEFjdHVhbENhbGxlcgEFAWkEDl90cmFkZXJBZGRyZXNzCQETdmFsdWVPckVycm9yTWVzc2FnZQIJAKYIAQUHX3RyYWRlcgIOSW52YWxpZCBjYWxsZXIEC3Bvc2l0aW9uRmVlCQEOZ2V0UG9zaXRpb25GZWUCBQdfdHJhZGVyBQpfZGlyZWN0aW9uAwMDAwMDCQEBIQEJARNyZXF1aXJlT3BlblBvc2l0aW9uAgUHX3RyYWRlcgUKX2RpcmVjdGlvbgYJAQEhAQkBC2luaXRpYWxpemVkAAYJAQZwYXVzZWQABgkAZwIAAAUFX3NpemUGCQBmAgAABRRfbWluUXVvdGVBc3NldEFtb3VudAYJAQ5pc01hcmtldENsb3NlZAAJAAIBAiBJbnZhbGlkIGNsb3NlUG9zaXRpb24gcGFyYW1ldGVycwQUb2xkUG9zaXRpb25UaW1lc3RhbXAICQELZ2V0UG9zaXRpb24CBQdfdHJhZGVyBQpfZGlyZWN0aW9uAl81BA0kdDA3Mjc4MjczMzg1CQEVaW50ZXJuYWxDbG9zZVBvc2l0aW9uCAUHX3RyYWRlcgUKX2RpcmVjdGlvbgUFX3NpemUFC3Bvc2l0aW9uRmVlBRRfbWluUXVvdGVBc3NldEFtb3VudAUMX2FkZFRvTWFyZ2luBgYED25ld1Bvc2l0aW9uU2l6ZQgFDSR0MDcyNzgyNzMzODUCXzEEEW5ld1Bvc2l0aW9uTWFyZ2luCAUNJHQwNzI3ODI3MzM4NQJfMgQXbmV3UG9zaXRpb25PcGVuTm90aW9uYWwIBQ0kdDA3Mjc4MjczMzg1Al8zBBRuZXdQb3NpdGlvbkxzdFVwZENQRggFDSR0MDcyNzgyNzMzODUCXzQED3Bvc2l0aW9uQmFkRGVidAgFDSR0MDcyNzgyNzMzODUCXzUEC3JlYWxpemVkUG5sCAUNJHQwNzI3ODI3MzM4NQJfNgQObWFyZ2luVG9UcmFkZXIIBQ0kdDA3Mjc4MjczMzg1Al83BBZxdW90ZUFzc2V0UmVzZXJ2ZUFmdGVyCAUNJHQwNzI3ODI3MzM4NQJfOAQVYmFzZUFzc2V0UmVzZXJ2ZUFmdGVyCAUNJHQwNzI3ODI3MzM4NQJfOQQWdG90YWxQb3NpdGlvblNpemVBZnRlcggFDSR0MDcyNzgyNzMzODUDXzEwBBlvcGVuSW50ZXJlc3ROb3Rpb25hbEFmdGVyCAUNJHQwNzI3ODI3MzM4NQNfMTEEDnRvdGFsTG9uZ0FmdGVyCAUNJHQwNzI3ODI3MzM4NQNfMTIED3RvdGFsU2hvcnRBZnRlcggFDSR0MDcyNzgyNzMzODUDXzEzBBp0b3RhbExvbmdPcGVuSW50ZXJlc3RBZnRlcggFDSR0MDcyNzgyNzMzODUDXzE0BBt0b3RhbFNob3J0T3BlbkludGVyZXN0QWZ0ZXIIBQ0kdDA3Mjc4MjczMzg1A18xNQQLcmVhbGl6ZWRGZWUIBQ0kdDA3Mjc4MjczMzg1A18xNgMJAGYCBQ9wb3NpdGlvbkJhZERlYnQAAAkAAgECKkludmFsaWQgY2xvc2VQb3NpdGlvbiBwYXJhbWV0ZXJzOiBiYWQgZGVidAMJAGcCBRRvbGRQb3NpdGlvblRpbWVzdGFtcAkBDWxhc3RUaW1lc3RhbXAACQACAQJTSW52YWxpZCBjbG9zZVBvc2l0aW9uIHBhcmFtZXRlcnM6IHdhaXQgYXQgbGVhc3QgMSBibG9jayBiZWZvcmUgY2xvc2luZyB0aGUgcG9zaXRpb24EDmlzUGFydGlhbENsb3NlCQECIT0CBQ9uZXdQb3NpdGlvblNpemUAAAQOd2l0aGRyYXdBbW91bnQJAGQCBQ5tYXJnaW5Ub1RyYWRlcgULcmVhbGl6ZWRGZWUECmFtbUJhbGFuY2UJAGUCCQEIY2JhbGFuY2UABQ53aXRoZHJhd0Ftb3VudAQNYW1tTmV3QmFsYW5jZQMJAGYCAAAFCmFtbUJhbGFuY2UAAAUKYW1tQmFsYW5jZQQHdW5zdGFrZQkA/AcECQEMdmF1bHRBZGRyZXNzAAIOd2l0aGRyYXdMb2NrZWQJAMwIAgUOd2l0aGRyYXdBbW91bnQFA25pbAUDbmlsAwkAAAIFB3Vuc3Rha2UFB3Vuc3Rha2UEDnJlZmVycmVyRmVlQW55CQD8BwQJAQ9yZWZlcnJhbEFkZHJlc3MAAg1hY2NlcHRQYXltZW50CQDMCAIFB190cmFkZXIFA25pbAkAzAgCCQEPQXR0YWNoZWRQYXltZW50AgkBCnF1b3RlQXNzZXQABQtyZWFsaXplZEZlZQUDbmlsAwkAAAIFDnJlZmVycmVyRmVlQW55BQ5yZWZlcnJlckZlZUFueQQLcmVmZXJyZXJGZWUEByRtYXRjaDAFDnJlZmVycmVyRmVlQW55AwkAAQIFByRtYXRjaDACA0ludAQBeAUHJG1hdGNoMAUBeAkAAgECE0ludmFsaWQgcmVmZXJyZXJGZWUEDSR0MDc0MzU3NzQ0MzAJAQ1kaXN0cmlidXRlRmVlAQkAZQIFC3JlYWxpemVkRmVlBQtyZWZlcnJlckZlZQQMZmVlVG9TdGFrZXJzCAUNJHQwNzQzNTc3NDQzMAJfMQQKZmVlVG9WYXVsdAgFDSR0MDc0MzU3NzQ0MzACXzIEDGRlcG9zaXRWYXVsdAkA/AcECQEMdmF1bHRBZGRyZXNzAAIHYWRkRnJlZQUDbmlsCQDMCAIJAQ9BdHRhY2hlZFBheW1lbnQCCQEKcXVvdGVBc3NldAAFCmZlZVRvVmF1bHQFA25pbAMJAAACBQxkZXBvc2l0VmF1bHQFDGRlcG9zaXRWYXVsdAQJbm90aWZ5RmVlCQD8BwQJAQxtaW5lckFkZHJlc3MAAgpub3RpZnlGZWVzCQDMCAIFB190cmFkZXIJAMwIAgULcmVhbGl6ZWRGZWUFA25pbAUDbmlsAwkAAAIFCW5vdGlmeUZlZQUJbm90aWZ5RmVlBA5ub3RpZnlOb3Rpb25hbAkA/AcECQEMbWluZXJBZGRyZXNzAAIObm90aWZ5Tm90aW9uYWwJAMwIAgUHX3RyYWRlcgkAzAgCBRduZXdQb3NpdGlvbk9wZW5Ob3Rpb25hbAUDbmlsBQNuaWwDCQAAAgUObm90aWZ5Tm90aW9uYWwFDm5vdGlmeU5vdGlvbmFsCQDOCAIJAM4IAgkAzggCCQDOCAIDBQ5pc1BhcnRpYWxDbG9zZQkBDnVwZGF0ZVBvc2l0aW9uBgUHX3RyYWRlcgUPbmV3UG9zaXRpb25TaXplBRFuZXdQb3NpdGlvbk1hcmdpbgUXbmV3UG9zaXRpb25PcGVuTm90aW9uYWwFFG5ld1Bvc2l0aW9uTHN0VXBkQ1BGCQENbGFzdFRpbWVzdGFtcAAJAQ5kZWxldGVQb3NpdGlvbgIFB190cmFkZXIFCl9kaXJlY3Rpb24JAQl1cGRhdGVBbW0IBRZxdW90ZUFzc2V0UmVzZXJ2ZUFmdGVyBRViYXNlQXNzZXRSZXNlcnZlQWZ0ZXIFFnRvdGFsUG9zaXRpb25TaXplQWZ0ZXIFGW9wZW5JbnRlcmVzdE5vdGlvbmFsQWZ0ZXIFDnRvdGFsTG9uZ0FmdGVyBQ90b3RhbFNob3J0QWZ0ZXIFGnRvdGFsTG9uZ09wZW5JbnRlcmVzdEFmdGVyBRt0b3RhbFNob3J0T3BlbkludGVyZXN0QWZ0ZXIDCQBmAgUObWFyZ2luVG9UcmFkZXIAAAkBCHdpdGhkcmF3AgUOX3RyYWRlckFkZHJlc3MFDm1hcmdpblRvVHJhZGVyBQNuaWwJAQ11cGRhdGVCYWxhbmNlAQUNYW1tTmV3QmFsYW5jZQkBC3RyYW5zZmVyRmVlAQUMZmVlVG9TdGFrZXJzCQACAQIkU3RyaWN0IHZhbHVlIGlzIG5vdCBlcXVhbCB0byBpdHNlbGYuCQACAQIkU3RyaWN0IHZhbHVlIGlzIG5vdCBlcXVhbCB0byBpdHNlbGYuCQACAQIkU3RyaWN0IHZhbHVlIGlzIG5vdCBlcXVhbCB0byBpdHNlbGYuCQACAQIkU3RyaWN0IHZhbHVlIGlzIG5vdCBlcXVhbCB0byBpdHNlbGYuCQACAQIkU3RyaWN0IHZhbHVlIGlzIG5vdCBlcXVhbCB0byBpdHNlbGYuCQACAQIkU3RyaWN0IHZhbHVlIGlzIG5vdCBlcXVhbCB0byBpdHNlbGYuCQACAQIkU3RyaWN0IHZhbHVlIGlzIG5vdCBlcXVhbCB0byBpdHNlbGYuCQACAQIkU3RyaWN0IHZhbHVlIGlzIG5vdCBlcXVhbCB0byBpdHNlbGYuAWkBCWxpcXVpZGF0ZQMHX3RyYWRlcgpfZGlyZWN0aW9uDF9wcmljZVVwZGF0ZQQMdXBkYXRlT3JhY2xlCQD8BwQFBHRoaXMCDHVwZGF0ZU9yYWNsZQkAzAgCBQxfcHJpY2VVcGRhdGUFA25pbAUDbmlsAwkAAAIFDHVwZGF0ZU9yYWNsZQUMdXBkYXRlT3JhY2xlBARzeW5jCQD8BwQFBHRoaXMCGXN5bmNUZXJtaW5hbFByaWNlVG9PcmFjbGUFA25pbAUDbmlsAwkAAAIFBHN5bmMFBHN5bmMED3Nwb3RNYXJnaW5SYXRpbwkBFmdldE1hcmdpblJhdGlvQnlPcHRpb24DBQdfdHJhZGVyBQpfZGlyZWN0aW9uBQ9QTkxfT1BUSU9OX1NQT1QEFmxpcXVpZGF0aW9uTWFyZ2luUmF0aW8DCQEWaXNPdmVyRmx1Y3R1YXRpb25MaW1pdAAEEW9yYWNsZU1hcmdpblJhdGlvCQEWZ2V0TWFyZ2luUmF0aW9CeU9wdGlvbgMFB190cmFkZXIFCl9kaXJlY3Rpb24FEVBOTF9PUFRJT05fT1JBQ0xFCQEEdm1heAIFD3Nwb3RNYXJnaW5SYXRpbwURb3JhY2xlTWFyZ2luUmF0aW8FD3Nwb3RNYXJnaW5SYXRpbwMDAwMDCQEBIQEJARZyZXF1aXJlTW9yZU1hcmdpblJhdGlvAwUWbGlxdWlkYXRpb25NYXJnaW5SYXRpbwkBFm1haW50ZW5hbmNlTWFyZ2luUmF0aW8ABwYJAQEhAQkBE3JlcXVpcmVPcGVuUG9zaXRpb24CBQdfdHJhZGVyBQpfZGlyZWN0aW9uBgkBASEBCQELaW5pdGlhbGl6ZWQABgkBBnBhdXNlZAAGCQEOaXNNYXJrZXRDbG9zZWQACQACAQITVW5hYmxlIHRvIGxpcXVpZGF0ZQQPb2xkUG9zaXRpb25TaXplCAkBC2dldFBvc2l0aW9uAgUHX3RyYWRlcgUKX2RpcmVjdGlvbgJfMQQPcG9zaXRpb25TaXplQWJzCQEDYWJzAQUPb2xkUG9zaXRpb25TaXplBBRpc1BhcnRpYWxMaXF1aWRhdGlvbgMDAwkAZgIFD3Nwb3RNYXJnaW5SYXRpbwkBE2xpcXVpZGF0aW9uRmVlUmF0aW8ACQBmAgkBF3BhcnRpYWxMaXF1aWRhdGlvblJhdGlvAAAABwkAZgIFDERFQ0lNQUxfVU5JVAkBF3BhcnRpYWxMaXF1aWRhdGlvblJhdGlvAAcJAGYCCQEEbXVsZAIFD3Bvc2l0aW9uU2l6ZUFicwkBDGdldFNwb3RQcmljZQAJAR1taW5QYXJ0aWFsTGlxdWlkYXRpb25Ob3Rpb25hbAAHBA0kdDA3NzEwNDc3NDkxAwUUaXNQYXJ0aWFsTGlxdWlkYXRpb24ED2xpcXVpZGF0aW9uU2l6ZQkBA2FicwEJARtnZXRQYXJ0aWFsTGlxdWlkYXRpb25BbW91bnQCBQdfdHJhZGVyBQ9vbGRQb3NpdGlvblNpemUEEGxpcXVpZGF0aW9uUmF0aW8JAQRkaXZkAgUPbGlxdWlkYXRpb25TaXplBQ9wb3NpdGlvblNpemVBYnMEE2xpcXVpZGF0aW9uTm90aW9uYWwJAQRtdWxkAgUPbGlxdWlkYXRpb25TaXplCQEMZ2V0U3BvdFByaWNlAAkAlAoCBRBsaXF1aWRhdGlvblJhdGlvBQ9saXF1aWRhdGlvblNpemUJAJQKAgAABQ9wb3NpdGlvblNpemVBYnMEEGxpcXVpZGF0aW9uUmF0aW8IBQ0kdDA3NzEwNDc3NDkxAl8xBA9saXF1aWRhdGlvblNpemUIBQ0kdDA3NzEwNDc3NDkxAl8yBA0kdDA3NzQ5Nzc4MTUzCQEVaW50ZXJuYWxDbG9zZVBvc2l0aW9uCAUHX3RyYWRlcgUKX2RpcmVjdGlvbgMFFGlzUGFydGlhbExpcXVpZGF0aW9uBQ9saXF1aWRhdGlvblNpemUFD3Bvc2l0aW9uU2l6ZUFicwkBE2xpcXVpZGF0aW9uRmVlUmF0aW8AAAAGBwYED25ld1Bvc2l0aW9uU2l6ZQgFDSR0MDc3NDk3NzgxNTMCXzEEEW5ld1Bvc2l0aW9uTWFyZ2luCAUNJHQwNzc0OTc3ODE1MwJfMgQXbmV3UG9zaXRpb25PcGVuTm90aW9uYWwIBQ0kdDA3NzQ5Nzc4MTUzAl8zBBRuZXdQb3NpdGlvbkxzdFVwZENQRggFDSR0MDc3NDk3NzgxNTMCXzQED3Bvc2l0aW9uQmFkRGVidAgFDSR0MDc3NDk3NzgxNTMCXzUEC3JlYWxpemVkUG5sCAUNJHQwNzc0OTc3ODE1MwJfNgQObWFyZ2luVG9UcmFkZXIIBQ0kdDA3NzQ5Nzc4MTUzAl83BBZxdW90ZUFzc2V0UmVzZXJ2ZUFmdGVyCAUNJHQwNzc0OTc3ODE1MwJfOAQVYmFzZUFzc2V0UmVzZXJ2ZUFmdGVyCAUNJHQwNzc0OTc3ODE1MwJfOQQWdG90YWxQb3NpdGlvblNpemVBZnRlcggFDSR0MDc3NDk3NzgxNTMDXzEwBBlvcGVuSW50ZXJlc3ROb3Rpb25hbEFmdGVyCAUNJHQwNzc0OTc3ODE1MwNfMTEEDnRvdGFsTG9uZ0FmdGVyCAUNJHQwNzc0OTc3ODE1MwNfMTIED3RvdGFsU2hvcnRBZnRlcggFDSR0MDc3NDk3NzgxNTMDXzEzBBp0b3RhbExvbmdPcGVuSW50ZXJlc3RBZnRlcggFDSR0MDc3NDk3NzgxNTMDXzE0BBt0b3RhbFNob3J0T3BlbkludGVyZXN0QWZ0ZXIIBQ0kdDA3NzQ5Nzc4MTUzA18xNQQSbGlxdWlkYXRpb25QZW5hbHR5CAUNJHQwNzc0OTc3ODE1MwNfMTYED2ZlZVRvTGlxdWlkYXRvcgkAaQIFEmxpcXVpZGF0aW9uUGVuYWx0eQACBApmZWVUb1ZhdWx0CQBlAgUSbGlxdWlkYXRpb25QZW5hbHR5BQ9mZWVUb0xpcXVpZGF0b3IECmFtbUJhbGFuY2UJAGUCCQEIY2JhbGFuY2UABRJsaXF1aWRhdGlvblBlbmFsdHkEDW5ld0FtbUJhbGFuY2UDCQBmAgAABQphbW1CYWxhbmNlAAAFCmFtbUJhbGFuY2UEC2xvY2tCYWREZWJ0AwkAZgIFD3Bvc2l0aW9uQmFkRGVidAAABAtsb2NrQmFkRGVidAkA/AcECQEMdmF1bHRBZGRyZXNzAAIVZXhjaGFuZ2VGcmVlQW5kTG9ja2VkCQDMCAIJAGQCBQ9wb3NpdGlvbkJhZERlYnQFEmxpcXVpZGF0aW9uUGVuYWx0eQUDbmlsBQNuaWwDCQAAAgULbG9ja0JhZERlYnQFC2xvY2tCYWREZWJ0BQNuaWwJAAIBAiRTdHJpY3QgdmFsdWUgaXMgbm90IGVxdWFsIHRvIGl0c2VsZi4FA25pbAMJAAACBQtsb2NrQmFkRGVidAULbG9ja0JhZERlYnQEB3Vuc3Rha2UJAPwHBAkBDHZhdWx0QWRkcmVzcwACDndpdGhkcmF3TG9ja2VkCQDMCAIFEmxpcXVpZGF0aW9uUGVuYWx0eQUDbmlsBQNuaWwDCQAAAgUHdW5zdGFrZQUHdW5zdGFrZQQQZGVwb3NpdEluc3VyYW5jZQkA/AcECQEMdmF1bHRBZGRyZXNzAAIHYWRkRnJlZQUDbmlsCQDMCAIJAQ9BdHRhY2hlZFBheW1lbnQCCQEKcXVvdGVBc3NldAAFCmZlZVRvVmF1bHQFA25pbAMJAAACBRBkZXBvc2l0SW5zdXJhbmNlBRBkZXBvc2l0SW5zdXJhbmNlBA5ub3RpZnlOb3Rpb25hbAkA/AcECQEMbWluZXJBZGRyZXNzAAIObm90aWZ5Tm90aW9uYWwJAMwIAgUHX3RyYWRlcgkAzAgCBRduZXdQb3NpdGlvbk9wZW5Ob3Rpb25hbAUDbmlsBQNuaWwDCQAAAgUObm90aWZ5Tm90aW9uYWwFDm5vdGlmeU5vdGlvbmFsCQDOCAIJAM4IAgkAzggCAwUUaXNQYXJ0aWFsTGlxdWlkYXRpb24JAQ51cGRhdGVQb3NpdGlvbgYFB190cmFkZXIFD25ld1Bvc2l0aW9uU2l6ZQURbmV3UG9zaXRpb25NYXJnaW4FF25ld1Bvc2l0aW9uT3Blbk5vdGlvbmFsBRRuZXdQb3NpdGlvbkxzdFVwZENQRgkBDWxhc3RUaW1lc3RhbXAACQEOZGVsZXRlUG9zaXRpb24CBQdfdHJhZGVyBQpfZGlyZWN0aW9uCQEJdXBkYXRlQW1tCAUWcXVvdGVBc3NldFJlc2VydmVBZnRlcgUVYmFzZUFzc2V0UmVzZXJ2ZUFmdGVyBRZ0b3RhbFBvc2l0aW9uU2l6ZUFmdGVyBRlvcGVuSW50ZXJlc3ROb3Rpb25hbEFmdGVyBQ50b3RhbExvbmdBZnRlcgUPdG90YWxTaG9ydEFmdGVyBRp0b3RhbExvbmdPcGVuSW50ZXJlc3RBZnRlcgUbdG90YWxTaG9ydE9wZW5JbnRlcmVzdEFmdGVyCQEId2l0aGRyYXcCCAUBaQZjYWxsZXIFD2ZlZVRvTGlxdWlkYXRvcgkBDXVwZGF0ZUJhbGFuY2UBBQ1uZXdBbW1CYWxhbmNlCQACAQIkU3RyaWN0IHZhbHVlIGlzIG5vdCBlcXVhbCB0byBpdHNlbGYuCQACAQIkU3RyaWN0IHZhbHVlIGlzIG5vdCBlcXVhbCB0byBpdHNlbGYuCQACAQIkU3RyaWN0IHZhbHVlIGlzIG5vdCBlcXVhbCB0byBpdHNlbGYuCQACAQIkU3RyaWN0IHZhbHVlIGlzIG5vdCBlcXVhbCB0byBpdHNlbGYuCQACAQIkU3RyaWN0IHZhbHVlIGlzIG5vdCBlcXVhbCB0byBpdHNlbGYuCQACAQIkU3RyaWN0IHZhbHVlIGlzIG5vdCBlcXVhbCB0byBpdHNlbGYuAWkBCnBheUZ1bmRpbmcBDF9wcmljZVVwZGF0ZQQMdXBkYXRlT3JhY2xlCQD8BwQFBHRoaXMCDHVwZGF0ZU9yYWNsZQkAzAgCBQxfcHJpY2VVcGRhdGUFA25pbAUDbmlsAwkAAAIFDHVwZGF0ZU9yYWNsZQUMdXBkYXRlT3JhY2xlBARzeW5jCQD8BwQFBHRoaXMCGXN5bmNUZXJtaW5hbFByaWNlVG9PcmFjbGUFA25pbAUDbmlsAwkAAAIFBHN5bmMFBHN5bmMEFWZ1bmRpbmdCbG9ja1RpbWVzdGFtcAkBGW5leHRGdW5kaW5nQmxvY2tUaW1lc3RhbXAAAwMDCQBmAgUVZnVuZGluZ0Jsb2NrVGltZXN0YW1wCQENbGFzdFRpbWVzdGFtcAAGCQEBIQEJAQtpbml0aWFsaXplZAAGCQEGcGF1c2VkAAkAAgEJAKwCAgkArAICCQCsAgICIUludmFsaWQgZnVuZGluZyBibG9jayB0aW1lc3RhbXA6IAkApAMBCQENbGFzdFRpbWVzdGFtcAACAyA8IAkApAMBBRVmdW5kaW5nQmxvY2tUaW1lc3RhbXAED3VuZGVybHlpbmdQcmljZQkBDmdldE9yYWNsZVByaWNlAAQNJHQwODAzNzE4MDQ0OQkBCmdldEZ1bmRpbmcABBRzaG9ydFByZW1pdW1GcmFjdGlvbggFDSR0MDgwMzcxODA0NDkCXzEEE2xvbmdQcmVtaXVtRnJhY3Rpb24IBQ0kdDA4MDM3MTgwNDQ5Al8yBA5wcmVtaXVtVG9WYXVsdAgFDSR0MDgwMzcxODA0NDkCXzMEE2RvUGF5RnVuZGluZ1RvVmF1bHQDCQBmAgUOcHJlbWl1bVRvVmF1bHQAAAQTZG9QYXlGdW5kaW5nVG9WYXVsdAkA/AcECQEMdmF1bHRBZGRyZXNzAAIVZXhjaGFuZ2VGcmVlQW5kTG9ja2VkCQDMCAIJAQEtAQUOcHJlbWl1bVRvVmF1bHQFA25pbAUDbmlsAwkAAAIFE2RvUGF5RnVuZGluZ1RvVmF1bHQFE2RvUGF5RnVuZGluZ1RvVmF1bHQFA25pbAkAAgECJFN0cmljdCB2YWx1ZSBpcyBub3QgZXF1YWwgdG8gaXRzZWxmLgUDbmlsAwkAAAIFE2RvUGF5RnVuZGluZ1RvVmF1bHQFE2RvUGF5RnVuZGluZ1RvVmF1bHQJAQ11cGRhdGVGdW5kaW5nBQkAZAIFFWZ1bmRpbmdCbG9ja1RpbWVzdGFtcAkBFGZ1bmRpbmdQZXJpb2RTZWNvbmRzAAkAZAIJASNsYXRlc3RMb25nQ3VtdWxhdGl2ZVByZW1pdW1GcmFjdGlvbgAFE2xvbmdQcmVtaXVtRnJhY3Rpb24JAGQCCQEkbGF0ZXN0U2hvcnRDdW11bGF0aXZlUHJlbWl1bUZyYWN0aW9uAAUUc2hvcnRQcmVtaXVtRnJhY3Rpb24JAQRkaXZkAgUTbG9uZ1ByZW1pdW1GcmFjdGlvbgUPdW5kZXJseWluZ1ByaWNlCQEEZGl2ZAIFFHNob3J0UHJlbWl1bUZyYWN0aW9uBQ91bmRlcmx5aW5nUHJpY2UJAAIBAiRTdHJpY3QgdmFsdWUgaXMgbm90IGVxdWFsIHRvIGl0c2VsZi4JAAIBAiRTdHJpY3QgdmFsdWUgaXMgbm90IGVxdWFsIHRvIGl0c2VsZi4JAAIBAiRTdHJpY3QgdmFsdWUgaXMgbm90IGVxdWFsIHRvIGl0c2VsZi4BaQEMdXBkYXRlT3JhY2xlAQxfcHJpY2VVcGRhdGUDCQAAAgkBCm9yYWNsZU1vZGUABQxPUkFDTEVfUExBSU4FA25pbAQMcHJpY2VVcGRhdGVzCQC8CQIFDF9wcmljZVVwZGF0ZQICOjoECmJhc2VPcmFjbGUJARN2YWx1ZU9yRXJyb3JNZXNzYWdlAgkBDWdldE9yYWNsZURhdGEBBQxrX2Jhc2VPcmFjbGUCGU5vIGJhc2UgYXNzZXQgb3JhY2xlIGRhdGEEEWJhc2VPcmFjbGVBZGRyZXNzCAUKYmFzZU9yYWNsZQJfMQQSZG9VcGRhdGVCYXNlT3JhY2xlCQD8BwQFEWJhc2VPcmFjbGVBZGRyZXNzAgp1cGRhdGVEYXRhCQDMCAIJAJEDAgUMcHJpY2VVcGRhdGVzAAAFA25pbAUDbmlsAwkAAAIFEmRvVXBkYXRlQmFzZU9yYWNsZQUSZG9VcGRhdGVCYXNlT3JhY2xlBAtxdW90ZU9yYWNsZQkBDWdldE9yYWNsZURhdGEBBQ1rX3F1b3RlT3JhY2xlBBNkb1VwZGF0ZVF1b3RlT3JhY2xlAwkBCWlzRGVmaW5lZAEFC3F1b3RlT3JhY2xlBAxxdW90ZU9yYWNsZVYJAQV2YWx1ZQEFC3F1b3RlT3JhY2xlBBJxdW90ZU9yYWNsZUFkZHJlc3MIBQxxdW90ZU9yYWNsZVYCXzEEE2RvVXBkYXRlUXVvdGVPcmFjbGUJAPwHBAUScXVvdGVPcmFjbGVBZGRyZXNzAgp1cGRhdGVEYXRhCQDMCAIJAJEDAgUMcHJpY2VVcGRhdGVzAAEFA25pbAUDbmlsAwkAAAIFE2RvVXBkYXRlUXVvdGVPcmFjbGUFE2RvVXBkYXRlUXVvdGVPcmFjbGUFA25pbAkAAgECJFN0cmljdCB2YWx1ZSBpcyBub3QgZXF1YWwgdG8gaXRzZWxmLgUDbmlsAwkAAAIFE2RvVXBkYXRlUXVvdGVPcmFjbGUFE2RvVXBkYXRlUXVvdGVPcmFjbGUFA25pbAkAAgECJFN0cmljdCB2YWx1ZSBpcyBub3QgZXF1YWwgdG8gaXRzZWxmLgkAAgECJFN0cmljdCB2YWx1ZSBpcyBub3QgZXF1YWwgdG8gaXRzZWxmLgFpARlzeW5jVGVybWluYWxQcmljZVRvT3JhY2xlAAQHX3F0QXN0UgkBBnF0QXN0UgAEB19ic0FzdFIJAQZic0FzdFIABA0kdDA4MjI2NjgyNjMyCQEUZ2V0U3luY1Rlcm1pbmFsUHJpY2UDCQEOZ2V0T3JhY2xlUHJpY2UABQdfcXRBc3RSBQdfYnNBc3RSBBNuZXdRdW90ZUFzc2V0V2VpZ2h0CAUNJHQwODIyNjY4MjYzMgJfMQQSbmV3QmFzZUFzc2V0V2VpZ2h0CAUNJHQwODIyNjY4MjYzMgJfMgQNbWFyZ2luVG9WYXVsdAgFDSR0MDgyMjY2ODI2MzICXzMEEG1hcmdpblRvVmF1bHRBZGoDAwkAZgIAAAUNbWFyZ2luVG9WYXVsdAkAZgIJAQNhYnMBBQ1tYXJnaW5Ub1ZhdWx0CQEIY2JhbGFuY2UABwkBAS0BCQEIY2JhbGFuY2UABQ1tYXJnaW5Ub1ZhdWx0BA1kb0V4Y2hhbmdlUG5MAwkBAiE9AgUQbWFyZ2luVG9WYXVsdEFkagAABA1kb0V4Y2hhbmdlUG5MCQD8BwQJAQx2YXVsdEFkZHJlc3MAAhVleGNoYW5nZUZyZWVBbmRMb2NrZWQJAMwIAgUQbWFyZ2luVG9WYXVsdEFkagUDbmlsBQNuaWwDCQAAAgUNZG9FeGNoYW5nZVBuTAUNZG9FeGNoYW5nZVBuTAUDbmlsCQACAQIkU3RyaWN0IHZhbHVlIGlzIG5vdCBlcXVhbCB0byBpdHNlbGYuBQNuaWwDCQAAAgUNZG9FeGNoYW5nZVBuTAUNZG9FeGNoYW5nZVBuTAkAzggCCQENdXBkYXRlQmFsYW5jZQEJAGQCCQEIY2JhbGFuY2UABRBtYXJnaW5Ub1ZhdWx0QWRqCQEQdXBkYXRlQW1tV2VpZ2h0cwIFE25ld1F1b3RlQXNzZXRXZWlnaHQFEm5ld0Jhc2VBc3NldFdlaWdodAkAAgECJFN0cmljdCB2YWx1ZSBpcyBub3QgZXF1YWwgdG8gaXRzZWxmLgFpARBlbnN1cmVDYWxsZWRPbmNlAAMJAQIhPQIIBQFpBmNhbGxlcgUEdGhpcwkAAgECIkludmFsaWQgc2F2ZUN1cnJlbnRUeElkIHBhcmFtZXRlcnMEBHR4SWQJANgEAQgFAWkNdHJhbnNhY3Rpb25JZAQGbGFzdFR4CQELdmFsdWVPckVsc2UCCQCdCAIFBHRoaXMFCGtfbGFzdFR4AgADCQECIT0CBQZsYXN0VHgFBHR4SWQJAMwIAgkBC1N0cmluZ0VudHJ5AgUIa19sYXN0VHgFBHR4SWQFA25pbAkAAgECKUNhbiBub3QgY2FsbCB2QU1NIG1ldGhvZHMgdHdpY2UgaW4gb25lIHR4AWkBD21pZ3JhdGVQb3NpdGlvbgEHX3RyYWRlcgQPcG9zaXRpb25TaXplT3B0CQCaCAIFBHRoaXMJAQ50b0NvbXBvc2l0ZUtleQIFDmtfcG9zaXRpb25TaXplBQdfdHJhZGVyAwMJAQlpc0RlZmluZWQBBQ9wb3NpdGlvblNpemVPcHQJAQlpc0RlZmluZWQBCQCmCAEFB190cmFkZXIHBAVwU2l6ZQkBEUBleHRyTmF0aXZlKDEwNTApAgUEdGhpcwkBDnRvQ29tcG9zaXRlS2V5AgUOa19wb3NpdGlvblNpemUFB190cmFkZXIEB3BNYXJnaW4JARFAZXh0ck5hdGl2ZSgxMDUwKQIFBHRoaXMJAQ50b0NvbXBvc2l0ZUtleQIFEGtfcG9zaXRpb25NYXJnaW4FB190cmFkZXIECXBOb3Rpb25hbAkBEUBleHRyTmF0aXZlKDEwNTApAgUEdGhpcwkBDnRvQ29tcG9zaXRlS2V5AgUWa19wb3NpdGlvbk9wZW5Ob3Rpb25hbAUHX3RyYWRlcgQJcEZyYWN0aW9uCQERQGV4dHJOYXRpdmUoMTA1MCkCBQR0aGlzCQEOdG9Db21wb3NpdGVLZXkCBS5rX3Bvc2l0aW9uTGFzdFVwZGF0ZWRDdW11bGF0aXZlUHJlbWl1bUZyYWN0aW9uBQdfdHJhZGVyBApwVGltZXN0YW1wCQELdmFsdWVPckVsc2UCCQCaCAIFBHRoaXMJAQ50b0NvbXBvc2l0ZUtleQIFHmtfcG9zaXRpb25MYXN0VXBkYXRlZFRpbWVzdGFtcAUHX3RyYWRlcggFCWxhc3RCbG9jawl0aW1lc3RhbXAEBHBGZWUJAQt2YWx1ZU9yRWxzZQIJAJoIAgUEdGhpcwkBDnRvQ29tcG9zaXRlS2V5AgUNa19wb3NpdGlvbkZlZQUHX3RyYWRlcgkBA2ZlZQAECXBTZXF1ZW5jZQkBEUBleHRyTmF0aXZlKDEwNTApAgUEdGhpcwkBDnRvQ29tcG9zaXRlS2V5AgUSa19wb3NpdGlvblNlcXVlbmNlBQdfdHJhZGVyBApwRGlyZWN0aW9uCQEMZ2V0RGlyZWN0aW9uAQUFcFNpemUEC3Bvc2l0aW9uS2V5CQCsAgIJAKwCAgUHX3RyYWRlcgIBXwkApAMBBQpwRGlyZWN0aW9uCQDMCAIJAQtEZWxldGVFbnRyeQEJAQ50b0NvbXBvc2l0ZUtleQIFDmtfcG9zaXRpb25TaXplBQdfdHJhZGVyCQDMCAIJAQtEZWxldGVFbnRyeQEJAQ50b0NvbXBvc2l0ZUtleQIFEGtfcG9zaXRpb25NYXJnaW4FB190cmFkZXIJAMwIAgkBC0RlbGV0ZUVudHJ5AQkBDnRvQ29tcG9zaXRlS2V5AgUWa19wb3NpdGlvbk9wZW5Ob3Rpb25hbAUHX3RyYWRlcgkAzAgCCQELRGVsZXRlRW50cnkBCQEOdG9Db21wb3NpdGVLZXkCBS5rX3Bvc2l0aW9uTGFzdFVwZGF0ZWRDdW11bGF0aXZlUHJlbWl1bUZyYWN0aW9uBQdfdHJhZGVyCQDMCAIJAQtEZWxldGVFbnRyeQEJAQ50b0NvbXBvc2l0ZUtleQIFHmtfcG9zaXRpb25MYXN0VXBkYXRlZFRpbWVzdGFtcAUHX3RyYWRlcgkAzAgCCQELRGVsZXRlRW50cnkBCQEOdG9Db21wb3NpdGVLZXkCBQ1rX3Bvc2l0aW9uRmVlBQdfdHJhZGVyCQDMCAIJAQtEZWxldGVFbnRyeQEJAQ50b0NvbXBvc2l0ZUtleQIFEmtfcG9zaXRpb25TZXF1ZW5jZQUHX3RyYWRlcgkAzAgCCQEMSW50ZWdlckVudHJ5AgkBDnRvQ29tcG9zaXRlS2V5AgUOa19wb3NpdGlvblNpemUFC3Bvc2l0aW9uS2V5BQVwU2l6ZQkAzAgCCQEMSW50ZWdlckVudHJ5AgkBDnRvQ29tcG9zaXRlS2V5AgUQa19wb3NpdGlvbk1hcmdpbgULcG9zaXRpb25LZXkFB3BNYXJnaW4JAMwIAgkBDEludGVnZXJFbnRyeQIJAQ50b0NvbXBvc2l0ZUtleQIFFmtfcG9zaXRpb25PcGVuTm90aW9uYWwFC3Bvc2l0aW9uS2V5BQlwTm90aW9uYWwJAMwIAgkBDEludGVnZXJFbnRyeQIJAQ50b0NvbXBvc2l0ZUtleQIFLmtfcG9zaXRpb25MYXN0VXBkYXRlZEN1bXVsYXRpdmVQcmVtaXVtRnJhY3Rpb24FC3Bvc2l0aW9uS2V5BQlwRnJhY3Rpb24JAMwIAgkBDEludGVnZXJFbnRyeQIJAQ50b0NvbXBvc2l0ZUtleQIFHmtfcG9zaXRpb25MYXN0VXBkYXRlZFRpbWVzdGFtcAULcG9zaXRpb25LZXkFCnBUaW1lc3RhbXAJAMwIAgkBDEludGVnZXJFbnRyeQIJAQ50b0NvbXBvc2l0ZUtleQIFDWtfcG9zaXRpb25GZWUFC3Bvc2l0aW9uS2V5BQRwRmVlCQDMCAIJAQxJbnRlZ2VyRW50cnkCCQEOdG9Db21wb3NpdGVLZXkCBRJrX3Bvc2l0aW9uU2VxdWVuY2UFC3Bvc2l0aW9uS2V5BQlwU2VxdWVuY2UFA25pbAkAAgEJAKwCAgIXTm90aGluZyB0byBtaWdyYXRlIGZvciAFB190cmFkZXIBaQEndmlld19jYWxjUmVtYWluTWFyZ2luV2l0aEZ1bmRpbmdQYXltZW50AwdfdHJhZGVyCl9kaXJlY3Rpb24MX3ByaWNlVXBkYXRlBAx1cGRhdGVPcmFjbGUJAPwHBAUEdGhpcwIMdXBkYXRlT3JhY2xlCQDMCAIFDF9wcmljZVVwZGF0ZQUDbmlsBQNuaWwDCQAAAgUMdXBkYXRlT3JhY2xlBQx1cGRhdGVPcmFjbGUEBHN5bmMJAPwHBAUEdGhpcwIZc3luY1Rlcm1pbmFsUHJpY2VUb09yYWNsZQUDbmlsBQNuaWwDCQAAAgUEc3luYwUEc3luYwQNJHQwODY0MjY4NjU2MgkBC2dldFBvc2l0aW9uAgUHX3RyYWRlcgUKX2RpcmVjdGlvbgQMcG9zaXRpb25TaXplCAUNJHQwODY0MjY4NjU2MgJfMQQOcG9zaXRpb25NYXJnaW4IBQ0kdDA4NjQyNjg2NTYyAl8yBANwb24IBQ0kdDA4NjQyNjg2NTYyAl8zBBFwb3NpdGlvbkxzdFVwZENQRggFDSR0MDg2NDI2ODY1NjICXzQEEXBvc2l0aW9uVGltZXN0YW1wCAUNJHQwODY0MjY4NjU2MgJfNQQNJHQwODY1NjU4NjY3OAkBI2dldFBvc2l0aW9uTm90aW9uYWxBbmRVbnJlYWxpemVkUG5sAwUHX3RyYWRlcgUKX2RpcmVjdGlvbgUPUE5MX09QVElPTl9TUE9UBBBwb3NpdGlvbk5vdGlvbmFsCAUNJHQwODY1NjU4NjY3OAJfMQQNdW5yZWFsaXplZFBubAgFDSR0MDg2NTY1ODY2NzgCXzIEDSR0MDg2NjgxODY5MDUJATBjYWxjUmVtYWluTWFyZ2luV2l0aEZ1bmRpbmdQYXltZW50QW5kUm9sbG92ZXJGZWUFBQxwb3NpdGlvblNpemUFDnBvc2l0aW9uTWFyZ2luBRFwb3NpdGlvbkxzdFVwZENQRgURcG9zaXRpb25UaW1lc3RhbXAFDXVucmVhbGl6ZWRQbmwEDHJlbWFpbk1hcmdpbggFDSR0MDg2NjgxODY5MDUCXzEEB2JhZERlYnQIBQ0kdDA4NjY4MTg2OTA1Al8yBA5mdW5kaW5nUGF5bWVudAgFDSR0MDg2NjgxODY5MDUCXzMEC3JvbGxvdmVyRmVlCAUNJHQwODY2ODE4NjkwNQJfNAQPdW5kZXJseWluZ1ByaWNlCQEOZ2V0T3JhY2xlUHJpY2UABAlzcG90UHJpY2UJAQxnZXRTcG90UHJpY2UACQACAQkArAICCQCsAgIJAKwCAgkArAICCQCsAgIJAKwCAgkArAICCQCsAgIJAQFzAQUMcmVtYWluTWFyZ2luCQEBcwEFDmZ1bmRpbmdQYXltZW50CQEBcwEJAQ5nZXRNYXJnaW5SYXRpbwIFB190cmFkZXIFCl9kaXJlY3Rpb24JAQFzAQUNdW5yZWFsaXplZFBubAkBAXMBBQdiYWREZWJ0CQEBcwEFEHBvc2l0aW9uTm90aW9uYWwJAQFzAQULcm9sbG92ZXJGZWUJAQFzAQUPdW5kZXJseWluZ1ByaWNlCQEBcwEFCXNwb3RQcmljZQkAAgECJFN0cmljdCB2YWx1ZSBpcyBub3QgZXF1YWwgdG8gaXRzZWxmLgkAAgECJFN0cmljdCB2YWx1ZSBpcyBub3QgZXF1YWwgdG8gaXRzZWxmLgFpARV2aWV3X2dldFBlZ0FkanVzdENvc3QBBl9wcmljZQQHX3F0QXN0UgkBBnF0QXN0UgAEB19ic0FzdFIJAQZic0FzdFIABAZyZXN1bHQJARRnZXRTeW5jVGVybWluYWxQcmljZQMFBl9wcmljZQUHX3F0QXN0UgUHX2JzQXN0UgkAAgEJAKQDAQgFBnJlc3VsdAJfMwFpARh2aWV3X2dldFRlcm1pbmFsQW1tUHJpY2UABA0kdDA4Nzc1ODg3ODM5CQETZ2V0VGVybWluYWxBbW1TdGF0ZQAEGXRlcm1pbmFsUXVvdGVBc3NldFJlc2VydmUIBQ0kdDA4Nzc1ODg3ODM5Al8xBBh0ZXJtaW5hbEJhc2VBc3NldFJlc2VydmUIBQ0kdDA4Nzc1ODg3ODM5Al8yBAVwcmljZQkBBGRpdmQCCQEEbXVsZAIFGXRlcm1pbmFsUXVvdGVBc3NldFJlc2VydmUJAQZxdEFzdFcACQEEbXVsZAIFGHRlcm1pbmFsQmFzZUFzc2V0UmVzZXJ2ZQkBBmJzQXN0VwAJAAIBCQCkAwEFBXByaWNlAWkBD3ZpZXdfZ2V0RnVuZGluZwEMX3ByaWNlVXBkYXRlBAx1cGRhdGVPcmFjbGUJAPwHBAUEdGhpcwIMdXBkYXRlT3JhY2xlCQDMCAIFDF9wcmljZVVwZGF0ZQUDbmlsBQNuaWwDCQAAAgUMdXBkYXRlT3JhY2xlBQx1cGRhdGVPcmFjbGUEBHN5bmMJAPwHBAUEdGhpcwIZc3luY1Rlcm1pbmFsUHJpY2VUb09yYWNsZQUDbmlsBQNuaWwDCQAAAgUEc3luYwUEc3luYwQPdW5kZXJseWluZ1ByaWNlCQEOZ2V0T3JhY2xlUHJpY2UABA0kdDA4ODQ5MTg4NTY5CQEKZ2V0RnVuZGluZwAEFHNob3J0UHJlbWl1bUZyYWN0aW9uCAUNJHQwODg0OTE4ODU2OQJfMQQTbG9uZ1ByZW1pdW1GcmFjdGlvbggFDSR0MDg4NDkxODg1NjkCXzIEDnByZW1pdW1Ub1ZhdWx0CAUNJHQwODg0OTE4ODU2OQJfMwQLbG9uZ0Z1bmRpbmcJAQRkaXZkAgUTbG9uZ1ByZW1pdW1GcmFjdGlvbgUPdW5kZXJseWluZ1ByaWNlBAxzaG9ydEZ1bmRpbmcJAQRkaXZkAgUUc2hvcnRQcmVtaXVtRnJhY3Rpb24FD3VuZGVybHlpbmdQcmljZQkAAgEJAKwCAgkArAICCQCsAgIJAKwCAgkBAXMBBQtsb25nRnVuZGluZwkBAXMBBQxzaG9ydEZ1bmRpbmcJAQFzAQkBDGdldFNwb3RQcmljZQAJAQFzAQkBDmdldE9yYWNsZVByaWNlAAkBAXMBBQ5wcmVtaXVtVG9WYXVsdAkAAgECJFN0cmljdCB2YWx1ZSBpcyBub3QgZXF1YWwgdG8gaXRzZWxmLgkAAgECJFN0cmljdCB2YWx1ZSBpcyBub3QgZXF1YWwgdG8gaXRzZWxmLgFpARBjb21wdXRlU3BvdFByaWNlAAQEc3luYwkA/AcEBQR0aGlzAhlzeW5jVGVybWluYWxQcmljZVRvT3JhY2xlBQNuaWwFA25pbAMJAAACBQRzeW5jBQRzeW5jBAZyZXN1bHQJAQxnZXRTcG90UHJpY2UACQCUCgIFA25pbAUGcmVzdWx0CQACAQIkU3RyaWN0IHZhbHVlIGlzIG5vdCBlcXVhbCB0byBpdHNlbGYuAWkBH2NvbXB1dGVGZWVGb3JUcmFkZXJXaXRoQXJ0aWZhY3QCB190cmFkZXILX2FydGlmYWN0SWQEBnJlc3VsdAkBGGdldEZvclRyYWRlcldpdGhBcnRpZmFjdAIFB190cmFkZXIFC19hcnRpZmFjdElkCQCUCgIFA25pbAUGcmVzdWx0AQJ0eAEGdmVyaWZ5AAQOY29vcmRpbmF0b3JTdHIJAJ0IAgUEdGhpcwUUa19jb29yZGluYXRvckFkZHJlc3MDCQEJaXNEZWZpbmVkAQUOY29vcmRpbmF0b3JTdHIEBWFkbWluCQCdCAIJARFAZXh0ck5hdGl2ZSgxMDYyKQEJAQV2YWx1ZQEFDmNvb3JkaW5hdG9yU3RyBQ9rX2FkbWluX2FkZHJlc3MDCQEJaXNEZWZpbmVkAQUFYWRtaW4JAQt2YWx1ZU9yRWxzZQIJAJsIAgkBEUBleHRyTmF0aXZlKDEwNjIpAQkBBXZhbHVlAQUFYWRtaW4JAKwCAgkArAICCQCsAgICB3N0YXR1c18JAKUIAQUEdGhpcwIBXwkA2AQBCAUCdHgCaWQHCQACAQIudW5hYmxlIHRvIHZlcmlmeTogYWRtaW4gbm90IHNldCBpbiBjb29yZGluYXRvcgkA9AMDCAUCdHgJYm9keUJ5dGVzCQCRAwIIBQJ0eAZwcm9vZnMAAAgFAnR4D3NlbmRlclB1YmxpY0tledwKBzM=", "height": 2661418, "applicationStatus": "succeeded", "spentComplexity": 0 } View: original | compacted Prev: HzqQsJPSYezqyEFqQtgA36AXqfpBBkf8387yytDwbZCg Next: GgvumTPZLgVXh8N8npSy4MZZYsMH3o2H3Hti3QyTdg3r 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, 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 $t01658516755 = updateReserve(_isAdd, quoteAssetAmountAdjusted, amountBaseAssetBoughtAbs)
466466 let quoteAssetReserveAfter1 = $t01658516755._1
467467 let baseAssetReserveAfter1 = $t01658516755._2
468468 let totalPositionSizeAfter1 = $t01658516755._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 $t01942219549 = if ((0 > signedMargin))
497497 then $Tuple2(0, abs(signedMargin))
498498 else $Tuple2(abs(signedMargin), 0)
499499 let remainMargin = $t01942219549._1
500500 let badDebt = $t01942219549._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 $t02081120973 = updateReserve(!(_isAdd), quoteAssetDelta, _baseAssetAmount)
519519 let quoteAssetReserveAfter1 = $t02081120973._1
520520 let baseAssetReserveAfter1 = $t02081120973._2
521521 let totalPositionSizeAfter1 = $t02081120973._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 $t02911429254 = getPosition(_trader, _direction)
662662 let positionSize = $t02911429254._1
663663 let positionMargin = $t02911429254._2
664664 let positionOpenNotional = $t02911429254._3
665665 let positionLstUpdCPF = $t02911429254._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 $t02978629939 = getPosition(_trader, _direction)
675675 let positionSize = $t02978629939._1
676676 let positionMargin = $t02978629939._2
677677 let pon = $t02978629939._3
678678 let positionLastUpdatedCPF = $t02978629939._4
679679 let positionTimestamp = $t02978629939._5
680680 let $t02994530050 = getPositionNotionalAndUnrealizedPnl(_trader, _direction, _option)
681681 let positionNotional = $t02994530050._1
682682 let unrealizedPnl = $t02994530050._2
683683 let $t03005530267 = calcRemainMarginWithFundingPaymentAndRolloverFee(positionSize, positionMargin, positionLastUpdatedCPF, positionTimestamp, unrealizedPnl)
684684 let remainMargin = $t03005530267._1
685685 let badDebt = $t03005530267._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 $t03143031598 = getPosition(_trader, _direction)
707707 let oldPositionSize = $t03143031598._1
708708 let oldPositionMargin = $t03143031598._2
709709 let oldPositionOpenNotional = $t03143031598._3
710710 let oldPositionLstUpdCPF = $t03143031598._4
711711 let oldPositionTimestamp = $t03143031598._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 $t03189032341 = swapOutput((oldPositionSize > 0), _size, _checkMaxPriceImpact)
720720 let exchangedQuoteAssetAmount = $t03189032341._1
721721 let quoteAssetReserveAfter = $t03189032341._2
722722 let baseAssetReserveAfter = $t03189032341._3
723723 let totalPositionSizeAfter = $t03189032341._4
724724 let exchangedPositionSize = if ((oldPositionSize > 0))
725725 then -(_size)
726726 else _size
727727 let $t03255632780 = getPositionNotionalAndUnrealizedPnl(_trader, _direction, PNL_OPTION_SPOT)
728728 let oldPositionNotional = $t03255632780._1
729729 let unrealizedPnl = $t03255632780._2
730730 let realizedRatio = divd(abs(exchangedPositionSize), absOldPositionSize)
731731 let realizedPnl = muld(unrealizedPnl, realizedRatio)
732732 let $t03312133367 = calcRemainMarginWithFundingPaymentAndRolloverFee(oldPositionSize, oldPositionMargin, oldPositionLstUpdCPF, oldPositionTimestamp, unrealizedPnl)
733733 let remainMarginBefore = $t03312133367._1
734734 let x1 = $t03312133367._2
735735 let x2 = $t03312133367._3
736736 let rolloverFee = $t03312133367._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 $t03477335159 = if ((newPositionSize == 0))
745745 then $Tuple2(0, 0)
746746 else $Tuple2(abs(remainOpenNotional), latestCumulativePremiumFraction(newPositionSize))
747747 let newPositionOpenNotional = $t03477335159._1
748748 let newPositionLstUpdCPF = $t03477335159._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 $t03840638585 = swapOutput(direction, abs(_positionSize), false)
792792 let currentNetMarketValue = $t03840638585._1
793793 let terminalQuoteAssetReserve = $t03840638585._2
794794 let terminalBaseAssetReserve = $t03840638585._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 $t04324943744 = 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 = $t04324943744._1
892892 let burnArtifact = $t04324943744._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 $t04409044164 = getAdjustedFee(_artifactId, feeDiscount)
908908 let adjustedFee = $t04409044164._1
909909 let burnArtifact = $t04409044164._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 $t05304953200 = getSyncTerminalPrice(getOraclePrice(), qtAstRAfter, bsAstRAfter)
10641064 let newQuoteAssetWeight = $t05304953200._1
10651065 let newBaseAssetWeight = $t05304953200._2
10661066 let marginToVault = $t05304953200._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 (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 (_minInitMarginRatio > DECIMAL_UNIT))
10921092 then true
10931093 else (_initMarginRatio > _minInitMarginRatio))
10941094 then true
10951095 else (0 >= _mmr))
10961096 then true
10971097 else (0 >= _liquidationFeeRatio))
10981098 then true
10991099 else (0 >= _fee))
11001100 then true
11011101 else (0 >= _spreadLimit))
11021102 then true
11031103 else (0 >= _maxPriceImpact))
11041104 then true
11051105 else (0 >= _partialLiquidationRatio))
11061106 then true
11071107 else (0 >= _maxPriceSpread))
11081108 then true
11091109 else (0 >= _maxOpenNotional))
11101110 then true
11111111 else (0 >= _feeToStakersPercent))
11121112 then true
11131113 else (_feeToStakersPercent > DECIMAL_UNIT))
11141114 then true
11151115 else (0 > _maxOracleDelay))
11161116 then true
11171117 else (0 >= _rolloverFee))
11181118 then true
11191119 else if ((_fundingMode != FUNDING_SYMMETRIC))
11201120 then (_fundingMode != FUNDING_ASYMMETRIC)
11211121 else false)
11221122 then true
11231123 else if ((_oracleMode != ORACLE_PLAIN))
11241124 then (_oracleMode != ORACLE_JIT)
11251125 else false)
11261126 then true
11271127 else if ((_positionMode != POSITION_DIRECT))
11281128 then (_positionMode != POSITION_ORDER)
11291129 else false)
11301130 then true
11311131 else !(initialized()))
11321132 then true
11331133 else (i.caller != adminAddress()))
11341134 then throw("Invalid changeSettings params")
11351135 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)])
11361136
11371137
11381138
11391139 @Callable(i)
11401140 func initialize (_qtAstR,_bsAstR,_fundingPeriod,_initMarginRatio,_mmr,_liquidationFeeRatio,_fee,_baseOracleData,_quoteOracleData,_coordinator,_spreadLimit,_maxPriceImpact,_partialLiquidationRatio,_maxPriceSpread,_maxOpenNotional,_feeToStakersPercent,_maxOracleDelay,_rolloverFee,_fundingMode,_oracleMode,_minInitMarginRatio,_positionMode) = if (if (if (if (if (if (if (if (if (if (if (if (if (if (if (if (if (if (if (if (if (if (if (if (if ((0 >= _qtAstR))
11411141 then true
11421142 else (0 >= _bsAstR))
11431143 then true
11441144 else (0 >= _fundingPeriod))
11451145 then true
11461146 else (0 >= _initMarginRatio))
11471147 then true
11481148 else (_initMarginRatio > DECIMAL_UNIT))
11491149 then true
11501150 else (0 >= _minInitMarginRatio))
11511151 then true
11521152 else (_minInitMarginRatio > DECIMAL_UNIT))
11531153 then true
11541154 else (_initMarginRatio > _minInitMarginRatio))
11551155 then true
11561156 else (0 >= _mmr))
11571157 then true
11581158 else (0 >= _liquidationFeeRatio))
11591159 then true
11601160 else (0 >= _fee))
11611161 then true
11621162 else (0 >= _spreadLimit))
11631163 then true
11641164 else (0 >= _maxPriceImpact))
11651165 then true
11661166 else (0 >= _partialLiquidationRatio))
11671167 then true
11681168 else (0 >= _maxPriceSpread))
11691169 then true
11701170 else (0 >= _maxOpenNotional))
11711171 then true
11721172 else (0 >= _feeToStakersPercent))
11731173 then true
11741174 else (_feeToStakersPercent > DECIMAL_UNIT))
11751175 then true
11761176 else (0 > _maxOracleDelay))
11771177 then true
11781178 else (0 >= _rolloverFee))
11791179 then true
11801180 else if ((_fundingMode != FUNDING_SYMMETRIC))
11811181 then (_fundingMode != FUNDING_ASYMMETRIC)
11821182 else false)
11831183 then true
11841184 else if ((_oracleMode != ORACLE_PLAIN))
11851185 then (_oracleMode != ORACLE_JIT)
11861186 else false)
11871187 then true
11881188 else if ((_positionMode != POSITION_DIRECT))
11891189 then (_positionMode != POSITION_ORDER)
11901190 else false)
11911191 then true
11921192 else initialized())
11931193 then true
11941194 else (i.caller != this))
11951195 then throw("Invalid initialize parameters")
11961196 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)))])
11971197
11981198
11991199
12001200 @Callable(i)
12011201 func increasePosition (_direction,_leverage,_minBaseAssetAmount,_refLink,_priceUpdate) = {
12021202 let updateOracle = invoke(this, "updateOracle", [_priceUpdate], nil)
12031203 if ((updateOracle == updateOracle))
12041204 then {
12051205 let sync = invoke(this, "syncTerminalPriceToOracle", nil, nil)
12061206 if ((sync == sync))
12071207 then {
12081208 let ensureCalledOnce = invoke(this, "ensureCalledOnce", nil, nil)
12091209 if ((ensureCalledOnce == ensureCalledOnce))
12101210 then {
12111211 let _trader = getActualCaller(i)
12121212 let _rawAmount = i.payments[0].amount
12131213 let _assetId = i.payments[0].assetId
12141214 let _assetIdStr = toBase58String(value(_assetId))
12151215 let isQuoteAsset = (_assetId == quoteAsset())
12161216 if (if (if (if (if (if (if (if (if (if (if ((_direction != DIR_LONG))
12171217 then (_direction != DIR_SHORT)
12181218 else false)
12191219 then true
12201220 else (0 >= _rawAmount))
12211221 then true
12221222 else !(initialized()))
12231223 then true
12241224 else !(isQuoteAsset))
12251225 then true
12261226 else !(requireMoreMarginRatio(divd(DECIMAL_UNIT, _leverage), initMarginRatio(), true)))
12271227 then true
12281228 else !(requireMoreMarginRatio(divd(DECIMAL_UNIT, _leverage), minInitMarginRatio(), false)))
12291229 then true
12301230 else !(requireSenderCanWorkWithPositions(i.caller)))
12311231 then true
12321232 else paused())
12331233 then true
12341234 else closeOnly())
12351235 then true
12361236 else isMarketClosed())
12371237 then throw("Invalid increasePosition parameters")
12381238 else {
12391239 let $t06053960688 = getForTraderWithArtifact(_trader, getArtifactId(i))
12401240 let adjustedFee = $t06053960688._1
12411241 let burnArtifact = $t06053960688._2
12421242 let _amount = divd(_rawAmount, (muld(adjustedFee, _leverage) + DECIMAL_UNIT))
12431243 let distributeFeeAmount = (_rawAmount - _amount)
12441244 let referrerFeeAny = invoke(referralAddress(), "acceptPaymentWithLink", [_trader, _refLink], [AttachedPayment(quoteAsset(), distributeFeeAmount)])
12451245 if ((referrerFeeAny == referrerFeeAny))
12461246 then {
12471247 let referrerFee = match referrerFeeAny {
12481248 case x: Int =>
12491249 x
12501250 case _ =>
12511251 throw("Invalid referrerFee")
12521252 }
12531253 let feeAmount = (distributeFeeAmount - referrerFee)
12541254 let $t06118461364 = getPosition(_trader, _direction)
12551255 let oldPositionSize = $t06118461364._1
12561256 let oldPositionMargin = $t06118461364._2
12571257 let oldPositionOpenNotional = $t06118461364._3
12581258 let oldPositionLstUpdCPF = $t06118461364._4
12591259 let oldPositionTimestamp = $t06118461364._5
12601260 let isNewPosition = (oldPositionSize == 0)
12611261 let isSameDirection = if ((oldPositionSize > 0))
12621262 then (_direction == DIR_LONG)
12631263 else (_direction == DIR_SHORT)
12641264 let expandExisting = if (!(isNewPosition))
12651265 then isSameDirection
12661266 else false
12671267 let isAdd = (_direction == DIR_LONG)
12681268 let $t06165364786 = if (if (isNewPosition)
12691269 then true
12701270 else expandExisting)
12711271 then {
12721272 let openNotional = muld(_amount, _leverage)
12731273 let $t06216262335 = swapInput(isAdd, openNotional)
12741274 let amountBaseAssetBought = $t06216262335._1
12751275 let quoteAssetReserveAfter = $t06216262335._2
12761276 let baseAssetReserveAfter = $t06216262335._3
12771277 let totalPositionSizeAfter = $t06216262335._4
12781278 if (if ((_minBaseAssetAmount != 0))
12791279 then (_minBaseAssetAmount > abs(amountBaseAssetBought))
12801280 else false)
12811281 then throw(((("Limit error: " + toString(abs(amountBaseAssetBought))) + " < ") + toString(_minBaseAssetAmount)))
12821282 else {
12831283 let newPositionSize = (oldPositionSize + amountBaseAssetBought)
12841284 let totalLongOpenInterestAfter = (openInterestLong() + (if ((newPositionSize > 0))
12851285 then openNotional
12861286 else 0))
12871287 let totalShortOpenInterestAfter = (openInterestShort() + (if ((0 > newPositionSize))
12881288 then openNotional
12891289 else 0))
12901290 let $t06288163156 = calcRemainMarginWithFundingPaymentAndRolloverFee(oldPositionSize, oldPositionMargin, oldPositionLstUpdCPF, oldPositionTimestamp, _amount)
12911291 let remainMargin = $t06288163156._1
12921292 let x1 = $t06288163156._2
12931293 let x2 = $t06288163156._3
12941294 let rolloverFee = $t06288163156._4
12951295 if (!(requireNotOverSpreadLimit(quoteAssetReserveAfter, baseAssetReserveAfter)))
12961296 then throw("Over max spread limit")
12971297 else if (!(requireNotOverMaxOpenNotional(totalLongOpenInterestAfter, totalShortOpenInterestAfter)))
12981298 then throw("Over max open notional")
12991299 else $Tuple14(newPositionSize, remainMargin, (oldPositionOpenNotional + openNotional), latestCumulativePremiumFraction(newPositionSize), lastTimestamp(), baseAssetReserveAfter, quoteAssetReserveAfter, totalPositionSizeAfter, (openInterestNotional() + openNotional), (totalLongPositionSize() + (if ((newPositionSize > 0))
13001300 then abs(amountBaseAssetBought)
13011301 else 0)), (totalShortPositionSize() + (if ((0 > newPositionSize))
13021302 then abs(amountBaseAssetBought)
13031303 else 0)), totalLongOpenInterestAfter, totalShortOpenInterestAfter, rolloverFee)
13041304 }
13051305 }
13061306 else {
13071307 let openNotional = muld(_amount, _leverage)
13081308 let $t06447464602 = getPositionNotionalAndUnrealizedPnl(toString(i.caller), _direction, PNL_OPTION_SPOT)
13091309 let oldPositionNotional = $t06447464602._1
13101310 let unrealizedPnl = $t06447464602._2
13111311 if ((oldPositionNotional > openNotional))
13121312 then throw("Use decreasePosition to decrease position size")
13131313 else throw("Close position first")
13141314 }
13151315 let newPositionSize = $t06165364786._1
13161316 let newPositionRemainMargin = $t06165364786._2
13171317 let newPositionOpenNotional = $t06165364786._3
13181318 let newPositionLatestCPF = $t06165364786._4
13191319 let newPositionTimestamp = $t06165364786._5
13201320 let baseAssetReserveAfter = $t06165364786._6
13211321 let quoteAssetReserveAfter = $t06165364786._7
13221322 let totalPositionSizeAfter = $t06165364786._8
13231323 let openInterestNotionalAfter = $t06165364786._9
13241324 let totalLongAfter = $t06165364786._10
13251325 let totalShortAfter = $t06165364786._11
13261326 let totalLongOpenInterestAfter = $t06165364786._12
13271327 let totalShortOpenInterestAfter = $t06165364786._13
13281328 let rolloverFee = $t06165364786._14
13291329 let $t06479264863 = distributeFee((feeAmount + rolloverFee))
13301330 let feeToStakers = $t06479264863._1
13311331 let feeToVault = $t06479264863._2
13321332 let stake = if ((_amount >= rolloverFee))
13331333 then invoke(vaultAddress(), "addLocked", nil, [AttachedPayment(quoteAsset(), (_amount - rolloverFee))])
13341334 else invoke(vaultAddress(), "withdrawLocked", [(rolloverFee - _amount)], nil)
13351335 if ((stake == stake))
13361336 then {
13371337 let depositVault = invoke(vaultAddress(), "addFree", nil, [AttachedPayment(quoteAsset(), feeToVault)])
13381338 if ((depositVault == depositVault))
13391339 then {
13401340 let notifyFee = invoke(minerAddress(), "notifyFees", [_trader, feeAmount], nil)
13411341 if ((notifyFee == notifyFee))
13421342 then {
13431343 let notifyNotional = invoke(minerAddress(), "notifyNotional", [_trader, newPositionOpenNotional], nil)
13441344 if ((notifyNotional == notifyNotional))
13451345 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))
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 else throw("Strict value is not equal to itself.")
13531353 }
13541354 else throw("Strict value is not equal to itself.")
13551355 }
13561356 }
13571357 else throw("Strict value is not equal to itself.")
13581358 }
13591359 else throw("Strict value is not equal to itself.")
13601360 }
13611361 else throw("Strict value is not equal to itself.")
13621362 }
13631363
13641364
13651365
13661366 @Callable(i)
13671367 func addMargin (_direction,_priceUpdate) = {
13681368 let updateOracle = invoke(this, "updateOracle", [_priceUpdate], nil)
13691369 if ((updateOracle == updateOracle))
13701370 then {
13711371 let sync = invoke(this, "syncTerminalPriceToOracle", nil, nil)
13721372 if ((sync == sync))
13731373 then {
13741374 let ensureCalledOnce = invoke(this, "ensureCalledOnce", nil, nil)
13751375 if ((ensureCalledOnce == ensureCalledOnce))
13761376 then {
13771377 let _trader = toString(i.caller)
13781378 let _amount = i.payments[0].amount
13791379 let _assetId = i.payments[0].assetId
13801380 let _assetIdStr = toBase58String(value(_assetId))
13811381 let isQuoteAsset = (_assetId == quoteAsset())
13821382 if (if (if (if (if (!(isQuoteAsset))
13831383 then true
13841384 else !(requireOpenPosition(toString(i.caller), _direction)))
13851385 then true
13861386 else !(initialized()))
13871387 then true
13881388 else paused())
13891389 then true
13901390 else isMarketClosed())
13911391 then throw("Invalid addMargin parameters")
13921392 else {
13931393 let $t06720567385 = getPosition(_trader, _direction)
13941394 let oldPositionSize = $t06720567385._1
13951395 let oldPositionMargin = $t06720567385._2
13961396 let oldPositionOpenNotional = $t06720567385._3
13971397 let oldPositionLstUpdCPF = $t06720567385._4
13981398 let oldPositionTimestamp = $t06720567385._5
13991399 let stake = invoke(vaultAddress(), "addLocked", nil, [AttachedPayment(quoteAsset(), _amount)])
14001400 if ((stake == stake))
14011401 then {
14021402 let $t06752567751 = calcRemainMarginWithFundingPaymentAndRolloverFee(oldPositionSize, oldPositionMargin, oldPositionLstUpdCPF, oldPositionTimestamp, _amount)
14031403 let remainMargin = $t06752567751._1
14041404 let badDebt = $t06752567751._2
14051405 let rolloverFee = $t06752567751._3
14061406 let marginRatio = calcMarginRatio(remainMargin, badDebt, oldPositionOpenNotional)
14071407 let checkMinMargin = requireMoreMarginRatio(marginRatio, minInitMarginRatio(), false)
14081408 if ((checkMinMargin == checkMinMargin))
14091409 then {
14101410 let doTransferFeeToStakers = if ((rolloverFee > 0))
14111411 then {
14121412 let $t06800768066 = distributeFee(rolloverFee)
14131413 let feeToStakers = $t06800768066._1
14141414 let feeToVault = $t06800768066._2
14151415 let unstake = invoke(vaultAddress(), "withdrawLocked", [feeToStakers], nil)
14161416 if ((unstake == unstake))
14171417 then {
14181418 let lockBadDebt = invoke(vaultAddress(), "exchangeFreeAndLocked", [-(feeToVault)], nil)
14191419 if ((lockBadDebt == lockBadDebt))
14201420 then transferFee(feeToStakers)
14211421 else throw("Strict value is not equal to itself.")
14221422 }
14231423 else throw("Strict value is not equal to itself.")
14241424 }
14251425 else nil
14261426 if ((doTransferFeeToStakers == doTransferFeeToStakers))
14271427 then ((updatePosition(_trader, oldPositionSize, ((oldPositionMargin - rolloverFee) + _amount), oldPositionOpenNotional, oldPositionLstUpdCPF, lastTimestamp()) ++ updateBalance(((cbalance() + _amount) - rolloverFee))) ++ doTransferFeeToStakers)
14281428 else throw("Strict value is not equal to itself.")
14291429 }
14301430 else throw("Strict value is not equal to itself.")
14311431 }
14321432 else throw("Strict value is not equal to itself.")
14331433 }
14341434 }
14351435 else throw("Strict value is not equal to itself.")
14361436 }
14371437 else throw("Strict value is not equal to itself.")
14381438 }
14391439 else throw("Strict value is not equal to itself.")
14401440 }
14411441
14421442
14431443
14441444 @Callable(i)
14451445 func removeMargin (_amount,_direction,_priceUpdate) = {
14461446 let updateOracle = invoke(this, "updateOracle", [_priceUpdate], nil)
14471447 if ((updateOracle == updateOracle))
14481448 then {
14491449 let sync = invoke(this, "syncTerminalPriceToOracle", nil, nil)
14501450 if ((sync == sync))
14511451 then {
14521452 let ensureCalledOnce = invoke(this, "ensureCalledOnce", nil, nil)
14531453 if ((ensureCalledOnce == ensureCalledOnce))
14541454 then {
14551455 let _trader = toString(i.caller)
14561456 if (if (if (if (if ((0 >= _amount))
14571457 then true
14581458 else !(requireOpenPosition(_trader, _direction)))
14591459 then true
14601460 else !(initialized()))
14611461 then true
14621462 else paused())
14631463 then true
14641464 else isMarketClosed())
14651465 then throw("Invalid removeMargin parameters")
14661466 else {
14671467 let $t06956769747 = getPosition(_trader, _direction)
14681468 let oldPositionSize = $t06956769747._1
14691469 let oldPositionMargin = $t06956769747._2
14701470 let oldPositionOpenNotional = $t06956769747._3
14711471 let oldPositionLstUpdCPF = $t06956769747._4
14721472 let oldPositionTimestamp = $t06956769747._5
14731473 let $t06975370002 = calcRemainMarginWithFundingPaymentAndRolloverFee(oldPositionSize, oldPositionMargin, oldPositionLstUpdCPF, oldPositionTimestamp, -(_amount))
14741474 let remainMargin = $t06975370002._1
14751475 let badDebt = $t06975370002._2
14761476 let fundingPayment = $t06975370002._3
14771477 let rolloverFee = $t06975370002._4
14781478 if ((badDebt != 0))
14791479 then throw("Invalid removed margin amount")
14801480 else {
14811481 let marginRatio = calcMarginRatio(remainMargin, badDebt, oldPositionOpenNotional)
14821482 if (!(requireMoreMarginRatio(marginRatio, initMarginRatio(), true)))
14831483 then throw(((("Too much margin removed: " + toString(marginRatio)) + " < ") + toString(initMarginRatio())))
14841484 else {
14851485 let $t07038870447 = distributeFee(rolloverFee)
14861486 let feeToStakers = $t07038870447._1
14871487 let feeToVault = $t07038870447._2
14881488 let doTransferFeeToStakers = if ((rolloverFee > 0))
14891489 then {
14901490 let lockBadDebt = invoke(vaultAddress(), "exchangeFreeAndLocked", [-(feeToVault)], nil)
14911491 if ((lockBadDebt == lockBadDebt))
14921492 then transferFee(feeToStakers)
14931493 else throw("Strict value is not equal to itself.")
14941494 }
14951495 else nil
14961496 if ((doTransferFeeToStakers == doTransferFeeToStakers))
14971497 then {
14981498 let unstake = invoke(vaultAddress(), "withdrawLocked", [(_amount + feeToStakers)], nil)
14991499 if ((unstake == unstake))
15001500 then (((updatePosition(_trader, oldPositionSize, remainMargin, oldPositionOpenNotional, latestCumulativePremiumFraction(oldPositionSize), lastTimestamp()) ++ withdraw(i.caller, _amount)) ++ updateBalance(((cbalance() - _amount) - rolloverFee))) ++ doTransferFeeToStakers)
15011501 else throw("Strict value is not equal to itself.")
15021502 }
15031503 else throw("Strict value is not equal to itself.")
15041504 }
15051505 }
15061506 }
15071507 }
15081508 else throw("Strict value is not equal to itself.")
15091509 }
15101510 else throw("Strict value is not equal to itself.")
15111511 }
15121512 else throw("Strict value is not equal to itself.")
15131513 }
15141514
15151515
15161516
15171517 @Callable(i)
15181518 func closePosition (_size,_direction,_minQuoteAssetAmount,_addToMargin,_priceUpdate) = {
15191519 let updateOracle = invoke(this, "updateOracle", [_priceUpdate], nil)
15201520 if ((updateOracle == updateOracle))
15211521 then {
15221522 let sync = invoke(this, "syncTerminalPriceToOracle", nil, nil)
15231523 if ((sync == sync))
15241524 then {
15251525 let ensureCalledOnce = invoke(this, "ensureCalledOnce", nil, nil)
15261526 if ((ensureCalledOnce == ensureCalledOnce))
15271527 then {
15281528 let _trader = getActualCaller(i)
15291529 let _traderAddress = valueOrErrorMessage(addressFromString(_trader), "Invalid caller")
15301530 let positionFee = getPositionFee(_trader, _direction)
15311531 if (if (if (if (if (if (!(requireOpenPosition(_trader, _direction)))
15321532 then true
15331533 else !(initialized()))
15341534 then true
15351535 else paused())
15361536 then true
15371537 else (0 >= _size))
15381538 then true
15391539 else (0 > _minQuoteAssetAmount))
15401540 then true
15411541 else isMarketClosed())
15421542 then throw("Invalid closePosition parameters")
15431543 else {
15441544 let oldPositionTimestamp = getPosition(_trader, _direction)._5
15451545 let $t07278273385 = internalClosePosition(_trader, _direction, _size, positionFee, _minQuoteAssetAmount, _addToMargin, true, true)
15461546 let newPositionSize = $t07278273385._1
15471547 let newPositionMargin = $t07278273385._2
15481548 let newPositionOpenNotional = $t07278273385._3
15491549 let newPositionLstUpdCPF = $t07278273385._4
15501550 let positionBadDebt = $t07278273385._5
15511551 let realizedPnl = $t07278273385._6
15521552 let marginToTrader = $t07278273385._7
15531553 let quoteAssetReserveAfter = $t07278273385._8
15541554 let baseAssetReserveAfter = $t07278273385._9
15551555 let totalPositionSizeAfter = $t07278273385._10
15561556 let openInterestNotionalAfter = $t07278273385._11
15571557 let totalLongAfter = $t07278273385._12
15581558 let totalShortAfter = $t07278273385._13
15591559 let totalLongOpenInterestAfter = $t07278273385._14
15601560 let totalShortOpenInterestAfter = $t07278273385._15
15611561 let realizedFee = $t07278273385._16
15621562 if ((positionBadDebt > 0))
15631563 then throw("Invalid closePosition parameters: bad debt")
15641564 else if ((oldPositionTimestamp >= lastTimestamp()))
15651565 then throw("Invalid closePosition parameters: wait at least 1 block before closing the position")
15661566 else {
15671567 let isPartialClose = (newPositionSize != 0)
15681568 let withdrawAmount = (marginToTrader + realizedFee)
15691569 let ammBalance = (cbalance() - withdrawAmount)
15701570 let ammNewBalance = if ((0 > ammBalance))
15711571 then 0
15721572 else ammBalance
15731573 let unstake = invoke(vaultAddress(), "withdrawLocked", [withdrawAmount], nil)
15741574 if ((unstake == unstake))
15751575 then {
15761576 let referrerFeeAny = invoke(referralAddress(), "acceptPayment", [_trader], [AttachedPayment(quoteAsset(), realizedFee)])
15771577 if ((referrerFeeAny == referrerFeeAny))
15781578 then {
15791579 let referrerFee = match referrerFeeAny {
15801580 case x: Int =>
15811581 x
15821582 case _ =>
15831583 throw("Invalid referrerFee")
15841584 }
15851585 let $t07435774430 = distributeFee((realizedFee - referrerFee))
15861586 let feeToStakers = $t07435774430._1
15871587 let feeToVault = $t07435774430._2
15881588 let depositVault = invoke(vaultAddress(), "addFree", nil, [AttachedPayment(quoteAsset(), feeToVault)])
15891589 if ((depositVault == depositVault))
15901590 then {
15911591 let notifyFee = invoke(minerAddress(), "notifyFees", [_trader, realizedFee], nil)
15921592 if ((notifyFee == notifyFee))
15931593 then {
15941594 let notifyNotional = invoke(minerAddress(), "notifyNotional", [_trader, newPositionOpenNotional], nil)
15951595 if ((notifyNotional == notifyNotional))
15961596 then (((((if (isPartialClose)
15971597 then updatePosition(_trader, newPositionSize, newPositionMargin, newPositionOpenNotional, newPositionLstUpdCPF, lastTimestamp())
15981598 else deletePosition(_trader, _direction)) ++ updateAmm(quoteAssetReserveAfter, baseAssetReserveAfter, totalPositionSizeAfter, openInterestNotionalAfter, totalLongAfter, totalShortAfter, totalLongOpenInterestAfter, totalShortOpenInterestAfter)) ++ (if ((marginToTrader > 0))
15991599 then withdraw(_traderAddress, marginToTrader)
16001600 else nil)) ++ updateBalance(ammNewBalance)) ++ transferFee(feeToStakers))
16011601 else throw("Strict value is not equal to itself.")
16021602 }
16031603 else throw("Strict value is not equal to itself.")
16041604 }
16051605 else throw("Strict value is not equal to itself.")
16061606 }
16071607 else throw("Strict value is not equal to itself.")
16081608 }
16091609 else throw("Strict value is not equal to itself.")
16101610 }
16111611 }
16121612 }
16131613 else throw("Strict value is not equal to itself.")
16141614 }
16151615 else throw("Strict value is not equal to itself.")
16161616 }
16171617 else throw("Strict value is not equal to itself.")
16181618 }
16191619
16201620
16211621
16221622 @Callable(i)
16231623 func liquidate (_trader,_direction,_priceUpdate) = {
16241624 let updateOracle = invoke(this, "updateOracle", [_priceUpdate], nil)
16251625 if ((updateOracle == updateOracle))
16261626 then {
16271627 let sync = invoke(this, "syncTerminalPriceToOracle", nil, nil)
16281628 if ((sync == sync))
16291629 then {
16301630 let spotMarginRatio = getMarginRatioByOption(_trader, _direction, PNL_OPTION_SPOT)
16311631 let liquidationMarginRatio = if (isOverFluctuationLimit())
16321632 then {
16331633 let oracleMarginRatio = getMarginRatioByOption(_trader, _direction, PNL_OPTION_ORACLE)
16341634 vmax(spotMarginRatio, oracleMarginRatio)
16351635 }
16361636 else spotMarginRatio
16371637 if (if (if (if (if (!(requireMoreMarginRatio(liquidationMarginRatio, maintenanceMarginRatio(), false)))
16381638 then true
16391639 else !(requireOpenPosition(_trader, _direction)))
16401640 then true
16411641 else !(initialized()))
16421642 then true
16431643 else paused())
16441644 then true
16451645 else isMarketClosed())
16461646 then throw("Unable to liquidate")
16471647 else {
16481648 let oldPositionSize = getPosition(_trader, _direction)._1
16491649 let positionSizeAbs = abs(oldPositionSize)
16501650 let isPartialLiquidation = if (if (if ((spotMarginRatio > liquidationFeeRatio()))
16511651 then (partialLiquidationRatio() > 0)
16521652 else false)
16531653 then (DECIMAL_UNIT > partialLiquidationRatio())
16541654 else false)
16551655 then (muld(positionSizeAbs, getSpotPrice()) > minPartialLiquidationNotional())
16561656 else false
16571657 let $t07710477491 = if (isPartialLiquidation)
16581658 then {
16591659 let liquidationSize = abs(getPartialLiquidationAmount(_trader, oldPositionSize))
16601660 let liquidationRatio = divd(liquidationSize, positionSizeAbs)
16611661 let liquidationNotional = muld(liquidationSize, getSpotPrice())
16621662 $Tuple2(liquidationRatio, liquidationSize)
16631663 }
16641664 else $Tuple2(0, positionSizeAbs)
16651665 let liquidationRatio = $t07710477491._1
16661666 let liquidationSize = $t07710477491._2
16671667 let $t07749778153 = internalClosePosition(_trader, _direction, if (isPartialLiquidation)
16681668 then liquidationSize
16691669 else positionSizeAbs, liquidationFeeRatio(), 0, true, false, true)
16701670 let newPositionSize = $t07749778153._1
16711671 let newPositionMargin = $t07749778153._2
16721672 let newPositionOpenNotional = $t07749778153._3
16731673 let newPositionLstUpdCPF = $t07749778153._4
16741674 let positionBadDebt = $t07749778153._5
16751675 let realizedPnl = $t07749778153._6
16761676 let marginToTrader = $t07749778153._7
16771677 let quoteAssetReserveAfter = $t07749778153._8
16781678 let baseAssetReserveAfter = $t07749778153._9
16791679 let totalPositionSizeAfter = $t07749778153._10
16801680 let openInterestNotionalAfter = $t07749778153._11
16811681 let totalLongAfter = $t07749778153._12
16821682 let totalShortAfter = $t07749778153._13
16831683 let totalLongOpenInterestAfter = $t07749778153._14
16841684 let totalShortOpenInterestAfter = $t07749778153._15
16851685 let liquidationPenalty = $t07749778153._16
16861686 let feeToLiquidator = (liquidationPenalty / 2)
16871687 let feeToVault = (liquidationPenalty - feeToLiquidator)
16881688 let ammBalance = (cbalance() - liquidationPenalty)
16891689 let newAmmBalance = if ((0 > ammBalance))
16901690 then 0
16911691 else ammBalance
16921692 let lockBadDebt = if ((positionBadDebt > 0))
16931693 then {
16941694 let lockBadDebt = invoke(vaultAddress(), "exchangeFreeAndLocked", [(positionBadDebt + liquidationPenalty)], nil)
16951695 if ((lockBadDebt == lockBadDebt))
16961696 then nil
16971697 else throw("Strict value is not equal to itself.")
16981698 }
16991699 else nil
17001700 if ((lockBadDebt == lockBadDebt))
17011701 then {
17021702 let unstake = invoke(vaultAddress(), "withdrawLocked", [liquidationPenalty], nil)
17031703 if ((unstake == unstake))
17041704 then {
17051705 let depositInsurance = invoke(vaultAddress(), "addFree", nil, [AttachedPayment(quoteAsset(), feeToVault)])
17061706 if ((depositInsurance == depositInsurance))
17071707 then {
17081708 let notifyNotional = invoke(minerAddress(), "notifyNotional", [_trader, newPositionOpenNotional], nil)
17091709 if ((notifyNotional == notifyNotional))
17101710 then ((((if (isPartialLiquidation)
17111711 then updatePosition(_trader, newPositionSize, newPositionMargin, newPositionOpenNotional, newPositionLstUpdCPF, lastTimestamp())
17121712 else deletePosition(_trader, _direction)) ++ updateAmm(quoteAssetReserveAfter, baseAssetReserveAfter, totalPositionSizeAfter, openInterestNotionalAfter, totalLongAfter, totalShortAfter, totalLongOpenInterestAfter, totalShortOpenInterestAfter)) ++ withdraw(i.caller, feeToLiquidator)) ++ updateBalance(newAmmBalance))
17131713 else throw("Strict value is not equal to itself.")
17141714 }
17151715 else throw("Strict value is not equal to itself.")
17161716 }
17171717 else throw("Strict value is not equal to itself.")
17181718 }
17191719 else throw("Strict value is not equal to itself.")
17201720 }
17211721 }
17221722 else throw("Strict value is not equal to itself.")
17231723 }
17241724 else throw("Strict value is not equal to itself.")
17251725 }
17261726
17271727
17281728
17291729 @Callable(i)
17301730 func payFunding (_priceUpdate) = {
17311731 let updateOracle = invoke(this, "updateOracle", [_priceUpdate], nil)
17321732 if ((updateOracle == updateOracle))
17331733 then {
17341734 let sync = invoke(this, "syncTerminalPriceToOracle", nil, nil)
17351735 if ((sync == sync))
17361736 then {
17371737 let fundingBlockTimestamp = nextFundingBlockTimestamp()
17381738 if (if (if ((fundingBlockTimestamp > lastTimestamp()))
17391739 then true
17401740 else !(initialized()))
17411741 then true
17421742 else paused())
17431743 then throw(((("Invalid funding block timestamp: " + toString(lastTimestamp())) + " < ") + toString(fundingBlockTimestamp)))
17441744 else {
17451745 let underlyingPrice = getOraclePrice()
17461746 let $t08037180449 = getFunding()
17471747 let shortPremiumFraction = $t08037180449._1
17481748 let longPremiumFraction = $t08037180449._2
17491749 let premiumToVault = $t08037180449._3
17501750 let doPayFundingToVault = if ((premiumToVault > 0))
17511751 then {
17521752 let doPayFundingToVault = invoke(vaultAddress(), "exchangeFreeAndLocked", [-(premiumToVault)], nil)
17531753 if ((doPayFundingToVault == doPayFundingToVault))
17541754 then nil
17551755 else throw("Strict value is not equal to itself.")
17561756 }
17571757 else nil
17581758 if ((doPayFundingToVault == doPayFundingToVault))
17591759 then updateFunding((fundingBlockTimestamp + fundingPeriodSeconds()), (latestLongCumulativePremiumFraction() + longPremiumFraction), (latestShortCumulativePremiumFraction() + shortPremiumFraction), divd(longPremiumFraction, underlyingPrice), divd(shortPremiumFraction, underlyingPrice))
17601760 else throw("Strict value is not equal to itself.")
17611761 }
17621762 }
17631763 else throw("Strict value is not equal to itself.")
17641764 }
17651765 else throw("Strict value is not equal to itself.")
17661766 }
17671767
17681768
17691769
17701770 @Callable(i)
17711771 func updateOracle (_priceUpdate) = if ((oracleMode() == ORACLE_PLAIN))
17721772 then nil
17731773 else {
17741774 let priceUpdates = split_4C(_priceUpdate, "::")
17751775 let baseOracle = valueOrErrorMessage(getOracleData(k_baseOracle), "No base asset oracle data")
17761776 let baseOracleAddress = baseOracle._1
17771777 let doUpdateBaseOracle = invoke(baseOracleAddress, "updateData", [priceUpdates[0]], nil)
17781778 if ((doUpdateBaseOracle == doUpdateBaseOracle))
17791779 then {
17801780 let quoteOracle = getOracleData(k_quoteOracle)
17811781 let doUpdateQuoteOracle = if (isDefined(quoteOracle))
17821782 then {
17831783 let quoteOracleV = value(quoteOracle)
17841784 let quoteOracleAddress = quoteOracleV._1
17851785 let doUpdateQuoteOracle = invoke(quoteOracleAddress, "updateData", [priceUpdates[1]], nil)
17861786 if ((doUpdateQuoteOracle == doUpdateQuoteOracle))
17871787 then nil
17881788 else throw("Strict value is not equal to itself.")
17891789 }
17901790 else nil
17911791 if ((doUpdateQuoteOracle == doUpdateQuoteOracle))
17921792 then nil
17931793 else throw("Strict value is not equal to itself.")
17941794 }
17951795 else throw("Strict value is not equal to itself.")
17961796 }
17971797
17981798
17991799
18001800 @Callable(i)
18011801 func syncTerminalPriceToOracle () = {
18021802 let _qtAstR = qtAstR()
18031803 let _bsAstR = bsAstR()
18041804 let $t08226682632 = getSyncTerminalPrice(getOraclePrice(), _qtAstR, _bsAstR)
18051805 let newQuoteAssetWeight = $t08226682632._1
18061806 let newBaseAssetWeight = $t08226682632._2
18071807 let marginToVault = $t08226682632._3
18081808 let marginToVaultAdj = if (if ((0 > marginToVault))
18091809 then (abs(marginToVault) > cbalance())
18101810 else false)
18111811 then -(cbalance())
18121812 else marginToVault
18131813 let doExchangePnL = if ((marginToVaultAdj != 0))
18141814 then {
18151815 let doExchangePnL = invoke(vaultAddress(), "exchangeFreeAndLocked", [marginToVaultAdj], nil)
18161816 if ((doExchangePnL == doExchangePnL))
18171817 then nil
18181818 else throw("Strict value is not equal to itself.")
18191819 }
18201820 else nil
18211821 if ((doExchangePnL == doExchangePnL))
18221822 then (updateBalance((cbalance() + marginToVaultAdj)) ++ updateAmmWeights(newQuoteAssetWeight, newBaseAssetWeight))
18231823 else throw("Strict value is not equal to itself.")
18241824 }
18251825
18261826
18271827
18281828 @Callable(i)
18291829 func ensureCalledOnce () = if ((i.caller != this))
18301830 then throw("Invalid saveCurrentTxId parameters")
18311831 else {
18321832 let txId = toBase58String(i.transactionId)
18331833 let lastTx = valueOrElse(getString(this, k_lastTx), "")
18341834 if ((lastTx != txId))
18351835 then [StringEntry(k_lastTx, txId)]
18361836 else throw("Can not call vAMM methods twice in one tx")
18371837 }
18381838
18391839
18401840
18411841 @Callable(i)
18421842 func migratePosition (_trader) = {
18431843 let positionSizeOpt = getInteger(this, toCompositeKey(k_positionSize, _trader))
18441844 if (if (isDefined(positionSizeOpt))
18451845 then isDefined(addressFromString(_trader))
18461846 else false)
18471847 then {
18481848 let pSize = getIntegerValue(this, toCompositeKey(k_positionSize, _trader))
18491849 let pMargin = getIntegerValue(this, toCompositeKey(k_positionMargin, _trader))
18501850 let pNotional = getIntegerValue(this, toCompositeKey(k_positionOpenNotional, _trader))
18511851 let pFraction = getIntegerValue(this, toCompositeKey(k_positionLastUpdatedCumulativePremiumFraction, _trader))
18521852 let pTimestamp = valueOrElse(getInteger(this, toCompositeKey(k_positionLastUpdatedTimestamp, _trader)), lastBlock.timestamp)
18531853 let pFee = valueOrElse(getInteger(this, toCompositeKey(k_positionFee, _trader)), fee())
18541854 let pSequence = getIntegerValue(this, toCompositeKey(k_positionSequence, _trader))
18551855 let pDirection = getDirection(pSize)
18561856 let positionKey = ((_trader + "_") + toString(pDirection))
18571857 [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)]
18581858 }
18591859 else throw(("Nothing to migrate for " + _trader))
18601860 }
18611861
18621862
18631863
18641864 @Callable(i)
18651865 func view_calcRemainMarginWithFundingPayment (_trader,_direction,_priceUpdate) = {
18661866 let updateOracle = invoke(this, "updateOracle", [_priceUpdate], nil)
18671867 if ((updateOracle == updateOracle))
18681868 then {
18691869 let sync = invoke(this, "syncTerminalPriceToOracle", nil, nil)
18701870 if ((sync == sync))
18711871 then {
18721872 let $t08642686562 = getPosition(_trader, _direction)
18731873 let positionSize = $t08642686562._1
18741874 let positionMargin = $t08642686562._2
18751875 let pon = $t08642686562._3
18761876 let positionLstUpdCPF = $t08642686562._4
18771877 let positionTimestamp = $t08642686562._5
18781878 let $t08656586678 = getPositionNotionalAndUnrealizedPnl(_trader, _direction, PNL_OPTION_SPOT)
18791879 let positionNotional = $t08656586678._1
18801880 let unrealizedPnl = $t08656586678._2
18811881 let $t08668186905 = calcRemainMarginWithFundingPaymentAndRolloverFee(positionSize, positionMargin, positionLstUpdCPF, positionTimestamp, unrealizedPnl)
18821882 let remainMargin = $t08668186905._1
18831883 let badDebt = $t08668186905._2
18841884 let fundingPayment = $t08668186905._3
18851885 let rolloverFee = $t08668186905._4
18861886 let underlyingPrice = getOraclePrice()
18871887 let spotPrice = getSpotPrice()
18881888 throw(((((((((s(remainMargin) + s(fundingPayment)) + s(getMarginRatio(_trader, _direction))) + s(unrealizedPnl)) + s(badDebt)) + s(positionNotional)) + s(rolloverFee)) + s(underlyingPrice)) + s(spotPrice)))
18891889 }
18901890 else throw("Strict value is not equal to itself.")
18911891 }
18921892 else throw("Strict value is not equal to itself.")
18931893 }
18941894
18951895
18961896
18971897 @Callable(i)
18981898 func view_getPegAdjustCost (_price) = {
18991899 let _qtAstR = qtAstR()
19001900 let _bsAstR = bsAstR()
19011901 let result = getSyncTerminalPrice(_price, _qtAstR, _bsAstR)
19021902 throw(toString(result._3))
19031903 }
19041904
19051905
19061906
19071907 @Callable(i)
19081908 func view_getTerminalAmmPrice () = {
19091909 let $t08775887839 = getTerminalAmmState()
19101910 let terminalQuoteAssetReserve = $t08775887839._1
19111911 let terminalBaseAssetReserve = $t08775887839._2
19121912 let price = divd(muld(terminalQuoteAssetReserve, qtAstW()), muld(terminalBaseAssetReserve, bsAstW()))
19131913 throw(toString(price))
19141914 }
19151915
19161916
19171917
19181918 @Callable(i)
19191919 func view_getFunding (_priceUpdate) = {
19201920 let updateOracle = invoke(this, "updateOracle", [_priceUpdate], nil)
19211921 if ((updateOracle == updateOracle))
19221922 then {
19231923 let sync = invoke(this, "syncTerminalPriceToOracle", nil, nil)
19241924 if ((sync == sync))
19251925 then {
19261926 let underlyingPrice = getOraclePrice()
19271927 let $t08849188569 = getFunding()
19281928 let shortPremiumFraction = $t08849188569._1
19291929 let longPremiumFraction = $t08849188569._2
19301930 let premiumToVault = $t08849188569._3
19311931 let longFunding = divd(longPremiumFraction, underlyingPrice)
19321932 let shortFunding = divd(shortPremiumFraction, underlyingPrice)
19331933 throw(((((s(longFunding) + s(shortFunding)) + s(getSpotPrice())) + s(getOraclePrice())) + s(premiumToVault)))
19341934 }
19351935 else throw("Strict value is not equal to itself.")
19361936 }
19371937 else throw("Strict value is not equal to itself.")
19381938 }
19391939
19401940
19411941
19421942 @Callable(i)
19431943 func computeSpotPrice () = {
19441944 let sync = invoke(this, "syncTerminalPriceToOracle", nil, nil)
19451945 if ((sync == sync))
19461946 then {
19471947 let result = getSpotPrice()
19481948 $Tuple2(nil, result)
19491949 }
19501950 else throw("Strict value is not equal to itself.")
19511951 }
19521952
19531953
19541954
19551955 @Callable(i)
19561956 func computeFeeForTraderWithArtifact (_trader,_artifactId) = {
19571957 let result = getForTraderWithArtifact(_trader, _artifactId)
19581958 $Tuple2(nil, result)
19591959 }
19601960
19611961
19621962 @Verifier(tx)
19631963 func verify () = {
19641964 let coordinatorStr = getString(this, k_coordinatorAddress)
19651965 if (isDefined(coordinatorStr))
19661966 then {
19671967 let admin = getString(addressFromStringValue(value(coordinatorStr)), k_admin_address)
19681968 if (isDefined(admin))
19691969 then valueOrElse(getBoolean(addressFromStringValue(value(admin)), ((("status_" + toString(this)) + "_") + toBase58String(tx.id))), false)
19701970 else throw("unable to verify: admin not set in coordinator")
19711971 }
19721972 else sigVerify(tx.bodyBytes, tx.proofs[0], tx.senderPublicKey)
19731973 }
19741974

github/deemru/w8io/873ac7e 
314.16 ms