Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix unit tests and Array<Never> related bugs #17

Merged
merged 8 commits into from
Mar 26, 2024
Merged
Show file tree
Hide file tree
Changes from 6 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,4 @@
/Packages
/*.xcodeproj
xcuserdata/
/.swiftpm
12 changes: 0 additions & 12 deletions Sources/EOSIO/ABICodable.swift
Original file line number Diff line number Diff line change
Expand Up @@ -164,18 +164,6 @@ public struct BinaryExtension<Value: ABICodable>: ABICodable {
extension BinaryExtension: Equatable where Value: Equatable {}
extension BinaryExtension: Hashable where Value: Hashable {}

extension Never: ABICodable {
public init(from decoder: Decoder) throws {
let ctx = DecodingError.Context(codingPath: decoder.codingPath, debugDescription: "Attempted to decode Never")
throw DecodingError.dataCorrupted(ctx)
}

public func encode(to encoder: Encoder) throws {
let ctx = EncodingError.Context(codingPath: encoder.codingPath, debugDescription: "Attempted to encode Never")
throw EncodingError.invalidValue(self, ctx)
}
}

// MARK: Dynamic ABI Coding

public extension CodingUserInfoKey {
Expand Down
13 changes: 1 addition & 12 deletions Sources/EOSIO/ABIDecoder.swift
Original file line number Diff line number Diff line change
Expand Up @@ -108,19 +108,8 @@ public extension ABIDecoder {
return Int(try self.readVarint()) as! T
case is UInt.Type:
return UInt(try self.readVaruint()) as! T
case is Array<Never>.Type:
return [] as! T
case let abiType as ABIDecodable.Type:
let decodedAbiType = try abiType.init(fromAbi: self)

// Instead of forcefully casting, verify the type at runtime.
if let result = decodedAbiType as? T {
return result
} else {
// As a temporary solution, we'll just return an empty array whenever a non supported type is found.
// This is not ideal, but it's better than crashing the app.
return [] as! T
}
return try abiType.init(fromAbi: self) as! T
default:
throw Error.typeNotConformingToABIDecodable(type)
}
Expand Down
1 change: 1 addition & 0 deletions Sources/EOSIO/API/Client.swift
Original file line number Diff line number Diff line change
Expand Up @@ -251,6 +251,7 @@ extension Client {
encoder.dataEncodingStrategy = self.dataEncoder
encoder.dateEncodingStrategy = self.dateEncoder
encoder.keyEncodingStrategy = .convertToSnakeCase
encoder.outputFormatting = .sortedKeys
return encoder
}
}
Expand Down
11 changes: 8 additions & 3 deletions Sources/EOSIO/Chain/ABI.swift
Original file line number Diff line number Diff line change
Expand Up @@ -307,6 +307,11 @@ public extension ABI {
let errorCode: UInt64
let errorMsg: String
}

private struct ExtensionsEntry: ABICodable, Equatable, Hashable {
let errorCode: UInt16
let errorMsg: Data
}
}

// MARK: ABI Coding
Expand Down Expand Up @@ -345,7 +350,7 @@ extension ABI: ABICodable {
self.tables = try decoder.decode([ABI.Table].self)
self.ricardianClauses = try decoder.decode([ABI.Clause].self)
_ = try decoder.decode([ABI.ErrorMessage].self) // ignore error messages, used only by abi compiler
_ = try decoder.decode([Never].self) // abi extensions not used
_ = try decoder.decode([ABI.ExtensionsEntry].self) // abi extensions not used
// decode variant typedefs (Y U NO USE EXTENSIONS?!)
do {
self.variants = try decoder.decode([ABI.Variant].self)
Expand All @@ -362,8 +367,8 @@ extension ABI: ABICodable {
try container.encode(self.actions, forKey: .actions)
try container.encode(self.tables, forKey: .tables)
try container.encode(self.ricardianClauses, forKey: .ricardianClauses)
try container.encode([] as [Never], forKey: .errorMessages)
try container.encode([] as [Never], forKey: .abiExtensions)
try container.encode([] as [ABI.ErrorMessage], forKey: .errorMessages)
try container.encode([] as [ABI.ExtensionsEntry], forKey: .abiExtensions)
try container.encode(self.variants, forKey: .variants)
}
}
Expand Down
2 changes: 1 addition & 1 deletion Sources/EOSIO/SigningRequest.swift
Original file line number Diff line number Diff line change
Expand Up @@ -1078,7 +1078,7 @@ public enum ChainName: UInt8, CaseIterable, CustomStringConvertible {
case .telos:
return "4667b205c6838ef70ff7988f6e8257e8be0e1284a2f59699054a018f743b1d11"
case .jungle:
return "e70aaab8997e1dfce58fbfac80cbbb8fecec7b99cf982a9444273cbc64c41473"
return "73e4385a2708e6d7048834fbc1079f2fabb17b3c125b146af438971e90716c4d"
case .kylin:
return "5fff1dae8dc8e2fc4d5b23b2c7665c97f9e9d8edf2b6485a86ba311c25639191"
case .worbli:
Expand Down
18 changes: 9 additions & 9 deletions Tests/EOSIOTests/API.swift
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ var mockSession = MockSession(
resourcePath.appendingPathComponent("API", isDirectory: true),
mode: env["MOCK_RECORD"] != nil ? .record : .replay
)
let nodeAddress = URL(string: "https://jungle3.greymass.com")! // only used when recording
let nodeAddress = URL(string: "https://jungle4.greymass.com")! // only used when recording
let client = Client(address: nodeAddress, session: mockSession)

final class APITests: XCTestCase {
Expand All @@ -39,7 +39,7 @@ final class APITests: XCTestCase {
let req = API.V1.Chain.GetTableRows<CurrencyStats>(
code: "eosio.token",
table: "stat",
scope: Asset.Symbol("4,EOS").symbolCode
scope: Asset.Symbol("4,EOS").name
)
let res = try? client.sendSync(req).get()
XCTAssertGreaterThan(res?.rows.first?.supply ?? "0.0000 EOS", "1000000000.0000 EOS")
Expand All @@ -50,7 +50,7 @@ final class APITests: XCTestCase {
func testGetInfo() {
let req = API.V1.Chain.GetInfo()
let res = try? client.sendSync(req).get()
XCTAssertEqual(res?.chainId, "e70aaab8997e1dfce58fbfac80cbbb8fecec7b99cf982a9444273cbc64c41473")
XCTAssertEqual(res?.chainId, "73e4385a2708e6d7048834fbc1079f2fabb17b3c125b146af438971e90716c4d")
}

func testGetRawAbi() {
Expand Down Expand Up @@ -98,24 +98,24 @@ final class APITests: XCTestCase {
let res = try! client.sendSync(req).get()

XCTAssertEqual(res.transactionId, transaction.id)
XCTAssertEqual(res.processed["blockNum"] as! Int, 60_423_261)
XCTAssertEqual(res.processed["blockNum"] as! Int, 129_978_519)
}

func testGetAccount() {
let req = API.V1.Chain.GetAccount("eosio")
let res = try! client.sendSync(req).get()
XCTAssertEqual(res.accountName, "eosio")
XCTAssertEqual(res.cpuLimit.used, -1)
XCTAssertEqual(res.cpuLimit.used, 149300)
XCTAssertEqual(res.voterInfo?.proxy, 0)
XCTAssertEqual(res.voterInfo?.producers.count, 0)
}

func testGetAccountsByAuthorizersUsingKey() {
let pubkey = PublicKey("EOS8X5SC2m6Q1iBpvP91mLBNpEu9LYuynC44os35n5RKaAVt9n7Ji")
let pubkey = PublicKey("EOS8aL4dzqLudQQbcNZYVeyuHfjE7K76BMNGRRT8hwyURPPapDt4h")
let req = API.V1.Chain.GetAccountsByAuthorizers(keys: [pubkey])
let res = try! client.sendSync(req).get()
XCTAssertEqual(res.accounts.first?.accountName, "jestasmobile")
XCTAssertEqual(res.accounts.first?.permissionName, "owner")
XCTAssertEqual(res.accounts.first?.accountName, "iamthewalrus")
XCTAssertEqual(res.accounts.first?.permissionName, "active")
XCTAssertEqual(res.accounts.first?.authorizingKey, pubkey)
XCTAssertEqual(res.accounts.first?.threshold, 1)
XCTAssertEqual(res.accounts.first?.weight, 1)
Expand Down Expand Up @@ -176,7 +176,7 @@ final class APITests: XCTestCase {
)
let req = API.V1.Chain.GetAccount("teamgreymass")
let res = try! client.sendSync(req).get()
XCTAssertEqual(res.netWeight, 432_714_455_333)
XCTAssertEqual(res.netWeight, 455_096_542_392)
XCTAssert(res.netWeight > 0xFFFFFF)
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1 +1 @@
{"data":"eyJhY2NvdW50X25hbWUiOiJ0ZWFtZ3JleW1hc3MiLCJoZWFkX2Jsb2NrX251bSI6NTk0OTQ2OTksImhlYWRfYmxvY2tfdGltZSI6IjIwMjAtMDYtMDNUMDk6MTk6MDQuNTAwIiwicHJpdmlsZWdlZCI6ZmFsc2UsImxhc3RfY29kZV91cGRhdGUiOiIxOTcwLTAxLTAxVDAwOjAwOjAwLjAwMCIsImNyZWF0ZWQiOiIyMDE5LTA3LTEyVDA1OjE4OjA3LjAwMCIsImNvcmVfbGlxdWlkX2JhbGFuY2UiOiI1NzU1NzYuOTYwODg2MzMgV0FYIiwicmFtX3F1b3RhIjoxMjY4MywibmV0X3dlaWdodCI6IjQzMjcxNDQ1NTMzMyIsImNwdV93ZWlnaHQiOiI0MzI4MTQ0NTUzMzYiLCJuZXRfbGltaXQiOnsidXNlZCI6MjQ3LCJhdmFpbGFibGUiOjkzODk1OTYzOCwibWF4Ijo5Mzg5NTk4ODV9LCJjcHVfbGltaXQiOnsidXNlZCI6MTQ4NSwiYXZhaWxhYmxlIjoxNjUxNjY5NDksIm1heCI6MTY1MTY4NDM0fSwicmFtX3VzYWdlIjo4NDg4LCJwZXJtaXNzaW9ucyI6W3sicGVybV9uYW1lIjoiYWN0aXZlIiwicGFyZW50Ijoib3duZXIiLCJyZXF1aXJlZF9hdXRoIjp7InRocmVzaG9sZCI6MSwia2V5cyI6W3sia2V5IjoiRU9TOEttaHlnVHJydnRXN3pKZDZIWFdyTnFBNVdYOU56U2NaMzdKeVhSaXdwaUpOMmcyclIiLCJ3ZWlnaHQiOjF9XSwiYWNjb3VudHMiOltdLCJ3YWl0cyI6W119fSx7InBlcm1fbmFtZSI6ImNsYWltIiwicGFyZW50IjoiYWN0aXZlIiwicmVxdWlyZWRfYXV0aCI6eyJ0aHJlc2hvbGQiOjEsImtleXMiOlt7ImtleSI6IkVPUzZETEQ5SHhNY3duNzNVNDFqamRHc05lOXZERlJLQjI2dW02cVRBcXJ0WWNKRnRFRDRDIiwid2VpZ2h0IjoxfV0sImFjY291bnRzIjpbXSwid2FpdHMiOltdfX0seyJwZXJtX25hbWUiOiJmYWlsb3ZlciIsInBhcmVudCI6ImFjdGl2ZSIsInJlcXVpcmVkX2F1dGgiOnsidGhyZXNob2xkIjoxLCJrZXlzIjpbeyJrZXkiOiJFT1M4Tkt5V1ZTZmJmbXlVOTh5NkFmdko4UWZ3YnROS0FnZm5aOUJiV2QzVXZRek1IaEpZNiIsIndlaWdodCI6MX1dLCJhY2NvdW50cyI6W10sIndhaXRzIjpbXX19LHsicGVybV9uYW1lIjoib3duZXIiLCJwYXJlbnQiOiIiLCJyZXF1aXJlZF9hdXRoIjp7InRocmVzaG9sZCI6MSwia2V5cyI6W3sia2V5IjoiRU9TNzZUUDhNNDhzUkJHZFBtc0t5eTNxQU1DWWdCTnN3amFXYVhHUjRqa1M1SHJvMTZraHIiLCJ3ZWlnaHQiOjF9XSwiYWNjb3VudHMiOltdLCJ3YWl0cyI6W119fSx7InBlcm1fbmFtZSI6InByb2R1Y2VyanNvbiIsInBhcmVudCI6ImFjdGl2ZSIsInJlcXVpcmVkX2F1dGgiOnsidGhyZXNob2xkIjoxLCJrZXlzIjpbeyJrZXkiOiJFT1M1SkNFY2lVZGZYblFtVHlqODVUOThiWFRBWloxZzdObWFqc2V1N1pXQjhEckRhNkV0cCIsIndlaWdodCI6MX1dLCJhY2NvdW50cyI6W10sIndhaXRzIjpbXX19XSwidG90YWxfcmVzb3VyY2VzIjp7Im93bmVyIjoidGVhbWdyZXltYXNzIiwibmV0X3dlaWdodCI6IjQzMjcuMTQ0NTUzMzMgV0FYIiwiY3B1X3dlaWdodCI6IjQzMjguMTQ0NTUzMzYgV0FYIiwicmFtX2J5dGVzIjoxMTI4M30sInNlbGZfZGVsZWdhdGVkX2JhbmR3aWR0aCI6eyJmcm9tIjoidGVhbWdyZXltYXNzIiwidG8iOiJ0ZWFtZ3JleW1hc3MiLCJuZXRfd2VpZ2h0IjoiNDMyNy4xNDQ1NTMzMyBXQVgiLCJjcHVfd2VpZ2h0IjoiNDMyOC4xNDQ1NTMzNiBXQVgifSwicmVmdW5kX3JlcXVlc3QiOm51bGwsInZvdGVyX2luZm8iOnsib3duZXIiOiJ0ZWFtZ3JleW1hc3MiLCJwcm94eSI6IiIsInByb2R1Y2VycyI6WyJhbG9oYWVvc3Byb2QiLCJhbXN0ZXJkYW13YXgiLCJjcnlwdG9saW9uczEiLCJjeXBoZXJnbGFzc3MiLCJkbWFpbGRvdGNvYnAiLCJlb3M0MmZyZWVkb20iLCJlb3NhdXRob3JpdHkiLCJlb3NiYXJjZWxvbmEiLCJlb3NkYWNzZXJ2ZXIiLCJlb3NkdWJsaW53b3ciLCJlb3Npb2RldHJvaXQiLCJlb3NwaGVyZWlvYnAiLCJlb3NyaW9icmF6aWwiLCJoa2Vvc2d1aWxkaGsiLCJpdm90ZTR3YXh1c2EiLCJuYXRpb24ud2F4IiwicGluay5nZyIsInRlYW1ncmV5bWFzcyIsIndheGNhZmVibG9jayIsIndheHN3ZWRlbm9yZyIsInplbmJsb2Nrc3dheCJdLCJzdGFrZWQiOiI4NjU1Mjg5MTA2NjkiLCJ1bnBhaWRfdm90ZXNoYXJlIjoiMC4wMDAwMDAwMDAwMDAwMDAwMCIsInVucGFpZF92b3Rlc2hhcmVfbGFzdF91cGRhdGVkIjoiMjAyMC0wNS0wNVQwNDo0MzowMC4wMDAiLCJ1bnBhaWRfdm90ZXNoYXJlX2NoYW5nZV9yYXRlIjoiMzIwNTk3NzM5NDM1NDI2MzM2Njc3MTE3OTE0NjM4ODE3Njg5Ni4wMDAwMDAwMDAwMDAwMDAwMCIsImxhc3RfY2xhaW1fdGltZSI6IjIwMjAtMDUtMDVUMDQ6NDM6MDAuMDAwIiwibGFzdF92b3RlX3dlaWdodCI6IjMyMDU5NzczOTQzNTQyNjMzNjY3NzExNzkxNDYzODgxNzY4OTYuMDAwMDAwMDAwMDAwMDAwMDAiLCJwcm94aWVkX3ZvdGVfd2VpZ2h0IjoiMC4wMDAwMDAwMDAwMDAwMDAwMCIsImlzX3Byb3h5IjowLCJmbGFnczEiOjAsInJlc2VydmVkMiI6MCwicmVzZXJ2ZWQzIjoiMCAifX0=","response":{"url":"https:\/\/wax.greymass.com\/v1\/chain\/get_account","status":200,"headers":{"Server":"nginx","access-control-allow-methods":"GET, POST, OPTIONS","Access-Control-Allow-Origin":"*","Content-Type":"application\/json","Date":"Wed, 03 Jun 2020 09:19:05 GMT","Host":"wax.greymass.com","Content-Length":"2477","access-control-allow-headers":"X-Requested-With,Accept,Content-Type,Origin"}}}
{"response":{"status":200,"url":"https:\/\/wax.greymass.com\/v1\/chain\/get_account","headers":{"Content-Type":"application\/json","Host":"wax.greymass.com","Content-Length":"4113","access-control-allow-headers":"X-Requested-With,Accept,Content-Type,Origin","Access-Control-Allow-Origin":"*","access-control-allow-methods":"GET, POST, OPTIONS","Server":"nginx","x-cached":"MISS","Date":"Mon, 18 Mar 2024 11:34:46 GMT"}},"data":"eyJhY2NvdW50X25hbWUiOiJ0ZWFtZ3JleW1hc3MiLCJoZWFkX2Jsb2NrX251bSI6Mjk4NTc2OTY3LCJoZWFkX2Jsb2NrX3RpbWUiOiIyMDI0LTAzLTE4VDExOjM0OjQ3LjAwMCIsInByaXZpbGVnZWQiOmZhbHNlLCJsYXN0X2NvZGVfdXBkYXRlIjoiMTk3MC0wMS0wMVQwMDowMDowMC4wMDAiLCJjcmVhdGVkIjoiMjAxOS0wNy0xMlQwNToxODowNy4wMDAiLCJjb3JlX2xpcXVpZF9iYWxhbmNlIjoiMjg2NzIxNC43ODYzODk1NSBXQVgiLCJyYW1fcXVvdGEiOjc0MDk3MywibmV0X3dlaWdodCI6IjQ1NTA5NjU0MjM5MiIsImNwdV93ZWlnaHQiOiIyNTU1MTk2NTQyNTk0IiwibmV0X2xpbWl0Ijp7InVzZWQiOjI2MjQxOSwiYXZhaWxhYmxlIjo1NzA0NzQ3NDcsIm1heCI6NTcwNzM3MTY2LCJsYXN0X3VzYWdlX3VwZGF0ZV90aW1lIjoiMjAyNC0wMy0xOFQxMTozNDoyOC4wMDAiLCJjdXJyZW50X3VzZWQiOjI2MjM2Mn0sImNwdV9saW1pdCI6eyJ1c2VkIjo2OTQ3MDAsImF2YWlsYWJsZSI6MTI1OTk2MywibWF4IjoxOTU0NjYzLCJsYXN0X3VzYWdlX3VwZGF0ZV90aW1lIjoiMjAyNC0wMy0xOFQxMTozNDoyOC4wMDAiLCJjdXJyZW50X3VzZWQiOjY5NDU0N30sInJhbV91c2FnZSI6MTI2MzUsInBlcm1pc3Npb25zIjpbeyJwZXJtX25hbWUiOiJhY3RpdmUiLCJwYXJlbnQiOiJvd25lciIsInJlcXVpcmVkX2F1dGgiOnsidGhyZXNob2xkIjoxLCJrZXlzIjpbeyJrZXkiOiJFT1M4S21oeWdUcnJ2dFc3ekpkNkhYV3JOcUE1V1g5TnpTY1ozN0p5WFJpd3BpSk4yZzJyUiIsIndlaWdodCI6MX1dLCJhY2NvdW50cyI6W10sIndhaXRzIjpbXX0sImxpbmtlZF9hY3Rpb25zIjpbXX0seyJwZXJtX25hbWUiOiJjbGFpbSIsInBhcmVudCI6ImFjdGl2ZSIsInJlcXVpcmVkX2F1dGgiOnsidGhyZXNob2xkIjoxLCJrZXlzIjpbeyJrZXkiOiJFT1M2RExEOUh4TWN3bjczVTQxampkR3NOZTl2REZSS0IyNnVtNnFUQXFydFljSkZ0RUQ0QyIsIndlaWdodCI6MX1dLCJhY2NvdW50cyI6W10sIndhaXRzIjpbXX0sImxpbmtlZF9hY3Rpb25zIjpbeyJhY2NvdW50IjoiZW9zaW8iLCJhY3Rpb24iOiJjbGFpbXJld2FyZHMifSx7ImFjY291bnQiOiJlb3NpbyIsImFjdGlvbiI6ImNsYWltZ2VuZXNpcyJ9LHsiYWNjb3VudCI6ImVvc2lvIiwiYWN0aW9uIjoiY2xhaW1nYm12b3RlIn0seyJhY2NvdW50IjoiZW9zaW8iLCJhY3Rpb24iOiJjbGFpbWdibXByb2QifV19LHsicGVybV9uYW1lIjoiZmFpbG92ZXIiLCJwYXJlbnQiOiJhY3RpdmUiLCJyZXF1aXJlZF9hdXRoIjp7InRocmVzaG9sZCI6MSwia2V5cyI6W3sia2V5IjoiRU9TOE5LeVdWU2ZiZm15VTk4eTZBZnZKOFFmd2J0TktBZ2ZuWjlCYldkM1V2UXpNSGhKWTYiLCJ3ZWlnaHQiOjF9XSwiYWNjb3VudHMiOltdLCJ3YWl0cyI6W119LCJsaW5rZWRfYWN0aW9ucyI6W3siYWNjb3VudCI6ImVvc2lvIiwiYWN0aW9uIjoicmVncHJvZHVjZXIifV19LHsicGVybV9uYW1lIjoia2lsbHN3aXRjaCIsInBhcmVudCI6ImFjdGl2ZSIsInJlcXVpcmVkX2F1dGgiOnsidGhyZXNob2xkIjoxLCJrZXlzIjpbeyJrZXkiOiJFT1M3Q2pDN0dMNzFtc1B6QXVBemQyV3dpQkVBelRjUEw0N0FDcmpTdWlObW5uR0d1ZllTbiIsIndlaWdodCI6MX1dLCJhY2NvdW50cyI6W10sIndhaXRzIjpbXX0sImxpbmtlZF9hY3Rpb25zIjpbeyJhY2NvdW50IjoiZW9zaW8iLCJhY3Rpb24iOiJ1bnJlZ3Byb2QifV19LHsicGVybV9uYW1lIjoib3JhY2xlIiwicGFyZW50IjoiYWN0aXZlIiwicmVxdWlyZWRfYXV0aCI6eyJ0aHJlc2hvbGQiOjEsImtleXMiOlt7ImtleSI6IkVPUzg4VnFtRG1KSjlTMjNlTnFkZVdZZjJ6eVN4djNja1FyV0JLeTdFdlZSQ1V1aFNVNGYzIiwid2VpZ2h0IjoxfV0sImFjY291bnRzIjpbXSwid2FpdHMiOltdfSwibGlua2VkX2FjdGlvbnMiOlt7ImFjY291bnQiOiJkZWxwaGlvcmFjbGUiLCJhY3Rpb24iOiJ3cml0ZSJ9XX0seyJwZXJtX25hbWUiOiJvd25lciIsInBhcmVudCI6IiIsInJlcXVpcmVkX2F1dGgiOnsidGhyZXNob2xkIjoxLCJrZXlzIjpbeyJrZXkiOiJFT1M3NlRQOE00OHNSQkdkUG1zS3l5M3FBTUNZZ0JOc3dqYVdhWEdSNGprUzVIcm8xNmtociIsIndlaWdodCI6MX1dLCJhY2NvdW50cyI6W10sIndhaXRzIjpbXX0sImxpbmtlZF9hY3Rpb25zIjpbXX0seyJwZXJtX25hbWUiOiJwcm9kdWNlcmpzb24iLCJwYXJlbnQiOiJhY3RpdmUiLCJyZXF1aXJlZF9hdXRoIjp7InRocmVzaG9sZCI6MSwia2V5cyI6W3sia2V5IjoiRU9TNUpDRWNpVWRmWG5RbVR5ajg1VDk4YlhUQVpaMWc3Tm1hanNldTdaV0I4RHJEYTZFdHAiLCJ3ZWlnaHQiOjF9XSwiYWNjb3VudHMiOltdLCJ3YWl0cyI6W119LCJsaW5rZWRfYWN0aW9ucyI6W3siYWNjb3VudCI6InByb2R1Y2VyanNvbiIsImFjdGlvbiI6InNldCJ9XX0seyJwZXJtX25hbWUiOiJ0cmFuc2ZlciIsInBhcmVudCI6ImFjdGl2ZSIsInJlcXVpcmVkX2F1dGgiOnsidGhyZXNob2xkIjoxLCJrZXlzIjpbeyJrZXkiOiJFT1M2QWtaWjVZWjZHNWVDUUdKQkFQYmttb3VFYWlTS0ZrZE0yODl3RU1LY2Yycm54N21yYiIsIndlaWdodCI6MX0seyJrZXkiOiJFT1M2UldaMUNtREw0QjZMZGl4dWVydG56eGNSdVVEYWMzTlFzcEpFdk1uZWJHY1V3aHZmWCIsIndlaWdodCI6MX1dLCJhY2NvdW50cyI6W10sIndhaXRzIjpbXX0sImxpbmtlZF9hY3Rpb25zIjpbeyJhY2NvdW50IjoiZW9zaW8udG9rZW4iLCJhY3Rpb24iOiJ0cmFuc2ZlciJ9XX1dLCJ0b3RhbF9yZXNvdXJjZXMiOnsib3duZXIiOiJ0ZWFtZ3JleW1hc3MiLCJuZXRfd2VpZ2h0IjoiNDU1MC45NjU0MjM5MiBXQVgiLCJjcHVfd2VpZ2h0IjoiMjU1NTEuOTY1NDI1OTQgV0FYIiwicmFtX2J5dGVzIjo3Mzk1NzN9LCJzZWxmX2RlbGVnYXRlZF9iYW5kd2lkdGgiOnsiZnJvbSI6InRlYW1ncmV5bWFzcyIsInRvIjoidGVhbWdyZXltYXNzIiwibmV0X3dlaWdodCI6IjQ1NTAuOTY1NDIzOTIgV0FYIiwiY3B1X3dlaWdodCI6IjI1NTUxLjk2NTQyNTk0IFdBWCJ9LCJyZWZ1bmRfcmVxdWVzdCI6bnVsbCwidm90ZXJfaW5mbyI6eyJvd25lciI6InRlYW1ncmV5bWFzcyIsInByb3h5IjoiIiwicHJvZHVjZXJzIjpbIjNka3JlbmRlcndheCIsImFsb2hhZW9zcHJvZCIsImFtc3RlcmRhbXdheCIsImJsYWNrbHVzaW9ueCIsImJsb2tjcmFmdGVycyIsImJvdW50eWJsb2ticCIsImJwLmJveCIsImJwLndlY2FuIiwiY3J5cHRvbGlvbnMxIiwiZGFwcGxpY2EiLCJlb3NhdXRob3JpdHkiLCJlb3NkYWNzZXJ2ZXIiLCJlb3NkdWJsaW53b3ciLCJlb3Npb2RldHJvaXQiLCJlb3NwaGVyZWlvYnAiLCJlb3NyaW9icmF6aWwiLCJncmVlbmVvc2lvYnAiLCJndWlsZC5uZWZ0eSIsImhrZW9zZ3VpbGRoayIsIml2b3RlNHdheHVzYSIsImxlZGdlcndpc2VpbyIsImxpcXVpZHN0dWRpbyIsIm5hdGlvbi53YXgiLCJwaW5rLmdnIiwic2VudG5sYWdlbnRzIiwidGVhbWdyZXltYXNzIiwidG9rZW5nYW1lcmlvIiwid2F4LmVhc3Rlcm4iLCJ3YXhoaXZlZ3VpbGQiLCJ3YXhzd2VkZW5vcmciXSwic3Rha2VkIjoiNTQwMjkwOTMwODQ5ODYiLCJ1bnBhaWRfdm90ZXNoYXJlIjoiMC4wMDAwMDAwMDAwMDAwMDAwMCIsInVucGFpZF92b3Rlc2hhcmVfbGFzdF91cGRhdGVkIjoiMjAyNC0wMy0xN1QxOTo0MzowMi41MDAiLCJ1bnBhaWRfdm90ZXNoYXJlX2NoYW5nZV9yYXRlIjoiNTAyMzE0NTA4MjE2MjYwNDc2MjE1MDYxOTA2MjcyMjM0ODIyNTM5NjczNi4wMDAwMDAwMDAwMDAwMDAwMCIsImxhc3RfY2xhaW1fdGltZSI6IjIwMjQtMDMtMTdUMTk6NDM6MDIuNTAwIiwibGFzdF92b3RlX3dlaWdodCI6IjUwMjMxNDUwODIxNjI2MDQ3NjIxNTA2MTkwNjI3MjIzNDgyMjUzOTY3MzYuMDAwMDAwMDAwMDAwMDAwMDAiLCJwcm94aWVkX3ZvdGVfd2VpZ2h0IjoiMC4wMDAwMDAwMDAwMDAwMDAwMCIsImlzX3Byb3h5IjowLCJmbGFnczEiOjAsInJlc2VydmVkMiI6MCwicmVzZXJ2ZWQzIjoiMCAifSwicmV4X2luZm8iOm51bGwsInN1YmplY3RpdmVfY3B1X2JpbGxfbGltaXQiOnsidXNlZCI6MCwiYXZhaWxhYmxlIjowLCJtYXgiOjAsImxhc3RfdXNhZ2VfdXBkYXRlX3RpbWUiOiIyMDAwLTAxLTAxVDAwOjAwOjAwLjAwMCIsImN1cnJlbnRfdXNlZCI6MH0sImVvc2lvX2FueV9saW5rZWRfYWN0aW9ucyI6W119"}
Loading