tx · 6q9jKmWEtf4idm22x5gtq7n6L7fSH7RW7HtZjWQmmbbC

3N9be2mwrA52WJho6DiesZkk4351GvpnWuj:  -0.04000000 Waves

2022.09.06 13:40 [2217149] smart account 3N9be2mwrA52WJho6DiesZkk4351GvpnWuj > SELF 0.00000000 Waves

{ "type": 13, "id": "6q9jKmWEtf4idm22x5gtq7n6L7fSH7RW7HtZjWQmmbbC", "fee": 4000000, "feeAssetId": null, "timestamp": 1662460896027, "version": 1, "sender": "3N9be2mwrA52WJho6DiesZkk4351GvpnWuj", "senderPublicKey": "6mzmbCza9iqbzxMEELcEA4Xc9NeF4CYpbTtz1zMK3C7x", "proofs": [ "3wYdw17rn7WTdLgR2vK7Sa7yMktzmpKxrEraacVFWcZ5Zt5FsB3NPZh5op7gxNpUprPP6Q8BHRVKDhFNyQnrXfPP", "3MbeAzTyv6oNx7Hjjy36ZgQZhx9NygQ5tkNnwsq4Euch9MzVfZ6uVbXbTxMiTMQ6rk17m3ikFnBwoEVs4xwD8PA7", "2V6pz5319cLTsP5umyJgf19ucDD7hqZBUqNf82gqVQgTPHrfC5BSYkiAjxGjD5RzhtGSQ2ywM1s9zk5K4FpcFqcX" ], "script": "base64:BgJXCAISDgoMCAgICAgIAQEBAQEBEgUKAwgIARIAEgASBQoDCAEIEgMKAQESBAoCAQgSABIFCgMIAQESBAoCAQESBAoCCAESBQoDCAEBEgYKBAgIAQESABIAqAEBD2dldFN0cmluZ09yRmFpbAIHYWRkcmVzcwNrZXkJARN2YWx1ZU9yRXJyb3JNZXNzYWdlAgkAnQgCBQdhZGRyZXNzBQNrZXkJALkJAgkAzAgCAgptYW5kYXRvcnkgCQDMCAIJAKUIAQUHYWRkcmVzcwkAzAgCAgEuCQDMCAIFA2tleQkAzAgCAg8gaXMgbm90IGRlZmluZWQFA25pbAIAAQVsY2FsYwEBbAkAuQgBBQFsAQ5nZXROdW1iZXJCeUtleQEDa2V5CQELdmFsdWVPckVsc2UCCQCaCAIFBHRoaXMFA2tleQAAAQ5nZXRTdHJpbmdCeUtleQEDa2V5CQELdmFsdWVPckVsc2UCCQCdCAIFBHRoaXMFA2tleQIAAQxnZXRCb29sQnlLZXkBA2tleQkBC3ZhbHVlT3JFbHNlAgkAmwgCBQR0aGlzBQNrZXkHARhnZXROdW1iZXJCeUFkZHJlc3NBbmRLZXkCB2FkZHJlc3MDa2V5CQELdmFsdWVPckVsc2UCCQCaCAIFB2FkZHJlc3MFA2tleQAAARhnZXRTdHJpbmdCeUFkZHJlc3NBbmRLZXkCB2FkZHJlc3MDa2V5CQELdmFsdWVPckVsc2UCCQCdCAIJARFAZXh0ck5hdGl2ZSgxMDYyKQEFB2FkZHJlc3MFA2tleQIAARZnZXRCb29sQnlBZGRyZXNzQW5kS2V5AgdhZGRyZXNzA2tleQkBC3ZhbHVlT3JFbHNlAgkAmwgCBQdhZGRyZXNzBQNrZXkHAQlhc0FueUxpc3QBAXYEByRtYXRjaDAFAXYDCQABAgUHJG1hdGNoMAIJTGlzdFtBbnldBAFsBQckbWF0Y2gwBQFsCQACAQIbZmFpbCB0byBjYXN0IGludG8gTGlzdFtBbnldAQhhc1N0cmluZwEBdgQHJG1hdGNoMAUBdgMJAAECBQckbWF0Y2gwAgZTdHJpbmcEAXMFByRtYXRjaDAFAXMJAAIBAhhmYWlsIHRvIGNhc3QgaW50byBTdHJpbmcBBWFzSW50AQF2BAckbWF0Y2gwBQF2AwkAAQIFByRtYXRjaDACA0ludAQBaQUHJG1hdGNoMAUBaQkAAgECFWZhaWwgdG8gY2FzdCBpbnRvIEludAEHYXNCeXRlcwEDdmFsBAckbWF0Y2gwBQN2YWwDCQABAgUHJG1hdGNoMAIKQnl0ZVZlY3RvcgQHdmFsQnl0ZQUHJG1hdGNoMAUHdmFsQnl0ZQkAAgECHGZhaWwgdG8gY2FzdCBpbnRvIEJ5dGVWZWN0b3IBCWFzUGF5bWVudAEBdgQHJG1hdGNoMAUBdgMJAAECBQckbWF0Y2gwAg9BdHRhY2hlZFBheW1lbnQEAXAFByRtYXRjaDAFAXAJAAIBAiFmYWlsIHRvIGNhc3QgaW50byBBdHRhY2hlZFBheW1lbnQBEmFzU3dhcFBhcmFtc1NUUlVDVAEBdgQHJG1hdGNoMAUBdgMJAAECBQckbWF0Y2gwAiMoSW50LCBJbnQsIEludCwgSW50LCBJbnQsIEludCwgSW50KQQGc3RydWN0BQckbWF0Y2gwBQZzdHJ1Y3QJAAIBAh1mYWlsIHRvIGNhc3QgaW50byBUdXBsZTUgaW50cwADU0VQAgJfXwAHV0FWRUxFVACAwtcvAAVQQVVMSQDAhD0ACFBSSUNFTEVUAMCEPQAOREVGQVVMVFNXQVBGRUUAoJwBAAtCUlBST1RFQ1RFRACgjQYADElkeE5ldEFtb3VudAAAAAxJZHhGZWVBbW91bnQAAQAOSWR4R3Jvc3NBbW91bnQAAgAZSWR4Q29udHJvbENmZ05ldXRyaW5vRGFwcAABABhJZHhDb250cm9sQ2ZnQXVjdGlvbkRhcHAAAgAUSWR4Q29udHJvbENmZ1JwZERhcHAAAwAVSWR4Q29udHJvbENmZ01hdGhEYXBwAAQAHElkeENvbnRyb2xDZmdMaXF1aWRhdGlvbkRhcHAABQAVSWR4Q29udHJvbENmZ1Jlc3REYXBwAAYAHUlkeENvbnRyb2xDZmdOb2RlUmVnaXN0cnlEYXBwAAcAHElkeENvbnRyb2xDZmdOc2J0U3Rha2luZ0RhcHAACAAZSWR4Q29udHJvbENmZ01lZGlhdG9yRGFwcAAJABxJZHhDb250cm9sQ2ZnU3VyZlN0YWtpbmdEYXBwAAoAIElkeENvbnRyb2xDZmdHbnNidENvbnRyb2xsZXJEYXBwAAsBEWtleUNvbnRyb2xBZGRyZXNzAAIcJXMlc19fY29uZmlnX19jb250cm9sQWRkcmVzcwENa2V5Q29udHJvbENmZwACESVzX19jb250cm9sQ29uZmlnARRyZWFkQ29udHJvbENmZ09yRmFpbAEHY29udHJvbAkAtQkCCQEPZ2V0U3RyaW5nT3JGYWlsAgUHY29udHJvbAkBDWtleUNvbnRyb2xDZmcABQNTRVABGGdldENvbnRyYWN0QWRkcmVzc09yRmFpbAIKY29udHJvbENmZwNpZHgJARN2YWx1ZU9yRXJyb3JNZXNzYWdlAgkApggBCQCRAwIFCmNvbnRyb2xDZmcFA2lkeAkArAICAi1Db250cm9sIGNmZyBkb2Vzbid0IGNvbnRhaW4gYWRkcmVzcyBhdCBpbmRleCAJAKQDAQUDaWR4AA9jb250cm9sQ29udHJhY3QJARFAZXh0ck5hdGl2ZSgxMDYyKQEJAQt2YWx1ZU9yRWxzZQIJAJ0IAgUEdGhpcwkBEWtleUNvbnRyb2xBZGRyZXNzAAIjM040TlM3ZDRKbzlhNkYxNExpRlVLS1lWZFVra2YyZVA0WngACmNvbnRyb2xDZmcJARRyZWFkQ29udHJvbENmZ09yRmFpbAEFD2NvbnRyb2xDb250cmFjdAAMbWF0aENvbnRyYWN0CQEYZ2V0Q29udHJhY3RBZGRyZXNzT3JGYWlsAgUKY29udHJvbENmZwUVSWR4Q29udHJvbENmZ01hdGhEYXBwABNuc2J0U3Rha2luZ0NvbnRyYWN0CQEYZ2V0Q29udHJhY3RBZGRyZXNzT3JGYWlsAgUKY29udHJvbENmZwUcSWR4Q29udHJvbENmZ05zYnRTdGFraW5nRGFwcAATc3VyZlN0YWtpbmdDb250cmFjdAkBGGdldENvbnRyYWN0QWRkcmVzc09yRmFpbAIFCmNvbnRyb2xDZmcFHElkeENvbnRyb2xDZmdTdXJmU3Rha2luZ0RhcHAAF2duc2J0Q29udHJvbGxlckNvbnRyYWN0CQEYZ2V0Q29udHJhY3RBZGRyZXNzT3JGYWlsAgUKY29udHJvbENmZwUgSWR4Q29udHJvbENmZ0duc2J0Q29udHJvbGxlckRhcHAAD2F1Y3Rpb25Db250cmFjdAkBGGdldENvbnRyYWN0QWRkcmVzc09yRmFpbAIFCmNvbnRyb2xDZmcFGElkeENvbnRyb2xDZmdBdWN0aW9uRGFwcAAUbm9kZVJlZ2lzdHJ5Q29udHJhY3QJARhnZXRDb250cmFjdEFkZHJlc3NPckZhaWwCBQpjb250cm9sQ2ZnBR1JZHhDb250cm9sQ2ZnTm9kZVJlZ2lzdHJ5RGFwcAASTmV1dHJpbm9Bc3NldElkS2V5AhFuZXV0cmlub19hc3NldF9pZAAOQm9uZEFzc2V0SWRLZXkCDWJvbmRfYXNzZXRfaWQAEkF1Y3Rpb25Db250cmFjdEtleQIQYXVjdGlvbl9jb250cmFjdAAWTnNidFN0YWtpbmdDb250cmFjdEtleQITbnNidFN0YWtpbmdDb250cmFjdAAWTGlxdWlkYXRpb25Db250cmFjdEtleQIUbGlxdWlkYXRpb25fY29udHJhY3QADlJQRENvbnRyYWN0S2V5AgxycGRfY29udHJhY3QAEUNvbnRvbENvbnRyYWN0S2V5AhBjb250cm9sX2NvbnRyYWN0AA9NYXRoQ29udHJhY3RLZXkCDW1hdGhfY29udHJhY3QAG0JhbGFuY2VXYXZlc0xvY2tJbnRlcnZhbEtleQIbYmFsYW5jZV93YXZlc19sb2NrX2ludGVydmFsAB5CYWxhbmNlTmV1dHJpbm9Mb2NrSW50ZXJ2YWxLZXkCHmJhbGFuY2VfbmV1dHJpbm9fbG9ja19pbnRlcnZhbAAVTWluV2F2ZXNTd2FwQW1vdW50S2V5AhVtaW5fd2F2ZXNfc3dhcF9hbW91bnQAGE1pbk5ldXRyaW5vU3dhcEFtb3VudEtleQIYbWluX25ldXRyaW5vX3N3YXBfYW1vdW50ABtOb2RlT3JhY2xlUHJvdmlkZXJQdWJLZXlLZXkCFG5vZGVfb3JhY2xlX3Byb3ZpZGVyABVOZXV0cmlub091dEZlZVBhcnRLZXkCGG5ldXRyaW5vT3V0X3N3YXBfZmVlUGFydAASV2F2ZXNPdXRGZWVQYXJ0S2V5AhV3YXZlc091dF9zd2FwX2ZlZVBhcnQBD2tleU5vZGVSZWdpc3RyeQEHYWRkcmVzcwkArAICAgQlc19fBQdhZGRyZXNzAAhQcmljZUtleQIFcHJpY2UADVByaWNlSW5kZXhLZXkCC3ByaWNlX2luZGV4AAxJc0Jsb2NrZWRLZXkCCmlzX2Jsb2NrZWQBEmdldFByaWNlSGlzdG9yeUtleQEFYmxvY2sJAKwCAgkArAICBQhQcmljZUtleQIBXwkApAMBBQVibG9jawEYZ2V0SGVpZ2h0UHJpY2VCeUluZGV4S2V5AQVpbmRleAkArAICCQCsAgIFDVByaWNlSW5kZXhLZXkCAV8JAKQDAQUFaW5kZXgBFWdldFN0YWtpbmdOb2RlQnlJbmRleAEDaWR4CQEOZ2V0U3RyaW5nQnlLZXkBCQC5CQIJAMwIAgIGJXMlZCVzCQDMCAICBWxlYXNlCQDMCAIJAKQDAQUDaWR4CQDMCAICC25vZGVBZGRyZXNzBQNuaWwFA1NFUAEcZ2V0U3Rha2luZ05vZGVBZGRyZXNzQnlJbmRleAEDaWR4CQERQGV4dHJOYXRpdmUoMTA2MikBCQEVZ2V0U3Rha2luZ05vZGVCeUluZGV4AQUDaWR4AR9nZXRSZXNlcnZlZEFtb3VudEZvclNwb25zb3JzaGlwAAkBC3ZhbHVlT3JFbHNlAgkAmggCBQR0aGlzCQC5CQIJAMwIAgIEJXMlcwkAzAgCAgVsZWFzZQkAzAgCAhdzcG9uc29yc2hpcFdhdmVzUmVzZXJ2ZQUDbmlsBQNTRVAJAGgCAOgHBQdXQVZFTEVUARhnZXRCYWxhbmNlVW5sb2NrQmxvY2tLZXkBBW93bmVyCQCsAgICFWJhbGFuY2VfdW5sb2NrX2Jsb2NrXwUFb3duZXIBDWdldExlYXNlSWRLZXkBCW5vZGVJbmRleAkAuQkCCQDMCAICBiVzJWQlcwkAzAgCAgVsZWFzZQkAzAgCCQCkAwEFCW5vZGVJbmRleAkAzAgCAgJpZAUDbmlsBQNTRVABFmdldExlYXNlSWRCeUFkZHJlc3NLZXkBC25vZGVBZGRyZXNzCQC5CQIJAMwIAgIGJXMlcyVzCQDMCAICDmxlYXNlQnlBZGRyZXNzCQDMCAIFC25vZGVBZGRyZXNzCQDMCAICAmlkBQNuaWwFA1NFUAERZ2V0TGVhc2VBbW91bnRLZXkBCW5vZGVJbmRleAkAuQkCCQDMCAICBiVzJWQlcwkAzAgCAgVsZWFzZQkAzAgCCQCkAwEFCW5vZGVJbmRleAkAzAgCAgZhbW91bnQFA25pbAUDU0VQARpnZXRMZWFzZUFtb3VudEJ5QWRkcmVzc0tleQELbm9kZUFkZHJlc3MJALkJAgkAzAgCAgYlcyVzJXMJAMwIAgIObGVhc2VCeUFkZHJlc3MJAMwIAgULbm9kZUFkZHJlc3MJAMwIAgIGYW1vdW50BQNuaWwFA1NFUAEYZ2V0TGVhc2VHcm91cE5vZGVMaXN0S2V5AQhncm91cE51bQkAuQkCCQDMCAICBiVzJWQlcwkAzAgCAgpsZWFzZUdyb3VwCQDMCAIJAKQDAQUIZ3JvdXBOdW0JAMwIAgIIbm9kZUxpc3QFA25pbAUDU0VQARBtaW5Td2FwQW1vdW50S0VZAQhzd2FwVHlwZQkArAICCQCsAgICBG1pbl8FCHN3YXBUeXBlAgxfc3dhcF9hbW91bnQBDnRvdGFsTG9ja2VkS0VZAQhzd2FwVHlwZQkArAICAg1iYWxhbmNlX2xvY2tfBQhzd2FwVHlwZQEUdG90YWxMb2NrZWRCeVVzZXJLRVkCCHN3YXBUeXBlBW93bmVyCQC5CQIJAMwIAgIMYmFsYW5jZV9sb2NrCQDMCAIFCHN3YXBUeXBlCQDMCAIFBW93bmVyBQNuaWwCAV8BFmJhbGFuY2VMb2NrSW50ZXJ2YWxLRVkBCHN3YXBUeXBlCQCsAgIJAKwCAgIIYmFsYW5jZV8FCHN3YXBUeXBlAg5fbG9ja19pbnRlcnZhbAEabm9kZUJhbGFuY2VMb2NrSW50ZXJ2YWxLRVkAAhpiYWxhbmNlX25vZGVfbG9ja19pbnRlcnZhbAENb3V0RmVlUGFydEtFWQEIc3dhcFR5cGUJAKwCAgUIc3dhcFR5cGUCEE91dF9zd2FwX2ZlZVBhcnQBEXN3YXBzVGltZWZyYW1lS0VZAAIPc3dhcHNfdGltZWZyYW1lAQ5iclByb3RlY3RlZEtFWQACF21pbl9CUl9wcm90ZWN0aW9uX2xldmVsARFtaW5Td2FwQW1vdW50UkVBRAEIc3dhcFR5cGUJAQt2YWx1ZU9yRWxzZQIJAJoIAgUEdGhpcwkBEG1pblN3YXBBbW91bnRLRVkBBQhzd2FwVHlwZQAAARJzd2Fwc1RpbWVmcmFtZVJFQUQACQELdmFsdWVPckVsc2UCCQCaCAIFBHRoaXMJARFzd2Fwc1RpbWVmcmFtZUtFWQAAoAsBD3RvdGFsTG9ja2VkUkVBRAEIc3dhcFR5cGUJAQt2YWx1ZU9yRWxzZQIJAJoIAgUEdGhpcwkBDnRvdGFsTG9ja2VkS0VZAQUIc3dhcFR5cGUAAAEVdG90YWxMb2NrZWRCeVVzZXJSRUFEAghzd2FwVHlwZQVvd25lcgkBC3ZhbHVlT3JFbHNlAgkAmggCBQR0aGlzCQEUdG90YWxMb2NrZWRCeVVzZXJLRVkCBQhzd2FwVHlwZQUFb3duZXIAAAEXYmFsYW5jZUxvY2tJbnRlcnZhbFJFQUQBCHN3YXBUeXBlCQELdmFsdWVPckVsc2UCCQCaCAIFBHRoaXMJARZiYWxhbmNlTG9ja0ludGVydmFsS0VZAQUIc3dhcFR5cGUAoAsBG25vZGVCYWxhbmNlTG9ja0ludGVydmFsUkVBRAAJAQt2YWx1ZU9yRWxzZQIJAJoIAgUEdGhpcwkBGm5vZGVCYWxhbmNlTG9ja0ludGVydmFsS0VZAAABARhrZXlTd2FwVXNlclNwZW50SW5QZXJpb2QBC3VzZXJBZGRyZXNzCQC5CQIJAMwIAgIEJXMlcwkAzAgCAhVzd2FwVXNlclNwZW50SW5QZXJpb2QJAMwIAgULdXNlckFkZHJlc3MFA25pbAUDU0VQARVrZXlVc2VyTGFzdFN3YXBIZWlnaHQBC3VzZXJBZGRyZXNzCQC5CQIJAMwIAgIEJXMlcwkAzAgCAhJ1c2VyTGFzdFN3YXBIZWlnaHQJAMwIAgULdXNlckFkZHJlc3MFA25pbAUDU0VQARZjb252ZXJ0TmV1dHJpbm9Ub1dhdmVzAgZhbW91bnQFcHJpY2UJAGsDCQBrAwUGYW1vdW50BQhQUklDRUxFVAUFcHJpY2UFB1dBVkVMRVQFBVBBVUxJARZjb252ZXJ0V2F2ZXNUb05ldXRyaW5vAgZhbW91bnQFcHJpY2UJAGsDCQBrAwUGYW1vdW50BQVwcmljZQUIUFJJQ0VMRVQFBVBBVUxJBQdXQVZFTEVUARJjb252ZXJ0V2F2ZXNUb0JvbmQCBmFtb3VudAVwcmljZQkBFmNvbnZlcnRXYXZlc1RvTmV1dHJpbm8CBQZhbW91bnQFBXByaWNlARZjb252ZXJ0SnNvbkFycmF5VG9MaXN0AQlqc29uQXJyYXkJALUJAgUJanNvbkFycmF5AgEsARFtaW5Td2FwQW1vdW50RkFJTAIIc3dhcFR5cGUNbWluU3dhcEFtb3VudAkAAgEJAKwCAgkArAICCQCsAgICGFRoZSBzcGVjaWZpZWQgYW1vdW50IGluIAUIc3dhcFR5cGUCKyBzd2FwIGlzIGxlc3MgdGhhbiB0aGUgcmVxdWlyZWQgbWluaW11bSBvZiAJAKQDAQUNbWluU3dhcEFtb3VudAEVZW1lcmdlbmN5U2h1dGRvd25GQUlMAAkAAgECWmNvbnRyYWN0IGlzIGJsb2NrZWQgYnkgRU1FUkdFTkNZIFNIVVRET1dOIGFjdGlvbnMgdW50aWxsIHJlYWN0aXZhdGlvbiBieSBlbWVyZ2VuY3kgb3JhY2xlcwEOcHJpY2VJbmRleEZBSUwFBWluZGV4CnByaWNlSW5kZXgLaW5kZXhIZWlnaHQMdW5sb2NrSGVpZ2h0D3ByZXZJbmRleEhlaWdodAkAAgEJAKwCAgkArAICCQCsAgIJAKwCAgkArAICCQCsAgIJAKwCAgkArAICCQCsAgICI2ludmFsaWQgcHJpY2UgaGlzdG9yeSBpbmRleDogaW5kZXg9CQCkAwEFBWluZGV4AgwgcHJpY2VJbmRleD0JAKQDAQUKcHJpY2VJbmRleAINIGluZGV4SGVpZ2h0PQkApAMBBQtpbmRleEhlaWdodAIOIHVubG9ja0hlaWdodD0JAKQDAQUMdW5sb2NrSGVpZ2h0AhEgcHJldkluZGV4SGVpZ2h0PQkApAMBBQ9wcmV2SW5kZXhIZWlnaHQAD25ldXRyaW5vQXNzZXRJZAkA2QQBCQEOZ2V0U3RyaW5nQnlLZXkBBRJOZXV0cmlub0Fzc2V0SWRLZXkACnByaWNlSW5kZXgJARhnZXROdW1iZXJCeUFkZHJlc3NBbmRLZXkCBQ9jb250cm9sQ29udHJhY3QFDVByaWNlSW5kZXhLZXkACWlzQmxvY2tlZAkBFmdldEJvb2xCeUFkZHJlc3NBbmRLZXkCBQ9jb250cm9sQ29udHJhY3QFDElzQmxvY2tlZEtleQAYbm9kZU9yYWNsZVByb3ZpZGVyUHViS2V5CQDZBAEJAQ5nZXRTdHJpbmdCeUtleQEFG05vZGVPcmFjbGVQcm92aWRlclB1YktleUtleQALYm9uZEFzc2V0SWQJANkEAQIsRjNpYXh6cnVGZUt1amZWZllTWkVrZWpwamg2N3dtUmZQQ1JIaU5tV0twM1oAFWRlcHJlY2F0ZWRCb25kQXNzZXRJZAkA2QQBAiw5NzVha1pCZm5NajUxM1U3TVphSEt6UXJtc0V4NWFFM3dkV0tUckhCaGJqRgAQbmV1dHJpbm9Db250cmFjdAUEdGhpcwAMY3VycmVudFByaWNlCQEYZ2V0TnVtYmVyQnlBZGRyZXNzQW5kS2V5AgUPY29udHJvbENvbnRyYWN0BQhQcmljZUtleQEbY2hlY2tJc1ZhbGlkTWluU3BvbnNvcmVkRmVlAQJ0eAQOTUlOVFJBTlNGRVJGRUUAoI0GBBZTcG9uc29yZWRGZWVVcHBlckJvdW5kAOgHBA9yZWFsTmV1dHJpbm9GZWUJARZjb252ZXJ0V2F2ZXNUb05ldXRyaW5vAgUOTUlOVFJBTlNGRVJGRUUFDGN1cnJlbnRQcmljZQQObWluTmV1dHJpbm9GZWUJAGgCBQ9yZWFsTmV1dHJpbm9GZWUAAgQObWF4TmV1dHJpbm9GZWUJAGsDBQ9yZWFsTmV1dHJpbm9GZWUFFlNwb25zb3JlZEZlZVVwcGVyQm91bmQAZAQIaW5wdXRGZWUJAQV2YWx1ZQEIBQJ0eBRtaW5TcG9uc29yZWRBc3NldEZlZQMDCQBnAgUIaW5wdXRGZWUFDm1pbk5ldXRyaW5vRmVlCQBnAgUObWF4TmV1dHJpbm9GZWUFCGlucHV0RmVlBwkAAAIIBQJ0eAdhc3NldElkBQ9uZXV0cmlub0Fzc2V0SWQHAQ9nZXRQcmljZUhpc3RvcnkBBWJsb2NrCQEYZ2V0TnVtYmVyQnlBZGRyZXNzQW5kS2V5AgUPY29udHJvbENvbnRyYWN0CQESZ2V0UHJpY2VIaXN0b3J5S2V5AQUFYmxvY2sBFWdldEhlaWdodFByaWNlQnlJbmRleAEFaW5kZXgJARhnZXROdW1iZXJCeUFkZHJlc3NBbmRLZXkCBQ9jb250cm9sQ29udHJhY3QJARhnZXRIZWlnaHRQcmljZUJ5SW5kZXhLZXkBBQVpbmRleAEWa2V5TG9ja1BhcmFtVXNlckFtb3VudAELdXNlckFkZHJlc3MJALkJAgkAzAgCAgYlcyVzJXMJAMwIAgILcGFyYW1CeVVzZXIJAMwIAgULdXNlckFkZHJlc3MJAMwIAgIGYW1vdW50BQNuaWwFA1NFUAAMc0lkeFN3YXBUeXBlAAEACnNJZHhTdGF0dXMAAgAMc0lkeEluQW1vdW50AAMACXNJZHhQcmljZQAEABBzSWR4T3V0TmV0QW1vdW50AAUAEHNJZHhPdXRGZWVBbW91bnQABgAPc0lkeFN0YXJ0SGVpZ2h0AAcAEnNJZHhTdGFydFRpbWVzdGFtcAAIAA1zSWR4RW5kSGVpZ2h0AAkAEHNJZHhFbmRUaW1lc3RhbXAACgAUc0lkeFNlbGZVbmxvY2tIZWlnaHQACwAUc0lkeFJhbmRVbmxvY2tIZWlnaHQADAAJc0lkeEluZGV4AA0AEHNJZHhXaXRoZHJhd1R4SWQADgALc0lkeE1pblJhbmQADwALc0lkeE1heFJhbmQAEAARc0lkeE91dFN1cmZBbW91bnQAEQAGc0lkeEJSABIBB3N3YXBLRVkCC3VzZXJBZGRyZXNzBHR4SWQJALkJAgkAzAgCAgQlcyVzCQDMCAIFC3VzZXJBZGRyZXNzCQDMCAIFBHR4SWQFA25pbAUDU0VQAQtzdHJTd2FwREFUQRIIc3dhcFR5cGUGc3RhdHVzCGluQW1vdW50BXByaWNlDG91dE5ldEFtb3VudAxvdXRGZWVBbW91bnQLc3RhcnRIZWlnaHQOc3RhcnRUaW1lc3RhbXAJZW5kSGVpZ2h0DGVuZFRpbWVzdGFtcBBzZWxmVW5sb2NrSGVpZ2h0EHJhbmRVbmxvY2tIZWlnaHQFaW5kZXgMd2l0aGRyYXdUeElkB3JhbmRNaW4HcmFuZE1heApvdXRTdXJmQW10AmJyCQC5CQIJAMwIAgIkJXMlcyVkJWQlZCVkJWQlZCVkJWQlZCVkJWQlcyVkJWQlZCVkCQDMCAIFCHN3YXBUeXBlCQDMCAIFBnN0YXR1cwkAzAgCBQhpbkFtb3VudAkAzAgCBQVwcmljZQkAzAgCBQxvdXROZXRBbW91bnQJAMwIAgUMb3V0RmVlQW1vdW50CQDMCAIFC3N0YXJ0SGVpZ2h0CQDMCAIFDnN0YXJ0VGltZXN0YW1wCQDMCAIFCWVuZEhlaWdodAkAzAgCBQxlbmRUaW1lc3RhbXAJAMwIAgUQc2VsZlVubG9ja0hlaWdodAkAzAgCBRByYW5kVW5sb2NrSGVpZ2h0CQDMCAIFBWluZGV4CQDMCAIFDHdpdGhkcmF3VHhJZAkAzAgCBQdyYW5kTWluCQDMCAIFB3JhbmRNYXgJAMwIAgUKb3V0U3VyZkFtdAkAzAgCBQJicgUDbmlsBQNTRVABD3BlbmRpbmdTd2FwREFUQQMIc3dhcFR5cGUNaW5Bc3NldEFtb3VudBBzZWxmVW5sb2NrSGVpZ2h0CQELc3RyU3dhcERBVEESBQhzd2FwVHlwZQIHUEVORElORwkApAMBBQ1pbkFzc2V0QW1vdW50AgEwAgEwAgEwCQCkAwEFBmhlaWdodAkApAMBCAUJbGFzdEJsb2NrCXRpbWVzdGFtcAIBMAIBMAkApAMBBRBzZWxmVW5sb2NrSGVpZ2h0AgEwAgEwAgROVUxMAgEwAgEwAgEwAgEwAQ5maW5pc2hTd2FwREFUQQkJZGF0YUFycmF5BXByaWNlDG91dE5ldEFtb3VudAxvdXRGZWVBbW91bnQQcmFuZFVubG9ja0hlaWdodAVpbmRleAx3aXRoZHJhd1R4SWQKb3V0U3VyZkFtdAJicgkBC3N0clN3YXBEQVRBEgkAkQMCBQlkYXRhQXJyYXkFDHNJZHhTd2FwVHlwZQIIRklOSVNIRUQJAJEDAgUJZGF0YUFycmF5BQxzSWR4SW5BbW91bnQJAKQDAQUFcHJpY2UJAKQDAQUMb3V0TmV0QW1vdW50CQCkAwEFDG91dEZlZUFtb3VudAkAkQMCBQlkYXRhQXJyYXkFD3NJZHhTdGFydEhlaWdodAkAkQMCBQlkYXRhQXJyYXkFEnNJZHhTdGFydFRpbWVzdGFtcAkApAMBBQZoZWlnaHQJAKQDAQgFCWxhc3RCbG9jawl0aW1lc3RhbXAJAJEDAgUJZGF0YUFycmF5BRRzSWR4U2VsZlVubG9ja0hlaWdodAkApAMBBRByYW5kVW5sb2NrSGVpZ2h0CQCkAwEFBWluZGV4BQx3aXRoZHJhd1R4SWQJAJEDAgUJZGF0YUFycmF5BQtzSWR4TWluUmFuZAkAkQMCBQlkYXRhQXJyYXkFC3NJZHhNYXhSYW5kCQCkAwEFCm91dFN1cmZBbXQJAKQDAQUCYnIBEnN3YXBEYXRhRmFpbE9yUkVBRAILdXNlckFkZHJlc3MIc3dhcFR4SWQEB3N3YXBLZXkJAQdzd2FwS0VZAgULdXNlckFkZHJlc3MFCHN3YXBUeElkCQC1CQIJARN2YWx1ZU9yRXJyb3JNZXNzYWdlAgkAnQgCBQR0aGlzBQdzd2FwS2V5CQCsAgICEW5vIHN3YXAgZGF0YSBmb3IgBQdzd2FwS2V5BQNTRVABCWFwcGx5RmVlcwMOYW1vdW50T3V0R3Jvc3MLaW5BbXRUb1NVUkYHZmVlUGFydAQJZmVlQW1vdW50CQBrAwUOYW1vdW50T3V0R3Jvc3MFB2ZlZVBhcnQFBVBBVUxJCQDMCAIJAGUCBQ5hbW91bnRPdXRHcm9zcwUJZmVlQW1vdW50CQDMCAIFCWZlZUFtb3VudAUDbmlsAQNhYnMBAXgDCQBmAgAABQF4CQEBLQEFAXgFAXgBCnNlbGVjdE5vZGUBDXVubGVhc2VBbW91bnQEDWFtb3VudFRvTGVhc2UJAGUCCQBlAggJAO8HAQUQbmV1dHJpbm9Db250cmFjdAlhdmFpbGFibGUFDXVubGVhc2VBbW91bnQJAR9nZXRSZXNlcnZlZEFtb3VudEZvclNwb25zb3JzaGlwAAQKb2xkTGVhc2VkMAkBDmdldE51bWJlckJ5S2V5AQkBEWdldExlYXNlQW1vdW50S2V5AQAABApvbGRMZWFzZWQxCQEOZ2V0TnVtYmVyQnlLZXkBCQERZ2V0TGVhc2VBbW91bnRLZXkBAAEECm5ld0xlYXNlZDAJAGQCBQ1hbW91bnRUb0xlYXNlBQpvbGRMZWFzZWQwBApuZXdMZWFzZWQxCQBkAgUNYW1vdW50VG9MZWFzZQUKb2xkTGVhc2VkMQMDCQBmAgUKbmV3TGVhc2VkMAAABgkAZgIFCm5ld0xlYXNlZDEAAAQGZGVsdGEwCQEDYWJzAQkAZQIFCm5ld0xlYXNlZDAFCm9sZExlYXNlZDEEBmRlbHRhMQkBA2FicwEJAGUCBQpuZXdMZWFzZWQxBQpvbGRMZWFzZWQwAwkAZwIFBmRlbHRhMQUGZGVsdGEwCQCUCgIAAAUKbmV3TGVhc2VkMAkAlAoCAAEFCm5ld0xlYXNlZDEJAJQKAgD///////////8BAAABCHRoaXNPbmx5AQFpAwkBAiE9AggFAWkGY2FsbGVyBQR0aGlzCQACAQItUGVybWlzc2lvbiBkZW5pZWQ6IHRoaXMgY29udHJhY3Qgb25seSBhbGxvd2VkBgEWcHJlcGFyZVVubGVhc2VBbmRMZWFzZQENdW5sZWFzZUFtb3VudAQJbm9kZVR1cGxlCQEKc2VsZWN0Tm9kZQEFDXVubGVhc2VBbW91bnQECW5vZGVJbmRleAgFCW5vZGVUdXBsZQJfMQQObmV3TGVhc2VBbW91bnQIBQlub2RlVHVwbGUCXzIDCQBmAgUObmV3TGVhc2VBbW91bnQAAAQKbGVhc2VJZEtleQkBDWdldExlYXNlSWRLZXkBBQlub2RlSW5kZXgECG9sZExlYXNlCQCcCAIFBHRoaXMFCmxlYXNlSWRLZXkEDnVubGVhc2VPckVtcHR5AwkBCWlzRGVmaW5lZAEFCG9sZExlYXNlCQDMCAIJAQtMZWFzZUNhbmNlbAEJAQV2YWx1ZQEFCG9sZExlYXNlBQNuaWwFA25pbAQObGVhc2VBbW91bnRLZXkJARFnZXRMZWFzZUFtb3VudEtleQEFCW5vZGVJbmRleAQFbGVhc2UJAMQIAgkBHGdldFN0YWtpbmdOb2RlQWRkcmVzc0J5SW5kZXgBBQlub2RlSW5kZXgFDm5ld0xlYXNlQW1vdW50CQDOCAIFDnVubGVhc2VPckVtcHR5CQDMCAIFBWxlYXNlCQDMCAIJAQtCaW5hcnlFbnRyeQIFCmxlYXNlSWRLZXkJAQVsY2FsYwEFBWxlYXNlCQDMCAIJAQxJbnRlZ2VyRW50cnkCCQERZ2V0TGVhc2VBbW91bnRLZXkBBQlub2RlSW5kZXgFDm5ld0xlYXNlQW1vdW50BQNuaWwFA25pbAEMcmVhZE5vZGVJbmZvAQdub2RlSWR4BAtub2RlQWRkcmVzcwkBHGdldFN0YWtpbmdOb2RlQWRkcmVzc0J5SW5kZXgBBQdub2RlSWR4BAxsZWFzZWRBbXRLRVkJARFnZXRMZWFzZUFtb3VudEtleQEFB25vZGVJZHgECWxlYXNlZEFtdAkBDmdldE51bWJlckJ5S2V5AQUMbGVhc2VkQW10S0VZBApsZWFzZUlkS0VZCQENZ2V0TGVhc2VJZEtleQEFB25vZGVJZHgEB2xlYXNlSWQJAQV2YWx1ZQEJAJwIAgUEdGhpcwUKbGVhc2VJZEtFWQkAlwoFBQtub2RlQWRkcmVzcwUMbGVhc2VkQW10S0VZBQlsZWFzZWRBbXQFCmxlYXNlSWRLRVkFB2xlYXNlSWQBCmNvbW1vblN3YXAFCHN3YXBUeXBlCXBtdEFtb3VudA51c2VyQWRkcmVzc1N0cgZ0eElkNTgbc3dhcFBhcmFtc0J5VXNlclNZU1JFQURPTkxZBA5zd2FwTGltaXRTcGVudAgFG3N3YXBQYXJhbXNCeVVzZXJTWVNSRUFET05MWQJfMgQOYmxja3MyTG10UmVzZXQIBRtzd2FwUGFyYW1zQnlVc2VyU1lTUkVBRE9OTFkCXzMEEXdhdmVzU3dhcExpbWl0TWF4CAUbc3dhcFBhcmFtc0J5VXNlclNZU1JFQURPTkxZAl82BBB1c2RuU3dhcExpbWl0TWF4CAUbc3dhcFBhcmFtc0J5VXNlclNZU1JFQURPTkxZAl83BA1taW5Td2FwQW1vdW50CQERbWluU3dhcEFtb3VudFJFQUQBBQhzd2FwVHlwZQQLdG90YWxMb2NrZWQJAQ90b3RhbExvY2tlZFJFQUQBBQhzd2FwVHlwZQQRdG90YWxMb2NrZWRCeVVzZXIJARV0b3RhbExvY2tlZEJ5VXNlclJFQUQCBQhzd2FwVHlwZQUOdXNlckFkZHJlc3NTdHIEC25vZGVBZGRyZXNzCQEVZ2V0U3Rha2luZ05vZGVCeUluZGV4AQAABAxwcmljZUJ5SW5kZXgJAQ9nZXRQcmljZUhpc3RvcnkBCQEVZ2V0SGVpZ2h0UHJpY2VCeUluZGV4AQUKcHJpY2VJbmRleAQMaXNTd2FwQnlOb2RlCQAAAgULbm9kZUFkZHJlc3MFDnVzZXJBZGRyZXNzU3RyBBZiYWxhbmNlTG9ja01heEludGVydmFsAwUMaXNTd2FwQnlOb2RlCQEbbm9kZUJhbGFuY2VMb2NrSW50ZXJ2YWxSRUFEAAkBF2JhbGFuY2VMb2NrSW50ZXJ2YWxSRUFEAQUIc3dhcFR5cGUEEHNlbGZVbmxvY2tIZWlnaHQJAGQCBQZoZWlnaHQFFmJhbGFuY2VMb2NrTWF4SW50ZXJ2YWwEDnN3YXBVc2RuVm9sdW1lAwkAAAIFCHN3YXBUeXBlAghuZXV0cmlubwUJcG10QW1vdW50CQEWY29udmVydFdhdmVzVG9OZXV0cmlubwIFCXBtdEFtb3VudAUMcHJpY2VCeUluZGV4BAxzd2FwTGltaXRNYXgDCQAAAgUIc3dhcFR5cGUCCG5ldXRyaW5vBRB1c2RuU3dhcExpbWl0TWF4CQEWY29udmVydFdhdmVzVG9OZXV0cmlubwIFEXdhdmVzU3dhcExpbWl0TWF4BQxwcmljZUJ5SW5kZXgDCQBmAgUNbWluU3dhcEFtb3VudAUJcG10QW1vdW50CQERbWluU3dhcEFtb3VudEZBSUwCBQhzd2FwVHlwZQUNbWluU3dhcEFtb3VudAMDCQEBIQEFDGlzU3dhcEJ5Tm9kZQkAZgIFDnN3YXBMaW1pdFNwZW50AAAHCQACAQkArAICAjpZb3UgaGF2ZSBleGNlZWRlZCBzd2FwIGxpbWl0ISBOZXh0IGFsbG93ZWQgc3dhcCBoZWlnaHQgaXMgCQCkAwEJAGQCBQZoZWlnaHQFDmJsY2tzMkxtdFJlc2V0AwMJAQEhAQUMaXNTd2FwQnlOb2RlCQBmAgUOc3dhcFVzZG5Wb2x1bWUFDHN3YXBMaW1pdE1heAcJAAIBCQCsAgIJAKwCAgkArAICAi5Zb3UgaGF2ZSBleGNlZWRlZCB5b3VyIHN3YXAgbGltaXQhIFJlcXVlc3RlZDogCQCkAwEFDnN3YXBVc2RuVm9sdW1lAg0sIGF2YWlsYWJsZTogCQCkAwEFDHN3YXBMaW1pdE1heAMFCWlzQmxvY2tlZAkBFWVtZXJnZW5jeVNodXRkb3duRkFJTAAECWxlYXNlUGFydAMJAAACBQhzd2FwVHlwZQIFd2F2ZXMJARZwcmVwYXJlVW5sZWFzZUFuZExlYXNlAQAABQNuaWwJAJQKAgkAzggCCQDMCAIJAQxJbnRlZ2VyRW50cnkCCQEYa2V5U3dhcFVzZXJTcGVudEluUGVyaW9kAQUOdXNlckFkZHJlc3NTdHIFDnN3YXBVc2RuVm9sdW1lCQDMCAIJAQxJbnRlZ2VyRW50cnkCCQEVa2V5VXNlckxhc3RTd2FwSGVpZ2h0AQUOdXNlckFkZHJlc3NTdHIFBmhlaWdodAkAzAgCCQEMSW50ZWdlckVudHJ5AgkBFHRvdGFsTG9ja2VkQnlVc2VyS0VZAgUIc3dhcFR5cGUFDnVzZXJBZGRyZXNzU3RyCQBkAgURdG90YWxMb2NrZWRCeVVzZXIFCXBtdEFtb3VudAkAzAgCCQEMSW50ZWdlckVudHJ5AgkBGGdldEJhbGFuY2VVbmxvY2tCbG9ja0tleQEFDnVzZXJBZGRyZXNzU3RyBRBzZWxmVW5sb2NrSGVpZ2h0CQDMCAIJAQxJbnRlZ2VyRW50cnkCCQEOdG90YWxMb2NrZWRLRVkBBQhzd2FwVHlwZQkAZAIFC3RvdGFsTG9ja2VkBQlwbXRBbW91bnQJAMwIAgkBC1N0cmluZ0VudHJ5AgkBB3N3YXBLRVkCBQ51c2VyQWRkcmVzc1N0cgUGdHhJZDU4CQEPcGVuZGluZ1N3YXBEQVRBAwUIc3dhcFR5cGUFCXBtdEFtb3VudAUQc2VsZlVubG9ja0hlaWdodAUDbmlsBQlsZWFzZVBhcnQFBHVuaXQAD25NZXRyaWNJZHhQcmljZQAAABtuTWV0cmljSWR4VXNkbkxvY2tlZEJhbGFuY2UAAQAcbk1ldHJpY0lkeFdhdmVzTG9ja2VkQmFsYW5jZQACABFuTWV0cmljSWR4UmVzZXJ2ZQADABduTWV0cmljSWR4UmVzZXJ2ZUluVXNkbgAEABRuTWV0cmljSWR4VXNkblN1cHBseQAFABFuTWV0cmljSWR4U3VycGx1cwAGABhuTWV0cmljSWR4U3VycGx1c1BlcmNlbnQABwAMbk1ldHJpY0lkeEJSAAgAFG5NZXRyaWNJZHhOc2J0U3VwcGx5AAkAF25NZXRyaWNJZHhNYXhOc2J0U3VwcGx5AAoAFG5NZXRyaWNJZHhTdXJmU3VwcGx5AAsADGJGdW5jSWR4U3VyZgAAAA1iRnVuY0lkeFdhdmVzAAEADGJGdW5jSWR4VXNkbgACABRiRnVuY0lkeFJlc2VydmVTdGFydAADABNiRnVuY0lkeFN1cHBseVN0YXJ0AAQAD2JGdW5jSWR4QlJTdGFydAAFABJiRnVuY0lkeFJlc2VydmVFbmQABgARYkZ1bmNJZHhTdXBwbHlFbmQABwANYkZ1bmNJZHhCUkVuZAAIAAxiRnVuY0lkeFJlc3QACQASYkZ1bmNJZHhXYXZlc1ByaWNlAAoBD2NhbGNXaXRoZHJhd1cyVQIHd2F2ZXNJbgVwcmljZQQLb3V0QW10R3Jvc3MJARZjb252ZXJ0V2F2ZXNUb05ldXRyaW5vAgUHd2F2ZXNJbgUFcHJpY2UJAJsKCQULb3V0QW10R3Jvc3MFD25ldXRyaW5vQXNzZXRJZAAABQR1bml0AAAFB3dhdmVzSW4AAAAAAAABD2NhbGNXaXRoZHJhd1UyVwUGdXNkbkluBXByaWNlAmJyDnJlc2VydmVzSW5Vc2RuCnVzZG5TdXBwbHkEC2JyUHJvdGVjdGVkCQELdmFsdWVPckVsc2UCCQCaCAIFBHRoaXMJAQ5iclByb3RlY3RlZEtFWQAFC0JSUFJPVEVDVEVEBBltYXhBbGxvd2VkVXNkbkJlZm9yZU1pbkJyAwkAZwIFC2JyUHJvdGVjdGVkBQJicgAACQBrAwkAZQIFDnJlc2VydmVzSW5Vc2RuCQBrAwULYnJQcm90ZWN0ZWQFCnVzZG5TdXBwbHkFBVBBVUxJBQVQQVVMSQkAZQIFBVBBVUxJBQticlByb3RlY3RlZAQWYWxsb3dlZFVzZG5CZWZvcmVNaW5CcgMJAGYCBQZ1c2RuSW4FGW1heEFsbG93ZWRVc2RuQmVmb3JlTWluQnIFGW1heEFsbG93ZWRVc2RuQmVmb3JlTWluQnIFBnVzZG5JbgQVYWxsb3dlZFVzZG5BZnRlck1pbkJyAwkAZgIFBnVzZG5JbgUZbWF4QWxsb3dlZFVzZG5CZWZvcmVNaW5CcgkAawMJAGUCBQZ1c2RuSW4FGW1heEFsbG93ZWRVc2RuQmVmb3JlTWluQnIFAmJyBQVQQVVMSQAABAthbGxvd2VkVXNkbgkAZAIFFmFsbG93ZWRVc2RuQmVmb3JlTWluQnIFFWFsbG93ZWRVc2RuQWZ0ZXJNaW5CcgQJdXNkbjJTVVJGCQBlAgUGdXNkbkluBQthbGxvd2VkVXNkbgQLb3V0QW10R3Jvc3MJARZjb252ZXJ0TmV1dHJpbm9Ub1dhdmVzAgULYWxsb3dlZFVzZG4FBXByaWNlCQCbCgkFC291dEFtdEdyb3NzBQR1bml0BQl1c2RuMlNVUkYFD25ldXRyaW5vQXNzZXRJZAULb3V0QW10R3Jvc3MFC2FsbG93ZWRVc2RuBRltYXhBbGxvd2VkVXNkbkJlZm9yZU1pbkJyBRZhbGxvd2VkVXNkbkJlZm9yZU1pbkJyBRVhbGxvd2VkVXNkbkFmdGVyTWluQnIBDGNhbGNXaXRoZHJhdwQIc3dhcFR5cGUIaW5BbW91bnQFcHJpY2UPbmV1dHJpbm9NZXRyaWNzBApvdXRGZWVQYXJ0CQELdmFsdWVPckVsc2UCCQCaCAIFBHRoaXMJAQ1vdXRGZWVQYXJ0S0VZAQUIc3dhcFR5cGUFDkRFRkFVTFRTV0FQRkVFAwMJAGYCAAAFCm91dEZlZVBhcnQGCQBnAgUKb3V0RmVlUGFydAUFUEFVTEkJAAIBCQCsAgIJAKwCAgkArAICAh5pbnZhbGlkIG91dEZlZVBhcnQgY29uZmlnIGZvciAFCHN3YXBUeXBlAhIgc3dhcDogb3V0RmVlUGFydD0JAKQDAQUKb3V0RmVlUGFydAQLYnJQcm90ZWN0ZWQJAQt2YWx1ZU9yRWxzZQIJAJoIAgUEdGhpcwkBDmJyUHJvdGVjdGVkS0VZAAULQlJQUk9URUNURUQEAkJSCQEFYXNJbnQBCQCRAwIFD25ldXRyaW5vTWV0cmljcwUMbk1ldHJpY0lkeEJSBA5yZXNlcnZlc0luVXNkbgkBBWFzSW50AQkAkQMCBQ9uZXV0cmlub01ldHJpY3MFF25NZXRyaWNJZHhSZXNlcnZlSW5Vc2RuBAp1c2RuU3VwcGx5CQEFYXNJbnQBCQCRAwIFD25ldXRyaW5vTWV0cmljcwUUbk1ldHJpY0lkeFVzZG5TdXBwbHkEDG91dERhdGFUdXBsZQMJAAACBQhzd2FwVHlwZQIFd2F2ZXMJAQ9jYWxjV2l0aGRyYXdXMlUCBQhpbkFtb3VudAUFcHJpY2UDCQAAAgUIc3dhcFR5cGUCCG5ldXRyaW5vCQEPY2FsY1dpdGhkcmF3VTJXBQUIaW5BbW91bnQFBXByaWNlBQJCUgUOcmVzZXJ2ZXNJblVzZG4FCnVzZG5TdXBwbHkJAAIBCQCsAgICFlVuc3VwcG9ydGVkIHN3YXAgdHlwZSAFCHN3YXBUeXBlBAtvdXRBbXRHcm9zcwgFDG91dERhdGFUdXBsZQJfMQQKb3V0QXNzZXRJZAgFDG91dERhdGFUdXBsZQJfMgQPaW5BbXRUb1N1cmZQYXJ0CAUMb3V0RGF0YVR1cGxlAl8zBAlpbkFzc2V0SWQIBQxvdXREYXRhVHVwbGUCXzQECnVubGVhc2VBbXQIBQxvdXREYXRhVHVwbGUCXzUEDHBheW91dHNBcnJheQkBCWFwcGx5RmVlcwMFC291dEFtdEdyb3NzBQ9pbkFtdFRvU3VyZlBhcnQFCm91dEZlZVBhcnQECW91dE5ldEFtdAkAkQMCBQxwYXlvdXRzQXJyYXkFDElkeE5ldEFtb3VudAQJb3V0RmVlQW10CQCRAwIFDHBheW91dHNBcnJheQUMSWR4RmVlQW1vdW50BApvdXRTdXJmQW10AwkAZwIAAAUPaW5BbXRUb1N1cmZQYXJ0AAAECnN1cmZSZXN1bHQJAQlhc0FueUxpc3QBCQD8BwQFDG1hdGhDb250cmFjdAIUc3VyZkZ1bmN0aW9uUkVBRE9OTFkJAMwIAgUPaW5BbXRUb1N1cmZQYXJ0CQDMCAIFCWluQXNzZXRJZAUDbmlsBQNuaWwJAQVhc0ludAEJAJEDAgUKc3VyZlJlc3VsdAUMYkZ1bmNJZHhTdXJmCQCZCgcFCW91dE5ldEFtdAUKb3V0QXNzZXRJZAUKb3V0U3VyZkFtdAUPaW5BbXRUb1N1cmZQYXJ0BQp1bmxlYXNlQW10BQlvdXRGZWVBbXQFC291dEFtdEdyb3NzAQ5jb21tb25XaXRoZHJhdwUHYWNjb3VudAVpbmRleAhzd2FwVHhJZAx3aXRoZHJhd1R4SWQPbmV1dHJpbm9NZXRyaWNzBAt1c2VyQWRkcmVzcwkBEUBleHRyTmF0aXZlKDEwNjIpAQUHYWNjb3VudAQJZGF0YUFycmF5CQESc3dhcERhdGFGYWlsT3JSRUFEAgUHYWNjb3VudAUIc3dhcFR4SWQEEHNlbGZVbmxvY2tIZWlnaHQJAQ1wYXJzZUludFZhbHVlAQkAkQMCBQlkYXRhQXJyYXkFFHNJZHhTZWxmVW5sb2NrSGVpZ2h0BAhzd2FwVHlwZQkAkQMCBQlkYXRhQXJyYXkFDHNJZHhTd2FwVHlwZQQIaW5BbW91bnQJAQ1wYXJzZUludFZhbHVlAQkAkQMCBQlkYXRhQXJyYXkFDHNJZHhJbkFtb3VudAQKc3dhcFN0YXR1cwkAkQMCBQlkYXRhQXJyYXkFCnNJZHhTdGF0dXMEC3N0YXJ0SGVpZ2h0CQENcGFyc2VJbnRWYWx1ZQEJAJEDAgUJZGF0YUFycmF5BQ9zSWR4U3RhcnRIZWlnaHQECm91dEZlZVBhcnQJAQt2YWx1ZU9yRWxzZQIJAJoIAgUEdGhpcwkBDW91dEZlZVBhcnRLRVkBBQhzd2FwVHlwZQUOREVGQVVMVFNXQVBGRUUEC3RvdGFsTG9ja2VkCQEPdG90YWxMb2NrZWRSRUFEAQUIc3dhcFR5cGUEEXRvdGFsTG9ja2VkQnlVc2VyCQEVdG90YWxMb2NrZWRCeVVzZXJSRUFEAgUIc3dhcFR5cGUFB2FjY291bnQEDHVubG9ja0hlaWdodAUQc2VsZlVubG9ja0hlaWdodAQLaW5kZXhIZWlnaHQJARVnZXRIZWlnaHRQcmljZUJ5SW5kZXgBBQVpbmRleAQPcHJldkluZGV4SGVpZ2h0CQEVZ2V0SGVpZ2h0UHJpY2VCeUluZGV4AQkAZQIFBWluZGV4AAEEDHByaWNlQnlJbmRleAkBD2dldFByaWNlSGlzdG9yeQEFC2luZGV4SGVpZ2h0AwUJaXNCbG9ja2VkCQEVZW1lcmdlbmN5U2h1dGRvd25GQUlMAAMJAQIhPQIFCnN3YXBTdGF0dXMCB1BFTkRJTkcJAAIBAh9zd2FwIGhhcyBiZWVuIGFscmVhZHkgcHJvY2Vzc2VkAwkAZgIFDHVubG9ja0hlaWdodAUGaGVpZ2h0CQACAQkArAICCQCsAgICEXBsZWFzZSB3YWl0IGZvcjogCQCkAwEFDHVubG9ja0hlaWdodAIfIGJsb2NrIGhlaWdodCB0byB3aXRoZHJhdyBmdW5kcwMDAwkAZgIFBWluZGV4BQpwcmljZUluZGV4BgkAZgIFDHVubG9ja0hlaWdodAULaW5kZXhIZWlnaHQGAwkBAiE9AgUPcHJldkluZGV4SGVpZ2h0AAAJAGcCBQ9wcmV2SW5kZXhIZWlnaHQFDHVubG9ja0hlaWdodAcJAQ5wcmljZUluZGV4RkFJTAUFBWluZGV4BQpwcmljZUluZGV4BQtpbmRleEhlaWdodAUMdW5sb2NrSGVpZ2h0BQ9wcmV2SW5kZXhIZWlnaHQEDXdpdGhkcmF3VHVwbGUJAQxjYWxjV2l0aGRyYXcEBQhzd2FwVHlwZQUIaW5BbW91bnQFDHByaWNlQnlJbmRleAUPbmV1dHJpbm9NZXRyaWNzBAxvdXROZXRBbW91bnQIBQ13aXRoZHJhd1R1cGxlAl8xBApvdXRBc3NldElkCAUNd2l0aGRyYXdUdXBsZQJfMgQKb3V0U3VyZkFtdAgFDXdpdGhkcmF3VHVwbGUCXzMED2luQW10VG9TdXJmUGFydAgFDXdpdGhkcmF3VHVwbGUCXzQECnVubGVhc2VBbXQIBQ13aXRoZHJhd1R1cGxlAl81BAxvdXRGZWVBbW91bnQIBQ13aXRoZHJhd1R1cGxlAl82BAtvdXRBbXRHcm9zcwgFDXdpdGhkcmF3VHVwbGUCXzcDCQBnAgAABQtvdXRBbXRHcm9zcwkAAgECE2JhbGFuY2UgZXF1YWxzIHplcm8EAkJSCQEFYXNJbnQBCQCRAwIFD25ldXRyaW5vTWV0cmljcwUMbk1ldHJpY0lkeEJSBAVzdGF0ZQkAzAgCCQEMSW50ZWdlckVudHJ5AgkBFHRvdGFsTG9ja2VkQnlVc2VyS0VZAgUIc3dhcFR5cGUFB2FjY291bnQJAGUCBRF0b3RhbExvY2tlZEJ5VXNlcgUIaW5BbW91bnQJAMwIAgkBDEludGVnZXJFbnRyeQIJAQ50b3RhbExvY2tlZEtFWQEFCHN3YXBUeXBlCQBlAgULdG90YWxMb2NrZWQFCGluQW1vdW50CQDMCAIJAQ5TY3JpcHRUcmFuc2ZlcgMFC3VzZXJBZGRyZXNzBQxvdXROZXRBbW91bnQFCm91dEFzc2V0SWQJAMwIAgkBC1N0cmluZ0VudHJ5AgkBB3N3YXBLRVkCBQdhY2NvdW50BQhzd2FwVHhJZAkBDmZpbmlzaFN3YXBEQVRBCQUJZGF0YUFycmF5BQxwcmljZUJ5SW5kZXgFDG91dE5ldEFtb3VudAUMb3V0RmVlQW1vdW50BQx1bmxvY2tIZWlnaHQFBWluZGV4BQx3aXRoZHJhd1R4SWQFCm91dFN1cmZBbXQFAkJSBQNuaWwEDXN1cmZDb25kaXRpb24DCQBmAgUKb3V0U3VyZkFtdAAABAtpc3N1ZVJlc3VsdAkA/AcEBQ9hdWN0aW9uQ29udHJhY3QCCWlzc3VlU3VyZgkAzAgCBQpvdXRTdXJmQW10CQDMCAIFB2FjY291bnQFA25pbAUDbmlsAwkAAAIFC2lzc3VlUmVzdWx0BQtpc3N1ZVJlc3VsdAAACQACAQIkU3RyaWN0IHZhbHVlIGlzIG5vdCBlcXVhbCB0byBpdHNlbGYuAAADCQAAAgUNc3VyZkNvbmRpdGlvbgUNc3VyZkNvbmRpdGlvbgkAlQoDBQVzdGF0ZQkBD0F0dGFjaGVkUGF5bWVudAIFCm91dEFzc2V0SWQFDG91dEZlZUFtb3VudAUKdW5sZWFzZUFtdAkAAgECJFN0cmljdCB2YWx1ZSBpcyBub3QgZXF1YWwgdG8gaXRzZWxmLg8BaQELY29uc3RydWN0b3IMEm5ldXRyaW5vQXNzZXRJZFBybQ5ib25kQXNzZXRJZFBybRJhdWN0aW9uQ29udHJhY3RQcm0WbGlxdWlkYXRpb25Db250cmFjdFBybQ5ycGRDb250cmFjdFBybRtub2RlT3JhY2xlUHJvdmlkZXJQdWJLZXlQcm0bYmFsYW5jZVdhdmVzTG9ja0ludGVydmFsUHJtHmJhbGFuY2VOZXV0cmlub0xvY2tJbnRlcnZhbFBybRVtaW5XYXZlc1N3YXBBbW91bnRQcm0YbWluTmV1dHJpbm9Td2FwQW1vdW50UHJtFW5ldXRyaW5vT3V0RmVlUGFydFBybRJ3YXZlc091dEZlZVBhcnRQcm0EC2NoZWNrQ2FsbGVyCQEIdGhpc09ubHkBBQFpAwkAAAIFC2NoZWNrQ2FsbGVyBQtjaGVja0NhbGxlcgMJAQIhPQIJAJADAQgFAWkIcGF5bWVudHMAAAkAAgECE25vIHBheW1lbnRzIGFsbG93ZWQJAMwIAgkBC1N0cmluZ0VudHJ5AgUSTmV1dHJpbm9Bc3NldElkS2V5BRJuZXV0cmlub0Fzc2V0SWRQcm0JAMwIAgkBC1N0cmluZ0VudHJ5AgUOQm9uZEFzc2V0SWRLZXkFDmJvbmRBc3NldElkUHJtCQDMCAIJAQtTdHJpbmdFbnRyeQIFEkF1Y3Rpb25Db250cmFjdEtleQUSYXVjdGlvbkNvbnRyYWN0UHJtCQDMCAIJAQtTdHJpbmdFbnRyeQIFFkxpcXVpZGF0aW9uQ29udHJhY3RLZXkFFmxpcXVpZGF0aW9uQ29udHJhY3RQcm0JAMwIAgkBC1N0cmluZ0VudHJ5AgUOUlBEQ29udHJhY3RLZXkFDnJwZENvbnRyYWN0UHJtCQDMCAIJAQtTdHJpbmdFbnRyeQIFG05vZGVPcmFjbGVQcm92aWRlclB1YktleUtleQUbbm9kZU9yYWNsZVByb3ZpZGVyUHViS2V5UHJtCQDMCAIJAQxJbnRlZ2VyRW50cnkCBRtCYWxhbmNlV2F2ZXNMb2NrSW50ZXJ2YWxLZXkFG2JhbGFuY2VXYXZlc0xvY2tJbnRlcnZhbFBybQkAzAgCCQEMSW50ZWdlckVudHJ5AgUeQmFsYW5jZU5ldXRyaW5vTG9ja0ludGVydmFsS2V5BR5iYWxhbmNlTmV1dHJpbm9Mb2NrSW50ZXJ2YWxQcm0JAMwIAgkBDEludGVnZXJFbnRyeQIFFU1pbldhdmVzU3dhcEFtb3VudEtleQUVbWluV2F2ZXNTd2FwQW1vdW50UHJtCQDMCAIJAQxJbnRlZ2VyRW50cnkCBRhNaW5OZXV0cmlub1N3YXBBbW91bnRLZXkFGG1pbk5ldXRyaW5vU3dhcEFtb3VudFBybQkAzAgCCQEMSW50ZWdlckVudHJ5AgUVTmV1dHJpbm9PdXRGZWVQYXJ0S2V5BRVuZXV0cmlub091dEZlZVBhcnRQcm0JAMwIAgkBDEludGVnZXJFbnRyeQIFEldhdmVzT3V0RmVlUGFydEtleQUSd2F2ZXNPdXRGZWVQYXJ0UHJtBQNuaWwJAAIBAiRTdHJpY3QgdmFsdWUgaXMgbm90IGVxdWFsIHRvIGl0c2VsZi4BaQENY29uc3RydWN0b3JWMgMMbWF0aENvbnRyYWN0E25zYnRTdGFraW5nQ29udHJhY3QUc3dhcHNUaW1lZnJhbWVCbG9ja3MEC2NoZWNrQ2FsbGVyCQEIdGhpc09ubHkBBQFpAwkAAAIFC2NoZWNrQ2FsbGVyBQtjaGVja0NhbGxlcgMJAQIhPQIJAJADAQgFAWkIcGF5bWVudHMAAAkAAgECE25vIHBheW1lbnRzIGFsbG93ZWQJAMwIAgkBC1N0cmluZ0VudHJ5AgUPTWF0aENvbnRyYWN0S2V5BQxtYXRoQ29udHJhY3QJAMwIAgkBC1N0cmluZ0VudHJ5AgUWTnNidFN0YWtpbmdDb250cmFjdEtleQUTbnNidFN0YWtpbmdDb250cmFjdAkAzAgCCQEMSW50ZWdlckVudHJ5AgkBEXN3YXBzVGltZWZyYW1lS0VZAAUUc3dhcHNUaW1lZnJhbWVCbG9ja3MFA25pbAkAAgECJFN0cmljdCB2YWx1ZSBpcyBub3QgZXF1YWwgdG8gaXRzZWxmLgFpARNzd2FwV2F2ZXNUb05ldXRyaW5vAAMJAQIhPQIJAJADAQgFAWkIcGF5bWVudHMAAQkAAgECLHN3YXBXYXZlc1RvTmV1dHJpbm8gcmVxdWlyZSBvbmx5IG9uZSBwYXltZW50BANwbXQJAQV2YWx1ZQEJAJEDAggFAWkIcGF5bWVudHMAAAMJAQlpc0RlZmluZWQBCAUDcG10B2Fzc2V0SWQJAAIBAilPbmx5IFdhdmVzIHRva2VuIGlzIGFsbG93ZWQgZm9yIHN3YXBwaW5nLgQLdXNlckFkZHJlc3MJAKUIAQgFAWkGY2FsbGVyBAZ0eElkNTgJANgEAQgFAWkNdHJhbnNhY3Rpb25JZAQQc3dhcFBhcmFtc1NUUlVDVAkBEmFzU3dhcFBhcmFtc1NUUlVDVAEJAPwHBAUEdGhpcwIbc3dhcFBhcmFtc0J5VXNlclNZU1JFQURPTkxZCQDMCAIFC3VzZXJBZGRyZXNzCQDMCAIAAAUDbmlsBQNuaWwEEGNvbW1vblN3YXBSZXN1bHQJAQpjb21tb25Td2FwBQIFd2F2ZXMIBQNwbXQGYW1vdW50BQt1c2VyQWRkcmVzcwUGdHhJZDU4BRBzd2FwUGFyYW1zU1RSVUNUBRBjb21tb25Td2FwUmVzdWx0AWkBE3N3YXBOZXV0cmlub1RvV2F2ZXMAAwkBAiE9AgkAkAMBCAUBaQhwYXltZW50cwABCQACAQIsc3dhcE5ldXRyaW5vVG9XYXZlcyByZXF1aXJlIG9ubHkgb25lIHBheW1lbnQEA3BtdAkBBXZhbHVlAQkAkQMCCAUBaQhwYXltZW50cwAAAwkBAiE9AggFA3BtdAdhc3NldElkBQ9uZXV0cmlub0Fzc2V0SWQJAAIBAjpPbmx5IGFwcHJvcHJpYXRlIE5ldXRyaW5vIHRva2VucyBhcmUgYWxsb3dlZCBmb3Igc3dhcHBpbmcuBAt1c2VyQWRkcmVzcwkApQgBCAUBaQZjYWxsZXIEBnR4SWQ1OAkA2AQBCAUBaQ10cmFuc2FjdGlvbklkBBBzd2FwUGFyYW1zU1RSVUNUCQESYXNTd2FwUGFyYW1zU1RSVUNUAQkA/AcEBQR0aGlzAhtzd2FwUGFyYW1zQnlVc2VyU1lTUkVBRE9OTFkJAMwIAgULdXNlckFkZHJlc3MJAMwIAgAABQNuaWwFA25pbAQQY29tbW9uU3dhcFJlc3VsdAkBCmNvbW1vblN3YXAFAghuZXV0cmlubwgFA3BtdAZhbW91bnQFC3VzZXJBZGRyZXNzBQZ0eElkNTgFEHN3YXBQYXJhbXNTVFJVQ1QFEGNvbW1vblN3YXBSZXN1bHQBaQEId2l0aGRyYXcDB2FjY291bnQFaW5kZXgIc3dhcFR4SWQEBHR4SWQJANgEAQgFAWkNdHJhbnNhY3Rpb25JZAMJAQIhPQIJAJADAQgFAWkIcGF5bWVudHMAAAkAAgECE25vIHBheW1lbnRzIGFsbG93ZWQED25ldXRyaW5vTWV0cmljcwkBCWFzQW55TGlzdAEJAPwHBAUMbWF0aENvbnRyYWN0AhpjYWxjTmV1dGlub01ldHJpY3NSRUFET05MWQUDbmlsBQNuaWwEAkJSCQEFYXNJbnQBCQCRAwIFD25ldXRyaW5vTWV0cmljcwUMbk1ldHJpY0lkeEJSBAtjb21tb25UdXBsZQkBDmNvbW1vbldpdGhkcmF3BQUHYWNjb3VudAUFaW5kZXgFCHN3YXBUeElkBQR0eElkBQ9uZXV0cmlub01ldHJpY3MEBXN0YXRlCAULY29tbW9uVHVwbGUCXzEEA2ZlZQgFC2NvbW1vblR1cGxlAl8yBAp1bmxlYXNlQW10CAULY29tbW9uVHVwbGUCXzMEEXVubGVhc2VJbnZPckVtcHR5CQD8BwQFBHRoaXMCF2ludGVybmFsVW5sZWFzZUFuZExlYXNlCQDMCAIFCnVubGVhc2VBbXQFA25pbAUDbmlsAwkAAAIFEXVubGVhc2VJbnZPckVtcHR5BRF1bmxlYXNlSW52T3JFbXB0eQQJZ25zYnREYXRhCQEJYXNBbnlMaXN0AQkA/AcEBRdnbnNidENvbnRyb2xsZXJDb250cmFjdAIUZ25zYnRJbmZvU1lTUkVBRE9OTFkJAMwIAgIACQDMCAIAAAkAzAgCAAAFA25pbAUDbmlsBA1nbnNidEFtdFRvdGFsCQEFYXNJbnQBCQCRAwIFCWduc2J0RGF0YQABBBVnbnNidEFtdEZyb21TdXJmVG90YWwJAQVhc0ludAEJAJEDAgkBCWFzQW55TGlzdAEJAJEDAgUJZ25zYnREYXRhAAMAAwQLc3VyZkZlZUFtdDEDCQECIT0CBQ1nbnNidEFtdFRvdGFsAAAJAGsDCAUDZmVlBmFtb3VudAUVZ25zYnRBbXRGcm9tU3VyZlRvdGFsBQ1nbnNidEFtdFRvdGFsAAAEC3N1cmZGZWVBbXQyAwkBAiE9AgUNZ25zYnRBbXRUb3RhbAAACQBrAwgFA2ZlZQZhbW91bnQJAGUCBQVQQVVMSQUCQlIFBVBBVUxJAAAECnN1cmZGZWVBbXQJAJYDAQkAzAgCBQtzdXJmRmVlQW10MQkAzAgCBQtzdXJmRmVlQW10MgUDbmlsBApuc2J0RmVlQW10CQBlAggFA2ZlZQZhbW91bnQFCnN1cmZGZWVBbXQEC3N1cmZEZXBvc2l0AwkAZgIFCnN1cmZGZWVBbXQAAAQHc3VyZkludgkA/AcEBRNzdXJmU3Rha2luZ0NvbnRyYWN0AgdkZXBvc2l0BQNuaWwJAMwIAgkBD0F0dGFjaGVkUGF5bWVudAIIBQNmZWUHYXNzZXRJZAUKc3VyZkZlZUFtdAUDbmlsAwkAAAIFB3N1cmZJbnYFB3N1cmZJbnYFA25pbAkAAgECJFN0cmljdCB2YWx1ZSBpcyBub3QgZXF1YWwgdG8gaXRzZWxmLgUDbmlsAwkAAAIFC3N1cmZEZXBvc2l0BQtzdXJmRGVwb3NpdAQLbnNidERlcG9zaXQDCQBmAgUKbnNidEZlZUFtdAAABAduc2J0SW52CQD8BwQFE25zYnRTdGFraW5nQ29udHJhY3QCB2RlcG9zaXQFA25pbAkAzAgCCQEPQXR0YWNoZWRQYXltZW50AggFA2ZlZQdhc3NldElkBQpuc2J0RmVlQW10BQNuaWwDCQAAAgUHbnNidEludgUHbnNidEludgUDbmlsCQACAQIkU3RyaWN0IHZhbHVlIGlzIG5vdCBlcXVhbCB0byBpdHNlbGYuBQNuaWwDCQAAAgULbnNidERlcG9zaXQFC25zYnREZXBvc2l0BQVzdGF0ZQkAAgECJFN0cmljdCB2YWx1ZSBpcyBub3QgZXF1YWwgdG8gaXRzZWxmLgkAAgECJFN0cmljdCB2YWx1ZSBpcyBub3QgZXF1YWwgdG8gaXRzZWxmLgkAAgECJFN0cmljdCB2YWx1ZSBpcyBub3QgZXF1YWwgdG8gaXRzZWxmLgFpARdpbnRlcm5hbFVubGVhc2VBbmRMZWFzZQENdW5sZWFzZUFtb3VudAMJAQIhPQIIBQFpBmNhbGxlcgUEdGhpcwkAAgECLGludGVybmFsVW5sZWFzZUFuZExlYXNlIGlzIG5vdCBwdWJsaWMgbWV0aG9kCQEWcHJlcGFyZVVubGVhc2VBbmRMZWFzZQEFDXVubGVhc2VBbW91bnQBaQESdHJhbnNmZXJVc2RuVG9Vc2VyAgZhbW91bnQEYWRkcgMJAQIhPQIIBQFpBmNhbGxlcgUPYXVjdGlvbkNvbnRyYWN0CQACAQIjT25seSBhdWN0aW9uIGNvbnRyYWN0IGlzIGF1dGhvcml6ZWQJAMwIAgkBDlNjcmlwdFRyYW5zZmVyAwkBEUBleHRyTmF0aXZlKDEwNjIpAQUEYWRkcgUGYW1vdW50BQ9uZXV0cmlub0Fzc2V0SWQFA25pbAFpAQthY2NlcHRXYXZlcwADCQECIT0CCAUBaQZjYWxsZXIFD2F1Y3Rpb25Db250cmFjdAkAAgECMkN1cnJlbnRseSBvbmx5IGF1Y3Rpb24gY29udHJhY3QgaXMgYWxsb3dlZCB0byBjYWxsCQCUCgIJARZwcmVwYXJlVW5sZWFzZUFuZExlYXNlAQAAAgdzdWNjZXNzAWkBD2FwcHJvdmVMZWFzaW5ncwMGbkxpc3RTCGdyb3VwTnVtBGxBbXQEBW5JZHhzCQDMCAIAAAkAzAgCAAEJAMwIAgACCQDMCAIAAwkAzAgCAAQJAMwIAgAFCQDMCAIABgkAzAgCAAcFA25pbAQHbW5nUHViUwkBC3ZhbHVlT3JFbHNlAgkAoggBAhwlcyVzX19jZmdfX2xlYXNpbmdNYW5hZ2VyUHViAiw3QVVNWDU0dWtZTVl2UG1tYTd5b0ZmNU5qWmhzNEJ1NW56M0V6OUVWOHN1cgQGbW5nUHViCQDZBAEFB21uZ1B1YlMEDm5vZGVSZWdBZGRyU3RyCQELdmFsdWVPckVsc2UCCQCiCAECHyVzJXNfX2NmZ19fbm9kZXNSZWdpc3RyeUFkZHJlc3MCIzNQOXZLcVFLalVkbXBYQWZpV2F1OGtyUkVZQVkxWHI2OXBFBAtub2RlUmVnQWRkcgkBEUBleHRyTmF0aXZlKDEwNjIpAQUObm9kZVJlZ0FkZHJTdHIEEWxHcm91cE5vZGVMaXN0S0VZCQEYZ2V0TGVhc2VHcm91cE5vZGVMaXN0S2V5AQUIZ3JvdXBOdW0ECmxHck5vZGVPcHQJAJ0IAgUEdGhpcwURbEdyb3VwTm9kZUxpc3RLRVkDCQEJaXNEZWZpbmVkAQUKbEdyTm9kZU9wdAkAAgEJAKwCAgkArAICAgZncm91cCAJAKQDAQUIZ3JvdXBOdW0CFCBhbHJlYWR5IGluaXRpYWxpemVkBAVuTGlzdAkAtQkCBQZuTGlzdFMFA1NFUAQIZXhwQ291bnQJAJADAQUFbklkeHMDCQECIT0CCAUBaQ9jYWxsZXJQdWJsaWNLZXkFBm1uZ1B1YgkAAgECHmFwcHJvdmVMZWFzaW5ncyBub3QgYXV0aG9yaXplZAQNJHQwMzQ0MjMzNDQ4NQkBDHJlYWROb2RlSW5mbwEAAAQGbkFkZHIwCAUNJHQwMzQ0MjMzNDQ4NQJfMQQIbEFtdEtFWTAIBQ0kdDAzNDQyMzM0NDg1Al8yBAVsQW10MAgFDSR0MDM0NDIzMzQ0ODUCXzMEB2xJZEtFWTAIBQ0kdDAzNDQyMzM0NDg1Al80BARsSWQwCAUNJHQwMzQ0MjMzNDQ4NQJfNQQFbmV3TDAJAMQIAgUGbkFkZHIwCQBlAgUFbEFtdDAJAGgCBQRsQW10BQhleHBDb3VudAQKdmFsaWRhdGlvbgkA/AcEBQtub2RlUmVnQWRkcgIadmFsaWRhdGVBbmRBcHByb3ZlTGVhc2luZ3MJAMwIAgUGbkxpc3RTBQNuaWwFA25pbAMJAAACBQp2YWxpZGF0aW9uBQp2YWxpZGF0aW9uCgEjZm9yRWFjaE5vZGVWYWxpZGF0ZUFuZEdlbmVyYXRlTGVhc2UCAWEBaQQEbm9kZQkAkQMCBQVuTGlzdAUBaQQCbGEJAMQIAgkBEUBleHRyTmF0aXZlKDEwNjIpAQUEbm9kZQUEbEFtdAkAzggCBQFhCQDMCAIFAmxhCQDMCAIJAQtCaW5hcnlFbnRyeQIJARZnZXRMZWFzZUlkQnlBZGRyZXNzS2V5AQUEbm9kZQkBBWxjYWxjAQUCbGEJAMwIAgkBDEludGVnZXJFbnRyeQIJARpnZXRMZWFzZUFtb3VudEJ5QWRkcmVzc0tleQEFBG5vZGUFBGxBbXQFA25pbAkAzggCCQDMCAIJAQtTdHJpbmdFbnRyeQIFEWxHcm91cE5vZGVMaXN0S0VZBQZuTGlzdFMJAMwIAgkBC0JpbmFyeUVudHJ5AgUHbElkS0VZMAkBBWxjYWxjAQUFbmV3TDAJAMwIAgkBDEludGVnZXJFbnRyeQIFCGxBbXRLRVkwCAUFbmV3TDAGYW1vdW50CQDMCAIJAQtMZWFzZUNhbmNlbAEFBGxJZDAJAMwIAgUFbmV3TDAFA25pbAoAAiRsBQVuSWR4cwoAAiRzCQCQAwEFAiRsCgAFJGFjYzAFA25pbAoBBSRmMF8xAgIkYQIkaQMJAGcCBQIkaQUCJHMFAiRhCQEjZm9yRWFjaE5vZGVWYWxpZGF0ZUFuZEdlbmVyYXRlTGVhc2UCBQIkYQkAkQMCBQIkbAUCJGkKAQUkZjBfMgICJGECJGkDCQBnAgUCJGkFAiRzBQIkYQkAAgECE0xpc3Qgc2l6ZSBleGNlZWRzIDgJAQUkZjBfMgIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIFBSRhY2MwAAAAAQACAAMABAAFAAYABwAICQACAQIkU3RyaWN0IHZhbHVlIGlzIG5vdCBlcXVhbCB0byBpdHNlbGYuAWkBEXJlYmFsYW5jZUxlYXNpbmdzAgZhbW91bnQIZ3JvdXBOdW0EBW5JZHhzCQDMCAIAAAkAzAgCAAEJAMwIAgACCQDMCAIAAwkAzAgCAAQJAMwIAgAFCQDMCAIABgkAzAgCAAcFA25pbAQHbW5nUHViUwkBC3ZhbHVlT3JFbHNlAgkAoggBAhwlcyVzX19jZmdfX2xlYXNpbmdNYW5hZ2VyUHViAiw3QVVNWDU0dWtZTVl2UG1tYTd5b0ZmNU5qWmhzNEJ1NW56M0V6OUVWOHN1cgQGbW5nUHViCQDZBAEFB21uZ1B1YlMEEWxHcm91cE5vZGVMaXN0S0VZCQEYZ2V0TGVhc2VHcm91cE5vZGVMaXN0S2V5AQUIZ3JvdXBOdW0EBm5MaXN0UwkBD2dldFN0cmluZ09yRmFpbAIFBHRoaXMFEWxHcm91cE5vZGVMaXN0S0VZBAVuTGlzdAkAtQkCBQZuTGlzdFMFA1NFUAMJAQIhPQIIBQFpD2NhbGxlclB1YmxpY0tleQUGbW5nUHViCQACAQIgcmViYWxhbmNlTGVhc2luZ3Mgbm90IGF1dGhvcml6ZWQECnVubGVhc2VBbXQJAGQCCQBpAgUGYW1vdW50CQCQAwEFBW5MaXN0AAEEDSR0MDM1NzI1MzU3ODcJAQxyZWFkTm9kZUluZm8BAAAEBm5BZGRyMAgFDSR0MDM1NzI1MzU3ODcCXzEECGxBbXRLRVkwCAUNJHQwMzU3MjUzNTc4NwJfMgQFbEFtdDAIBQ0kdDAzNTcyNTM1Nzg3Al8zBAdsSWRLRVkwCAUNJHQwMzU3MjUzNTc4NwJfNAQEbElkMAgFDSR0MDM1NzI1MzU3ODcCXzUEBW5ld0wwCQDECAIFBm5BZGRyMAkAZAIFBWxBbXQwCQBoAgUKdW5sZWFzZUFtdAkAkAMBBQVuTGlzdAoBFGZvckVhY2hOb2RlRG9VbmxlYXNlAgFhAWkEBG5vZGUJAJEDAgUFbkxpc3QFAWkEBmxJZEtFWQkBFmdldExlYXNlSWRCeUFkZHJlc3NLZXkBBQRub2RlBANsSWQJARFAZXh0ck5hdGl2ZSgxMDUyKQIFBHRoaXMFBmxJZEtFWQQHbEFtdEtFWQkBGmdldExlYXNlQW1vdW50QnlBZGRyZXNzS2V5AQUEbm9kZQQEbEFtdAkBEUBleHRyTmF0aXZlKDEwNTApAgUEdGhpcwUHbEFtdEtFWQQDdWxhCQELTGVhc2VDYW5jZWwBCQEFdmFsdWUBBQNsSWQEAmxhCQDECAIJARFAZXh0ck5hdGl2ZSgxMDYyKQEFBG5vZGUJAGUCBQRsQW10BQp1bmxlYXNlQW10CQDOCAIFAWEJAMwIAgkBC0xlYXNlQ2FuY2VsAQkBBXZhbHVlAQUDbElkCQDMCAIFAmxhCQDMCAIJAQtCaW5hcnlFbnRyeQIFBmxJZEtFWQkBBWxjYWxjAQUCbGEJAMwIAgkBDEludGVnZXJFbnRyeQIFB2xBbXRLRVkIBQJsYQZhbW91bnQFA25pbAkAzggCCgACJGwFBW5JZHhzCgACJHMJAJADAQUCJGwKAAUkYWNjMAUDbmlsCgEFJGYwXzECAiRhAiRpAwkAZwIFAiRpBQIkcwUCJGEJARRmb3JFYWNoTm9kZURvVW5sZWFzZQIFAiRhCQCRAwIFAiRsBQIkaQoBBSRmMF8yAgIkYQIkaQMJAGcCBQIkaQUCJHMFAiRhCQACAQITTGlzdCBzaXplIGV4Y2VlZHMgOAkBBSRmMF8yAgkBBSRmMF8xAgkBBSRmMF8xAgkBBSRmMF8xAgkBBSRmMF8xAgkBBSRmMF8xAgkBBSRmMF8xAgkBBSRmMF8xAgkBBSRmMF8xAgUFJGFjYzAAAAABAAIAAwAEAAUABgAHAAgJAMwIAgkBC0JpbmFyeUVudHJ5AgUHbElkS0VZMAkBBWxjYWxjAQUFbmV3TDAJAMwIAgkBDEludGVnZXJFbnRyeQIFCGxBbXRLRVkwCAUFbmV3TDAGYW1vdW50CQDMCAIJAQtMZWFzZUNhbmNlbAEFBGxJZDAJAMwIAgUFbmV3TDAFA25pbAFpARtzd2FwUGFyYW1zQnlVc2VyU1lTUkVBRE9OTFkCDnVzZXJBZGRyZXNzU3RyCWduc2J0RGlmZgQJZ25zYnREYXRhCQEJYXNBbnlMaXN0AQkA/AcEBRdnbnNidENvbnRyb2xsZXJDb250cmFjdAIUZ25zYnRJbmZvU1lTUkVBRE9OTFkJAMwIAgUOdXNlckFkZHJlc3NTdHIJAMwIAgAACQDMCAIAAAUDbmlsBQNuaWwECGduc2J0QW10CQBkAgkBBWFzSW50AQkAkQMCBQlnbnNidERhdGEAAAUJZ25zYnREaWZmBA1nbnNidEFtdFRvdGFsCQBkAgkBBWFzSW50AQkAkQMCBQlnbnNidERhdGEAAQUJZ25zYnREaWZmBA1zd2FwTGltaXREYXRhCQEJYXNBbnlMaXN0AQkA/AcEBQxtYXRoQ29udHJhY3QCFWNhbGNTd2FwTGltaXRSRUFET05MWQkAzAgCBQhnbnNidEFtdAUDbmlsBQNuaWwEF3dhdmVzU3dhcExpbWl0SW5Vc2RuTWF4CQEFYXNJbnQBCQCRAwIFDXN3YXBMaW1pdERhdGEAAAQRd2F2ZXNTd2FwTGltaXRNYXgJAQVhc0ludAEJAJEDAgUNc3dhcExpbWl0RGF0YQABBBB1c2RuU3dhcExpbWl0TWF4CQEFYXNJbnQBCQCRAwIFDXN3YXBMaW1pdERhdGEAAgQObGFzdFN3YXBIZWlnaHQJAQt2YWx1ZU9yRWxzZQIJAJoIAgUEdGhpcwkBFWtleVVzZXJMYXN0U3dhcEhlaWdodAEFDnVzZXJBZGRyZXNzU3RyAAAEF3N3YXBMaW1pdFRpbWVsaWZlQmxvY2tzCQESc3dhcHNUaW1lZnJhbWVSRUFEAAQZcGFzc2VkQmxvY2tzQWZ0ZXJMYXN0U3dhcAkAZQIFBmhlaWdodAUObGFzdFN3YXBIZWlnaHQEEWlzU3dhcFRpbWVsaWZlTmV3CQBnAgUZcGFzc2VkQmxvY2tzQWZ0ZXJMYXN0U3dhcAUXc3dhcExpbWl0VGltZWxpZmVCbG9ja3MEFHN3YXBMaW1pdFNwZW50SW5Vc2RuAwURaXNTd2FwVGltZWxpZmVOZXcAAAkBC3ZhbHVlT3JFbHNlAgkAmggCBQR0aGlzCQEYa2V5U3dhcFVzZXJTcGVudEluUGVyaW9kAQUOdXNlckFkZHJlc3NTdHIAAAQOYmxja3MyTG10UmVzZXQDBRFpc1N3YXBUaW1lbGlmZU5ldwAACQBlAgUXc3dhcExpbWl0VGltZWxpZmVCbG9ja3MFGXBhc3NlZEJsb2Nrc0FmdGVyTGFzdFN3YXAJAJQKAgUDbmlsCQCZCgcFF3dhdmVzU3dhcExpbWl0SW5Vc2RuTWF4BRRzd2FwTGltaXRTcGVudEluVXNkbgUOYmxja3MyTG10UmVzZXQFCGduc2J0QW10BQ1nbnNidEFtdFRvdGFsBRF3YXZlc1N3YXBMaW1pdE1heAUQdXNkblN3YXBMaW1pdE1heAFpAR1jYWxjV2l0aGRyYXdSZXN1bHRTWVNSRUFET05MWQMIc3dhcFR5cGUIaW5BbW91bnQFcHJpY2UED25ldXRyaW5vTWV0cmljcwkBCWFzQW55TGlzdAEJAPwHBAUMbWF0aENvbnRyYWN0AhpjYWxjTmV1dGlub01ldHJpY3NSRUFET05MWQUDbmlsBQNuaWwJAJQKAgUDbmlsCQEMY2FsY1dpdGhkcmF3BAUIc3dhcFR5cGUFCGluQW1vdW50BQVwcmljZQUPbmV1dHJpbm9NZXRyaWNzAWkBFHJlcGxhY2VDb21tdW5pdHlOb2RlBApvbGRBZGRyU3RyCm5ld0FkZHJTdHIIZ3JvdXBOdW0NcGVuYWx0eUFtb3VudAQHbW5nUHViUwkBC3ZhbHVlT3JFbHNlAgkAoggBAhwlcyVzX19jZmdfX2xlYXNpbmdNYW5hZ2VyUHViAiw3QVVNWDU0dWtZTVl2UG1tYTd5b0ZmNU5qWmhzNEJ1NW56M0V6OUVWOHN1cgQGbW5nUHViCQDZBAEFB21uZ1B1YlMDCQECIT0CCAUBaQ9jYWxsZXJQdWJsaWNLZXkFBm1uZ1B1YgkAAgECI3JlcGxhY2VDb21tdW5pdHlOb2RlIG5vdCBhdXRob3JpemVkBAhncm91cEtleQkBGGdldExlYXNlR3JvdXBOb2RlTGlzdEtleQEFCGdyb3VwTnVtBA5ncm91cE5vZGVMaXN0UwkBD2dldFN0cmluZ09yRmFpbAIFBHRoaXMFCGdyb3VwS2V5AwkBASEBCQEIY29udGFpbnMCBQ5ncm91cE5vZGVMaXN0UwUKb2xkQWRkclN0cgkAAgEJAKwCAgkArAICCQCsAgICBkdyb3VwIAkApAMBBQhncm91cE51bQIaIGRvZXMgbm90IGNvbnRhaW4gYWRkcmVzcyAFCm9sZEFkZHJTdHIECWRvUmVwbGFjZQkA/AcEBRRub2RlUmVnaXN0cnlDb250cmFjdAITcmVwbGFjZUFwcHJvdmVkTm9kZQkAzAgCBQpvbGRBZGRyU3RyCQDMCAIFCm5ld0FkZHJTdHIJAMwIAgUIZ3JvdXBOdW0JAMwIAgUNcGVuYWx0eUFtb3VudAUDbmlsBQNuaWwDCQAAAgUJZG9SZXBsYWNlBQlkb1JlcGxhY2UEDW9sZExlYXNlSWRLZXkJARZnZXRMZWFzZUlkQnlBZGRyZXNzS2V5AQUKb2xkQWRkclN0cgQOb2xkTGVhc2VBbXRLZXkJARpnZXRMZWFzZUFtb3VudEJ5QWRkcmVzc0tleQEFCm9sZEFkZHJTdHIECGxlYXNlQW10CQERQGV4dHJOYXRpdmUoMTA1NSkBBQ5vbGRMZWFzZUFtdEtleQQNbmV3TGVhc2VJZEtleQkBFmdldExlYXNlSWRCeUFkZHJlc3NLZXkBBQpvbGRBZGRyU3RyBA5uZXdMZWFzZUFtdEtleQkBGmdldExlYXNlQW1vdW50QnlBZGRyZXNzS2V5AQUKb2xkQWRkclN0cgQIbmV3TGVhc2UJAMQIAgkBEUBleHRyTmF0aXZlKDEwNjIpAQUKbmV3QWRkclN0cgUIbGVhc2VBbXQEFXVwZGF0ZWRHcm91cE5vZGVMaXN0UwkAuQkCCQC1CQIFDmdyb3VwTm9kZUxpc3RTBQpvbGRBZGRyU3RyBQpuZXdBZGRyU3RyCQCUCgIJAMwIAgkBC0xlYXNlQ2FuY2VsAQkBEUBleHRyTmF0aXZlKDEwNTcpAQUNb2xkTGVhc2VJZEtleQkAzAgCCQELRGVsZXRlRW50cnkBBQ1vbGRMZWFzZUlkS2V5CQDMCAIJAQtEZWxldGVFbnRyeQEFDm9sZExlYXNlQW10S2V5CQDMCAIJAQtTdHJpbmdFbnRyeQIFCGdyb3VwS2V5BRV1cGRhdGVkR3JvdXBOb2RlTGlzdFMJAMwIAgUIbmV3TGVhc2UJAMwIAgkBC0JpbmFyeUVudHJ5AgUNbmV3TGVhc2VJZEtleQkBBWxjYWxjAQUIbmV3TGVhc2UJAMwIAgkBDEludGVnZXJFbnRyeQIFDm5ld0xlYXNlQW10S2V5BQhsZWFzZUFtdAUDbmlsBQR1bml0CQACAQIkU3RyaWN0IHZhbHVlIGlzIG5vdCBlcXVhbCB0byBpdHNlbGYuAWkBH3VwZGF0ZVJlc2VydmVzQW5kTmV1dHJpbm9TdXBwbHkACgEWZ2V0TnVtYmVyQnlLZXlJbnRlcm5hbAEDa2V5BAckbWF0Y2gwCQCaCAIFBHRoaXMFA2tleQMJAAECBQckbWF0Y2gwAgNJbnQEAWEFByRtYXRjaDAFAWEAAAQHbk1ldHJpeAkBCWFzQW55TGlzdAEJAPwHBAUMbWF0aENvbnRyYWN0AhpjYWxjTmV1dGlub01ldHJpY3NSRUFET05MWQUDbmlsBQNuaWwEA2lkeAkBFmdldE51bWJlckJ5S2V5SW50ZXJuYWwBAiJ1cGRhdGVSZXNlcnZlc0FuZE5ldXRyaW5vU3VwcGx5SWR4BAZuZXdJZHgJAGQCBQNpZHgAAQkAzAgCCQEMSW50ZWdlckVudHJ5AgIidXBkYXRlUmVzZXJ2ZXNBbmROZXV0cmlub1N1cHBseUlkeAUGbmV3SWR4CQDMCAIJAQxJbnRlZ2VyRW50cnkCAgdyZXNlcnZlCQEFYXNJbnQBCQCRAwIFB25NZXRyaXgAAwkAzAgCCQEMSW50ZWdlckVudHJ5AgIObmV1dHJpbm9TdXBwbHkJAQVhc0ludAEJAJEDAgUHbk1ldHJpeAAFCQDMCAIJAQxJbnRlZ2VyRW50cnkCAg5yZXNlcnZlc0luVXNkbgkBFmNvbnZlcnRXYXZlc1RvTmV1dHJpbm8CCQEFYXNJbnQBCQCRAwIFB25NZXRyaXgAAwkBBWFzSW50AQkAkQMCBQduTWV0cml4AAAJAMwIAgkBDEludGVnZXJFbnRyeQICB3N1cnBsdXMJAQVhc0ludAEJAJEDAgUHbk1ldHJpeAAGCQDMCAIJAQxJbnRlZ2VyRW50cnkCAgdkZWZpY2l0CQEBLQEJAQVhc0ludAEJAJEDAgUHbk1ldHJpeAAGBQNuaWwBaQEWd2F2ZXNCYWxhbmNlc1ZzUGF5bWVudAAEAWIJAO8HAQUEdGhpcwkAzAgCCQEMSW50ZWdlckVudHJ5AgIWd2F2ZXNCYWxhbmNlX2F2YWlsYWJsZQgFAWIJYXZhaWxhYmxlCQDMCAIJAQxJbnRlZ2VyRW50cnkCAhR3YXZlc0JhbGFuY2VfcmVndWxhcggFAWIHcmVndWxhcgkAzAgCCQEMSW50ZWdlckVudHJ5AgIXd2F2ZXNCYWxhbmNlX2dlbmVyYXRpbmcIBQFiCmdlbmVyYXRpbmcJAMwIAgkBDEludGVnZXJFbnRyeQICFndhdmVzQmFsYW5jZV9lZmZlY3RpdmUIBQFiCWVmZmVjdGl2ZQkAzAgCCQEMSW50ZWdlckVudHJ5AgINd2F2ZXNfcGF5bWVudAgJAQV2YWx1ZQEJAJEDAggFAWkIcGF5bWVudHMAAAZhbW91bnQFA25pbAECdHgBBnZlcmlmeQAEAmlkCQDYBAEIBQJ0eAJpZAQTcHViS2V5QWRtaW5zTGlzdFN0cgkAuQkCCQDMCAICLEV4dEVFSzE5bm1LajltQ3BuV3l2RUVKRllBVExNY1ZFTXZvaGhVSGt5SE5tCQDMCAICLEV2NXB5NUZmQlFYOWNacFlLbmZRclRCNDlCeWY4UW1wWldlRFZSaW00eVY3CQDMCAICLERVdXVMalh1OThuQndaYzdmcXdDVGp0QTNublJ3Z1Ria01TcjVTVTJObURSCQDMCAICLERVdXVMalh1OThuQndaYzdmcXdDVGp0QTNublJ3Z1Ria01TcjVTVTJObURSBQNuaWwFA1NFUAQQcHViS2V5QWRtaW5zTGlzdAkAtQkCCQELdmFsdWVPckVsc2UCCQCdCAIFD2NvbnRyb2xDb250cmFjdAIMJXNfX211bHRpc2lnBRNwdWJLZXlBZG1pbnNMaXN0U3RyBQNTRVAEBWNvdW50CQBkAgkAZAIJAGQCAwkA9AMDCAUCdHgJYm9keUJ5dGVzCQCRAwIIBQJ0eAZwcm9vZnMAAAkA2QQBCQCRAwIFEHB1YktleUFkbWluc0xpc3QAAAABAAADCQD0AwMIBQJ0eAlib2R5Qnl0ZXMJAJEDAggFAnR4BnByb29mcwABCQDZBAEJAJEDAgUQcHViS2V5QWRtaW5zTGlzdAABAAEAAAMJAPQDAwgFAnR4CWJvZHlCeXRlcwkAkQMCCAUCdHgGcHJvb2ZzAAIJANkEAQkAkQMCBRBwdWJLZXlBZG1pbnNMaXN0AAIAAQAAAwkA9AMDCAUCdHgJYm9keUJ5dGVzCQCRAwIIBQJ0eAZwcm9vZnMAAwkA2QQBCQCRAwIFEHB1YktleUFkbWluc0xpc3QAAwACAAAEByRtYXRjaDAFAnR4AwkAAQIFByRtYXRjaDACFVNwb25zb3JGZWVUcmFuc2FjdGlvbgQJc3BvbnNvclR4BQckbWF0Y2gwAwkBG2NoZWNrSXNWYWxpZE1pblNwb25zb3JlZEZlZQEFCXNwb25zb3JUeAkAZwIFBWNvdW50AAMHCQBnAgUFY291bnQAA3+CL0U=", "chainId": 84, "height": 2217149, "applicationStatus": "succeeded", "spentComplexity": 0 } View: original | compacted Prev: 2YG32vXKqsqm5bGr318anrWctr9Uz2BQZiLuui7yxava Next: FBKpVvYZtNmJoLSRfrT4K54ipi1SzUzGcHGVAr44x6No Diff:
OldNewDifferences
138138 let gnsbtControllerContract = getContractAddressOrFail(controlCfg, IdxControlCfgGnsbtControllerDapp)
139139
140140 let auctionContract = getContractAddressOrFail(controlCfg, IdxControlCfgAuctionDapp)
141+
142+let nodeRegistryContract = getContractAddressOrFail(controlCfg, IdxControlCfgNodeRegistryDapp)
141143
142144 let NeutrinoAssetIdKey = "neutrino_asset_id"
143145
352354
353355 let sIdxMaxRand = 16
354356
357+let sIdxOutSurfAmount = 17
358+
359+let sIdxBR = 18
360+
355361 func swapKEY (userAddress,txId) = makeString(["%s%s", userAddress, txId], SEP)
356362
357363
358-func strSwapDATA (swapType,status,inAmount,price,outNetAmount,outFeeAmount,startHeight,startTimestamp,endHeight,endTimestamp,selfUnlockHeight,randUnlockHeight,index,withdrawTxId,randMin,randMax) = makeString(["%s%s%d%d%d%d%d%d%d%d%d%d%d%s", swapType, status, inAmount, price, outNetAmount, outFeeAmount, startHeight, startTimestamp, endHeight, endTimestamp, selfUnlockHeight, randUnlockHeight, index, withdrawTxId, randMin, randMax], SEP)
364+func strSwapDATA (swapType,status,inAmount,price,outNetAmount,outFeeAmount,startHeight,startTimestamp,endHeight,endTimestamp,selfUnlockHeight,randUnlockHeight,index,withdrawTxId,randMin,randMax,outSurfAmt,br) = makeString(["%s%s%d%d%d%d%d%d%d%d%d%d%d%s%d%d%d%d", swapType, status, inAmount, price, outNetAmount, outFeeAmount, startHeight, startTimestamp, endHeight, endTimestamp, selfUnlockHeight, randUnlockHeight, index, withdrawTxId, randMin, randMax, outSurfAmt, br], SEP)
359365
360366
361-func pendingSwapDATA (swapType,inAssetAmount,selfUnlockHeight) = strSwapDATA(swapType, "PENDING", toString(inAssetAmount), "0", "0", "0", toString(height), toString(lastBlock.timestamp), "0", "0", toString(selfUnlockHeight), "0", "0", "NULL", "0", "0")
367+func pendingSwapDATA (swapType,inAssetAmount,selfUnlockHeight) = strSwapDATA(swapType, "PENDING", toString(inAssetAmount), "0", "0", "0", toString(height), toString(lastBlock.timestamp), "0", "0", toString(selfUnlockHeight), "0", "0", "NULL", "0", "0", "0", "0")
362368
363369
364-func finishSwapDATA (dataArray,price,outNetAmount,outFeeAmount,randUnlockHeight,index,withdrawTxId) = strSwapDATA(dataArray[sIdxSwapType], "FINISHED", dataArray[sIdxInAmount], toString(price), toString(outNetAmount), toString(outFeeAmount), dataArray[sIdxStartHeight], dataArray[sIdxStartTimestamp], toString(height), toString(lastBlock.timestamp), dataArray[sIdxSelfUnlockHeight], toString(randUnlockHeight), toString(index), withdrawTxId, dataArray[sIdxMinRand], dataArray[sIdxMaxRand])
370+func finishSwapDATA (dataArray,price,outNetAmount,outFeeAmount,randUnlockHeight,index,withdrawTxId,outSurfAmt,br) = strSwapDATA(dataArray[sIdxSwapType], "FINISHED", dataArray[sIdxInAmount], toString(price), toString(outNetAmount), toString(outFeeAmount), dataArray[sIdxStartHeight], dataArray[sIdxStartTimestamp], toString(height), toString(lastBlock.timestamp), dataArray[sIdxSelfUnlockHeight], toString(randUnlockHeight), toString(index), withdrawTxId, dataArray[sIdxMinRand], dataArray[sIdxMaxRand], toString(outSurfAmt), toString(br))
365371
366372
367373 func swapDataFailOrREAD (userAddress,swapTxId) = {
547553 }
548554
549555
550-func calcWithdraw (swapType,inAmount,price) = {
556+func calcWithdraw (swapType,inAmount,price,neutrinoMetrics) = {
551557 let outFeePart = valueOrElse(getInteger(this, outFeePartKEY(swapType)), DEFAULTSWAPFEE)
552558 if (if ((0 > outFeePart))
553559 then true
555561 then throw(((("invalid outFeePart config for " + swapType) + " swap: outFeePart=") + toString(outFeePart)))
556562 else {
557563 let brProtected = valueOrElse(getInteger(this, brProtectedKEY()), BRPROTECTED)
558- let neutrinoMetrics = asAnyList(invoke(mathContract, "calcNeutinoMetricsREADONLY", nil, nil))
559564 let BR = asInt(neutrinoMetrics[nMetricIdxBR])
560565 let reservesInUsdn = asInt(neutrinoMetrics[nMetricIdxReserveInUsdn])
561566 let usdnSupply = asInt(neutrinoMetrics[nMetricIdxUsdnSupply])
583588 }
584589
585590
586-func commonWithdraw (account,index,swapTxId,withdrawTxId) = {
591+func commonWithdraw (account,index,swapTxId,withdrawTxId,neutrinoMetrics) = {
587592 let userAddress = addressFromStringValue(account)
588593 let dataArray = swapDataFailOrREAD(account, swapTxId)
589594 let selfUnlockHeight = parseIntValue(dataArray[sIdxSelfUnlockHeight])
613618 else false)
614619 then priceIndexFAIL(index, priceIndex, indexHeight, unlockHeight, prevIndexHeight)
615620 else {
616- let withdrawTuple = calcWithdraw(swapType, inAmount, priceByIndex)
621+ let withdrawTuple = calcWithdraw(swapType, inAmount, priceByIndex, neutrinoMetrics)
617622 let outNetAmount = withdrawTuple._1
618623 let outAssetId = withdrawTuple._2
619624 let outSurfAmt = withdrawTuple._3
624629 if ((0 >= outAmtGross))
625630 then throw("balance equals zero")
626631 else {
627- let state = [IntegerEntry(totalLockedByUserKEY(swapType, account), (totalLockedByUser - inAmount)), IntegerEntry(totalLockedKEY(swapType), (totalLocked - inAmount)), ScriptTransfer(userAddress, outNetAmount, outAssetId), StringEntry(swapKEY(account, swapTxId), finishSwapDATA(dataArray, priceByIndex, outNetAmount, outFeeAmount, unlockHeight, index, withdrawTxId))]
632+ let BR = asInt(neutrinoMetrics[nMetricIdxBR])
633+ let state = [IntegerEntry(totalLockedByUserKEY(swapType, account), (totalLockedByUser - inAmount)), IntegerEntry(totalLockedKEY(swapType), (totalLocked - inAmount)), ScriptTransfer(userAddress, outNetAmount, outAssetId), StringEntry(swapKEY(account, swapTxId), finishSwapDATA(dataArray, priceByIndex, outNetAmount, outFeeAmount, unlockHeight, index, withdrawTxId, outSurfAmt, BR))]
628634 let surfCondition = if ((outSurfAmt > 0))
629635 then {
630636 let issueResult = invoke(auctionContract, "issueSurf", [outSurfAmt, account], nil)
707713 if ((size(i.payments) != 0))
708714 then throw("no payments allowed")
709715 else {
710- let commonTuple = commonWithdraw(account, index, swapTxId, txId)
716+ let neutrinoMetrics = asAnyList(invoke(mathContract, "calcNeutinoMetricsREADONLY", nil, nil))
717+ let BR = asInt(neutrinoMetrics[nMetricIdxBR])
718+ let commonTuple = commonWithdraw(account, index, swapTxId, txId, neutrinoMetrics)
711719 let state = commonTuple._1
712720 let fee = commonTuple._2
713721 let unleaseAmt = commonTuple._3
717725 let gnsbtData = asAnyList(invoke(gnsbtControllerContract, "gnsbtInfoSYSREADONLY", ["", 0, 0], nil))
718726 let gnsbtAmtTotal = asInt(gnsbtData[1])
719727 let gnsbtAmtFromSurfTotal = asInt(asAnyList(gnsbtData[3])[3])
720- let surfFeeAmt = if ((gnsbtAmtTotal != 0))
728+ let surfFeeAmt1 = if ((gnsbtAmtTotal != 0))
721729 then fraction(fee.amount, gnsbtAmtFromSurfTotal, gnsbtAmtTotal)
722730 else 0
731+ let surfFeeAmt2 = if ((gnsbtAmtTotal != 0))
732+ then fraction(fee.amount, (PAULI - BR), PAULI)
733+ else 0
734+ let surfFeeAmt = max([surfFeeAmt1, surfFeeAmt2])
723735 let nsbtFeeAmt = (fee.amount - surfFeeAmt)
724736 let surfDeposit = if ((surfFeeAmt > 0))
725737 then {
773785
774786
775787 @Callable(i)
776-func approveLeasings (nListS,groupNum) = {
777- let lAmt = (50 * WAVELET)
788+func approveLeasings (nListS,groupNum,lAmt) = {
778789 let nIdxs = [0, 1, 2, 3, 4, 5, 6, 7]
779790 let mngPubS = valueOrElse(getString("%s%s__cfg__leasingManagerPub"), "7AUMX54ukYMYvPmma7yoFf5NjZhs4Bu5nz3Ez9EV8sur")
780791 let mngPub = fromBase58String(mngPubS)
790801 if ((i.callerPublicKey != mngPub))
791802 then throw("approveLeasings not authorized")
792803 else {
793- let $t03363933701 = readNodeInfo(0)
794- let nAddr0 = $t03363933701._1
795- let lAmtKEY0 = $t03363933701._2
796- let lAmt0 = $t03363933701._3
797- let lIdKEY0 = $t03363933701._4
798- let lId0 = $t03363933701._5
799- let $t03370433766 = readNodeInfo(1)
800- let nAddr1 = $t03370433766._1
801- let lAmtKEY1 = $t03370433766._2
802- let lAmt1 = $t03370433766._3
803- let lIdKEY1 = $t03370433766._4
804- let lId1 = $t03370433766._5
805- let newL0 = Lease(nAddr0, (lAmt0 - ((lAmt * expCount) / 2)))
806- let newL1 = Lease(nAddr1, (lAmt1 - ((lAmt * expCount) / 2)))
804+ let $t03442334485 = readNodeInfo(0)
805+ let nAddr0 = $t03442334485._1
806+ let lAmtKEY0 = $t03442334485._2
807+ let lAmt0 = $t03442334485._3
808+ let lIdKEY0 = $t03442334485._4
809+ let lId0 = $t03442334485._5
810+ let newL0 = Lease(nAddr0, (lAmt0 - (lAmt * expCount)))
807811 let validation = invoke(nodeRegAddr, "validateAndApproveLeasings", [nListS], nil)
808812 if ((validation == validation))
809813 then {
813817 (a ++ [la, BinaryEntry(getLeaseIdByAddressKey(node), lcalc(la)), IntegerEntry(getLeaseAmountByAddressKey(node), lAmt)])
814818 }
815819
816- ([StringEntry(lGroupNodeListKEY, nListS), BinaryEntry(lIdKEY0, lcalc(newL0)), BinaryEntry(lIdKEY1, lcalc(newL1)), IntegerEntry(lAmtKEY0, newL0.amount), IntegerEntry(lAmtKEY1, newL1.amount), LeaseCancel(lId0), LeaseCancel(lId1), newL0, newL1] ++ {
820+ ([StringEntry(lGroupNodeListKEY, nListS), BinaryEntry(lIdKEY0, lcalc(newL0)), IntegerEntry(lAmtKEY0, newL0.amount), LeaseCancel(lId0), newL0] ++ {
817821 let $l = nIdxs
818822 let $s = size($l)
819823 let $acc0 = nil
847851 then throw("rebalanceLeasings not authorized")
848852 else {
849853 let unleaseAmt = ((amount / size(nList)) + 1)
850- let $t03518335245 = readNodeInfo(0)
851- let nAddr0 = $t03518335245._1
852- let lAmtKEY0 = $t03518335245._2
853- let lAmt0 = $t03518335245._3
854- let lIdKEY0 = $t03518335245._4
855- let lId0 = $t03518335245._5
854+ let $t03572535787 = readNodeInfo(0)
855+ let nAddr0 = $t03572535787._1
856+ let lAmtKEY0 = $t03572535787._2
857+ let lAmt0 = $t03572535787._3
858+ let lIdKEY0 = $t03572535787._4
859+ let lId0 = $t03572535787._5
856860 let newL0 = Lease(nAddr0, (lAmt0 + (unleaseAmt * size(nList))))
857861 func forEachNodeDoUnlease (a,i) = {
858862 let node = nList[i]
909913
910914
911915 @Callable(i)
912-func calcWithdrawResultSYSREADONLY (swapType,inAmount,price) = $Tuple2(nil, calcWithdraw(swapType, inAmount, price))
916+func calcWithdrawResultSYSREADONLY (swapType,inAmount,price) = {
917+ let neutrinoMetrics = asAnyList(invoke(mathContract, "calcNeutinoMetricsREADONLY", nil, nil))
918+ $Tuple2(nil, calcWithdraw(swapType, inAmount, price, neutrinoMetrics))
919+ }
920+
921+
922+
923+@Callable(i)
924+func replaceCommunityNode (oldAddrStr,newAddrStr,groupNum,penaltyAmount) = {
925+ let mngPubS = valueOrElse(getString("%s%s__cfg__leasingManagerPub"), "7AUMX54ukYMYvPmma7yoFf5NjZhs4Bu5nz3Ez9EV8sur")
926+ let mngPub = fromBase58String(mngPubS)
927+ if ((i.callerPublicKey != mngPub))
928+ then throw("replaceCommunityNode not authorized")
929+ else {
930+ let groupKey = getLeaseGroupNodeListKey(groupNum)
931+ let groupNodeListS = getStringOrFail(this, groupKey)
932+ if (!(contains(groupNodeListS, oldAddrStr)))
933+ then throw(((("Group " + toString(groupNum)) + " does not contain address ") + oldAddrStr))
934+ else {
935+ let doReplace = invoke(nodeRegistryContract, "replaceApprovedNode", [oldAddrStr, newAddrStr, groupNum, penaltyAmount], nil)
936+ if ((doReplace == doReplace))
937+ then {
938+ let oldLeaseIdKey = getLeaseIdByAddressKey(oldAddrStr)
939+ let oldLeaseAmtKey = getLeaseAmountByAddressKey(oldAddrStr)
940+ let leaseAmt = getIntegerValue(oldLeaseAmtKey)
941+ let newLeaseIdKey = getLeaseIdByAddressKey(oldAddrStr)
942+ let newLeaseAmtKey = getLeaseAmountByAddressKey(oldAddrStr)
943+ let newLease = Lease(addressFromStringValue(newAddrStr), leaseAmt)
944+ let updatedGroupNodeListS = makeString(split(groupNodeListS, oldAddrStr), newAddrStr)
945+ $Tuple2([LeaseCancel(getBinaryValue(oldLeaseIdKey)), DeleteEntry(oldLeaseIdKey), DeleteEntry(oldLeaseAmtKey), StringEntry(groupKey, updatedGroupNodeListS), newLease, BinaryEntry(newLeaseIdKey, lcalc(newLease)), IntegerEntry(newLeaseAmtKey, leaseAmt)], unit)
946+ }
947+ else throw("Strict value is not equal to itself.")
948+ }
949+ }
950+ }
913951
914952
915953
Full:
OldNewDifferences
11 {-# STDLIB_VERSION 6 #-}
22 {-# SCRIPT_TYPE ACCOUNT #-}
33 {-# CONTENT_TYPE DAPP #-}
44 func getStringOrFail (address,key) = valueOrErrorMessage(getString(address, key), makeString(["mandatory ", toString(address), ".", key, " is not defined"], ""))
55
66
77 func lcalc (l) = calculateLeaseId(l)
88
99
1010 func getNumberByKey (key) = valueOrElse(getInteger(this, key), 0)
1111
1212
1313 func getStringByKey (key) = valueOrElse(getString(this, key), "")
1414
1515
1616 func getBoolByKey (key) = valueOrElse(getBoolean(this, key), false)
1717
1818
1919 func getNumberByAddressAndKey (address,key) = valueOrElse(getInteger(address, key), 0)
2020
2121
2222 func getStringByAddressAndKey (address,key) = valueOrElse(getString(addressFromStringValue(address), key), "")
2323
2424
2525 func getBoolByAddressAndKey (address,key) = valueOrElse(getBoolean(address, key), false)
2626
2727
2828 func asAnyList (v) = match v {
2929 case l: List[Any] =>
3030 l
3131 case _ =>
3232 throw("fail to cast into List[Any]")
3333 }
3434
3535
3636 func asString (v) = match v {
3737 case s: String =>
3838 s
3939 case _ =>
4040 throw("fail to cast into String")
4141 }
4242
4343
4444 func asInt (v) = match v {
4545 case i: Int =>
4646 i
4747 case _ =>
4848 throw("fail to cast into Int")
4949 }
5050
5151
5252 func asBytes (val) = match val {
5353 case valByte: ByteVector =>
5454 valByte
5555 case _ =>
5656 throw("fail to cast into ByteVector")
5757 }
5858
5959
6060 func asPayment (v) = match v {
6161 case p: AttachedPayment =>
6262 p
6363 case _ =>
6464 throw("fail to cast into AttachedPayment")
6565 }
6666
6767
6868 func asSwapParamsSTRUCT (v) = match v {
6969 case struct: (Int, Int, Int, Int, Int, Int, Int) =>
7070 struct
7171 case _ =>
7272 throw("fail to cast into Tuple5 ints")
7373 }
7474
7575
7676 let SEP = "__"
7777
7878 let WAVELET = 100000000
7979
8080 let PAULI = 1000000
8181
8282 let PRICELET = 1000000
8383
8484 let DEFAULTSWAPFEE = 20000
8585
8686 let BRPROTECTED = 100000
8787
8888 let IdxNetAmount = 0
8989
9090 let IdxFeeAmount = 1
9191
9292 let IdxGrossAmount = 2
9393
9494 let IdxControlCfgNeutrinoDapp = 1
9595
9696 let IdxControlCfgAuctionDapp = 2
9797
9898 let IdxControlCfgRpdDapp = 3
9999
100100 let IdxControlCfgMathDapp = 4
101101
102102 let IdxControlCfgLiquidationDapp = 5
103103
104104 let IdxControlCfgRestDapp = 6
105105
106106 let IdxControlCfgNodeRegistryDapp = 7
107107
108108 let IdxControlCfgNsbtStakingDapp = 8
109109
110110 let IdxControlCfgMediatorDapp = 9
111111
112112 let IdxControlCfgSurfStakingDapp = 10
113113
114114 let IdxControlCfgGnsbtControllerDapp = 11
115115
116116 func keyControlAddress () = "%s%s__config__controlAddress"
117117
118118
119119 func keyControlCfg () = "%s__controlConfig"
120120
121121
122122 func readControlCfgOrFail (control) = split(getStringOrFail(control, keyControlCfg()), SEP)
123123
124124
125125 func getContractAddressOrFail (controlCfg,idx) = valueOrErrorMessage(addressFromString(controlCfg[idx]), ("Control cfg doesn't contain address at index " + toString(idx)))
126126
127127
128128 let controlContract = addressFromStringValue(valueOrElse(getString(this, keyControlAddress()), "3N4NS7d4Jo9a6F14LiFUKKYVdUkkf2eP4Zx"))
129129
130130 let controlCfg = readControlCfgOrFail(controlContract)
131131
132132 let mathContract = getContractAddressOrFail(controlCfg, IdxControlCfgMathDapp)
133133
134134 let nsbtStakingContract = getContractAddressOrFail(controlCfg, IdxControlCfgNsbtStakingDapp)
135135
136136 let surfStakingContract = getContractAddressOrFail(controlCfg, IdxControlCfgSurfStakingDapp)
137137
138138 let gnsbtControllerContract = getContractAddressOrFail(controlCfg, IdxControlCfgGnsbtControllerDapp)
139139
140140 let auctionContract = getContractAddressOrFail(controlCfg, IdxControlCfgAuctionDapp)
141+
142+let nodeRegistryContract = getContractAddressOrFail(controlCfg, IdxControlCfgNodeRegistryDapp)
141143
142144 let NeutrinoAssetIdKey = "neutrino_asset_id"
143145
144146 let BondAssetIdKey = "bond_asset_id"
145147
146148 let AuctionContractKey = "auction_contract"
147149
148150 let NsbtStakingContractKey = "nsbtStakingContract"
149151
150152 let LiquidationContractKey = "liquidation_contract"
151153
152154 let RPDContractKey = "rpd_contract"
153155
154156 let ContolContractKey = "control_contract"
155157
156158 let MathContractKey = "math_contract"
157159
158160 let BalanceWavesLockIntervalKey = "balance_waves_lock_interval"
159161
160162 let BalanceNeutrinoLockIntervalKey = "balance_neutrino_lock_interval"
161163
162164 let MinWavesSwapAmountKey = "min_waves_swap_amount"
163165
164166 let MinNeutrinoSwapAmountKey = "min_neutrino_swap_amount"
165167
166168 let NodeOracleProviderPubKeyKey = "node_oracle_provider"
167169
168170 let NeutrinoOutFeePartKey = "neutrinoOut_swap_feePart"
169171
170172 let WavesOutFeePartKey = "wavesOut_swap_feePart"
171173
172174 func keyNodeRegistry (address) = ("%s__" + address)
173175
174176
175177 let PriceKey = "price"
176178
177179 let PriceIndexKey = "price_index"
178180
179181 let IsBlockedKey = "is_blocked"
180182
181183 func getPriceHistoryKey (block) = ((PriceKey + "_") + toString(block))
182184
183185
184186 func getHeightPriceByIndexKey (index) = ((PriceIndexKey + "_") + toString(index))
185187
186188
187189 func getStakingNodeByIndex (idx) = getStringByKey(makeString(["%s%d%s", "lease", toString(idx), "nodeAddress"], SEP))
188190
189191
190192 func getStakingNodeAddressByIndex (idx) = addressFromStringValue(getStakingNodeByIndex(idx))
191193
192194
193195 func getReservedAmountForSponsorship () = valueOrElse(getInteger(this, makeString(["%s%s", "lease", "sponsorshipWavesReserve"], SEP)), (1000 * WAVELET))
194196
195197
196198 func getBalanceUnlockBlockKey (owner) = ("balance_unlock_block_" + owner)
197199
198200
199201 func getLeaseIdKey (nodeIndex) = makeString(["%s%d%s", "lease", toString(nodeIndex), "id"], SEP)
200202
201203
202204 func getLeaseIdByAddressKey (nodeAddress) = makeString(["%s%s%s", "leaseByAddress", nodeAddress, "id"], SEP)
203205
204206
205207 func getLeaseAmountKey (nodeIndex) = makeString(["%s%d%s", "lease", toString(nodeIndex), "amount"], SEP)
206208
207209
208210 func getLeaseAmountByAddressKey (nodeAddress) = makeString(["%s%s%s", "leaseByAddress", nodeAddress, "amount"], SEP)
209211
210212
211213 func getLeaseGroupNodeListKey (groupNum) = makeString(["%s%d%s", "leaseGroup", toString(groupNum), "nodeList"], SEP)
212214
213215
214216 func minSwapAmountKEY (swapType) = (("min_" + swapType) + "_swap_amount")
215217
216218
217219 func totalLockedKEY (swapType) = ("balance_lock_" + swapType)
218220
219221
220222 func totalLockedByUserKEY (swapType,owner) = makeString(["balance_lock", swapType, owner], "_")
221223
222224
223225 func balanceLockIntervalKEY (swapType) = (("balance_" + swapType) + "_lock_interval")
224226
225227
226228 func nodeBalanceLockIntervalKEY () = "balance_node_lock_interval"
227229
228230
229231 func outFeePartKEY (swapType) = (swapType + "Out_swap_feePart")
230232
231233
232234 func swapsTimeframeKEY () = "swaps_timeframe"
233235
234236
235237 func brProtectedKEY () = "min_BR_protection_level"
236238
237239
238240 func minSwapAmountREAD (swapType) = valueOrElse(getInteger(this, minSwapAmountKEY(swapType)), 0)
239241
240242
241243 func swapsTimeframeREAD () = valueOrElse(getInteger(this, swapsTimeframeKEY()), 1440)
242244
243245
244246 func totalLockedREAD (swapType) = valueOrElse(getInteger(this, totalLockedKEY(swapType)), 0)
245247
246248
247249 func totalLockedByUserREAD (swapType,owner) = valueOrElse(getInteger(this, totalLockedByUserKEY(swapType, owner)), 0)
248250
249251
250252 func balanceLockIntervalREAD (swapType) = valueOrElse(getInteger(this, balanceLockIntervalKEY(swapType)), 1440)
251253
252254
253255 func nodeBalanceLockIntervalREAD () = valueOrElse(getInteger(this, nodeBalanceLockIntervalKEY()), 1)
254256
255257
256258 func keySwapUserSpentInPeriod (userAddress) = makeString(["%s%s", "swapUserSpentInPeriod", userAddress], SEP)
257259
258260
259261 func keyUserLastSwapHeight (userAddress) = makeString(["%s%s", "userLastSwapHeight", userAddress], SEP)
260262
261263
262264 func convertNeutrinoToWaves (amount,price) = fraction(fraction(amount, PRICELET, price), WAVELET, PAULI)
263265
264266
265267 func convertWavesToNeutrino (amount,price) = fraction(fraction(amount, price, PRICELET), PAULI, WAVELET)
266268
267269
268270 func convertWavesToBond (amount,price) = convertWavesToNeutrino(amount, price)
269271
270272
271273 func convertJsonArrayToList (jsonArray) = split(jsonArray, ",")
272274
273275
274276 func minSwapAmountFAIL (swapType,minSwapAmount) = throw(((("The specified amount in " + swapType) + " swap is less than the required minimum of ") + toString(minSwapAmount)))
275277
276278
277279 func emergencyShutdownFAIL () = throw("contract is blocked by EMERGENCY SHUTDOWN actions untill reactivation by emergency oracles")
278280
279281
280282 func priceIndexFAIL (index,priceIndex,indexHeight,unlockHeight,prevIndexHeight) = throw(((((((((("invalid price history index: index=" + toString(index)) + " priceIndex=") + toString(priceIndex)) + " indexHeight=") + toString(indexHeight)) + " unlockHeight=") + toString(unlockHeight)) + " prevIndexHeight=") + toString(prevIndexHeight)))
281283
282284
283285 let neutrinoAssetId = fromBase58String(getStringByKey(NeutrinoAssetIdKey))
284286
285287 let priceIndex = getNumberByAddressAndKey(controlContract, PriceIndexKey)
286288
287289 let isBlocked = getBoolByAddressAndKey(controlContract, IsBlockedKey)
288290
289291 let nodeOracleProviderPubKey = fromBase58String(getStringByKey(NodeOracleProviderPubKeyKey))
290292
291293 let bondAssetId = fromBase58String("F3iaxzruFeKujfVfYSZEkejpjh67wmRfPCRHiNmWKp3Z")
292294
293295 let deprecatedBondAssetId = fromBase58String("975akZBfnMj513U7MZaHKzQrmsEx5aE3wdWKTrHBhbjF")
294296
295297 let neutrinoContract = this
296298
297299 let currentPrice = getNumberByAddressAndKey(controlContract, PriceKey)
298300
299301 func checkIsValidMinSponsoredFee (tx) = {
300302 let MINTRANSFERFEE = 100000
301303 let SponsoredFeeUpperBound = 1000
302304 let realNeutrinoFee = convertWavesToNeutrino(MINTRANSFERFEE, currentPrice)
303305 let minNeutrinoFee = (realNeutrinoFee * 2)
304306 let maxNeutrinoFee = fraction(realNeutrinoFee, SponsoredFeeUpperBound, 100)
305307 let inputFee = value(tx.minSponsoredAssetFee)
306308 if (if ((inputFee >= minNeutrinoFee))
307309 then (maxNeutrinoFee >= inputFee)
308310 else false)
309311 then (tx.assetId == neutrinoAssetId)
310312 else false
311313 }
312314
313315
314316 func getPriceHistory (block) = getNumberByAddressAndKey(controlContract, getPriceHistoryKey(block))
315317
316318
317319 func getHeightPriceByIndex (index) = getNumberByAddressAndKey(controlContract, getHeightPriceByIndexKey(index))
318320
319321
320322 func keyLockParamUserAmount (userAddress) = makeString(["%s%s%s", "paramByUser", userAddress, "amount"], SEP)
321323
322324
323325 let sIdxSwapType = 1
324326
325327 let sIdxStatus = 2
326328
327329 let sIdxInAmount = 3
328330
329331 let sIdxPrice = 4
330332
331333 let sIdxOutNetAmount = 5
332334
333335 let sIdxOutFeeAmount = 6
334336
335337 let sIdxStartHeight = 7
336338
337339 let sIdxStartTimestamp = 8
338340
339341 let sIdxEndHeight = 9
340342
341343 let sIdxEndTimestamp = 10
342344
343345 let sIdxSelfUnlockHeight = 11
344346
345347 let sIdxRandUnlockHeight = 12
346348
347349 let sIdxIndex = 13
348350
349351 let sIdxWithdrawTxId = 14
350352
351353 let sIdxMinRand = 15
352354
353355 let sIdxMaxRand = 16
354356
357+let sIdxOutSurfAmount = 17
358+
359+let sIdxBR = 18
360+
355361 func swapKEY (userAddress,txId) = makeString(["%s%s", userAddress, txId], SEP)
356362
357363
358-func strSwapDATA (swapType,status,inAmount,price,outNetAmount,outFeeAmount,startHeight,startTimestamp,endHeight,endTimestamp,selfUnlockHeight,randUnlockHeight,index,withdrawTxId,randMin,randMax) = makeString(["%s%s%d%d%d%d%d%d%d%d%d%d%d%s", swapType, status, inAmount, price, outNetAmount, outFeeAmount, startHeight, startTimestamp, endHeight, endTimestamp, selfUnlockHeight, randUnlockHeight, index, withdrawTxId, randMin, randMax], SEP)
364+func strSwapDATA (swapType,status,inAmount,price,outNetAmount,outFeeAmount,startHeight,startTimestamp,endHeight,endTimestamp,selfUnlockHeight,randUnlockHeight,index,withdrawTxId,randMin,randMax,outSurfAmt,br) = makeString(["%s%s%d%d%d%d%d%d%d%d%d%d%d%s%d%d%d%d", swapType, status, inAmount, price, outNetAmount, outFeeAmount, startHeight, startTimestamp, endHeight, endTimestamp, selfUnlockHeight, randUnlockHeight, index, withdrawTxId, randMin, randMax, outSurfAmt, br], SEP)
359365
360366
361-func pendingSwapDATA (swapType,inAssetAmount,selfUnlockHeight) = strSwapDATA(swapType, "PENDING", toString(inAssetAmount), "0", "0", "0", toString(height), toString(lastBlock.timestamp), "0", "0", toString(selfUnlockHeight), "0", "0", "NULL", "0", "0")
367+func pendingSwapDATA (swapType,inAssetAmount,selfUnlockHeight) = strSwapDATA(swapType, "PENDING", toString(inAssetAmount), "0", "0", "0", toString(height), toString(lastBlock.timestamp), "0", "0", toString(selfUnlockHeight), "0", "0", "NULL", "0", "0", "0", "0")
362368
363369
364-func finishSwapDATA (dataArray,price,outNetAmount,outFeeAmount,randUnlockHeight,index,withdrawTxId) = strSwapDATA(dataArray[sIdxSwapType], "FINISHED", dataArray[sIdxInAmount], toString(price), toString(outNetAmount), toString(outFeeAmount), dataArray[sIdxStartHeight], dataArray[sIdxStartTimestamp], toString(height), toString(lastBlock.timestamp), dataArray[sIdxSelfUnlockHeight], toString(randUnlockHeight), toString(index), withdrawTxId, dataArray[sIdxMinRand], dataArray[sIdxMaxRand])
370+func finishSwapDATA (dataArray,price,outNetAmount,outFeeAmount,randUnlockHeight,index,withdrawTxId,outSurfAmt,br) = strSwapDATA(dataArray[sIdxSwapType], "FINISHED", dataArray[sIdxInAmount], toString(price), toString(outNetAmount), toString(outFeeAmount), dataArray[sIdxStartHeight], dataArray[sIdxStartTimestamp], toString(height), toString(lastBlock.timestamp), dataArray[sIdxSelfUnlockHeight], toString(randUnlockHeight), toString(index), withdrawTxId, dataArray[sIdxMinRand], dataArray[sIdxMaxRand], toString(outSurfAmt), toString(br))
365371
366372
367373 func swapDataFailOrREAD (userAddress,swapTxId) = {
368374 let swapKey = swapKEY(userAddress, swapTxId)
369375 split(valueOrErrorMessage(getString(this, swapKey), ("no swap data for " + swapKey)), SEP)
370376 }
371377
372378
373379 func applyFees (amountOutGross,inAmtToSURF,feePart) = {
374380 let feeAmount = fraction(amountOutGross, feePart, PAULI)
375381 [(amountOutGross - feeAmount), feeAmount]
376382 }
377383
378384
379385 func abs (x) = if ((0 > x))
380386 then -(x)
381387 else x
382388
383389
384390 func selectNode (unleaseAmount) = {
385391 let amountToLease = ((wavesBalance(neutrinoContract).available - unleaseAmount) - getReservedAmountForSponsorship())
386392 let oldLeased0 = getNumberByKey(getLeaseAmountKey(0))
387393 let oldLeased1 = getNumberByKey(getLeaseAmountKey(1))
388394 let newLeased0 = (amountToLease + oldLeased0)
389395 let newLeased1 = (amountToLease + oldLeased1)
390396 if (if ((newLeased0 > 0))
391397 then true
392398 else (newLeased1 > 0))
393399 then {
394400 let delta0 = abs((newLeased0 - oldLeased1))
395401 let delta1 = abs((newLeased1 - oldLeased0))
396402 if ((delta1 >= delta0))
397403 then $Tuple2(0, newLeased0)
398404 else $Tuple2(1, newLeased1)
399405 }
400406 else $Tuple2(-1, 0)
401407 }
402408
403409
404410 func thisOnly (i) = if ((i.caller != this))
405411 then throw("Permission denied: this contract only allowed")
406412 else true
407413
408414
409415 func prepareUnleaseAndLease (unleaseAmount) = {
410416 let nodeTuple = selectNode(unleaseAmount)
411417 let nodeIndex = nodeTuple._1
412418 let newLeaseAmount = nodeTuple._2
413419 if ((newLeaseAmount > 0))
414420 then {
415421 let leaseIdKey = getLeaseIdKey(nodeIndex)
416422 let oldLease = getBinary(this, leaseIdKey)
417423 let unleaseOrEmpty = if (isDefined(oldLease))
418424 then [LeaseCancel(value(oldLease))]
419425 else nil
420426 let leaseAmountKey = getLeaseAmountKey(nodeIndex)
421427 let lease = Lease(getStakingNodeAddressByIndex(nodeIndex), newLeaseAmount)
422428 (unleaseOrEmpty ++ [lease, BinaryEntry(leaseIdKey, lcalc(lease)), IntegerEntry(getLeaseAmountKey(nodeIndex), newLeaseAmount)])
423429 }
424430 else nil
425431 }
426432
427433
428434 func readNodeInfo (nodeIdx) = {
429435 let nodeAddress = getStakingNodeAddressByIndex(nodeIdx)
430436 let leasedAmtKEY = getLeaseAmountKey(nodeIdx)
431437 let leasedAmt = getNumberByKey(leasedAmtKEY)
432438 let leaseIdKEY = getLeaseIdKey(nodeIdx)
433439 let leaseId = value(getBinary(this, leaseIdKEY))
434440 $Tuple5(nodeAddress, leasedAmtKEY, leasedAmt, leaseIdKEY, leaseId)
435441 }
436442
437443
438444 func commonSwap (swapType,pmtAmount,userAddressStr,txId58,swapParamsByUserSYSREADONLY) = {
439445 let swapLimitSpent = swapParamsByUserSYSREADONLY._2
440446 let blcks2LmtReset = swapParamsByUserSYSREADONLY._3
441447 let wavesSwapLimitMax = swapParamsByUserSYSREADONLY._6
442448 let usdnSwapLimitMax = swapParamsByUserSYSREADONLY._7
443449 let minSwapAmount = minSwapAmountREAD(swapType)
444450 let totalLocked = totalLockedREAD(swapType)
445451 let totalLockedByUser = totalLockedByUserREAD(swapType, userAddressStr)
446452 let nodeAddress = getStakingNodeByIndex(0)
447453 let priceByIndex = getPriceHistory(getHeightPriceByIndex(priceIndex))
448454 let isSwapByNode = (nodeAddress == userAddressStr)
449455 let balanceLockMaxInterval = if (isSwapByNode)
450456 then nodeBalanceLockIntervalREAD()
451457 else balanceLockIntervalREAD(swapType)
452458 let selfUnlockHeight = (height + balanceLockMaxInterval)
453459 let swapUsdnVolume = if ((swapType == "neutrino"))
454460 then pmtAmount
455461 else convertWavesToNeutrino(pmtAmount, priceByIndex)
456462 let swapLimitMax = if ((swapType == "neutrino"))
457463 then usdnSwapLimitMax
458464 else convertWavesToNeutrino(wavesSwapLimitMax, priceByIndex)
459465 if ((minSwapAmount > pmtAmount))
460466 then minSwapAmountFAIL(swapType, minSwapAmount)
461467 else if (if (!(isSwapByNode))
462468 then (swapLimitSpent > 0)
463469 else false)
464470 then throw(("You have exceeded swap limit! Next allowed swap height is " + toString((height + blcks2LmtReset))))
465471 else if (if (!(isSwapByNode))
466472 then (swapUsdnVolume > swapLimitMax)
467473 else false)
468474 then throw(((("You have exceeded your swap limit! Requested: " + toString(swapUsdnVolume)) + ", available: ") + toString(swapLimitMax)))
469475 else if (isBlocked)
470476 then emergencyShutdownFAIL()
471477 else {
472478 let leasePart = if ((swapType == "waves"))
473479 then prepareUnleaseAndLease(0)
474480 else nil
475481 $Tuple2(([IntegerEntry(keySwapUserSpentInPeriod(userAddressStr), swapUsdnVolume), IntegerEntry(keyUserLastSwapHeight(userAddressStr), height), IntegerEntry(totalLockedByUserKEY(swapType, userAddressStr), (totalLockedByUser + pmtAmount)), IntegerEntry(getBalanceUnlockBlockKey(userAddressStr), selfUnlockHeight), IntegerEntry(totalLockedKEY(swapType), (totalLocked + pmtAmount)), StringEntry(swapKEY(userAddressStr, txId58), pendingSwapDATA(swapType, pmtAmount, selfUnlockHeight))] ++ leasePart), unit)
476482 }
477483 }
478484
479485
480486 let nMetricIdxPrice = 0
481487
482488 let nMetricIdxUsdnLockedBalance = 1
483489
484490 let nMetricIdxWavesLockedBalance = 2
485491
486492 let nMetricIdxReserve = 3
487493
488494 let nMetricIdxReserveInUsdn = 4
489495
490496 let nMetricIdxUsdnSupply = 5
491497
492498 let nMetricIdxSurplus = 6
493499
494500 let nMetricIdxSurplusPercent = 7
495501
496502 let nMetricIdxBR = 8
497503
498504 let nMetricIdxNsbtSupply = 9
499505
500506 let nMetricIdxMaxNsbtSupply = 10
501507
502508 let nMetricIdxSurfSupply = 11
503509
504510 let bFuncIdxSurf = 0
505511
506512 let bFuncIdxWaves = 1
507513
508514 let bFuncIdxUsdn = 2
509515
510516 let bFuncIdxReserveStart = 3
511517
512518 let bFuncIdxSupplyStart = 4
513519
514520 let bFuncIdxBRStart = 5
515521
516522 let bFuncIdxReserveEnd = 6
517523
518524 let bFuncIdxSupplyEnd = 7
519525
520526 let bFuncIdxBREnd = 8
521527
522528 let bFuncIdxRest = 9
523529
524530 let bFuncIdxWavesPrice = 10
525531
526532 func calcWithdrawW2U (wavesIn,price) = {
527533 let outAmtGross = convertWavesToNeutrino(wavesIn, price)
528534 $Tuple9(outAmtGross, neutrinoAssetId, 0, unit, 0, wavesIn, 0, 0, 0)
529535 }
530536
531537
532538 func calcWithdrawU2W (usdnIn,price,br,reservesInUsdn,usdnSupply) = {
533539 let brProtected = valueOrElse(getInteger(this, brProtectedKEY()), BRPROTECTED)
534540 let maxAllowedUsdnBeforeMinBr = if ((brProtected >= br))
535541 then 0
536542 else fraction((reservesInUsdn - fraction(brProtected, usdnSupply, PAULI)), PAULI, (PAULI - brProtected))
537543 let allowedUsdnBeforeMinBr = if ((usdnIn > maxAllowedUsdnBeforeMinBr))
538544 then maxAllowedUsdnBeforeMinBr
539545 else usdnIn
540546 let allowedUsdnAfterMinBr = if ((usdnIn > maxAllowedUsdnBeforeMinBr))
541547 then fraction((usdnIn - maxAllowedUsdnBeforeMinBr), br, PAULI)
542548 else 0
543549 let allowedUsdn = (allowedUsdnBeforeMinBr + allowedUsdnAfterMinBr)
544550 let usdn2SURF = (usdnIn - allowedUsdn)
545551 let outAmtGross = convertNeutrinoToWaves(allowedUsdn, price)
546552 $Tuple9(outAmtGross, unit, usdn2SURF, neutrinoAssetId, outAmtGross, allowedUsdn, maxAllowedUsdnBeforeMinBr, allowedUsdnBeforeMinBr, allowedUsdnAfterMinBr)
547553 }
548554
549555
550-func calcWithdraw (swapType,inAmount,price) = {
556+func calcWithdraw (swapType,inAmount,price,neutrinoMetrics) = {
551557 let outFeePart = valueOrElse(getInteger(this, outFeePartKEY(swapType)), DEFAULTSWAPFEE)
552558 if (if ((0 > outFeePart))
553559 then true
554560 else (outFeePart >= PAULI))
555561 then throw(((("invalid outFeePart config for " + swapType) + " swap: outFeePart=") + toString(outFeePart)))
556562 else {
557563 let brProtected = valueOrElse(getInteger(this, brProtectedKEY()), BRPROTECTED)
558- let neutrinoMetrics = asAnyList(invoke(mathContract, "calcNeutinoMetricsREADONLY", nil, nil))
559564 let BR = asInt(neutrinoMetrics[nMetricIdxBR])
560565 let reservesInUsdn = asInt(neutrinoMetrics[nMetricIdxReserveInUsdn])
561566 let usdnSupply = asInt(neutrinoMetrics[nMetricIdxUsdnSupply])
562567 let outDataTuple = if ((swapType == "waves"))
563568 then calcWithdrawW2U(inAmount, price)
564569 else if ((swapType == "neutrino"))
565570 then calcWithdrawU2W(inAmount, price, BR, reservesInUsdn, usdnSupply)
566571 else throw(("Unsupported swap type " + swapType))
567572 let outAmtGross = outDataTuple._1
568573 let outAssetId = outDataTuple._2
569574 let inAmtToSurfPart = outDataTuple._3
570575 let inAssetId = outDataTuple._4
571576 let unleaseAmt = outDataTuple._5
572577 let payoutsArray = applyFees(outAmtGross, inAmtToSurfPart, outFeePart)
573578 let outNetAmt = payoutsArray[IdxNetAmount]
574579 let outFeeAmt = payoutsArray[IdxFeeAmount]
575580 let outSurfAmt = if ((0 >= inAmtToSurfPart))
576581 then 0
577582 else {
578583 let surfResult = asAnyList(invoke(mathContract, "surfFunctionREADONLY", [inAmtToSurfPart, inAssetId], nil))
579584 asInt(surfResult[bFuncIdxSurf])
580585 }
581586 $Tuple7(outNetAmt, outAssetId, outSurfAmt, inAmtToSurfPart, unleaseAmt, outFeeAmt, outAmtGross)
582587 }
583588 }
584589
585590
586-func commonWithdraw (account,index,swapTxId,withdrawTxId) = {
591+func commonWithdraw (account,index,swapTxId,withdrawTxId,neutrinoMetrics) = {
587592 let userAddress = addressFromStringValue(account)
588593 let dataArray = swapDataFailOrREAD(account, swapTxId)
589594 let selfUnlockHeight = parseIntValue(dataArray[sIdxSelfUnlockHeight])
590595 let swapType = dataArray[sIdxSwapType]
591596 let inAmount = parseIntValue(dataArray[sIdxInAmount])
592597 let swapStatus = dataArray[sIdxStatus]
593598 let startHeight = parseIntValue(dataArray[sIdxStartHeight])
594599 let outFeePart = valueOrElse(getInteger(this, outFeePartKEY(swapType)), DEFAULTSWAPFEE)
595600 let totalLocked = totalLockedREAD(swapType)
596601 let totalLockedByUser = totalLockedByUserREAD(swapType, account)
597602 let unlockHeight = selfUnlockHeight
598603 let indexHeight = getHeightPriceByIndex(index)
599604 let prevIndexHeight = getHeightPriceByIndex((index - 1))
600605 let priceByIndex = getPriceHistory(indexHeight)
601606 if (isBlocked)
602607 then emergencyShutdownFAIL()
603608 else if ((swapStatus != "PENDING"))
604609 then throw("swap has been already processed")
605610 else if ((unlockHeight > height))
606611 then throw((("please wait for: " + toString(unlockHeight)) + " block height to withdraw funds"))
607612 else if (if (if ((index > priceIndex))
608613 then true
609614 else (unlockHeight > indexHeight))
610615 then true
611616 else if ((prevIndexHeight != 0))
612617 then (prevIndexHeight >= unlockHeight)
613618 else false)
614619 then priceIndexFAIL(index, priceIndex, indexHeight, unlockHeight, prevIndexHeight)
615620 else {
616- let withdrawTuple = calcWithdraw(swapType, inAmount, priceByIndex)
621+ let withdrawTuple = calcWithdraw(swapType, inAmount, priceByIndex, neutrinoMetrics)
617622 let outNetAmount = withdrawTuple._1
618623 let outAssetId = withdrawTuple._2
619624 let outSurfAmt = withdrawTuple._3
620625 let inAmtToSurfPart = withdrawTuple._4
621626 let unleaseAmt = withdrawTuple._5
622627 let outFeeAmount = withdrawTuple._6
623628 let outAmtGross = withdrawTuple._7
624629 if ((0 >= outAmtGross))
625630 then throw("balance equals zero")
626631 else {
627- let state = [IntegerEntry(totalLockedByUserKEY(swapType, account), (totalLockedByUser - inAmount)), IntegerEntry(totalLockedKEY(swapType), (totalLocked - inAmount)), ScriptTransfer(userAddress, outNetAmount, outAssetId), StringEntry(swapKEY(account, swapTxId), finishSwapDATA(dataArray, priceByIndex, outNetAmount, outFeeAmount, unlockHeight, index, withdrawTxId))]
632+ let BR = asInt(neutrinoMetrics[nMetricIdxBR])
633+ let state = [IntegerEntry(totalLockedByUserKEY(swapType, account), (totalLockedByUser - inAmount)), IntegerEntry(totalLockedKEY(swapType), (totalLocked - inAmount)), ScriptTransfer(userAddress, outNetAmount, outAssetId), StringEntry(swapKEY(account, swapTxId), finishSwapDATA(dataArray, priceByIndex, outNetAmount, outFeeAmount, unlockHeight, index, withdrawTxId, outSurfAmt, BR))]
628634 let surfCondition = if ((outSurfAmt > 0))
629635 then {
630636 let issueResult = invoke(auctionContract, "issueSurf", [outSurfAmt, account], nil)
631637 if ((issueResult == issueResult))
632638 then 0
633639 else throw("Strict value is not equal to itself.")
634640 }
635641 else 0
636642 if ((surfCondition == surfCondition))
637643 then $Tuple3(state, AttachedPayment(outAssetId, outFeeAmount), unleaseAmt)
638644 else throw("Strict value is not equal to itself.")
639645 }
640646 }
641647 }
642648
643649
644650 @Callable(i)
645651 func constructor (neutrinoAssetIdPrm,bondAssetIdPrm,auctionContractPrm,liquidationContractPrm,rpdContractPrm,nodeOracleProviderPubKeyPrm,balanceWavesLockIntervalPrm,balanceNeutrinoLockIntervalPrm,minWavesSwapAmountPrm,minNeutrinoSwapAmountPrm,neutrinoOutFeePartPrm,wavesOutFeePartPrm) = {
646652 let checkCaller = thisOnly(i)
647653 if ((checkCaller == checkCaller))
648654 then if ((size(i.payments) != 0))
649655 then throw("no payments allowed")
650656 else [StringEntry(NeutrinoAssetIdKey, neutrinoAssetIdPrm), StringEntry(BondAssetIdKey, bondAssetIdPrm), StringEntry(AuctionContractKey, auctionContractPrm), StringEntry(LiquidationContractKey, liquidationContractPrm), StringEntry(RPDContractKey, rpdContractPrm), StringEntry(NodeOracleProviderPubKeyKey, nodeOracleProviderPubKeyPrm), IntegerEntry(BalanceWavesLockIntervalKey, balanceWavesLockIntervalPrm), IntegerEntry(BalanceNeutrinoLockIntervalKey, balanceNeutrinoLockIntervalPrm), IntegerEntry(MinWavesSwapAmountKey, minWavesSwapAmountPrm), IntegerEntry(MinNeutrinoSwapAmountKey, minNeutrinoSwapAmountPrm), IntegerEntry(NeutrinoOutFeePartKey, neutrinoOutFeePartPrm), IntegerEntry(WavesOutFeePartKey, wavesOutFeePartPrm)]
651657 else throw("Strict value is not equal to itself.")
652658 }
653659
654660
655661
656662 @Callable(i)
657663 func constructorV2 (mathContract,nsbtStakingContract,swapsTimeframeBlocks) = {
658664 let checkCaller = thisOnly(i)
659665 if ((checkCaller == checkCaller))
660666 then if ((size(i.payments) != 0))
661667 then throw("no payments allowed")
662668 else [StringEntry(MathContractKey, mathContract), StringEntry(NsbtStakingContractKey, nsbtStakingContract), IntegerEntry(swapsTimeframeKEY(), swapsTimeframeBlocks)]
663669 else throw("Strict value is not equal to itself.")
664670 }
665671
666672
667673
668674 @Callable(i)
669675 func swapWavesToNeutrino () = if ((size(i.payments) != 1))
670676 then throw("swapWavesToNeutrino require only one payment")
671677 else {
672678 let pmt = value(i.payments[0])
673679 if (isDefined(pmt.assetId))
674680 then throw("Only Waves token is allowed for swapping.")
675681 else {
676682 let userAddress = toString(i.caller)
677683 let txId58 = toBase58String(i.transactionId)
678684 let swapParamsSTRUCT = asSwapParamsSTRUCT(invoke(this, "swapParamsByUserSYSREADONLY", [userAddress, 0], nil))
679685 let commonSwapResult = commonSwap("waves", pmt.amount, userAddress, txId58, swapParamsSTRUCT)
680686 commonSwapResult
681687 }
682688 }
683689
684690
685691
686692 @Callable(i)
687693 func swapNeutrinoToWaves () = if ((size(i.payments) != 1))
688694 then throw("swapNeutrinoToWaves require only one payment")
689695 else {
690696 let pmt = value(i.payments[0])
691697 if ((pmt.assetId != neutrinoAssetId))
692698 then throw("Only appropriate Neutrino tokens are allowed for swapping.")
693699 else {
694700 let userAddress = toString(i.caller)
695701 let txId58 = toBase58String(i.transactionId)
696702 let swapParamsSTRUCT = asSwapParamsSTRUCT(invoke(this, "swapParamsByUserSYSREADONLY", [userAddress, 0], nil))
697703 let commonSwapResult = commonSwap("neutrino", pmt.amount, userAddress, txId58, swapParamsSTRUCT)
698704 commonSwapResult
699705 }
700706 }
701707
702708
703709
704710 @Callable(i)
705711 func withdraw (account,index,swapTxId) = {
706712 let txId = toBase58String(i.transactionId)
707713 if ((size(i.payments) != 0))
708714 then throw("no payments allowed")
709715 else {
710- let commonTuple = commonWithdraw(account, index, swapTxId, txId)
716+ let neutrinoMetrics = asAnyList(invoke(mathContract, "calcNeutinoMetricsREADONLY", nil, nil))
717+ let BR = asInt(neutrinoMetrics[nMetricIdxBR])
718+ let commonTuple = commonWithdraw(account, index, swapTxId, txId, neutrinoMetrics)
711719 let state = commonTuple._1
712720 let fee = commonTuple._2
713721 let unleaseAmt = commonTuple._3
714722 let unleaseInvOrEmpty = invoke(this, "internalUnleaseAndLease", [unleaseAmt], nil)
715723 if ((unleaseInvOrEmpty == unleaseInvOrEmpty))
716724 then {
717725 let gnsbtData = asAnyList(invoke(gnsbtControllerContract, "gnsbtInfoSYSREADONLY", ["", 0, 0], nil))
718726 let gnsbtAmtTotal = asInt(gnsbtData[1])
719727 let gnsbtAmtFromSurfTotal = asInt(asAnyList(gnsbtData[3])[3])
720- let surfFeeAmt = if ((gnsbtAmtTotal != 0))
728+ let surfFeeAmt1 = if ((gnsbtAmtTotal != 0))
721729 then fraction(fee.amount, gnsbtAmtFromSurfTotal, gnsbtAmtTotal)
722730 else 0
731+ let surfFeeAmt2 = if ((gnsbtAmtTotal != 0))
732+ then fraction(fee.amount, (PAULI - BR), PAULI)
733+ else 0
734+ let surfFeeAmt = max([surfFeeAmt1, surfFeeAmt2])
723735 let nsbtFeeAmt = (fee.amount - surfFeeAmt)
724736 let surfDeposit = if ((surfFeeAmt > 0))
725737 then {
726738 let surfInv = invoke(surfStakingContract, "deposit", nil, [AttachedPayment(fee.assetId, surfFeeAmt)])
727739 if ((surfInv == surfInv))
728740 then nil
729741 else throw("Strict value is not equal to itself.")
730742 }
731743 else nil
732744 if ((surfDeposit == surfDeposit))
733745 then {
734746 let nsbtDeposit = if ((nsbtFeeAmt > 0))
735747 then {
736748 let nsbtInv = invoke(nsbtStakingContract, "deposit", nil, [AttachedPayment(fee.assetId, nsbtFeeAmt)])
737749 if ((nsbtInv == nsbtInv))
738750 then nil
739751 else throw("Strict value is not equal to itself.")
740752 }
741753 else nil
742754 if ((nsbtDeposit == nsbtDeposit))
743755 then state
744756 else throw("Strict value is not equal to itself.")
745757 }
746758 else throw("Strict value is not equal to itself.")
747759 }
748760 else throw("Strict value is not equal to itself.")
749761 }
750762 }
751763
752764
753765
754766 @Callable(i)
755767 func internalUnleaseAndLease (unleaseAmount) = if ((i.caller != this))
756768 then throw("internalUnleaseAndLease is not public method")
757769 else prepareUnleaseAndLease(unleaseAmount)
758770
759771
760772
761773 @Callable(i)
762774 func transferUsdnToUser (amount,addr) = if ((i.caller != auctionContract))
763775 then throw("Only auction contract is authorized")
764776 else [ScriptTransfer(addressFromStringValue(addr), amount, neutrinoAssetId)]
765777
766778
767779
768780 @Callable(i)
769781 func acceptWaves () = if ((i.caller != auctionContract))
770782 then throw("Currently only auction contract is allowed to call")
771783 else $Tuple2(prepareUnleaseAndLease(0), "success")
772784
773785
774786
775787 @Callable(i)
776-func approveLeasings (nListS,groupNum) = {
777- let lAmt = (50 * WAVELET)
788+func approveLeasings (nListS,groupNum,lAmt) = {
778789 let nIdxs = [0, 1, 2, 3, 4, 5, 6, 7]
779790 let mngPubS = valueOrElse(getString("%s%s__cfg__leasingManagerPub"), "7AUMX54ukYMYvPmma7yoFf5NjZhs4Bu5nz3Ez9EV8sur")
780791 let mngPub = fromBase58String(mngPubS)
781792 let nodeRegAddrStr = valueOrElse(getString("%s%s__cfg__nodesRegistryAddress"), "3P9vKqQKjUdmpXAfiWau8krREYAY1Xr69pE")
782793 let nodeRegAddr = addressFromStringValue(nodeRegAddrStr)
783794 let lGroupNodeListKEY = getLeaseGroupNodeListKey(groupNum)
784795 let lGrNodeOpt = getString(this, lGroupNodeListKEY)
785796 if (isDefined(lGrNodeOpt))
786797 then throw((("group " + toString(groupNum)) + " already initialized"))
787798 else {
788799 let nList = split(nListS, SEP)
789800 let expCount = size(nIdxs)
790801 if ((i.callerPublicKey != mngPub))
791802 then throw("approveLeasings not authorized")
792803 else {
793- let $t03363933701 = readNodeInfo(0)
794- let nAddr0 = $t03363933701._1
795- let lAmtKEY0 = $t03363933701._2
796- let lAmt0 = $t03363933701._3
797- let lIdKEY0 = $t03363933701._4
798- let lId0 = $t03363933701._5
799- let $t03370433766 = readNodeInfo(1)
800- let nAddr1 = $t03370433766._1
801- let lAmtKEY1 = $t03370433766._2
802- let lAmt1 = $t03370433766._3
803- let lIdKEY1 = $t03370433766._4
804- let lId1 = $t03370433766._5
805- let newL0 = Lease(nAddr0, (lAmt0 - ((lAmt * expCount) / 2)))
806- let newL1 = Lease(nAddr1, (lAmt1 - ((lAmt * expCount) / 2)))
804+ let $t03442334485 = readNodeInfo(0)
805+ let nAddr0 = $t03442334485._1
806+ let lAmtKEY0 = $t03442334485._2
807+ let lAmt0 = $t03442334485._3
808+ let lIdKEY0 = $t03442334485._4
809+ let lId0 = $t03442334485._5
810+ let newL0 = Lease(nAddr0, (lAmt0 - (lAmt * expCount)))
807811 let validation = invoke(nodeRegAddr, "validateAndApproveLeasings", [nListS], nil)
808812 if ((validation == validation))
809813 then {
810814 func forEachNodeValidateAndGenerateLease (a,i) = {
811815 let node = nList[i]
812816 let la = Lease(addressFromStringValue(node), lAmt)
813817 (a ++ [la, BinaryEntry(getLeaseIdByAddressKey(node), lcalc(la)), IntegerEntry(getLeaseAmountByAddressKey(node), lAmt)])
814818 }
815819
816- ([StringEntry(lGroupNodeListKEY, nListS), BinaryEntry(lIdKEY0, lcalc(newL0)), BinaryEntry(lIdKEY1, lcalc(newL1)), IntegerEntry(lAmtKEY0, newL0.amount), IntegerEntry(lAmtKEY1, newL1.amount), LeaseCancel(lId0), LeaseCancel(lId1), newL0, newL1] ++ {
820+ ([StringEntry(lGroupNodeListKEY, nListS), BinaryEntry(lIdKEY0, lcalc(newL0)), IntegerEntry(lAmtKEY0, newL0.amount), LeaseCancel(lId0), newL0] ++ {
817821 let $l = nIdxs
818822 let $s = size($l)
819823 let $acc0 = nil
820824 func $f0_1 ($a,$i) = if (($i >= $s))
821825 then $a
822826 else forEachNodeValidateAndGenerateLease($a, $l[$i])
823827
824828 func $f0_2 ($a,$i) = if (($i >= $s))
825829 then $a
826830 else throw("List size exceeds 8")
827831
828832 $f0_2($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($acc0, 0), 1), 2), 3), 4), 5), 6), 7), 8)
829833 })
830834 }
831835 else throw("Strict value is not equal to itself.")
832836 }
833837 }
834838 }
835839
836840
837841
838842 @Callable(i)
839843 func rebalanceLeasings (amount,groupNum) = {
840844 let nIdxs = [0, 1, 2, 3, 4, 5, 6, 7]
841845 let mngPubS = valueOrElse(getString("%s%s__cfg__leasingManagerPub"), "7AUMX54ukYMYvPmma7yoFf5NjZhs4Bu5nz3Ez9EV8sur")
842846 let mngPub = fromBase58String(mngPubS)
843847 let lGroupNodeListKEY = getLeaseGroupNodeListKey(groupNum)
844848 let nListS = getStringOrFail(this, lGroupNodeListKEY)
845849 let nList = split(nListS, SEP)
846850 if ((i.callerPublicKey != mngPub))
847851 then throw("rebalanceLeasings not authorized")
848852 else {
849853 let unleaseAmt = ((amount / size(nList)) + 1)
850- let $t03518335245 = readNodeInfo(0)
851- let nAddr0 = $t03518335245._1
852- let lAmtKEY0 = $t03518335245._2
853- let lAmt0 = $t03518335245._3
854- let lIdKEY0 = $t03518335245._4
855- let lId0 = $t03518335245._5
854+ let $t03572535787 = readNodeInfo(0)
855+ let nAddr0 = $t03572535787._1
856+ let lAmtKEY0 = $t03572535787._2
857+ let lAmt0 = $t03572535787._3
858+ let lIdKEY0 = $t03572535787._4
859+ let lId0 = $t03572535787._5
856860 let newL0 = Lease(nAddr0, (lAmt0 + (unleaseAmt * size(nList))))
857861 func forEachNodeDoUnlease (a,i) = {
858862 let node = nList[i]
859863 let lIdKEY = getLeaseIdByAddressKey(node)
860864 let lId = getBinaryValue(this, lIdKEY)
861865 let lAmtKEY = getLeaseAmountByAddressKey(node)
862866 let lAmt = getIntegerValue(this, lAmtKEY)
863867 let ula = LeaseCancel(value(lId))
864868 let la = Lease(addressFromStringValue(node), (lAmt - unleaseAmt))
865869 (a ++ [LeaseCancel(value(lId)), la, BinaryEntry(lIdKEY, lcalc(la)), IntegerEntry(lAmtKEY, la.amount)])
866870 }
867871
868872 ({
869873 let $l = nIdxs
870874 let $s = size($l)
871875 let $acc0 = nil
872876 func $f0_1 ($a,$i) = if (($i >= $s))
873877 then $a
874878 else forEachNodeDoUnlease($a, $l[$i])
875879
876880 func $f0_2 ($a,$i) = if (($i >= $s))
877881 then $a
878882 else throw("List size exceeds 8")
879883
880884 $f0_2($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($acc0, 0), 1), 2), 3), 4), 5), 6), 7), 8)
881885 } ++ [BinaryEntry(lIdKEY0, lcalc(newL0)), IntegerEntry(lAmtKEY0, newL0.amount), LeaseCancel(lId0), newL0])
882886 }
883887 }
884888
885889
886890
887891 @Callable(i)
888892 func swapParamsByUserSYSREADONLY (userAddressStr,gnsbtDiff) = {
889893 let gnsbtData = asAnyList(invoke(gnsbtControllerContract, "gnsbtInfoSYSREADONLY", [userAddressStr, 0, 0], nil))
890894 let gnsbtAmt = (asInt(gnsbtData[0]) + gnsbtDiff)
891895 let gnsbtAmtTotal = (asInt(gnsbtData[1]) + gnsbtDiff)
892896 let swapLimitData = asAnyList(invoke(mathContract, "calcSwapLimitREADONLY", [gnsbtAmt], nil))
893897 let wavesSwapLimitInUsdnMax = asInt(swapLimitData[0])
894898 let wavesSwapLimitMax = asInt(swapLimitData[1])
895899 let usdnSwapLimitMax = asInt(swapLimitData[2])
896900 let lastSwapHeight = valueOrElse(getInteger(this, keyUserLastSwapHeight(userAddressStr)), 0)
897901 let swapLimitTimelifeBlocks = swapsTimeframeREAD()
898902 let passedBlocksAfterLastSwap = (height - lastSwapHeight)
899903 let isSwapTimelifeNew = (passedBlocksAfterLastSwap >= swapLimitTimelifeBlocks)
900904 let swapLimitSpentInUsdn = if (isSwapTimelifeNew)
901905 then 0
902906 else valueOrElse(getInteger(this, keySwapUserSpentInPeriod(userAddressStr)), 0)
903907 let blcks2LmtReset = if (isSwapTimelifeNew)
904908 then 0
905909 else (swapLimitTimelifeBlocks - passedBlocksAfterLastSwap)
906910 $Tuple2(nil, $Tuple7(wavesSwapLimitInUsdnMax, swapLimitSpentInUsdn, blcks2LmtReset, gnsbtAmt, gnsbtAmtTotal, wavesSwapLimitMax, usdnSwapLimitMax))
907911 }
908912
909913
910914
911915 @Callable(i)
912-func calcWithdrawResultSYSREADONLY (swapType,inAmount,price) = $Tuple2(nil, calcWithdraw(swapType, inAmount, price))
916+func calcWithdrawResultSYSREADONLY (swapType,inAmount,price) = {
917+ let neutrinoMetrics = asAnyList(invoke(mathContract, "calcNeutinoMetricsREADONLY", nil, nil))
918+ $Tuple2(nil, calcWithdraw(swapType, inAmount, price, neutrinoMetrics))
919+ }
920+
921+
922+
923+@Callable(i)
924+func replaceCommunityNode (oldAddrStr,newAddrStr,groupNum,penaltyAmount) = {
925+ let mngPubS = valueOrElse(getString("%s%s__cfg__leasingManagerPub"), "7AUMX54ukYMYvPmma7yoFf5NjZhs4Bu5nz3Ez9EV8sur")
926+ let mngPub = fromBase58String(mngPubS)
927+ if ((i.callerPublicKey != mngPub))
928+ then throw("replaceCommunityNode not authorized")
929+ else {
930+ let groupKey = getLeaseGroupNodeListKey(groupNum)
931+ let groupNodeListS = getStringOrFail(this, groupKey)
932+ if (!(contains(groupNodeListS, oldAddrStr)))
933+ then throw(((("Group " + toString(groupNum)) + " does not contain address ") + oldAddrStr))
934+ else {
935+ let doReplace = invoke(nodeRegistryContract, "replaceApprovedNode", [oldAddrStr, newAddrStr, groupNum, penaltyAmount], nil)
936+ if ((doReplace == doReplace))
937+ then {
938+ let oldLeaseIdKey = getLeaseIdByAddressKey(oldAddrStr)
939+ let oldLeaseAmtKey = getLeaseAmountByAddressKey(oldAddrStr)
940+ let leaseAmt = getIntegerValue(oldLeaseAmtKey)
941+ let newLeaseIdKey = getLeaseIdByAddressKey(oldAddrStr)
942+ let newLeaseAmtKey = getLeaseAmountByAddressKey(oldAddrStr)
943+ let newLease = Lease(addressFromStringValue(newAddrStr), leaseAmt)
944+ let updatedGroupNodeListS = makeString(split(groupNodeListS, oldAddrStr), newAddrStr)
945+ $Tuple2([LeaseCancel(getBinaryValue(oldLeaseIdKey)), DeleteEntry(oldLeaseIdKey), DeleteEntry(oldLeaseAmtKey), StringEntry(groupKey, updatedGroupNodeListS), newLease, BinaryEntry(newLeaseIdKey, lcalc(newLease)), IntegerEntry(newLeaseAmtKey, leaseAmt)], unit)
946+ }
947+ else throw("Strict value is not equal to itself.")
948+ }
949+ }
950+ }
913951
914952
915953
916954 @Callable(i)
917955 func updateReservesAndNeutrinoSupply () = {
918956 func getNumberByKeyInternal (key) = match getInteger(this, key) {
919957 case a: Int =>
920958 a
921959 case _ =>
922960 0
923961 }
924962
925963 let nMetrix = asAnyList(invoke(mathContract, "calcNeutinoMetricsREADONLY", nil, nil))
926964 let idx = getNumberByKeyInternal("updateReservesAndNeutrinoSupplyIdx")
927965 let newIdx = (idx + 1)
928966 [IntegerEntry("updateReservesAndNeutrinoSupplyIdx", newIdx), IntegerEntry("reserve", asInt(nMetrix[3])), IntegerEntry("neutrinoSupply", asInt(nMetrix[5])), IntegerEntry("reservesInUsdn", convertWavesToNeutrino(asInt(nMetrix[3]), asInt(nMetrix[0]))), IntegerEntry("surplus", asInt(nMetrix[6])), IntegerEntry("deficit", -(asInt(nMetrix[6])))]
929967 }
930968
931969
932970
933971 @Callable(i)
934972 func wavesBalancesVsPayment () = {
935973 let b = wavesBalance(this)
936974 [IntegerEntry("wavesBalance_available", b.available), IntegerEntry("wavesBalance_regular", b.regular), IntegerEntry("wavesBalance_generating", b.generating), IntegerEntry("wavesBalance_effective", b.effective), IntegerEntry("waves_payment", value(i.payments[0]).amount)]
937975 }
938976
939977
940978 @Verifier(tx)
941979 func verify () = {
942980 let id = toBase58String(tx.id)
943981 let pubKeyAdminsListStr = makeString(["ExtEEK19nmKj9mCpnWyvEEJFYATLMcVEMvohhUHkyHNm", "Ev5py5FfBQX9cZpYKnfQrTB49Byf8QmpZWeDVRim4yV7", "DUuuLjXu98nBwZc7fqwCTjtA3nnRwgTbkMSr5SU2NmDR", "DUuuLjXu98nBwZc7fqwCTjtA3nnRwgTbkMSr5SU2NmDR"], SEP)
944982 let pubKeyAdminsList = split(valueOrElse(getString(controlContract, "%s__multisig"), pubKeyAdminsListStr), SEP)
945983 let count = ((((if (sigVerify(tx.bodyBytes, tx.proofs[0], fromBase58String(pubKeyAdminsList[0])))
946984 then 1
947985 else 0) + (if (sigVerify(tx.bodyBytes, tx.proofs[1], fromBase58String(pubKeyAdminsList[1])))
948986 then 1
949987 else 0)) + (if (sigVerify(tx.bodyBytes, tx.proofs[2], fromBase58String(pubKeyAdminsList[2])))
950988 then 1
951989 else 0)) + (if (sigVerify(tx.bodyBytes, tx.proofs[3], fromBase58String(pubKeyAdminsList[3])))
952990 then 2
953991 else 0))
954992 match tx {
955993 case sponsorTx: SponsorFeeTransaction =>
956994 if (checkIsValidMinSponsoredFee(sponsorTx))
957995 then (count >= 3)
958996 else false
959997 case _ =>
960998 (count >= 3)
961999 }
9621000 }
9631001

github/deemru/w8io/026f985 
111.06 ms