tx · 3MMioBn1hHwv1QAJHUuVqRC6odBGs6sn6St2Q2MxTgca

3MMQEhb3L8MhxW8qcvHueXPwffMJHHmLKeE:  -0.06000000 Waves

2026.05.06 02:42 [537303] smart account 3MMQEhb3L8MhxW8qcvHueXPwffMJHHmLKeE > SELF 0.00000000 Waves

{ "type": 13, "id": "3MMioBn1hHwv1QAJHUuVqRC6odBGs6sn6St2Q2MxTgca", "fee": 6000000, "feeAssetId": null, "timestamp": 1778024533014, "version": 2, "chainId": 82, "sender": "3MMQEhb3L8MhxW8qcvHueXPwffMJHHmLKeE", "senderPublicKey": "EjzEBCkPpgUboKArtrkGsKJoUtmbS9UL6VskZR6HXnE3", "proofs": [ "94jmFmvpAks8KjnCKJRXVPu6C2Mabv9Q8FmBHCxESfu6moRLuM78PRYaN5tKbkZo4juw7si2Qu8MnSx61PDupDN" ], "script": "base64:BgJuCAISBQoDGAEBEgMKAQgSAwoBCBIDCgEIEgMKAQgSAwoBCBIDCgEIEgMKAQESAwoBARIDCgEBEgMKAQESCAoGCAgICAgBEgMKAQgSAwoBCBIDCgEIEgkKBwgICAEICAgSAwoBCBIDCgEIEgMKAQghAAdWRVJTSU9OAgUxLjEuNAADU0VQAgFfAAZCSUdTRVACAl9fAAhrX0FETUlOUwILQURNSU5TX1BCS1MACmtfTUFOQUdFUlMCDU1BTkFHRVJTX1BCS1MAB2tfTElNSVQCDFZPVEVTX1FVT1JVTQAOa19TQ1JJUFRfVFlQRVMCDFNDUklQVF9UWVBFUwALa19JVEVSQVRJT04CCUlURVJBVElPTgAIa19JTklURUQCBklOSVRFRAASa19TQ1JJUFRTX0NPT0xET1dOAg9TQ1JJUFRTQ09PTERPV04AEWtfU1VCTUlUX0NPT0xET1dOAg9TVUJNSVRfQ09PTERPV04AD2tfVEFTS19DT09MRE9XTgINVEFTS19DT09MRE9XTgAMa19zY3JpcHRUeXBlAgpzY3JpcHRUeXBlAAxrX3NjcmlwdEhhc2gCCnNjcmlwdEhhc2gAEGtfc3RvcmFnZUFkZHJlc3MCDnN0b3JhZ2VBZGRyZXNzAAZrX2Rlc2MCBGRlc2MABmtfaXRlcgIJaXRlcmF0aW9uAAtrX2luaXRpYXRvcgIJaW5pdGlhdG9yAA9rX2NvbmZpcm1hdGlvbnMCDWNvbmZpcm1hdGlvbnMADWtfdmFsaWRCbG9ja3MCC3ZhbGlkQmxvY2tzAAlrX3ZhbGlkVG8CB3ZhbGlkVG8AC2tfdmFsaWRGcm9tAgl2YWxpZEZyb20BFWdldFNjcmlwdFZhbGlkRnJvbUtleQIKc2NyaXB0VHlwZQpzY3JpcHRIYXNoCQCsAgIJAKwCAgkArAICCQCsAgIJAKwCAgIIc2NyaXB0JSUFCnNjcmlwdFR5cGUCAiUlBQpzY3JpcHRIYXNoAgIlJQULa192YWxpZEZyb20BE2dldFNjcmlwdFZhbGlkVG9LZXkCCnNjcmlwdFR5cGUKc2NyaXB0SGFzaAkArAICCQCsAgIJAKwCAgkArAICCQCsAgICCHNjcmlwdCUlBQpzY3JpcHRUeXBlAgIlJQUKc2NyaXB0SGFzaAICJSUFCWtfdmFsaWRUbwEMX3ZhbGlkYXRlUGJrAQNwYmsECGtleUJ5dGVzCQDZBAEFA3BiawQLY2hlY2tMZW5ndGgDCQECIT0CCQDIAQEFCGtleUJ5dGVzACAJAAIBAhJJbnZhbGlkIHB1YmxpYyBrZXkGAwkAAAIFC2NoZWNrTGVuZ3RoBQtjaGVja0xlbmd0aAQHYWRkcmVzcwkApwgBBQhrZXlCeXRlcwMJAAACBQdhZGRyZXNzBQdhZGRyZXNzBAphZGRyZXNzU3RyCQClCAEFB2FkZHJlc3MDCQAAAgUKYWRkcmVzc1N0cgUKYWRkcmVzc1N0cgkAZgIJALECAQUKYWRkcmVzc1N0cgAACQACAQIkU3RyaWN0IHZhbHVlIGlzIG5vdCBlcXVhbCB0byBpdHNlbGYuCQACAQIkU3RyaWN0IHZhbHVlIGlzIG5vdCBlcXVhbCB0byBpdHNlbGYuCQACAQIkU3RyaWN0IHZhbHVlIGlzIG5vdCBlcXVhbCB0byBpdHNlbGYuARBfdmFsaWRhdGVBZGRyZXNzAQdhZGRyZXNzBARhZGRyCQERQGV4dHJOYXRpdmUoMTA2MikBBQdhZGRyZXNzAwkAAAIFBGFkZHIFBGFkZHIGCQACAQIkU3RyaWN0IHZhbHVlIGlzIG5vdCBlcXVhbCB0byBpdHNlbGYuAQtfdmFsaWRhdGVUcwECdHMEBmN1cnJUcwQHJG1hdGNoMAkA7QcBBQZoZWlnaHQDCQABAgUHJG1hdGNoMAIJQmxvY2tJbmZvBAVibG9jawUHJG1hdGNoMAgFBWJsb2NrCXRpbWVzdGFtcAkAAgECEENhbid0IGZpbmQgYmxvY2sEB29uZUhvdXIJAGgCCQBoAgA8ADwA6AcEBW1pblRzCQBlAgUGY3VyclRzBQdvbmVIb3VyCQBnAgUCdHMFBW1pblRzAQlfZ2V0TGltaXQACQETdmFsdWVPckVycm9yTWVzc2FnZQIJAJ8IAQUHa19MSU1JVAIYUXVvcnVtIGxpbWl0IG5vdCBkZWZpbmVkAQhfaXNBZG1pbgEDcGJrBAlhZG1pbnNTdHIJAQt2YWx1ZU9yRWxzZQIJAKIIAQUIa19BRE1JTlMCAAQGYWRtaW5zCQC1CQIFCWFkbWluc1N0cgIBLAkBAiE9AgkAzwgCBQZhZG1pbnMFA3BiawUEdW5pdAEKX2lzTWFuYWdlcgEDcGJrBAttYW5hZ2Vyc1N0cgkBC3ZhbHVlT3JFbHNlAgkAoggBBQprX01BTkFHRVJTAgAECG1hbmFnZXJzCQC1CQIFC21hbmFnZXJzU3RyAgEsCQECIT0CCQDPCAIFCG1hbmFnZXJzBQNwYmsFBHVuaXQBEF9pc1ZhbGlkT3BlcmF0b3IBA3BiawQLbWFuYWdlcnNTdHIJAQt2YWx1ZU9yRWxzZQIJAKIIAQUKa19NQU5BR0VSUwIABAhtYW5hZ2VycwkAtQkCBQttYW5hZ2Vyc1N0cgIBLAQHaXNBZG1pbgkBCF9pc0FkbWluAQUDcGJrBAlpc01hbmFnZXIJAQpfaXNNYW5hZ2VyAQUDcGJrAwUHaXNBZG1pbgYFCWlzTWFuYWdlcgEZX2ZpbHRlclZhbGlkQ29uZmlybWF0aW9ucwENY29uZmlybWF0aW9ucwoBC2ZpbHRlclZhbGlkAgNhY2MDcGJrAwkBCF9pc0FkbWluAQUDcGJrCQDNCAIFA2FjYwUDcGJrBQNhY2MKAAIkbAUNY29uZmlybWF0aW9ucwoAAiRzCQCQAwEFAiRsCgAFJGFjYzAFA25pbAoBBSRmMF8xAgIkYQIkaQMJAGcCBQIkaQUCJHMFAiRhCQELZmlsdGVyVmFsaWQCBQIkYQkAkQMCBQIkbAUCJGkKAQUkZjBfMgICJGECJGkDCQBnAgUCJGkFAiRzBQIkYQkAAgECFExpc3Qgc2l6ZSBleGNlZWRzIDIwCQEFJGYwXzICCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECBQUkYWNjMAAAAAEAAgADAAQABQAGAAcACAAJAAoACwAMAA0ADgAPABAAEQASABMAFAEJX2lzSW5pdGVkAAkBC3ZhbHVlT3JFbHNlAgkAoAgBBQhrX0lOSVRFRAcTAWkBBGluaXQDC2FkbWluc19wYmtzBWxpbWl0D3NjcmlwdHNDb29sZG93bgQGaXNTZWxmAwkAAAIIBQFpBmNhbGxlcgUEdGhpcwYJAAIBAhBPbmx5IHNlbGYgaW52b2tlAwkAAAIFBmlzU2VsZgUGaXNTZWxmBAtjaGVja0luaXRlZAMJAQlfaXNJbml0ZWQACQACAQIOQWxyZWFkeSBpbml0ZWQGAwkAAAIFC2NoZWNrSW5pdGVkBQtjaGVja0luaXRlZAQLc2l6ZV9hZG1pbnMDCQECIT0CCQCQAwEFC2FkbWluc19wYmtzAAAGCQACAQInQXQgbGVhc3Qgb25lIGFkbWluIHBiayBzaG91bGQgYmUgcGFzc2VkAwkAAAIFC3NpemVfYWRtaW5zBQtzaXplX2FkbWlucwQRc2l6ZV9hZG1pbnNfbGltaXQDCQBnAgAUCQCQAwEFC2FkbWluc19wYmtzBgkAAgEJAKwCAgIpTWF4aW11bSBhZG1pbiBjb3VudCBpcyAyMCwgY3VycmVudCBzaXplOiAJAKQDAQkAkAMBBQthZG1pbnNfcGJrcwMJAAACBRFzaXplX2FkbWluc19saW1pdAURc2l6ZV9hZG1pbnNfbGltaXQEDGNoZWNrX2FkbWlucwMJAQEhAQkBCWlzRGVmaW5lZAEJAKIIAQUIa19BRE1JTlMGCQACAQIOQWxyZWFkeSBpbml0ZWQDCQAAAgUMY2hlY2tfYWRtaW5zBQxjaGVja19hZG1pbnMECXplcm9MaW1pdAMJAGYCBQVsaW1pdAAABgkAAgECE0xpbWl0IHNob3VsZCBiZSA+IDADCQAAAgUJemVyb0xpbWl0BQl6ZXJvTGltaXQEFGNoZWNrU2NyaXB0c0Nvb2xkb3duAwkAZgIFD3NjcmlwdHNDb29sZG93bgAABgkAAgECHlNjcmlwdHMgY29vbGRvd24gc2hvdWxkIGJlID4gMAMJAAACBRRjaGVja1NjcmlwdHNDb29sZG93bgUUY2hlY2tTY3JpcHRzQ29vbGRvd24ECGxpbWl0X29rAwkAZwIJAJADAQULYWRtaW5zX3Bia3MFBWxpbWl0BgkAAgEJAKwCAgkArAICCQCsAgICOUxpbWl0IHF1b3J1bSBzaG91bGQgYmUgPD0gc2l6ZSBvZiBsaXN0IG9mIGFkbWlucywgbGltaXQ6IAkApAMBBQVsaW1pdAIQLCBjdXJyZW50IHNpemU6IAkApAMBCQCQAwEFC2FkbWluc19wYmtzAwkAAAIFCGxpbWl0X29rBQhsaW1pdF9vawoBCHZhbGlkYXRlAgVhY2N1bQRuZXh0CQEMX3ZhbGlkYXRlUGJrAQUEbmV4dAQIdmFsaWRSZXMKAAIkbAULYWRtaW5zX3Bia3MKAAIkcwkAkAMBBQIkbAoABSRhY2MwAgAKAQUkZjBfMQICJGECJGkDCQBnAgUCJGkFAiRzBQIkYQkBCHZhbGlkYXRlAgUCJGEJAJEDAgUCJGwFAiRpCgEFJGYwXzICAiRhAiRpAwkAZwIFAiRpBQIkcwUCJGEJAAIBAhRMaXN0IHNpemUgZXhjZWVkcyAyMAkBBSRmMF8yAgkBBSRmMF8xAgkBBSRmMF8xAgkBBSRmMF8xAgkBBSRmMF8xAgkBBSRmMF8xAgkBBSRmMF8xAgkBBSRmMF8xAgkBBSRmMF8xAgkBBSRmMF8xAgkBBSRmMF8xAgkBBSRmMF8xAgkBBSRmMF8xAgkBBSRmMF8xAgkBBSRmMF8xAgkBBSRmMF8xAgkBBSRmMF8xAgkBBSRmMF8xAgkBBSRmMF8xAgkBBSRmMF8xAgkBBSRmMF8xAgUFJGFjYzAAAAABAAIAAwAEAAUABgAHAAgACQAKAAsADAANAA4ADwAQABEAEgATABQDCQAAAgUIdmFsaWRSZXMFCHZhbGlkUmVzBAlhZG1pbnNTdHIJALkJAgULYWRtaW5zX3Bia3MCASwJAMwIAgkBC1N0cmluZ0VudHJ5AgUIa19BRE1JTlMFCWFkbWluc1N0cgkAzAgCCQEMSW50ZWdlckVudHJ5AgUHa19MSU1JVAUFbGltaXQJAMwIAgkBDEludGVnZXJFbnRyeQIFEmtfU0NSSVBUU19DT09MRE9XTgUPc2NyaXB0c0Nvb2xkb3duCQDMCAIJAQxJbnRlZ2VyRW50cnkCBRFrX1NVQk1JVF9DT09MRE9XTgADCQDMCAIJAQxJbnRlZ2VyRW50cnkCBQ9rX1RBU0tfQ09PTERPV04AAAkAzAgCCQEMQm9vbGVhbkVudHJ5AgUIa19JTklURUQGBQNuaWwJAAIBAiRTdHJpY3QgdmFsdWUgaXMgbm90IGVxdWFsIHRvIGl0c2VsZi4JAAIBAiRTdHJpY3QgdmFsdWUgaXMgbm90IGVxdWFsIHRvIGl0c2VsZi4JAAIBAiRTdHJpY3QgdmFsdWUgaXMgbm90IGVxdWFsIHRvIGl0c2VsZi4JAAIBAiRTdHJpY3QgdmFsdWUgaXMgbm90IGVxdWFsIHRvIGl0c2VsZi4JAAIBAiRTdHJpY3QgdmFsdWUgaXMgbm90IGVxdWFsIHRvIGl0c2VsZi4JAAIBAiRTdHJpY3QgdmFsdWUgaXMgbm90IGVxdWFsIHRvIGl0c2VsZi4JAAIBAiRTdHJpY3QgdmFsdWUgaXMgbm90IGVxdWFsIHRvIGl0c2VsZi4JAAIBAiRTdHJpY3QgdmFsdWUgaXMgbm90IGVxdWFsIHRvIGl0c2VsZi4JAAIBAiRTdHJpY3QgdmFsdWUgaXMgbm90IGVxdWFsIHRvIGl0c2VsZi4BaQEIYWRkQWRtaW4BA3BiawQGaXNTZWxmAwkAAAIIBQFpBmNhbGxlcgUEdGhpcwYJAAIBAhBPbmx5IHNlbGYgaW52b2tlAwkAAAIFBmlzU2VsZgUGaXNTZWxmBAdpc1ZhbGlkAwkBDF92YWxpZGF0ZVBiawEFA3BiawYJAAIBAhFJbnZhbGlkIGFkbWluIHBiawMJAAACBQdpc1ZhbGlkBQdpc1ZhbGlkBAxtYW5hZ2Vyc0xpc3QJALUJAgkBC3ZhbHVlT3JFbHNlAgkAoggBBQprX01BTkFHRVJTAgACASwEDmNoZWNrSXNNYW5hZ2VyAwkAAAIJAM8IAgUMbWFuYWdlcnNMaXN0BQNwYmsFBHVuaXQGCQACAQJRVGhpcyB1c2VyIGlzIGFscmVhZHkgbWFuYWdlciwgcmVtb3ZlIGZyb20gbWFuYWdlcnMgaWYgeW91IG5lZWQgdG8gYWRkIGl0IGFzIGFkbWluAwkAAAIFDmNoZWNrSXNNYW5hZ2VyBQ5jaGVja0lzTWFuYWdlcgQGYWRtaW5zCQERQGV4dHJOYXRpdmUoMTA1OCkBBQhrX0FETUlOUwQKYWRtaW5zTGlzdAkAtQkCBQZhZG1pbnMCASwEDmNoZWNrTWF4QWRtaW5zAwkAZwIJAJADAQUKYWRtaW5zTGlzdAAUCQACAQIgTWF4aW11bSBhZG1pbiBjb3VudCByZWFjaGVkICgyMCkGAwkAAAIFDmNoZWNrTWF4QWRtaW5zBQ5jaGVja01heEFkbWlucwQMY2hlY2tQcmVzZW50AwkBAiE9AgkAzwgCBQphZG1pbnNMaXN0BQNwYmsFBHVuaXQJAAIBAhpUaGlzIGFkbWluIGFscmVhZHkgcHJlc2VudAYDCQAAAgUMY2hlY2tQcmVzZW50BQxjaGVja1ByZXNlbnQEDG5ld0FkbWluc1N0cgkArAICCQCsAgIFBmFkbWlucwIBLAUDcGJrCQDMCAIJAQtTdHJpbmdFbnRyeQIFCGtfQURNSU5TBQxuZXdBZG1pbnNTdHIFA25pbAkAAgECJFN0cmljdCB2YWx1ZSBpcyBub3QgZXF1YWwgdG8gaXRzZWxmLgkAAgECJFN0cmljdCB2YWx1ZSBpcyBub3QgZXF1YWwgdG8gaXRzZWxmLgkAAgECJFN0cmljdCB2YWx1ZSBpcyBub3QgZXF1YWwgdG8gaXRzZWxmLgkAAgECJFN0cmljdCB2YWx1ZSBpcyBub3QgZXF1YWwgdG8gaXRzZWxmLgkAAgECJFN0cmljdCB2YWx1ZSBpcyBub3QgZXF1YWwgdG8gaXRzZWxmLgFpAQtyZW1vdmVBZG1pbgEDcGJrBAZpc1NlbGYDCQAAAggFAWkGY2FsbGVyBQR0aGlzBgkAAgECEE9ubHkgc2VsZiBpbnZva2UDCQAAAgUGaXNTZWxmBQZpc1NlbGYEB2lzVmFsaWQDCQEMX3ZhbGlkYXRlUGJrAQUDcGJrBgkAAgECEUludmFsaWQgYWRtaW4gcGJrAwkAAAIFB2lzVmFsaWQFB2lzVmFsaWQEDG9sZEFkbWluc1N0cgkBEUBleHRyTmF0aXZlKDEwNTgpAQUIa19BRE1JTlMECW9sZEFkbWlucwkAtQkCBQxvbGRBZG1pbnNTdHICASwECmNoZWNrQ291bnQDCQBnAgABCQCQAwEFCW9sZEFkbWlucwkAAgECL0Nhbm5vdCByZW1vdmUsIGF0IGxlYXN0IG9uZSBhZG1pbiBzaG91bGQgcmVtYWluBgMJAAACBQpjaGVja0NvdW50BQpjaGVja0NvdW50BAVpbmRleAkBE3ZhbHVlT3JFcnJvck1lc3NhZ2UCCQDPCAIFCW9sZEFkbWlucwUDcGJrAhhUaGlzIHBiayBpcyBub3QgYW4gYWRtaW4ECW5ld0FkbWlucwkA0QgCBQlvbGRBZG1pbnMFBWluZGV4BAVsaW1pdAkBCV9nZXRMaW1pdAAEC2NoZWNrUXVvcnVtAwkAZgIFBWxpbWl0CQCQAwEFCW5ld0FkbWlucwkAAgEJAKwCAgkArAICAjRDYW5ub3QgcmVtb3ZlOiBhZG1pbiBjb3VudCB3b3VsZCBmYWxsIGJlbG93IHF1b3J1bSAoCQCkAwEFBWxpbWl0AgEpBgMJAAACBQtjaGVja1F1b3J1bQULY2hlY2tRdW9ydW0EDG5ld0FkbWluc1N0cgkAuQkCBQluZXdBZG1pbnMCASwJAMwIAgkBC1N0cmluZ0VudHJ5AgUIa19BRE1JTlMFDG5ld0FkbWluc1N0cgUDbmlsCQACAQIkU3RyaWN0IHZhbHVlIGlzIG5vdCBlcXVhbCB0byBpdHNlbGYuCQACAQIkU3RyaWN0IHZhbHVlIGlzIG5vdCBlcXVhbCB0byBpdHNlbGYuCQACAQIkU3RyaWN0IHZhbHVlIGlzIG5vdCBlcXVhbCB0byBpdHNlbGYuCQACAQIkU3RyaWN0IHZhbHVlIGlzIG5vdCBlcXVhbCB0byBpdHNlbGYuAWkBCmFkZE1hbmFnZXIBA3BiawQGaXNTZWxmAwkAAAIIBQFpBmNhbGxlcgUEdGhpcwYJAAIBAhBPbmx5IHNlbGYgaW52b2tlAwkAAAIFBmlzU2VsZgUGaXNTZWxmBAdpc1ZhbGlkAwkBDF92YWxpZGF0ZVBiawEFA3BiawYJAAIBAhNJbnZhbGlkIG1hbmFnZXIgcGJrAwkAAAIFB2lzVmFsaWQFB2lzVmFsaWQECmFkbWluc0xpc3QJALUJAgkBC3ZhbHVlT3JFbHNlAgkAoggBBQhrX0FETUlOUwIAAgEsBAxjaGVja0lzQWRtaW4DCQAAAgkAzwgCBQphZG1pbnNMaXN0BQNwYmsFBHVuaXQGCQACAQJPVGhpcyB1c2VyIGlzIGFscmVhZHkgYWRtaW4sIHJlbW92ZSBmcm9tIGFkbWlucyBpZiB5b3UgbmVlZCB0byBhZGQgaXQgYXMgbWFuYWdlcgMJAAACBQxjaGVja0lzQWRtaW4FDGNoZWNrSXNBZG1pbgQIbWFuYWdlcnMJAQt2YWx1ZU9yRWxzZQIJAKIIAQUKa19NQU5BR0VSUwIABAxtYW5hZ2Vyc0xpc3QJALUJAgUIbWFuYWdlcnMCASwEDGNoZWNrUHJlc2VudAMJAQIhPQIJAM8IAgUMbWFuYWdlcnNMaXN0BQNwYmsFBHVuaXQJAAIBAhxUaGlzIG1hbmFnZXIgYWxyZWFkeSBwcmVzZW50BgMJAAACBQxjaGVja1ByZXNlbnQFDGNoZWNrUHJlc2VudAQObmV3TWFuYWdlcnNTdHIDCQAAAgUIbWFuYWdlcnMCAAUDcGJrCQCsAgIJAKwCAgUIbWFuYWdlcnMCASwFA3BiawkAzAgCCQELU3RyaW5nRW50cnkCBQprX01BTkFHRVJTBQ5uZXdNYW5hZ2Vyc1N0cgUDbmlsCQACAQIkU3RyaWN0IHZhbHVlIGlzIG5vdCBlcXVhbCB0byBpdHNlbGYuCQACAQIkU3RyaWN0IHZhbHVlIGlzIG5vdCBlcXVhbCB0byBpdHNlbGYuCQACAQIkU3RyaWN0IHZhbHVlIGlzIG5vdCBlcXVhbCB0byBpdHNlbGYuCQACAQIkU3RyaWN0IHZhbHVlIGlzIG5vdCBlcXVhbCB0byBpdHNlbGYuAWkBDXJlbW92ZU1hbmFnZXIBA3BiawQGaXNTZWxmAwkAAAIIBQFpBmNhbGxlcgUEdGhpcwYJAAIBAhBPbmx5IHNlbGYgaW52b2tlAwkAAAIFBmlzU2VsZgUGaXNTZWxmBAdpc1ZhbGlkAwkBDF92YWxpZGF0ZVBiawEFA3BiawYJAAIBAhNJbnZhbGlkIG1hbmFnZXIgcGJrAwkAAAIFB2lzVmFsaWQFB2lzVmFsaWQEDm9sZE1hbmFnZXJzU3RyCQERQGV4dHJOYXRpdmUoMTA1OCkBBQprX01BTkFHRVJTBAtvbGRNYW5hZ2VycwkAtQkCBQ5vbGRNYW5hZ2Vyc1N0cgIBLAQFaW5kZXgJARN2YWx1ZU9yRXJyb3JNZXNzYWdlAgkAzwgCBQtvbGRNYW5hZ2VycwUDcGJrAhpUaGlzIHBiayBpcyBub3QgYW4gbWFuYWdlcgQLbmV3TWFuYWdlcnMJANEIAgULb2xkTWFuYWdlcnMFBWluZGV4BA5uZXdNYW5hZ2Vyc1N0cgkAuQkCBQtuZXdNYW5hZ2VycwIBLAkAzAgCCQELU3RyaW5nRW50cnkCBQprX01BTkFHRVJTBQ5uZXdNYW5hZ2Vyc1N0cgUDbmlsCQACAQIkU3RyaWN0IHZhbHVlIGlzIG5vdCBlcXVhbCB0byBpdHNlbGYuCQACAQIkU3RyaWN0IHZhbHVlIGlzIG5vdCBlcXVhbCB0byBpdHNlbGYuAWkBDWFkZFNjcmlwdFR5cGUBCnNjcmlwdFR5cGUEBmlzU2VsZgMJAAACCAUBaQZjYWxsZXIFBHRoaXMGCQACAQIQT25seSBzZWxmIGludm9rZQMJAAACBQZpc1NlbGYFBmlzU2VsZgQKY2hlY2tFbXB0eQMJAAACCQCxAgEFCnNjcmlwdFR5cGUAAAkAAgECHFNjcmlwdCB0eXBlIGNhbiBub3QgYmUgZW1wdHkGAwkAAAIFCmNoZWNrRW1wdHkFCmNoZWNrRW1wdHkEDGNoZWNrTm9Db21tYQMJAQIhPQIJALMJAgUKc2NyaXB0VHlwZQIBLAUEdW5pdAkAAgECIVNjcmlwdCB0eXBlIGNhbm5vdCBjb250YWluIGNvbW1hcwYDCQAAAgUMY2hlY2tOb0NvbW1hBQxjaGVja05vQ29tbWEEDmNoZWNrTm9QZXJjZW50AwkBAiE9AgkAswkCBQpzY3JpcHRUeXBlAgElBQR1bml0CQACAQIeU2NyaXB0IHR5cGUgY2Fubm90IGNvbnRhaW4gJyUnBgMJAAACBQ5jaGVja05vUGVyY2VudAUOY2hlY2tOb1BlcmNlbnQEDWNoZWNrTm9CaWdTZXADCQECIT0CCQCzCQIFCnNjcmlwdFR5cGUCAl9fBQR1bml0CQACAQIfU2NyaXB0IHR5cGUgY2Fubm90IGNvbnRhaW4gJ19fJwYDCQAAAgUNY2hlY2tOb0JpZ1NlcAUNY2hlY2tOb0JpZ1NlcAQOc2NyaXB0VHlwZXNTdHIJAQt2YWx1ZU9yRWxzZQIJAKIIAQUOa19TQ1JJUFRfVFlQRVMCAAQLc2NyaXB0VHlwZXMJALwJAgUOc2NyaXB0VHlwZXNTdHICASwEC2NoZWNrRXhpc3RzAwkBAiE9AgkAzwgCBQtzY3JpcHRUeXBlcwUKc2NyaXB0VHlwZQUEdW5pdAkAAgEJAKwCAgkArAICAg1TY3JpcHQgdHlwZSA8BQpzY3JpcHRUeXBlAg8+IGFscmVhZHkgYWRkZWQGAwkAAAIFC2NoZWNrRXhpc3RzBQtjaGVja0V4aXN0cwQObmV3U2NyaXB0VHlwZXMDCQECIT0CBQ5zY3JpcHRUeXBlc1N0cgIACQDNCAIFC3NjcmlwdFR5cGVzBQpzY3JpcHRUeXBlCQDMCAIFCnNjcmlwdFR5cGUFA25pbAQRbmV3U2NyaXB0VHlwZXNTdHIJALoJAgUObmV3U2NyaXB0VHlwZXMCASwJAMwIAgkBC1N0cmluZ0VudHJ5AgUOa19TQ1JJUFRfVFlQRVMFEW5ld1NjcmlwdFR5cGVzU3RyBQNuaWwJAAIBAiRTdHJpY3QgdmFsdWUgaXMgbm90IGVxdWFsIHRvIGl0c2VsZi4JAAIBAiRTdHJpY3QgdmFsdWUgaXMgbm90IGVxdWFsIHRvIGl0c2VsZi4JAAIBAiRTdHJpY3QgdmFsdWUgaXMgbm90IGVxdWFsIHRvIGl0c2VsZi4JAAIBAiRTdHJpY3QgdmFsdWUgaXMgbm90IGVxdWFsIHRvIGl0c2VsZi4JAAIBAiRTdHJpY3QgdmFsdWUgaXMgbm90IGVxdWFsIHRvIGl0c2VsZi4JAAIBAiRTdHJpY3QgdmFsdWUgaXMgbm90IGVxdWFsIHRvIGl0c2VsZi4BaQEQcmVtb3ZlU2NyaXB0VHlwZQEKc2NyaXB0VHlwZQQGaXNTZWxmAwkAAAIIBQFpBmNhbGxlcgUEdGhpcwYJAAIBAhBPbmx5IHNlbGYgaW52b2tlAwkAAAIFBmlzU2VsZgUGaXNTZWxmBA5zY3JpcHRUeXBlc1N0cgkBC3ZhbHVlT3JFbHNlAgkAoggBBQ5rX1NDUklQVF9UWVBFUwIABAtzY3JpcHRUeXBlcwkAvAkCBQ5zY3JpcHRUeXBlc1N0cgIBLAQFaW5kZXgJARN2YWx1ZU9yRXJyb3JNZXNzYWdlAgkAzwgCBQtzY3JpcHRUeXBlcwUKc2NyaXB0VHlwZQkArAICCQCsAgICDVNjcmlwdCB0eXBlIDwFCnNjcmlwdFR5cGUCED4gaXMgbm90IHByZXNlbnQEDm5ld1NjcmlwdFR5cGVzCQDRCAIFC3NjcmlwdFR5cGVzBQVpbmRleAQRbmV3U2NyaXB0VHlwZXNTdHIJALoJAgUObmV3U2NyaXB0VHlwZXMCASwJAMwIAgkBC1N0cmluZ0VudHJ5AgUOa19TQ1JJUFRfVFlQRVMFEW5ld1NjcmlwdFR5cGVzU3RyBQNuaWwJAAIBAiRTdHJpY3QgdmFsdWUgaXMgbm90IGVxdWFsIHRvIGl0c2VsZi4BaQEIc2V0TGltaXQBBWxpbWl0BAZpc1NlbGYDCQAAAggFAWkGY2FsbGVyBQR0aGlzBgkAAgECEE9ubHkgc2VsZiBpbnZva2UDCQAAAgUGaXNTZWxmBQZpc1NlbGYECXplcm9MaW1pdAMJAGYCBQVsaW1pdAAABgkAAgECE0xpbWl0IHNob3VsZCBiZSA+IDADCQAAAgUJemVyb0xpbWl0BQl6ZXJvTGltaXQEBmFkbWlucwkAtQkCCQERQGV4dHJOYXRpdmUoMTA1OCkBBQhrX0FETUlOUwIBLAMJAGYCBQVsaW1pdAkAkAMBBQZhZG1pbnMJAAIBCQCsAgIJAKwCAgkArAICAjlMaW1pdCBxdW9ydW0gc2hvdWxkIGJlIDw9IHNpemUgb2YgbGlzdCBvZiBhZG1pbnMsIGxpbWl0OiAJAKQDAQUFbGltaXQCECwgY3VycmVudCBzaXplOiAJAKQDAQkAkAMBBQZhZG1pbnMJAMwIAgkBDEludGVnZXJFbnRyeQIFB2tfTElNSVQFBWxpbWl0BQNuaWwJAAIBAiRTdHJpY3QgdmFsdWUgaXMgbm90IGVxdWFsIHRvIGl0c2VsZi4JAAIBAiRTdHJpY3QgdmFsdWUgaXMgbm90IGVxdWFsIHRvIGl0c2VsZi4BaQERc2V0Q29vbGRvd25CbG9ja3MBD3NjcmlwdHNDb29sZG93bgQGaXNTZWxmAwkAAAIIBQFpBmNhbGxlcgUEdGhpcwYJAAIBAhBPbmx5IHNlbGYgaW52b2tlAwkAAAIFBmlzU2VsZgUGaXNTZWxmBBRjaGVja1NjcmlwdHNDb29sZG93bgMJAGYCBQ9zY3JpcHRzQ29vbGRvd24AAAYJAAIBAh5TY3JpcHRzIGNvb2xkb3duIHNob3VsZCBiZSA+IDADCQAAAgUUY2hlY2tTY3JpcHRzQ29vbGRvd24FFGNoZWNrU2NyaXB0c0Nvb2xkb3duBBBjaGVja01heENvb2xkb3duAwkAZgIFD3NjcmlwdHNDb29sZG93bgDAcAkAAgECNlNjcmlwdHMgY29vbGRvd24gY2Fubm90IGV4Y2VlZCAxNDQwMCBibG9ja3MgKH4xMCBkYXlzKQYDCQAAAgUQY2hlY2tNYXhDb29sZG93bgUQY2hlY2tNYXhDb29sZG93bgkAzAgCCQEMSW50ZWdlckVudHJ5AgUSa19TQ1JJUFRTX0NPT0xET1dOBQ9zY3JpcHRzQ29vbGRvd24FA25pbAkAAgECJFN0cmljdCB2YWx1ZSBpcyBub3QgZXF1YWwgdG8gaXRzZWxmLgkAAgECJFN0cmljdCB2YWx1ZSBpcyBub3QgZXF1YWwgdG8gaXRzZWxmLgkAAgECJFN0cmljdCB2YWx1ZSBpcyBub3QgZXF1YWwgdG8gaXRzZWxmLgFpARFzZXRTdWJtaXRDb29sZG93bgEOc3VibWl0Q29vbGRvd24EBmlzU2VsZgMJAAACCAUBaQZjYWxsZXIFBHRoaXMGCQACAQIQT25seSBzZWxmIGludm9rZQMJAAACBQZpc1NlbGYFBmlzU2VsZgQNY2hlY2tDb29sZG93bgMJAGcCBQ5zdWJtaXRDb29sZG93bgAABgkAAgECHlN1Ym1pdCBjb29sZG93biBzaG91bGQgYmUgPj0gMAMJAAACBQ1jaGVja0Nvb2xkb3duBQ1jaGVja0Nvb2xkb3duCQDMCAIJAQxJbnRlZ2VyRW50cnkCBRFrX1NVQk1JVF9DT09MRE9XTgUOc3VibWl0Q29vbGRvd24FA25pbAkAAgECJFN0cmljdCB2YWx1ZSBpcyBub3QgZXF1YWwgdG8gaXRzZWxmLgkAAgECJFN0cmljdCB2YWx1ZSBpcyBub3QgZXF1YWwgdG8gaXRzZWxmLgFpAQ9zZXRUYXNrQ29vbGRvd24BDHRhc2tDb29sZG93bgQGaXNTZWxmAwkAAAIIBQFpBmNhbGxlcgUEdGhpcwYJAAIBAhBPbmx5IHNlbGYgaW52b2tlAwkAAAIFBmlzU2VsZgUGaXNTZWxmBA1jaGVja0Nvb2xkb3duAwkAZwIFDHRhc2tDb29sZG93bgAABgkAAgECHFRhc2sgY29vbGRvd24gc2hvdWxkIGJlID49IDADCQAAAgUNY2hlY2tDb29sZG93bgUNY2hlY2tDb29sZG93bgQQY2hlY2tNYXhDb29sZG93bgMJAGYCBQx0YXNrQ29vbGRvd24APAkAAgECL1Rhc2sgY29vbGRvd24gY2Fubm90IGV4Y2VlZCA2MCBibG9ja3MgKH4xIGhvdXIpBgMJAAACBRBjaGVja01heENvb2xkb3duBRBjaGVja01heENvb2xkb3duCQDMCAIJAQxJbnRlZ2VyRW50cnkCBQ9rX1RBU0tfQ09PTERPV04FDHRhc2tDb29sZG93bgUDbmlsCQACAQIkU3RyaWN0IHZhbHVlIGlzIG5vdCBlcXVhbCB0byBpdHNlbGYuCQACAQIkU3RyaWN0IHZhbHVlIGlzIG5vdCBlcXVhbCB0byBpdHNlbGYuCQACAQIkU3RyaWN0IHZhbHVlIGlzIG5vdCBlcXVhbCB0byBpdHNlbGYuAWkBCWFkZFNjcmlwdAYKc2NyaXB0VHlwZQ5zdG9yYWdlQWRkcmVzcwtfc2NyaXB0SGFzaARkZXNjDGluaXRpYXRvckFkcgt2YWxpZEJsb2NrcwQJY2FsbGVyUGJrCQDYBAEIBQFpD2NhbGxlclB1YmxpY0tleQQRc3RvcmFnZVNjcmlwdEhhc2gJANgEAQkBBXZhbHVlAQkA8QcBCQERQGV4dHJOYXRpdmUoMTA2MikBBQ5zdG9yYWdlQWRkcmVzcwQOc2NyaXB0VHlwZXNTdHIJARFAZXh0ck5hdGl2ZSgxMDU4KQEFDmtfU0NSSVBUX1RZUEVTBAtzY3JpcHRUeXBlcwkAvAkCBQ5zY3JpcHRUeXBlc1N0cgIBLAQJaXNBbGxvd2VkAwkBASEBCQEQX2lzVmFsaWRPcGVyYXRvcgEFCWNhbGxlclBiawkAAgECJE9ubHkgYWRtaW5zIGFuZCBtYW5hZ2VycyBhcmUgYWxsb3dlZAYDCQAAAgUJaXNBbGxvd2VkBQlpc0FsbG93ZWQEDWxhc3RTdWJtaXRLZXkJAKwCAgIRbGFzdFN1Ym1pdFNjcmlwdF8FCWNhbGxlclBiawQKbGFzdFN1Ym1pdAkBC3ZhbHVlT3JFbHNlAgkAnwgBBQ1sYXN0U3VibWl0S2V5AAAEDnN1Ym1pdENvb2xkb3duCQELdmFsdWVPckVsc2UCCQCfCAEFEWtfU1VCTUlUX0NPT0xET1dOAAMED19zdWJtaXRDb29sZG93bgMJAGYCBQ5zdWJtaXRDb29sZG93bgkAZQIFBmhlaWdodAUKbGFzdFN1Ym1pdAkAAgEJAKwCAgkArAICAhZTdWJtaXQgY29vbGRvd246IHdhaXQgCQCkAwEJAGUCBQ5zdWJtaXRDb29sZG93bgkAZQIFBmhlaWdodAUKbGFzdFN1Ym1pdAIMIG1vcmUgYmxvY2tzBgMJAAACBQ9fc3VibWl0Q29vbGRvd24FD19zdWJtaXRDb29sZG93bgQRX2NoZWNrU2NyaXB0VHlwZXMDCQAAAgkAzwgCBQtzY3JpcHRUeXBlcwUKc2NyaXB0VHlwZQUEdW5pdAkAAgEJAKwCAgI1aW52YWxpZCBzY3JpcHQgdHlwZSBvciBpdCBpcyBub3QgcHJlc2VudCBpbiBzdG9yYWdlOiAFCnNjcmlwdFR5cGUGAwkAAAIFEV9jaGVja1NjcmlwdFR5cGVzBRFfY2hlY2tTY3JpcHRUeXBlcwQXX3NjcmlwdFN0b3JhZ2VIYXNoQ2hlY2sDCQECIT0CBRFzdG9yYWdlU2NyaXB0SGFzaAULX3NjcmlwdEhhc2gJAAIBAjRTdG9yZWQgYW5kIHBhc3NlZCBhcyBhcmd1bWVudCBzY3JpcHRIYXNoZXMgbm90IG1hdGNoBgMJAAACBRdfc2NyaXB0U3RvcmFnZUhhc2hDaGVjawUXX3NjcmlwdFN0b3JhZ2VIYXNoQ2hlY2sECl9kZXNjQ2hlY2sDCQAAAgkAsQIBBQRkZXNjAAAJAAIBAhpEZXNjcmlwdGlvbiBjYW4ndCBiZSBlbXB0eQYDCQAAAgUKX2Rlc2NDaGVjawUKX2Rlc2NDaGVjawQPX2luaXRpYXRvckNoZWNrAwkBAiE9AgkApQgBCQCnCAEIBQFpD2NhbGxlclB1YmxpY0tleQUMaW5pdGlhdG9yQWRyCQACAQImSW5pdGlhdG9yIGFkZHJlc3MgZG9lc24ndCBtYXRjaCBjYWxsZXIGAwkAAAIFD19pbml0aWF0b3JDaGVjawUPX2luaXRpYXRvckNoZWNrBBFfY2hlY2tWYWxpZEJsb2NrcwMJAGYCBQt2YWxpZEJsb2NrcwAABgkAAgECGlZhbGlkIGJsb2NrcyBzaG91bGQgYmUgPiAwAwkAAAIFEV9jaGVja1ZhbGlkQmxvY2tzBRFfY2hlY2tWYWxpZEJsb2NrcwQUX2NoZWNrTWF4VmFsaWRCbG9ja3MDCQBmAgULdmFsaWRCbG9ja3MA4E4JAAIBAjB2YWxpZEJsb2NrcyBjYW5ub3QgZXhjZWVkIDEwMDgwIGJsb2NrcyAofjcgZGF5cykGAwkAAAIFFF9jaGVja01heFZhbGlkQmxvY2tzBRRfY2hlY2tNYXhWYWxpZEJsb2NrcwQPc2NyaXB0c0Nvb2xkb3duCQERQGV4dHJOYXRpdmUoMTA1NSkBBRJrX1NDUklQVFNfQ09PTERPV04EFF9jaGVja0Nvb2xkb3duV2luZG93AwkAZwIFD3NjcmlwdHNDb29sZG93bgULdmFsaWRCbG9ja3MJAAIBCQCsAgIJAKwCAgkArAICCQCsAgICDXZhbGlkQmxvY2tzICgJAKQDAQULdmFsaWRCbG9ja3MCKSkgbXVzdCBiZSBncmVhdGVyIHRoYW4gc2NyaXB0cyBjb29sZG93biAoCQCkAwEFD3NjcmlwdHNDb29sZG93bgIBKQYDCQAAAgUUX2NoZWNrQ29vbGRvd25XaW5kb3cFFF9jaGVja0Nvb2xkb3duV2luZG93BAlpdGVyYXRpb24JAGQCCQELdmFsdWVPckVsc2UCCQCfCAEJAKwCAgkArAICBQtrX0lURVJBVElPTgUDU0VQBQpzY3JpcHRUeXBlAAAAAQQIc2NyaXB0SWQJAKwCAgkArAICCQCsAgICCHNjcmlwdCUlBQpzY3JpcHRUeXBlAgIlJQULX3NjcmlwdEhhc2gEDV9jaGVja1ByZXNlbnQDCQEJaXNEZWZpbmVkAQkAoggBCQCsAgIJAKwCAgUIc2NyaXB0SWQFBkJJR1NFUAUMa19zY3JpcHRIYXNoCQACAQIlU2NyaXB0IHdpdGggdGhpcyBoYXNoIGFscmVhZHkgcHJlc2VudAYDCQAAAgUNX2NoZWNrUHJlc2VudAUNX2NoZWNrUHJlc2VudAkAzAgCCQELU3RyaW5nRW50cnkCCQCsAgIJAKwCAgUIc2NyaXB0SWQFBkJJR1NFUAUMa19zY3JpcHRUeXBlBQpzY3JpcHRUeXBlCQDMCAIJAQtTdHJpbmdFbnRyeQIJAKwCAgkArAICBQhzY3JpcHRJZAUGQklHU0VQBRBrX3N0b3JhZ2VBZGRyZXNzBQ5zdG9yYWdlQWRkcmVzcwkAzAgCCQELU3RyaW5nRW50cnkCCQCsAgIJAKwCAgUIc2NyaXB0SWQFBkJJR1NFUAUMa19zY3JpcHRIYXNoBRFzdG9yYWdlU2NyaXB0SGFzaAkAzAgCCQELU3RyaW5nRW50cnkCCQCsAgIJAKwCAgUIc2NyaXB0SWQFBkJJR1NFUAUGa19kZXNjBQRkZXNjCQDMCAIJAQxJbnRlZ2VyRW50cnkCCQCsAgIJAKwCAgUIc2NyaXB0SWQFBkJJR1NFUAUGa19pdGVyBQlpdGVyYXRpb24JAMwIAgkBDEludGVnZXJFbnRyeQIJAKwCAgkArAICBQhzY3JpcHRJZAUGQklHU0VQBQ1rX3ZhbGlkQmxvY2tzBQt2YWxpZEJsb2NrcwkAzAgCCQELU3RyaW5nRW50cnkCCQCsAgIJAKwCAgUIc2NyaXB0SWQFBkJJR1NFUAULa19pbml0aWF0b3IFDGluaXRpYXRvckFkcgkAzAgCCQELU3RyaW5nRW50cnkCCQCsAgIJAKwCAgkArAICCQCsAgIJAKwCAgUKc2NyaXB0VHlwZQUGQklHU0VQBQZrX2l0ZXIFBkJJR1NFUAkApAMBBQlpdGVyYXRpb24CBl9faGFzaAULX3NjcmlwdEhhc2gJAMwIAgkBDEludGVnZXJFbnRyeQIJAKwCAgkArAICBQtrX0lURVJBVElPTgUDU0VQBQpzY3JpcHRUeXBlBQlpdGVyYXRpb24JAMwIAgkBDEludGVnZXJFbnRyeQIFDWxhc3RTdWJtaXRLZXkFBmhlaWdodAUDbmlsCQACAQIkU3RyaWN0IHZhbHVlIGlzIG5vdCBlcXVhbCB0byBpdHNlbGYuCQACAQIkU3RyaWN0IHZhbHVlIGlzIG5vdCBlcXVhbCB0byBpdHNlbGYuCQACAQIkU3RyaWN0IHZhbHVlIGlzIG5vdCBlcXVhbCB0byBpdHNlbGYuCQACAQIkU3RyaWN0IHZhbHVlIGlzIG5vdCBlcXVhbCB0byBpdHNlbGYuCQACAQIkU3RyaWN0IHZhbHVlIGlzIG5vdCBlcXVhbCB0byBpdHNlbGYuCQACAQIkU3RyaWN0IHZhbHVlIGlzIG5vdCBlcXVhbCB0byBpdHNlbGYuCQACAQIkU3RyaWN0IHZhbHVlIGlzIG5vdCBlcXVhbCB0byBpdHNlbGYuCQACAQIkU3RyaWN0IHZhbHVlIGlzIG5vdCBlcXVhbCB0byBpdHNlbGYuCQACAQIkU3RyaWN0IHZhbHVlIGlzIG5vdCBlcXVhbCB0byBpdHNlbGYuCQACAQIkU3RyaWN0IHZhbHVlIGlzIG5vdCBlcXVhbCB0byBpdHNlbGYuAWkBDHJlbW92ZVNjcmlwdAEIc2NyaXB0SWQECF9jaGVja0lkAwkBAiE9AgkAswkCBQhzY3JpcHRJZAIIc2NyaXB0JSUAAAkAAgECF0ludmFsaWQgc2NyaXB0SWQgZm9ybWF0BgMJAAACBQhfY2hlY2tJZAUIX2NoZWNrSWQECWNhbGxlclBiawkA2AQBCAUBaQ9jYWxsZXJQdWJsaWNLZXkEDWNhbGxlckFkZHJlc3MJAKUIAQkApwgBCAUBaQ9jYWxsZXJQdWJsaWNLZXkEB2lzQWRtaW4JAQhfaXNBZG1pbgEFCWNhbGxlclBiawQKaXNPcGVyYXRvcgkBEF9pc1ZhbGlkT3BlcmF0b3IBBQljYWxsZXJQYmsEDV9jaGVja0FsbG93ZWQDCQEBIQEFCmlzT3BlcmF0b3IJAAIBAiRPbmx5IGFkbWlucyBhbmQgbWFuYWdlcnMgYXJlIGFsbG93ZWQGAwkAAAIFDV9jaGVja0FsbG93ZWQFDV9jaGVja0FsbG93ZWQEDGluaXRpYXRvckFkcgkBEUBleHRyTmF0aXZlKDEwNTgpAQkArAICBQhzY3JpcHRJZAILX19pbml0aWF0b3IEEF9jaGVja1Blcm1pc3Npb24DAwkBASEBBQdpc0FkbWluCQECIT0CBQxpbml0aWF0b3JBZHIFDWNhbGxlckFkZHJlc3MHCQACAQIlT25seSBhZG1pbnMgb3IgdGhlIGNyZWF0b3IgY2FuIHJlbW92ZQYDCQAAAgUQX2NoZWNrUGVybWlzc2lvbgUQX2NoZWNrUGVybWlzc2lvbgQKc2NyaXB0VHlwZQkBEUBleHRyTmF0aXZlKDEwNTgpAQkArAICCQCsAgIFCHNjcmlwdElkBQZCSUdTRVAFDGtfc2NyaXB0VHlwZQQLX3NjcmlwdEhhc2gJARFAZXh0ck5hdGl2ZSgxMDU4KQEJAKwCAgkArAICBQhzY3JpcHRJZAUGQklHU0VQBQxrX3NjcmlwdEhhc2gEBGl0ZXIJARFAZXh0ck5hdGl2ZSgxMDU1KQEJAKwCAgkArAICBQhzY3JpcHRJZAUGQklHU0VQBQZrX2l0ZXIED2V4aXN0aW5nVmFsaWRUbwkAnwgBCQETZ2V0U2NyaXB0VmFsaWRUb0tleQIFCnNjcmlwdFR5cGUFC19zY3JpcHRIYXNoBBNpc0N1cnJlbnRseUFwcHJvdmVkBAckbWF0Y2gwBQ9leGlzdGluZ1ZhbGlkVG8DCQABAgUHJG1hdGNoMAIDSW50BAJ2dAUHJG1hdGNoMAkAZwIFAnZ0BQZoZWlnaHQHBA5fY2hlY2tBcHByb3ZlZAMFE2lzQ3VycmVudGx5QXBwcm92ZWQJAAIBAi9DYW5ub3QgcmVtb3ZlIGFwcHJvdmVkIHNjcmlwdCwgdXNlIHJldm9rZSBmaXJzdAYDCQAAAgUOX2NoZWNrQXBwcm92ZWQFDl9jaGVja0FwcHJvdmVkCQDMCAIJAQtEZWxldGVFbnRyeQEJAKwCAgkArAICBQhzY3JpcHRJZAUGQklHU0VQBQxrX3NjcmlwdFR5cGUJAMwIAgkBC0RlbGV0ZUVudHJ5AQkArAICCQCsAgIFCHNjcmlwdElkBQZCSUdTRVAFEGtfc3RvcmFnZUFkZHJlc3MJAMwIAgkBC0RlbGV0ZUVudHJ5AQkArAICCQCsAgIFCHNjcmlwdElkBQZCSUdTRVAFDGtfc2NyaXB0SGFzaAkAzAgCCQELRGVsZXRlRW50cnkBCQCsAgIJAKwCAgUIc2NyaXB0SWQFBkJJR1NFUAUGa19kZXNjCQDMCAIJAQtEZWxldGVFbnRyeQEJAKwCAgkArAICBQhzY3JpcHRJZAUGQklHU0VQBQZrX2l0ZXIJAMwIAgkBC0RlbGV0ZUVudHJ5AQkArAICCQCsAgIFCHNjcmlwdElkBQZCSUdTRVAFDWtfdmFsaWRCbG9ja3MJAMwIAgkBC0RlbGV0ZUVudHJ5AQkArAICCQCsAgIJAKwCAgkArAICCQCsAgIFCnNjcmlwdFR5cGUFBkJJR1NFUAUGa19pdGVyBQZCSUdTRVAJAKQDAQUEaXRlcgIGX19oYXNoCQDMCAIJAQtEZWxldGVFbnRyeQEJAKwCAgkArAICBQhzY3JpcHRJZAUGQklHU0VQBQtrX2luaXRpYXRvcgkAzAgCCQELRGVsZXRlRW50cnkBCQCsAgIJAKwCAgUIc2NyaXB0SWQFBkJJR1NFUAUPa19jb25maXJtYXRpb25zCQDMCAIJAQtEZWxldGVFbnRyeQEJARVnZXRTY3JpcHRWYWxpZEZyb21LZXkCBQpzY3JpcHRUeXBlBQtfc2NyaXB0SGFzaAkAzAgCCQELRGVsZXRlRW50cnkBCQETZ2V0U2NyaXB0VmFsaWRUb0tleQIFCnNjcmlwdFR5cGUFC19zY3JpcHRIYXNoBQNuaWwJAAIBAiRTdHJpY3QgdmFsdWUgaXMgbm90IGVxdWFsIHRvIGl0c2VsZi4JAAIBAiRTdHJpY3QgdmFsdWUgaXMgbm90IGVxdWFsIHRvIGl0c2VsZi4JAAIBAiRTdHJpY3QgdmFsdWUgaXMgbm90IGVxdWFsIHRvIGl0c2VsZi4JAAIBAiRTdHJpY3QgdmFsdWUgaXMgbm90IGVxdWFsIHRvIGl0c2VsZi4BaQEVYWRkQ29uZmlybWF0aW9uU2NyaXB0AQhzY3JpcHRJZAQIX2NoZWNrSWQDCQECIT0CCQCzCQIFCHNjcmlwdElkAghzY3JpcHQlJQAACQACAQIXSW52YWxpZCBzY3JpcHRJZCBmb3JtYXQGAwkAAAIFCF9jaGVja0lkBQhfY2hlY2tJZAQJY2FsbGVyUGJrCQDYBAEIBQFpD2NhbGxlclB1YmxpY0tleQQFbGltaXQJAQlfZ2V0TGltaXQABApjaGVja0FkbWluAwkBASEBCQEIX2lzQWRtaW4BBQljYWxsZXJQYmsJAAIBAhdPbmx5IGFkbWlucyBjYW4gY29uZmlybQYDCQAAAgUKY2hlY2tBZG1pbgUKY2hlY2tBZG1pbgQLX3NjcmlwdEhhc2gJARN2YWx1ZU9yRXJyb3JNZXNzYWdlAgkAoggBCQCsAgIJAKwCAgUIc2NyaXB0SWQFBkJJR1NFUAUMa19zY3JpcHRIYXNoAhBJbnZhbGlkIHNjcmlwdElkAwkAAAIFC19zY3JpcHRIYXNoBQtfc2NyaXB0SGFzaAQKc2NyaXB0VHlwZQkBEUBleHRyTmF0aXZlKDEwNTgpAQkArAICCQCsAgIFCHNjcmlwdElkBQZCSUdTRVAFDGtfc2NyaXB0VHlwZQQLdmFsaWRCbG9ja3MJARFAZXh0ck5hdGl2ZSgxMDU1KQEJAKwCAgkArAICBQhzY3JpcHRJZAUGQklHU0VQBQ1rX3ZhbGlkQmxvY2tzBA9leGlzdGluZ1ZhbGlkVG8JAJ8IAQkBE2dldFNjcmlwdFZhbGlkVG9LZXkCBQpzY3JpcHRUeXBlBQtfc2NyaXB0SGFzaAQRaXNBbHJlYWR5QXBwcm92ZWQEByRtYXRjaDAFD2V4aXN0aW5nVmFsaWRUbwMJAAECBQckbWF0Y2gwAgNJbnQEAnZ0BQckbWF0Y2gwCQBnAgUCdnQFBmhlaWdodAcEDl9jaGVja0FwcHJvdmVkAwURaXNBbHJlYWR5QXBwcm92ZWQJAAIBAi9UaGlzIHNjcmlwdCBpcyBhbHJlYWR5IGFwcHJvdmVkIGFuZCBzdGlsbCB2YWxpZAYDCQAAAgUOX2NoZWNrQXBwcm92ZWQFDl9jaGVja0FwcHJvdmVkBA9nbG9iYWxJdGVyYXRpb24JAQt2YWx1ZU9yRWxzZQIJAJ8IAQkArAICCQCsAgIFC2tfSVRFUkFUSU9OBQNTRVAFCnNjcmlwdFR5cGUAAAQQY29uZmlybWF0aW9uc1N0cgkBC3ZhbHVlT3JFbHNlAgkAoggBCQCsAgIFCHNjcmlwdElkAg9fX2NvbmZpcm1hdGlvbnMCAAQQcmF3Q29uZmlybWF0aW9ucwMJAQIhPQIFEGNvbmZpcm1hdGlvbnNTdHICAAkAtQkCBRBjb25maXJtYXRpb25zU3RyAgEsBQNuaWwECWlzRXhwaXJlZAQHJG1hdGNoMAUPZXhpc3RpbmdWYWxpZFRvAwkAAQIFByRtYXRjaDACA0ludAQCdnQFByRtYXRjaDAJAGYCBQZoZWlnaHQFAnZ0BwQNY29uZmlybWF0aW9ucwMFCWlzRXhwaXJlZAUDbmlsCQEZX2ZpbHRlclZhbGlkQ29uZmlybWF0aW9ucwEFEHJhd0NvbmZpcm1hdGlvbnMEDmV4cGlyZWRDbGVhbnVwAwUJaXNFeHBpcmVkCQDMCAIJAQtEZWxldGVFbnRyeQEJARVnZXRTY3JpcHRWYWxpZEZyb21LZXkCBQpzY3JpcHRUeXBlBQtfc2NyaXB0SGFzaAkAzAgCCQELRGVsZXRlRW50cnkBCQETZ2V0U2NyaXB0VmFsaWRUb0tleQIFCnNjcmlwdFR5cGUFC19zY3JpcHRIYXNoBQNuaWwFA25pbAMJAQIhPQIJAM8IAgUNY29uZmlybWF0aW9ucwUJY2FsbGVyUGJrBQR1bml0CQACAQIhWW91IGFscmVhZHkgY29uZmlybWVkIHRoaXMgc2NyaXB0BAduZXdMaXN0CQDNCAIFDWNvbmZpcm1hdGlvbnMFCWNhbGxlclBiawQKbmV3TGlzdFN0cgkAuQkCBQduZXdMaXN0AgEsBAhhcHByb3ZlZAkAZwIJAJADAQUHbmV3TGlzdAUFbGltaXQEBnJlc3VsdAMFCGFwcHJvdmVkCQDMCAIJAQxJbnRlZ2VyRW50cnkCCQEVZ2V0U2NyaXB0VmFsaWRGcm9tS2V5AgUKc2NyaXB0VHlwZQULX3NjcmlwdEhhc2gJAGQCBQZoZWlnaHQJARFAZXh0ck5hdGl2ZSgxMDU1KQEFEmtfU0NSSVBUU19DT09MRE9XTgkAzAgCCQEMSW50ZWdlckVudHJ5AgkBE2dldFNjcmlwdFZhbGlkVG9LZXkCBQpzY3JpcHRUeXBlBQtfc2NyaXB0SGFzaAkAZAIFBmhlaWdodAULdmFsaWRCbG9ja3MFA25pbAUDbmlsCQDOCAIJAM4IAgUOZXhwaXJlZENsZWFudXAFBnJlc3VsdAkAzAgCCQELU3RyaW5nRW50cnkCCQCsAgIFCHNjcmlwdElkAg9fX2NvbmZpcm1hdGlvbnMFCm5ld0xpc3RTdHIFA25pbAkAAgECJFN0cmljdCB2YWx1ZSBpcyBub3QgZXF1YWwgdG8gaXRzZWxmLgkAAgECJFN0cmljdCB2YWx1ZSBpcyBub3QgZXF1YWwgdG8gaXRzZWxmLgkAAgECJFN0cmljdCB2YWx1ZSBpcyBub3QgZXF1YWwgdG8gaXRzZWxmLgkAAgECJFN0cmljdCB2YWx1ZSBpcyBub3QgZXF1YWwgdG8gaXRzZWxmLgFpARhyZXZva2VDb25maXJtYXRpb25TY3JpcHQBCHNjcmlwdElkBAhfY2hlY2tJZAMJAQIhPQIJALMJAgUIc2NyaXB0SWQCCHNjcmlwdCUlAAAJAAIBAhdJbnZhbGlkIHNjcmlwdElkIGZvcm1hdAYDCQAAAgUIX2NoZWNrSWQFCF9jaGVja0lkBAljYWxsZXJQYmsJANgEAQgFAWkPY2FsbGVyUHVibGljS2V5BAVsaW1pdAkBCV9nZXRMaW1pdAADCQEBIQEJAQhfaXNBZG1pbgEFCWNhbGxlclBiawkAAgECJE9ubHkgYWRtaW5zIGNhbiByZXZva2UgY29uZmlybWF0aW9ucwQLX3NjcmlwdEhhc2gJARN2YWx1ZU9yRXJyb3JNZXNzYWdlAgkAoggBCQCsAgIFCHNjcmlwdElkAgxfX3NjcmlwdEhhc2gCEEludmFsaWQgc2NyaXB0SWQDCQAAAgULX3NjcmlwdEhhc2gFC19zY3JpcHRIYXNoBApzY3JpcHRUeXBlCQERQGV4dHJOYXRpdmUoMTA1OCkBCQCsAgIFCHNjcmlwdElkAgxfX3NjcmlwdFR5cGUEEGNvbmZpcm1hdGlvbnNTdHIJAQt2YWx1ZU9yRWxzZQIJAKIIAQkArAICBQhzY3JpcHRJZAIPX19jb25maXJtYXRpb25zAgAEEHJhd0NvbmZpcm1hdGlvbnMDCQECIT0CBRBjb25maXJtYXRpb25zU3RyAgAJALUJAgUQY29uZmlybWF0aW9uc1N0cgIBLAUDbmlsBA1jb25maXJtYXRpb25zCQEZX2ZpbHRlclZhbGlkQ29uZmlybWF0aW9ucwEFEHJhd0NvbmZpcm1hdGlvbnMEDGNvbmZpcm1JbmRleAkAzwgCBQ1jb25maXJtYXRpb25zBQljYWxsZXJQYmsECWlzRXhwaXJlZAkAZgIFBmhlaWdodAkBC3ZhbHVlT3JFbHNlAgkAnwgBCQETZ2V0U2NyaXB0VmFsaWRUb0tleQIFCnNjcmlwdFR5cGUFC19zY3JpcHRIYXNoCQBkAgUGaGVpZ2h0AAEEDGNoZWNrRXhwaXJlZAMJAQEhAQUJaXNFeHBpcmVkBgkAAgECIEV4cGlyZWQgc2NyaXB0cyBjYW4ndCBiZSByZXZva2VkAwkAAAIFDGNoZWNrRXhwaXJlZAUMY2hlY2tFeHBpcmVkAwkAAAIFDGNvbmZpcm1JbmRleAUEdW5pdAkAAgECMVlvdSBkaWRuJ3QgY29uZmlybSB0aGlzIHNjcmlwdCwgbm90aGluZyB0byByZXZva2UEEG5ld0NvbmZpcm1hdGlvbnMJANEIAgUNY29uZmlybWF0aW9ucwkBBXZhbHVlAQUMY29uZmlybUluZGV4BBNuZXdDb25maXJtYXRpb25zU3RyCQC5CQIFEG5ld0NvbmZpcm1hdGlvbnMCASwEC3dhc0FwcHJvdmVkAwkBCWlzRGVmaW5lZAEJAJ8IAQkBFWdldFNjcmlwdFZhbGlkRnJvbUtleQIFCnNjcmlwdFR5cGUFC19zY3JpcHRIYXNoCQEJaXNEZWZpbmVkAQkAnwgBCQETZ2V0U2NyaXB0VmFsaWRUb0tleQIFCnNjcmlwdFR5cGUFC19zY3JpcHRIYXNoBwQNc3RpbGxBcHByb3ZlZAkAZwIJAJADAQUQbmV3Q29uZmlybWF0aW9ucwUFbGltaXQEDHN0YXRlQ2hhbmdlcwMDBQt3YXNBcHByb3ZlZAkBASEBBQ1zdGlsbEFwcHJvdmVkBwkAzAgCCQELRGVsZXRlRW50cnkBCQEVZ2V0U2NyaXB0VmFsaWRGcm9tS2V5AgUKc2NyaXB0VHlwZQULX3NjcmlwdEhhc2gJAMwIAgkBC0RlbGV0ZUVudHJ5AQkBE2dldFNjcmlwdFZhbGlkVG9LZXkCBQpzY3JpcHRUeXBlBQtfc2NyaXB0SGFzaAUDbmlsBQNuaWwJAM4IAgUMc3RhdGVDaGFuZ2VzCQDMCAIJAQtTdHJpbmdFbnRyeQIJAKwCAgUIc2NyaXB0SWQCD19fY29uZmlybWF0aW9ucwUTbmV3Q29uZmlybWF0aW9uc1N0cgUDbmlsCQACAQIkU3RyaWN0IHZhbHVlIGlzIG5vdCBlcXVhbCB0byBpdHNlbGYuCQACAQIkU3RyaWN0IHZhbHVlIGlzIG5vdCBlcXVhbCB0byBpdHNlbGYuCQACAQIkU3RyaWN0IHZhbHVlIGlzIG5vdCBlcXVhbCB0byBpdHNlbGYuAWkBB2FkZFRhc2sHBG5hbWUEZGFwcAR0eGlkCWV4ZWN1dGVUcwRkZXNjDGluaXRpYXRvckFkcgt0eEJvZHlCeXRlcwQJY2FsbGVyUGJrCQDYBAEIBQFpD2NhbGxlclB1YmxpY0tleQMJAQEhAQkBEF9pc1ZhbGlkT3BlcmF0b3IBBQljYWxsZXJQYmsJAAIBAiRPbmx5IGFkbWlucyBhbmQgbWFuYWdlcnMgYXJlIGFsbG93ZWQEDWxhc3RTdWJtaXRLZXkJAKwCAgIPbGFzdFN1Ym1pdFRhc2tfBQljYWxsZXJQYmsECmxhc3RTdWJtaXQJAQt2YWx1ZU9yRWxzZQIJAJ8IAQUNbGFzdFN1Ym1pdEtleQAABA5zdWJtaXRDb29sZG93bgkBC3ZhbHVlT3JFbHNlAgkAnwgBBRFrX1NVQk1JVF9DT09MRE9XTgADBA9fc3VibWl0Q29vbGRvd24DCQBmAgUOc3VibWl0Q29vbGRvd24JAGUCBQZoZWlnaHQFCmxhc3RTdWJtaXQJAAIBCQCsAgIJAKwCAgIWU3VibWl0IGNvb2xkb3duOiB3YWl0IAkApAMBCQBlAgUOc3VibWl0Q29vbGRvd24JAGUCBQZoZWlnaHQFCmxhc3RTdWJtaXQCDCBtb3JlIGJsb2NrcwYDCQAAAgUPX3N1Ym1pdENvb2xkb3duBQ9fc3VibWl0Q29vbGRvd24ECl9uYW1lQ2hlY2sDCQAAAgkAsQIBBQRuYW1lAAAJAAIBAhNOYW1lIGNhbid0IGJlIGVtcHR5BgMJAAACBQpfbmFtZUNoZWNrBQpfbmFtZUNoZWNrBApfZGFwcENoZWNrAwkBASEBCQEQX3ZhbGlkYXRlQWRkcmVzcwEFBGRhcHAJAAIBAg5JbmNvcnJlY3QgZGFwcAYDCQAAAgUKX2RhcHBDaGVjawUKX2RhcHBDaGVjawQKX3R4aWRDaGVjawMJAAACCQCxAgEFBHR4aWQAAAkAAgECE3R4aWQgY2FuJ3QgYmUgZW1wdHkGAwkAAAIFCl90eGlkQ2hlY2sFCl90eGlkQ2hlY2sED190aW1lc3RhbXBDaGVjawMJAQEhAQkBC192YWxpZGF0ZVRzAQUJZXhlY3V0ZVRzCQACAQJESW52YWxpZCBleGVjdXRpb24gdGltZXN0YW1wIC0gY2Fubm90IGJlIG1vcmUgdGhhbiAxIGhvdXIgaW4gdGhlIHBhc3QGAwkAAAIFD190aW1lc3RhbXBDaGVjawUPX3RpbWVzdGFtcENoZWNrBApfZGVzY0NoZWNrAwkAAAIJALECAQUEZGVzYwAACQACAQIaRGVzY3JpcHRpb24gY2FuJ3QgYmUgZW1wdHkGAwkAAAIFCl9kZXNjQ2hlY2sFCl9kZXNjQ2hlY2sED19pbml0aWF0b3JDaGVjawMJAQIhPQIJAKUIAQkApwgBCAUBaQ9jYWxsZXJQdWJsaWNLZXkFDGluaXRpYXRvckFkcgkAAgECJkluaXRpYXRvciBhZGRyZXNzIGRvZXNuJ3QgbWF0Y2ggY2FsbGVyBgMJAAACBQ9faW5pdGlhdG9yQ2hlY2sFD19pbml0aWF0b3JDaGVjawQPX2JvZHlCeXRlc0NoZWNrAwkAAAIJALECAQULdHhCb2R5Qnl0ZXMAAAkAAgECHFR4IGJvZHkgYnl0ZXMgY2FuJ3QgYmUgZW1wdHkGAwkAAAIFD19ib2R5Qnl0ZXNDaGVjawUPX2JvZHlCeXRlc0NoZWNrBAlib2R5Qnl0ZXMJANsEAQULdHhCb2R5Qnl0ZXMECmNvbXB1dGVkSWQJANgEAQkA9gMBBQlib2R5Qnl0ZXMEC190eGlkVmVyaWZ5AwkBAiE9AgUKY29tcHV0ZWRJZAUEdHhpZAkAAgEJAKwCAgkArAICCQCsAgICMnR4aWQgdmVyaWZpY2F0aW9uIGZhaWxlZDogYmxha2UyYjI1Nihib2R5Qnl0ZXMpID0gBQpjb21wdXRlZElkAgsgIT0gdHhpZCA9IAUEdHhpZAYDCQAAAgULX3R4aWRWZXJpZnkFC190eGlkVmVyaWZ5BAZ0YXNrSWQJAKwCAgkArAICCQCsAgICA3R4XwUEZGFwcAUDU0VQBQR0eGlkBA1fY2hlY2tQcmVzZW50AwkBCWlzRGVmaW5lZAEJAKIIAQkArAICBQZ0YXNrSWQCBl9fdHhJZAkAAgECK1Rhc2sgd2l0aCB0aGlzIChkYXBwLCB0eGlkKSBhbHJlYWR5IHByZXNlbnQGAwkAAAIFDV9jaGVja1ByZXNlbnQFDV9jaGVja1ByZXNlbnQJAMwIAgkBC1N0cmluZ0VudHJ5AgkArAICBQZ0YXNrSWQCBl9fbmFtZQUEbmFtZQkAzAgCCQELU3RyaW5nRW50cnkCCQCsAgIFBnRhc2tJZAIGX19kYXBwBQRkYXBwCQDMCAIJAQtTdHJpbmdFbnRyeQIJAKwCAgUGdGFza0lkAgZfX3R4SWQFBHR4aWQJAMwIAgkBC1N0cmluZ0VudHJ5AgkArAICBQZ0YXNrSWQCBl9fZGVzYwUEZGVzYwkAzAgCCQELU3RyaW5nRW50cnkCCQCsAgIFBnRhc2tJZAINX190eEJvZHlCeXRlcwULdHhCb2R5Qnl0ZXMJAMwIAgkBC1N0cmluZ0VudHJ5AgkArAICBQZ0YXNrSWQCC19faW5pdGlhdG9yBQxpbml0aWF0b3JBZHIJAMwIAgkBDEludGVnZXJFbnRyeQIJAKwCAgUGdGFza0lkAgRfX3RzBQlleGVjdXRlVHMJAMwIAgkBDEludGVnZXJFbnRyeQIFDWxhc3RTdWJtaXRLZXkFBmhlaWdodAUDbmlsCQACAQIkU3RyaWN0IHZhbHVlIGlzIG5vdCBlcXVhbCB0byBpdHNlbGYuCQACAQIkU3RyaWN0IHZhbHVlIGlzIG5vdCBlcXVhbCB0byBpdHNlbGYuCQACAQIkU3RyaWN0IHZhbHVlIGlzIG5vdCBlcXVhbCB0byBpdHNlbGYuCQACAQIkU3RyaWN0IHZhbHVlIGlzIG5vdCBlcXVhbCB0byBpdHNlbGYuCQACAQIkU3RyaWN0IHZhbHVlIGlzIG5vdCBlcXVhbCB0byBpdHNlbGYuCQACAQIkU3RyaWN0IHZhbHVlIGlzIG5vdCBlcXVhbCB0byBpdHNlbGYuCQACAQIkU3RyaWN0IHZhbHVlIGlzIG5vdCBlcXVhbCB0byBpdHNlbGYuCQACAQIkU3RyaWN0IHZhbHVlIGlzIG5vdCBlcXVhbCB0byBpdHNlbGYuCQACAQIkU3RyaWN0IHZhbHVlIGlzIG5vdCBlcXVhbCB0byBpdHNlbGYuCQACAQIkU3RyaWN0IHZhbHVlIGlzIG5vdCBlcXVhbCB0byBpdHNlbGYuAWkBCnJlbW92ZVRhc2sBBnRhc2tJZAQIX2NoZWNrSWQDCQECIT0CCQCzCQIFBnRhc2tJZAIDdHhfAAAJAAIBAhVJbnZhbGlkIHRhc2tJZCBmb3JtYXQGAwkAAAIFCF9jaGVja0lkBQhfY2hlY2tJZAQJY2FsbGVyUGJrCQDYBAEIBQFpD2NhbGxlclB1YmxpY0tleQQNY2FsbGVyQWRkcmVzcwkApQgBCQCnCAEIBQFpD2NhbGxlclB1YmxpY0tleQQKaXNPcGVyYXRvcgkBEF9pc1ZhbGlkT3BlcmF0b3IBBQljYWxsZXJQYmsEDV9jaGVja0FsbG93ZWQDCQEBIQEFCmlzT3BlcmF0b3IJAAIBAiRPbmx5IGFkbWlucyBhbmQgbWFuYWdlcnMgYXJlIGFsbG93ZWQGAwkAAAIFDV9jaGVja0FsbG93ZWQFDV9jaGVja0FsbG93ZWQEDGluaXRpYXRvckFkcgkBEUBleHRyTmF0aXZlKDEwNTgpAQkArAICBQZ0YXNrSWQCC19faW5pdGlhdG9yBBBfY2hlY2tQZXJtaXNzaW9uAwkBAiE9AgUMaW5pdGlhdG9yQWRyBQ1jYWxsZXJBZGRyZXNzCQACAQIgT25seSB0aGUgdGFzayBjcmVhdG9yIGNhbiByZW1vdmUGAwkAAAIFEF9jaGVja1Blcm1pc3Npb24FEF9jaGVja1Blcm1pc3Npb24EBHR4SWQJARN2YWx1ZU9yRXJyb3JNZXNzYWdlAgkAoggBCQCsAgIFBnRhc2tJZAIGX190eElkAgxJbnZhbGlkIHRhc2sDCQAAAgUEdHhJZAUEdHhJZAQEZGFwcAkBEUBleHRyTmF0aXZlKDEwNTgpAQkArAICBQZ0YXNrSWQCBl9fZGFwcAkAzAgCCQELRGVsZXRlRW50cnkBCQCsAgIFBnRhc2tJZAIGX19uYW1lCQDMCAIJAQtEZWxldGVFbnRyeQEJAKwCAgUGdGFza0lkAgZfX2RhcHAJAMwIAgkBC0RlbGV0ZUVudHJ5AQkArAICBQZ0YXNrSWQCBl9fdHhJZAkAzAgCCQELRGVsZXRlRW50cnkBCQCsAgIFBnRhc2tJZAIGX19kZXNjCQDMCAIJAQtEZWxldGVFbnRyeQEJAKwCAgUGdGFza0lkAg1fX3R4Qm9keUJ5dGVzCQDMCAIJAQtEZWxldGVFbnRyeQEJAKwCAgUGdGFza0lkAgtfX2luaXRpYXRvcgkAzAgCCQELRGVsZXRlRW50cnkBCQCsAgIFBnRhc2tJZAIEX190cwkAzAgCCQELRGVsZXRlRW50cnkBCQCsAgIFBnRhc2tJZAIPX19jb25maXJtYXRpb25zCQDMCAIJAQtEZWxldGVFbnRyeQEJAKwCAgUGdGFza0lkAg5fX2FwcHJvdmVkRnJvbQkAzAgCCQELRGVsZXRlRW50cnkBCQCsAgIJAKwCAgkArAICBQRkYXBwBQNTRVAFBHR4SWQCCl9fYXBwcm92ZWQFA25pbAkAAgECJFN0cmljdCB2YWx1ZSBpcyBub3QgZXF1YWwgdG8gaXRzZWxmLgkAAgECJFN0cmljdCB2YWx1ZSBpcyBub3QgZXF1YWwgdG8gaXRzZWxmLgkAAgECJFN0cmljdCB2YWx1ZSBpcyBub3QgZXF1YWwgdG8gaXRzZWxmLgkAAgECJFN0cmljdCB2YWx1ZSBpcyBub3QgZXF1YWwgdG8gaXRzZWxmLgFpAQ9hZGRDb25maXJtYXRpb24BBnRhc2tJZAQIX2NoZWNrSWQDCQECIT0CCQCzCQIFBnRhc2tJZAIDdHhfAAAJAAIBAhVJbnZhbGlkIHRhc2tJZCBmb3JtYXQGAwkAAAIFCF9jaGVja0lkBQhfY2hlY2tJZAQJY2FsbGVyUGJrCQDYBAEIBQFpD2NhbGxlclB1YmxpY0tleQQFbGltaXQJAQlfZ2V0TGltaXQAAwkBASEBCQEIX2lzQWRtaW4BBQljYWxsZXJQYmsJAAIBAhdPbmx5IGFkbWlucyBjYW4gY29uZmlybQQEdHhJZAkBE3ZhbHVlT3JFcnJvck1lc3NhZ2UCCQCiCAEJAKwCAgUGdGFza0lkAgZfX3R4SWQCDEludmFsaWQgdGFzawMJAAACBQR0eElkBQR0eElkBARkYXBwCQERQGV4dHJOYXRpdmUoMTA1OCkBCQCsAgIFBnRhc2tJZAIGX19kYXBwBBBjb25maXJtYXRpb25zU3RyCQELdmFsdWVPckVsc2UCCQCiCAEJAKwCAgUGdGFza0lkAg9fX2NvbmZpcm1hdGlvbnMCAAQQcmF3Q29uZmlybWF0aW9ucwMJAQIhPQIFEGNvbmZpcm1hdGlvbnNTdHICAAkAtQkCBRBjb25maXJtYXRpb25zU3RyAgEsBQNuaWwEDWNvbmZpcm1hdGlvbnMJARlfZmlsdGVyVmFsaWRDb25maXJtYXRpb25zAQUQcmF3Q29uZmlybWF0aW9ucwMJAQIhPQIJAM8IAgUNY29uZmlybWF0aW9ucwUJY2FsbGVyUGJrBQR1bml0CQACAQIfWW91IGFscmVhZHkgY29uZmlybWVkIHRoaXMgdGFzawQHbmV3TGlzdAkAzQgCBQ1jb25maXJtYXRpb25zBQljYWxsZXJQYmsECm5ld0xpc3RTdHIJALkJAgUHbmV3TGlzdAIBLAQIYXBwcm92ZWQJAGcCCQCQAwEFB25ld0xpc3QFBWxpbWl0BAx0YXNrQ29vbGRvd24JAQt2YWx1ZU9yRWxzZQIJAJ8IAQUPa19UQVNLX0NPT0xET1dOAAAEFGV4aXN0aW5nQXBwcm92ZWRGcm9tCQCfCAEJAKwCAgUGdGFza0lkAg5fX2FwcHJvdmVkRnJvbQQRYXBwcm92ZWRGcm9tRW50cnkDBQhhcHByb3ZlZAQHJG1hdGNoMAUUZXhpc3RpbmdBcHByb3ZlZEZyb20DCQABAgUHJG1hdGNoMAIDSW50BQNuaWwJAMwIAgkBDEludGVnZXJFbnRyeQIJAKwCAgUGdGFza0lkAg5fX2FwcHJvdmVkRnJvbQkAZAIFBmhlaWdodAUMdGFza0Nvb2xkb3duBQNuaWwFA25pbAkAzggCCQDMCAIJAQtTdHJpbmdFbnRyeQIJAKwCAgUGdGFza0lkAg9fX2NvbmZpcm1hdGlvbnMFCm5ld0xpc3RTdHIJAMwIAgkBDEJvb2xlYW5FbnRyeQIJAKwCAgkArAICCQCsAgIFBGRhcHAFA1NFUAUEdHhJZAIKX19hcHByb3ZlZAUIYXBwcm92ZWQFA25pbAURYXBwcm92ZWRGcm9tRW50cnkJAAIBAiRTdHJpY3QgdmFsdWUgaXMgbm90IGVxdWFsIHRvIGl0c2VsZi4JAAIBAiRTdHJpY3QgdmFsdWUgaXMgbm90IGVxdWFsIHRvIGl0c2VsZi4BaQEKcmV2b2tlVGFzawEGdGFza0lkBAhfY2hlY2tJZAMJAQIhPQIJALMJAgUGdGFza0lkAgN0eF8AAAkAAgECFUludmFsaWQgdGFza0lkIGZvcm1hdAYDCQAAAgUIX2NoZWNrSWQFCF9jaGVja0lkBAljYWxsZXJQYmsJANgEAQgFAWkPY2FsbGVyUHVibGljS2V5BAVsaW1pdAkBCV9nZXRMaW1pdAADCQEBIQEJAQhfaXNBZG1pbgEFCWNhbGxlclBiawkAAgECFk9ubHkgYWRtaW5zIGNhbiByZXZva2UEBHR4SWQJARN2YWx1ZU9yRXJyb3JNZXNzYWdlAgkAoggBCQCsAgIFBnRhc2tJZAIGX190eElkAgxJbnZhbGlkIHRhc2sDCQAAAgUEdHhJZAUEdHhJZAQQY29uZmlybWF0aW9uc1N0cgkBC3ZhbHVlT3JFbHNlAgkAoggBCQCsAgIFBnRhc2tJZAIPX19jb25maXJtYXRpb25zAgAEEHJhd0NvbmZpcm1hdGlvbnMDCQECIT0CBRBjb25maXJtYXRpb25zU3RyAgAJALUJAgUQY29uZmlybWF0aW9uc1N0cgIBLAUDbmlsBA1jb25maXJtYXRpb25zCQEZX2ZpbHRlclZhbGlkQ29uZmlybWF0aW9ucwEFEHJhd0NvbmZpcm1hdGlvbnMEB2luZGV4TXkJAM8IAgUNY29uZmlybWF0aW9ucwUJY2FsbGVyUGJrAwkAAAIFB2luZGV4TXkFBHVuaXQJAAIBAjBZb3UgZGlkIG5vdCBjb25maXJtIHRoaXMgdGFzaywgbm90aGluZyB0byByZXZva2UEBGRhcHAJARFAZXh0ck5hdGl2ZSgxMDU4KQEJAKwCAgUGdGFza0lkAgZfX2RhcHAEB25ld0xpc3QJANEIAgUNY29uZmlybWF0aW9ucwkBBXZhbHVlAQUHaW5kZXhNeQQKbmV3TGlzdFN0cgkAuQkCBQduZXdMaXN0AgEsBAhhcHByb3ZlZAkAZwIJAJADAQUHbmV3TGlzdAUFbGltaXQJAMwIAgkBC1N0cmluZ0VudHJ5AgkArAICBQZ0YXNrSWQCD19fY29uZmlybWF0aW9ucwUKbmV3TGlzdFN0cgkAzAgCCQEMQm9vbGVhbkVudHJ5AgkArAICCQCsAgIJAKwCAgUEZGFwcAUDU0VQBQR0eElkAgpfX2FwcHJvdmVkBQhhcHByb3ZlZAUDbmlsCQACAQIkU3RyaWN0IHZhbHVlIGlzIG5vdCBlcXVhbCB0byBpdHNlbGYuCQACAQIkU3RyaWN0IHZhbHVlIGlzIG5vdCBlcXVhbCB0byBpdHNlbGYuAQJ0eAEGdmVyaWZ5AAQNQ09OVFJBQ1RfVFlQRQIRQVBQUk9WRVJfQ09OVFJBQ1QDCQEJX2lzSW5pdGVkAAQHJG1hdGNoMAUCdHgDCQABAgUHJG1hdGNoMAIUU2V0U2NyaXB0VHJhbnNhY3Rpb24EA3R0eAUHJG1hdGNoMAQHJG1hdGNoMQgFA3R0eAZzY3JpcHQDCQABAgUHJG1hdGNoMQIKQnl0ZVZlY3RvcgQGc2NyaXB0BQckbWF0Y2gxBAtzY3JpcHRIYXNoYQkA2AQBCQD2AwEFBnNjcmlwdAQJdmFsaWRGcm9tCQETdmFsdWVPckVycm9yTWVzc2FnZQIJAJoIAgUEdGhpcwkArAICCQCsAgIJAKwCAgkArAICAghzY3JpcHQlJQUNQ09OVFJBQ1RfVFlQRQICJSUFC3NjcmlwdEhhc2hhAgslJXZhbGlkRnJvbQIRdmFsaWRGcm9tIG5vdCBzZXQEB3ZhbGlkVG8JARN2YWx1ZU9yRXJyb3JNZXNzYWdlAgkAmggCBQR0aGlzCQCsAgIJAKwCAgkArAICCQCsAgICCHNjcmlwdCUlBQ1DT05UUkFDVF9UWVBFAgIlJQULc2NyaXB0SGFzaGECCSUldmFsaWRUbwIPdmFsaWRUbyBub3Qgc2V0AwkAZwIFBmhlaWdodAUJdmFsaWRGcm9tCQBnAgUHdmFsaWRUbwUGaGVpZ2h0BwcEA290eAUHJG1hdGNoMAQGdGFza0lkCQCsAgIJAKwCAgkArAICAgN0eF8JAKUIAQUEdGhpcwUDU0VQCQDYBAEIBQNvdHgCaWQECmlzQXBwcm92ZWQJAQt2YWx1ZU9yRWxzZQIJAJsIAgUEdGhpcwkArAICCQCsAgIJAKwCAgkApQgBBQR0aGlzAgFfCQDYBAEIBQNvdHgCaWQCCl9fYXBwcm92ZWQHBAxhcHByb3ZlZEZyb20JAQt2YWx1ZU9yRWxzZQIJAJoIAgUEdGhpcwkArAICBQZ0YXNrSWQCDl9fYXBwcm92ZWRGcm9tAAADBQppc0FwcHJvdmVkCQBnAgUGaGVpZ2h0BQxhcHByb3ZlZEZyb20HCQD0AwMIBQJ0eAlib2R5Qnl0ZXMJAJEDAggFAnR4BnByb29mcwAACAUCdHgPc2VuZGVyUHVibGljS2V5Zi8MRw==", "height": 537303, "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 VERSION = "1.1.4"
5+
6+let SEP = "_"
7+
8+let BIGSEP = "__"
9+
10+let k_ADMINS = "ADMINS_PBKS"
11+
12+let k_MANAGERS = "MANAGERS_PBKS"
13+
14+let k_LIMIT = "VOTES_QUORUM"
15+
16+let k_SCRIPT_TYPES = "SCRIPT_TYPES"
17+
18+let k_ITERATION = "ITERATION"
19+
20+let k_INITED = "INITED"
21+
22+let k_SCRIPTS_COOLDOWN = "SCRIPTSCOOLDOWN"
23+
24+let k_SUBMIT_COOLDOWN = "SUBMIT_COOLDOWN"
25+
26+let k_TASK_COOLDOWN = "TASK_COOLDOWN"
27+
28+let k_scriptType = "scriptType"
29+
30+let k_scriptHash = "scriptHash"
31+
32+let k_storageAddress = "storageAddress"
33+
34+let k_desc = "desc"
35+
36+let k_iter = "iteration"
37+
38+let k_initiator = "initiator"
39+
40+let k_confirmations = "confirmations"
41+
42+let k_validBlocks = "validBlocks"
43+
44+let k_validTo = "validTo"
45+
46+let k_validFrom = "validFrom"
47+
48+func getScriptValidFromKey (scriptType,scriptHash) = ((((("script%%" + scriptType) + "%%") + scriptHash) + "%%") + k_validFrom)
49+
50+
51+func getScriptValidToKey (scriptType,scriptHash) = ((((("script%%" + scriptType) + "%%") + scriptHash) + "%%") + k_validTo)
52+
53+
54+func _validatePbk (pbk) = {
55+ let keyBytes = fromBase58String(pbk)
56+ let checkLength = if ((size(keyBytes) != 32))
57+ then throw("Invalid public key")
58+ else true
59+ if ((checkLength == checkLength))
60+ then {
61+ let address = addressFromPublicKey(keyBytes)
62+ if ((address == address))
63+ then {
64+ let addressStr = toString(address)
65+ if ((addressStr == addressStr))
66+ then (size(addressStr) > 0)
67+ else throw("Strict value is not equal to itself.")
68+ }
69+ else throw("Strict value is not equal to itself.")
70+ }
71+ else throw("Strict value is not equal to itself.")
72+ }
73+
74+
75+func _validateAddress (address) = {
76+ let addr = addressFromStringValue(address)
77+ if ((addr == addr))
78+ then true
79+ else throw("Strict value is not equal to itself.")
80+ }
81+
82+
83+func _validateTs (ts) = {
84+ let currTs = match blockInfoByHeight(height) {
85+ case block: BlockInfo =>
86+ block.timestamp
87+ case _ =>
88+ throw("Can't find block")
89+ }
90+ let oneHour = ((60 * 60) * 1000)
91+ let minTs = (currTs - oneHour)
92+ (ts >= minTs)
93+ }
94+
95+
96+func _getLimit () = valueOrErrorMessage(getInteger(k_LIMIT), "Quorum limit not defined")
97+
98+
99+func _isAdmin (pbk) = {
100+ let adminsStr = valueOrElse(getString(k_ADMINS), "")
101+ let admins = split(adminsStr, ",")
102+ (indexOf(admins, pbk) != unit)
103+ }
104+
105+
106+func _isManager (pbk) = {
107+ let managersStr = valueOrElse(getString(k_MANAGERS), "")
108+ let managers = split(managersStr, ",")
109+ (indexOf(managers, pbk) != unit)
110+ }
111+
112+
113+func _isValidOperator (pbk) = {
114+ let managersStr = valueOrElse(getString(k_MANAGERS), "")
115+ let managers = split(managersStr, ",")
116+ let isAdmin = _isAdmin(pbk)
117+ let isManager = _isManager(pbk)
118+ if (isAdmin)
119+ then true
120+ else isManager
121+ }
122+
123+
124+func _filterValidConfirmations (confirmations) = {
125+ func filterValid (acc,pbk) = if (_isAdmin(pbk))
126+ then (acc :+ pbk)
127+ else acc
128+
129+ let $l = confirmations
130+ let $s = size($l)
131+ let $acc0 = nil
132+ func $f0_1 ($a,$i) = if (($i >= $s))
133+ then $a
134+ else filterValid($a, $l[$i])
135+
136+ func $f0_2 ($a,$i) = if (($i >= $s))
137+ then $a
138+ else throw("List size exceeds 20")
139+
140+ $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($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), 16), 17), 18), 19), 20)
141+ }
142+
143+
144+func _isInited () = valueOrElse(getBoolean(k_INITED), false)
145+
146+
147+@Callable(i)
148+func init (admins_pbks,limit,scriptsCooldown) = {
149+ let isSelf = if ((i.caller == this))
150+ then true
151+ else throw("Only self invoke")
152+ if ((isSelf == isSelf))
153+ then {
154+ let checkInited = if (_isInited())
155+ then throw("Already inited")
156+ else true
157+ if ((checkInited == checkInited))
158+ then {
159+ let size_admins = if ((size(admins_pbks) != 0))
160+ then true
161+ else throw("At least one admin pbk should be passed")
162+ if ((size_admins == size_admins))
163+ then {
164+ let size_admins_limit = if ((20 >= size(admins_pbks)))
165+ then true
166+ else throw(("Maximum admin count is 20, current size: " + toString(size(admins_pbks))))
167+ if ((size_admins_limit == size_admins_limit))
168+ then {
169+ let check_admins = if (!(isDefined(getString(k_ADMINS))))
170+ then true
171+ else throw("Already inited")
172+ if ((check_admins == check_admins))
173+ then {
174+ let zeroLimit = if ((limit > 0))
175+ then true
176+ else throw("Limit should be > 0")
177+ if ((zeroLimit == zeroLimit))
178+ then {
179+ let checkScriptsCooldown = if ((scriptsCooldown > 0))
180+ then true
181+ else throw("Scripts cooldown should be > 0")
182+ if ((checkScriptsCooldown == checkScriptsCooldown))
183+ then {
184+ let limit_ok = if ((size(admins_pbks) >= limit))
185+ then true
186+ else throw(((("Limit quorum should be <= size of list of admins, limit: " + toString(limit)) + ", current size: ") + toString(size(admins_pbks))))
187+ if ((limit_ok == limit_ok))
188+ then {
189+ func validate (accum,next) = _validatePbk(next)
190+
191+ let validRes = {
192+ let $l = admins_pbks
193+ let $s = size($l)
194+ let $acc0 = ""
195+ func $f0_1 ($a,$i) = if (($i >= $s))
196+ then $a
197+ else validate($a, $l[$i])
198+
199+ func $f0_2 ($a,$i) = if (($i >= $s))
200+ then $a
201+ else throw("List size exceeds 20")
202+
203+ $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($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), 16), 17), 18), 19), 20)
204+ }
205+ if ((validRes == validRes))
206+ then {
207+ let adminsStr = makeString(admins_pbks, ",")
208+[StringEntry(k_ADMINS, adminsStr), IntegerEntry(k_LIMIT, limit), IntegerEntry(k_SCRIPTS_COOLDOWN, scriptsCooldown), IntegerEntry(k_SUBMIT_COOLDOWN, 3), IntegerEntry(k_TASK_COOLDOWN, 0), BooleanEntry(k_INITED, true)]
209+ }
210+ else throw("Strict value is not equal to itself.")
211+ }
212+ else throw("Strict value is not equal to itself.")
213+ }
214+ else throw("Strict value is not equal to itself.")
215+ }
216+ else throw("Strict value is not equal to itself.")
217+ }
218+ else throw("Strict value is not equal to itself.")
219+ }
220+ else throw("Strict value is not equal to itself.")
221+ }
222+ else throw("Strict value is not equal to itself.")
223+ }
224+ else throw("Strict value is not equal to itself.")
225+ }
226+ else throw("Strict value is not equal to itself.")
227+ }
228+
229+
230+
231+@Callable(i)
232+func addAdmin (pbk) = {
233+ let isSelf = if ((i.caller == this))
234+ then true
235+ else throw("Only self invoke")
236+ if ((isSelf == isSelf))
237+ then {
238+ let isValid = if (_validatePbk(pbk))
239+ then true
240+ else throw("Invalid admin pbk")
241+ if ((isValid == isValid))
242+ then {
243+ let managersList = split(valueOrElse(getString(k_MANAGERS), ""), ",")
244+ let checkIsManager = if ((indexOf(managersList, pbk) == unit))
245+ then true
246+ else throw("This user is already manager, remove from managers if you need to add it as admin")
247+ if ((checkIsManager == checkIsManager))
248+ then {
249+ let admins = getStringValue(k_ADMINS)
250+ let adminsList = split(admins, ",")
251+ let checkMaxAdmins = if ((size(adminsList) >= 20))
252+ then throw("Maximum admin count reached (20)")
253+ else true
254+ if ((checkMaxAdmins == checkMaxAdmins))
255+ then {
256+ let checkPresent = if ((indexOf(adminsList, pbk) != unit))
257+ then throw("This admin already present")
258+ else true
259+ if ((checkPresent == checkPresent))
260+ then {
261+ let newAdminsStr = ((admins + ",") + pbk)
262+[StringEntry(k_ADMINS, newAdminsStr)]
263+ }
264+ else throw("Strict value is not equal to itself.")
265+ }
266+ else throw("Strict value is not equal to itself.")
267+ }
268+ else throw("Strict value is not equal to itself.")
269+ }
270+ else throw("Strict value is not equal to itself.")
271+ }
272+ else throw("Strict value is not equal to itself.")
273+ }
274+
275+
276+
277+@Callable(i)
278+func removeAdmin (pbk) = {
279+ let isSelf = if ((i.caller == this))
280+ then true
281+ else throw("Only self invoke")
282+ if ((isSelf == isSelf))
283+ then {
284+ let isValid = if (_validatePbk(pbk))
285+ then true
286+ else throw("Invalid admin pbk")
287+ if ((isValid == isValid))
288+ then {
289+ let oldAdminsStr = getStringValue(k_ADMINS)
290+ let oldAdmins = split(oldAdminsStr, ",")
291+ let checkCount = if ((1 >= size(oldAdmins)))
292+ then throw("Cannot remove, at least one admin should remain")
293+ else true
294+ if ((checkCount == checkCount))
295+ then {
296+ let index = valueOrErrorMessage(indexOf(oldAdmins, pbk), "This pbk is not an admin")
297+ let newAdmins = removeByIndex(oldAdmins, index)
298+ let limit = _getLimit()
299+ let checkQuorum = if ((limit > size(newAdmins)))
300+ then throw((("Cannot remove: admin count would fall below quorum (" + toString(limit)) + ")"))
301+ else true
302+ if ((checkQuorum == checkQuorum))
303+ then {
304+ let newAdminsStr = makeString(newAdmins, ",")
305+[StringEntry(k_ADMINS, newAdminsStr)]
306+ }
307+ else throw("Strict value is not equal to itself.")
308+ }
309+ else throw("Strict value is not equal to itself.")
310+ }
311+ else throw("Strict value is not equal to itself.")
312+ }
313+ else throw("Strict value is not equal to itself.")
314+ }
315+
316+
317+
318+@Callable(i)
319+func addManager (pbk) = {
320+ let isSelf = if ((i.caller == this))
321+ then true
322+ else throw("Only self invoke")
323+ if ((isSelf == isSelf))
324+ then {
325+ let isValid = if (_validatePbk(pbk))
326+ then true
327+ else throw("Invalid manager pbk")
328+ if ((isValid == isValid))
329+ then {
330+ let adminsList = split(valueOrElse(getString(k_ADMINS), ""), ",")
331+ let checkIsAdmin = if ((indexOf(adminsList, pbk) == unit))
332+ then true
333+ else throw("This user is already admin, remove from admins if you need to add it as manager")
334+ if ((checkIsAdmin == checkIsAdmin))
335+ then {
336+ let managers = valueOrElse(getString(k_MANAGERS), "")
337+ let managersList = split(managers, ",")
338+ let checkPresent = if ((indexOf(managersList, pbk) != unit))
339+ then throw("This manager already present")
340+ else true
341+ if ((checkPresent == checkPresent))
342+ then {
343+ let newManagersStr = if ((managers == ""))
344+ then pbk
345+ else ((managers + ",") + pbk)
346+[StringEntry(k_MANAGERS, newManagersStr)]
347+ }
348+ else throw("Strict value is not equal to itself.")
349+ }
350+ else throw("Strict value is not equal to itself.")
351+ }
352+ else throw("Strict value is not equal to itself.")
353+ }
354+ else throw("Strict value is not equal to itself.")
355+ }
356+
357+
358+
359+@Callable(i)
360+func removeManager (pbk) = {
361+ let isSelf = if ((i.caller == this))
362+ then true
363+ else throw("Only self invoke")
364+ if ((isSelf == isSelf))
365+ then {
366+ let isValid = if (_validatePbk(pbk))
367+ then true
368+ else throw("Invalid manager pbk")
369+ if ((isValid == isValid))
370+ then {
371+ let oldManagersStr = getStringValue(k_MANAGERS)
372+ let oldManagers = split(oldManagersStr, ",")
373+ let index = valueOrErrorMessage(indexOf(oldManagers, pbk), "This pbk is not an manager")
374+ let newManagers = removeByIndex(oldManagers, index)
375+ let newManagersStr = makeString(newManagers, ",")
376+[StringEntry(k_MANAGERS, newManagersStr)]
377+ }
378+ else throw("Strict value is not equal to itself.")
379+ }
380+ else throw("Strict value is not equal to itself.")
381+ }
382+
383+
384+
385+@Callable(i)
386+func addScriptType (scriptType) = {
387+ let isSelf = if ((i.caller == this))
388+ then true
389+ else throw("Only self invoke")
390+ if ((isSelf == isSelf))
391+ then {
392+ let checkEmpty = if ((size(scriptType) == 0))
393+ then throw("Script type can not be empty")
394+ else true
395+ if ((checkEmpty == checkEmpty))
396+ then {
397+ let checkNoComma = if ((indexOf(scriptType, ",") != unit))
398+ then throw("Script type cannot contain commas")
399+ else true
400+ if ((checkNoComma == checkNoComma))
401+ then {
402+ let checkNoPercent = if ((indexOf(scriptType, "%") != unit))
403+ then throw("Script type cannot contain '%'")
404+ else true
405+ if ((checkNoPercent == checkNoPercent))
406+ then {
407+ let checkNoBigSep = if ((indexOf(scriptType, "__") != unit))
408+ then throw("Script type cannot contain '__'")
409+ else true
410+ if ((checkNoBigSep == checkNoBigSep))
411+ then {
412+ let scriptTypesStr = valueOrElse(getString(k_SCRIPT_TYPES), "")
413+ let scriptTypes = split_4C(scriptTypesStr, ",")
414+ let checkExists = if ((indexOf(scriptTypes, scriptType) != unit))
415+ then throw((("Script type <" + scriptType) + "> already added"))
416+ else true
417+ if ((checkExists == checkExists))
418+ then {
419+ let newScriptTypes = if ((scriptTypesStr != ""))
420+ then (scriptTypes :+ scriptType)
421+ else [scriptType]
422+ let newScriptTypesStr = makeString_2C(newScriptTypes, ",")
423+[StringEntry(k_SCRIPT_TYPES, newScriptTypesStr)]
424+ }
425+ else throw("Strict value is not equal to itself.")
426+ }
427+ else throw("Strict value is not equal to itself.")
428+ }
429+ else throw("Strict value is not equal to itself.")
430+ }
431+ else throw("Strict value is not equal to itself.")
432+ }
433+ else throw("Strict value is not equal to itself.")
434+ }
435+ else throw("Strict value is not equal to itself.")
436+ }
437+
438+
439+
440+@Callable(i)
441+func removeScriptType (scriptType) = {
442+ let isSelf = if ((i.caller == this))
443+ then true
444+ else throw("Only self invoke")
445+ if ((isSelf == isSelf))
446+ then {
447+ let scriptTypesStr = valueOrElse(getString(k_SCRIPT_TYPES), "")
448+ let scriptTypes = split_4C(scriptTypesStr, ",")
449+ let index = valueOrErrorMessage(indexOf(scriptTypes, scriptType), (("Script type <" + scriptType) + "> is not present"))
450+ let newScriptTypes = removeByIndex(scriptTypes, index)
451+ let newScriptTypesStr = makeString_2C(newScriptTypes, ",")
452+[StringEntry(k_SCRIPT_TYPES, newScriptTypesStr)]
453+ }
454+ else throw("Strict value is not equal to itself.")
455+ }
456+
457+
458+
459+@Callable(i)
460+func setLimit (limit) = {
461+ let isSelf = if ((i.caller == this))
462+ then true
463+ else throw("Only self invoke")
464+ if ((isSelf == isSelf))
465+ then {
466+ let zeroLimit = if ((limit > 0))
467+ then true
468+ else throw("Limit should be > 0")
469+ if ((zeroLimit == zeroLimit))
470+ then {
471+ let admins = split(getStringValue(k_ADMINS), ",")
472+ if ((limit > size(admins)))
473+ then throw(((("Limit quorum should be <= size of list of admins, limit: " + toString(limit)) + ", current size: ") + toString(size(admins))))
474+ else [IntegerEntry(k_LIMIT, limit)]
475+ }
476+ else throw("Strict value is not equal to itself.")
477+ }
478+ else throw("Strict value is not equal to itself.")
479+ }
480+
481+
482+
483+@Callable(i)
484+func setCooldownBlocks (scriptsCooldown) = {
485+ let isSelf = if ((i.caller == this))
486+ then true
487+ else throw("Only self invoke")
488+ if ((isSelf == isSelf))
489+ then {
490+ let checkScriptsCooldown = if ((scriptsCooldown > 0))
491+ then true
492+ else throw("Scripts cooldown should be > 0")
493+ if ((checkScriptsCooldown == checkScriptsCooldown))
494+ then {
495+ let checkMaxCooldown = if ((scriptsCooldown > 14400))
496+ then throw("Scripts cooldown cannot exceed 14400 blocks (~10 days)")
497+ else true
498+ if ((checkMaxCooldown == checkMaxCooldown))
499+ then [IntegerEntry(k_SCRIPTS_COOLDOWN, scriptsCooldown)]
500+ else throw("Strict value is not equal to itself.")
501+ }
502+ else throw("Strict value is not equal to itself.")
503+ }
504+ else throw("Strict value is not equal to itself.")
505+ }
506+
507+
508+
509+@Callable(i)
510+func setSubmitCooldown (submitCooldown) = {
511+ let isSelf = if ((i.caller == this))
512+ then true
513+ else throw("Only self invoke")
514+ if ((isSelf == isSelf))
515+ then {
516+ let checkCooldown = if ((submitCooldown >= 0))
517+ then true
518+ else throw("Submit cooldown should be >= 0")
519+ if ((checkCooldown == checkCooldown))
520+ then [IntegerEntry(k_SUBMIT_COOLDOWN, submitCooldown)]
521+ else throw("Strict value is not equal to itself.")
522+ }
523+ else throw("Strict value is not equal to itself.")
524+ }
525+
526+
527+
528+@Callable(i)
529+func setTaskCooldown (taskCooldown) = {
530+ let isSelf = if ((i.caller == this))
531+ then true
532+ else throw("Only self invoke")
533+ if ((isSelf == isSelf))
534+ then {
535+ let checkCooldown = if ((taskCooldown >= 0))
536+ then true
537+ else throw("Task cooldown should be >= 0")
538+ if ((checkCooldown == checkCooldown))
539+ then {
540+ let checkMaxCooldown = if ((taskCooldown > 60))
541+ then throw("Task cooldown cannot exceed 60 blocks (~1 hour)")
542+ else true
543+ if ((checkMaxCooldown == checkMaxCooldown))
544+ then [IntegerEntry(k_TASK_COOLDOWN, taskCooldown)]
545+ else throw("Strict value is not equal to itself.")
546+ }
547+ else throw("Strict value is not equal to itself.")
548+ }
549+ else throw("Strict value is not equal to itself.")
550+ }
551+
552+
553+
554+@Callable(i)
555+func addScript (scriptType,storageAddress,_scriptHash,desc,initiatorAdr,validBlocks) = {
556+ let callerPbk = toBase58String(i.callerPublicKey)
557+ let storageScriptHash = toBase58String(value(scriptHash(addressFromStringValue(storageAddress))))
558+ let scriptTypesStr = getStringValue(k_SCRIPT_TYPES)
559+ let scriptTypes = split_4C(scriptTypesStr, ",")
560+ let isAllowed = if (!(_isValidOperator(callerPbk)))
561+ then throw("Only admins and managers are allowed")
562+ else true
563+ if ((isAllowed == isAllowed))
564+ then {
565+ let lastSubmitKey = ("lastSubmitScript_" + callerPbk)
566+ let lastSubmit = valueOrElse(getInteger(lastSubmitKey), 0)
567+ let submitCooldown = valueOrElse(getInteger(k_SUBMIT_COOLDOWN), 3)
568+ let _submitCooldown = if ((submitCooldown > (height - lastSubmit)))
569+ then throw((("Submit cooldown: wait " + toString((submitCooldown - (height - lastSubmit)))) + " more blocks"))
570+ else true
571+ if ((_submitCooldown == _submitCooldown))
572+ then {
573+ let _checkScriptTypes = if ((indexOf(scriptTypes, scriptType) == unit))
574+ then throw(("invalid script type or it is not present in storage: " + scriptType))
575+ else true
576+ if ((_checkScriptTypes == _checkScriptTypes))
577+ then {
578+ let _scriptStorageHashCheck = if ((storageScriptHash != _scriptHash))
579+ then throw("Stored and passed as argument scriptHashes not match")
580+ else true
581+ if ((_scriptStorageHashCheck == _scriptStorageHashCheck))
582+ then {
583+ let _descCheck = if ((size(desc) == 0))
584+ then throw("Description can't be empty")
585+ else true
586+ if ((_descCheck == _descCheck))
587+ then {
588+ let _initiatorCheck = if ((toString(addressFromPublicKey(i.callerPublicKey)) != initiatorAdr))
589+ then throw("Initiator address doesn't match caller")
590+ else true
591+ if ((_initiatorCheck == _initiatorCheck))
592+ then {
593+ let _checkValidBlocks = if ((validBlocks > 0))
594+ then true
595+ else throw("Valid blocks should be > 0")
596+ if ((_checkValidBlocks == _checkValidBlocks))
597+ then {
598+ let _checkMaxValidBlocks = if ((validBlocks > 10080))
599+ then throw("validBlocks cannot exceed 10080 blocks (~7 days)")
600+ else true
601+ if ((_checkMaxValidBlocks == _checkMaxValidBlocks))
602+ then {
603+ let scriptsCooldown = getIntegerValue(k_SCRIPTS_COOLDOWN)
604+ let _checkCooldownWindow = if ((scriptsCooldown >= validBlocks))
605+ then throw((((("validBlocks (" + toString(validBlocks)) + ") must be greater than scripts cooldown (") + toString(scriptsCooldown)) + ")"))
606+ else true
607+ if ((_checkCooldownWindow == _checkCooldownWindow))
608+ then {
609+ let iteration = (valueOrElse(getInteger(((k_ITERATION + SEP) + scriptType)), 0) + 1)
610+ let scriptId = ((("script%%" + scriptType) + "%%") + _scriptHash)
611+ let _checkPresent = if (isDefined(getString(((scriptId + BIGSEP) + k_scriptHash))))
612+ then throw("Script with this hash already present")
613+ else true
614+ if ((_checkPresent == _checkPresent))
615+ then [StringEntry(((scriptId + BIGSEP) + k_scriptType), scriptType), StringEntry(((scriptId + BIGSEP) + k_storageAddress), storageAddress), StringEntry(((scriptId + BIGSEP) + k_scriptHash), storageScriptHash), StringEntry(((scriptId + BIGSEP) + k_desc), desc), IntegerEntry(((scriptId + BIGSEP) + k_iter), iteration), IntegerEntry(((scriptId + BIGSEP) + k_validBlocks), validBlocks), StringEntry(((scriptId + BIGSEP) + k_initiator), initiatorAdr), StringEntry((((((scriptType + BIGSEP) + k_iter) + BIGSEP) + toString(iteration)) + "__hash"), _scriptHash), IntegerEntry(((k_ITERATION + SEP) + scriptType), iteration), IntegerEntry(lastSubmitKey, height)]
616+ else throw("Strict value is not equal to itself.")
617+ }
618+ else throw("Strict value is not equal to itself.")
619+ }
620+ else throw("Strict value is not equal to itself.")
621+ }
622+ else throw("Strict value is not equal to itself.")
623+ }
624+ else throw("Strict value is not equal to itself.")
625+ }
626+ else throw("Strict value is not equal to itself.")
627+ }
628+ else throw("Strict value is not equal to itself.")
629+ }
630+ else throw("Strict value is not equal to itself.")
631+ }
632+ else throw("Strict value is not equal to itself.")
633+ }
634+ else throw("Strict value is not equal to itself.")
635+ }
636+
637+
638+
639+@Callable(i)
640+func removeScript (scriptId) = {
641+ let _checkId = if ((indexOf(scriptId, "script%%") != 0))
642+ then throw("Invalid scriptId format")
643+ else true
644+ if ((_checkId == _checkId))
645+ then {
646+ let callerPbk = toBase58String(i.callerPublicKey)
647+ let callerAddress = toString(addressFromPublicKey(i.callerPublicKey))
648+ let isAdmin = _isAdmin(callerPbk)
649+ let isOperator = _isValidOperator(callerPbk)
650+ let _checkAllowed = if (!(isOperator))
651+ then throw("Only admins and managers are allowed")
652+ else true
653+ if ((_checkAllowed == _checkAllowed))
654+ then {
655+ let initiatorAdr = getStringValue((scriptId + "__initiator"))
656+ let _checkPermission = if (if (!(isAdmin))
657+ then (initiatorAdr != callerAddress)
658+ else false)
659+ then throw("Only admins or the creator can remove")
660+ else true
661+ if ((_checkPermission == _checkPermission))
662+ then {
663+ let scriptType = getStringValue(((scriptId + BIGSEP) + k_scriptType))
664+ let _scriptHash = getStringValue(((scriptId + BIGSEP) + k_scriptHash))
665+ let iter = getIntegerValue(((scriptId + BIGSEP) + k_iter))
666+ let existingValidTo = getInteger(getScriptValidToKey(scriptType, _scriptHash))
667+ let isCurrentlyApproved = match existingValidTo {
668+ case vt: Int =>
669+ (vt >= height)
670+ case _ =>
671+ false
672+ }
673+ let _checkApproved = if (isCurrentlyApproved)
674+ then throw("Cannot remove approved script, use revoke first")
675+ else true
676+ if ((_checkApproved == _checkApproved))
677+ then [DeleteEntry(((scriptId + BIGSEP) + k_scriptType)), DeleteEntry(((scriptId + BIGSEP) + k_storageAddress)), DeleteEntry(((scriptId + BIGSEP) + k_scriptHash)), DeleteEntry(((scriptId + BIGSEP) + k_desc)), DeleteEntry(((scriptId + BIGSEP) + k_iter)), DeleteEntry(((scriptId + BIGSEP) + k_validBlocks)), DeleteEntry((((((scriptType + BIGSEP) + k_iter) + BIGSEP) + toString(iter)) + "__hash")), DeleteEntry(((scriptId + BIGSEP) + k_initiator)), DeleteEntry(((scriptId + BIGSEP) + k_confirmations)), DeleteEntry(getScriptValidFromKey(scriptType, _scriptHash)), DeleteEntry(getScriptValidToKey(scriptType, _scriptHash))]
678+ else throw("Strict value is not equal to itself.")
679+ }
680+ else throw("Strict value is not equal to itself.")
681+ }
682+ else throw("Strict value is not equal to itself.")
683+ }
684+ else throw("Strict value is not equal to itself.")
685+ }
686+
687+
688+
689+@Callable(i)
690+func addConfirmationScript (scriptId) = {
691+ let _checkId = if ((indexOf(scriptId, "script%%") != 0))
692+ then throw("Invalid scriptId format")
693+ else true
694+ if ((_checkId == _checkId))
695+ then {
696+ let callerPbk = toBase58String(i.callerPublicKey)
697+ let limit = _getLimit()
698+ let checkAdmin = if (!(_isAdmin(callerPbk)))
699+ then throw("Only admins can confirm")
700+ else true
701+ if ((checkAdmin == checkAdmin))
702+ then {
703+ let _scriptHash = valueOrErrorMessage(getString(((scriptId + BIGSEP) + k_scriptHash)), "Invalid scriptId")
704+ if ((_scriptHash == _scriptHash))
705+ then {
706+ let scriptType = getStringValue(((scriptId + BIGSEP) + k_scriptType))
707+ let validBlocks = getIntegerValue(((scriptId + BIGSEP) + k_validBlocks))
708+ let existingValidTo = getInteger(getScriptValidToKey(scriptType, _scriptHash))
709+ let isAlreadyApproved = match existingValidTo {
710+ case vt: Int =>
711+ (vt >= height)
712+ case _ =>
713+ false
714+ }
715+ let _checkApproved = if (isAlreadyApproved)
716+ then throw("This script is already approved and still valid")
717+ else true
718+ if ((_checkApproved == _checkApproved))
719+ then {
720+ let globalIteration = valueOrElse(getInteger(((k_ITERATION + SEP) + scriptType)), 0)
721+ let confirmationsStr = valueOrElse(getString((scriptId + "__confirmations")), "")
722+ let rawConfirmations = if ((confirmationsStr != ""))
723+ then split(confirmationsStr, ",")
724+ else nil
725+ let isExpired = match existingValidTo {
726+ case vt: Int =>
727+ (height > vt)
728+ case _ =>
729+ false
730+ }
731+ let confirmations = if (isExpired)
732+ then nil
733+ else _filterValidConfirmations(rawConfirmations)
734+ let expiredCleanup = if (isExpired)
735+ then [DeleteEntry(getScriptValidFromKey(scriptType, _scriptHash)), DeleteEntry(getScriptValidToKey(scriptType, _scriptHash))]
736+ else nil
737+ if ((indexOf(confirmations, callerPbk) != unit))
738+ then throw("You already confirmed this script")
739+ else {
740+ let newList = (confirmations :+ callerPbk)
741+ let newListStr = makeString(newList, ",")
742+ let approved = (size(newList) >= limit)
743+ let result = if (approved)
744+ then [IntegerEntry(getScriptValidFromKey(scriptType, _scriptHash), (height + getIntegerValue(k_SCRIPTS_COOLDOWN))), IntegerEntry(getScriptValidToKey(scriptType, _scriptHash), (height + validBlocks))]
745+ else nil
746+ ((expiredCleanup ++ result) ++ [StringEntry((scriptId + "__confirmations"), newListStr)])
747+ }
748+ }
749+ else throw("Strict value is not equal to itself.")
750+ }
751+ else throw("Strict value is not equal to itself.")
752+ }
753+ else throw("Strict value is not equal to itself.")
754+ }
755+ else throw("Strict value is not equal to itself.")
756+ }
757+
758+
759+
760+@Callable(i)
761+func revokeConfirmationScript (scriptId) = {
762+ let _checkId = if ((indexOf(scriptId, "script%%") != 0))
763+ then throw("Invalid scriptId format")
764+ else true
765+ if ((_checkId == _checkId))
766+ then {
767+ let callerPbk = toBase58String(i.callerPublicKey)
768+ let limit = _getLimit()
769+ if (!(_isAdmin(callerPbk)))
770+ then throw("Only admins can revoke confirmations")
771+ else {
772+ let _scriptHash = valueOrErrorMessage(getString((scriptId + "__scriptHash")), "Invalid scriptId")
773+ if ((_scriptHash == _scriptHash))
774+ then {
775+ let scriptType = getStringValue((scriptId + "__scriptType"))
776+ let confirmationsStr = valueOrElse(getString((scriptId + "__confirmations")), "")
777+ let rawConfirmations = if ((confirmationsStr != ""))
778+ then split(confirmationsStr, ",")
779+ else nil
780+ let confirmations = _filterValidConfirmations(rawConfirmations)
781+ let confirmIndex = indexOf(confirmations, callerPbk)
782+ let isExpired = (height > valueOrElse(getInteger(getScriptValidToKey(scriptType, _scriptHash)), (height + 1)))
783+ let checkExpired = if (!(isExpired))
784+ then true
785+ else throw("Expired scripts can't be revoked")
786+ if ((checkExpired == checkExpired))
787+ then if ((confirmIndex == unit))
788+ then throw("You didn't confirm this script, nothing to revoke")
789+ else {
790+ let newConfirmations = removeByIndex(confirmations, value(confirmIndex))
791+ let newConfirmationsStr = makeString(newConfirmations, ",")
792+ let wasApproved = if (isDefined(getInteger(getScriptValidFromKey(scriptType, _scriptHash))))
793+ then isDefined(getInteger(getScriptValidToKey(scriptType, _scriptHash)))
794+ else false
795+ let stillApproved = (size(newConfirmations) >= limit)
796+ let stateChanges = if (if (wasApproved)
797+ then !(stillApproved)
798+ else false)
799+ then [DeleteEntry(getScriptValidFromKey(scriptType, _scriptHash)), DeleteEntry(getScriptValidToKey(scriptType, _scriptHash))]
800+ else nil
801+ (stateChanges ++ [StringEntry((scriptId + "__confirmations"), newConfirmationsStr)])
802+ }
803+ else throw("Strict value is not equal to itself.")
804+ }
805+ else throw("Strict value is not equal to itself.")
806+ }
807+ }
808+ else throw("Strict value is not equal to itself.")
809+ }
810+
811+
812+
813+@Callable(i)
814+func addTask (name,dapp,txid,executeTs,desc,initiatorAdr,txBodyBytes) = {
815+ let callerPbk = toBase58String(i.callerPublicKey)
816+ if (!(_isValidOperator(callerPbk)))
817+ then throw("Only admins and managers are allowed")
818+ else {
819+ let lastSubmitKey = ("lastSubmitTask_" + callerPbk)
820+ let lastSubmit = valueOrElse(getInteger(lastSubmitKey), 0)
821+ let submitCooldown = valueOrElse(getInteger(k_SUBMIT_COOLDOWN), 3)
822+ let _submitCooldown = if ((submitCooldown > (height - lastSubmit)))
823+ then throw((("Submit cooldown: wait " + toString((submitCooldown - (height - lastSubmit)))) + " more blocks"))
824+ else true
825+ if ((_submitCooldown == _submitCooldown))
826+ then {
827+ let _nameCheck = if ((size(name) == 0))
828+ then throw("Name can't be empty")
829+ else true
830+ if ((_nameCheck == _nameCheck))
831+ then {
832+ let _dappCheck = if (!(_validateAddress(dapp)))
833+ then throw("Incorrect dapp")
834+ else true
835+ if ((_dappCheck == _dappCheck))
836+ then {
837+ let _txidCheck = if ((size(txid) == 0))
838+ then throw("txid can't be empty")
839+ else true
840+ if ((_txidCheck == _txidCheck))
841+ then {
842+ let _timestampCheck = if (!(_validateTs(executeTs)))
843+ then throw("Invalid execution timestamp - cannot be more than 1 hour in the past")
844+ else true
845+ if ((_timestampCheck == _timestampCheck))
846+ then {
847+ let _descCheck = if ((size(desc) == 0))
848+ then throw("Description can't be empty")
849+ else true
850+ if ((_descCheck == _descCheck))
851+ then {
852+ let _initiatorCheck = if ((toString(addressFromPublicKey(i.callerPublicKey)) != initiatorAdr))
853+ then throw("Initiator address doesn't match caller")
854+ else true
855+ if ((_initiatorCheck == _initiatorCheck))
856+ then {
857+ let _bodyBytesCheck = if ((size(txBodyBytes) == 0))
858+ then throw("Tx body bytes can't be empty")
859+ else true
860+ if ((_bodyBytesCheck == _bodyBytesCheck))
861+ then {
862+ let bodyBytes = fromBase64String(txBodyBytes)
863+ let computedId = toBase58String(blake2b256(bodyBytes))
864+ let _txidVerify = if ((computedId != txid))
865+ then throw(((("txid verification failed: blake2b256(bodyBytes) = " + computedId) + " != txid = ") + txid))
866+ else true
867+ if ((_txidVerify == _txidVerify))
868+ then {
869+ let taskId = ((("tx_" + dapp) + SEP) + txid)
870+ let _checkPresent = if (isDefined(getString((taskId + "__txId"))))
871+ then throw("Task with this (dapp, txid) already present")
872+ else true
873+ if ((_checkPresent == _checkPresent))
874+ then [StringEntry((taskId + "__name"), name), StringEntry((taskId + "__dapp"), dapp), StringEntry((taskId + "__txId"), txid), StringEntry((taskId + "__desc"), desc), StringEntry((taskId + "__txBodyBytes"), txBodyBytes), StringEntry((taskId + "__initiator"), initiatorAdr), IntegerEntry((taskId + "__ts"), executeTs), IntegerEntry(lastSubmitKey, height)]
875+ else throw("Strict value is not equal to itself.")
876+ }
877+ else throw("Strict value is not equal to itself.")
878+ }
879+ else throw("Strict value is not equal to itself.")
880+ }
881+ else throw("Strict value is not equal to itself.")
882+ }
883+ else throw("Strict value is not equal to itself.")
884+ }
885+ else throw("Strict value is not equal to itself.")
886+ }
887+ else throw("Strict value is not equal to itself.")
888+ }
889+ else throw("Strict value is not equal to itself.")
890+ }
891+ else throw("Strict value is not equal to itself.")
892+ }
893+ else throw("Strict value is not equal to itself.")
894+ }
895+ }
896+
897+
898+
899+@Callable(i)
900+func removeTask (taskId) = {
901+ let _checkId = if ((indexOf(taskId, "tx_") != 0))
902+ then throw("Invalid taskId format")
903+ else true
904+ if ((_checkId == _checkId))
905+ then {
906+ let callerPbk = toBase58String(i.callerPublicKey)
907+ let callerAddress = toString(addressFromPublicKey(i.callerPublicKey))
908+ let isOperator = _isValidOperator(callerPbk)
909+ let _checkAllowed = if (!(isOperator))
910+ then throw("Only admins and managers are allowed")
911+ else true
912+ if ((_checkAllowed == _checkAllowed))
913+ then {
914+ let initiatorAdr = getStringValue((taskId + "__initiator"))
915+ let _checkPermission = if ((initiatorAdr != callerAddress))
916+ then throw("Only the task creator can remove")
917+ else true
918+ if ((_checkPermission == _checkPermission))
919+ then {
920+ let txId = valueOrErrorMessage(getString((taskId + "__txId")), "Invalid task")
921+ if ((txId == txId))
922+ then {
923+ let dapp = getStringValue((taskId + "__dapp"))
924+[DeleteEntry((taskId + "__name")), DeleteEntry((taskId + "__dapp")), DeleteEntry((taskId + "__txId")), DeleteEntry((taskId + "__desc")), DeleteEntry((taskId + "__txBodyBytes")), DeleteEntry((taskId + "__initiator")), DeleteEntry((taskId + "__ts")), DeleteEntry((taskId + "__confirmations")), DeleteEntry((taskId + "__approvedFrom")), DeleteEntry((((dapp + SEP) + txId) + "__approved"))]
925+ }
926+ else throw("Strict value is not equal to itself.")
927+ }
928+ else throw("Strict value is not equal to itself.")
929+ }
930+ else throw("Strict value is not equal to itself.")
931+ }
932+ else throw("Strict value is not equal to itself.")
933+ }
934+
935+
936+
937+@Callable(i)
938+func addConfirmation (taskId) = {
939+ let _checkId = if ((indexOf(taskId, "tx_") != 0))
940+ then throw("Invalid taskId format")
941+ else true
942+ if ((_checkId == _checkId))
943+ then {
944+ let callerPbk = toBase58String(i.callerPublicKey)
945+ let limit = _getLimit()
946+ if (!(_isAdmin(callerPbk)))
947+ then throw("Only admins can confirm")
948+ else {
949+ let txId = valueOrErrorMessage(getString((taskId + "__txId")), "Invalid task")
950+ if ((txId == txId))
951+ then {
952+ let dapp = getStringValue((taskId + "__dapp"))
953+ let confirmationsStr = valueOrElse(getString((taskId + "__confirmations")), "")
954+ let rawConfirmations = if ((confirmationsStr != ""))
955+ then split(confirmationsStr, ",")
956+ else nil
957+ let confirmations = _filterValidConfirmations(rawConfirmations)
958+ if ((indexOf(confirmations, callerPbk) != unit))
959+ then throw("You already confirmed this task")
960+ else {
961+ let newList = (confirmations :+ callerPbk)
962+ let newListStr = makeString(newList, ",")
963+ let approved = (size(newList) >= limit)
964+ let taskCooldown = valueOrElse(getInteger(k_TASK_COOLDOWN), 0)
965+ let existingApprovedFrom = getInteger((taskId + "__approvedFrom"))
966+ let approvedFromEntry = if (approved)
967+ then match existingApprovedFrom {
968+ case _: Int =>
969+ nil
970+ case _ =>
971+[IntegerEntry((taskId + "__approvedFrom"), (height + taskCooldown))]
972+ }
973+ else nil
974+ ([StringEntry((taskId + "__confirmations"), newListStr), BooleanEntry((((dapp + SEP) + txId) + "__approved"), approved)] ++ approvedFromEntry)
975+ }
976+ }
977+ else throw("Strict value is not equal to itself.")
978+ }
979+ }
980+ else throw("Strict value is not equal to itself.")
981+ }
982+
983+
984+
985+@Callable(i)
986+func revokeTask (taskId) = {
987+ let _checkId = if ((indexOf(taskId, "tx_") != 0))
988+ then throw("Invalid taskId format")
989+ else true
990+ if ((_checkId == _checkId))
991+ then {
992+ let callerPbk = toBase58String(i.callerPublicKey)
993+ let limit = _getLimit()
994+ if (!(_isAdmin(callerPbk)))
995+ then throw("Only admins can revoke")
996+ else {
997+ let txId = valueOrErrorMessage(getString((taskId + "__txId")), "Invalid task")
998+ if ((txId == txId))
999+ then {
1000+ let confirmationsStr = valueOrElse(getString((taskId + "__confirmations")), "")
1001+ let rawConfirmations = if ((confirmationsStr != ""))
1002+ then split(confirmationsStr, ",")
1003+ else nil
1004+ let confirmations = _filterValidConfirmations(rawConfirmations)
1005+ let indexMy = indexOf(confirmations, callerPbk)
1006+ if ((indexMy == unit))
1007+ then throw("You did not confirm this task, nothing to revoke")
1008+ else {
1009+ let dapp = getStringValue((taskId + "__dapp"))
1010+ let newList = removeByIndex(confirmations, value(indexMy))
1011+ let newListStr = makeString(newList, ",")
1012+ let approved = (size(newList) >= limit)
1013+[StringEntry((taskId + "__confirmations"), newListStr), BooleanEntry((((dapp + SEP) + txId) + "__approved"), approved)]
1014+ }
1015+ }
1016+ else throw("Strict value is not equal to itself.")
1017+ }
1018+ }
1019+ else throw("Strict value is not equal to itself.")
1020+ }
1021+
1022+
1023+@Verifier(tx)
1024+func verify () = {
1025+ let CONTRACT_TYPE = "APPROVER_CONTRACT"
1026+ if (_isInited())
1027+ then match tx {
1028+ case ttx: SetScriptTransaction =>
1029+ match ttx.script {
1030+ case script: ByteVector =>
1031+ let scriptHasha = toBase58String(blake2b256(script))
1032+ let validFrom = valueOrErrorMessage(getInteger(this, (((("script%%" + CONTRACT_TYPE) + "%%") + scriptHasha) + "%%validFrom")), "validFrom not set")
1033+ let validTo = valueOrErrorMessage(getInteger(this, (((("script%%" + CONTRACT_TYPE) + "%%") + scriptHasha) + "%%validTo")), "validTo not set")
1034+ if ((height >= validFrom))
1035+ then (validTo >= height)
1036+ else false
1037+ case _ =>
1038+ false
1039+ }
1040+ case otx =>
1041+ let taskId = ((("tx_" + toString(this)) + SEP) + toBase58String(otx.id))
1042+ let isApproved = valueOrElse(getBoolean(this, (((toString(this) + "_") + toBase58String(otx.id)) + "__approved")), false)
1043+ let approvedFrom = valueOrElse(getInteger(this, (taskId + "__approvedFrom")), 0)
1044+ if (isApproved)
1045+ then (height >= approvedFrom)
1046+ else false
1047+ }
1048+ else sigVerify(tx.bodyBytes, tx.proofs[0], tx.senderPublicKey)
1049+ }
1050+

github/deemru/w8io
495.49 ms