tx · 9vJFV6s8WPmG83t2rKXi7cDxg5Jc7YPonZy38qRTY5xw

3M8Rtqj1e8zWr4MJNBBvw1RtBzumPGWfU3M:  -0.06000000 Waves

2026.08.28 17:43 [1314050] smart account 3M8Rtqj1e8zWr4MJNBBvw1RtBzumPGWfU3M > SELF 0.00000000 Waves

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

github/deemru/w8io
273.42 ms