diff --git a/package-lock.json b/package-lock.json index c4f787f..863d3ea 100644 --- a/package-lock.json +++ b/package-lock.json @@ -9,8 +9,8 @@ "version": "1.0.0", "hasInstallScript": true, "dependencies": { - "@algorandfoundation/algorand-typescript": "^0.0.1-alpha.24", - "@algorandfoundation/puya-ts": "^1.0.0-alpha.36", + "@algorandfoundation/algorand-typescript": "^1.0.0-beta.4", + "@algorandfoundation/puya-ts": "^1.0.0-beta.6", "elliptic": "^6.5.7", "js-sha256": "^0.11.0", "js-sha3": "^0.9.3", @@ -73,22 +73,23 @@ } }, "node_modules/@algorandfoundation/algorand-typescript": { - "version": "0.0.1-alpha.24", - "resolved": "https://registry.npmjs.org/@algorandfoundation/algorand-typescript/-/algorand-typescript-0.0.1-alpha.24.tgz", - "integrity": "sha512-aAuIRrTmnprfquxY7ZNrlBmnH6SyCGHUOKrC5L+K5AKduCgWS3S4I2e9CRBZlSpdMKBZ5Ek97Ufm5ZJHvs1I+g==", + "version": "1.0.0-beta.4", + "resolved": "https://registry.npmjs.org/@algorandfoundation/algorand-typescript/-/algorand-typescript-1.0.0-beta.4.tgz", + "integrity": "sha512-vMCPeXqFuS1/ChQ8SZAdUHG1gvLFoJAxukY3yp0AjRLTJ5PTEwTVvbgEWcnqDhEi8Y+lmch1yTvGPEKC3o/Ipg==", "peerDependencies": { "tslib": "^2.6.2" } }, "node_modules/@algorandfoundation/puya-ts": { - "version": "1.0.0-alpha.36", - "resolved": "https://registry.npmjs.org/@algorandfoundation/puya-ts/-/puya-ts-1.0.0-alpha.36.tgz", - "integrity": "sha512-HHjRTvVMK3/9Oa1YRcKg/d1t9bsTnU3EdhF3rJyRSLOBDl87U5g3MUYgUuxzTbFDfUgqYNKfftL6m75EVpQ0og==", + "version": "1.0.0-beta.6", + "resolved": "https://registry.npmjs.org/@algorandfoundation/puya-ts/-/puya-ts-1.0.0-beta.6.tgz", + "integrity": "sha512-X4QmOirOAxQk+wvfdDJ33qgO0HUP6I17EFYqBZtolNH82eqMbKtSi5nb5RDejW5EBZINrNJDkQksgw2kl/8FmA==", "bundleDependencies": [ "typescript" ], "license": "MIT", "dependencies": { + "arcsecond": "^5.0.0", "chalk": "^5.3.0", "change-case": "^5.4.4", "commander": "^12.1.0", @@ -105,7 +106,7 @@ } }, "node_modules/@algorandfoundation/puya-ts/node_modules/typescript": { - "version": "5.7.2", + "version": "5.7.3", "inBundle": true, "license": "Apache-2.0", "bin": { @@ -2903,6 +2904,12 @@ "dev": true, "license": "MIT" }, + "node_modules/arcsecond": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/arcsecond/-/arcsecond-5.0.0.tgz", + "integrity": "sha512-J/fHdyadnsIencRsM6oUSsraCKG+Ni9Udcgr/eusxjTzX3SEQtCUQSpP0YtImFPfIK6DdT1nqwN0ng4FqNmwgA==", + "license": "MIT" + }, "node_modules/argparse": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", diff --git a/package.json b/package.json index c3001e9..6d703d2 100644 --- a/package.json +++ b/package.json @@ -63,8 +63,8 @@ "tslib": "^2.6.2" }, "dependencies": { - "@algorandfoundation/algorand-typescript": "^0.0.1-alpha.24", - "@algorandfoundation/puya-ts": "^1.0.0-alpha.36", + "@algorandfoundation/algorand-typescript": "^1.0.0-beta.4", + "@algorandfoundation/puya-ts": "^1.0.0-beta.6", "elliptic": "^6.5.7", "js-sha256": "^0.11.0", "js-sha3": "^0.9.3", diff --git a/src/abi-metadata.ts b/src/abi-metadata.ts index f31554f..f07a8a4 100644 --- a/src/abi-metadata.ts +++ b/src/abi-metadata.ts @@ -1,6 +1,6 @@ import { BaseContract, Contract } from '@algorandfoundation/algorand-typescript' import { AbiMethodConfig, BareMethodConfig, CreateOptions, OnCompleteActionStr } from '@algorandfoundation/algorand-typescript/arc4' -import { sha512_256 as js_sha512_256 } from 'js-sha512' +import js_sha512 from 'js-sha512' import { TypeInfo } from './encoders' import { getArc4TypeName as getArc4TypeNameForARC4Encoded } from './impl/encoded-types' import { DeliberateAny } from './typescript-helpers' @@ -79,7 +79,7 @@ export const getArc4Signature = (metadata: AbiMetadata): string => { } export const getArc4Selector = (metadata: AbiMetadata): Uint8Array => { - const hash = js_sha512_256.array(getArc4Signature(metadata)) + const hash = js_sha512.sha512_256.array(getArc4Signature(metadata)) return new Uint8Array(hash.slice(0, 4)) } diff --git a/src/context-helpers/internal-context.ts b/src/context-helpers/internal-context.ts index e7b6e1d..ccf780d 100644 --- a/src/context-helpers/internal-context.ts +++ b/src/context-helpers/internal-context.ts @@ -1,7 +1,6 @@ import { Account, BaseContract, internal } from '@algorandfoundation/algorand-typescript' -import { AccountData } from '../impl/account' -import { ApplicationData } from '../impl/application' -import { AssetData } from '../impl/asset' +import { AccountData, ApplicationData, AssetData } from '../impl/reference' +import { VoterData } from '../impl/voter-params' import { TransactionGroup } from '../subcontexts/transaction-context' import { TestExecutionContext } from '../test-execution-context' @@ -69,6 +68,14 @@ class InternalContext { } return data } + + getVoterData(account: Account): VoterData { + const data = this.ledger.voterDataMap.get(account) + if (!data) { + throw internal.errors.internalError('Unknown voter, check correct testing context is active') + } + return data + } } export const lazyContext = new InternalContext() diff --git a/src/encoders.ts b/src/encoders.ts index 2cf964c..b8aba0d 100644 --- a/src/encoders.ts +++ b/src/encoders.ts @@ -1,10 +1,8 @@ import { biguint, BigUint, bytes, internal, TransactionType, uint64, Uint64 } from '@algorandfoundation/algorand-typescript' import { ARC4Encoded, OnCompleteAction } from '@algorandfoundation/algorand-typescript/arc4' -import { AccountCls } from './impl/account' -import { ApplicationCls } from './impl/application' -import { AssetCls } from './impl/asset' import { BytesBackedCls, Uint64BackedCls } from './impl/base' import { arc4Encoders, encodeArc4Impl, getArc4Encoder } from './impl/encoded-types' +import { AccountCls, ApplicationCls, AssetCls } from './impl/reference' import { DeliberateAny } from './typescript-helpers' import { asBytes, asMaybeBigUintCls, asMaybeBytesCls, asMaybeUint64Cls, asUint64Cls, asUint8Array, nameOfType } from './util' diff --git a/src/impl/account.ts b/src/impl/account.ts deleted file mode 100644 index 614d8a8..0000000 --- a/src/impl/account.ts +++ /dev/null @@ -1,102 +0,0 @@ -import { Account, Application, Asset, bytes, internal, uint64 } from '@algorandfoundation/algorand-typescript' -import { Uint64Map } from '../collections/custom-key-map' -import { DEFAULT_ACCOUNT_MIN_BALANCE, ZERO_ADDRESS } from '../constants' -import { lazyContext } from '../context-helpers/internal-context' -import { Mutable } from '../typescript-helpers' -import { asUint64, asUint64Cls } from '../util' -import { ApplicationCls } from './application' -import { AssetCls } from './asset' -import { BytesBackedCls } from './base' - -export class AssetHolding { - balance: uint64 - frozen: boolean - constructor(balance: internal.primitives.StubUint64Compat, frozen: boolean) { - this.balance = asUint64(balance) - this.frozen = frozen - } -} - -export class AccountData { - optedAssets = new Uint64Map() - optedApplications = new Uint64Map() - account: Mutable> - - constructor() { - this.account = { - totalAppsCreated: 0, - totalAppsOptedIn: 0, - totalAssets: 0, - totalAssetsCreated: 0, - totalBoxBytes: 0, - totalBoxes: 0, - totalExtraAppPages: 0, - totalNumByteSlice: 0, - totalNumUint: 0, - minBalance: DEFAULT_ACCOUNT_MIN_BALANCE, - balance: 0, - authAddress: Account(), - } - } -} - -export class AccountCls extends BytesBackedCls implements Account { - constructor(address?: bytes) { - const addressBytes = address ?? ZERO_ADDRESS - if (![32n, 36n].includes(asUint64Cls(addressBytes.length).valueOf())) { - throw new internal.errors.AvmError('Address must be 32 bytes long, or 36 bytes including checksum') - } - super(addressBytes.slice(0, 32)) - } - - private get data(): AccountData { - return lazyContext.getAccountData(this) - } - - get balance(): uint64 { - return this.data.account.balance - } - get minBalance(): uint64 { - return this.data.account.minBalance - } - get authAddress(): Account { - return this.data.account.authAddress - } - get totalNumUint(): uint64 { - return this.data.account.totalNumUint - } - get totalNumByteSlice(): uint64 { - return this.data.account.totalNumByteSlice - } - get totalExtraAppPages(): uint64 { - return this.data.account.totalExtraAppPages - } - get totalAppsCreated(): uint64 { - return this.data.account.totalAppsCreated - } - get totalAppsOptedIn(): uint64 { - return this.data.account.totalAppsOptedIn - } - get totalAssetsCreated(): uint64 { - return this.data.account.totalAssetsCreated - } - get totalAssets(): uint64 { - return this.data.account.totalAssets - } - get totalBoxes(): uint64 { - return this.data.account.totalBoxes - } - get totalBoxBytes(): uint64 { - return this.data.account.totalBoxBytes - } - - isOptedIn(assetOrApp: Asset | Application): boolean { - if (assetOrApp instanceof AssetCls) { - return this.data.optedAssets.has(assetOrApp.id) - } - if (assetOrApp instanceof ApplicationCls) { - return this.data.optedApplications.has(asUint64Cls(assetOrApp.id).asBigInt()) - } - throw new internal.errors.InternalError('Invalid argument type. Must be an `Asset` or `Application` instance.') - } -} diff --git a/src/impl/acct-params.ts b/src/impl/acct-params.ts index 9042446..685fac5 100644 --- a/src/impl/acct-params.ts +++ b/src/impl/acct-params.ts @@ -2,6 +2,7 @@ import { Account, Application, gtxn, internal, uint64 } from '@algorandfoundatio import { lazyContext } from '../context-helpers/internal-context' import { asMaybeUint64Cls } from '../util' import { getApp } from './app-params' +import { Global } from './global' export const getAccount = (acct: Account | internal.primitives.StubUint64Compat): Account => { const acctId = asMaybeUint64Cls(acct) @@ -84,14 +85,19 @@ export const AcctParams: internal.opTypes.AcctParamsType = { const acct = getAccount(a) return [acct.totalBoxBytes, acct.balance !== 0] }, - // TODO: implement v11 methods - acctIncentiveEligible: function (_a: Account | uint64): readonly [boolean, boolean] { - throw new Error('Function not implemented.') + acctIncentiveEligible: function (a: Account | internal.primitives.StubUint64Compat): readonly [boolean, boolean] { + const acct = getAccount(a) + const accountData = lazyContext.ledger.accountDataMap.get(acct) + return [accountData?.incentiveEligible ?? false, acct.balance !== 0] }, - acctLastProposed: function (_a: Account | uint64): readonly [uint64, boolean] { - throw new Error('Function not implemented.') + acctLastProposed: function (a: Account | internal.primitives.StubUint64Compat): readonly [uint64, boolean] { + const acct = getAccount(a) + const accountData = lazyContext.ledger.accountDataMap.get(acct) + return [accountData?.lastProposed ?? Global.round, acct.balance !== 0] }, - acctLastHeartbeat: function (_a: Account | uint64): readonly [uint64, boolean] { - throw new Error('Function not implemented.') + acctLastHeartbeat: function (a: Account | internal.primitives.StubUint64Compat): readonly [uint64, boolean] { + const acct = getAccount(a) + const accountData = lazyContext.ledger.accountDataMap.get(acct) + return [accountData?.lastHeartbeat ?? Global.round, acct.balance !== 0] }, } diff --git a/src/impl/app-params.ts b/src/impl/app-params.ts index e1b339c..b8420c5 100644 --- a/src/impl/app-params.ts +++ b/src/impl/app-params.ts @@ -1,6 +1,7 @@ import { Account, Application, Bytes, bytes, gtxn, internal, Uint64, uint64 } from '@algorandfoundation/algorand-typescript' import { lazyContext } from '../context-helpers/internal-context' import { asMaybeUint64Cls, asUint64 } from '../util' +import { AccountImpl } from './reference' const resolveAppIndex = (appIdOrIndex: internal.primitives.StubUint64Compat): uint64 => { const input = asUint64(appIdOrIndex) @@ -54,10 +55,10 @@ export const AppParams: internal.opTypes.AppParamsType = { }, appCreator(a: Application | internal.primitives.StubUint64Compat): readonly [Account, boolean] { const app = getApp(a) - return app === undefined ? [Account(), false] : [app.creator, true] + return app === undefined ? [AccountImpl(), false] : [app.creator, true] }, appAddress(a: Application | internal.primitives.StubUint64Compat): readonly [Account, boolean] { const app = getApp(a) - return app === undefined ? [Account(), false] : [app.address, true] + return app === undefined ? [AccountImpl(), false] : [app.address, true] }, } diff --git a/src/impl/application.ts b/src/impl/application.ts deleted file mode 100644 index 9ae03cd..0000000 --- a/src/impl/application.ts +++ /dev/null @@ -1,80 +0,0 @@ -import { Account, Application, bytes, LocalState, uint64 } from '@algorandfoundation/algorand-typescript' -import { BytesMap } from '../collections/custom-key-map' -import { ALWAYS_APPROVE_TEAL_PROGRAM } from '../constants' -import { lazyContext } from '../context-helpers/internal-context' -import { Mutable } from '../typescript-helpers' -import { asUint64, getApplicationAddress } from '../util' -import { Uint64BackedCls } from './base' -import { GlobalStateCls } from './state' - -export class ApplicationData { - application: Mutable> & { - appLogs: bytes[] - globalStates: BytesMap> - localStates: BytesMap> - boxes: BytesMap - } - isCreating: boolean = false - - get appLogs() { - return this.application.appLogs - } - - constructor() { - this.application = { - approvalProgram: ALWAYS_APPROVE_TEAL_PROGRAM, - clearStateProgram: ALWAYS_APPROVE_TEAL_PROGRAM, - globalNumUint: 0, - globalNumBytes: 0, - localNumUint: 0, - localNumBytes: 0, - extraProgramPages: 0, - creator: lazyContext.defaultSender, - appLogs: [], - globalStates: new BytesMap(), - localStates: new BytesMap(), - boxes: new BytesMap(), - } - } -} - -export class ApplicationCls extends Uint64BackedCls implements Application { - get id() { - return this.uint64 - } - - constructor(id?: uint64) { - super(asUint64(id ?? 0)) - } - - private get data(): ApplicationData { - return lazyContext.getApplicationData(this.id) - } - get approvalProgram(): bytes { - return this.data.application.approvalProgram - } - get clearStateProgram(): bytes { - return this.data.application.clearStateProgram - } - get globalNumUint(): uint64 { - return this.data.application.globalNumUint - } - get globalNumBytes(): uint64 { - return this.data.application.globalNumBytes - } - get localNumUint(): uint64 { - return this.data.application.localNumUint - } - get localNumBytes(): uint64 { - return this.data.application.localNumBytes - } - get extraProgramPages(): uint64 { - return this.data.application.extraProgramPages - } - get creator(): Account { - return this.data.application.creator - } - get address(): Account { - return getApplicationAddress(this.id) - } -} diff --git a/src/impl/asset-holding.ts b/src/impl/asset-holding.ts index 1da7f3e..92fdc8d 100644 --- a/src/impl/asset-holding.ts +++ b/src/impl/asset-holding.ts @@ -1,8 +1,8 @@ import { Account, Asset, internal, Uint64, uint64 } from '@algorandfoundation/algorand-typescript' import { lazyContext } from '../context-helpers/internal-context' -import { AssetHolding as AssetHoldingData } from './account' import { getAccount } from './acct-params' import { getAsset } from './asset-params' +import { AssetHolding as AssetHoldingData } from './reference' const getAssetHolding = ( acctOrIndex: Account | internal.primitives.StubUint64Compat, diff --git a/src/impl/asset-params.ts b/src/impl/asset-params.ts index 05a4129..f53bf7c 100644 --- a/src/impl/asset-params.ts +++ b/src/impl/asset-params.ts @@ -1,6 +1,7 @@ import { Account, Asset, Bytes, bytes, gtxn, internal, Uint64, uint64 } from '@algorandfoundation/algorand-typescript' import { lazyContext } from '../context-helpers/internal-context' import { asMaybeUint64Cls, asUint64 } from '../util' +import { AccountImpl } from './reference' const resolveAssetIndex = (assetIdOrIndex: internal.primitives.StubUint64Compat): uint64 => { const input = asUint64(assetIdOrIndex) @@ -54,22 +55,22 @@ export const AssetParams: internal.opTypes.AssetParamsType = { }, assetManager(a: Asset | internal.primitives.StubUint64Compat): readonly [Account, boolean] { const asset = getAsset(a) - return asset === undefined ? [Account(), false] : [asset.manager, true] + return asset === undefined ? [AccountImpl(), false] : [asset.manager, true] }, assetReserve(a: Asset | internal.primitives.StubUint64Compat): readonly [Account, boolean] { const asset = getAsset(a) - return asset === undefined ? [Account(), false] : [asset.reserve, true] + return asset === undefined ? [AccountImpl(), false] : [asset.reserve, true] }, assetFreeze(a: Asset | internal.primitives.StubUint64Compat): readonly [Account, boolean] { const asset = getAsset(a) - return asset === undefined ? [Account(), false] : [asset.freeze, true] + return asset === undefined ? [AccountImpl(), false] : [asset.freeze, true] }, assetClawback(a: Asset | internal.primitives.StubUint64Compat): readonly [Account, boolean] { const asset = getAsset(a) - return asset === undefined ? [Account(), false] : [asset.clawback, true] + return asset === undefined ? [AccountImpl(), false] : [asset.clawback, true] }, assetCreator(a: Asset | internal.primitives.StubUint64Compat): readonly [Account, boolean] { const asset = getAsset(a) - return asset === undefined ? [Account(), false] : [asset.creator, true] + return asset === undefined ? [AccountImpl(), false] : [asset.creator, true] }, } diff --git a/src/impl/asset.ts b/src/impl/asset.ts deleted file mode 100644 index 5eeb156..0000000 --- a/src/impl/asset.ts +++ /dev/null @@ -1,76 +0,0 @@ -import { Account, Asset, bytes, internal, uint64 } from '@algorandfoundation/algorand-typescript' -import { lazyContext } from '../context-helpers/internal-context' -import { Mutable } from '../typescript-helpers' -import { asUint64 } from '../util' -import { AssetHolding } from './account' -import { Uint64BackedCls } from './base' - -export type AssetData = Mutable> - -export class AssetCls extends Uint64BackedCls implements Asset { - get id(): uint64 { - return this.uint64 - } - - constructor(id?: internal.primitives.StubUint64Compat) { - super(asUint64(id ?? 0)) - } - - private get data(): AssetData { - return lazyContext.getAssetData(this.id) - } - - get total(): uint64 { - return this.data.total - } - get decimals(): uint64 { - return this.data.decimals - } - get defaultFrozen(): boolean { - return this.data.defaultFrozen - } - get unitName(): bytes { - return this.data.unitName - } - get name(): bytes { - return this.data.name - } - get url(): bytes { - return this.data.url - } - get metadataHash(): bytes { - return this.data.metadataHash - } - get manager(): Account { - return this.data.manager - } - get reserve(): Account { - return this.data.reserve - } - get freeze(): Account { - return this.data.freeze - } - get clawback(): Account { - return this.data.clawback - } - get creator(): Account { - return this.data.creator - } - balance(account: Account): uint64 { - return this.getAssetHolding(account).balance - } - frozen(account: Account): boolean { - return this.getAssetHolding(account).frozen - } - - private getAssetHolding(account: Account): AssetHolding { - const accountData = lazyContext.getAccountData(account) - const assetHolding = accountData.optedAssets.get(this.id) - if (assetHolding === undefined) { - internal.errors.internalError( - 'The asset is not opted into the account! Use `ctx.any.account(opted_asset_balances={{ASSET_ID: VALUE}})` to set emulated opted asset into the account.', - ) - } - return assetHolding - } -} diff --git a/src/impl/block.ts b/src/impl/block.ts index 79e9069..1322c9b 100644 --- a/src/impl/block.ts +++ b/src/impl/block.ts @@ -1,38 +1,63 @@ -import { Account, bytes, internal, uint64 } from '@algorandfoundation/algorand-typescript' +import { Account, bytes, internal, Uint64, uint64 } from '@algorandfoundation/algorand-typescript' import { lazyContext } from '../context-helpers/internal-context' -import { asUint64 } from '../util' -import { itob } from './pure' +import { asUint64, getRandomBytes } from '../util' +import { AccountImpl } from './reference' + +export class BlockData { + seed: bytes + timestamp: uint64 + proposer: Account + feesCollected: uint64 + bonus: uint64 + branch: bytes + feeSink: Account + protocol: bytes + txnCounter: uint64 + proposerPayout: uint64 + + constructor() { + this.seed = getRandomBytes(32).asAlgoTs() + this.timestamp = asUint64(Date.now()) + this.proposer = AccountImpl() + this.feesCollected = Uint64(0) + this.bonus = Uint64(0) + this.branch = getRandomBytes(32).asAlgoTs() + this.feeSink = AccountImpl() + this.protocol = getRandomBytes(32).asAlgoTs() + this.txnCounter = Uint64(0) + this.proposerPayout = Uint64(0) + } +} export const Block: internal.opTypes.BlockType = { blkSeed: function (a: internal.primitives.StubUint64Compat): bytes { - return itob(lazyContext.ledger.getBlockContent(a).seed) + return lazyContext.ledger.getBlockData(a).seed }, blkTimestamp: function (a: internal.primitives.StubUint64Compat): uint64 { - return asUint64(lazyContext.ledger.getBlockContent(a).timestamp) + return lazyContext.ledger.getBlockData(a).timestamp }, - // TODO: implement v11 methods - blkProposer: function (_a: uint64): Account { - throw new Error('Function not implemented.') + blkProposer: function (a: uint64): Account { + return lazyContext.ledger.getBlockData(a).proposer }, - blkFeesCollected: function (_a: uint64): uint64 { - throw new Error('Function not implemented.') + blkFeesCollected: function (a: uint64): uint64 { + return lazyContext.ledger.getBlockData(a).feesCollected }, - blkBonus: function (_a: uint64): uint64 { - throw new Error('Function not implemented.') + blkBonus: function (a: uint64): uint64 { + return lazyContext.ledger.getBlockData(a).bonus }, - blkBranch: function (_a: uint64): bytes { - throw new Error('Function not implemented.') + blkBranch: function (a: uint64): bytes { + return lazyContext.ledger.getBlockData(a).branch }, - blkFeeSink: function (_a: uint64): Account { - throw new Error('Function not implemented.') + blkFeeSink: function (a: uint64): Account { + return lazyContext.ledger.getBlockData(a).feeSink }, - blkProtocol: function (_a: uint64): bytes { - throw new Error('Function not implemented.') + blkProtocol: function (a: uint64): bytes { + return lazyContext.ledger.getBlockData(a).protocol }, - blkTxnCounter: function (_a: uint64): uint64 { - throw new Error('Function not implemented.') + blkTxnCounter: function (a: uint64): uint64 { + return lazyContext.ledger.getBlockData(a).txnCounter }, - blkProposerPayout: function (_a: uint64): uint64 { - throw new Error('Function not implemented.') + blkProposerPayout: function (a: uint64): uint64 { + return lazyContext.ledger.getBlockData(a).proposerPayout }, } diff --git a/src/impl/compiled.ts b/src/impl/compiled.ts index 71aa7a2..c358fcb 100644 --- a/src/impl/compiled.ts +++ b/src/impl/compiled.ts @@ -9,7 +9,7 @@ import { } from '@algorandfoundation/algorand-typescript' import { lazyContext } from '../context-helpers/internal-context' import { ConstructorFor } from '../typescript-helpers' -import { ApplicationData } from './application' +import { ApplicationData } from './reference' export function compileImpl( artefact: ConstructorFor | ConstructorFor, diff --git a/src/impl/crypto.ts b/src/impl/crypto.ts index 6089807..bfc0523 100644 --- a/src/impl/crypto.ts +++ b/src/impl/crypto.ts @@ -1,8 +1,8 @@ import { arc4, bytes, Bytes, Ecdsa, gtxn, internal, VrfVerify } from '@algorandfoundation/algorand-typescript' -import { ec } from 'elliptic' -import { sha256 as js_sha256 } from 'js-sha256' -import { keccak256 as js_keccak256, sha3_256 as js_sha3_256 } from 'js-sha3' -import { sha512_256 as js_sha512_256 } from 'js-sha512' +import elliptic from 'elliptic' +import js_sha256 from 'js-sha256' +import js_sha3 from 'js-sha3' +import js_sha512 from 'js-sha512' import nacl from 'tweetnacl' import { LOGIC_DATA_PREFIX, PROGRAM_TAG } from '../constants' import { lazyContext } from '../context-helpers/internal-context' @@ -11,28 +11,28 @@ import { asBytes, asBytesCls, asUint8Array, conactUint8Arrays } from '../util' export const sha256 = (a: internal.primitives.StubBytesCompat): bytes => { const bytesA = internal.primitives.BytesCls.fromCompat(a) - const hashArray = js_sha256.create().update(bytesA.asUint8Array()).digest() + const hashArray = js_sha256.sha256.create().update(bytesA.asUint8Array()).digest() const hashBytes = internal.primitives.BytesCls.fromCompat(new Uint8Array(hashArray)) return hashBytes.asAlgoTs() } export const sha3_256 = (a: internal.primitives.StubBytesCompat): bytes => { const bytesA = internal.primitives.BytesCls.fromCompat(a) - const hashArray = js_sha3_256.create().update(bytesA.asUint8Array()).digest() + const hashArray = js_sha3.sha3_256.create().update(bytesA.asUint8Array()).digest() const hashBytes = internal.primitives.BytesCls.fromCompat(new Uint8Array(hashArray)) return hashBytes.asAlgoTs() } export const keccak256 = (a: internal.primitives.StubBytesCompat): bytes => { const bytesA = internal.primitives.BytesCls.fromCompat(a) - const hashArray = js_keccak256.create().update(bytesA.asUint8Array()).digest() + const hashArray = js_sha3.keccak256.create().update(bytesA.asUint8Array()).digest() const hashBytes = internal.primitives.BytesCls.fromCompat(new Uint8Array(hashArray)) return hashBytes.asAlgoTs() } export const sha512_256 = (a: internal.primitives.StubBytesCompat): bytes => { const bytesA = internal.primitives.BytesCls.fromCompat(a) - const hashArray = js_sha512_256.create().update(bytesA.asUint8Array()).digest() + const hashArray = js_sha512.sha512_256.create().update(bytesA.asUint8Array()).digest() const hashBytes = internal.primitives.BytesCls.fromCompat(new Uint8Array(hashArray)) return hashBytes.asAlgoTs() } @@ -59,7 +59,7 @@ export const ed25519verify = ( ) const logicSig = conactUint8Arrays(asUint8Array(PROGRAM_TAG), programBytes.asUint8Array()) - const logicSigAddress = js_sha512_256.array(logicSig) + const logicSigAddress = js_sha512.sha512_256.array(logicSig) const addressBytes = Bytes(logicSigAddress) const data = LOGIC_DATA_PREFIX.concat(addressBytes).concat(asBytes(a)) @@ -84,7 +84,7 @@ export const ecdsaVerify = ( .concat(pubkeyXBytes) .concat(pubkeyYBytes) - const ecdsa = new ec(curveMap[v]) + const ecdsa = new elliptic.ec(curveMap[v]) const keyPair = ecdsa.keyFromPublic(publicKey.asUint8Array()) return keyPair.verify(dataBytes.asUint8Array(), { r: sigRBytes.asUint8Array(), s: sigSBytes.asUint8Array() }) } @@ -104,7 +104,7 @@ export const ecdsaPkRecover = ( const sBytes = internal.primitives.BytesCls.fromCompat(d) const recoveryId = internal.primitives.Uint64Cls.fromCompat(b) - const ecdsa = new ec(curveMap[v]) + const ecdsa = new elliptic.ec(curveMap[v]) const pubKey = ecdsa.recoverPubKey( dataBytes.asUint8Array(), { r: rBytes.asUint8Array(), s: sBytes.asUint8Array() }, @@ -119,7 +119,7 @@ export const ecdsaPkRecover = ( export const ecdsaPkDecompress = (v: Ecdsa, a: internal.primitives.StubBytesCompat): readonly [bytes, bytes] => { const bytesA = internal.primitives.BytesCls.fromCompat(a) - const ecdsa = new ec(curveMap[v]) + const ecdsa = new elliptic.ec(curveMap[v]) const keyPair = ecdsa.keyFromPublic(bytesA.asUint8Array()) const pubKey = keyPair.getPublic() diff --git a/src/impl/emit.ts b/src/impl/emit.ts index d5974ed..a31bfae 100644 --- a/src/impl/emit.ts +++ b/src/impl/emit.ts @@ -1,8 +1,8 @@ import { internal } from '@algorandfoundation/algorand-typescript' -import { lazyContext } from '../context-helpers/internal-context' import { DeliberateAny } from '../typescript-helpers' import { sha512_256 } from './crypto' import { getArc4Encoded, getArc4TypeName } from './encoded-types' +import { logImpl } from './log' export function emitImpl(typeInfoString: string, event: T | string, ...eventProps: unknown[]) { let eventData @@ -24,5 +24,5 @@ export function emitImpl(typeInfoString: string, event: T | string, ...eventP } const eventHash = sha512_256(eventName) - lazyContext.value.log(eventHash.slice(0, 4).concat(eventData.bytes)) + logImpl(eventHash.slice(0, 4).concat(eventData.bytes)) } diff --git a/src/impl/encoded-types.ts b/src/impl/encoded-types.ts index 1d50312..0ca0636 100644 --- a/src/impl/encoded-types.ts +++ b/src/impl/encoded-types.ts @@ -28,9 +28,7 @@ import { lazyContext } from '../context-helpers/internal-context' import { fromBytes, TypeInfo } from '../encoders' import { DeliberateAny } from '../typescript-helpers' import { asBigInt, asBigUint, asBigUintCls, asBytesCls, asUint64, asUint8Array, conactUint8Arrays, uint8ArrayToNumber } from '../util' -import { AccountCls } from './account' -import { ApplicationCls } from './application' -import { AssetCls } from './asset' +import { AccountCls, AccountImpl, ApplicationCls, AssetCls } from './reference' import { ApplicationTransaction } from './transactions' const ABI_LENGTH_SIZE = 2 @@ -479,7 +477,7 @@ export class AddressImpl extends Address { } get native(): Account { - return Account(this.value.bytes) + return AccountImpl(this.value.bytes) } get items(): ByteImpl[] { diff --git a/src/impl/global.ts b/src/impl/global.ts index 393cc88..6a67426 100644 --- a/src/impl/global.ts +++ b/src/impl/global.ts @@ -9,7 +9,8 @@ import { ZERO_ADDRESS, } from '../constants' import { lazyContext } from '../context-helpers/internal-context' -import { getApplicationAddress, getObjectReference } from '../util' +import { getObjectReference } from '../util' +import { AccountImpl, getApplicationAddress } from './reference' export class GlobalData { minTxnFee: uint64 @@ -25,16 +26,24 @@ export class GlobalData { assetOptInMinBalance: uint64 genesisHash: bytes opcodeBudget?: uint64 + payoutsEnabled: boolean + payoutsGoOnlineFee: uint64 + payoutsPercent: uint64 + payoutsMinBalance: uint64 constructor() { this.minTxnFee = Uint64(MIN_TXN_FEE) this.minBalance = Uint64(DEFAULT_ACCOUNT_MIN_BALANCE) this.maxTxnLife = Uint64(DEFAULT_MAX_TXN_LIFE) - this.zeroAddress = Account(ZERO_ADDRESS) + this.zeroAddress = AccountImpl(ZERO_ADDRESS) this.callerApplicationId = Uint64(0) this.assetCreateMinBalance = Uint64(DEFAULT_ASSET_CREATE_MIN_BALANCE) this.assetOptInMinBalance = Uint64(DEFAULT_ASSET_OPT_IN_MIN_BALANCE) this.genesisHash = DEFAULT_GLOBAL_GENESIS_HASH + this.payoutsEnabled = false + this.payoutsGoOnlineFee = Uint64(0) + this.payoutsPercent = Uint64(0) + this.payoutsMinBalance = Uint64(0) } } const getGlobalData = (): GlobalData => { @@ -184,10 +193,44 @@ export const Global: internal.opTypes.GlobalType = { get genesisHash(): bytes { return getGlobalData().genesisHash }, - payoutsEnabled: false, - // TODO: implement v11 fields - payoutsGoOnlineFee: 0, - payoutsPercent: 0, - payoutsMinBalance: 0, - payoutsMaxBalance: 0, + + /** + * Whether block proposal payouts are enabled. + * Min AVM version: 11 + */ + get payoutsEnabled(): boolean { + return getGlobalData().payoutsEnabled + }, + + /** + * The fee required in a keyreg transaction to make an account incentive eligible. + * Min AVM version: 11 + */ + get payoutsGoOnlineFee(): uint64 { + return getGlobalData().payoutsGoOnlineFee + }, + + /** + * The percentage of transaction fees in a block that can be paid to the block proposer. + * Min AVM version: 11 + */ + get payoutsPercent(): uint64 { + return getGlobalData().payoutsPercent + }, + + /** + * The minimum algo balance an account must have in the agreement round to receive block payouts in the proposal round. + * Min AVM version: 11 + */ + get payoutsMinBalance(): uint64 { + return getGlobalData().payoutsMinBalance + }, + + /** + * The maximum algo balance an account can have in the agreement round to receive block payouts in the proposal round. + * Min AVM version: 11 + */ + get payoutsMaxBalance(): uint64 { + return getGlobalData().payoutsMinBalance + }, } diff --git a/src/impl/index.ts b/src/impl/index.ts index 42bd62b..a90600c 100644 --- a/src/impl/index.ts +++ b/src/impl/index.ts @@ -11,6 +11,8 @@ export { Global } from './global' export { GTxn } from './gtxn' export { GITxn, ITxn, ITxnCreate } from './itxn' export { arg } from './logicSigArg' +export { onlineStake } from './online-stake' export * from './pure' export { gloadBytes, gloadUint64, Scratch } from './scratch' export { gaid, Txn } from './txn' +export { VoterParams } from './voter-params' diff --git a/src/impl/inner-transactions.ts b/src/impl/inner-transactions.ts index 7ebe59f..04cd9f4 100644 --- a/src/impl/inner-transactions.ts +++ b/src/impl/inner-transactions.ts @@ -5,6 +5,7 @@ import { asBytes, asNumber } from '../util' import { getApp } from './app-params' import { getAsset } from './asset-params' import { InnerTxn, InnerTxnFields } from './itxn' +import { AccountImpl } from './reference' import { ApplicationTransaction, AssetConfigTransaction, @@ -21,9 +22,13 @@ const mapCommonFields = ( return { sender: - sender instanceof Account ? sender : typeof sender === 'string' ? Account(asBytes(sender)) : lazyContext.activeApplication.address, + sender instanceof Account + ? sender + : typeof sender === 'string' + ? AccountImpl(asBytes(sender)) + : lazyContext.activeApplication.address, note: note !== undefined ? asBytes(note) : undefined, - rekeyTo: rekeyTo instanceof Account ? rekeyTo : typeof rekeyTo === 'string' ? Account(asBytes(rekeyTo)) : undefined, + rekeyTo: rekeyTo instanceof Account ? rekeyTo : typeof rekeyTo === 'string' ? AccountImpl(asBytes(rekeyTo)) : undefined, ...rest, } } @@ -118,7 +123,8 @@ export class AssetFreezeInnerTxn extends AssetFreezeTransaction implements itxn. constructor(fields: itxn.AssetFreezeFields) { const { freezeAsset, freezeAccount, ...rest } = mapCommonFields(fields) const asset: Asset | undefined = freezeAsset instanceof internal.primitives.Uint64Cls ? getAsset(freezeAsset) : (freezeAsset as Asset) - const account: Account | undefined = typeof freezeAccount === 'string' ? Account(asBytes(freezeAccount)) : (freezeAccount as Account) + const account: Account | undefined = + typeof freezeAccount === 'string' ? AccountImpl(asBytes(freezeAccount)) : (freezeAccount as Account) super({ freezeAsset: asset, freezeAccount: account, diff --git a/src/impl/log.ts b/src/impl/log.ts new file mode 100644 index 0000000..2dc07a0 --- /dev/null +++ b/src/impl/log.ts @@ -0,0 +1,32 @@ +import { bytes, BytesBacked, internal, StringCompat } from '@algorandfoundation/algorand-typescript' +import { ARC4Encoded } from '@algorandfoundation/algorand-typescript/arc4' +import { lazyContext } from '../context-helpers/internal-context' +import { nameOfType } from '../util' + +const toBytes = (val: unknown): bytes => { + if (val instanceof internal.primitives.AlgoTsPrimitiveCls) return val.toBytes().asAlgoTs() + if (val instanceof ARC4Encoded) return val.bytes + + switch (typeof val) { + case 'string': + return internal.primitives.BytesCls.fromCompat(val).asAlgoTs() + case 'bigint': + return internal.primitives.BigUintCls.fromCompat(val).toBytes().asAlgoTs() + case 'number': + return internal.primitives.Uint64Cls.fromCompat(val).toBytes().asAlgoTs() + default: + internal.errors.internalError(`Unsupported arg type ${nameOfType(val)}`) + } +} + +export function logImpl( + ...args: Array< + | internal.primitives.StubUint64Compat + | internal.primitives.StubBytesCompat + | internal.primitives.StubBigUintCompat + | StringCompat + | BytesBacked + > +): void { + lazyContext.txn.appendLog(args.map(toBytes).reduce((left, right) => left.concat(right))) +} diff --git a/src/impl/online-stake.ts b/src/impl/online-stake.ts new file mode 100644 index 0000000..c9fa68b --- /dev/null +++ b/src/impl/online-stake.ts @@ -0,0 +1,6 @@ +import { internal } from '@algorandfoundation/algorand-typescript' +import { lazyContext } from '../context-helpers/internal-context' + +export const onlineStake: internal.opTypes.OnlineStakeType = () => { + return lazyContext.ledger.onlineStake +} diff --git a/src/impl/reference.ts b/src/impl/reference.ts new file mode 100644 index 0000000..0056d73 --- /dev/null +++ b/src/impl/reference.ts @@ -0,0 +1,290 @@ +import { Account, Application, Asset, bytes, Bytes, internal, LocalState, uint64 } from '@algorandfoundation/algorand-typescript' +import { encodingUtil } from '@algorandfoundation/puya-ts' +import { sha512_256 as js_sha512_256 } from 'js-sha512' +import { BytesMap, Uint64Map } from '../collections/custom-key-map' +import { + ALGORAND_ADDRESS_BYTE_LENGTH, + ALGORAND_ADDRESS_LENGTH, + ALGORAND_CHECKSUM_BYTE_LENGTH, + ALWAYS_APPROVE_TEAL_PROGRAM, + APP_ID_PREFIX, + DEFAULT_ACCOUNT_MIN_BALANCE, + HASH_BYTES_LENGTH, + ZERO_ADDRESS, +} from '../constants' +import { lazyContext } from '../context-helpers/internal-context' +import { Mutable } from '../typescript-helpers' +import { asBigInt, asUint64, asUint64Cls, asUint8Array, conactUint8Arrays } from '../util' +import { BytesBackedCls, Uint64BackedCls } from './base' +import { GlobalStateCls } from './state' + +export class AssetHolding { + balance: uint64 + frozen: boolean + constructor(balance: internal.primitives.StubUint64Compat, frozen: boolean) { + this.balance = asUint64(balance) + this.frozen = frozen + } +} + +export class AccountData { + optedAssets = new Uint64Map() + optedApplications = new Uint64Map() + incentiveEligible = false + lastProposed?: uint64 + lastHeartbeat?: uint64 + account: Mutable> + + constructor() { + this.account = { + totalAppsCreated: 0, + totalAppsOptedIn: 0, + totalAssets: 0, + totalAssetsCreated: 0, + totalBoxBytes: 0, + totalBoxes: 0, + totalExtraAppPages: 0, + totalNumByteSlice: 0, + totalNumUint: 0, + minBalance: DEFAULT_ACCOUNT_MIN_BALANCE, + balance: 0, + authAddress: AccountImpl(), + } + } +} + +export function AccountImpl(address?: bytes): Account { + return new AccountCls(address) +} + +export class AccountCls extends BytesBackedCls implements Account { + constructor(address?: bytes) { + const addressBytes = address ?? ZERO_ADDRESS + if (![32n, 36n].includes(asUint64Cls(addressBytes.length).valueOf())) { + throw new internal.errors.AvmError('Address must be 32 bytes long, or 36 bytes including checksum') + } + super(addressBytes.slice(0, 32)) + } + + private get data(): AccountData { + return lazyContext.getAccountData(this) + } + + get balance(): uint64 { + return this.data.account.balance + } + get minBalance(): uint64 { + return this.data.account.minBalance + } + get authAddress(): Account { + return this.data.account.authAddress + } + get totalNumUint(): uint64 { + return this.data.account.totalNumUint + } + get totalNumByteSlice(): uint64 { + return this.data.account.totalNumByteSlice + } + get totalExtraAppPages(): uint64 { + return this.data.account.totalExtraAppPages + } + get totalAppsCreated(): uint64 { + return this.data.account.totalAppsCreated + } + get totalAppsOptedIn(): uint64 { + return this.data.account.totalAppsOptedIn + } + get totalAssetsCreated(): uint64 { + return this.data.account.totalAssetsCreated + } + get totalAssets(): uint64 { + return this.data.account.totalAssets + } + get totalBoxes(): uint64 { + return this.data.account.totalBoxes + } + get totalBoxBytes(): uint64 { + return this.data.account.totalBoxBytes + } + + isOptedIn(assetOrApp: Asset | Application): boolean { + if (assetOrApp instanceof AssetCls) { + return this.data.optedAssets.has(assetOrApp.id) + } + if (assetOrApp instanceof ApplicationCls) { + return this.data.optedApplications.has(asUint64Cls(assetOrApp.id).asBigInt()) + } + throw new internal.errors.InternalError('Invalid argument type. Must be an `Asset` or `Application` instance.') + } +} + +export class ApplicationData { + application: Mutable> & { + appLogs: bytes[] + globalStates: BytesMap> + localStates: BytesMap> + boxes: BytesMap + } + isCreating: boolean = false + + get appLogs() { + return this.application.appLogs + } + + constructor() { + this.application = { + approvalProgram: ALWAYS_APPROVE_TEAL_PROGRAM, + clearStateProgram: ALWAYS_APPROVE_TEAL_PROGRAM, + globalNumUint: 0, + globalNumBytes: 0, + localNumUint: 0, + localNumBytes: 0, + extraProgramPages: 0, + creator: lazyContext.defaultSender, + appLogs: [], + globalStates: new BytesMap(), + localStates: new BytesMap(), + boxes: new BytesMap(), + } + } +} + +export function ApplicationImpl(applicationId?: uint64): Application { + return new ApplicationCls(applicationId) +} + +export class ApplicationCls extends Uint64BackedCls implements Application { + get id() { + return this.uint64 + } + + constructor(id?: uint64) { + super(asUint64(id ?? 0)) + } + + private get data(): ApplicationData { + return lazyContext.getApplicationData(this.id) + } + get approvalProgram(): bytes { + return this.data.application.approvalProgram + } + get clearStateProgram(): bytes { + return this.data.application.clearStateProgram + } + get globalNumUint(): uint64 { + return this.data.application.globalNumUint + } + get globalNumBytes(): uint64 { + return this.data.application.globalNumBytes + } + get localNumUint(): uint64 { + return this.data.application.localNumUint + } + get localNumBytes(): uint64 { + return this.data.application.localNumBytes + } + get extraProgramPages(): uint64 { + return this.data.application.extraProgramPages + } + get creator(): Account { + return this.data.application.creator + } + get address(): Account { + return getApplicationAddress(this.id) + } +} + +export type AssetData = Mutable> + +export function AssetImpl(assetId?: uint64): Asset { + return new AssetCls(assetId) +} +export class AssetCls extends Uint64BackedCls implements Asset { + get id(): uint64 { + return this.uint64 + } + + constructor(id?: internal.primitives.StubUint64Compat) { + super(asUint64(id ?? 0)) + } + + private get data(): AssetData { + return lazyContext.getAssetData(this.id) + } + + get total(): uint64 { + return this.data.total + } + get decimals(): uint64 { + return this.data.decimals + } + get defaultFrozen(): boolean { + return this.data.defaultFrozen + } + get unitName(): bytes { + return this.data.unitName + } + get name(): bytes { + return this.data.name + } + get url(): bytes { + return this.data.url + } + get metadataHash(): bytes { + return this.data.metadataHash + } + get manager(): Account { + return this.data.manager + } + get reserve(): Account { + return this.data.reserve + } + get freeze(): Account { + return this.data.freeze + } + get clawback(): Account { + return this.data.clawback + } + get creator(): Account { + return this.data.creator + } + balance(account: Account): uint64 { + return this.getAssetHolding(account).balance + } + frozen(account: Account): boolean { + return this.getAssetHolding(account).frozen + } + + private getAssetHolding(account: Account): AssetHolding { + const accountData = lazyContext.getAccountData(account) + const assetHolding = accountData.optedAssets.get(this.id) + if (assetHolding === undefined) { + internal.errors.internalError( + 'The asset is not opted into the account! Use `ctx.any.account(opted_asset_balances={{ASSET_ID: VALUE}})` to set emulated opted asset into the account.', + ) + } + return assetHolding + } +} + +export const checksumFromPublicKey = (pk: Uint8Array): Uint8Array => { + return Uint8Array.from(js_sha512_256.array(pk).slice(HASH_BYTES_LENGTH - ALGORAND_CHECKSUM_BYTE_LENGTH, HASH_BYTES_LENGTH)) +} + +export const getApplicationAddress = (appId: internal.primitives.StubUint64Compat): Account => { + const toBeSigned = conactUint8Arrays(asUint8Array(APP_ID_PREFIX), encodingUtil.bigIntToUint8Array(asBigInt(appId), 8)) + const appIdHash = js_sha512_256.array(toBeSigned) + const publicKey = Uint8Array.from(appIdHash) + const address = encodeAddress(publicKey) + return AccountImpl(Bytes.fromBase32(address)) +} + +export const encodeAddress = (address: Uint8Array): string => { + const checksum = checksumFromPublicKey(address) + return encodingUtil.uint8ArrayToBase32(conactUint8Arrays(address, checksum)).slice(0, ALGORAND_ADDRESS_LENGTH) +} + +export const decodePublicKey = (address: string): Uint8Array => { + const decoded = encodingUtil.base32ToUint8Array(address) + return decoded.slice(0, ALGORAND_ADDRESS_BYTE_LENGTH - ALGORAND_CHECKSUM_BYTE_LENGTH) +} diff --git a/src/impl/transactions.ts b/src/impl/transactions.ts index d2d7573..3396054 100644 --- a/src/impl/transactions.ts +++ b/src/impl/transactions.ts @@ -16,6 +16,7 @@ import { lazyContext } from '../context-helpers/internal-context' import { toBytes } from '../encoders' import { Mutable, ObjectKeys } from '../typescript-helpers' import { asBytes, asMaybeBytesCls, asMaybeUint64Cls, asNumber, asUint64Cls, combineIntoMaxBytePages, getRandomBytes } from '../util' +import { AccountImpl, ApplicationImpl, AssetImpl } from './reference' const baseDefaultFields = () => ({ sender: lazyContext.defaultSender, @@ -27,7 +28,7 @@ const baseDefaultFields = () => ({ lease: Bytes(), groupIndex: Uint64(0), txnId: getRandomBytes(32).asAlgoTs(), - rekeyTo: Account(), + rekeyTo: AccountImpl(), }) export type TxnFields = Partial>>> @@ -90,9 +91,9 @@ export class PaymentTransaction extends TransactionBase implements gtxn.PaymentT protected constructor(fields: TxnFields) { super(fields) - this.receiver = fields.receiver ?? Account() + this.receiver = fields.receiver ?? AccountImpl() this.amount = fields.amount ?? Uint64(0) - this.closeRemainderTo = fields.closeRemainderTo ?? Account() + this.closeRemainderTo = fields.closeRemainderTo ?? AccountImpl() } readonly receiver: Account @@ -117,6 +118,12 @@ export class KeyRegistrationTransaction extends TransactionBase implements gtxn. this.voteKeyDilution = fields.voteKeyDilution ?? Uint64(0) this.nonparticipation = fields.nonparticipation ?? false this.stateProofKey = fields.stateProofKey ?? Bytes() + const globalData = lazyContext.ledger.globalData + if (this.fee >= globalData.payoutsGoOnlineFee && globalData.payoutsEnabled) { + lazyContext.ledger.patchAccountData(this.sender, { + incentiveEligible: true, + }) + } } readonly voteKey: bytes @@ -138,7 +145,7 @@ export class AssetConfigTransaction extends TransactionBase implements gtxn.Asse protected constructor(fields: TxnFields) { super(fields) - this.configAsset = fields.configAsset ?? Asset() + this.configAsset = fields.configAsset ?? AssetImpl() this.total = fields.total ?? Uint64(0) this.decimals = fields.decimals ?? Uint64(0) this.defaultFrozen = fields.defaultFrozen ?? false @@ -146,11 +153,11 @@ export class AssetConfigTransaction extends TransactionBase implements gtxn.Asse this.assetName = fields.assetName ?? Bytes() this.url = fields.url ?? Bytes() this.metadataHash = fields.metadataHash ?? Bytes() - this.manager = fields.manager ?? Account() - this.reserve = fields.reserve ?? Account() - this.freeze = fields.freeze ?? Account() - this.clawback = fields.clawback ?? Account() - this.createdAsset = fields.createdAsset ?? Asset() + this.manager = fields.manager ?? AccountImpl() + this.reserve = fields.reserve ?? AccountImpl() + this.freeze = fields.freeze ?? AccountImpl() + this.clawback = fields.clawback ?? AccountImpl() + this.createdAsset = fields.createdAsset ?? AssetImpl() } readonly configAsset: Asset @@ -178,11 +185,11 @@ export class AssetTransferTransaction extends TransactionBase implements gtxn.As protected constructor(fields: TxnFields) { super(fields) - this.xferAsset = fields.xferAsset ?? Asset() + this.xferAsset = fields.xferAsset ?? AssetImpl() this.assetAmount = fields.assetAmount ?? Uint64(0) - this.assetSender = fields.assetSender ?? Account() - this.assetReceiver = fields.assetReceiver ?? Account() - this.assetCloseTo = fields.assetCloseTo ?? Account() + this.assetSender = fields.assetSender ?? AccountImpl() + this.assetReceiver = fields.assetReceiver ?? AccountImpl() + this.assetCloseTo = fields.assetCloseTo ?? AccountImpl() } readonly xferAsset: Asset @@ -203,8 +210,8 @@ export class AssetFreezeTransaction extends TransactionBase implements gtxn.Asse protected constructor(fields: TxnFields) { super(fields) - this.freezeAsset = fields.freezeAsset ?? Asset() - this.freezeAccount = fields.freezeAccount ?? Account() + this.freezeAsset = fields.freezeAsset ?? AssetImpl() + this.freezeAccount = fields.freezeAccount ?? AccountImpl() this.frozen = fields.frozen ?? false } @@ -243,14 +250,14 @@ export class ApplicationTransaction extends TransactionBase implements gtxn.Appl protected constructor(fields: ApplicationTransactionFields) { super(fields) - this.appId = fields.appId ?? Application() + this.appId = fields.appId ?? ApplicationImpl() this.onCompletion = fields.onCompletion ?? 'NoOp' this.globalNumUint = fields.globalNumUint ?? Uint64(0) this.globalNumBytes = fields.globalNumBytes ?? Uint64(0) this.localNumUint = fields.localNumUint ?? Uint64(0) this.localNumBytes = fields.localNumBytes ?? Uint64(0) this.extraProgramPages = fields.extraProgramPages ?? Uint64(0) - this.createdApp = fields.createdApp ?? Application() + this.createdApp = fields.createdApp ?? ApplicationImpl() this.#appArgs = fields.appArgs ?? [] this.#appLogs = fields.appLogs ?? [] this.#accounts = fields.accounts ?? [] diff --git a/src/impl/voter-params.ts b/src/impl/voter-params.ts new file mode 100644 index 0000000..b0722d2 --- /dev/null +++ b/src/impl/voter-params.ts @@ -0,0 +1,29 @@ +import { Account, internal, uint64 } from '@algorandfoundation/algorand-typescript' +import { lazyContext } from '../context-helpers/internal-context' +import { getAccount } from './acct-params' + +export class VoterData { + balance: uint64 + incentiveEligible: boolean + + constructor() { + this.balance = 0 + this.incentiveEligible = false + } +} + +const getVoterData = (a: Account | internal.primitives.StubUint64Compat): VoterData => { + const acct = getAccount(a) + return lazyContext.getVoterData(acct) +} + +export const VoterParams: internal.opTypes.VoterParamsType = { + voterBalance: function (a: Account | internal.primitives.StubUint64Compat): readonly [uint64, boolean] { + const data = getVoterData(a) + return [data.balance, data.balance !== 0] + }, + voterIncentiveEligible: function (a: Account | internal.primitives.StubUint64Compat): readonly [boolean, boolean] { + const data = getVoterData(a) + return [data.incentiveEligible, data.balance !== 0] + }, +} diff --git a/src/runtime-helpers.ts b/src/runtime-helpers.ts index 3d7c5bf..097e1ca 100644 --- a/src/runtime-helpers.ts +++ b/src/runtime-helpers.ts @@ -2,8 +2,8 @@ import { internal } from '@algorandfoundation/algorand-typescript' import { ARC4Encoded } from '@algorandfoundation/algorand-typescript/arc4' import { MAX_UINT64 } from './constants' import type { TypeInfo } from './encoders' -import { AccountCls } from './impl/account' import { Uint64BackedCls } from './impl/base' +import { AccountCls } from './impl/reference' import { DeliberateAny } from './typescript-helpers' import { nameOfType } from './util' @@ -13,7 +13,9 @@ export { emitImpl } from './impl/emit' export * from './impl/encoded-types' export { decodeArc4Impl, encodeArc4Impl } from './impl/encoded-types' export { ensureBudgetImpl } from './impl/ensure-budget' +export { logImpl } from './impl/log' export { assertMatchImpl, matchImpl } from './impl/match' +export { AccountImpl, ApplicationImpl, AssetImpl } from './impl/reference' export { TemplateVarImpl } from './impl/template-var' export { urangeImpl } from './impl/urange' diff --git a/src/set-up.ts b/src/set-up.ts index b368ebb..202a496 100644 --- a/src/set-up.ts +++ b/src/set-up.ts @@ -1,7 +1,7 @@ import { internal } from '@algorandfoundation/algorand-typescript' import { Address } from '@algorandfoundation/algorand-typescript/arc4' import { encodingUtil } from '@algorandfoundation/puya-ts' -import { AccountCls } from './impl/account' +import { AccountCls } from './impl/reference' type Tester = (this: TesterContext, a: unknown, b: unknown, customTesters: Array) => boolean | undefined interface TesterContext { diff --git a/src/subcontexts/contract-context.ts b/src/subcontexts/contract-context.ts index 4603e5b..241e9cf 100644 --- a/src/subcontexts/contract-context.ts +++ b/src/subcontexts/contract-context.ts @@ -22,9 +22,7 @@ import { BytesMap } from '../collections/custom-key-map' import { checkRoutingConditions } from '../context-helpers/context-util' import { lazyContext } from '../context-helpers/internal-context' import { toBytes, type TypeInfo } from '../encoders' -import { AccountCls } from '../impl/account' -import { ApplicationCls } from '../impl/application' -import { AssetCls } from '../impl/asset' +import { AccountCls, ApplicationCls, AssetCls } from '../impl/reference' import { BoxCls, BoxMapCls, BoxRefCls, GlobalStateCls } from '../impl/state' import { ApplicationTransaction, diff --git a/src/subcontexts/ledger-context.ts b/src/subcontexts/ledger-context.ts index 1a1b0e0..db22093 100644 --- a/src/subcontexts/ledger-context.ts +++ b/src/subcontexts/ledger-context.ts @@ -1,18 +1,13 @@ import { Account, Application, Asset, BaseContract, bytes, internal, LocalStateForAccount } from '@algorandfoundation/algorand-typescript' import { AccountMap, Uint64Map } from '../collections/custom-key-map' import { MAX_UINT64 } from '../constants' -import { AccountData, AssetHolding } from '../impl/account' -import { ApplicationData } from '../impl/application' -import { AssetData } from '../impl/asset' +import { BlockData } from '../impl/block' import { GlobalData } from '../impl/global' +import { AccountData, AccountImpl, ApplicationData, ApplicationImpl, AssetData, AssetHolding, AssetImpl } from '../impl/reference' import { GlobalStateCls } from '../impl/state' +import { VoterData } from '../impl/voter-params' import { asBigInt, asMaybeBytesCls, asMaybeUint64Cls, asUint64, asUint64Cls, iterBigInt } from '../util' -interface BlockData { - seed: bigint - timestamp: bigint -} - export class LedgerContext { appIdIter = iterBigInt(1001n, MAX_UINT64) assetIdIter = iterBigInt(1001n, MAX_UINT64) @@ -20,8 +15,10 @@ export class LedgerContext { appIdContractMap = new Uint64Map() accountDataMap = new AccountMap() assetDataMap = new Uint64Map() + voterDataMap = new AccountMap() blocks = new Uint64Map() globalData = new GlobalData() + onlineStake = 0 /* @internal */ addAppIdContractMap(appId: internal.primitives.StubUint64Compat, contract: BaseContract): void { @@ -30,21 +27,21 @@ export class LedgerContext { getAccount(address: Account): Account { if (this.accountDataMap.has(address)) { - return Account(address.bytes) + return AccountImpl(address.bytes) } throw internal.errors.internalError('Unknown account, check correct testing context is active') } getAsset(assetId: internal.primitives.StubUint64Compat): Asset { if (this.assetDataMap.has(assetId)) { - return Asset(asUint64(assetId)) + return AssetImpl(asUint64(assetId)) } throw internal.errors.internalError('Unknown asset, check correct testing context is active') } getApplication(applicationId: internal.primitives.StubUint64Compat): Application { if (this.applicationDataMap.has(applicationId)) { - return Application(asUint64(applicationId)) + return ApplicationImpl(asUint64(applicationId)) } throw internal.errors.internalError('Unknown application, check correct testing context is active') } @@ -53,7 +50,7 @@ export class LedgerContext { for (const [appId, c] of this.appIdContractMap) { if (c === contract) { if (this.applicationDataMap.has(appId)) { - return Application(asUint64(appId)) + return ApplicationImpl(asUint64(appId)) } } } @@ -76,7 +73,7 @@ export class LedgerContext { if (found && next?.value) { const appId = asUint64(next.value[0]) if (this.applicationDataMap.has(appId)) { - return Application(appId) + return ApplicationImpl(appId) } } return undefined @@ -112,19 +109,36 @@ export class LedgerContext { } } - setBlock( - index: internal.primitives.StubUint64Compat, - seed: internal.primitives.StubUint64Compat, - timestamp: internal.primitives.StubUint64Compat, - ): void { - const i = asBigInt(index) - const s = asBigInt(seed) - const t = asBigInt(timestamp) + patchAccountData(account: Account, data: Partial) { + const accountData = this.accountDataMap.get(account) ?? new AccountData() + this.accountDataMap.set(account, { + ...accountData, + ...data, + account: { + ...accountData?.account, + ...data.account, + }, + }) + } - this.blocks.set(i, { seed: s, timestamp: t }) + patchVoterData(account: Account, data: Partial) { + const voterData = this.voterDataMap.get(account) ?? new VoterData() + this.voterDataMap.set(account, { + ...voterData, + ...data, + }) + } + + patchBlockData(index: internal.primitives.StubUint64Compat, data: Partial): void { + const i = asUint64(index) + const blockData = this.blocks.get(i) ?? new BlockData() + this.blocks.set(i, { + ...blockData, + ...data, + }) } - getBlockContent(index: internal.primitives.StubUint64Compat): BlockData { + getBlockData(index: internal.primitives.StubUint64Compat): BlockData { const i = asBigInt(index) if (this.blocks.has(i)) { return this.blocks.get(i)! diff --git a/src/test-execution-context.ts b/src/test-execution-context.ts index 2ab676c..002db4f 100644 --- a/src/test-execution-context.ts +++ b/src/test-execution-context.ts @@ -1,11 +1,8 @@ -import { Account, Application, Asset, BaseContract, bytes, internal, LogicSig, uint64 } from '@algorandfoundation/algorand-typescript' +import { Account, BaseContract, bytes, internal, LogicSig, uint64 } from '@algorandfoundation/algorand-typescript' import { captureMethodConfig } from './abi-metadata' import { DEFAULT_TEMPLATE_VAR_PREFIX } from './constants' import { DecodedLogs, LogDecoding } from './decode-logs' import * as ops from './impl' -import { AccountCls } from './impl/account' -import { ApplicationCls } from './impl/application' -import { AssetCls } from './impl/asset' import { applicationCall as itxnApplicationCall, assetConfig as itxnAssetConfig, @@ -15,6 +12,7 @@ import { payment as itxnPayment, submitGroup as itxnSubmitGroup, } from './impl/inner-transactions' +import { AccountImpl } from './impl/reference' import { Box, BoxMap, BoxRef, GlobalState, LocalState } from './impl/state' import { ContractContext } from './subcontexts/contract-context' import { LedgerContext } from './subcontexts/ledger-context' @@ -40,30 +38,10 @@ export class TestExecutionContext implements internal.ExecutionContext { this.#ledgerContext = new LedgerContext() this.#txnContext = new TransactionContext() this.#valueGenerator = new ValueGenerator() - this.#defaultSender = Account(defaultSenderAddress ?? getRandomBytes(32).asAlgoTs()) + this.#defaultSender = AccountImpl(defaultSenderAddress ?? getRandomBytes(32).asAlgoTs()) this.#activeLogicSigArgs = [] } - /* @internal */ - account(address?: bytes): Account { - return new AccountCls(address) - } - - /* @internal */ - application(id?: uint64): Application { - return new ApplicationCls(id) - } - - /* @internal */ - asset(id?: uint64): Asset { - return new AssetCls(id) - } - - /* @internal */ - log(value: bytes): void { - this.txn.appendLog(value) - } - exportLogs(appId: uint64, ...decoding: T): DecodedLogs { return this.txn.exportLogs(appId, ...decoding) } diff --git a/src/test-transformer/visitors.ts b/src/test-transformer/visitors.ts index d4571b2..bcc2aa9 100644 --- a/src/test-transformer/visitors.ts +++ b/src/test-transformer/visitors.ts @@ -325,8 +325,8 @@ const isArc4EncodedType = (type: ptypes.PType): boolean => ptypes.UFixedNxMType, ptypes.UintNType, ) || - type === ptypes.ARC4StringType || - type === ptypes.ARC4BooleanType + type === ptypes.arc4StringType || + type === ptypes.arc4BooleanType const getGenericTypeInfo = (type: ptypes.PType): TypeInfo => { let typeName = type?.name ?? type?.toString() ?? 'unknown' @@ -388,6 +388,10 @@ const tryGetStubbedFunctionName = (node: ts.CallExpression, helper: VisitorHelpe 'urange', 'match', 'assertMatch', + 'Account', + 'Application', + 'Asset', + 'log', ] return stubbedFunctionNames.includes(functionName) ? functionName : undefined } diff --git a/src/util.ts b/src/util.ts index babf8f0..60c7743 100644 --- a/src/util.ts +++ b/src/util.ts @@ -1,19 +1,6 @@ -import { Account, Bytes, bytes, internal } from '@algorandfoundation/algorand-typescript' -import { encodingUtil } from '@algorandfoundation/puya-ts' +import { Bytes, bytes, internal } from '@algorandfoundation/algorand-typescript' import { randomBytes } from 'crypto' -import { sha512_256 as js_sha512_256 } from 'js-sha512' -import { - ALGORAND_ADDRESS_BYTE_LENGTH, - ALGORAND_ADDRESS_LENGTH, - ALGORAND_CHECKSUM_BYTE_LENGTH, - APP_ID_PREFIX, - BITS_IN_BYTE, - HASH_BYTES_LENGTH, - MAX_BYTES_SIZE, - MAX_UINT512, - MAX_UINT8, - UINT512_SIZE, -} from './constants' +import { BITS_IN_BYTE, MAX_BYTES_SIZE, MAX_UINT512, MAX_UINT8, UINT512_SIZE } from './constants' import { DeliberateAny } from './typescript-helpers' export const nameOfType = (x: unknown) => { @@ -170,25 +157,3 @@ export const conactUint8Arrays = (...values: Uint8Array[]): Uint8Array => { export const uint8ArrayToNumber = (value: Uint8Array): number => { return value.reduce((acc, x) => acc * 256 + x, 0) } - -export const checksumFromPublicKey = (pk: Uint8Array): Uint8Array => { - return Uint8Array.from(js_sha512_256.array(pk).slice(HASH_BYTES_LENGTH - ALGORAND_CHECKSUM_BYTE_LENGTH, HASH_BYTES_LENGTH)) -} - -export const getApplicationAddress = (appId: internal.primitives.StubUint64Compat): Account => { - const toBeSigned = conactUint8Arrays(asUint8Array(APP_ID_PREFIX), encodingUtil.bigIntToUint8Array(asBigInt(appId), 8)) - const appIdHash = js_sha512_256.array(toBeSigned) - const publicKey = Uint8Array.from(appIdHash) - const address = encodeAddress(publicKey) - return Account(Bytes.fromBase32(address)) -} - -export const encodeAddress = (address: Uint8Array): string => { - const checksum = checksumFromPublicKey(address) - return encodingUtil.uint8ArrayToBase32(conactUint8Arrays(address, checksum)).slice(0, ALGORAND_ADDRESS_LENGTH) -} - -export const decodePublicKey = (address: string): Uint8Array => { - const decoded = encodingUtil.base32ToUint8Array(address) - return decoded.slice(0, ALGORAND_ADDRESS_BYTE_LENGTH - ALGORAND_CHECKSUM_BYTE_LENGTH) -} diff --git a/src/value-generators/avm.ts b/src/value-generators/avm.ts index a3cca0f..8ef5897 100644 --- a/src/value-generators/avm.ts +++ b/src/value-generators/avm.ts @@ -2,13 +2,12 @@ import { Account, Application, Asset, bytes, Bytes, internal, Uint64, uint64 } f import { randomBytes } from 'crypto' import { MAX_BYTES_SIZE, MAX_UINT64, ZERO_ADDRESS } from '../constants' import { lazyContext } from '../context-helpers/internal-context' -import { AccountData } from '../impl/account' -import { ApplicationCls, ApplicationData } from '../impl/application' -import { AssetCls, AssetData } from '../impl/asset' +import { AccountData, AccountImpl, ApplicationCls, ApplicationData, AssetCls, AssetData } from '../impl/reference' import { asBigInt, asUint64Cls, getRandomBigInt, getRandomBytes } from '../util' type AccountContextData = Partial & { address?: Account + incentiveEligible?: boolean optedAssetBalances?: Map optedApplications?: Application[] } @@ -47,7 +46,7 @@ export class AvmValueGenerator { } account(input?: AccountContextData): Account { - const account = input?.address ?? Account(getRandomBytes(32).asAlgoTs()) + const account = input?.address ?? AccountImpl(getRandomBytes(32).asAlgoTs()) if (input?.address && lazyContext.ledger.accountDataMap.has(account)) { internal.errors.internalError( @@ -56,7 +55,8 @@ export class AvmValueGenerator { } const data = new AccountData() - const { address, optedAssetBalances, optedApplications, ...accountData } = input ?? {} + const { address, optedAssetBalances, optedApplications, incentiveEligible, ...accountData } = input ?? {} + data.incentiveEligible = incentiveEligible ?? false data.account = { ...data.account, ...accountData, @@ -90,11 +90,11 @@ export class AvmValueGenerator { name: lazyContext.any.bytes(32), url: lazyContext.any.bytes(10), metadataHash: lazyContext.any.bytes(32), - manager: Account(ZERO_ADDRESS), - freeze: Account(ZERO_ADDRESS), - clawback: Account(ZERO_ADDRESS), + manager: AccountImpl(ZERO_ADDRESS), + freeze: AccountImpl(ZERO_ADDRESS), + clawback: AccountImpl(ZERO_ADDRESS), creator: lazyContext.defaultSender, - reserve: Account(ZERO_ADDRESS), + reserve: AccountImpl(ZERO_ADDRESS), } const { assetId: _, ...assetData } = input ?? {} lazyContext.ledger.assetDataMap.set(assetId, { diff --git a/tests/arc4/address.spec.ts b/tests/arc4/address.spec.ts index c18c23b..de76052 100644 --- a/tests/arc4/address.spec.ts +++ b/tests/arc4/address.spec.ts @@ -4,7 +4,8 @@ import { TestExecutionContext } from '@algorandfoundation/algorand-typescript-te import { Address, interpretAsArc4 } from '@algorandfoundation/algorand-typescript/arc4' import { afterEach, describe, expect, test } from 'vitest' import { ABI_RETURN_VALUE_LOG_PREFIX } from '../../src/constants' -import { asUint8Array, encodeAddress } from '../../src/util' +import { encodeAddress } from '../../src/impl/reference' +import { asUint8Array } from '../../src/util' const abiTypeString = 'address' const testData = [ diff --git a/tests/arc4/dynamic-array.spec.ts b/tests/arc4/dynamic-array.spec.ts index ee70df1..3adfc57 100644 --- a/tests/arc4/dynamic-array.spec.ts +++ b/tests/arc4/dynamic-array.spec.ts @@ -15,7 +15,7 @@ import { } from '@algorandfoundation/algorand-typescript/arc4' import { encodingUtil } from '@algorandfoundation/puya-ts' import { afterEach, describe, expect, it, test } from 'vitest' -import { AccountCls } from '../../src/impl/account' +import { AccountCls } from '../../src/impl/reference' import { DeliberateAny } from '../../src/typescript-helpers' import { asBytes, asUint8Array } from '../../src/util' diff --git a/tests/arc4/static-array.spec.ts b/tests/arc4/static-array.spec.ts index 53e6e4c..217088a 100644 --- a/tests/arc4/static-array.spec.ts +++ b/tests/arc4/static-array.spec.ts @@ -15,7 +15,7 @@ import { } from '@algorandfoundation/algorand-typescript/arc4' import { encodingUtil } from '@algorandfoundation/puya-ts' import { afterEach, describe, expect, it, test } from 'vitest' -import { AccountCls } from '../../src/impl/account' +import { AccountCls } from '../../src/impl/reference' import { DeliberateAny } from '../../src/typescript-helpers' import { asBytes, asUint8Array } from '../../src/util' diff --git a/tests/arc4/struct.spec.ts b/tests/arc4/struct.spec.ts index 64cdc04..d71e95a 100644 --- a/tests/arc4/struct.spec.ts +++ b/tests/arc4/struct.spec.ts @@ -3,7 +3,7 @@ import { Bytes, internal } from '@algorandfoundation/algorand-typescript' import { Bool, DynamicArray, interpretAsArc4, StaticArray, Str, Struct, Tuple, UintN } from '@algorandfoundation/algorand-typescript/arc4' import { encodingUtil } from '@algorandfoundation/puya-ts' import { describe, expect, it, test } from 'vitest' -import { AccountCls } from '../../src/impl/account' +import { AccountCls } from '../../src/impl/reference' import { DeliberateAny } from '../../src/typescript-helpers' import { asBytes } from '../../src/util' diff --git a/tests/arc4/tuple.spec.ts b/tests/arc4/tuple.spec.ts index d4cc2a4..ca76519 100644 --- a/tests/arc4/tuple.spec.ts +++ b/tests/arc4/tuple.spec.ts @@ -4,7 +4,7 @@ import { TestExecutionContext } from '@algorandfoundation/algorand-typescript-te import { Address, Bool, DynamicArray, interpretAsArc4, StaticArray, Str, Tuple, UintN } from '@algorandfoundation/algorand-typescript/arc4' import { encodingUtil } from '@algorandfoundation/puya-ts' import { afterEach, describe, expect, test } from 'vitest' -import { AccountCls } from '../../src/impl/account' +import { AccountCls } from '../../src/impl/reference' import { DeliberateAny } from '../../src/typescript-helpers' import { asBytes, asUint8Array } from '../../src/util' diff --git a/tests/artifacts/state-ops/contract.algo.ts b/tests/artifacts/state-ops/contract.algo.ts index ac97863..0e2e9eb 100644 --- a/tests/artifacts/state-ops/contract.algo.ts +++ b/tests/artifacts/state-ops/contract.algo.ts @@ -23,122 +23,6 @@ function get_1st_ref_index(): uint64 { return op.btoi(Txn.applicationArgs(1)) } -export class StateAcctParamsGetContract extends arc4.Contract { - @arc4.abimethod() - public verify_acct_balance(a: Account): uint64 { - const [value, funded] = op.AcctParams.acctBalance(a) - const [value_index, funded_index] = op.AcctParams.acctBalance(get_1st_ref_index()) - assert(value === value_index, 'expected value by index to match') - assert(funded === funded_index, 'expected funded by index to match') - assert(value === a.balance, 'expected Account balance to match') - assert(value === op.balance(a), 'expected op.balance to match') - assert(value === op.balance(get_1st_ref_index()), 'expected op.balance by index to match') - return value - } - - @arc4.abimethod() - public verify_acct_min_balance(a: Account): uint64 { - const [value, funded] = op.AcctParams.acctMinBalance(a) - const [value_index, funded_index] = op.AcctParams.acctMinBalance(get_1st_ref_index()) - assert(value === value_index, 'expected value by index to match') - assert(funded === funded_index, 'expected funded by index to match') - assert(value === a.minBalance, 'expected Account min_balance to match') - assert(value === op.minBalance(a), 'expected op.min_balance to match') - assert(value === op.minBalance(get_1st_ref_index()), 'expected op.min_balance by index to match') - return value - } - - @arc4.abimethod() - public verify_acct_auth_addr(a: Account): Address { - const [value, funded] = op.AcctParams.acctAuthAddr(a) - const [value_index, funded_index] = op.AcctParams.acctAuthAddr(get_1st_ref_index()) - assert(value === value_index, 'expected value by index to match') - assert(funded === funded_index, 'expected funded by index to match') - return new Address(value) - } - - @arc4.abimethod() - public verify_acct_total_num_uint(a: Account): uint64 { - const [value, funded] = op.AcctParams.acctTotalNumUint(a) - const [value_index, funded_index] = op.AcctParams.acctTotalNumUint(get_1st_ref_index()) - assert(value === value_index, 'expected value by index to match') - assert(funded === funded_index, 'expected funded by index to match') - return value - } - - @arc4.abimethod() - public verify_acct_total_num_byte_slice(a: Account): uint64 { - const [value, funded] = op.AcctParams.acctTotalNumByteSlice(a) - const [value_index, funded_index] = op.AcctParams.acctTotalNumByteSlice(get_1st_ref_index()) - assert(value === value_index, 'expected value by index to match') - assert(funded === funded_index, 'expected funded by index to match') - return value - } - - @arc4.abimethod() - public verify_acct_total_extra_app_pages(a: Account): uint64 { - const [value, funded] = op.AcctParams.acctTotalExtraAppPages(a) - const [value_index, funded_index] = op.AcctParams.acctTotalExtraAppPages(get_1st_ref_index()) - assert(value === value_index, 'expected value by index to match') - assert(funded === funded_index, 'expected funded by index to match') - return value - } - - @arc4.abimethod() - public verify_acct_total_apps_created(a: Account): uint64 { - const [value, funded] = op.AcctParams.acctTotalAppsCreated(a) - const [value_index, funded_index] = op.AcctParams.acctTotalAppsCreated(get_1st_ref_index()) - assert(value === value_index, 'expected value by index to match') - assert(funded === funded_index, 'expected funded by index to match') - return value - } - - @arc4.abimethod() - public verify_acct_total_apps_opted_in(a: Account): uint64 { - const [value, funded] = op.AcctParams.acctTotalAppsOptedIn(a) - const [value_index, funded_index] = op.AcctParams.acctTotalAppsOptedIn(get_1st_ref_index()) - assert(value === value_index, 'expected value by index to match') - assert(funded === funded_index, 'expected funded by index to match') - return value - } - - @arc4.abimethod() - public verify_acct_total_assets_created(a: Account): uint64 { - const [value, funded] = op.AcctParams.acctTotalAssetsCreated(a) - const [value_index, funded_index] = op.AcctParams.acctTotalAssetsCreated(get_1st_ref_index()) - assert(value === value_index, 'expected value by index to match') - assert(funded === funded_index, 'expected funded by index to match') - return value - } - - @arc4.abimethod() - public verify_acct_total_assets(a: Account): uint64 { - const [value, funded] = op.AcctParams.acctTotalAssets(a) - const [value_index, funded_index] = op.AcctParams.acctTotalAssets(get_1st_ref_index()) - assert(value === value_index, 'expected value by index to match') - assert(funded === funded_index, 'expected funded by index to match') - return value - } - - @arc4.abimethod() - public verify_acct_total_boxes(a: Account): uint64 { - const [value, funded] = op.AcctParams.acctTotalBoxes(a) - const [value_index, funded_index] = op.AcctParams.acctTotalBoxes(get_1st_ref_index()) - assert(value === value_index, 'expected value by index to match') - assert(funded === funded_index, 'expected funded by index to match') - return value - } - - @arc4.abimethod() - public verify_acct_total_box_bytes(a: Account): uint64 { - const [value, funded] = op.AcctParams.acctTotalBoxBytes(a) - const [value_index, funded_index] = op.AcctParams.acctTotalBoxBytes(get_1st_ref_index()) - assert(value === value_index, 'expected value by index to match') - assert(funded === funded_index, 'expected funded by index to match') - return value - } -} - export class StateAssetHoldingContract extends arc4.Contract { @arc4.abimethod() public verify_asset_holding_get(a: Account, b: Asset): uint64 { diff --git a/tests/artifacts/state-ops/data/StateAcctParamsGetContract.approval.teal b/tests/artifacts/state-ops/data/StateAcctParamsGetContract.approval.teal index dceec00..d7a94a4 100644 --- a/tests/artifacts/state-ops/data/StateAcctParamsGetContract.approval.teal +++ b/tests/artifacts/state-ops/data/StateAcctParamsGetContract.approval.teal @@ -1,182 +1,185 @@ -#pragma version 10 +#pragma version 11 +#pragma typetrack false -tests/artifacts/state-ops/contract.algo.ts::StateAcctParamsGetContract.approvalProgram: +// @algorandfoundation/algorand-typescript/arc4/index.d.ts::Contract.approvalProgram() -> uint64: +main: intcblock 1 0 bytecblock 0x151f7c75 - callsub __puya_arc4_router__ - return - - -// tests/artifacts/state-ops/contract.algo.ts::StateAcctParamsGetContract.__puya_arc4_router__() -> uint64: -__puya_arc4_router__: - // tests/artifacts/state-ops/contract.algo.ts:26 + // tests/artifacts/state-ops/state-acct-params-get-contract.algo.ts:8 // export class StateAcctParamsGetContract extends arc4.Contract { - proto 0 1 txn NumAppArgs - bz __puya_arc4_router___bare_routing@16 - pushbytess 0x5f5b43e4 0x73dc93c7 0x5626dfeb 0xdc8a25bf 0x198ebd8c 0x2301ab26 0x9f68fca6 0xa975c2d1 0xd1e04801 0xb6966be5 0x195d5418 0x6adae3f1 // method "verify_acct_balance(account)uint64", method "verify_acct_min_balance(account)uint64", method "verify_acct_auth_addr(account)address", method "verify_acct_total_num_uint(account)uint64", method "verify_acct_total_num_byte_slice(account)uint64", method "verify_acct_total_extra_app_pages(account)uint64", method "verify_acct_total_apps_created(account)uint64", method "verify_acct_total_apps_opted_in(account)uint64", method "verify_acct_total_assets_created(account)uint64", method "verify_acct_total_assets(account)uint64", method "verify_acct_total_boxes(account)uint64", method "verify_acct_total_box_bytes(account)uint64" + bz main_bare_routing@18 + pushbytess 0x5f5b43e4 0x73dc93c7 0x5626dfeb 0xdc8a25bf 0x198ebd8c 0x2301ab26 0x9f68fca6 0xa975c2d1 0xd1e04801 0xb6966be5 0x195d5418 0x6adae3f1 0xdf8cfee5 // method "verify_acct_balance(account)uint64", method "verify_acct_min_balance(account)uint64", method "verify_acct_auth_addr(account)address", method "verify_acct_total_num_uint(account)uint64", method "verify_acct_total_num_byte_slice(account)uint64", method "verify_acct_total_extra_app_pages(account)uint64", method "verify_acct_total_apps_created(account)uint64", method "verify_acct_total_apps_opted_in(account)uint64", method "verify_acct_total_assets_created(account)uint64", method "verify_acct_total_assets(account)uint64", method "verify_acct_total_boxes(account)uint64", method "verify_acct_total_box_bytes(account)uint64", method "verify_acct_incentive_eligible(account)bool" txna ApplicationArgs 0 - match __puya_arc4_router___verify_acct_balance_route@2 __puya_arc4_router___verify_acct_min_balance_route@3 __puya_arc4_router___verify_acct_auth_addr_route@4 __puya_arc4_router___verify_acct_total_num_uint_route@5 __puya_arc4_router___verify_acct_total_num_byte_slice_route@6 __puya_arc4_router___verify_acct_total_extra_app_pages_route@7 __puya_arc4_router___verify_acct_total_apps_created_route@8 __puya_arc4_router___verify_acct_total_apps_opted_in_route@9 __puya_arc4_router___verify_acct_total_assets_created_route@10 __puya_arc4_router___verify_acct_total_assets_route@11 __puya_arc4_router___verify_acct_total_boxes_route@12 __puya_arc4_router___verify_acct_total_box_bytes_route@13 + match main_verify_acct_balance_route@3 main_verify_acct_min_balance_route@4 main_verify_acct_auth_addr_route@5 main_verify_acct_total_num_uint_route@6 main_verify_acct_total_num_byte_slice_route@7 main_verify_acct_total_extra_app_pages_route@8 main_verify_acct_total_apps_created_route@9 main_verify_acct_total_apps_opted_in_route@10 main_verify_acct_total_assets_created_route@11 main_verify_acct_total_assets_route@12 main_verify_acct_total_boxes_route@13 main_verify_acct_total_box_bytes_route@14 main_verify_acct_incentive_eligible_route@15 + +main_after_if_else@22: + // tests/artifacts/state-ops/state-acct-params-get-contract.algo.ts:8 + // export class StateAcctParamsGetContract extends arc4.Contract { intc_1 // 0 - retsub + return -__puya_arc4_router___verify_acct_balance_route@2: - // tests/artifacts/state-ops/contract.algo.ts:27 +main_verify_acct_incentive_eligible_route@15: + // tests/artifacts/state-ops/state-acct-params-get-contract.algo.ts:123 // @arc4.abimethod() txn OnCompletion ! assert // OnCompletion is not NoOp txn ApplicationID assert // can only call when not creating - // tests/artifacts/state-ops/contract.algo.ts:26 + // tests/artifacts/state-ops/state-acct-params-get-contract.algo.ts:8 // export class StateAcctParamsGetContract extends arc4.Contract { txna ApplicationArgs 1 btoi txnas Accounts - // tests/artifacts/state-ops/contract.algo.ts:27 + // tests/artifacts/state-ops/state-acct-params-get-contract.algo.ts:123 // @arc4.abimethod() - callsub verify_acct_balance - itob + callsub verify_acct_incentive_eligible + pushbytes 0x00 + intc_1 // 0 + uncover 2 + setbit bytec_0 // 0x151f7c75 swap concat log intc_0 // 1 - retsub + return -__puya_arc4_router___verify_acct_min_balance_route@3: - // tests/artifacts/state-ops/contract.algo.ts:39 +main_verify_acct_total_box_bytes_route@14: + // tests/artifacts/state-ops/state-acct-params-get-contract.algo.ts:114 // @arc4.abimethod() txn OnCompletion ! assert // OnCompletion is not NoOp txn ApplicationID assert // can only call when not creating - // tests/artifacts/state-ops/contract.algo.ts:26 + // tests/artifacts/state-ops/state-acct-params-get-contract.algo.ts:8 // export class StateAcctParamsGetContract extends arc4.Contract { txna ApplicationArgs 1 btoi txnas Accounts - // tests/artifacts/state-ops/contract.algo.ts:39 + // tests/artifacts/state-ops/state-acct-params-get-contract.algo.ts:114 // @arc4.abimethod() - callsub verify_acct_min_balance + callsub verify_acct_total_box_bytes itob bytec_0 // 0x151f7c75 swap concat log intc_0 // 1 - retsub + return -__puya_arc4_router___verify_acct_auth_addr_route@4: - // tests/artifacts/state-ops/contract.algo.ts:51 +main_verify_acct_total_boxes_route@13: + // tests/artifacts/state-ops/state-acct-params-get-contract.algo.ts:105 // @arc4.abimethod() txn OnCompletion ! assert // OnCompletion is not NoOp txn ApplicationID assert // can only call when not creating - // tests/artifacts/state-ops/contract.algo.ts:26 + // tests/artifacts/state-ops/state-acct-params-get-contract.algo.ts:8 // export class StateAcctParamsGetContract extends arc4.Contract { txna ApplicationArgs 1 btoi txnas Accounts - // tests/artifacts/state-ops/contract.algo.ts:51 + // tests/artifacts/state-ops/state-acct-params-get-contract.algo.ts:105 // @arc4.abimethod() - callsub verify_acct_auth_addr + callsub verify_acct_total_boxes + itob bytec_0 // 0x151f7c75 swap concat log intc_0 // 1 - retsub + return -__puya_arc4_router___verify_acct_total_num_uint_route@5: - // tests/artifacts/state-ops/contract.algo.ts:60 +main_verify_acct_total_assets_route@12: + // tests/artifacts/state-ops/state-acct-params-get-contract.algo.ts:96 // @arc4.abimethod() txn OnCompletion ! assert // OnCompletion is not NoOp txn ApplicationID assert // can only call when not creating - // tests/artifacts/state-ops/contract.algo.ts:26 + // tests/artifacts/state-ops/state-acct-params-get-contract.algo.ts:8 // export class StateAcctParamsGetContract extends arc4.Contract { txna ApplicationArgs 1 btoi txnas Accounts - // tests/artifacts/state-ops/contract.algo.ts:60 + // tests/artifacts/state-ops/state-acct-params-get-contract.algo.ts:96 // @arc4.abimethod() - callsub verify_acct_total_num_uint + callsub verify_acct_total_assets itob bytec_0 // 0x151f7c75 swap concat log intc_0 // 1 - retsub + return -__puya_arc4_router___verify_acct_total_num_byte_slice_route@6: - // tests/artifacts/state-ops/contract.algo.ts:69 +main_verify_acct_total_assets_created_route@11: + // tests/artifacts/state-ops/state-acct-params-get-contract.algo.ts:87 // @arc4.abimethod() txn OnCompletion ! assert // OnCompletion is not NoOp txn ApplicationID assert // can only call when not creating - // tests/artifacts/state-ops/contract.algo.ts:26 + // tests/artifacts/state-ops/state-acct-params-get-contract.algo.ts:8 // export class StateAcctParamsGetContract extends arc4.Contract { txna ApplicationArgs 1 btoi txnas Accounts - // tests/artifacts/state-ops/contract.algo.ts:69 + // tests/artifacts/state-ops/state-acct-params-get-contract.algo.ts:87 // @arc4.abimethod() - callsub verify_acct_total_num_byte_slice + callsub verify_acct_total_assets_created itob bytec_0 // 0x151f7c75 swap concat log intc_0 // 1 - retsub + return -__puya_arc4_router___verify_acct_total_extra_app_pages_route@7: - // tests/artifacts/state-ops/contract.algo.ts:78 +main_verify_acct_total_apps_opted_in_route@10: + // tests/artifacts/state-ops/state-acct-params-get-contract.algo.ts:78 // @arc4.abimethod() txn OnCompletion ! assert // OnCompletion is not NoOp txn ApplicationID assert // can only call when not creating - // tests/artifacts/state-ops/contract.algo.ts:26 + // tests/artifacts/state-ops/state-acct-params-get-contract.algo.ts:8 // export class StateAcctParamsGetContract extends arc4.Contract { txna ApplicationArgs 1 btoi txnas Accounts - // tests/artifacts/state-ops/contract.algo.ts:78 + // tests/artifacts/state-ops/state-acct-params-get-contract.algo.ts:78 // @arc4.abimethod() - callsub verify_acct_total_extra_app_pages + callsub verify_acct_total_apps_opted_in itob bytec_0 // 0x151f7c75 swap concat log intc_0 // 1 - retsub + return -__puya_arc4_router___verify_acct_total_apps_created_route@8: - // tests/artifacts/state-ops/contract.algo.ts:87 +main_verify_acct_total_apps_created_route@9: + // tests/artifacts/state-ops/state-acct-params-get-contract.algo.ts:69 // @arc4.abimethod() txn OnCompletion ! assert // OnCompletion is not NoOp txn ApplicationID assert // can only call when not creating - // tests/artifacts/state-ops/contract.algo.ts:26 + // tests/artifacts/state-ops/state-acct-params-get-contract.algo.ts:8 // export class StateAcctParamsGetContract extends arc4.Contract { txna ApplicationArgs 1 btoi txnas Accounts - // tests/artifacts/state-ops/contract.algo.ts:87 + // tests/artifacts/state-ops/state-acct-params-get-contract.algo.ts:69 // @arc4.abimethod() callsub verify_acct_total_apps_created itob @@ -185,546 +188,633 @@ __puya_arc4_router___verify_acct_total_apps_created_route@8: concat log intc_0 // 1 - retsub + return -__puya_arc4_router___verify_acct_total_apps_opted_in_route@9: - // tests/artifacts/state-ops/contract.algo.ts:96 +main_verify_acct_total_extra_app_pages_route@8: + // tests/artifacts/state-ops/state-acct-params-get-contract.algo.ts:60 // @arc4.abimethod() txn OnCompletion ! assert // OnCompletion is not NoOp txn ApplicationID assert // can only call when not creating - // tests/artifacts/state-ops/contract.algo.ts:26 + // tests/artifacts/state-ops/state-acct-params-get-contract.algo.ts:8 // export class StateAcctParamsGetContract extends arc4.Contract { txna ApplicationArgs 1 btoi txnas Accounts - // tests/artifacts/state-ops/contract.algo.ts:96 + // tests/artifacts/state-ops/state-acct-params-get-contract.algo.ts:60 // @arc4.abimethod() - callsub verify_acct_total_apps_opted_in + callsub verify_acct_total_extra_app_pages itob bytec_0 // 0x151f7c75 swap concat log intc_0 // 1 - retsub + return -__puya_arc4_router___verify_acct_total_assets_created_route@10: - // tests/artifacts/state-ops/contract.algo.ts:105 +main_verify_acct_total_num_byte_slice_route@7: + // tests/artifacts/state-ops/state-acct-params-get-contract.algo.ts:51 // @arc4.abimethod() txn OnCompletion ! assert // OnCompletion is not NoOp txn ApplicationID assert // can only call when not creating - // tests/artifacts/state-ops/contract.algo.ts:26 + // tests/artifacts/state-ops/state-acct-params-get-contract.algo.ts:8 // export class StateAcctParamsGetContract extends arc4.Contract { txna ApplicationArgs 1 btoi txnas Accounts - // tests/artifacts/state-ops/contract.algo.ts:105 + // tests/artifacts/state-ops/state-acct-params-get-contract.algo.ts:51 // @arc4.abimethod() - callsub verify_acct_total_assets_created + callsub verify_acct_total_num_byte_slice itob bytec_0 // 0x151f7c75 swap concat log intc_0 // 1 - retsub + return -__puya_arc4_router___verify_acct_total_assets_route@11: - // tests/artifacts/state-ops/contract.algo.ts:114 +main_verify_acct_total_num_uint_route@6: + // tests/artifacts/state-ops/state-acct-params-get-contract.algo.ts:42 // @arc4.abimethod() txn OnCompletion ! assert // OnCompletion is not NoOp txn ApplicationID assert // can only call when not creating - // tests/artifacts/state-ops/contract.algo.ts:26 + // tests/artifacts/state-ops/state-acct-params-get-contract.algo.ts:8 // export class StateAcctParamsGetContract extends arc4.Contract { txna ApplicationArgs 1 btoi txnas Accounts - // tests/artifacts/state-ops/contract.algo.ts:114 + // tests/artifacts/state-ops/state-acct-params-get-contract.algo.ts:42 // @arc4.abimethod() - callsub verify_acct_total_assets + callsub verify_acct_total_num_uint itob bytec_0 // 0x151f7c75 swap concat log intc_0 // 1 - retsub + return -__puya_arc4_router___verify_acct_total_boxes_route@12: - // tests/artifacts/state-ops/contract.algo.ts:123 +main_verify_acct_auth_addr_route@5: + // tests/artifacts/state-ops/state-acct-params-get-contract.algo.ts:33 // @arc4.abimethod() txn OnCompletion ! assert // OnCompletion is not NoOp txn ApplicationID assert // can only call when not creating - // tests/artifacts/state-ops/contract.algo.ts:26 + // tests/artifacts/state-ops/state-acct-params-get-contract.algo.ts:8 // export class StateAcctParamsGetContract extends arc4.Contract { txna ApplicationArgs 1 btoi txnas Accounts - // tests/artifacts/state-ops/contract.algo.ts:123 + // tests/artifacts/state-ops/state-acct-params-get-contract.algo.ts:33 // @arc4.abimethod() - callsub verify_acct_total_boxes + callsub verify_acct_auth_addr + bytec_0 // 0x151f7c75 + swap + concat + log + intc_0 // 1 + return + +main_verify_acct_min_balance_route@4: + // tests/artifacts/state-ops/state-acct-params-get-contract.algo.ts:21 + // @arc4.abimethod() + txn OnCompletion + ! + assert // OnCompletion is not NoOp + txn ApplicationID + assert // can only call when not creating + // tests/artifacts/state-ops/state-acct-params-get-contract.algo.ts:8 + // export class StateAcctParamsGetContract extends arc4.Contract { + txna ApplicationArgs 1 + btoi + txnas Accounts + // tests/artifacts/state-ops/state-acct-params-get-contract.algo.ts:21 + // @arc4.abimethod() + callsub verify_acct_min_balance itob bytec_0 // 0x151f7c75 swap concat log intc_0 // 1 - retsub + return -__puya_arc4_router___verify_acct_total_box_bytes_route@13: - // tests/artifacts/state-ops/contract.algo.ts:132 +main_verify_acct_balance_route@3: + // tests/artifacts/state-ops/state-acct-params-get-contract.algo.ts:9 // @arc4.abimethod() txn OnCompletion ! assert // OnCompletion is not NoOp txn ApplicationID assert // can only call when not creating - // tests/artifacts/state-ops/contract.algo.ts:26 + // tests/artifacts/state-ops/state-acct-params-get-contract.algo.ts:8 // export class StateAcctParamsGetContract extends arc4.Contract { txna ApplicationArgs 1 btoi txnas Accounts - // tests/artifacts/state-ops/contract.algo.ts:132 + // tests/artifacts/state-ops/state-acct-params-get-contract.algo.ts:9 // @arc4.abimethod() - callsub verify_acct_total_box_bytes + callsub verify_acct_balance itob bytec_0 // 0x151f7c75 swap concat log intc_0 // 1 - retsub + return -__puya_arc4_router___bare_routing@16: - // tests/artifacts/state-ops/contract.algo.ts:26 +main_bare_routing@18: + // tests/artifacts/state-ops/state-acct-params-get-contract.algo.ts:8 // export class StateAcctParamsGetContract extends arc4.Contract { txn OnCompletion - bnz __puya_arc4_router___after_if_else@20 + bnz main_after_if_else@22 txn ApplicationID ! assert // can only call when creating intc_0 // 1 - retsub - -__puya_arc4_router___after_if_else@20: - // tests/artifacts/state-ops/contract.algo.ts:26 - // export class StateAcctParamsGetContract extends arc4.Contract { - intc_1 // 0 - retsub + return -// tests/artifacts/state-ops/contract.algo.ts::StateAcctParamsGetContract.verify_acct_balance(a: bytes) -> uint64: +// tests/artifacts/state-ops/state-acct-params-get-contract.algo.ts::StateAcctParamsGetContract.verify_acct_balance(a: bytes) -> uint64: verify_acct_balance: - // tests/artifacts/state-ops/contract.algo.ts:27-28 + // tests/artifacts/state-ops/state-acct-params-get-contract.algo.ts:9-10 // @arc4.abimethod() // public verify_acct_balance(a: Account): uint64 { proto 1 1 - // tests/artifacts/state-ops/contract.algo.ts:29 + // tests/artifacts/state-ops/state-acct-params-get-contract.algo.ts:11 // const [value, funded] = op.AcctParams.acctBalance(a) frame_dig -1 acct_params_get AcctBalance - // tests/artifacts/state-ops/contract.algo.ts:30 + // tests/artifacts/state-ops/state-acct-params-get-contract.algo.ts:5 + // return op.btoi(Txn.applicationArgs(1)) + intc_0 // 1 + txnas ApplicationArgs + btoi + // tests/artifacts/state-ops/state-acct-params-get-contract.algo.ts:12 // const [value_index, funded_index] = op.AcctParams.acctBalance(get_1st_ref_index()) - callsub get_1st_ref_index + dup acct_params_get AcctBalance - // tests/artifacts/state-ops/contract.algo.ts:31 + // tests/artifacts/state-ops/state-acct-params-get-contract.algo.ts:13 // assert(value === value_index, 'expected value by index to match') - dig 3 + dig 4 uncover 2 == assert // expected value by index to match - // tests/artifacts/state-ops/contract.algo.ts:32 + // tests/artifacts/state-ops/state-acct-params-get-contract.algo.ts:14 // assert(funded === funded_index, 'expected funded by index to match') + uncover 2 == assert // expected funded by index to match - // tests/artifacts/state-ops/contract.algo.ts:33 + // tests/artifacts/state-ops/state-acct-params-get-contract.algo.ts:15 // assert(value === a.balance, 'expected Account balance to match') frame_dig -1 acct_params_get AcctBalance assert // account funded - dig 1 + dig 2 == assert // expected Account balance to match - // tests/artifacts/state-ops/contract.algo.ts:34 + // tests/artifacts/state-ops/state-acct-params-get-contract.algo.ts:16 // assert(value === op.balance(a), 'expected op.balance to match') frame_dig -1 balance - dig 1 + dig 2 == assert // expected op.balance to match - // tests/artifacts/state-ops/contract.algo.ts:35 + // tests/artifacts/state-ops/state-acct-params-get-contract.algo.ts:17 // assert(value === op.balance(get_1st_ref_index()), 'expected op.balance by index to match') - callsub get_1st_ref_index balance dig 1 == assert // expected op.balance by index to match - // tests/artifacts/state-ops/contract.algo.ts:36 + // tests/artifacts/state-ops/state-acct-params-get-contract.algo.ts:18 // return value retsub -// tests/artifacts/state-ops/contract.algo.ts::get_1st_ref_index() -> uint64: -get_1st_ref_index: - // tests/artifacts/state-ops/contract.algo.ts:22 - // function get_1st_ref_index(): uint64 { - proto 0 1 - // tests/artifacts/state-ops/contract.algo.ts:23 - // return op.btoi(Txn.applicationArgs(1)) - intc_0 // 1 - txnas ApplicationArgs - btoi - retsub - - -// tests/artifacts/state-ops/contract.algo.ts::StateAcctParamsGetContract.verify_acct_min_balance(a: bytes) -> uint64: +// tests/artifacts/state-ops/state-acct-params-get-contract.algo.ts::StateAcctParamsGetContract.verify_acct_min_balance(a: bytes) -> uint64: verify_acct_min_balance: - // tests/artifacts/state-ops/contract.algo.ts:39-40 + // tests/artifacts/state-ops/state-acct-params-get-contract.algo.ts:21-22 // @arc4.abimethod() // public verify_acct_min_balance(a: Account): uint64 { proto 1 1 - // tests/artifacts/state-ops/contract.algo.ts:41 + // tests/artifacts/state-ops/state-acct-params-get-contract.algo.ts:23 // const [value, funded] = op.AcctParams.acctMinBalance(a) frame_dig -1 acct_params_get AcctMinBalance - // tests/artifacts/state-ops/contract.algo.ts:42 + // tests/artifacts/state-ops/state-acct-params-get-contract.algo.ts:5 + // return op.btoi(Txn.applicationArgs(1)) + intc_0 // 1 + txnas ApplicationArgs + btoi + // tests/artifacts/state-ops/state-acct-params-get-contract.algo.ts:24 // const [value_index, funded_index] = op.AcctParams.acctMinBalance(get_1st_ref_index()) - callsub get_1st_ref_index + dup acct_params_get AcctMinBalance - // tests/artifacts/state-ops/contract.algo.ts:43 + // tests/artifacts/state-ops/state-acct-params-get-contract.algo.ts:25 // assert(value === value_index, 'expected value by index to match') - dig 3 + dig 4 uncover 2 == assert // expected value by index to match - // tests/artifacts/state-ops/contract.algo.ts:44 + // tests/artifacts/state-ops/state-acct-params-get-contract.algo.ts:26 // assert(funded === funded_index, 'expected funded by index to match') + uncover 2 == assert // expected funded by index to match - // tests/artifacts/state-ops/contract.algo.ts:45 + // tests/artifacts/state-ops/state-acct-params-get-contract.algo.ts:27 // assert(value === a.minBalance, 'expected Account min_balance to match') frame_dig -1 acct_params_get AcctMinBalance assert // account funded - dig 1 + dig 2 == assert // expected Account min_balance to match - // tests/artifacts/state-ops/contract.algo.ts:46 + // tests/artifacts/state-ops/state-acct-params-get-contract.algo.ts:28 // assert(value === op.minBalance(a), 'expected op.min_balance to match') frame_dig -1 min_balance - dig 1 + dig 2 == assert // expected op.min_balance to match - // tests/artifacts/state-ops/contract.algo.ts:47 + // tests/artifacts/state-ops/state-acct-params-get-contract.algo.ts:29 // assert(value === op.minBalance(get_1st_ref_index()), 'expected op.min_balance by index to match') - callsub get_1st_ref_index min_balance dig 1 == assert // expected op.min_balance by index to match - // tests/artifacts/state-ops/contract.algo.ts:48 + // tests/artifacts/state-ops/state-acct-params-get-contract.algo.ts:30 // return value retsub -// tests/artifacts/state-ops/contract.algo.ts::StateAcctParamsGetContract.verify_acct_auth_addr(a: bytes) -> bytes: +// tests/artifacts/state-ops/state-acct-params-get-contract.algo.ts::StateAcctParamsGetContract.verify_acct_auth_addr(a: bytes) -> bytes: verify_acct_auth_addr: - // tests/artifacts/state-ops/contract.algo.ts:51-52 + // tests/artifacts/state-ops/state-acct-params-get-contract.algo.ts:33-34 // @arc4.abimethod() // public verify_acct_auth_addr(a: Account): Address { proto 1 1 - // tests/artifacts/state-ops/contract.algo.ts:53 + // tests/artifacts/state-ops/state-acct-params-get-contract.algo.ts:35 // const [value, funded] = op.AcctParams.acctAuthAddr(a) frame_dig -1 acct_params_get AcctAuthAddr - // tests/artifacts/state-ops/contract.algo.ts:54 + // tests/artifacts/state-ops/state-acct-params-get-contract.algo.ts:5 + // return op.btoi(Txn.applicationArgs(1)) + intc_0 // 1 + txnas ApplicationArgs + btoi + // tests/artifacts/state-ops/state-acct-params-get-contract.algo.ts:36 // const [value_index, funded_index] = op.AcctParams.acctAuthAddr(get_1st_ref_index()) - callsub get_1st_ref_index acct_params_get AcctAuthAddr - // tests/artifacts/state-ops/contract.algo.ts:55 + // tests/artifacts/state-ops/state-acct-params-get-contract.algo.ts:37 // assert(value === value_index, 'expected value by index to match') dig 3 uncover 2 == assert // expected value by index to match - // tests/artifacts/state-ops/contract.algo.ts:56 + // tests/artifacts/state-ops/state-acct-params-get-contract.algo.ts:38 // assert(funded === funded_index, 'expected funded by index to match') == assert // expected funded by index to match - // tests/artifacts/state-ops/contract.algo.ts:57 + // tests/artifacts/state-ops/state-acct-params-get-contract.algo.ts:39 // return new Address(value) retsub -// tests/artifacts/state-ops/contract.algo.ts::StateAcctParamsGetContract.verify_acct_total_num_uint(a: bytes) -> uint64: +// tests/artifacts/state-ops/state-acct-params-get-contract.algo.ts::StateAcctParamsGetContract.verify_acct_total_num_uint(a: bytes) -> uint64: verify_acct_total_num_uint: - // tests/artifacts/state-ops/contract.algo.ts:60-61 + // tests/artifacts/state-ops/state-acct-params-get-contract.algo.ts:42-43 // @arc4.abimethod() // public verify_acct_total_num_uint(a: Account): uint64 { proto 1 1 - // tests/artifacts/state-ops/contract.algo.ts:62 + // tests/artifacts/state-ops/state-acct-params-get-contract.algo.ts:44 // const [value, funded] = op.AcctParams.acctTotalNumUint(a) frame_dig -1 acct_params_get AcctTotalNumUint - // tests/artifacts/state-ops/contract.algo.ts:63 + // tests/artifacts/state-ops/state-acct-params-get-contract.algo.ts:5 + // return op.btoi(Txn.applicationArgs(1)) + intc_0 // 1 + txnas ApplicationArgs + btoi + // tests/artifacts/state-ops/state-acct-params-get-contract.algo.ts:45 // const [value_index, funded_index] = op.AcctParams.acctTotalNumUint(get_1st_ref_index()) - callsub get_1st_ref_index acct_params_get AcctTotalNumUint - // tests/artifacts/state-ops/contract.algo.ts:64 + // tests/artifacts/state-ops/state-acct-params-get-contract.algo.ts:46 // assert(value === value_index, 'expected value by index to match') dig 3 uncover 2 == assert // expected value by index to match - // tests/artifacts/state-ops/contract.algo.ts:65 + // tests/artifacts/state-ops/state-acct-params-get-contract.algo.ts:47 // assert(funded === funded_index, 'expected funded by index to match') == assert // expected funded by index to match - // tests/artifacts/state-ops/contract.algo.ts:66 + // tests/artifacts/state-ops/state-acct-params-get-contract.algo.ts:48 // return value retsub -// tests/artifacts/state-ops/contract.algo.ts::StateAcctParamsGetContract.verify_acct_total_num_byte_slice(a: bytes) -> uint64: +// tests/artifacts/state-ops/state-acct-params-get-contract.algo.ts::StateAcctParamsGetContract.verify_acct_total_num_byte_slice(a: bytes) -> uint64: verify_acct_total_num_byte_slice: - // tests/artifacts/state-ops/contract.algo.ts:69-70 + // tests/artifacts/state-ops/state-acct-params-get-contract.algo.ts:51-52 // @arc4.abimethod() // public verify_acct_total_num_byte_slice(a: Account): uint64 { proto 1 1 - // tests/artifacts/state-ops/contract.algo.ts:71 + // tests/artifacts/state-ops/state-acct-params-get-contract.algo.ts:53 // const [value, funded] = op.AcctParams.acctTotalNumByteSlice(a) frame_dig -1 acct_params_get AcctTotalNumByteSlice - // tests/artifacts/state-ops/contract.algo.ts:72 + // tests/artifacts/state-ops/state-acct-params-get-contract.algo.ts:5 + // return op.btoi(Txn.applicationArgs(1)) + intc_0 // 1 + txnas ApplicationArgs + btoi + // tests/artifacts/state-ops/state-acct-params-get-contract.algo.ts:54 // const [value_index, funded_index] = op.AcctParams.acctTotalNumByteSlice(get_1st_ref_index()) - callsub get_1st_ref_index acct_params_get AcctTotalNumByteSlice - // tests/artifacts/state-ops/contract.algo.ts:73 + // tests/artifacts/state-ops/state-acct-params-get-contract.algo.ts:55 // assert(value === value_index, 'expected value by index to match') dig 3 uncover 2 == assert // expected value by index to match - // tests/artifacts/state-ops/contract.algo.ts:74 + // tests/artifacts/state-ops/state-acct-params-get-contract.algo.ts:56 // assert(funded === funded_index, 'expected funded by index to match') == assert // expected funded by index to match - // tests/artifacts/state-ops/contract.algo.ts:75 + // tests/artifacts/state-ops/state-acct-params-get-contract.algo.ts:57 // return value retsub -// tests/artifacts/state-ops/contract.algo.ts::StateAcctParamsGetContract.verify_acct_total_extra_app_pages(a: bytes) -> uint64: +// tests/artifacts/state-ops/state-acct-params-get-contract.algo.ts::StateAcctParamsGetContract.verify_acct_total_extra_app_pages(a: bytes) -> uint64: verify_acct_total_extra_app_pages: - // tests/artifacts/state-ops/contract.algo.ts:78-79 + // tests/artifacts/state-ops/state-acct-params-get-contract.algo.ts:60-61 // @arc4.abimethod() // public verify_acct_total_extra_app_pages(a: Account): uint64 { proto 1 1 - // tests/artifacts/state-ops/contract.algo.ts:80 + // tests/artifacts/state-ops/state-acct-params-get-contract.algo.ts:62 // const [value, funded] = op.AcctParams.acctTotalExtraAppPages(a) frame_dig -1 acct_params_get AcctTotalExtraAppPages - // tests/artifacts/state-ops/contract.algo.ts:81 + // tests/artifacts/state-ops/state-acct-params-get-contract.algo.ts:5 + // return op.btoi(Txn.applicationArgs(1)) + intc_0 // 1 + txnas ApplicationArgs + btoi + // tests/artifacts/state-ops/state-acct-params-get-contract.algo.ts:63 // const [value_index, funded_index] = op.AcctParams.acctTotalExtraAppPages(get_1st_ref_index()) - callsub get_1st_ref_index acct_params_get AcctTotalExtraAppPages - // tests/artifacts/state-ops/contract.algo.ts:82 + // tests/artifacts/state-ops/state-acct-params-get-contract.algo.ts:64 // assert(value === value_index, 'expected value by index to match') dig 3 uncover 2 == assert // expected value by index to match - // tests/artifacts/state-ops/contract.algo.ts:83 + // tests/artifacts/state-ops/state-acct-params-get-contract.algo.ts:65 // assert(funded === funded_index, 'expected funded by index to match') == assert // expected funded by index to match - // tests/artifacts/state-ops/contract.algo.ts:84 + // tests/artifacts/state-ops/state-acct-params-get-contract.algo.ts:66 // return value retsub -// tests/artifacts/state-ops/contract.algo.ts::StateAcctParamsGetContract.verify_acct_total_apps_created(a: bytes) -> uint64: +// tests/artifacts/state-ops/state-acct-params-get-contract.algo.ts::StateAcctParamsGetContract.verify_acct_total_apps_created(a: bytes) -> uint64: verify_acct_total_apps_created: - // tests/artifacts/state-ops/contract.algo.ts:87-88 + // tests/artifacts/state-ops/state-acct-params-get-contract.algo.ts:69-70 // @arc4.abimethod() // public verify_acct_total_apps_created(a: Account): uint64 { proto 1 1 - // tests/artifacts/state-ops/contract.algo.ts:89 + // tests/artifacts/state-ops/state-acct-params-get-contract.algo.ts:71 // const [value, funded] = op.AcctParams.acctTotalAppsCreated(a) frame_dig -1 acct_params_get AcctTotalAppsCreated - // tests/artifacts/state-ops/contract.algo.ts:90 + // tests/artifacts/state-ops/state-acct-params-get-contract.algo.ts:5 + // return op.btoi(Txn.applicationArgs(1)) + intc_0 // 1 + txnas ApplicationArgs + btoi + // tests/artifacts/state-ops/state-acct-params-get-contract.algo.ts:72 // const [value_index, funded_index] = op.AcctParams.acctTotalAppsCreated(get_1st_ref_index()) - callsub get_1st_ref_index acct_params_get AcctTotalAppsCreated - // tests/artifacts/state-ops/contract.algo.ts:91 + // tests/artifacts/state-ops/state-acct-params-get-contract.algo.ts:73 // assert(value === value_index, 'expected value by index to match') dig 3 uncover 2 == assert // expected value by index to match - // tests/artifacts/state-ops/contract.algo.ts:92 + // tests/artifacts/state-ops/state-acct-params-get-contract.algo.ts:74 // assert(funded === funded_index, 'expected funded by index to match') == assert // expected funded by index to match - // tests/artifacts/state-ops/contract.algo.ts:93 + // tests/artifacts/state-ops/state-acct-params-get-contract.algo.ts:75 // return value retsub -// tests/artifacts/state-ops/contract.algo.ts::StateAcctParamsGetContract.verify_acct_total_apps_opted_in(a: bytes) -> uint64: +// tests/artifacts/state-ops/state-acct-params-get-contract.algo.ts::StateAcctParamsGetContract.verify_acct_total_apps_opted_in(a: bytes) -> uint64: verify_acct_total_apps_opted_in: - // tests/artifacts/state-ops/contract.algo.ts:96-97 + // tests/artifacts/state-ops/state-acct-params-get-contract.algo.ts:78-79 // @arc4.abimethod() // public verify_acct_total_apps_opted_in(a: Account): uint64 { proto 1 1 - // tests/artifacts/state-ops/contract.algo.ts:98 + // tests/artifacts/state-ops/state-acct-params-get-contract.algo.ts:80 // const [value, funded] = op.AcctParams.acctTotalAppsOptedIn(a) frame_dig -1 acct_params_get AcctTotalAppsOptedIn - // tests/artifacts/state-ops/contract.algo.ts:99 + // tests/artifacts/state-ops/state-acct-params-get-contract.algo.ts:5 + // return op.btoi(Txn.applicationArgs(1)) + intc_0 // 1 + txnas ApplicationArgs + btoi + // tests/artifacts/state-ops/state-acct-params-get-contract.algo.ts:81 // const [value_index, funded_index] = op.AcctParams.acctTotalAppsOptedIn(get_1st_ref_index()) - callsub get_1st_ref_index acct_params_get AcctTotalAppsOptedIn - // tests/artifacts/state-ops/contract.algo.ts:100 + // tests/artifacts/state-ops/state-acct-params-get-contract.algo.ts:82 // assert(value === value_index, 'expected value by index to match') dig 3 uncover 2 == assert // expected value by index to match - // tests/artifacts/state-ops/contract.algo.ts:101 + // tests/artifacts/state-ops/state-acct-params-get-contract.algo.ts:83 // assert(funded === funded_index, 'expected funded by index to match') == assert // expected funded by index to match - // tests/artifacts/state-ops/contract.algo.ts:102 + // tests/artifacts/state-ops/state-acct-params-get-contract.algo.ts:84 // return value retsub -// tests/artifacts/state-ops/contract.algo.ts::StateAcctParamsGetContract.verify_acct_total_assets_created(a: bytes) -> uint64: +// tests/artifacts/state-ops/state-acct-params-get-contract.algo.ts::StateAcctParamsGetContract.verify_acct_total_assets_created(a: bytes) -> uint64: verify_acct_total_assets_created: - // tests/artifacts/state-ops/contract.algo.ts:105-106 + // tests/artifacts/state-ops/state-acct-params-get-contract.algo.ts:87-88 // @arc4.abimethod() // public verify_acct_total_assets_created(a: Account): uint64 { proto 1 1 - // tests/artifacts/state-ops/contract.algo.ts:107 + // tests/artifacts/state-ops/state-acct-params-get-contract.algo.ts:89 // const [value, funded] = op.AcctParams.acctTotalAssetsCreated(a) frame_dig -1 acct_params_get AcctTotalAssetsCreated - // tests/artifacts/state-ops/contract.algo.ts:108 + // tests/artifacts/state-ops/state-acct-params-get-contract.algo.ts:5 + // return op.btoi(Txn.applicationArgs(1)) + intc_0 // 1 + txnas ApplicationArgs + btoi + // tests/artifacts/state-ops/state-acct-params-get-contract.algo.ts:90 // const [value_index, funded_index] = op.AcctParams.acctTotalAssetsCreated(get_1st_ref_index()) - callsub get_1st_ref_index acct_params_get AcctTotalAssetsCreated - // tests/artifacts/state-ops/contract.algo.ts:109 + // tests/artifacts/state-ops/state-acct-params-get-contract.algo.ts:91 // assert(value === value_index, 'expected value by index to match') dig 3 uncover 2 == assert // expected value by index to match - // tests/artifacts/state-ops/contract.algo.ts:110 + // tests/artifacts/state-ops/state-acct-params-get-contract.algo.ts:92 // assert(funded === funded_index, 'expected funded by index to match') == assert // expected funded by index to match - // tests/artifacts/state-ops/contract.algo.ts:111 + // tests/artifacts/state-ops/state-acct-params-get-contract.algo.ts:93 // return value retsub -// tests/artifacts/state-ops/contract.algo.ts::StateAcctParamsGetContract.verify_acct_total_assets(a: bytes) -> uint64: +// tests/artifacts/state-ops/state-acct-params-get-contract.algo.ts::StateAcctParamsGetContract.verify_acct_total_assets(a: bytes) -> uint64: verify_acct_total_assets: - // tests/artifacts/state-ops/contract.algo.ts:114-115 + // tests/artifacts/state-ops/state-acct-params-get-contract.algo.ts:96-97 // @arc4.abimethod() // public verify_acct_total_assets(a: Account): uint64 { proto 1 1 - // tests/artifacts/state-ops/contract.algo.ts:116 + // tests/artifacts/state-ops/state-acct-params-get-contract.algo.ts:98 // const [value, funded] = op.AcctParams.acctTotalAssets(a) frame_dig -1 acct_params_get AcctTotalAssets - // tests/artifacts/state-ops/contract.algo.ts:117 + // tests/artifacts/state-ops/state-acct-params-get-contract.algo.ts:5 + // return op.btoi(Txn.applicationArgs(1)) + intc_0 // 1 + txnas ApplicationArgs + btoi + // tests/artifacts/state-ops/state-acct-params-get-contract.algo.ts:99 // const [value_index, funded_index] = op.AcctParams.acctTotalAssets(get_1st_ref_index()) - callsub get_1st_ref_index acct_params_get AcctTotalAssets - // tests/artifacts/state-ops/contract.algo.ts:118 + // tests/artifacts/state-ops/state-acct-params-get-contract.algo.ts:100 // assert(value === value_index, 'expected value by index to match') dig 3 uncover 2 == assert // expected value by index to match - // tests/artifacts/state-ops/contract.algo.ts:119 + // tests/artifacts/state-ops/state-acct-params-get-contract.algo.ts:101 // assert(funded === funded_index, 'expected funded by index to match') == assert // expected funded by index to match - // tests/artifacts/state-ops/contract.algo.ts:120 + // tests/artifacts/state-ops/state-acct-params-get-contract.algo.ts:102 // return value retsub -// tests/artifacts/state-ops/contract.algo.ts::StateAcctParamsGetContract.verify_acct_total_boxes(a: bytes) -> uint64: +// tests/artifacts/state-ops/state-acct-params-get-contract.algo.ts::StateAcctParamsGetContract.verify_acct_total_boxes(a: bytes) -> uint64: verify_acct_total_boxes: - // tests/artifacts/state-ops/contract.algo.ts:123-124 + // tests/artifacts/state-ops/state-acct-params-get-contract.algo.ts:105-106 // @arc4.abimethod() // public verify_acct_total_boxes(a: Account): uint64 { proto 1 1 - // tests/artifacts/state-ops/contract.algo.ts:125 + // tests/artifacts/state-ops/state-acct-params-get-contract.algo.ts:107 // const [value, funded] = op.AcctParams.acctTotalBoxes(a) frame_dig -1 acct_params_get AcctTotalBoxes - // tests/artifacts/state-ops/contract.algo.ts:126 + // tests/artifacts/state-ops/state-acct-params-get-contract.algo.ts:5 + // return op.btoi(Txn.applicationArgs(1)) + intc_0 // 1 + txnas ApplicationArgs + btoi + // tests/artifacts/state-ops/state-acct-params-get-contract.algo.ts:108 // const [value_index, funded_index] = op.AcctParams.acctTotalBoxes(get_1st_ref_index()) - callsub get_1st_ref_index acct_params_get AcctTotalBoxes - // tests/artifacts/state-ops/contract.algo.ts:127 + // tests/artifacts/state-ops/state-acct-params-get-contract.algo.ts:109 // assert(value === value_index, 'expected value by index to match') dig 3 uncover 2 == assert // expected value by index to match - // tests/artifacts/state-ops/contract.algo.ts:128 + // tests/artifacts/state-ops/state-acct-params-get-contract.algo.ts:110 // assert(funded === funded_index, 'expected funded by index to match') == assert // expected funded by index to match - // tests/artifacts/state-ops/contract.algo.ts:129 + // tests/artifacts/state-ops/state-acct-params-get-contract.algo.ts:111 // return value retsub -// tests/artifacts/state-ops/contract.algo.ts::StateAcctParamsGetContract.verify_acct_total_box_bytes(a: bytes) -> uint64: +// tests/artifacts/state-ops/state-acct-params-get-contract.algo.ts::StateAcctParamsGetContract.verify_acct_total_box_bytes(a: bytes) -> uint64: verify_acct_total_box_bytes: - // tests/artifacts/state-ops/contract.algo.ts:132-133 + // tests/artifacts/state-ops/state-acct-params-get-contract.algo.ts:114-115 // @arc4.abimethod() // public verify_acct_total_box_bytes(a: Account): uint64 { proto 1 1 - // tests/artifacts/state-ops/contract.algo.ts:134 + // tests/artifacts/state-ops/state-acct-params-get-contract.algo.ts:116 // const [value, funded] = op.AcctParams.acctTotalBoxBytes(a) frame_dig -1 acct_params_get AcctTotalBoxBytes - // tests/artifacts/state-ops/contract.algo.ts:135 + // tests/artifacts/state-ops/state-acct-params-get-contract.algo.ts:5 + // return op.btoi(Txn.applicationArgs(1)) + intc_0 // 1 + txnas ApplicationArgs + btoi + // tests/artifacts/state-ops/state-acct-params-get-contract.algo.ts:117 // const [value_index, funded_index] = op.AcctParams.acctTotalBoxBytes(get_1st_ref_index()) - callsub get_1st_ref_index acct_params_get AcctTotalBoxBytes - // tests/artifacts/state-ops/contract.algo.ts:136 + // tests/artifacts/state-ops/state-acct-params-get-contract.algo.ts:118 + // assert(value === value_index, 'expected value by index to match') + dig 3 + uncover 2 + == + assert // expected value by index to match + // tests/artifacts/state-ops/state-acct-params-get-contract.algo.ts:119 + // assert(funded === funded_index, 'expected funded by index to match') + == + assert // expected funded by index to match + // tests/artifacts/state-ops/state-acct-params-get-contract.algo.ts:120 + // return value + retsub + + +// tests/artifacts/state-ops/state-acct-params-get-contract.algo.ts::StateAcctParamsGetContract.verify_acct_incentive_eligible(a: bytes) -> uint64: +verify_acct_incentive_eligible: + // tests/artifacts/state-ops/state-acct-params-get-contract.algo.ts:123-124 + // @arc4.abimethod() + // public verify_acct_incentive_eligible(a: Account): boolean { + proto 1 1 + // tests/artifacts/state-ops/state-acct-params-get-contract.algo.ts:125 + // const [value, funded] = op.AcctParams.acctIncentiveEligible(a) + frame_dig -1 + acct_params_get AcctIncentiveEligible + // tests/artifacts/state-ops/state-acct-params-get-contract.algo.ts:5 + // return op.btoi(Txn.applicationArgs(1)) + intc_0 // 1 + txnas ApplicationArgs + btoi + // tests/artifacts/state-ops/state-acct-params-get-contract.algo.ts:126 + // const [value_index, funded_index] = op.AcctParams.acctIncentiveEligible(get_1st_ref_index()) + acct_params_get AcctIncentiveEligible + // tests/artifacts/state-ops/state-acct-params-get-contract.algo.ts:127 // assert(value === value_index, 'expected value by index to match') dig 3 uncover 2 == assert // expected value by index to match - // tests/artifacts/state-ops/contract.algo.ts:137 + // tests/artifacts/state-ops/state-acct-params-get-contract.algo.ts:128 // assert(funded === funded_index, 'expected funded by index to match') == assert // expected funded by index to match - // tests/artifacts/state-ops/contract.algo.ts:138 + // tests/artifacts/state-ops/state-acct-params-get-contract.algo.ts:129 // return value retsub diff --git a/tests/artifacts/state-ops/data/StateAcctParamsGetContract.arc32.json b/tests/artifacts/state-ops/data/StateAcctParamsGetContract.arc32.json index 4fbd3f2..42ebdd0 100644 --- a/tests/artifacts/state-ops/data/StateAcctParamsGetContract.arc32.json +++ b/tests/artifacts/state-ops/data/StateAcctParamsGetContract.arc32.json @@ -59,11 +59,16 @@ "call_config": { "no_op": "CALL" } + }, + "verify_acct_incentive_eligible(account)bool": { + "call_config": { + "no_op": "CALL" + } } }, "source": { - "approval": "I3ByYWdtYSB2ZXJzaW9uIDEwCgp0ZXN0cy9hcnRpZmFjdHMvc3RhdGUtb3BzL2NvbnRyYWN0LmFsZ28udHM6OlN0YXRlQWNjdFBhcmFtc0dldENvbnRyYWN0LmFwcHJvdmFsUHJvZ3JhbToKICAgIGludGNibG9jayAxIDAKICAgIGJ5dGVjYmxvY2sgMHgxNTFmN2M3NQogICAgY2FsbHN1YiBfX3B1eWFfYXJjNF9yb3V0ZXJfXwogICAgcmV0dXJuCgoKLy8gdGVzdHMvYXJ0aWZhY3RzL3N0YXRlLW9wcy9jb250cmFjdC5hbGdvLnRzOjpTdGF0ZUFjY3RQYXJhbXNHZXRDb250cmFjdC5fX3B1eWFfYXJjNF9yb3V0ZXJfXygpIC0+IHVpbnQ2NDoKX19wdXlhX2FyYzRfcm91dGVyX186CiAgICAvLyB0ZXN0cy9hcnRpZmFjdHMvc3RhdGUtb3BzL2NvbnRyYWN0LmFsZ28udHM6MjYKICAgIC8vIGV4cG9ydCBjbGFzcyBTdGF0ZUFjY3RQYXJhbXNHZXRDb250cmFjdCBleHRlbmRzIGFyYzQuQ29udHJhY3QgewogICAgcHJvdG8gMCAxCiAgICB0eG4gTnVtQXBwQXJncwogICAgYnogX19wdXlhX2FyYzRfcm91dGVyX19fYmFyZV9yb3V0aW5nQDE2CiAgICBwdXNoYnl0ZXNzIDB4NWY1YjQzZTQgMHg3M2RjOTNjNyAweDU2MjZkZmViIDB4ZGM4YTI1YmYgMHgxOThlYmQ4YyAweDIzMDFhYjI2IDB4OWY2OGZjYTYgMHhhOTc1YzJkMSAweGQxZTA0ODAxIDB4YjY5NjZiZTUgMHgxOTVkNTQxOCAweDZhZGFlM2YxIC8vIG1ldGhvZCAidmVyaWZ5X2FjY3RfYmFsYW5jZShhY2NvdW50KXVpbnQ2NCIsIG1ldGhvZCAidmVyaWZ5X2FjY3RfbWluX2JhbGFuY2UoYWNjb3VudCl1aW50NjQiLCBtZXRob2QgInZlcmlmeV9hY2N0X2F1dGhfYWRkcihhY2NvdW50KWFkZHJlc3MiLCBtZXRob2QgInZlcmlmeV9hY2N0X3RvdGFsX251bV91aW50KGFjY291bnQpdWludDY0IiwgbWV0aG9kICJ2ZXJpZnlfYWNjdF90b3RhbF9udW1fYnl0ZV9zbGljZShhY2NvdW50KXVpbnQ2NCIsIG1ldGhvZCAidmVyaWZ5X2FjY3RfdG90YWxfZXh0cmFfYXBwX3BhZ2VzKGFjY291bnQpdWludDY0IiwgbWV0aG9kICJ2ZXJpZnlfYWNjdF90b3RhbF9hcHBzX2NyZWF0ZWQoYWNjb3VudCl1aW50NjQiLCBtZXRob2QgInZlcmlmeV9hY2N0X3RvdGFsX2FwcHNfb3B0ZWRfaW4oYWNjb3VudCl1aW50NjQiLCBtZXRob2QgInZlcmlmeV9hY2N0X3RvdGFsX2Fzc2V0c19jcmVhdGVkKGFjY291bnQpdWludDY0IiwgbWV0aG9kICJ2ZXJpZnlfYWNjdF90b3RhbF9hc3NldHMoYWNjb3VudCl1aW50NjQiLCBtZXRob2QgInZlcmlmeV9hY2N0X3RvdGFsX2JveGVzKGFjY291bnQpdWludDY0IiwgbWV0aG9kICJ2ZXJpZnlfYWNjdF90b3RhbF9ib3hfYnl0ZXMoYWNjb3VudCl1aW50NjQiCiAgICB0eG5hIEFwcGxpY2F0aW9uQXJncyAwCiAgICBtYXRjaCBfX3B1eWFfYXJjNF9yb3V0ZXJfX192ZXJpZnlfYWNjdF9iYWxhbmNlX3JvdXRlQDIgX19wdXlhX2FyYzRfcm91dGVyX19fdmVyaWZ5X2FjY3RfbWluX2JhbGFuY2Vfcm91dGVAMyBfX3B1eWFfYXJjNF9yb3V0ZXJfX192ZXJpZnlfYWNjdF9hdXRoX2FkZHJfcm91dGVANCBfX3B1eWFfYXJjNF9yb3V0ZXJfX192ZXJpZnlfYWNjdF90b3RhbF9udW1fdWludF9yb3V0ZUA1IF9fcHV5YV9hcmM0X3JvdXRlcl9fX3ZlcmlmeV9hY2N0X3RvdGFsX251bV9ieXRlX3NsaWNlX3JvdXRlQDYgX19wdXlhX2FyYzRfcm91dGVyX19fdmVyaWZ5X2FjY3RfdG90YWxfZXh0cmFfYXBwX3BhZ2VzX3JvdXRlQDcgX19wdXlhX2FyYzRfcm91dGVyX19fdmVyaWZ5X2FjY3RfdG90YWxfYXBwc19jcmVhdGVkX3JvdXRlQDggX19wdXlhX2FyYzRfcm91dGVyX19fdmVyaWZ5X2FjY3RfdG90YWxfYXBwc19vcHRlZF9pbl9yb3V0ZUA5IF9fcHV5YV9hcmM0X3JvdXRlcl9fX3ZlcmlmeV9hY2N0X3RvdGFsX2Fzc2V0c19jcmVhdGVkX3JvdXRlQDEwIF9fcHV5YV9hcmM0X3JvdXRlcl9fX3ZlcmlmeV9hY2N0X3RvdGFsX2Fzc2V0c19yb3V0ZUAxMSBfX3B1eWFfYXJjNF9yb3V0ZXJfX192ZXJpZnlfYWNjdF90b3RhbF9ib3hlc19yb3V0ZUAxMiBfX3B1eWFfYXJjNF9yb3V0ZXJfX192ZXJpZnlfYWNjdF90b3RhbF9ib3hfYnl0ZXNfcm91dGVAMTMKICAgIGludGNfMSAvLyAwCiAgICByZXRzdWIKCl9fcHV5YV9hcmM0X3JvdXRlcl9fX3ZlcmlmeV9hY2N0X2JhbGFuY2Vfcm91dGVAMjoKICAgIC8vIHRlc3RzL2FydGlmYWN0cy9zdGF0ZS1vcHMvY29udHJhY3QuYWxnby50czoyNwogICAgLy8gQGFyYzQuYWJpbWV0aG9kKCkKICAgIHR4biBPbkNvbXBsZXRpb24KICAgICEKICAgIGFzc2VydCAvLyBPbkNvbXBsZXRpb24gaXMgbm90IE5vT3AKICAgIHR4biBBcHBsaWNhdGlvbklECiAgICBhc3NlcnQgLy8gY2FuIG9ubHkgY2FsbCB3aGVuIG5vdCBjcmVhdGluZwogICAgLy8gdGVzdHMvYXJ0aWZhY3RzL3N0YXRlLW9wcy9jb250cmFjdC5hbGdvLnRzOjI2CiAgICAvLyBleHBvcnQgY2xhc3MgU3RhdGVBY2N0UGFyYW1zR2V0Q29udHJhY3QgZXh0ZW5kcyBhcmM0LkNvbnRyYWN0IHsKICAgIHR4bmEgQXBwbGljYXRpb25BcmdzIDEKICAgIGJ0b2kKICAgIHR4bmFzIEFjY291bnRzCiAgICAvLyB0ZXN0cy9hcnRpZmFjdHMvc3RhdGUtb3BzL2NvbnRyYWN0LmFsZ28udHM6MjcKICAgIC8vIEBhcmM0LmFiaW1ldGhvZCgpCiAgICBjYWxsc3ViIHZlcmlmeV9hY2N0X2JhbGFuY2UKICAgIGl0b2IKICAgIGJ5dGVjXzAgLy8gMHgxNTFmN2M3NQogICAgc3dhcAogICAgY29uY2F0CiAgICBsb2cKICAgIGludGNfMCAvLyAxCiAgICByZXRzdWIKCl9fcHV5YV9hcmM0X3JvdXRlcl9fX3ZlcmlmeV9hY2N0X21pbl9iYWxhbmNlX3JvdXRlQDM6CiAgICAvLyB0ZXN0cy9hcnRpZmFjdHMvc3RhdGUtb3BzL2NvbnRyYWN0LmFsZ28udHM6MzkKICAgIC8vIEBhcmM0LmFiaW1ldGhvZCgpCiAgICB0eG4gT25Db21wbGV0aW9uCiAgICAhCiAgICBhc3NlcnQgLy8gT25Db21wbGV0aW9uIGlzIG5vdCBOb09wCiAgICB0eG4gQXBwbGljYXRpb25JRAogICAgYXNzZXJ0IC8vIGNhbiBvbmx5IGNhbGwgd2hlbiBub3QgY3JlYXRpbmcKICAgIC8vIHRlc3RzL2FydGlmYWN0cy9zdGF0ZS1vcHMvY29udHJhY3QuYWxnby50czoyNgogICAgLy8gZXhwb3J0IGNsYXNzIFN0YXRlQWNjdFBhcmFtc0dldENvbnRyYWN0IGV4dGVuZHMgYXJjNC5Db250cmFjdCB7CiAgICB0eG5hIEFwcGxpY2F0aW9uQXJncyAxCiAgICBidG9pCiAgICB0eG5hcyBBY2NvdW50cwogICAgLy8gdGVzdHMvYXJ0aWZhY3RzL3N0YXRlLW9wcy9jb250cmFjdC5hbGdvLnRzOjM5CiAgICAvLyBAYXJjNC5hYmltZXRob2QoKQogICAgY2FsbHN1YiB2ZXJpZnlfYWNjdF9taW5fYmFsYW5jZQogICAgaXRvYgogICAgYnl0ZWNfMCAvLyAweDE1MWY3Yzc1CiAgICBzd2FwCiAgICBjb25jYXQKICAgIGxvZwogICAgaW50Y18wIC8vIDEKICAgIHJldHN1YgoKX19wdXlhX2FyYzRfcm91dGVyX19fdmVyaWZ5X2FjY3RfYXV0aF9hZGRyX3JvdXRlQDQ6CiAgICAvLyB0ZXN0cy9hcnRpZmFjdHMvc3RhdGUtb3BzL2NvbnRyYWN0LmFsZ28udHM6NTEKICAgIC8vIEBhcmM0LmFiaW1ldGhvZCgpCiAgICB0eG4gT25Db21wbGV0aW9uCiAgICAhCiAgICBhc3NlcnQgLy8gT25Db21wbGV0aW9uIGlzIG5vdCBOb09wCiAgICB0eG4gQXBwbGljYXRpb25JRAogICAgYXNzZXJ0IC8vIGNhbiBvbmx5IGNhbGwgd2hlbiBub3QgY3JlYXRpbmcKICAgIC8vIHRlc3RzL2FydGlmYWN0cy9zdGF0ZS1vcHMvY29udHJhY3QuYWxnby50czoyNgogICAgLy8gZXhwb3J0IGNsYXNzIFN0YXRlQWNjdFBhcmFtc0dldENvbnRyYWN0IGV4dGVuZHMgYXJjNC5Db250cmFjdCB7CiAgICB0eG5hIEFwcGxpY2F0aW9uQXJncyAxCiAgICBidG9pCiAgICB0eG5hcyBBY2NvdW50cwogICAgLy8gdGVzdHMvYXJ0aWZhY3RzL3N0YXRlLW9wcy9jb250cmFjdC5hbGdvLnRzOjUxCiAgICAvLyBAYXJjNC5hYmltZXRob2QoKQogICAgY2FsbHN1YiB2ZXJpZnlfYWNjdF9hdXRoX2FkZHIKICAgIGJ5dGVjXzAgLy8gMHgxNTFmN2M3NQogICAgc3dhcAogICAgY29uY2F0CiAgICBsb2cKICAgIGludGNfMCAvLyAxCiAgICByZXRzdWIKCl9fcHV5YV9hcmM0X3JvdXRlcl9fX3ZlcmlmeV9hY2N0X3RvdGFsX251bV91aW50X3JvdXRlQDU6CiAgICAvLyB0ZXN0cy9hcnRpZmFjdHMvc3RhdGUtb3BzL2NvbnRyYWN0LmFsZ28udHM6NjAKICAgIC8vIEBhcmM0LmFiaW1ldGhvZCgpCiAgICB0eG4gT25Db21wbGV0aW9uCiAgICAhCiAgICBhc3NlcnQgLy8gT25Db21wbGV0aW9uIGlzIG5vdCBOb09wCiAgICB0eG4gQXBwbGljYXRpb25JRAogICAgYXNzZXJ0IC8vIGNhbiBvbmx5IGNhbGwgd2hlbiBub3QgY3JlYXRpbmcKICAgIC8vIHRlc3RzL2FydGlmYWN0cy9zdGF0ZS1vcHMvY29udHJhY3QuYWxnby50czoyNgogICAgLy8gZXhwb3J0IGNsYXNzIFN0YXRlQWNjdFBhcmFtc0dldENvbnRyYWN0IGV4dGVuZHMgYXJjNC5Db250cmFjdCB7CiAgICB0eG5hIEFwcGxpY2F0aW9uQXJncyAxCiAgICBidG9pCiAgICB0eG5hcyBBY2NvdW50cwogICAgLy8gdGVzdHMvYXJ0aWZhY3RzL3N0YXRlLW9wcy9jb250cmFjdC5hbGdvLnRzOjYwCiAgICAvLyBAYXJjNC5hYmltZXRob2QoKQogICAgY2FsbHN1YiB2ZXJpZnlfYWNjdF90b3RhbF9udW1fdWludAogICAgaXRvYgogICAgYnl0ZWNfMCAvLyAweDE1MWY3Yzc1CiAgICBzd2FwCiAgICBjb25jYXQKICAgIGxvZwogICAgaW50Y18wIC8vIDEKICAgIHJldHN1YgoKX19wdXlhX2FyYzRfcm91dGVyX19fdmVyaWZ5X2FjY3RfdG90YWxfbnVtX2J5dGVfc2xpY2Vfcm91dGVANjoKICAgIC8vIHRlc3RzL2FydGlmYWN0cy9zdGF0ZS1vcHMvY29udHJhY3QuYWxnby50czo2OQogICAgLy8gQGFyYzQuYWJpbWV0aG9kKCkKICAgIHR4biBPbkNvbXBsZXRpb24KICAgICEKICAgIGFzc2VydCAvLyBPbkNvbXBsZXRpb24gaXMgbm90IE5vT3AKICAgIHR4biBBcHBsaWNhdGlvbklECiAgICBhc3NlcnQgLy8gY2FuIG9ubHkgY2FsbCB3aGVuIG5vdCBjcmVhdGluZwogICAgLy8gdGVzdHMvYXJ0aWZhY3RzL3N0YXRlLW9wcy9jb250cmFjdC5hbGdvLnRzOjI2CiAgICAvLyBleHBvcnQgY2xhc3MgU3RhdGVBY2N0UGFyYW1zR2V0Q29udHJhY3QgZXh0ZW5kcyBhcmM0LkNvbnRyYWN0IHsKICAgIHR4bmEgQXBwbGljYXRpb25BcmdzIDEKICAgIGJ0b2kKICAgIHR4bmFzIEFjY291bnRzCiAgICAvLyB0ZXN0cy9hcnRpZmFjdHMvc3RhdGUtb3BzL2NvbnRyYWN0LmFsZ28udHM6NjkKICAgIC8vIEBhcmM0LmFiaW1ldGhvZCgpCiAgICBjYWxsc3ViIHZlcmlmeV9hY2N0X3RvdGFsX251bV9ieXRlX3NsaWNlCiAgICBpdG9iCiAgICBieXRlY18wIC8vIDB4MTUxZjdjNzUKICAgIHN3YXAKICAgIGNvbmNhdAogICAgbG9nCiAgICBpbnRjXzAgLy8gMQogICAgcmV0c3ViCgpfX3B1eWFfYXJjNF9yb3V0ZXJfX192ZXJpZnlfYWNjdF90b3RhbF9leHRyYV9hcHBfcGFnZXNfcm91dGVANzoKICAgIC8vIHRlc3RzL2FydGlmYWN0cy9zdGF0ZS1vcHMvY29udHJhY3QuYWxnby50czo3OAogICAgLy8gQGFyYzQuYWJpbWV0aG9kKCkKICAgIHR4biBPbkNvbXBsZXRpb24KICAgICEKICAgIGFzc2VydCAvLyBPbkNvbXBsZXRpb24gaXMgbm90IE5vT3AKICAgIHR4biBBcHBsaWNhdGlvbklECiAgICBhc3NlcnQgLy8gY2FuIG9ubHkgY2FsbCB3aGVuIG5vdCBjcmVhdGluZwogICAgLy8gdGVzdHMvYXJ0aWZhY3RzL3N0YXRlLW9wcy9jb250cmFjdC5hbGdvLnRzOjI2CiAgICAvLyBleHBvcnQgY2xhc3MgU3RhdGVBY2N0UGFyYW1zR2V0Q29udHJhY3QgZXh0ZW5kcyBhcmM0LkNvbnRyYWN0IHsKICAgIHR4bmEgQXBwbGljYXRpb25BcmdzIDEKICAgIGJ0b2kKICAgIHR4bmFzIEFjY291bnRzCiAgICAvLyB0ZXN0cy9hcnRpZmFjdHMvc3RhdGUtb3BzL2NvbnRyYWN0LmFsZ28udHM6NzgKICAgIC8vIEBhcmM0LmFiaW1ldGhvZCgpCiAgICBjYWxsc3ViIHZlcmlmeV9hY2N0X3RvdGFsX2V4dHJhX2FwcF9wYWdlcwogICAgaXRvYgogICAgYnl0ZWNfMCAvLyAweDE1MWY3Yzc1CiAgICBzd2FwCiAgICBjb25jYXQKICAgIGxvZwogICAgaW50Y18wIC8vIDEKICAgIHJldHN1YgoKX19wdXlhX2FyYzRfcm91dGVyX19fdmVyaWZ5X2FjY3RfdG90YWxfYXBwc19jcmVhdGVkX3JvdXRlQDg6CiAgICAvLyB0ZXN0cy9hcnRpZmFjdHMvc3RhdGUtb3BzL2NvbnRyYWN0LmFsZ28udHM6ODcKICAgIC8vIEBhcmM0LmFiaW1ldGhvZCgpCiAgICB0eG4gT25Db21wbGV0aW9uCiAgICAhCiAgICBhc3NlcnQgLy8gT25Db21wbGV0aW9uIGlzIG5vdCBOb09wCiAgICB0eG4gQXBwbGljYXRpb25JRAogICAgYXNzZXJ0IC8vIGNhbiBvbmx5IGNhbGwgd2hlbiBub3QgY3JlYXRpbmcKICAgIC8vIHRlc3RzL2FydGlmYWN0cy9zdGF0ZS1vcHMvY29udHJhY3QuYWxnby50czoyNgogICAgLy8gZXhwb3J0IGNsYXNzIFN0YXRlQWNjdFBhcmFtc0dldENvbnRyYWN0IGV4dGVuZHMgYXJjNC5Db250cmFjdCB7CiAgICB0eG5hIEFwcGxpY2F0aW9uQXJncyAxCiAgICBidG9pCiAgICB0eG5hcyBBY2NvdW50cwogICAgLy8gdGVzdHMvYXJ0aWZhY3RzL3N0YXRlLW9wcy9jb250cmFjdC5hbGdvLnRzOjg3CiAgICAvLyBAYXJjNC5hYmltZXRob2QoKQogICAgY2FsbHN1YiB2ZXJpZnlfYWNjdF90b3RhbF9hcHBzX2NyZWF0ZWQKICAgIGl0b2IKICAgIGJ5dGVjXzAgLy8gMHgxNTFmN2M3NQogICAgc3dhcAogICAgY29uY2F0CiAgICBsb2cKICAgIGludGNfMCAvLyAxCiAgICByZXRzdWIKCl9fcHV5YV9hcmM0X3JvdXRlcl9fX3ZlcmlmeV9hY2N0X3RvdGFsX2FwcHNfb3B0ZWRfaW5fcm91dGVAOToKICAgIC8vIHRlc3RzL2FydGlmYWN0cy9zdGF0ZS1vcHMvY29udHJhY3QuYWxnby50czo5NgogICAgLy8gQGFyYzQuYWJpbWV0aG9kKCkKICAgIHR4biBPbkNvbXBsZXRpb24KICAgICEKICAgIGFzc2VydCAvLyBPbkNvbXBsZXRpb24gaXMgbm90IE5vT3AKICAgIHR4biBBcHBsaWNhdGlvbklECiAgICBhc3NlcnQgLy8gY2FuIG9ubHkgY2FsbCB3aGVuIG5vdCBjcmVhdGluZwogICAgLy8gdGVzdHMvYXJ0aWZhY3RzL3N0YXRlLW9wcy9jb250cmFjdC5hbGdvLnRzOjI2CiAgICAvLyBleHBvcnQgY2xhc3MgU3RhdGVBY2N0UGFyYW1zR2V0Q29udHJhY3QgZXh0ZW5kcyBhcmM0LkNvbnRyYWN0IHsKICAgIHR4bmEgQXBwbGljYXRpb25BcmdzIDEKICAgIGJ0b2kKICAgIHR4bmFzIEFjY291bnRzCiAgICAvLyB0ZXN0cy9hcnRpZmFjdHMvc3RhdGUtb3BzL2NvbnRyYWN0LmFsZ28udHM6OTYKICAgIC8vIEBhcmM0LmFiaW1ldGhvZCgpCiAgICBjYWxsc3ViIHZlcmlmeV9hY2N0X3RvdGFsX2FwcHNfb3B0ZWRfaW4KICAgIGl0b2IKICAgIGJ5dGVjXzAgLy8gMHgxNTFmN2M3NQogICAgc3dhcAogICAgY29uY2F0CiAgICBsb2cKICAgIGludGNfMCAvLyAxCiAgICByZXRzdWIKCl9fcHV5YV9hcmM0X3JvdXRlcl9fX3ZlcmlmeV9hY2N0X3RvdGFsX2Fzc2V0c19jcmVhdGVkX3JvdXRlQDEwOgogICAgLy8gdGVzdHMvYXJ0aWZhY3RzL3N0YXRlLW9wcy9jb250cmFjdC5hbGdvLnRzOjEwNQogICAgLy8gQGFyYzQuYWJpbWV0aG9kKCkKICAgIHR4biBPbkNvbXBsZXRpb24KICAgICEKICAgIGFzc2VydCAvLyBPbkNvbXBsZXRpb24gaXMgbm90IE5vT3AKICAgIHR4biBBcHBsaWNhdGlvbklECiAgICBhc3NlcnQgLy8gY2FuIG9ubHkgY2FsbCB3aGVuIG5vdCBjcmVhdGluZwogICAgLy8gdGVzdHMvYXJ0aWZhY3RzL3N0YXRlLW9wcy9jb250cmFjdC5hbGdvLnRzOjI2CiAgICAvLyBleHBvcnQgY2xhc3MgU3RhdGVBY2N0UGFyYW1zR2V0Q29udHJhY3QgZXh0ZW5kcyBhcmM0LkNvbnRyYWN0IHsKICAgIHR4bmEgQXBwbGljYXRpb25BcmdzIDEKICAgIGJ0b2kKICAgIHR4bmFzIEFjY291bnRzCiAgICAvLyB0ZXN0cy9hcnRpZmFjdHMvc3RhdGUtb3BzL2NvbnRyYWN0LmFsZ28udHM6MTA1CiAgICAvLyBAYXJjNC5hYmltZXRob2QoKQogICAgY2FsbHN1YiB2ZXJpZnlfYWNjdF90b3RhbF9hc3NldHNfY3JlYXRlZAogICAgaXRvYgogICAgYnl0ZWNfMCAvLyAweDE1MWY3Yzc1CiAgICBzd2FwCiAgICBjb25jYXQKICAgIGxvZwogICAgaW50Y18wIC8vIDEKICAgIHJldHN1YgoKX19wdXlhX2FyYzRfcm91dGVyX19fdmVyaWZ5X2FjY3RfdG90YWxfYXNzZXRzX3JvdXRlQDExOgogICAgLy8gdGVzdHMvYXJ0aWZhY3RzL3N0YXRlLW9wcy9jb250cmFjdC5hbGdvLnRzOjExNAogICAgLy8gQGFyYzQuYWJpbWV0aG9kKCkKICAgIHR4biBPbkNvbXBsZXRpb24KICAgICEKICAgIGFzc2VydCAvLyBPbkNvbXBsZXRpb24gaXMgbm90IE5vT3AKICAgIHR4biBBcHBsaWNhdGlvbklECiAgICBhc3NlcnQgLy8gY2FuIG9ubHkgY2FsbCB3aGVuIG5vdCBjcmVhdGluZwogICAgLy8gdGVzdHMvYXJ0aWZhY3RzL3N0YXRlLW9wcy9jb250cmFjdC5hbGdvLnRzOjI2CiAgICAvLyBleHBvcnQgY2xhc3MgU3RhdGVBY2N0UGFyYW1zR2V0Q29udHJhY3QgZXh0ZW5kcyBhcmM0LkNvbnRyYWN0IHsKICAgIHR4bmEgQXBwbGljYXRpb25BcmdzIDEKICAgIGJ0b2kKICAgIHR4bmFzIEFjY291bnRzCiAgICAvLyB0ZXN0cy9hcnRpZmFjdHMvc3RhdGUtb3BzL2NvbnRyYWN0LmFsZ28udHM6MTE0CiAgICAvLyBAYXJjNC5hYmltZXRob2QoKQogICAgY2FsbHN1YiB2ZXJpZnlfYWNjdF90b3RhbF9hc3NldHMKICAgIGl0b2IKICAgIGJ5dGVjXzAgLy8gMHgxNTFmN2M3NQogICAgc3dhcAogICAgY29uY2F0CiAgICBsb2cKICAgIGludGNfMCAvLyAxCiAgICByZXRzdWIKCl9fcHV5YV9hcmM0X3JvdXRlcl9fX3ZlcmlmeV9hY2N0X3RvdGFsX2JveGVzX3JvdXRlQDEyOgogICAgLy8gdGVzdHMvYXJ0aWZhY3RzL3N0YXRlLW9wcy9jb250cmFjdC5hbGdvLnRzOjEyMwogICAgLy8gQGFyYzQuYWJpbWV0aG9kKCkKICAgIHR4biBPbkNvbXBsZXRpb24KICAgICEKICAgIGFzc2VydCAvLyBPbkNvbXBsZXRpb24gaXMgbm90IE5vT3AKICAgIHR4biBBcHBsaWNhdGlvbklECiAgICBhc3NlcnQgLy8gY2FuIG9ubHkgY2FsbCB3aGVuIG5vdCBjcmVhdGluZwogICAgLy8gdGVzdHMvYXJ0aWZhY3RzL3N0YXRlLW9wcy9jb250cmFjdC5hbGdvLnRzOjI2CiAgICAvLyBleHBvcnQgY2xhc3MgU3RhdGVBY2N0UGFyYW1zR2V0Q29udHJhY3QgZXh0ZW5kcyBhcmM0LkNvbnRyYWN0IHsKICAgIHR4bmEgQXBwbGljYXRpb25BcmdzIDEKICAgIGJ0b2kKICAgIHR4bmFzIEFjY291bnRzCiAgICAvLyB0ZXN0cy9hcnRpZmFjdHMvc3RhdGUtb3BzL2NvbnRyYWN0LmFsZ28udHM6MTIzCiAgICAvLyBAYXJjNC5hYmltZXRob2QoKQogICAgY2FsbHN1YiB2ZXJpZnlfYWNjdF90b3RhbF9ib3hlcwogICAgaXRvYgogICAgYnl0ZWNfMCAvLyAweDE1MWY3Yzc1CiAgICBzd2FwCiAgICBjb25jYXQKICAgIGxvZwogICAgaW50Y18wIC8vIDEKICAgIHJldHN1YgoKX19wdXlhX2FyYzRfcm91dGVyX19fdmVyaWZ5X2FjY3RfdG90YWxfYm94X2J5dGVzX3JvdXRlQDEzOgogICAgLy8gdGVzdHMvYXJ0aWZhY3RzL3N0YXRlLW9wcy9jb250cmFjdC5hbGdvLnRzOjEzMgogICAgLy8gQGFyYzQuYWJpbWV0aG9kKCkKICAgIHR4biBPbkNvbXBsZXRpb24KICAgICEKICAgIGFzc2VydCAvLyBPbkNvbXBsZXRpb24gaXMgbm90IE5vT3AKICAgIHR4biBBcHBsaWNhdGlvbklECiAgICBhc3NlcnQgLy8gY2FuIG9ubHkgY2FsbCB3aGVuIG5vdCBjcmVhdGluZwogICAgLy8gdGVzdHMvYXJ0aWZhY3RzL3N0YXRlLW9wcy9jb250cmFjdC5hbGdvLnRzOjI2CiAgICAvLyBleHBvcnQgY2xhc3MgU3RhdGVBY2N0UGFyYW1zR2V0Q29udHJhY3QgZXh0ZW5kcyBhcmM0LkNvbnRyYWN0IHsKICAgIHR4bmEgQXBwbGljYXRpb25BcmdzIDEKICAgIGJ0b2kKICAgIHR4bmFzIEFjY291bnRzCiAgICAvLyB0ZXN0cy9hcnRpZmFjdHMvc3RhdGUtb3BzL2NvbnRyYWN0LmFsZ28udHM6MTMyCiAgICAvLyBAYXJjNC5hYmltZXRob2QoKQogICAgY2FsbHN1YiB2ZXJpZnlfYWNjdF90b3RhbF9ib3hfYnl0ZXMKICAgIGl0b2IKICAgIGJ5dGVjXzAgLy8gMHgxNTFmN2M3NQogICAgc3dhcAogICAgY29uY2F0CiAgICBsb2cKICAgIGludGNfMCAvLyAxCiAgICByZXRzdWIKCl9fcHV5YV9hcmM0X3JvdXRlcl9fX2JhcmVfcm91dGluZ0AxNjoKICAgIC8vIHRlc3RzL2FydGlmYWN0cy9zdGF0ZS1vcHMvY29udHJhY3QuYWxnby50czoyNgogICAgLy8gZXhwb3J0IGNsYXNzIFN0YXRlQWNjdFBhcmFtc0dldENvbnRyYWN0IGV4dGVuZHMgYXJjNC5Db250cmFjdCB7CiAgICB0eG4gT25Db21wbGV0aW9uCiAgICBibnogX19wdXlhX2FyYzRfcm91dGVyX19fYWZ0ZXJfaWZfZWxzZUAyMAogICAgdHhuIEFwcGxpY2F0aW9uSUQKICAgICEKICAgIGFzc2VydCAvLyBjYW4gb25seSBjYWxsIHdoZW4gY3JlYXRpbmcKICAgIGludGNfMCAvLyAxCiAgICByZXRzdWIKCl9fcHV5YV9hcmM0X3JvdXRlcl9fX2FmdGVyX2lmX2Vsc2VAMjA6CiAgICAvLyB0ZXN0cy9hcnRpZmFjdHMvc3RhdGUtb3BzL2NvbnRyYWN0LmFsZ28udHM6MjYKICAgIC8vIGV4cG9ydCBjbGFzcyBTdGF0ZUFjY3RQYXJhbXNHZXRDb250cmFjdCBleHRlbmRzIGFyYzQuQ29udHJhY3QgewogICAgaW50Y18xIC8vIDAKICAgIHJldHN1YgoKCi8vIHRlc3RzL2FydGlmYWN0cy9zdGF0ZS1vcHMvY29udHJhY3QuYWxnby50czo6U3RhdGVBY2N0UGFyYW1zR2V0Q29udHJhY3QudmVyaWZ5X2FjY3RfYmFsYW5jZShhOiBieXRlcykgLT4gdWludDY0Ogp2ZXJpZnlfYWNjdF9iYWxhbmNlOgogICAgLy8gdGVzdHMvYXJ0aWZhY3RzL3N0YXRlLW9wcy9jb250cmFjdC5hbGdvLnRzOjI3LTI4CiAgICAvLyBAYXJjNC5hYmltZXRob2QoKQogICAgLy8gcHVibGljIHZlcmlmeV9hY2N0X2JhbGFuY2UoYTogQWNjb3VudCk6IHVpbnQ2NCB7CiAgICBwcm90byAxIDEKICAgIC8vIHRlc3RzL2FydGlmYWN0cy9zdGF0ZS1vcHMvY29udHJhY3QuYWxnby50czoyOQogICAgLy8gY29uc3QgW3ZhbHVlLCBmdW5kZWRdID0gb3AuQWNjdFBhcmFtcy5hY2N0QmFsYW5jZShhKQogICAgZnJhbWVfZGlnIC0xCiAgICBhY2N0X3BhcmFtc19nZXQgQWNjdEJhbGFuY2UKICAgIC8vIHRlc3RzL2FydGlmYWN0cy9zdGF0ZS1vcHMvY29udHJhY3QuYWxnby50czozMAogICAgLy8gY29uc3QgW3ZhbHVlX2luZGV4LCBmdW5kZWRfaW5kZXhdID0gb3AuQWNjdFBhcmFtcy5hY2N0QmFsYW5jZShnZXRfMXN0X3JlZl9pbmRleCgpKQogICAgY2FsbHN1YiBnZXRfMXN0X3JlZl9pbmRleAogICAgYWNjdF9wYXJhbXNfZ2V0IEFjY3RCYWxhbmNlCiAgICAvLyB0ZXN0cy9hcnRpZmFjdHMvc3RhdGUtb3BzL2NvbnRyYWN0LmFsZ28udHM6MzEKICAgIC8vIGFzc2VydCh2YWx1ZSA9PT0gdmFsdWVfaW5kZXgsICdleHBlY3RlZCB2YWx1ZSBieSBpbmRleCB0byBtYXRjaCcpCiAgICBkaWcgMwogICAgdW5jb3ZlciAyCiAgICA9PQogICAgYXNzZXJ0IC8vIGV4cGVjdGVkIHZhbHVlIGJ5IGluZGV4IHRvIG1hdGNoCiAgICAvLyB0ZXN0cy9hcnRpZmFjdHMvc3RhdGUtb3BzL2NvbnRyYWN0LmFsZ28udHM6MzIKICAgIC8vIGFzc2VydChmdW5kZWQgPT09IGZ1bmRlZF9pbmRleCwgJ2V4cGVjdGVkIGZ1bmRlZCBieSBpbmRleCB0byBtYXRjaCcpCiAgICA9PQogICAgYXNzZXJ0IC8vIGV4cGVjdGVkIGZ1bmRlZCBieSBpbmRleCB0byBtYXRjaAogICAgLy8gdGVzdHMvYXJ0aWZhY3RzL3N0YXRlLW9wcy9jb250cmFjdC5hbGdvLnRzOjMzCiAgICAvLyBhc3NlcnQodmFsdWUgPT09IGEuYmFsYW5jZSwgJ2V4cGVjdGVkIEFjY291bnQgYmFsYW5jZSB0byBtYXRjaCcpCiAgICBmcmFtZV9kaWcgLTEKICAgIGFjY3RfcGFyYW1zX2dldCBBY2N0QmFsYW5jZQogICAgYXNzZXJ0IC8vIGFjY291bnQgZnVuZGVkCiAgICBkaWcgMQogICAgPT0KICAgIGFzc2VydCAvLyBleHBlY3RlZCBBY2NvdW50IGJhbGFuY2UgdG8gbWF0Y2gKICAgIC8vIHRlc3RzL2FydGlmYWN0cy9zdGF0ZS1vcHMvY29udHJhY3QuYWxnby50czozNAogICAgLy8gYXNzZXJ0KHZhbHVlID09PSBvcC5iYWxhbmNlKGEpLCAnZXhwZWN0ZWQgb3AuYmFsYW5jZSB0byBtYXRjaCcpCiAgICBmcmFtZV9kaWcgLTEKICAgIGJhbGFuY2UKICAgIGRpZyAxCiAgICA9PQogICAgYXNzZXJ0IC8vIGV4cGVjdGVkIG9wLmJhbGFuY2UgdG8gbWF0Y2gKICAgIC8vIHRlc3RzL2FydGlmYWN0cy9zdGF0ZS1vcHMvY29udHJhY3QuYWxnby50czozNQogICAgLy8gYXNzZXJ0KHZhbHVlID09PSBvcC5iYWxhbmNlKGdldF8xc3RfcmVmX2luZGV4KCkpLCAnZXhwZWN0ZWQgb3AuYmFsYW5jZSBieSBpbmRleCB0byBtYXRjaCcpCiAgICBjYWxsc3ViIGdldF8xc3RfcmVmX2luZGV4CiAgICBiYWxhbmNlCiAgICBkaWcgMQogICAgPT0KICAgIGFzc2VydCAvLyBleHBlY3RlZCBvcC5iYWxhbmNlIGJ5IGluZGV4IHRvIG1hdGNoCiAgICAvLyB0ZXN0cy9hcnRpZmFjdHMvc3RhdGUtb3BzL2NvbnRyYWN0LmFsZ28udHM6MzYKICAgIC8vIHJldHVybiB2YWx1ZQogICAgcmV0c3ViCgoKLy8gdGVzdHMvYXJ0aWZhY3RzL3N0YXRlLW9wcy9jb250cmFjdC5hbGdvLnRzOjpnZXRfMXN0X3JlZl9pbmRleCgpIC0+IHVpbnQ2NDoKZ2V0XzFzdF9yZWZfaW5kZXg6CiAgICAvLyB0ZXN0cy9hcnRpZmFjdHMvc3RhdGUtb3BzL2NvbnRyYWN0LmFsZ28udHM6MjIKICAgIC8vIGZ1bmN0aW9uIGdldF8xc3RfcmVmX2luZGV4KCk6IHVpbnQ2NCB7CiAgICBwcm90byAwIDEKICAgIC8vIHRlc3RzL2FydGlmYWN0cy9zdGF0ZS1vcHMvY29udHJhY3QuYWxnby50czoyMwogICAgLy8gcmV0dXJuIG9wLmJ0b2koVHhuLmFwcGxpY2F0aW9uQXJncygxKSkKICAgIGludGNfMCAvLyAxCiAgICB0eG5hcyBBcHBsaWNhdGlvbkFyZ3MKICAgIGJ0b2kKICAgIHJldHN1YgoKCi8vIHRlc3RzL2FydGlmYWN0cy9zdGF0ZS1vcHMvY29udHJhY3QuYWxnby50czo6U3RhdGVBY2N0UGFyYW1zR2V0Q29udHJhY3QudmVyaWZ5X2FjY3RfbWluX2JhbGFuY2UoYTogYnl0ZXMpIC0+IHVpbnQ2NDoKdmVyaWZ5X2FjY3RfbWluX2JhbGFuY2U6CiAgICAvLyB0ZXN0cy9hcnRpZmFjdHMvc3RhdGUtb3BzL2NvbnRyYWN0LmFsZ28udHM6MzktNDAKICAgIC8vIEBhcmM0LmFiaW1ldGhvZCgpCiAgICAvLyBwdWJsaWMgdmVyaWZ5X2FjY3RfbWluX2JhbGFuY2UoYTogQWNjb3VudCk6IHVpbnQ2NCB7CiAgICBwcm90byAxIDEKICAgIC8vIHRlc3RzL2FydGlmYWN0cy9zdGF0ZS1vcHMvY29udHJhY3QuYWxnby50czo0MQogICAgLy8gY29uc3QgW3ZhbHVlLCBmdW5kZWRdID0gb3AuQWNjdFBhcmFtcy5hY2N0TWluQmFsYW5jZShhKQogICAgZnJhbWVfZGlnIC0xCiAgICBhY2N0X3BhcmFtc19nZXQgQWNjdE1pbkJhbGFuY2UKICAgIC8vIHRlc3RzL2FydGlmYWN0cy9zdGF0ZS1vcHMvY29udHJhY3QuYWxnby50czo0MgogICAgLy8gY29uc3QgW3ZhbHVlX2luZGV4LCBmdW5kZWRfaW5kZXhdID0gb3AuQWNjdFBhcmFtcy5hY2N0TWluQmFsYW5jZShnZXRfMXN0X3JlZl9pbmRleCgpKQogICAgY2FsbHN1YiBnZXRfMXN0X3JlZl9pbmRleAogICAgYWNjdF9wYXJhbXNfZ2V0IEFjY3RNaW5CYWxhbmNlCiAgICAvLyB0ZXN0cy9hcnRpZmFjdHMvc3RhdGUtb3BzL2NvbnRyYWN0LmFsZ28udHM6NDMKICAgIC8vIGFzc2VydCh2YWx1ZSA9PT0gdmFsdWVfaW5kZXgsICdleHBlY3RlZCB2YWx1ZSBieSBpbmRleCB0byBtYXRjaCcpCiAgICBkaWcgMwogICAgdW5jb3ZlciAyCiAgICA9PQogICAgYXNzZXJ0IC8vIGV4cGVjdGVkIHZhbHVlIGJ5IGluZGV4IHRvIG1hdGNoCiAgICAvLyB0ZXN0cy9hcnRpZmFjdHMvc3RhdGUtb3BzL2NvbnRyYWN0LmFsZ28udHM6NDQKICAgIC8vIGFzc2VydChmdW5kZWQgPT09IGZ1bmRlZF9pbmRleCwgJ2V4cGVjdGVkIGZ1bmRlZCBieSBpbmRleCB0byBtYXRjaCcpCiAgICA9PQogICAgYXNzZXJ0IC8vIGV4cGVjdGVkIGZ1bmRlZCBieSBpbmRleCB0byBtYXRjaAogICAgLy8gdGVzdHMvYXJ0aWZhY3RzL3N0YXRlLW9wcy9jb250cmFjdC5hbGdvLnRzOjQ1CiAgICAvLyBhc3NlcnQodmFsdWUgPT09IGEubWluQmFsYW5jZSwgJ2V4cGVjdGVkIEFjY291bnQgbWluX2JhbGFuY2UgdG8gbWF0Y2gnKQogICAgZnJhbWVfZGlnIC0xCiAgICBhY2N0X3BhcmFtc19nZXQgQWNjdE1pbkJhbGFuY2UKICAgIGFzc2VydCAvLyBhY2NvdW50IGZ1bmRlZAogICAgZGlnIDEKICAgID09CiAgICBhc3NlcnQgLy8gZXhwZWN0ZWQgQWNjb3VudCBtaW5fYmFsYW5jZSB0byBtYXRjaAogICAgLy8gdGVzdHMvYXJ0aWZhY3RzL3N0YXRlLW9wcy9jb250cmFjdC5hbGdvLnRzOjQ2CiAgICAvLyBhc3NlcnQodmFsdWUgPT09IG9wLm1pbkJhbGFuY2UoYSksICdleHBlY3RlZCBvcC5taW5fYmFsYW5jZSB0byBtYXRjaCcpCiAgICBmcmFtZV9kaWcgLTEKICAgIG1pbl9iYWxhbmNlCiAgICBkaWcgMQogICAgPT0KICAgIGFzc2VydCAvLyBleHBlY3RlZCBvcC5taW5fYmFsYW5jZSB0byBtYXRjaAogICAgLy8gdGVzdHMvYXJ0aWZhY3RzL3N0YXRlLW9wcy9jb250cmFjdC5hbGdvLnRzOjQ3CiAgICAvLyBhc3NlcnQodmFsdWUgPT09IG9wLm1pbkJhbGFuY2UoZ2V0XzFzdF9yZWZfaW5kZXgoKSksICdleHBlY3RlZCBvcC5taW5fYmFsYW5jZSBieSBpbmRleCB0byBtYXRjaCcpCiAgICBjYWxsc3ViIGdldF8xc3RfcmVmX2luZGV4CiAgICBtaW5fYmFsYW5jZQogICAgZGlnIDEKICAgID09CiAgICBhc3NlcnQgLy8gZXhwZWN0ZWQgb3AubWluX2JhbGFuY2UgYnkgaW5kZXggdG8gbWF0Y2gKICAgIC8vIHRlc3RzL2FydGlmYWN0cy9zdGF0ZS1vcHMvY29udHJhY3QuYWxnby50czo0OAogICAgLy8gcmV0dXJuIHZhbHVlCiAgICByZXRzdWIKCgovLyB0ZXN0cy9hcnRpZmFjdHMvc3RhdGUtb3BzL2NvbnRyYWN0LmFsZ28udHM6OlN0YXRlQWNjdFBhcmFtc0dldENvbnRyYWN0LnZlcmlmeV9hY2N0X2F1dGhfYWRkcihhOiBieXRlcykgLT4gYnl0ZXM6CnZlcmlmeV9hY2N0X2F1dGhfYWRkcjoKICAgIC8vIHRlc3RzL2FydGlmYWN0cy9zdGF0ZS1vcHMvY29udHJhY3QuYWxnby50czo1MS01MgogICAgLy8gQGFyYzQuYWJpbWV0aG9kKCkKICAgIC8vIHB1YmxpYyB2ZXJpZnlfYWNjdF9hdXRoX2FkZHIoYTogQWNjb3VudCk6IEFkZHJlc3MgewogICAgcHJvdG8gMSAxCiAgICAvLyB0ZXN0cy9hcnRpZmFjdHMvc3RhdGUtb3BzL2NvbnRyYWN0LmFsZ28udHM6NTMKICAgIC8vIGNvbnN0IFt2YWx1ZSwgZnVuZGVkXSA9IG9wLkFjY3RQYXJhbXMuYWNjdEF1dGhBZGRyKGEpCiAgICBmcmFtZV9kaWcgLTEKICAgIGFjY3RfcGFyYW1zX2dldCBBY2N0QXV0aEFkZHIKICAgIC8vIHRlc3RzL2FydGlmYWN0cy9zdGF0ZS1vcHMvY29udHJhY3QuYWxnby50czo1NAogICAgLy8gY29uc3QgW3ZhbHVlX2luZGV4LCBmdW5kZWRfaW5kZXhdID0gb3AuQWNjdFBhcmFtcy5hY2N0QXV0aEFkZHIoZ2V0XzFzdF9yZWZfaW5kZXgoKSkKICAgIGNhbGxzdWIgZ2V0XzFzdF9yZWZfaW5kZXgKICAgIGFjY3RfcGFyYW1zX2dldCBBY2N0QXV0aEFkZHIKICAgIC8vIHRlc3RzL2FydGlmYWN0cy9zdGF0ZS1vcHMvY29udHJhY3QuYWxnby50czo1NQogICAgLy8gYXNzZXJ0KHZhbHVlID09PSB2YWx1ZV9pbmRleCwgJ2V4cGVjdGVkIHZhbHVlIGJ5IGluZGV4IHRvIG1hdGNoJykKICAgIGRpZyAzCiAgICB1bmNvdmVyIDIKICAgID09CiAgICBhc3NlcnQgLy8gZXhwZWN0ZWQgdmFsdWUgYnkgaW5kZXggdG8gbWF0Y2gKICAgIC8vIHRlc3RzL2FydGlmYWN0cy9zdGF0ZS1vcHMvY29udHJhY3QuYWxnby50czo1NgogICAgLy8gYXNzZXJ0KGZ1bmRlZCA9PT0gZnVuZGVkX2luZGV4LCAnZXhwZWN0ZWQgZnVuZGVkIGJ5IGluZGV4IHRvIG1hdGNoJykKICAgID09CiAgICBhc3NlcnQgLy8gZXhwZWN0ZWQgZnVuZGVkIGJ5IGluZGV4IHRvIG1hdGNoCiAgICAvLyB0ZXN0cy9hcnRpZmFjdHMvc3RhdGUtb3BzL2NvbnRyYWN0LmFsZ28udHM6NTcKICAgIC8vIHJldHVybiBuZXcgQWRkcmVzcyh2YWx1ZSkKICAgIHJldHN1YgoKCi8vIHRlc3RzL2FydGlmYWN0cy9zdGF0ZS1vcHMvY29udHJhY3QuYWxnby50czo6U3RhdGVBY2N0UGFyYW1zR2V0Q29udHJhY3QudmVyaWZ5X2FjY3RfdG90YWxfbnVtX3VpbnQoYTogYnl0ZXMpIC0+IHVpbnQ2NDoKdmVyaWZ5X2FjY3RfdG90YWxfbnVtX3VpbnQ6CiAgICAvLyB0ZXN0cy9hcnRpZmFjdHMvc3RhdGUtb3BzL2NvbnRyYWN0LmFsZ28udHM6NjAtNjEKICAgIC8vIEBhcmM0LmFiaW1ldGhvZCgpCiAgICAvLyBwdWJsaWMgdmVyaWZ5X2FjY3RfdG90YWxfbnVtX3VpbnQoYTogQWNjb3VudCk6IHVpbnQ2NCB7CiAgICBwcm90byAxIDEKICAgIC8vIHRlc3RzL2FydGlmYWN0cy9zdGF0ZS1vcHMvY29udHJhY3QuYWxnby50czo2MgogICAgLy8gY29uc3QgW3ZhbHVlLCBmdW5kZWRdID0gb3AuQWNjdFBhcmFtcy5hY2N0VG90YWxOdW1VaW50KGEpCiAgICBmcmFtZV9kaWcgLTEKICAgIGFjY3RfcGFyYW1zX2dldCBBY2N0VG90YWxOdW1VaW50CiAgICAvLyB0ZXN0cy9hcnRpZmFjdHMvc3RhdGUtb3BzL2NvbnRyYWN0LmFsZ28udHM6NjMKICAgIC8vIGNvbnN0IFt2YWx1ZV9pbmRleCwgZnVuZGVkX2luZGV4XSA9IG9wLkFjY3RQYXJhbXMuYWNjdFRvdGFsTnVtVWludChnZXRfMXN0X3JlZl9pbmRleCgpKQogICAgY2FsbHN1YiBnZXRfMXN0X3JlZl9pbmRleAogICAgYWNjdF9wYXJhbXNfZ2V0IEFjY3RUb3RhbE51bVVpbnQKICAgIC8vIHRlc3RzL2FydGlmYWN0cy9zdGF0ZS1vcHMvY29udHJhY3QuYWxnby50czo2NAogICAgLy8gYXNzZXJ0KHZhbHVlID09PSB2YWx1ZV9pbmRleCwgJ2V4cGVjdGVkIHZhbHVlIGJ5IGluZGV4IHRvIG1hdGNoJykKICAgIGRpZyAzCiAgICB1bmNvdmVyIDIKICAgID09CiAgICBhc3NlcnQgLy8gZXhwZWN0ZWQgdmFsdWUgYnkgaW5kZXggdG8gbWF0Y2gKICAgIC8vIHRlc3RzL2FydGlmYWN0cy9zdGF0ZS1vcHMvY29udHJhY3QuYWxnby50czo2NQogICAgLy8gYXNzZXJ0KGZ1bmRlZCA9PT0gZnVuZGVkX2luZGV4LCAnZXhwZWN0ZWQgZnVuZGVkIGJ5IGluZGV4IHRvIG1hdGNoJykKICAgID09CiAgICBhc3NlcnQgLy8gZXhwZWN0ZWQgZnVuZGVkIGJ5IGluZGV4IHRvIG1hdGNoCiAgICAvLyB0ZXN0cy9hcnRpZmFjdHMvc3RhdGUtb3BzL2NvbnRyYWN0LmFsZ28udHM6NjYKICAgIC8vIHJldHVybiB2YWx1ZQogICAgcmV0c3ViCgoKLy8gdGVzdHMvYXJ0aWZhY3RzL3N0YXRlLW9wcy9jb250cmFjdC5hbGdvLnRzOjpTdGF0ZUFjY3RQYXJhbXNHZXRDb250cmFjdC52ZXJpZnlfYWNjdF90b3RhbF9udW1fYnl0ZV9zbGljZShhOiBieXRlcykgLT4gdWludDY0Ogp2ZXJpZnlfYWNjdF90b3RhbF9udW1fYnl0ZV9zbGljZToKICAgIC8vIHRlc3RzL2FydGlmYWN0cy9zdGF0ZS1vcHMvY29udHJhY3QuYWxnby50czo2OS03MAogICAgLy8gQGFyYzQuYWJpbWV0aG9kKCkKICAgIC8vIHB1YmxpYyB2ZXJpZnlfYWNjdF90b3RhbF9udW1fYnl0ZV9zbGljZShhOiBBY2NvdW50KTogdWludDY0IHsKICAgIHByb3RvIDEgMQogICAgLy8gdGVzdHMvYXJ0aWZhY3RzL3N0YXRlLW9wcy9jb250cmFjdC5hbGdvLnRzOjcxCiAgICAvLyBjb25zdCBbdmFsdWUsIGZ1bmRlZF0gPSBvcC5BY2N0UGFyYW1zLmFjY3RUb3RhbE51bUJ5dGVTbGljZShhKQogICAgZnJhbWVfZGlnIC0xCiAgICBhY2N0X3BhcmFtc19nZXQgQWNjdFRvdGFsTnVtQnl0ZVNsaWNlCiAgICAvLyB0ZXN0cy9hcnRpZmFjdHMvc3RhdGUtb3BzL2NvbnRyYWN0LmFsZ28udHM6NzIKICAgIC8vIGNvbnN0IFt2YWx1ZV9pbmRleCwgZnVuZGVkX2luZGV4XSA9IG9wLkFjY3RQYXJhbXMuYWNjdFRvdGFsTnVtQnl0ZVNsaWNlKGdldF8xc3RfcmVmX2luZGV4KCkpCiAgICBjYWxsc3ViIGdldF8xc3RfcmVmX2luZGV4CiAgICBhY2N0X3BhcmFtc19nZXQgQWNjdFRvdGFsTnVtQnl0ZVNsaWNlCiAgICAvLyB0ZXN0cy9hcnRpZmFjdHMvc3RhdGUtb3BzL2NvbnRyYWN0LmFsZ28udHM6NzMKICAgIC8vIGFzc2VydCh2YWx1ZSA9PT0gdmFsdWVfaW5kZXgsICdleHBlY3RlZCB2YWx1ZSBieSBpbmRleCB0byBtYXRjaCcpCiAgICBkaWcgMwogICAgdW5jb3ZlciAyCiAgICA9PQogICAgYXNzZXJ0IC8vIGV4cGVjdGVkIHZhbHVlIGJ5IGluZGV4IHRvIG1hdGNoCiAgICAvLyB0ZXN0cy9hcnRpZmFjdHMvc3RhdGUtb3BzL2NvbnRyYWN0LmFsZ28udHM6NzQKICAgIC8vIGFzc2VydChmdW5kZWQgPT09IGZ1bmRlZF9pbmRleCwgJ2V4cGVjdGVkIGZ1bmRlZCBieSBpbmRleCB0byBtYXRjaCcpCiAgICA9PQogICAgYXNzZXJ0IC8vIGV4cGVjdGVkIGZ1bmRlZCBieSBpbmRleCB0byBtYXRjaAogICAgLy8gdGVzdHMvYXJ0aWZhY3RzL3N0YXRlLW9wcy9jb250cmFjdC5hbGdvLnRzOjc1CiAgICAvLyByZXR1cm4gdmFsdWUKICAgIHJldHN1YgoKCi8vIHRlc3RzL2FydGlmYWN0cy9zdGF0ZS1vcHMvY29udHJhY3QuYWxnby50czo6U3RhdGVBY2N0UGFyYW1zR2V0Q29udHJhY3QudmVyaWZ5X2FjY3RfdG90YWxfZXh0cmFfYXBwX3BhZ2VzKGE6IGJ5dGVzKSAtPiB1aW50NjQ6CnZlcmlmeV9hY2N0X3RvdGFsX2V4dHJhX2FwcF9wYWdlczoKICAgIC8vIHRlc3RzL2FydGlmYWN0cy9zdGF0ZS1vcHMvY29udHJhY3QuYWxnby50czo3OC03OQogICAgLy8gQGFyYzQuYWJpbWV0aG9kKCkKICAgIC8vIHB1YmxpYyB2ZXJpZnlfYWNjdF90b3RhbF9leHRyYV9hcHBfcGFnZXMoYTogQWNjb3VudCk6IHVpbnQ2NCB7CiAgICBwcm90byAxIDEKICAgIC8vIHRlc3RzL2FydGlmYWN0cy9zdGF0ZS1vcHMvY29udHJhY3QuYWxnby50czo4MAogICAgLy8gY29uc3QgW3ZhbHVlLCBmdW5kZWRdID0gb3AuQWNjdFBhcmFtcy5hY2N0VG90YWxFeHRyYUFwcFBhZ2VzKGEpCiAgICBmcmFtZV9kaWcgLTEKICAgIGFjY3RfcGFyYW1zX2dldCBBY2N0VG90YWxFeHRyYUFwcFBhZ2VzCiAgICAvLyB0ZXN0cy9hcnRpZmFjdHMvc3RhdGUtb3BzL2NvbnRyYWN0LmFsZ28udHM6ODEKICAgIC8vIGNvbnN0IFt2YWx1ZV9pbmRleCwgZnVuZGVkX2luZGV4XSA9IG9wLkFjY3RQYXJhbXMuYWNjdFRvdGFsRXh0cmFBcHBQYWdlcyhnZXRfMXN0X3JlZl9pbmRleCgpKQogICAgY2FsbHN1YiBnZXRfMXN0X3JlZl9pbmRleAogICAgYWNjdF9wYXJhbXNfZ2V0IEFjY3RUb3RhbEV4dHJhQXBwUGFnZXMKICAgIC8vIHRlc3RzL2FydGlmYWN0cy9zdGF0ZS1vcHMvY29udHJhY3QuYWxnby50czo4MgogICAgLy8gYXNzZXJ0KHZhbHVlID09PSB2YWx1ZV9pbmRleCwgJ2V4cGVjdGVkIHZhbHVlIGJ5IGluZGV4IHRvIG1hdGNoJykKICAgIGRpZyAzCiAgICB1bmNvdmVyIDIKICAgID09CiAgICBhc3NlcnQgLy8gZXhwZWN0ZWQgdmFsdWUgYnkgaW5kZXggdG8gbWF0Y2gKICAgIC8vIHRlc3RzL2FydGlmYWN0cy9zdGF0ZS1vcHMvY29udHJhY3QuYWxnby50czo4MwogICAgLy8gYXNzZXJ0KGZ1bmRlZCA9PT0gZnVuZGVkX2luZGV4LCAnZXhwZWN0ZWQgZnVuZGVkIGJ5IGluZGV4IHRvIG1hdGNoJykKICAgID09CiAgICBhc3NlcnQgLy8gZXhwZWN0ZWQgZnVuZGVkIGJ5IGluZGV4IHRvIG1hdGNoCiAgICAvLyB0ZXN0cy9hcnRpZmFjdHMvc3RhdGUtb3BzL2NvbnRyYWN0LmFsZ28udHM6ODQKICAgIC8vIHJldHVybiB2YWx1ZQogICAgcmV0c3ViCgoKLy8gdGVzdHMvYXJ0aWZhY3RzL3N0YXRlLW9wcy9jb250cmFjdC5hbGdvLnRzOjpTdGF0ZUFjY3RQYXJhbXNHZXRDb250cmFjdC52ZXJpZnlfYWNjdF90b3RhbF9hcHBzX2NyZWF0ZWQoYTogYnl0ZXMpIC0+IHVpbnQ2NDoKdmVyaWZ5X2FjY3RfdG90YWxfYXBwc19jcmVhdGVkOgogICAgLy8gdGVzdHMvYXJ0aWZhY3RzL3N0YXRlLW9wcy9jb250cmFjdC5hbGdvLnRzOjg3LTg4CiAgICAvLyBAYXJjNC5hYmltZXRob2QoKQogICAgLy8gcHVibGljIHZlcmlmeV9hY2N0X3RvdGFsX2FwcHNfY3JlYXRlZChhOiBBY2NvdW50KTogdWludDY0IHsKICAgIHByb3RvIDEgMQogICAgLy8gdGVzdHMvYXJ0aWZhY3RzL3N0YXRlLW9wcy9jb250cmFjdC5hbGdvLnRzOjg5CiAgICAvLyBjb25zdCBbdmFsdWUsIGZ1bmRlZF0gPSBvcC5BY2N0UGFyYW1zLmFjY3RUb3RhbEFwcHNDcmVhdGVkKGEpCiAgICBmcmFtZV9kaWcgLTEKICAgIGFjY3RfcGFyYW1zX2dldCBBY2N0VG90YWxBcHBzQ3JlYXRlZAogICAgLy8gdGVzdHMvYXJ0aWZhY3RzL3N0YXRlLW9wcy9jb250cmFjdC5hbGdvLnRzOjkwCiAgICAvLyBjb25zdCBbdmFsdWVfaW5kZXgsIGZ1bmRlZF9pbmRleF0gPSBvcC5BY2N0UGFyYW1zLmFjY3RUb3RhbEFwcHNDcmVhdGVkKGdldF8xc3RfcmVmX2luZGV4KCkpCiAgICBjYWxsc3ViIGdldF8xc3RfcmVmX2luZGV4CiAgICBhY2N0X3BhcmFtc19nZXQgQWNjdFRvdGFsQXBwc0NyZWF0ZWQKICAgIC8vIHRlc3RzL2FydGlmYWN0cy9zdGF0ZS1vcHMvY29udHJhY3QuYWxnby50czo5MQogICAgLy8gYXNzZXJ0KHZhbHVlID09PSB2YWx1ZV9pbmRleCwgJ2V4cGVjdGVkIHZhbHVlIGJ5IGluZGV4IHRvIG1hdGNoJykKICAgIGRpZyAzCiAgICB1bmNvdmVyIDIKICAgID09CiAgICBhc3NlcnQgLy8gZXhwZWN0ZWQgdmFsdWUgYnkgaW5kZXggdG8gbWF0Y2gKICAgIC8vIHRlc3RzL2FydGlmYWN0cy9zdGF0ZS1vcHMvY29udHJhY3QuYWxnby50czo5MgogICAgLy8gYXNzZXJ0KGZ1bmRlZCA9PT0gZnVuZGVkX2luZGV4LCAnZXhwZWN0ZWQgZnVuZGVkIGJ5IGluZGV4IHRvIG1hdGNoJykKICAgID09CiAgICBhc3NlcnQgLy8gZXhwZWN0ZWQgZnVuZGVkIGJ5IGluZGV4IHRvIG1hdGNoCiAgICAvLyB0ZXN0cy9hcnRpZmFjdHMvc3RhdGUtb3BzL2NvbnRyYWN0LmFsZ28udHM6OTMKICAgIC8vIHJldHVybiB2YWx1ZQogICAgcmV0c3ViCgoKLy8gdGVzdHMvYXJ0aWZhY3RzL3N0YXRlLW9wcy9jb250cmFjdC5hbGdvLnRzOjpTdGF0ZUFjY3RQYXJhbXNHZXRDb250cmFjdC52ZXJpZnlfYWNjdF90b3RhbF9hcHBzX29wdGVkX2luKGE6IGJ5dGVzKSAtPiB1aW50NjQ6CnZlcmlmeV9hY2N0X3RvdGFsX2FwcHNfb3B0ZWRfaW46CiAgICAvLyB0ZXN0cy9hcnRpZmFjdHMvc3RhdGUtb3BzL2NvbnRyYWN0LmFsZ28udHM6OTYtOTcKICAgIC8vIEBhcmM0LmFiaW1ldGhvZCgpCiAgICAvLyBwdWJsaWMgdmVyaWZ5X2FjY3RfdG90YWxfYXBwc19vcHRlZF9pbihhOiBBY2NvdW50KTogdWludDY0IHsKICAgIHByb3RvIDEgMQogICAgLy8gdGVzdHMvYXJ0aWZhY3RzL3N0YXRlLW9wcy9jb250cmFjdC5hbGdvLnRzOjk4CiAgICAvLyBjb25zdCBbdmFsdWUsIGZ1bmRlZF0gPSBvcC5BY2N0UGFyYW1zLmFjY3RUb3RhbEFwcHNPcHRlZEluKGEpCiAgICBmcmFtZV9kaWcgLTEKICAgIGFjY3RfcGFyYW1zX2dldCBBY2N0VG90YWxBcHBzT3B0ZWRJbgogICAgLy8gdGVzdHMvYXJ0aWZhY3RzL3N0YXRlLW9wcy9jb250cmFjdC5hbGdvLnRzOjk5CiAgICAvLyBjb25zdCBbdmFsdWVfaW5kZXgsIGZ1bmRlZF9pbmRleF0gPSBvcC5BY2N0UGFyYW1zLmFjY3RUb3RhbEFwcHNPcHRlZEluKGdldF8xc3RfcmVmX2luZGV4KCkpCiAgICBjYWxsc3ViIGdldF8xc3RfcmVmX2luZGV4CiAgICBhY2N0X3BhcmFtc19nZXQgQWNjdFRvdGFsQXBwc09wdGVkSW4KICAgIC8vIHRlc3RzL2FydGlmYWN0cy9zdGF0ZS1vcHMvY29udHJhY3QuYWxnby50czoxMDAKICAgIC8vIGFzc2VydCh2YWx1ZSA9PT0gdmFsdWVfaW5kZXgsICdleHBlY3RlZCB2YWx1ZSBieSBpbmRleCB0byBtYXRjaCcpCiAgICBkaWcgMwogICAgdW5jb3ZlciAyCiAgICA9PQogICAgYXNzZXJ0IC8vIGV4cGVjdGVkIHZhbHVlIGJ5IGluZGV4IHRvIG1hdGNoCiAgICAvLyB0ZXN0cy9hcnRpZmFjdHMvc3RhdGUtb3BzL2NvbnRyYWN0LmFsZ28udHM6MTAxCiAgICAvLyBhc3NlcnQoZnVuZGVkID09PSBmdW5kZWRfaW5kZXgsICdleHBlY3RlZCBmdW5kZWQgYnkgaW5kZXggdG8gbWF0Y2gnKQogICAgPT0KICAgIGFzc2VydCAvLyBleHBlY3RlZCBmdW5kZWQgYnkgaW5kZXggdG8gbWF0Y2gKICAgIC8vIHRlc3RzL2FydGlmYWN0cy9zdGF0ZS1vcHMvY29udHJhY3QuYWxnby50czoxMDIKICAgIC8vIHJldHVybiB2YWx1ZQogICAgcmV0c3ViCgoKLy8gdGVzdHMvYXJ0aWZhY3RzL3N0YXRlLW9wcy9jb250cmFjdC5hbGdvLnRzOjpTdGF0ZUFjY3RQYXJhbXNHZXRDb250cmFjdC52ZXJpZnlfYWNjdF90b3RhbF9hc3NldHNfY3JlYXRlZChhOiBieXRlcykgLT4gdWludDY0Ogp2ZXJpZnlfYWNjdF90b3RhbF9hc3NldHNfY3JlYXRlZDoKICAgIC8vIHRlc3RzL2FydGlmYWN0cy9zdGF0ZS1vcHMvY29udHJhY3QuYWxnby50czoxMDUtMTA2CiAgICAvLyBAYXJjNC5hYmltZXRob2QoKQogICAgLy8gcHVibGljIHZlcmlmeV9hY2N0X3RvdGFsX2Fzc2V0c19jcmVhdGVkKGE6IEFjY291bnQpOiB1aW50NjQgewogICAgcHJvdG8gMSAxCiAgICAvLyB0ZXN0cy9hcnRpZmFjdHMvc3RhdGUtb3BzL2NvbnRyYWN0LmFsZ28udHM6MTA3CiAgICAvLyBjb25zdCBbdmFsdWUsIGZ1bmRlZF0gPSBvcC5BY2N0UGFyYW1zLmFjY3RUb3RhbEFzc2V0c0NyZWF0ZWQoYSkKICAgIGZyYW1lX2RpZyAtMQogICAgYWNjdF9wYXJhbXNfZ2V0IEFjY3RUb3RhbEFzc2V0c0NyZWF0ZWQKICAgIC8vIHRlc3RzL2FydGlmYWN0cy9zdGF0ZS1vcHMvY29udHJhY3QuYWxnby50czoxMDgKICAgIC8vIGNvbnN0IFt2YWx1ZV9pbmRleCwgZnVuZGVkX2luZGV4XSA9IG9wLkFjY3RQYXJhbXMuYWNjdFRvdGFsQXNzZXRzQ3JlYXRlZChnZXRfMXN0X3JlZl9pbmRleCgpKQogICAgY2FsbHN1YiBnZXRfMXN0X3JlZl9pbmRleAogICAgYWNjdF9wYXJhbXNfZ2V0IEFjY3RUb3RhbEFzc2V0c0NyZWF0ZWQKICAgIC8vIHRlc3RzL2FydGlmYWN0cy9zdGF0ZS1vcHMvY29udHJhY3QuYWxnby50czoxMDkKICAgIC8vIGFzc2VydCh2YWx1ZSA9PT0gdmFsdWVfaW5kZXgsICdleHBlY3RlZCB2YWx1ZSBieSBpbmRleCB0byBtYXRjaCcpCiAgICBkaWcgMwogICAgdW5jb3ZlciAyCiAgICA9PQogICAgYXNzZXJ0IC8vIGV4cGVjdGVkIHZhbHVlIGJ5IGluZGV4IHRvIG1hdGNoCiAgICAvLyB0ZXN0cy9hcnRpZmFjdHMvc3RhdGUtb3BzL2NvbnRyYWN0LmFsZ28udHM6MTEwCiAgICAvLyBhc3NlcnQoZnVuZGVkID09PSBmdW5kZWRfaW5kZXgsICdleHBlY3RlZCBmdW5kZWQgYnkgaW5kZXggdG8gbWF0Y2gnKQogICAgPT0KICAgIGFzc2VydCAvLyBleHBlY3RlZCBmdW5kZWQgYnkgaW5kZXggdG8gbWF0Y2gKICAgIC8vIHRlc3RzL2FydGlmYWN0cy9zdGF0ZS1vcHMvY29udHJhY3QuYWxnby50czoxMTEKICAgIC8vIHJldHVybiB2YWx1ZQogICAgcmV0c3ViCgoKLy8gdGVzdHMvYXJ0aWZhY3RzL3N0YXRlLW9wcy9jb250cmFjdC5hbGdvLnRzOjpTdGF0ZUFjY3RQYXJhbXNHZXRDb250cmFjdC52ZXJpZnlfYWNjdF90b3RhbF9hc3NldHMoYTogYnl0ZXMpIC0+IHVpbnQ2NDoKdmVyaWZ5X2FjY3RfdG90YWxfYXNzZXRzOgogICAgLy8gdGVzdHMvYXJ0aWZhY3RzL3N0YXRlLW9wcy9jb250cmFjdC5hbGdvLnRzOjExNC0xMTUKICAgIC8vIEBhcmM0LmFiaW1ldGhvZCgpCiAgICAvLyBwdWJsaWMgdmVyaWZ5X2FjY3RfdG90YWxfYXNzZXRzKGE6IEFjY291bnQpOiB1aW50NjQgewogICAgcHJvdG8gMSAxCiAgICAvLyB0ZXN0cy9hcnRpZmFjdHMvc3RhdGUtb3BzL2NvbnRyYWN0LmFsZ28udHM6MTE2CiAgICAvLyBjb25zdCBbdmFsdWUsIGZ1bmRlZF0gPSBvcC5BY2N0UGFyYW1zLmFjY3RUb3RhbEFzc2V0cyhhKQogICAgZnJhbWVfZGlnIC0xCiAgICBhY2N0X3BhcmFtc19nZXQgQWNjdFRvdGFsQXNzZXRzCiAgICAvLyB0ZXN0cy9hcnRpZmFjdHMvc3RhdGUtb3BzL2NvbnRyYWN0LmFsZ28udHM6MTE3CiAgICAvLyBjb25zdCBbdmFsdWVfaW5kZXgsIGZ1bmRlZF9pbmRleF0gPSBvcC5BY2N0UGFyYW1zLmFjY3RUb3RhbEFzc2V0cyhnZXRfMXN0X3JlZl9pbmRleCgpKQogICAgY2FsbHN1YiBnZXRfMXN0X3JlZl9pbmRleAogICAgYWNjdF9wYXJhbXNfZ2V0IEFjY3RUb3RhbEFzc2V0cwogICAgLy8gdGVzdHMvYXJ0aWZhY3RzL3N0YXRlLW9wcy9jb250cmFjdC5hbGdvLnRzOjExOAogICAgLy8gYXNzZXJ0KHZhbHVlID09PSB2YWx1ZV9pbmRleCwgJ2V4cGVjdGVkIHZhbHVlIGJ5IGluZGV4IHRvIG1hdGNoJykKICAgIGRpZyAzCiAgICB1bmNvdmVyIDIKICAgID09CiAgICBhc3NlcnQgLy8gZXhwZWN0ZWQgdmFsdWUgYnkgaW5kZXggdG8gbWF0Y2gKICAgIC8vIHRlc3RzL2FydGlmYWN0cy9zdGF0ZS1vcHMvY29udHJhY3QuYWxnby50czoxMTkKICAgIC8vIGFzc2VydChmdW5kZWQgPT09IGZ1bmRlZF9pbmRleCwgJ2V4cGVjdGVkIGZ1bmRlZCBieSBpbmRleCB0byBtYXRjaCcpCiAgICA9PQogICAgYXNzZXJ0IC8vIGV4cGVjdGVkIGZ1bmRlZCBieSBpbmRleCB0byBtYXRjaAogICAgLy8gdGVzdHMvYXJ0aWZhY3RzL3N0YXRlLW9wcy9jb250cmFjdC5hbGdvLnRzOjEyMAogICAgLy8gcmV0dXJuIHZhbHVlCiAgICByZXRzdWIKCgovLyB0ZXN0cy9hcnRpZmFjdHMvc3RhdGUtb3BzL2NvbnRyYWN0LmFsZ28udHM6OlN0YXRlQWNjdFBhcmFtc0dldENvbnRyYWN0LnZlcmlmeV9hY2N0X3RvdGFsX2JveGVzKGE6IGJ5dGVzKSAtPiB1aW50NjQ6CnZlcmlmeV9hY2N0X3RvdGFsX2JveGVzOgogICAgLy8gdGVzdHMvYXJ0aWZhY3RzL3N0YXRlLW9wcy9jb250cmFjdC5hbGdvLnRzOjEyMy0xMjQKICAgIC8vIEBhcmM0LmFiaW1ldGhvZCgpCiAgICAvLyBwdWJsaWMgdmVyaWZ5X2FjY3RfdG90YWxfYm94ZXMoYTogQWNjb3VudCk6IHVpbnQ2NCB7CiAgICBwcm90byAxIDEKICAgIC8vIHRlc3RzL2FydGlmYWN0cy9zdGF0ZS1vcHMvY29udHJhY3QuYWxnby50czoxMjUKICAgIC8vIGNvbnN0IFt2YWx1ZSwgZnVuZGVkXSA9IG9wLkFjY3RQYXJhbXMuYWNjdFRvdGFsQm94ZXMoYSkKICAgIGZyYW1lX2RpZyAtMQogICAgYWNjdF9wYXJhbXNfZ2V0IEFjY3RUb3RhbEJveGVzCiAgICAvLyB0ZXN0cy9hcnRpZmFjdHMvc3RhdGUtb3BzL2NvbnRyYWN0LmFsZ28udHM6MTI2CiAgICAvLyBjb25zdCBbdmFsdWVfaW5kZXgsIGZ1bmRlZF9pbmRleF0gPSBvcC5BY2N0UGFyYW1zLmFjY3RUb3RhbEJveGVzKGdldF8xc3RfcmVmX2luZGV4KCkpCiAgICBjYWxsc3ViIGdldF8xc3RfcmVmX2luZGV4CiAgICBhY2N0X3BhcmFtc19nZXQgQWNjdFRvdGFsQm94ZXMKICAgIC8vIHRlc3RzL2FydGlmYWN0cy9zdGF0ZS1vcHMvY29udHJhY3QuYWxnby50czoxMjcKICAgIC8vIGFzc2VydCh2YWx1ZSA9PT0gdmFsdWVfaW5kZXgsICdleHBlY3RlZCB2YWx1ZSBieSBpbmRleCB0byBtYXRjaCcpCiAgICBkaWcgMwogICAgdW5jb3ZlciAyCiAgICA9PQogICAgYXNzZXJ0IC8vIGV4cGVjdGVkIHZhbHVlIGJ5IGluZGV4IHRvIG1hdGNoCiAgICAvLyB0ZXN0cy9hcnRpZmFjdHMvc3RhdGUtb3BzL2NvbnRyYWN0LmFsZ28udHM6MTI4CiAgICAvLyBhc3NlcnQoZnVuZGVkID09PSBmdW5kZWRfaW5kZXgsICdleHBlY3RlZCBmdW5kZWQgYnkgaW5kZXggdG8gbWF0Y2gnKQogICAgPT0KICAgIGFzc2VydCAvLyBleHBlY3RlZCBmdW5kZWQgYnkgaW5kZXggdG8gbWF0Y2gKICAgIC8vIHRlc3RzL2FydGlmYWN0cy9zdGF0ZS1vcHMvY29udHJhY3QuYWxnby50czoxMjkKICAgIC8vIHJldHVybiB2YWx1ZQogICAgcmV0c3ViCgoKLy8gdGVzdHMvYXJ0aWZhY3RzL3N0YXRlLW9wcy9jb250cmFjdC5hbGdvLnRzOjpTdGF0ZUFjY3RQYXJhbXNHZXRDb250cmFjdC52ZXJpZnlfYWNjdF90b3RhbF9ib3hfYnl0ZXMoYTogYnl0ZXMpIC0+IHVpbnQ2NDoKdmVyaWZ5X2FjY3RfdG90YWxfYm94X2J5dGVzOgogICAgLy8gdGVzdHMvYXJ0aWZhY3RzL3N0YXRlLW9wcy9jb250cmFjdC5hbGdvLnRzOjEzMi0xMzMKICAgIC8vIEBhcmM0LmFiaW1ldGhvZCgpCiAgICAvLyBwdWJsaWMgdmVyaWZ5X2FjY3RfdG90YWxfYm94X2J5dGVzKGE6IEFjY291bnQpOiB1aW50NjQgewogICAgcHJvdG8gMSAxCiAgICAvLyB0ZXN0cy9hcnRpZmFjdHMvc3RhdGUtb3BzL2NvbnRyYWN0LmFsZ28udHM6MTM0CiAgICAvLyBjb25zdCBbdmFsdWUsIGZ1bmRlZF0gPSBvcC5BY2N0UGFyYW1zLmFjY3RUb3RhbEJveEJ5dGVzKGEpCiAgICBmcmFtZV9kaWcgLTEKICAgIGFjY3RfcGFyYW1zX2dldCBBY2N0VG90YWxCb3hCeXRlcwogICAgLy8gdGVzdHMvYXJ0aWZhY3RzL3N0YXRlLW9wcy9jb250cmFjdC5hbGdvLnRzOjEzNQogICAgLy8gY29uc3QgW3ZhbHVlX2luZGV4LCBmdW5kZWRfaW5kZXhdID0gb3AuQWNjdFBhcmFtcy5hY2N0VG90YWxCb3hCeXRlcyhnZXRfMXN0X3JlZl9pbmRleCgpKQogICAgY2FsbHN1YiBnZXRfMXN0X3JlZl9pbmRleAogICAgYWNjdF9wYXJhbXNfZ2V0IEFjY3RUb3RhbEJveEJ5dGVzCiAgICAvLyB0ZXN0cy9hcnRpZmFjdHMvc3RhdGUtb3BzL2NvbnRyYWN0LmFsZ28udHM6MTM2CiAgICAvLyBhc3NlcnQodmFsdWUgPT09IHZhbHVlX2luZGV4LCAnZXhwZWN0ZWQgdmFsdWUgYnkgaW5kZXggdG8gbWF0Y2gnKQogICAgZGlnIDMKICAgIHVuY292ZXIgMgogICAgPT0KICAgIGFzc2VydCAvLyBleHBlY3RlZCB2YWx1ZSBieSBpbmRleCB0byBtYXRjaAogICAgLy8gdGVzdHMvYXJ0aWZhY3RzL3N0YXRlLW9wcy9jb250cmFjdC5hbGdvLnRzOjEzNwogICAgLy8gYXNzZXJ0KGZ1bmRlZCA9PT0gZnVuZGVkX2luZGV4LCAnZXhwZWN0ZWQgZnVuZGVkIGJ5IGluZGV4IHRvIG1hdGNoJykKICAgID09CiAgICBhc3NlcnQgLy8gZXhwZWN0ZWQgZnVuZGVkIGJ5IGluZGV4IHRvIG1hdGNoCiAgICAvLyB0ZXN0cy9hcnRpZmFjdHMvc3RhdGUtb3BzL2NvbnRyYWN0LmFsZ28udHM6MTM4CiAgICAvLyByZXR1cm4gdmFsdWUKICAgIHJldHN1Ygo=", - "clear": "I3ByYWdtYSB2ZXJzaW9uIDEwCgp0ZXN0cy9hcnRpZmFjdHMvc3RhdGUtb3BzL2NvbnRyYWN0LmFsZ28udHM6OlN0YXRlQWNjdFBhcmFtc0dldENvbnRyYWN0LmNsZWFyU3RhdGVQcm9ncmFtOgogICAgcHVzaGludCAxIC8vIDEKICAgIHJldHVybgo=" + "approval": "I3ByYWdtYSB2ZXJzaW9uIDExCiNwcmFnbWEgdHlwZXRyYWNrIGZhbHNlCgovLyBAYWxnb3JhbmRmb3VuZGF0aW9uL2FsZ29yYW5kLXR5cGVzY3JpcHQvYXJjNC9pbmRleC5kLnRzOjpDb250cmFjdC5hcHByb3ZhbFByb2dyYW0oKSAtPiB1aW50NjQ6Cm1haW46CiAgICBpbnRjYmxvY2sgMSAwCiAgICBieXRlY2Jsb2NrIDB4MTUxZjdjNzUKICAgIC8vIHRlc3RzL2FydGlmYWN0cy9zdGF0ZS1vcHMvc3RhdGUtYWNjdC1wYXJhbXMtZ2V0LWNvbnRyYWN0LmFsZ28udHM6OAogICAgLy8gZXhwb3J0IGNsYXNzIFN0YXRlQWNjdFBhcmFtc0dldENvbnRyYWN0IGV4dGVuZHMgYXJjNC5Db250cmFjdCB7CiAgICB0eG4gTnVtQXBwQXJncwogICAgYnogbWFpbl9iYXJlX3JvdXRpbmdAMTgKICAgIHB1c2hieXRlc3MgMHg1ZjViNDNlNCAweDczZGM5M2M3IDB4NTYyNmRmZWIgMHhkYzhhMjViZiAweDE5OGViZDhjIDB4MjMwMWFiMjYgMHg5ZjY4ZmNhNiAweGE5NzVjMmQxIDB4ZDFlMDQ4MDEgMHhiNjk2NmJlNSAweDE5NWQ1NDE4IDB4NmFkYWUzZjEgMHhkZjhjZmVlNSAvLyBtZXRob2QgInZlcmlmeV9hY2N0X2JhbGFuY2UoYWNjb3VudCl1aW50NjQiLCBtZXRob2QgInZlcmlmeV9hY2N0X21pbl9iYWxhbmNlKGFjY291bnQpdWludDY0IiwgbWV0aG9kICJ2ZXJpZnlfYWNjdF9hdXRoX2FkZHIoYWNjb3VudClhZGRyZXNzIiwgbWV0aG9kICJ2ZXJpZnlfYWNjdF90b3RhbF9udW1fdWludChhY2NvdW50KXVpbnQ2NCIsIG1ldGhvZCAidmVyaWZ5X2FjY3RfdG90YWxfbnVtX2J5dGVfc2xpY2UoYWNjb3VudCl1aW50NjQiLCBtZXRob2QgInZlcmlmeV9hY2N0X3RvdGFsX2V4dHJhX2FwcF9wYWdlcyhhY2NvdW50KXVpbnQ2NCIsIG1ldGhvZCAidmVyaWZ5X2FjY3RfdG90YWxfYXBwc19jcmVhdGVkKGFjY291bnQpdWludDY0IiwgbWV0aG9kICJ2ZXJpZnlfYWNjdF90b3RhbF9hcHBzX29wdGVkX2luKGFjY291bnQpdWludDY0IiwgbWV0aG9kICJ2ZXJpZnlfYWNjdF90b3RhbF9hc3NldHNfY3JlYXRlZChhY2NvdW50KXVpbnQ2NCIsIG1ldGhvZCAidmVyaWZ5X2FjY3RfdG90YWxfYXNzZXRzKGFjY291bnQpdWludDY0IiwgbWV0aG9kICJ2ZXJpZnlfYWNjdF90b3RhbF9ib3hlcyhhY2NvdW50KXVpbnQ2NCIsIG1ldGhvZCAidmVyaWZ5X2FjY3RfdG90YWxfYm94X2J5dGVzKGFjY291bnQpdWludDY0IiwgbWV0aG9kICJ2ZXJpZnlfYWNjdF9pbmNlbnRpdmVfZWxpZ2libGUoYWNjb3VudClib29sIgogICAgdHhuYSBBcHBsaWNhdGlvbkFyZ3MgMAogICAgbWF0Y2ggbWFpbl92ZXJpZnlfYWNjdF9iYWxhbmNlX3JvdXRlQDMgbWFpbl92ZXJpZnlfYWNjdF9taW5fYmFsYW5jZV9yb3V0ZUA0IG1haW5fdmVyaWZ5X2FjY3RfYXV0aF9hZGRyX3JvdXRlQDUgbWFpbl92ZXJpZnlfYWNjdF90b3RhbF9udW1fdWludF9yb3V0ZUA2IG1haW5fdmVyaWZ5X2FjY3RfdG90YWxfbnVtX2J5dGVfc2xpY2Vfcm91dGVANyBtYWluX3ZlcmlmeV9hY2N0X3RvdGFsX2V4dHJhX2FwcF9wYWdlc19yb3V0ZUA4IG1haW5fdmVyaWZ5X2FjY3RfdG90YWxfYXBwc19jcmVhdGVkX3JvdXRlQDkgbWFpbl92ZXJpZnlfYWNjdF90b3RhbF9hcHBzX29wdGVkX2luX3JvdXRlQDEwIG1haW5fdmVyaWZ5X2FjY3RfdG90YWxfYXNzZXRzX2NyZWF0ZWRfcm91dGVAMTEgbWFpbl92ZXJpZnlfYWNjdF90b3RhbF9hc3NldHNfcm91dGVAMTIgbWFpbl92ZXJpZnlfYWNjdF90b3RhbF9ib3hlc19yb3V0ZUAxMyBtYWluX3ZlcmlmeV9hY2N0X3RvdGFsX2JveF9ieXRlc19yb3V0ZUAxNCBtYWluX3ZlcmlmeV9hY2N0X2luY2VudGl2ZV9lbGlnaWJsZV9yb3V0ZUAxNQoKbWFpbl9hZnRlcl9pZl9lbHNlQDIyOgogICAgLy8gdGVzdHMvYXJ0aWZhY3RzL3N0YXRlLW9wcy9zdGF0ZS1hY2N0LXBhcmFtcy1nZXQtY29udHJhY3QuYWxnby50czo4CiAgICAvLyBleHBvcnQgY2xhc3MgU3RhdGVBY2N0UGFyYW1zR2V0Q29udHJhY3QgZXh0ZW5kcyBhcmM0LkNvbnRyYWN0IHsKICAgIGludGNfMSAvLyAwCiAgICByZXR1cm4KCm1haW5fdmVyaWZ5X2FjY3RfaW5jZW50aXZlX2VsaWdpYmxlX3JvdXRlQDE1OgogICAgLy8gdGVzdHMvYXJ0aWZhY3RzL3N0YXRlLW9wcy9zdGF0ZS1hY2N0LXBhcmFtcy1nZXQtY29udHJhY3QuYWxnby50czoxMjMKICAgIC8vIEBhcmM0LmFiaW1ldGhvZCgpCiAgICB0eG4gT25Db21wbGV0aW9uCiAgICAhCiAgICBhc3NlcnQgLy8gT25Db21wbGV0aW9uIGlzIG5vdCBOb09wCiAgICB0eG4gQXBwbGljYXRpb25JRAogICAgYXNzZXJ0IC8vIGNhbiBvbmx5IGNhbGwgd2hlbiBub3QgY3JlYXRpbmcKICAgIC8vIHRlc3RzL2FydGlmYWN0cy9zdGF0ZS1vcHMvc3RhdGUtYWNjdC1wYXJhbXMtZ2V0LWNvbnRyYWN0LmFsZ28udHM6OAogICAgLy8gZXhwb3J0IGNsYXNzIFN0YXRlQWNjdFBhcmFtc0dldENvbnRyYWN0IGV4dGVuZHMgYXJjNC5Db250cmFjdCB7CiAgICB0eG5hIEFwcGxpY2F0aW9uQXJncyAxCiAgICBidG9pCiAgICB0eG5hcyBBY2NvdW50cwogICAgLy8gdGVzdHMvYXJ0aWZhY3RzL3N0YXRlLW9wcy9zdGF0ZS1hY2N0LXBhcmFtcy1nZXQtY29udHJhY3QuYWxnby50czoxMjMKICAgIC8vIEBhcmM0LmFiaW1ldGhvZCgpCiAgICBjYWxsc3ViIHZlcmlmeV9hY2N0X2luY2VudGl2ZV9lbGlnaWJsZQogICAgcHVzaGJ5dGVzIDB4MDAKICAgIGludGNfMSAvLyAwCiAgICB1bmNvdmVyIDIKICAgIHNldGJpdAogICAgYnl0ZWNfMCAvLyAweDE1MWY3Yzc1CiAgICBzd2FwCiAgICBjb25jYXQKICAgIGxvZwogICAgaW50Y18wIC8vIDEKICAgIHJldHVybgoKbWFpbl92ZXJpZnlfYWNjdF90b3RhbF9ib3hfYnl0ZXNfcm91dGVAMTQ6CiAgICAvLyB0ZXN0cy9hcnRpZmFjdHMvc3RhdGUtb3BzL3N0YXRlLWFjY3QtcGFyYW1zLWdldC1jb250cmFjdC5hbGdvLnRzOjExNAogICAgLy8gQGFyYzQuYWJpbWV0aG9kKCkKICAgIHR4biBPbkNvbXBsZXRpb24KICAgICEKICAgIGFzc2VydCAvLyBPbkNvbXBsZXRpb24gaXMgbm90IE5vT3AKICAgIHR4biBBcHBsaWNhdGlvbklECiAgICBhc3NlcnQgLy8gY2FuIG9ubHkgY2FsbCB3aGVuIG5vdCBjcmVhdGluZwogICAgLy8gdGVzdHMvYXJ0aWZhY3RzL3N0YXRlLW9wcy9zdGF0ZS1hY2N0LXBhcmFtcy1nZXQtY29udHJhY3QuYWxnby50czo4CiAgICAvLyBleHBvcnQgY2xhc3MgU3RhdGVBY2N0UGFyYW1zR2V0Q29udHJhY3QgZXh0ZW5kcyBhcmM0LkNvbnRyYWN0IHsKICAgIHR4bmEgQXBwbGljYXRpb25BcmdzIDEKICAgIGJ0b2kKICAgIHR4bmFzIEFjY291bnRzCiAgICAvLyB0ZXN0cy9hcnRpZmFjdHMvc3RhdGUtb3BzL3N0YXRlLWFjY3QtcGFyYW1zLWdldC1jb250cmFjdC5hbGdvLnRzOjExNAogICAgLy8gQGFyYzQuYWJpbWV0aG9kKCkKICAgIGNhbGxzdWIgdmVyaWZ5X2FjY3RfdG90YWxfYm94X2J5dGVzCiAgICBpdG9iCiAgICBieXRlY18wIC8vIDB4MTUxZjdjNzUKICAgIHN3YXAKICAgIGNvbmNhdAogICAgbG9nCiAgICBpbnRjXzAgLy8gMQogICAgcmV0dXJuCgptYWluX3ZlcmlmeV9hY2N0X3RvdGFsX2JveGVzX3JvdXRlQDEzOgogICAgLy8gdGVzdHMvYXJ0aWZhY3RzL3N0YXRlLW9wcy9zdGF0ZS1hY2N0LXBhcmFtcy1nZXQtY29udHJhY3QuYWxnby50czoxMDUKICAgIC8vIEBhcmM0LmFiaW1ldGhvZCgpCiAgICB0eG4gT25Db21wbGV0aW9uCiAgICAhCiAgICBhc3NlcnQgLy8gT25Db21wbGV0aW9uIGlzIG5vdCBOb09wCiAgICB0eG4gQXBwbGljYXRpb25JRAogICAgYXNzZXJ0IC8vIGNhbiBvbmx5IGNhbGwgd2hlbiBub3QgY3JlYXRpbmcKICAgIC8vIHRlc3RzL2FydGlmYWN0cy9zdGF0ZS1vcHMvc3RhdGUtYWNjdC1wYXJhbXMtZ2V0LWNvbnRyYWN0LmFsZ28udHM6OAogICAgLy8gZXhwb3J0IGNsYXNzIFN0YXRlQWNjdFBhcmFtc0dldENvbnRyYWN0IGV4dGVuZHMgYXJjNC5Db250cmFjdCB7CiAgICB0eG5hIEFwcGxpY2F0aW9uQXJncyAxCiAgICBidG9pCiAgICB0eG5hcyBBY2NvdW50cwogICAgLy8gdGVzdHMvYXJ0aWZhY3RzL3N0YXRlLW9wcy9zdGF0ZS1hY2N0LXBhcmFtcy1nZXQtY29udHJhY3QuYWxnby50czoxMDUKICAgIC8vIEBhcmM0LmFiaW1ldGhvZCgpCiAgICBjYWxsc3ViIHZlcmlmeV9hY2N0X3RvdGFsX2JveGVzCiAgICBpdG9iCiAgICBieXRlY18wIC8vIDB4MTUxZjdjNzUKICAgIHN3YXAKICAgIGNvbmNhdAogICAgbG9nCiAgICBpbnRjXzAgLy8gMQogICAgcmV0dXJuCgptYWluX3ZlcmlmeV9hY2N0X3RvdGFsX2Fzc2V0c19yb3V0ZUAxMjoKICAgIC8vIHRlc3RzL2FydGlmYWN0cy9zdGF0ZS1vcHMvc3RhdGUtYWNjdC1wYXJhbXMtZ2V0LWNvbnRyYWN0LmFsZ28udHM6OTYKICAgIC8vIEBhcmM0LmFiaW1ldGhvZCgpCiAgICB0eG4gT25Db21wbGV0aW9uCiAgICAhCiAgICBhc3NlcnQgLy8gT25Db21wbGV0aW9uIGlzIG5vdCBOb09wCiAgICB0eG4gQXBwbGljYXRpb25JRAogICAgYXNzZXJ0IC8vIGNhbiBvbmx5IGNhbGwgd2hlbiBub3QgY3JlYXRpbmcKICAgIC8vIHRlc3RzL2FydGlmYWN0cy9zdGF0ZS1vcHMvc3RhdGUtYWNjdC1wYXJhbXMtZ2V0LWNvbnRyYWN0LmFsZ28udHM6OAogICAgLy8gZXhwb3J0IGNsYXNzIFN0YXRlQWNjdFBhcmFtc0dldENvbnRyYWN0IGV4dGVuZHMgYXJjNC5Db250cmFjdCB7CiAgICB0eG5hIEFwcGxpY2F0aW9uQXJncyAxCiAgICBidG9pCiAgICB0eG5hcyBBY2NvdW50cwogICAgLy8gdGVzdHMvYXJ0aWZhY3RzL3N0YXRlLW9wcy9zdGF0ZS1hY2N0LXBhcmFtcy1nZXQtY29udHJhY3QuYWxnby50czo5NgogICAgLy8gQGFyYzQuYWJpbWV0aG9kKCkKICAgIGNhbGxzdWIgdmVyaWZ5X2FjY3RfdG90YWxfYXNzZXRzCiAgICBpdG9iCiAgICBieXRlY18wIC8vIDB4MTUxZjdjNzUKICAgIHN3YXAKICAgIGNvbmNhdAogICAgbG9nCiAgICBpbnRjXzAgLy8gMQogICAgcmV0dXJuCgptYWluX3ZlcmlmeV9hY2N0X3RvdGFsX2Fzc2V0c19jcmVhdGVkX3JvdXRlQDExOgogICAgLy8gdGVzdHMvYXJ0aWZhY3RzL3N0YXRlLW9wcy9zdGF0ZS1hY2N0LXBhcmFtcy1nZXQtY29udHJhY3QuYWxnby50czo4NwogICAgLy8gQGFyYzQuYWJpbWV0aG9kKCkKICAgIHR4biBPbkNvbXBsZXRpb24KICAgICEKICAgIGFzc2VydCAvLyBPbkNvbXBsZXRpb24gaXMgbm90IE5vT3AKICAgIHR4biBBcHBsaWNhdGlvbklECiAgICBhc3NlcnQgLy8gY2FuIG9ubHkgY2FsbCB3aGVuIG5vdCBjcmVhdGluZwogICAgLy8gdGVzdHMvYXJ0aWZhY3RzL3N0YXRlLW9wcy9zdGF0ZS1hY2N0LXBhcmFtcy1nZXQtY29udHJhY3QuYWxnby50czo4CiAgICAvLyBleHBvcnQgY2xhc3MgU3RhdGVBY2N0UGFyYW1zR2V0Q29udHJhY3QgZXh0ZW5kcyBhcmM0LkNvbnRyYWN0IHsKICAgIHR4bmEgQXBwbGljYXRpb25BcmdzIDEKICAgIGJ0b2kKICAgIHR4bmFzIEFjY291bnRzCiAgICAvLyB0ZXN0cy9hcnRpZmFjdHMvc3RhdGUtb3BzL3N0YXRlLWFjY3QtcGFyYW1zLWdldC1jb250cmFjdC5hbGdvLnRzOjg3CiAgICAvLyBAYXJjNC5hYmltZXRob2QoKQogICAgY2FsbHN1YiB2ZXJpZnlfYWNjdF90b3RhbF9hc3NldHNfY3JlYXRlZAogICAgaXRvYgogICAgYnl0ZWNfMCAvLyAweDE1MWY3Yzc1CiAgICBzd2FwCiAgICBjb25jYXQKICAgIGxvZwogICAgaW50Y18wIC8vIDEKICAgIHJldHVybgoKbWFpbl92ZXJpZnlfYWNjdF90b3RhbF9hcHBzX29wdGVkX2luX3JvdXRlQDEwOgogICAgLy8gdGVzdHMvYXJ0aWZhY3RzL3N0YXRlLW9wcy9zdGF0ZS1hY2N0LXBhcmFtcy1nZXQtY29udHJhY3QuYWxnby50czo3OAogICAgLy8gQGFyYzQuYWJpbWV0aG9kKCkKICAgIHR4biBPbkNvbXBsZXRpb24KICAgICEKICAgIGFzc2VydCAvLyBPbkNvbXBsZXRpb24gaXMgbm90IE5vT3AKICAgIHR4biBBcHBsaWNhdGlvbklECiAgICBhc3NlcnQgLy8gY2FuIG9ubHkgY2FsbCB3aGVuIG5vdCBjcmVhdGluZwogICAgLy8gdGVzdHMvYXJ0aWZhY3RzL3N0YXRlLW9wcy9zdGF0ZS1hY2N0LXBhcmFtcy1nZXQtY29udHJhY3QuYWxnby50czo4CiAgICAvLyBleHBvcnQgY2xhc3MgU3RhdGVBY2N0UGFyYW1zR2V0Q29udHJhY3QgZXh0ZW5kcyBhcmM0LkNvbnRyYWN0IHsKICAgIHR4bmEgQXBwbGljYXRpb25BcmdzIDEKICAgIGJ0b2kKICAgIHR4bmFzIEFjY291bnRzCiAgICAvLyB0ZXN0cy9hcnRpZmFjdHMvc3RhdGUtb3BzL3N0YXRlLWFjY3QtcGFyYW1zLWdldC1jb250cmFjdC5hbGdvLnRzOjc4CiAgICAvLyBAYXJjNC5hYmltZXRob2QoKQogICAgY2FsbHN1YiB2ZXJpZnlfYWNjdF90b3RhbF9hcHBzX29wdGVkX2luCiAgICBpdG9iCiAgICBieXRlY18wIC8vIDB4MTUxZjdjNzUKICAgIHN3YXAKICAgIGNvbmNhdAogICAgbG9nCiAgICBpbnRjXzAgLy8gMQogICAgcmV0dXJuCgptYWluX3ZlcmlmeV9hY2N0X3RvdGFsX2FwcHNfY3JlYXRlZF9yb3V0ZUA5OgogICAgLy8gdGVzdHMvYXJ0aWZhY3RzL3N0YXRlLW9wcy9zdGF0ZS1hY2N0LXBhcmFtcy1nZXQtY29udHJhY3QuYWxnby50czo2OQogICAgLy8gQGFyYzQuYWJpbWV0aG9kKCkKICAgIHR4biBPbkNvbXBsZXRpb24KICAgICEKICAgIGFzc2VydCAvLyBPbkNvbXBsZXRpb24gaXMgbm90IE5vT3AKICAgIHR4biBBcHBsaWNhdGlvbklECiAgICBhc3NlcnQgLy8gY2FuIG9ubHkgY2FsbCB3aGVuIG5vdCBjcmVhdGluZwogICAgLy8gdGVzdHMvYXJ0aWZhY3RzL3N0YXRlLW9wcy9zdGF0ZS1hY2N0LXBhcmFtcy1nZXQtY29udHJhY3QuYWxnby50czo4CiAgICAvLyBleHBvcnQgY2xhc3MgU3RhdGVBY2N0UGFyYW1zR2V0Q29udHJhY3QgZXh0ZW5kcyBhcmM0LkNvbnRyYWN0IHsKICAgIHR4bmEgQXBwbGljYXRpb25BcmdzIDEKICAgIGJ0b2kKICAgIHR4bmFzIEFjY291bnRzCiAgICAvLyB0ZXN0cy9hcnRpZmFjdHMvc3RhdGUtb3BzL3N0YXRlLWFjY3QtcGFyYW1zLWdldC1jb250cmFjdC5hbGdvLnRzOjY5CiAgICAvLyBAYXJjNC5hYmltZXRob2QoKQogICAgY2FsbHN1YiB2ZXJpZnlfYWNjdF90b3RhbF9hcHBzX2NyZWF0ZWQKICAgIGl0b2IKICAgIGJ5dGVjXzAgLy8gMHgxNTFmN2M3NQogICAgc3dhcAogICAgY29uY2F0CiAgICBsb2cKICAgIGludGNfMCAvLyAxCiAgICByZXR1cm4KCm1haW5fdmVyaWZ5X2FjY3RfdG90YWxfZXh0cmFfYXBwX3BhZ2VzX3JvdXRlQDg6CiAgICAvLyB0ZXN0cy9hcnRpZmFjdHMvc3RhdGUtb3BzL3N0YXRlLWFjY3QtcGFyYW1zLWdldC1jb250cmFjdC5hbGdvLnRzOjYwCiAgICAvLyBAYXJjNC5hYmltZXRob2QoKQogICAgdHhuIE9uQ29tcGxldGlvbgogICAgIQogICAgYXNzZXJ0IC8vIE9uQ29tcGxldGlvbiBpcyBub3QgTm9PcAogICAgdHhuIEFwcGxpY2F0aW9uSUQKICAgIGFzc2VydCAvLyBjYW4gb25seSBjYWxsIHdoZW4gbm90IGNyZWF0aW5nCiAgICAvLyB0ZXN0cy9hcnRpZmFjdHMvc3RhdGUtb3BzL3N0YXRlLWFjY3QtcGFyYW1zLWdldC1jb250cmFjdC5hbGdvLnRzOjgKICAgIC8vIGV4cG9ydCBjbGFzcyBTdGF0ZUFjY3RQYXJhbXNHZXRDb250cmFjdCBleHRlbmRzIGFyYzQuQ29udHJhY3QgewogICAgdHhuYSBBcHBsaWNhdGlvbkFyZ3MgMQogICAgYnRvaQogICAgdHhuYXMgQWNjb3VudHMKICAgIC8vIHRlc3RzL2FydGlmYWN0cy9zdGF0ZS1vcHMvc3RhdGUtYWNjdC1wYXJhbXMtZ2V0LWNvbnRyYWN0LmFsZ28udHM6NjAKICAgIC8vIEBhcmM0LmFiaW1ldGhvZCgpCiAgICBjYWxsc3ViIHZlcmlmeV9hY2N0X3RvdGFsX2V4dHJhX2FwcF9wYWdlcwogICAgaXRvYgogICAgYnl0ZWNfMCAvLyAweDE1MWY3Yzc1CiAgICBzd2FwCiAgICBjb25jYXQKICAgIGxvZwogICAgaW50Y18wIC8vIDEKICAgIHJldHVybgoKbWFpbl92ZXJpZnlfYWNjdF90b3RhbF9udW1fYnl0ZV9zbGljZV9yb3V0ZUA3OgogICAgLy8gdGVzdHMvYXJ0aWZhY3RzL3N0YXRlLW9wcy9zdGF0ZS1hY2N0LXBhcmFtcy1nZXQtY29udHJhY3QuYWxnby50czo1MQogICAgLy8gQGFyYzQuYWJpbWV0aG9kKCkKICAgIHR4biBPbkNvbXBsZXRpb24KICAgICEKICAgIGFzc2VydCAvLyBPbkNvbXBsZXRpb24gaXMgbm90IE5vT3AKICAgIHR4biBBcHBsaWNhdGlvbklECiAgICBhc3NlcnQgLy8gY2FuIG9ubHkgY2FsbCB3aGVuIG5vdCBjcmVhdGluZwogICAgLy8gdGVzdHMvYXJ0aWZhY3RzL3N0YXRlLW9wcy9zdGF0ZS1hY2N0LXBhcmFtcy1nZXQtY29udHJhY3QuYWxnby50czo4CiAgICAvLyBleHBvcnQgY2xhc3MgU3RhdGVBY2N0UGFyYW1zR2V0Q29udHJhY3QgZXh0ZW5kcyBhcmM0LkNvbnRyYWN0IHsKICAgIHR4bmEgQXBwbGljYXRpb25BcmdzIDEKICAgIGJ0b2kKICAgIHR4bmFzIEFjY291bnRzCiAgICAvLyB0ZXN0cy9hcnRpZmFjdHMvc3RhdGUtb3BzL3N0YXRlLWFjY3QtcGFyYW1zLWdldC1jb250cmFjdC5hbGdvLnRzOjUxCiAgICAvLyBAYXJjNC5hYmltZXRob2QoKQogICAgY2FsbHN1YiB2ZXJpZnlfYWNjdF90b3RhbF9udW1fYnl0ZV9zbGljZQogICAgaXRvYgogICAgYnl0ZWNfMCAvLyAweDE1MWY3Yzc1CiAgICBzd2FwCiAgICBjb25jYXQKICAgIGxvZwogICAgaW50Y18wIC8vIDEKICAgIHJldHVybgoKbWFpbl92ZXJpZnlfYWNjdF90b3RhbF9udW1fdWludF9yb3V0ZUA2OgogICAgLy8gdGVzdHMvYXJ0aWZhY3RzL3N0YXRlLW9wcy9zdGF0ZS1hY2N0LXBhcmFtcy1nZXQtY29udHJhY3QuYWxnby50czo0MgogICAgLy8gQGFyYzQuYWJpbWV0aG9kKCkKICAgIHR4biBPbkNvbXBsZXRpb24KICAgICEKICAgIGFzc2VydCAvLyBPbkNvbXBsZXRpb24gaXMgbm90IE5vT3AKICAgIHR4biBBcHBsaWNhdGlvbklECiAgICBhc3NlcnQgLy8gY2FuIG9ubHkgY2FsbCB3aGVuIG5vdCBjcmVhdGluZwogICAgLy8gdGVzdHMvYXJ0aWZhY3RzL3N0YXRlLW9wcy9zdGF0ZS1hY2N0LXBhcmFtcy1nZXQtY29udHJhY3QuYWxnby50czo4CiAgICAvLyBleHBvcnQgY2xhc3MgU3RhdGVBY2N0UGFyYW1zR2V0Q29udHJhY3QgZXh0ZW5kcyBhcmM0LkNvbnRyYWN0IHsKICAgIHR4bmEgQXBwbGljYXRpb25BcmdzIDEKICAgIGJ0b2kKICAgIHR4bmFzIEFjY291bnRzCiAgICAvLyB0ZXN0cy9hcnRpZmFjdHMvc3RhdGUtb3BzL3N0YXRlLWFjY3QtcGFyYW1zLWdldC1jb250cmFjdC5hbGdvLnRzOjQyCiAgICAvLyBAYXJjNC5hYmltZXRob2QoKQogICAgY2FsbHN1YiB2ZXJpZnlfYWNjdF90b3RhbF9udW1fdWludAogICAgaXRvYgogICAgYnl0ZWNfMCAvLyAweDE1MWY3Yzc1CiAgICBzd2FwCiAgICBjb25jYXQKICAgIGxvZwogICAgaW50Y18wIC8vIDEKICAgIHJldHVybgoKbWFpbl92ZXJpZnlfYWNjdF9hdXRoX2FkZHJfcm91dGVANToKICAgIC8vIHRlc3RzL2FydGlmYWN0cy9zdGF0ZS1vcHMvc3RhdGUtYWNjdC1wYXJhbXMtZ2V0LWNvbnRyYWN0LmFsZ28udHM6MzMKICAgIC8vIEBhcmM0LmFiaW1ldGhvZCgpCiAgICB0eG4gT25Db21wbGV0aW9uCiAgICAhCiAgICBhc3NlcnQgLy8gT25Db21wbGV0aW9uIGlzIG5vdCBOb09wCiAgICB0eG4gQXBwbGljYXRpb25JRAogICAgYXNzZXJ0IC8vIGNhbiBvbmx5IGNhbGwgd2hlbiBub3QgY3JlYXRpbmcKICAgIC8vIHRlc3RzL2FydGlmYWN0cy9zdGF0ZS1vcHMvc3RhdGUtYWNjdC1wYXJhbXMtZ2V0LWNvbnRyYWN0LmFsZ28udHM6OAogICAgLy8gZXhwb3J0IGNsYXNzIFN0YXRlQWNjdFBhcmFtc0dldENvbnRyYWN0IGV4dGVuZHMgYXJjNC5Db250cmFjdCB7CiAgICB0eG5hIEFwcGxpY2F0aW9uQXJncyAxCiAgICBidG9pCiAgICB0eG5hcyBBY2NvdW50cwogICAgLy8gdGVzdHMvYXJ0aWZhY3RzL3N0YXRlLW9wcy9zdGF0ZS1hY2N0LXBhcmFtcy1nZXQtY29udHJhY3QuYWxnby50czozMwogICAgLy8gQGFyYzQuYWJpbWV0aG9kKCkKICAgIGNhbGxzdWIgdmVyaWZ5X2FjY3RfYXV0aF9hZGRyCiAgICBieXRlY18wIC8vIDB4MTUxZjdjNzUKICAgIHN3YXAKICAgIGNvbmNhdAogICAgbG9nCiAgICBpbnRjXzAgLy8gMQogICAgcmV0dXJuCgptYWluX3ZlcmlmeV9hY2N0X21pbl9iYWxhbmNlX3JvdXRlQDQ6CiAgICAvLyB0ZXN0cy9hcnRpZmFjdHMvc3RhdGUtb3BzL3N0YXRlLWFjY3QtcGFyYW1zLWdldC1jb250cmFjdC5hbGdvLnRzOjIxCiAgICAvLyBAYXJjNC5hYmltZXRob2QoKQogICAgdHhuIE9uQ29tcGxldGlvbgogICAgIQogICAgYXNzZXJ0IC8vIE9uQ29tcGxldGlvbiBpcyBub3QgTm9PcAogICAgdHhuIEFwcGxpY2F0aW9uSUQKICAgIGFzc2VydCAvLyBjYW4gb25seSBjYWxsIHdoZW4gbm90IGNyZWF0aW5nCiAgICAvLyB0ZXN0cy9hcnRpZmFjdHMvc3RhdGUtb3BzL3N0YXRlLWFjY3QtcGFyYW1zLWdldC1jb250cmFjdC5hbGdvLnRzOjgKICAgIC8vIGV4cG9ydCBjbGFzcyBTdGF0ZUFjY3RQYXJhbXNHZXRDb250cmFjdCBleHRlbmRzIGFyYzQuQ29udHJhY3QgewogICAgdHhuYSBBcHBsaWNhdGlvbkFyZ3MgMQogICAgYnRvaQogICAgdHhuYXMgQWNjb3VudHMKICAgIC8vIHRlc3RzL2FydGlmYWN0cy9zdGF0ZS1vcHMvc3RhdGUtYWNjdC1wYXJhbXMtZ2V0LWNvbnRyYWN0LmFsZ28udHM6MjEKICAgIC8vIEBhcmM0LmFiaW1ldGhvZCgpCiAgICBjYWxsc3ViIHZlcmlmeV9hY2N0X21pbl9iYWxhbmNlCiAgICBpdG9iCiAgICBieXRlY18wIC8vIDB4MTUxZjdjNzUKICAgIHN3YXAKICAgIGNvbmNhdAogICAgbG9nCiAgICBpbnRjXzAgLy8gMQogICAgcmV0dXJuCgptYWluX3ZlcmlmeV9hY2N0X2JhbGFuY2Vfcm91dGVAMzoKICAgIC8vIHRlc3RzL2FydGlmYWN0cy9zdGF0ZS1vcHMvc3RhdGUtYWNjdC1wYXJhbXMtZ2V0LWNvbnRyYWN0LmFsZ28udHM6OQogICAgLy8gQGFyYzQuYWJpbWV0aG9kKCkKICAgIHR4biBPbkNvbXBsZXRpb24KICAgICEKICAgIGFzc2VydCAvLyBPbkNvbXBsZXRpb24gaXMgbm90IE5vT3AKICAgIHR4biBBcHBsaWNhdGlvbklECiAgICBhc3NlcnQgLy8gY2FuIG9ubHkgY2FsbCB3aGVuIG5vdCBjcmVhdGluZwogICAgLy8gdGVzdHMvYXJ0aWZhY3RzL3N0YXRlLW9wcy9zdGF0ZS1hY2N0LXBhcmFtcy1nZXQtY29udHJhY3QuYWxnby50czo4CiAgICAvLyBleHBvcnQgY2xhc3MgU3RhdGVBY2N0UGFyYW1zR2V0Q29udHJhY3QgZXh0ZW5kcyBhcmM0LkNvbnRyYWN0IHsKICAgIHR4bmEgQXBwbGljYXRpb25BcmdzIDEKICAgIGJ0b2kKICAgIHR4bmFzIEFjY291bnRzCiAgICAvLyB0ZXN0cy9hcnRpZmFjdHMvc3RhdGUtb3BzL3N0YXRlLWFjY3QtcGFyYW1zLWdldC1jb250cmFjdC5hbGdvLnRzOjkKICAgIC8vIEBhcmM0LmFiaW1ldGhvZCgpCiAgICBjYWxsc3ViIHZlcmlmeV9hY2N0X2JhbGFuY2UKICAgIGl0b2IKICAgIGJ5dGVjXzAgLy8gMHgxNTFmN2M3NQogICAgc3dhcAogICAgY29uY2F0CiAgICBsb2cKICAgIGludGNfMCAvLyAxCiAgICByZXR1cm4KCm1haW5fYmFyZV9yb3V0aW5nQDE4OgogICAgLy8gdGVzdHMvYXJ0aWZhY3RzL3N0YXRlLW9wcy9zdGF0ZS1hY2N0LXBhcmFtcy1nZXQtY29udHJhY3QuYWxnby50czo4CiAgICAvLyBleHBvcnQgY2xhc3MgU3RhdGVBY2N0UGFyYW1zR2V0Q29udHJhY3QgZXh0ZW5kcyBhcmM0LkNvbnRyYWN0IHsKICAgIHR4biBPbkNvbXBsZXRpb24KICAgIGJueiBtYWluX2FmdGVyX2lmX2Vsc2VAMjIKICAgIHR4biBBcHBsaWNhdGlvbklECiAgICAhCiAgICBhc3NlcnQgLy8gY2FuIG9ubHkgY2FsbCB3aGVuIGNyZWF0aW5nCiAgICBpbnRjXzAgLy8gMQogICAgcmV0dXJuCgoKLy8gdGVzdHMvYXJ0aWZhY3RzL3N0YXRlLW9wcy9zdGF0ZS1hY2N0LXBhcmFtcy1nZXQtY29udHJhY3QuYWxnby50czo6U3RhdGVBY2N0UGFyYW1zR2V0Q29udHJhY3QudmVyaWZ5X2FjY3RfYmFsYW5jZShhOiBieXRlcykgLT4gdWludDY0Ogp2ZXJpZnlfYWNjdF9iYWxhbmNlOgogICAgLy8gdGVzdHMvYXJ0aWZhY3RzL3N0YXRlLW9wcy9zdGF0ZS1hY2N0LXBhcmFtcy1nZXQtY29udHJhY3QuYWxnby50czo5LTEwCiAgICAvLyBAYXJjNC5hYmltZXRob2QoKQogICAgLy8gcHVibGljIHZlcmlmeV9hY2N0X2JhbGFuY2UoYTogQWNjb3VudCk6IHVpbnQ2NCB7CiAgICBwcm90byAxIDEKICAgIC8vIHRlc3RzL2FydGlmYWN0cy9zdGF0ZS1vcHMvc3RhdGUtYWNjdC1wYXJhbXMtZ2V0LWNvbnRyYWN0LmFsZ28udHM6MTEKICAgIC8vIGNvbnN0IFt2YWx1ZSwgZnVuZGVkXSA9IG9wLkFjY3RQYXJhbXMuYWNjdEJhbGFuY2UoYSkKICAgIGZyYW1lX2RpZyAtMQogICAgYWNjdF9wYXJhbXNfZ2V0IEFjY3RCYWxhbmNlCiAgICAvLyB0ZXN0cy9hcnRpZmFjdHMvc3RhdGUtb3BzL3N0YXRlLWFjY3QtcGFyYW1zLWdldC1jb250cmFjdC5hbGdvLnRzOjUKICAgIC8vIHJldHVybiBvcC5idG9pKFR4bi5hcHBsaWNhdGlvbkFyZ3MoMSkpCiAgICBpbnRjXzAgLy8gMQogICAgdHhuYXMgQXBwbGljYXRpb25BcmdzCiAgICBidG9pCiAgICAvLyB0ZXN0cy9hcnRpZmFjdHMvc3RhdGUtb3BzL3N0YXRlLWFjY3QtcGFyYW1zLWdldC1jb250cmFjdC5hbGdvLnRzOjEyCiAgICAvLyBjb25zdCBbdmFsdWVfaW5kZXgsIGZ1bmRlZF9pbmRleF0gPSBvcC5BY2N0UGFyYW1zLmFjY3RCYWxhbmNlKGdldF8xc3RfcmVmX2luZGV4KCkpCiAgICBkdXAKICAgIGFjY3RfcGFyYW1zX2dldCBBY2N0QmFsYW5jZQogICAgLy8gdGVzdHMvYXJ0aWZhY3RzL3N0YXRlLW9wcy9zdGF0ZS1hY2N0LXBhcmFtcy1nZXQtY29udHJhY3QuYWxnby50czoxMwogICAgLy8gYXNzZXJ0KHZhbHVlID09PSB2YWx1ZV9pbmRleCwgJ2V4cGVjdGVkIHZhbHVlIGJ5IGluZGV4IHRvIG1hdGNoJykKICAgIGRpZyA0CiAgICB1bmNvdmVyIDIKICAgID09CiAgICBhc3NlcnQgLy8gZXhwZWN0ZWQgdmFsdWUgYnkgaW5kZXggdG8gbWF0Y2gKICAgIC8vIHRlc3RzL2FydGlmYWN0cy9zdGF0ZS1vcHMvc3RhdGUtYWNjdC1wYXJhbXMtZ2V0LWNvbnRyYWN0LmFsZ28udHM6MTQKICAgIC8vIGFzc2VydChmdW5kZWQgPT09IGZ1bmRlZF9pbmRleCwgJ2V4cGVjdGVkIGZ1bmRlZCBieSBpbmRleCB0byBtYXRjaCcpCiAgICB1bmNvdmVyIDIKICAgID09CiAgICBhc3NlcnQgLy8gZXhwZWN0ZWQgZnVuZGVkIGJ5IGluZGV4IHRvIG1hdGNoCiAgICAvLyB0ZXN0cy9hcnRpZmFjdHMvc3RhdGUtb3BzL3N0YXRlLWFjY3QtcGFyYW1zLWdldC1jb250cmFjdC5hbGdvLnRzOjE1CiAgICAvLyBhc3NlcnQodmFsdWUgPT09IGEuYmFsYW5jZSwgJ2V4cGVjdGVkIEFjY291bnQgYmFsYW5jZSB0byBtYXRjaCcpCiAgICBmcmFtZV9kaWcgLTEKICAgIGFjY3RfcGFyYW1zX2dldCBBY2N0QmFsYW5jZQogICAgYXNzZXJ0IC8vIGFjY291bnQgZnVuZGVkCiAgICBkaWcgMgogICAgPT0KICAgIGFzc2VydCAvLyBleHBlY3RlZCBBY2NvdW50IGJhbGFuY2UgdG8gbWF0Y2gKICAgIC8vIHRlc3RzL2FydGlmYWN0cy9zdGF0ZS1vcHMvc3RhdGUtYWNjdC1wYXJhbXMtZ2V0LWNvbnRyYWN0LmFsZ28udHM6MTYKICAgIC8vIGFzc2VydCh2YWx1ZSA9PT0gb3AuYmFsYW5jZShhKSwgJ2V4cGVjdGVkIG9wLmJhbGFuY2UgdG8gbWF0Y2gnKQogICAgZnJhbWVfZGlnIC0xCiAgICBiYWxhbmNlCiAgICBkaWcgMgogICAgPT0KICAgIGFzc2VydCAvLyBleHBlY3RlZCBvcC5iYWxhbmNlIHRvIG1hdGNoCiAgICAvLyB0ZXN0cy9hcnRpZmFjdHMvc3RhdGUtb3BzL3N0YXRlLWFjY3QtcGFyYW1zLWdldC1jb250cmFjdC5hbGdvLnRzOjE3CiAgICAvLyBhc3NlcnQodmFsdWUgPT09IG9wLmJhbGFuY2UoZ2V0XzFzdF9yZWZfaW5kZXgoKSksICdleHBlY3RlZCBvcC5iYWxhbmNlIGJ5IGluZGV4IHRvIG1hdGNoJykKICAgIGJhbGFuY2UKICAgIGRpZyAxCiAgICA9PQogICAgYXNzZXJ0IC8vIGV4cGVjdGVkIG9wLmJhbGFuY2UgYnkgaW5kZXggdG8gbWF0Y2gKICAgIC8vIHRlc3RzL2FydGlmYWN0cy9zdGF0ZS1vcHMvc3RhdGUtYWNjdC1wYXJhbXMtZ2V0LWNvbnRyYWN0LmFsZ28udHM6MTgKICAgIC8vIHJldHVybiB2YWx1ZQogICAgcmV0c3ViCgoKLy8gdGVzdHMvYXJ0aWZhY3RzL3N0YXRlLW9wcy9zdGF0ZS1hY2N0LXBhcmFtcy1nZXQtY29udHJhY3QuYWxnby50czo6U3RhdGVBY2N0UGFyYW1zR2V0Q29udHJhY3QudmVyaWZ5X2FjY3RfbWluX2JhbGFuY2UoYTogYnl0ZXMpIC0+IHVpbnQ2NDoKdmVyaWZ5X2FjY3RfbWluX2JhbGFuY2U6CiAgICAvLyB0ZXN0cy9hcnRpZmFjdHMvc3RhdGUtb3BzL3N0YXRlLWFjY3QtcGFyYW1zLWdldC1jb250cmFjdC5hbGdvLnRzOjIxLTIyCiAgICAvLyBAYXJjNC5hYmltZXRob2QoKQogICAgLy8gcHVibGljIHZlcmlmeV9hY2N0X21pbl9iYWxhbmNlKGE6IEFjY291bnQpOiB1aW50NjQgewogICAgcHJvdG8gMSAxCiAgICAvLyB0ZXN0cy9hcnRpZmFjdHMvc3RhdGUtb3BzL3N0YXRlLWFjY3QtcGFyYW1zLWdldC1jb250cmFjdC5hbGdvLnRzOjIzCiAgICAvLyBjb25zdCBbdmFsdWUsIGZ1bmRlZF0gPSBvcC5BY2N0UGFyYW1zLmFjY3RNaW5CYWxhbmNlKGEpCiAgICBmcmFtZV9kaWcgLTEKICAgIGFjY3RfcGFyYW1zX2dldCBBY2N0TWluQmFsYW5jZQogICAgLy8gdGVzdHMvYXJ0aWZhY3RzL3N0YXRlLW9wcy9zdGF0ZS1hY2N0LXBhcmFtcy1nZXQtY29udHJhY3QuYWxnby50czo1CiAgICAvLyByZXR1cm4gb3AuYnRvaShUeG4uYXBwbGljYXRpb25BcmdzKDEpKQogICAgaW50Y18wIC8vIDEKICAgIHR4bmFzIEFwcGxpY2F0aW9uQXJncwogICAgYnRvaQogICAgLy8gdGVzdHMvYXJ0aWZhY3RzL3N0YXRlLW9wcy9zdGF0ZS1hY2N0LXBhcmFtcy1nZXQtY29udHJhY3QuYWxnby50czoyNAogICAgLy8gY29uc3QgW3ZhbHVlX2luZGV4LCBmdW5kZWRfaW5kZXhdID0gb3AuQWNjdFBhcmFtcy5hY2N0TWluQmFsYW5jZShnZXRfMXN0X3JlZl9pbmRleCgpKQogICAgZHVwCiAgICBhY2N0X3BhcmFtc19nZXQgQWNjdE1pbkJhbGFuY2UKICAgIC8vIHRlc3RzL2FydGlmYWN0cy9zdGF0ZS1vcHMvc3RhdGUtYWNjdC1wYXJhbXMtZ2V0LWNvbnRyYWN0LmFsZ28udHM6MjUKICAgIC8vIGFzc2VydCh2YWx1ZSA9PT0gdmFsdWVfaW5kZXgsICdleHBlY3RlZCB2YWx1ZSBieSBpbmRleCB0byBtYXRjaCcpCiAgICBkaWcgNAogICAgdW5jb3ZlciAyCiAgICA9PQogICAgYXNzZXJ0IC8vIGV4cGVjdGVkIHZhbHVlIGJ5IGluZGV4IHRvIG1hdGNoCiAgICAvLyB0ZXN0cy9hcnRpZmFjdHMvc3RhdGUtb3BzL3N0YXRlLWFjY3QtcGFyYW1zLWdldC1jb250cmFjdC5hbGdvLnRzOjI2CiAgICAvLyBhc3NlcnQoZnVuZGVkID09PSBmdW5kZWRfaW5kZXgsICdleHBlY3RlZCBmdW5kZWQgYnkgaW5kZXggdG8gbWF0Y2gnKQogICAgdW5jb3ZlciAyCiAgICA9PQogICAgYXNzZXJ0IC8vIGV4cGVjdGVkIGZ1bmRlZCBieSBpbmRleCB0byBtYXRjaAogICAgLy8gdGVzdHMvYXJ0aWZhY3RzL3N0YXRlLW9wcy9zdGF0ZS1hY2N0LXBhcmFtcy1nZXQtY29udHJhY3QuYWxnby50czoyNwogICAgLy8gYXNzZXJ0KHZhbHVlID09PSBhLm1pbkJhbGFuY2UsICdleHBlY3RlZCBBY2NvdW50IG1pbl9iYWxhbmNlIHRvIG1hdGNoJykKICAgIGZyYW1lX2RpZyAtMQogICAgYWNjdF9wYXJhbXNfZ2V0IEFjY3RNaW5CYWxhbmNlCiAgICBhc3NlcnQgLy8gYWNjb3VudCBmdW5kZWQKICAgIGRpZyAyCiAgICA9PQogICAgYXNzZXJ0IC8vIGV4cGVjdGVkIEFjY291bnQgbWluX2JhbGFuY2UgdG8gbWF0Y2gKICAgIC8vIHRlc3RzL2FydGlmYWN0cy9zdGF0ZS1vcHMvc3RhdGUtYWNjdC1wYXJhbXMtZ2V0LWNvbnRyYWN0LmFsZ28udHM6MjgKICAgIC8vIGFzc2VydCh2YWx1ZSA9PT0gb3AubWluQmFsYW5jZShhKSwgJ2V4cGVjdGVkIG9wLm1pbl9iYWxhbmNlIHRvIG1hdGNoJykKICAgIGZyYW1lX2RpZyAtMQogICAgbWluX2JhbGFuY2UKICAgIGRpZyAyCiAgICA9PQogICAgYXNzZXJ0IC8vIGV4cGVjdGVkIG9wLm1pbl9iYWxhbmNlIHRvIG1hdGNoCiAgICAvLyB0ZXN0cy9hcnRpZmFjdHMvc3RhdGUtb3BzL3N0YXRlLWFjY3QtcGFyYW1zLWdldC1jb250cmFjdC5hbGdvLnRzOjI5CiAgICAvLyBhc3NlcnQodmFsdWUgPT09IG9wLm1pbkJhbGFuY2UoZ2V0XzFzdF9yZWZfaW5kZXgoKSksICdleHBlY3RlZCBvcC5taW5fYmFsYW5jZSBieSBpbmRleCB0byBtYXRjaCcpCiAgICBtaW5fYmFsYW5jZQogICAgZGlnIDEKICAgID09CiAgICBhc3NlcnQgLy8gZXhwZWN0ZWQgb3AubWluX2JhbGFuY2UgYnkgaW5kZXggdG8gbWF0Y2gKICAgIC8vIHRlc3RzL2FydGlmYWN0cy9zdGF0ZS1vcHMvc3RhdGUtYWNjdC1wYXJhbXMtZ2V0LWNvbnRyYWN0LmFsZ28udHM6MzAKICAgIC8vIHJldHVybiB2YWx1ZQogICAgcmV0c3ViCgoKLy8gdGVzdHMvYXJ0aWZhY3RzL3N0YXRlLW9wcy9zdGF0ZS1hY2N0LXBhcmFtcy1nZXQtY29udHJhY3QuYWxnby50czo6U3RhdGVBY2N0UGFyYW1zR2V0Q29udHJhY3QudmVyaWZ5X2FjY3RfYXV0aF9hZGRyKGE6IGJ5dGVzKSAtPiBieXRlczoKdmVyaWZ5X2FjY3RfYXV0aF9hZGRyOgogICAgLy8gdGVzdHMvYXJ0aWZhY3RzL3N0YXRlLW9wcy9zdGF0ZS1hY2N0LXBhcmFtcy1nZXQtY29udHJhY3QuYWxnby50czozMy0zNAogICAgLy8gQGFyYzQuYWJpbWV0aG9kKCkKICAgIC8vIHB1YmxpYyB2ZXJpZnlfYWNjdF9hdXRoX2FkZHIoYTogQWNjb3VudCk6IEFkZHJlc3MgewogICAgcHJvdG8gMSAxCiAgICAvLyB0ZXN0cy9hcnRpZmFjdHMvc3RhdGUtb3BzL3N0YXRlLWFjY3QtcGFyYW1zLWdldC1jb250cmFjdC5hbGdvLnRzOjM1CiAgICAvLyBjb25zdCBbdmFsdWUsIGZ1bmRlZF0gPSBvcC5BY2N0UGFyYW1zLmFjY3RBdXRoQWRkcihhKQogICAgZnJhbWVfZGlnIC0xCiAgICBhY2N0X3BhcmFtc19nZXQgQWNjdEF1dGhBZGRyCiAgICAvLyB0ZXN0cy9hcnRpZmFjdHMvc3RhdGUtb3BzL3N0YXRlLWFjY3QtcGFyYW1zLWdldC1jb250cmFjdC5hbGdvLnRzOjUKICAgIC8vIHJldHVybiBvcC5idG9pKFR4bi5hcHBsaWNhdGlvbkFyZ3MoMSkpCiAgICBpbnRjXzAgLy8gMQogICAgdHhuYXMgQXBwbGljYXRpb25BcmdzCiAgICBidG9pCiAgICAvLyB0ZXN0cy9hcnRpZmFjdHMvc3RhdGUtb3BzL3N0YXRlLWFjY3QtcGFyYW1zLWdldC1jb250cmFjdC5hbGdvLnRzOjM2CiAgICAvLyBjb25zdCBbdmFsdWVfaW5kZXgsIGZ1bmRlZF9pbmRleF0gPSBvcC5BY2N0UGFyYW1zLmFjY3RBdXRoQWRkcihnZXRfMXN0X3JlZl9pbmRleCgpKQogICAgYWNjdF9wYXJhbXNfZ2V0IEFjY3RBdXRoQWRkcgogICAgLy8gdGVzdHMvYXJ0aWZhY3RzL3N0YXRlLW9wcy9zdGF0ZS1hY2N0LXBhcmFtcy1nZXQtY29udHJhY3QuYWxnby50czozNwogICAgLy8gYXNzZXJ0KHZhbHVlID09PSB2YWx1ZV9pbmRleCwgJ2V4cGVjdGVkIHZhbHVlIGJ5IGluZGV4IHRvIG1hdGNoJykKICAgIGRpZyAzCiAgICB1bmNvdmVyIDIKICAgID09CiAgICBhc3NlcnQgLy8gZXhwZWN0ZWQgdmFsdWUgYnkgaW5kZXggdG8gbWF0Y2gKICAgIC8vIHRlc3RzL2FydGlmYWN0cy9zdGF0ZS1vcHMvc3RhdGUtYWNjdC1wYXJhbXMtZ2V0LWNvbnRyYWN0LmFsZ28udHM6MzgKICAgIC8vIGFzc2VydChmdW5kZWQgPT09IGZ1bmRlZF9pbmRleCwgJ2V4cGVjdGVkIGZ1bmRlZCBieSBpbmRleCB0byBtYXRjaCcpCiAgICA9PQogICAgYXNzZXJ0IC8vIGV4cGVjdGVkIGZ1bmRlZCBieSBpbmRleCB0byBtYXRjaAogICAgLy8gdGVzdHMvYXJ0aWZhY3RzL3N0YXRlLW9wcy9zdGF0ZS1hY2N0LXBhcmFtcy1nZXQtY29udHJhY3QuYWxnby50czozOQogICAgLy8gcmV0dXJuIG5ldyBBZGRyZXNzKHZhbHVlKQogICAgcmV0c3ViCgoKLy8gdGVzdHMvYXJ0aWZhY3RzL3N0YXRlLW9wcy9zdGF0ZS1hY2N0LXBhcmFtcy1nZXQtY29udHJhY3QuYWxnby50czo6U3RhdGVBY2N0UGFyYW1zR2V0Q29udHJhY3QudmVyaWZ5X2FjY3RfdG90YWxfbnVtX3VpbnQoYTogYnl0ZXMpIC0+IHVpbnQ2NDoKdmVyaWZ5X2FjY3RfdG90YWxfbnVtX3VpbnQ6CiAgICAvLyB0ZXN0cy9hcnRpZmFjdHMvc3RhdGUtb3BzL3N0YXRlLWFjY3QtcGFyYW1zLWdldC1jb250cmFjdC5hbGdvLnRzOjQyLTQzCiAgICAvLyBAYXJjNC5hYmltZXRob2QoKQogICAgLy8gcHVibGljIHZlcmlmeV9hY2N0X3RvdGFsX251bV91aW50KGE6IEFjY291bnQpOiB1aW50NjQgewogICAgcHJvdG8gMSAxCiAgICAvLyB0ZXN0cy9hcnRpZmFjdHMvc3RhdGUtb3BzL3N0YXRlLWFjY3QtcGFyYW1zLWdldC1jb250cmFjdC5hbGdvLnRzOjQ0CiAgICAvLyBjb25zdCBbdmFsdWUsIGZ1bmRlZF0gPSBvcC5BY2N0UGFyYW1zLmFjY3RUb3RhbE51bVVpbnQoYSkKICAgIGZyYW1lX2RpZyAtMQogICAgYWNjdF9wYXJhbXNfZ2V0IEFjY3RUb3RhbE51bVVpbnQKICAgIC8vIHRlc3RzL2FydGlmYWN0cy9zdGF0ZS1vcHMvc3RhdGUtYWNjdC1wYXJhbXMtZ2V0LWNvbnRyYWN0LmFsZ28udHM6NQogICAgLy8gcmV0dXJuIG9wLmJ0b2koVHhuLmFwcGxpY2F0aW9uQXJncygxKSkKICAgIGludGNfMCAvLyAxCiAgICB0eG5hcyBBcHBsaWNhdGlvbkFyZ3MKICAgIGJ0b2kKICAgIC8vIHRlc3RzL2FydGlmYWN0cy9zdGF0ZS1vcHMvc3RhdGUtYWNjdC1wYXJhbXMtZ2V0LWNvbnRyYWN0LmFsZ28udHM6NDUKICAgIC8vIGNvbnN0IFt2YWx1ZV9pbmRleCwgZnVuZGVkX2luZGV4XSA9IG9wLkFjY3RQYXJhbXMuYWNjdFRvdGFsTnVtVWludChnZXRfMXN0X3JlZl9pbmRleCgpKQogICAgYWNjdF9wYXJhbXNfZ2V0IEFjY3RUb3RhbE51bVVpbnQKICAgIC8vIHRlc3RzL2FydGlmYWN0cy9zdGF0ZS1vcHMvc3RhdGUtYWNjdC1wYXJhbXMtZ2V0LWNvbnRyYWN0LmFsZ28udHM6NDYKICAgIC8vIGFzc2VydCh2YWx1ZSA9PT0gdmFsdWVfaW5kZXgsICdleHBlY3RlZCB2YWx1ZSBieSBpbmRleCB0byBtYXRjaCcpCiAgICBkaWcgMwogICAgdW5jb3ZlciAyCiAgICA9PQogICAgYXNzZXJ0IC8vIGV4cGVjdGVkIHZhbHVlIGJ5IGluZGV4IHRvIG1hdGNoCiAgICAvLyB0ZXN0cy9hcnRpZmFjdHMvc3RhdGUtb3BzL3N0YXRlLWFjY3QtcGFyYW1zLWdldC1jb250cmFjdC5hbGdvLnRzOjQ3CiAgICAvLyBhc3NlcnQoZnVuZGVkID09PSBmdW5kZWRfaW5kZXgsICdleHBlY3RlZCBmdW5kZWQgYnkgaW5kZXggdG8gbWF0Y2gnKQogICAgPT0KICAgIGFzc2VydCAvLyBleHBlY3RlZCBmdW5kZWQgYnkgaW5kZXggdG8gbWF0Y2gKICAgIC8vIHRlc3RzL2FydGlmYWN0cy9zdGF0ZS1vcHMvc3RhdGUtYWNjdC1wYXJhbXMtZ2V0LWNvbnRyYWN0LmFsZ28udHM6NDgKICAgIC8vIHJldHVybiB2YWx1ZQogICAgcmV0c3ViCgoKLy8gdGVzdHMvYXJ0aWZhY3RzL3N0YXRlLW9wcy9zdGF0ZS1hY2N0LXBhcmFtcy1nZXQtY29udHJhY3QuYWxnby50czo6U3RhdGVBY2N0UGFyYW1zR2V0Q29udHJhY3QudmVyaWZ5X2FjY3RfdG90YWxfbnVtX2J5dGVfc2xpY2UoYTogYnl0ZXMpIC0+IHVpbnQ2NDoKdmVyaWZ5X2FjY3RfdG90YWxfbnVtX2J5dGVfc2xpY2U6CiAgICAvLyB0ZXN0cy9hcnRpZmFjdHMvc3RhdGUtb3BzL3N0YXRlLWFjY3QtcGFyYW1zLWdldC1jb250cmFjdC5hbGdvLnRzOjUxLTUyCiAgICAvLyBAYXJjNC5hYmltZXRob2QoKQogICAgLy8gcHVibGljIHZlcmlmeV9hY2N0X3RvdGFsX251bV9ieXRlX3NsaWNlKGE6IEFjY291bnQpOiB1aW50NjQgewogICAgcHJvdG8gMSAxCiAgICAvLyB0ZXN0cy9hcnRpZmFjdHMvc3RhdGUtb3BzL3N0YXRlLWFjY3QtcGFyYW1zLWdldC1jb250cmFjdC5hbGdvLnRzOjUzCiAgICAvLyBjb25zdCBbdmFsdWUsIGZ1bmRlZF0gPSBvcC5BY2N0UGFyYW1zLmFjY3RUb3RhbE51bUJ5dGVTbGljZShhKQogICAgZnJhbWVfZGlnIC0xCiAgICBhY2N0X3BhcmFtc19nZXQgQWNjdFRvdGFsTnVtQnl0ZVNsaWNlCiAgICAvLyB0ZXN0cy9hcnRpZmFjdHMvc3RhdGUtb3BzL3N0YXRlLWFjY3QtcGFyYW1zLWdldC1jb250cmFjdC5hbGdvLnRzOjUKICAgIC8vIHJldHVybiBvcC5idG9pKFR4bi5hcHBsaWNhdGlvbkFyZ3MoMSkpCiAgICBpbnRjXzAgLy8gMQogICAgdHhuYXMgQXBwbGljYXRpb25BcmdzCiAgICBidG9pCiAgICAvLyB0ZXN0cy9hcnRpZmFjdHMvc3RhdGUtb3BzL3N0YXRlLWFjY3QtcGFyYW1zLWdldC1jb250cmFjdC5hbGdvLnRzOjU0CiAgICAvLyBjb25zdCBbdmFsdWVfaW5kZXgsIGZ1bmRlZF9pbmRleF0gPSBvcC5BY2N0UGFyYW1zLmFjY3RUb3RhbE51bUJ5dGVTbGljZShnZXRfMXN0X3JlZl9pbmRleCgpKQogICAgYWNjdF9wYXJhbXNfZ2V0IEFjY3RUb3RhbE51bUJ5dGVTbGljZQogICAgLy8gdGVzdHMvYXJ0aWZhY3RzL3N0YXRlLW9wcy9zdGF0ZS1hY2N0LXBhcmFtcy1nZXQtY29udHJhY3QuYWxnby50czo1NQogICAgLy8gYXNzZXJ0KHZhbHVlID09PSB2YWx1ZV9pbmRleCwgJ2V4cGVjdGVkIHZhbHVlIGJ5IGluZGV4IHRvIG1hdGNoJykKICAgIGRpZyAzCiAgICB1bmNvdmVyIDIKICAgID09CiAgICBhc3NlcnQgLy8gZXhwZWN0ZWQgdmFsdWUgYnkgaW5kZXggdG8gbWF0Y2gKICAgIC8vIHRlc3RzL2FydGlmYWN0cy9zdGF0ZS1vcHMvc3RhdGUtYWNjdC1wYXJhbXMtZ2V0LWNvbnRyYWN0LmFsZ28udHM6NTYKICAgIC8vIGFzc2VydChmdW5kZWQgPT09IGZ1bmRlZF9pbmRleCwgJ2V4cGVjdGVkIGZ1bmRlZCBieSBpbmRleCB0byBtYXRjaCcpCiAgICA9PQogICAgYXNzZXJ0IC8vIGV4cGVjdGVkIGZ1bmRlZCBieSBpbmRleCB0byBtYXRjaAogICAgLy8gdGVzdHMvYXJ0aWZhY3RzL3N0YXRlLW9wcy9zdGF0ZS1hY2N0LXBhcmFtcy1nZXQtY29udHJhY3QuYWxnby50czo1NwogICAgLy8gcmV0dXJuIHZhbHVlCiAgICByZXRzdWIKCgovLyB0ZXN0cy9hcnRpZmFjdHMvc3RhdGUtb3BzL3N0YXRlLWFjY3QtcGFyYW1zLWdldC1jb250cmFjdC5hbGdvLnRzOjpTdGF0ZUFjY3RQYXJhbXNHZXRDb250cmFjdC52ZXJpZnlfYWNjdF90b3RhbF9leHRyYV9hcHBfcGFnZXMoYTogYnl0ZXMpIC0+IHVpbnQ2NDoKdmVyaWZ5X2FjY3RfdG90YWxfZXh0cmFfYXBwX3BhZ2VzOgogICAgLy8gdGVzdHMvYXJ0aWZhY3RzL3N0YXRlLW9wcy9zdGF0ZS1hY2N0LXBhcmFtcy1nZXQtY29udHJhY3QuYWxnby50czo2MC02MQogICAgLy8gQGFyYzQuYWJpbWV0aG9kKCkKICAgIC8vIHB1YmxpYyB2ZXJpZnlfYWNjdF90b3RhbF9leHRyYV9hcHBfcGFnZXMoYTogQWNjb3VudCk6IHVpbnQ2NCB7CiAgICBwcm90byAxIDEKICAgIC8vIHRlc3RzL2FydGlmYWN0cy9zdGF0ZS1vcHMvc3RhdGUtYWNjdC1wYXJhbXMtZ2V0LWNvbnRyYWN0LmFsZ28udHM6NjIKICAgIC8vIGNvbnN0IFt2YWx1ZSwgZnVuZGVkXSA9IG9wLkFjY3RQYXJhbXMuYWNjdFRvdGFsRXh0cmFBcHBQYWdlcyhhKQogICAgZnJhbWVfZGlnIC0xCiAgICBhY2N0X3BhcmFtc19nZXQgQWNjdFRvdGFsRXh0cmFBcHBQYWdlcwogICAgLy8gdGVzdHMvYXJ0aWZhY3RzL3N0YXRlLW9wcy9zdGF0ZS1hY2N0LXBhcmFtcy1nZXQtY29udHJhY3QuYWxnby50czo1CiAgICAvLyByZXR1cm4gb3AuYnRvaShUeG4uYXBwbGljYXRpb25BcmdzKDEpKQogICAgaW50Y18wIC8vIDEKICAgIHR4bmFzIEFwcGxpY2F0aW9uQXJncwogICAgYnRvaQogICAgLy8gdGVzdHMvYXJ0aWZhY3RzL3N0YXRlLW9wcy9zdGF0ZS1hY2N0LXBhcmFtcy1nZXQtY29udHJhY3QuYWxnby50czo2MwogICAgLy8gY29uc3QgW3ZhbHVlX2luZGV4LCBmdW5kZWRfaW5kZXhdID0gb3AuQWNjdFBhcmFtcy5hY2N0VG90YWxFeHRyYUFwcFBhZ2VzKGdldF8xc3RfcmVmX2luZGV4KCkpCiAgICBhY2N0X3BhcmFtc19nZXQgQWNjdFRvdGFsRXh0cmFBcHBQYWdlcwogICAgLy8gdGVzdHMvYXJ0aWZhY3RzL3N0YXRlLW9wcy9zdGF0ZS1hY2N0LXBhcmFtcy1nZXQtY29udHJhY3QuYWxnby50czo2NAogICAgLy8gYXNzZXJ0KHZhbHVlID09PSB2YWx1ZV9pbmRleCwgJ2V4cGVjdGVkIHZhbHVlIGJ5IGluZGV4IHRvIG1hdGNoJykKICAgIGRpZyAzCiAgICB1bmNvdmVyIDIKICAgID09CiAgICBhc3NlcnQgLy8gZXhwZWN0ZWQgdmFsdWUgYnkgaW5kZXggdG8gbWF0Y2gKICAgIC8vIHRlc3RzL2FydGlmYWN0cy9zdGF0ZS1vcHMvc3RhdGUtYWNjdC1wYXJhbXMtZ2V0LWNvbnRyYWN0LmFsZ28udHM6NjUKICAgIC8vIGFzc2VydChmdW5kZWQgPT09IGZ1bmRlZF9pbmRleCwgJ2V4cGVjdGVkIGZ1bmRlZCBieSBpbmRleCB0byBtYXRjaCcpCiAgICA9PQogICAgYXNzZXJ0IC8vIGV4cGVjdGVkIGZ1bmRlZCBieSBpbmRleCB0byBtYXRjaAogICAgLy8gdGVzdHMvYXJ0aWZhY3RzL3N0YXRlLW9wcy9zdGF0ZS1hY2N0LXBhcmFtcy1nZXQtY29udHJhY3QuYWxnby50czo2NgogICAgLy8gcmV0dXJuIHZhbHVlCiAgICByZXRzdWIKCgovLyB0ZXN0cy9hcnRpZmFjdHMvc3RhdGUtb3BzL3N0YXRlLWFjY3QtcGFyYW1zLWdldC1jb250cmFjdC5hbGdvLnRzOjpTdGF0ZUFjY3RQYXJhbXNHZXRDb250cmFjdC52ZXJpZnlfYWNjdF90b3RhbF9hcHBzX2NyZWF0ZWQoYTogYnl0ZXMpIC0+IHVpbnQ2NDoKdmVyaWZ5X2FjY3RfdG90YWxfYXBwc19jcmVhdGVkOgogICAgLy8gdGVzdHMvYXJ0aWZhY3RzL3N0YXRlLW9wcy9zdGF0ZS1hY2N0LXBhcmFtcy1nZXQtY29udHJhY3QuYWxnby50czo2OS03MAogICAgLy8gQGFyYzQuYWJpbWV0aG9kKCkKICAgIC8vIHB1YmxpYyB2ZXJpZnlfYWNjdF90b3RhbF9hcHBzX2NyZWF0ZWQoYTogQWNjb3VudCk6IHVpbnQ2NCB7CiAgICBwcm90byAxIDEKICAgIC8vIHRlc3RzL2FydGlmYWN0cy9zdGF0ZS1vcHMvc3RhdGUtYWNjdC1wYXJhbXMtZ2V0LWNvbnRyYWN0LmFsZ28udHM6NzEKICAgIC8vIGNvbnN0IFt2YWx1ZSwgZnVuZGVkXSA9IG9wLkFjY3RQYXJhbXMuYWNjdFRvdGFsQXBwc0NyZWF0ZWQoYSkKICAgIGZyYW1lX2RpZyAtMQogICAgYWNjdF9wYXJhbXNfZ2V0IEFjY3RUb3RhbEFwcHNDcmVhdGVkCiAgICAvLyB0ZXN0cy9hcnRpZmFjdHMvc3RhdGUtb3BzL3N0YXRlLWFjY3QtcGFyYW1zLWdldC1jb250cmFjdC5hbGdvLnRzOjUKICAgIC8vIHJldHVybiBvcC5idG9pKFR4bi5hcHBsaWNhdGlvbkFyZ3MoMSkpCiAgICBpbnRjXzAgLy8gMQogICAgdHhuYXMgQXBwbGljYXRpb25BcmdzCiAgICBidG9pCiAgICAvLyB0ZXN0cy9hcnRpZmFjdHMvc3RhdGUtb3BzL3N0YXRlLWFjY3QtcGFyYW1zLWdldC1jb250cmFjdC5hbGdvLnRzOjcyCiAgICAvLyBjb25zdCBbdmFsdWVfaW5kZXgsIGZ1bmRlZF9pbmRleF0gPSBvcC5BY2N0UGFyYW1zLmFjY3RUb3RhbEFwcHNDcmVhdGVkKGdldF8xc3RfcmVmX2luZGV4KCkpCiAgICBhY2N0X3BhcmFtc19nZXQgQWNjdFRvdGFsQXBwc0NyZWF0ZWQKICAgIC8vIHRlc3RzL2FydGlmYWN0cy9zdGF0ZS1vcHMvc3RhdGUtYWNjdC1wYXJhbXMtZ2V0LWNvbnRyYWN0LmFsZ28udHM6NzMKICAgIC8vIGFzc2VydCh2YWx1ZSA9PT0gdmFsdWVfaW5kZXgsICdleHBlY3RlZCB2YWx1ZSBieSBpbmRleCB0byBtYXRjaCcpCiAgICBkaWcgMwogICAgdW5jb3ZlciAyCiAgICA9PQogICAgYXNzZXJ0IC8vIGV4cGVjdGVkIHZhbHVlIGJ5IGluZGV4IHRvIG1hdGNoCiAgICAvLyB0ZXN0cy9hcnRpZmFjdHMvc3RhdGUtb3BzL3N0YXRlLWFjY3QtcGFyYW1zLWdldC1jb250cmFjdC5hbGdvLnRzOjc0CiAgICAvLyBhc3NlcnQoZnVuZGVkID09PSBmdW5kZWRfaW5kZXgsICdleHBlY3RlZCBmdW5kZWQgYnkgaW5kZXggdG8gbWF0Y2gnKQogICAgPT0KICAgIGFzc2VydCAvLyBleHBlY3RlZCBmdW5kZWQgYnkgaW5kZXggdG8gbWF0Y2gKICAgIC8vIHRlc3RzL2FydGlmYWN0cy9zdGF0ZS1vcHMvc3RhdGUtYWNjdC1wYXJhbXMtZ2V0LWNvbnRyYWN0LmFsZ28udHM6NzUKICAgIC8vIHJldHVybiB2YWx1ZQogICAgcmV0c3ViCgoKLy8gdGVzdHMvYXJ0aWZhY3RzL3N0YXRlLW9wcy9zdGF0ZS1hY2N0LXBhcmFtcy1nZXQtY29udHJhY3QuYWxnby50czo6U3RhdGVBY2N0UGFyYW1zR2V0Q29udHJhY3QudmVyaWZ5X2FjY3RfdG90YWxfYXBwc19vcHRlZF9pbihhOiBieXRlcykgLT4gdWludDY0Ogp2ZXJpZnlfYWNjdF90b3RhbF9hcHBzX29wdGVkX2luOgogICAgLy8gdGVzdHMvYXJ0aWZhY3RzL3N0YXRlLW9wcy9zdGF0ZS1hY2N0LXBhcmFtcy1nZXQtY29udHJhY3QuYWxnby50czo3OC03OQogICAgLy8gQGFyYzQuYWJpbWV0aG9kKCkKICAgIC8vIHB1YmxpYyB2ZXJpZnlfYWNjdF90b3RhbF9hcHBzX29wdGVkX2luKGE6IEFjY291bnQpOiB1aW50NjQgewogICAgcHJvdG8gMSAxCiAgICAvLyB0ZXN0cy9hcnRpZmFjdHMvc3RhdGUtb3BzL3N0YXRlLWFjY3QtcGFyYW1zLWdldC1jb250cmFjdC5hbGdvLnRzOjgwCiAgICAvLyBjb25zdCBbdmFsdWUsIGZ1bmRlZF0gPSBvcC5BY2N0UGFyYW1zLmFjY3RUb3RhbEFwcHNPcHRlZEluKGEpCiAgICBmcmFtZV9kaWcgLTEKICAgIGFjY3RfcGFyYW1zX2dldCBBY2N0VG90YWxBcHBzT3B0ZWRJbgogICAgLy8gdGVzdHMvYXJ0aWZhY3RzL3N0YXRlLW9wcy9zdGF0ZS1hY2N0LXBhcmFtcy1nZXQtY29udHJhY3QuYWxnby50czo1CiAgICAvLyByZXR1cm4gb3AuYnRvaShUeG4uYXBwbGljYXRpb25BcmdzKDEpKQogICAgaW50Y18wIC8vIDEKICAgIHR4bmFzIEFwcGxpY2F0aW9uQXJncwogICAgYnRvaQogICAgLy8gdGVzdHMvYXJ0aWZhY3RzL3N0YXRlLW9wcy9zdGF0ZS1hY2N0LXBhcmFtcy1nZXQtY29udHJhY3QuYWxnby50czo4MQogICAgLy8gY29uc3QgW3ZhbHVlX2luZGV4LCBmdW5kZWRfaW5kZXhdID0gb3AuQWNjdFBhcmFtcy5hY2N0VG90YWxBcHBzT3B0ZWRJbihnZXRfMXN0X3JlZl9pbmRleCgpKQogICAgYWNjdF9wYXJhbXNfZ2V0IEFjY3RUb3RhbEFwcHNPcHRlZEluCiAgICAvLyB0ZXN0cy9hcnRpZmFjdHMvc3RhdGUtb3BzL3N0YXRlLWFjY3QtcGFyYW1zLWdldC1jb250cmFjdC5hbGdvLnRzOjgyCiAgICAvLyBhc3NlcnQodmFsdWUgPT09IHZhbHVlX2luZGV4LCAnZXhwZWN0ZWQgdmFsdWUgYnkgaW5kZXggdG8gbWF0Y2gnKQogICAgZGlnIDMKICAgIHVuY292ZXIgMgogICAgPT0KICAgIGFzc2VydCAvLyBleHBlY3RlZCB2YWx1ZSBieSBpbmRleCB0byBtYXRjaAogICAgLy8gdGVzdHMvYXJ0aWZhY3RzL3N0YXRlLW9wcy9zdGF0ZS1hY2N0LXBhcmFtcy1nZXQtY29udHJhY3QuYWxnby50czo4MwogICAgLy8gYXNzZXJ0KGZ1bmRlZCA9PT0gZnVuZGVkX2luZGV4LCAnZXhwZWN0ZWQgZnVuZGVkIGJ5IGluZGV4IHRvIG1hdGNoJykKICAgID09CiAgICBhc3NlcnQgLy8gZXhwZWN0ZWQgZnVuZGVkIGJ5IGluZGV4IHRvIG1hdGNoCiAgICAvLyB0ZXN0cy9hcnRpZmFjdHMvc3RhdGUtb3BzL3N0YXRlLWFjY3QtcGFyYW1zLWdldC1jb250cmFjdC5hbGdvLnRzOjg0CiAgICAvLyByZXR1cm4gdmFsdWUKICAgIHJldHN1YgoKCi8vIHRlc3RzL2FydGlmYWN0cy9zdGF0ZS1vcHMvc3RhdGUtYWNjdC1wYXJhbXMtZ2V0LWNvbnRyYWN0LmFsZ28udHM6OlN0YXRlQWNjdFBhcmFtc0dldENvbnRyYWN0LnZlcmlmeV9hY2N0X3RvdGFsX2Fzc2V0c19jcmVhdGVkKGE6IGJ5dGVzKSAtPiB1aW50NjQ6CnZlcmlmeV9hY2N0X3RvdGFsX2Fzc2V0c19jcmVhdGVkOgogICAgLy8gdGVzdHMvYXJ0aWZhY3RzL3N0YXRlLW9wcy9zdGF0ZS1hY2N0LXBhcmFtcy1nZXQtY29udHJhY3QuYWxnby50czo4Ny04OAogICAgLy8gQGFyYzQuYWJpbWV0aG9kKCkKICAgIC8vIHB1YmxpYyB2ZXJpZnlfYWNjdF90b3RhbF9hc3NldHNfY3JlYXRlZChhOiBBY2NvdW50KTogdWludDY0IHsKICAgIHByb3RvIDEgMQogICAgLy8gdGVzdHMvYXJ0aWZhY3RzL3N0YXRlLW9wcy9zdGF0ZS1hY2N0LXBhcmFtcy1nZXQtY29udHJhY3QuYWxnby50czo4OQogICAgLy8gY29uc3QgW3ZhbHVlLCBmdW5kZWRdID0gb3AuQWNjdFBhcmFtcy5hY2N0VG90YWxBc3NldHNDcmVhdGVkKGEpCiAgICBmcmFtZV9kaWcgLTEKICAgIGFjY3RfcGFyYW1zX2dldCBBY2N0VG90YWxBc3NldHNDcmVhdGVkCiAgICAvLyB0ZXN0cy9hcnRpZmFjdHMvc3RhdGUtb3BzL3N0YXRlLWFjY3QtcGFyYW1zLWdldC1jb250cmFjdC5hbGdvLnRzOjUKICAgIC8vIHJldHVybiBvcC5idG9pKFR4bi5hcHBsaWNhdGlvbkFyZ3MoMSkpCiAgICBpbnRjXzAgLy8gMQogICAgdHhuYXMgQXBwbGljYXRpb25BcmdzCiAgICBidG9pCiAgICAvLyB0ZXN0cy9hcnRpZmFjdHMvc3RhdGUtb3BzL3N0YXRlLWFjY3QtcGFyYW1zLWdldC1jb250cmFjdC5hbGdvLnRzOjkwCiAgICAvLyBjb25zdCBbdmFsdWVfaW5kZXgsIGZ1bmRlZF9pbmRleF0gPSBvcC5BY2N0UGFyYW1zLmFjY3RUb3RhbEFzc2V0c0NyZWF0ZWQoZ2V0XzFzdF9yZWZfaW5kZXgoKSkKICAgIGFjY3RfcGFyYW1zX2dldCBBY2N0VG90YWxBc3NldHNDcmVhdGVkCiAgICAvLyB0ZXN0cy9hcnRpZmFjdHMvc3RhdGUtb3BzL3N0YXRlLWFjY3QtcGFyYW1zLWdldC1jb250cmFjdC5hbGdvLnRzOjkxCiAgICAvLyBhc3NlcnQodmFsdWUgPT09IHZhbHVlX2luZGV4LCAnZXhwZWN0ZWQgdmFsdWUgYnkgaW5kZXggdG8gbWF0Y2gnKQogICAgZGlnIDMKICAgIHVuY292ZXIgMgogICAgPT0KICAgIGFzc2VydCAvLyBleHBlY3RlZCB2YWx1ZSBieSBpbmRleCB0byBtYXRjaAogICAgLy8gdGVzdHMvYXJ0aWZhY3RzL3N0YXRlLW9wcy9zdGF0ZS1hY2N0LXBhcmFtcy1nZXQtY29udHJhY3QuYWxnby50czo5MgogICAgLy8gYXNzZXJ0KGZ1bmRlZCA9PT0gZnVuZGVkX2luZGV4LCAnZXhwZWN0ZWQgZnVuZGVkIGJ5IGluZGV4IHRvIG1hdGNoJykKICAgID09CiAgICBhc3NlcnQgLy8gZXhwZWN0ZWQgZnVuZGVkIGJ5IGluZGV4IHRvIG1hdGNoCiAgICAvLyB0ZXN0cy9hcnRpZmFjdHMvc3RhdGUtb3BzL3N0YXRlLWFjY3QtcGFyYW1zLWdldC1jb250cmFjdC5hbGdvLnRzOjkzCiAgICAvLyByZXR1cm4gdmFsdWUKICAgIHJldHN1YgoKCi8vIHRlc3RzL2FydGlmYWN0cy9zdGF0ZS1vcHMvc3RhdGUtYWNjdC1wYXJhbXMtZ2V0LWNvbnRyYWN0LmFsZ28udHM6OlN0YXRlQWNjdFBhcmFtc0dldENvbnRyYWN0LnZlcmlmeV9hY2N0X3RvdGFsX2Fzc2V0cyhhOiBieXRlcykgLT4gdWludDY0Ogp2ZXJpZnlfYWNjdF90b3RhbF9hc3NldHM6CiAgICAvLyB0ZXN0cy9hcnRpZmFjdHMvc3RhdGUtb3BzL3N0YXRlLWFjY3QtcGFyYW1zLWdldC1jb250cmFjdC5hbGdvLnRzOjk2LTk3CiAgICAvLyBAYXJjNC5hYmltZXRob2QoKQogICAgLy8gcHVibGljIHZlcmlmeV9hY2N0X3RvdGFsX2Fzc2V0cyhhOiBBY2NvdW50KTogdWludDY0IHsKICAgIHByb3RvIDEgMQogICAgLy8gdGVzdHMvYXJ0aWZhY3RzL3N0YXRlLW9wcy9zdGF0ZS1hY2N0LXBhcmFtcy1nZXQtY29udHJhY3QuYWxnby50czo5OAogICAgLy8gY29uc3QgW3ZhbHVlLCBmdW5kZWRdID0gb3AuQWNjdFBhcmFtcy5hY2N0VG90YWxBc3NldHMoYSkKICAgIGZyYW1lX2RpZyAtMQogICAgYWNjdF9wYXJhbXNfZ2V0IEFjY3RUb3RhbEFzc2V0cwogICAgLy8gdGVzdHMvYXJ0aWZhY3RzL3N0YXRlLW9wcy9zdGF0ZS1hY2N0LXBhcmFtcy1nZXQtY29udHJhY3QuYWxnby50czo1CiAgICAvLyByZXR1cm4gb3AuYnRvaShUeG4uYXBwbGljYXRpb25BcmdzKDEpKQogICAgaW50Y18wIC8vIDEKICAgIHR4bmFzIEFwcGxpY2F0aW9uQXJncwogICAgYnRvaQogICAgLy8gdGVzdHMvYXJ0aWZhY3RzL3N0YXRlLW9wcy9zdGF0ZS1hY2N0LXBhcmFtcy1nZXQtY29udHJhY3QuYWxnby50czo5OQogICAgLy8gY29uc3QgW3ZhbHVlX2luZGV4LCBmdW5kZWRfaW5kZXhdID0gb3AuQWNjdFBhcmFtcy5hY2N0VG90YWxBc3NldHMoZ2V0XzFzdF9yZWZfaW5kZXgoKSkKICAgIGFjY3RfcGFyYW1zX2dldCBBY2N0VG90YWxBc3NldHMKICAgIC8vIHRlc3RzL2FydGlmYWN0cy9zdGF0ZS1vcHMvc3RhdGUtYWNjdC1wYXJhbXMtZ2V0LWNvbnRyYWN0LmFsZ28udHM6MTAwCiAgICAvLyBhc3NlcnQodmFsdWUgPT09IHZhbHVlX2luZGV4LCAnZXhwZWN0ZWQgdmFsdWUgYnkgaW5kZXggdG8gbWF0Y2gnKQogICAgZGlnIDMKICAgIHVuY292ZXIgMgogICAgPT0KICAgIGFzc2VydCAvLyBleHBlY3RlZCB2YWx1ZSBieSBpbmRleCB0byBtYXRjaAogICAgLy8gdGVzdHMvYXJ0aWZhY3RzL3N0YXRlLW9wcy9zdGF0ZS1hY2N0LXBhcmFtcy1nZXQtY29udHJhY3QuYWxnby50czoxMDEKICAgIC8vIGFzc2VydChmdW5kZWQgPT09IGZ1bmRlZF9pbmRleCwgJ2V4cGVjdGVkIGZ1bmRlZCBieSBpbmRleCB0byBtYXRjaCcpCiAgICA9PQogICAgYXNzZXJ0IC8vIGV4cGVjdGVkIGZ1bmRlZCBieSBpbmRleCB0byBtYXRjaAogICAgLy8gdGVzdHMvYXJ0aWZhY3RzL3N0YXRlLW9wcy9zdGF0ZS1hY2N0LXBhcmFtcy1nZXQtY29udHJhY3QuYWxnby50czoxMDIKICAgIC8vIHJldHVybiB2YWx1ZQogICAgcmV0c3ViCgoKLy8gdGVzdHMvYXJ0aWZhY3RzL3N0YXRlLW9wcy9zdGF0ZS1hY2N0LXBhcmFtcy1nZXQtY29udHJhY3QuYWxnby50czo6U3RhdGVBY2N0UGFyYW1zR2V0Q29udHJhY3QudmVyaWZ5X2FjY3RfdG90YWxfYm94ZXMoYTogYnl0ZXMpIC0+IHVpbnQ2NDoKdmVyaWZ5X2FjY3RfdG90YWxfYm94ZXM6CiAgICAvLyB0ZXN0cy9hcnRpZmFjdHMvc3RhdGUtb3BzL3N0YXRlLWFjY3QtcGFyYW1zLWdldC1jb250cmFjdC5hbGdvLnRzOjEwNS0xMDYKICAgIC8vIEBhcmM0LmFiaW1ldGhvZCgpCiAgICAvLyBwdWJsaWMgdmVyaWZ5X2FjY3RfdG90YWxfYm94ZXMoYTogQWNjb3VudCk6IHVpbnQ2NCB7CiAgICBwcm90byAxIDEKICAgIC8vIHRlc3RzL2FydGlmYWN0cy9zdGF0ZS1vcHMvc3RhdGUtYWNjdC1wYXJhbXMtZ2V0LWNvbnRyYWN0LmFsZ28udHM6MTA3CiAgICAvLyBjb25zdCBbdmFsdWUsIGZ1bmRlZF0gPSBvcC5BY2N0UGFyYW1zLmFjY3RUb3RhbEJveGVzKGEpCiAgICBmcmFtZV9kaWcgLTEKICAgIGFjY3RfcGFyYW1zX2dldCBBY2N0VG90YWxCb3hlcwogICAgLy8gdGVzdHMvYXJ0aWZhY3RzL3N0YXRlLW9wcy9zdGF0ZS1hY2N0LXBhcmFtcy1nZXQtY29udHJhY3QuYWxnby50czo1CiAgICAvLyByZXR1cm4gb3AuYnRvaShUeG4uYXBwbGljYXRpb25BcmdzKDEpKQogICAgaW50Y18wIC8vIDEKICAgIHR4bmFzIEFwcGxpY2F0aW9uQXJncwogICAgYnRvaQogICAgLy8gdGVzdHMvYXJ0aWZhY3RzL3N0YXRlLW9wcy9zdGF0ZS1hY2N0LXBhcmFtcy1nZXQtY29udHJhY3QuYWxnby50czoxMDgKICAgIC8vIGNvbnN0IFt2YWx1ZV9pbmRleCwgZnVuZGVkX2luZGV4XSA9IG9wLkFjY3RQYXJhbXMuYWNjdFRvdGFsQm94ZXMoZ2V0XzFzdF9yZWZfaW5kZXgoKSkKICAgIGFjY3RfcGFyYW1zX2dldCBBY2N0VG90YWxCb3hlcwogICAgLy8gdGVzdHMvYXJ0aWZhY3RzL3N0YXRlLW9wcy9zdGF0ZS1hY2N0LXBhcmFtcy1nZXQtY29udHJhY3QuYWxnby50czoxMDkKICAgIC8vIGFzc2VydCh2YWx1ZSA9PT0gdmFsdWVfaW5kZXgsICdleHBlY3RlZCB2YWx1ZSBieSBpbmRleCB0byBtYXRjaCcpCiAgICBkaWcgMwogICAgdW5jb3ZlciAyCiAgICA9PQogICAgYXNzZXJ0IC8vIGV4cGVjdGVkIHZhbHVlIGJ5IGluZGV4IHRvIG1hdGNoCiAgICAvLyB0ZXN0cy9hcnRpZmFjdHMvc3RhdGUtb3BzL3N0YXRlLWFjY3QtcGFyYW1zLWdldC1jb250cmFjdC5hbGdvLnRzOjExMAogICAgLy8gYXNzZXJ0KGZ1bmRlZCA9PT0gZnVuZGVkX2luZGV4LCAnZXhwZWN0ZWQgZnVuZGVkIGJ5IGluZGV4IHRvIG1hdGNoJykKICAgID09CiAgICBhc3NlcnQgLy8gZXhwZWN0ZWQgZnVuZGVkIGJ5IGluZGV4IHRvIG1hdGNoCiAgICAvLyB0ZXN0cy9hcnRpZmFjdHMvc3RhdGUtb3BzL3N0YXRlLWFjY3QtcGFyYW1zLWdldC1jb250cmFjdC5hbGdvLnRzOjExMQogICAgLy8gcmV0dXJuIHZhbHVlCiAgICByZXRzdWIKCgovLyB0ZXN0cy9hcnRpZmFjdHMvc3RhdGUtb3BzL3N0YXRlLWFjY3QtcGFyYW1zLWdldC1jb250cmFjdC5hbGdvLnRzOjpTdGF0ZUFjY3RQYXJhbXNHZXRDb250cmFjdC52ZXJpZnlfYWNjdF90b3RhbF9ib3hfYnl0ZXMoYTogYnl0ZXMpIC0+IHVpbnQ2NDoKdmVyaWZ5X2FjY3RfdG90YWxfYm94X2J5dGVzOgogICAgLy8gdGVzdHMvYXJ0aWZhY3RzL3N0YXRlLW9wcy9zdGF0ZS1hY2N0LXBhcmFtcy1nZXQtY29udHJhY3QuYWxnby50czoxMTQtMTE1CiAgICAvLyBAYXJjNC5hYmltZXRob2QoKQogICAgLy8gcHVibGljIHZlcmlmeV9hY2N0X3RvdGFsX2JveF9ieXRlcyhhOiBBY2NvdW50KTogdWludDY0IHsKICAgIHByb3RvIDEgMQogICAgLy8gdGVzdHMvYXJ0aWZhY3RzL3N0YXRlLW9wcy9zdGF0ZS1hY2N0LXBhcmFtcy1nZXQtY29udHJhY3QuYWxnby50czoxMTYKICAgIC8vIGNvbnN0IFt2YWx1ZSwgZnVuZGVkXSA9IG9wLkFjY3RQYXJhbXMuYWNjdFRvdGFsQm94Qnl0ZXMoYSkKICAgIGZyYW1lX2RpZyAtMQogICAgYWNjdF9wYXJhbXNfZ2V0IEFjY3RUb3RhbEJveEJ5dGVzCiAgICAvLyB0ZXN0cy9hcnRpZmFjdHMvc3RhdGUtb3BzL3N0YXRlLWFjY3QtcGFyYW1zLWdldC1jb250cmFjdC5hbGdvLnRzOjUKICAgIC8vIHJldHVybiBvcC5idG9pKFR4bi5hcHBsaWNhdGlvbkFyZ3MoMSkpCiAgICBpbnRjXzAgLy8gMQogICAgdHhuYXMgQXBwbGljYXRpb25BcmdzCiAgICBidG9pCiAgICAvLyB0ZXN0cy9hcnRpZmFjdHMvc3RhdGUtb3BzL3N0YXRlLWFjY3QtcGFyYW1zLWdldC1jb250cmFjdC5hbGdvLnRzOjExNwogICAgLy8gY29uc3QgW3ZhbHVlX2luZGV4LCBmdW5kZWRfaW5kZXhdID0gb3AuQWNjdFBhcmFtcy5hY2N0VG90YWxCb3hCeXRlcyhnZXRfMXN0X3JlZl9pbmRleCgpKQogICAgYWNjdF9wYXJhbXNfZ2V0IEFjY3RUb3RhbEJveEJ5dGVzCiAgICAvLyB0ZXN0cy9hcnRpZmFjdHMvc3RhdGUtb3BzL3N0YXRlLWFjY3QtcGFyYW1zLWdldC1jb250cmFjdC5hbGdvLnRzOjExOAogICAgLy8gYXNzZXJ0KHZhbHVlID09PSB2YWx1ZV9pbmRleCwgJ2V4cGVjdGVkIHZhbHVlIGJ5IGluZGV4IHRvIG1hdGNoJykKICAgIGRpZyAzCiAgICB1bmNvdmVyIDIKICAgID09CiAgICBhc3NlcnQgLy8gZXhwZWN0ZWQgdmFsdWUgYnkgaW5kZXggdG8gbWF0Y2gKICAgIC8vIHRlc3RzL2FydGlmYWN0cy9zdGF0ZS1vcHMvc3RhdGUtYWNjdC1wYXJhbXMtZ2V0LWNvbnRyYWN0LmFsZ28udHM6MTE5CiAgICAvLyBhc3NlcnQoZnVuZGVkID09PSBmdW5kZWRfaW5kZXgsICdleHBlY3RlZCBmdW5kZWQgYnkgaW5kZXggdG8gbWF0Y2gnKQogICAgPT0KICAgIGFzc2VydCAvLyBleHBlY3RlZCBmdW5kZWQgYnkgaW5kZXggdG8gbWF0Y2gKICAgIC8vIHRlc3RzL2FydGlmYWN0cy9zdGF0ZS1vcHMvc3RhdGUtYWNjdC1wYXJhbXMtZ2V0LWNvbnRyYWN0LmFsZ28udHM6MTIwCiAgICAvLyByZXR1cm4gdmFsdWUKICAgIHJldHN1YgoKCi8vIHRlc3RzL2FydGlmYWN0cy9zdGF0ZS1vcHMvc3RhdGUtYWNjdC1wYXJhbXMtZ2V0LWNvbnRyYWN0LmFsZ28udHM6OlN0YXRlQWNjdFBhcmFtc0dldENvbnRyYWN0LnZlcmlmeV9hY2N0X2luY2VudGl2ZV9lbGlnaWJsZShhOiBieXRlcykgLT4gdWludDY0Ogp2ZXJpZnlfYWNjdF9pbmNlbnRpdmVfZWxpZ2libGU6CiAgICAvLyB0ZXN0cy9hcnRpZmFjdHMvc3RhdGUtb3BzL3N0YXRlLWFjY3QtcGFyYW1zLWdldC1jb250cmFjdC5hbGdvLnRzOjEyMy0xMjQKICAgIC8vIEBhcmM0LmFiaW1ldGhvZCgpCiAgICAvLyBwdWJsaWMgdmVyaWZ5X2FjY3RfaW5jZW50aXZlX2VsaWdpYmxlKGE6IEFjY291bnQpOiBib29sZWFuIHsKICAgIHByb3RvIDEgMQogICAgLy8gdGVzdHMvYXJ0aWZhY3RzL3N0YXRlLW9wcy9zdGF0ZS1hY2N0LXBhcmFtcy1nZXQtY29udHJhY3QuYWxnby50czoxMjUKICAgIC8vIGNvbnN0IFt2YWx1ZSwgZnVuZGVkXSA9IG9wLkFjY3RQYXJhbXMuYWNjdEluY2VudGl2ZUVsaWdpYmxlKGEpCiAgICBmcmFtZV9kaWcgLTEKICAgIGFjY3RfcGFyYW1zX2dldCBBY2N0SW5jZW50aXZlRWxpZ2libGUKICAgIC8vIHRlc3RzL2FydGlmYWN0cy9zdGF0ZS1vcHMvc3RhdGUtYWNjdC1wYXJhbXMtZ2V0LWNvbnRyYWN0LmFsZ28udHM6NQogICAgLy8gcmV0dXJuIG9wLmJ0b2koVHhuLmFwcGxpY2F0aW9uQXJncygxKSkKICAgIGludGNfMCAvLyAxCiAgICB0eG5hcyBBcHBsaWNhdGlvbkFyZ3MKICAgIGJ0b2kKICAgIC8vIHRlc3RzL2FydGlmYWN0cy9zdGF0ZS1vcHMvc3RhdGUtYWNjdC1wYXJhbXMtZ2V0LWNvbnRyYWN0LmFsZ28udHM6MTI2CiAgICAvLyBjb25zdCBbdmFsdWVfaW5kZXgsIGZ1bmRlZF9pbmRleF0gPSBvcC5BY2N0UGFyYW1zLmFjY3RJbmNlbnRpdmVFbGlnaWJsZShnZXRfMXN0X3JlZl9pbmRleCgpKQogICAgYWNjdF9wYXJhbXNfZ2V0IEFjY3RJbmNlbnRpdmVFbGlnaWJsZQogICAgLy8gdGVzdHMvYXJ0aWZhY3RzL3N0YXRlLW9wcy9zdGF0ZS1hY2N0LXBhcmFtcy1nZXQtY29udHJhY3QuYWxnby50czoxMjcKICAgIC8vIGFzc2VydCh2YWx1ZSA9PT0gdmFsdWVfaW5kZXgsICdleHBlY3RlZCB2YWx1ZSBieSBpbmRleCB0byBtYXRjaCcpCiAgICBkaWcgMwogICAgdW5jb3ZlciAyCiAgICA9PQogICAgYXNzZXJ0IC8vIGV4cGVjdGVkIHZhbHVlIGJ5IGluZGV4IHRvIG1hdGNoCiAgICAvLyB0ZXN0cy9hcnRpZmFjdHMvc3RhdGUtb3BzL3N0YXRlLWFjY3QtcGFyYW1zLWdldC1jb250cmFjdC5hbGdvLnRzOjEyOAogICAgLy8gYXNzZXJ0KGZ1bmRlZCA9PT0gZnVuZGVkX2luZGV4LCAnZXhwZWN0ZWQgZnVuZGVkIGJ5IGluZGV4IHRvIG1hdGNoJykKICAgID09CiAgICBhc3NlcnQgLy8gZXhwZWN0ZWQgZnVuZGVkIGJ5IGluZGV4IHRvIG1hdGNoCiAgICAvLyB0ZXN0cy9hcnRpZmFjdHMvc3RhdGUtb3BzL3N0YXRlLWFjY3QtcGFyYW1zLWdldC1jb250cmFjdC5hbGdvLnRzOjEyOQogICAgLy8gcmV0dXJuIHZhbHVlCiAgICByZXRzdWIK", + "clear": "I3ByYWdtYSB2ZXJzaW9uIDExCiNwcmFnbWEgdHlwZXRyYWNrIGZhbHNlCgovLyBAYWxnb3JhbmRmb3VuZGF0aW9uL2FsZ29yYW5kLXR5cGVzY3JpcHQvYmFzZS1jb250cmFjdC5kLnRzOjpCYXNlQ29udHJhY3QuY2xlYXJTdGF0ZVByb2dyYW0oKSAtPiB1aW50NjQ6Cm1haW46CiAgICBwdXNoaW50IDEgLy8gMQogICAgcmV0dXJuCg==" }, "state": { "global": { @@ -243,6 +248,19 @@ "returns": { "type": "uint64" } + }, + { + "name": "verify_acct_incentive_eligible", + "args": [ + { + "type": "account", + "name": "a" + } + ], + "readonly": false, + "returns": { + "type": "bool" + } } ], "networks": {} diff --git a/tests/artifacts/state-ops/data/StateAcctParamsGetContract.arc56.json b/tests/artifacts/state-ops/data/StateAcctParamsGetContract.arc56.json index 0ad82cf..766444e 100644 --- a/tests/artifacts/state-ops/data/StateAcctParamsGetContract.arc56.json +++ b/tests/artifacts/state-ops/data/StateAcctParamsGetContract.arc56.json @@ -253,6 +253,27 @@ "readonly": false, "events": [], "recommendations": {} + }, + { + "name": "verify_acct_incentive_eligible", + "args": [ + { + "type": "account", + "name": "a" + } + ], + "returns": { + "type": "bool" + }, + "actions": { + "create": [], + "call": [ + "NoOp" + ] + }, + "readonly": false, + "events": [], + "recommendations": {} } ], "arcs": [ @@ -294,117 +315,121 @@ { "pc": [ 120, - 143, - 166, - 188, - 211, - 234, - 257, - 280, - 303, - 326, - 349, - 372 + 149, + 172, + 195, + 218, + 241, + 264, + 287, + 310, + 333, + 356, + 378, + 401 ], "errorMessage": "OnCompletion is not NoOp" }, { "pc": [ - 429, - 482 + 460, + 506 ], "errorMessage": "account funded" }, { "pc": [ - 400 + 429 ], "errorMessage": "can only call when creating" }, { "pc": [ 123, - 146, - 169, - 191, - 214, - 237, - 260, - 283, - 306, - 329, - 352, - 375 + 152, + 175, + 198, + 221, + 244, + 267, + 290, + 313, + 336, + 359, + 381, + 404 ], "errorMessage": "can only call when not creating" }, { "pc": [ - 433 + 464 ], "errorMessage": "expected Account balance to match" }, { "pc": [ - 486 + 510 ], "errorMessage": "expected Account min_balance to match" }, { "pc": [ - 424, - 477, - 522, - 543, - 564, - 585, - 606, - 627, - 648, - 669, - 690, - 711 + 455, + 501, + 544, + 566, + 588, + 610, + 632, + 654, + 676, + 698, + 720, + 742, + 764 ], "errorMessage": "expected funded by index to match" }, { "pc": [ - 448 + 476 ], "errorMessage": "expected op.balance by index to match" }, { "pc": [ - 440 + 471 ], "errorMessage": "expected op.balance to match" }, { "pc": [ - 501 + 522 ], "errorMessage": "expected op.min_balance by index to match" }, { "pc": [ - 493 + 517 ], "errorMessage": "expected op.min_balance to match" }, { "pc": [ - 422, - 475, - 520, - 541, - 562, - 583, - 604, - 625, - 646, - 667, - 688, - 709 + 451, + 497, + 542, + 564, + 586, + 608, + 630, + 652, + 674, + 696, + 718, + 740, + 762 ], "errorMessage": "expected value by index to match" } @@ -417,8 +442,20 @@ } }, "source": { - "approval": "I3ByYWdtYSB2ZXJzaW9uIDEwCgp0ZXN0cy9hcnRpZmFjdHMvc3RhdGUtb3BzL2NvbnRyYWN0LmFsZ28udHM6OlN0YXRlQWNjdFBhcmFtc0dldENvbnRyYWN0LmFwcHJvdmFsUHJvZ3JhbToKICAgIGludGNibG9jayAxIDAKICAgIGJ5dGVjYmxvY2sgMHgxNTFmN2M3NQogICAgY2FsbHN1YiBfX3B1eWFfYXJjNF9yb3V0ZXJfXwogICAgcmV0dXJuCgoKLy8gdGVzdHMvYXJ0aWZhY3RzL3N0YXRlLW9wcy9jb250cmFjdC5hbGdvLnRzOjpTdGF0ZUFjY3RQYXJhbXNHZXRDb250cmFjdC5fX3B1eWFfYXJjNF9yb3V0ZXJfXygpIC0+IHVpbnQ2NDoKX19wdXlhX2FyYzRfcm91dGVyX186CiAgICAvLyB0ZXN0cy9hcnRpZmFjdHMvc3RhdGUtb3BzL2NvbnRyYWN0LmFsZ28udHM6MjYKICAgIC8vIGV4cG9ydCBjbGFzcyBTdGF0ZUFjY3RQYXJhbXNHZXRDb250cmFjdCBleHRlbmRzIGFyYzQuQ29udHJhY3QgewogICAgcHJvdG8gMCAxCiAgICB0eG4gTnVtQXBwQXJncwogICAgYnogX19wdXlhX2FyYzRfcm91dGVyX19fYmFyZV9yb3V0aW5nQDE2CiAgICBwdXNoYnl0ZXNzIDB4NWY1YjQzZTQgMHg3M2RjOTNjNyAweDU2MjZkZmViIDB4ZGM4YTI1YmYgMHgxOThlYmQ4YyAweDIzMDFhYjI2IDB4OWY2OGZjYTYgMHhhOTc1YzJkMSAweGQxZTA0ODAxIDB4YjY5NjZiZTUgMHgxOTVkNTQxOCAweDZhZGFlM2YxIC8vIG1ldGhvZCAidmVyaWZ5X2FjY3RfYmFsYW5jZShhY2NvdW50KXVpbnQ2NCIsIG1ldGhvZCAidmVyaWZ5X2FjY3RfbWluX2JhbGFuY2UoYWNjb3VudCl1aW50NjQiLCBtZXRob2QgInZlcmlmeV9hY2N0X2F1dGhfYWRkcihhY2NvdW50KWFkZHJlc3MiLCBtZXRob2QgInZlcmlmeV9hY2N0X3RvdGFsX251bV91aW50KGFjY291bnQpdWludDY0IiwgbWV0aG9kICJ2ZXJpZnlfYWNjdF90b3RhbF9udW1fYnl0ZV9zbGljZShhY2NvdW50KXVpbnQ2NCIsIG1ldGhvZCAidmVyaWZ5X2FjY3RfdG90YWxfZXh0cmFfYXBwX3BhZ2VzKGFjY291bnQpdWludDY0IiwgbWV0aG9kICJ2ZXJpZnlfYWNjdF90b3RhbF9hcHBzX2NyZWF0ZWQoYWNjb3VudCl1aW50NjQiLCBtZXRob2QgInZlcmlmeV9hY2N0X3RvdGFsX2FwcHNfb3B0ZWRfaW4oYWNjb3VudCl1aW50NjQiLCBtZXRob2QgInZlcmlmeV9hY2N0X3RvdGFsX2Fzc2V0c19jcmVhdGVkKGFjY291bnQpdWludDY0IiwgbWV0aG9kICJ2ZXJpZnlfYWNjdF90b3RhbF9hc3NldHMoYWNjb3VudCl1aW50NjQiLCBtZXRob2QgInZlcmlmeV9hY2N0X3RvdGFsX2JveGVzKGFjY291bnQpdWludDY0IiwgbWV0aG9kICJ2ZXJpZnlfYWNjdF90b3RhbF9ib3hfYnl0ZXMoYWNjb3VudCl1aW50NjQiCiAgICB0eG5hIEFwcGxpY2F0aW9uQXJncyAwCiAgICBtYXRjaCBfX3B1eWFfYXJjNF9yb3V0ZXJfX192ZXJpZnlfYWNjdF9iYWxhbmNlX3JvdXRlQDIgX19wdXlhX2FyYzRfcm91dGVyX19fdmVyaWZ5X2FjY3RfbWluX2JhbGFuY2Vfcm91dGVAMyBfX3B1eWFfYXJjNF9yb3V0ZXJfX192ZXJpZnlfYWNjdF9hdXRoX2FkZHJfcm91dGVANCBfX3B1eWFfYXJjNF9yb3V0ZXJfX192ZXJpZnlfYWNjdF90b3RhbF9udW1fdWludF9yb3V0ZUA1IF9fcHV5YV9hcmM0X3JvdXRlcl9fX3ZlcmlmeV9hY2N0X3RvdGFsX251bV9ieXRlX3NsaWNlX3JvdXRlQDYgX19wdXlhX2FyYzRfcm91dGVyX19fdmVyaWZ5X2FjY3RfdG90YWxfZXh0cmFfYXBwX3BhZ2VzX3JvdXRlQDcgX19wdXlhX2FyYzRfcm91dGVyX19fdmVyaWZ5X2FjY3RfdG90YWxfYXBwc19jcmVhdGVkX3JvdXRlQDggX19wdXlhX2FyYzRfcm91dGVyX19fdmVyaWZ5X2FjY3RfdG90YWxfYXBwc19vcHRlZF9pbl9yb3V0ZUA5IF9fcHV5YV9hcmM0X3JvdXRlcl9fX3ZlcmlmeV9hY2N0X3RvdGFsX2Fzc2V0c19jcmVhdGVkX3JvdXRlQDEwIF9fcHV5YV9hcmM0X3JvdXRlcl9fX3ZlcmlmeV9hY2N0X3RvdGFsX2Fzc2V0c19yb3V0ZUAxMSBfX3B1eWFfYXJjNF9yb3V0ZXJfX192ZXJpZnlfYWNjdF90b3RhbF9ib3hlc19yb3V0ZUAxMiBfX3B1eWFfYXJjNF9yb3V0ZXJfX192ZXJpZnlfYWNjdF90b3RhbF9ib3hfYnl0ZXNfcm91dGVAMTMKICAgIGludGNfMSAvLyAwCiAgICByZXRzdWIKCl9fcHV5YV9hcmM0X3JvdXRlcl9fX3ZlcmlmeV9hY2N0X2JhbGFuY2Vfcm91dGVAMjoKICAgIC8vIHRlc3RzL2FydGlmYWN0cy9zdGF0ZS1vcHMvY29udHJhY3QuYWxnby50czoyNwogICAgLy8gQGFyYzQuYWJpbWV0aG9kKCkKICAgIHR4biBPbkNvbXBsZXRpb24KICAgICEKICAgIGFzc2VydCAvLyBPbkNvbXBsZXRpb24gaXMgbm90IE5vT3AKICAgIHR4biBBcHBsaWNhdGlvbklECiAgICBhc3NlcnQgLy8gY2FuIG9ubHkgY2FsbCB3aGVuIG5vdCBjcmVhdGluZwogICAgLy8gdGVzdHMvYXJ0aWZhY3RzL3N0YXRlLW9wcy9jb250cmFjdC5hbGdvLnRzOjI2CiAgICAvLyBleHBvcnQgY2xhc3MgU3RhdGVBY2N0UGFyYW1zR2V0Q29udHJhY3QgZXh0ZW5kcyBhcmM0LkNvbnRyYWN0IHsKICAgIHR4bmEgQXBwbGljYXRpb25BcmdzIDEKICAgIGJ0b2kKICAgIHR4bmFzIEFjY291bnRzCiAgICAvLyB0ZXN0cy9hcnRpZmFjdHMvc3RhdGUtb3BzL2NvbnRyYWN0LmFsZ28udHM6MjcKICAgIC8vIEBhcmM0LmFiaW1ldGhvZCgpCiAgICBjYWxsc3ViIHZlcmlmeV9hY2N0X2JhbGFuY2UKICAgIGl0b2IKICAgIGJ5dGVjXzAgLy8gMHgxNTFmN2M3NQogICAgc3dhcAogICAgY29uY2F0CiAgICBsb2cKICAgIGludGNfMCAvLyAxCiAgICByZXRzdWIKCl9fcHV5YV9hcmM0X3JvdXRlcl9fX3ZlcmlmeV9hY2N0X21pbl9iYWxhbmNlX3JvdXRlQDM6CiAgICAvLyB0ZXN0cy9hcnRpZmFjdHMvc3RhdGUtb3BzL2NvbnRyYWN0LmFsZ28udHM6MzkKICAgIC8vIEBhcmM0LmFiaW1ldGhvZCgpCiAgICB0eG4gT25Db21wbGV0aW9uCiAgICAhCiAgICBhc3NlcnQgLy8gT25Db21wbGV0aW9uIGlzIG5vdCBOb09wCiAgICB0eG4gQXBwbGljYXRpb25JRAogICAgYXNzZXJ0IC8vIGNhbiBvbmx5IGNhbGwgd2hlbiBub3QgY3JlYXRpbmcKICAgIC8vIHRlc3RzL2FydGlmYWN0cy9zdGF0ZS1vcHMvY29udHJhY3QuYWxnby50czoyNgogICAgLy8gZXhwb3J0IGNsYXNzIFN0YXRlQWNjdFBhcmFtc0dldENvbnRyYWN0IGV4dGVuZHMgYXJjNC5Db250cmFjdCB7CiAgICB0eG5hIEFwcGxpY2F0aW9uQXJncyAxCiAgICBidG9pCiAgICB0eG5hcyBBY2NvdW50cwogICAgLy8gdGVzdHMvYXJ0aWZhY3RzL3N0YXRlLW9wcy9jb250cmFjdC5hbGdvLnRzOjM5CiAgICAvLyBAYXJjNC5hYmltZXRob2QoKQogICAgY2FsbHN1YiB2ZXJpZnlfYWNjdF9taW5fYmFsYW5jZQogICAgaXRvYgogICAgYnl0ZWNfMCAvLyAweDE1MWY3Yzc1CiAgICBzd2FwCiAgICBjb25jYXQKICAgIGxvZwogICAgaW50Y18wIC8vIDEKICAgIHJldHN1YgoKX19wdXlhX2FyYzRfcm91dGVyX19fdmVyaWZ5X2FjY3RfYXV0aF9hZGRyX3JvdXRlQDQ6CiAgICAvLyB0ZXN0cy9hcnRpZmFjdHMvc3RhdGUtb3BzL2NvbnRyYWN0LmFsZ28udHM6NTEKICAgIC8vIEBhcmM0LmFiaW1ldGhvZCgpCiAgICB0eG4gT25Db21wbGV0aW9uCiAgICAhCiAgICBhc3NlcnQgLy8gT25Db21wbGV0aW9uIGlzIG5vdCBOb09wCiAgICB0eG4gQXBwbGljYXRpb25JRAogICAgYXNzZXJ0IC8vIGNhbiBvbmx5IGNhbGwgd2hlbiBub3QgY3JlYXRpbmcKICAgIC8vIHRlc3RzL2FydGlmYWN0cy9zdGF0ZS1vcHMvY29udHJhY3QuYWxnby50czoyNgogICAgLy8gZXhwb3J0IGNsYXNzIFN0YXRlQWNjdFBhcmFtc0dldENvbnRyYWN0IGV4dGVuZHMgYXJjNC5Db250cmFjdCB7CiAgICB0eG5hIEFwcGxpY2F0aW9uQXJncyAxCiAgICBidG9pCiAgICB0eG5hcyBBY2NvdW50cwogICAgLy8gdGVzdHMvYXJ0aWZhY3RzL3N0YXRlLW9wcy9jb250cmFjdC5hbGdvLnRzOjUxCiAgICAvLyBAYXJjNC5hYmltZXRob2QoKQogICAgY2FsbHN1YiB2ZXJpZnlfYWNjdF9hdXRoX2FkZHIKICAgIGJ5dGVjXzAgLy8gMHgxNTFmN2M3NQogICAgc3dhcAogICAgY29uY2F0CiAgICBsb2cKICAgIGludGNfMCAvLyAxCiAgICByZXRzdWIKCl9fcHV5YV9hcmM0X3JvdXRlcl9fX3ZlcmlmeV9hY2N0X3RvdGFsX251bV91aW50X3JvdXRlQDU6CiAgICAvLyB0ZXN0cy9hcnRpZmFjdHMvc3RhdGUtb3BzL2NvbnRyYWN0LmFsZ28udHM6NjAKICAgIC8vIEBhcmM0LmFiaW1ldGhvZCgpCiAgICB0eG4gT25Db21wbGV0aW9uCiAgICAhCiAgICBhc3NlcnQgLy8gT25Db21wbGV0aW9uIGlzIG5vdCBOb09wCiAgICB0eG4gQXBwbGljYXRpb25JRAogICAgYXNzZXJ0IC8vIGNhbiBvbmx5IGNhbGwgd2hlbiBub3QgY3JlYXRpbmcKICAgIC8vIHRlc3RzL2FydGlmYWN0cy9zdGF0ZS1vcHMvY29udHJhY3QuYWxnby50czoyNgogICAgLy8gZXhwb3J0IGNsYXNzIFN0YXRlQWNjdFBhcmFtc0dldENvbnRyYWN0IGV4dGVuZHMgYXJjNC5Db250cmFjdCB7CiAgICB0eG5hIEFwcGxpY2F0aW9uQXJncyAxCiAgICBidG9pCiAgICB0eG5hcyBBY2NvdW50cwogICAgLy8gdGVzdHMvYXJ0aWZhY3RzL3N0YXRlLW9wcy9jb250cmFjdC5hbGdvLnRzOjYwCiAgICAvLyBAYXJjNC5hYmltZXRob2QoKQogICAgY2FsbHN1YiB2ZXJpZnlfYWNjdF90b3RhbF9udW1fdWludAogICAgaXRvYgogICAgYnl0ZWNfMCAvLyAweDE1MWY3Yzc1CiAgICBzd2FwCiAgICBjb25jYXQKICAgIGxvZwogICAgaW50Y18wIC8vIDEKICAgIHJldHN1YgoKX19wdXlhX2FyYzRfcm91dGVyX19fdmVyaWZ5X2FjY3RfdG90YWxfbnVtX2J5dGVfc2xpY2Vfcm91dGVANjoKICAgIC8vIHRlc3RzL2FydGlmYWN0cy9zdGF0ZS1vcHMvY29udHJhY3QuYWxnby50czo2OQogICAgLy8gQGFyYzQuYWJpbWV0aG9kKCkKICAgIHR4biBPbkNvbXBsZXRpb24KICAgICEKICAgIGFzc2VydCAvLyBPbkNvbXBsZXRpb24gaXMgbm90IE5vT3AKICAgIHR4biBBcHBsaWNhdGlvbklECiAgICBhc3NlcnQgLy8gY2FuIG9ubHkgY2FsbCB3aGVuIG5vdCBjcmVhdGluZwogICAgLy8gdGVzdHMvYXJ0aWZhY3RzL3N0YXRlLW9wcy9jb250cmFjdC5hbGdvLnRzOjI2CiAgICAvLyBleHBvcnQgY2xhc3MgU3RhdGVBY2N0UGFyYW1zR2V0Q29udHJhY3QgZXh0ZW5kcyBhcmM0LkNvbnRyYWN0IHsKICAgIHR4bmEgQXBwbGljYXRpb25BcmdzIDEKICAgIGJ0b2kKICAgIHR4bmFzIEFjY291bnRzCiAgICAvLyB0ZXN0cy9hcnRpZmFjdHMvc3RhdGUtb3BzL2NvbnRyYWN0LmFsZ28udHM6NjkKICAgIC8vIEBhcmM0LmFiaW1ldGhvZCgpCiAgICBjYWxsc3ViIHZlcmlmeV9hY2N0X3RvdGFsX251bV9ieXRlX3NsaWNlCiAgICBpdG9iCiAgICBieXRlY18wIC8vIDB4MTUxZjdjNzUKICAgIHN3YXAKICAgIGNvbmNhdAogICAgbG9nCiAgICBpbnRjXzAgLy8gMQogICAgcmV0c3ViCgpfX3B1eWFfYXJjNF9yb3V0ZXJfX192ZXJpZnlfYWNjdF90b3RhbF9leHRyYV9hcHBfcGFnZXNfcm91dGVANzoKICAgIC8vIHRlc3RzL2FydGlmYWN0cy9zdGF0ZS1vcHMvY29udHJhY3QuYWxnby50czo3OAogICAgLy8gQGFyYzQuYWJpbWV0aG9kKCkKICAgIHR4biBPbkNvbXBsZXRpb24KICAgICEKICAgIGFzc2VydCAvLyBPbkNvbXBsZXRpb24gaXMgbm90IE5vT3AKICAgIHR4biBBcHBsaWNhdGlvbklECiAgICBhc3NlcnQgLy8gY2FuIG9ubHkgY2FsbCB3aGVuIG5vdCBjcmVhdGluZwogICAgLy8gdGVzdHMvYXJ0aWZhY3RzL3N0YXRlLW9wcy9jb250cmFjdC5hbGdvLnRzOjI2CiAgICAvLyBleHBvcnQgY2xhc3MgU3RhdGVBY2N0UGFyYW1zR2V0Q29udHJhY3QgZXh0ZW5kcyBhcmM0LkNvbnRyYWN0IHsKICAgIHR4bmEgQXBwbGljYXRpb25BcmdzIDEKICAgIGJ0b2kKICAgIHR4bmFzIEFjY291bnRzCiAgICAvLyB0ZXN0cy9hcnRpZmFjdHMvc3RhdGUtb3BzL2NvbnRyYWN0LmFsZ28udHM6NzgKICAgIC8vIEBhcmM0LmFiaW1ldGhvZCgpCiAgICBjYWxsc3ViIHZlcmlmeV9hY2N0X3RvdGFsX2V4dHJhX2FwcF9wYWdlcwogICAgaXRvYgogICAgYnl0ZWNfMCAvLyAweDE1MWY3Yzc1CiAgICBzd2FwCiAgICBjb25jYXQKICAgIGxvZwogICAgaW50Y18wIC8vIDEKICAgIHJldHN1YgoKX19wdXlhX2FyYzRfcm91dGVyX19fdmVyaWZ5X2FjY3RfdG90YWxfYXBwc19jcmVhdGVkX3JvdXRlQDg6CiAgICAvLyB0ZXN0cy9hcnRpZmFjdHMvc3RhdGUtb3BzL2NvbnRyYWN0LmFsZ28udHM6ODcKICAgIC8vIEBhcmM0LmFiaW1ldGhvZCgpCiAgICB0eG4gT25Db21wbGV0aW9uCiAgICAhCiAgICBhc3NlcnQgLy8gT25Db21wbGV0aW9uIGlzIG5vdCBOb09wCiAgICB0eG4gQXBwbGljYXRpb25JRAogICAgYXNzZXJ0IC8vIGNhbiBvbmx5IGNhbGwgd2hlbiBub3QgY3JlYXRpbmcKICAgIC8vIHRlc3RzL2FydGlmYWN0cy9zdGF0ZS1vcHMvY29udHJhY3QuYWxnby50czoyNgogICAgLy8gZXhwb3J0IGNsYXNzIFN0YXRlQWNjdFBhcmFtc0dldENvbnRyYWN0IGV4dGVuZHMgYXJjNC5Db250cmFjdCB7CiAgICB0eG5hIEFwcGxpY2F0aW9uQXJncyAxCiAgICBidG9pCiAgICB0eG5hcyBBY2NvdW50cwogICAgLy8gdGVzdHMvYXJ0aWZhY3RzL3N0YXRlLW9wcy9jb250cmFjdC5hbGdvLnRzOjg3CiAgICAvLyBAYXJjNC5hYmltZXRob2QoKQogICAgY2FsbHN1YiB2ZXJpZnlfYWNjdF90b3RhbF9hcHBzX2NyZWF0ZWQKICAgIGl0b2IKICAgIGJ5dGVjXzAgLy8gMHgxNTFmN2M3NQogICAgc3dhcAogICAgY29uY2F0CiAgICBsb2cKICAgIGludGNfMCAvLyAxCiAgICByZXRzdWIKCl9fcHV5YV9hcmM0X3JvdXRlcl9fX3ZlcmlmeV9hY2N0X3RvdGFsX2FwcHNfb3B0ZWRfaW5fcm91dGVAOToKICAgIC8vIHRlc3RzL2FydGlmYWN0cy9zdGF0ZS1vcHMvY29udHJhY3QuYWxnby50czo5NgogICAgLy8gQGFyYzQuYWJpbWV0aG9kKCkKICAgIHR4biBPbkNvbXBsZXRpb24KICAgICEKICAgIGFzc2VydCAvLyBPbkNvbXBsZXRpb24gaXMgbm90IE5vT3AKICAgIHR4biBBcHBsaWNhdGlvbklECiAgICBhc3NlcnQgLy8gY2FuIG9ubHkgY2FsbCB3aGVuIG5vdCBjcmVhdGluZwogICAgLy8gdGVzdHMvYXJ0aWZhY3RzL3N0YXRlLW9wcy9jb250cmFjdC5hbGdvLnRzOjI2CiAgICAvLyBleHBvcnQgY2xhc3MgU3RhdGVBY2N0UGFyYW1zR2V0Q29udHJhY3QgZXh0ZW5kcyBhcmM0LkNvbnRyYWN0IHsKICAgIHR4bmEgQXBwbGljYXRpb25BcmdzIDEKICAgIGJ0b2kKICAgIHR4bmFzIEFjY291bnRzCiAgICAvLyB0ZXN0cy9hcnRpZmFjdHMvc3RhdGUtb3BzL2NvbnRyYWN0LmFsZ28udHM6OTYKICAgIC8vIEBhcmM0LmFiaW1ldGhvZCgpCiAgICBjYWxsc3ViIHZlcmlmeV9hY2N0X3RvdGFsX2FwcHNfb3B0ZWRfaW4KICAgIGl0b2IKICAgIGJ5dGVjXzAgLy8gMHgxNTFmN2M3NQogICAgc3dhcAogICAgY29uY2F0CiAgICBsb2cKICAgIGludGNfMCAvLyAxCiAgICByZXRzdWIKCl9fcHV5YV9hcmM0X3JvdXRlcl9fX3ZlcmlmeV9hY2N0X3RvdGFsX2Fzc2V0c19jcmVhdGVkX3JvdXRlQDEwOgogICAgLy8gdGVzdHMvYXJ0aWZhY3RzL3N0YXRlLW9wcy9jb250cmFjdC5hbGdvLnRzOjEwNQogICAgLy8gQGFyYzQuYWJpbWV0aG9kKCkKICAgIHR4biBPbkNvbXBsZXRpb24KICAgICEKICAgIGFzc2VydCAvLyBPbkNvbXBsZXRpb24gaXMgbm90IE5vT3AKICAgIHR4biBBcHBsaWNhdGlvbklECiAgICBhc3NlcnQgLy8gY2FuIG9ubHkgY2FsbCB3aGVuIG5vdCBjcmVhdGluZwogICAgLy8gdGVzdHMvYXJ0aWZhY3RzL3N0YXRlLW9wcy9jb250cmFjdC5hbGdvLnRzOjI2CiAgICAvLyBleHBvcnQgY2xhc3MgU3RhdGVBY2N0UGFyYW1zR2V0Q29udHJhY3QgZXh0ZW5kcyBhcmM0LkNvbnRyYWN0IHsKICAgIHR4bmEgQXBwbGljYXRpb25BcmdzIDEKICAgIGJ0b2kKICAgIHR4bmFzIEFjY291bnRzCiAgICAvLyB0ZXN0cy9hcnRpZmFjdHMvc3RhdGUtb3BzL2NvbnRyYWN0LmFsZ28udHM6MTA1CiAgICAvLyBAYXJjNC5hYmltZXRob2QoKQogICAgY2FsbHN1YiB2ZXJpZnlfYWNjdF90b3RhbF9hc3NldHNfY3JlYXRlZAogICAgaXRvYgogICAgYnl0ZWNfMCAvLyAweDE1MWY3Yzc1CiAgICBzd2FwCiAgICBjb25jYXQKICAgIGxvZwogICAgaW50Y18wIC8vIDEKICAgIHJldHN1YgoKX19wdXlhX2FyYzRfcm91dGVyX19fdmVyaWZ5X2FjY3RfdG90YWxfYXNzZXRzX3JvdXRlQDExOgogICAgLy8gdGVzdHMvYXJ0aWZhY3RzL3N0YXRlLW9wcy9jb250cmFjdC5hbGdvLnRzOjExNAogICAgLy8gQGFyYzQuYWJpbWV0aG9kKCkKICAgIHR4biBPbkNvbXBsZXRpb24KICAgICEKICAgIGFzc2VydCAvLyBPbkNvbXBsZXRpb24gaXMgbm90IE5vT3AKICAgIHR4biBBcHBsaWNhdGlvbklECiAgICBhc3NlcnQgLy8gY2FuIG9ubHkgY2FsbCB3aGVuIG5vdCBjcmVhdGluZwogICAgLy8gdGVzdHMvYXJ0aWZhY3RzL3N0YXRlLW9wcy9jb250cmFjdC5hbGdvLnRzOjI2CiAgICAvLyBleHBvcnQgY2xhc3MgU3RhdGVBY2N0UGFyYW1zR2V0Q29udHJhY3QgZXh0ZW5kcyBhcmM0LkNvbnRyYWN0IHsKICAgIHR4bmEgQXBwbGljYXRpb25BcmdzIDEKICAgIGJ0b2kKICAgIHR4bmFzIEFjY291bnRzCiAgICAvLyB0ZXN0cy9hcnRpZmFjdHMvc3RhdGUtb3BzL2NvbnRyYWN0LmFsZ28udHM6MTE0CiAgICAvLyBAYXJjNC5hYmltZXRob2QoKQogICAgY2FsbHN1YiB2ZXJpZnlfYWNjdF90b3RhbF9hc3NldHMKICAgIGl0b2IKICAgIGJ5dGVjXzAgLy8gMHgxNTFmN2M3NQogICAgc3dhcAogICAgY29uY2F0CiAgICBsb2cKICAgIGludGNfMCAvLyAxCiAgICByZXRzdWIKCl9fcHV5YV9hcmM0X3JvdXRlcl9fX3ZlcmlmeV9hY2N0X3RvdGFsX2JveGVzX3JvdXRlQDEyOgogICAgLy8gdGVzdHMvYXJ0aWZhY3RzL3N0YXRlLW9wcy9jb250cmFjdC5hbGdvLnRzOjEyMwogICAgLy8gQGFyYzQuYWJpbWV0aG9kKCkKICAgIHR4biBPbkNvbXBsZXRpb24KICAgICEKICAgIGFzc2VydCAvLyBPbkNvbXBsZXRpb24gaXMgbm90IE5vT3AKICAgIHR4biBBcHBsaWNhdGlvbklECiAgICBhc3NlcnQgLy8gY2FuIG9ubHkgY2FsbCB3aGVuIG5vdCBjcmVhdGluZwogICAgLy8gdGVzdHMvYXJ0aWZhY3RzL3N0YXRlLW9wcy9jb250cmFjdC5hbGdvLnRzOjI2CiAgICAvLyBleHBvcnQgY2xhc3MgU3RhdGVBY2N0UGFyYW1zR2V0Q29udHJhY3QgZXh0ZW5kcyBhcmM0LkNvbnRyYWN0IHsKICAgIHR4bmEgQXBwbGljYXRpb25BcmdzIDEKICAgIGJ0b2kKICAgIHR4bmFzIEFjY291bnRzCiAgICAvLyB0ZXN0cy9hcnRpZmFjdHMvc3RhdGUtb3BzL2NvbnRyYWN0LmFsZ28udHM6MTIzCiAgICAvLyBAYXJjNC5hYmltZXRob2QoKQogICAgY2FsbHN1YiB2ZXJpZnlfYWNjdF90b3RhbF9ib3hlcwogICAgaXRvYgogICAgYnl0ZWNfMCAvLyAweDE1MWY3Yzc1CiAgICBzd2FwCiAgICBjb25jYXQKICAgIGxvZwogICAgaW50Y18wIC8vIDEKICAgIHJldHN1YgoKX19wdXlhX2FyYzRfcm91dGVyX19fdmVyaWZ5X2FjY3RfdG90YWxfYm94X2J5dGVzX3JvdXRlQDEzOgogICAgLy8gdGVzdHMvYXJ0aWZhY3RzL3N0YXRlLW9wcy9jb250cmFjdC5hbGdvLnRzOjEzMgogICAgLy8gQGFyYzQuYWJpbWV0aG9kKCkKICAgIHR4biBPbkNvbXBsZXRpb24KICAgICEKICAgIGFzc2VydCAvLyBPbkNvbXBsZXRpb24gaXMgbm90IE5vT3AKICAgIHR4biBBcHBsaWNhdGlvbklECiAgICBhc3NlcnQgLy8gY2FuIG9ubHkgY2FsbCB3aGVuIG5vdCBjcmVhdGluZwogICAgLy8gdGVzdHMvYXJ0aWZhY3RzL3N0YXRlLW9wcy9jb250cmFjdC5hbGdvLnRzOjI2CiAgICAvLyBleHBvcnQgY2xhc3MgU3RhdGVBY2N0UGFyYW1zR2V0Q29udHJhY3QgZXh0ZW5kcyBhcmM0LkNvbnRyYWN0IHsKICAgIHR4bmEgQXBwbGljYXRpb25BcmdzIDEKICAgIGJ0b2kKICAgIHR4bmFzIEFjY291bnRzCiAgICAvLyB0ZXN0cy9hcnRpZmFjdHMvc3RhdGUtb3BzL2NvbnRyYWN0LmFsZ28udHM6MTMyCiAgICAvLyBAYXJjNC5hYmltZXRob2QoKQogICAgY2FsbHN1YiB2ZXJpZnlfYWNjdF90b3RhbF9ib3hfYnl0ZXMKICAgIGl0b2IKICAgIGJ5dGVjXzAgLy8gMHgxNTFmN2M3NQogICAgc3dhcAogICAgY29uY2F0CiAgICBsb2cKICAgIGludGNfMCAvLyAxCiAgICByZXRzdWIKCl9fcHV5YV9hcmM0X3JvdXRlcl9fX2JhcmVfcm91dGluZ0AxNjoKICAgIC8vIHRlc3RzL2FydGlmYWN0cy9zdGF0ZS1vcHMvY29udHJhY3QuYWxnby50czoyNgogICAgLy8gZXhwb3J0IGNsYXNzIFN0YXRlQWNjdFBhcmFtc0dldENvbnRyYWN0IGV4dGVuZHMgYXJjNC5Db250cmFjdCB7CiAgICB0eG4gT25Db21wbGV0aW9uCiAgICBibnogX19wdXlhX2FyYzRfcm91dGVyX19fYWZ0ZXJfaWZfZWxzZUAyMAogICAgdHhuIEFwcGxpY2F0aW9uSUQKICAgICEKICAgIGFzc2VydCAvLyBjYW4gb25seSBjYWxsIHdoZW4gY3JlYXRpbmcKICAgIGludGNfMCAvLyAxCiAgICByZXRzdWIKCl9fcHV5YV9hcmM0X3JvdXRlcl9fX2FmdGVyX2lmX2Vsc2VAMjA6CiAgICAvLyB0ZXN0cy9hcnRpZmFjdHMvc3RhdGUtb3BzL2NvbnRyYWN0LmFsZ28udHM6MjYKICAgIC8vIGV4cG9ydCBjbGFzcyBTdGF0ZUFjY3RQYXJhbXNHZXRDb250cmFjdCBleHRlbmRzIGFyYzQuQ29udHJhY3QgewogICAgaW50Y18xIC8vIDAKICAgIHJldHN1YgoKCi8vIHRlc3RzL2FydGlmYWN0cy9zdGF0ZS1vcHMvY29udHJhY3QuYWxnby50czo6U3RhdGVBY2N0UGFyYW1zR2V0Q29udHJhY3QudmVyaWZ5X2FjY3RfYmFsYW5jZShhOiBieXRlcykgLT4gdWludDY0Ogp2ZXJpZnlfYWNjdF9iYWxhbmNlOgogICAgLy8gdGVzdHMvYXJ0aWZhY3RzL3N0YXRlLW9wcy9jb250cmFjdC5hbGdvLnRzOjI3LTI4CiAgICAvLyBAYXJjNC5hYmltZXRob2QoKQogICAgLy8gcHVibGljIHZlcmlmeV9hY2N0X2JhbGFuY2UoYTogQWNjb3VudCk6IHVpbnQ2NCB7CiAgICBwcm90byAxIDEKICAgIC8vIHRlc3RzL2FydGlmYWN0cy9zdGF0ZS1vcHMvY29udHJhY3QuYWxnby50czoyOQogICAgLy8gY29uc3QgW3ZhbHVlLCBmdW5kZWRdID0gb3AuQWNjdFBhcmFtcy5hY2N0QmFsYW5jZShhKQogICAgZnJhbWVfZGlnIC0xCiAgICBhY2N0X3BhcmFtc19nZXQgQWNjdEJhbGFuY2UKICAgIC8vIHRlc3RzL2FydGlmYWN0cy9zdGF0ZS1vcHMvY29udHJhY3QuYWxnby50czozMAogICAgLy8gY29uc3QgW3ZhbHVlX2luZGV4LCBmdW5kZWRfaW5kZXhdID0gb3AuQWNjdFBhcmFtcy5hY2N0QmFsYW5jZShnZXRfMXN0X3JlZl9pbmRleCgpKQogICAgY2FsbHN1YiBnZXRfMXN0X3JlZl9pbmRleAogICAgYWNjdF9wYXJhbXNfZ2V0IEFjY3RCYWxhbmNlCiAgICAvLyB0ZXN0cy9hcnRpZmFjdHMvc3RhdGUtb3BzL2NvbnRyYWN0LmFsZ28udHM6MzEKICAgIC8vIGFzc2VydCh2YWx1ZSA9PT0gdmFsdWVfaW5kZXgsICdleHBlY3RlZCB2YWx1ZSBieSBpbmRleCB0byBtYXRjaCcpCiAgICBkaWcgMwogICAgdW5jb3ZlciAyCiAgICA9PQogICAgYXNzZXJ0IC8vIGV4cGVjdGVkIHZhbHVlIGJ5IGluZGV4IHRvIG1hdGNoCiAgICAvLyB0ZXN0cy9hcnRpZmFjdHMvc3RhdGUtb3BzL2NvbnRyYWN0LmFsZ28udHM6MzIKICAgIC8vIGFzc2VydChmdW5kZWQgPT09IGZ1bmRlZF9pbmRleCwgJ2V4cGVjdGVkIGZ1bmRlZCBieSBpbmRleCB0byBtYXRjaCcpCiAgICA9PQogICAgYXNzZXJ0IC8vIGV4cGVjdGVkIGZ1bmRlZCBieSBpbmRleCB0byBtYXRjaAogICAgLy8gdGVzdHMvYXJ0aWZhY3RzL3N0YXRlLW9wcy9jb250cmFjdC5hbGdvLnRzOjMzCiAgICAvLyBhc3NlcnQodmFsdWUgPT09IGEuYmFsYW5jZSwgJ2V4cGVjdGVkIEFjY291bnQgYmFsYW5jZSB0byBtYXRjaCcpCiAgICBmcmFtZV9kaWcgLTEKICAgIGFjY3RfcGFyYW1zX2dldCBBY2N0QmFsYW5jZQogICAgYXNzZXJ0IC8vIGFjY291bnQgZnVuZGVkCiAgICBkaWcgMQogICAgPT0KICAgIGFzc2VydCAvLyBleHBlY3RlZCBBY2NvdW50IGJhbGFuY2UgdG8gbWF0Y2gKICAgIC8vIHRlc3RzL2FydGlmYWN0cy9zdGF0ZS1vcHMvY29udHJhY3QuYWxnby50czozNAogICAgLy8gYXNzZXJ0KHZhbHVlID09PSBvcC5iYWxhbmNlKGEpLCAnZXhwZWN0ZWQgb3AuYmFsYW5jZSB0byBtYXRjaCcpCiAgICBmcmFtZV9kaWcgLTEKICAgIGJhbGFuY2UKICAgIGRpZyAxCiAgICA9PQogICAgYXNzZXJ0IC8vIGV4cGVjdGVkIG9wLmJhbGFuY2UgdG8gbWF0Y2gKICAgIC8vIHRlc3RzL2FydGlmYWN0cy9zdGF0ZS1vcHMvY29udHJhY3QuYWxnby50czozNQogICAgLy8gYXNzZXJ0KHZhbHVlID09PSBvcC5iYWxhbmNlKGdldF8xc3RfcmVmX2luZGV4KCkpLCAnZXhwZWN0ZWQgb3AuYmFsYW5jZSBieSBpbmRleCB0byBtYXRjaCcpCiAgICBjYWxsc3ViIGdldF8xc3RfcmVmX2luZGV4CiAgICBiYWxhbmNlCiAgICBkaWcgMQogICAgPT0KICAgIGFzc2VydCAvLyBleHBlY3RlZCBvcC5iYWxhbmNlIGJ5IGluZGV4IHRvIG1hdGNoCiAgICAvLyB0ZXN0cy9hcnRpZmFjdHMvc3RhdGUtb3BzL2NvbnRyYWN0LmFsZ28udHM6MzYKICAgIC8vIHJldHVybiB2YWx1ZQogICAgcmV0c3ViCgoKLy8gdGVzdHMvYXJ0aWZhY3RzL3N0YXRlLW9wcy9jb250cmFjdC5hbGdvLnRzOjpnZXRfMXN0X3JlZl9pbmRleCgpIC0+IHVpbnQ2NDoKZ2V0XzFzdF9yZWZfaW5kZXg6CiAgICAvLyB0ZXN0cy9hcnRpZmFjdHMvc3RhdGUtb3BzL2NvbnRyYWN0LmFsZ28udHM6MjIKICAgIC8vIGZ1bmN0aW9uIGdldF8xc3RfcmVmX2luZGV4KCk6IHVpbnQ2NCB7CiAgICBwcm90byAwIDEKICAgIC8vIHRlc3RzL2FydGlmYWN0cy9zdGF0ZS1vcHMvY29udHJhY3QuYWxnby50czoyMwogICAgLy8gcmV0dXJuIG9wLmJ0b2koVHhuLmFwcGxpY2F0aW9uQXJncygxKSkKICAgIGludGNfMCAvLyAxCiAgICB0eG5hcyBBcHBsaWNhdGlvbkFyZ3MKICAgIGJ0b2kKICAgIHJldHN1YgoKCi8vIHRlc3RzL2FydGlmYWN0cy9zdGF0ZS1vcHMvY29udHJhY3QuYWxnby50czo6U3RhdGVBY2N0UGFyYW1zR2V0Q29udHJhY3QudmVyaWZ5X2FjY3RfbWluX2JhbGFuY2UoYTogYnl0ZXMpIC0+IHVpbnQ2NDoKdmVyaWZ5X2FjY3RfbWluX2JhbGFuY2U6CiAgICAvLyB0ZXN0cy9hcnRpZmFjdHMvc3RhdGUtb3BzL2NvbnRyYWN0LmFsZ28udHM6MzktNDAKICAgIC8vIEBhcmM0LmFiaW1ldGhvZCgpCiAgICAvLyBwdWJsaWMgdmVyaWZ5X2FjY3RfbWluX2JhbGFuY2UoYTogQWNjb3VudCk6IHVpbnQ2NCB7CiAgICBwcm90byAxIDEKICAgIC8vIHRlc3RzL2FydGlmYWN0cy9zdGF0ZS1vcHMvY29udHJhY3QuYWxnby50czo0MQogICAgLy8gY29uc3QgW3ZhbHVlLCBmdW5kZWRdID0gb3AuQWNjdFBhcmFtcy5hY2N0TWluQmFsYW5jZShhKQogICAgZnJhbWVfZGlnIC0xCiAgICBhY2N0X3BhcmFtc19nZXQgQWNjdE1pbkJhbGFuY2UKICAgIC8vIHRlc3RzL2FydGlmYWN0cy9zdGF0ZS1vcHMvY29udHJhY3QuYWxnby50czo0MgogICAgLy8gY29uc3QgW3ZhbHVlX2luZGV4LCBmdW5kZWRfaW5kZXhdID0gb3AuQWNjdFBhcmFtcy5hY2N0TWluQmFsYW5jZShnZXRfMXN0X3JlZl9pbmRleCgpKQogICAgY2FsbHN1YiBnZXRfMXN0X3JlZl9pbmRleAogICAgYWNjdF9wYXJhbXNfZ2V0IEFjY3RNaW5CYWxhbmNlCiAgICAvLyB0ZXN0cy9hcnRpZmFjdHMvc3RhdGUtb3BzL2NvbnRyYWN0LmFsZ28udHM6NDMKICAgIC8vIGFzc2VydCh2YWx1ZSA9PT0gdmFsdWVfaW5kZXgsICdleHBlY3RlZCB2YWx1ZSBieSBpbmRleCB0byBtYXRjaCcpCiAgICBkaWcgMwogICAgdW5jb3ZlciAyCiAgICA9PQogICAgYXNzZXJ0IC8vIGV4cGVjdGVkIHZhbHVlIGJ5IGluZGV4IHRvIG1hdGNoCiAgICAvLyB0ZXN0cy9hcnRpZmFjdHMvc3RhdGUtb3BzL2NvbnRyYWN0LmFsZ28udHM6NDQKICAgIC8vIGFzc2VydChmdW5kZWQgPT09IGZ1bmRlZF9pbmRleCwgJ2V4cGVjdGVkIGZ1bmRlZCBieSBpbmRleCB0byBtYXRjaCcpCiAgICA9PQogICAgYXNzZXJ0IC8vIGV4cGVjdGVkIGZ1bmRlZCBieSBpbmRleCB0byBtYXRjaAogICAgLy8gdGVzdHMvYXJ0aWZhY3RzL3N0YXRlLW9wcy9jb250cmFjdC5hbGdvLnRzOjQ1CiAgICAvLyBhc3NlcnQodmFsdWUgPT09IGEubWluQmFsYW5jZSwgJ2V4cGVjdGVkIEFjY291bnQgbWluX2JhbGFuY2UgdG8gbWF0Y2gnKQogICAgZnJhbWVfZGlnIC0xCiAgICBhY2N0X3BhcmFtc19nZXQgQWNjdE1pbkJhbGFuY2UKICAgIGFzc2VydCAvLyBhY2NvdW50IGZ1bmRlZAogICAgZGlnIDEKICAgID09CiAgICBhc3NlcnQgLy8gZXhwZWN0ZWQgQWNjb3VudCBtaW5fYmFsYW5jZSB0byBtYXRjaAogICAgLy8gdGVzdHMvYXJ0aWZhY3RzL3N0YXRlLW9wcy9jb250cmFjdC5hbGdvLnRzOjQ2CiAgICAvLyBhc3NlcnQodmFsdWUgPT09IG9wLm1pbkJhbGFuY2UoYSksICdleHBlY3RlZCBvcC5taW5fYmFsYW5jZSB0byBtYXRjaCcpCiAgICBmcmFtZV9kaWcgLTEKICAgIG1pbl9iYWxhbmNlCiAgICBkaWcgMQogICAgPT0KICAgIGFzc2VydCAvLyBleHBlY3RlZCBvcC5taW5fYmFsYW5jZSB0byBtYXRjaAogICAgLy8gdGVzdHMvYXJ0aWZhY3RzL3N0YXRlLW9wcy9jb250cmFjdC5hbGdvLnRzOjQ3CiAgICAvLyBhc3NlcnQodmFsdWUgPT09IG9wLm1pbkJhbGFuY2UoZ2V0XzFzdF9yZWZfaW5kZXgoKSksICdleHBlY3RlZCBvcC5taW5fYmFsYW5jZSBieSBpbmRleCB0byBtYXRjaCcpCiAgICBjYWxsc3ViIGdldF8xc3RfcmVmX2luZGV4CiAgICBtaW5fYmFsYW5jZQogICAgZGlnIDEKICAgID09CiAgICBhc3NlcnQgLy8gZXhwZWN0ZWQgb3AubWluX2JhbGFuY2UgYnkgaW5kZXggdG8gbWF0Y2gKICAgIC8vIHRlc3RzL2FydGlmYWN0cy9zdGF0ZS1vcHMvY29udHJhY3QuYWxnby50czo0OAogICAgLy8gcmV0dXJuIHZhbHVlCiAgICByZXRzdWIKCgovLyB0ZXN0cy9hcnRpZmFjdHMvc3RhdGUtb3BzL2NvbnRyYWN0LmFsZ28udHM6OlN0YXRlQWNjdFBhcmFtc0dldENvbnRyYWN0LnZlcmlmeV9hY2N0X2F1dGhfYWRkcihhOiBieXRlcykgLT4gYnl0ZXM6CnZlcmlmeV9hY2N0X2F1dGhfYWRkcjoKICAgIC8vIHRlc3RzL2FydGlmYWN0cy9zdGF0ZS1vcHMvY29udHJhY3QuYWxnby50czo1MS01MgogICAgLy8gQGFyYzQuYWJpbWV0aG9kKCkKICAgIC8vIHB1YmxpYyB2ZXJpZnlfYWNjdF9hdXRoX2FkZHIoYTogQWNjb3VudCk6IEFkZHJlc3MgewogICAgcHJvdG8gMSAxCiAgICAvLyB0ZXN0cy9hcnRpZmFjdHMvc3RhdGUtb3BzL2NvbnRyYWN0LmFsZ28udHM6NTMKICAgIC8vIGNvbnN0IFt2YWx1ZSwgZnVuZGVkXSA9IG9wLkFjY3RQYXJhbXMuYWNjdEF1dGhBZGRyKGEpCiAgICBmcmFtZV9kaWcgLTEKICAgIGFjY3RfcGFyYW1zX2dldCBBY2N0QXV0aEFkZHIKICAgIC8vIHRlc3RzL2FydGlmYWN0cy9zdGF0ZS1vcHMvY29udHJhY3QuYWxnby50czo1NAogICAgLy8gY29uc3QgW3ZhbHVlX2luZGV4LCBmdW5kZWRfaW5kZXhdID0gb3AuQWNjdFBhcmFtcy5hY2N0QXV0aEFkZHIoZ2V0XzFzdF9yZWZfaW5kZXgoKSkKICAgIGNhbGxzdWIgZ2V0XzFzdF9yZWZfaW5kZXgKICAgIGFjY3RfcGFyYW1zX2dldCBBY2N0QXV0aEFkZHIKICAgIC8vIHRlc3RzL2FydGlmYWN0cy9zdGF0ZS1vcHMvY29udHJhY3QuYWxnby50czo1NQogICAgLy8gYXNzZXJ0KHZhbHVlID09PSB2YWx1ZV9pbmRleCwgJ2V4cGVjdGVkIHZhbHVlIGJ5IGluZGV4IHRvIG1hdGNoJykKICAgIGRpZyAzCiAgICB1bmNvdmVyIDIKICAgID09CiAgICBhc3NlcnQgLy8gZXhwZWN0ZWQgdmFsdWUgYnkgaW5kZXggdG8gbWF0Y2gKICAgIC8vIHRlc3RzL2FydGlmYWN0cy9zdGF0ZS1vcHMvY29udHJhY3QuYWxnby50czo1NgogICAgLy8gYXNzZXJ0KGZ1bmRlZCA9PT0gZnVuZGVkX2luZGV4LCAnZXhwZWN0ZWQgZnVuZGVkIGJ5IGluZGV4IHRvIG1hdGNoJykKICAgID09CiAgICBhc3NlcnQgLy8gZXhwZWN0ZWQgZnVuZGVkIGJ5IGluZGV4IHRvIG1hdGNoCiAgICAvLyB0ZXN0cy9hcnRpZmFjdHMvc3RhdGUtb3BzL2NvbnRyYWN0LmFsZ28udHM6NTcKICAgIC8vIHJldHVybiBuZXcgQWRkcmVzcyh2YWx1ZSkKICAgIHJldHN1YgoKCi8vIHRlc3RzL2FydGlmYWN0cy9zdGF0ZS1vcHMvY29udHJhY3QuYWxnby50czo6U3RhdGVBY2N0UGFyYW1zR2V0Q29udHJhY3QudmVyaWZ5X2FjY3RfdG90YWxfbnVtX3VpbnQoYTogYnl0ZXMpIC0+IHVpbnQ2NDoKdmVyaWZ5X2FjY3RfdG90YWxfbnVtX3VpbnQ6CiAgICAvLyB0ZXN0cy9hcnRpZmFjdHMvc3RhdGUtb3BzL2NvbnRyYWN0LmFsZ28udHM6NjAtNjEKICAgIC8vIEBhcmM0LmFiaW1ldGhvZCgpCiAgICAvLyBwdWJsaWMgdmVyaWZ5X2FjY3RfdG90YWxfbnVtX3VpbnQoYTogQWNjb3VudCk6IHVpbnQ2NCB7CiAgICBwcm90byAxIDEKICAgIC8vIHRlc3RzL2FydGlmYWN0cy9zdGF0ZS1vcHMvY29udHJhY3QuYWxnby50czo2MgogICAgLy8gY29uc3QgW3ZhbHVlLCBmdW5kZWRdID0gb3AuQWNjdFBhcmFtcy5hY2N0VG90YWxOdW1VaW50KGEpCiAgICBmcmFtZV9kaWcgLTEKICAgIGFjY3RfcGFyYW1zX2dldCBBY2N0VG90YWxOdW1VaW50CiAgICAvLyB0ZXN0cy9hcnRpZmFjdHMvc3RhdGUtb3BzL2NvbnRyYWN0LmFsZ28udHM6NjMKICAgIC8vIGNvbnN0IFt2YWx1ZV9pbmRleCwgZnVuZGVkX2luZGV4XSA9IG9wLkFjY3RQYXJhbXMuYWNjdFRvdGFsTnVtVWludChnZXRfMXN0X3JlZl9pbmRleCgpKQogICAgY2FsbHN1YiBnZXRfMXN0X3JlZl9pbmRleAogICAgYWNjdF9wYXJhbXNfZ2V0IEFjY3RUb3RhbE51bVVpbnQKICAgIC8vIHRlc3RzL2FydGlmYWN0cy9zdGF0ZS1vcHMvY29udHJhY3QuYWxnby50czo2NAogICAgLy8gYXNzZXJ0KHZhbHVlID09PSB2YWx1ZV9pbmRleCwgJ2V4cGVjdGVkIHZhbHVlIGJ5IGluZGV4IHRvIG1hdGNoJykKICAgIGRpZyAzCiAgICB1bmNvdmVyIDIKICAgID09CiAgICBhc3NlcnQgLy8gZXhwZWN0ZWQgdmFsdWUgYnkgaW5kZXggdG8gbWF0Y2gKICAgIC8vIHRlc3RzL2FydGlmYWN0cy9zdGF0ZS1vcHMvY29udHJhY3QuYWxnby50czo2NQogICAgLy8gYXNzZXJ0KGZ1bmRlZCA9PT0gZnVuZGVkX2luZGV4LCAnZXhwZWN0ZWQgZnVuZGVkIGJ5IGluZGV4IHRvIG1hdGNoJykKICAgID09CiAgICBhc3NlcnQgLy8gZXhwZWN0ZWQgZnVuZGVkIGJ5IGluZGV4IHRvIG1hdGNoCiAgICAvLyB0ZXN0cy9hcnRpZmFjdHMvc3RhdGUtb3BzL2NvbnRyYWN0LmFsZ28udHM6NjYKICAgIC8vIHJldHVybiB2YWx1ZQogICAgcmV0c3ViCgoKLy8gdGVzdHMvYXJ0aWZhY3RzL3N0YXRlLW9wcy9jb250cmFjdC5hbGdvLnRzOjpTdGF0ZUFjY3RQYXJhbXNHZXRDb250cmFjdC52ZXJpZnlfYWNjdF90b3RhbF9udW1fYnl0ZV9zbGljZShhOiBieXRlcykgLT4gdWludDY0Ogp2ZXJpZnlfYWNjdF90b3RhbF9udW1fYnl0ZV9zbGljZToKICAgIC8vIHRlc3RzL2FydGlmYWN0cy9zdGF0ZS1vcHMvY29udHJhY3QuYWxnby50czo2OS03MAogICAgLy8gQGFyYzQuYWJpbWV0aG9kKCkKICAgIC8vIHB1YmxpYyB2ZXJpZnlfYWNjdF90b3RhbF9udW1fYnl0ZV9zbGljZShhOiBBY2NvdW50KTogdWludDY0IHsKICAgIHByb3RvIDEgMQogICAgLy8gdGVzdHMvYXJ0aWZhY3RzL3N0YXRlLW9wcy9jb250cmFjdC5hbGdvLnRzOjcxCiAgICAvLyBjb25zdCBbdmFsdWUsIGZ1bmRlZF0gPSBvcC5BY2N0UGFyYW1zLmFjY3RUb3RhbE51bUJ5dGVTbGljZShhKQogICAgZnJhbWVfZGlnIC0xCiAgICBhY2N0X3BhcmFtc19nZXQgQWNjdFRvdGFsTnVtQnl0ZVNsaWNlCiAgICAvLyB0ZXN0cy9hcnRpZmFjdHMvc3RhdGUtb3BzL2NvbnRyYWN0LmFsZ28udHM6NzIKICAgIC8vIGNvbnN0IFt2YWx1ZV9pbmRleCwgZnVuZGVkX2luZGV4XSA9IG9wLkFjY3RQYXJhbXMuYWNjdFRvdGFsTnVtQnl0ZVNsaWNlKGdldF8xc3RfcmVmX2luZGV4KCkpCiAgICBjYWxsc3ViIGdldF8xc3RfcmVmX2luZGV4CiAgICBhY2N0X3BhcmFtc19nZXQgQWNjdFRvdGFsTnVtQnl0ZVNsaWNlCiAgICAvLyB0ZXN0cy9hcnRpZmFjdHMvc3RhdGUtb3BzL2NvbnRyYWN0LmFsZ28udHM6NzMKICAgIC8vIGFzc2VydCh2YWx1ZSA9PT0gdmFsdWVfaW5kZXgsICdleHBlY3RlZCB2YWx1ZSBieSBpbmRleCB0byBtYXRjaCcpCiAgICBkaWcgMwogICAgdW5jb3ZlciAyCiAgICA9PQogICAgYXNzZXJ0IC8vIGV4cGVjdGVkIHZhbHVlIGJ5IGluZGV4IHRvIG1hdGNoCiAgICAvLyB0ZXN0cy9hcnRpZmFjdHMvc3RhdGUtb3BzL2NvbnRyYWN0LmFsZ28udHM6NzQKICAgIC8vIGFzc2VydChmdW5kZWQgPT09IGZ1bmRlZF9pbmRleCwgJ2V4cGVjdGVkIGZ1bmRlZCBieSBpbmRleCB0byBtYXRjaCcpCiAgICA9PQogICAgYXNzZXJ0IC8vIGV4cGVjdGVkIGZ1bmRlZCBieSBpbmRleCB0byBtYXRjaAogICAgLy8gdGVzdHMvYXJ0aWZhY3RzL3N0YXRlLW9wcy9jb250cmFjdC5hbGdvLnRzOjc1CiAgICAvLyByZXR1cm4gdmFsdWUKICAgIHJldHN1YgoKCi8vIHRlc3RzL2FydGlmYWN0cy9zdGF0ZS1vcHMvY29udHJhY3QuYWxnby50czo6U3RhdGVBY2N0UGFyYW1zR2V0Q29udHJhY3QudmVyaWZ5X2FjY3RfdG90YWxfZXh0cmFfYXBwX3BhZ2VzKGE6IGJ5dGVzKSAtPiB1aW50NjQ6CnZlcmlmeV9hY2N0X3RvdGFsX2V4dHJhX2FwcF9wYWdlczoKICAgIC8vIHRlc3RzL2FydGlmYWN0cy9zdGF0ZS1vcHMvY29udHJhY3QuYWxnby50czo3OC03OQogICAgLy8gQGFyYzQuYWJpbWV0aG9kKCkKICAgIC8vIHB1YmxpYyB2ZXJpZnlfYWNjdF90b3RhbF9leHRyYV9hcHBfcGFnZXMoYTogQWNjb3VudCk6IHVpbnQ2NCB7CiAgICBwcm90byAxIDEKICAgIC8vIHRlc3RzL2FydGlmYWN0cy9zdGF0ZS1vcHMvY29udHJhY3QuYWxnby50czo4MAogICAgLy8gY29uc3QgW3ZhbHVlLCBmdW5kZWRdID0gb3AuQWNjdFBhcmFtcy5hY2N0VG90YWxFeHRyYUFwcFBhZ2VzKGEpCiAgICBmcmFtZV9kaWcgLTEKICAgIGFjY3RfcGFyYW1zX2dldCBBY2N0VG90YWxFeHRyYUFwcFBhZ2VzCiAgICAvLyB0ZXN0cy9hcnRpZmFjdHMvc3RhdGUtb3BzL2NvbnRyYWN0LmFsZ28udHM6ODEKICAgIC8vIGNvbnN0IFt2YWx1ZV9pbmRleCwgZnVuZGVkX2luZGV4XSA9IG9wLkFjY3RQYXJhbXMuYWNjdFRvdGFsRXh0cmFBcHBQYWdlcyhnZXRfMXN0X3JlZl9pbmRleCgpKQogICAgY2FsbHN1YiBnZXRfMXN0X3JlZl9pbmRleAogICAgYWNjdF9wYXJhbXNfZ2V0IEFjY3RUb3RhbEV4dHJhQXBwUGFnZXMKICAgIC8vIHRlc3RzL2FydGlmYWN0cy9zdGF0ZS1vcHMvY29udHJhY3QuYWxnby50czo4MgogICAgLy8gYXNzZXJ0KHZhbHVlID09PSB2YWx1ZV9pbmRleCwgJ2V4cGVjdGVkIHZhbHVlIGJ5IGluZGV4IHRvIG1hdGNoJykKICAgIGRpZyAzCiAgICB1bmNvdmVyIDIKICAgID09CiAgICBhc3NlcnQgLy8gZXhwZWN0ZWQgdmFsdWUgYnkgaW5kZXggdG8gbWF0Y2gKICAgIC8vIHRlc3RzL2FydGlmYWN0cy9zdGF0ZS1vcHMvY29udHJhY3QuYWxnby50czo4MwogICAgLy8gYXNzZXJ0KGZ1bmRlZCA9PT0gZnVuZGVkX2luZGV4LCAnZXhwZWN0ZWQgZnVuZGVkIGJ5IGluZGV4IHRvIG1hdGNoJykKICAgID09CiAgICBhc3NlcnQgLy8gZXhwZWN0ZWQgZnVuZGVkIGJ5IGluZGV4IHRvIG1hdGNoCiAgICAvLyB0ZXN0cy9hcnRpZmFjdHMvc3RhdGUtb3BzL2NvbnRyYWN0LmFsZ28udHM6ODQKICAgIC8vIHJldHVybiB2YWx1ZQogICAgcmV0c3ViCgoKLy8gdGVzdHMvYXJ0aWZhY3RzL3N0YXRlLW9wcy9jb250cmFjdC5hbGdvLnRzOjpTdGF0ZUFjY3RQYXJhbXNHZXRDb250cmFjdC52ZXJpZnlfYWNjdF90b3RhbF9hcHBzX2NyZWF0ZWQoYTogYnl0ZXMpIC0+IHVpbnQ2NDoKdmVyaWZ5X2FjY3RfdG90YWxfYXBwc19jcmVhdGVkOgogICAgLy8gdGVzdHMvYXJ0aWZhY3RzL3N0YXRlLW9wcy9jb250cmFjdC5hbGdvLnRzOjg3LTg4CiAgICAvLyBAYXJjNC5hYmltZXRob2QoKQogICAgLy8gcHVibGljIHZlcmlmeV9hY2N0X3RvdGFsX2FwcHNfY3JlYXRlZChhOiBBY2NvdW50KTogdWludDY0IHsKICAgIHByb3RvIDEgMQogICAgLy8gdGVzdHMvYXJ0aWZhY3RzL3N0YXRlLW9wcy9jb250cmFjdC5hbGdvLnRzOjg5CiAgICAvLyBjb25zdCBbdmFsdWUsIGZ1bmRlZF0gPSBvcC5BY2N0UGFyYW1zLmFjY3RUb3RhbEFwcHNDcmVhdGVkKGEpCiAgICBmcmFtZV9kaWcgLTEKICAgIGFjY3RfcGFyYW1zX2dldCBBY2N0VG90YWxBcHBzQ3JlYXRlZAogICAgLy8gdGVzdHMvYXJ0aWZhY3RzL3N0YXRlLW9wcy9jb250cmFjdC5hbGdvLnRzOjkwCiAgICAvLyBjb25zdCBbdmFsdWVfaW5kZXgsIGZ1bmRlZF9pbmRleF0gPSBvcC5BY2N0UGFyYW1zLmFjY3RUb3RhbEFwcHNDcmVhdGVkKGdldF8xc3RfcmVmX2luZGV4KCkpCiAgICBjYWxsc3ViIGdldF8xc3RfcmVmX2luZGV4CiAgICBhY2N0X3BhcmFtc19nZXQgQWNjdFRvdGFsQXBwc0NyZWF0ZWQKICAgIC8vIHRlc3RzL2FydGlmYWN0cy9zdGF0ZS1vcHMvY29udHJhY3QuYWxnby50czo5MQogICAgLy8gYXNzZXJ0KHZhbHVlID09PSB2YWx1ZV9pbmRleCwgJ2V4cGVjdGVkIHZhbHVlIGJ5IGluZGV4IHRvIG1hdGNoJykKICAgIGRpZyAzCiAgICB1bmNvdmVyIDIKICAgID09CiAgICBhc3NlcnQgLy8gZXhwZWN0ZWQgdmFsdWUgYnkgaW5kZXggdG8gbWF0Y2gKICAgIC8vIHRlc3RzL2FydGlmYWN0cy9zdGF0ZS1vcHMvY29udHJhY3QuYWxnby50czo5MgogICAgLy8gYXNzZXJ0KGZ1bmRlZCA9PT0gZnVuZGVkX2luZGV4LCAnZXhwZWN0ZWQgZnVuZGVkIGJ5IGluZGV4IHRvIG1hdGNoJykKICAgID09CiAgICBhc3NlcnQgLy8gZXhwZWN0ZWQgZnVuZGVkIGJ5IGluZGV4IHRvIG1hdGNoCiAgICAvLyB0ZXN0cy9hcnRpZmFjdHMvc3RhdGUtb3BzL2NvbnRyYWN0LmFsZ28udHM6OTMKICAgIC8vIHJldHVybiB2YWx1ZQogICAgcmV0c3ViCgoKLy8gdGVzdHMvYXJ0aWZhY3RzL3N0YXRlLW9wcy9jb250cmFjdC5hbGdvLnRzOjpTdGF0ZUFjY3RQYXJhbXNHZXRDb250cmFjdC52ZXJpZnlfYWNjdF90b3RhbF9hcHBzX29wdGVkX2luKGE6IGJ5dGVzKSAtPiB1aW50NjQ6CnZlcmlmeV9hY2N0X3RvdGFsX2FwcHNfb3B0ZWRfaW46CiAgICAvLyB0ZXN0cy9hcnRpZmFjdHMvc3RhdGUtb3BzL2NvbnRyYWN0LmFsZ28udHM6OTYtOTcKICAgIC8vIEBhcmM0LmFiaW1ldGhvZCgpCiAgICAvLyBwdWJsaWMgdmVyaWZ5X2FjY3RfdG90YWxfYXBwc19vcHRlZF9pbihhOiBBY2NvdW50KTogdWludDY0IHsKICAgIHByb3RvIDEgMQogICAgLy8gdGVzdHMvYXJ0aWZhY3RzL3N0YXRlLW9wcy9jb250cmFjdC5hbGdvLnRzOjk4CiAgICAvLyBjb25zdCBbdmFsdWUsIGZ1bmRlZF0gPSBvcC5BY2N0UGFyYW1zLmFjY3RUb3RhbEFwcHNPcHRlZEluKGEpCiAgICBmcmFtZV9kaWcgLTEKICAgIGFjY3RfcGFyYW1zX2dldCBBY2N0VG90YWxBcHBzT3B0ZWRJbgogICAgLy8gdGVzdHMvYXJ0aWZhY3RzL3N0YXRlLW9wcy9jb250cmFjdC5hbGdvLnRzOjk5CiAgICAvLyBjb25zdCBbdmFsdWVfaW5kZXgsIGZ1bmRlZF9pbmRleF0gPSBvcC5BY2N0UGFyYW1zLmFjY3RUb3RhbEFwcHNPcHRlZEluKGdldF8xc3RfcmVmX2luZGV4KCkpCiAgICBjYWxsc3ViIGdldF8xc3RfcmVmX2luZGV4CiAgICBhY2N0X3BhcmFtc19nZXQgQWNjdFRvdGFsQXBwc09wdGVkSW4KICAgIC8vIHRlc3RzL2FydGlmYWN0cy9zdGF0ZS1vcHMvY29udHJhY3QuYWxnby50czoxMDAKICAgIC8vIGFzc2VydCh2YWx1ZSA9PT0gdmFsdWVfaW5kZXgsICdleHBlY3RlZCB2YWx1ZSBieSBpbmRleCB0byBtYXRjaCcpCiAgICBkaWcgMwogICAgdW5jb3ZlciAyCiAgICA9PQogICAgYXNzZXJ0IC8vIGV4cGVjdGVkIHZhbHVlIGJ5IGluZGV4IHRvIG1hdGNoCiAgICAvLyB0ZXN0cy9hcnRpZmFjdHMvc3RhdGUtb3BzL2NvbnRyYWN0LmFsZ28udHM6MTAxCiAgICAvLyBhc3NlcnQoZnVuZGVkID09PSBmdW5kZWRfaW5kZXgsICdleHBlY3RlZCBmdW5kZWQgYnkgaW5kZXggdG8gbWF0Y2gnKQogICAgPT0KICAgIGFzc2VydCAvLyBleHBlY3RlZCBmdW5kZWQgYnkgaW5kZXggdG8gbWF0Y2gKICAgIC8vIHRlc3RzL2FydGlmYWN0cy9zdGF0ZS1vcHMvY29udHJhY3QuYWxnby50czoxMDIKICAgIC8vIHJldHVybiB2YWx1ZQogICAgcmV0c3ViCgoKLy8gdGVzdHMvYXJ0aWZhY3RzL3N0YXRlLW9wcy9jb250cmFjdC5hbGdvLnRzOjpTdGF0ZUFjY3RQYXJhbXNHZXRDb250cmFjdC52ZXJpZnlfYWNjdF90b3RhbF9hc3NldHNfY3JlYXRlZChhOiBieXRlcykgLT4gdWludDY0Ogp2ZXJpZnlfYWNjdF90b3RhbF9hc3NldHNfY3JlYXRlZDoKICAgIC8vIHRlc3RzL2FydGlmYWN0cy9zdGF0ZS1vcHMvY29udHJhY3QuYWxnby50czoxMDUtMTA2CiAgICAvLyBAYXJjNC5hYmltZXRob2QoKQogICAgLy8gcHVibGljIHZlcmlmeV9hY2N0X3RvdGFsX2Fzc2V0c19jcmVhdGVkKGE6IEFjY291bnQpOiB1aW50NjQgewogICAgcHJvdG8gMSAxCiAgICAvLyB0ZXN0cy9hcnRpZmFjdHMvc3RhdGUtb3BzL2NvbnRyYWN0LmFsZ28udHM6MTA3CiAgICAvLyBjb25zdCBbdmFsdWUsIGZ1bmRlZF0gPSBvcC5BY2N0UGFyYW1zLmFjY3RUb3RhbEFzc2V0c0NyZWF0ZWQoYSkKICAgIGZyYW1lX2RpZyAtMQogICAgYWNjdF9wYXJhbXNfZ2V0IEFjY3RUb3RhbEFzc2V0c0NyZWF0ZWQKICAgIC8vIHRlc3RzL2FydGlmYWN0cy9zdGF0ZS1vcHMvY29udHJhY3QuYWxnby50czoxMDgKICAgIC8vIGNvbnN0IFt2YWx1ZV9pbmRleCwgZnVuZGVkX2luZGV4XSA9IG9wLkFjY3RQYXJhbXMuYWNjdFRvdGFsQXNzZXRzQ3JlYXRlZChnZXRfMXN0X3JlZl9pbmRleCgpKQogICAgY2FsbHN1YiBnZXRfMXN0X3JlZl9pbmRleAogICAgYWNjdF9wYXJhbXNfZ2V0IEFjY3RUb3RhbEFzc2V0c0NyZWF0ZWQKICAgIC8vIHRlc3RzL2FydGlmYWN0cy9zdGF0ZS1vcHMvY29udHJhY3QuYWxnby50czoxMDkKICAgIC8vIGFzc2VydCh2YWx1ZSA9PT0gdmFsdWVfaW5kZXgsICdleHBlY3RlZCB2YWx1ZSBieSBpbmRleCB0byBtYXRjaCcpCiAgICBkaWcgMwogICAgdW5jb3ZlciAyCiAgICA9PQogICAgYXNzZXJ0IC8vIGV4cGVjdGVkIHZhbHVlIGJ5IGluZGV4IHRvIG1hdGNoCiAgICAvLyB0ZXN0cy9hcnRpZmFjdHMvc3RhdGUtb3BzL2NvbnRyYWN0LmFsZ28udHM6MTEwCiAgICAvLyBhc3NlcnQoZnVuZGVkID09PSBmdW5kZWRfaW5kZXgsICdleHBlY3RlZCBmdW5kZWQgYnkgaW5kZXggdG8gbWF0Y2gnKQogICAgPT0KICAgIGFzc2VydCAvLyBleHBlY3RlZCBmdW5kZWQgYnkgaW5kZXggdG8gbWF0Y2gKICAgIC8vIHRlc3RzL2FydGlmYWN0cy9zdGF0ZS1vcHMvY29udHJhY3QuYWxnby50czoxMTEKICAgIC8vIHJldHVybiB2YWx1ZQogICAgcmV0c3ViCgoKLy8gdGVzdHMvYXJ0aWZhY3RzL3N0YXRlLW9wcy9jb250cmFjdC5hbGdvLnRzOjpTdGF0ZUFjY3RQYXJhbXNHZXRDb250cmFjdC52ZXJpZnlfYWNjdF90b3RhbF9hc3NldHMoYTogYnl0ZXMpIC0+IHVpbnQ2NDoKdmVyaWZ5X2FjY3RfdG90YWxfYXNzZXRzOgogICAgLy8gdGVzdHMvYXJ0aWZhY3RzL3N0YXRlLW9wcy9jb250cmFjdC5hbGdvLnRzOjExNC0xMTUKICAgIC8vIEBhcmM0LmFiaW1ldGhvZCgpCiAgICAvLyBwdWJsaWMgdmVyaWZ5X2FjY3RfdG90YWxfYXNzZXRzKGE6IEFjY291bnQpOiB1aW50NjQgewogICAgcHJvdG8gMSAxCiAgICAvLyB0ZXN0cy9hcnRpZmFjdHMvc3RhdGUtb3BzL2NvbnRyYWN0LmFsZ28udHM6MTE2CiAgICAvLyBjb25zdCBbdmFsdWUsIGZ1bmRlZF0gPSBvcC5BY2N0UGFyYW1zLmFjY3RUb3RhbEFzc2V0cyhhKQogICAgZnJhbWVfZGlnIC0xCiAgICBhY2N0X3BhcmFtc19nZXQgQWNjdFRvdGFsQXNzZXRzCiAgICAvLyB0ZXN0cy9hcnRpZmFjdHMvc3RhdGUtb3BzL2NvbnRyYWN0LmFsZ28udHM6MTE3CiAgICAvLyBjb25zdCBbdmFsdWVfaW5kZXgsIGZ1bmRlZF9pbmRleF0gPSBvcC5BY2N0UGFyYW1zLmFjY3RUb3RhbEFzc2V0cyhnZXRfMXN0X3JlZl9pbmRleCgpKQogICAgY2FsbHN1YiBnZXRfMXN0X3JlZl9pbmRleAogICAgYWNjdF9wYXJhbXNfZ2V0IEFjY3RUb3RhbEFzc2V0cwogICAgLy8gdGVzdHMvYXJ0aWZhY3RzL3N0YXRlLW9wcy9jb250cmFjdC5hbGdvLnRzOjExOAogICAgLy8gYXNzZXJ0KHZhbHVlID09PSB2YWx1ZV9pbmRleCwgJ2V4cGVjdGVkIHZhbHVlIGJ5IGluZGV4IHRvIG1hdGNoJykKICAgIGRpZyAzCiAgICB1bmNvdmVyIDIKICAgID09CiAgICBhc3NlcnQgLy8gZXhwZWN0ZWQgdmFsdWUgYnkgaW5kZXggdG8gbWF0Y2gKICAgIC8vIHRlc3RzL2FydGlmYWN0cy9zdGF0ZS1vcHMvY29udHJhY3QuYWxnby50czoxMTkKICAgIC8vIGFzc2VydChmdW5kZWQgPT09IGZ1bmRlZF9pbmRleCwgJ2V4cGVjdGVkIGZ1bmRlZCBieSBpbmRleCB0byBtYXRjaCcpCiAgICA9PQogICAgYXNzZXJ0IC8vIGV4cGVjdGVkIGZ1bmRlZCBieSBpbmRleCB0byBtYXRjaAogICAgLy8gdGVzdHMvYXJ0aWZhY3RzL3N0YXRlLW9wcy9jb250cmFjdC5hbGdvLnRzOjEyMAogICAgLy8gcmV0dXJuIHZhbHVlCiAgICByZXRzdWIKCgovLyB0ZXN0cy9hcnRpZmFjdHMvc3RhdGUtb3BzL2NvbnRyYWN0LmFsZ28udHM6OlN0YXRlQWNjdFBhcmFtc0dldENvbnRyYWN0LnZlcmlmeV9hY2N0X3RvdGFsX2JveGVzKGE6IGJ5dGVzKSAtPiB1aW50NjQ6CnZlcmlmeV9hY2N0X3RvdGFsX2JveGVzOgogICAgLy8gdGVzdHMvYXJ0aWZhY3RzL3N0YXRlLW9wcy9jb250cmFjdC5hbGdvLnRzOjEyMy0xMjQKICAgIC8vIEBhcmM0LmFiaW1ldGhvZCgpCiAgICAvLyBwdWJsaWMgdmVyaWZ5X2FjY3RfdG90YWxfYm94ZXMoYTogQWNjb3VudCk6IHVpbnQ2NCB7CiAgICBwcm90byAxIDEKICAgIC8vIHRlc3RzL2FydGlmYWN0cy9zdGF0ZS1vcHMvY29udHJhY3QuYWxnby50czoxMjUKICAgIC8vIGNvbnN0IFt2YWx1ZSwgZnVuZGVkXSA9IG9wLkFjY3RQYXJhbXMuYWNjdFRvdGFsQm94ZXMoYSkKICAgIGZyYW1lX2RpZyAtMQogICAgYWNjdF9wYXJhbXNfZ2V0IEFjY3RUb3RhbEJveGVzCiAgICAvLyB0ZXN0cy9hcnRpZmFjdHMvc3RhdGUtb3BzL2NvbnRyYWN0LmFsZ28udHM6MTI2CiAgICAvLyBjb25zdCBbdmFsdWVfaW5kZXgsIGZ1bmRlZF9pbmRleF0gPSBvcC5BY2N0UGFyYW1zLmFjY3RUb3RhbEJveGVzKGdldF8xc3RfcmVmX2luZGV4KCkpCiAgICBjYWxsc3ViIGdldF8xc3RfcmVmX2luZGV4CiAgICBhY2N0X3BhcmFtc19nZXQgQWNjdFRvdGFsQm94ZXMKICAgIC8vIHRlc3RzL2FydGlmYWN0cy9zdGF0ZS1vcHMvY29udHJhY3QuYWxnby50czoxMjcKICAgIC8vIGFzc2VydCh2YWx1ZSA9PT0gdmFsdWVfaW5kZXgsICdleHBlY3RlZCB2YWx1ZSBieSBpbmRleCB0byBtYXRjaCcpCiAgICBkaWcgMwogICAgdW5jb3ZlciAyCiAgICA9PQogICAgYXNzZXJ0IC8vIGV4cGVjdGVkIHZhbHVlIGJ5IGluZGV4IHRvIG1hdGNoCiAgICAvLyB0ZXN0cy9hcnRpZmFjdHMvc3RhdGUtb3BzL2NvbnRyYWN0LmFsZ28udHM6MTI4CiAgICAvLyBhc3NlcnQoZnVuZGVkID09PSBmdW5kZWRfaW5kZXgsICdleHBlY3RlZCBmdW5kZWQgYnkgaW5kZXggdG8gbWF0Y2gnKQogICAgPT0KICAgIGFzc2VydCAvLyBleHBlY3RlZCBmdW5kZWQgYnkgaW5kZXggdG8gbWF0Y2gKICAgIC8vIHRlc3RzL2FydGlmYWN0cy9zdGF0ZS1vcHMvY29udHJhY3QuYWxnby50czoxMjkKICAgIC8vIHJldHVybiB2YWx1ZQogICAgcmV0c3ViCgoKLy8gdGVzdHMvYXJ0aWZhY3RzL3N0YXRlLW9wcy9jb250cmFjdC5hbGdvLnRzOjpTdGF0ZUFjY3RQYXJhbXNHZXRDb250cmFjdC52ZXJpZnlfYWNjdF90b3RhbF9ib3hfYnl0ZXMoYTogYnl0ZXMpIC0+IHVpbnQ2NDoKdmVyaWZ5X2FjY3RfdG90YWxfYm94X2J5dGVzOgogICAgLy8gdGVzdHMvYXJ0aWZhY3RzL3N0YXRlLW9wcy9jb250cmFjdC5hbGdvLnRzOjEzMi0xMzMKICAgIC8vIEBhcmM0LmFiaW1ldGhvZCgpCiAgICAvLyBwdWJsaWMgdmVyaWZ5X2FjY3RfdG90YWxfYm94X2J5dGVzKGE6IEFjY291bnQpOiB1aW50NjQgewogICAgcHJvdG8gMSAxCiAgICAvLyB0ZXN0cy9hcnRpZmFjdHMvc3RhdGUtb3BzL2NvbnRyYWN0LmFsZ28udHM6MTM0CiAgICAvLyBjb25zdCBbdmFsdWUsIGZ1bmRlZF0gPSBvcC5BY2N0UGFyYW1zLmFjY3RUb3RhbEJveEJ5dGVzKGEpCiAgICBmcmFtZV9kaWcgLTEKICAgIGFjY3RfcGFyYW1zX2dldCBBY2N0VG90YWxCb3hCeXRlcwogICAgLy8gdGVzdHMvYXJ0aWZhY3RzL3N0YXRlLW9wcy9jb250cmFjdC5hbGdvLnRzOjEzNQogICAgLy8gY29uc3QgW3ZhbHVlX2luZGV4LCBmdW5kZWRfaW5kZXhdID0gb3AuQWNjdFBhcmFtcy5hY2N0VG90YWxCb3hCeXRlcyhnZXRfMXN0X3JlZl9pbmRleCgpKQogICAgY2FsbHN1YiBnZXRfMXN0X3JlZl9pbmRleAogICAgYWNjdF9wYXJhbXNfZ2V0IEFjY3RUb3RhbEJveEJ5dGVzCiAgICAvLyB0ZXN0cy9hcnRpZmFjdHMvc3RhdGUtb3BzL2NvbnRyYWN0LmFsZ28udHM6MTM2CiAgICAvLyBhc3NlcnQodmFsdWUgPT09IHZhbHVlX2luZGV4LCAnZXhwZWN0ZWQgdmFsdWUgYnkgaW5kZXggdG8gbWF0Y2gnKQogICAgZGlnIDMKICAgIHVuY292ZXIgMgogICAgPT0KICAgIGFzc2VydCAvLyBleHBlY3RlZCB2YWx1ZSBieSBpbmRleCB0byBtYXRjaAogICAgLy8gdGVzdHMvYXJ0aWZhY3RzL3N0YXRlLW9wcy9jb250cmFjdC5hbGdvLnRzOjEzNwogICAgLy8gYXNzZXJ0KGZ1bmRlZCA9PT0gZnVuZGVkX2luZGV4LCAnZXhwZWN0ZWQgZnVuZGVkIGJ5IGluZGV4IHRvIG1hdGNoJykKICAgID09CiAgICBhc3NlcnQgLy8gZXhwZWN0ZWQgZnVuZGVkIGJ5IGluZGV4IHRvIG1hdGNoCiAgICAvLyB0ZXN0cy9hcnRpZmFjdHMvc3RhdGUtb3BzL2NvbnRyYWN0LmFsZ28udHM6MTM4CiAgICAvLyByZXR1cm4gdmFsdWUKICAgIHJldHN1Ygo=", - "clear": "I3ByYWdtYSB2ZXJzaW9uIDEwCgp0ZXN0cy9hcnRpZmFjdHMvc3RhdGUtb3BzL2NvbnRyYWN0LmFsZ28udHM6OlN0YXRlQWNjdFBhcmFtc0dldENvbnRyYWN0LmNsZWFyU3RhdGVQcm9ncmFtOgogICAgcHVzaGludCAxIC8vIDEKICAgIHJldHVybgo=" + "approval": "I3ByYWdtYSB2ZXJzaW9uIDExCiNwcmFnbWEgdHlwZXRyYWNrIGZhbHNlCgovLyBAYWxnb3JhbmRmb3VuZGF0aW9uL2FsZ29yYW5kLXR5cGVzY3JpcHQvYXJjNC9pbmRleC5kLnRzOjpDb250cmFjdC5hcHByb3ZhbFByb2dyYW0oKSAtPiB1aW50NjQ6Cm1haW46CiAgICBpbnRjYmxvY2sgMSAwCiAgICBieXRlY2Jsb2NrIDB4MTUxZjdjNzUKICAgIC8vIHRlc3RzL2FydGlmYWN0cy9zdGF0ZS1vcHMvc3RhdGUtYWNjdC1wYXJhbXMtZ2V0LWNvbnRyYWN0LmFsZ28udHM6OAogICAgLy8gZXhwb3J0IGNsYXNzIFN0YXRlQWNjdFBhcmFtc0dldENvbnRyYWN0IGV4dGVuZHMgYXJjNC5Db250cmFjdCB7CiAgICB0eG4gTnVtQXBwQXJncwogICAgYnogbWFpbl9iYXJlX3JvdXRpbmdAMTgKICAgIHB1c2hieXRlc3MgMHg1ZjViNDNlNCAweDczZGM5M2M3IDB4NTYyNmRmZWIgMHhkYzhhMjViZiAweDE5OGViZDhjIDB4MjMwMWFiMjYgMHg5ZjY4ZmNhNiAweGE5NzVjMmQxIDB4ZDFlMDQ4MDEgMHhiNjk2NmJlNSAweDE5NWQ1NDE4IDB4NmFkYWUzZjEgMHhkZjhjZmVlNSAvLyBtZXRob2QgInZlcmlmeV9hY2N0X2JhbGFuY2UoYWNjb3VudCl1aW50NjQiLCBtZXRob2QgInZlcmlmeV9hY2N0X21pbl9iYWxhbmNlKGFjY291bnQpdWludDY0IiwgbWV0aG9kICJ2ZXJpZnlfYWNjdF9hdXRoX2FkZHIoYWNjb3VudClhZGRyZXNzIiwgbWV0aG9kICJ2ZXJpZnlfYWNjdF90b3RhbF9udW1fdWludChhY2NvdW50KXVpbnQ2NCIsIG1ldGhvZCAidmVyaWZ5X2FjY3RfdG90YWxfbnVtX2J5dGVfc2xpY2UoYWNjb3VudCl1aW50NjQiLCBtZXRob2QgInZlcmlmeV9hY2N0X3RvdGFsX2V4dHJhX2FwcF9wYWdlcyhhY2NvdW50KXVpbnQ2NCIsIG1ldGhvZCAidmVyaWZ5X2FjY3RfdG90YWxfYXBwc19jcmVhdGVkKGFjY291bnQpdWludDY0IiwgbWV0aG9kICJ2ZXJpZnlfYWNjdF90b3RhbF9hcHBzX29wdGVkX2luKGFjY291bnQpdWludDY0IiwgbWV0aG9kICJ2ZXJpZnlfYWNjdF90b3RhbF9hc3NldHNfY3JlYXRlZChhY2NvdW50KXVpbnQ2NCIsIG1ldGhvZCAidmVyaWZ5X2FjY3RfdG90YWxfYXNzZXRzKGFjY291bnQpdWludDY0IiwgbWV0aG9kICJ2ZXJpZnlfYWNjdF90b3RhbF9ib3hlcyhhY2NvdW50KXVpbnQ2NCIsIG1ldGhvZCAidmVyaWZ5X2FjY3RfdG90YWxfYm94X2J5dGVzKGFjY291bnQpdWludDY0IiwgbWV0aG9kICJ2ZXJpZnlfYWNjdF9pbmNlbnRpdmVfZWxpZ2libGUoYWNjb3VudClib29sIgogICAgdHhuYSBBcHBsaWNhdGlvbkFyZ3MgMAogICAgbWF0Y2ggbWFpbl92ZXJpZnlfYWNjdF9iYWxhbmNlX3JvdXRlQDMgbWFpbl92ZXJpZnlfYWNjdF9taW5fYmFsYW5jZV9yb3V0ZUA0IG1haW5fdmVyaWZ5X2FjY3RfYXV0aF9hZGRyX3JvdXRlQDUgbWFpbl92ZXJpZnlfYWNjdF90b3RhbF9udW1fdWludF9yb3V0ZUA2IG1haW5fdmVyaWZ5X2FjY3RfdG90YWxfbnVtX2J5dGVfc2xpY2Vfcm91dGVANyBtYWluX3ZlcmlmeV9hY2N0X3RvdGFsX2V4dHJhX2FwcF9wYWdlc19yb3V0ZUA4IG1haW5fdmVyaWZ5X2FjY3RfdG90YWxfYXBwc19jcmVhdGVkX3JvdXRlQDkgbWFpbl92ZXJpZnlfYWNjdF90b3RhbF9hcHBzX29wdGVkX2luX3JvdXRlQDEwIG1haW5fdmVyaWZ5X2FjY3RfdG90YWxfYXNzZXRzX2NyZWF0ZWRfcm91dGVAMTEgbWFpbl92ZXJpZnlfYWNjdF90b3RhbF9hc3NldHNfcm91dGVAMTIgbWFpbl92ZXJpZnlfYWNjdF90b3RhbF9ib3hlc19yb3V0ZUAxMyBtYWluX3ZlcmlmeV9hY2N0X3RvdGFsX2JveF9ieXRlc19yb3V0ZUAxNCBtYWluX3ZlcmlmeV9hY2N0X2luY2VudGl2ZV9lbGlnaWJsZV9yb3V0ZUAxNQoKbWFpbl9hZnRlcl9pZl9lbHNlQDIyOgogICAgLy8gdGVzdHMvYXJ0aWZhY3RzL3N0YXRlLW9wcy9zdGF0ZS1hY2N0LXBhcmFtcy1nZXQtY29udHJhY3QuYWxnby50czo4CiAgICAvLyBleHBvcnQgY2xhc3MgU3RhdGVBY2N0UGFyYW1zR2V0Q29udHJhY3QgZXh0ZW5kcyBhcmM0LkNvbnRyYWN0IHsKICAgIGludGNfMSAvLyAwCiAgICByZXR1cm4KCm1haW5fdmVyaWZ5X2FjY3RfaW5jZW50aXZlX2VsaWdpYmxlX3JvdXRlQDE1OgogICAgLy8gdGVzdHMvYXJ0aWZhY3RzL3N0YXRlLW9wcy9zdGF0ZS1hY2N0LXBhcmFtcy1nZXQtY29udHJhY3QuYWxnby50czoxMjMKICAgIC8vIEBhcmM0LmFiaW1ldGhvZCgpCiAgICB0eG4gT25Db21wbGV0aW9uCiAgICAhCiAgICBhc3NlcnQgLy8gT25Db21wbGV0aW9uIGlzIG5vdCBOb09wCiAgICB0eG4gQXBwbGljYXRpb25JRAogICAgYXNzZXJ0IC8vIGNhbiBvbmx5IGNhbGwgd2hlbiBub3QgY3JlYXRpbmcKICAgIC8vIHRlc3RzL2FydGlmYWN0cy9zdGF0ZS1vcHMvc3RhdGUtYWNjdC1wYXJhbXMtZ2V0LWNvbnRyYWN0LmFsZ28udHM6OAogICAgLy8gZXhwb3J0IGNsYXNzIFN0YXRlQWNjdFBhcmFtc0dldENvbnRyYWN0IGV4dGVuZHMgYXJjNC5Db250cmFjdCB7CiAgICB0eG5hIEFwcGxpY2F0aW9uQXJncyAxCiAgICBidG9pCiAgICB0eG5hcyBBY2NvdW50cwogICAgLy8gdGVzdHMvYXJ0aWZhY3RzL3N0YXRlLW9wcy9zdGF0ZS1hY2N0LXBhcmFtcy1nZXQtY29udHJhY3QuYWxnby50czoxMjMKICAgIC8vIEBhcmM0LmFiaW1ldGhvZCgpCiAgICBjYWxsc3ViIHZlcmlmeV9hY2N0X2luY2VudGl2ZV9lbGlnaWJsZQogICAgcHVzaGJ5dGVzIDB4MDAKICAgIGludGNfMSAvLyAwCiAgICB1bmNvdmVyIDIKICAgIHNldGJpdAogICAgYnl0ZWNfMCAvLyAweDE1MWY3Yzc1CiAgICBzd2FwCiAgICBjb25jYXQKICAgIGxvZwogICAgaW50Y18wIC8vIDEKICAgIHJldHVybgoKbWFpbl92ZXJpZnlfYWNjdF90b3RhbF9ib3hfYnl0ZXNfcm91dGVAMTQ6CiAgICAvLyB0ZXN0cy9hcnRpZmFjdHMvc3RhdGUtb3BzL3N0YXRlLWFjY3QtcGFyYW1zLWdldC1jb250cmFjdC5hbGdvLnRzOjExNAogICAgLy8gQGFyYzQuYWJpbWV0aG9kKCkKICAgIHR4biBPbkNvbXBsZXRpb24KICAgICEKICAgIGFzc2VydCAvLyBPbkNvbXBsZXRpb24gaXMgbm90IE5vT3AKICAgIHR4biBBcHBsaWNhdGlvbklECiAgICBhc3NlcnQgLy8gY2FuIG9ubHkgY2FsbCB3aGVuIG5vdCBjcmVhdGluZwogICAgLy8gdGVzdHMvYXJ0aWZhY3RzL3N0YXRlLW9wcy9zdGF0ZS1hY2N0LXBhcmFtcy1nZXQtY29udHJhY3QuYWxnby50czo4CiAgICAvLyBleHBvcnQgY2xhc3MgU3RhdGVBY2N0UGFyYW1zR2V0Q29udHJhY3QgZXh0ZW5kcyBhcmM0LkNvbnRyYWN0IHsKICAgIHR4bmEgQXBwbGljYXRpb25BcmdzIDEKICAgIGJ0b2kKICAgIHR4bmFzIEFjY291bnRzCiAgICAvLyB0ZXN0cy9hcnRpZmFjdHMvc3RhdGUtb3BzL3N0YXRlLWFjY3QtcGFyYW1zLWdldC1jb250cmFjdC5hbGdvLnRzOjExNAogICAgLy8gQGFyYzQuYWJpbWV0aG9kKCkKICAgIGNhbGxzdWIgdmVyaWZ5X2FjY3RfdG90YWxfYm94X2J5dGVzCiAgICBpdG9iCiAgICBieXRlY18wIC8vIDB4MTUxZjdjNzUKICAgIHN3YXAKICAgIGNvbmNhdAogICAgbG9nCiAgICBpbnRjXzAgLy8gMQogICAgcmV0dXJuCgptYWluX3ZlcmlmeV9hY2N0X3RvdGFsX2JveGVzX3JvdXRlQDEzOgogICAgLy8gdGVzdHMvYXJ0aWZhY3RzL3N0YXRlLW9wcy9zdGF0ZS1hY2N0LXBhcmFtcy1nZXQtY29udHJhY3QuYWxnby50czoxMDUKICAgIC8vIEBhcmM0LmFiaW1ldGhvZCgpCiAgICB0eG4gT25Db21wbGV0aW9uCiAgICAhCiAgICBhc3NlcnQgLy8gT25Db21wbGV0aW9uIGlzIG5vdCBOb09wCiAgICB0eG4gQXBwbGljYXRpb25JRAogICAgYXNzZXJ0IC8vIGNhbiBvbmx5IGNhbGwgd2hlbiBub3QgY3JlYXRpbmcKICAgIC8vIHRlc3RzL2FydGlmYWN0cy9zdGF0ZS1vcHMvc3RhdGUtYWNjdC1wYXJhbXMtZ2V0LWNvbnRyYWN0LmFsZ28udHM6OAogICAgLy8gZXhwb3J0IGNsYXNzIFN0YXRlQWNjdFBhcmFtc0dldENvbnRyYWN0IGV4dGVuZHMgYXJjNC5Db250cmFjdCB7CiAgICB0eG5hIEFwcGxpY2F0aW9uQXJncyAxCiAgICBidG9pCiAgICB0eG5hcyBBY2NvdW50cwogICAgLy8gdGVzdHMvYXJ0aWZhY3RzL3N0YXRlLW9wcy9zdGF0ZS1hY2N0LXBhcmFtcy1nZXQtY29udHJhY3QuYWxnby50czoxMDUKICAgIC8vIEBhcmM0LmFiaW1ldGhvZCgpCiAgICBjYWxsc3ViIHZlcmlmeV9hY2N0X3RvdGFsX2JveGVzCiAgICBpdG9iCiAgICBieXRlY18wIC8vIDB4MTUxZjdjNzUKICAgIHN3YXAKICAgIGNvbmNhdAogICAgbG9nCiAgICBpbnRjXzAgLy8gMQogICAgcmV0dXJuCgptYWluX3ZlcmlmeV9hY2N0X3RvdGFsX2Fzc2V0c19yb3V0ZUAxMjoKICAgIC8vIHRlc3RzL2FydGlmYWN0cy9zdGF0ZS1vcHMvc3RhdGUtYWNjdC1wYXJhbXMtZ2V0LWNvbnRyYWN0LmFsZ28udHM6OTYKICAgIC8vIEBhcmM0LmFiaW1ldGhvZCgpCiAgICB0eG4gT25Db21wbGV0aW9uCiAgICAhCiAgICBhc3NlcnQgLy8gT25Db21wbGV0aW9uIGlzIG5vdCBOb09wCiAgICB0eG4gQXBwbGljYXRpb25JRAogICAgYXNzZXJ0IC8vIGNhbiBvbmx5IGNhbGwgd2hlbiBub3QgY3JlYXRpbmcKICAgIC8vIHRlc3RzL2FydGlmYWN0cy9zdGF0ZS1vcHMvc3RhdGUtYWNjdC1wYXJhbXMtZ2V0LWNvbnRyYWN0LmFsZ28udHM6OAogICAgLy8gZXhwb3J0IGNsYXNzIFN0YXRlQWNjdFBhcmFtc0dldENvbnRyYWN0IGV4dGVuZHMgYXJjNC5Db250cmFjdCB7CiAgICB0eG5hIEFwcGxpY2F0aW9uQXJncyAxCiAgICBidG9pCiAgICB0eG5hcyBBY2NvdW50cwogICAgLy8gdGVzdHMvYXJ0aWZhY3RzL3N0YXRlLW9wcy9zdGF0ZS1hY2N0LXBhcmFtcy1nZXQtY29udHJhY3QuYWxnby50czo5NgogICAgLy8gQGFyYzQuYWJpbWV0aG9kKCkKICAgIGNhbGxzdWIgdmVyaWZ5X2FjY3RfdG90YWxfYXNzZXRzCiAgICBpdG9iCiAgICBieXRlY18wIC8vIDB4MTUxZjdjNzUKICAgIHN3YXAKICAgIGNvbmNhdAogICAgbG9nCiAgICBpbnRjXzAgLy8gMQogICAgcmV0dXJuCgptYWluX3ZlcmlmeV9hY2N0X3RvdGFsX2Fzc2V0c19jcmVhdGVkX3JvdXRlQDExOgogICAgLy8gdGVzdHMvYXJ0aWZhY3RzL3N0YXRlLW9wcy9zdGF0ZS1hY2N0LXBhcmFtcy1nZXQtY29udHJhY3QuYWxnby50czo4NwogICAgLy8gQGFyYzQuYWJpbWV0aG9kKCkKICAgIHR4biBPbkNvbXBsZXRpb24KICAgICEKICAgIGFzc2VydCAvLyBPbkNvbXBsZXRpb24gaXMgbm90IE5vT3AKICAgIHR4biBBcHBsaWNhdGlvbklECiAgICBhc3NlcnQgLy8gY2FuIG9ubHkgY2FsbCB3aGVuIG5vdCBjcmVhdGluZwogICAgLy8gdGVzdHMvYXJ0aWZhY3RzL3N0YXRlLW9wcy9zdGF0ZS1hY2N0LXBhcmFtcy1nZXQtY29udHJhY3QuYWxnby50czo4CiAgICAvLyBleHBvcnQgY2xhc3MgU3RhdGVBY2N0UGFyYW1zR2V0Q29udHJhY3QgZXh0ZW5kcyBhcmM0LkNvbnRyYWN0IHsKICAgIHR4bmEgQXBwbGljYXRpb25BcmdzIDEKICAgIGJ0b2kKICAgIHR4bmFzIEFjY291bnRzCiAgICAvLyB0ZXN0cy9hcnRpZmFjdHMvc3RhdGUtb3BzL3N0YXRlLWFjY3QtcGFyYW1zLWdldC1jb250cmFjdC5hbGdvLnRzOjg3CiAgICAvLyBAYXJjNC5hYmltZXRob2QoKQogICAgY2FsbHN1YiB2ZXJpZnlfYWNjdF90b3RhbF9hc3NldHNfY3JlYXRlZAogICAgaXRvYgogICAgYnl0ZWNfMCAvLyAweDE1MWY3Yzc1CiAgICBzd2FwCiAgICBjb25jYXQKICAgIGxvZwogICAgaW50Y18wIC8vIDEKICAgIHJldHVybgoKbWFpbl92ZXJpZnlfYWNjdF90b3RhbF9hcHBzX29wdGVkX2luX3JvdXRlQDEwOgogICAgLy8gdGVzdHMvYXJ0aWZhY3RzL3N0YXRlLW9wcy9zdGF0ZS1hY2N0LXBhcmFtcy1nZXQtY29udHJhY3QuYWxnby50czo3OAogICAgLy8gQGFyYzQuYWJpbWV0aG9kKCkKICAgIHR4biBPbkNvbXBsZXRpb24KICAgICEKICAgIGFzc2VydCAvLyBPbkNvbXBsZXRpb24gaXMgbm90IE5vT3AKICAgIHR4biBBcHBsaWNhdGlvbklECiAgICBhc3NlcnQgLy8gY2FuIG9ubHkgY2FsbCB3aGVuIG5vdCBjcmVhdGluZwogICAgLy8gdGVzdHMvYXJ0aWZhY3RzL3N0YXRlLW9wcy9zdGF0ZS1hY2N0LXBhcmFtcy1nZXQtY29udHJhY3QuYWxnby50czo4CiAgICAvLyBleHBvcnQgY2xhc3MgU3RhdGVBY2N0UGFyYW1zR2V0Q29udHJhY3QgZXh0ZW5kcyBhcmM0LkNvbnRyYWN0IHsKICAgIHR4bmEgQXBwbGljYXRpb25BcmdzIDEKICAgIGJ0b2kKICAgIHR4bmFzIEFjY291bnRzCiAgICAvLyB0ZXN0cy9hcnRpZmFjdHMvc3RhdGUtb3BzL3N0YXRlLWFjY3QtcGFyYW1zLWdldC1jb250cmFjdC5hbGdvLnRzOjc4CiAgICAvLyBAYXJjNC5hYmltZXRob2QoKQogICAgY2FsbHN1YiB2ZXJpZnlfYWNjdF90b3RhbF9hcHBzX29wdGVkX2luCiAgICBpdG9iCiAgICBieXRlY18wIC8vIDB4MTUxZjdjNzUKICAgIHN3YXAKICAgIGNvbmNhdAogICAgbG9nCiAgICBpbnRjXzAgLy8gMQogICAgcmV0dXJuCgptYWluX3ZlcmlmeV9hY2N0X3RvdGFsX2FwcHNfY3JlYXRlZF9yb3V0ZUA5OgogICAgLy8gdGVzdHMvYXJ0aWZhY3RzL3N0YXRlLW9wcy9zdGF0ZS1hY2N0LXBhcmFtcy1nZXQtY29udHJhY3QuYWxnby50czo2OQogICAgLy8gQGFyYzQuYWJpbWV0aG9kKCkKICAgIHR4biBPbkNvbXBsZXRpb24KICAgICEKICAgIGFzc2VydCAvLyBPbkNvbXBsZXRpb24gaXMgbm90IE5vT3AKICAgIHR4biBBcHBsaWNhdGlvbklECiAgICBhc3NlcnQgLy8gY2FuIG9ubHkgY2FsbCB3aGVuIG5vdCBjcmVhdGluZwogICAgLy8gdGVzdHMvYXJ0aWZhY3RzL3N0YXRlLW9wcy9zdGF0ZS1hY2N0LXBhcmFtcy1nZXQtY29udHJhY3QuYWxnby50czo4CiAgICAvLyBleHBvcnQgY2xhc3MgU3RhdGVBY2N0UGFyYW1zR2V0Q29udHJhY3QgZXh0ZW5kcyBhcmM0LkNvbnRyYWN0IHsKICAgIHR4bmEgQXBwbGljYXRpb25BcmdzIDEKICAgIGJ0b2kKICAgIHR4bmFzIEFjY291bnRzCiAgICAvLyB0ZXN0cy9hcnRpZmFjdHMvc3RhdGUtb3BzL3N0YXRlLWFjY3QtcGFyYW1zLWdldC1jb250cmFjdC5hbGdvLnRzOjY5CiAgICAvLyBAYXJjNC5hYmltZXRob2QoKQogICAgY2FsbHN1YiB2ZXJpZnlfYWNjdF90b3RhbF9hcHBzX2NyZWF0ZWQKICAgIGl0b2IKICAgIGJ5dGVjXzAgLy8gMHgxNTFmN2M3NQogICAgc3dhcAogICAgY29uY2F0CiAgICBsb2cKICAgIGludGNfMCAvLyAxCiAgICByZXR1cm4KCm1haW5fdmVyaWZ5X2FjY3RfdG90YWxfZXh0cmFfYXBwX3BhZ2VzX3JvdXRlQDg6CiAgICAvLyB0ZXN0cy9hcnRpZmFjdHMvc3RhdGUtb3BzL3N0YXRlLWFjY3QtcGFyYW1zLWdldC1jb250cmFjdC5hbGdvLnRzOjYwCiAgICAvLyBAYXJjNC5hYmltZXRob2QoKQogICAgdHhuIE9uQ29tcGxldGlvbgogICAgIQogICAgYXNzZXJ0IC8vIE9uQ29tcGxldGlvbiBpcyBub3QgTm9PcAogICAgdHhuIEFwcGxpY2F0aW9uSUQKICAgIGFzc2VydCAvLyBjYW4gb25seSBjYWxsIHdoZW4gbm90IGNyZWF0aW5nCiAgICAvLyB0ZXN0cy9hcnRpZmFjdHMvc3RhdGUtb3BzL3N0YXRlLWFjY3QtcGFyYW1zLWdldC1jb250cmFjdC5hbGdvLnRzOjgKICAgIC8vIGV4cG9ydCBjbGFzcyBTdGF0ZUFjY3RQYXJhbXNHZXRDb250cmFjdCBleHRlbmRzIGFyYzQuQ29udHJhY3QgewogICAgdHhuYSBBcHBsaWNhdGlvbkFyZ3MgMQogICAgYnRvaQogICAgdHhuYXMgQWNjb3VudHMKICAgIC8vIHRlc3RzL2FydGlmYWN0cy9zdGF0ZS1vcHMvc3RhdGUtYWNjdC1wYXJhbXMtZ2V0LWNvbnRyYWN0LmFsZ28udHM6NjAKICAgIC8vIEBhcmM0LmFiaW1ldGhvZCgpCiAgICBjYWxsc3ViIHZlcmlmeV9hY2N0X3RvdGFsX2V4dHJhX2FwcF9wYWdlcwogICAgaXRvYgogICAgYnl0ZWNfMCAvLyAweDE1MWY3Yzc1CiAgICBzd2FwCiAgICBjb25jYXQKICAgIGxvZwogICAgaW50Y18wIC8vIDEKICAgIHJldHVybgoKbWFpbl92ZXJpZnlfYWNjdF90b3RhbF9udW1fYnl0ZV9zbGljZV9yb3V0ZUA3OgogICAgLy8gdGVzdHMvYXJ0aWZhY3RzL3N0YXRlLW9wcy9zdGF0ZS1hY2N0LXBhcmFtcy1nZXQtY29udHJhY3QuYWxnby50czo1MQogICAgLy8gQGFyYzQuYWJpbWV0aG9kKCkKICAgIHR4biBPbkNvbXBsZXRpb24KICAgICEKICAgIGFzc2VydCAvLyBPbkNvbXBsZXRpb24gaXMgbm90IE5vT3AKICAgIHR4biBBcHBsaWNhdGlvbklECiAgICBhc3NlcnQgLy8gY2FuIG9ubHkgY2FsbCB3aGVuIG5vdCBjcmVhdGluZwogICAgLy8gdGVzdHMvYXJ0aWZhY3RzL3N0YXRlLW9wcy9zdGF0ZS1hY2N0LXBhcmFtcy1nZXQtY29udHJhY3QuYWxnby50czo4CiAgICAvLyBleHBvcnQgY2xhc3MgU3RhdGVBY2N0UGFyYW1zR2V0Q29udHJhY3QgZXh0ZW5kcyBhcmM0LkNvbnRyYWN0IHsKICAgIHR4bmEgQXBwbGljYXRpb25BcmdzIDEKICAgIGJ0b2kKICAgIHR4bmFzIEFjY291bnRzCiAgICAvLyB0ZXN0cy9hcnRpZmFjdHMvc3RhdGUtb3BzL3N0YXRlLWFjY3QtcGFyYW1zLWdldC1jb250cmFjdC5hbGdvLnRzOjUxCiAgICAvLyBAYXJjNC5hYmltZXRob2QoKQogICAgY2FsbHN1YiB2ZXJpZnlfYWNjdF90b3RhbF9udW1fYnl0ZV9zbGljZQogICAgaXRvYgogICAgYnl0ZWNfMCAvLyAweDE1MWY3Yzc1CiAgICBzd2FwCiAgICBjb25jYXQKICAgIGxvZwogICAgaW50Y18wIC8vIDEKICAgIHJldHVybgoKbWFpbl92ZXJpZnlfYWNjdF90b3RhbF9udW1fdWludF9yb3V0ZUA2OgogICAgLy8gdGVzdHMvYXJ0aWZhY3RzL3N0YXRlLW9wcy9zdGF0ZS1hY2N0LXBhcmFtcy1nZXQtY29udHJhY3QuYWxnby50czo0MgogICAgLy8gQGFyYzQuYWJpbWV0aG9kKCkKICAgIHR4biBPbkNvbXBsZXRpb24KICAgICEKICAgIGFzc2VydCAvLyBPbkNvbXBsZXRpb24gaXMgbm90IE5vT3AKICAgIHR4biBBcHBsaWNhdGlvbklECiAgICBhc3NlcnQgLy8gY2FuIG9ubHkgY2FsbCB3aGVuIG5vdCBjcmVhdGluZwogICAgLy8gdGVzdHMvYXJ0aWZhY3RzL3N0YXRlLW9wcy9zdGF0ZS1hY2N0LXBhcmFtcy1nZXQtY29udHJhY3QuYWxnby50czo4CiAgICAvLyBleHBvcnQgY2xhc3MgU3RhdGVBY2N0UGFyYW1zR2V0Q29udHJhY3QgZXh0ZW5kcyBhcmM0LkNvbnRyYWN0IHsKICAgIHR4bmEgQXBwbGljYXRpb25BcmdzIDEKICAgIGJ0b2kKICAgIHR4bmFzIEFjY291bnRzCiAgICAvLyB0ZXN0cy9hcnRpZmFjdHMvc3RhdGUtb3BzL3N0YXRlLWFjY3QtcGFyYW1zLWdldC1jb250cmFjdC5hbGdvLnRzOjQyCiAgICAvLyBAYXJjNC5hYmltZXRob2QoKQogICAgY2FsbHN1YiB2ZXJpZnlfYWNjdF90b3RhbF9udW1fdWludAogICAgaXRvYgogICAgYnl0ZWNfMCAvLyAweDE1MWY3Yzc1CiAgICBzd2FwCiAgICBjb25jYXQKICAgIGxvZwogICAgaW50Y18wIC8vIDEKICAgIHJldHVybgoKbWFpbl92ZXJpZnlfYWNjdF9hdXRoX2FkZHJfcm91dGVANToKICAgIC8vIHRlc3RzL2FydGlmYWN0cy9zdGF0ZS1vcHMvc3RhdGUtYWNjdC1wYXJhbXMtZ2V0LWNvbnRyYWN0LmFsZ28udHM6MzMKICAgIC8vIEBhcmM0LmFiaW1ldGhvZCgpCiAgICB0eG4gT25Db21wbGV0aW9uCiAgICAhCiAgICBhc3NlcnQgLy8gT25Db21wbGV0aW9uIGlzIG5vdCBOb09wCiAgICB0eG4gQXBwbGljYXRpb25JRAogICAgYXNzZXJ0IC8vIGNhbiBvbmx5IGNhbGwgd2hlbiBub3QgY3JlYXRpbmcKICAgIC8vIHRlc3RzL2FydGlmYWN0cy9zdGF0ZS1vcHMvc3RhdGUtYWNjdC1wYXJhbXMtZ2V0LWNvbnRyYWN0LmFsZ28udHM6OAogICAgLy8gZXhwb3J0IGNsYXNzIFN0YXRlQWNjdFBhcmFtc0dldENvbnRyYWN0IGV4dGVuZHMgYXJjNC5Db250cmFjdCB7CiAgICB0eG5hIEFwcGxpY2F0aW9uQXJncyAxCiAgICBidG9pCiAgICB0eG5hcyBBY2NvdW50cwogICAgLy8gdGVzdHMvYXJ0aWZhY3RzL3N0YXRlLW9wcy9zdGF0ZS1hY2N0LXBhcmFtcy1nZXQtY29udHJhY3QuYWxnby50czozMwogICAgLy8gQGFyYzQuYWJpbWV0aG9kKCkKICAgIGNhbGxzdWIgdmVyaWZ5X2FjY3RfYXV0aF9hZGRyCiAgICBieXRlY18wIC8vIDB4MTUxZjdjNzUKICAgIHN3YXAKICAgIGNvbmNhdAogICAgbG9nCiAgICBpbnRjXzAgLy8gMQogICAgcmV0dXJuCgptYWluX3ZlcmlmeV9hY2N0X21pbl9iYWxhbmNlX3JvdXRlQDQ6CiAgICAvLyB0ZXN0cy9hcnRpZmFjdHMvc3RhdGUtb3BzL3N0YXRlLWFjY3QtcGFyYW1zLWdldC1jb250cmFjdC5hbGdvLnRzOjIxCiAgICAvLyBAYXJjNC5hYmltZXRob2QoKQogICAgdHhuIE9uQ29tcGxldGlvbgogICAgIQogICAgYXNzZXJ0IC8vIE9uQ29tcGxldGlvbiBpcyBub3QgTm9PcAogICAgdHhuIEFwcGxpY2F0aW9uSUQKICAgIGFzc2VydCAvLyBjYW4gb25seSBjYWxsIHdoZW4gbm90IGNyZWF0aW5nCiAgICAvLyB0ZXN0cy9hcnRpZmFjdHMvc3RhdGUtb3BzL3N0YXRlLWFjY3QtcGFyYW1zLWdldC1jb250cmFjdC5hbGdvLnRzOjgKICAgIC8vIGV4cG9ydCBjbGFzcyBTdGF0ZUFjY3RQYXJhbXNHZXRDb250cmFjdCBleHRlbmRzIGFyYzQuQ29udHJhY3QgewogICAgdHhuYSBBcHBsaWNhdGlvbkFyZ3MgMQogICAgYnRvaQogICAgdHhuYXMgQWNjb3VudHMKICAgIC8vIHRlc3RzL2FydGlmYWN0cy9zdGF0ZS1vcHMvc3RhdGUtYWNjdC1wYXJhbXMtZ2V0LWNvbnRyYWN0LmFsZ28udHM6MjEKICAgIC8vIEBhcmM0LmFiaW1ldGhvZCgpCiAgICBjYWxsc3ViIHZlcmlmeV9hY2N0X21pbl9iYWxhbmNlCiAgICBpdG9iCiAgICBieXRlY18wIC8vIDB4MTUxZjdjNzUKICAgIHN3YXAKICAgIGNvbmNhdAogICAgbG9nCiAgICBpbnRjXzAgLy8gMQogICAgcmV0dXJuCgptYWluX3ZlcmlmeV9hY2N0X2JhbGFuY2Vfcm91dGVAMzoKICAgIC8vIHRlc3RzL2FydGlmYWN0cy9zdGF0ZS1vcHMvc3RhdGUtYWNjdC1wYXJhbXMtZ2V0LWNvbnRyYWN0LmFsZ28udHM6OQogICAgLy8gQGFyYzQuYWJpbWV0aG9kKCkKICAgIHR4biBPbkNvbXBsZXRpb24KICAgICEKICAgIGFzc2VydCAvLyBPbkNvbXBsZXRpb24gaXMgbm90IE5vT3AKICAgIHR4biBBcHBsaWNhdGlvbklECiAgICBhc3NlcnQgLy8gY2FuIG9ubHkgY2FsbCB3aGVuIG5vdCBjcmVhdGluZwogICAgLy8gdGVzdHMvYXJ0aWZhY3RzL3N0YXRlLW9wcy9zdGF0ZS1hY2N0LXBhcmFtcy1nZXQtY29udHJhY3QuYWxnby50czo4CiAgICAvLyBleHBvcnQgY2xhc3MgU3RhdGVBY2N0UGFyYW1zR2V0Q29udHJhY3QgZXh0ZW5kcyBhcmM0LkNvbnRyYWN0IHsKICAgIHR4bmEgQXBwbGljYXRpb25BcmdzIDEKICAgIGJ0b2kKICAgIHR4bmFzIEFjY291bnRzCiAgICAvLyB0ZXN0cy9hcnRpZmFjdHMvc3RhdGUtb3BzL3N0YXRlLWFjY3QtcGFyYW1zLWdldC1jb250cmFjdC5hbGdvLnRzOjkKICAgIC8vIEBhcmM0LmFiaW1ldGhvZCgpCiAgICBjYWxsc3ViIHZlcmlmeV9hY2N0X2JhbGFuY2UKICAgIGl0b2IKICAgIGJ5dGVjXzAgLy8gMHgxNTFmN2M3NQogICAgc3dhcAogICAgY29uY2F0CiAgICBsb2cKICAgIGludGNfMCAvLyAxCiAgICByZXR1cm4KCm1haW5fYmFyZV9yb3V0aW5nQDE4OgogICAgLy8gdGVzdHMvYXJ0aWZhY3RzL3N0YXRlLW9wcy9zdGF0ZS1hY2N0LXBhcmFtcy1nZXQtY29udHJhY3QuYWxnby50czo4CiAgICAvLyBleHBvcnQgY2xhc3MgU3RhdGVBY2N0UGFyYW1zR2V0Q29udHJhY3QgZXh0ZW5kcyBhcmM0LkNvbnRyYWN0IHsKICAgIHR4biBPbkNvbXBsZXRpb24KICAgIGJueiBtYWluX2FmdGVyX2lmX2Vsc2VAMjIKICAgIHR4biBBcHBsaWNhdGlvbklECiAgICAhCiAgICBhc3NlcnQgLy8gY2FuIG9ubHkgY2FsbCB3aGVuIGNyZWF0aW5nCiAgICBpbnRjXzAgLy8gMQogICAgcmV0dXJuCgoKLy8gdGVzdHMvYXJ0aWZhY3RzL3N0YXRlLW9wcy9zdGF0ZS1hY2N0LXBhcmFtcy1nZXQtY29udHJhY3QuYWxnby50czo6U3RhdGVBY2N0UGFyYW1zR2V0Q29udHJhY3QudmVyaWZ5X2FjY3RfYmFsYW5jZShhOiBieXRlcykgLT4gdWludDY0Ogp2ZXJpZnlfYWNjdF9iYWxhbmNlOgogICAgLy8gdGVzdHMvYXJ0aWZhY3RzL3N0YXRlLW9wcy9zdGF0ZS1hY2N0LXBhcmFtcy1nZXQtY29udHJhY3QuYWxnby50czo5LTEwCiAgICAvLyBAYXJjNC5hYmltZXRob2QoKQogICAgLy8gcHVibGljIHZlcmlmeV9hY2N0X2JhbGFuY2UoYTogQWNjb3VudCk6IHVpbnQ2NCB7CiAgICBwcm90byAxIDEKICAgIC8vIHRlc3RzL2FydGlmYWN0cy9zdGF0ZS1vcHMvc3RhdGUtYWNjdC1wYXJhbXMtZ2V0LWNvbnRyYWN0LmFsZ28udHM6MTEKICAgIC8vIGNvbnN0IFt2YWx1ZSwgZnVuZGVkXSA9IG9wLkFjY3RQYXJhbXMuYWNjdEJhbGFuY2UoYSkKICAgIGZyYW1lX2RpZyAtMQogICAgYWNjdF9wYXJhbXNfZ2V0IEFjY3RCYWxhbmNlCiAgICAvLyB0ZXN0cy9hcnRpZmFjdHMvc3RhdGUtb3BzL3N0YXRlLWFjY3QtcGFyYW1zLWdldC1jb250cmFjdC5hbGdvLnRzOjUKICAgIC8vIHJldHVybiBvcC5idG9pKFR4bi5hcHBsaWNhdGlvbkFyZ3MoMSkpCiAgICBpbnRjXzAgLy8gMQogICAgdHhuYXMgQXBwbGljYXRpb25BcmdzCiAgICBidG9pCiAgICAvLyB0ZXN0cy9hcnRpZmFjdHMvc3RhdGUtb3BzL3N0YXRlLWFjY3QtcGFyYW1zLWdldC1jb250cmFjdC5hbGdvLnRzOjEyCiAgICAvLyBjb25zdCBbdmFsdWVfaW5kZXgsIGZ1bmRlZF9pbmRleF0gPSBvcC5BY2N0UGFyYW1zLmFjY3RCYWxhbmNlKGdldF8xc3RfcmVmX2luZGV4KCkpCiAgICBkdXAKICAgIGFjY3RfcGFyYW1zX2dldCBBY2N0QmFsYW5jZQogICAgLy8gdGVzdHMvYXJ0aWZhY3RzL3N0YXRlLW9wcy9zdGF0ZS1hY2N0LXBhcmFtcy1nZXQtY29udHJhY3QuYWxnby50czoxMwogICAgLy8gYXNzZXJ0KHZhbHVlID09PSB2YWx1ZV9pbmRleCwgJ2V4cGVjdGVkIHZhbHVlIGJ5IGluZGV4IHRvIG1hdGNoJykKICAgIGRpZyA0CiAgICB1bmNvdmVyIDIKICAgID09CiAgICBhc3NlcnQgLy8gZXhwZWN0ZWQgdmFsdWUgYnkgaW5kZXggdG8gbWF0Y2gKICAgIC8vIHRlc3RzL2FydGlmYWN0cy9zdGF0ZS1vcHMvc3RhdGUtYWNjdC1wYXJhbXMtZ2V0LWNvbnRyYWN0LmFsZ28udHM6MTQKICAgIC8vIGFzc2VydChmdW5kZWQgPT09IGZ1bmRlZF9pbmRleCwgJ2V4cGVjdGVkIGZ1bmRlZCBieSBpbmRleCB0byBtYXRjaCcpCiAgICB1bmNvdmVyIDIKICAgID09CiAgICBhc3NlcnQgLy8gZXhwZWN0ZWQgZnVuZGVkIGJ5IGluZGV4IHRvIG1hdGNoCiAgICAvLyB0ZXN0cy9hcnRpZmFjdHMvc3RhdGUtb3BzL3N0YXRlLWFjY3QtcGFyYW1zLWdldC1jb250cmFjdC5hbGdvLnRzOjE1CiAgICAvLyBhc3NlcnQodmFsdWUgPT09IGEuYmFsYW5jZSwgJ2V4cGVjdGVkIEFjY291bnQgYmFsYW5jZSB0byBtYXRjaCcpCiAgICBmcmFtZV9kaWcgLTEKICAgIGFjY3RfcGFyYW1zX2dldCBBY2N0QmFsYW5jZQogICAgYXNzZXJ0IC8vIGFjY291bnQgZnVuZGVkCiAgICBkaWcgMgogICAgPT0KICAgIGFzc2VydCAvLyBleHBlY3RlZCBBY2NvdW50IGJhbGFuY2UgdG8gbWF0Y2gKICAgIC8vIHRlc3RzL2FydGlmYWN0cy9zdGF0ZS1vcHMvc3RhdGUtYWNjdC1wYXJhbXMtZ2V0LWNvbnRyYWN0LmFsZ28udHM6MTYKICAgIC8vIGFzc2VydCh2YWx1ZSA9PT0gb3AuYmFsYW5jZShhKSwgJ2V4cGVjdGVkIG9wLmJhbGFuY2UgdG8gbWF0Y2gnKQogICAgZnJhbWVfZGlnIC0xCiAgICBiYWxhbmNlCiAgICBkaWcgMgogICAgPT0KICAgIGFzc2VydCAvLyBleHBlY3RlZCBvcC5iYWxhbmNlIHRvIG1hdGNoCiAgICAvLyB0ZXN0cy9hcnRpZmFjdHMvc3RhdGUtb3BzL3N0YXRlLWFjY3QtcGFyYW1zLWdldC1jb250cmFjdC5hbGdvLnRzOjE3CiAgICAvLyBhc3NlcnQodmFsdWUgPT09IG9wLmJhbGFuY2UoZ2V0XzFzdF9yZWZfaW5kZXgoKSksICdleHBlY3RlZCBvcC5iYWxhbmNlIGJ5IGluZGV4IHRvIG1hdGNoJykKICAgIGJhbGFuY2UKICAgIGRpZyAxCiAgICA9PQogICAgYXNzZXJ0IC8vIGV4cGVjdGVkIG9wLmJhbGFuY2UgYnkgaW5kZXggdG8gbWF0Y2gKICAgIC8vIHRlc3RzL2FydGlmYWN0cy9zdGF0ZS1vcHMvc3RhdGUtYWNjdC1wYXJhbXMtZ2V0LWNvbnRyYWN0LmFsZ28udHM6MTgKICAgIC8vIHJldHVybiB2YWx1ZQogICAgcmV0c3ViCgoKLy8gdGVzdHMvYXJ0aWZhY3RzL3N0YXRlLW9wcy9zdGF0ZS1hY2N0LXBhcmFtcy1nZXQtY29udHJhY3QuYWxnby50czo6U3RhdGVBY2N0UGFyYW1zR2V0Q29udHJhY3QudmVyaWZ5X2FjY3RfbWluX2JhbGFuY2UoYTogYnl0ZXMpIC0+IHVpbnQ2NDoKdmVyaWZ5X2FjY3RfbWluX2JhbGFuY2U6CiAgICAvLyB0ZXN0cy9hcnRpZmFjdHMvc3RhdGUtb3BzL3N0YXRlLWFjY3QtcGFyYW1zLWdldC1jb250cmFjdC5hbGdvLnRzOjIxLTIyCiAgICAvLyBAYXJjNC5hYmltZXRob2QoKQogICAgLy8gcHVibGljIHZlcmlmeV9hY2N0X21pbl9iYWxhbmNlKGE6IEFjY291bnQpOiB1aW50NjQgewogICAgcHJvdG8gMSAxCiAgICAvLyB0ZXN0cy9hcnRpZmFjdHMvc3RhdGUtb3BzL3N0YXRlLWFjY3QtcGFyYW1zLWdldC1jb250cmFjdC5hbGdvLnRzOjIzCiAgICAvLyBjb25zdCBbdmFsdWUsIGZ1bmRlZF0gPSBvcC5BY2N0UGFyYW1zLmFjY3RNaW5CYWxhbmNlKGEpCiAgICBmcmFtZV9kaWcgLTEKICAgIGFjY3RfcGFyYW1zX2dldCBBY2N0TWluQmFsYW5jZQogICAgLy8gdGVzdHMvYXJ0aWZhY3RzL3N0YXRlLW9wcy9zdGF0ZS1hY2N0LXBhcmFtcy1nZXQtY29udHJhY3QuYWxnby50czo1CiAgICAvLyByZXR1cm4gb3AuYnRvaShUeG4uYXBwbGljYXRpb25BcmdzKDEpKQogICAgaW50Y18wIC8vIDEKICAgIHR4bmFzIEFwcGxpY2F0aW9uQXJncwogICAgYnRvaQogICAgLy8gdGVzdHMvYXJ0aWZhY3RzL3N0YXRlLW9wcy9zdGF0ZS1hY2N0LXBhcmFtcy1nZXQtY29udHJhY3QuYWxnby50czoyNAogICAgLy8gY29uc3QgW3ZhbHVlX2luZGV4LCBmdW5kZWRfaW5kZXhdID0gb3AuQWNjdFBhcmFtcy5hY2N0TWluQmFsYW5jZShnZXRfMXN0X3JlZl9pbmRleCgpKQogICAgZHVwCiAgICBhY2N0X3BhcmFtc19nZXQgQWNjdE1pbkJhbGFuY2UKICAgIC8vIHRlc3RzL2FydGlmYWN0cy9zdGF0ZS1vcHMvc3RhdGUtYWNjdC1wYXJhbXMtZ2V0LWNvbnRyYWN0LmFsZ28udHM6MjUKICAgIC8vIGFzc2VydCh2YWx1ZSA9PT0gdmFsdWVfaW5kZXgsICdleHBlY3RlZCB2YWx1ZSBieSBpbmRleCB0byBtYXRjaCcpCiAgICBkaWcgNAogICAgdW5jb3ZlciAyCiAgICA9PQogICAgYXNzZXJ0IC8vIGV4cGVjdGVkIHZhbHVlIGJ5IGluZGV4IHRvIG1hdGNoCiAgICAvLyB0ZXN0cy9hcnRpZmFjdHMvc3RhdGUtb3BzL3N0YXRlLWFjY3QtcGFyYW1zLWdldC1jb250cmFjdC5hbGdvLnRzOjI2CiAgICAvLyBhc3NlcnQoZnVuZGVkID09PSBmdW5kZWRfaW5kZXgsICdleHBlY3RlZCBmdW5kZWQgYnkgaW5kZXggdG8gbWF0Y2gnKQogICAgdW5jb3ZlciAyCiAgICA9PQogICAgYXNzZXJ0IC8vIGV4cGVjdGVkIGZ1bmRlZCBieSBpbmRleCB0byBtYXRjaAogICAgLy8gdGVzdHMvYXJ0aWZhY3RzL3N0YXRlLW9wcy9zdGF0ZS1hY2N0LXBhcmFtcy1nZXQtY29udHJhY3QuYWxnby50czoyNwogICAgLy8gYXNzZXJ0KHZhbHVlID09PSBhLm1pbkJhbGFuY2UsICdleHBlY3RlZCBBY2NvdW50IG1pbl9iYWxhbmNlIHRvIG1hdGNoJykKICAgIGZyYW1lX2RpZyAtMQogICAgYWNjdF9wYXJhbXNfZ2V0IEFjY3RNaW5CYWxhbmNlCiAgICBhc3NlcnQgLy8gYWNjb3VudCBmdW5kZWQKICAgIGRpZyAyCiAgICA9PQogICAgYXNzZXJ0IC8vIGV4cGVjdGVkIEFjY291bnQgbWluX2JhbGFuY2UgdG8gbWF0Y2gKICAgIC8vIHRlc3RzL2FydGlmYWN0cy9zdGF0ZS1vcHMvc3RhdGUtYWNjdC1wYXJhbXMtZ2V0LWNvbnRyYWN0LmFsZ28udHM6MjgKICAgIC8vIGFzc2VydCh2YWx1ZSA9PT0gb3AubWluQmFsYW5jZShhKSwgJ2V4cGVjdGVkIG9wLm1pbl9iYWxhbmNlIHRvIG1hdGNoJykKICAgIGZyYW1lX2RpZyAtMQogICAgbWluX2JhbGFuY2UKICAgIGRpZyAyCiAgICA9PQogICAgYXNzZXJ0IC8vIGV4cGVjdGVkIG9wLm1pbl9iYWxhbmNlIHRvIG1hdGNoCiAgICAvLyB0ZXN0cy9hcnRpZmFjdHMvc3RhdGUtb3BzL3N0YXRlLWFjY3QtcGFyYW1zLWdldC1jb250cmFjdC5hbGdvLnRzOjI5CiAgICAvLyBhc3NlcnQodmFsdWUgPT09IG9wLm1pbkJhbGFuY2UoZ2V0XzFzdF9yZWZfaW5kZXgoKSksICdleHBlY3RlZCBvcC5taW5fYmFsYW5jZSBieSBpbmRleCB0byBtYXRjaCcpCiAgICBtaW5fYmFsYW5jZQogICAgZGlnIDEKICAgID09CiAgICBhc3NlcnQgLy8gZXhwZWN0ZWQgb3AubWluX2JhbGFuY2UgYnkgaW5kZXggdG8gbWF0Y2gKICAgIC8vIHRlc3RzL2FydGlmYWN0cy9zdGF0ZS1vcHMvc3RhdGUtYWNjdC1wYXJhbXMtZ2V0LWNvbnRyYWN0LmFsZ28udHM6MzAKICAgIC8vIHJldHVybiB2YWx1ZQogICAgcmV0c3ViCgoKLy8gdGVzdHMvYXJ0aWZhY3RzL3N0YXRlLW9wcy9zdGF0ZS1hY2N0LXBhcmFtcy1nZXQtY29udHJhY3QuYWxnby50czo6U3RhdGVBY2N0UGFyYW1zR2V0Q29udHJhY3QudmVyaWZ5X2FjY3RfYXV0aF9hZGRyKGE6IGJ5dGVzKSAtPiBieXRlczoKdmVyaWZ5X2FjY3RfYXV0aF9hZGRyOgogICAgLy8gdGVzdHMvYXJ0aWZhY3RzL3N0YXRlLW9wcy9zdGF0ZS1hY2N0LXBhcmFtcy1nZXQtY29udHJhY3QuYWxnby50czozMy0zNAogICAgLy8gQGFyYzQuYWJpbWV0aG9kKCkKICAgIC8vIHB1YmxpYyB2ZXJpZnlfYWNjdF9hdXRoX2FkZHIoYTogQWNjb3VudCk6IEFkZHJlc3MgewogICAgcHJvdG8gMSAxCiAgICAvLyB0ZXN0cy9hcnRpZmFjdHMvc3RhdGUtb3BzL3N0YXRlLWFjY3QtcGFyYW1zLWdldC1jb250cmFjdC5hbGdvLnRzOjM1CiAgICAvLyBjb25zdCBbdmFsdWUsIGZ1bmRlZF0gPSBvcC5BY2N0UGFyYW1zLmFjY3RBdXRoQWRkcihhKQogICAgZnJhbWVfZGlnIC0xCiAgICBhY2N0X3BhcmFtc19nZXQgQWNjdEF1dGhBZGRyCiAgICAvLyB0ZXN0cy9hcnRpZmFjdHMvc3RhdGUtb3BzL3N0YXRlLWFjY3QtcGFyYW1zLWdldC1jb250cmFjdC5hbGdvLnRzOjUKICAgIC8vIHJldHVybiBvcC5idG9pKFR4bi5hcHBsaWNhdGlvbkFyZ3MoMSkpCiAgICBpbnRjXzAgLy8gMQogICAgdHhuYXMgQXBwbGljYXRpb25BcmdzCiAgICBidG9pCiAgICAvLyB0ZXN0cy9hcnRpZmFjdHMvc3RhdGUtb3BzL3N0YXRlLWFjY3QtcGFyYW1zLWdldC1jb250cmFjdC5hbGdvLnRzOjM2CiAgICAvLyBjb25zdCBbdmFsdWVfaW5kZXgsIGZ1bmRlZF9pbmRleF0gPSBvcC5BY2N0UGFyYW1zLmFjY3RBdXRoQWRkcihnZXRfMXN0X3JlZl9pbmRleCgpKQogICAgYWNjdF9wYXJhbXNfZ2V0IEFjY3RBdXRoQWRkcgogICAgLy8gdGVzdHMvYXJ0aWZhY3RzL3N0YXRlLW9wcy9zdGF0ZS1hY2N0LXBhcmFtcy1nZXQtY29udHJhY3QuYWxnby50czozNwogICAgLy8gYXNzZXJ0KHZhbHVlID09PSB2YWx1ZV9pbmRleCwgJ2V4cGVjdGVkIHZhbHVlIGJ5IGluZGV4IHRvIG1hdGNoJykKICAgIGRpZyAzCiAgICB1bmNvdmVyIDIKICAgID09CiAgICBhc3NlcnQgLy8gZXhwZWN0ZWQgdmFsdWUgYnkgaW5kZXggdG8gbWF0Y2gKICAgIC8vIHRlc3RzL2FydGlmYWN0cy9zdGF0ZS1vcHMvc3RhdGUtYWNjdC1wYXJhbXMtZ2V0LWNvbnRyYWN0LmFsZ28udHM6MzgKICAgIC8vIGFzc2VydChmdW5kZWQgPT09IGZ1bmRlZF9pbmRleCwgJ2V4cGVjdGVkIGZ1bmRlZCBieSBpbmRleCB0byBtYXRjaCcpCiAgICA9PQogICAgYXNzZXJ0IC8vIGV4cGVjdGVkIGZ1bmRlZCBieSBpbmRleCB0byBtYXRjaAogICAgLy8gdGVzdHMvYXJ0aWZhY3RzL3N0YXRlLW9wcy9zdGF0ZS1hY2N0LXBhcmFtcy1nZXQtY29udHJhY3QuYWxnby50czozOQogICAgLy8gcmV0dXJuIG5ldyBBZGRyZXNzKHZhbHVlKQogICAgcmV0c3ViCgoKLy8gdGVzdHMvYXJ0aWZhY3RzL3N0YXRlLW9wcy9zdGF0ZS1hY2N0LXBhcmFtcy1nZXQtY29udHJhY3QuYWxnby50czo6U3RhdGVBY2N0UGFyYW1zR2V0Q29udHJhY3QudmVyaWZ5X2FjY3RfdG90YWxfbnVtX3VpbnQoYTogYnl0ZXMpIC0+IHVpbnQ2NDoKdmVyaWZ5X2FjY3RfdG90YWxfbnVtX3VpbnQ6CiAgICAvLyB0ZXN0cy9hcnRpZmFjdHMvc3RhdGUtb3BzL3N0YXRlLWFjY3QtcGFyYW1zLWdldC1jb250cmFjdC5hbGdvLnRzOjQyLTQzCiAgICAvLyBAYXJjNC5hYmltZXRob2QoKQogICAgLy8gcHVibGljIHZlcmlmeV9hY2N0X3RvdGFsX251bV91aW50KGE6IEFjY291bnQpOiB1aW50NjQgewogICAgcHJvdG8gMSAxCiAgICAvLyB0ZXN0cy9hcnRpZmFjdHMvc3RhdGUtb3BzL3N0YXRlLWFjY3QtcGFyYW1zLWdldC1jb250cmFjdC5hbGdvLnRzOjQ0CiAgICAvLyBjb25zdCBbdmFsdWUsIGZ1bmRlZF0gPSBvcC5BY2N0UGFyYW1zLmFjY3RUb3RhbE51bVVpbnQoYSkKICAgIGZyYW1lX2RpZyAtMQogICAgYWNjdF9wYXJhbXNfZ2V0IEFjY3RUb3RhbE51bVVpbnQKICAgIC8vIHRlc3RzL2FydGlmYWN0cy9zdGF0ZS1vcHMvc3RhdGUtYWNjdC1wYXJhbXMtZ2V0LWNvbnRyYWN0LmFsZ28udHM6NQogICAgLy8gcmV0dXJuIG9wLmJ0b2koVHhuLmFwcGxpY2F0aW9uQXJncygxKSkKICAgIGludGNfMCAvLyAxCiAgICB0eG5hcyBBcHBsaWNhdGlvbkFyZ3MKICAgIGJ0b2kKICAgIC8vIHRlc3RzL2FydGlmYWN0cy9zdGF0ZS1vcHMvc3RhdGUtYWNjdC1wYXJhbXMtZ2V0LWNvbnRyYWN0LmFsZ28udHM6NDUKICAgIC8vIGNvbnN0IFt2YWx1ZV9pbmRleCwgZnVuZGVkX2luZGV4XSA9IG9wLkFjY3RQYXJhbXMuYWNjdFRvdGFsTnVtVWludChnZXRfMXN0X3JlZl9pbmRleCgpKQogICAgYWNjdF9wYXJhbXNfZ2V0IEFjY3RUb3RhbE51bVVpbnQKICAgIC8vIHRlc3RzL2FydGlmYWN0cy9zdGF0ZS1vcHMvc3RhdGUtYWNjdC1wYXJhbXMtZ2V0LWNvbnRyYWN0LmFsZ28udHM6NDYKICAgIC8vIGFzc2VydCh2YWx1ZSA9PT0gdmFsdWVfaW5kZXgsICdleHBlY3RlZCB2YWx1ZSBieSBpbmRleCB0byBtYXRjaCcpCiAgICBkaWcgMwogICAgdW5jb3ZlciAyCiAgICA9PQogICAgYXNzZXJ0IC8vIGV4cGVjdGVkIHZhbHVlIGJ5IGluZGV4IHRvIG1hdGNoCiAgICAvLyB0ZXN0cy9hcnRpZmFjdHMvc3RhdGUtb3BzL3N0YXRlLWFjY3QtcGFyYW1zLWdldC1jb250cmFjdC5hbGdvLnRzOjQ3CiAgICAvLyBhc3NlcnQoZnVuZGVkID09PSBmdW5kZWRfaW5kZXgsICdleHBlY3RlZCBmdW5kZWQgYnkgaW5kZXggdG8gbWF0Y2gnKQogICAgPT0KICAgIGFzc2VydCAvLyBleHBlY3RlZCBmdW5kZWQgYnkgaW5kZXggdG8gbWF0Y2gKICAgIC8vIHRlc3RzL2FydGlmYWN0cy9zdGF0ZS1vcHMvc3RhdGUtYWNjdC1wYXJhbXMtZ2V0LWNvbnRyYWN0LmFsZ28udHM6NDgKICAgIC8vIHJldHVybiB2YWx1ZQogICAgcmV0c3ViCgoKLy8gdGVzdHMvYXJ0aWZhY3RzL3N0YXRlLW9wcy9zdGF0ZS1hY2N0LXBhcmFtcy1nZXQtY29udHJhY3QuYWxnby50czo6U3RhdGVBY2N0UGFyYW1zR2V0Q29udHJhY3QudmVyaWZ5X2FjY3RfdG90YWxfbnVtX2J5dGVfc2xpY2UoYTogYnl0ZXMpIC0+IHVpbnQ2NDoKdmVyaWZ5X2FjY3RfdG90YWxfbnVtX2J5dGVfc2xpY2U6CiAgICAvLyB0ZXN0cy9hcnRpZmFjdHMvc3RhdGUtb3BzL3N0YXRlLWFjY3QtcGFyYW1zLWdldC1jb250cmFjdC5hbGdvLnRzOjUxLTUyCiAgICAvLyBAYXJjNC5hYmltZXRob2QoKQogICAgLy8gcHVibGljIHZlcmlmeV9hY2N0X3RvdGFsX251bV9ieXRlX3NsaWNlKGE6IEFjY291bnQpOiB1aW50NjQgewogICAgcHJvdG8gMSAxCiAgICAvLyB0ZXN0cy9hcnRpZmFjdHMvc3RhdGUtb3BzL3N0YXRlLWFjY3QtcGFyYW1zLWdldC1jb250cmFjdC5hbGdvLnRzOjUzCiAgICAvLyBjb25zdCBbdmFsdWUsIGZ1bmRlZF0gPSBvcC5BY2N0UGFyYW1zLmFjY3RUb3RhbE51bUJ5dGVTbGljZShhKQogICAgZnJhbWVfZGlnIC0xCiAgICBhY2N0X3BhcmFtc19nZXQgQWNjdFRvdGFsTnVtQnl0ZVNsaWNlCiAgICAvLyB0ZXN0cy9hcnRpZmFjdHMvc3RhdGUtb3BzL3N0YXRlLWFjY3QtcGFyYW1zLWdldC1jb250cmFjdC5hbGdvLnRzOjUKICAgIC8vIHJldHVybiBvcC5idG9pKFR4bi5hcHBsaWNhdGlvbkFyZ3MoMSkpCiAgICBpbnRjXzAgLy8gMQogICAgdHhuYXMgQXBwbGljYXRpb25BcmdzCiAgICBidG9pCiAgICAvLyB0ZXN0cy9hcnRpZmFjdHMvc3RhdGUtb3BzL3N0YXRlLWFjY3QtcGFyYW1zLWdldC1jb250cmFjdC5hbGdvLnRzOjU0CiAgICAvLyBjb25zdCBbdmFsdWVfaW5kZXgsIGZ1bmRlZF9pbmRleF0gPSBvcC5BY2N0UGFyYW1zLmFjY3RUb3RhbE51bUJ5dGVTbGljZShnZXRfMXN0X3JlZl9pbmRleCgpKQogICAgYWNjdF9wYXJhbXNfZ2V0IEFjY3RUb3RhbE51bUJ5dGVTbGljZQogICAgLy8gdGVzdHMvYXJ0aWZhY3RzL3N0YXRlLW9wcy9zdGF0ZS1hY2N0LXBhcmFtcy1nZXQtY29udHJhY3QuYWxnby50czo1NQogICAgLy8gYXNzZXJ0KHZhbHVlID09PSB2YWx1ZV9pbmRleCwgJ2V4cGVjdGVkIHZhbHVlIGJ5IGluZGV4IHRvIG1hdGNoJykKICAgIGRpZyAzCiAgICB1bmNvdmVyIDIKICAgID09CiAgICBhc3NlcnQgLy8gZXhwZWN0ZWQgdmFsdWUgYnkgaW5kZXggdG8gbWF0Y2gKICAgIC8vIHRlc3RzL2FydGlmYWN0cy9zdGF0ZS1vcHMvc3RhdGUtYWNjdC1wYXJhbXMtZ2V0LWNvbnRyYWN0LmFsZ28udHM6NTYKICAgIC8vIGFzc2VydChmdW5kZWQgPT09IGZ1bmRlZF9pbmRleCwgJ2V4cGVjdGVkIGZ1bmRlZCBieSBpbmRleCB0byBtYXRjaCcpCiAgICA9PQogICAgYXNzZXJ0IC8vIGV4cGVjdGVkIGZ1bmRlZCBieSBpbmRleCB0byBtYXRjaAogICAgLy8gdGVzdHMvYXJ0aWZhY3RzL3N0YXRlLW9wcy9zdGF0ZS1hY2N0LXBhcmFtcy1nZXQtY29udHJhY3QuYWxnby50czo1NwogICAgLy8gcmV0dXJuIHZhbHVlCiAgICByZXRzdWIKCgovLyB0ZXN0cy9hcnRpZmFjdHMvc3RhdGUtb3BzL3N0YXRlLWFjY3QtcGFyYW1zLWdldC1jb250cmFjdC5hbGdvLnRzOjpTdGF0ZUFjY3RQYXJhbXNHZXRDb250cmFjdC52ZXJpZnlfYWNjdF90b3RhbF9leHRyYV9hcHBfcGFnZXMoYTogYnl0ZXMpIC0+IHVpbnQ2NDoKdmVyaWZ5X2FjY3RfdG90YWxfZXh0cmFfYXBwX3BhZ2VzOgogICAgLy8gdGVzdHMvYXJ0aWZhY3RzL3N0YXRlLW9wcy9zdGF0ZS1hY2N0LXBhcmFtcy1nZXQtY29udHJhY3QuYWxnby50czo2MC02MQogICAgLy8gQGFyYzQuYWJpbWV0aG9kKCkKICAgIC8vIHB1YmxpYyB2ZXJpZnlfYWNjdF90b3RhbF9leHRyYV9hcHBfcGFnZXMoYTogQWNjb3VudCk6IHVpbnQ2NCB7CiAgICBwcm90byAxIDEKICAgIC8vIHRlc3RzL2FydGlmYWN0cy9zdGF0ZS1vcHMvc3RhdGUtYWNjdC1wYXJhbXMtZ2V0LWNvbnRyYWN0LmFsZ28udHM6NjIKICAgIC8vIGNvbnN0IFt2YWx1ZSwgZnVuZGVkXSA9IG9wLkFjY3RQYXJhbXMuYWNjdFRvdGFsRXh0cmFBcHBQYWdlcyhhKQogICAgZnJhbWVfZGlnIC0xCiAgICBhY2N0X3BhcmFtc19nZXQgQWNjdFRvdGFsRXh0cmFBcHBQYWdlcwogICAgLy8gdGVzdHMvYXJ0aWZhY3RzL3N0YXRlLW9wcy9zdGF0ZS1hY2N0LXBhcmFtcy1nZXQtY29udHJhY3QuYWxnby50czo1CiAgICAvLyByZXR1cm4gb3AuYnRvaShUeG4uYXBwbGljYXRpb25BcmdzKDEpKQogICAgaW50Y18wIC8vIDEKICAgIHR4bmFzIEFwcGxpY2F0aW9uQXJncwogICAgYnRvaQogICAgLy8gdGVzdHMvYXJ0aWZhY3RzL3N0YXRlLW9wcy9zdGF0ZS1hY2N0LXBhcmFtcy1nZXQtY29udHJhY3QuYWxnby50czo2MwogICAgLy8gY29uc3QgW3ZhbHVlX2luZGV4LCBmdW5kZWRfaW5kZXhdID0gb3AuQWNjdFBhcmFtcy5hY2N0VG90YWxFeHRyYUFwcFBhZ2VzKGdldF8xc3RfcmVmX2luZGV4KCkpCiAgICBhY2N0X3BhcmFtc19nZXQgQWNjdFRvdGFsRXh0cmFBcHBQYWdlcwogICAgLy8gdGVzdHMvYXJ0aWZhY3RzL3N0YXRlLW9wcy9zdGF0ZS1hY2N0LXBhcmFtcy1nZXQtY29udHJhY3QuYWxnby50czo2NAogICAgLy8gYXNzZXJ0KHZhbHVlID09PSB2YWx1ZV9pbmRleCwgJ2V4cGVjdGVkIHZhbHVlIGJ5IGluZGV4IHRvIG1hdGNoJykKICAgIGRpZyAzCiAgICB1bmNvdmVyIDIKICAgID09CiAgICBhc3NlcnQgLy8gZXhwZWN0ZWQgdmFsdWUgYnkgaW5kZXggdG8gbWF0Y2gKICAgIC8vIHRlc3RzL2FydGlmYWN0cy9zdGF0ZS1vcHMvc3RhdGUtYWNjdC1wYXJhbXMtZ2V0LWNvbnRyYWN0LmFsZ28udHM6NjUKICAgIC8vIGFzc2VydChmdW5kZWQgPT09IGZ1bmRlZF9pbmRleCwgJ2V4cGVjdGVkIGZ1bmRlZCBieSBpbmRleCB0byBtYXRjaCcpCiAgICA9PQogICAgYXNzZXJ0IC8vIGV4cGVjdGVkIGZ1bmRlZCBieSBpbmRleCB0byBtYXRjaAogICAgLy8gdGVzdHMvYXJ0aWZhY3RzL3N0YXRlLW9wcy9zdGF0ZS1hY2N0LXBhcmFtcy1nZXQtY29udHJhY3QuYWxnby50czo2NgogICAgLy8gcmV0dXJuIHZhbHVlCiAgICByZXRzdWIKCgovLyB0ZXN0cy9hcnRpZmFjdHMvc3RhdGUtb3BzL3N0YXRlLWFjY3QtcGFyYW1zLWdldC1jb250cmFjdC5hbGdvLnRzOjpTdGF0ZUFjY3RQYXJhbXNHZXRDb250cmFjdC52ZXJpZnlfYWNjdF90b3RhbF9hcHBzX2NyZWF0ZWQoYTogYnl0ZXMpIC0+IHVpbnQ2NDoKdmVyaWZ5X2FjY3RfdG90YWxfYXBwc19jcmVhdGVkOgogICAgLy8gdGVzdHMvYXJ0aWZhY3RzL3N0YXRlLW9wcy9zdGF0ZS1hY2N0LXBhcmFtcy1nZXQtY29udHJhY3QuYWxnby50czo2OS03MAogICAgLy8gQGFyYzQuYWJpbWV0aG9kKCkKICAgIC8vIHB1YmxpYyB2ZXJpZnlfYWNjdF90b3RhbF9hcHBzX2NyZWF0ZWQoYTogQWNjb3VudCk6IHVpbnQ2NCB7CiAgICBwcm90byAxIDEKICAgIC8vIHRlc3RzL2FydGlmYWN0cy9zdGF0ZS1vcHMvc3RhdGUtYWNjdC1wYXJhbXMtZ2V0LWNvbnRyYWN0LmFsZ28udHM6NzEKICAgIC8vIGNvbnN0IFt2YWx1ZSwgZnVuZGVkXSA9IG9wLkFjY3RQYXJhbXMuYWNjdFRvdGFsQXBwc0NyZWF0ZWQoYSkKICAgIGZyYW1lX2RpZyAtMQogICAgYWNjdF9wYXJhbXNfZ2V0IEFjY3RUb3RhbEFwcHNDcmVhdGVkCiAgICAvLyB0ZXN0cy9hcnRpZmFjdHMvc3RhdGUtb3BzL3N0YXRlLWFjY3QtcGFyYW1zLWdldC1jb250cmFjdC5hbGdvLnRzOjUKICAgIC8vIHJldHVybiBvcC5idG9pKFR4bi5hcHBsaWNhdGlvbkFyZ3MoMSkpCiAgICBpbnRjXzAgLy8gMQogICAgdHhuYXMgQXBwbGljYXRpb25BcmdzCiAgICBidG9pCiAgICAvLyB0ZXN0cy9hcnRpZmFjdHMvc3RhdGUtb3BzL3N0YXRlLWFjY3QtcGFyYW1zLWdldC1jb250cmFjdC5hbGdvLnRzOjcyCiAgICAvLyBjb25zdCBbdmFsdWVfaW5kZXgsIGZ1bmRlZF9pbmRleF0gPSBvcC5BY2N0UGFyYW1zLmFjY3RUb3RhbEFwcHNDcmVhdGVkKGdldF8xc3RfcmVmX2luZGV4KCkpCiAgICBhY2N0X3BhcmFtc19nZXQgQWNjdFRvdGFsQXBwc0NyZWF0ZWQKICAgIC8vIHRlc3RzL2FydGlmYWN0cy9zdGF0ZS1vcHMvc3RhdGUtYWNjdC1wYXJhbXMtZ2V0LWNvbnRyYWN0LmFsZ28udHM6NzMKICAgIC8vIGFzc2VydCh2YWx1ZSA9PT0gdmFsdWVfaW5kZXgsICdleHBlY3RlZCB2YWx1ZSBieSBpbmRleCB0byBtYXRjaCcpCiAgICBkaWcgMwogICAgdW5jb3ZlciAyCiAgICA9PQogICAgYXNzZXJ0IC8vIGV4cGVjdGVkIHZhbHVlIGJ5IGluZGV4IHRvIG1hdGNoCiAgICAvLyB0ZXN0cy9hcnRpZmFjdHMvc3RhdGUtb3BzL3N0YXRlLWFjY3QtcGFyYW1zLWdldC1jb250cmFjdC5hbGdvLnRzOjc0CiAgICAvLyBhc3NlcnQoZnVuZGVkID09PSBmdW5kZWRfaW5kZXgsICdleHBlY3RlZCBmdW5kZWQgYnkgaW5kZXggdG8gbWF0Y2gnKQogICAgPT0KICAgIGFzc2VydCAvLyBleHBlY3RlZCBmdW5kZWQgYnkgaW5kZXggdG8gbWF0Y2gKICAgIC8vIHRlc3RzL2FydGlmYWN0cy9zdGF0ZS1vcHMvc3RhdGUtYWNjdC1wYXJhbXMtZ2V0LWNvbnRyYWN0LmFsZ28udHM6NzUKICAgIC8vIHJldHVybiB2YWx1ZQogICAgcmV0c3ViCgoKLy8gdGVzdHMvYXJ0aWZhY3RzL3N0YXRlLW9wcy9zdGF0ZS1hY2N0LXBhcmFtcy1nZXQtY29udHJhY3QuYWxnby50czo6U3RhdGVBY2N0UGFyYW1zR2V0Q29udHJhY3QudmVyaWZ5X2FjY3RfdG90YWxfYXBwc19vcHRlZF9pbihhOiBieXRlcykgLT4gdWludDY0Ogp2ZXJpZnlfYWNjdF90b3RhbF9hcHBzX29wdGVkX2luOgogICAgLy8gdGVzdHMvYXJ0aWZhY3RzL3N0YXRlLW9wcy9zdGF0ZS1hY2N0LXBhcmFtcy1nZXQtY29udHJhY3QuYWxnby50czo3OC03OQogICAgLy8gQGFyYzQuYWJpbWV0aG9kKCkKICAgIC8vIHB1YmxpYyB2ZXJpZnlfYWNjdF90b3RhbF9hcHBzX29wdGVkX2luKGE6IEFjY291bnQpOiB1aW50NjQgewogICAgcHJvdG8gMSAxCiAgICAvLyB0ZXN0cy9hcnRpZmFjdHMvc3RhdGUtb3BzL3N0YXRlLWFjY3QtcGFyYW1zLWdldC1jb250cmFjdC5hbGdvLnRzOjgwCiAgICAvLyBjb25zdCBbdmFsdWUsIGZ1bmRlZF0gPSBvcC5BY2N0UGFyYW1zLmFjY3RUb3RhbEFwcHNPcHRlZEluKGEpCiAgICBmcmFtZV9kaWcgLTEKICAgIGFjY3RfcGFyYW1zX2dldCBBY2N0VG90YWxBcHBzT3B0ZWRJbgogICAgLy8gdGVzdHMvYXJ0aWZhY3RzL3N0YXRlLW9wcy9zdGF0ZS1hY2N0LXBhcmFtcy1nZXQtY29udHJhY3QuYWxnby50czo1CiAgICAvLyByZXR1cm4gb3AuYnRvaShUeG4uYXBwbGljYXRpb25BcmdzKDEpKQogICAgaW50Y18wIC8vIDEKICAgIHR4bmFzIEFwcGxpY2F0aW9uQXJncwogICAgYnRvaQogICAgLy8gdGVzdHMvYXJ0aWZhY3RzL3N0YXRlLW9wcy9zdGF0ZS1hY2N0LXBhcmFtcy1nZXQtY29udHJhY3QuYWxnby50czo4MQogICAgLy8gY29uc3QgW3ZhbHVlX2luZGV4LCBmdW5kZWRfaW5kZXhdID0gb3AuQWNjdFBhcmFtcy5hY2N0VG90YWxBcHBzT3B0ZWRJbihnZXRfMXN0X3JlZl9pbmRleCgpKQogICAgYWNjdF9wYXJhbXNfZ2V0IEFjY3RUb3RhbEFwcHNPcHRlZEluCiAgICAvLyB0ZXN0cy9hcnRpZmFjdHMvc3RhdGUtb3BzL3N0YXRlLWFjY3QtcGFyYW1zLWdldC1jb250cmFjdC5hbGdvLnRzOjgyCiAgICAvLyBhc3NlcnQodmFsdWUgPT09IHZhbHVlX2luZGV4LCAnZXhwZWN0ZWQgdmFsdWUgYnkgaW5kZXggdG8gbWF0Y2gnKQogICAgZGlnIDMKICAgIHVuY292ZXIgMgogICAgPT0KICAgIGFzc2VydCAvLyBleHBlY3RlZCB2YWx1ZSBieSBpbmRleCB0byBtYXRjaAogICAgLy8gdGVzdHMvYXJ0aWZhY3RzL3N0YXRlLW9wcy9zdGF0ZS1hY2N0LXBhcmFtcy1nZXQtY29udHJhY3QuYWxnby50czo4MwogICAgLy8gYXNzZXJ0KGZ1bmRlZCA9PT0gZnVuZGVkX2luZGV4LCAnZXhwZWN0ZWQgZnVuZGVkIGJ5IGluZGV4IHRvIG1hdGNoJykKICAgID09CiAgICBhc3NlcnQgLy8gZXhwZWN0ZWQgZnVuZGVkIGJ5IGluZGV4IHRvIG1hdGNoCiAgICAvLyB0ZXN0cy9hcnRpZmFjdHMvc3RhdGUtb3BzL3N0YXRlLWFjY3QtcGFyYW1zLWdldC1jb250cmFjdC5hbGdvLnRzOjg0CiAgICAvLyByZXR1cm4gdmFsdWUKICAgIHJldHN1YgoKCi8vIHRlc3RzL2FydGlmYWN0cy9zdGF0ZS1vcHMvc3RhdGUtYWNjdC1wYXJhbXMtZ2V0LWNvbnRyYWN0LmFsZ28udHM6OlN0YXRlQWNjdFBhcmFtc0dldENvbnRyYWN0LnZlcmlmeV9hY2N0X3RvdGFsX2Fzc2V0c19jcmVhdGVkKGE6IGJ5dGVzKSAtPiB1aW50NjQ6CnZlcmlmeV9hY2N0X3RvdGFsX2Fzc2V0c19jcmVhdGVkOgogICAgLy8gdGVzdHMvYXJ0aWZhY3RzL3N0YXRlLW9wcy9zdGF0ZS1hY2N0LXBhcmFtcy1nZXQtY29udHJhY3QuYWxnby50czo4Ny04OAogICAgLy8gQGFyYzQuYWJpbWV0aG9kKCkKICAgIC8vIHB1YmxpYyB2ZXJpZnlfYWNjdF90b3RhbF9hc3NldHNfY3JlYXRlZChhOiBBY2NvdW50KTogdWludDY0IHsKICAgIHByb3RvIDEgMQogICAgLy8gdGVzdHMvYXJ0aWZhY3RzL3N0YXRlLW9wcy9zdGF0ZS1hY2N0LXBhcmFtcy1nZXQtY29udHJhY3QuYWxnby50czo4OQogICAgLy8gY29uc3QgW3ZhbHVlLCBmdW5kZWRdID0gb3AuQWNjdFBhcmFtcy5hY2N0VG90YWxBc3NldHNDcmVhdGVkKGEpCiAgICBmcmFtZV9kaWcgLTEKICAgIGFjY3RfcGFyYW1zX2dldCBBY2N0VG90YWxBc3NldHNDcmVhdGVkCiAgICAvLyB0ZXN0cy9hcnRpZmFjdHMvc3RhdGUtb3BzL3N0YXRlLWFjY3QtcGFyYW1zLWdldC1jb250cmFjdC5hbGdvLnRzOjUKICAgIC8vIHJldHVybiBvcC5idG9pKFR4bi5hcHBsaWNhdGlvbkFyZ3MoMSkpCiAgICBpbnRjXzAgLy8gMQogICAgdHhuYXMgQXBwbGljYXRpb25BcmdzCiAgICBidG9pCiAgICAvLyB0ZXN0cy9hcnRpZmFjdHMvc3RhdGUtb3BzL3N0YXRlLWFjY3QtcGFyYW1zLWdldC1jb250cmFjdC5hbGdvLnRzOjkwCiAgICAvLyBjb25zdCBbdmFsdWVfaW5kZXgsIGZ1bmRlZF9pbmRleF0gPSBvcC5BY2N0UGFyYW1zLmFjY3RUb3RhbEFzc2V0c0NyZWF0ZWQoZ2V0XzFzdF9yZWZfaW5kZXgoKSkKICAgIGFjY3RfcGFyYW1zX2dldCBBY2N0VG90YWxBc3NldHNDcmVhdGVkCiAgICAvLyB0ZXN0cy9hcnRpZmFjdHMvc3RhdGUtb3BzL3N0YXRlLWFjY3QtcGFyYW1zLWdldC1jb250cmFjdC5hbGdvLnRzOjkxCiAgICAvLyBhc3NlcnQodmFsdWUgPT09IHZhbHVlX2luZGV4LCAnZXhwZWN0ZWQgdmFsdWUgYnkgaW5kZXggdG8gbWF0Y2gnKQogICAgZGlnIDMKICAgIHVuY292ZXIgMgogICAgPT0KICAgIGFzc2VydCAvLyBleHBlY3RlZCB2YWx1ZSBieSBpbmRleCB0byBtYXRjaAogICAgLy8gdGVzdHMvYXJ0aWZhY3RzL3N0YXRlLW9wcy9zdGF0ZS1hY2N0LXBhcmFtcy1nZXQtY29udHJhY3QuYWxnby50czo5MgogICAgLy8gYXNzZXJ0KGZ1bmRlZCA9PT0gZnVuZGVkX2luZGV4LCAnZXhwZWN0ZWQgZnVuZGVkIGJ5IGluZGV4IHRvIG1hdGNoJykKICAgID09CiAgICBhc3NlcnQgLy8gZXhwZWN0ZWQgZnVuZGVkIGJ5IGluZGV4IHRvIG1hdGNoCiAgICAvLyB0ZXN0cy9hcnRpZmFjdHMvc3RhdGUtb3BzL3N0YXRlLWFjY3QtcGFyYW1zLWdldC1jb250cmFjdC5hbGdvLnRzOjkzCiAgICAvLyByZXR1cm4gdmFsdWUKICAgIHJldHN1YgoKCi8vIHRlc3RzL2FydGlmYWN0cy9zdGF0ZS1vcHMvc3RhdGUtYWNjdC1wYXJhbXMtZ2V0LWNvbnRyYWN0LmFsZ28udHM6OlN0YXRlQWNjdFBhcmFtc0dldENvbnRyYWN0LnZlcmlmeV9hY2N0X3RvdGFsX2Fzc2V0cyhhOiBieXRlcykgLT4gdWludDY0Ogp2ZXJpZnlfYWNjdF90b3RhbF9hc3NldHM6CiAgICAvLyB0ZXN0cy9hcnRpZmFjdHMvc3RhdGUtb3BzL3N0YXRlLWFjY3QtcGFyYW1zLWdldC1jb250cmFjdC5hbGdvLnRzOjk2LTk3CiAgICAvLyBAYXJjNC5hYmltZXRob2QoKQogICAgLy8gcHVibGljIHZlcmlmeV9hY2N0X3RvdGFsX2Fzc2V0cyhhOiBBY2NvdW50KTogdWludDY0IHsKICAgIHByb3RvIDEgMQogICAgLy8gdGVzdHMvYXJ0aWZhY3RzL3N0YXRlLW9wcy9zdGF0ZS1hY2N0LXBhcmFtcy1nZXQtY29udHJhY3QuYWxnby50czo5OAogICAgLy8gY29uc3QgW3ZhbHVlLCBmdW5kZWRdID0gb3AuQWNjdFBhcmFtcy5hY2N0VG90YWxBc3NldHMoYSkKICAgIGZyYW1lX2RpZyAtMQogICAgYWNjdF9wYXJhbXNfZ2V0IEFjY3RUb3RhbEFzc2V0cwogICAgLy8gdGVzdHMvYXJ0aWZhY3RzL3N0YXRlLW9wcy9zdGF0ZS1hY2N0LXBhcmFtcy1nZXQtY29udHJhY3QuYWxnby50czo1CiAgICAvLyByZXR1cm4gb3AuYnRvaShUeG4uYXBwbGljYXRpb25BcmdzKDEpKQogICAgaW50Y18wIC8vIDEKICAgIHR4bmFzIEFwcGxpY2F0aW9uQXJncwogICAgYnRvaQogICAgLy8gdGVzdHMvYXJ0aWZhY3RzL3N0YXRlLW9wcy9zdGF0ZS1hY2N0LXBhcmFtcy1nZXQtY29udHJhY3QuYWxnby50czo5OQogICAgLy8gY29uc3QgW3ZhbHVlX2luZGV4LCBmdW5kZWRfaW5kZXhdID0gb3AuQWNjdFBhcmFtcy5hY2N0VG90YWxBc3NldHMoZ2V0XzFzdF9yZWZfaW5kZXgoKSkKICAgIGFjY3RfcGFyYW1zX2dldCBBY2N0VG90YWxBc3NldHMKICAgIC8vIHRlc3RzL2FydGlmYWN0cy9zdGF0ZS1vcHMvc3RhdGUtYWNjdC1wYXJhbXMtZ2V0LWNvbnRyYWN0LmFsZ28udHM6MTAwCiAgICAvLyBhc3NlcnQodmFsdWUgPT09IHZhbHVlX2luZGV4LCAnZXhwZWN0ZWQgdmFsdWUgYnkgaW5kZXggdG8gbWF0Y2gnKQogICAgZGlnIDMKICAgIHVuY292ZXIgMgogICAgPT0KICAgIGFzc2VydCAvLyBleHBlY3RlZCB2YWx1ZSBieSBpbmRleCB0byBtYXRjaAogICAgLy8gdGVzdHMvYXJ0aWZhY3RzL3N0YXRlLW9wcy9zdGF0ZS1hY2N0LXBhcmFtcy1nZXQtY29udHJhY3QuYWxnby50czoxMDEKICAgIC8vIGFzc2VydChmdW5kZWQgPT09IGZ1bmRlZF9pbmRleCwgJ2V4cGVjdGVkIGZ1bmRlZCBieSBpbmRleCB0byBtYXRjaCcpCiAgICA9PQogICAgYXNzZXJ0IC8vIGV4cGVjdGVkIGZ1bmRlZCBieSBpbmRleCB0byBtYXRjaAogICAgLy8gdGVzdHMvYXJ0aWZhY3RzL3N0YXRlLW9wcy9zdGF0ZS1hY2N0LXBhcmFtcy1nZXQtY29udHJhY3QuYWxnby50czoxMDIKICAgIC8vIHJldHVybiB2YWx1ZQogICAgcmV0c3ViCgoKLy8gdGVzdHMvYXJ0aWZhY3RzL3N0YXRlLW9wcy9zdGF0ZS1hY2N0LXBhcmFtcy1nZXQtY29udHJhY3QuYWxnby50czo6U3RhdGVBY2N0UGFyYW1zR2V0Q29udHJhY3QudmVyaWZ5X2FjY3RfdG90YWxfYm94ZXMoYTogYnl0ZXMpIC0+IHVpbnQ2NDoKdmVyaWZ5X2FjY3RfdG90YWxfYm94ZXM6CiAgICAvLyB0ZXN0cy9hcnRpZmFjdHMvc3RhdGUtb3BzL3N0YXRlLWFjY3QtcGFyYW1zLWdldC1jb250cmFjdC5hbGdvLnRzOjEwNS0xMDYKICAgIC8vIEBhcmM0LmFiaW1ldGhvZCgpCiAgICAvLyBwdWJsaWMgdmVyaWZ5X2FjY3RfdG90YWxfYm94ZXMoYTogQWNjb3VudCk6IHVpbnQ2NCB7CiAgICBwcm90byAxIDEKICAgIC8vIHRlc3RzL2FydGlmYWN0cy9zdGF0ZS1vcHMvc3RhdGUtYWNjdC1wYXJhbXMtZ2V0LWNvbnRyYWN0LmFsZ28udHM6MTA3CiAgICAvLyBjb25zdCBbdmFsdWUsIGZ1bmRlZF0gPSBvcC5BY2N0UGFyYW1zLmFjY3RUb3RhbEJveGVzKGEpCiAgICBmcmFtZV9kaWcgLTEKICAgIGFjY3RfcGFyYW1zX2dldCBBY2N0VG90YWxCb3hlcwogICAgLy8gdGVzdHMvYXJ0aWZhY3RzL3N0YXRlLW9wcy9zdGF0ZS1hY2N0LXBhcmFtcy1nZXQtY29udHJhY3QuYWxnby50czo1CiAgICAvLyByZXR1cm4gb3AuYnRvaShUeG4uYXBwbGljYXRpb25BcmdzKDEpKQogICAgaW50Y18wIC8vIDEKICAgIHR4bmFzIEFwcGxpY2F0aW9uQXJncwogICAgYnRvaQogICAgLy8gdGVzdHMvYXJ0aWZhY3RzL3N0YXRlLW9wcy9zdGF0ZS1hY2N0LXBhcmFtcy1nZXQtY29udHJhY3QuYWxnby50czoxMDgKICAgIC8vIGNvbnN0IFt2YWx1ZV9pbmRleCwgZnVuZGVkX2luZGV4XSA9IG9wLkFjY3RQYXJhbXMuYWNjdFRvdGFsQm94ZXMoZ2V0XzFzdF9yZWZfaW5kZXgoKSkKICAgIGFjY3RfcGFyYW1zX2dldCBBY2N0VG90YWxCb3hlcwogICAgLy8gdGVzdHMvYXJ0aWZhY3RzL3N0YXRlLW9wcy9zdGF0ZS1hY2N0LXBhcmFtcy1nZXQtY29udHJhY3QuYWxnby50czoxMDkKICAgIC8vIGFzc2VydCh2YWx1ZSA9PT0gdmFsdWVfaW5kZXgsICdleHBlY3RlZCB2YWx1ZSBieSBpbmRleCB0byBtYXRjaCcpCiAgICBkaWcgMwogICAgdW5jb3ZlciAyCiAgICA9PQogICAgYXNzZXJ0IC8vIGV4cGVjdGVkIHZhbHVlIGJ5IGluZGV4IHRvIG1hdGNoCiAgICAvLyB0ZXN0cy9hcnRpZmFjdHMvc3RhdGUtb3BzL3N0YXRlLWFjY3QtcGFyYW1zLWdldC1jb250cmFjdC5hbGdvLnRzOjExMAogICAgLy8gYXNzZXJ0KGZ1bmRlZCA9PT0gZnVuZGVkX2luZGV4LCAnZXhwZWN0ZWQgZnVuZGVkIGJ5IGluZGV4IHRvIG1hdGNoJykKICAgID09CiAgICBhc3NlcnQgLy8gZXhwZWN0ZWQgZnVuZGVkIGJ5IGluZGV4IHRvIG1hdGNoCiAgICAvLyB0ZXN0cy9hcnRpZmFjdHMvc3RhdGUtb3BzL3N0YXRlLWFjY3QtcGFyYW1zLWdldC1jb250cmFjdC5hbGdvLnRzOjExMQogICAgLy8gcmV0dXJuIHZhbHVlCiAgICByZXRzdWIKCgovLyB0ZXN0cy9hcnRpZmFjdHMvc3RhdGUtb3BzL3N0YXRlLWFjY3QtcGFyYW1zLWdldC1jb250cmFjdC5hbGdvLnRzOjpTdGF0ZUFjY3RQYXJhbXNHZXRDb250cmFjdC52ZXJpZnlfYWNjdF90b3RhbF9ib3hfYnl0ZXMoYTogYnl0ZXMpIC0+IHVpbnQ2NDoKdmVyaWZ5X2FjY3RfdG90YWxfYm94X2J5dGVzOgogICAgLy8gdGVzdHMvYXJ0aWZhY3RzL3N0YXRlLW9wcy9zdGF0ZS1hY2N0LXBhcmFtcy1nZXQtY29udHJhY3QuYWxnby50czoxMTQtMTE1CiAgICAvLyBAYXJjNC5hYmltZXRob2QoKQogICAgLy8gcHVibGljIHZlcmlmeV9hY2N0X3RvdGFsX2JveF9ieXRlcyhhOiBBY2NvdW50KTogdWludDY0IHsKICAgIHByb3RvIDEgMQogICAgLy8gdGVzdHMvYXJ0aWZhY3RzL3N0YXRlLW9wcy9zdGF0ZS1hY2N0LXBhcmFtcy1nZXQtY29udHJhY3QuYWxnby50czoxMTYKICAgIC8vIGNvbnN0IFt2YWx1ZSwgZnVuZGVkXSA9IG9wLkFjY3RQYXJhbXMuYWNjdFRvdGFsQm94Qnl0ZXMoYSkKICAgIGZyYW1lX2RpZyAtMQogICAgYWNjdF9wYXJhbXNfZ2V0IEFjY3RUb3RhbEJveEJ5dGVzCiAgICAvLyB0ZXN0cy9hcnRpZmFjdHMvc3RhdGUtb3BzL3N0YXRlLWFjY3QtcGFyYW1zLWdldC1jb250cmFjdC5hbGdvLnRzOjUKICAgIC8vIHJldHVybiBvcC5idG9pKFR4bi5hcHBsaWNhdGlvbkFyZ3MoMSkpCiAgICBpbnRjXzAgLy8gMQogICAgdHhuYXMgQXBwbGljYXRpb25BcmdzCiAgICBidG9pCiAgICAvLyB0ZXN0cy9hcnRpZmFjdHMvc3RhdGUtb3BzL3N0YXRlLWFjY3QtcGFyYW1zLWdldC1jb250cmFjdC5hbGdvLnRzOjExNwogICAgLy8gY29uc3QgW3ZhbHVlX2luZGV4LCBmdW5kZWRfaW5kZXhdID0gb3AuQWNjdFBhcmFtcy5hY2N0VG90YWxCb3hCeXRlcyhnZXRfMXN0X3JlZl9pbmRleCgpKQogICAgYWNjdF9wYXJhbXNfZ2V0IEFjY3RUb3RhbEJveEJ5dGVzCiAgICAvLyB0ZXN0cy9hcnRpZmFjdHMvc3RhdGUtb3BzL3N0YXRlLWFjY3QtcGFyYW1zLWdldC1jb250cmFjdC5hbGdvLnRzOjExOAogICAgLy8gYXNzZXJ0KHZhbHVlID09PSB2YWx1ZV9pbmRleCwgJ2V4cGVjdGVkIHZhbHVlIGJ5IGluZGV4IHRvIG1hdGNoJykKICAgIGRpZyAzCiAgICB1bmNvdmVyIDIKICAgID09CiAgICBhc3NlcnQgLy8gZXhwZWN0ZWQgdmFsdWUgYnkgaW5kZXggdG8gbWF0Y2gKICAgIC8vIHRlc3RzL2FydGlmYWN0cy9zdGF0ZS1vcHMvc3RhdGUtYWNjdC1wYXJhbXMtZ2V0LWNvbnRyYWN0LmFsZ28udHM6MTE5CiAgICAvLyBhc3NlcnQoZnVuZGVkID09PSBmdW5kZWRfaW5kZXgsICdleHBlY3RlZCBmdW5kZWQgYnkgaW5kZXggdG8gbWF0Y2gnKQogICAgPT0KICAgIGFzc2VydCAvLyBleHBlY3RlZCBmdW5kZWQgYnkgaW5kZXggdG8gbWF0Y2gKICAgIC8vIHRlc3RzL2FydGlmYWN0cy9zdGF0ZS1vcHMvc3RhdGUtYWNjdC1wYXJhbXMtZ2V0LWNvbnRyYWN0LmFsZ28udHM6MTIwCiAgICAvLyByZXR1cm4gdmFsdWUKICAgIHJldHN1YgoKCi8vIHRlc3RzL2FydGlmYWN0cy9zdGF0ZS1vcHMvc3RhdGUtYWNjdC1wYXJhbXMtZ2V0LWNvbnRyYWN0LmFsZ28udHM6OlN0YXRlQWNjdFBhcmFtc0dldENvbnRyYWN0LnZlcmlmeV9hY2N0X2luY2VudGl2ZV9lbGlnaWJsZShhOiBieXRlcykgLT4gdWludDY0Ogp2ZXJpZnlfYWNjdF9pbmNlbnRpdmVfZWxpZ2libGU6CiAgICAvLyB0ZXN0cy9hcnRpZmFjdHMvc3RhdGUtb3BzL3N0YXRlLWFjY3QtcGFyYW1zLWdldC1jb250cmFjdC5hbGdvLnRzOjEyMy0xMjQKICAgIC8vIEBhcmM0LmFiaW1ldGhvZCgpCiAgICAvLyBwdWJsaWMgdmVyaWZ5X2FjY3RfaW5jZW50aXZlX2VsaWdpYmxlKGE6IEFjY291bnQpOiBib29sZWFuIHsKICAgIHByb3RvIDEgMQogICAgLy8gdGVzdHMvYXJ0aWZhY3RzL3N0YXRlLW9wcy9zdGF0ZS1hY2N0LXBhcmFtcy1nZXQtY29udHJhY3QuYWxnby50czoxMjUKICAgIC8vIGNvbnN0IFt2YWx1ZSwgZnVuZGVkXSA9IG9wLkFjY3RQYXJhbXMuYWNjdEluY2VudGl2ZUVsaWdpYmxlKGEpCiAgICBmcmFtZV9kaWcgLTEKICAgIGFjY3RfcGFyYW1zX2dldCBBY2N0SW5jZW50aXZlRWxpZ2libGUKICAgIC8vIHRlc3RzL2FydGlmYWN0cy9zdGF0ZS1vcHMvc3RhdGUtYWNjdC1wYXJhbXMtZ2V0LWNvbnRyYWN0LmFsZ28udHM6NQogICAgLy8gcmV0dXJuIG9wLmJ0b2koVHhuLmFwcGxpY2F0aW9uQXJncygxKSkKICAgIGludGNfMCAvLyAxCiAgICB0eG5hcyBBcHBsaWNhdGlvbkFyZ3MKICAgIGJ0b2kKICAgIC8vIHRlc3RzL2FydGlmYWN0cy9zdGF0ZS1vcHMvc3RhdGUtYWNjdC1wYXJhbXMtZ2V0LWNvbnRyYWN0LmFsZ28udHM6MTI2CiAgICAvLyBjb25zdCBbdmFsdWVfaW5kZXgsIGZ1bmRlZF9pbmRleF0gPSBvcC5BY2N0UGFyYW1zLmFjY3RJbmNlbnRpdmVFbGlnaWJsZShnZXRfMXN0X3JlZl9pbmRleCgpKQogICAgYWNjdF9wYXJhbXNfZ2V0IEFjY3RJbmNlbnRpdmVFbGlnaWJsZQogICAgLy8gdGVzdHMvYXJ0aWZhY3RzL3N0YXRlLW9wcy9zdGF0ZS1hY2N0LXBhcmFtcy1nZXQtY29udHJhY3QuYWxnby50czoxMjcKICAgIC8vIGFzc2VydCh2YWx1ZSA9PT0gdmFsdWVfaW5kZXgsICdleHBlY3RlZCB2YWx1ZSBieSBpbmRleCB0byBtYXRjaCcpCiAgICBkaWcgMwogICAgdW5jb3ZlciAyCiAgICA9PQogICAgYXNzZXJ0IC8vIGV4cGVjdGVkIHZhbHVlIGJ5IGluZGV4IHRvIG1hdGNoCiAgICAvLyB0ZXN0cy9hcnRpZmFjdHMvc3RhdGUtb3BzL3N0YXRlLWFjY3QtcGFyYW1zLWdldC1jb250cmFjdC5hbGdvLnRzOjEyOAogICAgLy8gYXNzZXJ0KGZ1bmRlZCA9PT0gZnVuZGVkX2luZGV4LCAnZXhwZWN0ZWQgZnVuZGVkIGJ5IGluZGV4IHRvIG1hdGNoJykKICAgID09CiAgICBhc3NlcnQgLy8gZXhwZWN0ZWQgZnVuZGVkIGJ5IGluZGV4IHRvIG1hdGNoCiAgICAvLyB0ZXN0cy9hcnRpZmFjdHMvc3RhdGUtb3BzL3N0YXRlLWFjY3QtcGFyYW1zLWdldC1jb250cmFjdC5hbGdvLnRzOjEyOQogICAgLy8gcmV0dXJuIHZhbHVlCiAgICByZXRzdWIK", + "clear": "I3ByYWdtYSB2ZXJzaW9uIDExCiNwcmFnbWEgdHlwZXRyYWNrIGZhbHNlCgovLyBAYWxnb3JhbmRmb3VuZGF0aW9uL2FsZ29yYW5kLXR5cGVzY3JpcHQvYmFzZS1jb250cmFjdC5kLnRzOjpCYXNlQ29udHJhY3QuY2xlYXJTdGF0ZVByb2dyYW0oKSAtPiB1aW50NjQ6Cm1haW46CiAgICBwdXNoaW50IDEgLy8gMQogICAgcmV0dXJuCg==" + }, + "byteCode": { + "approval": "CyACAQAmAQQVH3x1MRtBAZSCDQRfW0PkBHPck8cEVibf6wTciiW/BBmOvYwEIwGrJgSfaPymBKl1wtEE0eBIAQS2lmvlBBldVBgEatrj8QTfjP7lNhoAjg0BGwEEAO4A1wDAAKkAkgB7AGQATQA2AB8AAiNDMRkURDEYRDYaARfAHIgCY4ABACNPAlQoTFCwIkMxGRREMRhENhoBF8AciAIwFihMULAiQzEZFEQxGEQ2GgEXwByIAgMWKExQsCJDMRkURDEYRDYaARfAHIgB1hYoTFCwIkMxGRREMRhENhoBF8AciAGpFihMULAiQzEZFEQxGEQ2GgEXwByIAXwWKExQsCJDMRkURDEYRDYaARfAHIgBTxYoTFCwIkMxGRREMRhENhoBF8AciAEiFihMULAiQzEZFEQxGEQ2GgEXwByIAPUWKExQsCJDMRkURDEYRDYaARfAHIgAyBYoTFCwIkMxGRREMRhENhoBF8AciACbKExQsCJDMRkURDEYRDYaARfAHIgAVxYoTFCwIkMxGRREMRhENhoBF8AciAASFihMULAiQzEZQP7JMRgURCJDigEBi/9zACLAGhdJcwBLBE8CEkRPAhJEi/9zAERLAhJEi/9gSwISRGBLARJEiYoBAYv/cwEiwBoXSXMBSwRPAhJETwISRIv/cwFESwISRIv/eEsCEkR4SwESRImKAQGL/3MCIsAaF3MCSwNPAhJEEkSJigEBi/9zAyLAGhdzA0sDTwISRBJEiYoBAYv/cwQiwBoXcwRLA08CEkQSRImKAQGL/3MFIsAaF3MFSwNPAhJEEkSJigEBi/9zBiLAGhdzBksDTwISRBJEiYoBAYv/cwciwBoXcwdLA08CEkQSRImKAQGL/3MIIsAaF3MISwNPAhJEEkSJigEBi/9zCSLAGhdzCUsDTwISRBJEiYoBAYv/cwoiwBoXcwpLA08CEkQSRImKAQGL/3MLIsAaF3MLSwNPAhJEEkSJigEBi/9zDCLAGhdzDEsDTwISRBJEiQ==", + "clear": "C4EBQw==" + }, + "compilerInfo": { + "compiler": "puya", + "compilerVersion": { + "major": 4, + "minor": 1, + "patch": 1 + } }, "events": [], "templateVariables": {} diff --git a/tests/artifacts/state-ops/data/StateAcctParamsGetContract.clear.teal b/tests/artifacts/state-ops/data/StateAcctParamsGetContract.clear.teal index c48a376..42f81b0 100644 --- a/tests/artifacts/state-ops/data/StateAcctParamsGetContract.clear.teal +++ b/tests/artifacts/state-ops/data/StateAcctParamsGetContract.clear.teal @@ -1,5 +1,7 @@ -#pragma version 10 +#pragma version 11 +#pragma typetrack false -tests/artifacts/state-ops/contract.algo.ts::StateAcctParamsGetContract.clearStateProgram: +// @algorandfoundation/algorand-typescript/base-contract.d.ts::BaseContract.clearStateProgram() -> uint64: +main: pushint 1 // 1 return diff --git a/tests/artifacts/state-ops/state-acct-params-get-contract.algo.ts b/tests/artifacts/state-ops/state-acct-params-get-contract.algo.ts new file mode 100644 index 0000000..fd7514c --- /dev/null +++ b/tests/artifacts/state-ops/state-acct-params-get-contract.algo.ts @@ -0,0 +1,131 @@ +import { Account, arc4, assert, op, Txn, uint64 } from '@algorandfoundation/algorand-typescript' +import { Address } from '@algorandfoundation/algorand-typescript/arc4' + +function get_1st_ref_index(): uint64 { + return op.btoi(Txn.applicationArgs(1)) +} + +export class StateAcctParamsGetContract extends arc4.Contract { + @arc4.abimethod() + public verify_acct_balance(a: Account): uint64 { + const [value, funded] = op.AcctParams.acctBalance(a) + const [value_index, funded_index] = op.AcctParams.acctBalance(get_1st_ref_index()) + assert(value === value_index, 'expected value by index to match') + assert(funded === funded_index, 'expected funded by index to match') + assert(value === a.balance, 'expected Account balance to match') + assert(value === op.balance(a), 'expected op.balance to match') + assert(value === op.balance(get_1st_ref_index()), 'expected op.balance by index to match') + return value + } + + @arc4.abimethod() + public verify_acct_min_balance(a: Account): uint64 { + const [value, funded] = op.AcctParams.acctMinBalance(a) + const [value_index, funded_index] = op.AcctParams.acctMinBalance(get_1st_ref_index()) + assert(value === value_index, 'expected value by index to match') + assert(funded === funded_index, 'expected funded by index to match') + assert(value === a.minBalance, 'expected Account min_balance to match') + assert(value === op.minBalance(a), 'expected op.min_balance to match') + assert(value === op.minBalance(get_1st_ref_index()), 'expected op.min_balance by index to match') + return value + } + + @arc4.abimethod() + public verify_acct_auth_addr(a: Account): Address { + const [value, funded] = op.AcctParams.acctAuthAddr(a) + const [value_index, funded_index] = op.AcctParams.acctAuthAddr(get_1st_ref_index()) + assert(value === value_index, 'expected value by index to match') + assert(funded === funded_index, 'expected funded by index to match') + return new Address(value) + } + + @arc4.abimethod() + public verify_acct_total_num_uint(a: Account): uint64 { + const [value, funded] = op.AcctParams.acctTotalNumUint(a) + const [value_index, funded_index] = op.AcctParams.acctTotalNumUint(get_1st_ref_index()) + assert(value === value_index, 'expected value by index to match') + assert(funded === funded_index, 'expected funded by index to match') + return value + } + + @arc4.abimethod() + public verify_acct_total_num_byte_slice(a: Account): uint64 { + const [value, funded] = op.AcctParams.acctTotalNumByteSlice(a) + const [value_index, funded_index] = op.AcctParams.acctTotalNumByteSlice(get_1st_ref_index()) + assert(value === value_index, 'expected value by index to match') + assert(funded === funded_index, 'expected funded by index to match') + return value + } + + @arc4.abimethod() + public verify_acct_total_extra_app_pages(a: Account): uint64 { + const [value, funded] = op.AcctParams.acctTotalExtraAppPages(a) + const [value_index, funded_index] = op.AcctParams.acctTotalExtraAppPages(get_1st_ref_index()) + assert(value === value_index, 'expected value by index to match') + assert(funded === funded_index, 'expected funded by index to match') + return value + } + + @arc4.abimethod() + public verify_acct_total_apps_created(a: Account): uint64 { + const [value, funded] = op.AcctParams.acctTotalAppsCreated(a) + const [value_index, funded_index] = op.AcctParams.acctTotalAppsCreated(get_1st_ref_index()) + assert(value === value_index, 'expected value by index to match') + assert(funded === funded_index, 'expected funded by index to match') + return value + } + + @arc4.abimethod() + public verify_acct_total_apps_opted_in(a: Account): uint64 { + const [value, funded] = op.AcctParams.acctTotalAppsOptedIn(a) + const [value_index, funded_index] = op.AcctParams.acctTotalAppsOptedIn(get_1st_ref_index()) + assert(value === value_index, 'expected value by index to match') + assert(funded === funded_index, 'expected funded by index to match') + return value + } + + @arc4.abimethod() + public verify_acct_total_assets_created(a: Account): uint64 { + const [value, funded] = op.AcctParams.acctTotalAssetsCreated(a) + const [value_index, funded_index] = op.AcctParams.acctTotalAssetsCreated(get_1st_ref_index()) + assert(value === value_index, 'expected value by index to match') + assert(funded === funded_index, 'expected funded by index to match') + return value + } + + @arc4.abimethod() + public verify_acct_total_assets(a: Account): uint64 { + const [value, funded] = op.AcctParams.acctTotalAssets(a) + const [value_index, funded_index] = op.AcctParams.acctTotalAssets(get_1st_ref_index()) + assert(value === value_index, 'expected value by index to match') + assert(funded === funded_index, 'expected funded by index to match') + return value + } + + @arc4.abimethod() + public verify_acct_total_boxes(a: Account): uint64 { + const [value, funded] = op.AcctParams.acctTotalBoxes(a) + const [value_index, funded_index] = op.AcctParams.acctTotalBoxes(get_1st_ref_index()) + assert(value === value_index, 'expected value by index to match') + assert(funded === funded_index, 'expected funded by index to match') + return value + } + + @arc4.abimethod() + public verify_acct_total_box_bytes(a: Account): uint64 { + const [value, funded] = op.AcctParams.acctTotalBoxBytes(a) + const [value_index, funded_index] = op.AcctParams.acctTotalBoxBytes(get_1st_ref_index()) + assert(value === value_index, 'expected value by index to match') + assert(funded === funded_index, 'expected funded by index to match') + return value + } + + @arc4.abimethod() + public verify_acct_incentive_eligible(a: Account): boolean { + const [value, funded] = op.AcctParams.acctIncentiveEligible(a) + const [value_index, funded_index] = op.AcctParams.acctIncentiveEligible(get_1st_ref_index()) + assert(value === value_index, 'expected value by index to match') + assert(funded === funded_index, 'expected funded by index to match') + return value + } +} diff --git a/tests/avm-invoker.ts b/tests/avm-invoker.ts index 844ff7c..5705667 100644 --- a/tests/avm-invoker.ts +++ b/tests/avm-invoker.ts @@ -6,6 +6,7 @@ import { AssetCreateParams } from '@algorandfoundation/algokit-utils/types/compo import { KmdAccountManager } from '@algorandfoundation/algokit-utils/types/kmd-account-manager' import { nullLogger } from '@algorandfoundation/algokit-utils/types/logging' import { Account, Bytes, internal, uint64 } from '@algorandfoundation/algorand-typescript' +import { AccountImpl } from '@algorandfoundation/algorand-typescript-testing/runtime-helpers' import { randomUUID } from 'crypto' import { Mutable } from '../src/typescript-helpers' import { asUint64, getRandomBigInt, getRandomNumber, Lazy } from '../src/util' @@ -14,15 +15,33 @@ export type ABIValue = boolean | number | bigint | string | Uint8Array | ABIValu algokit.Config.configure({ logger: nullLogger }) -const algorandClient = Lazy(() => algokit.AlgorandClient.defaultLocalNet()) +const algorandClient = Lazy(() => { + const client = algokit.AlgorandClient.defaultLocalNet() + client.setDefaultValidityWindow(1000) + return client +}) export const INITIAL_BALANCE_MICRO_ALGOS = Number(20e6) +export const getAlgorandAppClientV11 = async (appSpec: AppSpec) => { + if ((await getAlgodMajorVersion()) < 4) { + return undefined + } + const [appClient, _] = await getAlgorandAppClientWithApp(appSpec) + return appClient +} + export const getAlgorandAppClient = async (appSpec: AppSpec) => { const [appClient, _] = await getAlgorandAppClientWithApp(appSpec) return appClient } +export const getAlgodMajorVersion = async () => { + const algorand = algorandClient() + const version = await algorand.client.algod.versionsCheck().do() + return version.build.major +} + export const getAlgorandAppClientWithApp = async (appSpec: AppSpec) => { const algorand = algorandClient() const defaultSigner = await algorand.account.kmd.getLocalNetDispenserAccount() @@ -91,7 +110,7 @@ export const generateAVMTestAccount = async (): Promise => { const account = await generateAVMTestAccount() - return Account(Bytes.fromBase32(account.addr.toString())) + return AccountImpl(Bytes.fromBase32(account.addr.toString())) } export const generateTestAsset = async (fields: Mutable): Promise => { diff --git a/tests/crypto-op-codes.spec.ts b/tests/crypto-op-codes.spec.ts index 2875019..8c006ba 100644 --- a/tests/crypto-op-codes.spec.ts +++ b/tests/crypto-op-codes.spec.ts @@ -1,15 +1,16 @@ import { AlgoAmount } from '@algorandfoundation/algokit-utils/types/amount' import { AppSpec } from '@algorandfoundation/algokit-utils/types/app-spec' import { Bytes, Ec, Ecdsa, internal, uint64, VrfVerify } from '@algorandfoundation/algorand-typescript' -import { ec } from 'elliptic' -import { keccak256 as js_keccak256 } from 'js-sha3' -import { sha512_256 as js_sha512_256 } from 'js-sha512' +import elliptic from 'elliptic' +import js_sha3 from 'js-sha3' +import js_sha512 from 'js-sha512' import nacl from 'tweetnacl' import { afterEach, describe, expect, it, Mock, test, vi } from 'vitest' import { TestExecutionContext } from '../src' import { LOGIC_DATA_PREFIX, MAX_BYTES_SIZE, PROGRAM_TAG } from '../src/constants' import * as op from '../src/impl/crypto' -import { asUint8Array, conactUint8Arrays, decodePublicKey } from '../src/util' +import { decodePublicKey } from '../src/impl/reference' +import { asUint8Array, conactUint8Arrays } from '../src/util' import appSpecJson from './artifacts/crypto-ops/data/CryptoOpsContract.arc32.json' import { generateAVMTestAccount, getAlgorandAppClientWithApp, getAvmResult } from './avm-invoker' import { getPaddedBytes } from './util' @@ -122,7 +123,7 @@ describe('crypto op codes', async () => { const account = await generateAVMTestAccount() const publicKey = decodePublicKey(account.addr.toString()) const logicSig = conactUint8Arrays(asUint8Array(PROGRAM_TAG), approval.compiledBase64ToBytes) - const logicSigAddress = js_sha512_256.array(logicSig) + const logicSigAddress = js_sha512.sha512_256.array(logicSig) const parts = conactUint8Arrays(new Uint8Array(logicSigAddress), asUint8Array(message)) const toBeSigned = conactUint8Arrays(asUint8Array(LOGIC_DATA_PREFIX), parts) const signature = nacl.sign.detached(toBeSigned, account.account.sk) @@ -234,7 +235,7 @@ describe('crypto op codes', async () => { it('should be able to decompress k1 public key', async () => { const v = Ecdsa.Secp256k1 const testData = generateEcdsaTestData(v) - const ecdsa = new ec(curveMap[v]) + const ecdsa = new elliptic.ec(curveMap[v]) const keyPair = ecdsa.keyFromPublic(testData.pubkeyX.concat(testData.pubkeyY).asUint8Array()) const pubKeyArray = new Uint8Array(keyPair.getPublic(true, 'array')) const avmResult = await getAvmResult( @@ -298,11 +299,11 @@ describe('crypto op codes', async () => { }) const generateEcdsaTestData = (v: Ecdsa) => { - const ecdsa = new ec(curveMap[v]) + const ecdsa = new elliptic.ec(curveMap[v]) const keyPair = ecdsa.genKeyPair() const pk = keyPair.getPublic('array') const data = internal.primitives.BytesCls.fromCompat('test data for ecdsa') - const messageHash = js_keccak256.create().update(data.asUint8Array()).digest() + const messageHash = js_sha3.keccak256.create().update(data.asUint8Array()).digest() const signature = keyPair.sign(messageHash) const recoveryId = 0 // Recovery ID is typically 0 or 1 diff --git a/tests/references/asset.spec.ts b/tests/references/asset.spec.ts index 980d72c..1e85144 100644 --- a/tests/references/asset.spec.ts +++ b/tests/references/asset.spec.ts @@ -1,7 +1,7 @@ import { Account, Bytes, Uint64 } from '@algorandfoundation/algorand-typescript' import { afterEach, describe, expect, it, test } from 'vitest' import { TestExecutionContext } from '../../src' -import { AssetCls } from '../../src/impl/asset' +import { AssetCls } from '../../src/impl/reference' import { asBytes, asUint64, asUint8Array } from '../../src/util' describe('Asset', () => { diff --git a/tests/state-op-codes.spec.ts b/tests/state-op-codes.spec.ts index 84326de..86843b5 100644 --- a/tests/state-op-codes.spec.ts +++ b/tests/state-op-codes.spec.ts @@ -1,23 +1,23 @@ import { AlgoAmount } from '@algorandfoundation/algokit-utils/types/amount' import { AppClient } from '@algorandfoundation/algokit-utils/types/app-client' import { AppSpec } from '@algorandfoundation/algokit-utils/types/app-spec' -import { Account, arc4, bytes, Bytes, internal, op, TransactionType, uint64, Uint64 } from '@algorandfoundation/algorand-typescript' +import { Account, arc4, bytes, Bytes, Global, internal, op, TransactionType, uint64, Uint64 } from '@algorandfoundation/algorand-typescript' import { DynamicBytes, UintN64 } from '@algorandfoundation/algorand-typescript/arc4' import { afterEach, describe, expect, it, test } from 'vitest' import { TestExecutionContext } from '../src' import { ABI_RETURN_VALUE_LOG_PREFIX, MIN_TXN_FEE, OnApplicationComplete, ZERO_ADDRESS } from '../src/constants' +import { lazyContext } from '../src/context-helpers/internal-context' import { testInvariant } from '../src/errors' import { Block, gloadBytes, gloadUint64 } from '../src/impl' -import { AccountCls } from '../src/impl/account' import { InnerTxn } from '../src/impl/itxn' +import { AccountCls, encodeAddress } from '../src/impl/reference' import { ApplicationTransaction } from '../src/impl/transactions' import { DeliberateAny } from '../src/typescript-helpers' -import { asBigInt, asNumber, asUint64Cls, asUint8Array } from '../src/util' +import { asBigInt, asBigUintCls, asNumber, asUint64Cls, asUint8Array, getRandomBytes } from '../src/util' import { AppExpectingEffects } from './artifacts/created-app-asset/contract.algo' import { ItxnDemoContract, ITxnOpsContract, - StateAcctParamsGetContract, StateAppGlobalContract, StateAppGlobalExContract, StateAppLocalContract, @@ -34,10 +34,13 @@ import appLocalExAppSpecJson from './artifacts/state-ops/data/StateAppLocalExCon import appParamsAppSpecJson from './artifacts/state-ops/data/StateAppParamsContract.arc32.json' import assetHoldingAppSpecJson from './artifacts/state-ops/data/StateAssetHoldingContract.arc32.json' import assetParamsAppSpecJson from './artifacts/state-ops/data/StateAssetParamsContract.arc32.json' +import { StateAcctParamsGetContract } from './artifacts/state-ops/state-acct-params-get-contract.algo' import { generateTestAccount, generateTestAsset, + getAlgodMajorVersion, getAlgorandAppClient, + getAlgorandAppClientV11, getAlgorandAppClientWithApp, getAvmResult, getLocalNetDefaultAccount, @@ -46,13 +49,15 @@ import { describe('State op codes', async () => { const ctx = new TestExecutionContext() + const algodVersion = await getAlgodMajorVersion() + const isV11Supported = algodVersion > 4 afterEach(async () => { ctx.reset() }) - describe('AcctParams', async () => { - const [appClient, dummyAccount] = await Promise.all([getAlgorandAppClient(acctParamsAppSpecJson as AppSpec), generateTestAccount()]) + describe.skipIf(!isV11Supported)('AcctParams', async () => { + const [appClient, dummyAccount] = await Promise.all([getAlgorandAppClientV11(acctParamsAppSpecJson as AppSpec), generateTestAccount()]) test.each([ ['verify_acct_balance', INITIAL_BALANCE_MICRO_ALGOS + 100_000], @@ -85,7 +90,7 @@ describe('State op codes', async () => { }) const avmResult = await getAvmResult( - { appClient, sendParams: { staticFee: AlgoAmount.Algos(1000) } }, + { appClient: appClient!, sendParams: { staticFee: AlgoAmount.Algos(1000) } }, methodName, asUint8Array(dummyAccount.bytes), ) @@ -96,6 +101,58 @@ describe('State op codes', async () => { expect(mockResult).toEqual(avmResult) expect(mockResult).toEqual(expectedValue) }) + + it('should return true when account is eligible for incentive', async () => { + const mockAccount = ctx.any.account({ + address: dummyAccount, + balance: Uint64(INITIAL_BALANCE_MICRO_ALGOS + 100000), + minBalance: Uint64(100000), + }) + ctx.ledger.patchGlobalData({ payoutsEnabled: true, payoutsGoOnlineFee: 10 }) + ctx.txn.createScope([ctx.any.txn.keyRegistration({ sender: mockAccount, fee: 10 })]).execute(() => { + expect(op.AcctParams.acctIncentiveEligible(mockAccount)).toEqual([true, true]) + }) + + await appClient!.algorand.send.onlineKeyRegistration({ + sender: encodeAddress(asUint8Array(dummyAccount.bytes)), + voteKey: getRandomBytes(32).asUint8Array(), + selectionKey: getRandomBytes(32).asUint8Array(), + voteFirst: 1n, + voteLast: 1000000n, + voteKeyDilution: 1000000n, + stateProofKey: getRandomBytes(64).asUint8Array(), + staticFee: AlgoAmount.Algos(10), + }) + const avmResult = await getAvmResult( + { appClient: appClient!, sendParams: { staticFee: AlgoAmount.Algos(10) } }, + 'verify_acct_incentive_eligible', + asUint8Array(dummyAccount.bytes), + ) + expect(avmResult).toEqual(true) + }) + + it('should return last round as last proposed and last hearbeat by default', () => { + const mockAccount = ctx.any.account({ + address: dummyAccount, + balance: Uint64(INITIAL_BALANCE_MICRO_ALGOS + 100000), + }) + const lastProposed = op.AcctParams.acctLastProposed(mockAccount) + const lastHeartbeat = op.AcctParams.acctLastHeartbeat(mockAccount) + expect(lastProposed).toEqual([Global.round, true]) + expect(lastHeartbeat).toEqual([Global.round, true]) + }) + + it('should return configured round as last proposed and last hearbeat', () => { + const mockAccount = ctx.any.account({ + address: dummyAccount, + balance: Uint64(INITIAL_BALANCE_MICRO_ALGOS + 100000), + }) + ctx.ledger.patchAccountData(mockAccount, { lastProposed: 100, lastHeartbeat: 200 }) + const lastProposed = op.AcctParams.acctLastProposed(mockAccount) + const lastHeartbeat = op.AcctParams.acctLastHeartbeat(mockAccount) + expect(lastProposed).toEqual([100, true]) + expect(lastHeartbeat).toEqual([200, true]) + }) }) describe('AppParams', async () => { @@ -235,6 +292,25 @@ describe('State op codes', async () => { }) }) + describe('VoterParams', async () => { + it('should return the configured balance and incentive eligibility', async () => { + const mockAccount = ctx.any.account() + ctx.ledger.patchVoterData(mockAccount, { balance: 100, incentiveEligible: true }) + const balance = op.VoterParams.voterBalance(mockAccount) + const incentiveEligible = op.VoterParams.voterIncentiveEligible(mockAccount) + expect(balance).toEqual([100, true]) + expect(incentiveEligible).toEqual([true, true]) + }) + }) + + describe('onlineStake', async () => { + it('should return the configured online stake', async () => { + lazyContext.ledger.onlineStake = Uint64(42) + const result = op.onlineStake() + expect(result).toEqual(42) + }) + }) + describe('Global', async () => { it('should return the correct global field value', async () => { const creator = ctx.any.account() @@ -272,6 +348,18 @@ describe('State op codes', async () => { }) expect([...asUint8Array(firstGroupId)]).not.toEqual([...asUint8Array(secondGroupId)]) expect(firstTimestamp.valueOf()).not.toEqual(secondTimestamp.valueOf()) + + ctx.ledger.patchGlobalData({ + payoutsEnabled: true, + payoutsGoOnlineFee: 12, + payoutsPercent: 2, + payoutsMinBalance: 42, + }) + + expect(op.Global.payoutsEnabled).toEqual(true) + expect(op.Global.payoutsGoOnlineFee).toEqual(12) + expect(op.Global.payoutsPercent).toEqual(2) + expect(op.Global.payoutsMinBalance).toEqual(42) }) }) @@ -427,14 +515,40 @@ describe('State op codes', async () => { describe('Block', async () => { it('should return the correct field value of the block', async () => { const index = 42 - const seed = 123 + const seed = asBigUintCls(123n).toBytes().asAlgoTs() const timestamp = 1234567890 - ctx.ledger.setBlock(index, seed, timestamp) - const seedResult = op.btoi(Block.blkSeed(Uint64(index))) - const timestampResult = Block.blkTimestamp(Uint64(index)) + const proposer = ctx.any.account() + const feesCollected = 1000 + const bonus = 12 + const branch = getRandomBytes(32).asAlgoTs() + const feeSink = ctx.any.account() + const protocol = getRandomBytes(32).asAlgoTs() + const txnCounter = 32 + const proposerPayout = 42 + + ctx.ledger.patchBlockData(index, { + seed, + timestamp, + proposer, + feesCollected, + bonus, + branch, + feeSink, + protocol, + txnCounter, + proposerPayout, + }) - expect(seedResult).toEqual(Uint64(seed)) - expect(timestampResult).toEqual(Uint64(timestamp)) + expect(Block.blkSeed(index)).toEqual(seed) + expect(Block.blkTimestamp(index)).toEqual(timestamp) + expect(Block.blkProposer(index)).toEqual(proposer) + expect(Block.blkFeesCollected(index)).toEqual(feesCollected) + expect(Block.blkBonus(index)).toEqual(bonus) + expect(Block.blkBranch(index)).toEqual(branch) + expect(Block.blkFeeSink(index)).toEqual(feeSink) + expect(Block.blkProtocol(index)).toEqual(protocol) + expect(Block.blkTxnCounter(index)).toEqual(txnCounter) + expect(Block.blkProposerPayout(index)).toEqual(proposerPayout) }) it('should throw error if the block is not set', async () => { const index = 42