tx · 2bdXR5o749gf4wGve1noJMMiUhvGA61adYNYqAr3TRpw

3PLncXtS1U83D6cQbFD3H8rBHPLgzxSFKZ1:  -0.03400000 Waves

2023.01.29 20:44 [3492118] smart account 3PLncXtS1U83D6cQbFD3H8rBHPLgzxSFKZ1 > SELF 0.00000000 Waves

{ "type": 13, "id": "2bdXR5o749gf4wGve1noJMMiUhvGA61adYNYqAr3TRpw", "fee": 3400000, "feeAssetId": null, "timestamp": 1675014235637, "version": 2, "chainId": 87, "sender": "3PLncXtS1U83D6cQbFD3H8rBHPLgzxSFKZ1", "senderPublicKey": "BtDpFhgHQKHFVqYTMLReuZzqy94CRPSRkrYcSEVyjt4q", "proofs": [ "XAyUoRQ6Kc2pi8E1vVsQcmtjEcKsFaAp2eRtxvnrScTysDBniXaD9hU1uNmJ7Vhsmhf5zX1Vr7fYZXAsumJfJEm" ], "script": "base64:BgJjCAISAwoBBBIAEgMKAQgSABIDCgEIEgQKAgEIEgQKAgICEgQKAgEIEgQKAgEBEgQKAggIEgQKAgICEgQKAgICEgMKAQgSAwoBCBIDCgEIEgMKARgSAwoBGBIDCgEBEgQKAgEIYgAFY2hhaW4JAMkBAgkAygECCAUEdGhpcwVieXRlcwABAAEAC3VzZG5Bc3NldElkBAckbWF0Y2gwBQVjaGFpbgMJAAACAQFXBQckbWF0Y2gwASC2JinDBPXOU5GkDkt1JC9kjFGx+t+vVCm9SNIdKrKq0QMJAAACAQFUBQckbWF0Y2gwASD3dur394PKZdtuE+4CO89YKZWpwdGN8kvabNgdYoDI3gkAAgECDVVua25vd24gY2hhaW4ADWluY3ViYXRvckFkZHIEByRtYXRjaDAFBWNoYWluAwkAAAIBAVcFByRtYXRjaDAJARFAZXh0ck5hdGl2ZSgxMDYyKQECIzNQRWt0VnV4MlJoY2hTTjYzRHNEbzRiNG16NFFxektTZUR2AwkAAAIBAVQFByRtYXRjaDAFBHRoaXMJAAIBAg1Vbmtub3duIGNoYWluAAticmVlZGVyQWRkcgQHJG1hdGNoMAUFY2hhaW4DCQAAAgEBVwUHJG1hdGNoMAkBEUBleHRyTmF0aXZlKDEwNjIpAQIjM1BEVnVVNDVIN0VoNWRtdE5iblJOUlN0R3dVTEE3Tlk2SGIDCQAAAgEBVAUHJG1hdGNoMAUEdGhpcwkAAgECDVVua25vd24gY2hhaW4AD2Vjb25vbXlDb250cmFjdAkBEUBleHRyTmF0aXZlKDEwNjIpAQQHJG1hdGNoMAUFY2hhaW4DCQAAAgEBVwUHJG1hdGNoMAIjM1Ayc2sxS25jU3hSYVpzOGI0Q1dHUHcyamt2dmF2NzR1NEQDCQAAAgEBVAUHJG1hdGNoMAIjM044eTR3eFgzSkM0VGRyQ0pCWFgxNlNqV2Y2WDI1NmhyZXAJAAIBAg1Vbmtub3duIGNoYWluAANwdWIBIE9T4ho/VKjWnVJOEx1GJ1W9s1PzLHvJVFSw/0PBtBQoAAhIRUFMQ09TVACQTgAKTEFORFBSRUZJWAIETEFORAAKRFVDS1BSRUZJWAIERFVDSwAPREVGQVVMVExPQ0FUSU9OAg9BZnJpY2FfRl9BZnJpY2EABk5VTVJFUwAGAAVTU0laRQAZAAVNU0laRQBkAAVMU0laRQDhAQAGWExTSVpFAJADAAdYWExTSVpFAPEEAA9EQUlMWVJFU0JZUElFQ0UAgPjSAQAJREFZTUlMTElTAIC4mSkAEUZJVkVNSU5VVEVTTUlMTElTAOCnEgAQUkVTT1VSQ0VQUklDRU1JTgDV1gkAEUluZnJhVXBncmFkZUNvc3RTBAckbWF0Y2gwBQVjaGFpbgMJAAACAQFXBQckbWF0Y2gwAMbrwL8XAwkAAAIBAVQFByRtYXRjaDAA8M2JHgkAAgECDVVua25vd24gY2hhaW4AFUluZnJhVXBncmFkZUNvc3RTVXNkbgQHJG1hdGNoMAUFY2hhaW4DCQAAAgEBVwUHJG1hdGNoMACAtIkTAwkAAAIBAVQFByRtYXRjaDAAgLUYCQACAQINVW5rbm93biBjaGFpbgAMRVhQTUFURVJJQUxTBAckbWF0Y2gwBQVjaGFpbgMJAAACAQFXBQckbWF0Y2gwAMuA1bPLBAMJAAACAQFUBQckbWF0Y2gwAPGa8O8FCQACAQINVW5rbm93biBjaGFpbgAHRVhQVVNETgQHJG1hdGNoMAUFY2hhaW4DCQAAAgEBVwUHJG1hdGNoMACAlOvcAwMJAAACAQFUBQckbWF0Y2gwAICt4gQJAAIBAg1Vbmtub3duIGNoYWluAAVNVUxUNgDAhD0ABUZJVkVYCQC2AgEABQAHVFdFTlRZWAkAtgIBABQACFRXRU5UWTJYCQC2AgEJAGgCABQAFAAIVFdFTlRZM1gJALYCAQkAaAIJAGgCABQAFAAUAAhUV0VOVFk0WAkAtgIBCQBoAgkAaAIJAGgCABQAFAAUABQACFRXRU5UWTVYCQC2AgEJAGgCCQBoAgkAaAIJAGgCABQAFAAUABQAFAAIbWF0VHlwZXMJAMwIAgIERnVlbAkAzAgCAgVNZXRhbAkAzAgCAgVQbGFuawkAzAgCAgVHbGFzcwkAzAgCAgdQbGFzdGljCQDMCAICB1Byb3RlaW4FA25pbAAKY29udGluZW50cwkAzAgCAgRBc2lhCQDMCAICBkV1cm9wZQkAzAgCAghBbWVyaWNhcwkAzAgCAgdPY2VhbmlhCQDMCAICBkFmcmljYQUDbmlsAApBUlRQUkVTQUxFAgdQUkVTQUxFAA9QUkVTQUxFTlVNTEFORFMA9AMBEWtleUxhc3RUeElkQnlVc2VyAQRhZGRyCQCsAgICD2xhc3RUeElkQnlVc2VyXwUEYWRkcgESa2V5TmV4dEZyZWVMYW5kTnVtAAILbmV4dExhbmROdW0BEGtleUxhbmRUb0Fzc2V0SWQBB2xhbmROdW0JAKwCAgIMbGFuZFRvQXNzZXRfBQdsYW5kTnVtAQprZXlOZnROYW1lAgdsYW5kTnVtCGxhbmRTaXplCQCsAgIJAKwCAgUKTEFORFBSRUZJWAUHbGFuZE51bQUIbGFuZFNpemUBFWtleUxhbmRBc3NldElkVG9Pd25lcgEHYXNzZXRJZAkArAICAgluZnRPd25lcl8FB2Fzc2V0SWQBEGtleUR1Y2tJZFRvT3duZXIBB2Fzc2V0SWQJAKwCAgIKZHVja093bmVyXwUHYXNzZXRJZAEWa2V5U3Rha2VkVGltZUJ5QXNzZXRJZAEHYXNzZXRJZAkArAICAgtzdGFrZWRUaW1lXwUHYXNzZXRJZAEWa2V5SW5mcmFMZXZlbEJ5QXNzZXRJZAEHYXNzZXRJZAkArAICAgtpbmZyYUxldmVsXwUHYXNzZXRJZAEea2V5SW5mcmFMZXZlbEJ5QXNzZXRJZEFuZE93bmVyAgdhc3NldElkCW93bmVyQWRkcgkArAICCQCsAgIJAKwCAgIcaW5mcmFMZXZlbEJ5QXNzZXRJZEFuZE93bmVyXwUHYXNzZXRJZAIBXwUJb3duZXJBZGRyAR9rZXlQcmVzYWxlQXJ0QWN0aXZhdGVkQnlBc3NldElkAQdhc3NldElkCQCsAgICFHByZXNhbGVBcnRBY3RpdmF0ZWRfBQdhc3NldElkASdrZXlQcmVzYWxlQXJ0QWN0aXZhdGVkQnlBc3NldElkQW5kT3duZXICB2Fzc2V0SWQJb3duZXJBZGRyCQCsAgIJAKwCAgkArAICAiVwcmVzYWxlQXJ0QWN0aXZhdGVkQnlBc3NldElkQW5kT3duZXJfBQdhc3NldElkAgFfBQlvd25lckFkZHIBIGtleUxhbmRBcnRTdGF0dXNCeVR5cGVBbmRBc3NldElkAgR0eXBlB2Fzc2V0SWQJALkJAgkAzAgCAg1sYW5kQXJ0U3RhdHVzCQDMCAIFBHR5cGUJAMwIAgUHYXNzZXRJZAUDbmlsAgFfASVrZXlMYW5kQXJ0U3RhdHVzQnlUeXBlQXNzZXRJZEFuZE93bmVyAwR0eXBlB2Fzc2V0SWQJb3duZXJBZGRyCQC5CQIJAMwIAgIibGFuZEFydFN0YXR1c0J5VHlwZUFzc2V0SWRBbmRPd25lcgkAzAgCBQR0eXBlCQDMCAIFB2Fzc2V0SWQJAMwIAgUJb3duZXJBZGRyBQNuaWwCAV8BFGtleVN0YWtlZER1Y2tCeU93bmVyAQlvd25lckFkZHIJAKwCAgISc3Rha2VkRHVja0J5T3duZXJfBQlvd25lckFkZHIBImtleVN0YWtlZFRpbWVCeVR5cGVBc3NldElkQW5kT3duZXIDB25mdFR5cGUHYXNzZXRJZAlvd25lckFkZHIJAKwCAgkArAICCQCsAgIJAKwCAgkArAICAiBzdGFrZWRUaW1lQnlUeXBlQXNzZXRJZEFuZE93bmVyXwUHbmZ0VHlwZQIBXwUHYXNzZXRJZAIBXwUJb3duZXJBZGRyARFrZXlMYW5kTnVtVG9Pd25lcgEHbGFuZE51bQkArAICAgpsYW5kT3duZXJfBQdsYW5kTnVtARFrZXlCYWNrcGFja0J5RHVjawELZHVja0Fzc2V0SWQJAKwCAgIJYmFja1BhY2tfBQtkdWNrQXNzZXRJZAEPa2V5RHVja0xvY2F0aW9uAQtkdWNrQXNzZXRJZAkArAICAg1kdWNrTG9jYXRpb25fBQtkdWNrQXNzZXRJZAENa2V5RHVja0hlYWx0aAELZHVja0Fzc2V0SWQJAKwCAgILZHVja0hlYWx0aF8FC2R1Y2tBc3NldElkARFrZXlSZXNQcm9wb3J0aW9ucwACE3Jlc1R5cGVzUHJvcG9ydGlvbnMBFWtleVN0YWtlZExhbmRzQnlPd25lcgEJb3duZXJBZGRyCQCsAgICE3N0YWtlZExhbmRzQnlPd25lcl8FCW93bmVyQWRkcgEKa2V5QmxvY2tlZAACEGNvbnRyYWN0c0Jsb2NrZWQACnJlY0xhbmROdW0AAAALcmVjTGFuZFNpemUAAQALcmVjVGVycmFpbnMAAgAMcmVjQ29udGluZW50AAMAD2xvY0lkeENvbnRpbmVudAAAAApsb2NJZHhUeXBlAAEACGxvY0lkeElkAAIACmJwSWR4TGV2ZWwAAAAIYnBJZHhSZXMAAQAIYnBJZHhNYXQAAgAJYnBJZHhQcm9kAAMBCGFzU3RyaW5nAQF2BAckbWF0Y2gwBQF2AwkAAQIFByRtYXRjaDACBlN0cmluZwQBcwUHJG1hdGNoMAUBcwkAAgECGGZhaWwgdG8gY2FzdCBpbnRvIFN0cmluZwETZGlzdHJpYnV0ZUJ5V2VpZ2h0cwIFdG90YWwHd2VpZ2h0cwQDc3VtCQBkAgkAZAIJAGQCCQBkAgkAZAIJAJEDAgUHd2VpZ2h0cwAACQCRAwIFB3dlaWdodHMAAQkAkQMCBQd3ZWlnaHRzAAIJAJEDAgUHd2VpZ2h0cwADCQCRAwIFB3dlaWdodHMABAkAkQMCBQd3ZWlnaHRzAAUDCQBnAgAABQNzdW0JAAIBAhBaZXJvIHdlaWdodHMgc3VtBAVub3JtNgkAawMFBXRvdGFsBQVNVUxUNgUDc3VtCgEKbm9ybWFsaXplcgIDYWNjBGVsZW0JAM0IAgUDYWNjCQBrAwUEZWxlbQUFbm9ybTYFBU1VTFQ2CgACJGwFB3dlaWdodHMKAAIkcwkAkAMBBQIkbAoABSRhY2MwBQNuaWwKAQUkZjBfMQICJGECJGkDCQBnAgUCJGkFAiRzBQIkYQkBCm5vcm1hbGl6ZXICBQIkYQkAkQMCBQIkbAUCJGkKAQUkZjBfMgICJGECJGkDCQBnAgUCJGkFAiRzBQIkYQkAAgECE0xpc3Qgc2l6ZSBleGNlZWRzIDYJAQUkZjBfMgIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIFBSRhY2MwAAAAAQACAAMABAAFAAYBEmdldE5lZWRlZE1hdGVyaWFscwEFdG90YWwEBXByb3BzCQC1CQIJAQV2YWx1ZQEJAKIIAQkBEWtleVJlc1Byb3BvcnRpb25zAAIBXwMJAQIhPQIJAJADAQUFcHJvcHMFBk5VTVJFUwkAAgECFldyb25nIHByb3BvcnRpb25zIGRhdGEEAXIJAMwIAgkBDXBhcnNlSW50VmFsdWUBCQCRAwIFBXByb3BzAAAJAMwIAgkBDXBhcnNlSW50VmFsdWUBCQCRAwIFBXByb3BzAAEJAMwIAgkBDXBhcnNlSW50VmFsdWUBCQCRAwIFBXByb3BzAAIJAMwIAgkBDXBhcnNlSW50VmFsdWUBCQCRAwIFBXByb3BzAAMJAMwIAgkBDXBhcnNlSW50VmFsdWUBCQCRAwIFBXByb3BzAAQJAMwIAgkBDXBhcnNlSW50VmFsdWUBCQCRAwIFBXByb3BzAAUFA25pbAkBE2Rpc3RyaWJ1dGVCeVdlaWdodHMCBQV0b3RhbAUBcgERc3VidHJhY3RNYXRlcmlhbHMDDHNob3VsZFVzZU1hdANoYXMJdG90YWxOZWVkBARuZWVkCQESZ2V0TmVlZGVkTWF0ZXJpYWxzAQUJdG90YWxOZWVkCgEKc3VidHJhY3RvcgIDYWNjA2lkeAQGcmVzdWx0CQBlAgkBDXBhcnNlSW50VmFsdWUBCQCRAwIFA2hhcwUDaWR4CQCRAwIFBG5lZWQFA2lkeAMJAGYCAAAFBnJlc3VsdAkAAgEJAKwCAgkArAICCQCsAgIJAKwCAgkArAICAhhOb3QgZW5vdWdoIG1hdGVyaWFsIGlkeD0JAKQDAQUDaWR4AgssIHlvdSBoYXZlIAkAkQMCBQNoYXMFA2lkeAILLCBidXQgbmVlZCAJAKQDAQkAkQMCBQRuZWVkBQNpZHgJAM0IAgUDYWNjCQCkAwEFBnJlc3VsdAMFDHNob3VsZFVzZU1hdAoAAiRsCQDMCAIAAAkAzAgCAAEJAMwIAgACCQDMCAIAAwkAzAgCAAQJAMwIAgAFBQNuaWwKAAIkcwkAkAMBBQIkbAoABSRhY2MwBQNuaWwKAQUkZjBfMQICJGECJGkDCQBnAgUCJGkFAiRzBQIkYQkBCnN1YnRyYWN0b3ICBQIkYQkAkQMCBQIkbAUCJGkKAQUkZjBfMgICJGECJGkDCQBnAgUCJGkFAiRzBQIkYQkAAgECE0xpc3Qgc2l6ZSBleGNlZWRzIDYJAQUkZjBfMgIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIFBSRhY2MwAAAAAQACAAMABAAFAAYFA2hhcwEZdXBkYXRlUHJvcG9ydGlvbnNJbnRlcm5hbAQIcHJvcExpc3QNdGVycmFpbkNvdW50cw1sYW5kU2l6ZUluZGV4BHNpZ24DCQECIT0CCQCQAwEFCHByb3BMaXN0BQZOVU1SRVMJAAIBAhZXcm9uZyBwcm9wb3J0aW9ucyBkYXRhCgEHdXBkYXRlcgIDYWNjAWkEBnJlc3VsdAkAZAIJAQ1wYXJzZUludFZhbHVlAQkAkQMCBQhwcm9wTGlzdAUBaQkAaAIJAGgCBQRzaWduCQCRAwIFDXRlcnJhaW5Db3VudHMFAWkFDWxhbmRTaXplSW5kZXgDCQBmAgAABQZyZXN1bHQJAAIBCQCsAgIJAKwCAgkArAICCQCsAgIJAKwCAgkArAICCQCsAgICFlBhbmljISBQaWVjZXMgb2YgdHlwZT0JAKQDAQUBaQIHLCBzaWduPQkApAMBBQRzaWduAhQsICB0ZXJyYWluQ291bnRzW2ldPQkApAMBCQCRAwIFDXRlcnJhaW5Db3VudHMFAWkCECwgbGFuZFNpemVJbmRleD0JAKQDAQUNbGFuZFNpemVJbmRleAkAzQgCBQNhY2MJAKQDAQUGcmVzdWx0BAFyCgACJGwJAMwIAgAACQDMCAIAAQkAzAgCAAIJAMwIAgADCQDMCAIABAkAzAgCAAUFA25pbAoAAiRzCQCQAwEFAiRsCgAFJGFjYzAFA25pbAoBBSRmMF8xAgIkYQIkaQMJAGcCBQIkaQUCJHMFAiRhCQEHdXBkYXRlcgIFAiRhCQCRAwIFAiRsBQIkaQoBBSRmMF8yAgIkYQIkaQMJAGcCBQIkaQUCJHMFAiRhCQACAQITTGlzdCBzaXplIGV4Y2VlZHMgNgkBBSRmMF8yAgkBBSRmMF8xAgkBBSRmMF8xAgkBBSRmMF8xAgkBBSRmMF8xAgkBBSRmMF8xAgkBBSRmMF8xAgUFJGFjYzAAAAABAAIAAwAEAAUABgkAuQkCBQFyAgFfARF1cGRhdGVQcm9wb3J0aW9ucwMNdGVycmFpbkNvdW50cw1sYW5kU2l6ZUluZGV4BHNpZ24ECHByb3BMaXN0CQC1CQIJAQt2YWx1ZU9yRWxzZQIJAKIIAQkBEWtleVJlc1Byb3BvcnRpb25zAAILMF8wXzBfMF8wXzACAV8JARl1cGRhdGVQcm9wb3J0aW9uc0ludGVybmFsBAUIcHJvcExpc3QFDXRlcnJhaW5Db3VudHMFDWxhbmRTaXplSW5kZXgFBHNpZ24BDWNvdW50VGVycmFpbnMBCHRlcnJhaW5zCQDMCAIJAGUCCQCQAwEJALUJAgUIdGVycmFpbnMCAUEAAQkAzAgCCQBlAgkAkAMBCQC1CQIFCHRlcnJhaW5zAgFCAAEJAMwIAgkAZQIJAJADAQkAtQkCBQh0ZXJyYWlucwIBQwABCQDMCAIJAGUCCQCQAwEJALUJAgUIdGVycmFpbnMCAUQAAQkAzAgCCQBlAgkAkAMBCQC1CQIFCHRlcnJhaW5zAgFFAAEJAMwIAgkAZQIJAJADAQkAtQkCBQh0ZXJyYWlucwIBRgABBQNuaWwBD251bVBpZWNlc0J5U2l6ZQEIbGFuZFNpemUEByRtYXRjaDAFCGxhbmRTaXplAwkAAAICAVMFByRtYXRjaDAFBVNTSVpFAwkAAAICAU0FByRtYXRjaDAFBU1TSVpFAwkAAAICAUwFByRtYXRjaDAFBUxTSVpFAwkAAAICAlhMBQckbWF0Y2gwBQZYTFNJWkUDCQAAAgIDWFhMBQckbWF0Y2gwBQdYWExTSVpFCQACAQIRVW5rbm93biBsYW5kIHNpemUBDHN1Yk9uZUluTGlzdAMFYUxpc3QDaWR4BmFtb3VudAoBBnN1YmJlcgIDYWNjAWkJAM0IAgUDYWNjAwkAAAIFAWkFA2lkeAkApAMBCQBlAgkBDXBhcnNlSW50VmFsdWUBCQCRAwIFBWFMaXN0BQFpBQZhbW91bnQJAJEDAgUFYUxpc3QFAWkEAXIKAAIkbAkAzAgCAAAJAMwIAgABCQDMCAIAAgkAzAgCAAMJAMwIAgAECQDMCAIABQUDbmlsCgACJHMJAJADAQUCJGwKAAUkYWNjMAUDbmlsCgEFJGYwXzECAiRhAiRpAwkAZwIFAiRpBQIkcwUCJGEJAQZzdWJiZXICBQIkYQkAkQMCBQIkbAUCJGkKAQUkZjBfMgICJGECJGkDCQBnAgUCJGkFAiRzBQIkYQkAAgECE0xpc3Qgc2l6ZSBleGNlZWRzIDYJAQUkZjBfMgIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIFBSRhY2MwAAAAAQACAAMABAAFAAYJALkJAgUBcgIBXwEGYWRkUmVzBQpjdXJyZW50UmVzDXRlcnJhaW5Db3VudHMJZGVsdGFUaW1lDWxhbmRTaXplSW5kZXgXZGFpbHlCeVBpZWNlV2l0aEJvbnVzZXMKAQVhZGRlcgIDYWNjAWkECXJlc09mVHlwZQkAaAIJAGgCCQBrAwUJZGVsdGFUaW1lBRdkYWlseUJ5UGllY2VXaXRoQm9udXNlcwUJREFZTUlMTElTCQCRAwIFDXRlcnJhaW5Db3VudHMFAWkFDWxhbmRTaXplSW5kZXgJAM0IAgUDYWNjCQCkAwEJAGQCCQENcGFyc2VJbnRWYWx1ZQEJAJEDAgUKY3VycmVudFJlcwUBaQUJcmVzT2ZUeXBlBAFyCgACJGwJAMwIAgAACQDMCAIAAQkAzAgCAAIJAMwIAgADCQDMCAIABAkAzAgCAAUFA25pbAoAAiRzCQCQAwEFAiRsCgAFJGFjYzAFA25pbAoBBSRmMF8xAgIkYQIkaQMJAGcCBQIkaQUCJHMFAiRhCQEFYWRkZXICBQIkYQkAkQMCBQIkbAUCJGkKAQUkZjBfMgICJGECJGkDCQBnAgUCJGkFAiRzBQIkYQkAAgECE0xpc3Qgc2l6ZSBleGNlZWRzIDYJAQUkZjBfMgIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIFBSRhY2MwAAAAAQACAAMABAAFAAYJALkJAgUBcgIBXwEDYWJzAQF4AwkAwAICBQF4CQC2AgEAAAUBeAkAvgIBBQF4AARmcmVxCQDMCAIJAMwIAgABCQDMCAIABAkAzAgCAAkJAMwIAgAKCQDMCAIADwUDbmlsCQDMCAIJAMwIAgAFCQDMCAIACAkAzAgCAA0JAMwIAgAOCQDMCAIADwUDbmlsCQDMCAIJAMwIAgAGCQDMCAIACQkAzAgCAA4JAMwIAgAPCQDMCAIAEAUDbmlsCQDMCAIJAMwIAgAECQDMCAIABwkAzAgCAAgJAMwIAgANCQDMCAIAEgUDbmlsCQDMCAIJAMwIAgABCQDMCAIABgkAzAgCAAcJAMwIAgAPCQDMCAIAEwUDbmlsBQNuaWwBB2dlbkNoYXICAW4FZnJlcXMEA3JlbQkAoAMBCQC7AgIFAW4FB1RXRU5UWVgEBmxldHRlcgMJAGYCCQCRAwIFBWZyZXFzAAAFA3JlbQIBQQMJAGYCCQCRAwIFBWZyZXFzAAEFA3JlbQIBQgMJAGYCCQCRAwIFBWZyZXFzAAIFA3JlbQIBQwMJAGYCCQCRAwIFBWZyZXFzAAMFA3JlbQIBRAMJAGYCCQCRAwIFBWZyZXFzAAQFA3JlbQIBRQIBRgUGbGV0dGVyAQtnZW5UZXJyYWlucwIEc2VlZAxjb250aW5lbnRJZHgEAWYJAJEDAgUEZnJlcQUMY29udGluZW50SWR4CgEQdGVycmFpbkdlbmVyYXRvcgIDYWNjBGVsZW0JAJQKAgkArAICCQCsAgIJAKwCAgkArAICCQCsAgIIBQNhY2MCXzEJAQdnZW5DaGFyAggFA2FjYwJfMgUBZgkBB2dlbkNoYXICCQC6AgIIBQNhY2MCXzIFB1RXRU5UWVgFAWYJAQdnZW5DaGFyAgkAugICCAUDYWNjAl8yBQhUV0VOVFkyWAUBZgkBB2dlbkNoYXICCQC6AgIIBQNhY2MCXzIFCFRXRU5UWTNYBQFmCQEHZ2VuQ2hhcgIJALoCAggFA2FjYwJfMgUIVFdFTlRZNFgFAWYJALoCAggFA2FjYwJfMgUIVFdFTlRZNVgEAXQKAAIkbAkAzAgCAAEJAMwIAgACCQDMCAIAAwkAzAgCAAQJAMwIAgAFBQNuaWwKAAIkcwkAkAMBBQIkbAoABSRhY2MwCQCUCgICAAkAugICBQRzZWVkBQVGSVZFWAoBBSRmMF8xAgIkYQIkaQMJAGcCBQIkaQUCJHMFAiRhCQEQdGVycmFpbkdlbmVyYXRvcgIFAiRhCQCRAwIFAiRsBQIkaQoBBSRmMF8yAgIkYQIkaQMJAGcCBQIkaQUCJHMFAiRhCQACAQITTGlzdCBzaXplIGV4Y2VlZHMgNQkBBSRmMF8yAgkBBSRmMF8xAgkBBSRmMF8xAgkBBSRmMF8xAgkBBSRmMF8xAgkBBSRmMF8xAgUFJGFjYzAAAAABAAIAAwAEAAUIBQF0Al8xAQtnZXRCYWNrcGFjawEFYnBLZXkEAXAJALUJAgkBC3ZhbHVlT3JFbHNlAgkAoggBBQVicEtleQIaMDowXzBfMF8wXzBfMDowXzBfMF8wXzBfMDoCAToJAMwIAgkApAMBCQELdmFsdWVPckVsc2UCCQC2CQEJAJEDAgUBcAUKYnBJZHhMZXZlbAAACQDMCAIDCQAAAgkAkAMBCQC1CQIJAJEDAgUBcAUIYnBJZHhSZXMCAV8FBk5VTVJFUwkAkQMCBQFwBQhicElkeFJlcwILMF8wXzBfMF8wXzAJAMwIAgMJAAACCQCQAwEJALUJAgkAkQMCBQFwBQhicElkeE1hdAIBXwUGTlVNUkVTCQCRAwIFAXAFCGJwSWR4TWF0AgswXzBfMF8wXzBfMAkAzAgCCQCRAwIFAXAFCWJwSWR4UHJvZAUDbmlsARBleHBlZGl0aW9uQ29tbW9uBQxzaG91bGRVc2VNYXQGY2FsbGVyBHR4SWQHbWVzc2FnZQNzaWcDCQEBIQEJAMQTAwUHbWVzc2FnZQUDc2lnBQNwdWIJAAIBAhhzaWduYXR1cmUgZG9lcyBub3QgbWF0Y2gEBXBhcnRzCQC1CQIJALAJAQUHbWVzc2FnZQIBOwQCaHAJALUJAgkAkQMCCQC1CQIJAJEDAgUFcGFydHMAAAIBfAAAAgFfBAVjdXJIUAkBDXBhcnNlSW50VmFsdWUBCQCRAwIFAmhwAAAEBW5ld0hQCQENcGFyc2VJbnRWYWx1ZQEJAJEDAgUCaHAAAQQKbG9jQW5kVGltZQkAtQkCCQCRAwIFBXBhcnRzAAECAToEDnRhcmdldExvY2F0aW9uCQC1CQIJAJEDAgUKbG9jQW5kVGltZQAAAgFfAwkBAiE9AgkAkQMCBQ50YXJnZXRMb2NhdGlvbgABAgFFCQACAQIrZXhwZWRpdGlvbiB0YXJnZXQgbG9jYXRpb24gdHlwZSBzaG91bGQgYmUgRQQEdGltZQkBDXBhcnNlSW50VmFsdWUBCQCRAwIFCmxvY0FuZFRpbWUAAQMDCQBmAgUEdGltZQkAZAIIBQlsYXN0QmxvY2sJdGltZXN0YW1wBRFGSVZFTUlOVVRFU01JTExJUwYJAGYCCQBlAggFCWxhc3RCbG9jawl0aW1lc3RhbXAFEUZJVkVNSU5VVEVTTUlMTElTBQR0aW1lCQACAQISc2lnbmF0dXJlIG91dGRhdGVkBAh1c2VyQWRkcgkApQgBBQZjYWxsZXIEC2R1Y2tBc3NldElkCQETdmFsdWVPckVycm9yTWVzc2FnZQIJAKIIAQkBFGtleVN0YWtlZER1Y2tCeU93bmVyAQUIdXNlckFkZHICHFlvdSBkb24ndCBoYXZlIGEgZHVjayBzdGFrZWQECWtleUhlYWx0aAkBDWtleUR1Y2tIZWFsdGgBBQtkdWNrQXNzZXRJZAQMb2xkRnJvbVN0YXRlCQELdmFsdWVPckVsc2UCCQCfCAEFCWtleUhlYWx0aABkAwkBAiE9AgUMb2xkRnJvbVN0YXRlBQVjdXJIUAkAAgEJAKwCAgkArAICCQCsAgICCm9sZEhlYWx0aD0JAKQDAQkBC3ZhbHVlT3JFbHNlAgkAnwgBBQlrZXlIZWFsdGgAZAIvIGZyb20gc3RhdGUgZG9lcyBub3QgbWF0Y2ggb25lIGZyb20gZmxpZ2h0IGxvZz0JAKQDAQUFY3VySFADCQBnAgAABQVjdXJIUAkAAgECHllvdSBjYW4ndCBmbHkgd2l0aCB6ZXJvIGhlYWx0aAMJAGcCAAAFBW5ld0hQCQCUCgIJAM0IAgMJAQEhAQUMc2hvdWxkVXNlTWF0CQDMCAIJAQ5TY3JpcHRUcmFuc2ZlcgMFBmNhbGxlcgUHRVhQVVNETgULdXNkbkFzc2V0SWQFA25pbAUDbmlsCQEMSW50ZWdlckVudHJ5AgUJa2V5SGVhbHRoAAACAAQFYnBLZXkJARFrZXlCYWNrcGFja0J5RHVjawEFC2R1Y2tBc3NldElkBAtjdXJyZW50UGFjawkBC2dldEJhY2twYWNrAQUFYnBLZXkEBW1MaXN0CQC1CQIJAJEDAgULY3VycmVudFBhY2sFCGJwSWR4TWF0AgFfBAZuZXdNYXQJALkJAgkBEXN1YnRyYWN0TWF0ZXJpYWxzAwUMc2hvdWxkVXNlTWF0BQVtTGlzdAUMRVhQTUFURVJJQUxTAgFfBAZiaWdOdW0JAQNhYnMBCQCeAwEFBHR4SWQEB2ZyZWVOdW0JAQt2YWx1ZU9yRWxzZQIJAJ8IAQkBEmtleU5leHRGcmVlTGFuZE51bQAJAGQCBQ9QUkVTQUxFTlVNTEFORFMAAQQHbGFuZE51bQkApAMBBQdmcmVlTnVtBAxjb250aW5lbnRJZHgJAKADAQkAuwICBQZiaWdOdW0FBUZJVkVYBAh0ZXJyYWlucwkBC2dlblRlcnJhaW5zAgUGYmlnTnVtBQxjb250aW5lbnRJZHgECWNvbnRpbmVudAkAkQMCBQpjb250aW5lbnRzBQxjb250aW5lbnRJZHgEBWlzc3VlCQDCCAUJAQprZXlOZnROYW1lAgUHbGFuZE51bQIBUwkAuQkCCQDMCAIFB2xhbmROdW0JAMwIAgIBUwkAzAgCBQh0ZXJyYWlucwkAzAgCBQljb250aW5lbnQFA25pbAIBXwABAAAHBAdhc3NldElkCQC4CAEFBWlzc3VlBAJpZAkA2AQBBQdhc3NldElkCQCUCgIJAMwIAgkBDEludGVnZXJFbnRyeQIJARJrZXlOZXh0RnJlZUxhbmROdW0ACQBkAgUHZnJlZU51bQABCQDMCAIFBWlzc3VlCQDMCAIJAQtTdHJpbmdFbnRyeQIJARBrZXlMYW5kVG9Bc3NldElkAQUHbGFuZE51bQUCaWQJAMwIAgkBC1N0cmluZ0VudHJ5AgkBFWtleUxhbmRBc3NldElkVG9Pd25lcgEFAmlkBQh1c2VyQWRkcgkAzAgCCQELU3RyaW5nRW50cnkCCQERa2V5TGFuZE51bVRvT3duZXIBBQdsYW5kTnVtBQh1c2VyQWRkcgkAzAgCCQEMSW50ZWdlckVudHJ5AgkBFmtleUluZnJhTGV2ZWxCeUFzc2V0SWQBBQJpZAAACQDMCAIJAQxJbnRlZ2VyRW50cnkCCQEea2V5SW5mcmFMZXZlbEJ5QXNzZXRJZEFuZE93bmVyAgUCaWQFCHVzZXJBZGRyAAAJAMwIAgkBDlNjcmlwdFRyYW5zZmVyAwUGY2FsbGVyAAEFB2Fzc2V0SWQJAMwIAgkBC1N0cmluZ0VudHJ5AgkBD2tleUR1Y2tMb2NhdGlvbgEFC2R1Y2tBc3NldElkCQC5CQIJAMwIAgUJY29udGluZW50CQDMCAICAUwJAMwIAgUCaWQFA25pbAIBXwkAzAgCCQEMSW50ZWdlckVudHJ5AgUJa2V5SGVhbHRoBQVuZXdIUAkAzAgCCQELU3RyaW5nRW50cnkCBQVicEtleQkAuQkCCQDMCAIJAJEDAgULY3VycmVudFBhY2sFCmJwSWR4TGV2ZWwJAMwIAgkAkQMCBQtjdXJyZW50UGFjawUIYnBJZHhSZXMJAMwIAgUGbmV3TWF0CQDMCAIJAJEDAgULY3VycmVudFBhY2sFCWJwSWR4UHJvZAUDbmlsAgE6BQNuaWwFAmlkAQxhcHBseUJvbnVzZXMCC2xhbmRBc3NldElkBnBpZWNlcwQKaW5mcmFMZXZlbAkBC3ZhbHVlT3JFbHNlAgkAnwgBCQEWa2V5SW5mcmFMZXZlbEJ5QXNzZXRJZAEFC2xhbmRBc3NldElkAAAECWFydFBpZWNlcwkBC3ZhbHVlT3JFbHNlAgkAnwgBCQEga2V5TGFuZEFydFN0YXR1c0J5VHlwZUFuZEFzc2V0SWQCBQpBUlRQUkVTQUxFBQtsYW5kQXNzZXRJZAMJAQt2YWx1ZU9yRWxzZQIJAKAIAQkBH2tleVByZXNhbGVBcnRBY3RpdmF0ZWRCeUFzc2V0SWQBBQtsYW5kQXNzZXRJZAcFBnBpZWNlcwAACQBkAgkAZAIFD0RBSUxZUkVTQllQSUVDRQkAawMFD0RBSUxZUkVTQllQSUVDRQUKaW5mcmFMZXZlbAAECQBrAwUPREFJTFlSRVNCWVBJRUNFCQBoAgUJYXJ0UGllY2VzAAMJAGgCBQZwaWVjZXMAFAEUY2hlY2tDbGFpbUNvbmRpdGlvbnMBBGFkZHIEC2R1Y2tBc3NldElkCQETdmFsdWVPckVycm9yTWVzc2FnZQIJAKIIAQkBFGtleVN0YWtlZER1Y2tCeU93bmVyAQUEYWRkcgIcWW91IGRvbid0IGhhdmUgYSBkdWNrIHN0YWtlZAQLY3VyTG9jYXRpb24JAQt2YWx1ZU9yRWxzZQIJAKIIAQkBD2tleUR1Y2tMb2NhdGlvbgEFC2R1Y2tBc3NldElkBQ9ERUZBVUxUTE9DQVRJT04EA2xvYwkAtQkCCQEFdmFsdWUBBQtjdXJMb2NhdGlvbgIBXwMJAQIhPQIJAJEDAgUDbG9jBQpsb2NJZHhUeXBlAgFMCQACAQkArAICCQCsAgICFkR1Y2sgbG9jYXRpb24gdHlwZSBpcyAJAJEDAgUDbG9jBQpsb2NJZHhUeXBlAhEsIGJ1dCBzaG91bGQgYmUgTAQLbGFuZEFzc2V0SWQJAJEDAgUDbG9jBQhsb2NJZHhJZAQFYXNzZXQJAQV2YWx1ZQEJAOwHAQkA2QQBBQtsYW5kQXNzZXRJZAQHdGltZUtleQkBFmtleVN0YWtlZFRpbWVCeUFzc2V0SWQBBQtsYW5kQXNzZXRJZAQJc2F2ZWRUaW1lCQETdmFsdWVPckVycm9yTWVzc2FnZQIJAJ8IAQUHdGltZUtleQkArAICCQCsAgICEFlvdXIgZHVjayBpcyBvbiAIBQVhc3NldARuYW1lAhUsIHdoaWNoIGlzIG5vdCBzdGFrZWQEBW93bmVyCQETdmFsdWVPckVycm9yTWVzc2FnZQIJAKIIAQkBFWtleUxhbmRBc3NldElkVG9Pd25lcgEFC2xhbmRBc3NldElkCQCsAgIJAKwCAgIETkZUIAgFBWFzc2V0BG5hbWUCDCBpcyBvcnBoYW5lZAMJAQIhPQIFBW93bmVyBQRhZGRyCQACAQkArAICBQpMQU5EUFJFRklYAg0gaXMgbm90IHlvdXJzBAFkCQC1CQIIBQVhc3NldAtkZXNjcmlwdGlvbgIBXwkAlgoEBQtkdWNrQXNzZXRJZAULbGFuZEFzc2V0SWQFAWQFCXNhdmVkVGltZQEQY2xhaW1SZXNJbnRlcm5hbAIEYWRkcgZhbW91bnQDCQBmAgAABQZhbW91bnQJAAIBAg9OZWdhdGl2ZSBhbW91bnQEAWMJARRjaGVja0NsYWltQ29uZGl0aW9ucwEFBGFkZHIECGxhbmRTaXplCQCRAwIIBQFjAl8zBQtyZWNMYW5kU2l6ZQQNdGVycmFpbkNvdW50cwkBDWNvdW50VGVycmFpbnMBCQCRAwIIBQFjAl8zBQtyZWNUZXJyYWlucwQJZGVsdGFUaW1lCQBlAggFCWxhc3RCbG9jawl0aW1lc3RhbXAIBQFjAl80AwkAZgIAAAUJZGVsdGFUaW1lCQACAQkArAICCQCsAgIJAKwCAgImU2F2ZWQgdGltZXN0YW1wIGlzIGluIGZ1dHVyZSwgc2F2ZWQgPSAJAKQDAQgFAWMCXzQCDCwgY3VycmVudCA9IAkApAMBCAUJbGFzdEJsb2NrCXRpbWVzdGFtcAQGcGllY2VzCQEPbnVtUGllY2VzQnlTaXplAQUIbGFuZFNpemUEFmRhaWx5UHJvZHVjdGlvbkJ5UGllY2UJAQxhcHBseUJvbnVzZXMCCAUBYwJfMgUGcGllY2VzBAhhdmFpbFJlcwkAawMFCWRlbHRhVGltZQkAaAIFFmRhaWx5UHJvZHVjdGlvbkJ5UGllY2UFBnBpZWNlcwUJREFZTUlMTElTAwkAZgIFBmFtb3VudAUIYXZhaWxSZXMJAAIBCQCsAgIJAKwCAgkArAICAiJOb3QgZW5vdWdoIHJlc291cmNlcywgYXZhaWxhYmxlID0gCQCkAwEFCGF2YWlsUmVzAg4sIHJlcXVlc3RlZCA9IAkApAMBBQZhbW91bnQEDG5ld0RlbHRhVGltZQkAawMJAGUCBQhhdmFpbFJlcwUGYW1vdW50BQlEQVlNSUxMSVMJAGgCBRZkYWlseVByb2R1Y3Rpb25CeVBpZWNlBQZwaWVjZXMEDG5ld1RpbWVzdGFtcAkAZQIIBQlsYXN0QmxvY2sJdGltZXN0YW1wBQxuZXdEZWx0YVRpbWUEBWJwS2V5CQERa2V5QmFja3BhY2tCeUR1Y2sBCAUBYwJfMQQLY3VycmVudFBhY2sJAQtnZXRCYWNrcGFjawEFBWJwS2V5BApjdXJyZW50UmVzCQC1CQIJAJEDAgULY3VycmVudFBhY2sFCGJwSWR4UmVzAgFfBAVicFJlcwkBBmFkZFJlcwUFCmN1cnJlbnRSZXMFDXRlcnJhaW5Db3VudHMJAGUCBQlkZWx0YVRpbWUFDG5ld0RlbHRhVGltZQkAaQIFBnBpZWNlcwUFU1NJWkUFFmRhaWx5UHJvZHVjdGlvbkJ5UGllY2UJAJUKAwkAzAgCCQEMSW50ZWdlckVudHJ5AgkBFmtleVN0YWtlZFRpbWVCeUFzc2V0SWQBCAUBYwJfMgUMbmV3VGltZXN0YW1wCQDMCAIJAQxJbnRlZ2VyRW50cnkCCQEia2V5U3Rha2VkVGltZUJ5VHlwZUFzc2V0SWRBbmRPd25lcgMFCkxBTkRQUkVGSVgIBQFjAl8yBQRhZGRyBQxuZXdUaW1lc3RhbXAFA25pbAUFYnBLZXkJAMwIAgkAkQMCBQtjdXJyZW50UGFjawUKYnBJZHhMZXZlbAkAzAgCBQVicFJlcwkAzAgCCQCRAwIFC2N1cnJlbnRQYWNrBQhicElkeE1hdAkAzAgCCQCRAwIFC2N1cnJlbnRQYWNrBQlicElkeFByb2QFA25pbAEIY2xhaW1BbGwDBGFkZHILbGFuZEFzc2V0SWQGcGllY2VzBAd0aW1lS2V5CQEWa2V5U3Rha2VkVGltZUJ5QXNzZXRJZAEFC2xhbmRBc3NldElkBAlzYXZlZFRpbWUJAQV2YWx1ZQEJAJ8IAQUHdGltZUtleQQIYXZhaWxSZXMJAGgCCQBrAwkAZQIIBQlsYXN0QmxvY2sJdGltZXN0YW1wBQlzYXZlZFRpbWUJAQxhcHBseUJvbnVzZXMCBQtsYW5kQXNzZXRJZAUGcGllY2VzBQlEQVlNSUxMSVMFBnBpZWNlcwkBEGNsYWltUmVzSW50ZXJuYWwCBQRhZGRyBQhhdmFpbFJlcwENdXBJbmZyYUNvbW1vbgMMc2hvdWxkVXNlTWF0BmNhbGxlcg1wYXltZW50QW1vdW50BARhZGRyCQClCAEFBmNhbGxlcgQBYwkBFGNoZWNrQ2xhaW1Db25kaXRpb25zAQUEYWRkcgQGcGllY2VzCQEPbnVtUGllY2VzQnlTaXplAQkAkQMCCAUBYwJfMwULcmVjTGFuZFNpemUECGluZnJhS2V5CQEWa2V5SW5mcmFMZXZlbEJ5QXNzZXRJZAEIBQFjAl8yBAhjdXJMZXZlbAkBC3ZhbHVlT3JFbHNlAgkAnwgBBQhpbmZyYUtleQAAAwkAZwIFCGN1ckxldmVsAAMJAAIBAiZDdXJyZW50bHkgbWF4IGluZnJhc3RydWN0dXJlIGxldmVsID0gMwQIbmV3TGV2ZWwJAGQCBQhjdXJMZXZlbAABBARjb3N0CQBrAwUVSW5mcmFVcGdyYWRlQ29zdFNVc2RuCQBoAgUGcGllY2VzBQhuZXdMZXZlbAUFU1NJWkUDAwkBASEBBQxzaG91bGRVc2VNYXQJAQIhPQIFDXBheW1lbnRBbW91bnQFBGNvc3QHCQACAQkArAICAhtQYXltZW50IGF0dGFjaGVkIHNob3VsZCBiZSAJAKQDAQUEY29zdAQFYnBLZXkJARFrZXlCYWNrcGFja0J5RHVjawEIBQFjAl8xBAtjdXJyZW50UGFjawkBC2dldEJhY2twYWNrAQUFYnBLZXkEBW1MaXN0CQC1CQIJAJEDAgULY3VycmVudFBhY2sFCGJwSWR4TWF0AgFfBAZuZXdNYXQJALkJAgkBEXN1YnRyYWN0TWF0ZXJpYWxzAwUMc2hvdWxkVXNlTWF0BQVtTGlzdAkAawMFEUluZnJhVXBncmFkZUNvc3RTCQBoAgUGcGllY2VzBQhuZXdMZXZlbAUFU1NJWkUCAV8EC2NsYWltUmVzdWx0CQEIY2xhaW1BbGwDBQRhZGRyCAUBYwJfMgUGcGllY2VzCQCUCgIJAM4IAgkAzAgCCQEMSW50ZWdlckVudHJ5AgUIaW5mcmFLZXkFCG5ld0xldmVsCQDMCAIJAQxJbnRlZ2VyRW50cnkCCQEea2V5SW5mcmFMZXZlbEJ5QXNzZXRJZEFuZE93bmVyAggFAWMCXzIFBGFkZHIFCG5ld0xldmVsCQDMCAIJAQtTdHJpbmdFbnRyeQIFBWJwS2V5CQC5CQIJAMwIAgkAkQMCBQtjdXJyZW50UGFjawUKYnBJZHhMZXZlbAkAzAgCCQCRAwIIBQtjbGFpbVJlc3VsdAJfMwUIYnBJZHhSZXMJAMwIAgUGbmV3TWF0CQDMCAIJAJEDAgULY3VycmVudFBhY2sFCWJwSWR4UHJvZAUDbmlsAgE6BQNuaWwIBQtjbGFpbVJlc3VsdAJfMQUIbmV3TGV2ZWwBEmFjdGl2YXRlUHJlc2FsZUFydAEEYWRkcgQBYwkBFGNoZWNrQ2xhaW1Db25kaXRpb25zAQUEYWRkcgQLbGFuZEFzc2V0SWQIBQFjAl8yBA1hY3RpdmF0aW9uS2V5CQEfa2V5UHJlc2FsZUFydEFjdGl2YXRlZEJ5QXNzZXRJZAEFC2xhbmRBc3NldElkAwkBC3ZhbHVlT3JFbHNlAgkAoAgBBQ1hY3RpdmF0aW9uS2V5BwkAAgECJVByZXNhbGUgYXJ0aWZhY3QgaXMgYWxyZWFkeSBhY3RpdmF0ZWQDCQBmAgkBDXBhcnNlSW50VmFsdWUBCQCRAwIIBQFjAl8zBQpyZWNMYW5kTnVtBQ9QUkVTQUxFTlVNTEFORFMJAAIBCQCsAgIJAKwCAgkArAICBQpMQU5EUFJFRklYAgEgBQtsYW5kQXNzZXRJZAIlIGlzIG5vdCBlbGlnaWJsZSBmb3IgcHJlc2FsZSBhcnRpZmFjdAQGcGllY2VzCQEPbnVtUGllY2VzQnlTaXplAQkAkQMCCAUBYwJfMwULcmVjTGFuZFNpemUEC2NsYWltUmVzdWx0CQEIY2xhaW1BbGwDBQRhZGRyBQtsYW5kQXNzZXRJZAUGcGllY2VzCQDNCAIJAM0IAgkAzQgCCQDNCAIJAM0IAggFC2NsYWltUmVzdWx0Al8xCQEMQm9vbGVhbkVudHJ5AgUNYWN0aXZhdGlvbktleQYJAQxCb29sZWFuRW50cnkCCQEna2V5UHJlc2FsZUFydEFjdGl2YXRlZEJ5QXNzZXRJZEFuZE93bmVyAgULbGFuZEFzc2V0SWQFBGFkZHIGCQEMSW50ZWdlckVudHJ5AgkBIGtleUxhbmRBcnRTdGF0dXNCeVR5cGVBbmRBc3NldElkAgUKQVJUUFJFU0FMRQULbGFuZEFzc2V0SWQFBnBpZWNlcwkBDEludGVnZXJFbnRyeQIJASVrZXlMYW5kQXJ0U3RhdHVzQnlUeXBlQXNzZXRJZEFuZE93bmVyAwUKQVJUUFJFU0FMRQULbGFuZEFzc2V0SWQFBGFkZHIFBnBpZWNlcwkBC1N0cmluZ0VudHJ5AggFC2NsYWltUmVzdWx0Al8yCQC5CQIIBQtjbGFpbVJlc3VsdAJfMwIBOgENbWVyZ2VJbnRlcm5hbAcLbmV3TGFuZFNpemUIbmV3TGV2ZWwHZm9ybXVsYQRhZGRyDGxhbmRBc3NldElkcwR0eElkB25lZWRNYXQEC2R1Y2tBc3NldElkCQETdmFsdWVPckVycm9yTWVzc2FnZQIJAKIIAQkBFGtleVN0YWtlZER1Y2tCeU93bmVyAQUEYWRkcgIcWW91IGRvbid0IGhhdmUgYSBkdWNrIHN0YWtlZAoBCmNoZWNrTWVyZ2UCA2FjYwtsYW5kQXNzZXRJZAQFYXNzZXQJAQV2YWx1ZQEJAOwHAQkA2QQBBQtsYW5kQXNzZXRJZAQHdGltZUtleQkBFmtleVN0YWtlZFRpbWVCeUFzc2V0SWQBBQtsYW5kQXNzZXRJZAQJc2F2ZWRUaW1lCQETdmFsdWVPckVycm9yTWVzc2FnZQIJAJ8IAQUHdGltZUtleQkArAICCQCsAgICBE5GVCAIBQVhc3NldARuYW1lAg4gaXMgbm90IHN0YWtlZAQFb3duZXIJARN2YWx1ZU9yRXJyb3JNZXNzYWdlAgkAoggBCQEVa2V5TGFuZEFzc2V0SWRUb093bmVyAQULbGFuZEFzc2V0SWQJAKwCAgkArAICAgRORlQgCAUFYXNzZXQEbmFtZQIMIGlzIG9ycGhhbmVkAwkBAiE9AgUFb3duZXIFBGFkZHIJAAIBCQCsAgIFCkxBTkRQUkVGSVgCDSBpcyBub3QgeW91cnMEAWQJALUJAggFBWFzc2V0C2Rlc2NyaXB0aW9uAgFfBAljb250aW5lbnQJAJEDAgUBZAUMcmVjQ29udGluZW50AwMJAQIhPQIIBQNhY2MCXzMCAAkBAiE9AggFA2FjYwJfMwUJY29udGluZW50BwkAAgECLkxhbmRzIHNob3VsZCBiZSBvbiB0aGUgc2FtZSBjb250aW5lbnQgdG8gbWVyZ2UECGxhbmRTaXplCQCRAwIFAWQFC3JlY0xhbmRTaXplBAdzaXplc0luCAUDYWNjAl8xBAFpCQETdmFsdWVPckVycm9yTWVzc2FnZQIJALMJAgUHc2l6ZXNJbgUIbGFuZFNpemUCJ1lvdSBoYXZlbid0IHBhc3NlZCBhbGwgdGhlIGxhbmRzIG5lZWRlZAQIc2l6ZXNPdXQJAKwCAgkArwICBQdzaXplc0luBQFpCQCwAgIFB3NpemVzSW4JAGQCBQFpAAEEBnBpZWNlcwkBD251bVBpZWNlc0J5U2l6ZQEFCGxhbmRTaXplBARhcnRzCQBkAggFA2FjYwJfMgkBC3ZhbHVlT3JFbHNlAgkAnwgBCQEga2V5TGFuZEFydFN0YXR1c0J5VHlwZUFuZEFzc2V0SWQCBQpBUlRQUkVTQUxFBQtsYW5kQXNzZXRJZAMJAQt2YWx1ZU9yRWxzZQIJAKAIAQkBH2tleVByZXNhbGVBcnRBY3RpdmF0ZWRCeUFzc2V0SWQBBQtsYW5kQXNzZXRJZAcFBnBpZWNlcwAABAppbmZyYUxldmVsCQELdmFsdWVPckVsc2UCCQCfCAEJARZrZXlJbmZyYUxldmVsQnlBc3NldElkAQULbGFuZEFzc2V0SWQAAAQIcmVxTGV2ZWwEByRtYXRjaDAFCGxhbmRTaXplAwkAAAICAVMFByRtYXRjaDAAAwMJAAACAgFNBQckbWF0Y2gwAAQDCQAAAgIBTAUHJG1hdGNoMAAFAwkAAAICAlhMBQckbWF0Y2gwAAYJAAIBAhpPbmx5IFMsIE0sIEwsIFhMIGNhbiBtZXJnZQMJAQIhPQIFCmluZnJhTGV2ZWwFCHJlcUxldmVsCQACAQIiQWxsIGxhbmRzIHNob3VsZCBiZSBtYXhlZCB0byBtZXJnZQQHbGFuZE51bQkAkQMCBQFkBQpyZWNMYW5kTnVtBA10ZXJyYWluQ291bnRzCQENY291bnRUZXJyYWlucwEJAJEDAgUBZAULcmVjVGVycmFpbnMECWRlbHRhVGltZQkAZQIIBQlsYXN0QmxvY2sJdGltZXN0YW1wBQlzYXZlZFRpbWUDCQBmAgAABQlkZWx0YVRpbWUJAAIBCQCsAgIJAKwCAgkArAICAiZTYXZlZCB0aW1lc3RhbXAgaXMgaW4gZnV0dXJlLCBzYXZlZCA9IAkApAMBBQlzYXZlZFRpbWUCDCwgY3VycmVudCA9IAkApAMBCAUJbGFzdEJsb2NrCXRpbWVzdGFtcAQWZGFpbHlQcm9kdWN0aW9uQnlQaWVjZQkBDGFwcGx5Qm9udXNlcwIFC2xhbmRBc3NldElkBQZwaWVjZXMEBWJwUmVzCQEGYWRkUmVzBQkAtQkCCAUDYWNjAl80AgFfBQ10ZXJyYWluQ291bnRzBQlkZWx0YVRpbWUJAGkCBQZwaWVjZXMFBVNTSVpFBRZkYWlseVByb2R1Y3Rpb25CeVBpZWNlBAVwcm9wcwkBGXVwZGF0ZVByb3BvcnRpb25zSW50ZXJuYWwECQC1CQIIBQNhY2MCXzYCAV8FDXRlcnJhaW5Db3VudHMJAGkCBQZwaWVjZXMFBVNTSVpFAP///////////wEEBWxhbmRzCAUDYWNjAl83BANpZHgJAM8IAgUFbGFuZHMFC2xhbmRBc3NldElkAwkBASEBCQEJaXNEZWZpbmVkAQUDaWR4CQACAQkArAICAiBZb3VyIHN0YWtlZCBsYW5kcyBkb24ndCBjb250YWluIAULbGFuZEFzc2V0SWQJAJkKBwUIc2l6ZXNPdXQFBGFydHMFCWNvbnRpbmVudAUFYnBSZXMJAM0IAgkAzQgCCQDNCAIJAM0IAgkAzQgCCQDNCAIJAM0IAgkAzQgCCQDNCAIJAM0IAgkAzQgCCQDNCAIJAM0IAggFA2FjYwJfNQkBC0RlbGV0ZUVudHJ5AQkBFmtleVN0YWtlZFRpbWVCeUFzc2V0SWQBBQtsYW5kQXNzZXRJZAkBC0RlbGV0ZUVudHJ5AQkBImtleVN0YWtlZFRpbWVCeVR5cGVBc3NldElkQW5kT3duZXIDBQpMQU5EUFJFRklYBQtsYW5kQXNzZXRJZAUEYWRkcgkBC0RlbGV0ZUVudHJ5AQkBEGtleUxhbmRUb0Fzc2V0SWQBBQdsYW5kTnVtCQELRGVsZXRlRW50cnkBCQEKa2V5TmZ0TmFtZQIFB2xhbmROdW0FCGxhbmRTaXplCQELRGVsZXRlRW50cnkBCQEVa2V5TGFuZEFzc2V0SWRUb093bmVyAQULbGFuZEFzc2V0SWQJAQtEZWxldGVFbnRyeQEJARZrZXlJbmZyYUxldmVsQnlBc3NldElkAQULbGFuZEFzc2V0SWQJAQtEZWxldGVFbnRyeQEJAR5rZXlJbmZyYUxldmVsQnlBc3NldElkQW5kT3duZXICBQtsYW5kQXNzZXRJZAUEYWRkcgkBC0RlbGV0ZUVudHJ5AQkBH2tleVByZXNhbGVBcnRBY3RpdmF0ZWRCeUFzc2V0SWQBBQtsYW5kQXNzZXRJZAkBC0RlbGV0ZUVudHJ5AQkBJ2tleVByZXNhbGVBcnRBY3RpdmF0ZWRCeUFzc2V0SWRBbmRPd25lcgIFC2xhbmRBc3NldElkBQRhZGRyCQELRGVsZXRlRW50cnkBCQEga2V5TGFuZEFydFN0YXR1c0J5VHlwZUFuZEFzc2V0SWQCBQpBUlRQUkVTQUxFBQtsYW5kQXNzZXRJZAkBC0RlbGV0ZUVudHJ5AQkBJWtleUxhbmRBcnRTdGF0dXNCeVR5cGVBc3NldElkQW5kT3duZXIDBQpBUlRQUkVTQUxFBQtsYW5kQXNzZXRJZAUEYWRkcgkBC0RlbGV0ZUVudHJ5AQkBEWtleUxhbmROdW1Ub093bmVyAQUHbGFuZE51bQkBBEJ1cm4CCQDZBAEFC2xhbmRBc3NldElkAAEFBXByb3BzCQDRCAIFBWxhbmRzCQEFdmFsdWUBBQNpZHgEBWJwS2V5CQERa2V5QmFja3BhY2tCeUR1Y2sBBQtkdWNrQXNzZXRJZAQLY3VycmVudFBhY2sJAQtnZXRCYWNrcGFjawEFBWJwS2V5BAdwcm9wU3RyCQELdmFsdWVPckVsc2UCCQCiCAEJARFrZXlSZXNQcm9wb3J0aW9ucwACCzBfMF8wXzBfMF8wBAhsYW5kc0tleQkBFWtleVN0YWtlZExhbmRzQnlPd25lcgEFBGFkZHIEB2xhbmRzSW4JAL0JAgkBC3ZhbHVlT3JFbHNlAgkAoggBBQhsYW5kc0tleQIAAgFfBAFyCgACJGwFDGxhbmRBc3NldElkcwoAAiRzCQCQAwEFAiRsCgAFJGFjYzAJAJkKBwUHZm9ybXVsYQAAAgAJAJEDAgULY3VycmVudFBhY2sFCGJwSWR4UmVzBQNuaWwFB3Byb3BTdHIFB2xhbmRzSW4KAQUkZjBfMQICJGECJGkDCQBnAgUCJGkFAiRzBQIkYQkBCmNoZWNrTWVyZ2UCBQIkYQkAkQMCBQIkbAUCJGkKAQUkZjBfMgICJGECJGkDCQBnAgUCJGkFAiRzBQIkYQkAAgECE0xpc3Qgc2l6ZSBleGNlZWRzIDUJAQUkZjBfMgIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIFBSRhY2MwAAAAAQACAAMABAAFBAljb250aW5lbnQIBQFyAl8zBAxjb250aW5lbnRJZHgJARN2YWx1ZU9yRXJyb3JNZXNzYWdlAgkAzwgCBQpjb250aW5lbnRzBQljb250aW5lbnQJAKwCAgITVW5rbm93biBjb250aW5lbnQ6IAUJY29udGluZW50BAh0ZXJyYWlucwkBC2dlblRlcnJhaW5zAgkBA2FicwEJAJ4DAQUEdHhJZAUMY29udGluZW50SWR4BAdmcmVlTnVtCQELdmFsdWVPckVsc2UCCQCfCAEJARJrZXlOZXh0RnJlZUxhbmROdW0ACQBkAgUPUFJFU0FMRU5VTUxBTkRTAAEECm5ld0xhbmROdW0JAKQDAQUHZnJlZU51bQQFaXNzdWUJAMIIBQkBCmtleU5mdE5hbWUCBQpuZXdMYW5kTnVtBQtuZXdMYW5kU2l6ZQkAuQkCCQDMCAIFCm5ld0xhbmROdW0JAMwIAgULbmV3TGFuZFNpemUJAMwIAgUIdGVycmFpbnMJAMwIAgUJY29udGluZW50BQNuaWwCAV8AAQAABwQHYXNzZXRJZAkAuAgBBQVpc3N1ZQQObmV3TGFuZEFzc2V0SWQJANgEAQUHYXNzZXRJZAQGbmV3TWF0CQC5CQIJARFzdWJ0cmFjdE1hdGVyaWFscwMJAGYCBQduZWVkTWF0AAAJALUJAgkAkQMCBQtjdXJyZW50UGFjawUIYnBJZHhNYXQCAV8FB25lZWRNYXQCAV8JAJQKAgkAzQgCCQDNCAIJAM0IAgkAzQgCCQDNCAIJAM0IAgkAzQgCCQDNCAIJAM0IAgkAzQgCCQDNCAIJAM0IAgkAzQgCCQDNCAIIBQFyAl81AwkAZgIJAJADAQgFAXICXzcAAAkBC1N0cmluZ0VudHJ5AgUIbGFuZHNLZXkJALsJAggFAXICXzcCAV8JAQtEZWxldGVFbnRyeQEFCGxhbmRzS2V5CQEMSW50ZWdlckVudHJ5AgkBEmtleU5leHRGcmVlTGFuZE51bQAJAGQCBQdmcmVlTnVtAAEFBWlzc3VlCQELU3RyaW5nRW50cnkCCQEQa2V5TGFuZFRvQXNzZXRJZAEFCm5ld0xhbmROdW0FDm5ld0xhbmRBc3NldElkCQELU3RyaW5nRW50cnkCCQEVa2V5TGFuZEFzc2V0SWRUb093bmVyAQUObmV3TGFuZEFzc2V0SWQFBGFkZHIJAQtTdHJpbmdFbnRyeQIJARFrZXlMYW5kTnVtVG9Pd25lcgEFCm5ld0xhbmROdW0FBGFkZHIJAQxJbnRlZ2VyRW50cnkCCQEga2V5TGFuZEFydFN0YXR1c0J5VHlwZUFuZEFzc2V0SWQCBQpBUlRQUkVTQUxFBQ5uZXdMYW5kQXNzZXRJZAgFAXICXzIJAQxJbnRlZ2VyRW50cnkCCQEla2V5TGFuZEFydFN0YXR1c0J5VHlwZUFzc2V0SWRBbmRPd25lcgMFCkFSVFBSRVNBTEUFDm5ld0xhbmRBc3NldElkBQRhZGRyCAUBcgJfMgkBDEludGVnZXJFbnRyeQIJARZrZXlJbmZyYUxldmVsQnlBc3NldElkAQUObmV3TGFuZEFzc2V0SWQFCG5ld0xldmVsCQEMSW50ZWdlckVudHJ5AgkBHmtleUluZnJhTGV2ZWxCeUFzc2V0SWRBbmRPd25lcgIFDm5ld0xhbmRBc3NldElkBQRhZGRyBQhuZXdMZXZlbAkBC1N0cmluZ0VudHJ5AgUFYnBLZXkJALkJAgkAzAgCCQCRAwIFC2N1cnJlbnRQYWNrBQpicElkeExldmVsCQDMCAIIBQFyAl80CQDMCAIFBm5ld01hdAkAzAgCCQCRAwIFC2N1cnJlbnRQYWNrBQlicElkeFByb2QFA25pbAIBOgkBC1N0cmluZ0VudHJ5AgkBEWtleVJlc1Byb3BvcnRpb25zAAgFAXICXzYJAQtTdHJpbmdFbnRyeQIJAQ9rZXlEdWNrTG9jYXRpb24BBQtkdWNrQXNzZXRJZAkAuQkCCQDMCAIFCWNvbnRpbmVudAkAzAgCAgFMCQDMCAIFDm5ld0xhbmRBc3NldElkBQNuaWwCAV8JAQ5TY3JpcHRUcmFuc2ZlcgMJARFAZXh0ck5hdGl2ZSgxMDYyKQEFBGFkZHIAAQUHYXNzZXRJZAUObmV3TGFuZEFzc2V0SWQBA3MybQMEYWRkcgxsYW5kQXNzZXRJZHMEdHhJZAkBDW1lcmdlSW50ZXJuYWwHAgFNAAMCBFNTU1MFBGFkZHIFDGxhbmRBc3NldElkcwUEdHhJZAAAAQNtMmwFBGFkZHIMbGFuZEFzc2V0SWRzBHR4SWQMc2hvdWxkVXNlTWF0DXBheW1lbnRBbW91bnQEBGNvc3QJAGgCBRVJbmZyYVVwZ3JhZGVDb3N0U1VzZG4ABAMDCQEBIQEFDHNob3VsZFVzZU1hdAkBAiE9AgUNcGF5bWVudEFtb3VudAUEY29zdAcJAAIBCQCsAgICG1BheW1lbnQgYXR0YWNoZWQgc2hvdWxkIGJlIAkApAMBBQRjb3N0CQENbWVyZ2VJbnRlcm5hbAcCAUwABAIDU01NBQRhZGRyBQxsYW5kQXNzZXRJZHMFBHR4SWQJAGgCBRFJbmZyYVVwZ3JhZGVDb3N0UwAEAQRsMnhsBQRhZGRyDGxhbmRBc3NldElkcwR0eElkDHNob3VsZFVzZU1hdA1wYXltZW50QW1vdW50BARjb3N0CQBoAgUVSW5mcmFVcGdyYWRlQ29zdFNVc2RuAC8DAwkBASEBBQxzaG91bGRVc2VNYXQJAQIhPQIFDXBheW1lbnRBbW91bnQFBGNvc3QHCQACAQkArAICAhtQYXltZW50IGF0dGFjaGVkIHNob3VsZCBiZSAJAKQDAQUEY29zdAkBDW1lcmdlSW50ZXJuYWwHAgJYTAAFAgVTU1NNTAUEYWRkcgUMbGFuZEFzc2V0SWRzBQR0eElkCQBoAgURSW5mcmFVcGdyYWRlQ29zdFMALwEGeGwyeHhsBQRhZGRyDGxhbmRBc3NldElkcwR0eElkDHNob3VsZFVzZU1hdA1wYXltZW50QW1vdW50BARjb3N0CQBoAgUVSW5mcmFVcGdyYWRlQ29zdFNVc2RuADYDAwkBASEBBQxzaG91bGRVc2VNYXQJAQIhPQIFDXBheW1lbnRBbW91bnQFBGNvc3QHCQACAQkArAICAhtQYXltZW50IGF0dGFjaGVkIHNob3VsZCBiZSAJAKQDAQUEY29zdAkBDW1lcmdlSW50ZXJuYWwHAgNYWEwABgIDTFhMBQRhZGRyBQxsYW5kQXNzZXRJZHMFBHR4SWQJAGgCBRFJbmZyYVVwZ3JhZGVDb3N0UwA2AQttZXJnZUNvbW1vbgUMc2hvdWxkVXNlTWF0BGFkZHINcGF5bWVudEFtb3VudAxsYW5kQXNzZXRJZHMEdHhJZAQLbWVyZ2VSZXN1bHQEByRtYXRjaDAJAJADAQUMbGFuZEFzc2V0SWRzAwkAAAIABAUHJG1hdGNoMAkBA3MybQMFBGFkZHIFDGxhbmRBc3NldElkcwUEdHhJZAMJAAACAAMFByRtYXRjaDAJAQNtMmwFBQRhZGRyBQxsYW5kQXNzZXRJZHMFBHR4SWQFDHNob3VsZFVzZU1hdAUNcGF5bWVudEFtb3VudAMJAAACAAUFByRtYXRjaDAJAQRsMnhsBQUEYWRkcgUMbGFuZEFzc2V0SWRzBQR0eElkBQxzaG91bGRVc2VNYXQFDXBheW1lbnRBbW91bnQDCQAAAgACBQckbWF0Y2gwCQEGeGwyeHhsBQUEYWRkcgUMbGFuZEFzc2V0SWRzBQR0eElkBQxzaG91bGRVc2VNYXQFDXBheW1lbnRBbW91bnQJAAIBAg1Vbmtub3duIG1lcmdlBQttZXJnZVJlc3VsdAEIc2F2ZVR4SWQCBGFkZHIEdHhJZAkBC1N0cmluZ0VudHJ5AgkBEWtleUxhc3RUeElkQnlVc2VyAQkApQgBBQRhZGRyCQDYBAEFBHR4SWQBDGNoZWNrQmxvY2tlZAADCQELdmFsdWVPckVsc2UCCQCgCAEJAQprZXlCbG9ja2VkAAcJAAIBAh9Db250cmFjdHMgYXJlIHVuZGVyIG1haW50ZW5hbmNlBQR1bml0EwFpAQpzZXRCbG9ja2VkAQlpc0Jsb2NrZWQDCQECIT0CCAUBaQZjYWxsZXIFBHRoaXMJAAIBAhFwZXJtaXNzaW9uIGRlbmllZAkAzAgCCQEMQm9vbGVhbkVudHJ5AgkBCmtleUJsb2NrZWQABQlpc0Jsb2NrZWQFA25pbAFpAQlzdGFrZUxhbmQABAdibG9ja2VkCQEMY2hlY2tCbG9ja2VkAAMJAAACBQdibG9ja2VkBQdibG9ja2VkAwkBAiE9AgkAkAMBCAUBaQhwYXltZW50cwABCQACAQIcRXhhY3RseSBvbmUgcGF5bWVudCByZXF1aXJlZAQDcG10CQEFdmFsdWUBCQCRAwIIBQFpCHBheW1lbnRzAAAEB2Fzc2V0SWQJAQV2YWx1ZQEIBQNwbXQHYXNzZXRJZAQHYWRkcmVzcwkApQgBCAUBaQZjYWxsZXIDCQECIT0CCAUDcG10BmFtb3VudAABCQACAQkArAICCQCsAgICBE5GVCAFCkxBTkRQUkVGSVgCJCB0b2tlbiBzaG91bGQgYmUgYXR0YWNoZWQgYXMgcGF5bWVudAQFYXNzZXQJAQV2YWx1ZQEJAOwHAQUHYXNzZXRJZAMJAQIhPQIIBQVhc3NldAZpc3N1ZXIFBHRoaXMJAAIBAhdVbmtub3duIGlzc3VlciBvZiB0b2tlbgMJAQEhAQkBCGNvbnRhaW5zAggFBWFzc2V0BG5hbWUFCkxBTkRQUkVGSVgJAAIBCQCsAgIJAKwCAgIJT25seSBORlQgBQpMQU5EUFJFRklYAhQgdG9rZW5zIGFyZSBhY2NlcHRlZAQLbGFuZE51bVNpemUJALACAggFBWFzc2V0BG5hbWUABAQHbGFuZE51bQMJAQhjb250YWlucwIFC2xhbmROdW1TaXplAgNYWEwJALMCAgULbGFuZE51bVNpemUAAwMJAQhjb250YWlucwIFC2xhbmROdW1TaXplAgJYTAkAswICBQtsYW5kTnVtU2l6ZQACCQCzAgIFC2xhbmROdW1TaXplAAEDCQEBIQEJAQlpc0RlZmluZWQBCQC2CQEFB2xhbmROdW0JAAIBCQCsAgICHkNhbm5vdCBwYXJzZSBsYW5kIG51bWJlciBmcm9tIAgFBWFzc2V0BG5hbWUEC2xhbmRBc3NldElkCQDYBAEFB2Fzc2V0SWQEB3RpbWVLZXkJARZrZXlTdGFrZWRUaW1lQnlBc3NldElkAQULbGFuZEFzc2V0SWQDCQEJaXNEZWZpbmVkAQkAnwgBBQd0aW1lS2V5CQACAQkArAICCQCsAgICBE5GVCAIBQVhc3NldARuYW1lAhIgaXMgYWxyZWFkeSBzdGFrZWQEAWQJALUJAggFBWFzc2V0C2Rlc2NyaXB0aW9uAgFfBA10ZXJyYWluQ291bnRzCQENY291bnRUZXJyYWlucwEJAJEDAgUBZAULcmVjVGVycmFpbnMEBXByb3BzCQERdXBkYXRlUHJvcG9ydGlvbnMDBQ10ZXJyYWluQ291bnRzCQBpAgkBD251bVBpZWNlc0J5U2l6ZQEJAJEDAgUBZAULcmVjTGFuZFNpemUFBVNTSVpFAAEEBWxhbmRzCQC9CQIJAQt2YWx1ZU9yRWxzZQIJAKIIAQkBFWtleVN0YWtlZExhbmRzQnlPd25lcgEFB2FkZHJlc3MCAAIBXwMJAQ9jb250YWluc0VsZW1lbnQCBQVsYW5kcwULbGFuZEFzc2V0SWQJAAIBCQCsAgICIllvdXIgc3Rha2VkIGxhbmRzIGFscmVhZHkgY29udGFpbiAFC2xhbmRBc3NldElkCQDMCAIJAQxJbnRlZ2VyRW50cnkCBQd0aW1lS2V5CAUJbGFzdEJsb2NrCXRpbWVzdGFtcAkAzAgCCQEMSW50ZWdlckVudHJ5AgkBImtleVN0YWtlZFRpbWVCeVR5cGVBc3NldElkQW5kT3duZXIDBQpMQU5EUFJFRklYBQtsYW5kQXNzZXRJZAUHYWRkcmVzcwgFCWxhc3RCbG9jawl0aW1lc3RhbXAJAMwIAgkBC1N0cmluZ0VudHJ5AgkBFWtleVN0YWtlZExhbmRzQnlPd25lcgEFB2FkZHJlc3MJALsJAgkAzQgCBQVsYW5kcwULbGFuZEFzc2V0SWQCAV8JAMwIAgkBC1N0cmluZ0VudHJ5AgkBFWtleUxhbmRBc3NldElkVG9Pd25lcgEFC2xhbmRBc3NldElkBQdhZGRyZXNzCQDMCAIJAQtTdHJpbmdFbnRyeQIJARFrZXlMYW5kTnVtVG9Pd25lcgEFB2xhbmROdW0FB2FkZHJlc3MJAMwIAgkBC1N0cmluZ0VudHJ5AgkBEWtleVJlc1Byb3BvcnRpb25zAAUFcHJvcHMFA25pbAkAAgECJFN0cmljdCB2YWx1ZSBpcyBub3QgZXF1YWwgdG8gaXRzZWxmLgFpAQt1bnN0YWtlTGFuZAESbGFuZEFzc2V0SWRJZ25vcmVkBAdibG9ja2VkCQEMY2hlY2tCbG9ja2VkAAMJAAACBQdibG9ja2VkBQdibG9ja2VkAwkBAiE9AgkAkAMBCAUBaQhwYXltZW50cwAACQACAQIkdW5zdGFrZSBkb2Vzbid0IHJlcXVpcmUgYW55IHBheW1lbnRzBARhZGRyCQClCAEIBQFpBmNhbGxlcgQBYwkBFGNoZWNrQ2xhaW1Db25kaXRpb25zAQUEYWRkcgQLbGFuZEFzc2V0SWQIBQFjAl8yBAhsYW5kc0tleQkBFWtleVN0YWtlZExhbmRzQnlPd25lcgEFBGFkZHIEDXRlcnJhaW5Db3VudHMJAQ1jb3VudFRlcnJhaW5zAQkAkQMCCAUBYwJfMwULcmVjVGVycmFpbnMEBnBpZWNlcwkBD251bVBpZWNlc0J5U2l6ZQEJAJEDAggFAWMCXzMFC3JlY0xhbmRTaXplBAVwcm9wcwkBEXVwZGF0ZVByb3BvcnRpb25zAwUNdGVycmFpbkNvdW50cwkAaQIFBnBpZWNlcwUFU1NJWkUA////////////AQQLY2xhaW1SZXN1bHQJAQhjbGFpbUFsbAMFBGFkZHIFC2xhbmRBc3NldElkBQZwaWVjZXMEBWxhbmRzCQC9CQIJAQt2YWx1ZU9yRWxzZQIJAKIIAQUIbGFuZHNLZXkCAAIBXwQDaWR4CQDPCAIFBWxhbmRzBQtsYW5kQXNzZXRJZAMJAQEhAQkBCWlzRGVmaW5lZAEFA2lkeAkAAgEJAKwCAgIgWW91ciBzdGFrZWQgbGFuZHMgZG9uJ3QgY29udGFpbiAFC2xhbmRBc3NldElkCQDMCAIJAQ5TY3JpcHRUcmFuc2ZlcgMIBQFpBmNhbGxlcgABCQDZBAEFC2xhbmRBc3NldElkCQDMCAIJAQtEZWxldGVFbnRyeQEJARZrZXlTdGFrZWRUaW1lQnlBc3NldElkAQULbGFuZEFzc2V0SWQJAMwIAgkBC0RlbGV0ZUVudHJ5AQkBImtleVN0YWtlZFRpbWVCeVR5cGVBc3NldElkQW5kT3duZXIDBQpMQU5EUFJFRklYBQtsYW5kQXNzZXRJZAUEYWRkcgkAzAgCCQELU3RyaW5nRW50cnkCCQERa2V5UmVzUHJvcG9ydGlvbnMABQVwcm9wcwkAzAgCCQELU3RyaW5nRW50cnkCCAULY2xhaW1SZXN1bHQCXzIJALkJAggFC2NsYWltUmVzdWx0Al8zAgE6CQDMCAIDCQBmAgkAkAMBBQVsYW5kcwABCQELU3RyaW5nRW50cnkCBQhsYW5kc0tleQkAuwkCCQDRCAIFBWxhbmRzCQEFdmFsdWUBBQNpZHgCAV8JAQtEZWxldGVFbnRyeQEFCGxhbmRzS2V5BQNuaWwJAAIBAiRTdHJpY3QgdmFsdWUgaXMgbm90IGVxdWFsIHRvIGl0c2VsZi4BaQEJc3Rha2VEdWNrAAQHYmxvY2tlZAkBDGNoZWNrQmxvY2tlZAADCQAAAgUHYmxvY2tlZAUHYmxvY2tlZAMJAQIhPQIJAJADAQgFAWkIcGF5bWVudHMAAQkAAgECHEV4YWN0bHkgb25lIHBheW1lbnQgcmVxdWlyZWQEA3BtdAkBBXZhbHVlAQkAkQMCCAUBaQhwYXltZW50cwAABAdhc3NldElkCQEFdmFsdWUBCAUDcG10B2Fzc2V0SWQEB2FkZHJlc3MJAKUIAQgFAWkGY2FsbGVyAwkBAiE9AggFA3BtdAZhbW91bnQAAQkAAgEJAKwCAgkArAICAgRORlQgBQpEVUNLUFJFRklYAiQgdG9rZW4gc2hvdWxkIGJlIGF0dGFjaGVkIGFzIHBheW1lbnQEBWFzc2V0CQEFdmFsdWUBCQDsBwEFB2Fzc2V0SWQDAwkBAiE9AggFBWFzc2V0Bmlzc3VlcgUNaW5jdWJhdG9yQWRkcgkBAiE9AggFBWFzc2V0Bmlzc3VlcgULYnJlZWRlckFkZHIHCQACAQkArAICCQCsAgICElVua25vd24gaXNzdWVyIG9mIAUKRFVDS1BSRUZJWAIGIHRva2VuAwkBASEBCQEIY29udGFpbnMCCAUFYXNzZXQEbmFtZQUKRFVDS1BSRUZJWAkAAgEJAKwCAgkArAICAglPbmx5IE5GVCAFCkRVQ0tQUkVGSVgCFCB0b2tlbnMgYXJlIGFjY2VwdGVkBAphc3NldElkU3RyCQDYBAEFB2Fzc2V0SWQEB3RpbWVLZXkJARZrZXlTdGFrZWRUaW1lQnlBc3NldElkAQUKYXNzZXRJZFN0cgMJAQlpc0RlZmluZWQBCQCfCAEFB3RpbWVLZXkJAAIBCQCsAgIJAKwCAgIETkZUIAgFBWFzc2V0BG5hbWUCEiBpcyBhbHJlYWR5IHN0YWtlZAMJAQlpc0RlZmluZWQBCQCiCAEJARRrZXlTdGFrZWREdWNrQnlPd25lcgEFB2FkZHJlc3MJAAIBCQCsAgICHVlvdSBhbHJlYWR5IHN0YWtlZCBvbmUgZHVjazogCAUFYXNzZXQEbmFtZQQGbG9jS2V5CQEPa2V5RHVja0xvY2F0aW9uAQUKYXNzZXRJZFN0cgQIbG9jYXRpb24JAKIIAQUGbG9jS2V5BAVicEtleQkBEWtleUJhY2twYWNrQnlEdWNrAQUKYXNzZXRJZFN0cgQIYmFja3BhY2sJAKIIAQUFYnBLZXkJAM4IAgkAzAgCCQEMSW50ZWdlckVudHJ5AgUHdGltZUtleQgFCWxhc3RCbG9jawl0aW1lc3RhbXAJAMwIAgkBDEludGVnZXJFbnRyeQIJASJrZXlTdGFrZWRUaW1lQnlUeXBlQXNzZXRJZEFuZE93bmVyAwUKRFVDS1BSRUZJWAkA2AQBBQdhc3NldElkBQdhZGRyZXNzCAUJbGFzdEJsb2NrCXRpbWVzdGFtcAkAzAgCCQELU3RyaW5nRW50cnkCCQEQa2V5RHVja0lkVG9Pd25lcgEFCmFzc2V0SWRTdHIFB2FkZHJlc3MJAMwIAgkBC1N0cmluZ0VudHJ5AgkBFGtleVN0YWtlZER1Y2tCeU93bmVyAQUHYWRkcmVzcwUKYXNzZXRJZFN0cgUDbmlsAwkBCWlzRGVmaW5lZAEFCGxvY2F0aW9uBQNuaWwJAM4IAgkAzAgCCQELU3RyaW5nRW50cnkCBQZsb2NLZXkFD0RFRkFVTFRMT0NBVElPTgUDbmlsAwkBCWlzRGVmaW5lZAEFCGJhY2twYWNrBQNuaWwJAM0IAgkAzAgCCQELU3RyaW5nRW50cnkCBQVicEtleQIaMDowXzBfMF8wXzBfMDowXzBfMF8wXzBfMDoFA25pbAkBDEludGVnZXJFbnRyeQIJAQ1rZXlEdWNrSGVhbHRoAQUKYXNzZXRJZFN0cgBkCQACAQIkU3RyaWN0IHZhbHVlIGlzIG5vdCBlcXVhbCB0byBpdHNlbGYuAWkBC3Vuc3Rha2VEdWNrAQphc3NldElkU3RyBAdibG9ja2VkCQEMY2hlY2tCbG9ja2VkAAMJAAACBQdibG9ja2VkBQdibG9ja2VkAwkBAiE9AgkAkAMBCAUBaQhwYXltZW50cwAACQACAQIkdW5zdGFrZSBkb2Vzbid0IHJlcXVpcmUgYW55IHBheW1lbnRzBAdhc3NldElkCQDZBAEFCmFzc2V0SWRTdHIEB2FkZHJlc3MJAKUIAQgFAWkGY2FsbGVyBAVhc3NldAkBBXZhbHVlAQkA7AcBBQdhc3NldElkBAd0aW1lS2V5CQEWa2V5U3Rha2VkVGltZUJ5QXNzZXRJZAEJANgEAQUHYXNzZXRJZAMJAQEhAQkBCWlzRGVmaW5lZAEFB3RpbWVLZXkJAAIBCQCsAgIJAKwCAgIETkZUIAgFBWFzc2V0BG5hbWUCDiBpcyBub3Qgc3Rha2VkAwkBASEBCQEJaXNEZWZpbmVkAQkBFGtleVN0YWtlZER1Y2tCeU93bmVyAQUHYWRkcmVzcwkAAgEJAKwCAgkArAICAglUaGUgZHVjayAIBQVhc3NldARuYW1lAg4gaXMgbm90IHN0YWtlZAQFb3duZXIJARN2YWx1ZU9yRXJyb3JNZXNzYWdlAgkAoggBCQEQa2V5RHVja0lkVG9Pd25lcgEJANgEAQUHYXNzZXRJZAkArAICCQCsAgICBE5GVCAIBQVhc3NldARuYW1lAgwgaXMgb3JwaGFuZWQDCQECIT0CBQVvd25lcgUHYWRkcmVzcwkAAgECF1N0YWtlZCBORlQgaXMgbm90IHlvdXJzBAlrZXlIZWFsdGgJAQ1rZXlEdWNrSGVhbHRoAQUKYXNzZXRJZFN0cgQGaGVhbHRoCQELdmFsdWVPckVsc2UCCQCfCAEFCWtleUhlYWx0aABkAwkBAiE9AgUGaGVhbHRoAGQJAAIBAiZQbGVhc2UgaGVhbCB5b3VyIGR1Y2sgYmVmb3JlIHVuc3Rha2luZwkAzAgCCQEOU2NyaXB0VHJhbnNmZXIDCAUBaQZjYWxsZXIAAQUHYXNzZXRJZAkAzAgCCQELRGVsZXRlRW50cnkBBQd0aW1lS2V5CQDMCAIJAQtEZWxldGVFbnRyeQEFCWtleUhlYWx0aAkAzAgCCQELRGVsZXRlRW50cnkBCQEPa2V5RHVja0xvY2F0aW9uAQUKYXNzZXRJZFN0cgkAzAgCCQELRGVsZXRlRW50cnkBCQEQa2V5RHVja0lkVG9Pd25lcgEFCmFzc2V0SWRTdHIJAMwIAgkBC0RlbGV0ZUVudHJ5AQkBImtleVN0YWtlZFRpbWVCeVR5cGVBc3NldElkQW5kT3duZXIDBQpEVUNLUFJFRklYBQphc3NldElkU3RyBQdhZGRyZXNzCQDMCAIJAQtEZWxldGVFbnRyeQEJARRrZXlTdGFrZWREdWNrQnlPd25lcgEFB2FkZHJlc3MFA25pbAkAAgECJFN0cmljdCB2YWx1ZSBpcyBub3QgZXF1YWwgdG8gaXRzZWxmLgFpAQhjbGFpbVJlcwIGYW1vdW50DmxhbmRBc3NldElkU3RyBAdibG9ja2VkCQEMY2hlY2tCbG9ja2VkAAMJAAACBQdibG9ja2VkBQdibG9ja2VkAwkBAiE9AgkAkAMBCAUBaQhwYXltZW50cwAACQACAQIlY2xhaW1SZXMgZG9lc24ndCByZXF1aXJlIGFueSBwYXltZW50cwQEYWRkcgkApQgBCAUBaQxvcmlnaW5DYWxsZXIEBnJlc3VsdAkBEGNsYWltUmVzSW50ZXJuYWwCBQRhZGRyBQZhbW91bnQJAJQKAgkAzQgCCAUGcmVzdWx0Al8xCQELU3RyaW5nRW50cnkCCAUGcmVzdWx0Al8yCQC5CQIIBQZyZXN1bHQCXzMCAToJAJEDAggFBnJlc3VsdAJfMwUIYnBJZHhSZXMJAAIBAiRTdHJpY3QgdmFsdWUgaXMgbm90IGVxdWFsIHRvIGl0c2VsZi4BaQEGZmxpZ2h0AgdtZXNzYWdlA3NpZwQHYmxvY2tlZAkBDGNoZWNrQmxvY2tlZAADCQAAAgUHYmxvY2tlZAUHYmxvY2tlZAMJAQEhAQkAxBMDBQdtZXNzYWdlBQNzaWcFA3B1YgkAAgECGHNpZ25hdHVyZSBkb2VzIG5vdCBtYXRjaAMJAQIhPQIJAJADAQgFAWkIcGF5bWVudHMAAAkAAgECI2ZsaWdodCBkb2Vzbid0IHJlcXVpcmUgYW55IHBheW1lbnRzBAVwYXJ0cwkAtQkCCQCwCQEFB21lc3NhZ2UCATsEAmhwCQC1CQIJAJEDAgkAtQkCCQCRAwIFBXBhcnRzAAACAXwAAAIBXwQFY3VySFAJAQ1wYXJzZUludFZhbHVlAQkAkQMCBQJocAAABAVuZXdIUAkBDXBhcnNlSW50VmFsdWUBCQCRAwIFAmhwAAEEDW5ld0xvY0FuZFRpbWUJALUJAgkAkQMCBQVwYXJ0cwABAgE6BAtuZXdMb2NhdGlvbgkAkQMCBQ1uZXdMb2NBbmRUaW1lAAAEBHRpbWUJAQ1wYXJzZUludFZhbHVlAQkAkQMCBQ1uZXdMb2NBbmRUaW1lAAEDAwkAZgIFBHRpbWUJAGQCCAUJbGFzdEJsb2NrCXRpbWVzdGFtcAURRklWRU1JTlVURVNNSUxMSVMGCQBmAgkAZQIIBQlsYXN0QmxvY2sJdGltZXN0YW1wBRFGSVZFTUlOVVRFU01JTExJUwUEdGltZQkAAgECEnNpZ25hdHVyZSBvdXRkYXRlZAQLZHVja0Fzc2V0SWQJARN2YWx1ZU9yRXJyb3JNZXNzYWdlAgkAoggBCQEUa2V5U3Rha2VkRHVja0J5T3duZXIBCQClCAEIBQFpBmNhbGxlcgIcWW91IGRvbid0IGhhdmUgYSBkdWNrIHN0YWtlZAQJa2V5SGVhbHRoCQENa2V5RHVja0hlYWx0aAEFC2R1Y2tBc3NldElkBAxvbGRGcm9tU3RhdGUJAQt2YWx1ZU9yRWxzZQIJAJ8IAQUJa2V5SGVhbHRoAGQDCQECIT0CBQxvbGRGcm9tU3RhdGUFBWN1ckhQCQACAQkArAICCQCsAgIJAKwCAgIKb2xkSGVhbHRoPQkApAMBCQELdmFsdWVPckVsc2UCCQCfCAEFCWtleUhlYWx0aABkAi8gZnJvbSBzdGF0ZSBkb2VzIG5vdCBtYXRjaCBvbmUgZnJvbSBmbGlnaHQgbG9nPQkApAMBBQVjdXJIUAMJAGcCAAAFBWN1ckhQCQACAQIeWW91IGNhbid0IGZseSB3aXRoIHplcm8gaGVhbHRoBAZsb2NLZXkJAQ9rZXlEdWNrTG9jYXRpb24BBQtkdWNrQXNzZXRJZAQLY3VyTG9jYXRpb24JAQt2YWx1ZU9yRWxzZQIJAKIIAQUGbG9jS2V5BQ9ERUZBVUxUTE9DQVRJT04DCQAAAgULbmV3TG9jYXRpb24FC2N1ckxvY2F0aW9uCQACAQIiWW91IGNhbid0IGZseSB0byB0aGUgc2FtZSBsb2NhdGlvbgkAlAoCCQDMCAIJAQtTdHJpbmdFbnRyeQIFBmxvY0tleQMJAGYCBQVuZXdIUAAABQtuZXdMb2NhdGlvbgULY3VyTG9jYXRpb24JAMwIAgkBDEludGVnZXJFbnRyeQIFCWtleUhlYWx0aAUFbmV3SFAFA25pbAUEdW5pdAkAAgECJFN0cmljdCB2YWx1ZSBpcyBub3QgZXF1YWwgdG8gaXRzZWxmLgFpAQlzZXRIZWFsdGgCBmhlYWx0aAtkdWNrQXNzZXRJZAQHYmxvY2tlZAkBDGNoZWNrQmxvY2tlZAADCQAAAgUHYmxvY2tlZAUHYmxvY2tlZAMDCQBmAgAABQZoZWFsdGgGCQBmAgUGaGVhbHRoAGQJAAIBAhpIUCBzaG91bGQgYmUgd2l0aGluIDAuLjEwMAkAzAgCCQEMSW50ZWdlckVudHJ5AgkBDWtleUR1Y2tIZWFsdGgBBQtkdWNrQXNzZXRJZAUGaGVhbHRoBQNuaWwJAAIBAiRTdHJpY3QgdmFsdWUgaXMgbm90IGVxdWFsIHRvIGl0c2VsZi4BaQEEaGVhbAIHbWF0VHlwZQZhbW91bnQEB2Jsb2NrZWQJAQxjaGVja0Jsb2NrZWQAAwkAAAIFB2Jsb2NrZWQFB2Jsb2NrZWQDAwkAZgIAAAUHbWF0VHlwZQYJAGcCBQdtYXRUeXBlBQZOVU1SRVMJAAIBCQCsAgICElVua25vd24gbWF0ZXJpYWw6IAkApAMBBQdtYXRUeXBlAwkAZwIAAAUGYW1vdW50CQACAQkArAICAhtBbW91bnQgc2hvdWxkIGJlIHBvc2l0aXZlISAJAKQDAQUGYW1vdW50BAtkdWNrQXNzZXRJZAkBE3ZhbHVlT3JFcnJvck1lc3NhZ2UCCQCiCAEJARRrZXlTdGFrZWREdWNrQnlPd25lcgEJAKUIAQgFAWkGY2FsbGVyAhxZb3UgZG9uJ3QgaGF2ZSBhIGR1Y2sgc3Rha2VkBAlrZXlIZWFsdGgJAQ1rZXlEdWNrSGVhbHRoAQULZHVja0Fzc2V0SWQECW9sZEhlYWx0aAkBC3ZhbHVlT3JFbHNlAgkAnwgBBQlrZXlIZWFsdGgAZAMJAGcCBQlvbGRIZWFsdGgAZAkAAgECGkhQIHNob3VsZCBiZSA8IDEwMCB0byBoZWFsBAVicEtleQkBEWtleUJhY2twYWNrQnlEdWNrAQULZHVja0Fzc2V0SWQEC2N1cnJlbnRQYWNrCQELZ2V0QmFja3BhY2sBBQVicEtleQQFbUxpc3QJALUJAgkAkQMCBQtjdXJyZW50UGFjawUIYnBJZHhNYXQCAV8EDWN1cnJlbnRBbW91bnQJAQ1wYXJzZUludFZhbHVlAQkAkQMCBQVtTGlzdAUHbWF0VHlwZQQLZGVsdGFIZWFsdGgJAJcDAQkAzAgCCQBpAgUGYW1vdW50BQhIRUFMQ09TVAkAzAgCCQBlAgBkBQlvbGRIZWFsdGgFA25pbAQLc3BlbmRBbW91bnQJAGgCBQtkZWx0YUhlYWx0aAUISEVBTENPU1QDCQBmAgULc3BlbmRBbW91bnQFDWN1cnJlbnRBbW91bnQJAAIBCQCsAgIJAKwCAgkArAICCQCsAgIJAKwCAgIJWW91IG5lZWQgCQCkAwEFC3NwZW5kQW1vdW50AgQgb2YgCQCRAwIFCG1hdFR5cGVzBQdtYXRUeXBlAiQgdG8gaGVhbCwgYnV0IHlvdSBiYWNrcGFjayBjb250YWlucyAJAKQDAQUNY3VycmVudEFtb3VudAQGbmV3TWF0CQEMc3ViT25lSW5MaXN0AwUFbUxpc3QFB21hdFR5cGUFC3NwZW5kQW1vdW50CQDMCAIJAQxJbnRlZ2VyRW50cnkCBQlrZXlIZWFsdGgJAGQCBQlvbGRIZWFsdGgFC2RlbHRhSGVhbHRoCQDMCAIJAQtTdHJpbmdFbnRyeQIFBWJwS2V5CQC5CQIJAMwIAgkAkQMCBQtjdXJyZW50UGFjawUKYnBJZHhMZXZlbAkAzAgCCQCRAwIFC2N1cnJlbnRQYWNrBQhicElkeFJlcwkAzAgCBQZuZXdNYXQJAMwIAgkAkQMCBQtjdXJyZW50UGFjawUJYnBJZHhQcm9kBQNuaWwCAToFA25pbAkAAgECJFN0cmljdCB2YWx1ZSBpcyBub3QgZXF1YWwgdG8gaXRzZWxmLgFpAQ51cGRhdGVCYWNrcGFjawILZHVja0Fzc2V0SWQHbmV3UGFjawMJAQIhPQIIBQFpBmNhbGxlcgUPZWNvbm9teUNvbnRyYWN0CQACAQIRcGVybWlzc2lvbiBkZW5pZWQJAJQKAgkAzAgCCQELU3RyaW5nRW50cnkCCQERa2V5QmFja3BhY2tCeUR1Y2sBBQtkdWNrQXNzZXRJZAUHbmV3UGFjawUDbmlsBQduZXdQYWNrAWkBDWV4cGVkaXRpb25CdXkCB21lc3NhZ2UDc2lnBAdibG9ja2VkCQEMY2hlY2tCbG9ja2VkAAMJAAACBQdibG9ja2VkBQdibG9ja2VkAwkBAiE9AgkAkAMBCAUBaQhwYXltZW50cwABCQACAQIcRXhhY3RseSBvbmUgcGF5bWVudCByZXF1aXJlZAQDcG10CQEFdmFsdWUBCQCRAwIIBQFpCHBheW1lbnRzAAADCQECIT0CCAUDcG10B2Fzc2V0SWQFC3VzZG5Bc3NldElkCQACAQIaQWxsb3dlZCBVU0ROIHBheW1lbnQgb25seSEDCQECIT0CCAUDcG10BmFtb3VudAUHRVhQVVNETgkAAgEJAKwCAgIbUGF5bWVudCBhdHRhY2hlZCBzaG91bGQgYmUgCQCkAwEFB0VYUFVTRE4EBnJlc3VsdAkBEGV4cGVkaXRpb25Db21tb24FBwgFAWkGY2FsbGVyCAUBaQ10cmFuc2FjdGlvbklkBQdtZXNzYWdlBQNzaWcDCQAAAggFBnJlc3VsdAJfMgIABQZyZXN1bHQJAJQKAgkAzQgCCAUGcmVzdWx0Al8xCQEOU2NyaXB0VHJhbnNmZXIDBQ9lY29ub215Q29udHJhY3QIBQNwbXQGYW1vdW50BQt1c2RuQXNzZXRJZAgFBnJlc3VsdAJfMgkAAgECJFN0cmljdCB2YWx1ZSBpcyBub3QgZXF1YWwgdG8gaXRzZWxmLgFpAQpleHBlZGl0aW9uAgdtZXNzYWdlA3NpZwQHYmxvY2tlZAkBDGNoZWNrQmxvY2tlZAADCQAAAgUHYmxvY2tlZAUHYmxvY2tlZAMJAQIhPQIJAJADAQgFAWkIcGF5bWVudHMAAAkAAgECJ2V4cGVkaXRpb24gZG9lc24ndCByZXF1aXJlIGFueSBwYXltZW50cwkBEGV4cGVkaXRpb25Db21tb24FBggFAWkGY2FsbGVyCAUBaQ10cmFuc2FjdGlvbklkBQdtZXNzYWdlBQNzaWcJAAIBAiRTdHJpY3QgdmFsdWUgaXMgbm90IGVxdWFsIHRvIGl0c2VsZi4BaQEMdXBncmFkZUluZnJhARJsYW5kQXNzZXRJZElnbm9yZWQEB2Jsb2NrZWQJAQxjaGVja0Jsb2NrZWQAAwkAAAIFB2Jsb2NrZWQFB2Jsb2NrZWQDCQECIT0CCQCQAwEIBQFpCHBheW1lbnRzAAAJAAIBAjNJbmZyYXN0cnVjdHVyZSB1cGdyYWRlIGRvZXNuJ3QgcmVxdWlyZSBhbnkgcGF5bWVudHMJAQ11cEluZnJhQ29tbW9uAwYIBQFpBmNhbGxlcgAACQACAQIkU3RyaWN0IHZhbHVlIGlzIG5vdCBlcXVhbCB0byBpdHNlbGYuAWkBEHVwZ3JhZGVJbmZyYVVzZG4BEmxhbmRBc3NldElkSWdub3JlZAQHYmxvY2tlZAkBDGNoZWNrQmxvY2tlZAADCQAAAgUHYmxvY2tlZAUHYmxvY2tlZAMJAQIhPQIJAJADAQgFAWkIcGF5bWVudHMAAQkAAgECHEV4YWN0bHkgb25lIHBheW1lbnQgcmVxdWlyZWQEA3BtdAkBBXZhbHVlAQkAkQMCCAUBaQhwYXltZW50cwAAAwkBAiE9AggFA3BtdAdhc3NldElkBQt1c2RuQXNzZXRJZAkAAgECGkFsbG93ZWQgVVNETiBwYXltZW50IG9ubHkhBAZyZXN1bHQJAQ11cEluZnJhQ29tbW9uAwcIBQFpBmNhbGxlcggFA3BtdAZhbW91bnQJAJQKAgkAzQgCCAUGcmVzdWx0Al8xCQEOU2NyaXB0VHJhbnNmZXIDBQ9lY29ub215Q29udHJhY3QIBQNwbXQGYW1vdW50BQt1c2RuQXNzZXRJZAgFBnJlc3VsdAJfMgkAAgECJFN0cmljdCB2YWx1ZSBpcyBub3QgZXF1YWwgdG8gaXRzZWxmLgFpARBhY3RpdmF0ZUFydGlmYWN0AQdhcnROYW1lBAdibG9ja2VkCQEMY2hlY2tCbG9ja2VkAAMJAAACBQdibG9ja2VkBQdibG9ja2VkAwkBAiE9AgkAkAMBCAUBaQhwYXltZW50cwAACQACAQIwQXJ0aWZhY3QgYWN0aXZhdGlvbiBkb2Vzbid0IHJlcXVpcmUgYW55IHBheW1lbnRzBAZyZXN1bHQEByRtYXRjaDAFB2FydE5hbWUDCQAAAgIHUFJFU0FMRQUHJG1hdGNoMAkBEmFjdGl2YXRlUHJlc2FsZUFydAEJAKUIAQgFAWkGY2FsbGVyCQACAQIQVW5rbm93biBhcnRpZmFjdAUGcmVzdWx0CQACAQIkU3RyaWN0IHZhbHVlIGlzIG5vdCBlcXVhbCB0byBpdHNlbGYuAWkBCm1lcmdlTGFuZHMBDGxhbmRBc3NldElkcwMJAQIhPQIIBQFpBmNhbGxlcgUEdGhpcwkAAgECEXBlcm1pc3Npb24gZGVuaWVkBAdibG9ja2VkCQEMY2hlY2tCbG9ja2VkAAMJAAACBQdibG9ja2VkBQdibG9ja2VkAwkBAiE9AgkAkAMBCAUBaQhwYXltZW50cwAACQACAQIqTGFuZHMgbWVyZ2luZyBkb2Vzbid0IHJlcXVpcmUgYW55IHBheW1lbnRzCQELbWVyZ2VDb21tb24FBgkApQgBCAUBaQZjYWxsZXIAAAUMbGFuZEFzc2V0SWRzCAUBaQ10cmFuc2FjdGlvbklkCQACAQIkU3RyaWN0IHZhbHVlIGlzIG5vdCBlcXVhbCB0byBpdHNlbGYuAWkBDm1lcmdlTGFuZHNVc2RuAQxsYW5kQXNzZXRJZHMDCQECIT0CCAUBaQZjYWxsZXIFBHRoaXMJAAIBAhFwZXJtaXNzaW9uIGRlbmllZAQHYmxvY2tlZAkBDGNoZWNrQmxvY2tlZAADCQAAAgUHYmxvY2tlZAUHYmxvY2tlZAMJAQIhPQIJAJADAQgFAWkIcGF5bWVudHMAAQkAAgECHEV4YWN0bHkgb25lIHBheW1lbnQgcmVxdWlyZWQEA3BtdAkBBXZhbHVlAQkAkQMCCAUBaQhwYXltZW50cwAAAwkBAiE9AggFA3BtdAdhc3NldElkBQt1c2RuQXNzZXRJZAkAAgECGkFsbG93ZWQgVVNETiBwYXltZW50IG9ubHkhBAZyZXN1bHQJAQttZXJnZUNvbW1vbgUHCQClCAEIBQFpBmNhbGxlcggFA3BtdAZhbW91bnQFDGxhbmRBc3NldElkcwgFAWkNdHJhbnNhY3Rpb25JZAkAlAoCCQDNCAIIBQZyZXN1bHQCXzEJAQ5TY3JpcHRUcmFuc2ZlcgMFD2Vjb25vbXlDb250cmFjdAgFA3BtdAZhbW91bnQFC3VzZG5Bc3NldElkCAUGcmVzdWx0Al8yCQACAQIkU3RyaWN0IHZhbHVlIGlzIG5vdCBlcXVhbCB0byBpdHNlbGYuAWkBHHNwbGl0QnlHbG9iYWxXZWlnaHRzUkVBRE9OTFkBBmFtb3VudAkAlAoCBQNuaWwJARJnZXROZWVkZWRNYXRlcmlhbHMBBQZhbW91bnQBaQEbc3BsaXRCeUxvY2FsV2VpZ2h0c1JFQURPTkxZAgZhbW91bnQIdGVycmFpbnMEDXRlcnJhaW5Db3VudHMJAQ1jb3VudFRlcnJhaW5zAQUIdGVycmFpbnMJAJQKAgUDbmlsCQETZGlzdHJpYnV0ZUJ5V2VpZ2h0cwIFBmFtb3VudAUNdGVycmFpbkNvdW50cwAGeSj5", "height": 3492118, "applicationStatus": "succeeded", "spentComplexity": 0 } View: original | compacted Prev: 71Pbz8UAhKFDR9e7mdQw3iFnURpDwqv5RtbhthokL5Lf Next: 4HfReAZ5UweZTCzPBt5qUBEw4sF8rKxMb2nS8YmLrWj7 Diff:
OldNewDifferences
185185
186186
187187 func keyResProportions () = "resTypesProportions"
188+
189+
190+func keyStakedLandsByOwner (ownerAddr) = ("stakedLandsByOwner_" + ownerAddr)
191+
192+
193+func keyBlocked () = "contractsBlocked"
188194
189195
190196 let recLandNum = 0
647653 let dailyProductionByPiece = applyBonuses(landAssetId, pieces)
648654 let bpRes = addRes(split(acc._4, "_"), terrainCounts, deltaTime, (pieces / SSIZE), dailyProductionByPiece)
649655 let props = updateProportionsInternal(split(acc._6, "_"), terrainCounts, (pieces / SSIZE), -1)
650- $Tuple6(sizesOut, arts, continent, bpRes, (((((((((((((acc._5 :+ DeleteEntry(keyStakedTimeByAssetId(landAssetId))) :+ DeleteEntry(keyStakedTimeByTypeAssetIdAndOwner(LANDPREFIX, landAssetId, addr))) :+ DeleteEntry(keyLandToAssetId(landNum))) :+ DeleteEntry(keyNftName(landNum, landSize))) :+ DeleteEntry(keyLandAssetIdToOwner(landAssetId))) :+ DeleteEntry(keyInfraLevelByAssetId(landAssetId))) :+ DeleteEntry(keyInfraLevelByAssetIdAndOwner(landAssetId, addr))) :+ DeleteEntry(keyPresaleArtActivatedByAssetId(landAssetId))) :+ DeleteEntry(keyPresaleArtActivatedByAssetIdAndOwner(landAssetId, addr))) :+ DeleteEntry(keyLandArtStatusByTypeAndAssetId(ARTPRESALE, landAssetId))) :+ DeleteEntry(keyLandArtStatusByTypeAssetIdAndOwner(ARTPRESALE, landAssetId, addr))) :+ DeleteEntry(keyLandNumToOwner(landNum))) :+ Burn(fromBase58String(landAssetId), 1)), props)
656+ let lands = acc._7
657+ let idx = indexOf(lands, landAssetId)
658+ if (!(isDefined(idx)))
659+ then throw(("Your staked lands don't contain " + landAssetId))
660+ else $Tuple7(sizesOut, arts, continent, bpRes, (((((((((((((acc._5 :+ DeleteEntry(keyStakedTimeByAssetId(landAssetId))) :+ DeleteEntry(keyStakedTimeByTypeAssetIdAndOwner(LANDPREFIX, landAssetId, addr))) :+ DeleteEntry(keyLandToAssetId(landNum))) :+ DeleteEntry(keyNftName(landNum, landSize))) :+ DeleteEntry(keyLandAssetIdToOwner(landAssetId))) :+ DeleteEntry(keyInfraLevelByAssetId(landAssetId))) :+ DeleteEntry(keyInfraLevelByAssetIdAndOwner(landAssetId, addr))) :+ DeleteEntry(keyPresaleArtActivatedByAssetId(landAssetId))) :+ DeleteEntry(keyPresaleArtActivatedByAssetIdAndOwner(landAssetId, addr))) :+ DeleteEntry(keyLandArtStatusByTypeAndAssetId(ARTPRESALE, landAssetId))) :+ DeleteEntry(keyLandArtStatusByTypeAssetIdAndOwner(ARTPRESALE, landAssetId, addr))) :+ DeleteEntry(keyLandNumToOwner(landNum))) :+ Burn(fromBase58String(landAssetId), 1)), props, removeByIndex(lands, value(idx)))
651661 }
652662 }
653663 }
657667 let bpKey = keyBackpackByDuck(duckAssetId)
658668 let currentPack = getBackpack(bpKey)
659669 let propStr = valueOrElse(getString(keyResProportions()), "0_0_0_0_0_0")
670+ let landsKey = keyStakedLandsByOwner(addr)
671+ let landsIn = split_51C(valueOrElse(getString(landsKey), ""), "_")
660672 let r = {
661673 let $l = landAssetIds
662674 let $s = size($l)
663- let $acc0 = $Tuple6(formula, 0, "", currentPack[bpIdxRes], nil, propStr)
675+ let $acc0 = $Tuple7(formula, 0, "", currentPack[bpIdxRes], nil, propStr, landsIn)
664676 func $f0_1 ($a,$i) = if (($i >= $s))
665677 then $a
666678 else checkMerge($a, $l[$i])
667679
668680 func $f0_2 ($a,$i) = if (($i >= $s))
669681 then $a
670- else throw("List size exceeds 4")
682+ else throw("List size exceeds 5")
671683
672- $f0_2($f0_1($f0_1($f0_1($f0_1($acc0, 0), 1), 2), 3), 4)
684+ $f0_2($f0_1($f0_1($f0_1($f0_1($f0_1($acc0, 0), 1), 2), 3), 4), 5)
673685 }
674686 let continent = r._3
675687 let continentIdx = valueOrErrorMessage(indexOf(continents, continent), ("Unknown continent: " + continent))
680692 let assetId = calculateAssetId(issue)
681693 let newLandAssetId = toBase58String(assetId)
682694 let newMat = makeString(subtractMaterials((needMat > 0), split(currentPack[bpIdxMat], "_"), needMat), "_")
683- $Tuple2((((((((((((((r._5 :+ IntegerEntry(keyNextFreeLandNum(), (freeNum + 1))) :+ issue) :+ StringEntry(keyLandToAssetId(newLandNum), newLandAssetId)) :+ StringEntry(keyLandAssetIdToOwner(newLandAssetId), addr)) :+ StringEntry(keyLandNumToOwner(newLandNum), addr)) :+ IntegerEntry(keyLandArtStatusByTypeAndAssetId(ARTPRESALE, newLandAssetId), r._2)) :+ IntegerEntry(keyLandArtStatusByTypeAssetIdAndOwner(ARTPRESALE, newLandAssetId, addr), r._2)) :+ IntegerEntry(keyInfraLevelByAssetId(newLandAssetId), newLevel)) :+ IntegerEntry(keyInfraLevelByAssetIdAndOwner(newLandAssetId, addr), newLevel)) :+ StringEntry(bpKey, makeString([currentPack[bpIdxLevel], r._4, newMat, currentPack[bpIdxProd]], ":"))) :+ StringEntry(keyResProportions(), r._6)) :+ StringEntry(keyDuckLocation(duckAssetId), makeString([continent, "L", newLandAssetId], "_"))) :+ ScriptTransfer(addressFromStringValue(addr), 1, assetId)), newLandAssetId)
695+ $Tuple2(((((((((((((((r._5 :+ (if ((size(r._7) > 0))
696+ then StringEntry(landsKey, makeString_11C(r._7, "_"))
697+ else DeleteEntry(landsKey))) :+ IntegerEntry(keyNextFreeLandNum(), (freeNum + 1))) :+ issue) :+ StringEntry(keyLandToAssetId(newLandNum), newLandAssetId)) :+ StringEntry(keyLandAssetIdToOwner(newLandAssetId), addr)) :+ StringEntry(keyLandNumToOwner(newLandNum), addr)) :+ IntegerEntry(keyLandArtStatusByTypeAndAssetId(ARTPRESALE, newLandAssetId), r._2)) :+ IntegerEntry(keyLandArtStatusByTypeAssetIdAndOwner(ARTPRESALE, newLandAssetId, addr), r._2)) :+ IntegerEntry(keyInfraLevelByAssetId(newLandAssetId), newLevel)) :+ IntegerEntry(keyInfraLevelByAssetIdAndOwner(newLandAssetId, addr), newLevel)) :+ StringEntry(bpKey, makeString([currentPack[bpIdxLevel], r._4, newMat, currentPack[bpIdxProd]], ":"))) :+ StringEntry(keyResProportions(), r._6)) :+ StringEntry(keyDuckLocation(duckAssetId), makeString([continent, "L", newLandAssetId], "_"))) :+ ScriptTransfer(addressFromStringValue(addr), 1, assetId)), newLandAssetId)
684698 }
685699
686700
737751 func saveTxId (addr,txId) = StringEntry(keyLastTxIdByUser(toString(addr)), toBase58String(txId))
738752
739753
754+func checkBlocked () = if (valueOrElse(getBoolean(keyBlocked()), false))
755+ then throw("Contracts are under maintenance")
756+ else unit
757+
758+
740759 @Callable(i)
741-func stakeLand () = if ((size(i.payments) != 1))
742- then throw("Exactly one payment required")
743- else {
744- let pmt = value(i.payments[0])
745- let assetId = value(pmt.assetId)
746- let address = toString(i.caller)
747- if ((pmt.amount != 1))
748- then throw((("NFT " + LANDPREFIX) + " token should be attached as payment"))
749- else {
750- let asset = value(assetInfo(assetId))
751- if ((asset.issuer != this))
752- then throw("Unknown issuer of token")
753- else if (!(contains(asset.name, LANDPREFIX)))
754- then throw((("Only NFT " + LANDPREFIX) + " tokens are accepted"))
755- else {
756- let landNumSize = drop(asset.name, 4)
757- let landNum = if (contains(landNumSize, "XXL"))
758- then dropRight(landNumSize, 3)
759- else if (contains(landNumSize, "XL"))
760- then dropRight(landNumSize, 2)
761- else dropRight(landNumSize, 1)
762- if (!(isDefined(parseInt(landNum))))
763- then throw(("Cannot parse land number from " + asset.name))
764- else {
765- let landAssetId = toBase58String(assetId)
766- let timeKey = keyStakedTimeByAssetId(landAssetId)
767- if (isDefined(getInteger(timeKey)))
768- then throw((("NFT " + asset.name) + " is already staked"))
769- else {
770- let d = split(asset.description, "_")
771- let terrainCounts = countTerrains(d[recTerrains])
772- let props = updateProportions(terrainCounts, (numPiecesBySize(d[recLandSize]) / SSIZE), 1)
773-[IntegerEntry(timeKey, lastBlock.timestamp), IntegerEntry(keyStakedTimeByTypeAssetIdAndOwner(LANDPREFIX, landAssetId, address), lastBlock.timestamp), StringEntry(keyLandAssetIdToOwner(landAssetId), address), StringEntry(keyLandNumToOwner(landNum), address), StringEntry(keyResProportions(), props)]
774- }
775- }
776- }
777- }
778- }
760+func setBlocked (isBlocked) = if ((i.caller != this))
761+ then throw("permission denied")
762+ else [BooleanEntry(keyBlocked(), isBlocked)]
779763
780764
781765
782766 @Callable(i)
783-func unstakeLand (landAssetIdStr) = if ((size(i.payments) != 0))
784- then throw("unstake doesn't require any payments")
785- else {
786- let addr = toString(i.caller)
787- let c = checkClaimConditions(addr)
788- let terrainCounts = countTerrains(c._3[recTerrains])
789- let pieces = numPiecesBySize(c._3[recLandSize])
790- let props = updateProportions(terrainCounts, (pieces / SSIZE), -1)
791- let claimResult = claimAll(addr, c._2, pieces)
792-[ScriptTransfer(i.caller, 1, fromBase58String(c._2)), DeleteEntry(keyStakedTimeByAssetId(c._2)), DeleteEntry(keyStakedTimeByTypeAssetIdAndOwner(LANDPREFIX, c._2, addr)), StringEntry(keyResProportions(), props), StringEntry(claimResult._2, makeString(claimResult._3, ":"))]
793- }
767+func stakeLand () = {
768+ let blocked = checkBlocked()
769+ if ((blocked == blocked))
770+ then if ((size(i.payments) != 1))
771+ then throw("Exactly one payment required")
772+ else {
773+ let pmt = value(i.payments[0])
774+ let assetId = value(pmt.assetId)
775+ let address = toString(i.caller)
776+ if ((pmt.amount != 1))
777+ then throw((("NFT " + LANDPREFIX) + " token should be attached as payment"))
778+ else {
779+ let asset = value(assetInfo(assetId))
780+ if ((asset.issuer != this))
781+ then throw("Unknown issuer of token")
782+ else if (!(contains(asset.name, LANDPREFIX)))
783+ then throw((("Only NFT " + LANDPREFIX) + " tokens are accepted"))
784+ else {
785+ let landNumSize = drop(asset.name, 4)
786+ let landNum = if (contains(landNumSize, "XXL"))
787+ then dropRight(landNumSize, 3)
788+ else if (contains(landNumSize, "XL"))
789+ then dropRight(landNumSize, 2)
790+ else dropRight(landNumSize, 1)
791+ if (!(isDefined(parseInt(landNum))))
792+ then throw(("Cannot parse land number from " + asset.name))
793+ else {
794+ let landAssetId = toBase58String(assetId)
795+ let timeKey = keyStakedTimeByAssetId(landAssetId)
796+ if (isDefined(getInteger(timeKey)))
797+ then throw((("NFT " + asset.name) + " is already staked"))
798+ else {
799+ let d = split(asset.description, "_")
800+ let terrainCounts = countTerrains(d[recTerrains])
801+ let props = updateProportions(terrainCounts, (numPiecesBySize(d[recLandSize]) / SSIZE), 1)
802+ let lands = split_51C(valueOrElse(getString(keyStakedLandsByOwner(address)), ""), "_")
803+ if (containsElement(lands, landAssetId))
804+ then throw(("Your staked lands already contain " + landAssetId))
805+ else [IntegerEntry(timeKey, lastBlock.timestamp), IntegerEntry(keyStakedTimeByTypeAssetIdAndOwner(LANDPREFIX, landAssetId, address), lastBlock.timestamp), StringEntry(keyStakedLandsByOwner(address), makeString_11C((lands :+ landAssetId), "_")), StringEntry(keyLandAssetIdToOwner(landAssetId), address), StringEntry(keyLandNumToOwner(landNum), address), StringEntry(keyResProportions(), props)]
806+ }
807+ }
808+ }
809+ }
810+ }
811+ else throw("Strict value is not equal to itself.")
812+ }
794813
795814
796815
797816 @Callable(i)
798-func stakeDuck () = if ((size(i.payments) != 1))
799- then throw("Exactly one payment required")
800- else {
801- let pmt = value(i.payments[0])
802- let assetId = value(pmt.assetId)
803- let address = toString(i.caller)
804- if ((pmt.amount != 1))
805- then throw((("NFT " + DUCKPREFIX) + " token should be attached as payment"))
817+func unstakeLand (landAssetIdIgnored) = {
818+ let blocked = checkBlocked()
819+ if ((blocked == blocked))
820+ then if ((size(i.payments) != 0))
821+ then throw("unstake doesn't require any payments")
806822 else {
807- let asset = value(assetInfo(assetId))
808- if (if ((asset.issuer != incubatorAddr))
809- then (asset.issuer != breederAddr)
810- else false)
811- then throw((("Unknown issuer of " + DUCKPREFIX) + " token"))
812- else if (!(contains(asset.name, DUCKPREFIX)))
813- then throw((("Only NFT " + DUCKPREFIX) + " tokens are accepted"))
814- else {
815- let assetIdStr = toBase58String(assetId)
816- let timeKey = keyStakedTimeByAssetId(assetIdStr)
817- if (isDefined(getInteger(timeKey)))
818- then throw((("NFT " + asset.name) + " is already staked"))
819- else if (isDefined(getString(keyStakedDuckByOwner(address))))
820- then throw(("You already staked one duck: " + asset.name))
821- else {
822- let locKey = keyDuckLocation(assetIdStr)
823- let location = getString(locKey)
824- let bpKey = keyBackpackByDuck(assetIdStr)
825- let backpack = getString(bpKey)
826- ([IntegerEntry(timeKey, lastBlock.timestamp), IntegerEntry(keyStakedTimeByTypeAssetIdAndOwner(DUCKPREFIX, toBase58String(assetId), address), lastBlock.timestamp), StringEntry(keyDuckIdToOwner(assetIdStr), address), StringEntry(keyStakedDuckByOwner(address), assetIdStr)] ++ (if (isDefined(location))
827- then nil
828- else ([StringEntry(locKey, DEFAULTLOCATION)] ++ (if (isDefined(backpack))
829- then nil
830- else ([StringEntry(bpKey, "0:0_0_0_0_0_0:0_0_0_0_0_0:")] :+ IntegerEntry(keyDuckHealth(assetIdStr), 100))))))
831- }
832- }
823+ let addr = toString(i.caller)
824+ let c = checkClaimConditions(addr)
825+ let landAssetId = c._2
826+ let landsKey = keyStakedLandsByOwner(addr)
827+ let terrainCounts = countTerrains(c._3[recTerrains])
828+ let pieces = numPiecesBySize(c._3[recLandSize])
829+ let props = updateProportions(terrainCounts, (pieces / SSIZE), -1)
830+ let claimResult = claimAll(addr, landAssetId, pieces)
831+ let lands = split_51C(valueOrElse(getString(landsKey), ""), "_")
832+ let idx = indexOf(lands, landAssetId)
833+ if (!(isDefined(idx)))
834+ then throw(("Your staked lands don't contain " + landAssetId))
835+ else [ScriptTransfer(i.caller, 1, fromBase58String(landAssetId)), DeleteEntry(keyStakedTimeByAssetId(landAssetId)), DeleteEntry(keyStakedTimeByTypeAssetIdAndOwner(LANDPREFIX, landAssetId, addr)), StringEntry(keyResProportions(), props), StringEntry(claimResult._2, makeString(claimResult._3, ":")), if ((size(lands) > 1))
836+ then StringEntry(landsKey, makeString_11C(removeByIndex(lands, value(idx)), "_"))
837+ else DeleteEntry(landsKey)]
833838 }
834- }
839+ else throw("Strict value is not equal to itself.")
840+ }
835841
836842
837843
838844 @Callable(i)
839-func unstakeDuck (assetIdStr) = if ((size(i.payments) != 0))
840- then throw("unstake doesn't require any payments")
841- else {
842- let assetId = fromBase58String(assetIdStr)
843- let address = toString(i.caller)
844- let asset = value(assetInfo(assetId))
845- let timeKey = keyStakedTimeByAssetId(toBase58String(assetId))
846- if (!(isDefined(timeKey)))
847- then throw((("NFT " + asset.name) + " is not staked"))
848- else if (!(isDefined(keyStakedDuckByOwner(address))))
849- then throw((("The duck " + asset.name) + " is not staked"))
850- else {
851- let owner = valueOrErrorMessage(getString(keyDuckIdToOwner(toBase58String(assetId))), (("NFT " + asset.name) + " is orphaned"))
852- if ((owner != address))
853- then throw("Staked NFT is not yours")
854- else {
855- let keyHealth = keyDuckHealth(assetIdStr)
856- let health = valueOrElse(getInteger(keyHealth), 100)
857- if ((health != 100))
858- then throw("Please heal your duck before unstaking")
859- else [ScriptTransfer(i.caller, 1, assetId), DeleteEntry(timeKey), DeleteEntry(keyHealth), DeleteEntry(keyDuckLocation(assetIdStr)), DeleteEntry(keyDuckIdToOwner(assetIdStr)), DeleteEntry(keyStakedTimeByTypeAssetIdAndOwner(DUCKPREFIX, assetIdStr, address)), DeleteEntry(keyStakedDuckByOwner(address))]
860- }
861- }
862- }
845+func stakeDuck () = {
846+ let blocked = checkBlocked()
847+ if ((blocked == blocked))
848+ then if ((size(i.payments) != 1))
849+ then throw("Exactly one payment required")
850+ else {
851+ let pmt = value(i.payments[0])
852+ let assetId = value(pmt.assetId)
853+ let address = toString(i.caller)
854+ if ((pmt.amount != 1))
855+ then throw((("NFT " + DUCKPREFIX) + " token should be attached as payment"))
856+ else {
857+ let asset = value(assetInfo(assetId))
858+ if (if ((asset.issuer != incubatorAddr))
859+ then (asset.issuer != breederAddr)
860+ else false)
861+ then throw((("Unknown issuer of " + DUCKPREFIX) + " token"))
862+ else if (!(contains(asset.name, DUCKPREFIX)))
863+ then throw((("Only NFT " + DUCKPREFIX) + " tokens are accepted"))
864+ else {
865+ let assetIdStr = toBase58String(assetId)
866+ let timeKey = keyStakedTimeByAssetId(assetIdStr)
867+ if (isDefined(getInteger(timeKey)))
868+ then throw((("NFT " + asset.name) + " is already staked"))
869+ else if (isDefined(getString(keyStakedDuckByOwner(address))))
870+ then throw(("You already staked one duck: " + asset.name))
871+ else {
872+ let locKey = keyDuckLocation(assetIdStr)
873+ let location = getString(locKey)
874+ let bpKey = keyBackpackByDuck(assetIdStr)
875+ let backpack = getString(bpKey)
876+ ([IntegerEntry(timeKey, lastBlock.timestamp), IntegerEntry(keyStakedTimeByTypeAssetIdAndOwner(DUCKPREFIX, toBase58String(assetId), address), lastBlock.timestamp), StringEntry(keyDuckIdToOwner(assetIdStr), address), StringEntry(keyStakedDuckByOwner(address), assetIdStr)] ++ (if (isDefined(location))
877+ then nil
878+ else ([StringEntry(locKey, DEFAULTLOCATION)] ++ (if (isDefined(backpack))
879+ then nil
880+ else ([StringEntry(bpKey, "0:0_0_0_0_0_0:0_0_0_0_0_0:")] :+ IntegerEntry(keyDuckHealth(assetIdStr), 100))))))
881+ }
882+ }
883+ }
884+ }
885+ else throw("Strict value is not equal to itself.")
886+ }
863887
864888
865889
866890 @Callable(i)
867-func claimRes (amount,landAssetIdStr) = if ((size(i.payments) != 0))
868- then throw("claimRes doesn't require any payments")
869- else {
870- let addr = toString(i.originCaller)
871- let result = claimResInternal(addr, amount)
872- $Tuple2((result._1 :+ StringEntry(result._2, makeString(result._3, ":"))), result._3[bpIdxRes])
873- }
891+func unstakeDuck (assetIdStr) = {
892+ let blocked = checkBlocked()
893+ if ((blocked == blocked))
894+ then if ((size(i.payments) != 0))
895+ then throw("unstake doesn't require any payments")
896+ else {
897+ let assetId = fromBase58String(assetIdStr)
898+ let address = toString(i.caller)
899+ let asset = value(assetInfo(assetId))
900+ let timeKey = keyStakedTimeByAssetId(toBase58String(assetId))
901+ if (!(isDefined(timeKey)))
902+ then throw((("NFT " + asset.name) + " is not staked"))
903+ else if (!(isDefined(keyStakedDuckByOwner(address))))
904+ then throw((("The duck " + asset.name) + " is not staked"))
905+ else {
906+ let owner = valueOrErrorMessage(getString(keyDuckIdToOwner(toBase58String(assetId))), (("NFT " + asset.name) + " is orphaned"))
907+ if ((owner != address))
908+ then throw("Staked NFT is not yours")
909+ else {
910+ let keyHealth = keyDuckHealth(assetIdStr)
911+ let health = valueOrElse(getInteger(keyHealth), 100)
912+ if ((health != 100))
913+ then throw("Please heal your duck before unstaking")
914+ else [ScriptTransfer(i.caller, 1, assetId), DeleteEntry(timeKey), DeleteEntry(keyHealth), DeleteEntry(keyDuckLocation(assetIdStr)), DeleteEntry(keyDuckIdToOwner(assetIdStr)), DeleteEntry(keyStakedTimeByTypeAssetIdAndOwner(DUCKPREFIX, assetIdStr, address)), DeleteEntry(keyStakedDuckByOwner(address))]
915+ }
916+ }
917+ }
918+ else throw("Strict value is not equal to itself.")
919+ }
874920
875921
876922
877923 @Callable(i)
878-func flight (message,sig) = if (!(sigVerify_8Kb(message, sig, pub)))
879- then throw("signature does not match")
880- else if ((size(i.payments) != 0))
881- then throw("flight doesn't require any payments")
882- else {
883- let parts = split(toUtf8String(message), ";")
884- let hp = split(split(parts[0], "|")[0], "_")
885- let curHP = parseIntValue(hp[0])
886- let newHP = parseIntValue(hp[1])
887- let newLocAndTime = split(parts[1], ":")
888- let newLocation = newLocAndTime[0]
889- let time = parseIntValue(newLocAndTime[1])
890- if (if ((time > (lastBlock.timestamp + FIVEMINUTESMILLIS)))
891- then true
892- else ((lastBlock.timestamp - FIVEMINUTESMILLIS) > time))
893- then throw("signature outdated")
894- else {
895- let duckAssetId = valueOrErrorMessage(getString(keyStakedDuckByOwner(toString(i.caller))), "You don't have a duck staked")
896- let keyHealth = keyDuckHealth(duckAssetId)
897- let oldFromState = valueOrElse(getInteger(keyHealth), 100)
898- if ((oldFromState != curHP))
899- then throw(((("oldHealth=" + toString(valueOrElse(getInteger(keyHealth), 100))) + " from state does not match one from flight log=") + toString(curHP)))
900- else if ((0 >= curHP))
901- then throw("You can't fly with zero health")
902- else {
903- let locKey = keyDuckLocation(duckAssetId)
904- let curLocation = valueOrElse(getString(locKey), DEFAULTLOCATION)
905- if ((newLocation == curLocation))
906- then throw("You can't fly to the same location")
907- else $Tuple2([StringEntry(locKey, if ((newHP > 0))
908- then newLocation
909- else curLocation), IntegerEntry(keyHealth, newHP)], unit)
910- }
911- }
912- }
924+func claimRes (amount,landAssetIdStr) = {
925+ let blocked = checkBlocked()
926+ if ((blocked == blocked))
927+ then if ((size(i.payments) != 0))
928+ then throw("claimRes doesn't require any payments")
929+ else {
930+ let addr = toString(i.originCaller)
931+ let result = claimResInternal(addr, amount)
932+ $Tuple2((result._1 :+ StringEntry(result._2, makeString(result._3, ":"))), result._3[bpIdxRes])
933+ }
934+ else throw("Strict value is not equal to itself.")
935+ }
913936
914937
915938
916939 @Callable(i)
917-func setHealth (health,duckAssetId) = if (if ((0 > health))
918- then true
919- else (health > 100))
920- then throw("HP should be within 0..100")
921- else [IntegerEntry(keyDuckHealth(duckAssetId), health)]
940+func flight (message,sig) = {
941+ let blocked = checkBlocked()
942+ if ((blocked == blocked))
943+ then if (!(sigVerify_8Kb(message, sig, pub)))
944+ then throw("signature does not match")
945+ else if ((size(i.payments) != 0))
946+ then throw("flight doesn't require any payments")
947+ else {
948+ let parts = split(toUtf8String(message), ";")
949+ let hp = split(split(parts[0], "|")[0], "_")
950+ let curHP = parseIntValue(hp[0])
951+ let newHP = parseIntValue(hp[1])
952+ let newLocAndTime = split(parts[1], ":")
953+ let newLocation = newLocAndTime[0]
954+ let time = parseIntValue(newLocAndTime[1])
955+ if (if ((time > (lastBlock.timestamp + FIVEMINUTESMILLIS)))
956+ then true
957+ else ((lastBlock.timestamp - FIVEMINUTESMILLIS) > time))
958+ then throw("signature outdated")
959+ else {
960+ let duckAssetId = valueOrErrorMessage(getString(keyStakedDuckByOwner(toString(i.caller))), "You don't have a duck staked")
961+ let keyHealth = keyDuckHealth(duckAssetId)
962+ let oldFromState = valueOrElse(getInteger(keyHealth), 100)
963+ if ((oldFromState != curHP))
964+ then throw(((("oldHealth=" + toString(valueOrElse(getInteger(keyHealth), 100))) + " from state does not match one from flight log=") + toString(curHP)))
965+ else if ((0 >= curHP))
966+ then throw("You can't fly with zero health")
967+ else {
968+ let locKey = keyDuckLocation(duckAssetId)
969+ let curLocation = valueOrElse(getString(locKey), DEFAULTLOCATION)
970+ if ((newLocation == curLocation))
971+ then throw("You can't fly to the same location")
972+ else $Tuple2([StringEntry(locKey, if ((newHP > 0))
973+ then newLocation
974+ else curLocation), IntegerEntry(keyHealth, newHP)], unit)
975+ }
976+ }
977+ }
978+ else throw("Strict value is not equal to itself.")
979+ }
922980
923981
924982
925983 @Callable(i)
926-func heal (matType,amount) = if (if ((0 > matType))
927- then true
928- else (matType >= NUMRES))
929- then throw(("Unknown material: " + toString(matType)))
930- else if ((0 >= amount))
931- then throw(("Amount should be positive! " + toString(amount)))
932- else {
933- let duckAssetId = valueOrErrorMessage(getString(keyStakedDuckByOwner(toString(i.caller))), "You don't have a duck staked")
934- let keyHealth = keyDuckHealth(duckAssetId)
935- let oldHealth = valueOrElse(getInteger(keyHealth), 100)
936- if ((oldHealth >= 100))
937- then throw("HP should be < 100 to heal")
984+func setHealth (health,duckAssetId) = {
985+ let blocked = checkBlocked()
986+ if ((blocked == blocked))
987+ then if (if ((0 > health))
988+ then true
989+ else (health > 100))
990+ then throw("HP should be within 0..100")
991+ else [IntegerEntry(keyDuckHealth(duckAssetId), health)]
992+ else throw("Strict value is not equal to itself.")
993+ }
994+
995+
996+
997+@Callable(i)
998+func heal (matType,amount) = {
999+ let blocked = checkBlocked()
1000+ if ((blocked == blocked))
1001+ then if (if ((0 > matType))
1002+ then true
1003+ else (matType >= NUMRES))
1004+ then throw(("Unknown material: " + toString(matType)))
1005+ else if ((0 >= amount))
1006+ then throw(("Amount should be positive! " + toString(amount)))
9381007 else {
939- let bpKey = keyBackpackByDuck(duckAssetId)
940- let currentPack = getBackpack(bpKey)
941- let mList = split(currentPack[bpIdxMat], "_")
942- let currentAmount = parseIntValue(mList[matType])
943- let deltaHealth = min([(amount / HEALCOST), (100 - oldHealth)])
944- let spendAmount = (deltaHealth * HEALCOST)
945- if ((spendAmount > currentAmount))
946- then throw(((((("You need " + toString(spendAmount)) + " of ") + matTypes[matType]) + " to heal, but you backpack contains ") + toString(currentAmount)))
1008+ let duckAssetId = valueOrErrorMessage(getString(keyStakedDuckByOwner(toString(i.caller))), "You don't have a duck staked")
1009+ let keyHealth = keyDuckHealth(duckAssetId)
1010+ let oldHealth = valueOrElse(getInteger(keyHealth), 100)
1011+ if ((oldHealth >= 100))
1012+ then throw("HP should be < 100 to heal")
9471013 else {
948- let newMat = subOneInList(mList, matType, spendAmount)
1014+ let bpKey = keyBackpackByDuck(duckAssetId)
1015+ let currentPack = getBackpack(bpKey)
1016+ let mList = split(currentPack[bpIdxMat], "_")
1017+ let currentAmount = parseIntValue(mList[matType])
1018+ let deltaHealth = min([(amount / HEALCOST), (100 - oldHealth)])
1019+ let spendAmount = (deltaHealth * HEALCOST)
1020+ if ((spendAmount > currentAmount))
1021+ then throw(((((("You need " + toString(spendAmount)) + " of ") + matTypes[matType]) + " to heal, but you backpack contains ") + toString(currentAmount)))
1022+ else {
1023+ let newMat = subOneInList(mList, matType, spendAmount)
9491024 [IntegerEntry(keyHealth, (oldHealth + deltaHealth)), StringEntry(bpKey, makeString([currentPack[bpIdxLevel], currentPack[bpIdxRes], newMat, currentPack[bpIdxProd]], ":"))]
1025+ }
9501026 }
9511027 }
952- }
1028+ else throw("Strict value is not equal to itself.")
1029+ }
9531030
9541031
9551032
9611038
9621039
9631040 @Callable(i)
964-func expeditionBuy (message,sig) = if ((size(i.payments) != 1))
965- then throw("Exactly one payment required")
966- else {
967- let pmt = value(i.payments[0])
968- if ((pmt.assetId != usdnAssetId))
969- then throw("Allowed USDN payment only!")
970- else if ((pmt.amount != EXPUSDN))
971- then throw(("Payment attached should be " + toString(EXPUSDN)))
972- else {
973- let result = expeditionCommon(false, i.caller, i.transactionId, message, sig)
974- if ((result._2 == ""))
975- then result
976- else $Tuple2((result._1 :+ ScriptTransfer(economyContract, pmt.amount, usdnAssetId)), result._2)
977- }
978- }
1041+func expeditionBuy (message,sig) = {
1042+ let blocked = checkBlocked()
1043+ if ((blocked == blocked))
1044+ then if ((size(i.payments) != 1))
1045+ then throw("Exactly one payment required")
1046+ else {
1047+ let pmt = value(i.payments[0])
1048+ if ((pmt.assetId != usdnAssetId))
1049+ then throw("Allowed USDN payment only!")
1050+ else if ((pmt.amount != EXPUSDN))
1051+ then throw(("Payment attached should be " + toString(EXPUSDN)))
1052+ else {
1053+ let result = expeditionCommon(false, i.caller, i.transactionId, message, sig)
1054+ if ((result._2 == ""))
1055+ then result
1056+ else $Tuple2((result._1 :+ ScriptTransfer(economyContract, pmt.amount, usdnAssetId)), result._2)
1057+ }
1058+ }
1059+ else throw("Strict value is not equal to itself.")
1060+ }
9791061
9801062
9811063
9821064 @Callable(i)
983-func expedition (message,sig) = if ((size(i.payments) != 0))
984- then throw("expedition doesn't require any payments")
985- else expeditionCommon(true, i.caller, i.transactionId, message, sig)
1065+func expedition (message,sig) = {
1066+ let blocked = checkBlocked()
1067+ if ((blocked == blocked))
1068+ then if ((size(i.payments) != 0))
1069+ then throw("expedition doesn't require any payments")
1070+ else expeditionCommon(true, i.caller, i.transactionId, message, sig)
1071+ else throw("Strict value is not equal to itself.")
1072+ }
9861073
9871074
9881075
9891076 @Callable(i)
990-func upgradeInfra (landAssetIdIgnored) = if ((size(i.payments) != 0))
991- then throw("Infrastructure upgrade doesn't require any payments")
992- else upInfraCommon(true, i.caller, 0)
1077+func upgradeInfra (landAssetIdIgnored) = {
1078+ let blocked = checkBlocked()
1079+ if ((blocked == blocked))
1080+ then if ((size(i.payments) != 0))
1081+ then throw("Infrastructure upgrade doesn't require any payments")
1082+ else upInfraCommon(true, i.caller, 0)
1083+ else throw("Strict value is not equal to itself.")
1084+ }
9931085
9941086
9951087
9961088 @Callable(i)
997-func upgradeInfraUsdn (landAssetIdIgnored) = if ((size(i.payments) != 1))
998- then throw("Exactly one payment required")
999- else {
1000- let pmt = value(i.payments[0])
1001- if ((pmt.assetId != usdnAssetId))
1002- then throw("Allowed USDN payment only!")
1089+func upgradeInfraUsdn (landAssetIdIgnored) = {
1090+ let blocked = checkBlocked()
1091+ if ((blocked == blocked))
1092+ then if ((size(i.payments) != 1))
1093+ then throw("Exactly one payment required")
10031094 else {
1004- let result = upInfraCommon(false, i.caller, pmt.amount)
1005- $Tuple2((result._1 :+ ScriptTransfer(economyContract, pmt.amount, usdnAssetId)), result._2)
1095+ let pmt = value(i.payments[0])
1096+ if ((pmt.assetId != usdnAssetId))
1097+ then throw("Allowed USDN payment only!")
1098+ else {
1099+ let result = upInfraCommon(false, i.caller, pmt.amount)
1100+ $Tuple2((result._1 :+ ScriptTransfer(economyContract, pmt.amount, usdnAssetId)), result._2)
1101+ }
10061102 }
1007- }
1103+ else throw("Strict value is not equal to itself.")
1104+ }
10081105
10091106
10101107
10111108 @Callable(i)
1012-func activateArtifact (artName) = if ((size(i.payments) != 0))
1013- then throw("Artifact activation doesn't require any payments")
1014- else {
1015- let result = match artName {
1016- case _ =>
1017- if (("PRESALE" == $match0))
1018- then activatePresaleArt(toString(i.caller))
1019- else throw("Unknown artifact")
1020- }
1021- result
1022- }
1109+func activateArtifact (artName) = {
1110+ let blocked = checkBlocked()
1111+ if ((blocked == blocked))
1112+ then if ((size(i.payments) != 0))
1113+ then throw("Artifact activation doesn't require any payments")
1114+ else {
1115+ let result = match artName {
1116+ case _ =>
1117+ if (("PRESALE" == $match0))
1118+ then activatePresaleArt(toString(i.caller))
1119+ else throw("Unknown artifact")
1120+ }
1121+ result
1122+ }
1123+ else throw("Strict value is not equal to itself.")
1124+ }
10231125
10241126
10251127
10261128 @Callable(i)
10271129 func mergeLands (landAssetIds) = if ((i.caller != this))
10281130 then throw("permission denied")
1029- else if ((size(i.payments) != 0))
1030- then throw("Lands merging doesn't require any payments")
1031- else mergeCommon(true, toString(i.caller), 0, landAssetIds, i.transactionId)
1131+ else {
1132+ let blocked = checkBlocked()
1133+ if ((blocked == blocked))
1134+ then if ((size(i.payments) != 0))
1135+ then throw("Lands merging doesn't require any payments")
1136+ else mergeCommon(true, toString(i.caller), 0, landAssetIds, i.transactionId)
1137+ else throw("Strict value is not equal to itself.")
1138+ }
10321139
10331140
10341141
10351142 @Callable(i)
10361143 func mergeLandsUsdn (landAssetIds) = if ((i.caller != this))
10371144 then throw("permission denied")
1038- else if ((size(i.payments) != 1))
1039- then throw("Exactly one payment required")
1040- else {
1041- let pmt = value(i.payments[0])
1042- if ((pmt.assetId != usdnAssetId))
1043- then throw("Allowed USDN payment only!")
1145+ else {
1146+ let blocked = checkBlocked()
1147+ if ((blocked == blocked))
1148+ then if ((size(i.payments) != 1))
1149+ then throw("Exactly one payment required")
10441150 else {
1045- let result = mergeCommon(false, toString(i.caller), pmt.amount, landAssetIds, i.transactionId)
1046- $Tuple2((result._1 :+ ScriptTransfer(economyContract, pmt.amount, usdnAssetId)), result._2)
1151+ let pmt = value(i.payments[0])
1152+ if ((pmt.assetId != usdnAssetId))
1153+ then throw("Allowed USDN payment only!")
1154+ else {
1155+ let result = mergeCommon(false, toString(i.caller), pmt.amount, landAssetIds, i.transactionId)
1156+ $Tuple2((result._1 :+ ScriptTransfer(economyContract, pmt.amount, usdnAssetId)), result._2)
1157+ }
10471158 }
1048- }
1159+ else throw("Strict value is not equal to itself.")
1160+ }
10491161
10501162
10511163
Full:
OldNewDifferences
11 {-# STDLIB_VERSION 6 #-}
22 {-# SCRIPT_TYPE ACCOUNT #-}
33 {-# CONTENT_TYPE DAPP #-}
44 let chain = take(drop(this.bytes, 1), 1)
55
66 let usdnAssetId = match chain {
77 case _ =>
88 if ((base58'2W' == $match0))
99 then base58'DG2xFkPdDwKUoBkzGAhQtLpSGzfXLiCYPEzeKH2Ad24p'
1010 else if ((base58'2T' == $match0))
1111 then base58'HezsdQuRDtzksAYUy97gfhKy7Z1NW2uXYSHA3bgqenNZ'
1212 else throw("Unknown chain")
1313 }
1414
1515 let incubatorAddr = match chain {
1616 case _ =>
1717 if ((base58'2W' == $match0))
1818 then addressFromStringValue("3PEktVux2RhchSN63DsDo4b4mz4QqzKSeDv")
1919 else if ((base58'2T' == $match0))
2020 then this
2121 else throw("Unknown chain")
2222 }
2323
2424 let breederAddr = match chain {
2525 case _ =>
2626 if ((base58'2W' == $match0))
2727 then addressFromStringValue("3PDVuU45H7Eh5dmtNbnRNRStGwULA7NY6Hb")
2828 else if ((base58'2T' == $match0))
2929 then this
3030 else throw("Unknown chain")
3131 }
3232
3333 let economyContract = addressFromStringValue(match chain {
3434 case _ =>
3535 if ((base58'2W' == $match0))
3636 then "3P2sk1KncSxRaZs8b4CWGPw2jkvvav74u4D"
3737 else if ((base58'2T' == $match0))
3838 then "3N8y4wxX3JC4TdrCJBXX16SjWf6X256hrep"
3939 else throw("Unknown chain")
4040 })
4141
4242 let pub = base58'6LfPuKJjLgekmncBhMg2LZyMTNVzZBccXR28ySXm9uXD'
4343
4444 let HEALCOST = 10000
4545
4646 let LANDPREFIX = "LAND"
4747
4848 let DUCKPREFIX = "DUCK"
4949
5050 let DEFAULTLOCATION = "Africa_F_Africa"
5151
5252 let NUMRES = 6
5353
5454 let SSIZE = 25
5555
5656 let MSIZE = 100
5757
5858 let LSIZE = 225
5959
6060 let XLSIZE = 400
6161
6262 let XXLSIZE = 625
6363
6464 let DAILYRESBYPIECE = 3456000
6565
6666 let DAYMILLIS = 86400000
6767
6868 let FIVEMINUTESMILLIS = 300000
6969
7070 let RESOURCEPRICEMIN = 158549
7171
7272 let InfraUpgradeCostS = match chain {
7373 case _ =>
7474 if ((base58'2W' == $match0))
7575 then 6307198406
7676 else if ((base58'2T' == $match0))
7777 then 63071984
7878 else throw("Unknown chain")
7979 }
8080
8181 let InfraUpgradeCostSUsdn = match chain {
8282 case _ =>
8383 if ((base58'2W' == $match0))
8484 then 40000000
8585 else if ((base58'2T' == $match0))
8686 then 400000
8787 else throw("Unknown chain")
8888 }
8989
9090 let EXPMATERIALS = match chain {
9191 case _ =>
9292 if ((base58'2W' == $match0))
9393 then 157679960139
9494 else if ((base58'2T' == $match0))
9595 then 1576799601
9696 else throw("Unknown chain")
9797 }
9898
9999 let EXPUSDN = match chain {
100100 case _ =>
101101 if ((base58'2W' == $match0))
102102 then 1000000000
103103 else if ((base58'2T' == $match0))
104104 then 10000000
105105 else throw("Unknown chain")
106106 }
107107
108108 let MULT6 = 1000000
109109
110110 let FIVEX = toBigInt(5)
111111
112112 let TWENTYX = toBigInt(20)
113113
114114 let TWENTY2X = toBigInt((20 * 20))
115115
116116 let TWENTY3X = toBigInt(((20 * 20) * 20))
117117
118118 let TWENTY4X = toBigInt((((20 * 20) * 20) * 20))
119119
120120 let TWENTY5X = toBigInt(((((20 * 20) * 20) * 20) * 20))
121121
122122 let matTypes = ["Fuel", "Metal", "Plank", "Glass", "Plastic", "Protein"]
123123
124124 let continents = ["Asia", "Europe", "Americas", "Oceania", "Africa"]
125125
126126 let ARTPRESALE = "PRESALE"
127127
128128 let PRESALENUMLANDS = 500
129129
130130 func keyLastTxIdByUser (addr) = ("lastTxIdByUser_" + addr)
131131
132132
133133 func keyNextFreeLandNum () = "nextLandNum"
134134
135135
136136 func keyLandToAssetId (landNum) = ("landToAsset_" + landNum)
137137
138138
139139 func keyNftName (landNum,landSize) = ((LANDPREFIX + landNum) + landSize)
140140
141141
142142 func keyLandAssetIdToOwner (assetId) = ("nftOwner_" + assetId)
143143
144144
145145 func keyDuckIdToOwner (assetId) = ("duckOwner_" + assetId)
146146
147147
148148 func keyStakedTimeByAssetId (assetId) = ("stakedTime_" + assetId)
149149
150150
151151 func keyInfraLevelByAssetId (assetId) = ("infraLevel_" + assetId)
152152
153153
154154 func keyInfraLevelByAssetIdAndOwner (assetId,ownerAddr) = ((("infraLevelByAssetIdAndOwner_" + assetId) + "_") + ownerAddr)
155155
156156
157157 func keyPresaleArtActivatedByAssetId (assetId) = ("presaleArtActivated_" + assetId)
158158
159159
160160 func keyPresaleArtActivatedByAssetIdAndOwner (assetId,ownerAddr) = ((("presaleArtActivatedByAssetIdAndOwner_" + assetId) + "_") + ownerAddr)
161161
162162
163163 func keyLandArtStatusByTypeAndAssetId (type,assetId) = makeString(["landArtStatus", type, assetId], "_")
164164
165165
166166 func keyLandArtStatusByTypeAssetIdAndOwner (type,assetId,ownerAddr) = makeString(["landArtStatusByTypeAssetIdAndOwner", type, assetId, ownerAddr], "_")
167167
168168
169169 func keyStakedDuckByOwner (ownerAddr) = ("stakedDuckByOwner_" + ownerAddr)
170170
171171
172172 func keyStakedTimeByTypeAssetIdAndOwner (nftType,assetId,ownerAddr) = ((((("stakedTimeByTypeAssetIdAndOwner_" + nftType) + "_") + assetId) + "_") + ownerAddr)
173173
174174
175175 func keyLandNumToOwner (landNum) = ("landOwner_" + landNum)
176176
177177
178178 func keyBackpackByDuck (duckAssetId) = ("backPack_" + duckAssetId)
179179
180180
181181 func keyDuckLocation (duckAssetId) = ("duckLocation_" + duckAssetId)
182182
183183
184184 func keyDuckHealth (duckAssetId) = ("duckHealth_" + duckAssetId)
185185
186186
187187 func keyResProportions () = "resTypesProportions"
188+
189+
190+func keyStakedLandsByOwner (ownerAddr) = ("stakedLandsByOwner_" + ownerAddr)
191+
192+
193+func keyBlocked () = "contractsBlocked"
188194
189195
190196 let recLandNum = 0
191197
192198 let recLandSize = 1
193199
194200 let recTerrains = 2
195201
196202 let recContinent = 3
197203
198204 let locIdxContinent = 0
199205
200206 let locIdxType = 1
201207
202208 let locIdxId = 2
203209
204210 let bpIdxLevel = 0
205211
206212 let bpIdxRes = 1
207213
208214 let bpIdxMat = 2
209215
210216 let bpIdxProd = 3
211217
212218 func asString (v) = match v {
213219 case s: String =>
214220 s
215221 case _ =>
216222 throw("fail to cast into String")
217223 }
218224
219225
220226 func distributeByWeights (total,weights) = {
221227 let sum = (((((weights[0] + weights[1]) + weights[2]) + weights[3]) + weights[4]) + weights[5])
222228 if ((0 >= sum))
223229 then throw("Zero weights sum")
224230 else {
225231 let norm6 = fraction(total, MULT6, sum)
226232 func normalizer (acc,elem) = (acc :+ fraction(elem, norm6, MULT6))
227233
228234 let $l = weights
229235 let $s = size($l)
230236 let $acc0 = nil
231237 func $f0_1 ($a,$i) = if (($i >= $s))
232238 then $a
233239 else normalizer($a, $l[$i])
234240
235241 func $f0_2 ($a,$i) = if (($i >= $s))
236242 then $a
237243 else throw("List size exceeds 6")
238244
239245 $f0_2($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($acc0, 0), 1), 2), 3), 4), 5), 6)
240246 }
241247 }
242248
243249
244250 func getNeededMaterials (total) = {
245251 let props = split(value(getString(keyResProportions())), "_")
246252 if ((size(props) != NUMRES))
247253 then throw("Wrong proportions data")
248254 else {
249255 let r = [parseIntValue(props[0]), parseIntValue(props[1]), parseIntValue(props[2]), parseIntValue(props[3]), parseIntValue(props[4]), parseIntValue(props[5])]
250256 distributeByWeights(total, r)
251257 }
252258 }
253259
254260
255261 func subtractMaterials (shouldUseMat,has,totalNeed) = {
256262 let need = getNeededMaterials(totalNeed)
257263 func subtractor (acc,idx) = {
258264 let result = (parseIntValue(has[idx]) - need[idx])
259265 if ((0 > result))
260266 then throw(((((("Not enough material idx=" + toString(idx)) + ", you have ") + has[idx]) + ", but need ") + toString(need[idx])))
261267 else (acc :+ toString(result))
262268 }
263269
264270 if (shouldUseMat)
265271 then {
266272 let $l = [0, 1, 2, 3, 4, 5]
267273 let $s = size($l)
268274 let $acc0 = nil
269275 func $f0_1 ($a,$i) = if (($i >= $s))
270276 then $a
271277 else subtractor($a, $l[$i])
272278
273279 func $f0_2 ($a,$i) = if (($i >= $s))
274280 then $a
275281 else throw("List size exceeds 6")
276282
277283 $f0_2($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($acc0, 0), 1), 2), 3), 4), 5), 6)
278284 }
279285 else has
280286 }
281287
282288
283289 func updateProportionsInternal (propList,terrainCounts,landSizeIndex,sign) = if ((size(propList) != NUMRES))
284290 then throw("Wrong proportions data")
285291 else {
286292 func updater (acc,i) = {
287293 let result = (parseIntValue(propList[i]) + ((sign * terrainCounts[i]) * landSizeIndex))
288294 if ((0 > result))
289295 then throw(((((((("Panic! Pieces of type=" + toString(i)) + ", sign=") + toString(sign)) + ", terrainCounts[i]=") + toString(terrainCounts[i])) + ", landSizeIndex=") + toString(landSizeIndex)))
290296 else (acc :+ toString(result))
291297 }
292298
293299 let r = {
294300 let $l = [0, 1, 2, 3, 4, 5]
295301 let $s = size($l)
296302 let $acc0 = nil
297303 func $f0_1 ($a,$i) = if (($i >= $s))
298304 then $a
299305 else updater($a, $l[$i])
300306
301307 func $f0_2 ($a,$i) = if (($i >= $s))
302308 then $a
303309 else throw("List size exceeds 6")
304310
305311 $f0_2($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($acc0, 0), 1), 2), 3), 4), 5), 6)
306312 }
307313 makeString(r, "_")
308314 }
309315
310316
311317 func updateProportions (terrainCounts,landSizeIndex,sign) = {
312318 let propList = split(valueOrElse(getString(keyResProportions()), "0_0_0_0_0_0"), "_")
313319 updateProportionsInternal(propList, terrainCounts, landSizeIndex, sign)
314320 }
315321
316322
317323 func countTerrains (terrains) = [(size(split(terrains, "A")) - 1), (size(split(terrains, "B")) - 1), (size(split(terrains, "C")) - 1), (size(split(terrains, "D")) - 1), (size(split(terrains, "E")) - 1), (size(split(terrains, "F")) - 1)]
318324
319325
320326 func numPiecesBySize (landSize) = match landSize {
321327 case _ =>
322328 if (("S" == $match0))
323329 then SSIZE
324330 else if (("M" == $match0))
325331 then MSIZE
326332 else if (("L" == $match0))
327333 then LSIZE
328334 else if (("XL" == $match0))
329335 then XLSIZE
330336 else if (("XXL" == $match0))
331337 then XXLSIZE
332338 else throw("Unknown land size")
333339 }
334340
335341
336342 func subOneInList (aList,idx,amount) = {
337343 func subber (acc,i) = (acc :+ (if ((i == idx))
338344 then toString((parseIntValue(aList[i]) - amount))
339345 else aList[i]))
340346
341347 let r = {
342348 let $l = [0, 1, 2, 3, 4, 5]
343349 let $s = size($l)
344350 let $acc0 = nil
345351 func $f0_1 ($a,$i) = if (($i >= $s))
346352 then $a
347353 else subber($a, $l[$i])
348354
349355 func $f0_2 ($a,$i) = if (($i >= $s))
350356 then $a
351357 else throw("List size exceeds 6")
352358
353359 $f0_2($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($acc0, 0), 1), 2), 3), 4), 5), 6)
354360 }
355361 makeString(r, "_")
356362 }
357363
358364
359365 func addRes (currentRes,terrainCounts,deltaTime,landSizeIndex,dailyByPieceWithBonuses) = {
360366 func adder (acc,i) = {
361367 let resOfType = ((fraction(deltaTime, dailyByPieceWithBonuses, DAYMILLIS) * terrainCounts[i]) * landSizeIndex)
362368 (acc :+ toString((parseIntValue(currentRes[i]) + resOfType)))
363369 }
364370
365371 let r = {
366372 let $l = [0, 1, 2, 3, 4, 5]
367373 let $s = size($l)
368374 let $acc0 = nil
369375 func $f0_1 ($a,$i) = if (($i >= $s))
370376 then $a
371377 else adder($a, $l[$i])
372378
373379 func $f0_2 ($a,$i) = if (($i >= $s))
374380 then $a
375381 else throw("List size exceeds 6")
376382
377383 $f0_2($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($acc0, 0), 1), 2), 3), 4), 5), 6)
378384 }
379385 makeString(r, "_")
380386 }
381387
382388
383389 func abs (x) = if ((x >= toBigInt(0)))
384390 then x
385391 else -(x)
386392
387393
388394 let freq = [[1, 4, 9, 10, 15], [5, 8, 13, 14, 15], [6, 9, 14, 15, 16], [4, 7, 8, 13, 18], [1, 6, 7, 15, 19]]
389395
390396 func genChar (n,freqs) = {
391397 let rem = toInt((n % TWENTYX))
392398 let letter = if ((freqs[0] > rem))
393399 then "A"
394400 else if ((freqs[1] > rem))
395401 then "B"
396402 else if ((freqs[2] > rem))
397403 then "C"
398404 else if ((freqs[3] > rem))
399405 then "D"
400406 else if ((freqs[4] > rem))
401407 then "E"
402408 else "F"
403409 letter
404410 }
405411
406412
407413 func genTerrains (seed,continentIdx) = {
408414 let f = freq[continentIdx]
409415 func terrainGenerator (acc,elem) = $Tuple2((((((acc._1 + genChar(acc._2, f)) + genChar((acc._2 / TWENTYX), f)) + genChar((acc._2 / TWENTY2X), f)) + genChar((acc._2 / TWENTY3X), f)) + genChar((acc._2 / TWENTY4X), f)), (acc._2 / TWENTY5X))
410416
411417 let t = {
412418 let $l = [1, 2, 3, 4, 5]
413419 let $s = size($l)
414420 let $acc0 = $Tuple2("", (seed / FIVEX))
415421 func $f0_1 ($a,$i) = if (($i >= $s))
416422 then $a
417423 else terrainGenerator($a, $l[$i])
418424
419425 func $f0_2 ($a,$i) = if (($i >= $s))
420426 then $a
421427 else throw("List size exceeds 5")
422428
423429 $f0_2($f0_1($f0_1($f0_1($f0_1($f0_1($acc0, 0), 1), 2), 3), 4), 5)
424430 }
425431 t._1
426432 }
427433
428434
429435 func getBackpack (bpKey) = {
430436 let p = split(valueOrElse(getString(bpKey), "0:0_0_0_0_0_0:0_0_0_0_0_0:"), ":")
431437 [toString(valueOrElse(parseInt(p[bpIdxLevel]), 0)), if ((size(split(p[bpIdxRes], "_")) == NUMRES))
432438 then p[bpIdxRes]
433439 else "0_0_0_0_0_0", if ((size(split(p[bpIdxMat], "_")) == NUMRES))
434440 then p[bpIdxMat]
435441 else "0_0_0_0_0_0", p[bpIdxProd]]
436442 }
437443
438444
439445 func expeditionCommon (shouldUseMat,caller,txId,message,sig) = if (!(sigVerify_8Kb(message, sig, pub)))
440446 then throw("signature does not match")
441447 else {
442448 let parts = split(toUtf8String(message), ";")
443449 let hp = split(split(parts[0], "|")[0], "_")
444450 let curHP = parseIntValue(hp[0])
445451 let newHP = parseIntValue(hp[1])
446452 let locAndTime = split(parts[1], ":")
447453 let targetLocation = split(locAndTime[0], "_")
448454 if ((targetLocation[1] != "E"))
449455 then throw("expedition target location type should be E")
450456 else {
451457 let time = parseIntValue(locAndTime[1])
452458 if (if ((time > (lastBlock.timestamp + FIVEMINUTESMILLIS)))
453459 then true
454460 else ((lastBlock.timestamp - FIVEMINUTESMILLIS) > time))
455461 then throw("signature outdated")
456462 else {
457463 let userAddr = toString(caller)
458464 let duckAssetId = valueOrErrorMessage(getString(keyStakedDuckByOwner(userAddr)), "You don't have a duck staked")
459465 let keyHealth = keyDuckHealth(duckAssetId)
460466 let oldFromState = valueOrElse(getInteger(keyHealth), 100)
461467 if ((oldFromState != curHP))
462468 then throw(((("oldHealth=" + toString(valueOrElse(getInteger(keyHealth), 100))) + " from state does not match one from flight log=") + toString(curHP)))
463469 else if ((0 >= curHP))
464470 then throw("You can't fly with zero health")
465471 else if ((0 >= newHP))
466472 then $Tuple2(((if (!(shouldUseMat))
467473 then [ScriptTransfer(caller, EXPUSDN, usdnAssetId)]
468474 else nil) :+ IntegerEntry(keyHealth, 0)), "")
469475 else {
470476 let bpKey = keyBackpackByDuck(duckAssetId)
471477 let currentPack = getBackpack(bpKey)
472478 let mList = split(currentPack[bpIdxMat], "_")
473479 let newMat = makeString(subtractMaterials(shouldUseMat, mList, EXPMATERIALS), "_")
474480 let bigNum = abs(toBigInt(txId))
475481 let freeNum = valueOrElse(getInteger(keyNextFreeLandNum()), (PRESALENUMLANDS + 1))
476482 let landNum = toString(freeNum)
477483 let continentIdx = toInt((bigNum % FIVEX))
478484 let terrains = genTerrains(bigNum, continentIdx)
479485 let continent = continents[continentIdx]
480486 let issue = Issue(keyNftName(landNum, "S"), makeString([landNum, "S", terrains, continent], "_"), 1, 0, false)
481487 let assetId = calculateAssetId(issue)
482488 let id = toBase58String(assetId)
483489 $Tuple2([IntegerEntry(keyNextFreeLandNum(), (freeNum + 1)), issue, StringEntry(keyLandToAssetId(landNum), id), StringEntry(keyLandAssetIdToOwner(id), userAddr), StringEntry(keyLandNumToOwner(landNum), userAddr), IntegerEntry(keyInfraLevelByAssetId(id), 0), IntegerEntry(keyInfraLevelByAssetIdAndOwner(id, userAddr), 0), ScriptTransfer(caller, 1, assetId), StringEntry(keyDuckLocation(duckAssetId), makeString([continent, "L", id], "_")), IntegerEntry(keyHealth, newHP), StringEntry(bpKey, makeString([currentPack[bpIdxLevel], currentPack[bpIdxRes], newMat, currentPack[bpIdxProd]], ":"))], id)
484490 }
485491 }
486492 }
487493 }
488494
489495
490496 func applyBonuses (landAssetId,pieces) = {
491497 let infraLevel = valueOrElse(getInteger(keyInfraLevelByAssetId(landAssetId)), 0)
492498 let artPieces = valueOrElse(getInteger(keyLandArtStatusByTypeAndAssetId(ARTPRESALE, landAssetId)), if (valueOrElse(getBoolean(keyPresaleArtActivatedByAssetId(landAssetId)), false))
493499 then pieces
494500 else 0)
495501 ((DAILYRESBYPIECE + fraction(DAILYRESBYPIECE, infraLevel, 4)) + fraction(DAILYRESBYPIECE, (artPieces * 3), (pieces * 20)))
496502 }
497503
498504
499505 func checkClaimConditions (addr) = {
500506 let duckAssetId = valueOrErrorMessage(getString(keyStakedDuckByOwner(addr)), "You don't have a duck staked")
501507 let curLocation = valueOrElse(getString(keyDuckLocation(duckAssetId)), DEFAULTLOCATION)
502508 let loc = split(value(curLocation), "_")
503509 if ((loc[locIdxType] != "L"))
504510 then throw((("Duck location type is " + loc[locIdxType]) + ", but should be L"))
505511 else {
506512 let landAssetId = loc[locIdxId]
507513 let asset = value(assetInfo(fromBase58String(landAssetId)))
508514 let timeKey = keyStakedTimeByAssetId(landAssetId)
509515 let savedTime = valueOrErrorMessage(getInteger(timeKey), (("Your duck is on " + asset.name) + ", which is not staked"))
510516 let owner = valueOrErrorMessage(getString(keyLandAssetIdToOwner(landAssetId)), (("NFT " + asset.name) + " is orphaned"))
511517 if ((owner != addr))
512518 then throw((LANDPREFIX + " is not yours"))
513519 else {
514520 let d = split(asset.description, "_")
515521 $Tuple4(duckAssetId, landAssetId, d, savedTime)
516522 }
517523 }
518524 }
519525
520526
521527 func claimResInternal (addr,amount) = if ((0 > amount))
522528 then throw("Negative amount")
523529 else {
524530 let c = checkClaimConditions(addr)
525531 let landSize = c._3[recLandSize]
526532 let terrainCounts = countTerrains(c._3[recTerrains])
527533 let deltaTime = (lastBlock.timestamp - c._4)
528534 if ((0 > deltaTime))
529535 then throw(((("Saved timestamp is in future, saved = " + toString(c._4)) + ", current = ") + toString(lastBlock.timestamp)))
530536 else {
531537 let pieces = numPiecesBySize(landSize)
532538 let dailyProductionByPiece = applyBonuses(c._2, pieces)
533539 let availRes = fraction(deltaTime, (dailyProductionByPiece * pieces), DAYMILLIS)
534540 if ((amount > availRes))
535541 then throw(((("Not enough resources, available = " + toString(availRes)) + ", requested = ") + toString(amount)))
536542 else {
537543 let newDeltaTime = fraction((availRes - amount), DAYMILLIS, (dailyProductionByPiece * pieces))
538544 let newTimestamp = (lastBlock.timestamp - newDeltaTime)
539545 let bpKey = keyBackpackByDuck(c._1)
540546 let currentPack = getBackpack(bpKey)
541547 let currentRes = split(currentPack[bpIdxRes], "_")
542548 let bpRes = addRes(currentRes, terrainCounts, (deltaTime - newDeltaTime), (pieces / SSIZE), dailyProductionByPiece)
543549 $Tuple3([IntegerEntry(keyStakedTimeByAssetId(c._2), newTimestamp), IntegerEntry(keyStakedTimeByTypeAssetIdAndOwner(LANDPREFIX, c._2, addr), newTimestamp)], bpKey, [currentPack[bpIdxLevel], bpRes, currentPack[bpIdxMat], currentPack[bpIdxProd]])
544550 }
545551 }
546552 }
547553
548554
549555 func claimAll (addr,landAssetId,pieces) = {
550556 let timeKey = keyStakedTimeByAssetId(landAssetId)
551557 let savedTime = value(getInteger(timeKey))
552558 let availRes = (fraction((lastBlock.timestamp - savedTime), applyBonuses(landAssetId, pieces), DAYMILLIS) * pieces)
553559 claimResInternal(addr, availRes)
554560 }
555561
556562
557563 func upInfraCommon (shouldUseMat,caller,paymentAmount) = {
558564 let addr = toString(caller)
559565 let c = checkClaimConditions(addr)
560566 let pieces = numPiecesBySize(c._3[recLandSize])
561567 let infraKey = keyInfraLevelByAssetId(c._2)
562568 let curLevel = valueOrElse(getInteger(infraKey), 0)
563569 if ((curLevel >= 3))
564570 then throw("Currently max infrastructure level = 3")
565571 else {
566572 let newLevel = (curLevel + 1)
567573 let cost = fraction(InfraUpgradeCostSUsdn, (pieces * newLevel), SSIZE)
568574 if (if (!(shouldUseMat))
569575 then (paymentAmount != cost)
570576 else false)
571577 then throw(("Payment attached should be " + toString(cost)))
572578 else {
573579 let bpKey = keyBackpackByDuck(c._1)
574580 let currentPack = getBackpack(bpKey)
575581 let mList = split(currentPack[bpIdxMat], "_")
576582 let newMat = makeString(subtractMaterials(shouldUseMat, mList, fraction(InfraUpgradeCostS, (pieces * newLevel), SSIZE)), "_")
577583 let claimResult = claimAll(addr, c._2, pieces)
578584 $Tuple2(([IntegerEntry(infraKey, newLevel), IntegerEntry(keyInfraLevelByAssetIdAndOwner(c._2, addr), newLevel), StringEntry(bpKey, makeString([currentPack[bpIdxLevel], claimResult._3[bpIdxRes], newMat, currentPack[bpIdxProd]], ":"))] ++ claimResult._1), newLevel)
579585 }
580586 }
581587 }
582588
583589
584590 func activatePresaleArt (addr) = {
585591 let c = checkClaimConditions(addr)
586592 let landAssetId = c._2
587593 let activationKey = keyPresaleArtActivatedByAssetId(landAssetId)
588594 if (valueOrElse(getBoolean(activationKey), false))
589595 then throw("Presale artifact is already activated")
590596 else if ((parseIntValue(c._3[recLandNum]) > PRESALENUMLANDS))
591597 then throw((((LANDPREFIX + " ") + landAssetId) + " is not eligible for presale artifact"))
592598 else {
593599 let pieces = numPiecesBySize(c._3[recLandSize])
594600 let claimResult = claimAll(addr, landAssetId, pieces)
595601 (((((claimResult._1 :+ BooleanEntry(activationKey, true)) :+ BooleanEntry(keyPresaleArtActivatedByAssetIdAndOwner(landAssetId, addr), true)) :+ IntegerEntry(keyLandArtStatusByTypeAndAssetId(ARTPRESALE, landAssetId), pieces)) :+ IntegerEntry(keyLandArtStatusByTypeAssetIdAndOwner(ARTPRESALE, landAssetId, addr), pieces)) :+ StringEntry(claimResult._2, makeString(claimResult._3, ":")))
596602 }
597603 }
598604
599605
600606 func mergeInternal (newLandSize,newLevel,formula,addr,landAssetIds,txId,needMat) = {
601607 let duckAssetId = valueOrErrorMessage(getString(keyStakedDuckByOwner(addr)), "You don't have a duck staked")
602608 func checkMerge (acc,landAssetId) = {
603609 let asset = value(assetInfo(fromBase58String(landAssetId)))
604610 let timeKey = keyStakedTimeByAssetId(landAssetId)
605611 let savedTime = valueOrErrorMessage(getInteger(timeKey), (("NFT " + asset.name) + " is not staked"))
606612 let owner = valueOrErrorMessage(getString(keyLandAssetIdToOwner(landAssetId)), (("NFT " + asset.name) + " is orphaned"))
607613 if ((owner != addr))
608614 then throw((LANDPREFIX + " is not yours"))
609615 else {
610616 let d = split(asset.description, "_")
611617 let continent = d[recContinent]
612618 if (if ((acc._3 != ""))
613619 then (acc._3 != continent)
614620 else false)
615621 then throw("Lands should be on the same continent to merge")
616622 else {
617623 let landSize = d[recLandSize]
618624 let sizesIn = acc._1
619625 let i = valueOrErrorMessage(indexOf(sizesIn, landSize), "You haven't passed all the lands needed")
620626 let sizesOut = (take(sizesIn, i) + drop(sizesIn, (i + 1)))
621627 let pieces = numPiecesBySize(landSize)
622628 let arts = (acc._2 + valueOrElse(getInteger(keyLandArtStatusByTypeAndAssetId(ARTPRESALE, landAssetId)), if (valueOrElse(getBoolean(keyPresaleArtActivatedByAssetId(landAssetId)), false))
623629 then pieces
624630 else 0))
625631 let infraLevel = valueOrElse(getInteger(keyInfraLevelByAssetId(landAssetId)), 0)
626632 let reqLevel = match landSize {
627633 case _ =>
628634 if (("S" == $match0))
629635 then 3
630636 else if (("M" == $match0))
631637 then 4
632638 else if (("L" == $match0))
633639 then 5
634640 else if (("XL" == $match0))
635641 then 6
636642 else throw("Only S, M, L, XL can merge")
637643 }
638644 if ((infraLevel != reqLevel))
639645 then throw("All lands should be maxed to merge")
640646 else {
641647 let landNum = d[recLandNum]
642648 let terrainCounts = countTerrains(d[recTerrains])
643649 let deltaTime = (lastBlock.timestamp - savedTime)
644650 if ((0 > deltaTime))
645651 then throw(((("Saved timestamp is in future, saved = " + toString(savedTime)) + ", current = ") + toString(lastBlock.timestamp)))
646652 else {
647653 let dailyProductionByPiece = applyBonuses(landAssetId, pieces)
648654 let bpRes = addRes(split(acc._4, "_"), terrainCounts, deltaTime, (pieces / SSIZE), dailyProductionByPiece)
649655 let props = updateProportionsInternal(split(acc._6, "_"), terrainCounts, (pieces / SSIZE), -1)
650- $Tuple6(sizesOut, arts, continent, bpRes, (((((((((((((acc._5 :+ DeleteEntry(keyStakedTimeByAssetId(landAssetId))) :+ DeleteEntry(keyStakedTimeByTypeAssetIdAndOwner(LANDPREFIX, landAssetId, addr))) :+ DeleteEntry(keyLandToAssetId(landNum))) :+ DeleteEntry(keyNftName(landNum, landSize))) :+ DeleteEntry(keyLandAssetIdToOwner(landAssetId))) :+ DeleteEntry(keyInfraLevelByAssetId(landAssetId))) :+ DeleteEntry(keyInfraLevelByAssetIdAndOwner(landAssetId, addr))) :+ DeleteEntry(keyPresaleArtActivatedByAssetId(landAssetId))) :+ DeleteEntry(keyPresaleArtActivatedByAssetIdAndOwner(landAssetId, addr))) :+ DeleteEntry(keyLandArtStatusByTypeAndAssetId(ARTPRESALE, landAssetId))) :+ DeleteEntry(keyLandArtStatusByTypeAssetIdAndOwner(ARTPRESALE, landAssetId, addr))) :+ DeleteEntry(keyLandNumToOwner(landNum))) :+ Burn(fromBase58String(landAssetId), 1)), props)
656+ let lands = acc._7
657+ let idx = indexOf(lands, landAssetId)
658+ if (!(isDefined(idx)))
659+ then throw(("Your staked lands don't contain " + landAssetId))
660+ else $Tuple7(sizesOut, arts, continent, bpRes, (((((((((((((acc._5 :+ DeleteEntry(keyStakedTimeByAssetId(landAssetId))) :+ DeleteEntry(keyStakedTimeByTypeAssetIdAndOwner(LANDPREFIX, landAssetId, addr))) :+ DeleteEntry(keyLandToAssetId(landNum))) :+ DeleteEntry(keyNftName(landNum, landSize))) :+ DeleteEntry(keyLandAssetIdToOwner(landAssetId))) :+ DeleteEntry(keyInfraLevelByAssetId(landAssetId))) :+ DeleteEntry(keyInfraLevelByAssetIdAndOwner(landAssetId, addr))) :+ DeleteEntry(keyPresaleArtActivatedByAssetId(landAssetId))) :+ DeleteEntry(keyPresaleArtActivatedByAssetIdAndOwner(landAssetId, addr))) :+ DeleteEntry(keyLandArtStatusByTypeAndAssetId(ARTPRESALE, landAssetId))) :+ DeleteEntry(keyLandArtStatusByTypeAssetIdAndOwner(ARTPRESALE, landAssetId, addr))) :+ DeleteEntry(keyLandNumToOwner(landNum))) :+ Burn(fromBase58String(landAssetId), 1)), props, removeByIndex(lands, value(idx)))
651661 }
652662 }
653663 }
654664 }
655665 }
656666
657667 let bpKey = keyBackpackByDuck(duckAssetId)
658668 let currentPack = getBackpack(bpKey)
659669 let propStr = valueOrElse(getString(keyResProportions()), "0_0_0_0_0_0")
670+ let landsKey = keyStakedLandsByOwner(addr)
671+ let landsIn = split_51C(valueOrElse(getString(landsKey), ""), "_")
660672 let r = {
661673 let $l = landAssetIds
662674 let $s = size($l)
663- let $acc0 = $Tuple6(formula, 0, "", currentPack[bpIdxRes], nil, propStr)
675+ let $acc0 = $Tuple7(formula, 0, "", currentPack[bpIdxRes], nil, propStr, landsIn)
664676 func $f0_1 ($a,$i) = if (($i >= $s))
665677 then $a
666678 else checkMerge($a, $l[$i])
667679
668680 func $f0_2 ($a,$i) = if (($i >= $s))
669681 then $a
670- else throw("List size exceeds 4")
682+ else throw("List size exceeds 5")
671683
672- $f0_2($f0_1($f0_1($f0_1($f0_1($acc0, 0), 1), 2), 3), 4)
684+ $f0_2($f0_1($f0_1($f0_1($f0_1($f0_1($acc0, 0), 1), 2), 3), 4), 5)
673685 }
674686 let continent = r._3
675687 let continentIdx = valueOrErrorMessage(indexOf(continents, continent), ("Unknown continent: " + continent))
676688 let terrains = genTerrains(abs(toBigInt(txId)), continentIdx)
677689 let freeNum = valueOrElse(getInteger(keyNextFreeLandNum()), (PRESALENUMLANDS + 1))
678690 let newLandNum = toString(freeNum)
679691 let issue = Issue(keyNftName(newLandNum, newLandSize), makeString([newLandNum, newLandSize, terrains, continent], "_"), 1, 0, false)
680692 let assetId = calculateAssetId(issue)
681693 let newLandAssetId = toBase58String(assetId)
682694 let newMat = makeString(subtractMaterials((needMat > 0), split(currentPack[bpIdxMat], "_"), needMat), "_")
683- $Tuple2((((((((((((((r._5 :+ IntegerEntry(keyNextFreeLandNum(), (freeNum + 1))) :+ issue) :+ StringEntry(keyLandToAssetId(newLandNum), newLandAssetId)) :+ StringEntry(keyLandAssetIdToOwner(newLandAssetId), addr)) :+ StringEntry(keyLandNumToOwner(newLandNum), addr)) :+ IntegerEntry(keyLandArtStatusByTypeAndAssetId(ARTPRESALE, newLandAssetId), r._2)) :+ IntegerEntry(keyLandArtStatusByTypeAssetIdAndOwner(ARTPRESALE, newLandAssetId, addr), r._2)) :+ IntegerEntry(keyInfraLevelByAssetId(newLandAssetId), newLevel)) :+ IntegerEntry(keyInfraLevelByAssetIdAndOwner(newLandAssetId, addr), newLevel)) :+ StringEntry(bpKey, makeString([currentPack[bpIdxLevel], r._4, newMat, currentPack[bpIdxProd]], ":"))) :+ StringEntry(keyResProportions(), r._6)) :+ StringEntry(keyDuckLocation(duckAssetId), makeString([continent, "L", newLandAssetId], "_"))) :+ ScriptTransfer(addressFromStringValue(addr), 1, assetId)), newLandAssetId)
695+ $Tuple2(((((((((((((((r._5 :+ (if ((size(r._7) > 0))
696+ then StringEntry(landsKey, makeString_11C(r._7, "_"))
697+ else DeleteEntry(landsKey))) :+ IntegerEntry(keyNextFreeLandNum(), (freeNum + 1))) :+ issue) :+ StringEntry(keyLandToAssetId(newLandNum), newLandAssetId)) :+ StringEntry(keyLandAssetIdToOwner(newLandAssetId), addr)) :+ StringEntry(keyLandNumToOwner(newLandNum), addr)) :+ IntegerEntry(keyLandArtStatusByTypeAndAssetId(ARTPRESALE, newLandAssetId), r._2)) :+ IntegerEntry(keyLandArtStatusByTypeAssetIdAndOwner(ARTPRESALE, newLandAssetId, addr), r._2)) :+ IntegerEntry(keyInfraLevelByAssetId(newLandAssetId), newLevel)) :+ IntegerEntry(keyInfraLevelByAssetIdAndOwner(newLandAssetId, addr), newLevel)) :+ StringEntry(bpKey, makeString([currentPack[bpIdxLevel], r._4, newMat, currentPack[bpIdxProd]], ":"))) :+ StringEntry(keyResProportions(), r._6)) :+ StringEntry(keyDuckLocation(duckAssetId), makeString([continent, "L", newLandAssetId], "_"))) :+ ScriptTransfer(addressFromStringValue(addr), 1, assetId)), newLandAssetId)
684698 }
685699
686700
687701 func s2m (addr,landAssetIds,txId) = mergeInternal("M", 3, "SSSS", addr, landAssetIds, txId, 0)
688702
689703
690704 func m2l (addr,landAssetIds,txId,shouldUseMat,paymentAmount) = {
691705 let cost = (InfraUpgradeCostSUsdn * 4)
692706 if (if (!(shouldUseMat))
693707 then (paymentAmount != cost)
694708 else false)
695709 then throw(("Payment attached should be " + toString(cost)))
696710 else mergeInternal("L", 4, "SMM", addr, landAssetIds, txId, (InfraUpgradeCostS * 4))
697711 }
698712
699713
700714 func l2xl (addr,landAssetIds,txId,shouldUseMat,paymentAmount) = {
701715 let cost = (InfraUpgradeCostSUsdn * 47)
702716 if (if (!(shouldUseMat))
703717 then (paymentAmount != cost)
704718 else false)
705719 then throw(("Payment attached should be " + toString(cost)))
706720 else mergeInternal("XL", 5, "SSSML", addr, landAssetIds, txId, (InfraUpgradeCostS * 47))
707721 }
708722
709723
710724 func xl2xxl (addr,landAssetIds,txId,shouldUseMat,paymentAmount) = {
711725 let cost = (InfraUpgradeCostSUsdn * 54)
712726 if (if (!(shouldUseMat))
713727 then (paymentAmount != cost)
714728 else false)
715729 then throw(("Payment attached should be " + toString(cost)))
716730 else mergeInternal("XXL", 6, "LXL", addr, landAssetIds, txId, (InfraUpgradeCostS * 54))
717731 }
718732
719733
720734 func mergeCommon (shouldUseMat,addr,paymentAmount,landAssetIds,txId) = {
721735 let mergeResult = match size(landAssetIds) {
722736 case _ =>
723737 if ((4 == $match0))
724738 then s2m(addr, landAssetIds, txId)
725739 else if ((3 == $match0))
726740 then m2l(addr, landAssetIds, txId, shouldUseMat, paymentAmount)
727741 else if ((5 == $match0))
728742 then l2xl(addr, landAssetIds, txId, shouldUseMat, paymentAmount)
729743 else if ((2 == $match0))
730744 then xl2xxl(addr, landAssetIds, txId, shouldUseMat, paymentAmount)
731745 else throw("Unknown merge")
732746 }
733747 mergeResult
734748 }
735749
736750
737751 func saveTxId (addr,txId) = StringEntry(keyLastTxIdByUser(toString(addr)), toBase58String(txId))
738752
739753
754+func checkBlocked () = if (valueOrElse(getBoolean(keyBlocked()), false))
755+ then throw("Contracts are under maintenance")
756+ else unit
757+
758+
740759 @Callable(i)
741-func stakeLand () = if ((size(i.payments) != 1))
742- then throw("Exactly one payment required")
743- else {
744- let pmt = value(i.payments[0])
745- let assetId = value(pmt.assetId)
746- let address = toString(i.caller)
747- if ((pmt.amount != 1))
748- then throw((("NFT " + LANDPREFIX) + " token should be attached as payment"))
749- else {
750- let asset = value(assetInfo(assetId))
751- if ((asset.issuer != this))
752- then throw("Unknown issuer of token")
753- else if (!(contains(asset.name, LANDPREFIX)))
754- then throw((("Only NFT " + LANDPREFIX) + " tokens are accepted"))
755- else {
756- let landNumSize = drop(asset.name, 4)
757- let landNum = if (contains(landNumSize, "XXL"))
758- then dropRight(landNumSize, 3)
759- else if (contains(landNumSize, "XL"))
760- then dropRight(landNumSize, 2)
761- else dropRight(landNumSize, 1)
762- if (!(isDefined(parseInt(landNum))))
763- then throw(("Cannot parse land number from " + asset.name))
764- else {
765- let landAssetId = toBase58String(assetId)
766- let timeKey = keyStakedTimeByAssetId(landAssetId)
767- if (isDefined(getInteger(timeKey)))
768- then throw((("NFT " + asset.name) + " is already staked"))
769- else {
770- let d = split(asset.description, "_")
771- let terrainCounts = countTerrains(d[recTerrains])
772- let props = updateProportions(terrainCounts, (numPiecesBySize(d[recLandSize]) / SSIZE), 1)
773-[IntegerEntry(timeKey, lastBlock.timestamp), IntegerEntry(keyStakedTimeByTypeAssetIdAndOwner(LANDPREFIX, landAssetId, address), lastBlock.timestamp), StringEntry(keyLandAssetIdToOwner(landAssetId), address), StringEntry(keyLandNumToOwner(landNum), address), StringEntry(keyResProportions(), props)]
774- }
775- }
776- }
777- }
778- }
760+func setBlocked (isBlocked) = if ((i.caller != this))
761+ then throw("permission denied")
762+ else [BooleanEntry(keyBlocked(), isBlocked)]
779763
780764
781765
782766 @Callable(i)
783-func unstakeLand (landAssetIdStr) = if ((size(i.payments) != 0))
784- then throw("unstake doesn't require any payments")
785- else {
786- let addr = toString(i.caller)
787- let c = checkClaimConditions(addr)
788- let terrainCounts = countTerrains(c._3[recTerrains])
789- let pieces = numPiecesBySize(c._3[recLandSize])
790- let props = updateProportions(terrainCounts, (pieces / SSIZE), -1)
791- let claimResult = claimAll(addr, c._2, pieces)
792-[ScriptTransfer(i.caller, 1, fromBase58String(c._2)), DeleteEntry(keyStakedTimeByAssetId(c._2)), DeleteEntry(keyStakedTimeByTypeAssetIdAndOwner(LANDPREFIX, c._2, addr)), StringEntry(keyResProportions(), props), StringEntry(claimResult._2, makeString(claimResult._3, ":"))]
793- }
767+func stakeLand () = {
768+ let blocked = checkBlocked()
769+ if ((blocked == blocked))
770+ then if ((size(i.payments) != 1))
771+ then throw("Exactly one payment required")
772+ else {
773+ let pmt = value(i.payments[0])
774+ let assetId = value(pmt.assetId)
775+ let address = toString(i.caller)
776+ if ((pmt.amount != 1))
777+ then throw((("NFT " + LANDPREFIX) + " token should be attached as payment"))
778+ else {
779+ let asset = value(assetInfo(assetId))
780+ if ((asset.issuer != this))
781+ then throw("Unknown issuer of token")
782+ else if (!(contains(asset.name, LANDPREFIX)))
783+ then throw((("Only NFT " + LANDPREFIX) + " tokens are accepted"))
784+ else {
785+ let landNumSize = drop(asset.name, 4)
786+ let landNum = if (contains(landNumSize, "XXL"))
787+ then dropRight(landNumSize, 3)
788+ else if (contains(landNumSize, "XL"))
789+ then dropRight(landNumSize, 2)
790+ else dropRight(landNumSize, 1)
791+ if (!(isDefined(parseInt(landNum))))
792+ then throw(("Cannot parse land number from " + asset.name))
793+ else {
794+ let landAssetId = toBase58String(assetId)
795+ let timeKey = keyStakedTimeByAssetId(landAssetId)
796+ if (isDefined(getInteger(timeKey)))
797+ then throw((("NFT " + asset.name) + " is already staked"))
798+ else {
799+ let d = split(asset.description, "_")
800+ let terrainCounts = countTerrains(d[recTerrains])
801+ let props = updateProportions(terrainCounts, (numPiecesBySize(d[recLandSize]) / SSIZE), 1)
802+ let lands = split_51C(valueOrElse(getString(keyStakedLandsByOwner(address)), ""), "_")
803+ if (containsElement(lands, landAssetId))
804+ then throw(("Your staked lands already contain " + landAssetId))
805+ else [IntegerEntry(timeKey, lastBlock.timestamp), IntegerEntry(keyStakedTimeByTypeAssetIdAndOwner(LANDPREFIX, landAssetId, address), lastBlock.timestamp), StringEntry(keyStakedLandsByOwner(address), makeString_11C((lands :+ landAssetId), "_")), StringEntry(keyLandAssetIdToOwner(landAssetId), address), StringEntry(keyLandNumToOwner(landNum), address), StringEntry(keyResProportions(), props)]
806+ }
807+ }
808+ }
809+ }
810+ }
811+ else throw("Strict value is not equal to itself.")
812+ }
794813
795814
796815
797816 @Callable(i)
798-func stakeDuck () = if ((size(i.payments) != 1))
799- then throw("Exactly one payment required")
800- else {
801- let pmt = value(i.payments[0])
802- let assetId = value(pmt.assetId)
803- let address = toString(i.caller)
804- if ((pmt.amount != 1))
805- then throw((("NFT " + DUCKPREFIX) + " token should be attached as payment"))
817+func unstakeLand (landAssetIdIgnored) = {
818+ let blocked = checkBlocked()
819+ if ((blocked == blocked))
820+ then if ((size(i.payments) != 0))
821+ then throw("unstake doesn't require any payments")
806822 else {
807- let asset = value(assetInfo(assetId))
808- if (if ((asset.issuer != incubatorAddr))
809- then (asset.issuer != breederAddr)
810- else false)
811- then throw((("Unknown issuer of " + DUCKPREFIX) + " token"))
812- else if (!(contains(asset.name, DUCKPREFIX)))
813- then throw((("Only NFT " + DUCKPREFIX) + " tokens are accepted"))
814- else {
815- let assetIdStr = toBase58String(assetId)
816- let timeKey = keyStakedTimeByAssetId(assetIdStr)
817- if (isDefined(getInteger(timeKey)))
818- then throw((("NFT " + asset.name) + " is already staked"))
819- else if (isDefined(getString(keyStakedDuckByOwner(address))))
820- then throw(("You already staked one duck: " + asset.name))
821- else {
822- let locKey = keyDuckLocation(assetIdStr)
823- let location = getString(locKey)
824- let bpKey = keyBackpackByDuck(assetIdStr)
825- let backpack = getString(bpKey)
826- ([IntegerEntry(timeKey, lastBlock.timestamp), IntegerEntry(keyStakedTimeByTypeAssetIdAndOwner(DUCKPREFIX, toBase58String(assetId), address), lastBlock.timestamp), StringEntry(keyDuckIdToOwner(assetIdStr), address), StringEntry(keyStakedDuckByOwner(address), assetIdStr)] ++ (if (isDefined(location))
827- then nil
828- else ([StringEntry(locKey, DEFAULTLOCATION)] ++ (if (isDefined(backpack))
829- then nil
830- else ([StringEntry(bpKey, "0:0_0_0_0_0_0:0_0_0_0_0_0:")] :+ IntegerEntry(keyDuckHealth(assetIdStr), 100))))))
831- }
832- }
823+ let addr = toString(i.caller)
824+ let c = checkClaimConditions(addr)
825+ let landAssetId = c._2
826+ let landsKey = keyStakedLandsByOwner(addr)
827+ let terrainCounts = countTerrains(c._3[recTerrains])
828+ let pieces = numPiecesBySize(c._3[recLandSize])
829+ let props = updateProportions(terrainCounts, (pieces / SSIZE), -1)
830+ let claimResult = claimAll(addr, landAssetId, pieces)
831+ let lands = split_51C(valueOrElse(getString(landsKey), ""), "_")
832+ let idx = indexOf(lands, landAssetId)
833+ if (!(isDefined(idx)))
834+ then throw(("Your staked lands don't contain " + landAssetId))
835+ else [ScriptTransfer(i.caller, 1, fromBase58String(landAssetId)), DeleteEntry(keyStakedTimeByAssetId(landAssetId)), DeleteEntry(keyStakedTimeByTypeAssetIdAndOwner(LANDPREFIX, landAssetId, addr)), StringEntry(keyResProportions(), props), StringEntry(claimResult._2, makeString(claimResult._3, ":")), if ((size(lands) > 1))
836+ then StringEntry(landsKey, makeString_11C(removeByIndex(lands, value(idx)), "_"))
837+ else DeleteEntry(landsKey)]
833838 }
834- }
839+ else throw("Strict value is not equal to itself.")
840+ }
835841
836842
837843
838844 @Callable(i)
839-func unstakeDuck (assetIdStr) = if ((size(i.payments) != 0))
840- then throw("unstake doesn't require any payments")
841- else {
842- let assetId = fromBase58String(assetIdStr)
843- let address = toString(i.caller)
844- let asset = value(assetInfo(assetId))
845- let timeKey = keyStakedTimeByAssetId(toBase58String(assetId))
846- if (!(isDefined(timeKey)))
847- then throw((("NFT " + asset.name) + " is not staked"))
848- else if (!(isDefined(keyStakedDuckByOwner(address))))
849- then throw((("The duck " + asset.name) + " is not staked"))
850- else {
851- let owner = valueOrErrorMessage(getString(keyDuckIdToOwner(toBase58String(assetId))), (("NFT " + asset.name) + " is orphaned"))
852- if ((owner != address))
853- then throw("Staked NFT is not yours")
854- else {
855- let keyHealth = keyDuckHealth(assetIdStr)
856- let health = valueOrElse(getInteger(keyHealth), 100)
857- if ((health != 100))
858- then throw("Please heal your duck before unstaking")
859- else [ScriptTransfer(i.caller, 1, assetId), DeleteEntry(timeKey), DeleteEntry(keyHealth), DeleteEntry(keyDuckLocation(assetIdStr)), DeleteEntry(keyDuckIdToOwner(assetIdStr)), DeleteEntry(keyStakedTimeByTypeAssetIdAndOwner(DUCKPREFIX, assetIdStr, address)), DeleteEntry(keyStakedDuckByOwner(address))]
860- }
861- }
862- }
845+func stakeDuck () = {
846+ let blocked = checkBlocked()
847+ if ((blocked == blocked))
848+ then if ((size(i.payments) != 1))
849+ then throw("Exactly one payment required")
850+ else {
851+ let pmt = value(i.payments[0])
852+ let assetId = value(pmt.assetId)
853+ let address = toString(i.caller)
854+ if ((pmt.amount != 1))
855+ then throw((("NFT " + DUCKPREFIX) + " token should be attached as payment"))
856+ else {
857+ let asset = value(assetInfo(assetId))
858+ if (if ((asset.issuer != incubatorAddr))
859+ then (asset.issuer != breederAddr)
860+ else false)
861+ then throw((("Unknown issuer of " + DUCKPREFIX) + " token"))
862+ else if (!(contains(asset.name, DUCKPREFIX)))
863+ then throw((("Only NFT " + DUCKPREFIX) + " tokens are accepted"))
864+ else {
865+ let assetIdStr = toBase58String(assetId)
866+ let timeKey = keyStakedTimeByAssetId(assetIdStr)
867+ if (isDefined(getInteger(timeKey)))
868+ then throw((("NFT " + asset.name) + " is already staked"))
869+ else if (isDefined(getString(keyStakedDuckByOwner(address))))
870+ then throw(("You already staked one duck: " + asset.name))
871+ else {
872+ let locKey = keyDuckLocation(assetIdStr)
873+ let location = getString(locKey)
874+ let bpKey = keyBackpackByDuck(assetIdStr)
875+ let backpack = getString(bpKey)
876+ ([IntegerEntry(timeKey, lastBlock.timestamp), IntegerEntry(keyStakedTimeByTypeAssetIdAndOwner(DUCKPREFIX, toBase58String(assetId), address), lastBlock.timestamp), StringEntry(keyDuckIdToOwner(assetIdStr), address), StringEntry(keyStakedDuckByOwner(address), assetIdStr)] ++ (if (isDefined(location))
877+ then nil
878+ else ([StringEntry(locKey, DEFAULTLOCATION)] ++ (if (isDefined(backpack))
879+ then nil
880+ else ([StringEntry(bpKey, "0:0_0_0_0_0_0:0_0_0_0_0_0:")] :+ IntegerEntry(keyDuckHealth(assetIdStr), 100))))))
881+ }
882+ }
883+ }
884+ }
885+ else throw("Strict value is not equal to itself.")
886+ }
863887
864888
865889
866890 @Callable(i)
867-func claimRes (amount,landAssetIdStr) = if ((size(i.payments) != 0))
868- then throw("claimRes doesn't require any payments")
869- else {
870- let addr = toString(i.originCaller)
871- let result = claimResInternal(addr, amount)
872- $Tuple2((result._1 :+ StringEntry(result._2, makeString(result._3, ":"))), result._3[bpIdxRes])
873- }
891+func unstakeDuck (assetIdStr) = {
892+ let blocked = checkBlocked()
893+ if ((blocked == blocked))
894+ then if ((size(i.payments) != 0))
895+ then throw("unstake doesn't require any payments")
896+ else {
897+ let assetId = fromBase58String(assetIdStr)
898+ let address = toString(i.caller)
899+ let asset = value(assetInfo(assetId))
900+ let timeKey = keyStakedTimeByAssetId(toBase58String(assetId))
901+ if (!(isDefined(timeKey)))
902+ then throw((("NFT " + asset.name) + " is not staked"))
903+ else if (!(isDefined(keyStakedDuckByOwner(address))))
904+ then throw((("The duck " + asset.name) + " is not staked"))
905+ else {
906+ let owner = valueOrErrorMessage(getString(keyDuckIdToOwner(toBase58String(assetId))), (("NFT " + asset.name) + " is orphaned"))
907+ if ((owner != address))
908+ then throw("Staked NFT is not yours")
909+ else {
910+ let keyHealth = keyDuckHealth(assetIdStr)
911+ let health = valueOrElse(getInteger(keyHealth), 100)
912+ if ((health != 100))
913+ then throw("Please heal your duck before unstaking")
914+ else [ScriptTransfer(i.caller, 1, assetId), DeleteEntry(timeKey), DeleteEntry(keyHealth), DeleteEntry(keyDuckLocation(assetIdStr)), DeleteEntry(keyDuckIdToOwner(assetIdStr)), DeleteEntry(keyStakedTimeByTypeAssetIdAndOwner(DUCKPREFIX, assetIdStr, address)), DeleteEntry(keyStakedDuckByOwner(address))]
915+ }
916+ }
917+ }
918+ else throw("Strict value is not equal to itself.")
919+ }
874920
875921
876922
877923 @Callable(i)
878-func flight (message,sig) = if (!(sigVerify_8Kb(message, sig, pub)))
879- then throw("signature does not match")
880- else if ((size(i.payments) != 0))
881- then throw("flight doesn't require any payments")
882- else {
883- let parts = split(toUtf8String(message), ";")
884- let hp = split(split(parts[0], "|")[0], "_")
885- let curHP = parseIntValue(hp[0])
886- let newHP = parseIntValue(hp[1])
887- let newLocAndTime = split(parts[1], ":")
888- let newLocation = newLocAndTime[0]
889- let time = parseIntValue(newLocAndTime[1])
890- if (if ((time > (lastBlock.timestamp + FIVEMINUTESMILLIS)))
891- then true
892- else ((lastBlock.timestamp - FIVEMINUTESMILLIS) > time))
893- then throw("signature outdated")
894- else {
895- let duckAssetId = valueOrErrorMessage(getString(keyStakedDuckByOwner(toString(i.caller))), "You don't have a duck staked")
896- let keyHealth = keyDuckHealth(duckAssetId)
897- let oldFromState = valueOrElse(getInteger(keyHealth), 100)
898- if ((oldFromState != curHP))
899- then throw(((("oldHealth=" + toString(valueOrElse(getInteger(keyHealth), 100))) + " from state does not match one from flight log=") + toString(curHP)))
900- else if ((0 >= curHP))
901- then throw("You can't fly with zero health")
902- else {
903- let locKey = keyDuckLocation(duckAssetId)
904- let curLocation = valueOrElse(getString(locKey), DEFAULTLOCATION)
905- if ((newLocation == curLocation))
906- then throw("You can't fly to the same location")
907- else $Tuple2([StringEntry(locKey, if ((newHP > 0))
908- then newLocation
909- else curLocation), IntegerEntry(keyHealth, newHP)], unit)
910- }
911- }
912- }
924+func claimRes (amount,landAssetIdStr) = {
925+ let blocked = checkBlocked()
926+ if ((blocked == blocked))
927+ then if ((size(i.payments) != 0))
928+ then throw("claimRes doesn't require any payments")
929+ else {
930+ let addr = toString(i.originCaller)
931+ let result = claimResInternal(addr, amount)
932+ $Tuple2((result._1 :+ StringEntry(result._2, makeString(result._3, ":"))), result._3[bpIdxRes])
933+ }
934+ else throw("Strict value is not equal to itself.")
935+ }
913936
914937
915938
916939 @Callable(i)
917-func setHealth (health,duckAssetId) = if (if ((0 > health))
918- then true
919- else (health > 100))
920- then throw("HP should be within 0..100")
921- else [IntegerEntry(keyDuckHealth(duckAssetId), health)]
940+func flight (message,sig) = {
941+ let blocked = checkBlocked()
942+ if ((blocked == blocked))
943+ then if (!(sigVerify_8Kb(message, sig, pub)))
944+ then throw("signature does not match")
945+ else if ((size(i.payments) != 0))
946+ then throw("flight doesn't require any payments")
947+ else {
948+ let parts = split(toUtf8String(message), ";")
949+ let hp = split(split(parts[0], "|")[0], "_")
950+ let curHP = parseIntValue(hp[0])
951+ let newHP = parseIntValue(hp[1])
952+ let newLocAndTime = split(parts[1], ":")
953+ let newLocation = newLocAndTime[0]
954+ let time = parseIntValue(newLocAndTime[1])
955+ if (if ((time > (lastBlock.timestamp + FIVEMINUTESMILLIS)))
956+ then true
957+ else ((lastBlock.timestamp - FIVEMINUTESMILLIS) > time))
958+ then throw("signature outdated")
959+ else {
960+ let duckAssetId = valueOrErrorMessage(getString(keyStakedDuckByOwner(toString(i.caller))), "You don't have a duck staked")
961+ let keyHealth = keyDuckHealth(duckAssetId)
962+ let oldFromState = valueOrElse(getInteger(keyHealth), 100)
963+ if ((oldFromState != curHP))
964+ then throw(((("oldHealth=" + toString(valueOrElse(getInteger(keyHealth), 100))) + " from state does not match one from flight log=") + toString(curHP)))
965+ else if ((0 >= curHP))
966+ then throw("You can't fly with zero health")
967+ else {
968+ let locKey = keyDuckLocation(duckAssetId)
969+ let curLocation = valueOrElse(getString(locKey), DEFAULTLOCATION)
970+ if ((newLocation == curLocation))
971+ then throw("You can't fly to the same location")
972+ else $Tuple2([StringEntry(locKey, if ((newHP > 0))
973+ then newLocation
974+ else curLocation), IntegerEntry(keyHealth, newHP)], unit)
975+ }
976+ }
977+ }
978+ else throw("Strict value is not equal to itself.")
979+ }
922980
923981
924982
925983 @Callable(i)
926-func heal (matType,amount) = if (if ((0 > matType))
927- then true
928- else (matType >= NUMRES))
929- then throw(("Unknown material: " + toString(matType)))
930- else if ((0 >= amount))
931- then throw(("Amount should be positive! " + toString(amount)))
932- else {
933- let duckAssetId = valueOrErrorMessage(getString(keyStakedDuckByOwner(toString(i.caller))), "You don't have a duck staked")
934- let keyHealth = keyDuckHealth(duckAssetId)
935- let oldHealth = valueOrElse(getInteger(keyHealth), 100)
936- if ((oldHealth >= 100))
937- then throw("HP should be < 100 to heal")
984+func setHealth (health,duckAssetId) = {
985+ let blocked = checkBlocked()
986+ if ((blocked == blocked))
987+ then if (if ((0 > health))
988+ then true
989+ else (health > 100))
990+ then throw("HP should be within 0..100")
991+ else [IntegerEntry(keyDuckHealth(duckAssetId), health)]
992+ else throw("Strict value is not equal to itself.")
993+ }
994+
995+
996+
997+@Callable(i)
998+func heal (matType,amount) = {
999+ let blocked = checkBlocked()
1000+ if ((blocked == blocked))
1001+ then if (if ((0 > matType))
1002+ then true
1003+ else (matType >= NUMRES))
1004+ then throw(("Unknown material: " + toString(matType)))
1005+ else if ((0 >= amount))
1006+ then throw(("Amount should be positive! " + toString(amount)))
9381007 else {
939- let bpKey = keyBackpackByDuck(duckAssetId)
940- let currentPack = getBackpack(bpKey)
941- let mList = split(currentPack[bpIdxMat], "_")
942- let currentAmount = parseIntValue(mList[matType])
943- let deltaHealth = min([(amount / HEALCOST), (100 - oldHealth)])
944- let spendAmount = (deltaHealth * HEALCOST)
945- if ((spendAmount > currentAmount))
946- then throw(((((("You need " + toString(spendAmount)) + " of ") + matTypes[matType]) + " to heal, but you backpack contains ") + toString(currentAmount)))
1008+ let duckAssetId = valueOrErrorMessage(getString(keyStakedDuckByOwner(toString(i.caller))), "You don't have a duck staked")
1009+ let keyHealth = keyDuckHealth(duckAssetId)
1010+ let oldHealth = valueOrElse(getInteger(keyHealth), 100)
1011+ if ((oldHealth >= 100))
1012+ then throw("HP should be < 100 to heal")
9471013 else {
948- let newMat = subOneInList(mList, matType, spendAmount)
1014+ let bpKey = keyBackpackByDuck(duckAssetId)
1015+ let currentPack = getBackpack(bpKey)
1016+ let mList = split(currentPack[bpIdxMat], "_")
1017+ let currentAmount = parseIntValue(mList[matType])
1018+ let deltaHealth = min([(amount / HEALCOST), (100 - oldHealth)])
1019+ let spendAmount = (deltaHealth * HEALCOST)
1020+ if ((spendAmount > currentAmount))
1021+ then throw(((((("You need " + toString(spendAmount)) + " of ") + matTypes[matType]) + " to heal, but you backpack contains ") + toString(currentAmount)))
1022+ else {
1023+ let newMat = subOneInList(mList, matType, spendAmount)
9491024 [IntegerEntry(keyHealth, (oldHealth + deltaHealth)), StringEntry(bpKey, makeString([currentPack[bpIdxLevel], currentPack[bpIdxRes], newMat, currentPack[bpIdxProd]], ":"))]
1025+ }
9501026 }
9511027 }
952- }
1028+ else throw("Strict value is not equal to itself.")
1029+ }
9531030
9541031
9551032
9561033 @Callable(i)
9571034 func updateBackpack (duckAssetId,newPack) = if ((i.caller != economyContract))
9581035 then throw("permission denied")
9591036 else $Tuple2([StringEntry(keyBackpackByDuck(duckAssetId), newPack)], newPack)
9601037
9611038
9621039
9631040 @Callable(i)
964-func expeditionBuy (message,sig) = if ((size(i.payments) != 1))
965- then throw("Exactly one payment required")
966- else {
967- let pmt = value(i.payments[0])
968- if ((pmt.assetId != usdnAssetId))
969- then throw("Allowed USDN payment only!")
970- else if ((pmt.amount != EXPUSDN))
971- then throw(("Payment attached should be " + toString(EXPUSDN)))
972- else {
973- let result = expeditionCommon(false, i.caller, i.transactionId, message, sig)
974- if ((result._2 == ""))
975- then result
976- else $Tuple2((result._1 :+ ScriptTransfer(economyContract, pmt.amount, usdnAssetId)), result._2)
977- }
978- }
1041+func expeditionBuy (message,sig) = {
1042+ let blocked = checkBlocked()
1043+ if ((blocked == blocked))
1044+ then if ((size(i.payments) != 1))
1045+ then throw("Exactly one payment required")
1046+ else {
1047+ let pmt = value(i.payments[0])
1048+ if ((pmt.assetId != usdnAssetId))
1049+ then throw("Allowed USDN payment only!")
1050+ else if ((pmt.amount != EXPUSDN))
1051+ then throw(("Payment attached should be " + toString(EXPUSDN)))
1052+ else {
1053+ let result = expeditionCommon(false, i.caller, i.transactionId, message, sig)
1054+ if ((result._2 == ""))
1055+ then result
1056+ else $Tuple2((result._1 :+ ScriptTransfer(economyContract, pmt.amount, usdnAssetId)), result._2)
1057+ }
1058+ }
1059+ else throw("Strict value is not equal to itself.")
1060+ }
9791061
9801062
9811063
9821064 @Callable(i)
983-func expedition (message,sig) = if ((size(i.payments) != 0))
984- then throw("expedition doesn't require any payments")
985- else expeditionCommon(true, i.caller, i.transactionId, message, sig)
1065+func expedition (message,sig) = {
1066+ let blocked = checkBlocked()
1067+ if ((blocked == blocked))
1068+ then if ((size(i.payments) != 0))
1069+ then throw("expedition doesn't require any payments")
1070+ else expeditionCommon(true, i.caller, i.transactionId, message, sig)
1071+ else throw("Strict value is not equal to itself.")
1072+ }
9861073
9871074
9881075
9891076 @Callable(i)
990-func upgradeInfra (landAssetIdIgnored) = if ((size(i.payments) != 0))
991- then throw("Infrastructure upgrade doesn't require any payments")
992- else upInfraCommon(true, i.caller, 0)
1077+func upgradeInfra (landAssetIdIgnored) = {
1078+ let blocked = checkBlocked()
1079+ if ((blocked == blocked))
1080+ then if ((size(i.payments) != 0))
1081+ then throw("Infrastructure upgrade doesn't require any payments")
1082+ else upInfraCommon(true, i.caller, 0)
1083+ else throw("Strict value is not equal to itself.")
1084+ }
9931085
9941086
9951087
9961088 @Callable(i)
997-func upgradeInfraUsdn (landAssetIdIgnored) = if ((size(i.payments) != 1))
998- then throw("Exactly one payment required")
999- else {
1000- let pmt = value(i.payments[0])
1001- if ((pmt.assetId != usdnAssetId))
1002- then throw("Allowed USDN payment only!")
1089+func upgradeInfraUsdn (landAssetIdIgnored) = {
1090+ let blocked = checkBlocked()
1091+ if ((blocked == blocked))
1092+ then if ((size(i.payments) != 1))
1093+ then throw("Exactly one payment required")
10031094 else {
1004- let result = upInfraCommon(false, i.caller, pmt.amount)
1005- $Tuple2((result._1 :+ ScriptTransfer(economyContract, pmt.amount, usdnAssetId)), result._2)
1095+ let pmt = value(i.payments[0])
1096+ if ((pmt.assetId != usdnAssetId))
1097+ then throw("Allowed USDN payment only!")
1098+ else {
1099+ let result = upInfraCommon(false, i.caller, pmt.amount)
1100+ $Tuple2((result._1 :+ ScriptTransfer(economyContract, pmt.amount, usdnAssetId)), result._2)
1101+ }
10061102 }
1007- }
1103+ else throw("Strict value is not equal to itself.")
1104+ }
10081105
10091106
10101107
10111108 @Callable(i)
1012-func activateArtifact (artName) = if ((size(i.payments) != 0))
1013- then throw("Artifact activation doesn't require any payments")
1014- else {
1015- let result = match artName {
1016- case _ =>
1017- if (("PRESALE" == $match0))
1018- then activatePresaleArt(toString(i.caller))
1019- else throw("Unknown artifact")
1020- }
1021- result
1022- }
1109+func activateArtifact (artName) = {
1110+ let blocked = checkBlocked()
1111+ if ((blocked == blocked))
1112+ then if ((size(i.payments) != 0))
1113+ then throw("Artifact activation doesn't require any payments")
1114+ else {
1115+ let result = match artName {
1116+ case _ =>
1117+ if (("PRESALE" == $match0))
1118+ then activatePresaleArt(toString(i.caller))
1119+ else throw("Unknown artifact")
1120+ }
1121+ result
1122+ }
1123+ else throw("Strict value is not equal to itself.")
1124+ }
10231125
10241126
10251127
10261128 @Callable(i)
10271129 func mergeLands (landAssetIds) = if ((i.caller != this))
10281130 then throw("permission denied")
1029- else if ((size(i.payments) != 0))
1030- then throw("Lands merging doesn't require any payments")
1031- else mergeCommon(true, toString(i.caller), 0, landAssetIds, i.transactionId)
1131+ else {
1132+ let blocked = checkBlocked()
1133+ if ((blocked == blocked))
1134+ then if ((size(i.payments) != 0))
1135+ then throw("Lands merging doesn't require any payments")
1136+ else mergeCommon(true, toString(i.caller), 0, landAssetIds, i.transactionId)
1137+ else throw("Strict value is not equal to itself.")
1138+ }
10321139
10331140
10341141
10351142 @Callable(i)
10361143 func mergeLandsUsdn (landAssetIds) = if ((i.caller != this))
10371144 then throw("permission denied")
1038- else if ((size(i.payments) != 1))
1039- then throw("Exactly one payment required")
1040- else {
1041- let pmt = value(i.payments[0])
1042- if ((pmt.assetId != usdnAssetId))
1043- then throw("Allowed USDN payment only!")
1145+ else {
1146+ let blocked = checkBlocked()
1147+ if ((blocked == blocked))
1148+ then if ((size(i.payments) != 1))
1149+ then throw("Exactly one payment required")
10441150 else {
1045- let result = mergeCommon(false, toString(i.caller), pmt.amount, landAssetIds, i.transactionId)
1046- $Tuple2((result._1 :+ ScriptTransfer(economyContract, pmt.amount, usdnAssetId)), result._2)
1151+ let pmt = value(i.payments[0])
1152+ if ((pmt.assetId != usdnAssetId))
1153+ then throw("Allowed USDN payment only!")
1154+ else {
1155+ let result = mergeCommon(false, toString(i.caller), pmt.amount, landAssetIds, i.transactionId)
1156+ $Tuple2((result._1 :+ ScriptTransfer(economyContract, pmt.amount, usdnAssetId)), result._2)
1157+ }
10471158 }
1048- }
1159+ else throw("Strict value is not equal to itself.")
1160+ }
10491161
10501162
10511163
10521164 @Callable(i)
10531165 func splitByGlobalWeightsREADONLY (amount) = $Tuple2(nil, getNeededMaterials(amount))
10541166
10551167
10561168
10571169 @Callable(i)
10581170 func splitByLocalWeightsREADONLY (amount,terrains) = {
10591171 let terrainCounts = countTerrains(terrains)
10601172 $Tuple2(nil, distributeByWeights(amount, terrainCounts))
10611173 }
10621174
10631175

github/deemru/w8io/3ef1775 
295.05 ms