tx · 9LgLQwqZRj1mnoLCLEPjiZMfAG8BBExSLkAhZgPy76RY

3MJFg4EuxAmRL9yHhz4fq9YJyFWqMjKphvp:  -0.06000000 Waves

2026.07.14 19:33 [932541] smart account 3MJFg4EuxAmRL9yHhz4fq9YJyFWqMjKphvp > SELF 0.00000000 Waves

{ "type": 13, "id": "9LgLQwqZRj1mnoLCLEPjiZMfAG8BBExSLkAhZgPy76RY", "fee": 6000000, "feeAssetId": null, "timestamp": 1784046790966, "version": 2, "chainId": 82, "sender": "3MJFg4EuxAmRL9yHhz4fq9YJyFWqMjKphvp", "senderPublicKey": "HAbEJCcJneQZB5H4zjkiD3Nm2QajoAZdfQtwM7v9yi3D", "proofs": [ "MNq9Go7hyrwuSuddQKAaMZFjmzfgqetx6wAzaNYzES9xmrSUkcSDjeJDLocp7bNSn8wmt1DByKWcoeRYQmbBbBH" ], "script": "base64:BgKqAQgCEgASBAoCCAESBAoCCAESABIDCgEIEgQKAggBEgMKAQgSBAoCCAESBAoCCAESABIGCgQICAgIEgYKBAgICAgSBAoCCAgSBAoCCAgSAwoBCBIDCgEIEgMKAQgSAwoBCBIDCgEEEggKBgQIAQgICBIFCgMECAgSBgoEBAgECBIDCgEEEgQKAggEEgQKAggEEgMKAQQSAwoBBBIDCgEIEgMKAQgSAwoBCBIALQANQ09OVFJBQ1RfVFlQRQIOTEVORC1MUC1NQVJLRVQAB1ZFUlNJT04CCVBMUC0xLjMuMgETZ2V0QWRkcmVzc0Zyb21TdGF0ZQEDa2V5CQELdmFsdWVPckVsc2UCCQCmCAEJAQt2YWx1ZU9yRWxzZQIJAJ0IAgUEdGhpcwkArAICAg5zZXR1cF9hZGRyZXNzXwUDa2V5AiMzUEV3UmNZTkFVdG9GdktwQmhLb2l3YWpuWmZkb0RSNmg0aAkBB0FkZHJlc3MBARoBV46zaotfT5rTy6/BBdbIYhwwXDI85kwhvgEVZ2V0QWRkcmVzc2VzRnJvbVN0YXRlAQNrZXkKAQFmAgVhY2N1bQRuZXh0CQDOCAIFBWFjY3VtCQDMCAIJAQt2YWx1ZU9yRWxzZQIJAKYIAQUEbmV4dAkBB0FkZHJlc3MBARoBV46zaotfT5rTy6/BBdbIYhwwXDI85kwhvgUDbmlsCgACJGwJALwJAgkBC3ZhbHVlT3JFbHNlAgkAnQgCBQR0aGlzCQCsAgICDnNldHVwX2FkZHJlc3NfBQNrZXkCIzNQRXdSY1lOQVV0b0Z2S3BCaEtvaXdham5aZmRvRFI2aDRoAgEsCgACJHMJAJADAQUCJGwKAAUkYWNjMAUDbmlsCgEFJGYwXzECAiRhAiRpAwkAZwIFAiRpBQIkcwUCJGEJAQFmAgUCJGEJAJEDAgUCJGwFAiRpCgEFJGYwXzICAiRhAiRpAwkAZwIFAiRpBQIkcwUCJGEJAAIBAhRMaXN0IHNpemUgZXhjZWVkcyAxNQkBBSRmMF8yAgkBBSRmMF8xAgkBBSRmMF8xAgkBBSRmMF8xAgkBBSRmMF8xAgkBBSRmMF8xAgkBBSRmMF8xAgkBBSRmMF8xAgkBBSRmMF8xAgkBBSRmMF8xAgkBBSRmMF8xAgkBBSRmMF8xAgkBBSRmMF8xAgkBBSRmMF8xAgkBBSRmMF8xAgkBBSRmMF8xAgUFJGFjYzAAAAABAAIAAwAEAAUABgAHAAgACQAKAAsADAANAA4ADwAScmVzZXJ2ZUZ1bmRBZGRyZXNzCQETZ2V0QWRkcmVzc0Zyb21TdGF0ZQECC3Jlc2VydmVGdW5kAA1vcmFjbGVBZGRyZXNzCQETZ2V0QWRkcmVzc0Zyb21TdGF0ZQECBm9yYWNsZQARYWdncmVnYXRvckFkZHJlc3MJARNnZXRBZGRyZXNzRnJvbVN0YXRlAQIKYWdncmVnYXRvcgAMYWRtaW5BZGRyZXNzCQETZ2V0QWRkcmVzc0Zyb21TdGF0ZQECBWFkbWluABFzdGFibGVGdW5kQWRkcmVzcwkBE2dldEFkZHJlc3NGcm9tU3RhdGUBAgpzdGFibGVGdW5kABZmZWVDb2xsZWN0b3JBZGRyZXNzU3RyCQCdCAIFBHRoaXMCGnNldHVwX2FkZHJlc3NfZmVlQ29sbGVjdG9yABFzaHV0ZG93bldoaXRlbGlzdAkBFWdldEFkZHJlc3Nlc0Zyb21TdGF0ZQECD3NodXRkb3duQ2FsbGVycwAUbGlxdWlkYXRvcnNXaGl0ZWxpc3QJARVnZXRBZGRyZXNzZXNGcm9tU3RhdGUBAgtsaXF1aWRhdG9ycwEWdmVyaWZ5TGlxdWlkYXRvclJpZ2h0cwEHYWRkcmVzcwkBAiE9AgkAzwgCBRRsaXF1aWRhdG9yc1doaXRlbGlzdAUHYWRkcmVzcwUEdW5pdAALcmVzZXJ2ZUZ1bmQJAJcDAQkAzAgCCQCWAwEJAMwIAgkBC3ZhbHVlT3JFbHNlAgkAmggCBQR0aGlzAhRzZXR1cF9yZXNlcnZlRnVuZEZlZQAUCQDMCAIAAAUDbmlsCQDMCAIAZAUDbmlsAAxzdGFibGVzSWRTdHIJALUJAgkBC3ZhbHVlT3JFbHNlAgkAnQgCBQR0aGlzAhBzZXR1cF9zdGFibGVzSWRzAlk5d2MzTFhOQTRURUJzWHlLdG9MRTltcmJERDdXTUhYdlhyQ2padmFiTEFzaSxIR2dhYlRxVVM4V3RWRlVKemZtclRETWdFY2NKdVpMQlBoRmdRRnh2bnNvVwIBLAEMZ2V0UmF0ZUN1cnZlAQphc3NldElkU3RyBA5jdXJ2ZVJhdGVTdHJMaQkAtQkCCQELdmFsdWVPckVsc2UCCQCdCAIFBHRoaXMJAKwCAgIQc2V0dXBfcmF0ZUN1cnZlXwUKYXNzZXRJZFN0cgIlMjAwMDAwMDAsMTAwMDAwMDAwLDYwMDAwMDAwLDQwMDAwMDAwMAIBLAkAlgoECQENcGFyc2VJbnRWYWx1ZQEJAJEDAgUOY3VydmVSYXRlU3RyTGkAAAkBDXBhcnNlSW50VmFsdWUBCQCRAwIFDmN1cnZlUmF0ZVN0ckxpAAEJAQ1wYXJzZUludFZhbHVlAQkAkQMCBQ5jdXJ2ZVJhdGVTdHJMaQACCQENcGFyc2VJbnRWYWx1ZQEJAJEDAgUOY3VydmVSYXRlU3RyTGkAAwETZ2V0UmV3YXJkc1NwbGl0dGluZwEKYXNzZXRJZFN0cgQVcmV3YXJkc1NwbGl0dGluZ1N0ckxpCQC1CQIJAQt2YWx1ZU9yRWxzZQIJAJ0IAgUEdGhpcwkArAICAhdzZXR1cF9yZXdhcmRzU3BsaXR0aW5nXwUKYXNzZXRJZFN0cgIIMzAsNTAsMjACASwJAJUKAwkBDXBhcnNlSW50VmFsdWUBCQCRAwIFFXJld2FyZHNTcGxpdHRpbmdTdHJMaQAACQENcGFyc2VJbnRWYWx1ZQEJAJEDAgUVcmV3YXJkc1NwbGl0dGluZ1N0ckxpAAEJAQ1wYXJzZUludFZhbHVlAQkAkQMCBRVyZXdhcmRzU3BsaXR0aW5nU3RyTGkAAgAJc2VudGluZWxzCQDMCAIJAQdBZGRyZXNzAQEaAVfX4SNRjnyriFrV1yiXddiIddOPriMFpuEJAMwIAgkBB0FkZHJlc3MBARoBV/j6+gImwFGL7Go7RjNJ0hxxsHWL+aTKmgkAzAgCCQEHQWRkcmVzcwEBGgFXSQEY9kN/P0xs4Wd15bfkly/eUC2yg93xCQDMCAIJAQdBZGRyZXNzAQEaAVdLw2zO+zNYQ1hDURDu7+4hEBdL8njLfDIFA25pbAAGU2NhbGU4AIDC1y8AB1NjYWxlMTAAgMivoCUAB1NjYWxlMTYJAGgCBQZTY2FsZTgFBlNjYWxlOAAJZGF5QmxvY2tzAKALABV3aXRoZHJhd2FsTGltaXRCbG9ja3MJAQt2YWx1ZU9yRWxzZQIJAJoIAgUEdGhpcwIbc2V0dXBfd2l0aGRyYXdhbExpbWl0QmxvY2tzAGQBDXRyeUdldEludGVnZXIBA2tleQQHJG1hdGNoMAkAmggCBQR0aGlzBQNrZXkDCQABAgUHJG1hdGNoMAIDSW50BAFiBQckbWF0Y2gwBQFiAAABDXRyeUdldEJvb2xlYW4BA2tleQQHJG1hdGNoMAkAmwgCBQR0aGlzBQNrZXkDCQABAgUHJG1hdGNoMAIHQm9vbGVhbgQBYgUHJG1hdGNoMAUBYgcBDHRyeUdldFN0cmluZwEDa2V5BAckbWF0Y2gwCQCdCAIFBHRoaXMFA2tleQMJAAECBQckbWF0Y2gwAgZTdHJpbmcEAWIFByRtYXRjaDAFAWICAAEMdHJ5R2V0QmluYXJ5AQNrZXkEByRtYXRjaDAJAJwIAgUEdGhpcwUDa2V5AwkAAQIFByRtYXRjaDACCkJ5dGVWZWN0b3IEAWIFByRtYXRjaDAFAWIBAAEOZ2V0QXNzZXRTdHJpbmcBB2Fzc2V0SWQEByRtYXRjaDAFB2Fzc2V0SWQDCQABAgUHJG1hdGNoMAIKQnl0ZVZlY3RvcgQBYgUHJG1hdGNoMAkA2AQBBQFiAgVXQVZFUwENZ2V0QXNzZXRCeXRlcwEKYXNzZXRJZFN0cgMJAAACBQphc3NldElkU3RyAgVXQVZFUwUEdW5pdAkA2QQBBQphc3NldElkU3RyAQpnZXRCYWxhbmNlAQphc3NldElkU3RyAwkAAAIFCmFzc2V0SWRTdHICBVdBVkVTCAkA7wcBBQR0aGlzCWF2YWlsYWJsZQkA8AcCBQR0aGlzCQDZBAEFCmFzc2V0SWRTdHIBD2dldE1hcmtldEFzc2V0cwAJALUJAgkBDHRyeUdldFN0cmluZwECDHNldHVwX3Rva2VucwIBLAENZ2V0T3V0ZGF0ZWRVcgEKYXNzZXRJZFN0cgQEZG93bgkAawMJAQ10cnlHZXRJbnRlZ2VyAQkArAICAg90b3RhbF9zdXBwbGllZF8FCmFzc2V0SWRTdHIJAQ10cnlHZXRJbnRlZ2VyAQkArAICBQphc3NldElkU3RyAgZfc1JhdGUFB1NjYWxlMTYDCQAAAgUEZG93bgAAAAAJAGsDBQZTY2FsZTgJAGsDCQENdHJ5R2V0SW50ZWdlcgEJAKwCAgIPdG90YWxfYm9ycm93ZWRfBQphc3NldElkU3RyCQENdHJ5R2V0SW50ZWdlcgEJAKwCAgUKYXNzZXRJZFN0cgIGX2JSYXRlBQdTY2FsZTE2BQRkb3duAQtnZXRJbnRlcmVzdAEKYXNzZXRJZFN0cgQCdXIJAQ1nZXRPdXRkYXRlZFVyAQUKYXNzZXRJZFN0cgQFY3VydmUJAQxnZXRSYXRlQ3VydmUBBQphc3NldElkU3RyBARyYXRlCQBkAggFBWN1cnZlAl8xAwkAZwIIBQVjdXJ2ZQJfMwUCdXIJAGsDBQJ1cggFBWN1cnZlAl8yCAUFY3VydmUCXzMJAGQCCAUFY3VydmUCXzIJAGsDCQBlAgUCdXIIBQVjdXJ2ZQJfMwgFBWN1cnZlAl80CQBlAgCAwtcvCAUFY3VydmUCXzMJAJYDAQkAzAgCCQBrAwUEcmF0ZQUGU2NhbGU4CQBoAgUJZGF5QmxvY2tzAO0CCQDMCAIAAQUDbmlsARB0b2tlblJhdGVzUmVjYWxjAQphc3NldElkU3RyBAhpbnRlcmVzdAkBC2dldEludGVyZXN0AQUKYXNzZXRJZFN0cgQCdXIJAQ1nZXRPdXRkYXRlZFVyAQUKYXNzZXRJZFN0cgQQbGFzdFJlY2FsY0hlaWdodAkBDXRyeUdldEludGVnZXIBAg5sYXN0UmF0ZUhlaWdodAQJbGFzdEJSYXRlCQCWAwEJAMwIAgkBDXRyeUdldEludGVnZXIBCQCsAgIFCmFzc2V0SWRTdHICBl9iUmF0ZQkAzAgCBQdTY2FsZTE2BQNuaWwECG5ld0JSYXRlCQBkAgUJbGFzdEJSYXRlCQBoAgkAZQIFBmhlaWdodAUQbGFzdFJlY2FsY0hlaWdodAUIaW50ZXJlc3QECWxhc3RTUmF0ZQkAlgMBCQDMCAIJAQ10cnlHZXRJbnRlZ2VyAQkArAICBQphc3NldElkU3RyAgZfc1JhdGUJAMwIAgUHU2NhbGUxNgUDbmlsBAhuZXdTUmF0ZQkAZAIFCWxhc3RTUmF0ZQkAawMJAGkCCQBoAgkAaAIJAGUCBQZoZWlnaHQFEGxhc3RSZWNhbGNIZWlnaHQJAGsDBQhpbnRlcmVzdAUCdXIFBlNjYWxlOAkAZQIAZAULcmVzZXJ2ZUZ1bmQAZAUJbGFzdFNSYXRlBQlsYXN0QlJhdGUJAMwIAgkBDEludGVnZXJFbnRyeQIJAKwCAgUKYXNzZXRJZFN0cgIGX3NSYXRlBQhuZXdTUmF0ZQkAzAgCCQEMSW50ZWdlckVudHJ5AgkArAICBQphc3NldElkU3RyAgZfYlJhdGUFCG5ld0JSYXRlCQDMCAIJAQxJbnRlZ2VyRW50cnkCAg5sYXN0UmF0ZUhlaWdodAUGaGVpZ2h0BQNuaWwBDWdldEFjdHVhbFJhdGUCCmFzc2V0SWRTdHIIcmF0ZVR5cGUKAQFmAgVhY2N1bQV0b2tlbgQGcmVjYWxjCQEQdG9rZW5SYXRlc1JlY2FsYwEFBXRva2VuBAlsYXN0QlJhdGUJAJYDAQkAzAgCCQENdHJ5R2V0SW50ZWdlcgEJAKwCAgUFdG9rZW4CBl9iUmF0ZQkAzAgCBQdTY2FsZTE2BQNuaWwECGZlZURlbHRhCQBrAwULcmVzZXJ2ZUZ1bmQJAGsDCQENdHJ5R2V0SW50ZWdlcgEJAKwCAgIPdG90YWxfYm9ycm93ZWRfBQV0b2tlbgkAZQIICQCRAwIFBnJlY2FsYwABBXZhbHVlBQlsYXN0QlJhdGUFB1NjYWxlMTYAZAQIZmVlRW50cnkJAQxJbnRlZ2VyRW50cnkCCQCsAgIJAKwCAgIEZmVlXwUFdG9rZW4CCV9pbnRlcmVzdAkAZAIJAQ10cnlHZXRJbnRlZ2VyAQkArAICCQCsAgICBGZlZV8FBXRva2VuAglfaW50ZXJlc3QFCGZlZURlbHRhCQCVCgMDCQECIT0CBQV0b2tlbgUKYXNzZXRJZFN0cggFBWFjY3VtAl8xAwkAAAIFCHJhdGVUeXBlAgVzUmF0ZQgJAJEDAgUGcmVjYWxjAAAFdmFsdWUICQCRAwIFBnJlY2FsYwABBXZhbHVlCQDOCAIIBQVhY2N1bQJfMgUGcmVjYWxjCQDOCAIIBQVhY2N1bQJfMwkAzAgCBQhmZWVFbnRyeQUDbmlsBAFyCgACJGwJAQ9nZXRNYXJrZXRBc3NldHMACgACJHMJAJADAQUCJGwKAAUkYWNjMAkAlQoDAAAFA25pbAUDbmlsCgEFJGYwXzECAiRhAiRpAwkAZwIFAiRpBQIkcwUCJGEJAQFmAgUCJGEJAJEDAgUCJGwFAiRpCgEFJGYwXzICAiRhAiRpAwkAZwIFAiRpBQIkcwUCJGEJAAIBAhRMaXN0IHNpemUgZXhjZWVkcyAxMgkBBSRmMF8yAgkBBSRmMF8xAgkBBSRmMF8xAgkBBSRmMF8xAgkBBSRmMF8xAgkBBSRmMF8xAgkBBSRmMF8xAgkBBSRmMF8xAgkBBSRmMF8xAgkBBSRmMF8xAgkBBSRmMF8xAgkBBSRmMF8xAgkBBSRmMF8xAgUFJGFjYzAAAAABAAIAAwAEAAUABgAHAAgACQAKAAsADAkAlAoCCAUBcgJfMQkAzggCCAUBcgJfMggFAXICXzMBBWdldFVyAQphc3NldElkU3RyBAVyYXRlcwkBEHRva2VuUmF0ZXNSZWNhbGMBBQphc3NldElkU3RyBARkb3duCQBrAwkBDXRyeUdldEludGVnZXIBCQCsAgICD3RvdGFsX3N1cHBsaWVkXwUKYXNzZXRJZFN0cggJAJEDAgUFcmF0ZXMAAAV2YWx1ZQUHU2NhbGUxNgkAawMFBlNjYWxlOAkAawMJAQ10cnlHZXRJbnRlZ2VyAQkArAICAg90b3RhbF9ib3Jyb3dlZF8FCmFzc2V0SWRTdHIICQCRAwIFBXJhdGVzAAEFdmFsdWUFB1NjYWxlMTYFBGRvd24BC3JhdGVzUmVjYWxjAAoBAWYCBWFjY3VtBXRva2VuCQDOCAIFBWFjY3VtCQEQdG9rZW5SYXRlc1JlY2FsYwEFBXRva2VuCgACJGwJAQ9nZXRNYXJrZXRBc3NldHMACgACJHMJAJADAQUCJGwKAAUkYWNjMAUDbmlsCgEFJGYwXzECAiRhAiRpAwkAZwIFAiRpBQIkcwUCJGEJAQFmAgUCJGEJAJEDAgUCJGwFAiRpCgEFJGYwXzICAiRhAiRpAwkAZwIFAiRpBQIkcwUCJGEJAAIBAhRMaXN0IHNpemUgZXhjZWVkcyAxMgkBBSRmMF8yAgkBBSRmMF8xAgkBBSRmMF8xAgkBBSRmMF8xAgkBBSRmMF8xAgkBBSRmMF8xAgkBBSRmMF8xAgkBBSRmMF8xAgkBBSRmMF8xAgkBBSRmMF8xAgkBBSRmMF8xAgkBBSRmMF8xAgkBBSRmMF8xAgUFJGFjYzAAAAABAAIAAwAEAAUABgAHAAgACQAKAAsADAEVZ2V0VG9rZW5QcmljZVdpdGhSaXNrAgphc3NldElkU3RyDHJpc2tBdmVyc2l0eQMJAQIhPQIJAM8IAgUMc3RhYmxlc0lkU3RyBQphc3NldElkU3RyBQR1bml0CQCUCgIAwIQ9AMCEPQQFcHJpY2UJARFAZXh0ck5hdGl2ZSgxMDUwKQIFDW9yYWNsZUFkZHJlc3MJAKwCAgUKYXNzZXRJZFN0cgIHX3R3YXA1QgQJcmlza0xldmVsCQERQGV4dHJOYXRpdmUoMTA1MCkCBQ1vcmFjbGVBZGRyZXNzCQCsAgIFCmFzc2V0SWRTdHICCl9yaXNrTGV2ZWwDCQBnAgUMcmlza0F2ZXJzaXR5BQlyaXNrTGV2ZWwJAJQKAgUFcHJpY2UFBXByaWNlCQACAQkArAICCQCsAgICG29yYWNsZSBwcmljZXMgZG9uJ3QgbWF0Y2g6IAkApAMBBQVwcmljZQIjIGlzIHRoZSBwcmljZSwgYnV0IHJpc2sgaXMgdG9vIGhpZ2gBDWdldFRva2VuUHJpY2UBCmFzc2V0SWRTdHIJARVnZXRUb2tlblByaWNlV2l0aFJpc2sCBQphc3NldElkU3RyAAMBE2dldFRva2VuUHJpY2VDYXBwZWQBCmFzc2V0SWRTdHIEDSR0MDEwNTUxMTA2MTQJARVnZXRUb2tlblByaWNlV2l0aFJpc2sCBQphc3NldElkU3RyAAMECG1pblByaWNlCAUNJHQwMTA1NTExMDYxNAJfMQQIbWF4UHJpY2UIBQ0kdDAxMDU1MTEwNjE0Al8yBA9tYXhBbGxvd2VkUHJpY2UJAQt2YWx1ZU9yRWxzZQIJAJoIAgUEdGhpcwkArAICAg9zZXR1cF9tYXhQcmljZV8FCmFzc2V0SWRTdHIA////////////AQQPbWluQWxsb3dlZFByaWNlCQELdmFsdWVPckVsc2UCCQCaCAIFBHRoaXMJAKwCAgIPc2V0dXBfbWluUHJpY2VfBQphc3NldElkU3RyAP///////////wEDAwkBAiE9AgUPbWF4QWxsb3dlZFByaWNlAP///////////wEJAGYCBQhtYXhQcmljZQUPbWF4QWxsb3dlZFByaWNlBwkAlAoCBQ9tYXhBbGxvd2VkUHJpY2UFD21heEFsbG93ZWRQcmljZQMDCQECIT0CBQ9taW5BbGxvd2VkUHJpY2UA////////////AQkAZgIFD21pbkFsbG93ZWRQcmljZQUIbWluUHJpY2UHCQCUCgIFD21pbkFsbG93ZWRQcmljZQUPbWluQWxsb3dlZFByaWNlCQCUCgIFCG1pblByaWNlBQhtYXhQcmljZQEWZ2V0VG9rZW5QcmljZUZvckhlYWx0aAEKYXNzZXRJZFN0cgQFcHJpY2UICQEVZ2V0VG9rZW5QcmljZVdpdGhSaXNrAgUKYXNzZXRJZFN0cgADAl8xBA9tYXhBbGxvd2VkUHJpY2UJAQt2YWx1ZU9yRWxzZQIJAJoIAgUEdGhpcwkArAICAg9zZXR1cF9tYXhQcmljZV8FCmFzc2V0SWRTdHIA////////////AQQPbWluQWxsb3dlZFByaWNlCQELdmFsdWVPckVsc2UCCQCaCAIFBHRoaXMJAKwCAgIPc2V0dXBfbWluUHJpY2VfBQphc3NldElkU3RyAP///////////wEEC2NvbGxhdFByaWNlAwMJAQIhPQIFD21heEFsbG93ZWRQcmljZQD///////////8BCQBmAgUFcHJpY2UFD21heEFsbG93ZWRQcmljZQcFD21heEFsbG93ZWRQcmljZQUFcHJpY2UECWRlYnRQcmljZQMDCQECIT0CBQ9taW5BbGxvd2VkUHJpY2UA////////////AQkAZgIFD21pbkFsbG93ZWRQcmljZQUFcHJpY2UHBQ9taW5BbGxvd2VkUHJpY2UFBXByaWNlCQCUCgIFC2NvbGxhdFByaWNlBQlkZWJ0UHJpY2UBDmNhbGNBc3NldFNjYWxlAQphc3NldElkU3RyBAhkZWNpbWFscwMJAAACBQphc3NldElkU3RyAgVXQVZFUwAICAkBBXZhbHVlAQkA7AcBCQDZBAEFCmFzc2V0SWRTdHIIZGVjaW1hbHMJAGwGAAoAAAUIZGVjaW1hbHMAAAAABQRET1dOARJjYWxjVXNlckNvbGxhdGVyYWwBB2FkZHJlc3MEFHVzZXJDb2xsYXRlcmFsSW52b2tlCQD8BwQFBHRoaXMCEWdldFVzZXJDb2xsYXRlcmFsCQDMCAIHCQDMCAIFB2FkZHJlc3MJAMwIAgYJAMwIAgIABQNuaWwFA25pbAMJAAACBRR1c2VyQ29sbGF0ZXJhbEludm9rZQUUdXNlckNvbGxhdGVyYWxJbnZva2UEE3VzZXJDb2xsYXRlcmFsVmFsdWUEByRtYXRjaDAFFHVzZXJDb2xsYXRlcmFsSW52b2tlAwkAAQIFByRtYXRjaDACA0ludAQBeAUHJG1hdGNoMAUBeAkAAgECJGlzc3VlIHdoaWxlIGRvaW5nIGluLWRhcHAgaW52b2NhdGlvbgMJAAACBRN1c2VyQ29sbGF0ZXJhbFZhbHVlBRN1c2VyQ29sbGF0ZXJhbFZhbHVlBRN1c2VyQ29sbGF0ZXJhbFZhbHVlCQACAQIkU3RyaWN0IHZhbHVlIGlzIG5vdCBlcXVhbCB0byBpdHNlbGYuCQACAQIkU3RyaWN0IHZhbHVlIGlzIG5vdCBlcXVhbCB0byBpdHNlbGYuARRjaGVja1dpdGhkcmF3YWxMaW1pdAQHYWRkcmVzcwphc3NldElkU3RyDmFtb3VudEludGVybmFsBXNSYXRlBA93aXRoZHJhd2FsTGltaXQJAQt2YWx1ZU9yRWxzZQIJAJoIAgUEdGhpcwkArAICCQCsAgICBnNldHVwXwUKYXNzZXRJZFN0cgITX21heFdpdGhkcmF3UGVyMTAwQgD///////////8BAwkAAAIFD3dpdGhkcmF3YWxMaW1pdAD///////////8BBQNuaWwEDXRvdGFsU3VwcGxpZWQJAQ10cnlHZXRJbnRlZ2VyAQkArAICAg90b3RhbF9zdXBwbGllZF8FCmFzc2V0SWRTdHIECGxpbWl0Q2FwCQBrAwUNdG90YWxTdXBwbGllZAUPd2l0aGRyYXdhbExpbWl0AGQEBWxhc3RICQENdHJ5R2V0SW50ZWdlcgEJAKwCAgkArAICBQdhZGRyZXNzAhVfd2l0aGRyYXdMaW1pdEhlaWdodF8FCmFzc2V0SWRTdHIEB2VsYXBzZWQJAGUCBQZoZWlnaHQFBWxhc3RIBA13aW5kb3dFeHBpcmVkCQBmAgUHZWxhcHNlZAUVd2l0aGRyYXdhbExpbWl0QmxvY2tzBAtjdXJyZW50VXNlZAMFDXdpbmRvd0V4cGlyZWQAAAkBDXRyeUdldEludGVnZXIBCQCsAgIJAKwCAgUHYWRkcmVzcwITX3dpdGhkcmF3TGltaXRVc2VkXwUKYXNzZXRJZFN0cgQNYmxvY2tzVG9SZXNldAMFDXdpbmRvd0V4cGlyZWQFFXdpdGhkcmF3YWxMaW1pdEJsb2NrcwkAZQIFFXdpdGhkcmF3YWxMaW1pdEJsb2NrcwUHZWxhcHNlZAQJYXZhaWxhYmxlCQBlAgUIbGltaXRDYXAFC2N1cnJlbnRVc2VkBA9hdmFpbGFibGVTY2FsZWQJAG4EBQlhdmFpbGFibGUFBXNSYXRlBQdTY2FsZTE2BQdDRUlMSU5HAwkAZgIFDmFtb3VudEludGVybmFsBQlhdmFpbGFibGUJAAIBCQCsAgIJAKwCAgkArAICCQCsAgIJAKwCAgIed2l0aGRyYXdhbCBsaW1pdCBleGNlZWRlZCBmb3IgBQphc3NldElkU3RyAg0sIGF2YWlsYWJsZTogCQCkAwEFD2F2YWlsYWJsZVNjYWxlZAITLCBibG9ja3MgdG8gcmVzZXQ6IAkApAMBBQ1ibG9ja3NUb1Jlc2V0CQDOCAIDBQ13aW5kb3dFeHBpcmVkCQDMCAIJAQxJbnRlZ2VyRW50cnkCCQCsAgIJAKwCAgUHYWRkcmVzcwIVX3dpdGhkcmF3TGltaXRIZWlnaHRfBQphc3NldElkU3RyBQZoZWlnaHQFA25pbAUDbmlsCQDMCAIJAQxJbnRlZ2VyRW50cnkCCQCsAgIJAKwCAgUHYWRkcmVzcwITX3dpdGhkcmF3TGltaXRVc2VkXwUKYXNzZXRJZFN0cgkAZAIFC2N1cnJlbnRVc2VkBQ5hbW91bnRJbnRlcm5hbAUDbmlsARBjaGVja0JvcnJvd0xpbWl0BQdhZGRyZXNzCmFzc2V0SWRTdHIOYW1vdW50SW50ZXJuYWwFYlJhdGUFc1JhdGUEC2JvcnJvd0xpbWl0CQELdmFsdWVPckVsc2UCCQCaCAIFBHRoaXMJAKwCAgkArAICAgZzZXR1cF8FCmFzc2V0SWRTdHICEV9tYXhCb3Jyb3dQZXIxMDBCAP///////////wEDCQAAAgULYm9ycm93TGltaXQA////////////AQUDbmlsBA10b3RhbFN1cHBsaWVkCQENdHJ5R2V0SW50ZWdlcgEJAKwCAgIPdG90YWxfc3VwcGxpZWRfBQphc3NldElkU3RyBA5saW1pdENhcFN1cHBseQkAawMFDXRvdGFsU3VwcGxpZWQFC2JvcnJvd0xpbWl0AGQECGxpbWl0Q2FwCQBrAwkAawMFDmxpbWl0Q2FwU3VwcGx5BQVzUmF0ZQUHU2NhbGUxNgUHU2NhbGUxNgUFYlJhdGUEBWxhc3RICQENdHJ5R2V0SW50ZWdlcgEJAKwCAgkArAICBQdhZGRyZXNzAhNfYm9ycm93TGltaXRIZWlnaHRfBQphc3NldElkU3RyBAdlbGFwc2VkCQBlAgUGaGVpZ2h0BQVsYXN0SAQNd2luZG93RXhwaXJlZAkAZgIFB2VsYXBzZWQFFXdpdGhkcmF3YWxMaW1pdEJsb2NrcwQLY3VycmVudFVzZWQDBQ13aW5kb3dFeHBpcmVkAAAJAQ10cnlHZXRJbnRlZ2VyAQkArAICCQCsAgIFB2FkZHJlc3MCEV9ib3Jyb3dMaW1pdFVzZWRfBQphc3NldElkU3RyBA1ibG9ja3NUb1Jlc2V0AwUNd2luZG93RXhwaXJlZAUVd2l0aGRyYXdhbExpbWl0QmxvY2tzCQBlAgUVd2l0aGRyYXdhbExpbWl0QmxvY2tzBQdlbGFwc2VkBAlhdmFpbGFibGUJAGUCBQhsaW1pdENhcAULY3VycmVudFVzZWQED2F2YWlsYWJsZVNjYWxlZAkAbgQFCWF2YWlsYWJsZQUFYlJhdGUFB1NjYWxlMTYFB0NFSUxJTkcDCQBmAgUOYW1vdW50SW50ZXJuYWwFCWF2YWlsYWJsZQkAAgEJAKwCAgkArAICCQCsAgIJAKwCAgkArAICAhpib3Jyb3cgbGltaXQgZXhjZWVkZWQgZm9yIAUKYXNzZXRJZFN0cgINLCBhdmFpbGFibGU6IAkApAMBBQ9hdmFpbGFibGVTY2FsZWQCEywgYmxvY2tzIHRvIHJlc2V0OiAJAKQDAQUNYmxvY2tzVG9SZXNldAkAzggCAwUNd2luZG93RXhwaXJlZAkAzAgCCQEMSW50ZWdlckVudHJ5AgkArAICCQCsAgIFB2FkZHJlc3MCE19ib3Jyb3dMaW1pdEhlaWdodF8FCmFzc2V0SWRTdHIFBmhlaWdodAUDbmlsBQNuaWwJAMwIAgkBDEludGVnZXJFbnRyeQIJAKwCAgkArAICBQdhZGRyZXNzAhFfYm9ycm93TGltaXRVc2VkXwUKYXNzZXRJZFN0cgkAZAIFC2N1cnJlbnRVc2VkBQ5hbW91bnRJbnRlcm5hbAUDbmlsHwFpAQZzdXBwbHkAAwkBASEBCQENdHJ5R2V0Qm9vbGVhbgECDHNldHVwX2FjdGl2ZQkAAgECEW1hcmtldCBpcyBzdG9wcGVkAwMJAQIhPQIJAJADAQgFAWkIcGF5bWVudHMAAQYJAAACCAkAkQMCCAUBaQhwYXltZW50cwAABmFtb3VudAAACQACAQIcMSBwYXltZW50IGhhcyB0byBiZSBhdHRhY2hlZAQKYXNzZXRJZFN0cgkBDmdldEFzc2V0U3RyaW5nAQgJAJEDAggFAWkIcGF5bWVudHMAAAdhc3NldElkBAthc3NldEFtb3VudAgJAJEDAggFAWkIcGF5bWVudHMAAAZhbW91bnQEDSR0MDE1OTUyMTYwMTkJAQ1nZXRBY3R1YWxSYXRlAgUKYXNzZXRJZFN0cgIFc1JhdGUEBXNSYXRlCAUNJHQwMTU5NTIxNjAxOQJfMQQRcmF0ZXNSZWNhbGNSZXN1bHQIBQ0kdDAxNTk1MjE2MDE5Al8yBAZhbW91bnQJAG4EBQthc3NldEFtb3VudAUHU2NhbGUxNgUFc1JhdGUFBERPV04EB2FkZHJlc3MJAKUIAQgFAWkGY2FsbGVyBAltYXhTdXBwbHkEByRtYXRjaDAJAKIIAQkArAICAhBzZXR1cF9tYXhTdXBwbHlfBQphc3NldElkU3RyAwkAAQIFByRtYXRjaDACBlN0cmluZwQBeAUHJG1hdGNoMAkBDXBhcnNlSW50VmFsdWUBBQF4CQENdHJ5R2V0SW50ZWdlcgEJAKwCAgIQc2V0dXBfbWF4U3VwcGx5XwUKYXNzZXRJZFN0cgQKYXNzZXRQcmljZQkBE2dldFRva2VuUHJpY2VDYXBwZWQBBQphc3NldElkU3RyBBJuZXdBZGRyZXNzU3VwcGxpZWQJAGQCCQENdHJ5R2V0SW50ZWdlcgEJAKwCAgkArAICBQdhZGRyZXNzAgpfc3VwcGxpZWRfBQphc3NldElkU3RyBQZhbW91bnQEEG5ld1RvdGFsU3VwcGxpZWQJAGQCCQENdHJ5R2V0SW50ZWdlcgEJAKwCAgIPdG90YWxfc3VwcGxpZWRfBQphc3NldElkU3RyBQZhbW91bnQEBHJhdGUICQENZ2V0QWN0dWFsUmF0ZQIFCmFzc2V0SWRTdHICBXNSYXRlAl8xBAphc3NldFNjYWxlCQEOY2FsY0Fzc2V0U2NhbGUBBQphc3NldElkU3RyBBNuZXdUb3RhbFN1cHBsaWVkVXNkCQBrAwkAawMFEG5ld1RvdGFsU3VwcGxpZWQFBHJhdGUFB1NjYWxlMTYIBQphc3NldFByaWNlAl8xBQphc3NldFNjYWxlAwkAAAIJALMJAgkBDHRyeUdldFN0cmluZwECDHNldHVwX3Rva2VucwUKYXNzZXRJZFN0cgUEdW5pdAkAAgECKXRoaXMgYXNzZXQgaXMgbm90IHN1cHBvcnRlZCBieSB0aGUgbWFya2V0AwMJAQIhPQIFCW1heFN1cHBseQAACQBmAgUTbmV3VG90YWxTdXBwbGllZFVzZAUJbWF4U3VwcGx5BwkAAgECM21heCB0b3RhbCBzdXBwbHkgZm9yIHRoaXMgdG9rZW4gcmVhY2hlZCBpbiB0aGUgcG9vbAMJAGYCCQENdHJ5R2V0SW50ZWdlcgEJAKwCAgINc2V0dXBfcGF1c2VkXwUKYXNzZXRJZFN0cgAACQACAQIodGhpcyBhc3NldCBjYW4ndCBiZSBzdXBwbGllZCBvciBib3Jyb3dlZAQDaW52AwkBAiE9AgkBDHRyeUdldFN0cmluZwEJAKwCAgIQc2V0dXBfYXV0b3N0YWtlXwUKYXNzZXRJZFN0cgIACQD8BwQFBHRoaXMCCnN0YWtlVG9rZW4JAMwIAgUKYXNzZXRJZFN0cgkAzAgCBQthc3NldEFtb3VudAUDbmlsBQNuaWwFBHVuaXQDCQAAAgUDaW52BQNpbnYJAM4IAgkAzAgCCQEMSW50ZWdlckVudHJ5AgkArAICCQCsAgIFB2FkZHJlc3MCCl9zdXBwbGllZF8FCmFzc2V0SWRTdHIFEm5ld0FkZHJlc3NTdXBwbGllZAkAzAgCCQEMSW50ZWdlckVudHJ5AgkArAICAg90b3RhbF9zdXBwbGllZF8FCmFzc2V0SWRTdHIFEG5ld1RvdGFsU3VwcGxpZWQFA25pbAURcmF0ZXNSZWNhbGNSZXN1bHQJAAIBAiRTdHJpY3QgdmFsdWUgaXMgbm90IGVxdWFsIHRvIGl0c2VsZi4BaQEId2l0aGRyYXcCCmFzc2V0SWRTdHILYXNzZXRBbW91bnQEDSR0MDE3NTg2MTc2NTMJAQ1nZXRBY3R1YWxSYXRlAgUKYXNzZXRJZFN0cgIFc1JhdGUEBXNSYXRlCAUNJHQwMTc1ODYxNzY1MwJfMQQRcmF0ZXNSZWNhbGNSZXN1bHQIBQ0kdDAxNzU4NjE3NjUzAl8yBAZhbW91bnQJAG4EBQthc3NldEFtb3VudAUHU2NhbGUxNgUFc1JhdGUFB0NFSUxJTkcEB2FkZHJlc3MJAKUIAQgFAWkGY2FsbGVyBA1hc3NldFN1cHBsaWVkCQENdHJ5R2V0SW50ZWdlcgEJAKwCAgIPdG90YWxfc3VwcGxpZWRfBQphc3NldElkU3RyBA1hc3NldEJvcnJvd2VkCQENdHJ5R2V0SW50ZWdlcgEJAKwCAgIPdG90YWxfYm9ycm93ZWRfBQphc3NldElkU3RyBBF1c2VyQXNzZXRTdXBwbGllZAkBDXRyeUdldEludGVnZXIBCQCsAgIJAKwCAgUHYWRkcmVzcwIKX3N1cHBsaWVkXwUKYXNzZXRJZFN0cgQRdXNlckFzc2V0Qm9ycm93ZWQJAQ10cnlHZXRJbnRlZ2VyAQkArAICCQCsAgIFB2FkZHJlc3MCCl9ib3Jyb3dlZF8FCmFzc2V0SWRTdHIEEmNvbGxhdGVyYWxWYWx1ZUludgkA/AcEBQR0aGlzAhFnZXRVc2VyQ29sbGF0ZXJhbAkAzAgCBwkAzAgCBQdhZGRyZXNzCQDMCAIGCQDMCAIJAKwCAgkArAICBQphc3NldElkU3RyAgosc3VwcGxpZWQsCQCkAwEJAQEtAQUGYW1vdW50BQNuaWwFA25pbAMJAAACBRJjb2xsYXRlcmFsVmFsdWVJbnYFEmNvbGxhdGVyYWxWYWx1ZUludgQPY29sbGF0ZXJhbFZhbHVlBAckbWF0Y2gwBRJjb2xsYXRlcmFsVmFsdWVJbnYDCQABAgUHJG1hdGNoMAIDSW50BAF4BQckbWF0Y2gwBQF4CQACAQIfY2FuJ3QgZ2V0IHVzZXIgY29sbGF0ZXJhbCB2YWx1ZQMJAQEhAQkBDXRyeUdldEJvb2xlYW4BAgxzZXR1cF9hY3RpdmUJAAIBAhFtYXJrZXQgaXMgc3RvcHBlZAMJAGYCAAAFD2NvbGxhdGVyYWxWYWx1ZQkAAgECMnlvdSBkb250IGhhdmUgZW5vdWdoIGNvbGxhdGVyYWwgZm9yIHRoaXMgb3BlcmF0aW9uAwkAZgIFBmFtb3VudAkAZQIFDWFzc2V0U3VwcGxpZWQFDWFzc2V0Qm9ycm93ZWQJAAIBAip0aGlzIGFtb3VudCBpcyBub3QgYXZhaWxhYmxlIG9uIHRoZSBtYXJrZXQDCQBmAgUGYW1vdW50CQBlAgURdXNlckFzc2V0U3VwcGxpZWQFEXVzZXJBc3NldEJvcnJvd2VkCQACAQIqdGhpcyBhbW91bnQgaXMgbm90IGF2YWlsYWJsZSBmb3IgdGhpcyB1c2VyBANpbnYDCQECIT0CCQEMdHJ5R2V0U3RyaW5nAQkArAICAhBzZXR1cF9hdXRvc3Rha2VfBQphc3NldElkU3RyAgAJAPwHBAUEdGhpcwIMdW5zdGFrZVRva2VuCQDMCAIFCmFzc2V0SWRTdHIJAMwIAgULYXNzZXRBbW91bnQFA25pbAUDbmlsBQR1bml0AwkAAAIFA2ludgUDaW52BBFsaW1pdENoZWNrQWN0aW9ucwkBFGNoZWNrV2l0aGRyYXdhbExpbWl0BAUHYWRkcmVzcwUKYXNzZXRJZFN0cgUGYW1vdW50BQVzUmF0ZQMJAAACBRFsaW1pdENoZWNrQWN0aW9ucwURbGltaXRDaGVja0FjdGlvbnMJAM4IAgkAzggCCQDMCAIJAQxJbnRlZ2VyRW50cnkCCQCsAgIJAKwCAgUHYWRkcmVzcwIKX3N1cHBsaWVkXwUKYXNzZXRJZFN0cgkAZQIJAQ10cnlHZXRJbnRlZ2VyAQkArAICCQCsAgIFB2FkZHJlc3MCCl9zdXBwbGllZF8FCmFzc2V0SWRTdHIFBmFtb3VudAkAzAgCCQEMSW50ZWdlckVudHJ5AgkArAICAg90b3RhbF9zdXBwbGllZF8FCmFzc2V0SWRTdHIJAGUCCQENdHJ5R2V0SW50ZWdlcgEJAKwCAgIPdG90YWxfc3VwcGxpZWRfBQphc3NldElkU3RyBQZhbW91bnQJAMwIAgkBDlNjcmlwdFRyYW5zZmVyAwgFAWkGY2FsbGVyBQthc3NldEFtb3VudAkBDWdldEFzc2V0Qnl0ZXMBBQphc3NldElkU3RyBQNuaWwFEXJhdGVzUmVjYWxjUmVzdWx0BRFsaW1pdENoZWNrQWN0aW9ucwkAAgECJFN0cmljdCB2YWx1ZSBpcyBub3QgZXF1YWwgdG8gaXRzZWxmLgkAAgECJFN0cmljdCB2YWx1ZSBpcyBub3QgZXF1YWwgdG8gaXRzZWxmLgkAAgECJFN0cmljdCB2YWx1ZSBpcyBub3QgZXF1YWwgdG8gaXRzZWxmLgFpAQZib3Jyb3cCCmFzc2V0SWRTdHILYXNzZXRBbW91bnQEB2FkZHJlc3MJAKUIAQgFAWkGY2FsbGVyBA0kdDAxOTQxNzE5NDg0CQENZ2V0QWN0dWFsUmF0ZQIFCmFzc2V0SWRTdHICBWJSYXRlBAViUmF0ZQgFDSR0MDE5NDE3MTk0ODQCXzEEEXJhdGVzUmVjYWxjUmVzdWx0CAUNJHQwMTk0MTcxOTQ4NAJfMgQGYW1vdW50CQBuBAULYXNzZXRBbW91bnQFB1NjYWxlMTYFBWJSYXRlBQdDRUlMSU5HBBJjb2xsYXRlcmFsVmFsdWVJbnYJAPwHBAUEdGhpcwIRZ2V0VXNlckNvbGxhdGVyYWwJAMwIAgcJAMwIAgUHYWRkcmVzcwkAzAgCBgkAzAgCCQCsAgIJAKwCAgUKYXNzZXRJZFN0cgIKLGJvcnJvd2VkLAkApAMBBQZhbW91bnQFA25pbAUDbmlsAwkAAAIFEmNvbGxhdGVyYWxWYWx1ZUludgUSY29sbGF0ZXJhbFZhbHVlSW52BA9jb2xsYXRlcmFsVmFsdWUEByRtYXRjaDAFEmNvbGxhdGVyYWxWYWx1ZUludgMJAAECBQckbWF0Y2gwAgNJbnQEAXgFByRtYXRjaDAFAXgJAAIBAh9jYW4ndCBnZXQgdXNlciBjb2xsYXRlcmFsIHZhbHVlAwkBASEBCQENdHJ5R2V0Qm9vbGVhbgECDHNldHVwX2FjdGl2ZQkAAgECEW1hcmtldCBpcyBzdG9wcGVkAwkAZgIAAAUPY29sbGF0ZXJhbFZhbHVlCQACAQIheW91IGhhdmUgdG8gc3VwcGx5IG1vcmUgdG8gYm9ycm93AwkAAAIJAQ10cnlHZXRJbnRlZ2VyAQkArAICAhRzZXR1cF9ib3Jyb3dFbmFibGVkXwUKYXNzZXRJZFN0cgAACQACAQIcdGhpcyBhc3NldCBjYW4ndCBiZSBib3Jyb3dlZAMJAGYCCQENdHJ5R2V0SW50ZWdlcgEJAKwCAgINc2V0dXBfcGF1c2VkXwUKYXNzZXRJZFN0cgAACQACAQIodGhpcyBhc3NldCBjYW4ndCBiZSBzdXBwbGllZCBvciBib3Jyb3dlZAQNYXNzZXRTdXBwbGllZAkBDXRyeUdldEludGVnZXIBCQCsAgICD3RvdGFsX3N1cHBsaWVkXwUKYXNzZXRJZFN0cgQNYXNzZXRCb3Jyb3dlZAkBDXRyeUdldEludGVnZXIBCQCsAgICD3RvdGFsX2JvcnJvd2VkXwUKYXNzZXRJZFN0cgQRdXNlckFzc2V0Qm9ycm93ZWQJAQ10cnlHZXRJbnRlZ2VyAQkArAICCQCsAgIFB2FkZHJlc3MCCl9ib3Jyb3dlZF8FCmFzc2V0SWRTdHIDCQBmAgUGYW1vdW50CQBlAgUNYXNzZXRTdXBwbGllZAUNYXNzZXRCb3Jyb3dlZAkAAgECHHRoaXMgYW1vdW50IGlzIG5vdCBhdmFpbGFibGUEA2ludgMJAQIhPQIJAQx0cnlHZXRTdHJpbmcBCQCsAgICEHNldHVwX2F1dG9zdGFrZV8FCmFzc2V0SWRTdHICAAkA/AcEBQR0aGlzAgx1bnN0YWtlVG9rZW4JAMwIAgUKYXNzZXRJZFN0cgkAzAgCBQthc3NldEFtb3VudAUDbmlsBQNuaWwFBHVuaXQDCQAAAgUDaW52BQNpbnYEBXNSYXRlCAkAkQMCBRFyYXRlc1JlY2FsY1Jlc3VsdAkAaAIJAQV2YWx1ZQEJAM8IAgkBD2dldE1hcmtldEFzc2V0cwAFCmFzc2V0SWRTdHIAAwV2YWx1ZQQRbGltaXRDaGVja0FjdGlvbnMJARBjaGVja0JvcnJvd0xpbWl0BQUHYWRkcmVzcwUKYXNzZXRJZFN0cgUGYW1vdW50BQViUmF0ZQUFc1JhdGUDCQAAAgURbGltaXRDaGVja0FjdGlvbnMFEWxpbWl0Q2hlY2tBY3Rpb25zCQDOCAIJAM4IAgkAzAgCCQEMSW50ZWdlckVudHJ5AgkArAICCQCsAgIFB2FkZHJlc3MCCl9ib3Jyb3dlZF8FCmFzc2V0SWRTdHIJAGQCBRF1c2VyQXNzZXRCb3Jyb3dlZAUGYW1vdW50CQDMCAIJAQxJbnRlZ2VyRW50cnkCCQCsAgICD3RvdGFsX2JvcnJvd2VkXwUKYXNzZXRJZFN0cgkAZAIFDWFzc2V0Qm9ycm93ZWQFBmFtb3VudAkAzAgCCQEOU2NyaXB0VHJhbnNmZXIDCAUBaQZjYWxsZXIFC2Fzc2V0QW1vdW50CQENZ2V0QXNzZXRCeXRlcwEFCmFzc2V0SWRTdHIFA25pbAURcmF0ZXNSZWNhbGNSZXN1bHQFEWxpbWl0Q2hlY2tBY3Rpb25zCQACAQIkU3RyaWN0IHZhbHVlIGlzIG5vdCBlcXVhbCB0byBpdHNlbGYuCQACAQIkU3RyaWN0IHZhbHVlIGlzIG5vdCBlcXVhbCB0byBpdHNlbGYuCQACAQIkU3RyaWN0IHZhbHVlIGlzIG5vdCBlcXVhbCB0byBpdHNlbGYuAWkBBXJlcGF5AAMJAQEhAQkBDXRyeUdldEJvb2xlYW4BAgxzZXR1cF9hY3RpdmUJAAIBAhFtYXJrZXQgaXMgc3RvcHBlZAMDCQECIT0CCQCQAwEIBQFpCHBheW1lbnRzAAEGCQAAAggJAJEDAggFAWkIcGF5bWVudHMAAAZhbW91bnQAAAkAAgECHDEgcGF5bWVudCBoYXMgdG8gYmUgYXR0YWNoZWQECmFzc2V0SWRTdHIJAQ5nZXRBc3NldFN0cmluZwEICQCRAwIIBQFpCHBheW1lbnRzAAAHYXNzZXRJZAQLYXNzZXRBbW91bnQICQCRAwIIBQFpCHBheW1lbnRzAAAGYW1vdW50BA0kdDAyMTU3ODIyMjYyCQENZ2V0QWN0dWFsUmF0ZQIFCmFzc2V0SWRTdHICBWJSYXRlBAViUmF0ZQgFDSR0MDIxNTc4MjIyNjICXzEEEXJhdGVzUmVjYWxjUmVzdWx0CAUNJHQwMjE1NzgyMjI2MgJfMgQGYW1vdW50CQBuBAULYXNzZXRBbW91bnQFB1NjYWxlMTYFBWJSYXRlBQdDRUlMSU5HBAdhZGRyZXNzCQClCAEIBQFpBmNhbGxlcgQNYXNzZXRTdXBwbGllZAkBDXRyeUdldEludGVnZXIBCQCsAgICD3RvdGFsX3N1cHBsaWVkXwUKYXNzZXRJZFN0cgQNYXNzZXRCb3Jyb3dlZAkBDXRyeUdldEludGVnZXIBCQCsAgICD3RvdGFsX2JvcnJvd2VkXwUKYXNzZXRJZFN0cgQRdXNlckFzc2V0Qm9ycm93ZWQJAQ10cnlHZXRJbnRlZ2VyAQkArAICCQCsAgIFB2FkZHJlc3MCCl9ib3Jyb3dlZF8FCmFzc2V0SWRTdHIECmFtb3VudExlZnQJAGUCBRF1c2VyQXNzZXRCb3Jyb3dlZAUGYW1vdW50BAtyZXBheUFtb3VudAMJAGcCBQphbW91bnRMZWZ0AAAFBmFtb3VudAURdXNlckFzc2V0Qm9ycm93ZWQDCQAAAgkAswkCCQEMdHJ5R2V0U3RyaW5nAQIMc2V0dXBfdG9rZW5zBQphc3NldElkU3RyBQR1bml0CQACAQIpdGhpcyBhc3NldCBpcyBub3Qgc3VwcG9ydGVkIGJ5IHRoZSBtYXJrZXQEA2ludgMJAQIhPQIJAQx0cnlHZXRTdHJpbmcBCQCsAgICEHNldHVwX2F1dG9zdGFrZV8FCmFzc2V0SWRTdHICAAkA/AcEBQR0aGlzAgpzdGFrZVRva2VuCQDMCAIFCmFzc2V0SWRTdHIJAMwIAgULYXNzZXRBbW91bnQFA25pbAUDbmlsBQR1bml0AwkAAAIFA2ludgUDaW52BAxleGNlc3NUb2tlbnMJAGUCBQthc3NldEFtb3VudAkAawMFC3JlcGF5QW1vdW50BQViUmF0ZQUHU2NhbGUxNgkAzggCCQDOCAIJAMwIAgkBDEludGVnZXJFbnRyeQIJAKwCAgkArAICBQdhZGRyZXNzAgpfYm9ycm93ZWRfBQphc3NldElkU3RyCQBlAgURdXNlckFzc2V0Qm9ycm93ZWQFC3JlcGF5QW1vdW50CQDMCAIJAQxJbnRlZ2VyRW50cnkCCQCsAgICD3RvdGFsX2JvcnJvd2VkXwUKYXNzZXRJZFN0cgkAZQIFDWFzc2V0Qm9ycm93ZWQFC3JlcGF5QW1vdW50BQNuaWwFEXJhdGVzUmVjYWxjUmVzdWx0AwkAZwIFCmFtb3VudExlZnQAAAUDbmlsCQDMCAIJAQ5TY3JpcHRUcmFuc2ZlcgMIBQFpBmNhbGxlcgUMZXhjZXNzVG9rZW5zCAkAkQMCCAUBaQhwYXltZW50cwAAB2Fzc2V0SWQFA25pbAkAAgECJFN0cmljdCB2YWx1ZSBpcyBub3QgZXF1YWwgdG8gaXRzZWxmLgFpAQhyZXBheUZvcgEHYWRkcmVzcwMJAQEhAQkBDXRyeUdldEJvb2xlYW4BAgxzZXR1cF9hY3RpdmUJAAIBAhFtYXJrZXQgaXMgc3RvcHBlZAMJAQIhPQIIBQFpBmNhbGxlcgUScmVzZXJ2ZUZ1bmRBZGRyZXNzCQACAQInYXZhaWxhYmxlIG9ubHkgZm9yIHJlc2VydmUgZnVuZCBhZGRyZXNzAwkAAAIFB2FkZHJlc3MCBmdsb2JhbAkAAgECIHlvdSBjYW4ndCByZXBheSBmb3IgZXZlcnlvbmUgOl8pAwMJAQIhPQIJAJADAQgFAWkIcGF5bWVudHMAAQYJAAACCAkAkQMCCAUBaQhwYXltZW50cwAABmFtb3VudAAACQACAQIcMSBwYXltZW50IGhhcyB0byBiZSBhdHRhY2hlZAQKYXNzZXRJZFN0cgkBDmdldEFzc2V0U3RyaW5nAQgJAJEDAggFAWkIcGF5bWVudHMAAAdhc3NldElkBAthc3NldEFtb3VudAgJAJEDAggFAWkIcGF5bWVudHMAAAZhbW91bnQEDSR0MDIzOTM4MjQ2MjIJAQ1nZXRBY3R1YWxSYXRlAgUKYXNzZXRJZFN0cgIFYlJhdGUEBWJSYXRlCAUNJHQwMjM5MzgyNDYyMgJfMQQRcmF0ZXNSZWNhbGNSZXN1bHQIBQ0kdDAyMzkzODI0NjIyAl8yBAZhbW91bnQJAG4EBQthc3NldEFtb3VudAUHU2NhbGUxNgUFYlJhdGUFB0NFSUxJTkcEDWFzc2V0U3VwcGxpZWQJAQ10cnlHZXRJbnRlZ2VyAQkArAICAg90b3RhbF9zdXBwbGllZF8FCmFzc2V0SWRTdHIEDWFzc2V0Qm9ycm93ZWQJAQ10cnlHZXRJbnRlZ2VyAQkArAICAg90b3RhbF9ib3Jyb3dlZF8FCmFzc2V0SWRTdHIEEXVzZXJBc3NldEJvcnJvd2VkCQENdHJ5R2V0SW50ZWdlcgEJAKwCAgkArAICBQdhZGRyZXNzAgpfYm9ycm93ZWRfBQphc3NldElkU3RyBAphbW91bnRMZWZ0CQBlAgURdXNlckFzc2V0Qm9ycm93ZWQFBmFtb3VudAQLcmVwYXlBbW91bnQDCQBnAgUKYW1vdW50TGVmdAAABQZhbW91bnQFEXVzZXJBc3NldEJvcnJvd2VkAwkAAAIJALMJAgkBDHRyeUdldFN0cmluZwECDHNldHVwX3Rva2VucwUKYXNzZXRJZFN0cgUEdW5pdAkAAgECKXRoaXMgYXNzZXQgaXMgbm90IHN1cHBvcnRlZCBieSB0aGUgbWFya2V0BANpbnYDCQECIT0CCQEMdHJ5R2V0U3RyaW5nAQkArAICAhBzZXR1cF9hdXRvc3Rha2VfBQphc3NldElkU3RyAgAJAPwHBAUEdGhpcwIKc3Rha2VUb2tlbgkAzAgCBQphc3NldElkU3RyCQDMCAIFC2Fzc2V0QW1vdW50BQNuaWwFA25pbAUEdW5pdAMJAAACBQNpbnYFA2ludgQMZXhjZXNzVG9rZW5zCQBlAgULYXNzZXRBbW91bnQJAGsDBQtyZXBheUFtb3VudAUFYlJhdGUFB1NjYWxlMTYJAM4IAgkAzggCCQDMCAIJAQxJbnRlZ2VyRW50cnkCCQCsAgIJAKwCAgUHYWRkcmVzcwIKX2JvcnJvd2VkXwUKYXNzZXRJZFN0cgkAZQIFEXVzZXJBc3NldEJvcnJvd2VkBQtyZXBheUFtb3VudAkAzAgCCQEMSW50ZWdlckVudHJ5AgkArAICAg90b3RhbF9ib3Jyb3dlZF8FCmFzc2V0SWRTdHIJAGUCBQ1hc3NldEJvcnJvd2VkBQtyZXBheUFtb3VudAUDbmlsBRFyYXRlc1JlY2FsY1Jlc3VsdAMJAGcCBQphbW91bnRMZWZ0AAAFA25pbAkAzAgCCQEOU2NyaXB0VHJhbnNmZXIDCAUBaQZjYWxsZXIFDGV4Y2Vzc1Rva2VucwgJAJEDAggFAWkIcGF5bWVudHMAAAdhc3NldElkBQNuaWwJAAIBAiRTdHJpY3QgdmFsdWUgaXMgbm90IGVxdWFsIHRvIGl0c2VsZi4BaQEKc3Rha2VUb2tlbgIKYXNzZXRJZFN0cgZhbW91bnQEEGF1dG9zdGFrZUFkZHJlc3MJAQt2YWx1ZU9yRWxzZQIJAKYIAQkBDHRyeUdldFN0cmluZwEJAKwCAgIQc2V0dXBfYXV0b3N0YWtlXwUKYXNzZXRJZFN0cgkBB0FkZHJlc3MBARoBV3vJqP6V1issYKZ2YPlTI8WKEFoN716o2wQVc3Rha2VyU3VwcG9ydGVkQXNzZXRzCQERQGV4dHJOYXRpdmUoMTA1MykCBRBhdXRvc3Rha2VBZGRyZXNzAhVzZXR1cF9zdXBwb3J0ZWRBc3NldHMDCQECIT0CCAUBaQZjYWxsZXIFBHRoaXMJAAIBAixvbmx5IGZvciBpbnRlcm5hbCBzbWFydCBjb250cmFjdCBpbnZvY2F0aW9ucwMJAAACCQCzCQIFFXN0YWtlclN1cHBvcnRlZEFzc2V0cwUKYXNzZXRJZFN0cgUEdW5pdAUDbmlsBAxhbW91bnRTdGFrZWQJAQ10cnlHZXRJbnRlZ2VyAQkArAICAhFhdXRvc3Rha2VfYW1vdW50XwUKYXNzZXRJZFN0cgQIc3Rha2VJbnYJAP0HBAUQYXV0b3N0YWtlQWRkcmVzcwIHc3Rha2VMUAUDbmlsCQDMCAIJAQ9BdHRhY2hlZFBheW1lbnQCCQENZ2V0QXNzZXRCeXRlcwEFCmFzc2V0SWRTdHIFBmFtb3VudAUDbmlsAwkAAAIFCHN0YWtlSW52BQhzdGFrZUludgkAzAgCCQEMSW50ZWdlckVudHJ5AgkArAICAhFhdXRvc3Rha2VfYW1vdW50XwUKYXNzZXRJZFN0cgkAZAIFDGFtb3VudFN0YWtlZAUGYW1vdW50BQNuaWwJAAIBAiRTdHJpY3QgdmFsdWUgaXMgbm90IGVxdWFsIHRvIGl0c2VsZi4BaQENc3Rha2VUb2tlbkFsbAEKYXNzZXRJZFN0cgMJAQIhPQIIBQFpBmNhbGxlcgUEdGhpcwkAAgECLG9ubHkgZm9yIGludGVybmFsIHNtYXJ0IGNvbnRyYWN0IGludm9jYXRpb25zBAZhbW91bnQJAQpnZXRCYWxhbmNlAQUKYXNzZXRJZFN0cgQDaW52CQD9BwQFBHRoaXMCCnN0YWtlVG9rZW4JAMwIAgUKYXNzZXRJZFN0cgkAzAgCBQZhbW91bnQFA25pbAUDbmlsAwkAAAIFA2ludgUDaW52BQNuaWwJAAIBAiRTdHJpY3QgdmFsdWUgaXMgbm90IGVxdWFsIHRvIGl0c2VsZi4BaQEMdW5zdGFrZVRva2VuAgphc3NldElkU3RyBmFtb3VudAQQYXV0b3N0YWtlQWRkcmVzcwkBC3ZhbHVlT3JFbHNlAgkApggBCQEMdHJ5R2V0U3RyaW5nAQkArAICAhBzZXR1cF9hdXRvc3Rha2VfBQphc3NldElkU3RyCQEHQWRkcmVzcwEBGgFXe8mo/pXWKyxgpnZg+VMjxYoQWg3vXqjbBBVzdGFrZXJTdXBwb3J0ZWRBc3NldHMJARFAZXh0ck5hdGl2ZSgxMDUzKQIFEGF1dG9zdGFrZUFkZHJlc3MCFXNldHVwX3N1cHBvcnRlZEFzc2V0cwMJAQIhPQIIBQFpBmNhbGxlcgUEdGhpcwkAAgECLG9ubHkgZm9yIGludGVybmFsIHNtYXJ0IGNvbnRyYWN0IGludm9jYXRpb25zAwkAAAIJALMJAgUVc3Rha2VyU3VwcG9ydGVkQXNzZXRzBQphc3NldElkU3RyBQR1bml0BQNuaWwEDGFtb3VudFN0YWtlZAkBDXRyeUdldEludGVnZXIBCQCsAgICEWF1dG9zdGFrZV9hbW91bnRfBQphc3NldElkU3RyBAhzdGFrZUludgkA/QcEBRBhdXRvc3Rha2VBZGRyZXNzAgl1bnN0YWtlTFAJAMwIAgUKYXNzZXRJZFN0cgkAzAgCBQZhbW91bnQFA25pbAUDbmlsAwkAAAIFCHN0YWtlSW52BQhzdGFrZUludgkAzAgCCQEMSW50ZWdlckVudHJ5AgkArAICAhFhdXRvc3Rha2VfYW1vdW50XwUKYXNzZXRJZFN0cgkAZQIFDGFtb3VudFN0YWtlZAUGYW1vdW50BQNuaWwJAAIBAiRTdHJpY3QgdmFsdWUgaXMgbm90IGVxdWFsIHRvIGl0c2VsZi4BaQELYWRkSW50ZXJlc3QCCmFzc2V0SWRTdHIGYW1vdW50AwkBAiE9AggFAWkGY2FsbGVyBQR0aGlzCQACAQIYb25seSBmb3Igc2VsZiBpbnZvY2F0aW9uBAZlYXJuZWQJAQ10cnlHZXRJbnRlZ2VyAQkArAICAhVhdXRvc3Rha2VfbGFzdEVhcm5lZF8FCmFzc2V0SWRTdHIECmxhc3RIZWlnaHQJAQ10cnlHZXRJbnRlZ2VyAQkArAICAhRhdXRvc3Rha2VfbGFzdEJsb2NrXwUKYXNzZXRJZFN0cgQLY2xlYW5BbW91bnQJAGsDBQZhbW91bnQAUABkBApzdGFraW5nRmVlCQBlAgUGYW1vdW50BQtjbGVhbkFtb3VudAQMc3RhdGVDaGFuZ2VzAwMJAAACBQpsYXN0SGVpZ2h0BQZoZWlnaHQGCQAAAgUGYW1vdW50AAAFA25pbAkAzAgCCQEMSW50ZWdlckVudHJ5AgkArAICAhhhdXRvc3Rha2VfcHJlTGFzdEVhcm5lZF8FCmFzc2V0SWRTdHIFBmVhcm5lZAkAzAgCCQEMSW50ZWdlckVudHJ5AgkArAICAhdhdXRvc3Rha2VfcHJlTGFzdEJsb2NrXwUKYXNzZXRJZFN0cgUKbGFzdEhlaWdodAkAzAgCCQEMSW50ZWdlckVudHJ5AgkArAICAhVhdXRvc3Rha2VfbGFzdEVhcm5lZF8FCmFzc2V0SWRTdHIJAGQCBQZlYXJuZWQFC2NsZWFuQW1vdW50CQDMCAIJAQxJbnRlZ2VyRW50cnkCCQCsAgICFGF1dG9zdGFrZV9sYXN0QmxvY2tfBQphc3NldElkU3RyBQZoZWlnaHQFA25pbAkAzggCBQxzdGF0ZUNoYW5nZXMJAMwIAgkBDEludGVnZXJFbnRyeQIJAKwCAgUKYXNzZXRJZFN0cgIGX3NSYXRlCQBkAgkBDXRyeUdldEludGVnZXIBCQCsAgIFCmFzc2V0SWRTdHICBl9zUmF0ZQkAawMFB1NjYWxlMTYFC2NsZWFuQW1vdW50CQENdHJ5R2V0SW50ZWdlcgEJAKwCAgIPdG90YWxfc3VwcGxpZWRfBQphc3NldElkU3RyCQDMCAIJAQxJbnRlZ2VyRW50cnkCCQCsAgIJAKwCAgIEZmVlXwUKYXNzZXRJZFN0cgIIX3N0YWtpbmcJAGQCCQENdHJ5R2V0SW50ZWdlcgEJAKwCAgkArAICAgRmZWVfBQphc3NldElkU3RyAghfc3Rha2luZwUKc3Rha2luZ0ZlZQUDbmlsAWkBE2FkZEludGVyZXN0RVhURVJOQUwAAwkBAiE9AgkAkAMBCAUBaQhwYXltZW50cwABCQACAQIkZXhhY3RseSAxIHBheW1lbnQgaGFzIHRvIGJlIGF0dGFjaGVkBAdhc3NldElkCAkAkQMCCAUBaQhwYXltZW50cwAAB2Fzc2V0SWQECmFzc2V0SWRTdHIJAQ5nZXRBc3NldFN0cmluZwEFB2Fzc2V0SWQDCQAAAgkAswkCCQEMdHJ5R2V0U3RyaW5nAQIMc2V0dXBfdG9rZW5zBQphc3NldElkU3RyBQR1bml0CQACAQIpdGhpcyBhc3NldCBpcyBub3Qgc3VwcG9ydGVkIGJ5IHRoZSBtYXJrZXQECXNwbGl0dGluZwkBE2dldFJld2FyZHNTcGxpdHRpbmcBBQphc3NldElkU3RyBAZhbW91bnQJAGsDCAkAkQMCCAUBaQhwYXltZW50cwAABmFtb3VudAgFCXNwbGl0dGluZwJfMgBkBA10b3RhbFN1cHBsaWVkCQENdHJ5R2V0SW50ZWdlcgEJAKwCAgIPdG90YWxfc3VwcGxpZWRfBQphc3NldElkU3RyBA5zdXBwbGllckFtb3VudAMJAGYCBQ10b3RhbFN1cHBsaWVkAAAFBmFtb3VudAAABA1zdGFraW5nRmVlQWRkCQBkAgkAawMICQCRAwIIBQFpCHBheW1lbnRzAAAGYW1vdW50CAUJc3BsaXR0aW5nAl8zAGQJAGUCBQZhbW91bnQFDnN1cHBsaWVyQW1vdW50BAZlYXJuZWQJAQ10cnlHZXRJbnRlZ2VyAQkArAICAhVhdXRvc3Rha2VfbGFzdEVhcm5lZF8FCmFzc2V0SWRTdHIECmxhc3RIZWlnaHQJAQ10cnlHZXRJbnRlZ2VyAQkArAICAhRhdXRvc3Rha2VfbGFzdEJsb2NrXwUKYXNzZXRJZFN0cgQMc3RhdGVDaGFuZ2VzAwMJAAACBQpsYXN0SGVpZ2h0BQZoZWlnaHQGCQAAAgUOc3VwcGxpZXJBbW91bnQAAAUDbmlsCQDMCAIJAQxJbnRlZ2VyRW50cnkCCQCsAgICGGF1dG9zdGFrZV9wcmVMYXN0RWFybmVkXwUKYXNzZXRJZFN0cgUGZWFybmVkCQDMCAIJAQxJbnRlZ2VyRW50cnkCCQCsAgICF2F1dG9zdGFrZV9wcmVMYXN0QmxvY2tfBQphc3NldElkU3RyBQpsYXN0SGVpZ2h0CQDMCAIJAQxJbnRlZ2VyRW50cnkCCQCsAgICFWF1dG9zdGFrZV9sYXN0RWFybmVkXwUKYXNzZXRJZFN0cgkAZAIFBmVhcm5lZAUOc3VwcGxpZXJBbW91bnQJAMwIAgkBDEludGVnZXJFbnRyeQIJAKwCAgIUYXV0b3N0YWtlX2xhc3RCbG9ja18FCmFzc2V0SWRTdHIFBmhlaWdodAUDbmlsCQDOCAIJAM4IAgUMc3RhdGVDaGFuZ2VzAwkAZgIFDnN1cHBsaWVyQW1vdW50AAAJAMwIAgkBDEludGVnZXJFbnRyeQIJAKwCAgUKYXNzZXRJZFN0cgIGX3NSYXRlCQBkAgkBDXRyeUdldEludGVnZXIBCQCsAgIFCmFzc2V0SWRTdHICBl9zUmF0ZQkAawMFB1NjYWxlMTYFDnN1cHBsaWVyQW1vdW50BQ10b3RhbFN1cHBsaWVkBQNuaWwFA25pbAkAzAgCCQEOU2NyaXB0VHJhbnNmZXIDBRFzdGFibGVGdW5kQWRkcmVzcwkAawMICQCRAwIIBQFpCHBheW1lbnRzAAAGYW1vdW50CAUJc3BsaXR0aW5nAl8xAGQFB2Fzc2V0SWQJAMwIAgkBDEludGVnZXJFbnRyeQIJAKwCAgkArAICAgRmZWVfBQphc3NldElkU3RyAghfc3Rha2luZwkAZAIJAQ10cnlHZXRJbnRlZ2VyAQkArAICCQCsAgICBGZlZV8FCmFzc2V0SWRTdHICCF9zdGFraW5nBQ1zdGFraW5nRmVlQWRkBQNuaWwBaQEHcHJlSW5pdAQGdG9rZW5zBGx0dnMDbHRzCXBlbmFsdGllcwoBAWYCBWFjY3VtBXRva2VuCQDOCAIFBWFjY3VtCQDMCAIJAQxJbnRlZ2VyRW50cnkCCQCsAgIFBXRva2VuAgZfYlJhdGUFB1NjYWxlMTYJAMwIAgkBDEludGVnZXJFbnRyeQIJAKwCAgUFdG9rZW4CBl9zUmF0ZQUHU2NhbGUxNgUDbmlsAwkBAiE9AggFAWkGY2FsbGVyBQR0aGlzCQACAQIKYWRtaW4gb25seQQFcmF0ZXMKAAIkbAkAtQkCBQZ0b2tlbnMCASwKAAIkcwkAkAMBBQIkbAoABSRhY2MwBQNuaWwKAQUkZjBfMQICJGECJGkDCQBnAgUCJGkFAiRzBQIkYQkBAWYCBQIkYQkAkQMCBQIkbAUCJGkKAQUkZjBfMgICJGECJGkDCQBnAgUCJGkFAiRzBQIkYQkAAgECFExpc3Qgc2l6ZSBleGNlZWRzIDEyCQEFJGYwXzICCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECBQUkYWNjMAAAAAEAAgADAAQABQAGAAcACAAJAAoACwAMCQDOCAIJAMwIAgkBC1N0cmluZ0VudHJ5AgIMc2V0dXBfdG9rZW5zBQZ0b2tlbnMJAMwIAgkBC1N0cmluZ0VudHJ5AgIKc2V0dXBfbHR2cwUEbHR2cwkAzAgCCQELU3RyaW5nRW50cnkCAglzZXR1cF9sdHMFA2x0cwkAzAgCCQELU3RyaW5nRW50cnkCAg9zZXR1cF9wZW5hbHRpZXMFCXBlbmFsdGllcwkAzAgCCQEMQm9vbGVhbkVudHJ5AgIMc2V0dXBfYWN0aXZlBgUDbmlsBQVyYXRlcwFpAQxpbml0TmV3VG9rZW4EBXRva2VuA2x0dgJsdAdwZW5hbHR5AwkBAiE9AggFAWkGY2FsbGVyBQR0aGlzCQACAQIKYWRtaW4gb25seQkAzAgCCQELU3RyaW5nRW50cnkCAgxzZXR1cF90b2tlbnMJAKwCAgkArAICCQEMdHJ5R2V0U3RyaW5nAQIMc2V0dXBfdG9rZW5zAgEsBQV0b2tlbgkAzAgCCQELU3RyaW5nRW50cnkCAgpzZXR1cF9sdHZzCQCsAgIJAKwCAgkBDHRyeUdldFN0cmluZwECCnNldHVwX2x0dnMCASwFA2x0dgkAzAgCCQELU3RyaW5nRW50cnkCAglzZXR1cF9sdHMJAKwCAgkArAICCQEMdHJ5R2V0U3RyaW5nAQIJc2V0dXBfbHRzAgEsBQJsdAkAzAgCCQELU3RyaW5nRW50cnkCAg9zZXR1cF9wZW5hbHRpZXMJAKwCAgkArAICCQEMdHJ5R2V0U3RyaW5nAQIPc2V0dXBfcGVuYWx0aWVzAgEsBQdwZW5hbHR5CQDMCAIJAQxJbnRlZ2VyRW50cnkCCQCsAgIFBXRva2VuAgZfYlJhdGUFB1NjYWxlMTYJAMwIAgkBDEludGVnZXJFbnRyeQIJAKwCAgUFdG9rZW4CBl9zUmF0ZQUHU2NhbGUxNgUDbmlsAWkBD3VwZGF0ZVBhcmFtZXRlcgIDa2V5A3ZhbAMDCQECIT0CCAUBaQZjYWxsZXIFBHRoaXMJAQIhPQIIBQFpBmNhbGxlcgUMYWRtaW5BZGRyZXNzBwkAAgECCmFkbWluIG9ubHkJAMwIAgkBDEludGVnZXJFbnRyeQIFA2tleQkBDXBhcnNlSW50VmFsdWUBBQN2YWwFA25pbAFpAQx1cGRhdGVTdHJpbmcCA2tleQN2YWwDAwkBAiE9AggFAWkGY2FsbGVyBQR0aGlzCQECIT0CCAUBaQZjYWxsZXIFDGFkbWluQWRkcmVzcwcJAAIBAgphZG1pbiBvbmx5CQDMCAIJAQtTdHJpbmdFbnRyeQIFA2tleQUDdmFsBQNuaWwBaQEJY2xhaW1GZWVzAQphc3NldElkU3RyAwkAAAIFFmZlZUNvbGxlY3RvckFkZHJlc3NTdHIFBHVuaXQJAAIBAhxmZWUgY29sbGVjdG9yIG5vdCBjb25maWd1cmVkAwkAAAIJALMJAgkBDHRyeUdldFN0cmluZwECDHNldHVwX3Rva2VucwUKYXNzZXRJZFN0cgUEdW5pdAkAAgECKXRoaXMgYXNzZXQgaXMgbm90IHN1cHBvcnRlZCBieSB0aGUgbWFya2V0BAhpbnRlcmVzdAkBDXRyeUdldEludGVnZXIBCQCsAgIJAKwCAgIEZmVlXwUKYXNzZXRJZFN0cgIJX2ludGVyZXN0BANzdGsJAQ10cnlHZXRJbnRlZ2VyAQkArAICCQCsAgICBGZlZV8FCmFzc2V0SWRTdHICCF9zdGFraW5nBANsaXEJAQ10cnlHZXRJbnRlZ2VyAQkArAICCQCsAgICBGZlZV8FCmFzc2V0SWRTdHICDF9saXF1aWRhdGlvbgQFdG90YWwJAGQCCQBkAgUIaW50ZXJlc3QFA3N0awUDbGlxAwkAZwIAAAUFdG90YWwFA25pbAQDYmFsCQEKZ2V0QmFsYW5jZQEFCmFzc2V0SWRTdHIECGlzU3Rha2VkCQECIT0CCQEMdHJ5R2V0U3RyaW5nAQkArAICAhBzZXR1cF9hdXRvc3Rha2VfBQphc3NldElkU3RyAgAECnVuc3Rha2VJbnYDAwUIaXNTdGFrZWQJAGYCBQV0b3RhbAUDYmFsBwkA/AcEBQR0aGlzAgx1bnN0YWtlVG9rZW4JAMwIAgUKYXNzZXRJZFN0cgkAzAgCCQBlAgUFdG90YWwFA2JhbAUDbmlsBQNuaWwFBHVuaXQDCQAAAgUKdW5zdGFrZUludgUKdW5zdGFrZUludgQGbGlxdWlkCQEKZ2V0QmFsYW5jZQEFCmFzc2V0SWRTdHIEB3BheWFibGUJAJcDAQkAzAgCBQV0b3RhbAkAzAgCBQZsaXF1aWQFA25pbAQLcGF5SW50ZXJlc3QJAJcDAQkAzAgCCQCWAwEJAMwIAgUIaW50ZXJlc3QJAMwIAgAABQNuaWwJAMwIAgUHcGF5YWJsZQUDbmlsBAZwYXlTdGsJAJcDAQkAzAgCCQCWAwEJAMwIAgUDc3RrCQDMCAIAAAUDbmlsCQDMCAIJAGUCBQdwYXlhYmxlBQtwYXlJbnRlcmVzdAUDbmlsBAZwYXlMaXEJAJcDAQkAzAgCCQCWAwEJAMwIAgUDbGlxCQDMCAIAAAUDbmlsCQDMCAIJAGUCCQBlAgUHcGF5YWJsZQULcGF5SW50ZXJlc3QFBnBheVN0awUDbmlsBANwYXkJAGQCCQBkAgULcGF5SW50ZXJlc3QFBnBheVN0awUGcGF5TGlxAwkAZwIAAAUDcGF5BQNuaWwECXJlY29yZEludgkA/AcECQERQGV4dHJOYXRpdmUoMTA2MikBCQEFdmFsdWUBBRZmZWVDb2xsZWN0b3JBZGRyZXNzU3RyAgtwcm9jZXNzRmVlcwkAzAgCBQphc3NldElkU3RyCQDMCAIFC3BheUludGVyZXN0CQDMCAIFBnBheVN0awkAzAgCBQZwYXlMaXEFA25pbAkAzAgCCQEPQXR0YWNoZWRQYXltZW50AgkBDWdldEFzc2V0Qnl0ZXMBBQphc3NldElkU3RyBQNwYXkFA25pbAMJAAACBQlyZWNvcmRJbnYFCXJlY29yZEludgkAzAgCCQEMSW50ZWdlckVudHJ5AgkArAICCQCsAgICBGZlZV8FCmFzc2V0SWRTdHICCV9pbnRlcmVzdAkAZQIFCGludGVyZXN0BQtwYXlJbnRlcmVzdAkAzAgCCQEMSW50ZWdlckVudHJ5AgkArAICCQCsAgICBGZlZV8FCmFzc2V0SWRTdHICCF9zdGFraW5nCQBlAgUDc3RrBQZwYXlTdGsJAMwIAgkBDEludGVnZXJFbnRyeQIJAKwCAgkArAICAgRmZWVfBQphc3NldElkU3RyAgxfbGlxdWlkYXRpb24JAGUCBQNsaXEFBnBheUxpcQUDbmlsCQACAQIkU3RyaWN0IHZhbHVlIGlzIG5vdCBlcXVhbCB0byBpdHNlbGYuCQACAQIkU3RyaWN0IHZhbHVlIGlzIG5vdCBlcXVhbCB0byBpdHNlbGYuAWkBDGNsYWltRmVlc0FsbAEKdG9rZW5zTGlzdAQGdG9rZW5zAwkAAAIFCnRva2Vuc0xpc3QCAAkBD2dldE1hcmtldEFzc2V0cwAJALUJAgUKdG9rZW5zTGlzdAIBLAoBAWYCBWFjY3VtBXRva2VuBANpbnYJAPwHBAUEdGhpcwIJY2xhaW1GZWVzCQDMCAIFBXRva2VuBQNuaWwFA25pbAMJAAACBQNpbnYFA2ludgUFYWNjdW0JAAIBAiRTdHJpY3QgdmFsdWUgaXMgbm90IGVxdWFsIHRvIGl0c2VsZi4EBGRvbmUKAAIkbAUGdG9rZW5zCgACJHMJAJADAQUCJGwKAAUkYWNjMAUEdW5pdAoBBSRmMF8xAgIkYQIkaQMJAGcCBQIkaQUCJHMFAiRhCQEBZgIFAiRhCQCRAwIFAiRsBQIkaQoBBSRmMF8yAgIkYQIkaQMJAGcCBQIkaQUCJHMFAiRhCQACAQIUTGlzdCBzaXplIGV4Y2VlZHMgMTIJAQUkZjBfMgIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIFBSRhY2MwAAAAAQACAAMABAAFAAYABwAIAAkACgALAAwDCQAAAgUEZG9uZQUEZG9uZQUDbmlsCQACAQIkU3RyaWN0IHZhbHVlIGlzIG5vdCBlcXVhbCB0byBpdHNlbGYuAWkBFmNsYWltTGlxdWlkYXRvclJld2FyZHMBCmFzc2V0SWRTdHIEC2xpcVByb3h5U3RyCQELdmFsdWVPckVsc2UCCQCdCAIFBHRoaXMCHXNldHVwX2FkZHJlc3NfbGlxdWlkYXRvclByb3h5AgADCQAAAgULbGlxUHJveHlTdHICAAkAAgECH2xpcXVpZGF0b3IgcHJveHkgbm90IGNvbmZpZ3VyZWQDCQAAAgkAswkCCQEMdHJ5R2V0U3RyaW5nAQIMc2V0dXBfdG9rZW5zBQphc3NldElkU3RyBQR1bml0CQACAQIpdGhpcyBhc3NldCBpcyBub3Qgc3VwcG9ydGVkIGJ5IHRoZSBtYXJrZXQEBnJld2FyZAkBDXRyeUdldEludGVnZXIBCQCsAgICCmxpcVJld2FyZF8FCmFzc2V0SWRTdHIDCQBnAgAABQZyZXdhcmQFA25pbAQDYmFsCQEKZ2V0QmFsYW5jZQEFCmFzc2V0SWRTdHIECGlzU3Rha2VkCQECIT0CCQEMdHJ5R2V0U3RyaW5nAQkArAICAhBzZXR1cF9hdXRvc3Rha2VfBQphc3NldElkU3RyAgAECnVuc3Rha2VJbnYDAwUIaXNTdGFrZWQJAGYCBQZyZXdhcmQFA2JhbAcJAPwHBAUEdGhpcwIMdW5zdGFrZVRva2VuCQDMCAIFCmFzc2V0SWRTdHIJAMwIAgkAZQIFBnJld2FyZAUDYmFsBQNuaWwFA25pbAUEdW5pdAMJAAACBQp1bnN0YWtlSW52BQp1bnN0YWtlSW52BAZsaXF1aWQJAQpnZXRCYWxhbmNlAQUKYXNzZXRJZFN0cgQDcGF5CQCXAwEJAMwIAgUGcmV3YXJkCQDMCAIFBmxpcXVpZAUDbmlsAwkAZwIAAAUDcGF5BQNuaWwJAMwIAgkBDlNjcmlwdFRyYW5zZmVyAwkBEUBleHRyTmF0aXZlKDEwNjIpAQULbGlxUHJveHlTdHIFA3BheQkBDWdldEFzc2V0Qnl0ZXMBBQphc3NldElkU3RyCQDMCAIJAQxJbnRlZ2VyRW50cnkCCQCsAgICCmxpcVJld2FyZF8FCmFzc2V0SWRTdHIJAGUCBQZyZXdhcmQFA3BheQUDbmlsCQACAQIkU3RyaWN0IHZhbHVlIGlzIG5vdCBlcXVhbCB0byBpdHNlbGYuAWkBB3JlU2V0dXABCmFzc2V0SWRTdHIDBgkAAgECEFJlc2V0dXAgZGlzYWJsZWQEC2xhc3RSZXNldHVwCQENdHJ5R2V0SW50ZWdlcgECEnJlc2V0dXBfbGFzdFVwZGF0ZQMJAGYCBQlkYXlCbG9ja3MJAGUCBQZoZWlnaHQFC2xhc3RSZXNldHVwCQACAQIgY2FuIGJlIHVwZGF0ZWQgb25seSBvbmNlIHBlciBkYXkEA2x0cwkAtQkCCQEMdHJ5R2V0U3RyaW5nAQIJc2V0dXBfbHRzAgEsBAZhc3NldHMJAQ9nZXRNYXJrZXRBc3NldHMABAJ1cgkBBWdldFVyAQUKYXNzZXRJZFN0cgQGdGVtcExUCQENdHJ5R2V0SW50ZWdlcgEJAKwCAgkArAICAgZzZXR1cF8FCmFzc2V0SWRTdHICB190ZW1wTFQEAmx0CQENcGFyc2VJbnRWYWx1ZQEJAJEDAgUGYXNzZXRzCQEFdmFsdWUBCQDPCAIFBmFzc2V0cwUKYXNzZXRJZFN0cgMJAGYCBQJ1cgCAlfUqCQDMCAIJAQxJbnRlZ2VyRW50cnkCCQCsAgIJAKwCAgIGc2V0dXBfBQphc3NldElkU3RyAgdfdGVtcExUCQBrAwUGdGVtcExUAPdNAJBOBQNuaWwDAwkAZgIFAmx0BQZ0ZW1wTFQJAGYCAICV9SoFAnVyBwkAzAgCCQEMSW50ZWdlckVudHJ5AgkArAICCQCsAgICBnNldHVwXwUKYXNzZXRJZFN0cgIHX3RlbXBMVAkAawMFBnRlbXBMVACpTgCQTgUDbmlsBQNuaWwBaQEIc2h1dGRvd24BCHNodXRkb3duAwkAAAIJAM8IAgURc2h1dGRvd25XaGl0ZWxpc3QIBQFpBmNhbGxlcgUEdW5pdAkAAgECF3VzZXIgbm90IGluIGEgd2hpdGVsaXN0CQDMCAIJAQxCb29sZWFuRW50cnkCAgxzZXR1cF9hY3RpdmUJAQEhAQUIc2h1dGRvd24FA25pbAFpAQlsaXF1aWRhdGUGBWRlYnVnB2FkZHJlc3MLYXNzZXRBbW91bnQLc0Fzc2V0SWRTdHILYkFzc2V0SWRTdHIIcm91dGVTdHIDCQEBIQEJARZ2ZXJpZnlMaXF1aWRhdG9yUmlnaHRzAQgFAWkGY2FsbGVyCQACAQIodGVtcG9yYXJpbHkgYXZhaWxhYmxlIGZvciB3aGl0ZWxpc3Qgb25seQMJAQEhAQkBDXRyeUdldEJvb2xlYW4BAgxzZXR1cF9hY3RpdmUJAAIBAhFtYXJrZXQgaXMgc3RvcHBlZAQOdXNlckNvbGxhdGVyYWwJARJjYWxjVXNlckNvbGxhdGVyYWwBBQdhZGRyZXNzAwkAAAIFDnVzZXJDb2xsYXRlcmFsBQ51c2VyQ29sbGF0ZXJhbAQNJHQwNDAwOTY0MDE1OAkBDWdldEFjdHVhbFJhdGUCBQtzQXNzZXRJZFN0cgIFc1JhdGUEBXNSYXRlCAUNJHQwNDAwOTY0MDE1OAJfMQQLcmF0ZXNSZXN1bHQIBQ0kdDA0MDA5NjQwMTU4Al8yBA0kdDA0MDE2MzQwMjMyCQENZ2V0QWN0dWFsUmF0ZQIFC2JBc3NldElkU3RyAgViUmF0ZQQFYlJhdGUIBQ0kdDA0MDE2MzQwMjMyAl8xBBJyYXRlc1JlY2FsY1Jlc3VsdDIIBQ0kdDA0MDE2MzQwMjMyAl8yBAxzQXNzZXRBbW91bnQJAGsDBQthc3NldEFtb3VudAUHU2NhbGUxNgUFc1JhdGUEEGN1cnJlbnRTUG9zaXRpb24JAQ10cnlHZXRJbnRlZ2VyAQkArAICCQCsAgIFB2FkZHJlc3MCCl9zdXBwbGllZF8FC3NBc3NldElkU3RyBBNjdXJyZW50QlBvc2l0aW9uVmFsCQENdHJ5R2V0SW50ZWdlcgEJAKwCAgkArAICBQdhZGRyZXNzAgpfYm9ycm93ZWRfBQtiQXNzZXRJZFN0cgQQY3VycmVudEJQb3NpdGlvbgMJAGYCBRNjdXJyZW50QlBvc2l0aW9uVmFsAAAFE2N1cnJlbnRCUG9zaXRpb25WYWwJAAIBAiB1c2VyIGhhcyBubyBib3Jyb3cgaW4gdGhpcyB0b2tlbgMJAGYCBQ51c2VyQ29sbGF0ZXJhbAAACQACAQIYdXNlciBjYW4ndCBiZSBsaXF1aWRhdGVkAwkAZgIFDHNBc3NldEFtb3VudAUQY3VycmVudFNQb3NpdGlvbgkAAgECMnBvc2l0aW9uIHRvIGxpcXVpZGF0ZSBpcyBiaWdnZXIgdGhhbiB1c2VyJ3Mgc3VwcGx5BANpbnYDCQECIT0CCQEMdHJ5R2V0U3RyaW5nAQkArAICAhBzZXR1cF9hdXRvc3Rha2VfBQtzQXNzZXRJZFN0cgIACQD8BwQFBHRoaXMCDHVuc3Rha2VUb2tlbgkAzAgCBQtzQXNzZXRJZFN0cgkAzAgCBQthc3NldEFtb3VudAUDbmlsBQNuaWwFBHVuaXQDCQAAAgUDaW52BQNpbnYEDmJhbGFuY2UwQmVmb3JlCQEKZ2V0QmFsYW5jZQEFC3NBc3NldElkU3RyAwkAAAIFDmJhbGFuY2UwQmVmb3JlBQ5iYWxhbmNlMEJlZm9yZQQOYmFsYW5jZTFCZWZvcmUJAQpnZXRCYWxhbmNlAQULYkFzc2V0SWRTdHIDCQAAAgUOYmFsYW5jZTFCZWZvcmUFDmJhbGFuY2UxQmVmb3JlBA5leGNoYW5nZUludm9rZQkA/AcEBRFhZ2dyZWdhdG9yQWRkcmVzcwIEc3dhcAkAzAgCBQhyb3V0ZVN0cgkAzAgCAAAFA25pbAkAzAgCCQEPQXR0YWNoZWRQYXltZW50AgkBDWdldEFzc2V0Qnl0ZXMBBQtzQXNzZXRJZFN0cgULYXNzZXRBbW91bnQFA25pbAMJAAACBQ5leGNoYW5nZUludm9rZQUOZXhjaGFuZ2VJbnZva2UECmFzc2V0MFNvbGQJAGUCBQ5iYWxhbmNlMEJlZm9yZQkBCmdldEJhbGFuY2UBBQtzQXNzZXRJZFN0cgMJAAACBQphc3NldDBTb2xkBQphc3NldDBTb2xkBAxhc3NldDFCb3VnaHQJAGUCCQEKZ2V0QmFsYW5jZQEFC2JBc3NldElkU3RyBQ5iYWxhbmNlMUJlZm9yZQMJAAACBQxhc3NldDFCb3VnaHQFDGFzc2V0MUJvdWdodAQLYXNzZXQwUHJpY2UICQETZ2V0VG9rZW5QcmljZUNhcHBlZAEFC3NBc3NldElkU3RyAl8xBAthc3NldDBTY2FsZQkBDmNhbGNBc3NldFNjYWxlAQULc0Fzc2V0SWRTdHIECWFzc2V0MFVzZAkAawMFCmFzc2V0MFNvbGQFC2Fzc2V0MFByaWNlBQthc3NldDBTY2FsZQQLYXNzZXQxUHJpY2UICQETZ2V0VG9rZW5QcmljZUNhcHBlZAEFC2JBc3NldElkU3RyAl8yBAthc3NldDFTY2FsZQkBDmNhbGNBc3NldFNjYWxlAQULYkFzc2V0SWRTdHIECWFzc2V0MVVzZAkAawMFDGFzc2V0MUJvdWdodAULYXNzZXQxUHJpY2UFC2Fzc2V0MVNjYWxlBAdwZW5hbHR5CQENcGFyc2VJbnRWYWx1ZQEJAJEDAgkAtQkCCQEMdHJ5R2V0U3RyaW5nAQIPc2V0dXBfcGVuYWx0aWVzAgEsCQEFdmFsdWUBCQDPCAIJAQ9nZXRNYXJrZXRBc3NldHMABQtiQXNzZXRJZFN0cgQRbGlxdWlkYXRpb25Qcm9maXQJAGUCBQlhc3NldDFVc2QJAGsDBQlhc3NldDBVc2QJAGUCBQZTY2FsZTgFB3BlbmFsdHkFBlNjYWxlOAQMc0Fzc2V0Q2hhbmdlCQBrAwUKYXNzZXQwU29sZAUHU2NhbGUxNgUFc1JhdGUEDGJBc3NldENoYW5nZQkAawMJAGsDBQxhc3NldDFCb3VnaHQFB1NjYWxlMTYFBWJSYXRlCQBlAgUGU2NhbGU4CQBrAwURbGlxdWlkYXRpb25Qcm9maXQFBlNjYWxlOAUJYXNzZXQxVXNkBQZTY2FsZTgEDXBlbmFsdHlUb2tlbnMJAGUCBQxhc3NldDFCb3VnaHQJAGsDBQxiQXNzZXRDaGFuZ2UFBWJSYXRlBQdTY2FsZTE2BAtsaXFQcm94eVN0cgkBC3ZhbHVlT3JFbHNlAgkAnQgCBQR0aGlzAh1zZXR1cF9hZGRyZXNzX2xpcXVpZGF0b3JQcm94eQIABA9saXF1aWRhdG9yU2hhcmUDAwkBAiE9AgULbGlxUHJveHlTdHICAAkAAAIJAKUIAQgFAWkGY2FsbGVyBQtsaXFQcm94eVN0cgcJAJcDAQkAzAgCCQCWAwEJAMwIAgkBC3ZhbHVlT3JFbHNlAgkAmggCCQERQGV4dHJOYXRpdmUoMTA2MikBBQtsaXFQcm94eVN0cgISc2V0dXBfcGVuYWx0eVNoYXJlAAAJAMwIAgAABQNuaWwJAMwIAgCQTgUDbmlsAAAEDmxpcXVpZGF0b3JQYXJ0CQBrAwUNcGVuYWx0eVRva2VucwUPbGlxdWlkYXRvclNoYXJlAJBOAwkAZgIFCmFzc2V0MFNvbGQFC2Fzc2V0QW1vdW50CQACAQIjbW9yZSBhc3NldHMgZXhjaGFuZ2VkIHRoYW4gZXhwZWN0ZWQDCQBmAgAABRFsaXF1aWRhdGlvblByb2ZpdAkAAgECL3ByaWNlIGltcGFjdCBpcyBiaWdnZXIgdGhhbiBsaXF1aWRhdGlvbiBwZW5hbHR5AwkAZgIFDGJBc3NldENoYW5nZQUQY3VycmVudEJQb3NpdGlvbgkAAgECJGRlYnQgcmVkdWN0aW9uIGV4Y2VlZHMgdXNlcidzIGJvcnJvdwkAlAoCCQDOCAIJAMwIAgkBDEludGVnZXJFbnRyeQIJAKwCAgkArAICBQdhZGRyZXNzAgpfc3VwcGxpZWRfBQtzQXNzZXRJZFN0cgkAZQIFEGN1cnJlbnRTUG9zaXRpb24FDHNBc3NldENoYW5nZQkAzAgCCQEMSW50ZWdlckVudHJ5AgkArAICCQCsAgIFB2FkZHJlc3MCCl9ib3Jyb3dlZF8FC2JBc3NldElkU3RyCQBlAgUQY3VycmVudEJQb3NpdGlvbgUMYkFzc2V0Q2hhbmdlCQDMCAIJAQxJbnRlZ2VyRW50cnkCCQCsAgICD3RvdGFsX3N1cHBsaWVkXwULc0Fzc2V0SWRTdHIJAGUCCQENdHJ5R2V0SW50ZWdlcgEJAKwCAgIPdG90YWxfc3VwcGxpZWRfBQtzQXNzZXRJZFN0cgUMc0Fzc2V0Q2hhbmdlCQDMCAIJAQxJbnRlZ2VyRW50cnkCCQCsAgICD3RvdGFsX2JvcnJvd2VkXwULYkFzc2V0SWRTdHIJAGUCCQENdHJ5R2V0SW50ZWdlcgEJAKwCAgIPdG90YWxfYm9ycm93ZWRfBQtiQXNzZXRJZFN0cgUMYkFzc2V0Q2hhbmdlCQDMCAIJAQxJbnRlZ2VyRW50cnkCCQCsAgIJAKwCAgIEZmVlXwULYkFzc2V0SWRTdHICDF9saXF1aWRhdGlvbgkAZAIJAQ10cnlHZXRJbnRlZ2VyAQkArAICCQCsAgICBGZlZV8FC2JBc3NldElkU3RyAgxfbGlxdWlkYXRpb24JAGUCBQ1wZW5hbHR5VG9rZW5zBQ5saXF1aWRhdG9yUGFydAUDbmlsAwkAZgIFDmxpcXVpZGF0b3JQYXJ0AAAJAMwIAgkBDEludGVnZXJFbnRyeQIJAKwCAgIKbGlxUmV3YXJkXwULYkFzc2V0SWRTdHIJAGQCCQENdHJ5R2V0SW50ZWdlcgEJAKwCAgIKbGlxUmV3YXJkXwULYkFzc2V0SWRTdHIFDmxpcXVpZGF0b3JQYXJ0BQNuaWwFA25pbAUObGlxdWlkYXRvclBhcnQJAAIBAiRTdHJpY3QgdmFsdWUgaXMgbm90IGVxdWFsIHRvIGl0c2VsZi4JAAIBAiRTdHJpY3QgdmFsdWUgaXMgbm90IGVxdWFsIHRvIGl0c2VsZi4JAAIBAiRTdHJpY3QgdmFsdWUgaXMgbm90IGVxdWFsIHRvIGl0c2VsZi4JAAIBAiRTdHJpY3QgdmFsdWUgaXMgbm90IGVxdWFsIHRvIGl0c2VsZi4JAAIBAiRTdHJpY3QgdmFsdWUgaXMgbm90IGVxdWFsIHRvIGl0c2VsZi4JAAIBAiRTdHJpY3QgdmFsdWUgaXMgbm90IGVxdWFsIHRvIGl0c2VsZi4JAAIBAiRTdHJpY3QgdmFsdWUgaXMgbm90IGVxdWFsIHRvIGl0c2VsZi4BaQELbGlxdWlkYXRlVjIDBWRlYnVnB2FkZHJlc3MLc0Fzc2V0SWRTdHIDCQEBIQEJARZ2ZXJpZnlMaXF1aWRhdG9yUmlnaHRzAQgFAWkGY2FsbGVyCQACAQIodGVtcG9yYXJpbHkgYXZhaWxhYmxlIGZvciB3aGl0ZWxpc3Qgb25seQMJAQEhAQkBDXRyeUdldEJvb2xlYW4BAgxzZXR1cF9hY3RpdmUJAAIBAhFtYXJrZXQgaXMgc3RvcHBlZAMJAQIhPQIJAJADAQgFAWkIcGF5bWVudHMAAQkAAgECJGV4YWN0bHkgMSBwYXltZW50IGhhcyB0byBiZSBhdHRhY2hlZAQIYkFzc2V0SWQICQCRAwIIBQFpCHBheW1lbnRzAAAHYXNzZXRJZAQLYkFzc2V0SWRTdHIJAQ5nZXRBc3NldFN0cmluZwEFCGJBc3NldElkBAxiQXNzZXRBbW91bnQICQCRAwIIBQFpCHBheW1lbnRzAAAGYW1vdW50BA51c2VyQ29sbGF0ZXJhbAkBEmNhbGNVc2VyQ29sbGF0ZXJhbAEFB2FkZHJlc3MDCQAAAgUOdXNlckNvbGxhdGVyYWwFDnVzZXJDb2xsYXRlcmFsAwkAZgIFDnVzZXJDb2xsYXRlcmFsAAAJAAIBAhh1c2VyIGNhbid0IGJlIGxpcXVpZGF0ZWQEDG1hcmtldEFzc2V0cwkBD2dldE1hcmtldEFzc2V0cwAECWFzc2V0MU51bQkBBXZhbHVlAQkAzwgCBQxtYXJrZXRBc3NldHMFC2JBc3NldElkU3RyBAlhc3NldDBOdW0JAQV2YWx1ZQEJAM8IAgUMbWFya2V0QXNzZXRzBQtzQXNzZXRJZFN0cgQNJHQwNDYzNzc0NjQzOQkBDWdldEFjdHVhbFJhdGUCBQtiQXNzZXRJZFN0cgIFYlJhdGUEBWJSYXRlCAUNJHQwNDYzNzc0NjQzOQJfMQQLcmF0ZXNSZXN1bHQIBQ0kdDA0NjM3NzQ2NDM5Al8yBBBjdXJyZW50U1Bvc2l0aW9uCQENdHJ5R2V0SW50ZWdlcgEJAKwCAgkArAICBQdhZGRyZXNzAgpfc3VwcGxpZWRfBQtzQXNzZXRJZFN0cgQTY3VycmVudEJQb3NpdGlvblZhbAkBDXRyeUdldEludGVnZXIBCQCsAgIJAKwCAgUHYWRkcmVzcwIKX2JvcnJvd2VkXwULYkFzc2V0SWRTdHIEEGN1cnJlbnRCUG9zaXRpb24DCQBmAgUTY3VycmVudEJQb3NpdGlvblZhbAAABRNjdXJyZW50QlBvc2l0aW9uVmFsCQACAQIgdXNlciBoYXMgbm8gYm9ycm93IGluIHRoaXMgdG9rZW4ECmJBbW91bnRSYXcJAGsDBQxiQXNzZXRBbW91bnQFB1NjYWxlMTYFBWJSYXRlBAdiQW1vdW50CQCXAwEJAMwIAgUKYkFtb3VudFJhdwkAzAgCBRBjdXJyZW50QlBvc2l0aW9uBQNuaWwED2JBc3NldEFtb3VudEVmZgMJAGcCBRBjdXJyZW50QlBvc2l0aW9uBQpiQW1vdW50UmF3BQxiQXNzZXRBbW91bnQJAG4EBQdiQW1vdW50BQViUmF0ZQUHU2NhbGUxNgUHQ0VJTElORwQGcmVmdW5kCQBlAgUMYkFzc2V0QW1vdW50BQ9iQXNzZXRBbW91bnRFZmYEC2Fzc2V0MVByaWNlCAkBE2dldFRva2VuUHJpY2VDYXBwZWQBBQtiQXNzZXRJZFN0cgJfMgQLYXNzZXQxU2NhbGUJAQ5jYWxjQXNzZXRTY2FsZQEFC2JBc3NldElkU3RyBApiQW1vdW50VXNkCQBrAwUPYkFzc2V0QW1vdW50RWZmBQthc3NldDFQcmljZQULYXNzZXQxU2NhbGUEB3BlbmFsdHkJAQ1wYXJzZUludFZhbHVlAQkBBXZhbHVlAQkAkQMCCQC1CQIJAQx0cnlHZXRTdHJpbmcBAg9zZXR1cF9wZW5hbHRpZXMCASwFCWFzc2V0MU51bQQLYXNzZXQwUHJpY2UICQETZ2V0VG9rZW5QcmljZUNhcHBlZAEFC3NBc3NldElkU3RyAl8xBAthc3NldDBTY2FsZQkBDmNhbGNBc3NldFNjYWxlAQULc0Fzc2V0SWRTdHIECnNBbW91bnRVc2QJAGsDBQpiQW1vdW50VXNkCQBkAgUGU2NhbGU4BQdwZW5hbHR5BQZTY2FsZTgEDHNBc3NldEFtb3VudAkAawMFCnNBbW91bnRVc2QFC2Fzc2V0MFNjYWxlBQthc3NldDBQcmljZQQHc0Ftb3VudAkAawMFDHNBc3NldEFtb3VudAUHU2NhbGUxNggJAJEDAgULcmF0ZXNSZXN1bHQJAGgCBQlhc3NldDBOdW0AAwV2YWx1ZQMJAGYCBQdzQW1vdW50BRBjdXJyZW50U1Bvc2l0aW9uCQACAQIycG9zaXRpb24gdG8gbGlxdWlkYXRlIGlzIGJpZ2dlciB0aGFuIHVzZXIncyBzdXBwbHkEA2ludgMJAQIhPQIJAQx0cnlHZXRTdHJpbmcBCQCsAgICEHNldHVwX2F1dG9zdGFrZV8FC3NBc3NldElkU3RyAgAJAPwHBAUEdGhpcwIMdW5zdGFrZVRva2VuCQDMCAIFC3NBc3NldElkU3RyCQDMCAIFDHNBc3NldEFtb3VudAUDbmlsBQNuaWwFBHVuaXQDCQAAAgUDaW52BQNpbnYDBQVkZWJ1ZwkAAgECFWxpcXVpZGF0aW9uIHdpbGwgcGFzcwkAzggCCQDOCAIJAMwIAgkBDlNjcmlwdFRyYW5zZmVyAwgFAWkGY2FsbGVyBQxzQXNzZXRBbW91bnQJAQ1nZXRBc3NldEJ5dGVzAQULc0Fzc2V0SWRTdHIJAMwIAgkBDEludGVnZXJFbnRyeQIJAKwCAgkArAICBQdhZGRyZXNzAgpfc3VwcGxpZWRfBQtzQXNzZXRJZFN0cgkAZQIFEGN1cnJlbnRTUG9zaXRpb24FB3NBbW91bnQJAMwIAgkBDEludGVnZXJFbnRyeQIJAKwCAgkArAICBQdhZGRyZXNzAgpfYm9ycm93ZWRfBQtiQXNzZXRJZFN0cgkAZQIFEGN1cnJlbnRCUG9zaXRpb24FB2JBbW91bnQJAMwIAgkBDEludGVnZXJFbnRyeQIJAKwCAgIPdG90YWxfc3VwcGxpZWRfBQtzQXNzZXRJZFN0cgkAZQIJAQ10cnlHZXRJbnRlZ2VyAQkArAICAg90b3RhbF9zdXBwbGllZF8FC3NBc3NldElkU3RyBQdzQW1vdW50CQDMCAIJAQxJbnRlZ2VyRW50cnkCCQCsAgICD3RvdGFsX2JvcnJvd2VkXwULYkFzc2V0SWRTdHIJAGUCCQENdHJ5R2V0SW50ZWdlcgEJAKwCAgIPdG90YWxfYm9ycm93ZWRfBQtiQXNzZXRJZFN0cgUHYkFtb3VudAUDbmlsBQtyYXRlc1Jlc3VsdAMJAGYCBQZyZWZ1bmQAAAkAzAgCCQEOU2NyaXB0VHJhbnNmZXIDCAUBaQZjYWxsZXIFBnJlZnVuZAUIYkFzc2V0SWQFA25pbAUDbmlsCQACAQIkU3RyaWN0IHZhbHVlIGlzIG5vdCBlcXVhbCB0byBpdHNlbGYuCQACAQIkU3RyaWN0IHZhbHVlIGlzIG5vdCBlcXVhbCB0byBpdHNlbGYuAWkBEWdldFVzZXJDb2xsYXRlcmFsBAVkZWJ1ZwdhZGRyZXNzDW1pbnVzQm9ycm93ZWQLYWZ0ZXJDaGFuZ2UEBmFzc2V0cwkBD2dldE1hcmtldEFzc2V0cwAEBGx0dnMJALUJAgkBDHRyeUdldFN0cmluZwECCnNldHVwX2x0dnMCASwEA2x0cwkAtQkCCQEMdHJ5R2V0U3RyaW5nAQIJc2V0dXBfbHRzAgEsBAVyYXRlcwgJAQ1nZXRBY3R1YWxSYXRlAgkAkQMCBQZhc3NldHMAAAIFc1JhdGUCXzIEDWNoYW5nZUhhbmRsZXIJALUJAgULYWZ0ZXJDaGFuZ2UCASwKAQFmAgVhY2N1bQRuZXh0AwkAZwIFBG5leHQJAJADAQUGYXNzZXRzBQVhY2N1bQQMdXNlclN1cHBsaWVkCQENdHJ5R2V0SW50ZWdlcgEJAKwCAgkArAICBQdhZGRyZXNzAgpfc3VwcGxpZWRfCQCRAwIFBmFzc2V0cwUEbmV4dAQMdXNlckJvcnJvd2VkCQENdHJ5R2V0SW50ZWdlcgEJAKwCAgkArAICBQdhZGRyZXNzAgpfYm9ycm93ZWRfCQCRAwIFBmFzc2V0cwUEbmV4dAQTbmVlZFRva2VuQWNjb3VudGluZwMJAAACBQthZnRlckNoYW5nZQIAAwMJAQIhPQIFDHVzZXJCb3Jyb3dlZAAABgkBAiE9AgUMdXNlclN1cHBsaWVkAAAGBwYDBRNuZWVkVG9rZW5BY2NvdW50aW5nBAphc3NldFNjYWxlCQEOY2FsY0Fzc2V0U2NhbGUBCQCRAwIFBmFzc2V0cwUEbmV4dAQKYXNzZXRQcmljZQkBFmdldFRva2VuUHJpY2VGb3JIZWFsdGgBCQCRAwIFBmFzc2V0cwUEbmV4dAkAZQIJAGQCBQVhY2N1bQkAawMJAGsDCQBrAwkAZAIFDHVzZXJTdXBwbGllZAMDAwkBAiE9AgULYWZ0ZXJDaGFuZ2UCAAkAAAIJAJEDAgUNY2hhbmdlSGFuZGxlcgAACQCRAwIFBmFzc2V0cwUEbmV4dAcJAAACCQCRAwIFDWNoYW5nZUhhbmRsZXIAAQIIc3VwcGxpZWQHCQENcGFyc2VJbnRWYWx1ZQEJAJEDAgUNY2hhbmdlSGFuZGxlcgACAAAICQCRAwIFBXJhdGVzCQBoAgUEbmV4dAADBXZhbHVlBQdTY2FsZTE2CQENcGFyc2VJbnRWYWx1ZQEJAJEDAgUEbHR2cwUEbmV4dAUGU2NhbGU4CAUKYXNzZXRQcmljZQJfMQUKYXNzZXRTY2FsZQMFDW1pbnVzQm9ycm93ZWQJAGsDCQBrAwkAawMJAGQCBQx1c2VyQm9ycm93ZWQDAwMJAQIhPQIFC2FmdGVyQ2hhbmdlAgAJAAACCQCRAwIFDWNoYW5nZUhhbmRsZXIAAAkAkQMCBQZhc3NldHMFBG5leHQHCQAAAgkAkQMCBQ1jaGFuZ2VIYW5kbGVyAAECCGJvcnJvd2VkBwkBDXBhcnNlSW50VmFsdWUBCQCRAwIFDWNoYW5nZUhhbmRsZXIAAgAACAkAkQMCBQVyYXRlcwkAZAIJAGgCBQRuZXh0AAMAAQV2YWx1ZQUHU2NhbGUxNgUGU2NhbGU4CQENcGFyc2VJbnRWYWx1ZQEJAJEDAgUDbHRzBQRuZXh0CAUKYXNzZXRQcmljZQJfMgUKYXNzZXRTY2FsZQAABQVhY2N1bQQGcmVzdWx0CgACJGwJAMwIAgAACQDMCAIAAQkAzAgCAAIJAMwIAgADCQDMCAIABAkAzAgCAAUJAMwIAgAGCQDMCAIABwkAzAgCAAgJAMwIAgAJCQDMCAIACgkAzAgCAAsFA25pbAoAAiRzCQCQAwEFAiRsCgAFJGFjYzAAAAoBBSRmMF8xAgIkYQIkaQMJAGcCBQIkaQUCJHMFAiRhCQEBZgIFAiRhCQCRAwIFAiRsBQIkaQoBBSRmMF8yAgIkYQIkaQMJAGcCBQIkaQUCJHMFAiRhCQACAQIUTGlzdCBzaXplIGV4Y2VlZHMgMTIJAQUkZjBfMgIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIFBSRhY2MwAAAAAQACAAMABAAFAAYABwAIAAkACgALAAwDBQVkZWJ1ZwkAAgEJAKQDAQUGcmVzdWx0CQCUCgIFBXJhdGVzBQZyZXN1bHQBaQEJZ2V0UHJpY2VzAQVkZWJ1ZwQGYXNzZXRzCQEPZ2V0TWFya2V0QXNzZXRzAAoBAWYCBWFjY3VtBG5leHQDCQBnAgUEbmV4dAkAkAMBBQZhc3NldHMFBWFjY3VtBAphc3NldFByaWNlCQEVZ2V0VG9rZW5QcmljZVdpdGhSaXNrAgkAkQMCBQZhc3NldHMFBG5leHQAAwkArAICCQCsAgIJAKwCAgkArAICBQVhY2N1bQkApAMBCAUKYXNzZXRQcmljZQJfMQIBLAkApAMBCAUKYXNzZXRQcmljZQJfMgIBfAQGcmVzdWx0CgACJGwJAMwIAgAACQDMCAIAAQkAzAgCAAIJAMwIAgADCQDMCAIABAkAzAgCAAUJAMwIAgAGCQDMCAIABwkAzAgCAAgJAMwIAgAJCQDMCAIACgkAzAgCAAsFA25pbAoAAiRzCQCQAwEFAiRsCgAFJGFjYzACAAoBBSRmMF8xAgIkYQIkaQMJAGcCBQIkaQUCJHMFAiRhCQEBZgIFAiRhCQCRAwIFAiRsBQIkaQoBBSRmMF8yAgIkYQIkaQMJAGcCBQIkaQUCJHMFAiRhCQACAQIUTGlzdCBzaXplIGV4Y2VlZHMgMTIJAQUkZjBfMgIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIFBSRhY2MwAAAAAQACAAMABAAFAAYABwAIAAkACgALAAwDBQVkZWJ1ZwkAAgEFBnJlc3VsdAkAlAoCBQNuaWwFBnJlc3VsdAFpARljYWxjdWxhdGVVdGlsaXphdGlvblJhdGlvAgphc3NldElkU3RyBWRlYnVnAwUFZGVidWcJAAIBCQCkAwEJAQVnZXRVcgEFCmFzc2V0SWRTdHIJAJQKAgUDbmlsCQEFZ2V0VXIBBQphc3NldElkU3RyAWkBE2NhbGN1bGF0ZU91dGRhdGVkVVICCmFzc2V0SWRTdHIFZGVidWcDBQVkZWJ1ZwkAAgEJAKQDAQkBDWdldE91dGRhdGVkVXIBBQphc3NldElkU3RyCQCUCgIFA25pbAkBDWdldE91dGRhdGVkVXIBBQphc3NldElkU3RyAWkBE2NhbGN1bGF0ZVRva2VuUmF0ZXMBBWRlYnVnCgEBZgIFYWNjdW0KYXNzZXRJZFN0cgQFcmF0ZXMJARB0b2tlblJhdGVzUmVjYWxjAQUKYXNzZXRJZFN0cgQJbGFzdEJSYXRlCQCWAwEJAMwIAgkBDXRyeUdldEludGVnZXIBCQCsAgIFCmFzc2V0SWRTdHICBl9iUmF0ZQkAzAgCBQdTY2FsZTE2BQNuaWwECGZlZURlbHRhCQBrAwULcmVzZXJ2ZUZ1bmQJAGsDCQENdHJ5R2V0SW50ZWdlcgEJAKwCAgIPdG90YWxfYm9ycm93ZWRfBQphc3NldElkU3RyCQBlAggJAJEDAgUFcmF0ZXMAAQV2YWx1ZQUJbGFzdEJSYXRlBQdTY2FsZTE2AGQECGZlZUVudHJ5CQEMSW50ZWdlckVudHJ5AgkArAICCQCsAgICBGZlZV8FCmFzc2V0SWRTdHICCV9pbnRlcmVzdAkAZAIJAQ10cnlHZXRJbnRlZ2VyAQkArAICCQCsAgICBGZlZV8FCmFzc2V0SWRTdHICCV9pbnRlcmVzdAUIZmVlRGVsdGEJAJUKAwkArAICCQCsAgIJAKwCAgkArAICCAUFYWNjdW0CXzEJAKQDAQgJAJEDAgUFcmF0ZXMAAQV2YWx1ZQIBfAkApAMBCAkAkQMCBQVyYXRlcwAABXZhbHVlAgEsCQDOCAIIBQVhY2N1bQJfMgUFcmF0ZXMJAM4IAggFBWFjY3VtAl8zCQDMCAIFCGZlZUVudHJ5BQNuaWwECXBhcmFtZXRlcgoAAiRsCQEPZ2V0TWFya2V0QXNzZXRzAAoAAiRzCQCQAwEFAiRsCgAFJGFjYzAJAJUKAwIABQNuaWwFA25pbAoBBSRmMF8xAgIkYQIkaQMJAGcCBQIkaQUCJHMFAiRhCQEBZgIFAiRhCQCRAwIFAiRsBQIkaQoBBSRmMF8yAgIkYQIkaQMJAGcCBQIkaQUCJHMFAiRhCQACAQIUTGlzdCBzaXplIGV4Y2VlZHMgMTIJAQUkZjBfMgIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIFBSRhY2MwAAAAAQACAAMABAAFAAYABwAIAAkACgALAAwDBQVkZWJ1ZwkAAgEIBQlwYXJhbWV0ZXICXzEJAJQKAgkAzggCCAUJcGFyYW1ldGVyAl8yCAUJcGFyYW1ldGVyAl8zCAUJcGFyYW1ldGVyAl8xAWkBF2NhbGN1bGF0ZVRva2Vuc0ludGVyZXN0AQVkZWJ1ZwoBAWYCBWFjY3VtCmFzc2V0SWRTdHIEBHJhdGUJAGsDCQELZ2V0SW50ZXJlc3QBBQphc3NldElkU3RyBQlkYXlCbG9ja3MFBlNjYWxlOAkArAICCQCsAgIFBWFjY3VtCQCkAwEFBHJhdGUCASwECXBhcmFtZXRlcgoAAiRsCQEPZ2V0TWFya2V0QXNzZXRzAAoAAiRzCQCQAwEFAiRsCgAFJGFjYzACAAoBBSRmMF8xAgIkYQIkaQMJAGcCBQIkaQUCJHMFAiRhCQEBZgIFAiRhCQCRAwIFAiRsBQIkaQoBBSRmMF8yAgIkYQIkaQMJAGcCBQIkaQUCJHMFAiRhCQACAQIUTGlzdCBzaXplIGV4Y2VlZHMgMTIJAQUkZjBfMgIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIFBSRhY2MwAAAAAQACAAMABAAFAAYABwAIAAkACgALAAwDBQVkZWJ1ZwkAAgEFCXBhcmFtZXRlcgkAlAoCBQNuaWwFCXBhcmFtZXRlcgFpARJzZXRBcHByb3ZlckFkZHJlc3MBD2FwcHJvdmVyQWRkcmVzcwQGaXNTZWxmAwkAAAIIBQFpBmNhbGxlcgUEdGhpcwYJAAIBAhBPbmx5IHNlbGYgaW52b2tlAwkAAAIFBmlzU2VsZgUGaXNTZWxmBBBfYXBwcm92ZXJBZGRyZXNzCQCmCAEFD2FwcHJvdmVyQWRkcmVzcwQKYXBwcm92ZXJPawQHJG1hdGNoMAUQX2FwcHJvdmVyQWRkcmVzcwMJAAECBQckbWF0Y2gwAgdBZGRyZXNzBAF0BQckbWF0Y2gwBgcEDmNhblNldEFwcHJvdmVyAwMFCmFwcHJvdmVyT2sGCQAAAgUPYXBwcm92ZXJBZGRyZXNzAgAGCQACAQIWV3JvbmcgYXBwcm92ZXIgYWRkcmVzcwMJAAACBQ5jYW5TZXRBcHByb3ZlcgUOY2FuU2V0QXBwcm92ZXIECGlzSW5pdGVkCQELdmFsdWVPckVsc2UCCQCbCAIJAQV2YWx1ZQEFEF9hcHByb3ZlckFkZHJlc3MCBklOSVRFRAcECWhhc0FkbWlucwkBAiE9AgkBC3ZhbHVlT3JFbHNlAgkAnQgCCQEFdmFsdWUBBRBfYXBwcm92ZXJBZGRyZXNzAgtBRE1JTlNfUEJLUwIAAgAEEmlzQXBwcm92ZXJDb250cmFjdAMDCQAAAgUPYXBwcm92ZXJBZGRyZXNzAgAGAwUIaXNJbml0ZWQFCWhhc0FkbWlucwcGCQACAQIgQWRkcmVzcyBpcyBub3QgYXBwcm92ZXIgY29udHJhY3QDCQAAAgUSaXNBcHByb3ZlckNvbnRyYWN0BRJpc0FwcHJvdmVyQ29udHJhY3QJAMwIAgkBC1N0cmluZ0VudHJ5AgIQQVBQUk9WRVJfQUREUkVTUwUPYXBwcm92ZXJBZGRyZXNzBQNuaWwJAAIBAiRTdHJpY3QgdmFsdWUgaXMgbm90IGVxdWFsIHRvIGl0c2VsZi4JAAIBAiRTdHJpY3QgdmFsdWUgaXMgbm90IGVxdWFsIHRvIGl0c2VsZi4JAAIBAiRTdHJpY3QgdmFsdWUgaXMgbm90IGVxdWFsIHRvIGl0c2VsZi4BaQENaW5pdE5ld01hc3RlcgEGbWFzdGVyBAlhZGRyZXNzT0sEByRtYXRjaDAJAKYIAQUGbWFzdGVyAwkAAQIFByRtYXRjaDACB0FkZHJlc3MEAWEFByRtYXRjaDAGBwMJAQEhAQUJYWRkcmVzc09LCQACAQkArAICAhJpbmNvcnJlY3QgYWRkcmVzcyAFBm1hc3RlcgMJAQIhPQIIBQFpBmNhbGxlcgUEdGhpcwkAAgECHGF2YWlsYWJsZSBmb3Igc2VsZiBjYWxsIG9ubHkJAMwIAgkBC1N0cmluZ0VudHJ5AgIPdmVyaWZpZXJfbWFzdGVyBQZtYXN0ZXIFA25pbAFpARByZXF1ZXN0TmV3TWFzdGVyAQluZXdNYXN0ZXIECWFkZHJlc3NPSwQHJG1hdGNoMAkApggBBQluZXdNYXN0ZXIDCQABAgUHJG1hdGNoMAIHQWRkcmVzcwQBYQUHJG1hdGNoMAYHAwkBASEBBQlhZGRyZXNzT0sJAAIBCQCsAgICEmluY29ycmVjdCBhZGRyZXNzIAUJbmV3TWFzdGVyAwkAAAIJAM8IAgUJc2VudGluZWxzCAUBaQZjYWxsZXIFBHVuaXQJAAIBAg53aGl0ZWxpc3Qgb25seQkAzAgCCQELU3RyaW5nRW50cnkCAhJ2ZXJpZmllcl9uZXdNYXN0ZXIFCW5ld01hc3RlcgkAzAgCCQEMSW50ZWdlckVudHJ5AgIfdmVyaWZpZXJfbmV3TWFzdGVyRWxpZ2libGVBZnRlcgkAZAIFBmhlaWdodACQTgUDbmlsAWkBEWFjdGl2YXRlTmV3TWFzdGVyAAQOZWxpZ2libGVIZWlnaHQJARFAZXh0ck5hdGl2ZSgxMDUwKQIFBHRoaXMCH3ZlcmlmaWVyX25ld01hc3RlckVsaWdpYmxlQWZ0ZXIECW5ld01hc3RlcgkBEUBleHRyTmF0aXZlKDEwNTMpAgUEdGhpcwISdmVyaWZpZXJfbmV3TWFzdGVyAwkAAAIJAM8IAgUJc2VudGluZWxzCAUBaQZjYWxsZXIFBHVuaXQJAAIBAg53aGl0ZWxpc3Qgb25seQMJAGYCBQ5lbGlnaWJsZUhlaWdodAUGaGVpZ2h0CQACAQIibmV3IG1hc3RlciBjYW5ub3QgYmUgYWN0aXZhdGVkIHlldAkAzAgCCQELRGVsZXRlRW50cnkBAhJ2ZXJpZmllcl9uZXdNYXN0ZXIJAMwIAgkBC0RlbGV0ZUVudHJ5AQIfdmVyaWZpZXJfbmV3TWFzdGVyRWxpZ2libGVBZnRlcgkAzAgCCQELU3RyaW5nRW50cnkCAg92ZXJpZmllcl9tYXN0ZXIFCW5ld01hc3RlcgUDbmlsAQJ0eAEGdmVyaWZ5AAQLbXVsdGlzaWdTdHIJAQt2YWx1ZU9yRWxzZQIJAKIIAQIQQVBQUk9WRVJfQUREUkVTUwIABA9tdWx0aXNpZ0FkZHJlc3MJAKYIAQULbXVsdGlzaWdTdHIECm11bHRpc2lnT2sEByRtYXRjaDAFD211bHRpc2lnQWRkcmVzcwMJAAECBQckbWF0Y2gwAgdBZGRyZXNzBAF0BQckbWF0Y2gwBgcECGlzSW5pdGVkAwUKbXVsdGlzaWdPawkBC3ZhbHVlT3JFbHNlAgkAmwgCCQEFdmFsdWUBBQ9tdWx0aXNpZ0FkZHJlc3MCBklOSVRFRAcHBAloYXNBZG1pbnMDBQptdWx0aXNpZ09rCQECIT0CCQELdmFsdWVPckVsc2UCCQCdCAIJAQV2YWx1ZQEFD211bHRpc2lnQWRkcmVzcwILQURNSU5TX1BCS1MCAAIABwMDAwUKbXVsdGlzaWdPawUIaXNJbml0ZWQHBQloYXNBZG1pbnMHBAckbWF0Y2gwBQJ0eAMJAAECBQckbWF0Y2gwAhRTZXRTY3JpcHRUcmFuc2FjdGlvbgQDdHR4BQckbWF0Y2gwBAckbWF0Y2gxCAUDdHR4BnNjcmlwdAMJAAECBQckbWF0Y2gxAgpCeXRlVmVjdG9yBAZzY3JpcHQFByRtYXRjaDEEC3NjcmlwdEhhc2hhCQDYBAEJAPYDAQUGc2NyaXB0BAl2YWxpZEZyb20JARN2YWx1ZU9yRXJyb3JNZXNzYWdlAgkAmggCCQEFdmFsdWUBBQ9tdWx0aXNpZ0FkZHJlc3MJAKwCAgkArAICCQCsAgIJAKwCAgIIc2NyaXB0JSUFDUNPTlRSQUNUX1RZUEUCAiUlBQtzY3JpcHRIYXNoYQILJSV2YWxpZEZyb20CEXZhbGlkRnJvbSBub3Qgc2V0BAd2YWxpZFRvCQETdmFsdWVPckVycm9yTWVzc2FnZQIJAJoIAgkBBXZhbHVlAQUPbXVsdGlzaWdBZGRyZXNzCQCsAgIJAKwCAgkArAICCQCsAgICCHNjcmlwdCUlBQ1DT05UUkFDVF9UWVBFAgIlJQULc2NyaXB0SGFzaGECCSUldmFsaWRUbwIPdmFsaWRUbyBub3Qgc2V0AwMDCQBnAgUGaGVpZ2h0BQl2YWxpZEZyb20JAGcCBQd2YWxpZFRvBQZoZWlnaHQHCQBnAgCAttwFCAUDdHR4A2ZlZQcJAQIhPQIJAPEHAQUEdGhpcwkA9gMBBQZzY3JpcHQHBwQDb3R4BQckbWF0Y2gwBAZ0YXNrSWQJAKwCAgkArAICCQCsAgICA3R4XwkApQgBBQR0aGlzAgFfCQDYBAEIBQNvdHgCaWQECmlzQXBwcm92ZWQJAQt2YWx1ZU9yRWxzZQIJAJsIAgkBBXZhbHVlAQUPbXVsdGlzaWdBZGRyZXNzCQCsAgIJAKwCAgkArAICCQClCAEFBHRoaXMCAV8JANgEAQgFA290eAJpZAIKX19hcHByb3ZlZAcEDGFwcHJvdmVkRnJvbQkBC3ZhbHVlT3JFbHNlAgkAmggCCQEFdmFsdWUBBQ9tdWx0aXNpZ0FkZHJlc3MJAKwCAgUGdGFza0lkAg5fX2FwcHJvdmVkRnJvbQAAAwUKaXNBcHByb3ZlZAkAZwIFBmhlaWdodAUMYXBwcm92ZWRGcm9tBwQNbWFzdGVyQWRkcmVzcwkAoggBAg92ZXJpZmllcl9tYXN0ZXIEEGFwcHJvdmVkQnlNYXN0ZXIEByRtYXRjaDAFDW1hc3RlckFkZHJlc3MDCQABAgUHJG1hdGNoMAIGU3RyaW5nBAF4BQckbWF0Y2gwBAckbWF0Y2gxCQCaCAIJARFAZXh0ck5hdGl2ZSgxMDYyKQEFAXgJAKwCAgILYXBwcm92ZWRUeF8JANgEAQgFAnR4AmlkAwkAAQIFByRtYXRjaDECA0ludAQBeQUHJG1hdGNoMQUBeQAAAAEDCQD0AwMIBQJ0eAlib2R5Qnl0ZXMJAJEDAggFAnR4BnByb29mcwAACAUCdHgPc2VuZGVyUHVibGljS2V5CQBmAgUQYXBwcm92ZWRCeU1hc3RlcgAABz2Djog=", "height": 932541, "applicationStatus": "succeeded", "spentComplexity": 0 } View: original | compacted Prev: none Next: none Full:
OldNewDifferences
1-# no script
1+{-# STDLIB_VERSION 6 #-}
2+{-# SCRIPT_TYPE ACCOUNT #-}
3+{-# CONTENT_TYPE DAPP #-}
4+let CONTRACT_TYPE = "LEND-LP-MARKET"
5+
6+let VERSION = "PLP-1.3.2"
7+
8+func getAddressFromState (key) = valueOrElse(addressFromString(valueOrElse(getString(this, ("setup_address_" + key)), "3PEwRcYNAUtoFvKpBhKoiwajnZfdoDR6h4h")), Address(base58'3PEwRcYNAUtoFvKpBhKoiwajnZfdoDR6h4h'))
9+
10+
11+func getAddressesFromState (key) = {
12+ func f (accum,next) = (accum ++ [valueOrElse(addressFromString(next), Address(base58'3PEwRcYNAUtoFvKpBhKoiwajnZfdoDR6h4h'))])
13+
14+ let $l = split_4C(valueOrElse(getString(this, ("setup_address_" + key)), "3PEwRcYNAUtoFvKpBhKoiwajnZfdoDR6h4h"), ",")
15+ let $s = size($l)
16+ let $acc0 = nil
17+ func $f0_1 ($a,$i) = if (($i >= $s))
18+ then $a
19+ else f($a, $l[$i])
20+
21+ func $f0_2 ($a,$i) = if (($i >= $s))
22+ then $a
23+ else throw("List size exceeds 15")
24+
25+ $f0_2($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($acc0, 0), 1), 2), 3), 4), 5), 6), 7), 8), 9), 10), 11), 12), 13), 14), 15)
26+ }
27+
28+
29+let reserveFundAddress = getAddressFromState("reserveFund")
30+
31+let oracleAddress = getAddressFromState("oracle")
32+
33+let aggregatorAddress = getAddressFromState("aggregator")
34+
35+let adminAddress = getAddressFromState("admin")
36+
37+let stableFundAddress = getAddressFromState("stableFund")
38+
39+let feeCollectorAddressStr = getString(this, "setup_address_feeCollector")
40+
41+let shutdownWhitelist = getAddressesFromState("shutdownCallers")
42+
43+let liquidatorsWhitelist = getAddressesFromState("liquidators")
44+
45+func verifyLiquidatorRights (address) = (indexOf(liquidatorsWhitelist, address) != unit)
46+
47+
48+let reserveFund = min([max([valueOrElse(getInteger(this, "setup_reserveFundFee"), 20), 0]), 100])
49+
50+let stablesIdStr = split(valueOrElse(getString(this, "setup_stablesIds"), "9wc3LXNA4TEBsXyKtoLE9mrbDD7WMHXvXrCjZvabLAsi,HGgabTqUS8WtVFUJzfmrTDMgEccJuZLBPhFgQFxvnsoW"), ",")
51+
52+func getRateCurve (assetIdStr) = {
53+ let curveRateStrLi = split(valueOrElse(getString(this, ("setup_rateCurve_" + assetIdStr)), "20000000,100000000,60000000,400000000"), ",")
54+ $Tuple4(parseIntValue(curveRateStrLi[0]), parseIntValue(curveRateStrLi[1]), parseIntValue(curveRateStrLi[2]), parseIntValue(curveRateStrLi[3]))
55+ }
56+
57+
58+func getRewardsSplitting (assetIdStr) = {
59+ let rewardsSplittingStrLi = split(valueOrElse(getString(this, ("setup_rewardsSplitting_" + assetIdStr)), "30,50,20"), ",")
60+ $Tuple3(parseIntValue(rewardsSplittingStrLi[0]), parseIntValue(rewardsSplittingStrLi[1]), parseIntValue(rewardsSplittingStrLi[2]))
61+ }
62+
63+
64+let sentinels = [Address(base58'3PMcMiMEs6w56NRGacksXtFG5zS7doE9fpL'), Address(base58'3PQdNxynJy5mche2kxMVc5shXWzK8Gstq3o'), Address(base58'3P8auNWJkxxByyJtwErFXaxiXcGM45qQ1hA'), Address(base58'3P8qVX189qpoTJZQQQdKS9endHK5sxWsvrd')]
65+
66+let Scale8 = 100000000
67+
68+let Scale10 = 10000000000
69+
70+let Scale16 = (Scale8 * Scale8)
71+
72+let dayBlocks = 1440
73+
74+let withdrawalLimitBlocks = valueOrElse(getInteger(this, "setup_withdrawalLimitBlocks"), 100)
75+
76+func tryGetInteger (key) = match getInteger(this, key) {
77+ case b: Int =>
78+ b
79+ case _ =>
80+ 0
81+}
82+
83+
84+func tryGetBoolean (key) = match getBoolean(this, key) {
85+ case b: Boolean =>
86+ b
87+ case _ =>
88+ false
89+}
90+
91+
92+func tryGetString (key) = match getString(this, key) {
93+ case b: String =>
94+ b
95+ case _ =>
96+ ""
97+}
98+
99+
100+func tryGetBinary (key) = match getBinary(this, key) {
101+ case b: ByteVector =>
102+ b
103+ case _ =>
104+ base58''
105+}
106+
107+
108+func getAssetString (assetId) = match assetId {
109+ case b: ByteVector =>
110+ toBase58String(b)
111+ case _ =>
112+ "WAVES"
113+}
114+
115+
116+func getAssetBytes (assetIdStr) = if ((assetIdStr == "WAVES"))
117+ then unit
118+ else fromBase58String(assetIdStr)
119+
120+
121+func getBalance (assetIdStr) = if ((assetIdStr == "WAVES"))
122+ then wavesBalance(this).available
123+ else assetBalance(this, fromBase58String(assetIdStr))
124+
125+
126+func getMarketAssets () = split(tryGetString("setup_tokens"), ",")
127+
128+
129+func getOutdatedUr (assetIdStr) = {
130+ let down = fraction(tryGetInteger(("total_supplied_" + assetIdStr)), tryGetInteger((assetIdStr + "_sRate")), Scale16)
131+ if ((down == 0))
132+ then 0
133+ else fraction(Scale8, fraction(tryGetInteger(("total_borrowed_" + assetIdStr)), tryGetInteger((assetIdStr + "_bRate")), Scale16), down)
134+ }
135+
136+
137+func getInterest (assetIdStr) = {
138+ let ur = getOutdatedUr(assetIdStr)
139+ let curve = getRateCurve(assetIdStr)
140+ let rate = (curve._1 + (if ((curve._3 >= ur))
141+ then fraction(ur, curve._2, curve._3)
142+ else (curve._2 + fraction((ur - curve._3), curve._4, (100000000 - curve._3)))))
143+ max([fraction(rate, Scale8, (dayBlocks * 365)), 1])
144+ }
145+
146+
147+func tokenRatesRecalc (assetIdStr) = {
148+ let interest = getInterest(assetIdStr)
149+ let ur = getOutdatedUr(assetIdStr)
150+ let lastRecalcHeight = tryGetInteger("lastRateHeight")
151+ let lastBRate = max([tryGetInteger((assetIdStr + "_bRate")), Scale16])
152+ let newBRate = (lastBRate + ((height - lastRecalcHeight) * interest))
153+ let lastSRate = max([tryGetInteger((assetIdStr + "_sRate")), Scale16])
154+ let newSRate = (lastSRate + fraction(((((height - lastRecalcHeight) * fraction(interest, ur, Scale8)) * (100 - reserveFund)) / 100), lastSRate, lastBRate))
155+[IntegerEntry((assetIdStr + "_sRate"), newSRate), IntegerEntry((assetIdStr + "_bRate"), newBRate), IntegerEntry("lastRateHeight", height)]
156+ }
157+
158+
159+func getActualRate (assetIdStr,rateType) = {
160+ func f (accum,token) = {
161+ let recalc = tokenRatesRecalc(token)
162+ let lastBRate = max([tryGetInteger((token + "_bRate")), Scale16])
163+ let feeDelta = fraction(reserveFund, fraction(tryGetInteger(("total_borrowed_" + token)), (recalc[1].value - lastBRate), Scale16), 100)
164+ let feeEntry = IntegerEntry((("fee_" + token) + "_interest"), (tryGetInteger((("fee_" + token) + "_interest")) + feeDelta))
165+ $Tuple3(if ((token != assetIdStr))
166+ then accum._1
167+ else if ((rateType == "sRate"))
168+ then recalc[0].value
169+ else recalc[1].value, (accum._2 ++ recalc), (accum._3 ++ [feeEntry]))
170+ }
171+
172+ let r = {
173+ let $l = getMarketAssets()
174+ let $s = size($l)
175+ let $acc0 = $Tuple3(0, nil, nil)
176+ func $f0_1 ($a,$i) = if (($i >= $s))
177+ then $a
178+ else f($a, $l[$i])
179+
180+ func $f0_2 ($a,$i) = if (($i >= $s))
181+ then $a
182+ else throw("List size exceeds 12")
183+
184+ $f0_2($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($acc0, 0), 1), 2), 3), 4), 5), 6), 7), 8), 9), 10), 11), 12)
185+ }
186+ $Tuple2(r._1, (r._2 ++ r._3))
187+ }
188+
189+
190+func getUr (assetIdStr) = {
191+ let rates = tokenRatesRecalc(assetIdStr)
192+ let down = fraction(tryGetInteger(("total_supplied_" + assetIdStr)), rates[0].value, Scale16)
193+ fraction(Scale8, fraction(tryGetInteger(("total_borrowed_" + assetIdStr)), rates[1].value, Scale16), down)
194+ }
195+
196+
197+func ratesRecalc () = {
198+ func f (accum,token) = (accum ++ tokenRatesRecalc(token))
199+
200+ let $l = getMarketAssets()
201+ let $s = size($l)
202+ let $acc0 = nil
203+ func $f0_1 ($a,$i) = if (($i >= $s))
204+ then $a
205+ else f($a, $l[$i])
206+
207+ func $f0_2 ($a,$i) = if (($i >= $s))
208+ then $a
209+ else throw("List size exceeds 12")
210+
211+ $f0_2($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($acc0, 0), 1), 2), 3), 4), 5), 6), 7), 8), 9), 10), 11), 12)
212+ }
213+
214+
215+func getTokenPriceWithRisk (assetIdStr,riskAversity) = if ((indexOf(stablesIdStr, assetIdStr) != unit))
216+ then $Tuple2(1000000, 1000000)
217+ else {
218+ let price = getIntegerValue(oracleAddress, (assetIdStr + "_twap5B"))
219+ let riskLevel = getIntegerValue(oracleAddress, (assetIdStr + "_riskLevel"))
220+ if ((riskAversity >= riskLevel))
221+ then $Tuple2(price, price)
222+ else throw((("oracle prices don't match: " + toString(price)) + " is the price, but risk is too high"))
223+ }
224+
225+
226+func getTokenPrice (assetIdStr) = getTokenPriceWithRisk(assetIdStr, 3)
227+
228+
229+func getTokenPriceCapped (assetIdStr) = {
230+ let $t01055110614 = getTokenPriceWithRisk(assetIdStr, 3)
231+ let minPrice = $t01055110614._1
232+ let maxPrice = $t01055110614._2
233+ let maxAllowedPrice = valueOrElse(getInteger(this, ("setup_maxPrice_" + assetIdStr)), -1)
234+ let minAllowedPrice = valueOrElse(getInteger(this, ("setup_minPrice_" + assetIdStr)), -1)
235+ if (if ((maxAllowedPrice != -1))
236+ then (maxPrice > maxAllowedPrice)
237+ else false)
238+ then $Tuple2(maxAllowedPrice, maxAllowedPrice)
239+ else if (if ((minAllowedPrice != -1))
240+ then (minAllowedPrice > minPrice)
241+ else false)
242+ then $Tuple2(minAllowedPrice, minAllowedPrice)
243+ else $Tuple2(minPrice, maxPrice)
244+ }
245+
246+
247+func getTokenPriceForHealth (assetIdStr) = {
248+ let price = getTokenPriceWithRisk(assetIdStr, 3)._1
249+ let maxAllowedPrice = valueOrElse(getInteger(this, ("setup_maxPrice_" + assetIdStr)), -1)
250+ let minAllowedPrice = valueOrElse(getInteger(this, ("setup_minPrice_" + assetIdStr)), -1)
251+ let collatPrice = if (if ((maxAllowedPrice != -1))
252+ then (price > maxAllowedPrice)
253+ else false)
254+ then maxAllowedPrice
255+ else price
256+ let debtPrice = if (if ((minAllowedPrice != -1))
257+ then (minAllowedPrice > price)
258+ else false)
259+ then minAllowedPrice
260+ else price
261+ $Tuple2(collatPrice, debtPrice)
262+ }
263+
264+
265+func calcAssetScale (assetIdStr) = {
266+ let decimals = if ((assetIdStr == "WAVES"))
267+ then 8
268+ else value(assetInfo(fromBase58String(assetIdStr))).decimals
269+ pow(10, 0, decimals, 0, 0, DOWN)
270+ }
271+
272+
273+func calcUserCollateral (address) = {
274+ let userCollateralInvoke = invoke(this, "getUserCollateral", [false, address, true, ""], nil)
275+ if ((userCollateralInvoke == userCollateralInvoke))
276+ then {
277+ let userCollateralValue = match userCollateralInvoke {
278+ case x: Int =>
279+ x
280+ case _ =>
281+ throw("issue while doing in-dapp invocation")
282+ }
283+ if ((userCollateralValue == userCollateralValue))
284+ then userCollateralValue
285+ else throw("Strict value is not equal to itself.")
286+ }
287+ else throw("Strict value is not equal to itself.")
288+ }
289+
290+
291+func checkWithdrawalLimit (address,assetIdStr,amountInternal,sRate) = {
292+ let withdrawalLimit = valueOrElse(getInteger(this, (("setup_" + assetIdStr) + "_maxWithdrawPer100B")), -1)
293+ if ((withdrawalLimit == -1))
294+ then nil
295+ else {
296+ let totalSupplied = tryGetInteger(("total_supplied_" + assetIdStr))
297+ let limitCap = fraction(totalSupplied, withdrawalLimit, 100)
298+ let lastH = tryGetInteger(((address + "_withdrawLimitHeight_") + assetIdStr))
299+ let elapsed = (height - lastH)
300+ let windowExpired = (elapsed > withdrawalLimitBlocks)
301+ let currentUsed = if (windowExpired)
302+ then 0
303+ else tryGetInteger(((address + "_withdrawLimitUsed_") + assetIdStr))
304+ let blocksToReset = if (windowExpired)
305+ then withdrawalLimitBlocks
306+ else (withdrawalLimitBlocks - elapsed)
307+ let available = (limitCap - currentUsed)
308+ let availableScaled = fraction(available, sRate, Scale16, CEILING)
309+ if ((amountInternal > available))
310+ then throw(((((("withdrawal limit exceeded for " + assetIdStr) + ", available: ") + toString(availableScaled)) + ", blocks to reset: ") + toString(blocksToReset)))
311+ else ((if (windowExpired)
312+ then [IntegerEntry(((address + "_withdrawLimitHeight_") + assetIdStr), height)]
313+ else nil) ++ [IntegerEntry(((address + "_withdrawLimitUsed_") + assetIdStr), (currentUsed + amountInternal))])
314+ }
315+ }
316+
317+
318+func checkBorrowLimit (address,assetIdStr,amountInternal,bRate,sRate) = {
319+ let borrowLimit = valueOrElse(getInteger(this, (("setup_" + assetIdStr) + "_maxBorrowPer100B")), -1)
320+ if ((borrowLimit == -1))
321+ then nil
322+ else {
323+ let totalSupplied = tryGetInteger(("total_supplied_" + assetIdStr))
324+ let limitCapSupply = fraction(totalSupplied, borrowLimit, 100)
325+ let limitCap = fraction(fraction(limitCapSupply, sRate, Scale16), Scale16, bRate)
326+ let lastH = tryGetInteger(((address + "_borrowLimitHeight_") + assetIdStr))
327+ let elapsed = (height - lastH)
328+ let windowExpired = (elapsed > withdrawalLimitBlocks)
329+ let currentUsed = if (windowExpired)
330+ then 0
331+ else tryGetInteger(((address + "_borrowLimitUsed_") + assetIdStr))
332+ let blocksToReset = if (windowExpired)
333+ then withdrawalLimitBlocks
334+ else (withdrawalLimitBlocks - elapsed)
335+ let available = (limitCap - currentUsed)
336+ let availableScaled = fraction(available, bRate, Scale16, CEILING)
337+ if ((amountInternal > available))
338+ then throw(((((("borrow limit exceeded for " + assetIdStr) + ", available: ") + toString(availableScaled)) + ", blocks to reset: ") + toString(blocksToReset)))
339+ else ((if (windowExpired)
340+ then [IntegerEntry(((address + "_borrowLimitHeight_") + assetIdStr), height)]
341+ else nil) ++ [IntegerEntry(((address + "_borrowLimitUsed_") + assetIdStr), (currentUsed + amountInternal))])
342+ }
343+ }
344+
345+
346+@Callable(i)
347+func supply () = if (!(tryGetBoolean("setup_active")))
348+ then throw("market is stopped")
349+ else if (if ((size(i.payments) != 1))
350+ then true
351+ else (i.payments[0].amount == 0))
352+ then throw("1 payment has to be attached")
353+ else {
354+ let assetIdStr = getAssetString(i.payments[0].assetId)
355+ let assetAmount = i.payments[0].amount
356+ let $t01595216019 = getActualRate(assetIdStr, "sRate")
357+ let sRate = $t01595216019._1
358+ let ratesRecalcResult = $t01595216019._2
359+ let amount = fraction(assetAmount, Scale16, sRate, DOWN)
360+ let address = toString(i.caller)
361+ let maxSupply = match getString(("setup_maxSupply_" + assetIdStr)) {
362+ case x: String =>
363+ parseIntValue(x)
364+ case _ =>
365+ tryGetInteger(("setup_maxSupply_" + assetIdStr))
366+ }
367+ let assetPrice = getTokenPriceCapped(assetIdStr)
368+ let newAddressSupplied = (tryGetInteger(((address + "_supplied_") + assetIdStr)) + amount)
369+ let newTotalSupplied = (tryGetInteger(("total_supplied_" + assetIdStr)) + amount)
370+ let rate = getActualRate(assetIdStr, "sRate")._1
371+ let assetScale = calcAssetScale(assetIdStr)
372+ let newTotalSuppliedUsd = fraction(fraction(newTotalSupplied, rate, Scale16), assetPrice._1, assetScale)
373+ if ((indexOf(tryGetString("setup_tokens"), assetIdStr) == unit))
374+ then throw("this asset is not supported by the market")
375+ else if (if ((maxSupply != 0))
376+ then (newTotalSuppliedUsd > maxSupply)
377+ else false)
378+ then throw("max total supply for this token reached in the pool")
379+ else if ((tryGetInteger(("setup_paused_" + assetIdStr)) > 0))
380+ then throw("this asset can't be supplied or borrowed")
381+ else {
382+ let inv = if ((tryGetString(("setup_autostake_" + assetIdStr)) != ""))
383+ then invoke(this, "stakeToken", [assetIdStr, assetAmount], nil)
384+ else unit
385+ if ((inv == inv))
386+ then ([IntegerEntry(((address + "_supplied_") + assetIdStr), newAddressSupplied), IntegerEntry(("total_supplied_" + assetIdStr), newTotalSupplied)] ++ ratesRecalcResult)
387+ else throw("Strict value is not equal to itself.")
388+ }
389+ }
390+
391+
392+
393+@Callable(i)
394+func withdraw (assetIdStr,assetAmount) = {
395+ let $t01758617653 = getActualRate(assetIdStr, "sRate")
396+ let sRate = $t01758617653._1
397+ let ratesRecalcResult = $t01758617653._2
398+ let amount = fraction(assetAmount, Scale16, sRate, CEILING)
399+ let address = toString(i.caller)
400+ let assetSupplied = tryGetInteger(("total_supplied_" + assetIdStr))
401+ let assetBorrowed = tryGetInteger(("total_borrowed_" + assetIdStr))
402+ let userAssetSupplied = tryGetInteger(((address + "_supplied_") + assetIdStr))
403+ let userAssetBorrowed = tryGetInteger(((address + "_borrowed_") + assetIdStr))
404+ let collateralValueInv = invoke(this, "getUserCollateral", [false, address, true, ((assetIdStr + ",supplied,") + toString(-(amount)))], nil)
405+ if ((collateralValueInv == collateralValueInv))
406+ then {
407+ let collateralValue = match collateralValueInv {
408+ case x: Int =>
409+ x
410+ case _ =>
411+ throw("can't get user collateral value")
412+ }
413+ if (!(tryGetBoolean("setup_active")))
414+ then throw("market is stopped")
415+ else if ((0 > collateralValue))
416+ then throw("you dont have enough collateral for this operation")
417+ else if ((amount > (assetSupplied - assetBorrowed)))
418+ then throw("this amount is not available on the market")
419+ else if ((amount > (userAssetSupplied - userAssetBorrowed)))
420+ then throw("this amount is not available for this user")
421+ else {
422+ let inv = if ((tryGetString(("setup_autostake_" + assetIdStr)) != ""))
423+ then invoke(this, "unstakeToken", [assetIdStr, assetAmount], nil)
424+ else unit
425+ if ((inv == inv))
426+ then {
427+ let limitCheckActions = checkWithdrawalLimit(address, assetIdStr, amount, sRate)
428+ if ((limitCheckActions == limitCheckActions))
429+ then (([IntegerEntry(((address + "_supplied_") + assetIdStr), (tryGetInteger(((address + "_supplied_") + assetIdStr)) - amount)), IntegerEntry(("total_supplied_" + assetIdStr), (tryGetInteger(("total_supplied_" + assetIdStr)) - amount)), ScriptTransfer(i.caller, assetAmount, getAssetBytes(assetIdStr))] ++ ratesRecalcResult) ++ limitCheckActions)
430+ else throw("Strict value is not equal to itself.")
431+ }
432+ else throw("Strict value is not equal to itself.")
433+ }
434+ }
435+ else throw("Strict value is not equal to itself.")
436+ }
437+
438+
439+
440+@Callable(i)
441+func borrow (assetIdStr,assetAmount) = {
442+ let address = toString(i.caller)
443+ let $t01941719484 = getActualRate(assetIdStr, "bRate")
444+ let bRate = $t01941719484._1
445+ let ratesRecalcResult = $t01941719484._2
446+ let amount = fraction(assetAmount, Scale16, bRate, CEILING)
447+ let collateralValueInv = invoke(this, "getUserCollateral", [false, address, true, ((assetIdStr + ",borrowed,") + toString(amount))], nil)
448+ if ((collateralValueInv == collateralValueInv))
449+ then {
450+ let collateralValue = match collateralValueInv {
451+ case x: Int =>
452+ x
453+ case _ =>
454+ throw("can't get user collateral value")
455+ }
456+ if (!(tryGetBoolean("setup_active")))
457+ then throw("market is stopped")
458+ else if ((0 > collateralValue))
459+ then throw("you have to supply more to borrow")
460+ else if ((tryGetInteger(("setup_borrowEnabled_" + assetIdStr)) == 0))
461+ then throw("this asset can't be borrowed")
462+ else if ((tryGetInteger(("setup_paused_" + assetIdStr)) > 0))
463+ then throw("this asset can't be supplied or borrowed")
464+ else {
465+ let assetSupplied = tryGetInteger(("total_supplied_" + assetIdStr))
466+ let assetBorrowed = tryGetInteger(("total_borrowed_" + assetIdStr))
467+ let userAssetBorrowed = tryGetInteger(((address + "_borrowed_") + assetIdStr))
468+ if ((amount > (assetSupplied - assetBorrowed)))
469+ then throw("this amount is not available")
470+ else {
471+ let inv = if ((tryGetString(("setup_autostake_" + assetIdStr)) != ""))
472+ then invoke(this, "unstakeToken", [assetIdStr, assetAmount], nil)
473+ else unit
474+ if ((inv == inv))
475+ then {
476+ let sRate = ratesRecalcResult[(value(indexOf(getMarketAssets(), assetIdStr)) * 3)].value
477+ let limitCheckActions = checkBorrowLimit(address, assetIdStr, amount, bRate, sRate)
478+ if ((limitCheckActions == limitCheckActions))
479+ then (([IntegerEntry(((address + "_borrowed_") + assetIdStr), (userAssetBorrowed + amount)), IntegerEntry(("total_borrowed_" + assetIdStr), (assetBorrowed + amount)), ScriptTransfer(i.caller, assetAmount, getAssetBytes(assetIdStr))] ++ ratesRecalcResult) ++ limitCheckActions)
480+ else throw("Strict value is not equal to itself.")
481+ }
482+ else throw("Strict value is not equal to itself.")
483+ }
484+ }
485+ }
486+ else throw("Strict value is not equal to itself.")
487+ }
488+
489+
490+
491+@Callable(i)
492+func repay () = if (!(tryGetBoolean("setup_active")))
493+ then throw("market is stopped")
494+ else if (if ((size(i.payments) != 1))
495+ then true
496+ else (i.payments[0].amount == 0))
497+ then throw("1 payment has to be attached")
498+ else {
499+ let assetIdStr = getAssetString(i.payments[0].assetId)
500+ let assetAmount = i.payments[0].amount
501+ let $t02157822262 = getActualRate(assetIdStr, "bRate")
502+ let bRate = $t02157822262._1
503+ let ratesRecalcResult = $t02157822262._2
504+ let amount = fraction(assetAmount, Scale16, bRate, CEILING)
505+ let address = toString(i.caller)
506+ let assetSupplied = tryGetInteger(("total_supplied_" + assetIdStr))
507+ let assetBorrowed = tryGetInteger(("total_borrowed_" + assetIdStr))
508+ let userAssetBorrowed = tryGetInteger(((address + "_borrowed_") + assetIdStr))
509+ let amountLeft = (userAssetBorrowed - amount)
510+ let repayAmount = if ((amountLeft >= 0))
511+ then amount
512+ else userAssetBorrowed
513+ if ((indexOf(tryGetString("setup_tokens"), assetIdStr) == unit))
514+ then throw("this asset is not supported by the market")
515+ else {
516+ let inv = if ((tryGetString(("setup_autostake_" + assetIdStr)) != ""))
517+ then invoke(this, "stakeToken", [assetIdStr, assetAmount], nil)
518+ else unit
519+ if ((inv == inv))
520+ then {
521+ let excessTokens = (assetAmount - fraction(repayAmount, bRate, Scale16))
522+ (([IntegerEntry(((address + "_borrowed_") + assetIdStr), (userAssetBorrowed - repayAmount)), IntegerEntry(("total_borrowed_" + assetIdStr), (assetBorrowed - repayAmount))] ++ ratesRecalcResult) ++ (if ((amountLeft >= 0))
523+ then nil
524+ else [ScriptTransfer(i.caller, excessTokens, i.payments[0].assetId)]))
525+ }
526+ else throw("Strict value is not equal to itself.")
527+ }
528+ }
529+
530+
531+
532+@Callable(i)
533+func repayFor (address) = if (!(tryGetBoolean("setup_active")))
534+ then throw("market is stopped")
535+ else if ((i.caller != reserveFundAddress))
536+ then throw("available only for reserve fund address")
537+ else if ((address == "global"))
538+ then throw("you can't repay for everyone :_)")
539+ else if (if ((size(i.payments) != 1))
540+ then true
541+ else (i.payments[0].amount == 0))
542+ then throw("1 payment has to be attached")
543+ else {
544+ let assetIdStr = getAssetString(i.payments[0].assetId)
545+ let assetAmount = i.payments[0].amount
546+ let $t02393824622 = getActualRate(assetIdStr, "bRate")
547+ let bRate = $t02393824622._1
548+ let ratesRecalcResult = $t02393824622._2
549+ let amount = fraction(assetAmount, Scale16, bRate, CEILING)
550+ let assetSupplied = tryGetInteger(("total_supplied_" + assetIdStr))
551+ let assetBorrowed = tryGetInteger(("total_borrowed_" + assetIdStr))
552+ let userAssetBorrowed = tryGetInteger(((address + "_borrowed_") + assetIdStr))
553+ let amountLeft = (userAssetBorrowed - amount)
554+ let repayAmount = if ((amountLeft >= 0))
555+ then amount
556+ else userAssetBorrowed
557+ if ((indexOf(tryGetString("setup_tokens"), assetIdStr) == unit))
558+ then throw("this asset is not supported by the market")
559+ else {
560+ let inv = if ((tryGetString(("setup_autostake_" + assetIdStr)) != ""))
561+ then invoke(this, "stakeToken", [assetIdStr, assetAmount], nil)
562+ else unit
563+ if ((inv == inv))
564+ then {
565+ let excessTokens = (assetAmount - fraction(repayAmount, bRate, Scale16))
566+ (([IntegerEntry(((address + "_borrowed_") + assetIdStr), (userAssetBorrowed - repayAmount)), IntegerEntry(("total_borrowed_" + assetIdStr), (assetBorrowed - repayAmount))] ++ ratesRecalcResult) ++ (if ((amountLeft >= 0))
567+ then nil
568+ else [ScriptTransfer(i.caller, excessTokens, i.payments[0].assetId)]))
569+ }
570+ else throw("Strict value is not equal to itself.")
571+ }
572+ }
573+
574+
575+
576+@Callable(i)
577+func stakeToken (assetIdStr,amount) = {
578+ let autostakeAddress = valueOrElse(addressFromString(tryGetString(("setup_autostake_" + assetIdStr))), Address(base58'3PDDRRS5gKyDQRpJskzWTdxREHGu1FNpdwg'))
579+ let stakerSupportedAssets = getStringValue(autostakeAddress, "setup_supportedAssets")
580+ if ((i.caller != this))
581+ then throw("only for internal smart contract invocations")
582+ else if ((indexOf(stakerSupportedAssets, assetIdStr) == unit))
583+ then nil
584+ else {
585+ let amountStaked = tryGetInteger(("autostake_amount_" + assetIdStr))
586+ let stakeInv = reentrantInvoke(autostakeAddress, "stakeLP", nil, [AttachedPayment(getAssetBytes(assetIdStr), amount)])
587+ if ((stakeInv == stakeInv))
588+ then [IntegerEntry(("autostake_amount_" + assetIdStr), (amountStaked + amount))]
589+ else throw("Strict value is not equal to itself.")
590+ }
591+ }
592+
593+
594+
595+@Callable(i)
596+func stakeTokenAll (assetIdStr) = if ((i.caller != this))
597+ then throw("only for internal smart contract invocations")
598+ else {
599+ let amount = getBalance(assetIdStr)
600+ let inv = reentrantInvoke(this, "stakeToken", [assetIdStr, amount], nil)
601+ if ((inv == inv))
602+ then nil
603+ else throw("Strict value is not equal to itself.")
604+ }
605+
606+
607+
608+@Callable(i)
609+func unstakeToken (assetIdStr,amount) = {
610+ let autostakeAddress = valueOrElse(addressFromString(tryGetString(("setup_autostake_" + assetIdStr))), Address(base58'3PDDRRS5gKyDQRpJskzWTdxREHGu1FNpdwg'))
611+ let stakerSupportedAssets = getStringValue(autostakeAddress, "setup_supportedAssets")
612+ if ((i.caller != this))
613+ then throw("only for internal smart contract invocations")
614+ else if ((indexOf(stakerSupportedAssets, assetIdStr) == unit))
615+ then nil
616+ else {
617+ let amountStaked = tryGetInteger(("autostake_amount_" + assetIdStr))
618+ let stakeInv = reentrantInvoke(autostakeAddress, "unstakeLP", [assetIdStr, amount], nil)
619+ if ((stakeInv == stakeInv))
620+ then [IntegerEntry(("autostake_amount_" + assetIdStr), (amountStaked - amount))]
621+ else throw("Strict value is not equal to itself.")
622+ }
623+ }
624+
625+
626+
627+@Callable(i)
628+func addInterest (assetIdStr,amount) = if ((i.caller != this))
629+ then throw("only for self invocation")
630+ else {
631+ let earned = tryGetInteger(("autostake_lastEarned_" + assetIdStr))
632+ let lastHeight = tryGetInteger(("autostake_lastBlock_" + assetIdStr))
633+ let cleanAmount = fraction(amount, 80, 100)
634+ let stakingFee = (amount - cleanAmount)
635+ let stateChanges = if (if ((lastHeight == height))
636+ then true
637+ else (amount == 0))
638+ then nil
639+ else [IntegerEntry(("autostake_preLastEarned_" + assetIdStr), earned), IntegerEntry(("autostake_preLastBlock_" + assetIdStr), lastHeight), IntegerEntry(("autostake_lastEarned_" + assetIdStr), (earned + cleanAmount)), IntegerEntry(("autostake_lastBlock_" + assetIdStr), height)]
640+ (stateChanges ++ [IntegerEntry((assetIdStr + "_sRate"), (tryGetInteger((assetIdStr + "_sRate")) + fraction(Scale16, cleanAmount, tryGetInteger(("total_supplied_" + assetIdStr))))), IntegerEntry((("fee_" + assetIdStr) + "_staking"), (tryGetInteger((("fee_" + assetIdStr) + "_staking")) + stakingFee))])
641+ }
642+
643+
644+
645+@Callable(i)
646+func addInterestEXTERNAL () = if ((size(i.payments) != 1))
647+ then throw("exactly 1 payment has to be attached")
648+ else {
649+ let assetId = i.payments[0].assetId
650+ let assetIdStr = getAssetString(assetId)
651+ if ((indexOf(tryGetString("setup_tokens"), assetIdStr) == unit))
652+ then throw("this asset is not supported by the market")
653+ else {
654+ let splitting = getRewardsSplitting(assetIdStr)
655+ let amount = fraction(i.payments[0].amount, splitting._2, 100)
656+ let totalSupplied = tryGetInteger(("total_supplied_" + assetIdStr))
657+ let supplierAmount = if ((totalSupplied > 0))
658+ then amount
659+ else 0
660+ let stakingFeeAdd = (fraction(i.payments[0].amount, splitting._3, 100) + (amount - supplierAmount))
661+ let earned = tryGetInteger(("autostake_lastEarned_" + assetIdStr))
662+ let lastHeight = tryGetInteger(("autostake_lastBlock_" + assetIdStr))
663+ let stateChanges = if (if ((lastHeight == height))
664+ then true
665+ else (supplierAmount == 0))
666+ then nil
667+ else [IntegerEntry(("autostake_preLastEarned_" + assetIdStr), earned), IntegerEntry(("autostake_preLastBlock_" + assetIdStr), lastHeight), IntegerEntry(("autostake_lastEarned_" + assetIdStr), (earned + supplierAmount)), IntegerEntry(("autostake_lastBlock_" + assetIdStr), height)]
668+ ((stateChanges ++ (if ((supplierAmount > 0))
669+ then [IntegerEntry((assetIdStr + "_sRate"), (tryGetInteger((assetIdStr + "_sRate")) + fraction(Scale16, supplierAmount, totalSupplied)))]
670+ else nil)) ++ [ScriptTransfer(stableFundAddress, fraction(i.payments[0].amount, splitting._1, 100), assetId), IntegerEntry((("fee_" + assetIdStr) + "_staking"), (tryGetInteger((("fee_" + assetIdStr) + "_staking")) + stakingFeeAdd))])
671+ }
672+ }
673+
674+
675+
676+@Callable(i)
677+func preInit (tokens,ltvs,lts,penalties) = {
678+ func f (accum,token) = (accum ++ [IntegerEntry((token + "_bRate"), Scale16), IntegerEntry((token + "_sRate"), Scale16)])
679+
680+ if ((i.caller != this))
681+ then throw("admin only")
682+ else {
683+ let rates = {
684+ let $l = split(tokens, ",")
685+ let $s = size($l)
686+ let $acc0 = nil
687+ func $f0_1 ($a,$i) = if (($i >= $s))
688+ then $a
689+ else f($a, $l[$i])
690+
691+ func $f0_2 ($a,$i) = if (($i >= $s))
692+ then $a
693+ else throw("List size exceeds 12")
694+
695+ $f0_2($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($acc0, 0), 1), 2), 3), 4), 5), 6), 7), 8), 9), 10), 11), 12)
696+ }
697+ ([StringEntry("setup_tokens", tokens), StringEntry("setup_ltvs", ltvs), StringEntry("setup_lts", lts), StringEntry("setup_penalties", penalties), BooleanEntry("setup_active", true)] ++ rates)
698+ }
699+ }
700+
701+
702+
703+@Callable(i)
704+func initNewToken (token,ltv,lt,penalty) = if ((i.caller != this))
705+ then throw("admin only")
706+ else [StringEntry("setup_tokens", ((tryGetString("setup_tokens") + ",") + token)), StringEntry("setup_ltvs", ((tryGetString("setup_ltvs") + ",") + ltv)), StringEntry("setup_lts", ((tryGetString("setup_lts") + ",") + lt)), StringEntry("setup_penalties", ((tryGetString("setup_penalties") + ",") + penalty)), IntegerEntry((token + "_bRate"), Scale16), IntegerEntry((token + "_sRate"), Scale16)]
707+
708+
709+
710+@Callable(i)
711+func updateParameter (key,val) = if (if ((i.caller != this))
712+ then (i.caller != adminAddress)
713+ else false)
714+ then throw("admin only")
715+ else [IntegerEntry(key, parseIntValue(val))]
716+
717+
718+
719+@Callable(i)
720+func updateString (key,val) = if (if ((i.caller != this))
721+ then (i.caller != adminAddress)
722+ else false)
723+ then throw("admin only")
724+ else [StringEntry(key, val)]
725+
726+
727+
728+@Callable(i)
729+func claimFees (assetIdStr) = if ((feeCollectorAddressStr == unit))
730+ then throw("fee collector not configured")
731+ else if ((indexOf(tryGetString("setup_tokens"), assetIdStr) == unit))
732+ then throw("this asset is not supported by the market")
733+ else {
734+ let interest = tryGetInteger((("fee_" + assetIdStr) + "_interest"))
735+ let stk = tryGetInteger((("fee_" + assetIdStr) + "_staking"))
736+ let liq = tryGetInteger((("fee_" + assetIdStr) + "_liquidation"))
737+ let total = ((interest + stk) + liq)
738+ if ((0 >= total))
739+ then nil
740+ else {
741+ let bal = getBalance(assetIdStr)
742+ let isStaked = (tryGetString(("setup_autostake_" + assetIdStr)) != "")
743+ let unstakeInv = if (if (isStaked)
744+ then (total > bal)
745+ else false)
746+ then invoke(this, "unstakeToken", [assetIdStr, (total - bal)], nil)
747+ else unit
748+ if ((unstakeInv == unstakeInv))
749+ then {
750+ let liquid = getBalance(assetIdStr)
751+ let payable = min([total, liquid])
752+ let payInterest = min([max([interest, 0]), payable])
753+ let payStk = min([max([stk, 0]), (payable - payInterest)])
754+ let payLiq = min([max([liq, 0]), ((payable - payInterest) - payStk)])
755+ let pay = ((payInterest + payStk) + payLiq)
756+ if ((0 >= pay))
757+ then nil
758+ else {
759+ let recordInv = invoke(addressFromStringValue(value(feeCollectorAddressStr)), "processFees", [assetIdStr, payInterest, payStk, payLiq], [AttachedPayment(getAssetBytes(assetIdStr), pay)])
760+ if ((recordInv == recordInv))
761+ then [IntegerEntry((("fee_" + assetIdStr) + "_interest"), (interest - payInterest)), IntegerEntry((("fee_" + assetIdStr) + "_staking"), (stk - payStk)), IntegerEntry((("fee_" + assetIdStr) + "_liquidation"), (liq - payLiq))]
762+ else throw("Strict value is not equal to itself.")
763+ }
764+ }
765+ else throw("Strict value is not equal to itself.")
766+ }
767+ }
768+
769+
770+
771+@Callable(i)
772+func claimFeesAll (tokensList) = {
773+ let tokens = if ((tokensList == ""))
774+ then getMarketAssets()
775+ else split(tokensList, ",")
776+ func f (accum,token) = {
777+ let inv = invoke(this, "claimFees", [token], nil)
778+ if ((inv == inv))
779+ then accum
780+ else throw("Strict value is not equal to itself.")
781+ }
782+
783+ let done = {
784+ let $l = tokens
785+ let $s = size($l)
786+ let $acc0 = unit
787+ func $f0_1 ($a,$i) = if (($i >= $s))
788+ then $a
789+ else f($a, $l[$i])
790+
791+ func $f0_2 ($a,$i) = if (($i >= $s))
792+ then $a
793+ else throw("List size exceeds 12")
794+
795+ $f0_2($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($acc0, 0), 1), 2), 3), 4), 5), 6), 7), 8), 9), 10), 11), 12)
796+ }
797+ if ((done == done))
798+ then nil
799+ else throw("Strict value is not equal to itself.")
800+ }
801+
802+
803+
804+@Callable(i)
805+func claimLiquidatorRewards (assetIdStr) = {
806+ let liqProxyStr = valueOrElse(getString(this, "setup_address_liquidatorProxy"), "")
807+ if ((liqProxyStr == ""))
808+ then throw("liquidator proxy not configured")
809+ else if ((indexOf(tryGetString("setup_tokens"), assetIdStr) == unit))
810+ then throw("this asset is not supported by the market")
811+ else {
812+ let reward = tryGetInteger(("liqReward_" + assetIdStr))
813+ if ((0 >= reward))
814+ then nil
815+ else {
816+ let bal = getBalance(assetIdStr)
817+ let isStaked = (tryGetString(("setup_autostake_" + assetIdStr)) != "")
818+ let unstakeInv = if (if (isStaked)
819+ then (reward > bal)
820+ else false)
821+ then invoke(this, "unstakeToken", [assetIdStr, (reward - bal)], nil)
822+ else unit
823+ if ((unstakeInv == unstakeInv))
824+ then {
825+ let liquid = getBalance(assetIdStr)
826+ let pay = min([reward, liquid])
827+ if ((0 >= pay))
828+ then nil
829+ else [ScriptTransfer(addressFromStringValue(liqProxyStr), pay, getAssetBytes(assetIdStr)), IntegerEntry(("liqReward_" + assetIdStr), (reward - pay))]
830+ }
831+ else throw("Strict value is not equal to itself.")
832+ }
833+ }
834+ }
835+
836+
837+
838+@Callable(i)
839+func reSetup (assetIdStr) = if (true)
840+ then throw("Resetup disabled")
841+ else {
842+ let lastResetup = tryGetInteger("resetup_lastUpdate")
843+ if ((dayBlocks > (height - lastResetup)))
844+ then throw("can be updated only once per day")
845+ else {
846+ let lts = split(tryGetString("setup_lts"), ",")
847+ let assets = getMarketAssets()
848+ let ur = getUr(assetIdStr)
849+ let tempLT = tryGetInteger((("setup_" + assetIdStr) + "_tempLT"))
850+ let lt = parseIntValue(assets[value(indexOf(assets, assetIdStr))])
851+ if ((ur > 90000000))
852+ then [IntegerEntry((("setup_" + assetIdStr) + "_tempLT"), fraction(tempLT, 9975, 10000))]
853+ else if (if ((lt > tempLT))
854+ then (90000000 > ur)
855+ else false)
856+ then [IntegerEntry((("setup_" + assetIdStr) + "_tempLT"), fraction(tempLT, 10025, 10000))]
857+ else nil
858+ }
859+ }
860+
861+
862+
863+@Callable(i)
864+func shutdown (shutdown) = if ((indexOf(shutdownWhitelist, i.caller) == unit))
865+ then throw("user not in a whitelist")
866+ else [BooleanEntry("setup_active", !(shutdown))]
867+
868+
869+
870+@Callable(i)
871+func liquidate (debug,address,assetAmount,sAssetIdStr,bAssetIdStr,routeStr) = if (!(verifyLiquidatorRights(i.caller)))
872+ then throw("temporarily available for whitelist only")
873+ else if (!(tryGetBoolean("setup_active")))
874+ then throw("market is stopped")
875+ else {
876+ let userCollateral = calcUserCollateral(address)
877+ if ((userCollateral == userCollateral))
878+ then {
879+ let $t04009640158 = getActualRate(sAssetIdStr, "sRate")
880+ let sRate = $t04009640158._1
881+ let ratesResult = $t04009640158._2
882+ let $t04016340232 = getActualRate(bAssetIdStr, "bRate")
883+ let bRate = $t04016340232._1
884+ let ratesRecalcResult2 = $t04016340232._2
885+ let sAssetAmount = fraction(assetAmount, Scale16, sRate)
886+ let currentSPosition = tryGetInteger(((address + "_supplied_") + sAssetIdStr))
887+ let currentBPositionVal = tryGetInteger(((address + "_borrowed_") + bAssetIdStr))
888+ let currentBPosition = if ((currentBPositionVal > 0))
889+ then currentBPositionVal
890+ else throw("user has no borrow in this token")
891+ if ((userCollateral > 0))
892+ then throw("user can't be liquidated")
893+ else if ((sAssetAmount > currentSPosition))
894+ then throw("position to liquidate is bigger than user's supply")
895+ else {
896+ let inv = if ((tryGetString(("setup_autostake_" + sAssetIdStr)) != ""))
897+ then invoke(this, "unstakeToken", [sAssetIdStr, assetAmount], nil)
898+ else unit
899+ if ((inv == inv))
900+ then {
901+ let balance0Before = getBalance(sAssetIdStr)
902+ if ((balance0Before == balance0Before))
903+ then {
904+ let balance1Before = getBalance(bAssetIdStr)
905+ if ((balance1Before == balance1Before))
906+ then {
907+ let exchangeInvoke = invoke(aggregatorAddress, "swap", [routeStr, 0], [AttachedPayment(getAssetBytes(sAssetIdStr), assetAmount)])
908+ if ((exchangeInvoke == exchangeInvoke))
909+ then {
910+ let asset0Sold = (balance0Before - getBalance(sAssetIdStr))
911+ if ((asset0Sold == asset0Sold))
912+ then {
913+ let asset1Bought = (getBalance(bAssetIdStr) - balance1Before)
914+ if ((asset1Bought == asset1Bought))
915+ then {
916+ let asset0Price = getTokenPriceCapped(sAssetIdStr)._1
917+ let asset0Scale = calcAssetScale(sAssetIdStr)
918+ let asset0Usd = fraction(asset0Sold, asset0Price, asset0Scale)
919+ let asset1Price = getTokenPriceCapped(bAssetIdStr)._2
920+ let asset1Scale = calcAssetScale(bAssetIdStr)
921+ let asset1Usd = fraction(asset1Bought, asset1Price, asset1Scale)
922+ let penalty = parseIntValue(split(tryGetString("setup_penalties"), ",")[value(indexOf(getMarketAssets(), bAssetIdStr))])
923+ let liquidationProfit = (asset1Usd - fraction(asset0Usd, (Scale8 - penalty), Scale8))
924+ let sAssetChange = fraction(asset0Sold, Scale16, sRate)
925+ let bAssetChange = fraction(fraction(asset1Bought, Scale16, bRate), (Scale8 - fraction(liquidationProfit, Scale8, asset1Usd)), Scale8)
926+ let penaltyTokens = (asset1Bought - fraction(bAssetChange, bRate, Scale16))
927+ let liqProxyStr = valueOrElse(getString(this, "setup_address_liquidatorProxy"), "")
928+ let liquidatorShare = if (if ((liqProxyStr != ""))
929+ then (toString(i.caller) == liqProxyStr)
930+ else false)
931+ then min([max([valueOrElse(getInteger(addressFromStringValue(liqProxyStr), "setup_penaltyShare"), 0), 0]), 10000])
932+ else 0
933+ let liquidatorPart = fraction(penaltyTokens, liquidatorShare, 10000)
934+ if ((asset0Sold > assetAmount))
935+ then throw("more assets exchanged than expected")
936+ else if ((0 > liquidationProfit))
937+ then throw("price impact is bigger than liquidation penalty")
938+ else if ((bAssetChange > currentBPosition))
939+ then throw("debt reduction exceeds user's borrow")
940+ else $Tuple2(([IntegerEntry(((address + "_supplied_") + sAssetIdStr), (currentSPosition - sAssetChange)), IntegerEntry(((address + "_borrowed_") + bAssetIdStr), (currentBPosition - bAssetChange)), IntegerEntry(("total_supplied_" + sAssetIdStr), (tryGetInteger(("total_supplied_" + sAssetIdStr)) - sAssetChange)), IntegerEntry(("total_borrowed_" + bAssetIdStr), (tryGetInteger(("total_borrowed_" + bAssetIdStr)) - bAssetChange)), IntegerEntry((("fee_" + bAssetIdStr) + "_liquidation"), (tryGetInteger((("fee_" + bAssetIdStr) + "_liquidation")) + (penaltyTokens - liquidatorPart)))] ++ (if ((liquidatorPart > 0))
941+ then [IntegerEntry(("liqReward_" + bAssetIdStr), (tryGetInteger(("liqReward_" + bAssetIdStr)) + liquidatorPart))]
942+ else nil)), liquidatorPart)
943+ }
944+ else throw("Strict value is not equal to itself.")
945+ }
946+ else throw("Strict value is not equal to itself.")
947+ }
948+ else throw("Strict value is not equal to itself.")
949+ }
950+ else throw("Strict value is not equal to itself.")
951+ }
952+ else throw("Strict value is not equal to itself.")
953+ }
954+ else throw("Strict value is not equal to itself.")
955+ }
956+ }
957+ else throw("Strict value is not equal to itself.")
958+ }
959+
960+
961+
962+@Callable(i)
963+func liquidateV2 (debug,address,sAssetIdStr) = if (!(verifyLiquidatorRights(i.caller)))
964+ then throw("temporarily available for whitelist only")
965+ else if (!(tryGetBoolean("setup_active")))
966+ then throw("market is stopped")
967+ else if ((size(i.payments) != 1))
968+ then throw("exactly 1 payment has to be attached")
969+ else {
970+ let bAssetId = i.payments[0].assetId
971+ let bAssetIdStr = getAssetString(bAssetId)
972+ let bAssetAmount = i.payments[0].amount
973+ let userCollateral = calcUserCollateral(address)
974+ if ((userCollateral == userCollateral))
975+ then if ((userCollateral > 0))
976+ then throw("user can't be liquidated")
977+ else {
978+ let marketAssets = getMarketAssets()
979+ let asset1Num = value(indexOf(marketAssets, bAssetIdStr))
980+ let asset0Num = value(indexOf(marketAssets, sAssetIdStr))
981+ let $t04637746439 = getActualRate(bAssetIdStr, "bRate")
982+ let bRate = $t04637746439._1
983+ let ratesResult = $t04637746439._2
984+ let currentSPosition = tryGetInteger(((address + "_supplied_") + sAssetIdStr))
985+ let currentBPositionVal = tryGetInteger(((address + "_borrowed_") + bAssetIdStr))
986+ let currentBPosition = if ((currentBPositionVal > 0))
987+ then currentBPositionVal
988+ else throw("user has no borrow in this token")
989+ let bAmountRaw = fraction(bAssetAmount, Scale16, bRate)
990+ let bAmount = min([bAmountRaw, currentBPosition])
991+ let bAssetAmountEff = if ((currentBPosition >= bAmountRaw))
992+ then bAssetAmount
993+ else fraction(bAmount, bRate, Scale16, CEILING)
994+ let refund = (bAssetAmount - bAssetAmountEff)
995+ let asset1Price = getTokenPriceCapped(bAssetIdStr)._2
996+ let asset1Scale = calcAssetScale(bAssetIdStr)
997+ let bAmountUsd = fraction(bAssetAmountEff, asset1Price, asset1Scale)
998+ let penalty = parseIntValue(value(split(tryGetString("setup_penalties"), ",")[asset1Num]))
999+ let asset0Price = getTokenPriceCapped(sAssetIdStr)._1
1000+ let asset0Scale = calcAssetScale(sAssetIdStr)
1001+ let sAmountUsd = fraction(bAmountUsd, (Scale8 + penalty), Scale8)
1002+ let sAssetAmount = fraction(sAmountUsd, asset0Scale, asset0Price)
1003+ let sAmount = fraction(sAssetAmount, Scale16, ratesResult[(asset0Num * 3)].value)
1004+ if ((sAmount > currentSPosition))
1005+ then throw("position to liquidate is bigger than user's supply")
1006+ else {
1007+ let inv = if ((tryGetString(("setup_autostake_" + sAssetIdStr)) != ""))
1008+ then invoke(this, "unstakeToken", [sAssetIdStr, sAssetAmount], nil)
1009+ else unit
1010+ if ((inv == inv))
1011+ then if (debug)
1012+ then throw("liquidation will pass")
1013+ else (([ScriptTransfer(i.caller, sAssetAmount, getAssetBytes(sAssetIdStr)), IntegerEntry(((address + "_supplied_") + sAssetIdStr), (currentSPosition - sAmount)), IntegerEntry(((address + "_borrowed_") + bAssetIdStr), (currentBPosition - bAmount)), IntegerEntry(("total_supplied_" + sAssetIdStr), (tryGetInteger(("total_supplied_" + sAssetIdStr)) - sAmount)), IntegerEntry(("total_borrowed_" + bAssetIdStr), (tryGetInteger(("total_borrowed_" + bAssetIdStr)) - bAmount))] ++ ratesResult) ++ (if ((refund > 0))
1014+ then [ScriptTransfer(i.caller, refund, bAssetId)]
1015+ else nil))
1016+ else throw("Strict value is not equal to itself.")
1017+ }
1018+ }
1019+ else throw("Strict value is not equal to itself.")
1020+ }
1021+
1022+
1023+
1024+@Callable(i)
1025+func getUserCollateral (debug,address,minusBorrowed,afterChange) = {
1026+ let assets = getMarketAssets()
1027+ let ltvs = split(tryGetString("setup_ltvs"), ",")
1028+ let lts = split(tryGetString("setup_lts"), ",")
1029+ let rates = getActualRate(assets[0], "sRate")._2
1030+ let changeHandler = split(afterChange, ",")
1031+ func f (accum,next) = if ((next >= size(assets)))
1032+ then accum
1033+ else {
1034+ let userSupplied = tryGetInteger(((address + "_supplied_") + assets[next]))
1035+ let userBorrowed = tryGetInteger(((address + "_borrowed_") + assets[next]))
1036+ let needTokenAccounting = if ((afterChange == ""))
1037+ then if (if ((userBorrowed != 0))
1038+ then true
1039+ else (userSupplied != 0))
1040+ then true
1041+ else false
1042+ else true
1043+ if (needTokenAccounting)
1044+ then {
1045+ let assetScale = calcAssetScale(assets[next])
1046+ let assetPrice = getTokenPriceForHealth(assets[next])
1047+ ((accum + fraction(fraction(fraction((userSupplied + (if (if (if ((afterChange != ""))
1048+ then (changeHandler[0] == assets[next])
1049+ else false)
1050+ then (changeHandler[1] == "supplied")
1051+ else false)
1052+ then parseIntValue(changeHandler[2])
1053+ else 0)), rates[(next * 3)].value, Scale16), parseIntValue(ltvs[next]), Scale8), assetPrice._1, assetScale)) - (if (minusBorrowed)
1054+ then fraction(fraction(fraction((userBorrowed + (if (if (if ((afterChange != ""))
1055+ then (changeHandler[0] == assets[next])
1056+ else false)
1057+ then (changeHandler[1] == "borrowed")
1058+ else false)
1059+ then parseIntValue(changeHandler[2])
1060+ else 0)), rates[((next * 3) + 1)].value, Scale16), Scale8, parseIntValue(lts[next])), assetPrice._2, assetScale)
1061+ else 0))
1062+ }
1063+ else accum
1064+ }
1065+
1066+ let result = {
1067+ let $l = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11]
1068+ let $s = size($l)
1069+ let $acc0 = 0
1070+ func $f0_1 ($a,$i) = if (($i >= $s))
1071+ then $a
1072+ else f($a, $l[$i])
1073+
1074+ func $f0_2 ($a,$i) = if (($i >= $s))
1075+ then $a
1076+ else throw("List size exceeds 12")
1077+
1078+ $f0_2($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($acc0, 0), 1), 2), 3), 4), 5), 6), 7), 8), 9), 10), 11), 12)
1079+ }
1080+ if (debug)
1081+ then throw(toString(result))
1082+ else $Tuple2(rates, result)
1083+ }
1084+
1085+
1086+
1087+@Callable(i)
1088+func getPrices (debug) = {
1089+ let assets = getMarketAssets()
1090+ func f (accum,next) = if ((next >= size(assets)))
1091+ then accum
1092+ else {
1093+ let assetPrice = getTokenPriceWithRisk(assets[next], 3)
1094+ ((((accum + toString(assetPrice._1)) + ",") + toString(assetPrice._2)) + "|")
1095+ }
1096+
1097+ let result = {
1098+ let $l = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11]
1099+ let $s = size($l)
1100+ let $acc0 = ""
1101+ func $f0_1 ($a,$i) = if (($i >= $s))
1102+ then $a
1103+ else f($a, $l[$i])
1104+
1105+ func $f0_2 ($a,$i) = if (($i >= $s))
1106+ then $a
1107+ else throw("List size exceeds 12")
1108+
1109+ $f0_2($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($acc0, 0), 1), 2), 3), 4), 5), 6), 7), 8), 9), 10), 11), 12)
1110+ }
1111+ if (debug)
1112+ then throw(result)
1113+ else $Tuple2(nil, result)
1114+ }
1115+
1116+
1117+
1118+@Callable(i)
1119+func calculateUtilizationRatio (assetIdStr,debug) = if (debug)
1120+ then throw(toString(getUr(assetIdStr)))
1121+ else $Tuple2(nil, getUr(assetIdStr))
1122+
1123+
1124+
1125+@Callable(i)
1126+func calculateOutdatedUR (assetIdStr,debug) = if (debug)
1127+ then throw(toString(getOutdatedUr(assetIdStr)))
1128+ else $Tuple2(nil, getOutdatedUr(assetIdStr))
1129+
1130+
1131+
1132+@Callable(i)
1133+func calculateTokenRates (debug) = {
1134+ func f (accum,assetIdStr) = {
1135+ let rates = tokenRatesRecalc(assetIdStr)
1136+ let lastBRate = max([tryGetInteger((assetIdStr + "_bRate")), Scale16])
1137+ let feeDelta = fraction(reserveFund, fraction(tryGetInteger(("total_borrowed_" + assetIdStr)), (rates[1].value - lastBRate), Scale16), 100)
1138+ let feeEntry = IntegerEntry((("fee_" + assetIdStr) + "_interest"), (tryGetInteger((("fee_" + assetIdStr) + "_interest")) + feeDelta))
1139+ $Tuple3(((((accum._1 + toString(rates[1].value)) + "|") + toString(rates[0].value)) + ","), (accum._2 ++ rates), (accum._3 ++ [feeEntry]))
1140+ }
1141+
1142+ let parameter = {
1143+ let $l = getMarketAssets()
1144+ let $s = size($l)
1145+ let $acc0 = $Tuple3("", nil, nil)
1146+ func $f0_1 ($a,$i) = if (($i >= $s))
1147+ then $a
1148+ else f($a, $l[$i])
1149+
1150+ func $f0_2 ($a,$i) = if (($i >= $s))
1151+ then $a
1152+ else throw("List size exceeds 12")
1153+
1154+ $f0_2($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($acc0, 0), 1), 2), 3), 4), 5), 6), 7), 8), 9), 10), 11), 12)
1155+ }
1156+ if (debug)
1157+ then throw(parameter._1)
1158+ else $Tuple2((parameter._2 ++ parameter._3), parameter._1)
1159+ }
1160+
1161+
1162+
1163+@Callable(i)
1164+func calculateTokensInterest (debug) = {
1165+ func f (accum,assetIdStr) = {
1166+ let rate = fraction(getInterest(assetIdStr), dayBlocks, Scale8)
1167+ ((accum + toString(rate)) + ",")
1168+ }
1169+
1170+ let parameter = {
1171+ let $l = getMarketAssets()
1172+ let $s = size($l)
1173+ let $acc0 = ""
1174+ func $f0_1 ($a,$i) = if (($i >= $s))
1175+ then $a
1176+ else f($a, $l[$i])
1177+
1178+ func $f0_2 ($a,$i) = if (($i >= $s))
1179+ then $a
1180+ else throw("List size exceeds 12")
1181+
1182+ $f0_2($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($acc0, 0), 1), 2), 3), 4), 5), 6), 7), 8), 9), 10), 11), 12)
1183+ }
1184+ if (debug)
1185+ then throw(parameter)
1186+ else $Tuple2(nil, parameter)
1187+ }
1188+
1189+
1190+
1191+@Callable(i)
1192+func setApproverAddress (approverAddress) = {
1193+ let isSelf = if ((i.caller == this))
1194+ then true
1195+ else throw("Only self invoke")
1196+ if ((isSelf == isSelf))
1197+ then {
1198+ let _approverAddress = addressFromString(approverAddress)
1199+ let approverOk = match _approverAddress {
1200+ case t: Address =>
1201+ true
1202+ case _ =>
1203+ false
1204+ }
1205+ let canSetApprover = if (if (approverOk)
1206+ then true
1207+ else (approverAddress == ""))
1208+ then true
1209+ else throw("Wrong approver address")
1210+ if ((canSetApprover == canSetApprover))
1211+ then {
1212+ let isInited = valueOrElse(getBoolean(value(_approverAddress), "INITED"), false)
1213+ let hasAdmins = (valueOrElse(getString(value(_approverAddress), "ADMINS_PBKS"), "") != "")
1214+ let isApproverContract = if (if ((approverAddress == ""))
1215+ then true
1216+ else if (isInited)
1217+ then hasAdmins
1218+ else false)
1219+ then true
1220+ else throw("Address is not approver contract")
1221+ if ((isApproverContract == isApproverContract))
1222+ then [StringEntry("APPROVER_ADDRESS", approverAddress)]
1223+ else throw("Strict value is not equal to itself.")
1224+ }
1225+ else throw("Strict value is not equal to itself.")
1226+ }
1227+ else throw("Strict value is not equal to itself.")
1228+ }
1229+
1230+
1231+
1232+@Callable(i)
1233+func initNewMaster (master) = {
1234+ let addressOK = match addressFromString(master) {
1235+ case a: Address =>
1236+ true
1237+ case _ =>
1238+ false
1239+ }
1240+ if (!(addressOK))
1241+ then throw(("incorrect address " + master))
1242+ else if ((i.caller != this))
1243+ then throw("available for self call only")
1244+ else [StringEntry("verifier_master", master)]
1245+ }
1246+
1247+
1248+
1249+@Callable(i)
1250+func requestNewMaster (newMaster) = {
1251+ let addressOK = match addressFromString(newMaster) {
1252+ case a: Address =>
1253+ true
1254+ case _ =>
1255+ false
1256+ }
1257+ if (!(addressOK))
1258+ then throw(("incorrect address " + newMaster))
1259+ else if ((indexOf(sentinels, i.caller) == unit))
1260+ then throw("whitelist only")
1261+ else [StringEntry("verifier_newMaster", newMaster), IntegerEntry("verifier_newMasterEligibleAfter", (height + 10000))]
1262+ }
1263+
1264+
1265+
1266+@Callable(i)
1267+func activateNewMaster () = {
1268+ let eligibleHeight = getIntegerValue(this, "verifier_newMasterEligibleAfter")
1269+ let newMaster = getStringValue(this, "verifier_newMaster")
1270+ if ((indexOf(sentinels, i.caller) == unit))
1271+ then throw("whitelist only")
1272+ else if ((eligibleHeight > height))
1273+ then throw("new master cannot be activated yet")
1274+ else [DeleteEntry("verifier_newMaster"), DeleteEntry("verifier_newMasterEligibleAfter"), StringEntry("verifier_master", newMaster)]
1275+ }
1276+
1277+
1278+@Verifier(tx)
1279+func verify () = {
1280+ let multisigStr = valueOrElse(getString("APPROVER_ADDRESS"), "")
1281+ let multisigAddress = addressFromString(multisigStr)
1282+ let multisigOk = match multisigAddress {
1283+ case t: Address =>
1284+ true
1285+ case _ =>
1286+ false
1287+ }
1288+ let isInited = if (multisigOk)
1289+ then valueOrElse(getBoolean(value(multisigAddress), "INITED"), false)
1290+ else false
1291+ let hasAdmins = if (multisigOk)
1292+ then (valueOrElse(getString(value(multisigAddress), "ADMINS_PBKS"), "") != "")
1293+ else false
1294+ if (if (if (multisigOk)
1295+ then isInited
1296+ else false)
1297+ then hasAdmins
1298+ else false)
1299+ then match tx {
1300+ case ttx: SetScriptTransaction =>
1301+ match ttx.script {
1302+ case script: ByteVector =>
1303+ let scriptHasha = toBase58String(blake2b256(script))
1304+ let validFrom = valueOrErrorMessage(getInteger(value(multisigAddress), (((("script%%" + CONTRACT_TYPE) + "%%") + scriptHasha) + "%%validFrom")), "validFrom not set")
1305+ let validTo = valueOrErrorMessage(getInteger(value(multisigAddress), (((("script%%" + CONTRACT_TYPE) + "%%") + scriptHasha) + "%%validTo")), "validTo not set")
1306+ if (if (if ((height >= validFrom))
1307+ then (validTo >= height)
1308+ else false)
1309+ then (12000000 >= ttx.fee)
1310+ else false)
1311+ then (scriptHash(this) != blake2b256(script))
1312+ else false
1313+ case _ =>
1314+ false
1315+ }
1316+ case otx =>
1317+ let taskId = ((("tx_" + toString(this)) + "_") + toBase58String(otx.id))
1318+ let isApproved = valueOrElse(getBoolean(value(multisigAddress), (((toString(this) + "_") + toBase58String(otx.id)) + "__approved")), false)
1319+ let approvedFrom = valueOrElse(getInteger(value(multisigAddress), (taskId + "__approvedFrom")), 0)
1320+ if (isApproved)
1321+ then (height >= approvedFrom)
1322+ else false
1323+ }
1324+ else {
1325+ let masterAddress = getString("verifier_master")
1326+ let approvedByMaster = match masterAddress {
1327+ case x: String =>
1328+ match getInteger(addressFromStringValue(x), ("approvedTx_" + toBase58String(tx.id))) {
1329+ case y: Int =>
1330+ y
1331+ case _ =>
1332+ 0
1333+ }
1334+ case _ =>
1335+ 1
1336+ }
1337+ if (sigVerify(tx.bodyBytes, tx.proofs[0], tx.senderPublicKey))
1338+ then (approvedByMaster > 0)
1339+ else false
1340+ }
1341+ }
1342+

github/deemru/w8io
43.81 ms