diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 00000000..17a5772f --- /dev/null +++ b/.dockerignore @@ -0,0 +1,3 @@ +nodemgr/.env.sandbox +**/node_modules/ +go.work diff --git a/.github/workflows/release.yaml b/.github/workflows/release.yaml new file mode 100644 index 00000000..717345f3 --- /dev/null +++ b/.github/workflows/release.yaml @@ -0,0 +1,28 @@ +on: + release: + types: [created] + +permissions: + contents: write + packages: write + +jobs: + releases-matrix: + name: Release Go Binary + runs-on: ubuntu-latest + strategy: + matrix: + # build and publish in parallel: linux/windows/darwin, amd64/arm64 + goos: [linux, windows, darwin] + goarch: [amd64, arm64] + steps: + - uses: actions/checkout@v4 + - uses: wangyoucao577/go-release-action@v1 + with: + github_token: ${{ secrets.GITHUB_TOKEN }} + goos: ${{ matrix.goos }} + goarch: ${{ matrix.goarch }} + extra_files: LICENSE README.md + goversion: '1.21' + project_path: './nodemgr' + diff --git a/.gitignore b/.gitignore new file mode 100644 index 00000000..e4ffe156 --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +.env.* +node_modules/ diff --git a/.idea/.gitignore b/.idea/.gitignore new file mode 100644 index 00000000..13566b81 --- /dev/null +++ b/.idea/.gitignore @@ -0,0 +1,8 @@ +# Default ignored files +/shelf/ +/workspace.xml +# Editor-based HTTP Client requests +/httpRequests/ +# Datasource local storage ignored files +/dataSources/ +/dataSources.local.xml diff --git a/.idea/codeStyles/codeStyleConfig.xml b/.idea/codeStyles/codeStyleConfig.xml new file mode 100644 index 00000000..a55e7a17 --- /dev/null +++ b/.idea/codeStyles/codeStyleConfig.xml @@ -0,0 +1,5 @@ + + + + \ No newline at end of file diff --git a/.idea/inspectionProfiles/Project_Default.xml b/.idea/inspectionProfiles/Project_Default.xml new file mode 100644 index 00000000..03d9549e --- /dev/null +++ b/.idea/inspectionProfiles/Project_Default.xml @@ -0,0 +1,6 @@ + + + + \ No newline at end of file diff --git a/.idea/jsLibraryMappings.xml b/.idea/jsLibraryMappings.xml new file mode 100644 index 00000000..afac610d --- /dev/null +++ b/.idea/jsLibraryMappings.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/.idea/modules.xml b/.idea/modules.xml new file mode 100644 index 00000000..2a12fc64 --- /dev/null +++ b/.idea/modules.xml @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/.idea/reti.iml b/.idea/reti.iml new file mode 100644 index 00000000..67d7a984 --- /dev/null +++ b/.idea/reti.iml @@ -0,0 +1,11 @@ + + + + + + + + + + + diff --git a/.idea/vcs.xml b/.idea/vcs.xml new file mode 100644 index 00000000..35eb1ddf --- /dev/null +++ b/.idea/vcs.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 00000000..0d66da72 --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,8 @@ +{ + "editor.formatOnSave": true, + "editor.defaultFormatter": "esbenp.prettier-vscode", + "editor.codeActionsOnSave": { + "source.fixAll.eslint": "explicit" + }, + "typescript.tsdk": "./ui/node_modules/typescript/lib" +} diff --git a/CODEOWNERS b/CODEOWNERS new file mode 100644 index 00000000..b60da01c --- /dev/null +++ b/CODEOWNERS @@ -0,0 +1,5 @@ +* @pbennett @drichar +/contracts/ @pbennett +/nodemgr/ @pbennett +/ui/ @drichar +/docs/ @johnmizz diff --git a/Dockerfile-nodemgr b/Dockerfile-nodemgr new file mode 100644 index 00000000..541233ec --- /dev/null +++ b/Dockerfile-nodemgr @@ -0,0 +1,23 @@ +FROM golang:1.21-alpine as builder +# Install git and certificates +RUN apk --no-cache add tzdata zip ca-certificates git +# Make repository path +RUN mkdir -p /go/src/app +WORKDIR /go/src/app + +# just fetch the dependencies in a cachable layer +COPY nodemgr/go.* ./nodemgr/ +RUN cd nodemgr && go mod download && cd .. + +# Copy all project files (.env's are skipped due to .dockerignore) +COPY . ./ +RUN --mount=type=cache,target=/root/.cache/go-build env CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -C nodemgr -v -o /out/ . + +FROM scratch + +WORKDIR /app + +COPY --from=builder /etc/ssl/certs/ca-certificates.crt /etc/ssl/certs/ +COPY --from=builder /out/* /app/ + +ENTRYPOINT ["/app/reti"] diff --git a/LICENSE b/LICENSE index 8ff17c46..e19fbfa1 100644 --- a/LICENSE +++ b/LICENSE @@ -1,6 +1,6 @@ MIT License -Copyright (c) 2024 TxnLab Inc +Copyright (c) 2024 Algorand Foundation Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/Makefile b/Makefile new file mode 100644 index 00000000..e21265bf --- /dev/null +++ b/Makefile @@ -0,0 +1,19 @@ +.PHONY: none load_env docker-push docker-build + +.DEFAULT_GOAL := none + +none: + @echo bleha bleah + +IMAGE_REPO ?= us-central1-docker.pkg.dev/nfd-nodes/nodes + +# preference would be to fetch version from latest vX.X tag in git +VERSION ?= latest + +IMAGE := reti:$(VERSION) + +docker-build: + docker build --no-cache --platform linux/amd64 -f Dockerfile-nodemgr -t $(IMAGE_REPO)/$(IMAGE) . + +docker-push: docker-build + docker push $(IMAGE_REPO)/$(IMAGE) diff --git a/README.md b/README.md index acd41d6d..dfc636cf 100644 --- a/README.md +++ b/README.md @@ -1,2 +1,13 @@ -# reti -Contracts and node sidecar for Algorand 'The Reti' consensus incentives +# Reti Open Pooling + +See [Reti Open Pooling](./docs/reti-open-pooling.md) for details on the proposal this implementation is for. + +## Tealscript Contracts + +See [Contracts](./contracts/README.md) + +## Node Daemon + +## UI + +See [UI](./ui/README.md) diff --git a/contracts/.devcontainer.json b/contracts/.devcontainer.json new file mode 100644 index 00000000..3a30b2f9 --- /dev/null +++ b/contracts/.devcontainer.json @@ -0,0 +1,16 @@ +{ + "forwardPorts": [4001, 4002, 8980], + "portsAttributes": { + "4001": { + "label": "algod" + }, + "4002": { + "label": "kmd" + }, + "8980": { + "label": "indexer" + } + }, + "postCreateCommand": "pipx install algokit-cli", + "postStartCommand": "algokit localnet start" +} \ No newline at end of file diff --git a/contracts/.eslintrc.js b/contracts/.eslintrc.js new file mode 100644 index 00000000..55dd2a98 --- /dev/null +++ b/contracts/.eslintrc.js @@ -0,0 +1,77 @@ +module.exports = { + env: { + browser: true, + es2021: true, + }, + extends: [ + 'airbnb-base', + 'plugin:import/errors', + 'plugin:import/warnings', + 'plugin:import/typescript', + 'plugin:prettier/recommended', + ], + parser: '@typescript-eslint/parser', + parserOptions: { + ecmaVersion: 'latest', + sourceType: 'module', + }, + plugins: ['@typescript-eslint'], + rules: { + '@typescript-eslint/no-explicit-any': 'error', + '@typescript-eslint/ban-ts-comment': 'warn', + 'import/prefer-default-export': 'off', + 'import/extensions': [ + 'error', + 'ignorePackages', + { + js: 'never', + jsx: 'never', + ts: 'never', + tsx: 'never', + }, + ], + 'import/no-extraneous-dependencies': [ + 'error', + { + devDependencies: ['**/*.test.ts'], + }, + ], + 'prettier/prettier': [ + 'error', + { + tabWidth: 4, + }, + ], + }, + overrides: [ + { + files: ['*.ts'], + rules: { + 'no-continue': 'off', + }, + }, + { + files: ['*.algo.ts'], + rules: { + 'import/no-extraneous-dependencies': 'off', + 'object-shorthand': 'off', + 'class-methods-use-this': 'off', + 'no-undef': 'off', + 'max-classes-per-file': 'off', + 'no-bitwise': 'off', + 'operator-assignment': 'off', + 'prefer-template': 'off', + 'prefer-destructuring': 'off', + 'no-param-reassign': 'off', + 'no-restricted-syntax': 'off', + 'no-continue': 'off', + }, + }, + { + files: ['*.test.ts'], + rules: { + 'no-await-in-loop': 'off', + }, + }, + ], +}; diff --git a/contracts/.gitignore b/contracts/.gitignore new file mode 100644 index 00000000..a47615d9 --- /dev/null +++ b/contracts/.gitignore @@ -0,0 +1,2 @@ +node_modules/ +/bootstrap/dist/ diff --git a/contracts/.prettierrc.toml b/contracts/.prettierrc.toml new file mode 100644 index 00000000..b79b00db --- /dev/null +++ b/contracts/.prettierrc.toml @@ -0,0 +1,6 @@ +# .prettierrc.toml +trailingComma = "es5" +tabWidth = 4 +semi = true +singleQuote = true +printWidth = 120 diff --git a/contracts/.vscode/extensions.json b/contracts/.vscode/extensions.json new file mode 100644 index 00000000..c5823796 --- /dev/null +++ b/contracts/.vscode/extensions.json @@ -0,0 +1,5 @@ +{ + "recommendations": [ + "dbaeumer.vscode-eslint", + ] + } \ No newline at end of file diff --git a/contracts/.vscode/settings.json b/contracts/.vscode/settings.json new file mode 100644 index 00000000..99a5c708 --- /dev/null +++ b/contracts/.vscode/settings.json @@ -0,0 +1,5 @@ +{ + "editor.codeActionsOnSave": { + "source.fixAll.eslint": "explicit" + }, +} \ No newline at end of file diff --git a/contracts/README.md b/contracts/README.md new file mode 100644 index 00000000..73670c12 --- /dev/null +++ b/contracts/README.md @@ -0,0 +1,34 @@ +# Reti Open Pooling + +## Documentation + +These contracts, node daemon, and UI are for the proposal described in [Reti Open Pooling](../docs/reti-open-pooling.md). + +The contracts themselves are written in Tealscript. See [Tealscript](https://tealscript.algo.xyz) for details. + +## Usage + +### Algokit + +This repository assumes you have [AlgoKit](https://github.com/algorandfoundation/algokit-cli) installed and have a local network running on your machine. The default 'devmode' sandbox (`algokit localnet start`) is required for the system tests as they manipulate the block time offsets.template assumes you have a local network running on your machine. + +### PNPM + +The PNPM package manager was used for this project. See [pnpm](https://pnpm.io/) for installation details. Be sure to `pnpm install` first. + +### Build Contracts + +`pnpm run build` will compile the contracts to TEAL and generate ABI and appspec JSON files in [./contracts/artifacts](./contracts/artifacts/) and AlgoKit TypeScript clients in [./contracts/clients](./contracts/clients/). + +`pnpm run compile-contract` or `pnpm run generate-client` can be used to compile the contract or generate the contract seperately. + +### Run Tests + +`pnpm run test` will execute the tests defined in [./\_\_test\_\_](./__test__) + +## Deploying + +### Bootstrap script + +A bootstrap script is in the ./bootstrap directory. Running `pnpm run bootstrap --network {network}` will bootstrap the validator. The localnet networkbootstraps the local sandbox and also funds two new test accounts - updating an .env.sandbox file inside the nodemgr directory for local CLI use/testing. It is recommended to use a named sandbox configuration that has devmode disabled so blocks proceed normally. + diff --git a/contracts/__test__/contracts.test.ts b/contracts/__test__/contracts.test.ts new file mode 100644 index 00000000..48f7a9f4 --- /dev/null +++ b/contracts/__test__/contracts.test.ts @@ -0,0 +1,2723 @@ +import { afterEach, beforeAll, beforeEach, describe, expect, test } from '@jest/globals'; +import { algoKitLogCaptureFixture, algorandFixture, getTestAccount } from '@algorandfoundation/algokit-utils/testing'; +import { consoleLogger } from '@algorandfoundation/algokit-utils/types/logging'; +import { AlgoAmount } from '@algorandfoundation/algokit-utils/types/amount'; +import { Account, decodeAddress, encodeAddress, getApplicationAddress } from 'algosdk'; +import { assetOptIn, transferAlgos, transferAsset } from '@algorandfoundation/algokit-utils'; +import * as constants from 'node:constants'; +import { StakingPoolClient } from '../contracts/clients/StakingPoolClient'; +import { ValidatorRegistryClient } from '../contracts/clients/ValidatorRegistryClient'; +import { + addStake, + addStakingPool, + addValidator, + claimTokens, + createAsset, + createValidatorConfig, + epochBalanceUpdate, + gatingValueFromBigint, + getCurMaxStatePerPool, + getMbrAmountsFromValidatorClient, + getPoolAvailBalance, + getPoolInfo, + getProtocolConstraints, + getStakedPoolsForAccount, + getStakeInfoFromBoxValue, + getStakerInfo, + getTokenPayoutRatio, + getValidatorState, + logStakingPoolInfo, + ProtocolConstraints, + removeStake, + StakedInfo, + ValidatorConfig, + ValidatorPoolKey, + verifyRewardAmounts, + GATING_TYPE_ASSET_ID, + GATING_TYPE_ASSETS_CREATED_BY, +} from './helpers'; + +const FEE_SINK_ADDR = 'Y76M3MSY6DKBRHBL7C3NNDXGS5IIMQVQVUAB6MP4XEMMGVF2QWNPL226CA'; + +const MaxPoolsPerNode = 3; +// Periodically set this to max amount allowed in protocol (200 atm) but when testing more frequently this should be lowered to something like 20 stakers +// The ValidatorWFullPoolWRewards test is 'skip'ped for now - but should be periodically enabled for testing. +const MaxStakersPerPool = 200; + +const fixture = algorandFixture({ testAccountFunding: AlgoAmount.Algos(10000) }); +const logs = algoKitLogCaptureFixture(); + +// algokit.Config.configure({ debug: true }); + +const MaxAlgoPerPool = AlgoAmount.Algos(100_000).microAlgos; +let validatorMasterClient: ValidatorRegistryClient; +let poolClient: StakingPoolClient; + +let validatorMbr: bigint; +let poolMbr: bigint; +let poolInitMbr: bigint; +let stakerMbr: bigint; + +// ===== +// First construct the 'template' pool and then the master validator contract that everything will use +beforeAll(async () => { + await fixture.beforeEach(); + // testAccount here is the account that creates the Validator master contracts themselves - but basically one-time thing to be ignored.. + const { algod, testAccount } = fixture.context; + + // First we have to create dummy instance of a pool that we can use as template contract for validator + // which it can use to create new instances of that contract for staking pool. + poolClient = new StakingPoolClient( + { + sender: testAccount, + resolveBy: 'id', + id: 0, + deployTimeParams: { + nfdRegistryAppId: 0, + feeSinkAddr: decodeAddress(FEE_SINK_ADDR).publicKey, + }, + }, + algod + ); + const tmplPool = await poolClient.create.createApplication({ + creatingContractId: 0, + validatorId: 0, + poolId: 0, + minEntryStake: 1_000_000, + }); + validatorMasterClient = new ValidatorRegistryClient( + { + sender: testAccount, + resolveBy: 'id', + id: 0, + deployTimeParams: { + nfdRegistryAppId: 0, + }, + }, + algod + ); + + const validatorApp = await validatorMasterClient.create.createApplication({ poolTemplateAppId: tmplPool.appId }); + // verify that the constructed validator contract is initialized as expected + expect(validatorApp.appId).toBeDefined(); + expect(validatorApp.appAddress).toBeDefined(); + + const validatorGlobalState = await validatorMasterClient.appClient.getGlobalState(); + expect(validatorGlobalState.numV.value).toEqual(0); + expect(validatorGlobalState.foo).toBeUndefined(); // sanity check that undefined states doesn't match 0. + + // need .1 ALGO for things to really work at all w/ this validator contract account so get that out of the way + await validatorMasterClient.appClient.fundAppAccount(AlgoAmount.Algos(0.1)); + + [validatorMbr, poolMbr, poolInitMbr, stakerMbr] = await getMbrAmountsFromValidatorClient(validatorMasterClient); +}); + +describe('MultValidatorAddCheck', () => { + beforeEach(fixture.beforeEach); + beforeEach(logs.beforeEach); + afterEach(logs.afterEach); + + // Just verify adding new validators and their ids incrementing and mbrs being covered, etc, + test('validatorAddTests', async () => { + const validatorOwnerAccount = await getTestAccount( + { initialFunds: AlgoAmount.Algos(500), suppressLog: true }, + fixture.context.algod, + fixture.context.kmd + ); + const validatorsAppRef = await validatorMasterClient.appClient.getAppReference(); + const origMbr = (await fixture.context.algod.accountInformation(validatorsAppRef.appAddress).do())[ + 'min-balance' + ]; + + const config = createValidatorConfig({ + Owner: validatorOwnerAccount.addr, + Manager: validatorOwnerAccount.addr, + ValidatorCommissionAddress: validatorOwnerAccount.addr, + }); + let expectedID = 1; + let validatorId = await addValidator( + fixture.context, + validatorMasterClient, + validatorOwnerAccount, + config, + validatorMbr + ); + expect(validatorId).toEqual(expectedID); + const newMbr = (await fixture.context.algod.accountInformation(validatorsAppRef.appAddress).do())[ + 'min-balance' + ]; + expect(newMbr).toEqual(origMbr + Number(validatorMbr)); + + expectedID += 1; + validatorId = await addValidator( + fixture.context, + validatorMasterClient, + validatorOwnerAccount, + config, + validatorMbr + ); + expect(validatorId).toEqual(expectedID); + expectedID += 1; + validatorId = await addValidator( + fixture.context, + validatorMasterClient, + validatorOwnerAccount, + config, + validatorMbr + ); + expect(validatorId).toEqual(expectedID); + }); +}); + +describe('StakeAdds', () => { + beforeEach(fixture.beforeEach); + beforeEach(logs.beforeEach); + afterEach(logs.afterEach); + + let validatorId: number; + let validatorOwnerAccount: Account; + let poolAppId: bigint; + let firstPoolKey: ValidatorPoolKey; + + // add validator and 1 pool for subsequent stake tests + beforeAll(async () => { + // Fund a 'validator account' that will be the validator owner. + validatorOwnerAccount = await getTestAccount( + { initialFunds: AlgoAmount.Algos(500), suppressLog: true }, + fixture.context.algod, + fixture.context.kmd + ); + consoleLogger.info(`validator account ${validatorOwnerAccount.addr}`); + + const config = createValidatorConfig({ + Owner: validatorOwnerAccount.addr, + Manager: validatorOwnerAccount.addr, + ValidatorCommissionAddress: validatorOwnerAccount.addr, + MinEntryStake: BigInt(AlgoAmount.Algos(1000).microAlgos), + MaxAlgoPerPool: BigInt(MaxAlgoPerPool), // this comes into play in later tests !! + PercentToValidator: 50000, // 5% + PoolsPerNode: MaxPoolsPerNode, + }); + + validatorId = await addValidator( + fixture.context, + validatorMasterClient, + validatorOwnerAccount, + config, + validatorMbr + ); + + // Add new pool - then we'll add stake and verify balances. + firstPoolKey = await addStakingPool( + fixture.context, + validatorMasterClient, + validatorId, + 1, + validatorOwnerAccount, + poolMbr, + poolInitMbr + ); + // should be [validator id, pool id (1 based)] + expect(firstPoolKey.id).toEqual(BigInt(validatorId)); + expect(firstPoolKey.poolId).toEqual(1n); + + // get the app id via contract call - it should match what we just got back in poolKey[2] + poolAppId = ( + await validatorMasterClient.getPoolAppId( + { validatorId: firstPoolKey.id, poolId: firstPoolKey.poolId }, + { sendParams: { populateAppCallResources: true } } + ) + ).return!; + expect(firstPoolKey.poolAppId).toEqual(poolAppId); + + const stateData = await getValidatorState(validatorMasterClient, validatorId); + expect(stateData.numPools).toEqual(1); + expect(stateData.totalAlgoStaked).toEqual(0n); + expect(stateData.totalStakers).toEqual(0n); + + const validatorGlobalState = await validatorMasterClient.appClient.getGlobalState(); + expect(validatorGlobalState.staked.value).toEqual(0); + expect(validatorGlobalState.numStakers.value).toEqual(0); + + const poolInfo = await getPoolInfo(validatorMasterClient, firstPoolKey); + expect(poolInfo.poolAppId).toEqual(BigInt(poolAppId)); + expect(poolInfo.totalStakers).toEqual(0); + expect(poolInfo.totalAlgoStaked).toEqual(0n); + }); + + // Creates dummy staker: + // adds 'not enough' 1000 algo but taking out staker mbr - fails because <1000 min - checks failure + // adds 1000 algo (plus enough to cover staker mbr) + // tries to remove 200 algo (checks failure) because it would go below 1000 algo min. + // adds 1000 algo more - should end at exactly 2000 algo staked + test('firstStaker', async () => { + // get current balance of staker pool (should already include needed MBR in balance - but subtract it out so it's seen as the '0' amount) + const origStakePoolInfo = await fixture.context.algod.accountInformation(getApplicationAddress(poolAppId)).do(); + + // Fund a 'staker account' that will be the new 'staker' + const stakerAccount = await getTestAccount( + { initialFunds: AlgoAmount.Algos(5000), suppressLog: true }, + fixture.context.algod, + fixture.context.kmd + ); + // Start by funding 'not enough' (we pay minimum stake [but no mbr]) - should fail (!) + await expect( + addStake(fixture.context, validatorMasterClient, validatorId, stakerAccount, AlgoAmount.Algos(1000), 0n) + ).rejects.toThrowError(); + + // now stake 1000(+mbr), min for this pool - for the first time - which means actual stake amount will be reduced + // by 'first time staker' fee to cover MBR (which goes to VALIDATOR contract account, not staker contract account!) + // we pay the extra here so the final staked amount should be exactly 1000 + const stakeAmount1 = AlgoAmount.MicroAlgos( + AlgoAmount.Algos(1000).microAlgos + AlgoAmount.MicroAlgos(Number(stakerMbr)).microAlgos + ); + const [stakedPoolKey, fees1] = await addStake( + fixture.context, + validatorMasterClient, + validatorId, + stakerAccount, + stakeAmount1, + 0n + ); + // should match info from first staking pool + expect(stakedPoolKey.id).toEqual(firstPoolKey.id); + expect(stakedPoolKey.poolId).toEqual(firstPoolKey.poolId); + expect(stakedPoolKey.poolAppId).toEqual(firstPoolKey.poolAppId); + + let poolInfo = await getPoolInfo(validatorMasterClient, firstPoolKey); + expect(poolInfo.totalStakers).toEqual(1); + expect(poolInfo.totalAlgoStaked).toEqual(BigInt(stakeAmount1.microAlgos - Number(stakerMbr))); + + expect((await getValidatorState(validatorMasterClient, validatorId)).totalStakers).toEqual(1n); + + let validatorGlobalState = await validatorMasterClient.appClient.getGlobalState(); + expect(validatorGlobalState.staked.value).toEqual(stakeAmount1.microAlgos - Number(stakerMbr)); + expect(validatorGlobalState.numStakers.value).toEqual(1); + + const poolBalance1 = await fixture.context.algod.accountInformation(getApplicationAddress(poolAppId)).do(); + expect(poolBalance1.amount).toEqual(origStakePoolInfo.amount + stakeAmount1.microAlgos - Number(stakerMbr)); + + // now try to remove partial amount - which should fail because it will take staked amount to < its 'minimum amount' + const ourPoolClient = new StakingPoolClient( + { sender: stakerAccount, resolveBy: 'id', id: stakedPoolKey.poolAppId }, + fixture.context.algod + ); + await expect(removeStake(ourPoolClient, stakerAccount, AlgoAmount.Algos(200))).rejects.toThrowError(); + + // verify pool stake didn't change! + poolInfo = await getPoolInfo(validatorMasterClient, firstPoolKey); + expect(poolInfo.totalAlgoStaked).toEqual(BigInt(stakeAmount1.microAlgos - Number(stakerMbr))); + expect((await getValidatorState(validatorMasterClient, validatorId)).totalStakers).toEqual(1n); + + validatorGlobalState = await validatorMasterClient.appClient.getGlobalState(); + expect(validatorGlobalState.staked.value).toEqual(stakeAmount1.microAlgos - Number(stakerMbr)); + expect(validatorGlobalState.numStakers.value).toEqual(1); + + // stake again for 1000 more - should go to same pool (!) + const stakeAmount2 = AlgoAmount.Algos(1000); + const [stakedKey2, fees2] = await addStake( + fixture.context, + validatorMasterClient, + validatorId, + stakerAccount, + stakeAmount2, + 0n + ); + // should be same as what we added prior + expect(stakedKey2.id).toEqual(firstPoolKey.id); + expect(stakedKey2.poolId).toEqual(firstPoolKey.poolId); + expect(stakedKey2.poolAppId).toEqual(firstPoolKey.poolAppId); + // verify pool state changed... + poolInfo = await getPoolInfo(validatorMasterClient, firstPoolKey); + expect(poolInfo.totalAlgoStaked).toEqual( + BigInt(stakeAmount1.microAlgos - Number(stakerMbr) + stakeAmount2.microAlgos) + ); + // and global state changed + validatorGlobalState = await validatorMasterClient.appClient.getGlobalState(); + expect(validatorGlobalState.staked.value).toEqual( + stakeAmount1.microAlgos - Number(stakerMbr) + stakeAmount2.microAlgos + ); + + // ....and verify data for the 'staker' is correct as well + const stakerInfo = await getStakerInfo(ourPoolClient, stakerAccount); + expect(encodeAddress(stakerInfo.staker.publicKey)).toEqual(stakerAccount.addr); + // should be full 2000 algos (we included extra for mbr to begin with) + expect(stakerInfo.balance).toEqual(BigInt(AlgoAmount.Algos(2000).microAlgos)); + + expect((await getValidatorState(validatorMasterClient, validatorId)).totalStakers).toEqual(1n); + + // let's also get list of all staked pools we're part of... should only contain 1 entry and just be our pool + const allPools = await getStakedPoolsForAccount(validatorMasterClient, stakerAccount); + expect(allPools).toHaveLength(1); + expect(allPools[0]).toEqual(firstPoolKey); + + // second balance check of pool - it should increase by full stake amount since existing staker staked again, so no additional + // mbr was needed + const poolBalance2 = await fixture.context.algod.accountInformation(getApplicationAddress(poolAppId)).do(); + expect(poolBalance2.amount).toEqual(poolBalance1.amount + stakeAmount2.microAlgos); + + const stakerAcctBalance = await fixture.context.algod.accountInformation(stakerAccount.addr).do(); + expect(stakerAcctBalance.amount).toEqual( + AlgoAmount.Algos(5000).microAlgos - // funded amount + stakeAmount1.microAlgos - + stakeAmount2.microAlgos - + fees1.microAlgos - + fees2.microAlgos + ); + + // Verify 'total' staked from validator contract + const stateData = await getValidatorState(validatorMasterClient, validatorId); + expect(stateData.numPools).toEqual(1); + expect(stateData.totalAlgoStaked).toEqual( + BigInt(stakeAmount1.microAlgos + stakeAmount2.microAlgos - Number(stakerMbr)) + ); + expect(stateData.totalStakers).toEqual(1n); + // and.. globally + validatorGlobalState = await validatorMasterClient.appClient.getGlobalState(); + expect(validatorGlobalState.staked.value).toEqual( + stakeAmount1.microAlgos + stakeAmount2.microAlgos - Number(stakerMbr) + ); + }); + + // Creates new staker account + // Adds 2000 algo to pool (not caring about mbr - so actual amount will be less the stakermbr amount) + test('nextStaker', async () => { + // get current balance of staker pool + const origStakePoolInfo = await fixture.context.algod.accountInformation(getApplicationAddress(poolAppId)).do(); + // and of all pools + const origValidatorState = await getValidatorState(validatorMasterClient, validatorId); + + // Fund a 'staker account' that will be the new 'staker' + const stakerAccount = await getTestAccount( + { initialFunds: AlgoAmount.Algos(5000), suppressLog: true }, + fixture.context.algod, + fixture.context.kmd + ); + // add 2000 stake by random staker - should go to NEW slot - but this is still their first add so they have to pay more mbr + // this time - since it's over minimum... don't pay 'extra' - so we should ensure that the MBR is NOT part of what we stake + const stakeAmount1 = AlgoAmount.Algos(2000); + const [stakedPoolKey, fees] = await addStake( + fixture.context, + validatorMasterClient, + validatorId, + stakerAccount, + stakeAmount1, + 0n + ); + // should be same as what we added prior + expect(stakedPoolKey.id).toEqual(firstPoolKey.id); + expect(stakedPoolKey.poolId).toEqual(firstPoolKey.poolId); + expect(stakedPoolKey.poolAppId).toEqual(firstPoolKey.poolAppId); + + const poolBalance1 = await fixture.context.algod.accountInformation(getApplicationAddress(poolAppId)).do(); + expect(poolBalance1.amount).toEqual(origStakePoolInfo.amount + stakeAmount1.microAlgos - Number(stakerMbr)); + + const stakerAcctBalance = await fixture.context.algod.accountInformation(stakerAccount.addr).do(); + expect(stakerAcctBalance.amount).toEqual( + AlgoAmount.Algos(5000).microAlgos - // funded amount + stakeAmount1.microAlgos - + fees.microAlgos + ); + + // let's also get list of all staked pools we're part of... should only contain 1 entry and just be our pool + const allPools = await getStakedPoolsForAccount(validatorMasterClient, stakerAccount); + expect(allPools).toHaveLength(1); + expect(allPools[0]).toEqual(firstPoolKey); + + // Verify 'total' staked from validator contract + const stateData = await getValidatorState(validatorMasterClient, validatorId); + expect(stateData.numPools).toEqual(1); + expect(stateData.totalAlgoStaked).toEqual( + origValidatorState.totalAlgoStaked + BigInt(stakeAmount1.microAlgos - Number(stakerMbr)) + ); + expect(stateData.totalStakers).toEqual(BigInt(2)); + }); + + test('validatorPoolCheck', async () => { + const poolInfo = await getPoolInfo(validatorMasterClient, firstPoolKey); + expect(poolInfo.poolAppId).toEqual(BigInt(poolAppId)); + expect(poolInfo.totalStakers).toEqual(2); + expect(poolInfo.totalAlgoStaked).toEqual(BigInt(AlgoAmount.Algos(4000).microAlgos - Number(stakerMbr))); + }); + + test('addMaxPoolsAndFill', async () => { + const pools = []; + const stakers = []; + const poolsToCreate = MaxPoolsPerNode; + + // capture current 'total' state for all pools + const origValidatorState = await getValidatorState(validatorMasterClient, validatorId); + + // we create 'max pools per node' new pools on new node (first pool is still there which wee added as part of beforeAll) + for (let i = 0; i < poolsToCreate; i += 1) { + // eslint-disable-next-line no-await-in-loop + const newPool = await addStakingPool( + fixture.context, + validatorMasterClient, + validatorId, + 2, // add to different node - otherwise we'll fail + validatorOwnerAccount, + poolMbr, + poolInitMbr + ); + expect(newPool.poolId).toEqual(BigInt(2 + i)); + pools.push(newPool); + } + + for (let i = 0; i < poolsToCreate; i += 1) { + const poolInfo = await getPoolInfo(validatorMasterClient, pools[i]); + expect(poolInfo.poolAppId).toEqual(pools[i].poolAppId); + expect(poolInfo.totalStakers).toEqual(0); + expect(poolInfo.totalAlgoStaked).toEqual(0n); + } + + // now create X new stakers + for (let i = 0; i < poolsToCreate; i += 1) { + // fund some new staker accounts (4) + const stakerAccount = await getTestAccount( + { + initialFunds: AlgoAmount.MicroAlgos(MaxAlgoPerPool + AlgoAmount.Algos(4000).microAlgos), + suppressLog: true, + }, + fixture.context.algod, + fixture.context.kmd + ); + stakers.push(stakerAccount); + } + // have the first max-1 of the max new stakers - add such that each pool is basically completely full but just + // short so we can still add a small amount later in a test. + // add stake for each - each time should work and go to new pool (starting with first pool we added - the one + // that's already there shouldn't have room). Then next add of same size should fail.. then next add of something + // small should go to first pool again + const stakeAmount = AlgoAmount.MicroAlgos(MaxAlgoPerPool - AlgoAmount.Algos(1000).microAlgos); + for (let i = 0; i < poolsToCreate - 1; i += 1) { + const [stakedPoolKey] = await addStake( + fixture.context, + validatorMasterClient, + validatorId, + stakers[i], + stakeAmount, + 0n + ); + // should go to each pool in succession since it's basically the entire pool + expect(stakedPoolKey.id).toEqual(pools[i].id); + expect(stakedPoolKey.poolId).toEqual(pools[i].poolId); + expect(stakedPoolKey.poolAppId).toEqual(pools[i].poolAppId); + + expect(await getStakedPoolsForAccount(validatorMasterClient, stakers[i])).toEqual([stakedPoolKey]); + } + // now try to add larger stake from staker max-1... should fail... nothing free + await expect( + addStake( + fixture.context, + validatorMasterClient, + validatorId, + stakers[MaxPoolsPerNode - 1], + AlgoAmount.MicroAlgos(MaxAlgoPerPool + AlgoAmount.Algos(1000).microAlgos), + 0n + ) + ).rejects.toThrowError(); + + // For last staker - get their staked pool list - should be empty + expect(await getStakedPoolsForAccount(validatorMasterClient, stakers[MaxPoolsPerNode - 1])).toHaveLength(0); + // have stakermaxPools-1 stake large amount - just barely under max - so should only fit in last pool + const [fitTestStake1] = await addStake( + fixture.context, + validatorMasterClient, + validatorId, + stakers[MaxPoolsPerNode - 1], + AlgoAmount.MicroAlgos(MaxAlgoPerPool - AlgoAmount.Algos(1000).microAlgos), + 0n + ); + expect(fitTestStake1.id).toEqual(pools[MaxPoolsPerNode - 1].id); + expect(fitTestStake1.poolId).toEqual(pools[MaxPoolsPerNode - 1].poolId); + expect(fitTestStake1.poolAppId).toEqual(pools[MaxPoolsPerNode - 1].poolAppId); + + // Now have staker maxPools-1 stake 1000 - it'll fit in last pool (just) since it first tries pools staker is already in + const [fitTestStake2] = await addStake( + fixture.context, + validatorMasterClient, + validatorId, + stakers[MaxPoolsPerNode - 1], + AlgoAmount.Algos(1000), + 0n + ); + expect(fitTestStake2.id).toEqual(pools[MaxPoolsPerNode - 1].id); + expect(fitTestStake2.poolId).toEqual(pools[MaxPoolsPerNode - 1].poolId); + expect(fitTestStake2.poolAppId).toEqual(pools[MaxPoolsPerNode - 1].poolAppId); + + // now try to add smallish stake from staker maxPools-1... should go to very first pool + // # of stakers shouldn't increase! They're new entrant into pool but already staked somewhere else ! + const [fitTestStake3] = await addStake( + fixture.context, + validatorMasterClient, + validatorId, + stakers[MaxPoolsPerNode - 1], + AlgoAmount.Algos(1000), + 0n + ); + expect(fitTestStake3.id).toEqual(firstPoolKey.id); + expect(fitTestStake3.poolId).toEqual(firstPoolKey.poolId); + expect(fitTestStake3.poolAppId).toEqual(firstPoolKey.poolAppId); + + // For staker maxPools-1 - get their staked pool list - should now be two entries - pool maxPools+1 (pool #maxpools we added) then pool 1 (order of staking) + const lastStakerPools = await getStakedPoolsForAccount(validatorMasterClient, stakers[MaxPoolsPerNode - 1]); + expect(lastStakerPools).toHaveLength(2); + expect(lastStakerPools[0]).toEqual(pools[MaxPoolsPerNode - 1]); + expect(lastStakerPools[1]).toEqual(firstPoolKey); + + // Get 'total' staked from validator contract + const stateData = await getValidatorState(validatorMasterClient, validatorId); + consoleLogger.info( + `num pools: ${stateData.numPools}, total staked:${stateData.totalAlgoStaked}, stakers:${stateData.totalStakers}` + ); + expect(stateData.numPools).toEqual(MaxPoolsPerNode + 1); + expect(stateData.totalAlgoStaked).toEqual( + origValidatorState.totalAlgoStaked + + BigInt(stakeAmount.microAlgos * MaxPoolsPerNode) - + BigInt(stakerMbr * BigInt(MaxPoolsPerNode)) + + BigInt(AlgoAmount.Algos(2000).microAlgos) + ); + expect(stateData.totalStakers).toEqual(BigInt(MaxPoolsPerNode + 2)); + }); + + test('addThenRemoveStake', async () => { + const stakerAccount = await getTestAccount( + { + initialFunds: AlgoAmount.Algos(10_000), + suppressLog: true, + }, + fixture.context.algod, + fixture.context.kmd + ); + let amountStaked = 0; + // smallish amount of stake - should just get added to first pool + const [addStake1, fees1] = await addStake( + fixture.context, + validatorMasterClient, + validatorId, + stakerAccount, + AlgoAmount.Algos(1100), + 0n + ); + amountStaked += AlgoAmount.Algos(1100).microAlgos; + expect(addStake1.id).toEqual(firstPoolKey.id); + expect(addStake1.poolId).toEqual(firstPoolKey.poolId); + expect(addStake1.poolAppId).toEqual(firstPoolKey.poolAppId); + + // add again.. should go to same place + const [addStake2, fees2] = await addStake( + fixture.context, + validatorMasterClient, + validatorId, + stakerAccount, + AlgoAmount.Algos(2000), + 0n + ); + amountStaked += AlgoAmount.Algos(2000).microAlgos; + + expect(addStake2.id).toEqual(firstPoolKey.id); + expect(addStake2.poolId).toEqual(firstPoolKey.poolId); + expect(addStake2.poolAppId).toEqual(firstPoolKey.poolAppId); + + const stakerAcctBalance = await fixture.context.algod.accountInformation(stakerAccount.addr).do(); + expect(stakerAcctBalance.amount).toEqual( + AlgoAmount.Algos(10_000).microAlgos - // funded amount + amountStaked - + fees1.microAlgos - + fees2.microAlgos + ); + + // Verify the staked data matches.... + const allPools = await getStakedPoolsForAccount(validatorMasterClient, stakerAccount); + expect(allPools).toHaveLength(1); + expect(allPools[0]).toEqual(firstPoolKey); + // ....and verify data for the 'staker' is correct as well + const ourPoolClient = new StakingPoolClient( + { sender: stakerAccount, resolveBy: 'id', id: firstPoolKey.poolAppId }, + fixture.context.algod + ); + // The amount 'actually' staked won't include the MBR amount + const stakerInfo = await getStakerInfo(ourPoolClient, stakerAccount); + expect(encodeAddress(stakerInfo.staker.publicKey)).toEqual(stakerAccount.addr); + expect(stakerInfo.balance).toEqual(BigInt(amountStaked - Number(stakerMbr))); + + // Get Pool info before removing stake.. + const preRemovePoolInfo = await getPoolInfo(validatorMasterClient, firstPoolKey); + + // then remove the stake ! + const removeFees = await removeStake( + ourPoolClient, + stakerAccount, + AlgoAmount.MicroAlgos(Number(stakerInfo.balance)) + ); + const newBalance = await fixture.context.algod.accountInformation(stakerAccount.addr).do(); + expect(newBalance.amount).toEqual( + stakerAcctBalance.amount + Number(stakerInfo.balance) - removeFees // microAlgo for `removeStake fees + ); + + // stakers should have been reduced and stake amount should have been reduced by stake removed + const postRemovePoolInfo = await getPoolInfo(validatorMasterClient, firstPoolKey); + expect(postRemovePoolInfo.totalStakers).toEqual(preRemovePoolInfo.totalStakers - 1); + expect(postRemovePoolInfo.totalAlgoStaked).toEqual(preRemovePoolInfo.totalAlgoStaked - stakerInfo.balance); + }); + + test('addThenRemoveAllStake', async () => { + const stakerAccount = await getTestAccount( + { + initialFunds: AlgoAmount.Algos(10_000), + suppressLog: true, + }, + fixture.context.algod, + fixture.context.kmd + ); + let amountStaked = 0; + // smallish amount of stake - should just get added to first pool + const [addStake1, addFees] = await addStake( + fixture.context, + validatorMasterClient, + validatorId, + stakerAccount, + AlgoAmount.Algos(1100), + 0n + ); + amountStaked += AlgoAmount.Algos(1100).microAlgos; + expect(addStake1.id).toEqual(firstPoolKey.id); + expect(addStake1.poolId).toEqual(firstPoolKey.poolId); + expect(addStake1.poolAppId).toEqual(firstPoolKey.poolAppId); + + const stakerAcctBalance = await fixture.context.algod.accountInformation(stakerAccount.addr).do(); + expect(stakerAcctBalance.amount).toEqual( + AlgoAmount.Algos(10_000).microAlgos - // funded amount + amountStaked - + addFees.microAlgos + ); + + // Verify the staked data matches.... + const allPools = await getStakedPoolsForAccount(validatorMasterClient, stakerAccount); + expect(allPools).toHaveLength(1); + expect(allPools[0]).toEqual(firstPoolKey); + // ....and verify data for the 'staker' is correct as well + const ourPoolClient = new StakingPoolClient( + { sender: stakerAccount, resolveBy: 'id', id: firstPoolKey.poolAppId }, + fixture.context.algod + ); + // The amount 'actually' staked won't include the MBR amount + const stakerInfo = await getStakerInfo(ourPoolClient, stakerAccount); + expect(encodeAddress(stakerInfo.staker.publicKey)).toEqual(stakerAccount.addr); + expect(stakerInfo.balance).toEqual(BigInt(amountStaked - Number(stakerMbr))); + + // Get Pool info before removing stake.. + const preRemovePoolInfo = await getPoolInfo(validatorMasterClient, firstPoolKey); + + // then remove ALL the stake (specifying 0 to remove all) + const removeFees = await removeStake(ourPoolClient, stakerAccount, AlgoAmount.MicroAlgos(0)); + const newBalance = await fixture.context.algod.accountInformation(stakerAccount.addr).do(); + expect(newBalance.amount).toEqual( + stakerAcctBalance.amount + Number(stakerInfo.balance) - removeFees // microAlgo for removeStake fees + ); + + // stakers should have been reduced and stake amount should have been reduced by stake removed + const postRemovePoolInfo = await getPoolInfo(validatorMasterClient, firstPoolKey); + expect(postRemovePoolInfo.totalStakers).toEqual(preRemovePoolInfo.totalStakers - 1); + expect(postRemovePoolInfo.totalAlgoStaked).toEqual(preRemovePoolInfo.totalAlgoStaked - stakerInfo.balance); + }); + + test('getStakeInfo', async () => { + await logStakingPoolInfo(fixture.context, firstPoolKey.poolAppId, 'getStakeInfo'); + }); +}); + +describe('StakeWRewards', () => { + beforeEach(fixture.beforeEach); + beforeEach(logs.beforeEach); + afterEach(logs.afterEach); + + let validatorId: number; + let validatorOwnerAccount: Account; + const stakerAccounts: Account[] = []; + let poolAppId: bigint; + let firstPoolKey: ValidatorPoolKey; + let firstPoolClient: StakingPoolClient; + + const PctToValidator = 5; + + // add validator and 1 pool for subsequent stake tests + beforeAll(async () => { + // Fund a 'validator account' that will be the validator owner. + validatorOwnerAccount = await getTestAccount( + { initialFunds: AlgoAmount.Algos(500), suppressLog: true }, + fixture.context.algod, + fixture.context.kmd + ); + consoleLogger.info(`validator account ${validatorOwnerAccount.addr}`); + + const config = createValidatorConfig({ + Owner: validatorOwnerAccount.addr, + Manager: validatorOwnerAccount.addr, + MinEntryStake: BigInt(AlgoAmount.Algos(1000).microAlgos), + MaxAlgoPerPool: BigInt(MaxAlgoPerPool), // this comes into play in later tests !! + PercentToValidator: PctToValidator * 10000, + ValidatorCommissionAddress: validatorOwnerAccount.addr, + }); + validatorId = await addValidator( + fixture.context, + validatorMasterClient, + validatorOwnerAccount, + config, + validatorMbr + ); + + // Add new pool - then we'll add stake and verify balances. + firstPoolKey = await addStakingPool( + fixture.context, + validatorMasterClient, + validatorId, + 1, + validatorOwnerAccount, + poolMbr, + poolInitMbr + ); + // should be [validator id, pool id (1 based)] + expect(firstPoolKey.id).toEqual(BigInt(validatorId)); + expect(firstPoolKey.poolId).toEqual(1n); + + firstPoolClient = new StakingPoolClient( + { sender: validatorOwnerAccount, resolveBy: 'id', id: firstPoolKey.poolAppId }, + fixture.context.algod + ); + + // get the app id via contract call - it should match what we just got back in poolKey[2] + poolAppId = ( + await validatorMasterClient.getPoolAppId( + { validatorId: firstPoolKey.id, poolId: firstPoolKey.poolId }, + { sendParams: { populateAppCallResources: true } } + ) + ).return!; + expect(firstPoolKey.poolAppId).toEqual(poolAppId); + + const stateData = await getValidatorState(validatorMasterClient, validatorId); + expect(stateData.numPools).toEqual(1); + expect(stateData.totalAlgoStaked).toEqual(0n); + expect(stateData.totalStakers).toEqual(0n); + + const poolInfo = await getPoolInfo(validatorMasterClient, firstPoolKey); + expect(poolInfo.poolAppId).toEqual(BigInt(poolAppId)); + expect(poolInfo.totalStakers).toEqual(0); + expect(poolInfo.totalAlgoStaked).toEqual(0n); + }); + + // Creates dummy staker: + // adds 1000 algo (plus enough to cover staker mbr) + test('firstStaker', async () => { + // Fund a 'staker account' that will be the new 'staker' + const stakerAccount = await getTestAccount( + { initialFunds: AlgoAmount.Algos(5000), suppressLog: true }, + fixture.context.algod, + fixture.context.kmd + ); + stakerAccounts.push(stakerAccount); + + // now stake 1000(+mbr), min for this pool - for the first time - which means actual stake amount will be reduced + // by 'first time staker' fee to cover MBR (which goes to VALIDATOR contract account, not staker contract account!) + // we pay the extra here so the final staked amount should be exactly 1000 + const stakeAmount1 = AlgoAmount.MicroAlgos( + AlgoAmount.Algos(1000).microAlgos + AlgoAmount.MicroAlgos(Number(stakerMbr)).microAlgos + ); + const [stakedPoolKey] = await addStake( + fixture.context, + validatorMasterClient, + validatorId, + stakerAccount, + stakeAmount1, + 0n + ); + // should match info from first staking pool + expect(stakedPoolKey.id).toEqual(firstPoolKey.id); + expect(stakedPoolKey.poolId).toEqual(firstPoolKey.poolId); + expect(stakedPoolKey.poolAppId).toEqual(firstPoolKey.poolAppId); + + const poolInfo = await getPoolInfo(validatorMasterClient, firstPoolKey); + expect(poolInfo.totalStakers).toEqual(1); + expect(poolInfo.totalAlgoStaked).toEqual(BigInt(stakeAmount1.microAlgos - Number(stakerMbr))); + + expect((await getValidatorState(validatorMasterClient, validatorId)).totalStakers).toEqual(1n); + }); + + test('testFirstRewards', async () => { + // increment time a day(+) at a time per transaction + await fixture.context.algod.setBlockOffsetTimestamp(60 * 61 * 24).do(); + + const origValidatorState = await getValidatorState(validatorMasterClient, validatorId); + const ownerBalance = await fixture.context.algod.accountInformation(validatorOwnerAccount.addr).do(); + const stakersPriorToReward = await getStakeInfoFromBoxValue(firstPoolClient); + + const reward = AlgoAmount.Algos(200); + // put some test 'reward' algos into staking pool + await transferAlgos( + { + from: fixture.context.testAccount, + to: getApplicationAddress(firstPoolKey.poolAppId), + amount: reward, + }, + fixture.context.algod + ); + + const poolInfo = await getPoolInfo(validatorMasterClient, firstPoolKey); + consoleLogger.info(`pool stakers:${poolInfo.totalStakers}, staked:${poolInfo.totalAlgoStaked}`); + + const epochBefore = BigInt((await firstPoolClient.appClient.getGlobalState()).epochNumber.value as bigint); + + // Perform epoch payout calculation - we also get back how much it cost to issue the txn + const fees = await epochBalanceUpdate(firstPoolClient); + const expectedValidatorReward = reward.microAlgos * (PctToValidator / 100); + + expect(BigInt((await firstPoolClient.appClient.getGlobalState()).epochNumber.value as bigint)).toEqual( + epochBefore + 1n + ); + + const newValidatorState = await getValidatorState(validatorMasterClient, validatorId); + const newOwnerBalance = await fixture.context.algod.accountInformation(validatorOwnerAccount.addr).do(); + // validator owner should have gotten the expected reward (minus the fees they just paid ofc) + expect(newOwnerBalance.amount).toEqual(ownerBalance.amount - fees.microAlgos + expectedValidatorReward); + + // Verify all the stakers in the pool got what we think they should have + const stakersAfterReward = await getStakeInfoFromBoxValue(firstPoolClient); + + await verifyRewardAmounts( + fixture.context, + (BigInt(reward.microAlgos) - BigInt(expectedValidatorReward)) as bigint, + 0n, + stakersPriorToReward as StakedInfo[], + stakersAfterReward as StakedInfo[], + 1 as number + ); + + // the total staked should have grown as well - reward minus what the validator was paid in their commission + expect(Number(newValidatorState.totalAlgoStaked)).toEqual( + Number(origValidatorState.totalAlgoStaked) + (reward.microAlgos - expectedValidatorReward) + ); + + const poolBalance = await getPoolAvailBalance(fixture.context, firstPoolKey); + expect(poolBalance).toEqual(newValidatorState.totalAlgoStaked); + }); + + test('extractRewards', async () => { + const origStakerBalance = await fixture.context.algod.accountInformation(stakerAccounts[0].addr).do(); + + // Remove it all + const fees = await removeStake(firstPoolClient, stakerAccounts[0], AlgoAmount.Algos(1190)); + + const newStakerBalance = await fixture.context.algod.accountInformation(stakerAccounts[0].addr).do(); + // 1000 algos staked + 190 reward (- fees for removing stake) + expect(newStakerBalance.amount).toEqual(origStakerBalance.amount + AlgoAmount.Algos(1190).microAlgos - fees); + + // no one should be left and be 0 balance + const postRemovePoolInfo = await getPoolInfo(validatorMasterClient, firstPoolKey); + expect(postRemovePoolInfo.totalStakers).toEqual(0); + expect(postRemovePoolInfo.totalAlgoStaked).toEqual(0n); + + const newValidatorState = await getValidatorState(validatorMasterClient, validatorId); + expect(Number(newValidatorState.totalAlgoStaked)).toEqual(0); + expect(Number(newValidatorState.totalStakers)).toEqual(0); + + const poolBalance = await getPoolAvailBalance(fixture.context, firstPoolKey); + expect(poolBalance).toEqual(newValidatorState.totalAlgoStaked); + }); + + test('testFailNotEnoughRewards', async () => { + // Do epoch payout immediately with no new funds - should fail because not enough to pay out to validator, etc. + await expect(epochBalanceUpdate(firstPoolClient)).rejects.toThrowError(); + }); + + test('testTooEarlyEpoch', async () => { + // increment 1 hour at a time per transaction + await fixture.context.algod.setBlockOffsetTimestamp(60 * 60).do(); + + // put some test 'reward' algos into staking pool + await transferAlgos( + { + from: fixture.context.testAccount, + to: getApplicationAddress(firstPoolKey.poolAppId), + amount: AlgoAmount.Algos(100), + }, + fixture.context.algod + ); + + // this payout should work... between prior tests and just now - it's been a day.. + // validator will have received 5 algo (on the 100 we just put in the pool) - we account for that later... + await epochBalanceUpdate(firstPoolClient); + + await transferAlgos( + { + from: fixture.context.testAccount, + to: getApplicationAddress(firstPoolKey.poolAppId), + amount: AlgoAmount.Algos(100), + }, + fixture.context.algod + ); + // We added more again - but enough time shouldn't have passed to allow another payout + await expect(epochBalanceUpdate(firstPoolClient)).rejects.toThrowError(); + + // and staked amount should still be 0 + const poolInfo = await getPoolInfo(validatorMasterClient, firstPoolKey); + expect(poolInfo.totalStakers).toEqual(0); + expect(poolInfo.totalAlgoStaked).toEqual(0n); + + await logStakingPoolInfo(fixture.context, firstPoolKey.poolAppId, 'should be no stakers !'); + + // We added 200 algo in to bump the clock a bit - and cause transactions - this is basically future reward + // we did 1 payout - so balance should be 200 - (validator % of 100) + const poolBalance = await getPoolAvailBalance(fixture.context, firstPoolKey); + expect(poolBalance).toEqual( + BigInt(AlgoAmount.Algos(200).microAlgos) - BigInt(AlgoAmount.Algos(100).microAlgos * (PctToValidator / 100)) + ); + consoleLogger.info(`ending pool balance: ${poolBalance}`); + }); + + test('testPartialReward', async () => { + // increment 1 hour at a time per transaction + await fixture.context.algod.setBlockOffsetTimestamp(60 * 60).do(); + + // loop until we get a payout (from prior 'too early' state) + for (let i = 0; i < 24; i += 1) { + try { + await epochBalanceUpdate(firstPoolClient); + break; + } catch (exception) { + // move the clock by issuing a txn. + await transferAlgos( + { + from: fixture.context.testAccount, + to: getApplicationAddress(firstPoolKey.poolAppId), + amount: AlgoAmount.Algos(10), + }, + fixture.context.algod + ); + } + } + + // double-check no one should be left and be 0 balance + const checkPoolInfo = await getPoolInfo(validatorMasterClient, firstPoolKey); + expect(checkPoolInfo.totalStakers).toEqual(0); + expect(checkPoolInfo.totalAlgoStaked).toEqual(0n); + + const checkValidatorState = await getValidatorState(validatorMasterClient, validatorId); + expect(Number(checkValidatorState.totalAlgoStaked)).toEqual(0); + expect(Number(checkValidatorState.totalStakers)).toEqual(0); + + // Ok, re-enter the pool - but we'll be in right off the bat and be there for full epoch + // now stake 1000(+mbr), min for this pool - for the first time - which means actual stake amount will be reduced + // by 'first time staker' fee to cover MBR (which goes to VALIDATOR contract account, not staker contract account!) + // we pay the extra here so the final staked amount should be exactly 1000 + const stakeAmount1 = AlgoAmount.Algos(1000); + // Add stake for first staker - partial epoch + const [aPoolKey] = await addStake( + fixture.context, + validatorMasterClient, + validatorId, + stakerAccounts[0], + stakeAmount1, + 0n + ); + expect(aPoolKey.poolAppId).toEqual(aPoolKey.poolAppId); + + const staker1Info = await getStakerInfo(firstPoolClient, stakerAccounts[0]); + const entryTime = new Date(Number(staker1Info.entryTime) * 1000); // convert to ms + const stakingPoolGS = await firstPoolClient.appClient.getGlobalState(); + const lastPayoutTime = new Date(Number(stakingPoolGS.lastPayout.value as bigint) * 1000); + consoleLogger.info(`lastPayout:${lastPayoutTime.toString()}, new entry time: ${entryTime.toString()}`); + + // Ok - bump time so that the next staker will be towards tail end of next epoch payout + await fixture.context.algod.setBlockOffsetTimestamp(60 * 60 * 24).do(); + + // Add second (brand new!) staker - with same amount entered - but entering later (so it will be a 'partial' + // entry into the epoch (so we can ensure partial payout occurs) + const partialEpochStaker = await getTestAccount( + { initialFunds: AlgoAmount.Algos(5000), suppressLog: true }, + fixture.context.algod, + fixture.context.kmd + ); + stakerAccounts.push(partialEpochStaker); + const stakeAmount2 = AlgoAmount.MicroAlgos( + AlgoAmount.Algos(1000).microAlgos + AlgoAmount.MicroAlgos(Number(stakerMbr)).microAlgos + ); + + // Add stake for partial-epoch staker + const [newPoolKey] = await addStake( + fixture.context, + validatorMasterClient, + validatorId, + partialEpochStaker, + stakeAmount2, + 0n + ); + + expect(newPoolKey.poolAppId).toEqual(aPoolKey.poolAppId); + const staker2Info = await getStakerInfo(firstPoolClient, partialEpochStaker); + const staker2Entry = new Date(Number(staker2Info.entryTime) * 1000); + consoleLogger.info(`partialEpochStaker: new entry time: ${staker2Entry.toString()}`); + + await logStakingPoolInfo(fixture.context, firstPoolKey.poolAppId, 'should have two stakers'); + + // ok now do payouts - and see if we can verify the expected totals + const poolInfo = await getPoolInfo(validatorMasterClient, aPoolKey); + expect(poolInfo.totalStakers).toEqual(2); + // only subtract out 1 staker mbr because only the 'fullEpochStaker' will be 'new' to staking + expect(poolInfo.totalAlgoStaked).toEqual(BigInt(stakeAmount1.microAlgos + stakeAmount2.microAlgos) - stakerMbr); + + // What's pool's current balance + const poolBalance = await getPoolAvailBalance(fixture.context, firstPoolKey); + const knownReward = poolBalance - poolInfo.totalAlgoStaked; + const expectedValidatorReward = Number(knownReward) * (PctToValidator / 100); + + const stakersPriorToReward = await getStakeInfoFromBoxValue(firstPoolClient); + + // do reward calcs + await epochBalanceUpdate(firstPoolClient); + const stakersAfterReward = await getStakeInfoFromBoxValue(firstPoolClient); + + await logStakingPoolInfo(fixture.context, firstPoolKey.poolAppId, 'after payouts'); + await verifyRewardAmounts( + fixture.context, + knownReward - BigInt(expectedValidatorReward), + 0n, + stakersPriorToReward, + stakersAfterReward, + 1 + ); + }); +}); + +describe('StakeWTokenWRewards', () => { + beforeEach(fixture.beforeEach); + beforeEach(logs.beforeEach); + afterEach(logs.afterEach); + + let validatorId: number; + let validatorOwnerAccount: Account; + let validatorConfig: ValidatorConfig; + const stakerAccounts: Account[] = []; + let poolAppId: bigint; + let firstPoolKey: ValidatorPoolKey; + let firstPoolClient: StakingPoolClient; + + let rewardTokenID: bigint; + const PctToValidator = 5; + const decimals = 0; + const tokenRewardPerPayout = BigInt(1000 * 10 ** decimals); + + // add validator and 1 pool for subsequent stake tests + beforeAll(async () => { + // Create a reward token to pay out to stakers + const tokenCreatorAccount = await getTestAccount( + { initialFunds: AlgoAmount.Algos(5000), suppressLog: true }, + fixture.context.algod, + fixture.context.kmd + ); + rewardTokenID = await createAsset( + fixture.context.algod, + tokenCreatorAccount, + 'Reward Token', + 'RWDTOKEN', + 100_000, + decimals + ); + + // Fund a 'validator account' that will be the validator owner. + validatorOwnerAccount = await getTestAccount( + { initialFunds: AlgoAmount.Algos(500), suppressLog: true }, + fixture.context.algod, + fixture.context.kmd + ); + consoleLogger.info(`validator account ${validatorOwnerAccount.addr}`); + + validatorConfig = createValidatorConfig({ + Owner: validatorOwnerAccount.addr, + Manager: validatorOwnerAccount.addr, + MinEntryStake: BigInt(AlgoAmount.Algos(1000).microAlgos), + MaxAlgoPerPool: BigInt(MaxAlgoPerPool), // this comes into play in later tests !! + PercentToValidator: PctToValidator * 10000, + ValidatorCommissionAddress: validatorOwnerAccount.addr, + RewardTokenID: rewardTokenID, + RewardPerPayout: tokenRewardPerPayout, // 1000 tokens per epoch + }); + validatorId = await addValidator( + fixture.context, + validatorMasterClient, + validatorOwnerAccount, + validatorConfig, + validatorMbr + ); + + // Add new pool - then we'll add stake and verify balances. + // first pool needs extra .1 to cover MBR of opted-in reward token ! + firstPoolKey = await addStakingPool( + fixture.context, + validatorMasterClient, + validatorId, + 1, + validatorOwnerAccount, + poolMbr, + poolInitMbr + BigInt(AlgoAmount.Algos(0.1).microAlgos) + ); + // should be [validator id, pool id (1 based)] + expect(firstPoolKey.id).toEqual(BigInt(validatorId)); + expect(firstPoolKey.poolId).toEqual(1n); + + // now send a bunch of our reward token to the pool ! + await transferAsset( + { + from: tokenCreatorAccount, + to: getApplicationAddress(firstPoolKey.poolAppId), + assetId: Number(rewardTokenID), + amount: 5000 * 10 ** decimals, + }, + fixture.context.algod + ); + + firstPoolClient = new StakingPoolClient( + { sender: validatorOwnerAccount, resolveBy: 'id', id: firstPoolKey.poolAppId }, + fixture.context.algod + ); + + // get the app id via contract call - it should match what we just got back in the poolKey + poolAppId = ( + await validatorMasterClient.getPoolAppId( + { validatorId: firstPoolKey.id, poolId: firstPoolKey.poolId }, + { sendParams: { populateAppCallResources: true } } + ) + ).return!; + expect(firstPoolKey.poolAppId).toEqual(poolAppId); + + const stateData = await getValidatorState(validatorMasterClient, validatorId); + expect(stateData.numPools).toEqual(1); + expect(stateData.totalAlgoStaked).toEqual(0n); + expect(stateData.totalStakers).toEqual(0n); + expect(stateData.rewardTokenHeldBack).toEqual(0n); + + const poolInfo = await getPoolInfo(validatorMasterClient, firstPoolKey); + expect(poolInfo.poolAppId).toEqual(BigInt(poolAppId)); + expect(poolInfo.totalStakers).toEqual(0); + expect(poolInfo.totalAlgoStaked).toEqual(0n); + }); + + // Creates dummy staker: + // adds 1000 algo (plus enough to cover staker mbr) + test('firstStaker', async () => { + // Fund a 'staker account' that will be the new 'staker' + const stakerAccount = await getTestAccount( + { initialFunds: AlgoAmount.Algos(5000), suppressLog: true }, + fixture.context.algod, + fixture.context.kmd + ); + stakerAccounts.push(stakerAccount); + // opt-in to reward token + await assetOptIn({ account: stakerAccount, assetId: Number(rewardTokenID) }, fixture.context.algod); + + // now stake 1000(+mbr), min for this pool - for the first time - which means actual stake amount will be reduced + // by 'first time staker' fee to cover MBR (which goes to VALIDATOR contract account, not staker contract account!) + // we pay the extra here so the final staked amount should be exactly 1000 + const stakeAmount1 = AlgoAmount.MicroAlgos( + AlgoAmount.Algos(1000).microAlgos + AlgoAmount.MicroAlgos(Number(stakerMbr)).microAlgos + ); + const [stakedPoolKey] = await addStake( + fixture.context, + validatorMasterClient, + validatorId, + stakerAccount, + stakeAmount1, + 0n + ); + // should match info from first staking pool + expect(stakedPoolKey.id).toEqual(firstPoolKey.id); + expect(stakedPoolKey.poolId).toEqual(firstPoolKey.poolId); + expect(stakedPoolKey.poolAppId).toEqual(firstPoolKey.poolAppId); + + const poolInfo = await getPoolInfo(validatorMasterClient, firstPoolKey); + expect(poolInfo.totalStakers).toEqual(1); + expect(poolInfo.totalAlgoStaked).toEqual(BigInt(stakeAmount1.microAlgos - Number(stakerMbr))); + + expect((await getValidatorState(validatorMasterClient, validatorId)).totalStakers).toEqual(1n); + }); + + test('testFirstRewards', async () => { + // increment time a day(+) at a time per transaction + await fixture.context.algod.setBlockOffsetTimestamp(60 * 60 * 25).do(); + + const origValidatorState = await getValidatorState(validatorMasterClient, validatorId); + const ownerBalance = await fixture.context.algod.accountInformation(validatorOwnerAccount.addr).do(); + const stakersPriorToReward = await getStakeInfoFromBoxValue(firstPoolClient); + + const reward = AlgoAmount.Algos(200); + + // put some test 'reward' algos into staking pool - reward tokens are already there + await transferAlgos( + { + from: fixture.context.testAccount, + to: getApplicationAddress(firstPoolKey.poolAppId), + amount: reward, + }, + fixture.context.algod + ); + + const poolInfo = await getPoolInfo(validatorMasterClient, firstPoolKey); + consoleLogger.info(`pool stakers:${poolInfo.totalStakers}, staked:${poolInfo.totalAlgoStaked}`); + + // Perform epoch payout calculation - we also get back how much it cost to issue the txn + const fees = await epochBalanceUpdate(firstPoolClient); + const expectedValidatorReward = reward.microAlgos * (PctToValidator / 100); + + const newValidatorState = await getValidatorState(validatorMasterClient, validatorId); + const newOwnerBalance = await fixture.context.algod.accountInformation(validatorOwnerAccount.addr).do(); + // validator owner should have gotten the expected reward (minus the fees they just paid ofc) + expect(newOwnerBalance.amount).toEqual(ownerBalance.amount - fees.microAlgos + expectedValidatorReward); + + // Verify all the stakers in the pool got what we think they should have + const stakersAfterReward = await getStakeInfoFromBoxValue(firstPoolClient); + + await verifyRewardAmounts( + fixture.context, + (BigInt(reward.microAlgos) - BigInt(expectedValidatorReward)) as bigint, + BigInt(tokenRewardPerPayout), + stakersPriorToReward as StakedInfo[], + stakersAfterReward as StakedInfo[], + 1 as number + ); + + // the total staked should have grown as well - reward minus what the validator was paid in their commission + expect(Number(newValidatorState.totalAlgoStaked)).toEqual( + Number(origValidatorState.totalAlgoStaked) + (reward.microAlgos - expectedValidatorReward) + ); + // await logStakingPoolInfo(fixture.context, firstPoolKey.poolAppId, 'tokenRewardCheck'); + + // the reward tokens 'held' back should've grown by the token payout amount + expect(newValidatorState.rewardTokenHeldBack).toEqual(BigInt(validatorConfig.RewardPerPayout)); + + const poolBalance = await getPoolAvailBalance(fixture.context, firstPoolKey); + expect(poolBalance).toEqual(newValidatorState.totalAlgoStaked); + }); + + test('extractRewards', async () => { + const origStakerBalance = await fixture.context.algod.accountInformation(stakerAccounts[0].addr).do(); + + // Remove it all + const removeFees = await removeStake(firstPoolClient, stakerAccounts[0], AlgoAmount.Algos(1190)); + + const newStakerBalance = await fixture.context.algod.accountInformation(stakerAccounts[0].addr).do(); + // 1000 algos staked + 190 reward (- .004 in fees for removing stake) + expect(newStakerBalance.amount).toEqual( + origStakerBalance.amount + AlgoAmount.Algos(1190).microAlgos - removeFees + ); + // verify that reward token payout came to us + const assetInfo = await fixture.context.algod + .accountAssetInformation(stakerAccounts[0].addr, Number(rewardTokenID)) + .do(); + expect(BigInt(assetInfo['asset-holding'].amount)).toEqual(tokenRewardPerPayout); + + // no one should be left and be 0 balance + const postRemovePoolInfo = await getPoolInfo(validatorMasterClient, firstPoolKey); + expect(postRemovePoolInfo.totalStakers).toEqual(0); + expect(postRemovePoolInfo.totalAlgoStaked).toEqual(0n); + + const newValidatorState = await getValidatorState(validatorMasterClient, validatorId); + expect(Number(newValidatorState.totalAlgoStaked)).toEqual(0); + expect(Number(newValidatorState.totalStakers)).toEqual(0); + expect(newValidatorState.rewardTokenHeldBack).toEqual(0n); + + const poolBalance = await getPoolAvailBalance(fixture.context, firstPoolKey); + expect(poolBalance).toEqual(newValidatorState.totalAlgoStaked); + }); + + test('testPartialReward', async () => { + // increment 1 hour at a time per transaction + await fixture.context.algod.setBlockOffsetTimestamp(60 * 60).do(); + + // loop until we get a payout (from prior 'too early' state) + for (let i = 0; i < 24; i += 1) { + try { + await epochBalanceUpdate(firstPoolClient); + break; + } catch (exception) { + // move the clock by issuing a txn. + await transferAlgos( + { + from: fixture.context.testAccount, + to: getApplicationAddress(firstPoolKey.poolAppId), + amount: AlgoAmount.Algos(10), + }, + fixture.context.algod + ); + } + } + + // double-check no one should be left and be 0 balance + const checkPoolInfo = await getPoolInfo(validatorMasterClient, firstPoolKey); + expect(checkPoolInfo.totalStakers).toEqual(0); + expect(checkPoolInfo.totalAlgoStaked).toEqual(0n); + + const checkValidatorState = await getValidatorState(validatorMasterClient, validatorId); + expect(Number(checkValidatorState.totalAlgoStaked)).toEqual(0); + expect(Number(checkValidatorState.totalStakers)).toEqual(0); + + // Ok, re-enter the pool - but we'll be in right off the bat and be there for full epoch + // now stake 1000(+mbr), min for this pool - for the first time - which means actual stake amount will be reduced + // by 'first time staker' fee to cover MBR (which goes to VALIDATOR contract account, not staker contract account!) + // we pay the extra here so the final staked amount should be exactly 1000 + const stakeAmount1 = AlgoAmount.Algos(1000); + // Add stake for first staker - partial epoch + const [aPoolKey] = await addStake( + fixture.context, + validatorMasterClient, + validatorId, + stakerAccounts[0], + stakeAmount1, + 0n + ); + expect(aPoolKey.poolAppId).toEqual(aPoolKey.poolAppId); + + const staker1Info = await getStakerInfo(firstPoolClient, stakerAccounts[0]); + const entryTime = new Date(Number(staker1Info.entryTime) * 1000); // convert to ms + const stakingPoolGS = await firstPoolClient.appClient.getGlobalState(); + const lastPayoutTime = new Date(Number(stakingPoolGS.lastPayout.value as bigint) * 1000); + consoleLogger.info(`lastPayout:${lastPayoutTime.toString()}, new entry time: ${entryTime.toString()}`); + + // Ok - bump time so that the next staker will be towards tail end of next epoch payout + await fixture.context.algod.setBlockOffsetTimestamp(60 * 60 * 24).do(); + + // Add second (brand new!) staker - with same amount entered - but entering later (so it will be a 'partial' + // entry into the epoch (so we can ensure partial payout occurs) + const partialEpochStaker = await getTestAccount( + { initialFunds: AlgoAmount.Algos(5000), suppressLog: true }, + fixture.context.algod, + fixture.context.kmd + ); + stakerAccounts.push(partialEpochStaker); + // opt-in to reward token + await assetOptIn({ account: partialEpochStaker, assetId: Number(rewardTokenID) }, fixture.context.algod); + + const stakeAmount2 = AlgoAmount.MicroAlgos( + AlgoAmount.Algos(1000).microAlgos + AlgoAmount.MicroAlgos(Number(stakerMbr)).microAlgos + ); + + // Add stake for partial-epoch staker + const [newPoolKey] = await addStake( + fixture.context, + validatorMasterClient, + validatorId, + partialEpochStaker, + stakeAmount2, + 0n + ); + + expect(newPoolKey.poolAppId).toEqual(aPoolKey.poolAppId); + const staker2Info = await getStakerInfo(firstPoolClient, partialEpochStaker); + const staker2Entry = new Date(Number(staker2Info.entryTime) * 1000); + consoleLogger.info(`partialEpochStaker: new entry time: ${staker2Entry.toString()}`); + + await logStakingPoolInfo(fixture.context, firstPoolKey.poolAppId, 'should have two stakers'); + + // ok now do payouts - and see if we can verify the expected totals + const poolInfo = await getPoolInfo(validatorMasterClient, aPoolKey); + expect(poolInfo.totalStakers).toEqual(2); + // only subtract out 1 staker mbr because only the 'fullEpochStaker' will be 'new' to staking + expect(poolInfo.totalAlgoStaked).toEqual(BigInt(stakeAmount1.microAlgos + stakeAmount2.microAlgos) - stakerMbr); + + // What's pool's current balance + const poolBalance = await getPoolAvailBalance(fixture.context, firstPoolKey); + const knownReward = poolBalance - poolInfo.totalAlgoStaked; + const expectedValidatorReward = Number(knownReward) * (PctToValidator / 100); + + const stakersPriorToReward = await getStakeInfoFromBoxValue(firstPoolClient); + + // do reward calcs + await epochBalanceUpdate(firstPoolClient); + const stakersAfterReward = await getStakeInfoFromBoxValue(firstPoolClient); + + await logStakingPoolInfo(fixture.context, firstPoolKey.poolAppId, 'after payouts'); + await verifyRewardAmounts( + fixture.context, + knownReward - BigInt(expectedValidatorReward), + BigInt(tokenRewardPerPayout), + stakersPriorToReward, + stakersAfterReward, + 1 + ); + }); +}); + +describe('TokenRewardOnlyTokens', () => { + beforeEach(fixture.beforeEach); + beforeEach(logs.beforeEach); + afterEach(logs.afterEach); + + let validatorId: number; + let validatorOwnerAccount: Account; + let validatorConfig: ValidatorConfig; + let firstPoolKey: ValidatorPoolKey; + let firstPoolClient: StakingPoolClient; + let stakerAccount: Account; + + let rewardTokenID: bigint; + const tokenRewardPerPayout = 1000n; + + beforeAll(async () => { + // Create a reward token to pay out to stakers + const tokenCreatorAccount = await getTestAccount( + { initialFunds: AlgoAmount.Algos(5000), suppressLog: true }, + fixture.context.algod, + fixture.context.kmd + ); + rewardTokenID = await createAsset( + fixture.context.algod, + tokenCreatorAccount, + 'Reward Token', + 'RWDTOKEN', + 100_000, + 0 + ); + + validatorOwnerAccount = await getTestAccount( + { initialFunds: AlgoAmount.Algos(500), suppressLog: true }, + fixture.context.algod, + fixture.context.kmd + ); + consoleLogger.info(`validator account ${validatorOwnerAccount.addr}`); + + validatorConfig = createValidatorConfig({ + Owner: validatorOwnerAccount.addr, + Manager: validatorOwnerAccount.addr, + MinEntryStake: BigInt(AlgoAmount.Algos(1000).microAlgos), + MaxAlgoPerPool: BigInt(MaxAlgoPerPool), // this comes into play in later tests !! + PercentToValidator: 5 * 10000, + ValidatorCommissionAddress: validatorOwnerAccount.addr, + RewardTokenID: rewardTokenID, + RewardPerPayout: tokenRewardPerPayout, // 1000 tokens per epoch + }); + validatorId = await addValidator( + fixture.context, + validatorMasterClient, + validatorOwnerAccount, + validatorConfig, + validatorMbr + ); + + // Add new pool - then we'll add stake and verify balances. + // first pool needs extra .1 to cover MBR of opted-in reward token ! + firstPoolKey = await addStakingPool( + fixture.context, + validatorMasterClient, + validatorId, + 1, + validatorOwnerAccount, + poolMbr, + poolInitMbr + BigInt(AlgoAmount.Algos(0.1).microAlgos) + ); + // should be [validator id, pool id (1 based)] + expect(firstPoolKey.id).toEqual(BigInt(validatorId)); + expect(firstPoolKey.poolId).toEqual(1n); + + await transferAsset( + { + from: tokenCreatorAccount, + to: getApplicationAddress(firstPoolKey.poolAppId), + assetId: Number(rewardTokenID), + amount: 5000, + }, + fixture.context.algod + ); + + firstPoolClient = new StakingPoolClient( + { sender: validatorOwnerAccount, resolveBy: 'id', id: firstPoolKey.poolAppId }, + fixture.context.algod + ); + }); + + // Creates dummy staker: + // adds 1000 algo (plus enough to cover staker mbr) + test('firstStaker', async () => { + // Fund a 'staker account' that will be the new 'staker' + stakerAccount = await getTestAccount( + { initialFunds: AlgoAmount.Algos(5000), suppressLog: true }, + fixture.context.algod, + fixture.context.kmd + ); + // opt-in to reward token + await assetOptIn({ account: stakerAccount, assetId: Number(rewardTokenID) }, fixture.context.algod); + + // now stake 1000(+mbr), min for this pool - for the first time - which means actual stake amount will be reduced + // by 'first time staker' fee to cover MBR (which goes to VALIDATOR contract account, not staker contract account!) + // we pay the extra here so the final staked amount should be exactly 1000 + const stakeAmount1 = AlgoAmount.MicroAlgos( + AlgoAmount.Algos(1000).microAlgos + AlgoAmount.MicroAlgos(Number(stakerMbr)).microAlgos + ); + await addStake(fixture.context, validatorMasterClient, validatorId, stakerAccount, stakeAmount1, 0n); + const poolInfo = await getPoolInfo(validatorMasterClient, firstPoolKey); + expect(poolInfo.totalAlgoStaked).toEqual(BigInt(stakeAmount1.microAlgos - Number(stakerMbr))); + expect((await getValidatorState(validatorMasterClient, validatorId)).totalStakers).toEqual(1n); + }); + + test('testFirstRewards', async () => { + // increment time a day at a time per transaction + await fixture.context.algod.setBlockOffsetTimestamp(60 * 60 * 25).do(); + + const origValidatorState = await getValidatorState(validatorMasterClient, validatorId); + const ownerBalance = await fixture.context.algod.accountInformation(validatorOwnerAccount.addr).do(); + const stakersPriorToReward = await getStakeInfoFromBoxValue(firstPoolClient); + + // Perform epoch payout calculation - should be 0 algo reward (!) + // we should just do token payout + const fees = await epochBalanceUpdate(firstPoolClient); + + const newValidatorState = await getValidatorState(validatorMasterClient, validatorId); + const newOwnerBalance = await fixture.context.algod.accountInformation(validatorOwnerAccount.addr).do(); + // validator owner balance shouldn't have changed (other than fees to call epoch update) + expect(newOwnerBalance.amount).toEqual(ownerBalance.amount - fees.microAlgos); + + // Verify all the stakers in the pool got what we think they should have + const stakersAfterReward = await getStakeInfoFromBoxValue(firstPoolClient); + + await verifyRewardAmounts( + fixture.context, + 0n, // 0 algo reward + BigInt(tokenRewardPerPayout), + stakersPriorToReward as StakedInfo[], + stakersAfterReward as StakedInfo[], + 1 as number + ); + + // the total staked should have grown as well - reward minus what the validator was paid in their commission + expect(newValidatorState.totalAlgoStaked).toEqual(origValidatorState.totalAlgoStaked); + + // the reward tokens 'held' back should've grown by the token payout amount + expect(newValidatorState.rewardTokenHeldBack).toEqual(BigInt(validatorConfig.RewardPerPayout)); + + const poolBalance = await getPoolAvailBalance(fixture.context, firstPoolKey); + expect(poolBalance).toEqual(newValidatorState.totalAlgoStaked); + }); + + test('extractRewards', async () => { + const origStakerBalance = await fixture.context.algod.accountInformation(stakerAccount.addr).do(); + + // Remove it all - but w/ claimTokens call instead of removeStake + const removeFees = await claimTokens(firstPoolClient, stakerAccount); + + const newStakerBalance = await fixture.context.algod.accountInformation(stakerAccount.addr).do(); + // 1000 algos staked + 190 reward (- .004 in fees for removing stake) + expect(newStakerBalance.amount).toEqual(origStakerBalance.amount - removeFees); + // verify that reward token payout came to us + const assetInfo = await fixture.context.algod + .accountAssetInformation(stakerAccount.addr, Number(rewardTokenID)) + .do(); + expect(BigInt(assetInfo['asset-holding'].amount)).toEqual(tokenRewardPerPayout); + + const newValidatorState = await getValidatorState(validatorMasterClient, validatorId); + // total staked should be same -staker shouldn't have gone away - token held back should've gone to 0 + expect(newValidatorState.totalAlgoStaked).toEqual(BigInt(AlgoAmount.Algos(1000).microAlgos)); + expect(newValidatorState.totalStakers).toEqual(1n); + expect(newValidatorState.rewardTokenHeldBack).toEqual(0n); + + const poolBalance = await getPoolAvailBalance(fixture.context, firstPoolKey); + expect(poolBalance).toEqual(newValidatorState.totalAlgoStaked); + }); +}); + +describe('DoublePoolWTokens', () => { + beforeEach(fixture.beforeEach); + beforeEach(logs.beforeEach); + afterEach(logs.afterEach); + + let validatorId: number; + let validatorOwnerAccount: Account; + let validatorConfig: ValidatorConfig; + const stakerAccounts: Account[] = []; + let poolAppId: bigint; + const poolKeys: ValidatorPoolKey[] = []; + const poolClients: StakingPoolClient[] = []; + + let rewardTokenID: bigint; + const PctToValidator = 5; + const decimals = 0; + const tokenRewardPerPayout = BigInt(1000 * 10 ** decimals); + + // add validator and 1 pool for subsequent stake tests + beforeAll(async () => { + // Create a reward token to pay out to stakers + const tokenCreatorAccount = await getTestAccount( + { initialFunds: AlgoAmount.Algos(5000), suppressLog: true }, + fixture.context.algod, + fixture.context.kmd + ); + rewardTokenID = await createAsset( + fixture.context.algod, + tokenCreatorAccount, + 'Reward Token', + 'RWDTOKEN', + 100_000, + decimals + ); + + // Fund a 'validator account' that will be the validator owner. + validatorOwnerAccount = await getTestAccount( + { initialFunds: AlgoAmount.Algos(500), suppressLog: true }, + fixture.context.algod, + fixture.context.kmd + ); + consoleLogger.info(`validator account ${validatorOwnerAccount.addr}`); + + validatorConfig = createValidatorConfig({ + Owner: validatorOwnerAccount.addr, + Manager: validatorOwnerAccount.addr, + MinEntryStake: BigInt(AlgoAmount.Algos(1000).microAlgos), + MaxAlgoPerPool: BigInt(AlgoAmount.Algos(5_000).microAlgos), // just do 5k per pool + PercentToValidator: PctToValidator * 10000, + ValidatorCommissionAddress: validatorOwnerAccount.addr, + RewardTokenID: rewardTokenID, + RewardPerPayout: tokenRewardPerPayout, // 1000 tokens per epoch + }); + validatorId = await addValidator( + fixture.context, + validatorMasterClient, + validatorOwnerAccount, + validatorConfig, + validatorMbr + ); + + // Add new pool - then we'll add stake and verify balances. + // first pool needs extra .1 to cover MBR of opted-in reward token ! + poolKeys.push( + await addStakingPool( + fixture.context, + validatorMasterClient, + validatorId, + 1, + validatorOwnerAccount, + poolMbr, + poolInitMbr + BigInt(AlgoAmount.Algos(0.1).microAlgos) + ) + ); + // should be [validator id, pool id (1 based)] + expect(poolKeys[0].id).toEqual(BigInt(validatorId)); + expect(poolKeys[0].poolId).toEqual(1n); + + // now send a bunch of our reward token to the pool ! + await transferAsset( + { + from: tokenCreatorAccount, + to: getApplicationAddress(poolKeys[0].poolAppId), + assetId: Number(rewardTokenID), + amount: 5000 * 10 ** decimals, + }, + fixture.context.algod + ); + + poolClients.push( + new StakingPoolClient( + { sender: validatorOwnerAccount, resolveBy: 'id', id: poolKeys[0].poolAppId }, + fixture.context.algod + ) + ); + + // get the app id via contract call - it should match what we just got back in the poolKey + poolAppId = ( + await validatorMasterClient.getPoolAppId( + { validatorId: poolKeys[0].id, poolId: poolKeys[0].poolId }, + { sendParams: { populateAppCallResources: true } } + ) + ).return!; + expect(poolKeys[0].poolAppId).toEqual(poolAppId); + + const stateData = await getValidatorState(validatorMasterClient, validatorId); + expect(stateData.numPools).toEqual(1); + expect(stateData.totalAlgoStaked).toEqual(0n); + expect(stateData.totalStakers).toEqual(0n); + expect(stateData.rewardTokenHeldBack).toEqual(0n); + + const poolInfo = await getPoolInfo(validatorMasterClient, poolKeys[0]); + expect(poolInfo.poolAppId).toEqual(BigInt(poolAppId)); + expect(poolInfo.totalStakers).toEqual(0); + expect(poolInfo.totalAlgoStaked).toEqual(0n); + + // ok - all in working order.. add second pool as well - no need to do + poolKeys.push( + await addStakingPool( + fixture.context, + validatorMasterClient, + validatorId, + 1, + validatorOwnerAccount, + poolMbr, + poolInitMbr // no extra .1 for pool 2 ! + ) + ); + expect(poolKeys[1].poolId).toEqual(BigInt(2)); + poolClients.push( + new StakingPoolClient( + { sender: validatorOwnerAccount, resolveBy: 'id', id: poolKeys[1].poolAppId }, + fixture.context.algod + ) + ); + }); + + // add 2 stakers - full pool amount each + test('addStakers', async () => { + for (let i = 0; i < 2; i += 1) { + const stakerAccount = await getTestAccount( + { initialFunds: AlgoAmount.Algos(6000), suppressLog: true }, + fixture.context.algod, + fixture.context.kmd + ); + stakerAccounts.push(stakerAccount); + // opt-in to reward token + await assetOptIn({ account: stakerAccount, assetId: Number(rewardTokenID) }, fixture.context.algod); + + const stakeAmount = AlgoAmount.MicroAlgos( + AlgoAmount.Algos(5000).microAlgos + AlgoAmount.MicroAlgos(Number(stakerMbr)).microAlgos + ); + const [stakedPoolKey] = await addStake( + fixture.context, + validatorMasterClient, + validatorId, + stakerAccount, + stakeAmount, + 0n + ); + // each staker should land in diff pool because we're maxing the pool + expect(stakedPoolKey.id).toEqual(poolKeys[i].id); + expect(stakedPoolKey.poolId).toEqual(poolKeys[i].poolId); + expect(stakedPoolKey.poolAppId).toEqual(poolKeys[i].poolAppId); + + const poolInfo = await getPoolInfo(validatorMasterClient, poolKeys[i]); + expect(poolInfo.totalStakers).toEqual(1); + expect(poolInfo.totalAlgoStaked).toEqual(BigInt(stakeAmount.microAlgos - Number(stakerMbr))); + } + + expect((await getValidatorState(validatorMasterClient, validatorId)).totalStakers).toEqual(BigInt(2)); + expect((await getValidatorState(validatorMasterClient, validatorId)).totalAlgoStaked).toEqual( + BigInt(AlgoAmount.Algos(10000).microAlgos) + ); + }); + + test('testFirstRewards', async () => { + // increment time a day at a time per transaction + await fixture.context.algod.setBlockOffsetTimestamp(60 * 60 * 24).do(); + + let cumTokRewards = 0n; + for (let poolIdx = 0; poolIdx < 2; poolIdx += 1) { + consoleLogger.info(`testing rewards payout for pool # ${poolIdx + 1}`); + const origValidatorState = await getValidatorState(validatorMasterClient, validatorId); + const ownerBalance = await fixture.context.algod.accountInformation(validatorOwnerAccount.addr).do(); + const stakersPriorToReward = await getStakeInfoFromBoxValue(poolClients[poolIdx]); + const reward = AlgoAmount.Algos(200); + // put some test 'reward' algos into each staking pool + await transferAlgos( + { + from: fixture.context.testAccount, + to: getApplicationAddress(poolKeys[poolIdx].poolAppId), + amount: reward, + }, + fixture.context.algod + ); + // Perform epoch payout calculation - we also get back how much it cost to issue the txn + const fees = await epochBalanceUpdate(poolClients[poolIdx]); + const expectedValidatorReward = reward.microAlgos * (PctToValidator / 100); + const newValidatorState = await getValidatorState(validatorMasterClient, validatorId); + const newOwnerBalance = await fixture.context.algod.accountInformation(validatorOwnerAccount.addr).do(); + // validator owner should have gotten the expected reward (minus the fees they just paid ofc) + expect(newOwnerBalance.amount).toEqual(ownerBalance.amount - fees.microAlgos + expectedValidatorReward); + + // Verify all the stakers in the pool got what we think they should have + const stakersAfterReward = await getStakeInfoFromBoxValue(poolClients[poolIdx]); + + const payoutRatio = await getTokenPayoutRatio(validatorMasterClient, validatorId); + const tokenRewardForThisPool = + (BigInt(tokenRewardPerPayout) * payoutRatio.PoolPctOfWhole[poolIdx]) / BigInt(1_000_000); + cumTokRewards += tokenRewardForThisPool; + + await verifyRewardAmounts( + fixture.context, + (BigInt(reward.microAlgos) - BigInt(expectedValidatorReward)) as bigint, + tokenRewardForThisPool, // we split evenly into 2 pools - so token reward should be as well + stakersPriorToReward as StakedInfo[], + stakersAfterReward as StakedInfo[], + 1 as number + ); + + // the total staked should have grown as well - reward minus what the validator was paid in their commission + expect(Number(newValidatorState.totalAlgoStaked)).toEqual( + Number(origValidatorState.totalAlgoStaked) + (reward.microAlgos - expectedValidatorReward) + ); + + // the reward tokens 'held' back should've grown by the token payout amount for this pool + expect(newValidatorState.rewardTokenHeldBack).toEqual(cumTokRewards); + } + }); + + test('extractRewards', async () => { + for (let i = 0; i < 2; i += 1) { + const origPoolInfo = await getPoolInfo(validatorMasterClient, poolKeys[i]); + const origValidatorState = await getValidatorState(validatorMasterClient, validatorId); + const stakerInfo = await getStakerInfo(poolClients[i], stakerAccounts[i]); + const origStakerBalance = await fixture.context.algod.accountInformation(stakerAccounts[i].addr).do(); + const origStakerAssetBalance = await fixture.context.algod + .accountAssetInformation(stakerAccounts[i].addr, Number(rewardTokenID)) + .do(); + + // Remove all stake + await removeStake(poolClients[i], stakerAccounts[i], AlgoAmount.Algos(0)); + const removeFees = AlgoAmount.MicroAlgos(7000).microAlgos; + + const newStakerBalance = await fixture.context.algod.accountInformation(stakerAccounts[i].addr).do(); + + expect(BigInt(newStakerBalance.amount)).toEqual( + BigInt(origStakerBalance.amount) + stakerInfo.balance - BigInt(removeFees) + ); + // verify that pending reward token payout came to us + const newStakerAssetBalance = await fixture.context.algod + .accountAssetInformation(stakerAccounts[0].addr, Number(rewardTokenID)) + .do(); + expect(BigInt(newStakerAssetBalance['asset-holding'].amount)).toEqual( + BigInt(origStakerAssetBalance['asset-holding'].amount) + stakerInfo.rewardTokenBalance + ); + + // no one should be left and be 0 balance + const postRemovePoolInfo = await getPoolInfo(validatorMasterClient, poolKeys[i]); + expect(postRemovePoolInfo.totalStakers).toEqual(origPoolInfo.totalStakers - 1); + expect(postRemovePoolInfo.totalAlgoStaked).toEqual( + BigInt(origPoolInfo.totalAlgoStaked - stakerInfo.balance) + ); + + const newValidatorState = await getValidatorState(validatorMasterClient, validatorId); + expect(newValidatorState.totalAlgoStaked).toEqual(origValidatorState.totalAlgoStaked - stakerInfo.balance); + expect(newValidatorState.totalStakers).toEqual(origValidatorState.totalStakers - 1n); + expect(newValidatorState.rewardTokenHeldBack).toEqual( + BigInt(origValidatorState.rewardTokenHeldBack - stakerInfo.rewardTokenBalance) + ); + } + }); +}); + +describe('TokenGatingByCreator', () => { + beforeEach(fixture.beforeEach); + beforeEach(logs.beforeEach); + afterEach(logs.afterEach); + + let validatorId: number; + + let tokenCreatorAccount: Account; + let validatorOwnerAccount: Account; + let validatorConfig: ValidatorConfig; + let firstPoolKey: ValidatorPoolKey; + + let gatingToken1Id: bigint; + let gatingToken2Id: bigint; + + // add validator and 1 pool for subsequent stake tests + beforeAll(async () => { + // Create a token that will be required for stakers to possess in order to stake + tokenCreatorAccount = await getTestAccount( + { initialFunds: AlgoAmount.Algos(5000), suppressLog: true }, + fixture.context.algod, + fixture.context.kmd + ); + gatingToken1Id = await createAsset( + fixture.context.algod, + tokenCreatorAccount, + 'Gating Token 1', + 'GATETK1', + 10, + 0 + ); + gatingToken2Id = await createAsset( + fixture.context.algod, + tokenCreatorAccount, + 'Gating Token 2', + 'GATETK2', + 10, + 0 + ); + + // Fund a 'validator account' that will be the validator owner. + validatorOwnerAccount = await getTestAccount( + { initialFunds: AlgoAmount.Algos(500), suppressLog: true }, + fixture.context.algod, + fixture.context.kmd + ); + consoleLogger.info(`validator account ${validatorOwnerAccount.addr}`); + + validatorConfig = createValidatorConfig({ + Owner: validatorOwnerAccount.addr, + Manager: validatorOwnerAccount.addr, + MinEntryStake: BigInt(AlgoAmount.Algos(1000).microAlgos), + MaxAlgoPerPool: BigInt(MaxAlgoPerPool), // this comes into play in later tests !! + PercentToValidator: 5 * 10000, + ValidatorCommissionAddress: validatorOwnerAccount.addr, + // stakers must possess any token created by tokenCreatorAccount + EntryGatingType: GATING_TYPE_ASSETS_CREATED_BY, + EntryGatingValue: decodeAddress(tokenCreatorAccount.addr).publicKey, + GatingAssetMinBalance: 2n, // require 2 so we can see if only having 1 fails us + }); + validatorId = await addValidator( + fixture.context, + validatorMasterClient, + validatorOwnerAccount, + validatorConfig, + validatorMbr + ); + + firstPoolKey = await addStakingPool( + fixture.context, + validatorMasterClient, + validatorId, + 1, + validatorOwnerAccount, + poolMbr, + poolInitMbr + ); + }); + + describe('stakeTest', () => { + beforeEach(fixture.beforeEach); + beforeEach(logs.beforeEach); + afterEach(logs.afterEach); + + let stakerAccount: Account; + let stakerCreatedTokenId: bigint; + beforeAll(async () => { + // Fund a 'staker account' that will be the new 'staker' + stakerAccount = await getTestAccount( + { initialFunds: AlgoAmount.Algos(5000), suppressLog: true }, + fixture.context.algod, + fixture.context.kmd + ); + + await assetOptIn({ account: stakerAccount, assetId: Number(gatingToken1Id) }, fixture.context.algod); + await assetOptIn({ account: stakerAccount, assetId: Number(gatingToken2Id) }, fixture.context.algod); + // Send gating tokens to our staker for use in tests + await transferAsset( + { + from: tokenCreatorAccount, + to: stakerAccount, + assetId: Number(gatingToken1Id), + amount: 2, + }, + fixture.context.algod + ); + await transferAsset( + { + from: tokenCreatorAccount, + to: stakerAccount, + assetId: Number(gatingToken2Id), + amount: 2, + }, + fixture.context.algod + ); + + stakerCreatedTokenId = await createAsset( + fixture.context.algod, + stakerAccount, + 'Dummy Token', + 'DUMMY', + 10, + 0 + ); + }); + + test('stakeNoTokenOffered', async () => { + const stakeAmount1 = AlgoAmount.MicroAlgos( + AlgoAmount.Algos(1000).microAlgos + AlgoAmount.MicroAlgos(Number(stakerMbr)).microAlgos + ); + await expect( + addStake(fixture.context, validatorMasterClient, validatorId, stakerAccount, stakeAmount1, 0n) + ).rejects.toThrowError(); + }); + + test('stakeWrongTokenOffered', async () => { + const stakeAmount1 = AlgoAmount.MicroAlgos( + AlgoAmount.Algos(1000).microAlgos + AlgoAmount.MicroAlgos(Number(stakerMbr)).microAlgos + ); + await expect( + addStake( + fixture.context, + validatorMasterClient, + validatorId, + stakerAccount, + stakeAmount1, + stakerCreatedTokenId + ) + ).rejects.toThrowError(); + }); + + test('stakeWGatingToken1', async () => { + const stakeAmount1 = AlgoAmount.MicroAlgos( + AlgoAmount.Algos(1000).microAlgos + AlgoAmount.MicroAlgos(Number(stakerMbr)).microAlgos + ); + const [stakedPoolKey] = await addStake( + fixture.context, + validatorMasterClient, + validatorId, + stakerAccount, + stakeAmount1, + gatingToken1Id + ); + // should match info from first staking pool + expect(stakedPoolKey.id).toEqual(firstPoolKey.id); + expect(stakedPoolKey.poolId).toEqual(firstPoolKey.poolId); + expect(stakedPoolKey.poolAppId).toEqual(firstPoolKey.poolAppId); + + const poolInfo = await getPoolInfo(validatorMasterClient, firstPoolKey); + expect(poolInfo.totalStakers).toEqual(1); + expect(poolInfo.totalAlgoStaked).toEqual(BigInt(stakeAmount1.microAlgos - Number(stakerMbr))); + + expect((await getValidatorState(validatorMasterClient, validatorId)).totalStakers).toEqual(1n); + }); + + test('stakeWGatingToken2', async () => { + const stakeAmount2 = AlgoAmount.MicroAlgos(AlgoAmount.Algos(1000).microAlgos); + const [stakedPoolKey] = await addStake( + fixture.context, + validatorMasterClient, + validatorId, + stakerAccount, + stakeAmount2, + gatingToken2Id + ); + // should match info from first staking pool + expect(stakedPoolKey.id).toEqual(firstPoolKey.id); + expect(stakedPoolKey.poolId).toEqual(firstPoolKey.poolId); + expect(stakedPoolKey.poolAppId).toEqual(firstPoolKey.poolAppId); + + const poolInfo = await getPoolInfo(validatorMasterClient, firstPoolKey); + expect(poolInfo.totalStakers).toEqual(1); + expect(poolInfo.totalAlgoStaked).toEqual(BigInt(stakeAmount2.microAlgos * 2)); + + expect((await getValidatorState(validatorMasterClient, validatorId)).totalStakers).toEqual(1n); + }); + + test('stakeWGatingToken2NotMeetingBalReq', async () => { + // send 1 of the token back to creator - we should now fail to add more stake because we don't meet the token minimum + await transferAsset( + { + from: stakerAccount, + to: tokenCreatorAccount, + assetId: Number(gatingToken2Id), + amount: 1, + }, + fixture.context.algod + ); + + await expect( + addStake( + fixture.context, + validatorMasterClient, + validatorId, + stakerAccount, + AlgoAmount.MicroAlgos(AlgoAmount.Algos(1000).microAlgos), + gatingToken2Id + ) + ).rejects.toThrowError(); + }); + }); +}); + +describe('TokenGatingByAsset', () => { + beforeEach(fixture.beforeEach); + beforeEach(logs.beforeEach); + afterEach(logs.afterEach); + + let validatorId: number; + + let tokenCreatorAccount: Account; + let validatorOwnerAccount: Account; + let validatorConfig: ValidatorConfig; + let firstPoolKey: ValidatorPoolKey; + + let gatingToken1Id: bigint; + let gatingToken2Id: bigint; + + // add validator and 1 pool for subsequent stake tests + beforeAll(async () => { + // Create a token that will be required for stakers to possess in order to stake + tokenCreatorAccount = await getTestAccount( + { initialFunds: AlgoAmount.Algos(5000), suppressLog: true }, + fixture.context.algod, + fixture.context.kmd + ); + gatingToken1Id = await createAsset( + fixture.context.algod, + tokenCreatorAccount, + 'Gating Token 1', + 'GATETK1', + 10, + 0 + ); + gatingToken2Id = await createAsset( + fixture.context.algod, + tokenCreatorAccount, + 'Gating Token 2', + 'GATETK2', + 10, + 0 + ); + + // Fund a 'validator account' that will be the validator owner. + validatorOwnerAccount = await getTestAccount( + { initialFunds: AlgoAmount.Algos(500), suppressLog: true }, + fixture.context.algod, + fixture.context.kmd + ); + consoleLogger.info(`validator account ${validatorOwnerAccount.addr}`); + + validatorConfig = createValidatorConfig({ + Owner: validatorOwnerAccount.addr, + Manager: validatorOwnerAccount.addr, + MinEntryStake: BigInt(AlgoAmount.Algos(1000).microAlgos), + MaxAlgoPerPool: BigInt(MaxAlgoPerPool), // this comes into play in later tests !! + PercentToValidator: 5 * 10000, + ValidatorCommissionAddress: validatorOwnerAccount.addr, + // stakers must possess ONLY the second gating token - explicit id ! + EntryGatingType: GATING_TYPE_ASSET_ID, + EntryGatingValue: gatingValueFromBigint(gatingToken2Id), + GatingAssetMinBalance: 2n, // require 2 so we can see if only having 1 fails us + }); + validatorId = await addValidator( + fixture.context, + validatorMasterClient, + validatorOwnerAccount, + validatorConfig, + validatorMbr + ); + + firstPoolKey = await addStakingPool( + fixture.context, + validatorMasterClient, + validatorId, + 1, + validatorOwnerAccount, + poolMbr, + poolInitMbr + ); + }); + + describe('stakeTest', () => { + beforeEach(fixture.beforeEach); + beforeEach(logs.beforeEach); + afterEach(logs.afterEach); + + let stakerAccount: Account; + let stakerCreatedTokenId: bigint; + beforeAll(async () => { + // Fund a 'staker account' that will be the new 'staker' + stakerAccount = await getTestAccount( + { initialFunds: AlgoAmount.Algos(5000), suppressLog: true }, + fixture.context.algod, + fixture.context.kmd + ); + + await assetOptIn({ account: stakerAccount, assetId: Number(gatingToken1Id) }, fixture.context.algod); + await assetOptIn({ account: stakerAccount, assetId: Number(gatingToken2Id) }, fixture.context.algod); + // Send gating tokens to our staker for use in tests + await transferAsset( + { + from: tokenCreatorAccount, + to: stakerAccount, + assetId: Number(gatingToken1Id), + amount: 2, + }, + fixture.context.algod + ); + await transferAsset( + { + from: tokenCreatorAccount, + to: stakerAccount, + assetId: Number(gatingToken2Id), + amount: 2, + }, + fixture.context.algod + ); + + stakerCreatedTokenId = await createAsset( + fixture.context.algod, + stakerAccount, + 'Dummy Token', + 'DUMMY', + 10, + 0 + ); + }); + + test('stakeNoTokenOffered', async () => { + const stakeAmount1 = AlgoAmount.MicroAlgos( + AlgoAmount.Algos(1000).microAlgos + AlgoAmount.MicroAlgos(Number(stakerMbr)).microAlgos + ); + await expect( + addStake(fixture.context, validatorMasterClient, validatorId, stakerAccount, stakeAmount1, 0n) + ).rejects.toThrowError(); + }); + + test('stakeWrongTokenOffered', async () => { + const stakeAmount1 = AlgoAmount.MicroAlgos( + AlgoAmount.Algos(1000).microAlgos + AlgoAmount.MicroAlgos(Number(stakerMbr)).microAlgos + ); + await expect( + addStake( + fixture.context, + validatorMasterClient, + validatorId, + stakerAccount, + stakeAmount1, + stakerCreatedTokenId + ) + ).rejects.toThrowError(); + }); + + test('stakeWGatingToken1ShouldFail', async () => { + const stakeAmount1 = AlgoAmount.MicroAlgos( + AlgoAmount.Algos(1000).microAlgos + AlgoAmount.MicroAlgos(Number(stakerMbr)).microAlgos + ); + await expect( + addStake( + fixture.context, + validatorMasterClient, + validatorId, + stakerAccount, + stakeAmount1, + gatingToken1Id + ) + ).rejects.toThrowError(); + }); + + test('stakeWGatingToken2ShouldPass', async () => { + const stakeAmount1 = AlgoAmount.MicroAlgos( + AlgoAmount.Algos(1000).microAlgos + AlgoAmount.MicroAlgos(Number(stakerMbr)).microAlgos + ); + const [stakedPoolKey] = await addStake( + fixture.context, + validatorMasterClient, + validatorId, + stakerAccount, + stakeAmount1, + gatingToken2Id + ); + // should match info from first staking pool + expect(stakedPoolKey.id).toEqual(firstPoolKey.id); + expect(stakedPoolKey.poolId).toEqual(firstPoolKey.poolId); + expect(stakedPoolKey.poolAppId).toEqual(firstPoolKey.poolAppId); + + const poolInfo = await getPoolInfo(validatorMasterClient, firstPoolKey); + expect(poolInfo.totalStakers).toEqual(1); + expect(poolInfo.totalAlgoStaked).toEqual(BigInt(stakeAmount1.microAlgos - Number(stakerMbr))); + + expect((await getValidatorState(validatorMasterClient, validatorId)).totalStakers).toEqual(1n); + }); + + test('stakeWGatingToken2NotMeetingBalReq', async () => { + // send 1 of the token back to creator - we should now fail to add more stake because we don't meet the token minimum + await transferAsset( + { + from: stakerAccount, + to: tokenCreatorAccount, + assetId: Number(gatingToken2Id), + amount: 1, + }, + fixture.context.algod + ); + + await expect( + addStake( + fixture.context, + validatorMasterClient, + validatorId, + stakerAccount, + AlgoAmount.MicroAlgos(AlgoAmount.Algos(1000).microAlgos), + gatingToken2Id + ) + ).rejects.toThrowError(); + }); + }); +}); + +describe('SaturatedValidator', () => { + beforeEach(fixture.beforeEach); + beforeEach(logs.beforeEach); + afterEach(logs.afterEach); + + let validatorId: number; + + let validatorOwnerAccount: Account; + let stakerAccount: Account; + let validatorConfig: ValidatorConfig; + const pools: ValidatorPoolKey[] = []; + + let constraints: ProtocolConstraints; + + // add validator and 1 pool for subsequent stake tests + beforeAll(async () => { + constraints = await getProtocolConstraints(validatorMasterClient); + + // Fund a 'validator account' that will be the validator owner. + validatorOwnerAccount = await getTestAccount( + { initialFunds: AlgoAmount.Algos(500), suppressLog: true }, + fixture.context.algod, + fixture.context.kmd + ); + consoleLogger.info(`validator account ${validatorOwnerAccount.addr}`); + + validatorConfig = createValidatorConfig({ + Owner: validatorOwnerAccount.addr, + Manager: validatorOwnerAccount.addr, + MinEntryStake: BigInt(AlgoAmount.Algos(1000).microAlgos), + MaxAlgoPerPool: constraints.MaxAlgoPerPool, + PayoutEveryXMins: 1, + PercentToValidator: 5 * 10000, + ValidatorCommissionAddress: validatorOwnerAccount.addr, + }); + validatorId = await addValidator( + fixture.context, + validatorMasterClient, + validatorOwnerAccount, + validatorConfig, + validatorMbr + ); + + pools.push( + await addStakingPool( + fixture.context, + validatorMasterClient, + validatorId, + 1, + validatorOwnerAccount, + poolMbr, + poolInitMbr + ) + ); + + stakerAccount = await getTestAccount( + { initialFunds: AlgoAmount.Algos(300e6), suppressLog: true }, + fixture.context.algod, + fixture.context.kmd + ); + }); + + // Fill up the first pool completely + test('stakeFillingPool', async () => { + const stakeAmount = AlgoAmount.MicroAlgos(Number(constraints.MaxAlgoPerPool + stakerMbr)); + await addStake(fixture.context, validatorMasterClient, validatorId, stakerAccount, stakeAmount, 0n); + expect((await getValidatorState(validatorMasterClient, validatorId)).totalStakers).toEqual(1n); + const poolInfo = await getPoolInfo(validatorMasterClient, pools[0]); + expect(poolInfo.totalStakers).toEqual(1); + expect(poolInfo.totalAlgoStaked).toEqual(BigInt(stakeAmount.microAlgos - Number(stakerMbr))); + + // try to add again - should fail + await expect( + addStake( + fixture.context, + validatorMasterClient, + validatorId, + stakerAccount, + AlgoAmount.MicroAlgos(1000), + 0n + ) + ).rejects.toThrowError(); + }); + + // Now we add 2 more pools, total of 3 - which means we can have up to 70m * 3 = 210m total stake yet in current config + test('addPools', async () => { + const curSoftMax = await getCurMaxStatePerPool(validatorMasterClient, validatorId); + expect(curSoftMax).toEqual(constraints.MaxAlgoPerPool); + + for (let i = 0; i < 2; i += 1) { + pools.push( + await addStakingPool( + fixture.context, + validatorMasterClient, + validatorId, + 1, + validatorOwnerAccount, + poolMbr, + poolInitMbr + ) + ); + } + expect((await getValidatorState(validatorMasterClient, validatorId)).numPools).toEqual(3); + // Our maximum per pool should've changed now - to be max algo per validator / numNodes (3) + const newSoftMax = await getCurMaxStatePerPool(validatorMasterClient, validatorId); + expect(newSoftMax).toEqual( + BigInt(Math.min(Number(constraints.MaxAlgoPerValidator / 3n), Number(constraints.MaxAlgoPerPool))) + ); + }); + + test('fillNewPools', async () => { + // bump by 15 mins at a time, so we account for the entry time post-dating and can stake and be immediately + // 100% + await fixture.context.algod.setBlockOffsetTimestamp(60 * 15).do(); + + const newSoftMax = await getCurMaxStatePerPool(validatorMasterClient, validatorId); + + let [poolKey] = await addStake( + fixture.context, + validatorMasterClient, + validatorId, + stakerAccount, + AlgoAmount.MicroAlgos(Number(newSoftMax)), + 0n + ); + expect(poolKey.poolId).toEqual(2n); + + const state = await getValidatorState(validatorMasterClient, validatorId); + expect(state.totalAlgoStaked).toEqual(constraints.MaxAlgoPerPool + newSoftMax); + + // Fill again - this will put us at max and with current dev defaults at least - over saturation limit + // 3 pools of 70m (210m) vs saturation limit of 10% of 2b or 200m. + [poolKey] = await addStake( + fixture.context, + validatorMasterClient, + validatorId, + stakerAccount, + AlgoAmount.MicroAlgos(Number(newSoftMax)), + 0n + ); + expect(poolKey.poolId).toEqual(3n); + }); + + test('testPenalties', async () => { + const state = await getValidatorState(validatorMasterClient, validatorId); + const origPoolBalance = await getPoolAvailBalance(fixture.context, pools[2]); + + const tmpPoolClient = new StakingPoolClient( + { sender: validatorOwnerAccount, resolveBy: 'id', id: pools[2].poolAppId }, + fixture.context.algod + ); + const poolInfo = await getPoolInfo(validatorMasterClient, pools[2]); + const rewardAmount = AlgoAmount.Algos(200).microAlgos; + // ok, NOW it should be over the limit on next balance update - send a bit more algo - and it should be in + // saturated state now - so reward gets diminished, validator gets nothing, rest goes to fee sink + const rewardSender = await getTestAccount( + { initialFunds: AlgoAmount.MicroAlgos(rewardAmount + 4e6), suppressLog: true }, + fixture.context.algod, + fixture.context.kmd + ); + await transferAlgos( + { + from: rewardSender, + to: getApplicationAddress(pools[2].poolAppId), + amount: AlgoAmount.MicroAlgos(rewardAmount), + }, + fixture.context.algod + ); + const wNewRewardPoolBal = await getPoolAvailBalance(fixture.context, pools[2]); + // balance should be excess above totalAlgoStaked now... + expect(wNewRewardPoolBal).toEqual(poolInfo.totalAlgoStaked + BigInt(rewardAmount)); + + // but after next epochBalanceUpdate - it should have grown - but not by as much (depends on ratio of stake vs saturation limit) + const origFeeSinkBal = await fixture.context.algod.accountInformation(FEE_SINK_ADDR).do(); + await epochBalanceUpdate(tmpPoolClient); + + const postSaturatedPoolBal = await getPoolAvailBalance(fixture.context, pools[2]); + + const diminishedRewards = (BigInt(rewardAmount) * constraints.AmtConsideredSaturated) / state.totalAlgoStaked; + expect(postSaturatedPoolBal).toEqual(poolInfo.totalAlgoStaked + diminishedRewards); + // reward should've been reduced with rest going to fee sink + const newFeeSinkBal = await fixture.context.algod.accountInformation(FEE_SINK_ADDR).do(); + expect(newFeeSinkBal.amount).toBeGreaterThanOrEqual( + origFeeSinkBal.amount + (rewardAmount - Number(diminishedRewards)) + ); + + // stake should've increased by diminishedRewards + const newPoolInfo = await getPoolInfo(validatorMasterClient, pools[2]); + const newPoolBalance = await getPoolAvailBalance(fixture.context, pools[2]); + expect(newPoolBalance).toEqual(origPoolBalance + diminishedRewards); + expect(newPoolBalance).toEqual(newPoolInfo.totalAlgoStaked); + }); +}); + +// Uncomment skip when want to do full pool testing +describe.skip('ValidatorWFullPoolWRewards', () => { + beforeEach(fixture.beforeEach); + beforeEach(logs.beforeEach); + afterEach(logs.afterEach); + + let validatorId: number; + let validatorOwnerAccount: Account; + const stakerAccounts: Account[] = []; + let poolAppId: bigint; + let firstPoolKey: ValidatorPoolKey; + let firstPoolClient: StakingPoolClient; + + const PctToValidator = 5; + const NumStakers = MaxStakersPerPool; + + // add validator and 1 pool for subsequent stake tests + beforeAll(async () => { + await fixture.context.algod.setBlockOffsetTimestamp(0).do(); + + // Fund a 'validator account' that will be the validator owner. + validatorOwnerAccount = await getTestAccount( + { initialFunds: AlgoAmount.Algos(500), suppressLog: true }, + fixture.context.algod, + fixture.context.kmd + ); + consoleLogger.info(`validator account ${validatorOwnerAccount.addr}`); + + const config = createValidatorConfig({ + Owner: validatorOwnerAccount.addr, + Manager: validatorOwnerAccount.addr, + MinEntryStake: BigInt(AlgoAmount.Algos(1000).microAlgos), + MaxAlgoPerPool: BigInt(AlgoAmount.Algos(1000 * NumStakers).microAlgos), // this comes into play in later tests !! + PercentToValidator: PctToValidator * 10000, + ValidatorCommissionAddress: validatorOwnerAccount.addr, + }); + validatorId = await addValidator( + fixture.context, + validatorMasterClient, + validatorOwnerAccount, + config, + validatorMbr + ); + + // Add new pool - then we'll add stake and verify balances. + firstPoolKey = await addStakingPool( + fixture.context, + validatorMasterClient, + validatorId, + 1, + validatorOwnerAccount, + poolMbr, + poolInitMbr + ); + // should be [validator id, pool id (1 based)] + expect(firstPoolKey.id).toEqual(BigInt(validatorId)); + expect(firstPoolKey.poolId).toEqual(1n); + + firstPoolClient = new StakingPoolClient( + { sender: validatorOwnerAccount, resolveBy: 'id', id: firstPoolKey.poolAppId }, + fixture.context.algod + ); + + // get the app id via contract call - it should match what we just got back in poolKey[2] + poolAppId = ( + await validatorMasterClient.getPoolAppId( + { validatorId: firstPoolKey.id, poolId: firstPoolKey.poolId }, + { sendParams: { populateAppCallResources: true } } + ) + ).return!; + expect(firstPoolKey.poolAppId).toEqual(poolAppId); + + const stateData = await getValidatorState(validatorMasterClient, validatorId); + expect(stateData.numPools).toEqual(1); + expect(stateData.totalAlgoStaked).toEqual(0n); + expect(stateData.totalStakers).toEqual(0n); + + const poolInfo = await getPoolInfo(validatorMasterClient, firstPoolKey); + expect(poolInfo.poolAppId).toEqual(BigInt(poolAppId)); + expect(poolInfo.totalStakers).toEqual(0); + expect(poolInfo.totalAlgoStaked).toEqual(0n); + }); + + // Creates maxStakersPerPool stakers: + test( + 'addStakers', + async () => { + for (let i = 0; i < NumStakers + 1; i += 1) { + const stakerAccount = await getTestAccount( + { initialFunds: AlgoAmount.Algos(5000), suppressLog: true }, + fixture.context.algod, + fixture.context.kmd + ); + stakerAccounts.push(stakerAccount); + + // now stake 1000(+mbr), min for this pool - for the first time - which means actual stake amount will be reduced + // by 'first time staker' fee to cover MBR (which goes to VALIDATOR contract account, not staker contract account!) + // we pay the extra here so the final staked amount should be exactly 1000 + const stakeAmount1 = AlgoAmount.MicroAlgos( + AlgoAmount.Algos(1000).microAlgos + AlgoAmount.MicroAlgos(Number(stakerMbr)).microAlgos + ); + let stakedPoolKey: ValidatorPoolKey; + if (i < NumStakers) { + [stakedPoolKey] = await addStake( + fixture.context, + validatorMasterClient, + validatorId, + stakerAccount, + stakeAmount1, + 0n + ); + } else { + // staker # numStakers + 1 should fail because no pool is available (because we exceeded max algo) + await expect( + addStake(fixture.context, validatorMasterClient, validatorId, stakerAccount, stakeAmount1, 0n) + ).rejects.toThrowError(); + continue; + } + // should match info from first staking pool + expect(stakedPoolKey.id).toEqual(firstPoolKey.id); + expect(stakedPoolKey.poolId).toEqual(firstPoolKey.poolId); + expect(stakedPoolKey.poolAppId).toEqual(firstPoolKey.poolAppId); + + const poolInfo = await getPoolInfo(validatorMasterClient, firstPoolKey); + expect(poolInfo.totalStakers).toEqual(i + 1); + expect(poolInfo.totalAlgoStaked).toEqual( + BigInt(stakeAmount1.microAlgos - Number(stakerMbr)) * BigInt(i + 1) + ); + + expect((await getValidatorState(validatorMasterClient, validatorId)).totalStakers).toEqual( + BigInt(i + 1) + ); + } + }, + 4 * 60 * 1000 // 4 mins + ); + + test('testFirstRewards', async () => { + // increment time a day at a time per transaction + await fixture.context.algod.setBlockOffsetTimestamp(60 * 60 * 25).do(); + + const origValidatorState = await getValidatorState(validatorMasterClient, validatorId); + const ownerBalance = await fixture.context.algod.accountInformation(validatorOwnerAccount.addr).do(); + const stakersPriorToReward = await getStakeInfoFromBoxValue(firstPoolClient); + + const reward = AlgoAmount.Algos(2000); + // put some test 'reward' algos into staking pool + await transferAlgos( + { + from: fixture.context.testAccount, + to: getApplicationAddress(firstPoolKey.poolAppId), + amount: reward, + }, + fixture.context.algod + ); + + const poolInfo = await getPoolInfo(validatorMasterClient, firstPoolKey); + consoleLogger.info(`pool stakers:${poolInfo.totalStakers}, staked:${poolInfo.totalAlgoStaked}`); + + // Perform epoch payout calculation - we get back how much it cost to issue the txn + const fees = await epochBalanceUpdate(firstPoolClient); + const expectedValidatorReward = reward.microAlgos * (PctToValidator / 100); + + const newValidatorState = await getValidatorState(validatorMasterClient, validatorId); + const newOwnerBalance = await fixture.context.algod.accountInformation(validatorOwnerAccount.addr).do(); + // validator owner should have gotten the expected reward (minus the fees they just paid ofc) + expect(newOwnerBalance.amount).toEqual(ownerBalance.amount - fees.microAlgos + expectedValidatorReward); + + // Verify all the stakers in the pool got what we think they should have + const stakersAfterReward = await getStakeInfoFromBoxValue(firstPoolClient); + + // get time from most recent block to use as + await verifyRewardAmounts( + fixture.context, + BigInt(reward.microAlgos) - BigInt(expectedValidatorReward), + 0n, + stakersPriorToReward, + stakersAfterReward, + 1 + ); + + // the total staked should have grown as well - reward minus what the validator was paid in their commission + expect(Number(newValidatorState.totalAlgoStaked)).toEqual( + Number(origValidatorState.totalAlgoStaked) + (reward.microAlgos - expectedValidatorReward) + ); + + const poolBalance = await getPoolAvailBalance(fixture.context, firstPoolKey); + expect(poolBalance).toEqual(newValidatorState.totalAlgoStaked); + }); +}); diff --git a/contracts/__test__/helpers.ts b/contracts/__test__/helpers.ts new file mode 100644 index 00000000..b931d82c --- /dev/null +++ b/contracts/__test__/helpers.ts @@ -0,0 +1,1083 @@ +import { + Account, + Address, + Algodv2, + bytesToBigInt, + decodeAddress, + encodeAddress, + encodeUint64, + getApplicationAddress, + makeAssetCreateTxnWithSuggestedParamsFromObject, + makePaymentTxnWithSuggestedParamsFromObject, +} from 'algosdk'; +import { LogicError } from '@algorandfoundation/algokit-utils/types/logic-error'; +import { AlgoAmount } from '@algorandfoundation/algokit-utils/types/amount'; +import { AlgorandTestAutomationContext } from '@algorandfoundation/algokit-utils/types/testing'; +import { consoleLogger } from '@algorandfoundation/algokit-utils/types/logging'; +import { expect } from '@jest/globals'; +import { ValidatorRegistryClient } from '../contracts/clients/ValidatorRegistryClient'; +import { StakingPoolClient } from '../contracts/clients/StakingPoolClient'; + +export const ALGORAND_ZERO_ADDRESS_STRING = 'AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAY5HFKQ'; + +export const GATING_TYPE_NONE = 0; +export const GATING_TYPE_ASSETS_CREATED_BY = 1; +export const GATING_TYPE_ASSET_ID = 2; +export const GATING_TYPE_CREATED_BY_NFD_ADDRESSES = 3; +export const GATING_TYPE_SEGMENT_OF_NFD = 4; + +export class ValidatorConfig { + ID: bigint; // id of this validator (sequentially assigned) + + Owner: string; // account that controls config - presumably cold-wallet + + Manager: string; // account that triggers/pays for payouts and keyreg transactions - needs to be hotwallet as node has to sign for the transactions + + // Optional NFD AppID which the validator uses to describe their validator pool + // NFD must be currently OWNED by address that adds the validator + NFDForInfo: bigint; + + EntryGatingType: number; + + EntryGatingValue: Uint8Array; + + GatingAssetMinBalance: bigint; + + RewardTokenID: bigint; + + RewardPerPayout: bigint; + + PayoutEveryXMins: number; // // Payout frequency in minutes (can be no shorter than this) + + PercentToValidator: number; // Payout percentage expressed w/ four decimals - ie: 50000 = 5% -> .0005 - + + ValidatorCommissionAddress: string; // account that receives the validation commission each epoch payout + + MinEntryStake: bigint; // minimum stake required to enter pool + + MaxAlgoPerPool: bigint; // maximum stake allowed per pool (to keep under incentive limits) + + PoolsPerNode: number; // Number of pools to allow per node (max of 3 is recommended) + + SunsettingOn: bigint; // timestamp when validator will sunset (if != 0) + + SunsettingTo: bigint; // validator id that validator is 'moving' to (if known) + + // getValidatorConfig(uint64)(uint64,address,address,uint64,uint16,uint32,address,uint64,uint64,uint8) + // constructor to take array of values like ABI string above and set into the named instance vars + constructor([ + ID, + Owner, + Manager, + NFDForInfo, + EntryGatingType, + EntryGatingValue, + GatingAssetMinBalance, + RewardTokenID, + RewardPerPayout, + PayoutEveryXMins, + PercentToValidator, + ValidatorCommissionAddress, + MinEntryStake, + MaxAlgoPerPool, + PoolsPerNode, + SunsettingOn, + SunsettingTo, + ]: [ + bigint, + string, + string, + bigint, + number, + Uint8Array, + bigint, + bigint, + bigint, + number, + number, + string, + bigint, + bigint, + number, + bigint, + bigint, + ]) { + this.ID = ID; + this.Owner = Owner; + this.Manager = Manager; + this.NFDForInfo = NFDForInfo; + this.EntryGatingType = Number(EntryGatingType); + this.EntryGatingValue = EntryGatingValue; + this.GatingAssetMinBalance = GatingAssetMinBalance; + this.RewardTokenID = RewardTokenID; + this.RewardPerPayout = RewardPerPayout; + this.PayoutEveryXMins = Number(PayoutEveryXMins); + this.PercentToValidator = Number(PercentToValidator); + this.ValidatorCommissionAddress = ValidatorCommissionAddress; + this.MinEntryStake = MinEntryStake; + this.MaxAlgoPerPool = MaxAlgoPerPool; + this.PoolsPerNode = Number(PoolsPerNode); + this.SunsettingOn = SunsettingOn; + this.SunsettingTo = SunsettingTo; + } +} + +const DefaultValidatorConfig: ValidatorConfig = { + ID: BigInt(0), + Owner: 'AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAY5HFKQ', + Manager: 'AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAY5HFKQ', + NFDForInfo: BigInt(0), + EntryGatingType: GATING_TYPE_NONE, + EntryGatingValue: new Uint8Array(32), + GatingAssetMinBalance: BigInt(0), + RewardTokenID: BigInt(0), + RewardPerPayout: BigInt(0), + PayoutEveryXMins: 60 * 24, // daily payout + PercentToValidator: 10000, // 1.0000% + ValidatorCommissionAddress: 'AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAY5HFKQ', + MinEntryStake: BigInt(AlgoAmount.Algos(1000).microAlgos), + MaxAlgoPerPool: 0n, // float w/ online caps + PoolsPerNode: 3, + SunsettingOn: BigInt(0), + SunsettingTo: BigInt(0), +}; + +export function createValidatorConfig(inputConfig: Partial): ValidatorConfig { + const configObj = { + ...DefaultValidatorConfig, + ...inputConfig, + }; + + return new ValidatorConfig([ + configObj.ID, + configObj.Owner, + configObj.Manager, + configObj.NFDForInfo, + configObj.EntryGatingType, + configObj.EntryGatingValue, + configObj.GatingAssetMinBalance, + configObj.RewardTokenID, + configObj.RewardPerPayout, + configObj.PayoutEveryXMins, + configObj.PercentToValidator, + configObj.ValidatorCommissionAddress, + configObj.MinEntryStake, + configObj.MaxAlgoPerPool, + configObj.PoolsPerNode, + configObj.SunsettingOn, + configObj.SunsettingTo, + ]); +} + +function validatorConfigAsArray( + config: ValidatorConfig +): [ + bigint, + string, + string, + bigint, + number, + Uint8Array, + bigint, + bigint, + bigint, + number, + number, + string, + bigint, + bigint, + number, + bigint, + bigint, +] { + return [ + config.ID, + config.Owner, + config.Manager, + config.NFDForInfo, + config.EntryGatingType, + config.EntryGatingValue, + config.GatingAssetMinBalance, + config.RewardTokenID, + config.RewardPerPayout, + config.PayoutEveryXMins, + config.PercentToValidator, + config.ValidatorCommissionAddress, + config.MinEntryStake, + config.MaxAlgoPerPool, + config.PoolsPerNode, + config.SunsettingOn, + config.SunsettingTo, + ]; +} + +class ValidatorCurState { + numPools: number; // current number of pools this validator has - capped at MaxPools + + totalStakers: bigint; // total number of stakers across all pools + + totalAlgoStaked: bigint; // total amount staked to this validator across ALL of its pools + + rewardTokenHeldBack: bigint; // amount of token held back for future payout to stakers + + constructor([numPools, totalStakers, totalAlgoStaked, rewardTokenHeldBack]: [number, bigint, bigint, bigint]) { + this.numPools = Number(numPools); + this.totalStakers = totalStakers; + this.totalAlgoStaked = totalAlgoStaked; + this.rewardTokenHeldBack = rewardTokenHeldBack; + } +} + +export class PoolInfo { + poolAppId: bigint; // The App id of this staking pool contract instance + + totalStakers: number; + + totalAlgoStaked: bigint; + + constructor([poolAppId, totalStakers, totalAlgoStaked]: [bigint, number, bigint]) { + this.poolAppId = poolAppId; + this.totalStakers = Number(totalStakers); + this.totalAlgoStaked = totalAlgoStaked; + } +} + +export class ValidatorPoolKey { + id: bigint; + + poolId: bigint; // 0 means INVALID ! - so 1 is index, technically of [0] + + poolAppId: bigint; + + constructor([id, poolId, poolAppId]: [bigint, bigint, bigint]) { + this.id = id; + this.poolId = poolId; + this.poolAppId = poolAppId; + } + + encode(): [bigint, bigint, bigint] { + return [this.id, this.poolId, this.poolAppId]; + } +} + +// StakedInfo is the testing-friendly version of what's stored as a static array in each staking pool +export class StakedInfo { + staker: Address; + + balance: bigint; + + totalRewarded: bigint; + + rewardTokenBalance: bigint; + + entryTime: bigint; + + constructor(data: Uint8Array) { + this.staker = decodeAddress(encodeAddress(data.slice(0, 32))); + this.balance = bytesToBigInt(data.slice(32, 40)); + this.totalRewarded = bytesToBigInt(data.slice(40, 48)); + this.rewardTokenBalance = bytesToBigInt(data.slice(48, 56)); + this.entryTime = bytesToBigInt(data.slice(56, 64)); + } + + public static fromValues([Staker, Balance, TotalRewarded, RewardTokenBalance, EntryTime]: [ + string, + bigint, + bigint, + bigint, + bigint, + ]): StakedInfo { + return { staker: decodeAddress(Staker), balance: Balance, totalRewarded: TotalRewarded, rewardTokenBalance: RewardTokenBalance, entryTime: EntryTime }; + } + + public static FromBoxData(boxData: Uint8Array): StakedInfo[] { + // take 64-byte chunks of boxData and return as an array of StakedInfo values (initialized via its constructor + // which takes 64-byte chunks and returns an initialized StakedInfo + const chunkSize = 64; + const stakedInfoArray: StakedInfo[] = []; + for (let i = 0; i < boxData.length; i += chunkSize) { + const chunk = boxData.slice(i, i + chunkSize); + stakedInfoArray.push(new StakedInfo(chunk)); + } + return stakedInfoArray; + } +} + +// ProtocolConstraints returns data from the contracts on minimums, maximums, etc. +export class ProtocolConstraints { + EpochPayoutMinsMin: bigint; + + EpochPayoutMinsMax: bigint; + + MinPctToValidatorWFourDecimals: bigint; + + MaxPctToValidatorWFourDecimals: bigint; + + MinEntryStake: bigint; // in microAlgo + + MaxAlgoPerPool: bigint; // in microAlgo + + MaxAlgoPerValidator: bigint; // in microAlgo + + AmtConsideredSaturated: bigint; + + MaxNodes: bigint; + + MaxPoolsPerNode: bigint; + + MaxStakersPerPool: bigint; + + constructor([ + EpochPayoutMinsMin, + EpochPayoutMinsMax, + MinPctToValidatorWFourDecimals, + MaxPctToValidatorWFourDecimals, + MinEntryStake, + MaxAlgoPerPool, + MaxAlgoPerValidator, + AmtConsideredSaturated, + MaxNodes, + MaxPoolsPerNode, + MaxStakersPerPool, + ]: [bigint, bigint, bigint, bigint, bigint, bigint, bigint, bigint, bigint, bigint, bigint]) { + this.EpochPayoutMinsMin = EpochPayoutMinsMin; + this.EpochPayoutMinsMax = EpochPayoutMinsMax; + this.MinPctToValidatorWFourDecimals = MinPctToValidatorWFourDecimals; + this.MaxPctToValidatorWFourDecimals = MaxPctToValidatorWFourDecimals; + this.MinEntryStake = MinEntryStake; + this.MaxAlgoPerPool = MaxAlgoPerPool; + this.MaxAlgoPerValidator = MaxAlgoPerValidator; + this.AmtConsideredSaturated = AmtConsideredSaturated; + this.MaxNodes = MaxNodes; + this.MaxPoolsPerNode = MaxPoolsPerNode; + this.MaxStakersPerPool = MaxStakersPerPool; + } + + public static fromValues([ + EpochPayoutMinsMin, + EpochPayoutMinsMax, + MinPctToValidatorWFourDecimals, + MaxPctToValidatorWFourDecimals, + MinEntryStake, + MaxAlgoPerPool, + MaxAlgoPerValidator, + AmtConsideredSaturated, + MaxNodes, + MaxPoolsPerNode, + MaxStakersPerPool, + ]: [bigint, bigint, bigint, bigint, bigint, bigint, bigint, bigint, bigint, bigint, bigint]): ProtocolConstraints { + return { + EpochPayoutMinsMin, + EpochPayoutMinsMax, + MinPctToValidatorWFourDecimals, + MaxPctToValidatorWFourDecimals, + MinEntryStake, + MaxAlgoPerPool, + MaxAlgoPerValidator, + AmtConsideredSaturated, + MaxNodes, + MaxPoolsPerNode, + MaxStakersPerPool, + }; + } +} + +class PoolTokenPayoutRatio { + PoolPctOfWhole: bigint[]; + + UpdatedForPayout: bigint; + + constructor([PoolPctOfWhole, UpdatedForPayout]: [bigint[], bigint]) { + this.PoolPctOfWhole = PoolPctOfWhole; + this.UpdatedForPayout = UpdatedForPayout; + } +} + +function concatUint8Arrays(a: Uint8Array, b: Uint8Array): Uint8Array { + const result = new Uint8Array(a.length + b.length); + result.set(a); + result.set(b, a.length); + return result; +} + +export function gatingValueFromBigint(val: bigint): Uint8Array { + // construct and return 32-byte long Uint8Array instance but set first 8 bytes to the 64-bit big-endian value + // contained in 'val'... so we just concat 24 empty bytes to result of encodeUint64 + return concatUint8Arrays(encodeUint64(val), new Uint8Array(24)); +} + +export async function getStakeInfoFromBoxValue(stakeClient: StakingPoolClient) { + const stakerData = await stakeClient.appClient.getBoxValue('stakers'); + return StakedInfo.FromBoxData(stakerData); +} + +export function getValidatorListBoxName(validatorId: number) { + const prefix = new TextEncoder().encode('v'); + return concatUint8Arrays(prefix, encodeUint64(validatorId)); +} + +function getStakerPoolSetBoxName(stakerAccount: Account) { + const prefix = new TextEncoder().encode('sps'); + return concatUint8Arrays(prefix, decodeAddress(stakerAccount.addr).publicKey); +} + +function getStakersBoxName() { + return new TextEncoder().encode('stakers'); +} + +export async function getMbrAmountsFromValidatorClient(validatorClient: ValidatorRegistryClient) { + return (await validatorClient.compose().getMbrAmounts({}, {}).simulate()).returns![0]; +} + +export async function getProtocolConstraints(validatorClient: ValidatorRegistryClient) { + return new ProtocolConstraints( + (await validatorClient.compose().getProtocolConstraints({}, {}).simulate()).returns![0] + ); +} + +function dumpLogs(logs: Uint8Array[]) { + consoleLogger.info(logs.map((uint8array) => new TextDecoder().decode(uint8array)).join('\n')); + // logs.forEach((uint8array) => { + // let strVal = new TextDecoder().decode(uint8array); + // + // // Get the indices where '%i' exists + // const foundIndices = [...strVal.matchAll(/%i/g)].map((e) => e.index); + // + // // Start index so we know where to start reading for the 64-bit big endian number + // const endIndex = strVal.lastIndexOf('%i') + 2; // includes the two characters in '%i' + // + // // Change Uint8Array to ArrayBuffer + // const arrayBuffer = ArrayBuffer.from(uint8array.buffer); + // const dataView = new DataView(arrayBuffer, endIndex); + // + // // Replace each '%i' with their corresponding integers + // foundIndices.reverse().forEach((index, iteration) => { + // // 64-bit big endian integer + // const integer64Bit = dataView.getBigInt64(iteration * 8); + // + // // Replace the '%i' with the integer + // strVal = strVal.substring(0, index) + integer64Bit + strVal.substring(index! + 2); + // }); + // + // consoleLogger.info(strVal); + // }); +} + +export async function addValidator( + context: AlgorandTestAutomationContext, + validatorClient: ValidatorRegistryClient, + owner: Account, + config: ValidatorConfig, + validatorMbr: bigint +) { + const suggestedParams = await context.algod.getTransactionParams().do(); + const validatorsAppRef = await validatorClient.appClient.getAppReference(); + + // Pay the additional mbr to the validator contract for the new validator mbr + const payValidatorMbr = makePaymentTxnWithSuggestedParamsFromObject({ + from: context.testAccount.addr, + to: validatorsAppRef.appAddress, + amount: Number(validatorMbr), + suggestedParams, + }); + + try { + const results = await validatorClient + .compose() + .addValidator( + { + // the required MBR payment transaction.. + mbrPayment: { transaction: payValidatorMbr, signer: context.testAccount }, + // -- + nfdName: '', + config: validatorConfigAsArray(config), + }, + { + sender: owner, + } + ) + .execute({ populateAppCallResources: true }); + return Number(results.returns![0]); + } catch (e) { + // throw validatorClient.appClient.exposeLogicError(e as Error) + consoleLogger.warn((e as LogicError).message); + throw e; + } +} + +export async function getValidatorState(validatorClient: ValidatorRegistryClient, validatorId: number) { + return new ValidatorCurState( + ( + await validatorClient + .compose() + .getValidatorState({ validatorId }, {}) + .simulate({ allowUnnamedResources: true }) + ).returns![0] + ); +} + +export async function addStakingPool( + context: AlgorandTestAutomationContext, + validatorClient: ValidatorRegistryClient, + validatorId: number, + nodeNum: number, + vldtrAcct: Account, + poolMbr: bigint, + poolInitMbr: bigint +) { + const suggestedParams = await context.algod.getTransactionParams().do(); + const validatorsAppRef = await validatorClient.appClient.getAppReference(); + + // Pay the additional mbr to the validator contract for the new pool mbr + const payPoolMbr = makePaymentTxnWithSuggestedParamsFromObject({ + from: context.testAccount.addr, + to: validatorsAppRef.appAddress, + amount: Number(poolMbr), + suggestedParams, + }); + + let addPoolResults: any; + // Before validator can add pools it needs to be funded + try { + // Now add a staking pool + addPoolResults = await validatorClient + .compose() + .gas({}, { note: '1' }) + .gas({}, { note: '2' }) + .addPool( + { + mbrPayment: { transaction: payPoolMbr, signer: context.testAccount }, + validatorId, + nodeNum, + }, + { + sendParams: { + fee: AlgoAmount.MicroAlgos(2000), + }, + sender: vldtrAcct, + } + ) + .execute({ populateAppCallResources: true }); + } catch (exception) { + console.log((exception as LogicError).message); + throw exception; + } + const poolKey = new ValidatorPoolKey(addPoolResults.returns![2]); + + // Pay the mbr to the newly created staking pool contract to cover its upcoming box mbr storage req + const payStakingPoolMbr = makePaymentTxnWithSuggestedParamsFromObject({ + from: context.testAccount.addr, + to: getApplicationAddress(poolKey.poolAppId), + amount: Number(poolInitMbr), + suggestedParams, + }); + + // now tell it to initialize its storage (w/ our mbr payment) + const newPoolClient = new StakingPoolClient( + { sender: vldtrAcct, resolveBy: 'id', id: poolKey.poolAppId }, + context.algod + ); + + await newPoolClient + .compose() + .gas({}, { note: '1' }) + .gas({}, { note: '2' }) + .initStorage( + { + // the required MBR payment transaction + mbrPayment: { transaction: payStakingPoolMbr, signer: context.testAccount }, + }, + { + sendParams: { + fee: AlgoAmount.MicroAlgos(3000), + }, + } + ) + .execute({ populateAppCallResources: true }); + + return poolKey; +} + +export async function getPoolInfo(validatorClient: ValidatorRegistryClient, poolKey: ValidatorPoolKey) { + try { + const PoolRet = await validatorClient + .compose() + .getPoolInfo({ poolKey: poolKey.encode() }, {}) + .simulate({ allowUnnamedResources: true }); + return new PoolInfo(PoolRet.returns![0]); + } catch (exception) { + console.log((exception as LogicError).message); + throw validatorClient.appClient.exposeLogicError(exception as Error); + // throw exception; + } +} + +export async function getCurMaxStatePerPool(validatorClient: ValidatorRegistryClient, validatorId: number) { + try { + return ( + await validatorClient + .compose() + .getCurMaxStakePerPool({ validatorId }) + .simulate({ allowUnnamedResources: true }) + ).returns![0]; + } catch (exception) { + console.log((exception as LogicError).message); + throw validatorClient.appClient.exposeLogicError(exception as Error); + } +} + +export async function getStakedPoolsForAccount( + validatorClient: ValidatorRegistryClient, + stakerAccount: Account +): Promise { + const results = await validatorClient.getStakedPoolsForAccount( + { staker: stakerAccount.addr }, + { sendParams: { populateAppCallResources: true } } + ); + const retPoolKeys: ValidatorPoolKey[] = []; + results.return!.forEach((poolKey) => { + retPoolKeys.push(new ValidatorPoolKey(poolKey)); + }); + return retPoolKeys; +} + +export async function getStakerInfo(stakeClient: StakingPoolClient, staker: Account) { + try { + return StakedInfo.fromValues( + ( + await stakeClient + .compose() + .getStakerInfo({ staker: staker.addr }, {}) + .simulate({ allowUnnamedResources: true }) + ).returns![0] + ); + } catch (exception) { + console.log((exception as LogicError).message); + throw stakeClient.appClient.exposeLogicError(exception as Error); + // throw exception; + } +} + +export async function getTokenPayoutRatio(validatorClient: ValidatorRegistryClient, validatorId: number) { + return new PoolTokenPayoutRatio( + ( + await validatorClient + .compose() + .getTokenPayoutRatio({ validatorId }, {}) + .simulate({ allowUnnamedResources: true }) + ).returns![0] + ); +} + +export async function addStake( + context: AlgorandTestAutomationContext, + validatorClient: ValidatorRegistryClient, + vldtrId: number, + staker: Account, + algoAmount: AlgoAmount, + valueToVerify: bigint // depends on gating but could be nfd id, or asset id +): Promise<[ValidatorPoolKey, AlgoAmount]> { + try { + const suggestedParams = await context.algod.getTransactionParams().do(); + const validatorsAppRef = await validatorClient.appClient.getAppReference(); + + suggestedParams.flatFee = true; + suggestedParams.fee = 0; + + const findPoolSim = await validatorClient + .compose() + .gas({}) + .findPoolForStaker( + { validatorId: vldtrId, staker: staker.addr, amountToStake: algoAmount.microAlgos }, + { + sendParams: { + fee: AlgoAmount.MicroAlgos(2000), + }, + } + ) + .simulate({ allowUnnamedResources: true }); + if (findPoolSim.simulateResponse.txnGroups[0].failureMessage !== undefined) { + consoleLogger.error( + `simulate failed in findPoolForStaker: ${findPoolSim.simulateResponse.txnGroups[0].failureMessage}` + ); + } + const expectedPool = findPoolSim.returns![1]; + + const poolKey = new ValidatorPoolKey(expectedPool[0]); + const willBeNewStaker = expectedPool[1]; + + consoleLogger.info( + `addStake findPool will add to validator:${poolKey.id}, pool:${poolKey.poolId} and willBeNew:${willBeNewStaker}` + ); + + // Pay the stake to the validator contract + const stakeTransfer = makePaymentTxnWithSuggestedParamsFromObject({ + from: staker.addr, + to: validatorsAppRef.appAddress, + amount: algoAmount.microAlgos, + suggestedParams, + }); + + // simulate to get fees + let fees = AlgoAmount.MicroAlgos(240_000); + const simulateResults = await validatorClient + .compose() + .gas({}) + .addStake( + // This the actual send of stake to the ac + { + stakedAmountPayment: { transaction: stakeTransfer, signer: staker }, + validatorId: vldtrId, + valueToVerify, + }, + { sendParams: { fee: fees }, sender: staker } + ) + .simulate({ allowUnnamedResources: true, allowMoreLogging: true }); + + const { logs } = simulateResults.simulateResponse.txnGroups[0].txnResults[2].txnResult; + // verify logs isn't undefined + if (logs !== undefined) { + dumpLogs(logs); + } + stakeTransfer.group = undefined; + fees = AlgoAmount.MicroAlgos( + 2000 + + 1000 * + Math.floor(((simulateResults.simulateResponse.txnGroups[0].appBudgetAdded as number) + 699) / 700) + ); + consoleLogger.info(`addStake fees:${fees.toString()}`); + + const results = await validatorClient + .compose() + .gas({}, { sendParams: { fee: AlgoAmount.MicroAlgos(0) } }) + .addStake( + { + // -- + // This the actual send of stake to the validator contract (which then sends to the staking pool) + stakedAmountPayment: { transaction: stakeTransfer, signer: staker }, + // -- + validatorId: vldtrId, + valueToVerify, + }, + { sendParams: { fee: fees }, sender: staker } + ) + .execute({ populateAppCallResources: true }); + + return [new ValidatorPoolKey(results.returns[1]), fees]; + } catch (exception) { + consoleLogger.warn((exception as LogicError).message); + // throw validatorClient.appClient.exposeLogicError(exception as Error); + throw exception; + } +} + +export async function removeStake(stakeClient: StakingPoolClient, staker: Account, unstakeAmount: AlgoAmount) { + const simulateResults = await stakeClient + .compose() + .gas({}, { note: '1', sendParams: { fee: AlgoAmount.MicroAlgos(0) } }) + .gas({}, { note: '2', sendParams: { fee: AlgoAmount.MicroAlgos(0) } }) + .removeStake( + { amountToUnstake: unstakeAmount.microAlgos }, + { + sendParams: { + fee: AlgoAmount.MicroAlgos(240000), + }, + sender: staker, + } + ) + .simulate({ allowUnnamedResources: true }); + + const itxnfees = AlgoAmount.MicroAlgos( + 1000 * Math.floor(((simulateResults.simulateResponse.txnGroups[0].appBudgetAdded as number) + 699) / 700) + ); + consoleLogger.info(`removeStake fees:${itxnfees.toString()}`); + + try { + await stakeClient + .compose() + .gas({}, { note: '1', sendParams: { fee: AlgoAmount.MicroAlgos(0) } }) + .gas({}, { note: '2', sendParams: { fee: AlgoAmount.MicroAlgos(0) } }) + .removeStake( + { amountToUnstake: unstakeAmount.microAlgos }, + { + sendParams: { + // pays us back and tells validator about balance changed + fee: AlgoAmount.MicroAlgos(itxnfees.microAlgos), + }, + sender: staker, + } + ) + .execute({ populateAppCallResources: true }); + } catch (exception) { + consoleLogger.warn((exception as LogicError).message); + // throw stakeClient.appClient.exposeLogicError(exception as Error); + throw exception; + } + return itxnfees.microAlgos; +} + +export async function claimTokens(stakeClient: StakingPoolClient, staker: Account) { + const simulateResults = await stakeClient + .compose() + .gas({}, { note: '1', sendParams: { fee: AlgoAmount.MicroAlgos(0) } }) + .gas({}, { note: '2', sendParams: { fee: AlgoAmount.MicroAlgos(0) } }) + .claimTokens( + {}, + { + sendParams: { + fee: AlgoAmount.MicroAlgos(240000), + }, + sender: staker, + } + ) + .simulate({ allowUnnamedResources: true }); + + const itxnfees = AlgoAmount.MicroAlgos( + 1000 * Math.floor(((simulateResults.simulateResponse.txnGroups[0].appBudgetAdded as number) + 699) / 700) + ); + consoleLogger.info(`removeStake fees:${itxnfees.toString()}`); + + try { + await stakeClient + .compose() + .gas({}, { note: '1', sendParams: { fee: AlgoAmount.MicroAlgos(0) } }) + .gas({}, { note: '2', sendParams: { fee: AlgoAmount.MicroAlgos(0) } }) + .claimTokens( + {}, + { + sendParams: { + // pays us back and tells validator about balance changed + fee: AlgoAmount.MicroAlgos(itxnfees.microAlgos), + }, + sender: staker, + } + ) + .execute({ populateAppCallResources: true }); + } catch (exception) { + consoleLogger.warn((exception as LogicError).message); + // throw stakeClient.appClient.exposeLogicError(exception as Error); + throw exception; + } + return itxnfees.microAlgos; +} + +export async function epochBalanceUpdate(stakeClient: StakingPoolClient) { + let fees = AlgoAmount.MicroAlgos(240_000); + const simulateResults = await stakeClient + .compose() + .gas({}, { note: '1' }) + .gas({}, { note: '2' }) + .epochBalanceUpdate({}, { sendParams: { fee: fees } }) + .simulate({ allowUnnamedResources: true, allowMoreLogging: true }); + + const { logs } = await simulateResults.simulateResponse.txnGroups[0].txnResults[2].txnResult; + // verify logs isn't undefined + if (logs !== undefined) { + dumpLogs(logs); + } + fees = AlgoAmount.MicroAlgos( + 1000 * Math.floor(((simulateResults.simulateResponse.txnGroups[0].appBudgetAdded as number) + 699) / 700) + ); + consoleLogger.info(`epoch update fees of:${fees.toString()}`); + + await stakeClient + .compose() + .gas({}, { note: '1', sendParams: { fee: AlgoAmount.MicroAlgos(0) } }) + .gas({}, { note: '2', sendParams: { fee: AlgoAmount.MicroAlgos(0) } }) + .epochBalanceUpdate({}, { sendParams: { fee: fees } }) + .execute({ populateAppCallResources: true }); + return fees; +} + +export async function logStakingPoolInfo( + context: AlgorandTestAutomationContext, + PoolAppID: bigint, + msgToDisplay: string +) { + const firstPoolClient = new StakingPoolClient( + { sender: context.testAccount, resolveBy: 'id', id: PoolAppID }, + context.algod + ); + const stakingPoolGS = await firstPoolClient.appClient.getGlobalState(); + let lastPayoutTime: Date = new Date(); + if (stakingPoolGS.lastPayout !== undefined) { + lastPayoutTime = new Date(Number(stakingPoolGS.lastPayout.value as bigint) * 1000); + } + + const stakers = await getStakeInfoFromBoxValue(firstPoolClient); + // iterate stakers displaying the info + consoleLogger.info(`${msgToDisplay}, last Payout: ${lastPayoutTime.toUTCString()}`); + for (let i = 0; i < stakers.length; i += 1) { + if (encodeAddress(stakers[i].staker.publicKey) !== ALGORAND_ZERO_ADDRESS_STRING) { + const entryTime = new Date(Number(stakers[i].entryTime) * 1000); + consoleLogger.info( + `${i}: Staker:${encodeAddress(stakers[i].staker.publicKey)}, Balance:${stakers[i].balance}, Rwd Tokens:${stakers[i].rewardTokenBalance} Entry:${entryTime.toUTCString()}` + ); + } + } +} + +export async function verifyRewardAmounts( + context: AlgorandTestAutomationContext, + algoRewardedAmount: bigint, + tokenRewardedAmount: bigint, + stakersPriorToReward: StakedInfo[], + stakersAfterReward: StakedInfo[], + payoutEveryXMins: number +): Promise { + const payoutDaysInSecs = payoutEveryXMins * 24 * 60 * 60; + // iterate stakersPriorToReward and total the 'balance' value to get a 'total amount' + // then determine if the stakersAfterReward version's balance incremented in accordance w/ their percentage of + // the 'total' - where they get that percentage of the rewardedAmount. + const totalAmount = stakersPriorToReward.reduce((total, staker) => BigInt(total) + staker.balance, BigInt(0)); + + // Figure out the timestamp of prior block and use that as the 'current time' for purposes + // of matching the epoch payout calculations in the contract + const curStatus = await context.algod.status().do(); + const lastBlock = await context.algod.block(curStatus['last-round'] - 1).do(); + const payoutTimeToUse = new Date(lastBlock.block.ts * 1000); + + consoleLogger.info( + `verifyRewardAmounts checking ${stakersPriorToReward.length} stakers. reward:${algoRewardedAmount}, totalAmount:${totalAmount}, payout time to use:${payoutTimeToUse.toString()}` + ); + // Iterate all stakers - determine which haven't been for entire epoch - pay them proportionally less for having + // less time in pool. We keep track of their stake and then will later reduce the effective 'total staked' amount + // by that so that the remaining stakers get the remaining reward + excess based on their % of stake against + // remaining participants. + let partialStakeAmount: bigint = BigInt(0); + let algoRewardsAvail: bigint = algoRewardedAmount; + let tokenRewardsAvail: bigint = tokenRewardedAmount; + + for (let i = 0; i < stakersPriorToReward.length; i += 1) { + if (encodeAddress(stakersPriorToReward[i].staker.publicKey) === ALGORAND_ZERO_ADDRESS_STRING) { + continue; + } + const stakerEntryTime = new Date(Number(stakersPriorToReward[i].entryTime) * 1000); + if (stakerEntryTime.getTime() >= payoutTimeToUse.getTime()) { + continue; + } + const origBalance = stakersPriorToReward[i].balance; + const origRwdTokenBal = stakersPriorToReward[i].rewardTokenBalance; + const timeInPoolSecs: bigint = + (BigInt(payoutTimeToUse.getTime()) - BigInt(stakerEntryTime.getTime())) / BigInt(1000); + const timePercentage: bigint = (BigInt(timeInPoolSecs) * BigInt(1000)) / BigInt(payoutDaysInSecs); // 34.7% becomes 347 + if (timePercentage < BigInt(1000)) { + // partial staker + const expectedReward = + (BigInt(origBalance) * algoRewardedAmount * BigInt(timePercentage)) / (totalAmount * BigInt(1000)); + consoleLogger.info( + `staker:${i}, TimePct:${timePercentage}, PctTotal:${Number((origBalance * BigInt(1000)) / totalAmount) / 10} ExpReward:${expectedReward}, ActReward:${stakersAfterReward[i].balance - origBalance} ${encodeAddress(stakersPriorToReward[i].staker.publicKey)}` + ); + + if (origBalance + expectedReward !== stakersAfterReward[i].balance) { + consoleLogger.warn( + `staker:${i} expected: ${origBalance + expectedReward} reward but got: ${stakersAfterReward[i].balance}` + ); + expect(stakersAfterReward[i].balance).toBe(origBalance + expectedReward); + } + const expectedTokenReward = + (BigInt(origBalance) * tokenRewardedAmount * BigInt(timePercentage)) / (totalAmount * BigInt(1000)); + consoleLogger.info( + `staker:${i}, ExpTokenReward:${expectedTokenReward}, ActTokenReward:${stakersAfterReward[i].rewardTokenBalance - origRwdTokenBal}` + ); + + if (origRwdTokenBal + expectedTokenReward !== stakersAfterReward[i].rewardTokenBalance) { + consoleLogger.warn( + `staker:${i} expected: ${origRwdTokenBal + expectedTokenReward} reward but got: ${stakersAfterReward[i].rewardTokenBalance}` + ); + expect(stakersAfterReward[i].rewardTokenBalance).toBe(origRwdTokenBal + expectedTokenReward); + } + + partialStakeAmount += origBalance; + + algoRewardsAvail -= expectedReward; + tokenRewardsAvail -= expectedTokenReward; + } + } + const newPoolTotalStake = totalAmount - partialStakeAmount; + + // now go through again and only worry about full 100% time-in-epoch stakers + for (let i = 0; i < stakersPriorToReward.length; i += 1) { + if (encodeAddress(stakersPriorToReward[i].staker.publicKey) === ALGORAND_ZERO_ADDRESS_STRING) { + continue; + } + const stakerEntryTime = new Date(Number(stakersPriorToReward[i].entryTime) * 1000); + if (stakerEntryTime.getTime() >= payoutTimeToUse.getTime()) { + consoleLogger.info( + `staker:${i}, ${encodeAddress(stakersPriorToReward[i].staker.publicKey)} SKIPPED because entry is newer at:${stakerEntryTime.toString()}` + ); + } else { + const origBalance = stakersPriorToReward[i].balance; + const origRwdTokenBal = stakersPriorToReward[i].rewardTokenBalance; + const timeInPoolSecs: bigint = + (BigInt(payoutTimeToUse.getTime()) - BigInt(stakerEntryTime.getTime())) / BigInt(1000); + let timePercentage: bigint = (BigInt(timeInPoolSecs) * BigInt(1000)) / BigInt(payoutDaysInSecs); // 34.7% becomes 347 + if (timePercentage < BigInt(1000)) { + continue; + } + if (timePercentage > BigInt(1000)) { + timePercentage = BigInt(1000); + } + const expectedReward = (BigInt(origBalance) * algoRewardsAvail) / newPoolTotalStake; + consoleLogger.info( + `staker:${i}, TimePct:${timePercentage}, PctTotal:${Number((origBalance * BigInt(1000)) / newPoolTotalStake) / 10} ExpReward:${expectedReward}, ActReward:${stakersAfterReward[i].balance - origBalance} ${encodeAddress(stakersPriorToReward[i].staker.publicKey)}` + ); + const expectedTokenReward = (BigInt(origBalance) * tokenRewardsAvail) / newPoolTotalStake; + consoleLogger.info( + `staker:${i}, ExpTokenReward:${expectedTokenReward}, ActTokenReward:${stakersAfterReward[i].rewardTokenBalance - origRwdTokenBal}` + ); + + if (origRwdTokenBal + expectedTokenReward !== stakersAfterReward[i].rewardTokenBalance) { + consoleLogger.warn( + `staker:${i} expected: ${origRwdTokenBal + expectedTokenReward} reward but got: ${stakersAfterReward[i].rewardTokenBalance}` + ); + expect(stakersAfterReward[i].rewardTokenBalance).toBe(origRwdTokenBal + expectedTokenReward); + } + } + } +} + +export async function getPoolAvailBalance(context: AlgorandTestAutomationContext, poolKey: ValidatorPoolKey) { + const poolAcctInfo = await context.algod.accountInformation(getApplicationAddress(poolKey.poolAppId)).do(); + return BigInt(poolAcctInfo.amount - poolAcctInfo['min-balance']); +} + +export async function createAsset( + client: Algodv2, + sender: Account, + assetName: string, + unitName: string, + total?: number, + decimals?: number +) { + const newTotal = !total ? Math.floor(Math.random() * 100) + 20 : total; + const newDecimals = !decimals ? 6 : decimals; + + const params = await client.getTransactionParams().do(); + + const txn = makeAssetCreateTxnWithSuggestedParamsFromObject({ + from: sender.addr, + suggestedParams: params, + total: newTotal * 10 ** newDecimals, + decimals: newDecimals, + defaultFrozen: false, + unitName, + assetName, + manager: sender.addr, + reserve: sender.addr, + freeze: sender.addr, + clawback: sender.addr, + assetURL: 'https://path/to/my/asset/details', + }); + + const stxn = txn.signTxn(sender.sk); + + let txid = await client.sendRawTransaction(stxn).do(); + txid = txid.txId; + + const ptx = await client.pendingTransactionInformation(txid).do(); + + const assetId = ptx['asset-index']; + + return assetId; +} diff --git a/contracts/bootstrap/.eslintrc.js b/contracts/bootstrap/.eslintrc.js new file mode 100644 index 00000000..638f2f05 --- /dev/null +++ b/contracts/bootstrap/.eslintrc.js @@ -0,0 +1,70 @@ +module.exports = { + env: { + browser: true, + es2021: true, + }, + extends: [ + 'airbnb-base', + 'plugin:import/errors', + 'plugin:import/warnings', + 'plugin:import/typescript', + 'plugin:prettier/recommended', + ], + parser: '@typescript-eslint/parser', + parserOptions: { + ecmaVersion: 'latest', + sourceType: 'module', + }, + plugins: ['@typescript-eslint'], + rules: { + '@typescript-eslint/no-explicit-any': 'error', + '@typescript-eslint/ban-ts-comment': 'warn', + 'import/prefer-default-export': 'off', + 'import/extensions': [ + 'error', + 'ignorePackages', + { + js: 'never', + jsx: 'never', + ts: 'never', + tsx: 'never', + }, + ], + 'import/no-extraneous-dependencies': [ + 'error', + { + devDependencies: ['**/*.test.ts'], + }, + ], + 'prettier/prettier': [ + 'error', + { + tabWidth: 4, + }, + ], + }, + overrides: [ + { + files: ['*.algo.ts'], + rules: { + 'import/no-extraneous-dependencies': 'off', + 'object-shorthand': 'off', + 'class-methods-use-this': 'off', + 'no-undef': 'off', + 'max-classes-per-file': 'off', + 'no-bitwise': 'off', + 'operator-assignment': 'off', + 'prefer-template': 'off', + 'prefer-destructuring': 'off', + 'no-param-reassign': 'off', + 'no-restricted-syntax': 'off', + }, + }, + { + files: ['*.test.ts'], + rules: { + 'no-await-in-loop': 'off', + }, + }, + ], +}; diff --git a/contracts/bootstrap/.prettierrc.toml b/contracts/bootstrap/.prettierrc.toml new file mode 100644 index 00000000..b79b00db --- /dev/null +++ b/contracts/bootstrap/.prettierrc.toml @@ -0,0 +1,6 @@ +# .prettierrc.toml +trailingComma = "es5" +tabWidth = 4 +semi = true +singleQuote = true +printWidth = 120 diff --git a/contracts/bootstrap/index.ts b/contracts/bootstrap/index.ts new file mode 100644 index 00000000..0b47da53 --- /dev/null +++ b/contracts/bootstrap/index.ts @@ -0,0 +1,152 @@ +/* eslint-disable import/no-relative-packages */ +import * as algokit from '@algorandfoundation/algokit-utils'; +import { Account, decodeAddress, secretKeyToMnemonic } from 'algosdk'; +import { AlgoAmount } from '@algorandfoundation/algokit-utils/types/amount'; +import { getTestAccount } from '@algorandfoundation/algokit-utils/testing'; +import * as fs from 'fs'; +import { AlgoClientConfig } from '@algorandfoundation/algokit-utils/types/network-client'; +import yargs from 'yargs'; +import prompts from 'prompts'; +import { mnemonicAccountFromEnvironment } from '@algorandfoundation/algokit-utils'; +import { StakingPoolClient } from '../contracts/clients/StakingPoolClient'; +import { ValidatorRegistryClient } from '../contracts/clients/ValidatorRegistryClient'; + +async function getNetworkConfig(network: string): Promise<[AlgoClientConfig, bigint, string]> { + let registryAppID: bigint; + let feeSink: string; + switch (network) { + case 'devnet': + case 'localnet': + registryAppID = 0n; + feeSink = 'A7NMWS3NT3IUDMLVO26ULGXGIIOUQ3ND2TXSER6EBGRZNOBOUIQXHIBGDE'; + return [algokit.getConfigFromEnvOrDefaults().algodConfig, registryAppID, feeSink]; + case 'betanet': + registryAppID = 842656530n; + feeSink = 'A7NMWS3NT3IUDMLVO26ULGXGIIOUQ3ND2TXSER6EBGRZNOBOUIQXHIBGDE'; + break; + case 'testnet': + registryAppID = 84366825n; + feeSink = 'A7NMWS3NT3IUDMLVO26ULGXGIIOUQ3ND2TXSER6EBGRZNOBOUIQXHIBGDE'; + break; + case 'mainnet': + registryAppID = 760937186n; + feeSink = 'Y76M3MSY6DKBRHBL7C3NNDXGS5IIMQVQVUAB6MP4XEMMGVF2QWNPL226CA'; + break; + default: + throw new Error(`Unsupported network network: ${network}`); + } + const config = { + server: `https://${network}-api.algonode.cloud/`, + port: 443, + } as AlgoClientConfig; + + return [config, registryAppID, feeSink]; +} + +async function main() { + const args = await yargs.option('network', { + default: 'localnet', + choices: ['localnet', 'betanet', 'testnet', 'mainnet'], + demandOption: true, + }).argv; + + const [algodconfig, registryAppID, feeSink] = await getNetworkConfig(args.network); + + const algod = algokit.getAlgoClient(algodconfig); + const localConfig = algokit.getConfigFromEnvOrDefaults(); + + let creatorAcct: Account; + + // Confirm the network choice by prompting the user if they want to continue if !localnet + if (args.network !== 'localnet') { + // verify an env variable is defined for CREATOR_MNEMONIC ! + if (!process.env.CREATOR_MNEMONIC) { + console.error('Environment variable CREATOR_MNEMONIC is not defined'); + process.exit(1); + } + creatorAcct = await mnemonicAccountFromEnvironment('CREATOR', algod); + console.log(`using ${creatorAcct.addr} as Reti creator. MAKE SURE THIS IS CORRECT!`); + + console.log(`You've specified you want to DEPLOY to ${args.network}! This is permanent !`); + const yn = await prompts({ + type: 'confirm', + name: 'value', + message: 'Can you confirm?', + initial: true, + }); + if (!yn.value) { + return; + } + } else { + const kmd = algokit.getAlgoKmdClient(localConfig.kmdConfig); + creatorAcct = await algokit.getDispenserAccount(algod, kmd); + + console.log(`Primary DISPENSER account is: ${creatorAcct.addr}`); + } + + // Generate staking pool template instance that the validatory registry will reference + const poolClient = new StakingPoolClient( + { + sender: creatorAcct, + resolveBy: 'id', + id: 0, + deployTimeParams: { + nfdRegistryAppId: registryAppID, + feeSinkAddr: decodeAddress(feeSink).publicKey, + }, + }, + algod + ); + const tmplPool = await poolClient.create.createApplication({ + creatingContractId: 0, + validatorId: 0, + poolId: 0, + minEntryStake: 1_000_000, // 1 algo min is hard req in contract creation + }); + + // first we have to deploy a staking pool contract instance for future use by the staking master contract (which uses it as its + // 'reference' instance when creating new staking pool contract instances. + const validatorClient = new ValidatorRegistryClient( + { + sender: creatorAcct, + resolveBy: 'id', + id: 0, + deployTimeParams: { + nfdRegistryAppId: registryAppID, + }, + }, + algod + ); + const validatorApp = await validatorClient.create.createApplication({ poolTemplateAppId: tmplPool.appId }); + + // Fund the validator w/ min .1 ALGO ! + algokit.transferAlgos({ from: creatorAcct, to: validatorApp.appAddress, amount: AlgoAmount.Algos(0.1) }, algod); + + console.log(`Validator registry app id is:${validatorApp.appId}`); + + if (args.network === 'localnet') { + const kmd = algokit.getAlgoKmdClient(localConfig.kmdConfig); + // generate two dummy stakers - each w/ 100 million + const staker1 = await getTestAccount( + { initialFunds: AlgoAmount.Algos(100_000_000), suppressLog: true }, + algod, + kmd + ); + const staker2 = await getTestAccount( + { initialFunds: AlgoAmount.Algos(100_000_000), suppressLog: true }, + algod, + kmd + ); + console.log(`Created test account 1:${staker1.addr}`); + console.log(`Created test account 2:${staker2.addr}`); + + // Write the mnemonic to a .sandbox file in ../../nodemgr directory + fs.writeFileSync( + '../../nodemgr/.env.sandbox', + `ALGO_MNEMONIC_${creatorAcct.addr.substring(0, 4)}=${secretKeyToMnemonic(creatorAcct.sk)}\nRETI_APPID=${validatorApp.appId}\nALGO_MNEMONIC_${staker1.addr.substring(0, 4)}=${secretKeyToMnemonic(staker1.sk)}\nALGO_MNEMONIC_${staker2.addr.substring(0, 4)}=${secretKeyToMnemonic(staker2.sk)}\n` + ); + console.log('Modified .env.sandbox in nodemgr directory with these values for testing'); + } +} + +main(); diff --git a/contracts/bootstrap/package.json b/contracts/bootstrap/package.json new file mode 100644 index 00000000..935866b7 --- /dev/null +++ b/contracts/bootstrap/package.json @@ -0,0 +1,25 @@ +{ + "name": "bootstrap", + "version": "0.1.0", + "description": "", + "main": "index.ts", + "scripts": { + "build": "tsc", + "start": "node dist/bootstrap/index.js", + "bootstrap": "pnpm run build && pnpm run start" + }, + "license": "MIT", + "dependencies": { + "@algorandfoundation/algokit-utils": "^5.8.0", + "algosdk": "^2.7.0", + "prompts": "^2.4.2", + "yargs": "^17.7.2" + }, + "devDependencies": { + "@tsconfig/node18": "^18.2.4", + "@types/node": "^20.12.2", + "@types/prompts": "^2.4.9", + "@types/yargs": "^17.0.32", + "typescript": "^5.4.3" + } +} diff --git a/contracts/bootstrap/pnpm-lock.yaml b/contracts/bootstrap/pnpm-lock.yaml new file mode 100644 index 00000000..6e8eda16 --- /dev/null +++ b/contracts/bootstrap/pnpm-lock.yaml @@ -0,0 +1,274 @@ +lockfileVersion: '6.0' + +settings: + autoInstallPeers: true + excludeLinksFromLockfile: false + +dependencies: + '@algorandfoundation/algokit-utils': + specifier: ^5.8.0 + version: 5.8.0(algosdk@2.7.0) + algosdk: + specifier: ^2.7.0 + version: 2.7.0 + prompts: + specifier: ^2.4.2 + version: 2.4.2 + yargs: + specifier: ^17.7.2 + version: 17.7.2 + +devDependencies: + '@tsconfig/node18': + specifier: ^18.2.4 + version: 18.2.4 + '@types/node': + specifier: ^20.12.2 + version: 20.12.2 + '@types/prompts': + specifier: ^2.4.9 + version: 2.4.9 + '@types/yargs': + specifier: ^17.0.32 + version: 17.0.32 + typescript: + specifier: ^5.4.3 + version: 5.4.3 + +packages: + + /@algorandfoundation/algokit-utils@5.8.0(algosdk@2.7.0): + resolution: {integrity: sha512-BxwUBQ0BaAPpOZt7e2kwP0pfvG2W2AqOBBI6Y3AbJ01a9P7yJ1wIaJfqG02aiG4mpKbLgz84WBQij+0DqGK80Q==} + engines: {node: '>=18.0'} + peerDependencies: + algosdk: ^2.7.0 + dependencies: + algosdk: 2.7.0 + buffer: 6.0.3 + dev: false + + /@tsconfig/node18@18.2.4: + resolution: {integrity: sha512-5xxU8vVs9/FNcvm3gE07fPbn9tl6tqGGWA9tSlwsUEkBxtRnTsNmwrV8gasZ9F/EobaSv9+nu8AxUKccw77JpQ==} + dev: true + + /@types/node@20.12.2: + resolution: {integrity: sha512-zQ0NYO87hyN6Xrclcqp7f8ZbXNbRfoGWNcMvHTPQp9UUrwI0mI7XBz+cu7/W6/VClYo2g63B0cjull/srU7LgQ==} + dependencies: + undici-types: 5.26.5 + dev: true + + /@types/prompts@2.4.9: + resolution: {integrity: sha512-qTxFi6Buiu8+50/+3DGIWLHM6QuWsEKugJnnP6iv2Mc4ncxE4A/OJkjuVOA+5X0X1S/nq5VJRa8Lu+nwcvbrKA==} + dependencies: + '@types/node': 20.12.2 + kleur: 3.0.3 + dev: true + + /@types/yargs-parser@21.0.3: + resolution: {integrity: sha512-I4q9QU9MQv4oEOz4tAHJtNz1cwuLxn2F3xcc2iV5WdqLPpUnj30aUuxt1mAxYTG+oe8CZMV/+6rU4S4gRDzqtQ==} + dev: true + + /@types/yargs@17.0.32: + resolution: {integrity: sha512-xQ67Yc/laOG5uMfX/093MRlGGCIBzZMarVa+gfNKJxWAIgykYpVGkBdbqEzGDDfCrVUj6Hiff4mTZ5BA6TmAog==} + dependencies: + '@types/yargs-parser': 21.0.3 + dev: true + + /algo-msgpack-with-bigint@2.1.1: + resolution: {integrity: sha512-F1tGh056XczEaEAqu7s+hlZUDWwOBT70Eq0lfMpBP2YguSQVyxRbprLq5rELXKQOyOaixTWYhMeMQMzP0U5FoQ==} + engines: {node: '>= 10'} + dev: false + + /algosdk@2.7.0: + resolution: {integrity: sha512-sBE9lpV7bup3rZ+q2j3JQaFAE9JwZvjWKX00vPlG8e9txctXbgLL56jZhSWZndqhDI9oI+0P4NldkuQIWdrUyg==} + engines: {node: '>=18.0.0'} + dependencies: + algo-msgpack-with-bigint: 2.1.1 + buffer: 6.0.3 + hi-base32: 0.5.1 + js-sha256: 0.9.0 + js-sha3: 0.8.0 + js-sha512: 0.8.0 + json-bigint: 1.0.0 + tweetnacl: 1.0.3 + vlq: 2.0.4 + dev: false + + /ansi-regex@5.0.1: + resolution: {integrity: sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==} + engines: {node: '>=8'} + dev: false + + /ansi-styles@4.3.0: + resolution: {integrity: sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==} + engines: {node: '>=8'} + dependencies: + color-convert: 2.0.1 + dev: false + + /base64-js@1.5.1: + resolution: {integrity: sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==} + dev: false + + /bignumber.js@9.1.2: + resolution: {integrity: sha512-2/mKyZH9K85bzOEfhXDBFZTGd1CTs+5IHpeFQo9luiBG7hghdC851Pj2WAhb6E3R6b9tZj/XKhbg4fum+Kepug==} + dev: false + + /buffer@6.0.3: + resolution: {integrity: sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==} + dependencies: + base64-js: 1.5.1 + ieee754: 1.2.1 + dev: false + + /cliui@8.0.1: + resolution: {integrity: sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==} + engines: {node: '>=12'} + dependencies: + string-width: 4.2.3 + strip-ansi: 6.0.1 + wrap-ansi: 7.0.0 + dev: false + + /color-convert@2.0.1: + resolution: {integrity: sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==} + engines: {node: '>=7.0.0'} + dependencies: + color-name: 1.1.4 + dev: false + + /color-name@1.1.4: + resolution: {integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==} + dev: false + + /emoji-regex@8.0.0: + resolution: {integrity: sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==} + dev: false + + /escalade@3.1.2: + resolution: {integrity: sha512-ErCHMCae19vR8vQGe50xIsVomy19rg6gFu3+r3jkEO46suLMWBksvVyoGgQV+jOfl84ZSOSlmv6Gxa89PmTGmA==} + engines: {node: '>=6'} + dev: false + + /get-caller-file@2.0.5: + resolution: {integrity: sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==} + engines: {node: 6.* || 8.* || >= 10.*} + dev: false + + /hi-base32@0.5.1: + resolution: {integrity: sha512-EmBBpvdYh/4XxsnUybsPag6VikPYnN30td+vQk+GI3qpahVEG9+gTkG0aXVxTjBqQ5T6ijbWIu77O+C5WFWsnA==} + dev: false + + /ieee754@1.2.1: + resolution: {integrity: sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==} + dev: false + + /is-fullwidth-code-point@3.0.0: + resolution: {integrity: sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==} + engines: {node: '>=8'} + dev: false + + /js-sha256@0.9.0: + resolution: {integrity: sha512-sga3MHh9sgQN2+pJ9VYZ+1LPwXOxuBJBA5nrR5/ofPfuiJBE2hnjsaN8se8JznOmGLN2p49Pe5U/ttafcs/apA==} + dev: false + + /js-sha3@0.8.0: + resolution: {integrity: sha512-gF1cRrHhIzNfToc802P800N8PpXS+evLLXfsVpowqmAFR9uwbi89WvXg2QspOmXL8QL86J4T1EpFu+yUkwJY3Q==} + dev: false + + /js-sha512@0.8.0: + resolution: {integrity: sha512-PWsmefG6Jkodqt+ePTvBZCSMFgN7Clckjd0O7su3I0+BW2QWUTJNzjktHsztGLhncP2h8mcF9V9Y2Ha59pAViQ==} + dev: false + + /json-bigint@1.0.0: + resolution: {integrity: sha512-SiPv/8VpZuWbvLSMtTDU8hEfrZWg/mH/nV/b4o0CYbSxu1UIQPLdwKOCIyLQX+VIPO5vrLX3i8qtqFyhdPSUSQ==} + dependencies: + bignumber.js: 9.1.2 + dev: false + + /kleur@3.0.3: + resolution: {integrity: sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w==} + engines: {node: '>=6'} + + /prompts@2.4.2: + resolution: {integrity: sha512-NxNv/kLguCA7p3jE8oL2aEBsrJWgAakBpgmgK6lpPWV+WuOmY6r2/zbAVnP+T8bQlA0nzHXSJSJW0Hq7ylaD2Q==} + engines: {node: '>= 6'} + dependencies: + kleur: 3.0.3 + sisteransi: 1.0.5 + dev: false + + /require-directory@2.1.1: + resolution: {integrity: sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==} + engines: {node: '>=0.10.0'} + dev: false + + /sisteransi@1.0.5: + resolution: {integrity: sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg==} + dev: false + + /string-width@4.2.3: + resolution: {integrity: sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==} + engines: {node: '>=8'} + dependencies: + emoji-regex: 8.0.0 + is-fullwidth-code-point: 3.0.0 + strip-ansi: 6.0.1 + dev: false + + /strip-ansi@6.0.1: + resolution: {integrity: sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==} + engines: {node: '>=8'} + dependencies: + ansi-regex: 5.0.1 + dev: false + + /tweetnacl@1.0.3: + resolution: {integrity: sha512-6rt+RN7aOi1nGMyC4Xa5DdYiukl2UWCbcJft7YhxReBGQD7OAM8Pbxw6YMo4r2diNEA8FEmu32YOn9rhaiE5yw==} + dev: false + + /typescript@5.4.3: + resolution: {integrity: sha512-KrPd3PKaCLr78MalgiwJnA25Nm8HAmdwN3mYUYZgG/wizIo9EainNVQI9/yDavtVFRN2h3k8uf3GLHuhDMgEHg==} + engines: {node: '>=14.17'} + hasBin: true + dev: true + + /undici-types@5.26.5: + resolution: {integrity: sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==} + dev: true + + /vlq@2.0.4: + resolution: {integrity: sha512-aodjPa2wPQFkra1G8CzJBTHXhgk3EVSwxSWXNPr1fgdFLUb8kvLV1iEb6rFgasIsjP82HWI6dsb5Io26DDnasA==} + dev: false + + /wrap-ansi@7.0.0: + resolution: {integrity: sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==} + engines: {node: '>=10'} + dependencies: + ansi-styles: 4.3.0 + string-width: 4.2.3 + strip-ansi: 6.0.1 + dev: false + + /y18n@5.0.8: + resolution: {integrity: sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==} + engines: {node: '>=10'} + dev: false + + /yargs-parser@21.1.1: + resolution: {integrity: sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==} + engines: {node: '>=12'} + dev: false + + /yargs@17.7.2: + resolution: {integrity: sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==} + engines: {node: '>=12'} + dependencies: + cliui: 8.0.1 + escalade: 3.1.2 + get-caller-file: 2.0.5 + require-directory: 2.1.1 + string-width: 4.2.3 + y18n: 5.0.8 + yargs-parser: 21.1.1 + dev: false diff --git a/contracts/bootstrap/tsconfig.json b/contracts/bootstrap/tsconfig.json new file mode 100644 index 00000000..0d06debb --- /dev/null +++ b/contracts/bootstrap/tsconfig.json @@ -0,0 +1,12 @@ +{ + "extends": "@tsconfig/node18/tsconfig.json", + "compilerOptions": { + "outDir": "dist", + "target": "ES2020", + "lib": ["ES2020", "DOM"], + }, + "include": [ + "*.ts", + "src/**/*.ts" + ] +} diff --git a/contracts/contracts/artifacts/StakingPool.approval.teal b/contracts/contracts/artifacts/StakingPool.approval.teal new file mode 100644 index 00000000..021968c4 --- /dev/null +++ b/contracts/contracts/artifacts/StakingPool.approval.teal @@ -0,0 +1,3793 @@ +#pragma version 10 + +// This TEAL was generated by TEALScript v0.88.1 +// https://github.com/algorandfoundation/TEALScript + +// This contract is compliant with and/or implements the following ARCs: [ ARC4 ] + +// The following ten lines of TEAL handle initial program flow +// This pattern is used to make it easy for anyone to parse the start of the program and determine if a specific action is allowed +// Here, action refers to the OnComplete in combination with whether the app is being created or called +// Every possible action for this contract is represented in the switch statement +// If the action is not implemented in the contract, its respective branch will be "*NOT_IMPLEMENTED" which just contains "err" +txn ApplicationID +! +int 6 +* +txn OnCompletion ++ +switch *call_NoOp *NOT_IMPLEMENTED *NOT_IMPLEMENTED *NOT_IMPLEMENTED *NOT_IMPLEMENTED *NOT_IMPLEMENTED *create_NoOp *NOT_IMPLEMENTED *NOT_IMPLEMENTED *NOT_IMPLEMENTED *NOT_IMPLEMENTED *NOT_IMPLEMENTED + +*NOT_IMPLEMENTED: + err + +// createApplication(uint64,uint64,uint64,uint64)void +*abi_route_createApplication: + // minEntryStake: uint64 + txna ApplicationArgs 4 + btoi + + // poolId: uint64 + txna ApplicationArgs 3 + btoi + + // validatorId: uint64 + txna ApplicationArgs 2 + btoi + + // creatingContractId: uint64 + txna ApplicationArgs 1 + btoi + + // execute createApplication(uint64,uint64,uint64,uint64)void + callsub createApplication + int 1 + return + +// createApplication(creatingContractId: uint64, validatorId: uint64, poolId: uint64, minEntryStake: uint64): void +// +// Initialize the staking pool w/ owner and manager, but can only be created by the validator contract. +// @param {uint64} creatingContractId - id of contract that constructed us - the validator application (single global instance) +// @param {uint64} validatorId - id of validator we're a staking pool of +// @param {uint64} poolId - which pool id are we +// @param {uint64} minEntryStake - minimum amount to be in pool, but also minimum amount balance can't go below (without removing all!) +createApplication: + proto 4 0 + + // *if0_condition + // contracts/stakingPool.algo.ts:86 + // creatingContractId === 0 + frame_dig -1 // creatingContractId: uint64 + int 0 + == + bz *if0_else + + // *if0_consequent + // contracts/stakingPool.algo.ts:88 + // assert(validatorId === 0) + frame_dig -2 // validatorId: uint64 + int 0 + == + assert + + // contracts/stakingPool.algo.ts:89 + // assert(poolId === 0) + frame_dig -3 // poolId: uint64 + int 0 + == + assert + b *if0_end + +*if0_else: + // contracts/stakingPool.algo.ts:91 + // assert(validatorId !== 0) + frame_dig -2 // validatorId: uint64 + int 0 + != + assert + + // contracts/stakingPool.algo.ts:92 + // assert(poolId !== 0) + frame_dig -3 // poolId: uint64 + int 0 + != + assert + +*if0_end: + // contracts/stakingPool.algo.ts:94 + // assert(minEntryStake >= MIN_ALGO_STAKE_PER_POOL) + frame_dig -4 // minEntryStake: uint64 + int 1000000 + >= + assert + + // contracts/stakingPool.algo.ts:95 + // this.creatingValidatorContractAppId.value = creatingContractId + byte 0x63726561746f72417070 // "creatorApp" + frame_dig -1 // creatingContractId: uint64 + app_global_put + + // contracts/stakingPool.algo.ts:96 + // this.validatorId.value = validatorId + byte 0x76616c696461746f724964 // "validatorId" + frame_dig -2 // validatorId: uint64 + app_global_put + + // contracts/stakingPool.algo.ts:97 + // this.poolId.value = poolId + byte 0x706f6f6c4964 // "poolId" + frame_dig -3 // poolId: uint64 + app_global_put + + // contracts/stakingPool.algo.ts:98 + // this.numStakers.value = 0 + byte 0x6e756d5374616b657273 // "numStakers" + int 0 + app_global_put + + // contracts/stakingPool.algo.ts:99 + // this.totalAlgoStaked.value = 0 + byte 0x7374616b6564 // "staked" + int 0 + app_global_put + + // contracts/stakingPool.algo.ts:100 + // this.minEntryStake.value = minEntryStake + byte 0x6d696e456e7472795374616b65 // "minEntryStake" + frame_dig -4 // minEntryStake: uint64 + app_global_put + + // contracts/stakingPool.algo.ts:101 + // this.lastPayout.value = globals.latestTimestamp + byte 0x6c6173745061796f7574 // "lastPayout" + global LatestTimestamp + app_global_put + + // contracts/stakingPool.algo.ts:102 + // this.epochNumber.value = 0 + byte 0x65706f63684e756d626572 // "epochNumber" + int 0 + app_global_put + retsub + +// gas()void +*abi_route_gas: + // execute gas()void + callsub gas + int 1 + return + +// gas(): void +// +// gas is a dummy no-op call that can be used to pool-up resource references and opcode cost +gas: + proto 0 0 + retsub + +// minBalanceForAccount(contracts: uint64, extraPages: uint64, assets: uint64, localInts: uint64, localBytes: uint64, globalInts: uint64, globalBytes: uint64): uint64 +minBalanceForAccount: + proto 7 1 + + // Push empty bytes after the frame pointer to reserve space for local variables + byte 0x + + // contracts/stakingPool.algo.ts:119 + // minBal = ALGORAND_ACCOUNT_MIN_BALANCE + int 100000 + frame_bury 0 // minBal: uint64 + + // contracts/stakingPool.algo.ts:120 + // minBal += contracts * APPLICATION_BASE_FEE + frame_dig 0 // minBal: uint64 + frame_dig -1 // contracts: uint64 + int 100000 + * + + + frame_bury 0 // minBal: uint64 + + // contracts/stakingPool.algo.ts:121 + // minBal += extraPages * APPLICATION_BASE_FEE + frame_dig 0 // minBal: uint64 + frame_dig -2 // extraPages: uint64 + int 100000 + * + + + frame_bury 0 // minBal: uint64 + + // contracts/stakingPool.algo.ts:122 + // minBal += assets * ASSET_HOLDING_FEE + frame_dig 0 // minBal: uint64 + frame_dig -3 // assets: uint64 + int 100000 + * + + + frame_bury 0 // minBal: uint64 + + // contracts/stakingPool.algo.ts:123 + // minBal += localInts * SSC_VALUE_UINT + frame_dig 0 // minBal: uint64 + frame_dig -4 // localInts: uint64 + int 28500 + * + + + frame_bury 0 // minBal: uint64 + + // contracts/stakingPool.algo.ts:124 + // minBal += globalInts * SSC_VALUE_UINT + frame_dig 0 // minBal: uint64 + frame_dig -6 // globalInts: uint64 + int 28500 + * + + + frame_bury 0 // minBal: uint64 + + // contracts/stakingPool.algo.ts:125 + // minBal += localBytes * SSC_VALUE_BYTES + frame_dig 0 // minBal: uint64 + frame_dig -5 // localBytes: uint64 + int 50000 + * + + + frame_bury 0 // minBal: uint64 + + // contracts/stakingPool.algo.ts:126 + // minBal += globalBytes * SSC_VALUE_BYTES + frame_dig 0 // minBal: uint64 + frame_dig -7 // globalBytes: uint64 + int 50000 + * + + + frame_bury 0 // minBal: uint64 + + // contracts/stakingPool.algo.ts:127 + // return minBal; + frame_dig 0 // minBal: uint64 + + // set the subroutine return value + frame_bury 0 + retsub + +// costForBoxStorage(totalNumBytes: uint64): uint64 +costForBoxStorage: + proto 1 1 + + // contracts/stakingPool.algo.ts:134 + // return SCBOX_PERBOX + totalNumBytes * SCBOX_PERBYTE; + int 2500 + frame_dig -1 // totalNumBytes: uint64 + int 400 + * + + + retsub + +// initStorage(pay)void +*abi_route_initStorage: + // mbrPayment: pay + txn GroupIndex + int 1 + - + dup + gtxns TypeEnum + int pay + == + assert + + // execute initStorage(pay)void + callsub initStorage + int 1 + return + +// initStorage(mbrPayment: PayTxn): void +// +// Called after we're created and then funded so we can create our large stakers ledger storage +// Caller has to get MBR amounts from ValidatorRegistry to know how much to fund us to cover the box storage cost +// If this is pool 1 AND the validator has specified a reward token, opt-in to that token +// so that the validator can seed the pool with future rewards of that token. +// @param mbrPayment payment from caller which covers mbr increase of new staking pools' storage +initStorage: + proto 1 0 + + // Push empty bytes after the frame pointer to reserve space for local variables + byte 0x + dupn 3 + + // contracts/stakingPool.algo.ts:145 + // assert(!this.stakers.exists, 'staking pool already initialized') + byte 0x7374616b657273 // "stakers" + box_len + swap + pop + ! + + // staking pool already initialized + assert + + // contracts/stakingPool.algo.ts:148 + // validatorConfig = sendMethodCall({ + // applicationID: AppID.fromUint64(this.creatingValidatorContractAppId.value), + // methodArgs: [this.validatorId.value], + // }) + itxn_begin + int appl + itxn_field TypeEnum + method "getValidatorConfig(uint64)(uint64,address,address,uint64,uint8,byte[32],uint64,uint64,uint64,uint16,uint32,address,uint64,uint64,uint8,uint64,uint64)" + itxn_field ApplicationArgs + + // contracts/stakingPool.algo.ts:149 + // applicationID: AppID.fromUint64(this.creatingValidatorContractAppId.value) + byte 0x63726561746f72417070 // "creatorApp" + app_global_get + itxn_field ApplicationID + + // contracts/stakingPool.algo.ts:150 + // methodArgs: [this.validatorId.value] + byte 0x76616c696461746f724964 // "validatorId" + app_global_get + itob + itxn_field ApplicationArgs + + // Fee field not set, defaulting to 0 + int 0 + itxn_field Fee + + // Submit inner transaction + itxn_submit + itxn NumLogs + int 1 + - + itxnas Logs + extract 4 0 + frame_bury 0 // validatorConfig: (uint64,address,address,uint64,uint8,byte[32],uint64,uint64,uint64,uint16,uint32,address,uint64,uint64,uint8,uint64,uint64) + + // contracts/stakingPool.algo.ts:152 + // isTokenEligible = validatorConfig.rewardTokenId !== 0 + frame_dig 0 // validatorConfig: (uint64,address,address,uint64,uint8,byte[32],uint64,uint64,uint64,uint16,uint32,address,uint64,uint64,uint8,uint64,uint64) + extract 121 8 + btoi + int 0 + != + frame_bury 1 // isTokenEligible: bool + + // contracts/stakingPool.algo.ts:153 + // extraMBR = isTokenEligible && this.poolId.value === 1 ? ASSET_HOLDING_FEE : 0 + frame_dig 1 // isTokenEligible: bool + dup + bz *skip_and1 + byte 0x706f6f6c4964 // "poolId" + app_global_get + int 1 + == + && + +*skip_and1: + bz *ternary1_false + int 100000 + b *ternary1_end + +*ternary1_false: + int 0 + +*ternary1_end: + frame_bury 2 // extraMBR: uint64 + + // contracts/stakingPool.algo.ts:154 + // PoolInitMbr = + // ALGORAND_ACCOUNT_MIN_BALANCE + + // extraMBR + + // this.costForBoxStorage(7 /* 'stakers' name */ + len() * MAX_STAKERS_PER_POOL) + int 100000 + frame_dig 2 // extraMBR: uint64 + + + int 12807 + callsub costForBoxStorage + + + frame_bury 3 // PoolInitMbr: uint64 + + // contracts/stakingPool.algo.ts:160 + // verifyPayTxn(mbrPayment, { amount: PoolInitMbr }) + // verify amount + frame_dig -1 // mbrPayment: PayTxn + gtxns Amount + frame_dig 3 // PoolInitMbr: uint64 + == + assert + + // contracts/stakingPool.algo.ts:161 + // this.stakers.create() + byte 0x7374616b657273 // "stakers" + int 12800 + box_create + pop + + // *if1_condition + // contracts/stakingPool.algo.ts:163 + // isTokenEligible && this.poolId.value === 1 + frame_dig 1 // isTokenEligible: bool + dup + bz *skip_and2 + byte 0x706f6f6c4964 // "poolId" + app_global_get + int 1 + == + && + +*skip_and2: + bz *if1_end + + // *if1_consequent + // contracts/stakingPool.algo.ts:165 + // sendAssetTransfer({ + // xferAsset: AssetID.fromUint64(validatorConfig.rewardTokenId), + // assetReceiver: this.app.address, + // assetAmount: 0, + // }) + itxn_begin + int axfer + itxn_field TypeEnum + + // contracts/stakingPool.algo.ts:166 + // xferAsset: AssetID.fromUint64(validatorConfig.rewardTokenId) + frame_dig 0 // validatorConfig: (uint64,address,address,uint64,uint8,byte[32],uint64,uint64,uint64,uint16,uint32,address,uint64,uint64,uint8,uint64,uint64) + extract 121 8 + btoi + itxn_field XferAsset + + // contracts/stakingPool.algo.ts:167 + // assetReceiver: this.app.address + global CurrentApplicationAddress + itxn_field AssetReceiver + + // contracts/stakingPool.algo.ts:168 + // assetAmount: 0 + int 0 + itxn_field AssetAmount + + // Fee field not set, defaulting to 0 + int 0 + itxn_field Fee + + // Submit inner transaction + itxn_submit + +*if1_end: + retsub + +// addStake(pay,address)uint64 +*abi_route_addStake: + // The ABI return prefix + byte 0x151f7c75 + + // staker: address + txna ApplicationArgs 1 + dup + len + int 32 + == + assert + + // stakedAmountPayment: pay + txn GroupIndex + int 1 + - + dup + gtxns TypeEnum + int pay + == + assert + + // execute addStake(pay,address)uint64 + callsub addStake + itob + concat + log + int 1 + return + +// addStake(stakedAmountPayment: PayTxn, staker: Address): uint64 +// +// Adds stake to the given account. +// Can ONLY be called by the validator contract that created us +// Must receive payment from the validator contract for amount being staked. +// +// @param {PayTxn} stakedAmountPayment prior payment coming from validator contract to us on behalf of staker. +// @param {Address} staker - The account adding new stake +// @throws {Error} - Throws an error if the staking pool is full. +// @returns {uint64} new 'entry time' in seconds of stake add. +addStake: + proto 2 1 + + // Push empty bytes after the frame pointer to reserve space for local variables + byte 0x + dupn 3 + + // contracts/stakingPool.algo.ts:184 + // assert(this.stakers.exists) + byte 0x7374616b657273 // "stakers" + box_len + swap + pop + assert + + // contracts/stakingPool.algo.ts:187 + // assert(this.txn.sender === AppID.fromUint64(this.creatingValidatorContractAppId.value).address) + txn Sender + byte 0x63726561746f72417070 // "creatorApp" + app_global_get + app_params_get AppAddress + pop + == + assert + + // contracts/stakingPool.algo.ts:188 + // assert(staker !== globals.zeroAddress) + frame_dig -2 // staker: Address + global ZeroAddress + != + assert + + // contracts/stakingPool.algo.ts:192 + // verifyPayTxn(stakedAmountPayment, { + // sender: AppID.fromUint64(this.creatingValidatorContractAppId.value).address, + // receiver: this.app.address, + // amount: stakedAmountPayment.amount, + // }) + // verify sender + frame_dig -1 // stakedAmountPayment: PayTxn + gtxns Sender + byte 0x63726561746f72417070 // "creatorApp" + app_global_get + app_params_get AppAddress + pop + == + assert + + // verify receiver + frame_dig -1 // stakedAmountPayment: PayTxn + gtxns Receiver + global CurrentApplicationAddress + == + assert + + // verify amount + frame_dig -1 // stakedAmountPayment: PayTxn + gtxns Amount + frame_dig -1 // stakedAmountPayment: PayTxn + gtxns Amount + == + assert + + // contracts/stakingPool.algo.ts:201 + // entryTime = this.getEntryTime() + callsub getEntryTime + frame_bury 0 // entryTime: uint64 + + // contracts/stakingPool.algo.ts:202 + // firstEmpty = 0 + int 0 + frame_bury 1 // firstEmpty: uint64 + + // contracts/stakingPool.algo.ts:205 + // for (let i = 0; i < this.stakers.value.length; i += 1) + int 0 + frame_bury 2 // i: uint64 + +*for_0: + // contracts/stakingPool.algo.ts:205 + // i < this.stakers.value.length + frame_dig 2 // i: uint64 + int 200 + < + bz *for_0_end + + // *if2_condition + // contracts/stakingPool.algo.ts:206 + // globals.opcodeBudget < 300 + global OpcodeBudget + int 300 + < + bz *if2_end + + // *if2_consequent + // contracts/stakingPool.algo.ts:207 + // increaseOpcodeBudget() + itxn_begin + int appl + itxn_field TypeEnum + int 0 + itxn_field Fee + byte b64 CoEB // #pragma version 10; int 1 + dup + itxn_field ApprovalProgram + itxn_field ClearStateProgram + int DeleteApplication + itxn_field OnCompletion + itxn_submit + +*if2_end: + // contracts/stakingPool.algo.ts:209 + // cmpStaker = clone(this.stakers.value[i]) + frame_dig 2 // i: uint64 + int 64 + * // acc * typeLength + int 64 + byte 0x7374616b657273 // "stakers" + cover 2 + box_extract + frame_bury 3 // cmpStaker: (address,uint64,uint64,uint64,uint64) + + // *if3_condition + // contracts/stakingPool.algo.ts:210 + // cmpStaker.account === staker + frame_dig 3 // cmpStaker: (address,uint64,uint64,uint64,uint64) + extract 0 32 + frame_dig -2 // staker: Address + == + bz *if3_end + + // *if3_consequent + // contracts/stakingPool.algo.ts:211 + // cmpStaker.balance += stakedAmountPayment.amount + frame_dig 3 // cmpStaker: (address,uint64,uint64,uint64,uint64) + int 32 // headOffset + frame_dig 3 // cmpStaker: (address,uint64,uint64,uint64,uint64) + extract 32 8 + btoi + frame_dig -1 // stakedAmountPayment: PayTxn + gtxns Amount + + + itob + replace3 + frame_bury 3 // cmpStaker: (address,uint64,uint64,uint64,uint64) + + // contracts/stakingPool.algo.ts:212 + // cmpStaker.entryTime = entryTime + frame_dig 3 // cmpStaker: (address,uint64,uint64,uint64,uint64) + int 56 // headOffset + frame_dig 0 // entryTime: uint64 + itob + replace3 + frame_bury 3 // cmpStaker: (address,uint64,uint64,uint64,uint64) + + // contracts/stakingPool.algo.ts:215 + // this.stakers.value[i] = cmpStaker + frame_dig 2 // i: uint64 + int 64 + * // acc * typeLength + frame_dig 3 // cmpStaker: (address,uint64,uint64,uint64,uint64) + byte 0x7374616b657273 // "stakers" + cover 2 + box_replace + + // contracts/stakingPool.algo.ts:217 + // this.totalAlgoStaked.value += stakedAmountPayment.amount + byte 0x7374616b6564 // "staked" + app_global_get + frame_dig -1 // stakedAmountPayment: PayTxn + gtxns Amount + + + byte 0x7374616b6564 // "staked" + swap + app_global_put + + // contracts/stakingPool.algo.ts:218 + // return entryTime; + frame_dig 0 // entryTime: uint64 + + // set the subroutine return value + frame_bury 0 + + // pop all local variables from the stack + popn 3 + retsub + +*if3_end: + // *if4_condition + // contracts/stakingPool.algo.ts:220 + // cmpStaker.account === globals.zeroAddress + frame_dig 3 // cmpStaker: (address,uint64,uint64,uint64,uint64) + extract 0 32 + global ZeroAddress + == + bz *if4_end + + // *if4_consequent + // contracts/stakingPool.algo.ts:221 + // firstEmpty = i + 1 + frame_dig 2 // i: uint64 + int 1 + + + frame_bury 1 // firstEmpty: uint64 + b *for_0_end + +*if4_end: + +*for_0_continue: + // contracts/stakingPool.algo.ts:205 + // i += 1 + frame_dig 2 // i: uint64 + int 1 + + + frame_bury 2 // i: uint64 + b *for_0 + +*for_0_end: + // *if5_condition + // contracts/stakingPool.algo.ts:226 + // firstEmpty === 0 + frame_dig 1 // firstEmpty: uint64 + int 0 + == + bz *if5_end + + // *if5_consequent + err // 'Staking pool full' + +*if5_end: + // contracts/stakingPool.algo.ts:233 + // assert(stakedAmountPayment.amount >= this.minEntryStake.value, 'must stake at least the minimum for this pool') + frame_dig -1 // stakedAmountPayment: PayTxn + gtxns Amount + byte 0x6d696e456e7472795374616b65 // "minEntryStake" + app_global_get + >= + + // must stake at least the minimum for this pool + assert + + // contracts/stakingPool.algo.ts:235 + // assert(this.stakers.value[firstEmpty - 1].account === globals.zeroAddress) + frame_dig 1 // firstEmpty: uint64 + int 1 + - + int 64 + * // acc * typeLength + int 0 + + + int 32 + byte 0x7374616b657273 // "stakers" + cover 2 + box_extract + global ZeroAddress + == + assert + + // contracts/stakingPool.algo.ts:236 + // this.stakers.value[firstEmpty - 1] = { + // account: staker, + // balance: stakedAmountPayment.amount, + // totalRewarded: 0, + // rewardTokenBalance: 0, + // entryTime: entryTime, + // } + frame_dig 1 // firstEmpty: uint64 + int 1 + - + int 64 + * // acc * typeLength + frame_dig -2 // staker: Address + frame_dig -1 // stakedAmountPayment: PayTxn + gtxns Amount + itob + concat + byte 0x0000000000000000 + concat + byte 0x0000000000000000 + concat + frame_dig 0 // entryTime: uint64 + itob + concat + byte 0x7374616b657273 // "stakers" + cover 2 + box_replace + + // contracts/stakingPool.algo.ts:243 + // this.numStakers.value += 1 + byte 0x6e756d5374616b657273 // "numStakers" + app_global_get + int 1 + + + byte 0x6e756d5374616b657273 // "numStakers" + swap + app_global_put + + // contracts/stakingPool.algo.ts:244 + // this.totalAlgoStaked.value += stakedAmountPayment.amount + byte 0x7374616b6564 // "staked" + app_global_get + frame_dig -1 // stakedAmountPayment: PayTxn + gtxns Amount + + + byte 0x7374616b6564 // "staked" + swap + app_global_put + + // contracts/stakingPool.algo.ts:245 + // return entryTime; + frame_dig 0 // entryTime: uint64 + + // set the subroutine return value + frame_bury 0 + + // pop all local variables from the stack + popn 3 + retsub + +// removeStake(uint64)void +*abi_route_removeStake: + // amountToUnstake: uint64 + txna ApplicationArgs 1 + btoi + + // execute removeStake(uint64)void + callsub removeStake + int 1 + return + +// removeStake(amountToUnstake: uint64): void +// +// Removes stake on behalf of caller (removing own stake). If any token rewards exist, those are always sent in +// full. Also notifies the validator contract for this pools validator of the staker / balance changes. +// +// @param {uint64} amountToUnstake - The amount of stake to be removed. Specify 0 to remove all stake. +// @throws {Error} If the account has insufficient balance or if the account is not found. +removeStake: + proto 1 0 + + // Push empty bytes after the frame pointer to reserve space for local variables + byte 0x + dupn 5 + + // contracts/stakingPool.algo.ts:259 + // staker = this.txn.sender + txn Sender + frame_bury 0 // staker: address + + // contracts/stakingPool.algo.ts:261 + // for (let i = 0; i < this.stakers.value.length; i += 1) + int 0 + frame_bury 1 // i: uint64 + +*for_1: + // contracts/stakingPool.algo.ts:261 + // i < this.stakers.value.length + frame_dig 1 // i: uint64 + int 200 + < + bz *for_1_end + + // *if6_condition + // contracts/stakingPool.algo.ts:262 + // globals.opcodeBudget < 300 + global OpcodeBudget + int 300 + < + bz *if6_end + + // *if6_consequent + // contracts/stakingPool.algo.ts:263 + // increaseOpcodeBudget() + itxn_begin + int appl + itxn_field TypeEnum + int 0 + itxn_field Fee + byte b64 CoEB // #pragma version 10; int 1 + dup + itxn_field ApprovalProgram + itxn_field ClearStateProgram + int DeleteApplication + itxn_field OnCompletion + itxn_submit + +*if6_end: + // contracts/stakingPool.algo.ts:265 + // cmpStaker = clone(this.stakers.value[i]) + frame_dig 1 // i: uint64 + int 64 + * // acc * typeLength + int 64 + byte 0x7374616b657273 // "stakers" + cover 2 + box_extract + frame_bury 2 // cmpStaker: (address,uint64,uint64,uint64,uint64) + + // *if7_condition + // contracts/stakingPool.algo.ts:266 + // cmpStaker.account === staker + frame_dig 2 // cmpStaker: (address,uint64,uint64,uint64,uint64) + extract 0 32 + frame_dig 0 // staker: address + == + bz *if7_end + + // *if7_consequent + // *if8_condition + // contracts/stakingPool.algo.ts:267 + // amountToUnstake === 0 + frame_dig -1 // amountToUnstake: uint64 + int 0 + == + bz *if8_end + + // *if8_consequent + // contracts/stakingPool.algo.ts:269 + // amountToUnstake = cmpStaker.balance + frame_dig 2 // cmpStaker: (address,uint64,uint64,uint64,uint64) + extract 32 8 + btoi + frame_bury -1 // amountToUnstake: uint64 + +*if8_end: + // *if9_condition + // contracts/stakingPool.algo.ts:271 + // cmpStaker.balance < amountToUnstake + frame_dig 2 // cmpStaker: (address,uint64,uint64,uint64,uint64) + extract 32 8 + btoi + frame_dig -1 // amountToUnstake: uint64 + < + bz *if9_end + + // *if9_consequent + err // 'Insufficient balance' + +*if9_end: + // contracts/stakingPool.algo.ts:274 + // cmpStaker.balance -= amountToUnstake + frame_dig 2 // cmpStaker: (address,uint64,uint64,uint64,uint64) + int 32 // headOffset + frame_dig 2 // cmpStaker: (address,uint64,uint64,uint64,uint64) + extract 32 8 + btoi + frame_dig -1 // amountToUnstake: uint64 + - + itob + replace3 + frame_bury 2 // cmpStaker: (address,uint64,uint64,uint64,uint64) + + // contracts/stakingPool.algo.ts:275 + // this.totalAlgoStaked.value -= amountToUnstake + byte 0x7374616b6564 // "staked" + app_global_get + frame_dig -1 // amountToUnstake: uint64 + - + byte 0x7374616b6564 // "staked" + swap + app_global_put + + // contracts/stakingPool.algo.ts:277 + // amountRewardTokenRemoved = 0 + int 0 + frame_bury 3 // amountRewardTokenRemoved: uint64 + + // *if10_condition + // contracts/stakingPool.algo.ts:278 + // cmpStaker.rewardTokenBalance > 0 + frame_dig 2 // cmpStaker: (address,uint64,uint64,uint64,uint64) + extract 48 8 + btoi + int 0 + > + bz *if10_end + + // *if10_consequent + // *if11_condition + // contracts/stakingPool.algo.ts:280 + // this.poolId.value === 1 + byte 0x706f6f6c4964 // "poolId" + app_global_get + int 1 + == + bz *if11_else + + // *if11_consequent + // contracts/stakingPool.algo.ts:281 + // validatorConfig = sendMethodCall({ + // applicationID: AppID.fromUint64(this.creatingValidatorContractAppId.value), + // methodArgs: [this.validatorId.value], + // }) + itxn_begin + int appl + itxn_field TypeEnum + method "getValidatorConfig(uint64)(uint64,address,address,uint64,uint8,byte[32],uint64,uint64,uint64,uint16,uint32,address,uint64,uint64,uint8,uint64,uint64)" + itxn_field ApplicationArgs + + // contracts/stakingPool.algo.ts:282 + // applicationID: AppID.fromUint64(this.creatingValidatorContractAppId.value) + byte 0x63726561746f72417070 // "creatorApp" + app_global_get + itxn_field ApplicationID + + // contracts/stakingPool.algo.ts:283 + // methodArgs: [this.validatorId.value] + byte 0x76616c696461746f724964 // "validatorId" + app_global_get + itob + itxn_field ApplicationArgs + + // Fee field not set, defaulting to 0 + int 0 + itxn_field Fee + + // Submit inner transaction + itxn_submit + itxn NumLogs + int 1 + - + itxnas Logs + extract 4 0 + frame_bury 4 // validatorConfig: (uint64,address,address,uint64,uint8,byte[32],uint64,uint64,uint64,uint16,uint32,address,uint64,uint64,uint8,uint64,uint64) + + // contracts/stakingPool.algo.ts:289 + // sendAssetTransfer({ + // xferAsset: AssetID.fromUint64(validatorConfig.rewardTokenId), + // assetReceiver: staker, + // assetAmount: cmpStaker.rewardTokenBalance, + // }) + itxn_begin + int axfer + itxn_field TypeEnum + + // contracts/stakingPool.algo.ts:290 + // xferAsset: AssetID.fromUint64(validatorConfig.rewardTokenId) + frame_dig 4 // validatorConfig: (uint64,address,address,uint64,uint8,byte[32],uint64,uint64,uint64,uint16,uint32,address,uint64,uint64,uint8,uint64,uint64) + extract 121 8 + btoi + itxn_field XferAsset + + // contracts/stakingPool.algo.ts:291 + // assetReceiver: staker + frame_dig 0 // staker: address + itxn_field AssetReceiver + + // contracts/stakingPool.algo.ts:292 + // assetAmount: cmpStaker.rewardTokenBalance + frame_dig 2 // cmpStaker: (address,uint64,uint64,uint64,uint64) + extract 48 8 + btoi + itxn_field AssetAmount + + // Fee field not set, defaulting to 0 + int 0 + itxn_field Fee + + // Submit inner transaction + itxn_submit + + // contracts/stakingPool.algo.ts:294 + // amountRewardTokenRemoved = cmpStaker.rewardTokenBalance + frame_dig 2 // cmpStaker: (address,uint64,uint64,uint64,uint64) + extract 48 8 + btoi + frame_bury 3 // amountRewardTokenRemoved: uint64 + + // contracts/stakingPool.algo.ts:295 + // cmpStaker.rewardTokenBalance = 0 + frame_dig 2 // cmpStaker: (address,uint64,uint64,uint64,uint64) + byte 0x0000000000000000 + replace2 48 + frame_bury 2 // cmpStaker: (address,uint64,uint64,uint64,uint64) + b *if11_end + +*if11_else: + // contracts/stakingPool.algo.ts:300 + // amountRewardTokenRemoved = cmpStaker.rewardTokenBalance + frame_dig 2 // cmpStaker: (address,uint64,uint64,uint64,uint64) + extract 48 8 + btoi + frame_bury 3 // amountRewardTokenRemoved: uint64 + + // contracts/stakingPool.algo.ts:301 + // cmpStaker.rewardTokenBalance = 0 + frame_dig 2 // cmpStaker: (address,uint64,uint64,uint64,uint64) + byte 0x0000000000000000 + replace2 48 + frame_bury 2 // cmpStaker: (address,uint64,uint64,uint64,uint64) + +*if11_end: + +*if10_end: + // contracts/stakingPool.algo.ts:306 + // assert( + // cmpStaker.balance === 0 || cmpStaker.balance >= this.minEntryStake.value, + // 'cannot reduce balance below minimum allowed stake unless all is removed' + // ) + frame_dig 2 // cmpStaker: (address,uint64,uint64,uint64,uint64) + extract 32 8 + btoi + int 0 + == + dup + bnz *skip_or0 + frame_dig 2 // cmpStaker: (address,uint64,uint64,uint64,uint64) + extract 32 8 + btoi + byte 0x6d696e456e7472795374616b65 // "minEntryStake" + app_global_get + >= + || + +*skip_or0: + // cannot reduce balance below minimum allowed stake unless all is removed + assert + + // contracts/stakingPool.algo.ts:314 + // sendPayment({ + // amount: amountToUnstake, + // receiver: staker, + // note: 'unstaked', + // }) + itxn_begin + int pay + itxn_field TypeEnum + + // contracts/stakingPool.algo.ts:315 + // amount: amountToUnstake + frame_dig -1 // amountToUnstake: uint64 + itxn_field Amount + + // contracts/stakingPool.algo.ts:316 + // receiver: staker + frame_dig 0 // staker: address + itxn_field Receiver + + // contracts/stakingPool.algo.ts:317 + // note: 'unstaked' + byte 0x756e7374616b6564 // "unstaked" + itxn_field Note + + // Fee field not set, defaulting to 0 + int 0 + itxn_field Fee + + // Submit inner transaction + itxn_submit + + // contracts/stakingPool.algo.ts:319 + // stakerRemoved = false + int 0 + frame_bury 5 // stakerRemoved: bool + + // *if12_condition + // contracts/stakingPool.algo.ts:320 + // cmpStaker.balance === 0 + frame_dig 2 // cmpStaker: (address,uint64,uint64,uint64,uint64) + extract 32 8 + btoi + int 0 + == + bz *if12_end + + // *if12_consequent + // contracts/stakingPool.algo.ts:322 + // this.numStakers.value -= 1 + byte 0x6e756d5374616b657273 // "numStakers" + app_global_get + int 1 + - + byte 0x6e756d5374616b657273 // "numStakers" + swap + app_global_put + + // contracts/stakingPool.algo.ts:323 + // cmpStaker.account = globals.zeroAddress + frame_dig 2 // cmpStaker: (address,uint64,uint64,uint64,uint64) + int 0 + global ZeroAddress + replace3 + frame_bury 2 // cmpStaker: (address,uint64,uint64,uint64,uint64) + + // contracts/stakingPool.algo.ts:324 + // cmpStaker.totalRewarded = 0 + frame_dig 2 // cmpStaker: (address,uint64,uint64,uint64,uint64) + byte 0x0000000000000000 + replace2 40 + frame_bury 2 // cmpStaker: (address,uint64,uint64,uint64,uint64) + + // contracts/stakingPool.algo.ts:325 + // cmpStaker.rewardTokenBalance = 0 + frame_dig 2 // cmpStaker: (address,uint64,uint64,uint64,uint64) + byte 0x0000000000000000 + replace2 48 + frame_bury 2 // cmpStaker: (address,uint64,uint64,uint64,uint64) + + // contracts/stakingPool.algo.ts:326 + // stakerRemoved = true + int 1 + frame_bury 5 // stakerRemoved: bool + +*if12_end: + // contracts/stakingPool.algo.ts:329 + // this.stakers.value[i] = cmpStaker + frame_dig 1 // i: uint64 + int 64 + * // acc * typeLength + frame_dig 2 // cmpStaker: (address,uint64,uint64,uint64,uint64) + byte 0x7374616b657273 // "stakers" + cover 2 + box_replace + + // contracts/stakingPool.algo.ts:334 + // sendMethodCall({ + // applicationID: AppID.fromUint64(this.creatingValidatorContractAppId.value), + // methodArgs: [ + // { id: this.validatorId.value, poolId: this.poolId.value, poolAppId: this.app.id }, + // staker, + // amountToUnstake, + // amountRewardTokenRemoved, + // stakerRemoved, + // ], + // }) + itxn_begin + int appl + itxn_field TypeEnum + method "stakeRemoved((uint64,uint64,uint64),address,uint64,uint64,bool)void" + itxn_field ApplicationArgs + + // contracts/stakingPool.algo.ts:335 + // applicationID: AppID.fromUint64(this.creatingValidatorContractAppId.value) + byte 0x63726561746f72417070 // "creatorApp" + app_global_get + itxn_field ApplicationID + + // contracts/stakingPool.algo.ts:336 + // methodArgs: [ + // { id: this.validatorId.value, poolId: this.poolId.value, poolAppId: this.app.id }, + // staker, + // amountToUnstake, + // amountRewardTokenRemoved, + // stakerRemoved, + // ] + byte 0x76616c696461746f724964 // "validatorId" + app_global_get + itob + byte 0x706f6f6c4964 // "poolId" + app_global_get + itob + concat + txna Applications 0 + itob + concat + itxn_field ApplicationArgs + frame_dig 0 // staker: address + itxn_field ApplicationArgs + frame_dig -1 // amountToUnstake: uint64 + itob + itxn_field ApplicationArgs + frame_dig 3 // amountRewardTokenRemoved: uint64 + itob + itxn_field ApplicationArgs + frame_dig 5 // stakerRemoved: bool + byte 0x00 + int 0 + uncover 2 + setbit + itxn_field ApplicationArgs + + // Fee field not set, defaulting to 0 + int 0 + itxn_field Fee + + // Submit inner transaction + itxn_submit + + // contracts/stakingPool.algo.ts:344 + // return; + retsub + +*if7_end: + +*for_1_continue: + // contracts/stakingPool.algo.ts:261 + // i += 1 + frame_dig 1 // i: uint64 + int 1 + + + frame_bury 1 // i: uint64 + b *for_1 + +*for_1_end: + err // 'account not found' + +// claimTokens()void +*abi_route_claimTokens: + // execute claimTokens()void + callsub claimTokens + int 1 + return + +// claimTokens(): void +// +// Claims all the available reward tokens a staker has available, sending their entire balance to the staker from +// pool 1 (either directly, or via validator->pool1 to pay it out) +// Also notifies the validator contract for this pools validator of the staker / balance changes. +claimTokens: + proto 0 0 + + // Push empty bytes after the frame pointer to reserve space for local variables + byte 0x + dupn 4 + + // contracts/stakingPool.algo.ts:359 + // staker = this.txn.sender + txn Sender + frame_bury 0 // staker: address + + // contracts/stakingPool.algo.ts:361 + // for (let i = 0; i < this.stakers.value.length; i += 1) + int 0 + frame_bury 1 // i: uint64 + +*for_2: + // contracts/stakingPool.algo.ts:361 + // i < this.stakers.value.length + frame_dig 1 // i: uint64 + int 200 + < + bz *for_2_end + + // *if13_condition + // contracts/stakingPool.algo.ts:362 + // globals.opcodeBudget < 300 + global OpcodeBudget + int 300 + < + bz *if13_end + + // *if13_consequent + // contracts/stakingPool.algo.ts:363 + // increaseOpcodeBudget() + itxn_begin + int appl + itxn_field TypeEnum + int 0 + itxn_field Fee + byte b64 CoEB // #pragma version 10; int 1 + dup + itxn_field ApprovalProgram + itxn_field ClearStateProgram + int DeleteApplication + itxn_field OnCompletion + itxn_submit + +*if13_end: + // contracts/stakingPool.algo.ts:365 + // cmpStaker = clone(this.stakers.value[i]) + frame_dig 1 // i: uint64 + int 64 + * // acc * typeLength + int 64 + byte 0x7374616b657273 // "stakers" + cover 2 + box_extract + frame_bury 2 // cmpStaker: (address,uint64,uint64,uint64,uint64) + + // *if14_condition + // contracts/stakingPool.algo.ts:366 + // cmpStaker.account === staker + frame_dig 2 // cmpStaker: (address,uint64,uint64,uint64,uint64) + extract 0 32 + frame_dig 0 // staker: address + == + bz *if14_end + + // *if14_consequent + // *if15_condition + // contracts/stakingPool.algo.ts:367 + // cmpStaker.rewardTokenBalance === 0 + frame_dig 2 // cmpStaker: (address,uint64,uint64,uint64,uint64) + extract 48 8 + btoi + int 0 + == + bz *if15_end + + // *if15_consequent + // contracts/stakingPool.algo.ts:368 + // return; + retsub + +*if15_end: + // contracts/stakingPool.algo.ts:370 + // amountRewardTokenRemoved = 0 + int 0 + frame_bury 3 // amountRewardTokenRemoved: uint64 + + // *if16_condition + // contracts/stakingPool.algo.ts:372 + // this.poolId.value === 1 + byte 0x706f6f6c4964 // "poolId" + app_global_get + int 1 + == + bz *if16_else + + // *if16_consequent + // contracts/stakingPool.algo.ts:373 + // validatorConfig = sendMethodCall({ + // applicationID: AppID.fromUint64(this.creatingValidatorContractAppId.value), + // methodArgs: [this.validatorId.value], + // }) + itxn_begin + int appl + itxn_field TypeEnum + method "getValidatorConfig(uint64)(uint64,address,address,uint64,uint8,byte[32],uint64,uint64,uint64,uint16,uint32,address,uint64,uint64,uint8,uint64,uint64)" + itxn_field ApplicationArgs + + // contracts/stakingPool.algo.ts:374 + // applicationID: AppID.fromUint64(this.creatingValidatorContractAppId.value) + byte 0x63726561746f72417070 // "creatorApp" + app_global_get + itxn_field ApplicationID + + // contracts/stakingPool.algo.ts:375 + // methodArgs: [this.validatorId.value] + byte 0x76616c696461746f724964 // "validatorId" + app_global_get + itob + itxn_field ApplicationArgs + + // Fee field not set, defaulting to 0 + int 0 + itxn_field Fee + + // Submit inner transaction + itxn_submit + itxn NumLogs + int 1 + - + itxnas Logs + extract 4 0 + frame_bury 4 // validatorConfig: (uint64,address,address,uint64,uint8,byte[32],uint64,uint64,uint64,uint16,uint32,address,uint64,uint64,uint8,uint64,uint64) + + // contracts/stakingPool.algo.ts:380 + // sendAssetTransfer({ + // xferAsset: AssetID.fromUint64(validatorConfig.rewardTokenId), + // assetReceiver: staker, + // assetAmount: cmpStaker.rewardTokenBalance, + // }) + itxn_begin + int axfer + itxn_field TypeEnum + + // contracts/stakingPool.algo.ts:381 + // xferAsset: AssetID.fromUint64(validatorConfig.rewardTokenId) + frame_dig 4 // validatorConfig: (uint64,address,address,uint64,uint8,byte[32],uint64,uint64,uint64,uint16,uint32,address,uint64,uint64,uint8,uint64,uint64) + extract 121 8 + btoi + itxn_field XferAsset + + // contracts/stakingPool.algo.ts:382 + // assetReceiver: staker + frame_dig 0 // staker: address + itxn_field AssetReceiver + + // contracts/stakingPool.algo.ts:383 + // assetAmount: cmpStaker.rewardTokenBalance + frame_dig 2 // cmpStaker: (address,uint64,uint64,uint64,uint64) + extract 48 8 + btoi + itxn_field AssetAmount + + // Fee field not set, defaulting to 0 + int 0 + itxn_field Fee + + // Submit inner transaction + itxn_submit + + // contracts/stakingPool.algo.ts:385 + // amountRewardTokenRemoved = cmpStaker.rewardTokenBalance + frame_dig 2 // cmpStaker: (address,uint64,uint64,uint64,uint64) + extract 48 8 + btoi + frame_bury 3 // amountRewardTokenRemoved: uint64 + + // contracts/stakingPool.algo.ts:386 + // cmpStaker.rewardTokenBalance = 0 + frame_dig 2 // cmpStaker: (address,uint64,uint64,uint64,uint64) + byte 0x0000000000000000 + replace2 48 + frame_bury 2 // cmpStaker: (address,uint64,uint64,uint64,uint64) + b *if16_end + +*if16_else: + // contracts/stakingPool.algo.ts:391 + // amountRewardTokenRemoved = cmpStaker.rewardTokenBalance + frame_dig 2 // cmpStaker: (address,uint64,uint64,uint64,uint64) + extract 48 8 + btoi + frame_bury 3 // amountRewardTokenRemoved: uint64 + + // contracts/stakingPool.algo.ts:392 + // cmpStaker.rewardTokenBalance = 0 + frame_dig 2 // cmpStaker: (address,uint64,uint64,uint64,uint64) + byte 0x0000000000000000 + replace2 48 + frame_bury 2 // cmpStaker: (address,uint64,uint64,uint64,uint64) + +*if16_end: + // contracts/stakingPool.algo.ts:396 + // this.stakers.value[i] = cmpStaker + frame_dig 1 // i: uint64 + int 64 + * // acc * typeLength + frame_dig 2 // cmpStaker: (address,uint64,uint64,uint64,uint64) + byte 0x7374616b657273 // "stakers" + cover 2 + box_replace + + // contracts/stakingPool.algo.ts:401 + // sendMethodCall({ + // applicationID: AppID.fromUint64(this.creatingValidatorContractAppId.value), + // methodArgs: [ + // { id: this.validatorId.value, poolId: this.poolId.value, poolAppId: this.app.id }, + // staker, + // 0, // no algo removed + // amountRewardTokenRemoved, + // false, // staker isn't being removed. + // ], + // }) + itxn_begin + int appl + itxn_field TypeEnum + method "stakeRemoved((uint64,uint64,uint64),address,uint64,uint64,bool)void" + itxn_field ApplicationArgs + + // contracts/stakingPool.algo.ts:402 + // applicationID: AppID.fromUint64(this.creatingValidatorContractAppId.value) + byte 0x63726561746f72417070 // "creatorApp" + app_global_get + itxn_field ApplicationID + + // contracts/stakingPool.algo.ts:403 + // methodArgs: [ + // { id: this.validatorId.value, poolId: this.poolId.value, poolAppId: this.app.id }, + // staker, + // 0, // no algo removed + // amountRewardTokenRemoved, + // false, // staker isn't being removed. + // ] + byte 0x76616c696461746f724964 // "validatorId" + app_global_get + itob + byte 0x706f6f6c4964 // "poolId" + app_global_get + itob + concat + txna Applications 0 + itob + concat + itxn_field ApplicationArgs + frame_dig 0 // staker: address + itxn_field ApplicationArgs + byte 0x0000000000000000 + itxn_field ApplicationArgs + frame_dig 3 // amountRewardTokenRemoved: uint64 + itob + itxn_field ApplicationArgs + int 0 + byte 0x00 + int 0 + uncover 2 + setbit + itxn_field ApplicationArgs + + // Fee field not set, defaulting to 0 + int 0 + itxn_field Fee + + // Submit inner transaction + itxn_submit + + // contracts/stakingPool.algo.ts:411 + // return; + retsub + +*if14_end: + +*for_2_continue: + // contracts/stakingPool.algo.ts:361 + // i += 1 + frame_dig 1 // i: uint64 + int 1 + + + frame_bury 1 // i: uint64 + b *for_2 + +*for_2_end: + err // 'account not found' + +// getStakerInfo(address)(address,uint64,uint64,uint64,uint64) +*abi_route_getStakerInfo: + // The ABI return prefix + byte 0x151f7c75 + + // staker: address + txna ApplicationArgs 1 + dup + len + int 32 + == + assert + + // execute getStakerInfo(address)(address,uint64,uint64,uint64,uint64) + callsub getStakerInfo + concat + log + int 1 + return + +// getStakerInfo(staker: Address): StakedInfo +// +// Retrieves the staked information for a given staker. +// +// @param {Address} staker - The address of the staker. +// @returns {StakedInfo} - The staked information for the given staker. +// @throws {Error} - If the staker's account is not found. +getStakerInfo: + proto 1 1 + + // Push empty bytes after the frame pointer to reserve space for local variables + byte 0x + + // contracts/stakingPool.algo.ts:426 + // for (let i = 0; i < this.stakers.value.length; i += 1) + int 0 + frame_bury 0 // i: uint64 + +*for_3: + // contracts/stakingPool.algo.ts:426 + // i < this.stakers.value.length + frame_dig 0 // i: uint64 + int 200 + < + bz *for_3_end + + // *if17_condition + // contracts/stakingPool.algo.ts:427 + // globals.opcodeBudget < 200 + global OpcodeBudget + int 200 + < + bz *if17_end + + // *if17_consequent + // contracts/stakingPool.algo.ts:428 + // increaseOpcodeBudget() + itxn_begin + int appl + itxn_field TypeEnum + int 0 + itxn_field Fee + byte b64 CoEB // #pragma version 10; int 1 + dup + itxn_field ApprovalProgram + itxn_field ClearStateProgram + int DeleteApplication + itxn_field OnCompletion + itxn_submit + +*if17_end: + // *if18_condition + // contracts/stakingPool.algo.ts:430 + // this.stakers.value[i].account === staker + frame_dig 0 // i: uint64 + int 64 + * // acc * typeLength + int 0 + + + int 32 + byte 0x7374616b657273 // "stakers" + cover 2 + box_extract + frame_dig -1 // staker: Address + == + bz *if18_end + + // *if18_consequent + // contracts/stakingPool.algo.ts:431 + // return this.stakers.value[i]; + frame_dig 0 // i: uint64 + int 64 + * // acc * typeLength + int 64 + byte 0x7374616b657273 // "stakers" + cover 2 + box_extract + + // set the subroutine return value + frame_bury 0 + retsub + +*if18_end: + +*for_3_continue: + // contracts/stakingPool.algo.ts:426 + // i += 1 + frame_dig 0 // i: uint64 + int 1 + + + frame_bury 0 // i: uint64 + b *for_3 + +*for_3_end: + err // 'account not found' + +// payTokenReward(address,uint64,uint64)void +*abi_route_payTokenReward: + // amountToSend: uint64 + txna ApplicationArgs 3 + btoi + + // rewardToken: uint64 + txna ApplicationArgs 2 + btoi + + // staker: address + txna ApplicationArgs 1 + dup + len + int 32 + == + assert + + // execute payTokenReward(address,uint64,uint64)void + callsub payTokenReward + int 1 + return + +// payTokenReward(staker: Address, rewardToken: uint64, amountToSend: uint64): void +// +// [Internal protocol method] Remove a specified amount of 'community token' rewards for a staker. +// This can ONLY be called by our validator and only if we're pool 1 - with the token. +// @param staker - the staker account to send rewards to +// @param rewardToken - id of reward token (to avoid re-entrancy in calling validator back to get id) +// @param amountToSend - amount to send the staker (there is significant trust here(!) - also why only validator can call us +payTokenReward: + proto 3 0 + + // contracts/stakingPool.algo.ts:446 + // assert(this.txn.sender === AppID.fromUint64(this.creatingValidatorContractAppId.value).address) + txn Sender + byte 0x63726561746f72417070 // "creatorApp" + app_global_get + app_params_get AppAddress + pop + == + assert + + // contracts/stakingPool.algo.ts:447 + // assert(this.poolId.value === 1, 'must be pool 1 in order to be called to pay out token rewards') + byte 0x706f6f6c4964 // "poolId" + app_global_get + int 1 + == + + // must be pool 1 in order to be called to pay out token rewards + assert + + // contracts/stakingPool.algo.ts:448 + // assert(rewardToken !== 0, 'can only claim token rewards from validator that has them') + frame_dig -2 // rewardToken: uint64 + int 0 + != + + // can only claim token rewards from validator that has them + assert + + // contracts/stakingPool.algo.ts:451 + // sendAssetTransfer({ + // xferAsset: AssetID.fromUint64(rewardToken), + // assetReceiver: staker, + // assetAmount: amountToSend, + // }) + itxn_begin + int axfer + itxn_field TypeEnum + + // contracts/stakingPool.algo.ts:452 + // xferAsset: AssetID.fromUint64(rewardToken) + frame_dig -2 // rewardToken: uint64 + itxn_field XferAsset + + // contracts/stakingPool.algo.ts:453 + // assetReceiver: staker + frame_dig -1 // staker: Address + itxn_field AssetReceiver + + // contracts/stakingPool.algo.ts:454 + // assetAmount: amountToSend + frame_dig -3 // amountToSend: uint64 + itxn_field AssetAmount + + // Fee field not set, defaulting to 0 + int 0 + itxn_field Fee + + // Submit inner transaction + itxn_submit + retsub + +// updateAlgodVer(string)void +*abi_route_updateAlgodVer: + // algodVer: string + txna ApplicationArgs 1 + extract 2 0 + + // execute updateAlgodVer(string)void + callsub updateAlgodVer + int 1 + return + +// updateAlgodVer(algodVer: string): void +// +// Update the (honor system) algod version for the node associated to this pool. The node management daemon +// should compare its current nodes version to the version stored in global state, updating when different. +// The reti node daemon composes its own version string using format: +// {major}.{minor}.{build} {branch} [{commit hash}], +// ie: 3.22.0 rel/stable [6b508975] +// [ ONLY OWNER OR MANAGER CAN CALL ] +// @param {string} algodVer - string representing the algorand node daemon version (reti node daemon composes its own meta version) +updateAlgodVer: + proto 1 0 + + // contracts/stakingPool.algo.ts:468 + // assert(this.isOwnerOrManagerCaller()) + callsub isOwnerOrManagerCaller + assert + + // contracts/stakingPool.algo.ts:469 + // this.algodVer.value = algodVer + byte 0x616c676f64566572 // "algodVer" + frame_dig -1 // algodVer: string + app_global_put + retsub + +// epochBalanceUpdate()void +*abi_route_epochBalanceUpdate: + // execute epochBalanceUpdate()void + callsub epochBalanceUpdate + int 1 + return + +// epochBalanceUpdate(): void +// +// Updates the balance of stakers in the pool based on the received 'rewards' (current balance vs known staked balance) +// stakers outstanding balance is adjusted based on their % of stake and time in the current epoch - so that balance +// compounds over time and staker can remove that amount at will. +// The validator is paid their percentage each epoch payout. +// +// Note: ANYONE can call this. +epochBalanceUpdate: + proto 0 0 + + // Push empty bytes after the frame pointer to reserve space for local variables + byte 0x + dupn 33 + + // contracts/stakingPool.algo.ts:482 + // validatorConfig = sendMethodCall({ + // applicationID: AppID.fromUint64(this.creatingValidatorContractAppId.value), + // methodArgs: [this.validatorId.value], + // }) + itxn_begin + int appl + itxn_field TypeEnum + method "getValidatorConfig(uint64)(uint64,address,address,uint64,uint8,byte[32],uint64,uint64,uint64,uint16,uint32,address,uint64,uint64,uint8,uint64,uint64)" + itxn_field ApplicationArgs + + // contracts/stakingPool.algo.ts:483 + // applicationID: AppID.fromUint64(this.creatingValidatorContractAppId.value) + byte 0x63726561746f72417070 // "creatorApp" + app_global_get + itxn_field ApplicationID + + // contracts/stakingPool.algo.ts:484 + // methodArgs: [this.validatorId.value] + byte 0x76616c696461746f724964 // "validatorId" + app_global_get + itob + itxn_field ApplicationArgs + + // Fee field not set, defaulting to 0 + int 0 + itxn_field Fee + + // Submit inner transaction + itxn_submit + itxn NumLogs + int 1 + - + itxnas Logs + extract 4 0 + frame_bury 0 // validatorConfig: (uint64,address,address,uint64,uint8,byte[32],uint64,uint64,uint64,uint16,uint32,address,uint64,uint64,uint8,uint64,uint64) + + // contracts/stakingPool.algo.ts:492 + // curTime = globals.latestTimestamp + global LatestTimestamp + frame_bury 1 // curTime: uint64 + + // contracts/stakingPool.algo.ts:494 + // epochInSecs = (validatorConfig.payoutEveryXMins as uint64) * 60 + frame_dig 0 // validatorConfig: (uint64,address,address,uint64,uint8,byte[32],uint64,uint64,uint64,uint16,uint32,address,uint64,uint64,uint8,uint64,uint64) + extract 137 2 + btoi + int 60 + * + frame_bury 2 // epochInSecs: uint64 + + // *if19_condition + // contracts/stakingPool.algo.ts:495 + // this.lastPayout.exists + txna Applications 0 + byte 0x6c6173745061796f7574 // "lastPayout" + app_global_get_ex + swap + pop + bz *if19_end + + // *if19_consequent + // contracts/stakingPool.algo.ts:496 + // secsSinceLastPayout = curTime - this.lastPayout.value + frame_dig 1 // curTime: uint64 + byte 0x6c6173745061796f7574 // "lastPayout" + app_global_get + - + frame_bury 3 // secsSinceLastPayout: uint64 + + // contracts/stakingPool.algo.ts:497 + // log(concat('secs since last payout: %i', itob(secsSinceLastPayout))) + byte 0x736563732073696e6365206c617374207061796f75743a202569 // "secs since last payout: %i" + frame_dig 3 // secsSinceLastPayout: uint64 + itob + concat + log + + // contracts/stakingPool.algo.ts:500 + // assert(secsSinceLastPayout >= epochInSecs, "Can't payout earlier than last payout + epoch time") + frame_dig 3 // secsSinceLastPayout: uint64 + frame_dig 2 // epochInSecs: uint64 + >= + + // Can't payout earlier than last payout + epoch time + assert + +*if19_end: + // contracts/stakingPool.algo.ts:503 + // this.lastPayout.value = curTime + byte 0x6c6173745061796f7574 // "lastPayout" + frame_dig 1 // curTime: uint64 + app_global_put + + // contracts/stakingPool.algo.ts:504 + // this.epochNumber.value += 1 + byte 0x65706f63684e756d626572 // "epochNumber" + app_global_get + int 1 + + + byte 0x65706f63684e756d626572 // "epochNumber" + swap + app_global_put + + // contracts/stakingPool.algo.ts:509 + // isTokenEligible = validatorConfig.rewardTokenId !== 0 + frame_dig 0 // validatorConfig: (uint64,address,address,uint64,uint8,byte[32],uint64,uint64,uint64,uint16,uint32,address,uint64,uint64,uint8,uint64,uint64) + extract 121 8 + btoi + int 0 + != + frame_bury 4 // isTokenEligible: bool + + // contracts/stakingPool.algo.ts:510 + // poolOneAppID = this.app.id + txna Applications 0 + frame_bury 5 // poolOneAppID: uint64 + + // contracts/stakingPool.algo.ts:511 + // poolOneAddress = this.app.address + global CurrentApplicationAddress + frame_bury 6 // poolOneAddress: address + + // *if20_condition + // contracts/stakingPool.algo.ts:516 + // isTokenEligible + frame_dig 4 // isTokenEligible: bool + bz *if20_end + + // *if20_consequent + // *if21_condition + // contracts/stakingPool.algo.ts:517 + // this.poolId.value !== 1 + byte 0x706f6f6c4964 // "poolId" + app_global_get + int 1 + != + bz *if21_end + + // *if21_consequent + // contracts/stakingPool.algo.ts:519 + // poolOneAppID = sendMethodCall({ + // applicationID: AppID.fromUint64(this.creatingValidatorContractAppId.value), + // methodArgs: [this.validatorId.value, 1], + // }) + itxn_begin + int appl + itxn_field TypeEnum + method "getPoolAppId(uint64,uint64)uint64" + itxn_field ApplicationArgs + + // contracts/stakingPool.algo.ts:520 + // applicationID: AppID.fromUint64(this.creatingValidatorContractAppId.value) + byte 0x63726561746f72417070 // "creatorApp" + app_global_get + itxn_field ApplicationID + + // contracts/stakingPool.algo.ts:521 + // methodArgs: [this.validatorId.value, 1] + byte 0x76616c696461746f724964 // "validatorId" + app_global_get + itob + itxn_field ApplicationArgs + byte 0x0000000000000001 + itxn_field ApplicationArgs + + // Fee field not set, defaulting to 0 + int 0 + itxn_field Fee + + // Submit inner transaction + itxn_submit + itxn NumLogs + int 1 + - + itxnas Logs + extract 4 0 + btoi + frame_bury 5 // poolOneAppID: uint64 + + // contracts/stakingPool.algo.ts:523 + // poolOneAddress = AppID.fromUint64(poolOneAppID).address + frame_dig 5 // poolOneAppID: uint64 + app_params_get AppAddress + pop + frame_bury 6 // poolOneAddress: address + +*if21_end: + // *if22_condition + // contracts/stakingPool.algo.ts:528 + // this.poolId.value === 1 + byte 0x706f6f6c4964 // "poolId" + app_global_get + int 1 + == + bz *if22_else + + // *if22_consequent + // contracts/stakingPool.algo.ts:529 + // tokenPayoutRatio = sendMethodCall({ + // applicationID: AppID.fromUint64(this.creatingValidatorContractAppId.value), + // methodArgs: [this.validatorId.value], + // }) + itxn_begin + int appl + itxn_field TypeEnum + method "setTokenPayoutRatio(uint64)(uint64[24],uint64)" + itxn_field ApplicationArgs + + // contracts/stakingPool.algo.ts:530 + // applicationID: AppID.fromUint64(this.creatingValidatorContractAppId.value) + byte 0x63726561746f72417070 // "creatorApp" + app_global_get + itxn_field ApplicationID + + // contracts/stakingPool.algo.ts:531 + // methodArgs: [this.validatorId.value] + byte 0x76616c696461746f724964 // "validatorId" + app_global_get + itob + itxn_field ApplicationArgs + + // Fee field not set, defaulting to 0 + int 0 + itxn_field Fee + + // Submit inner transaction + itxn_submit + itxn NumLogs + int 1 + - + itxnas Logs + extract 4 0 + frame_bury 7 // tokenPayoutRatio: PoolTokenPayoutRatio + b *if22_end + +*if22_else: + // contracts/stakingPool.algo.ts:535 + // tokenPayoutRatio = sendMethodCall({ + // applicationID: AppID.fromUint64(poolOneAppID), + // methodArgs: [{ id: this.validatorId.value, poolId: this.poolId.value, poolAppId: this.app.id }], + // }) + itxn_begin + int appl + itxn_field TypeEnum + method "proxiedSetTokenPayoutRatio((uint64,uint64,uint64))(uint64[24],uint64)" + itxn_field ApplicationArgs + + // contracts/stakingPool.algo.ts:536 + // applicationID: AppID.fromUint64(poolOneAppID) + frame_dig 5 // poolOneAppID: uint64 + itxn_field ApplicationID + + // contracts/stakingPool.algo.ts:537 + // methodArgs: [{ id: this.validatorId.value, poolId: this.poolId.value, poolAppId: this.app.id }] + byte 0x76616c696461746f724964 // "validatorId" + app_global_get + itob + byte 0x706f6f6c4964 // "poolId" + app_global_get + itob + concat + txna Applications 0 + itob + concat + itxn_field ApplicationArgs + + // Fee field not set, defaulting to 0 + int 0 + itxn_field Fee + + // Submit inner transaction + itxn_submit + itxn NumLogs + int 1 + - + itxnas Logs + extract 4 0 + frame_bury 7 // tokenPayoutRatio: PoolTokenPayoutRatio + +*if22_end: + +*if20_end: + // contracts/stakingPool.algo.ts:544 + // validatorState = sendMethodCall({ + // applicationID: AppID.fromUint64(this.creatingValidatorContractAppId.value), + // methodArgs: [this.validatorId.value], + // }) + itxn_begin + int appl + itxn_field TypeEnum + method "getValidatorState(uint64)(uint16,uint64,uint64,uint64)" + itxn_field ApplicationArgs + + // contracts/stakingPool.algo.ts:545 + // applicationID: AppID.fromUint64(this.creatingValidatorContractAppId.value) + byte 0x63726561746f72417070 // "creatorApp" + app_global_get + itxn_field ApplicationID + + // contracts/stakingPool.algo.ts:546 + // methodArgs: [this.validatorId.value] + byte 0x76616c696461746f724964 // "validatorId" + app_global_get + itob + itxn_field ApplicationArgs + + // Fee field not set, defaulting to 0 + int 0 + itxn_field Fee + + // Submit inner transaction + itxn_submit + itxn NumLogs + int 1 + - + itxnas Logs + extract 4 0 + frame_bury 8 // validatorState: (uint16,uint64,uint64,uint64) + + // contracts/stakingPool.algo.ts:548 + // rewardTokenHeldBack = validatorState.rewardTokenHeldBack + frame_dig 8 // validatorState: (uint16,uint64,uint64,uint64) + extract 18 8 + btoi + frame_bury 9 // rewardTokenHeldBack: uint64 + + // contracts/stakingPool.algo.ts:554 + // algoRewardAvail = this.app.address.balance - this.totalAlgoStaked.value - this.app.address.minBalance + global CurrentApplicationAddress + acct_params_get AcctBalance + pop + byte 0x7374616b6564 // "staked" + app_global_get + - + global CurrentApplicationAddress + acct_params_get AcctMinBalance + pop + - + frame_bury 10 // algoRewardAvail: uint64 + + // contracts/stakingPool.algo.ts:555 + // isPoolSaturated = false + int 0 + frame_bury 11 // isPoolSaturated: bool + + // contracts/stakingPool.algo.ts:556 + // algoSaturationAmt = this.algoSaturationLevel() + callsub algoSaturationLevel + frame_bury 12 // algoSaturationAmt: uint64 + + // *if23_condition + // contracts/stakingPool.algo.ts:564 + // validatorState.totalAlgoStaked > algoSaturationAmt + frame_dig 8 // validatorState: (uint16,uint64,uint64,uint64) + extract 10 8 + btoi + frame_dig 12 // algoSaturationAmt: uint64 + > + bz *if23_end + + // *if23_consequent + // contracts/stakingPool.algo.ts:565 + // log('validator in saturated state') + byte 0x76616c696461746f7220696e20736174757261746564207374617465 // "validator in saturated state" + log + + // contracts/stakingPool.algo.ts:566 + // isPoolSaturated = true + int 1 + frame_bury 11 // isPoolSaturated: bool + +*if23_end: + // contracts/stakingPool.algo.ts:572 + // tokenRewardAvail = 0 + int 0 + frame_bury 13 // tokenRewardAvail: uint64 + + // contracts/stakingPool.algo.ts:573 + // tokenRewardPaidOut = 0 + int 0 + frame_bury 14 // tokenRewardPaidOut: uint64 + + // *if24_condition + // contracts/stakingPool.algo.ts:574 + // isTokenEligible + frame_dig 4 // isTokenEligible: bool + bz *if24_end + + // *if24_consequent + // contracts/stakingPool.algo.ts:575 + // tokenRewardBal = + // poolOneAddress.assetBalance(AssetID.fromUint64(validatorConfig.rewardTokenId)) - rewardTokenHeldBack + frame_dig 6 // poolOneAddress: address + frame_dig 0 // validatorConfig: (uint64,address,address,uint64,uint8,byte[32],uint64,uint64,uint64,uint16,uint32,address,uint64,uint64,uint8,uint64,uint64) + extract 121 8 + btoi + asset_holding_get AssetBalance + pop + frame_dig 9 // rewardTokenHeldBack: uint64 + - + frame_bury 15 // tokenRewardBal: uint64 + + // *if25_condition + // contracts/stakingPool.algo.ts:580 + // tokenRewardBal >= validatorConfig.rewardPerPayout + frame_dig 15 // tokenRewardBal: uint64 + frame_dig 0 // validatorConfig: (uint64,address,address,uint64,uint8,byte[32],uint64,uint64,uint64,uint16,uint32,address,uint64,uint64,uint8,uint64,uint64) + extract 129 8 + btoi + >= + bz *if25_end + + // *if25_consequent + // contracts/stakingPool.algo.ts:584 + // ourPoolPctOfWhole = tokenPayoutRatio.poolPctOfWhole[this.poolId.value - 1] + frame_dig 7 // tokenPayoutRatio: PoolTokenPayoutRatio + int 0 + byte 0x706f6f6c4964 // "poolId" + app_global_get + int 1 + - + int 8 + * // acc * typeLength + + + int 8 + extract3 + btoi + frame_bury 16 // ourPoolPctOfWhole: uint64 + + // contracts/stakingPool.algo.ts:587 + // tokenRewardAvail = wideRatio([validatorConfig.rewardPerPayout, ourPoolPctOfWhole], [1_000_000]) + frame_dig 0 // validatorConfig: (uint64,address,address,uint64,uint8,byte[32],uint64,uint64,uint64,uint16,uint32,address,uint64,uint64,uint8,uint64,uint64) + extract 129 8 + btoi + frame_dig 16 // ourPoolPctOfWhole: uint64 + mulw + int 0 + int 1_000_000 + divmodw + pop + pop + swap + ! + assert + frame_bury 13 // tokenRewardAvail: uint64 + + // contracts/stakingPool.algo.ts:591 + // log(concat('token reward avail: ', tokenRewardAvail.toString())) + byte 0x746f6b656e2072657761726420617661696c3a20 // "token reward avail: " + frame_dig 13 // tokenRewardAvail: uint64 + callsub *itoa + concat + log + +*if25_end: + +*if24_end: + // *if26_condition + // contracts/stakingPool.algo.ts:595 + // tokenRewardAvail === 0 + frame_dig 13 // tokenRewardAvail: uint64 + int 0 + == + bz *if26_end + + // *if26_consequent + // contracts/stakingPool.algo.ts:598 + // assert(algoRewardAvail > 1_000_000, 'Reward needs to be at least 1 ALGO') + frame_dig 10 // algoRewardAvail: uint64 + int 1_000_000 + > + + // Reward needs to be at least 1 ALGO + assert + +*if26_end: + // contracts/stakingPool.algo.ts:600 + // log(concat('algo reward avail: ', algoRewardAvail.toString())) + byte 0x616c676f2072657761726420617661696c3a20 // "algo reward avail: " + frame_dig 10 // algoRewardAvail: uint64 + callsub *itoa + concat + log + + // *if27_condition + // contracts/stakingPool.algo.ts:603 + // isPoolSaturated + frame_dig 11 // isPoolSaturated: bool + bz *if27_elseif1_condition + + // *if27_consequent + // contracts/stakingPool.algo.ts:606 + // diminishedReward = wideRatio([algoRewardAvail, algoSaturationAmt], [validatorState.totalAlgoStaked]) + frame_dig 10 // algoRewardAvail: uint64 + frame_dig 12 // algoSaturationAmt: uint64 + mulw + int 0 + frame_dig 8 // validatorState: (uint16,uint64,uint64,uint64) + extract 10 8 + btoi + divmodw + pop + pop + swap + ! + assert + frame_bury 17 // diminishedReward: uint64 + + // contracts/stakingPool.algo.ts:608 + // excessToFeeSink = algoRewardAvail - diminishedReward + frame_dig 10 // algoRewardAvail: uint64 + frame_dig 17 // diminishedReward: uint64 + - + frame_bury 18 // excessToFeeSink: uint64 + + // contracts/stakingPool.algo.ts:609 + // increaseOpcodeBudget() + itxn_begin + int appl + itxn_field TypeEnum + int 0 + itxn_field Fee + byte b64 CoEB // #pragma version 10; int 1 + dup + itxn_field ApprovalProgram + itxn_field ClearStateProgram + int DeleteApplication + itxn_field OnCompletion + itxn_submit + + // contracts/stakingPool.algo.ts:610 + // log(concat('dim rwd: ', diminishedReward.toString())) + byte 0x64696d207277643a20 // "dim rwd: " + frame_dig 17 // diminishedReward: uint64 + callsub *itoa + concat + log + + // contracts/stakingPool.algo.ts:611 + // log(concat('to sink: ', excessToFeeSink.toString())) + byte 0x746f2073696e6b3a20 // "to sink: " + frame_dig 18 // excessToFeeSink: uint64 + callsub *itoa + concat + log + + // contracts/stakingPool.algo.ts:612 + // sendPayment({ + // amount: excessToFeeSink, + // receiver: this.getFeeSink(), + // note: 'pool saturated, portion sent back to fee sink', + // }) + itxn_begin + int pay + itxn_field TypeEnum + + // contracts/stakingPool.algo.ts:613 + // amount: excessToFeeSink + frame_dig 18 // excessToFeeSink: uint64 + itxn_field Amount + + // contracts/stakingPool.algo.ts:614 + // receiver: this.getFeeSink() + callsub getFeeSink + itxn_field Receiver + + // contracts/stakingPool.algo.ts:615 + // note: 'pool saturated, portion sent back to fee sink' + byte 0x706f6f6c207361747572617465642c20706f7274696f6e2073656e74206261636b20746f206665652073696e6b // "pool saturated, portion sent back to fee sink" + itxn_field Note + + // Fee field not set, defaulting to 0 + int 0 + itxn_field Fee + + // Submit inner transaction + itxn_submit + + // contracts/stakingPool.algo.ts:618 + // algoRewardAvail = diminishedReward + frame_dig 17 // diminishedReward: uint64 + frame_bury 10 // algoRewardAvail: uint64 + b *if27_end + +*if27_elseif1_condition: + // contracts/stakingPool.algo.ts:619 + // validatorConfig.percentToValidator !== 0 + frame_dig 0 // validatorConfig: (uint64,address,address,uint64,uint8,byte[32],uint64,uint64,uint64,uint16,uint32,address,uint64,uint64,uint8,uint64,uint64) + extract 139 4 + btoi + int 0 + != + bz *if27_end + + // *if27_elseif1_consequent + // contracts/stakingPool.algo.ts:622 + // validatorPay = wideRatio( + // [algoRewardAvail, validatorConfig.percentToValidator as uint64], + // [1_000_000] + // ) + frame_dig 10 // algoRewardAvail: uint64 + frame_dig 0 // validatorConfig: (uint64,address,address,uint64,uint8,byte[32],uint64,uint64,uint64,uint16,uint32,address,uint64,uint64,uint8,uint64,uint64) + extract 139 4 + btoi + mulw + int 0 + int 1_000_000 + divmodw + pop + pop + swap + ! + assert + frame_bury 19 // validatorPay: uint64 + + // contracts/stakingPool.algo.ts:628 + // algoRewardAvail -= validatorPay + frame_dig 10 // algoRewardAvail: uint64 + frame_dig 19 // validatorPay: uint64 + - + frame_bury 10 // algoRewardAvail: uint64 + + // *if28_condition + // contracts/stakingPool.algo.ts:632 + // validatorPay > 0 + frame_dig 19 // validatorPay: uint64 + int 0 + > + bz *if28_end + + // *if28_consequent + // contracts/stakingPool.algo.ts:633 + // log(concat('paying validator: %i', itob(validatorPay))) + byte 0x706179696e672076616c696461746f723a202569 // "paying validator: %i" + frame_dig 19 // validatorPay: uint64 + itob + concat + log + + // contracts/stakingPool.algo.ts:634 + // sendPayment({ + // amount: validatorPay, + // receiver: validatorConfig.validatorCommissionAddress, + // note: 'validator reward', + // }) + itxn_begin + int pay + itxn_field TypeEnum + + // contracts/stakingPool.algo.ts:635 + // amount: validatorPay + frame_dig 19 // validatorPay: uint64 + itxn_field Amount + + // contracts/stakingPool.algo.ts:636 + // receiver: validatorConfig.validatorCommissionAddress + frame_dig 0 // validatorConfig: (uint64,address,address,uint64,uint8,byte[32],uint64,uint64,uint64,uint16,uint32,address,uint64,uint64,uint8,uint64,uint64) + extract 143 32 + itxn_field Receiver + + // contracts/stakingPool.algo.ts:637 + // note: 'validator reward' + byte 0x76616c696461746f7220726577617264 // "validator reward" + itxn_field Note + + // Fee field not set, defaulting to 0 + int 0 + itxn_field Fee + + // Submit inner transaction + itxn_submit + + // contracts/stakingPool.algo.ts:639 + // log(concat('remaining reward: %i', itob(algoRewardAvail))) + byte 0x72656d61696e696e67207265776172643a202569 // "remaining reward: %i" + frame_dig 10 // algoRewardAvail: uint64 + itob + concat + log + +*if28_end: + +*if27_end: + // *if29_condition + // contracts/stakingPool.algo.ts:643 + // algoRewardAvail === 0 && tokenRewardAvail === 0 + frame_dig 10 // algoRewardAvail: uint64 + int 0 + == + dup + bz *skip_and3 + frame_dig 13 // tokenRewardAvail: uint64 + int 0 + == + && + +*skip_and3: + bz *if29_end + + // *if29_consequent + // contracts/stakingPool.algo.ts:646 + // return; + retsub + +*if29_end: + // contracts/stakingPool.algo.ts:654 + // increasedStake = 0 + int 0 + frame_bury 20 // increasedStake: uint64 + + // contracts/stakingPool.algo.ts:678 + // partialStakersTotalStake: uint64 = 0 + int 0 + frame_bury 21 // partialStakersTotalStake: uint64 + + // contracts/stakingPool.algo.ts:679 + // for (let i = 0; i < this.stakers.value.length; i += 1) + int 0 + frame_bury 22 // i: uint64 + +*for_4: + // contracts/stakingPool.algo.ts:679 + // i < this.stakers.value.length + frame_dig 22 // i: uint64 + int 200 + < + bz *for_4_end + + // *if30_condition + // contracts/stakingPool.algo.ts:680 + // globals.opcodeBudget < 400 + global OpcodeBudget + int 400 + < + bz *if30_end + + // *if30_consequent + // contracts/stakingPool.algo.ts:681 + // increaseOpcodeBudget() + itxn_begin + int appl + itxn_field TypeEnum + int 0 + itxn_field Fee + byte b64 CoEB // #pragma version 10; int 1 + dup + itxn_field ApprovalProgram + itxn_field ClearStateProgram + int DeleteApplication + itxn_field OnCompletion + itxn_submit + +*if30_end: + // contracts/stakingPool.algo.ts:683 + // cmpStaker = clone(this.stakers.value[i]) + frame_dig 22 // i: uint64 + int 64 + * // acc * typeLength + int 64 + byte 0x7374616b657273 // "stakers" + cover 2 + box_extract + frame_bury 23 // cmpStaker: (address,uint64,uint64,uint64,uint64) + + // *if31_condition + // contracts/stakingPool.algo.ts:684 + // cmpStaker.account !== globals.zeroAddress + frame_dig 23 // cmpStaker: (address,uint64,uint64,uint64,uint64) + extract 0 32 + global ZeroAddress + != + bz *if31_end + + // *if31_consequent + // *if32_condition + // contracts/stakingPool.algo.ts:685 + // cmpStaker.entryTime > curTime + frame_dig 23 // cmpStaker: (address,uint64,uint64,uint64,uint64) + extract 56 8 + btoi + frame_dig 1 // curTime: uint64 + > + bz *if32_else + + // *if32_consequent + // contracts/stakingPool.algo.ts:688 + // partialStakersTotalStake += cmpStaker.balance + frame_dig 21 // partialStakersTotalStake: uint64 + frame_dig 23 // cmpStaker: (address,uint64,uint64,uint64,uint64) + extract 32 8 + btoi + + + frame_bury 21 // partialStakersTotalStake: uint64 + b *if32_end + +*if32_else: + // contracts/stakingPool.algo.ts:692 + // timeInPool = curTime - cmpStaker.entryTime + frame_dig 1 // curTime: uint64 + frame_dig 23 // cmpStaker: (address,uint64,uint64,uint64,uint64) + extract 56 8 + btoi + - + frame_bury 24 // timeInPool: uint64 + + // *if33_condition + // contracts/stakingPool.algo.ts:696 + // timeInPool < epochInSecs + frame_dig 24 // timeInPool: uint64 + frame_dig 2 // epochInSecs: uint64 + < + bz *if33_end + + // *if33_consequent + // contracts/stakingPool.algo.ts:697 + // partialStakersTotalStake += cmpStaker.balance + frame_dig 21 // partialStakersTotalStake: uint64 + frame_dig 23 // cmpStaker: (address,uint64,uint64,uint64,uint64) + extract 32 8 + btoi + + + frame_bury 21 // partialStakersTotalStake: uint64 + + // contracts/stakingPool.algo.ts:698 + // timePercentage = (timeInPool * 1000) / epochInSecs + frame_dig 24 // timeInPool: uint64 + int 1000 + * + frame_dig 2 // epochInSecs: uint64 + / + frame_bury 25 // timePercentage: uint64 + + // *if34_condition + // contracts/stakingPool.algo.ts:701 + // tokenRewardAvail > 0 + frame_dig 13 // tokenRewardAvail: uint64 + int 0 + > + bz *if34_end + + // *if34_consequent + // contracts/stakingPool.algo.ts:703 + // stakerTokenReward = wideRatio( + // [cmpStaker.balance, tokenRewardAvail, timePercentage], + // [this.totalAlgoStaked.value, 1000] + // ) + frame_dig 23 // cmpStaker: (address,uint64,uint64,uint64,uint64) + extract 32 8 + btoi + frame_dig 13 // tokenRewardAvail: uint64 + mulw + frame_dig 25 // timePercentage: uint64 + uncover 2 + dig 1 + * + cover 2 + mulw + cover 2 + + + swap + byte 0x7374616b6564 // "staked" + app_global_get + int 1000 + mulw + divmodw + pop + pop + swap + ! + assert + frame_bury 26 // stakerTokenReward: uint64 + + // contracts/stakingPool.algo.ts:710 + // tokenRewardAvail -= stakerTokenReward + frame_dig 13 // tokenRewardAvail: uint64 + frame_dig 26 // stakerTokenReward: uint64 + - + frame_bury 13 // tokenRewardAvail: uint64 + + // contracts/stakingPool.algo.ts:711 + // cmpStaker.rewardTokenBalance += stakerTokenReward + frame_dig 23 // cmpStaker: (address,uint64,uint64,uint64,uint64) + int 48 // headOffset + frame_dig 23 // cmpStaker: (address,uint64,uint64,uint64,uint64) + extract 48 8 + btoi + frame_dig 26 // stakerTokenReward: uint64 + + + itob + replace3 + frame_bury 23 // cmpStaker: (address,uint64,uint64,uint64,uint64) + + // contracts/stakingPool.algo.ts:712 + // tokenRewardPaidOut += stakerTokenReward + frame_dig 14 // tokenRewardPaidOut: uint64 + frame_dig 26 // stakerTokenReward: uint64 + + + frame_bury 14 // tokenRewardPaidOut: uint64 + +*if34_end: + // *if35_condition + // contracts/stakingPool.algo.ts:714 + // algoRewardAvail > 0 + frame_dig 10 // algoRewardAvail: uint64 + int 0 + > + bz *if35_end + + // *if35_consequent + // contracts/stakingPool.algo.ts:716 + // stakerReward = wideRatio( + // [cmpStaker.balance, algoRewardAvail, timePercentage], + // [this.totalAlgoStaked.value, 1000] + // ) + frame_dig 23 // cmpStaker: (address,uint64,uint64,uint64,uint64) + extract 32 8 + btoi + frame_dig 10 // algoRewardAvail: uint64 + mulw + frame_dig 25 // timePercentage: uint64 + uncover 2 + dig 1 + * + cover 2 + mulw + cover 2 + + + swap + byte 0x7374616b6564 // "staked" + app_global_get + int 1000 + mulw + divmodw + pop + pop + swap + ! + assert + frame_bury 27 // stakerReward: uint64 + + // contracts/stakingPool.algo.ts:723 + // algoRewardAvail -= stakerReward + frame_dig 10 // algoRewardAvail: uint64 + frame_dig 27 // stakerReward: uint64 + - + frame_bury 10 // algoRewardAvail: uint64 + + // contracts/stakingPool.algo.ts:726 + // cmpStaker.balance += stakerReward + frame_dig 23 // cmpStaker: (address,uint64,uint64,uint64,uint64) + int 32 // headOffset + frame_dig 23 // cmpStaker: (address,uint64,uint64,uint64,uint64) + extract 32 8 + btoi + frame_dig 27 // stakerReward: uint64 + + + itob + replace3 + frame_bury 23 // cmpStaker: (address,uint64,uint64,uint64,uint64) + + // contracts/stakingPool.algo.ts:727 + // cmpStaker.totalRewarded += stakerReward + frame_dig 23 // cmpStaker: (address,uint64,uint64,uint64,uint64) + int 40 // headOffset + frame_dig 23 // cmpStaker: (address,uint64,uint64,uint64,uint64) + extract 40 8 + btoi + frame_dig 27 // stakerReward: uint64 + + + itob + replace3 + frame_bury 23 // cmpStaker: (address,uint64,uint64,uint64,uint64) + + // contracts/stakingPool.algo.ts:728 + // increasedStake += stakerReward + frame_dig 20 // increasedStake: uint64 + frame_dig 27 // stakerReward: uint64 + + + frame_bury 20 // increasedStake: uint64 + +*if35_end: + // contracts/stakingPool.algo.ts:731 + // this.stakers.value[i] = cmpStaker + frame_dig 22 // i: uint64 + int 64 + * // acc * typeLength + frame_dig 23 // cmpStaker: (address,uint64,uint64,uint64,uint64) + byte 0x7374616b657273 // "stakers" + cover 2 + box_replace + +*if33_end: + +*if32_end: + +*if31_end: + +*for_4_continue: + // contracts/stakingPool.algo.ts:679 + // i += 1 + frame_dig 22 // i: uint64 + int 1 + + + frame_bury 22 // i: uint64 + b *for_4 + +*for_4_end: + // contracts/stakingPool.algo.ts:736 + // log(concat('partial staker total stake: %i', itob(partialStakersTotalStake))) + byte 0x7061727469616c207374616b657220746f74616c207374616b653a202569 // "partial staker total stake: %i" + frame_dig 21 // partialStakersTotalStake: uint64 + itob + concat + log + + // contracts/stakingPool.algo.ts:740 + // newPoolTotalStake = this.totalAlgoStaked.value - partialStakersTotalStake + byte 0x7374616b6564 // "staked" + app_global_get + frame_dig 21 // partialStakersTotalStake: uint64 + - + frame_bury 28 // newPoolTotalStake: uint64 + + // *if36_condition + // contracts/stakingPool.algo.ts:744 + // newPoolTotalStake > 0 + frame_dig 28 // newPoolTotalStake: uint64 + int 0 + > + bz *if36_end + + // *if36_consequent + // contracts/stakingPool.algo.ts:746 + // for (let i = 0; i < this.stakers.value.length; i += 1) + int 0 + frame_bury 29 // i: uint64 + +*for_5: + // contracts/stakingPool.algo.ts:746 + // i < this.stakers.value.length + frame_dig 29 // i: uint64 + int 200 + < + bz *for_5_end + + // *if37_condition + // contracts/stakingPool.algo.ts:747 + // globals.opcodeBudget < 200 + global OpcodeBudget + int 200 + < + bz *if37_end + + // *if37_consequent + // contracts/stakingPool.algo.ts:748 + // increaseOpcodeBudget() + itxn_begin + int appl + itxn_field TypeEnum + int 0 + itxn_field Fee + byte b64 CoEB // #pragma version 10; int 1 + dup + itxn_field ApprovalProgram + itxn_field ClearStateProgram + int DeleteApplication + itxn_field OnCompletion + itxn_submit + +*if37_end: + // contracts/stakingPool.algo.ts:750 + // cmpStaker = clone(this.stakers.value[i]) + frame_dig 29 // i: uint64 + int 64 + * // acc * typeLength + int 64 + byte 0x7374616b657273 // "stakers" + cover 2 + box_extract + frame_bury 30 // cmpStaker: (address,uint64,uint64,uint64,uint64) + + // *if38_condition + // contracts/stakingPool.algo.ts:751 + // cmpStaker.account !== globals.zeroAddress && cmpStaker.entryTime < curTime + frame_dig 30 // cmpStaker: (address,uint64,uint64,uint64,uint64) + extract 0 32 + global ZeroAddress + != + dup + bz *skip_and4 + frame_dig 30 // cmpStaker: (address,uint64,uint64,uint64,uint64) + extract 56 8 + btoi + frame_dig 1 // curTime: uint64 + < + && + +*skip_and4: + bz *if38_end + + // *if38_consequent + // contracts/stakingPool.algo.ts:752 + // timeInPool = curTime - cmpStaker.entryTime + frame_dig 1 // curTime: uint64 + frame_dig 30 // cmpStaker: (address,uint64,uint64,uint64,uint64) + extract 56 8 + btoi + - + frame_bury 31 // timeInPool: uint64 + + // *if39_condition + // contracts/stakingPool.algo.ts:754 + // timeInPool >= epochInSecs + frame_dig 31 // timeInPool: uint64 + frame_dig 2 // epochInSecs: uint64 + >= + bz *if39_end + + // *if39_consequent + // *if40_condition + // contracts/stakingPool.algo.ts:759 + // tokenRewardAvail > 0 + frame_dig 13 // tokenRewardAvail: uint64 + int 0 + > + bz *if40_end + + // *if40_consequent + // contracts/stakingPool.algo.ts:766 + // stakerTokenReward = wideRatio( + // [cmpStaker.balance, tokenRewardAvail], + // [newPoolTotalStake] + // ) + frame_dig 30 // cmpStaker: (address,uint64,uint64,uint64,uint64) + extract 32 8 + btoi + frame_dig 13 // tokenRewardAvail: uint64 + mulw + int 0 + frame_dig 28 // newPoolTotalStake: uint64 + divmodw + pop + pop + swap + ! + assert + frame_bury 32 // stakerTokenReward: uint64 + + // contracts/stakingPool.algo.ts:775 + // cmpStaker.rewardTokenBalance += stakerTokenReward + frame_dig 30 // cmpStaker: (address,uint64,uint64,uint64,uint64) + int 48 // headOffset + frame_dig 30 // cmpStaker: (address,uint64,uint64,uint64,uint64) + extract 48 8 + btoi + frame_dig 32 // stakerTokenReward: uint64 + + + itob + replace3 + frame_bury 30 // cmpStaker: (address,uint64,uint64,uint64,uint64) + + // contracts/stakingPool.algo.ts:776 + // tokenRewardPaidOut += stakerTokenReward + frame_dig 14 // tokenRewardPaidOut: uint64 + frame_dig 32 // stakerTokenReward: uint64 + + + frame_bury 14 // tokenRewardPaidOut: uint64 + +*if40_end: + // *if41_condition + // contracts/stakingPool.algo.ts:778 + // algoRewardAvail > 0 + frame_dig 10 // algoRewardAvail: uint64 + int 0 + > + bz *if41_end + + // *if41_consequent + // contracts/stakingPool.algo.ts:779 + // stakerReward = wideRatio([cmpStaker.balance, algoRewardAvail], [newPoolTotalStake]) + frame_dig 30 // cmpStaker: (address,uint64,uint64,uint64,uint64) + extract 32 8 + btoi + frame_dig 10 // algoRewardAvail: uint64 + mulw + int 0 + frame_dig 28 // newPoolTotalStake: uint64 + divmodw + pop + pop + swap + ! + assert + frame_bury 33 // stakerReward: uint64 + + // contracts/stakingPool.algo.ts:782 + // cmpStaker.balance += stakerReward + frame_dig 30 // cmpStaker: (address,uint64,uint64,uint64,uint64) + int 32 // headOffset + frame_dig 30 // cmpStaker: (address,uint64,uint64,uint64,uint64) + extract 32 8 + btoi + frame_dig 33 // stakerReward: uint64 + + + itob + replace3 + frame_bury 30 // cmpStaker: (address,uint64,uint64,uint64,uint64) + + // contracts/stakingPool.algo.ts:783 + // cmpStaker.totalRewarded += stakerReward + frame_dig 30 // cmpStaker: (address,uint64,uint64,uint64,uint64) + int 40 // headOffset + frame_dig 30 // cmpStaker: (address,uint64,uint64,uint64,uint64) + extract 40 8 + btoi + frame_dig 33 // stakerReward: uint64 + + + itob + replace3 + frame_bury 30 // cmpStaker: (address,uint64,uint64,uint64,uint64) + + // contracts/stakingPool.algo.ts:784 + // increasedStake += stakerReward + frame_dig 20 // increasedStake: uint64 + frame_dig 33 // stakerReward: uint64 + + + frame_bury 20 // increasedStake: uint64 + +*if41_end: + // contracts/stakingPool.algo.ts:788 + // this.stakers.value[i] = cmpStaker + frame_dig 29 // i: uint64 + int 64 + * // acc * typeLength + frame_dig 30 // cmpStaker: (address,uint64,uint64,uint64,uint64) + byte 0x7374616b657273 // "stakers" + cover 2 + box_replace + +*if39_end: + +*if38_end: + +*for_5_continue: + // contracts/stakingPool.algo.ts:746 + // i += 1 + frame_dig 29 // i: uint64 + int 1 + + + frame_bury 29 // i: uint64 + b *for_5 + +*for_5_end: + +*if36_end: + // contracts/stakingPool.algo.ts:796 + // this.totalAlgoStaked.value += increasedStake + byte 0x7374616b6564 // "staked" + app_global_get + frame_dig 20 // increasedStake: uint64 + + + byte 0x7374616b6564 // "staked" + swap + app_global_put + + // contracts/stakingPool.algo.ts:798 + // log(concat('incr stake: %i', itob(increasedStake))) + byte 0x696e6372207374616b653a202569 // "incr stake: %i" + frame_dig 20 // increasedStake: uint64 + itob + concat + log + + // contracts/stakingPool.algo.ts:799 + // log(concat('tok. rwd paid: %i', itob(tokenRewardPaidOut))) + byte 0x746f6b2e2072776420706169643a202569 // "tok. rwd paid: %i" + frame_dig 14 // tokenRewardPaidOut: uint64 + itob + concat + log + + // contracts/stakingPool.algo.ts:804 + // sendMethodCall({ + // applicationID: AppID.fromUint64(this.creatingValidatorContractAppId.value), + // methodArgs: [ + // { id: this.validatorId.value, poolId: this.poolId.value, poolAppId: this.app.id }, + // increasedStake, + // tokenRewardPaidOut, + // ], + // }) + itxn_begin + int appl + itxn_field TypeEnum + method "stakeUpdatedViaRewards((uint64,uint64,uint64),uint64,uint64)void" + itxn_field ApplicationArgs + + // contracts/stakingPool.algo.ts:805 + // applicationID: AppID.fromUint64(this.creatingValidatorContractAppId.value) + byte 0x63726561746f72417070 // "creatorApp" + app_global_get + itxn_field ApplicationID + + // contracts/stakingPool.algo.ts:806 + // methodArgs: [ + // { id: this.validatorId.value, poolId: this.poolId.value, poolAppId: this.app.id }, + // increasedStake, + // tokenRewardPaidOut, + // ] + byte 0x76616c696461746f724964 // "validatorId" + app_global_get + itob + byte 0x706f6f6c4964 // "poolId" + app_global_get + itob + concat + txna Applications 0 + itob + concat + itxn_field ApplicationArgs + frame_dig 20 // increasedStake: uint64 + itob + itxn_field ApplicationArgs + frame_dig 14 // tokenRewardPaidOut: uint64 + itob + itxn_field ApplicationArgs + + // Fee field not set, defaulting to 0 + int 0 + itxn_field Fee + + // Submit inner transaction + itxn_submit + retsub + +// goOnline(byte[],byte[],byte[],uint64,uint64,uint64)void +*abi_route_goOnline: + // voteKeyDilution: uint64 + txna ApplicationArgs 6 + btoi + + // voteLast: uint64 + txna ApplicationArgs 5 + btoi + + // voteFirst: uint64 + txna ApplicationArgs 4 + btoi + + // stateProofPK: byte[] + txna ApplicationArgs 3 + extract 2 0 + + // selectionPK: byte[] + txna ApplicationArgs 2 + extract 2 0 + + // votePK: byte[] + txna ApplicationArgs 1 + extract 2 0 + + // execute goOnline(byte[],byte[],byte[],uint64,uint64,uint64)void + callsub goOnline + int 1 + return + +// goOnline(votePK: bytes, selectionPK: bytes, stateProofPK: bytes, voteFirst: uint64, voteLast: uint64, voteKeyDilution: uint64): void +// +// Registers a staking pool key online against a participation key. +// [ ONLY OWNER OR MANAGER CAN CALL ] +// +// @param {bytes} votePK - The vote public key. +// @param {bytes} selectionPK - The selection public key. +// @param {bytes} stateProofPK - The state proof public key. +// @param {uint64} voteFirst - The first vote index. +// @param {uint64} voteLast - The last vote index. +// @param {uint64} voteKeyDilution - The vote key dilution value. +// @throws {Error} Will throw an error if the caller is not the owner or a manager. +goOnline: + proto 6 0 + + // contracts/stakingPool.algo.ts:834 + // assert(this.isOwnerOrManagerCaller()) + callsub isOwnerOrManagerCaller + assert + + // contracts/stakingPool.algo.ts:835 + // sendOnlineKeyRegistration({ + // votePK: votePK, + // selectionPK: selectionPK, + // stateProofPK: stateProofPK, + // voteFirst: voteFirst, + // voteLast: voteLast, + // voteKeyDilution: voteKeyDilution, + // }) + itxn_begin + int keyreg + itxn_field TypeEnum + + // contracts/stakingPool.algo.ts:836 + // votePK: votePK + frame_dig -1 // votePK: bytes + itxn_field VotePK + + // contracts/stakingPool.algo.ts:837 + // selectionPK: selectionPK + frame_dig -2 // selectionPK: bytes + itxn_field SelectionPK + + // contracts/stakingPool.algo.ts:838 + // stateProofPK: stateProofPK + frame_dig -3 // stateProofPK: bytes + itxn_field StateProofPK + + // contracts/stakingPool.algo.ts:839 + // voteFirst: voteFirst + frame_dig -4 // voteFirst: uint64 + itxn_field VoteFirst + + // contracts/stakingPool.algo.ts:840 + // voteLast: voteLast + frame_dig -5 // voteLast: uint64 + itxn_field VoteLast + + // contracts/stakingPool.algo.ts:841 + // voteKeyDilution: voteKeyDilution + frame_dig -6 // voteKeyDilution: uint64 + itxn_field VoteKeyDilution + + // Fee field not set, defaulting to 0 + int 0 + itxn_field Fee + + // Submit inner transaction + itxn_submit + retsub + +// goOffline()void +*abi_route_goOffline: + // execute goOffline()void + callsub goOffline + int 1 + return + +// goOffline(): void +// +// Marks a staking pool key OFFLINE. +// [ ONLY OWNER OR MANAGER CAN CALL ] +goOffline: + proto 0 0 + + // *if42_condition + // contracts/stakingPool.algo.ts:853 + // this.txn.sender !== AppID.fromUint64(this.creatingValidatorContractAppId.value).address + txn Sender + byte 0x63726561746f72417070 // "creatorApp" + app_global_get + app_params_get AppAddress + pop + != + bz *if42_end + + // *if42_consequent + // contracts/stakingPool.algo.ts:854 + // assert(this.isOwnerOrManagerCaller()) + callsub isOwnerOrManagerCaller + assert + +*if42_end: + // contracts/stakingPool.algo.ts:857 + // sendOfflineKeyRegistration({}) + itxn_begin + int keyreg + itxn_field TypeEnum + + // Fee field not set, defaulting to 0 + int 0 + itxn_field Fee + + // Submit inner transaction + itxn_submit + retsub + +// linkToNFD(uint64,string)void +*abi_route_linkToNFD: + // nfdName: string + txna ApplicationArgs 2 + extract 2 0 + + // nfdAppId: uint64 + txna ApplicationArgs 1 + btoi + + // execute linkToNFD(uint64,string)void + callsub linkToNFD + int 1 + return + +// linkToNFD(nfdAppId: uint64, nfdName: string): void +linkToNFD: + proto 2 0 + + // contracts/stakingPool.algo.ts:864 + // assert(this.isOwnerOrManagerCaller()) + callsub isOwnerOrManagerCaller + assert + + // contracts/stakingPool.algo.ts:866 + // sendAppCall({ + // applicationID: AppID.fromUint64(this.nfdRegistryAppId), + // applicationArgs: ['verify_nfd_addr', nfdName, itob(nfdAppId), rawBytes(this.app.address)], + // applications: [AppID.fromUint64(nfdAppId)], + // }) + itxn_begin + int appl + itxn_field TypeEnum + + // contracts/stakingPool.algo.ts:867 + // applicationID: AppID.fromUint64(this.nfdRegistryAppId) + pushint TMPL_nfdRegistryAppId + itxn_field ApplicationID + + // contracts/stakingPool.algo.ts:868 + // applicationArgs: ['verify_nfd_addr', nfdName, itob(nfdAppId), rawBytes(this.app.address)] + byte 0x7665726966795f6e66645f61646472 // "verify_nfd_addr" + itxn_field ApplicationArgs + frame_dig -2 // nfdName: string + itxn_field ApplicationArgs + frame_dig -1 // nfdAppId: uint64 + itob + itxn_field ApplicationArgs + global CurrentApplicationAddress + itxn_field ApplicationArgs + + // contracts/stakingPool.algo.ts:869 + // applications: [AppID.fromUint64(nfdAppId)] + frame_dig -1 // nfdAppId: uint64 + itxn_field Applications + + // Fee field not set, defaulting to 0 + int 0 + itxn_field Fee + + // Submit inner transaction + itxn_submit + retsub + +// proxiedSetTokenPayoutRatio((uint64,uint64,uint64))(uint64[24],uint64) +*abi_route_proxiedSetTokenPayoutRatio: + // The ABI return prefix + byte 0x151f7c75 + + // poolKey: (uint64,uint64,uint64) + txna ApplicationArgs 1 + dup + len + int 24 + == + assert + + // execute proxiedSetTokenPayoutRatio((uint64,uint64,uint64))(uint64[24],uint64) + callsub proxiedSetTokenPayoutRatio + concat + log + int 1 + return + +// proxiedSetTokenPayoutRatio(poolKey: ValidatorPoolKey): PoolTokenPayoutRatio +// +// proxiedSetTokenPayoutRatio is meant to be called by pools != 1 - calling US, pool #1 +// We need to verify that we are in fact being called by another of OUR pools (not us) +// and then we'll call the validator on their behalf to update the token payouts +// @param poolKey - ValidatorPoolKey tuple +proxiedSetTokenPayoutRatio: + proto 1 1 + + // Push empty bytes after the frame pointer to reserve space for local variables + byte 0x + + // contracts/stakingPool.algo.ts:880 + // assert(this.validatorId.value === poolKey.id, 'caller must be part of same validator set!') + byte 0x76616c696461746f724964 // "validatorId" + app_global_get + frame_dig -1 // poolKey: ValidatorPoolKey + extract 0 8 + btoi + == + + // caller must be part of same validator set! + assert + + // contracts/stakingPool.algo.ts:881 + // assert(this.poolId.value === 1, 'callee must be pool 1') + byte 0x706f6f6c4964 // "poolId" + app_global_get + int 1 + == + + // callee must be pool 1 + assert + + // contracts/stakingPool.algo.ts:882 + // assert(poolKey.poolId !== 1, 'caller must NOT be pool 1') + frame_dig -1 // poolKey: ValidatorPoolKey + extract 8 8 + btoi + int 1 + != + + // caller must NOT be pool 1 + assert + + // contracts/stakingPool.algo.ts:884 + // callerPoolAppID = sendMethodCall({ + // applicationID: AppID.fromUint64(this.creatingValidatorContractAppId.value), + // methodArgs: [poolKey.id, poolKey.poolId], + // }) + itxn_begin + int appl + itxn_field TypeEnum + method "getPoolAppId(uint64,uint64)uint64" + itxn_field ApplicationArgs + + // contracts/stakingPool.algo.ts:885 + // applicationID: AppID.fromUint64(this.creatingValidatorContractAppId.value) + byte 0x63726561746f72417070 // "creatorApp" + app_global_get + itxn_field ApplicationID + + // contracts/stakingPool.algo.ts:886 + // methodArgs: [poolKey.id, poolKey.poolId] + frame_dig -1 // poolKey: ValidatorPoolKey + extract 0 8 + btoi + itob + itxn_field ApplicationArgs + frame_dig -1 // poolKey: ValidatorPoolKey + extract 8 8 + btoi + itob + itxn_field ApplicationArgs + + // Fee field not set, defaulting to 0 + int 0 + itxn_field Fee + + // Submit inner transaction + itxn_submit + itxn NumLogs + int 1 + - + itxnas Logs + extract 4 0 + btoi + frame_bury 0 // callerPoolAppID: uint64 + + // contracts/stakingPool.algo.ts:888 + // assert(callerPoolAppID === poolKey.poolAppId) + frame_dig 0 // callerPoolAppID: uint64 + frame_dig -1 // poolKey: ValidatorPoolKey + extract 16 8 + btoi + == + assert + + // contracts/stakingPool.algo.ts:889 + // assert(this.txn.sender === AppID.fromUint64(poolKey.poolAppId).address) + txn Sender + frame_dig -1 // poolKey: ValidatorPoolKey + extract 16 8 + btoi + app_params_get AppAddress + pop + == + assert + + // contracts/stakingPool.algo.ts:891 + // return sendMethodCall({ + // applicationID: AppID.fromUint64(this.creatingValidatorContractAppId.value), + // methodArgs: [this.validatorId.value], + // }); + itxn_begin + int appl + itxn_field TypeEnum + method "setTokenPayoutRatio(uint64)(uint64[24],uint64)" + itxn_field ApplicationArgs + + // contracts/stakingPool.algo.ts:892 + // applicationID: AppID.fromUint64(this.creatingValidatorContractAppId.value) + byte 0x63726561746f72417070 // "creatorApp" + app_global_get + itxn_field ApplicationID + + // contracts/stakingPool.algo.ts:893 + // methodArgs: [this.validatorId.value] + byte 0x76616c696461746f724964 // "validatorId" + app_global_get + itob + itxn_field ApplicationArgs + + // Fee field not set, defaulting to 0 + int 0 + itxn_field Fee + + // Submit inner transaction + itxn_submit + itxn NumLogs + int 1 + - + itxnas Logs + extract 4 0 + + // set the subroutine return value + frame_bury 0 + retsub + +// isOwnerOrManagerCaller(): boolean +isOwnerOrManagerCaller: + proto 0 1 + + // Push empty bytes after the frame pointer to reserve space for local variables + byte 0x + + // contracts/stakingPool.algo.ts:898 + // OwnerAndManager = sendMethodCall({ + // applicationID: AppID.fromUint64(this.creatingValidatorContractAppId.value), + // methodArgs: [this.validatorId.value], + // }) + itxn_begin + int appl + itxn_field TypeEnum + method "getValidatorOwnerAndManager(uint64)(address,address)" + itxn_field ApplicationArgs + + // contracts/stakingPool.algo.ts:899 + // applicationID: AppID.fromUint64(this.creatingValidatorContractAppId.value) + byte 0x63726561746f72417070 // "creatorApp" + app_global_get + itxn_field ApplicationID + + // contracts/stakingPool.algo.ts:900 + // methodArgs: [this.validatorId.value] + byte 0x76616c696461746f724964 // "validatorId" + app_global_get + itob + itxn_field ApplicationArgs + + // Fee field not set, defaulting to 0 + int 0 + itxn_field Fee + + // Submit inner transaction + itxn_submit + itxn NumLogs + int 1 + - + itxnas Logs + extract 4 0 + frame_bury 0 // OwnerAndManager: (address,address) + + // contracts/stakingPool.algo.ts:902 + // return this.txn.sender === OwnerAndManager[0] || this.txn.sender === OwnerAndManager[1]; + txn Sender + frame_dig 0 // OwnerAndManager: (address,address) + extract 0 32 + == + dup + bnz *skip_or1 + txn Sender + frame_dig 0 // OwnerAndManager: (address,address) + extract 32 32 + == + || + +*skip_or1: + // set the subroutine return value + frame_bury 0 + retsub + +// getEntryTime(): uint64 +// +// Calculate the entry time for counting a stake as entering the pool. +// Algorand won't see the balance increase for ALGORAND_STAKING_BLOCK_DELAY rounds, so we approximate it. +// The entry time is calculated by adding an approximate number of seconds based on current AVG block times +// to the original entry time. This means users don't get payouts based on time their balance wouldn't have +// been seen by the network. +// +// @returns {uint64} - The updated entry time. +getEntryTime: + proto 0 1 + + // Push empty bytes after the frame pointer to reserve space for local variables + byte 0x + + // contracts/stakingPool.algo.ts:917 + // entryTime = globals.latestTimestamp + global LatestTimestamp + frame_bury 0 // entryTime: uint64 + + // contracts/stakingPool.algo.ts:920 + // return entryTime + (ALGORAND_STAKING_BLOCK_DELAY * AVG_BLOCK_TIME_SECS) / 10; + frame_dig 0 // entryTime: uint64 + int 896 + + + + // set the subroutine return value + frame_bury 0 + retsub + +// getFeeSink(): Address +getFeeSink: + proto 0 1 + + // contracts/stakingPool.algo.ts:924 + // return this.feeSinkAddr; + pushbytes TMPL_feeSinkAddr + retsub + +// algoSaturationLevel(): uint64 +// +// Returns the maximum allowed stake per validator based on a percentage of all current online stake before +// the validator is considered saturated - where rewards are diminished. +algoSaturationLevel: + proto 0 1 + + // Push empty bytes after the frame pointer to reserve space for local variables + byte 0x + + // contracts/stakingPool.algo.ts:934 + // online = this.getCurrentOnlineStake() + callsub getCurrentOnlineStake + frame_bury 0 // online: uint64 + + // contracts/stakingPool.algo.ts:936 + // return wideRatio([online, MAX_VALIDATOR_SOFT_PCT_OF_ONLINE_1DECIMAL], [1000]); + frame_dig 0 // online: uint64 + int 100 + mulw + int 0 + int 1000 + divmodw + pop + pop + swap + ! + assert + + // set the subroutine return value + frame_bury 0 + retsub + +// getCurrentOnlineStake(): uint64 +getCurrentOnlineStake: + proto 0 1 + + // contracts/stakingPool.algo.ts:941 + // return 2_000_000_000_000_000; + int 2_000_000_000_000_000 + retsub + +*create_NoOp: + method "createApplication(uint64,uint64,uint64,uint64)void" + txna ApplicationArgs 0 + match *abi_route_createApplication + err + +*call_NoOp: + method "gas()void" + method "initStorage(pay)void" + method "addStake(pay,address)uint64" + method "removeStake(uint64)void" + method "claimTokens()void" + method "getStakerInfo(address)(address,uint64,uint64,uint64,uint64)" + method "payTokenReward(address,uint64,uint64)void" + method "updateAlgodVer(string)void" + method "epochBalanceUpdate()void" + method "goOnline(byte[],byte[],byte[],uint64,uint64,uint64)void" + method "goOffline()void" + method "linkToNFD(uint64,string)void" + method "proxiedSetTokenPayoutRatio((uint64,uint64,uint64))(uint64[24],uint64)" + txna ApplicationArgs 0 + match *abi_route_gas *abi_route_initStorage *abi_route_addStake *abi_route_removeStake *abi_route_claimTokens *abi_route_getStakerInfo *abi_route_payTokenReward *abi_route_updateAlgodVer *abi_route_epochBalanceUpdate *abi_route_goOnline *abi_route_goOffline *abi_route_linkToNFD *abi_route_proxiedSetTokenPayoutRatio + err + +*intToAscii: + proto 1 1 + byte 0x30313233343536373839 // "0123456789" + frame_dig -1 // i: uint64 + int 1 + extract3 + retsub + + +*itoa: + proto 1 1 + frame_dig -1 // i: uint64 + int 0 + == + bz *itoa_if_end + byte 0x30 + retsub + +*itoa_if_end: + frame_dig -1 // i: uint64 + int 10 + / + int 0 + > + bz *itoa_ternary_false + frame_dig -1 // i: uint64 + int 10 + / + callsub *itoa + b *itoa_ternary_end + +*itoa_ternary_false: + byte 0x // "" + +*itoa_ternary_end: + frame_dig -1 // i: uint64 + int 10 + % + callsub *intToAscii + concat + retsub \ No newline at end of file diff --git a/contracts/contracts/artifacts/StakingPool.arc32.json b/contracts/contracts/artifacts/StakingPool.arc32.json new file mode 100644 index 00000000..25e0d3f7 --- /dev/null +++ b/contracts/contracts/artifacts/StakingPool.arc32.json @@ -0,0 +1,379 @@ +{ + "hints": { + "createApplication(uint64,uint64,uint64,uint64)void": { + "call_config": { + "no_op": "CREATE" + } + }, + "gas()void": { + "call_config": { + "no_op": "CALL" + } + }, + "initStorage(pay)void": { + "call_config": { + "no_op": "CALL" + } + }, + "addStake(pay,address)uint64": { + "call_config": { + "no_op": "CALL" + } + }, + "removeStake(uint64)void": { + "call_config": { + "no_op": "CALL" + } + }, + "claimTokens()void": { + "call_config": { + "no_op": "CALL" + } + }, + "getStakerInfo(address)(address,uint64,uint64,uint64,uint64)": { + "call_config": { + "no_op": "CALL" + } + }, + "payTokenReward(address,uint64,uint64)void": { + "call_config": { + "no_op": "CALL" + } + }, + "updateAlgodVer(string)void": { + "call_config": { + "no_op": "CALL" + } + }, + "epochBalanceUpdate()void": { + "call_config": { + "no_op": "CALL" + } + }, + "goOnline(byte[],byte[],byte[],uint64,uint64,uint64)void": { + "call_config": { + "no_op": "CALL" + } + }, + "goOffline()void": { + "call_config": { + "no_op": "CALL" + } + }, + "linkToNFD(uint64,string)void": { + "call_config": { + "no_op": "CALL" + } + }, + "proxiedSetTokenPayoutRatio((uint64,uint64,uint64))(uint64[24],uint64)": { + "call_config": { + "no_op": "CALL" + } + } + }, + "bare_call_config": { + "no_op": "NEVER", + "opt_in": "NEVER", + "close_out": "NEVER", + "update_application": "NEVER", + "delete_application": "NEVER" + }, + "schema": { + "local": { + "declared": {}, + "reserved": {} + }, + "global": { + "declared": { + "creatingValidatorContractAppId": { + "type": "uint64", + "key": "creatorApp" + }, + "validatorId": { + "type": "uint64", + "key": "validatorId" + }, + "poolId": { + "type": "uint64", + "key": "poolId" + }, + "numStakers": { + "type": "uint64", + "key": "numStakers" + }, + "totalAlgoStaked": { + "type": "uint64", + "key": "staked" + }, + "minEntryStake": { + "type": "uint64", + "key": "minEntryStake" + }, + "lastPayout": { + "type": "uint64", + "key": "lastPayout" + }, + "epochNumber": { + "type": "uint64", + "key": "epochNumber" + }, + "algodVer": { + "type": "bytes", + "key": "algodVer" + } + }, + "reserved": {} + } + }, + "state": { + "global": { + "num_byte_slices": 1, + "num_uints": 8 + }, + "local": { + "num_byte_slices": 0, + "num_uints": 0 + } + }, + "source": { + "approval": "I3ByYWdtYSB2ZXJzaW9uIDEwCgovLyBUaGlzIFRFQUwgd2FzIGdlbmVyYXRlZCBieSBURUFMU2NyaXB0IHYwLjg4LjEKLy8gaHR0cHM6Ly9naXRodWIuY29tL2FsZ29yYW5kZm91bmRhdGlvbi9URUFMU2NyaXB0CgovLyBUaGlzIGNvbnRyYWN0IGlzIGNvbXBsaWFudCB3aXRoIGFuZC9vciBpbXBsZW1lbnRzIHRoZSBmb2xsb3dpbmcgQVJDczogWyBBUkM0IF0KCi8vIFRoZSBmb2xsb3dpbmcgdGVuIGxpbmVzIG9mIFRFQUwgaGFuZGxlIGluaXRpYWwgcHJvZ3JhbSBmbG93Ci8vIFRoaXMgcGF0dGVybiBpcyB1c2VkIHRvIG1ha2UgaXQgZWFzeSBmb3IgYW55b25lIHRvIHBhcnNlIHRoZSBzdGFydCBvZiB0aGUgcHJvZ3JhbSBhbmQgZGV0ZXJtaW5lIGlmIGEgc3BlY2lmaWMgYWN0aW9uIGlzIGFsbG93ZWQKLy8gSGVyZSwgYWN0aW9uIHJlZmVycyB0byB0aGUgT25Db21wbGV0ZSBpbiBjb21iaW5hdGlvbiB3aXRoIHdoZXRoZXIgdGhlIGFwcCBpcyBiZWluZyBjcmVhdGVkIG9yIGNhbGxlZAovLyBFdmVyeSBwb3NzaWJsZSBhY3Rpb24gZm9yIHRoaXMgY29udHJhY3QgaXMgcmVwcmVzZW50ZWQgaW4gdGhlIHN3aXRjaCBzdGF0ZW1lbnQKLy8gSWYgdGhlIGFjdGlvbiBpcyBub3QgaW1wbGVtZW50ZWQgaW4gdGhlIGNvbnRyYWN0LCBpdHMgcmVzcGVjdGl2ZSBicmFuY2ggd2lsbCBiZSAiKk5PVF9JTVBMRU1FTlRFRCIgd2hpY2gganVzdCBjb250YWlucyAiZXJyIgp0eG4gQXBwbGljYXRpb25JRAohCmludCA2CioKdHhuIE9uQ29tcGxldGlvbgorCnN3aXRjaCAqY2FsbF9Ob09wICpOT1RfSU1QTEVNRU5URUQgKk5PVF9JTVBMRU1FTlRFRCAqTk9UX0lNUExFTUVOVEVEICpOT1RfSU1QTEVNRU5URUQgKk5PVF9JTVBMRU1FTlRFRCAqY3JlYXRlX05vT3AgKk5PVF9JTVBMRU1FTlRFRCAqTk9UX0lNUExFTUVOVEVEICpOT1RfSU1QTEVNRU5URUQgKk5PVF9JTVBMRU1FTlRFRCAqTk9UX0lNUExFTUVOVEVECgoqTk9UX0lNUExFTUVOVEVEOgoJZXJyCgovLyBjcmVhdGVBcHBsaWNhdGlvbih1aW50NjQsdWludDY0LHVpbnQ2NCx1aW50NjQpdm9pZAoqYWJpX3JvdXRlX2NyZWF0ZUFwcGxpY2F0aW9uOgoJLy8gbWluRW50cnlTdGFrZTogdWludDY0Cgl0eG5hIEFwcGxpY2F0aW9uQXJncyA0CglidG9pCgoJLy8gcG9vbElkOiB1aW50NjQKCXR4bmEgQXBwbGljYXRpb25BcmdzIDMKCWJ0b2kKCgkvLyB2YWxpZGF0b3JJZDogdWludDY0Cgl0eG5hIEFwcGxpY2F0aW9uQXJncyAyCglidG9pCgoJLy8gY3JlYXRpbmdDb250cmFjdElkOiB1aW50NjQKCXR4bmEgQXBwbGljYXRpb25BcmdzIDEKCWJ0b2kKCgkvLyBleGVjdXRlIGNyZWF0ZUFwcGxpY2F0aW9uKHVpbnQ2NCx1aW50NjQsdWludDY0LHVpbnQ2NCl2b2lkCgljYWxsc3ViIGNyZWF0ZUFwcGxpY2F0aW9uCglpbnQgMQoJcmV0dXJuCgovLyBjcmVhdGVBcHBsaWNhdGlvbihjcmVhdGluZ0NvbnRyYWN0SWQ6IHVpbnQ2NCwgdmFsaWRhdG9ySWQ6IHVpbnQ2NCwgcG9vbElkOiB1aW50NjQsIG1pbkVudHJ5U3Rha2U6IHVpbnQ2NCk6IHZvaWQKLy8KLy8gSW5pdGlhbGl6ZSB0aGUgc3Rha2luZyBwb29sIHcvIG93bmVyIGFuZCBtYW5hZ2VyLCBidXQgY2FuIG9ubHkgYmUgY3JlYXRlZCBieSB0aGUgdmFsaWRhdG9yIGNvbnRyYWN0LgovLyBAcGFyYW0ge3VpbnQ2NH0gY3JlYXRpbmdDb250cmFjdElkIC0gaWQgb2YgY29udHJhY3QgdGhhdCBjb25zdHJ1Y3RlZCB1cyAtIHRoZSB2YWxpZGF0b3IgYXBwbGljYXRpb24gKHNpbmdsZSBnbG9iYWwgaW5zdGFuY2UpCi8vIEBwYXJhbSB7dWludDY0fSB2YWxpZGF0b3JJZCAtIGlkIG9mIHZhbGlkYXRvciB3ZSdyZSBhIHN0YWtpbmcgcG9vbCBvZgovLyBAcGFyYW0ge3VpbnQ2NH0gcG9vbElkIC0gd2hpY2ggcG9vbCBpZCBhcmUgd2UKLy8gQHBhcmFtIHt1aW50NjR9IG1pbkVudHJ5U3Rha2UgLSBtaW5pbXVtIGFtb3VudCB0byBiZSBpbiBwb29sLCBidXQgYWxzbyBtaW5pbXVtIGFtb3VudCBiYWxhbmNlIGNhbid0IGdvIGJlbG93ICh3aXRob3V0IHJlbW92aW5nIGFsbCEpCmNyZWF0ZUFwcGxpY2F0aW9uOgoJcHJvdG8gNCAwCgoJLy8gKmlmMF9jb25kaXRpb24KCS8vIGNvbnRyYWN0cy9zdGFraW5nUG9vbC5hbGdvLnRzOjg2CgkvLyBjcmVhdGluZ0NvbnRyYWN0SWQgPT09IDAKCWZyYW1lX2RpZyAtMSAvLyBjcmVhdGluZ0NvbnRyYWN0SWQ6IHVpbnQ2NAoJaW50IDAKCT09CglieiAqaWYwX2Vsc2UKCgkvLyAqaWYwX2NvbnNlcXVlbnQKCS8vIGNvbnRyYWN0cy9zdGFraW5nUG9vbC5hbGdvLnRzOjg4CgkvLyBhc3NlcnQodmFsaWRhdG9ySWQgPT09IDApCglmcmFtZV9kaWcgLTIgLy8gdmFsaWRhdG9ySWQ6IHVpbnQ2NAoJaW50IDAKCT09Cglhc3NlcnQKCgkvLyBjb250cmFjdHMvc3Rha2luZ1Bvb2wuYWxnby50czo4OQoJLy8gYXNzZXJ0KHBvb2xJZCA9PT0gMCkKCWZyYW1lX2RpZyAtMyAvLyBwb29sSWQ6IHVpbnQ2NAoJaW50IDAKCT09Cglhc3NlcnQKCWIgKmlmMF9lbmQKCippZjBfZWxzZToKCS8vIGNvbnRyYWN0cy9zdGFraW5nUG9vbC5hbGdvLnRzOjkxCgkvLyBhc3NlcnQodmFsaWRhdG9ySWQgIT09IDApCglmcmFtZV9kaWcgLTIgLy8gdmFsaWRhdG9ySWQ6IHVpbnQ2NAoJaW50IDAKCSE9Cglhc3NlcnQKCgkvLyBjb250cmFjdHMvc3Rha2luZ1Bvb2wuYWxnby50czo5MgoJLy8gYXNzZXJ0KHBvb2xJZCAhPT0gMCkKCWZyYW1lX2RpZyAtMyAvLyBwb29sSWQ6IHVpbnQ2NAoJaW50IDAKCSE9Cglhc3NlcnQKCippZjBfZW5kOgoJLy8gY29udHJhY3RzL3N0YWtpbmdQb29sLmFsZ28udHM6OTQKCS8vIGFzc2VydChtaW5FbnRyeVN0YWtlID49IE1JTl9BTEdPX1NUQUtFX1BFUl9QT09MKQoJZnJhbWVfZGlnIC00IC8vIG1pbkVudHJ5U3Rha2U6IHVpbnQ2NAoJaW50IDEwMDAwMDAKCT49Cglhc3NlcnQKCgkvLyBjb250cmFjdHMvc3Rha2luZ1Bvb2wuYWxnby50czo5NQoJLy8gdGhpcy5jcmVhdGluZ1ZhbGlkYXRvckNvbnRyYWN0QXBwSWQudmFsdWUgPSBjcmVhdGluZ0NvbnRyYWN0SWQKCWJ5dGUgMHg2MzcyNjU2MTc0NmY3MjQxNzA3MCAvLyAiY3JlYXRvckFwcCIKCWZyYW1lX2RpZyAtMSAvLyBjcmVhdGluZ0NvbnRyYWN0SWQ6IHVpbnQ2NAoJYXBwX2dsb2JhbF9wdXQKCgkvLyBjb250cmFjdHMvc3Rha2luZ1Bvb2wuYWxnby50czo5NgoJLy8gdGhpcy52YWxpZGF0b3JJZC52YWx1ZSA9IHZhbGlkYXRvcklkCglieXRlIDB4NzY2MTZjNjk2NDYxNzQ2ZjcyNDk2NCAvLyAidmFsaWRhdG9ySWQiCglmcmFtZV9kaWcgLTIgLy8gdmFsaWRhdG9ySWQ6IHVpbnQ2NAoJYXBwX2dsb2JhbF9wdXQKCgkvLyBjb250cmFjdHMvc3Rha2luZ1Bvb2wuYWxnby50czo5NwoJLy8gdGhpcy5wb29sSWQudmFsdWUgPSBwb29sSWQKCWJ5dGUgMHg3MDZmNmY2YzQ5NjQgLy8gInBvb2xJZCIKCWZyYW1lX2RpZyAtMyAvLyBwb29sSWQ6IHVpbnQ2NAoJYXBwX2dsb2JhbF9wdXQKCgkvLyBjb250cmFjdHMvc3Rha2luZ1Bvb2wuYWxnby50czo5OAoJLy8gdGhpcy5udW1TdGFrZXJzLnZhbHVlID0gMAoJYnl0ZSAweDZlNzU2ZDUzNzQ2MTZiNjU3MjczIC8vICJudW1TdGFrZXJzIgoJaW50IDAKCWFwcF9nbG9iYWxfcHV0CgoJLy8gY29udHJhY3RzL3N0YWtpbmdQb29sLmFsZ28udHM6OTkKCS8vIHRoaXMudG90YWxBbGdvU3Rha2VkLnZhbHVlID0gMAoJYnl0ZSAweDczNzQ2MTZiNjU2NCAvLyAic3Rha2VkIgoJaW50IDAKCWFwcF9nbG9iYWxfcHV0CgoJLy8gY29udHJhY3RzL3N0YWtpbmdQb29sLmFsZ28udHM6MTAwCgkvLyB0aGlzLm1pbkVudHJ5U3Rha2UudmFsdWUgPSBtaW5FbnRyeVN0YWtlCglieXRlIDB4NmQ2OTZlNDU2ZTc0NzI3OTUzNzQ2MTZiNjUgLy8gIm1pbkVudHJ5U3Rha2UiCglmcmFtZV9kaWcgLTQgLy8gbWluRW50cnlTdGFrZTogdWludDY0CglhcHBfZ2xvYmFsX3B1dAoKCS8vIGNvbnRyYWN0cy9zdGFraW5nUG9vbC5hbGdvLnRzOjEwMQoJLy8gdGhpcy5sYXN0UGF5b3V0LnZhbHVlID0gZ2xvYmFscy5sYXRlc3RUaW1lc3RhbXAKCWJ5dGUgMHg2YzYxNzM3NDUwNjE3OTZmNzU3NCAvLyAibGFzdFBheW91dCIKCWdsb2JhbCBMYXRlc3RUaW1lc3RhbXAKCWFwcF9nbG9iYWxfcHV0CgoJLy8gY29udHJhY3RzL3N0YWtpbmdQb29sLmFsZ28udHM6MTAyCgkvLyB0aGlzLmVwb2NoTnVtYmVyLnZhbHVlID0gMAoJYnl0ZSAweDY1NzA2ZjYzNjg0ZTc1NmQ2MjY1NzIgLy8gImVwb2NoTnVtYmVyIgoJaW50IDAKCWFwcF9nbG9iYWxfcHV0CglyZXRzdWIKCi8vIGdhcygpdm9pZAoqYWJpX3JvdXRlX2dhczoKCS8vIGV4ZWN1dGUgZ2FzKCl2b2lkCgljYWxsc3ViIGdhcwoJaW50IDEKCXJldHVybgoKLy8gZ2FzKCk6IHZvaWQKLy8KLy8gZ2FzIGlzIGEgZHVtbXkgbm8tb3AgY2FsbCB0aGF0IGNhbiBiZSB1c2VkIHRvIHBvb2wtdXAgcmVzb3VyY2UgcmVmZXJlbmNlcyBhbmQgb3Bjb2RlIGNvc3QKZ2FzOgoJcHJvdG8gMCAwCglyZXRzdWIKCi8vIG1pbkJhbGFuY2VGb3JBY2NvdW50KGNvbnRyYWN0czogdWludDY0LCBleHRyYVBhZ2VzOiB1aW50NjQsIGFzc2V0czogdWludDY0LCBsb2NhbEludHM6IHVpbnQ2NCwgbG9jYWxCeXRlczogdWludDY0LCBnbG9iYWxJbnRzOiB1aW50NjQsIGdsb2JhbEJ5dGVzOiB1aW50NjQpOiB1aW50NjQKbWluQmFsYW5jZUZvckFjY291bnQ6Cglwcm90byA3IDEKCgkvLyBQdXNoIGVtcHR5IGJ5dGVzIGFmdGVyIHRoZSBmcmFtZSBwb2ludGVyIHRvIHJlc2VydmUgc3BhY2UgZm9yIGxvY2FsIHZhcmlhYmxlcwoJYnl0ZSAweAoKCS8vIGNvbnRyYWN0cy9zdGFraW5nUG9vbC5hbGdvLnRzOjExOQoJLy8gbWluQmFsID0gQUxHT1JBTkRfQUNDT1VOVF9NSU5fQkFMQU5DRQoJaW50IDEwMDAwMAoJZnJhbWVfYnVyeSAwIC8vIG1pbkJhbDogdWludDY0CgoJLy8gY29udHJhY3RzL3N0YWtpbmdQb29sLmFsZ28udHM6MTIwCgkvLyBtaW5CYWwgKz0gY29udHJhY3RzICogQVBQTElDQVRJT05fQkFTRV9GRUUKCWZyYW1lX2RpZyAwIC8vIG1pbkJhbDogdWludDY0CglmcmFtZV9kaWcgLTEgLy8gY29udHJhY3RzOiB1aW50NjQKCWludCAxMDAwMDAKCSoKCSsKCWZyYW1lX2J1cnkgMCAvLyBtaW5CYWw6IHVpbnQ2NAoKCS8vIGNvbnRyYWN0cy9zdGFraW5nUG9vbC5hbGdvLnRzOjEyMQoJLy8gbWluQmFsICs9IGV4dHJhUGFnZXMgKiBBUFBMSUNBVElPTl9CQVNFX0ZFRQoJZnJhbWVfZGlnIDAgLy8gbWluQmFsOiB1aW50NjQKCWZyYW1lX2RpZyAtMiAvLyBleHRyYVBhZ2VzOiB1aW50NjQKCWludCAxMDAwMDAKCSoKCSsKCWZyYW1lX2J1cnkgMCAvLyBtaW5CYWw6IHVpbnQ2NAoKCS8vIGNvbnRyYWN0cy9zdGFraW5nUG9vbC5hbGdvLnRzOjEyMgoJLy8gbWluQmFsICs9IGFzc2V0cyAqIEFTU0VUX0hPTERJTkdfRkVFCglmcmFtZV9kaWcgMCAvLyBtaW5CYWw6IHVpbnQ2NAoJZnJhbWVfZGlnIC0zIC8vIGFzc2V0czogdWludDY0CglpbnQgMTAwMDAwCgkqCgkrCglmcmFtZV9idXJ5IDAgLy8gbWluQmFsOiB1aW50NjQKCgkvLyBjb250cmFjdHMvc3Rha2luZ1Bvb2wuYWxnby50czoxMjMKCS8vIG1pbkJhbCArPSBsb2NhbEludHMgKiBTU0NfVkFMVUVfVUlOVAoJZnJhbWVfZGlnIDAgLy8gbWluQmFsOiB1aW50NjQKCWZyYW1lX2RpZyAtNCAvLyBsb2NhbEludHM6IHVpbnQ2NAoJaW50IDI4NTAwCgkqCgkrCglmcmFtZV9idXJ5IDAgLy8gbWluQmFsOiB1aW50NjQKCgkvLyBjb250cmFjdHMvc3Rha2luZ1Bvb2wuYWxnby50czoxMjQKCS8vIG1pbkJhbCArPSBnbG9iYWxJbnRzICogU1NDX1ZBTFVFX1VJTlQKCWZyYW1lX2RpZyAwIC8vIG1pbkJhbDogdWludDY0CglmcmFtZV9kaWcgLTYgLy8gZ2xvYmFsSW50czogdWludDY0CglpbnQgMjg1MDAKCSoKCSsKCWZyYW1lX2J1cnkgMCAvLyBtaW5CYWw6IHVpbnQ2NAoKCS8vIGNvbnRyYWN0cy9zdGFraW5nUG9vbC5hbGdvLnRzOjEyNQoJLy8gbWluQmFsICs9IGxvY2FsQnl0ZXMgKiBTU0NfVkFMVUVfQllURVMKCWZyYW1lX2RpZyAwIC8vIG1pbkJhbDogdWludDY0CglmcmFtZV9kaWcgLTUgLy8gbG9jYWxCeXRlczogdWludDY0CglpbnQgNTAwMDAKCSoKCSsKCWZyYW1lX2J1cnkgMCAvLyBtaW5CYWw6IHVpbnQ2NAoKCS8vIGNvbnRyYWN0cy9zdGFraW5nUG9vbC5hbGdvLnRzOjEyNgoJLy8gbWluQmFsICs9IGdsb2JhbEJ5dGVzICogU1NDX1ZBTFVFX0JZVEVTCglmcmFtZV9kaWcgMCAvLyBtaW5CYWw6IHVpbnQ2NAoJZnJhbWVfZGlnIC03IC8vIGdsb2JhbEJ5dGVzOiB1aW50NjQKCWludCA1MDAwMAoJKgoJKwoJZnJhbWVfYnVyeSAwIC8vIG1pbkJhbDogdWludDY0CgoJLy8gY29udHJhY3RzL3N0YWtpbmdQb29sLmFsZ28udHM6MTI3CgkvLyByZXR1cm4gbWluQmFsOwoJZnJhbWVfZGlnIDAgLy8gbWluQmFsOiB1aW50NjQKCgkvLyBzZXQgdGhlIHN1YnJvdXRpbmUgcmV0dXJuIHZhbHVlCglmcmFtZV9idXJ5IDAKCXJldHN1YgoKLy8gY29zdEZvckJveFN0b3JhZ2UodG90YWxOdW1CeXRlczogdWludDY0KTogdWludDY0CmNvc3RGb3JCb3hTdG9yYWdlOgoJcHJvdG8gMSAxCgoJLy8gY29udHJhY3RzL3N0YWtpbmdQb29sLmFsZ28udHM6MTM0CgkvLyByZXR1cm4gU0NCT1hfUEVSQk9YICsgdG90YWxOdW1CeXRlcyAqIFNDQk9YX1BFUkJZVEU7CglpbnQgMjUwMAoJZnJhbWVfZGlnIC0xIC8vIHRvdGFsTnVtQnl0ZXM6IHVpbnQ2NAoJaW50IDQwMAoJKgoJKwoJcmV0c3ViCgovLyBpbml0U3RvcmFnZShwYXkpdm9pZAoqYWJpX3JvdXRlX2luaXRTdG9yYWdlOgoJLy8gbWJyUGF5bWVudDogcGF5Cgl0eG4gR3JvdXBJbmRleAoJaW50IDEKCS0KCWR1cAoJZ3R4bnMgVHlwZUVudW0KCWludCBwYXkKCT09Cglhc3NlcnQKCgkvLyBleGVjdXRlIGluaXRTdG9yYWdlKHBheSl2b2lkCgljYWxsc3ViIGluaXRTdG9yYWdlCglpbnQgMQoJcmV0dXJuCgovLyBpbml0U3RvcmFnZShtYnJQYXltZW50OiBQYXlUeG4pOiB2b2lkCi8vCi8vIENhbGxlZCBhZnRlciB3ZSdyZSBjcmVhdGVkIGFuZCB0aGVuIGZ1bmRlZCBzbyB3ZSBjYW4gY3JlYXRlIG91ciBsYXJnZSBzdGFrZXJzIGxlZGdlciBzdG9yYWdlCi8vIENhbGxlciBoYXMgdG8gZ2V0IE1CUiBhbW91bnRzIGZyb20gVmFsaWRhdG9yUmVnaXN0cnkgdG8ga25vdyBob3cgbXVjaCB0byBmdW5kIHVzIHRvIGNvdmVyIHRoZSBib3ggc3RvcmFnZSBjb3N0Ci8vIElmIHRoaXMgaXMgcG9vbCAxIEFORCB0aGUgdmFsaWRhdG9yIGhhcyBzcGVjaWZpZWQgYSByZXdhcmQgdG9rZW4sIG9wdC1pbiB0byB0aGF0IHRva2VuCi8vIHNvIHRoYXQgdGhlIHZhbGlkYXRvciBjYW4gc2VlZCB0aGUgcG9vbCB3aXRoIGZ1dHVyZSByZXdhcmRzIG9mIHRoYXQgdG9rZW4uCi8vIEBwYXJhbSBtYnJQYXltZW50IHBheW1lbnQgZnJvbSBjYWxsZXIgd2hpY2ggY292ZXJzIG1iciBpbmNyZWFzZSBvZiBuZXcgc3Rha2luZyBwb29scycgc3RvcmFnZQppbml0U3RvcmFnZToKCXByb3RvIDEgMAoKCS8vIFB1c2ggZW1wdHkgYnl0ZXMgYWZ0ZXIgdGhlIGZyYW1lIHBvaW50ZXIgdG8gcmVzZXJ2ZSBzcGFjZSBmb3IgbG9jYWwgdmFyaWFibGVzCglieXRlIDB4CglkdXBuIDMKCgkvLyBjb250cmFjdHMvc3Rha2luZ1Bvb2wuYWxnby50czoxNDUKCS8vIGFzc2VydCghdGhpcy5zdGFrZXJzLmV4aXN0cywgJ3N0YWtpbmcgcG9vbCBhbHJlYWR5IGluaXRpYWxpemVkJykKCWJ5dGUgMHg3Mzc0NjE2YjY1NzI3MyAvLyAic3Rha2VycyIKCWJveF9sZW4KCXN3YXAKCXBvcAoJIQoKCS8vIHN0YWtpbmcgcG9vbCBhbHJlYWR5IGluaXRpYWxpemVkCglhc3NlcnQKCgkvLyBjb250cmFjdHMvc3Rha2luZ1Bvb2wuYWxnby50czoxNDgKCS8vIHZhbGlkYXRvckNvbmZpZyA9IHNlbmRNZXRob2RDYWxsPHR5cGVvZiBWYWxpZGF0b3JSZWdpc3RyeS5wcm90b3R5cGUuZ2V0VmFsaWRhdG9yQ29uZmlnPih7CgkvLyAgICAgICAgICAgICBhcHBsaWNhdGlvbklEOiBBcHBJRC5mcm9tVWludDY0KHRoaXMuY3JlYXRpbmdWYWxpZGF0b3JDb250cmFjdEFwcElkLnZhbHVlKSwKCS8vICAgICAgICAgICAgIG1ldGhvZEFyZ3M6IFt0aGlzLnZhbGlkYXRvcklkLnZhbHVlXSwKCS8vICAgICAgICAgfSkKCWl0eG5fYmVnaW4KCWludCBhcHBsCglpdHhuX2ZpZWxkIFR5cGVFbnVtCgltZXRob2QgImdldFZhbGlkYXRvckNvbmZpZyh1aW50NjQpKHVpbnQ2NCxhZGRyZXNzLGFkZHJlc3MsdWludDY0LHVpbnQ4LGJ5dGVbMzJdLHVpbnQ2NCx1aW50NjQsdWludDY0LHVpbnQxNix1aW50MzIsYWRkcmVzcyx1aW50NjQsdWludDY0LHVpbnQ4LHVpbnQ2NCx1aW50NjQpIgoJaXR4bl9maWVsZCBBcHBsaWNhdGlvbkFyZ3MKCgkvLyBjb250cmFjdHMvc3Rha2luZ1Bvb2wuYWxnby50czoxNDkKCS8vIGFwcGxpY2F0aW9uSUQ6IEFwcElELmZyb21VaW50NjQodGhpcy5jcmVhdGluZ1ZhbGlkYXRvckNvbnRyYWN0QXBwSWQudmFsdWUpCglieXRlIDB4NjM3MjY1NjE3NDZmNzI0MTcwNzAgLy8gImNyZWF0b3JBcHAiCglhcHBfZ2xvYmFsX2dldAoJaXR4bl9maWVsZCBBcHBsaWNhdGlvbklECgoJLy8gY29udHJhY3RzL3N0YWtpbmdQb29sLmFsZ28udHM6MTUwCgkvLyBtZXRob2RBcmdzOiBbdGhpcy52YWxpZGF0b3JJZC52YWx1ZV0KCWJ5dGUgMHg3NjYxNmM2OTY0NjE3NDZmNzI0OTY0IC8vICJ2YWxpZGF0b3JJZCIKCWFwcF9nbG9iYWxfZ2V0CglpdG9iCglpdHhuX2ZpZWxkIEFwcGxpY2F0aW9uQXJncwoKCS8vIEZlZSBmaWVsZCBub3Qgc2V0LCBkZWZhdWx0aW5nIHRvIDAKCWludCAwCglpdHhuX2ZpZWxkIEZlZQoKCS8vIFN1Ym1pdCBpbm5lciB0cmFuc2FjdGlvbgoJaXR4bl9zdWJtaXQKCWl0eG4gTnVtTG9ncwoJaW50IDEKCS0KCWl0eG5hcyBMb2dzCglleHRyYWN0IDQgMAoJZnJhbWVfYnVyeSAwIC8vIHZhbGlkYXRvckNvbmZpZzogKHVpbnQ2NCxhZGRyZXNzLGFkZHJlc3MsdWludDY0LHVpbnQ4LGJ5dGVbMzJdLHVpbnQ2NCx1aW50NjQsdWludDY0LHVpbnQxNix1aW50MzIsYWRkcmVzcyx1aW50NjQsdWludDY0LHVpbnQ4LHVpbnQ2NCx1aW50NjQpCgoJLy8gY29udHJhY3RzL3N0YWtpbmdQb29sLmFsZ28udHM6MTUyCgkvLyBpc1Rva2VuRWxpZ2libGUgPSB2YWxpZGF0b3JDb25maWcucmV3YXJkVG9rZW5JZCAhPT0gMAoJZnJhbWVfZGlnIDAgLy8gdmFsaWRhdG9yQ29uZmlnOiAodWludDY0LGFkZHJlc3MsYWRkcmVzcyx1aW50NjQsdWludDgsYnl0ZVszMl0sdWludDY0LHVpbnQ2NCx1aW50NjQsdWludDE2LHVpbnQzMixhZGRyZXNzLHVpbnQ2NCx1aW50NjQsdWludDgsdWludDY0LHVpbnQ2NCkKCWV4dHJhY3QgMTIxIDgKCWJ0b2kKCWludCAwCgkhPQoJZnJhbWVfYnVyeSAxIC8vIGlzVG9rZW5FbGlnaWJsZTogYm9vbAoKCS8vIGNvbnRyYWN0cy9zdGFraW5nUG9vbC5hbGdvLnRzOjE1MwoJLy8gZXh0cmFNQlIgPSBpc1Rva2VuRWxpZ2libGUgJiYgdGhpcy5wb29sSWQudmFsdWUgPT09IDEgPyBBU1NFVF9IT0xESU5HX0ZFRSA6IDAKCWZyYW1lX2RpZyAxIC8vIGlzVG9rZW5FbGlnaWJsZTogYm9vbAoJZHVwCglieiAqc2tpcF9hbmQxCglieXRlIDB4NzA2ZjZmNmM0OTY0IC8vICJwb29sSWQiCglhcHBfZ2xvYmFsX2dldAoJaW50IDEKCT09CgkmJgoKKnNraXBfYW5kMToKCWJ6ICp0ZXJuYXJ5MV9mYWxzZQoJaW50IDEwMDAwMAoJYiAqdGVybmFyeTFfZW5kCgoqdGVybmFyeTFfZmFsc2U6CglpbnQgMAoKKnRlcm5hcnkxX2VuZDoKCWZyYW1lX2J1cnkgMiAvLyBleHRyYU1CUjogdWludDY0CgoJLy8gY29udHJhY3RzL3N0YWtpbmdQb29sLmFsZ28udHM6MTU0CgkvLyBQb29sSW5pdE1iciA9CgkvLyAgICAgICAgICAgICBBTEdPUkFORF9BQ0NPVU5UX01JTl9CQUxBTkNFICsKCS8vICAgICAgICAgICAgIGV4dHJhTUJSICsKCS8vICAgICAgICAgICAgIHRoaXMuY29zdEZvckJveFN0b3JhZ2UoNyAvKiAnc3Rha2VycycgbmFtZSAqLyArIGxlbjxTdGFrZWRJbmZvPigpICogTUFYX1NUQUtFUlNfUEVSX1BPT0wpCglpbnQgMTAwMDAwCglmcmFtZV9kaWcgMiAvLyBleHRyYU1CUjogdWludDY0CgkrCglpbnQgMTI4MDcKCWNhbGxzdWIgY29zdEZvckJveFN0b3JhZ2UKCSsKCWZyYW1lX2J1cnkgMyAvLyBQb29sSW5pdE1icjogdWludDY0CgoJLy8gY29udHJhY3RzL3N0YWtpbmdQb29sLmFsZ28udHM6MTYwCgkvLyB2ZXJpZnlQYXlUeG4obWJyUGF5bWVudCwgeyBhbW91bnQ6IFBvb2xJbml0TWJyIH0pCgkvLyB2ZXJpZnkgYW1vdW50CglmcmFtZV9kaWcgLTEgLy8gbWJyUGF5bWVudDogUGF5VHhuCglndHhucyBBbW91bnQKCWZyYW1lX2RpZyAzIC8vIFBvb2xJbml0TWJyOiB1aW50NjQKCT09Cglhc3NlcnQKCgkvLyBjb250cmFjdHMvc3Rha2luZ1Bvb2wuYWxnby50czoxNjEKCS8vIHRoaXMuc3Rha2Vycy5jcmVhdGUoKQoJYnl0ZSAweDczNzQ2MTZiNjU3MjczIC8vICJzdGFrZXJzIgoJaW50IDEyODAwCglib3hfY3JlYXRlCglwb3AKCgkvLyAqaWYxX2NvbmRpdGlvbgoJLy8gY29udHJhY3RzL3N0YWtpbmdQb29sLmFsZ28udHM6MTYzCgkvLyBpc1Rva2VuRWxpZ2libGUgJiYgdGhpcy5wb29sSWQudmFsdWUgPT09IDEKCWZyYW1lX2RpZyAxIC8vIGlzVG9rZW5FbGlnaWJsZTogYm9vbAoJZHVwCglieiAqc2tpcF9hbmQyCglieXRlIDB4NzA2ZjZmNmM0OTY0IC8vICJwb29sSWQiCglhcHBfZ2xvYmFsX2dldAoJaW50IDEKCT09CgkmJgoKKnNraXBfYW5kMjoKCWJ6ICppZjFfZW5kCgoJLy8gKmlmMV9jb25zZXF1ZW50CgkvLyBjb250cmFjdHMvc3Rha2luZ1Bvb2wuYWxnby50czoxNjUKCS8vIHNlbmRBc3NldFRyYW5zZmVyKHsKCS8vICAgICAgICAgICAgICAgICB4ZmVyQXNzZXQ6IEFzc2V0SUQuZnJvbVVpbnQ2NCh2YWxpZGF0b3JDb25maWcucmV3YXJkVG9rZW5JZCksCgkvLyAgICAgICAgICAgICAgICAgYXNzZXRSZWNlaXZlcjogdGhpcy5hcHAuYWRkcmVzcywKCS8vICAgICAgICAgICAgICAgICBhc3NldEFtb3VudDogMCwKCS8vICAgICAgICAgICAgIH0pCglpdHhuX2JlZ2luCglpbnQgYXhmZXIKCWl0eG5fZmllbGQgVHlwZUVudW0KCgkvLyBjb250cmFjdHMvc3Rha2luZ1Bvb2wuYWxnby50czoxNjYKCS8vIHhmZXJBc3NldDogQXNzZXRJRC5mcm9tVWludDY0KHZhbGlkYXRvckNvbmZpZy5yZXdhcmRUb2tlbklkKQoJZnJhbWVfZGlnIDAgLy8gdmFsaWRhdG9yQ29uZmlnOiAodWludDY0LGFkZHJlc3MsYWRkcmVzcyx1aW50NjQsdWludDgsYnl0ZVszMl0sdWludDY0LHVpbnQ2NCx1aW50NjQsdWludDE2LHVpbnQzMixhZGRyZXNzLHVpbnQ2NCx1aW50NjQsdWludDgsdWludDY0LHVpbnQ2NCkKCWV4dHJhY3QgMTIxIDgKCWJ0b2kKCWl0eG5fZmllbGQgWGZlckFzc2V0CgoJLy8gY29udHJhY3RzL3N0YWtpbmdQb29sLmFsZ28udHM6MTY3CgkvLyBhc3NldFJlY2VpdmVyOiB0aGlzLmFwcC5hZGRyZXNzCglnbG9iYWwgQ3VycmVudEFwcGxpY2F0aW9uQWRkcmVzcwoJaXR4bl9maWVsZCBBc3NldFJlY2VpdmVyCgoJLy8gY29udHJhY3RzL3N0YWtpbmdQb29sLmFsZ28udHM6MTY4CgkvLyBhc3NldEFtb3VudDogMAoJaW50IDAKCWl0eG5fZmllbGQgQXNzZXRBbW91bnQKCgkvLyBGZWUgZmllbGQgbm90IHNldCwgZGVmYXVsdGluZyB0byAwCglpbnQgMAoJaXR4bl9maWVsZCBGZWUKCgkvLyBTdWJtaXQgaW5uZXIgdHJhbnNhY3Rpb24KCWl0eG5fc3VibWl0CgoqaWYxX2VuZDoKCXJldHN1YgoKLy8gYWRkU3Rha2UocGF5LGFkZHJlc3MpdWludDY0CiphYmlfcm91dGVfYWRkU3Rha2U6CgkvLyBUaGUgQUJJIHJldHVybiBwcmVmaXgKCWJ5dGUgMHgxNTFmN2M3NQoKCS8vIHN0YWtlcjogYWRkcmVzcwoJdHhuYSBBcHBsaWNhdGlvbkFyZ3MgMQoJZHVwCglsZW4KCWludCAzMgoJPT0KCWFzc2VydAoKCS8vIHN0YWtlZEFtb3VudFBheW1lbnQ6IHBheQoJdHhuIEdyb3VwSW5kZXgKCWludCAxCgktCglkdXAKCWd0eG5zIFR5cGVFbnVtCglpbnQgcGF5Cgk9PQoJYXNzZXJ0CgoJLy8gZXhlY3V0ZSBhZGRTdGFrZShwYXksYWRkcmVzcyl1aW50NjQKCWNhbGxzdWIgYWRkU3Rha2UKCWl0b2IKCWNvbmNhdAoJbG9nCglpbnQgMQoJcmV0dXJuCgovLyBhZGRTdGFrZShzdGFrZWRBbW91bnRQYXltZW50OiBQYXlUeG4sIHN0YWtlcjogQWRkcmVzcyk6IHVpbnQ2NAovLwovLyBBZGRzIHN0YWtlIHRvIHRoZSBnaXZlbiBhY2NvdW50LgovLyBDYW4gT05MWSBiZSBjYWxsZWQgYnkgdGhlIHZhbGlkYXRvciBjb250cmFjdCB0aGF0IGNyZWF0ZWQgdXMKLy8gTXVzdCByZWNlaXZlIHBheW1lbnQgZnJvbSB0aGUgdmFsaWRhdG9yIGNvbnRyYWN0IGZvciBhbW91bnQgYmVpbmcgc3Rha2VkLgovLwovLyBAcGFyYW0ge1BheVR4bn0gc3Rha2VkQW1vdW50UGF5bWVudCBwcmlvciBwYXltZW50IGNvbWluZyBmcm9tIHZhbGlkYXRvciBjb250cmFjdCB0byB1cyBvbiBiZWhhbGYgb2Ygc3Rha2VyLgovLyBAcGFyYW0ge0FkZHJlc3N9IHN0YWtlciAtIFRoZSBhY2NvdW50IGFkZGluZyBuZXcgc3Rha2UKLy8gQHRocm93cyB7RXJyb3J9IC0gVGhyb3dzIGFuIGVycm9yIGlmIHRoZSBzdGFraW5nIHBvb2wgaXMgZnVsbC4KLy8gQHJldHVybnMge3VpbnQ2NH0gbmV3ICdlbnRyeSB0aW1lJyBpbiBzZWNvbmRzIG9mIHN0YWtlIGFkZC4KYWRkU3Rha2U6Cglwcm90byAyIDEKCgkvLyBQdXNoIGVtcHR5IGJ5dGVzIGFmdGVyIHRoZSBmcmFtZSBwb2ludGVyIHRvIHJlc2VydmUgc3BhY2UgZm9yIGxvY2FsIHZhcmlhYmxlcwoJYnl0ZSAweAoJZHVwbiAzCgoJLy8gY29udHJhY3RzL3N0YWtpbmdQb29sLmFsZ28udHM6MTg0CgkvLyBhc3NlcnQodGhpcy5zdGFrZXJzLmV4aXN0cykKCWJ5dGUgMHg3Mzc0NjE2YjY1NzI3MyAvLyAic3Rha2VycyIKCWJveF9sZW4KCXN3YXAKCXBvcAoJYXNzZXJ0CgoJLy8gY29udHJhY3RzL3N0YWtpbmdQb29sLmFsZ28udHM6MTg3CgkvLyBhc3NlcnQodGhpcy50eG4uc2VuZGVyID09PSBBcHBJRC5mcm9tVWludDY0KHRoaXMuY3JlYXRpbmdWYWxpZGF0b3JDb250cmFjdEFwcElkLnZhbHVlKS5hZGRyZXNzKQoJdHhuIFNlbmRlcgoJYnl0ZSAweDYzNzI2NTYxNzQ2ZjcyNDE3MDcwIC8vICJjcmVhdG9yQXBwIgoJYXBwX2dsb2JhbF9nZXQKCWFwcF9wYXJhbXNfZ2V0IEFwcEFkZHJlc3MKCXBvcAoJPT0KCWFzc2VydAoKCS8vIGNvbnRyYWN0cy9zdGFraW5nUG9vbC5hbGdvLnRzOjE4OAoJLy8gYXNzZXJ0KHN0YWtlciAhPT0gZ2xvYmFscy56ZXJvQWRkcmVzcykKCWZyYW1lX2RpZyAtMiAvLyBzdGFrZXI6IEFkZHJlc3MKCWdsb2JhbCBaZXJvQWRkcmVzcwoJIT0KCWFzc2VydAoKCS8vIGNvbnRyYWN0cy9zdGFraW5nUG9vbC5hbGdvLnRzOjE5MgoJLy8gdmVyaWZ5UGF5VHhuKHN0YWtlZEFtb3VudFBheW1lbnQsIHsKCS8vICAgICAgICAgICAgIHNlbmRlcjogQXBwSUQuZnJvbVVpbnQ2NCh0aGlzLmNyZWF0aW5nVmFsaWRhdG9yQ29udHJhY3RBcHBJZC52YWx1ZSkuYWRkcmVzcywKCS8vICAgICAgICAgICAgIHJlY2VpdmVyOiB0aGlzLmFwcC5hZGRyZXNzLAoJLy8gICAgICAgICAgICAgYW1vdW50OiBzdGFrZWRBbW91bnRQYXltZW50LmFtb3VudCwKCS8vICAgICAgICAgfSkKCS8vIHZlcmlmeSBzZW5kZXIKCWZyYW1lX2RpZyAtMSAvLyBzdGFrZWRBbW91bnRQYXltZW50OiBQYXlUeG4KCWd0eG5zIFNlbmRlcgoJYnl0ZSAweDYzNzI2NTYxNzQ2ZjcyNDE3MDcwIC8vICJjcmVhdG9yQXBwIgoJYXBwX2dsb2JhbF9nZXQKCWFwcF9wYXJhbXNfZ2V0IEFwcEFkZHJlc3MKCXBvcAoJPT0KCWFzc2VydAoKCS8vIHZlcmlmeSByZWNlaXZlcgoJZnJhbWVfZGlnIC0xIC8vIHN0YWtlZEFtb3VudFBheW1lbnQ6IFBheVR4bgoJZ3R4bnMgUmVjZWl2ZXIKCWdsb2JhbCBDdXJyZW50QXBwbGljYXRpb25BZGRyZXNzCgk9PQoJYXNzZXJ0CgoJLy8gdmVyaWZ5IGFtb3VudAoJZnJhbWVfZGlnIC0xIC8vIHN0YWtlZEFtb3VudFBheW1lbnQ6IFBheVR4bgoJZ3R4bnMgQW1vdW50CglmcmFtZV9kaWcgLTEgLy8gc3Rha2VkQW1vdW50UGF5bWVudDogUGF5VHhuCglndHhucyBBbW91bnQKCT09Cglhc3NlcnQKCgkvLyBjb250cmFjdHMvc3Rha2luZ1Bvb2wuYWxnby50czoyMDEKCS8vIGVudHJ5VGltZSA9IHRoaXMuZ2V0RW50cnlUaW1lKCkKCWNhbGxzdWIgZ2V0RW50cnlUaW1lCglmcmFtZV9idXJ5IDAgLy8gZW50cnlUaW1lOiB1aW50NjQKCgkvLyBjb250cmFjdHMvc3Rha2luZ1Bvb2wuYWxnby50czoyMDIKCS8vIGZpcnN0RW1wdHkgPSAwCglpbnQgMAoJZnJhbWVfYnVyeSAxIC8vIGZpcnN0RW1wdHk6IHVpbnQ2NAoKCS8vIGNvbnRyYWN0cy9zdGFraW5nUG9vbC5hbGdvLnRzOjIwNQoJLy8gZm9yIChsZXQgaSA9IDA7IGkgPCB0aGlzLnN0YWtlcnMudmFsdWUubGVuZ3RoOyBpICs9IDEpCglpbnQgMAoJZnJhbWVfYnVyeSAyIC8vIGk6IHVpbnQ2NAoKKmZvcl8wOgoJLy8gY29udHJhY3RzL3N0YWtpbmdQb29sLmFsZ28udHM6MjA1CgkvLyBpIDwgdGhpcy5zdGFrZXJzLnZhbHVlLmxlbmd0aAoJZnJhbWVfZGlnIDIgLy8gaTogdWludDY0CglpbnQgMjAwCgk8CglieiAqZm9yXzBfZW5kCgoJLy8gKmlmMl9jb25kaXRpb24KCS8vIGNvbnRyYWN0cy9zdGFraW5nUG9vbC5hbGdvLnRzOjIwNgoJLy8gZ2xvYmFscy5vcGNvZGVCdWRnZXQgPCAzMDAKCWdsb2JhbCBPcGNvZGVCdWRnZXQKCWludCAzMDAKCTwKCWJ6ICppZjJfZW5kCgoJLy8gKmlmMl9jb25zZXF1ZW50CgkvLyBjb250cmFjdHMvc3Rha2luZ1Bvb2wuYWxnby50czoyMDcKCS8vIGluY3JlYXNlT3Bjb2RlQnVkZ2V0KCkKCWl0eG5fYmVnaW4KCWludCBhcHBsCglpdHhuX2ZpZWxkIFR5cGVFbnVtCglpbnQgMAoJaXR4bl9maWVsZCBGZWUKCWJ5dGUgYjY0IENvRUIgLy8gI3ByYWdtYSB2ZXJzaW9uIDEwOyBpbnQgMQoJZHVwCglpdHhuX2ZpZWxkIEFwcHJvdmFsUHJvZ3JhbQoJaXR4bl9maWVsZCBDbGVhclN0YXRlUHJvZ3JhbQoJaW50IERlbGV0ZUFwcGxpY2F0aW9uCglpdHhuX2ZpZWxkIE9uQ29tcGxldGlvbgoJaXR4bl9zdWJtaXQKCippZjJfZW5kOgoJLy8gY29udHJhY3RzL3N0YWtpbmdQb29sLmFsZ28udHM6MjA5CgkvLyBjbXBTdGFrZXIgPSBjbG9uZSh0aGlzLnN0YWtlcnMudmFsdWVbaV0pCglmcmFtZV9kaWcgMiAvLyBpOiB1aW50NjQKCWludCA2NAoJKiAvLyBhY2MgKiB0eXBlTGVuZ3RoCglpbnQgNjQKCWJ5dGUgMHg3Mzc0NjE2YjY1NzI3MyAvLyAic3Rha2VycyIKCWNvdmVyIDIKCWJveF9leHRyYWN0CglmcmFtZV9idXJ5IDMgLy8gY21wU3Rha2VyOiAoYWRkcmVzcyx1aW50NjQsdWludDY0LHVpbnQ2NCx1aW50NjQpCgoJLy8gKmlmM19jb25kaXRpb24KCS8vIGNvbnRyYWN0cy9zdGFraW5nUG9vbC5hbGdvLnRzOjIxMAoJLy8gY21wU3Rha2VyLmFjY291bnQgPT09IHN0YWtlcgoJZnJhbWVfZGlnIDMgLy8gY21wU3Rha2VyOiAoYWRkcmVzcyx1aW50NjQsdWludDY0LHVpbnQ2NCx1aW50NjQpCglleHRyYWN0IDAgMzIKCWZyYW1lX2RpZyAtMiAvLyBzdGFrZXI6IEFkZHJlc3MKCT09CglieiAqaWYzX2VuZAoKCS8vICppZjNfY29uc2VxdWVudAoJLy8gY29udHJhY3RzL3N0YWtpbmdQb29sLmFsZ28udHM6MjExCgkvLyBjbXBTdGFrZXIuYmFsYW5jZSArPSBzdGFrZWRBbW91bnRQYXltZW50LmFtb3VudAoJZnJhbWVfZGlnIDMgLy8gY21wU3Rha2VyOiAoYWRkcmVzcyx1aW50NjQsdWludDY0LHVpbnQ2NCx1aW50NjQpCglpbnQgMzIgLy8gaGVhZE9mZnNldAoJZnJhbWVfZGlnIDMgLy8gY21wU3Rha2VyOiAoYWRkcmVzcyx1aW50NjQsdWludDY0LHVpbnQ2NCx1aW50NjQpCglleHRyYWN0IDMyIDgKCWJ0b2kKCWZyYW1lX2RpZyAtMSAvLyBzdGFrZWRBbW91bnRQYXltZW50OiBQYXlUeG4KCWd0eG5zIEFtb3VudAoJKwoJaXRvYgoJcmVwbGFjZTMKCWZyYW1lX2J1cnkgMyAvLyBjbXBTdGFrZXI6IChhZGRyZXNzLHVpbnQ2NCx1aW50NjQsdWludDY0LHVpbnQ2NCkKCgkvLyBjb250cmFjdHMvc3Rha2luZ1Bvb2wuYWxnby50czoyMTIKCS8vIGNtcFN0YWtlci5lbnRyeVRpbWUgPSBlbnRyeVRpbWUKCWZyYW1lX2RpZyAzIC8vIGNtcFN0YWtlcjogKGFkZHJlc3MsdWludDY0LHVpbnQ2NCx1aW50NjQsdWludDY0KQoJaW50IDU2IC8vIGhlYWRPZmZzZXQKCWZyYW1lX2RpZyAwIC8vIGVudHJ5VGltZTogdWludDY0CglpdG9iCglyZXBsYWNlMwoJZnJhbWVfYnVyeSAzIC8vIGNtcFN0YWtlcjogKGFkZHJlc3MsdWludDY0LHVpbnQ2NCx1aW50NjQsdWludDY0KQoKCS8vIGNvbnRyYWN0cy9zdGFraW5nUG9vbC5hbGdvLnRzOjIxNQoJLy8gdGhpcy5zdGFrZXJzLnZhbHVlW2ldID0gY21wU3Rha2VyCglmcmFtZV9kaWcgMiAvLyBpOiB1aW50NjQKCWludCA2NAoJKiAvLyBhY2MgKiB0eXBlTGVuZ3RoCglmcmFtZV9kaWcgMyAvLyBjbXBTdGFrZXI6IChhZGRyZXNzLHVpbnQ2NCx1aW50NjQsdWludDY0LHVpbnQ2NCkKCWJ5dGUgMHg3Mzc0NjE2YjY1NzI3MyAvLyAic3Rha2VycyIKCWNvdmVyIDIKCWJveF9yZXBsYWNlCgoJLy8gY29udHJhY3RzL3N0YWtpbmdQb29sLmFsZ28udHM6MjE3CgkvLyB0aGlzLnRvdGFsQWxnb1N0YWtlZC52YWx1ZSArPSBzdGFrZWRBbW91bnRQYXltZW50LmFtb3VudAoJYnl0ZSAweDczNzQ2MTZiNjU2NCAvLyAic3Rha2VkIgoJYXBwX2dsb2JhbF9nZXQKCWZyYW1lX2RpZyAtMSAvLyBzdGFrZWRBbW91bnRQYXltZW50OiBQYXlUeG4KCWd0eG5zIEFtb3VudAoJKwoJYnl0ZSAweDczNzQ2MTZiNjU2NCAvLyAic3Rha2VkIgoJc3dhcAoJYXBwX2dsb2JhbF9wdXQKCgkvLyBjb250cmFjdHMvc3Rha2luZ1Bvb2wuYWxnby50czoyMTgKCS8vIHJldHVybiBlbnRyeVRpbWU7CglmcmFtZV9kaWcgMCAvLyBlbnRyeVRpbWU6IHVpbnQ2NAoKCS8vIHNldCB0aGUgc3Vicm91dGluZSByZXR1cm4gdmFsdWUKCWZyYW1lX2J1cnkgMAoKCS8vIHBvcCBhbGwgbG9jYWwgdmFyaWFibGVzIGZyb20gdGhlIHN0YWNrCglwb3BuIDMKCXJldHN1YgoKKmlmM19lbmQ6CgkvLyAqaWY0X2NvbmRpdGlvbgoJLy8gY29udHJhY3RzL3N0YWtpbmdQb29sLmFsZ28udHM6MjIwCgkvLyBjbXBTdGFrZXIuYWNjb3VudCA9PT0gZ2xvYmFscy56ZXJvQWRkcmVzcwoJZnJhbWVfZGlnIDMgLy8gY21wU3Rha2VyOiAoYWRkcmVzcyx1aW50NjQsdWludDY0LHVpbnQ2NCx1aW50NjQpCglleHRyYWN0IDAgMzIKCWdsb2JhbCBaZXJvQWRkcmVzcwoJPT0KCWJ6ICppZjRfZW5kCgoJLy8gKmlmNF9jb25zZXF1ZW50CgkvLyBjb250cmFjdHMvc3Rha2luZ1Bvb2wuYWxnby50czoyMjEKCS8vIGZpcnN0RW1wdHkgPSBpICsgMQoJZnJhbWVfZGlnIDIgLy8gaTogdWludDY0CglpbnQgMQoJKwoJZnJhbWVfYnVyeSAxIC8vIGZpcnN0RW1wdHk6IHVpbnQ2NAoJYiAqZm9yXzBfZW5kCgoqaWY0X2VuZDoKCipmb3JfMF9jb250aW51ZToKCS8vIGNvbnRyYWN0cy9zdGFraW5nUG9vbC5hbGdvLnRzOjIwNQoJLy8gaSArPSAxCglmcmFtZV9kaWcgMiAvLyBpOiB1aW50NjQKCWludCAxCgkrCglmcmFtZV9idXJ5IDIgLy8gaTogdWludDY0CgliICpmb3JfMAoKKmZvcl8wX2VuZDoKCS8vICppZjVfY29uZGl0aW9uCgkvLyBjb250cmFjdHMvc3Rha2luZ1Bvb2wuYWxnby50czoyMjYKCS8vIGZpcnN0RW1wdHkgPT09IDAKCWZyYW1lX2RpZyAxIC8vIGZpcnN0RW1wdHk6IHVpbnQ2NAoJaW50IDAKCT09CglieiAqaWY1X2VuZAoKCS8vICppZjVfY29uc2VxdWVudAoJZXJyIC8vICdTdGFraW5nIHBvb2wgZnVsbCcKCippZjVfZW5kOgoJLy8gY29udHJhY3RzL3N0YWtpbmdQb29sLmFsZ28udHM6MjMzCgkvLyBhc3NlcnQoc3Rha2VkQW1vdW50UGF5bWVudC5hbW91bnQgPj0gdGhpcy5taW5FbnRyeVN0YWtlLnZhbHVlLCAnbXVzdCBzdGFrZSBhdCBsZWFzdCB0aGUgbWluaW11bSBmb3IgdGhpcyBwb29sJykKCWZyYW1lX2RpZyAtMSAvLyBzdGFrZWRBbW91bnRQYXltZW50OiBQYXlUeG4KCWd0eG5zIEFtb3VudAoJYnl0ZSAweDZkNjk2ZTQ1NmU3NDcyNzk1Mzc0NjE2YjY1IC8vICJtaW5FbnRyeVN0YWtlIgoJYXBwX2dsb2JhbF9nZXQKCT49CgoJLy8gbXVzdCBzdGFrZSBhdCBsZWFzdCB0aGUgbWluaW11bSBmb3IgdGhpcyBwb29sCglhc3NlcnQKCgkvLyBjb250cmFjdHMvc3Rha2luZ1Bvb2wuYWxnby50czoyMzUKCS8vIGFzc2VydCh0aGlzLnN0YWtlcnMudmFsdWVbZmlyc3RFbXB0eSAtIDFdLmFjY291bnQgPT09IGdsb2JhbHMuemVyb0FkZHJlc3MpCglmcmFtZV9kaWcgMSAvLyBmaXJzdEVtcHR5OiB1aW50NjQKCWludCAxCgktCglpbnQgNjQKCSogLy8gYWNjICogdHlwZUxlbmd0aAoJaW50IDAKCSsKCWludCAzMgoJYnl0ZSAweDczNzQ2MTZiNjU3MjczIC8vICJzdGFrZXJzIgoJY292ZXIgMgoJYm94X2V4dHJhY3QKCWdsb2JhbCBaZXJvQWRkcmVzcwoJPT0KCWFzc2VydAoKCS8vIGNvbnRyYWN0cy9zdGFraW5nUG9vbC5hbGdvLnRzOjIzNgoJLy8gdGhpcy5zdGFrZXJzLnZhbHVlW2ZpcnN0RW1wdHkgLSAxXSA9IHsKCS8vICAgICAgICAgICAgIGFjY291bnQ6IHN0YWtlciwKCS8vICAgICAgICAgICAgIGJhbGFuY2U6IHN0YWtlZEFtb3VudFBheW1lbnQuYW1vdW50LAoJLy8gICAgICAgICAgICAgdG90YWxSZXdhcmRlZDogMCwKCS8vICAgICAgICAgICAgIHJld2FyZFRva2VuQmFsYW5jZTogMCwKCS8vICAgICAgICAgICAgIGVudHJ5VGltZTogZW50cnlUaW1lLAoJLy8gICAgICAgICB9CglmcmFtZV9kaWcgMSAvLyBmaXJzdEVtcHR5OiB1aW50NjQKCWludCAxCgktCglpbnQgNjQKCSogLy8gYWNjICogdHlwZUxlbmd0aAoJZnJhbWVfZGlnIC0yIC8vIHN0YWtlcjogQWRkcmVzcwoJZnJhbWVfZGlnIC0xIC8vIHN0YWtlZEFtb3VudFBheW1lbnQ6IFBheVR4bgoJZ3R4bnMgQW1vdW50CglpdG9iCgljb25jYXQKCWJ5dGUgMHgwMDAwMDAwMDAwMDAwMDAwCgljb25jYXQKCWJ5dGUgMHgwMDAwMDAwMDAwMDAwMDAwCgljb25jYXQKCWZyYW1lX2RpZyAwIC8vIGVudHJ5VGltZTogdWludDY0CglpdG9iCgljb25jYXQKCWJ5dGUgMHg3Mzc0NjE2YjY1NzI3MyAvLyAic3Rha2VycyIKCWNvdmVyIDIKCWJveF9yZXBsYWNlCgoJLy8gY29udHJhY3RzL3N0YWtpbmdQb29sLmFsZ28udHM6MjQzCgkvLyB0aGlzLm51bVN0YWtlcnMudmFsdWUgKz0gMQoJYnl0ZSAweDZlNzU2ZDUzNzQ2MTZiNjU3MjczIC8vICJudW1TdGFrZXJzIgoJYXBwX2dsb2JhbF9nZXQKCWludCAxCgkrCglieXRlIDB4NmU3NTZkNTM3NDYxNmI2NTcyNzMgLy8gIm51bVN0YWtlcnMiCglzd2FwCglhcHBfZ2xvYmFsX3B1dAoKCS8vIGNvbnRyYWN0cy9zdGFraW5nUG9vbC5hbGdvLnRzOjI0NAoJLy8gdGhpcy50b3RhbEFsZ29TdGFrZWQudmFsdWUgKz0gc3Rha2VkQW1vdW50UGF5bWVudC5hbW91bnQKCWJ5dGUgMHg3Mzc0NjE2YjY1NjQgLy8gInN0YWtlZCIKCWFwcF9nbG9iYWxfZ2V0CglmcmFtZV9kaWcgLTEgLy8gc3Rha2VkQW1vdW50UGF5bWVudDogUGF5VHhuCglndHhucyBBbW91bnQKCSsKCWJ5dGUgMHg3Mzc0NjE2YjY1NjQgLy8gInN0YWtlZCIKCXN3YXAKCWFwcF9nbG9iYWxfcHV0CgoJLy8gY29udHJhY3RzL3N0YWtpbmdQb29sLmFsZ28udHM6MjQ1CgkvLyByZXR1cm4gZW50cnlUaW1lOwoJZnJhbWVfZGlnIDAgLy8gZW50cnlUaW1lOiB1aW50NjQKCgkvLyBzZXQgdGhlIHN1YnJvdXRpbmUgcmV0dXJuIHZhbHVlCglmcmFtZV9idXJ5IDAKCgkvLyBwb3AgYWxsIGxvY2FsIHZhcmlhYmxlcyBmcm9tIHRoZSBzdGFjawoJcG9wbiAzCglyZXRzdWIKCi8vIHJlbW92ZVN0YWtlKHVpbnQ2NCl2b2lkCiphYmlfcm91dGVfcmVtb3ZlU3Rha2U6CgkvLyBhbW91bnRUb1Vuc3Rha2U6IHVpbnQ2NAoJdHhuYSBBcHBsaWNhdGlvbkFyZ3MgMQoJYnRvaQoKCS8vIGV4ZWN1dGUgcmVtb3ZlU3Rha2UodWludDY0KXZvaWQKCWNhbGxzdWIgcmVtb3ZlU3Rha2UKCWludCAxCglyZXR1cm4KCi8vIHJlbW92ZVN0YWtlKGFtb3VudFRvVW5zdGFrZTogdWludDY0KTogdm9pZAovLwovLyBSZW1vdmVzIHN0YWtlIG9uIGJlaGFsZiBvZiBjYWxsZXIgKHJlbW92aW5nIG93biBzdGFrZSkuICBJZiBhbnkgdG9rZW4gcmV3YXJkcyBleGlzdCwgdGhvc2UgYXJlIGFsd2F5cyBzZW50IGluCi8vIGZ1bGwuIEFsc28gbm90aWZpZXMgdGhlIHZhbGlkYXRvciBjb250cmFjdCBmb3IgdGhpcyBwb29scyB2YWxpZGF0b3Igb2YgdGhlIHN0YWtlciAvIGJhbGFuY2UgY2hhbmdlcy4KLy8KLy8gQHBhcmFtIHt1aW50NjR9IGFtb3VudFRvVW5zdGFrZSAtIFRoZSBhbW91bnQgb2Ygc3Rha2UgdG8gYmUgcmVtb3ZlZC4gIFNwZWNpZnkgMCB0byByZW1vdmUgYWxsIHN0YWtlLgovLyBAdGhyb3dzIHtFcnJvcn0gSWYgdGhlIGFjY291bnQgaGFzIGluc3VmZmljaWVudCBiYWxhbmNlIG9yIGlmIHRoZSBhY2NvdW50IGlzIG5vdCBmb3VuZC4KcmVtb3ZlU3Rha2U6Cglwcm90byAxIDAKCgkvLyBQdXNoIGVtcHR5IGJ5dGVzIGFmdGVyIHRoZSBmcmFtZSBwb2ludGVyIHRvIHJlc2VydmUgc3BhY2UgZm9yIGxvY2FsIHZhcmlhYmxlcwoJYnl0ZSAweAoJZHVwbiA1CgoJLy8gY29udHJhY3RzL3N0YWtpbmdQb29sLmFsZ28udHM6MjU5CgkvLyBzdGFrZXIgPSB0aGlzLnR4bi5zZW5kZXIKCXR4biBTZW5kZXIKCWZyYW1lX2J1cnkgMCAvLyBzdGFrZXI6IGFkZHJlc3MKCgkvLyBjb250cmFjdHMvc3Rha2luZ1Bvb2wuYWxnby50czoyNjEKCS8vIGZvciAobGV0IGkgPSAwOyBpIDwgdGhpcy5zdGFrZXJzLnZhbHVlLmxlbmd0aDsgaSArPSAxKQoJaW50IDAKCWZyYW1lX2J1cnkgMSAvLyBpOiB1aW50NjQKCipmb3JfMToKCS8vIGNvbnRyYWN0cy9zdGFraW5nUG9vbC5hbGdvLnRzOjI2MQoJLy8gaSA8IHRoaXMuc3Rha2Vycy52YWx1ZS5sZW5ndGgKCWZyYW1lX2RpZyAxIC8vIGk6IHVpbnQ2NAoJaW50IDIwMAoJPAoJYnogKmZvcl8xX2VuZAoKCS8vICppZjZfY29uZGl0aW9uCgkvLyBjb250cmFjdHMvc3Rha2luZ1Bvb2wuYWxnby50czoyNjIKCS8vIGdsb2JhbHMub3Bjb2RlQnVkZ2V0IDwgMzAwCglnbG9iYWwgT3Bjb2RlQnVkZ2V0CglpbnQgMzAwCgk8CglieiAqaWY2X2VuZAoKCS8vICppZjZfY29uc2VxdWVudAoJLy8gY29udHJhY3RzL3N0YWtpbmdQb29sLmFsZ28udHM6MjYzCgkvLyBpbmNyZWFzZU9wY29kZUJ1ZGdldCgpCglpdHhuX2JlZ2luCglpbnQgYXBwbAoJaXR4bl9maWVsZCBUeXBlRW51bQoJaW50IDAKCWl0eG5fZmllbGQgRmVlCglieXRlIGI2NCBDb0VCIC8vICNwcmFnbWEgdmVyc2lvbiAxMDsgaW50IDEKCWR1cAoJaXR4bl9maWVsZCBBcHByb3ZhbFByb2dyYW0KCWl0eG5fZmllbGQgQ2xlYXJTdGF0ZVByb2dyYW0KCWludCBEZWxldGVBcHBsaWNhdGlvbgoJaXR4bl9maWVsZCBPbkNvbXBsZXRpb24KCWl0eG5fc3VibWl0CgoqaWY2X2VuZDoKCS8vIGNvbnRyYWN0cy9zdGFraW5nUG9vbC5hbGdvLnRzOjI2NQoJLy8gY21wU3Rha2VyID0gY2xvbmUodGhpcy5zdGFrZXJzLnZhbHVlW2ldKQoJZnJhbWVfZGlnIDEgLy8gaTogdWludDY0CglpbnQgNjQKCSogLy8gYWNjICogdHlwZUxlbmd0aAoJaW50IDY0CglieXRlIDB4NzM3NDYxNmI2NTcyNzMgLy8gInN0YWtlcnMiCgljb3ZlciAyCglib3hfZXh0cmFjdAoJZnJhbWVfYnVyeSAyIC8vIGNtcFN0YWtlcjogKGFkZHJlc3MsdWludDY0LHVpbnQ2NCx1aW50NjQsdWludDY0KQoKCS8vICppZjdfY29uZGl0aW9uCgkvLyBjb250cmFjdHMvc3Rha2luZ1Bvb2wuYWxnby50czoyNjYKCS8vIGNtcFN0YWtlci5hY2NvdW50ID09PSBzdGFrZXIKCWZyYW1lX2RpZyAyIC8vIGNtcFN0YWtlcjogKGFkZHJlc3MsdWludDY0LHVpbnQ2NCx1aW50NjQsdWludDY0KQoJZXh0cmFjdCAwIDMyCglmcmFtZV9kaWcgMCAvLyBzdGFrZXI6IGFkZHJlc3MKCT09CglieiAqaWY3X2VuZAoKCS8vICppZjdfY29uc2VxdWVudAoJLy8gKmlmOF9jb25kaXRpb24KCS8vIGNvbnRyYWN0cy9zdGFraW5nUG9vbC5hbGdvLnRzOjI2NwoJLy8gYW1vdW50VG9VbnN0YWtlID09PSAwCglmcmFtZV9kaWcgLTEgLy8gYW1vdW50VG9VbnN0YWtlOiB1aW50NjQKCWludCAwCgk9PQoJYnogKmlmOF9lbmQKCgkvLyAqaWY4X2NvbnNlcXVlbnQKCS8vIGNvbnRyYWN0cy9zdGFraW5nUG9vbC5hbGdvLnRzOjI2OQoJLy8gYW1vdW50VG9VbnN0YWtlID0gY21wU3Rha2VyLmJhbGFuY2UKCWZyYW1lX2RpZyAyIC8vIGNtcFN0YWtlcjogKGFkZHJlc3MsdWludDY0LHVpbnQ2NCx1aW50NjQsdWludDY0KQoJZXh0cmFjdCAzMiA4CglidG9pCglmcmFtZV9idXJ5IC0xIC8vIGFtb3VudFRvVW5zdGFrZTogdWludDY0CgoqaWY4X2VuZDoKCS8vICppZjlfY29uZGl0aW9uCgkvLyBjb250cmFjdHMvc3Rha2luZ1Bvb2wuYWxnby50czoyNzEKCS8vIGNtcFN0YWtlci5iYWxhbmNlIDwgYW1vdW50VG9VbnN0YWtlCglmcmFtZV9kaWcgMiAvLyBjbXBTdGFrZXI6IChhZGRyZXNzLHVpbnQ2NCx1aW50NjQsdWludDY0LHVpbnQ2NCkKCWV4dHJhY3QgMzIgOAoJYnRvaQoJZnJhbWVfZGlnIC0xIC8vIGFtb3VudFRvVW5zdGFrZTogdWludDY0Cgk8CglieiAqaWY5X2VuZAoKCS8vICppZjlfY29uc2VxdWVudAoJZXJyIC8vICdJbnN1ZmZpY2llbnQgYmFsYW5jZScKCippZjlfZW5kOgoJLy8gY29udHJhY3RzL3N0YWtpbmdQb29sLmFsZ28udHM6Mjc0CgkvLyBjbXBTdGFrZXIuYmFsYW5jZSAtPSBhbW91bnRUb1Vuc3Rha2UKCWZyYW1lX2RpZyAyIC8vIGNtcFN0YWtlcjogKGFkZHJlc3MsdWludDY0LHVpbnQ2NCx1aW50NjQsdWludDY0KQoJaW50IDMyIC8vIGhlYWRPZmZzZXQKCWZyYW1lX2RpZyAyIC8vIGNtcFN0YWtlcjogKGFkZHJlc3MsdWludDY0LHVpbnQ2NCx1aW50NjQsdWludDY0KQoJZXh0cmFjdCAzMiA4CglidG9pCglmcmFtZV9kaWcgLTEgLy8gYW1vdW50VG9VbnN0YWtlOiB1aW50NjQKCS0KCWl0b2IKCXJlcGxhY2UzCglmcmFtZV9idXJ5IDIgLy8gY21wU3Rha2VyOiAoYWRkcmVzcyx1aW50NjQsdWludDY0LHVpbnQ2NCx1aW50NjQpCgoJLy8gY29udHJhY3RzL3N0YWtpbmdQb29sLmFsZ28udHM6Mjc1CgkvLyB0aGlzLnRvdGFsQWxnb1N0YWtlZC52YWx1ZSAtPSBhbW91bnRUb1Vuc3Rha2UKCWJ5dGUgMHg3Mzc0NjE2YjY1NjQgLy8gInN0YWtlZCIKCWFwcF9nbG9iYWxfZ2V0CglmcmFtZV9kaWcgLTEgLy8gYW1vdW50VG9VbnN0YWtlOiB1aW50NjQKCS0KCWJ5dGUgMHg3Mzc0NjE2YjY1NjQgLy8gInN0YWtlZCIKCXN3YXAKCWFwcF9nbG9iYWxfcHV0CgoJLy8gY29udHJhY3RzL3N0YWtpbmdQb29sLmFsZ28udHM6Mjc3CgkvLyBhbW91bnRSZXdhcmRUb2tlblJlbW92ZWQgPSAwCglpbnQgMAoJZnJhbWVfYnVyeSAzIC8vIGFtb3VudFJld2FyZFRva2VuUmVtb3ZlZDogdWludDY0CgoJLy8gKmlmMTBfY29uZGl0aW9uCgkvLyBjb250cmFjdHMvc3Rha2luZ1Bvb2wuYWxnby50czoyNzgKCS8vIGNtcFN0YWtlci5yZXdhcmRUb2tlbkJhbGFuY2UgPiAwCglmcmFtZV9kaWcgMiAvLyBjbXBTdGFrZXI6IChhZGRyZXNzLHVpbnQ2NCx1aW50NjQsdWludDY0LHVpbnQ2NCkKCWV4dHJhY3QgNDggOAoJYnRvaQoJaW50IDAKCT4KCWJ6ICppZjEwX2VuZAoKCS8vICppZjEwX2NvbnNlcXVlbnQKCS8vICppZjExX2NvbmRpdGlvbgoJLy8gY29udHJhY3RzL3N0YWtpbmdQb29sLmFsZ28udHM6MjgwCgkvLyB0aGlzLnBvb2xJZC52YWx1ZSA9PT0gMQoJYnl0ZSAweDcwNmY2ZjZjNDk2NCAvLyAicG9vbElkIgoJYXBwX2dsb2JhbF9nZXQKCWludCAxCgk9PQoJYnogKmlmMTFfZWxzZQoKCS8vICppZjExX2NvbnNlcXVlbnQKCS8vIGNvbnRyYWN0cy9zdGFraW5nUG9vbC5hbGdvLnRzOjI4MQoJLy8gdmFsaWRhdG9yQ29uZmlnID0gc2VuZE1ldGhvZENhbGw8dHlwZW9mIFZhbGlkYXRvclJlZ2lzdHJ5LnByb3RvdHlwZS5nZXRWYWxpZGF0b3JDb25maWc+KHsKCS8vICAgICAgICAgICAgICAgICAgICAgICAgICAgICBhcHBsaWNhdGlvbklEOiBBcHBJRC5mcm9tVWludDY0KHRoaXMuY3JlYXRpbmdWYWxpZGF0b3JDb250cmFjdEFwcElkLnZhbHVlKSwKCS8vICAgICAgICAgICAgICAgICAgICAgICAgICAgICBtZXRob2RBcmdzOiBbdGhpcy52YWxpZGF0b3JJZC52YWx1ZV0sCgkvLyAgICAgICAgICAgICAgICAgICAgICAgICB9KQoJaXR4bl9iZWdpbgoJaW50IGFwcGwKCWl0eG5fZmllbGQgVHlwZUVudW0KCW1ldGhvZCAiZ2V0VmFsaWRhdG9yQ29uZmlnKHVpbnQ2NCkodWludDY0LGFkZHJlc3MsYWRkcmVzcyx1aW50NjQsdWludDgsYnl0ZVszMl0sdWludDY0LHVpbnQ2NCx1aW50NjQsdWludDE2LHVpbnQzMixhZGRyZXNzLHVpbnQ2NCx1aW50NjQsdWludDgsdWludDY0LHVpbnQ2NCkiCglpdHhuX2ZpZWxkIEFwcGxpY2F0aW9uQXJncwoKCS8vIGNvbnRyYWN0cy9zdGFraW5nUG9vbC5hbGdvLnRzOjI4MgoJLy8gYXBwbGljYXRpb25JRDogQXBwSUQuZnJvbVVpbnQ2NCh0aGlzLmNyZWF0aW5nVmFsaWRhdG9yQ29udHJhY3RBcHBJZC52YWx1ZSkKCWJ5dGUgMHg2MzcyNjU2MTc0NmY3MjQxNzA3MCAvLyAiY3JlYXRvckFwcCIKCWFwcF9nbG9iYWxfZ2V0CglpdHhuX2ZpZWxkIEFwcGxpY2F0aW9uSUQKCgkvLyBjb250cmFjdHMvc3Rha2luZ1Bvb2wuYWxnby50czoyODMKCS8vIG1ldGhvZEFyZ3M6IFt0aGlzLnZhbGlkYXRvcklkLnZhbHVlXQoJYnl0ZSAweDc2NjE2YzY5NjQ2MTc0NmY3MjQ5NjQgLy8gInZhbGlkYXRvcklkIgoJYXBwX2dsb2JhbF9nZXQKCWl0b2IKCWl0eG5fZmllbGQgQXBwbGljYXRpb25BcmdzCgoJLy8gRmVlIGZpZWxkIG5vdCBzZXQsIGRlZmF1bHRpbmcgdG8gMAoJaW50IDAKCWl0eG5fZmllbGQgRmVlCgoJLy8gU3VibWl0IGlubmVyIHRyYW5zYWN0aW9uCglpdHhuX3N1Ym1pdAoJaXR4biBOdW1Mb2dzCglpbnQgMQoJLQoJaXR4bmFzIExvZ3MKCWV4dHJhY3QgNCAwCglmcmFtZV9idXJ5IDQgLy8gdmFsaWRhdG9yQ29uZmlnOiAodWludDY0LGFkZHJlc3MsYWRkcmVzcyx1aW50NjQsdWludDgsYnl0ZVszMl0sdWludDY0LHVpbnQ2NCx1aW50NjQsdWludDE2LHVpbnQzMixhZGRyZXNzLHVpbnQ2NCx1aW50NjQsdWludDgsdWludDY0LHVpbnQ2NCkKCgkvLyBjb250cmFjdHMvc3Rha2luZ1Bvb2wuYWxnby50czoyODkKCS8vIHNlbmRBc3NldFRyYW5zZmVyKHsKCS8vICAgICAgICAgICAgICAgICAgICAgICAgICAgICB4ZmVyQXNzZXQ6IEFzc2V0SUQuZnJvbVVpbnQ2NCh2YWxpZGF0b3JDb25maWcucmV3YXJkVG9rZW5JZCksCgkvLyAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYXNzZXRSZWNlaXZlcjogc3Rha2VyLAoJLy8gICAgICAgICAgICAgICAgICAgICAgICAgICAgIGFzc2V0QW1vdW50OiBjbXBTdGFrZXIucmV3YXJkVG9rZW5CYWxhbmNlLAoJLy8gICAgICAgICAgICAgICAgICAgICAgICAgfSkKCWl0eG5fYmVnaW4KCWludCBheGZlcgoJaXR4bl9maWVsZCBUeXBlRW51bQoKCS8vIGNvbnRyYWN0cy9zdGFraW5nUG9vbC5hbGdvLnRzOjI5MAoJLy8geGZlckFzc2V0OiBBc3NldElELmZyb21VaW50NjQodmFsaWRhdG9yQ29uZmlnLnJld2FyZFRva2VuSWQpCglmcmFtZV9kaWcgNCAvLyB2YWxpZGF0b3JDb25maWc6ICh1aW50NjQsYWRkcmVzcyxhZGRyZXNzLHVpbnQ2NCx1aW50OCxieXRlWzMyXSx1aW50NjQsdWludDY0LHVpbnQ2NCx1aW50MTYsdWludDMyLGFkZHJlc3MsdWludDY0LHVpbnQ2NCx1aW50OCx1aW50NjQsdWludDY0KQoJZXh0cmFjdCAxMjEgOAoJYnRvaQoJaXR4bl9maWVsZCBYZmVyQXNzZXQKCgkvLyBjb250cmFjdHMvc3Rha2luZ1Bvb2wuYWxnby50czoyOTEKCS8vIGFzc2V0UmVjZWl2ZXI6IHN0YWtlcgoJZnJhbWVfZGlnIDAgLy8gc3Rha2VyOiBhZGRyZXNzCglpdHhuX2ZpZWxkIEFzc2V0UmVjZWl2ZXIKCgkvLyBjb250cmFjdHMvc3Rha2luZ1Bvb2wuYWxnby50czoyOTIKCS8vIGFzc2V0QW1vdW50OiBjbXBTdGFrZXIucmV3YXJkVG9rZW5CYWxhbmNlCglmcmFtZV9kaWcgMiAvLyBjbXBTdGFrZXI6IChhZGRyZXNzLHVpbnQ2NCx1aW50NjQsdWludDY0LHVpbnQ2NCkKCWV4dHJhY3QgNDggOAoJYnRvaQoJaXR4bl9maWVsZCBBc3NldEFtb3VudAoKCS8vIEZlZSBmaWVsZCBub3Qgc2V0LCBkZWZhdWx0aW5nIHRvIDAKCWludCAwCglpdHhuX2ZpZWxkIEZlZQoKCS8vIFN1Ym1pdCBpbm5lciB0cmFuc2FjdGlvbgoJaXR4bl9zdWJtaXQKCgkvLyBjb250cmFjdHMvc3Rha2luZ1Bvb2wuYWxnby50czoyOTQKCS8vIGFtb3VudFJld2FyZFRva2VuUmVtb3ZlZCA9IGNtcFN0YWtlci5yZXdhcmRUb2tlbkJhbGFuY2UKCWZyYW1lX2RpZyAyIC8vIGNtcFN0YWtlcjogKGFkZHJlc3MsdWludDY0LHVpbnQ2NCx1aW50NjQsdWludDY0KQoJZXh0cmFjdCA0OCA4CglidG9pCglmcmFtZV9idXJ5IDMgLy8gYW1vdW50UmV3YXJkVG9rZW5SZW1vdmVkOiB1aW50NjQKCgkvLyBjb250cmFjdHMvc3Rha2luZ1Bvb2wuYWxnby50czoyOTUKCS8vIGNtcFN0YWtlci5yZXdhcmRUb2tlbkJhbGFuY2UgPSAwCglmcmFtZV9kaWcgMiAvLyBjbXBTdGFrZXI6IChhZGRyZXNzLHVpbnQ2NCx1aW50NjQsdWludDY0LHVpbnQ2NCkKCWJ5dGUgMHgwMDAwMDAwMDAwMDAwMDAwCglyZXBsYWNlMiA0OAoJZnJhbWVfYnVyeSAyIC8vIGNtcFN0YWtlcjogKGFkZHJlc3MsdWludDY0LHVpbnQ2NCx1aW50NjQsdWludDY0KQoJYiAqaWYxMV9lbmQKCippZjExX2Vsc2U6CgkvLyBjb250cmFjdHMvc3Rha2luZ1Bvb2wuYWxnby50czozMDAKCS8vIGFtb3VudFJld2FyZFRva2VuUmVtb3ZlZCA9IGNtcFN0YWtlci5yZXdhcmRUb2tlbkJhbGFuY2UKCWZyYW1lX2RpZyAyIC8vIGNtcFN0YWtlcjogKGFkZHJlc3MsdWludDY0LHVpbnQ2NCx1aW50NjQsdWludDY0KQoJZXh0cmFjdCA0OCA4CglidG9pCglmcmFtZV9idXJ5IDMgLy8gYW1vdW50UmV3YXJkVG9rZW5SZW1vdmVkOiB1aW50NjQKCgkvLyBjb250cmFjdHMvc3Rha2luZ1Bvb2wuYWxnby50czozMDEKCS8vIGNtcFN0YWtlci5yZXdhcmRUb2tlbkJhbGFuY2UgPSAwCglmcmFtZV9kaWcgMiAvLyBjbXBTdGFrZXI6IChhZGRyZXNzLHVpbnQ2NCx1aW50NjQsdWludDY0LHVpbnQ2NCkKCWJ5dGUgMHgwMDAwMDAwMDAwMDAwMDAwCglyZXBsYWNlMiA0OAoJZnJhbWVfYnVyeSAyIC8vIGNtcFN0YWtlcjogKGFkZHJlc3MsdWludDY0LHVpbnQ2NCx1aW50NjQsdWludDY0KQoKKmlmMTFfZW5kOgoKKmlmMTBfZW5kOgoJLy8gY29udHJhY3RzL3N0YWtpbmdQb29sLmFsZ28udHM6MzA2CgkvLyBhc3NlcnQoCgkvLyAgICAgICAgICAgICAgICAgICAgIGNtcFN0YWtlci5iYWxhbmNlID09PSAwIHx8IGNtcFN0YWtlci5iYWxhbmNlID49IHRoaXMubWluRW50cnlTdGFrZS52YWx1ZSwKCS8vICAgICAgICAgICAgICAgICAgICAgJ2Nhbm5vdCByZWR1Y2UgYmFsYW5jZSBiZWxvdyBtaW5pbXVtIGFsbG93ZWQgc3Rha2UgdW5sZXNzIGFsbCBpcyByZW1vdmVkJwoJLy8gICAgICAgICAgICAgICAgICkKCWZyYW1lX2RpZyAyIC8vIGNtcFN0YWtlcjogKGFkZHJlc3MsdWludDY0LHVpbnQ2NCx1aW50NjQsdWludDY0KQoJZXh0cmFjdCAzMiA4CglidG9pCglpbnQgMAoJPT0KCWR1cAoJYm56ICpza2lwX29yMAoJZnJhbWVfZGlnIDIgLy8gY21wU3Rha2VyOiAoYWRkcmVzcyx1aW50NjQsdWludDY0LHVpbnQ2NCx1aW50NjQpCglleHRyYWN0IDMyIDgKCWJ0b2kKCWJ5dGUgMHg2ZDY5NmU0NTZlNzQ3Mjc5NTM3NDYxNmI2NSAvLyAibWluRW50cnlTdGFrZSIKCWFwcF9nbG9iYWxfZ2V0Cgk+PQoJfHwKCipza2lwX29yMDoKCS8vIGNhbm5vdCByZWR1Y2UgYmFsYW5jZSBiZWxvdyBtaW5pbXVtIGFsbG93ZWQgc3Rha2UgdW5sZXNzIGFsbCBpcyByZW1vdmVkCglhc3NlcnQKCgkvLyBjb250cmFjdHMvc3Rha2luZ1Bvb2wuYWxnby50czozMTQKCS8vIHNlbmRQYXltZW50KHsKCS8vICAgICAgICAgICAgICAgICAgICAgYW1vdW50OiBhbW91bnRUb1Vuc3Rha2UsCgkvLyAgICAgICAgICAgICAgICAgICAgIHJlY2VpdmVyOiBzdGFrZXIsCgkvLyAgICAgICAgICAgICAgICAgICAgIG5vdGU6ICd1bnN0YWtlZCcsCgkvLyAgICAgICAgICAgICAgICAgfSkKCWl0eG5fYmVnaW4KCWludCBwYXkKCWl0eG5fZmllbGQgVHlwZUVudW0KCgkvLyBjb250cmFjdHMvc3Rha2luZ1Bvb2wuYWxnby50czozMTUKCS8vIGFtb3VudDogYW1vdW50VG9VbnN0YWtlCglmcmFtZV9kaWcgLTEgLy8gYW1vdW50VG9VbnN0YWtlOiB1aW50NjQKCWl0eG5fZmllbGQgQW1vdW50CgoJLy8gY29udHJhY3RzL3N0YWtpbmdQb29sLmFsZ28udHM6MzE2CgkvLyByZWNlaXZlcjogc3Rha2VyCglmcmFtZV9kaWcgMCAvLyBzdGFrZXI6IGFkZHJlc3MKCWl0eG5fZmllbGQgUmVjZWl2ZXIKCgkvLyBjb250cmFjdHMvc3Rha2luZ1Bvb2wuYWxnby50czozMTcKCS8vIG5vdGU6ICd1bnN0YWtlZCcKCWJ5dGUgMHg3NTZlNzM3NDYxNmI2NTY0IC8vICJ1bnN0YWtlZCIKCWl0eG5fZmllbGQgTm90ZQoKCS8vIEZlZSBmaWVsZCBub3Qgc2V0LCBkZWZhdWx0aW5nIHRvIDAKCWludCAwCglpdHhuX2ZpZWxkIEZlZQoKCS8vIFN1Ym1pdCBpbm5lciB0cmFuc2FjdGlvbgoJaXR4bl9zdWJtaXQKCgkvLyBjb250cmFjdHMvc3Rha2luZ1Bvb2wuYWxnby50czozMTkKCS8vIHN0YWtlclJlbW92ZWQgPSBmYWxzZQoJaW50IDAKCWZyYW1lX2J1cnkgNSAvLyBzdGFrZXJSZW1vdmVkOiBib29sCgoJLy8gKmlmMTJfY29uZGl0aW9uCgkvLyBjb250cmFjdHMvc3Rha2luZ1Bvb2wuYWxnby50czozMjAKCS8vIGNtcFN0YWtlci5iYWxhbmNlID09PSAwCglmcmFtZV9kaWcgMiAvLyBjbXBTdGFrZXI6IChhZGRyZXNzLHVpbnQ2NCx1aW50NjQsdWludDY0LHVpbnQ2NCkKCWV4dHJhY3QgMzIgOAoJYnRvaQoJaW50IDAKCT09CglieiAqaWYxMl9lbmQKCgkvLyAqaWYxMl9jb25zZXF1ZW50CgkvLyBjb250cmFjdHMvc3Rha2luZ1Bvb2wuYWxnby50czozMjIKCS8vIHRoaXMubnVtU3Rha2Vycy52YWx1ZSAtPSAxCglieXRlIDB4NmU3NTZkNTM3NDYxNmI2NTcyNzMgLy8gIm51bVN0YWtlcnMiCglhcHBfZ2xvYmFsX2dldAoJaW50IDEKCS0KCWJ5dGUgMHg2ZTc1NmQ1Mzc0NjE2YjY1NzI3MyAvLyAibnVtU3Rha2VycyIKCXN3YXAKCWFwcF9nbG9iYWxfcHV0CgoJLy8gY29udHJhY3RzL3N0YWtpbmdQb29sLmFsZ28udHM6MzIzCgkvLyBjbXBTdGFrZXIuYWNjb3VudCA9IGdsb2JhbHMuemVyb0FkZHJlc3MKCWZyYW1lX2RpZyAyIC8vIGNtcFN0YWtlcjogKGFkZHJlc3MsdWludDY0LHVpbnQ2NCx1aW50NjQsdWludDY0KQoJaW50IDAKCWdsb2JhbCBaZXJvQWRkcmVzcwoJcmVwbGFjZTMKCWZyYW1lX2J1cnkgMiAvLyBjbXBTdGFrZXI6IChhZGRyZXNzLHVpbnQ2NCx1aW50NjQsdWludDY0LHVpbnQ2NCkKCgkvLyBjb250cmFjdHMvc3Rha2luZ1Bvb2wuYWxnby50czozMjQKCS8vIGNtcFN0YWtlci50b3RhbFJld2FyZGVkID0gMAoJZnJhbWVfZGlnIDIgLy8gY21wU3Rha2VyOiAoYWRkcmVzcyx1aW50NjQsdWludDY0LHVpbnQ2NCx1aW50NjQpCglieXRlIDB4MDAwMDAwMDAwMDAwMDAwMAoJcmVwbGFjZTIgNDAKCWZyYW1lX2J1cnkgMiAvLyBjbXBTdGFrZXI6IChhZGRyZXNzLHVpbnQ2NCx1aW50NjQsdWludDY0LHVpbnQ2NCkKCgkvLyBjb250cmFjdHMvc3Rha2luZ1Bvb2wuYWxnby50czozMjUKCS8vIGNtcFN0YWtlci5yZXdhcmRUb2tlbkJhbGFuY2UgPSAwCglmcmFtZV9kaWcgMiAvLyBjbXBTdGFrZXI6IChhZGRyZXNzLHVpbnQ2NCx1aW50NjQsdWludDY0LHVpbnQ2NCkKCWJ5dGUgMHgwMDAwMDAwMDAwMDAwMDAwCglyZXBsYWNlMiA0OAoJZnJhbWVfYnVyeSAyIC8vIGNtcFN0YWtlcjogKGFkZHJlc3MsdWludDY0LHVpbnQ2NCx1aW50NjQsdWludDY0KQoKCS8vIGNvbnRyYWN0cy9zdGFraW5nUG9vbC5hbGdvLnRzOjMyNgoJLy8gc3Rha2VyUmVtb3ZlZCA9IHRydWUKCWludCAxCglmcmFtZV9idXJ5IDUgLy8gc3Rha2VyUmVtb3ZlZDogYm9vbAoKKmlmMTJfZW5kOgoJLy8gY29udHJhY3RzL3N0YWtpbmdQb29sLmFsZ28udHM6MzI5CgkvLyB0aGlzLnN0YWtlcnMudmFsdWVbaV0gPSBjbXBTdGFrZXIKCWZyYW1lX2RpZyAxIC8vIGk6IHVpbnQ2NAoJaW50IDY0CgkqIC8vIGFjYyAqIHR5cGVMZW5ndGgKCWZyYW1lX2RpZyAyIC8vIGNtcFN0YWtlcjogKGFkZHJlc3MsdWludDY0LHVpbnQ2NCx1aW50NjQsdWludDY0KQoJYnl0ZSAweDczNzQ2MTZiNjU3MjczIC8vICJzdGFrZXJzIgoJY292ZXIgMgoJYm94X3JlcGxhY2UKCgkvLyBjb250cmFjdHMvc3Rha2luZ1Bvb2wuYWxnby50czozMzQKCS8vIHNlbmRNZXRob2RDYWxsPHR5cGVvZiBWYWxpZGF0b3JSZWdpc3RyeS5wcm90b3R5cGUuc3Rha2VSZW1vdmVkPih7CgkvLyAgICAgICAgICAgICAgICAgICAgIGFwcGxpY2F0aW9uSUQ6IEFwcElELmZyb21VaW50NjQodGhpcy5jcmVhdGluZ1ZhbGlkYXRvckNvbnRyYWN0QXBwSWQudmFsdWUpLAoJLy8gICAgICAgICAgICAgICAgICAgICBtZXRob2RBcmdzOiBbCgkvLyAgICAgICAgICAgICAgICAgICAgICAgICB7IGlkOiB0aGlzLnZhbGlkYXRvcklkLnZhbHVlLCBwb29sSWQ6IHRoaXMucG9vbElkLnZhbHVlLCBwb29sQXBwSWQ6IHRoaXMuYXBwLmlkIH0sCgkvLyAgICAgICAgICAgICAgICAgICAgICAgICBzdGFrZXIsCgkvLyAgICAgICAgICAgICAgICAgICAgICAgICBhbW91bnRUb1Vuc3Rha2UsCgkvLyAgICAgICAgICAgICAgICAgICAgICAgICBhbW91bnRSZXdhcmRUb2tlblJlbW92ZWQsCgkvLyAgICAgICAgICAgICAgICAgICAgICAgICBzdGFrZXJSZW1vdmVkLAoJLy8gICAgICAgICAgICAgICAgICAgICBdLAoJLy8gICAgICAgICAgICAgICAgIH0pCglpdHhuX2JlZ2luCglpbnQgYXBwbAoJaXR4bl9maWVsZCBUeXBlRW51bQoJbWV0aG9kICJzdGFrZVJlbW92ZWQoKHVpbnQ2NCx1aW50NjQsdWludDY0KSxhZGRyZXNzLHVpbnQ2NCx1aW50NjQsYm9vbCl2b2lkIgoJaXR4bl9maWVsZCBBcHBsaWNhdGlvbkFyZ3MKCgkvLyBjb250cmFjdHMvc3Rha2luZ1Bvb2wuYWxnby50czozMzUKCS8vIGFwcGxpY2F0aW9uSUQ6IEFwcElELmZyb21VaW50NjQodGhpcy5jcmVhdGluZ1ZhbGlkYXRvckNvbnRyYWN0QXBwSWQudmFsdWUpCglieXRlIDB4NjM3MjY1NjE3NDZmNzI0MTcwNzAgLy8gImNyZWF0b3JBcHAiCglhcHBfZ2xvYmFsX2dldAoJaXR4bl9maWVsZCBBcHBsaWNhdGlvbklECgoJLy8gY29udHJhY3RzL3N0YWtpbmdQb29sLmFsZ28udHM6MzM2CgkvLyBtZXRob2RBcmdzOiBbCgkvLyAgICAgICAgICAgICAgICAgICAgICAgICB7IGlkOiB0aGlzLnZhbGlkYXRvcklkLnZhbHVlLCBwb29sSWQ6IHRoaXMucG9vbElkLnZhbHVlLCBwb29sQXBwSWQ6IHRoaXMuYXBwLmlkIH0sCgkvLyAgICAgICAgICAgICAgICAgICAgICAgICBzdGFrZXIsCgkvLyAgICAgICAgICAgICAgICAgICAgICAgICBhbW91bnRUb1Vuc3Rha2UsCgkvLyAgICAgICAgICAgICAgICAgICAgICAgICBhbW91bnRSZXdhcmRUb2tlblJlbW92ZWQsCgkvLyAgICAgICAgICAgICAgICAgICAgICAgICBzdGFrZXJSZW1vdmVkLAoJLy8gICAgICAgICAgICAgICAgICAgICBdCglieXRlIDB4NzY2MTZjNjk2NDYxNzQ2ZjcyNDk2NCAvLyAidmFsaWRhdG9ySWQiCglhcHBfZ2xvYmFsX2dldAoJaXRvYgoJYnl0ZSAweDcwNmY2ZjZjNDk2NCAvLyAicG9vbElkIgoJYXBwX2dsb2JhbF9nZXQKCWl0b2IKCWNvbmNhdAoJdHhuYSBBcHBsaWNhdGlvbnMgMAoJaXRvYgoJY29uY2F0CglpdHhuX2ZpZWxkIEFwcGxpY2F0aW9uQXJncwoJZnJhbWVfZGlnIDAgLy8gc3Rha2VyOiBhZGRyZXNzCglpdHhuX2ZpZWxkIEFwcGxpY2F0aW9uQXJncwoJZnJhbWVfZGlnIC0xIC8vIGFtb3VudFRvVW5zdGFrZTogdWludDY0CglpdG9iCglpdHhuX2ZpZWxkIEFwcGxpY2F0aW9uQXJncwoJZnJhbWVfZGlnIDMgLy8gYW1vdW50UmV3YXJkVG9rZW5SZW1vdmVkOiB1aW50NjQKCWl0b2IKCWl0eG5fZmllbGQgQXBwbGljYXRpb25BcmdzCglmcmFtZV9kaWcgNSAvLyBzdGFrZXJSZW1vdmVkOiBib29sCglieXRlIDB4MDAKCWludCAwCgl1bmNvdmVyIDIKCXNldGJpdAoJaXR4bl9maWVsZCBBcHBsaWNhdGlvbkFyZ3MKCgkvLyBGZWUgZmllbGQgbm90IHNldCwgZGVmYXVsdGluZyB0byAwCglpbnQgMAoJaXR4bl9maWVsZCBGZWUKCgkvLyBTdWJtaXQgaW5uZXIgdHJhbnNhY3Rpb24KCWl0eG5fc3VibWl0CgoJLy8gY29udHJhY3RzL3N0YWtpbmdQb29sLmFsZ28udHM6MzQ0CgkvLyByZXR1cm47CglyZXRzdWIKCippZjdfZW5kOgoKKmZvcl8xX2NvbnRpbnVlOgoJLy8gY29udHJhY3RzL3N0YWtpbmdQb29sLmFsZ28udHM6MjYxCgkvLyBpICs9IDEKCWZyYW1lX2RpZyAxIC8vIGk6IHVpbnQ2NAoJaW50IDEKCSsKCWZyYW1lX2J1cnkgMSAvLyBpOiB1aW50NjQKCWIgKmZvcl8xCgoqZm9yXzFfZW5kOgoJZXJyIC8vICdhY2NvdW50IG5vdCBmb3VuZCcKCi8vIGNsYWltVG9rZW5zKCl2b2lkCiphYmlfcm91dGVfY2xhaW1Ub2tlbnM6CgkvLyBleGVjdXRlIGNsYWltVG9rZW5zKCl2b2lkCgljYWxsc3ViIGNsYWltVG9rZW5zCglpbnQgMQoJcmV0dXJuCgovLyBjbGFpbVRva2VucygpOiB2b2lkCi8vCi8vIENsYWltcyBhbGwgdGhlIGF2YWlsYWJsZSByZXdhcmQgdG9rZW5zIGEgc3Rha2VyIGhhcyBhdmFpbGFibGUsIHNlbmRpbmcgdGhlaXIgZW50aXJlIGJhbGFuY2UgdG8gdGhlIHN0YWtlciBmcm9tCi8vIHBvb2wgMSAoZWl0aGVyIGRpcmVjdGx5LCBvciB2aWEgdmFsaWRhdG9yLT5wb29sMSB0byBwYXkgaXQgb3V0KQovLyBBbHNvIG5vdGlmaWVzIHRoZSB2YWxpZGF0b3IgY29udHJhY3QgZm9yIHRoaXMgcG9vbHMgdmFsaWRhdG9yIG9mIHRoZSBzdGFrZXIgLyBiYWxhbmNlIGNoYW5nZXMuCmNsYWltVG9rZW5zOgoJcHJvdG8gMCAwCgoJLy8gUHVzaCBlbXB0eSBieXRlcyBhZnRlciB0aGUgZnJhbWUgcG9pbnRlciB0byByZXNlcnZlIHNwYWNlIGZvciBsb2NhbCB2YXJpYWJsZXMKCWJ5dGUgMHgKCWR1cG4gNAoKCS8vIGNvbnRyYWN0cy9zdGFraW5nUG9vbC5hbGdvLnRzOjM1OQoJLy8gc3Rha2VyID0gdGhpcy50eG4uc2VuZGVyCgl0eG4gU2VuZGVyCglmcmFtZV9idXJ5IDAgLy8gc3Rha2VyOiBhZGRyZXNzCgoJLy8gY29udHJhY3RzL3N0YWtpbmdQb29sLmFsZ28udHM6MzYxCgkvLyBmb3IgKGxldCBpID0gMDsgaSA8IHRoaXMuc3Rha2Vycy52YWx1ZS5sZW5ndGg7IGkgKz0gMSkKCWludCAwCglmcmFtZV9idXJ5IDEgLy8gaTogdWludDY0CgoqZm9yXzI6CgkvLyBjb250cmFjdHMvc3Rha2luZ1Bvb2wuYWxnby50czozNjEKCS8vIGkgPCB0aGlzLnN0YWtlcnMudmFsdWUubGVuZ3RoCglmcmFtZV9kaWcgMSAvLyBpOiB1aW50NjQKCWludCAyMDAKCTwKCWJ6ICpmb3JfMl9lbmQKCgkvLyAqaWYxM19jb25kaXRpb24KCS8vIGNvbnRyYWN0cy9zdGFraW5nUG9vbC5hbGdvLnRzOjM2MgoJLy8gZ2xvYmFscy5vcGNvZGVCdWRnZXQgPCAzMDAKCWdsb2JhbCBPcGNvZGVCdWRnZXQKCWludCAzMDAKCTwKCWJ6ICppZjEzX2VuZAoKCS8vICppZjEzX2NvbnNlcXVlbnQKCS8vIGNvbnRyYWN0cy9zdGFraW5nUG9vbC5hbGdvLnRzOjM2MwoJLy8gaW5jcmVhc2VPcGNvZGVCdWRnZXQoKQoJaXR4bl9iZWdpbgoJaW50IGFwcGwKCWl0eG5fZmllbGQgVHlwZUVudW0KCWludCAwCglpdHhuX2ZpZWxkIEZlZQoJYnl0ZSBiNjQgQ29FQiAvLyAjcHJhZ21hIHZlcnNpb24gMTA7IGludCAxCglkdXAKCWl0eG5fZmllbGQgQXBwcm92YWxQcm9ncmFtCglpdHhuX2ZpZWxkIENsZWFyU3RhdGVQcm9ncmFtCglpbnQgRGVsZXRlQXBwbGljYXRpb24KCWl0eG5fZmllbGQgT25Db21wbGV0aW9uCglpdHhuX3N1Ym1pdAoKKmlmMTNfZW5kOgoJLy8gY29udHJhY3RzL3N0YWtpbmdQb29sLmFsZ28udHM6MzY1CgkvLyBjbXBTdGFrZXIgPSBjbG9uZSh0aGlzLnN0YWtlcnMudmFsdWVbaV0pCglmcmFtZV9kaWcgMSAvLyBpOiB1aW50NjQKCWludCA2NAoJKiAvLyBhY2MgKiB0eXBlTGVuZ3RoCglpbnQgNjQKCWJ5dGUgMHg3Mzc0NjE2YjY1NzI3MyAvLyAic3Rha2VycyIKCWNvdmVyIDIKCWJveF9leHRyYWN0CglmcmFtZV9idXJ5IDIgLy8gY21wU3Rha2VyOiAoYWRkcmVzcyx1aW50NjQsdWludDY0LHVpbnQ2NCx1aW50NjQpCgoJLy8gKmlmMTRfY29uZGl0aW9uCgkvLyBjb250cmFjdHMvc3Rha2luZ1Bvb2wuYWxnby50czozNjYKCS8vIGNtcFN0YWtlci5hY2NvdW50ID09PSBzdGFrZXIKCWZyYW1lX2RpZyAyIC8vIGNtcFN0YWtlcjogKGFkZHJlc3MsdWludDY0LHVpbnQ2NCx1aW50NjQsdWludDY0KQoJZXh0cmFjdCAwIDMyCglmcmFtZV9kaWcgMCAvLyBzdGFrZXI6IGFkZHJlc3MKCT09CglieiAqaWYxNF9lbmQKCgkvLyAqaWYxNF9jb25zZXF1ZW50CgkvLyAqaWYxNV9jb25kaXRpb24KCS8vIGNvbnRyYWN0cy9zdGFraW5nUG9vbC5hbGdvLnRzOjM2NwoJLy8gY21wU3Rha2VyLnJld2FyZFRva2VuQmFsYW5jZSA9PT0gMAoJZnJhbWVfZGlnIDIgLy8gY21wU3Rha2VyOiAoYWRkcmVzcyx1aW50NjQsdWludDY0LHVpbnQ2NCx1aW50NjQpCglleHRyYWN0IDQ4IDgKCWJ0b2kKCWludCAwCgk9PQoJYnogKmlmMTVfZW5kCgoJLy8gKmlmMTVfY29uc2VxdWVudAoJLy8gY29udHJhY3RzL3N0YWtpbmdQb29sLmFsZ28udHM6MzY4CgkvLyByZXR1cm47CglyZXRzdWIKCippZjE1X2VuZDoKCS8vIGNvbnRyYWN0cy9zdGFraW5nUG9vbC5hbGdvLnRzOjM3MAoJLy8gYW1vdW50UmV3YXJkVG9rZW5SZW1vdmVkID0gMAoJaW50IDAKCWZyYW1lX2J1cnkgMyAvLyBhbW91bnRSZXdhcmRUb2tlblJlbW92ZWQ6IHVpbnQ2NAoKCS8vICppZjE2X2NvbmRpdGlvbgoJLy8gY29udHJhY3RzL3N0YWtpbmdQb29sLmFsZ28udHM6MzcyCgkvLyB0aGlzLnBvb2xJZC52YWx1ZSA9PT0gMQoJYnl0ZSAweDcwNmY2ZjZjNDk2NCAvLyAicG9vbElkIgoJYXBwX2dsb2JhbF9nZXQKCWludCAxCgk9PQoJYnogKmlmMTZfZWxzZQoKCS8vICppZjE2X2NvbnNlcXVlbnQKCS8vIGNvbnRyYWN0cy9zdGFraW5nUG9vbC5hbGdvLnRzOjM3MwoJLy8gdmFsaWRhdG9yQ29uZmlnID0gc2VuZE1ldGhvZENhbGw8dHlwZW9mIFZhbGlkYXRvclJlZ2lzdHJ5LnByb3RvdHlwZS5nZXRWYWxpZGF0b3JDb25maWc+KHsKCS8vICAgICAgICAgICAgICAgICAgICAgICAgIGFwcGxpY2F0aW9uSUQ6IEFwcElELmZyb21VaW50NjQodGhpcy5jcmVhdGluZ1ZhbGlkYXRvckNvbnRyYWN0QXBwSWQudmFsdWUpLAoJLy8gICAgICAgICAgICAgICAgICAgICAgICAgbWV0aG9kQXJnczogW3RoaXMudmFsaWRhdG9ySWQudmFsdWVdLAoJLy8gICAgICAgICAgICAgICAgICAgICB9KQoJaXR4bl9iZWdpbgoJaW50IGFwcGwKCWl0eG5fZmllbGQgVHlwZUVudW0KCW1ldGhvZCAiZ2V0VmFsaWRhdG9yQ29uZmlnKHVpbnQ2NCkodWludDY0LGFkZHJlc3MsYWRkcmVzcyx1aW50NjQsdWludDgsYnl0ZVszMl0sdWludDY0LHVpbnQ2NCx1aW50NjQsdWludDE2LHVpbnQzMixhZGRyZXNzLHVpbnQ2NCx1aW50NjQsdWludDgsdWludDY0LHVpbnQ2NCkiCglpdHhuX2ZpZWxkIEFwcGxpY2F0aW9uQXJncwoKCS8vIGNvbnRyYWN0cy9zdGFraW5nUG9vbC5hbGdvLnRzOjM3NAoJLy8gYXBwbGljYXRpb25JRDogQXBwSUQuZnJvbVVpbnQ2NCh0aGlzLmNyZWF0aW5nVmFsaWRhdG9yQ29udHJhY3RBcHBJZC52YWx1ZSkKCWJ5dGUgMHg2MzcyNjU2MTc0NmY3MjQxNzA3MCAvLyAiY3JlYXRvckFwcCIKCWFwcF9nbG9iYWxfZ2V0CglpdHhuX2ZpZWxkIEFwcGxpY2F0aW9uSUQKCgkvLyBjb250cmFjdHMvc3Rha2luZ1Bvb2wuYWxnby50czozNzUKCS8vIG1ldGhvZEFyZ3M6IFt0aGlzLnZhbGlkYXRvcklkLnZhbHVlXQoJYnl0ZSAweDc2NjE2YzY5NjQ2MTc0NmY3MjQ5NjQgLy8gInZhbGlkYXRvcklkIgoJYXBwX2dsb2JhbF9nZXQKCWl0b2IKCWl0eG5fZmllbGQgQXBwbGljYXRpb25BcmdzCgoJLy8gRmVlIGZpZWxkIG5vdCBzZXQsIGRlZmF1bHRpbmcgdG8gMAoJaW50IDAKCWl0eG5fZmllbGQgRmVlCgoJLy8gU3VibWl0IGlubmVyIHRyYW5zYWN0aW9uCglpdHhuX3N1Ym1pdAoJaXR4biBOdW1Mb2dzCglpbnQgMQoJLQoJaXR4bmFzIExvZ3MKCWV4dHJhY3QgNCAwCglmcmFtZV9idXJ5IDQgLy8gdmFsaWRhdG9yQ29uZmlnOiAodWludDY0LGFkZHJlc3MsYWRkcmVzcyx1aW50NjQsdWludDgsYnl0ZVszMl0sdWludDY0LHVpbnQ2NCx1aW50NjQsdWludDE2LHVpbnQzMixhZGRyZXNzLHVpbnQ2NCx1aW50NjQsdWludDgsdWludDY0LHVpbnQ2NCkKCgkvLyBjb250cmFjdHMvc3Rha2luZ1Bvb2wuYWxnby50czozODAKCS8vIHNlbmRBc3NldFRyYW5zZmVyKHsKCS8vICAgICAgICAgICAgICAgICAgICAgICAgIHhmZXJBc3NldDogQXNzZXRJRC5mcm9tVWludDY0KHZhbGlkYXRvckNvbmZpZy5yZXdhcmRUb2tlbklkKSwKCS8vICAgICAgICAgICAgICAgICAgICAgICAgIGFzc2V0UmVjZWl2ZXI6IHN0YWtlciwKCS8vICAgICAgICAgICAgICAgICAgICAgICAgIGFzc2V0QW1vdW50OiBjbXBTdGFrZXIucmV3YXJkVG9rZW5CYWxhbmNlLAoJLy8gICAgICAgICAgICAgICAgICAgICB9KQoJaXR4bl9iZWdpbgoJaW50IGF4ZmVyCglpdHhuX2ZpZWxkIFR5cGVFbnVtCgoJLy8gY29udHJhY3RzL3N0YWtpbmdQb29sLmFsZ28udHM6MzgxCgkvLyB4ZmVyQXNzZXQ6IEFzc2V0SUQuZnJvbVVpbnQ2NCh2YWxpZGF0b3JDb25maWcucmV3YXJkVG9rZW5JZCkKCWZyYW1lX2RpZyA0IC8vIHZhbGlkYXRvckNvbmZpZzogKHVpbnQ2NCxhZGRyZXNzLGFkZHJlc3MsdWludDY0LHVpbnQ4LGJ5dGVbMzJdLHVpbnQ2NCx1aW50NjQsdWludDY0LHVpbnQxNix1aW50MzIsYWRkcmVzcyx1aW50NjQsdWludDY0LHVpbnQ4LHVpbnQ2NCx1aW50NjQpCglleHRyYWN0IDEyMSA4CglidG9pCglpdHhuX2ZpZWxkIFhmZXJBc3NldAoKCS8vIGNvbnRyYWN0cy9zdGFraW5nUG9vbC5hbGdvLnRzOjM4MgoJLy8gYXNzZXRSZWNlaXZlcjogc3Rha2VyCglmcmFtZV9kaWcgMCAvLyBzdGFrZXI6IGFkZHJlc3MKCWl0eG5fZmllbGQgQXNzZXRSZWNlaXZlcgoKCS8vIGNvbnRyYWN0cy9zdGFraW5nUG9vbC5hbGdvLnRzOjM4MwoJLy8gYXNzZXRBbW91bnQ6IGNtcFN0YWtlci5yZXdhcmRUb2tlbkJhbGFuY2UKCWZyYW1lX2RpZyAyIC8vIGNtcFN0YWtlcjogKGFkZHJlc3MsdWludDY0LHVpbnQ2NCx1aW50NjQsdWludDY0KQoJZXh0cmFjdCA0OCA4CglidG9pCglpdHhuX2ZpZWxkIEFzc2V0QW1vdW50CgoJLy8gRmVlIGZpZWxkIG5vdCBzZXQsIGRlZmF1bHRpbmcgdG8gMAoJaW50IDAKCWl0eG5fZmllbGQgRmVlCgoJLy8gU3VibWl0IGlubmVyIHRyYW5zYWN0aW9uCglpdHhuX3N1Ym1pdAoKCS8vIGNvbnRyYWN0cy9zdGFraW5nUG9vbC5hbGdvLnRzOjM4NQoJLy8gYW1vdW50UmV3YXJkVG9rZW5SZW1vdmVkID0gY21wU3Rha2VyLnJld2FyZFRva2VuQmFsYW5jZQoJZnJhbWVfZGlnIDIgLy8gY21wU3Rha2VyOiAoYWRkcmVzcyx1aW50NjQsdWludDY0LHVpbnQ2NCx1aW50NjQpCglleHRyYWN0IDQ4IDgKCWJ0b2kKCWZyYW1lX2J1cnkgMyAvLyBhbW91bnRSZXdhcmRUb2tlblJlbW92ZWQ6IHVpbnQ2NAoKCS8vIGNvbnRyYWN0cy9zdGFraW5nUG9vbC5hbGdvLnRzOjM4NgoJLy8gY21wU3Rha2VyLnJld2FyZFRva2VuQmFsYW5jZSA9IDAKCWZyYW1lX2RpZyAyIC8vIGNtcFN0YWtlcjogKGFkZHJlc3MsdWludDY0LHVpbnQ2NCx1aW50NjQsdWludDY0KQoJYnl0ZSAweDAwMDAwMDAwMDAwMDAwMDAKCXJlcGxhY2UyIDQ4CglmcmFtZV9idXJ5IDIgLy8gY21wU3Rha2VyOiAoYWRkcmVzcyx1aW50NjQsdWludDY0LHVpbnQ2NCx1aW50NjQpCgliICppZjE2X2VuZAoKKmlmMTZfZWxzZToKCS8vIGNvbnRyYWN0cy9zdGFraW5nUG9vbC5hbGdvLnRzOjM5MQoJLy8gYW1vdW50UmV3YXJkVG9rZW5SZW1vdmVkID0gY21wU3Rha2VyLnJld2FyZFRva2VuQmFsYW5jZQoJZnJhbWVfZGlnIDIgLy8gY21wU3Rha2VyOiAoYWRkcmVzcyx1aW50NjQsdWludDY0LHVpbnQ2NCx1aW50NjQpCglleHRyYWN0IDQ4IDgKCWJ0b2kKCWZyYW1lX2J1cnkgMyAvLyBhbW91bnRSZXdhcmRUb2tlblJlbW92ZWQ6IHVpbnQ2NAoKCS8vIGNvbnRyYWN0cy9zdGFraW5nUG9vbC5hbGdvLnRzOjM5MgoJLy8gY21wU3Rha2VyLnJld2FyZFRva2VuQmFsYW5jZSA9IDAKCWZyYW1lX2RpZyAyIC8vIGNtcFN0YWtlcjogKGFkZHJlc3MsdWludDY0LHVpbnQ2NCx1aW50NjQsdWludDY0KQoJYnl0ZSAweDAwMDAwMDAwMDAwMDAwMDAKCXJlcGxhY2UyIDQ4CglmcmFtZV9idXJ5IDIgLy8gY21wU3Rha2VyOiAoYWRkcmVzcyx1aW50NjQsdWludDY0LHVpbnQ2NCx1aW50NjQpCgoqaWYxNl9lbmQ6CgkvLyBjb250cmFjdHMvc3Rha2luZ1Bvb2wuYWxnby50czozOTYKCS8vIHRoaXMuc3Rha2Vycy52YWx1ZVtpXSA9IGNtcFN0YWtlcgoJZnJhbWVfZGlnIDEgLy8gaTogdWludDY0CglpbnQgNjQKCSogLy8gYWNjICogdHlwZUxlbmd0aAoJZnJhbWVfZGlnIDIgLy8gY21wU3Rha2VyOiAoYWRkcmVzcyx1aW50NjQsdWludDY0LHVpbnQ2NCx1aW50NjQpCglieXRlIDB4NzM3NDYxNmI2NTcyNzMgLy8gInN0YWtlcnMiCgljb3ZlciAyCglib3hfcmVwbGFjZQoKCS8vIGNvbnRyYWN0cy9zdGFraW5nUG9vbC5hbGdvLnRzOjQwMQoJLy8gc2VuZE1ldGhvZENhbGw8dHlwZW9mIFZhbGlkYXRvclJlZ2lzdHJ5LnByb3RvdHlwZS5zdGFrZVJlbW92ZWQ+KHsKCS8vICAgICAgICAgICAgICAgICAgICAgYXBwbGljYXRpb25JRDogQXBwSUQuZnJvbVVpbnQ2NCh0aGlzLmNyZWF0aW5nVmFsaWRhdG9yQ29udHJhY3RBcHBJZC52YWx1ZSksCgkvLyAgICAgICAgICAgICAgICAgICAgIG1ldGhvZEFyZ3M6IFsKCS8vICAgICAgICAgICAgICAgICAgICAgICAgIHsgaWQ6IHRoaXMudmFsaWRhdG9ySWQudmFsdWUsIHBvb2xJZDogdGhpcy5wb29sSWQudmFsdWUsIHBvb2xBcHBJZDogdGhpcy5hcHAuaWQgfSwKCS8vICAgICAgICAgICAgICAgICAgICAgICAgIHN0YWtlciwKCS8vICAgICAgICAgICAgICAgICAgICAgICAgIDAsIC8vIG5vIGFsZ28gcmVtb3ZlZAoJLy8gICAgICAgICAgICAgICAgICAgICAgICAgYW1vdW50UmV3YXJkVG9rZW5SZW1vdmVkLAoJLy8gICAgICAgICAgICAgICAgICAgICAgICAgZmFsc2UsIC8vIHN0YWtlciBpc24ndCBiZWluZyByZW1vdmVkLgoJLy8gICAgICAgICAgICAgICAgICAgICBdLAoJLy8gICAgICAgICAgICAgICAgIH0pCglpdHhuX2JlZ2luCglpbnQgYXBwbAoJaXR4bl9maWVsZCBUeXBlRW51bQoJbWV0aG9kICJzdGFrZVJlbW92ZWQoKHVpbnQ2NCx1aW50NjQsdWludDY0KSxhZGRyZXNzLHVpbnQ2NCx1aW50NjQsYm9vbCl2b2lkIgoJaXR4bl9maWVsZCBBcHBsaWNhdGlvbkFyZ3MKCgkvLyBjb250cmFjdHMvc3Rha2luZ1Bvb2wuYWxnby50czo0MDIKCS8vIGFwcGxpY2F0aW9uSUQ6IEFwcElELmZyb21VaW50NjQodGhpcy5jcmVhdGluZ1ZhbGlkYXRvckNvbnRyYWN0QXBwSWQudmFsdWUpCglieXRlIDB4NjM3MjY1NjE3NDZmNzI0MTcwNzAgLy8gImNyZWF0b3JBcHAiCglhcHBfZ2xvYmFsX2dldAoJaXR4bl9maWVsZCBBcHBsaWNhdGlvbklECgoJLy8gY29udHJhY3RzL3N0YWtpbmdQb29sLmFsZ28udHM6NDAzCgkvLyBtZXRob2RBcmdzOiBbCgkvLyAgICAgICAgICAgICAgICAgICAgICAgICB7IGlkOiB0aGlzLnZhbGlkYXRvcklkLnZhbHVlLCBwb29sSWQ6IHRoaXMucG9vbElkLnZhbHVlLCBwb29sQXBwSWQ6IHRoaXMuYXBwLmlkIH0sCgkvLyAgICAgICAgICAgICAgICAgICAgICAgICBzdGFrZXIsCgkvLyAgICAgICAgICAgICAgICAgICAgICAgICAwLCAvLyBubyBhbGdvIHJlbW92ZWQKCS8vICAgICAgICAgICAgICAgICAgICAgICAgIGFtb3VudFJld2FyZFRva2VuUmVtb3ZlZCwKCS8vICAgICAgICAgICAgICAgICAgICAgICAgIGZhbHNlLCAvLyBzdGFrZXIgaXNuJ3QgYmVpbmcgcmVtb3ZlZC4KCS8vICAgICAgICAgICAgICAgICAgICAgXQoJYnl0ZSAweDc2NjE2YzY5NjQ2MTc0NmY3MjQ5NjQgLy8gInZhbGlkYXRvcklkIgoJYXBwX2dsb2JhbF9nZXQKCWl0b2IKCWJ5dGUgMHg3MDZmNmY2YzQ5NjQgLy8gInBvb2xJZCIKCWFwcF9nbG9iYWxfZ2V0CglpdG9iCgljb25jYXQKCXR4bmEgQXBwbGljYXRpb25zIDAKCWl0b2IKCWNvbmNhdAoJaXR4bl9maWVsZCBBcHBsaWNhdGlvbkFyZ3MKCWZyYW1lX2RpZyAwIC8vIHN0YWtlcjogYWRkcmVzcwoJaXR4bl9maWVsZCBBcHBsaWNhdGlvbkFyZ3MKCWJ5dGUgMHgwMDAwMDAwMDAwMDAwMDAwCglpdHhuX2ZpZWxkIEFwcGxpY2F0aW9uQXJncwoJZnJhbWVfZGlnIDMgLy8gYW1vdW50UmV3YXJkVG9rZW5SZW1vdmVkOiB1aW50NjQKCWl0b2IKCWl0eG5fZmllbGQgQXBwbGljYXRpb25BcmdzCglpbnQgMAoJYnl0ZSAweDAwCglpbnQgMAoJdW5jb3ZlciAyCglzZXRiaXQKCWl0eG5fZmllbGQgQXBwbGljYXRpb25BcmdzCgoJLy8gRmVlIGZpZWxkIG5vdCBzZXQsIGRlZmF1bHRpbmcgdG8gMAoJaW50IDAKCWl0eG5fZmllbGQgRmVlCgoJLy8gU3VibWl0IGlubmVyIHRyYW5zYWN0aW9uCglpdHhuX3N1Ym1pdAoKCS8vIGNvbnRyYWN0cy9zdGFraW5nUG9vbC5hbGdvLnRzOjQxMQoJLy8gcmV0dXJuOwoJcmV0c3ViCgoqaWYxNF9lbmQ6CgoqZm9yXzJfY29udGludWU6CgkvLyBjb250cmFjdHMvc3Rha2luZ1Bvb2wuYWxnby50czozNjEKCS8vIGkgKz0gMQoJZnJhbWVfZGlnIDEgLy8gaTogdWludDY0CglpbnQgMQoJKwoJZnJhbWVfYnVyeSAxIC8vIGk6IHVpbnQ2NAoJYiAqZm9yXzIKCipmb3JfMl9lbmQ6CgllcnIgLy8gJ2FjY291bnQgbm90IGZvdW5kJwoKLy8gZ2V0U3Rha2VySW5mbyhhZGRyZXNzKShhZGRyZXNzLHVpbnQ2NCx1aW50NjQsdWludDY0LHVpbnQ2NCkKKmFiaV9yb3V0ZV9nZXRTdGFrZXJJbmZvOgoJLy8gVGhlIEFCSSByZXR1cm4gcHJlZml4CglieXRlIDB4MTUxZjdjNzUKCgkvLyBzdGFrZXI6IGFkZHJlc3MKCXR4bmEgQXBwbGljYXRpb25BcmdzIDEKCWR1cAoJbGVuCglpbnQgMzIKCT09Cglhc3NlcnQKCgkvLyBleGVjdXRlIGdldFN0YWtlckluZm8oYWRkcmVzcykoYWRkcmVzcyx1aW50NjQsdWludDY0LHVpbnQ2NCx1aW50NjQpCgljYWxsc3ViIGdldFN0YWtlckluZm8KCWNvbmNhdAoJbG9nCglpbnQgMQoJcmV0dXJuCgovLyBnZXRTdGFrZXJJbmZvKHN0YWtlcjogQWRkcmVzcyk6IFN0YWtlZEluZm8KLy8KLy8gUmV0cmlldmVzIHRoZSBzdGFrZWQgaW5mb3JtYXRpb24gZm9yIGEgZ2l2ZW4gc3Rha2VyLgovLwovLyBAcGFyYW0ge0FkZHJlc3N9IHN0YWtlciAtIFRoZSBhZGRyZXNzIG9mIHRoZSBzdGFrZXIuCi8vIEByZXR1cm5zIHtTdGFrZWRJbmZvfSAtIFRoZSBzdGFrZWQgaW5mb3JtYXRpb24gZm9yIHRoZSBnaXZlbiBzdGFrZXIuCi8vIEB0aHJvd3Mge0Vycm9yfSAtIElmIHRoZSBzdGFrZXIncyBhY2NvdW50IGlzIG5vdCBmb3VuZC4KZ2V0U3Rha2VySW5mbzoKCXByb3RvIDEgMQoKCS8vIFB1c2ggZW1wdHkgYnl0ZXMgYWZ0ZXIgdGhlIGZyYW1lIHBvaW50ZXIgdG8gcmVzZXJ2ZSBzcGFjZSBmb3IgbG9jYWwgdmFyaWFibGVzCglieXRlIDB4CgoJLy8gY29udHJhY3RzL3N0YWtpbmdQb29sLmFsZ28udHM6NDI2CgkvLyBmb3IgKGxldCBpID0gMDsgaSA8IHRoaXMuc3Rha2Vycy52YWx1ZS5sZW5ndGg7IGkgKz0gMSkKCWludCAwCglmcmFtZV9idXJ5IDAgLy8gaTogdWludDY0CgoqZm9yXzM6CgkvLyBjb250cmFjdHMvc3Rha2luZ1Bvb2wuYWxnby50czo0MjYKCS8vIGkgPCB0aGlzLnN0YWtlcnMudmFsdWUubGVuZ3RoCglmcmFtZV9kaWcgMCAvLyBpOiB1aW50NjQKCWludCAyMDAKCTwKCWJ6ICpmb3JfM19lbmQKCgkvLyAqaWYxN19jb25kaXRpb24KCS8vIGNvbnRyYWN0cy9zdGFraW5nUG9vbC5hbGdvLnRzOjQyNwoJLy8gZ2xvYmFscy5vcGNvZGVCdWRnZXQgPCAyMDAKCWdsb2JhbCBPcGNvZGVCdWRnZXQKCWludCAyMDAKCTwKCWJ6ICppZjE3X2VuZAoKCS8vICppZjE3X2NvbnNlcXVlbnQKCS8vIGNvbnRyYWN0cy9zdGFraW5nUG9vbC5hbGdvLnRzOjQyOAoJLy8gaW5jcmVhc2VPcGNvZGVCdWRnZXQoKQoJaXR4bl9iZWdpbgoJaW50IGFwcGwKCWl0eG5fZmllbGQgVHlwZUVudW0KCWludCAwCglpdHhuX2ZpZWxkIEZlZQoJYnl0ZSBiNjQgQ29FQiAvLyAjcHJhZ21hIHZlcnNpb24gMTA7IGludCAxCglkdXAKCWl0eG5fZmllbGQgQXBwcm92YWxQcm9ncmFtCglpdHhuX2ZpZWxkIENsZWFyU3RhdGVQcm9ncmFtCglpbnQgRGVsZXRlQXBwbGljYXRpb24KCWl0eG5fZmllbGQgT25Db21wbGV0aW9uCglpdHhuX3N1Ym1pdAoKKmlmMTdfZW5kOgoJLy8gKmlmMThfY29uZGl0aW9uCgkvLyBjb250cmFjdHMvc3Rha2luZ1Bvb2wuYWxnby50czo0MzAKCS8vIHRoaXMuc3Rha2Vycy52YWx1ZVtpXS5hY2NvdW50ID09PSBzdGFrZXIKCWZyYW1lX2RpZyAwIC8vIGk6IHVpbnQ2NAoJaW50IDY0CgkqIC8vIGFjYyAqIHR5cGVMZW5ndGgKCWludCAwCgkrCglpbnQgMzIKCWJ5dGUgMHg3Mzc0NjE2YjY1NzI3MyAvLyAic3Rha2VycyIKCWNvdmVyIDIKCWJveF9leHRyYWN0CglmcmFtZV9kaWcgLTEgLy8gc3Rha2VyOiBBZGRyZXNzCgk9PQoJYnogKmlmMThfZW5kCgoJLy8gKmlmMThfY29uc2VxdWVudAoJLy8gY29udHJhY3RzL3N0YWtpbmdQb29sLmFsZ28udHM6NDMxCgkvLyByZXR1cm4gdGhpcy5zdGFrZXJzLnZhbHVlW2ldOwoJZnJhbWVfZGlnIDAgLy8gaTogdWludDY0CglpbnQgNjQKCSogLy8gYWNjICogdHlwZUxlbmd0aAoJaW50IDY0CglieXRlIDB4NzM3NDYxNmI2NTcyNzMgLy8gInN0YWtlcnMiCgljb3ZlciAyCglib3hfZXh0cmFjdAoKCS8vIHNldCB0aGUgc3Vicm91dGluZSByZXR1cm4gdmFsdWUKCWZyYW1lX2J1cnkgMAoJcmV0c3ViCgoqaWYxOF9lbmQ6CgoqZm9yXzNfY29udGludWU6CgkvLyBjb250cmFjdHMvc3Rha2luZ1Bvb2wuYWxnby50czo0MjYKCS8vIGkgKz0gMQoJZnJhbWVfZGlnIDAgLy8gaTogdWludDY0CglpbnQgMQoJKwoJZnJhbWVfYnVyeSAwIC8vIGk6IHVpbnQ2NAoJYiAqZm9yXzMKCipmb3JfM19lbmQ6CgllcnIgLy8gJ2FjY291bnQgbm90IGZvdW5kJwoKLy8gcGF5VG9rZW5SZXdhcmQoYWRkcmVzcyx1aW50NjQsdWludDY0KXZvaWQKKmFiaV9yb3V0ZV9wYXlUb2tlblJld2FyZDoKCS8vIGFtb3VudFRvU2VuZDogdWludDY0Cgl0eG5hIEFwcGxpY2F0aW9uQXJncyAzCglidG9pCgoJLy8gcmV3YXJkVG9rZW46IHVpbnQ2NAoJdHhuYSBBcHBsaWNhdGlvbkFyZ3MgMgoJYnRvaQoKCS8vIHN0YWtlcjogYWRkcmVzcwoJdHhuYSBBcHBsaWNhdGlvbkFyZ3MgMQoJZHVwCglsZW4KCWludCAzMgoJPT0KCWFzc2VydAoKCS8vIGV4ZWN1dGUgcGF5VG9rZW5SZXdhcmQoYWRkcmVzcyx1aW50NjQsdWludDY0KXZvaWQKCWNhbGxzdWIgcGF5VG9rZW5SZXdhcmQKCWludCAxCglyZXR1cm4KCi8vIHBheVRva2VuUmV3YXJkKHN0YWtlcjogQWRkcmVzcywgcmV3YXJkVG9rZW46IHVpbnQ2NCwgYW1vdW50VG9TZW5kOiB1aW50NjQpOiB2b2lkCi8vCi8vIFtJbnRlcm5hbCBwcm90b2NvbCBtZXRob2RdIFJlbW92ZSBhIHNwZWNpZmllZCBhbW91bnQgb2YgJ2NvbW11bml0eSB0b2tlbicgcmV3YXJkcyBmb3IgYSBzdGFrZXIuCi8vIFRoaXMgY2FuIE9OTFkgYmUgY2FsbGVkIGJ5IG91ciB2YWxpZGF0b3IgYW5kIG9ubHkgaWYgd2UncmUgcG9vbCAxIC0gd2l0aCB0aGUgdG9rZW4uCi8vIEBwYXJhbSBzdGFrZXIgLSB0aGUgc3Rha2VyIGFjY291bnQgdG8gc2VuZCByZXdhcmRzIHRvCi8vIEBwYXJhbSByZXdhcmRUb2tlbiAtIGlkIG9mIHJld2FyZCB0b2tlbiAodG8gYXZvaWQgcmUtZW50cmFuY3kgaW4gY2FsbGluZyB2YWxpZGF0b3IgYmFjayB0byBnZXQgaWQpCi8vIEBwYXJhbSBhbW91bnRUb1NlbmQgLSBhbW91bnQgdG8gc2VuZCB0aGUgc3Rha2VyICh0aGVyZSBpcyBzaWduaWZpY2FudCB0cnVzdCBoZXJlKCEpIC0gYWxzbyB3aHkgb25seSB2YWxpZGF0b3IgY2FuIGNhbGwgdXMKcGF5VG9rZW5SZXdhcmQ6Cglwcm90byAzIDAKCgkvLyBjb250cmFjdHMvc3Rha2luZ1Bvb2wuYWxnby50czo0NDYKCS8vIGFzc2VydCh0aGlzLnR4bi5zZW5kZXIgPT09IEFwcElELmZyb21VaW50NjQodGhpcy5jcmVhdGluZ1ZhbGlkYXRvckNvbnRyYWN0QXBwSWQudmFsdWUpLmFkZHJlc3MpCgl0eG4gU2VuZGVyCglieXRlIDB4NjM3MjY1NjE3NDZmNzI0MTcwNzAgLy8gImNyZWF0b3JBcHAiCglhcHBfZ2xvYmFsX2dldAoJYXBwX3BhcmFtc19nZXQgQXBwQWRkcmVzcwoJcG9wCgk9PQoJYXNzZXJ0CgoJLy8gY29udHJhY3RzL3N0YWtpbmdQb29sLmFsZ28udHM6NDQ3CgkvLyBhc3NlcnQodGhpcy5wb29sSWQudmFsdWUgPT09IDEsICdtdXN0IGJlIHBvb2wgMSBpbiBvcmRlciB0byBiZSBjYWxsZWQgdG8gcGF5IG91dCB0b2tlbiByZXdhcmRzJykKCWJ5dGUgMHg3MDZmNmY2YzQ5NjQgLy8gInBvb2xJZCIKCWFwcF9nbG9iYWxfZ2V0CglpbnQgMQoJPT0KCgkvLyBtdXN0IGJlIHBvb2wgMSBpbiBvcmRlciB0byBiZSBjYWxsZWQgdG8gcGF5IG91dCB0b2tlbiByZXdhcmRzCglhc3NlcnQKCgkvLyBjb250cmFjdHMvc3Rha2luZ1Bvb2wuYWxnby50czo0NDgKCS8vIGFzc2VydChyZXdhcmRUb2tlbiAhPT0gMCwgJ2NhbiBvbmx5IGNsYWltIHRva2VuIHJld2FyZHMgZnJvbSB2YWxpZGF0b3IgdGhhdCBoYXMgdGhlbScpCglmcmFtZV9kaWcgLTIgLy8gcmV3YXJkVG9rZW46IHVpbnQ2NAoJaW50IDAKCSE9CgoJLy8gY2FuIG9ubHkgY2xhaW0gdG9rZW4gcmV3YXJkcyBmcm9tIHZhbGlkYXRvciB0aGF0IGhhcyB0aGVtCglhc3NlcnQKCgkvLyBjb250cmFjdHMvc3Rha2luZ1Bvb2wuYWxnby50czo0NTEKCS8vIHNlbmRBc3NldFRyYW5zZmVyKHsKCS8vICAgICAgICAgICAgIHhmZXJBc3NldDogQXNzZXRJRC5mcm9tVWludDY0KHJld2FyZFRva2VuKSwKCS8vICAgICAgICAgICAgIGFzc2V0UmVjZWl2ZXI6IHN0YWtlciwKCS8vICAgICAgICAgICAgIGFzc2V0QW1vdW50OiBhbW91bnRUb1NlbmQsCgkvLyAgICAgICAgIH0pCglpdHhuX2JlZ2luCglpbnQgYXhmZXIKCWl0eG5fZmllbGQgVHlwZUVudW0KCgkvLyBjb250cmFjdHMvc3Rha2luZ1Bvb2wuYWxnby50czo0NTIKCS8vIHhmZXJBc3NldDogQXNzZXRJRC5mcm9tVWludDY0KHJld2FyZFRva2VuKQoJZnJhbWVfZGlnIC0yIC8vIHJld2FyZFRva2VuOiB1aW50NjQKCWl0eG5fZmllbGQgWGZlckFzc2V0CgoJLy8gY29udHJhY3RzL3N0YWtpbmdQb29sLmFsZ28udHM6NDUzCgkvLyBhc3NldFJlY2VpdmVyOiBzdGFrZXIKCWZyYW1lX2RpZyAtMSAvLyBzdGFrZXI6IEFkZHJlc3MKCWl0eG5fZmllbGQgQXNzZXRSZWNlaXZlcgoKCS8vIGNvbnRyYWN0cy9zdGFraW5nUG9vbC5hbGdvLnRzOjQ1NAoJLy8gYXNzZXRBbW91bnQ6IGFtb3VudFRvU2VuZAoJZnJhbWVfZGlnIC0zIC8vIGFtb3VudFRvU2VuZDogdWludDY0CglpdHhuX2ZpZWxkIEFzc2V0QW1vdW50CgoJLy8gRmVlIGZpZWxkIG5vdCBzZXQsIGRlZmF1bHRpbmcgdG8gMAoJaW50IDAKCWl0eG5fZmllbGQgRmVlCgoJLy8gU3VibWl0IGlubmVyIHRyYW5zYWN0aW9uCglpdHhuX3N1Ym1pdAoJcmV0c3ViCgovLyB1cGRhdGVBbGdvZFZlcihzdHJpbmcpdm9pZAoqYWJpX3JvdXRlX3VwZGF0ZUFsZ29kVmVyOgoJLy8gYWxnb2RWZXI6IHN0cmluZwoJdHhuYSBBcHBsaWNhdGlvbkFyZ3MgMQoJZXh0cmFjdCAyIDAKCgkvLyBleGVjdXRlIHVwZGF0ZUFsZ29kVmVyKHN0cmluZyl2b2lkCgljYWxsc3ViIHVwZGF0ZUFsZ29kVmVyCglpbnQgMQoJcmV0dXJuCgovLyB1cGRhdGVBbGdvZFZlcihhbGdvZFZlcjogc3RyaW5nKTogdm9pZAovLwovLyBVcGRhdGUgdGhlIChob25vciBzeXN0ZW0pIGFsZ29kIHZlcnNpb24gZm9yIHRoZSBub2RlIGFzc29jaWF0ZWQgdG8gdGhpcyBwb29sLiAgVGhlIG5vZGUgbWFuYWdlbWVudCBkYWVtb24KLy8gc2hvdWxkIGNvbXBhcmUgaXRzIGN1cnJlbnQgbm9kZXMgdmVyc2lvbiB0byB0aGUgdmVyc2lvbiBzdG9yZWQgaW4gZ2xvYmFsIHN0YXRlLCB1cGRhdGluZyB3aGVuIGRpZmZlcmVudC4KLy8gVGhlIHJldGkgbm9kZSBkYWVtb24gY29tcG9zZXMgaXRzIG93biB2ZXJzaW9uIHN0cmluZyB1c2luZyBmb3JtYXQ6Ci8vIHttYWpvcn0ue21pbm9yfS57YnVpbGR9IHticmFuY2h9IFt7Y29tbWl0IGhhc2h9XSwKLy8gaWU6IDMuMjIuMCByZWwvc3RhYmxlIFs2YjUwODk3NV0KLy8gWyBPTkxZIE9XTkVSIE9SIE1BTkFHRVIgQ0FOIENBTEwgXQovLyBAcGFyYW0ge3N0cmluZ30gYWxnb2RWZXIgLSBzdHJpbmcgcmVwcmVzZW50aW5nIHRoZSBhbGdvcmFuZCBub2RlIGRhZW1vbiB2ZXJzaW9uIChyZXRpIG5vZGUgZGFlbW9uIGNvbXBvc2VzIGl0cyBvd24gbWV0YSB2ZXJzaW9uKQp1cGRhdGVBbGdvZFZlcjoKCXByb3RvIDEgMAoKCS8vIGNvbnRyYWN0cy9zdGFraW5nUG9vbC5hbGdvLnRzOjQ2OAoJLy8gYXNzZXJ0KHRoaXMuaXNPd25lck9yTWFuYWdlckNhbGxlcigpKQoJY2FsbHN1YiBpc093bmVyT3JNYW5hZ2VyQ2FsbGVyCglhc3NlcnQKCgkvLyBjb250cmFjdHMvc3Rha2luZ1Bvb2wuYWxnby50czo0NjkKCS8vIHRoaXMuYWxnb2RWZXIudmFsdWUgPSBhbGdvZFZlcgoJYnl0ZSAweDYxNmM2NzZmNjQ1NjY1NzIgLy8gImFsZ29kVmVyIgoJZnJhbWVfZGlnIC0xIC8vIGFsZ29kVmVyOiBzdHJpbmcKCWFwcF9nbG9iYWxfcHV0CglyZXRzdWIKCi8vIGVwb2NoQmFsYW5jZVVwZGF0ZSgpdm9pZAoqYWJpX3JvdXRlX2Vwb2NoQmFsYW5jZVVwZGF0ZToKCS8vIGV4ZWN1dGUgZXBvY2hCYWxhbmNlVXBkYXRlKCl2b2lkCgljYWxsc3ViIGVwb2NoQmFsYW5jZVVwZGF0ZQoJaW50IDEKCXJldHVybgoKLy8gZXBvY2hCYWxhbmNlVXBkYXRlKCk6IHZvaWQKLy8KLy8gVXBkYXRlcyB0aGUgYmFsYW5jZSBvZiBzdGFrZXJzIGluIHRoZSBwb29sIGJhc2VkIG9uIHRoZSByZWNlaXZlZCAncmV3YXJkcycgKGN1cnJlbnQgYmFsYW5jZSB2cyBrbm93biBzdGFrZWQgYmFsYW5jZSkKLy8gc3Rha2VycyBvdXRzdGFuZGluZyBiYWxhbmNlIGlzIGFkanVzdGVkIGJhc2VkIG9uIHRoZWlyICUgb2Ygc3Rha2UgYW5kIHRpbWUgaW4gdGhlIGN1cnJlbnQgZXBvY2ggLSBzbyB0aGF0IGJhbGFuY2UKLy8gY29tcG91bmRzIG92ZXIgdGltZSBhbmQgc3Rha2VyIGNhbiByZW1vdmUgdGhhdCBhbW91bnQgYXQgd2lsbC4KLy8gVGhlIHZhbGlkYXRvciBpcyBwYWlkIHRoZWlyIHBlcmNlbnRhZ2UgZWFjaCBlcG9jaCBwYXlvdXQuCi8vCi8vIE5vdGU6IEFOWU9ORSBjYW4gY2FsbCB0aGlzLgplcG9jaEJhbGFuY2VVcGRhdGU6Cglwcm90byAwIDAKCgkvLyBQdXNoIGVtcHR5IGJ5dGVzIGFmdGVyIHRoZSBmcmFtZSBwb2ludGVyIHRvIHJlc2VydmUgc3BhY2UgZm9yIGxvY2FsIHZhcmlhYmxlcwoJYnl0ZSAweAoJZHVwbiAzMwoKCS8vIGNvbnRyYWN0cy9zdGFraW5nUG9vbC5hbGdvLnRzOjQ4MgoJLy8gdmFsaWRhdG9yQ29uZmlnID0gc2VuZE1ldGhvZENhbGw8dHlwZW9mIFZhbGlkYXRvclJlZ2lzdHJ5LnByb3RvdHlwZS5nZXRWYWxpZGF0b3JDb25maWc+KHsKCS8vICAgICAgICAgICAgIGFwcGxpY2F0aW9uSUQ6IEFwcElELmZyb21VaW50NjQodGhpcy5jcmVhdGluZ1ZhbGlkYXRvckNvbnRyYWN0QXBwSWQudmFsdWUpLAoJLy8gICAgICAgICAgICAgbWV0aG9kQXJnczogW3RoaXMudmFsaWRhdG9ySWQudmFsdWVdLAoJLy8gICAgICAgICB9KQoJaXR4bl9iZWdpbgoJaW50IGFwcGwKCWl0eG5fZmllbGQgVHlwZUVudW0KCW1ldGhvZCAiZ2V0VmFsaWRhdG9yQ29uZmlnKHVpbnQ2NCkodWludDY0LGFkZHJlc3MsYWRkcmVzcyx1aW50NjQsdWludDgsYnl0ZVszMl0sdWludDY0LHVpbnQ2NCx1aW50NjQsdWludDE2LHVpbnQzMixhZGRyZXNzLHVpbnQ2NCx1aW50NjQsdWludDgsdWludDY0LHVpbnQ2NCkiCglpdHhuX2ZpZWxkIEFwcGxpY2F0aW9uQXJncwoKCS8vIGNvbnRyYWN0cy9zdGFraW5nUG9vbC5hbGdvLnRzOjQ4MwoJLy8gYXBwbGljYXRpb25JRDogQXBwSUQuZnJvbVVpbnQ2NCh0aGlzLmNyZWF0aW5nVmFsaWRhdG9yQ29udHJhY3RBcHBJZC52YWx1ZSkKCWJ5dGUgMHg2MzcyNjU2MTc0NmY3MjQxNzA3MCAvLyAiY3JlYXRvckFwcCIKCWFwcF9nbG9iYWxfZ2V0CglpdHhuX2ZpZWxkIEFwcGxpY2F0aW9uSUQKCgkvLyBjb250cmFjdHMvc3Rha2luZ1Bvb2wuYWxnby50czo0ODQKCS8vIG1ldGhvZEFyZ3M6IFt0aGlzLnZhbGlkYXRvcklkLnZhbHVlXQoJYnl0ZSAweDc2NjE2YzY5NjQ2MTc0NmY3MjQ5NjQgLy8gInZhbGlkYXRvcklkIgoJYXBwX2dsb2JhbF9nZXQKCWl0b2IKCWl0eG5fZmllbGQgQXBwbGljYXRpb25BcmdzCgoJLy8gRmVlIGZpZWxkIG5vdCBzZXQsIGRlZmF1bHRpbmcgdG8gMAoJaW50IDAKCWl0eG5fZmllbGQgRmVlCgoJLy8gU3VibWl0IGlubmVyIHRyYW5zYWN0aW9uCglpdHhuX3N1Ym1pdAoJaXR4biBOdW1Mb2dzCglpbnQgMQoJLQoJaXR4bmFzIExvZ3MKCWV4dHJhY3QgNCAwCglmcmFtZV9idXJ5IDAgLy8gdmFsaWRhdG9yQ29uZmlnOiAodWludDY0LGFkZHJlc3MsYWRkcmVzcyx1aW50NjQsdWludDgsYnl0ZVszMl0sdWludDY0LHVpbnQ2NCx1aW50NjQsdWludDE2LHVpbnQzMixhZGRyZXNzLHVpbnQ2NCx1aW50NjQsdWludDgsdWludDY0LHVpbnQ2NCkKCgkvLyBjb250cmFjdHMvc3Rha2luZ1Bvb2wuYWxnby50czo0OTIKCS8vIGN1clRpbWUgPSBnbG9iYWxzLmxhdGVzdFRpbWVzdGFtcAoJZ2xvYmFsIExhdGVzdFRpbWVzdGFtcAoJZnJhbWVfYnVyeSAxIC8vIGN1clRpbWU6IHVpbnQ2NAoKCS8vIGNvbnRyYWN0cy9zdGFraW5nUG9vbC5hbGdvLnRzOjQ5NAoJLy8gZXBvY2hJblNlY3MgPSAodmFsaWRhdG9yQ29uZmlnLnBheW91dEV2ZXJ5WE1pbnMgYXMgdWludDY0KSAqIDYwCglmcmFtZV9kaWcgMCAvLyB2YWxpZGF0b3JDb25maWc6ICh1aW50NjQsYWRkcmVzcyxhZGRyZXNzLHVpbnQ2NCx1aW50OCxieXRlWzMyXSx1aW50NjQsdWludDY0LHVpbnQ2NCx1aW50MTYsdWludDMyLGFkZHJlc3MsdWludDY0LHVpbnQ2NCx1aW50OCx1aW50NjQsdWludDY0KQoJZXh0cmFjdCAxMzcgMgoJYnRvaQoJaW50IDYwCgkqCglmcmFtZV9idXJ5IDIgLy8gZXBvY2hJblNlY3M6IHVpbnQ2NAoKCS8vICppZjE5X2NvbmRpdGlvbgoJLy8gY29udHJhY3RzL3N0YWtpbmdQb29sLmFsZ28udHM6NDk1CgkvLyB0aGlzLmxhc3RQYXlvdXQuZXhpc3RzCgl0eG5hIEFwcGxpY2F0aW9ucyAwCglieXRlIDB4NmM2MTczNzQ1MDYxNzk2Zjc1NzQgLy8gImxhc3RQYXlvdXQiCglhcHBfZ2xvYmFsX2dldF9leAoJc3dhcAoJcG9wCglieiAqaWYxOV9lbmQKCgkvLyAqaWYxOV9jb25zZXF1ZW50CgkvLyBjb250cmFjdHMvc3Rha2luZ1Bvb2wuYWxnby50czo0OTYKCS8vIHNlY3NTaW5jZUxhc3RQYXlvdXQgPSBjdXJUaW1lIC0gdGhpcy5sYXN0UGF5b3V0LnZhbHVlCglmcmFtZV9kaWcgMSAvLyBjdXJUaW1lOiB1aW50NjQKCWJ5dGUgMHg2YzYxNzM3NDUwNjE3OTZmNzU3NCAvLyAibGFzdFBheW91dCIKCWFwcF9nbG9iYWxfZ2V0CgktCglmcmFtZV9idXJ5IDMgLy8gc2Vjc1NpbmNlTGFzdFBheW91dDogdWludDY0CgoJLy8gY29udHJhY3RzL3N0YWtpbmdQb29sLmFsZ28udHM6NDk3CgkvLyBsb2coY29uY2F0KCdzZWNzIHNpbmNlIGxhc3QgcGF5b3V0OiAlaScsIGl0b2Ioc2Vjc1NpbmNlTGFzdFBheW91dCkpKQoJYnl0ZSAweDczNjU2MzczMjA3MzY5NmU2MzY1MjA2YzYxNzM3NDIwNzA2MTc5NmY3NTc0M2EyMDI1NjkgLy8gInNlY3Mgc2luY2UgbGFzdCBwYXlvdXQ6ICVpIgoJZnJhbWVfZGlnIDMgLy8gc2Vjc1NpbmNlTGFzdFBheW91dDogdWludDY0CglpdG9iCgljb25jYXQKCWxvZwoKCS8vIGNvbnRyYWN0cy9zdGFraW5nUG9vbC5hbGdvLnRzOjUwMAoJLy8gYXNzZXJ0KHNlY3NTaW5jZUxhc3RQYXlvdXQgPj0gZXBvY2hJblNlY3MsICJDYW4ndCBwYXlvdXQgZWFybGllciB0aGFuIGxhc3QgcGF5b3V0ICsgZXBvY2ggdGltZSIpCglmcmFtZV9kaWcgMyAvLyBzZWNzU2luY2VMYXN0UGF5b3V0OiB1aW50NjQKCWZyYW1lX2RpZyAyIC8vIGVwb2NoSW5TZWNzOiB1aW50NjQKCT49CgoJLy8gQ2FuJ3QgcGF5b3V0IGVhcmxpZXIgdGhhbiBsYXN0IHBheW91dCArIGVwb2NoIHRpbWUKCWFzc2VydAoKKmlmMTlfZW5kOgoJLy8gY29udHJhY3RzL3N0YWtpbmdQb29sLmFsZ28udHM6NTAzCgkvLyB0aGlzLmxhc3RQYXlvdXQudmFsdWUgPSBjdXJUaW1lCglieXRlIDB4NmM2MTczNzQ1MDYxNzk2Zjc1NzQgLy8gImxhc3RQYXlvdXQiCglmcmFtZV9kaWcgMSAvLyBjdXJUaW1lOiB1aW50NjQKCWFwcF9nbG9iYWxfcHV0CgoJLy8gY29udHJhY3RzL3N0YWtpbmdQb29sLmFsZ28udHM6NTA0CgkvLyB0aGlzLmVwb2NoTnVtYmVyLnZhbHVlICs9IDEKCWJ5dGUgMHg2NTcwNmY2MzY4NGU3NTZkNjI2NTcyIC8vICJlcG9jaE51bWJlciIKCWFwcF9nbG9iYWxfZ2V0CglpbnQgMQoJKwoJYnl0ZSAweDY1NzA2ZjYzNjg0ZTc1NmQ2MjY1NzIgLy8gImVwb2NoTnVtYmVyIgoJc3dhcAoJYXBwX2dsb2JhbF9wdXQKCgkvLyBjb250cmFjdHMvc3Rha2luZ1Bvb2wuYWxnby50czo1MDkKCS8vIGlzVG9rZW5FbGlnaWJsZSA9IHZhbGlkYXRvckNvbmZpZy5yZXdhcmRUb2tlbklkICE9PSAwCglmcmFtZV9kaWcgMCAvLyB2YWxpZGF0b3JDb25maWc6ICh1aW50NjQsYWRkcmVzcyxhZGRyZXNzLHVpbnQ2NCx1aW50OCxieXRlWzMyXSx1aW50NjQsdWludDY0LHVpbnQ2NCx1aW50MTYsdWludDMyLGFkZHJlc3MsdWludDY0LHVpbnQ2NCx1aW50OCx1aW50NjQsdWludDY0KQoJZXh0cmFjdCAxMjEgOAoJYnRvaQoJaW50IDAKCSE9CglmcmFtZV9idXJ5IDQgLy8gaXNUb2tlbkVsaWdpYmxlOiBib29sCgoJLy8gY29udHJhY3RzL3N0YWtpbmdQb29sLmFsZ28udHM6NTEwCgkvLyBwb29sT25lQXBwSUQgPSB0aGlzLmFwcC5pZAoJdHhuYSBBcHBsaWNhdGlvbnMgMAoJZnJhbWVfYnVyeSA1IC8vIHBvb2xPbmVBcHBJRDogdWludDY0CgoJLy8gY29udHJhY3RzL3N0YWtpbmdQb29sLmFsZ28udHM6NTExCgkvLyBwb29sT25lQWRkcmVzcyA9IHRoaXMuYXBwLmFkZHJlc3MKCWdsb2JhbCBDdXJyZW50QXBwbGljYXRpb25BZGRyZXNzCglmcmFtZV9idXJ5IDYgLy8gcG9vbE9uZUFkZHJlc3M6IGFkZHJlc3MKCgkvLyAqaWYyMF9jb25kaXRpb24KCS8vIGNvbnRyYWN0cy9zdGFraW5nUG9vbC5hbGdvLnRzOjUxNgoJLy8gaXNUb2tlbkVsaWdpYmxlCglmcmFtZV9kaWcgNCAvLyBpc1Rva2VuRWxpZ2libGU6IGJvb2wKCWJ6ICppZjIwX2VuZAoKCS8vICppZjIwX2NvbnNlcXVlbnQKCS8vICppZjIxX2NvbmRpdGlvbgoJLy8gY29udHJhY3RzL3N0YWtpbmdQb29sLmFsZ28udHM6NTE3CgkvLyB0aGlzLnBvb2xJZC52YWx1ZSAhPT0gMQoJYnl0ZSAweDcwNmY2ZjZjNDk2NCAvLyAicG9vbElkIgoJYXBwX2dsb2JhbF9nZXQKCWludCAxCgkhPQoJYnogKmlmMjFfZW5kCgoJLy8gKmlmMjFfY29uc2VxdWVudAoJLy8gY29udHJhY3RzL3N0YWtpbmdQb29sLmFsZ28udHM6NTE5CgkvLyBwb29sT25lQXBwSUQgPSBzZW5kTWV0aG9kQ2FsbDx0eXBlb2YgVmFsaWRhdG9yUmVnaXN0cnkucHJvdG90eXBlLmdldFBvb2xBcHBJZD4oewoJLy8gICAgICAgICAgICAgICAgICAgICBhcHBsaWNhdGlvbklEOiBBcHBJRC5mcm9tVWludDY0KHRoaXMuY3JlYXRpbmdWYWxpZGF0b3JDb250cmFjdEFwcElkLnZhbHVlKSwKCS8vICAgICAgICAgICAgICAgICAgICAgbWV0aG9kQXJnczogW3RoaXMudmFsaWRhdG9ySWQudmFsdWUsIDFdLAoJLy8gICAgICAgICAgICAgICAgIH0pCglpdHhuX2JlZ2luCglpbnQgYXBwbAoJaXR4bl9maWVsZCBUeXBlRW51bQoJbWV0aG9kICJnZXRQb29sQXBwSWQodWludDY0LHVpbnQ2NCl1aW50NjQiCglpdHhuX2ZpZWxkIEFwcGxpY2F0aW9uQXJncwoKCS8vIGNvbnRyYWN0cy9zdGFraW5nUG9vbC5hbGdvLnRzOjUyMAoJLy8gYXBwbGljYXRpb25JRDogQXBwSUQuZnJvbVVpbnQ2NCh0aGlzLmNyZWF0aW5nVmFsaWRhdG9yQ29udHJhY3RBcHBJZC52YWx1ZSkKCWJ5dGUgMHg2MzcyNjU2MTc0NmY3MjQxNzA3MCAvLyAiY3JlYXRvckFwcCIKCWFwcF9nbG9iYWxfZ2V0CglpdHhuX2ZpZWxkIEFwcGxpY2F0aW9uSUQKCgkvLyBjb250cmFjdHMvc3Rha2luZ1Bvb2wuYWxnby50czo1MjEKCS8vIG1ldGhvZEFyZ3M6IFt0aGlzLnZhbGlkYXRvcklkLnZhbHVlLCAxXQoJYnl0ZSAweDc2NjE2YzY5NjQ2MTc0NmY3MjQ5NjQgLy8gInZhbGlkYXRvcklkIgoJYXBwX2dsb2JhbF9nZXQKCWl0b2IKCWl0eG5fZmllbGQgQXBwbGljYXRpb25BcmdzCglieXRlIDB4MDAwMDAwMDAwMDAwMDAwMQoJaXR4bl9maWVsZCBBcHBsaWNhdGlvbkFyZ3MKCgkvLyBGZWUgZmllbGQgbm90IHNldCwgZGVmYXVsdGluZyB0byAwCglpbnQgMAoJaXR4bl9maWVsZCBGZWUKCgkvLyBTdWJtaXQgaW5uZXIgdHJhbnNhY3Rpb24KCWl0eG5fc3VibWl0CglpdHhuIE51bUxvZ3MKCWludCAxCgktCglpdHhuYXMgTG9ncwoJZXh0cmFjdCA0IDAKCWJ0b2kKCWZyYW1lX2J1cnkgNSAvLyBwb29sT25lQXBwSUQ6IHVpbnQ2NAoKCS8vIGNvbnRyYWN0cy9zdGFraW5nUG9vbC5hbGdvLnRzOjUyMwoJLy8gcG9vbE9uZUFkZHJlc3MgPSBBcHBJRC5mcm9tVWludDY0KHBvb2xPbmVBcHBJRCkuYWRkcmVzcwoJZnJhbWVfZGlnIDUgLy8gcG9vbE9uZUFwcElEOiB1aW50NjQKCWFwcF9wYXJhbXNfZ2V0IEFwcEFkZHJlc3MKCXBvcAoJZnJhbWVfYnVyeSA2IC8vIHBvb2xPbmVBZGRyZXNzOiBhZGRyZXNzCgoqaWYyMV9lbmQ6CgkvLyAqaWYyMl9jb25kaXRpb24KCS8vIGNvbnRyYWN0cy9zdGFraW5nUG9vbC5hbGdvLnRzOjUyOAoJLy8gdGhpcy5wb29sSWQudmFsdWUgPT09IDEKCWJ5dGUgMHg3MDZmNmY2YzQ5NjQgLy8gInBvb2xJZCIKCWFwcF9nbG9iYWxfZ2V0CglpbnQgMQoJPT0KCWJ6ICppZjIyX2Vsc2UKCgkvLyAqaWYyMl9jb25zZXF1ZW50CgkvLyBjb250cmFjdHMvc3Rha2luZ1Bvb2wuYWxnby50czo1MjkKCS8vIHRva2VuUGF5b3V0UmF0aW8gPSBzZW5kTWV0aG9kQ2FsbDx0eXBlb2YgVmFsaWRhdG9yUmVnaXN0cnkucHJvdG90eXBlLnNldFRva2VuUGF5b3V0UmF0aW8+KHsKCS8vICAgICAgICAgICAgICAgICAgICAgYXBwbGljYXRpb25JRDogQXBwSUQuZnJvbVVpbnQ2NCh0aGlzLmNyZWF0aW5nVmFsaWRhdG9yQ29udHJhY3RBcHBJZC52YWx1ZSksCgkvLyAgICAgICAgICAgICAgICAgICAgIG1ldGhvZEFyZ3M6IFt0aGlzLnZhbGlkYXRvcklkLnZhbHVlXSwKCS8vICAgICAgICAgICAgICAgICB9KQoJaXR4bl9iZWdpbgoJaW50IGFwcGwKCWl0eG5fZmllbGQgVHlwZUVudW0KCW1ldGhvZCAic2V0VG9rZW5QYXlvdXRSYXRpbyh1aW50NjQpKHVpbnQ2NFsyNF0sdWludDY0KSIKCWl0eG5fZmllbGQgQXBwbGljYXRpb25BcmdzCgoJLy8gY29udHJhY3RzL3N0YWtpbmdQb29sLmFsZ28udHM6NTMwCgkvLyBhcHBsaWNhdGlvbklEOiBBcHBJRC5mcm9tVWludDY0KHRoaXMuY3JlYXRpbmdWYWxpZGF0b3JDb250cmFjdEFwcElkLnZhbHVlKQoJYnl0ZSAweDYzNzI2NTYxNzQ2ZjcyNDE3MDcwIC8vICJjcmVhdG9yQXBwIgoJYXBwX2dsb2JhbF9nZXQKCWl0eG5fZmllbGQgQXBwbGljYXRpb25JRAoKCS8vIGNvbnRyYWN0cy9zdGFraW5nUG9vbC5hbGdvLnRzOjUzMQoJLy8gbWV0aG9kQXJnczogW3RoaXMudmFsaWRhdG9ySWQudmFsdWVdCglieXRlIDB4NzY2MTZjNjk2NDYxNzQ2ZjcyNDk2NCAvLyAidmFsaWRhdG9ySWQiCglhcHBfZ2xvYmFsX2dldAoJaXRvYgoJaXR4bl9maWVsZCBBcHBsaWNhdGlvbkFyZ3MKCgkvLyBGZWUgZmllbGQgbm90IHNldCwgZGVmYXVsdGluZyB0byAwCglpbnQgMAoJaXR4bl9maWVsZCBGZWUKCgkvLyBTdWJtaXQgaW5uZXIgdHJhbnNhY3Rpb24KCWl0eG5fc3VibWl0CglpdHhuIE51bUxvZ3MKCWludCAxCgktCglpdHhuYXMgTG9ncwoJZXh0cmFjdCA0IDAKCWZyYW1lX2J1cnkgNyAvLyB0b2tlblBheW91dFJhdGlvOiBQb29sVG9rZW5QYXlvdXRSYXRpbwoJYiAqaWYyMl9lbmQKCippZjIyX2Vsc2U6CgkvLyBjb250cmFjdHMvc3Rha2luZ1Bvb2wuYWxnby50czo1MzUKCS8vIHRva2VuUGF5b3V0UmF0aW8gPSBzZW5kTWV0aG9kQ2FsbDx0eXBlb2YgU3Rha2luZ1Bvb2wucHJvdG90eXBlLnByb3hpZWRTZXRUb2tlblBheW91dFJhdGlvPih7CgkvLyAgICAgICAgICAgICAgICAgICAgIGFwcGxpY2F0aW9uSUQ6IEFwcElELmZyb21VaW50NjQocG9vbE9uZUFwcElEKSwKCS8vICAgICAgICAgICAgICAgICAgICAgbWV0aG9kQXJnczogW3sgaWQ6IHRoaXMudmFsaWRhdG9ySWQudmFsdWUsIHBvb2xJZDogdGhpcy5wb29sSWQudmFsdWUsIHBvb2xBcHBJZDogdGhpcy5hcHAuaWQgfV0sCgkvLyAgICAgICAgICAgICAgICAgfSkKCWl0eG5fYmVnaW4KCWludCBhcHBsCglpdHhuX2ZpZWxkIFR5cGVFbnVtCgltZXRob2QgInByb3hpZWRTZXRUb2tlblBheW91dFJhdGlvKCh1aW50NjQsdWludDY0LHVpbnQ2NCkpKHVpbnQ2NFsyNF0sdWludDY0KSIKCWl0eG5fZmllbGQgQXBwbGljYXRpb25BcmdzCgoJLy8gY29udHJhY3RzL3N0YWtpbmdQb29sLmFsZ28udHM6NTM2CgkvLyBhcHBsaWNhdGlvbklEOiBBcHBJRC5mcm9tVWludDY0KHBvb2xPbmVBcHBJRCkKCWZyYW1lX2RpZyA1IC8vIHBvb2xPbmVBcHBJRDogdWludDY0CglpdHhuX2ZpZWxkIEFwcGxpY2F0aW9uSUQKCgkvLyBjb250cmFjdHMvc3Rha2luZ1Bvb2wuYWxnby50czo1MzcKCS8vIG1ldGhvZEFyZ3M6IFt7IGlkOiB0aGlzLnZhbGlkYXRvcklkLnZhbHVlLCBwb29sSWQ6IHRoaXMucG9vbElkLnZhbHVlLCBwb29sQXBwSWQ6IHRoaXMuYXBwLmlkIH1dCglieXRlIDB4NzY2MTZjNjk2NDYxNzQ2ZjcyNDk2NCAvLyAidmFsaWRhdG9ySWQiCglhcHBfZ2xvYmFsX2dldAoJaXRvYgoJYnl0ZSAweDcwNmY2ZjZjNDk2NCAvLyAicG9vbElkIgoJYXBwX2dsb2JhbF9nZXQKCWl0b2IKCWNvbmNhdAoJdHhuYSBBcHBsaWNhdGlvbnMgMAoJaXRvYgoJY29uY2F0CglpdHhuX2ZpZWxkIEFwcGxpY2F0aW9uQXJncwoKCS8vIEZlZSBmaWVsZCBub3Qgc2V0LCBkZWZhdWx0aW5nIHRvIDAKCWludCAwCglpdHhuX2ZpZWxkIEZlZQoKCS8vIFN1Ym1pdCBpbm5lciB0cmFuc2FjdGlvbgoJaXR4bl9zdWJtaXQKCWl0eG4gTnVtTG9ncwoJaW50IDEKCS0KCWl0eG5hcyBMb2dzCglleHRyYWN0IDQgMAoJZnJhbWVfYnVyeSA3IC8vIHRva2VuUGF5b3V0UmF0aW86IFBvb2xUb2tlblBheW91dFJhdGlvCgoqaWYyMl9lbmQ6CgoqaWYyMF9lbmQ6CgkvLyBjb250cmFjdHMvc3Rha2luZ1Bvb2wuYWxnby50czo1NDQKCS8vIHZhbGlkYXRvclN0YXRlID0gc2VuZE1ldGhvZENhbGw8dHlwZW9mIFZhbGlkYXRvclJlZ2lzdHJ5LnByb3RvdHlwZS5nZXRWYWxpZGF0b3JTdGF0ZT4oewoJLy8gICAgICAgICAgICAgYXBwbGljYXRpb25JRDogQXBwSUQuZnJvbVVpbnQ2NCh0aGlzLmNyZWF0aW5nVmFsaWRhdG9yQ29udHJhY3RBcHBJZC52YWx1ZSksCgkvLyAgICAgICAgICAgICBtZXRob2RBcmdzOiBbdGhpcy52YWxpZGF0b3JJZC52YWx1ZV0sCgkvLyAgICAgICAgIH0pCglpdHhuX2JlZ2luCglpbnQgYXBwbAoJaXR4bl9maWVsZCBUeXBlRW51bQoJbWV0aG9kICJnZXRWYWxpZGF0b3JTdGF0ZSh1aW50NjQpKHVpbnQxNix1aW50NjQsdWludDY0LHVpbnQ2NCkiCglpdHhuX2ZpZWxkIEFwcGxpY2F0aW9uQXJncwoKCS8vIGNvbnRyYWN0cy9zdGFraW5nUG9vbC5hbGdvLnRzOjU0NQoJLy8gYXBwbGljYXRpb25JRDogQXBwSUQuZnJvbVVpbnQ2NCh0aGlzLmNyZWF0aW5nVmFsaWRhdG9yQ29udHJhY3RBcHBJZC52YWx1ZSkKCWJ5dGUgMHg2MzcyNjU2MTc0NmY3MjQxNzA3MCAvLyAiY3JlYXRvckFwcCIKCWFwcF9nbG9iYWxfZ2V0CglpdHhuX2ZpZWxkIEFwcGxpY2F0aW9uSUQKCgkvLyBjb250cmFjdHMvc3Rha2luZ1Bvb2wuYWxnby50czo1NDYKCS8vIG1ldGhvZEFyZ3M6IFt0aGlzLnZhbGlkYXRvcklkLnZhbHVlXQoJYnl0ZSAweDc2NjE2YzY5NjQ2MTc0NmY3MjQ5NjQgLy8gInZhbGlkYXRvcklkIgoJYXBwX2dsb2JhbF9nZXQKCWl0b2IKCWl0eG5fZmllbGQgQXBwbGljYXRpb25BcmdzCgoJLy8gRmVlIGZpZWxkIG5vdCBzZXQsIGRlZmF1bHRpbmcgdG8gMAoJaW50IDAKCWl0eG5fZmllbGQgRmVlCgoJLy8gU3VibWl0IGlubmVyIHRyYW5zYWN0aW9uCglpdHhuX3N1Ym1pdAoJaXR4biBOdW1Mb2dzCglpbnQgMQoJLQoJaXR4bmFzIExvZ3MKCWV4dHJhY3QgNCAwCglmcmFtZV9idXJ5IDggLy8gdmFsaWRhdG9yU3RhdGU6ICh1aW50MTYsdWludDY0LHVpbnQ2NCx1aW50NjQpCgoJLy8gY29udHJhY3RzL3N0YWtpbmdQb29sLmFsZ28udHM6NTQ4CgkvLyByZXdhcmRUb2tlbkhlbGRCYWNrID0gdmFsaWRhdG9yU3RhdGUucmV3YXJkVG9rZW5IZWxkQmFjawoJZnJhbWVfZGlnIDggLy8gdmFsaWRhdG9yU3RhdGU6ICh1aW50MTYsdWludDY0LHVpbnQ2NCx1aW50NjQpCglleHRyYWN0IDE4IDgKCWJ0b2kKCWZyYW1lX2J1cnkgOSAvLyByZXdhcmRUb2tlbkhlbGRCYWNrOiB1aW50NjQKCgkvLyBjb250cmFjdHMvc3Rha2luZ1Bvb2wuYWxnby50czo1NTQKCS8vIGFsZ29SZXdhcmRBdmFpbCA9IHRoaXMuYXBwLmFkZHJlc3MuYmFsYW5jZSAtIHRoaXMudG90YWxBbGdvU3Rha2VkLnZhbHVlIC0gdGhpcy5hcHAuYWRkcmVzcy5taW5CYWxhbmNlCglnbG9iYWwgQ3VycmVudEFwcGxpY2F0aW9uQWRkcmVzcwoJYWNjdF9wYXJhbXNfZ2V0IEFjY3RCYWxhbmNlCglwb3AKCWJ5dGUgMHg3Mzc0NjE2YjY1NjQgLy8gInN0YWtlZCIKCWFwcF9nbG9iYWxfZ2V0CgktCglnbG9iYWwgQ3VycmVudEFwcGxpY2F0aW9uQWRkcmVzcwoJYWNjdF9wYXJhbXNfZ2V0IEFjY3RNaW5CYWxhbmNlCglwb3AKCS0KCWZyYW1lX2J1cnkgMTAgLy8gYWxnb1Jld2FyZEF2YWlsOiB1aW50NjQKCgkvLyBjb250cmFjdHMvc3Rha2luZ1Bvb2wuYWxnby50czo1NTUKCS8vIGlzUG9vbFNhdHVyYXRlZCA9IGZhbHNlCglpbnQgMAoJZnJhbWVfYnVyeSAxMSAvLyBpc1Bvb2xTYXR1cmF0ZWQ6IGJvb2wKCgkvLyBjb250cmFjdHMvc3Rha2luZ1Bvb2wuYWxnby50czo1NTYKCS8vIGFsZ29TYXR1cmF0aW9uQW10ID0gdGhpcy5hbGdvU2F0dXJhdGlvbkxldmVsKCkKCWNhbGxzdWIgYWxnb1NhdHVyYXRpb25MZXZlbAoJZnJhbWVfYnVyeSAxMiAvLyBhbGdvU2F0dXJhdGlvbkFtdDogdWludDY0CgoJLy8gKmlmMjNfY29uZGl0aW9uCgkvLyBjb250cmFjdHMvc3Rha2luZ1Bvb2wuYWxnby50czo1NjQKCS8vIHZhbGlkYXRvclN0YXRlLnRvdGFsQWxnb1N0YWtlZCA+IGFsZ29TYXR1cmF0aW9uQW10CglmcmFtZV9kaWcgOCAvLyB2YWxpZGF0b3JTdGF0ZTogKHVpbnQxNix1aW50NjQsdWludDY0LHVpbnQ2NCkKCWV4dHJhY3QgMTAgOAoJYnRvaQoJZnJhbWVfZGlnIDEyIC8vIGFsZ29TYXR1cmF0aW9uQW10OiB1aW50NjQKCT4KCWJ6ICppZjIzX2VuZAoKCS8vICppZjIzX2NvbnNlcXVlbnQKCS8vIGNvbnRyYWN0cy9zdGFraW5nUG9vbC5hbGdvLnRzOjU2NQoJLy8gbG9nKCd2YWxpZGF0b3IgaW4gc2F0dXJhdGVkIHN0YXRlJykKCWJ5dGUgMHg3NjYxNmM2OTY0NjE3NDZmNzIyMDY5NmUyMDczNjE3NDc1NzI2MTc0NjU2NDIwNzM3NDYxNzQ2NSAvLyAidmFsaWRhdG9yIGluIHNhdHVyYXRlZCBzdGF0ZSIKCWxvZwoKCS8vIGNvbnRyYWN0cy9zdGFraW5nUG9vbC5hbGdvLnRzOjU2NgoJLy8gaXNQb29sU2F0dXJhdGVkID0gdHJ1ZQoJaW50IDEKCWZyYW1lX2J1cnkgMTEgLy8gaXNQb29sU2F0dXJhdGVkOiBib29sCgoqaWYyM19lbmQ6CgkvLyBjb250cmFjdHMvc3Rha2luZ1Bvb2wuYWxnby50czo1NzIKCS8vIHRva2VuUmV3YXJkQXZhaWwgPSAwCglpbnQgMAoJZnJhbWVfYnVyeSAxMyAvLyB0b2tlblJld2FyZEF2YWlsOiB1aW50NjQKCgkvLyBjb250cmFjdHMvc3Rha2luZ1Bvb2wuYWxnby50czo1NzMKCS8vIHRva2VuUmV3YXJkUGFpZE91dCA9IDAKCWludCAwCglmcmFtZV9idXJ5IDE0IC8vIHRva2VuUmV3YXJkUGFpZE91dDogdWludDY0CgoJLy8gKmlmMjRfY29uZGl0aW9uCgkvLyBjb250cmFjdHMvc3Rha2luZ1Bvb2wuYWxnby50czo1NzQKCS8vIGlzVG9rZW5FbGlnaWJsZQoJZnJhbWVfZGlnIDQgLy8gaXNUb2tlbkVsaWdpYmxlOiBib29sCglieiAqaWYyNF9lbmQKCgkvLyAqaWYyNF9jb25zZXF1ZW50CgkvLyBjb250cmFjdHMvc3Rha2luZ1Bvb2wuYWxnby50czo1NzUKCS8vIHRva2VuUmV3YXJkQmFsID0KCS8vICAgICAgICAgICAgICAgICBwb29sT25lQWRkcmVzcy5hc3NldEJhbGFuY2UoQXNzZXRJRC5mcm9tVWludDY0KHZhbGlkYXRvckNvbmZpZy5yZXdhcmRUb2tlbklkKSkgLSByZXdhcmRUb2tlbkhlbGRCYWNrCglmcmFtZV9kaWcgNiAvLyBwb29sT25lQWRkcmVzczogYWRkcmVzcwoJZnJhbWVfZGlnIDAgLy8gdmFsaWRhdG9yQ29uZmlnOiAodWludDY0LGFkZHJlc3MsYWRkcmVzcyx1aW50NjQsdWludDgsYnl0ZVszMl0sdWludDY0LHVpbnQ2NCx1aW50NjQsdWludDE2LHVpbnQzMixhZGRyZXNzLHVpbnQ2NCx1aW50NjQsdWludDgsdWludDY0LHVpbnQ2NCkKCWV4dHJhY3QgMTIxIDgKCWJ0b2kKCWFzc2V0X2hvbGRpbmdfZ2V0IEFzc2V0QmFsYW5jZQoJcG9wCglmcmFtZV9kaWcgOSAvLyByZXdhcmRUb2tlbkhlbGRCYWNrOiB1aW50NjQKCS0KCWZyYW1lX2J1cnkgMTUgLy8gdG9rZW5SZXdhcmRCYWw6IHVpbnQ2NAoKCS8vICppZjI1X2NvbmRpdGlvbgoJLy8gY29udHJhY3RzL3N0YWtpbmdQb29sLmFsZ28udHM6NTgwCgkvLyB0b2tlblJld2FyZEJhbCA+PSB2YWxpZGF0b3JDb25maWcucmV3YXJkUGVyUGF5b3V0CglmcmFtZV9kaWcgMTUgLy8gdG9rZW5SZXdhcmRCYWw6IHVpbnQ2NAoJZnJhbWVfZGlnIDAgLy8gdmFsaWRhdG9yQ29uZmlnOiAodWludDY0LGFkZHJlc3MsYWRkcmVzcyx1aW50NjQsdWludDgsYnl0ZVszMl0sdWludDY0LHVpbnQ2NCx1aW50NjQsdWludDE2LHVpbnQzMixhZGRyZXNzLHVpbnQ2NCx1aW50NjQsdWludDgsdWludDY0LHVpbnQ2NCkKCWV4dHJhY3QgMTI5IDgKCWJ0b2kKCT49CglieiAqaWYyNV9lbmQKCgkvLyAqaWYyNV9jb25zZXF1ZW50CgkvLyBjb250cmFjdHMvc3Rha2luZ1Bvb2wuYWxnby50czo1ODQKCS8vIG91clBvb2xQY3RPZldob2xlID0gdG9rZW5QYXlvdXRSYXRpby5wb29sUGN0T2ZXaG9sZVt0aGlzLnBvb2xJZC52YWx1ZSAtIDFdCglmcmFtZV9kaWcgNyAvLyB0b2tlblBheW91dFJhdGlvOiBQb29sVG9rZW5QYXlvdXRSYXRpbwoJaW50IDAKCWJ5dGUgMHg3MDZmNmY2YzQ5NjQgLy8gInBvb2xJZCIKCWFwcF9nbG9iYWxfZ2V0CglpbnQgMQoJLQoJaW50IDgKCSogLy8gYWNjICogdHlwZUxlbmd0aAoJKwoJaW50IDgKCWV4dHJhY3QzCglidG9pCglmcmFtZV9idXJ5IDE2IC8vIG91clBvb2xQY3RPZldob2xlOiB1aW50NjQKCgkvLyBjb250cmFjdHMvc3Rha2luZ1Bvb2wuYWxnby50czo1ODcKCS8vIHRva2VuUmV3YXJkQXZhaWwgPSB3aWRlUmF0aW8oW3ZhbGlkYXRvckNvbmZpZy5yZXdhcmRQZXJQYXlvdXQsIG91clBvb2xQY3RPZldob2xlXSwgWzFfMDAwXzAwMF0pCglmcmFtZV9kaWcgMCAvLyB2YWxpZGF0b3JDb25maWc6ICh1aW50NjQsYWRkcmVzcyxhZGRyZXNzLHVpbnQ2NCx1aW50OCxieXRlWzMyXSx1aW50NjQsdWludDY0LHVpbnQ2NCx1aW50MTYsdWludDMyLGFkZHJlc3MsdWludDY0LHVpbnQ2NCx1aW50OCx1aW50NjQsdWludDY0KQoJZXh0cmFjdCAxMjkgOAoJYnRvaQoJZnJhbWVfZGlnIDE2IC8vIG91clBvb2xQY3RPZldob2xlOiB1aW50NjQKCW11bHcKCWludCAwCglpbnQgMV8wMDBfMDAwCglkaXZtb2R3Cglwb3AKCXBvcAoJc3dhcAoJIQoJYXNzZXJ0CglmcmFtZV9idXJ5IDEzIC8vIHRva2VuUmV3YXJkQXZhaWw6IHVpbnQ2NAoKCS8vIGNvbnRyYWN0cy9zdGFraW5nUG9vbC5hbGdvLnRzOjU5MQoJLy8gbG9nKGNvbmNhdCgndG9rZW4gcmV3YXJkIGF2YWlsOiAnLCB0b2tlblJld2FyZEF2YWlsLnRvU3RyaW5nKCkpKQoJYnl0ZSAweDc0NmY2YjY1NmUyMDcyNjU3NzYxNzI2NDIwNjE3NjYxNjk2YzNhMjAgLy8gInRva2VuIHJld2FyZCBhdmFpbDogIgoJZnJhbWVfZGlnIDEzIC8vIHRva2VuUmV3YXJkQXZhaWw6IHVpbnQ2NAoJY2FsbHN1YiAqaXRvYQoJY29uY2F0Cglsb2cKCippZjI1X2VuZDoKCippZjI0X2VuZDoKCS8vICppZjI2X2NvbmRpdGlvbgoJLy8gY29udHJhY3RzL3N0YWtpbmdQb29sLmFsZ28udHM6NTk1CgkvLyB0b2tlblJld2FyZEF2YWlsID09PSAwCglmcmFtZV9kaWcgMTMgLy8gdG9rZW5SZXdhcmRBdmFpbDogdWludDY0CglpbnQgMAoJPT0KCWJ6ICppZjI2X2VuZAoKCS8vICppZjI2X2NvbnNlcXVlbnQKCS8vIGNvbnRyYWN0cy9zdGFraW5nUG9vbC5hbGdvLnRzOjU5OAoJLy8gYXNzZXJ0KGFsZ29SZXdhcmRBdmFpbCA+IDFfMDAwXzAwMCwgJ1Jld2FyZCBuZWVkcyB0byBiZSBhdCBsZWFzdCAxIEFMR08nKQoJZnJhbWVfZGlnIDEwIC8vIGFsZ29SZXdhcmRBdmFpbDogdWludDY0CglpbnQgMV8wMDBfMDAwCgk+CgoJLy8gUmV3YXJkIG5lZWRzIHRvIGJlIGF0IGxlYXN0IDEgQUxHTwoJYXNzZXJ0CgoqaWYyNl9lbmQ6CgkvLyBjb250cmFjdHMvc3Rha2luZ1Bvb2wuYWxnby50czo2MDAKCS8vIGxvZyhjb25jYXQoJ2FsZ28gcmV3YXJkIGF2YWlsOiAnLCBhbGdvUmV3YXJkQXZhaWwudG9TdHJpbmcoKSkpCglieXRlIDB4NjE2YzY3NmYyMDcyNjU3NzYxNzI2NDIwNjE3NjYxNjk2YzNhMjAgLy8gImFsZ28gcmV3YXJkIGF2YWlsOiAiCglmcmFtZV9kaWcgMTAgLy8gYWxnb1Jld2FyZEF2YWlsOiB1aW50NjQKCWNhbGxzdWIgKml0b2EKCWNvbmNhdAoJbG9nCgoJLy8gKmlmMjdfY29uZGl0aW9uCgkvLyBjb250cmFjdHMvc3Rha2luZ1Bvb2wuYWxnby50czo2MDMKCS8vIGlzUG9vbFNhdHVyYXRlZAoJZnJhbWVfZGlnIDExIC8vIGlzUG9vbFNhdHVyYXRlZDogYm9vbAoJYnogKmlmMjdfZWxzZWlmMV9jb25kaXRpb24KCgkvLyAqaWYyN19jb25zZXF1ZW50CgkvLyBjb250cmFjdHMvc3Rha2luZ1Bvb2wuYWxnby50czo2MDYKCS8vIGRpbWluaXNoZWRSZXdhcmQgPSB3aWRlUmF0aW8oW2FsZ29SZXdhcmRBdmFpbCwgYWxnb1NhdHVyYXRpb25BbXRdLCBbdmFsaWRhdG9yU3RhdGUudG90YWxBbGdvU3Rha2VkXSkKCWZyYW1lX2RpZyAxMCAvLyBhbGdvUmV3YXJkQXZhaWw6IHVpbnQ2NAoJZnJhbWVfZGlnIDEyIC8vIGFsZ29TYXR1cmF0aW9uQW10OiB1aW50NjQKCW11bHcKCWludCAwCglmcmFtZV9kaWcgOCAvLyB2YWxpZGF0b3JTdGF0ZTogKHVpbnQxNix1aW50NjQsdWludDY0LHVpbnQ2NCkKCWV4dHJhY3QgMTAgOAoJYnRvaQoJZGl2bW9kdwoJcG9wCglwb3AKCXN3YXAKCSEKCWFzc2VydAoJZnJhbWVfYnVyeSAxNyAvLyBkaW1pbmlzaGVkUmV3YXJkOiB1aW50NjQKCgkvLyBjb250cmFjdHMvc3Rha2luZ1Bvb2wuYWxnby50czo2MDgKCS8vIGV4Y2Vzc1RvRmVlU2luayA9IGFsZ29SZXdhcmRBdmFpbCAtIGRpbWluaXNoZWRSZXdhcmQKCWZyYW1lX2RpZyAxMCAvLyBhbGdvUmV3YXJkQXZhaWw6IHVpbnQ2NAoJZnJhbWVfZGlnIDE3IC8vIGRpbWluaXNoZWRSZXdhcmQ6IHVpbnQ2NAoJLQoJZnJhbWVfYnVyeSAxOCAvLyBleGNlc3NUb0ZlZVNpbms6IHVpbnQ2NAoKCS8vIGNvbnRyYWN0cy9zdGFraW5nUG9vbC5hbGdvLnRzOjYwOQoJLy8gaW5jcmVhc2VPcGNvZGVCdWRnZXQoKQoJaXR4bl9iZWdpbgoJaW50IGFwcGwKCWl0eG5fZmllbGQgVHlwZUVudW0KCWludCAwCglpdHhuX2ZpZWxkIEZlZQoJYnl0ZSBiNjQgQ29FQiAvLyAjcHJhZ21hIHZlcnNpb24gMTA7IGludCAxCglkdXAKCWl0eG5fZmllbGQgQXBwcm92YWxQcm9ncmFtCglpdHhuX2ZpZWxkIENsZWFyU3RhdGVQcm9ncmFtCglpbnQgRGVsZXRlQXBwbGljYXRpb24KCWl0eG5fZmllbGQgT25Db21wbGV0aW9uCglpdHhuX3N1Ym1pdAoKCS8vIGNvbnRyYWN0cy9zdGFraW5nUG9vbC5hbGdvLnRzOjYxMAoJLy8gbG9nKGNvbmNhdCgnZGltIHJ3ZDogJywgZGltaW5pc2hlZFJld2FyZC50b1N0cmluZygpKSkKCWJ5dGUgMHg2NDY5NmQyMDcyNzc2NDNhMjAgLy8gImRpbSByd2Q6ICIKCWZyYW1lX2RpZyAxNyAvLyBkaW1pbmlzaGVkUmV3YXJkOiB1aW50NjQKCWNhbGxzdWIgKml0b2EKCWNvbmNhdAoJbG9nCgoJLy8gY29udHJhY3RzL3N0YWtpbmdQb29sLmFsZ28udHM6NjExCgkvLyBsb2coY29uY2F0KCd0byBzaW5rOiAnLCBleGNlc3NUb0ZlZVNpbmsudG9TdHJpbmcoKSkpCglieXRlIDB4NzQ2ZjIwNzM2OTZlNmIzYTIwIC8vICJ0byBzaW5rOiAiCglmcmFtZV9kaWcgMTggLy8gZXhjZXNzVG9GZWVTaW5rOiB1aW50NjQKCWNhbGxzdWIgKml0b2EKCWNvbmNhdAoJbG9nCgoJLy8gY29udHJhY3RzL3N0YWtpbmdQb29sLmFsZ28udHM6NjEyCgkvLyBzZW5kUGF5bWVudCh7CgkvLyAgICAgICAgICAgICAgICAgYW1vdW50OiBleGNlc3NUb0ZlZVNpbmssCgkvLyAgICAgICAgICAgICAgICAgcmVjZWl2ZXI6IHRoaXMuZ2V0RmVlU2luaygpLAoJLy8gICAgICAgICAgICAgICAgIG5vdGU6ICdwb29sIHNhdHVyYXRlZCwgcG9ydGlvbiBzZW50IGJhY2sgdG8gZmVlIHNpbmsnLAoJLy8gICAgICAgICAgICAgfSkKCWl0eG5fYmVnaW4KCWludCBwYXkKCWl0eG5fZmllbGQgVHlwZUVudW0KCgkvLyBjb250cmFjdHMvc3Rha2luZ1Bvb2wuYWxnby50czo2MTMKCS8vIGFtb3VudDogZXhjZXNzVG9GZWVTaW5rCglmcmFtZV9kaWcgMTggLy8gZXhjZXNzVG9GZWVTaW5rOiB1aW50NjQKCWl0eG5fZmllbGQgQW1vdW50CgoJLy8gY29udHJhY3RzL3N0YWtpbmdQb29sLmFsZ28udHM6NjE0CgkvLyByZWNlaXZlcjogdGhpcy5nZXRGZWVTaW5rKCkKCWNhbGxzdWIgZ2V0RmVlU2luawoJaXR4bl9maWVsZCBSZWNlaXZlcgoKCS8vIGNvbnRyYWN0cy9zdGFraW5nUG9vbC5hbGdvLnRzOjYxNQoJLy8gbm90ZTogJ3Bvb2wgc2F0dXJhdGVkLCBwb3J0aW9uIHNlbnQgYmFjayB0byBmZWUgc2luaycKCWJ5dGUgMHg3MDZmNmY2YzIwNzM2MTc0NzU3MjYxNzQ2NTY0MmMyMDcwNmY3Mjc0Njk2ZjZlMjA3MzY1NmU3NDIwNjI2MTYzNmIyMDc0NmYyMDY2NjU2NTIwNzM2OTZlNmIgLy8gInBvb2wgc2F0dXJhdGVkLCBwb3J0aW9uIHNlbnQgYmFjayB0byBmZWUgc2luayIKCWl0eG5fZmllbGQgTm90ZQoKCS8vIEZlZSBmaWVsZCBub3Qgc2V0LCBkZWZhdWx0aW5nIHRvIDAKCWludCAwCglpdHhuX2ZpZWxkIEZlZQoKCS8vIFN1Ym1pdCBpbm5lciB0cmFuc2FjdGlvbgoJaXR4bl9zdWJtaXQKCgkvLyBjb250cmFjdHMvc3Rha2luZ1Bvb2wuYWxnby50czo2MTgKCS8vIGFsZ29SZXdhcmRBdmFpbCA9IGRpbWluaXNoZWRSZXdhcmQKCWZyYW1lX2RpZyAxNyAvLyBkaW1pbmlzaGVkUmV3YXJkOiB1aW50NjQKCWZyYW1lX2J1cnkgMTAgLy8gYWxnb1Jld2FyZEF2YWlsOiB1aW50NjQKCWIgKmlmMjdfZW5kCgoqaWYyN19lbHNlaWYxX2NvbmRpdGlvbjoKCS8vIGNvbnRyYWN0cy9zdGFraW5nUG9vbC5hbGdvLnRzOjYxOQoJLy8gdmFsaWRhdG9yQ29uZmlnLnBlcmNlbnRUb1ZhbGlkYXRvciAhPT0gMAoJZnJhbWVfZGlnIDAgLy8gdmFsaWRhdG9yQ29uZmlnOiAodWludDY0LGFkZHJlc3MsYWRkcmVzcyx1aW50NjQsdWludDgsYnl0ZVszMl0sdWludDY0LHVpbnQ2NCx1aW50NjQsdWludDE2LHVpbnQzMixhZGRyZXNzLHVpbnQ2NCx1aW50NjQsdWludDgsdWludDY0LHVpbnQ2NCkKCWV4dHJhY3QgMTM5IDQKCWJ0b2kKCWludCAwCgkhPQoJYnogKmlmMjdfZW5kCgoJLy8gKmlmMjdfZWxzZWlmMV9jb25zZXF1ZW50CgkvLyBjb250cmFjdHMvc3Rha2luZ1Bvb2wuYWxnby50czo2MjIKCS8vIHZhbGlkYXRvclBheSA9IHdpZGVSYXRpbygKCS8vICAgICAgICAgICAgICAgICBbYWxnb1Jld2FyZEF2YWlsLCB2YWxpZGF0b3JDb25maWcucGVyY2VudFRvVmFsaWRhdG9yIGFzIHVpbnQ2NF0sCgkvLyAgICAgICAgICAgICAgICAgWzFfMDAwXzAwMF0KCS8vICAgICAgICAgICAgICkKCWZyYW1lX2RpZyAxMCAvLyBhbGdvUmV3YXJkQXZhaWw6IHVpbnQ2NAoJZnJhbWVfZGlnIDAgLy8gdmFsaWRhdG9yQ29uZmlnOiAodWludDY0LGFkZHJlc3MsYWRkcmVzcyx1aW50NjQsdWludDgsYnl0ZVszMl0sdWludDY0LHVpbnQ2NCx1aW50NjQsdWludDE2LHVpbnQzMixhZGRyZXNzLHVpbnQ2NCx1aW50NjQsdWludDgsdWludDY0LHVpbnQ2NCkKCWV4dHJhY3QgMTM5IDQKCWJ0b2kKCW11bHcKCWludCAwCglpbnQgMV8wMDBfMDAwCglkaXZtb2R3Cglwb3AKCXBvcAoJc3dhcAoJIQoJYXNzZXJ0CglmcmFtZV9idXJ5IDE5IC8vIHZhbGlkYXRvclBheTogdWludDY0CgoJLy8gY29udHJhY3RzL3N0YWtpbmdQb29sLmFsZ28udHM6NjI4CgkvLyBhbGdvUmV3YXJkQXZhaWwgLT0gdmFsaWRhdG9yUGF5CglmcmFtZV9kaWcgMTAgLy8gYWxnb1Jld2FyZEF2YWlsOiB1aW50NjQKCWZyYW1lX2RpZyAxOSAvLyB2YWxpZGF0b3JQYXk6IHVpbnQ2NAoJLQoJZnJhbWVfYnVyeSAxMCAvLyBhbGdvUmV3YXJkQXZhaWw6IHVpbnQ2NAoKCS8vICppZjI4X2NvbmRpdGlvbgoJLy8gY29udHJhY3RzL3N0YWtpbmdQb29sLmFsZ28udHM6NjMyCgkvLyB2YWxpZGF0b3JQYXkgPiAwCglmcmFtZV9kaWcgMTkgLy8gdmFsaWRhdG9yUGF5OiB1aW50NjQKCWludCAwCgk+CglieiAqaWYyOF9lbmQKCgkvLyAqaWYyOF9jb25zZXF1ZW50CgkvLyBjb250cmFjdHMvc3Rha2luZ1Bvb2wuYWxnby50czo2MzMKCS8vIGxvZyhjb25jYXQoJ3BheWluZyB2YWxpZGF0b3I6ICVpJywgaXRvYih2YWxpZGF0b3JQYXkpKSkKCWJ5dGUgMHg3MDYxNzk2OTZlNjcyMDc2NjE2YzY5NjQ2MTc0NmY3MjNhMjAyNTY5IC8vICJwYXlpbmcgdmFsaWRhdG9yOiAlaSIKCWZyYW1lX2RpZyAxOSAvLyB2YWxpZGF0b3JQYXk6IHVpbnQ2NAoJaXRvYgoJY29uY2F0Cglsb2cKCgkvLyBjb250cmFjdHMvc3Rha2luZ1Bvb2wuYWxnby50czo2MzQKCS8vIHNlbmRQYXltZW50KHsKCS8vICAgICAgICAgICAgICAgICAgICAgYW1vdW50OiB2YWxpZGF0b3JQYXksCgkvLyAgICAgICAgICAgICAgICAgICAgIHJlY2VpdmVyOiB2YWxpZGF0b3JDb25maWcudmFsaWRhdG9yQ29tbWlzc2lvbkFkZHJlc3MsCgkvLyAgICAgICAgICAgICAgICAgICAgIG5vdGU6ICd2YWxpZGF0b3IgcmV3YXJkJywKCS8vICAgICAgICAgICAgICAgICB9KQoJaXR4bl9iZWdpbgoJaW50IHBheQoJaXR4bl9maWVsZCBUeXBlRW51bQoKCS8vIGNvbnRyYWN0cy9zdGFraW5nUG9vbC5hbGdvLnRzOjYzNQoJLy8gYW1vdW50OiB2YWxpZGF0b3JQYXkKCWZyYW1lX2RpZyAxOSAvLyB2YWxpZGF0b3JQYXk6IHVpbnQ2NAoJaXR4bl9maWVsZCBBbW91bnQKCgkvLyBjb250cmFjdHMvc3Rha2luZ1Bvb2wuYWxnby50czo2MzYKCS8vIHJlY2VpdmVyOiB2YWxpZGF0b3JDb25maWcudmFsaWRhdG9yQ29tbWlzc2lvbkFkZHJlc3MKCWZyYW1lX2RpZyAwIC8vIHZhbGlkYXRvckNvbmZpZzogKHVpbnQ2NCxhZGRyZXNzLGFkZHJlc3MsdWludDY0LHVpbnQ4LGJ5dGVbMzJdLHVpbnQ2NCx1aW50NjQsdWludDY0LHVpbnQxNix1aW50MzIsYWRkcmVzcyx1aW50NjQsdWludDY0LHVpbnQ4LHVpbnQ2NCx1aW50NjQpCglleHRyYWN0IDE0MyAzMgoJaXR4bl9maWVsZCBSZWNlaXZlcgoKCS8vIGNvbnRyYWN0cy9zdGFraW5nUG9vbC5hbGdvLnRzOjYzNwoJLy8gbm90ZTogJ3ZhbGlkYXRvciByZXdhcmQnCglieXRlIDB4NzY2MTZjNjk2NDYxNzQ2ZjcyMjA3MjY1Nzc2MTcyNjQgLy8gInZhbGlkYXRvciByZXdhcmQiCglpdHhuX2ZpZWxkIE5vdGUKCgkvLyBGZWUgZmllbGQgbm90IHNldCwgZGVmYXVsdGluZyB0byAwCglpbnQgMAoJaXR4bl9maWVsZCBGZWUKCgkvLyBTdWJtaXQgaW5uZXIgdHJhbnNhY3Rpb24KCWl0eG5fc3VibWl0CgoJLy8gY29udHJhY3RzL3N0YWtpbmdQb29sLmFsZ28udHM6NjM5CgkvLyBsb2coY29uY2F0KCdyZW1haW5pbmcgcmV3YXJkOiAlaScsIGl0b2IoYWxnb1Jld2FyZEF2YWlsKSkpCglieXRlIDB4NzI2NTZkNjE2OTZlNjk2ZTY3MjA3MjY1Nzc2MTcyNjQzYTIwMjU2OSAvLyAicmVtYWluaW5nIHJld2FyZDogJWkiCglmcmFtZV9kaWcgMTAgLy8gYWxnb1Jld2FyZEF2YWlsOiB1aW50NjQKCWl0b2IKCWNvbmNhdAoJbG9nCgoqaWYyOF9lbmQ6CgoqaWYyN19lbmQ6CgkvLyAqaWYyOV9jb25kaXRpb24KCS8vIGNvbnRyYWN0cy9zdGFraW5nUG9vbC5hbGdvLnRzOjY0MwoJLy8gYWxnb1Jld2FyZEF2YWlsID09PSAwICYmIHRva2VuUmV3YXJkQXZhaWwgPT09IDAKCWZyYW1lX2RpZyAxMCAvLyBhbGdvUmV3YXJkQXZhaWw6IHVpbnQ2NAoJaW50IDAKCT09CglkdXAKCWJ6ICpza2lwX2FuZDMKCWZyYW1lX2RpZyAxMyAvLyB0b2tlblJld2FyZEF2YWlsOiB1aW50NjQKCWludCAwCgk9PQoJJiYKCipza2lwX2FuZDM6CglieiAqaWYyOV9lbmQKCgkvLyAqaWYyOV9jb25zZXF1ZW50CgkvLyBjb250cmFjdHMvc3Rha2luZ1Bvb2wuYWxnby50czo2NDYKCS8vIHJldHVybjsKCXJldHN1YgoKKmlmMjlfZW5kOgoJLy8gY29udHJhY3RzL3N0YWtpbmdQb29sLmFsZ28udHM6NjU0CgkvLyBpbmNyZWFzZWRTdGFrZSA9IDAKCWludCAwCglmcmFtZV9idXJ5IDIwIC8vIGluY3JlYXNlZFN0YWtlOiB1aW50NjQKCgkvLyBjb250cmFjdHMvc3Rha2luZ1Bvb2wuYWxnby50czo2NzgKCS8vIHBhcnRpYWxTdGFrZXJzVG90YWxTdGFrZTogdWludDY0ID0gMAoJaW50IDAKCWZyYW1lX2J1cnkgMjEgLy8gcGFydGlhbFN0YWtlcnNUb3RhbFN0YWtlOiB1aW50NjQKCgkvLyBjb250cmFjdHMvc3Rha2luZ1Bvb2wuYWxnby50czo2NzkKCS8vIGZvciAobGV0IGkgPSAwOyBpIDwgdGhpcy5zdGFrZXJzLnZhbHVlLmxlbmd0aDsgaSArPSAxKQoJaW50IDAKCWZyYW1lX2J1cnkgMjIgLy8gaTogdWludDY0CgoqZm9yXzQ6CgkvLyBjb250cmFjdHMvc3Rha2luZ1Bvb2wuYWxnby50czo2NzkKCS8vIGkgPCB0aGlzLnN0YWtlcnMudmFsdWUubGVuZ3RoCglmcmFtZV9kaWcgMjIgLy8gaTogdWludDY0CglpbnQgMjAwCgk8CglieiAqZm9yXzRfZW5kCgoJLy8gKmlmMzBfY29uZGl0aW9uCgkvLyBjb250cmFjdHMvc3Rha2luZ1Bvb2wuYWxnby50czo2ODAKCS8vIGdsb2JhbHMub3Bjb2RlQnVkZ2V0IDwgNDAwCglnbG9iYWwgT3Bjb2RlQnVkZ2V0CglpbnQgNDAwCgk8CglieiAqaWYzMF9lbmQKCgkvLyAqaWYzMF9jb25zZXF1ZW50CgkvLyBjb250cmFjdHMvc3Rha2luZ1Bvb2wuYWxnby50czo2ODEKCS8vIGluY3JlYXNlT3Bjb2RlQnVkZ2V0KCkKCWl0eG5fYmVnaW4KCWludCBhcHBsCglpdHhuX2ZpZWxkIFR5cGVFbnVtCglpbnQgMAoJaXR4bl9maWVsZCBGZWUKCWJ5dGUgYjY0IENvRUIgLy8gI3ByYWdtYSB2ZXJzaW9uIDEwOyBpbnQgMQoJZHVwCglpdHhuX2ZpZWxkIEFwcHJvdmFsUHJvZ3JhbQoJaXR4bl9maWVsZCBDbGVhclN0YXRlUHJvZ3JhbQoJaW50IERlbGV0ZUFwcGxpY2F0aW9uCglpdHhuX2ZpZWxkIE9uQ29tcGxldGlvbgoJaXR4bl9zdWJtaXQKCippZjMwX2VuZDoKCS8vIGNvbnRyYWN0cy9zdGFraW5nUG9vbC5hbGdvLnRzOjY4MwoJLy8gY21wU3Rha2VyID0gY2xvbmUodGhpcy5zdGFrZXJzLnZhbHVlW2ldKQoJZnJhbWVfZGlnIDIyIC8vIGk6IHVpbnQ2NAoJaW50IDY0CgkqIC8vIGFjYyAqIHR5cGVMZW5ndGgKCWludCA2NAoJYnl0ZSAweDczNzQ2MTZiNjU3MjczIC8vICJzdGFrZXJzIgoJY292ZXIgMgoJYm94X2V4dHJhY3QKCWZyYW1lX2J1cnkgMjMgLy8gY21wU3Rha2VyOiAoYWRkcmVzcyx1aW50NjQsdWludDY0LHVpbnQ2NCx1aW50NjQpCgoJLy8gKmlmMzFfY29uZGl0aW9uCgkvLyBjb250cmFjdHMvc3Rha2luZ1Bvb2wuYWxnby50czo2ODQKCS8vIGNtcFN0YWtlci5hY2NvdW50ICE9PSBnbG9iYWxzLnplcm9BZGRyZXNzCglmcmFtZV9kaWcgMjMgLy8gY21wU3Rha2VyOiAoYWRkcmVzcyx1aW50NjQsdWludDY0LHVpbnQ2NCx1aW50NjQpCglleHRyYWN0IDAgMzIKCWdsb2JhbCBaZXJvQWRkcmVzcwoJIT0KCWJ6ICppZjMxX2VuZAoKCS8vICppZjMxX2NvbnNlcXVlbnQKCS8vICppZjMyX2NvbmRpdGlvbgoJLy8gY29udHJhY3RzL3N0YWtpbmdQb29sLmFsZ28udHM6Njg1CgkvLyBjbXBTdGFrZXIuZW50cnlUaW1lID4gY3VyVGltZQoJZnJhbWVfZGlnIDIzIC8vIGNtcFN0YWtlcjogKGFkZHJlc3MsdWludDY0LHVpbnQ2NCx1aW50NjQsdWludDY0KQoJZXh0cmFjdCA1NiA4CglidG9pCglmcmFtZV9kaWcgMSAvLyBjdXJUaW1lOiB1aW50NjQKCT4KCWJ6ICppZjMyX2Vsc2UKCgkvLyAqaWYzMl9jb25zZXF1ZW50CgkvLyBjb250cmFjdHMvc3Rha2luZ1Bvb2wuYWxnby50czo2ODgKCS8vIHBhcnRpYWxTdGFrZXJzVG90YWxTdGFrZSArPSBjbXBTdGFrZXIuYmFsYW5jZQoJZnJhbWVfZGlnIDIxIC8vIHBhcnRpYWxTdGFrZXJzVG90YWxTdGFrZTogdWludDY0CglmcmFtZV9kaWcgMjMgLy8gY21wU3Rha2VyOiAoYWRkcmVzcyx1aW50NjQsdWludDY0LHVpbnQ2NCx1aW50NjQpCglleHRyYWN0IDMyIDgKCWJ0b2kKCSsKCWZyYW1lX2J1cnkgMjEgLy8gcGFydGlhbFN0YWtlcnNUb3RhbFN0YWtlOiB1aW50NjQKCWIgKmlmMzJfZW5kCgoqaWYzMl9lbHNlOgoJLy8gY29udHJhY3RzL3N0YWtpbmdQb29sLmFsZ28udHM6NjkyCgkvLyB0aW1lSW5Qb29sID0gY3VyVGltZSAtIGNtcFN0YWtlci5lbnRyeVRpbWUKCWZyYW1lX2RpZyAxIC8vIGN1clRpbWU6IHVpbnQ2NAoJZnJhbWVfZGlnIDIzIC8vIGNtcFN0YWtlcjogKGFkZHJlc3MsdWludDY0LHVpbnQ2NCx1aW50NjQsdWludDY0KQoJZXh0cmFjdCA1NiA4CglidG9pCgktCglmcmFtZV9idXJ5IDI0IC8vIHRpbWVJblBvb2w6IHVpbnQ2NAoKCS8vICppZjMzX2NvbmRpdGlvbgoJLy8gY29udHJhY3RzL3N0YWtpbmdQb29sLmFsZ28udHM6Njk2CgkvLyB0aW1lSW5Qb29sIDwgZXBvY2hJblNlY3MKCWZyYW1lX2RpZyAyNCAvLyB0aW1lSW5Qb29sOiB1aW50NjQKCWZyYW1lX2RpZyAyIC8vIGVwb2NoSW5TZWNzOiB1aW50NjQKCTwKCWJ6ICppZjMzX2VuZAoKCS8vICppZjMzX2NvbnNlcXVlbnQKCS8vIGNvbnRyYWN0cy9zdGFraW5nUG9vbC5hbGdvLnRzOjY5NwoJLy8gcGFydGlhbFN0YWtlcnNUb3RhbFN0YWtlICs9IGNtcFN0YWtlci5iYWxhbmNlCglmcmFtZV9kaWcgMjEgLy8gcGFydGlhbFN0YWtlcnNUb3RhbFN0YWtlOiB1aW50NjQKCWZyYW1lX2RpZyAyMyAvLyBjbXBTdGFrZXI6IChhZGRyZXNzLHVpbnQ2NCx1aW50NjQsdWludDY0LHVpbnQ2NCkKCWV4dHJhY3QgMzIgOAoJYnRvaQoJKwoJZnJhbWVfYnVyeSAyMSAvLyBwYXJ0aWFsU3Rha2Vyc1RvdGFsU3Rha2U6IHVpbnQ2NAoKCS8vIGNvbnRyYWN0cy9zdGFraW5nUG9vbC5hbGdvLnRzOjY5OAoJLy8gdGltZVBlcmNlbnRhZ2UgPSAodGltZUluUG9vbCAqIDEwMDApIC8gZXBvY2hJblNlY3MKCWZyYW1lX2RpZyAyNCAvLyB0aW1lSW5Qb29sOiB1aW50NjQKCWludCAxMDAwCgkqCglmcmFtZV9kaWcgMiAvLyBlcG9jaEluU2VjczogdWludDY0CgkvCglmcmFtZV9idXJ5IDI1IC8vIHRpbWVQZXJjZW50YWdlOiB1aW50NjQKCgkvLyAqaWYzNF9jb25kaXRpb24KCS8vIGNvbnRyYWN0cy9zdGFraW5nUG9vbC5hbGdvLnRzOjcwMQoJLy8gdG9rZW5SZXdhcmRBdmFpbCA+IDAKCWZyYW1lX2RpZyAxMyAvLyB0b2tlblJld2FyZEF2YWlsOiB1aW50NjQKCWludCAwCgk+CglieiAqaWYzNF9lbmQKCgkvLyAqaWYzNF9jb25zZXF1ZW50CgkvLyBjb250cmFjdHMvc3Rha2luZ1Bvb2wuYWxnby50czo3MDMKCS8vIHN0YWtlclRva2VuUmV3YXJkID0gd2lkZVJhdGlvKAoJLy8gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBbY21wU3Rha2VyLmJhbGFuY2UsIHRva2VuUmV3YXJkQXZhaWwsIHRpbWVQZXJjZW50YWdlXSwKCS8vICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgW3RoaXMudG90YWxBbGdvU3Rha2VkLnZhbHVlLCAxMDAwXQoJLy8gICAgICAgICAgICAgICAgICAgICAgICAgICAgICkKCWZyYW1lX2RpZyAyMyAvLyBjbXBTdGFrZXI6IChhZGRyZXNzLHVpbnQ2NCx1aW50NjQsdWludDY0LHVpbnQ2NCkKCWV4dHJhY3QgMzIgOAoJYnRvaQoJZnJhbWVfZGlnIDEzIC8vIHRva2VuUmV3YXJkQXZhaWw6IHVpbnQ2NAoJbXVsdwoJZnJhbWVfZGlnIDI1IC8vIHRpbWVQZXJjZW50YWdlOiB1aW50NjQKCXVuY292ZXIgMgoJZGlnIDEKCSoKCWNvdmVyIDIKCW11bHcKCWNvdmVyIDIKCSsKCXN3YXAKCWJ5dGUgMHg3Mzc0NjE2YjY1NjQgLy8gInN0YWtlZCIKCWFwcF9nbG9iYWxfZ2V0CglpbnQgMTAwMAoJbXVsdwoJZGl2bW9kdwoJcG9wCglwb3AKCXN3YXAKCSEKCWFzc2VydAoJZnJhbWVfYnVyeSAyNiAvLyBzdGFrZXJUb2tlblJld2FyZDogdWludDY0CgoJLy8gY29udHJhY3RzL3N0YWtpbmdQb29sLmFsZ28udHM6NzEwCgkvLyB0b2tlblJld2FyZEF2YWlsIC09IHN0YWtlclRva2VuUmV3YXJkCglmcmFtZV9kaWcgMTMgLy8gdG9rZW5SZXdhcmRBdmFpbDogdWludDY0CglmcmFtZV9kaWcgMjYgLy8gc3Rha2VyVG9rZW5SZXdhcmQ6IHVpbnQ2NAoJLQoJZnJhbWVfYnVyeSAxMyAvLyB0b2tlblJld2FyZEF2YWlsOiB1aW50NjQKCgkvLyBjb250cmFjdHMvc3Rha2luZ1Bvb2wuYWxnby50czo3MTEKCS8vIGNtcFN0YWtlci5yZXdhcmRUb2tlbkJhbGFuY2UgKz0gc3Rha2VyVG9rZW5SZXdhcmQKCWZyYW1lX2RpZyAyMyAvLyBjbXBTdGFrZXI6IChhZGRyZXNzLHVpbnQ2NCx1aW50NjQsdWludDY0LHVpbnQ2NCkKCWludCA0OCAvLyBoZWFkT2Zmc2V0CglmcmFtZV9kaWcgMjMgLy8gY21wU3Rha2VyOiAoYWRkcmVzcyx1aW50NjQsdWludDY0LHVpbnQ2NCx1aW50NjQpCglleHRyYWN0IDQ4IDgKCWJ0b2kKCWZyYW1lX2RpZyAyNiAvLyBzdGFrZXJUb2tlblJld2FyZDogdWludDY0CgkrCglpdG9iCglyZXBsYWNlMwoJZnJhbWVfYnVyeSAyMyAvLyBjbXBTdGFrZXI6IChhZGRyZXNzLHVpbnQ2NCx1aW50NjQsdWludDY0LHVpbnQ2NCkKCgkvLyBjb250cmFjdHMvc3Rha2luZ1Bvb2wuYWxnby50czo3MTIKCS8vIHRva2VuUmV3YXJkUGFpZE91dCArPSBzdGFrZXJUb2tlblJld2FyZAoJZnJhbWVfZGlnIDE0IC8vIHRva2VuUmV3YXJkUGFpZE91dDogdWludDY0CglmcmFtZV9kaWcgMjYgLy8gc3Rha2VyVG9rZW5SZXdhcmQ6IHVpbnQ2NAoJKwoJZnJhbWVfYnVyeSAxNCAvLyB0b2tlblJld2FyZFBhaWRPdXQ6IHVpbnQ2NAoKKmlmMzRfZW5kOgoJLy8gKmlmMzVfY29uZGl0aW9uCgkvLyBjb250cmFjdHMvc3Rha2luZ1Bvb2wuYWxnby50czo3MTQKCS8vIGFsZ29SZXdhcmRBdmFpbCA+IDAKCWZyYW1lX2RpZyAxMCAvLyBhbGdvUmV3YXJkQXZhaWw6IHVpbnQ2NAoJaW50IDAKCT4KCWJ6ICppZjM1X2VuZAoKCS8vICppZjM1X2NvbnNlcXVlbnQKCS8vIGNvbnRyYWN0cy9zdGFraW5nUG9vbC5hbGdvLnRzOjcxNgoJLy8gc3Rha2VyUmV3YXJkID0gd2lkZVJhdGlvKAoJLy8gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBbY21wU3Rha2VyLmJhbGFuY2UsIGFsZ29SZXdhcmRBdmFpbCwgdGltZVBlcmNlbnRhZ2VdLAoJLy8gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBbdGhpcy50b3RhbEFsZ29TdGFrZWQudmFsdWUsIDEwMDBdCgkvLyAgICAgICAgICAgICAgICAgICAgICAgICAgICAgKQoJZnJhbWVfZGlnIDIzIC8vIGNtcFN0YWtlcjogKGFkZHJlc3MsdWludDY0LHVpbnQ2NCx1aW50NjQsdWludDY0KQoJZXh0cmFjdCAzMiA4CglidG9pCglmcmFtZV9kaWcgMTAgLy8gYWxnb1Jld2FyZEF2YWlsOiB1aW50NjQKCW11bHcKCWZyYW1lX2RpZyAyNSAvLyB0aW1lUGVyY2VudGFnZTogdWludDY0Cgl1bmNvdmVyIDIKCWRpZyAxCgkqCgljb3ZlciAyCgltdWx3Cgljb3ZlciAyCgkrCglzd2FwCglieXRlIDB4NzM3NDYxNmI2NTY0IC8vICJzdGFrZWQiCglhcHBfZ2xvYmFsX2dldAoJaW50IDEwMDAKCW11bHcKCWRpdm1vZHcKCXBvcAoJcG9wCglzd2FwCgkhCglhc3NlcnQKCWZyYW1lX2J1cnkgMjcgLy8gc3Rha2VyUmV3YXJkOiB1aW50NjQKCgkvLyBjb250cmFjdHMvc3Rha2luZ1Bvb2wuYWxnby50czo3MjMKCS8vIGFsZ29SZXdhcmRBdmFpbCAtPSBzdGFrZXJSZXdhcmQKCWZyYW1lX2RpZyAxMCAvLyBhbGdvUmV3YXJkQXZhaWw6IHVpbnQ2NAoJZnJhbWVfZGlnIDI3IC8vIHN0YWtlclJld2FyZDogdWludDY0CgktCglmcmFtZV9idXJ5IDEwIC8vIGFsZ29SZXdhcmRBdmFpbDogdWludDY0CgoJLy8gY29udHJhY3RzL3N0YWtpbmdQb29sLmFsZ28udHM6NzI2CgkvLyBjbXBTdGFrZXIuYmFsYW5jZSArPSBzdGFrZXJSZXdhcmQKCWZyYW1lX2RpZyAyMyAvLyBjbXBTdGFrZXI6IChhZGRyZXNzLHVpbnQ2NCx1aW50NjQsdWludDY0LHVpbnQ2NCkKCWludCAzMiAvLyBoZWFkT2Zmc2V0CglmcmFtZV9kaWcgMjMgLy8gY21wU3Rha2VyOiAoYWRkcmVzcyx1aW50NjQsdWludDY0LHVpbnQ2NCx1aW50NjQpCglleHRyYWN0IDMyIDgKCWJ0b2kKCWZyYW1lX2RpZyAyNyAvLyBzdGFrZXJSZXdhcmQ6IHVpbnQ2NAoJKwoJaXRvYgoJcmVwbGFjZTMKCWZyYW1lX2J1cnkgMjMgLy8gY21wU3Rha2VyOiAoYWRkcmVzcyx1aW50NjQsdWludDY0LHVpbnQ2NCx1aW50NjQpCgoJLy8gY29udHJhY3RzL3N0YWtpbmdQb29sLmFsZ28udHM6NzI3CgkvLyBjbXBTdGFrZXIudG90YWxSZXdhcmRlZCArPSBzdGFrZXJSZXdhcmQKCWZyYW1lX2RpZyAyMyAvLyBjbXBTdGFrZXI6IChhZGRyZXNzLHVpbnQ2NCx1aW50NjQsdWludDY0LHVpbnQ2NCkKCWludCA0MCAvLyBoZWFkT2Zmc2V0CglmcmFtZV9kaWcgMjMgLy8gY21wU3Rha2VyOiAoYWRkcmVzcyx1aW50NjQsdWludDY0LHVpbnQ2NCx1aW50NjQpCglleHRyYWN0IDQwIDgKCWJ0b2kKCWZyYW1lX2RpZyAyNyAvLyBzdGFrZXJSZXdhcmQ6IHVpbnQ2NAoJKwoJaXRvYgoJcmVwbGFjZTMKCWZyYW1lX2J1cnkgMjMgLy8gY21wU3Rha2VyOiAoYWRkcmVzcyx1aW50NjQsdWludDY0LHVpbnQ2NCx1aW50NjQpCgoJLy8gY29udHJhY3RzL3N0YWtpbmdQb29sLmFsZ28udHM6NzI4CgkvLyBpbmNyZWFzZWRTdGFrZSArPSBzdGFrZXJSZXdhcmQKCWZyYW1lX2RpZyAyMCAvLyBpbmNyZWFzZWRTdGFrZTogdWludDY0CglmcmFtZV9kaWcgMjcgLy8gc3Rha2VyUmV3YXJkOiB1aW50NjQKCSsKCWZyYW1lX2J1cnkgMjAgLy8gaW5jcmVhc2VkU3Rha2U6IHVpbnQ2NAoKKmlmMzVfZW5kOgoJLy8gY29udHJhY3RzL3N0YWtpbmdQb29sLmFsZ28udHM6NzMxCgkvLyB0aGlzLnN0YWtlcnMudmFsdWVbaV0gPSBjbXBTdGFrZXIKCWZyYW1lX2RpZyAyMiAvLyBpOiB1aW50NjQKCWludCA2NAoJKiAvLyBhY2MgKiB0eXBlTGVuZ3RoCglmcmFtZV9kaWcgMjMgLy8gY21wU3Rha2VyOiAoYWRkcmVzcyx1aW50NjQsdWludDY0LHVpbnQ2NCx1aW50NjQpCglieXRlIDB4NzM3NDYxNmI2NTcyNzMgLy8gInN0YWtlcnMiCgljb3ZlciAyCglib3hfcmVwbGFjZQoKKmlmMzNfZW5kOgoKKmlmMzJfZW5kOgoKKmlmMzFfZW5kOgoKKmZvcl80X2NvbnRpbnVlOgoJLy8gY29udHJhY3RzL3N0YWtpbmdQb29sLmFsZ28udHM6Njc5CgkvLyBpICs9IDEKCWZyYW1lX2RpZyAyMiAvLyBpOiB1aW50NjQKCWludCAxCgkrCglmcmFtZV9idXJ5IDIyIC8vIGk6IHVpbnQ2NAoJYiAqZm9yXzQKCipmb3JfNF9lbmQ6CgkvLyBjb250cmFjdHMvc3Rha2luZ1Bvb2wuYWxnby50czo3MzYKCS8vIGxvZyhjb25jYXQoJ3BhcnRpYWwgc3Rha2VyIHRvdGFsIHN0YWtlOiAlaScsIGl0b2IocGFydGlhbFN0YWtlcnNUb3RhbFN0YWtlKSkpCglieXRlIDB4NzA2MTcyNzQ2OTYxNmMyMDczNzQ2MTZiNjU3MjIwNzQ2Zjc0NjE2YzIwNzM3NDYxNmI2NTNhMjAyNTY5IC8vICJwYXJ0aWFsIHN0YWtlciB0b3RhbCBzdGFrZTogJWkiCglmcmFtZV9kaWcgMjEgLy8gcGFydGlhbFN0YWtlcnNUb3RhbFN0YWtlOiB1aW50NjQKCWl0b2IKCWNvbmNhdAoJbG9nCgoJLy8gY29udHJhY3RzL3N0YWtpbmdQb29sLmFsZ28udHM6NzQwCgkvLyBuZXdQb29sVG90YWxTdGFrZSA9IHRoaXMudG90YWxBbGdvU3Rha2VkLnZhbHVlIC0gcGFydGlhbFN0YWtlcnNUb3RhbFN0YWtlCglieXRlIDB4NzM3NDYxNmI2NTY0IC8vICJzdGFrZWQiCglhcHBfZ2xvYmFsX2dldAoJZnJhbWVfZGlnIDIxIC8vIHBhcnRpYWxTdGFrZXJzVG90YWxTdGFrZTogdWludDY0CgktCglmcmFtZV9idXJ5IDI4IC8vIG5ld1Bvb2xUb3RhbFN0YWtlOiB1aW50NjQKCgkvLyAqaWYzNl9jb25kaXRpb24KCS8vIGNvbnRyYWN0cy9zdGFraW5nUG9vbC5hbGdvLnRzOjc0NAoJLy8gbmV3UG9vbFRvdGFsU3Rha2UgPiAwCglmcmFtZV9kaWcgMjggLy8gbmV3UG9vbFRvdGFsU3Rha2U6IHVpbnQ2NAoJaW50IDAKCT4KCWJ6ICppZjM2X2VuZAoKCS8vICppZjM2X2NvbnNlcXVlbnQKCS8vIGNvbnRyYWN0cy9zdGFraW5nUG9vbC5hbGdvLnRzOjc0NgoJLy8gZm9yIChsZXQgaSA9IDA7IGkgPCB0aGlzLnN0YWtlcnMudmFsdWUubGVuZ3RoOyBpICs9IDEpCglpbnQgMAoJZnJhbWVfYnVyeSAyOSAvLyBpOiB1aW50NjQKCipmb3JfNToKCS8vIGNvbnRyYWN0cy9zdGFraW5nUG9vbC5hbGdvLnRzOjc0NgoJLy8gaSA8IHRoaXMuc3Rha2Vycy52YWx1ZS5sZW5ndGgKCWZyYW1lX2RpZyAyOSAvLyBpOiB1aW50NjQKCWludCAyMDAKCTwKCWJ6ICpmb3JfNV9lbmQKCgkvLyAqaWYzN19jb25kaXRpb24KCS8vIGNvbnRyYWN0cy9zdGFraW5nUG9vbC5hbGdvLnRzOjc0NwoJLy8gZ2xvYmFscy5vcGNvZGVCdWRnZXQgPCAyMDAKCWdsb2JhbCBPcGNvZGVCdWRnZXQKCWludCAyMDAKCTwKCWJ6ICppZjM3X2VuZAoKCS8vICppZjM3X2NvbnNlcXVlbnQKCS8vIGNvbnRyYWN0cy9zdGFraW5nUG9vbC5hbGdvLnRzOjc0OAoJLy8gaW5jcmVhc2VPcGNvZGVCdWRnZXQoKQoJaXR4bl9iZWdpbgoJaW50IGFwcGwKCWl0eG5fZmllbGQgVHlwZUVudW0KCWludCAwCglpdHhuX2ZpZWxkIEZlZQoJYnl0ZSBiNjQgQ29FQiAvLyAjcHJhZ21hIHZlcnNpb24gMTA7IGludCAxCglkdXAKCWl0eG5fZmllbGQgQXBwcm92YWxQcm9ncmFtCglpdHhuX2ZpZWxkIENsZWFyU3RhdGVQcm9ncmFtCglpbnQgRGVsZXRlQXBwbGljYXRpb24KCWl0eG5fZmllbGQgT25Db21wbGV0aW9uCglpdHhuX3N1Ym1pdAoKKmlmMzdfZW5kOgoJLy8gY29udHJhY3RzL3N0YWtpbmdQb29sLmFsZ28udHM6NzUwCgkvLyBjbXBTdGFrZXIgPSBjbG9uZSh0aGlzLnN0YWtlcnMudmFsdWVbaV0pCglmcmFtZV9kaWcgMjkgLy8gaTogdWludDY0CglpbnQgNjQKCSogLy8gYWNjICogdHlwZUxlbmd0aAoJaW50IDY0CglieXRlIDB4NzM3NDYxNmI2NTcyNzMgLy8gInN0YWtlcnMiCgljb3ZlciAyCglib3hfZXh0cmFjdAoJZnJhbWVfYnVyeSAzMCAvLyBjbXBTdGFrZXI6IChhZGRyZXNzLHVpbnQ2NCx1aW50NjQsdWludDY0LHVpbnQ2NCkKCgkvLyAqaWYzOF9jb25kaXRpb24KCS8vIGNvbnRyYWN0cy9zdGFraW5nUG9vbC5hbGdvLnRzOjc1MQoJLy8gY21wU3Rha2VyLmFjY291bnQgIT09IGdsb2JhbHMuemVyb0FkZHJlc3MgJiYgY21wU3Rha2VyLmVudHJ5VGltZSA8IGN1clRpbWUKCWZyYW1lX2RpZyAzMCAvLyBjbXBTdGFrZXI6IChhZGRyZXNzLHVpbnQ2NCx1aW50NjQsdWludDY0LHVpbnQ2NCkKCWV4dHJhY3QgMCAzMgoJZ2xvYmFsIFplcm9BZGRyZXNzCgkhPQoJZHVwCglieiAqc2tpcF9hbmQ0CglmcmFtZV9kaWcgMzAgLy8gY21wU3Rha2VyOiAoYWRkcmVzcyx1aW50NjQsdWludDY0LHVpbnQ2NCx1aW50NjQpCglleHRyYWN0IDU2IDgKCWJ0b2kKCWZyYW1lX2RpZyAxIC8vIGN1clRpbWU6IHVpbnQ2NAoJPAoJJiYKCipza2lwX2FuZDQ6CglieiAqaWYzOF9lbmQKCgkvLyAqaWYzOF9jb25zZXF1ZW50CgkvLyBjb250cmFjdHMvc3Rha2luZ1Bvb2wuYWxnby50czo3NTIKCS8vIHRpbWVJblBvb2wgPSBjdXJUaW1lIC0gY21wU3Rha2VyLmVudHJ5VGltZQoJZnJhbWVfZGlnIDEgLy8gY3VyVGltZTogdWludDY0CglmcmFtZV9kaWcgMzAgLy8gY21wU3Rha2VyOiAoYWRkcmVzcyx1aW50NjQsdWludDY0LHVpbnQ2NCx1aW50NjQpCglleHRyYWN0IDU2IDgKCWJ0b2kKCS0KCWZyYW1lX2J1cnkgMzEgLy8gdGltZUluUG9vbDogdWludDY0CgoJLy8gKmlmMzlfY29uZGl0aW9uCgkvLyBjb250cmFjdHMvc3Rha2luZ1Bvb2wuYWxnby50czo3NTQKCS8vIHRpbWVJblBvb2wgPj0gZXBvY2hJblNlY3MKCWZyYW1lX2RpZyAzMSAvLyB0aW1lSW5Qb29sOiB1aW50NjQKCWZyYW1lX2RpZyAyIC8vIGVwb2NoSW5TZWNzOiB1aW50NjQKCT49CglieiAqaWYzOV9lbmQKCgkvLyAqaWYzOV9jb25zZXF1ZW50CgkvLyAqaWY0MF9jb25kaXRpb24KCS8vIGNvbnRyYWN0cy9zdGFraW5nUG9vbC5hbGdvLnRzOjc1OQoJLy8gdG9rZW5SZXdhcmRBdmFpbCA+IDAKCWZyYW1lX2RpZyAxMyAvLyB0b2tlblJld2FyZEF2YWlsOiB1aW50NjQKCWludCAwCgk+CglieiAqaWY0MF9lbmQKCgkvLyAqaWY0MF9jb25zZXF1ZW50CgkvLyBjb250cmFjdHMvc3Rha2luZ1Bvb2wuYWxnby50czo3NjYKCS8vIHN0YWtlclRva2VuUmV3YXJkID0gd2lkZVJhdGlvKAoJLy8gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBbY21wU3Rha2VyLmJhbGFuY2UsIHRva2VuUmV3YXJkQXZhaWxdLAoJLy8gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBbbmV3UG9vbFRvdGFsU3Rha2VdCgkvLyAgICAgICAgICAgICAgICAgICAgICAgICAgICAgKQoJZnJhbWVfZGlnIDMwIC8vIGNtcFN0YWtlcjogKGFkZHJlc3MsdWludDY0LHVpbnQ2NCx1aW50NjQsdWludDY0KQoJZXh0cmFjdCAzMiA4CglidG9pCglmcmFtZV9kaWcgMTMgLy8gdG9rZW5SZXdhcmRBdmFpbDogdWludDY0CgltdWx3CglpbnQgMAoJZnJhbWVfZGlnIDI4IC8vIG5ld1Bvb2xUb3RhbFN0YWtlOiB1aW50NjQKCWRpdm1vZHcKCXBvcAoJcG9wCglzd2FwCgkhCglhc3NlcnQKCWZyYW1lX2J1cnkgMzIgLy8gc3Rha2VyVG9rZW5SZXdhcmQ6IHVpbnQ2NAoKCS8vIGNvbnRyYWN0cy9zdGFraW5nUG9vbC5hbGdvLnRzOjc3NQoJLy8gY21wU3Rha2VyLnJld2FyZFRva2VuQmFsYW5jZSArPSBzdGFrZXJUb2tlblJld2FyZAoJZnJhbWVfZGlnIDMwIC8vIGNtcFN0YWtlcjogKGFkZHJlc3MsdWludDY0LHVpbnQ2NCx1aW50NjQsdWludDY0KQoJaW50IDQ4IC8vIGhlYWRPZmZzZXQKCWZyYW1lX2RpZyAzMCAvLyBjbXBTdGFrZXI6IChhZGRyZXNzLHVpbnQ2NCx1aW50NjQsdWludDY0LHVpbnQ2NCkKCWV4dHJhY3QgNDggOAoJYnRvaQoJZnJhbWVfZGlnIDMyIC8vIHN0YWtlclRva2VuUmV3YXJkOiB1aW50NjQKCSsKCWl0b2IKCXJlcGxhY2UzCglmcmFtZV9idXJ5IDMwIC8vIGNtcFN0YWtlcjogKGFkZHJlc3MsdWludDY0LHVpbnQ2NCx1aW50NjQsdWludDY0KQoKCS8vIGNvbnRyYWN0cy9zdGFraW5nUG9vbC5hbGdvLnRzOjc3NgoJLy8gdG9rZW5SZXdhcmRQYWlkT3V0ICs9IHN0YWtlclRva2VuUmV3YXJkCglmcmFtZV9kaWcgMTQgLy8gdG9rZW5SZXdhcmRQYWlkT3V0OiB1aW50NjQKCWZyYW1lX2RpZyAzMiAvLyBzdGFrZXJUb2tlblJld2FyZDogdWludDY0CgkrCglmcmFtZV9idXJ5IDE0IC8vIHRva2VuUmV3YXJkUGFpZE91dDogdWludDY0CgoqaWY0MF9lbmQ6CgkvLyAqaWY0MV9jb25kaXRpb24KCS8vIGNvbnRyYWN0cy9zdGFraW5nUG9vbC5hbGdvLnRzOjc3OAoJLy8gYWxnb1Jld2FyZEF2YWlsID4gMAoJZnJhbWVfZGlnIDEwIC8vIGFsZ29SZXdhcmRBdmFpbDogdWludDY0CglpbnQgMAoJPgoJYnogKmlmNDFfZW5kCgoJLy8gKmlmNDFfY29uc2VxdWVudAoJLy8gY29udHJhY3RzL3N0YWtpbmdQb29sLmFsZ28udHM6Nzc5CgkvLyBzdGFrZXJSZXdhcmQgPSB3aWRlUmF0aW8oW2NtcFN0YWtlci5iYWxhbmNlLCBhbGdvUmV3YXJkQXZhaWxdLCBbbmV3UG9vbFRvdGFsU3Rha2VdKQoJZnJhbWVfZGlnIDMwIC8vIGNtcFN0YWtlcjogKGFkZHJlc3MsdWludDY0LHVpbnQ2NCx1aW50NjQsdWludDY0KQoJZXh0cmFjdCAzMiA4CglidG9pCglmcmFtZV9kaWcgMTAgLy8gYWxnb1Jld2FyZEF2YWlsOiB1aW50NjQKCW11bHcKCWludCAwCglmcmFtZV9kaWcgMjggLy8gbmV3UG9vbFRvdGFsU3Rha2U6IHVpbnQ2NAoJZGl2bW9kdwoJcG9wCglwb3AKCXN3YXAKCSEKCWFzc2VydAoJZnJhbWVfYnVyeSAzMyAvLyBzdGFrZXJSZXdhcmQ6IHVpbnQ2NAoKCS8vIGNvbnRyYWN0cy9zdGFraW5nUG9vbC5hbGdvLnRzOjc4MgoJLy8gY21wU3Rha2VyLmJhbGFuY2UgKz0gc3Rha2VyUmV3YXJkCglmcmFtZV9kaWcgMzAgLy8gY21wU3Rha2VyOiAoYWRkcmVzcyx1aW50NjQsdWludDY0LHVpbnQ2NCx1aW50NjQpCglpbnQgMzIgLy8gaGVhZE9mZnNldAoJZnJhbWVfZGlnIDMwIC8vIGNtcFN0YWtlcjogKGFkZHJlc3MsdWludDY0LHVpbnQ2NCx1aW50NjQsdWludDY0KQoJZXh0cmFjdCAzMiA4CglidG9pCglmcmFtZV9kaWcgMzMgLy8gc3Rha2VyUmV3YXJkOiB1aW50NjQKCSsKCWl0b2IKCXJlcGxhY2UzCglmcmFtZV9idXJ5IDMwIC8vIGNtcFN0YWtlcjogKGFkZHJlc3MsdWludDY0LHVpbnQ2NCx1aW50NjQsdWludDY0KQoKCS8vIGNvbnRyYWN0cy9zdGFraW5nUG9vbC5hbGdvLnRzOjc4MwoJLy8gY21wU3Rha2VyLnRvdGFsUmV3YXJkZWQgKz0gc3Rha2VyUmV3YXJkCglmcmFtZV9kaWcgMzAgLy8gY21wU3Rha2VyOiAoYWRkcmVzcyx1aW50NjQsdWludDY0LHVpbnQ2NCx1aW50NjQpCglpbnQgNDAgLy8gaGVhZE9mZnNldAoJZnJhbWVfZGlnIDMwIC8vIGNtcFN0YWtlcjogKGFkZHJlc3MsdWludDY0LHVpbnQ2NCx1aW50NjQsdWludDY0KQoJZXh0cmFjdCA0MCA4CglidG9pCglmcmFtZV9kaWcgMzMgLy8gc3Rha2VyUmV3YXJkOiB1aW50NjQKCSsKCWl0b2IKCXJlcGxhY2UzCglmcmFtZV9idXJ5IDMwIC8vIGNtcFN0YWtlcjogKGFkZHJlc3MsdWludDY0LHVpbnQ2NCx1aW50NjQsdWludDY0KQoKCS8vIGNvbnRyYWN0cy9zdGFraW5nUG9vbC5hbGdvLnRzOjc4NAoJLy8gaW5jcmVhc2VkU3Rha2UgKz0gc3Rha2VyUmV3YXJkCglmcmFtZV9kaWcgMjAgLy8gaW5jcmVhc2VkU3Rha2U6IHVpbnQ2NAoJZnJhbWVfZGlnIDMzIC8vIHN0YWtlclJld2FyZDogdWludDY0CgkrCglmcmFtZV9idXJ5IDIwIC8vIGluY3JlYXNlZFN0YWtlOiB1aW50NjQKCippZjQxX2VuZDoKCS8vIGNvbnRyYWN0cy9zdGFraW5nUG9vbC5hbGdvLnRzOjc4OAoJLy8gdGhpcy5zdGFrZXJzLnZhbHVlW2ldID0gY21wU3Rha2VyCglmcmFtZV9kaWcgMjkgLy8gaTogdWludDY0CglpbnQgNjQKCSogLy8gYWNjICogdHlwZUxlbmd0aAoJZnJhbWVfZGlnIDMwIC8vIGNtcFN0YWtlcjogKGFkZHJlc3MsdWludDY0LHVpbnQ2NCx1aW50NjQsdWludDY0KQoJYnl0ZSAweDczNzQ2MTZiNjU3MjczIC8vICJzdGFrZXJzIgoJY292ZXIgMgoJYm94X3JlcGxhY2UKCippZjM5X2VuZDoKCippZjM4X2VuZDoKCipmb3JfNV9jb250aW51ZToKCS8vIGNvbnRyYWN0cy9zdGFraW5nUG9vbC5hbGdvLnRzOjc0NgoJLy8gaSArPSAxCglmcmFtZV9kaWcgMjkgLy8gaTogdWludDY0CglpbnQgMQoJKwoJZnJhbWVfYnVyeSAyOSAvLyBpOiB1aW50NjQKCWIgKmZvcl81CgoqZm9yXzVfZW5kOgoKKmlmMzZfZW5kOgoJLy8gY29udHJhY3RzL3N0YWtpbmdQb29sLmFsZ28udHM6Nzk2CgkvLyB0aGlzLnRvdGFsQWxnb1N0YWtlZC52YWx1ZSArPSBpbmNyZWFzZWRTdGFrZQoJYnl0ZSAweDczNzQ2MTZiNjU2NCAvLyAic3Rha2VkIgoJYXBwX2dsb2JhbF9nZXQKCWZyYW1lX2RpZyAyMCAvLyBpbmNyZWFzZWRTdGFrZTogdWludDY0CgkrCglieXRlIDB4NzM3NDYxNmI2NTY0IC8vICJzdGFrZWQiCglzd2FwCglhcHBfZ2xvYmFsX3B1dAoKCS8vIGNvbnRyYWN0cy9zdGFraW5nUG9vbC5hbGdvLnRzOjc5OAoJLy8gbG9nKGNvbmNhdCgnaW5jciBzdGFrZTogJWknLCBpdG9iKGluY3JlYXNlZFN0YWtlKSkpCglieXRlIDB4Njk2ZTYzNzIyMDczNzQ2MTZiNjUzYTIwMjU2OSAvLyAiaW5jciBzdGFrZTogJWkiCglmcmFtZV9kaWcgMjAgLy8gaW5jcmVhc2VkU3Rha2U6IHVpbnQ2NAoJaXRvYgoJY29uY2F0Cglsb2cKCgkvLyBjb250cmFjdHMvc3Rha2luZ1Bvb2wuYWxnby50czo3OTkKCS8vIGxvZyhjb25jYXQoJ3Rvay4gcndkIHBhaWQ6ICVpJywgaXRvYih0b2tlblJld2FyZFBhaWRPdXQpKSkKCWJ5dGUgMHg3NDZmNmIyZTIwNzI3NzY0MjA3MDYxNjk2NDNhMjAyNTY5IC8vICJ0b2suIHJ3ZCBwYWlkOiAlaSIKCWZyYW1lX2RpZyAxNCAvLyB0b2tlblJld2FyZFBhaWRPdXQ6IHVpbnQ2NAoJaXRvYgoJY29uY2F0Cglsb2cKCgkvLyBjb250cmFjdHMvc3Rha2luZ1Bvb2wuYWxnby50czo4MDQKCS8vIHNlbmRNZXRob2RDYWxsPHR5cGVvZiBWYWxpZGF0b3JSZWdpc3RyeS5wcm90b3R5cGUuc3Rha2VVcGRhdGVkVmlhUmV3YXJkcz4oewoJLy8gICAgICAgICAgICAgYXBwbGljYXRpb25JRDogQXBwSUQuZnJvbVVpbnQ2NCh0aGlzLmNyZWF0aW5nVmFsaWRhdG9yQ29udHJhY3RBcHBJZC52YWx1ZSksCgkvLyAgICAgICAgICAgICBtZXRob2RBcmdzOiBbCgkvLyAgICAgICAgICAgICAgICAgeyBpZDogdGhpcy52YWxpZGF0b3JJZC52YWx1ZSwgcG9vbElkOiB0aGlzLnBvb2xJZC52YWx1ZSwgcG9vbEFwcElkOiB0aGlzLmFwcC5pZCB9LAoJLy8gICAgICAgICAgICAgICAgIGluY3JlYXNlZFN0YWtlLAoJLy8gICAgICAgICAgICAgICAgIHRva2VuUmV3YXJkUGFpZE91dCwKCS8vICAgICAgICAgICAgIF0sCgkvLyAgICAgICAgIH0pCglpdHhuX2JlZ2luCglpbnQgYXBwbAoJaXR4bl9maWVsZCBUeXBlRW51bQoJbWV0aG9kICJzdGFrZVVwZGF0ZWRWaWFSZXdhcmRzKCh1aW50NjQsdWludDY0LHVpbnQ2NCksdWludDY0LHVpbnQ2NCl2b2lkIgoJaXR4bl9maWVsZCBBcHBsaWNhdGlvbkFyZ3MKCgkvLyBjb250cmFjdHMvc3Rha2luZ1Bvb2wuYWxnby50czo4MDUKCS8vIGFwcGxpY2F0aW9uSUQ6IEFwcElELmZyb21VaW50NjQodGhpcy5jcmVhdGluZ1ZhbGlkYXRvckNvbnRyYWN0QXBwSWQudmFsdWUpCglieXRlIDB4NjM3MjY1NjE3NDZmNzI0MTcwNzAgLy8gImNyZWF0b3JBcHAiCglhcHBfZ2xvYmFsX2dldAoJaXR4bl9maWVsZCBBcHBsaWNhdGlvbklECgoJLy8gY29udHJhY3RzL3N0YWtpbmdQb29sLmFsZ28udHM6ODA2CgkvLyBtZXRob2RBcmdzOiBbCgkvLyAgICAgICAgICAgICAgICAgeyBpZDogdGhpcy52YWxpZGF0b3JJZC52YWx1ZSwgcG9vbElkOiB0aGlzLnBvb2xJZC52YWx1ZSwgcG9vbEFwcElkOiB0aGlzLmFwcC5pZCB9LAoJLy8gICAgICAgICAgICAgICAgIGluY3JlYXNlZFN0YWtlLAoJLy8gICAgICAgICAgICAgICAgIHRva2VuUmV3YXJkUGFpZE91dCwKCS8vICAgICAgICAgICAgIF0KCWJ5dGUgMHg3NjYxNmM2OTY0NjE3NDZmNzI0OTY0IC8vICJ2YWxpZGF0b3JJZCIKCWFwcF9nbG9iYWxfZ2V0CglpdG9iCglieXRlIDB4NzA2ZjZmNmM0OTY0IC8vICJwb29sSWQiCglhcHBfZ2xvYmFsX2dldAoJaXRvYgoJY29uY2F0Cgl0eG5hIEFwcGxpY2F0aW9ucyAwCglpdG9iCgljb25jYXQKCWl0eG5fZmllbGQgQXBwbGljYXRpb25BcmdzCglmcmFtZV9kaWcgMjAgLy8gaW5jcmVhc2VkU3Rha2U6IHVpbnQ2NAoJaXRvYgoJaXR4bl9maWVsZCBBcHBsaWNhdGlvbkFyZ3MKCWZyYW1lX2RpZyAxNCAvLyB0b2tlblJld2FyZFBhaWRPdXQ6IHVpbnQ2NAoJaXRvYgoJaXR4bl9maWVsZCBBcHBsaWNhdGlvbkFyZ3MKCgkvLyBGZWUgZmllbGQgbm90IHNldCwgZGVmYXVsdGluZyB0byAwCglpbnQgMAoJaXR4bl9maWVsZCBGZWUKCgkvLyBTdWJtaXQgaW5uZXIgdHJhbnNhY3Rpb24KCWl0eG5fc3VibWl0CglyZXRzdWIKCi8vIGdvT25saW5lKGJ5dGVbXSxieXRlW10sYnl0ZVtdLHVpbnQ2NCx1aW50NjQsdWludDY0KXZvaWQKKmFiaV9yb3V0ZV9nb09ubGluZToKCS8vIHZvdGVLZXlEaWx1dGlvbjogdWludDY0Cgl0eG5hIEFwcGxpY2F0aW9uQXJncyA2CglidG9pCgoJLy8gdm90ZUxhc3Q6IHVpbnQ2NAoJdHhuYSBBcHBsaWNhdGlvbkFyZ3MgNQoJYnRvaQoKCS8vIHZvdGVGaXJzdDogdWludDY0Cgl0eG5hIEFwcGxpY2F0aW9uQXJncyA0CglidG9pCgoJLy8gc3RhdGVQcm9vZlBLOiBieXRlW10KCXR4bmEgQXBwbGljYXRpb25BcmdzIDMKCWV4dHJhY3QgMiAwCgoJLy8gc2VsZWN0aW9uUEs6IGJ5dGVbXQoJdHhuYSBBcHBsaWNhdGlvbkFyZ3MgMgoJZXh0cmFjdCAyIDAKCgkvLyB2b3RlUEs6IGJ5dGVbXQoJdHhuYSBBcHBsaWNhdGlvbkFyZ3MgMQoJZXh0cmFjdCAyIDAKCgkvLyBleGVjdXRlIGdvT25saW5lKGJ5dGVbXSxieXRlW10sYnl0ZVtdLHVpbnQ2NCx1aW50NjQsdWludDY0KXZvaWQKCWNhbGxzdWIgZ29PbmxpbmUKCWludCAxCglyZXR1cm4KCi8vIGdvT25saW5lKHZvdGVQSzogYnl0ZXMsIHNlbGVjdGlvblBLOiBieXRlcywgc3RhdGVQcm9vZlBLOiBieXRlcywgdm90ZUZpcnN0OiB1aW50NjQsIHZvdGVMYXN0OiB1aW50NjQsIHZvdGVLZXlEaWx1dGlvbjogdWludDY0KTogdm9pZAovLwovLyBSZWdpc3RlcnMgYSBzdGFraW5nIHBvb2wga2V5IG9ubGluZSBhZ2FpbnN0IGEgcGFydGljaXBhdGlvbiBrZXkuCi8vIFsgT05MWSBPV05FUiBPUiBNQU5BR0VSIENBTiBDQUxMIF0KLy8KLy8gQHBhcmFtIHtieXRlc30gdm90ZVBLIC0gVGhlIHZvdGUgcHVibGljIGtleS4KLy8gQHBhcmFtIHtieXRlc30gc2VsZWN0aW9uUEsgLSBUaGUgc2VsZWN0aW9uIHB1YmxpYyBrZXkuCi8vIEBwYXJhbSB7Ynl0ZXN9IHN0YXRlUHJvb2ZQSyAtIFRoZSBzdGF0ZSBwcm9vZiBwdWJsaWMga2V5LgovLyBAcGFyYW0ge3VpbnQ2NH0gdm90ZUZpcnN0IC0gVGhlIGZpcnN0IHZvdGUgaW5kZXguCi8vIEBwYXJhbSB7dWludDY0fSB2b3RlTGFzdCAtIFRoZSBsYXN0IHZvdGUgaW5kZXguCi8vIEBwYXJhbSB7dWludDY0fSB2b3RlS2V5RGlsdXRpb24gLSBUaGUgdm90ZSBrZXkgZGlsdXRpb24gdmFsdWUuCi8vIEB0aHJvd3Mge0Vycm9yfSBXaWxsIHRocm93IGFuIGVycm9yIGlmIHRoZSBjYWxsZXIgaXMgbm90IHRoZSBvd25lciBvciBhIG1hbmFnZXIuCmdvT25saW5lOgoJcHJvdG8gNiAwCgoJLy8gY29udHJhY3RzL3N0YWtpbmdQb29sLmFsZ28udHM6ODM0CgkvLyBhc3NlcnQodGhpcy5pc093bmVyT3JNYW5hZ2VyQ2FsbGVyKCkpCgljYWxsc3ViIGlzT3duZXJPck1hbmFnZXJDYWxsZXIKCWFzc2VydAoKCS8vIGNvbnRyYWN0cy9zdGFraW5nUG9vbC5hbGdvLnRzOjgzNQoJLy8gc2VuZE9ubGluZUtleVJlZ2lzdHJhdGlvbih7CgkvLyAgICAgICAgICAgICB2b3RlUEs6IHZvdGVQSywKCS8vICAgICAgICAgICAgIHNlbGVjdGlvblBLOiBzZWxlY3Rpb25QSywKCS8vICAgICAgICAgICAgIHN0YXRlUHJvb2ZQSzogc3RhdGVQcm9vZlBLLAoJLy8gICAgICAgICAgICAgdm90ZUZpcnN0OiB2b3RlRmlyc3QsCgkvLyAgICAgICAgICAgICB2b3RlTGFzdDogdm90ZUxhc3QsCgkvLyAgICAgICAgICAgICB2b3RlS2V5RGlsdXRpb246IHZvdGVLZXlEaWx1dGlvbiwKCS8vICAgICAgICAgfSkKCWl0eG5fYmVnaW4KCWludCBrZXlyZWcKCWl0eG5fZmllbGQgVHlwZUVudW0KCgkvLyBjb250cmFjdHMvc3Rha2luZ1Bvb2wuYWxnby50czo4MzYKCS8vIHZvdGVQSzogdm90ZVBLCglmcmFtZV9kaWcgLTEgLy8gdm90ZVBLOiBieXRlcwoJaXR4bl9maWVsZCBWb3RlUEsKCgkvLyBjb250cmFjdHMvc3Rha2luZ1Bvb2wuYWxnby50czo4MzcKCS8vIHNlbGVjdGlvblBLOiBzZWxlY3Rpb25QSwoJZnJhbWVfZGlnIC0yIC8vIHNlbGVjdGlvblBLOiBieXRlcwoJaXR4bl9maWVsZCBTZWxlY3Rpb25QSwoKCS8vIGNvbnRyYWN0cy9zdGFraW5nUG9vbC5hbGdvLnRzOjgzOAoJLy8gc3RhdGVQcm9vZlBLOiBzdGF0ZVByb29mUEsKCWZyYW1lX2RpZyAtMyAvLyBzdGF0ZVByb29mUEs6IGJ5dGVzCglpdHhuX2ZpZWxkIFN0YXRlUHJvb2ZQSwoKCS8vIGNvbnRyYWN0cy9zdGFraW5nUG9vbC5hbGdvLnRzOjgzOQoJLy8gdm90ZUZpcnN0OiB2b3RlRmlyc3QKCWZyYW1lX2RpZyAtNCAvLyB2b3RlRmlyc3Q6IHVpbnQ2NAoJaXR4bl9maWVsZCBWb3RlRmlyc3QKCgkvLyBjb250cmFjdHMvc3Rha2luZ1Bvb2wuYWxnby50czo4NDAKCS8vIHZvdGVMYXN0OiB2b3RlTGFzdAoJZnJhbWVfZGlnIC01IC8vIHZvdGVMYXN0OiB1aW50NjQKCWl0eG5fZmllbGQgVm90ZUxhc3QKCgkvLyBjb250cmFjdHMvc3Rha2luZ1Bvb2wuYWxnby50czo4NDEKCS8vIHZvdGVLZXlEaWx1dGlvbjogdm90ZUtleURpbHV0aW9uCglmcmFtZV9kaWcgLTYgLy8gdm90ZUtleURpbHV0aW9uOiB1aW50NjQKCWl0eG5fZmllbGQgVm90ZUtleURpbHV0aW9uCgoJLy8gRmVlIGZpZWxkIG5vdCBzZXQsIGRlZmF1bHRpbmcgdG8gMAoJaW50IDAKCWl0eG5fZmllbGQgRmVlCgoJLy8gU3VibWl0IGlubmVyIHRyYW5zYWN0aW9uCglpdHhuX3N1Ym1pdAoJcmV0c3ViCgovLyBnb09mZmxpbmUoKXZvaWQKKmFiaV9yb3V0ZV9nb09mZmxpbmU6CgkvLyBleGVjdXRlIGdvT2ZmbGluZSgpdm9pZAoJY2FsbHN1YiBnb09mZmxpbmUKCWludCAxCglyZXR1cm4KCi8vIGdvT2ZmbGluZSgpOiB2b2lkCi8vCi8vIE1hcmtzIGEgc3Rha2luZyBwb29sIGtleSBPRkZMSU5FLgovLyBbIE9OTFkgT1dORVIgT1IgTUFOQUdFUiBDQU4gQ0FMTCBdCmdvT2ZmbGluZToKCXByb3RvIDAgMAoKCS8vICppZjQyX2NvbmRpdGlvbgoJLy8gY29udHJhY3RzL3N0YWtpbmdQb29sLmFsZ28udHM6ODUzCgkvLyB0aGlzLnR4bi5zZW5kZXIgIT09IEFwcElELmZyb21VaW50NjQodGhpcy5jcmVhdGluZ1ZhbGlkYXRvckNvbnRyYWN0QXBwSWQudmFsdWUpLmFkZHJlc3MKCXR4biBTZW5kZXIKCWJ5dGUgMHg2MzcyNjU2MTc0NmY3MjQxNzA3MCAvLyAiY3JlYXRvckFwcCIKCWFwcF9nbG9iYWxfZ2V0CglhcHBfcGFyYW1zX2dldCBBcHBBZGRyZXNzCglwb3AKCSE9CglieiAqaWY0Ml9lbmQKCgkvLyAqaWY0Ml9jb25zZXF1ZW50CgkvLyBjb250cmFjdHMvc3Rha2luZ1Bvb2wuYWxnby50czo4NTQKCS8vIGFzc2VydCh0aGlzLmlzT3duZXJPck1hbmFnZXJDYWxsZXIoKSkKCWNhbGxzdWIgaXNPd25lck9yTWFuYWdlckNhbGxlcgoJYXNzZXJ0CgoqaWY0Ml9lbmQ6CgkvLyBjb250cmFjdHMvc3Rha2luZ1Bvb2wuYWxnby50czo4NTcKCS8vIHNlbmRPZmZsaW5lS2V5UmVnaXN0cmF0aW9uKHt9KQoJaXR4bl9iZWdpbgoJaW50IGtleXJlZwoJaXR4bl9maWVsZCBUeXBlRW51bQoKCS8vIEZlZSBmaWVsZCBub3Qgc2V0LCBkZWZhdWx0aW5nIHRvIDAKCWludCAwCglpdHhuX2ZpZWxkIEZlZQoKCS8vIFN1Ym1pdCBpbm5lciB0cmFuc2FjdGlvbgoJaXR4bl9zdWJtaXQKCXJldHN1YgoKLy8gbGlua1RvTkZEKHVpbnQ2NCxzdHJpbmcpdm9pZAoqYWJpX3JvdXRlX2xpbmtUb05GRDoKCS8vIG5mZE5hbWU6IHN0cmluZwoJdHhuYSBBcHBsaWNhdGlvbkFyZ3MgMgoJZXh0cmFjdCAyIDAKCgkvLyBuZmRBcHBJZDogdWludDY0Cgl0eG5hIEFwcGxpY2F0aW9uQXJncyAxCglidG9pCgoJLy8gZXhlY3V0ZSBsaW5rVG9ORkQodWludDY0LHN0cmluZyl2b2lkCgljYWxsc3ViIGxpbmtUb05GRAoJaW50IDEKCXJldHVybgoKLy8gbGlua1RvTkZEKG5mZEFwcElkOiB1aW50NjQsIG5mZE5hbWU6IHN0cmluZyk6IHZvaWQKbGlua1RvTkZEOgoJcHJvdG8gMiAwCgoJLy8gY29udHJhY3RzL3N0YWtpbmdQb29sLmFsZ28udHM6ODY0CgkvLyBhc3NlcnQodGhpcy5pc093bmVyT3JNYW5hZ2VyQ2FsbGVyKCkpCgljYWxsc3ViIGlzT3duZXJPck1hbmFnZXJDYWxsZXIKCWFzc2VydAoKCS8vIGNvbnRyYWN0cy9zdGFraW5nUG9vbC5hbGdvLnRzOjg2NgoJLy8gc2VuZEFwcENhbGwoewoJLy8gICAgICAgICAgICAgYXBwbGljYXRpb25JRDogQXBwSUQuZnJvbVVpbnQ2NCh0aGlzLm5mZFJlZ2lzdHJ5QXBwSWQpLAoJLy8gICAgICAgICAgICAgYXBwbGljYXRpb25BcmdzOiBbJ3ZlcmlmeV9uZmRfYWRkcicsIG5mZE5hbWUsIGl0b2IobmZkQXBwSWQpLCByYXdCeXRlcyh0aGlzLmFwcC5hZGRyZXNzKV0sCgkvLyAgICAgICAgICAgICBhcHBsaWNhdGlvbnM6IFtBcHBJRC5mcm9tVWludDY0KG5mZEFwcElkKV0sCgkvLyAgICAgICAgIH0pCglpdHhuX2JlZ2luCglpbnQgYXBwbAoJaXR4bl9maWVsZCBUeXBlRW51bQoKCS8vIGNvbnRyYWN0cy9zdGFraW5nUG9vbC5hbGdvLnRzOjg2NwoJLy8gYXBwbGljYXRpb25JRDogQXBwSUQuZnJvbVVpbnQ2NCh0aGlzLm5mZFJlZ2lzdHJ5QXBwSWQpCglwdXNoaW50IFRNUExfbmZkUmVnaXN0cnlBcHBJZAoJaXR4bl9maWVsZCBBcHBsaWNhdGlvbklECgoJLy8gY29udHJhY3RzL3N0YWtpbmdQb29sLmFsZ28udHM6ODY4CgkvLyBhcHBsaWNhdGlvbkFyZ3M6IFsndmVyaWZ5X25mZF9hZGRyJywgbmZkTmFtZSwgaXRvYihuZmRBcHBJZCksIHJhd0J5dGVzKHRoaXMuYXBwLmFkZHJlc3MpXQoJYnl0ZSAweDc2NjU3MjY5NjY3OTVmNmU2NjY0NWY2MTY0NjQ3MiAvLyAidmVyaWZ5X25mZF9hZGRyIgoJaXR4bl9maWVsZCBBcHBsaWNhdGlvbkFyZ3MKCWZyYW1lX2RpZyAtMiAvLyBuZmROYW1lOiBzdHJpbmcKCWl0eG5fZmllbGQgQXBwbGljYXRpb25BcmdzCglmcmFtZV9kaWcgLTEgLy8gbmZkQXBwSWQ6IHVpbnQ2NAoJaXRvYgoJaXR4bl9maWVsZCBBcHBsaWNhdGlvbkFyZ3MKCWdsb2JhbCBDdXJyZW50QXBwbGljYXRpb25BZGRyZXNzCglpdHhuX2ZpZWxkIEFwcGxpY2F0aW9uQXJncwoKCS8vIGNvbnRyYWN0cy9zdGFraW5nUG9vbC5hbGdvLnRzOjg2OQoJLy8gYXBwbGljYXRpb25zOiBbQXBwSUQuZnJvbVVpbnQ2NChuZmRBcHBJZCldCglmcmFtZV9kaWcgLTEgLy8gbmZkQXBwSWQ6IHVpbnQ2NAoJaXR4bl9maWVsZCBBcHBsaWNhdGlvbnMKCgkvLyBGZWUgZmllbGQgbm90IHNldCwgZGVmYXVsdGluZyB0byAwCglpbnQgMAoJaXR4bl9maWVsZCBGZWUKCgkvLyBTdWJtaXQgaW5uZXIgdHJhbnNhY3Rpb24KCWl0eG5fc3VibWl0CglyZXRzdWIKCi8vIHByb3hpZWRTZXRUb2tlblBheW91dFJhdGlvKCh1aW50NjQsdWludDY0LHVpbnQ2NCkpKHVpbnQ2NFsyNF0sdWludDY0KQoqYWJpX3JvdXRlX3Byb3hpZWRTZXRUb2tlblBheW91dFJhdGlvOgoJLy8gVGhlIEFCSSByZXR1cm4gcHJlZml4CglieXRlIDB4MTUxZjdjNzUKCgkvLyBwb29sS2V5OiAodWludDY0LHVpbnQ2NCx1aW50NjQpCgl0eG5hIEFwcGxpY2F0aW9uQXJncyAxCglkdXAKCWxlbgoJaW50IDI0Cgk9PQoJYXNzZXJ0CgoJLy8gZXhlY3V0ZSBwcm94aWVkU2V0VG9rZW5QYXlvdXRSYXRpbygodWludDY0LHVpbnQ2NCx1aW50NjQpKSh1aW50NjRbMjRdLHVpbnQ2NCkKCWNhbGxzdWIgcHJveGllZFNldFRva2VuUGF5b3V0UmF0aW8KCWNvbmNhdAoJbG9nCglpbnQgMQoJcmV0dXJuCgovLyBwcm94aWVkU2V0VG9rZW5QYXlvdXRSYXRpbyhwb29sS2V5OiBWYWxpZGF0b3JQb29sS2V5KTogUG9vbFRva2VuUGF5b3V0UmF0aW8KLy8KLy8gcHJveGllZFNldFRva2VuUGF5b3V0UmF0aW8gaXMgbWVhbnQgdG8gYmUgY2FsbGVkIGJ5IHBvb2xzICE9IDEgLSBjYWxsaW5nIFVTLCBwb29sICMxCi8vIFdlIG5lZWQgdG8gdmVyaWZ5IHRoYXQgd2UgYXJlIGluIGZhY3QgYmVpbmcgY2FsbGVkIGJ5IGFub3RoZXIgb2YgT1VSIHBvb2xzIChub3QgdXMpCi8vIGFuZCB0aGVuIHdlJ2xsIGNhbGwgdGhlIHZhbGlkYXRvciBvbiB0aGVpciBiZWhhbGYgdG8gdXBkYXRlIHRoZSB0b2tlbiBwYXlvdXRzCi8vIEBwYXJhbSBwb29sS2V5IC0gVmFsaWRhdG9yUG9vbEtleSB0dXBsZQpwcm94aWVkU2V0VG9rZW5QYXlvdXRSYXRpbzoKCXByb3RvIDEgMQoKCS8vIFB1c2ggZW1wdHkgYnl0ZXMgYWZ0ZXIgdGhlIGZyYW1lIHBvaW50ZXIgdG8gcmVzZXJ2ZSBzcGFjZSBmb3IgbG9jYWwgdmFyaWFibGVzCglieXRlIDB4CgoJLy8gY29udHJhY3RzL3N0YWtpbmdQb29sLmFsZ28udHM6ODgwCgkvLyBhc3NlcnQodGhpcy52YWxpZGF0b3JJZC52YWx1ZSA9PT0gcG9vbEtleS5pZCwgJ2NhbGxlciBtdXN0IGJlIHBhcnQgb2Ygc2FtZSB2YWxpZGF0b3Igc2V0IScpCglieXRlIDB4NzY2MTZjNjk2NDYxNzQ2ZjcyNDk2NCAvLyAidmFsaWRhdG9ySWQiCglhcHBfZ2xvYmFsX2dldAoJZnJhbWVfZGlnIC0xIC8vIHBvb2xLZXk6IFZhbGlkYXRvclBvb2xLZXkKCWV4dHJhY3QgMCA4CglidG9pCgk9PQoKCS8vIGNhbGxlciBtdXN0IGJlIHBhcnQgb2Ygc2FtZSB2YWxpZGF0b3Igc2V0IQoJYXNzZXJ0CgoJLy8gY29udHJhY3RzL3N0YWtpbmdQb29sLmFsZ28udHM6ODgxCgkvLyBhc3NlcnQodGhpcy5wb29sSWQudmFsdWUgPT09IDEsICdjYWxsZWUgbXVzdCBiZSBwb29sIDEnKQoJYnl0ZSAweDcwNmY2ZjZjNDk2NCAvLyAicG9vbElkIgoJYXBwX2dsb2JhbF9nZXQKCWludCAxCgk9PQoKCS8vIGNhbGxlZSBtdXN0IGJlIHBvb2wgMQoJYXNzZXJ0CgoJLy8gY29udHJhY3RzL3N0YWtpbmdQb29sLmFsZ28udHM6ODgyCgkvLyBhc3NlcnQocG9vbEtleS5wb29sSWQgIT09IDEsICdjYWxsZXIgbXVzdCBOT1QgYmUgcG9vbCAxJykKCWZyYW1lX2RpZyAtMSAvLyBwb29sS2V5OiBWYWxpZGF0b3JQb29sS2V5CglleHRyYWN0IDggOAoJYnRvaQoJaW50IDEKCSE9CgoJLy8gY2FsbGVyIG11c3QgTk9UIGJlIHBvb2wgMQoJYXNzZXJ0CgoJLy8gY29udHJhY3RzL3N0YWtpbmdQb29sLmFsZ28udHM6ODg0CgkvLyBjYWxsZXJQb29sQXBwSUQgPSBzZW5kTWV0aG9kQ2FsbDx0eXBlb2YgVmFsaWRhdG9yUmVnaXN0cnkucHJvdG90eXBlLmdldFBvb2xBcHBJZD4oewoJLy8gICAgICAgICAgICAgYXBwbGljYXRpb25JRDogQXBwSUQuZnJvbVVpbnQ2NCh0aGlzLmNyZWF0aW5nVmFsaWRhdG9yQ29udHJhY3RBcHBJZC52YWx1ZSksCgkvLyAgICAgICAgICAgICBtZXRob2RBcmdzOiBbcG9vbEtleS5pZCwgcG9vbEtleS5wb29sSWRdLAoJLy8gICAgICAgICB9KQoJaXR4bl9iZWdpbgoJaW50IGFwcGwKCWl0eG5fZmllbGQgVHlwZUVudW0KCW1ldGhvZCAiZ2V0UG9vbEFwcElkKHVpbnQ2NCx1aW50NjQpdWludDY0IgoJaXR4bl9maWVsZCBBcHBsaWNhdGlvbkFyZ3MKCgkvLyBjb250cmFjdHMvc3Rha2luZ1Bvb2wuYWxnby50czo4ODUKCS8vIGFwcGxpY2F0aW9uSUQ6IEFwcElELmZyb21VaW50NjQodGhpcy5jcmVhdGluZ1ZhbGlkYXRvckNvbnRyYWN0QXBwSWQudmFsdWUpCglieXRlIDB4NjM3MjY1NjE3NDZmNzI0MTcwNzAgLy8gImNyZWF0b3JBcHAiCglhcHBfZ2xvYmFsX2dldAoJaXR4bl9maWVsZCBBcHBsaWNhdGlvbklECgoJLy8gY29udHJhY3RzL3N0YWtpbmdQb29sLmFsZ28udHM6ODg2CgkvLyBtZXRob2RBcmdzOiBbcG9vbEtleS5pZCwgcG9vbEtleS5wb29sSWRdCglmcmFtZV9kaWcgLTEgLy8gcG9vbEtleTogVmFsaWRhdG9yUG9vbEtleQoJZXh0cmFjdCAwIDgKCWJ0b2kKCWl0b2IKCWl0eG5fZmllbGQgQXBwbGljYXRpb25BcmdzCglmcmFtZV9kaWcgLTEgLy8gcG9vbEtleTogVmFsaWRhdG9yUG9vbEtleQoJZXh0cmFjdCA4IDgKCWJ0b2kKCWl0b2IKCWl0eG5fZmllbGQgQXBwbGljYXRpb25BcmdzCgoJLy8gRmVlIGZpZWxkIG5vdCBzZXQsIGRlZmF1bHRpbmcgdG8gMAoJaW50IDAKCWl0eG5fZmllbGQgRmVlCgoJLy8gU3VibWl0IGlubmVyIHRyYW5zYWN0aW9uCglpdHhuX3N1Ym1pdAoJaXR4biBOdW1Mb2dzCglpbnQgMQoJLQoJaXR4bmFzIExvZ3MKCWV4dHJhY3QgNCAwCglidG9pCglmcmFtZV9idXJ5IDAgLy8gY2FsbGVyUG9vbEFwcElEOiB1aW50NjQKCgkvLyBjb250cmFjdHMvc3Rha2luZ1Bvb2wuYWxnby50czo4ODgKCS8vIGFzc2VydChjYWxsZXJQb29sQXBwSUQgPT09IHBvb2xLZXkucG9vbEFwcElkKQoJZnJhbWVfZGlnIDAgLy8gY2FsbGVyUG9vbEFwcElEOiB1aW50NjQKCWZyYW1lX2RpZyAtMSAvLyBwb29sS2V5OiBWYWxpZGF0b3JQb29sS2V5CglleHRyYWN0IDE2IDgKCWJ0b2kKCT09Cglhc3NlcnQKCgkvLyBjb250cmFjdHMvc3Rha2luZ1Bvb2wuYWxnby50czo4ODkKCS8vIGFzc2VydCh0aGlzLnR4bi5zZW5kZXIgPT09IEFwcElELmZyb21VaW50NjQocG9vbEtleS5wb29sQXBwSWQpLmFkZHJlc3MpCgl0eG4gU2VuZGVyCglmcmFtZV9kaWcgLTEgLy8gcG9vbEtleTogVmFsaWRhdG9yUG9vbEtleQoJZXh0cmFjdCAxNiA4CglidG9pCglhcHBfcGFyYW1zX2dldCBBcHBBZGRyZXNzCglwb3AKCT09Cglhc3NlcnQKCgkvLyBjb250cmFjdHMvc3Rha2luZ1Bvb2wuYWxnby50czo4OTEKCS8vIHJldHVybiBzZW5kTWV0aG9kQ2FsbDx0eXBlb2YgVmFsaWRhdG9yUmVnaXN0cnkucHJvdG90eXBlLnNldFRva2VuUGF5b3V0UmF0aW8+KHsKCS8vICAgICAgICAgICAgIGFwcGxpY2F0aW9uSUQ6IEFwcElELmZyb21VaW50NjQodGhpcy5jcmVhdGluZ1ZhbGlkYXRvckNvbnRyYWN0QXBwSWQudmFsdWUpLAoJLy8gICAgICAgICAgICAgbWV0aG9kQXJnczogW3RoaXMudmFsaWRhdG9ySWQudmFsdWVdLAoJLy8gICAgICAgICB9KTsKCWl0eG5fYmVnaW4KCWludCBhcHBsCglpdHhuX2ZpZWxkIFR5cGVFbnVtCgltZXRob2QgInNldFRva2VuUGF5b3V0UmF0aW8odWludDY0KSh1aW50NjRbMjRdLHVpbnQ2NCkiCglpdHhuX2ZpZWxkIEFwcGxpY2F0aW9uQXJncwoKCS8vIGNvbnRyYWN0cy9zdGFraW5nUG9vbC5hbGdvLnRzOjg5MgoJLy8gYXBwbGljYXRpb25JRDogQXBwSUQuZnJvbVVpbnQ2NCh0aGlzLmNyZWF0aW5nVmFsaWRhdG9yQ29udHJhY3RBcHBJZC52YWx1ZSkKCWJ5dGUgMHg2MzcyNjU2MTc0NmY3MjQxNzA3MCAvLyAiY3JlYXRvckFwcCIKCWFwcF9nbG9iYWxfZ2V0CglpdHhuX2ZpZWxkIEFwcGxpY2F0aW9uSUQKCgkvLyBjb250cmFjdHMvc3Rha2luZ1Bvb2wuYWxnby50czo4OTMKCS8vIG1ldGhvZEFyZ3M6IFt0aGlzLnZhbGlkYXRvcklkLnZhbHVlXQoJYnl0ZSAweDc2NjE2YzY5NjQ2MTc0NmY3MjQ5NjQgLy8gInZhbGlkYXRvcklkIgoJYXBwX2dsb2JhbF9nZXQKCWl0b2IKCWl0eG5fZmllbGQgQXBwbGljYXRpb25BcmdzCgoJLy8gRmVlIGZpZWxkIG5vdCBzZXQsIGRlZmF1bHRpbmcgdG8gMAoJaW50IDAKCWl0eG5fZmllbGQgRmVlCgoJLy8gU3VibWl0IGlubmVyIHRyYW5zYWN0aW9uCglpdHhuX3N1Ym1pdAoJaXR4biBOdW1Mb2dzCglpbnQgMQoJLQoJaXR4bmFzIExvZ3MKCWV4dHJhY3QgNCAwCgoJLy8gc2V0IHRoZSBzdWJyb3V0aW5lIHJldHVybiB2YWx1ZQoJZnJhbWVfYnVyeSAwCglyZXRzdWIKCi8vIGlzT3duZXJPck1hbmFnZXJDYWxsZXIoKTogYm9vbGVhbgppc093bmVyT3JNYW5hZ2VyQ2FsbGVyOgoJcHJvdG8gMCAxCgoJLy8gUHVzaCBlbXB0eSBieXRlcyBhZnRlciB0aGUgZnJhbWUgcG9pbnRlciB0byByZXNlcnZlIHNwYWNlIGZvciBsb2NhbCB2YXJpYWJsZXMKCWJ5dGUgMHgKCgkvLyBjb250cmFjdHMvc3Rha2luZ1Bvb2wuYWxnby50czo4OTgKCS8vIE93bmVyQW5kTWFuYWdlciA9IHNlbmRNZXRob2RDYWxsPHR5cGVvZiBWYWxpZGF0b3JSZWdpc3RyeS5wcm90b3R5cGUuZ2V0VmFsaWRhdG9yT3duZXJBbmRNYW5hZ2VyPih7CgkvLyAgICAgICAgICAgICBhcHBsaWNhdGlvbklEOiBBcHBJRC5mcm9tVWludDY0KHRoaXMuY3JlYXRpbmdWYWxpZGF0b3JDb250cmFjdEFwcElkLnZhbHVlKSwKCS8vICAgICAgICAgICAgIG1ldGhvZEFyZ3M6IFt0aGlzLnZhbGlkYXRvcklkLnZhbHVlXSwKCS8vICAgICAgICAgfSkKCWl0eG5fYmVnaW4KCWludCBhcHBsCglpdHhuX2ZpZWxkIFR5cGVFbnVtCgltZXRob2QgImdldFZhbGlkYXRvck93bmVyQW5kTWFuYWdlcih1aW50NjQpKGFkZHJlc3MsYWRkcmVzcykiCglpdHhuX2ZpZWxkIEFwcGxpY2F0aW9uQXJncwoKCS8vIGNvbnRyYWN0cy9zdGFraW5nUG9vbC5hbGdvLnRzOjg5OQoJLy8gYXBwbGljYXRpb25JRDogQXBwSUQuZnJvbVVpbnQ2NCh0aGlzLmNyZWF0aW5nVmFsaWRhdG9yQ29udHJhY3RBcHBJZC52YWx1ZSkKCWJ5dGUgMHg2MzcyNjU2MTc0NmY3MjQxNzA3MCAvLyAiY3JlYXRvckFwcCIKCWFwcF9nbG9iYWxfZ2V0CglpdHhuX2ZpZWxkIEFwcGxpY2F0aW9uSUQKCgkvLyBjb250cmFjdHMvc3Rha2luZ1Bvb2wuYWxnby50czo5MDAKCS8vIG1ldGhvZEFyZ3M6IFt0aGlzLnZhbGlkYXRvcklkLnZhbHVlXQoJYnl0ZSAweDc2NjE2YzY5NjQ2MTc0NmY3MjQ5NjQgLy8gInZhbGlkYXRvcklkIgoJYXBwX2dsb2JhbF9nZXQKCWl0b2IKCWl0eG5fZmllbGQgQXBwbGljYXRpb25BcmdzCgoJLy8gRmVlIGZpZWxkIG5vdCBzZXQsIGRlZmF1bHRpbmcgdG8gMAoJaW50IDAKCWl0eG5fZmllbGQgRmVlCgoJLy8gU3VibWl0IGlubmVyIHRyYW5zYWN0aW9uCglpdHhuX3N1Ym1pdAoJaXR4biBOdW1Mb2dzCglpbnQgMQoJLQoJaXR4bmFzIExvZ3MKCWV4dHJhY3QgNCAwCglmcmFtZV9idXJ5IDAgLy8gT3duZXJBbmRNYW5hZ2VyOiAoYWRkcmVzcyxhZGRyZXNzKQoKCS8vIGNvbnRyYWN0cy9zdGFraW5nUG9vbC5hbGdvLnRzOjkwMgoJLy8gcmV0dXJuIHRoaXMudHhuLnNlbmRlciA9PT0gT3duZXJBbmRNYW5hZ2VyWzBdIHx8IHRoaXMudHhuLnNlbmRlciA9PT0gT3duZXJBbmRNYW5hZ2VyWzFdOwoJdHhuIFNlbmRlcgoJZnJhbWVfZGlnIDAgLy8gT3duZXJBbmRNYW5hZ2VyOiAoYWRkcmVzcyxhZGRyZXNzKQoJZXh0cmFjdCAwIDMyCgk9PQoJZHVwCglibnogKnNraXBfb3IxCgl0eG4gU2VuZGVyCglmcmFtZV9kaWcgMCAvLyBPd25lckFuZE1hbmFnZXI6IChhZGRyZXNzLGFkZHJlc3MpCglleHRyYWN0IDMyIDMyCgk9PQoJfHwKCipza2lwX29yMToKCS8vIHNldCB0aGUgc3Vicm91dGluZSByZXR1cm4gdmFsdWUKCWZyYW1lX2J1cnkgMAoJcmV0c3ViCgovLyBnZXRFbnRyeVRpbWUoKTogdWludDY0Ci8vCi8vIENhbGN1bGF0ZSB0aGUgZW50cnkgdGltZSBmb3IgY291bnRpbmcgYSBzdGFrZSBhcyBlbnRlcmluZyB0aGUgcG9vbC4KLy8gQWxnb3JhbmQgd29uJ3Qgc2VlIHRoZSBiYWxhbmNlIGluY3JlYXNlIGZvciBBTEdPUkFORF9TVEFLSU5HX0JMT0NLX0RFTEFZIHJvdW5kcywgc28gd2UgYXBwcm94aW1hdGUgaXQuCi8vIFRoZSBlbnRyeSB0aW1lIGlzIGNhbGN1bGF0ZWQgYnkgYWRkaW5nIGFuIGFwcHJveGltYXRlIG51bWJlciBvZiBzZWNvbmRzIGJhc2VkIG9uIGN1cnJlbnQgQVZHIGJsb2NrIHRpbWVzCi8vIHRvIHRoZSBvcmlnaW5hbCBlbnRyeSB0aW1lLiAgVGhpcyBtZWFucyB1c2VycyBkb24ndCBnZXQgcGF5b3V0cyBiYXNlZCBvbiB0aW1lIHRoZWlyIGJhbGFuY2Ugd291bGRuJ3QgaGF2ZQovLyBiZWVuIHNlZW4gYnkgdGhlIG5ldHdvcmsuCi8vCi8vIEByZXR1cm5zIHt1aW50NjR9IC0gVGhlIHVwZGF0ZWQgZW50cnkgdGltZS4KZ2V0RW50cnlUaW1lOgoJcHJvdG8gMCAxCgoJLy8gUHVzaCBlbXB0eSBieXRlcyBhZnRlciB0aGUgZnJhbWUgcG9pbnRlciB0byByZXNlcnZlIHNwYWNlIGZvciBsb2NhbCB2YXJpYWJsZXMKCWJ5dGUgMHgKCgkvLyBjb250cmFjdHMvc3Rha2luZ1Bvb2wuYWxnby50czo5MTcKCS8vIGVudHJ5VGltZSA9IGdsb2JhbHMubGF0ZXN0VGltZXN0YW1wCglnbG9iYWwgTGF0ZXN0VGltZXN0YW1wCglmcmFtZV9idXJ5IDAgLy8gZW50cnlUaW1lOiB1aW50NjQKCgkvLyBjb250cmFjdHMvc3Rha2luZ1Bvb2wuYWxnby50czo5MjAKCS8vIHJldHVybiBlbnRyeVRpbWUgKyAoQUxHT1JBTkRfU1RBS0lOR19CTE9DS19ERUxBWSAqIEFWR19CTE9DS19USU1FX1NFQ1MpIC8gMTA7CglmcmFtZV9kaWcgMCAvLyBlbnRyeVRpbWU6IHVpbnQ2NAoJaW50IDg5NgoJKwoKCS8vIHNldCB0aGUgc3Vicm91dGluZSByZXR1cm4gdmFsdWUKCWZyYW1lX2J1cnkgMAoJcmV0c3ViCgovLyBnZXRGZWVTaW5rKCk6IEFkZHJlc3MKZ2V0RmVlU2luazoKCXByb3RvIDAgMQoKCS8vIGNvbnRyYWN0cy9zdGFraW5nUG9vbC5hbGdvLnRzOjkyNAoJLy8gcmV0dXJuIHRoaXMuZmVlU2lua0FkZHI7CglwdXNoYnl0ZXMgVE1QTF9mZWVTaW5rQWRkcgoJcmV0c3ViCgovLyBhbGdvU2F0dXJhdGlvbkxldmVsKCk6IHVpbnQ2NAovLwovLyBSZXR1cm5zIHRoZSBtYXhpbXVtIGFsbG93ZWQgc3Rha2UgcGVyIHZhbGlkYXRvciBiYXNlZCBvbiBhIHBlcmNlbnRhZ2Ugb2YgYWxsIGN1cnJlbnQgb25saW5lIHN0YWtlIGJlZm9yZQovLyB0aGUgdmFsaWRhdG9yIGlzIGNvbnNpZGVyZWQgc2F0dXJhdGVkIC0gd2hlcmUgcmV3YXJkcyBhcmUgZGltaW5pc2hlZC4KYWxnb1NhdHVyYXRpb25MZXZlbDoKCXByb3RvIDAgMQoKCS8vIFB1c2ggZW1wdHkgYnl0ZXMgYWZ0ZXIgdGhlIGZyYW1lIHBvaW50ZXIgdG8gcmVzZXJ2ZSBzcGFjZSBmb3IgbG9jYWwgdmFyaWFibGVzCglieXRlIDB4CgoJLy8gY29udHJhY3RzL3N0YWtpbmdQb29sLmFsZ28udHM6OTM0CgkvLyBvbmxpbmUgPSB0aGlzLmdldEN1cnJlbnRPbmxpbmVTdGFrZSgpCgljYWxsc3ViIGdldEN1cnJlbnRPbmxpbmVTdGFrZQoJZnJhbWVfYnVyeSAwIC8vIG9ubGluZTogdWludDY0CgoJLy8gY29udHJhY3RzL3N0YWtpbmdQb29sLmFsZ28udHM6OTM2CgkvLyByZXR1cm4gd2lkZVJhdGlvKFtvbmxpbmUsIE1BWF9WQUxJREFUT1JfU09GVF9QQ1RfT0ZfT05MSU5FXzFERUNJTUFMXSwgWzEwMDBdKTsKCWZyYW1lX2RpZyAwIC8vIG9ubGluZTogdWludDY0CglpbnQgMTAwCgltdWx3CglpbnQgMAoJaW50IDEwMDAKCWRpdm1vZHcKCXBvcAoJcG9wCglzd2FwCgkhCglhc3NlcnQKCgkvLyBzZXQgdGhlIHN1YnJvdXRpbmUgcmV0dXJuIHZhbHVlCglmcmFtZV9idXJ5IDAKCXJldHN1YgoKLy8gZ2V0Q3VycmVudE9ubGluZVN0YWtlKCk6IHVpbnQ2NApnZXRDdXJyZW50T25saW5lU3Rha2U6Cglwcm90byAwIDEKCgkvLyBjb250cmFjdHMvc3Rha2luZ1Bvb2wuYWxnby50czo5NDEKCS8vIHJldHVybiAyXzAwMF8wMDBfMDAwXzAwMF8wMDA7CglpbnQgMl8wMDBfMDAwXzAwMF8wMDBfMDAwCglyZXRzdWIKCipjcmVhdGVfTm9PcDoKCW1ldGhvZCAiY3JlYXRlQXBwbGljYXRpb24odWludDY0LHVpbnQ2NCx1aW50NjQsdWludDY0KXZvaWQiCgl0eG5hIEFwcGxpY2F0aW9uQXJncyAwCgltYXRjaCAqYWJpX3JvdXRlX2NyZWF0ZUFwcGxpY2F0aW9uCgllcnIKCipjYWxsX05vT3A6CgltZXRob2QgImdhcygpdm9pZCIKCW1ldGhvZCAiaW5pdFN0b3JhZ2UocGF5KXZvaWQiCgltZXRob2QgImFkZFN0YWtlKHBheSxhZGRyZXNzKXVpbnQ2NCIKCW1ldGhvZCAicmVtb3ZlU3Rha2UodWludDY0KXZvaWQiCgltZXRob2QgImNsYWltVG9rZW5zKCl2b2lkIgoJbWV0aG9kICJnZXRTdGFrZXJJbmZvKGFkZHJlc3MpKGFkZHJlc3MsdWludDY0LHVpbnQ2NCx1aW50NjQsdWludDY0KSIKCW1ldGhvZCAicGF5VG9rZW5SZXdhcmQoYWRkcmVzcyx1aW50NjQsdWludDY0KXZvaWQiCgltZXRob2QgInVwZGF0ZUFsZ29kVmVyKHN0cmluZyl2b2lkIgoJbWV0aG9kICJlcG9jaEJhbGFuY2VVcGRhdGUoKXZvaWQiCgltZXRob2QgImdvT25saW5lKGJ5dGVbXSxieXRlW10sYnl0ZVtdLHVpbnQ2NCx1aW50NjQsdWludDY0KXZvaWQiCgltZXRob2QgImdvT2ZmbGluZSgpdm9pZCIKCW1ldGhvZCAibGlua1RvTkZEKHVpbnQ2NCxzdHJpbmcpdm9pZCIKCW1ldGhvZCAicHJveGllZFNldFRva2VuUGF5b3V0UmF0aW8oKHVpbnQ2NCx1aW50NjQsdWludDY0KSkodWludDY0WzI0XSx1aW50NjQpIgoJdHhuYSBBcHBsaWNhdGlvbkFyZ3MgMAoJbWF0Y2ggKmFiaV9yb3V0ZV9nYXMgKmFiaV9yb3V0ZV9pbml0U3RvcmFnZSAqYWJpX3JvdXRlX2FkZFN0YWtlICphYmlfcm91dGVfcmVtb3ZlU3Rha2UgKmFiaV9yb3V0ZV9jbGFpbVRva2VucyAqYWJpX3JvdXRlX2dldFN0YWtlckluZm8gKmFiaV9yb3V0ZV9wYXlUb2tlblJld2FyZCAqYWJpX3JvdXRlX3VwZGF0ZUFsZ29kVmVyICphYmlfcm91dGVfZXBvY2hCYWxhbmNlVXBkYXRlICphYmlfcm91dGVfZ29PbmxpbmUgKmFiaV9yb3V0ZV9nb09mZmxpbmUgKmFiaV9yb3V0ZV9saW5rVG9ORkQgKmFiaV9yb3V0ZV9wcm94aWVkU2V0VG9rZW5QYXlvdXRSYXRpbwoJZXJyCgoqaW50VG9Bc2NpaToKCXByb3RvIDEgMQoJYnl0ZSAweDMwMzEzMjMzMzQzNTM2MzczODM5IC8vICIwMTIzNDU2Nzg5IgoJZnJhbWVfZGlnIC0xIC8vIGk6IHVpbnQ2NAoJaW50IDEKCWV4dHJhY3QzCglyZXRzdWIKCQoKKml0b2E6Cglwcm90byAxIDEKCWZyYW1lX2RpZyAtMSAvLyBpOiB1aW50NjQKCWludCAwCgk9PQoJYnogKml0b2FfaWZfZW5kCglieXRlIDB4MzAKCXJldHN1YgoKKml0b2FfaWZfZW5kOgoJZnJhbWVfZGlnIC0xIC8vIGk6IHVpbnQ2NAoJaW50IDEwCgkvCglpbnQgMAoJPgoJYnogKml0b2FfdGVybmFyeV9mYWxzZQoJZnJhbWVfZGlnIC0xIC8vIGk6IHVpbnQ2NAoJaW50IDEwCgkvCgljYWxsc3ViICppdG9hCgliICppdG9hX3Rlcm5hcnlfZW5kCgoqaXRvYV90ZXJuYXJ5X2ZhbHNlOgoJYnl0ZSAweCAvLyAiIgoKKml0b2FfdGVybmFyeV9lbmQ6CglmcmFtZV9kaWcgLTEgLy8gaTogdWludDY0CglpbnQgMTAKCSUKCWNhbGxzdWIgKmludFRvQXNjaWkKCWNvbmNhdAoJcmV0c3Vi", + "clear": "I3ByYWdtYSB2ZXJzaW9uIDEw" + }, + "contract": { + "name": "StakingPool", + "desc": "", + "methods": [ + { + "name": "createApplication", + "desc": "Initialize the staking pool w/ owner and manager, but can only be created by the validator contract.", + "args": [ + { + "name": "creatingContractId", + "type": "uint64", + "desc": "id of contract that constructed us - the validator application (single global instance)" + }, + { + "name": "validatorId", + "type": "uint64", + "desc": "id of validator we're a staking pool of" + }, + { + "name": "poolId", + "type": "uint64", + "desc": "which pool id are we" + }, + { + "name": "minEntryStake", + "type": "uint64", + "desc": "minimum amount to be in pool, but also minimum amount balance can't go below (without removing all!)" + } + ], + "returns": { + "type": "void" + } + }, + { + "name": "gas", + "desc": "gas is a dummy no-op call that can be used to pool-up resource references and opcode cost", + "args": [], + "returns": { + "type": "void" + } + }, + { + "name": "initStorage", + "desc": "Called after we're created and then funded so we can create our large stakers ledger storageCaller has to get MBR amounts from ValidatorRegistry to know how much to fund us to cover the box storage costIf this is pool 1 AND the validator has specified a reward token, opt-in to that tokenso that the validator can seed the pool with future rewards of that token.", + "args": [ + { + "name": "mbrPayment", + "type": "pay", + "desc": "payment from caller which covers mbr increase of new staking pools' storage" + } + ], + "returns": { + "type": "void" + } + }, + { + "name": "addStake", + "desc": "Adds stake to the given account.Can ONLY be called by the validator contract that created usMust receive payment from the validator contract for amount being staked.", + "args": [ + { + "name": "stakedAmountPayment", + "type": "pay", + "desc": "prior payment coming from validator contract to us on behalf of staker." + }, + { + "name": "staker", + "type": "address", + "desc": "The account adding new stake" + } + ], + "returns": { + "type": "uint64", + "desc": "{uint64}new 'entry time' in seconds of stake add." + } + }, + { + "name": "removeStake", + "desc": "Removes stake on behalf of caller (removing own stake). If any token rewards exist, those are always sent infull. Also notifies the validator contract for this pools validator of the staker / balance changes.", + "args": [ + { + "name": "amountToUnstake", + "type": "uint64", + "desc": "The amount of stake to be removed. Specify 0 to remove all stake." + } + ], + "returns": { + "type": "void" + } + }, + { + "name": "claimTokens", + "desc": "Claims all the available reward tokens a staker has available, sending their entire balance to the staker frompool 1 (either directly, or via validator->pool1 to pay it out)Also notifies the validator contract for this pools validator of the staker / balance changes.", + "args": [], + "returns": { + "type": "void" + } + }, + { + "name": "getStakerInfo", + "desc": "Retrieves the staked information for a given staker.", + "args": [ + { + "name": "staker", + "type": "address", + "desc": "The address of the staker." + } + ], + "returns": { + "type": "(address,uint64,uint64,uint64,uint64)", + "desc": "{StakedInfo}- The staked information for the given staker." + } + }, + { + "name": "payTokenReward", + "desc": "[Internal protocol method] Remove a specified amount of 'community token' rewards for a staker.This can ONLY be called by our validator and only if we're pool 1 - with the token.", + "args": [ + { + "name": "staker", + "type": "address", + "desc": "the staker account to send rewards to" + }, + { + "name": "rewardToken", + "type": "uint64", + "desc": "id of reward token (to avoid re-entrancy in calling validator back to get id)" + }, + { + "name": "amountToSend", + "type": "uint64", + "desc": "amount to send the staker (there is significant trust here(!) - also why only validator can call us" + } + ], + "returns": { + "type": "void" + } + }, + { + "name": "updateAlgodVer", + "desc": "Update the (honor system) algod version for the node associated to this pool. The node management daemonshould compare its current nodes version to the version stored in global state, updating when different.The reti node daemon composes its own version string using format:{major}.{minor}.{build}{branch}[{commit hash}],ie: 3.22.0 rel/stable [6b508975][ ONLY OWNER OR MANAGER CAN CALL ]", + "args": [ + { + "name": "algodVer", + "type": "string", + "desc": "string representing the algorand node daemon version (reti node daemon composes its own meta version)" + } + ], + "returns": { + "type": "void" + } + }, + { + "name": "epochBalanceUpdate", + "desc": "Updates the balance of stakers in the pool based on the received 'rewards' (current balance vs known staked balance)stakers outstanding balance is adjusted based on their % of stake and time in the current epoch - so that balancecompounds over time and staker can remove that amount at will.The validator is paid their percentage each epoch payout.Note: ANYONE can call this.", + "args": [], + "returns": { + "type": "void" + } + }, + { + "name": "goOnline", + "desc": "Registers a staking pool key online against a participation key.[ ONLY OWNER OR MANAGER CAN CALL ]", + "args": [ + { + "name": "votePK", + "type": "byte[]", + "desc": "The vote public key." + }, + { + "name": "selectionPK", + "type": "byte[]", + "desc": "The selection public key." + }, + { + "name": "stateProofPK", + "type": "byte[]", + "desc": "The state proof public key." + }, + { + "name": "voteFirst", + "type": "uint64", + "desc": "The first vote index." + }, + { + "name": "voteLast", + "type": "uint64", + "desc": "The last vote index." + }, + { + "name": "voteKeyDilution", + "type": "uint64", + "desc": "The vote key dilution value." + } + ], + "returns": { + "type": "void" + } + }, + { + "name": "goOffline", + "desc": "Marks a staking pool key OFFLINE.[ ONLY OWNER OR MANAGER CAN CALL ]", + "args": [], + "returns": { + "type": "void" + } + }, + { + "name": "linkToNFD", + "args": [ + { + "name": "nfdAppId", + "type": "uint64" + }, + { + "name": "nfdName", + "type": "string" + } + ], + "returns": { + "type": "void" + } + }, + { + "name": "proxiedSetTokenPayoutRatio", + "desc": "proxiedSetTokenPayoutRatio is meant to be called by pools != 1 - calling US, pool #1We need to verify that we are in fact being called by another of OUR pools (not us)and then we'll call the validator on their behalf to update the token payouts", + "args": [ + { + "name": "poolKey", + "type": "(uint64,uint64,uint64)", + "desc": "ValidatorPoolKey tuple" + } + ], + "returns": { + "type": "(uint64[24],uint64)" + } + } + ] + } +} \ No newline at end of file diff --git a/contracts/contracts/artifacts/StakingPool.arc4.json b/contracts/contracts/artifacts/StakingPool.arc4.json new file mode 100644 index 00000000..fab67f4d --- /dev/null +++ b/contracts/contracts/artifacts/StakingPool.arc4.json @@ -0,0 +1,237 @@ +{ + "name": "StakingPool", + "desc": "", + "methods": [ + { + "name": "createApplication", + "desc": "Initialize the staking pool w/ owner and manager, but can only be created by the validator contract.", + "args": [ + { + "name": "creatingContractId", + "type": "uint64", + "desc": "id of contract that constructed us - the validator application (single global instance)" + }, + { + "name": "validatorId", + "type": "uint64", + "desc": "id of validator we're a staking pool of" + }, + { + "name": "poolId", + "type": "uint64", + "desc": "which pool id are we" + }, + { + "name": "minEntryStake", + "type": "uint64", + "desc": "minimum amount to be in pool, but also minimum amount balance can't go below (without removing all!)" + } + ], + "returns": { + "type": "void" + } + }, + { + "name": "gas", + "desc": "gas is a dummy no-op call that can be used to pool-up resource references and opcode cost", + "args": [], + "returns": { + "type": "void" + } + }, + { + "name": "initStorage", + "desc": "Called after we're created and then funded so we can create our large stakers ledger storageCaller has to get MBR amounts from ValidatorRegistry to know how much to fund us to cover the box storage costIf this is pool 1 AND the validator has specified a reward token, opt-in to that tokenso that the validator can seed the pool with future rewards of that token.", + "args": [ + { + "name": "mbrPayment", + "type": "pay", + "desc": "payment from caller which covers mbr increase of new staking pools' storage" + } + ], + "returns": { + "type": "void" + } + }, + { + "name": "addStake", + "desc": "Adds stake to the given account.Can ONLY be called by the validator contract that created usMust receive payment from the validator contract for amount being staked.", + "args": [ + { + "name": "stakedAmountPayment", + "type": "pay", + "desc": "prior payment coming from validator contract to us on behalf of staker." + }, + { + "name": "staker", + "type": "address", + "desc": "The account adding new stake" + } + ], + "returns": { + "type": "uint64", + "desc": "{uint64}new 'entry time' in seconds of stake add." + } + }, + { + "name": "removeStake", + "desc": "Removes stake on behalf of caller (removing own stake). If any token rewards exist, those are always sent infull. Also notifies the validator contract for this pools validator of the staker / balance changes.", + "args": [ + { + "name": "amountToUnstake", + "type": "uint64", + "desc": "The amount of stake to be removed. Specify 0 to remove all stake." + } + ], + "returns": { + "type": "void" + } + }, + { + "name": "claimTokens", + "desc": "Claims all the available reward tokens a staker has available, sending their entire balance to the staker frompool 1 (either directly, or via validator->pool1 to pay it out)Also notifies the validator contract for this pools validator of the staker / balance changes.", + "args": [], + "returns": { + "type": "void" + } + }, + { + "name": "getStakerInfo", + "desc": "Retrieves the staked information for a given staker.", + "args": [ + { + "name": "staker", + "type": "address", + "desc": "The address of the staker." + } + ], + "returns": { + "type": "(address,uint64,uint64,uint64,uint64)", + "desc": "{StakedInfo}- The staked information for the given staker." + } + }, + { + "name": "payTokenReward", + "desc": "[Internal protocol method] Remove a specified amount of 'community token' rewards for a staker.This can ONLY be called by our validator and only if we're pool 1 - with the token.", + "args": [ + { + "name": "staker", + "type": "address", + "desc": "the staker account to send rewards to" + }, + { + "name": "rewardToken", + "type": "uint64", + "desc": "id of reward token (to avoid re-entrancy in calling validator back to get id)" + }, + { + "name": "amountToSend", + "type": "uint64", + "desc": "amount to send the staker (there is significant trust here(!) - also why only validator can call us" + } + ], + "returns": { + "type": "void" + } + }, + { + "name": "updateAlgodVer", + "desc": "Update the (honor system) algod version for the node associated to this pool. The node management daemonshould compare its current nodes version to the version stored in global state, updating when different.The reti node daemon composes its own version string using format:{major}.{minor}.{build}{branch}[{commit hash}],ie: 3.22.0 rel/stable [6b508975][ ONLY OWNER OR MANAGER CAN CALL ]", + "args": [ + { + "name": "algodVer", + "type": "string", + "desc": "string representing the algorand node daemon version (reti node daemon composes its own meta version)" + } + ], + "returns": { + "type": "void" + } + }, + { + "name": "epochBalanceUpdate", + "desc": "Updates the balance of stakers in the pool based on the received 'rewards' (current balance vs known staked balance)stakers outstanding balance is adjusted based on their % of stake and time in the current epoch - so that balancecompounds over time and staker can remove that amount at will.The validator is paid their percentage each epoch payout.Note: ANYONE can call this.", + "args": [], + "returns": { + "type": "void" + } + }, + { + "name": "goOnline", + "desc": "Registers a staking pool key online against a participation key.[ ONLY OWNER OR MANAGER CAN CALL ]", + "args": [ + { + "name": "votePK", + "type": "byte[]", + "desc": "The vote public key." + }, + { + "name": "selectionPK", + "type": "byte[]", + "desc": "The selection public key." + }, + { + "name": "stateProofPK", + "type": "byte[]", + "desc": "The state proof public key." + }, + { + "name": "voteFirst", + "type": "uint64", + "desc": "The first vote index." + }, + { + "name": "voteLast", + "type": "uint64", + "desc": "The last vote index." + }, + { + "name": "voteKeyDilution", + "type": "uint64", + "desc": "The vote key dilution value." + } + ], + "returns": { + "type": "void" + } + }, + { + "name": "goOffline", + "desc": "Marks a staking pool key OFFLINE.[ ONLY OWNER OR MANAGER CAN CALL ]", + "args": [], + "returns": { + "type": "void" + } + }, + { + "name": "linkToNFD", + "args": [ + { + "name": "nfdAppId", + "type": "uint64" + }, + { + "name": "nfdName", + "type": "string" + } + ], + "returns": { + "type": "void" + } + }, + { + "name": "proxiedSetTokenPayoutRatio", + "desc": "proxiedSetTokenPayoutRatio is meant to be called by pools != 1 - calling US, pool #1We need to verify that we are in fact being called by another of OUR pools (not us)and then we'll call the validator on their behalf to update the token payouts", + "args": [ + { + "name": "poolKey", + "type": "(uint64,uint64,uint64)", + "desc": "ValidatorPoolKey tuple" + } + ], + "returns": { + "type": "(uint64[24],uint64)" + } + } + ] +} \ No newline at end of file diff --git a/contracts/contracts/artifacts/StakingPool.clear.teal b/contracts/contracts/artifacts/StakingPool.clear.teal new file mode 100644 index 00000000..e9f1d65b --- /dev/null +++ b/contracts/contracts/artifacts/StakingPool.clear.teal @@ -0,0 +1 @@ +#pragma version 10 \ No newline at end of file diff --git a/contracts/contracts/artifacts/StakingPool.src_map.json b/contracts/contracts/artifacts/StakingPool.src_map.json new file mode 100644 index 00000000..f803e03e --- /dev/null +++ b/contracts/contracts/artifacts/StakingPool.src_map.json @@ -0,0 +1,16422 @@ +[ + { + "teal": 1, + "source": 39, + "pc": [ + 0, + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9, + 10, + 11, + 12, + 13, + 14, + 15, + 16, + 17, + 18, + 19, + 20, + 21, + 22, + 23, + 24, + 25, + 26, + 27, + 28, + 29, + 30, + 31, + 32, + 33, + 34, + 35, + 36, + 37, + 38, + 39, + 40, + 41, + 42, + 43, + 44, + 45, + 46, + 47, + 48, + 49, + 50, + 51, + 52, + 53, + 54, + 55, + 56, + 57, + 58, + 59, + 60, + 61, + 62, + 63, + 64, + 65, + 66, + 67, + 68, + 69, + 70, + 71, + 72, + 73, + 74, + 75, + 76, + 77, + 78, + 79, + 80, + 81, + 82, + 83, + 84, + 85, + 86, + 87, + 88, + 89, + 90, + 91, + 92, + 93, + 94, + 95, + 96, + 97, + 98, + 99, + 100, + 101, + 102, + 103, + 104, + 105, + 106, + 107, + 108, + 109, + 110, + 111, + 112, + 113, + 114, + 115, + 116, + 117, + 118, + 119, + 120, + 121, + 122, + 123, + 124, + 125, + 126, + 127, + 128, + 129, + 130, + 131, + 132, + 133, + 134, + 135, + 136, + 137, + 138, + 139, + 140, + 141, + 142, + 143, + 144, + 145, + 146, + 147, + 148, + 149, + 150, + 151, + 152, + 153, + 154, + 155, + 156, + 157, + 158, + 159, + 160, + 161, + 162, + 163, + 164, + 165, + 166, + 167, + 168, + 169, + 170, + 171, + 172, + 173, + 174, + 175 + ] + }, + { + "teal": 13, + "source": 39, + "pc": [ + 176, + 177 + ] + }, + { + "teal": 14, + "source": 39, + "pc": [ + 178 + ] + }, + { + "teal": 15, + "source": 39, + "pc": [ + 179 + ] + }, + { + "teal": 16, + "source": 39, + "pc": [ + 180 + ] + }, + { + "teal": 17, + "source": 39, + "pc": [ + 181, + 182 + ] + }, + { + "teal": 18, + "source": 39, + "pc": [ + 183 + ] + }, + { + "teal": 19, + "source": 39, + "pc": [ + 184, + 185, + 186, + 187, + 188, + 189, + 190, + 191, + 192, + 193, + 194, + 195, + 196, + 197, + 198, + 199, + 200, + 201, + 202, + 203, + 204, + 205, + 206, + 207, + 208, + 209 + ] + }, + { + "teal": 22, + "source": 39, + "pc": [ + 210 + ] + }, + { + "teal": 27, + "source": 85, + "pc": [ + 211, + 212, + 213 + ] + }, + { + "teal": 28, + "source": 85, + "pc": [ + 214 + ] + }, + { + "teal": 31, + "source": 85, + "pc": [ + 215, + 216, + 217 + ] + }, + { + "teal": 32, + "source": 85, + "pc": [ + 218 + ] + }, + { + "teal": 35, + "source": 85, + "pc": [ + 219, + 220, + 221 + ] + }, + { + "teal": 36, + "source": 85, + "pc": [ + 222 + ] + }, + { + "teal": 39, + "source": 85, + "pc": [ + 223, + 224, + 225 + ] + }, + { + "teal": 40, + "source": 85, + "pc": [ + 226 + ] + }, + { + "teal": 43, + "source": 85, + "pc": [ + 227, + 228, + 229 + ] + }, + { + "teal": 44, + "source": 85, + "pc": [ + 230 + ] + }, + { + "teal": 45, + "source": 85, + "pc": [ + 231 + ] + }, + { + "teal": 55, + "source": 85, + "pc": [ + 232, + 233, + 234 + ] + }, + { + "teal": 60, + "source": 86, + "pc": [ + 235, + 236 + ] + }, + { + "teal": 61, + "source": 86, + "pc": [ + 237 + ] + }, + { + "teal": 62, + "source": 86, + "pc": [ + 238 + ] + }, + { + "teal": 63, + "source": 86, + "pc": [ + 239, + 240, + 241 + ] + }, + { + "teal": 68, + "source": 88, + "pc": [ + 242, + 243 + ] + }, + { + "teal": 69, + "source": 88, + "pc": [ + 244 + ] + }, + { + "teal": 70, + "source": 88, + "pc": [ + 245 + ] + }, + { + "teal": 71, + "source": 88, + "pc": [ + 246 + ] + }, + { + "teal": 75, + "source": 89, + "pc": [ + 247, + 248 + ] + }, + { + "teal": 76, + "source": 89, + "pc": [ + 249 + ] + }, + { + "teal": 77, + "source": 89, + "pc": [ + 250 + ] + }, + { + "teal": 78, + "source": 89, + "pc": [ + 251 + ] + }, + { + "teal": 79, + "source": 86, + "pc": [ + 252, + 253, + 254 + ] + }, + { + "teal": 84, + "source": 91, + "pc": [ + 255, + 256 + ] + }, + { + "teal": 85, + "source": 91, + "pc": [ + 257 + ] + }, + { + "teal": 86, + "source": 91, + "pc": [ + 258 + ] + }, + { + "teal": 87, + "source": 91, + "pc": [ + 259 + ] + }, + { + "teal": 91, + "source": 92, + "pc": [ + 260, + 261 + ] + }, + { + "teal": 92, + "source": 92, + "pc": [ + 262 + ] + }, + { + "teal": 93, + "source": 92, + "pc": [ + 263 + ] + }, + { + "teal": 94, + "source": 92, + "pc": [ + 264 + ] + }, + { + "teal": 99, + "source": 94, + "pc": [ + 265, + 266 + ] + }, + { + "teal": 100, + "source": 94, + "pc": [ + 267, + 268 + ] + }, + { + "teal": 101, + "source": 94, + "pc": [ + 269 + ] + }, + { + "teal": 102, + "source": 94, + "pc": [ + 270 + ] + }, + { + "teal": 106, + "source": 95, + "pc": [ + 271 + ] + }, + { + "teal": 107, + "source": 95, + "pc": [ + 272, + 273 + ] + }, + { + "teal": 108, + "source": 95, + "pc": [ + 274 + ] + }, + { + "teal": 112, + "source": 96, + "pc": [ + 275 + ] + }, + { + "teal": 113, + "source": 96, + "pc": [ + 276, + 277 + ] + }, + { + "teal": 114, + "source": 96, + "pc": [ + 278 + ] + }, + { + "teal": 118, + "source": 97, + "pc": [ + 279 + ] + }, + { + "teal": 119, + "source": 97, + "pc": [ + 280, + 281 + ] + }, + { + "teal": 120, + "source": 97, + "pc": [ + 282 + ] + }, + { + "teal": 124, + "source": 98, + "pc": [ + 283, + 284 + ] + }, + { + "teal": 125, + "source": 98, + "pc": [ + 285 + ] + }, + { + "teal": 126, + "source": 98, + "pc": [ + 286 + ] + }, + { + "teal": 130, + "source": 99, + "pc": [ + 287, + 288 + ] + }, + { + "teal": 131, + "source": 99, + "pc": [ + 289 + ] + }, + { + "teal": 132, + "source": 99, + "pc": [ + 290 + ] + }, + { + "teal": 136, + "source": 100, + "pc": [ + 291, + 292 + ] + }, + { + "teal": 137, + "source": 100, + "pc": [ + 293, + 294 + ] + }, + { + "teal": 138, + "source": 100, + "pc": [ + 295 + ] + }, + { + "teal": 142, + "source": 101, + "pc": [ + 296, + 297 + ] + }, + { + "teal": 143, + "source": 101, + "pc": [ + 298, + 299 + ] + }, + { + "teal": 144, + "source": 101, + "pc": [ + 300 + ] + }, + { + "teal": 148, + "source": 102, + "pc": [ + 301, + 302 + ] + }, + { + "teal": 149, + "source": 102, + "pc": [ + 303 + ] + }, + { + "teal": 150, + "source": 102, + "pc": [ + 304 + ] + }, + { + "teal": 151, + "source": 85, + "pc": [ + 305 + ] + }, + { + "teal": 156, + "source": 108, + "pc": [ + 306, + 307, + 308 + ] + }, + { + "teal": 157, + "source": 108, + "pc": [ + 309 + ] + }, + { + "teal": 158, + "source": 108, + "pc": [ + 310 + ] + }, + { + "teal": 164, + "source": 108, + "pc": [ + 311, + 312, + 313 + ] + }, + { + "teal": 165, + "source": 108, + "pc": [ + 314 + ] + }, + { + "teal": 169, + "source": 110, + "pc": [ + 315, + 316, + 317 + ] + }, + { + "teal": 172, + "source": 110, + "pc": [ + 318, + 319 + ] + }, + { + "teal": 176, + "source": 119, + "pc": [ + 320, + 321 + ] + }, + { + "teal": 177, + "source": 119, + "pc": [ + 322, + 323 + ] + }, + { + "teal": 181, + "source": 120, + "pc": [ + 324, + 325 + ] + }, + { + "teal": 182, + "source": 120, + "pc": [ + 326, + 327 + ] + }, + { + "teal": 183, + "source": 120, + "pc": [ + 328, + 329 + ] + }, + { + "teal": 184, + "source": 120, + "pc": [ + 330 + ] + }, + { + "teal": 185, + "source": 120, + "pc": [ + 331 + ] + }, + { + "teal": 186, + "source": 120, + "pc": [ + 332, + 333 + ] + }, + { + "teal": 190, + "source": 121, + "pc": [ + 334, + 335 + ] + }, + { + "teal": 191, + "source": 121, + "pc": [ + 336, + 337 + ] + }, + { + "teal": 192, + "source": 121, + "pc": [ + 338, + 339 + ] + }, + { + "teal": 193, + "source": 121, + "pc": [ + 340 + ] + }, + { + "teal": 194, + "source": 121, + "pc": [ + 341 + ] + }, + { + "teal": 195, + "source": 121, + "pc": [ + 342, + 343 + ] + }, + { + "teal": 199, + "source": 122, + "pc": [ + 344, + 345 + ] + }, + { + "teal": 200, + "source": 122, + "pc": [ + 346, + 347 + ] + }, + { + "teal": 201, + "source": 122, + "pc": [ + 348, + 349 + ] + }, + { + "teal": 202, + "source": 122, + "pc": [ + 350 + ] + }, + { + "teal": 203, + "source": 122, + "pc": [ + 351 + ] + }, + { + "teal": 204, + "source": 122, + "pc": [ + 352, + 353 + ] + }, + { + "teal": 208, + "source": 123, + "pc": [ + 354, + 355 + ] + }, + { + "teal": 209, + "source": 123, + "pc": [ + 356, + 357 + ] + }, + { + "teal": 210, + "source": 123, + "pc": [ + 358, + 359 + ] + }, + { + "teal": 211, + "source": 123, + "pc": [ + 360 + ] + }, + { + "teal": 212, + "source": 123, + "pc": [ + 361 + ] + }, + { + "teal": 213, + "source": 123, + "pc": [ + 362, + 363 + ] + }, + { + "teal": 217, + "source": 124, + "pc": [ + 364, + 365 + ] + }, + { + "teal": 218, + "source": 124, + "pc": [ + 366, + 367 + ] + }, + { + "teal": 219, + "source": 124, + "pc": [ + 368, + 369 + ] + }, + { + "teal": 220, + "source": 124, + "pc": [ + 370 + ] + }, + { + "teal": 221, + "source": 124, + "pc": [ + 371 + ] + }, + { + "teal": 222, + "source": 124, + "pc": [ + 372, + 373 + ] + }, + { + "teal": 226, + "source": 125, + "pc": [ + 374, + 375 + ] + }, + { + "teal": 227, + "source": 125, + "pc": [ + 376, + 377 + ] + }, + { + "teal": 228, + "source": 125, + "pc": [ + 378, + 379 + ] + }, + { + "teal": 229, + "source": 125, + "pc": [ + 380 + ] + }, + { + "teal": 230, + "source": 125, + "pc": [ + 381 + ] + }, + { + "teal": 231, + "source": 125, + "pc": [ + 382, + 383 + ] + }, + { + "teal": 235, + "source": 126, + "pc": [ + 384, + 385 + ] + }, + { + "teal": 236, + "source": 126, + "pc": [ + 386, + 387 + ] + }, + { + "teal": 237, + "source": 126, + "pc": [ + 388, + 389 + ] + }, + { + "teal": 238, + "source": 126, + "pc": [ + 390 + ] + }, + { + "teal": 239, + "source": 126, + "pc": [ + 391 + ] + }, + { + "teal": 240, + "source": 126, + "pc": [ + 392, + 393 + ] + }, + { + "teal": 244, + "source": 127, + "pc": [ + 394, + 395 + ] + }, + { + "teal": 247, + "source": 127, + "pc": [ + 396, + 397 + ] + }, + { + "teal": 248, + "source": 127, + "pc": [ + 398 + ] + }, + { + "teal": 252, + "source": 130, + "pc": [ + 399, + 400, + 401 + ] + }, + { + "teal": 256, + "source": 134, + "pc": [ + 402, + 403, + 404 + ] + }, + { + "teal": 257, + "source": 134, + "pc": [ + 405, + 406 + ] + }, + { + "teal": 258, + "source": 134, + "pc": [ + 407, + 408 + ] + }, + { + "teal": 259, + "source": 134, + "pc": [ + 409 + ] + }, + { + "teal": 260, + "source": 134, + "pc": [ + 410 + ] + }, + { + "teal": 261, + "source": 134, + "pc": [ + 411 + ] + }, + { + "teal": 266, + "source": 144, + "pc": [ + 412, + 413 + ] + }, + { + "teal": 267, + "source": 144, + "pc": [ + 414 + ] + }, + { + "teal": 268, + "source": 144, + "pc": [ + 415 + ] + }, + { + "teal": 269, + "source": 144, + "pc": [ + 416 + ] + }, + { + "teal": 270, + "source": 144, + "pc": [ + 417, + 418 + ] + }, + { + "teal": 271, + "source": 144, + "pc": [ + 419 + ] + }, + { + "teal": 272, + "source": 144, + "pc": [ + 420 + ] + }, + { + "teal": 273, + "source": 144, + "pc": [ + 421 + ] + }, + { + "teal": 276, + "source": 144, + "pc": [ + 422, + 423, + 424 + ] + }, + { + "teal": 277, + "source": 144, + "pc": [ + 425 + ] + }, + { + "teal": 278, + "source": 144, + "pc": [ + 426 + ] + }, + { + "teal": 288, + "source": 144, + "pc": [ + 427, + 428, + 429 + ] + }, + { + "teal": 291, + "source": 144, + "pc": [ + 430, + 431 + ] + }, + { + "teal": 292, + "source": 144, + "pc": [ + 432, + 433 + ] + }, + { + "teal": 296, + "source": 145, + "pc": [ + 434 + ] + }, + { + "teal": 297, + "source": 145, + "pc": [ + 435 + ] + }, + { + "teal": 298, + "source": 145, + "pc": [ + 436 + ] + }, + { + "teal": 299, + "source": 145, + "pc": [ + 437 + ] + }, + { + "teal": 300, + "source": 145, + "pc": [ + 438 + ] + }, + { + "teal": 303, + "source": 145, + "pc": [ + 439 + ] + }, + { + "teal": 310, + "source": 148, + "pc": [ + 440 + ] + }, + { + "teal": 311, + "source": 148, + "pc": [ + 441 + ] + }, + { + "teal": 312, + "source": 148, + "pc": [ + 442, + 443 + ] + }, + { + "teal": 313, + "source": 148, + "pc": [ + 444, + 445 + ] + }, + { + "teal": 314, + "source": 148, + "pc": [ + 446, + 447 + ] + }, + { + "teal": 318, + "source": 149, + "pc": [ + 448 + ] + }, + { + "teal": 319, + "source": 149, + "pc": [ + 449 + ] + }, + { + "teal": 320, + "source": 149, + "pc": [ + 450, + 451 + ] + }, + { + "teal": 324, + "source": 150, + "pc": [ + 452 + ] + }, + { + "teal": 325, + "source": 150, + "pc": [ + 453 + ] + }, + { + "teal": 326, + "source": 150, + "pc": [ + 454 + ] + }, + { + "teal": 327, + "source": 150, + "pc": [ + 455, + 456 + ] + }, + { + "teal": 330, + "source": 148, + "pc": [ + 457 + ] + }, + { + "teal": 331, + "source": 148, + "pc": [ + 458, + 459 + ] + }, + { + "teal": 334, + "source": 148, + "pc": [ + 460 + ] + }, + { + "teal": 335, + "source": 148, + "pc": [ + 461, + 462 + ] + }, + { + "teal": 336, + "source": 148, + "pc": [ + 463 + ] + }, + { + "teal": 337, + "source": 148, + "pc": [ + 464 + ] + }, + { + "teal": 338, + "source": 148, + "pc": [ + 465, + 466 + ] + }, + { + "teal": 339, + "source": 148, + "pc": [ + 467, + 468, + 469 + ] + }, + { + "teal": 340, + "source": 148, + "pc": [ + 470, + 471 + ] + }, + { + "teal": 344, + "source": 152, + "pc": [ + 472, + 473 + ] + }, + { + "teal": 345, + "source": 152, + "pc": [ + 474, + 475, + 476 + ] + }, + { + "teal": 346, + "source": 152, + "pc": [ + 477 + ] + }, + { + "teal": 347, + "source": 152, + "pc": [ + 478 + ] + }, + { + "teal": 348, + "source": 152, + "pc": [ + 479 + ] + }, + { + "teal": 349, + "source": 152, + "pc": [ + 480, + 481 + ] + }, + { + "teal": 353, + "source": 153, + "pc": [ + 482, + 483 + ] + }, + { + "teal": 354, + "source": 153, + "pc": [ + 484 + ] + }, + { + "teal": 355, + "source": 153, + "pc": [ + 485, + 486, + 487 + ] + }, + { + "teal": 356, + "source": 153, + "pc": [ + 488 + ] + }, + { + "teal": 357, + "source": 153, + "pc": [ + 489 + ] + }, + { + "teal": 358, + "source": 153, + "pc": [ + 490 + ] + }, + { + "teal": 359, + "source": 153, + "pc": [ + 491 + ] + }, + { + "teal": 360, + "source": 153, + "pc": [ + 492 + ] + }, + { + "teal": 363, + "source": 153, + "pc": [ + 493, + 494, + 495 + ] + }, + { + "teal": 364, + "source": 153, + "pc": [ + 496, + 497 + ] + }, + { + "teal": 365, + "source": 153, + "pc": [ + 498, + 499, + 500 + ] + }, + { + "teal": 368, + "source": 153, + "pc": [ + 501 + ] + }, + { + "teal": 371, + "source": 153, + "pc": [ + 502, + 503 + ] + }, + { + "teal": 378, + "source": 155, + "pc": [ + 504, + 505 + ] + }, + { + "teal": 379, + "source": 156, + "pc": [ + 506, + 507 + ] + }, + { + "teal": 380, + "source": 155, + "pc": [ + 508 + ] + }, + { + "teal": 381, + "source": 157, + "pc": [ + 509, + 510, + 511 + ] + }, + { + "teal": 382, + "source": 157, + "pc": [ + 512, + 513, + 514 + ] + }, + { + "teal": 383, + "source": 156, + "pc": [ + 515 + ] + }, + { + "teal": 384, + "source": 154, + "pc": [ + 516, + 517 + ] + }, + { + "teal": 389, + "source": 160, + "pc": [ + 518, + 519 + ] + }, + { + "teal": 390, + "source": 160, + "pc": [ + 520, + 521 + ] + }, + { + "teal": 391, + "source": 160, + "pc": [ + 522, + 523 + ] + }, + { + "teal": 392, + "source": 160, + "pc": [ + 524 + ] + }, + { + "teal": 393, + "source": 160, + "pc": [ + 525 + ] + }, + { + "teal": 397, + "source": 161, + "pc": [ + 526 + ] + }, + { + "teal": 398, + "source": 161, + "pc": [ + 527, + 528, + 529 + ] + }, + { + "teal": 399, + "source": 161, + "pc": [ + 530 + ] + }, + { + "teal": 400, + "source": 161, + "pc": [ + 531 + ] + }, + { + "teal": 405, + "source": 163, + "pc": [ + 532, + 533 + ] + }, + { + "teal": 406, + "source": 163, + "pc": [ + 534 + ] + }, + { + "teal": 407, + "source": 163, + "pc": [ + 535, + 536, + 537 + ] + }, + { + "teal": 408, + "source": 163, + "pc": [ + 538 + ] + }, + { + "teal": 409, + "source": 163, + "pc": [ + 539 + ] + }, + { + "teal": 410, + "source": 163, + "pc": [ + 540 + ] + }, + { + "teal": 411, + "source": 163, + "pc": [ + 541 + ] + }, + { + "teal": 412, + "source": 163, + "pc": [ + 542 + ] + }, + { + "teal": 415, + "source": 163, + "pc": [ + 543, + 544, + 545 + ] + }, + { + "teal": 424, + "source": 165, + "pc": [ + 546 + ] + }, + { + "teal": 425, + "source": 165, + "pc": [ + 547, + 548 + ] + }, + { + "teal": 426, + "source": 165, + "pc": [ + 549, + 550 + ] + }, + { + "teal": 430, + "source": 166, + "pc": [ + 551, + 552 + ] + }, + { + "teal": 431, + "source": 166, + "pc": [ + 553, + 554, + 555 + ] + }, + { + "teal": 432, + "source": 166, + "pc": [ + 556 + ] + }, + { + "teal": 433, + "source": 166, + "pc": [ + 557, + 558 + ] + }, + { + "teal": 437, + "source": 167, + "pc": [ + 559, + 560 + ] + }, + { + "teal": 438, + "source": 167, + "pc": [ + 561, + 562 + ] + }, + { + "teal": 442, + "source": 168, + "pc": [ + 563 + ] + }, + { + "teal": 443, + "source": 168, + "pc": [ + 564, + 565 + ] + }, + { + "teal": 446, + "source": 165, + "pc": [ + 566 + ] + }, + { + "teal": 447, + "source": 165, + "pc": [ + 567, + 568 + ] + }, + { + "teal": 450, + "source": 165, + "pc": [ + 569 + ] + }, + { + "teal": 453, + "source": 144, + "pc": [ + 570 + ] + }, + { + "teal": 458, + "source": 183, + "pc": [ + 571, + 572 + ] + }, + { + "teal": 461, + "source": 183, + "pc": [ + 573, + 574, + 575 + ] + }, + { + "teal": 462, + "source": 183, + "pc": [ + 576 + ] + }, + { + "teal": 463, + "source": 183, + "pc": [ + 577 + ] + }, + { + "teal": 464, + "source": 183, + "pc": [ + 578, + 579 + ] + }, + { + "teal": 465, + "source": 183, + "pc": [ + 580 + ] + }, + { + "teal": 466, + "source": 183, + "pc": [ + 581 + ] + }, + { + "teal": 469, + "source": 183, + "pc": [ + 582, + 583 + ] + }, + { + "teal": 470, + "source": 183, + "pc": [ + 584 + ] + }, + { + "teal": 471, + "source": 183, + "pc": [ + 585 + ] + }, + { + "teal": 472, + "source": 183, + "pc": [ + 586 + ] + }, + { + "teal": 473, + "source": 183, + "pc": [ + 587, + 588 + ] + }, + { + "teal": 474, + "source": 183, + "pc": [ + 589 + ] + }, + { + "teal": 475, + "source": 183, + "pc": [ + 590 + ] + }, + { + "teal": 476, + "source": 183, + "pc": [ + 591 + ] + }, + { + "teal": 479, + "source": 183, + "pc": [ + 592, + 593, + 594 + ] + }, + { + "teal": 480, + "source": 183, + "pc": [ + 595 + ] + }, + { + "teal": 481, + "source": 183, + "pc": [ + 596 + ] + }, + { + "teal": 482, + "source": 183, + "pc": [ + 597 + ] + }, + { + "teal": 483, + "source": 183, + "pc": [ + 598 + ] + }, + { + "teal": 484, + "source": 183, + "pc": [ + 599 + ] + }, + { + "teal": 497, + "source": 183, + "pc": [ + 600, + 601, + 602 + ] + }, + { + "teal": 500, + "source": 183, + "pc": [ + 603, + 604 + ] + }, + { + "teal": 501, + "source": 183, + "pc": [ + 605, + 606 + ] + }, + { + "teal": 505, + "source": 184, + "pc": [ + 607 + ] + }, + { + "teal": 506, + "source": 184, + "pc": [ + 608 + ] + }, + { + "teal": 507, + "source": 184, + "pc": [ + 609 + ] + }, + { + "teal": 508, + "source": 184, + "pc": [ + 610 + ] + }, + { + "teal": 509, + "source": 184, + "pc": [ + 611 + ] + }, + { + "teal": 513, + "source": 187, + "pc": [ + 612, + 613 + ] + }, + { + "teal": 514, + "source": 187, + "pc": [ + 614 + ] + }, + { + "teal": 515, + "source": 187, + "pc": [ + 615 + ] + }, + { + "teal": 516, + "source": 187, + "pc": [ + 616, + 617 + ] + }, + { + "teal": 517, + "source": 187, + "pc": [ + 618 + ] + }, + { + "teal": 518, + "source": 187, + "pc": [ + 619 + ] + }, + { + "teal": 519, + "source": 187, + "pc": [ + 620 + ] + }, + { + "teal": 523, + "source": 188, + "pc": [ + 621, + 622 + ] + }, + { + "teal": 524, + "source": 188, + "pc": [ + 623, + 624 + ] + }, + { + "teal": 525, + "source": 188, + "pc": [ + 625 + ] + }, + { + "teal": 526, + "source": 188, + "pc": [ + 626 + ] + }, + { + "teal": 535, + "source": 192, + "pc": [ + 627, + 628 + ] + }, + { + "teal": 536, + "source": 193, + "pc": [ + 629, + 630 + ] + }, + { + "teal": 537, + "source": 193, + "pc": [ + 631 + ] + }, + { + "teal": 538, + "source": 193, + "pc": [ + 632 + ] + }, + { + "teal": 539, + "source": 193, + "pc": [ + 633, + 634 + ] + }, + { + "teal": 540, + "source": 193, + "pc": [ + 635 + ] + }, + { + "teal": 541, + "source": 193, + "pc": [ + 636 + ] + }, + { + "teal": 542, + "source": 193, + "pc": [ + 637 + ] + }, + { + "teal": 545, + "source": 192, + "pc": [ + 638, + 639 + ] + }, + { + "teal": 546, + "source": 194, + "pc": [ + 640, + 641 + ] + }, + { + "teal": 547, + "source": 194, + "pc": [ + 642, + 643 + ] + }, + { + "teal": 548, + "source": 194, + "pc": [ + 644 + ] + }, + { + "teal": 549, + "source": 194, + "pc": [ + 645 + ] + }, + { + "teal": 552, + "source": 192, + "pc": [ + 646, + 647 + ] + }, + { + "teal": 553, + "source": 195, + "pc": [ + 648, + 649 + ] + }, + { + "teal": 554, + "source": 195, + "pc": [ + 650, + 651 + ] + }, + { + "teal": 555, + "source": 195, + "pc": [ + 652, + 653 + ] + }, + { + "teal": 556, + "source": 195, + "pc": [ + 654 + ] + }, + { + "teal": 557, + "source": 195, + "pc": [ + 655 + ] + }, + { + "teal": 561, + "source": 201, + "pc": [ + 656, + 657, + 658 + ] + }, + { + "teal": 562, + "source": 201, + "pc": [ + 659, + 660 + ] + }, + { + "teal": 566, + "source": 202, + "pc": [ + 661 + ] + }, + { + "teal": 567, + "source": 202, + "pc": [ + 662, + 663 + ] + }, + { + "teal": 571, + "source": 205, + "pc": [ + 664 + ] + }, + { + "teal": 572, + "source": 205, + "pc": [ + 665, + 666 + ] + }, + { + "teal": 577, + "source": 205, + "pc": [ + 667, + 668 + ] + }, + { + "teal": 578, + "source": 205, + "pc": [ + 669, + 670 + ] + }, + { + "teal": 579, + "source": 205, + "pc": [ + 671 + ] + }, + { + "teal": 580, + "source": 205, + "pc": [ + 672, + 673, + 674 + ] + }, + { + "teal": 585, + "source": 206, + "pc": [ + 675, + 676 + ] + }, + { + "teal": 586, + "source": 206, + "pc": [ + 677, + 678 + ] + }, + { + "teal": 587, + "source": 206, + "pc": [ + 679 + ] + }, + { + "teal": 588, + "source": 206, + "pc": [ + 680, + 681, + 682 + ] + }, + { + "teal": 593, + "source": 207, + "pc": [ + 683 + ] + }, + { + "teal": 594, + "source": 207, + "pc": [ + 684 + ] + }, + { + "teal": 595, + "source": 207, + "pc": [ + 685, + 686 + ] + }, + { + "teal": 596, + "source": 207, + "pc": [ + 687 + ] + }, + { + "teal": 597, + "source": 207, + "pc": [ + 688, + 689 + ] + }, + { + "teal": 598, + "source": 207, + "pc": [ + 690, + 691 + ] + }, + { + "teal": 599, + "source": 207, + "pc": [ + 692 + ] + }, + { + "teal": 600, + "source": 207, + "pc": [ + 693, + 694 + ] + }, + { + "teal": 601, + "source": 207, + "pc": [ + 695, + 696 + ] + }, + { + "teal": 602, + "source": 207, + "pc": [ + 697, + 698 + ] + }, + { + "teal": 603, + "source": 207, + "pc": [ + 699, + 700 + ] + }, + { + "teal": 604, + "source": 207, + "pc": [ + 701 + ] + }, + { + "teal": 609, + "source": 209, + "pc": [ + 702, + 703 + ] + }, + { + "teal": 610, + "source": 209, + "pc": [ + 704 + ] + }, + { + "teal": 611, + "source": 209, + "pc": [ + 705 + ] + }, + { + "teal": 612, + "source": 209, + "pc": [ + 706 + ] + }, + { + "teal": 613, + "source": 209, + "pc": [ + 707 + ] + }, + { + "teal": 614, + "source": 209, + "pc": [ + 708, + 709 + ] + }, + { + "teal": 615, + "source": 209, + "pc": [ + 710 + ] + }, + { + "teal": 616, + "source": 209, + "pc": [ + 711, + 712 + ] + }, + { + "teal": 621, + "source": 210, + "pc": [ + 713, + 714 + ] + }, + { + "teal": 622, + "source": 210, + "pc": [ + 715, + 716, + 717 + ] + }, + { + "teal": 623, + "source": 210, + "pc": [ + 718, + 719 + ] + }, + { + "teal": 624, + "source": 210, + "pc": [ + 720 + ] + }, + { + "teal": 625, + "source": 210, + "pc": [ + 721, + 722, + 723 + ] + }, + { + "teal": 630, + "source": 211, + "pc": [ + 724, + 725 + ] + }, + { + "teal": 631, + "source": 211, + "pc": [ + 726, + 727 + ] + }, + { + "teal": 632, + "source": 211, + "pc": [ + 728, + 729 + ] + }, + { + "teal": 633, + "source": 211, + "pc": [ + 730, + 731, + 732 + ] + }, + { + "teal": 634, + "source": 211, + "pc": [ + 733 + ] + }, + { + "teal": 635, + "source": 211, + "pc": [ + 734, + 735 + ] + }, + { + "teal": 636, + "source": 211, + "pc": [ + 736, + 737 + ] + }, + { + "teal": 637, + "source": 211, + "pc": [ + 738 + ] + }, + { + "teal": 638, + "source": 211, + "pc": [ + 739 + ] + }, + { + "teal": 639, + "source": 211, + "pc": [ + 740 + ] + }, + { + "teal": 640, + "source": 211, + "pc": [ + 741, + 742 + ] + }, + { + "teal": 644, + "source": 212, + "pc": [ + 743, + 744 + ] + }, + { + "teal": 645, + "source": 212, + "pc": [ + 745, + 746 + ] + }, + { + "teal": 646, + "source": 212, + "pc": [ + 747, + 748 + ] + }, + { + "teal": 647, + "source": 212, + "pc": [ + 749 + ] + }, + { + "teal": 648, + "source": 212, + "pc": [ + 750 + ] + }, + { + "teal": 649, + "source": 212, + "pc": [ + 751, + 752 + ] + }, + { + "teal": 653, + "source": 215, + "pc": [ + 753, + 754 + ] + }, + { + "teal": 654, + "source": 215, + "pc": [ + 755 + ] + }, + { + "teal": 655, + "source": 215, + "pc": [ + 756 + ] + }, + { + "teal": 656, + "source": 215, + "pc": [ + 757, + 758 + ] + }, + { + "teal": 657, + "source": 215, + "pc": [ + 759 + ] + }, + { + "teal": 658, + "source": 215, + "pc": [ + 760, + 761 + ] + }, + { + "teal": 659, + "source": 215, + "pc": [ + 762 + ] + }, + { + "teal": 663, + "source": 217, + "pc": [ + 763, + 764 + ] + }, + { + "teal": 664, + "source": 217, + "pc": [ + 765 + ] + }, + { + "teal": 665, + "source": 217, + "pc": [ + 766, + 767 + ] + }, + { + "teal": 666, + "source": 217, + "pc": [ + 768, + 769 + ] + }, + { + "teal": 667, + "source": 217, + "pc": [ + 770 + ] + }, + { + "teal": 668, + "source": 217, + "pc": [ + 771, + 772 + ] + }, + { + "teal": 669, + "source": 217, + "pc": [ + 773 + ] + }, + { + "teal": 670, + "source": 217, + "pc": [ + 774 + ] + }, + { + "teal": 674, + "source": 218, + "pc": [ + 775, + 776 + ] + }, + { + "teal": 677, + "source": 218, + "pc": [ + 777, + 778 + ] + }, + { + "teal": 680, + "source": 218, + "pc": [ + 779, + 780 + ] + }, + { + "teal": 681, + "source": 218, + "pc": [ + 781 + ] + }, + { + "teal": 687, + "source": 220, + "pc": [ + 782, + 783 + ] + }, + { + "teal": 688, + "source": 220, + "pc": [ + 784, + 785, + 786 + ] + }, + { + "teal": 689, + "source": 220, + "pc": [ + 787, + 788 + ] + }, + { + "teal": 690, + "source": 220, + "pc": [ + 789 + ] + }, + { + "teal": 691, + "source": 220, + "pc": [ + 790, + 791, + 792 + ] + }, + { + "teal": 696, + "source": 221, + "pc": [ + 793, + 794 + ] + }, + { + "teal": 697, + "source": 221, + "pc": [ + 795 + ] + }, + { + "teal": 698, + "source": 221, + "pc": [ + 796 + ] + }, + { + "teal": 699, + "source": 221, + "pc": [ + 797, + 798 + ] + }, + { + "teal": 700, + "source": 222, + "pc": [ + 799, + 800, + 801 + ] + }, + { + "teal": 707, + "source": 205, + "pc": [ + 802, + 803 + ] + }, + { + "teal": 708, + "source": 205, + "pc": [ + 804 + ] + }, + { + "teal": 709, + "source": 205, + "pc": [ + 805 + ] + }, + { + "teal": 710, + "source": 205, + "pc": [ + 806, + 807 + ] + }, + { + "teal": 711, + "source": 205, + "pc": [ + 808, + 809, + 810 + ] + }, + { + "teal": 717, + "source": 226, + "pc": [ + 811, + 812 + ] + }, + { + "teal": 718, + "source": 226, + "pc": [ + 813 + ] + }, + { + "teal": 719, + "source": 226, + "pc": [ + 814 + ] + }, + { + "teal": 720, + "source": 226, + "pc": [ + 815, + 816, + 817 + ] + }, + { + "teal": 723, + "source": 228, + "pc": [ + 818 + ] + }, + { + "teal": 728, + "source": 233, + "pc": [ + 819, + 820 + ] + }, + { + "teal": 729, + "source": 233, + "pc": [ + 821, + 822 + ] + }, + { + "teal": 730, + "source": 233, + "pc": [ + 823, + 824 + ] + }, + { + "teal": 731, + "source": 233, + "pc": [ + 825 + ] + }, + { + "teal": 732, + "source": 233, + "pc": [ + 826 + ] + }, + { + "teal": 735, + "source": 233, + "pc": [ + 827 + ] + }, + { + "teal": 739, + "source": 235, + "pc": [ + 828, + 829 + ] + }, + { + "teal": 740, + "source": 235, + "pc": [ + 830 + ] + }, + { + "teal": 741, + "source": 235, + "pc": [ + 831 + ] + }, + { + "teal": 742, + "source": 235, + "pc": [ + 832 + ] + }, + { + "teal": 743, + "source": 235, + "pc": [ + 833 + ] + }, + { + "teal": 744, + "source": 235, + "pc": [ + 834 + ] + }, + { + "teal": 745, + "source": 235, + "pc": [ + 835 + ] + }, + { + "teal": 746, + "source": 235, + "pc": [ + 836, + 837 + ] + }, + { + "teal": 747, + "source": 235, + "pc": [ + 838 + ] + }, + { + "teal": 748, + "source": 235, + "pc": [ + 839, + 840 + ] + }, + { + "teal": 749, + "source": 235, + "pc": [ + 841 + ] + }, + { + "teal": 750, + "source": 235, + "pc": [ + 842, + 843 + ] + }, + { + "teal": 751, + "source": 235, + "pc": [ + 844 + ] + }, + { + "teal": 752, + "source": 235, + "pc": [ + 845 + ] + }, + { + "teal": 762, + "source": 236, + "pc": [ + 846, + 847 + ] + }, + { + "teal": 763, + "source": 236, + "pc": [ + 848 + ] + }, + { + "teal": 764, + "source": 236, + "pc": [ + 849 + ] + }, + { + "teal": 765, + "source": 236, + "pc": [ + 850 + ] + }, + { + "teal": 766, + "source": 236, + "pc": [ + 851 + ] + }, + { + "teal": 767, + "source": 237, + "pc": [ + 852, + 853 + ] + }, + { + "teal": 768, + "source": 238, + "pc": [ + 854, + 855 + ] + }, + { + "teal": 769, + "source": 238, + "pc": [ + 856, + 857 + ] + }, + { + "teal": 770, + "source": 238, + "pc": [ + 858 + ] + }, + { + "teal": 771, + "source": 238, + "pc": [ + 859 + ] + }, + { + "teal": 772, + "source": 239, + "pc": [ + 860, + 861 + ] + }, + { + "teal": 773, + "source": 239, + "pc": [ + 862 + ] + }, + { + "teal": 774, + "source": 240, + "pc": [ + 863, + 864 + ] + }, + { + "teal": 775, + "source": 240, + "pc": [ + 865 + ] + }, + { + "teal": 776, + "source": 241, + "pc": [ + 866, + 867 + ] + }, + { + "teal": 777, + "source": 241, + "pc": [ + 868 + ] + }, + { + "teal": 778, + "source": 241, + "pc": [ + 869 + ] + }, + { + "teal": 779, + "source": 236, + "pc": [ + 870 + ] + }, + { + "teal": 780, + "source": 236, + "pc": [ + 871, + 872 + ] + }, + { + "teal": 781, + "source": 236, + "pc": [ + 873 + ] + }, + { + "teal": 785, + "source": 243, + "pc": [ + 874, + 875 + ] + }, + { + "teal": 786, + "source": 243, + "pc": [ + 876 + ] + }, + { + "teal": 787, + "source": 243, + "pc": [ + 877 + ] + }, + { + "teal": 788, + "source": 243, + "pc": [ + 878 + ] + }, + { + "teal": 789, + "source": 243, + "pc": [ + 879, + 880 + ] + }, + { + "teal": 790, + "source": 243, + "pc": [ + 881 + ] + }, + { + "teal": 791, + "source": 243, + "pc": [ + 882 + ] + }, + { + "teal": 795, + "source": 244, + "pc": [ + 883, + 884 + ] + }, + { + "teal": 796, + "source": 244, + "pc": [ + 885 + ] + }, + { + "teal": 797, + "source": 244, + "pc": [ + 886, + 887 + ] + }, + { + "teal": 798, + "source": 244, + "pc": [ + 888, + 889 + ] + }, + { + "teal": 799, + "source": 244, + "pc": [ + 890 + ] + }, + { + "teal": 800, + "source": 244, + "pc": [ + 891, + 892 + ] + }, + { + "teal": 801, + "source": 244, + "pc": [ + 893 + ] + }, + { + "teal": 802, + "source": 244, + "pc": [ + 894 + ] + }, + { + "teal": 806, + "source": 245, + "pc": [ + 895, + 896 + ] + }, + { + "teal": 809, + "source": 245, + "pc": [ + 897, + 898 + ] + }, + { + "teal": 812, + "source": 245, + "pc": [ + 899, + 900 + ] + }, + { + "teal": 813, + "source": 245, + "pc": [ + 901 + ] + }, + { + "teal": 818, + "source": 255, + "pc": [ + 902, + 903, + 904 + ] + }, + { + "teal": 819, + "source": 255, + "pc": [ + 905 + ] + }, + { + "teal": 822, + "source": 255, + "pc": [ + 906, + 907, + 908 + ] + }, + { + "teal": 823, + "source": 255, + "pc": [ + 909 + ] + }, + { + "teal": 824, + "source": 255, + "pc": [ + 910 + ] + }, + { + "teal": 834, + "source": 255, + "pc": [ + 911, + 912, + 913 + ] + }, + { + "teal": 837, + "source": 255, + "pc": [ + 914, + 915 + ] + }, + { + "teal": 838, + "source": 255, + "pc": [ + 916, + 917 + ] + }, + { + "teal": 842, + "source": 259, + "pc": [ + 918, + 919 + ] + }, + { + "teal": 843, + "source": 259, + "pc": [ + 920, + 921 + ] + }, + { + "teal": 847, + "source": 261, + "pc": [ + 922 + ] + }, + { + "teal": 848, + "source": 261, + "pc": [ + 923, + 924 + ] + }, + { + "teal": 853, + "source": 261, + "pc": [ + 925, + 926 + ] + }, + { + "teal": 854, + "source": 261, + "pc": [ + 927, + 928 + ] + }, + { + "teal": 855, + "source": 261, + "pc": [ + 929 + ] + }, + { + "teal": 856, + "source": 261, + "pc": [ + 930, + 931, + 932 + ] + }, + { + "teal": 861, + "source": 262, + "pc": [ + 933, + 934 + ] + }, + { + "teal": 862, + "source": 262, + "pc": [ + 935, + 936 + ] + }, + { + "teal": 863, + "source": 262, + "pc": [ + 937 + ] + }, + { + "teal": 864, + "source": 262, + "pc": [ + 938, + 939, + 940 + ] + }, + { + "teal": 869, + "source": 263, + "pc": [ + 941 + ] + }, + { + "teal": 870, + "source": 263, + "pc": [ + 942 + ] + }, + { + "teal": 871, + "source": 263, + "pc": [ + 943, + 944 + ] + }, + { + "teal": 872, + "source": 263, + "pc": [ + 945 + ] + }, + { + "teal": 873, + "source": 263, + "pc": [ + 946, + 947 + ] + }, + { + "teal": 874, + "source": 263, + "pc": [ + 948, + 949 + ] + }, + { + "teal": 875, + "source": 263, + "pc": [ + 950 + ] + }, + { + "teal": 876, + "source": 263, + "pc": [ + 951, + 952 + ] + }, + { + "teal": 877, + "source": 263, + "pc": [ + 953, + 954 + ] + }, + { + "teal": 878, + "source": 263, + "pc": [ + 955, + 956 + ] + }, + { + "teal": 879, + "source": 263, + "pc": [ + 957, + 958 + ] + }, + { + "teal": 880, + "source": 263, + "pc": [ + 959 + ] + }, + { + "teal": 885, + "source": 265, + "pc": [ + 960, + 961 + ] + }, + { + "teal": 886, + "source": 265, + "pc": [ + 962 + ] + }, + { + "teal": 887, + "source": 265, + "pc": [ + 963 + ] + }, + { + "teal": 888, + "source": 265, + "pc": [ + 964 + ] + }, + { + "teal": 889, + "source": 265, + "pc": [ + 965 + ] + }, + { + "teal": 890, + "source": 265, + "pc": [ + 966, + 967 + ] + }, + { + "teal": 891, + "source": 265, + "pc": [ + 968 + ] + }, + { + "teal": 892, + "source": 265, + "pc": [ + 969, + 970 + ] + }, + { + "teal": 897, + "source": 266, + "pc": [ + 971, + 972 + ] + }, + { + "teal": 898, + "source": 266, + "pc": [ + 973, + 974, + 975 + ] + }, + { + "teal": 899, + "source": 266, + "pc": [ + 976, + 977 + ] + }, + { + "teal": 900, + "source": 266, + "pc": [ + 978 + ] + }, + { + "teal": 901, + "source": 266, + "pc": [ + 979, + 980, + 981 + ] + }, + { + "teal": 907, + "source": 267, + "pc": [ + 982, + 983 + ] + }, + { + "teal": 908, + "source": 267, + "pc": [ + 984 + ] + }, + { + "teal": 909, + "source": 267, + "pc": [ + 985 + ] + }, + { + "teal": 910, + "source": 267, + "pc": [ + 986, + 987, + 988 + ] + }, + { + "teal": 915, + "source": 269, + "pc": [ + 989, + 990 + ] + }, + { + "teal": 916, + "source": 269, + "pc": [ + 991, + 992, + 993 + ] + }, + { + "teal": 917, + "source": 269, + "pc": [ + 994 + ] + }, + { + "teal": 918, + "source": 269, + "pc": [ + 995, + 996 + ] + }, + { + "teal": 924, + "source": 271, + "pc": [ + 997, + 998 + ] + }, + { + "teal": 925, + "source": 271, + "pc": [ + 999, + 1000, + 1001 + ] + }, + { + "teal": 926, + "source": 271, + "pc": [ + 1002 + ] + }, + { + "teal": 927, + "source": 271, + "pc": [ + 1003, + 1004 + ] + }, + { + "teal": 928, + "source": 271, + "pc": [ + 1005 + ] + }, + { + "teal": 929, + "source": 271, + "pc": [ + 1006, + 1007, + 1008 + ] + }, + { + "teal": 932, + "source": 272, + "pc": [ + 1009 + ] + }, + { + "teal": 937, + "source": 274, + "pc": [ + 1010, + 1011 + ] + }, + { + "teal": 938, + "source": 274, + "pc": [ + 1012, + 1013 + ] + }, + { + "teal": 939, + "source": 274, + "pc": [ + 1014, + 1015 + ] + }, + { + "teal": 940, + "source": 274, + "pc": [ + 1016, + 1017, + 1018 + ] + }, + { + "teal": 941, + "source": 274, + "pc": [ + 1019 + ] + }, + { + "teal": 942, + "source": 274, + "pc": [ + 1020, + 1021 + ] + }, + { + "teal": 943, + "source": 274, + "pc": [ + 1022 + ] + }, + { + "teal": 944, + "source": 274, + "pc": [ + 1023 + ] + }, + { + "teal": 945, + "source": 274, + "pc": [ + 1024 + ] + }, + { + "teal": 946, + "source": 274, + "pc": [ + 1025, + 1026 + ] + }, + { + "teal": 950, + "source": 275, + "pc": [ + 1027, + 1028 + ] + }, + { + "teal": 951, + "source": 275, + "pc": [ + 1029 + ] + }, + { + "teal": 952, + "source": 275, + "pc": [ + 1030, + 1031 + ] + }, + { + "teal": 953, + "source": 275, + "pc": [ + 1032 + ] + }, + { + "teal": 954, + "source": 275, + "pc": [ + 1033, + 1034 + ] + }, + { + "teal": 955, + "source": 275, + "pc": [ + 1035 + ] + }, + { + "teal": 956, + "source": 275, + "pc": [ + 1036 + ] + }, + { + "teal": 960, + "source": 277, + "pc": [ + 1037 + ] + }, + { + "teal": 961, + "source": 277, + "pc": [ + 1038, + 1039 + ] + }, + { + "teal": 966, + "source": 278, + "pc": [ + 1040, + 1041 + ] + }, + { + "teal": 967, + "source": 278, + "pc": [ + 1042, + 1043, + 1044 + ] + }, + { + "teal": 968, + "source": 278, + "pc": [ + 1045 + ] + }, + { + "teal": 969, + "source": 278, + "pc": [ + 1046 + ] + }, + { + "teal": 970, + "source": 278, + "pc": [ + 1047 + ] + }, + { + "teal": 971, + "source": 278, + "pc": [ + 1048, + 1049, + 1050 + ] + }, + { + "teal": 977, + "source": 280, + "pc": [ + 1051 + ] + }, + { + "teal": 978, + "source": 280, + "pc": [ + 1052 + ] + }, + { + "teal": 979, + "source": 280, + "pc": [ + 1053 + ] + }, + { + "teal": 980, + "source": 280, + "pc": [ + 1054 + ] + }, + { + "teal": 981, + "source": 280, + "pc": [ + 1055, + 1056, + 1057 + ] + }, + { + "teal": 989, + "source": 281, + "pc": [ + 1058 + ] + }, + { + "teal": 990, + "source": 281, + "pc": [ + 1059 + ] + }, + { + "teal": 991, + "source": 281, + "pc": [ + 1060, + 1061 + ] + }, + { + "teal": 992, + "source": 281, + "pc": [ + 1062, + 1063 + ] + }, + { + "teal": 993, + "source": 281, + "pc": [ + 1064, + 1065 + ] + }, + { + "teal": 997, + "source": 282, + "pc": [ + 1066 + ] + }, + { + "teal": 998, + "source": 282, + "pc": [ + 1067 + ] + }, + { + "teal": 999, + "source": 282, + "pc": [ + 1068, + 1069 + ] + }, + { + "teal": 1003, + "source": 283, + "pc": [ + 1070 + ] + }, + { + "teal": 1004, + "source": 283, + "pc": [ + 1071 + ] + }, + { + "teal": 1005, + "source": 283, + "pc": [ + 1072 + ] + }, + { + "teal": 1006, + "source": 283, + "pc": [ + 1073, + 1074 + ] + }, + { + "teal": 1009, + "source": 281, + "pc": [ + 1075 + ] + }, + { + "teal": 1010, + "source": 281, + "pc": [ + 1076, + 1077 + ] + }, + { + "teal": 1013, + "source": 281, + "pc": [ + 1078 + ] + }, + { + "teal": 1014, + "source": 281, + "pc": [ + 1079, + 1080 + ] + }, + { + "teal": 1015, + "source": 281, + "pc": [ + 1081 + ] + }, + { + "teal": 1016, + "source": 281, + "pc": [ + 1082 + ] + }, + { + "teal": 1017, + "source": 281, + "pc": [ + 1083, + 1084 + ] + }, + { + "teal": 1018, + "source": 281, + "pc": [ + 1085, + 1086, + 1087 + ] + }, + { + "teal": 1019, + "source": 281, + "pc": [ + 1088, + 1089 + ] + }, + { + "teal": 1027, + "source": 289, + "pc": [ + 1090 + ] + }, + { + "teal": 1028, + "source": 289, + "pc": [ + 1091, + 1092 + ] + }, + { + "teal": 1029, + "source": 289, + "pc": [ + 1093, + 1094 + ] + }, + { + "teal": 1033, + "source": 290, + "pc": [ + 1095, + 1096 + ] + }, + { + "teal": 1034, + "source": 290, + "pc": [ + 1097, + 1098, + 1099 + ] + }, + { + "teal": 1035, + "source": 290, + "pc": [ + 1100 + ] + }, + { + "teal": 1036, + "source": 290, + "pc": [ + 1101, + 1102 + ] + }, + { + "teal": 1040, + "source": 291, + "pc": [ + 1103, + 1104 + ] + }, + { + "teal": 1041, + "source": 291, + "pc": [ + 1105, + 1106 + ] + }, + { + "teal": 1045, + "source": 292, + "pc": [ + 1107, + 1108 + ] + }, + { + "teal": 1046, + "source": 292, + "pc": [ + 1109, + 1110, + 1111 + ] + }, + { + "teal": 1047, + "source": 292, + "pc": [ + 1112 + ] + }, + { + "teal": 1048, + "source": 292, + "pc": [ + 1113, + 1114 + ] + }, + { + "teal": 1051, + "source": 289, + "pc": [ + 1115 + ] + }, + { + "teal": 1052, + "source": 289, + "pc": [ + 1116, + 1117 + ] + }, + { + "teal": 1055, + "source": 289, + "pc": [ + 1118 + ] + }, + { + "teal": 1059, + "source": 294, + "pc": [ + 1119, + 1120 + ] + }, + { + "teal": 1060, + "source": 294, + "pc": [ + 1121, + 1122, + 1123 + ] + }, + { + "teal": 1061, + "source": 294, + "pc": [ + 1124 + ] + }, + { + "teal": 1062, + "source": 294, + "pc": [ + 1125, + 1126 + ] + }, + { + "teal": 1066, + "source": 295, + "pc": [ + 1127, + 1128 + ] + }, + { + "teal": 1067, + "source": 295, + "pc": [ + 1129, + 1130 + ] + }, + { + "teal": 1068, + "source": 295, + "pc": [ + 1131, + 1132 + ] + }, + { + "teal": 1069, + "source": 295, + "pc": [ + 1133, + 1134 + ] + }, + { + "teal": 1070, + "source": 280, + "pc": [ + 1135, + 1136, + 1137 + ] + }, + { + "teal": 1075, + "source": 300, + "pc": [ + 1138, + 1139 + ] + }, + { + "teal": 1076, + "source": 300, + "pc": [ + 1140, + 1141, + 1142 + ] + }, + { + "teal": 1077, + "source": 300, + "pc": [ + 1143 + ] + }, + { + "teal": 1078, + "source": 300, + "pc": [ + 1144, + 1145 + ] + }, + { + "teal": 1082, + "source": 301, + "pc": [ + 1146, + 1147 + ] + }, + { + "teal": 1083, + "source": 301, + "pc": [ + 1148, + 1149 + ] + }, + { + "teal": 1084, + "source": 301, + "pc": [ + 1150, + 1151 + ] + }, + { + "teal": 1085, + "source": 301, + "pc": [ + 1152, + 1153 + ] + }, + { + "teal": 1095, + "source": 307, + "pc": [ + 1154, + 1155 + ] + }, + { + "teal": 1096, + "source": 307, + "pc": [ + 1156, + 1157, + 1158 + ] + }, + { + "teal": 1097, + "source": 307, + "pc": [ + 1159 + ] + }, + { + "teal": 1098, + "source": 307, + "pc": [ + 1160 + ] + }, + { + "teal": 1099, + "source": 307, + "pc": [ + 1161 + ] + }, + { + "teal": 1100, + "source": 307, + "pc": [ + 1162 + ] + }, + { + "teal": 1101, + "source": 307, + "pc": [ + 1163, + 1164, + 1165 + ] + }, + { + "teal": 1102, + "source": 307, + "pc": [ + 1166, + 1167 + ] + }, + { + "teal": 1103, + "source": 307, + "pc": [ + 1168, + 1169, + 1170 + ] + }, + { + "teal": 1104, + "source": 307, + "pc": [ + 1171 + ] + }, + { + "teal": 1105, + "source": 307, + "pc": [ + 1172, + 1173 + ] + }, + { + "teal": 1106, + "source": 307, + "pc": [ + 1174 + ] + }, + { + "teal": 1107, + "source": 307, + "pc": [ + 1175 + ] + }, + { + "teal": 1108, + "source": 307, + "pc": [ + 1176 + ] + }, + { + "teal": 1112, + "source": 306, + "pc": [ + 1177 + ] + }, + { + "teal": 1120, + "source": 314, + "pc": [ + 1178 + ] + }, + { + "teal": 1121, + "source": 314, + "pc": [ + 1179 + ] + }, + { + "teal": 1122, + "source": 314, + "pc": [ + 1180, + 1181 + ] + }, + { + "teal": 1126, + "source": 315, + "pc": [ + 1182, + 1183 + ] + }, + { + "teal": 1127, + "source": 315, + "pc": [ + 1184, + 1185 + ] + }, + { + "teal": 1131, + "source": 316, + "pc": [ + 1186, + 1187 + ] + }, + { + "teal": 1132, + "source": 316, + "pc": [ + 1188, + 1189 + ] + }, + { + "teal": 1136, + "source": 317, + "pc": [ + 1190, + 1191, + 1192, + 1193, + 1194, + 1195, + 1196, + 1197, + 1198, + 1199 + ] + }, + { + "teal": 1137, + "source": 317, + "pc": [ + 1200, + 1201 + ] + }, + { + "teal": 1140, + "source": 314, + "pc": [ + 1202 + ] + }, + { + "teal": 1141, + "source": 314, + "pc": [ + 1203, + 1204 + ] + }, + { + "teal": 1144, + "source": 314, + "pc": [ + 1205 + ] + }, + { + "teal": 1148, + "source": 319, + "pc": [ + 1206 + ] + }, + { + "teal": 1149, + "source": 319, + "pc": [ + 1207, + 1208 + ] + }, + { + "teal": 1154, + "source": 320, + "pc": [ + 1209, + 1210 + ] + }, + { + "teal": 1155, + "source": 320, + "pc": [ + 1211, + 1212, + 1213 + ] + }, + { + "teal": 1156, + "source": 320, + "pc": [ + 1214 + ] + }, + { + "teal": 1157, + "source": 320, + "pc": [ + 1215 + ] + }, + { + "teal": 1158, + "source": 320, + "pc": [ + 1216 + ] + }, + { + "teal": 1159, + "source": 320, + "pc": [ + 1217, + 1218, + 1219 + ] + }, + { + "teal": 1164, + "source": 322, + "pc": [ + 1220, + 1221 + ] + }, + { + "teal": 1165, + "source": 322, + "pc": [ + 1222 + ] + }, + { + "teal": 1166, + "source": 322, + "pc": [ + 1223 + ] + }, + { + "teal": 1167, + "source": 322, + "pc": [ + 1224 + ] + }, + { + "teal": 1168, + "source": 322, + "pc": [ + 1225, + 1226 + ] + }, + { + "teal": 1169, + "source": 322, + "pc": [ + 1227 + ] + }, + { + "teal": 1170, + "source": 322, + "pc": [ + 1228 + ] + }, + { + "teal": 1174, + "source": 323, + "pc": [ + 1229, + 1230 + ] + }, + { + "teal": 1175, + "source": 323, + "pc": [ + 1231 + ] + }, + { + "teal": 1176, + "source": 323, + "pc": [ + 1232, + 1233 + ] + }, + { + "teal": 1177, + "source": 323, + "pc": [ + 1234 + ] + }, + { + "teal": 1178, + "source": 323, + "pc": [ + 1235, + 1236 + ] + }, + { + "teal": 1182, + "source": 324, + "pc": [ + 1237, + 1238 + ] + }, + { + "teal": 1183, + "source": 324, + "pc": [ + 1239, + 1240 + ] + }, + { + "teal": 1184, + "source": 324, + "pc": [ + 1241, + 1242 + ] + }, + { + "teal": 1185, + "source": 324, + "pc": [ + 1243, + 1244 + ] + }, + { + "teal": 1189, + "source": 325, + "pc": [ + 1245, + 1246 + ] + }, + { + "teal": 1190, + "source": 325, + "pc": [ + 1247, + 1248 + ] + }, + { + "teal": 1191, + "source": 325, + "pc": [ + 1249, + 1250 + ] + }, + { + "teal": 1192, + "source": 325, + "pc": [ + 1251, + 1252 + ] + }, + { + "teal": 1196, + "source": 326, + "pc": [ + 1253 + ] + }, + { + "teal": 1197, + "source": 326, + "pc": [ + 1254, + 1255 + ] + }, + { + "teal": 1202, + "source": 329, + "pc": [ + 1256, + 1257 + ] + }, + { + "teal": 1203, + "source": 329, + "pc": [ + 1258 + ] + }, + { + "teal": 1204, + "source": 329, + "pc": [ + 1259 + ] + }, + { + "teal": 1205, + "source": 329, + "pc": [ + 1260, + 1261 + ] + }, + { + "teal": 1206, + "source": 329, + "pc": [ + 1262 + ] + }, + { + "teal": 1207, + "source": 329, + "pc": [ + 1263, + 1264 + ] + }, + { + "teal": 1208, + "source": 329, + "pc": [ + 1265 + ] + }, + { + "teal": 1221, + "source": 334, + "pc": [ + 1266 + ] + }, + { + "teal": 1222, + "source": 334, + "pc": [ + 1267 + ] + }, + { + "teal": 1223, + "source": 334, + "pc": [ + 1268, + 1269 + ] + }, + { + "teal": 1224, + "source": 334, + "pc": [ + 1270, + 1271 + ] + }, + { + "teal": 1225, + "source": 334, + "pc": [ + 1272, + 1273 + ] + }, + { + "teal": 1229, + "source": 335, + "pc": [ + 1274 + ] + }, + { + "teal": 1230, + "source": 335, + "pc": [ + 1275 + ] + }, + { + "teal": 1231, + "source": 335, + "pc": [ + 1276, + 1277 + ] + }, + { + "teal": 1241, + "source": 337, + "pc": [ + 1278 + ] + }, + { + "teal": 1242, + "source": 337, + "pc": [ + 1279 + ] + }, + { + "teal": 1243, + "source": 337, + "pc": [ + 1280 + ] + }, + { + "teal": 1244, + "source": 337, + "pc": [ + 1281 + ] + }, + { + "teal": 1245, + "source": 337, + "pc": [ + 1282 + ] + }, + { + "teal": 1246, + "source": 337, + "pc": [ + 1283 + ] + }, + { + "teal": 1247, + "source": 337, + "pc": [ + 1284 + ] + }, + { + "teal": 1248, + "source": 337, + "pc": [ + 1285, + 1286, + 1287 + ] + }, + { + "teal": 1249, + "source": 337, + "pc": [ + 1288 + ] + }, + { + "teal": 1250, + "source": 337, + "pc": [ + 1289 + ] + }, + { + "teal": 1251, + "source": 337, + "pc": [ + 1290, + 1291 + ] + }, + { + "teal": 1252, + "source": 338, + "pc": [ + 1292, + 1293 + ] + }, + { + "teal": 1253, + "source": 338, + "pc": [ + 1294, + 1295 + ] + }, + { + "teal": 1254, + "source": 339, + "pc": [ + 1296, + 1297 + ] + }, + { + "teal": 1255, + "source": 339, + "pc": [ + 1298 + ] + }, + { + "teal": 1256, + "source": 339, + "pc": [ + 1299, + 1300 + ] + }, + { + "teal": 1257, + "source": 340, + "pc": [ + 1301, + 1302 + ] + }, + { + "teal": 1258, + "source": 340, + "pc": [ + 1303 + ] + }, + { + "teal": 1259, + "source": 340, + "pc": [ + 1304, + 1305 + ] + }, + { + "teal": 1260, + "source": 341, + "pc": [ + 1306, + 1307 + ] + }, + { + "teal": 1261, + "source": 341, + "pc": [ + 1308, + 1309 + ] + }, + { + "teal": 1262, + "source": 341, + "pc": [ + 1310 + ] + }, + { + "teal": 1263, + "source": 341, + "pc": [ + 1311, + 1312 + ] + }, + { + "teal": 1264, + "source": 341, + "pc": [ + 1313 + ] + }, + { + "teal": 1265, + "source": 341, + "pc": [ + 1314, + 1315 + ] + }, + { + "teal": 1268, + "source": 334, + "pc": [ + 1316 + ] + }, + { + "teal": 1269, + "source": 334, + "pc": [ + 1317, + 1318 + ] + }, + { + "teal": 1272, + "source": 334, + "pc": [ + 1319 + ] + }, + { + "teal": 1276, + "source": 344, + "pc": [ + 1320 + ] + }, + { + "teal": 1283, + "source": 261, + "pc": [ + 1321, + 1322 + ] + }, + { + "teal": 1284, + "source": 261, + "pc": [ + 1323 + ] + }, + { + "teal": 1285, + "source": 261, + "pc": [ + 1324 + ] + }, + { + "teal": 1286, + "source": 261, + "pc": [ + 1325, + 1326 + ] + }, + { + "teal": 1287, + "source": 261, + "pc": [ + 1327, + 1328, + 1329 + ] + }, + { + "teal": 1290, + "source": 347, + "pc": [ + 1330 + ] + }, + { + "teal": 1295, + "source": 355, + "pc": [ + 1331, + 1332, + 1333 + ] + }, + { + "teal": 1296, + "source": 355, + "pc": [ + 1334 + ] + }, + { + "teal": 1297, + "source": 355, + "pc": [ + 1335 + ] + }, + { + "teal": 1305, + "source": 355, + "pc": [ + 1336, + 1337, + 1338 + ] + }, + { + "teal": 1308, + "source": 355, + "pc": [ + 1339, + 1340 + ] + }, + { + "teal": 1309, + "source": 355, + "pc": [ + 1341, + 1342 + ] + }, + { + "teal": 1313, + "source": 359, + "pc": [ + 1343, + 1344 + ] + }, + { + "teal": 1314, + "source": 359, + "pc": [ + 1345, + 1346 + ] + }, + { + "teal": 1318, + "source": 361, + "pc": [ + 1347 + ] + }, + { + "teal": 1319, + "source": 361, + "pc": [ + 1348, + 1349 + ] + }, + { + "teal": 1324, + "source": 361, + "pc": [ + 1350, + 1351 + ] + }, + { + "teal": 1325, + "source": 361, + "pc": [ + 1352, + 1353 + ] + }, + { + "teal": 1326, + "source": 361, + "pc": [ + 1354 + ] + }, + { + "teal": 1327, + "source": 361, + "pc": [ + 1355, + 1356, + 1357 + ] + }, + { + "teal": 1332, + "source": 362, + "pc": [ + 1358, + 1359 + ] + }, + { + "teal": 1333, + "source": 362, + "pc": [ + 1360, + 1361 + ] + }, + { + "teal": 1334, + "source": 362, + "pc": [ + 1362 + ] + }, + { + "teal": 1335, + "source": 362, + "pc": [ + 1363, + 1364, + 1365 + ] + }, + { + "teal": 1340, + "source": 363, + "pc": [ + 1366 + ] + }, + { + "teal": 1341, + "source": 363, + "pc": [ + 1367 + ] + }, + { + "teal": 1342, + "source": 363, + "pc": [ + 1368, + 1369 + ] + }, + { + "teal": 1343, + "source": 363, + "pc": [ + 1370 + ] + }, + { + "teal": 1344, + "source": 363, + "pc": [ + 1371, + 1372 + ] + }, + { + "teal": 1345, + "source": 363, + "pc": [ + 1373, + 1374 + ] + }, + { + "teal": 1346, + "source": 363, + "pc": [ + 1375 + ] + }, + { + "teal": 1347, + "source": 363, + "pc": [ + 1376, + 1377 + ] + }, + { + "teal": 1348, + "source": 363, + "pc": [ + 1378, + 1379 + ] + }, + { + "teal": 1349, + "source": 363, + "pc": [ + 1380, + 1381 + ] + }, + { + "teal": 1350, + "source": 363, + "pc": [ + 1382, + 1383 + ] + }, + { + "teal": 1351, + "source": 363, + "pc": [ + 1384 + ] + }, + { + "teal": 1356, + "source": 365, + "pc": [ + 1385, + 1386 + ] + }, + { + "teal": 1357, + "source": 365, + "pc": [ + 1387 + ] + }, + { + "teal": 1358, + "source": 365, + "pc": [ + 1388 + ] + }, + { + "teal": 1359, + "source": 365, + "pc": [ + 1389 + ] + }, + { + "teal": 1360, + "source": 365, + "pc": [ + 1390 + ] + }, + { + "teal": 1361, + "source": 365, + "pc": [ + 1391, + 1392 + ] + }, + { + "teal": 1362, + "source": 365, + "pc": [ + 1393 + ] + }, + { + "teal": 1363, + "source": 365, + "pc": [ + 1394, + 1395 + ] + }, + { + "teal": 1368, + "source": 366, + "pc": [ + 1396, + 1397 + ] + }, + { + "teal": 1369, + "source": 366, + "pc": [ + 1398, + 1399, + 1400 + ] + }, + { + "teal": 1370, + "source": 366, + "pc": [ + 1401, + 1402 + ] + }, + { + "teal": 1371, + "source": 366, + "pc": [ + 1403 + ] + }, + { + "teal": 1372, + "source": 366, + "pc": [ + 1404, + 1405, + 1406 + ] + }, + { + "teal": 1378, + "source": 367, + "pc": [ + 1407, + 1408 + ] + }, + { + "teal": 1379, + "source": 367, + "pc": [ + 1409, + 1410, + 1411 + ] + }, + { + "teal": 1380, + "source": 367, + "pc": [ + 1412 + ] + }, + { + "teal": 1381, + "source": 367, + "pc": [ + 1413 + ] + }, + { + "teal": 1382, + "source": 367, + "pc": [ + 1414 + ] + }, + { + "teal": 1383, + "source": 367, + "pc": [ + 1415, + 1416, + 1417 + ] + }, + { + "teal": 1388, + "source": 368, + "pc": [ + 1418 + ] + }, + { + "teal": 1393, + "source": 370, + "pc": [ + 1419 + ] + }, + { + "teal": 1394, + "source": 370, + "pc": [ + 1420, + 1421 + ] + }, + { + "teal": 1399, + "source": 372, + "pc": [ + 1422 + ] + }, + { + "teal": 1400, + "source": 372, + "pc": [ + 1423 + ] + }, + { + "teal": 1401, + "source": 372, + "pc": [ + 1424 + ] + }, + { + "teal": 1402, + "source": 372, + "pc": [ + 1425 + ] + }, + { + "teal": 1403, + "source": 372, + "pc": [ + 1426, + 1427, + 1428 + ] + }, + { + "teal": 1411, + "source": 373, + "pc": [ + 1429 + ] + }, + { + "teal": 1412, + "source": 373, + "pc": [ + 1430 + ] + }, + { + "teal": 1413, + "source": 373, + "pc": [ + 1431, + 1432 + ] + }, + { + "teal": 1414, + "source": 373, + "pc": [ + 1433, + 1434 + ] + }, + { + "teal": 1415, + "source": 373, + "pc": [ + 1435, + 1436 + ] + }, + { + "teal": 1419, + "source": 374, + "pc": [ + 1437 + ] + }, + { + "teal": 1420, + "source": 374, + "pc": [ + 1438 + ] + }, + { + "teal": 1421, + "source": 374, + "pc": [ + 1439, + 1440 + ] + }, + { + "teal": 1425, + "source": 375, + "pc": [ + 1441 + ] + }, + { + "teal": 1426, + "source": 375, + "pc": [ + 1442 + ] + }, + { + "teal": 1427, + "source": 375, + "pc": [ + 1443 + ] + }, + { + "teal": 1428, + "source": 375, + "pc": [ + 1444, + 1445 + ] + }, + { + "teal": 1431, + "source": 373, + "pc": [ + 1446 + ] + }, + { + "teal": 1432, + "source": 373, + "pc": [ + 1447, + 1448 + ] + }, + { + "teal": 1435, + "source": 373, + "pc": [ + 1449 + ] + }, + { + "teal": 1436, + "source": 373, + "pc": [ + 1450, + 1451 + ] + }, + { + "teal": 1437, + "source": 373, + "pc": [ + 1452 + ] + }, + { + "teal": 1438, + "source": 373, + "pc": [ + 1453 + ] + }, + { + "teal": 1439, + "source": 373, + "pc": [ + 1454, + 1455 + ] + }, + { + "teal": 1440, + "source": 373, + "pc": [ + 1456, + 1457, + 1458 + ] + }, + { + "teal": 1441, + "source": 373, + "pc": [ + 1459, + 1460 + ] + }, + { + "teal": 1449, + "source": 380, + "pc": [ + 1461 + ] + }, + { + "teal": 1450, + "source": 380, + "pc": [ + 1462, + 1463 + ] + }, + { + "teal": 1451, + "source": 380, + "pc": [ + 1464, + 1465 + ] + }, + { + "teal": 1455, + "source": 381, + "pc": [ + 1466, + 1467 + ] + }, + { + "teal": 1456, + "source": 381, + "pc": [ + 1468, + 1469, + 1470 + ] + }, + { + "teal": 1457, + "source": 381, + "pc": [ + 1471 + ] + }, + { + "teal": 1458, + "source": 381, + "pc": [ + 1472, + 1473 + ] + }, + { + "teal": 1462, + "source": 382, + "pc": [ + 1474, + 1475 + ] + }, + { + "teal": 1463, + "source": 382, + "pc": [ + 1476, + 1477 + ] + }, + { + "teal": 1467, + "source": 383, + "pc": [ + 1478, + 1479 + ] + }, + { + "teal": 1468, + "source": 383, + "pc": [ + 1480, + 1481, + 1482 + ] + }, + { + "teal": 1469, + "source": 383, + "pc": [ + 1483 + ] + }, + { + "teal": 1470, + "source": 383, + "pc": [ + 1484, + 1485 + ] + }, + { + "teal": 1473, + "source": 380, + "pc": [ + 1486 + ] + }, + { + "teal": 1474, + "source": 380, + "pc": [ + 1487, + 1488 + ] + }, + { + "teal": 1477, + "source": 380, + "pc": [ + 1489 + ] + }, + { + "teal": 1481, + "source": 385, + "pc": [ + 1490, + 1491 + ] + }, + { + "teal": 1482, + "source": 385, + "pc": [ + 1492, + 1493, + 1494 + ] + }, + { + "teal": 1483, + "source": 385, + "pc": [ + 1495 + ] + }, + { + "teal": 1484, + "source": 385, + "pc": [ + 1496, + 1497 + ] + }, + { + "teal": 1488, + "source": 386, + "pc": [ + 1498, + 1499 + ] + }, + { + "teal": 1489, + "source": 386, + "pc": [ + 1500, + 1501 + ] + }, + { + "teal": 1490, + "source": 386, + "pc": [ + 1502, + 1503 + ] + }, + { + "teal": 1491, + "source": 386, + "pc": [ + 1504, + 1505 + ] + }, + { + "teal": 1492, + "source": 372, + "pc": [ + 1506, + 1507, + 1508 + ] + }, + { + "teal": 1497, + "source": 391, + "pc": [ + 1509, + 1510 + ] + }, + { + "teal": 1498, + "source": 391, + "pc": [ + 1511, + 1512, + 1513 + ] + }, + { + "teal": 1499, + "source": 391, + "pc": [ + 1514 + ] + }, + { + "teal": 1500, + "source": 391, + "pc": [ + 1515, + 1516 + ] + }, + { + "teal": 1504, + "source": 392, + "pc": [ + 1517, + 1518 + ] + }, + { + "teal": 1505, + "source": 392, + "pc": [ + 1519, + 1520 + ] + }, + { + "teal": 1506, + "source": 392, + "pc": [ + 1521, + 1522 + ] + }, + { + "teal": 1507, + "source": 392, + "pc": [ + 1523, + 1524 + ] + }, + { + "teal": 1512, + "source": 396, + "pc": [ + 1525, + 1526 + ] + }, + { + "teal": 1513, + "source": 396, + "pc": [ + 1527 + ] + }, + { + "teal": 1514, + "source": 396, + "pc": [ + 1528 + ] + }, + { + "teal": 1515, + "source": 396, + "pc": [ + 1529, + 1530 + ] + }, + { + "teal": 1516, + "source": 396, + "pc": [ + 1531 + ] + }, + { + "teal": 1517, + "source": 396, + "pc": [ + 1532, + 1533 + ] + }, + { + "teal": 1518, + "source": 396, + "pc": [ + 1534 + ] + }, + { + "teal": 1531, + "source": 401, + "pc": [ + 1535 + ] + }, + { + "teal": 1532, + "source": 401, + "pc": [ + 1536 + ] + }, + { + "teal": 1533, + "source": 401, + "pc": [ + 1537, + 1538 + ] + }, + { + "teal": 1534, + "source": 401, + "pc": [ + 1539, + 1540 + ] + }, + { + "teal": 1535, + "source": 401, + "pc": [ + 1541, + 1542 + ] + }, + { + "teal": 1539, + "source": 402, + "pc": [ + 1543 + ] + }, + { + "teal": 1540, + "source": 402, + "pc": [ + 1544 + ] + }, + { + "teal": 1541, + "source": 402, + "pc": [ + 1545, + 1546 + ] + }, + { + "teal": 1551, + "source": 404, + "pc": [ + 1547 + ] + }, + { + "teal": 1552, + "source": 404, + "pc": [ + 1548 + ] + }, + { + "teal": 1553, + "source": 404, + "pc": [ + 1549 + ] + }, + { + "teal": 1554, + "source": 404, + "pc": [ + 1550 + ] + }, + { + "teal": 1555, + "source": 404, + "pc": [ + 1551 + ] + }, + { + "teal": 1556, + "source": 404, + "pc": [ + 1552 + ] + }, + { + "teal": 1557, + "source": 404, + "pc": [ + 1553 + ] + }, + { + "teal": 1558, + "source": 404, + "pc": [ + 1554, + 1555, + 1556 + ] + }, + { + "teal": 1559, + "source": 404, + "pc": [ + 1557 + ] + }, + { + "teal": 1560, + "source": 404, + "pc": [ + 1558 + ] + }, + { + "teal": 1561, + "source": 404, + "pc": [ + 1559, + 1560 + ] + }, + { + "teal": 1562, + "source": 405, + "pc": [ + 1561, + 1562 + ] + }, + { + "teal": 1563, + "source": 405, + "pc": [ + 1563, + 1564 + ] + }, + { + "teal": 1564, + "source": 406, + "pc": [ + 1565, + 1566 + ] + }, + { + "teal": 1565, + "source": 406, + "pc": [ + 1567, + 1568 + ] + }, + { + "teal": 1566, + "source": 407, + "pc": [ + 1569, + 1570 + ] + }, + { + "teal": 1567, + "source": 407, + "pc": [ + 1571 + ] + }, + { + "teal": 1568, + "source": 407, + "pc": [ + 1572, + 1573 + ] + }, + { + "teal": 1569, + "source": 408, + "pc": [ + 1574 + ] + }, + { + "teal": 1570, + "source": 408, + "pc": [ + 1575, + 1576 + ] + }, + { + "teal": 1571, + "source": 408, + "pc": [ + 1577 + ] + }, + { + "teal": 1572, + "source": 408, + "pc": [ + 1578, + 1579 + ] + }, + { + "teal": 1573, + "source": 408, + "pc": [ + 1580 + ] + }, + { + "teal": 1574, + "source": 408, + "pc": [ + 1581, + 1582 + ] + }, + { + "teal": 1577, + "source": 401, + "pc": [ + 1583 + ] + }, + { + "teal": 1578, + "source": 401, + "pc": [ + 1584, + 1585 + ] + }, + { + "teal": 1581, + "source": 401, + "pc": [ + 1586 + ] + }, + { + "teal": 1585, + "source": 411, + "pc": [ + 1587 + ] + }, + { + "teal": 1592, + "source": 361, + "pc": [ + 1588, + 1589 + ] + }, + { + "teal": 1593, + "source": 361, + "pc": [ + 1590 + ] + }, + { + "teal": 1594, + "source": 361, + "pc": [ + 1591 + ] + }, + { + "teal": 1595, + "source": 361, + "pc": [ + 1592, + 1593 + ] + }, + { + "teal": 1596, + "source": 361, + "pc": [ + 1594, + 1595, + 1596 + ] + }, + { + "teal": 1599, + "source": 414, + "pc": [ + 1597 + ] + }, + { + "teal": 1604, + "source": 425, + "pc": [ + 1598, + 1599 + ] + }, + { + "teal": 1607, + "source": 425, + "pc": [ + 1600, + 1601, + 1602 + ] + }, + { + "teal": 1608, + "source": 425, + "pc": [ + 1603 + ] + }, + { + "teal": 1609, + "source": 425, + "pc": [ + 1604 + ] + }, + { + "teal": 1610, + "source": 425, + "pc": [ + 1605, + 1606 + ] + }, + { + "teal": 1611, + "source": 425, + "pc": [ + 1607 + ] + }, + { + "teal": 1612, + "source": 425, + "pc": [ + 1608 + ] + }, + { + "teal": 1615, + "source": 425, + "pc": [ + 1609, + 1610, + 1611 + ] + }, + { + "teal": 1616, + "source": 425, + "pc": [ + 1612 + ] + }, + { + "teal": 1617, + "source": 425, + "pc": [ + 1613 + ] + }, + { + "teal": 1618, + "source": 425, + "pc": [ + 1614 + ] + }, + { + "teal": 1619, + "source": 425, + "pc": [ + 1615 + ] + }, + { + "teal": 1629, + "source": 425, + "pc": [ + 1616, + 1617, + 1618 + ] + }, + { + "teal": 1632, + "source": 425, + "pc": [ + 1619, + 1620 + ] + }, + { + "teal": 1636, + "source": 426, + "pc": [ + 1621 + ] + }, + { + "teal": 1637, + "source": 426, + "pc": [ + 1622, + 1623 + ] + }, + { + "teal": 1642, + "source": 426, + "pc": [ + 1624, + 1625 + ] + }, + { + "teal": 1643, + "source": 426, + "pc": [ + 1626, + 1627 + ] + }, + { + "teal": 1644, + "source": 426, + "pc": [ + 1628 + ] + }, + { + "teal": 1645, + "source": 426, + "pc": [ + 1629, + 1630, + 1631 + ] + }, + { + "teal": 1650, + "source": 427, + "pc": [ + 1632, + 1633 + ] + }, + { + "teal": 1651, + "source": 427, + "pc": [ + 1634, + 1635 + ] + }, + { + "teal": 1652, + "source": 427, + "pc": [ + 1636 + ] + }, + { + "teal": 1653, + "source": 427, + "pc": [ + 1637, + 1638, + 1639 + ] + }, + { + "teal": 1658, + "source": 428, + "pc": [ + 1640 + ] + }, + { + "teal": 1659, + "source": 428, + "pc": [ + 1641 + ] + }, + { + "teal": 1660, + "source": 428, + "pc": [ + 1642, + 1643 + ] + }, + { + "teal": 1661, + "source": 428, + "pc": [ + 1644 + ] + }, + { + "teal": 1662, + "source": 428, + "pc": [ + 1645, + 1646 + ] + }, + { + "teal": 1663, + "source": 428, + "pc": [ + 1647, + 1648 + ] + }, + { + "teal": 1664, + "source": 428, + "pc": [ + 1649 + ] + }, + { + "teal": 1665, + "source": 428, + "pc": [ + 1650, + 1651 + ] + }, + { + "teal": 1666, + "source": 428, + "pc": [ + 1652, + 1653 + ] + }, + { + "teal": 1667, + "source": 428, + "pc": [ + 1654, + 1655 + ] + }, + { + "teal": 1668, + "source": 428, + "pc": [ + 1656, + 1657 + ] + }, + { + "teal": 1669, + "source": 428, + "pc": [ + 1658 + ] + }, + { + "teal": 1675, + "source": 430, + "pc": [ + 1659, + 1660 + ] + }, + { + "teal": 1676, + "source": 430, + "pc": [ + 1661 + ] + }, + { + "teal": 1677, + "source": 430, + "pc": [ + 1662 + ] + }, + { + "teal": 1678, + "source": 430, + "pc": [ + 1663 + ] + }, + { + "teal": 1679, + "source": 430, + "pc": [ + 1664 + ] + }, + { + "teal": 1680, + "source": 430, + "pc": [ + 1665, + 1666 + ] + }, + { + "teal": 1681, + "source": 430, + "pc": [ + 1667 + ] + }, + { + "teal": 1682, + "source": 430, + "pc": [ + 1668, + 1669 + ] + }, + { + "teal": 1683, + "source": 430, + "pc": [ + 1670 + ] + }, + { + "teal": 1684, + "source": 430, + "pc": [ + 1671, + 1672 + ] + }, + { + "teal": 1685, + "source": 430, + "pc": [ + 1673 + ] + }, + { + "teal": 1686, + "source": 430, + "pc": [ + 1674, + 1675, + 1676 + ] + }, + { + "teal": 1691, + "source": 431, + "pc": [ + 1677, + 1678 + ] + }, + { + "teal": 1692, + "source": 431, + "pc": [ + 1679 + ] + }, + { + "teal": 1693, + "source": 431, + "pc": [ + 1680 + ] + }, + { + "teal": 1694, + "source": 431, + "pc": [ + 1681 + ] + }, + { + "teal": 1695, + "source": 431, + "pc": [ + 1682 + ] + }, + { + "teal": 1696, + "source": 431, + "pc": [ + 1683, + 1684 + ] + }, + { + "teal": 1697, + "source": 431, + "pc": [ + 1685 + ] + }, + { + "teal": 1700, + "source": 431, + "pc": [ + 1686, + 1687 + ] + }, + { + "teal": 1701, + "source": 431, + "pc": [ + 1688 + ] + }, + { + "teal": 1708, + "source": 426, + "pc": [ + 1689, + 1690 + ] + }, + { + "teal": 1709, + "source": 426, + "pc": [ + 1691 + ] + }, + { + "teal": 1710, + "source": 426, + "pc": [ + 1692 + ] + }, + { + "teal": 1711, + "source": 426, + "pc": [ + 1693, + 1694 + ] + }, + { + "teal": 1712, + "source": 426, + "pc": [ + 1695, + 1696, + 1697 + ] + }, + { + "teal": 1715, + "source": 434, + "pc": [ + 1698 + ] + }, + { + "teal": 1720, + "source": 444, + "pc": [ + 1699, + 1700, + 1701 + ] + }, + { + "teal": 1721, + "source": 444, + "pc": [ + 1702 + ] + }, + { + "teal": 1724, + "source": 444, + "pc": [ + 1703, + 1704, + 1705 + ] + }, + { + "teal": 1725, + "source": 444, + "pc": [ + 1706 + ] + }, + { + "teal": 1728, + "source": 444, + "pc": [ + 1707, + 1708, + 1709 + ] + }, + { + "teal": 1729, + "source": 444, + "pc": [ + 1710 + ] + }, + { + "teal": 1730, + "source": 444, + "pc": [ + 1711 + ] + }, + { + "teal": 1731, + "source": 444, + "pc": [ + 1712, + 1713 + ] + }, + { + "teal": 1732, + "source": 444, + "pc": [ + 1714 + ] + }, + { + "teal": 1733, + "source": 444, + "pc": [ + 1715 + ] + }, + { + "teal": 1736, + "source": 444, + "pc": [ + 1716, + 1717, + 1718 + ] + }, + { + "teal": 1737, + "source": 444, + "pc": [ + 1719 + ] + }, + { + "teal": 1738, + "source": 444, + "pc": [ + 1720 + ] + }, + { + "teal": 1748, + "source": 444, + "pc": [ + 1721, + 1722, + 1723 + ] + }, + { + "teal": 1752, + "source": 446, + "pc": [ + 1724, + 1725 + ] + }, + { + "teal": 1753, + "source": 446, + "pc": [ + 1726 + ] + }, + { + "teal": 1754, + "source": 446, + "pc": [ + 1727 + ] + }, + { + "teal": 1755, + "source": 446, + "pc": [ + 1728, + 1729 + ] + }, + { + "teal": 1756, + "source": 446, + "pc": [ + 1730 + ] + }, + { + "teal": 1757, + "source": 446, + "pc": [ + 1731 + ] + }, + { + "teal": 1758, + "source": 446, + "pc": [ + 1732 + ] + }, + { + "teal": 1762, + "source": 447, + "pc": [ + 1733 + ] + }, + { + "teal": 1763, + "source": 447, + "pc": [ + 1734 + ] + }, + { + "teal": 1764, + "source": 447, + "pc": [ + 1735 + ] + }, + { + "teal": 1765, + "source": 447, + "pc": [ + 1736 + ] + }, + { + "teal": 1768, + "source": 447, + "pc": [ + 1737 + ] + }, + { + "teal": 1772, + "source": 448, + "pc": [ + 1738, + 1739 + ] + }, + { + "teal": 1773, + "source": 448, + "pc": [ + 1740 + ] + }, + { + "teal": 1774, + "source": 448, + "pc": [ + 1741 + ] + }, + { + "teal": 1777, + "source": 448, + "pc": [ + 1742 + ] + }, + { + "teal": 1785, + "source": 451, + "pc": [ + 1743 + ] + }, + { + "teal": 1786, + "source": 451, + "pc": [ + 1744, + 1745 + ] + }, + { + "teal": 1787, + "source": 451, + "pc": [ + 1746, + 1747 + ] + }, + { + "teal": 1791, + "source": 452, + "pc": [ + 1748, + 1749 + ] + }, + { + "teal": 1792, + "source": 452, + "pc": [ + 1750, + 1751 + ] + }, + { + "teal": 1796, + "source": 453, + "pc": [ + 1752, + 1753 + ] + }, + { + "teal": 1797, + "source": 453, + "pc": [ + 1754, + 1755 + ] + }, + { + "teal": 1801, + "source": 454, + "pc": [ + 1756, + 1757 + ] + }, + { + "teal": 1802, + "source": 454, + "pc": [ + 1758, + 1759 + ] + }, + { + "teal": 1805, + "source": 451, + "pc": [ + 1760 + ] + }, + { + "teal": 1806, + "source": 451, + "pc": [ + 1761, + 1762 + ] + }, + { + "teal": 1809, + "source": 451, + "pc": [ + 1763 + ] + }, + { + "teal": 1810, + "source": 444, + "pc": [ + 1764 + ] + }, + { + "teal": 1815, + "source": 467, + "pc": [ + 1765, + 1766, + 1767 + ] + }, + { + "teal": 1816, + "source": 467, + "pc": [ + 1768, + 1769, + 1770 + ] + }, + { + "teal": 1819, + "source": 467, + "pc": [ + 1771, + 1772, + 1773 + ] + }, + { + "teal": 1820, + "source": 467, + "pc": [ + 1774 + ] + }, + { + "teal": 1821, + "source": 467, + "pc": [ + 1775 + ] + }, + { + "teal": 1833, + "source": 467, + "pc": [ + 1776, + 1777, + 1778 + ] + }, + { + "teal": 1837, + "source": 468, + "pc": [ + 1779, + 1780, + 1781 + ] + }, + { + "teal": 1838, + "source": 468, + "pc": [ + 1782 + ] + }, + { + "teal": 1842, + "source": 469, + "pc": [ + 1783, + 1784, + 1785, + 1786, + 1787, + 1788, + 1789, + 1790, + 1791, + 1792 + ] + }, + { + "teal": 1843, + "source": 469, + "pc": [ + 1793, + 1794 + ] + }, + { + "teal": 1844, + "source": 469, + "pc": [ + 1795 + ] + }, + { + "teal": 1845, + "source": 467, + "pc": [ + 1796 + ] + }, + { + "teal": 1850, + "source": 480, + "pc": [ + 1797, + 1798, + 1799 + ] + }, + { + "teal": 1851, + "source": 480, + "pc": [ + 1800 + ] + }, + { + "teal": 1852, + "source": 480, + "pc": [ + 1801 + ] + }, + { + "teal": 1863, + "source": 480, + "pc": [ + 1802, + 1803, + 1804 + ] + }, + { + "teal": 1866, + "source": 480, + "pc": [ + 1805, + 1806 + ] + }, + { + "teal": 1867, + "source": 480, + "pc": [ + 1807, + 1808 + ] + }, + { + "teal": 1874, + "source": 482, + "pc": [ + 1809 + ] + }, + { + "teal": 1875, + "source": 482, + "pc": [ + 1810 + ] + }, + { + "teal": 1876, + "source": 482, + "pc": [ + 1811, + 1812 + ] + }, + { + "teal": 1877, + "source": 482, + "pc": [ + 1813, + 1814 + ] + }, + { + "teal": 1878, + "source": 482, + "pc": [ + 1815, + 1816 + ] + }, + { + "teal": 1882, + "source": 483, + "pc": [ + 1817 + ] + }, + { + "teal": 1883, + "source": 483, + "pc": [ + 1818 + ] + }, + { + "teal": 1884, + "source": 483, + "pc": [ + 1819, + 1820 + ] + }, + { + "teal": 1888, + "source": 484, + "pc": [ + 1821 + ] + }, + { + "teal": 1889, + "source": 484, + "pc": [ + 1822 + ] + }, + { + "teal": 1890, + "source": 484, + "pc": [ + 1823 + ] + }, + { + "teal": 1891, + "source": 484, + "pc": [ + 1824, + 1825 + ] + }, + { + "teal": 1894, + "source": 482, + "pc": [ + 1826 + ] + }, + { + "teal": 1895, + "source": 482, + "pc": [ + 1827, + 1828 + ] + }, + { + "teal": 1898, + "source": 482, + "pc": [ + 1829 + ] + }, + { + "teal": 1899, + "source": 482, + "pc": [ + 1830, + 1831 + ] + }, + { + "teal": 1900, + "source": 482, + "pc": [ + 1832 + ] + }, + { + "teal": 1901, + "source": 482, + "pc": [ + 1833 + ] + }, + { + "teal": 1902, + "source": 482, + "pc": [ + 1834, + 1835 + ] + }, + { + "teal": 1903, + "source": 482, + "pc": [ + 1836, + 1837, + 1838 + ] + }, + { + "teal": 1904, + "source": 482, + "pc": [ + 1839, + 1840 + ] + }, + { + "teal": 1908, + "source": 492, + "pc": [ + 1841, + 1842 + ] + }, + { + "teal": 1909, + "source": 492, + "pc": [ + 1843, + 1844 + ] + }, + { + "teal": 1913, + "source": 494, + "pc": [ + 1845, + 1846 + ] + }, + { + "teal": 1914, + "source": 494, + "pc": [ + 1847, + 1848, + 1849 + ] + }, + { + "teal": 1915, + "source": 494, + "pc": [ + 1850 + ] + }, + { + "teal": 1916, + "source": 494, + "pc": [ + 1851, + 1852 + ] + }, + { + "teal": 1917, + "source": 494, + "pc": [ + 1853 + ] + }, + { + "teal": 1918, + "source": 494, + "pc": [ + 1854, + 1855 + ] + }, + { + "teal": 1923, + "source": 495, + "pc": [ + 1856, + 1857, + 1858 + ] + }, + { + "teal": 1924, + "source": 495, + "pc": [ + 1859, + 1860 + ] + }, + { + "teal": 1925, + "source": 495, + "pc": [ + 1861 + ] + }, + { + "teal": 1926, + "source": 495, + "pc": [ + 1862 + ] + }, + { + "teal": 1927, + "source": 495, + "pc": [ + 1863 + ] + }, + { + "teal": 1928, + "source": 495, + "pc": [ + 1864, + 1865, + 1866 + ] + }, + { + "teal": 1933, + "source": 496, + "pc": [ + 1867, + 1868 + ] + }, + { + "teal": 1934, + "source": 496, + "pc": [ + 1869, + 1870 + ] + }, + { + "teal": 1935, + "source": 496, + "pc": [ + 1871 + ] + }, + { + "teal": 1936, + "source": 496, + "pc": [ + 1872 + ] + }, + { + "teal": 1937, + "source": 496, + "pc": [ + 1873, + 1874 + ] + }, + { + "teal": 1941, + "source": 497, + "pc": [ + 1875, + 1876, + 1877, + 1878, + 1879, + 1880, + 1881, + 1882, + 1883, + 1884, + 1885, + 1886, + 1887, + 1888, + 1889, + 1890, + 1891, + 1892, + 1893, + 1894, + 1895, + 1896, + 1897, + 1898, + 1899, + 1900, + 1901, + 1902 + ] + }, + { + "teal": 1942, + "source": 497, + "pc": [ + 1903, + 1904 + ] + }, + { + "teal": 1943, + "source": 497, + "pc": [ + 1905 + ] + }, + { + "teal": 1944, + "source": 497, + "pc": [ + 1906 + ] + }, + { + "teal": 1945, + "source": 497, + "pc": [ + 1907 + ] + }, + { + "teal": 1949, + "source": 500, + "pc": [ + 1908, + 1909 + ] + }, + { + "teal": 1950, + "source": 500, + "pc": [ + 1910, + 1911 + ] + }, + { + "teal": 1951, + "source": 500, + "pc": [ + 1912 + ] + }, + { + "teal": 1954, + "source": 500, + "pc": [ + 1913 + ] + }, + { + "teal": 1959, + "source": 503, + "pc": [ + 1914, + 1915 + ] + }, + { + "teal": 1960, + "source": 503, + "pc": [ + 1916, + 1917 + ] + }, + { + "teal": 1961, + "source": 503, + "pc": [ + 1918 + ] + }, + { + "teal": 1965, + "source": 504, + "pc": [ + 1919, + 1920 + ] + }, + { + "teal": 1966, + "source": 504, + "pc": [ + 1921 + ] + }, + { + "teal": 1967, + "source": 504, + "pc": [ + 1922 + ] + }, + { + "teal": 1968, + "source": 504, + "pc": [ + 1923 + ] + }, + { + "teal": 1969, + "source": 504, + "pc": [ + 1924, + 1925 + ] + }, + { + "teal": 1970, + "source": 504, + "pc": [ + 1926 + ] + }, + { + "teal": 1971, + "source": 504, + "pc": [ + 1927 + ] + }, + { + "teal": 1975, + "source": 509, + "pc": [ + 1928, + 1929 + ] + }, + { + "teal": 1976, + "source": 509, + "pc": [ + 1930, + 1931, + 1932 + ] + }, + { + "teal": 1977, + "source": 509, + "pc": [ + 1933 + ] + }, + { + "teal": 1978, + "source": 509, + "pc": [ + 1934 + ] + }, + { + "teal": 1979, + "source": 509, + "pc": [ + 1935 + ] + }, + { + "teal": 1980, + "source": 509, + "pc": [ + 1936, + 1937 + ] + }, + { + "teal": 1984, + "source": 510, + "pc": [ + 1938, + 1939, + 1940 + ] + }, + { + "teal": 1985, + "source": 510, + "pc": [ + 1941, + 1942 + ] + }, + { + "teal": 1989, + "source": 511, + "pc": [ + 1943, + 1944 + ] + }, + { + "teal": 1990, + "source": 511, + "pc": [ + 1945, + 1946 + ] + }, + { + "teal": 1995, + "source": 516, + "pc": [ + 1947, + 1948 + ] + }, + { + "teal": 1996, + "source": 516, + "pc": [ + 1949, + 1950, + 1951 + ] + }, + { + "teal": 2002, + "source": 517, + "pc": [ + 1952 + ] + }, + { + "teal": 2003, + "source": 517, + "pc": [ + 1953 + ] + }, + { + "teal": 2004, + "source": 517, + "pc": [ + 1954 + ] + }, + { + "teal": 2005, + "source": 517, + "pc": [ + 1955 + ] + }, + { + "teal": 2006, + "source": 517, + "pc": [ + 1956, + 1957, + 1958 + ] + }, + { + "teal": 2014, + "source": 519, + "pc": [ + 1959 + ] + }, + { + "teal": 2015, + "source": 519, + "pc": [ + 1960 + ] + }, + { + "teal": 2016, + "source": 519, + "pc": [ + 1961, + 1962 + ] + }, + { + "teal": 2017, + "source": 519, + "pc": [ + 1963, + 1964 + ] + }, + { + "teal": 2018, + "source": 519, + "pc": [ + 1965, + 1966 + ] + }, + { + "teal": 2022, + "source": 520, + "pc": [ + 1967 + ] + }, + { + "teal": 2023, + "source": 520, + "pc": [ + 1968 + ] + }, + { + "teal": 2024, + "source": 520, + "pc": [ + 1969, + 1970 + ] + }, + { + "teal": 2028, + "source": 521, + "pc": [ + 1971 + ] + }, + { + "teal": 2029, + "source": 521, + "pc": [ + 1972 + ] + }, + { + "teal": 2030, + "source": 521, + "pc": [ + 1973 + ] + }, + { + "teal": 2031, + "source": 521, + "pc": [ + 1974, + 1975 + ] + }, + { + "teal": 2032, + "source": 521, + "pc": [ + 1976, + 1977, + 1978, + 1979, + 1980, + 1981, + 1982, + 1983, + 1984, + 1985 + ] + }, + { + "teal": 2033, + "source": 521, + "pc": [ + 1986, + 1987 + ] + }, + { + "teal": 2036, + "source": 519, + "pc": [ + 1988 + ] + }, + { + "teal": 2037, + "source": 519, + "pc": [ + 1989, + 1990 + ] + }, + { + "teal": 2040, + "source": 519, + "pc": [ + 1991 + ] + }, + { + "teal": 2041, + "source": 519, + "pc": [ + 1992, + 1993 + ] + }, + { + "teal": 2042, + "source": 519, + "pc": [ + 1994 + ] + }, + { + "teal": 2043, + "source": 519, + "pc": [ + 1995 + ] + }, + { + "teal": 2044, + "source": 519, + "pc": [ + 1996, + 1997 + ] + }, + { + "teal": 2045, + "source": 519, + "pc": [ + 1998, + 1999, + 2000 + ] + }, + { + "teal": 2046, + "source": 519, + "pc": [ + 2001 + ] + }, + { + "teal": 2047, + "source": 519, + "pc": [ + 2002, + 2003 + ] + }, + { + "teal": 2051, + "source": 523, + "pc": [ + 2004, + 2005 + ] + }, + { + "teal": 2052, + "source": 523, + "pc": [ + 2006, + 2007 + ] + }, + { + "teal": 2053, + "source": 523, + "pc": [ + 2008 + ] + }, + { + "teal": 2054, + "source": 523, + "pc": [ + 2009, + 2010 + ] + }, + { + "teal": 2060, + "source": 528, + "pc": [ + 2011 + ] + }, + { + "teal": 2061, + "source": 528, + "pc": [ + 2012 + ] + }, + { + "teal": 2062, + "source": 528, + "pc": [ + 2013 + ] + }, + { + "teal": 2063, + "source": 528, + "pc": [ + 2014 + ] + }, + { + "teal": 2064, + "source": 528, + "pc": [ + 2015, + 2016, + 2017 + ] + }, + { + "teal": 2072, + "source": 529, + "pc": [ + 2018 + ] + }, + { + "teal": 2073, + "source": 529, + "pc": [ + 2019 + ] + }, + { + "teal": 2074, + "source": 529, + "pc": [ + 2020, + 2021 + ] + }, + { + "teal": 2075, + "source": 529, + "pc": [ + 2022, + 2023 + ] + }, + { + "teal": 2076, + "source": 529, + "pc": [ + 2024, + 2025 + ] + }, + { + "teal": 2080, + "source": 530, + "pc": [ + 2026 + ] + }, + { + "teal": 2081, + "source": 530, + "pc": [ + 2027 + ] + }, + { + "teal": 2082, + "source": 530, + "pc": [ + 2028, + 2029 + ] + }, + { + "teal": 2086, + "source": 531, + "pc": [ + 2030 + ] + }, + { + "teal": 2087, + "source": 531, + "pc": [ + 2031 + ] + }, + { + "teal": 2088, + "source": 531, + "pc": [ + 2032 + ] + }, + { + "teal": 2089, + "source": 531, + "pc": [ + 2033, + 2034 + ] + }, + { + "teal": 2092, + "source": 529, + "pc": [ + 2035 + ] + }, + { + "teal": 2093, + "source": 529, + "pc": [ + 2036, + 2037 + ] + }, + { + "teal": 2096, + "source": 529, + "pc": [ + 2038 + ] + }, + { + "teal": 2097, + "source": 529, + "pc": [ + 2039, + 2040 + ] + }, + { + "teal": 2098, + "source": 529, + "pc": [ + 2041 + ] + }, + { + "teal": 2099, + "source": 529, + "pc": [ + 2042 + ] + }, + { + "teal": 2100, + "source": 529, + "pc": [ + 2043, + 2044 + ] + }, + { + "teal": 2101, + "source": 529, + "pc": [ + 2045, + 2046, + 2047 + ] + }, + { + "teal": 2102, + "source": 529, + "pc": [ + 2048, + 2049 + ] + }, + { + "teal": 2103, + "source": 528, + "pc": [ + 2050, + 2051, + 2052 + ] + }, + { + "teal": 2111, + "source": 535, + "pc": [ + 2053 + ] + }, + { + "teal": 2112, + "source": 535, + "pc": [ + 2054 + ] + }, + { + "teal": 2113, + "source": 535, + "pc": [ + 2055, + 2056 + ] + }, + { + "teal": 2114, + "source": 535, + "pc": [ + 2057, + 2058 + ] + }, + { + "teal": 2115, + "source": 535, + "pc": [ + 2059, + 2060 + ] + }, + { + "teal": 2119, + "source": 536, + "pc": [ + 2061, + 2062 + ] + }, + { + "teal": 2120, + "source": 536, + "pc": [ + 2063, + 2064 + ] + }, + { + "teal": 2124, + "source": 537, + "pc": [ + 2065 + ] + }, + { + "teal": 2125, + "source": 537, + "pc": [ + 2066 + ] + }, + { + "teal": 2126, + "source": 537, + "pc": [ + 2067 + ] + }, + { + "teal": 2127, + "source": 537, + "pc": [ + 2068 + ] + }, + { + "teal": 2128, + "source": 537, + "pc": [ + 2069 + ] + }, + { + "teal": 2129, + "source": 537, + "pc": [ + 2070 + ] + }, + { + "teal": 2130, + "source": 537, + "pc": [ + 2071 + ] + }, + { + "teal": 2131, + "source": 537, + "pc": [ + 2072, + 2073, + 2074 + ] + }, + { + "teal": 2132, + "source": 537, + "pc": [ + 2075 + ] + }, + { + "teal": 2133, + "source": 537, + "pc": [ + 2076 + ] + }, + { + "teal": 2134, + "source": 537, + "pc": [ + 2077, + 2078 + ] + }, + { + "teal": 2137, + "source": 535, + "pc": [ + 2079 + ] + }, + { + "teal": 2138, + "source": 535, + "pc": [ + 2080, + 2081 + ] + }, + { + "teal": 2141, + "source": 535, + "pc": [ + 2082 + ] + }, + { + "teal": 2142, + "source": 535, + "pc": [ + 2083, + 2084 + ] + }, + { + "teal": 2143, + "source": 535, + "pc": [ + 2085 + ] + }, + { + "teal": 2144, + "source": 535, + "pc": [ + 2086 + ] + }, + { + "teal": 2145, + "source": 535, + "pc": [ + 2087, + 2088 + ] + }, + { + "teal": 2146, + "source": 535, + "pc": [ + 2089, + 2090, + 2091 + ] + }, + { + "teal": 2147, + "source": 535, + "pc": [ + 2092, + 2093 + ] + }, + { + "teal": 2157, + "source": 544, + "pc": [ + 2094 + ] + }, + { + "teal": 2158, + "source": 544, + "pc": [ + 2095 + ] + }, + { + "teal": 2159, + "source": 544, + "pc": [ + 2096, + 2097 + ] + }, + { + "teal": 2160, + "source": 544, + "pc": [ + 2098, + 2099, + 2100, + 2101, + 2102, + 2103 + ] + }, + { + "teal": 2161, + "source": 544, + "pc": [ + 2104, + 2105 + ] + }, + { + "teal": 2165, + "source": 545, + "pc": [ + 2106 + ] + }, + { + "teal": 2166, + "source": 545, + "pc": [ + 2107 + ] + }, + { + "teal": 2167, + "source": 545, + "pc": [ + 2108, + 2109 + ] + }, + { + "teal": 2171, + "source": 546, + "pc": [ + 2110 + ] + }, + { + "teal": 2172, + "source": 546, + "pc": [ + 2111 + ] + }, + { + "teal": 2173, + "source": 546, + "pc": [ + 2112 + ] + }, + { + "teal": 2174, + "source": 546, + "pc": [ + 2113, + 2114 + ] + }, + { + "teal": 2177, + "source": 544, + "pc": [ + 2115 + ] + }, + { + "teal": 2178, + "source": 544, + "pc": [ + 2116, + 2117 + ] + }, + { + "teal": 2181, + "source": 544, + "pc": [ + 2118 + ] + }, + { + "teal": 2182, + "source": 544, + "pc": [ + 2119, + 2120 + ] + }, + { + "teal": 2183, + "source": 544, + "pc": [ + 2121 + ] + }, + { + "teal": 2184, + "source": 544, + "pc": [ + 2122 + ] + }, + { + "teal": 2185, + "source": 544, + "pc": [ + 2123, + 2124 + ] + }, + { + "teal": 2186, + "source": 544, + "pc": [ + 2125, + 2126, + 2127 + ] + }, + { + "teal": 2187, + "source": 544, + "pc": [ + 2128, + 2129 + ] + }, + { + "teal": 2191, + "source": 548, + "pc": [ + 2130, + 2131 + ] + }, + { + "teal": 2192, + "source": 548, + "pc": [ + 2132, + 2133, + 2134 + ] + }, + { + "teal": 2193, + "source": 548, + "pc": [ + 2135 + ] + }, + { + "teal": 2194, + "source": 548, + "pc": [ + 2136, + 2137 + ] + }, + { + "teal": 2198, + "source": 554, + "pc": [ + 2138, + 2139 + ] + }, + { + "teal": 2199, + "source": 554, + "pc": [ + 2140, + 2141 + ] + }, + { + "teal": 2200, + "source": 554, + "pc": [ + 2142 + ] + }, + { + "teal": 2201, + "source": 554, + "pc": [ + 2143, + 2144 + ] + }, + { + "teal": 2202, + "source": 554, + "pc": [ + 2145 + ] + }, + { + "teal": 2203, + "source": 554, + "pc": [ + 2146 + ] + }, + { + "teal": 2204, + "source": 554, + "pc": [ + 2147, + 2148 + ] + }, + { + "teal": 2205, + "source": 554, + "pc": [ + 2149, + 2150 + ] + }, + { + "teal": 2206, + "source": 554, + "pc": [ + 2151 + ] + }, + { + "teal": 2207, + "source": 554, + "pc": [ + 2152 + ] + }, + { + "teal": 2208, + "source": 554, + "pc": [ + 2153, + 2154 + ] + }, + { + "teal": 2212, + "source": 555, + "pc": [ + 2155 + ] + }, + { + "teal": 2213, + "source": 555, + "pc": [ + 2156, + 2157 + ] + }, + { + "teal": 2217, + "source": 556, + "pc": [ + 2158, + 2159, + 2160 + ] + }, + { + "teal": 2218, + "source": 556, + "pc": [ + 2161, + 2162 + ] + }, + { + "teal": 2223, + "source": 564, + "pc": [ + 2163, + 2164 + ] + }, + { + "teal": 2224, + "source": 564, + "pc": [ + 2165, + 2166, + 2167 + ] + }, + { + "teal": 2225, + "source": 564, + "pc": [ + 2168 + ] + }, + { + "teal": 2226, + "source": 564, + "pc": [ + 2169, + 2170 + ] + }, + { + "teal": 2227, + "source": 564, + "pc": [ + 2171 + ] + }, + { + "teal": 2228, + "source": 564, + "pc": [ + 2172, + 2173, + 2174 + ] + }, + { + "teal": 2233, + "source": 565, + "pc": [ + 2175, + 2176, + 2177, + 2178, + 2179, + 2180, + 2181, + 2182, + 2183, + 2184, + 2185, + 2186, + 2187, + 2188, + 2189, + 2190, + 2191, + 2192, + 2193, + 2194, + 2195, + 2196, + 2197, + 2198, + 2199, + 2200, + 2201, + 2202, + 2203, + 2204 + ] + }, + { + "teal": 2234, + "source": 565, + "pc": [ + 2205 + ] + }, + { + "teal": 2238, + "source": 566, + "pc": [ + 2206 + ] + }, + { + "teal": 2239, + "source": 566, + "pc": [ + 2207, + 2208 + ] + }, + { + "teal": 2244, + "source": 572, + "pc": [ + 2209 + ] + }, + { + "teal": 2245, + "source": 572, + "pc": [ + 2210, + 2211 + ] + }, + { + "teal": 2249, + "source": 573, + "pc": [ + 2212 + ] + }, + { + "teal": 2250, + "source": 573, + "pc": [ + 2213, + 2214 + ] + }, + { + "teal": 2255, + "source": 574, + "pc": [ + 2215, + 2216 + ] + }, + { + "teal": 2256, + "source": 574, + "pc": [ + 2217, + 2218, + 2219 + ] + }, + { + "teal": 2262, + "source": 576, + "pc": [ + 2220, + 2221 + ] + }, + { + "teal": 2263, + "source": 576, + "pc": [ + 2222, + 2223 + ] + }, + { + "teal": 2264, + "source": 576, + "pc": [ + 2224, + 2225, + 2226 + ] + }, + { + "teal": 2265, + "source": 576, + "pc": [ + 2227 + ] + }, + { + "teal": 2266, + "source": 576, + "pc": [ + 2228, + 2229 + ] + }, + { + "teal": 2267, + "source": 576, + "pc": [ + 2230 + ] + }, + { + "teal": 2268, + "source": 576, + "pc": [ + 2231, + 2232 + ] + }, + { + "teal": 2269, + "source": 576, + "pc": [ + 2233 + ] + }, + { + "teal": 2270, + "source": 575, + "pc": [ + 2234, + 2235 + ] + }, + { + "teal": 2275, + "source": 580, + "pc": [ + 2236, + 2237 + ] + }, + { + "teal": 2276, + "source": 580, + "pc": [ + 2238, + 2239 + ] + }, + { + "teal": 2277, + "source": 580, + "pc": [ + 2240, + 2241, + 2242 + ] + }, + { + "teal": 2278, + "source": 580, + "pc": [ + 2243 + ] + }, + { + "teal": 2279, + "source": 580, + "pc": [ + 2244 + ] + }, + { + "teal": 2280, + "source": 580, + "pc": [ + 2245, + 2246, + 2247 + ] + }, + { + "teal": 2285, + "source": 584, + "pc": [ + 2248, + 2249 + ] + }, + { + "teal": 2286, + "source": 584, + "pc": [ + 2250 + ] + }, + { + "teal": 2287, + "source": 584, + "pc": [ + 2251 + ] + }, + { + "teal": 2288, + "source": 584, + "pc": [ + 2252 + ] + }, + { + "teal": 2289, + "source": 584, + "pc": [ + 2253 + ] + }, + { + "teal": 2290, + "source": 584, + "pc": [ + 2254 + ] + }, + { + "teal": 2291, + "source": 584, + "pc": [ + 2255, + 2256 + ] + }, + { + "teal": 2292, + "source": 584, + "pc": [ + 2257 + ] + }, + { + "teal": 2293, + "source": 584, + "pc": [ + 2258 + ] + }, + { + "teal": 2294, + "source": 584, + "pc": [ + 2259, + 2260 + ] + }, + { + "teal": 2295, + "source": 584, + "pc": [ + 2261 + ] + }, + { + "teal": 2296, + "source": 584, + "pc": [ + 2262 + ] + }, + { + "teal": 2297, + "source": 584, + "pc": [ + 2263, + 2264 + ] + }, + { + "teal": 2301, + "source": 587, + "pc": [ + 2265, + 2266 + ] + }, + { + "teal": 2302, + "source": 587, + "pc": [ + 2267, + 2268, + 2269 + ] + }, + { + "teal": 2303, + "source": 587, + "pc": [ + 2270 + ] + }, + { + "teal": 2304, + "source": 587, + "pc": [ + 2271, + 2272 + ] + }, + { + "teal": 2305, + "source": 587, + "pc": [ + 2273 + ] + }, + { + "teal": 2306, + "source": 587, + "pc": [ + 2274 + ] + }, + { + "teal": 2307, + "source": 587, + "pc": [ + 2275, + 2276 + ] + }, + { + "teal": 2308, + "source": 587, + "pc": [ + 2277 + ] + }, + { + "teal": 2309, + "source": 587, + "pc": [ + 2278 + ] + }, + { + "teal": 2310, + "source": 587, + "pc": [ + 2279 + ] + }, + { + "teal": 2311, + "source": 587, + "pc": [ + 2280 + ] + }, + { + "teal": 2312, + "source": 587, + "pc": [ + 2281 + ] + }, + { + "teal": 2313, + "source": 587, + "pc": [ + 2282 + ] + }, + { + "teal": 2314, + "source": 587, + "pc": [ + 2283, + 2284 + ] + }, + { + "teal": 2318, + "source": 591, + "pc": [ + 2285, + 2286, + 2287, + 2288, + 2289, + 2290, + 2291, + 2292, + 2293, + 2294, + 2295, + 2296, + 2297, + 2298, + 2299, + 2300, + 2301, + 2302, + 2303, + 2304, + 2305, + 2306 + ] + }, + { + "teal": 2319, + "source": 591, + "pc": [ + 2307, + 2308 + ] + }, + { + "teal": 2320, + "source": 591, + "pc": [ + 2309, + 2310, + 2311 + ] + }, + { + "teal": 2321, + "source": 591, + "pc": [ + 2312 + ] + }, + { + "teal": 2322, + "source": 591, + "pc": [ + 2313 + ] + }, + { + "teal": 2330, + "source": 595, + "pc": [ + 2314, + 2315 + ] + }, + { + "teal": 2331, + "source": 595, + "pc": [ + 2316 + ] + }, + { + "teal": 2332, + "source": 595, + "pc": [ + 2317 + ] + }, + { + "teal": 2333, + "source": 595, + "pc": [ + 2318, + 2319, + 2320 + ] + }, + { + "teal": 2338, + "source": 598, + "pc": [ + 2321, + 2322 + ] + }, + { + "teal": 2339, + "source": 598, + "pc": [ + 2323, + 2324 + ] + }, + { + "teal": 2340, + "source": 598, + "pc": [ + 2325 + ] + }, + { + "teal": 2343, + "source": 598, + "pc": [ + 2326 + ] + }, + { + "teal": 2348, + "source": 600, + "pc": [ + 2327, + 2328, + 2329, + 2330, + 2331, + 2332, + 2333, + 2334, + 2335, + 2336, + 2337, + 2338, + 2339, + 2340, + 2341, + 2342, + 2343, + 2344, + 2345, + 2346, + 2347 + ] + }, + { + "teal": 2349, + "source": 600, + "pc": [ + 2348, + 2349 + ] + }, + { + "teal": 2350, + "source": 600, + "pc": [ + 2350, + 2351, + 2352 + ] + }, + { + "teal": 2351, + "source": 600, + "pc": [ + 2353 + ] + }, + { + "teal": 2352, + "source": 600, + "pc": [ + 2354 + ] + }, + { + "teal": 2357, + "source": 603, + "pc": [ + 2355, + 2356 + ] + }, + { + "teal": 2358, + "source": 603, + "pc": [ + 2357, + 2358, + 2359 + ] + }, + { + "teal": 2363, + "source": 606, + "pc": [ + 2360, + 2361 + ] + }, + { + "teal": 2364, + "source": 606, + "pc": [ + 2362, + 2363 + ] + }, + { + "teal": 2365, + "source": 606, + "pc": [ + 2364 + ] + }, + { + "teal": 2366, + "source": 606, + "pc": [ + 2365 + ] + }, + { + "teal": 2367, + "source": 606, + "pc": [ + 2366, + 2367 + ] + }, + { + "teal": 2368, + "source": 606, + "pc": [ + 2368, + 2369, + 2370 + ] + }, + { + "teal": 2369, + "source": 606, + "pc": [ + 2371 + ] + }, + { + "teal": 2370, + "source": 606, + "pc": [ + 2372 + ] + }, + { + "teal": 2371, + "source": 606, + "pc": [ + 2373 + ] + }, + { + "teal": 2372, + "source": 606, + "pc": [ + 2374 + ] + }, + { + "teal": 2373, + "source": 606, + "pc": [ + 2375 + ] + }, + { + "teal": 2374, + "source": 606, + "pc": [ + 2376 + ] + }, + { + "teal": 2375, + "source": 606, + "pc": [ + 2377 + ] + }, + { + "teal": 2376, + "source": 606, + "pc": [ + 2378, + 2379 + ] + }, + { + "teal": 2380, + "source": 608, + "pc": [ + 2380, + 2381 + ] + }, + { + "teal": 2381, + "source": 608, + "pc": [ + 2382, + 2383 + ] + }, + { + "teal": 2382, + "source": 608, + "pc": [ + 2384 + ] + }, + { + "teal": 2383, + "source": 608, + "pc": [ + 2385, + 2386 + ] + }, + { + "teal": 2387, + "source": 609, + "pc": [ + 2387 + ] + }, + { + "teal": 2388, + "source": 609, + "pc": [ + 2388 + ] + }, + { + "teal": 2389, + "source": 609, + "pc": [ + 2389, + 2390 + ] + }, + { + "teal": 2390, + "source": 609, + "pc": [ + 2391 + ] + }, + { + "teal": 2391, + "source": 609, + "pc": [ + 2392, + 2393 + ] + }, + { + "teal": 2392, + "source": 609, + "pc": [ + 2394, + 2395 + ] + }, + { + "teal": 2393, + "source": 609, + "pc": [ + 2396 + ] + }, + { + "teal": 2394, + "source": 609, + "pc": [ + 2397, + 2398 + ] + }, + { + "teal": 2395, + "source": 609, + "pc": [ + 2399, + 2400 + ] + }, + { + "teal": 2396, + "source": 609, + "pc": [ + 2401, + 2402 + ] + }, + { + "teal": 2397, + "source": 609, + "pc": [ + 2403, + 2404 + ] + }, + { + "teal": 2398, + "source": 609, + "pc": [ + 2405 + ] + }, + { + "teal": 2402, + "source": 610, + "pc": [ + 2406, + 2407, + 2408, + 2409, + 2410, + 2411, + 2412, + 2413, + 2414, + 2415, + 2416 + ] + }, + { + "teal": 2403, + "source": 610, + "pc": [ + 2417, + 2418 + ] + }, + { + "teal": 2404, + "source": 610, + "pc": [ + 2419, + 2420, + 2421 + ] + }, + { + "teal": 2405, + "source": 610, + "pc": [ + 2422 + ] + }, + { + "teal": 2406, + "source": 610, + "pc": [ + 2423 + ] + }, + { + "teal": 2410, + "source": 611, + "pc": [ + 2424, + 2425, + 2426, + 2427, + 2428, + 2429, + 2430, + 2431, + 2432, + 2433, + 2434 + ] + }, + { + "teal": 2411, + "source": 611, + "pc": [ + 2435, + 2436 + ] + }, + { + "teal": 2412, + "source": 611, + "pc": [ + 2437, + 2438, + 2439 + ] + }, + { + "teal": 2413, + "source": 611, + "pc": [ + 2440 + ] + }, + { + "teal": 2414, + "source": 611, + "pc": [ + 2441 + ] + }, + { + "teal": 2422, + "source": 612, + "pc": [ + 2442 + ] + }, + { + "teal": 2423, + "source": 612, + "pc": [ + 2443 + ] + }, + { + "teal": 2424, + "source": 612, + "pc": [ + 2444, + 2445 + ] + }, + { + "teal": 2428, + "source": 613, + "pc": [ + 2446, + 2447 + ] + }, + { + "teal": 2429, + "source": 613, + "pc": [ + 2448, + 2449 + ] + }, + { + "teal": 2433, + "source": 614, + "pc": [ + 2450, + 2451, + 2452 + ] + }, + { + "teal": 2434, + "source": 614, + "pc": [ + 2453, + 2454 + ] + }, + { + "teal": 2438, + "source": 615, + "pc": [ + 2455, + 2456, + 2457, + 2458, + 2459, + 2460, + 2461, + 2462, + 2463, + 2464, + 2465, + 2466, + 2467, + 2468, + 2469, + 2470, + 2471, + 2472, + 2473, + 2474, + 2475, + 2476, + 2477, + 2478, + 2479, + 2480, + 2481, + 2482, + 2483, + 2484, + 2485, + 2486, + 2487, + 2488, + 2489, + 2490, + 2491, + 2492, + 2493, + 2494, + 2495, + 2496, + 2497, + 2498, + 2499, + 2500, + 2501 + ] + }, + { + "teal": 2439, + "source": 615, + "pc": [ + 2502, + 2503 + ] + }, + { + "teal": 2442, + "source": 612, + "pc": [ + 2504 + ] + }, + { + "teal": 2443, + "source": 612, + "pc": [ + 2505, + 2506 + ] + }, + { + "teal": 2446, + "source": 612, + "pc": [ + 2507 + ] + }, + { + "teal": 2450, + "source": 618, + "pc": [ + 2508, + 2509 + ] + }, + { + "teal": 2451, + "source": 618, + "pc": [ + 2510, + 2511 + ] + }, + { + "teal": 2452, + "source": 603, + "pc": [ + 2512, + 2513, + 2514 + ] + }, + { + "teal": 2457, + "source": 619, + "pc": [ + 2515, + 2516 + ] + }, + { + "teal": 2458, + "source": 619, + "pc": [ + 2517, + 2518, + 2519 + ] + }, + { + "teal": 2459, + "source": 619, + "pc": [ + 2520 + ] + }, + { + "teal": 2460, + "source": 619, + "pc": [ + 2521 + ] + }, + { + "teal": 2461, + "source": 619, + "pc": [ + 2522 + ] + }, + { + "teal": 2462, + "source": 619, + "pc": [ + 2523, + 2524, + 2525 + ] + }, + { + "teal": 2470, + "source": 623, + "pc": [ + 2526, + 2527 + ] + }, + { + "teal": 2471, + "source": 623, + "pc": [ + 2528, + 2529 + ] + }, + { + "teal": 2472, + "source": 623, + "pc": [ + 2530, + 2531, + 2532 + ] + }, + { + "teal": 2473, + "source": 623, + "pc": [ + 2533 + ] + }, + { + "teal": 2474, + "source": 622, + "pc": [ + 2534 + ] + }, + { + "teal": 2475, + "source": 622, + "pc": [ + 2535 + ] + }, + { + "teal": 2476, + "source": 624, + "pc": [ + 2536, + 2537 + ] + }, + { + "teal": 2477, + "source": 622, + "pc": [ + 2538 + ] + }, + { + "teal": 2478, + "source": 622, + "pc": [ + 2539 + ] + }, + { + "teal": 2479, + "source": 622, + "pc": [ + 2540 + ] + }, + { + "teal": 2480, + "source": 622, + "pc": [ + 2541 + ] + }, + { + "teal": 2481, + "source": 622, + "pc": [ + 2542 + ] + }, + { + "teal": 2482, + "source": 622, + "pc": [ + 2543 + ] + }, + { + "teal": 2483, + "source": 622, + "pc": [ + 2544, + 2545 + ] + }, + { + "teal": 2487, + "source": 628, + "pc": [ + 2546, + 2547 + ] + }, + { + "teal": 2488, + "source": 628, + "pc": [ + 2548, + 2549 + ] + }, + { + "teal": 2489, + "source": 628, + "pc": [ + 2550 + ] + }, + { + "teal": 2490, + "source": 628, + "pc": [ + 2551, + 2552 + ] + }, + { + "teal": 2495, + "source": 632, + "pc": [ + 2553, + 2554 + ] + }, + { + "teal": 2496, + "source": 632, + "pc": [ + 2555 + ] + }, + { + "teal": 2497, + "source": 632, + "pc": [ + 2556 + ] + }, + { + "teal": 2498, + "source": 632, + "pc": [ + 2557, + 2558, + 2559 + ] + }, + { + "teal": 2503, + "source": 633, + "pc": [ + 2560, + 2561, + 2562, + 2563, + 2564, + 2565, + 2566, + 2567, + 2568, + 2569, + 2570, + 2571, + 2572, + 2573, + 2574, + 2575, + 2576, + 2577, + 2578, + 2579, + 2580, + 2581 + ] + }, + { + "teal": 2504, + "source": 633, + "pc": [ + 2582, + 2583 + ] + }, + { + "teal": 2505, + "source": 633, + "pc": [ + 2584 + ] + }, + { + "teal": 2506, + "source": 633, + "pc": [ + 2585 + ] + }, + { + "teal": 2507, + "source": 633, + "pc": [ + 2586 + ] + }, + { + "teal": 2515, + "source": 634, + "pc": [ + 2587 + ] + }, + { + "teal": 2516, + "source": 634, + "pc": [ + 2588 + ] + }, + { + "teal": 2517, + "source": 634, + "pc": [ + 2589, + 2590 + ] + }, + { + "teal": 2521, + "source": 635, + "pc": [ + 2591, + 2592 + ] + }, + { + "teal": 2522, + "source": 635, + "pc": [ + 2593, + 2594 + ] + }, + { + "teal": 2526, + "source": 636, + "pc": [ + 2595, + 2596 + ] + }, + { + "teal": 2527, + "source": 636, + "pc": [ + 2597, + 2598, + 2599 + ] + }, + { + "teal": 2528, + "source": 636, + "pc": [ + 2600, + 2601 + ] + }, + { + "teal": 2532, + "source": 637, + "pc": [ + 2602, + 2603, + 2604, + 2605, + 2606, + 2607, + 2608, + 2609, + 2610, + 2611, + 2612, + 2613, + 2614, + 2615, + 2616, + 2617, + 2618, + 2619 + ] + }, + { + "teal": 2533, + "source": 637, + "pc": [ + 2620, + 2621 + ] + }, + { + "teal": 2536, + "source": 634, + "pc": [ + 2622 + ] + }, + { + "teal": 2537, + "source": 634, + "pc": [ + 2623, + 2624 + ] + }, + { + "teal": 2540, + "source": 634, + "pc": [ + 2625 + ] + }, + { + "teal": 2544, + "source": 639, + "pc": [ + 2626, + 2627, + 2628, + 2629, + 2630, + 2631, + 2632, + 2633, + 2634, + 2635, + 2636, + 2637, + 2638, + 2639, + 2640, + 2641, + 2642, + 2643, + 2644, + 2645, + 2646, + 2647 + ] + }, + { + "teal": 2545, + "source": 639, + "pc": [ + 2648, + 2649 + ] + }, + { + "teal": 2546, + "source": 639, + "pc": [ + 2650 + ] + }, + { + "teal": 2547, + "source": 639, + "pc": [ + 2651 + ] + }, + { + "teal": 2548, + "source": 639, + "pc": [ + 2652 + ] + }, + { + "teal": 2556, + "source": 643, + "pc": [ + 2653, + 2654 + ] + }, + { + "teal": 2557, + "source": 643, + "pc": [ + 2655 + ] + }, + { + "teal": 2558, + "source": 643, + "pc": [ + 2656 + ] + }, + { + "teal": 2559, + "source": 643, + "pc": [ + 2657 + ] + }, + { + "teal": 2560, + "source": 643, + "pc": [ + 2658, + 2659, + 2660 + ] + }, + { + "teal": 2561, + "source": 643, + "pc": [ + 2661, + 2662 + ] + }, + { + "teal": 2562, + "source": 643, + "pc": [ + 2663 + ] + }, + { + "teal": 2563, + "source": 643, + "pc": [ + 2664 + ] + }, + { + "teal": 2564, + "source": 643, + "pc": [ + 2665 + ] + }, + { + "teal": 2567, + "source": 643, + "pc": [ + 2666, + 2667, + 2668 + ] + }, + { + "teal": 2572, + "source": 646, + "pc": [ + 2669 + ] + }, + { + "teal": 2577, + "source": 654, + "pc": [ + 2670 + ] + }, + { + "teal": 2578, + "source": 654, + "pc": [ + 2671, + 2672 + ] + }, + { + "teal": 2582, + "source": 678, + "pc": [ + 2673 + ] + }, + { + "teal": 2583, + "source": 678, + "pc": [ + 2674, + 2675 + ] + }, + { + "teal": 2587, + "source": 679, + "pc": [ + 2676 + ] + }, + { + "teal": 2588, + "source": 679, + "pc": [ + 2677, + 2678 + ] + }, + { + "teal": 2593, + "source": 679, + "pc": [ + 2679, + 2680 + ] + }, + { + "teal": 2594, + "source": 679, + "pc": [ + 2681, + 2682 + ] + }, + { + "teal": 2595, + "source": 679, + "pc": [ + 2683 + ] + }, + { + "teal": 2596, + "source": 679, + "pc": [ + 2684, + 2685, + 2686 + ] + }, + { + "teal": 2601, + "source": 680, + "pc": [ + 2687, + 2688 + ] + }, + { + "teal": 2602, + "source": 680, + "pc": [ + 2689, + 2690 + ] + }, + { + "teal": 2603, + "source": 680, + "pc": [ + 2691 + ] + }, + { + "teal": 2604, + "source": 680, + "pc": [ + 2692, + 2693, + 2694 + ] + }, + { + "teal": 2609, + "source": 681, + "pc": [ + 2695 + ] + }, + { + "teal": 2610, + "source": 681, + "pc": [ + 2696 + ] + }, + { + "teal": 2611, + "source": 681, + "pc": [ + 2697, + 2698 + ] + }, + { + "teal": 2612, + "source": 681, + "pc": [ + 2699 + ] + }, + { + "teal": 2613, + "source": 681, + "pc": [ + 2700, + 2701 + ] + }, + { + "teal": 2614, + "source": 681, + "pc": [ + 2702, + 2703 + ] + }, + { + "teal": 2615, + "source": 681, + "pc": [ + 2704 + ] + }, + { + "teal": 2616, + "source": 681, + "pc": [ + 2705, + 2706 + ] + }, + { + "teal": 2617, + "source": 681, + "pc": [ + 2707, + 2708 + ] + }, + { + "teal": 2618, + "source": 681, + "pc": [ + 2709, + 2710 + ] + }, + { + "teal": 2619, + "source": 681, + "pc": [ + 2711, + 2712 + ] + }, + { + "teal": 2620, + "source": 681, + "pc": [ + 2713 + ] + }, + { + "teal": 2625, + "source": 683, + "pc": [ + 2714, + 2715 + ] + }, + { + "teal": 2626, + "source": 683, + "pc": [ + 2716 + ] + }, + { + "teal": 2627, + "source": 683, + "pc": [ + 2717 + ] + }, + { + "teal": 2628, + "source": 683, + "pc": [ + 2718 + ] + }, + { + "teal": 2629, + "source": 683, + "pc": [ + 2719 + ] + }, + { + "teal": 2630, + "source": 683, + "pc": [ + 2720, + 2721 + ] + }, + { + "teal": 2631, + "source": 683, + "pc": [ + 2722 + ] + }, + { + "teal": 2632, + "source": 683, + "pc": [ + 2723, + 2724 + ] + }, + { + "teal": 2637, + "source": 684, + "pc": [ + 2725, + 2726 + ] + }, + { + "teal": 2638, + "source": 684, + "pc": [ + 2727, + 2728, + 2729 + ] + }, + { + "teal": 2639, + "source": 684, + "pc": [ + 2730, + 2731 + ] + }, + { + "teal": 2640, + "source": 684, + "pc": [ + 2732 + ] + }, + { + "teal": 2641, + "source": 684, + "pc": [ + 2733, + 2734, + 2735 + ] + }, + { + "teal": 2647, + "source": 685, + "pc": [ + 2736, + 2737 + ] + }, + { + "teal": 2648, + "source": 685, + "pc": [ + 2738, + 2739, + 2740 + ] + }, + { + "teal": 2649, + "source": 685, + "pc": [ + 2741 + ] + }, + { + "teal": 2650, + "source": 685, + "pc": [ + 2742, + 2743 + ] + }, + { + "teal": 2651, + "source": 685, + "pc": [ + 2744 + ] + }, + { + "teal": 2652, + "source": 685, + "pc": [ + 2745, + 2746, + 2747 + ] + }, + { + "teal": 2657, + "source": 688, + "pc": [ + 2748, + 2749 + ] + }, + { + "teal": 2658, + "source": 688, + "pc": [ + 2750, + 2751 + ] + }, + { + "teal": 2659, + "source": 688, + "pc": [ + 2752, + 2753, + 2754 + ] + }, + { + "teal": 2660, + "source": 688, + "pc": [ + 2755 + ] + }, + { + "teal": 2661, + "source": 688, + "pc": [ + 2756 + ] + }, + { + "teal": 2662, + "source": 688, + "pc": [ + 2757, + 2758 + ] + }, + { + "teal": 2663, + "source": 685, + "pc": [ + 2759, + 2760, + 2761 + ] + }, + { + "teal": 2668, + "source": 692, + "pc": [ + 2762, + 2763 + ] + }, + { + "teal": 2669, + "source": 692, + "pc": [ + 2764, + 2765 + ] + }, + { + "teal": 2670, + "source": 692, + "pc": [ + 2766, + 2767, + 2768 + ] + }, + { + "teal": 2671, + "source": 692, + "pc": [ + 2769 + ] + }, + { + "teal": 2672, + "source": 692, + "pc": [ + 2770 + ] + }, + { + "teal": 2673, + "source": 692, + "pc": [ + 2771, + 2772 + ] + }, + { + "teal": 2678, + "source": 696, + "pc": [ + 2773, + 2774 + ] + }, + { + "teal": 2679, + "source": 696, + "pc": [ + 2775, + 2776 + ] + }, + { + "teal": 2680, + "source": 696, + "pc": [ + 2777 + ] + }, + { + "teal": 2681, + "source": 696, + "pc": [ + 2778, + 2779, + 2780 + ] + }, + { + "teal": 2686, + "source": 697, + "pc": [ + 2781, + 2782 + ] + }, + { + "teal": 2687, + "source": 697, + "pc": [ + 2783, + 2784 + ] + }, + { + "teal": 2688, + "source": 697, + "pc": [ + 2785, + 2786, + 2787 + ] + }, + { + "teal": 2689, + "source": 697, + "pc": [ + 2788 + ] + }, + { + "teal": 2690, + "source": 697, + "pc": [ + 2789 + ] + }, + { + "teal": 2691, + "source": 697, + "pc": [ + 2790, + 2791 + ] + }, + { + "teal": 2695, + "source": 698, + "pc": [ + 2792, + 2793 + ] + }, + { + "teal": 2696, + "source": 698, + "pc": [ + 2794, + 2795 + ] + }, + { + "teal": 2697, + "source": 698, + "pc": [ + 2796 + ] + }, + { + "teal": 2698, + "source": 698, + "pc": [ + 2797, + 2798 + ] + }, + { + "teal": 2699, + "source": 698, + "pc": [ + 2799 + ] + }, + { + "teal": 2700, + "source": 698, + "pc": [ + 2800, + 2801 + ] + }, + { + "teal": 2705, + "source": 701, + "pc": [ + 2802, + 2803 + ] + }, + { + "teal": 2706, + "source": 701, + "pc": [ + 2804 + ] + }, + { + "teal": 2707, + "source": 701, + "pc": [ + 2805 + ] + }, + { + "teal": 2708, + "source": 701, + "pc": [ + 2806, + 2807, + 2808 + ] + }, + { + "teal": 2716, + "source": 704, + "pc": [ + 2809, + 2810 + ] + }, + { + "teal": 2717, + "source": 704, + "pc": [ + 2811, + 2812, + 2813 + ] + }, + { + "teal": 2718, + "source": 704, + "pc": [ + 2814 + ] + }, + { + "teal": 2719, + "source": 704, + "pc": [ + 2815, + 2816 + ] + }, + { + "teal": 2720, + "source": 703, + "pc": [ + 2817 + ] + }, + { + "teal": 2721, + "source": 704, + "pc": [ + 2818, + 2819 + ] + }, + { + "teal": 2722, + "source": 703, + "pc": [ + 2820, + 2821 + ] + }, + { + "teal": 2723, + "source": 703, + "pc": [ + 2822, + 2823 + ] + }, + { + "teal": 2724, + "source": 703, + "pc": [ + 2824 + ] + }, + { + "teal": 2725, + "source": 703, + "pc": [ + 2825, + 2826 + ] + }, + { + "teal": 2726, + "source": 703, + "pc": [ + 2827 + ] + }, + { + "teal": 2727, + "source": 703, + "pc": [ + 2828, + 2829 + ] + }, + { + "teal": 2728, + "source": 703, + "pc": [ + 2830 + ] + }, + { + "teal": 2729, + "source": 703, + "pc": [ + 2831 + ] + }, + { + "teal": 2730, + "source": 705, + "pc": [ + 2832, + 2833 + ] + }, + { + "teal": 2731, + "source": 705, + "pc": [ + 2834 + ] + }, + { + "teal": 2732, + "source": 705, + "pc": [ + 2835, + 2836 + ] + }, + { + "teal": 2733, + "source": 703, + "pc": [ + 2837 + ] + }, + { + "teal": 2734, + "source": 703, + "pc": [ + 2838 + ] + }, + { + "teal": 2735, + "source": 703, + "pc": [ + 2839 + ] + }, + { + "teal": 2736, + "source": 703, + "pc": [ + 2840 + ] + }, + { + "teal": 2737, + "source": 703, + "pc": [ + 2841 + ] + }, + { + "teal": 2738, + "source": 703, + "pc": [ + 2842 + ] + }, + { + "teal": 2739, + "source": 703, + "pc": [ + 2843 + ] + }, + { + "teal": 2740, + "source": 703, + "pc": [ + 2844, + 2845 + ] + }, + { + "teal": 2744, + "source": 710, + "pc": [ + 2846, + 2847 + ] + }, + { + "teal": 2745, + "source": 710, + "pc": [ + 2848, + 2849 + ] + }, + { + "teal": 2746, + "source": 710, + "pc": [ + 2850 + ] + }, + { + "teal": 2747, + "source": 710, + "pc": [ + 2851, + 2852 + ] + }, + { + "teal": 2751, + "source": 711, + "pc": [ + 2853, + 2854 + ] + }, + { + "teal": 2752, + "source": 711, + "pc": [ + 2855, + 2856 + ] + }, + { + "teal": 2753, + "source": 711, + "pc": [ + 2857, + 2858 + ] + }, + { + "teal": 2754, + "source": 711, + "pc": [ + 2859, + 2860, + 2861 + ] + }, + { + "teal": 2755, + "source": 711, + "pc": [ + 2862 + ] + }, + { + "teal": 2756, + "source": 711, + "pc": [ + 2863, + 2864 + ] + }, + { + "teal": 2757, + "source": 711, + "pc": [ + 2865 + ] + }, + { + "teal": 2758, + "source": 711, + "pc": [ + 2866 + ] + }, + { + "teal": 2759, + "source": 711, + "pc": [ + 2867 + ] + }, + { + "teal": 2760, + "source": 711, + "pc": [ + 2868, + 2869 + ] + }, + { + "teal": 2764, + "source": 712, + "pc": [ + 2870, + 2871 + ] + }, + { + "teal": 2765, + "source": 712, + "pc": [ + 2872, + 2873 + ] + }, + { + "teal": 2766, + "source": 712, + "pc": [ + 2874 + ] + }, + { + "teal": 2767, + "source": 712, + "pc": [ + 2875, + 2876 + ] + }, + { + "teal": 2773, + "source": 714, + "pc": [ + 2877, + 2878 + ] + }, + { + "teal": 2774, + "source": 714, + "pc": [ + 2879 + ] + }, + { + "teal": 2775, + "source": 714, + "pc": [ + 2880 + ] + }, + { + "teal": 2776, + "source": 714, + "pc": [ + 2881, + 2882, + 2883 + ] + }, + { + "teal": 2784, + "source": 717, + "pc": [ + 2884, + 2885 + ] + }, + { + "teal": 2785, + "source": 717, + "pc": [ + 2886, + 2887, + 2888 + ] + }, + { + "teal": 2786, + "source": 717, + "pc": [ + 2889 + ] + }, + { + "teal": 2787, + "source": 717, + "pc": [ + 2890, + 2891 + ] + }, + { + "teal": 2788, + "source": 716, + "pc": [ + 2892 + ] + }, + { + "teal": 2789, + "source": 717, + "pc": [ + 2893, + 2894 + ] + }, + { + "teal": 2790, + "source": 716, + "pc": [ + 2895, + 2896 + ] + }, + { + "teal": 2791, + "source": 716, + "pc": [ + 2897, + 2898 + ] + }, + { + "teal": 2792, + "source": 716, + "pc": [ + 2899 + ] + }, + { + "teal": 2793, + "source": 716, + "pc": [ + 2900, + 2901 + ] + }, + { + "teal": 2794, + "source": 716, + "pc": [ + 2902 + ] + }, + { + "teal": 2795, + "source": 716, + "pc": [ + 2903, + 2904 + ] + }, + { + "teal": 2796, + "source": 716, + "pc": [ + 2905 + ] + }, + { + "teal": 2797, + "source": 716, + "pc": [ + 2906 + ] + }, + { + "teal": 2798, + "source": 718, + "pc": [ + 2907, + 2908 + ] + }, + { + "teal": 2799, + "source": 718, + "pc": [ + 2909 + ] + }, + { + "teal": 2800, + "source": 718, + "pc": [ + 2910, + 2911 + ] + }, + { + "teal": 2801, + "source": 716, + "pc": [ + 2912 + ] + }, + { + "teal": 2802, + "source": 716, + "pc": [ + 2913 + ] + }, + { + "teal": 2803, + "source": 716, + "pc": [ + 2914 + ] + }, + { + "teal": 2804, + "source": 716, + "pc": [ + 2915 + ] + }, + { + "teal": 2805, + "source": 716, + "pc": [ + 2916 + ] + }, + { + "teal": 2806, + "source": 716, + "pc": [ + 2917 + ] + }, + { + "teal": 2807, + "source": 716, + "pc": [ + 2918 + ] + }, + { + "teal": 2808, + "source": 716, + "pc": [ + 2919, + 2920 + ] + }, + { + "teal": 2812, + "source": 723, + "pc": [ + 2921, + 2922 + ] + }, + { + "teal": 2813, + "source": 723, + "pc": [ + 2923, + 2924 + ] + }, + { + "teal": 2814, + "source": 723, + "pc": [ + 2925 + ] + }, + { + "teal": 2815, + "source": 723, + "pc": [ + 2926, + 2927 + ] + }, + { + "teal": 2819, + "source": 726, + "pc": [ + 2928, + 2929 + ] + }, + { + "teal": 2820, + "source": 726, + "pc": [ + 2930, + 2931 + ] + }, + { + "teal": 2821, + "source": 726, + "pc": [ + 2932, + 2933 + ] + }, + { + "teal": 2822, + "source": 726, + "pc": [ + 2934, + 2935, + 2936 + ] + }, + { + "teal": 2823, + "source": 726, + "pc": [ + 2937 + ] + }, + { + "teal": 2824, + "source": 726, + "pc": [ + 2938, + 2939 + ] + }, + { + "teal": 2825, + "source": 726, + "pc": [ + 2940 + ] + }, + { + "teal": 2826, + "source": 726, + "pc": [ + 2941 + ] + }, + { + "teal": 2827, + "source": 726, + "pc": [ + 2942 + ] + }, + { + "teal": 2828, + "source": 726, + "pc": [ + 2943, + 2944 + ] + }, + { + "teal": 2832, + "source": 727, + "pc": [ + 2945, + 2946 + ] + }, + { + "teal": 2833, + "source": 727, + "pc": [ + 2947, + 2948 + ] + }, + { + "teal": 2834, + "source": 727, + "pc": [ + 2949, + 2950 + ] + }, + { + "teal": 2835, + "source": 727, + "pc": [ + 2951, + 2952, + 2953 + ] + }, + { + "teal": 2836, + "source": 727, + "pc": [ + 2954 + ] + }, + { + "teal": 2837, + "source": 727, + "pc": [ + 2955, + 2956 + ] + }, + { + "teal": 2838, + "source": 727, + "pc": [ + 2957 + ] + }, + { + "teal": 2839, + "source": 727, + "pc": [ + 2958 + ] + }, + { + "teal": 2840, + "source": 727, + "pc": [ + 2959 + ] + }, + { + "teal": 2841, + "source": 727, + "pc": [ + 2960, + 2961 + ] + }, + { + "teal": 2845, + "source": 728, + "pc": [ + 2962, + 2963 + ] + }, + { + "teal": 2846, + "source": 728, + "pc": [ + 2964, + 2965 + ] + }, + { + "teal": 2847, + "source": 728, + "pc": [ + 2966 + ] + }, + { + "teal": 2848, + "source": 728, + "pc": [ + 2967, + 2968 + ] + }, + { + "teal": 2853, + "source": 731, + "pc": [ + 2969, + 2970 + ] + }, + { + "teal": 2854, + "source": 731, + "pc": [ + 2971 + ] + }, + { + "teal": 2855, + "source": 731, + "pc": [ + 2972 + ] + }, + { + "teal": 2856, + "source": 731, + "pc": [ + 2973, + 2974 + ] + }, + { + "teal": 2857, + "source": 731, + "pc": [ + 2975 + ] + }, + { + "teal": 2858, + "source": 731, + "pc": [ + 2976, + 2977 + ] + }, + { + "teal": 2859, + "source": 731, + "pc": [ + 2978 + ] + }, + { + "teal": 2870, + "source": 679, + "pc": [ + 2979, + 2980 + ] + }, + { + "teal": 2871, + "source": 679, + "pc": [ + 2981 + ] + }, + { + "teal": 2872, + "source": 679, + "pc": [ + 2982 + ] + }, + { + "teal": 2873, + "source": 679, + "pc": [ + 2983, + 2984 + ] + }, + { + "teal": 2874, + "source": 679, + "pc": [ + 2985, + 2986, + 2987 + ] + }, + { + "teal": 2879, + "source": 736, + "pc": [ + 2988, + 2989, + 2990, + 2991, + 2992, + 2993, + 2994, + 2995, + 2996, + 2997, + 2998, + 2999, + 3000, + 3001, + 3002, + 3003, + 3004, + 3005, + 3006, + 3007, + 3008, + 3009, + 3010, + 3011, + 3012, + 3013, + 3014, + 3015, + 3016, + 3017, + 3018, + 3019 + ] + }, + { + "teal": 2880, + "source": 736, + "pc": [ + 3020, + 3021 + ] + }, + { + "teal": 2881, + "source": 736, + "pc": [ + 3022 + ] + }, + { + "teal": 2882, + "source": 736, + "pc": [ + 3023 + ] + }, + { + "teal": 2883, + "source": 736, + "pc": [ + 3024 + ] + }, + { + "teal": 2887, + "source": 740, + "pc": [ + 3025, + 3026 + ] + }, + { + "teal": 2888, + "source": 740, + "pc": [ + 3027 + ] + }, + { + "teal": 2889, + "source": 740, + "pc": [ + 3028, + 3029 + ] + }, + { + "teal": 2890, + "source": 740, + "pc": [ + 3030 + ] + }, + { + "teal": 2891, + "source": 740, + "pc": [ + 3031, + 3032 + ] + }, + { + "teal": 2896, + "source": 744, + "pc": [ + 3033, + 3034 + ] + }, + { + "teal": 2897, + "source": 744, + "pc": [ + 3035 + ] + }, + { + "teal": 2898, + "source": 744, + "pc": [ + 3036 + ] + }, + { + "teal": 2899, + "source": 744, + "pc": [ + 3037, + 3038, + 3039 + ] + }, + { + "teal": 2904, + "source": 746, + "pc": [ + 3040 + ] + }, + { + "teal": 2905, + "source": 746, + "pc": [ + 3041, + 3042 + ] + }, + { + "teal": 2910, + "source": 746, + "pc": [ + 3043, + 3044 + ] + }, + { + "teal": 2911, + "source": 746, + "pc": [ + 3045, + 3046 + ] + }, + { + "teal": 2912, + "source": 746, + "pc": [ + 3047 + ] + }, + { + "teal": 2913, + "source": 746, + "pc": [ + 3048, + 3049, + 3050 + ] + }, + { + "teal": 2918, + "source": 747, + "pc": [ + 3051, + 3052 + ] + }, + { + "teal": 2919, + "source": 747, + "pc": [ + 3053, + 3054 + ] + }, + { + "teal": 2920, + "source": 747, + "pc": [ + 3055 + ] + }, + { + "teal": 2921, + "source": 747, + "pc": [ + 3056, + 3057, + 3058 + ] + }, + { + "teal": 2926, + "source": 748, + "pc": [ + 3059 + ] + }, + { + "teal": 2927, + "source": 748, + "pc": [ + 3060 + ] + }, + { + "teal": 2928, + "source": 748, + "pc": [ + 3061, + 3062 + ] + }, + { + "teal": 2929, + "source": 748, + "pc": [ + 3063 + ] + }, + { + "teal": 2930, + "source": 748, + "pc": [ + 3064, + 3065 + ] + }, + { + "teal": 2931, + "source": 748, + "pc": [ + 3066, + 3067 + ] + }, + { + "teal": 2932, + "source": 748, + "pc": [ + 3068 + ] + }, + { + "teal": 2933, + "source": 748, + "pc": [ + 3069, + 3070 + ] + }, + { + "teal": 2934, + "source": 748, + "pc": [ + 3071, + 3072 + ] + }, + { + "teal": 2935, + "source": 748, + "pc": [ + 3073, + 3074 + ] + }, + { + "teal": 2936, + "source": 748, + "pc": [ + 3075, + 3076 + ] + }, + { + "teal": 2937, + "source": 748, + "pc": [ + 3077 + ] + }, + { + "teal": 2942, + "source": 750, + "pc": [ + 3078, + 3079 + ] + }, + { + "teal": 2943, + "source": 750, + "pc": [ + 3080 + ] + }, + { + "teal": 2944, + "source": 750, + "pc": [ + 3081 + ] + }, + { + "teal": 2945, + "source": 750, + "pc": [ + 3082 + ] + }, + { + "teal": 2946, + "source": 750, + "pc": [ + 3083 + ] + }, + { + "teal": 2947, + "source": 750, + "pc": [ + 3084, + 3085 + ] + }, + { + "teal": 2948, + "source": 750, + "pc": [ + 3086 + ] + }, + { + "teal": 2949, + "source": 750, + "pc": [ + 3087, + 3088 + ] + }, + { + "teal": 2954, + "source": 751, + "pc": [ + 3089, + 3090 + ] + }, + { + "teal": 2955, + "source": 751, + "pc": [ + 3091, + 3092, + 3093 + ] + }, + { + "teal": 2956, + "source": 751, + "pc": [ + 3094, + 3095 + ] + }, + { + "teal": 2957, + "source": 751, + "pc": [ + 3096 + ] + }, + { + "teal": 2958, + "source": 751, + "pc": [ + 3097 + ] + }, + { + "teal": 2959, + "source": 751, + "pc": [ + 3098, + 3099, + 3100 + ] + }, + { + "teal": 2960, + "source": 751, + "pc": [ + 3101, + 3102 + ] + }, + { + "teal": 2961, + "source": 751, + "pc": [ + 3103, + 3104, + 3105 + ] + }, + { + "teal": 2962, + "source": 751, + "pc": [ + 3106 + ] + }, + { + "teal": 2963, + "source": 751, + "pc": [ + 3107, + 3108 + ] + }, + { + "teal": 2964, + "source": 751, + "pc": [ + 3109 + ] + }, + { + "teal": 2965, + "source": 751, + "pc": [ + 3110 + ] + }, + { + "teal": 2968, + "source": 751, + "pc": [ + 3111, + 3112, + 3113 + ] + }, + { + "teal": 2973, + "source": 752, + "pc": [ + 3114, + 3115 + ] + }, + { + "teal": 2974, + "source": 752, + "pc": [ + 3116, + 3117 + ] + }, + { + "teal": 2975, + "source": 752, + "pc": [ + 3118, + 3119, + 3120 + ] + }, + { + "teal": 2976, + "source": 752, + "pc": [ + 3121 + ] + }, + { + "teal": 2977, + "source": 752, + "pc": [ + 3122 + ] + }, + { + "teal": 2978, + "source": 752, + "pc": [ + 3123, + 3124 + ] + }, + { + "teal": 2983, + "source": 754, + "pc": [ + 3125, + 3126 + ] + }, + { + "teal": 2984, + "source": 754, + "pc": [ + 3127, + 3128 + ] + }, + { + "teal": 2985, + "source": 754, + "pc": [ + 3129 + ] + }, + { + "teal": 2986, + "source": 754, + "pc": [ + 3130, + 3131, + 3132 + ] + }, + { + "teal": 2992, + "source": 759, + "pc": [ + 3133, + 3134 + ] + }, + { + "teal": 2993, + "source": 759, + "pc": [ + 3135 + ] + }, + { + "teal": 2994, + "source": 759, + "pc": [ + 3136 + ] + }, + { + "teal": 2995, + "source": 759, + "pc": [ + 3137, + 3138, + 3139 + ] + }, + { + "teal": 3003, + "source": 767, + "pc": [ + 3140, + 3141 + ] + }, + { + "teal": 3004, + "source": 767, + "pc": [ + 3142, + 3143, + 3144 + ] + }, + { + "teal": 3005, + "source": 767, + "pc": [ + 3145 + ] + }, + { + "teal": 3006, + "source": 767, + "pc": [ + 3146, + 3147 + ] + }, + { + "teal": 3007, + "source": 766, + "pc": [ + 3148 + ] + }, + { + "teal": 3008, + "source": 766, + "pc": [ + 3149 + ] + }, + { + "teal": 3009, + "source": 768, + "pc": [ + 3150, + 3151 + ] + }, + { + "teal": 3010, + "source": 766, + "pc": [ + 3152 + ] + }, + { + "teal": 3011, + "source": 766, + "pc": [ + 3153 + ] + }, + { + "teal": 3012, + "source": 766, + "pc": [ + 3154 + ] + }, + { + "teal": 3013, + "source": 766, + "pc": [ + 3155 + ] + }, + { + "teal": 3014, + "source": 766, + "pc": [ + 3156 + ] + }, + { + "teal": 3015, + "source": 766, + "pc": [ + 3157 + ] + }, + { + "teal": 3016, + "source": 766, + "pc": [ + 3158, + 3159 + ] + }, + { + "teal": 3020, + "source": 775, + "pc": [ + 3160, + 3161 + ] + }, + { + "teal": 3021, + "source": 775, + "pc": [ + 3162, + 3163 + ] + }, + { + "teal": 3022, + "source": 775, + "pc": [ + 3164, + 3165 + ] + }, + { + "teal": 3023, + "source": 775, + "pc": [ + 3166, + 3167, + 3168 + ] + }, + { + "teal": 3024, + "source": 775, + "pc": [ + 3169 + ] + }, + { + "teal": 3025, + "source": 775, + "pc": [ + 3170, + 3171 + ] + }, + { + "teal": 3026, + "source": 775, + "pc": [ + 3172 + ] + }, + { + "teal": 3027, + "source": 775, + "pc": [ + 3173 + ] + }, + { + "teal": 3028, + "source": 775, + "pc": [ + 3174 + ] + }, + { + "teal": 3029, + "source": 775, + "pc": [ + 3175, + 3176 + ] + }, + { + "teal": 3033, + "source": 776, + "pc": [ + 3177, + 3178 + ] + }, + { + "teal": 3034, + "source": 776, + "pc": [ + 3179, + 3180 + ] + }, + { + "teal": 3035, + "source": 776, + "pc": [ + 3181 + ] + }, + { + "teal": 3036, + "source": 776, + "pc": [ + 3182, + 3183 + ] + }, + { + "teal": 3042, + "source": 778, + "pc": [ + 3184, + 3185 + ] + }, + { + "teal": 3043, + "source": 778, + "pc": [ + 3186 + ] + }, + { + "teal": 3044, + "source": 778, + "pc": [ + 3187 + ] + }, + { + "teal": 3045, + "source": 778, + "pc": [ + 3188, + 3189, + 3190 + ] + }, + { + "teal": 3050, + "source": 779, + "pc": [ + 3191, + 3192 + ] + }, + { + "teal": 3051, + "source": 779, + "pc": [ + 3193, + 3194, + 3195 + ] + }, + { + "teal": 3052, + "source": 779, + "pc": [ + 3196 + ] + }, + { + "teal": 3053, + "source": 779, + "pc": [ + 3197, + 3198 + ] + }, + { + "teal": 3054, + "source": 779, + "pc": [ + 3199 + ] + }, + { + "teal": 3055, + "source": 779, + "pc": [ + 3200 + ] + }, + { + "teal": 3056, + "source": 779, + "pc": [ + 3201, + 3202 + ] + }, + { + "teal": 3057, + "source": 779, + "pc": [ + 3203 + ] + }, + { + "teal": 3058, + "source": 779, + "pc": [ + 3204 + ] + }, + { + "teal": 3059, + "source": 779, + "pc": [ + 3205 + ] + }, + { + "teal": 3060, + "source": 779, + "pc": [ + 3206 + ] + }, + { + "teal": 3061, + "source": 779, + "pc": [ + 3207 + ] + }, + { + "teal": 3062, + "source": 779, + "pc": [ + 3208 + ] + }, + { + "teal": 3063, + "source": 779, + "pc": [ + 3209, + 3210 + ] + }, + { + "teal": 3067, + "source": 782, + "pc": [ + 3211, + 3212 + ] + }, + { + "teal": 3068, + "source": 782, + "pc": [ + 3213, + 3214 + ] + }, + { + "teal": 3069, + "source": 782, + "pc": [ + 3215, + 3216 + ] + }, + { + "teal": 3070, + "source": 782, + "pc": [ + 3217, + 3218, + 3219 + ] + }, + { + "teal": 3071, + "source": 782, + "pc": [ + 3220 + ] + }, + { + "teal": 3072, + "source": 782, + "pc": [ + 3221, + 3222 + ] + }, + { + "teal": 3073, + "source": 782, + "pc": [ + 3223 + ] + }, + { + "teal": 3074, + "source": 782, + "pc": [ + 3224 + ] + }, + { + "teal": 3075, + "source": 782, + "pc": [ + 3225 + ] + }, + { + "teal": 3076, + "source": 782, + "pc": [ + 3226, + 3227 + ] + }, + { + "teal": 3080, + "source": 783, + "pc": [ + 3228, + 3229 + ] + }, + { + "teal": 3081, + "source": 783, + "pc": [ + 3230, + 3231 + ] + }, + { + "teal": 3082, + "source": 783, + "pc": [ + 3232, + 3233 + ] + }, + { + "teal": 3083, + "source": 783, + "pc": [ + 3234, + 3235, + 3236 + ] + }, + { + "teal": 3084, + "source": 783, + "pc": [ + 3237 + ] + }, + { + "teal": 3085, + "source": 783, + "pc": [ + 3238, + 3239 + ] + }, + { + "teal": 3086, + "source": 783, + "pc": [ + 3240 + ] + }, + { + "teal": 3087, + "source": 783, + "pc": [ + 3241 + ] + }, + { + "teal": 3088, + "source": 783, + "pc": [ + 3242 + ] + }, + { + "teal": 3089, + "source": 783, + "pc": [ + 3243, + 3244 + ] + }, + { + "teal": 3093, + "source": 784, + "pc": [ + 3245, + 3246 + ] + }, + { + "teal": 3094, + "source": 784, + "pc": [ + 3247, + 3248 + ] + }, + { + "teal": 3095, + "source": 784, + "pc": [ + 3249 + ] + }, + { + "teal": 3096, + "source": 784, + "pc": [ + 3250, + 3251 + ] + }, + { + "teal": 3101, + "source": 788, + "pc": [ + 3252, + 3253 + ] + }, + { + "teal": 3102, + "source": 788, + "pc": [ + 3254 + ] + }, + { + "teal": 3103, + "source": 788, + "pc": [ + 3255 + ] + }, + { + "teal": 3104, + "source": 788, + "pc": [ + 3256, + 3257 + ] + }, + { + "teal": 3105, + "source": 788, + "pc": [ + 3258 + ] + }, + { + "teal": 3106, + "source": 788, + "pc": [ + 3259, + 3260 + ] + }, + { + "teal": 3107, + "source": 788, + "pc": [ + 3261 + ] + }, + { + "teal": 3116, + "source": 746, + "pc": [ + 3262, + 3263 + ] + }, + { + "teal": 3117, + "source": 746, + "pc": [ + 3264 + ] + }, + { + "teal": 3118, + "source": 746, + "pc": [ + 3265 + ] + }, + { + "teal": 3119, + "source": 746, + "pc": [ + 3266, + 3267 + ] + }, + { + "teal": 3120, + "source": 746, + "pc": [ + 3268, + 3269, + 3270 + ] + }, + { + "teal": 3127, + "source": 796, + "pc": [ + 3271, + 3272 + ] + }, + { + "teal": 3128, + "source": 796, + "pc": [ + 3273 + ] + }, + { + "teal": 3129, + "source": 796, + "pc": [ + 3274, + 3275 + ] + }, + { + "teal": 3130, + "source": 796, + "pc": [ + 3276 + ] + }, + { + "teal": 3131, + "source": 796, + "pc": [ + 3277, + 3278 + ] + }, + { + "teal": 3132, + "source": 796, + "pc": [ + 3279 + ] + }, + { + "teal": 3133, + "source": 796, + "pc": [ + 3280 + ] + }, + { + "teal": 3137, + "source": 798, + "pc": [ + 3281, + 3282, + 3283, + 3284, + 3285, + 3286, + 3287, + 3288, + 3289, + 3290, + 3291, + 3292, + 3293, + 3294, + 3295, + 3296 + ] + }, + { + "teal": 3138, + "source": 798, + "pc": [ + 3297, + 3298 + ] + }, + { + "teal": 3139, + "source": 798, + "pc": [ + 3299 + ] + }, + { + "teal": 3140, + "source": 798, + "pc": [ + 3300 + ] + }, + { + "teal": 3141, + "source": 798, + "pc": [ + 3301 + ] + }, + { + "teal": 3145, + "source": 799, + "pc": [ + 3302, + 3303, + 3304, + 3305, + 3306, + 3307, + 3308, + 3309, + 3310, + 3311, + 3312, + 3313, + 3314, + 3315, + 3316, + 3317, + 3318, + 3319, + 3320 + ] + }, + { + "teal": 3146, + "source": 799, + "pc": [ + 3321, + 3322 + ] + }, + { + "teal": 3147, + "source": 799, + "pc": [ + 3323 + ] + }, + { + "teal": 3148, + "source": 799, + "pc": [ + 3324 + ] + }, + { + "teal": 3149, + "source": 799, + "pc": [ + 3325 + ] + }, + { + "teal": 3160, + "source": 804, + "pc": [ + 3326 + ] + }, + { + "teal": 3161, + "source": 804, + "pc": [ + 3327 + ] + }, + { + "teal": 3162, + "source": 804, + "pc": [ + 3328, + 3329 + ] + }, + { + "teal": 3163, + "source": 804, + "pc": [ + 3330, + 3331, + 3332, + 3333, + 3334, + 3335 + ] + }, + { + "teal": 3164, + "source": 804, + "pc": [ + 3336, + 3337 + ] + }, + { + "teal": 3168, + "source": 805, + "pc": [ + 3338 + ] + }, + { + "teal": 3169, + "source": 805, + "pc": [ + 3339 + ] + }, + { + "teal": 3170, + "source": 805, + "pc": [ + 3340, + 3341 + ] + }, + { + "teal": 3178, + "source": 807, + "pc": [ + 3342 + ] + }, + { + "teal": 3179, + "source": 807, + "pc": [ + 3343 + ] + }, + { + "teal": 3180, + "source": 807, + "pc": [ + 3344 + ] + }, + { + "teal": 3181, + "source": 807, + "pc": [ + 3345 + ] + }, + { + "teal": 3182, + "source": 807, + "pc": [ + 3346 + ] + }, + { + "teal": 3183, + "source": 807, + "pc": [ + 3347 + ] + }, + { + "teal": 3184, + "source": 807, + "pc": [ + 3348 + ] + }, + { + "teal": 3185, + "source": 807, + "pc": [ + 3349, + 3350, + 3351 + ] + }, + { + "teal": 3186, + "source": 807, + "pc": [ + 3352 + ] + }, + { + "teal": 3187, + "source": 807, + "pc": [ + 3353 + ] + }, + { + "teal": 3188, + "source": 807, + "pc": [ + 3354, + 3355 + ] + }, + { + "teal": 3189, + "source": 808, + "pc": [ + 3356, + 3357 + ] + }, + { + "teal": 3190, + "source": 808, + "pc": [ + 3358 + ] + }, + { + "teal": 3191, + "source": 808, + "pc": [ + 3359, + 3360 + ] + }, + { + "teal": 3192, + "source": 809, + "pc": [ + 3361, + 3362 + ] + }, + { + "teal": 3193, + "source": 809, + "pc": [ + 3363 + ] + }, + { + "teal": 3194, + "source": 809, + "pc": [ + 3364, + 3365 + ] + }, + { + "teal": 3197, + "source": 804, + "pc": [ + 3366 + ] + }, + { + "teal": 3198, + "source": 804, + "pc": [ + 3367, + 3368 + ] + }, + { + "teal": 3201, + "source": 804, + "pc": [ + 3369 + ] + }, + { + "teal": 3202, + "source": 480, + "pc": [ + 3370 + ] + }, + { + "teal": 3207, + "source": 832, + "pc": [ + 3371, + 3372, + 3373 + ] + }, + { + "teal": 3208, + "source": 832, + "pc": [ + 3374 + ] + }, + { + "teal": 3211, + "source": 831, + "pc": [ + 3375, + 3376, + 3377 + ] + }, + { + "teal": 3212, + "source": 831, + "pc": [ + 3378 + ] + }, + { + "teal": 3215, + "source": 830, + "pc": [ + 3379, + 3380, + 3381 + ] + }, + { + "teal": 3216, + "source": 830, + "pc": [ + 3382 + ] + }, + { + "teal": 3219, + "source": 829, + "pc": [ + 3383, + 3384, + 3385 + ] + }, + { + "teal": 3220, + "source": 829, + "pc": [ + 3386, + 3387, + 3388 + ] + }, + { + "teal": 3223, + "source": 828, + "pc": [ + 3389, + 3390, + 3391 + ] + }, + { + "teal": 3224, + "source": 828, + "pc": [ + 3392, + 3393, + 3394 + ] + }, + { + "teal": 3227, + "source": 827, + "pc": [ + 3395, + 3396, + 3397 + ] + }, + { + "teal": 3228, + "source": 827, + "pc": [ + 3398, + 3399, + 3400 + ] + }, + { + "teal": 3231, + "source": 826, + "pc": [ + 3401, + 3402, + 3403 + ] + }, + { + "teal": 3232, + "source": 826, + "pc": [ + 3404 + ] + }, + { + "teal": 3233, + "source": 826, + "pc": [ + 3405 + ] + }, + { + "teal": 3248, + "source": 826, + "pc": [ + 3406, + 3407, + 3408 + ] + }, + { + "teal": 3252, + "source": 834, + "pc": [ + 3409, + 3410, + 3411 + ] + }, + { + "teal": 3253, + "source": 834, + "pc": [ + 3412 + ] + }, + { + "teal": 3264, + "source": 835, + "pc": [ + 3413 + ] + }, + { + "teal": 3265, + "source": 835, + "pc": [ + 3414, + 3415 + ] + }, + { + "teal": 3266, + "source": 835, + "pc": [ + 3416, + 3417 + ] + }, + { + "teal": 3270, + "source": 836, + "pc": [ + 3418, + 3419 + ] + }, + { + "teal": 3271, + "source": 836, + "pc": [ + 3420, + 3421 + ] + }, + { + "teal": 3275, + "source": 837, + "pc": [ + 3422, + 3423 + ] + }, + { + "teal": 3276, + "source": 837, + "pc": [ + 3424, + 3425 + ] + }, + { + "teal": 3280, + "source": 838, + "pc": [ + 3426, + 3427 + ] + }, + { + "teal": 3281, + "source": 838, + "pc": [ + 3428, + 3429 + ] + }, + { + "teal": 3285, + "source": 839, + "pc": [ + 3430, + 3431 + ] + }, + { + "teal": 3286, + "source": 839, + "pc": [ + 3432, + 3433 + ] + }, + { + "teal": 3290, + "source": 840, + "pc": [ + 3434, + 3435 + ] + }, + { + "teal": 3291, + "source": 840, + "pc": [ + 3436, + 3437 + ] + }, + { + "teal": 3295, + "source": 841, + "pc": [ + 3438, + 3439 + ] + }, + { + "teal": 3296, + "source": 841, + "pc": [ + 3440, + 3441 + ] + }, + { + "teal": 3299, + "source": 835, + "pc": [ + 3442 + ] + }, + { + "teal": 3300, + "source": 835, + "pc": [ + 3443, + 3444 + ] + }, + { + "teal": 3303, + "source": 835, + "pc": [ + 3445 + ] + }, + { + "teal": 3304, + "source": 826, + "pc": [ + 3446 + ] + }, + { + "teal": 3309, + "source": 850, + "pc": [ + 3447, + 3448, + 3449 + ] + }, + { + "teal": 3310, + "source": 850, + "pc": [ + 3450 + ] + }, + { + "teal": 3311, + "source": 850, + "pc": [ + 3451 + ] + }, + { + "teal": 3318, + "source": 850, + "pc": [ + 3452, + 3453, + 3454 + ] + }, + { + "teal": 3323, + "source": 853, + "pc": [ + 3455, + 3456 + ] + }, + { + "teal": 3324, + "source": 853, + "pc": [ + 3457 + ] + }, + { + "teal": 3325, + "source": 853, + "pc": [ + 3458 + ] + }, + { + "teal": 3326, + "source": 853, + "pc": [ + 3459, + 3460 + ] + }, + { + "teal": 3327, + "source": 853, + "pc": [ + 3461 + ] + }, + { + "teal": 3328, + "source": 853, + "pc": [ + 3462 + ] + }, + { + "teal": 3329, + "source": 853, + "pc": [ + 3463, + 3464, + 3465 + ] + }, + { + "teal": 3334, + "source": 854, + "pc": [ + 3466, + 3467, + 3468 + ] + }, + { + "teal": 3335, + "source": 854, + "pc": [ + 3469 + ] + }, + { + "teal": 3340, + "source": 857, + "pc": [ + 3470 + ] + }, + { + "teal": 3341, + "source": 857, + "pc": [ + 3471, + 3472 + ] + }, + { + "teal": 3342, + "source": 857, + "pc": [ + 3473, + 3474 + ] + }, + { + "teal": 3345, + "source": 857, + "pc": [ + 3475 + ] + }, + { + "teal": 3346, + "source": 857, + "pc": [ + 3476, + 3477 + ] + }, + { + "teal": 3349, + "source": 857, + "pc": [ + 3478 + ] + }, + { + "teal": 3350, + "source": 850, + "pc": [ + 3479 + ] + }, + { + "teal": 3355, + "source": 863, + "pc": [ + 3480, + 3481, + 3482 + ] + }, + { + "teal": 3356, + "source": 863, + "pc": [ + 3483, + 3484, + 3485 + ] + }, + { + "teal": 3359, + "source": 863, + "pc": [ + 3486, + 3487, + 3488 + ] + }, + { + "teal": 3360, + "source": 863, + "pc": [ + 3489 + ] + }, + { + "teal": 3363, + "source": 863, + "pc": [ + 3490, + 3491, + 3492 + ] + }, + { + "teal": 3364, + "source": 863, + "pc": [ + 3493 + ] + }, + { + "teal": 3365, + "source": 863, + "pc": [ + 3494 + ] + }, + { + "teal": 3369, + "source": 863, + "pc": [ + 3495, + 3496, + 3497 + ] + }, + { + "teal": 3373, + "source": 864, + "pc": [ + 3498, + 3499, + 3500 + ] + }, + { + "teal": 3374, + "source": 864, + "pc": [ + 3501 + ] + }, + { + "teal": 3382, + "source": 866, + "pc": [ + 3502 + ] + }, + { + "teal": 3383, + "source": 866, + "pc": [ + 3503 + ] + }, + { + "teal": 3384, + "source": 866, + "pc": [ + 3504, + 3505 + ] + }, + { + "teal": 3388, + "source": 867, + "pc": [ + 3506, + 3507 + ] + }, + { + "teal": 3389, + "source": 867, + "pc": [ + 3508, + 3509 + ] + }, + { + "teal": 3393, + "source": 868, + "pc": [ + 3510, + 3511, + 3512, + 3513, + 3514, + 3515, + 3516, + 3517, + 3518, + 3519, + 3520, + 3521, + 3522, + 3523, + 3524, + 3525, + 3526 + ] + }, + { + "teal": 3394, + "source": 868, + "pc": [ + 3527, + 3528 + ] + }, + { + "teal": 3395, + "source": 868, + "pc": [ + 3529, + 3530 + ] + }, + { + "teal": 3396, + "source": 868, + "pc": [ + 3531, + 3532 + ] + }, + { + "teal": 3397, + "source": 868, + "pc": [ + 3533, + 3534 + ] + }, + { + "teal": 3398, + "source": 868, + "pc": [ + 3535 + ] + }, + { + "teal": 3399, + "source": 868, + "pc": [ + 3536, + 3537 + ] + }, + { + "teal": 3400, + "source": 868, + "pc": [ + 3538, + 3539 + ] + }, + { + "teal": 3401, + "source": 868, + "pc": [ + 3540, + 3541 + ] + }, + { + "teal": 3405, + "source": 869, + "pc": [ + 3542, + 3543 + ] + }, + { + "teal": 3406, + "source": 869, + "pc": [ + 3544, + 3545 + ] + }, + { + "teal": 3409, + "source": 866, + "pc": [ + 3546 + ] + }, + { + "teal": 3410, + "source": 866, + "pc": [ + 3547, + 3548 + ] + }, + { + "teal": 3413, + "source": 866, + "pc": [ + 3549 + ] + }, + { + "teal": 3414, + "source": 863, + "pc": [ + 3550 + ] + }, + { + "teal": 3419, + "source": 879, + "pc": [ + 3551, + 3552 + ] + }, + { + "teal": 3422, + "source": 879, + "pc": [ + 3553, + 3554, + 3555 + ] + }, + { + "teal": 3423, + "source": 879, + "pc": [ + 3556 + ] + }, + { + "teal": 3424, + "source": 879, + "pc": [ + 3557 + ] + }, + { + "teal": 3425, + "source": 879, + "pc": [ + 3558, + 3559 + ] + }, + { + "teal": 3426, + "source": 879, + "pc": [ + 3560 + ] + }, + { + "teal": 3427, + "source": 879, + "pc": [ + 3561 + ] + }, + { + "teal": 3430, + "source": 879, + "pc": [ + 3562, + 3563, + 3564 + ] + }, + { + "teal": 3431, + "source": 879, + "pc": [ + 3565 + ] + }, + { + "teal": 3432, + "source": 879, + "pc": [ + 3566 + ] + }, + { + "teal": 3433, + "source": 879, + "pc": [ + 3567 + ] + }, + { + "teal": 3434, + "source": 879, + "pc": [ + 3568 + ] + }, + { + "teal": 3443, + "source": 879, + "pc": [ + 3569, + 3570, + 3571 + ] + }, + { + "teal": 3446, + "source": 879, + "pc": [ + 3572, + 3573 + ] + }, + { + "teal": 3450, + "source": 880, + "pc": [ + 3574 + ] + }, + { + "teal": 3451, + "source": 880, + "pc": [ + 3575 + ] + }, + { + "teal": 3452, + "source": 880, + "pc": [ + 3576, + 3577 + ] + }, + { + "teal": 3453, + "source": 880, + "pc": [ + 3578, + 3579, + 3580 + ] + }, + { + "teal": 3454, + "source": 880, + "pc": [ + 3581 + ] + }, + { + "teal": 3455, + "source": 880, + "pc": [ + 3582 + ] + }, + { + "teal": 3458, + "source": 880, + "pc": [ + 3583 + ] + }, + { + "teal": 3462, + "source": 881, + "pc": [ + 3584 + ] + }, + { + "teal": 3463, + "source": 881, + "pc": [ + 3585 + ] + }, + { + "teal": 3464, + "source": 881, + "pc": [ + 3586 + ] + }, + { + "teal": 3465, + "source": 881, + "pc": [ + 3587 + ] + }, + { + "teal": 3468, + "source": 881, + "pc": [ + 3588 + ] + }, + { + "teal": 3472, + "source": 882, + "pc": [ + 3589, + 3590 + ] + }, + { + "teal": 3473, + "source": 882, + "pc": [ + 3591, + 3592, + 3593 + ] + }, + { + "teal": 3474, + "source": 882, + "pc": [ + 3594 + ] + }, + { + "teal": 3475, + "source": 882, + "pc": [ + 3595 + ] + }, + { + "teal": 3476, + "source": 882, + "pc": [ + 3596 + ] + }, + { + "teal": 3479, + "source": 882, + "pc": [ + 3597 + ] + }, + { + "teal": 3486, + "source": 884, + "pc": [ + 3598 + ] + }, + { + "teal": 3487, + "source": 884, + "pc": [ + 3599 + ] + }, + { + "teal": 3488, + "source": 884, + "pc": [ + 3600, + 3601 + ] + }, + { + "teal": 3489, + "source": 884, + "pc": [ + 3602, + 3603 + ] + }, + { + "teal": 3490, + "source": 884, + "pc": [ + 3604, + 3605 + ] + }, + { + "teal": 3494, + "source": 885, + "pc": [ + 3606 + ] + }, + { + "teal": 3495, + "source": 885, + "pc": [ + 3607 + ] + }, + { + "teal": 3496, + "source": 885, + "pc": [ + 3608, + 3609 + ] + }, + { + "teal": 3500, + "source": 886, + "pc": [ + 3610, + 3611 + ] + }, + { + "teal": 3501, + "source": 886, + "pc": [ + 3612, + 3613, + 3614 + ] + }, + { + "teal": 3502, + "source": 886, + "pc": [ + 3615 + ] + }, + { + "teal": 3503, + "source": 886, + "pc": [ + 3616 + ] + }, + { + "teal": 3504, + "source": 886, + "pc": [ + 3617, + 3618 + ] + }, + { + "teal": 3505, + "source": 886, + "pc": [ + 3619, + 3620 + ] + }, + { + "teal": 3506, + "source": 886, + "pc": [ + 3621, + 3622, + 3623 + ] + }, + { + "teal": 3507, + "source": 886, + "pc": [ + 3624 + ] + }, + { + "teal": 3508, + "source": 886, + "pc": [ + 3625 + ] + }, + { + "teal": 3509, + "source": 886, + "pc": [ + 3626, + 3627 + ] + }, + { + "teal": 3512, + "source": 884, + "pc": [ + 3628 + ] + }, + { + "teal": 3513, + "source": 884, + "pc": [ + 3629, + 3630 + ] + }, + { + "teal": 3516, + "source": 884, + "pc": [ + 3631 + ] + }, + { + "teal": 3517, + "source": 884, + "pc": [ + 3632, + 3633 + ] + }, + { + "teal": 3518, + "source": 884, + "pc": [ + 3634 + ] + }, + { + "teal": 3519, + "source": 884, + "pc": [ + 3635 + ] + }, + { + "teal": 3520, + "source": 884, + "pc": [ + 3636, + 3637 + ] + }, + { + "teal": 3521, + "source": 884, + "pc": [ + 3638, + 3639, + 3640 + ] + }, + { + "teal": 3522, + "source": 884, + "pc": [ + 3641 + ] + }, + { + "teal": 3523, + "source": 884, + "pc": [ + 3642, + 3643 + ] + }, + { + "teal": 3527, + "source": 888, + "pc": [ + 3644, + 3645 + ] + }, + { + "teal": 3528, + "source": 888, + "pc": [ + 3646, + 3647 + ] + }, + { + "teal": 3529, + "source": 888, + "pc": [ + 3648, + 3649, + 3650 + ] + }, + { + "teal": 3530, + "source": 888, + "pc": [ + 3651 + ] + }, + { + "teal": 3531, + "source": 888, + "pc": [ + 3652 + ] + }, + { + "teal": 3532, + "source": 888, + "pc": [ + 3653 + ] + }, + { + "teal": 3536, + "source": 889, + "pc": [ + 3654, + 3655 + ] + }, + { + "teal": 3537, + "source": 889, + "pc": [ + 3656, + 3657 + ] + }, + { + "teal": 3538, + "source": 889, + "pc": [ + 3658, + 3659, + 3660 + ] + }, + { + "teal": 3539, + "source": 889, + "pc": [ + 3661 + ] + }, + { + "teal": 3540, + "source": 889, + "pc": [ + 3662, + 3663 + ] + }, + { + "teal": 3541, + "source": 889, + "pc": [ + 3664 + ] + }, + { + "teal": 3542, + "source": 889, + "pc": [ + 3665 + ] + }, + { + "teal": 3543, + "source": 889, + "pc": [ + 3666 + ] + }, + { + "teal": 3550, + "source": 891, + "pc": [ + 3667 + ] + }, + { + "teal": 3551, + "source": 891, + "pc": [ + 3668 + ] + }, + { + "teal": 3552, + "source": 891, + "pc": [ + 3669, + 3670 + ] + }, + { + "teal": 3553, + "source": 891, + "pc": [ + 3671, + 3672 + ] + }, + { + "teal": 3554, + "source": 891, + "pc": [ + 3673, + 3674 + ] + }, + { + "teal": 3558, + "source": 892, + "pc": [ + 3675 + ] + }, + { + "teal": 3559, + "source": 892, + "pc": [ + 3676 + ] + }, + { + "teal": 3560, + "source": 892, + "pc": [ + 3677, + 3678 + ] + }, + { + "teal": 3564, + "source": 893, + "pc": [ + 3679 + ] + }, + { + "teal": 3565, + "source": 893, + "pc": [ + 3680 + ] + }, + { + "teal": 3566, + "source": 893, + "pc": [ + 3681 + ] + }, + { + "teal": 3567, + "source": 893, + "pc": [ + 3682, + 3683 + ] + }, + { + "teal": 3570, + "source": 891, + "pc": [ + 3684 + ] + }, + { + "teal": 3571, + "source": 891, + "pc": [ + 3685, + 3686 + ] + }, + { + "teal": 3574, + "source": 891, + "pc": [ + 3687 + ] + }, + { + "teal": 3575, + "source": 891, + "pc": [ + 3688, + 3689 + ] + }, + { + "teal": 3576, + "source": 891, + "pc": [ + 3690 + ] + }, + { + "teal": 3577, + "source": 891, + "pc": [ + 3691 + ] + }, + { + "teal": 3578, + "source": 891, + "pc": [ + 3692, + 3693 + ] + }, + { + "teal": 3579, + "source": 891, + "pc": [ + 3694, + 3695, + 3696 + ] + }, + { + "teal": 3582, + "source": 891, + "pc": [ + 3697, + 3698 + ] + }, + { + "teal": 3583, + "source": 891, + "pc": [ + 3699 + ] + }, + { + "teal": 3587, + "source": 897, + "pc": [ + 3700, + 3701, + 3702 + ] + }, + { + "teal": 3590, + "source": 897, + "pc": [ + 3703, + 3704 + ] + }, + { + "teal": 3597, + "source": 898, + "pc": [ + 3705 + ] + }, + { + "teal": 3598, + "source": 898, + "pc": [ + 3706 + ] + }, + { + "teal": 3599, + "source": 898, + "pc": [ + 3707, + 3708 + ] + }, + { + "teal": 3600, + "source": 898, + "pc": [ + 3709, + 3710, + 3711, + 3712, + 3713, + 3714 + ] + }, + { + "teal": 3601, + "source": 898, + "pc": [ + 3715, + 3716 + ] + }, + { + "teal": 3605, + "source": 899, + "pc": [ + 3717 + ] + }, + { + "teal": 3606, + "source": 899, + "pc": [ + 3718 + ] + }, + { + "teal": 3607, + "source": 899, + "pc": [ + 3719, + 3720 + ] + }, + { + "teal": 3611, + "source": 900, + "pc": [ + 3721 + ] + }, + { + "teal": 3612, + "source": 900, + "pc": [ + 3722 + ] + }, + { + "teal": 3613, + "source": 900, + "pc": [ + 3723 + ] + }, + { + "teal": 3614, + "source": 900, + "pc": [ + 3724, + 3725 + ] + }, + { + "teal": 3617, + "source": 898, + "pc": [ + 3726 + ] + }, + { + "teal": 3618, + "source": 898, + "pc": [ + 3727, + 3728 + ] + }, + { + "teal": 3621, + "source": 898, + "pc": [ + 3729 + ] + }, + { + "teal": 3622, + "source": 898, + "pc": [ + 3730, + 3731 + ] + }, + { + "teal": 3623, + "source": 898, + "pc": [ + 3732 + ] + }, + { + "teal": 3624, + "source": 898, + "pc": [ + 3733 + ] + }, + { + "teal": 3625, + "source": 898, + "pc": [ + 3734, + 3735 + ] + }, + { + "teal": 3626, + "source": 898, + "pc": [ + 3736, + 3737, + 3738 + ] + }, + { + "teal": 3627, + "source": 898, + "pc": [ + 3739, + 3740 + ] + }, + { + "teal": 3631, + "source": 902, + "pc": [ + 3741, + 3742 + ] + }, + { + "teal": 3632, + "source": 902, + "pc": [ + 3743, + 3744 + ] + }, + { + "teal": 3633, + "source": 902, + "pc": [ + 3745, + 3746, + 3747 + ] + }, + { + "teal": 3634, + "source": 902, + "pc": [ + 3748 + ] + }, + { + "teal": 3635, + "source": 902, + "pc": [ + 3749 + ] + }, + { + "teal": 3636, + "source": 902, + "pc": [ + 3750, + 3751, + 3752 + ] + }, + { + "teal": 3637, + "source": 902, + "pc": [ + 3753, + 3754 + ] + }, + { + "teal": 3638, + "source": 902, + "pc": [ + 3755, + 3756 + ] + }, + { + "teal": 3639, + "source": 902, + "pc": [ + 3757, + 3758, + 3759 + ] + }, + { + "teal": 3640, + "source": 902, + "pc": [ + 3760 + ] + }, + { + "teal": 3641, + "source": 902, + "pc": [ + 3761 + ] + }, + { + "teal": 3645, + "source": 902, + "pc": [ + 3762, + 3763 + ] + }, + { + "teal": 3646, + "source": 902, + "pc": [ + 3764 + ] + }, + { + "teal": 3658, + "source": 914, + "pc": [ + 3765, + 3766, + 3767 + ] + }, + { + "teal": 3661, + "source": 914, + "pc": [ + 3768, + 3769 + ] + }, + { + "teal": 3665, + "source": 917, + "pc": [ + 3770, + 3771 + ] + }, + { + "teal": 3666, + "source": 917, + "pc": [ + 3772, + 3773 + ] + }, + { + "teal": 3670, + "source": 920, + "pc": [ + 3774, + 3775 + ] + }, + { + "teal": 3671, + "source": 920, + "pc": [ + 3776, + 3777, + 3778 + ] + }, + { + "teal": 3672, + "source": 920, + "pc": [ + 3779 + ] + }, + { + "teal": 3675, + "source": 920, + "pc": [ + 3780, + 3781 + ] + }, + { + "teal": 3676, + "source": 920, + "pc": [ + 3782 + ] + }, + { + "teal": 3680, + "source": 923, + "pc": [ + 3783, + 3784, + 3785 + ] + }, + { + "teal": 3684, + "source": 924, + "pc": [ + 3786, + 3787, + 3788, + 3789, + 3790, + 3791, + 3792, + 3793, + 3794, + 3795, + 3796, + 3797, + 3798, + 3799, + 3800, + 3801, + 3802, + 3803 + ] + }, + { + "teal": 3685, + "source": 924, + "pc": [ + 3804 + ] + }, + { + "teal": 3692, + "source": 933, + "pc": [ + 3805, + 3806, + 3807 + ] + }, + { + "teal": 3695, + "source": 933, + "pc": [ + 3808, + 3809 + ] + }, + { + "teal": 3699, + "source": 934, + "pc": [ + 3810, + 3811, + 3812 + ] + }, + { + "teal": 3700, + "source": 934, + "pc": [ + 3813, + 3814 + ] + }, + { + "teal": 3704, + "source": 936, + "pc": [ + 3815, + 3816 + ] + }, + { + "teal": 3705, + "source": 936, + "pc": [ + 3817, + 3818 + ] + }, + { + "teal": 3706, + "source": 936, + "pc": [ + 3819 + ] + }, + { + "teal": 3707, + "source": 936, + "pc": [ + 3820 + ] + }, + { + "teal": 3708, + "source": 936, + "pc": [ + 3821, + 3822 + ] + }, + { + "teal": 3709, + "source": 936, + "pc": [ + 3823 + ] + }, + { + "teal": 3710, + "source": 936, + "pc": [ + 3824 + ] + }, + { + "teal": 3711, + "source": 936, + "pc": [ + 3825 + ] + }, + { + "teal": 3712, + "source": 936, + "pc": [ + 3826 + ] + }, + { + "teal": 3713, + "source": 936, + "pc": [ + 3827 + ] + }, + { + "teal": 3714, + "source": 936, + "pc": [ + 3828 + ] + }, + { + "teal": 3717, + "source": 936, + "pc": [ + 3829, + 3830 + ] + }, + { + "teal": 3718, + "source": 936, + "pc": [ + 3831 + ] + }, + { + "teal": 3722, + "source": 939, + "pc": [ + 3832, + 3833, + 3834 + ] + }, + { + "teal": 3726, + "source": 941, + "pc": [ + 3835, + 3836, + 3837, + 3838, + 3839, + 3840, + 3841, + 3842, + 3843 + ] + }, + { + "teal": 3727, + "source": 941, + "pc": [ + 3844 + ] + }, + { + "teal": 3730, + "source": 39, + "pc": [ + 3845, + 3846, + 3847, + 3848, + 3849, + 3850 + ] + }, + { + "teal": 3731, + "source": 39, + "pc": [ + 3851, + 3852, + 3853 + ] + }, + { + "teal": 3732, + "source": 39, + "pc": [ + 3854, + 3855, + 3856, + 3857 + ] + }, + { + "teal": 3733, + "source": 39, + "pc": [ + 3858 + ] + }, + { + "teal": 3736, + "source": 39, + "pc": [ + 3859, + 3860, + 3861, + 3862, + 3863, + 3864 + ] + }, + { + "teal": 3737, + "source": 39, + "pc": [ + 3865, + 3866, + 3867, + 3868, + 3869, + 3870 + ] + }, + { + "teal": 3738, + "source": 39, + "pc": [ + 3871, + 3872, + 3873, + 3874, + 3875, + 3876 + ] + }, + { + "teal": 3739, + "source": 39, + "pc": [ + 3877, + 3878, + 3879, + 3880, + 3881, + 3882 + ] + }, + { + "teal": 3740, + "source": 39, + "pc": [ + 3883, + 3884, + 3885, + 3886, + 3887, + 3888 + ] + }, + { + "teal": 3741, + "source": 39, + "pc": [ + 3889, + 3890, + 3891, + 3892, + 3893, + 3894 + ] + }, + { + "teal": 3742, + "source": 39, + "pc": [ + 3895, + 3896, + 3897, + 3898, + 3899, + 3900 + ] + }, + { + "teal": 3743, + "source": 39, + "pc": [ + 3901, + 3902, + 3903, + 3904, + 3905, + 3906 + ] + }, + { + "teal": 3744, + "source": 39, + "pc": [ + 3907, + 3908, + 3909, + 3910, + 3911, + 3912 + ] + }, + { + "teal": 3745, + "source": 39, + "pc": [ + 3913, + 3914, + 3915, + 3916, + 3917, + 3918 + ] + }, + { + "teal": 3746, + "source": 39, + "pc": [ + 3919, + 3920, + 3921, + 3922, + 3923, + 3924 + ] + }, + { + "teal": 3747, + "source": 39, + "pc": [ + 3925, + 3926, + 3927, + 3928, + 3929, + 3930 + ] + }, + { + "teal": 3748, + "source": 39, + "pc": [ + 3931, + 3932 + ] + }, + { + "teal": 3749, + "source": 39, + "pc": [ + 3933, + 3934, + 3935 + ] + }, + { + "teal": 3750, + "source": 39, + "pc": [ + 3936, + 3937, + 3938, + 3939, + 3940, + 3941, + 3942, + 3943, + 3944, + 3945, + 3946, + 3947, + 3948, + 3949, + 3950, + 3951, + 3952, + 3953, + 3954, + 3955, + 3956, + 3957, + 3958, + 3959, + 3960, + 3961, + 3962, + 3963 + ] + }, + { + "teal": 3751, + "source": 39, + "pc": [ + 3964 + ] + }, + { + "teal": 3754, + "source": 39, + "pc": [ + 3965, + 3966, + 3967 + ] + }, + { + "teal": 3755, + "source": 39, + "pc": [ + 3968, + 3969, + 3970, + 3971, + 3972, + 3973, + 3974, + 3975, + 3976, + 3977, + 3978, + 3979 + ] + }, + { + "teal": 3756, + "source": 39, + "pc": [ + 3980, + 3981 + ] + }, + { + "teal": 3757, + "source": 39, + "pc": [ + 3982 + ] + }, + { + "teal": 3758, + "source": 39, + "pc": [ + 3983 + ] + }, + { + "teal": 3759, + "source": 39, + "pc": [ + 3984 + ] + }, + { + "teal": 3760, + "source": 39 + }, + { + "teal": 3763, + "source": 39, + "pc": [ + 3985, + 3986, + 3987 + ] + }, + { + "teal": 3764, + "source": 39, + "pc": [ + 3988, + 3989 + ] + }, + { + "teal": 3765, + "source": 39, + "pc": [ + 3990 + ] + }, + { + "teal": 3766, + "source": 39, + "pc": [ + 3991 + ] + }, + { + "teal": 3767, + "source": 39, + "pc": [ + 3992, + 3993, + 3994 + ] + }, + { + "teal": 3768, + "source": 39, + "pc": [ + 3995, + 3996, + 3997 + ] + }, + { + "teal": 3769, + "source": 39, + "pc": [ + 3998 + ] + }, + { + "teal": 3772, + "source": 39, + "pc": [ + 3999, + 4000 + ] + }, + { + "teal": 3773, + "source": 39, + "pc": [ + 4001, + 4002 + ] + }, + { + "teal": 3774, + "source": 39, + "pc": [ + 4003 + ] + }, + { + "teal": 3775, + "source": 39, + "pc": [ + 4004 + ] + }, + { + "teal": 3776, + "source": 39, + "pc": [ + 4005 + ] + }, + { + "teal": 3777, + "source": 39, + "pc": [ + 4006, + 4007, + 4008 + ] + }, + { + "teal": 3778, + "source": 39, + "pc": [ + 4009, + 4010 + ] + }, + { + "teal": 3779, + "source": 39, + "pc": [ + 4011, + 4012 + ] + }, + { + "teal": 3780, + "source": 39, + "pc": [ + 4013 + ] + }, + { + "teal": 3781, + "source": 39, + "pc": [ + 4014, + 4015, + 4016 + ] + }, + { + "teal": 3782, + "source": 39, + "pc": [ + 4017, + 4018, + 4019 + ] + }, + { + "teal": 3785, + "source": 39, + "pc": [ + 4020, + 4021 + ] + }, + { + "teal": 3788, + "source": 39, + "pc": [ + 4022, + 4023 + ] + }, + { + "teal": 3789, + "source": 39, + "pc": [ + 4024, + 4025 + ] + }, + { + "teal": 3790, + "source": 39, + "pc": [ + 4026 + ] + }, + { + "teal": 3791, + "source": 39, + "pc": [ + 4027, + 4028, + 4029 + ] + }, + { + "teal": 3792, + "source": 39, + "pc": [ + 4030 + ] + }, + { + "teal": 3793, + "source": 39, + "pc": [ + 4031 + ] + } +] \ No newline at end of file diff --git a/contracts/contracts/artifacts/ValidatorRegistry.approval.teal b/contracts/contracts/artifacts/ValidatorRegistry.approval.teal new file mode 100644 index 00000000..7d2d0b1c --- /dev/null +++ b/contracts/contracts/artifacts/ValidatorRegistry.approval.teal @@ -0,0 +1,5570 @@ +#pragma version 10 + +// This TEAL was generated by TEALScript v0.88.1 +// https://github.com/algorandfoundation/TEALScript + +// This contract is compliant with and/or implements the following ARCs: [ ARC4 ] + +// The following ten lines of TEAL handle initial program flow +// This pattern is used to make it easy for anyone to parse the start of the program and determine if a specific action is allowed +// Here, action refers to the OnComplete in combination with whether the app is being created or called +// Every possible action for this contract is represented in the switch statement +// If the action is not implemented in the contract, its respective branch will be "*NOT_IMPLEMENTED" which just contains "err" +txn ApplicationID +! +int 6 +* +txn OnCompletion ++ +switch *call_NoOp *NOT_IMPLEMENTED *NOT_IMPLEMENTED *NOT_IMPLEMENTED *NOT_IMPLEMENTED *NOT_IMPLEMENTED *create_NoOp *NOT_IMPLEMENTED *NOT_IMPLEMENTED *NOT_IMPLEMENTED *NOT_IMPLEMENTED *NOT_IMPLEMENTED + +*NOT_IMPLEMENTED: + err + +// createApplication(uint64)void +*abi_route_createApplication: + // poolTemplateAppId: uint64 + txna ApplicationArgs 1 + btoi + + // execute createApplication(uint64)void + callsub createApplication + int 1 + return + +// createApplication(poolTemplateAppId: uint64): void +createApplication: + proto 1 0 + + // contracts/validatorRegistry.algo.ts:194 + // this.numValidators.value = 0 + byte 0x6e756d56 // "numV" + int 0 + app_global_put + + // contracts/validatorRegistry.algo.ts:195 + // this.stakingPoolTemplateAppId.value = poolTemplateAppId + byte 0x706f6f6c54656d706c6174654170704964 // "poolTemplateAppId" + frame_dig -1 // poolTemplateAppId: uint64 + app_global_put + + // contracts/validatorRegistry.algo.ts:196 + // this.numStakers.value = 0 + byte 0x6e756d5374616b657273 // "numStakers" + int 0 + app_global_put + + // contracts/validatorRegistry.algo.ts:197 + // this.totalAlgoStaked.value = 0 + byte 0x7374616b6564 // "staked" + int 0 + app_global_put + retsub + +// gas()void +*abi_route_gas: + // execute gas()void + callsub gas + int 1 + return + +// gas(): void +// +// gas is a dummy no-op call that can be used to pool-up resource references and opcode cost +gas: + proto 0 0 + retsub + +// getMbrAmounts()(uint64,uint64,uint64,uint64) +*abi_route_getMbrAmounts: + // The ABI return prefix + byte 0x151f7c75 + + // execute getMbrAmounts()(uint64,uint64,uint64,uint64) + callsub getMbrAmounts + concat + log + int 1 + return + +// getMbrAmounts(): MbrAmounts +// +// Returns the MBR amounts needed for various actions: +// [ +// addValidatorMbr: uint64 - mbr needed to add a new validator - paid to validator contract +// addPoolMbr: uint64 - mbr needed to add a new pool - paid to validator +// poolInitMbr: uint64 - mbr needed to initStorage() of pool - paid to pool itself +// addStakerMbr: uint64 - mbr staker needs to add to first staking payment (stays w/ validator) +// ] +getMbrAmounts: + proto 0 1 + + // contracts/validatorRegistry.algo.ts:217 + // return { + // addValidatorMbr: this.costForBoxStorage(1 /* v prefix */ + len() + len()), + // addPoolMbr: this.minBalanceForAccount( + // 1, + // 0, + // 0, + // 0, + // 0, + // StakingPool.schema.global.numUint, + // StakingPool.schema.global.numByteSlice + // ), + // poolInitMbr: + // ALGORAND_ACCOUNT_MIN_BALANCE + + // this.costForBoxStorage(7 /* 'stakers' name */ + len() * MAX_STAKERS_PER_POOL), + // addStakerMbr: + // // how much to charge for first time a staker adds stake - since we add a tracking box per staker + // this.costForBoxStorage( + // 3 /* 'sps' prefix */ + len
() + len() * MAX_POOLS_PER_STAKER + // ), // size of key + all values + // }; + int 1067 + callsub costForBoxStorage + itob + int 1 + int 8 + int 0 + dupn 3 + int 1 + callsub minBalanceForAccount + itob + concat + int 100000 + int 12807 + callsub costForBoxStorage + + + itob + concat + int 179 + callsub costForBoxStorage + itob + concat + retsub + +// getProtocolConstraints()(uint64,uint64,uint64,uint64,uint64,uint64,uint64,uint64,uint64,uint64,uint64) +*abi_route_getProtocolConstraints: + // The ABI return prefix + byte 0x151f7c75 + + // execute getProtocolConstraints()(uint64,uint64,uint64,uint64,uint64,uint64,uint64,uint64,uint64,uint64,uint64) + callsub getProtocolConstraints + concat + log + int 1 + return + +// getProtocolConstraints(): Constraints +// +// Returns the protocol constraints so that UIs can limit what users specify for validator configuration parameters. +getProtocolConstraints: + proto 0 1 + + // contracts/validatorRegistry.algo.ts:243 + // return { + // epochPayoutMinsMin: MIN_PAYOUT_MINS, + // epochPayoutMinsMax: MAX_PAYOUT_MINS, + // minPctToValidatorWFourDecimals: MIN_PCT_TO_VALIDATOR, + // maxPctToValidatorWFourDecimals: MAX_PCT_TO_VALIDATOR, + // minEntryStake: MIN_ALGO_STAKE_PER_POOL, + // maxAlgoPerPool: this.maxAlgoAllowedPerPool(), + // maxAlgoPerValidator: this.maxAllowedStake(), + // amtConsideredSaturated: this.algoSaturationLevel(), + // maxNodes: MAX_NODES, + // maxPoolsPerNode: MAX_POOLS_PER_NODE, + // maxStakersPerPool: MAX_STAKERS_PER_POOL, + // }; + byte 0x00000000000000010000000000002760000000000000000000000000000f424000000000000f4240 + callsub maxAlgoAllowedPerPool + itob + concat + callsub maxAllowedStake + itob + concat + callsub algoSaturationLevel + itob + concat + byte 0x0000000000000008 + concat + byte 0x0000000000000003 + concat + byte 0x00000000000000c8 + concat + retsub + +// getNumValidators()uint64 +*abi_route_getNumValidators: + // The ABI return prefix + byte 0x151f7c75 + + // execute getNumValidators()uint64 + callsub getNumValidators + itob + concat + log + int 1 + return + +// getNumValidators(): uint64 +// +// Returns the current number of validators +getNumValidators: + proto 0 1 + + // contracts/validatorRegistry.algo.ts:263 + // return this.numValidators.value; + byte 0x6e756d56 // "numV" + app_global_get + retsub + +// getValidatorConfig(uint64)(uint64,address,address,uint64,uint8,byte[32],uint64,uint64,uint64,uint16,uint32,address,uint64,uint64,uint8,uint64,uint64) +*abi_route_getValidatorConfig: + // The ABI return prefix + byte 0x151f7c75 + + // validatorId: uint64 + txna ApplicationArgs 1 + btoi + + // execute getValidatorConfig(uint64)(uint64,address,address,uint64,uint8,byte[32],uint64,uint64,uint64,uint16,uint32,address,uint64,uint64,uint8,uint64,uint64) + callsub getValidatorConfig + concat + log + int 1 + return + +// getValidatorConfig(validatorId: ValidatorIdType): ValidatorConfig +getValidatorConfig: + proto 1 1 + + // contracts/validatorRegistry.algo.ts:268 + // return this.validatorList(validatorId).value.config; + int 0 + int 208 + byte 0x76 // "v" + frame_dig -1 // validatorId: ValidatorIdType + itob + concat + cover 2 + box_extract + retsub + +// getValidatorState(uint64)(uint16,uint64,uint64,uint64) +*abi_route_getValidatorState: + // The ABI return prefix + byte 0x151f7c75 + + // validatorId: uint64 + txna ApplicationArgs 1 + btoi + + // execute getValidatorState(uint64)(uint16,uint64,uint64,uint64) + callsub getValidatorState + concat + log + int 1 + return + +// getValidatorState(validatorId: ValidatorIdType): ValidatorCurState +getValidatorState: + proto 1 1 + + // contracts/validatorRegistry.algo.ts:273 + // return this.validatorList(validatorId).value.state; + int 208 // headOffset + int 26 + byte 0x76 // "v" + frame_dig -1 // validatorId: ValidatorIdType + itob + concat + cover 2 + box_extract + retsub + +// getValidatorOwnerAndManager(uint64)(address,address) +*abi_route_getValidatorOwnerAndManager: + // The ABI return prefix + byte 0x151f7c75 + + // validatorId: uint64 + txna ApplicationArgs 1 + btoi + + // execute getValidatorOwnerAndManager(uint64)(address,address) + callsub getValidatorOwnerAndManager + concat + log + int 1 + return + +// getValidatorOwnerAndManager(validatorId: ValidatorIdType): [Address, Address] +getValidatorOwnerAndManager: + proto 1 1 + + // contracts/validatorRegistry.algo.ts:278 + // return [ + // this.validatorList(validatorId).value.config.owner, + // this.validatorList(validatorId).value.config.manager, + // ]; + int 8 + int 32 + byte 0x76 // "v" + frame_dig -1 // validatorId: ValidatorIdType + itob + concat + cover 2 + box_extract + int 40 + int 32 + byte 0x76 // "v" + frame_dig -1 // validatorId: ValidatorIdType + itob + concat + cover 2 + box_extract + concat + retsub + +// getPools(uint64)(uint64,uint16,uint64)[] +*abi_route_getPools: + // The ABI return prefix + byte 0x151f7c75 + + // validatorId: uint64 + txna ApplicationArgs 1 + btoi + + // execute getPools(uint64)(uint64,uint16,uint64)[] + callsub getPools + dup + len + int 18 + / + itob + extract 6 2 + swap + concat + concat + log + int 1 + return + +// getPools(validatorId: ValidatorIdType): PoolInfo[] +// +// Return list of all pools for this validator. +// @param {uint64} validatorId +// @return {PoolInfo[]} - array of pools +// Not callable from other contracts because >1K return but can be called w/ simulate which bumps log returns +getPools: + proto 1 1 + + // Push empty bytes after the frame pointer to reserve space for local variables + byte 0x + dupn 2 + + // contracts/validatorRegistry.algo.ts:292 + // retData: PoolInfo[] = [] + byte 0x + frame_bury 0 // retData: PoolInfo[] + + // contracts/validatorRegistry.algo.ts:293 + // poolSet = clone(this.validatorList(validatorId).value.pools) + int 234 // headOffset + int 432 + byte 0x76 // "v" + frame_dig -1 // validatorId: ValidatorIdType + itob + concat + cover 2 + box_extract + frame_bury 1 // poolSet: (uint64,uint16,uint64)[24] + + // contracts/validatorRegistry.algo.ts:294 + // for (let i = 0; i < poolSet.length; i += 1) + int 0 + frame_bury 2 // i: uint64 + +*for_0: + // contracts/validatorRegistry.algo.ts:294 + // i < poolSet.length + frame_dig 2 // i: uint64 + int 24 + < + bz *for_0_end + + // *if0_condition + // contracts/validatorRegistry.algo.ts:295 + // poolSet[i].poolAppId === 0 + frame_dig 1 // poolSet: (uint64,uint16,uint64)[24] + frame_dig 2 // i: uint64 + int 18 + * // acc * typeLength + int 0 + + + int 8 + extract3 + btoi + int 0 + == + bz *if0_end + + // *if0_consequent + b *for_0_end + +*if0_end: + // contracts/validatorRegistry.algo.ts:299 + // retData.push(poolSet[i]) + frame_dig 0 // retData: PoolInfo[] + frame_dig 1 // poolSet: (uint64,uint16,uint64)[24] + frame_dig 2 // i: uint64 + int 18 + * // acc * typeLength + int 18 + extract3 + concat + frame_bury 0 // retData: PoolInfo[] + +*for_0_continue: + // contracts/validatorRegistry.algo.ts:294 + // i += 1 + frame_dig 2 // i: uint64 + int 1 + + + frame_bury 2 // i: uint64 + b *for_0 + +*for_0_end: + // contracts/validatorRegistry.algo.ts:301 + // return retData; + frame_dig 0 // retData: PoolInfo[] + + // set the subroutine return value + frame_bury 0 + + // pop all local variables from the stack + popn 2 + retsub + +// getPoolAppId(uint64,uint64)uint64 +*abi_route_getPoolAppId: + // The ABI return prefix + byte 0x151f7c75 + + // poolId: uint64 + txna ApplicationArgs 2 + btoi + + // validatorId: uint64 + txna ApplicationArgs 1 + btoi + + // execute getPoolAppId(uint64,uint64)uint64 + callsub getPoolAppId + itob + concat + log + int 1 + return + +// getPoolAppId(validatorId: uint64, poolId: uint64): uint64 +getPoolAppId: + proto 2 1 + + // contracts/validatorRegistry.algo.ts:309 + // assert(poolId !== 0 && poolId <= this.validatorList(validatorId).value.pools.length) + frame_dig -2 // poolId: uint64 + int 0 + != + dup + bz *skip_and0 + frame_dig -2 // poolId: uint64 + int 24 + <= + && + +*skip_and0: + assert + + // contracts/validatorRegistry.algo.ts:310 + // return this.validatorList(validatorId).value.pools[poolId - 1].poolAppId; + int 234 // headOffset + frame_dig -2 // poolId: uint64 + int 1 + - + int 18 + * // acc * typeLength + + + int 0 + + + int 8 + byte 0x76 // "v" + frame_dig -1 // validatorId: uint64 + itob + concat + cover 2 + box_extract + btoi + retsub + +// getPoolInfo((uint64,uint64,uint64))(uint64,uint16,uint64) +*abi_route_getPoolInfo: + // The ABI return prefix + byte 0x151f7c75 + + // poolKey: (uint64,uint64,uint64) + txna ApplicationArgs 1 + dup + len + int 24 + == + assert + + // execute getPoolInfo((uint64,uint64,uint64))(uint64,uint16,uint64) + callsub getPoolInfo + concat + log + int 1 + return + +// getPoolInfo(poolKey: ValidatorPoolKey): PoolInfo +getPoolInfo: + proto 1 1 + + // contracts/validatorRegistry.algo.ts:315 + // return this.validatorList(poolKey.id).value.pools[poolKey.poolId - 1]; + int 234 // headOffset + frame_dig -1 // poolKey: ValidatorPoolKey + extract 8 8 + btoi + int 1 + - + int 18 + * // acc * typeLength + + + int 18 + byte 0x76 // "v" + frame_dig -1 // poolKey: ValidatorPoolKey + extract 0 8 + btoi + itob + concat + cover 2 + box_extract + retsub + +// getCurMaxStakePerPool(uint64)uint64 +*abi_route_getCurMaxStakePerPool: + // The ABI return prefix + byte 0x151f7c75 + + // validatorId: uint64 + txna ApplicationArgs 1 + btoi + + // execute getCurMaxStakePerPool(uint64)uint64 + callsub getCurMaxStakePerPool + itob + concat + log + int 1 + return + +// getCurMaxStakePerPool(validatorId: ValidatorIdType): uint64 +// +// Calculate the maximum stake per pool for a given validator. +// Normally this would be maxAlgoPerPool, but it should also never go above MaxAllowedStake / numPools so +// as pools are added the max allowed per pool can reduce. +// +// @param {ValidatorIdType} validatorId - The id of the validator. +getCurMaxStakePerPool: + proto 1 1 + + // Push empty bytes after the frame pointer to reserve space for local variables + byte 0x + dupn 2 + + // contracts/validatorRegistry.algo.ts:326 + // numPools = this.validatorList(validatorId).value.state.numPools as uint64 + int 208 + int 2 + byte 0x76 // "v" + frame_dig -1 // validatorId: ValidatorIdType + itob + concat + cover 2 + box_extract + btoi + frame_bury 0 // numPools: uint64 + + // contracts/validatorRegistry.algo.ts:327 + // hardMaxDividedBetweenPools = this.maxAllowedStake() / numPools + callsub maxAllowedStake + frame_dig 0 // numPools: uint64 + / + frame_bury 1 // hardMaxDividedBetweenPools: uint64 + + // contracts/validatorRegistry.algo.ts:328 + // maxPerPool: uint64 = this.validatorList(validatorId).value.config.maxAlgoPerPool + int 183 + int 8 + byte 0x76 // "v" + frame_dig -1 // validatorId: ValidatorIdType + itob + concat + cover 2 + box_extract + btoi + frame_bury 2 // maxPerPool: uint64 + + // *if1_condition + // contracts/validatorRegistry.algo.ts:329 + // maxPerPool === 0 + frame_dig 2 // maxPerPool: uint64 + int 0 + == + bz *if1_end + + // *if1_consequent + // contracts/validatorRegistry.algo.ts:330 + // maxPerPool = this.maxAlgoAllowedPerPool() + callsub maxAlgoAllowedPerPool + frame_bury 2 // maxPerPool: uint64 + +*if1_end: + // *if2_condition + // contracts/validatorRegistry.algo.ts:332 + // hardMaxDividedBetweenPools < maxPerPool + frame_dig 1 // hardMaxDividedBetweenPools: uint64 + frame_dig 2 // maxPerPool: uint64 + < + bz *if2_end + + // *if2_consequent + // contracts/validatorRegistry.algo.ts:333 + // maxPerPool = hardMaxDividedBetweenPools + frame_dig 1 // hardMaxDividedBetweenPools: uint64 + frame_bury 2 // maxPerPool: uint64 + +*if2_end: + // contracts/validatorRegistry.algo.ts:335 + // return maxPerPool; + frame_dig 2 // maxPerPool: uint64 + + // set the subroutine return value + frame_bury 0 + + // pop all local variables from the stack + popn 2 + retsub + +// doesStakerNeedToPayMBR(address)bool +*abi_route_doesStakerNeedToPayMBR: + // The ABI return prefix + byte 0x151f7c75 + + // staker: address + txna ApplicationArgs 1 + dup + len + int 32 + == + assert + + // execute doesStakerNeedToPayMBR(address)bool + callsub doesStakerNeedToPayMBR + byte 0x00 + int 0 + uncover 2 + setbit + concat + log + int 1 + return + +// doesStakerNeedToPayMBR(staker: Address): boolean +// +// Helper callers can call w/ simulate to determine if 'AddStaker' MBR should be included w/ staking amount +// @param staker +doesStakerNeedToPayMBR: + proto 1 1 + + // contracts/validatorRegistry.algo.ts:344 + // return !this.stakerPoolSet(staker).exists; + byte 0x737073 // "sps" + frame_dig -1 // staker: Address + concat + box_len + swap + pop + ! + retsub + +// getStakedPoolsForAccount(address)(uint64,uint64,uint64)[] +*abi_route_getStakedPoolsForAccount: + // The ABI return prefix + byte 0x151f7c75 + + // staker: address + txna ApplicationArgs 1 + dup + len + int 32 + == + assert + + // execute getStakedPoolsForAccount(address)(uint64,uint64,uint64)[] + callsub getStakedPoolsForAccount + dup + len + int 24 + / + itob + extract 6 2 + swap + concat + concat + log + int 1 + return + +// getStakedPoolsForAccount(staker: Address): ValidatorPoolKey[] +// +// Retrieves the staked pools for an account. +// +// @param {Address} staker - The account to retrieve staked pools for. +// @return {ValidatorPoolKey[]} - The array of staked pools for the account. +getStakedPoolsForAccount: + proto 1 1 + + // Push empty bytes after the frame pointer to reserve space for local variables + byte 0x + dupn 2 + + // *if3_condition + // contracts/validatorRegistry.algo.ts:354 + // !this.stakerPoolSet(staker).exists + byte 0x737073 // "sps" + frame_dig -1 // staker: Address + concat + box_len + swap + pop + ! + bz *if3_end + + // *if3_consequent + // contracts/validatorRegistry.algo.ts:355 + // return []; + byte 0x + retsub + +*if3_end: + // contracts/validatorRegistry.algo.ts:357 + // retData: ValidatorPoolKey[] = [] + byte 0x + frame_bury 0 // retData: ValidatorPoolKey[] + + // contracts/validatorRegistry.algo.ts:358 + // poolSet = clone(this.stakerPoolSet(staker).value) + byte 0x737073 // "sps" + frame_dig -1 // staker: Address + concat + box_get + assert + frame_bury 1 // poolSet: (uint64,uint64,uint64)[6] + + // contracts/validatorRegistry.algo.ts:359 + // for (let i = 0; i < poolSet.length; i += 1) + int 0 + frame_bury 2 // i: uint64 + +*for_1: + // contracts/validatorRegistry.algo.ts:359 + // i < poolSet.length + frame_dig 2 // i: uint64 + int 6 + < + bz *for_1_end + + // *if4_condition + // contracts/validatorRegistry.algo.ts:360 + // poolSet[i].id !== 0 + frame_dig 1 // poolSet: (uint64,uint64,uint64)[6] + frame_dig 2 // i: uint64 + int 24 + * // acc * typeLength + int 0 + + + int 8 + extract3 + btoi + int 0 + != + bz *if4_end + + // *if4_consequent + // contracts/validatorRegistry.algo.ts:361 + // retData.push(poolSet[i]) + frame_dig 0 // retData: ValidatorPoolKey[] + frame_dig 1 // poolSet: (uint64,uint64,uint64)[6] + frame_dig 2 // i: uint64 + int 24 + * // acc * typeLength + int 24 + extract3 + concat + frame_bury 0 // retData: ValidatorPoolKey[] + +*if4_end: + +*for_1_continue: + // contracts/validatorRegistry.algo.ts:359 + // i += 1 + frame_dig 2 // i: uint64 + int 1 + + + frame_bury 2 // i: uint64 + b *for_1 + +*for_1_end: + // contracts/validatorRegistry.algo.ts:364 + // return retData; + frame_dig 0 // retData: ValidatorPoolKey[] + + // set the subroutine return value + frame_bury 0 + + // pop all local variables from the stack + popn 2 + retsub + +// getTokenPayoutRatio(uint64)(uint64[24],uint64) +*abi_route_getTokenPayoutRatio: + // The ABI return prefix + byte 0x151f7c75 + + // validatorId: uint64 + txna ApplicationArgs 1 + btoi + + // execute getTokenPayoutRatio(uint64)(uint64[24],uint64) + callsub getTokenPayoutRatio + concat + log + int 1 + return + +// getTokenPayoutRatio(validatorId: ValidatorIdType): PoolTokenPayoutRatio +// +// Retrieves the token payout ratio for a given validator - returning the pool ratios of whole so that token +// payouts across pools can be based on a stable snaphost of stake. +// +// @param {ValidatorIdType} validatorId - The id of the validator. +// @return {PoolTokenPayoutRatio} - The token payout ratio for the validator. +getTokenPayoutRatio: + proto 1 1 + + // contracts/validatorRegistry.algo.ts:376 + // return this.validatorList(validatorId).value.tokenPayoutRatio; + int 666 // headOffset + int 200 + byte 0x76 // "v" + frame_dig -1 // validatorId: ValidatorIdType + itob + concat + cover 2 + box_extract + retsub + +// getNodePoolAssignments(uint64)((uint64[3])[8]) +*abi_route_getNodePoolAssignments: + // The ABI return prefix + byte 0x151f7c75 + + // validatorId: uint64 + txna ApplicationArgs 1 + btoi + + // execute getNodePoolAssignments(uint64)((uint64[3])[8]) + callsub getNodePoolAssignments + concat + log + int 1 + return + +// getNodePoolAssignments(validatorId: uint64): NodePoolAssignmentConfig +getNodePoolAssignments: + proto 1 1 + + // contracts/validatorRegistry.algo.ts:381 + // assert(this.validatorList(validatorId).exists) + byte 0x76 // "v" + frame_dig -1 // validatorId: uint64 + itob + concat + box_len + swap + pop + assert + + // contracts/validatorRegistry.algo.ts:383 + // return this.validatorList(validatorId).value.nodePoolAssignments; + int 866 // headOffset + int 192 + byte 0x76 // "v" + frame_dig -1 // validatorId: uint64 + itob + concat + cover 2 + box_extract + retsub + +// getNFDRegistryID()uint64 +*abi_route_getNFDRegistryID: + // The ABI return prefix + byte 0x151f7c75 + + // execute getNFDRegistryID()uint64 + callsub getNFDRegistryID + itob + concat + log + int 1 + return + +// getNFDRegistryID(): uint64 +getNFDRegistryID: + proto 0 1 + + // contracts/validatorRegistry.algo.ts:387 + // return this.nfdRegistryAppId; + pushint TMPL_nfdRegistryAppId + retsub + +// addValidator(pay,string,(uint64,address,address,uint64,uint8,byte[32],uint64,uint64,uint64,uint16,uint32,address,uint64,uint64,uint8,uint64,uint64))uint64 +*abi_route_addValidator: + // The ABI return prefix + byte 0x151f7c75 + + // config: (uint64,address,address,uint64,uint8,byte[32],uint64,uint64,uint64,uint16,uint32,address,uint64,uint64,uint8,uint64,uint64) + txna ApplicationArgs 2 + dup + len + int 208 + == + assert + + // nfdName: string + txna ApplicationArgs 1 + extract 2 0 + + // mbrPayment: pay + txn GroupIndex + int 1 + - + dup + gtxns TypeEnum + int pay + == + assert + + // execute addValidator(pay,string,(uint64,address,address,uint64,uint8,byte[32],uint64,uint64,uint64,uint16,uint32,address,uint64,uint64,uint8,uint64,uint64))uint64 + callsub addValidator + itob + concat + log + int 1 + return + +// addValidator(mbrPayment: PayTxn, nfdName: string, config: ValidatorConfig): uint64 +// +// Adds a new validator +// @param mbrPayment payment from caller which covers mbr increase of new validator storage +// @param nfdName (Optional) Name of nfd (used as double-check against id specified in config) +// @param config ValidatorConfig struct +// @returns validator id +addValidator: + proto 3 1 + + // Push empty bytes after the frame pointer to reserve space for local variables + byte 0x + dup + + // contracts/validatorRegistry.algo.ts:397 + // this.validateConfig(config) + frame_dig -3 // config: ValidatorConfig + callsub validateConfig + + // contracts/validatorRegistry.algo.ts:398 + // assert(config.owner !== Address.zeroAddress) + frame_dig -3 // config: ValidatorConfig + extract 8 32 + global ZeroAddress + != + assert + + // contracts/validatorRegistry.algo.ts:399 + // assert(config.manager !== Address.zeroAddress) + frame_dig -3 // config: ValidatorConfig + extract 40 32 + global ZeroAddress + != + assert + + // contracts/validatorRegistry.algo.ts:400 + // assert(this.txn.sender === config.owner, 'sender must be owner to add new validator') + txn Sender + frame_dig -3 // config: ValidatorConfig + extract 8 32 + == + + // sender must be owner to add new validator + assert + + // contracts/validatorRegistry.algo.ts:402 + // verifyPayTxn(mbrPayment, { amount: this.getMbrAmounts().addValidatorMbr }) + // verify amount + frame_dig -1 // mbrPayment: PayTxn + gtxns Amount + callsub getMbrAmounts + extract 0 8 + btoi + == + assert + + // contracts/validatorRegistry.algo.ts:405 + // validatorId = this.numValidators.value + 1 + byte 0x6e756d56 // "numV" + app_global_get + int 1 + + + frame_bury 0 // validatorId: uint64 + + // contracts/validatorRegistry.algo.ts:406 + // this.numValidators.value = validatorId + byte 0x6e756d56 // "numV" + frame_dig 0 // validatorId: uint64 + app_global_put + + // contracts/validatorRegistry.algo.ts:408 + // this.validatorList(validatorId).create() + byte 0x76 // "v" + frame_dig 0 // validatorId: uint64 + itob + concat + int 1058 + box_create + pop + + // contracts/validatorRegistry.algo.ts:409 + // this.validatorList(validatorId).value.config = config + int 0 + frame_dig -3 // config: ValidatorConfig + byte 0x76 // "v" + frame_dig 0 // validatorId: uint64 + itob + concat + cover 2 + box_replace + + // contracts/validatorRegistry.algo.ts:410 + // this.validatorList(validatorId).value.config.id = validatorId + int 0 + frame_dig 0 // validatorId: uint64 + itob + byte 0x76 // "v" + frame_dig 0 // validatorId: uint64 + itob + concat + cover 2 + box_replace + + // *if5_condition + // contracts/validatorRegistry.algo.ts:413 + // config.nfdForInfo !== 0 + frame_dig -3 // config: ValidatorConfig + extract 72 8 + btoi + int 0 + != + bz *if5_end + + // *if5_consequent + // contracts/validatorRegistry.algo.ts:415 + // sendAppCall({ + // applicationID: AppID.fromUint64(this.nfdRegistryAppId), + // applicationArgs: ['is_valid_nfd_appid', nfdName, itob(config.nfdForInfo)], + // applications: [AppID.fromUint64(config.nfdForInfo)], + // }) + itxn_begin + int appl + itxn_field TypeEnum + + // contracts/validatorRegistry.algo.ts:416 + // applicationID: AppID.fromUint64(this.nfdRegistryAppId) + pushint TMPL_nfdRegistryAppId + itxn_field ApplicationID + + // contracts/validatorRegistry.algo.ts:417 + // applicationArgs: ['is_valid_nfd_appid', nfdName, itob(config.nfdForInfo)] + byte 0x69735f76616c69645f6e66645f6170706964 // "is_valid_nfd_appid" + itxn_field ApplicationArgs + frame_dig -2 // nfdName: string + itxn_field ApplicationArgs + frame_dig -3 // config: ValidatorConfig + extract 72 8 + btoi + itob + itxn_field ApplicationArgs + + // contracts/validatorRegistry.algo.ts:418 + // applications: [AppID.fromUint64(config.nfdForInfo)] + frame_dig -3 // config: ValidatorConfig + extract 72 8 + btoi + itxn_field Applications + + // Fee field not set, defaulting to 0 + int 0 + itxn_field Fee + + // Submit inner transaction + itxn_submit + + // contracts/validatorRegistry.algo.ts:420 + // assert(btoi(this.itxn.lastLog) === 1, "provided NFD isn't valid") + itxn LastLog + btoi + int 1 + == + + // provided NFD isn't valid + assert + + // contracts/validatorRegistry.algo.ts:422 + // assert( + // this.txn.sender === (AppID.fromUint64(config.nfdForInfo).globalState('i.owner.a') as Address), + // 'If specifying NFD, account adding validator must be owner' + // ) + txn Sender + frame_dig -3 // config: ValidatorConfig + extract 72 8 + btoi + byte 0x692e6f776e65722e61 // "i.owner.a" + app_global_get_ex + assert + == + + // If specifying NFD, account adding validator must be owner + assert + +*if5_end: + // *if6_condition + // contracts/validatorRegistry.algo.ts:427 + // config.entryGatingType === GATING_TYPE_CREATED_BY_NFD_ADDRESSES + frame_dig -3 // config: ValidatorConfig + extract 80 1 + btoi + int 3 + == + bz *if6_end + + // *if6_consequent + // contracts/validatorRegistry.algo.ts:429 + // assert(config.nfdForInfo !== 0, 'an NFD must be specified for the validator when gating by NFD addresses') + frame_dig -3 // config: ValidatorConfig + extract 72 8 + btoi + int 0 + != + + // an NFD must be specified for the validator when gating by NFD addresses + assert + +*if6_end: + // *if7_condition + // contracts/validatorRegistry.algo.ts:431 + // config.entryGatingType === GATING_TYPE_SEGMENT_OF_NFD + frame_dig -3 // config: ValidatorConfig + extract 80 1 + btoi + int 4 + == + bz *if7_end + + // *if7_consequent + // contracts/validatorRegistry.algo.ts:433 + // nfdRootAppID = extractUint64(config.entryGatingValue, 0) + frame_dig -3 // config: ValidatorConfig + extract 81 32 + int 0 + extract_uint64 + frame_bury 1 // nfdRootAppID: uint64 + + // contracts/validatorRegistry.algo.ts:434 + // assert(this.isNFDAppIDValid(nfdRootAppID), 'provided NFD App id for gating must be valid NFD') + frame_dig 1 // nfdRootAppID: uint64 + callsub isNFDAppIDValid + + // provided NFD App id for gating must be valid NFD + assert + +*if7_end: + // contracts/validatorRegistry.algo.ts:437 + // return validatorId; + frame_dig 0 // validatorId: uint64 + + // set the subroutine return value + frame_bury 0 + + // pop all local variables from the stack + popn 1 + retsub + +// changeValidatorManager(uint64,address)void +*abi_route_changeValidatorManager: + // manager: address + txna ApplicationArgs 2 + dup + len + int 32 + == + assert + + // validatorId: uint64 + txna ApplicationArgs 1 + btoi + + // execute changeValidatorManager(uint64,address)void + callsub changeValidatorManager + int 1 + return + +// changeValidatorManager(validatorId: ValidatorIdType, manager: Address): void +// +// Changes the Validator manager for a specific Validator id. +// [ ONLY OWNER CAN CHANGE ] +// +// @param {ValidatorIdType} validatorId - The id of the validator to change the manager for. +// @param {Address} manager - The new manager address. +changeValidatorManager: + proto 2 0 + + // contracts/validatorRegistry.algo.ts:448 + // assert(this.txn.sender === this.validatorList(validatorId).value.config.owner) + txn Sender + int 8 + int 32 + byte 0x76 // "v" + frame_dig -1 // validatorId: ValidatorIdType + itob + concat + cover 2 + box_extract + == + assert + + // contracts/validatorRegistry.algo.ts:449 + // this.validatorList(validatorId).value.config.manager = manager + int 40 + frame_dig -2 // manager: Address + byte 0x76 // "v" + frame_dig -1 // validatorId: ValidatorIdType + itob + concat + cover 2 + box_replace + retsub + +// changeValidatorSunsetInfo(uint64,uint64,uint64)void +*abi_route_changeValidatorSunsetInfo: + // sunsettingTo: uint64 + txna ApplicationArgs 3 + btoi + + // sunsettingOn: uint64 + txna ApplicationArgs 2 + btoi + + // validatorId: uint64 + txna ApplicationArgs 1 + btoi + + // execute changeValidatorSunsetInfo(uint64,uint64,uint64)void + callsub changeValidatorSunsetInfo + int 1 + return + +// changeValidatorSunsetInfo(validatorId: ValidatorIdType, sunsettingOn: uint64, sunsettingTo: ValidatorIdType): void +// +// Updates the sunset information for a given validator. +// [ ONLY OWNER CAN CHANGE ] +// +// @param {ValidatorIdType} validatorId - The id of the validator to update. +// @param {uint64} sunsettingOn - The new sunset timestamp. +// @param {uint64} sunsettingTo - The new sunset to validator id. +changeValidatorSunsetInfo: + proto 3 0 + + // contracts/validatorRegistry.algo.ts:461 + // assert(this.txn.sender === this.validatorList(validatorId).value.config.owner) + txn Sender + int 8 + int 32 + byte 0x76 // "v" + frame_dig -1 // validatorId: ValidatorIdType + itob + concat + cover 2 + box_extract + == + assert + + // contracts/validatorRegistry.algo.ts:462 + // this.validatorList(validatorId).value.config.sunsettingOn = sunsettingOn + int 192 + frame_dig -2 // sunsettingOn: uint64 + itob + byte 0x76 // "v" + frame_dig -1 // validatorId: ValidatorIdType + itob + concat + cover 2 + box_replace + + // contracts/validatorRegistry.algo.ts:463 + // this.validatorList(validatorId).value.config.sunsettingTo = sunsettingTo + int 200 + frame_dig -3 // sunsettingTo: ValidatorIdType + itob + byte 0x76 // "v" + frame_dig -1 // validatorId: ValidatorIdType + itob + concat + cover 2 + box_replace + retsub + +// changeValidatorNFD(uint64,uint64,string)void +*abi_route_changeValidatorNFD: + // nfdName: string + txna ApplicationArgs 3 + extract 2 0 + + // nfdAppID: uint64 + txna ApplicationArgs 2 + btoi + + // validatorId: uint64 + txna ApplicationArgs 1 + btoi + + // execute changeValidatorNFD(uint64,uint64,string)void + callsub changeValidatorNFD + int 1 + return + +// changeValidatorNFD(validatorId: ValidatorIdType, nfdAppID: uint64, nfdName: string): void +// +// Changes the NFD for a validator in the validatorList contract. +// [ ONLY OWNER OR MANAGER CAN CHANGE ] +// +// @param {ValidatorIdType} validatorId - The id of the validator to update. +// @param {uint64} nfdAppID - The application id of the NFD to assign to the validator. +// @param {string} nfdName - The name of the NFD (which must match) +changeValidatorNFD: + proto 3 0 + + // contracts/validatorRegistry.algo.ts:476 + // assert( + // this.txn.sender === this.validatorList(validatorId).value.config.owner || + // this.txn.sender === this.validatorList(validatorId).value.config.manager + // ) + txn Sender + int 8 + int 32 + byte 0x76 // "v" + frame_dig -1 // validatorId: ValidatorIdType + itob + concat + cover 2 + box_extract + == + dup + bnz *skip_or0 + txn Sender + int 40 + int 32 + byte 0x76 // "v" + frame_dig -1 // validatorId: ValidatorIdType + itob + concat + cover 2 + box_extract + == + || + +*skip_or0: + assert + + // contracts/validatorRegistry.algo.ts:481 + // sendAppCall({ + // applicationID: AppID.fromUint64(this.nfdRegistryAppId), + // applicationArgs: ['is_valid_nfd_appid', nfdName, itob(nfdAppID)], + // applications: [AppID.fromUint64(nfdAppID)], + // }) + itxn_begin + int appl + itxn_field TypeEnum + + // contracts/validatorRegistry.algo.ts:482 + // applicationID: AppID.fromUint64(this.nfdRegistryAppId) + pushint TMPL_nfdRegistryAppId + itxn_field ApplicationID + + // contracts/validatorRegistry.algo.ts:483 + // applicationArgs: ['is_valid_nfd_appid', nfdName, itob(nfdAppID)] + byte 0x69735f76616c69645f6e66645f6170706964 // "is_valid_nfd_appid" + itxn_field ApplicationArgs + frame_dig -3 // nfdName: string + itxn_field ApplicationArgs + frame_dig -2 // nfdAppID: uint64 + itob + itxn_field ApplicationArgs + + // contracts/validatorRegistry.algo.ts:484 + // applications: [AppID.fromUint64(nfdAppID)] + frame_dig -2 // nfdAppID: uint64 + itxn_field Applications + + // Fee field not set, defaulting to 0 + int 0 + itxn_field Fee + + // Submit inner transaction + itxn_submit + + // contracts/validatorRegistry.algo.ts:487 + // assert( + // this.txn.sender === (AppID.fromUint64(nfdAppID).globalState('i.owner.a') as Address), + // 'If specifying NFD, account adding validator must be owner' + // ) + txn Sender + frame_dig -2 // nfdAppID: uint64 + byte 0x692e6f776e65722e61 // "i.owner.a" + app_global_get_ex + assert + == + + // If specifying NFD, account adding validator must be owner + assert + + // contracts/validatorRegistry.algo.ts:491 + // this.validatorList(validatorId).value.config.nfdForInfo = nfdAppID + int 72 + frame_dig -2 // nfdAppID: uint64 + itob + byte 0x76 // "v" + frame_dig -1 // validatorId: ValidatorIdType + itob + concat + cover 2 + box_replace + retsub + +// changeValidatorCommissionAddress(uint64,address)void +*abi_route_changeValidatorCommissionAddress: + // commissionAddress: address + txna ApplicationArgs 2 + dup + len + int 32 + == + assert + + // validatorId: uint64 + txna ApplicationArgs 1 + btoi + + // execute changeValidatorCommissionAddress(uint64,address)void + callsub changeValidatorCommissionAddress + int 1 + return + +// changeValidatorCommissionAddress(validatorId: ValidatorIdType, commissionAddress: Address): void +// +// Change the commission address that validator rewards are sent to. +// [ ONLY OWNER CAN CHANGE ] +changeValidatorCommissionAddress: + proto 2 0 + + // contracts/validatorRegistry.algo.ts:499 + // assert(this.txn.sender === this.validatorList(validatorId).value.config.owner) + txn Sender + int 8 + int 32 + byte 0x76 // "v" + frame_dig -1 // validatorId: ValidatorIdType + itob + concat + cover 2 + box_extract + == + assert + + // contracts/validatorRegistry.algo.ts:500 + // assert(commissionAddress !== Address.zeroAddress) + frame_dig -2 // commissionAddress: Address + global ZeroAddress + != + assert + + // contracts/validatorRegistry.algo.ts:501 + // this.validatorList(validatorId).value.config.validatorCommissionAddress = commissionAddress + int 143 + frame_dig -2 // commissionAddress: Address + byte 0x76 // "v" + frame_dig -1 // validatorId: ValidatorIdType + itob + concat + cover 2 + box_replace + retsub + +// changeValidatorRewardInfo(uint64,uint8,byte[32],uint64,uint64)void +*abi_route_changeValidatorRewardInfo: + // RewardPerPayout: uint64 + txna ApplicationArgs 5 + btoi + + // GatingAssetMinBalance: uint64 + txna ApplicationArgs 4 + btoi + + // EntryGatingValue: byte[32] + txna ApplicationArgs 3 + dup + len + int 32 + == + assert + + // EntryGatingType: uint8 + txna ApplicationArgs 2 + dup + len + int 1 + == + assert + btoi + + // validatorId: uint64 + txna ApplicationArgs 1 + btoi + + // execute changeValidatorRewardInfo(uint64,uint8,byte[32],uint64,uint64)void + callsub changeValidatorRewardInfo + int 1 + return + +// changeValidatorRewardInfo(validatorId: ValidatorIdType, EntryGatingType: uint8, EntryGatingValue: bytes32, GatingAssetMinBalance: uint64, RewardPerPayout: uint64): void +// +// Allow the additional rewards (gating entry, additional token rewards) information be changed at will. +// [ ONLY OWNER CAN CHANGE ] +changeValidatorRewardInfo: + proto 5 0 + + // contracts/validatorRegistry.algo.ts:515 + // assert(this.txn.sender === this.validatorList(validatorId).value.config.owner) + txn Sender + int 8 + int 32 + byte 0x76 // "v" + frame_dig -1 // validatorId: ValidatorIdType + itob + concat + cover 2 + box_extract + == + assert + + // contracts/validatorRegistry.algo.ts:517 + // this.validatorList(validatorId).value.config.entryGatingType = EntryGatingType + int 80 + frame_dig -2 // EntryGatingType: uint8 + itob + extract 7 1 + byte 0x76 // "v" + frame_dig -1 // validatorId: ValidatorIdType + itob + concat + cover 2 + box_replace + + // contracts/validatorRegistry.algo.ts:518 + // this.validatorList(validatorId).value.config.entryGatingValue = EntryGatingValue + int 81 + frame_dig -3 // EntryGatingValue: bytes32 + byte 0x76 // "v" + frame_dig -1 // validatorId: ValidatorIdType + itob + concat + cover 2 + box_replace + + // contracts/validatorRegistry.algo.ts:519 + // this.validatorList(validatorId).value.config.gatingAssetMinBalance = GatingAssetMinBalance + int 113 + frame_dig -4 // GatingAssetMinBalance: uint64 + itob + byte 0x76 // "v" + frame_dig -1 // validatorId: ValidatorIdType + itob + concat + cover 2 + box_replace + + // contracts/validatorRegistry.algo.ts:520 + // this.validatorList(validatorId).value.config.rewardPerPayout = RewardPerPayout + int 129 + frame_dig -5 // RewardPerPayout: uint64 + itob + byte 0x76 // "v" + frame_dig -1 // validatorId: ValidatorIdType + itob + concat + cover 2 + box_replace + retsub + +// addPool(pay,uint64,uint64)(uint64,uint64,uint64) +*abi_route_addPool: + // The ABI return prefix + byte 0x151f7c75 + + // nodeNum: uint64 + txna ApplicationArgs 2 + btoi + + // validatorId: uint64 + txna ApplicationArgs 1 + btoi + + // mbrPayment: pay + txn GroupIndex + int 1 + - + dup + gtxns TypeEnum + int pay + == + assert + + // execute addPool(pay,uint64,uint64)(uint64,uint64,uint64) + callsub addPool + concat + log + int 1 + return + +// addPool(mbrPayment: PayTxn, validatorId: ValidatorIdType, nodeNum: uint64): ValidatorPoolKey +// +// Adds a new pool to a validator's pool set, returning the 'key' to reference the pool in the future for staking, etc. +// The caller must pay the cost of the validators MBR increase as well as the MBR that will be needed for the pool itself. +// +// [ ONLY OWNER OR MANAGER CAN call ] +// @param {PayTxn} mbrPayment payment from caller which covers mbr increase of adding a new pool +// @param {uint64} validatorId is id of validator to pool to (must be owner or manager) +// @param {uint64} nodeNum is node number to add to +// @returns {ValidatorPoolKey} pool key to created pool +addPool: + proto 3 1 + + // Push empty bytes after the frame pointer to reserve space for local variables + byte 0x + dup + + // contracts/validatorRegistry.algo.ts:536 + // assert( + // this.txn.sender === this.validatorList(validatorId).value.config.owner || + // this.txn.sender === this.validatorList(validatorId).value.config.manager + // ) + txn Sender + int 8 + int 32 + byte 0x76 // "v" + frame_dig -2 // validatorId: ValidatorIdType + itob + concat + cover 2 + box_extract + == + dup + bnz *skip_or1 + txn Sender + int 40 + int 32 + byte 0x76 // "v" + frame_dig -2 // validatorId: ValidatorIdType + itob + concat + cover 2 + box_extract + == + || + +*skip_or1: + assert + + // contracts/validatorRegistry.algo.ts:542 + // verifyPayTxn(mbrPayment, { amount: this.getMbrAmounts().addPoolMbr, receiver: this.app.address }) + // verify amount + frame_dig -1 // mbrPayment: PayTxn + gtxns Amount + callsub getMbrAmounts + extract 8 8 + btoi + == + assert + + // verify receiver + frame_dig -1 // mbrPayment: PayTxn + gtxns Receiver + global CurrentApplicationAddress + == + assert + + // contracts/validatorRegistry.algo.ts:544 + // assert(this.validatorList(validatorId).exists) + byte 0x76 // "v" + frame_dig -2 // validatorId: ValidatorIdType + itob + concat + box_len + swap + pop + assert + + // contracts/validatorRegistry.algo.ts:546 + // numPools: uint64 = this.validatorList(validatorId).value.state.numPools as uint64 + int 208 + int 2 + byte 0x76 // "v" + frame_dig -2 // validatorId: ValidatorIdType + itob + concat + cover 2 + box_extract + btoi + frame_bury 0 // numPools: uint64 + + // *if8_condition + // contracts/validatorRegistry.algo.ts:547 + // (numPools as uint64) >= MAX_POOLS + frame_dig 0 // numPools: uint64 + int 24 + >= + bz *if8_end + + // *if8_consequent + err // 'already at max pool size' + +*if8_end: + // contracts/validatorRegistry.algo.ts:550 + // numPools += 1 + frame_dig 0 // numPools: uint64 + int 1 + + + frame_bury 0 // numPools: uint64 + + // contracts/validatorRegistry.algo.ts:553 + // sendAppCall({ + // onCompletion: OnCompletion.NoOp, + // approvalProgram: AppID.fromUint64(this.stakingPoolTemplateAppId.value).approvalProgram, + // clearStateProgram: AppID.fromUint64(this.stakingPoolTemplateAppId.value).clearStateProgram, + // globalNumUint: AppID.fromUint64(this.stakingPoolTemplateAppId.value).globalNumUint, + // globalNumByteSlice: AppID.fromUint64(this.stakingPoolTemplateAppId.value).globalNumByteSlice, + // extraProgramPages: AppID.fromUint64(this.stakingPoolTemplateAppId.value).extraProgramPages, + // applicationArgs: [ + // // creatingContractID, validatorId, poolId, minEntryStake + // method('createApplication(uint64,uint64,uint64,uint64)void'), + // itob(this.app.id), + // itob(validatorId), + // itob(numPools as uint64), + // itob(this.validatorList(validatorId).value.config.minEntryStake), + // ], + // }) + itxn_begin + int appl + itxn_field TypeEnum + + // contracts/validatorRegistry.algo.ts:554 + // onCompletion: OnCompletion.NoOp + int 0 // NoOp + itxn_field OnCompletion + + // contracts/validatorRegistry.algo.ts:555 + // approvalProgram: AppID.fromUint64(this.stakingPoolTemplateAppId.value).approvalProgram + byte 0x706f6f6c54656d706c6174654170704964 // "poolTemplateAppId" + app_global_get + app_params_get AppApprovalProgram + pop + itxn_field ApprovalProgram + + // contracts/validatorRegistry.algo.ts:556 + // clearStateProgram: AppID.fromUint64(this.stakingPoolTemplateAppId.value).clearStateProgram + byte 0x706f6f6c54656d706c6174654170704964 // "poolTemplateAppId" + app_global_get + app_params_get AppClearStateProgram + pop + itxn_field ClearStateProgram + + // contracts/validatorRegistry.algo.ts:557 + // globalNumUint: AppID.fromUint64(this.stakingPoolTemplateAppId.value).globalNumUint + byte 0x706f6f6c54656d706c6174654170704964 // "poolTemplateAppId" + app_global_get + app_params_get AppGlobalNumUint + pop + itxn_field GlobalNumUint + + // contracts/validatorRegistry.algo.ts:558 + // globalNumByteSlice: AppID.fromUint64(this.stakingPoolTemplateAppId.value).globalNumByteSlice + byte 0x706f6f6c54656d706c6174654170704964 // "poolTemplateAppId" + app_global_get + app_params_get AppGlobalNumByteSlice + pop + itxn_field GlobalNumByteSlice + + // contracts/validatorRegistry.algo.ts:559 + // extraProgramPages: AppID.fromUint64(this.stakingPoolTemplateAppId.value).extraProgramPages + byte 0x706f6f6c54656d706c6174654170704964 // "poolTemplateAppId" + app_global_get + app_params_get AppExtraProgramPages + pop + itxn_field ExtraProgramPages + + // contracts/validatorRegistry.algo.ts:560 + // applicationArgs: [ + // // creatingContractID, validatorId, poolId, minEntryStake + // method('createApplication(uint64,uint64,uint64,uint64)void'), + // itob(this.app.id), + // itob(validatorId), + // itob(numPools as uint64), + // itob(this.validatorList(validatorId).value.config.minEntryStake), + // ] + method "createApplication(uint64,uint64,uint64,uint64)void" + itxn_field ApplicationArgs + txna Applications 0 + itob + itxn_field ApplicationArgs + frame_dig -2 // validatorId: ValidatorIdType + itob + itxn_field ApplicationArgs + frame_dig 0 // numPools: uint64 + itob + itxn_field ApplicationArgs + int 175 + int 8 + byte 0x76 // "v" + frame_dig -2 // validatorId: ValidatorIdType + itob + concat + cover 2 + box_extract + btoi + itob + itxn_field ApplicationArgs + + // Fee field not set, defaulting to 0 + int 0 + itxn_field Fee + + // Submit inner transaction + itxn_submit + + // contracts/validatorRegistry.algo.ts:570 + // this.validatorList(validatorId).value.state.numPools = numPools as uint16 + int 208 + frame_dig 0 // numPools: uint64 + itob + extract 6 2 + byte 0x76 // "v" + frame_dig -2 // validatorId: ValidatorIdType + itob + concat + cover 2 + box_replace + + // contracts/validatorRegistry.algo.ts:573 + // poolAppId = this.itxn.createdApplicationID.id + itxn CreatedApplicationID + frame_bury 1 // poolAppId: uint64 + + // contracts/validatorRegistry.algo.ts:574 + // this.validatorList(validatorId).value.pools[numPools - 1].poolAppId = poolAppId + int 234 // headOffset + frame_dig 0 // numPools: uint64 + int 1 + - + int 18 + * // acc * typeLength + + + int 0 + + + frame_dig 1 // poolAppId: uint64 + itob + byte 0x76 // "v" + frame_dig -2 // validatorId: ValidatorIdType + itob + concat + cover 2 + box_replace + + // contracts/validatorRegistry.algo.ts:575 + // this.addPoolToNode(validatorId, poolAppId, nodeNum) + frame_dig -3 // nodeNum: uint64 + frame_dig 1 // poolAppId: uint64 + frame_dig -2 // validatorId: ValidatorIdType + callsub addPoolToNode + + // contracts/validatorRegistry.algo.ts:583 + // return { id: validatorId, poolId: numPools as uint64, poolAppId: this.itxn!.createdApplicationID.id }; + frame_dig -2 // validatorId: ValidatorIdType + itob + frame_dig 0 // numPools: uint64 + itob + concat + itxn CreatedApplicationID + itob + concat + + // set the subroutine return value + frame_bury 0 + + // pop all local variables from the stack + popn 1 + retsub + +// addStake(pay,uint64,uint64)(uint64,uint64,uint64) +*abi_route_addStake: + // The ABI return prefix + byte 0x151f7c75 + + // valueToVerify: uint64 + txna ApplicationArgs 2 + btoi + + // validatorId: uint64 + txna ApplicationArgs 1 + btoi + + // stakedAmountPayment: pay + txn GroupIndex + int 1 + - + dup + gtxns TypeEnum + int pay + == + assert + + // execute addStake(pay,uint64,uint64)(uint64,uint64,uint64) + callsub addStake + concat + log + int 1 + return + +// addStake(stakedAmountPayment: PayTxn, validatorId: ValidatorIdType, valueToVerify: uint64): ValidatorPoolKey +// +// Adds stake to a validator pool. +// +// @param {PayTxn} stakedAmountPayment - payment coming from staker to place into a pool +// @param {ValidatorIdType} validatorId - The id of the validator. +// @param {uint64} valueToVerify - only if validator has gating to enter - this is asset id or nfd id that corresponds to gating. +// Txn sender is factored in as well if that is part of gating. +// * @returns {ValidatorPoolKey} - The key of the validator pool. +addStake: + proto 3 1 + + // Push empty bytes after the frame pointer to reserve space for local variables + byte 0x + dupn 5 + + // contracts/validatorRegistry.algo.ts:596 + // assert(this.validatorList(validatorId).exists) + byte 0x76 // "v" + frame_dig -2 // validatorId: ValidatorIdType + itob + concat + box_len + swap + pop + assert + + // contracts/validatorRegistry.algo.ts:598 + // staker = this.txn.sender + txn Sender + frame_bury 0 // staker: address + + // contracts/validatorRegistry.algo.ts:602 + // verifyPayTxn(stakedAmountPayment, { + // sender: staker, + // receiver: this.app.address, + // }) + // verify sender + frame_dig -1 // stakedAmountPayment: PayTxn + gtxns Sender + frame_dig 0 // staker: address + == + assert + + // verify receiver + frame_dig -1 // stakedAmountPayment: PayTxn + gtxns Receiver + global CurrentApplicationAddress + == + assert + + // contracts/validatorRegistry.algo.ts:609 + // assert( + // this.validatorList(validatorId).value.state.totalAlgoStaked < this.maxAllowedStake(), + // 'total staked for all of a validators pools may not exceed hard cap' + // ) + int 218 + int 8 + byte 0x76 // "v" + frame_dig -2 // validatorId: ValidatorIdType + itob + concat + cover 2 + box_extract + btoi + callsub maxAllowedStake + < + + // total staked for all of a validators pools may not exceed hard cap + assert + + // contracts/validatorRegistry.algo.ts:616 + // this.doesStakerMeetGating(validatorId, valueToVerify) + frame_dig -3 // valueToVerify: uint64 + frame_dig -2 // validatorId: ValidatorIdType + callsub doesStakerMeetGating + + // contracts/validatorRegistry.algo.ts:618 + // realAmount = stakedAmountPayment.amount + frame_dig -1 // stakedAmountPayment: PayTxn + gtxns Amount + frame_bury 1 // realAmount: uint64 + + // contracts/validatorRegistry.algo.ts:619 + // mbrAmtLeftBehind: uint64 = 0 + int 0 + frame_bury 2 // mbrAmtLeftBehind: uint64 + + // *if9_condition + // contracts/validatorRegistry.algo.ts:621 + // !this.stakerPoolSet(staker).exists + byte 0x737073 // "sps" + frame_dig 0 // staker: address + concat + box_len + swap + pop + ! + bz *if9_end + + // *if9_consequent + // contracts/validatorRegistry.algo.ts:624 + // mbrAmtLeftBehind = this.getMbrAmounts().addStakerMbr + callsub getMbrAmounts + extract 24 8 + btoi + frame_bury 2 // mbrAmtLeftBehind: uint64 + + // contracts/validatorRegistry.algo.ts:625 + // realAmount -= mbrAmtLeftBehind + frame_dig 1 // realAmount: uint64 + frame_dig 2 // mbrAmtLeftBehind: uint64 + - + frame_bury 1 // realAmount: uint64 + + // contracts/validatorRegistry.algo.ts:626 + // this.stakerPoolSet(staker).create() + byte 0x737073 // "sps" + frame_dig 0 // staker: address + concat + int 144 + box_create + pop + +*if9_end: + // contracts/validatorRegistry.algo.ts:630 + // findRet = this.findPoolForStaker(validatorId, staker, realAmount) + frame_dig 1 // realAmount: uint64 + frame_dig 0 // staker: address + frame_dig -2 // validatorId: ValidatorIdType + callsub findPoolForStaker + frame_bury 3 // findRet: ((uint64,uint64,uint64),bool,bool) + + // contracts/validatorRegistry.algo.ts:631 + // poolKey = findRet[0] + // contracts/validatorRegistry.algo.ts:632 + // isNewStakerToValidator = findRet[1] + frame_dig 3 // findRet: ((uint64,uint64,uint64),bool,bool) + store 255 // full array + load 255 // full array + int 192 + getbit + frame_bury 4 // isNewStakerToValidator: bool + + // contracts/validatorRegistry.algo.ts:633 + // isNewStakerToProtocol = findRet[2] + frame_dig 3 // findRet: ((uint64,uint64,uint64),bool,bool) + store 255 // full array + load 255 // full array + int 193 + getbit + frame_bury 5 // isNewStakerToProtocol: bool + + // *if10_condition + // contracts/validatorRegistry.algo.ts:634 + // poolKey.poolId === 0 + frame_dig 3 // findRet: ((uint64,uint64,uint64),bool,bool) + store 255 // full array + load 255 // full array + extract 8 8 + btoi + int 0 + == + bz *if10_end + + // *if10_consequent + err // 'No pool available with free stake. Validator needs to add another pool' + +*if10_end: + // contracts/validatorRegistry.algo.ts:639 + // this.updateStakerPoolSet(staker, poolKey) + frame_dig 3 // findRet: ((uint64,uint64,uint64),bool,bool) + store 255 // full array + load 255 // full array + extract 0 24 + frame_dig 0 // staker: address + callsub updateStakerPoolSet + + // contracts/validatorRegistry.algo.ts:642 + // this.callPoolAddStake( + // stakedAmountPayment, + // poolKey, + // mbrAmtLeftBehind, + // isNewStakerToValidator, + // isNewStakerToProtocol + // ) + frame_dig 5 // isNewStakerToProtocol: bool + frame_dig 4 // isNewStakerToValidator: bool + frame_dig 2 // mbrAmtLeftBehind: uint64 + frame_dig 3 // findRet: ((uint64,uint64,uint64),bool,bool) + store 255 // full array + load 255 // full array + extract 0 24 + frame_dig -1 // stakedAmountPayment: PayTxn + callsub callPoolAddStake + + // contracts/validatorRegistry.algo.ts:657 + // return poolKey; + frame_dig 3 // findRet: ((uint64,uint64,uint64),bool,bool) + store 255 // full array + load 255 // full array + extract 0 24 + + // set the subroutine return value + frame_bury 0 + + // pop all local variables from the stack + popn 5 + retsub + +// setTokenPayoutRatio(uint64)(uint64[24],uint64) +*abi_route_setTokenPayoutRatio: + // The ABI return prefix + byte 0x151f7c75 + + // validatorId: uint64 + txna ApplicationArgs 1 + btoi + + // execute setTokenPayoutRatio(uint64)(uint64[24],uint64) + callsub setTokenPayoutRatio + concat + log + int 1 + return + +// setTokenPayoutRatio(validatorId: ValidatorIdType): PoolTokenPayoutRatio +// +// setTokenPayoutRatio is called by Staking Pool # 1 (ONLY) to ask the validator (us) to calculate the ratios +// of stake in the pools for subsequent token payouts (ie: 2 pools, '100' algo total staked, 60 in pool 1, and 40 +// in pool 2. This is done so we have a stable snapshot of stake - taken once per epoch - only triggered by +// pool 1 doing payout. pools other than 1 doing payout call pool 1 to ask it do it first. +// It would be 60/40% in the poolPctOfWhole values. The token reward payouts then use these values instead of +// their 'current' stake which changes as part of the payouts themselves (and people could be changing stake +// during the epoch updates across pools) +// +// Multiple pools will call us via pool 1 (pool2->pool1->valdiator, etc.) so don't assert on pool1 calling multiple +// times in same epoch. Just return. +// +// @param validatorId - validator id (and thus pool) calling us. Verified so that sender MUST be pool 1 of this validator. +// @returns PoolTokenPayoutRatio - the finished ratio data +setTokenPayoutRatio: + proto 1 1 + + // Push empty bytes after the frame pointer to reserve space for local variables + byte 0x + dupn 8 + + // contracts/validatorRegistry.algo.ts:677 + // pool1AppID = this.validatorList(validatorId).value.pools[0].poolAppId + int 234 + int 8 + byte 0x76 // "v" + frame_dig -1 // validatorId: ValidatorIdType + itob + concat + cover 2 + box_extract + btoi + frame_bury 0 // pool1AppID: uint64 + + // contracts/validatorRegistry.algo.ts:678 + // assert(pool1AppID !== 0) + frame_dig 0 // pool1AppID: uint64 + int 0 + != + assert + + // *if11_condition + // contracts/validatorRegistry.algo.ts:680 + // this.txn.sender !== AppID.fromUint64(pool1AppID).address + txn Sender + frame_dig 0 // pool1AppID: uint64 + app_params_get AppAddress + pop + != + bz *if11_end + + // *if11_consequent + // contracts/validatorRegistry.algo.ts:681 + // return this.validatorList(validatorId).value.tokenPayoutRatio; + int 666 // headOffset + int 200 + byte 0x76 // "v" + frame_dig -1 // validatorId: ValidatorIdType + itob + concat + cover 2 + box_extract + + // set the subroutine return value + frame_bury 0 + retsub + +*if11_end: + // contracts/validatorRegistry.algo.ts:686 + // curTime = globals.latestTimestamp + global LatestTimestamp + frame_bury 1 // curTime: uint64 + + // contracts/validatorRegistry.algo.ts:687 + // lastPayoutUpdate = this.validatorList(validatorId).value.tokenPayoutRatio.updatedForPayout + int 858 + int 8 + byte 0x76 // "v" + frame_dig -1 // validatorId: ValidatorIdType + itob + concat + cover 2 + box_extract + btoi + frame_bury 2 // lastPayoutUpdate: uint64 + + // *if12_condition + // contracts/validatorRegistry.algo.ts:688 + // lastPayoutUpdate !== 0 + frame_dig 2 // lastPayoutUpdate: uint64 + int 0 + != + bz *if12_end + + // *if12_consequent + // *if13_condition + // contracts/validatorRegistry.algo.ts:690 + // (AppID.fromUint64(pool1AppID).globalState('lastPayout') as uint64) === lastPayoutUpdate + frame_dig 0 // pool1AppID: uint64 + byte 0x6c6173745061796f7574 // "lastPayout" + app_global_get_ex + assert + frame_dig 2 // lastPayoutUpdate: uint64 + == + bz *if13_end + + // *if13_consequent + // contracts/validatorRegistry.algo.ts:691 + // return this.validatorList(validatorId).value.tokenPayoutRatio; + int 666 // headOffset + int 200 + byte 0x76 // "v" + frame_dig -1 // validatorId: ValidatorIdType + itob + concat + cover 2 + box_extract + + // set the subroutine return value + frame_bury 0 + + // pop all local variables from the stack + popn 2 + retsub + +*if13_end: + // contracts/validatorRegistry.algo.ts:693 + // secsSinceLastPayout = curTime - lastPayoutUpdate + frame_dig 1 // curTime: uint64 + frame_dig 2 // lastPayoutUpdate: uint64 + - + frame_bury 3 // secsSinceLastPayout: uint64 + + // contracts/validatorRegistry.algo.ts:694 + // epochInSecs = (this.validatorList(validatorId).value.config.payoutEveryXMins as uint64) * 60 + int 137 + int 2 + byte 0x76 // "v" + frame_dig -1 // validatorId: ValidatorIdType + itob + concat + cover 2 + box_extract + btoi + int 60 + * + frame_bury 4 // epochInSecs: uint64 + + // *if14_condition + // contracts/validatorRegistry.algo.ts:696 + // secsSinceLastPayout < epochInSecs + frame_dig 3 // secsSinceLastPayout: uint64 + frame_dig 4 // epochInSecs: uint64 + < + bz *if14_end + + // *if14_consequent + // contracts/validatorRegistry.algo.ts:697 + // return this.validatorList(validatorId).value.tokenPayoutRatio; + int 666 // headOffset + int 200 + byte 0x76 // "v" + frame_dig -1 // validatorId: ValidatorIdType + itob + concat + cover 2 + box_extract + + // set the subroutine return value + frame_bury 0 + + // pop all local variables from the stack + popn 4 + retsub + +*if14_end: + +*if12_end: + // contracts/validatorRegistry.algo.ts:700 + // this.validatorList(validatorId).value.tokenPayoutRatio.updatedForPayout = curTime + int 858 + frame_dig 1 // curTime: uint64 + itob + byte 0x76 // "v" + frame_dig -1 // validatorId: ValidatorIdType + itob + concat + cover 2 + box_replace + + // contracts/validatorRegistry.algo.ts:702 + // curNumPools = this.validatorList(validatorId).value.state.numPools as uint64 + int 208 + int 2 + byte 0x76 // "v" + frame_dig -1 // validatorId: ValidatorIdType + itob + concat + cover 2 + box_extract + btoi + frame_bury 5 // curNumPools: uint64 + + // contracts/validatorRegistry.algo.ts:703 + // totalStakeForValidator = this.validatorList(validatorId).value.state.totalAlgoStaked + int 218 + int 8 + byte 0x76 // "v" + frame_dig -1 // validatorId: ValidatorIdType + itob + concat + cover 2 + box_extract + btoi + frame_bury 6 // totalStakeForValidator: uint64 + + // contracts/validatorRegistry.algo.ts:704 + // for (let i = 0; i < curNumPools; i += 1) + int 0 + frame_bury 7 // i: uint64 + +*for_2: + // contracts/validatorRegistry.algo.ts:704 + // i < curNumPools + frame_dig 7 // i: uint64 + frame_dig 5 // curNumPools: uint64 + < + bz *for_2_end + + // contracts/validatorRegistry.algo.ts:709 + // ourPoolPctOfWhole = wideRatio( + // [this.validatorList(validatorId).value.pools[i].totalAlgoStaked, 1_000_000], + // [totalStakeForValidator] + // ) + int 234 // headOffset + frame_dig 7 // i: uint64 + int 18 + * // acc * typeLength + + + int 10 // headOffset + + + int 8 + byte 0x76 // "v" + frame_dig -1 // validatorId: ValidatorIdType + itob + concat + cover 2 + box_extract + btoi + int 1_000_000 + mulw + int 0 + frame_dig 6 // totalStakeForValidator: uint64 + divmodw + pop + pop + swap + ! + assert + frame_bury 8 // ourPoolPctOfWhole: uint64 + + // contracts/validatorRegistry.algo.ts:713 + // this.validatorList(validatorId).value.tokenPayoutRatio.poolPctOfWhole[i] = ourPoolPctOfWhole + int 666 + frame_dig 7 // i: uint64 + int 8 + * // acc * typeLength + + + frame_dig 8 // ourPoolPctOfWhole: uint64 + itob + byte 0x76 // "v" + frame_dig -1 // validatorId: ValidatorIdType + itob + concat + cover 2 + box_replace + +*for_2_continue: + // contracts/validatorRegistry.algo.ts:704 + // i += 1 + frame_dig 7 // i: uint64 + int 1 + + + frame_bury 7 // i: uint64 + b *for_2 + +*for_2_end: + // contracts/validatorRegistry.algo.ts:715 + // return this.validatorList(validatorId).value.tokenPayoutRatio; + int 666 // headOffset + int 200 + byte 0x76 // "v" + frame_dig -1 // validatorId: ValidatorIdType + itob + concat + cover 2 + box_extract + + // set the subroutine return value + frame_bury 0 + + // pop all local variables from the stack + popn 8 + retsub + +// stakeUpdatedViaRewards((uint64,uint64,uint64),uint64,uint64)void +*abi_route_stakeUpdatedViaRewards: + // rewardTokenAmountReserved: uint64 + txna ApplicationArgs 3 + btoi + + // algoToAdd: uint64 + txna ApplicationArgs 2 + btoi + + // poolKey: (uint64,uint64,uint64) + txna ApplicationArgs 1 + dup + len + int 24 + == + assert + + // execute stakeUpdatedViaRewards((uint64,uint64,uint64),uint64,uint64)void + callsub stakeUpdatedViaRewards + int 1 + return + +// stakeUpdatedViaRewards(poolKey: ValidatorPoolKey, algoToAdd: uint64, rewardTokenAmountReserved: uint64): void +// +// stakeUpdatedViaRewards is called by Staking pools to inform the validator (us) that a particular amount of total +// stake has been added to the specified pool. This is used to update the stats we have in our PoolInfo storage. +// The calling App id is validated against our pool list as well. +// @param {ValidatorPoolKey} poolKey - ValidatorPoolKey type +// @param {uint64} algoToAdd - amount this validator's total stake increased via rewards +// @param {uint64} rewardTokenAmountReserved - amount this validator's total stake increased via rewards (that should be +// seen as 'accounted for/pending spent') +stakeUpdatedViaRewards: + proto 3 0 + + // contracts/validatorRegistry.algo.ts:728 + // this.verifyPoolKeyCaller(poolKey) + frame_dig -1 // poolKey: ValidatorPoolKey + callsub verifyPoolKeyCaller + + // contracts/validatorRegistry.algo.ts:731 + // this.validatorList(poolKey.id).value.pools[poolKey.poolId - 1].totalAlgoStaked += algoToAdd + int 234 // headOffset + frame_dig -1 // poolKey: ValidatorPoolKey + extract 8 8 + btoi + int 1 + - + int 18 + * // acc * typeLength + + + int 10 // headOffset + + + int 234 // headOffset + frame_dig -1 // poolKey: ValidatorPoolKey + extract 8 8 + btoi + int 1 + - + int 18 + * // acc * typeLength + + + int 10 // headOffset + + + int 8 + byte 0x76 // "v" + frame_dig -1 // poolKey: ValidatorPoolKey + extract 0 8 + btoi + itob + concat + cover 2 + box_extract + btoi + frame_dig -2 // algoToAdd: uint64 + + + itob + byte 0x76 // "v" + frame_dig -1 // poolKey: ValidatorPoolKey + extract 0 8 + btoi + itob + concat + cover 2 + box_replace + + // contracts/validatorRegistry.algo.ts:732 + // this.validatorList(poolKey.id).value.state.totalAlgoStaked += algoToAdd + int 218 + dup + int 8 + byte 0x76 // "v" + frame_dig -1 // poolKey: ValidatorPoolKey + extract 0 8 + btoi + itob + concat + cover 2 + box_extract + btoi + frame_dig -2 // algoToAdd: uint64 + + + itob + byte 0x76 // "v" + frame_dig -1 // poolKey: ValidatorPoolKey + extract 0 8 + btoi + itob + concat + cover 2 + box_replace + + // contracts/validatorRegistry.algo.ts:733 + // this.validatorList(poolKey.id).value.state.rewardTokenHeldBack += rewardTokenAmountReserved + int 226 + dup + int 8 + byte 0x76 // "v" + frame_dig -1 // poolKey: ValidatorPoolKey + extract 0 8 + btoi + itob + concat + cover 2 + box_extract + btoi + frame_dig -3 // rewardTokenAmountReserved: uint64 + + + itob + byte 0x76 // "v" + frame_dig -1 // poolKey: ValidatorPoolKey + extract 0 8 + btoi + itob + concat + cover 2 + box_replace + + // contracts/validatorRegistry.algo.ts:735 + // this.totalAlgoStaked.value += algoToAdd + byte 0x7374616b6564 // "staked" + app_global_get + frame_dig -2 // algoToAdd: uint64 + + + byte 0x7374616b6564 // "staked" + swap + app_global_put + + // contracts/validatorRegistry.algo.ts:738 + // this.reverifyNFDOwnership(poolKey.id) + frame_dig -1 // poolKey: ValidatorPoolKey + extract 0 8 + btoi + callsub reverifyNFDOwnership + retsub + +// stakeRemoved((uint64,uint64,uint64),address,uint64,uint64,bool)void +*abi_route_stakeRemoved: + // stakerRemoved: bool + txna ApplicationArgs 5 + dup + len + int 1 + == + assert + int 0 + getbit + + // rewardRemoved: uint64 + txna ApplicationArgs 4 + btoi + + // amountRemoved: uint64 + txna ApplicationArgs 3 + btoi + + // staker: address + txna ApplicationArgs 2 + dup + len + int 32 + == + assert + + // poolKey: (uint64,uint64,uint64) + txna ApplicationArgs 1 + dup + len + int 24 + == + assert + + // execute stakeRemoved((uint64,uint64,uint64),address,uint64,uint64,bool)void + callsub stakeRemoved + int 1 + return + +// stakeRemoved(poolKey: ValidatorPoolKey, staker: Address, amountRemoved: uint64, rewardRemoved: uint64, stakerRemoved: boolean): void +// +// stakeRemoved is called by Staking pools to inform the validator (us) that a particular amount of total stake has been removed +// from the specified pool. This is used to update the stats we have in our PoolInfo storage. +// If any amount of rewardRemoved is specified, then that amount of reward is sent to the use +// The calling App id is validated against our pool list as well. +// +// @param {ValidatorPoolKey} poolKey calling us from which stake was removed +// @param {Address} staker +// @param {uint64} amountRemoved - algo amount removed +// @param {uint64} rewardRemoved - if applicable, amount of token reward removed (by pool 1 caller) or TO remove and pay out (via pool 1 from different pool caller) +// @param {boolean} stakerRemoved +stakeRemoved: + proto 5 0 + + // Push empty bytes after the frame pointer to reserve space for local variables + byte 0x + dupn 3 + + // *if15_condition + // contracts/validatorRegistry.algo.ts:768 + // globals.opcodeBudget < 300 + global OpcodeBudget + int 300 + < + bz *if15_end + + // *if15_consequent + // contracts/validatorRegistry.algo.ts:769 + // increaseOpcodeBudget() + itxn_begin + int appl + itxn_field TypeEnum + int 0 + itxn_field Fee + byte b64 CoEB // #pragma version 10; int 1 + dup + itxn_field ApprovalProgram + itxn_field ClearStateProgram + int DeleteApplication + itxn_field OnCompletion + itxn_submit + +*if15_end: + // contracts/validatorRegistry.algo.ts:771 + // this.verifyPoolKeyCaller(poolKey) + frame_dig -1 // poolKey: ValidatorPoolKey + callsub verifyPoolKeyCaller + + // contracts/validatorRegistry.algo.ts:775 + // assert(amountRemoved > 0 || rewardRemoved > 0) + frame_dig -3 // amountRemoved: uint64 + int 0 + > + dup + bnz *skip_or2 + frame_dig -4 // rewardRemoved: uint64 + int 0 + > + || + +*skip_or2: + assert + + // contracts/validatorRegistry.algo.ts:778 + // this.validatorList(poolKey.id).value.pools[poolKey.poolId - 1].totalAlgoStaked -= amountRemoved + int 234 // headOffset + frame_dig -1 // poolKey: ValidatorPoolKey + extract 8 8 + btoi + int 1 + - + int 18 + * // acc * typeLength + + + int 10 // headOffset + + + int 234 // headOffset + frame_dig -1 // poolKey: ValidatorPoolKey + extract 8 8 + btoi + int 1 + - + int 18 + * // acc * typeLength + + + int 10 // headOffset + + + int 8 + byte 0x76 // "v" + frame_dig -1 // poolKey: ValidatorPoolKey + extract 0 8 + btoi + itob + concat + cover 2 + box_extract + btoi + frame_dig -3 // amountRemoved: uint64 + - + itob + byte 0x76 // "v" + frame_dig -1 // poolKey: ValidatorPoolKey + extract 0 8 + btoi + itob + concat + cover 2 + box_replace + + // contracts/validatorRegistry.algo.ts:779 + // this.validatorList(poolKey.id).value.state.totalAlgoStaked -= amountRemoved + int 218 + dup + int 8 + byte 0x76 // "v" + frame_dig -1 // poolKey: ValidatorPoolKey + extract 0 8 + btoi + itob + concat + cover 2 + box_extract + btoi + frame_dig -3 // amountRemoved: uint64 + - + itob + byte 0x76 // "v" + frame_dig -1 // poolKey: ValidatorPoolKey + extract 0 8 + btoi + itob + concat + cover 2 + box_replace + + // contracts/validatorRegistry.algo.ts:780 + // this.totalAlgoStaked.value -= amountRemoved + byte 0x7374616b6564 // "staked" + app_global_get + frame_dig -3 // amountRemoved: uint64 + - + byte 0x7374616b6564 // "staked" + swap + app_global_put + + // *if16_condition + // contracts/validatorRegistry.algo.ts:782 + // rewardRemoved > 0 + frame_dig -4 // rewardRemoved: uint64 + int 0 + > + bz *if16_else + + // *if16_consequent + // contracts/validatorRegistry.algo.ts:783 + // rewardTokenID = this.validatorList(poolKey.id).value.config.rewardTokenId + int 121 + int 8 + byte 0x76 // "v" + frame_dig -1 // poolKey: ValidatorPoolKey + extract 0 8 + btoi + itob + concat + cover 2 + box_extract + btoi + frame_bury 0 // rewardTokenID: uint64 + + // contracts/validatorRegistry.algo.ts:784 + // assert(rewardTokenID !== 0, "rewardRemoved can't be set if validator doesn't have reward token!") + frame_dig 0 // rewardTokenID: uint64 + int 0 + != + + // rewardRemoved can't be set if validator doesn't have reward token! + assert + + // contracts/validatorRegistry.algo.ts:785 + // assert( + // this.validatorList(poolKey.id).value.state.rewardTokenHeldBack >= rewardRemoved, + // 'reward being removed must be covered by hold back amount' + // ) + int 226 + int 8 + byte 0x76 // "v" + frame_dig -1 // poolKey: ValidatorPoolKey + extract 0 8 + btoi + itob + concat + cover 2 + box_extract + btoi + frame_dig -4 // rewardRemoved: uint64 + >= + + // reward being removed must be covered by hold back amount + assert + + // contracts/validatorRegistry.algo.ts:791 + // this.validatorList(poolKey.id).value.state.rewardTokenHeldBack -= rewardRemoved + int 226 + dup + int 8 + byte 0x76 // "v" + frame_dig -1 // poolKey: ValidatorPoolKey + extract 0 8 + btoi + itob + concat + cover 2 + box_extract + btoi + frame_dig -4 // rewardRemoved: uint64 + - + itob + byte 0x76 // "v" + frame_dig -1 // poolKey: ValidatorPoolKey + extract 0 8 + btoi + itob + concat + cover 2 + box_replace + + // *if17_condition + // contracts/validatorRegistry.algo.ts:796 + // poolKey.poolId !== 1 + frame_dig -1 // poolKey: ValidatorPoolKey + extract 8 8 + btoi + int 1 + != + bz *if17_end + + // *if17_consequent + // contracts/validatorRegistry.algo.ts:797 + // sendMethodCall({ + // applicationID: AppID.fromUint64(this.validatorList(poolKey.id).value.pools[0].poolAppId), + // methodArgs: [staker, rewardTokenID, rewardRemoved], + // }) + itxn_begin + int appl + itxn_field TypeEnum + method "payTokenReward(address,uint64,uint64)void" + itxn_field ApplicationArgs + + // contracts/validatorRegistry.algo.ts:798 + // applicationID: AppID.fromUint64(this.validatorList(poolKey.id).value.pools[0].poolAppId) + int 234 + int 8 + byte 0x76 // "v" + frame_dig -1 // poolKey: ValidatorPoolKey + extract 0 8 + btoi + itob + concat + cover 2 + box_extract + btoi + itxn_field ApplicationID + + // contracts/validatorRegistry.algo.ts:799 + // methodArgs: [staker, rewardTokenID, rewardRemoved] + frame_dig -2 // staker: Address + itxn_field ApplicationArgs + frame_dig 0 // rewardTokenID: uint64 + itob + itxn_field ApplicationArgs + frame_dig -4 // rewardRemoved: uint64 + itob + itxn_field ApplicationArgs + + // Fee field not set, defaulting to 0 + int 0 + itxn_field Fee + + // Submit inner transaction + itxn_submit + +*if17_end: + b *if16_end + +*if16_else: + +*if16_end: + // *if18_condition + // contracts/validatorRegistry.algo.ts:824 + // stakerRemoved + frame_dig -5 // stakerRemoved: boolean + bz *if18_end + + // *if18_consequent + // contracts/validatorRegistry.algo.ts:826 + // this.validatorList(poolKey.id).value.pools[poolKey.poolId - 1].totalStakers -= 1 + int 234 // headOffset + frame_dig -1 // poolKey: ValidatorPoolKey + extract 8 8 + btoi + int 1 + - + int 18 + * // acc * typeLength + + + int 8 // headOffset + + + int 234 // headOffset + frame_dig -1 // poolKey: ValidatorPoolKey + extract 8 8 + btoi + int 1 + - + int 18 + * // acc * typeLength + + + int 8 // headOffset + + + int 2 + byte 0x76 // "v" + frame_dig -1 // poolKey: ValidatorPoolKey + extract 0 8 + btoi + itob + concat + cover 2 + box_extract + btoi + int 1 + - + itob + extract 6 2 + byte 0x76 // "v" + frame_dig -1 // poolKey: ValidatorPoolKey + extract 0 8 + btoi + itob + concat + cover 2 + box_replace + + // contracts/validatorRegistry.algo.ts:828 + // removeRet = this.removeFromStakerPoolSet(staker, { + // id: poolKey.id, + // poolId: poolKey.poolId, + // poolAppId: poolKey.poolAppId, + // }) + frame_dig -1 // poolKey: ValidatorPoolKey + extract 0 8 + btoi + itob + frame_dig -1 // poolKey: ValidatorPoolKey + extract 8 8 + btoi + itob + concat + frame_dig -1 // poolKey: ValidatorPoolKey + extract 16 8 + btoi + itob + concat + frame_dig -2 // staker: Address + callsub removeFromStakerPoolSet + frame_bury 1 // removeRet: (bool,bool) + + // contracts/validatorRegistry.algo.ts:833 + // stakerOutOfThisValidator = removeRet[0] + frame_dig 1 // removeRet: (bool,bool) + store 255 // full array + load 255 // full array + int 0 + getbit + frame_bury 2 // stakerOutOfThisValidator: bool + + // contracts/validatorRegistry.algo.ts:834 + // stakerOutOfProtocol = removeRet[1] + frame_dig 1 // removeRet: (bool,bool) + store 255 // full array + load 255 // full array + int 1 + getbit + frame_bury 3 // stakerOutOfProtocol: bool + + // *if19_condition + // contracts/validatorRegistry.algo.ts:836 + // stakerOutOfThisValidator + frame_dig 2 // stakerOutOfThisValidator: bool + bz *if19_end + + // *if19_consequent + // contracts/validatorRegistry.algo.ts:837 + // this.validatorList(poolKey.id).value.state.totalStakers -= 1 + int 210 + dup + int 8 + byte 0x76 // "v" + frame_dig -1 // poolKey: ValidatorPoolKey + extract 0 8 + btoi + itob + concat + cover 2 + box_extract + btoi + int 1 + - + itob + byte 0x76 // "v" + frame_dig -1 // poolKey: ValidatorPoolKey + extract 0 8 + btoi + itob + concat + cover 2 + box_replace + +*if19_end: + // *if20_condition + // contracts/validatorRegistry.algo.ts:840 + // stakerOutOfProtocol + frame_dig 3 // stakerOutOfProtocol: bool + bz *if20_end + + // *if20_consequent + // contracts/validatorRegistry.algo.ts:841 + // this.numStakers.value -= 1 + byte 0x6e756d5374616b657273 // "numStakers" + app_global_get + int 1 + - + byte 0x6e756d5374616b657273 // "numStakers" + swap + app_global_put + +*if20_end: + +*if18_end: + retsub + +// findPoolForStaker(uint64,address,uint64)((uint64,uint64,uint64),bool,bool) +*abi_route_findPoolForStaker: + // The ABI return prefix + byte 0x151f7c75 + + // amountToStake: uint64 + txna ApplicationArgs 3 + btoi + + // staker: address + txna ApplicationArgs 2 + dup + len + int 32 + == + assert + + // validatorId: uint64 + txna ApplicationArgs 1 + btoi + + // execute findPoolForStaker(uint64,address,uint64)((uint64,uint64,uint64),bool,bool) + callsub findPoolForStaker + concat + log + int 1 + return + +// findPoolForStaker(validatorId: ValidatorIdType, staker: Address, amountToStake: uint64): [ValidatorPoolKey, boolean, boolean] +// +// Finds the pool for a staker based on the provided validator id, staker address, and amount to stake. +// First checks the stakers 'already staked list' for the validator preferring those (adding if possible) then adds +// to new pool if necessary. +// +// @param {ValidatorIdType} validatorId - The id of the validator. +// @param {Address} staker - The address of the staker. +// @param {uint64} amountToStake - The amount to stake. +// @returns {ValidatorPoolKey, boolean, boolean} - The pool for the staker, true/false on whether the staker is 'new' +// to this VALIDATOR, and true/false if staker is new to the protocol. +findPoolForStaker: + proto 3 1 + + // Push empty bytes after the frame pointer to reserve space for local variables + byte 0x + dupn 7 + + // contracts/validatorRegistry.algo.ts:862 + // isNewStakerToValidator = true + int 1 + frame_bury 0 // isNewStakerToValidator: bool + + // contracts/validatorRegistry.algo.ts:863 + // isNewStakerToProtocol = true + int 1 + frame_bury 1 // isNewStakerToProtocol: bool + + // contracts/validatorRegistry.algo.ts:871 + // maxPerPool = this.getCurMaxStakePerPool(validatorId) + frame_dig -1 // validatorId: ValidatorIdType + callsub getCurMaxStakePerPool + frame_bury 2 // maxPerPool: uint64 + + // *if21_condition + // contracts/validatorRegistry.algo.ts:874 + // this.stakerPoolSet(staker).exists + byte 0x737073 // "sps" + frame_dig -2 // staker: Address + concat + box_len + swap + pop + bz *if21_end + + // *if21_consequent + // contracts/validatorRegistry.algo.ts:875 + // poolSet = clone(this.stakerPoolSet(staker).value) + byte 0x737073 // "sps" + frame_dig -2 // staker: Address + concat + box_get + assert + frame_bury 3 // poolSet: (uint64,uint64,uint64)[6] + + // contracts/validatorRegistry.algo.ts:876 + // assert(validatorId !== 0) + frame_dig -1 // validatorId: ValidatorIdType + int 0 + != + assert + + // contracts/validatorRegistry.algo.ts:877 + // for (let i = 0; i < poolSet.length; i += 1) + int 0 + frame_bury 4 // i: uint64 + +*for_3: + // contracts/validatorRegistry.algo.ts:877 + // i < poolSet.length + frame_dig 4 // i: uint64 + int 6 + < + bz *for_3_end + + // *if22_condition + // contracts/validatorRegistry.algo.ts:878 + // globals.opcodeBudget < 300 + global OpcodeBudget + int 300 + < + bz *if22_end + + // *if22_consequent + // contracts/validatorRegistry.algo.ts:879 + // increaseOpcodeBudget() + itxn_begin + int appl + itxn_field TypeEnum + int 0 + itxn_field Fee + byte b64 CoEB // #pragma version 10; int 1 + dup + itxn_field ApprovalProgram + itxn_field ClearStateProgram + int DeleteApplication + itxn_field OnCompletion + itxn_submit + +*if22_end: + // *if23_condition + // contracts/validatorRegistry.algo.ts:881 + // poolSet[i].id === 0 + frame_dig 3 // poolSet: (uint64,uint64,uint64)[6] + frame_dig 4 // i: uint64 + int 24 + * // acc * typeLength + int 0 + + + int 8 + extract3 + btoi + int 0 + == + bz *if23_end + + // *if23_consequent + b *for_3_continue + +*if23_end: + // contracts/validatorRegistry.algo.ts:884 + // isNewStakerToProtocol = false + int 0 + frame_bury 1 // isNewStakerToProtocol: bool + + // *if24_condition + // contracts/validatorRegistry.algo.ts:885 + // poolSet[i].id === validatorId + frame_dig 3 // poolSet: (uint64,uint64,uint64)[6] + frame_dig 4 // i: uint64 + int 24 + * // acc * typeLength + int 0 + + + int 8 + extract3 + btoi + frame_dig -1 // validatorId: ValidatorIdType + == + bz *if24_end + + // *if24_consequent + // contracts/validatorRegistry.algo.ts:887 + // isNewStakerToValidator = false + int 0 + frame_bury 0 // isNewStakerToValidator: bool + + // *if25_condition + // contracts/validatorRegistry.algo.ts:889 + // this.validatorList(validatorId).value.pools[poolSet[i].poolId - 1].totalAlgoStaked + + // amountToStake <= + // maxPerPool + int 234 // headOffset + frame_dig 3 // poolSet: (uint64,uint64,uint64)[6] + frame_dig 4 // i: uint64 + int 24 + * // acc * typeLength + int 8 // headOffset + + + int 8 + extract3 + btoi + int 1 + - + int 18 + * // acc * typeLength + + + int 10 // headOffset + + + int 8 + byte 0x76 // "v" + frame_dig -1 // validatorId: ValidatorIdType + itob + concat + cover 2 + box_extract + btoi + frame_dig -3 // amountToStake: uint64 + + + frame_dig 2 // maxPerPool: uint64 + <= + bz *if25_end + + // *if25_consequent + // contracts/validatorRegistry.algo.ts:893 + // return [poolSet[i], isNewStakerToValidator, isNewStakerToProtocol]; + frame_dig 3 // poolSet: (uint64,uint64,uint64)[6] + frame_dig 4 // i: uint64 + int 24 + * // acc * typeLength + int 24 + extract3 + byte 0x00 + int 0 + frame_dig 0 // isNewStakerToValidator: bool + setbit + int 1 + frame_dig 1 // isNewStakerToProtocol: bool + setbit + concat + + // set the subroutine return value + frame_bury 0 + + // pop all local variables from the stack + popn 4 + retsub + +*if25_end: + +*if24_end: + +*for_3_continue: + // contracts/validatorRegistry.algo.ts:877 + // i += 1 + frame_dig 4 // i: uint64 + int 1 + + + frame_bury 4 // i: uint64 + b *for_3 + +*for_3_end: + +*if21_end: + // contracts/validatorRegistry.algo.ts:900 + // assert( + // amountToStake >= this.validatorList(validatorId).value.config.minEntryStake, + // 'must stake at least the minimum for this pool' + // ) + frame_dig -3 // amountToStake: uint64 + int 175 + int 8 + byte 0x76 // "v" + frame_dig -1 // validatorId: ValidatorIdType + itob + concat + cover 2 + box_extract + btoi + >= + + // must stake at least the minimum for this pool + assert + + // contracts/validatorRegistry.algo.ts:906 + // pools = clone(this.validatorList(validatorId).value.pools) + int 234 // headOffset + int 432 + byte 0x76 // "v" + frame_dig -1 // validatorId: ValidatorIdType + itob + concat + cover 2 + box_extract + frame_bury 5 // pools: (uint64,uint16,uint64)[24] + + // contracts/validatorRegistry.algo.ts:907 + // curNumPools = this.validatorList(validatorId).value.state.numPools as uint64 + int 208 + int 2 + byte 0x76 // "v" + frame_dig -1 // validatorId: ValidatorIdType + itob + concat + cover 2 + box_extract + btoi + frame_bury 6 // curNumPools: uint64 + + // contracts/validatorRegistry.algo.ts:908 + // for (let i = 0; i < curNumPools; i += 1) + int 0 + frame_bury 7 // i: uint64 + +*for_4: + // contracts/validatorRegistry.algo.ts:908 + // i < curNumPools + frame_dig 7 // i: uint64 + frame_dig 6 // curNumPools: uint64 + < + bz *for_4_end + + // *if26_condition + // contracts/validatorRegistry.algo.ts:909 + // pools[i].totalAlgoStaked + amountToStake <= maxPerPool + frame_dig 5 // pools: (uint64,uint16,uint64)[24] + frame_dig 7 // i: uint64 + int 18 + * // acc * typeLength + int 10 // headOffset + + + int 8 + extract3 + btoi + frame_dig -3 // amountToStake: uint64 + + + frame_dig 2 // maxPerPool: uint64 + <= + bz *if26_end + + // *if26_consequent + // contracts/validatorRegistry.algo.ts:910 + // return [ + // { id: validatorId, poolId: i + 1, poolAppId: pools[i].poolAppId }, + // isNewStakerToValidator, + // isNewStakerToProtocol, + // ]; + frame_dig -1 // validatorId: ValidatorIdType + itob + frame_dig 7 // i: uint64 + int 1 + + + itob + concat + frame_dig 5 // pools: (uint64,uint16,uint64)[24] + frame_dig 7 // i: uint64 + int 18 + * // acc * typeLength + int 0 + + + int 8 + extract3 + btoi + itob + concat + byte 0x00 + int 0 + frame_dig 0 // isNewStakerToValidator: bool + setbit + int 1 + frame_dig 1 // isNewStakerToProtocol: bool + setbit + concat + + // set the subroutine return value + frame_bury 0 + + // pop all local variables from the stack + popn 7 + retsub + +*if26_end: + +*for_4_continue: + // contracts/validatorRegistry.algo.ts:908 + // i += 1 + frame_dig 7 // i: uint64 + int 1 + + + frame_bury 7 // i: uint64 + b *for_4 + +*for_4_end: + // contracts/validatorRegistry.algo.ts:918 + // return [{ id: validatorId, poolId: 0, poolAppId: 0 }, isNewStakerToValidator, isNewStakerToProtocol]; + frame_dig -1 // validatorId: ValidatorIdType + itob + byte 0x0000000000000000 + concat + byte 0x0000000000000000 + concat + byte 0x00 + int 0 + frame_dig 0 // isNewStakerToValidator: bool + setbit + int 1 + frame_dig 1 // isNewStakerToProtocol: bool + setbit + concat + + // set the subroutine return value + frame_bury 0 + + // pop all local variables from the stack + popn 7 + retsub + +// movePoolToNode(uint64,uint64,uint64)void +*abi_route_movePoolToNode: + // nodeNum: uint64 + txna ApplicationArgs 3 + btoi + + // poolAppId: uint64 + txna ApplicationArgs 2 + btoi + + // validatorId: uint64 + txna ApplicationArgs 1 + btoi + + // execute movePoolToNode(uint64,uint64,uint64)void + callsub movePoolToNode + int 1 + return + +// movePoolToNode(validatorId: ValidatorIdType, poolAppId: uint64, nodeNum: uint64): void +// +// Find the specified pool (in any node number) and move it to the specified node. +// The pool account is forced offline if moved so prior node will still run for 320 rounds but +// new key goes online on new node soon after (320 rounds after it goes online) +// No-op if success, asserts if not found or can't move (no space in target) +// [ ONLY OWNER OR MANAGER CAN CHANGE ] +// Only callable by owner or manager +movePoolToNode: + proto 3 0 + + // Push empty bytes after the frame pointer to reserve space for local variables + byte 0x + dupn 2 + + // contracts/validatorRegistry.algo.ts:931 + // assert( + // this.txn.sender === this.validatorList(validatorId).value.config.owner || + // this.txn.sender === this.validatorList(validatorId).value.config.manager + // ) + txn Sender + int 8 + int 32 + byte 0x76 // "v" + frame_dig -1 // validatorId: ValidatorIdType + itob + concat + cover 2 + box_extract + == + dup + bnz *skip_or3 + txn Sender + int 40 + int 32 + byte 0x76 // "v" + frame_dig -1 // validatorId: ValidatorIdType + itob + concat + cover 2 + box_extract + == + || + +*skip_or3: + assert + + // contracts/validatorRegistry.algo.ts:936 + // nodePoolAssignments = clone(this.validatorList(validatorId).value.nodePoolAssignments) + int 866 // headOffset + int 192 + byte 0x76 // "v" + frame_dig -1 // validatorId: ValidatorIdType + itob + concat + cover 2 + box_extract + frame_bury 0 // nodePoolAssignments: ((uint64[3])[8]) + + // contracts/validatorRegistry.algo.ts:937 + // assert(nodeNum >= 1 && nodeNum <= MAX_NODES) + frame_dig -3 // nodeNum: uint64 + int 1 + >= + dup + bz *skip_and1 + frame_dig -3 // nodeNum: uint64 + int 8 + <= + && + +*skip_and1: + assert + + // contracts/validatorRegistry.algo.ts:939 + // for (let srcNodeIdx = 0; srcNodeIdx < MAX_NODES; srcNodeIdx += 1) + int 0 + frame_bury 1 // srcNodeIdx: uint64 + +*for_5: + // contracts/validatorRegistry.algo.ts:939 + // srcNodeIdx < MAX_NODES + frame_dig 1 // srcNodeIdx: uint64 + int 8 + < + bz *for_5_end + + // contracts/validatorRegistry.algo.ts:940 + // for (let i = 0; i < MAX_POOLS_PER_NODE; i += 1) + int 0 + frame_bury 2 // i: uint64 + +*for_6: + // contracts/validatorRegistry.algo.ts:940 + // i < MAX_POOLS_PER_NODE + frame_dig 2 // i: uint64 + int 3 + < + bz *for_6_end + + // *if27_condition + // contracts/validatorRegistry.algo.ts:941 + // nodePoolAssignments.nodes[srcNodeIdx].poolAppIds[i] === poolAppId + frame_dig 0 // nodePoolAssignments: ((uint64[3])[8]) + int 0 + frame_dig 1 // srcNodeIdx: uint64 + int 24 + * // acc * typeLength + + + int 0 + + + frame_dig 2 // i: uint64 + int 8 + * // acc * typeLength + + + int 8 + extract3 + btoi + frame_dig -2 // poolAppId: uint64 + == + bz *if27_end + + // *if27_consequent + // contracts/validatorRegistry.algo.ts:942 + // assert(nodeNum - 1 !== srcNodeIdx, "can't move to same node") + frame_dig -3 // nodeNum: uint64 + int 1 + - + frame_dig 1 // srcNodeIdx: uint64 + != + + // can't move to same node + assert + + // contracts/validatorRegistry.algo.ts:944 + // this.validatorList(validatorId).value.nodePoolAssignments.nodes[srcNodeIdx].poolAppIds[i] = 0 + int 866 + frame_dig 1 // srcNodeIdx: uint64 + int 24 + * // acc * typeLength + + + int 0 + + + frame_dig 2 // i: uint64 + int 8 + * // acc * typeLength + + + byte 0x0000000000000000 + byte 0x76 // "v" + frame_dig -1 // validatorId: ValidatorIdType + itob + concat + cover 2 + box_replace + + // contracts/validatorRegistry.algo.ts:947 + // sendMethodCall({ + // applicationID: AppID.fromUint64(poolAppId), + // }) + itxn_begin + int appl + itxn_field TypeEnum + method "goOffline()void" + itxn_field ApplicationArgs + + // contracts/validatorRegistry.algo.ts:948 + // applicationID: AppID.fromUint64(poolAppId) + frame_dig -2 // poolAppId: uint64 + itxn_field ApplicationID + + // Fee field not set, defaulting to 0 + int 0 + itxn_field Fee + + // Submit inner transaction + itxn_submit + + // contracts/validatorRegistry.algo.ts:952 + // this.addPoolToNode(validatorId, poolAppId, nodeNum) + frame_dig -3 // nodeNum: uint64 + frame_dig -2 // poolAppId: uint64 + frame_dig -1 // validatorId: ValidatorIdType + callsub addPoolToNode + + // contracts/validatorRegistry.algo.ts:953 + // return; + retsub + +*if27_end: + +*for_6_continue: + // contracts/validatorRegistry.algo.ts:940 + // i += 1 + frame_dig 2 // i: uint64 + int 1 + + + frame_bury 2 // i: uint64 + b *for_6 + +*for_6_end: + +*for_5_continue: + // contracts/validatorRegistry.algo.ts:939 + // srcNodeIdx += 1 + frame_dig 1 // srcNodeIdx: uint64 + int 1 + + + frame_bury 1 // srcNodeIdx: uint64 + b *for_5 + +*for_5_end: + err // "couldn't find pool app id in nodes to move" + +// verifyPoolKeyCaller(poolKey: ValidatorPoolKey): void +// +// Logs the addition of a new validator to the system, its initial owner and manager +// +// +// verifyPoolKeyCaller verifies the passed in key (from a staking pool calling us to update metrics) is valid +// and matches the information we have in our state. 'Fake' pools could call us to update our data, but they +// can't fake the ids and most importantly application id(!) of the caller that has to match. +verifyPoolKeyCaller: + proto 1 0 + + // contracts/validatorRegistry.algo.ts:1051 + // assert(this.validatorList(poolKey.id).exists) + byte 0x76 // "v" + frame_dig -1 // poolKey: ValidatorPoolKey + extract 0 8 + btoi + itob + concat + box_len + swap + pop + assert + + // contracts/validatorRegistry.algo.ts:1052 + // assert((poolKey.poolId as uint64) < 2 ** 16) + frame_dig -1 // poolKey: ValidatorPoolKey + extract 8 8 + btoi + int 2 + int 16 + exp + < + assert + + // contracts/validatorRegistry.algo.ts:1053 + // assert(poolKey.poolId > 0 && (poolKey.poolId as uint16) <= this.validatorList(poolKey.id).value.state.numPools) + frame_dig -1 // poolKey: ValidatorPoolKey + extract 8 8 + btoi + int 0 + > + dup + bz *skip_and2 + frame_dig -1 // poolKey: ValidatorPoolKey + extract 8 8 + btoi + int 208 + int 2 + byte 0x76 // "v" + frame_dig -1 // poolKey: ValidatorPoolKey + extract 0 8 + btoi + itob + concat + cover 2 + box_extract + btoi + <= + && + +*skip_and2: + assert + + // contracts/validatorRegistry.algo.ts:1056 + // assert( + // poolKey.poolAppId === this.validatorList(poolKey.id).value.pools[poolKey.poolId - 1].poolAppId, + // "The passed in app id doesn't match the passed in ids" + // ) + frame_dig -1 // poolKey: ValidatorPoolKey + extract 16 8 + btoi + int 234 // headOffset + frame_dig -1 // poolKey: ValidatorPoolKey + extract 8 8 + btoi + int 1 + - + int 18 + * // acc * typeLength + + + int 0 + + + int 8 + byte 0x76 // "v" + frame_dig -1 // poolKey: ValidatorPoolKey + extract 0 8 + btoi + itob + concat + cover 2 + box_extract + btoi + == + + // The passed in app id doesn't match the passed in ids + assert + + // contracts/validatorRegistry.algo.ts:1061 + // assert(this.txn.sender === AppID.fromUint64(poolKey.poolAppId).address) + txn Sender + frame_dig -1 // poolKey: ValidatorPoolKey + extract 16 8 + btoi + app_params_get AppAddress + pop + == + assert + + // contracts/validatorRegistry.algo.ts:1063 + // assert(poolKey.id === (AppID.fromUint64(poolKey.poolAppId).globalState('validatorId') as uint64)) + frame_dig -1 // poolKey: ValidatorPoolKey + extract 0 8 + btoi + frame_dig -1 // poolKey: ValidatorPoolKey + extract 16 8 + btoi + byte 0x76616c696461746f724964 // "validatorId" + app_global_get_ex + assert + == + assert + + // contracts/validatorRegistry.algo.ts:1064 + // assert(poolKey.poolId === (AppID.fromUint64(poolKey.poolAppId).globalState('poolId') as uint64)) + frame_dig -1 // poolKey: ValidatorPoolKey + extract 8 8 + btoi + frame_dig -1 // poolKey: ValidatorPoolKey + extract 16 8 + btoi + byte 0x706f6f6c4964 // "poolId" + app_global_get_ex + assert + == + assert + retsub + +// reverifyNFDOwnership(validatorId: ValidatorIdType): void +// +// This method verifies the ownership of NFD (Named Function Data) by a validator. +// If the ownership is no longer valid, it removes the NFD from the validator's configuration. +// +// @param {ValidatorIdType} validatorId - The id of the validator whose data should be re-evaluated. +reverifyNFDOwnership: + proto 1 0 + + // Push empty bytes after the frame pointer to reserve space for local variables + byte 0x + dup + + // contracts/validatorRegistry.algo.ts:1074 + // validatorConfig = this.validatorList(validatorId).value.config + byte 0x76 // "v" + frame_dig -1 // validatorId: ValidatorIdType + itob + concat + frame_bury 0 // storage key//validatorConfig + + // *if28_condition + // contracts/validatorRegistry.algo.ts:1075 + // validatorConfig.nfdForInfo !== 0 + int 72 + int 8 + byte 0x76 // "v" + frame_dig -1 // validatorId: ValidatorIdType + itob + concat + cover 2 + box_extract + btoi + int 0 + != + bz *if28_end + + // *if28_consequent + // contracts/validatorRegistry.algo.ts:1078 + // nfdOwner = AppID.fromUint64(validatorConfig.nfdForInfo).globalState('i.owner.a') as Address + int 72 + int 8 + byte 0x76 // "v" + frame_dig -1 // validatorId: ValidatorIdType + itob + concat + cover 2 + box_extract + btoi + byte 0x692e6f776e65722e61 // "i.owner.a" + app_global_get_ex + assert + frame_bury 1 // nfdOwner: address + + // *if29_condition + // contracts/validatorRegistry.algo.ts:1080 + // validatorConfig.owner !== nfdOwner && validatorConfig.manager !== nfdOwner + int 8 + int 32 + byte 0x76 // "v" + frame_dig -1 // validatorId: ValidatorIdType + itob + concat + cover 2 + box_extract + frame_dig 1 // nfdOwner: address + != + dup + bz *skip_and3 + int 40 + int 32 + byte 0x76 // "v" + frame_dig -1 // validatorId: ValidatorIdType + itob + concat + cover 2 + box_extract + frame_dig 1 // nfdOwner: address + != + && + +*skip_and3: + bz *if29_end + + // *if29_consequent + // contracts/validatorRegistry.algo.ts:1082 + // this.validatorList(validatorId).value.config.nfdForInfo = 0 + int 72 + byte 0x0000000000000000 + byte 0x76 // "v" + frame_dig -1 // validatorId: ValidatorIdType + itob + concat + cover 2 + box_replace + +*if29_end: + +*if28_end: + retsub + +// validateConfig(config: ValidatorConfig): void +validateConfig: + proto 1 0 + + // contracts/validatorRegistry.algo.ts:1089 + // assert(config.entryGatingType >= GATING_TYPE_NONE && config.entryGatingType <= GATING_TYPE_CONST_MAX) + frame_dig -1 // config: ValidatorConfig + extract 80 1 + btoi + int 0 + >= + dup + bz *skip_and4 + frame_dig -1 // config: ValidatorConfig + extract 80 1 + btoi + int 4 + <= + && + +*skip_and4: + assert + + // contracts/validatorRegistry.algo.ts:1090 + // assert(config.payoutEveryXMins >= MIN_PAYOUT_MINS && config.payoutEveryXMins <= MAX_PAYOUT_MINS) + frame_dig -1 // config: ValidatorConfig + extract 137 2 + btoi + int 1 + >= + dup + bz *skip_and5 + frame_dig -1 // config: ValidatorConfig + extract 137 2 + btoi + int 10080 + <= + && + +*skip_and5: + assert + + // contracts/validatorRegistry.algo.ts:1091 + // assert(config.percentToValidator >= MIN_PCT_TO_VALIDATOR && config.percentToValidator <= MAX_PCT_TO_VALIDATOR) + frame_dig -1 // config: ValidatorConfig + extract 139 4 + btoi + int 0 + >= + dup + bz *skip_and6 + frame_dig -1 // config: ValidatorConfig + extract 139 4 + btoi + int 1000000 + <= + && + +*skip_and6: + assert + + // *if30_condition + // contracts/validatorRegistry.algo.ts:1092 + // config.percentToValidator !== 0 + frame_dig -1 // config: ValidatorConfig + extract 139 4 + btoi + int 0 + != + bz *if30_end + + // *if30_consequent + // contracts/validatorRegistry.algo.ts:1093 + // assert( + // config.validatorCommissionAddress !== Address.zeroAddress, + // 'validatorCommissionAddress must be set if percent to validator is not 0' + // ) + frame_dig -1 // config: ValidatorConfig + extract 143 32 + global ZeroAddress + != + + // validatorCommissionAddress must be set if percent to validator is not 0 + assert + +*if30_end: + // contracts/validatorRegistry.algo.ts:1098 + // assert(config.minEntryStake >= MIN_ALGO_STAKE_PER_POOL) + frame_dig -1 // config: ValidatorConfig + extract 175 8 + btoi + int 1000000 + >= + assert + + // contracts/validatorRegistry.algo.ts:1100 + // assert(config.poolsPerNode > 0 && config.poolsPerNode <= MAX_POOLS_PER_NODE) + frame_dig -1 // config: ValidatorConfig + extract 191 1 + btoi + int 0 + > + dup + bz *skip_and7 + frame_dig -1 // config: ValidatorConfig + extract 191 1 + btoi + int 3 + <= + && + +*skip_and7: + assert + retsub + +// callPoolAddStake(stakedAmountPayment: PayTxn, poolKey: ValidatorPoolKey, mbrAmtPaid: uint64, isNewStakerToValidator: boolean, isNewStakerToProtocol: boolean): void +// +// Adds a stakers amount of algo to a validator pool, transferring the algo we received from them (already verified +// by our caller) to the staking pool account, and then telling it about the amount being added for the specified +// staker. +// +// @param {PayTxn} stakedAmountPayment - payment coming from staker to place into a pool +// @param {ValidatorPoolKey} poolKey - The key of the validator pool. +// @param {uint64} mbrAmtPaid - Amount the user is leaving behind in the validator to pay for their staker MBR cost +// @param {boolean} isNewStakerToValidator - if this is a new, first-time staker to the validator +// @param {boolean} isNewStakerToProtocol - if this is a new, first-time staker to the protocol +callPoolAddStake: + proto 5 0 + + // Push empty bytes after the frame pointer to reserve space for local variables + byte 0x + dupn 2 + + // *if31_condition + // contracts/validatorRegistry.algo.ts:1121 + // globals.opcodeBudget < 500 + global OpcodeBudget + int 500 + < + bz *if31_end + + // *if31_consequent + // contracts/validatorRegistry.algo.ts:1122 + // increaseOpcodeBudget() + itxn_begin + int appl + itxn_field TypeEnum + int 0 + itxn_field Fee + byte b64 CoEB // #pragma version 10; int 1 + dup + itxn_field ApprovalProgram + itxn_field ClearStateProgram + int DeleteApplication + itxn_field OnCompletion + itxn_submit + +*if31_end: + // contracts/validatorRegistry.algo.ts:1124 + // poolAppId = this.validatorList(poolKey.id).value.pools[poolKey.poolId - 1].poolAppId + int 234 // headOffset + frame_dig -2 // poolKey: ValidatorPoolKey + extract 8 8 + btoi + int 1 + - + int 18 + * // acc * typeLength + + + int 0 + + + int 8 + byte 0x76 // "v" + frame_dig -2 // poolKey: ValidatorPoolKey + extract 0 8 + btoi + itob + concat + cover 2 + box_extract + btoi + frame_bury 0 // poolAppId: uint64 + + // contracts/validatorRegistry.algo.ts:1128 + // sendMethodCall({ + // applicationID: AppID.fromUint64(poolAppId), + // methodArgs: [ + // // ======= + // // THIS IS A SEND of the amount received right back out and into the staking pool contract account. + // { amount: stakedAmountPayment.amount - mbrAmtPaid, receiver: AppID.fromUint64(poolAppId).address }, + // // ======= + // stakedAmountPayment.sender, + // ], + // }) + itxn_begin + int pay + itxn_field TypeEnum + + // contracts/validatorRegistry.algo.ts:1133 + // amount: stakedAmountPayment.amount - mbrAmtPaid + frame_dig -1 // stakedAmountPayment: PayTxn + gtxns Amount + frame_dig -3 // mbrAmtPaid: uint64 + - + itxn_field Amount + + // contracts/validatorRegistry.algo.ts:1133 + // receiver: AppID.fromUint64(poolAppId).address + frame_dig 0 // poolAppId: uint64 + app_params_get AppAddress + pop + itxn_field Receiver + + // Fee field not set, defaulting to 0 + int 0 + itxn_field Fee + itxn_next + int appl + itxn_field TypeEnum + method "addStake(pay,address)uint64" + itxn_field ApplicationArgs + + // contracts/validatorRegistry.algo.ts:1129 + // applicationID: AppID.fromUint64(poolAppId) + frame_dig 0 // poolAppId: uint64 + itxn_field ApplicationID + + // contracts/validatorRegistry.algo.ts:1130 + // methodArgs: [ + // // ======= + // // THIS IS A SEND of the amount received right back out and into the staking pool contract account. + // { amount: stakedAmountPayment.amount - mbrAmtPaid, receiver: AppID.fromUint64(poolAppId).address }, + // // ======= + // stakedAmountPayment.sender, + // ] + frame_dig -1 // stakedAmountPayment: PayTxn + gtxns Sender + itxn_field ApplicationArgs + + // Fee field not set, defaulting to 0 + int 0 + itxn_field Fee + + // Submit inner transaction + itxn_submit + itxn NumLogs + int 1 + - + itxnas Logs + extract 4 0 + btoi + + // contracts/validatorRegistry.algo.ts:1140 + // poolNumStakers = AppID.fromUint64(poolAppId).globalState('numStakers') as uint64 + frame_dig 0 // poolAppId: uint64 + byte 0x6e756d5374616b657273 // "numStakers" + app_global_get_ex + assert + frame_bury 1 // poolNumStakers: uint64 + + // contracts/validatorRegistry.algo.ts:1141 + // poolAlgoStaked = AppID.fromUint64(poolAppId).globalState('staked') as uint64 + frame_dig 0 // poolAppId: uint64 + byte 0x7374616b6564 // "staked" + app_global_get_ex + assert + frame_bury 2 // poolAlgoStaked: uint64 + + // contracts/validatorRegistry.algo.ts:1142 + // this.validatorList(poolKey.id).value.pools[poolKey.poolId - 1].totalStakers = poolNumStakers as uint16 + int 234 // headOffset + frame_dig -2 // poolKey: ValidatorPoolKey + extract 8 8 + btoi + int 1 + - + int 18 + * // acc * typeLength + + + int 8 // headOffset + + + frame_dig 1 // poolNumStakers: uint64 + itob + extract 6 2 + byte 0x76 // "v" + frame_dig -2 // poolKey: ValidatorPoolKey + extract 0 8 + btoi + itob + concat + cover 2 + box_replace + + // contracts/validatorRegistry.algo.ts:1143 + // this.validatorList(poolKey.id).value.pools[poolKey.poolId - 1].totalAlgoStaked = poolAlgoStaked + int 234 // headOffset + frame_dig -2 // poolKey: ValidatorPoolKey + extract 8 8 + btoi + int 1 + - + int 18 + * // acc * typeLength + + + int 10 // headOffset + + + frame_dig 2 // poolAlgoStaked: uint64 + itob + byte 0x76 // "v" + frame_dig -2 // poolKey: ValidatorPoolKey + extract 0 8 + btoi + itob + concat + cover 2 + box_replace + + // *if32_condition + // contracts/validatorRegistry.algo.ts:1146 + // isNewStakerToValidator + frame_dig -4 // isNewStakerToValidator: boolean + bz *if32_end + + // *if32_consequent + // contracts/validatorRegistry.algo.ts:1147 + // this.validatorList(poolKey.id).value.state.totalStakers += 1 + int 210 + dup + int 8 + byte 0x76 // "v" + frame_dig -2 // poolKey: ValidatorPoolKey + extract 0 8 + btoi + itob + concat + cover 2 + box_extract + btoi + int 1 + + + itob + byte 0x76 // "v" + frame_dig -2 // poolKey: ValidatorPoolKey + extract 0 8 + btoi + itob + concat + cover 2 + box_replace + +*if32_end: + // *if33_condition + // contracts/validatorRegistry.algo.ts:1149 + // isNewStakerToProtocol + frame_dig -5 // isNewStakerToProtocol: boolean + bz *if33_end + + // *if33_consequent + // contracts/validatorRegistry.algo.ts:1150 + // this.numStakers.value += 1 + byte 0x6e756d5374616b657273 // "numStakers" + app_global_get + int 1 + + + byte 0x6e756d5374616b657273 // "numStakers" + swap + app_global_put + +*if33_end: + // contracts/validatorRegistry.algo.ts:1152 + // this.validatorList(poolKey.id).value.state.totalAlgoStaked += stakedAmountPayment.amount - mbrAmtPaid + int 218 + dup + int 8 + byte 0x76 // "v" + frame_dig -2 // poolKey: ValidatorPoolKey + extract 0 8 + btoi + itob + concat + cover 2 + box_extract + btoi + frame_dig -1 // stakedAmountPayment: PayTxn + gtxns Amount + frame_dig -3 // mbrAmtPaid: uint64 + - + + + itob + byte 0x76 // "v" + frame_dig -2 // poolKey: ValidatorPoolKey + extract 0 8 + btoi + itob + concat + cover 2 + box_replace + + // contracts/validatorRegistry.algo.ts:1153 + // this.totalAlgoStaked.value += stakedAmountPayment.amount - mbrAmtPaid + byte 0x7374616b6564 // "staked" + app_global_get + frame_dig -1 // stakedAmountPayment: PayTxn + gtxns Amount + frame_dig -3 // mbrAmtPaid: uint64 + - + + + byte 0x7374616b6564 // "staked" + swap + app_global_put + retsub + +// updateStakerPoolSet(staker: Address, poolKey: ValidatorPoolKey): void +updateStakerPoolSet: + proto 2 0 + + // Push empty bytes after the frame pointer to reserve space for local variables + byte 0x + dup + + // contracts/validatorRegistry.algo.ts:1157 + // assert(this.stakerPoolSet(staker).exists) + byte 0x737073 // "sps" + frame_dig -1 // staker: Address + concat + box_len + swap + pop + assert + + // contracts/validatorRegistry.algo.ts:1159 + // poolSet = clone(this.stakerPoolSet(staker).value) + byte 0x737073 // "sps" + frame_dig -1 // staker: Address + concat + box_get + assert + frame_bury 0 // poolSet: (uint64,uint64,uint64)[6] + + // contracts/validatorRegistry.algo.ts:1160 + // for (let i = 0; i < this.stakerPoolSet(staker).value.length; i += 1) + int 0 + frame_bury 1 // i: uint64 + +*for_7: + // contracts/validatorRegistry.algo.ts:1160 + // i < this.stakerPoolSet(staker).value.length + frame_dig 1 // i: uint64 + int 6 + < + bz *for_7_end + + // *if34_condition + // contracts/validatorRegistry.algo.ts:1161 + // poolSet[i] === poolKey + frame_dig 0 // poolSet: (uint64,uint64,uint64)[6] + frame_dig 1 // i: uint64 + int 24 + * // acc * typeLength + int 24 + extract3 + frame_dig -2 // poolKey: ValidatorPoolKey + == + bz *if34_end + + // *if34_consequent + // contracts/validatorRegistry.algo.ts:1163 + // return; + retsub + +*if34_end: + // *if35_condition + // contracts/validatorRegistry.algo.ts:1165 + // poolSet[i].id === 0 + frame_dig 0 // poolSet: (uint64,uint64,uint64)[6] + frame_dig 1 // i: uint64 + int 24 + * // acc * typeLength + int 0 + + + int 8 + extract3 + btoi + int 0 + == + bz *if35_end + + // *if35_consequent + // contracts/validatorRegistry.algo.ts:1166 + // this.stakerPoolSet(staker).value[i] = poolKey + frame_dig 1 // i: uint64 + int 24 + * // acc * typeLength + frame_dig -2 // poolKey: ValidatorPoolKey + byte 0x737073 // "sps" + frame_dig -1 // staker: Address + concat + cover 2 + box_replace + + // contracts/validatorRegistry.algo.ts:1167 + // return; + retsub + +*if35_end: + +*for_7_continue: + // contracts/validatorRegistry.algo.ts:1160 + // i += 1 + frame_dig 1 // i: uint64 + int 1 + + + frame_bury 1 // i: uint64 + b *for_7 + +*for_7_end: + err // 'No empty slot available in the staker pool set' + +// removeFromStakerPoolSet(staker: Address, poolKey: ValidatorPoolKey): [boolean, boolean] +// +// Removes a pool key from the staker's active pool set - fails if not found (!) +// +// @param {Address} staker - The address of the staker. +// @param {ValidatorPoolKey} poolKey - The pool key they should be stored in +// +// @return [boolean, boolean] [is the staker gone from ALL pools of the given VALIDATOR, and is staker gone from ALL pools] +removeFromStakerPoolSet: + proto 2 1 + + // Push empty bytes after the frame pointer to reserve space for local variables + byte 0x + dupn 4 + + // contracts/validatorRegistry.algo.ts:1183 + // inSameValidatorPoolCount = 0 + int 0 + frame_bury 0 // inSameValidatorPoolCount: uint64 + + // contracts/validatorRegistry.algo.ts:1184 + // inAnyPoolCount = 0 + int 0 + frame_bury 1 // inAnyPoolCount: uint64 + + // contracts/validatorRegistry.algo.ts:1185 + // found = false + int 0 + frame_bury 2 // found: bool + + // contracts/validatorRegistry.algo.ts:1187 + // poolSet = clone(this.stakerPoolSet(staker).value) + byte 0x737073 // "sps" + frame_dig -1 // staker: Address + concat + box_get + assert + frame_bury 3 // poolSet: (uint64,uint64,uint64)[6] + + // contracts/validatorRegistry.algo.ts:1188 + // for (let i = 0; i < this.stakerPoolSet(staker).value.length; i += 1) + int 0 + frame_bury 4 // i: uint64 + +*for_8: + // contracts/validatorRegistry.algo.ts:1188 + // i < this.stakerPoolSet(staker).value.length + frame_dig 4 // i: uint64 + int 6 + < + bz *for_8_end + + // *if36_condition + // contracts/validatorRegistry.algo.ts:1189 + // poolSet[i].id === 0 + frame_dig 3 // poolSet: (uint64,uint64,uint64)[6] + frame_dig 4 // i: uint64 + int 24 + * // acc * typeLength + int 0 + + + int 8 + extract3 + btoi + int 0 + == + bz *if36_end + + // *if36_consequent + b *for_8_continue + +*if36_end: + // contracts/validatorRegistry.algo.ts:1192 + // inAnyPoolCount += 1 + frame_dig 1 // inAnyPoolCount: uint64 + int 1 + + + frame_bury 1 // inAnyPoolCount: uint64 + + // *if37_condition + // contracts/validatorRegistry.algo.ts:1193 + // poolSet[i].id === poolKey.id + frame_dig 3 // poolSet: (uint64,uint64,uint64)[6] + frame_dig 4 // i: uint64 + int 24 + * // acc * typeLength + int 0 + + + int 8 + extract3 + btoi + frame_dig -2 // poolKey: ValidatorPoolKey + extract 0 8 + btoi + == + bz *if37_end + + // *if37_consequent + // *if38_condition + // contracts/validatorRegistry.algo.ts:1194 + // poolSet[i] === poolKey + frame_dig 3 // poolSet: (uint64,uint64,uint64)[6] + frame_dig 4 // i: uint64 + int 24 + * // acc * typeLength + int 24 + extract3 + frame_dig -2 // poolKey: ValidatorPoolKey + == + bz *if38_else + + // *if38_consequent + // contracts/validatorRegistry.algo.ts:1195 + // found = true + int 1 + frame_bury 2 // found: bool + + // contracts/validatorRegistry.algo.ts:1197 + // this.stakerPoolSet(staker).value[i] = { id: 0, poolId: 0, poolAppId: 0 } + frame_dig 4 // i: uint64 + int 24 + * // acc * typeLength + byte 0x000000000000000000000000000000000000000000000000 + byte 0x737073 // "sps" + frame_dig -1 // staker: Address + concat + cover 2 + box_replace + b *if38_end + +*if38_else: + // contracts/validatorRegistry.algo.ts:1199 + // inSameValidatorPoolCount += 1 + frame_dig 0 // inSameValidatorPoolCount: uint64 + int 1 + + + frame_bury 0 // inSameValidatorPoolCount: uint64 + +*if38_end: + +*if37_end: + +*for_8_continue: + // contracts/validatorRegistry.algo.ts:1188 + // i += 1 + frame_dig 4 // i: uint64 + int 1 + + + frame_bury 4 // i: uint64 + b *for_8 + +*for_8_end: + // *if39_condition + // contracts/validatorRegistry.algo.ts:1203 + // !found + frame_dig 2 // found: bool + ! + bz *if39_end + + // *if39_consequent + err // 'No matching slot found when told to remove a pool from the stakers set' + +*if39_end: + // contracts/validatorRegistry.algo.ts:1207 + // return [inSameValidatorPoolCount === 0, inAnyPoolCount === 0]; + byte 0x00 + int 0 + frame_dig 0 // inSameValidatorPoolCount: uint64 + int 0 + == + setbit + int 1 + frame_dig 1 // inAnyPoolCount: uint64 + int 0 + == + setbit + + // set the subroutine return value + frame_bury 0 + + // pop all local variables from the stack + popn 4 + retsub + +// addPoolToNode(validatorId: ValidatorIdType, poolAppId: uint64, nodeNum: uint64): void +addPoolToNode: + proto 3 0 + + // Push empty bytes after the frame pointer to reserve space for local variables + byte 0x + dupn 2 + + // contracts/validatorRegistry.algo.ts:1211 + // nodePoolAssignments = clone(this.validatorList(validatorId).value.nodePoolAssignments) + int 866 // headOffset + int 192 + byte 0x76 // "v" + frame_dig -1 // validatorId: ValidatorIdType + itob + concat + cover 2 + box_extract + frame_bury 0 // nodePoolAssignments: ((uint64[3])[8]) + + // contracts/validatorRegistry.algo.ts:1212 + // maxPoolsPerNodeForThisValidator = this.validatorList(validatorId).value.config.poolsPerNode as uint64 + int 191 + int 1 + byte 0x76 // "v" + frame_dig -1 // validatorId: ValidatorIdType + itob + concat + cover 2 + box_extract + btoi + frame_bury 1 // maxPoolsPerNodeForThisValidator: uint64 + + // contracts/validatorRegistry.algo.ts:1214 + // assert(nodeNum >= 1 && nodeNum <= MAX_NODES) + frame_dig -3 // nodeNum: uint64 + int 1 + >= + dup + bz *skip_and8 + frame_dig -3 // nodeNum: uint64 + int 8 + <= + && + +*skip_and8: + assert + + // contracts/validatorRegistry.algo.ts:1216 + // for (let i = 0; i < maxPoolsPerNodeForThisValidator; i += 1) + int 0 + frame_bury 2 // i: uint64 + +*for_9: + // contracts/validatorRegistry.algo.ts:1216 + // i < maxPoolsPerNodeForThisValidator + frame_dig 2 // i: uint64 + frame_dig 1 // maxPoolsPerNodeForThisValidator: uint64 + < + bz *for_9_end + + // *if40_condition + // contracts/validatorRegistry.algo.ts:1217 + // nodePoolAssignments.nodes[nodeNum - 1].poolAppIds[i] === 0 + frame_dig 0 // nodePoolAssignments: ((uint64[3])[8]) + int 0 + frame_dig -3 // nodeNum: uint64 + int 1 + - + int 24 + * // acc * typeLength + + + int 0 + + + frame_dig 2 // i: uint64 + int 8 + * // acc * typeLength + + + int 8 + extract3 + btoi + int 0 + == + bz *if40_end + + // *if40_consequent + // contracts/validatorRegistry.algo.ts:1219 + // this.validatorList(validatorId).value.nodePoolAssignments.nodes[nodeNum - 1].poolAppIds[i] = poolAppId + int 866 + frame_dig -3 // nodeNum: uint64 + int 1 + - + int 24 + * // acc * typeLength + + + int 0 + + + frame_dig 2 // i: uint64 + int 8 + * // acc * typeLength + + + frame_dig -2 // poolAppId: uint64 + itob + byte 0x76 // "v" + frame_dig -1 // validatorId: ValidatorIdType + itob + concat + cover 2 + box_replace + + // contracts/validatorRegistry.algo.ts:1220 + // return; + retsub + +*if40_end: + +*for_9_continue: + // contracts/validatorRegistry.algo.ts:1216 + // i += 1 + frame_dig 2 // i: uint64 + int 1 + + + frame_bury 2 // i: uint64 + b *for_9 + +*for_9_end: + err // 'no available space in specified node for this pool' + +// doesStakerMeetGating(validatorId: ValidatorIdType, valueToVerify: uint64): void +// +// Checks if a staker meets the gating requirements specified by the validator. +// +// @param {ValidatorIdType} validatorId - The id of the validator. +// @param {uint64} valueToVerify - The value to verify against the gating requirements. +// @returns {void} or asserts if requirements not met. +doesStakerMeetGating: + proto 2 0 + + // Push empty bytes after the frame pointer to reserve space for local variables + byte 0x + dupn 7 + + // contracts/validatorRegistry.algo.ts:1234 + // type = this.validatorList(validatorId).value.config.entryGatingType + int 80 + int 1 + byte 0x76 // "v" + frame_dig -1 // validatorId: ValidatorIdType + itob + concat + cover 2 + box_extract + btoi + frame_bury 0 // type: uint8 + + // *if41_condition + // contracts/validatorRegistry.algo.ts:1235 + // type === GATING_TYPE_NONE + frame_dig 0 // type: uint8 + int 0 + == + bz *if41_end + + // *if41_consequent + // contracts/validatorRegistry.algo.ts:1236 + // return; + retsub + +*if41_end: + // contracts/validatorRegistry.algo.ts:1238 + // staker = this.txn.sender + txn Sender + frame_bury 1 // staker: address + + // contracts/validatorRegistry.algo.ts:1239 + // gateReq = clone(this.validatorList(validatorId).value.config.entryGatingValue) + int 81 + int 32 + byte 0x76 // "v" + frame_dig -1 // validatorId: ValidatorIdType + itob + concat + cover 2 + box_extract + frame_bury 2 // gateReq: byte[32] + + // *if42_condition + // contracts/validatorRegistry.algo.ts:1243 + // type === GATING_TYPE_ASSETS_CREATED_BY || + // type === GATING_TYPE_ASSET_ID || + // type === GATING_TYPE_CREATED_BY_NFD_ADDRESSES + frame_dig 0 // type: uint8 + int 1 + == + dup + bnz *skip_or4 + frame_dig 0 // type: uint8 + int 2 + == + || + +*skip_or4: + dup + bnz *skip_or5 + frame_dig 0 // type: uint8 + int 3 + == + || + +*skip_or5: + bz *if42_end + + // *if42_consequent + // contracts/validatorRegistry.algo.ts:1247 + // assert(valueToVerify !== 0) + frame_dig -2 // valueToVerify: uint64 + int 0 + != + assert + + // contracts/validatorRegistry.algo.ts:1248 + // balRequired = this.validatorList(validatorId).value.config.gatingAssetMinBalance + int 113 + int 8 + byte 0x76 // "v" + frame_dig -1 // validatorId: ValidatorIdType + itob + concat + cover 2 + box_extract + btoi + frame_bury 3 // balRequired: uint64 + + // *if43_condition + // contracts/validatorRegistry.algo.ts:1249 + // balRequired === 0 + frame_dig 3 // balRequired: uint64 + int 0 + == + bz *if43_end + + // *if43_consequent + // contracts/validatorRegistry.algo.ts:1250 + // balRequired = 1 + int 1 + frame_bury 3 // balRequired: uint64 + +*if43_end: + // contracts/validatorRegistry.algo.ts:1252 + // assert( + // staker.assetBalance(AssetID.fromUint64(valueToVerify)) >= balRequired, + // 'must have required minimum balance of validator defined token to add stake' + // ) + frame_dig 1 // staker: address + frame_dig -2 // valueToVerify: uint64 + asset_holding_get AssetBalance + pop + frame_dig 3 // balRequired: uint64 + >= + + // must have required minimum balance of validator defined token to add stake + assert + +*if42_end: + // *if44_condition + // contracts/validatorRegistry.algo.ts:1257 + // type === GATING_TYPE_ASSETS_CREATED_BY + frame_dig 0 // type: uint8 + int 1 + == + bz *if44_end + + // *if44_consequent + // contracts/validatorRegistry.algo.ts:1258 + // assert( + // AssetID.fromUint64(valueToVerify).creator === Address.fromBytes(gateReq), + // 'specified asset must be created by creator that the validator defined as a requirement to stake' + // ) + frame_dig -2 // valueToVerify: uint64 + asset_params_get AssetCreator + pop + frame_dig 2 // gateReq: byte[32] + == + + // specified asset must be created by creator that the validator defined as a requirement to stake + assert + +*if44_end: + // *if45_condition + // contracts/validatorRegistry.algo.ts:1263 + // type === GATING_TYPE_ASSET_ID + frame_dig 0 // type: uint8 + int 2 + == + bz *if45_end + + // *if45_consequent + // contracts/validatorRegistry.algo.ts:1264 + // requiredAsset = extractUint64(gateReq, 0) + frame_dig 2 // gateReq: byte[32] + int 0 + extract_uint64 + frame_bury 4 // requiredAsset: uint64 + + // contracts/validatorRegistry.algo.ts:1265 + // assert(requiredAsset !== 0) + frame_dig 4 // requiredAsset: uint64 + int 0 + != + assert + + // contracts/validatorRegistry.algo.ts:1266 + // assert( + // valueToVerify === requiredAsset, + // 'specified asset must be identical to the asset id defined as a requirement to stake' + // ) + frame_dig -2 // valueToVerify: uint64 + frame_dig 4 // requiredAsset: uint64 + == + + // specified asset must be identical to the asset id defined as a requirement to stake + assert + +*if45_end: + // *if46_condition + // contracts/validatorRegistry.algo.ts:1271 + // type === GATING_TYPE_CREATED_BY_NFD_ADDRESSES + frame_dig 0 // type: uint8 + int 3 + == + bz *if46_end + + // *if46_consequent + // contracts/validatorRegistry.algo.ts:1272 + // nfdForInfo = this.validatorList(validatorId).value.config.nfdForInfo + int 72 + int 8 + byte 0x76 // "v" + frame_dig -1 // validatorId: ValidatorIdType + itob + concat + cover 2 + box_extract + btoi + frame_bury 5 // nfdForInfo: uint64 + + // contracts/validatorRegistry.algo.ts:1275 + // assert( + // this.isAddressInNFDCAAlgoList(nfdForInfo, AssetID.fromUint64(valueToVerify).creator), + // 'specified asset must be created by creator that is one of the linked addresses in an nfd' + // ) + frame_dig -2 // valueToVerify: uint64 + asset_params_get AssetCreator + pop + frame_dig 5 // nfdForInfo: uint64 + callsub isAddressInNFDCAAlgoList + + // specified asset must be created by creator that is one of the linked addresses in an nfd + assert + +*if46_end: + // *if47_condition + // contracts/validatorRegistry.algo.ts:1280 + // type === GATING_TYPE_SEGMENT_OF_NFD + frame_dig 0 // type: uint8 + int 4 + == + bz *if47_end + + // *if47_consequent + // contracts/validatorRegistry.algo.ts:1282 + // userOfferedNFDAppID = valueToVerify + frame_dig -2 // valueToVerify: uint64 + frame_bury 6 // userOfferedNFDAppID: uint64 + + // contracts/validatorRegistry.algo.ts:1283 + // assert(this.isNFDAppIDValid(userOfferedNFDAppID), 'provided NFD must be valid') + frame_dig 6 // userOfferedNFDAppID: uint64 + callsub isNFDAppIDValid + + // provided NFD must be valid + assert + + // contracts/validatorRegistry.algo.ts:1286 + // assert( + // rawBytes(AppID.fromUint64(userOfferedNFDAppID).globalState('i.owner.a') as Address) === + // rawBytes(staker) || this.isAddressInNFDCAAlgoList(userOfferedNFDAppID, staker), + // "provided nfd for entry isn't owned or linked to the staker" + // ) + frame_dig 6 // userOfferedNFDAppID: uint64 + byte 0x692e6f776e65722e61 // "i.owner.a" + app_global_get_ex + assert + frame_dig 1 // staker: address + == + dup + bnz *skip_or6 + frame_dig 1 // staker: address + frame_dig 6 // userOfferedNFDAppID: uint64 + callsub isAddressInNFDCAAlgoList + || + +*skip_or6: + // provided nfd for entry isn't owned or linked to the staker + assert + + // contracts/validatorRegistry.algo.ts:1293 + // requiredParentAppID = extractUint64(gateReq, 0) + frame_dig 2 // gateReq: byte[32] + int 0 + extract_uint64 + frame_bury 7 // requiredParentAppID: uint64 + + // contracts/validatorRegistry.algo.ts:1295 + // assert( + // (AppID.fromUint64(userOfferedNFDAppID).globalState('i.parentAppID') as uint64) === requiredParentAppID, + // 'specified nfd must be a segment of the nfd the validator specified as a requirement' + // ) + frame_dig 6 // userOfferedNFDAppID: uint64 + byte 0x692e706172656e744170704944 // "i.parentAppID" + app_global_get_ex + assert + frame_dig 7 // requiredParentAppID: uint64 + == + + // specified nfd must be a segment of the nfd the validator specified as a requirement + assert + +*if47_end: + retsub + +// isNFDAppIDValid(nfdAppID: uint64): boolean +// +// Checks if the given NFD App id is valid. Using only the App id there's no validation against the name (ie: that nfd X is name Y) +// So it's assumed for the caller, the app id alone is fine. The name is fetched from the specified app id and the two +// together are used for validity check call to the nfd registry. +// +// @param {uint64} nfdAppID - The NFD App id to verify. +// +// @returns {boolean} - Returns true if the NFD App id is valid, otherwise false. +isNFDAppIDValid: + proto 1 1 + + // Push empty bytes after the frame pointer to reserve space for local variables + byte 0x + + // contracts/validatorRegistry.algo.ts:1313 + // userOfferedNFDName = AppID.fromUint64(nfdAppID).globalState('i.name') as string + frame_dig -1 // nfdAppID: uint64 + byte 0x692e6e616d65 // "i.name" + app_global_get_ex + assert + frame_bury 0 // userOfferedNFDName: string + + // contracts/validatorRegistry.algo.ts:1315 + // sendAppCall({ + // applicationID: AppID.fromUint64(this.nfdRegistryAppId), + // applicationArgs: ['is_valid_nfd_appid', userOfferedNFDName, itob(nfdAppID)], + // applications: [AppID.fromUint64(nfdAppID)], + // }) + itxn_begin + int appl + itxn_field TypeEnum + + // contracts/validatorRegistry.algo.ts:1316 + // applicationID: AppID.fromUint64(this.nfdRegistryAppId) + pushint TMPL_nfdRegistryAppId + itxn_field ApplicationID + + // contracts/validatorRegistry.algo.ts:1317 + // applicationArgs: ['is_valid_nfd_appid', userOfferedNFDName, itob(nfdAppID)] + byte 0x69735f76616c69645f6e66645f6170706964 // "is_valid_nfd_appid" + itxn_field ApplicationArgs + frame_dig 0 // userOfferedNFDName: string + itxn_field ApplicationArgs + frame_dig -1 // nfdAppID: uint64 + itob + itxn_field ApplicationArgs + + // contracts/validatorRegistry.algo.ts:1318 + // applications: [AppID.fromUint64(nfdAppID)] + frame_dig -1 // nfdAppID: uint64 + itxn_field Applications + + // Fee field not set, defaulting to 0 + int 0 + itxn_field Fee + + // Submit inner transaction + itxn_submit + + // contracts/validatorRegistry.algo.ts:1320 + // return btoi(this.itxn.lastLog) === 1; + itxn LastLog + btoi + int 1 + == + + // set the subroutine return value + frame_bury 0 + retsub + +// isAddressInNFDCAAlgoList(nfdAppID: uint64, addrToFind: Address): boolean +// +// Checks if the specified address is present in an NFDs list of verified addresses. +// The NFD is assumed to have already been validated as official. +// +// @param {uint64} nfdAppID - The NFD application id. +// @param {Address} addrToFind - The address to find in the v.caAlgo.0.as property +// @return {boolean} - `true` if the address is present, `false` otherwise. +isAddressInNFDCAAlgoList: + proto 2 1 + + // Push empty bytes after the frame pointer to reserve space for local variables + byte 0x + dupn 2 + + // contracts/validatorRegistry.algo.ts:1332 + // sendAppCall({ + // applicationID: AppID.fromUint64(nfdAppID), + // applicationArgs: ['read_property', 'v.caAlgo.0.as'], + // }) + itxn_begin + int appl + itxn_field TypeEnum + + // contracts/validatorRegistry.algo.ts:1333 + // applicationID: AppID.fromUint64(nfdAppID) + frame_dig -1 // nfdAppID: uint64 + itxn_field ApplicationID + + // contracts/validatorRegistry.algo.ts:1334 + // applicationArgs: ['read_property', 'v.caAlgo.0.as'] + byte 0x726561645f70726f7065727479 // "read_property" + itxn_field ApplicationArgs + byte 0x762e6361416c676f2e302e6173 // "v.caAlgo.0.as" + itxn_field ApplicationArgs + + // Fee field not set, defaulting to 0 + int 0 + itxn_field Fee + + // Submit inner transaction + itxn_submit + + // contracts/validatorRegistry.algo.ts:1336 + // caAlgoData = this.itxn.lastLog + itxn LastLog + frame_bury 0 // caAlgoData: byte[] + + // contracts/validatorRegistry.algo.ts:1337 + // for (let i = 0; i < caAlgoData.length; i += 32) + int 0 + frame_bury 1 // i: uint64 + +*for_10: + // contracts/validatorRegistry.algo.ts:1337 + // i < caAlgoData.length + frame_dig 1 // i: uint64 + frame_dig 0 // caAlgoData: byte[] + len + < + bz *for_10_end + + // contracts/validatorRegistry.algo.ts:1338 + // addr = extract3(caAlgoData, i, 32) + frame_dig 0 // caAlgoData: byte[] + frame_dig 1 // i: uint64 + int 32 + extract3 + frame_bury 2 // addr: byte[] + + // *if48_condition + // contracts/validatorRegistry.algo.ts:1339 + // addr !== rawBytes(globals.zeroAddress) && addr === rawBytes(addrToFind) + frame_dig 2 // addr: byte[] + global ZeroAddress + != + dup + bz *skip_and9 + frame_dig 2 // addr: byte[] + frame_dig -2 // addrToFind: Address + == + && + +*skip_and9: + bz *if48_end + + // *if48_consequent + // contracts/validatorRegistry.algo.ts:1340 + // return true; + int 1 + + // set the subroutine return value + frame_bury 0 + + // pop all local variables from the stack + popn 2 + retsub + +*if48_end: + +*for_10_continue: + // contracts/validatorRegistry.algo.ts:1337 + // i += 32 + frame_dig 1 // i: uint64 + int 32 + + + frame_bury 1 // i: uint64 + b *for_10 + +*for_10_end: + // contracts/validatorRegistry.algo.ts:1343 + // return false; + int 0 + + // set the subroutine return value + frame_bury 0 + + // pop all local variables from the stack + popn 2 + retsub + +// maxAlgoAllowedPerPool(): uint64 +// +// Returns the MAXIMUM allowed stake per pool and still receive incentives - we'll treat this as the 'max per pool' +maxAlgoAllowedPerPool: + proto 0 1 + + // contracts/validatorRegistry.algo.ts:1351 + // return 70_000_000_000_000; + int 70_000_000_000_000 + retsub + +// algoSaturationLevel(): uint64 +// +// Returns the maximum allowed stake per validator based on a percentage of all current online stake before +// the validator is considered saturated - where rewards are diminished. +// NOTE: this function is defined twice - here and in staking pool contract. Both must be identical. +algoSaturationLevel: + proto 0 1 + + // Push empty bytes after the frame pointer to reserve space for local variables + byte 0x + + // contracts/validatorRegistry.algo.ts:1360 + // online = this.getCurrentOnlineStake() + callsub getCurrentOnlineStake + frame_bury 0 // online: uint64 + + // contracts/validatorRegistry.algo.ts:1362 + // return wideRatio([online, MAX_VALIDATOR_SOFT_PCT_OF_ONLINE_1DECIMAL], [1000]); + frame_dig 0 // online: uint64 + int 100 + mulw + int 0 + int 1000 + divmodw + pop + pop + swap + ! + assert + + // set the subroutine return value + frame_bury 0 + retsub + +// maxAllowedStake(): uint64 +// +// Returns the MAXIMUM allowed stake per validator based on a percentage of all current online stake. +// Adding stake is completely blocked at this amount. +maxAllowedStake: + proto 0 1 + + // Push empty bytes after the frame pointer to reserve space for local variables + byte 0x + + // contracts/validatorRegistry.algo.ts:1370 + // online = this.getCurrentOnlineStake() + callsub getCurrentOnlineStake + frame_bury 0 // online: uint64 + + // contracts/validatorRegistry.algo.ts:1372 + // return wideRatio([online, MAX_VALIDATOR_HARD_PCT_OF_ONLINE_1DECIMAL], [1000]); + frame_dig 0 // online: uint64 + int 150 + mulw + int 0 + int 1000 + divmodw + pop + pop + swap + ! + assert + + // set the subroutine return value + frame_bury 0 + retsub + +// getCurrentOnlineStake(): uint64 +getCurrentOnlineStake: + proto 0 1 + + // contracts/validatorRegistry.algo.ts:1377 + // return 2_000_000_000_000_000; + int 2_000_000_000_000_000 + retsub + +// minBalanceForAccount(contracts: uint64, extraPages: uint64, assets: uint64, localInts: uint64, localBytes: uint64, globalInts: uint64, globalBytes: uint64): uint64 +minBalanceForAccount: + proto 7 1 + + // Push empty bytes after the frame pointer to reserve space for local variables + byte 0x + + // contracts/validatorRegistry.algo.ts:1389 + // minBal = ALGORAND_ACCOUNT_MIN_BALANCE + int 100000 + frame_bury 0 // minBal: uint64 + + // contracts/validatorRegistry.algo.ts:1390 + // minBal += contracts * APPLICATION_BASE_FEE + frame_dig 0 // minBal: uint64 + frame_dig -1 // contracts: uint64 + int 100000 + * + + + frame_bury 0 // minBal: uint64 + + // contracts/validatorRegistry.algo.ts:1391 + // minBal += extraPages * APPLICATION_BASE_FEE + frame_dig 0 // minBal: uint64 + frame_dig -2 // extraPages: uint64 + int 100000 + * + + + frame_bury 0 // minBal: uint64 + + // contracts/validatorRegistry.algo.ts:1392 + // minBal += assets * ASSET_HOLDING_FEE + frame_dig 0 // minBal: uint64 + frame_dig -3 // assets: uint64 + int 100000 + * + + + frame_bury 0 // minBal: uint64 + + // contracts/validatorRegistry.algo.ts:1393 + // minBal += localInts * SSC_VALUE_UINT + frame_dig 0 // minBal: uint64 + frame_dig -4 // localInts: uint64 + int 28500 + * + + + frame_bury 0 // minBal: uint64 + + // contracts/validatorRegistry.algo.ts:1394 + // minBal += globalInts * SSC_VALUE_UINT + frame_dig 0 // minBal: uint64 + frame_dig -6 // globalInts: uint64 + int 28500 + * + + + frame_bury 0 // minBal: uint64 + + // contracts/validatorRegistry.algo.ts:1395 + // minBal += localBytes * SSC_VALUE_BYTES + frame_dig 0 // minBal: uint64 + frame_dig -5 // localBytes: uint64 + int 50000 + * + + + frame_bury 0 // minBal: uint64 + + // contracts/validatorRegistry.algo.ts:1396 + // minBal += globalBytes * SSC_VALUE_BYTES + frame_dig 0 // minBal: uint64 + frame_dig -7 // globalBytes: uint64 + int 50000 + * + + + frame_bury 0 // minBal: uint64 + + // contracts/validatorRegistry.algo.ts:1397 + // return minBal; + frame_dig 0 // minBal: uint64 + + // set the subroutine return value + frame_bury 0 + retsub + +// costForBoxStorage(totalNumBytes: uint64): uint64 +costForBoxStorage: + proto 1 1 + + // contracts/validatorRegistry.algo.ts:1404 + // return SCBOX_PERBOX + totalNumBytes * SCBOX_PERBYTE; + int 2500 + frame_dig -1 // totalNumBytes: uint64 + int 400 + * + + + retsub + +*create_NoOp: + method "createApplication(uint64)void" + txna ApplicationArgs 0 + match *abi_route_createApplication + err + +*call_NoOp: + method "gas()void" + method "getMbrAmounts()(uint64,uint64,uint64,uint64)" + method "getProtocolConstraints()(uint64,uint64,uint64,uint64,uint64,uint64,uint64,uint64,uint64,uint64,uint64)" + method "getNumValidators()uint64" + method "getValidatorConfig(uint64)(uint64,address,address,uint64,uint8,byte[32],uint64,uint64,uint64,uint16,uint32,address,uint64,uint64,uint8,uint64,uint64)" + method "getValidatorState(uint64)(uint16,uint64,uint64,uint64)" + method "getValidatorOwnerAndManager(uint64)(address,address)" + method "getPools(uint64)(uint64,uint16,uint64)[]" + method "getPoolAppId(uint64,uint64)uint64" + method "getPoolInfo((uint64,uint64,uint64))(uint64,uint16,uint64)" + method "getCurMaxStakePerPool(uint64)uint64" + method "doesStakerNeedToPayMBR(address)bool" + method "getStakedPoolsForAccount(address)(uint64,uint64,uint64)[]" + method "getTokenPayoutRatio(uint64)(uint64[24],uint64)" + method "getNodePoolAssignments(uint64)((uint64[3])[8])" + method "getNFDRegistryID()uint64" + method "addValidator(pay,string,(uint64,address,address,uint64,uint8,byte[32],uint64,uint64,uint64,uint16,uint32,address,uint64,uint64,uint8,uint64,uint64))uint64" + method "changeValidatorManager(uint64,address)void" + method "changeValidatorSunsetInfo(uint64,uint64,uint64)void" + method "changeValidatorNFD(uint64,uint64,string)void" + method "changeValidatorCommissionAddress(uint64,address)void" + method "changeValidatorRewardInfo(uint64,uint8,byte[32],uint64,uint64)void" + method "addPool(pay,uint64,uint64)(uint64,uint64,uint64)" + method "addStake(pay,uint64,uint64)(uint64,uint64,uint64)" + method "setTokenPayoutRatio(uint64)(uint64[24],uint64)" + method "stakeUpdatedViaRewards((uint64,uint64,uint64),uint64,uint64)void" + method "stakeRemoved((uint64,uint64,uint64),address,uint64,uint64,bool)void" + method "findPoolForStaker(uint64,address,uint64)((uint64,uint64,uint64),bool,bool)" + method "movePoolToNode(uint64,uint64,uint64)void" + txna ApplicationArgs 0 + match *abi_route_gas *abi_route_getMbrAmounts *abi_route_getProtocolConstraints *abi_route_getNumValidators *abi_route_getValidatorConfig *abi_route_getValidatorState *abi_route_getValidatorOwnerAndManager *abi_route_getPools *abi_route_getPoolAppId *abi_route_getPoolInfo *abi_route_getCurMaxStakePerPool *abi_route_doesStakerNeedToPayMBR *abi_route_getStakedPoolsForAccount *abi_route_getTokenPayoutRatio *abi_route_getNodePoolAssignments *abi_route_getNFDRegistryID *abi_route_addValidator *abi_route_changeValidatorManager *abi_route_changeValidatorSunsetInfo *abi_route_changeValidatorNFD *abi_route_changeValidatorCommissionAddress *abi_route_changeValidatorRewardInfo *abi_route_addPool *abi_route_addStake *abi_route_setTokenPayoutRatio *abi_route_stakeUpdatedViaRewards *abi_route_stakeRemoved *abi_route_findPoolForStaker *abi_route_movePoolToNode + err \ No newline at end of file diff --git a/contracts/contracts/artifacts/ValidatorRegistry.arc32.json b/contracts/contracts/artifacts/ValidatorRegistry.arc32.json new file mode 100644 index 00000000..a49b3069 --- /dev/null +++ b/contracts/contracts/artifacts/ValidatorRegistry.arc32.json @@ -0,0 +1,709 @@ +{ + "hints": { + "createApplication(uint64)void": { + "call_config": { + "no_op": "CREATE" + } + }, + "gas()void": { + "call_config": { + "no_op": "CALL" + } + }, + "getMbrAmounts()(uint64,uint64,uint64,uint64)": { + "call_config": { + "no_op": "CALL" + } + }, + "getProtocolConstraints()(uint64,uint64,uint64,uint64,uint64,uint64,uint64,uint64,uint64,uint64,uint64)": { + "call_config": { + "no_op": "CALL" + } + }, + "getNumValidators()uint64": { + "call_config": { + "no_op": "CALL" + } + }, + "getValidatorConfig(uint64)(uint64,address,address,uint64,uint8,byte[32],uint64,uint64,uint64,uint16,uint32,address,uint64,uint64,uint8,uint64,uint64)": { + "call_config": { + "no_op": "CALL" + } + }, + "getValidatorState(uint64)(uint16,uint64,uint64,uint64)": { + "call_config": { + "no_op": "CALL" + } + }, + "getValidatorOwnerAndManager(uint64)(address,address)": { + "call_config": { + "no_op": "CALL" + } + }, + "getPools(uint64)(uint64,uint16,uint64)[]": { + "call_config": { + "no_op": "CALL" + } + }, + "getPoolAppId(uint64,uint64)uint64": { + "call_config": { + "no_op": "CALL" + } + }, + "getPoolInfo((uint64,uint64,uint64))(uint64,uint16,uint64)": { + "call_config": { + "no_op": "CALL" + } + }, + "getCurMaxStakePerPool(uint64)uint64": { + "call_config": { + "no_op": "CALL" + } + }, + "doesStakerNeedToPayMBR(address)bool": { + "call_config": { + "no_op": "CALL" + } + }, + "getStakedPoolsForAccount(address)(uint64,uint64,uint64)[]": { + "call_config": { + "no_op": "CALL" + } + }, + "getTokenPayoutRatio(uint64)(uint64[24],uint64)": { + "call_config": { + "no_op": "CALL" + } + }, + "getNodePoolAssignments(uint64)((uint64[3])[8])": { + "call_config": { + "no_op": "CALL" + } + }, + "getNFDRegistryID()uint64": { + "call_config": { + "no_op": "CALL" + } + }, + "addValidator(pay,string,(uint64,address,address,uint64,uint8,byte[32],uint64,uint64,uint64,uint16,uint32,address,uint64,uint64,uint8,uint64,uint64))uint64": { + "call_config": { + "no_op": "CALL" + } + }, + "changeValidatorManager(uint64,address)void": { + "call_config": { + "no_op": "CALL" + } + }, + "changeValidatorSunsetInfo(uint64,uint64,uint64)void": { + "call_config": { + "no_op": "CALL" + } + }, + "changeValidatorNFD(uint64,uint64,string)void": { + "call_config": { + "no_op": "CALL" + } + }, + "changeValidatorCommissionAddress(uint64,address)void": { + "call_config": { + "no_op": "CALL" + } + }, + "changeValidatorRewardInfo(uint64,uint8,byte[32],uint64,uint64)void": { + "call_config": { + "no_op": "CALL" + } + }, + "addPool(pay,uint64,uint64)(uint64,uint64,uint64)": { + "call_config": { + "no_op": "CALL" + } + }, + "addStake(pay,uint64,uint64)(uint64,uint64,uint64)": { + "call_config": { + "no_op": "CALL" + } + }, + "setTokenPayoutRatio(uint64)(uint64[24],uint64)": { + "call_config": { + "no_op": "CALL" + } + }, + "stakeUpdatedViaRewards((uint64,uint64,uint64),uint64,uint64)void": { + "call_config": { + "no_op": "CALL" + } + }, + "stakeRemoved((uint64,uint64,uint64),address,uint64,uint64,bool)void": { + "call_config": { + "no_op": "CALL" + } + }, + "findPoolForStaker(uint64,address,uint64)((uint64,uint64,uint64),bool,bool)": { + "call_config": { + "no_op": "CALL" + } + }, + "movePoolToNode(uint64,uint64,uint64)void": { + "call_config": { + "no_op": "CALL" + } + } + }, + "bare_call_config": { + "no_op": "NEVER", + "opt_in": "NEVER", + "close_out": "NEVER", + "update_application": "NEVER", + "delete_application": "NEVER" + }, + "schema": { + "local": { + "declared": {}, + "reserved": {} + }, + "global": { + "declared": { + "numValidators": { + "type": "uint64", + "key": "numV" + }, + "stakingPoolTemplateAppId": { + "type": "uint64", + "key": "poolTemplateAppId" + }, + "numStakers": { + "type": "uint64", + "key": "numStakers" + }, + "totalAlgoStaked": { + "type": "uint64", + "key": "staked" + } + }, + "reserved": {} + } + }, + "state": { + "global": { + "num_byte_slices": 0, + "num_uints": 4 + }, + "local": { + "num_byte_slices": 0, + "num_uints": 0 + } + }, + "source": { + "approval": "I3ByYWdtYSB2ZXJzaW9uIDEwCgovLyBUaGlzIFRFQUwgd2FzIGdlbmVyYXRlZCBieSBURUFMU2NyaXB0IHYwLjg4LjEKLy8gaHR0cHM6Ly9naXRodWIuY29tL2FsZ29yYW5kZm91bmRhdGlvbi9URUFMU2NyaXB0CgovLyBUaGlzIGNvbnRyYWN0IGlzIGNvbXBsaWFudCB3aXRoIGFuZC9vciBpbXBsZW1lbnRzIHRoZSBmb2xsb3dpbmcgQVJDczogWyBBUkM0IF0KCi8vIFRoZSBmb2xsb3dpbmcgdGVuIGxpbmVzIG9mIFRFQUwgaGFuZGxlIGluaXRpYWwgcHJvZ3JhbSBmbG93Ci8vIFRoaXMgcGF0dGVybiBpcyB1c2VkIHRvIG1ha2UgaXQgZWFzeSBmb3IgYW55b25lIHRvIHBhcnNlIHRoZSBzdGFydCBvZiB0aGUgcHJvZ3JhbSBhbmQgZGV0ZXJtaW5lIGlmIGEgc3BlY2lmaWMgYWN0aW9uIGlzIGFsbG93ZWQKLy8gSGVyZSwgYWN0aW9uIHJlZmVycyB0byB0aGUgT25Db21wbGV0ZSBpbiBjb21iaW5hdGlvbiB3aXRoIHdoZXRoZXIgdGhlIGFwcCBpcyBiZWluZyBjcmVhdGVkIG9yIGNhbGxlZAovLyBFdmVyeSBwb3NzaWJsZSBhY3Rpb24gZm9yIHRoaXMgY29udHJhY3QgaXMgcmVwcmVzZW50ZWQgaW4gdGhlIHN3aXRjaCBzdGF0ZW1lbnQKLy8gSWYgdGhlIGFjdGlvbiBpcyBub3QgaW1wbGVtZW50ZWQgaW4gdGhlIGNvbnRyYWN0LCBpdHMgcmVzcGVjdGl2ZSBicmFuY2ggd2lsbCBiZSAiKk5PVF9JTVBMRU1FTlRFRCIgd2hpY2gganVzdCBjb250YWlucyAiZXJyIgp0eG4gQXBwbGljYXRpb25JRAohCmludCA2CioKdHhuIE9uQ29tcGxldGlvbgorCnN3aXRjaCAqY2FsbF9Ob09wICpOT1RfSU1QTEVNRU5URUQgKk5PVF9JTVBMRU1FTlRFRCAqTk9UX0lNUExFTUVOVEVEICpOT1RfSU1QTEVNRU5URUQgKk5PVF9JTVBMRU1FTlRFRCAqY3JlYXRlX05vT3AgKk5PVF9JTVBMRU1FTlRFRCAqTk9UX0lNUExFTUVOVEVEICpOT1RfSU1QTEVNRU5URUQgKk5PVF9JTVBMRU1FTlRFRCAqTk9UX0lNUExFTUVOVEVECgoqTk9UX0lNUExFTUVOVEVEOgoJZXJyCgovLyBjcmVhdGVBcHBsaWNhdGlvbih1aW50NjQpdm9pZAoqYWJpX3JvdXRlX2NyZWF0ZUFwcGxpY2F0aW9uOgoJLy8gcG9vbFRlbXBsYXRlQXBwSWQ6IHVpbnQ2NAoJdHhuYSBBcHBsaWNhdGlvbkFyZ3MgMQoJYnRvaQoKCS8vIGV4ZWN1dGUgY3JlYXRlQXBwbGljYXRpb24odWludDY0KXZvaWQKCWNhbGxzdWIgY3JlYXRlQXBwbGljYXRpb24KCWludCAxCglyZXR1cm4KCi8vIGNyZWF0ZUFwcGxpY2F0aW9uKHBvb2xUZW1wbGF0ZUFwcElkOiB1aW50NjQpOiB2b2lkCmNyZWF0ZUFwcGxpY2F0aW9uOgoJcHJvdG8gMSAwCgoJLy8gY29udHJhY3RzL3ZhbGlkYXRvclJlZ2lzdHJ5LmFsZ28udHM6MTk0CgkvLyB0aGlzLm51bVZhbGlkYXRvcnMudmFsdWUgPSAwCglieXRlIDB4NmU3NTZkNTYgLy8gIm51bVYiCglpbnQgMAoJYXBwX2dsb2JhbF9wdXQKCgkvLyBjb250cmFjdHMvdmFsaWRhdG9yUmVnaXN0cnkuYWxnby50czoxOTUKCS8vIHRoaXMuc3Rha2luZ1Bvb2xUZW1wbGF0ZUFwcElkLnZhbHVlID0gcG9vbFRlbXBsYXRlQXBwSWQKCWJ5dGUgMHg3MDZmNmY2YzU0NjU2ZDcwNmM2MTc0NjU0MTcwNzA0OTY0IC8vICJwb29sVGVtcGxhdGVBcHBJZCIKCWZyYW1lX2RpZyAtMSAvLyBwb29sVGVtcGxhdGVBcHBJZDogdWludDY0CglhcHBfZ2xvYmFsX3B1dAoKCS8vIGNvbnRyYWN0cy92YWxpZGF0b3JSZWdpc3RyeS5hbGdvLnRzOjE5NgoJLy8gdGhpcy5udW1TdGFrZXJzLnZhbHVlID0gMAoJYnl0ZSAweDZlNzU2ZDUzNzQ2MTZiNjU3MjczIC8vICJudW1TdGFrZXJzIgoJaW50IDAKCWFwcF9nbG9iYWxfcHV0CgoJLy8gY29udHJhY3RzL3ZhbGlkYXRvclJlZ2lzdHJ5LmFsZ28udHM6MTk3CgkvLyB0aGlzLnRvdGFsQWxnb1N0YWtlZC52YWx1ZSA9IDAKCWJ5dGUgMHg3Mzc0NjE2YjY1NjQgLy8gInN0YWtlZCIKCWludCAwCglhcHBfZ2xvYmFsX3B1dAoJcmV0c3ViCgovLyBnYXMoKXZvaWQKKmFiaV9yb3V0ZV9nYXM6CgkvLyBleGVjdXRlIGdhcygpdm9pZAoJY2FsbHN1YiBnYXMKCWludCAxCglyZXR1cm4KCi8vIGdhcygpOiB2b2lkCi8vCi8vIGdhcyBpcyBhIGR1bW15IG5vLW9wIGNhbGwgdGhhdCBjYW4gYmUgdXNlZCB0byBwb29sLXVwIHJlc291cmNlIHJlZmVyZW5jZXMgYW5kIG9wY29kZSBjb3N0CmdhczoKCXByb3RvIDAgMAoJcmV0c3ViCgovLyBnZXRNYnJBbW91bnRzKCkodWludDY0LHVpbnQ2NCx1aW50NjQsdWludDY0KQoqYWJpX3JvdXRlX2dldE1ickFtb3VudHM6CgkvLyBUaGUgQUJJIHJldHVybiBwcmVmaXgKCWJ5dGUgMHgxNTFmN2M3NQoKCS8vIGV4ZWN1dGUgZ2V0TWJyQW1vdW50cygpKHVpbnQ2NCx1aW50NjQsdWludDY0LHVpbnQ2NCkKCWNhbGxzdWIgZ2V0TWJyQW1vdW50cwoJY29uY2F0Cglsb2cKCWludCAxCglyZXR1cm4KCi8vIGdldE1ickFtb3VudHMoKTogTWJyQW1vdW50cwovLwovLyBSZXR1cm5zIHRoZSBNQlIgYW1vdW50cyBuZWVkZWQgZm9yIHZhcmlvdXMgYWN0aW9uczoKLy8gWwovLyBhZGRWYWxpZGF0b3JNYnI6IHVpbnQ2NCAtIG1iciBuZWVkZWQgdG8gYWRkIGEgbmV3IHZhbGlkYXRvciAtIHBhaWQgdG8gdmFsaWRhdG9yIGNvbnRyYWN0Ci8vIGFkZFBvb2xNYnI6IHVpbnQ2NCAtIG1iciBuZWVkZWQgdG8gYWRkIGEgbmV3IHBvb2wgLSBwYWlkIHRvIHZhbGlkYXRvcgovLyBwb29sSW5pdE1icjogdWludDY0IC0gbWJyIG5lZWRlZCB0byBpbml0U3RvcmFnZSgpIG9mIHBvb2wgLSBwYWlkIHRvIHBvb2wgaXRzZWxmCi8vIGFkZFN0YWtlck1icjogdWludDY0IC0gbWJyIHN0YWtlciBuZWVkcyB0byBhZGQgdG8gZmlyc3Qgc3Rha2luZyBwYXltZW50IChzdGF5cyB3LyB2YWxpZGF0b3IpCi8vIF0KZ2V0TWJyQW1vdW50czoKCXByb3RvIDAgMQoKCS8vIGNvbnRyYWN0cy92YWxpZGF0b3JSZWdpc3RyeS5hbGdvLnRzOjIxNwoJLy8gcmV0dXJuIHsKCS8vICAgICAgICAgICAgIGFkZFZhbGlkYXRvck1icjogdGhpcy5jb3N0Rm9yQm94U3RvcmFnZSgxIC8qIHYgcHJlZml4ICovICsgbGVuPFZhbGlkYXRvcklkVHlwZT4oKSArIGxlbjxWYWxpZGF0b3JJbmZvPigpKSwKCS8vICAgICAgICAgICAgIGFkZFBvb2xNYnI6IHRoaXMubWluQmFsYW5jZUZvckFjY291bnQoCgkvLyAgICAgICAgICAgICAgICAgMSwKCS8vICAgICAgICAgICAgICAgICAwLAoJLy8gICAgICAgICAgICAgICAgIDAsCgkvLyAgICAgICAgICAgICAgICAgMCwKCS8vICAgICAgICAgICAgICAgICAwLAoJLy8gICAgICAgICAgICAgICAgIFN0YWtpbmdQb29sLnNjaGVtYS5nbG9iYWwubnVtVWludCwKCS8vICAgICAgICAgICAgICAgICBTdGFraW5nUG9vbC5zY2hlbWEuZ2xvYmFsLm51bUJ5dGVTbGljZQoJLy8gICAgICAgICAgICAgKSwKCS8vICAgICAgICAgICAgIHBvb2xJbml0TWJyOgoJLy8gICAgICAgICAgICAgICAgIEFMR09SQU5EX0FDQ09VTlRfTUlOX0JBTEFOQ0UgKwoJLy8gICAgICAgICAgICAgICAgIHRoaXMuY29zdEZvckJveFN0b3JhZ2UoNyAvKiAnc3Rha2VycycgbmFtZSAqLyArIGxlbjxTdGFrZWRJbmZvPigpICogTUFYX1NUQUtFUlNfUEVSX1BPT0wpLAoJLy8gICAgICAgICAgICAgYWRkU3Rha2VyTWJyOgoJLy8gICAgICAgICAgICAgICAgIC8vIGhvdyBtdWNoIHRvIGNoYXJnZSBmb3IgZmlyc3QgdGltZSBhIHN0YWtlciBhZGRzIHN0YWtlIC0gc2luY2Ugd2UgYWRkIGEgdHJhY2tpbmcgYm94IHBlciBzdGFrZXIKCS8vICAgICAgICAgICAgICAgICB0aGlzLmNvc3RGb3JCb3hTdG9yYWdlKAoJLy8gICAgICAgICAgICAgICAgICAgICAzIC8qICdzcHMnIHByZWZpeCAqLyArIGxlbjxBZGRyZXNzPigpICsgbGVuPFZhbGlkYXRvclBvb2xLZXk+KCkgKiBNQVhfUE9PTFNfUEVSX1NUQUtFUgoJLy8gICAgICAgICAgICAgICAgICksIC8vIHNpemUgb2Yga2V5ICsgYWxsIHZhbHVlcwoJLy8gICAgICAgICB9OwoJaW50IDEwNjcKCWNhbGxzdWIgY29zdEZvckJveFN0b3JhZ2UKCWl0b2IKCWludCAxCglpbnQgOAoJaW50IDAKCWR1cG4gMwoJaW50IDEKCWNhbGxzdWIgbWluQmFsYW5jZUZvckFjY291bnQKCWl0b2IKCWNvbmNhdAoJaW50IDEwMDAwMAoJaW50IDEyODA3CgljYWxsc3ViIGNvc3RGb3JCb3hTdG9yYWdlCgkrCglpdG9iCgljb25jYXQKCWludCAxNzkKCWNhbGxzdWIgY29zdEZvckJveFN0b3JhZ2UKCWl0b2IKCWNvbmNhdAoJcmV0c3ViCgovLyBnZXRQcm90b2NvbENvbnN0cmFpbnRzKCkodWludDY0LHVpbnQ2NCx1aW50NjQsdWludDY0LHVpbnQ2NCx1aW50NjQsdWludDY0LHVpbnQ2NCx1aW50NjQsdWludDY0LHVpbnQ2NCkKKmFiaV9yb3V0ZV9nZXRQcm90b2NvbENvbnN0cmFpbnRzOgoJLy8gVGhlIEFCSSByZXR1cm4gcHJlZml4CglieXRlIDB4MTUxZjdjNzUKCgkvLyBleGVjdXRlIGdldFByb3RvY29sQ29uc3RyYWludHMoKSh1aW50NjQsdWludDY0LHVpbnQ2NCx1aW50NjQsdWludDY0LHVpbnQ2NCx1aW50NjQsdWludDY0LHVpbnQ2NCx1aW50NjQsdWludDY0KQoJY2FsbHN1YiBnZXRQcm90b2NvbENvbnN0cmFpbnRzCgljb25jYXQKCWxvZwoJaW50IDEKCXJldHVybgoKLy8gZ2V0UHJvdG9jb2xDb25zdHJhaW50cygpOiBDb25zdHJhaW50cwovLwovLyBSZXR1cm5zIHRoZSBwcm90b2NvbCBjb25zdHJhaW50cyBzbyB0aGF0IFVJcyBjYW4gbGltaXQgd2hhdCB1c2VycyBzcGVjaWZ5IGZvciB2YWxpZGF0b3IgY29uZmlndXJhdGlvbiBwYXJhbWV0ZXJzLgpnZXRQcm90b2NvbENvbnN0cmFpbnRzOgoJcHJvdG8gMCAxCgoJLy8gY29udHJhY3RzL3ZhbGlkYXRvclJlZ2lzdHJ5LmFsZ28udHM6MjQzCgkvLyByZXR1cm4gewoJLy8gICAgICAgICAgICAgZXBvY2hQYXlvdXRNaW5zTWluOiBNSU5fUEFZT1VUX01JTlMsCgkvLyAgICAgICAgICAgICBlcG9jaFBheW91dE1pbnNNYXg6IE1BWF9QQVlPVVRfTUlOUywKCS8vICAgICAgICAgICAgIG1pblBjdFRvVmFsaWRhdG9yV0ZvdXJEZWNpbWFsczogTUlOX1BDVF9UT19WQUxJREFUT1IsCgkvLyAgICAgICAgICAgICBtYXhQY3RUb1ZhbGlkYXRvcldGb3VyRGVjaW1hbHM6IE1BWF9QQ1RfVE9fVkFMSURBVE9SLAoJLy8gICAgICAgICAgICAgbWluRW50cnlTdGFrZTogTUlOX0FMR09fU1RBS0VfUEVSX1BPT0wsCgkvLyAgICAgICAgICAgICBtYXhBbGdvUGVyUG9vbDogdGhpcy5tYXhBbGdvQWxsb3dlZFBlclBvb2woKSwKCS8vICAgICAgICAgICAgIG1heEFsZ29QZXJWYWxpZGF0b3I6IHRoaXMubWF4QWxsb3dlZFN0YWtlKCksCgkvLyAgICAgICAgICAgICBhbXRDb25zaWRlcmVkU2F0dXJhdGVkOiB0aGlzLmFsZ29TYXR1cmF0aW9uTGV2ZWwoKSwKCS8vICAgICAgICAgICAgIG1heE5vZGVzOiBNQVhfTk9ERVMsCgkvLyAgICAgICAgICAgICBtYXhQb29sc1Blck5vZGU6IE1BWF9QT09MU19QRVJfTk9ERSwKCS8vICAgICAgICAgICAgIG1heFN0YWtlcnNQZXJQb29sOiBNQVhfU1RBS0VSU19QRVJfUE9PTCwKCS8vICAgICAgICAgfTsKCWJ5dGUgMHgwMDAwMDAwMDAwMDAwMDAxMDAwMDAwMDAwMDAwMjc2MDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMGY0MjQwMDAwMDAwMDAwMDBmNDI0MAoJY2FsbHN1YiBtYXhBbGdvQWxsb3dlZFBlclBvb2wKCWl0b2IKCWNvbmNhdAoJY2FsbHN1YiBtYXhBbGxvd2VkU3Rha2UKCWl0b2IKCWNvbmNhdAoJY2FsbHN1YiBhbGdvU2F0dXJhdGlvbkxldmVsCglpdG9iCgljb25jYXQKCWJ5dGUgMHgwMDAwMDAwMDAwMDAwMDA4Cgljb25jYXQKCWJ5dGUgMHgwMDAwMDAwMDAwMDAwMDAzCgljb25jYXQKCWJ5dGUgMHgwMDAwMDAwMDAwMDAwMGM4Cgljb25jYXQKCXJldHN1YgoKLy8gZ2V0TnVtVmFsaWRhdG9ycygpdWludDY0CiphYmlfcm91dGVfZ2V0TnVtVmFsaWRhdG9yczoKCS8vIFRoZSBBQkkgcmV0dXJuIHByZWZpeAoJYnl0ZSAweDE1MWY3Yzc1CgoJLy8gZXhlY3V0ZSBnZXROdW1WYWxpZGF0b3JzKCl1aW50NjQKCWNhbGxzdWIgZ2V0TnVtVmFsaWRhdG9ycwoJaXRvYgoJY29uY2F0Cglsb2cKCWludCAxCglyZXR1cm4KCi8vIGdldE51bVZhbGlkYXRvcnMoKTogdWludDY0Ci8vCi8vIFJldHVybnMgdGhlIGN1cnJlbnQgbnVtYmVyIG9mIHZhbGlkYXRvcnMKZ2V0TnVtVmFsaWRhdG9yczoKCXByb3RvIDAgMQoKCS8vIGNvbnRyYWN0cy92YWxpZGF0b3JSZWdpc3RyeS5hbGdvLnRzOjI2MwoJLy8gcmV0dXJuIHRoaXMubnVtVmFsaWRhdG9ycy52YWx1ZTsKCWJ5dGUgMHg2ZTc1NmQ1NiAvLyAibnVtViIKCWFwcF9nbG9iYWxfZ2V0CglyZXRzdWIKCi8vIGdldFZhbGlkYXRvckNvbmZpZyh1aW50NjQpKHVpbnQ2NCxhZGRyZXNzLGFkZHJlc3MsdWludDY0LHVpbnQ4LGJ5dGVbMzJdLHVpbnQ2NCx1aW50NjQsdWludDY0LHVpbnQxNix1aW50MzIsYWRkcmVzcyx1aW50NjQsdWludDY0LHVpbnQ4LHVpbnQ2NCx1aW50NjQpCiphYmlfcm91dGVfZ2V0VmFsaWRhdG9yQ29uZmlnOgoJLy8gVGhlIEFCSSByZXR1cm4gcHJlZml4CglieXRlIDB4MTUxZjdjNzUKCgkvLyB2YWxpZGF0b3JJZDogdWludDY0Cgl0eG5hIEFwcGxpY2F0aW9uQXJncyAxCglidG9pCgoJLy8gZXhlY3V0ZSBnZXRWYWxpZGF0b3JDb25maWcodWludDY0KSh1aW50NjQsYWRkcmVzcyxhZGRyZXNzLHVpbnQ2NCx1aW50OCxieXRlWzMyXSx1aW50NjQsdWludDY0LHVpbnQ2NCx1aW50MTYsdWludDMyLGFkZHJlc3MsdWludDY0LHVpbnQ2NCx1aW50OCx1aW50NjQsdWludDY0KQoJY2FsbHN1YiBnZXRWYWxpZGF0b3JDb25maWcKCWNvbmNhdAoJbG9nCglpbnQgMQoJcmV0dXJuCgovLyBnZXRWYWxpZGF0b3JDb25maWcodmFsaWRhdG9ySWQ6IFZhbGlkYXRvcklkVHlwZSk6IFZhbGlkYXRvckNvbmZpZwpnZXRWYWxpZGF0b3JDb25maWc6Cglwcm90byAxIDEKCgkvLyBjb250cmFjdHMvdmFsaWRhdG9yUmVnaXN0cnkuYWxnby50czoyNjgKCS8vIHJldHVybiB0aGlzLnZhbGlkYXRvckxpc3QodmFsaWRhdG9ySWQpLnZhbHVlLmNvbmZpZzsKCWludCAwCglpbnQgMjA4CglieXRlIDB4NzYgLy8gInYiCglmcmFtZV9kaWcgLTEgLy8gdmFsaWRhdG9ySWQ6IFZhbGlkYXRvcklkVHlwZQoJaXRvYgoJY29uY2F0Cgljb3ZlciAyCglib3hfZXh0cmFjdAoJcmV0c3ViCgovLyBnZXRWYWxpZGF0b3JTdGF0ZSh1aW50NjQpKHVpbnQxNix1aW50NjQsdWludDY0LHVpbnQ2NCkKKmFiaV9yb3V0ZV9nZXRWYWxpZGF0b3JTdGF0ZToKCS8vIFRoZSBBQkkgcmV0dXJuIHByZWZpeAoJYnl0ZSAweDE1MWY3Yzc1CgoJLy8gdmFsaWRhdG9ySWQ6IHVpbnQ2NAoJdHhuYSBBcHBsaWNhdGlvbkFyZ3MgMQoJYnRvaQoKCS8vIGV4ZWN1dGUgZ2V0VmFsaWRhdG9yU3RhdGUodWludDY0KSh1aW50MTYsdWludDY0LHVpbnQ2NCx1aW50NjQpCgljYWxsc3ViIGdldFZhbGlkYXRvclN0YXRlCgljb25jYXQKCWxvZwoJaW50IDEKCXJldHVybgoKLy8gZ2V0VmFsaWRhdG9yU3RhdGUodmFsaWRhdG9ySWQ6IFZhbGlkYXRvcklkVHlwZSk6IFZhbGlkYXRvckN1clN0YXRlCmdldFZhbGlkYXRvclN0YXRlOgoJcHJvdG8gMSAxCgoJLy8gY29udHJhY3RzL3ZhbGlkYXRvclJlZ2lzdHJ5LmFsZ28udHM6MjczCgkvLyByZXR1cm4gdGhpcy52YWxpZGF0b3JMaXN0KHZhbGlkYXRvcklkKS52YWx1ZS5zdGF0ZTsKCWludCAyMDggLy8gaGVhZE9mZnNldAoJaW50IDI2CglieXRlIDB4NzYgLy8gInYiCglmcmFtZV9kaWcgLTEgLy8gdmFsaWRhdG9ySWQ6IFZhbGlkYXRvcklkVHlwZQoJaXRvYgoJY29uY2F0Cgljb3ZlciAyCglib3hfZXh0cmFjdAoJcmV0c3ViCgovLyBnZXRWYWxpZGF0b3JPd25lckFuZE1hbmFnZXIodWludDY0KShhZGRyZXNzLGFkZHJlc3MpCiphYmlfcm91dGVfZ2V0VmFsaWRhdG9yT3duZXJBbmRNYW5hZ2VyOgoJLy8gVGhlIEFCSSByZXR1cm4gcHJlZml4CglieXRlIDB4MTUxZjdjNzUKCgkvLyB2YWxpZGF0b3JJZDogdWludDY0Cgl0eG5hIEFwcGxpY2F0aW9uQXJncyAxCglidG9pCgoJLy8gZXhlY3V0ZSBnZXRWYWxpZGF0b3JPd25lckFuZE1hbmFnZXIodWludDY0KShhZGRyZXNzLGFkZHJlc3MpCgljYWxsc3ViIGdldFZhbGlkYXRvck93bmVyQW5kTWFuYWdlcgoJY29uY2F0Cglsb2cKCWludCAxCglyZXR1cm4KCi8vIGdldFZhbGlkYXRvck93bmVyQW5kTWFuYWdlcih2YWxpZGF0b3JJZDogVmFsaWRhdG9ySWRUeXBlKTogW0FkZHJlc3MsIEFkZHJlc3NdCmdldFZhbGlkYXRvck93bmVyQW5kTWFuYWdlcjoKCXByb3RvIDEgMQoKCS8vIGNvbnRyYWN0cy92YWxpZGF0b3JSZWdpc3RyeS5hbGdvLnRzOjI3OAoJLy8gcmV0dXJuIFsKCS8vICAgICAgICAgICAgIHRoaXMudmFsaWRhdG9yTGlzdCh2YWxpZGF0b3JJZCkudmFsdWUuY29uZmlnLm93bmVyLAoJLy8gICAgICAgICAgICAgdGhpcy52YWxpZGF0b3JMaXN0KHZhbGlkYXRvcklkKS52YWx1ZS5jb25maWcubWFuYWdlciwKCS8vICAgICAgICAgXTsKCWludCA4CglpbnQgMzIKCWJ5dGUgMHg3NiAvLyAidiIKCWZyYW1lX2RpZyAtMSAvLyB2YWxpZGF0b3JJZDogVmFsaWRhdG9ySWRUeXBlCglpdG9iCgljb25jYXQKCWNvdmVyIDIKCWJveF9leHRyYWN0CglpbnQgNDAKCWludCAzMgoJYnl0ZSAweDc2IC8vICJ2IgoJZnJhbWVfZGlnIC0xIC8vIHZhbGlkYXRvcklkOiBWYWxpZGF0b3JJZFR5cGUKCWl0b2IKCWNvbmNhdAoJY292ZXIgMgoJYm94X2V4dHJhY3QKCWNvbmNhdAoJcmV0c3ViCgovLyBnZXRQb29scyh1aW50NjQpKHVpbnQ2NCx1aW50MTYsdWludDY0KVtdCiphYmlfcm91dGVfZ2V0UG9vbHM6CgkvLyBUaGUgQUJJIHJldHVybiBwcmVmaXgKCWJ5dGUgMHgxNTFmN2M3NQoKCS8vIHZhbGlkYXRvcklkOiB1aW50NjQKCXR4bmEgQXBwbGljYXRpb25BcmdzIDEKCWJ0b2kKCgkvLyBleGVjdXRlIGdldFBvb2xzKHVpbnQ2NCkodWludDY0LHVpbnQxNix1aW50NjQpW10KCWNhbGxzdWIgZ2V0UG9vbHMKCWR1cAoJbGVuCglpbnQgMTgKCS8KCWl0b2IKCWV4dHJhY3QgNiAyCglzd2FwCgljb25jYXQKCWNvbmNhdAoJbG9nCglpbnQgMQoJcmV0dXJuCgovLyBnZXRQb29scyh2YWxpZGF0b3JJZDogVmFsaWRhdG9ySWRUeXBlKTogUG9vbEluZm9bXQovLwovLyBSZXR1cm4gbGlzdCBvZiBhbGwgcG9vbHMgZm9yIHRoaXMgdmFsaWRhdG9yLgovLyBAcGFyYW0ge3VpbnQ2NH0gdmFsaWRhdG9ySWQKLy8gQHJldHVybiB7UG9vbEluZm9bXX0gLSBhcnJheSBvZiBwb29scwovLyBOb3QgY2FsbGFibGUgZnJvbSBvdGhlciBjb250cmFjdHMgYmVjYXVzZSA+MUsgcmV0dXJuIGJ1dCBjYW4gYmUgY2FsbGVkIHcvIHNpbXVsYXRlIHdoaWNoIGJ1bXBzIGxvZyByZXR1cm5zCmdldFBvb2xzOgoJcHJvdG8gMSAxCgoJLy8gUHVzaCBlbXB0eSBieXRlcyBhZnRlciB0aGUgZnJhbWUgcG9pbnRlciB0byByZXNlcnZlIHNwYWNlIGZvciBsb2NhbCB2YXJpYWJsZXMKCWJ5dGUgMHgKCWR1cG4gMgoKCS8vIGNvbnRyYWN0cy92YWxpZGF0b3JSZWdpc3RyeS5hbGdvLnRzOjI5MgoJLy8gcmV0RGF0YTogUG9vbEluZm9bXSA9IFtdCglieXRlIDB4CglmcmFtZV9idXJ5IDAgLy8gcmV0RGF0YTogUG9vbEluZm9bXQoKCS8vIGNvbnRyYWN0cy92YWxpZGF0b3JSZWdpc3RyeS5hbGdvLnRzOjI5MwoJLy8gcG9vbFNldCA9IGNsb25lKHRoaXMudmFsaWRhdG9yTGlzdCh2YWxpZGF0b3JJZCkudmFsdWUucG9vbHMpCglpbnQgMjM0IC8vIGhlYWRPZmZzZXQKCWludCA0MzIKCWJ5dGUgMHg3NiAvLyAidiIKCWZyYW1lX2RpZyAtMSAvLyB2YWxpZGF0b3JJZDogVmFsaWRhdG9ySWRUeXBlCglpdG9iCgljb25jYXQKCWNvdmVyIDIKCWJveF9leHRyYWN0CglmcmFtZV9idXJ5IDEgLy8gcG9vbFNldDogKHVpbnQ2NCx1aW50MTYsdWludDY0KVsyNF0KCgkvLyBjb250cmFjdHMvdmFsaWRhdG9yUmVnaXN0cnkuYWxnby50czoyOTQKCS8vIGZvciAobGV0IGkgPSAwOyBpIDwgcG9vbFNldC5sZW5ndGg7IGkgKz0gMSkKCWludCAwCglmcmFtZV9idXJ5IDIgLy8gaTogdWludDY0CgoqZm9yXzA6CgkvLyBjb250cmFjdHMvdmFsaWRhdG9yUmVnaXN0cnkuYWxnby50czoyOTQKCS8vIGkgPCBwb29sU2V0Lmxlbmd0aAoJZnJhbWVfZGlnIDIgLy8gaTogdWludDY0CglpbnQgMjQKCTwKCWJ6ICpmb3JfMF9lbmQKCgkvLyAqaWYwX2NvbmRpdGlvbgoJLy8gY29udHJhY3RzL3ZhbGlkYXRvclJlZ2lzdHJ5LmFsZ28udHM6Mjk1CgkvLyBwb29sU2V0W2ldLnBvb2xBcHBJZCA9PT0gMAoJZnJhbWVfZGlnIDEgLy8gcG9vbFNldDogKHVpbnQ2NCx1aW50MTYsdWludDY0KVsyNF0KCWZyYW1lX2RpZyAyIC8vIGk6IHVpbnQ2NAoJaW50IDE4CgkqIC8vIGFjYyAqIHR5cGVMZW5ndGgKCWludCAwCgkrCglpbnQgOAoJZXh0cmFjdDMKCWJ0b2kKCWludCAwCgk9PQoJYnogKmlmMF9lbmQKCgkvLyAqaWYwX2NvbnNlcXVlbnQKCWIgKmZvcl8wX2VuZAoKKmlmMF9lbmQ6CgkvLyBjb250cmFjdHMvdmFsaWRhdG9yUmVnaXN0cnkuYWxnby50czoyOTkKCS8vIHJldERhdGEucHVzaChwb29sU2V0W2ldKQoJZnJhbWVfZGlnIDAgLy8gcmV0RGF0YTogUG9vbEluZm9bXQoJZnJhbWVfZGlnIDEgLy8gcG9vbFNldDogKHVpbnQ2NCx1aW50MTYsdWludDY0KVsyNF0KCWZyYW1lX2RpZyAyIC8vIGk6IHVpbnQ2NAoJaW50IDE4CgkqIC8vIGFjYyAqIHR5cGVMZW5ndGgKCWludCAxOAoJZXh0cmFjdDMKCWNvbmNhdAoJZnJhbWVfYnVyeSAwIC8vIHJldERhdGE6IFBvb2xJbmZvW10KCipmb3JfMF9jb250aW51ZToKCS8vIGNvbnRyYWN0cy92YWxpZGF0b3JSZWdpc3RyeS5hbGdvLnRzOjI5NAoJLy8gaSArPSAxCglmcmFtZV9kaWcgMiAvLyBpOiB1aW50NjQKCWludCAxCgkrCglmcmFtZV9idXJ5IDIgLy8gaTogdWludDY0CgliICpmb3JfMAoKKmZvcl8wX2VuZDoKCS8vIGNvbnRyYWN0cy92YWxpZGF0b3JSZWdpc3RyeS5hbGdvLnRzOjMwMQoJLy8gcmV0dXJuIHJldERhdGE7CglmcmFtZV9kaWcgMCAvLyByZXREYXRhOiBQb29sSW5mb1tdCgoJLy8gc2V0IHRoZSBzdWJyb3V0aW5lIHJldHVybiB2YWx1ZQoJZnJhbWVfYnVyeSAwCgoJLy8gcG9wIGFsbCBsb2NhbCB2YXJpYWJsZXMgZnJvbSB0aGUgc3RhY2sKCXBvcG4gMgoJcmV0c3ViCgovLyBnZXRQb29sQXBwSWQodWludDY0LHVpbnQ2NCl1aW50NjQKKmFiaV9yb3V0ZV9nZXRQb29sQXBwSWQ6CgkvLyBUaGUgQUJJIHJldHVybiBwcmVmaXgKCWJ5dGUgMHgxNTFmN2M3NQoKCS8vIHBvb2xJZDogdWludDY0Cgl0eG5hIEFwcGxpY2F0aW9uQXJncyAyCglidG9pCgoJLy8gdmFsaWRhdG9ySWQ6IHVpbnQ2NAoJdHhuYSBBcHBsaWNhdGlvbkFyZ3MgMQoJYnRvaQoKCS8vIGV4ZWN1dGUgZ2V0UG9vbEFwcElkKHVpbnQ2NCx1aW50NjQpdWludDY0CgljYWxsc3ViIGdldFBvb2xBcHBJZAoJaXRvYgoJY29uY2F0Cglsb2cKCWludCAxCglyZXR1cm4KCi8vIGdldFBvb2xBcHBJZCh2YWxpZGF0b3JJZDogdWludDY0LCBwb29sSWQ6IHVpbnQ2NCk6IHVpbnQ2NApnZXRQb29sQXBwSWQ6Cglwcm90byAyIDEKCgkvLyBjb250cmFjdHMvdmFsaWRhdG9yUmVnaXN0cnkuYWxnby50czozMDkKCS8vIGFzc2VydChwb29sSWQgIT09IDAgJiYgcG9vbElkIDw9IHRoaXMudmFsaWRhdG9yTGlzdCh2YWxpZGF0b3JJZCkudmFsdWUucG9vbHMubGVuZ3RoKQoJZnJhbWVfZGlnIC0yIC8vIHBvb2xJZDogdWludDY0CglpbnQgMAoJIT0KCWR1cAoJYnogKnNraXBfYW5kMAoJZnJhbWVfZGlnIC0yIC8vIHBvb2xJZDogdWludDY0CglpbnQgMjQKCTw9CgkmJgoKKnNraXBfYW5kMDoKCWFzc2VydAoKCS8vIGNvbnRyYWN0cy92YWxpZGF0b3JSZWdpc3RyeS5hbGdvLnRzOjMxMAoJLy8gcmV0dXJuIHRoaXMudmFsaWRhdG9yTGlzdCh2YWxpZGF0b3JJZCkudmFsdWUucG9vbHNbcG9vbElkIC0gMV0ucG9vbEFwcElkOwoJaW50IDIzNCAvLyBoZWFkT2Zmc2V0CglmcmFtZV9kaWcgLTIgLy8gcG9vbElkOiB1aW50NjQKCWludCAxCgktCglpbnQgMTgKCSogLy8gYWNjICogdHlwZUxlbmd0aAoJKwoJaW50IDAKCSsKCWludCA4CglieXRlIDB4NzYgLy8gInYiCglmcmFtZV9kaWcgLTEgLy8gdmFsaWRhdG9ySWQ6IHVpbnQ2NAoJaXRvYgoJY29uY2F0Cgljb3ZlciAyCglib3hfZXh0cmFjdAoJYnRvaQoJcmV0c3ViCgovLyBnZXRQb29sSW5mbygodWludDY0LHVpbnQ2NCx1aW50NjQpKSh1aW50NjQsdWludDE2LHVpbnQ2NCkKKmFiaV9yb3V0ZV9nZXRQb29sSW5mbzoKCS8vIFRoZSBBQkkgcmV0dXJuIHByZWZpeAoJYnl0ZSAweDE1MWY3Yzc1CgoJLy8gcG9vbEtleTogKHVpbnQ2NCx1aW50NjQsdWludDY0KQoJdHhuYSBBcHBsaWNhdGlvbkFyZ3MgMQoJZHVwCglsZW4KCWludCAyNAoJPT0KCWFzc2VydAoKCS8vIGV4ZWN1dGUgZ2V0UG9vbEluZm8oKHVpbnQ2NCx1aW50NjQsdWludDY0KSkodWludDY0LHVpbnQxNix1aW50NjQpCgljYWxsc3ViIGdldFBvb2xJbmZvCgljb25jYXQKCWxvZwoJaW50IDEKCXJldHVybgoKLy8gZ2V0UG9vbEluZm8ocG9vbEtleTogVmFsaWRhdG9yUG9vbEtleSk6IFBvb2xJbmZvCmdldFBvb2xJbmZvOgoJcHJvdG8gMSAxCgoJLy8gY29udHJhY3RzL3ZhbGlkYXRvclJlZ2lzdHJ5LmFsZ28udHM6MzE1CgkvLyByZXR1cm4gdGhpcy52YWxpZGF0b3JMaXN0KHBvb2xLZXkuaWQpLnZhbHVlLnBvb2xzW3Bvb2xLZXkucG9vbElkIC0gMV07CglpbnQgMjM0IC8vIGhlYWRPZmZzZXQKCWZyYW1lX2RpZyAtMSAvLyBwb29sS2V5OiBWYWxpZGF0b3JQb29sS2V5CglleHRyYWN0IDggOAoJYnRvaQoJaW50IDEKCS0KCWludCAxOAoJKiAvLyBhY2MgKiB0eXBlTGVuZ3RoCgkrCglpbnQgMTgKCWJ5dGUgMHg3NiAvLyAidiIKCWZyYW1lX2RpZyAtMSAvLyBwb29sS2V5OiBWYWxpZGF0b3JQb29sS2V5CglleHRyYWN0IDAgOAoJYnRvaQoJaXRvYgoJY29uY2F0Cgljb3ZlciAyCglib3hfZXh0cmFjdAoJcmV0c3ViCgovLyBnZXRDdXJNYXhTdGFrZVBlclBvb2wodWludDY0KXVpbnQ2NAoqYWJpX3JvdXRlX2dldEN1ck1heFN0YWtlUGVyUG9vbDoKCS8vIFRoZSBBQkkgcmV0dXJuIHByZWZpeAoJYnl0ZSAweDE1MWY3Yzc1CgoJLy8gdmFsaWRhdG9ySWQ6IHVpbnQ2NAoJdHhuYSBBcHBsaWNhdGlvbkFyZ3MgMQoJYnRvaQoKCS8vIGV4ZWN1dGUgZ2V0Q3VyTWF4U3Rha2VQZXJQb29sKHVpbnQ2NCl1aW50NjQKCWNhbGxzdWIgZ2V0Q3VyTWF4U3Rha2VQZXJQb29sCglpdG9iCgljb25jYXQKCWxvZwoJaW50IDEKCXJldHVybgoKLy8gZ2V0Q3VyTWF4U3Rha2VQZXJQb29sKHZhbGlkYXRvcklkOiBWYWxpZGF0b3JJZFR5cGUpOiB1aW50NjQKLy8KLy8gQ2FsY3VsYXRlIHRoZSBtYXhpbXVtIHN0YWtlIHBlciBwb29sIGZvciBhIGdpdmVuIHZhbGlkYXRvci4KLy8gTm9ybWFsbHkgdGhpcyB3b3VsZCBiZSBtYXhBbGdvUGVyUG9vbCwgYnV0IGl0IHNob3VsZCBhbHNvIG5ldmVyIGdvIGFib3ZlIE1heEFsbG93ZWRTdGFrZSAvIG51bVBvb2xzIHNvCi8vIGFzIHBvb2xzIGFyZSBhZGRlZCB0aGUgbWF4IGFsbG93ZWQgcGVyIHBvb2wgY2FuIHJlZHVjZS4KLy8KLy8gQHBhcmFtIHtWYWxpZGF0b3JJZFR5cGV9IHZhbGlkYXRvcklkIC0gVGhlIGlkIG9mIHRoZSB2YWxpZGF0b3IuCmdldEN1ck1heFN0YWtlUGVyUG9vbDoKCXByb3RvIDEgMQoKCS8vIFB1c2ggZW1wdHkgYnl0ZXMgYWZ0ZXIgdGhlIGZyYW1lIHBvaW50ZXIgdG8gcmVzZXJ2ZSBzcGFjZSBmb3IgbG9jYWwgdmFyaWFibGVzCglieXRlIDB4CglkdXBuIDIKCgkvLyBjb250cmFjdHMvdmFsaWRhdG9yUmVnaXN0cnkuYWxnby50czozMjYKCS8vIG51bVBvb2xzID0gdGhpcy52YWxpZGF0b3JMaXN0KHZhbGlkYXRvcklkKS52YWx1ZS5zdGF0ZS5udW1Qb29scyBhcyB1aW50NjQKCWludCAyMDgKCWludCAyCglieXRlIDB4NzYgLy8gInYiCglmcmFtZV9kaWcgLTEgLy8gdmFsaWRhdG9ySWQ6IFZhbGlkYXRvcklkVHlwZQoJaXRvYgoJY29uY2F0Cgljb3ZlciAyCglib3hfZXh0cmFjdAoJYnRvaQoJZnJhbWVfYnVyeSAwIC8vIG51bVBvb2xzOiB1aW50NjQKCgkvLyBjb250cmFjdHMvdmFsaWRhdG9yUmVnaXN0cnkuYWxnby50czozMjcKCS8vIGhhcmRNYXhEaXZpZGVkQmV0d2VlblBvb2xzID0gdGhpcy5tYXhBbGxvd2VkU3Rha2UoKSAvIG51bVBvb2xzCgljYWxsc3ViIG1heEFsbG93ZWRTdGFrZQoJZnJhbWVfZGlnIDAgLy8gbnVtUG9vbHM6IHVpbnQ2NAoJLwoJZnJhbWVfYnVyeSAxIC8vIGhhcmRNYXhEaXZpZGVkQmV0d2VlblBvb2xzOiB1aW50NjQKCgkvLyBjb250cmFjdHMvdmFsaWRhdG9yUmVnaXN0cnkuYWxnby50czozMjgKCS8vIG1heFBlclBvb2w6IHVpbnQ2NCA9IHRoaXMudmFsaWRhdG9yTGlzdCh2YWxpZGF0b3JJZCkudmFsdWUuY29uZmlnLm1heEFsZ29QZXJQb29sCglpbnQgMTgzCglpbnQgOAoJYnl0ZSAweDc2IC8vICJ2IgoJZnJhbWVfZGlnIC0xIC8vIHZhbGlkYXRvcklkOiBWYWxpZGF0b3JJZFR5cGUKCWl0b2IKCWNvbmNhdAoJY292ZXIgMgoJYm94X2V4dHJhY3QKCWJ0b2kKCWZyYW1lX2J1cnkgMiAvLyBtYXhQZXJQb29sOiB1aW50NjQKCgkvLyAqaWYxX2NvbmRpdGlvbgoJLy8gY29udHJhY3RzL3ZhbGlkYXRvclJlZ2lzdHJ5LmFsZ28udHM6MzI5CgkvLyBtYXhQZXJQb29sID09PSAwCglmcmFtZV9kaWcgMiAvLyBtYXhQZXJQb29sOiB1aW50NjQKCWludCAwCgk9PQoJYnogKmlmMV9lbmQKCgkvLyAqaWYxX2NvbnNlcXVlbnQKCS8vIGNvbnRyYWN0cy92YWxpZGF0b3JSZWdpc3RyeS5hbGdvLnRzOjMzMAoJLy8gbWF4UGVyUG9vbCA9IHRoaXMubWF4QWxnb0FsbG93ZWRQZXJQb29sKCkKCWNhbGxzdWIgbWF4QWxnb0FsbG93ZWRQZXJQb29sCglmcmFtZV9idXJ5IDIgLy8gbWF4UGVyUG9vbDogdWludDY0CgoqaWYxX2VuZDoKCS8vICppZjJfY29uZGl0aW9uCgkvLyBjb250cmFjdHMvdmFsaWRhdG9yUmVnaXN0cnkuYWxnby50czozMzIKCS8vIGhhcmRNYXhEaXZpZGVkQmV0d2VlblBvb2xzIDwgbWF4UGVyUG9vbAoJZnJhbWVfZGlnIDEgLy8gaGFyZE1heERpdmlkZWRCZXR3ZWVuUG9vbHM6IHVpbnQ2NAoJZnJhbWVfZGlnIDIgLy8gbWF4UGVyUG9vbDogdWludDY0Cgk8CglieiAqaWYyX2VuZAoKCS8vICppZjJfY29uc2VxdWVudAoJLy8gY29udHJhY3RzL3ZhbGlkYXRvclJlZ2lzdHJ5LmFsZ28udHM6MzMzCgkvLyBtYXhQZXJQb29sID0gaGFyZE1heERpdmlkZWRCZXR3ZWVuUG9vbHMKCWZyYW1lX2RpZyAxIC8vIGhhcmRNYXhEaXZpZGVkQmV0d2VlblBvb2xzOiB1aW50NjQKCWZyYW1lX2J1cnkgMiAvLyBtYXhQZXJQb29sOiB1aW50NjQKCippZjJfZW5kOgoJLy8gY29udHJhY3RzL3ZhbGlkYXRvclJlZ2lzdHJ5LmFsZ28udHM6MzM1CgkvLyByZXR1cm4gbWF4UGVyUG9vbDsKCWZyYW1lX2RpZyAyIC8vIG1heFBlclBvb2w6IHVpbnQ2NAoKCS8vIHNldCB0aGUgc3Vicm91dGluZSByZXR1cm4gdmFsdWUKCWZyYW1lX2J1cnkgMAoKCS8vIHBvcCBhbGwgbG9jYWwgdmFyaWFibGVzIGZyb20gdGhlIHN0YWNrCglwb3BuIDIKCXJldHN1YgoKLy8gZG9lc1N0YWtlck5lZWRUb1BheU1CUihhZGRyZXNzKWJvb2wKKmFiaV9yb3V0ZV9kb2VzU3Rha2VyTmVlZFRvUGF5TUJSOgoJLy8gVGhlIEFCSSByZXR1cm4gcHJlZml4CglieXRlIDB4MTUxZjdjNzUKCgkvLyBzdGFrZXI6IGFkZHJlc3MKCXR4bmEgQXBwbGljYXRpb25BcmdzIDEKCWR1cAoJbGVuCglpbnQgMzIKCT09Cglhc3NlcnQKCgkvLyBleGVjdXRlIGRvZXNTdGFrZXJOZWVkVG9QYXlNQlIoYWRkcmVzcylib29sCgljYWxsc3ViIGRvZXNTdGFrZXJOZWVkVG9QYXlNQlIKCWJ5dGUgMHgwMAoJaW50IDAKCXVuY292ZXIgMgoJc2V0Yml0Cgljb25jYXQKCWxvZwoJaW50IDEKCXJldHVybgoKLy8gZG9lc1N0YWtlck5lZWRUb1BheU1CUihzdGFrZXI6IEFkZHJlc3MpOiBib29sZWFuCi8vCi8vIEhlbHBlciBjYWxsZXJzIGNhbiBjYWxsIHcvIHNpbXVsYXRlIHRvIGRldGVybWluZSBpZiAnQWRkU3Rha2VyJyBNQlIgc2hvdWxkIGJlIGluY2x1ZGVkIHcvIHN0YWtpbmcgYW1vdW50Ci8vIEBwYXJhbSBzdGFrZXIKZG9lc1N0YWtlck5lZWRUb1BheU1CUjoKCXByb3RvIDEgMQoKCS8vIGNvbnRyYWN0cy92YWxpZGF0b3JSZWdpc3RyeS5hbGdvLnRzOjM0NAoJLy8gcmV0dXJuICF0aGlzLnN0YWtlclBvb2xTZXQoc3Rha2VyKS5leGlzdHM7CglieXRlIDB4NzM3MDczIC8vICJzcHMiCglmcmFtZV9kaWcgLTEgLy8gc3Rha2VyOiBBZGRyZXNzCgljb25jYXQKCWJveF9sZW4KCXN3YXAKCXBvcAoJIQoJcmV0c3ViCgovLyBnZXRTdGFrZWRQb29sc0ZvckFjY291bnQoYWRkcmVzcykodWludDY0LHVpbnQ2NCx1aW50NjQpW10KKmFiaV9yb3V0ZV9nZXRTdGFrZWRQb29sc0ZvckFjY291bnQ6CgkvLyBUaGUgQUJJIHJldHVybiBwcmVmaXgKCWJ5dGUgMHgxNTFmN2M3NQoKCS8vIHN0YWtlcjogYWRkcmVzcwoJdHhuYSBBcHBsaWNhdGlvbkFyZ3MgMQoJZHVwCglsZW4KCWludCAzMgoJPT0KCWFzc2VydAoKCS8vIGV4ZWN1dGUgZ2V0U3Rha2VkUG9vbHNGb3JBY2NvdW50KGFkZHJlc3MpKHVpbnQ2NCx1aW50NjQsdWludDY0KVtdCgljYWxsc3ViIGdldFN0YWtlZFBvb2xzRm9yQWNjb3VudAoJZHVwCglsZW4KCWludCAyNAoJLwoJaXRvYgoJZXh0cmFjdCA2IDIKCXN3YXAKCWNvbmNhdAoJY29uY2F0Cglsb2cKCWludCAxCglyZXR1cm4KCi8vIGdldFN0YWtlZFBvb2xzRm9yQWNjb3VudChzdGFrZXI6IEFkZHJlc3MpOiBWYWxpZGF0b3JQb29sS2V5W10KLy8KLy8gUmV0cmlldmVzIHRoZSBzdGFrZWQgcG9vbHMgZm9yIGFuIGFjY291bnQuCi8vCi8vIEBwYXJhbSB7QWRkcmVzc30gc3Rha2VyIC0gVGhlIGFjY291bnQgdG8gcmV0cmlldmUgc3Rha2VkIHBvb2xzIGZvci4KLy8gQHJldHVybiB7VmFsaWRhdG9yUG9vbEtleVtdfSAtIFRoZSBhcnJheSBvZiBzdGFrZWQgcG9vbHMgZm9yIHRoZSBhY2NvdW50LgpnZXRTdGFrZWRQb29sc0ZvckFjY291bnQ6Cglwcm90byAxIDEKCgkvLyBQdXNoIGVtcHR5IGJ5dGVzIGFmdGVyIHRoZSBmcmFtZSBwb2ludGVyIHRvIHJlc2VydmUgc3BhY2UgZm9yIGxvY2FsIHZhcmlhYmxlcwoJYnl0ZSAweAoJZHVwbiAyCgoJLy8gKmlmM19jb25kaXRpb24KCS8vIGNvbnRyYWN0cy92YWxpZGF0b3JSZWdpc3RyeS5hbGdvLnRzOjM1NAoJLy8gIXRoaXMuc3Rha2VyUG9vbFNldChzdGFrZXIpLmV4aXN0cwoJYnl0ZSAweDczNzA3MyAvLyAic3BzIgoJZnJhbWVfZGlnIC0xIC8vIHN0YWtlcjogQWRkcmVzcwoJY29uY2F0Cglib3hfbGVuCglzd2FwCglwb3AKCSEKCWJ6ICppZjNfZW5kCgoJLy8gKmlmM19jb25zZXF1ZW50CgkvLyBjb250cmFjdHMvdmFsaWRhdG9yUmVnaXN0cnkuYWxnby50czozNTUKCS8vIHJldHVybiBbXTsKCWJ5dGUgMHgKCXJldHN1YgoKKmlmM19lbmQ6CgkvLyBjb250cmFjdHMvdmFsaWRhdG9yUmVnaXN0cnkuYWxnby50czozNTcKCS8vIHJldERhdGE6IFZhbGlkYXRvclBvb2xLZXlbXSA9IFtdCglieXRlIDB4CglmcmFtZV9idXJ5IDAgLy8gcmV0RGF0YTogVmFsaWRhdG9yUG9vbEtleVtdCgoJLy8gY29udHJhY3RzL3ZhbGlkYXRvclJlZ2lzdHJ5LmFsZ28udHM6MzU4CgkvLyBwb29sU2V0ID0gY2xvbmUodGhpcy5zdGFrZXJQb29sU2V0KHN0YWtlcikudmFsdWUpCglieXRlIDB4NzM3MDczIC8vICJzcHMiCglmcmFtZV9kaWcgLTEgLy8gc3Rha2VyOiBBZGRyZXNzCgljb25jYXQKCWJveF9nZXQKCWFzc2VydAoJZnJhbWVfYnVyeSAxIC8vIHBvb2xTZXQ6ICh1aW50NjQsdWludDY0LHVpbnQ2NClbNl0KCgkvLyBjb250cmFjdHMvdmFsaWRhdG9yUmVnaXN0cnkuYWxnby50czozNTkKCS8vIGZvciAobGV0IGkgPSAwOyBpIDwgcG9vbFNldC5sZW5ndGg7IGkgKz0gMSkKCWludCAwCglmcmFtZV9idXJ5IDIgLy8gaTogdWludDY0CgoqZm9yXzE6CgkvLyBjb250cmFjdHMvdmFsaWRhdG9yUmVnaXN0cnkuYWxnby50czozNTkKCS8vIGkgPCBwb29sU2V0Lmxlbmd0aAoJZnJhbWVfZGlnIDIgLy8gaTogdWludDY0CglpbnQgNgoJPAoJYnogKmZvcl8xX2VuZAoKCS8vICppZjRfY29uZGl0aW9uCgkvLyBjb250cmFjdHMvdmFsaWRhdG9yUmVnaXN0cnkuYWxnby50czozNjAKCS8vIHBvb2xTZXRbaV0uaWQgIT09IDAKCWZyYW1lX2RpZyAxIC8vIHBvb2xTZXQ6ICh1aW50NjQsdWludDY0LHVpbnQ2NClbNl0KCWZyYW1lX2RpZyAyIC8vIGk6IHVpbnQ2NAoJaW50IDI0CgkqIC8vIGFjYyAqIHR5cGVMZW5ndGgKCWludCAwCgkrCglpbnQgOAoJZXh0cmFjdDMKCWJ0b2kKCWludCAwCgkhPQoJYnogKmlmNF9lbmQKCgkvLyAqaWY0X2NvbnNlcXVlbnQKCS8vIGNvbnRyYWN0cy92YWxpZGF0b3JSZWdpc3RyeS5hbGdvLnRzOjM2MQoJLy8gcmV0RGF0YS5wdXNoKHBvb2xTZXRbaV0pCglmcmFtZV9kaWcgMCAvLyByZXREYXRhOiBWYWxpZGF0b3JQb29sS2V5W10KCWZyYW1lX2RpZyAxIC8vIHBvb2xTZXQ6ICh1aW50NjQsdWludDY0LHVpbnQ2NClbNl0KCWZyYW1lX2RpZyAyIC8vIGk6IHVpbnQ2NAoJaW50IDI0CgkqIC8vIGFjYyAqIHR5cGVMZW5ndGgKCWludCAyNAoJZXh0cmFjdDMKCWNvbmNhdAoJZnJhbWVfYnVyeSAwIC8vIHJldERhdGE6IFZhbGlkYXRvclBvb2xLZXlbXQoKKmlmNF9lbmQ6CgoqZm9yXzFfY29udGludWU6CgkvLyBjb250cmFjdHMvdmFsaWRhdG9yUmVnaXN0cnkuYWxnby50czozNTkKCS8vIGkgKz0gMQoJZnJhbWVfZGlnIDIgLy8gaTogdWludDY0CglpbnQgMQoJKwoJZnJhbWVfYnVyeSAyIC8vIGk6IHVpbnQ2NAoJYiAqZm9yXzEKCipmb3JfMV9lbmQ6CgkvLyBjb250cmFjdHMvdmFsaWRhdG9yUmVnaXN0cnkuYWxnby50czozNjQKCS8vIHJldHVybiByZXREYXRhOwoJZnJhbWVfZGlnIDAgLy8gcmV0RGF0YTogVmFsaWRhdG9yUG9vbEtleVtdCgoJLy8gc2V0IHRoZSBzdWJyb3V0aW5lIHJldHVybiB2YWx1ZQoJZnJhbWVfYnVyeSAwCgoJLy8gcG9wIGFsbCBsb2NhbCB2YXJpYWJsZXMgZnJvbSB0aGUgc3RhY2sKCXBvcG4gMgoJcmV0c3ViCgovLyBnZXRUb2tlblBheW91dFJhdGlvKHVpbnQ2NCkodWludDY0WzI0XSx1aW50NjQpCiphYmlfcm91dGVfZ2V0VG9rZW5QYXlvdXRSYXRpbzoKCS8vIFRoZSBBQkkgcmV0dXJuIHByZWZpeAoJYnl0ZSAweDE1MWY3Yzc1CgoJLy8gdmFsaWRhdG9ySWQ6IHVpbnQ2NAoJdHhuYSBBcHBsaWNhdGlvbkFyZ3MgMQoJYnRvaQoKCS8vIGV4ZWN1dGUgZ2V0VG9rZW5QYXlvdXRSYXRpbyh1aW50NjQpKHVpbnQ2NFsyNF0sdWludDY0KQoJY2FsbHN1YiBnZXRUb2tlblBheW91dFJhdGlvCgljb25jYXQKCWxvZwoJaW50IDEKCXJldHVybgoKLy8gZ2V0VG9rZW5QYXlvdXRSYXRpbyh2YWxpZGF0b3JJZDogVmFsaWRhdG9ySWRUeXBlKTogUG9vbFRva2VuUGF5b3V0UmF0aW8KLy8KLy8gUmV0cmlldmVzIHRoZSB0b2tlbiBwYXlvdXQgcmF0aW8gZm9yIGEgZ2l2ZW4gdmFsaWRhdG9yIC0gcmV0dXJuaW5nIHRoZSBwb29sIHJhdGlvcyBvZiB3aG9sZSBzbyB0aGF0IHRva2VuCi8vIHBheW91dHMgYWNyb3NzIHBvb2xzIGNhbiBiZSBiYXNlZCBvbiBhIHN0YWJsZSBzbmFwaG9zdCBvZiBzdGFrZS4KLy8KLy8gQHBhcmFtIHtWYWxpZGF0b3JJZFR5cGV9IHZhbGlkYXRvcklkIC0gVGhlIGlkIG9mIHRoZSB2YWxpZGF0b3IuCi8vIEByZXR1cm4ge1Bvb2xUb2tlblBheW91dFJhdGlvfSAtIFRoZSB0b2tlbiBwYXlvdXQgcmF0aW8gZm9yIHRoZSB2YWxpZGF0b3IuCmdldFRva2VuUGF5b3V0UmF0aW86Cglwcm90byAxIDEKCgkvLyBjb250cmFjdHMvdmFsaWRhdG9yUmVnaXN0cnkuYWxnby50czozNzYKCS8vIHJldHVybiB0aGlzLnZhbGlkYXRvckxpc3QodmFsaWRhdG9ySWQpLnZhbHVlLnRva2VuUGF5b3V0UmF0aW87CglpbnQgNjY2IC8vIGhlYWRPZmZzZXQKCWludCAyMDAKCWJ5dGUgMHg3NiAvLyAidiIKCWZyYW1lX2RpZyAtMSAvLyB2YWxpZGF0b3JJZDogVmFsaWRhdG9ySWRUeXBlCglpdG9iCgljb25jYXQKCWNvdmVyIDIKCWJveF9leHRyYWN0CglyZXRzdWIKCi8vIGdldE5vZGVQb29sQXNzaWdubWVudHModWludDY0KSgodWludDY0WzNdKVs4XSkKKmFiaV9yb3V0ZV9nZXROb2RlUG9vbEFzc2lnbm1lbnRzOgoJLy8gVGhlIEFCSSByZXR1cm4gcHJlZml4CglieXRlIDB4MTUxZjdjNzUKCgkvLyB2YWxpZGF0b3JJZDogdWludDY0Cgl0eG5hIEFwcGxpY2F0aW9uQXJncyAxCglidG9pCgoJLy8gZXhlY3V0ZSBnZXROb2RlUG9vbEFzc2lnbm1lbnRzKHVpbnQ2NCkoKHVpbnQ2NFszXSlbOF0pCgljYWxsc3ViIGdldE5vZGVQb29sQXNzaWdubWVudHMKCWNvbmNhdAoJbG9nCglpbnQgMQoJcmV0dXJuCgovLyBnZXROb2RlUG9vbEFzc2lnbm1lbnRzKHZhbGlkYXRvcklkOiB1aW50NjQpOiBOb2RlUG9vbEFzc2lnbm1lbnRDb25maWcKZ2V0Tm9kZVBvb2xBc3NpZ25tZW50czoKCXByb3RvIDEgMQoKCS8vIGNvbnRyYWN0cy92YWxpZGF0b3JSZWdpc3RyeS5hbGdvLnRzOjM4MQoJLy8gYXNzZXJ0KHRoaXMudmFsaWRhdG9yTGlzdCh2YWxpZGF0b3JJZCkuZXhpc3RzKQoJYnl0ZSAweDc2IC8vICJ2IgoJZnJhbWVfZGlnIC0xIC8vIHZhbGlkYXRvcklkOiB1aW50NjQKCWl0b2IKCWNvbmNhdAoJYm94X2xlbgoJc3dhcAoJcG9wCglhc3NlcnQKCgkvLyBjb250cmFjdHMvdmFsaWRhdG9yUmVnaXN0cnkuYWxnby50czozODMKCS8vIHJldHVybiB0aGlzLnZhbGlkYXRvckxpc3QodmFsaWRhdG9ySWQpLnZhbHVlLm5vZGVQb29sQXNzaWdubWVudHM7CglpbnQgODY2IC8vIGhlYWRPZmZzZXQKCWludCAxOTIKCWJ5dGUgMHg3NiAvLyAidiIKCWZyYW1lX2RpZyAtMSAvLyB2YWxpZGF0b3JJZDogdWludDY0CglpdG9iCgljb25jYXQKCWNvdmVyIDIKCWJveF9leHRyYWN0CglyZXRzdWIKCi8vIGdldE5GRFJlZ2lzdHJ5SUQoKXVpbnQ2NAoqYWJpX3JvdXRlX2dldE5GRFJlZ2lzdHJ5SUQ6CgkvLyBUaGUgQUJJIHJldHVybiBwcmVmaXgKCWJ5dGUgMHgxNTFmN2M3NQoKCS8vIGV4ZWN1dGUgZ2V0TkZEUmVnaXN0cnlJRCgpdWludDY0CgljYWxsc3ViIGdldE5GRFJlZ2lzdHJ5SUQKCWl0b2IKCWNvbmNhdAoJbG9nCglpbnQgMQoJcmV0dXJuCgovLyBnZXRORkRSZWdpc3RyeUlEKCk6IHVpbnQ2NApnZXRORkRSZWdpc3RyeUlEOgoJcHJvdG8gMCAxCgoJLy8gY29udHJhY3RzL3ZhbGlkYXRvclJlZ2lzdHJ5LmFsZ28udHM6Mzg3CgkvLyByZXR1cm4gdGhpcy5uZmRSZWdpc3RyeUFwcElkOwoJcHVzaGludCBUTVBMX25mZFJlZ2lzdHJ5QXBwSWQKCXJldHN1YgoKLy8gYWRkVmFsaWRhdG9yKHBheSxzdHJpbmcsKHVpbnQ2NCxhZGRyZXNzLGFkZHJlc3MsdWludDY0LHVpbnQ4LGJ5dGVbMzJdLHVpbnQ2NCx1aW50NjQsdWludDY0LHVpbnQxNix1aW50MzIsYWRkcmVzcyx1aW50NjQsdWludDY0LHVpbnQ4LHVpbnQ2NCx1aW50NjQpKXVpbnQ2NAoqYWJpX3JvdXRlX2FkZFZhbGlkYXRvcjoKCS8vIFRoZSBBQkkgcmV0dXJuIHByZWZpeAoJYnl0ZSAweDE1MWY3Yzc1CgoJLy8gY29uZmlnOiAodWludDY0LGFkZHJlc3MsYWRkcmVzcyx1aW50NjQsdWludDgsYnl0ZVszMl0sdWludDY0LHVpbnQ2NCx1aW50NjQsdWludDE2LHVpbnQzMixhZGRyZXNzLHVpbnQ2NCx1aW50NjQsdWludDgsdWludDY0LHVpbnQ2NCkKCXR4bmEgQXBwbGljYXRpb25BcmdzIDIKCWR1cAoJbGVuCglpbnQgMjA4Cgk9PQoJYXNzZXJ0CgoJLy8gbmZkTmFtZTogc3RyaW5nCgl0eG5hIEFwcGxpY2F0aW9uQXJncyAxCglleHRyYWN0IDIgMAoKCS8vIG1iclBheW1lbnQ6IHBheQoJdHhuIEdyb3VwSW5kZXgKCWludCAxCgktCglkdXAKCWd0eG5zIFR5cGVFbnVtCglpbnQgcGF5Cgk9PQoJYXNzZXJ0CgoJLy8gZXhlY3V0ZSBhZGRWYWxpZGF0b3IocGF5LHN0cmluZywodWludDY0LGFkZHJlc3MsYWRkcmVzcyx1aW50NjQsdWludDgsYnl0ZVszMl0sdWludDY0LHVpbnQ2NCx1aW50NjQsdWludDE2LHVpbnQzMixhZGRyZXNzLHVpbnQ2NCx1aW50NjQsdWludDgsdWludDY0LHVpbnQ2NCkpdWludDY0CgljYWxsc3ViIGFkZFZhbGlkYXRvcgoJaXRvYgoJY29uY2F0Cglsb2cKCWludCAxCglyZXR1cm4KCi8vIGFkZFZhbGlkYXRvcihtYnJQYXltZW50OiBQYXlUeG4sIG5mZE5hbWU6IHN0cmluZywgY29uZmlnOiBWYWxpZGF0b3JDb25maWcpOiB1aW50NjQKLy8KLy8gQWRkcyBhIG5ldyB2YWxpZGF0b3IKLy8gQHBhcmFtIG1iclBheW1lbnQgcGF5bWVudCBmcm9tIGNhbGxlciB3aGljaCBjb3ZlcnMgbWJyIGluY3JlYXNlIG9mIG5ldyB2YWxpZGF0b3Igc3RvcmFnZQovLyBAcGFyYW0gbmZkTmFtZSAoT3B0aW9uYWwpIE5hbWUgb2YgbmZkICh1c2VkIGFzIGRvdWJsZS1jaGVjayBhZ2FpbnN0IGlkIHNwZWNpZmllZCBpbiBjb25maWcpCi8vIEBwYXJhbSBjb25maWcgVmFsaWRhdG9yQ29uZmlnIHN0cnVjdAovLyBAcmV0dXJucyB2YWxpZGF0b3IgaWQKYWRkVmFsaWRhdG9yOgoJcHJvdG8gMyAxCgoJLy8gUHVzaCBlbXB0eSBieXRlcyBhZnRlciB0aGUgZnJhbWUgcG9pbnRlciB0byByZXNlcnZlIHNwYWNlIGZvciBsb2NhbCB2YXJpYWJsZXMKCWJ5dGUgMHgKCWR1cAoKCS8vIGNvbnRyYWN0cy92YWxpZGF0b3JSZWdpc3RyeS5hbGdvLnRzOjM5NwoJLy8gdGhpcy52YWxpZGF0ZUNvbmZpZyhjb25maWcpCglmcmFtZV9kaWcgLTMgLy8gY29uZmlnOiBWYWxpZGF0b3JDb25maWcKCWNhbGxzdWIgdmFsaWRhdGVDb25maWcKCgkvLyBjb250cmFjdHMvdmFsaWRhdG9yUmVnaXN0cnkuYWxnby50czozOTgKCS8vIGFzc2VydChjb25maWcub3duZXIgIT09IEFkZHJlc3MuemVyb0FkZHJlc3MpCglmcmFtZV9kaWcgLTMgLy8gY29uZmlnOiBWYWxpZGF0b3JDb25maWcKCWV4dHJhY3QgOCAzMgoJZ2xvYmFsIFplcm9BZGRyZXNzCgkhPQoJYXNzZXJ0CgoJLy8gY29udHJhY3RzL3ZhbGlkYXRvclJlZ2lzdHJ5LmFsZ28udHM6Mzk5CgkvLyBhc3NlcnQoY29uZmlnLm1hbmFnZXIgIT09IEFkZHJlc3MuemVyb0FkZHJlc3MpCglmcmFtZV9kaWcgLTMgLy8gY29uZmlnOiBWYWxpZGF0b3JDb25maWcKCWV4dHJhY3QgNDAgMzIKCWdsb2JhbCBaZXJvQWRkcmVzcwoJIT0KCWFzc2VydAoKCS8vIGNvbnRyYWN0cy92YWxpZGF0b3JSZWdpc3RyeS5hbGdvLnRzOjQwMAoJLy8gYXNzZXJ0KHRoaXMudHhuLnNlbmRlciA9PT0gY29uZmlnLm93bmVyLCAnc2VuZGVyIG11c3QgYmUgb3duZXIgdG8gYWRkIG5ldyB2YWxpZGF0b3InKQoJdHhuIFNlbmRlcgoJZnJhbWVfZGlnIC0zIC8vIGNvbmZpZzogVmFsaWRhdG9yQ29uZmlnCglleHRyYWN0IDggMzIKCT09CgoJLy8gc2VuZGVyIG11c3QgYmUgb3duZXIgdG8gYWRkIG5ldyB2YWxpZGF0b3IKCWFzc2VydAoKCS8vIGNvbnRyYWN0cy92YWxpZGF0b3JSZWdpc3RyeS5hbGdvLnRzOjQwMgoJLy8gdmVyaWZ5UGF5VHhuKG1iclBheW1lbnQsIHsgYW1vdW50OiB0aGlzLmdldE1ickFtb3VudHMoKS5hZGRWYWxpZGF0b3JNYnIgfSkKCS8vIHZlcmlmeSBhbW91bnQKCWZyYW1lX2RpZyAtMSAvLyBtYnJQYXltZW50OiBQYXlUeG4KCWd0eG5zIEFtb3VudAoJY2FsbHN1YiBnZXRNYnJBbW91bnRzCglleHRyYWN0IDAgOAoJYnRvaQoJPT0KCWFzc2VydAoKCS8vIGNvbnRyYWN0cy92YWxpZGF0b3JSZWdpc3RyeS5hbGdvLnRzOjQwNQoJLy8gdmFsaWRhdG9ySWQgPSB0aGlzLm51bVZhbGlkYXRvcnMudmFsdWUgKyAxCglieXRlIDB4NmU3NTZkNTYgLy8gIm51bVYiCglhcHBfZ2xvYmFsX2dldAoJaW50IDEKCSsKCWZyYW1lX2J1cnkgMCAvLyB2YWxpZGF0b3JJZDogdWludDY0CgoJLy8gY29udHJhY3RzL3ZhbGlkYXRvclJlZ2lzdHJ5LmFsZ28udHM6NDA2CgkvLyB0aGlzLm51bVZhbGlkYXRvcnMudmFsdWUgPSB2YWxpZGF0b3JJZAoJYnl0ZSAweDZlNzU2ZDU2IC8vICJudW1WIgoJZnJhbWVfZGlnIDAgLy8gdmFsaWRhdG9ySWQ6IHVpbnQ2NAoJYXBwX2dsb2JhbF9wdXQKCgkvLyBjb250cmFjdHMvdmFsaWRhdG9yUmVnaXN0cnkuYWxnby50czo0MDgKCS8vIHRoaXMudmFsaWRhdG9yTGlzdCh2YWxpZGF0b3JJZCkuY3JlYXRlKCkKCWJ5dGUgMHg3NiAvLyAidiIKCWZyYW1lX2RpZyAwIC8vIHZhbGlkYXRvcklkOiB1aW50NjQKCWl0b2IKCWNvbmNhdAoJaW50IDEwNTgKCWJveF9jcmVhdGUKCXBvcAoKCS8vIGNvbnRyYWN0cy92YWxpZGF0b3JSZWdpc3RyeS5hbGdvLnRzOjQwOQoJLy8gdGhpcy52YWxpZGF0b3JMaXN0KHZhbGlkYXRvcklkKS52YWx1ZS5jb25maWcgPSBjb25maWcKCWludCAwCglmcmFtZV9kaWcgLTMgLy8gY29uZmlnOiBWYWxpZGF0b3JDb25maWcKCWJ5dGUgMHg3NiAvLyAidiIKCWZyYW1lX2RpZyAwIC8vIHZhbGlkYXRvcklkOiB1aW50NjQKCWl0b2IKCWNvbmNhdAoJY292ZXIgMgoJYm94X3JlcGxhY2UKCgkvLyBjb250cmFjdHMvdmFsaWRhdG9yUmVnaXN0cnkuYWxnby50czo0MTAKCS8vIHRoaXMudmFsaWRhdG9yTGlzdCh2YWxpZGF0b3JJZCkudmFsdWUuY29uZmlnLmlkID0gdmFsaWRhdG9ySWQKCWludCAwCglmcmFtZV9kaWcgMCAvLyB2YWxpZGF0b3JJZDogdWludDY0CglpdG9iCglieXRlIDB4NzYgLy8gInYiCglmcmFtZV9kaWcgMCAvLyB2YWxpZGF0b3JJZDogdWludDY0CglpdG9iCgljb25jYXQKCWNvdmVyIDIKCWJveF9yZXBsYWNlCgoJLy8gKmlmNV9jb25kaXRpb24KCS8vIGNvbnRyYWN0cy92YWxpZGF0b3JSZWdpc3RyeS5hbGdvLnRzOjQxMwoJLy8gY29uZmlnLm5mZEZvckluZm8gIT09IDAKCWZyYW1lX2RpZyAtMyAvLyBjb25maWc6IFZhbGlkYXRvckNvbmZpZwoJZXh0cmFjdCA3MiA4CglidG9pCglpbnQgMAoJIT0KCWJ6ICppZjVfZW5kCgoJLy8gKmlmNV9jb25zZXF1ZW50CgkvLyBjb250cmFjdHMvdmFsaWRhdG9yUmVnaXN0cnkuYWxnby50czo0MTUKCS8vIHNlbmRBcHBDYWxsKHsKCS8vICAgICAgICAgICAgICAgICBhcHBsaWNhdGlvbklEOiBBcHBJRC5mcm9tVWludDY0KHRoaXMubmZkUmVnaXN0cnlBcHBJZCksCgkvLyAgICAgICAgICAgICAgICAgYXBwbGljYXRpb25BcmdzOiBbJ2lzX3ZhbGlkX25mZF9hcHBpZCcsIG5mZE5hbWUsIGl0b2IoY29uZmlnLm5mZEZvckluZm8pXSwKCS8vICAgICAgICAgICAgICAgICBhcHBsaWNhdGlvbnM6IFtBcHBJRC5mcm9tVWludDY0KGNvbmZpZy5uZmRGb3JJbmZvKV0sCgkvLyAgICAgICAgICAgICB9KQoJaXR4bl9iZWdpbgoJaW50IGFwcGwKCWl0eG5fZmllbGQgVHlwZUVudW0KCgkvLyBjb250cmFjdHMvdmFsaWRhdG9yUmVnaXN0cnkuYWxnby50czo0MTYKCS8vIGFwcGxpY2F0aW9uSUQ6IEFwcElELmZyb21VaW50NjQodGhpcy5uZmRSZWdpc3RyeUFwcElkKQoJcHVzaGludCBUTVBMX25mZFJlZ2lzdHJ5QXBwSWQKCWl0eG5fZmllbGQgQXBwbGljYXRpb25JRAoKCS8vIGNvbnRyYWN0cy92YWxpZGF0b3JSZWdpc3RyeS5hbGdvLnRzOjQxNwoJLy8gYXBwbGljYXRpb25BcmdzOiBbJ2lzX3ZhbGlkX25mZF9hcHBpZCcsIG5mZE5hbWUsIGl0b2IoY29uZmlnLm5mZEZvckluZm8pXQoJYnl0ZSAweDY5NzM1Zjc2NjE2YzY5NjQ1ZjZlNjY2NDVmNjE3MDcwNjk2NCAvLyAiaXNfdmFsaWRfbmZkX2FwcGlkIgoJaXR4bl9maWVsZCBBcHBsaWNhdGlvbkFyZ3MKCWZyYW1lX2RpZyAtMiAvLyBuZmROYW1lOiBzdHJpbmcKCWl0eG5fZmllbGQgQXBwbGljYXRpb25BcmdzCglmcmFtZV9kaWcgLTMgLy8gY29uZmlnOiBWYWxpZGF0b3JDb25maWcKCWV4dHJhY3QgNzIgOAoJYnRvaQoJaXRvYgoJaXR4bl9maWVsZCBBcHBsaWNhdGlvbkFyZ3MKCgkvLyBjb250cmFjdHMvdmFsaWRhdG9yUmVnaXN0cnkuYWxnby50czo0MTgKCS8vIGFwcGxpY2F0aW9uczogW0FwcElELmZyb21VaW50NjQoY29uZmlnLm5mZEZvckluZm8pXQoJZnJhbWVfZGlnIC0zIC8vIGNvbmZpZzogVmFsaWRhdG9yQ29uZmlnCglleHRyYWN0IDcyIDgKCWJ0b2kKCWl0eG5fZmllbGQgQXBwbGljYXRpb25zCgoJLy8gRmVlIGZpZWxkIG5vdCBzZXQsIGRlZmF1bHRpbmcgdG8gMAoJaW50IDAKCWl0eG5fZmllbGQgRmVlCgoJLy8gU3VibWl0IGlubmVyIHRyYW5zYWN0aW9uCglpdHhuX3N1Ym1pdAoKCS8vIGNvbnRyYWN0cy92YWxpZGF0b3JSZWdpc3RyeS5hbGdvLnRzOjQyMAoJLy8gYXNzZXJ0KGJ0b2kodGhpcy5pdHhuLmxhc3RMb2cpID09PSAxLCAicHJvdmlkZWQgTkZEIGlzbid0IHZhbGlkIikKCWl0eG4gTGFzdExvZwoJYnRvaQoJaW50IDEKCT09CgoJLy8gcHJvdmlkZWQgTkZEIGlzbid0IHZhbGlkCglhc3NlcnQKCgkvLyBjb250cmFjdHMvdmFsaWRhdG9yUmVnaXN0cnkuYWxnby50czo0MjIKCS8vIGFzc2VydCgKCS8vICAgICAgICAgICAgICAgICB0aGlzLnR4bi5zZW5kZXIgPT09IChBcHBJRC5mcm9tVWludDY0KGNvbmZpZy5uZmRGb3JJbmZvKS5nbG9iYWxTdGF0ZSgnaS5vd25lci5hJykgYXMgQWRkcmVzcyksCgkvLyAgICAgICAgICAgICAgICAgJ0lmIHNwZWNpZnlpbmcgTkZELCBhY2NvdW50IGFkZGluZyB2YWxpZGF0b3IgbXVzdCBiZSBvd25lcicKCS8vICAgICAgICAgICAgICkKCXR4biBTZW5kZXIKCWZyYW1lX2RpZyAtMyAvLyBjb25maWc6IFZhbGlkYXRvckNvbmZpZwoJZXh0cmFjdCA3MiA4CglidG9pCglieXRlIDB4NjkyZTZmNzc2ZTY1NzIyZTYxIC8vICJpLm93bmVyLmEiCglhcHBfZ2xvYmFsX2dldF9leAoJYXNzZXJ0Cgk9PQoKCS8vIElmIHNwZWNpZnlpbmcgTkZELCBhY2NvdW50IGFkZGluZyB2YWxpZGF0b3IgbXVzdCBiZSBvd25lcgoJYXNzZXJ0CgoqaWY1X2VuZDoKCS8vICppZjZfY29uZGl0aW9uCgkvLyBjb250cmFjdHMvdmFsaWRhdG9yUmVnaXN0cnkuYWxnby50czo0MjcKCS8vIGNvbmZpZy5lbnRyeUdhdGluZ1R5cGUgPT09IEdBVElOR19UWVBFX0NSRUFURURfQllfTkZEX0FERFJFU1NFUwoJZnJhbWVfZGlnIC0zIC8vIGNvbmZpZzogVmFsaWRhdG9yQ29uZmlnCglleHRyYWN0IDgwIDEKCWJ0b2kKCWludCAzCgk9PQoJYnogKmlmNl9lbmQKCgkvLyAqaWY2X2NvbnNlcXVlbnQKCS8vIGNvbnRyYWN0cy92YWxpZGF0b3JSZWdpc3RyeS5hbGdvLnRzOjQyOQoJLy8gYXNzZXJ0KGNvbmZpZy5uZmRGb3JJbmZvICE9PSAwLCAnYW4gTkZEIG11c3QgYmUgc3BlY2lmaWVkIGZvciB0aGUgdmFsaWRhdG9yIHdoZW4gZ2F0aW5nIGJ5IE5GRCBhZGRyZXNzZXMnKQoJZnJhbWVfZGlnIC0zIC8vIGNvbmZpZzogVmFsaWRhdG9yQ29uZmlnCglleHRyYWN0IDcyIDgKCWJ0b2kKCWludCAwCgkhPQoKCS8vIGFuIE5GRCBtdXN0IGJlIHNwZWNpZmllZCBmb3IgdGhlIHZhbGlkYXRvciB3aGVuIGdhdGluZyBieSBORkQgYWRkcmVzc2VzCglhc3NlcnQKCippZjZfZW5kOgoJLy8gKmlmN19jb25kaXRpb24KCS8vIGNvbnRyYWN0cy92YWxpZGF0b3JSZWdpc3RyeS5hbGdvLnRzOjQzMQoJLy8gY29uZmlnLmVudHJ5R2F0aW5nVHlwZSA9PT0gR0FUSU5HX1RZUEVfU0VHTUVOVF9PRl9ORkQKCWZyYW1lX2RpZyAtMyAvLyBjb25maWc6IFZhbGlkYXRvckNvbmZpZwoJZXh0cmFjdCA4MCAxCglidG9pCglpbnQgNAoJPT0KCWJ6ICppZjdfZW5kCgoJLy8gKmlmN19jb25zZXF1ZW50CgkvLyBjb250cmFjdHMvdmFsaWRhdG9yUmVnaXN0cnkuYWxnby50czo0MzMKCS8vIG5mZFJvb3RBcHBJRCA9IGV4dHJhY3RVaW50NjQoY29uZmlnLmVudHJ5R2F0aW5nVmFsdWUsIDApCglmcmFtZV9kaWcgLTMgLy8gY29uZmlnOiBWYWxpZGF0b3JDb25maWcKCWV4dHJhY3QgODEgMzIKCWludCAwCglleHRyYWN0X3VpbnQ2NAoJZnJhbWVfYnVyeSAxIC8vIG5mZFJvb3RBcHBJRDogdWludDY0CgoJLy8gY29udHJhY3RzL3ZhbGlkYXRvclJlZ2lzdHJ5LmFsZ28udHM6NDM0CgkvLyBhc3NlcnQodGhpcy5pc05GREFwcElEVmFsaWQobmZkUm9vdEFwcElEKSwgJ3Byb3ZpZGVkIE5GRCBBcHAgaWQgZm9yIGdhdGluZyBtdXN0IGJlIHZhbGlkIE5GRCcpCglmcmFtZV9kaWcgMSAvLyBuZmRSb290QXBwSUQ6IHVpbnQ2NAoJY2FsbHN1YiBpc05GREFwcElEVmFsaWQKCgkvLyBwcm92aWRlZCBORkQgQXBwIGlkIGZvciBnYXRpbmcgbXVzdCBiZSB2YWxpZCBORkQKCWFzc2VydAoKKmlmN19lbmQ6CgkvLyBjb250cmFjdHMvdmFsaWRhdG9yUmVnaXN0cnkuYWxnby50czo0MzcKCS8vIHJldHVybiB2YWxpZGF0b3JJZDsKCWZyYW1lX2RpZyAwIC8vIHZhbGlkYXRvcklkOiB1aW50NjQKCgkvLyBzZXQgdGhlIHN1YnJvdXRpbmUgcmV0dXJuIHZhbHVlCglmcmFtZV9idXJ5IDAKCgkvLyBwb3AgYWxsIGxvY2FsIHZhcmlhYmxlcyBmcm9tIHRoZSBzdGFjawoJcG9wbiAxCglyZXRzdWIKCi8vIGNoYW5nZVZhbGlkYXRvck1hbmFnZXIodWludDY0LGFkZHJlc3Mpdm9pZAoqYWJpX3JvdXRlX2NoYW5nZVZhbGlkYXRvck1hbmFnZXI6CgkvLyBtYW5hZ2VyOiBhZGRyZXNzCgl0eG5hIEFwcGxpY2F0aW9uQXJncyAyCglkdXAKCWxlbgoJaW50IDMyCgk9PQoJYXNzZXJ0CgoJLy8gdmFsaWRhdG9ySWQ6IHVpbnQ2NAoJdHhuYSBBcHBsaWNhdGlvbkFyZ3MgMQoJYnRvaQoKCS8vIGV4ZWN1dGUgY2hhbmdlVmFsaWRhdG9yTWFuYWdlcih1aW50NjQsYWRkcmVzcyl2b2lkCgljYWxsc3ViIGNoYW5nZVZhbGlkYXRvck1hbmFnZXIKCWludCAxCglyZXR1cm4KCi8vIGNoYW5nZVZhbGlkYXRvck1hbmFnZXIodmFsaWRhdG9ySWQ6IFZhbGlkYXRvcklkVHlwZSwgbWFuYWdlcjogQWRkcmVzcyk6IHZvaWQKLy8KLy8gQ2hhbmdlcyB0aGUgVmFsaWRhdG9yIG1hbmFnZXIgZm9yIGEgc3BlY2lmaWMgVmFsaWRhdG9yIGlkLgovLyBbIE9OTFkgT1dORVIgQ0FOIENIQU5HRSBdCi8vCi8vIEBwYXJhbSB7VmFsaWRhdG9ySWRUeXBlfSB2YWxpZGF0b3JJZCAtIFRoZSBpZCBvZiB0aGUgdmFsaWRhdG9yIHRvIGNoYW5nZSB0aGUgbWFuYWdlciBmb3IuCi8vIEBwYXJhbSB7QWRkcmVzc30gbWFuYWdlciAtIFRoZSBuZXcgbWFuYWdlciBhZGRyZXNzLgpjaGFuZ2VWYWxpZGF0b3JNYW5hZ2VyOgoJcHJvdG8gMiAwCgoJLy8gY29udHJhY3RzL3ZhbGlkYXRvclJlZ2lzdHJ5LmFsZ28udHM6NDQ4CgkvLyBhc3NlcnQodGhpcy50eG4uc2VuZGVyID09PSB0aGlzLnZhbGlkYXRvckxpc3QodmFsaWRhdG9ySWQpLnZhbHVlLmNvbmZpZy5vd25lcikKCXR4biBTZW5kZXIKCWludCA4CglpbnQgMzIKCWJ5dGUgMHg3NiAvLyAidiIKCWZyYW1lX2RpZyAtMSAvLyB2YWxpZGF0b3JJZDogVmFsaWRhdG9ySWRUeXBlCglpdG9iCgljb25jYXQKCWNvdmVyIDIKCWJveF9leHRyYWN0Cgk9PQoJYXNzZXJ0CgoJLy8gY29udHJhY3RzL3ZhbGlkYXRvclJlZ2lzdHJ5LmFsZ28udHM6NDQ5CgkvLyB0aGlzLnZhbGlkYXRvckxpc3QodmFsaWRhdG9ySWQpLnZhbHVlLmNvbmZpZy5tYW5hZ2VyID0gbWFuYWdlcgoJaW50IDQwCglmcmFtZV9kaWcgLTIgLy8gbWFuYWdlcjogQWRkcmVzcwoJYnl0ZSAweDc2IC8vICJ2IgoJZnJhbWVfZGlnIC0xIC8vIHZhbGlkYXRvcklkOiBWYWxpZGF0b3JJZFR5cGUKCWl0b2IKCWNvbmNhdAoJY292ZXIgMgoJYm94X3JlcGxhY2UKCXJldHN1YgoKLy8gY2hhbmdlVmFsaWRhdG9yU3Vuc2V0SW5mbyh1aW50NjQsdWludDY0LHVpbnQ2NCl2b2lkCiphYmlfcm91dGVfY2hhbmdlVmFsaWRhdG9yU3Vuc2V0SW5mbzoKCS8vIHN1bnNldHRpbmdUbzogdWludDY0Cgl0eG5hIEFwcGxpY2F0aW9uQXJncyAzCglidG9pCgoJLy8gc3Vuc2V0dGluZ09uOiB1aW50NjQKCXR4bmEgQXBwbGljYXRpb25BcmdzIDIKCWJ0b2kKCgkvLyB2YWxpZGF0b3JJZDogdWludDY0Cgl0eG5hIEFwcGxpY2F0aW9uQXJncyAxCglidG9pCgoJLy8gZXhlY3V0ZSBjaGFuZ2VWYWxpZGF0b3JTdW5zZXRJbmZvKHVpbnQ2NCx1aW50NjQsdWludDY0KXZvaWQKCWNhbGxzdWIgY2hhbmdlVmFsaWRhdG9yU3Vuc2V0SW5mbwoJaW50IDEKCXJldHVybgoKLy8gY2hhbmdlVmFsaWRhdG9yU3Vuc2V0SW5mbyh2YWxpZGF0b3JJZDogVmFsaWRhdG9ySWRUeXBlLCBzdW5zZXR0aW5nT246IHVpbnQ2NCwgc3Vuc2V0dGluZ1RvOiBWYWxpZGF0b3JJZFR5cGUpOiB2b2lkCi8vCi8vIFVwZGF0ZXMgdGhlIHN1bnNldCBpbmZvcm1hdGlvbiBmb3IgYSBnaXZlbiB2YWxpZGF0b3IuCi8vIFsgT05MWSBPV05FUiBDQU4gQ0hBTkdFIF0KLy8KLy8gQHBhcmFtIHtWYWxpZGF0b3JJZFR5cGV9IHZhbGlkYXRvcklkIC0gVGhlIGlkIG9mIHRoZSB2YWxpZGF0b3IgdG8gdXBkYXRlLgovLyBAcGFyYW0ge3VpbnQ2NH0gc3Vuc2V0dGluZ09uIC0gVGhlIG5ldyBzdW5zZXQgdGltZXN0YW1wLgovLyBAcGFyYW0ge3VpbnQ2NH0gc3Vuc2V0dGluZ1RvIC0gVGhlIG5ldyBzdW5zZXQgdG8gdmFsaWRhdG9yIGlkLgpjaGFuZ2VWYWxpZGF0b3JTdW5zZXRJbmZvOgoJcHJvdG8gMyAwCgoJLy8gY29udHJhY3RzL3ZhbGlkYXRvclJlZ2lzdHJ5LmFsZ28udHM6NDYxCgkvLyBhc3NlcnQodGhpcy50eG4uc2VuZGVyID09PSB0aGlzLnZhbGlkYXRvckxpc3QodmFsaWRhdG9ySWQpLnZhbHVlLmNvbmZpZy5vd25lcikKCXR4biBTZW5kZXIKCWludCA4CglpbnQgMzIKCWJ5dGUgMHg3NiAvLyAidiIKCWZyYW1lX2RpZyAtMSAvLyB2YWxpZGF0b3JJZDogVmFsaWRhdG9ySWRUeXBlCglpdG9iCgljb25jYXQKCWNvdmVyIDIKCWJveF9leHRyYWN0Cgk9PQoJYXNzZXJ0CgoJLy8gY29udHJhY3RzL3ZhbGlkYXRvclJlZ2lzdHJ5LmFsZ28udHM6NDYyCgkvLyB0aGlzLnZhbGlkYXRvckxpc3QodmFsaWRhdG9ySWQpLnZhbHVlLmNvbmZpZy5zdW5zZXR0aW5nT24gPSBzdW5zZXR0aW5nT24KCWludCAxOTIKCWZyYW1lX2RpZyAtMiAvLyBzdW5zZXR0aW5nT246IHVpbnQ2NAoJaXRvYgoJYnl0ZSAweDc2IC8vICJ2IgoJZnJhbWVfZGlnIC0xIC8vIHZhbGlkYXRvcklkOiBWYWxpZGF0b3JJZFR5cGUKCWl0b2IKCWNvbmNhdAoJY292ZXIgMgoJYm94X3JlcGxhY2UKCgkvLyBjb250cmFjdHMvdmFsaWRhdG9yUmVnaXN0cnkuYWxnby50czo0NjMKCS8vIHRoaXMudmFsaWRhdG9yTGlzdCh2YWxpZGF0b3JJZCkudmFsdWUuY29uZmlnLnN1bnNldHRpbmdUbyA9IHN1bnNldHRpbmdUbwoJaW50IDIwMAoJZnJhbWVfZGlnIC0zIC8vIHN1bnNldHRpbmdUbzogVmFsaWRhdG9ySWRUeXBlCglpdG9iCglieXRlIDB4NzYgLy8gInYiCglmcmFtZV9kaWcgLTEgLy8gdmFsaWRhdG9ySWQ6IFZhbGlkYXRvcklkVHlwZQoJaXRvYgoJY29uY2F0Cgljb3ZlciAyCglib3hfcmVwbGFjZQoJcmV0c3ViCgovLyBjaGFuZ2VWYWxpZGF0b3JORkQodWludDY0LHVpbnQ2NCxzdHJpbmcpdm9pZAoqYWJpX3JvdXRlX2NoYW5nZVZhbGlkYXRvck5GRDoKCS8vIG5mZE5hbWU6IHN0cmluZwoJdHhuYSBBcHBsaWNhdGlvbkFyZ3MgMwoJZXh0cmFjdCAyIDAKCgkvLyBuZmRBcHBJRDogdWludDY0Cgl0eG5hIEFwcGxpY2F0aW9uQXJncyAyCglidG9pCgoJLy8gdmFsaWRhdG9ySWQ6IHVpbnQ2NAoJdHhuYSBBcHBsaWNhdGlvbkFyZ3MgMQoJYnRvaQoKCS8vIGV4ZWN1dGUgY2hhbmdlVmFsaWRhdG9yTkZEKHVpbnQ2NCx1aW50NjQsc3RyaW5nKXZvaWQKCWNhbGxzdWIgY2hhbmdlVmFsaWRhdG9yTkZECglpbnQgMQoJcmV0dXJuCgovLyBjaGFuZ2VWYWxpZGF0b3JORkQodmFsaWRhdG9ySWQ6IFZhbGlkYXRvcklkVHlwZSwgbmZkQXBwSUQ6IHVpbnQ2NCwgbmZkTmFtZTogc3RyaW5nKTogdm9pZAovLwovLyBDaGFuZ2VzIHRoZSBORkQgZm9yIGEgdmFsaWRhdG9yIGluIHRoZSB2YWxpZGF0b3JMaXN0IGNvbnRyYWN0LgovLyBbIE9OTFkgT1dORVIgT1IgTUFOQUdFUiBDQU4gQ0hBTkdFIF0KLy8KLy8gQHBhcmFtIHtWYWxpZGF0b3JJZFR5cGV9IHZhbGlkYXRvcklkIC0gVGhlIGlkIG9mIHRoZSB2YWxpZGF0b3IgdG8gdXBkYXRlLgovLyBAcGFyYW0ge3VpbnQ2NH0gbmZkQXBwSUQgLSBUaGUgYXBwbGljYXRpb24gaWQgb2YgdGhlIE5GRCB0byBhc3NpZ24gdG8gdGhlIHZhbGlkYXRvci4KLy8gQHBhcmFtIHtzdHJpbmd9IG5mZE5hbWUgLSBUaGUgbmFtZSBvZiB0aGUgTkZEICh3aGljaCBtdXN0IG1hdGNoKQpjaGFuZ2VWYWxpZGF0b3JORkQ6Cglwcm90byAzIDAKCgkvLyBjb250cmFjdHMvdmFsaWRhdG9yUmVnaXN0cnkuYWxnby50czo0NzYKCS8vIGFzc2VydCgKCS8vICAgICAgICAgICAgIHRoaXMudHhuLnNlbmRlciA9PT0gdGhpcy52YWxpZGF0b3JMaXN0KHZhbGlkYXRvcklkKS52YWx1ZS5jb25maWcub3duZXIgfHwKCS8vICAgICAgICAgICAgICAgICB0aGlzLnR4bi5zZW5kZXIgPT09IHRoaXMudmFsaWRhdG9yTGlzdCh2YWxpZGF0b3JJZCkudmFsdWUuY29uZmlnLm1hbmFnZXIKCS8vICAgICAgICAgKQoJdHhuIFNlbmRlcgoJaW50IDgKCWludCAzMgoJYnl0ZSAweDc2IC8vICJ2IgoJZnJhbWVfZGlnIC0xIC8vIHZhbGlkYXRvcklkOiBWYWxpZGF0b3JJZFR5cGUKCWl0b2IKCWNvbmNhdAoJY292ZXIgMgoJYm94X2V4dHJhY3QKCT09CglkdXAKCWJueiAqc2tpcF9vcjAKCXR4biBTZW5kZXIKCWludCA0MAoJaW50IDMyCglieXRlIDB4NzYgLy8gInYiCglmcmFtZV9kaWcgLTEgLy8gdmFsaWRhdG9ySWQ6IFZhbGlkYXRvcklkVHlwZQoJaXRvYgoJY29uY2F0Cgljb3ZlciAyCglib3hfZXh0cmFjdAoJPT0KCXx8Cgoqc2tpcF9vcjA6Cglhc3NlcnQKCgkvLyBjb250cmFjdHMvdmFsaWRhdG9yUmVnaXN0cnkuYWxnby50czo0ODEKCS8vIHNlbmRBcHBDYWxsKHsKCS8vICAgICAgICAgICAgIGFwcGxpY2F0aW9uSUQ6IEFwcElELmZyb21VaW50NjQodGhpcy5uZmRSZWdpc3RyeUFwcElkKSwKCS8vICAgICAgICAgICAgIGFwcGxpY2F0aW9uQXJnczogWydpc192YWxpZF9uZmRfYXBwaWQnLCBuZmROYW1lLCBpdG9iKG5mZEFwcElEKV0sCgkvLyAgICAgICAgICAgICBhcHBsaWNhdGlvbnM6IFtBcHBJRC5mcm9tVWludDY0KG5mZEFwcElEKV0sCgkvLyAgICAgICAgIH0pCglpdHhuX2JlZ2luCglpbnQgYXBwbAoJaXR4bl9maWVsZCBUeXBlRW51bQoKCS8vIGNvbnRyYWN0cy92YWxpZGF0b3JSZWdpc3RyeS5hbGdvLnRzOjQ4MgoJLy8gYXBwbGljYXRpb25JRDogQXBwSUQuZnJvbVVpbnQ2NCh0aGlzLm5mZFJlZ2lzdHJ5QXBwSWQpCglwdXNoaW50IFRNUExfbmZkUmVnaXN0cnlBcHBJZAoJaXR4bl9maWVsZCBBcHBsaWNhdGlvbklECgoJLy8gY29udHJhY3RzL3ZhbGlkYXRvclJlZ2lzdHJ5LmFsZ28udHM6NDgzCgkvLyBhcHBsaWNhdGlvbkFyZ3M6IFsnaXNfdmFsaWRfbmZkX2FwcGlkJywgbmZkTmFtZSwgaXRvYihuZmRBcHBJRCldCglieXRlIDB4Njk3MzVmNzY2MTZjNjk2NDVmNmU2NjY0NWY2MTcwNzA2OTY0IC8vICJpc192YWxpZF9uZmRfYXBwaWQiCglpdHhuX2ZpZWxkIEFwcGxpY2F0aW9uQXJncwoJZnJhbWVfZGlnIC0zIC8vIG5mZE5hbWU6IHN0cmluZwoJaXR4bl9maWVsZCBBcHBsaWNhdGlvbkFyZ3MKCWZyYW1lX2RpZyAtMiAvLyBuZmRBcHBJRDogdWludDY0CglpdG9iCglpdHhuX2ZpZWxkIEFwcGxpY2F0aW9uQXJncwoKCS8vIGNvbnRyYWN0cy92YWxpZGF0b3JSZWdpc3RyeS5hbGdvLnRzOjQ4NAoJLy8gYXBwbGljYXRpb25zOiBbQXBwSUQuZnJvbVVpbnQ2NChuZmRBcHBJRCldCglmcmFtZV9kaWcgLTIgLy8gbmZkQXBwSUQ6IHVpbnQ2NAoJaXR4bl9maWVsZCBBcHBsaWNhdGlvbnMKCgkvLyBGZWUgZmllbGQgbm90IHNldCwgZGVmYXVsdGluZyB0byAwCglpbnQgMAoJaXR4bl9maWVsZCBGZWUKCgkvLyBTdWJtaXQgaW5uZXIgdHJhbnNhY3Rpb24KCWl0eG5fc3VibWl0CgoJLy8gY29udHJhY3RzL3ZhbGlkYXRvclJlZ2lzdHJ5LmFsZ28udHM6NDg3CgkvLyBhc3NlcnQoCgkvLyAgICAgICAgICAgICB0aGlzLnR4bi5zZW5kZXIgPT09IChBcHBJRC5mcm9tVWludDY0KG5mZEFwcElEKS5nbG9iYWxTdGF0ZSgnaS5vd25lci5hJykgYXMgQWRkcmVzcyksCgkvLyAgICAgICAgICAgICAnSWYgc3BlY2lmeWluZyBORkQsIGFjY291bnQgYWRkaW5nIHZhbGlkYXRvciBtdXN0IGJlIG93bmVyJwoJLy8gICAgICAgICApCgl0eG4gU2VuZGVyCglmcmFtZV9kaWcgLTIgLy8gbmZkQXBwSUQ6IHVpbnQ2NAoJYnl0ZSAweDY5MmU2Zjc3NmU2NTcyMmU2MSAvLyAiaS5vd25lci5hIgoJYXBwX2dsb2JhbF9nZXRfZXgKCWFzc2VydAoJPT0KCgkvLyBJZiBzcGVjaWZ5aW5nIE5GRCwgYWNjb3VudCBhZGRpbmcgdmFsaWRhdG9yIG11c3QgYmUgb3duZXIKCWFzc2VydAoKCS8vIGNvbnRyYWN0cy92YWxpZGF0b3JSZWdpc3RyeS5hbGdvLnRzOjQ5MQoJLy8gdGhpcy52YWxpZGF0b3JMaXN0KHZhbGlkYXRvcklkKS52YWx1ZS5jb25maWcubmZkRm9ySW5mbyA9IG5mZEFwcElECglpbnQgNzIKCWZyYW1lX2RpZyAtMiAvLyBuZmRBcHBJRDogdWludDY0CglpdG9iCglieXRlIDB4NzYgLy8gInYiCglmcmFtZV9kaWcgLTEgLy8gdmFsaWRhdG9ySWQ6IFZhbGlkYXRvcklkVHlwZQoJaXRvYgoJY29uY2F0Cgljb3ZlciAyCglib3hfcmVwbGFjZQoJcmV0c3ViCgovLyBjaGFuZ2VWYWxpZGF0b3JDb21taXNzaW9uQWRkcmVzcyh1aW50NjQsYWRkcmVzcyl2b2lkCiphYmlfcm91dGVfY2hhbmdlVmFsaWRhdG9yQ29tbWlzc2lvbkFkZHJlc3M6CgkvLyBjb21taXNzaW9uQWRkcmVzczogYWRkcmVzcwoJdHhuYSBBcHBsaWNhdGlvbkFyZ3MgMgoJZHVwCglsZW4KCWludCAzMgoJPT0KCWFzc2VydAoKCS8vIHZhbGlkYXRvcklkOiB1aW50NjQKCXR4bmEgQXBwbGljYXRpb25BcmdzIDEKCWJ0b2kKCgkvLyBleGVjdXRlIGNoYW5nZVZhbGlkYXRvckNvbW1pc3Npb25BZGRyZXNzKHVpbnQ2NCxhZGRyZXNzKXZvaWQKCWNhbGxzdWIgY2hhbmdlVmFsaWRhdG9yQ29tbWlzc2lvbkFkZHJlc3MKCWludCAxCglyZXR1cm4KCi8vIGNoYW5nZVZhbGlkYXRvckNvbW1pc3Npb25BZGRyZXNzKHZhbGlkYXRvcklkOiBWYWxpZGF0b3JJZFR5cGUsIGNvbW1pc3Npb25BZGRyZXNzOiBBZGRyZXNzKTogdm9pZAovLwovLyBDaGFuZ2UgdGhlIGNvbW1pc3Npb24gYWRkcmVzcyB0aGF0IHZhbGlkYXRvciByZXdhcmRzIGFyZSBzZW50IHRvLgovLyBbIE9OTFkgT1dORVIgQ0FOIENIQU5HRSBdCmNoYW5nZVZhbGlkYXRvckNvbW1pc3Npb25BZGRyZXNzOgoJcHJvdG8gMiAwCgoJLy8gY29udHJhY3RzL3ZhbGlkYXRvclJlZ2lzdHJ5LmFsZ28udHM6NDk5CgkvLyBhc3NlcnQodGhpcy50eG4uc2VuZGVyID09PSB0aGlzLnZhbGlkYXRvckxpc3QodmFsaWRhdG9ySWQpLnZhbHVlLmNvbmZpZy5vd25lcikKCXR4biBTZW5kZXIKCWludCA4CglpbnQgMzIKCWJ5dGUgMHg3NiAvLyAidiIKCWZyYW1lX2RpZyAtMSAvLyB2YWxpZGF0b3JJZDogVmFsaWRhdG9ySWRUeXBlCglpdG9iCgljb25jYXQKCWNvdmVyIDIKCWJveF9leHRyYWN0Cgk9PQoJYXNzZXJ0CgoJLy8gY29udHJhY3RzL3ZhbGlkYXRvclJlZ2lzdHJ5LmFsZ28udHM6NTAwCgkvLyBhc3NlcnQoY29tbWlzc2lvbkFkZHJlc3MgIT09IEFkZHJlc3MuemVyb0FkZHJlc3MpCglmcmFtZV9kaWcgLTIgLy8gY29tbWlzc2lvbkFkZHJlc3M6IEFkZHJlc3MKCWdsb2JhbCBaZXJvQWRkcmVzcwoJIT0KCWFzc2VydAoKCS8vIGNvbnRyYWN0cy92YWxpZGF0b3JSZWdpc3RyeS5hbGdvLnRzOjUwMQoJLy8gdGhpcy52YWxpZGF0b3JMaXN0KHZhbGlkYXRvcklkKS52YWx1ZS5jb25maWcudmFsaWRhdG9yQ29tbWlzc2lvbkFkZHJlc3MgPSBjb21taXNzaW9uQWRkcmVzcwoJaW50IDE0MwoJZnJhbWVfZGlnIC0yIC8vIGNvbW1pc3Npb25BZGRyZXNzOiBBZGRyZXNzCglieXRlIDB4NzYgLy8gInYiCglmcmFtZV9kaWcgLTEgLy8gdmFsaWRhdG9ySWQ6IFZhbGlkYXRvcklkVHlwZQoJaXRvYgoJY29uY2F0Cgljb3ZlciAyCglib3hfcmVwbGFjZQoJcmV0c3ViCgovLyBjaGFuZ2VWYWxpZGF0b3JSZXdhcmRJbmZvKHVpbnQ2NCx1aW50OCxieXRlWzMyXSx1aW50NjQsdWludDY0KXZvaWQKKmFiaV9yb3V0ZV9jaGFuZ2VWYWxpZGF0b3JSZXdhcmRJbmZvOgoJLy8gUmV3YXJkUGVyUGF5b3V0OiB1aW50NjQKCXR4bmEgQXBwbGljYXRpb25BcmdzIDUKCWJ0b2kKCgkvLyBHYXRpbmdBc3NldE1pbkJhbGFuY2U6IHVpbnQ2NAoJdHhuYSBBcHBsaWNhdGlvbkFyZ3MgNAoJYnRvaQoKCS8vIEVudHJ5R2F0aW5nVmFsdWU6IGJ5dGVbMzJdCgl0eG5hIEFwcGxpY2F0aW9uQXJncyAzCglkdXAKCWxlbgoJaW50IDMyCgk9PQoJYXNzZXJ0CgoJLy8gRW50cnlHYXRpbmdUeXBlOiB1aW50OAoJdHhuYSBBcHBsaWNhdGlvbkFyZ3MgMgoJZHVwCglsZW4KCWludCAxCgk9PQoJYXNzZXJ0CglidG9pCgoJLy8gdmFsaWRhdG9ySWQ6IHVpbnQ2NAoJdHhuYSBBcHBsaWNhdGlvbkFyZ3MgMQoJYnRvaQoKCS8vIGV4ZWN1dGUgY2hhbmdlVmFsaWRhdG9yUmV3YXJkSW5mbyh1aW50NjQsdWludDgsYnl0ZVszMl0sdWludDY0LHVpbnQ2NCl2b2lkCgljYWxsc3ViIGNoYW5nZVZhbGlkYXRvclJld2FyZEluZm8KCWludCAxCglyZXR1cm4KCi8vIGNoYW5nZVZhbGlkYXRvclJld2FyZEluZm8odmFsaWRhdG9ySWQ6IFZhbGlkYXRvcklkVHlwZSwgRW50cnlHYXRpbmdUeXBlOiB1aW50OCwgRW50cnlHYXRpbmdWYWx1ZTogYnl0ZXMzMiwgR2F0aW5nQXNzZXRNaW5CYWxhbmNlOiB1aW50NjQsIFJld2FyZFBlclBheW91dDogdWludDY0KTogdm9pZAovLwovLyBBbGxvdyB0aGUgYWRkaXRpb25hbCByZXdhcmRzIChnYXRpbmcgZW50cnksIGFkZGl0aW9uYWwgdG9rZW4gcmV3YXJkcykgaW5mb3JtYXRpb24gYmUgY2hhbmdlZCBhdCB3aWxsLgovLyBbIE9OTFkgT1dORVIgQ0FOIENIQU5HRSBdCmNoYW5nZVZhbGlkYXRvclJld2FyZEluZm86Cglwcm90byA1IDAKCgkvLyBjb250cmFjdHMvdmFsaWRhdG9yUmVnaXN0cnkuYWxnby50czo1MTUKCS8vIGFzc2VydCh0aGlzLnR4bi5zZW5kZXIgPT09IHRoaXMudmFsaWRhdG9yTGlzdCh2YWxpZGF0b3JJZCkudmFsdWUuY29uZmlnLm93bmVyKQoJdHhuIFNlbmRlcgoJaW50IDgKCWludCAzMgoJYnl0ZSAweDc2IC8vICJ2IgoJZnJhbWVfZGlnIC0xIC8vIHZhbGlkYXRvcklkOiBWYWxpZGF0b3JJZFR5cGUKCWl0b2IKCWNvbmNhdAoJY292ZXIgMgoJYm94X2V4dHJhY3QKCT09Cglhc3NlcnQKCgkvLyBjb250cmFjdHMvdmFsaWRhdG9yUmVnaXN0cnkuYWxnby50czo1MTcKCS8vIHRoaXMudmFsaWRhdG9yTGlzdCh2YWxpZGF0b3JJZCkudmFsdWUuY29uZmlnLmVudHJ5R2F0aW5nVHlwZSA9IEVudHJ5R2F0aW5nVHlwZQoJaW50IDgwCglmcmFtZV9kaWcgLTIgLy8gRW50cnlHYXRpbmdUeXBlOiB1aW50OAoJaXRvYgoJZXh0cmFjdCA3IDEKCWJ5dGUgMHg3NiAvLyAidiIKCWZyYW1lX2RpZyAtMSAvLyB2YWxpZGF0b3JJZDogVmFsaWRhdG9ySWRUeXBlCglpdG9iCgljb25jYXQKCWNvdmVyIDIKCWJveF9yZXBsYWNlCgoJLy8gY29udHJhY3RzL3ZhbGlkYXRvclJlZ2lzdHJ5LmFsZ28udHM6NTE4CgkvLyB0aGlzLnZhbGlkYXRvckxpc3QodmFsaWRhdG9ySWQpLnZhbHVlLmNvbmZpZy5lbnRyeUdhdGluZ1ZhbHVlID0gRW50cnlHYXRpbmdWYWx1ZQoJaW50IDgxCglmcmFtZV9kaWcgLTMgLy8gRW50cnlHYXRpbmdWYWx1ZTogYnl0ZXMzMgoJYnl0ZSAweDc2IC8vICJ2IgoJZnJhbWVfZGlnIC0xIC8vIHZhbGlkYXRvcklkOiBWYWxpZGF0b3JJZFR5cGUKCWl0b2IKCWNvbmNhdAoJY292ZXIgMgoJYm94X3JlcGxhY2UKCgkvLyBjb250cmFjdHMvdmFsaWRhdG9yUmVnaXN0cnkuYWxnby50czo1MTkKCS8vIHRoaXMudmFsaWRhdG9yTGlzdCh2YWxpZGF0b3JJZCkudmFsdWUuY29uZmlnLmdhdGluZ0Fzc2V0TWluQmFsYW5jZSA9IEdhdGluZ0Fzc2V0TWluQmFsYW5jZQoJaW50IDExMwoJZnJhbWVfZGlnIC00IC8vIEdhdGluZ0Fzc2V0TWluQmFsYW5jZTogdWludDY0CglpdG9iCglieXRlIDB4NzYgLy8gInYiCglmcmFtZV9kaWcgLTEgLy8gdmFsaWRhdG9ySWQ6IFZhbGlkYXRvcklkVHlwZQoJaXRvYgoJY29uY2F0Cgljb3ZlciAyCglib3hfcmVwbGFjZQoKCS8vIGNvbnRyYWN0cy92YWxpZGF0b3JSZWdpc3RyeS5hbGdvLnRzOjUyMAoJLy8gdGhpcy52YWxpZGF0b3JMaXN0KHZhbGlkYXRvcklkKS52YWx1ZS5jb25maWcucmV3YXJkUGVyUGF5b3V0ID0gUmV3YXJkUGVyUGF5b3V0CglpbnQgMTI5CglmcmFtZV9kaWcgLTUgLy8gUmV3YXJkUGVyUGF5b3V0OiB1aW50NjQKCWl0b2IKCWJ5dGUgMHg3NiAvLyAidiIKCWZyYW1lX2RpZyAtMSAvLyB2YWxpZGF0b3JJZDogVmFsaWRhdG9ySWRUeXBlCglpdG9iCgljb25jYXQKCWNvdmVyIDIKCWJveF9yZXBsYWNlCglyZXRzdWIKCi8vIGFkZFBvb2wocGF5LHVpbnQ2NCx1aW50NjQpKHVpbnQ2NCx1aW50NjQsdWludDY0KQoqYWJpX3JvdXRlX2FkZFBvb2w6CgkvLyBUaGUgQUJJIHJldHVybiBwcmVmaXgKCWJ5dGUgMHgxNTFmN2M3NQoKCS8vIG5vZGVOdW06IHVpbnQ2NAoJdHhuYSBBcHBsaWNhdGlvbkFyZ3MgMgoJYnRvaQoKCS8vIHZhbGlkYXRvcklkOiB1aW50NjQKCXR4bmEgQXBwbGljYXRpb25BcmdzIDEKCWJ0b2kKCgkvLyBtYnJQYXltZW50OiBwYXkKCXR4biBHcm91cEluZGV4CglpbnQgMQoJLQoJZHVwCglndHhucyBUeXBlRW51bQoJaW50IHBheQoJPT0KCWFzc2VydAoKCS8vIGV4ZWN1dGUgYWRkUG9vbChwYXksdWludDY0LHVpbnQ2NCkodWludDY0LHVpbnQ2NCx1aW50NjQpCgljYWxsc3ViIGFkZFBvb2wKCWNvbmNhdAoJbG9nCglpbnQgMQoJcmV0dXJuCgovLyBhZGRQb29sKG1iclBheW1lbnQ6IFBheVR4biwgdmFsaWRhdG9ySWQ6IFZhbGlkYXRvcklkVHlwZSwgbm9kZU51bTogdWludDY0KTogVmFsaWRhdG9yUG9vbEtleQovLwovLyBBZGRzIGEgbmV3IHBvb2wgdG8gYSB2YWxpZGF0b3IncyBwb29sIHNldCwgcmV0dXJuaW5nIHRoZSAna2V5JyB0byByZWZlcmVuY2UgdGhlIHBvb2wgaW4gdGhlIGZ1dHVyZSBmb3Igc3Rha2luZywgZXRjLgovLyBUaGUgY2FsbGVyIG11c3QgcGF5IHRoZSBjb3N0IG9mIHRoZSB2YWxpZGF0b3JzIE1CUiBpbmNyZWFzZSBhcyB3ZWxsIGFzIHRoZSBNQlIgdGhhdCB3aWxsIGJlIG5lZWRlZCBmb3IgdGhlIHBvb2wgaXRzZWxmLgovLwovLyBbIE9OTFkgT1dORVIgT1IgTUFOQUdFUiBDQU4gY2FsbCBdCi8vIEBwYXJhbSB7UGF5VHhufSBtYnJQYXltZW50IHBheW1lbnQgZnJvbSBjYWxsZXIgd2hpY2ggY292ZXJzIG1iciBpbmNyZWFzZSBvZiBhZGRpbmcgYSBuZXcgcG9vbAovLyBAcGFyYW0ge3VpbnQ2NH0gdmFsaWRhdG9ySWQgaXMgaWQgb2YgdmFsaWRhdG9yIHRvIHBvb2wgdG8gKG11c3QgYmUgb3duZXIgb3IgbWFuYWdlcikKLy8gQHBhcmFtIHt1aW50NjR9IG5vZGVOdW0gaXMgbm9kZSBudW1iZXIgdG8gYWRkIHRvCi8vIEByZXR1cm5zIHtWYWxpZGF0b3JQb29sS2V5fSBwb29sIGtleSB0byBjcmVhdGVkIHBvb2wKYWRkUG9vbDoKCXByb3RvIDMgMQoKCS8vIFB1c2ggZW1wdHkgYnl0ZXMgYWZ0ZXIgdGhlIGZyYW1lIHBvaW50ZXIgdG8gcmVzZXJ2ZSBzcGFjZSBmb3IgbG9jYWwgdmFyaWFibGVzCglieXRlIDB4CglkdXAKCgkvLyBjb250cmFjdHMvdmFsaWRhdG9yUmVnaXN0cnkuYWxnby50czo1MzYKCS8vIGFzc2VydCgKCS8vICAgICAgICAgICAgIHRoaXMudHhuLnNlbmRlciA9PT0gdGhpcy52YWxpZGF0b3JMaXN0KHZhbGlkYXRvcklkKS52YWx1ZS5jb25maWcub3duZXIgfHwKCS8vICAgICAgICAgICAgICAgICB0aGlzLnR4bi5zZW5kZXIgPT09IHRoaXMudmFsaWRhdG9yTGlzdCh2YWxpZGF0b3JJZCkudmFsdWUuY29uZmlnLm1hbmFnZXIKCS8vICAgICAgICAgKQoJdHhuIFNlbmRlcgoJaW50IDgKCWludCAzMgoJYnl0ZSAweDc2IC8vICJ2IgoJZnJhbWVfZGlnIC0yIC8vIHZhbGlkYXRvcklkOiBWYWxpZGF0b3JJZFR5cGUKCWl0b2IKCWNvbmNhdAoJY292ZXIgMgoJYm94X2V4dHJhY3QKCT09CglkdXAKCWJueiAqc2tpcF9vcjEKCXR4biBTZW5kZXIKCWludCA0MAoJaW50IDMyCglieXRlIDB4NzYgLy8gInYiCglmcmFtZV9kaWcgLTIgLy8gdmFsaWRhdG9ySWQ6IFZhbGlkYXRvcklkVHlwZQoJaXRvYgoJY29uY2F0Cgljb3ZlciAyCglib3hfZXh0cmFjdAoJPT0KCXx8Cgoqc2tpcF9vcjE6Cglhc3NlcnQKCgkvLyBjb250cmFjdHMvdmFsaWRhdG9yUmVnaXN0cnkuYWxnby50czo1NDIKCS8vIHZlcmlmeVBheVR4bihtYnJQYXltZW50LCB7IGFtb3VudDogdGhpcy5nZXRNYnJBbW91bnRzKCkuYWRkUG9vbE1iciwgcmVjZWl2ZXI6IHRoaXMuYXBwLmFkZHJlc3MgfSkKCS8vIHZlcmlmeSBhbW91bnQKCWZyYW1lX2RpZyAtMSAvLyBtYnJQYXltZW50OiBQYXlUeG4KCWd0eG5zIEFtb3VudAoJY2FsbHN1YiBnZXRNYnJBbW91bnRzCglleHRyYWN0IDggOAoJYnRvaQoJPT0KCWFzc2VydAoKCS8vIHZlcmlmeSByZWNlaXZlcgoJZnJhbWVfZGlnIC0xIC8vIG1iclBheW1lbnQ6IFBheVR4bgoJZ3R4bnMgUmVjZWl2ZXIKCWdsb2JhbCBDdXJyZW50QXBwbGljYXRpb25BZGRyZXNzCgk9PQoJYXNzZXJ0CgoJLy8gY29udHJhY3RzL3ZhbGlkYXRvclJlZ2lzdHJ5LmFsZ28udHM6NTQ0CgkvLyBhc3NlcnQodGhpcy52YWxpZGF0b3JMaXN0KHZhbGlkYXRvcklkKS5leGlzdHMpCglieXRlIDB4NzYgLy8gInYiCglmcmFtZV9kaWcgLTIgLy8gdmFsaWRhdG9ySWQ6IFZhbGlkYXRvcklkVHlwZQoJaXRvYgoJY29uY2F0Cglib3hfbGVuCglzd2FwCglwb3AKCWFzc2VydAoKCS8vIGNvbnRyYWN0cy92YWxpZGF0b3JSZWdpc3RyeS5hbGdvLnRzOjU0NgoJLy8gbnVtUG9vbHM6IHVpbnQ2NCA9IHRoaXMudmFsaWRhdG9yTGlzdCh2YWxpZGF0b3JJZCkudmFsdWUuc3RhdGUubnVtUG9vbHMgYXMgdWludDY0CglpbnQgMjA4CglpbnQgMgoJYnl0ZSAweDc2IC8vICJ2IgoJZnJhbWVfZGlnIC0yIC8vIHZhbGlkYXRvcklkOiBWYWxpZGF0b3JJZFR5cGUKCWl0b2IKCWNvbmNhdAoJY292ZXIgMgoJYm94X2V4dHJhY3QKCWJ0b2kKCWZyYW1lX2J1cnkgMCAvLyBudW1Qb29sczogdWludDY0CgoJLy8gKmlmOF9jb25kaXRpb24KCS8vIGNvbnRyYWN0cy92YWxpZGF0b3JSZWdpc3RyeS5hbGdvLnRzOjU0NwoJLy8gKG51bVBvb2xzIGFzIHVpbnQ2NCkgPj0gTUFYX1BPT0xTCglmcmFtZV9kaWcgMCAvLyBudW1Qb29sczogdWludDY0CglpbnQgMjQKCT49CglieiAqaWY4X2VuZAoKCS8vICppZjhfY29uc2VxdWVudAoJZXJyIC8vICdhbHJlYWR5IGF0IG1heCBwb29sIHNpemUnCgoqaWY4X2VuZDoKCS8vIGNvbnRyYWN0cy92YWxpZGF0b3JSZWdpc3RyeS5hbGdvLnRzOjU1MAoJLy8gbnVtUG9vbHMgKz0gMQoJZnJhbWVfZGlnIDAgLy8gbnVtUG9vbHM6IHVpbnQ2NAoJaW50IDEKCSsKCWZyYW1lX2J1cnkgMCAvLyBudW1Qb29sczogdWludDY0CgoJLy8gY29udHJhY3RzL3ZhbGlkYXRvclJlZ2lzdHJ5LmFsZ28udHM6NTUzCgkvLyBzZW5kQXBwQ2FsbCh7CgkvLyAgICAgICAgICAgICBvbkNvbXBsZXRpb246IE9uQ29tcGxldGlvbi5Ob09wLAoJLy8gICAgICAgICAgICAgYXBwcm92YWxQcm9ncmFtOiBBcHBJRC5mcm9tVWludDY0KHRoaXMuc3Rha2luZ1Bvb2xUZW1wbGF0ZUFwcElkLnZhbHVlKS5hcHByb3ZhbFByb2dyYW0sCgkvLyAgICAgICAgICAgICBjbGVhclN0YXRlUHJvZ3JhbTogQXBwSUQuZnJvbVVpbnQ2NCh0aGlzLnN0YWtpbmdQb29sVGVtcGxhdGVBcHBJZC52YWx1ZSkuY2xlYXJTdGF0ZVByb2dyYW0sCgkvLyAgICAgICAgICAgICBnbG9iYWxOdW1VaW50OiBBcHBJRC5mcm9tVWludDY0KHRoaXMuc3Rha2luZ1Bvb2xUZW1wbGF0ZUFwcElkLnZhbHVlKS5nbG9iYWxOdW1VaW50LAoJLy8gICAgICAgICAgICAgZ2xvYmFsTnVtQnl0ZVNsaWNlOiBBcHBJRC5mcm9tVWludDY0KHRoaXMuc3Rha2luZ1Bvb2xUZW1wbGF0ZUFwcElkLnZhbHVlKS5nbG9iYWxOdW1CeXRlU2xpY2UsCgkvLyAgICAgICAgICAgICBleHRyYVByb2dyYW1QYWdlczogQXBwSUQuZnJvbVVpbnQ2NCh0aGlzLnN0YWtpbmdQb29sVGVtcGxhdGVBcHBJZC52YWx1ZSkuZXh0cmFQcm9ncmFtUGFnZXMsCgkvLyAgICAgICAgICAgICBhcHBsaWNhdGlvbkFyZ3M6IFsKCS8vICAgICAgICAgICAgICAgICAvLyBjcmVhdGluZ0NvbnRyYWN0SUQsIHZhbGlkYXRvcklkLCBwb29sSWQsIG1pbkVudHJ5U3Rha2UKCS8vICAgICAgICAgICAgICAgICBtZXRob2QoJ2NyZWF0ZUFwcGxpY2F0aW9uKHVpbnQ2NCx1aW50NjQsdWludDY0LHVpbnQ2NCl2b2lkJyksCgkvLyAgICAgICAgICAgICAgICAgaXRvYih0aGlzLmFwcC5pZCksCgkvLyAgICAgICAgICAgICAgICAgaXRvYih2YWxpZGF0b3JJZCksCgkvLyAgICAgICAgICAgICAgICAgaXRvYihudW1Qb29scyBhcyB1aW50NjQpLAoJLy8gICAgICAgICAgICAgICAgIGl0b2IodGhpcy52YWxpZGF0b3JMaXN0KHZhbGlkYXRvcklkKS52YWx1ZS5jb25maWcubWluRW50cnlTdGFrZSksCgkvLyAgICAgICAgICAgICBdLAoJLy8gICAgICAgICB9KQoJaXR4bl9iZWdpbgoJaW50IGFwcGwKCWl0eG5fZmllbGQgVHlwZUVudW0KCgkvLyBjb250cmFjdHMvdmFsaWRhdG9yUmVnaXN0cnkuYWxnby50czo1NTQKCS8vIG9uQ29tcGxldGlvbjogT25Db21wbGV0aW9uLk5vT3AKCWludCAwIC8vIE5vT3AKCWl0eG5fZmllbGQgT25Db21wbGV0aW9uCgoJLy8gY29udHJhY3RzL3ZhbGlkYXRvclJlZ2lzdHJ5LmFsZ28udHM6NTU1CgkvLyBhcHByb3ZhbFByb2dyYW06IEFwcElELmZyb21VaW50NjQodGhpcy5zdGFraW5nUG9vbFRlbXBsYXRlQXBwSWQudmFsdWUpLmFwcHJvdmFsUHJvZ3JhbQoJYnl0ZSAweDcwNmY2ZjZjNTQ2NTZkNzA2YzYxNzQ2NTQxNzA3MDQ5NjQgLy8gInBvb2xUZW1wbGF0ZUFwcElkIgoJYXBwX2dsb2JhbF9nZXQKCWFwcF9wYXJhbXNfZ2V0IEFwcEFwcHJvdmFsUHJvZ3JhbQoJcG9wCglpdHhuX2ZpZWxkIEFwcHJvdmFsUHJvZ3JhbQoKCS8vIGNvbnRyYWN0cy92YWxpZGF0b3JSZWdpc3RyeS5hbGdvLnRzOjU1NgoJLy8gY2xlYXJTdGF0ZVByb2dyYW06IEFwcElELmZyb21VaW50NjQodGhpcy5zdGFraW5nUG9vbFRlbXBsYXRlQXBwSWQudmFsdWUpLmNsZWFyU3RhdGVQcm9ncmFtCglieXRlIDB4NzA2ZjZmNmM1NDY1NmQ3MDZjNjE3NDY1NDE3MDcwNDk2NCAvLyAicG9vbFRlbXBsYXRlQXBwSWQiCglhcHBfZ2xvYmFsX2dldAoJYXBwX3BhcmFtc19nZXQgQXBwQ2xlYXJTdGF0ZVByb2dyYW0KCXBvcAoJaXR4bl9maWVsZCBDbGVhclN0YXRlUHJvZ3JhbQoKCS8vIGNvbnRyYWN0cy92YWxpZGF0b3JSZWdpc3RyeS5hbGdvLnRzOjU1NwoJLy8gZ2xvYmFsTnVtVWludDogQXBwSUQuZnJvbVVpbnQ2NCh0aGlzLnN0YWtpbmdQb29sVGVtcGxhdGVBcHBJZC52YWx1ZSkuZ2xvYmFsTnVtVWludAoJYnl0ZSAweDcwNmY2ZjZjNTQ2NTZkNzA2YzYxNzQ2NTQxNzA3MDQ5NjQgLy8gInBvb2xUZW1wbGF0ZUFwcElkIgoJYXBwX2dsb2JhbF9nZXQKCWFwcF9wYXJhbXNfZ2V0IEFwcEdsb2JhbE51bVVpbnQKCXBvcAoJaXR4bl9maWVsZCBHbG9iYWxOdW1VaW50CgoJLy8gY29udHJhY3RzL3ZhbGlkYXRvclJlZ2lzdHJ5LmFsZ28udHM6NTU4CgkvLyBnbG9iYWxOdW1CeXRlU2xpY2U6IEFwcElELmZyb21VaW50NjQodGhpcy5zdGFraW5nUG9vbFRlbXBsYXRlQXBwSWQudmFsdWUpLmdsb2JhbE51bUJ5dGVTbGljZQoJYnl0ZSAweDcwNmY2ZjZjNTQ2NTZkNzA2YzYxNzQ2NTQxNzA3MDQ5NjQgLy8gInBvb2xUZW1wbGF0ZUFwcElkIgoJYXBwX2dsb2JhbF9nZXQKCWFwcF9wYXJhbXNfZ2V0IEFwcEdsb2JhbE51bUJ5dGVTbGljZQoJcG9wCglpdHhuX2ZpZWxkIEdsb2JhbE51bUJ5dGVTbGljZQoKCS8vIGNvbnRyYWN0cy92YWxpZGF0b3JSZWdpc3RyeS5hbGdvLnRzOjU1OQoJLy8gZXh0cmFQcm9ncmFtUGFnZXM6IEFwcElELmZyb21VaW50NjQodGhpcy5zdGFraW5nUG9vbFRlbXBsYXRlQXBwSWQudmFsdWUpLmV4dHJhUHJvZ3JhbVBhZ2VzCglieXRlIDB4NzA2ZjZmNmM1NDY1NmQ3MDZjNjE3NDY1NDE3MDcwNDk2NCAvLyAicG9vbFRlbXBsYXRlQXBwSWQiCglhcHBfZ2xvYmFsX2dldAoJYXBwX3BhcmFtc19nZXQgQXBwRXh0cmFQcm9ncmFtUGFnZXMKCXBvcAoJaXR4bl9maWVsZCBFeHRyYVByb2dyYW1QYWdlcwoKCS8vIGNvbnRyYWN0cy92YWxpZGF0b3JSZWdpc3RyeS5hbGdvLnRzOjU2MAoJLy8gYXBwbGljYXRpb25BcmdzOiBbCgkvLyAgICAgICAgICAgICAgICAgLy8gY3JlYXRpbmdDb250cmFjdElELCB2YWxpZGF0b3JJZCwgcG9vbElkLCBtaW5FbnRyeVN0YWtlCgkvLyAgICAgICAgICAgICAgICAgbWV0aG9kKCdjcmVhdGVBcHBsaWNhdGlvbih1aW50NjQsdWludDY0LHVpbnQ2NCx1aW50NjQpdm9pZCcpLAoJLy8gICAgICAgICAgICAgICAgIGl0b2IodGhpcy5hcHAuaWQpLAoJLy8gICAgICAgICAgICAgICAgIGl0b2IodmFsaWRhdG9ySWQpLAoJLy8gICAgICAgICAgICAgICAgIGl0b2IobnVtUG9vbHMgYXMgdWludDY0KSwKCS8vICAgICAgICAgICAgICAgICBpdG9iKHRoaXMudmFsaWRhdG9yTGlzdCh2YWxpZGF0b3JJZCkudmFsdWUuY29uZmlnLm1pbkVudHJ5U3Rha2UpLAoJLy8gICAgICAgICAgICAgXQoJbWV0aG9kICJjcmVhdGVBcHBsaWNhdGlvbih1aW50NjQsdWludDY0LHVpbnQ2NCx1aW50NjQpdm9pZCIKCWl0eG5fZmllbGQgQXBwbGljYXRpb25BcmdzCgl0eG5hIEFwcGxpY2F0aW9ucyAwCglpdG9iCglpdHhuX2ZpZWxkIEFwcGxpY2F0aW9uQXJncwoJZnJhbWVfZGlnIC0yIC8vIHZhbGlkYXRvcklkOiBWYWxpZGF0b3JJZFR5cGUKCWl0b2IKCWl0eG5fZmllbGQgQXBwbGljYXRpb25BcmdzCglmcmFtZV9kaWcgMCAvLyBudW1Qb29sczogdWludDY0CglpdG9iCglpdHhuX2ZpZWxkIEFwcGxpY2F0aW9uQXJncwoJaW50IDE3NQoJaW50IDgKCWJ5dGUgMHg3NiAvLyAidiIKCWZyYW1lX2RpZyAtMiAvLyB2YWxpZGF0b3JJZDogVmFsaWRhdG9ySWRUeXBlCglpdG9iCgljb25jYXQKCWNvdmVyIDIKCWJveF9leHRyYWN0CglidG9pCglpdG9iCglpdHhuX2ZpZWxkIEFwcGxpY2F0aW9uQXJncwoKCS8vIEZlZSBmaWVsZCBub3Qgc2V0LCBkZWZhdWx0aW5nIHRvIDAKCWludCAwCglpdHhuX2ZpZWxkIEZlZQoKCS8vIFN1Ym1pdCBpbm5lciB0cmFuc2FjdGlvbgoJaXR4bl9zdWJtaXQKCgkvLyBjb250cmFjdHMvdmFsaWRhdG9yUmVnaXN0cnkuYWxnby50czo1NzAKCS8vIHRoaXMudmFsaWRhdG9yTGlzdCh2YWxpZGF0b3JJZCkudmFsdWUuc3RhdGUubnVtUG9vbHMgPSBudW1Qb29scyBhcyB1aW50MTYKCWludCAyMDgKCWZyYW1lX2RpZyAwIC8vIG51bVBvb2xzOiB1aW50NjQKCWl0b2IKCWV4dHJhY3QgNiAyCglieXRlIDB4NzYgLy8gInYiCglmcmFtZV9kaWcgLTIgLy8gdmFsaWRhdG9ySWQ6IFZhbGlkYXRvcklkVHlwZQoJaXRvYgoJY29uY2F0Cgljb3ZlciAyCglib3hfcmVwbGFjZQoKCS8vIGNvbnRyYWN0cy92YWxpZGF0b3JSZWdpc3RyeS5hbGdvLnRzOjU3MwoJLy8gcG9vbEFwcElkID0gdGhpcy5pdHhuLmNyZWF0ZWRBcHBsaWNhdGlvbklELmlkCglpdHhuIENyZWF0ZWRBcHBsaWNhdGlvbklECglmcmFtZV9idXJ5IDEgLy8gcG9vbEFwcElkOiB1aW50NjQKCgkvLyBjb250cmFjdHMvdmFsaWRhdG9yUmVnaXN0cnkuYWxnby50czo1NzQKCS8vIHRoaXMudmFsaWRhdG9yTGlzdCh2YWxpZGF0b3JJZCkudmFsdWUucG9vbHNbbnVtUG9vbHMgLSAxXS5wb29sQXBwSWQgPSBwb29sQXBwSWQKCWludCAyMzQgLy8gaGVhZE9mZnNldAoJZnJhbWVfZGlnIDAgLy8gbnVtUG9vbHM6IHVpbnQ2NAoJaW50IDEKCS0KCWludCAxOAoJKiAvLyBhY2MgKiB0eXBlTGVuZ3RoCgkrCglpbnQgMAoJKwoJZnJhbWVfZGlnIDEgLy8gcG9vbEFwcElkOiB1aW50NjQKCWl0b2IKCWJ5dGUgMHg3NiAvLyAidiIKCWZyYW1lX2RpZyAtMiAvLyB2YWxpZGF0b3JJZDogVmFsaWRhdG9ySWRUeXBlCglpdG9iCgljb25jYXQKCWNvdmVyIDIKCWJveF9yZXBsYWNlCgoJLy8gY29udHJhY3RzL3ZhbGlkYXRvclJlZ2lzdHJ5LmFsZ28udHM6NTc1CgkvLyB0aGlzLmFkZFBvb2xUb05vZGUodmFsaWRhdG9ySWQsIHBvb2xBcHBJZCwgbm9kZU51bSkKCWZyYW1lX2RpZyAtMyAvLyBub2RlTnVtOiB1aW50NjQKCWZyYW1lX2RpZyAxIC8vIHBvb2xBcHBJZDogdWludDY0CglmcmFtZV9kaWcgLTIgLy8gdmFsaWRhdG9ySWQ6IFZhbGlkYXRvcklkVHlwZQoJY2FsbHN1YiBhZGRQb29sVG9Ob2RlCgoJLy8gY29udHJhY3RzL3ZhbGlkYXRvclJlZ2lzdHJ5LmFsZ28udHM6NTgzCgkvLyByZXR1cm4geyBpZDogdmFsaWRhdG9ySWQsIHBvb2xJZDogbnVtUG9vbHMgYXMgdWludDY0LCBwb29sQXBwSWQ6IHRoaXMuaXR4biEuY3JlYXRlZEFwcGxpY2F0aW9uSUQuaWQgfTsKCWZyYW1lX2RpZyAtMiAvLyB2YWxpZGF0b3JJZDogVmFsaWRhdG9ySWRUeXBlCglpdG9iCglmcmFtZV9kaWcgMCAvLyBudW1Qb29sczogdWludDY0CglpdG9iCgljb25jYXQKCWl0eG4gQ3JlYXRlZEFwcGxpY2F0aW9uSUQKCWl0b2IKCWNvbmNhdAoKCS8vIHNldCB0aGUgc3Vicm91dGluZSByZXR1cm4gdmFsdWUKCWZyYW1lX2J1cnkgMAoKCS8vIHBvcCBhbGwgbG9jYWwgdmFyaWFibGVzIGZyb20gdGhlIHN0YWNrCglwb3BuIDEKCXJldHN1YgoKLy8gYWRkU3Rha2UocGF5LHVpbnQ2NCx1aW50NjQpKHVpbnQ2NCx1aW50NjQsdWludDY0KQoqYWJpX3JvdXRlX2FkZFN0YWtlOgoJLy8gVGhlIEFCSSByZXR1cm4gcHJlZml4CglieXRlIDB4MTUxZjdjNzUKCgkvLyB2YWx1ZVRvVmVyaWZ5OiB1aW50NjQKCXR4bmEgQXBwbGljYXRpb25BcmdzIDIKCWJ0b2kKCgkvLyB2YWxpZGF0b3JJZDogdWludDY0Cgl0eG5hIEFwcGxpY2F0aW9uQXJncyAxCglidG9pCgoJLy8gc3Rha2VkQW1vdW50UGF5bWVudDogcGF5Cgl0eG4gR3JvdXBJbmRleAoJaW50IDEKCS0KCWR1cAoJZ3R4bnMgVHlwZUVudW0KCWludCBwYXkKCT09Cglhc3NlcnQKCgkvLyBleGVjdXRlIGFkZFN0YWtlKHBheSx1aW50NjQsdWludDY0KSh1aW50NjQsdWludDY0LHVpbnQ2NCkKCWNhbGxzdWIgYWRkU3Rha2UKCWNvbmNhdAoJbG9nCglpbnQgMQoJcmV0dXJuCgovLyBhZGRTdGFrZShzdGFrZWRBbW91bnRQYXltZW50OiBQYXlUeG4sIHZhbGlkYXRvcklkOiBWYWxpZGF0b3JJZFR5cGUsIHZhbHVlVG9WZXJpZnk6IHVpbnQ2NCk6IFZhbGlkYXRvclBvb2xLZXkKLy8KLy8gQWRkcyBzdGFrZSB0byBhIHZhbGlkYXRvciBwb29sLgovLwovLyBAcGFyYW0ge1BheVR4bn0gc3Rha2VkQW1vdW50UGF5bWVudCAtIHBheW1lbnQgY29taW5nIGZyb20gc3Rha2VyIHRvIHBsYWNlIGludG8gYSBwb29sCi8vIEBwYXJhbSB7VmFsaWRhdG9ySWRUeXBlfSB2YWxpZGF0b3JJZCAtIFRoZSBpZCBvZiB0aGUgdmFsaWRhdG9yLgovLyBAcGFyYW0ge3VpbnQ2NH0gdmFsdWVUb1ZlcmlmeSAtIG9ubHkgaWYgdmFsaWRhdG9yIGhhcyBnYXRpbmcgdG8gZW50ZXIgLSB0aGlzIGlzIGFzc2V0IGlkIG9yIG5mZCBpZCB0aGF0IGNvcnJlc3BvbmRzIHRvIGdhdGluZy4KLy8gVHhuIHNlbmRlciBpcyBmYWN0b3JlZCBpbiBhcyB3ZWxsIGlmIHRoYXQgaXMgcGFydCBvZiBnYXRpbmcuCi8vICogQHJldHVybnMge1ZhbGlkYXRvclBvb2xLZXl9IC0gVGhlIGtleSBvZiB0aGUgdmFsaWRhdG9yIHBvb2wuCmFkZFN0YWtlOgoJcHJvdG8gMyAxCgoJLy8gUHVzaCBlbXB0eSBieXRlcyBhZnRlciB0aGUgZnJhbWUgcG9pbnRlciB0byByZXNlcnZlIHNwYWNlIGZvciBsb2NhbCB2YXJpYWJsZXMKCWJ5dGUgMHgKCWR1cG4gNQoKCS8vIGNvbnRyYWN0cy92YWxpZGF0b3JSZWdpc3RyeS5hbGdvLnRzOjU5NgoJLy8gYXNzZXJ0KHRoaXMudmFsaWRhdG9yTGlzdCh2YWxpZGF0b3JJZCkuZXhpc3RzKQoJYnl0ZSAweDc2IC8vICJ2IgoJZnJhbWVfZGlnIC0yIC8vIHZhbGlkYXRvcklkOiBWYWxpZGF0b3JJZFR5cGUKCWl0b2IKCWNvbmNhdAoJYm94X2xlbgoJc3dhcAoJcG9wCglhc3NlcnQKCgkvLyBjb250cmFjdHMvdmFsaWRhdG9yUmVnaXN0cnkuYWxnby50czo1OTgKCS8vIHN0YWtlciA9IHRoaXMudHhuLnNlbmRlcgoJdHhuIFNlbmRlcgoJZnJhbWVfYnVyeSAwIC8vIHN0YWtlcjogYWRkcmVzcwoKCS8vIGNvbnRyYWN0cy92YWxpZGF0b3JSZWdpc3RyeS5hbGdvLnRzOjYwMgoJLy8gdmVyaWZ5UGF5VHhuKHN0YWtlZEFtb3VudFBheW1lbnQsIHsKCS8vICAgICAgICAgICAgIHNlbmRlcjogc3Rha2VyLAoJLy8gICAgICAgICAgICAgcmVjZWl2ZXI6IHRoaXMuYXBwLmFkZHJlc3MsCgkvLyAgICAgICAgIH0pCgkvLyB2ZXJpZnkgc2VuZGVyCglmcmFtZV9kaWcgLTEgLy8gc3Rha2VkQW1vdW50UGF5bWVudDogUGF5VHhuCglndHhucyBTZW5kZXIKCWZyYW1lX2RpZyAwIC8vIHN0YWtlcjogYWRkcmVzcwoJPT0KCWFzc2VydAoKCS8vIHZlcmlmeSByZWNlaXZlcgoJZnJhbWVfZGlnIC0xIC8vIHN0YWtlZEFtb3VudFBheW1lbnQ6IFBheVR4bgoJZ3R4bnMgUmVjZWl2ZXIKCWdsb2JhbCBDdXJyZW50QXBwbGljYXRpb25BZGRyZXNzCgk9PQoJYXNzZXJ0CgoJLy8gY29udHJhY3RzL3ZhbGlkYXRvclJlZ2lzdHJ5LmFsZ28udHM6NjA5CgkvLyBhc3NlcnQoCgkvLyAgICAgICAgICAgICB0aGlzLnZhbGlkYXRvckxpc3QodmFsaWRhdG9ySWQpLnZhbHVlLnN0YXRlLnRvdGFsQWxnb1N0YWtlZCA8IHRoaXMubWF4QWxsb3dlZFN0YWtlKCksCgkvLyAgICAgICAgICAgICAndG90YWwgc3Rha2VkIGZvciBhbGwgb2YgYSB2YWxpZGF0b3JzIHBvb2xzIG1heSBub3QgZXhjZWVkIGhhcmQgY2FwJwoJLy8gICAgICAgICApCglpbnQgMjE4CglpbnQgOAoJYnl0ZSAweDc2IC8vICJ2IgoJZnJhbWVfZGlnIC0yIC8vIHZhbGlkYXRvcklkOiBWYWxpZGF0b3JJZFR5cGUKCWl0b2IKCWNvbmNhdAoJY292ZXIgMgoJYm94X2V4dHJhY3QKCWJ0b2kKCWNhbGxzdWIgbWF4QWxsb3dlZFN0YWtlCgk8CgoJLy8gdG90YWwgc3Rha2VkIGZvciBhbGwgb2YgYSB2YWxpZGF0b3JzIHBvb2xzIG1heSBub3QgZXhjZWVkIGhhcmQgY2FwCglhc3NlcnQKCgkvLyBjb250cmFjdHMvdmFsaWRhdG9yUmVnaXN0cnkuYWxnby50czo2MTYKCS8vIHRoaXMuZG9lc1N0YWtlck1lZXRHYXRpbmcodmFsaWRhdG9ySWQsIHZhbHVlVG9WZXJpZnkpCglmcmFtZV9kaWcgLTMgLy8gdmFsdWVUb1ZlcmlmeTogdWludDY0CglmcmFtZV9kaWcgLTIgLy8gdmFsaWRhdG9ySWQ6IFZhbGlkYXRvcklkVHlwZQoJY2FsbHN1YiBkb2VzU3Rha2VyTWVldEdhdGluZwoKCS8vIGNvbnRyYWN0cy92YWxpZGF0b3JSZWdpc3RyeS5hbGdvLnRzOjYxOAoJLy8gcmVhbEFtb3VudCA9IHN0YWtlZEFtb3VudFBheW1lbnQuYW1vdW50CglmcmFtZV9kaWcgLTEgLy8gc3Rha2VkQW1vdW50UGF5bWVudDogUGF5VHhuCglndHhucyBBbW91bnQKCWZyYW1lX2J1cnkgMSAvLyByZWFsQW1vdW50OiB1aW50NjQKCgkvLyBjb250cmFjdHMvdmFsaWRhdG9yUmVnaXN0cnkuYWxnby50czo2MTkKCS8vIG1ickFtdExlZnRCZWhpbmQ6IHVpbnQ2NCA9IDAKCWludCAwCglmcmFtZV9idXJ5IDIgLy8gbWJyQW10TGVmdEJlaGluZDogdWludDY0CgoJLy8gKmlmOV9jb25kaXRpb24KCS8vIGNvbnRyYWN0cy92YWxpZGF0b3JSZWdpc3RyeS5hbGdvLnRzOjYyMQoJLy8gIXRoaXMuc3Rha2VyUG9vbFNldChzdGFrZXIpLmV4aXN0cwoJYnl0ZSAweDczNzA3MyAvLyAic3BzIgoJZnJhbWVfZGlnIDAgLy8gc3Rha2VyOiBhZGRyZXNzCgljb25jYXQKCWJveF9sZW4KCXN3YXAKCXBvcAoJIQoJYnogKmlmOV9lbmQKCgkvLyAqaWY5X2NvbnNlcXVlbnQKCS8vIGNvbnRyYWN0cy92YWxpZGF0b3JSZWdpc3RyeS5hbGdvLnRzOjYyNAoJLy8gbWJyQW10TGVmdEJlaGluZCA9IHRoaXMuZ2V0TWJyQW1vdW50cygpLmFkZFN0YWtlck1icgoJY2FsbHN1YiBnZXRNYnJBbW91bnRzCglleHRyYWN0IDI0IDgKCWJ0b2kKCWZyYW1lX2J1cnkgMiAvLyBtYnJBbXRMZWZ0QmVoaW5kOiB1aW50NjQKCgkvLyBjb250cmFjdHMvdmFsaWRhdG9yUmVnaXN0cnkuYWxnby50czo2MjUKCS8vIHJlYWxBbW91bnQgLT0gbWJyQW10TGVmdEJlaGluZAoJZnJhbWVfZGlnIDEgLy8gcmVhbEFtb3VudDogdWludDY0CglmcmFtZV9kaWcgMiAvLyBtYnJBbXRMZWZ0QmVoaW5kOiB1aW50NjQKCS0KCWZyYW1lX2J1cnkgMSAvLyByZWFsQW1vdW50OiB1aW50NjQKCgkvLyBjb250cmFjdHMvdmFsaWRhdG9yUmVnaXN0cnkuYWxnby50czo2MjYKCS8vIHRoaXMuc3Rha2VyUG9vbFNldChzdGFrZXIpLmNyZWF0ZSgpCglieXRlIDB4NzM3MDczIC8vICJzcHMiCglmcmFtZV9kaWcgMCAvLyBzdGFrZXI6IGFkZHJlc3MKCWNvbmNhdAoJaW50IDE0NAoJYm94X2NyZWF0ZQoJcG9wCgoqaWY5X2VuZDoKCS8vIGNvbnRyYWN0cy92YWxpZGF0b3JSZWdpc3RyeS5hbGdvLnRzOjYzMAoJLy8gZmluZFJldCA9IHRoaXMuZmluZFBvb2xGb3JTdGFrZXIodmFsaWRhdG9ySWQsIHN0YWtlciwgcmVhbEFtb3VudCkKCWZyYW1lX2RpZyAxIC8vIHJlYWxBbW91bnQ6IHVpbnQ2NAoJZnJhbWVfZGlnIDAgLy8gc3Rha2VyOiBhZGRyZXNzCglmcmFtZV9kaWcgLTIgLy8gdmFsaWRhdG9ySWQ6IFZhbGlkYXRvcklkVHlwZQoJY2FsbHN1YiBmaW5kUG9vbEZvclN0YWtlcgoJZnJhbWVfYnVyeSAzIC8vIGZpbmRSZXQ6ICgodWludDY0LHVpbnQ2NCx1aW50NjQpLGJvb2wsYm9vbCkKCgkvLyBjb250cmFjdHMvdmFsaWRhdG9yUmVnaXN0cnkuYWxnby50czo2MzEKCS8vIHBvb2xLZXkgPSBmaW5kUmV0WzBdCgkvLyBjb250cmFjdHMvdmFsaWRhdG9yUmVnaXN0cnkuYWxnby50czo2MzIKCS8vIGlzTmV3U3Rha2VyVG9WYWxpZGF0b3IgPSBmaW5kUmV0WzFdCglmcmFtZV9kaWcgMyAvLyBmaW5kUmV0OiAoKHVpbnQ2NCx1aW50NjQsdWludDY0KSxib29sLGJvb2wpCglzdG9yZSAyNTUgLy8gZnVsbCBhcnJheQoJbG9hZCAyNTUgLy8gZnVsbCBhcnJheQoJaW50IDE5MgoJZ2V0Yml0CglmcmFtZV9idXJ5IDQgLy8gaXNOZXdTdGFrZXJUb1ZhbGlkYXRvcjogYm9vbAoKCS8vIGNvbnRyYWN0cy92YWxpZGF0b3JSZWdpc3RyeS5hbGdvLnRzOjYzMwoJLy8gaXNOZXdTdGFrZXJUb1Byb3RvY29sID0gZmluZFJldFsyXQoJZnJhbWVfZGlnIDMgLy8gZmluZFJldDogKCh1aW50NjQsdWludDY0LHVpbnQ2NCksYm9vbCxib29sKQoJc3RvcmUgMjU1IC8vIGZ1bGwgYXJyYXkKCWxvYWQgMjU1IC8vIGZ1bGwgYXJyYXkKCWludCAxOTMKCWdldGJpdAoJZnJhbWVfYnVyeSA1IC8vIGlzTmV3U3Rha2VyVG9Qcm90b2NvbDogYm9vbAoKCS8vICppZjEwX2NvbmRpdGlvbgoJLy8gY29udHJhY3RzL3ZhbGlkYXRvclJlZ2lzdHJ5LmFsZ28udHM6NjM0CgkvLyBwb29sS2V5LnBvb2xJZCA9PT0gMAoJZnJhbWVfZGlnIDMgLy8gZmluZFJldDogKCh1aW50NjQsdWludDY0LHVpbnQ2NCksYm9vbCxib29sKQoJc3RvcmUgMjU1IC8vIGZ1bGwgYXJyYXkKCWxvYWQgMjU1IC8vIGZ1bGwgYXJyYXkKCWV4dHJhY3QgOCA4CglidG9pCglpbnQgMAoJPT0KCWJ6ICppZjEwX2VuZAoKCS8vICppZjEwX2NvbnNlcXVlbnQKCWVyciAvLyAnTm8gcG9vbCBhdmFpbGFibGUgd2l0aCBmcmVlIHN0YWtlLiAgVmFsaWRhdG9yIG5lZWRzIHRvIGFkZCBhbm90aGVyIHBvb2wnCgoqaWYxMF9lbmQ6CgkvLyBjb250cmFjdHMvdmFsaWRhdG9yUmVnaXN0cnkuYWxnby50czo2MzkKCS8vIHRoaXMudXBkYXRlU3Rha2VyUG9vbFNldChzdGFrZXIsIHBvb2xLZXkpCglmcmFtZV9kaWcgMyAvLyBmaW5kUmV0OiAoKHVpbnQ2NCx1aW50NjQsdWludDY0KSxib29sLGJvb2wpCglzdG9yZSAyNTUgLy8gZnVsbCBhcnJheQoJbG9hZCAyNTUgLy8gZnVsbCBhcnJheQoJZXh0cmFjdCAwIDI0CglmcmFtZV9kaWcgMCAvLyBzdGFrZXI6IGFkZHJlc3MKCWNhbGxzdWIgdXBkYXRlU3Rha2VyUG9vbFNldAoKCS8vIGNvbnRyYWN0cy92YWxpZGF0b3JSZWdpc3RyeS5hbGdvLnRzOjY0MgoJLy8gdGhpcy5jYWxsUG9vbEFkZFN0YWtlKAoJLy8gICAgICAgICAgICAgc3Rha2VkQW1vdW50UGF5bWVudCwKCS8vICAgICAgICAgICAgIHBvb2xLZXksCgkvLyAgICAgICAgICAgICBtYnJBbXRMZWZ0QmVoaW5kLAoJLy8gICAgICAgICAgICAgaXNOZXdTdGFrZXJUb1ZhbGlkYXRvciwKCS8vICAgICAgICAgICAgIGlzTmV3U3Rha2VyVG9Qcm90b2NvbAoJLy8gICAgICAgICApCglmcmFtZV9kaWcgNSAvLyBpc05ld1N0YWtlclRvUHJvdG9jb2w6IGJvb2wKCWZyYW1lX2RpZyA0IC8vIGlzTmV3U3Rha2VyVG9WYWxpZGF0b3I6IGJvb2wKCWZyYW1lX2RpZyAyIC8vIG1ickFtdExlZnRCZWhpbmQ6IHVpbnQ2NAoJZnJhbWVfZGlnIDMgLy8gZmluZFJldDogKCh1aW50NjQsdWludDY0LHVpbnQ2NCksYm9vbCxib29sKQoJc3RvcmUgMjU1IC8vIGZ1bGwgYXJyYXkKCWxvYWQgMjU1IC8vIGZ1bGwgYXJyYXkKCWV4dHJhY3QgMCAyNAoJZnJhbWVfZGlnIC0xIC8vIHN0YWtlZEFtb3VudFBheW1lbnQ6IFBheVR4bgoJY2FsbHN1YiBjYWxsUG9vbEFkZFN0YWtlCgoJLy8gY29udHJhY3RzL3ZhbGlkYXRvclJlZ2lzdHJ5LmFsZ28udHM6NjU3CgkvLyByZXR1cm4gcG9vbEtleTsKCWZyYW1lX2RpZyAzIC8vIGZpbmRSZXQ6ICgodWludDY0LHVpbnQ2NCx1aW50NjQpLGJvb2wsYm9vbCkKCXN0b3JlIDI1NSAvLyBmdWxsIGFycmF5Cglsb2FkIDI1NSAvLyBmdWxsIGFycmF5CglleHRyYWN0IDAgMjQKCgkvLyBzZXQgdGhlIHN1YnJvdXRpbmUgcmV0dXJuIHZhbHVlCglmcmFtZV9idXJ5IDAKCgkvLyBwb3AgYWxsIGxvY2FsIHZhcmlhYmxlcyBmcm9tIHRoZSBzdGFjawoJcG9wbiA1CglyZXRzdWIKCi8vIHNldFRva2VuUGF5b3V0UmF0aW8odWludDY0KSh1aW50NjRbMjRdLHVpbnQ2NCkKKmFiaV9yb3V0ZV9zZXRUb2tlblBheW91dFJhdGlvOgoJLy8gVGhlIEFCSSByZXR1cm4gcHJlZml4CglieXRlIDB4MTUxZjdjNzUKCgkvLyB2YWxpZGF0b3JJZDogdWludDY0Cgl0eG5hIEFwcGxpY2F0aW9uQXJncyAxCglidG9pCgoJLy8gZXhlY3V0ZSBzZXRUb2tlblBheW91dFJhdGlvKHVpbnQ2NCkodWludDY0WzI0XSx1aW50NjQpCgljYWxsc3ViIHNldFRva2VuUGF5b3V0UmF0aW8KCWNvbmNhdAoJbG9nCglpbnQgMQoJcmV0dXJuCgovLyBzZXRUb2tlblBheW91dFJhdGlvKHZhbGlkYXRvcklkOiBWYWxpZGF0b3JJZFR5cGUpOiBQb29sVG9rZW5QYXlvdXRSYXRpbwovLwovLyBzZXRUb2tlblBheW91dFJhdGlvIGlzIGNhbGxlZCBieSBTdGFraW5nIFBvb2wgIyAxIChPTkxZKSB0byBhc2sgdGhlIHZhbGlkYXRvciAodXMpIHRvIGNhbGN1bGF0ZSB0aGUgcmF0aW9zCi8vIG9mIHN0YWtlIGluIHRoZSBwb29scyBmb3Igc3Vic2VxdWVudCB0b2tlbiBwYXlvdXRzIChpZTogMiBwb29scywgJzEwMCcgYWxnbyB0b3RhbCBzdGFrZWQsIDYwIGluIHBvb2wgMSwgYW5kIDQwCi8vIGluIHBvb2wgMi4gIFRoaXMgaXMgZG9uZSBzbyB3ZSBoYXZlIGEgc3RhYmxlIHNuYXBzaG90IG9mIHN0YWtlIC0gdGFrZW4gb25jZSBwZXIgZXBvY2ggLSBvbmx5IHRyaWdnZXJlZCBieQovLyBwb29sIDEgZG9pbmcgcGF5b3V0LiAgcG9vbHMgb3RoZXIgdGhhbiAxIGRvaW5nIHBheW91dCBjYWxsIHBvb2wgMSB0byBhc2sgaXQgZG8gaXQgZmlyc3QuCi8vIEl0IHdvdWxkIGJlIDYwLzQwJSBpbiB0aGUgcG9vbFBjdE9mV2hvbGUgdmFsdWVzLiAgVGhlIHRva2VuIHJld2FyZCBwYXlvdXRzIHRoZW4gdXNlIHRoZXNlIHZhbHVlcyBpbnN0ZWFkIG9mCi8vIHRoZWlyICdjdXJyZW50JyBzdGFrZSB3aGljaCBjaGFuZ2VzIGFzIHBhcnQgb2YgdGhlIHBheW91dHMgdGhlbXNlbHZlcyAoYW5kIHBlb3BsZSBjb3VsZCBiZSBjaGFuZ2luZyBzdGFrZQovLyBkdXJpbmcgdGhlIGVwb2NoIHVwZGF0ZXMgYWNyb3NzIHBvb2xzKQovLwovLyBNdWx0aXBsZSBwb29scyB3aWxsIGNhbGwgdXMgdmlhIHBvb2wgMSAocG9vbDItPnBvb2wxLT52YWxkaWF0b3IsIGV0Yy4pIHNvIGRvbid0IGFzc2VydCBvbiBwb29sMSBjYWxsaW5nIG11bHRpcGxlCi8vIHRpbWVzIGluIHNhbWUgZXBvY2guICBKdXN0IHJldHVybi4KLy8KLy8gQHBhcmFtIHZhbGlkYXRvcklkIC0gdmFsaWRhdG9yIGlkIChhbmQgdGh1cyBwb29sKSBjYWxsaW5nIHVzLiAgVmVyaWZpZWQgc28gdGhhdCBzZW5kZXIgTVVTVCBiZSBwb29sIDEgb2YgdGhpcyB2YWxpZGF0b3IuCi8vIEByZXR1cm5zIFBvb2xUb2tlblBheW91dFJhdGlvIC0gdGhlIGZpbmlzaGVkIHJhdGlvIGRhdGEKc2V0VG9rZW5QYXlvdXRSYXRpbzoKCXByb3RvIDEgMQoKCS8vIFB1c2ggZW1wdHkgYnl0ZXMgYWZ0ZXIgdGhlIGZyYW1lIHBvaW50ZXIgdG8gcmVzZXJ2ZSBzcGFjZSBmb3IgbG9jYWwgdmFyaWFibGVzCglieXRlIDB4CglkdXBuIDgKCgkvLyBjb250cmFjdHMvdmFsaWRhdG9yUmVnaXN0cnkuYWxnby50czo2NzcKCS8vIHBvb2wxQXBwSUQgPSB0aGlzLnZhbGlkYXRvckxpc3QodmFsaWRhdG9ySWQpLnZhbHVlLnBvb2xzWzBdLnBvb2xBcHBJZAoJaW50IDIzNAoJaW50IDgKCWJ5dGUgMHg3NiAvLyAidiIKCWZyYW1lX2RpZyAtMSAvLyB2YWxpZGF0b3JJZDogVmFsaWRhdG9ySWRUeXBlCglpdG9iCgljb25jYXQKCWNvdmVyIDIKCWJveF9leHRyYWN0CglidG9pCglmcmFtZV9idXJ5IDAgLy8gcG9vbDFBcHBJRDogdWludDY0CgoJLy8gY29udHJhY3RzL3ZhbGlkYXRvclJlZ2lzdHJ5LmFsZ28udHM6Njc4CgkvLyBhc3NlcnQocG9vbDFBcHBJRCAhPT0gMCkKCWZyYW1lX2RpZyAwIC8vIHBvb2wxQXBwSUQ6IHVpbnQ2NAoJaW50IDAKCSE9Cglhc3NlcnQKCgkvLyAqaWYxMV9jb25kaXRpb24KCS8vIGNvbnRyYWN0cy92YWxpZGF0b3JSZWdpc3RyeS5hbGdvLnRzOjY4MAoJLy8gdGhpcy50eG4uc2VuZGVyICE9PSBBcHBJRC5mcm9tVWludDY0KHBvb2wxQXBwSUQpLmFkZHJlc3MKCXR4biBTZW5kZXIKCWZyYW1lX2RpZyAwIC8vIHBvb2wxQXBwSUQ6IHVpbnQ2NAoJYXBwX3BhcmFtc19nZXQgQXBwQWRkcmVzcwoJcG9wCgkhPQoJYnogKmlmMTFfZW5kCgoJLy8gKmlmMTFfY29uc2VxdWVudAoJLy8gY29udHJhY3RzL3ZhbGlkYXRvclJlZ2lzdHJ5LmFsZ28udHM6NjgxCgkvLyByZXR1cm4gdGhpcy52YWxpZGF0b3JMaXN0KHZhbGlkYXRvcklkKS52YWx1ZS50b2tlblBheW91dFJhdGlvOwoJaW50IDY2NiAvLyBoZWFkT2Zmc2V0CglpbnQgMjAwCglieXRlIDB4NzYgLy8gInYiCglmcmFtZV9kaWcgLTEgLy8gdmFsaWRhdG9ySWQ6IFZhbGlkYXRvcklkVHlwZQoJaXRvYgoJY29uY2F0Cgljb3ZlciAyCglib3hfZXh0cmFjdAoKCS8vIHNldCB0aGUgc3Vicm91dGluZSByZXR1cm4gdmFsdWUKCWZyYW1lX2J1cnkgMAoJcmV0c3ViCgoqaWYxMV9lbmQ6CgkvLyBjb250cmFjdHMvdmFsaWRhdG9yUmVnaXN0cnkuYWxnby50czo2ODYKCS8vIGN1clRpbWUgPSBnbG9iYWxzLmxhdGVzdFRpbWVzdGFtcAoJZ2xvYmFsIExhdGVzdFRpbWVzdGFtcAoJZnJhbWVfYnVyeSAxIC8vIGN1clRpbWU6IHVpbnQ2NAoKCS8vIGNvbnRyYWN0cy92YWxpZGF0b3JSZWdpc3RyeS5hbGdvLnRzOjY4NwoJLy8gbGFzdFBheW91dFVwZGF0ZSA9IHRoaXMudmFsaWRhdG9yTGlzdCh2YWxpZGF0b3JJZCkudmFsdWUudG9rZW5QYXlvdXRSYXRpby51cGRhdGVkRm9yUGF5b3V0CglpbnQgODU4CglpbnQgOAoJYnl0ZSAweDc2IC8vICJ2IgoJZnJhbWVfZGlnIC0xIC8vIHZhbGlkYXRvcklkOiBWYWxpZGF0b3JJZFR5cGUKCWl0b2IKCWNvbmNhdAoJY292ZXIgMgoJYm94X2V4dHJhY3QKCWJ0b2kKCWZyYW1lX2J1cnkgMiAvLyBsYXN0UGF5b3V0VXBkYXRlOiB1aW50NjQKCgkvLyAqaWYxMl9jb25kaXRpb24KCS8vIGNvbnRyYWN0cy92YWxpZGF0b3JSZWdpc3RyeS5hbGdvLnRzOjY4OAoJLy8gbGFzdFBheW91dFVwZGF0ZSAhPT0gMAoJZnJhbWVfZGlnIDIgLy8gbGFzdFBheW91dFVwZGF0ZTogdWludDY0CglpbnQgMAoJIT0KCWJ6ICppZjEyX2VuZAoKCS8vICppZjEyX2NvbnNlcXVlbnQKCS8vICppZjEzX2NvbmRpdGlvbgoJLy8gY29udHJhY3RzL3ZhbGlkYXRvclJlZ2lzdHJ5LmFsZ28udHM6NjkwCgkvLyAoQXBwSUQuZnJvbVVpbnQ2NChwb29sMUFwcElEKS5nbG9iYWxTdGF0ZSgnbGFzdFBheW91dCcpIGFzIHVpbnQ2NCkgPT09IGxhc3RQYXlvdXRVcGRhdGUKCWZyYW1lX2RpZyAwIC8vIHBvb2wxQXBwSUQ6IHVpbnQ2NAoJYnl0ZSAweDZjNjE3Mzc0NTA2MTc5NmY3NTc0IC8vICJsYXN0UGF5b3V0IgoJYXBwX2dsb2JhbF9nZXRfZXgKCWFzc2VydAoJZnJhbWVfZGlnIDIgLy8gbGFzdFBheW91dFVwZGF0ZTogdWludDY0Cgk9PQoJYnogKmlmMTNfZW5kCgoJLy8gKmlmMTNfY29uc2VxdWVudAoJLy8gY29udHJhY3RzL3ZhbGlkYXRvclJlZ2lzdHJ5LmFsZ28udHM6NjkxCgkvLyByZXR1cm4gdGhpcy52YWxpZGF0b3JMaXN0KHZhbGlkYXRvcklkKS52YWx1ZS50b2tlblBheW91dFJhdGlvOwoJaW50IDY2NiAvLyBoZWFkT2Zmc2V0CglpbnQgMjAwCglieXRlIDB4NzYgLy8gInYiCglmcmFtZV9kaWcgLTEgLy8gdmFsaWRhdG9ySWQ6IFZhbGlkYXRvcklkVHlwZQoJaXRvYgoJY29uY2F0Cgljb3ZlciAyCglib3hfZXh0cmFjdAoKCS8vIHNldCB0aGUgc3Vicm91dGluZSByZXR1cm4gdmFsdWUKCWZyYW1lX2J1cnkgMAoKCS8vIHBvcCBhbGwgbG9jYWwgdmFyaWFibGVzIGZyb20gdGhlIHN0YWNrCglwb3BuIDIKCXJldHN1YgoKKmlmMTNfZW5kOgoJLy8gY29udHJhY3RzL3ZhbGlkYXRvclJlZ2lzdHJ5LmFsZ28udHM6NjkzCgkvLyBzZWNzU2luY2VMYXN0UGF5b3V0ID0gY3VyVGltZSAtIGxhc3RQYXlvdXRVcGRhdGUKCWZyYW1lX2RpZyAxIC8vIGN1clRpbWU6IHVpbnQ2NAoJZnJhbWVfZGlnIDIgLy8gbGFzdFBheW91dFVwZGF0ZTogdWludDY0CgktCglmcmFtZV9idXJ5IDMgLy8gc2Vjc1NpbmNlTGFzdFBheW91dDogdWludDY0CgoJLy8gY29udHJhY3RzL3ZhbGlkYXRvclJlZ2lzdHJ5LmFsZ28udHM6Njk0CgkvLyBlcG9jaEluU2VjcyA9ICh0aGlzLnZhbGlkYXRvckxpc3QodmFsaWRhdG9ySWQpLnZhbHVlLmNvbmZpZy5wYXlvdXRFdmVyeVhNaW5zIGFzIHVpbnQ2NCkgKiA2MAoJaW50IDEzNwoJaW50IDIKCWJ5dGUgMHg3NiAvLyAidiIKCWZyYW1lX2RpZyAtMSAvLyB2YWxpZGF0b3JJZDogVmFsaWRhdG9ySWRUeXBlCglpdG9iCgljb25jYXQKCWNvdmVyIDIKCWJveF9leHRyYWN0CglidG9pCglpbnQgNjAKCSoKCWZyYW1lX2J1cnkgNCAvLyBlcG9jaEluU2VjczogdWludDY0CgoJLy8gKmlmMTRfY29uZGl0aW9uCgkvLyBjb250cmFjdHMvdmFsaWRhdG9yUmVnaXN0cnkuYWxnby50czo2OTYKCS8vIHNlY3NTaW5jZUxhc3RQYXlvdXQgPCBlcG9jaEluU2VjcwoJZnJhbWVfZGlnIDMgLy8gc2Vjc1NpbmNlTGFzdFBheW91dDogdWludDY0CglmcmFtZV9kaWcgNCAvLyBlcG9jaEluU2VjczogdWludDY0Cgk8CglieiAqaWYxNF9lbmQKCgkvLyAqaWYxNF9jb25zZXF1ZW50CgkvLyBjb250cmFjdHMvdmFsaWRhdG9yUmVnaXN0cnkuYWxnby50czo2OTcKCS8vIHJldHVybiB0aGlzLnZhbGlkYXRvckxpc3QodmFsaWRhdG9ySWQpLnZhbHVlLnRva2VuUGF5b3V0UmF0aW87CglpbnQgNjY2IC8vIGhlYWRPZmZzZXQKCWludCAyMDAKCWJ5dGUgMHg3NiAvLyAidiIKCWZyYW1lX2RpZyAtMSAvLyB2YWxpZGF0b3JJZDogVmFsaWRhdG9ySWRUeXBlCglpdG9iCgljb25jYXQKCWNvdmVyIDIKCWJveF9leHRyYWN0CgoJLy8gc2V0IHRoZSBzdWJyb3V0aW5lIHJldHVybiB2YWx1ZQoJZnJhbWVfYnVyeSAwCgoJLy8gcG9wIGFsbCBsb2NhbCB2YXJpYWJsZXMgZnJvbSB0aGUgc3RhY2sKCXBvcG4gNAoJcmV0c3ViCgoqaWYxNF9lbmQ6CgoqaWYxMl9lbmQ6CgkvLyBjb250cmFjdHMvdmFsaWRhdG9yUmVnaXN0cnkuYWxnby50czo3MDAKCS8vIHRoaXMudmFsaWRhdG9yTGlzdCh2YWxpZGF0b3JJZCkudmFsdWUudG9rZW5QYXlvdXRSYXRpby51cGRhdGVkRm9yUGF5b3V0ID0gY3VyVGltZQoJaW50IDg1OAoJZnJhbWVfZGlnIDEgLy8gY3VyVGltZTogdWludDY0CglpdG9iCglieXRlIDB4NzYgLy8gInYiCglmcmFtZV9kaWcgLTEgLy8gdmFsaWRhdG9ySWQ6IFZhbGlkYXRvcklkVHlwZQoJaXRvYgoJY29uY2F0Cgljb3ZlciAyCglib3hfcmVwbGFjZQoKCS8vIGNvbnRyYWN0cy92YWxpZGF0b3JSZWdpc3RyeS5hbGdvLnRzOjcwMgoJLy8gY3VyTnVtUG9vbHMgPSB0aGlzLnZhbGlkYXRvckxpc3QodmFsaWRhdG9ySWQpLnZhbHVlLnN0YXRlLm51bVBvb2xzIGFzIHVpbnQ2NAoJaW50IDIwOAoJaW50IDIKCWJ5dGUgMHg3NiAvLyAidiIKCWZyYW1lX2RpZyAtMSAvLyB2YWxpZGF0b3JJZDogVmFsaWRhdG9ySWRUeXBlCglpdG9iCgljb25jYXQKCWNvdmVyIDIKCWJveF9leHRyYWN0CglidG9pCglmcmFtZV9idXJ5IDUgLy8gY3VyTnVtUG9vbHM6IHVpbnQ2NAoKCS8vIGNvbnRyYWN0cy92YWxpZGF0b3JSZWdpc3RyeS5hbGdvLnRzOjcwMwoJLy8gdG90YWxTdGFrZUZvclZhbGlkYXRvciA9IHRoaXMudmFsaWRhdG9yTGlzdCh2YWxpZGF0b3JJZCkudmFsdWUuc3RhdGUudG90YWxBbGdvU3Rha2VkCglpbnQgMjE4CglpbnQgOAoJYnl0ZSAweDc2IC8vICJ2IgoJZnJhbWVfZGlnIC0xIC8vIHZhbGlkYXRvcklkOiBWYWxpZGF0b3JJZFR5cGUKCWl0b2IKCWNvbmNhdAoJY292ZXIgMgoJYm94X2V4dHJhY3QKCWJ0b2kKCWZyYW1lX2J1cnkgNiAvLyB0b3RhbFN0YWtlRm9yVmFsaWRhdG9yOiB1aW50NjQKCgkvLyBjb250cmFjdHMvdmFsaWRhdG9yUmVnaXN0cnkuYWxnby50czo3MDQKCS8vIGZvciAobGV0IGkgPSAwOyBpIDwgY3VyTnVtUG9vbHM7IGkgKz0gMSkKCWludCAwCglmcmFtZV9idXJ5IDcgLy8gaTogdWludDY0CgoqZm9yXzI6CgkvLyBjb250cmFjdHMvdmFsaWRhdG9yUmVnaXN0cnkuYWxnby50czo3MDQKCS8vIGkgPCBjdXJOdW1Qb29scwoJZnJhbWVfZGlnIDcgLy8gaTogdWludDY0CglmcmFtZV9kaWcgNSAvLyBjdXJOdW1Qb29sczogdWludDY0Cgk8CglieiAqZm9yXzJfZW5kCgoJLy8gY29udHJhY3RzL3ZhbGlkYXRvclJlZ2lzdHJ5LmFsZ28udHM6NzA5CgkvLyBvdXJQb29sUGN0T2ZXaG9sZSA9IHdpZGVSYXRpbygKCS8vICAgICAgICAgICAgICAgICBbdGhpcy52YWxpZGF0b3JMaXN0KHZhbGlkYXRvcklkKS52YWx1ZS5wb29sc1tpXS50b3RhbEFsZ29TdGFrZWQsIDFfMDAwXzAwMF0sCgkvLyAgICAgICAgICAgICAgICAgW3RvdGFsU3Rha2VGb3JWYWxpZGF0b3JdCgkvLyAgICAgICAgICAgICApCglpbnQgMjM0IC8vIGhlYWRPZmZzZXQKCWZyYW1lX2RpZyA3IC8vIGk6IHVpbnQ2NAoJaW50IDE4CgkqIC8vIGFjYyAqIHR5cGVMZW5ndGgKCSsKCWludCAxMCAvLyBoZWFkT2Zmc2V0CgkrCglpbnQgOAoJYnl0ZSAweDc2IC8vICJ2IgoJZnJhbWVfZGlnIC0xIC8vIHZhbGlkYXRvcklkOiBWYWxpZGF0b3JJZFR5cGUKCWl0b2IKCWNvbmNhdAoJY292ZXIgMgoJYm94X2V4dHJhY3QKCWJ0b2kKCWludCAxXzAwMF8wMDAKCW11bHcKCWludCAwCglmcmFtZV9kaWcgNiAvLyB0b3RhbFN0YWtlRm9yVmFsaWRhdG9yOiB1aW50NjQKCWRpdm1vZHcKCXBvcAoJcG9wCglzd2FwCgkhCglhc3NlcnQKCWZyYW1lX2J1cnkgOCAvLyBvdXJQb29sUGN0T2ZXaG9sZTogdWludDY0CgoJLy8gY29udHJhY3RzL3ZhbGlkYXRvclJlZ2lzdHJ5LmFsZ28udHM6NzEzCgkvLyB0aGlzLnZhbGlkYXRvckxpc3QodmFsaWRhdG9ySWQpLnZhbHVlLnRva2VuUGF5b3V0UmF0aW8ucG9vbFBjdE9mV2hvbGVbaV0gPSBvdXJQb29sUGN0T2ZXaG9sZQoJaW50IDY2NgoJZnJhbWVfZGlnIDcgLy8gaTogdWludDY0CglpbnQgOAoJKiAvLyBhY2MgKiB0eXBlTGVuZ3RoCgkrCglmcmFtZV9kaWcgOCAvLyBvdXJQb29sUGN0T2ZXaG9sZTogdWludDY0CglpdG9iCglieXRlIDB4NzYgLy8gInYiCglmcmFtZV9kaWcgLTEgLy8gdmFsaWRhdG9ySWQ6IFZhbGlkYXRvcklkVHlwZQoJaXRvYgoJY29uY2F0Cgljb3ZlciAyCglib3hfcmVwbGFjZQoKKmZvcl8yX2NvbnRpbnVlOgoJLy8gY29udHJhY3RzL3ZhbGlkYXRvclJlZ2lzdHJ5LmFsZ28udHM6NzA0CgkvLyBpICs9IDEKCWZyYW1lX2RpZyA3IC8vIGk6IHVpbnQ2NAoJaW50IDEKCSsKCWZyYW1lX2J1cnkgNyAvLyBpOiB1aW50NjQKCWIgKmZvcl8yCgoqZm9yXzJfZW5kOgoJLy8gY29udHJhY3RzL3ZhbGlkYXRvclJlZ2lzdHJ5LmFsZ28udHM6NzE1CgkvLyByZXR1cm4gdGhpcy52YWxpZGF0b3JMaXN0KHZhbGlkYXRvcklkKS52YWx1ZS50b2tlblBheW91dFJhdGlvOwoJaW50IDY2NiAvLyBoZWFkT2Zmc2V0CglpbnQgMjAwCglieXRlIDB4NzYgLy8gInYiCglmcmFtZV9kaWcgLTEgLy8gdmFsaWRhdG9ySWQ6IFZhbGlkYXRvcklkVHlwZQoJaXRvYgoJY29uY2F0Cgljb3ZlciAyCglib3hfZXh0cmFjdAoKCS8vIHNldCB0aGUgc3Vicm91dGluZSByZXR1cm4gdmFsdWUKCWZyYW1lX2J1cnkgMAoKCS8vIHBvcCBhbGwgbG9jYWwgdmFyaWFibGVzIGZyb20gdGhlIHN0YWNrCglwb3BuIDgKCXJldHN1YgoKLy8gc3Rha2VVcGRhdGVkVmlhUmV3YXJkcygodWludDY0LHVpbnQ2NCx1aW50NjQpLHVpbnQ2NCx1aW50NjQpdm9pZAoqYWJpX3JvdXRlX3N0YWtlVXBkYXRlZFZpYVJld2FyZHM6CgkvLyByZXdhcmRUb2tlbkFtb3VudFJlc2VydmVkOiB1aW50NjQKCXR4bmEgQXBwbGljYXRpb25BcmdzIDMKCWJ0b2kKCgkvLyBhbGdvVG9BZGQ6IHVpbnQ2NAoJdHhuYSBBcHBsaWNhdGlvbkFyZ3MgMgoJYnRvaQoKCS8vIHBvb2xLZXk6ICh1aW50NjQsdWludDY0LHVpbnQ2NCkKCXR4bmEgQXBwbGljYXRpb25BcmdzIDEKCWR1cAoJbGVuCglpbnQgMjQKCT09Cglhc3NlcnQKCgkvLyBleGVjdXRlIHN0YWtlVXBkYXRlZFZpYVJld2FyZHMoKHVpbnQ2NCx1aW50NjQsdWludDY0KSx1aW50NjQsdWludDY0KXZvaWQKCWNhbGxzdWIgc3Rha2VVcGRhdGVkVmlhUmV3YXJkcwoJaW50IDEKCXJldHVybgoKLy8gc3Rha2VVcGRhdGVkVmlhUmV3YXJkcyhwb29sS2V5OiBWYWxpZGF0b3JQb29sS2V5LCBhbGdvVG9BZGQ6IHVpbnQ2NCwgcmV3YXJkVG9rZW5BbW91bnRSZXNlcnZlZDogdWludDY0KTogdm9pZAovLwovLyBzdGFrZVVwZGF0ZWRWaWFSZXdhcmRzIGlzIGNhbGxlZCBieSBTdGFraW5nIHBvb2xzIHRvIGluZm9ybSB0aGUgdmFsaWRhdG9yICh1cykgdGhhdCBhIHBhcnRpY3VsYXIgYW1vdW50IG9mIHRvdGFsCi8vIHN0YWtlIGhhcyBiZWVuIGFkZGVkIHRvIHRoZSBzcGVjaWZpZWQgcG9vbC4gIFRoaXMgaXMgdXNlZCB0byB1cGRhdGUgdGhlIHN0YXRzIHdlIGhhdmUgaW4gb3VyIFBvb2xJbmZvIHN0b3JhZ2UuCi8vIFRoZSBjYWxsaW5nIEFwcCBpZCBpcyB2YWxpZGF0ZWQgYWdhaW5zdCBvdXIgcG9vbCBsaXN0IGFzIHdlbGwuCi8vIEBwYXJhbSB7VmFsaWRhdG9yUG9vbEtleX0gcG9vbEtleSAtIFZhbGlkYXRvclBvb2xLZXkgdHlwZQovLyBAcGFyYW0ge3VpbnQ2NH0gYWxnb1RvQWRkIC0gYW1vdW50IHRoaXMgdmFsaWRhdG9yJ3MgdG90YWwgc3Rha2UgaW5jcmVhc2VkIHZpYSByZXdhcmRzCi8vIEBwYXJhbSB7dWludDY0fSByZXdhcmRUb2tlbkFtb3VudFJlc2VydmVkIC0gYW1vdW50IHRoaXMgdmFsaWRhdG9yJ3MgdG90YWwgc3Rha2UgaW5jcmVhc2VkIHZpYSByZXdhcmRzICh0aGF0IHNob3VsZCBiZQovLyBzZWVuIGFzICdhY2NvdW50ZWQgZm9yL3BlbmRpbmcgc3BlbnQnKQpzdGFrZVVwZGF0ZWRWaWFSZXdhcmRzOgoJcHJvdG8gMyAwCgoJLy8gY29udHJhY3RzL3ZhbGlkYXRvclJlZ2lzdHJ5LmFsZ28udHM6NzI4CgkvLyB0aGlzLnZlcmlmeVBvb2xLZXlDYWxsZXIocG9vbEtleSkKCWZyYW1lX2RpZyAtMSAvLyBwb29sS2V5OiBWYWxpZGF0b3JQb29sS2V5CgljYWxsc3ViIHZlcmlmeVBvb2xLZXlDYWxsZXIKCgkvLyBjb250cmFjdHMvdmFsaWRhdG9yUmVnaXN0cnkuYWxnby50czo3MzEKCS8vIHRoaXMudmFsaWRhdG9yTGlzdChwb29sS2V5LmlkKS52YWx1ZS5wb29sc1twb29sS2V5LnBvb2xJZCAtIDFdLnRvdGFsQWxnb1N0YWtlZCArPSBhbGdvVG9BZGQKCWludCAyMzQgLy8gaGVhZE9mZnNldAoJZnJhbWVfZGlnIC0xIC8vIHBvb2xLZXk6IFZhbGlkYXRvclBvb2xLZXkKCWV4dHJhY3QgOCA4CglidG9pCglpbnQgMQoJLQoJaW50IDE4CgkqIC8vIGFjYyAqIHR5cGVMZW5ndGgKCSsKCWludCAxMCAvLyBoZWFkT2Zmc2V0CgkrCglpbnQgMjM0IC8vIGhlYWRPZmZzZXQKCWZyYW1lX2RpZyAtMSAvLyBwb29sS2V5OiBWYWxpZGF0b3JQb29sS2V5CglleHRyYWN0IDggOAoJYnRvaQoJaW50IDEKCS0KCWludCAxOAoJKiAvLyBhY2MgKiB0eXBlTGVuZ3RoCgkrCglpbnQgMTAgLy8gaGVhZE9mZnNldAoJKwoJaW50IDgKCWJ5dGUgMHg3NiAvLyAidiIKCWZyYW1lX2RpZyAtMSAvLyBwb29sS2V5OiBWYWxpZGF0b3JQb29sS2V5CglleHRyYWN0IDAgOAoJYnRvaQoJaXRvYgoJY29uY2F0Cgljb3ZlciAyCglib3hfZXh0cmFjdAoJYnRvaQoJZnJhbWVfZGlnIC0yIC8vIGFsZ29Ub0FkZDogdWludDY0CgkrCglpdG9iCglieXRlIDB4NzYgLy8gInYiCglmcmFtZV9kaWcgLTEgLy8gcG9vbEtleTogVmFsaWRhdG9yUG9vbEtleQoJZXh0cmFjdCAwIDgKCWJ0b2kKCWl0b2IKCWNvbmNhdAoJY292ZXIgMgoJYm94X3JlcGxhY2UKCgkvLyBjb250cmFjdHMvdmFsaWRhdG9yUmVnaXN0cnkuYWxnby50czo3MzIKCS8vIHRoaXMudmFsaWRhdG9yTGlzdChwb29sS2V5LmlkKS52YWx1ZS5zdGF0ZS50b3RhbEFsZ29TdGFrZWQgKz0gYWxnb1RvQWRkCglpbnQgMjE4CglkdXAKCWludCA4CglieXRlIDB4NzYgLy8gInYiCglmcmFtZV9kaWcgLTEgLy8gcG9vbEtleTogVmFsaWRhdG9yUG9vbEtleQoJZXh0cmFjdCAwIDgKCWJ0b2kKCWl0b2IKCWNvbmNhdAoJY292ZXIgMgoJYm94X2V4dHJhY3QKCWJ0b2kKCWZyYW1lX2RpZyAtMiAvLyBhbGdvVG9BZGQ6IHVpbnQ2NAoJKwoJaXRvYgoJYnl0ZSAweDc2IC8vICJ2IgoJZnJhbWVfZGlnIC0xIC8vIHBvb2xLZXk6IFZhbGlkYXRvclBvb2xLZXkKCWV4dHJhY3QgMCA4CglidG9pCglpdG9iCgljb25jYXQKCWNvdmVyIDIKCWJveF9yZXBsYWNlCgoJLy8gY29udHJhY3RzL3ZhbGlkYXRvclJlZ2lzdHJ5LmFsZ28udHM6NzMzCgkvLyB0aGlzLnZhbGlkYXRvckxpc3QocG9vbEtleS5pZCkudmFsdWUuc3RhdGUucmV3YXJkVG9rZW5IZWxkQmFjayArPSByZXdhcmRUb2tlbkFtb3VudFJlc2VydmVkCglpbnQgMjI2CglkdXAKCWludCA4CglieXRlIDB4NzYgLy8gInYiCglmcmFtZV9kaWcgLTEgLy8gcG9vbEtleTogVmFsaWRhdG9yUG9vbEtleQoJZXh0cmFjdCAwIDgKCWJ0b2kKCWl0b2IKCWNvbmNhdAoJY292ZXIgMgoJYm94X2V4dHJhY3QKCWJ0b2kKCWZyYW1lX2RpZyAtMyAvLyByZXdhcmRUb2tlbkFtb3VudFJlc2VydmVkOiB1aW50NjQKCSsKCWl0b2IKCWJ5dGUgMHg3NiAvLyAidiIKCWZyYW1lX2RpZyAtMSAvLyBwb29sS2V5OiBWYWxpZGF0b3JQb29sS2V5CglleHRyYWN0IDAgOAoJYnRvaQoJaXRvYgoJY29uY2F0Cgljb3ZlciAyCglib3hfcmVwbGFjZQoKCS8vIGNvbnRyYWN0cy92YWxpZGF0b3JSZWdpc3RyeS5hbGdvLnRzOjczNQoJLy8gdGhpcy50b3RhbEFsZ29TdGFrZWQudmFsdWUgKz0gYWxnb1RvQWRkCglieXRlIDB4NzM3NDYxNmI2NTY0IC8vICJzdGFrZWQiCglhcHBfZ2xvYmFsX2dldAoJZnJhbWVfZGlnIC0yIC8vIGFsZ29Ub0FkZDogdWludDY0CgkrCglieXRlIDB4NzM3NDYxNmI2NTY0IC8vICJzdGFrZWQiCglzd2FwCglhcHBfZ2xvYmFsX3B1dAoKCS8vIGNvbnRyYWN0cy92YWxpZGF0b3JSZWdpc3RyeS5hbGdvLnRzOjczOAoJLy8gdGhpcy5yZXZlcmlmeU5GRE93bmVyc2hpcChwb29sS2V5LmlkKQoJZnJhbWVfZGlnIC0xIC8vIHBvb2xLZXk6IFZhbGlkYXRvclBvb2xLZXkKCWV4dHJhY3QgMCA4CglidG9pCgljYWxsc3ViIHJldmVyaWZ5TkZET3duZXJzaGlwCglyZXRzdWIKCi8vIHN0YWtlUmVtb3ZlZCgodWludDY0LHVpbnQ2NCx1aW50NjQpLGFkZHJlc3MsdWludDY0LHVpbnQ2NCxib29sKXZvaWQKKmFiaV9yb3V0ZV9zdGFrZVJlbW92ZWQ6CgkvLyBzdGFrZXJSZW1vdmVkOiBib29sCgl0eG5hIEFwcGxpY2F0aW9uQXJncyA1CglkdXAKCWxlbgoJaW50IDEKCT09Cglhc3NlcnQKCWludCAwCglnZXRiaXQKCgkvLyByZXdhcmRSZW1vdmVkOiB1aW50NjQKCXR4bmEgQXBwbGljYXRpb25BcmdzIDQKCWJ0b2kKCgkvLyBhbW91bnRSZW1vdmVkOiB1aW50NjQKCXR4bmEgQXBwbGljYXRpb25BcmdzIDMKCWJ0b2kKCgkvLyBzdGFrZXI6IGFkZHJlc3MKCXR4bmEgQXBwbGljYXRpb25BcmdzIDIKCWR1cAoJbGVuCglpbnQgMzIKCT09Cglhc3NlcnQKCgkvLyBwb29sS2V5OiAodWludDY0LHVpbnQ2NCx1aW50NjQpCgl0eG5hIEFwcGxpY2F0aW9uQXJncyAxCglkdXAKCWxlbgoJaW50IDI0Cgk9PQoJYXNzZXJ0CgoJLy8gZXhlY3V0ZSBzdGFrZVJlbW92ZWQoKHVpbnQ2NCx1aW50NjQsdWludDY0KSxhZGRyZXNzLHVpbnQ2NCx1aW50NjQsYm9vbCl2b2lkCgljYWxsc3ViIHN0YWtlUmVtb3ZlZAoJaW50IDEKCXJldHVybgoKLy8gc3Rha2VSZW1vdmVkKHBvb2xLZXk6IFZhbGlkYXRvclBvb2xLZXksIHN0YWtlcjogQWRkcmVzcywgYW1vdW50UmVtb3ZlZDogdWludDY0LCByZXdhcmRSZW1vdmVkOiB1aW50NjQsIHN0YWtlclJlbW92ZWQ6IGJvb2xlYW4pOiB2b2lkCi8vCi8vIHN0YWtlUmVtb3ZlZCBpcyBjYWxsZWQgYnkgU3Rha2luZyBwb29scyB0byBpbmZvcm0gdGhlIHZhbGlkYXRvciAodXMpIHRoYXQgYSBwYXJ0aWN1bGFyIGFtb3VudCBvZiB0b3RhbCBzdGFrZSBoYXMgYmVlbiByZW1vdmVkCi8vIGZyb20gdGhlIHNwZWNpZmllZCBwb29sLiAgVGhpcyBpcyB1c2VkIHRvIHVwZGF0ZSB0aGUgc3RhdHMgd2UgaGF2ZSBpbiBvdXIgUG9vbEluZm8gc3RvcmFnZS4KLy8gSWYgYW55IGFtb3VudCBvZiByZXdhcmRSZW1vdmVkIGlzIHNwZWNpZmllZCwgdGhlbiB0aGF0IGFtb3VudCBvZiByZXdhcmQgaXMgc2VudCB0byB0aGUgdXNlCi8vIFRoZSBjYWxsaW5nIEFwcCBpZCBpcyB2YWxpZGF0ZWQgYWdhaW5zdCBvdXIgcG9vbCBsaXN0IGFzIHdlbGwuCi8vCi8vIEBwYXJhbSB7VmFsaWRhdG9yUG9vbEtleX0gcG9vbEtleSBjYWxsaW5nIHVzIGZyb20gd2hpY2ggc3Rha2Ugd2FzIHJlbW92ZWQKLy8gQHBhcmFtIHtBZGRyZXNzfSBzdGFrZXIKLy8gQHBhcmFtIHt1aW50NjR9IGFtb3VudFJlbW92ZWQgLSBhbGdvIGFtb3VudCByZW1vdmVkCi8vIEBwYXJhbSB7dWludDY0fSByZXdhcmRSZW1vdmVkIC0gaWYgYXBwbGljYWJsZSwgYW1vdW50IG9mIHRva2VuIHJld2FyZCByZW1vdmVkIChieSBwb29sIDEgY2FsbGVyKSBvciBUTyByZW1vdmUgYW5kIHBheSBvdXQgKHZpYSBwb29sIDEgZnJvbSBkaWZmZXJlbnQgcG9vbCBjYWxsZXIpCi8vIEBwYXJhbSB7Ym9vbGVhbn0gc3Rha2VyUmVtb3ZlZApzdGFrZVJlbW92ZWQ6Cglwcm90byA1IDAKCgkvLyBQdXNoIGVtcHR5IGJ5dGVzIGFmdGVyIHRoZSBmcmFtZSBwb2ludGVyIHRvIHJlc2VydmUgc3BhY2UgZm9yIGxvY2FsIHZhcmlhYmxlcwoJYnl0ZSAweAoJZHVwbiAzCgoJLy8gKmlmMTVfY29uZGl0aW9uCgkvLyBjb250cmFjdHMvdmFsaWRhdG9yUmVnaXN0cnkuYWxnby50czo3NjgKCS8vIGdsb2JhbHMub3Bjb2RlQnVkZ2V0IDwgMzAwCglnbG9iYWwgT3Bjb2RlQnVkZ2V0CglpbnQgMzAwCgk8CglieiAqaWYxNV9lbmQKCgkvLyAqaWYxNV9jb25zZXF1ZW50CgkvLyBjb250cmFjdHMvdmFsaWRhdG9yUmVnaXN0cnkuYWxnby50czo3NjkKCS8vIGluY3JlYXNlT3Bjb2RlQnVkZ2V0KCkKCWl0eG5fYmVnaW4KCWludCBhcHBsCglpdHhuX2ZpZWxkIFR5cGVFbnVtCglpbnQgMAoJaXR4bl9maWVsZCBGZWUKCWJ5dGUgYjY0IENvRUIgLy8gI3ByYWdtYSB2ZXJzaW9uIDEwOyBpbnQgMQoJZHVwCglpdHhuX2ZpZWxkIEFwcHJvdmFsUHJvZ3JhbQoJaXR4bl9maWVsZCBDbGVhclN0YXRlUHJvZ3JhbQoJaW50IERlbGV0ZUFwcGxpY2F0aW9uCglpdHhuX2ZpZWxkIE9uQ29tcGxldGlvbgoJaXR4bl9zdWJtaXQKCippZjE1X2VuZDoKCS8vIGNvbnRyYWN0cy92YWxpZGF0b3JSZWdpc3RyeS5hbGdvLnRzOjc3MQoJLy8gdGhpcy52ZXJpZnlQb29sS2V5Q2FsbGVyKHBvb2xLZXkpCglmcmFtZV9kaWcgLTEgLy8gcG9vbEtleTogVmFsaWRhdG9yUG9vbEtleQoJY2FsbHN1YiB2ZXJpZnlQb29sS2V5Q2FsbGVyCgoJLy8gY29udHJhY3RzL3ZhbGlkYXRvclJlZ2lzdHJ5LmFsZ28udHM6Nzc1CgkvLyBhc3NlcnQoYW1vdW50UmVtb3ZlZCA+IDAgfHwgcmV3YXJkUmVtb3ZlZCA+IDApCglmcmFtZV9kaWcgLTMgLy8gYW1vdW50UmVtb3ZlZDogdWludDY0CglpbnQgMAoJPgoJZHVwCglibnogKnNraXBfb3IyCglmcmFtZV9kaWcgLTQgLy8gcmV3YXJkUmVtb3ZlZDogdWludDY0CglpbnQgMAoJPgoJfHwKCipza2lwX29yMjoKCWFzc2VydAoKCS8vIGNvbnRyYWN0cy92YWxpZGF0b3JSZWdpc3RyeS5hbGdvLnRzOjc3OAoJLy8gdGhpcy52YWxpZGF0b3JMaXN0KHBvb2xLZXkuaWQpLnZhbHVlLnBvb2xzW3Bvb2xLZXkucG9vbElkIC0gMV0udG90YWxBbGdvU3Rha2VkIC09IGFtb3VudFJlbW92ZWQKCWludCAyMzQgLy8gaGVhZE9mZnNldAoJZnJhbWVfZGlnIC0xIC8vIHBvb2xLZXk6IFZhbGlkYXRvclBvb2xLZXkKCWV4dHJhY3QgOCA4CglidG9pCglpbnQgMQoJLQoJaW50IDE4CgkqIC8vIGFjYyAqIHR5cGVMZW5ndGgKCSsKCWludCAxMCAvLyBoZWFkT2Zmc2V0CgkrCglpbnQgMjM0IC8vIGhlYWRPZmZzZXQKCWZyYW1lX2RpZyAtMSAvLyBwb29sS2V5OiBWYWxpZGF0b3JQb29sS2V5CglleHRyYWN0IDggOAoJYnRvaQoJaW50IDEKCS0KCWludCAxOAoJKiAvLyBhY2MgKiB0eXBlTGVuZ3RoCgkrCglpbnQgMTAgLy8gaGVhZE9mZnNldAoJKwoJaW50IDgKCWJ5dGUgMHg3NiAvLyAidiIKCWZyYW1lX2RpZyAtMSAvLyBwb29sS2V5OiBWYWxpZGF0b3JQb29sS2V5CglleHRyYWN0IDAgOAoJYnRvaQoJaXRvYgoJY29uY2F0Cgljb3ZlciAyCglib3hfZXh0cmFjdAoJYnRvaQoJZnJhbWVfZGlnIC0zIC8vIGFtb3VudFJlbW92ZWQ6IHVpbnQ2NAoJLQoJaXRvYgoJYnl0ZSAweDc2IC8vICJ2IgoJZnJhbWVfZGlnIC0xIC8vIHBvb2xLZXk6IFZhbGlkYXRvclBvb2xLZXkKCWV4dHJhY3QgMCA4CglidG9pCglpdG9iCgljb25jYXQKCWNvdmVyIDIKCWJveF9yZXBsYWNlCgoJLy8gY29udHJhY3RzL3ZhbGlkYXRvclJlZ2lzdHJ5LmFsZ28udHM6Nzc5CgkvLyB0aGlzLnZhbGlkYXRvckxpc3QocG9vbEtleS5pZCkudmFsdWUuc3RhdGUudG90YWxBbGdvU3Rha2VkIC09IGFtb3VudFJlbW92ZWQKCWludCAyMTgKCWR1cAoJaW50IDgKCWJ5dGUgMHg3NiAvLyAidiIKCWZyYW1lX2RpZyAtMSAvLyBwb29sS2V5OiBWYWxpZGF0b3JQb29sS2V5CglleHRyYWN0IDAgOAoJYnRvaQoJaXRvYgoJY29uY2F0Cgljb3ZlciAyCglib3hfZXh0cmFjdAoJYnRvaQoJZnJhbWVfZGlnIC0zIC8vIGFtb3VudFJlbW92ZWQ6IHVpbnQ2NAoJLQoJaXRvYgoJYnl0ZSAweDc2IC8vICJ2IgoJZnJhbWVfZGlnIC0xIC8vIHBvb2xLZXk6IFZhbGlkYXRvclBvb2xLZXkKCWV4dHJhY3QgMCA4CglidG9pCglpdG9iCgljb25jYXQKCWNvdmVyIDIKCWJveF9yZXBsYWNlCgoJLy8gY29udHJhY3RzL3ZhbGlkYXRvclJlZ2lzdHJ5LmFsZ28udHM6NzgwCgkvLyB0aGlzLnRvdGFsQWxnb1N0YWtlZC52YWx1ZSAtPSBhbW91bnRSZW1vdmVkCglieXRlIDB4NzM3NDYxNmI2NTY0IC8vICJzdGFrZWQiCglhcHBfZ2xvYmFsX2dldAoJZnJhbWVfZGlnIC0zIC8vIGFtb3VudFJlbW92ZWQ6IHVpbnQ2NAoJLQoJYnl0ZSAweDczNzQ2MTZiNjU2NCAvLyAic3Rha2VkIgoJc3dhcAoJYXBwX2dsb2JhbF9wdXQKCgkvLyAqaWYxNl9jb25kaXRpb24KCS8vIGNvbnRyYWN0cy92YWxpZGF0b3JSZWdpc3RyeS5hbGdvLnRzOjc4MgoJLy8gcmV3YXJkUmVtb3ZlZCA+IDAKCWZyYW1lX2RpZyAtNCAvLyByZXdhcmRSZW1vdmVkOiB1aW50NjQKCWludCAwCgk+CglieiAqaWYxNl9lbHNlCgoJLy8gKmlmMTZfY29uc2VxdWVudAoJLy8gY29udHJhY3RzL3ZhbGlkYXRvclJlZ2lzdHJ5LmFsZ28udHM6NzgzCgkvLyByZXdhcmRUb2tlbklEID0gdGhpcy52YWxpZGF0b3JMaXN0KHBvb2xLZXkuaWQpLnZhbHVlLmNvbmZpZy5yZXdhcmRUb2tlbklkCglpbnQgMTIxCglpbnQgOAoJYnl0ZSAweDc2IC8vICJ2IgoJZnJhbWVfZGlnIC0xIC8vIHBvb2xLZXk6IFZhbGlkYXRvclBvb2xLZXkKCWV4dHJhY3QgMCA4CglidG9pCglpdG9iCgljb25jYXQKCWNvdmVyIDIKCWJveF9leHRyYWN0CglidG9pCglmcmFtZV9idXJ5IDAgLy8gcmV3YXJkVG9rZW5JRDogdWludDY0CgoJLy8gY29udHJhY3RzL3ZhbGlkYXRvclJlZ2lzdHJ5LmFsZ28udHM6Nzg0CgkvLyBhc3NlcnQocmV3YXJkVG9rZW5JRCAhPT0gMCwgInJld2FyZFJlbW92ZWQgY2FuJ3QgYmUgc2V0IGlmIHZhbGlkYXRvciBkb2Vzbid0IGhhdmUgcmV3YXJkIHRva2VuISIpCglmcmFtZV9kaWcgMCAvLyByZXdhcmRUb2tlbklEOiB1aW50NjQKCWludCAwCgkhPQoKCS8vIHJld2FyZFJlbW92ZWQgY2FuJ3QgYmUgc2V0IGlmIHZhbGlkYXRvciBkb2Vzbid0IGhhdmUgcmV3YXJkIHRva2VuIQoJYXNzZXJ0CgoJLy8gY29udHJhY3RzL3ZhbGlkYXRvclJlZ2lzdHJ5LmFsZ28udHM6Nzg1CgkvLyBhc3NlcnQoCgkvLyAgICAgICAgICAgICAgICAgdGhpcy52YWxpZGF0b3JMaXN0KHBvb2xLZXkuaWQpLnZhbHVlLnN0YXRlLnJld2FyZFRva2VuSGVsZEJhY2sgPj0gcmV3YXJkUmVtb3ZlZCwKCS8vICAgICAgICAgICAgICAgICAncmV3YXJkIGJlaW5nIHJlbW92ZWQgbXVzdCBiZSBjb3ZlcmVkIGJ5IGhvbGQgYmFjayBhbW91bnQnCgkvLyAgICAgICAgICAgICApCglpbnQgMjI2CglpbnQgOAoJYnl0ZSAweDc2IC8vICJ2IgoJZnJhbWVfZGlnIC0xIC8vIHBvb2xLZXk6IFZhbGlkYXRvclBvb2xLZXkKCWV4dHJhY3QgMCA4CglidG9pCglpdG9iCgljb25jYXQKCWNvdmVyIDIKCWJveF9leHRyYWN0CglidG9pCglmcmFtZV9kaWcgLTQgLy8gcmV3YXJkUmVtb3ZlZDogdWludDY0Cgk+PQoKCS8vIHJld2FyZCBiZWluZyByZW1vdmVkIG11c3QgYmUgY292ZXJlZCBieSBob2xkIGJhY2sgYW1vdW50Cglhc3NlcnQKCgkvLyBjb250cmFjdHMvdmFsaWRhdG9yUmVnaXN0cnkuYWxnby50czo3OTEKCS8vIHRoaXMudmFsaWRhdG9yTGlzdChwb29sS2V5LmlkKS52YWx1ZS5zdGF0ZS5yZXdhcmRUb2tlbkhlbGRCYWNrIC09IHJld2FyZFJlbW92ZWQKCWludCAyMjYKCWR1cAoJaW50IDgKCWJ5dGUgMHg3NiAvLyAidiIKCWZyYW1lX2RpZyAtMSAvLyBwb29sS2V5OiBWYWxpZGF0b3JQb29sS2V5CglleHRyYWN0IDAgOAoJYnRvaQoJaXRvYgoJY29uY2F0Cgljb3ZlciAyCglib3hfZXh0cmFjdAoJYnRvaQoJZnJhbWVfZGlnIC00IC8vIHJld2FyZFJlbW92ZWQ6IHVpbnQ2NAoJLQoJaXRvYgoJYnl0ZSAweDc2IC8vICJ2IgoJZnJhbWVfZGlnIC0xIC8vIHBvb2xLZXk6IFZhbGlkYXRvclBvb2xLZXkKCWV4dHJhY3QgMCA4CglidG9pCglpdG9iCgljb25jYXQKCWNvdmVyIDIKCWJveF9yZXBsYWNlCgoJLy8gKmlmMTdfY29uZGl0aW9uCgkvLyBjb250cmFjdHMvdmFsaWRhdG9yUmVnaXN0cnkuYWxnby50czo3OTYKCS8vIHBvb2xLZXkucG9vbElkICE9PSAxCglmcmFtZV9kaWcgLTEgLy8gcG9vbEtleTogVmFsaWRhdG9yUG9vbEtleQoJZXh0cmFjdCA4IDgKCWJ0b2kKCWludCAxCgkhPQoJYnogKmlmMTdfZW5kCgoJLy8gKmlmMTdfY29uc2VxdWVudAoJLy8gY29udHJhY3RzL3ZhbGlkYXRvclJlZ2lzdHJ5LmFsZ28udHM6Nzk3CgkvLyBzZW5kTWV0aG9kQ2FsbDx0eXBlb2YgU3Rha2luZ1Bvb2wucHJvdG90eXBlLnBheVRva2VuUmV3YXJkPih7CgkvLyAgICAgICAgICAgICAgICAgICAgIGFwcGxpY2F0aW9uSUQ6IEFwcElELmZyb21VaW50NjQodGhpcy52YWxpZGF0b3JMaXN0KHBvb2xLZXkuaWQpLnZhbHVlLnBvb2xzWzBdLnBvb2xBcHBJZCksCgkvLyAgICAgICAgICAgICAgICAgICAgIG1ldGhvZEFyZ3M6IFtzdGFrZXIsIHJld2FyZFRva2VuSUQsIHJld2FyZFJlbW92ZWRdLAoJLy8gICAgICAgICAgICAgICAgIH0pCglpdHhuX2JlZ2luCglpbnQgYXBwbAoJaXR4bl9maWVsZCBUeXBlRW51bQoJbWV0aG9kICJwYXlUb2tlblJld2FyZChhZGRyZXNzLHVpbnQ2NCx1aW50NjQpdm9pZCIKCWl0eG5fZmllbGQgQXBwbGljYXRpb25BcmdzCgoJLy8gY29udHJhY3RzL3ZhbGlkYXRvclJlZ2lzdHJ5LmFsZ28udHM6Nzk4CgkvLyBhcHBsaWNhdGlvbklEOiBBcHBJRC5mcm9tVWludDY0KHRoaXMudmFsaWRhdG9yTGlzdChwb29sS2V5LmlkKS52YWx1ZS5wb29sc1swXS5wb29sQXBwSWQpCglpbnQgMjM0CglpbnQgOAoJYnl0ZSAweDc2IC8vICJ2IgoJZnJhbWVfZGlnIC0xIC8vIHBvb2xLZXk6IFZhbGlkYXRvclBvb2xLZXkKCWV4dHJhY3QgMCA4CglidG9pCglpdG9iCgljb25jYXQKCWNvdmVyIDIKCWJveF9leHRyYWN0CglidG9pCglpdHhuX2ZpZWxkIEFwcGxpY2F0aW9uSUQKCgkvLyBjb250cmFjdHMvdmFsaWRhdG9yUmVnaXN0cnkuYWxnby50czo3OTkKCS8vIG1ldGhvZEFyZ3M6IFtzdGFrZXIsIHJld2FyZFRva2VuSUQsIHJld2FyZFJlbW92ZWRdCglmcmFtZV9kaWcgLTIgLy8gc3Rha2VyOiBBZGRyZXNzCglpdHhuX2ZpZWxkIEFwcGxpY2F0aW9uQXJncwoJZnJhbWVfZGlnIDAgLy8gcmV3YXJkVG9rZW5JRDogdWludDY0CglpdG9iCglpdHhuX2ZpZWxkIEFwcGxpY2F0aW9uQXJncwoJZnJhbWVfZGlnIC00IC8vIHJld2FyZFJlbW92ZWQ6IHVpbnQ2NAoJaXRvYgoJaXR4bl9maWVsZCBBcHBsaWNhdGlvbkFyZ3MKCgkvLyBGZWUgZmllbGQgbm90IHNldCwgZGVmYXVsdGluZyB0byAwCglpbnQgMAoJaXR4bl9maWVsZCBGZWUKCgkvLyBTdWJtaXQgaW5uZXIgdHJhbnNhY3Rpb24KCWl0eG5fc3VibWl0CgoqaWYxN19lbmQ6CgliICppZjE2X2VuZAoKKmlmMTZfZWxzZToKCippZjE2X2VuZDoKCS8vICppZjE4X2NvbmRpdGlvbgoJLy8gY29udHJhY3RzL3ZhbGlkYXRvclJlZ2lzdHJ5LmFsZ28udHM6ODI0CgkvLyBzdGFrZXJSZW1vdmVkCglmcmFtZV9kaWcgLTUgLy8gc3Rha2VyUmVtb3ZlZDogYm9vbGVhbgoJYnogKmlmMThfZW5kCgoJLy8gKmlmMThfY29uc2VxdWVudAoJLy8gY29udHJhY3RzL3ZhbGlkYXRvclJlZ2lzdHJ5LmFsZ28udHM6ODI2CgkvLyB0aGlzLnZhbGlkYXRvckxpc3QocG9vbEtleS5pZCkudmFsdWUucG9vbHNbcG9vbEtleS5wb29sSWQgLSAxXS50b3RhbFN0YWtlcnMgLT0gMQoJaW50IDIzNCAvLyBoZWFkT2Zmc2V0CglmcmFtZV9kaWcgLTEgLy8gcG9vbEtleTogVmFsaWRhdG9yUG9vbEtleQoJZXh0cmFjdCA4IDgKCWJ0b2kKCWludCAxCgktCglpbnQgMTgKCSogLy8gYWNjICogdHlwZUxlbmd0aAoJKwoJaW50IDggLy8gaGVhZE9mZnNldAoJKwoJaW50IDIzNCAvLyBoZWFkT2Zmc2V0CglmcmFtZV9kaWcgLTEgLy8gcG9vbEtleTogVmFsaWRhdG9yUG9vbEtleQoJZXh0cmFjdCA4IDgKCWJ0b2kKCWludCAxCgktCglpbnQgMTgKCSogLy8gYWNjICogdHlwZUxlbmd0aAoJKwoJaW50IDggLy8gaGVhZE9mZnNldAoJKwoJaW50IDIKCWJ5dGUgMHg3NiAvLyAidiIKCWZyYW1lX2RpZyAtMSAvLyBwb29sS2V5OiBWYWxpZGF0b3JQb29sS2V5CglleHRyYWN0IDAgOAoJYnRvaQoJaXRvYgoJY29uY2F0Cgljb3ZlciAyCglib3hfZXh0cmFjdAoJYnRvaQoJaW50IDEKCS0KCWl0b2IKCWV4dHJhY3QgNiAyCglieXRlIDB4NzYgLy8gInYiCglmcmFtZV9kaWcgLTEgLy8gcG9vbEtleTogVmFsaWRhdG9yUG9vbEtleQoJZXh0cmFjdCAwIDgKCWJ0b2kKCWl0b2IKCWNvbmNhdAoJY292ZXIgMgoJYm94X3JlcGxhY2UKCgkvLyBjb250cmFjdHMvdmFsaWRhdG9yUmVnaXN0cnkuYWxnby50czo4MjgKCS8vIHJlbW92ZVJldCA9IHRoaXMucmVtb3ZlRnJvbVN0YWtlclBvb2xTZXQoc3Rha2VyLCA8VmFsaWRhdG9yUG9vbEtleT57CgkvLyAgICAgICAgICAgICAgICAgaWQ6IHBvb2xLZXkuaWQsCgkvLyAgICAgICAgICAgICAgICAgcG9vbElkOiBwb29sS2V5LnBvb2xJZCwKCS8vICAgICAgICAgICAgICAgICBwb29sQXBwSWQ6IHBvb2xLZXkucG9vbEFwcElkLAoJLy8gICAgICAgICAgICAgfSkKCWZyYW1lX2RpZyAtMSAvLyBwb29sS2V5OiBWYWxpZGF0b3JQb29sS2V5CglleHRyYWN0IDAgOAoJYnRvaQoJaXRvYgoJZnJhbWVfZGlnIC0xIC8vIHBvb2xLZXk6IFZhbGlkYXRvclBvb2xLZXkKCWV4dHJhY3QgOCA4CglidG9pCglpdG9iCgljb25jYXQKCWZyYW1lX2RpZyAtMSAvLyBwb29sS2V5OiBWYWxpZGF0b3JQb29sS2V5CglleHRyYWN0IDE2IDgKCWJ0b2kKCWl0b2IKCWNvbmNhdAoJZnJhbWVfZGlnIC0yIC8vIHN0YWtlcjogQWRkcmVzcwoJY2FsbHN1YiByZW1vdmVGcm9tU3Rha2VyUG9vbFNldAoJZnJhbWVfYnVyeSAxIC8vIHJlbW92ZVJldDogKGJvb2wsYm9vbCkKCgkvLyBjb250cmFjdHMvdmFsaWRhdG9yUmVnaXN0cnkuYWxnby50czo4MzMKCS8vIHN0YWtlck91dE9mVGhpc1ZhbGlkYXRvciA9IHJlbW92ZVJldFswXQoJZnJhbWVfZGlnIDEgLy8gcmVtb3ZlUmV0OiAoYm9vbCxib29sKQoJc3RvcmUgMjU1IC8vIGZ1bGwgYXJyYXkKCWxvYWQgMjU1IC8vIGZ1bGwgYXJyYXkKCWludCAwCglnZXRiaXQKCWZyYW1lX2J1cnkgMiAvLyBzdGFrZXJPdXRPZlRoaXNWYWxpZGF0b3I6IGJvb2wKCgkvLyBjb250cmFjdHMvdmFsaWRhdG9yUmVnaXN0cnkuYWxnby50czo4MzQKCS8vIHN0YWtlck91dE9mUHJvdG9jb2wgPSByZW1vdmVSZXRbMV0KCWZyYW1lX2RpZyAxIC8vIHJlbW92ZVJldDogKGJvb2wsYm9vbCkKCXN0b3JlIDI1NSAvLyBmdWxsIGFycmF5Cglsb2FkIDI1NSAvLyBmdWxsIGFycmF5CglpbnQgMQoJZ2V0Yml0CglmcmFtZV9idXJ5IDMgLy8gc3Rha2VyT3V0T2ZQcm90b2NvbDogYm9vbAoKCS8vICppZjE5X2NvbmRpdGlvbgoJLy8gY29udHJhY3RzL3ZhbGlkYXRvclJlZ2lzdHJ5LmFsZ28udHM6ODM2CgkvLyBzdGFrZXJPdXRPZlRoaXNWYWxpZGF0b3IKCWZyYW1lX2RpZyAyIC8vIHN0YWtlck91dE9mVGhpc1ZhbGlkYXRvcjogYm9vbAoJYnogKmlmMTlfZW5kCgoJLy8gKmlmMTlfY29uc2VxdWVudAoJLy8gY29udHJhY3RzL3ZhbGlkYXRvclJlZ2lzdHJ5LmFsZ28udHM6ODM3CgkvLyB0aGlzLnZhbGlkYXRvckxpc3QocG9vbEtleS5pZCkudmFsdWUuc3RhdGUudG90YWxTdGFrZXJzIC09IDEKCWludCAyMTAKCWR1cAoJaW50IDgKCWJ5dGUgMHg3NiAvLyAidiIKCWZyYW1lX2RpZyAtMSAvLyBwb29sS2V5OiBWYWxpZGF0b3JQb29sS2V5CglleHRyYWN0IDAgOAoJYnRvaQoJaXRvYgoJY29uY2F0Cgljb3ZlciAyCglib3hfZXh0cmFjdAoJYnRvaQoJaW50IDEKCS0KCWl0b2IKCWJ5dGUgMHg3NiAvLyAidiIKCWZyYW1lX2RpZyAtMSAvLyBwb29sS2V5OiBWYWxpZGF0b3JQb29sS2V5CglleHRyYWN0IDAgOAoJYnRvaQoJaXRvYgoJY29uY2F0Cgljb3ZlciAyCglib3hfcmVwbGFjZQoKKmlmMTlfZW5kOgoJLy8gKmlmMjBfY29uZGl0aW9uCgkvLyBjb250cmFjdHMvdmFsaWRhdG9yUmVnaXN0cnkuYWxnby50czo4NDAKCS8vIHN0YWtlck91dE9mUHJvdG9jb2wKCWZyYW1lX2RpZyAzIC8vIHN0YWtlck91dE9mUHJvdG9jb2w6IGJvb2wKCWJ6ICppZjIwX2VuZAoKCS8vICppZjIwX2NvbnNlcXVlbnQKCS8vIGNvbnRyYWN0cy92YWxpZGF0b3JSZWdpc3RyeS5hbGdvLnRzOjg0MQoJLy8gdGhpcy5udW1TdGFrZXJzLnZhbHVlIC09IDEKCWJ5dGUgMHg2ZTc1NmQ1Mzc0NjE2YjY1NzI3MyAvLyAibnVtU3Rha2VycyIKCWFwcF9nbG9iYWxfZ2V0CglpbnQgMQoJLQoJYnl0ZSAweDZlNzU2ZDUzNzQ2MTZiNjU3MjczIC8vICJudW1TdGFrZXJzIgoJc3dhcAoJYXBwX2dsb2JhbF9wdXQKCippZjIwX2VuZDoKCippZjE4X2VuZDoKCXJldHN1YgoKLy8gZmluZFBvb2xGb3JTdGFrZXIodWludDY0LGFkZHJlc3MsdWludDY0KSgodWludDY0LHVpbnQ2NCx1aW50NjQpLGJvb2wsYm9vbCkKKmFiaV9yb3V0ZV9maW5kUG9vbEZvclN0YWtlcjoKCS8vIFRoZSBBQkkgcmV0dXJuIHByZWZpeAoJYnl0ZSAweDE1MWY3Yzc1CgoJLy8gYW1vdW50VG9TdGFrZTogdWludDY0Cgl0eG5hIEFwcGxpY2F0aW9uQXJncyAzCglidG9pCgoJLy8gc3Rha2VyOiBhZGRyZXNzCgl0eG5hIEFwcGxpY2F0aW9uQXJncyAyCglkdXAKCWxlbgoJaW50IDMyCgk9PQoJYXNzZXJ0CgoJLy8gdmFsaWRhdG9ySWQ6IHVpbnQ2NAoJdHhuYSBBcHBsaWNhdGlvbkFyZ3MgMQoJYnRvaQoKCS8vIGV4ZWN1dGUgZmluZFBvb2xGb3JTdGFrZXIodWludDY0LGFkZHJlc3MsdWludDY0KSgodWludDY0LHVpbnQ2NCx1aW50NjQpLGJvb2wsYm9vbCkKCWNhbGxzdWIgZmluZFBvb2xGb3JTdGFrZXIKCWNvbmNhdAoJbG9nCglpbnQgMQoJcmV0dXJuCgovLyBmaW5kUG9vbEZvclN0YWtlcih2YWxpZGF0b3JJZDogVmFsaWRhdG9ySWRUeXBlLCBzdGFrZXI6IEFkZHJlc3MsIGFtb3VudFRvU3Rha2U6IHVpbnQ2NCk6IFtWYWxpZGF0b3JQb29sS2V5LCBib29sZWFuLCBib29sZWFuXQovLwovLyBGaW5kcyB0aGUgcG9vbCBmb3IgYSBzdGFrZXIgYmFzZWQgb24gdGhlIHByb3ZpZGVkIHZhbGlkYXRvciBpZCwgc3Rha2VyIGFkZHJlc3MsIGFuZCBhbW91bnQgdG8gc3Rha2UuCi8vIEZpcnN0IGNoZWNrcyB0aGUgc3Rha2VycyAnYWxyZWFkeSBzdGFrZWQgbGlzdCcgZm9yIHRoZSB2YWxpZGF0b3IgcHJlZmVycmluZyB0aG9zZSAoYWRkaW5nIGlmIHBvc3NpYmxlKSB0aGVuIGFkZHMKLy8gdG8gbmV3IHBvb2wgaWYgbmVjZXNzYXJ5LgovLwovLyBAcGFyYW0ge1ZhbGlkYXRvcklkVHlwZX0gdmFsaWRhdG9ySWQgLSBUaGUgaWQgb2YgdGhlIHZhbGlkYXRvci4KLy8gQHBhcmFtIHtBZGRyZXNzfSBzdGFrZXIgLSBUaGUgYWRkcmVzcyBvZiB0aGUgc3Rha2VyLgovLyBAcGFyYW0ge3VpbnQ2NH0gYW1vdW50VG9TdGFrZSAtIFRoZSBhbW91bnQgdG8gc3Rha2UuCi8vIEByZXR1cm5zIHtWYWxpZGF0b3JQb29sS2V5LCBib29sZWFuLCBib29sZWFufSAtIFRoZSBwb29sIGZvciB0aGUgc3Rha2VyLCB0cnVlL2ZhbHNlIG9uIHdoZXRoZXIgdGhlIHN0YWtlciBpcyAnbmV3JwovLyB0byB0aGlzIFZBTElEQVRPUiwgYW5kIHRydWUvZmFsc2UgaWYgc3Rha2VyIGlzIG5ldyB0byB0aGUgcHJvdG9jb2wuCmZpbmRQb29sRm9yU3Rha2VyOgoJcHJvdG8gMyAxCgoJLy8gUHVzaCBlbXB0eSBieXRlcyBhZnRlciB0aGUgZnJhbWUgcG9pbnRlciB0byByZXNlcnZlIHNwYWNlIGZvciBsb2NhbCB2YXJpYWJsZXMKCWJ5dGUgMHgKCWR1cG4gNwoKCS8vIGNvbnRyYWN0cy92YWxpZGF0b3JSZWdpc3RyeS5hbGdvLnRzOjg2MgoJLy8gaXNOZXdTdGFrZXJUb1ZhbGlkYXRvciA9IHRydWUKCWludCAxCglmcmFtZV9idXJ5IDAgLy8gaXNOZXdTdGFrZXJUb1ZhbGlkYXRvcjogYm9vbAoKCS8vIGNvbnRyYWN0cy92YWxpZGF0b3JSZWdpc3RyeS5hbGdvLnRzOjg2MwoJLy8gaXNOZXdTdGFrZXJUb1Byb3RvY29sID0gdHJ1ZQoJaW50IDEKCWZyYW1lX2J1cnkgMSAvLyBpc05ld1N0YWtlclRvUHJvdG9jb2w6IGJvb2wKCgkvLyBjb250cmFjdHMvdmFsaWRhdG9yUmVnaXN0cnkuYWxnby50czo4NzEKCS8vIG1heFBlclBvb2wgPSB0aGlzLmdldEN1ck1heFN0YWtlUGVyUG9vbCh2YWxpZGF0b3JJZCkKCWZyYW1lX2RpZyAtMSAvLyB2YWxpZGF0b3JJZDogVmFsaWRhdG9ySWRUeXBlCgljYWxsc3ViIGdldEN1ck1heFN0YWtlUGVyUG9vbAoJZnJhbWVfYnVyeSAyIC8vIG1heFBlclBvb2w6IHVpbnQ2NAoKCS8vICppZjIxX2NvbmRpdGlvbgoJLy8gY29udHJhY3RzL3ZhbGlkYXRvclJlZ2lzdHJ5LmFsZ28udHM6ODc0CgkvLyB0aGlzLnN0YWtlclBvb2xTZXQoc3Rha2VyKS5leGlzdHMKCWJ5dGUgMHg3MzcwNzMgLy8gInNwcyIKCWZyYW1lX2RpZyAtMiAvLyBzdGFrZXI6IEFkZHJlc3MKCWNvbmNhdAoJYm94X2xlbgoJc3dhcAoJcG9wCglieiAqaWYyMV9lbmQKCgkvLyAqaWYyMV9jb25zZXF1ZW50CgkvLyBjb250cmFjdHMvdmFsaWRhdG9yUmVnaXN0cnkuYWxnby50czo4NzUKCS8vIHBvb2xTZXQgPSBjbG9uZSh0aGlzLnN0YWtlclBvb2xTZXQoc3Rha2VyKS52YWx1ZSkKCWJ5dGUgMHg3MzcwNzMgLy8gInNwcyIKCWZyYW1lX2RpZyAtMiAvLyBzdGFrZXI6IEFkZHJlc3MKCWNvbmNhdAoJYm94X2dldAoJYXNzZXJ0CglmcmFtZV9idXJ5IDMgLy8gcG9vbFNldDogKHVpbnQ2NCx1aW50NjQsdWludDY0KVs2XQoKCS8vIGNvbnRyYWN0cy92YWxpZGF0b3JSZWdpc3RyeS5hbGdvLnRzOjg3NgoJLy8gYXNzZXJ0KHZhbGlkYXRvcklkICE9PSAwKQoJZnJhbWVfZGlnIC0xIC8vIHZhbGlkYXRvcklkOiBWYWxpZGF0b3JJZFR5cGUKCWludCAwCgkhPQoJYXNzZXJ0CgoJLy8gY29udHJhY3RzL3ZhbGlkYXRvclJlZ2lzdHJ5LmFsZ28udHM6ODc3CgkvLyBmb3IgKGxldCBpID0gMDsgaSA8IHBvb2xTZXQubGVuZ3RoOyBpICs9IDEpCglpbnQgMAoJZnJhbWVfYnVyeSA0IC8vIGk6IHVpbnQ2NAoKKmZvcl8zOgoJLy8gY29udHJhY3RzL3ZhbGlkYXRvclJlZ2lzdHJ5LmFsZ28udHM6ODc3CgkvLyBpIDwgcG9vbFNldC5sZW5ndGgKCWZyYW1lX2RpZyA0IC8vIGk6IHVpbnQ2NAoJaW50IDYKCTwKCWJ6ICpmb3JfM19lbmQKCgkvLyAqaWYyMl9jb25kaXRpb24KCS8vIGNvbnRyYWN0cy92YWxpZGF0b3JSZWdpc3RyeS5hbGdvLnRzOjg3OAoJLy8gZ2xvYmFscy5vcGNvZGVCdWRnZXQgPCAzMDAKCWdsb2JhbCBPcGNvZGVCdWRnZXQKCWludCAzMDAKCTwKCWJ6ICppZjIyX2VuZAoKCS8vICppZjIyX2NvbnNlcXVlbnQKCS8vIGNvbnRyYWN0cy92YWxpZGF0b3JSZWdpc3RyeS5hbGdvLnRzOjg3OQoJLy8gaW5jcmVhc2VPcGNvZGVCdWRnZXQoKQoJaXR4bl9iZWdpbgoJaW50IGFwcGwKCWl0eG5fZmllbGQgVHlwZUVudW0KCWludCAwCglpdHhuX2ZpZWxkIEZlZQoJYnl0ZSBiNjQgQ29FQiAvLyAjcHJhZ21hIHZlcnNpb24gMTA7IGludCAxCglkdXAKCWl0eG5fZmllbGQgQXBwcm92YWxQcm9ncmFtCglpdHhuX2ZpZWxkIENsZWFyU3RhdGVQcm9ncmFtCglpbnQgRGVsZXRlQXBwbGljYXRpb24KCWl0eG5fZmllbGQgT25Db21wbGV0aW9uCglpdHhuX3N1Ym1pdAoKKmlmMjJfZW5kOgoJLy8gKmlmMjNfY29uZGl0aW9uCgkvLyBjb250cmFjdHMvdmFsaWRhdG9yUmVnaXN0cnkuYWxnby50czo4ODEKCS8vIHBvb2xTZXRbaV0uaWQgPT09IDAKCWZyYW1lX2RpZyAzIC8vIHBvb2xTZXQ6ICh1aW50NjQsdWludDY0LHVpbnQ2NClbNl0KCWZyYW1lX2RpZyA0IC8vIGk6IHVpbnQ2NAoJaW50IDI0CgkqIC8vIGFjYyAqIHR5cGVMZW5ndGgKCWludCAwCgkrCglpbnQgOAoJZXh0cmFjdDMKCWJ0b2kKCWludCAwCgk9PQoJYnogKmlmMjNfZW5kCgoJLy8gKmlmMjNfY29uc2VxdWVudAoJYiAqZm9yXzNfY29udGludWUKCippZjIzX2VuZDoKCS8vIGNvbnRyYWN0cy92YWxpZGF0b3JSZWdpc3RyeS5hbGdvLnRzOjg4NAoJLy8gaXNOZXdTdGFrZXJUb1Byb3RvY29sID0gZmFsc2UKCWludCAwCglmcmFtZV9idXJ5IDEgLy8gaXNOZXdTdGFrZXJUb1Byb3RvY29sOiBib29sCgoJLy8gKmlmMjRfY29uZGl0aW9uCgkvLyBjb250cmFjdHMvdmFsaWRhdG9yUmVnaXN0cnkuYWxnby50czo4ODUKCS8vIHBvb2xTZXRbaV0uaWQgPT09IHZhbGlkYXRvcklkCglmcmFtZV9kaWcgMyAvLyBwb29sU2V0OiAodWludDY0LHVpbnQ2NCx1aW50NjQpWzZdCglmcmFtZV9kaWcgNCAvLyBpOiB1aW50NjQKCWludCAyNAoJKiAvLyBhY2MgKiB0eXBlTGVuZ3RoCglpbnQgMAoJKwoJaW50IDgKCWV4dHJhY3QzCglidG9pCglmcmFtZV9kaWcgLTEgLy8gdmFsaWRhdG9ySWQ6IFZhbGlkYXRvcklkVHlwZQoJPT0KCWJ6ICppZjI0X2VuZAoKCS8vICppZjI0X2NvbnNlcXVlbnQKCS8vIGNvbnRyYWN0cy92YWxpZGF0b3JSZWdpc3RyeS5hbGdvLnRzOjg4NwoJLy8gaXNOZXdTdGFrZXJUb1ZhbGlkYXRvciA9IGZhbHNlCglpbnQgMAoJZnJhbWVfYnVyeSAwIC8vIGlzTmV3U3Rha2VyVG9WYWxpZGF0b3I6IGJvb2wKCgkvLyAqaWYyNV9jb25kaXRpb24KCS8vIGNvbnRyYWN0cy92YWxpZGF0b3JSZWdpc3RyeS5hbGdvLnRzOjg4OQoJLy8gdGhpcy52YWxpZGF0b3JMaXN0KHZhbGlkYXRvcklkKS52YWx1ZS5wb29sc1twb29sU2V0W2ldLnBvb2xJZCAtIDFdLnRvdGFsQWxnb1N0YWtlZCArCgkvLyAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYW1vdW50VG9TdGFrZSA8PQoJLy8gICAgICAgICAgICAgICAgICAgICAgICAgbWF4UGVyUG9vbAoJaW50IDIzNCAvLyBoZWFkT2Zmc2V0CglmcmFtZV9kaWcgMyAvLyBwb29sU2V0OiAodWludDY0LHVpbnQ2NCx1aW50NjQpWzZdCglmcmFtZV9kaWcgNCAvLyBpOiB1aW50NjQKCWludCAyNAoJKiAvLyBhY2MgKiB0eXBlTGVuZ3RoCglpbnQgOCAvLyBoZWFkT2Zmc2V0CgkrCglpbnQgOAoJZXh0cmFjdDMKCWJ0b2kKCWludCAxCgktCglpbnQgMTgKCSogLy8gYWNjICogdHlwZUxlbmd0aAoJKwoJaW50IDEwIC8vIGhlYWRPZmZzZXQKCSsKCWludCA4CglieXRlIDB4NzYgLy8gInYiCglmcmFtZV9kaWcgLTEgLy8gdmFsaWRhdG9ySWQ6IFZhbGlkYXRvcklkVHlwZQoJaXRvYgoJY29uY2F0Cgljb3ZlciAyCglib3hfZXh0cmFjdAoJYnRvaQoJZnJhbWVfZGlnIC0zIC8vIGFtb3VudFRvU3Rha2U6IHVpbnQ2NAoJKwoJZnJhbWVfZGlnIDIgLy8gbWF4UGVyUG9vbDogdWludDY0Cgk8PQoJYnogKmlmMjVfZW5kCgoJLy8gKmlmMjVfY29uc2VxdWVudAoJLy8gY29udHJhY3RzL3ZhbGlkYXRvclJlZ2lzdHJ5LmFsZ28udHM6ODkzCgkvLyByZXR1cm4gW3Bvb2xTZXRbaV0sIGlzTmV3U3Rha2VyVG9WYWxpZGF0b3IsIGlzTmV3U3Rha2VyVG9Qcm90b2NvbF07CglmcmFtZV9kaWcgMyAvLyBwb29sU2V0OiAodWludDY0LHVpbnQ2NCx1aW50NjQpWzZdCglmcmFtZV9kaWcgNCAvLyBpOiB1aW50NjQKCWludCAyNAoJKiAvLyBhY2MgKiB0eXBlTGVuZ3RoCglpbnQgMjQKCWV4dHJhY3QzCglieXRlIDB4MDAKCWludCAwCglmcmFtZV9kaWcgMCAvLyBpc05ld1N0YWtlclRvVmFsaWRhdG9yOiBib29sCglzZXRiaXQKCWludCAxCglmcmFtZV9kaWcgMSAvLyBpc05ld1N0YWtlclRvUHJvdG9jb2w6IGJvb2wKCXNldGJpdAoJY29uY2F0CgoJLy8gc2V0IHRoZSBzdWJyb3V0aW5lIHJldHVybiB2YWx1ZQoJZnJhbWVfYnVyeSAwCgoJLy8gcG9wIGFsbCBsb2NhbCB2YXJpYWJsZXMgZnJvbSB0aGUgc3RhY2sKCXBvcG4gNAoJcmV0c3ViCgoqaWYyNV9lbmQ6CgoqaWYyNF9lbmQ6CgoqZm9yXzNfY29udGludWU6CgkvLyBjb250cmFjdHMvdmFsaWRhdG9yUmVnaXN0cnkuYWxnby50czo4NzcKCS8vIGkgKz0gMQoJZnJhbWVfZGlnIDQgLy8gaTogdWludDY0CglpbnQgMQoJKwoJZnJhbWVfYnVyeSA0IC8vIGk6IHVpbnQ2NAoJYiAqZm9yXzMKCipmb3JfM19lbmQ6CgoqaWYyMV9lbmQ6CgkvLyBjb250cmFjdHMvdmFsaWRhdG9yUmVnaXN0cnkuYWxnby50czo5MDAKCS8vIGFzc2VydCgKCS8vICAgICAgICAgICAgIGFtb3VudFRvU3Rha2UgPj0gdGhpcy52YWxpZGF0b3JMaXN0KHZhbGlkYXRvcklkKS52YWx1ZS5jb25maWcubWluRW50cnlTdGFrZSwKCS8vICAgICAgICAgICAgICdtdXN0IHN0YWtlIGF0IGxlYXN0IHRoZSBtaW5pbXVtIGZvciB0aGlzIHBvb2wnCgkvLyAgICAgICAgICkKCWZyYW1lX2RpZyAtMyAvLyBhbW91bnRUb1N0YWtlOiB1aW50NjQKCWludCAxNzUKCWludCA4CglieXRlIDB4NzYgLy8gInYiCglmcmFtZV9kaWcgLTEgLy8gdmFsaWRhdG9ySWQ6IFZhbGlkYXRvcklkVHlwZQoJaXRvYgoJY29uY2F0Cgljb3ZlciAyCglib3hfZXh0cmFjdAoJYnRvaQoJPj0KCgkvLyBtdXN0IHN0YWtlIGF0IGxlYXN0IHRoZSBtaW5pbXVtIGZvciB0aGlzIHBvb2wKCWFzc2VydAoKCS8vIGNvbnRyYWN0cy92YWxpZGF0b3JSZWdpc3RyeS5hbGdvLnRzOjkwNgoJLy8gcG9vbHMgPSBjbG9uZSh0aGlzLnZhbGlkYXRvckxpc3QodmFsaWRhdG9ySWQpLnZhbHVlLnBvb2xzKQoJaW50IDIzNCAvLyBoZWFkT2Zmc2V0CglpbnQgNDMyCglieXRlIDB4NzYgLy8gInYiCglmcmFtZV9kaWcgLTEgLy8gdmFsaWRhdG9ySWQ6IFZhbGlkYXRvcklkVHlwZQoJaXRvYgoJY29uY2F0Cgljb3ZlciAyCglib3hfZXh0cmFjdAoJZnJhbWVfYnVyeSA1IC8vIHBvb2xzOiAodWludDY0LHVpbnQxNix1aW50NjQpWzI0XQoKCS8vIGNvbnRyYWN0cy92YWxpZGF0b3JSZWdpc3RyeS5hbGdvLnRzOjkwNwoJLy8gY3VyTnVtUG9vbHMgPSB0aGlzLnZhbGlkYXRvckxpc3QodmFsaWRhdG9ySWQpLnZhbHVlLnN0YXRlLm51bVBvb2xzIGFzIHVpbnQ2NAoJaW50IDIwOAoJaW50IDIKCWJ5dGUgMHg3NiAvLyAidiIKCWZyYW1lX2RpZyAtMSAvLyB2YWxpZGF0b3JJZDogVmFsaWRhdG9ySWRUeXBlCglpdG9iCgljb25jYXQKCWNvdmVyIDIKCWJveF9leHRyYWN0CglidG9pCglmcmFtZV9idXJ5IDYgLy8gY3VyTnVtUG9vbHM6IHVpbnQ2NAoKCS8vIGNvbnRyYWN0cy92YWxpZGF0b3JSZWdpc3RyeS5hbGdvLnRzOjkwOAoJLy8gZm9yIChsZXQgaSA9IDA7IGkgPCBjdXJOdW1Qb29sczsgaSArPSAxKQoJaW50IDAKCWZyYW1lX2J1cnkgNyAvLyBpOiB1aW50NjQKCipmb3JfNDoKCS8vIGNvbnRyYWN0cy92YWxpZGF0b3JSZWdpc3RyeS5hbGdvLnRzOjkwOAoJLy8gaSA8IGN1ck51bVBvb2xzCglmcmFtZV9kaWcgNyAvLyBpOiB1aW50NjQKCWZyYW1lX2RpZyA2IC8vIGN1ck51bVBvb2xzOiB1aW50NjQKCTwKCWJ6ICpmb3JfNF9lbmQKCgkvLyAqaWYyNl9jb25kaXRpb24KCS8vIGNvbnRyYWN0cy92YWxpZGF0b3JSZWdpc3RyeS5hbGdvLnRzOjkwOQoJLy8gcG9vbHNbaV0udG90YWxBbGdvU3Rha2VkICsgYW1vdW50VG9TdGFrZSA8PSBtYXhQZXJQb29sCglmcmFtZV9kaWcgNSAvLyBwb29sczogKHVpbnQ2NCx1aW50MTYsdWludDY0KVsyNF0KCWZyYW1lX2RpZyA3IC8vIGk6IHVpbnQ2NAoJaW50IDE4CgkqIC8vIGFjYyAqIHR5cGVMZW5ndGgKCWludCAxMCAvLyBoZWFkT2Zmc2V0CgkrCglpbnQgOAoJZXh0cmFjdDMKCWJ0b2kKCWZyYW1lX2RpZyAtMyAvLyBhbW91bnRUb1N0YWtlOiB1aW50NjQKCSsKCWZyYW1lX2RpZyAyIC8vIG1heFBlclBvb2w6IHVpbnQ2NAoJPD0KCWJ6ICppZjI2X2VuZAoKCS8vICppZjI2X2NvbnNlcXVlbnQKCS8vIGNvbnRyYWN0cy92YWxpZGF0b3JSZWdpc3RyeS5hbGdvLnRzOjkxMAoJLy8gcmV0dXJuIFsKCS8vICAgICAgICAgICAgICAgICAgICAgeyBpZDogdmFsaWRhdG9ySWQsIHBvb2xJZDogaSArIDEsIHBvb2xBcHBJZDogcG9vbHNbaV0ucG9vbEFwcElkIH0sCgkvLyAgICAgICAgICAgICAgICAgICAgIGlzTmV3U3Rha2VyVG9WYWxpZGF0b3IsCgkvLyAgICAgICAgICAgICAgICAgICAgIGlzTmV3U3Rha2VyVG9Qcm90b2NvbCwKCS8vICAgICAgICAgICAgICAgICBdOwoJZnJhbWVfZGlnIC0xIC8vIHZhbGlkYXRvcklkOiBWYWxpZGF0b3JJZFR5cGUKCWl0b2IKCWZyYW1lX2RpZyA3IC8vIGk6IHVpbnQ2NAoJaW50IDEKCSsKCWl0b2IKCWNvbmNhdAoJZnJhbWVfZGlnIDUgLy8gcG9vbHM6ICh1aW50NjQsdWludDE2LHVpbnQ2NClbMjRdCglmcmFtZV9kaWcgNyAvLyBpOiB1aW50NjQKCWludCAxOAoJKiAvLyBhY2MgKiB0eXBlTGVuZ3RoCglpbnQgMAoJKwoJaW50IDgKCWV4dHJhY3QzCglidG9pCglpdG9iCgljb25jYXQKCWJ5dGUgMHgwMAoJaW50IDAKCWZyYW1lX2RpZyAwIC8vIGlzTmV3U3Rha2VyVG9WYWxpZGF0b3I6IGJvb2wKCXNldGJpdAoJaW50IDEKCWZyYW1lX2RpZyAxIC8vIGlzTmV3U3Rha2VyVG9Qcm90b2NvbDogYm9vbAoJc2V0Yml0Cgljb25jYXQKCgkvLyBzZXQgdGhlIHN1YnJvdXRpbmUgcmV0dXJuIHZhbHVlCglmcmFtZV9idXJ5IDAKCgkvLyBwb3AgYWxsIGxvY2FsIHZhcmlhYmxlcyBmcm9tIHRoZSBzdGFjawoJcG9wbiA3CglyZXRzdWIKCippZjI2X2VuZDoKCipmb3JfNF9jb250aW51ZToKCS8vIGNvbnRyYWN0cy92YWxpZGF0b3JSZWdpc3RyeS5hbGdvLnRzOjkwOAoJLy8gaSArPSAxCglmcmFtZV9kaWcgNyAvLyBpOiB1aW50NjQKCWludCAxCgkrCglmcmFtZV9idXJ5IDcgLy8gaTogdWludDY0CgliICpmb3JfNAoKKmZvcl80X2VuZDoKCS8vIGNvbnRyYWN0cy92YWxpZGF0b3JSZWdpc3RyeS5hbGdvLnRzOjkxOAoJLy8gcmV0dXJuIFt7IGlkOiB2YWxpZGF0b3JJZCwgcG9vbElkOiAwLCBwb29sQXBwSWQ6IDAgfSwgaXNOZXdTdGFrZXJUb1ZhbGlkYXRvciwgaXNOZXdTdGFrZXJUb1Byb3RvY29sXTsKCWZyYW1lX2RpZyAtMSAvLyB2YWxpZGF0b3JJZDogVmFsaWRhdG9ySWRUeXBlCglpdG9iCglieXRlIDB4MDAwMDAwMDAwMDAwMDAwMAoJY29uY2F0CglieXRlIDB4MDAwMDAwMDAwMDAwMDAwMAoJY29uY2F0CglieXRlIDB4MDAKCWludCAwCglmcmFtZV9kaWcgMCAvLyBpc05ld1N0YWtlclRvVmFsaWRhdG9yOiBib29sCglzZXRiaXQKCWludCAxCglmcmFtZV9kaWcgMSAvLyBpc05ld1N0YWtlclRvUHJvdG9jb2w6IGJvb2wKCXNldGJpdAoJY29uY2F0CgoJLy8gc2V0IHRoZSBzdWJyb3V0aW5lIHJldHVybiB2YWx1ZQoJZnJhbWVfYnVyeSAwCgoJLy8gcG9wIGFsbCBsb2NhbCB2YXJpYWJsZXMgZnJvbSB0aGUgc3RhY2sKCXBvcG4gNwoJcmV0c3ViCgovLyBtb3ZlUG9vbFRvTm9kZSh1aW50NjQsdWludDY0LHVpbnQ2NCl2b2lkCiphYmlfcm91dGVfbW92ZVBvb2xUb05vZGU6CgkvLyBub2RlTnVtOiB1aW50NjQKCXR4bmEgQXBwbGljYXRpb25BcmdzIDMKCWJ0b2kKCgkvLyBwb29sQXBwSWQ6IHVpbnQ2NAoJdHhuYSBBcHBsaWNhdGlvbkFyZ3MgMgoJYnRvaQoKCS8vIHZhbGlkYXRvcklkOiB1aW50NjQKCXR4bmEgQXBwbGljYXRpb25BcmdzIDEKCWJ0b2kKCgkvLyBleGVjdXRlIG1vdmVQb29sVG9Ob2RlKHVpbnQ2NCx1aW50NjQsdWludDY0KXZvaWQKCWNhbGxzdWIgbW92ZVBvb2xUb05vZGUKCWludCAxCglyZXR1cm4KCi8vIG1vdmVQb29sVG9Ob2RlKHZhbGlkYXRvcklkOiBWYWxpZGF0b3JJZFR5cGUsIHBvb2xBcHBJZDogdWludDY0LCBub2RlTnVtOiB1aW50NjQpOiB2b2lkCi8vCi8vIEZpbmQgdGhlIHNwZWNpZmllZCBwb29sIChpbiBhbnkgbm9kZSBudW1iZXIpIGFuZCBtb3ZlIGl0IHRvIHRoZSBzcGVjaWZpZWQgbm9kZS4KLy8gVGhlIHBvb2wgYWNjb3VudCBpcyBmb3JjZWQgb2ZmbGluZSBpZiBtb3ZlZCBzbyBwcmlvciBub2RlIHdpbGwgc3RpbGwgcnVuIGZvciAzMjAgcm91bmRzIGJ1dAovLyBuZXcga2V5IGdvZXMgb25saW5lIG9uIG5ldyBub2RlIHNvb24gYWZ0ZXIgKDMyMCByb3VuZHMgYWZ0ZXIgaXQgZ29lcyBvbmxpbmUpCi8vIE5vLW9wIGlmIHN1Y2Nlc3MsIGFzc2VydHMgaWYgbm90IGZvdW5kIG9yIGNhbid0IG1vdmUgIChubyBzcGFjZSBpbiB0YXJnZXQpCi8vIFsgT05MWSBPV05FUiBPUiBNQU5BR0VSIENBTiBDSEFOR0UgXQovLyBPbmx5IGNhbGxhYmxlIGJ5IG93bmVyIG9yIG1hbmFnZXIKbW92ZVBvb2xUb05vZGU6Cglwcm90byAzIDAKCgkvLyBQdXNoIGVtcHR5IGJ5dGVzIGFmdGVyIHRoZSBmcmFtZSBwb2ludGVyIHRvIHJlc2VydmUgc3BhY2UgZm9yIGxvY2FsIHZhcmlhYmxlcwoJYnl0ZSAweAoJZHVwbiAyCgoJLy8gY29udHJhY3RzL3ZhbGlkYXRvclJlZ2lzdHJ5LmFsZ28udHM6OTMxCgkvLyBhc3NlcnQoCgkvLyAgICAgICAgICAgICB0aGlzLnR4bi5zZW5kZXIgPT09IHRoaXMudmFsaWRhdG9yTGlzdCh2YWxpZGF0b3JJZCkudmFsdWUuY29uZmlnLm93bmVyIHx8CgkvLyAgICAgICAgICAgICAgICAgdGhpcy50eG4uc2VuZGVyID09PSB0aGlzLnZhbGlkYXRvckxpc3QodmFsaWRhdG9ySWQpLnZhbHVlLmNvbmZpZy5tYW5hZ2VyCgkvLyAgICAgICAgICkKCXR4biBTZW5kZXIKCWludCA4CglpbnQgMzIKCWJ5dGUgMHg3NiAvLyAidiIKCWZyYW1lX2RpZyAtMSAvLyB2YWxpZGF0b3JJZDogVmFsaWRhdG9ySWRUeXBlCglpdG9iCgljb25jYXQKCWNvdmVyIDIKCWJveF9leHRyYWN0Cgk9PQoJZHVwCglibnogKnNraXBfb3IzCgl0eG4gU2VuZGVyCglpbnQgNDAKCWludCAzMgoJYnl0ZSAweDc2IC8vICJ2IgoJZnJhbWVfZGlnIC0xIC8vIHZhbGlkYXRvcklkOiBWYWxpZGF0b3JJZFR5cGUKCWl0b2IKCWNvbmNhdAoJY292ZXIgMgoJYm94X2V4dHJhY3QKCT09Cgl8fAoKKnNraXBfb3IzOgoJYXNzZXJ0CgoJLy8gY29udHJhY3RzL3ZhbGlkYXRvclJlZ2lzdHJ5LmFsZ28udHM6OTM2CgkvLyBub2RlUG9vbEFzc2lnbm1lbnRzID0gY2xvbmUodGhpcy52YWxpZGF0b3JMaXN0KHZhbGlkYXRvcklkKS52YWx1ZS5ub2RlUG9vbEFzc2lnbm1lbnRzKQoJaW50IDg2NiAvLyBoZWFkT2Zmc2V0CglpbnQgMTkyCglieXRlIDB4NzYgLy8gInYiCglmcmFtZV9kaWcgLTEgLy8gdmFsaWRhdG9ySWQ6IFZhbGlkYXRvcklkVHlwZQoJaXRvYgoJY29uY2F0Cgljb3ZlciAyCglib3hfZXh0cmFjdAoJZnJhbWVfYnVyeSAwIC8vIG5vZGVQb29sQXNzaWdubWVudHM6ICgodWludDY0WzNdKVs4XSkKCgkvLyBjb250cmFjdHMvdmFsaWRhdG9yUmVnaXN0cnkuYWxnby50czo5MzcKCS8vIGFzc2VydChub2RlTnVtID49IDEgJiYgbm9kZU51bSA8PSBNQVhfTk9ERVMpCglmcmFtZV9kaWcgLTMgLy8gbm9kZU51bTogdWludDY0CglpbnQgMQoJPj0KCWR1cAoJYnogKnNraXBfYW5kMQoJZnJhbWVfZGlnIC0zIC8vIG5vZGVOdW06IHVpbnQ2NAoJaW50IDgKCTw9CgkmJgoKKnNraXBfYW5kMToKCWFzc2VydAoKCS8vIGNvbnRyYWN0cy92YWxpZGF0b3JSZWdpc3RyeS5hbGdvLnRzOjkzOQoJLy8gZm9yIChsZXQgc3JjTm9kZUlkeCA9IDA7IHNyY05vZGVJZHggPCBNQVhfTk9ERVM7IHNyY05vZGVJZHggKz0gMSkKCWludCAwCglmcmFtZV9idXJ5IDEgLy8gc3JjTm9kZUlkeDogdWludDY0CgoqZm9yXzU6CgkvLyBjb250cmFjdHMvdmFsaWRhdG9yUmVnaXN0cnkuYWxnby50czo5MzkKCS8vIHNyY05vZGVJZHggPCBNQVhfTk9ERVMKCWZyYW1lX2RpZyAxIC8vIHNyY05vZGVJZHg6IHVpbnQ2NAoJaW50IDgKCTwKCWJ6ICpmb3JfNV9lbmQKCgkvLyBjb250cmFjdHMvdmFsaWRhdG9yUmVnaXN0cnkuYWxnby50czo5NDAKCS8vIGZvciAobGV0IGkgPSAwOyBpIDwgTUFYX1BPT0xTX1BFUl9OT0RFOyBpICs9IDEpCglpbnQgMAoJZnJhbWVfYnVyeSAyIC8vIGk6IHVpbnQ2NAoKKmZvcl82OgoJLy8gY29udHJhY3RzL3ZhbGlkYXRvclJlZ2lzdHJ5LmFsZ28udHM6OTQwCgkvLyBpIDwgTUFYX1BPT0xTX1BFUl9OT0RFCglmcmFtZV9kaWcgMiAvLyBpOiB1aW50NjQKCWludCAzCgk8CglieiAqZm9yXzZfZW5kCgoJLy8gKmlmMjdfY29uZGl0aW9uCgkvLyBjb250cmFjdHMvdmFsaWRhdG9yUmVnaXN0cnkuYWxnby50czo5NDEKCS8vIG5vZGVQb29sQXNzaWdubWVudHMubm9kZXNbc3JjTm9kZUlkeF0ucG9vbEFwcElkc1tpXSA9PT0gcG9vbEFwcElkCglmcmFtZV9kaWcgMCAvLyBub2RlUG9vbEFzc2lnbm1lbnRzOiAoKHVpbnQ2NFszXSlbOF0pCglpbnQgMAoJZnJhbWVfZGlnIDEgLy8gc3JjTm9kZUlkeDogdWludDY0CglpbnQgMjQKCSogLy8gYWNjICogdHlwZUxlbmd0aAoJKwoJaW50IDAKCSsKCWZyYW1lX2RpZyAyIC8vIGk6IHVpbnQ2NAoJaW50IDgKCSogLy8gYWNjICogdHlwZUxlbmd0aAoJKwoJaW50IDgKCWV4dHJhY3QzCglidG9pCglmcmFtZV9kaWcgLTIgLy8gcG9vbEFwcElkOiB1aW50NjQKCT09CglieiAqaWYyN19lbmQKCgkvLyAqaWYyN19jb25zZXF1ZW50CgkvLyBjb250cmFjdHMvdmFsaWRhdG9yUmVnaXN0cnkuYWxnby50czo5NDIKCS8vIGFzc2VydChub2RlTnVtIC0gMSAhPT0gc3JjTm9kZUlkeCwgImNhbid0IG1vdmUgdG8gc2FtZSBub2RlIikKCWZyYW1lX2RpZyAtMyAvLyBub2RlTnVtOiB1aW50NjQKCWludCAxCgktCglmcmFtZV9kaWcgMSAvLyBzcmNOb2RlSWR4OiB1aW50NjQKCSE9CgoJLy8gY2FuJ3QgbW92ZSB0byBzYW1lIG5vZGUKCWFzc2VydAoKCS8vIGNvbnRyYWN0cy92YWxpZGF0b3JSZWdpc3RyeS5hbGdvLnRzOjk0NAoJLy8gdGhpcy52YWxpZGF0b3JMaXN0KHZhbGlkYXRvcklkKS52YWx1ZS5ub2RlUG9vbEFzc2lnbm1lbnRzLm5vZGVzW3NyY05vZGVJZHhdLnBvb2xBcHBJZHNbaV0gPSAwCglpbnQgODY2CglmcmFtZV9kaWcgMSAvLyBzcmNOb2RlSWR4OiB1aW50NjQKCWludCAyNAoJKiAvLyBhY2MgKiB0eXBlTGVuZ3RoCgkrCglpbnQgMAoJKwoJZnJhbWVfZGlnIDIgLy8gaTogdWludDY0CglpbnQgOAoJKiAvLyBhY2MgKiB0eXBlTGVuZ3RoCgkrCglieXRlIDB4MDAwMDAwMDAwMDAwMDAwMAoJYnl0ZSAweDc2IC8vICJ2IgoJZnJhbWVfZGlnIC0xIC8vIHZhbGlkYXRvcklkOiBWYWxpZGF0b3JJZFR5cGUKCWl0b2IKCWNvbmNhdAoJY292ZXIgMgoJYm94X3JlcGxhY2UKCgkvLyBjb250cmFjdHMvdmFsaWRhdG9yUmVnaXN0cnkuYWxnby50czo5NDcKCS8vIHNlbmRNZXRob2RDYWxsPHR5cGVvZiBTdGFraW5nUG9vbC5wcm90b3R5cGUuZ29PZmZsaW5lPih7CgkvLyAgICAgICAgICAgICAgICAgICAgICAgICBhcHBsaWNhdGlvbklEOiBBcHBJRC5mcm9tVWludDY0KHBvb2xBcHBJZCksCgkvLyAgICAgICAgICAgICAgICAgICAgIH0pCglpdHhuX2JlZ2luCglpbnQgYXBwbAoJaXR4bl9maWVsZCBUeXBlRW51bQoJbWV0aG9kICJnb09mZmxpbmUoKXZvaWQiCglpdHhuX2ZpZWxkIEFwcGxpY2F0aW9uQXJncwoKCS8vIGNvbnRyYWN0cy92YWxpZGF0b3JSZWdpc3RyeS5hbGdvLnRzOjk0OAoJLy8gYXBwbGljYXRpb25JRDogQXBwSUQuZnJvbVVpbnQ2NChwb29sQXBwSWQpCglmcmFtZV9kaWcgLTIgLy8gcG9vbEFwcElkOiB1aW50NjQKCWl0eG5fZmllbGQgQXBwbGljYXRpb25JRAoKCS8vIEZlZSBmaWVsZCBub3Qgc2V0LCBkZWZhdWx0aW5nIHRvIDAKCWludCAwCglpdHhuX2ZpZWxkIEZlZQoKCS8vIFN1Ym1pdCBpbm5lciB0cmFuc2FjdGlvbgoJaXR4bl9zdWJtaXQKCgkvLyBjb250cmFjdHMvdmFsaWRhdG9yUmVnaXN0cnkuYWxnby50czo5NTIKCS8vIHRoaXMuYWRkUG9vbFRvTm9kZSh2YWxpZGF0b3JJZCwgcG9vbEFwcElkLCBub2RlTnVtKQoJZnJhbWVfZGlnIC0zIC8vIG5vZGVOdW06IHVpbnQ2NAoJZnJhbWVfZGlnIC0yIC8vIHBvb2xBcHBJZDogdWludDY0CglmcmFtZV9kaWcgLTEgLy8gdmFsaWRhdG9ySWQ6IFZhbGlkYXRvcklkVHlwZQoJY2FsbHN1YiBhZGRQb29sVG9Ob2RlCgoJLy8gY29udHJhY3RzL3ZhbGlkYXRvclJlZ2lzdHJ5LmFsZ28udHM6OTUzCgkvLyByZXR1cm47CglyZXRzdWIKCippZjI3X2VuZDoKCipmb3JfNl9jb250aW51ZToKCS8vIGNvbnRyYWN0cy92YWxpZGF0b3JSZWdpc3RyeS5hbGdvLnRzOjk0MAoJLy8gaSArPSAxCglmcmFtZV9kaWcgMiAvLyBpOiB1aW50NjQKCWludCAxCgkrCglmcmFtZV9idXJ5IDIgLy8gaTogdWludDY0CgliICpmb3JfNgoKKmZvcl82X2VuZDoKCipmb3JfNV9jb250aW51ZToKCS8vIGNvbnRyYWN0cy92YWxpZGF0b3JSZWdpc3RyeS5hbGdvLnRzOjkzOQoJLy8gc3JjTm9kZUlkeCArPSAxCglmcmFtZV9kaWcgMSAvLyBzcmNOb2RlSWR4OiB1aW50NjQKCWludCAxCgkrCglmcmFtZV9idXJ5IDEgLy8gc3JjTm9kZUlkeDogdWludDY0CgliICpmb3JfNQoKKmZvcl81X2VuZDoKCWVyciAvLyAiY291bGRuJ3QgZmluZCBwb29sIGFwcCBpZCBpbiBub2RlcyB0byBtb3ZlIgoKLy8gdmVyaWZ5UG9vbEtleUNhbGxlcihwb29sS2V5OiBWYWxpZGF0b3JQb29sS2V5KTogdm9pZAovLwovLyBMb2dzIHRoZSBhZGRpdGlvbiBvZiBhIG5ldyB2YWxpZGF0b3IgdG8gdGhlIHN5c3RlbSwgaXRzIGluaXRpYWwgb3duZXIgYW5kIG1hbmFnZXIKLy8KLy8KLy8gdmVyaWZ5UG9vbEtleUNhbGxlciB2ZXJpZmllcyB0aGUgcGFzc2VkIGluIGtleSAoZnJvbSBhIHN0YWtpbmcgcG9vbCBjYWxsaW5nIHVzIHRvIHVwZGF0ZSBtZXRyaWNzKSBpcyB2YWxpZAovLyBhbmQgbWF0Y2hlcyB0aGUgaW5mb3JtYXRpb24gd2UgaGF2ZSBpbiBvdXIgc3RhdGUuICAnRmFrZScgcG9vbHMgY291bGQgY2FsbCB1cyB0byB1cGRhdGUgb3VyIGRhdGEsIGJ1dCB0aGV5Ci8vIGNhbid0IGZha2UgdGhlIGlkcyBhbmQgbW9zdCBpbXBvcnRhbnRseSBhcHBsaWNhdGlvbiBpZCghKSBvZiB0aGUgY2FsbGVyIHRoYXQgaGFzIHRvIG1hdGNoLgp2ZXJpZnlQb29sS2V5Q2FsbGVyOgoJcHJvdG8gMSAwCgoJLy8gY29udHJhY3RzL3ZhbGlkYXRvclJlZ2lzdHJ5LmFsZ28udHM6MTA1MQoJLy8gYXNzZXJ0KHRoaXMudmFsaWRhdG9yTGlzdChwb29sS2V5LmlkKS5leGlzdHMpCglieXRlIDB4NzYgLy8gInYiCglmcmFtZV9kaWcgLTEgLy8gcG9vbEtleTogVmFsaWRhdG9yUG9vbEtleQoJZXh0cmFjdCAwIDgKCWJ0b2kKCWl0b2IKCWNvbmNhdAoJYm94X2xlbgoJc3dhcAoJcG9wCglhc3NlcnQKCgkvLyBjb250cmFjdHMvdmFsaWRhdG9yUmVnaXN0cnkuYWxnby50czoxMDUyCgkvLyBhc3NlcnQoKHBvb2xLZXkucG9vbElkIGFzIHVpbnQ2NCkgPCAyICoqIDE2KQoJZnJhbWVfZGlnIC0xIC8vIHBvb2xLZXk6IFZhbGlkYXRvclBvb2xLZXkKCWV4dHJhY3QgOCA4CglidG9pCglpbnQgMgoJaW50IDE2CglleHAKCTwKCWFzc2VydAoKCS8vIGNvbnRyYWN0cy92YWxpZGF0b3JSZWdpc3RyeS5hbGdvLnRzOjEwNTMKCS8vIGFzc2VydChwb29sS2V5LnBvb2xJZCA+IDAgJiYgKHBvb2xLZXkucG9vbElkIGFzIHVpbnQxNikgPD0gdGhpcy52YWxpZGF0b3JMaXN0KHBvb2xLZXkuaWQpLnZhbHVlLnN0YXRlLm51bVBvb2xzKQoJZnJhbWVfZGlnIC0xIC8vIHBvb2xLZXk6IFZhbGlkYXRvclBvb2xLZXkKCWV4dHJhY3QgOCA4CglidG9pCglpbnQgMAoJPgoJZHVwCglieiAqc2tpcF9hbmQyCglmcmFtZV9kaWcgLTEgLy8gcG9vbEtleTogVmFsaWRhdG9yUG9vbEtleQoJZXh0cmFjdCA4IDgKCWJ0b2kKCWludCAyMDgKCWludCAyCglieXRlIDB4NzYgLy8gInYiCglmcmFtZV9kaWcgLTEgLy8gcG9vbEtleTogVmFsaWRhdG9yUG9vbEtleQoJZXh0cmFjdCAwIDgKCWJ0b2kKCWl0b2IKCWNvbmNhdAoJY292ZXIgMgoJYm94X2V4dHJhY3QKCWJ0b2kKCTw9CgkmJgoKKnNraXBfYW5kMjoKCWFzc2VydAoKCS8vIGNvbnRyYWN0cy92YWxpZGF0b3JSZWdpc3RyeS5hbGdvLnRzOjEwNTYKCS8vIGFzc2VydCgKCS8vICAgICAgICAgICAgIHBvb2xLZXkucG9vbEFwcElkID09PSB0aGlzLnZhbGlkYXRvckxpc3QocG9vbEtleS5pZCkudmFsdWUucG9vbHNbcG9vbEtleS5wb29sSWQgLSAxXS5wb29sQXBwSWQsCgkvLyAgICAgICAgICAgICAiVGhlIHBhc3NlZCBpbiBhcHAgaWQgZG9lc24ndCBtYXRjaCB0aGUgcGFzc2VkIGluIGlkcyIKCS8vICAgICAgICAgKQoJZnJhbWVfZGlnIC0xIC8vIHBvb2xLZXk6IFZhbGlkYXRvclBvb2xLZXkKCWV4dHJhY3QgMTYgOAoJYnRvaQoJaW50IDIzNCAvLyBoZWFkT2Zmc2V0CglmcmFtZV9kaWcgLTEgLy8gcG9vbEtleTogVmFsaWRhdG9yUG9vbEtleQoJZXh0cmFjdCA4IDgKCWJ0b2kKCWludCAxCgktCglpbnQgMTgKCSogLy8gYWNjICogdHlwZUxlbmd0aAoJKwoJaW50IDAKCSsKCWludCA4CglieXRlIDB4NzYgLy8gInYiCglmcmFtZV9kaWcgLTEgLy8gcG9vbEtleTogVmFsaWRhdG9yUG9vbEtleQoJZXh0cmFjdCAwIDgKCWJ0b2kKCWl0b2IKCWNvbmNhdAoJY292ZXIgMgoJYm94X2V4dHJhY3QKCWJ0b2kKCT09CgoJLy8gVGhlIHBhc3NlZCBpbiBhcHAgaWQgZG9lc24ndCBtYXRjaCB0aGUgcGFzc2VkIGluIGlkcwoJYXNzZXJ0CgoJLy8gY29udHJhY3RzL3ZhbGlkYXRvclJlZ2lzdHJ5LmFsZ28udHM6MTA2MQoJLy8gYXNzZXJ0KHRoaXMudHhuLnNlbmRlciA9PT0gQXBwSUQuZnJvbVVpbnQ2NChwb29sS2V5LnBvb2xBcHBJZCkuYWRkcmVzcykKCXR4biBTZW5kZXIKCWZyYW1lX2RpZyAtMSAvLyBwb29sS2V5OiBWYWxpZGF0b3JQb29sS2V5CglleHRyYWN0IDE2IDgKCWJ0b2kKCWFwcF9wYXJhbXNfZ2V0IEFwcEFkZHJlc3MKCXBvcAoJPT0KCWFzc2VydAoKCS8vIGNvbnRyYWN0cy92YWxpZGF0b3JSZWdpc3RyeS5hbGdvLnRzOjEwNjMKCS8vIGFzc2VydChwb29sS2V5LmlkID09PSAoQXBwSUQuZnJvbVVpbnQ2NChwb29sS2V5LnBvb2xBcHBJZCkuZ2xvYmFsU3RhdGUoJ3ZhbGlkYXRvcklkJykgYXMgdWludDY0KSkKCWZyYW1lX2RpZyAtMSAvLyBwb29sS2V5OiBWYWxpZGF0b3JQb29sS2V5CglleHRyYWN0IDAgOAoJYnRvaQoJZnJhbWVfZGlnIC0xIC8vIHBvb2xLZXk6IFZhbGlkYXRvclBvb2xLZXkKCWV4dHJhY3QgMTYgOAoJYnRvaQoJYnl0ZSAweDc2NjE2YzY5NjQ2MTc0NmY3MjQ5NjQgLy8gInZhbGlkYXRvcklkIgoJYXBwX2dsb2JhbF9nZXRfZXgKCWFzc2VydAoJPT0KCWFzc2VydAoKCS8vIGNvbnRyYWN0cy92YWxpZGF0b3JSZWdpc3RyeS5hbGdvLnRzOjEwNjQKCS8vIGFzc2VydChwb29sS2V5LnBvb2xJZCA9PT0gKEFwcElELmZyb21VaW50NjQocG9vbEtleS5wb29sQXBwSWQpLmdsb2JhbFN0YXRlKCdwb29sSWQnKSBhcyB1aW50NjQpKQoJZnJhbWVfZGlnIC0xIC8vIHBvb2xLZXk6IFZhbGlkYXRvclBvb2xLZXkKCWV4dHJhY3QgOCA4CglidG9pCglmcmFtZV9kaWcgLTEgLy8gcG9vbEtleTogVmFsaWRhdG9yUG9vbEtleQoJZXh0cmFjdCAxNiA4CglidG9pCglieXRlIDB4NzA2ZjZmNmM0OTY0IC8vICJwb29sSWQiCglhcHBfZ2xvYmFsX2dldF9leAoJYXNzZXJ0Cgk9PQoJYXNzZXJ0CglyZXRzdWIKCi8vIHJldmVyaWZ5TkZET3duZXJzaGlwKHZhbGlkYXRvcklkOiBWYWxpZGF0b3JJZFR5cGUpOiB2b2lkCi8vCi8vIFRoaXMgbWV0aG9kIHZlcmlmaWVzIHRoZSBvd25lcnNoaXAgb2YgTkZEIChOYW1lZCBGdW5jdGlvbiBEYXRhKSBieSBhIHZhbGlkYXRvci4KLy8gSWYgdGhlIG93bmVyc2hpcCBpcyBubyBsb25nZXIgdmFsaWQsIGl0IHJlbW92ZXMgdGhlIE5GRCBmcm9tIHRoZSB2YWxpZGF0b3IncyBjb25maWd1cmF0aW9uLgovLwovLyBAcGFyYW0ge1ZhbGlkYXRvcklkVHlwZX0gdmFsaWRhdG9ySWQgLSBUaGUgaWQgb2YgdGhlIHZhbGlkYXRvciB3aG9zZSBkYXRhIHNob3VsZCBiZSByZS1ldmFsdWF0ZWQuCnJldmVyaWZ5TkZET3duZXJzaGlwOgoJcHJvdG8gMSAwCgoJLy8gUHVzaCBlbXB0eSBieXRlcyBhZnRlciB0aGUgZnJhbWUgcG9pbnRlciB0byByZXNlcnZlIHNwYWNlIGZvciBsb2NhbCB2YXJpYWJsZXMKCWJ5dGUgMHgKCWR1cAoKCS8vIGNvbnRyYWN0cy92YWxpZGF0b3JSZWdpc3RyeS5hbGdvLnRzOjEwNzQKCS8vIHZhbGlkYXRvckNvbmZpZyA9IHRoaXMudmFsaWRhdG9yTGlzdCh2YWxpZGF0b3JJZCkudmFsdWUuY29uZmlnCglieXRlIDB4NzYgLy8gInYiCglmcmFtZV9kaWcgLTEgLy8gdmFsaWRhdG9ySWQ6IFZhbGlkYXRvcklkVHlwZQoJaXRvYgoJY29uY2F0CglmcmFtZV9idXJ5IDAgLy8gc3RvcmFnZSBrZXkvL3ZhbGlkYXRvckNvbmZpZwoKCS8vICppZjI4X2NvbmRpdGlvbgoJLy8gY29udHJhY3RzL3ZhbGlkYXRvclJlZ2lzdHJ5LmFsZ28udHM6MTA3NQoJLy8gdmFsaWRhdG9yQ29uZmlnLm5mZEZvckluZm8gIT09IDAKCWludCA3MgoJaW50IDgKCWJ5dGUgMHg3NiAvLyAidiIKCWZyYW1lX2RpZyAtMSAvLyB2YWxpZGF0b3JJZDogVmFsaWRhdG9ySWRUeXBlCglpdG9iCgljb25jYXQKCWNvdmVyIDIKCWJveF9leHRyYWN0CglidG9pCglpbnQgMAoJIT0KCWJ6ICppZjI4X2VuZAoKCS8vICppZjI4X2NvbnNlcXVlbnQKCS8vIGNvbnRyYWN0cy92YWxpZGF0b3JSZWdpc3RyeS5hbGdvLnRzOjEwNzgKCS8vIG5mZE93bmVyID0gQXBwSUQuZnJvbVVpbnQ2NCh2YWxpZGF0b3JDb25maWcubmZkRm9ySW5mbykuZ2xvYmFsU3RhdGUoJ2kub3duZXIuYScpIGFzIEFkZHJlc3MKCWludCA3MgoJaW50IDgKCWJ5dGUgMHg3NiAvLyAidiIKCWZyYW1lX2RpZyAtMSAvLyB2YWxpZGF0b3JJZDogVmFsaWRhdG9ySWRUeXBlCglpdG9iCgljb25jYXQKCWNvdmVyIDIKCWJveF9leHRyYWN0CglidG9pCglieXRlIDB4NjkyZTZmNzc2ZTY1NzIyZTYxIC8vICJpLm93bmVyLmEiCglhcHBfZ2xvYmFsX2dldF9leAoJYXNzZXJ0CglmcmFtZV9idXJ5IDEgLy8gbmZkT3duZXI6IGFkZHJlc3MKCgkvLyAqaWYyOV9jb25kaXRpb24KCS8vIGNvbnRyYWN0cy92YWxpZGF0b3JSZWdpc3RyeS5hbGdvLnRzOjEwODAKCS8vIHZhbGlkYXRvckNvbmZpZy5vd25lciAhPT0gbmZkT3duZXIgJiYgdmFsaWRhdG9yQ29uZmlnLm1hbmFnZXIgIT09IG5mZE93bmVyCglpbnQgOAoJaW50IDMyCglieXRlIDB4NzYgLy8gInYiCglmcmFtZV9kaWcgLTEgLy8gdmFsaWRhdG9ySWQ6IFZhbGlkYXRvcklkVHlwZQoJaXRvYgoJY29uY2F0Cgljb3ZlciAyCglib3hfZXh0cmFjdAoJZnJhbWVfZGlnIDEgLy8gbmZkT3duZXI6IGFkZHJlc3MKCSE9CglkdXAKCWJ6ICpza2lwX2FuZDMKCWludCA0MAoJaW50IDMyCglieXRlIDB4NzYgLy8gInYiCglmcmFtZV9kaWcgLTEgLy8gdmFsaWRhdG9ySWQ6IFZhbGlkYXRvcklkVHlwZQoJaXRvYgoJY29uY2F0Cgljb3ZlciAyCglib3hfZXh0cmFjdAoJZnJhbWVfZGlnIDEgLy8gbmZkT3duZXI6IGFkZHJlc3MKCSE9CgkmJgoKKnNraXBfYW5kMzoKCWJ6ICppZjI5X2VuZAoKCS8vICppZjI5X2NvbnNlcXVlbnQKCS8vIGNvbnRyYWN0cy92YWxpZGF0b3JSZWdpc3RyeS5hbGdvLnRzOjEwODIKCS8vIHRoaXMudmFsaWRhdG9yTGlzdCh2YWxpZGF0b3JJZCkudmFsdWUuY29uZmlnLm5mZEZvckluZm8gPSAwCglpbnQgNzIKCWJ5dGUgMHgwMDAwMDAwMDAwMDAwMDAwCglieXRlIDB4NzYgLy8gInYiCglmcmFtZV9kaWcgLTEgLy8gdmFsaWRhdG9ySWQ6IFZhbGlkYXRvcklkVHlwZQoJaXRvYgoJY29uY2F0Cgljb3ZlciAyCglib3hfcmVwbGFjZQoKKmlmMjlfZW5kOgoKKmlmMjhfZW5kOgoJcmV0c3ViCgovLyB2YWxpZGF0ZUNvbmZpZyhjb25maWc6IFZhbGlkYXRvckNvbmZpZyk6IHZvaWQKdmFsaWRhdGVDb25maWc6Cglwcm90byAxIDAKCgkvLyBjb250cmFjdHMvdmFsaWRhdG9yUmVnaXN0cnkuYWxnby50czoxMDg5CgkvLyBhc3NlcnQoY29uZmlnLmVudHJ5R2F0aW5nVHlwZSA+PSBHQVRJTkdfVFlQRV9OT05FICYmIGNvbmZpZy5lbnRyeUdhdGluZ1R5cGUgPD0gR0FUSU5HX1RZUEVfQ09OU1RfTUFYKQoJZnJhbWVfZGlnIC0xIC8vIGNvbmZpZzogVmFsaWRhdG9yQ29uZmlnCglleHRyYWN0IDgwIDEKCWJ0b2kKCWludCAwCgk+PQoJZHVwCglieiAqc2tpcF9hbmQ0CglmcmFtZV9kaWcgLTEgLy8gY29uZmlnOiBWYWxpZGF0b3JDb25maWcKCWV4dHJhY3QgODAgMQoJYnRvaQoJaW50IDQKCTw9CgkmJgoKKnNraXBfYW5kNDoKCWFzc2VydAoKCS8vIGNvbnRyYWN0cy92YWxpZGF0b3JSZWdpc3RyeS5hbGdvLnRzOjEwOTAKCS8vIGFzc2VydChjb25maWcucGF5b3V0RXZlcnlYTWlucyA+PSBNSU5fUEFZT1VUX01JTlMgJiYgY29uZmlnLnBheW91dEV2ZXJ5WE1pbnMgPD0gTUFYX1BBWU9VVF9NSU5TKQoJZnJhbWVfZGlnIC0xIC8vIGNvbmZpZzogVmFsaWRhdG9yQ29uZmlnCglleHRyYWN0IDEzNyAyCglidG9pCglpbnQgMQoJPj0KCWR1cAoJYnogKnNraXBfYW5kNQoJZnJhbWVfZGlnIC0xIC8vIGNvbmZpZzogVmFsaWRhdG9yQ29uZmlnCglleHRyYWN0IDEzNyAyCglidG9pCglpbnQgMTAwODAKCTw9CgkmJgoKKnNraXBfYW5kNToKCWFzc2VydAoKCS8vIGNvbnRyYWN0cy92YWxpZGF0b3JSZWdpc3RyeS5hbGdvLnRzOjEwOTEKCS8vIGFzc2VydChjb25maWcucGVyY2VudFRvVmFsaWRhdG9yID49IE1JTl9QQ1RfVE9fVkFMSURBVE9SICYmIGNvbmZpZy5wZXJjZW50VG9WYWxpZGF0b3IgPD0gTUFYX1BDVF9UT19WQUxJREFUT1IpCglmcmFtZV9kaWcgLTEgLy8gY29uZmlnOiBWYWxpZGF0b3JDb25maWcKCWV4dHJhY3QgMTM5IDQKCWJ0b2kKCWludCAwCgk+PQoJZHVwCglieiAqc2tpcF9hbmQ2CglmcmFtZV9kaWcgLTEgLy8gY29uZmlnOiBWYWxpZGF0b3JDb25maWcKCWV4dHJhY3QgMTM5IDQKCWJ0b2kKCWludCAxMDAwMDAwCgk8PQoJJiYKCipza2lwX2FuZDY6Cglhc3NlcnQKCgkvLyAqaWYzMF9jb25kaXRpb24KCS8vIGNvbnRyYWN0cy92YWxpZGF0b3JSZWdpc3RyeS5hbGdvLnRzOjEwOTIKCS8vIGNvbmZpZy5wZXJjZW50VG9WYWxpZGF0b3IgIT09IDAKCWZyYW1lX2RpZyAtMSAvLyBjb25maWc6IFZhbGlkYXRvckNvbmZpZwoJZXh0cmFjdCAxMzkgNAoJYnRvaQoJaW50IDAKCSE9CglieiAqaWYzMF9lbmQKCgkvLyAqaWYzMF9jb25zZXF1ZW50CgkvLyBjb250cmFjdHMvdmFsaWRhdG9yUmVnaXN0cnkuYWxnby50czoxMDkzCgkvLyBhc3NlcnQoCgkvLyAgICAgICAgICAgICAgICAgY29uZmlnLnZhbGlkYXRvckNvbW1pc3Npb25BZGRyZXNzICE9PSBBZGRyZXNzLnplcm9BZGRyZXNzLAoJLy8gICAgICAgICAgICAgICAgICd2YWxpZGF0b3JDb21taXNzaW9uQWRkcmVzcyBtdXN0IGJlIHNldCBpZiBwZXJjZW50IHRvIHZhbGlkYXRvciBpcyBub3QgMCcKCS8vICAgICAgICAgICAgICkKCWZyYW1lX2RpZyAtMSAvLyBjb25maWc6IFZhbGlkYXRvckNvbmZpZwoJZXh0cmFjdCAxNDMgMzIKCWdsb2JhbCBaZXJvQWRkcmVzcwoJIT0KCgkvLyB2YWxpZGF0b3JDb21taXNzaW9uQWRkcmVzcyBtdXN0IGJlIHNldCBpZiBwZXJjZW50IHRvIHZhbGlkYXRvciBpcyBub3QgMAoJYXNzZXJ0CgoqaWYzMF9lbmQ6CgkvLyBjb250cmFjdHMvdmFsaWRhdG9yUmVnaXN0cnkuYWxnby50czoxMDk4CgkvLyBhc3NlcnQoY29uZmlnLm1pbkVudHJ5U3Rha2UgPj0gTUlOX0FMR09fU1RBS0VfUEVSX1BPT0wpCglmcmFtZV9kaWcgLTEgLy8gY29uZmlnOiBWYWxpZGF0b3JDb25maWcKCWV4dHJhY3QgMTc1IDgKCWJ0b2kKCWludCAxMDAwMDAwCgk+PQoJYXNzZXJ0CgoJLy8gY29udHJhY3RzL3ZhbGlkYXRvclJlZ2lzdHJ5LmFsZ28udHM6MTEwMAoJLy8gYXNzZXJ0KGNvbmZpZy5wb29sc1Blck5vZGUgPiAwICYmIGNvbmZpZy5wb29sc1Blck5vZGUgPD0gTUFYX1BPT0xTX1BFUl9OT0RFKQoJZnJhbWVfZGlnIC0xIC8vIGNvbmZpZzogVmFsaWRhdG9yQ29uZmlnCglleHRyYWN0IDE5MSAxCglidG9pCglpbnQgMAoJPgoJZHVwCglieiAqc2tpcF9hbmQ3CglmcmFtZV9kaWcgLTEgLy8gY29uZmlnOiBWYWxpZGF0b3JDb25maWcKCWV4dHJhY3QgMTkxIDEKCWJ0b2kKCWludCAzCgk8PQoJJiYKCipza2lwX2FuZDc6Cglhc3NlcnQKCXJldHN1YgoKLy8gY2FsbFBvb2xBZGRTdGFrZShzdGFrZWRBbW91bnRQYXltZW50OiBQYXlUeG4sIHBvb2xLZXk6IFZhbGlkYXRvclBvb2xLZXksIG1ickFtdFBhaWQ6IHVpbnQ2NCwgaXNOZXdTdGFrZXJUb1ZhbGlkYXRvcjogYm9vbGVhbiwgaXNOZXdTdGFrZXJUb1Byb3RvY29sOiBib29sZWFuKTogdm9pZAovLwovLyBBZGRzIGEgc3Rha2VycyBhbW91bnQgb2YgYWxnbyB0byBhIHZhbGlkYXRvciBwb29sLCB0cmFuc2ZlcnJpbmcgdGhlIGFsZ28gd2UgcmVjZWl2ZWQgZnJvbSB0aGVtIChhbHJlYWR5IHZlcmlmaWVkCi8vIGJ5IG91ciBjYWxsZXIpIHRvIHRoZSBzdGFraW5nIHBvb2wgYWNjb3VudCwgYW5kIHRoZW4gdGVsbGluZyBpdCBhYm91dCB0aGUgYW1vdW50IGJlaW5nIGFkZGVkIGZvciB0aGUgc3BlY2lmaWVkCi8vIHN0YWtlci4KLy8KLy8gQHBhcmFtIHtQYXlUeG59IHN0YWtlZEFtb3VudFBheW1lbnQgLSBwYXltZW50IGNvbWluZyBmcm9tIHN0YWtlciB0byBwbGFjZSBpbnRvIGEgcG9vbAovLyBAcGFyYW0ge1ZhbGlkYXRvclBvb2xLZXl9IHBvb2xLZXkgLSBUaGUga2V5IG9mIHRoZSB2YWxpZGF0b3IgcG9vbC4KLy8gQHBhcmFtIHt1aW50NjR9IG1ickFtdFBhaWQgLSBBbW91bnQgdGhlIHVzZXIgaXMgbGVhdmluZyBiZWhpbmQgaW4gdGhlIHZhbGlkYXRvciB0byBwYXkgZm9yIHRoZWlyIHN0YWtlciBNQlIgY29zdAovLyBAcGFyYW0ge2Jvb2xlYW59IGlzTmV3U3Rha2VyVG9WYWxpZGF0b3IgLSBpZiB0aGlzIGlzIGEgbmV3LCBmaXJzdC10aW1lIHN0YWtlciB0byB0aGUgdmFsaWRhdG9yCi8vIEBwYXJhbSB7Ym9vbGVhbn0gaXNOZXdTdGFrZXJUb1Byb3RvY29sIC0gaWYgdGhpcyBpcyBhIG5ldywgZmlyc3QtdGltZSBzdGFrZXIgdG8gdGhlIHByb3RvY29sCmNhbGxQb29sQWRkU3Rha2U6Cglwcm90byA1IDAKCgkvLyBQdXNoIGVtcHR5IGJ5dGVzIGFmdGVyIHRoZSBmcmFtZSBwb2ludGVyIHRvIHJlc2VydmUgc3BhY2UgZm9yIGxvY2FsIHZhcmlhYmxlcwoJYnl0ZSAweAoJZHVwbiAyCgoJLy8gKmlmMzFfY29uZGl0aW9uCgkvLyBjb250cmFjdHMvdmFsaWRhdG9yUmVnaXN0cnkuYWxnby50czoxMTIxCgkvLyBnbG9iYWxzLm9wY29kZUJ1ZGdldCA8IDUwMAoJZ2xvYmFsIE9wY29kZUJ1ZGdldAoJaW50IDUwMAoJPAoJYnogKmlmMzFfZW5kCgoJLy8gKmlmMzFfY29uc2VxdWVudAoJLy8gY29udHJhY3RzL3ZhbGlkYXRvclJlZ2lzdHJ5LmFsZ28udHM6MTEyMgoJLy8gaW5jcmVhc2VPcGNvZGVCdWRnZXQoKQoJaXR4bl9iZWdpbgoJaW50IGFwcGwKCWl0eG5fZmllbGQgVHlwZUVudW0KCWludCAwCglpdHhuX2ZpZWxkIEZlZQoJYnl0ZSBiNjQgQ29FQiAvLyAjcHJhZ21hIHZlcnNpb24gMTA7IGludCAxCglkdXAKCWl0eG5fZmllbGQgQXBwcm92YWxQcm9ncmFtCglpdHhuX2ZpZWxkIENsZWFyU3RhdGVQcm9ncmFtCglpbnQgRGVsZXRlQXBwbGljYXRpb24KCWl0eG5fZmllbGQgT25Db21wbGV0aW9uCglpdHhuX3N1Ym1pdAoKKmlmMzFfZW5kOgoJLy8gY29udHJhY3RzL3ZhbGlkYXRvclJlZ2lzdHJ5LmFsZ28udHM6MTEyNAoJLy8gcG9vbEFwcElkID0gdGhpcy52YWxpZGF0b3JMaXN0KHBvb2xLZXkuaWQpLnZhbHVlLnBvb2xzW3Bvb2xLZXkucG9vbElkIC0gMV0ucG9vbEFwcElkCglpbnQgMjM0IC8vIGhlYWRPZmZzZXQKCWZyYW1lX2RpZyAtMiAvLyBwb29sS2V5OiBWYWxpZGF0b3JQb29sS2V5CglleHRyYWN0IDggOAoJYnRvaQoJaW50IDEKCS0KCWludCAxOAoJKiAvLyBhY2MgKiB0eXBlTGVuZ3RoCgkrCglpbnQgMAoJKwoJaW50IDgKCWJ5dGUgMHg3NiAvLyAidiIKCWZyYW1lX2RpZyAtMiAvLyBwb29sS2V5OiBWYWxpZGF0b3JQb29sS2V5CglleHRyYWN0IDAgOAoJYnRvaQoJaXRvYgoJY29uY2F0Cgljb3ZlciAyCglib3hfZXh0cmFjdAoJYnRvaQoJZnJhbWVfYnVyeSAwIC8vIHBvb2xBcHBJZDogdWludDY0CgoJLy8gY29udHJhY3RzL3ZhbGlkYXRvclJlZ2lzdHJ5LmFsZ28udHM6MTEyOAoJLy8gc2VuZE1ldGhvZENhbGw8dHlwZW9mIFN0YWtpbmdQb29sLnByb3RvdHlwZS5hZGRTdGFrZT4oewoJLy8gICAgICAgICAgICAgYXBwbGljYXRpb25JRDogQXBwSUQuZnJvbVVpbnQ2NChwb29sQXBwSWQpLAoJLy8gICAgICAgICAgICAgbWV0aG9kQXJnczogWwoJLy8gICAgICAgICAgICAgICAgIC8vID09PT09PT0KCS8vICAgICAgICAgICAgICAgICAvLyBUSElTIElTIEEgU0VORCBvZiB0aGUgYW1vdW50IHJlY2VpdmVkIHJpZ2h0IGJhY2sgb3V0IGFuZCBpbnRvIHRoZSBzdGFraW5nIHBvb2wgY29udHJhY3QgYWNjb3VudC4KCS8vICAgICAgICAgICAgICAgICB7IGFtb3VudDogc3Rha2VkQW1vdW50UGF5bWVudC5hbW91bnQgLSBtYnJBbXRQYWlkLCByZWNlaXZlcjogQXBwSUQuZnJvbVVpbnQ2NChwb29sQXBwSWQpLmFkZHJlc3MgfSwKCS8vICAgICAgICAgICAgICAgICAvLyA9PT09PT09CgkvLyAgICAgICAgICAgICAgICAgc3Rha2VkQW1vdW50UGF5bWVudC5zZW5kZXIsCgkvLyAgICAgICAgICAgICBdLAoJLy8gICAgICAgICB9KQoJaXR4bl9iZWdpbgoJaW50IHBheQoJaXR4bl9maWVsZCBUeXBlRW51bQoKCS8vIGNvbnRyYWN0cy92YWxpZGF0b3JSZWdpc3RyeS5hbGdvLnRzOjExMzMKCS8vIGFtb3VudDogc3Rha2VkQW1vdW50UGF5bWVudC5hbW91bnQgLSBtYnJBbXRQYWlkCglmcmFtZV9kaWcgLTEgLy8gc3Rha2VkQW1vdW50UGF5bWVudDogUGF5VHhuCglndHhucyBBbW91bnQKCWZyYW1lX2RpZyAtMyAvLyBtYnJBbXRQYWlkOiB1aW50NjQKCS0KCWl0eG5fZmllbGQgQW1vdW50CgoJLy8gY29udHJhY3RzL3ZhbGlkYXRvclJlZ2lzdHJ5LmFsZ28udHM6MTEzMwoJLy8gcmVjZWl2ZXI6IEFwcElELmZyb21VaW50NjQocG9vbEFwcElkKS5hZGRyZXNzCglmcmFtZV9kaWcgMCAvLyBwb29sQXBwSWQ6IHVpbnQ2NAoJYXBwX3BhcmFtc19nZXQgQXBwQWRkcmVzcwoJcG9wCglpdHhuX2ZpZWxkIFJlY2VpdmVyCgoJLy8gRmVlIGZpZWxkIG5vdCBzZXQsIGRlZmF1bHRpbmcgdG8gMAoJaW50IDAKCWl0eG5fZmllbGQgRmVlCglpdHhuX25leHQKCWludCBhcHBsCglpdHhuX2ZpZWxkIFR5cGVFbnVtCgltZXRob2QgImFkZFN0YWtlKHBheSxhZGRyZXNzKXVpbnQ2NCIKCWl0eG5fZmllbGQgQXBwbGljYXRpb25BcmdzCgoJLy8gY29udHJhY3RzL3ZhbGlkYXRvclJlZ2lzdHJ5LmFsZ28udHM6MTEyOQoJLy8gYXBwbGljYXRpb25JRDogQXBwSUQuZnJvbVVpbnQ2NChwb29sQXBwSWQpCglmcmFtZV9kaWcgMCAvLyBwb29sQXBwSWQ6IHVpbnQ2NAoJaXR4bl9maWVsZCBBcHBsaWNhdGlvbklECgoJLy8gY29udHJhY3RzL3ZhbGlkYXRvclJlZ2lzdHJ5LmFsZ28udHM6MTEzMAoJLy8gbWV0aG9kQXJnczogWwoJLy8gICAgICAgICAgICAgICAgIC8vID09PT09PT0KCS8vICAgICAgICAgICAgICAgICAvLyBUSElTIElTIEEgU0VORCBvZiB0aGUgYW1vdW50IHJlY2VpdmVkIHJpZ2h0IGJhY2sgb3V0IGFuZCBpbnRvIHRoZSBzdGFraW5nIHBvb2wgY29udHJhY3QgYWNjb3VudC4KCS8vICAgICAgICAgICAgICAgICB7IGFtb3VudDogc3Rha2VkQW1vdW50UGF5bWVudC5hbW91bnQgLSBtYnJBbXRQYWlkLCByZWNlaXZlcjogQXBwSUQuZnJvbVVpbnQ2NChwb29sQXBwSWQpLmFkZHJlc3MgfSwKCS8vICAgICAgICAgICAgICAgICAvLyA9PT09PT09CgkvLyAgICAgICAgICAgICAgICAgc3Rha2VkQW1vdW50UGF5bWVudC5zZW5kZXIsCgkvLyAgICAgICAgICAgICBdCglmcmFtZV9kaWcgLTEgLy8gc3Rha2VkQW1vdW50UGF5bWVudDogUGF5VHhuCglndHhucyBTZW5kZXIKCWl0eG5fZmllbGQgQXBwbGljYXRpb25BcmdzCgoJLy8gRmVlIGZpZWxkIG5vdCBzZXQsIGRlZmF1bHRpbmcgdG8gMAoJaW50IDAKCWl0eG5fZmllbGQgRmVlCgoJLy8gU3VibWl0IGlubmVyIHRyYW5zYWN0aW9uCglpdHhuX3N1Ym1pdAoJaXR4biBOdW1Mb2dzCglpbnQgMQoJLQoJaXR4bmFzIExvZ3MKCWV4dHJhY3QgNCAwCglidG9pCgoJLy8gY29udHJhY3RzL3ZhbGlkYXRvclJlZ2lzdHJ5LmFsZ28udHM6MTE0MAoJLy8gcG9vbE51bVN0YWtlcnMgPSBBcHBJRC5mcm9tVWludDY0KHBvb2xBcHBJZCkuZ2xvYmFsU3RhdGUoJ251bVN0YWtlcnMnKSBhcyB1aW50NjQKCWZyYW1lX2RpZyAwIC8vIHBvb2xBcHBJZDogdWludDY0CglieXRlIDB4NmU3NTZkNTM3NDYxNmI2NTcyNzMgLy8gIm51bVN0YWtlcnMiCglhcHBfZ2xvYmFsX2dldF9leAoJYXNzZXJ0CglmcmFtZV9idXJ5IDEgLy8gcG9vbE51bVN0YWtlcnM6IHVpbnQ2NAoKCS8vIGNvbnRyYWN0cy92YWxpZGF0b3JSZWdpc3RyeS5hbGdvLnRzOjExNDEKCS8vIHBvb2xBbGdvU3Rha2VkID0gQXBwSUQuZnJvbVVpbnQ2NChwb29sQXBwSWQpLmdsb2JhbFN0YXRlKCdzdGFrZWQnKSBhcyB1aW50NjQKCWZyYW1lX2RpZyAwIC8vIHBvb2xBcHBJZDogdWludDY0CglieXRlIDB4NzM3NDYxNmI2NTY0IC8vICJzdGFrZWQiCglhcHBfZ2xvYmFsX2dldF9leAoJYXNzZXJ0CglmcmFtZV9idXJ5IDIgLy8gcG9vbEFsZ29TdGFrZWQ6IHVpbnQ2NAoKCS8vIGNvbnRyYWN0cy92YWxpZGF0b3JSZWdpc3RyeS5hbGdvLnRzOjExNDIKCS8vIHRoaXMudmFsaWRhdG9yTGlzdChwb29sS2V5LmlkKS52YWx1ZS5wb29sc1twb29sS2V5LnBvb2xJZCAtIDFdLnRvdGFsU3Rha2VycyA9IHBvb2xOdW1TdGFrZXJzIGFzIHVpbnQxNgoJaW50IDIzNCAvLyBoZWFkT2Zmc2V0CglmcmFtZV9kaWcgLTIgLy8gcG9vbEtleTogVmFsaWRhdG9yUG9vbEtleQoJZXh0cmFjdCA4IDgKCWJ0b2kKCWludCAxCgktCglpbnQgMTgKCSogLy8gYWNjICogdHlwZUxlbmd0aAoJKwoJaW50IDggLy8gaGVhZE9mZnNldAoJKwoJZnJhbWVfZGlnIDEgLy8gcG9vbE51bVN0YWtlcnM6IHVpbnQ2NAoJaXRvYgoJZXh0cmFjdCA2IDIKCWJ5dGUgMHg3NiAvLyAidiIKCWZyYW1lX2RpZyAtMiAvLyBwb29sS2V5OiBWYWxpZGF0b3JQb29sS2V5CglleHRyYWN0IDAgOAoJYnRvaQoJaXRvYgoJY29uY2F0Cgljb3ZlciAyCglib3hfcmVwbGFjZQoKCS8vIGNvbnRyYWN0cy92YWxpZGF0b3JSZWdpc3RyeS5hbGdvLnRzOjExNDMKCS8vIHRoaXMudmFsaWRhdG9yTGlzdChwb29sS2V5LmlkKS52YWx1ZS5wb29sc1twb29sS2V5LnBvb2xJZCAtIDFdLnRvdGFsQWxnb1N0YWtlZCA9IHBvb2xBbGdvU3Rha2VkCglpbnQgMjM0IC8vIGhlYWRPZmZzZXQKCWZyYW1lX2RpZyAtMiAvLyBwb29sS2V5OiBWYWxpZGF0b3JQb29sS2V5CglleHRyYWN0IDggOAoJYnRvaQoJaW50IDEKCS0KCWludCAxOAoJKiAvLyBhY2MgKiB0eXBlTGVuZ3RoCgkrCglpbnQgMTAgLy8gaGVhZE9mZnNldAoJKwoJZnJhbWVfZGlnIDIgLy8gcG9vbEFsZ29TdGFrZWQ6IHVpbnQ2NAoJaXRvYgoJYnl0ZSAweDc2IC8vICJ2IgoJZnJhbWVfZGlnIC0yIC8vIHBvb2xLZXk6IFZhbGlkYXRvclBvb2xLZXkKCWV4dHJhY3QgMCA4CglidG9pCglpdG9iCgljb25jYXQKCWNvdmVyIDIKCWJveF9yZXBsYWNlCgoJLy8gKmlmMzJfY29uZGl0aW9uCgkvLyBjb250cmFjdHMvdmFsaWRhdG9yUmVnaXN0cnkuYWxnby50czoxMTQ2CgkvLyBpc05ld1N0YWtlclRvVmFsaWRhdG9yCglmcmFtZV9kaWcgLTQgLy8gaXNOZXdTdGFrZXJUb1ZhbGlkYXRvcjogYm9vbGVhbgoJYnogKmlmMzJfZW5kCgoJLy8gKmlmMzJfY29uc2VxdWVudAoJLy8gY29udHJhY3RzL3ZhbGlkYXRvclJlZ2lzdHJ5LmFsZ28udHM6MTE0NwoJLy8gdGhpcy52YWxpZGF0b3JMaXN0KHBvb2xLZXkuaWQpLnZhbHVlLnN0YXRlLnRvdGFsU3Rha2VycyArPSAxCglpbnQgMjEwCglkdXAKCWludCA4CglieXRlIDB4NzYgLy8gInYiCglmcmFtZV9kaWcgLTIgLy8gcG9vbEtleTogVmFsaWRhdG9yUG9vbEtleQoJZXh0cmFjdCAwIDgKCWJ0b2kKCWl0b2IKCWNvbmNhdAoJY292ZXIgMgoJYm94X2V4dHJhY3QKCWJ0b2kKCWludCAxCgkrCglpdG9iCglieXRlIDB4NzYgLy8gInYiCglmcmFtZV9kaWcgLTIgLy8gcG9vbEtleTogVmFsaWRhdG9yUG9vbEtleQoJZXh0cmFjdCAwIDgKCWJ0b2kKCWl0b2IKCWNvbmNhdAoJY292ZXIgMgoJYm94X3JlcGxhY2UKCippZjMyX2VuZDoKCS8vICppZjMzX2NvbmRpdGlvbgoJLy8gY29udHJhY3RzL3ZhbGlkYXRvclJlZ2lzdHJ5LmFsZ28udHM6MTE0OQoJLy8gaXNOZXdTdGFrZXJUb1Byb3RvY29sCglmcmFtZV9kaWcgLTUgLy8gaXNOZXdTdGFrZXJUb1Byb3RvY29sOiBib29sZWFuCglieiAqaWYzM19lbmQKCgkvLyAqaWYzM19jb25zZXF1ZW50CgkvLyBjb250cmFjdHMvdmFsaWRhdG9yUmVnaXN0cnkuYWxnby50czoxMTUwCgkvLyB0aGlzLm51bVN0YWtlcnMudmFsdWUgKz0gMQoJYnl0ZSAweDZlNzU2ZDUzNzQ2MTZiNjU3MjczIC8vICJudW1TdGFrZXJzIgoJYXBwX2dsb2JhbF9nZXQKCWludCAxCgkrCglieXRlIDB4NmU3NTZkNTM3NDYxNmI2NTcyNzMgLy8gIm51bVN0YWtlcnMiCglzd2FwCglhcHBfZ2xvYmFsX3B1dAoKKmlmMzNfZW5kOgoJLy8gY29udHJhY3RzL3ZhbGlkYXRvclJlZ2lzdHJ5LmFsZ28udHM6MTE1MgoJLy8gdGhpcy52YWxpZGF0b3JMaXN0KHBvb2xLZXkuaWQpLnZhbHVlLnN0YXRlLnRvdGFsQWxnb1N0YWtlZCArPSBzdGFrZWRBbW91bnRQYXltZW50LmFtb3VudCAtIG1ickFtdFBhaWQKCWludCAyMTgKCWR1cAoJaW50IDgKCWJ5dGUgMHg3NiAvLyAidiIKCWZyYW1lX2RpZyAtMiAvLyBwb29sS2V5OiBWYWxpZGF0b3JQb29sS2V5CglleHRyYWN0IDAgOAoJYnRvaQoJaXRvYgoJY29uY2F0Cgljb3ZlciAyCglib3hfZXh0cmFjdAoJYnRvaQoJZnJhbWVfZGlnIC0xIC8vIHN0YWtlZEFtb3VudFBheW1lbnQ6IFBheVR4bgoJZ3R4bnMgQW1vdW50CglmcmFtZV9kaWcgLTMgLy8gbWJyQW10UGFpZDogdWludDY0CgktCgkrCglpdG9iCglieXRlIDB4NzYgLy8gInYiCglmcmFtZV9kaWcgLTIgLy8gcG9vbEtleTogVmFsaWRhdG9yUG9vbEtleQoJZXh0cmFjdCAwIDgKCWJ0b2kKCWl0b2IKCWNvbmNhdAoJY292ZXIgMgoJYm94X3JlcGxhY2UKCgkvLyBjb250cmFjdHMvdmFsaWRhdG9yUmVnaXN0cnkuYWxnby50czoxMTUzCgkvLyB0aGlzLnRvdGFsQWxnb1N0YWtlZC52YWx1ZSArPSBzdGFrZWRBbW91bnRQYXltZW50LmFtb3VudCAtIG1ickFtdFBhaWQKCWJ5dGUgMHg3Mzc0NjE2YjY1NjQgLy8gInN0YWtlZCIKCWFwcF9nbG9iYWxfZ2V0CglmcmFtZV9kaWcgLTEgLy8gc3Rha2VkQW1vdW50UGF5bWVudDogUGF5VHhuCglndHhucyBBbW91bnQKCWZyYW1lX2RpZyAtMyAvLyBtYnJBbXRQYWlkOiB1aW50NjQKCS0KCSsKCWJ5dGUgMHg3Mzc0NjE2YjY1NjQgLy8gInN0YWtlZCIKCXN3YXAKCWFwcF9nbG9iYWxfcHV0CglyZXRzdWIKCi8vIHVwZGF0ZVN0YWtlclBvb2xTZXQoc3Rha2VyOiBBZGRyZXNzLCBwb29sS2V5OiBWYWxpZGF0b3JQb29sS2V5KTogdm9pZAp1cGRhdGVTdGFrZXJQb29sU2V0OgoJcHJvdG8gMiAwCgoJLy8gUHVzaCBlbXB0eSBieXRlcyBhZnRlciB0aGUgZnJhbWUgcG9pbnRlciB0byByZXNlcnZlIHNwYWNlIGZvciBsb2NhbCB2YXJpYWJsZXMKCWJ5dGUgMHgKCWR1cAoKCS8vIGNvbnRyYWN0cy92YWxpZGF0b3JSZWdpc3RyeS5hbGdvLnRzOjExNTcKCS8vIGFzc2VydCh0aGlzLnN0YWtlclBvb2xTZXQoc3Rha2VyKS5leGlzdHMpCglieXRlIDB4NzM3MDczIC8vICJzcHMiCglmcmFtZV9kaWcgLTEgLy8gc3Rha2VyOiBBZGRyZXNzCgljb25jYXQKCWJveF9sZW4KCXN3YXAKCXBvcAoJYXNzZXJ0CgoJLy8gY29udHJhY3RzL3ZhbGlkYXRvclJlZ2lzdHJ5LmFsZ28udHM6MTE1OQoJLy8gcG9vbFNldCA9IGNsb25lKHRoaXMuc3Rha2VyUG9vbFNldChzdGFrZXIpLnZhbHVlKQoJYnl0ZSAweDczNzA3MyAvLyAic3BzIgoJZnJhbWVfZGlnIC0xIC8vIHN0YWtlcjogQWRkcmVzcwoJY29uY2F0Cglib3hfZ2V0Cglhc3NlcnQKCWZyYW1lX2J1cnkgMCAvLyBwb29sU2V0OiAodWludDY0LHVpbnQ2NCx1aW50NjQpWzZdCgoJLy8gY29udHJhY3RzL3ZhbGlkYXRvclJlZ2lzdHJ5LmFsZ28udHM6MTE2MAoJLy8gZm9yIChsZXQgaSA9IDA7IGkgPCB0aGlzLnN0YWtlclBvb2xTZXQoc3Rha2VyKS52YWx1ZS5sZW5ndGg7IGkgKz0gMSkKCWludCAwCglmcmFtZV9idXJ5IDEgLy8gaTogdWludDY0CgoqZm9yXzc6CgkvLyBjb250cmFjdHMvdmFsaWRhdG9yUmVnaXN0cnkuYWxnby50czoxMTYwCgkvLyBpIDwgdGhpcy5zdGFrZXJQb29sU2V0KHN0YWtlcikudmFsdWUubGVuZ3RoCglmcmFtZV9kaWcgMSAvLyBpOiB1aW50NjQKCWludCA2Cgk8CglieiAqZm9yXzdfZW5kCgoJLy8gKmlmMzRfY29uZGl0aW9uCgkvLyBjb250cmFjdHMvdmFsaWRhdG9yUmVnaXN0cnkuYWxnby50czoxMTYxCgkvLyBwb29sU2V0W2ldID09PSBwb29sS2V5CglmcmFtZV9kaWcgMCAvLyBwb29sU2V0OiAodWludDY0LHVpbnQ2NCx1aW50NjQpWzZdCglmcmFtZV9kaWcgMSAvLyBpOiB1aW50NjQKCWludCAyNAoJKiAvLyBhY2MgKiB0eXBlTGVuZ3RoCglpbnQgMjQKCWV4dHJhY3QzCglmcmFtZV9kaWcgLTIgLy8gcG9vbEtleTogVmFsaWRhdG9yUG9vbEtleQoJPT0KCWJ6ICppZjM0X2VuZAoKCS8vICppZjM0X2NvbnNlcXVlbnQKCS8vIGNvbnRyYWN0cy92YWxpZGF0b3JSZWdpc3RyeS5hbGdvLnRzOjExNjMKCS8vIHJldHVybjsKCXJldHN1YgoKKmlmMzRfZW5kOgoJLy8gKmlmMzVfY29uZGl0aW9uCgkvLyBjb250cmFjdHMvdmFsaWRhdG9yUmVnaXN0cnkuYWxnby50czoxMTY1CgkvLyBwb29sU2V0W2ldLmlkID09PSAwCglmcmFtZV9kaWcgMCAvLyBwb29sU2V0OiAodWludDY0LHVpbnQ2NCx1aW50NjQpWzZdCglmcmFtZV9kaWcgMSAvLyBpOiB1aW50NjQKCWludCAyNAoJKiAvLyBhY2MgKiB0eXBlTGVuZ3RoCglpbnQgMAoJKwoJaW50IDgKCWV4dHJhY3QzCglidG9pCglpbnQgMAoJPT0KCWJ6ICppZjM1X2VuZAoKCS8vICppZjM1X2NvbnNlcXVlbnQKCS8vIGNvbnRyYWN0cy92YWxpZGF0b3JSZWdpc3RyeS5hbGdvLnRzOjExNjYKCS8vIHRoaXMuc3Rha2VyUG9vbFNldChzdGFrZXIpLnZhbHVlW2ldID0gcG9vbEtleQoJZnJhbWVfZGlnIDEgLy8gaTogdWludDY0CglpbnQgMjQKCSogLy8gYWNjICogdHlwZUxlbmd0aAoJZnJhbWVfZGlnIC0yIC8vIHBvb2xLZXk6IFZhbGlkYXRvclBvb2xLZXkKCWJ5dGUgMHg3MzcwNzMgLy8gInNwcyIKCWZyYW1lX2RpZyAtMSAvLyBzdGFrZXI6IEFkZHJlc3MKCWNvbmNhdAoJY292ZXIgMgoJYm94X3JlcGxhY2UKCgkvLyBjb250cmFjdHMvdmFsaWRhdG9yUmVnaXN0cnkuYWxnby50czoxMTY3CgkvLyByZXR1cm47CglyZXRzdWIKCippZjM1X2VuZDoKCipmb3JfN19jb250aW51ZToKCS8vIGNvbnRyYWN0cy92YWxpZGF0b3JSZWdpc3RyeS5hbGdvLnRzOjExNjAKCS8vIGkgKz0gMQoJZnJhbWVfZGlnIDEgLy8gaTogdWludDY0CglpbnQgMQoJKwoJZnJhbWVfYnVyeSAxIC8vIGk6IHVpbnQ2NAoJYiAqZm9yXzcKCipmb3JfN19lbmQ6CgllcnIgLy8gJ05vIGVtcHR5IHNsb3QgYXZhaWxhYmxlIGluIHRoZSBzdGFrZXIgcG9vbCBzZXQnCgovLyByZW1vdmVGcm9tU3Rha2VyUG9vbFNldChzdGFrZXI6IEFkZHJlc3MsIHBvb2xLZXk6IFZhbGlkYXRvclBvb2xLZXkpOiBbYm9vbGVhbiwgYm9vbGVhbl0KLy8KLy8gUmVtb3ZlcyBhIHBvb2wga2V5IGZyb20gdGhlIHN0YWtlcidzIGFjdGl2ZSBwb29sIHNldCAtIGZhaWxzIGlmIG5vdCBmb3VuZCAoISkKLy8KLy8gQHBhcmFtIHtBZGRyZXNzfSBzdGFrZXIgLSBUaGUgYWRkcmVzcyBvZiB0aGUgc3Rha2VyLgovLyBAcGFyYW0ge1ZhbGlkYXRvclBvb2xLZXl9IHBvb2xLZXkgLSBUaGUgcG9vbCBrZXkgdGhleSBzaG91bGQgYmUgc3RvcmVkIGluCi8vCi8vIEByZXR1cm4gW2Jvb2xlYW4sIGJvb2xlYW5dIFtpcyB0aGUgc3Rha2VyIGdvbmUgZnJvbSBBTEwgcG9vbHMgb2YgdGhlIGdpdmVuIFZBTElEQVRPUiwgYW5kIGlzIHN0YWtlciBnb25lIGZyb20gQUxMIHBvb2xzXQpyZW1vdmVGcm9tU3Rha2VyUG9vbFNldDoKCXByb3RvIDIgMQoKCS8vIFB1c2ggZW1wdHkgYnl0ZXMgYWZ0ZXIgdGhlIGZyYW1lIHBvaW50ZXIgdG8gcmVzZXJ2ZSBzcGFjZSBmb3IgbG9jYWwgdmFyaWFibGVzCglieXRlIDB4CglkdXBuIDQKCgkvLyBjb250cmFjdHMvdmFsaWRhdG9yUmVnaXN0cnkuYWxnby50czoxMTgzCgkvLyBpblNhbWVWYWxpZGF0b3JQb29sQ291bnQgPSAwCglpbnQgMAoJZnJhbWVfYnVyeSAwIC8vIGluU2FtZVZhbGlkYXRvclBvb2xDb3VudDogdWludDY0CgoJLy8gY29udHJhY3RzL3ZhbGlkYXRvclJlZ2lzdHJ5LmFsZ28udHM6MTE4NAoJLy8gaW5BbnlQb29sQ291bnQgPSAwCglpbnQgMAoJZnJhbWVfYnVyeSAxIC8vIGluQW55UG9vbENvdW50OiB1aW50NjQKCgkvLyBjb250cmFjdHMvdmFsaWRhdG9yUmVnaXN0cnkuYWxnby50czoxMTg1CgkvLyBmb3VuZCA9IGZhbHNlCglpbnQgMAoJZnJhbWVfYnVyeSAyIC8vIGZvdW5kOiBib29sCgoJLy8gY29udHJhY3RzL3ZhbGlkYXRvclJlZ2lzdHJ5LmFsZ28udHM6MTE4NwoJLy8gcG9vbFNldCA9IGNsb25lKHRoaXMuc3Rha2VyUG9vbFNldChzdGFrZXIpLnZhbHVlKQoJYnl0ZSAweDczNzA3MyAvLyAic3BzIgoJZnJhbWVfZGlnIC0xIC8vIHN0YWtlcjogQWRkcmVzcwoJY29uY2F0Cglib3hfZ2V0Cglhc3NlcnQKCWZyYW1lX2J1cnkgMyAvLyBwb29sU2V0OiAodWludDY0LHVpbnQ2NCx1aW50NjQpWzZdCgoJLy8gY29udHJhY3RzL3ZhbGlkYXRvclJlZ2lzdHJ5LmFsZ28udHM6MTE4OAoJLy8gZm9yIChsZXQgaSA9IDA7IGkgPCB0aGlzLnN0YWtlclBvb2xTZXQoc3Rha2VyKS52YWx1ZS5sZW5ndGg7IGkgKz0gMSkKCWludCAwCglmcmFtZV9idXJ5IDQgLy8gaTogdWludDY0CgoqZm9yXzg6CgkvLyBjb250cmFjdHMvdmFsaWRhdG9yUmVnaXN0cnkuYWxnby50czoxMTg4CgkvLyBpIDwgdGhpcy5zdGFrZXJQb29sU2V0KHN0YWtlcikudmFsdWUubGVuZ3RoCglmcmFtZV9kaWcgNCAvLyBpOiB1aW50NjQKCWludCA2Cgk8CglieiAqZm9yXzhfZW5kCgoJLy8gKmlmMzZfY29uZGl0aW9uCgkvLyBjb250cmFjdHMvdmFsaWRhdG9yUmVnaXN0cnkuYWxnby50czoxMTg5CgkvLyBwb29sU2V0W2ldLmlkID09PSAwCglmcmFtZV9kaWcgMyAvLyBwb29sU2V0OiAodWludDY0LHVpbnQ2NCx1aW50NjQpWzZdCglmcmFtZV9kaWcgNCAvLyBpOiB1aW50NjQKCWludCAyNAoJKiAvLyBhY2MgKiB0eXBlTGVuZ3RoCglpbnQgMAoJKwoJaW50IDgKCWV4dHJhY3QzCglidG9pCglpbnQgMAoJPT0KCWJ6ICppZjM2X2VuZAoKCS8vICppZjM2X2NvbnNlcXVlbnQKCWIgKmZvcl84X2NvbnRpbnVlCgoqaWYzNl9lbmQ6CgkvLyBjb250cmFjdHMvdmFsaWRhdG9yUmVnaXN0cnkuYWxnby50czoxMTkyCgkvLyBpbkFueVBvb2xDb3VudCArPSAxCglmcmFtZV9kaWcgMSAvLyBpbkFueVBvb2xDb3VudDogdWludDY0CglpbnQgMQoJKwoJZnJhbWVfYnVyeSAxIC8vIGluQW55UG9vbENvdW50OiB1aW50NjQKCgkvLyAqaWYzN19jb25kaXRpb24KCS8vIGNvbnRyYWN0cy92YWxpZGF0b3JSZWdpc3RyeS5hbGdvLnRzOjExOTMKCS8vIHBvb2xTZXRbaV0uaWQgPT09IHBvb2xLZXkuaWQKCWZyYW1lX2RpZyAzIC8vIHBvb2xTZXQ6ICh1aW50NjQsdWludDY0LHVpbnQ2NClbNl0KCWZyYW1lX2RpZyA0IC8vIGk6IHVpbnQ2NAoJaW50IDI0CgkqIC8vIGFjYyAqIHR5cGVMZW5ndGgKCWludCAwCgkrCglpbnQgOAoJZXh0cmFjdDMKCWJ0b2kKCWZyYW1lX2RpZyAtMiAvLyBwb29sS2V5OiBWYWxpZGF0b3JQb29sS2V5CglleHRyYWN0IDAgOAoJYnRvaQoJPT0KCWJ6ICppZjM3X2VuZAoKCS8vICppZjM3X2NvbnNlcXVlbnQKCS8vICppZjM4X2NvbmRpdGlvbgoJLy8gY29udHJhY3RzL3ZhbGlkYXRvclJlZ2lzdHJ5LmFsZ28udHM6MTE5NAoJLy8gcG9vbFNldFtpXSA9PT0gcG9vbEtleQoJZnJhbWVfZGlnIDMgLy8gcG9vbFNldDogKHVpbnQ2NCx1aW50NjQsdWludDY0KVs2XQoJZnJhbWVfZGlnIDQgLy8gaTogdWludDY0CglpbnQgMjQKCSogLy8gYWNjICogdHlwZUxlbmd0aAoJaW50IDI0CglleHRyYWN0MwoJZnJhbWVfZGlnIC0yIC8vIHBvb2xLZXk6IFZhbGlkYXRvclBvb2xLZXkKCT09CglieiAqaWYzOF9lbHNlCgoJLy8gKmlmMzhfY29uc2VxdWVudAoJLy8gY29udHJhY3RzL3ZhbGlkYXRvclJlZ2lzdHJ5LmFsZ28udHM6MTE5NQoJLy8gZm91bmQgPSB0cnVlCglpbnQgMQoJZnJhbWVfYnVyeSAyIC8vIGZvdW5kOiBib29sCgoJLy8gY29udHJhY3RzL3ZhbGlkYXRvclJlZ2lzdHJ5LmFsZ28udHM6MTE5NwoJLy8gdGhpcy5zdGFrZXJQb29sU2V0KHN0YWtlcikudmFsdWVbaV0gPSB7IGlkOiAwLCBwb29sSWQ6IDAsIHBvb2xBcHBJZDogMCB9CglmcmFtZV9kaWcgNCAvLyBpOiB1aW50NjQKCWludCAyNAoJKiAvLyBhY2MgKiB0eXBlTGVuZ3RoCglieXRlIDB4MDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwCglieXRlIDB4NzM3MDczIC8vICJzcHMiCglmcmFtZV9kaWcgLTEgLy8gc3Rha2VyOiBBZGRyZXNzCgljb25jYXQKCWNvdmVyIDIKCWJveF9yZXBsYWNlCgliICppZjM4X2VuZAoKKmlmMzhfZWxzZToKCS8vIGNvbnRyYWN0cy92YWxpZGF0b3JSZWdpc3RyeS5hbGdvLnRzOjExOTkKCS8vIGluU2FtZVZhbGlkYXRvclBvb2xDb3VudCArPSAxCglmcmFtZV9kaWcgMCAvLyBpblNhbWVWYWxpZGF0b3JQb29sQ291bnQ6IHVpbnQ2NAoJaW50IDEKCSsKCWZyYW1lX2J1cnkgMCAvLyBpblNhbWVWYWxpZGF0b3JQb29sQ291bnQ6IHVpbnQ2NAoKKmlmMzhfZW5kOgoKKmlmMzdfZW5kOgoKKmZvcl84X2NvbnRpbnVlOgoJLy8gY29udHJhY3RzL3ZhbGlkYXRvclJlZ2lzdHJ5LmFsZ28udHM6MTE4OAoJLy8gaSArPSAxCglmcmFtZV9kaWcgNCAvLyBpOiB1aW50NjQKCWludCAxCgkrCglmcmFtZV9idXJ5IDQgLy8gaTogdWludDY0CgliICpmb3JfOAoKKmZvcl84X2VuZDoKCS8vICppZjM5X2NvbmRpdGlvbgoJLy8gY29udHJhY3RzL3ZhbGlkYXRvclJlZ2lzdHJ5LmFsZ28udHM6MTIwMwoJLy8gIWZvdW5kCglmcmFtZV9kaWcgMiAvLyBmb3VuZDogYm9vbAoJIQoJYnogKmlmMzlfZW5kCgoJLy8gKmlmMzlfY29uc2VxdWVudAoJZXJyIC8vICdObyBtYXRjaGluZyBzbG90IGZvdW5kIHdoZW4gdG9sZCB0byByZW1vdmUgYSBwb29sIGZyb20gdGhlIHN0YWtlcnMgc2V0JwoKKmlmMzlfZW5kOgoJLy8gY29udHJhY3RzL3ZhbGlkYXRvclJlZ2lzdHJ5LmFsZ28udHM6MTIwNwoJLy8gcmV0dXJuIFtpblNhbWVWYWxpZGF0b3JQb29sQ291bnQgPT09IDAsIGluQW55UG9vbENvdW50ID09PSAwXTsKCWJ5dGUgMHgwMAoJaW50IDAKCWZyYW1lX2RpZyAwIC8vIGluU2FtZVZhbGlkYXRvclBvb2xDb3VudDogdWludDY0CglpbnQgMAoJPT0KCXNldGJpdAoJaW50IDEKCWZyYW1lX2RpZyAxIC8vIGluQW55UG9vbENvdW50OiB1aW50NjQKCWludCAwCgk9PQoJc2V0Yml0CgoJLy8gc2V0IHRoZSBzdWJyb3V0aW5lIHJldHVybiB2YWx1ZQoJZnJhbWVfYnVyeSAwCgoJLy8gcG9wIGFsbCBsb2NhbCB2YXJpYWJsZXMgZnJvbSB0aGUgc3RhY2sKCXBvcG4gNAoJcmV0c3ViCgovLyBhZGRQb29sVG9Ob2RlKHZhbGlkYXRvcklkOiBWYWxpZGF0b3JJZFR5cGUsIHBvb2xBcHBJZDogdWludDY0LCBub2RlTnVtOiB1aW50NjQpOiB2b2lkCmFkZFBvb2xUb05vZGU6Cglwcm90byAzIDAKCgkvLyBQdXNoIGVtcHR5IGJ5dGVzIGFmdGVyIHRoZSBmcmFtZSBwb2ludGVyIHRvIHJlc2VydmUgc3BhY2UgZm9yIGxvY2FsIHZhcmlhYmxlcwoJYnl0ZSAweAoJZHVwbiAyCgoJLy8gY29udHJhY3RzL3ZhbGlkYXRvclJlZ2lzdHJ5LmFsZ28udHM6MTIxMQoJLy8gbm9kZVBvb2xBc3NpZ25tZW50cyA9IGNsb25lKHRoaXMudmFsaWRhdG9yTGlzdCh2YWxpZGF0b3JJZCkudmFsdWUubm9kZVBvb2xBc3NpZ25tZW50cykKCWludCA4NjYgLy8gaGVhZE9mZnNldAoJaW50IDE5MgoJYnl0ZSAweDc2IC8vICJ2IgoJZnJhbWVfZGlnIC0xIC8vIHZhbGlkYXRvcklkOiBWYWxpZGF0b3JJZFR5cGUKCWl0b2IKCWNvbmNhdAoJY292ZXIgMgoJYm94X2V4dHJhY3QKCWZyYW1lX2J1cnkgMCAvLyBub2RlUG9vbEFzc2lnbm1lbnRzOiAoKHVpbnQ2NFszXSlbOF0pCgoJLy8gY29udHJhY3RzL3ZhbGlkYXRvclJlZ2lzdHJ5LmFsZ28udHM6MTIxMgoJLy8gbWF4UG9vbHNQZXJOb2RlRm9yVGhpc1ZhbGlkYXRvciA9IHRoaXMudmFsaWRhdG9yTGlzdCh2YWxpZGF0b3JJZCkudmFsdWUuY29uZmlnLnBvb2xzUGVyTm9kZSBhcyB1aW50NjQKCWludCAxOTEKCWludCAxCglieXRlIDB4NzYgLy8gInYiCglmcmFtZV9kaWcgLTEgLy8gdmFsaWRhdG9ySWQ6IFZhbGlkYXRvcklkVHlwZQoJaXRvYgoJY29uY2F0Cgljb3ZlciAyCglib3hfZXh0cmFjdAoJYnRvaQoJZnJhbWVfYnVyeSAxIC8vIG1heFBvb2xzUGVyTm9kZUZvclRoaXNWYWxpZGF0b3I6IHVpbnQ2NAoKCS8vIGNvbnRyYWN0cy92YWxpZGF0b3JSZWdpc3RyeS5hbGdvLnRzOjEyMTQKCS8vIGFzc2VydChub2RlTnVtID49IDEgJiYgbm9kZU51bSA8PSBNQVhfTk9ERVMpCglmcmFtZV9kaWcgLTMgLy8gbm9kZU51bTogdWludDY0CglpbnQgMQoJPj0KCWR1cAoJYnogKnNraXBfYW5kOAoJZnJhbWVfZGlnIC0zIC8vIG5vZGVOdW06IHVpbnQ2NAoJaW50IDgKCTw9CgkmJgoKKnNraXBfYW5kODoKCWFzc2VydAoKCS8vIGNvbnRyYWN0cy92YWxpZGF0b3JSZWdpc3RyeS5hbGdvLnRzOjEyMTYKCS8vIGZvciAobGV0IGkgPSAwOyBpIDwgbWF4UG9vbHNQZXJOb2RlRm9yVGhpc1ZhbGlkYXRvcjsgaSArPSAxKQoJaW50IDAKCWZyYW1lX2J1cnkgMiAvLyBpOiB1aW50NjQKCipmb3JfOToKCS8vIGNvbnRyYWN0cy92YWxpZGF0b3JSZWdpc3RyeS5hbGdvLnRzOjEyMTYKCS8vIGkgPCBtYXhQb29sc1Blck5vZGVGb3JUaGlzVmFsaWRhdG9yCglmcmFtZV9kaWcgMiAvLyBpOiB1aW50NjQKCWZyYW1lX2RpZyAxIC8vIG1heFBvb2xzUGVyTm9kZUZvclRoaXNWYWxpZGF0b3I6IHVpbnQ2NAoJPAoJYnogKmZvcl85X2VuZAoKCS8vICppZjQwX2NvbmRpdGlvbgoJLy8gY29udHJhY3RzL3ZhbGlkYXRvclJlZ2lzdHJ5LmFsZ28udHM6MTIxNwoJLy8gbm9kZVBvb2xBc3NpZ25tZW50cy5ub2Rlc1tub2RlTnVtIC0gMV0ucG9vbEFwcElkc1tpXSA9PT0gMAoJZnJhbWVfZGlnIDAgLy8gbm9kZVBvb2xBc3NpZ25tZW50czogKCh1aW50NjRbM10pWzhdKQoJaW50IDAKCWZyYW1lX2RpZyAtMyAvLyBub2RlTnVtOiB1aW50NjQKCWludCAxCgktCglpbnQgMjQKCSogLy8gYWNjICogdHlwZUxlbmd0aAoJKwoJaW50IDAKCSsKCWZyYW1lX2RpZyAyIC8vIGk6IHVpbnQ2NAoJaW50IDgKCSogLy8gYWNjICogdHlwZUxlbmd0aAoJKwoJaW50IDgKCWV4dHJhY3QzCglidG9pCglpbnQgMAoJPT0KCWJ6ICppZjQwX2VuZAoKCS8vICppZjQwX2NvbnNlcXVlbnQKCS8vIGNvbnRyYWN0cy92YWxpZGF0b3JSZWdpc3RyeS5hbGdvLnRzOjEyMTkKCS8vIHRoaXMudmFsaWRhdG9yTGlzdCh2YWxpZGF0b3JJZCkudmFsdWUubm9kZVBvb2xBc3NpZ25tZW50cy5ub2Rlc1tub2RlTnVtIC0gMV0ucG9vbEFwcElkc1tpXSA9IHBvb2xBcHBJZAoJaW50IDg2NgoJZnJhbWVfZGlnIC0zIC8vIG5vZGVOdW06IHVpbnQ2NAoJaW50IDEKCS0KCWludCAyNAoJKiAvLyBhY2MgKiB0eXBlTGVuZ3RoCgkrCglpbnQgMAoJKwoJZnJhbWVfZGlnIDIgLy8gaTogdWludDY0CglpbnQgOAoJKiAvLyBhY2MgKiB0eXBlTGVuZ3RoCgkrCglmcmFtZV9kaWcgLTIgLy8gcG9vbEFwcElkOiB1aW50NjQKCWl0b2IKCWJ5dGUgMHg3NiAvLyAidiIKCWZyYW1lX2RpZyAtMSAvLyB2YWxpZGF0b3JJZDogVmFsaWRhdG9ySWRUeXBlCglpdG9iCgljb25jYXQKCWNvdmVyIDIKCWJveF9yZXBsYWNlCgoJLy8gY29udHJhY3RzL3ZhbGlkYXRvclJlZ2lzdHJ5LmFsZ28udHM6MTIyMAoJLy8gcmV0dXJuOwoJcmV0c3ViCgoqaWY0MF9lbmQ6CgoqZm9yXzlfY29udGludWU6CgkvLyBjb250cmFjdHMvdmFsaWRhdG9yUmVnaXN0cnkuYWxnby50czoxMjE2CgkvLyBpICs9IDEKCWZyYW1lX2RpZyAyIC8vIGk6IHVpbnQ2NAoJaW50IDEKCSsKCWZyYW1lX2J1cnkgMiAvLyBpOiB1aW50NjQKCWIgKmZvcl85CgoqZm9yXzlfZW5kOgoJZXJyIC8vICdubyBhdmFpbGFibGUgc3BhY2UgaW4gc3BlY2lmaWVkIG5vZGUgZm9yIHRoaXMgcG9vbCcKCi8vIGRvZXNTdGFrZXJNZWV0R2F0aW5nKHZhbGlkYXRvcklkOiBWYWxpZGF0b3JJZFR5cGUsIHZhbHVlVG9WZXJpZnk6IHVpbnQ2NCk6IHZvaWQKLy8KLy8gQ2hlY2tzIGlmIGEgc3Rha2VyIG1lZXRzIHRoZSBnYXRpbmcgcmVxdWlyZW1lbnRzIHNwZWNpZmllZCBieSB0aGUgdmFsaWRhdG9yLgovLwovLyBAcGFyYW0ge1ZhbGlkYXRvcklkVHlwZX0gdmFsaWRhdG9ySWQgLSBUaGUgaWQgb2YgdGhlIHZhbGlkYXRvci4KLy8gQHBhcmFtIHt1aW50NjR9IHZhbHVlVG9WZXJpZnkgLSBUaGUgdmFsdWUgdG8gdmVyaWZ5IGFnYWluc3QgdGhlIGdhdGluZyByZXF1aXJlbWVudHMuCi8vIEByZXR1cm5zIHt2b2lkfSBvciBhc3NlcnRzIGlmIHJlcXVpcmVtZW50cyBub3QgbWV0Lgpkb2VzU3Rha2VyTWVldEdhdGluZzoKCXByb3RvIDIgMAoKCS8vIFB1c2ggZW1wdHkgYnl0ZXMgYWZ0ZXIgdGhlIGZyYW1lIHBvaW50ZXIgdG8gcmVzZXJ2ZSBzcGFjZSBmb3IgbG9jYWwgdmFyaWFibGVzCglieXRlIDB4CglkdXBuIDcKCgkvLyBjb250cmFjdHMvdmFsaWRhdG9yUmVnaXN0cnkuYWxnby50czoxMjM0CgkvLyB0eXBlID0gdGhpcy52YWxpZGF0b3JMaXN0KHZhbGlkYXRvcklkKS52YWx1ZS5jb25maWcuZW50cnlHYXRpbmdUeXBlCglpbnQgODAKCWludCAxCglieXRlIDB4NzYgLy8gInYiCglmcmFtZV9kaWcgLTEgLy8gdmFsaWRhdG9ySWQ6IFZhbGlkYXRvcklkVHlwZQoJaXRvYgoJY29uY2F0Cgljb3ZlciAyCglib3hfZXh0cmFjdAoJYnRvaQoJZnJhbWVfYnVyeSAwIC8vIHR5cGU6IHVpbnQ4CgoJLy8gKmlmNDFfY29uZGl0aW9uCgkvLyBjb250cmFjdHMvdmFsaWRhdG9yUmVnaXN0cnkuYWxnby50czoxMjM1CgkvLyB0eXBlID09PSBHQVRJTkdfVFlQRV9OT05FCglmcmFtZV9kaWcgMCAvLyB0eXBlOiB1aW50OAoJaW50IDAKCT09CglieiAqaWY0MV9lbmQKCgkvLyAqaWY0MV9jb25zZXF1ZW50CgkvLyBjb250cmFjdHMvdmFsaWRhdG9yUmVnaXN0cnkuYWxnby50czoxMjM2CgkvLyByZXR1cm47CglyZXRzdWIKCippZjQxX2VuZDoKCS8vIGNvbnRyYWN0cy92YWxpZGF0b3JSZWdpc3RyeS5hbGdvLnRzOjEyMzgKCS8vIHN0YWtlciA9IHRoaXMudHhuLnNlbmRlcgoJdHhuIFNlbmRlcgoJZnJhbWVfYnVyeSAxIC8vIHN0YWtlcjogYWRkcmVzcwoKCS8vIGNvbnRyYWN0cy92YWxpZGF0b3JSZWdpc3RyeS5hbGdvLnRzOjEyMzkKCS8vIGdhdGVSZXEgPSBjbG9uZSh0aGlzLnZhbGlkYXRvckxpc3QodmFsaWRhdG9ySWQpLnZhbHVlLmNvbmZpZy5lbnRyeUdhdGluZ1ZhbHVlKQoJaW50IDgxCglpbnQgMzIKCWJ5dGUgMHg3NiAvLyAidiIKCWZyYW1lX2RpZyAtMSAvLyB2YWxpZGF0b3JJZDogVmFsaWRhdG9ySWRUeXBlCglpdG9iCgljb25jYXQKCWNvdmVyIDIKCWJveF9leHRyYWN0CglmcmFtZV9idXJ5IDIgLy8gZ2F0ZVJlcTogYnl0ZVszMl0KCgkvLyAqaWY0Ml9jb25kaXRpb24KCS8vIGNvbnRyYWN0cy92YWxpZGF0b3JSZWdpc3RyeS5hbGdvLnRzOjEyNDMKCS8vIHR5cGUgPT09IEdBVElOR19UWVBFX0FTU0VUU19DUkVBVEVEX0JZIHx8CgkvLyAgICAgICAgICAgICB0eXBlID09PSBHQVRJTkdfVFlQRV9BU1NFVF9JRCB8fAoJLy8gICAgICAgICAgICAgdHlwZSA9PT0gR0FUSU5HX1RZUEVfQ1JFQVRFRF9CWV9ORkRfQUREUkVTU0VTCglmcmFtZV9kaWcgMCAvLyB0eXBlOiB1aW50OAoJaW50IDEKCT09CglkdXAKCWJueiAqc2tpcF9vcjQKCWZyYW1lX2RpZyAwIC8vIHR5cGU6IHVpbnQ4CglpbnQgMgoJPT0KCXx8Cgoqc2tpcF9vcjQ6CglkdXAKCWJueiAqc2tpcF9vcjUKCWZyYW1lX2RpZyAwIC8vIHR5cGU6IHVpbnQ4CglpbnQgMwoJPT0KCXx8Cgoqc2tpcF9vcjU6CglieiAqaWY0Ml9lbmQKCgkvLyAqaWY0Ml9jb25zZXF1ZW50CgkvLyBjb250cmFjdHMvdmFsaWRhdG9yUmVnaXN0cnkuYWxnby50czoxMjQ3CgkvLyBhc3NlcnQodmFsdWVUb1ZlcmlmeSAhPT0gMCkKCWZyYW1lX2RpZyAtMiAvLyB2YWx1ZVRvVmVyaWZ5OiB1aW50NjQKCWludCAwCgkhPQoJYXNzZXJ0CgoJLy8gY29udHJhY3RzL3ZhbGlkYXRvclJlZ2lzdHJ5LmFsZ28udHM6MTI0OAoJLy8gYmFsUmVxdWlyZWQgPSB0aGlzLnZhbGlkYXRvckxpc3QodmFsaWRhdG9ySWQpLnZhbHVlLmNvbmZpZy5nYXRpbmdBc3NldE1pbkJhbGFuY2UKCWludCAxMTMKCWludCA4CglieXRlIDB4NzYgLy8gInYiCglmcmFtZV9kaWcgLTEgLy8gdmFsaWRhdG9ySWQ6IFZhbGlkYXRvcklkVHlwZQoJaXRvYgoJY29uY2F0Cgljb3ZlciAyCglib3hfZXh0cmFjdAoJYnRvaQoJZnJhbWVfYnVyeSAzIC8vIGJhbFJlcXVpcmVkOiB1aW50NjQKCgkvLyAqaWY0M19jb25kaXRpb24KCS8vIGNvbnRyYWN0cy92YWxpZGF0b3JSZWdpc3RyeS5hbGdvLnRzOjEyNDkKCS8vIGJhbFJlcXVpcmVkID09PSAwCglmcmFtZV9kaWcgMyAvLyBiYWxSZXF1aXJlZDogdWludDY0CglpbnQgMAoJPT0KCWJ6ICppZjQzX2VuZAoKCS8vICppZjQzX2NvbnNlcXVlbnQKCS8vIGNvbnRyYWN0cy92YWxpZGF0b3JSZWdpc3RyeS5hbGdvLnRzOjEyNTAKCS8vIGJhbFJlcXVpcmVkID0gMQoJaW50IDEKCWZyYW1lX2J1cnkgMyAvLyBiYWxSZXF1aXJlZDogdWludDY0CgoqaWY0M19lbmQ6CgkvLyBjb250cmFjdHMvdmFsaWRhdG9yUmVnaXN0cnkuYWxnby50czoxMjUyCgkvLyBhc3NlcnQoCgkvLyAgICAgICAgICAgICAgICAgc3Rha2VyLmFzc2V0QmFsYW5jZShBc3NldElELmZyb21VaW50NjQodmFsdWVUb1ZlcmlmeSkpID49IGJhbFJlcXVpcmVkLAoJLy8gICAgICAgICAgICAgICAgICdtdXN0IGhhdmUgcmVxdWlyZWQgbWluaW11bSBiYWxhbmNlIG9mIHZhbGlkYXRvciBkZWZpbmVkIHRva2VuIHRvIGFkZCBzdGFrZScKCS8vICAgICAgICAgICAgICkKCWZyYW1lX2RpZyAxIC8vIHN0YWtlcjogYWRkcmVzcwoJZnJhbWVfZGlnIC0yIC8vIHZhbHVlVG9WZXJpZnk6IHVpbnQ2NAoJYXNzZXRfaG9sZGluZ19nZXQgQXNzZXRCYWxhbmNlCglwb3AKCWZyYW1lX2RpZyAzIC8vIGJhbFJlcXVpcmVkOiB1aW50NjQKCT49CgoJLy8gbXVzdCBoYXZlIHJlcXVpcmVkIG1pbmltdW0gYmFsYW5jZSBvZiB2YWxpZGF0b3IgZGVmaW5lZCB0b2tlbiB0byBhZGQgc3Rha2UKCWFzc2VydAoKKmlmNDJfZW5kOgoJLy8gKmlmNDRfY29uZGl0aW9uCgkvLyBjb250cmFjdHMvdmFsaWRhdG9yUmVnaXN0cnkuYWxnby50czoxMjU3CgkvLyB0eXBlID09PSBHQVRJTkdfVFlQRV9BU1NFVFNfQ1JFQVRFRF9CWQoJZnJhbWVfZGlnIDAgLy8gdHlwZTogdWludDgKCWludCAxCgk9PQoJYnogKmlmNDRfZW5kCgoJLy8gKmlmNDRfY29uc2VxdWVudAoJLy8gY29udHJhY3RzL3ZhbGlkYXRvclJlZ2lzdHJ5LmFsZ28udHM6MTI1OAoJLy8gYXNzZXJ0KAoJLy8gICAgICAgICAgICAgICAgIEFzc2V0SUQuZnJvbVVpbnQ2NCh2YWx1ZVRvVmVyaWZ5KS5jcmVhdG9yID09PSBBZGRyZXNzLmZyb21CeXRlcyhnYXRlUmVxKSwKCS8vICAgICAgICAgICAgICAgICAnc3BlY2lmaWVkIGFzc2V0IG11c3QgYmUgY3JlYXRlZCBieSBjcmVhdG9yIHRoYXQgdGhlIHZhbGlkYXRvciBkZWZpbmVkIGFzIGEgcmVxdWlyZW1lbnQgdG8gc3Rha2UnCgkvLyAgICAgICAgICAgICApCglmcmFtZV9kaWcgLTIgLy8gdmFsdWVUb1ZlcmlmeTogdWludDY0Cglhc3NldF9wYXJhbXNfZ2V0IEFzc2V0Q3JlYXRvcgoJcG9wCglmcmFtZV9kaWcgMiAvLyBnYXRlUmVxOiBieXRlWzMyXQoJPT0KCgkvLyBzcGVjaWZpZWQgYXNzZXQgbXVzdCBiZSBjcmVhdGVkIGJ5IGNyZWF0b3IgdGhhdCB0aGUgdmFsaWRhdG9yIGRlZmluZWQgYXMgYSByZXF1aXJlbWVudCB0byBzdGFrZQoJYXNzZXJ0CgoqaWY0NF9lbmQ6CgkvLyAqaWY0NV9jb25kaXRpb24KCS8vIGNvbnRyYWN0cy92YWxpZGF0b3JSZWdpc3RyeS5hbGdvLnRzOjEyNjMKCS8vIHR5cGUgPT09IEdBVElOR19UWVBFX0FTU0VUX0lECglmcmFtZV9kaWcgMCAvLyB0eXBlOiB1aW50OAoJaW50IDIKCT09CglieiAqaWY0NV9lbmQKCgkvLyAqaWY0NV9jb25zZXF1ZW50CgkvLyBjb250cmFjdHMvdmFsaWRhdG9yUmVnaXN0cnkuYWxnby50czoxMjY0CgkvLyByZXF1aXJlZEFzc2V0ID0gZXh0cmFjdFVpbnQ2NChnYXRlUmVxLCAwKQoJZnJhbWVfZGlnIDIgLy8gZ2F0ZVJlcTogYnl0ZVszMl0KCWludCAwCglleHRyYWN0X3VpbnQ2NAoJZnJhbWVfYnVyeSA0IC8vIHJlcXVpcmVkQXNzZXQ6IHVpbnQ2NAoKCS8vIGNvbnRyYWN0cy92YWxpZGF0b3JSZWdpc3RyeS5hbGdvLnRzOjEyNjUKCS8vIGFzc2VydChyZXF1aXJlZEFzc2V0ICE9PSAwKQoJZnJhbWVfZGlnIDQgLy8gcmVxdWlyZWRBc3NldDogdWludDY0CglpbnQgMAoJIT0KCWFzc2VydAoKCS8vIGNvbnRyYWN0cy92YWxpZGF0b3JSZWdpc3RyeS5hbGdvLnRzOjEyNjYKCS8vIGFzc2VydCgKCS8vICAgICAgICAgICAgICAgICB2YWx1ZVRvVmVyaWZ5ID09PSByZXF1aXJlZEFzc2V0LAoJLy8gICAgICAgICAgICAgICAgICdzcGVjaWZpZWQgYXNzZXQgbXVzdCBiZSBpZGVudGljYWwgdG8gdGhlIGFzc2V0IGlkIGRlZmluZWQgYXMgYSByZXF1aXJlbWVudCB0byBzdGFrZScKCS8vICAgICAgICAgICAgICkKCWZyYW1lX2RpZyAtMiAvLyB2YWx1ZVRvVmVyaWZ5OiB1aW50NjQKCWZyYW1lX2RpZyA0IC8vIHJlcXVpcmVkQXNzZXQ6IHVpbnQ2NAoJPT0KCgkvLyBzcGVjaWZpZWQgYXNzZXQgbXVzdCBiZSBpZGVudGljYWwgdG8gdGhlIGFzc2V0IGlkIGRlZmluZWQgYXMgYSByZXF1aXJlbWVudCB0byBzdGFrZQoJYXNzZXJ0CgoqaWY0NV9lbmQ6CgkvLyAqaWY0Nl9jb25kaXRpb24KCS8vIGNvbnRyYWN0cy92YWxpZGF0b3JSZWdpc3RyeS5hbGdvLnRzOjEyNzEKCS8vIHR5cGUgPT09IEdBVElOR19UWVBFX0NSRUFURURfQllfTkZEX0FERFJFU1NFUwoJZnJhbWVfZGlnIDAgLy8gdHlwZTogdWludDgKCWludCAzCgk9PQoJYnogKmlmNDZfZW5kCgoJLy8gKmlmNDZfY29uc2VxdWVudAoJLy8gY29udHJhY3RzL3ZhbGlkYXRvclJlZ2lzdHJ5LmFsZ28udHM6MTI3MgoJLy8gbmZkRm9ySW5mbyA9IHRoaXMudmFsaWRhdG9yTGlzdCh2YWxpZGF0b3JJZCkudmFsdWUuY29uZmlnLm5mZEZvckluZm8KCWludCA3MgoJaW50IDgKCWJ5dGUgMHg3NiAvLyAidiIKCWZyYW1lX2RpZyAtMSAvLyB2YWxpZGF0b3JJZDogVmFsaWRhdG9ySWRUeXBlCglpdG9iCgljb25jYXQKCWNvdmVyIDIKCWJveF9leHRyYWN0CglidG9pCglmcmFtZV9idXJ5IDUgLy8gbmZkRm9ySW5mbzogdWludDY0CgoJLy8gY29udHJhY3RzL3ZhbGlkYXRvclJlZ2lzdHJ5LmFsZ28udHM6MTI3NQoJLy8gYXNzZXJ0KAoJLy8gICAgICAgICAgICAgICAgIHRoaXMuaXNBZGRyZXNzSW5ORkRDQUFsZ29MaXN0KG5mZEZvckluZm8sIEFzc2V0SUQuZnJvbVVpbnQ2NCh2YWx1ZVRvVmVyaWZ5KS5jcmVhdG9yKSwKCS8vICAgICAgICAgICAgICAgICAnc3BlY2lmaWVkIGFzc2V0IG11c3QgYmUgY3JlYXRlZCBieSBjcmVhdG9yIHRoYXQgaXMgb25lIG9mIHRoZSBsaW5rZWQgYWRkcmVzc2VzIGluIGFuIG5mZCcKCS8vICAgICAgICAgICAgICkKCWZyYW1lX2RpZyAtMiAvLyB2YWx1ZVRvVmVyaWZ5OiB1aW50NjQKCWFzc2V0X3BhcmFtc19nZXQgQXNzZXRDcmVhdG9yCglwb3AKCWZyYW1lX2RpZyA1IC8vIG5mZEZvckluZm86IHVpbnQ2NAoJY2FsbHN1YiBpc0FkZHJlc3NJbk5GRENBQWxnb0xpc3QKCgkvLyBzcGVjaWZpZWQgYXNzZXQgbXVzdCBiZSBjcmVhdGVkIGJ5IGNyZWF0b3IgdGhhdCBpcyBvbmUgb2YgdGhlIGxpbmtlZCBhZGRyZXNzZXMgaW4gYW4gbmZkCglhc3NlcnQKCippZjQ2X2VuZDoKCS8vICppZjQ3X2NvbmRpdGlvbgoJLy8gY29udHJhY3RzL3ZhbGlkYXRvclJlZ2lzdHJ5LmFsZ28udHM6MTI4MAoJLy8gdHlwZSA9PT0gR0FUSU5HX1RZUEVfU0VHTUVOVF9PRl9ORkQKCWZyYW1lX2RpZyAwIC8vIHR5cGU6IHVpbnQ4CglpbnQgNAoJPT0KCWJ6ICppZjQ3X2VuZAoKCS8vICppZjQ3X2NvbnNlcXVlbnQKCS8vIGNvbnRyYWN0cy92YWxpZGF0b3JSZWdpc3RyeS5hbGdvLnRzOjEyODIKCS8vIHVzZXJPZmZlcmVkTkZEQXBwSUQgPSB2YWx1ZVRvVmVyaWZ5CglmcmFtZV9kaWcgLTIgLy8gdmFsdWVUb1ZlcmlmeTogdWludDY0CglmcmFtZV9idXJ5IDYgLy8gdXNlck9mZmVyZWRORkRBcHBJRDogdWludDY0CgoJLy8gY29udHJhY3RzL3ZhbGlkYXRvclJlZ2lzdHJ5LmFsZ28udHM6MTI4MwoJLy8gYXNzZXJ0KHRoaXMuaXNORkRBcHBJRFZhbGlkKHVzZXJPZmZlcmVkTkZEQXBwSUQpLCAncHJvdmlkZWQgTkZEIG11c3QgYmUgdmFsaWQnKQoJZnJhbWVfZGlnIDYgLy8gdXNlck9mZmVyZWRORkRBcHBJRDogdWludDY0CgljYWxsc3ViIGlzTkZEQXBwSURWYWxpZAoKCS8vIHByb3ZpZGVkIE5GRCBtdXN0IGJlIHZhbGlkCglhc3NlcnQKCgkvLyBjb250cmFjdHMvdmFsaWRhdG9yUmVnaXN0cnkuYWxnby50czoxMjg2CgkvLyBhc3NlcnQoCgkvLyAgICAgICAgICAgICAgICAgcmF3Qnl0ZXMoQXBwSUQuZnJvbVVpbnQ2NCh1c2VyT2ZmZXJlZE5GREFwcElEKS5nbG9iYWxTdGF0ZSgnaS5vd25lci5hJykgYXMgQWRkcmVzcykgPT09CgkvLyAgICAgICAgICAgICAgICAgICAgIHJhd0J5dGVzKHN0YWtlcikgfHwgdGhpcy5pc0FkZHJlc3NJbk5GRENBQWxnb0xpc3QodXNlck9mZmVyZWRORkRBcHBJRCwgc3Rha2VyKSwKCS8vICAgICAgICAgICAgICAgICAicHJvdmlkZWQgbmZkIGZvciBlbnRyeSBpc24ndCBvd25lZCBvciBsaW5rZWQgdG8gdGhlIHN0YWtlciIKCS8vICAgICAgICAgICAgICkKCWZyYW1lX2RpZyA2IC8vIHVzZXJPZmZlcmVkTkZEQXBwSUQ6IHVpbnQ2NAoJYnl0ZSAweDY5MmU2Zjc3NmU2NTcyMmU2MSAvLyAiaS5vd25lci5hIgoJYXBwX2dsb2JhbF9nZXRfZXgKCWFzc2VydAoJZnJhbWVfZGlnIDEgLy8gc3Rha2VyOiBhZGRyZXNzCgk9PQoJZHVwCglibnogKnNraXBfb3I2CglmcmFtZV9kaWcgMSAvLyBzdGFrZXI6IGFkZHJlc3MKCWZyYW1lX2RpZyA2IC8vIHVzZXJPZmZlcmVkTkZEQXBwSUQ6IHVpbnQ2NAoJY2FsbHN1YiBpc0FkZHJlc3NJbk5GRENBQWxnb0xpc3QKCXx8Cgoqc2tpcF9vcjY6CgkvLyBwcm92aWRlZCBuZmQgZm9yIGVudHJ5IGlzbid0IG93bmVkIG9yIGxpbmtlZCB0byB0aGUgc3Rha2VyCglhc3NlcnQKCgkvLyBjb250cmFjdHMvdmFsaWRhdG9yUmVnaXN0cnkuYWxnby50czoxMjkzCgkvLyByZXF1aXJlZFBhcmVudEFwcElEID0gZXh0cmFjdFVpbnQ2NChnYXRlUmVxLCAwKQoJZnJhbWVfZGlnIDIgLy8gZ2F0ZVJlcTogYnl0ZVszMl0KCWludCAwCglleHRyYWN0X3VpbnQ2NAoJZnJhbWVfYnVyeSA3IC8vIHJlcXVpcmVkUGFyZW50QXBwSUQ6IHVpbnQ2NAoKCS8vIGNvbnRyYWN0cy92YWxpZGF0b3JSZWdpc3RyeS5hbGdvLnRzOjEyOTUKCS8vIGFzc2VydCgKCS8vICAgICAgICAgICAgICAgICAoQXBwSUQuZnJvbVVpbnQ2NCh1c2VyT2ZmZXJlZE5GREFwcElEKS5nbG9iYWxTdGF0ZSgnaS5wYXJlbnRBcHBJRCcpIGFzIHVpbnQ2NCkgPT09IHJlcXVpcmVkUGFyZW50QXBwSUQsCgkvLyAgICAgICAgICAgICAgICAgJ3NwZWNpZmllZCBuZmQgbXVzdCBiZSBhIHNlZ21lbnQgb2YgdGhlIG5mZCB0aGUgdmFsaWRhdG9yIHNwZWNpZmllZCBhcyBhIHJlcXVpcmVtZW50JwoJLy8gICAgICAgICAgICAgKQoJZnJhbWVfZGlnIDYgLy8gdXNlck9mZmVyZWRORkRBcHBJRDogdWludDY0CglieXRlIDB4NjkyZTcwNjE3MjY1NmU3NDQxNzA3MDQ5NDQgLy8gImkucGFyZW50QXBwSUQiCglhcHBfZ2xvYmFsX2dldF9leAoJYXNzZXJ0CglmcmFtZV9kaWcgNyAvLyByZXF1aXJlZFBhcmVudEFwcElEOiB1aW50NjQKCT09CgoJLy8gc3BlY2lmaWVkIG5mZCBtdXN0IGJlIGEgc2VnbWVudCBvZiB0aGUgbmZkIHRoZSB2YWxpZGF0b3Igc3BlY2lmaWVkIGFzIGEgcmVxdWlyZW1lbnQKCWFzc2VydAoKKmlmNDdfZW5kOgoJcmV0c3ViCgovLyBpc05GREFwcElEVmFsaWQobmZkQXBwSUQ6IHVpbnQ2NCk6IGJvb2xlYW4KLy8KLy8gQ2hlY2tzIGlmIHRoZSBnaXZlbiBORkQgQXBwIGlkIGlzIHZhbGlkLiAgVXNpbmcgb25seSB0aGUgQXBwIGlkIHRoZXJlJ3Mgbm8gdmFsaWRhdGlvbiBhZ2FpbnN0IHRoZSBuYW1lIChpZTogdGhhdCBuZmQgWCBpcyBuYW1lIFkpCi8vIFNvIGl0J3MgYXNzdW1lZCBmb3IgdGhlIGNhbGxlciwgdGhlIGFwcCBpZCBhbG9uZSBpcyBmaW5lLiAgVGhlIG5hbWUgaXMgZmV0Y2hlZCBmcm9tIHRoZSBzcGVjaWZpZWQgYXBwIGlkIGFuZCB0aGUgdHdvCi8vIHRvZ2V0aGVyIGFyZSB1c2VkIGZvciB2YWxpZGl0eSBjaGVjayBjYWxsIHRvIHRoZSBuZmQgcmVnaXN0cnkuCi8vCi8vIEBwYXJhbSB7dWludDY0fSBuZmRBcHBJRCAtIFRoZSBORkQgQXBwIGlkIHRvIHZlcmlmeS4KLy8KLy8gQHJldHVybnMge2Jvb2xlYW59IC0gUmV0dXJucyB0cnVlIGlmIHRoZSBORkQgQXBwIGlkIGlzIHZhbGlkLCBvdGhlcndpc2UgZmFsc2UuCmlzTkZEQXBwSURWYWxpZDoKCXByb3RvIDEgMQoKCS8vIFB1c2ggZW1wdHkgYnl0ZXMgYWZ0ZXIgdGhlIGZyYW1lIHBvaW50ZXIgdG8gcmVzZXJ2ZSBzcGFjZSBmb3IgbG9jYWwgdmFyaWFibGVzCglieXRlIDB4CgoJLy8gY29udHJhY3RzL3ZhbGlkYXRvclJlZ2lzdHJ5LmFsZ28udHM6MTMxMwoJLy8gdXNlck9mZmVyZWRORkROYW1lID0gQXBwSUQuZnJvbVVpbnQ2NChuZmRBcHBJRCkuZ2xvYmFsU3RhdGUoJ2kubmFtZScpIGFzIHN0cmluZwoJZnJhbWVfZGlnIC0xIC8vIG5mZEFwcElEOiB1aW50NjQKCWJ5dGUgMHg2OTJlNmU2MTZkNjUgLy8gImkubmFtZSIKCWFwcF9nbG9iYWxfZ2V0X2V4Cglhc3NlcnQKCWZyYW1lX2J1cnkgMCAvLyB1c2VyT2ZmZXJlZE5GRE5hbWU6IHN0cmluZwoKCS8vIGNvbnRyYWN0cy92YWxpZGF0b3JSZWdpc3RyeS5hbGdvLnRzOjEzMTUKCS8vIHNlbmRBcHBDYWxsKHsKCS8vICAgICAgICAgICAgIGFwcGxpY2F0aW9uSUQ6IEFwcElELmZyb21VaW50NjQodGhpcy5uZmRSZWdpc3RyeUFwcElkKSwKCS8vICAgICAgICAgICAgIGFwcGxpY2F0aW9uQXJnczogWydpc192YWxpZF9uZmRfYXBwaWQnLCB1c2VyT2ZmZXJlZE5GRE5hbWUsIGl0b2IobmZkQXBwSUQpXSwKCS8vICAgICAgICAgICAgIGFwcGxpY2F0aW9uczogW0FwcElELmZyb21VaW50NjQobmZkQXBwSUQpXSwKCS8vICAgICAgICAgfSkKCWl0eG5fYmVnaW4KCWludCBhcHBsCglpdHhuX2ZpZWxkIFR5cGVFbnVtCgoJLy8gY29udHJhY3RzL3ZhbGlkYXRvclJlZ2lzdHJ5LmFsZ28udHM6MTMxNgoJLy8gYXBwbGljYXRpb25JRDogQXBwSUQuZnJvbVVpbnQ2NCh0aGlzLm5mZFJlZ2lzdHJ5QXBwSWQpCglwdXNoaW50IFRNUExfbmZkUmVnaXN0cnlBcHBJZAoJaXR4bl9maWVsZCBBcHBsaWNhdGlvbklECgoJLy8gY29udHJhY3RzL3ZhbGlkYXRvclJlZ2lzdHJ5LmFsZ28udHM6MTMxNwoJLy8gYXBwbGljYXRpb25BcmdzOiBbJ2lzX3ZhbGlkX25mZF9hcHBpZCcsIHVzZXJPZmZlcmVkTkZETmFtZSwgaXRvYihuZmRBcHBJRCldCglieXRlIDB4Njk3MzVmNzY2MTZjNjk2NDVmNmU2NjY0NWY2MTcwNzA2OTY0IC8vICJpc192YWxpZF9uZmRfYXBwaWQiCglpdHhuX2ZpZWxkIEFwcGxpY2F0aW9uQXJncwoJZnJhbWVfZGlnIDAgLy8gdXNlck9mZmVyZWRORkROYW1lOiBzdHJpbmcKCWl0eG5fZmllbGQgQXBwbGljYXRpb25BcmdzCglmcmFtZV9kaWcgLTEgLy8gbmZkQXBwSUQ6IHVpbnQ2NAoJaXRvYgoJaXR4bl9maWVsZCBBcHBsaWNhdGlvbkFyZ3MKCgkvLyBjb250cmFjdHMvdmFsaWRhdG9yUmVnaXN0cnkuYWxnby50czoxMzE4CgkvLyBhcHBsaWNhdGlvbnM6IFtBcHBJRC5mcm9tVWludDY0KG5mZEFwcElEKV0KCWZyYW1lX2RpZyAtMSAvLyBuZmRBcHBJRDogdWludDY0CglpdHhuX2ZpZWxkIEFwcGxpY2F0aW9ucwoKCS8vIEZlZSBmaWVsZCBub3Qgc2V0LCBkZWZhdWx0aW5nIHRvIDAKCWludCAwCglpdHhuX2ZpZWxkIEZlZQoKCS8vIFN1Ym1pdCBpbm5lciB0cmFuc2FjdGlvbgoJaXR4bl9zdWJtaXQKCgkvLyBjb250cmFjdHMvdmFsaWRhdG9yUmVnaXN0cnkuYWxnby50czoxMzIwCgkvLyByZXR1cm4gYnRvaSh0aGlzLml0eG4ubGFzdExvZykgPT09IDE7CglpdHhuIExhc3RMb2cKCWJ0b2kKCWludCAxCgk9PQoKCS8vIHNldCB0aGUgc3Vicm91dGluZSByZXR1cm4gdmFsdWUKCWZyYW1lX2J1cnkgMAoJcmV0c3ViCgovLyBpc0FkZHJlc3NJbk5GRENBQWxnb0xpc3QobmZkQXBwSUQ6IHVpbnQ2NCwgYWRkclRvRmluZDogQWRkcmVzcyk6IGJvb2xlYW4KLy8KLy8gQ2hlY2tzIGlmIHRoZSBzcGVjaWZpZWQgYWRkcmVzcyBpcyBwcmVzZW50IGluIGFuIE5GRHMgbGlzdCBvZiB2ZXJpZmllZCBhZGRyZXNzZXMuCi8vIFRoZSBORkQgaXMgYXNzdW1lZCB0byBoYXZlIGFscmVhZHkgYmVlbiB2YWxpZGF0ZWQgYXMgb2ZmaWNpYWwuCi8vCi8vIEBwYXJhbSB7dWludDY0fSBuZmRBcHBJRCAtIFRoZSBORkQgYXBwbGljYXRpb24gaWQuCi8vIEBwYXJhbSB7QWRkcmVzc30gYWRkclRvRmluZCAtIFRoZSBhZGRyZXNzIHRvIGZpbmQgaW4gdGhlIHYuY2FBbGdvLjAuYXMgcHJvcGVydHkKLy8gQHJldHVybiB7Ym9vbGVhbn0gLSBgdHJ1ZWAgaWYgdGhlIGFkZHJlc3MgaXMgcHJlc2VudCwgYGZhbHNlYCBvdGhlcndpc2UuCmlzQWRkcmVzc0luTkZEQ0FBbGdvTGlzdDoKCXByb3RvIDIgMQoKCS8vIFB1c2ggZW1wdHkgYnl0ZXMgYWZ0ZXIgdGhlIGZyYW1lIHBvaW50ZXIgdG8gcmVzZXJ2ZSBzcGFjZSBmb3IgbG9jYWwgdmFyaWFibGVzCglieXRlIDB4CglkdXBuIDIKCgkvLyBjb250cmFjdHMvdmFsaWRhdG9yUmVnaXN0cnkuYWxnby50czoxMzMyCgkvLyBzZW5kQXBwQ2FsbCh7CgkvLyAgICAgICAgICAgICBhcHBsaWNhdGlvbklEOiBBcHBJRC5mcm9tVWludDY0KG5mZEFwcElEKSwKCS8vICAgICAgICAgICAgIGFwcGxpY2F0aW9uQXJnczogWydyZWFkX3Byb3BlcnR5JywgJ3YuY2FBbGdvLjAuYXMnXSwKCS8vICAgICAgICAgfSkKCWl0eG5fYmVnaW4KCWludCBhcHBsCglpdHhuX2ZpZWxkIFR5cGVFbnVtCgoJLy8gY29udHJhY3RzL3ZhbGlkYXRvclJlZ2lzdHJ5LmFsZ28udHM6MTMzMwoJLy8gYXBwbGljYXRpb25JRDogQXBwSUQuZnJvbVVpbnQ2NChuZmRBcHBJRCkKCWZyYW1lX2RpZyAtMSAvLyBuZmRBcHBJRDogdWludDY0CglpdHhuX2ZpZWxkIEFwcGxpY2F0aW9uSUQKCgkvLyBjb250cmFjdHMvdmFsaWRhdG9yUmVnaXN0cnkuYWxnby50czoxMzM0CgkvLyBhcHBsaWNhdGlvbkFyZ3M6IFsncmVhZF9wcm9wZXJ0eScsICd2LmNhQWxnby4wLmFzJ10KCWJ5dGUgMHg3MjY1NjE2NDVmNzA3MjZmNzA2NTcyNzQ3OSAvLyAicmVhZF9wcm9wZXJ0eSIKCWl0eG5fZmllbGQgQXBwbGljYXRpb25BcmdzCglieXRlIDB4NzYyZTYzNjE0MTZjNjc2ZjJlMzAyZTYxNzMgLy8gInYuY2FBbGdvLjAuYXMiCglpdHhuX2ZpZWxkIEFwcGxpY2F0aW9uQXJncwoKCS8vIEZlZSBmaWVsZCBub3Qgc2V0LCBkZWZhdWx0aW5nIHRvIDAKCWludCAwCglpdHhuX2ZpZWxkIEZlZQoKCS8vIFN1Ym1pdCBpbm5lciB0cmFuc2FjdGlvbgoJaXR4bl9zdWJtaXQKCgkvLyBjb250cmFjdHMvdmFsaWRhdG9yUmVnaXN0cnkuYWxnby50czoxMzM2CgkvLyBjYUFsZ29EYXRhID0gdGhpcy5pdHhuLmxhc3RMb2cKCWl0eG4gTGFzdExvZwoJZnJhbWVfYnVyeSAwIC8vIGNhQWxnb0RhdGE6IGJ5dGVbXQoKCS8vIGNvbnRyYWN0cy92YWxpZGF0b3JSZWdpc3RyeS5hbGdvLnRzOjEzMzcKCS8vIGZvciAobGV0IGkgPSAwOyBpIDwgY2FBbGdvRGF0YS5sZW5ndGg7IGkgKz0gMzIpCglpbnQgMAoJZnJhbWVfYnVyeSAxIC8vIGk6IHVpbnQ2NAoKKmZvcl8xMDoKCS8vIGNvbnRyYWN0cy92YWxpZGF0b3JSZWdpc3RyeS5hbGdvLnRzOjEzMzcKCS8vIGkgPCBjYUFsZ29EYXRhLmxlbmd0aAoJZnJhbWVfZGlnIDEgLy8gaTogdWludDY0CglmcmFtZV9kaWcgMCAvLyBjYUFsZ29EYXRhOiBieXRlW10KCWxlbgoJPAoJYnogKmZvcl8xMF9lbmQKCgkvLyBjb250cmFjdHMvdmFsaWRhdG9yUmVnaXN0cnkuYWxnby50czoxMzM4CgkvLyBhZGRyID0gZXh0cmFjdDMoY2FBbGdvRGF0YSwgaSwgMzIpCglmcmFtZV9kaWcgMCAvLyBjYUFsZ29EYXRhOiBieXRlW10KCWZyYW1lX2RpZyAxIC8vIGk6IHVpbnQ2NAoJaW50IDMyCglleHRyYWN0MwoJZnJhbWVfYnVyeSAyIC8vIGFkZHI6IGJ5dGVbXQoKCS8vICppZjQ4X2NvbmRpdGlvbgoJLy8gY29udHJhY3RzL3ZhbGlkYXRvclJlZ2lzdHJ5LmFsZ28udHM6MTMzOQoJLy8gYWRkciAhPT0gcmF3Qnl0ZXMoZ2xvYmFscy56ZXJvQWRkcmVzcykgJiYgYWRkciA9PT0gcmF3Qnl0ZXMoYWRkclRvRmluZCkKCWZyYW1lX2RpZyAyIC8vIGFkZHI6IGJ5dGVbXQoJZ2xvYmFsIFplcm9BZGRyZXNzCgkhPQoJZHVwCglieiAqc2tpcF9hbmQ5CglmcmFtZV9kaWcgMiAvLyBhZGRyOiBieXRlW10KCWZyYW1lX2RpZyAtMiAvLyBhZGRyVG9GaW5kOiBBZGRyZXNzCgk9PQoJJiYKCipza2lwX2FuZDk6CglieiAqaWY0OF9lbmQKCgkvLyAqaWY0OF9jb25zZXF1ZW50CgkvLyBjb250cmFjdHMvdmFsaWRhdG9yUmVnaXN0cnkuYWxnby50czoxMzQwCgkvLyByZXR1cm4gdHJ1ZTsKCWludCAxCgoJLy8gc2V0IHRoZSBzdWJyb3V0aW5lIHJldHVybiB2YWx1ZQoJZnJhbWVfYnVyeSAwCgoJLy8gcG9wIGFsbCBsb2NhbCB2YXJpYWJsZXMgZnJvbSB0aGUgc3RhY2sKCXBvcG4gMgoJcmV0c3ViCgoqaWY0OF9lbmQ6CgoqZm9yXzEwX2NvbnRpbnVlOgoJLy8gY29udHJhY3RzL3ZhbGlkYXRvclJlZ2lzdHJ5LmFsZ28udHM6MTMzNwoJLy8gaSArPSAzMgoJZnJhbWVfZGlnIDEgLy8gaTogdWludDY0CglpbnQgMzIKCSsKCWZyYW1lX2J1cnkgMSAvLyBpOiB1aW50NjQKCWIgKmZvcl8xMAoKKmZvcl8xMF9lbmQ6CgkvLyBjb250cmFjdHMvdmFsaWRhdG9yUmVnaXN0cnkuYWxnby50czoxMzQzCgkvLyByZXR1cm4gZmFsc2U7CglpbnQgMAoKCS8vIHNldCB0aGUgc3Vicm91dGluZSByZXR1cm4gdmFsdWUKCWZyYW1lX2J1cnkgMAoKCS8vIHBvcCBhbGwgbG9jYWwgdmFyaWFibGVzIGZyb20gdGhlIHN0YWNrCglwb3BuIDIKCXJldHN1YgoKLy8gbWF4QWxnb0FsbG93ZWRQZXJQb29sKCk6IHVpbnQ2NAovLwovLyBSZXR1cm5zIHRoZSBNQVhJTVVNIGFsbG93ZWQgc3Rha2UgcGVyIHBvb2wgYW5kIHN0aWxsIHJlY2VpdmUgaW5jZW50aXZlcyAtIHdlJ2xsIHRyZWF0IHRoaXMgYXMgdGhlICdtYXggcGVyIHBvb2wnCm1heEFsZ29BbGxvd2VkUGVyUG9vbDoKCXByb3RvIDAgMQoKCS8vIGNvbnRyYWN0cy92YWxpZGF0b3JSZWdpc3RyeS5hbGdvLnRzOjEzNTEKCS8vIHJldHVybiA3MF8wMDBfMDAwXzAwMF8wMDA7CglpbnQgNzBfMDAwXzAwMF8wMDBfMDAwCglyZXRzdWIKCi8vIGFsZ29TYXR1cmF0aW9uTGV2ZWwoKTogdWludDY0Ci8vCi8vIFJldHVybnMgdGhlIG1heGltdW0gYWxsb3dlZCBzdGFrZSBwZXIgdmFsaWRhdG9yIGJhc2VkIG9uIGEgcGVyY2VudGFnZSBvZiBhbGwgY3VycmVudCBvbmxpbmUgc3Rha2UgYmVmb3JlCi8vIHRoZSB2YWxpZGF0b3IgaXMgY29uc2lkZXJlZCBzYXR1cmF0ZWQgLSB3aGVyZSByZXdhcmRzIGFyZSBkaW1pbmlzaGVkLgovLyBOT1RFOiB0aGlzIGZ1bmN0aW9uIGlzIGRlZmluZWQgdHdpY2UgLSBoZXJlIGFuZCBpbiBzdGFraW5nIHBvb2wgY29udHJhY3QuICBCb3RoIG11c3QgYmUgaWRlbnRpY2FsLgphbGdvU2F0dXJhdGlvbkxldmVsOgoJcHJvdG8gMCAxCgoJLy8gUHVzaCBlbXB0eSBieXRlcyBhZnRlciB0aGUgZnJhbWUgcG9pbnRlciB0byByZXNlcnZlIHNwYWNlIGZvciBsb2NhbCB2YXJpYWJsZXMKCWJ5dGUgMHgKCgkvLyBjb250cmFjdHMvdmFsaWRhdG9yUmVnaXN0cnkuYWxnby50czoxMzYwCgkvLyBvbmxpbmUgPSB0aGlzLmdldEN1cnJlbnRPbmxpbmVTdGFrZSgpCgljYWxsc3ViIGdldEN1cnJlbnRPbmxpbmVTdGFrZQoJZnJhbWVfYnVyeSAwIC8vIG9ubGluZTogdWludDY0CgoJLy8gY29udHJhY3RzL3ZhbGlkYXRvclJlZ2lzdHJ5LmFsZ28udHM6MTM2MgoJLy8gcmV0dXJuIHdpZGVSYXRpbyhbb25saW5lLCBNQVhfVkFMSURBVE9SX1NPRlRfUENUX09GX09OTElORV8xREVDSU1BTF0sIFsxMDAwXSk7CglmcmFtZV9kaWcgMCAvLyBvbmxpbmU6IHVpbnQ2NAoJaW50IDEwMAoJbXVsdwoJaW50IDAKCWludCAxMDAwCglkaXZtb2R3Cglwb3AKCXBvcAoJc3dhcAoJIQoJYXNzZXJ0CgoJLy8gc2V0IHRoZSBzdWJyb3V0aW5lIHJldHVybiB2YWx1ZQoJZnJhbWVfYnVyeSAwCglyZXRzdWIKCi8vIG1heEFsbG93ZWRTdGFrZSgpOiB1aW50NjQKLy8KLy8gUmV0dXJucyB0aGUgTUFYSU1VTSBhbGxvd2VkIHN0YWtlIHBlciB2YWxpZGF0b3IgYmFzZWQgb24gYSBwZXJjZW50YWdlIG9mIGFsbCBjdXJyZW50IG9ubGluZSBzdGFrZS4KLy8gQWRkaW5nIHN0YWtlIGlzIGNvbXBsZXRlbHkgYmxvY2tlZCBhdCB0aGlzIGFtb3VudC4KbWF4QWxsb3dlZFN0YWtlOgoJcHJvdG8gMCAxCgoJLy8gUHVzaCBlbXB0eSBieXRlcyBhZnRlciB0aGUgZnJhbWUgcG9pbnRlciB0byByZXNlcnZlIHNwYWNlIGZvciBsb2NhbCB2YXJpYWJsZXMKCWJ5dGUgMHgKCgkvLyBjb250cmFjdHMvdmFsaWRhdG9yUmVnaXN0cnkuYWxnby50czoxMzcwCgkvLyBvbmxpbmUgPSB0aGlzLmdldEN1cnJlbnRPbmxpbmVTdGFrZSgpCgljYWxsc3ViIGdldEN1cnJlbnRPbmxpbmVTdGFrZQoJZnJhbWVfYnVyeSAwIC8vIG9ubGluZTogdWludDY0CgoJLy8gY29udHJhY3RzL3ZhbGlkYXRvclJlZ2lzdHJ5LmFsZ28udHM6MTM3MgoJLy8gcmV0dXJuIHdpZGVSYXRpbyhbb25saW5lLCBNQVhfVkFMSURBVE9SX0hBUkRfUENUX09GX09OTElORV8xREVDSU1BTF0sIFsxMDAwXSk7CglmcmFtZV9kaWcgMCAvLyBvbmxpbmU6IHVpbnQ2NAoJaW50IDE1MAoJbXVsdwoJaW50IDAKCWludCAxMDAwCglkaXZtb2R3Cglwb3AKCXBvcAoJc3dhcAoJIQoJYXNzZXJ0CgoJLy8gc2V0IHRoZSBzdWJyb3V0aW5lIHJldHVybiB2YWx1ZQoJZnJhbWVfYnVyeSAwCglyZXRzdWIKCi8vIGdldEN1cnJlbnRPbmxpbmVTdGFrZSgpOiB1aW50NjQKZ2V0Q3VycmVudE9ubGluZVN0YWtlOgoJcHJvdG8gMCAxCgoJLy8gY29udHJhY3RzL3ZhbGlkYXRvclJlZ2lzdHJ5LmFsZ28udHM6MTM3NwoJLy8gcmV0dXJuIDJfMDAwXzAwMF8wMDBfMDAwXzAwMDsKCWludCAyXzAwMF8wMDBfMDAwXzAwMF8wMDAKCXJldHN1YgoKLy8gbWluQmFsYW5jZUZvckFjY291bnQoY29udHJhY3RzOiB1aW50NjQsIGV4dHJhUGFnZXM6IHVpbnQ2NCwgYXNzZXRzOiB1aW50NjQsIGxvY2FsSW50czogdWludDY0LCBsb2NhbEJ5dGVzOiB1aW50NjQsIGdsb2JhbEludHM6IHVpbnQ2NCwgZ2xvYmFsQnl0ZXM6IHVpbnQ2NCk6IHVpbnQ2NAptaW5CYWxhbmNlRm9yQWNjb3VudDoKCXByb3RvIDcgMQoKCS8vIFB1c2ggZW1wdHkgYnl0ZXMgYWZ0ZXIgdGhlIGZyYW1lIHBvaW50ZXIgdG8gcmVzZXJ2ZSBzcGFjZSBmb3IgbG9jYWwgdmFyaWFibGVzCglieXRlIDB4CgoJLy8gY29udHJhY3RzL3ZhbGlkYXRvclJlZ2lzdHJ5LmFsZ28udHM6MTM4OQoJLy8gbWluQmFsID0gQUxHT1JBTkRfQUNDT1VOVF9NSU5fQkFMQU5DRQoJaW50IDEwMDAwMAoJZnJhbWVfYnVyeSAwIC8vIG1pbkJhbDogdWludDY0CgoJLy8gY29udHJhY3RzL3ZhbGlkYXRvclJlZ2lzdHJ5LmFsZ28udHM6MTM5MAoJLy8gbWluQmFsICs9IGNvbnRyYWN0cyAqIEFQUExJQ0FUSU9OX0JBU0VfRkVFCglmcmFtZV9kaWcgMCAvLyBtaW5CYWw6IHVpbnQ2NAoJZnJhbWVfZGlnIC0xIC8vIGNvbnRyYWN0czogdWludDY0CglpbnQgMTAwMDAwCgkqCgkrCglmcmFtZV9idXJ5IDAgLy8gbWluQmFsOiB1aW50NjQKCgkvLyBjb250cmFjdHMvdmFsaWRhdG9yUmVnaXN0cnkuYWxnby50czoxMzkxCgkvLyBtaW5CYWwgKz0gZXh0cmFQYWdlcyAqIEFQUExJQ0FUSU9OX0JBU0VfRkVFCglmcmFtZV9kaWcgMCAvLyBtaW5CYWw6IHVpbnQ2NAoJZnJhbWVfZGlnIC0yIC8vIGV4dHJhUGFnZXM6IHVpbnQ2NAoJaW50IDEwMDAwMAoJKgoJKwoJZnJhbWVfYnVyeSAwIC8vIG1pbkJhbDogdWludDY0CgoJLy8gY29udHJhY3RzL3ZhbGlkYXRvclJlZ2lzdHJ5LmFsZ28udHM6MTM5MgoJLy8gbWluQmFsICs9IGFzc2V0cyAqIEFTU0VUX0hPTERJTkdfRkVFCglmcmFtZV9kaWcgMCAvLyBtaW5CYWw6IHVpbnQ2NAoJZnJhbWVfZGlnIC0zIC8vIGFzc2V0czogdWludDY0CglpbnQgMTAwMDAwCgkqCgkrCglmcmFtZV9idXJ5IDAgLy8gbWluQmFsOiB1aW50NjQKCgkvLyBjb250cmFjdHMvdmFsaWRhdG9yUmVnaXN0cnkuYWxnby50czoxMzkzCgkvLyBtaW5CYWwgKz0gbG9jYWxJbnRzICogU1NDX1ZBTFVFX1VJTlQKCWZyYW1lX2RpZyAwIC8vIG1pbkJhbDogdWludDY0CglmcmFtZV9kaWcgLTQgLy8gbG9jYWxJbnRzOiB1aW50NjQKCWludCAyODUwMAoJKgoJKwoJZnJhbWVfYnVyeSAwIC8vIG1pbkJhbDogdWludDY0CgoJLy8gY29udHJhY3RzL3ZhbGlkYXRvclJlZ2lzdHJ5LmFsZ28udHM6MTM5NAoJLy8gbWluQmFsICs9IGdsb2JhbEludHMgKiBTU0NfVkFMVUVfVUlOVAoJZnJhbWVfZGlnIDAgLy8gbWluQmFsOiB1aW50NjQKCWZyYW1lX2RpZyAtNiAvLyBnbG9iYWxJbnRzOiB1aW50NjQKCWludCAyODUwMAoJKgoJKwoJZnJhbWVfYnVyeSAwIC8vIG1pbkJhbDogdWludDY0CgoJLy8gY29udHJhY3RzL3ZhbGlkYXRvclJlZ2lzdHJ5LmFsZ28udHM6MTM5NQoJLy8gbWluQmFsICs9IGxvY2FsQnl0ZXMgKiBTU0NfVkFMVUVfQllURVMKCWZyYW1lX2RpZyAwIC8vIG1pbkJhbDogdWludDY0CglmcmFtZV9kaWcgLTUgLy8gbG9jYWxCeXRlczogdWludDY0CglpbnQgNTAwMDAKCSoKCSsKCWZyYW1lX2J1cnkgMCAvLyBtaW5CYWw6IHVpbnQ2NAoKCS8vIGNvbnRyYWN0cy92YWxpZGF0b3JSZWdpc3RyeS5hbGdvLnRzOjEzOTYKCS8vIG1pbkJhbCArPSBnbG9iYWxCeXRlcyAqIFNTQ19WQUxVRV9CWVRFUwoJZnJhbWVfZGlnIDAgLy8gbWluQmFsOiB1aW50NjQKCWZyYW1lX2RpZyAtNyAvLyBnbG9iYWxCeXRlczogdWludDY0CglpbnQgNTAwMDAKCSoKCSsKCWZyYW1lX2J1cnkgMCAvLyBtaW5CYWw6IHVpbnQ2NAoKCS8vIGNvbnRyYWN0cy92YWxpZGF0b3JSZWdpc3RyeS5hbGdvLnRzOjEzOTcKCS8vIHJldHVybiBtaW5CYWw7CglmcmFtZV9kaWcgMCAvLyBtaW5CYWw6IHVpbnQ2NAoKCS8vIHNldCB0aGUgc3Vicm91dGluZSByZXR1cm4gdmFsdWUKCWZyYW1lX2J1cnkgMAoJcmV0c3ViCgovLyBjb3N0Rm9yQm94U3RvcmFnZSh0b3RhbE51bUJ5dGVzOiB1aW50NjQpOiB1aW50NjQKY29zdEZvckJveFN0b3JhZ2U6Cglwcm90byAxIDEKCgkvLyBjb250cmFjdHMvdmFsaWRhdG9yUmVnaXN0cnkuYWxnby50czoxNDA0CgkvLyByZXR1cm4gU0NCT1hfUEVSQk9YICsgdG90YWxOdW1CeXRlcyAqIFNDQk9YX1BFUkJZVEU7CglpbnQgMjUwMAoJZnJhbWVfZGlnIC0xIC8vIHRvdGFsTnVtQnl0ZXM6IHVpbnQ2NAoJaW50IDQwMAoJKgoJKwoJcmV0c3ViCgoqY3JlYXRlX05vT3A6CgltZXRob2QgImNyZWF0ZUFwcGxpY2F0aW9uKHVpbnQ2NCl2b2lkIgoJdHhuYSBBcHBsaWNhdGlvbkFyZ3MgMAoJbWF0Y2ggKmFiaV9yb3V0ZV9jcmVhdGVBcHBsaWNhdGlvbgoJZXJyCgoqY2FsbF9Ob09wOgoJbWV0aG9kICJnYXMoKXZvaWQiCgltZXRob2QgImdldE1ickFtb3VudHMoKSh1aW50NjQsdWludDY0LHVpbnQ2NCx1aW50NjQpIgoJbWV0aG9kICJnZXRQcm90b2NvbENvbnN0cmFpbnRzKCkodWludDY0LHVpbnQ2NCx1aW50NjQsdWludDY0LHVpbnQ2NCx1aW50NjQsdWludDY0LHVpbnQ2NCx1aW50NjQsdWludDY0LHVpbnQ2NCkiCgltZXRob2QgImdldE51bVZhbGlkYXRvcnMoKXVpbnQ2NCIKCW1ldGhvZCAiZ2V0VmFsaWRhdG9yQ29uZmlnKHVpbnQ2NCkodWludDY0LGFkZHJlc3MsYWRkcmVzcyx1aW50NjQsdWludDgsYnl0ZVszMl0sdWludDY0LHVpbnQ2NCx1aW50NjQsdWludDE2LHVpbnQzMixhZGRyZXNzLHVpbnQ2NCx1aW50NjQsdWludDgsdWludDY0LHVpbnQ2NCkiCgltZXRob2QgImdldFZhbGlkYXRvclN0YXRlKHVpbnQ2NCkodWludDE2LHVpbnQ2NCx1aW50NjQsdWludDY0KSIKCW1ldGhvZCAiZ2V0VmFsaWRhdG9yT3duZXJBbmRNYW5hZ2VyKHVpbnQ2NCkoYWRkcmVzcyxhZGRyZXNzKSIKCW1ldGhvZCAiZ2V0UG9vbHModWludDY0KSh1aW50NjQsdWludDE2LHVpbnQ2NClbXSIKCW1ldGhvZCAiZ2V0UG9vbEFwcElkKHVpbnQ2NCx1aW50NjQpdWludDY0IgoJbWV0aG9kICJnZXRQb29sSW5mbygodWludDY0LHVpbnQ2NCx1aW50NjQpKSh1aW50NjQsdWludDE2LHVpbnQ2NCkiCgltZXRob2QgImdldEN1ck1heFN0YWtlUGVyUG9vbCh1aW50NjQpdWludDY0IgoJbWV0aG9kICJkb2VzU3Rha2VyTmVlZFRvUGF5TUJSKGFkZHJlc3MpYm9vbCIKCW1ldGhvZCAiZ2V0U3Rha2VkUG9vbHNGb3JBY2NvdW50KGFkZHJlc3MpKHVpbnQ2NCx1aW50NjQsdWludDY0KVtdIgoJbWV0aG9kICJnZXRUb2tlblBheW91dFJhdGlvKHVpbnQ2NCkodWludDY0WzI0XSx1aW50NjQpIgoJbWV0aG9kICJnZXROb2RlUG9vbEFzc2lnbm1lbnRzKHVpbnQ2NCkoKHVpbnQ2NFszXSlbOF0pIgoJbWV0aG9kICJnZXRORkRSZWdpc3RyeUlEKCl1aW50NjQiCgltZXRob2QgImFkZFZhbGlkYXRvcihwYXksc3RyaW5nLCh1aW50NjQsYWRkcmVzcyxhZGRyZXNzLHVpbnQ2NCx1aW50OCxieXRlWzMyXSx1aW50NjQsdWludDY0LHVpbnQ2NCx1aW50MTYsdWludDMyLGFkZHJlc3MsdWludDY0LHVpbnQ2NCx1aW50OCx1aW50NjQsdWludDY0KSl1aW50NjQiCgltZXRob2QgImNoYW5nZVZhbGlkYXRvck1hbmFnZXIodWludDY0LGFkZHJlc3Mpdm9pZCIKCW1ldGhvZCAiY2hhbmdlVmFsaWRhdG9yU3Vuc2V0SW5mbyh1aW50NjQsdWludDY0LHVpbnQ2NCl2b2lkIgoJbWV0aG9kICJjaGFuZ2VWYWxpZGF0b3JORkQodWludDY0LHVpbnQ2NCxzdHJpbmcpdm9pZCIKCW1ldGhvZCAiY2hhbmdlVmFsaWRhdG9yQ29tbWlzc2lvbkFkZHJlc3ModWludDY0LGFkZHJlc3Mpdm9pZCIKCW1ldGhvZCAiY2hhbmdlVmFsaWRhdG9yUmV3YXJkSW5mbyh1aW50NjQsdWludDgsYnl0ZVszMl0sdWludDY0LHVpbnQ2NCl2b2lkIgoJbWV0aG9kICJhZGRQb29sKHBheSx1aW50NjQsdWludDY0KSh1aW50NjQsdWludDY0LHVpbnQ2NCkiCgltZXRob2QgImFkZFN0YWtlKHBheSx1aW50NjQsdWludDY0KSh1aW50NjQsdWludDY0LHVpbnQ2NCkiCgltZXRob2QgInNldFRva2VuUGF5b3V0UmF0aW8odWludDY0KSh1aW50NjRbMjRdLHVpbnQ2NCkiCgltZXRob2QgInN0YWtlVXBkYXRlZFZpYVJld2FyZHMoKHVpbnQ2NCx1aW50NjQsdWludDY0KSx1aW50NjQsdWludDY0KXZvaWQiCgltZXRob2QgInN0YWtlUmVtb3ZlZCgodWludDY0LHVpbnQ2NCx1aW50NjQpLGFkZHJlc3MsdWludDY0LHVpbnQ2NCxib29sKXZvaWQiCgltZXRob2QgImZpbmRQb29sRm9yU3Rha2VyKHVpbnQ2NCxhZGRyZXNzLHVpbnQ2NCkoKHVpbnQ2NCx1aW50NjQsdWludDY0KSxib29sLGJvb2wpIgoJbWV0aG9kICJtb3ZlUG9vbFRvTm9kZSh1aW50NjQsdWludDY0LHVpbnQ2NCl2b2lkIgoJdHhuYSBBcHBsaWNhdGlvbkFyZ3MgMAoJbWF0Y2ggKmFiaV9yb3V0ZV9nYXMgKmFiaV9yb3V0ZV9nZXRNYnJBbW91bnRzICphYmlfcm91dGVfZ2V0UHJvdG9jb2xDb25zdHJhaW50cyAqYWJpX3JvdXRlX2dldE51bVZhbGlkYXRvcnMgKmFiaV9yb3V0ZV9nZXRWYWxpZGF0b3JDb25maWcgKmFiaV9yb3V0ZV9nZXRWYWxpZGF0b3JTdGF0ZSAqYWJpX3JvdXRlX2dldFZhbGlkYXRvck93bmVyQW5kTWFuYWdlciAqYWJpX3JvdXRlX2dldFBvb2xzICphYmlfcm91dGVfZ2V0UG9vbEFwcElkICphYmlfcm91dGVfZ2V0UG9vbEluZm8gKmFiaV9yb3V0ZV9nZXRDdXJNYXhTdGFrZVBlclBvb2wgKmFiaV9yb3V0ZV9kb2VzU3Rha2VyTmVlZFRvUGF5TUJSICphYmlfcm91dGVfZ2V0U3Rha2VkUG9vbHNGb3JBY2NvdW50ICphYmlfcm91dGVfZ2V0VG9rZW5QYXlvdXRSYXRpbyAqYWJpX3JvdXRlX2dldE5vZGVQb29sQXNzaWdubWVudHMgKmFiaV9yb3V0ZV9nZXRORkRSZWdpc3RyeUlEICphYmlfcm91dGVfYWRkVmFsaWRhdG9yICphYmlfcm91dGVfY2hhbmdlVmFsaWRhdG9yTWFuYWdlciAqYWJpX3JvdXRlX2NoYW5nZVZhbGlkYXRvclN1bnNldEluZm8gKmFiaV9yb3V0ZV9jaGFuZ2VWYWxpZGF0b3JORkQgKmFiaV9yb3V0ZV9jaGFuZ2VWYWxpZGF0b3JDb21taXNzaW9uQWRkcmVzcyAqYWJpX3JvdXRlX2NoYW5nZVZhbGlkYXRvclJld2FyZEluZm8gKmFiaV9yb3V0ZV9hZGRQb29sICphYmlfcm91dGVfYWRkU3Rha2UgKmFiaV9yb3V0ZV9zZXRUb2tlblBheW91dFJhdGlvICphYmlfcm91dGVfc3Rha2VVcGRhdGVkVmlhUmV3YXJkcyAqYWJpX3JvdXRlX3N0YWtlUmVtb3ZlZCAqYWJpX3JvdXRlX2ZpbmRQb29sRm9yU3Rha2VyICphYmlfcm91dGVfbW92ZVBvb2xUb05vZGUKCWVycg==", + "clear": "I3ByYWdtYSB2ZXJzaW9uIDEw" + }, + "contract": { + "name": "ValidatorRegistry", + "desc": "", + "methods": [ + { + "name": "createApplication", + "args": [ + { + "name": "poolTemplateAppId", + "type": "uint64" + } + ], + "returns": { + "type": "void" + } + }, + { + "name": "gas", + "desc": "gas is a dummy no-op call that can be used to pool-up resource references and opcode cost", + "args": [], + "returns": { + "type": "void" + } + }, + { + "name": "getMbrAmounts", + "desc": "Returns the MBR amounts needed for various actions:[addValidatorMbr: uint64 - mbr needed to add a new validator - paid to validator contractaddPoolMbr: uint64 - mbr needed to add a new pool - paid to validatorpoolInitMbr: uint64 - mbr needed to initStorage() of pool - paid to pool itselfaddStakerMbr: uint64 - mbr staker needs to add to first staking payment (stays w/ validator)]", + "args": [], + "returns": { + "type": "(uint64,uint64,uint64,uint64)" + } + }, + { + "name": "getProtocolConstraints", + "desc": "Returns the protocol constraints so that UIs can limit what users specify for validator configuration parameters.", + "args": [], + "returns": { + "type": "(uint64,uint64,uint64,uint64,uint64,uint64,uint64,uint64,uint64,uint64,uint64)" + } + }, + { + "name": "getNumValidators", + "desc": "Returns the current number of validators", + "args": [], + "returns": { + "type": "uint64" + } + }, + { + "name": "getValidatorConfig", + "args": [ + { + "name": "validatorId", + "type": "uint64" + } + ], + "returns": { + "type": "(uint64,address,address,uint64,uint8,byte[32],uint64,uint64,uint64,uint16,uint32,address,uint64,uint64,uint8,uint64,uint64)" + } + }, + { + "name": "getValidatorState", + "args": [ + { + "name": "validatorId", + "type": "uint64" + } + ], + "returns": { + "type": "(uint16,uint64,uint64,uint64)" + } + }, + { + "name": "getValidatorOwnerAndManager", + "args": [ + { + "name": "validatorId", + "type": "uint64" + } + ], + "returns": { + "type": "(address,address)" + } + }, + { + "name": "getPools", + "desc": "Return list of all pools for this validator.", + "args": [ + { + "name": "validatorId", + "type": "uint64", + "desc": "@return{PoolInfo[]}- array of poolsNot callable from other contracts because>1K return but can be called w/ simulate which bumps log returns" + } + ], + "returns": { + "type": "(uint64,uint16,uint64)[]" + } + }, + { + "name": "getPoolAppId", + "args": [ + { + "name": "validatorId", + "type": "uint64" + }, + { + "name": "poolId", + "type": "uint64" + } + ], + "returns": { + "type": "uint64" + } + }, + { + "name": "getPoolInfo", + "args": [ + { + "name": "poolKey", + "type": "(uint64,uint64,uint64)" + } + ], + "returns": { + "type": "(uint64,uint16,uint64)" + } + }, + { + "name": "getCurMaxStakePerPool", + "desc": "Calculate the maximum stake per pool for a given validator.Normally this would be maxAlgoPerPool, but it should also never go above MaxAllowedStake / numPools soas pools are added the max allowed per pool can reduce.", + "args": [ + { + "name": "validatorId", + "type": "uint64", + "desc": "The id of the validator." + } + ], + "returns": { + "type": "uint64" + } + }, + { + "name": "doesStakerNeedToPayMBR", + "desc": "Helper callers can call w/ simulate to determine if 'AddStaker' MBR should be included w/ staking amount", + "args": [ + { + "name": "staker", + "type": "address" + } + ], + "returns": { + "type": "bool" + } + }, + { + "name": "getStakedPoolsForAccount", + "desc": "Retrieves the staked pools for an account.", + "args": [ + { + "name": "staker", + "type": "address", + "desc": "The account to retrieve staked pools for.@return{ValidatorPoolKey[]}- The array of staked pools for the account." + } + ], + "returns": { + "type": "(uint64,uint64,uint64)[]" + } + }, + { + "name": "getTokenPayoutRatio", + "desc": "Retrieves the token payout ratio for a given validator - returning the pool ratios of whole so that tokenpayouts across pools can be based on a stable snaphost of stake.", + "args": [ + { + "name": "validatorId", + "type": "uint64", + "desc": "The id of the validator.@return{PoolTokenPayoutRatio}- The token payout ratio for the validator." + } + ], + "returns": { + "type": "(uint64[24],uint64)" + } + }, + { + "name": "getNodePoolAssignments", + "args": [ + { + "name": "validatorId", + "type": "uint64" + } + ], + "returns": { + "type": "((uint64[3])[8])" + } + }, + { + "name": "getNFDRegistryID", + "args": [], + "returns": { + "type": "uint64" + } + }, + { + "name": "addValidator", + "desc": "Adds a new validator", + "args": [ + { + "name": "mbrPayment", + "type": "pay", + "desc": "payment from caller which covers mbr increase of new validator storage" + }, + { + "name": "nfdName", + "type": "string", + "desc": "(Optional) Name of nfd (used as double-check against id specified in config)" + }, + { + "name": "config", + "type": "(uint64,address,address,uint64,uint8,byte[32],uint64,uint64,uint64,uint16,uint32,address,uint64,uint64,uint8,uint64,uint64)", + "desc": "ValidatorConfig struct" + } + ], + "returns": { + "type": "uint64", + "desc": "validator id" + } + }, + { + "name": "changeValidatorManager", + "desc": "Changes the Validator manager for a specific Validator id.[ ONLY OWNER CAN CHANGE ]", + "args": [ + { + "name": "validatorId", + "type": "uint64", + "desc": "The id of the validator to change the manager for." + }, + { + "name": "manager", + "type": "address", + "desc": "The new manager address." + } + ], + "returns": { + "type": "void" + } + }, + { + "name": "changeValidatorSunsetInfo", + "desc": "Updates the sunset information for a given validator.[ ONLY OWNER CAN CHANGE ]", + "args": [ + { + "name": "validatorId", + "type": "uint64", + "desc": "The id of the validator to update." + }, + { + "name": "sunsettingOn", + "type": "uint64", + "desc": "The new sunset timestamp." + }, + { + "name": "sunsettingTo", + "type": "uint64", + "desc": "The new sunset to validator id." + } + ], + "returns": { + "type": "void" + } + }, + { + "name": "changeValidatorNFD", + "desc": "Changes the NFD for a validator in the validatorList contract.[ ONLY OWNER OR MANAGER CAN CHANGE ]", + "args": [ + { + "name": "validatorId", + "type": "uint64", + "desc": "The id of the validator to update." + }, + { + "name": "nfdAppID", + "type": "uint64", + "desc": "The application id of the NFD to assign to the validator." + }, + { + "name": "nfdName", + "type": "string", + "desc": "The name of the NFD (which must match)" + } + ], + "returns": { + "type": "void" + } + }, + { + "name": "changeValidatorCommissionAddress", + "desc": "Change the commission address that validator rewards are sent to.[ ONLY OWNER CAN CHANGE ]", + "args": [ + { + "name": "validatorId", + "type": "uint64" + }, + { + "name": "commissionAddress", + "type": "address" + } + ], + "returns": { + "type": "void" + } + }, + { + "name": "changeValidatorRewardInfo", + "desc": "Allow the additional rewards (gating entry, additional token rewards) information be changed at will.[ ONLY OWNER CAN CHANGE ]", + "args": [ + { + "name": "validatorId", + "type": "uint64" + }, + { + "name": "EntryGatingType", + "type": "uint8" + }, + { + "name": "EntryGatingValue", + "type": "byte[32]" + }, + { + "name": "GatingAssetMinBalance", + "type": "uint64" + }, + { + "name": "RewardPerPayout", + "type": "uint64" + } + ], + "returns": { + "type": "void" + } + }, + { + "name": "addPool", + "desc": "Adds a new pool to a validator's pool set, returning the 'key' to reference the pool in the future for staking, etc.The caller must pay the cost of the validators MBR increase as well as the MBR that will be needed for the pool itself.[ ONLY OWNER OR MANAGER CAN call ]", + "args": [ + { + "name": "mbrPayment", + "type": "pay", + "desc": "payment from caller which covers mbr increase of adding a new pool" + }, + { + "name": "validatorId", + "type": "uint64", + "desc": "is id of validator to pool to (must be owner or manager)" + }, + { + "name": "nodeNum", + "type": "uint64", + "desc": "is node number to add to" + } + ], + "returns": { + "type": "(uint64,uint64,uint64)", + "desc": "{ValidatorPoolKey}pool key to created pool" + } + }, + { + "name": "addStake", + "desc": "Adds stake to a validator pool.", + "args": [ + { + "name": "stakedAmountPayment", + "type": "pay", + "desc": "payment coming from staker to place into a pool" + }, + { + "name": "validatorId", + "type": "uint64", + "desc": "The id of the validator." + }, + { + "name": "valueToVerify", + "type": "uint64", + "desc": "only if validator has gating to enter - this is asset id or nfd id that corresponds to gating.Txn sender is factored in as well if that is part of gating.*" + } + ], + "returns": { + "type": "(uint64,uint64,uint64)", + "desc": "{ValidatorPoolKey}- The key of the validator pool." + } + }, + { + "name": "setTokenPayoutRatio", + "desc": "setTokenPayoutRatio is called by Staking Pool # 1 (ONLY) to ask the validator (us) to calculate the ratiosof stake in the pools for subsequent token payouts (ie: 2 pools, '100' algo total staked, 60 in pool 1, and 40in pool 2. This is done so we have a stable snapshot of stake - taken once per epoch - only triggered bypool 1 doing payout. pools other than 1 doing payout call pool 1 to ask it do it first.It would be 60/40% in the poolPctOfWhole values. The token reward payouts then use these values instead oftheir 'current' stake which changes as part of the payouts themselves (and people could be changing stakeduring the epoch updates across pools)Multiple pools will call us via pool 1 (pool2->pool1->valdiator, etc.) so don't assert on pool1 calling multipletimes in same epoch. Just return.", + "args": [ + { + "name": "validatorId", + "type": "uint64", + "desc": "validator id (and thus pool) calling us. Verified so that sender MUST be pool 1 of this validator." + } + ], + "returns": { + "type": "(uint64[24],uint64)", + "desc": "PoolTokenPayoutRatio - the finished ratio data" + } + }, + { + "name": "stakeUpdatedViaRewards", + "desc": "stakeUpdatedViaRewards is called by Staking pools to inform the validator (us) that a particular amount of totalstake has been added to the specified pool. This is used to update the stats we have in our PoolInfo storage.The calling App id is validated against our pool list as well.", + "args": [ + { + "name": "poolKey", + "type": "(uint64,uint64,uint64)", + "desc": "ValidatorPoolKey type" + }, + { + "name": "algoToAdd", + "type": "uint64", + "desc": "amount this validator's total stake increased via rewards" + }, + { + "name": "rewardTokenAmountReserved", + "type": "uint64", + "desc": "amount this validator's total stake increased via rewards (that should beseen as 'accounted for/pending spent')" + } + ], + "returns": { + "type": "void" + } + }, + { + "name": "stakeRemoved", + "desc": "stakeRemoved is called by Staking pools to inform the validator (us) that a particular amount of total stake has been removedfrom the specified pool. This is used to update the stats we have in our PoolInfo storage.If any amount of rewardRemoved is specified, then that amount of reward is sent to the useThe calling App id is validated against our pool list as well.", + "args": [ + { + "name": "poolKey", + "type": "(uint64,uint64,uint64)", + "desc": "calling us from which stake was removed" + }, + { + "name": "staker", + "type": "address" + }, + { + "name": "amountRemoved", + "type": "uint64", + "desc": "algo amount removed" + }, + { + "name": "rewardRemoved", + "type": "uint64", + "desc": "if applicable, amount of token reward removed (by pool 1 caller) or TO remove and pay out (via pool 1 from different pool caller)" + }, + { + "name": "stakerRemoved", + "type": "bool" + } + ], + "returns": { + "type": "void" + } + }, + { + "name": "findPoolForStaker", + "desc": "Finds the pool for a staker based on the provided validator id, staker address, and amount to stake.First checks the stakers 'already staked list' for the validator preferring those (adding if possible) then addsto new pool if necessary.", + "args": [ + { + "name": "validatorId", + "type": "uint64", + "desc": "The id of the validator." + }, + { + "name": "staker", + "type": "address", + "desc": "The address of the staker." + }, + { + "name": "amountToStake", + "type": "uint64", + "desc": "The amount to stake." + } + ], + "returns": { + "type": "((uint64,uint64,uint64),bool,bool)", + "desc": "{ValidatorPoolKey, boolean, boolean}- The pool for the staker, true/false on whether the staker is 'new'to this VALIDATOR, and true/false if staker is new to the protocol." + } + }, + { + "name": "movePoolToNode", + "desc": "Find the specified pool (in any node number) and move it to the specified node.The pool account is forced offline if moved so prior node will still run for 320 rounds butnew key goes online on new node soon after (320 rounds after it goes online)No-op if success, asserts if not found or can't move (no space in target)[ ONLY OWNER OR MANAGER CAN CHANGE ]Only callable by owner or manager", + "args": [ + { + "name": "validatorId", + "type": "uint64" + }, + { + "name": "poolAppId", + "type": "uint64" + }, + { + "name": "nodeNum", + "type": "uint64" + } + ], + "returns": { + "type": "void" + } + } + ] + } +} \ No newline at end of file diff --git a/contracts/contracts/artifacts/ValidatorRegistry.arc4.json b/contracts/contracts/artifacts/ValidatorRegistry.arc4.json new file mode 100644 index 00000000..e4ff9f35 --- /dev/null +++ b/contracts/contracts/artifacts/ValidatorRegistry.arc4.json @@ -0,0 +1,507 @@ +{ + "name": "ValidatorRegistry", + "desc": "", + "methods": [ + { + "name": "createApplication", + "args": [ + { + "name": "poolTemplateAppId", + "type": "uint64" + } + ], + "returns": { + "type": "void" + } + }, + { + "name": "gas", + "desc": "gas is a dummy no-op call that can be used to pool-up resource references and opcode cost", + "args": [], + "returns": { + "type": "void" + } + }, + { + "name": "getMbrAmounts", + "desc": "Returns the MBR amounts needed for various actions:[addValidatorMbr: uint64 - mbr needed to add a new validator - paid to validator contractaddPoolMbr: uint64 - mbr needed to add a new pool - paid to validatorpoolInitMbr: uint64 - mbr needed to initStorage() of pool - paid to pool itselfaddStakerMbr: uint64 - mbr staker needs to add to first staking payment (stays w/ validator)]", + "args": [], + "returns": { + "type": "(uint64,uint64,uint64,uint64)" + } + }, + { + "name": "getProtocolConstraints", + "desc": "Returns the protocol constraints so that UIs can limit what users specify for validator configuration parameters.", + "args": [], + "returns": { + "type": "(uint64,uint64,uint64,uint64,uint64,uint64,uint64,uint64,uint64,uint64,uint64)" + } + }, + { + "name": "getNumValidators", + "desc": "Returns the current number of validators", + "args": [], + "returns": { + "type": "uint64" + } + }, + { + "name": "getValidatorConfig", + "args": [ + { + "name": "validatorId", + "type": "uint64" + } + ], + "returns": { + "type": "(uint64,address,address,uint64,uint8,byte[32],uint64,uint64,uint64,uint16,uint32,address,uint64,uint64,uint8,uint64,uint64)" + } + }, + { + "name": "getValidatorState", + "args": [ + { + "name": "validatorId", + "type": "uint64" + } + ], + "returns": { + "type": "(uint16,uint64,uint64,uint64)" + } + }, + { + "name": "getValidatorOwnerAndManager", + "args": [ + { + "name": "validatorId", + "type": "uint64" + } + ], + "returns": { + "type": "(address,address)" + } + }, + { + "name": "getPools", + "desc": "Return list of all pools for this validator.", + "args": [ + { + "name": "validatorId", + "type": "uint64", + "desc": "@return{PoolInfo[]}- array of poolsNot callable from other contracts because>1K return but can be called w/ simulate which bumps log returns" + } + ], + "returns": { + "type": "(uint64,uint16,uint64)[]" + } + }, + { + "name": "getPoolAppId", + "args": [ + { + "name": "validatorId", + "type": "uint64" + }, + { + "name": "poolId", + "type": "uint64" + } + ], + "returns": { + "type": "uint64" + } + }, + { + "name": "getPoolInfo", + "args": [ + { + "name": "poolKey", + "type": "(uint64,uint64,uint64)" + } + ], + "returns": { + "type": "(uint64,uint16,uint64)" + } + }, + { + "name": "getCurMaxStakePerPool", + "desc": "Calculate the maximum stake per pool for a given validator.Normally this would be maxAlgoPerPool, but it should also never go above MaxAllowedStake / numPools soas pools are added the max allowed per pool can reduce.", + "args": [ + { + "name": "validatorId", + "type": "uint64", + "desc": "The id of the validator." + } + ], + "returns": { + "type": "uint64" + } + }, + { + "name": "doesStakerNeedToPayMBR", + "desc": "Helper callers can call w/ simulate to determine if 'AddStaker' MBR should be included w/ staking amount", + "args": [ + { + "name": "staker", + "type": "address" + } + ], + "returns": { + "type": "bool" + } + }, + { + "name": "getStakedPoolsForAccount", + "desc": "Retrieves the staked pools for an account.", + "args": [ + { + "name": "staker", + "type": "address", + "desc": "The account to retrieve staked pools for.@return{ValidatorPoolKey[]}- The array of staked pools for the account." + } + ], + "returns": { + "type": "(uint64,uint64,uint64)[]" + } + }, + { + "name": "getTokenPayoutRatio", + "desc": "Retrieves the token payout ratio for a given validator - returning the pool ratios of whole so that tokenpayouts across pools can be based on a stable snaphost of stake.", + "args": [ + { + "name": "validatorId", + "type": "uint64", + "desc": "The id of the validator.@return{PoolTokenPayoutRatio}- The token payout ratio for the validator." + } + ], + "returns": { + "type": "(uint64[24],uint64)" + } + }, + { + "name": "getNodePoolAssignments", + "args": [ + { + "name": "validatorId", + "type": "uint64" + } + ], + "returns": { + "type": "((uint64[3])[8])" + } + }, + { + "name": "getNFDRegistryID", + "args": [], + "returns": { + "type": "uint64" + } + }, + { + "name": "addValidator", + "desc": "Adds a new validator", + "args": [ + { + "name": "mbrPayment", + "type": "pay", + "desc": "payment from caller which covers mbr increase of new validator storage" + }, + { + "name": "nfdName", + "type": "string", + "desc": "(Optional) Name of nfd (used as double-check against id specified in config)" + }, + { + "name": "config", + "type": "(uint64,address,address,uint64,uint8,byte[32],uint64,uint64,uint64,uint16,uint32,address,uint64,uint64,uint8,uint64,uint64)", + "desc": "ValidatorConfig struct" + } + ], + "returns": { + "type": "uint64", + "desc": "validator id" + } + }, + { + "name": "changeValidatorManager", + "desc": "Changes the Validator manager for a specific Validator id.[ ONLY OWNER CAN CHANGE ]", + "args": [ + { + "name": "validatorId", + "type": "uint64", + "desc": "The id of the validator to change the manager for." + }, + { + "name": "manager", + "type": "address", + "desc": "The new manager address." + } + ], + "returns": { + "type": "void" + } + }, + { + "name": "changeValidatorSunsetInfo", + "desc": "Updates the sunset information for a given validator.[ ONLY OWNER CAN CHANGE ]", + "args": [ + { + "name": "validatorId", + "type": "uint64", + "desc": "The id of the validator to update." + }, + { + "name": "sunsettingOn", + "type": "uint64", + "desc": "The new sunset timestamp." + }, + { + "name": "sunsettingTo", + "type": "uint64", + "desc": "The new sunset to validator id." + } + ], + "returns": { + "type": "void" + } + }, + { + "name": "changeValidatorNFD", + "desc": "Changes the NFD for a validator in the validatorList contract.[ ONLY OWNER OR MANAGER CAN CHANGE ]", + "args": [ + { + "name": "validatorId", + "type": "uint64", + "desc": "The id of the validator to update." + }, + { + "name": "nfdAppID", + "type": "uint64", + "desc": "The application id of the NFD to assign to the validator." + }, + { + "name": "nfdName", + "type": "string", + "desc": "The name of the NFD (which must match)" + } + ], + "returns": { + "type": "void" + } + }, + { + "name": "changeValidatorCommissionAddress", + "desc": "Change the commission address that validator rewards are sent to.[ ONLY OWNER CAN CHANGE ]", + "args": [ + { + "name": "validatorId", + "type": "uint64" + }, + { + "name": "commissionAddress", + "type": "address" + } + ], + "returns": { + "type": "void" + } + }, + { + "name": "changeValidatorRewardInfo", + "desc": "Allow the additional rewards (gating entry, additional token rewards) information be changed at will.[ ONLY OWNER CAN CHANGE ]", + "args": [ + { + "name": "validatorId", + "type": "uint64" + }, + { + "name": "EntryGatingType", + "type": "uint8" + }, + { + "name": "EntryGatingValue", + "type": "byte[32]" + }, + { + "name": "GatingAssetMinBalance", + "type": "uint64" + }, + { + "name": "RewardPerPayout", + "type": "uint64" + } + ], + "returns": { + "type": "void" + } + }, + { + "name": "addPool", + "desc": "Adds a new pool to a validator's pool set, returning the 'key' to reference the pool in the future for staking, etc.The caller must pay the cost of the validators MBR increase as well as the MBR that will be needed for the pool itself.[ ONLY OWNER OR MANAGER CAN call ]", + "args": [ + { + "name": "mbrPayment", + "type": "pay", + "desc": "payment from caller which covers mbr increase of adding a new pool" + }, + { + "name": "validatorId", + "type": "uint64", + "desc": "is id of validator to pool to (must be owner or manager)" + }, + { + "name": "nodeNum", + "type": "uint64", + "desc": "is node number to add to" + } + ], + "returns": { + "type": "(uint64,uint64,uint64)", + "desc": "{ValidatorPoolKey}pool key to created pool" + } + }, + { + "name": "addStake", + "desc": "Adds stake to a validator pool.", + "args": [ + { + "name": "stakedAmountPayment", + "type": "pay", + "desc": "payment coming from staker to place into a pool" + }, + { + "name": "validatorId", + "type": "uint64", + "desc": "The id of the validator." + }, + { + "name": "valueToVerify", + "type": "uint64", + "desc": "only if validator has gating to enter - this is asset id or nfd id that corresponds to gating.Txn sender is factored in as well if that is part of gating.*" + } + ], + "returns": { + "type": "(uint64,uint64,uint64)", + "desc": "{ValidatorPoolKey}- The key of the validator pool." + } + }, + { + "name": "setTokenPayoutRatio", + "desc": "setTokenPayoutRatio is called by Staking Pool # 1 (ONLY) to ask the validator (us) to calculate the ratiosof stake in the pools for subsequent token payouts (ie: 2 pools, '100' algo total staked, 60 in pool 1, and 40in pool 2. This is done so we have a stable snapshot of stake - taken once per epoch - only triggered bypool 1 doing payout. pools other than 1 doing payout call pool 1 to ask it do it first.It would be 60/40% in the poolPctOfWhole values. The token reward payouts then use these values instead oftheir 'current' stake which changes as part of the payouts themselves (and people could be changing stakeduring the epoch updates across pools)Multiple pools will call us via pool 1 (pool2->pool1->valdiator, etc.) so don't assert on pool1 calling multipletimes in same epoch. Just return.", + "args": [ + { + "name": "validatorId", + "type": "uint64", + "desc": "validator id (and thus pool) calling us. Verified so that sender MUST be pool 1 of this validator." + } + ], + "returns": { + "type": "(uint64[24],uint64)", + "desc": "PoolTokenPayoutRatio - the finished ratio data" + } + }, + { + "name": "stakeUpdatedViaRewards", + "desc": "stakeUpdatedViaRewards is called by Staking pools to inform the validator (us) that a particular amount of totalstake has been added to the specified pool. This is used to update the stats we have in our PoolInfo storage.The calling App id is validated against our pool list as well.", + "args": [ + { + "name": "poolKey", + "type": "(uint64,uint64,uint64)", + "desc": "ValidatorPoolKey type" + }, + { + "name": "algoToAdd", + "type": "uint64", + "desc": "amount this validator's total stake increased via rewards" + }, + { + "name": "rewardTokenAmountReserved", + "type": "uint64", + "desc": "amount this validator's total stake increased via rewards (that should beseen as 'accounted for/pending spent')" + } + ], + "returns": { + "type": "void" + } + }, + { + "name": "stakeRemoved", + "desc": "stakeRemoved is called by Staking pools to inform the validator (us) that a particular amount of total stake has been removedfrom the specified pool. This is used to update the stats we have in our PoolInfo storage.If any amount of rewardRemoved is specified, then that amount of reward is sent to the useThe calling App id is validated against our pool list as well.", + "args": [ + { + "name": "poolKey", + "type": "(uint64,uint64,uint64)", + "desc": "calling us from which stake was removed" + }, + { + "name": "staker", + "type": "address" + }, + { + "name": "amountRemoved", + "type": "uint64", + "desc": "algo amount removed" + }, + { + "name": "rewardRemoved", + "type": "uint64", + "desc": "if applicable, amount of token reward removed (by pool 1 caller) or TO remove and pay out (via pool 1 from different pool caller)" + }, + { + "name": "stakerRemoved", + "type": "bool" + } + ], + "returns": { + "type": "void" + } + }, + { + "name": "findPoolForStaker", + "desc": "Finds the pool for a staker based on the provided validator id, staker address, and amount to stake.First checks the stakers 'already staked list' for the validator preferring those (adding if possible) then addsto new pool if necessary.", + "args": [ + { + "name": "validatorId", + "type": "uint64", + "desc": "The id of the validator." + }, + { + "name": "staker", + "type": "address", + "desc": "The address of the staker." + }, + { + "name": "amountToStake", + "type": "uint64", + "desc": "The amount to stake." + } + ], + "returns": { + "type": "((uint64,uint64,uint64),bool,bool)", + "desc": "{ValidatorPoolKey, boolean, boolean}- The pool for the staker, true/false on whether the staker is 'new'to this VALIDATOR, and true/false if staker is new to the protocol." + } + }, + { + "name": "movePoolToNode", + "desc": "Find the specified pool (in any node number) and move it to the specified node.The pool account is forced offline if moved so prior node will still run for 320 rounds butnew key goes online on new node soon after (320 rounds after it goes online)No-op if success, asserts if not found or can't move (no space in target)[ ONLY OWNER OR MANAGER CAN CHANGE ]Only callable by owner or manager", + "args": [ + { + "name": "validatorId", + "type": "uint64" + }, + { + "name": "poolAppId", + "type": "uint64" + }, + { + "name": "nodeNum", + "type": "uint64" + } + ], + "returns": { + "type": "void" + } + } + ] +} \ No newline at end of file diff --git a/contracts/contracts/artifacts/ValidatorRegistry.clear.teal b/contracts/contracts/artifacts/ValidatorRegistry.clear.teal new file mode 100644 index 00000000..e9f1d65b --- /dev/null +++ b/contracts/contracts/artifacts/ValidatorRegistry.clear.teal @@ -0,0 +1 @@ +#pragma version 10 \ No newline at end of file diff --git a/contracts/contracts/artifacts/ValidatorRegistry.src_map.json b/contracts/contracts/artifacts/ValidatorRegistry.src_map.json new file mode 100644 index 00000000..b022ffac --- /dev/null +++ b/contracts/contracts/artifacts/ValidatorRegistry.src_map.json @@ -0,0 +1,25533 @@ +[ + { + "teal": 1, + "source": 163, + "pc": [ + 0, + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9, + 10, + 11, + 12, + 13, + 14, + 15, + 16, + 17, + 18, + 19, + 20, + 21, + 22, + 23, + 24, + 25, + 26, + 27, + 28, + 29, + 30, + 31, + 32, + 33, + 34, + 35, + 36, + 37, + 38, + 39, + 40, + 41, + 42, + 43, + 44, + 45, + 46, + 47, + 48, + 49, + 50, + 51, + 52, + 53, + 54, + 55, + 56, + 57, + 58, + 59, + 60, + 61, + 62, + 63, + 64, + 65, + 66, + 67, + 68, + 69, + 70, + 71, + 72, + 73, + 74, + 75, + 76, + 77, + 78, + 79, + 80, + 81, + 82, + 83, + 84, + 85, + 86, + 87, + 88, + 89, + 90, + 91, + 92, + 93, + 94, + 95, + 96, + 97, + 98, + 99, + 100, + 101, + 102, + 103, + 104, + 105, + 106, + 107, + 108, + 109, + 110, + 111, + 112, + 113, + 114, + 115, + 116, + 117, + 118, + 119, + 120, + 121, + 122, + 123, + 124, + 125, + 126, + 127, + 128, + 129, + 130, + 131, + 132, + 133, + 134, + 135, + 136, + 137, + 138, + 139, + 140, + 141, + 142, + 143, + 144, + 145, + 146, + 147, + 148, + 149, + 150, + 151, + 152, + 153, + 154, + 155, + 156, + 157, + 158 + ] + }, + { + "teal": 13, + "source": 163, + "pc": [ + 159, + 160 + ] + }, + { + "teal": 14, + "source": 163, + "pc": [ + 161 + ] + }, + { + "teal": 15, + "source": 163, + "pc": [ + 162, + 163 + ] + }, + { + "teal": 16, + "source": 163, + "pc": [ + 164 + ] + }, + { + "teal": 17, + "source": 163, + "pc": [ + 165, + 166 + ] + }, + { + "teal": 18, + "source": 163, + "pc": [ + 167 + ] + }, + { + "teal": 19, + "source": 163, + "pc": [ + 168, + 169, + 170, + 171, + 172, + 173, + 174, + 175, + 176, + 177, + 178, + 179, + 180, + 181, + 182, + 183, + 184, + 185, + 186, + 187, + 188, + 189, + 190, + 191, + 192, + 193 + ] + }, + { + "teal": 22, + "source": 163, + "pc": [ + 194 + ] + }, + { + "teal": 27, + "source": 193, + "pc": [ + 195, + 196, + 197 + ] + }, + { + "teal": 28, + "source": 193, + "pc": [ + 198 + ] + }, + { + "teal": 31, + "source": 193, + "pc": [ + 199, + 200, + 201 + ] + }, + { + "teal": 32, + "source": 193, + "pc": [ + 202 + ] + }, + { + "teal": 33, + "source": 193, + "pc": [ + 203 + ] + }, + { + "teal": 37, + "source": 193, + "pc": [ + 204, + 205, + 206 + ] + }, + { + "teal": 41, + "source": 194, + "pc": [ + 207, + 208 + ] + }, + { + "teal": 42, + "source": 194, + "pc": [ + 209 + ] + }, + { + "teal": 43, + "source": 194, + "pc": [ + 210 + ] + }, + { + "teal": 47, + "source": 195, + "pc": [ + 211, + 212 + ] + }, + { + "teal": 48, + "source": 195, + "pc": [ + 213, + 214 + ] + }, + { + "teal": 49, + "source": 195, + "pc": [ + 215 + ] + }, + { + "teal": 53, + "source": 196, + "pc": [ + 216, + 217 + ] + }, + { + "teal": 54, + "source": 196, + "pc": [ + 218 + ] + }, + { + "teal": 55, + "source": 196, + "pc": [ + 219 + ] + }, + { + "teal": 59, + "source": 197, + "pc": [ + 220, + 221 + ] + }, + { + "teal": 60, + "source": 197, + "pc": [ + 222 + ] + }, + { + "teal": 61, + "source": 197, + "pc": [ + 223 + ] + }, + { + "teal": 62, + "source": 193, + "pc": [ + 224 + ] + }, + { + "teal": 67, + "source": 203, + "pc": [ + 225, + 226, + 227 + ] + }, + { + "teal": 68, + "source": 203, + "pc": [ + 228 + ] + }, + { + "teal": 69, + "source": 203, + "pc": [ + 229 + ] + }, + { + "teal": 75, + "source": 203, + "pc": [ + 230, + 231, + 232 + ] + }, + { + "teal": 76, + "source": 203, + "pc": [ + 233 + ] + }, + { + "teal": 81, + "source": 214, + "pc": [ + 234 + ] + }, + { + "teal": 84, + "source": 214, + "pc": [ + 235, + 236, + 237 + ] + }, + { + "teal": 85, + "source": 214, + "pc": [ + 238 + ] + }, + { + "teal": 86, + "source": 214, + "pc": [ + 239 + ] + }, + { + "teal": 87, + "source": 214, + "pc": [ + 240 + ] + }, + { + "teal": 88, + "source": 214, + "pc": [ + 241 + ] + }, + { + "teal": 100, + "source": 214, + "pc": [ + 242, + 243, + 244 + ] + }, + { + "teal": 123, + "source": 218, + "pc": [ + 245, + 246, + 247 + ] + }, + { + "teal": 124, + "source": 218, + "pc": [ + 248, + 249, + 250 + ] + }, + { + "teal": 125, + "source": 218, + "pc": [ + 251 + ] + }, + { + "teal": 126, + "source": 226, + "pc": [ + 252 + ] + }, + { + "teal": 127, + "source": 225, + "pc": [ + 253 + ] + }, + { + "teal": 128, + "source": 224, + "pc": [ + 254 + ] + }, + { + "teal": 129, + "source": 224, + "pc": [ + 255, + 256 + ] + }, + { + "teal": 130, + "source": 220, + "pc": [ + 257 + ] + }, + { + "teal": 131, + "source": 219, + "pc": [ + 258, + 259, + 260 + ] + }, + { + "teal": 132, + "source": 219, + "pc": [ + 261 + ] + }, + { + "teal": 133, + "source": 219, + "pc": [ + 262 + ] + }, + { + "teal": 134, + "source": 229, + "pc": [ + 263, + 264 + ] + }, + { + "teal": 135, + "source": 230, + "pc": [ + 265, + 266, + 267 + ] + }, + { + "teal": 136, + "source": 230, + "pc": [ + 268, + 269, + 270 + ] + }, + { + "teal": 137, + "source": 229, + "pc": [ + 271 + ] + }, + { + "teal": 138, + "source": 229, + "pc": [ + 272 + ] + }, + { + "teal": 139, + "source": 229, + "pc": [ + 273 + ] + }, + { + "teal": 140, + "source": 234, + "pc": [ + 274, + 275, + 276 + ] + }, + { + "teal": 141, + "source": 233, + "pc": [ + 277, + 278, + 279 + ] + }, + { + "teal": 142, + "source": 233, + "pc": [ + 280 + ] + }, + { + "teal": 143, + "source": 233, + "pc": [ + 281 + ] + }, + { + "teal": 144, + "source": 217, + "pc": [ + 282 + ] + }, + { + "teal": 149, + "source": 242, + "pc": [ + 283 + ] + }, + { + "teal": 152, + "source": 242, + "pc": [ + 284, + 285, + 286 + ] + }, + { + "teal": 153, + "source": 242, + "pc": [ + 287 + ] + }, + { + "teal": 154, + "source": 242, + "pc": [ + 288 + ] + }, + { + "teal": 155, + "source": 242, + "pc": [ + 289 + ] + }, + { + "teal": 156, + "source": 242, + "pc": [ + 290 + ] + }, + { + "teal": 162, + "source": 242, + "pc": [ + 291, + 292, + 293 + ] + }, + { + "teal": 178, + "source": 248, + "pc": [ + 294, + 295, + 296, + 297, + 298, + 299, + 300, + 301, + 302, + 303, + 304, + 305, + 306, + 307, + 308, + 309, + 310, + 311, + 312, + 313, + 314, + 315, + 316, + 317, + 318, + 319, + 320, + 321, + 322, + 323, + 324, + 325, + 326, + 327, + 328, + 329, + 330, + 331, + 332, + 333, + 334, + 335 + ] + }, + { + "teal": 179, + "source": 249, + "pc": [ + 336, + 337, + 338 + ] + }, + { + "teal": 180, + "source": 249, + "pc": [ + 339 + ] + }, + { + "teal": 181, + "source": 249, + "pc": [ + 340 + ] + }, + { + "teal": 182, + "source": 250, + "pc": [ + 341, + 342, + 343 + ] + }, + { + "teal": 183, + "source": 250, + "pc": [ + 344 + ] + }, + { + "teal": 184, + "source": 250, + "pc": [ + 345 + ] + }, + { + "teal": 185, + "source": 251, + "pc": [ + 346, + 347, + 348 + ] + }, + { + "teal": 186, + "source": 251, + "pc": [ + 349 + ] + }, + { + "teal": 187, + "source": 251, + "pc": [ + 350 + ] + }, + { + "teal": 188, + "source": 252, + "pc": [ + 351, + 352, + 353, + 354, + 355, + 356, + 357, + 358, + 359, + 360 + ] + }, + { + "teal": 189, + "source": 252, + "pc": [ + 361 + ] + }, + { + "teal": 190, + "source": 253, + "pc": [ + 362, + 363, + 364, + 365, + 366, + 367, + 368, + 369, + 370, + 371 + ] + }, + { + "teal": 191, + "source": 253, + "pc": [ + 372 + ] + }, + { + "teal": 192, + "source": 254, + "pc": [ + 373, + 374, + 375, + 376, + 377, + 378, + 379, + 380, + 381, + 382 + ] + }, + { + "teal": 193, + "source": 254, + "pc": [ + 383 + ] + }, + { + "teal": 194, + "source": 243, + "pc": [ + 384 + ] + }, + { + "teal": 199, + "source": 262, + "pc": [ + 385 + ] + }, + { + "teal": 202, + "source": 262, + "pc": [ + 386, + 387, + 388 + ] + }, + { + "teal": 203, + "source": 262, + "pc": [ + 389 + ] + }, + { + "teal": 204, + "source": 262, + "pc": [ + 390 + ] + }, + { + "teal": 205, + "source": 262, + "pc": [ + 391 + ] + }, + { + "teal": 206, + "source": 262, + "pc": [ + 392 + ] + }, + { + "teal": 207, + "source": 262, + "pc": [ + 393 + ] + }, + { + "teal": 213, + "source": 262, + "pc": [ + 394, + 395, + 396 + ] + }, + { + "teal": 217, + "source": 263, + "pc": [ + 397, + 398 + ] + }, + { + "teal": 218, + "source": 263, + "pc": [ + 399 + ] + }, + { + "teal": 219, + "source": 263, + "pc": [ + 400 + ] + }, + { + "teal": 224, + "source": 267, + "pc": [ + 401 + ] + }, + { + "teal": 227, + "source": 267, + "pc": [ + 402, + 403, + 404 + ] + }, + { + "teal": 228, + "source": 267, + "pc": [ + 405 + ] + }, + { + "teal": 231, + "source": 267, + "pc": [ + 406, + 407, + 408 + ] + }, + { + "teal": 232, + "source": 267, + "pc": [ + 409 + ] + }, + { + "teal": 233, + "source": 267, + "pc": [ + 410 + ] + }, + { + "teal": 234, + "source": 267, + "pc": [ + 411 + ] + }, + { + "teal": 235, + "source": 267, + "pc": [ + 412 + ] + }, + { + "teal": 239, + "source": 267, + "pc": [ + 413, + 414, + 415 + ] + }, + { + "teal": 243, + "source": 268, + "pc": [ + 416 + ] + }, + { + "teal": 244, + "source": 268, + "pc": [ + 417, + 418 + ] + }, + { + "teal": 245, + "source": 268, + "pc": [ + 419 + ] + }, + { + "teal": 246, + "source": 268, + "pc": [ + 420, + 421 + ] + }, + { + "teal": 247, + "source": 268, + "pc": [ + 422 + ] + }, + { + "teal": 248, + "source": 268, + "pc": [ + 423 + ] + }, + { + "teal": 249, + "source": 268, + "pc": [ + 424, + 425 + ] + }, + { + "teal": 250, + "source": 268, + "pc": [ + 426 + ] + }, + { + "teal": 251, + "source": 268, + "pc": [ + 427 + ] + }, + { + "teal": 256, + "source": 272, + "pc": [ + 428 + ] + }, + { + "teal": 259, + "source": 272, + "pc": [ + 429, + 430, + 431 + ] + }, + { + "teal": 260, + "source": 272, + "pc": [ + 432 + ] + }, + { + "teal": 263, + "source": 272, + "pc": [ + 433, + 434, + 435 + ] + }, + { + "teal": 264, + "source": 272, + "pc": [ + 436 + ] + }, + { + "teal": 265, + "source": 272, + "pc": [ + 437 + ] + }, + { + "teal": 266, + "source": 272, + "pc": [ + 438 + ] + }, + { + "teal": 267, + "source": 272, + "pc": [ + 439 + ] + }, + { + "teal": 271, + "source": 272, + "pc": [ + 440, + 441, + 442 + ] + }, + { + "teal": 275, + "source": 273, + "pc": [ + 443, + 444 + ] + }, + { + "teal": 276, + "source": 273, + "pc": [ + 445, + 446 + ] + }, + { + "teal": 277, + "source": 273, + "pc": [ + 447 + ] + }, + { + "teal": 278, + "source": 273, + "pc": [ + 448, + 449 + ] + }, + { + "teal": 279, + "source": 273, + "pc": [ + 450 + ] + }, + { + "teal": 280, + "source": 273, + "pc": [ + 451 + ] + }, + { + "teal": 281, + "source": 273, + "pc": [ + 452, + 453 + ] + }, + { + "teal": 282, + "source": 273, + "pc": [ + 454 + ] + }, + { + "teal": 283, + "source": 273, + "pc": [ + 455 + ] + }, + { + "teal": 288, + "source": 277, + "pc": [ + 456 + ] + }, + { + "teal": 291, + "source": 277, + "pc": [ + 457, + 458, + 459 + ] + }, + { + "teal": 292, + "source": 277, + "pc": [ + 460 + ] + }, + { + "teal": 295, + "source": 277, + "pc": [ + 461, + 462, + 463 + ] + }, + { + "teal": 296, + "source": 277, + "pc": [ + 464 + ] + }, + { + "teal": 297, + "source": 277, + "pc": [ + 465 + ] + }, + { + "teal": 298, + "source": 277, + "pc": [ + 466 + ] + }, + { + "teal": 299, + "source": 277, + "pc": [ + 467 + ] + }, + { + "teal": 303, + "source": 277, + "pc": [ + 468, + 469, + 470 + ] + }, + { + "teal": 310, + "source": 279, + "pc": [ + 471 + ] + }, + { + "teal": 311, + "source": 279, + "pc": [ + 472, + 473 + ] + }, + { + "teal": 312, + "source": 279, + "pc": [ + 474 + ] + }, + { + "teal": 313, + "source": 279, + "pc": [ + 475, + 476 + ] + }, + { + "teal": 314, + "source": 279, + "pc": [ + 477 + ] + }, + { + "teal": 315, + "source": 279, + "pc": [ + 478 + ] + }, + { + "teal": 316, + "source": 279, + "pc": [ + 479, + 480 + ] + }, + { + "teal": 317, + "source": 279, + "pc": [ + 481 + ] + }, + { + "teal": 318, + "source": 280, + "pc": [ + 482, + 483 + ] + }, + { + "teal": 319, + "source": 280, + "pc": [ + 484, + 485 + ] + }, + { + "teal": 320, + "source": 280, + "pc": [ + 486 + ] + }, + { + "teal": 321, + "source": 280, + "pc": [ + 487, + 488 + ] + }, + { + "teal": 322, + "source": 280, + "pc": [ + 489 + ] + }, + { + "teal": 323, + "source": 280, + "pc": [ + 490 + ] + }, + { + "teal": 324, + "source": 280, + "pc": [ + 491, + 492 + ] + }, + { + "teal": 325, + "source": 280, + "pc": [ + 493 + ] + }, + { + "teal": 326, + "source": 280, + "pc": [ + 494 + ] + }, + { + "teal": 327, + "source": 278, + "pc": [ + 495 + ] + }, + { + "teal": 332, + "source": 291, + "pc": [ + 496 + ] + }, + { + "teal": 335, + "source": 291, + "pc": [ + 497, + 498, + 499 + ] + }, + { + "teal": 336, + "source": 291, + "pc": [ + 500 + ] + }, + { + "teal": 339, + "source": 291, + "pc": [ + 501, + 502, + 503 + ] + }, + { + "teal": 340, + "source": 291, + "pc": [ + 504 + ] + }, + { + "teal": 341, + "source": 291, + "pc": [ + 505 + ] + }, + { + "teal": 342, + "source": 291, + "pc": [ + 506, + 507 + ] + }, + { + "teal": 343, + "source": 291, + "pc": [ + 508 + ] + }, + { + "teal": 344, + "source": 291, + "pc": [ + 509 + ] + }, + { + "teal": 345, + "source": 291, + "pc": [ + 510, + 511, + 512 + ] + }, + { + "teal": 346, + "source": 291, + "pc": [ + 513 + ] + }, + { + "teal": 347, + "source": 291, + "pc": [ + 514 + ] + }, + { + "teal": 348, + "source": 291, + "pc": [ + 515 + ] + }, + { + "teal": 349, + "source": 291, + "pc": [ + 516 + ] + }, + { + "teal": 350, + "source": 291, + "pc": [ + 517 + ] + }, + { + "teal": 351, + "source": 291, + "pc": [ + 518 + ] + }, + { + "teal": 360, + "source": 291, + "pc": [ + 519, + 520, + 521 + ] + }, + { + "teal": 363, + "source": 291, + "pc": [ + 522 + ] + }, + { + "teal": 364, + "source": 291, + "pc": [ + 523, + 524 + ] + }, + { + "teal": 368, + "source": 292, + "pc": [ + 525 + ] + }, + { + "teal": 369, + "source": 292, + "pc": [ + 526, + 527 + ] + }, + { + "teal": 373, + "source": 293, + "pc": [ + 528, + 529 + ] + }, + { + "teal": 374, + "source": 293, + "pc": [ + 530, + 531 + ] + }, + { + "teal": 375, + "source": 293, + "pc": [ + 532 + ] + }, + { + "teal": 376, + "source": 293, + "pc": [ + 533, + 534 + ] + }, + { + "teal": 377, + "source": 293, + "pc": [ + 535 + ] + }, + { + "teal": 378, + "source": 293, + "pc": [ + 536 + ] + }, + { + "teal": 379, + "source": 293, + "pc": [ + 537, + 538 + ] + }, + { + "teal": 380, + "source": 293, + "pc": [ + 539 + ] + }, + { + "teal": 381, + "source": 293, + "pc": [ + 540, + 541 + ] + }, + { + "teal": 385, + "source": 294, + "pc": [ + 542 + ] + }, + { + "teal": 386, + "source": 294, + "pc": [ + 543, + 544 + ] + }, + { + "teal": 391, + "source": 294, + "pc": [ + 545, + 546 + ] + }, + { + "teal": 392, + "source": 294, + "pc": [ + 547 + ] + }, + { + "teal": 393, + "source": 294, + "pc": [ + 548 + ] + }, + { + "teal": 394, + "source": 294, + "pc": [ + 549, + 550, + 551 + ] + }, + { + "teal": 399, + "source": 295, + "pc": [ + 552, + 553 + ] + }, + { + "teal": 400, + "source": 295, + "pc": [ + 554, + 555 + ] + }, + { + "teal": 401, + "source": 295, + "pc": [ + 556, + 557 + ] + }, + { + "teal": 402, + "source": 295, + "pc": [ + 558 + ] + }, + { + "teal": 403, + "source": 295, + "pc": [ + 559 + ] + }, + { + "teal": 404, + "source": 295, + "pc": [ + 560 + ] + }, + { + "teal": 405, + "source": 295, + "pc": [ + 561 + ] + }, + { + "teal": 406, + "source": 295, + "pc": [ + 562 + ] + }, + { + "teal": 407, + "source": 295, + "pc": [ + 563 + ] + }, + { + "teal": 408, + "source": 295, + "pc": [ + 564 + ] + }, + { + "teal": 409, + "source": 295, + "pc": [ + 565 + ] + }, + { + "teal": 410, + "source": 295, + "pc": [ + 566, + 567, + 568 + ] + }, + { + "teal": 413, + "source": 297, + "pc": [ + 569, + 570, + 571 + ] + }, + { + "teal": 418, + "source": 299, + "pc": [ + 572, + 573 + ] + }, + { + "teal": 419, + "source": 299, + "pc": [ + 574, + 575 + ] + }, + { + "teal": 420, + "source": 299, + "pc": [ + 576, + 577 + ] + }, + { + "teal": 421, + "source": 299, + "pc": [ + 578, + 579 + ] + }, + { + "teal": 422, + "source": 299, + "pc": [ + 580 + ] + }, + { + "teal": 423, + "source": 299, + "pc": [ + 581, + 582 + ] + }, + { + "teal": 424, + "source": 299, + "pc": [ + 583 + ] + }, + { + "teal": 425, + "source": 299, + "pc": [ + 584 + ] + }, + { + "teal": 426, + "source": 299, + "pc": [ + 585, + 586 + ] + }, + { + "teal": 431, + "source": 294, + "pc": [ + 587, + 588 + ] + }, + { + "teal": 432, + "source": 294, + "pc": [ + 589 + ] + }, + { + "teal": 433, + "source": 294, + "pc": [ + 590 + ] + }, + { + "teal": 434, + "source": 294, + "pc": [ + 591, + 592 + ] + }, + { + "teal": 435, + "source": 294, + "pc": [ + 593, + 594, + 595 + ] + }, + { + "teal": 440, + "source": 301, + "pc": [ + 596, + 597 + ] + }, + { + "teal": 443, + "source": 301, + "pc": [ + 598, + 599 + ] + }, + { + "teal": 446, + "source": 301, + "pc": [ + 600, + 601 + ] + }, + { + "teal": 447, + "source": 301, + "pc": [ + 602 + ] + }, + { + "teal": 452, + "source": 308, + "pc": [ + 603 + ] + }, + { + "teal": 455, + "source": 308, + "pc": [ + 604, + 605, + 606 + ] + }, + { + "teal": 456, + "source": 308, + "pc": [ + 607 + ] + }, + { + "teal": 459, + "source": 308, + "pc": [ + 608, + 609, + 610 + ] + }, + { + "teal": 460, + "source": 308, + "pc": [ + 611 + ] + }, + { + "teal": 463, + "source": 308, + "pc": [ + 612, + 613, + 614 + ] + }, + { + "teal": 464, + "source": 308, + "pc": [ + 615 + ] + }, + { + "teal": 465, + "source": 308, + "pc": [ + 616 + ] + }, + { + "teal": 466, + "source": 308, + "pc": [ + 617 + ] + }, + { + "teal": 467, + "source": 308, + "pc": [ + 618 + ] + }, + { + "teal": 468, + "source": 308, + "pc": [ + 619 + ] + }, + { + "teal": 472, + "source": 308, + "pc": [ + 620, + 621, + 622 + ] + }, + { + "teal": 476, + "source": 309, + "pc": [ + 623, + 624 + ] + }, + { + "teal": 477, + "source": 309, + "pc": [ + 625 + ] + }, + { + "teal": 478, + "source": 309, + "pc": [ + 626 + ] + }, + { + "teal": 479, + "source": 309, + "pc": [ + 627 + ] + }, + { + "teal": 480, + "source": 309, + "pc": [ + 628, + 629, + 630 + ] + }, + { + "teal": 481, + "source": 309, + "pc": [ + 631, + 632 + ] + }, + { + "teal": 482, + "source": 309, + "pc": [ + 633 + ] + }, + { + "teal": 483, + "source": 309, + "pc": [ + 634 + ] + }, + { + "teal": 484, + "source": 309, + "pc": [ + 635 + ] + }, + { + "teal": 487, + "source": 309, + "pc": [ + 636 + ] + }, + { + "teal": 491, + "source": 310, + "pc": [ + 637, + 638 + ] + }, + { + "teal": 492, + "source": 310, + "pc": [ + 639, + 640 + ] + }, + { + "teal": 493, + "source": 310, + "pc": [ + 641 + ] + }, + { + "teal": 494, + "source": 310, + "pc": [ + 642 + ] + }, + { + "teal": 495, + "source": 310, + "pc": [ + 643, + 644 + ] + }, + { + "teal": 496, + "source": 310, + "pc": [ + 645 + ] + }, + { + "teal": 497, + "source": 310, + "pc": [ + 646 + ] + }, + { + "teal": 498, + "source": 310, + "pc": [ + 647 + ] + }, + { + "teal": 499, + "source": 310, + "pc": [ + 648 + ] + }, + { + "teal": 500, + "source": 310, + "pc": [ + 649 + ] + }, + { + "teal": 501, + "source": 310, + "pc": [ + 650 + ] + }, + { + "teal": 502, + "source": 310, + "pc": [ + 651, + 652 + ] + }, + { + "teal": 503, + "source": 310, + "pc": [ + 653 + ] + }, + { + "teal": 504, + "source": 310, + "pc": [ + 654 + ] + }, + { + "teal": 505, + "source": 310, + "pc": [ + 655, + 656 + ] + }, + { + "teal": 506, + "source": 310, + "pc": [ + 657 + ] + }, + { + "teal": 507, + "source": 310, + "pc": [ + 658 + ] + }, + { + "teal": 508, + "source": 310, + "pc": [ + 659 + ] + }, + { + "teal": 513, + "source": 314, + "pc": [ + 660 + ] + }, + { + "teal": 516, + "source": 314, + "pc": [ + 661, + 662, + 663 + ] + }, + { + "teal": 517, + "source": 314, + "pc": [ + 664 + ] + }, + { + "teal": 518, + "source": 314, + "pc": [ + 665 + ] + }, + { + "teal": 519, + "source": 314, + "pc": [ + 666 + ] + }, + { + "teal": 520, + "source": 314, + "pc": [ + 667 + ] + }, + { + "teal": 521, + "source": 314, + "pc": [ + 668 + ] + }, + { + "teal": 524, + "source": 314, + "pc": [ + 669, + 670, + 671 + ] + }, + { + "teal": 525, + "source": 314, + "pc": [ + 672 + ] + }, + { + "teal": 526, + "source": 314, + "pc": [ + 673 + ] + }, + { + "teal": 527, + "source": 314, + "pc": [ + 674 + ] + }, + { + "teal": 528, + "source": 314, + "pc": [ + 675 + ] + }, + { + "teal": 532, + "source": 314, + "pc": [ + 676, + 677, + 678 + ] + }, + { + "teal": 536, + "source": 315, + "pc": [ + 679, + 680 + ] + }, + { + "teal": 537, + "source": 315, + "pc": [ + 681, + 682 + ] + }, + { + "teal": 538, + "source": 315, + "pc": [ + 683, + 684, + 685 + ] + }, + { + "teal": 539, + "source": 315, + "pc": [ + 686 + ] + }, + { + "teal": 540, + "source": 315, + "pc": [ + 687 + ] + }, + { + "teal": 541, + "source": 315, + "pc": [ + 688 + ] + }, + { + "teal": 542, + "source": 315, + "pc": [ + 689, + 690 + ] + }, + { + "teal": 543, + "source": 315, + "pc": [ + 691 + ] + }, + { + "teal": 544, + "source": 315, + "pc": [ + 692 + ] + }, + { + "teal": 545, + "source": 315, + "pc": [ + 693, + 694 + ] + }, + { + "teal": 546, + "source": 315, + "pc": [ + 695 + ] + }, + { + "teal": 547, + "source": 315, + "pc": [ + 696, + 697 + ] + }, + { + "teal": 548, + "source": 315, + "pc": [ + 698, + 699, + 700 + ] + }, + { + "teal": 549, + "source": 315, + "pc": [ + 701 + ] + }, + { + "teal": 550, + "source": 315, + "pc": [ + 702 + ] + }, + { + "teal": 551, + "source": 315, + "pc": [ + 703 + ] + }, + { + "teal": 552, + "source": 315, + "pc": [ + 704, + 705 + ] + }, + { + "teal": 553, + "source": 315, + "pc": [ + 706 + ] + }, + { + "teal": 554, + "source": 315, + "pc": [ + 707 + ] + }, + { + "teal": 559, + "source": 325, + "pc": [ + 708 + ] + }, + { + "teal": 562, + "source": 325, + "pc": [ + 709, + 710, + 711 + ] + }, + { + "teal": 563, + "source": 325, + "pc": [ + 712 + ] + }, + { + "teal": 566, + "source": 325, + "pc": [ + 713, + 714, + 715 + ] + }, + { + "teal": 567, + "source": 325, + "pc": [ + 716 + ] + }, + { + "teal": 568, + "source": 325, + "pc": [ + 717 + ] + }, + { + "teal": 569, + "source": 325, + "pc": [ + 718 + ] + }, + { + "teal": 570, + "source": 325, + "pc": [ + 719 + ] + }, + { + "teal": 571, + "source": 325, + "pc": [ + 720 + ] + }, + { + "teal": 581, + "source": 325, + "pc": [ + 721, + 722, + 723 + ] + }, + { + "teal": 584, + "source": 325, + "pc": [ + 724 + ] + }, + { + "teal": 585, + "source": 325, + "pc": [ + 725, + 726 + ] + }, + { + "teal": 589, + "source": 326, + "pc": [ + 727, + 728 + ] + }, + { + "teal": 590, + "source": 326, + "pc": [ + 729, + 730 + ] + }, + { + "teal": 591, + "source": 326, + "pc": [ + 731 + ] + }, + { + "teal": 592, + "source": 326, + "pc": [ + 732, + 733 + ] + }, + { + "teal": 593, + "source": 326, + "pc": [ + 734 + ] + }, + { + "teal": 594, + "source": 326, + "pc": [ + 735 + ] + }, + { + "teal": 595, + "source": 326, + "pc": [ + 736, + 737 + ] + }, + { + "teal": 596, + "source": 326, + "pc": [ + 738 + ] + }, + { + "teal": 597, + "source": 326, + "pc": [ + 739 + ] + }, + { + "teal": 598, + "source": 326, + "pc": [ + 740, + 741 + ] + }, + { + "teal": 602, + "source": 327, + "pc": [ + 742, + 743, + 744 + ] + }, + { + "teal": 603, + "source": 327, + "pc": [ + 745, + 746 + ] + }, + { + "teal": 604, + "source": 327, + "pc": [ + 747 + ] + }, + { + "teal": 605, + "source": 327, + "pc": [ + 748, + 749 + ] + }, + { + "teal": 609, + "source": 328, + "pc": [ + 750, + 751, + 752 + ] + }, + { + "teal": 610, + "source": 328, + "pc": [ + 753 + ] + }, + { + "teal": 611, + "source": 328, + "pc": [ + 754 + ] + }, + { + "teal": 612, + "source": 328, + "pc": [ + 755, + 756 + ] + }, + { + "teal": 613, + "source": 328, + "pc": [ + 757 + ] + }, + { + "teal": 614, + "source": 328, + "pc": [ + 758 + ] + }, + { + "teal": 615, + "source": 328, + "pc": [ + 759, + 760 + ] + }, + { + "teal": 616, + "source": 328, + "pc": [ + 761 + ] + }, + { + "teal": 617, + "source": 328, + "pc": [ + 762 + ] + }, + { + "teal": 618, + "source": 328, + "pc": [ + 763, + 764 + ] + }, + { + "teal": 623, + "source": 329, + "pc": [ + 765, + 766 + ] + }, + { + "teal": 624, + "source": 329, + "pc": [ + 767 + ] + }, + { + "teal": 625, + "source": 329, + "pc": [ + 768 + ] + }, + { + "teal": 626, + "source": 329, + "pc": [ + 769, + 770, + 771 + ] + }, + { + "teal": 631, + "source": 330, + "pc": [ + 772, + 773, + 774 + ] + }, + { + "teal": 632, + "source": 330, + "pc": [ + 775, + 776 + ] + }, + { + "teal": 638, + "source": 332, + "pc": [ + 777, + 778 + ] + }, + { + "teal": 639, + "source": 332, + "pc": [ + 779, + 780 + ] + }, + { + "teal": 640, + "source": 332, + "pc": [ + 781 + ] + }, + { + "teal": 641, + "source": 332, + "pc": [ + 782, + 783, + 784 + ] + }, + { + "teal": 646, + "source": 333, + "pc": [ + 785, + 786 + ] + }, + { + "teal": 647, + "source": 333, + "pc": [ + 787, + 788 + ] + }, + { + "teal": 652, + "source": 335, + "pc": [ + 789, + 790 + ] + }, + { + "teal": 655, + "source": 335, + "pc": [ + 791, + 792 + ] + }, + { + "teal": 658, + "source": 335, + "pc": [ + 793, + 794 + ] + }, + { + "teal": 659, + "source": 335, + "pc": [ + 795 + ] + }, + { + "teal": 664, + "source": 343, + "pc": [ + 796 + ] + }, + { + "teal": 667, + "source": 343, + "pc": [ + 797, + 798, + 799 + ] + }, + { + "teal": 668, + "source": 343, + "pc": [ + 800 + ] + }, + { + "teal": 669, + "source": 343, + "pc": [ + 801 + ] + }, + { + "teal": 670, + "source": 343, + "pc": [ + 802, + 803 + ] + }, + { + "teal": 671, + "source": 343, + "pc": [ + 804 + ] + }, + { + "teal": 672, + "source": 343, + "pc": [ + 805 + ] + }, + { + "teal": 675, + "source": 343, + "pc": [ + 806, + 807, + 808 + ] + }, + { + "teal": 676, + "source": 343, + "pc": [ + 809, + 810 + ] + }, + { + "teal": 677, + "source": 343, + "pc": [ + 811 + ] + }, + { + "teal": 678, + "source": 343, + "pc": [ + 812, + 813 + ] + }, + { + "teal": 679, + "source": 343, + "pc": [ + 814 + ] + }, + { + "teal": 680, + "source": 343, + "pc": [ + 815 + ] + }, + { + "teal": 681, + "source": 343, + "pc": [ + 816 + ] + }, + { + "teal": 682, + "source": 343, + "pc": [ + 817 + ] + }, + { + "teal": 683, + "source": 343, + "pc": [ + 818 + ] + }, + { + "teal": 690, + "source": 343, + "pc": [ + 819, + 820, + 821 + ] + }, + { + "teal": 694, + "source": 344, + "pc": [ + 822 + ] + }, + { + "teal": 695, + "source": 344, + "pc": [ + 823, + 824 + ] + }, + { + "teal": 696, + "source": 344, + "pc": [ + 825 + ] + }, + { + "teal": 697, + "source": 344, + "pc": [ + 826 + ] + }, + { + "teal": 698, + "source": 344, + "pc": [ + 827 + ] + }, + { + "teal": 699, + "source": 344, + "pc": [ + 828 + ] + }, + { + "teal": 700, + "source": 344, + "pc": [ + 829 + ] + }, + { + "teal": 701, + "source": 344, + "pc": [ + 830 + ] + }, + { + "teal": 706, + "source": 353, + "pc": [ + 831 + ] + }, + { + "teal": 709, + "source": 353, + "pc": [ + 832, + 833, + 834 + ] + }, + { + "teal": 710, + "source": 353, + "pc": [ + 835 + ] + }, + { + "teal": 711, + "source": 353, + "pc": [ + 836 + ] + }, + { + "teal": 712, + "source": 353, + "pc": [ + 837, + 838 + ] + }, + { + "teal": 713, + "source": 353, + "pc": [ + 839 + ] + }, + { + "teal": 714, + "source": 353, + "pc": [ + 840 + ] + }, + { + "teal": 717, + "source": 353, + "pc": [ + 841, + 842, + 843 + ] + }, + { + "teal": 718, + "source": 353, + "pc": [ + 844 + ] + }, + { + "teal": 719, + "source": 353, + "pc": [ + 845 + ] + }, + { + "teal": 720, + "source": 353, + "pc": [ + 846 + ] + }, + { + "teal": 721, + "source": 353, + "pc": [ + 847 + ] + }, + { + "teal": 722, + "source": 353, + "pc": [ + 848 + ] + }, + { + "teal": 723, + "source": 353, + "pc": [ + 849, + 850, + 851 + ] + }, + { + "teal": 724, + "source": 353, + "pc": [ + 852 + ] + }, + { + "teal": 725, + "source": 353, + "pc": [ + 853 + ] + }, + { + "teal": 726, + "source": 353, + "pc": [ + 854 + ] + }, + { + "teal": 727, + "source": 353, + "pc": [ + 855 + ] + }, + { + "teal": 728, + "source": 353, + "pc": [ + 856 + ] + }, + { + "teal": 729, + "source": 353, + "pc": [ + 857 + ] + }, + { + "teal": 738, + "source": 353, + "pc": [ + 858, + 859, + 860 + ] + }, + { + "teal": 741, + "source": 353, + "pc": [ + 861 + ] + }, + { + "teal": 742, + "source": 353, + "pc": [ + 862, + 863 + ] + }, + { + "teal": 747, + "source": 354, + "pc": [ + 864 + ] + }, + { + "teal": 748, + "source": 354, + "pc": [ + 865, + 866 + ] + }, + { + "teal": 749, + "source": 354, + "pc": [ + 867 + ] + }, + { + "teal": 750, + "source": 354, + "pc": [ + 868 + ] + }, + { + "teal": 751, + "source": 354, + "pc": [ + 869 + ] + }, + { + "teal": 752, + "source": 354, + "pc": [ + 870 + ] + }, + { + "teal": 753, + "source": 354, + "pc": [ + 871 + ] + }, + { + "teal": 754, + "source": 354, + "pc": [ + 872, + 873, + 874 + ] + }, + { + "teal": 759, + "source": 355, + "pc": [ + 875 + ] + }, + { + "teal": 760, + "source": 355, + "pc": [ + 876 + ] + }, + { + "teal": 765, + "source": 357, + "pc": [ + 877 + ] + }, + { + "teal": 766, + "source": 357, + "pc": [ + 878, + 879 + ] + }, + { + "teal": 770, + "source": 358, + "pc": [ + 880 + ] + }, + { + "teal": 771, + "source": 358, + "pc": [ + 881, + 882 + ] + }, + { + "teal": 772, + "source": 358, + "pc": [ + 883 + ] + }, + { + "teal": 773, + "source": 358, + "pc": [ + 884 + ] + }, + { + "teal": 774, + "source": 358, + "pc": [ + 885 + ] + }, + { + "teal": 775, + "source": 358, + "pc": [ + 886, + 887 + ] + }, + { + "teal": 779, + "source": 359, + "pc": [ + 888 + ] + }, + { + "teal": 780, + "source": 359, + "pc": [ + 889, + 890 + ] + }, + { + "teal": 785, + "source": 359, + "pc": [ + 891, + 892 + ] + }, + { + "teal": 786, + "source": 359, + "pc": [ + 893, + 894 + ] + }, + { + "teal": 787, + "source": 359, + "pc": [ + 895 + ] + }, + { + "teal": 788, + "source": 359, + "pc": [ + 896, + 897, + 898 + ] + }, + { + "teal": 793, + "source": 360, + "pc": [ + 899, + 900 + ] + }, + { + "teal": 794, + "source": 360, + "pc": [ + 901, + 902 + ] + }, + { + "teal": 795, + "source": 360, + "pc": [ + 903 + ] + }, + { + "teal": 796, + "source": 360, + "pc": [ + 904 + ] + }, + { + "teal": 797, + "source": 360, + "pc": [ + 905 + ] + }, + { + "teal": 798, + "source": 360, + "pc": [ + 906 + ] + }, + { + "teal": 799, + "source": 360, + "pc": [ + 907 + ] + }, + { + "teal": 800, + "source": 360, + "pc": [ + 908 + ] + }, + { + "teal": 801, + "source": 360, + "pc": [ + 909 + ] + }, + { + "teal": 802, + "source": 360, + "pc": [ + 910 + ] + }, + { + "teal": 803, + "source": 360, + "pc": [ + 911 + ] + }, + { + "teal": 804, + "source": 360, + "pc": [ + 912, + 913, + 914 + ] + }, + { + "teal": 809, + "source": 361, + "pc": [ + 915, + 916 + ] + }, + { + "teal": 810, + "source": 361, + "pc": [ + 917, + 918 + ] + }, + { + "teal": 811, + "source": 361, + "pc": [ + 919, + 920 + ] + }, + { + "teal": 812, + "source": 361, + "pc": [ + 921 + ] + }, + { + "teal": 813, + "source": 361, + "pc": [ + 922 + ] + }, + { + "teal": 814, + "source": 361, + "pc": [ + 923 + ] + }, + { + "teal": 815, + "source": 361, + "pc": [ + 924 + ] + }, + { + "teal": 816, + "source": 361, + "pc": [ + 925 + ] + }, + { + "teal": 817, + "source": 361, + "pc": [ + 926, + 927 + ] + }, + { + "teal": 824, + "source": 359, + "pc": [ + 928, + 929 + ] + }, + { + "teal": 825, + "source": 359, + "pc": [ + 930 + ] + }, + { + "teal": 826, + "source": 359, + "pc": [ + 931 + ] + }, + { + "teal": 827, + "source": 359, + "pc": [ + 932, + 933 + ] + }, + { + "teal": 828, + "source": 359, + "pc": [ + 934, + 935, + 936 + ] + }, + { + "teal": 833, + "source": 364, + "pc": [ + 937, + 938 + ] + }, + { + "teal": 836, + "source": 364, + "pc": [ + 939, + 940 + ] + }, + { + "teal": 839, + "source": 364, + "pc": [ + 941, + 942 + ] + }, + { + "teal": 840, + "source": 364, + "pc": [ + 943 + ] + }, + { + "teal": 845, + "source": 375, + "pc": [ + 944 + ] + }, + { + "teal": 848, + "source": 375, + "pc": [ + 945, + 946, + 947 + ] + }, + { + "teal": 849, + "source": 375, + "pc": [ + 948 + ] + }, + { + "teal": 852, + "source": 375, + "pc": [ + 949, + 950, + 951 + ] + }, + { + "teal": 853, + "source": 375, + "pc": [ + 952 + ] + }, + { + "teal": 854, + "source": 375, + "pc": [ + 953 + ] + }, + { + "teal": 855, + "source": 375, + "pc": [ + 954 + ] + }, + { + "teal": 856, + "source": 375, + "pc": [ + 955 + ] + }, + { + "teal": 866, + "source": 375, + "pc": [ + 956, + 957, + 958 + ] + }, + { + "teal": 870, + "source": 376, + "pc": [ + 959, + 960 + ] + }, + { + "teal": 871, + "source": 376, + "pc": [ + 961, + 962 + ] + }, + { + "teal": 872, + "source": 376, + "pc": [ + 963 + ] + }, + { + "teal": 873, + "source": 376, + "pc": [ + 964, + 965 + ] + }, + { + "teal": 874, + "source": 376, + "pc": [ + 966 + ] + }, + { + "teal": 875, + "source": 376, + "pc": [ + 967 + ] + }, + { + "teal": 876, + "source": 376, + "pc": [ + 968, + 969 + ] + }, + { + "teal": 877, + "source": 376, + "pc": [ + 970 + ] + }, + { + "teal": 878, + "source": 376, + "pc": [ + 971 + ] + }, + { + "teal": 883, + "source": 380, + "pc": [ + 972 + ] + }, + { + "teal": 886, + "source": 380, + "pc": [ + 973, + 974, + 975 + ] + }, + { + "teal": 887, + "source": 380, + "pc": [ + 976 + ] + }, + { + "teal": 890, + "source": 380, + "pc": [ + 977, + 978, + 979 + ] + }, + { + "teal": 891, + "source": 380, + "pc": [ + 980 + ] + }, + { + "teal": 892, + "source": 380, + "pc": [ + 981 + ] + }, + { + "teal": 893, + "source": 380, + "pc": [ + 982 + ] + }, + { + "teal": 894, + "source": 380, + "pc": [ + 983 + ] + }, + { + "teal": 898, + "source": 380, + "pc": [ + 984, + 985, + 986 + ] + }, + { + "teal": 902, + "source": 381, + "pc": [ + 987 + ] + }, + { + "teal": 903, + "source": 381, + "pc": [ + 988, + 989 + ] + }, + { + "teal": 904, + "source": 381, + "pc": [ + 990 + ] + }, + { + "teal": 905, + "source": 381, + "pc": [ + 991 + ] + }, + { + "teal": 906, + "source": 381, + "pc": [ + 992 + ] + }, + { + "teal": 907, + "source": 381, + "pc": [ + 993 + ] + }, + { + "teal": 908, + "source": 381, + "pc": [ + 994 + ] + }, + { + "teal": 909, + "source": 381, + "pc": [ + 995 + ] + }, + { + "teal": 913, + "source": 383, + "pc": [ + 996, + 997 + ] + }, + { + "teal": 914, + "source": 383, + "pc": [ + 998, + 999 + ] + }, + { + "teal": 915, + "source": 383, + "pc": [ + 1000 + ] + }, + { + "teal": 916, + "source": 383, + "pc": [ + 1001, + 1002 + ] + }, + { + "teal": 917, + "source": 383, + "pc": [ + 1003 + ] + }, + { + "teal": 918, + "source": 383, + "pc": [ + 1004 + ] + }, + { + "teal": 919, + "source": 383, + "pc": [ + 1005, + 1006 + ] + }, + { + "teal": 920, + "source": 383, + "pc": [ + 1007 + ] + }, + { + "teal": 921, + "source": 383, + "pc": [ + 1008 + ] + }, + { + "teal": 926, + "source": 386, + "pc": [ + 1009 + ] + }, + { + "teal": 929, + "source": 386, + "pc": [ + 1010, + 1011, + 1012 + ] + }, + { + "teal": 930, + "source": 386, + "pc": [ + 1013 + ] + }, + { + "teal": 931, + "source": 386, + "pc": [ + 1014 + ] + }, + { + "teal": 932, + "source": 386, + "pc": [ + 1015 + ] + }, + { + "teal": 933, + "source": 386, + "pc": [ + 1016 + ] + }, + { + "teal": 934, + "source": 386, + "pc": [ + 1017 + ] + }, + { + "teal": 938, + "source": 386, + "pc": [ + 1018, + 1019, + 1020 + ] + }, + { + "teal": 942, + "source": 387, + "pc": [ + 1021, + 1022 + ] + }, + { + "teal": 943, + "source": 387, + "pc": [ + 1023 + ] + }, + { + "teal": 948, + "source": 396, + "pc": [ + 1024 + ] + }, + { + "teal": 951, + "source": 396, + "pc": [ + 1025, + 1026, + 1027 + ] + }, + { + "teal": 952, + "source": 396, + "pc": [ + 1028 + ] + }, + { + "teal": 953, + "source": 396, + "pc": [ + 1029 + ] + }, + { + "teal": 954, + "source": 396, + "pc": [ + 1030, + 1031 + ] + }, + { + "teal": 955, + "source": 396, + "pc": [ + 1032 + ] + }, + { + "teal": 956, + "source": 396, + "pc": [ + 1033 + ] + }, + { + "teal": 959, + "source": 396, + "pc": [ + 1034, + 1035, + 1036 + ] + }, + { + "teal": 960, + "source": 396, + "pc": [ + 1037, + 1038, + 1039 + ] + }, + { + "teal": 963, + "source": 396, + "pc": [ + 1040, + 1041 + ] + }, + { + "teal": 964, + "source": 396, + "pc": [ + 1042 + ] + }, + { + "teal": 965, + "source": 396, + "pc": [ + 1043 + ] + }, + { + "teal": 966, + "source": 396, + "pc": [ + 1044 + ] + }, + { + "teal": 967, + "source": 396, + "pc": [ + 1045, + 1046 + ] + }, + { + "teal": 968, + "source": 396, + "pc": [ + 1047 + ] + }, + { + "teal": 969, + "source": 396, + "pc": [ + 1048 + ] + }, + { + "teal": 970, + "source": 396, + "pc": [ + 1049 + ] + }, + { + "teal": 973, + "source": 396, + "pc": [ + 1050, + 1051, + 1052 + ] + }, + { + "teal": 974, + "source": 396, + "pc": [ + 1053 + ] + }, + { + "teal": 975, + "source": 396, + "pc": [ + 1054 + ] + }, + { + "teal": 976, + "source": 396, + "pc": [ + 1055 + ] + }, + { + "teal": 977, + "source": 396, + "pc": [ + 1056 + ] + }, + { + "teal": 978, + "source": 396, + "pc": [ + 1057 + ] + }, + { + "teal": 988, + "source": 396, + "pc": [ + 1058, + 1059, + 1060 + ] + }, + { + "teal": 991, + "source": 396, + "pc": [ + 1061 + ] + }, + { + "teal": 992, + "source": 396, + "pc": [ + 1062 + ] + }, + { + "teal": 996, + "source": 397, + "pc": [ + 1063, + 1064 + ] + }, + { + "teal": 997, + "source": 397, + "pc": [ + 1065, + 1066, + 1067 + ] + }, + { + "teal": 1001, + "source": 398, + "pc": [ + 1068, + 1069 + ] + }, + { + "teal": 1002, + "source": 398, + "pc": [ + 1070, + 1071, + 1072 + ] + }, + { + "teal": 1003, + "source": 398, + "pc": [ + 1073, + 1074 + ] + }, + { + "teal": 1004, + "source": 398, + "pc": [ + 1075 + ] + }, + { + "teal": 1005, + "source": 398, + "pc": [ + 1076 + ] + }, + { + "teal": 1009, + "source": 399, + "pc": [ + 1077, + 1078 + ] + }, + { + "teal": 1010, + "source": 399, + "pc": [ + 1079, + 1080, + 1081 + ] + }, + { + "teal": 1011, + "source": 399, + "pc": [ + 1082, + 1083 + ] + }, + { + "teal": 1012, + "source": 399, + "pc": [ + 1084 + ] + }, + { + "teal": 1013, + "source": 399, + "pc": [ + 1085 + ] + }, + { + "teal": 1017, + "source": 400, + "pc": [ + 1086, + 1087 + ] + }, + { + "teal": 1018, + "source": 400, + "pc": [ + 1088, + 1089 + ] + }, + { + "teal": 1019, + "source": 400, + "pc": [ + 1090, + 1091, + 1092 + ] + }, + { + "teal": 1020, + "source": 400, + "pc": [ + 1093 + ] + }, + { + "teal": 1023, + "source": 400, + "pc": [ + 1094 + ] + }, + { + "teal": 1028, + "source": 402, + "pc": [ + 1095, + 1096 + ] + }, + { + "teal": 1029, + "source": 402, + "pc": [ + 1097, + 1098 + ] + }, + { + "teal": 1030, + "source": 402, + "pc": [ + 1099, + 1100, + 1101 + ] + }, + { + "teal": 1031, + "source": 402, + "pc": [ + 1102, + 1103, + 1104 + ] + }, + { + "teal": 1032, + "source": 402, + "pc": [ + 1105 + ] + }, + { + "teal": 1033, + "source": 402, + "pc": [ + 1106 + ] + }, + { + "teal": 1034, + "source": 402, + "pc": [ + 1107 + ] + }, + { + "teal": 1038, + "source": 405, + "pc": [ + 1108, + 1109 + ] + }, + { + "teal": 1039, + "source": 405, + "pc": [ + 1110 + ] + }, + { + "teal": 1040, + "source": 405, + "pc": [ + 1111 + ] + }, + { + "teal": 1041, + "source": 405, + "pc": [ + 1112 + ] + }, + { + "teal": 1042, + "source": 405, + "pc": [ + 1113, + 1114 + ] + }, + { + "teal": 1046, + "source": 406, + "pc": [ + 1115, + 1116 + ] + }, + { + "teal": 1047, + "source": 406, + "pc": [ + 1117, + 1118 + ] + }, + { + "teal": 1048, + "source": 406, + "pc": [ + 1119 + ] + }, + { + "teal": 1052, + "source": 408, + "pc": [ + 1120 + ] + }, + { + "teal": 1053, + "source": 408, + "pc": [ + 1121, + 1122 + ] + }, + { + "teal": 1054, + "source": 408, + "pc": [ + 1123 + ] + }, + { + "teal": 1055, + "source": 408, + "pc": [ + 1124 + ] + }, + { + "teal": 1056, + "source": 408, + "pc": [ + 1125, + 1126, + 1127 + ] + }, + { + "teal": 1057, + "source": 408, + "pc": [ + 1128 + ] + }, + { + "teal": 1058, + "source": 408, + "pc": [ + 1129 + ] + }, + { + "teal": 1062, + "source": 409, + "pc": [ + 1130 + ] + }, + { + "teal": 1063, + "source": 409, + "pc": [ + 1131, + 1132 + ] + }, + { + "teal": 1064, + "source": 409, + "pc": [ + 1133 + ] + }, + { + "teal": 1065, + "source": 409, + "pc": [ + 1134, + 1135 + ] + }, + { + "teal": 1066, + "source": 409, + "pc": [ + 1136 + ] + }, + { + "teal": 1067, + "source": 409, + "pc": [ + 1137 + ] + }, + { + "teal": 1068, + "source": 409, + "pc": [ + 1138, + 1139 + ] + }, + { + "teal": 1069, + "source": 409, + "pc": [ + 1140 + ] + }, + { + "teal": 1073, + "source": 410, + "pc": [ + 1141 + ] + }, + { + "teal": 1074, + "source": 410, + "pc": [ + 1142, + 1143 + ] + }, + { + "teal": 1075, + "source": 410, + "pc": [ + 1144 + ] + }, + { + "teal": 1076, + "source": 410, + "pc": [ + 1145 + ] + }, + { + "teal": 1077, + "source": 410, + "pc": [ + 1146, + 1147 + ] + }, + { + "teal": 1078, + "source": 410, + "pc": [ + 1148 + ] + }, + { + "teal": 1079, + "source": 410, + "pc": [ + 1149 + ] + }, + { + "teal": 1080, + "source": 410, + "pc": [ + 1150, + 1151 + ] + }, + { + "teal": 1081, + "source": 410, + "pc": [ + 1152 + ] + }, + { + "teal": 1086, + "source": 413, + "pc": [ + 1153, + 1154 + ] + }, + { + "teal": 1087, + "source": 413, + "pc": [ + 1155, + 1156, + 1157 + ] + }, + { + "teal": 1088, + "source": 413, + "pc": [ + 1158 + ] + }, + { + "teal": 1089, + "source": 413, + "pc": [ + 1159 + ] + }, + { + "teal": 1090, + "source": 413, + "pc": [ + 1160 + ] + }, + { + "teal": 1091, + "source": 413, + "pc": [ + 1161, + 1162, + 1163 + ] + }, + { + "teal": 1100, + "source": 415, + "pc": [ + 1164 + ] + }, + { + "teal": 1101, + "source": 415, + "pc": [ + 1165, + 1166 + ] + }, + { + "teal": 1102, + "source": 415, + "pc": [ + 1167, + 1168 + ] + }, + { + "teal": 1106, + "source": 416, + "pc": [ + 1169, + 1170 + ] + }, + { + "teal": 1107, + "source": 416, + "pc": [ + 1171, + 1172 + ] + }, + { + "teal": 1111, + "source": 417, + "pc": [ + 1173, + 1174 + ] + }, + { + "teal": 1112, + "source": 417, + "pc": [ + 1175, + 1176 + ] + }, + { + "teal": 1113, + "source": 417, + "pc": [ + 1177, + 1178 + ] + }, + { + "teal": 1114, + "source": 417, + "pc": [ + 1179, + 1180 + ] + }, + { + "teal": 1115, + "source": 417, + "pc": [ + 1181, + 1182 + ] + }, + { + "teal": 1116, + "source": 417, + "pc": [ + 1183, + 1184, + 1185 + ] + }, + { + "teal": 1117, + "source": 417, + "pc": [ + 1186 + ] + }, + { + "teal": 1118, + "source": 417, + "pc": [ + 1187 + ] + }, + { + "teal": 1119, + "source": 417, + "pc": [ + 1188, + 1189 + ] + }, + { + "teal": 1123, + "source": 418, + "pc": [ + 1190, + 1191 + ] + }, + { + "teal": 1124, + "source": 418, + "pc": [ + 1192, + 1193, + 1194 + ] + }, + { + "teal": 1125, + "source": 418, + "pc": [ + 1195 + ] + }, + { + "teal": 1126, + "source": 418, + "pc": [ + 1196, + 1197 + ] + }, + { + "teal": 1129, + "source": 415, + "pc": [ + 1198 + ] + }, + { + "teal": 1130, + "source": 415, + "pc": [ + 1199, + 1200 + ] + }, + { + "teal": 1133, + "source": 415, + "pc": [ + 1201 + ] + }, + { + "teal": 1137, + "source": 420, + "pc": [ + 1202, + 1203 + ] + }, + { + "teal": 1138, + "source": 420, + "pc": [ + 1204 + ] + }, + { + "teal": 1139, + "source": 420, + "pc": [ + 1205 + ] + }, + { + "teal": 1140, + "source": 420, + "pc": [ + 1206 + ] + }, + { + "teal": 1143, + "source": 420, + "pc": [ + 1207 + ] + }, + { + "teal": 1150, + "source": 423, + "pc": [ + 1208, + 1209 + ] + }, + { + "teal": 1151, + "source": 423, + "pc": [ + 1210, + 1211 + ] + }, + { + "teal": 1152, + "source": 423, + "pc": [ + 1212, + 1213, + 1214 + ] + }, + { + "teal": 1153, + "source": 423, + "pc": [ + 1215 + ] + }, + { + "teal": 1154, + "source": 423, + "pc": [ + 1216, + 1217 + ] + }, + { + "teal": 1155, + "source": 423, + "pc": [ + 1218 + ] + }, + { + "teal": 1156, + "source": 423, + "pc": [ + 1219 + ] + }, + { + "teal": 1157, + "source": 423, + "pc": [ + 1220 + ] + }, + { + "teal": 1160, + "source": 422, + "pc": [ + 1221 + ] + }, + { + "teal": 1166, + "source": 427, + "pc": [ + 1222, + 1223 + ] + }, + { + "teal": 1167, + "source": 427, + "pc": [ + 1224, + 1225, + 1226 + ] + }, + { + "teal": 1168, + "source": 427, + "pc": [ + 1227 + ] + }, + { + "teal": 1169, + "source": 427, + "pc": [ + 1228, + 1229 + ] + }, + { + "teal": 1170, + "source": 427, + "pc": [ + 1230 + ] + }, + { + "teal": 1171, + "source": 427, + "pc": [ + 1231, + 1232, + 1233 + ] + }, + { + "teal": 1176, + "source": 429, + "pc": [ + 1234, + 1235 + ] + }, + { + "teal": 1177, + "source": 429, + "pc": [ + 1236, + 1237, + 1238 + ] + }, + { + "teal": 1178, + "source": 429, + "pc": [ + 1239 + ] + }, + { + "teal": 1179, + "source": 429, + "pc": [ + 1240 + ] + }, + { + "teal": 1180, + "source": 429, + "pc": [ + 1241 + ] + }, + { + "teal": 1183, + "source": 429, + "pc": [ + 1242 + ] + }, + { + "teal": 1189, + "source": 431, + "pc": [ + 1243, + 1244 + ] + }, + { + "teal": 1190, + "source": 431, + "pc": [ + 1245, + 1246, + 1247 + ] + }, + { + "teal": 1191, + "source": 431, + "pc": [ + 1248 + ] + }, + { + "teal": 1192, + "source": 431, + "pc": [ + 1249, + 1250 + ] + }, + { + "teal": 1193, + "source": 431, + "pc": [ + 1251 + ] + }, + { + "teal": 1194, + "source": 431, + "pc": [ + 1252, + 1253, + 1254 + ] + }, + { + "teal": 1199, + "source": 433, + "pc": [ + 1255, + 1256 + ] + }, + { + "teal": 1200, + "source": 433, + "pc": [ + 1257, + 1258, + 1259 + ] + }, + { + "teal": 1201, + "source": 433, + "pc": [ + 1260 + ] + }, + { + "teal": 1202, + "source": 433, + "pc": [ + 1261 + ] + }, + { + "teal": 1203, + "source": 433, + "pc": [ + 1262, + 1263 + ] + }, + { + "teal": 1207, + "source": 434, + "pc": [ + 1264, + 1265 + ] + }, + { + "teal": 1208, + "source": 434, + "pc": [ + 1266, + 1267, + 1268 + ] + }, + { + "teal": 1211, + "source": 434, + "pc": [ + 1269 + ] + }, + { + "teal": 1216, + "source": 437, + "pc": [ + 1270, + 1271 + ] + }, + { + "teal": 1219, + "source": 437, + "pc": [ + 1272, + 1273 + ] + }, + { + "teal": 1222, + "source": 437, + "pc": [ + 1274, + 1275 + ] + }, + { + "teal": 1223, + "source": 437, + "pc": [ + 1276 + ] + }, + { + "teal": 1228, + "source": 447, + "pc": [ + 1277, + 1278, + 1279 + ] + }, + { + "teal": 1229, + "source": 447, + "pc": [ + 1280 + ] + }, + { + "teal": 1230, + "source": 447, + "pc": [ + 1281 + ] + }, + { + "teal": 1231, + "source": 447, + "pc": [ + 1282, + 1283 + ] + }, + { + "teal": 1232, + "source": 447, + "pc": [ + 1284 + ] + }, + { + "teal": 1233, + "source": 447, + "pc": [ + 1285 + ] + }, + { + "teal": 1236, + "source": 447, + "pc": [ + 1286, + 1287, + 1288 + ] + }, + { + "teal": 1237, + "source": 447, + "pc": [ + 1289 + ] + }, + { + "teal": 1240, + "source": 447, + "pc": [ + 1290, + 1291, + 1292 + ] + }, + { + "teal": 1241, + "source": 447, + "pc": [ + 1293 + ] + }, + { + "teal": 1242, + "source": 447, + "pc": [ + 1294 + ] + }, + { + "teal": 1252, + "source": 447, + "pc": [ + 1295, + 1296, + 1297 + ] + }, + { + "teal": 1256, + "source": 448, + "pc": [ + 1298, + 1299 + ] + }, + { + "teal": 1257, + "source": 448, + "pc": [ + 1300 + ] + }, + { + "teal": 1258, + "source": 448, + "pc": [ + 1301, + 1302 + ] + }, + { + "teal": 1259, + "source": 448, + "pc": [ + 1303 + ] + }, + { + "teal": 1260, + "source": 448, + "pc": [ + 1304, + 1305 + ] + }, + { + "teal": 1261, + "source": 448, + "pc": [ + 1306 + ] + }, + { + "teal": 1262, + "source": 448, + "pc": [ + 1307 + ] + }, + { + "teal": 1263, + "source": 448, + "pc": [ + 1308, + 1309 + ] + }, + { + "teal": 1264, + "source": 448, + "pc": [ + 1310 + ] + }, + { + "teal": 1265, + "source": 448, + "pc": [ + 1311 + ] + }, + { + "teal": 1266, + "source": 448, + "pc": [ + 1312 + ] + }, + { + "teal": 1270, + "source": 449, + "pc": [ + 1313, + 1314 + ] + }, + { + "teal": 1271, + "source": 449, + "pc": [ + 1315, + 1316 + ] + }, + { + "teal": 1272, + "source": 449, + "pc": [ + 1317 + ] + }, + { + "teal": 1273, + "source": 449, + "pc": [ + 1318, + 1319 + ] + }, + { + "teal": 1274, + "source": 449, + "pc": [ + 1320 + ] + }, + { + "teal": 1275, + "source": 449, + "pc": [ + 1321 + ] + }, + { + "teal": 1276, + "source": 449, + "pc": [ + 1322, + 1323 + ] + }, + { + "teal": 1277, + "source": 449, + "pc": [ + 1324 + ] + }, + { + "teal": 1278, + "source": 447, + "pc": [ + 1325 + ] + }, + { + "teal": 1283, + "source": 460, + "pc": [ + 1326, + 1327, + 1328 + ] + }, + { + "teal": 1284, + "source": 460, + "pc": [ + 1329 + ] + }, + { + "teal": 1287, + "source": 460, + "pc": [ + 1330, + 1331, + 1332 + ] + }, + { + "teal": 1288, + "source": 460, + "pc": [ + 1333 + ] + }, + { + "teal": 1291, + "source": 460, + "pc": [ + 1334, + 1335, + 1336 + ] + }, + { + "teal": 1292, + "source": 460, + "pc": [ + 1337 + ] + }, + { + "teal": 1295, + "source": 460, + "pc": [ + 1338, + 1339, + 1340 + ] + }, + { + "teal": 1296, + "source": 460, + "pc": [ + 1341 + ] + }, + { + "teal": 1297, + "source": 460, + "pc": [ + 1342 + ] + }, + { + "teal": 1308, + "source": 460, + "pc": [ + 1343, + 1344, + 1345 + ] + }, + { + "teal": 1312, + "source": 461, + "pc": [ + 1346, + 1347 + ] + }, + { + "teal": 1313, + "source": 461, + "pc": [ + 1348 + ] + }, + { + "teal": 1314, + "source": 461, + "pc": [ + 1349, + 1350 + ] + }, + { + "teal": 1315, + "source": 461, + "pc": [ + 1351 + ] + }, + { + "teal": 1316, + "source": 461, + "pc": [ + 1352, + 1353 + ] + }, + { + "teal": 1317, + "source": 461, + "pc": [ + 1354 + ] + }, + { + "teal": 1318, + "source": 461, + "pc": [ + 1355 + ] + }, + { + "teal": 1319, + "source": 461, + "pc": [ + 1356, + 1357 + ] + }, + { + "teal": 1320, + "source": 461, + "pc": [ + 1358 + ] + }, + { + "teal": 1321, + "source": 461, + "pc": [ + 1359 + ] + }, + { + "teal": 1322, + "source": 461, + "pc": [ + 1360 + ] + }, + { + "teal": 1326, + "source": 462, + "pc": [ + 1361, + 1362 + ] + }, + { + "teal": 1327, + "source": 462, + "pc": [ + 1363, + 1364 + ] + }, + { + "teal": 1328, + "source": 462, + "pc": [ + 1365 + ] + }, + { + "teal": 1329, + "source": 462, + "pc": [ + 1366 + ] + }, + { + "teal": 1330, + "source": 462, + "pc": [ + 1367, + 1368 + ] + }, + { + "teal": 1331, + "source": 462, + "pc": [ + 1369 + ] + }, + { + "teal": 1332, + "source": 462, + "pc": [ + 1370 + ] + }, + { + "teal": 1333, + "source": 462, + "pc": [ + 1371, + 1372 + ] + }, + { + "teal": 1334, + "source": 462, + "pc": [ + 1373 + ] + }, + { + "teal": 1338, + "source": 463, + "pc": [ + 1374, + 1375 + ] + }, + { + "teal": 1339, + "source": 463, + "pc": [ + 1376, + 1377 + ] + }, + { + "teal": 1340, + "source": 463, + "pc": [ + 1378 + ] + }, + { + "teal": 1341, + "source": 463, + "pc": [ + 1379 + ] + }, + { + "teal": 1342, + "source": 463, + "pc": [ + 1380, + 1381 + ] + }, + { + "teal": 1343, + "source": 463, + "pc": [ + 1382 + ] + }, + { + "teal": 1344, + "source": 463, + "pc": [ + 1383 + ] + }, + { + "teal": 1345, + "source": 463, + "pc": [ + 1384, + 1385 + ] + }, + { + "teal": 1346, + "source": 463, + "pc": [ + 1386 + ] + }, + { + "teal": 1347, + "source": 460, + "pc": [ + 1387 + ] + }, + { + "teal": 1352, + "source": 474, + "pc": [ + 1388, + 1389, + 1390 + ] + }, + { + "teal": 1353, + "source": 474, + "pc": [ + 1391, + 1392, + 1393 + ] + }, + { + "teal": 1356, + "source": 474, + "pc": [ + 1394, + 1395, + 1396 + ] + }, + { + "teal": 1357, + "source": 474, + "pc": [ + 1397 + ] + }, + { + "teal": 1360, + "source": 474, + "pc": [ + 1398, + 1399, + 1400 + ] + }, + { + "teal": 1361, + "source": 474, + "pc": [ + 1401 + ] + }, + { + "teal": 1364, + "source": 474, + "pc": [ + 1402, + 1403, + 1404 + ] + }, + { + "teal": 1365, + "source": 474, + "pc": [ + 1405 + ] + }, + { + "teal": 1366, + "source": 474, + "pc": [ + 1406 + ] + }, + { + "teal": 1377, + "source": 474, + "pc": [ + 1407, + 1408, + 1409 + ] + }, + { + "teal": 1384, + "source": 477, + "pc": [ + 1410, + 1411 + ] + }, + { + "teal": 1385, + "source": 477, + "pc": [ + 1412 + ] + }, + { + "teal": 1386, + "source": 477, + "pc": [ + 1413, + 1414 + ] + }, + { + "teal": 1387, + "source": 477, + "pc": [ + 1415 + ] + }, + { + "teal": 1388, + "source": 477, + "pc": [ + 1416, + 1417 + ] + }, + { + "teal": 1389, + "source": 477, + "pc": [ + 1418 + ] + }, + { + "teal": 1390, + "source": 477, + "pc": [ + 1419 + ] + }, + { + "teal": 1391, + "source": 477, + "pc": [ + 1420, + 1421 + ] + }, + { + "teal": 1392, + "source": 477, + "pc": [ + 1422 + ] + }, + { + "teal": 1393, + "source": 477, + "pc": [ + 1423 + ] + }, + { + "teal": 1394, + "source": 477, + "pc": [ + 1424 + ] + }, + { + "teal": 1395, + "source": 477, + "pc": [ + 1425, + 1426, + 1427 + ] + }, + { + "teal": 1396, + "source": 478, + "pc": [ + 1428, + 1429 + ] + }, + { + "teal": 1397, + "source": 478, + "pc": [ + 1430, + 1431 + ] + }, + { + "teal": 1398, + "source": 478, + "pc": [ + 1432, + 1433 + ] + }, + { + "teal": 1399, + "source": 478, + "pc": [ + 1434 + ] + }, + { + "teal": 1400, + "source": 478, + "pc": [ + 1435, + 1436 + ] + }, + { + "teal": 1401, + "source": 478, + "pc": [ + 1437 + ] + }, + { + "teal": 1402, + "source": 478, + "pc": [ + 1438 + ] + }, + { + "teal": 1403, + "source": 478, + "pc": [ + 1439, + 1440 + ] + }, + { + "teal": 1404, + "source": 478, + "pc": [ + 1441 + ] + }, + { + "teal": 1405, + "source": 478, + "pc": [ + 1442 + ] + }, + { + "teal": 1406, + "source": 477, + "pc": [ + 1443 + ] + }, + { + "teal": 1409, + "source": 476, + "pc": [ + 1444 + ] + }, + { + "teal": 1417, + "source": 481, + "pc": [ + 1445 + ] + }, + { + "teal": 1418, + "source": 481, + "pc": [ + 1446, + 1447 + ] + }, + { + "teal": 1419, + "source": 481, + "pc": [ + 1448, + 1449 + ] + }, + { + "teal": 1423, + "source": 482, + "pc": [ + 1450, + 1451 + ] + }, + { + "teal": 1424, + "source": 482, + "pc": [ + 1452, + 1453 + ] + }, + { + "teal": 1428, + "source": 483, + "pc": [ + 1454, + 1455 + ] + }, + { + "teal": 1429, + "source": 483, + "pc": [ + 1456, + 1457 + ] + }, + { + "teal": 1430, + "source": 483, + "pc": [ + 1458, + 1459 + ] + }, + { + "teal": 1431, + "source": 483, + "pc": [ + 1460, + 1461 + ] + }, + { + "teal": 1432, + "source": 483, + "pc": [ + 1462, + 1463 + ] + }, + { + "teal": 1433, + "source": 483, + "pc": [ + 1464 + ] + }, + { + "teal": 1434, + "source": 483, + "pc": [ + 1465, + 1466 + ] + }, + { + "teal": 1438, + "source": 484, + "pc": [ + 1467, + 1468 + ] + }, + { + "teal": 1439, + "source": 484, + "pc": [ + 1469, + 1470 + ] + }, + { + "teal": 1442, + "source": 481, + "pc": [ + 1471 + ] + }, + { + "teal": 1443, + "source": 481, + "pc": [ + 1472, + 1473 + ] + }, + { + "teal": 1446, + "source": 481, + "pc": [ + 1474 + ] + }, + { + "teal": 1453, + "source": 488, + "pc": [ + 1475, + 1476 + ] + }, + { + "teal": 1454, + "source": 488, + "pc": [ + 1477, + 1478 + ] + }, + { + "teal": 1455, + "source": 488, + "pc": [ + 1479, + 1480 + ] + }, + { + "teal": 1456, + "source": 488, + "pc": [ + 1481 + ] + }, + { + "teal": 1457, + "source": 488, + "pc": [ + 1482 + ] + }, + { + "teal": 1458, + "source": 488, + "pc": [ + 1483 + ] + }, + { + "teal": 1461, + "source": 487, + "pc": [ + 1484 + ] + }, + { + "teal": 1465, + "source": 491, + "pc": [ + 1485, + 1486 + ] + }, + { + "teal": 1466, + "source": 491, + "pc": [ + 1487, + 1488 + ] + }, + { + "teal": 1467, + "source": 491, + "pc": [ + 1489 + ] + }, + { + "teal": 1468, + "source": 491, + "pc": [ + 1490 + ] + }, + { + "teal": 1469, + "source": 491, + "pc": [ + 1491, + 1492 + ] + }, + { + "teal": 1470, + "source": 491, + "pc": [ + 1493 + ] + }, + { + "teal": 1471, + "source": 491, + "pc": [ + 1494 + ] + }, + { + "teal": 1472, + "source": 491, + "pc": [ + 1495, + 1496 + ] + }, + { + "teal": 1473, + "source": 491, + "pc": [ + 1497 + ] + }, + { + "teal": 1474, + "source": 474, + "pc": [ + 1498 + ] + }, + { + "teal": 1479, + "source": 498, + "pc": [ + 1499, + 1500, + 1501 + ] + }, + { + "teal": 1480, + "source": 498, + "pc": [ + 1502 + ] + }, + { + "teal": 1481, + "source": 498, + "pc": [ + 1503 + ] + }, + { + "teal": 1482, + "source": 498, + "pc": [ + 1504, + 1505 + ] + }, + { + "teal": 1483, + "source": 498, + "pc": [ + 1506 + ] + }, + { + "teal": 1484, + "source": 498, + "pc": [ + 1507 + ] + }, + { + "teal": 1487, + "source": 498, + "pc": [ + 1508, + 1509, + 1510 + ] + }, + { + "teal": 1488, + "source": 498, + "pc": [ + 1511 + ] + }, + { + "teal": 1491, + "source": 498, + "pc": [ + 1512, + 1513, + 1514 + ] + }, + { + "teal": 1492, + "source": 498, + "pc": [ + 1515 + ] + }, + { + "teal": 1493, + "source": 498, + "pc": [ + 1516 + ] + }, + { + "teal": 1500, + "source": 498, + "pc": [ + 1517, + 1518, + 1519 + ] + }, + { + "teal": 1504, + "source": 499, + "pc": [ + 1520, + 1521 + ] + }, + { + "teal": 1505, + "source": 499, + "pc": [ + 1522 + ] + }, + { + "teal": 1506, + "source": 499, + "pc": [ + 1523, + 1524 + ] + }, + { + "teal": 1507, + "source": 499, + "pc": [ + 1525 + ] + }, + { + "teal": 1508, + "source": 499, + "pc": [ + 1526, + 1527 + ] + }, + { + "teal": 1509, + "source": 499, + "pc": [ + 1528 + ] + }, + { + "teal": 1510, + "source": 499, + "pc": [ + 1529 + ] + }, + { + "teal": 1511, + "source": 499, + "pc": [ + 1530, + 1531 + ] + }, + { + "teal": 1512, + "source": 499, + "pc": [ + 1532 + ] + }, + { + "teal": 1513, + "source": 499, + "pc": [ + 1533 + ] + }, + { + "teal": 1514, + "source": 499, + "pc": [ + 1534 + ] + }, + { + "teal": 1518, + "source": 500, + "pc": [ + 1535, + 1536 + ] + }, + { + "teal": 1519, + "source": 500, + "pc": [ + 1537, + 1538 + ] + }, + { + "teal": 1520, + "source": 500, + "pc": [ + 1539 + ] + }, + { + "teal": 1521, + "source": 500, + "pc": [ + 1540 + ] + }, + { + "teal": 1525, + "source": 501, + "pc": [ + 1541, + 1542, + 1543 + ] + }, + { + "teal": 1526, + "source": 501, + "pc": [ + 1544, + 1545 + ] + }, + { + "teal": 1527, + "source": 501, + "pc": [ + 1546 + ] + }, + { + "teal": 1528, + "source": 501, + "pc": [ + 1547, + 1548 + ] + }, + { + "teal": 1529, + "source": 501, + "pc": [ + 1549 + ] + }, + { + "teal": 1530, + "source": 501, + "pc": [ + 1550 + ] + }, + { + "teal": 1531, + "source": 501, + "pc": [ + 1551, + 1552 + ] + }, + { + "teal": 1532, + "source": 501, + "pc": [ + 1553 + ] + }, + { + "teal": 1533, + "source": 498, + "pc": [ + 1554 + ] + }, + { + "teal": 1538, + "source": 513, + "pc": [ + 1555, + 1556, + 1557 + ] + }, + { + "teal": 1539, + "source": 513, + "pc": [ + 1558 + ] + }, + { + "teal": 1542, + "source": 512, + "pc": [ + 1559, + 1560, + 1561 + ] + }, + { + "teal": 1543, + "source": 512, + "pc": [ + 1562 + ] + }, + { + "teal": 1546, + "source": 511, + "pc": [ + 1563, + 1564, + 1565 + ] + }, + { + "teal": 1547, + "source": 511, + "pc": [ + 1566 + ] + }, + { + "teal": 1548, + "source": 511, + "pc": [ + 1567 + ] + }, + { + "teal": 1549, + "source": 511, + "pc": [ + 1568, + 1569 + ] + }, + { + "teal": 1550, + "source": 511, + "pc": [ + 1570 + ] + }, + { + "teal": 1551, + "source": 511, + "pc": [ + 1571 + ] + }, + { + "teal": 1554, + "source": 510, + "pc": [ + 1572, + 1573, + 1574 + ] + }, + { + "teal": 1555, + "source": 510, + "pc": [ + 1575 + ] + }, + { + "teal": 1556, + "source": 510, + "pc": [ + 1576 + ] + }, + { + "teal": 1557, + "source": 510, + "pc": [ + 1577 + ] + }, + { + "teal": 1558, + "source": 510, + "pc": [ + 1578 + ] + }, + { + "teal": 1559, + "source": 510, + "pc": [ + 1579 + ] + }, + { + "teal": 1560, + "source": 510, + "pc": [ + 1580 + ] + }, + { + "teal": 1563, + "source": 509, + "pc": [ + 1581, + 1582, + 1583 + ] + }, + { + "teal": 1564, + "source": 509, + "pc": [ + 1584 + ] + }, + { + "teal": 1567, + "source": 508, + "pc": [ + 1585, + 1586, + 1587 + ] + }, + { + "teal": 1568, + "source": 508, + "pc": [ + 1588 + ] + }, + { + "teal": 1569, + "source": 508, + "pc": [ + 1589 + ] + }, + { + "teal": 1576, + "source": 508, + "pc": [ + 1590, + 1591, + 1592 + ] + }, + { + "teal": 1580, + "source": 515, + "pc": [ + 1593, + 1594 + ] + }, + { + "teal": 1581, + "source": 515, + "pc": [ + 1595 + ] + }, + { + "teal": 1582, + "source": 515, + "pc": [ + 1596, + 1597 + ] + }, + { + "teal": 1583, + "source": 515, + "pc": [ + 1598 + ] + }, + { + "teal": 1584, + "source": 515, + "pc": [ + 1599, + 1600 + ] + }, + { + "teal": 1585, + "source": 515, + "pc": [ + 1601 + ] + }, + { + "teal": 1586, + "source": 515, + "pc": [ + 1602 + ] + }, + { + "teal": 1587, + "source": 515, + "pc": [ + 1603, + 1604 + ] + }, + { + "teal": 1588, + "source": 515, + "pc": [ + 1605 + ] + }, + { + "teal": 1589, + "source": 515, + "pc": [ + 1606 + ] + }, + { + "teal": 1590, + "source": 515, + "pc": [ + 1607 + ] + }, + { + "teal": 1594, + "source": 517, + "pc": [ + 1608, + 1609 + ] + }, + { + "teal": 1595, + "source": 517, + "pc": [ + 1610, + 1611 + ] + }, + { + "teal": 1596, + "source": 517, + "pc": [ + 1612 + ] + }, + { + "teal": 1597, + "source": 517, + "pc": [ + 1613, + 1614, + 1615 + ] + }, + { + "teal": 1598, + "source": 517, + "pc": [ + 1616 + ] + }, + { + "teal": 1599, + "source": 517, + "pc": [ + 1617, + 1618 + ] + }, + { + "teal": 1600, + "source": 517, + "pc": [ + 1619 + ] + }, + { + "teal": 1601, + "source": 517, + "pc": [ + 1620 + ] + }, + { + "teal": 1602, + "source": 517, + "pc": [ + 1621, + 1622 + ] + }, + { + "teal": 1603, + "source": 517, + "pc": [ + 1623 + ] + }, + { + "teal": 1607, + "source": 518, + "pc": [ + 1624, + 1625 + ] + }, + { + "teal": 1608, + "source": 518, + "pc": [ + 1626, + 1627 + ] + }, + { + "teal": 1609, + "source": 518, + "pc": [ + 1628 + ] + }, + { + "teal": 1610, + "source": 518, + "pc": [ + 1629, + 1630 + ] + }, + { + "teal": 1611, + "source": 518, + "pc": [ + 1631 + ] + }, + { + "teal": 1612, + "source": 518, + "pc": [ + 1632 + ] + }, + { + "teal": 1613, + "source": 518, + "pc": [ + 1633, + 1634 + ] + }, + { + "teal": 1614, + "source": 518, + "pc": [ + 1635 + ] + }, + { + "teal": 1618, + "source": 519, + "pc": [ + 1636, + 1637 + ] + }, + { + "teal": 1619, + "source": 519, + "pc": [ + 1638, + 1639 + ] + }, + { + "teal": 1620, + "source": 519, + "pc": [ + 1640 + ] + }, + { + "teal": 1621, + "source": 519, + "pc": [ + 1641 + ] + }, + { + "teal": 1622, + "source": 519, + "pc": [ + 1642, + 1643 + ] + }, + { + "teal": 1623, + "source": 519, + "pc": [ + 1644 + ] + }, + { + "teal": 1624, + "source": 519, + "pc": [ + 1645 + ] + }, + { + "teal": 1625, + "source": 519, + "pc": [ + 1646, + 1647 + ] + }, + { + "teal": 1626, + "source": 519, + "pc": [ + 1648 + ] + }, + { + "teal": 1630, + "source": 520, + "pc": [ + 1649, + 1650, + 1651 + ] + }, + { + "teal": 1631, + "source": 520, + "pc": [ + 1652, + 1653 + ] + }, + { + "teal": 1632, + "source": 520, + "pc": [ + 1654 + ] + }, + { + "teal": 1633, + "source": 520, + "pc": [ + 1655 + ] + }, + { + "teal": 1634, + "source": 520, + "pc": [ + 1656, + 1657 + ] + }, + { + "teal": 1635, + "source": 520, + "pc": [ + 1658 + ] + }, + { + "teal": 1636, + "source": 520, + "pc": [ + 1659 + ] + }, + { + "teal": 1637, + "source": 520, + "pc": [ + 1660, + 1661 + ] + }, + { + "teal": 1638, + "source": 520, + "pc": [ + 1662 + ] + }, + { + "teal": 1639, + "source": 508, + "pc": [ + 1663 + ] + }, + { + "teal": 1644, + "source": 534, + "pc": [ + 1664 + ] + }, + { + "teal": 1647, + "source": 534, + "pc": [ + 1665, + 1666, + 1667 + ] + }, + { + "teal": 1648, + "source": 534, + "pc": [ + 1668 + ] + }, + { + "teal": 1651, + "source": 534, + "pc": [ + 1669, + 1670, + 1671 + ] + }, + { + "teal": 1652, + "source": 534, + "pc": [ + 1672 + ] + }, + { + "teal": 1655, + "source": 534, + "pc": [ + 1673, + 1674 + ] + }, + { + "teal": 1656, + "source": 534, + "pc": [ + 1675 + ] + }, + { + "teal": 1657, + "source": 534, + "pc": [ + 1676 + ] + }, + { + "teal": 1658, + "source": 534, + "pc": [ + 1677 + ] + }, + { + "teal": 1659, + "source": 534, + "pc": [ + 1678, + 1679 + ] + }, + { + "teal": 1660, + "source": 534, + "pc": [ + 1680 + ] + }, + { + "teal": 1661, + "source": 534, + "pc": [ + 1681 + ] + }, + { + "teal": 1662, + "source": 534, + "pc": [ + 1682 + ] + }, + { + "teal": 1665, + "source": 534, + "pc": [ + 1683, + 1684, + 1685 + ] + }, + { + "teal": 1666, + "source": 534, + "pc": [ + 1686 + ] + }, + { + "teal": 1667, + "source": 534, + "pc": [ + 1687 + ] + }, + { + "teal": 1668, + "source": 534, + "pc": [ + 1688 + ] + }, + { + "teal": 1669, + "source": 534, + "pc": [ + 1689 + ] + }, + { + "teal": 1682, + "source": 534, + "pc": [ + 1690, + 1691, + 1692 + ] + }, + { + "teal": 1685, + "source": 534, + "pc": [ + 1693 + ] + }, + { + "teal": 1686, + "source": 534, + "pc": [ + 1694 + ] + }, + { + "teal": 1693, + "source": 537, + "pc": [ + 1695, + 1696 + ] + }, + { + "teal": 1694, + "source": 537, + "pc": [ + 1697 + ] + }, + { + "teal": 1695, + "source": 537, + "pc": [ + 1698, + 1699 + ] + }, + { + "teal": 1696, + "source": 537, + "pc": [ + 1700 + ] + }, + { + "teal": 1697, + "source": 537, + "pc": [ + 1701, + 1702 + ] + }, + { + "teal": 1698, + "source": 537, + "pc": [ + 1703 + ] + }, + { + "teal": 1699, + "source": 537, + "pc": [ + 1704 + ] + }, + { + "teal": 1700, + "source": 537, + "pc": [ + 1705, + 1706 + ] + }, + { + "teal": 1701, + "source": 537, + "pc": [ + 1707 + ] + }, + { + "teal": 1702, + "source": 537, + "pc": [ + 1708 + ] + }, + { + "teal": 1703, + "source": 537, + "pc": [ + 1709 + ] + }, + { + "teal": 1704, + "source": 537, + "pc": [ + 1710, + 1711, + 1712 + ] + }, + { + "teal": 1705, + "source": 538, + "pc": [ + 1713, + 1714 + ] + }, + { + "teal": 1706, + "source": 538, + "pc": [ + 1715, + 1716 + ] + }, + { + "teal": 1707, + "source": 538, + "pc": [ + 1717, + 1718 + ] + }, + { + "teal": 1708, + "source": 538, + "pc": [ + 1719 + ] + }, + { + "teal": 1709, + "source": 538, + "pc": [ + 1720, + 1721 + ] + }, + { + "teal": 1710, + "source": 538, + "pc": [ + 1722 + ] + }, + { + "teal": 1711, + "source": 538, + "pc": [ + 1723 + ] + }, + { + "teal": 1712, + "source": 538, + "pc": [ + 1724, + 1725 + ] + }, + { + "teal": 1713, + "source": 538, + "pc": [ + 1726 + ] + }, + { + "teal": 1714, + "source": 538, + "pc": [ + 1727 + ] + }, + { + "teal": 1715, + "source": 537, + "pc": [ + 1728 + ] + }, + { + "teal": 1718, + "source": 536, + "pc": [ + 1729 + ] + }, + { + "teal": 1723, + "source": 542, + "pc": [ + 1730, + 1731 + ] + }, + { + "teal": 1724, + "source": 542, + "pc": [ + 1732, + 1733 + ] + }, + { + "teal": 1725, + "source": 542, + "pc": [ + 1734, + 1735, + 1736 + ] + }, + { + "teal": 1726, + "source": 542, + "pc": [ + 1737, + 1738, + 1739 + ] + }, + { + "teal": 1727, + "source": 542, + "pc": [ + 1740 + ] + }, + { + "teal": 1728, + "source": 542, + "pc": [ + 1741 + ] + }, + { + "teal": 1729, + "source": 542, + "pc": [ + 1742 + ] + }, + { + "teal": 1732, + "source": 542, + "pc": [ + 1743, + 1744 + ] + }, + { + "teal": 1733, + "source": 542, + "pc": [ + 1745, + 1746 + ] + }, + { + "teal": 1734, + "source": 542, + "pc": [ + 1747, + 1748 + ] + }, + { + "teal": 1735, + "source": 542, + "pc": [ + 1749 + ] + }, + { + "teal": 1736, + "source": 542, + "pc": [ + 1750 + ] + }, + { + "teal": 1740, + "source": 544, + "pc": [ + 1751 + ] + }, + { + "teal": 1741, + "source": 544, + "pc": [ + 1752, + 1753 + ] + }, + { + "teal": 1742, + "source": 544, + "pc": [ + 1754 + ] + }, + { + "teal": 1743, + "source": 544, + "pc": [ + 1755 + ] + }, + { + "teal": 1744, + "source": 544, + "pc": [ + 1756 + ] + }, + { + "teal": 1745, + "source": 544, + "pc": [ + 1757 + ] + }, + { + "teal": 1746, + "source": 544, + "pc": [ + 1758 + ] + }, + { + "teal": 1747, + "source": 544, + "pc": [ + 1759 + ] + }, + { + "teal": 1751, + "source": 546, + "pc": [ + 1760, + 1761 + ] + }, + { + "teal": 1752, + "source": 546, + "pc": [ + 1762, + 1763 + ] + }, + { + "teal": 1753, + "source": 546, + "pc": [ + 1764 + ] + }, + { + "teal": 1754, + "source": 546, + "pc": [ + 1765, + 1766 + ] + }, + { + "teal": 1755, + "source": 546, + "pc": [ + 1767 + ] + }, + { + "teal": 1756, + "source": 546, + "pc": [ + 1768 + ] + }, + { + "teal": 1757, + "source": 546, + "pc": [ + 1769, + 1770 + ] + }, + { + "teal": 1758, + "source": 546, + "pc": [ + 1771 + ] + }, + { + "teal": 1759, + "source": 546, + "pc": [ + 1772 + ] + }, + { + "teal": 1760, + "source": 546, + "pc": [ + 1773, + 1774 + ] + }, + { + "teal": 1765, + "source": 547, + "pc": [ + 1775, + 1776 + ] + }, + { + "teal": 1766, + "source": 28, + "pc": [ + 1777 + ] + }, + { + "teal": 1767, + "source": 547, + "pc": [ + 1778 + ] + }, + { + "teal": 1768, + "source": 547, + "pc": [ + 1779, + 1780, + 1781 + ] + }, + { + "teal": 1771, + "source": 548, + "pc": [ + 1782 + ] + }, + { + "teal": 1776, + "source": 550, + "pc": [ + 1783, + 1784 + ] + }, + { + "teal": 1777, + "source": 550, + "pc": [ + 1785 + ] + }, + { + "teal": 1778, + "source": 550, + "pc": [ + 1786 + ] + }, + { + "teal": 1779, + "source": 550, + "pc": [ + 1787, + 1788 + ] + }, + { + "teal": 1798, + "source": 553, + "pc": [ + 1789 + ] + }, + { + "teal": 1799, + "source": 553, + "pc": [ + 1790, + 1791 + ] + }, + { + "teal": 1800, + "source": 553, + "pc": [ + 1792, + 1793 + ] + }, + { + "teal": 1804, + "source": 554, + "pc": [ + 1794 + ] + }, + { + "teal": 1805, + "source": 554, + "pc": [ + 1795, + 1796 + ] + }, + { + "teal": 1809, + "source": 555, + "pc": [ + 1797, + 1798 + ] + }, + { + "teal": 1810, + "source": 555, + "pc": [ + 1799 + ] + }, + { + "teal": 1811, + "source": 555, + "pc": [ + 1800, + 1801 + ] + }, + { + "teal": 1812, + "source": 555, + "pc": [ + 1802 + ] + }, + { + "teal": 1813, + "source": 555, + "pc": [ + 1803, + 1804 + ] + }, + { + "teal": 1817, + "source": 556, + "pc": [ + 1805, + 1806 + ] + }, + { + "teal": 1818, + "source": 556, + "pc": [ + 1807 + ] + }, + { + "teal": 1819, + "source": 556, + "pc": [ + 1808, + 1809 + ] + }, + { + "teal": 1820, + "source": 556, + "pc": [ + 1810 + ] + }, + { + "teal": 1821, + "source": 556, + "pc": [ + 1811, + 1812 + ] + }, + { + "teal": 1825, + "source": 557, + "pc": [ + 1813, + 1814 + ] + }, + { + "teal": 1826, + "source": 557, + "pc": [ + 1815 + ] + }, + { + "teal": 1827, + "source": 557, + "pc": [ + 1816, + 1817 + ] + }, + { + "teal": 1828, + "source": 557, + "pc": [ + 1818 + ] + }, + { + "teal": 1829, + "source": 557, + "pc": [ + 1819, + 1820 + ] + }, + { + "teal": 1833, + "source": 558, + "pc": [ + 1821, + 1822 + ] + }, + { + "teal": 1834, + "source": 558, + "pc": [ + 1823 + ] + }, + { + "teal": 1835, + "source": 558, + "pc": [ + 1824, + 1825 + ] + }, + { + "teal": 1836, + "source": 558, + "pc": [ + 1826 + ] + }, + { + "teal": 1837, + "source": 558, + "pc": [ + 1827, + 1828 + ] + }, + { + "teal": 1841, + "source": 559, + "pc": [ + 1829, + 1830 + ] + }, + { + "teal": 1842, + "source": 559, + "pc": [ + 1831 + ] + }, + { + "teal": 1843, + "source": 559, + "pc": [ + 1832, + 1833 + ] + }, + { + "teal": 1844, + "source": 559, + "pc": [ + 1834 + ] + }, + { + "teal": 1845, + "source": 559, + "pc": [ + 1835, + 1836 + ] + }, + { + "teal": 1856, + "source": 562, + "pc": [ + 1837, + 1838, + 1839, + 1840, + 1841, + 1842 + ] + }, + { + "teal": 1857, + "source": 562, + "pc": [ + 1843, + 1844 + ] + }, + { + "teal": 1858, + "source": 563, + "pc": [ + 1845, + 1846, + 1847 + ] + }, + { + "teal": 1859, + "source": 563, + "pc": [ + 1848 + ] + }, + { + "teal": 1860, + "source": 563, + "pc": [ + 1849, + 1850 + ] + }, + { + "teal": 1861, + "source": 564, + "pc": [ + 1851, + 1852 + ] + }, + { + "teal": 1862, + "source": 564, + "pc": [ + 1853 + ] + }, + { + "teal": 1863, + "source": 564, + "pc": [ + 1854, + 1855 + ] + }, + { + "teal": 1864, + "source": 565, + "pc": [ + 1856, + 1857 + ] + }, + { + "teal": 1865, + "source": 565, + "pc": [ + 1858 + ] + }, + { + "teal": 1866, + "source": 565, + "pc": [ + 1859, + 1860 + ] + }, + { + "teal": 1867, + "source": 566, + "pc": [ + 1861, + 1862 + ] + }, + { + "teal": 1868, + "source": 566, + "pc": [ + 1863 + ] + }, + { + "teal": 1869, + "source": 566, + "pc": [ + 1864 + ] + }, + { + "teal": 1870, + "source": 566, + "pc": [ + 1865, + 1866 + ] + }, + { + "teal": 1871, + "source": 566, + "pc": [ + 1867 + ] + }, + { + "teal": 1872, + "source": 566, + "pc": [ + 1868 + ] + }, + { + "teal": 1873, + "source": 566, + "pc": [ + 1869, + 1870 + ] + }, + { + "teal": 1874, + "source": 566, + "pc": [ + 1871 + ] + }, + { + "teal": 1875, + "source": 566, + "pc": [ + 1872 + ] + }, + { + "teal": 1876, + "source": 566, + "pc": [ + 1873 + ] + }, + { + "teal": 1877, + "source": 566, + "pc": [ + 1874, + 1875 + ] + }, + { + "teal": 1880, + "source": 553, + "pc": [ + 1876 + ] + }, + { + "teal": 1881, + "source": 553, + "pc": [ + 1877, + 1878 + ] + }, + { + "teal": 1884, + "source": 553, + "pc": [ + 1879 + ] + }, + { + "teal": 1888, + "source": 570, + "pc": [ + 1880, + 1881 + ] + }, + { + "teal": 1889, + "source": 570, + "pc": [ + 1882, + 1883 + ] + }, + { + "teal": 1890, + "source": 570, + "pc": [ + 1884 + ] + }, + { + "teal": 1891, + "source": 570, + "pc": [ + 1885, + 1886, + 1887 + ] + }, + { + "teal": 1892, + "source": 570, + "pc": [ + 1888 + ] + }, + { + "teal": 1893, + "source": 570, + "pc": [ + 1889, + 1890 + ] + }, + { + "teal": 1894, + "source": 570, + "pc": [ + 1891 + ] + }, + { + "teal": 1895, + "source": 570, + "pc": [ + 1892 + ] + }, + { + "teal": 1896, + "source": 570, + "pc": [ + 1893, + 1894 + ] + }, + { + "teal": 1897, + "source": 570, + "pc": [ + 1895 + ] + }, + { + "teal": 1901, + "source": 573, + "pc": [ + 1896, + 1897 + ] + }, + { + "teal": 1902, + "source": 573, + "pc": [ + 1898, + 1899 + ] + }, + { + "teal": 1906, + "source": 574, + "pc": [ + 1900, + 1901 + ] + }, + { + "teal": 1907, + "source": 574, + "pc": [ + 1902, + 1903 + ] + }, + { + "teal": 1908, + "source": 574, + "pc": [ + 1904 + ] + }, + { + "teal": 1909, + "source": 574, + "pc": [ + 1905 + ] + }, + { + "teal": 1910, + "source": 574, + "pc": [ + 1906, + 1907 + ] + }, + { + "teal": 1911, + "source": 574, + "pc": [ + 1908 + ] + }, + { + "teal": 1912, + "source": 574, + "pc": [ + 1909 + ] + }, + { + "teal": 1913, + "source": 574, + "pc": [ + 1910 + ] + }, + { + "teal": 1914, + "source": 574, + "pc": [ + 1911 + ] + }, + { + "teal": 1915, + "source": 574, + "pc": [ + 1912, + 1913 + ] + }, + { + "teal": 1916, + "source": 574, + "pc": [ + 1914 + ] + }, + { + "teal": 1917, + "source": 574, + "pc": [ + 1915 + ] + }, + { + "teal": 1918, + "source": 574, + "pc": [ + 1916, + 1917 + ] + }, + { + "teal": 1919, + "source": 574, + "pc": [ + 1918 + ] + }, + { + "teal": 1920, + "source": 574, + "pc": [ + 1919 + ] + }, + { + "teal": 1921, + "source": 574, + "pc": [ + 1920, + 1921 + ] + }, + { + "teal": 1922, + "source": 574, + "pc": [ + 1922 + ] + }, + { + "teal": 1926, + "source": 575, + "pc": [ + 1923, + 1924 + ] + }, + { + "teal": 1927, + "source": 575, + "pc": [ + 1925, + 1926 + ] + }, + { + "teal": 1928, + "source": 575, + "pc": [ + 1927, + 1928 + ] + }, + { + "teal": 1929, + "source": 575, + "pc": [ + 1929, + 1930, + 1931 + ] + }, + { + "teal": 1933, + "source": 583, + "pc": [ + 1932, + 1933 + ] + }, + { + "teal": 1934, + "source": 583, + "pc": [ + 1934 + ] + }, + { + "teal": 1935, + "source": 583, + "pc": [ + 1935, + 1936 + ] + }, + { + "teal": 1936, + "source": 583, + "pc": [ + 1937 + ] + }, + { + "teal": 1937, + "source": 583, + "pc": [ + 1938 + ] + }, + { + "teal": 1938, + "source": 583, + "pc": [ + 1939, + 1940 + ] + }, + { + "teal": 1939, + "source": 583, + "pc": [ + 1941 + ] + }, + { + "teal": 1940, + "source": 583, + "pc": [ + 1942 + ] + }, + { + "teal": 1943, + "source": 583, + "pc": [ + 1943, + 1944 + ] + }, + { + "teal": 1946, + "source": 583, + "pc": [ + 1945, + 1946 + ] + }, + { + "teal": 1947, + "source": 583, + "pc": [ + 1947 + ] + }, + { + "teal": 1952, + "source": 595, + "pc": [ + 1948 + ] + }, + { + "teal": 1955, + "source": 595, + "pc": [ + 1949, + 1950, + 1951 + ] + }, + { + "teal": 1956, + "source": 595, + "pc": [ + 1952 + ] + }, + { + "teal": 1959, + "source": 595, + "pc": [ + 1953, + 1954, + 1955 + ] + }, + { + "teal": 1960, + "source": 595, + "pc": [ + 1956 + ] + }, + { + "teal": 1963, + "source": 595, + "pc": [ + 1957, + 1958 + ] + }, + { + "teal": 1964, + "source": 595, + "pc": [ + 1959 + ] + }, + { + "teal": 1965, + "source": 595, + "pc": [ + 1960 + ] + }, + { + "teal": 1966, + "source": 595, + "pc": [ + 1961 + ] + }, + { + "teal": 1967, + "source": 595, + "pc": [ + 1962, + 1963 + ] + }, + { + "teal": 1968, + "source": 595, + "pc": [ + 1964 + ] + }, + { + "teal": 1969, + "source": 595, + "pc": [ + 1965 + ] + }, + { + "teal": 1970, + "source": 595, + "pc": [ + 1966 + ] + }, + { + "teal": 1973, + "source": 595, + "pc": [ + 1967, + 1968, + 1969 + ] + }, + { + "teal": 1974, + "source": 595, + "pc": [ + 1970 + ] + }, + { + "teal": 1975, + "source": 595, + "pc": [ + 1971 + ] + }, + { + "teal": 1976, + "source": 595, + "pc": [ + 1972 + ] + }, + { + "teal": 1977, + "source": 595, + "pc": [ + 1973 + ] + }, + { + "teal": 1989, + "source": 595, + "pc": [ + 1974, + 1975, + 1976 + ] + }, + { + "teal": 1992, + "source": 595, + "pc": [ + 1977 + ] + }, + { + "teal": 1993, + "source": 595, + "pc": [ + 1978, + 1979 + ] + }, + { + "teal": 1997, + "source": 596, + "pc": [ + 1980 + ] + }, + { + "teal": 1998, + "source": 596, + "pc": [ + 1981, + 1982 + ] + }, + { + "teal": 1999, + "source": 596, + "pc": [ + 1983 + ] + }, + { + "teal": 2000, + "source": 596, + "pc": [ + 1984 + ] + }, + { + "teal": 2001, + "source": 596, + "pc": [ + 1985 + ] + }, + { + "teal": 2002, + "source": 596, + "pc": [ + 1986 + ] + }, + { + "teal": 2003, + "source": 596, + "pc": [ + 1987 + ] + }, + { + "teal": 2004, + "source": 596, + "pc": [ + 1988 + ] + }, + { + "teal": 2008, + "source": 598, + "pc": [ + 1989, + 1990 + ] + }, + { + "teal": 2009, + "source": 598, + "pc": [ + 1991, + 1992 + ] + }, + { + "teal": 2017, + "source": 602, + "pc": [ + 1993, + 1994 + ] + }, + { + "teal": 2018, + "source": 603, + "pc": [ + 1995, + 1996 + ] + }, + { + "teal": 2019, + "source": 603, + "pc": [ + 1997, + 1998 + ] + }, + { + "teal": 2020, + "source": 603, + "pc": [ + 1999 + ] + }, + { + "teal": 2021, + "source": 603, + "pc": [ + 2000 + ] + }, + { + "teal": 2024, + "source": 602, + "pc": [ + 2001, + 2002 + ] + }, + { + "teal": 2025, + "source": 604, + "pc": [ + 2003, + 2004 + ] + }, + { + "teal": 2026, + "source": 604, + "pc": [ + 2005, + 2006 + ] + }, + { + "teal": 2027, + "source": 604, + "pc": [ + 2007 + ] + }, + { + "teal": 2028, + "source": 604, + "pc": [ + 2008 + ] + }, + { + "teal": 2035, + "source": 610, + "pc": [ + 2009, + 2010 + ] + }, + { + "teal": 2036, + "source": 610, + "pc": [ + 2011 + ] + }, + { + "teal": 2037, + "source": 610, + "pc": [ + 2012 + ] + }, + { + "teal": 2038, + "source": 610, + "pc": [ + 2013, + 2014 + ] + }, + { + "teal": 2039, + "source": 610, + "pc": [ + 2015 + ] + }, + { + "teal": 2040, + "source": 610, + "pc": [ + 2016 + ] + }, + { + "teal": 2041, + "source": 610, + "pc": [ + 2017, + 2018 + ] + }, + { + "teal": 2042, + "source": 610, + "pc": [ + 2019 + ] + }, + { + "teal": 2043, + "source": 610, + "pc": [ + 2020 + ] + }, + { + "teal": 2044, + "source": 610, + "pc": [ + 2021, + 2022, + 2023 + ] + }, + { + "teal": 2045, + "source": 610, + "pc": [ + 2024 + ] + }, + { + "teal": 2048, + "source": 609, + "pc": [ + 2025 + ] + }, + { + "teal": 2052, + "source": 616, + "pc": [ + 2026, + 2027 + ] + }, + { + "teal": 2053, + "source": 616, + "pc": [ + 2028, + 2029 + ] + }, + { + "teal": 2054, + "source": 616, + "pc": [ + 2030, + 2031, + 2032 + ] + }, + { + "teal": 2058, + "source": 618, + "pc": [ + 2033, + 2034 + ] + }, + { + "teal": 2059, + "source": 618, + "pc": [ + 2035, + 2036 + ] + }, + { + "teal": 2060, + "source": 618, + "pc": [ + 2037, + 2038 + ] + }, + { + "teal": 2064, + "source": 619, + "pc": [ + 2039 + ] + }, + { + "teal": 2065, + "source": 619, + "pc": [ + 2040, + 2041 + ] + }, + { + "teal": 2070, + "source": 621, + "pc": [ + 2042 + ] + }, + { + "teal": 2071, + "source": 621, + "pc": [ + 2043, + 2044 + ] + }, + { + "teal": 2072, + "source": 621, + "pc": [ + 2045 + ] + }, + { + "teal": 2073, + "source": 621, + "pc": [ + 2046 + ] + }, + { + "teal": 2074, + "source": 621, + "pc": [ + 2047 + ] + }, + { + "teal": 2075, + "source": 621, + "pc": [ + 2048 + ] + }, + { + "teal": 2076, + "source": 621, + "pc": [ + 2049 + ] + }, + { + "teal": 2077, + "source": 621, + "pc": [ + 2050, + 2051, + 2052 + ] + }, + { + "teal": 2082, + "source": 624, + "pc": [ + 2053, + 2054, + 2055 + ] + }, + { + "teal": 2083, + "source": 624, + "pc": [ + 2056, + 2057, + 2058 + ] + }, + { + "teal": 2084, + "source": 624, + "pc": [ + 2059 + ] + }, + { + "teal": 2085, + "source": 624, + "pc": [ + 2060, + 2061 + ] + }, + { + "teal": 2089, + "source": 625, + "pc": [ + 2062, + 2063 + ] + }, + { + "teal": 2090, + "source": 625, + "pc": [ + 2064, + 2065 + ] + }, + { + "teal": 2091, + "source": 625, + "pc": [ + 2066 + ] + }, + { + "teal": 2092, + "source": 625, + "pc": [ + 2067, + 2068 + ] + }, + { + "teal": 2096, + "source": 626, + "pc": [ + 2069 + ] + }, + { + "teal": 2097, + "source": 626, + "pc": [ + 2070, + 2071 + ] + }, + { + "teal": 2098, + "source": 626, + "pc": [ + 2072 + ] + }, + { + "teal": 2099, + "source": 626, + "pc": [ + 2073, + 2074, + 2075 + ] + }, + { + "teal": 2100, + "source": 626, + "pc": [ + 2076 + ] + }, + { + "teal": 2101, + "source": 626, + "pc": [ + 2077 + ] + }, + { + "teal": 2106, + "source": 630, + "pc": [ + 2078, + 2079 + ] + }, + { + "teal": 2107, + "source": 630, + "pc": [ + 2080, + 2081 + ] + }, + { + "teal": 2108, + "source": 630, + "pc": [ + 2082, + 2083 + ] + }, + { + "teal": 2109, + "source": 630, + "pc": [ + 2084, + 2085, + 2086 + ] + }, + { + "teal": 2110, + "source": 630, + "pc": [ + 2087, + 2088 + ] + }, + { + "teal": 2116, + "source": 632, + "pc": [ + 2089, + 2090 + ] + }, + { + "teal": 2117, + "source": 632, + "pc": [ + 2091, + 2092 + ] + }, + { + "teal": 2118, + "source": 632, + "pc": [ + 2093, + 2094 + ] + }, + { + "teal": 2119, + "source": 632, + "pc": [ + 2095, + 2096 + ] + }, + { + "teal": 2120, + "source": 632, + "pc": [ + 2097 + ] + }, + { + "teal": 2121, + "source": 632, + "pc": [ + 2098, + 2099 + ] + }, + { + "teal": 2125, + "source": 633, + "pc": [ + 2100, + 2101 + ] + }, + { + "teal": 2126, + "source": 633, + "pc": [ + 2102, + 2103 + ] + }, + { + "teal": 2127, + "source": 633, + "pc": [ + 2104, + 2105 + ] + }, + { + "teal": 2128, + "source": 633, + "pc": [ + 2106, + 2107, + 2108 + ] + }, + { + "teal": 2129, + "source": 633, + "pc": [ + 2109 + ] + }, + { + "teal": 2130, + "source": 633, + "pc": [ + 2110, + 2111 + ] + }, + { + "teal": 2135, + "source": 634, + "pc": [ + 2112, + 2113 + ] + }, + { + "teal": 2136, + "source": 634, + "pc": [ + 2114, + 2115 + ] + }, + { + "teal": 2137, + "source": 634, + "pc": [ + 2116, + 2117 + ] + }, + { + "teal": 2138, + "source": 634, + "pc": [ + 2118, + 2119, + 2120 + ] + }, + { + "teal": 2139, + "source": 634, + "pc": [ + 2121 + ] + }, + { + "teal": 2140, + "source": 634, + "pc": [ + 2122 + ] + }, + { + "teal": 2141, + "source": 634, + "pc": [ + 2123 + ] + }, + { + "teal": 2142, + "source": 634, + "pc": [ + 2124, + 2125, + 2126 + ] + }, + { + "teal": 2145, + "source": 635, + "pc": [ + 2127 + ] + }, + { + "teal": 2150, + "source": 639, + "pc": [ + 2128, + 2129 + ] + }, + { + "teal": 2151, + "source": 639, + "pc": [ + 2130, + 2131 + ] + }, + { + "teal": 2152, + "source": 639, + "pc": [ + 2132, + 2133 + ] + }, + { + "teal": 2153, + "source": 639, + "pc": [ + 2134, + 2135, + 2136 + ] + }, + { + "teal": 2154, + "source": 639, + "pc": [ + 2137, + 2138 + ] + }, + { + "teal": 2155, + "source": 639, + "pc": [ + 2139, + 2140, + 2141 + ] + }, + { + "teal": 2165, + "source": 647, + "pc": [ + 2142, + 2143 + ] + }, + { + "teal": 2166, + "source": 646, + "pc": [ + 2144, + 2145 + ] + }, + { + "teal": 2167, + "source": 645, + "pc": [ + 2146, + 2147 + ] + }, + { + "teal": 2168, + "source": 644, + "pc": [ + 2148, + 2149 + ] + }, + { + "teal": 2169, + "source": 644, + "pc": [ + 2150, + 2151 + ] + }, + { + "teal": 2170, + "source": 644, + "pc": [ + 2152, + 2153 + ] + }, + { + "teal": 2171, + "source": 644, + "pc": [ + 2154, + 2155, + 2156 + ] + }, + { + "teal": 2172, + "source": 643, + "pc": [ + 2157, + 2158 + ] + }, + { + "teal": 2173, + "source": 642, + "pc": [ + 2159, + 2160, + 2161 + ] + }, + { + "teal": 2177, + "source": 657, + "pc": [ + 2162, + 2163 + ] + }, + { + "teal": 2178, + "source": 657, + "pc": [ + 2164, + 2165 + ] + }, + { + "teal": 2179, + "source": 657, + "pc": [ + 2166, + 2167 + ] + }, + { + "teal": 2180, + "source": 657, + "pc": [ + 2168, + 2169, + 2170 + ] + }, + { + "teal": 2183, + "source": 657, + "pc": [ + 2171, + 2172 + ] + }, + { + "teal": 2186, + "source": 657, + "pc": [ + 2173, + 2174 + ] + }, + { + "teal": 2187, + "source": 657, + "pc": [ + 2175 + ] + }, + { + "teal": 2192, + "source": 675, + "pc": [ + 2176 + ] + }, + { + "teal": 2195, + "source": 675, + "pc": [ + 2177, + 2178, + 2179 + ] + }, + { + "teal": 2196, + "source": 675, + "pc": [ + 2180 + ] + }, + { + "teal": 2199, + "source": 675, + "pc": [ + 2181, + 2182, + 2183 + ] + }, + { + "teal": 2200, + "source": 675, + "pc": [ + 2184 + ] + }, + { + "teal": 2201, + "source": 675, + "pc": [ + 2185 + ] + }, + { + "teal": 2202, + "source": 675, + "pc": [ + 2186 + ] + }, + { + "teal": 2203, + "source": 675, + "pc": [ + 2187 + ] + }, + { + "teal": 2221, + "source": 675, + "pc": [ + 2188, + 2189, + 2190 + ] + }, + { + "teal": 2224, + "source": 675, + "pc": [ + 2191 + ] + }, + { + "teal": 2225, + "source": 675, + "pc": [ + 2192, + 2193 + ] + }, + { + "teal": 2229, + "source": 677, + "pc": [ + 2194, + 2195 + ] + }, + { + "teal": 2230, + "source": 677, + "pc": [ + 2196 + ] + }, + { + "teal": 2231, + "source": 677, + "pc": [ + 2197 + ] + }, + { + "teal": 2232, + "source": 677, + "pc": [ + 2198, + 2199 + ] + }, + { + "teal": 2233, + "source": 677, + "pc": [ + 2200 + ] + }, + { + "teal": 2234, + "source": 677, + "pc": [ + 2201 + ] + }, + { + "teal": 2235, + "source": 677, + "pc": [ + 2202, + 2203 + ] + }, + { + "teal": 2236, + "source": 677, + "pc": [ + 2204 + ] + }, + { + "teal": 2237, + "source": 677, + "pc": [ + 2205 + ] + }, + { + "teal": 2238, + "source": 677, + "pc": [ + 2206, + 2207 + ] + }, + { + "teal": 2242, + "source": 678, + "pc": [ + 2208, + 2209 + ] + }, + { + "teal": 2243, + "source": 678, + "pc": [ + 2210 + ] + }, + { + "teal": 2244, + "source": 678, + "pc": [ + 2211 + ] + }, + { + "teal": 2245, + "source": 678, + "pc": [ + 2212 + ] + }, + { + "teal": 2250, + "source": 680, + "pc": [ + 2213, + 2214 + ] + }, + { + "teal": 2251, + "source": 680, + "pc": [ + 2215, + 2216 + ] + }, + { + "teal": 2252, + "source": 680, + "pc": [ + 2217, + 2218 + ] + }, + { + "teal": 2253, + "source": 680, + "pc": [ + 2219 + ] + }, + { + "teal": 2254, + "source": 680, + "pc": [ + 2220 + ] + }, + { + "teal": 2255, + "source": 680, + "pc": [ + 2221, + 2222, + 2223 + ] + }, + { + "teal": 2260, + "source": 681, + "pc": [ + 2224, + 2225 + ] + }, + { + "teal": 2261, + "source": 681, + "pc": [ + 2226, + 2227 + ] + }, + { + "teal": 2262, + "source": 681, + "pc": [ + 2228 + ] + }, + { + "teal": 2263, + "source": 681, + "pc": [ + 2229, + 2230 + ] + }, + { + "teal": 2264, + "source": 681, + "pc": [ + 2231 + ] + }, + { + "teal": 2265, + "source": 681, + "pc": [ + 2232 + ] + }, + { + "teal": 2266, + "source": 681, + "pc": [ + 2233, + 2234 + ] + }, + { + "teal": 2267, + "source": 681, + "pc": [ + 2235 + ] + }, + { + "teal": 2270, + "source": 681, + "pc": [ + 2236, + 2237 + ] + }, + { + "teal": 2271, + "source": 681, + "pc": [ + 2238 + ] + }, + { + "teal": 2276, + "source": 686, + "pc": [ + 2239, + 2240 + ] + }, + { + "teal": 2277, + "source": 686, + "pc": [ + 2241, + 2242 + ] + }, + { + "teal": 2281, + "source": 687, + "pc": [ + 2243, + 2244 + ] + }, + { + "teal": 2282, + "source": 687, + "pc": [ + 2245 + ] + }, + { + "teal": 2283, + "source": 687, + "pc": [ + 2246 + ] + }, + { + "teal": 2284, + "source": 687, + "pc": [ + 2247, + 2248 + ] + }, + { + "teal": 2285, + "source": 687, + "pc": [ + 2249 + ] + }, + { + "teal": 2286, + "source": 687, + "pc": [ + 2250 + ] + }, + { + "teal": 2287, + "source": 687, + "pc": [ + 2251, + 2252 + ] + }, + { + "teal": 2288, + "source": 687, + "pc": [ + 2253 + ] + }, + { + "teal": 2289, + "source": 687, + "pc": [ + 2254 + ] + }, + { + "teal": 2290, + "source": 687, + "pc": [ + 2255, + 2256 + ] + }, + { + "teal": 2295, + "source": 688, + "pc": [ + 2257, + 2258 + ] + }, + { + "teal": 2296, + "source": 688, + "pc": [ + 2259 + ] + }, + { + "teal": 2297, + "source": 688, + "pc": [ + 2260 + ] + }, + { + "teal": 2298, + "source": 688, + "pc": [ + 2261, + 2262, + 2263 + ] + }, + { + "teal": 2304, + "source": 690, + "pc": [ + 2264, + 2265 + ] + }, + { + "teal": 2305, + "source": 690, + "pc": [ + 2266, + 2267, + 2268, + 2269, + 2270, + 2271, + 2272, + 2273, + 2274, + 2275, + 2276, + 2277 + ] + }, + { + "teal": 2306, + "source": 690, + "pc": [ + 2278 + ] + }, + { + "teal": 2307, + "source": 690, + "pc": [ + 2279 + ] + }, + { + "teal": 2308, + "source": 690, + "pc": [ + 2280, + 2281 + ] + }, + { + "teal": 2309, + "source": 690, + "pc": [ + 2282 + ] + }, + { + "teal": 2310, + "source": 690, + "pc": [ + 2283, + 2284, + 2285 + ] + }, + { + "teal": 2315, + "source": 691, + "pc": [ + 2286, + 2287 + ] + }, + { + "teal": 2316, + "source": 691, + "pc": [ + 2288, + 2289 + ] + }, + { + "teal": 2317, + "source": 691, + "pc": [ + 2290 + ] + }, + { + "teal": 2318, + "source": 691, + "pc": [ + 2291, + 2292 + ] + }, + { + "teal": 2319, + "source": 691, + "pc": [ + 2293 + ] + }, + { + "teal": 2320, + "source": 691, + "pc": [ + 2294 + ] + }, + { + "teal": 2321, + "source": 691, + "pc": [ + 2295, + 2296 + ] + }, + { + "teal": 2322, + "source": 691, + "pc": [ + 2297 + ] + }, + { + "teal": 2325, + "source": 691, + "pc": [ + 2298, + 2299 + ] + }, + { + "teal": 2328, + "source": 691, + "pc": [ + 2300, + 2301 + ] + }, + { + "teal": 2329, + "source": 691, + "pc": [ + 2302 + ] + }, + { + "teal": 2334, + "source": 693, + "pc": [ + 2303, + 2304 + ] + }, + { + "teal": 2335, + "source": 693, + "pc": [ + 2305, + 2306 + ] + }, + { + "teal": 2336, + "source": 693, + "pc": [ + 2307 + ] + }, + { + "teal": 2337, + "source": 693, + "pc": [ + 2308, + 2309 + ] + }, + { + "teal": 2341, + "source": 694, + "pc": [ + 2310, + 2311, + 2312 + ] + }, + { + "teal": 2342, + "source": 694, + "pc": [ + 2313, + 2314 + ] + }, + { + "teal": 2343, + "source": 694, + "pc": [ + 2315 + ] + }, + { + "teal": 2344, + "source": 694, + "pc": [ + 2316, + 2317 + ] + }, + { + "teal": 2345, + "source": 694, + "pc": [ + 2318 + ] + }, + { + "teal": 2346, + "source": 694, + "pc": [ + 2319 + ] + }, + { + "teal": 2347, + "source": 694, + "pc": [ + 2320, + 2321 + ] + }, + { + "teal": 2348, + "source": 694, + "pc": [ + 2322 + ] + }, + { + "teal": 2349, + "source": 694, + "pc": [ + 2323 + ] + }, + { + "teal": 2350, + "source": 694, + "pc": [ + 2324, + 2325 + ] + }, + { + "teal": 2351, + "source": 694, + "pc": [ + 2326 + ] + }, + { + "teal": 2352, + "source": 694, + "pc": [ + 2327, + 2328 + ] + }, + { + "teal": 2357, + "source": 696, + "pc": [ + 2329, + 2330 + ] + }, + { + "teal": 2358, + "source": 696, + "pc": [ + 2331, + 2332 + ] + }, + { + "teal": 2359, + "source": 696, + "pc": [ + 2333 + ] + }, + { + "teal": 2360, + "source": 696, + "pc": [ + 2334, + 2335, + 2336 + ] + }, + { + "teal": 2365, + "source": 697, + "pc": [ + 2337, + 2338 + ] + }, + { + "teal": 2366, + "source": 697, + "pc": [ + 2339, + 2340 + ] + }, + { + "teal": 2367, + "source": 697, + "pc": [ + 2341 + ] + }, + { + "teal": 2368, + "source": 697, + "pc": [ + 2342, + 2343 + ] + }, + { + "teal": 2369, + "source": 697, + "pc": [ + 2344 + ] + }, + { + "teal": 2370, + "source": 697, + "pc": [ + 2345 + ] + }, + { + "teal": 2371, + "source": 697, + "pc": [ + 2346, + 2347 + ] + }, + { + "teal": 2372, + "source": 697, + "pc": [ + 2348 + ] + }, + { + "teal": 2375, + "source": 697, + "pc": [ + 2349, + 2350 + ] + }, + { + "teal": 2378, + "source": 697, + "pc": [ + 2351, + 2352 + ] + }, + { + "teal": 2379, + "source": 697, + "pc": [ + 2353 + ] + }, + { + "teal": 2386, + "source": 700, + "pc": [ + 2354, + 2355 + ] + }, + { + "teal": 2387, + "source": 700, + "pc": [ + 2356, + 2357 + ] + }, + { + "teal": 2388, + "source": 700, + "pc": [ + 2358 + ] + }, + { + "teal": 2389, + "source": 700, + "pc": [ + 2359 + ] + }, + { + "teal": 2390, + "source": 700, + "pc": [ + 2360, + 2361 + ] + }, + { + "teal": 2391, + "source": 700, + "pc": [ + 2362 + ] + }, + { + "teal": 2392, + "source": 700, + "pc": [ + 2363 + ] + }, + { + "teal": 2393, + "source": 700, + "pc": [ + 2364, + 2365 + ] + }, + { + "teal": 2394, + "source": 700, + "pc": [ + 2366 + ] + }, + { + "teal": 2398, + "source": 702, + "pc": [ + 2367, + 2368 + ] + }, + { + "teal": 2399, + "source": 702, + "pc": [ + 2369, + 2370 + ] + }, + { + "teal": 2400, + "source": 702, + "pc": [ + 2371 + ] + }, + { + "teal": 2401, + "source": 702, + "pc": [ + 2372, + 2373 + ] + }, + { + "teal": 2402, + "source": 702, + "pc": [ + 2374 + ] + }, + { + "teal": 2403, + "source": 702, + "pc": [ + 2375 + ] + }, + { + "teal": 2404, + "source": 702, + "pc": [ + 2376, + 2377 + ] + }, + { + "teal": 2405, + "source": 702, + "pc": [ + 2378 + ] + }, + { + "teal": 2406, + "source": 702, + "pc": [ + 2379 + ] + }, + { + "teal": 2407, + "source": 702, + "pc": [ + 2380, + 2381 + ] + }, + { + "teal": 2411, + "source": 703, + "pc": [ + 2382, + 2383 + ] + }, + { + "teal": 2412, + "source": 703, + "pc": [ + 2384 + ] + }, + { + "teal": 2413, + "source": 703, + "pc": [ + 2385 + ] + }, + { + "teal": 2414, + "source": 703, + "pc": [ + 2386, + 2387 + ] + }, + { + "teal": 2415, + "source": 703, + "pc": [ + 2388 + ] + }, + { + "teal": 2416, + "source": 703, + "pc": [ + 2389 + ] + }, + { + "teal": 2417, + "source": 703, + "pc": [ + 2390, + 2391 + ] + }, + { + "teal": 2418, + "source": 703, + "pc": [ + 2392 + ] + }, + { + "teal": 2419, + "source": 703, + "pc": [ + 2393 + ] + }, + { + "teal": 2420, + "source": 703, + "pc": [ + 2394, + 2395 + ] + }, + { + "teal": 2424, + "source": 704, + "pc": [ + 2396 + ] + }, + { + "teal": 2425, + "source": 704, + "pc": [ + 2397, + 2398 + ] + }, + { + "teal": 2430, + "source": 704, + "pc": [ + 2399, + 2400 + ] + }, + { + "teal": 2431, + "source": 704, + "pc": [ + 2401, + 2402 + ] + }, + { + "teal": 2432, + "source": 704, + "pc": [ + 2403 + ] + }, + { + "teal": 2433, + "source": 704, + "pc": [ + 2404, + 2405, + 2406 + ] + }, + { + "teal": 2440, + "source": 710, + "pc": [ + 2407, + 2408 + ] + }, + { + "teal": 2441, + "source": 710, + "pc": [ + 2409, + 2410 + ] + }, + { + "teal": 2442, + "source": 710, + "pc": [ + 2411, + 2412 + ] + }, + { + "teal": 2443, + "source": 710, + "pc": [ + 2413 + ] + }, + { + "teal": 2444, + "source": 710, + "pc": [ + 2414 + ] + }, + { + "teal": 2445, + "source": 710, + "pc": [ + 2415, + 2416 + ] + }, + { + "teal": 2446, + "source": 710, + "pc": [ + 2417 + ] + }, + { + "teal": 2447, + "source": 710, + "pc": [ + 2418 + ] + }, + { + "teal": 2448, + "source": 710, + "pc": [ + 2419 + ] + }, + { + "teal": 2449, + "source": 710, + "pc": [ + 2420, + 2421 + ] + }, + { + "teal": 2450, + "source": 710, + "pc": [ + 2422 + ] + }, + { + "teal": 2451, + "source": 710, + "pc": [ + 2423 + ] + }, + { + "teal": 2452, + "source": 710, + "pc": [ + 2424, + 2425 + ] + }, + { + "teal": 2453, + "source": 710, + "pc": [ + 2426 + ] + }, + { + "teal": 2454, + "source": 710, + "pc": [ + 2427 + ] + }, + { + "teal": 2455, + "source": 710, + "pc": [ + 2428, + 2429 + ] + }, + { + "teal": 2456, + "source": 709, + "pc": [ + 2430 + ] + }, + { + "teal": 2457, + "source": 709, + "pc": [ + 2431 + ] + }, + { + "teal": 2458, + "source": 711, + "pc": [ + 2432, + 2433 + ] + }, + { + "teal": 2459, + "source": 709, + "pc": [ + 2434 + ] + }, + { + "teal": 2460, + "source": 709, + "pc": [ + 2435 + ] + }, + { + "teal": 2461, + "source": 709, + "pc": [ + 2436 + ] + }, + { + "teal": 2462, + "source": 709, + "pc": [ + 2437 + ] + }, + { + "teal": 2463, + "source": 709, + "pc": [ + 2438 + ] + }, + { + "teal": 2464, + "source": 709, + "pc": [ + 2439 + ] + }, + { + "teal": 2465, + "source": 709, + "pc": [ + 2440, + 2441 + ] + }, + { + "teal": 2469, + "source": 713, + "pc": [ + 2442, + 2443 + ] + }, + { + "teal": 2470, + "source": 713, + "pc": [ + 2444, + 2445 + ] + }, + { + "teal": 2471, + "source": 713, + "pc": [ + 2446 + ] + }, + { + "teal": 2472, + "source": 713, + "pc": [ + 2447 + ] + }, + { + "teal": 2473, + "source": 713, + "pc": [ + 2448 + ] + }, + { + "teal": 2474, + "source": 713, + "pc": [ + 2449, + 2450 + ] + }, + { + "teal": 2475, + "source": 713, + "pc": [ + 2451 + ] + }, + { + "teal": 2476, + "source": 713, + "pc": [ + 2452 + ] + }, + { + "teal": 2477, + "source": 713, + "pc": [ + 2453, + 2454 + ] + }, + { + "teal": 2478, + "source": 713, + "pc": [ + 2455 + ] + }, + { + "teal": 2479, + "source": 713, + "pc": [ + 2456 + ] + }, + { + "teal": 2480, + "source": 713, + "pc": [ + 2457, + 2458 + ] + }, + { + "teal": 2481, + "source": 713, + "pc": [ + 2459 + ] + }, + { + "teal": 2486, + "source": 704, + "pc": [ + 2460, + 2461 + ] + }, + { + "teal": 2487, + "source": 704, + "pc": [ + 2462 + ] + }, + { + "teal": 2488, + "source": 704, + "pc": [ + 2463 + ] + }, + { + "teal": 2489, + "source": 704, + "pc": [ + 2464, + 2465 + ] + }, + { + "teal": 2490, + "source": 704, + "pc": [ + 2466, + 2467, + 2468 + ] + }, + { + "teal": 2495, + "source": 715, + "pc": [ + 2469, + 2470 + ] + }, + { + "teal": 2496, + "source": 715, + "pc": [ + 2471, + 2472 + ] + }, + { + "teal": 2497, + "source": 715, + "pc": [ + 2473 + ] + }, + { + "teal": 2498, + "source": 715, + "pc": [ + 2474, + 2475 + ] + }, + { + "teal": 2499, + "source": 715, + "pc": [ + 2476 + ] + }, + { + "teal": 2500, + "source": 715, + "pc": [ + 2477 + ] + }, + { + "teal": 2501, + "source": 715, + "pc": [ + 2478, + 2479 + ] + }, + { + "teal": 2502, + "source": 715, + "pc": [ + 2480 + ] + }, + { + "teal": 2505, + "source": 715, + "pc": [ + 2481, + 2482 + ] + }, + { + "teal": 2508, + "source": 715, + "pc": [ + 2483, + 2484 + ] + }, + { + "teal": 2509, + "source": 715, + "pc": [ + 2485 + ] + }, + { + "teal": 2514, + "source": 727, + "pc": [ + 2486, + 2487, + 2488 + ] + }, + { + "teal": 2515, + "source": 727, + "pc": [ + 2489 + ] + }, + { + "teal": 2518, + "source": 727, + "pc": [ + 2490, + 2491, + 2492 + ] + }, + { + "teal": 2519, + "source": 727, + "pc": [ + 2493 + ] + }, + { + "teal": 2522, + "source": 727, + "pc": [ + 2494, + 2495, + 2496 + ] + }, + { + "teal": 2523, + "source": 727, + "pc": [ + 2497 + ] + }, + { + "teal": 2524, + "source": 727, + "pc": [ + 2498 + ] + }, + { + "teal": 2525, + "source": 727, + "pc": [ + 2499 + ] + }, + { + "teal": 2526, + "source": 727, + "pc": [ + 2500 + ] + }, + { + "teal": 2527, + "source": 727, + "pc": [ + 2501 + ] + }, + { + "teal": 2530, + "source": 727, + "pc": [ + 2502, + 2503, + 2504 + ] + }, + { + "teal": 2531, + "source": 727, + "pc": [ + 2505 + ] + }, + { + "teal": 2532, + "source": 727, + "pc": [ + 2506 + ] + }, + { + "teal": 2544, + "source": 727, + "pc": [ + 2507, + 2508, + 2509 + ] + }, + { + "teal": 2548, + "source": 728, + "pc": [ + 2510, + 2511 + ] + }, + { + "teal": 2549, + "source": 728, + "pc": [ + 2512, + 2513, + 2514 + ] + }, + { + "teal": 2553, + "source": 731, + "pc": [ + 2515, + 2516 + ] + }, + { + "teal": 2554, + "source": 731, + "pc": [ + 2517, + 2518 + ] + }, + { + "teal": 2555, + "source": 731, + "pc": [ + 2519, + 2520, + 2521 + ] + }, + { + "teal": 2556, + "source": 731, + "pc": [ + 2522 + ] + }, + { + "teal": 2557, + "source": 731, + "pc": [ + 2523 + ] + }, + { + "teal": 2558, + "source": 731, + "pc": [ + 2524 + ] + }, + { + "teal": 2559, + "source": 731, + "pc": [ + 2525, + 2526 + ] + }, + { + "teal": 2560, + "source": 731, + "pc": [ + 2527 + ] + }, + { + "teal": 2561, + "source": 731, + "pc": [ + 2528 + ] + }, + { + "teal": 2562, + "source": 731, + "pc": [ + 2529, + 2530 + ] + }, + { + "teal": 2563, + "source": 731, + "pc": [ + 2531 + ] + }, + { + "teal": 2564, + "source": 731, + "pc": [ + 2532, + 2533 + ] + }, + { + "teal": 2565, + "source": 731, + "pc": [ + 2534, + 2535 + ] + }, + { + "teal": 2566, + "source": 731, + "pc": [ + 2536, + 2537, + 2538 + ] + }, + { + "teal": 2567, + "source": 731, + "pc": [ + 2539 + ] + }, + { + "teal": 2568, + "source": 731, + "pc": [ + 2540 + ] + }, + { + "teal": 2569, + "source": 731, + "pc": [ + 2541 + ] + }, + { + "teal": 2570, + "source": 731, + "pc": [ + 2542, + 2543 + ] + }, + { + "teal": 2571, + "source": 731, + "pc": [ + 2544 + ] + }, + { + "teal": 2572, + "source": 731, + "pc": [ + 2545 + ] + }, + { + "teal": 2573, + "source": 731, + "pc": [ + 2546, + 2547 + ] + }, + { + "teal": 2574, + "source": 731, + "pc": [ + 2548 + ] + }, + { + "teal": 2575, + "source": 731, + "pc": [ + 2549 + ] + }, + { + "teal": 2576, + "source": 731, + "pc": [ + 2550 + ] + }, + { + "teal": 2577, + "source": 731, + "pc": [ + 2551, + 2552 + ] + }, + { + "teal": 2578, + "source": 731, + "pc": [ + 2553, + 2554, + 2555 + ] + }, + { + "teal": 2579, + "source": 731, + "pc": [ + 2556 + ] + }, + { + "teal": 2580, + "source": 731, + "pc": [ + 2557 + ] + }, + { + "teal": 2581, + "source": 731, + "pc": [ + 2558 + ] + }, + { + "teal": 2582, + "source": 731, + "pc": [ + 2559, + 2560 + ] + }, + { + "teal": 2583, + "source": 731, + "pc": [ + 2561 + ] + }, + { + "teal": 2584, + "source": 731, + "pc": [ + 2562 + ] + }, + { + "teal": 2585, + "source": 731, + "pc": [ + 2563, + 2564 + ] + }, + { + "teal": 2586, + "source": 731, + "pc": [ + 2565 + ] + }, + { + "teal": 2587, + "source": 731, + "pc": [ + 2566 + ] + }, + { + "teal": 2588, + "source": 731, + "pc": [ + 2567 + ] + }, + { + "teal": 2589, + "source": 731, + "pc": [ + 2568, + 2569 + ] + }, + { + "teal": 2590, + "source": 731, + "pc": [ + 2570, + 2571, + 2572 + ] + }, + { + "teal": 2591, + "source": 731, + "pc": [ + 2573 + ] + }, + { + "teal": 2592, + "source": 731, + "pc": [ + 2574 + ] + }, + { + "teal": 2593, + "source": 731, + "pc": [ + 2575 + ] + }, + { + "teal": 2594, + "source": 731, + "pc": [ + 2576, + 2577 + ] + }, + { + "teal": 2595, + "source": 731, + "pc": [ + 2578 + ] + }, + { + "teal": 2599, + "source": 732, + "pc": [ + 2579, + 2580 + ] + }, + { + "teal": 2600, + "source": 732, + "pc": [ + 2581 + ] + }, + { + "teal": 2601, + "source": 732, + "pc": [ + 2582 + ] + }, + { + "teal": 2602, + "source": 732, + "pc": [ + 2583 + ] + }, + { + "teal": 2603, + "source": 732, + "pc": [ + 2584, + 2585 + ] + }, + { + "teal": 2604, + "source": 732, + "pc": [ + 2586, + 2587, + 2588 + ] + }, + { + "teal": 2605, + "source": 732, + "pc": [ + 2589 + ] + }, + { + "teal": 2606, + "source": 732, + "pc": [ + 2590 + ] + }, + { + "teal": 2607, + "source": 732, + "pc": [ + 2591 + ] + }, + { + "teal": 2608, + "source": 732, + "pc": [ + 2592, + 2593 + ] + }, + { + "teal": 2609, + "source": 732, + "pc": [ + 2594 + ] + }, + { + "teal": 2610, + "source": 732, + "pc": [ + 2595 + ] + }, + { + "teal": 2611, + "source": 732, + "pc": [ + 2596, + 2597 + ] + }, + { + "teal": 2612, + "source": 732, + "pc": [ + 2598 + ] + }, + { + "teal": 2613, + "source": 732, + "pc": [ + 2599 + ] + }, + { + "teal": 2614, + "source": 732, + "pc": [ + 2600 + ] + }, + { + "teal": 2615, + "source": 732, + "pc": [ + 2601, + 2602 + ] + }, + { + "teal": 2616, + "source": 732, + "pc": [ + 2603, + 2604, + 2605 + ] + }, + { + "teal": 2617, + "source": 732, + "pc": [ + 2606 + ] + }, + { + "teal": 2618, + "source": 732, + "pc": [ + 2607 + ] + }, + { + "teal": 2619, + "source": 732, + "pc": [ + 2608 + ] + }, + { + "teal": 2620, + "source": 732, + "pc": [ + 2609, + 2610 + ] + }, + { + "teal": 2621, + "source": 732, + "pc": [ + 2611 + ] + }, + { + "teal": 2625, + "source": 733, + "pc": [ + 2612, + 2613 + ] + }, + { + "teal": 2626, + "source": 733, + "pc": [ + 2614 + ] + }, + { + "teal": 2627, + "source": 733, + "pc": [ + 2615 + ] + }, + { + "teal": 2628, + "source": 733, + "pc": [ + 2616 + ] + }, + { + "teal": 2629, + "source": 733, + "pc": [ + 2617, + 2618 + ] + }, + { + "teal": 2630, + "source": 733, + "pc": [ + 2619, + 2620, + 2621 + ] + }, + { + "teal": 2631, + "source": 733, + "pc": [ + 2622 + ] + }, + { + "teal": 2632, + "source": 733, + "pc": [ + 2623 + ] + }, + { + "teal": 2633, + "source": 733, + "pc": [ + 2624 + ] + }, + { + "teal": 2634, + "source": 733, + "pc": [ + 2625, + 2626 + ] + }, + { + "teal": 2635, + "source": 733, + "pc": [ + 2627 + ] + }, + { + "teal": 2636, + "source": 733, + "pc": [ + 2628 + ] + }, + { + "teal": 2637, + "source": 733, + "pc": [ + 2629, + 2630 + ] + }, + { + "teal": 2638, + "source": 733, + "pc": [ + 2631 + ] + }, + { + "teal": 2639, + "source": 733, + "pc": [ + 2632 + ] + }, + { + "teal": 2640, + "source": 733, + "pc": [ + 2633 + ] + }, + { + "teal": 2641, + "source": 733, + "pc": [ + 2634, + 2635 + ] + }, + { + "teal": 2642, + "source": 733, + "pc": [ + 2636, + 2637, + 2638 + ] + }, + { + "teal": 2643, + "source": 733, + "pc": [ + 2639 + ] + }, + { + "teal": 2644, + "source": 733, + "pc": [ + 2640 + ] + }, + { + "teal": 2645, + "source": 733, + "pc": [ + 2641 + ] + }, + { + "teal": 2646, + "source": 733, + "pc": [ + 2642, + 2643 + ] + }, + { + "teal": 2647, + "source": 733, + "pc": [ + 2644 + ] + }, + { + "teal": 2651, + "source": 735, + "pc": [ + 2645, + 2646 + ] + }, + { + "teal": 2652, + "source": 735, + "pc": [ + 2647 + ] + }, + { + "teal": 2653, + "source": 735, + "pc": [ + 2648, + 2649 + ] + }, + { + "teal": 2654, + "source": 735, + "pc": [ + 2650 + ] + }, + { + "teal": 2655, + "source": 735, + "pc": [ + 2651, + 2652 + ] + }, + { + "teal": 2656, + "source": 735, + "pc": [ + 2653 + ] + }, + { + "teal": 2657, + "source": 735, + "pc": [ + 2654 + ] + }, + { + "teal": 2661, + "source": 738, + "pc": [ + 2655, + 2656 + ] + }, + { + "teal": 2662, + "source": 738, + "pc": [ + 2657, + 2658, + 2659 + ] + }, + { + "teal": 2663, + "source": 738, + "pc": [ + 2660 + ] + }, + { + "teal": 2664, + "source": 738, + "pc": [ + 2661, + 2662, + 2663 + ] + }, + { + "teal": 2665, + "source": 727, + "pc": [ + 2664 + ] + }, + { + "teal": 2670, + "source": 766, + "pc": [ + 2665, + 2666, + 2667 + ] + }, + { + "teal": 2671, + "source": 766, + "pc": [ + 2668 + ] + }, + { + "teal": 2672, + "source": 766, + "pc": [ + 2669 + ] + }, + { + "teal": 2673, + "source": 766, + "pc": [ + 2670 + ] + }, + { + "teal": 2674, + "source": 766, + "pc": [ + 2671 + ] + }, + { + "teal": 2675, + "source": 766, + "pc": [ + 2672 + ] + }, + { + "teal": 2676, + "source": 766, + "pc": [ + 2673 + ] + }, + { + "teal": 2677, + "source": 766, + "pc": [ + 2674 + ] + }, + { + "teal": 2680, + "source": 765, + "pc": [ + 2675, + 2676, + 2677 + ] + }, + { + "teal": 2681, + "source": 765, + "pc": [ + 2678 + ] + }, + { + "teal": 2684, + "source": 764, + "pc": [ + 2679, + 2680, + 2681 + ] + }, + { + "teal": 2685, + "source": 764, + "pc": [ + 2682 + ] + }, + { + "teal": 2688, + "source": 763, + "pc": [ + 2683, + 2684, + 2685 + ] + }, + { + "teal": 2689, + "source": 763, + "pc": [ + 2686 + ] + }, + { + "teal": 2690, + "source": 763, + "pc": [ + 2687 + ] + }, + { + "teal": 2691, + "source": 763, + "pc": [ + 2688, + 2689 + ] + }, + { + "teal": 2692, + "source": 763, + "pc": [ + 2690 + ] + }, + { + "teal": 2693, + "source": 763, + "pc": [ + 2691 + ] + }, + { + "teal": 2696, + "source": 762, + "pc": [ + 2692, + 2693, + 2694 + ] + }, + { + "teal": 2697, + "source": 762, + "pc": [ + 2695 + ] + }, + { + "teal": 2698, + "source": 762, + "pc": [ + 2696 + ] + }, + { + "teal": 2699, + "source": 762, + "pc": [ + 2697 + ] + }, + { + "teal": 2700, + "source": 762, + "pc": [ + 2698 + ] + }, + { + "teal": 2701, + "source": 762, + "pc": [ + 2699 + ] + }, + { + "teal": 2704, + "source": 761, + "pc": [ + 2700, + 2701, + 2702 + ] + }, + { + "teal": 2705, + "source": 761, + "pc": [ + 2703 + ] + }, + { + "teal": 2706, + "source": 761, + "pc": [ + 2704 + ] + }, + { + "teal": 2721, + "source": 761, + "pc": [ + 2705, + 2706, + 2707 + ] + }, + { + "teal": 2724, + "source": 761, + "pc": [ + 2708 + ] + }, + { + "teal": 2725, + "source": 761, + "pc": [ + 2709, + 2710 + ] + }, + { + "teal": 2730, + "source": 768, + "pc": [ + 2711, + 2712 + ] + }, + { + "teal": 2731, + "source": 768, + "pc": [ + 2713, + 2714 + ] + }, + { + "teal": 2732, + "source": 768, + "pc": [ + 2715 + ] + }, + { + "teal": 2733, + "source": 768, + "pc": [ + 2716, + 2717, + 2718 + ] + }, + { + "teal": 2738, + "source": 769, + "pc": [ + 2719 + ] + }, + { + "teal": 2739, + "source": 769, + "pc": [ + 2720, + 2721 + ] + }, + { + "teal": 2740, + "source": 769, + "pc": [ + 2722, + 2723 + ] + }, + { + "teal": 2741, + "source": 769, + "pc": [ + 2724 + ] + }, + { + "teal": 2742, + "source": 769, + "pc": [ + 2725, + 2726 + ] + }, + { + "teal": 2743, + "source": 769, + "pc": [ + 2727, + 2728 + ] + }, + { + "teal": 2744, + "source": 769, + "pc": [ + 2729 + ] + }, + { + "teal": 2745, + "source": 769, + "pc": [ + 2730, + 2731 + ] + }, + { + "teal": 2746, + "source": 769, + "pc": [ + 2732, + 2733 + ] + }, + { + "teal": 2747, + "source": 769, + "pc": [ + 2734, + 2735 + ] + }, + { + "teal": 2748, + "source": 769, + "pc": [ + 2736, + 2737 + ] + }, + { + "teal": 2749, + "source": 769, + "pc": [ + 2738 + ] + }, + { + "teal": 2754, + "source": 771, + "pc": [ + 2739, + 2740 + ] + }, + { + "teal": 2755, + "source": 771, + "pc": [ + 2741, + 2742, + 2743 + ] + }, + { + "teal": 2759, + "source": 775, + "pc": [ + 2744, + 2745 + ] + }, + { + "teal": 2760, + "source": 775, + "pc": [ + 2746 + ] + }, + { + "teal": 2761, + "source": 775, + "pc": [ + 2747 + ] + }, + { + "teal": 2762, + "source": 775, + "pc": [ + 2748 + ] + }, + { + "teal": 2763, + "source": 775, + "pc": [ + 2749, + 2750, + 2751 + ] + }, + { + "teal": 2764, + "source": 775, + "pc": [ + 2752, + 2753 + ] + }, + { + "teal": 2765, + "source": 775, + "pc": [ + 2754 + ] + }, + { + "teal": 2766, + "source": 775, + "pc": [ + 2755 + ] + }, + { + "teal": 2767, + "source": 775, + "pc": [ + 2756 + ] + }, + { + "teal": 2770, + "source": 775, + "pc": [ + 2757 + ] + }, + { + "teal": 2774, + "source": 778, + "pc": [ + 2758, + 2759 + ] + }, + { + "teal": 2775, + "source": 778, + "pc": [ + 2760, + 2761 + ] + }, + { + "teal": 2776, + "source": 778, + "pc": [ + 2762, + 2763, + 2764 + ] + }, + { + "teal": 2777, + "source": 778, + "pc": [ + 2765 + ] + }, + { + "teal": 2778, + "source": 778, + "pc": [ + 2766 + ] + }, + { + "teal": 2779, + "source": 778, + "pc": [ + 2767 + ] + }, + { + "teal": 2780, + "source": 778, + "pc": [ + 2768, + 2769 + ] + }, + { + "teal": 2781, + "source": 778, + "pc": [ + 2770 + ] + }, + { + "teal": 2782, + "source": 778, + "pc": [ + 2771 + ] + }, + { + "teal": 2783, + "source": 778, + "pc": [ + 2772, + 2773 + ] + }, + { + "teal": 2784, + "source": 778, + "pc": [ + 2774 + ] + }, + { + "teal": 2785, + "source": 778, + "pc": [ + 2775, + 2776 + ] + }, + { + "teal": 2786, + "source": 778, + "pc": [ + 2777, + 2778 + ] + }, + { + "teal": 2787, + "source": 778, + "pc": [ + 2779, + 2780, + 2781 + ] + }, + { + "teal": 2788, + "source": 778, + "pc": [ + 2782 + ] + }, + { + "teal": 2789, + "source": 778, + "pc": [ + 2783 + ] + }, + { + "teal": 2790, + "source": 778, + "pc": [ + 2784 + ] + }, + { + "teal": 2791, + "source": 778, + "pc": [ + 2785, + 2786 + ] + }, + { + "teal": 2792, + "source": 778, + "pc": [ + 2787 + ] + }, + { + "teal": 2793, + "source": 778, + "pc": [ + 2788 + ] + }, + { + "teal": 2794, + "source": 778, + "pc": [ + 2789, + 2790 + ] + }, + { + "teal": 2795, + "source": 778, + "pc": [ + 2791 + ] + }, + { + "teal": 2796, + "source": 778, + "pc": [ + 2792 + ] + }, + { + "teal": 2797, + "source": 778, + "pc": [ + 2793 + ] + }, + { + "teal": 2798, + "source": 778, + "pc": [ + 2794, + 2795 + ] + }, + { + "teal": 2799, + "source": 778, + "pc": [ + 2796, + 2797, + 2798 + ] + }, + { + "teal": 2800, + "source": 778, + "pc": [ + 2799 + ] + }, + { + "teal": 2801, + "source": 778, + "pc": [ + 2800 + ] + }, + { + "teal": 2802, + "source": 778, + "pc": [ + 2801 + ] + }, + { + "teal": 2803, + "source": 778, + "pc": [ + 2802, + 2803 + ] + }, + { + "teal": 2804, + "source": 778, + "pc": [ + 2804 + ] + }, + { + "teal": 2805, + "source": 778, + "pc": [ + 2805 + ] + }, + { + "teal": 2806, + "source": 778, + "pc": [ + 2806, + 2807 + ] + }, + { + "teal": 2807, + "source": 778, + "pc": [ + 2808 + ] + }, + { + "teal": 2808, + "source": 778, + "pc": [ + 2809 + ] + }, + { + "teal": 2809, + "source": 778, + "pc": [ + 2810 + ] + }, + { + "teal": 2810, + "source": 778, + "pc": [ + 2811, + 2812 + ] + }, + { + "teal": 2811, + "source": 778, + "pc": [ + 2813, + 2814, + 2815 + ] + }, + { + "teal": 2812, + "source": 778, + "pc": [ + 2816 + ] + }, + { + "teal": 2813, + "source": 778, + "pc": [ + 2817 + ] + }, + { + "teal": 2814, + "source": 778, + "pc": [ + 2818 + ] + }, + { + "teal": 2815, + "source": 778, + "pc": [ + 2819, + 2820 + ] + }, + { + "teal": 2816, + "source": 778, + "pc": [ + 2821 + ] + }, + { + "teal": 2820, + "source": 779, + "pc": [ + 2822, + 2823 + ] + }, + { + "teal": 2821, + "source": 779, + "pc": [ + 2824 + ] + }, + { + "teal": 2822, + "source": 779, + "pc": [ + 2825 + ] + }, + { + "teal": 2823, + "source": 779, + "pc": [ + 2826 + ] + }, + { + "teal": 2824, + "source": 779, + "pc": [ + 2827, + 2828 + ] + }, + { + "teal": 2825, + "source": 779, + "pc": [ + 2829, + 2830, + 2831 + ] + }, + { + "teal": 2826, + "source": 779, + "pc": [ + 2832 + ] + }, + { + "teal": 2827, + "source": 779, + "pc": [ + 2833 + ] + }, + { + "teal": 2828, + "source": 779, + "pc": [ + 2834 + ] + }, + { + "teal": 2829, + "source": 779, + "pc": [ + 2835, + 2836 + ] + }, + { + "teal": 2830, + "source": 779, + "pc": [ + 2837 + ] + }, + { + "teal": 2831, + "source": 779, + "pc": [ + 2838 + ] + }, + { + "teal": 2832, + "source": 779, + "pc": [ + 2839, + 2840 + ] + }, + { + "teal": 2833, + "source": 779, + "pc": [ + 2841 + ] + }, + { + "teal": 2834, + "source": 779, + "pc": [ + 2842 + ] + }, + { + "teal": 2835, + "source": 779, + "pc": [ + 2843 + ] + }, + { + "teal": 2836, + "source": 779, + "pc": [ + 2844, + 2845 + ] + }, + { + "teal": 2837, + "source": 779, + "pc": [ + 2846, + 2847, + 2848 + ] + }, + { + "teal": 2838, + "source": 779, + "pc": [ + 2849 + ] + }, + { + "teal": 2839, + "source": 779, + "pc": [ + 2850 + ] + }, + { + "teal": 2840, + "source": 779, + "pc": [ + 2851 + ] + }, + { + "teal": 2841, + "source": 779, + "pc": [ + 2852, + 2853 + ] + }, + { + "teal": 2842, + "source": 779, + "pc": [ + 2854 + ] + }, + { + "teal": 2846, + "source": 780, + "pc": [ + 2855, + 2856 + ] + }, + { + "teal": 2847, + "source": 780, + "pc": [ + 2857 + ] + }, + { + "teal": 2848, + "source": 780, + "pc": [ + 2858, + 2859 + ] + }, + { + "teal": 2849, + "source": 780, + "pc": [ + 2860 + ] + }, + { + "teal": 2850, + "source": 780, + "pc": [ + 2861, + 2862 + ] + }, + { + "teal": 2851, + "source": 780, + "pc": [ + 2863 + ] + }, + { + "teal": 2852, + "source": 780, + "pc": [ + 2864 + ] + }, + { + "teal": 2857, + "source": 782, + "pc": [ + 2865, + 2866 + ] + }, + { + "teal": 2858, + "source": 782, + "pc": [ + 2867 + ] + }, + { + "teal": 2859, + "source": 782, + "pc": [ + 2868 + ] + }, + { + "teal": 2860, + "source": 782, + "pc": [ + 2869, + 2870, + 2871 + ] + }, + { + "teal": 2865, + "source": 783, + "pc": [ + 2872, + 2873 + ] + }, + { + "teal": 2866, + "source": 783, + "pc": [ + 2874 + ] + }, + { + "teal": 2867, + "source": 783, + "pc": [ + 2875 + ] + }, + { + "teal": 2868, + "source": 783, + "pc": [ + 2876, + 2877 + ] + }, + { + "teal": 2869, + "source": 783, + "pc": [ + 2878, + 2879, + 2880 + ] + }, + { + "teal": 2870, + "source": 783, + "pc": [ + 2881 + ] + }, + { + "teal": 2871, + "source": 783, + "pc": [ + 2882 + ] + }, + { + "teal": 2872, + "source": 783, + "pc": [ + 2883 + ] + }, + { + "teal": 2873, + "source": 783, + "pc": [ + 2884, + 2885 + ] + }, + { + "teal": 2874, + "source": 783, + "pc": [ + 2886 + ] + }, + { + "teal": 2875, + "source": 783, + "pc": [ + 2887 + ] + }, + { + "teal": 2876, + "source": 783, + "pc": [ + 2888, + 2889 + ] + }, + { + "teal": 2880, + "source": 784, + "pc": [ + 2890, + 2891 + ] + }, + { + "teal": 2881, + "source": 784, + "pc": [ + 2892 + ] + }, + { + "teal": 2882, + "source": 784, + "pc": [ + 2893 + ] + }, + { + "teal": 2885, + "source": 784, + "pc": [ + 2894 + ] + }, + { + "teal": 2892, + "source": 786, + "pc": [ + 2895, + 2896 + ] + }, + { + "teal": 2893, + "source": 786, + "pc": [ + 2897 + ] + }, + { + "teal": 2894, + "source": 786, + "pc": [ + 2898 + ] + }, + { + "teal": 2895, + "source": 786, + "pc": [ + 2899, + 2900 + ] + }, + { + "teal": 2896, + "source": 786, + "pc": [ + 2901, + 2902, + 2903 + ] + }, + { + "teal": 2897, + "source": 786, + "pc": [ + 2904 + ] + }, + { + "teal": 2898, + "source": 786, + "pc": [ + 2905 + ] + }, + { + "teal": 2899, + "source": 786, + "pc": [ + 2906 + ] + }, + { + "teal": 2900, + "source": 786, + "pc": [ + 2907, + 2908 + ] + }, + { + "teal": 2901, + "source": 786, + "pc": [ + 2909 + ] + }, + { + "teal": 2902, + "source": 786, + "pc": [ + 2910 + ] + }, + { + "teal": 2903, + "source": 786, + "pc": [ + 2911, + 2912 + ] + }, + { + "teal": 2904, + "source": 786, + "pc": [ + 2913 + ] + }, + { + "teal": 2907, + "source": 785, + "pc": [ + 2914 + ] + }, + { + "teal": 2911, + "source": 791, + "pc": [ + 2915, + 2916 + ] + }, + { + "teal": 2912, + "source": 791, + "pc": [ + 2917 + ] + }, + { + "teal": 2913, + "source": 791, + "pc": [ + 2918 + ] + }, + { + "teal": 2914, + "source": 791, + "pc": [ + 2919 + ] + }, + { + "teal": 2915, + "source": 791, + "pc": [ + 2920, + 2921 + ] + }, + { + "teal": 2916, + "source": 791, + "pc": [ + 2922, + 2923, + 2924 + ] + }, + { + "teal": 2917, + "source": 791, + "pc": [ + 2925 + ] + }, + { + "teal": 2918, + "source": 791, + "pc": [ + 2926 + ] + }, + { + "teal": 2919, + "source": 791, + "pc": [ + 2927 + ] + }, + { + "teal": 2920, + "source": 791, + "pc": [ + 2928, + 2929 + ] + }, + { + "teal": 2921, + "source": 791, + "pc": [ + 2930 + ] + }, + { + "teal": 2922, + "source": 791, + "pc": [ + 2931 + ] + }, + { + "teal": 2923, + "source": 791, + "pc": [ + 2932, + 2933 + ] + }, + { + "teal": 2924, + "source": 791, + "pc": [ + 2934 + ] + }, + { + "teal": 2925, + "source": 791, + "pc": [ + 2935 + ] + }, + { + "teal": 2926, + "source": 791, + "pc": [ + 2936 + ] + }, + { + "teal": 2927, + "source": 791, + "pc": [ + 2937, + 2938 + ] + }, + { + "teal": 2928, + "source": 791, + "pc": [ + 2939, + 2940, + 2941 + ] + }, + { + "teal": 2929, + "source": 791, + "pc": [ + 2942 + ] + }, + { + "teal": 2930, + "source": 791, + "pc": [ + 2943 + ] + }, + { + "teal": 2931, + "source": 791, + "pc": [ + 2944 + ] + }, + { + "teal": 2932, + "source": 791, + "pc": [ + 2945, + 2946 + ] + }, + { + "teal": 2933, + "source": 791, + "pc": [ + 2947 + ] + }, + { + "teal": 2938, + "source": 796, + "pc": [ + 2948, + 2949 + ] + }, + { + "teal": 2939, + "source": 796, + "pc": [ + 2950, + 2951, + 2952 + ] + }, + { + "teal": 2940, + "source": 796, + "pc": [ + 2953 + ] + }, + { + "teal": 2941, + "source": 796, + "pc": [ + 2954 + ] + }, + { + "teal": 2942, + "source": 796, + "pc": [ + 2955 + ] + }, + { + "teal": 2943, + "source": 796, + "pc": [ + 2956, + 2957, + 2958 + ] + }, + { + "teal": 2951, + "source": 797, + "pc": [ + 2959 + ] + }, + { + "teal": 2952, + "source": 797, + "pc": [ + 2960, + 2961 + ] + }, + { + "teal": 2953, + "source": 797, + "pc": [ + 2962, + 2963 + ] + }, + { + "teal": 2954, + "source": 797, + "pc": [ + 2964, + 2965, + 2966, + 2967, + 2968, + 2969 + ] + }, + { + "teal": 2955, + "source": 797, + "pc": [ + 2970, + 2971 + ] + }, + { + "teal": 2959, + "source": 798, + "pc": [ + 2972, + 2973 + ] + }, + { + "teal": 2960, + "source": 798, + "pc": [ + 2974 + ] + }, + { + "teal": 2961, + "source": 798, + "pc": [ + 2975 + ] + }, + { + "teal": 2962, + "source": 798, + "pc": [ + 2976, + 2977 + ] + }, + { + "teal": 2963, + "source": 798, + "pc": [ + 2978, + 2979, + 2980 + ] + }, + { + "teal": 2964, + "source": 798, + "pc": [ + 2981 + ] + }, + { + "teal": 2965, + "source": 798, + "pc": [ + 2982 + ] + }, + { + "teal": 2966, + "source": 798, + "pc": [ + 2983 + ] + }, + { + "teal": 2967, + "source": 798, + "pc": [ + 2984, + 2985 + ] + }, + { + "teal": 2968, + "source": 798, + "pc": [ + 2986 + ] + }, + { + "teal": 2969, + "source": 798, + "pc": [ + 2987 + ] + }, + { + "teal": 2970, + "source": 798, + "pc": [ + 2988, + 2989 + ] + }, + { + "teal": 2974, + "source": 799, + "pc": [ + 2990, + 2991 + ] + }, + { + "teal": 2975, + "source": 799, + "pc": [ + 2992, + 2993 + ] + }, + { + "teal": 2976, + "source": 799, + "pc": [ + 2994, + 2995 + ] + }, + { + "teal": 2977, + "source": 799, + "pc": [ + 2996 + ] + }, + { + "teal": 2978, + "source": 799, + "pc": [ + 2997, + 2998 + ] + }, + { + "teal": 2979, + "source": 799, + "pc": [ + 2999, + 3000 + ] + }, + { + "teal": 2980, + "source": 799, + "pc": [ + 3001 + ] + }, + { + "teal": 2981, + "source": 799, + "pc": [ + 3002, + 3003 + ] + }, + { + "teal": 2984, + "source": 797, + "pc": [ + 3004 + ] + }, + { + "teal": 2985, + "source": 797, + "pc": [ + 3005, + 3006 + ] + }, + { + "teal": 2988, + "source": 797, + "pc": [ + 3007 + ] + }, + { + "teal": 2991, + "source": 782, + "pc": [ + 3008, + 3009, + 3010 + ] + }, + { + "teal": 2999, + "source": 824, + "pc": [ + 3011, + 3012 + ] + }, + { + "teal": 3000, + "source": 824, + "pc": [ + 3013, + 3014, + 3015 + ] + }, + { + "teal": 3005, + "source": 826, + "pc": [ + 3016, + 3017 + ] + }, + { + "teal": 3006, + "source": 826, + "pc": [ + 3018, + 3019 + ] + }, + { + "teal": 3007, + "source": 826, + "pc": [ + 3020, + 3021, + 3022 + ] + }, + { + "teal": 3008, + "source": 826, + "pc": [ + 3023 + ] + }, + { + "teal": 3009, + "source": 826, + "pc": [ + 3024 + ] + }, + { + "teal": 3010, + "source": 826, + "pc": [ + 3025 + ] + }, + { + "teal": 3011, + "source": 826, + "pc": [ + 3026, + 3027 + ] + }, + { + "teal": 3012, + "source": 826, + "pc": [ + 3028 + ] + }, + { + "teal": 3013, + "source": 826, + "pc": [ + 3029 + ] + }, + { + "teal": 3014, + "source": 826, + "pc": [ + 3030 + ] + }, + { + "teal": 3015, + "source": 826, + "pc": [ + 3031 + ] + }, + { + "teal": 3016, + "source": 826, + "pc": [ + 3032, + 3033 + ] + }, + { + "teal": 3017, + "source": 826, + "pc": [ + 3034, + 3035 + ] + }, + { + "teal": 3018, + "source": 826, + "pc": [ + 3036, + 3037, + 3038 + ] + }, + { + "teal": 3019, + "source": 826, + "pc": [ + 3039 + ] + }, + { + "teal": 3020, + "source": 826, + "pc": [ + 3040 + ] + }, + { + "teal": 3021, + "source": 826, + "pc": [ + 3041 + ] + }, + { + "teal": 3022, + "source": 826, + "pc": [ + 3042, + 3043 + ] + }, + { + "teal": 3023, + "source": 826, + "pc": [ + 3044 + ] + }, + { + "teal": 3024, + "source": 826, + "pc": [ + 3045 + ] + }, + { + "teal": 3025, + "source": 826, + "pc": [ + 3046 + ] + }, + { + "teal": 3026, + "source": 826, + "pc": [ + 3047 + ] + }, + { + "teal": 3027, + "source": 826, + "pc": [ + 3048, + 3049 + ] + }, + { + "teal": 3028, + "source": 826, + "pc": [ + 3050 + ] + }, + { + "teal": 3029, + "source": 826, + "pc": [ + 3051, + 3052 + ] + }, + { + "teal": 3030, + "source": 826, + "pc": [ + 3053, + 3054, + 3055 + ] + }, + { + "teal": 3031, + "source": 826, + "pc": [ + 3056 + ] + }, + { + "teal": 3032, + "source": 826, + "pc": [ + 3057 + ] + }, + { + "teal": 3033, + "source": 826, + "pc": [ + 3058 + ] + }, + { + "teal": 3034, + "source": 826, + "pc": [ + 3059, + 3060 + ] + }, + { + "teal": 3035, + "source": 826, + "pc": [ + 3061 + ] + }, + { + "teal": 3036, + "source": 826, + "pc": [ + 3062 + ] + }, + { + "teal": 3037, + "source": 826, + "pc": [ + 3063 + ] + }, + { + "teal": 3038, + "source": 826, + "pc": [ + 3064 + ] + }, + { + "teal": 3039, + "source": 826, + "pc": [ + 3065 + ] + }, + { + "teal": 3040, + "source": 826, + "pc": [ + 3066, + 3067, + 3068 + ] + }, + { + "teal": 3041, + "source": 826, + "pc": [ + 3069 + ] + }, + { + "teal": 3042, + "source": 826, + "pc": [ + 3070, + 3071 + ] + }, + { + "teal": 3043, + "source": 826, + "pc": [ + 3072, + 3073, + 3074 + ] + }, + { + "teal": 3044, + "source": 826, + "pc": [ + 3075 + ] + }, + { + "teal": 3045, + "source": 826, + "pc": [ + 3076 + ] + }, + { + "teal": 3046, + "source": 826, + "pc": [ + 3077 + ] + }, + { + "teal": 3047, + "source": 826, + "pc": [ + 3078, + 3079 + ] + }, + { + "teal": 3048, + "source": 826, + "pc": [ + 3080 + ] + }, + { + "teal": 3056, + "source": 829, + "pc": [ + 3081, + 3082 + ] + }, + { + "teal": 3057, + "source": 829, + "pc": [ + 3083, + 3084, + 3085 + ] + }, + { + "teal": 3058, + "source": 829, + "pc": [ + 3086 + ] + }, + { + "teal": 3059, + "source": 829, + "pc": [ + 3087 + ] + }, + { + "teal": 3060, + "source": 830, + "pc": [ + 3088, + 3089 + ] + }, + { + "teal": 3061, + "source": 830, + "pc": [ + 3090, + 3091, + 3092 + ] + }, + { + "teal": 3062, + "source": 830, + "pc": [ + 3093 + ] + }, + { + "teal": 3063, + "source": 830, + "pc": [ + 3094 + ] + }, + { + "teal": 3064, + "source": 830, + "pc": [ + 3095 + ] + }, + { + "teal": 3065, + "source": 831, + "pc": [ + 3096, + 3097 + ] + }, + { + "teal": 3066, + "source": 831, + "pc": [ + 3098, + 3099, + 3100 + ] + }, + { + "teal": 3067, + "source": 831, + "pc": [ + 3101 + ] + }, + { + "teal": 3068, + "source": 831, + "pc": [ + 3102 + ] + }, + { + "teal": 3069, + "source": 831, + "pc": [ + 3103 + ] + }, + { + "teal": 3070, + "source": 828, + "pc": [ + 3104, + 3105 + ] + }, + { + "teal": 3071, + "source": 828, + "pc": [ + 3106, + 3107, + 3108 + ] + }, + { + "teal": 3072, + "source": 828, + "pc": [ + 3109, + 3110 + ] + }, + { + "teal": 3076, + "source": 833, + "pc": [ + 3111, + 3112 + ] + }, + { + "teal": 3077, + "source": 833, + "pc": [ + 3113, + 3114 + ] + }, + { + "teal": 3078, + "source": 833, + "pc": [ + 3115, + 3116 + ] + }, + { + "teal": 3079, + "source": 833, + "pc": [ + 3117 + ] + }, + { + "teal": 3080, + "source": 833, + "pc": [ + 3118 + ] + }, + { + "teal": 3081, + "source": 833, + "pc": [ + 3119, + 3120 + ] + }, + { + "teal": 3085, + "source": 834, + "pc": [ + 3121, + 3122 + ] + }, + { + "teal": 3086, + "source": 834, + "pc": [ + 3123, + 3124 + ] + }, + { + "teal": 3087, + "source": 834, + "pc": [ + 3125, + 3126 + ] + }, + { + "teal": 3088, + "source": 834, + "pc": [ + 3127 + ] + }, + { + "teal": 3089, + "source": 834, + "pc": [ + 3128 + ] + }, + { + "teal": 3090, + "source": 834, + "pc": [ + 3129, + 3130 + ] + }, + { + "teal": 3095, + "source": 836, + "pc": [ + 3131, + 3132 + ] + }, + { + "teal": 3096, + "source": 836, + "pc": [ + 3133, + 3134, + 3135 + ] + }, + { + "teal": 3101, + "source": 837, + "pc": [ + 3136, + 3137 + ] + }, + { + "teal": 3102, + "source": 837, + "pc": [ + 3138 + ] + }, + { + "teal": 3103, + "source": 837, + "pc": [ + 3139 + ] + }, + { + "teal": 3104, + "source": 837, + "pc": [ + 3140 + ] + }, + { + "teal": 3105, + "source": 837, + "pc": [ + 3141, + 3142 + ] + }, + { + "teal": 3106, + "source": 837, + "pc": [ + 3143, + 3144, + 3145 + ] + }, + { + "teal": 3107, + "source": 837, + "pc": [ + 3146 + ] + }, + { + "teal": 3108, + "source": 837, + "pc": [ + 3147 + ] + }, + { + "teal": 3109, + "source": 837, + "pc": [ + 3148 + ] + }, + { + "teal": 3110, + "source": 837, + "pc": [ + 3149, + 3150 + ] + }, + { + "teal": 3111, + "source": 837, + "pc": [ + 3151 + ] + }, + { + "teal": 3112, + "source": 837, + "pc": [ + 3152 + ] + }, + { + "teal": 3113, + "source": 837, + "pc": [ + 3153 + ] + }, + { + "teal": 3114, + "source": 837, + "pc": [ + 3154 + ] + }, + { + "teal": 3115, + "source": 837, + "pc": [ + 3155 + ] + }, + { + "teal": 3116, + "source": 837, + "pc": [ + 3156 + ] + }, + { + "teal": 3117, + "source": 837, + "pc": [ + 3157, + 3158 + ] + }, + { + "teal": 3118, + "source": 837, + "pc": [ + 3159, + 3160, + 3161 + ] + }, + { + "teal": 3119, + "source": 837, + "pc": [ + 3162 + ] + }, + { + "teal": 3120, + "source": 837, + "pc": [ + 3163 + ] + }, + { + "teal": 3121, + "source": 837, + "pc": [ + 3164 + ] + }, + { + "teal": 3122, + "source": 837, + "pc": [ + 3165, + 3166 + ] + }, + { + "teal": 3123, + "source": 837, + "pc": [ + 3167 + ] + }, + { + "teal": 3129, + "source": 840, + "pc": [ + 3168, + 3169 + ] + }, + { + "teal": 3130, + "source": 840, + "pc": [ + 3170, + 3171, + 3172 + ] + }, + { + "teal": 3135, + "source": 841, + "pc": [ + 3173, + 3174 + ] + }, + { + "teal": 3136, + "source": 841, + "pc": [ + 3175 + ] + }, + { + "teal": 3137, + "source": 841, + "pc": [ + 3176 + ] + }, + { + "teal": 3138, + "source": 841, + "pc": [ + 3177 + ] + }, + { + "teal": 3139, + "source": 841, + "pc": [ + 3178, + 3179 + ] + }, + { + "teal": 3140, + "source": 841, + "pc": [ + 3180 + ] + }, + { + "teal": 3141, + "source": 841, + "pc": [ + 3181 + ] + }, + { + "teal": 3146, + "source": 761, + "pc": [ + 3182 + ] + }, + { + "teal": 3151, + "source": 857, + "pc": [ + 3183 + ] + }, + { + "teal": 3154, + "source": 860, + "pc": [ + 3184, + 3185, + 3186 + ] + }, + { + "teal": 3155, + "source": 860, + "pc": [ + 3187 + ] + }, + { + "teal": 3158, + "source": 859, + "pc": [ + 3188, + 3189, + 3190 + ] + }, + { + "teal": 3159, + "source": 859, + "pc": [ + 3191 + ] + }, + { + "teal": 3160, + "source": 859, + "pc": [ + 3192 + ] + }, + { + "teal": 3161, + "source": 859, + "pc": [ + 3193, + 3194 + ] + }, + { + "teal": 3162, + "source": 859, + "pc": [ + 3195 + ] + }, + { + "teal": 3163, + "source": 859, + "pc": [ + 3196 + ] + }, + { + "teal": 3166, + "source": 858, + "pc": [ + 3197, + 3198, + 3199 + ] + }, + { + "teal": 3167, + "source": 858, + "pc": [ + 3200 + ] + }, + { + "teal": 3170, + "source": 857, + "pc": [ + 3201, + 3202, + 3203 + ] + }, + { + "teal": 3171, + "source": 857, + "pc": [ + 3204 + ] + }, + { + "teal": 3172, + "source": 857, + "pc": [ + 3205 + ] + }, + { + "teal": 3173, + "source": 857, + "pc": [ + 3206 + ] + }, + { + "teal": 3174, + "source": 857, + "pc": [ + 3207 + ] + }, + { + "teal": 3188, + "source": 857, + "pc": [ + 3208, + 3209, + 3210 + ] + }, + { + "teal": 3191, + "source": 857, + "pc": [ + 3211 + ] + }, + { + "teal": 3192, + "source": 857, + "pc": [ + 3212, + 3213 + ] + }, + { + "teal": 3196, + "source": 862, + "pc": [ + 3214 + ] + }, + { + "teal": 3197, + "source": 862, + "pc": [ + 3215, + 3216 + ] + }, + { + "teal": 3201, + "source": 863, + "pc": [ + 3217 + ] + }, + { + "teal": 3202, + "source": 863, + "pc": [ + 3218, + 3219 + ] + }, + { + "teal": 3206, + "source": 871, + "pc": [ + 3220, + 3221 + ] + }, + { + "teal": 3207, + "source": 871, + "pc": [ + 3222, + 3223, + 3224 + ] + }, + { + "teal": 3208, + "source": 871, + "pc": [ + 3225, + 3226 + ] + }, + { + "teal": 3213, + "source": 874, + "pc": [ + 3227 + ] + }, + { + "teal": 3214, + "source": 874, + "pc": [ + 3228, + 3229 + ] + }, + { + "teal": 3215, + "source": 874, + "pc": [ + 3230 + ] + }, + { + "teal": 3216, + "source": 874, + "pc": [ + 3231 + ] + }, + { + "teal": 3217, + "source": 874, + "pc": [ + 3232 + ] + }, + { + "teal": 3218, + "source": 874, + "pc": [ + 3233 + ] + }, + { + "teal": 3219, + "source": 874, + "pc": [ + 3234, + 3235, + 3236 + ] + }, + { + "teal": 3224, + "source": 875, + "pc": [ + 3237 + ] + }, + { + "teal": 3225, + "source": 875, + "pc": [ + 3238, + 3239 + ] + }, + { + "teal": 3226, + "source": 875, + "pc": [ + 3240 + ] + }, + { + "teal": 3227, + "source": 875, + "pc": [ + 3241 + ] + }, + { + "teal": 3228, + "source": 875, + "pc": [ + 3242 + ] + }, + { + "teal": 3229, + "source": 875, + "pc": [ + 3243, + 3244 + ] + }, + { + "teal": 3233, + "source": 876, + "pc": [ + 3245, + 3246 + ] + }, + { + "teal": 3234, + "source": 876, + "pc": [ + 3247 + ] + }, + { + "teal": 3235, + "source": 876, + "pc": [ + 3248 + ] + }, + { + "teal": 3236, + "source": 876, + "pc": [ + 3249 + ] + }, + { + "teal": 3240, + "source": 877, + "pc": [ + 3250 + ] + }, + { + "teal": 3241, + "source": 877, + "pc": [ + 3251, + 3252 + ] + }, + { + "teal": 3246, + "source": 877, + "pc": [ + 3253, + 3254 + ] + }, + { + "teal": 3247, + "source": 877, + "pc": [ + 3255, + 3256 + ] + }, + { + "teal": 3248, + "source": 877, + "pc": [ + 3257 + ] + }, + { + "teal": 3249, + "source": 877, + "pc": [ + 3258, + 3259, + 3260 + ] + }, + { + "teal": 3254, + "source": 878, + "pc": [ + 3261, + 3262 + ] + }, + { + "teal": 3255, + "source": 878, + "pc": [ + 3263, + 3264 + ] + }, + { + "teal": 3256, + "source": 878, + "pc": [ + 3265 + ] + }, + { + "teal": 3257, + "source": 878, + "pc": [ + 3266, + 3267, + 3268 + ] + }, + { + "teal": 3262, + "source": 879, + "pc": [ + 3269 + ] + }, + { + "teal": 3263, + "source": 879, + "pc": [ + 3270, + 3271 + ] + }, + { + "teal": 3264, + "source": 879, + "pc": [ + 3272, + 3273 + ] + }, + { + "teal": 3265, + "source": 879, + "pc": [ + 3274 + ] + }, + { + "teal": 3266, + "source": 879, + "pc": [ + 3275, + 3276 + ] + }, + { + "teal": 3267, + "source": 879, + "pc": [ + 3277, + 3278 + ] + }, + { + "teal": 3268, + "source": 879, + "pc": [ + 3279 + ] + }, + { + "teal": 3269, + "source": 879, + "pc": [ + 3280, + 3281 + ] + }, + { + "teal": 3270, + "source": 879, + "pc": [ + 3282, + 3283 + ] + }, + { + "teal": 3271, + "source": 879, + "pc": [ + 3284, + 3285 + ] + }, + { + "teal": 3272, + "source": 879, + "pc": [ + 3286, + 3287 + ] + }, + { + "teal": 3273, + "source": 879, + "pc": [ + 3288 + ] + }, + { + "teal": 3279, + "source": 881, + "pc": [ + 3289, + 3290 + ] + }, + { + "teal": 3280, + "source": 881, + "pc": [ + 3291, + 3292 + ] + }, + { + "teal": 3281, + "source": 881, + "pc": [ + 3293 + ] + }, + { + "teal": 3282, + "source": 881, + "pc": [ + 3294 + ] + }, + { + "teal": 3283, + "source": 881, + "pc": [ + 3295 + ] + }, + { + "teal": 3284, + "source": 881, + "pc": [ + 3296 + ] + }, + { + "teal": 3285, + "source": 881, + "pc": [ + 3297 + ] + }, + { + "teal": 3286, + "source": 881, + "pc": [ + 3298 + ] + }, + { + "teal": 3287, + "source": 881, + "pc": [ + 3299 + ] + }, + { + "teal": 3288, + "source": 881, + "pc": [ + 3300 + ] + }, + { + "teal": 3289, + "source": 881, + "pc": [ + 3301 + ] + }, + { + "teal": 3290, + "source": 881, + "pc": [ + 3302, + 3303, + 3304 + ] + }, + { + "teal": 3293, + "source": 882, + "pc": [ + 3305, + 3306, + 3307 + ] + }, + { + "teal": 3298, + "source": 884, + "pc": [ + 3308 + ] + }, + { + "teal": 3299, + "source": 884, + "pc": [ + 3309, + 3310 + ] + }, + { + "teal": 3304, + "source": 885, + "pc": [ + 3311, + 3312 + ] + }, + { + "teal": 3305, + "source": 885, + "pc": [ + 3313, + 3314 + ] + }, + { + "teal": 3306, + "source": 885, + "pc": [ + 3315 + ] + }, + { + "teal": 3307, + "source": 885, + "pc": [ + 3316 + ] + }, + { + "teal": 3308, + "source": 885, + "pc": [ + 3317 + ] + }, + { + "teal": 3309, + "source": 885, + "pc": [ + 3318 + ] + }, + { + "teal": 3310, + "source": 885, + "pc": [ + 3319 + ] + }, + { + "teal": 3311, + "source": 885, + "pc": [ + 3320 + ] + }, + { + "teal": 3312, + "source": 885, + "pc": [ + 3321 + ] + }, + { + "teal": 3313, + "source": 885, + "pc": [ + 3322, + 3323 + ] + }, + { + "teal": 3314, + "source": 885, + "pc": [ + 3324 + ] + }, + { + "teal": 3315, + "source": 885, + "pc": [ + 3325, + 3326, + 3327 + ] + }, + { + "teal": 3320, + "source": 887, + "pc": [ + 3328 + ] + }, + { + "teal": 3321, + "source": 887, + "pc": [ + 3329, + 3330 + ] + }, + { + "teal": 3328, + "source": 889, + "pc": [ + 3331, + 3332 + ] + }, + { + "teal": 3329, + "source": 889, + "pc": [ + 3333, + 3334 + ] + }, + { + "teal": 3330, + "source": 889, + "pc": [ + 3335, + 3336 + ] + }, + { + "teal": 3331, + "source": 889, + "pc": [ + 3337 + ] + }, + { + "teal": 3332, + "source": 889, + "pc": [ + 3338 + ] + }, + { + "teal": 3333, + "source": 889, + "pc": [ + 3339 + ] + }, + { + "teal": 3334, + "source": 889, + "pc": [ + 3340 + ] + }, + { + "teal": 3335, + "source": 889, + "pc": [ + 3341 + ] + }, + { + "teal": 3336, + "source": 889, + "pc": [ + 3342 + ] + }, + { + "teal": 3337, + "source": 889, + "pc": [ + 3343 + ] + }, + { + "teal": 3338, + "source": 889, + "pc": [ + 3344 + ] + }, + { + "teal": 3339, + "source": 889, + "pc": [ + 3345 + ] + }, + { + "teal": 3340, + "source": 889, + "pc": [ + 3346, + 3347 + ] + }, + { + "teal": 3341, + "source": 889, + "pc": [ + 3348 + ] + }, + { + "teal": 3342, + "source": 889, + "pc": [ + 3349 + ] + }, + { + "teal": 3343, + "source": 889, + "pc": [ + 3350, + 3351 + ] + }, + { + "teal": 3344, + "source": 889, + "pc": [ + 3352 + ] + }, + { + "teal": 3345, + "source": 889, + "pc": [ + 3353 + ] + }, + { + "teal": 3346, + "source": 889, + "pc": [ + 3354 + ] + }, + { + "teal": 3347, + "source": 889, + "pc": [ + 3355, + 3356 + ] + }, + { + "teal": 3348, + "source": 889, + "pc": [ + 3357 + ] + }, + { + "teal": 3349, + "source": 889, + "pc": [ + 3358 + ] + }, + { + "teal": 3350, + "source": 889, + "pc": [ + 3359, + 3360 + ] + }, + { + "teal": 3351, + "source": 889, + "pc": [ + 3361 + ] + }, + { + "teal": 3352, + "source": 889, + "pc": [ + 3362 + ] + }, + { + "teal": 3353, + "source": 890, + "pc": [ + 3363, + 3364 + ] + }, + { + "teal": 3354, + "source": 889, + "pc": [ + 3365 + ] + }, + { + "teal": 3355, + "source": 891, + "pc": [ + 3366, + 3367 + ] + }, + { + "teal": 3356, + "source": 890, + "pc": [ + 3368 + ] + }, + { + "teal": 3357, + "source": 888, + "pc": [ + 3369, + 3370, + 3371 + ] + }, + { + "teal": 3362, + "source": 893, + "pc": [ + 3372, + 3373 + ] + }, + { + "teal": 3363, + "source": 893, + "pc": [ + 3374, + 3375 + ] + }, + { + "teal": 3364, + "source": 893, + "pc": [ + 3376 + ] + }, + { + "teal": 3365, + "source": 893, + "pc": [ + 3377 + ] + }, + { + "teal": 3366, + "source": 893, + "pc": [ + 3378 + ] + }, + { + "teal": 3367, + "source": 893, + "pc": [ + 3379 + ] + }, + { + "teal": 3368, + "source": 893, + "pc": [ + 3380, + 3381 + ] + }, + { + "teal": 3369, + "source": 893, + "pc": [ + 3382 + ] + }, + { + "teal": 3370, + "source": 893, + "pc": [ + 3383, + 3384 + ] + }, + { + "teal": 3371, + "source": 893, + "pc": [ + 3385 + ] + }, + { + "teal": 3372, + "source": 893, + "pc": [ + 3386 + ] + }, + { + "teal": 3373, + "source": 893, + "pc": [ + 3387, + 3388 + ] + }, + { + "teal": 3374, + "source": 893, + "pc": [ + 3389 + ] + }, + { + "teal": 3375, + "source": 893, + "pc": [ + 3390 + ] + }, + { + "teal": 3378, + "source": 893, + "pc": [ + 3391, + 3392 + ] + }, + { + "teal": 3381, + "source": 893, + "pc": [ + 3393, + 3394 + ] + }, + { + "teal": 3382, + "source": 893, + "pc": [ + 3395 + ] + }, + { + "teal": 3391, + "source": 877, + "pc": [ + 3396, + 3397 + ] + }, + { + "teal": 3392, + "source": 877, + "pc": [ + 3398 + ] + }, + { + "teal": 3393, + "source": 877, + "pc": [ + 3399 + ] + }, + { + "teal": 3394, + "source": 877, + "pc": [ + 3400, + 3401 + ] + }, + { + "teal": 3395, + "source": 877, + "pc": [ + 3402, + 3403, + 3404 + ] + }, + { + "teal": 3405, + "source": 901, + "pc": [ + 3405, + 3406 + ] + }, + { + "teal": 3406, + "source": 901, + "pc": [ + 3407, + 3408 + ] + }, + { + "teal": 3407, + "source": 901, + "pc": [ + 3409 + ] + }, + { + "teal": 3408, + "source": 901, + "pc": [ + 3410 + ] + }, + { + "teal": 3409, + "source": 901, + "pc": [ + 3411, + 3412 + ] + }, + { + "teal": 3410, + "source": 901, + "pc": [ + 3413 + ] + }, + { + "teal": 3411, + "source": 901, + "pc": [ + 3414 + ] + }, + { + "teal": 3412, + "source": 901, + "pc": [ + 3415, + 3416 + ] + }, + { + "teal": 3413, + "source": 901, + "pc": [ + 3417 + ] + }, + { + "teal": 3414, + "source": 901, + "pc": [ + 3418 + ] + }, + { + "teal": 3415, + "source": 901, + "pc": [ + 3419 + ] + }, + { + "teal": 3418, + "source": 900, + "pc": [ + 3420 + ] + }, + { + "teal": 3422, + "source": 906, + "pc": [ + 3421, + 3422 + ] + }, + { + "teal": 3423, + "source": 906, + "pc": [ + 3423, + 3424 + ] + }, + { + "teal": 3424, + "source": 906, + "pc": [ + 3425 + ] + }, + { + "teal": 3425, + "source": 906, + "pc": [ + 3426, + 3427 + ] + }, + { + "teal": 3426, + "source": 906, + "pc": [ + 3428 + ] + }, + { + "teal": 3427, + "source": 906, + "pc": [ + 3429 + ] + }, + { + "teal": 3428, + "source": 906, + "pc": [ + 3430, + 3431 + ] + }, + { + "teal": 3429, + "source": 906, + "pc": [ + 3432 + ] + }, + { + "teal": 3430, + "source": 906, + "pc": [ + 3433, + 3434 + ] + }, + { + "teal": 3434, + "source": 907, + "pc": [ + 3435, + 3436 + ] + }, + { + "teal": 3435, + "source": 907, + "pc": [ + 3437, + 3438 + ] + }, + { + "teal": 3436, + "source": 907, + "pc": [ + 3439 + ] + }, + { + "teal": 3437, + "source": 907, + "pc": [ + 3440, + 3441 + ] + }, + { + "teal": 3438, + "source": 907, + "pc": [ + 3442 + ] + }, + { + "teal": 3439, + "source": 907, + "pc": [ + 3443 + ] + }, + { + "teal": 3440, + "source": 907, + "pc": [ + 3444, + 3445 + ] + }, + { + "teal": 3441, + "source": 907, + "pc": [ + 3446 + ] + }, + { + "teal": 3442, + "source": 907, + "pc": [ + 3447 + ] + }, + { + "teal": 3443, + "source": 907, + "pc": [ + 3448, + 3449 + ] + }, + { + "teal": 3447, + "source": 908, + "pc": [ + 3450 + ] + }, + { + "teal": 3448, + "source": 908, + "pc": [ + 3451, + 3452 + ] + }, + { + "teal": 3453, + "source": 908, + "pc": [ + 3453, + 3454 + ] + }, + { + "teal": 3454, + "source": 908, + "pc": [ + 3455, + 3456 + ] + }, + { + "teal": 3455, + "source": 908, + "pc": [ + 3457 + ] + }, + { + "teal": 3456, + "source": 908, + "pc": [ + 3458, + 3459, + 3460 + ] + }, + { + "teal": 3461, + "source": 909, + "pc": [ + 3461, + 3462 + ] + }, + { + "teal": 3462, + "source": 909, + "pc": [ + 3463, + 3464 + ] + }, + { + "teal": 3463, + "source": 909, + "pc": [ + 3465, + 3466 + ] + }, + { + "teal": 3464, + "source": 909, + "pc": [ + 3467 + ] + }, + { + "teal": 3465, + "source": 909, + "pc": [ + 3468, + 3469 + ] + }, + { + "teal": 3466, + "source": 909, + "pc": [ + 3470 + ] + }, + { + "teal": 3467, + "source": 909, + "pc": [ + 3471 + ] + }, + { + "teal": 3468, + "source": 909, + "pc": [ + 3472 + ] + }, + { + "teal": 3469, + "source": 909, + "pc": [ + 3473 + ] + }, + { + "teal": 3470, + "source": 909, + "pc": [ + 3474, + 3475 + ] + }, + { + "teal": 3471, + "source": 909, + "pc": [ + 3476 + ] + }, + { + "teal": 3472, + "source": 909, + "pc": [ + 3477, + 3478 + ] + }, + { + "teal": 3473, + "source": 909, + "pc": [ + 3479 + ] + }, + { + "teal": 3474, + "source": 909, + "pc": [ + 3480, + 3481, + 3482 + ] + }, + { + "teal": 3483, + "source": 911, + "pc": [ + 3483, + 3484 + ] + }, + { + "teal": 3484, + "source": 911, + "pc": [ + 3485 + ] + }, + { + "teal": 3485, + "source": 911, + "pc": [ + 3486, + 3487 + ] + }, + { + "teal": 3486, + "source": 911, + "pc": [ + 3488 + ] + }, + { + "teal": 3487, + "source": 911, + "pc": [ + 3489 + ] + }, + { + "teal": 3488, + "source": 911, + "pc": [ + 3490 + ] + }, + { + "teal": 3489, + "source": 911, + "pc": [ + 3491 + ] + }, + { + "teal": 3490, + "source": 911, + "pc": [ + 3492, + 3493 + ] + }, + { + "teal": 3491, + "source": 911, + "pc": [ + 3494, + 3495 + ] + }, + { + "teal": 3492, + "source": 911, + "pc": [ + 3496, + 3497 + ] + }, + { + "teal": 3493, + "source": 911, + "pc": [ + 3498 + ] + }, + { + "teal": 3494, + "source": 911, + "pc": [ + 3499 + ] + }, + { + "teal": 3495, + "source": 911, + "pc": [ + 3500 + ] + }, + { + "teal": 3496, + "source": 911, + "pc": [ + 3501 + ] + }, + { + "teal": 3497, + "source": 911, + "pc": [ + 3502 + ] + }, + { + "teal": 3498, + "source": 911, + "pc": [ + 3503 + ] + }, + { + "teal": 3499, + "source": 911, + "pc": [ + 3504 + ] + }, + { + "teal": 3500, + "source": 911, + "pc": [ + 3505 + ] + }, + { + "teal": 3501, + "source": 912, + "pc": [ + 3506, + 3507 + ] + }, + { + "teal": 3502, + "source": 912, + "pc": [ + 3508 + ] + }, + { + "teal": 3503, + "source": 912, + "pc": [ + 3509, + 3510 + ] + }, + { + "teal": 3504, + "source": 912, + "pc": [ + 3511 + ] + }, + { + "teal": 3505, + "source": 913, + "pc": [ + 3512 + ] + }, + { + "teal": 3506, + "source": 913, + "pc": [ + 3513, + 3514 + ] + }, + { + "teal": 3507, + "source": 913, + "pc": [ + 3515 + ] + }, + { + "teal": 3508, + "source": 910, + "pc": [ + 3516 + ] + }, + { + "teal": 3511, + "source": 910, + "pc": [ + 3517, + 3518 + ] + }, + { + "teal": 3514, + "source": 910, + "pc": [ + 3519, + 3520 + ] + }, + { + "teal": 3515, + "source": 910, + "pc": [ + 3521 + ] + }, + { + "teal": 3522, + "source": 908, + "pc": [ + 3522, + 3523 + ] + }, + { + "teal": 3523, + "source": 908, + "pc": [ + 3524 + ] + }, + { + "teal": 3524, + "source": 908, + "pc": [ + 3525 + ] + }, + { + "teal": 3525, + "source": 908, + "pc": [ + 3526, + 3527 + ] + }, + { + "teal": 3526, + "source": 908, + "pc": [ + 3528, + 3529, + 3530 + ] + }, + { + "teal": 3531, + "source": 918, + "pc": [ + 3531, + 3532 + ] + }, + { + "teal": 3532, + "source": 918, + "pc": [ + 3533 + ] + }, + { + "teal": 3533, + "source": 918, + "pc": [ + 3534, + 3535 + ] + }, + { + "teal": 3534, + "source": 918, + "pc": [ + 3536 + ] + }, + { + "teal": 3535, + "source": 918, + "pc": [ + 3537, + 3538 + ] + }, + { + "teal": 3536, + "source": 918, + "pc": [ + 3539 + ] + }, + { + "teal": 3537, + "source": 918, + "pc": [ + 3540, + 3541 + ] + }, + { + "teal": 3538, + "source": 918, + "pc": [ + 3542 + ] + }, + { + "teal": 3539, + "source": 918, + "pc": [ + 3543, + 3544 + ] + }, + { + "teal": 3540, + "source": 918, + "pc": [ + 3545 + ] + }, + { + "teal": 3541, + "source": 918, + "pc": [ + 3546 + ] + }, + { + "teal": 3542, + "source": 918, + "pc": [ + 3547, + 3548 + ] + }, + { + "teal": 3543, + "source": 918, + "pc": [ + 3549 + ] + }, + { + "teal": 3544, + "source": 918, + "pc": [ + 3550 + ] + }, + { + "teal": 3547, + "source": 918, + "pc": [ + 3551, + 3552 + ] + }, + { + "teal": 3550, + "source": 918, + "pc": [ + 3553, + 3554 + ] + }, + { + "teal": 3551, + "source": 918, + "pc": [ + 3555 + ] + }, + { + "teal": 3556, + "source": 929, + "pc": [ + 3556, + 3557, + 3558 + ] + }, + { + "teal": 3557, + "source": 929, + "pc": [ + 3559 + ] + }, + { + "teal": 3560, + "source": 929, + "pc": [ + 3560, + 3561, + 3562 + ] + }, + { + "teal": 3561, + "source": 929, + "pc": [ + 3563 + ] + }, + { + "teal": 3564, + "source": 929, + "pc": [ + 3564, + 3565, + 3566 + ] + }, + { + "teal": 3565, + "source": 929, + "pc": [ + 3567 + ] + }, + { + "teal": 3568, + "source": 929, + "pc": [ + 3568, + 3569, + 3570 + ] + }, + { + "teal": 3569, + "source": 929, + "pc": [ + 3571 + ] + }, + { + "teal": 3570, + "source": 929, + "pc": [ + 3572 + ] + }, + { + "teal": 3581, + "source": 929, + "pc": [ + 3573, + 3574, + 3575 + ] + }, + { + "teal": 3584, + "source": 929, + "pc": [ + 3576 + ] + }, + { + "teal": 3585, + "source": 929, + "pc": [ + 3577, + 3578 + ] + }, + { + "teal": 3592, + "source": 932, + "pc": [ + 3579, + 3580 + ] + }, + { + "teal": 3593, + "source": 932, + "pc": [ + 3581 + ] + }, + { + "teal": 3594, + "source": 932, + "pc": [ + 3582, + 3583 + ] + }, + { + "teal": 3595, + "source": 932, + "pc": [ + 3584 + ] + }, + { + "teal": 3596, + "source": 932, + "pc": [ + 3585, + 3586 + ] + }, + { + "teal": 3597, + "source": 932, + "pc": [ + 3587 + ] + }, + { + "teal": 3598, + "source": 932, + "pc": [ + 3588 + ] + }, + { + "teal": 3599, + "source": 932, + "pc": [ + 3589, + 3590 + ] + }, + { + "teal": 3600, + "source": 932, + "pc": [ + 3591 + ] + }, + { + "teal": 3601, + "source": 932, + "pc": [ + 3592 + ] + }, + { + "teal": 3602, + "source": 932, + "pc": [ + 3593 + ] + }, + { + "teal": 3603, + "source": 932, + "pc": [ + 3594, + 3595, + 3596 + ] + }, + { + "teal": 3604, + "source": 933, + "pc": [ + 3597, + 3598 + ] + }, + { + "teal": 3605, + "source": 933, + "pc": [ + 3599, + 3600 + ] + }, + { + "teal": 3606, + "source": 933, + "pc": [ + 3601, + 3602 + ] + }, + { + "teal": 3607, + "source": 933, + "pc": [ + 3603 + ] + }, + { + "teal": 3608, + "source": 933, + "pc": [ + 3604, + 3605 + ] + }, + { + "teal": 3609, + "source": 933, + "pc": [ + 3606 + ] + }, + { + "teal": 3610, + "source": 933, + "pc": [ + 3607 + ] + }, + { + "teal": 3611, + "source": 933, + "pc": [ + 3608, + 3609 + ] + }, + { + "teal": 3612, + "source": 933, + "pc": [ + 3610 + ] + }, + { + "teal": 3613, + "source": 933, + "pc": [ + 3611 + ] + }, + { + "teal": 3614, + "source": 932, + "pc": [ + 3612 + ] + }, + { + "teal": 3617, + "source": 931, + "pc": [ + 3613 + ] + }, + { + "teal": 3621, + "source": 936, + "pc": [ + 3614, + 3615 + ] + }, + { + "teal": 3622, + "source": 936, + "pc": [ + 3616, + 3617 + ] + }, + { + "teal": 3623, + "source": 936, + "pc": [ + 3618 + ] + }, + { + "teal": 3624, + "source": 936, + "pc": [ + 3619, + 3620 + ] + }, + { + "teal": 3625, + "source": 936, + "pc": [ + 3621 + ] + }, + { + "teal": 3626, + "source": 936, + "pc": [ + 3622 + ] + }, + { + "teal": 3627, + "source": 936, + "pc": [ + 3623, + 3624 + ] + }, + { + "teal": 3628, + "source": 936, + "pc": [ + 3625 + ] + }, + { + "teal": 3629, + "source": 936, + "pc": [ + 3626, + 3627 + ] + }, + { + "teal": 3633, + "source": 937, + "pc": [ + 3628, + 3629 + ] + }, + { + "teal": 3634, + "source": 937, + "pc": [ + 3630 + ] + }, + { + "teal": 3635, + "source": 937, + "pc": [ + 3631 + ] + }, + { + "teal": 3636, + "source": 937, + "pc": [ + 3632 + ] + }, + { + "teal": 3637, + "source": 937, + "pc": [ + 3633, + 3634, + 3635 + ] + }, + { + "teal": 3638, + "source": 937, + "pc": [ + 3636, + 3637 + ] + }, + { + "teal": 3639, + "source": 937, + "pc": [ + 3638 + ] + }, + { + "teal": 3640, + "source": 937, + "pc": [ + 3639 + ] + }, + { + "teal": 3641, + "source": 937, + "pc": [ + 3640 + ] + }, + { + "teal": 3644, + "source": 937, + "pc": [ + 3641 + ] + }, + { + "teal": 3648, + "source": 939, + "pc": [ + 3642 + ] + }, + { + "teal": 3649, + "source": 939, + "pc": [ + 3643, + 3644 + ] + }, + { + "teal": 3654, + "source": 939, + "pc": [ + 3645, + 3646 + ] + }, + { + "teal": 3655, + "source": 939, + "pc": [ + 3647 + ] + }, + { + "teal": 3656, + "source": 939, + "pc": [ + 3648 + ] + }, + { + "teal": 3657, + "source": 939, + "pc": [ + 3649, + 3650, + 3651 + ] + }, + { + "teal": 3661, + "source": 940, + "pc": [ + 3652 + ] + }, + { + "teal": 3662, + "source": 940, + "pc": [ + 3653, + 3654 + ] + }, + { + "teal": 3667, + "source": 940, + "pc": [ + 3655, + 3656 + ] + }, + { + "teal": 3668, + "source": 940, + "pc": [ + 3657, + 3658 + ] + }, + { + "teal": 3669, + "source": 940, + "pc": [ + 3659 + ] + }, + { + "teal": 3670, + "source": 940, + "pc": [ + 3660, + 3661, + 3662 + ] + }, + { + "teal": 3675, + "source": 941, + "pc": [ + 3663, + 3664 + ] + }, + { + "teal": 3676, + "source": 941, + "pc": [ + 3665 + ] + }, + { + "teal": 3677, + "source": 941, + "pc": [ + 3666, + 3667 + ] + }, + { + "teal": 3678, + "source": 941, + "pc": [ + 3668 + ] + }, + { + "teal": 3679, + "source": 941, + "pc": [ + 3669 + ] + }, + { + "teal": 3680, + "source": 941, + "pc": [ + 3670 + ] + }, + { + "teal": 3681, + "source": 941, + "pc": [ + 3671 + ] + }, + { + "teal": 3682, + "source": 941, + "pc": [ + 3672 + ] + }, + { + "teal": 3683, + "source": 941, + "pc": [ + 3673, + 3674 + ] + }, + { + "teal": 3684, + "source": 941, + "pc": [ + 3675 + ] + }, + { + "teal": 3685, + "source": 941, + "pc": [ + 3676 + ] + }, + { + "teal": 3686, + "source": 941, + "pc": [ + 3677 + ] + }, + { + "teal": 3687, + "source": 941, + "pc": [ + 3678 + ] + }, + { + "teal": 3688, + "source": 941, + "pc": [ + 3679 + ] + }, + { + "teal": 3689, + "source": 941, + "pc": [ + 3680 + ] + }, + { + "teal": 3690, + "source": 941, + "pc": [ + 3681, + 3682 + ] + }, + { + "teal": 3691, + "source": 941, + "pc": [ + 3683 + ] + }, + { + "teal": 3692, + "source": 941, + "pc": [ + 3684, + 3685, + 3686 + ] + }, + { + "teal": 3697, + "source": 942, + "pc": [ + 3687, + 3688 + ] + }, + { + "teal": 3698, + "source": 942, + "pc": [ + 3689 + ] + }, + { + "teal": 3699, + "source": 942, + "pc": [ + 3690 + ] + }, + { + "teal": 3700, + "source": 942, + "pc": [ + 3691, + 3692 + ] + }, + { + "teal": 3701, + "source": 942, + "pc": [ + 3693 + ] + }, + { + "teal": 3704, + "source": 942, + "pc": [ + 3694 + ] + }, + { + "teal": 3708, + "source": 944, + "pc": [ + 3695, + 3696 + ] + }, + { + "teal": 3709, + "source": 944, + "pc": [ + 3697, + 3698 + ] + }, + { + "teal": 3710, + "source": 944, + "pc": [ + 3699 + ] + }, + { + "teal": 3711, + "source": 944, + "pc": [ + 3700 + ] + }, + { + "teal": 3712, + "source": 944, + "pc": [ + 3701 + ] + }, + { + "teal": 3713, + "source": 944, + "pc": [ + 3702 + ] + }, + { + "teal": 3714, + "source": 944, + "pc": [ + 3703 + ] + }, + { + "teal": 3715, + "source": 944, + "pc": [ + 3704, + 3705 + ] + }, + { + "teal": 3716, + "source": 944, + "pc": [ + 3706 + ] + }, + { + "teal": 3717, + "source": 944, + "pc": [ + 3707 + ] + }, + { + "teal": 3718, + "source": 944, + "pc": [ + 3708 + ] + }, + { + "teal": 3719, + "source": 944, + "pc": [ + 3709, + 3710 + ] + }, + { + "teal": 3720, + "source": 944, + "pc": [ + 3711 + ] + }, + { + "teal": 3721, + "source": 944, + "pc": [ + 3712, + 3713 + ] + }, + { + "teal": 3722, + "source": 944, + "pc": [ + 3714 + ] + }, + { + "teal": 3723, + "source": 944, + "pc": [ + 3715 + ] + }, + { + "teal": 3724, + "source": 944, + "pc": [ + 3716, + 3717 + ] + }, + { + "teal": 3725, + "source": 944, + "pc": [ + 3718 + ] + }, + { + "teal": 3731, + "source": 947, + "pc": [ + 3719 + ] + }, + { + "teal": 3732, + "source": 947, + "pc": [ + 3720, + 3721 + ] + }, + { + "teal": 3733, + "source": 947, + "pc": [ + 3722, + 3723 + ] + }, + { + "teal": 3734, + "source": 947, + "pc": [ + 3724, + 3725, + 3726, + 3727, + 3728, + 3729 + ] + }, + { + "teal": 3735, + "source": 947, + "pc": [ + 3730, + 3731 + ] + }, + { + "teal": 3739, + "source": 948, + "pc": [ + 3732, + 3733 + ] + }, + { + "teal": 3740, + "source": 948, + "pc": [ + 3734, + 3735 + ] + }, + { + "teal": 3743, + "source": 947, + "pc": [ + 3736 + ] + }, + { + "teal": 3744, + "source": 947, + "pc": [ + 3737, + 3738 + ] + }, + { + "teal": 3747, + "source": 947, + "pc": [ + 3739 + ] + }, + { + "teal": 3751, + "source": 952, + "pc": [ + 3740, + 3741 + ] + }, + { + "teal": 3752, + "source": 952, + "pc": [ + 3742, + 3743 + ] + }, + { + "teal": 3753, + "source": 952, + "pc": [ + 3744, + 3745 + ] + }, + { + "teal": 3754, + "source": 952, + "pc": [ + 3746, + 3747, + 3748 + ] + }, + { + "teal": 3758, + "source": 953, + "pc": [ + 3749 + ] + }, + { + "teal": 3765, + "source": 940, + "pc": [ + 3750, + 3751 + ] + }, + { + "teal": 3766, + "source": 940, + "pc": [ + 3752 + ] + }, + { + "teal": 3767, + "source": 940, + "pc": [ + 3753 + ] + }, + { + "teal": 3768, + "source": 940, + "pc": [ + 3754, + 3755 + ] + }, + { + "teal": 3769, + "source": 940, + "pc": [ + 3756, + 3757, + 3758 + ] + }, + { + "teal": 3776, + "source": 939, + "pc": [ + 3759, + 3760 + ] + }, + { + "teal": 3777, + "source": 939, + "pc": [ + 3761 + ] + }, + { + "teal": 3778, + "source": 939, + "pc": [ + 3762 + ] + }, + { + "teal": 3779, + "source": 939, + "pc": [ + 3763, + 3764 + ] + }, + { + "teal": 3780, + "source": 939, + "pc": [ + 3765, + 3766, + 3767 + ] + }, + { + "teal": 3783, + "source": 957, + "pc": [ + 3768 + ] + }, + { + "teal": 3794, + "source": 1050, + "pc": [ + 3769, + 3770, + 3771 + ] + }, + { + "teal": 3798, + "source": 1051, + "pc": [ + 3772 + ] + }, + { + "teal": 3799, + "source": 1051, + "pc": [ + 3773, + 3774 + ] + }, + { + "teal": 3800, + "source": 1051, + "pc": [ + 3775, + 3776, + 3777 + ] + }, + { + "teal": 3801, + "source": 1051, + "pc": [ + 3778 + ] + }, + { + "teal": 3802, + "source": 1051, + "pc": [ + 3779 + ] + }, + { + "teal": 3803, + "source": 1051, + "pc": [ + 3780 + ] + }, + { + "teal": 3804, + "source": 1051, + "pc": [ + 3781 + ] + }, + { + "teal": 3805, + "source": 1051, + "pc": [ + 3782 + ] + }, + { + "teal": 3806, + "source": 1051, + "pc": [ + 3783 + ] + }, + { + "teal": 3807, + "source": 1051, + "pc": [ + 3784 + ] + }, + { + "teal": 3811, + "source": 1052, + "pc": [ + 3785, + 3786 + ] + }, + { + "teal": 3812, + "source": 1052, + "pc": [ + 3787, + 3788, + 3789 + ] + }, + { + "teal": 3813, + "source": 1052, + "pc": [ + 3790 + ] + }, + { + "teal": 3814, + "source": 1052, + "pc": [ + 3791, + 3792 + ] + }, + { + "teal": 3815, + "source": 1052, + "pc": [ + 3793, + 3794 + ] + }, + { + "teal": 3816, + "source": 1052, + "pc": [ + 3795 + ] + }, + { + "teal": 3817, + "source": 1052, + "pc": [ + 3796 + ] + }, + { + "teal": 3818, + "source": 1052, + "pc": [ + 3797 + ] + }, + { + "teal": 3822, + "source": 1053, + "pc": [ + 3798, + 3799 + ] + }, + { + "teal": 3823, + "source": 1053, + "pc": [ + 3800, + 3801, + 3802 + ] + }, + { + "teal": 3824, + "source": 1053, + "pc": [ + 3803 + ] + }, + { + "teal": 3825, + "source": 1053, + "pc": [ + 3804 + ] + }, + { + "teal": 3826, + "source": 1053, + "pc": [ + 3805 + ] + }, + { + "teal": 3827, + "source": 1053, + "pc": [ + 3806 + ] + }, + { + "teal": 3828, + "source": 1053, + "pc": [ + 3807, + 3808, + 3809 + ] + }, + { + "teal": 3829, + "source": 1053, + "pc": [ + 3810, + 3811 + ] + }, + { + "teal": 3830, + "source": 1053, + "pc": [ + 3812, + 3813, + 3814 + ] + }, + { + "teal": 3831, + "source": 1053, + "pc": [ + 3815 + ] + }, + { + "teal": 3832, + "source": 1053, + "pc": [ + 3816, + 3817 + ] + }, + { + "teal": 3833, + "source": 1053, + "pc": [ + 3818, + 3819 + ] + }, + { + "teal": 3834, + "source": 1053, + "pc": [ + 3820 + ] + }, + { + "teal": 3835, + "source": 1053, + "pc": [ + 3821, + 3822 + ] + }, + { + "teal": 3836, + "source": 1053, + "pc": [ + 3823, + 3824, + 3825 + ] + }, + { + "teal": 3837, + "source": 1053, + "pc": [ + 3826 + ] + }, + { + "teal": 3838, + "source": 1053, + "pc": [ + 3827 + ] + }, + { + "teal": 3839, + "source": 1053, + "pc": [ + 3828 + ] + }, + { + "teal": 3840, + "source": 1053, + "pc": [ + 3829, + 3830 + ] + }, + { + "teal": 3841, + "source": 1053, + "pc": [ + 3831 + ] + }, + { + "teal": 3842, + "source": 1053, + "pc": [ + 3832 + ] + }, + { + "teal": 3843, + "source": 1053, + "pc": [ + 3833 + ] + }, + { + "teal": 3844, + "source": 1053, + "pc": [ + 3834 + ] + }, + { + "teal": 3847, + "source": 1053, + "pc": [ + 3835 + ] + }, + { + "teal": 3854, + "source": 1057, + "pc": [ + 3836, + 3837 + ] + }, + { + "teal": 3855, + "source": 1057, + "pc": [ + 3838, + 3839, + 3840 + ] + }, + { + "teal": 3856, + "source": 1057, + "pc": [ + 3841 + ] + }, + { + "teal": 3857, + "source": 1057, + "pc": [ + 3842, + 3843 + ] + }, + { + "teal": 3858, + "source": 1057, + "pc": [ + 3844, + 3845 + ] + }, + { + "teal": 3859, + "source": 1057, + "pc": [ + 3846, + 3847, + 3848 + ] + }, + { + "teal": 3860, + "source": 1057, + "pc": [ + 3849 + ] + }, + { + "teal": 3861, + "source": 1057, + "pc": [ + 3850 + ] + }, + { + "teal": 3862, + "source": 1057, + "pc": [ + 3851 + ] + }, + { + "teal": 3863, + "source": 1057, + "pc": [ + 3852, + 3853 + ] + }, + { + "teal": 3864, + "source": 1057, + "pc": [ + 3854 + ] + }, + { + "teal": 3865, + "source": 1057, + "pc": [ + 3855 + ] + }, + { + "teal": 3866, + "source": 1057, + "pc": [ + 3856 + ] + }, + { + "teal": 3867, + "source": 1057, + "pc": [ + 3857 + ] + }, + { + "teal": 3868, + "source": 1057, + "pc": [ + 3858 + ] + }, + { + "teal": 3869, + "source": 1057, + "pc": [ + 3859 + ] + }, + { + "teal": 3870, + "source": 1057, + "pc": [ + 3860, + 3861 + ] + }, + { + "teal": 3871, + "source": 1057, + "pc": [ + 3862, + 3863, + 3864 + ] + }, + { + "teal": 3872, + "source": 1057, + "pc": [ + 3865 + ] + }, + { + "teal": 3873, + "source": 1057, + "pc": [ + 3866 + ] + }, + { + "teal": 3874, + "source": 1057, + "pc": [ + 3867 + ] + }, + { + "teal": 3875, + "source": 1057, + "pc": [ + 3868, + 3869 + ] + }, + { + "teal": 3876, + "source": 1057, + "pc": [ + 3870 + ] + }, + { + "teal": 3877, + "source": 1057, + "pc": [ + 3871 + ] + }, + { + "teal": 3878, + "source": 1057, + "pc": [ + 3872 + ] + }, + { + "teal": 3881, + "source": 1056, + "pc": [ + 3873 + ] + }, + { + "teal": 3885, + "source": 1061, + "pc": [ + 3874, + 3875 + ] + }, + { + "teal": 3886, + "source": 1061, + "pc": [ + 3876, + 3877 + ] + }, + { + "teal": 3887, + "source": 1061, + "pc": [ + 3878, + 3879, + 3880 + ] + }, + { + "teal": 3888, + "source": 1061, + "pc": [ + 3881 + ] + }, + { + "teal": 3889, + "source": 1061, + "pc": [ + 3882, + 3883 + ] + }, + { + "teal": 3890, + "source": 1061, + "pc": [ + 3884 + ] + }, + { + "teal": 3891, + "source": 1061, + "pc": [ + 3885 + ] + }, + { + "teal": 3892, + "source": 1061, + "pc": [ + 3886 + ] + }, + { + "teal": 3896, + "source": 1063, + "pc": [ + 3887, + 3888 + ] + }, + { + "teal": 3897, + "source": 1063, + "pc": [ + 3889, + 3890, + 3891 + ] + }, + { + "teal": 3898, + "source": 1063, + "pc": [ + 3892 + ] + }, + { + "teal": 3899, + "source": 1063, + "pc": [ + 3893, + 3894 + ] + }, + { + "teal": 3900, + "source": 1063, + "pc": [ + 3895, + 3896, + 3897 + ] + }, + { + "teal": 3901, + "source": 1063, + "pc": [ + 3898 + ] + }, + { + "teal": 3902, + "source": 1063, + "pc": [ + 3899, + 3900, + 3901, + 3902, + 3903, + 3904, + 3905, + 3906, + 3907, + 3908, + 3909, + 3910, + 3911 + ] + }, + { + "teal": 3903, + "source": 1063, + "pc": [ + 3912 + ] + }, + { + "teal": 3904, + "source": 1063, + "pc": [ + 3913 + ] + }, + { + "teal": 3905, + "source": 1063, + "pc": [ + 3914 + ] + }, + { + "teal": 3906, + "source": 1063, + "pc": [ + 3915 + ] + }, + { + "teal": 3910, + "source": 1064, + "pc": [ + 3916, + 3917 + ] + }, + { + "teal": 3911, + "source": 1064, + "pc": [ + 3918, + 3919, + 3920 + ] + }, + { + "teal": 3912, + "source": 1064, + "pc": [ + 3921 + ] + }, + { + "teal": 3913, + "source": 1064, + "pc": [ + 3922, + 3923 + ] + }, + { + "teal": 3914, + "source": 1064, + "pc": [ + 3924, + 3925, + 3926 + ] + }, + { + "teal": 3915, + "source": 1064, + "pc": [ + 3927 + ] + }, + { + "teal": 3916, + "source": 1064, + "pc": [ + 3928, + 3929, + 3930, + 3931, + 3932, + 3933, + 3934, + 3935 + ] + }, + { + "teal": 3917, + "source": 1064, + "pc": [ + 3936 + ] + }, + { + "teal": 3918, + "source": 1064, + "pc": [ + 3937 + ] + }, + { + "teal": 3919, + "source": 1064, + "pc": [ + 3938 + ] + }, + { + "teal": 3920, + "source": 1064, + "pc": [ + 3939 + ] + }, + { + "teal": 3921, + "source": 1050, + "pc": [ + 3940 + ] + }, + { + "teal": 3930, + "source": 1073, + "pc": [ + 3941, + 3942, + 3943 + ] + }, + { + "teal": 3933, + "source": 1073, + "pc": [ + 3944 + ] + }, + { + "teal": 3934, + "source": 1073, + "pc": [ + 3945 + ] + }, + { + "teal": 3938, + "source": 1074, + "pc": [ + 3946 + ] + }, + { + "teal": 3939, + "source": 1074, + "pc": [ + 3947, + 3948 + ] + }, + { + "teal": 3940, + "source": 1074, + "pc": [ + 3949 + ] + }, + { + "teal": 3941, + "source": 1074, + "pc": [ + 3950 + ] + }, + { + "teal": 3942, + "source": 1074, + "pc": [ + 3951, + 3952 + ] + }, + { + "teal": 3947, + "source": 1075, + "pc": [ + 3953, + 3954 + ] + }, + { + "teal": 3948, + "source": 1075, + "pc": [ + 3955 + ] + }, + { + "teal": 3949, + "source": 1074, + "pc": [ + 3956 + ] + }, + { + "teal": 3950, + "source": 1074, + "pc": [ + 3957, + 3958 + ] + }, + { + "teal": 3951, + "source": 1074, + "pc": [ + 3959 + ] + }, + { + "teal": 3952, + "source": 1074, + "pc": [ + 3960 + ] + }, + { + "teal": 3953, + "source": 1074, + "pc": [ + 3961, + 3962 + ] + }, + { + "teal": 3954, + "source": 1074, + "pc": [ + 3963 + ] + }, + { + "teal": 3955, + "source": 1075, + "pc": [ + 3964 + ] + }, + { + "teal": 3956, + "source": 1075, + "pc": [ + 3965 + ] + }, + { + "teal": 3957, + "source": 1075, + "pc": [ + 3966 + ] + }, + { + "teal": 3958, + "source": 1075, + "pc": [ + 3967, + 3968, + 3969 + ] + }, + { + "teal": 3963, + "source": 1078, + "pc": [ + 3970, + 3971 + ] + }, + { + "teal": 3964, + "source": 1078, + "pc": [ + 3972 + ] + }, + { + "teal": 3965, + "source": 1074, + "pc": [ + 3973 + ] + }, + { + "teal": 3966, + "source": 1074, + "pc": [ + 3974, + 3975 + ] + }, + { + "teal": 3967, + "source": 1074, + "pc": [ + 3976 + ] + }, + { + "teal": 3968, + "source": 1074, + "pc": [ + 3977 + ] + }, + { + "teal": 3969, + "source": 1074, + "pc": [ + 3978, + 3979 + ] + }, + { + "teal": 3970, + "source": 1074, + "pc": [ + 3980 + ] + }, + { + "teal": 3971, + "source": 1078, + "pc": [ + 3981 + ] + }, + { + "teal": 3972, + "source": 1078, + "pc": [ + 3982, + 3983 + ] + }, + { + "teal": 3973, + "source": 1078, + "pc": [ + 3984 + ] + }, + { + "teal": 3974, + "source": 1078, + "pc": [ + 3985 + ] + }, + { + "teal": 3975, + "source": 1078, + "pc": [ + 3986, + 3987 + ] + }, + { + "teal": 3980, + "source": 1080, + "pc": [ + 3988 + ] + }, + { + "teal": 3981, + "source": 1080, + "pc": [ + 3989, + 3990 + ] + }, + { + "teal": 3982, + "source": 1074, + "pc": [ + 3991 + ] + }, + { + "teal": 3983, + "source": 1074, + "pc": [ + 3992, + 3993 + ] + }, + { + "teal": 3984, + "source": 1074, + "pc": [ + 3994 + ] + }, + { + "teal": 3985, + "source": 1074, + "pc": [ + 3995 + ] + }, + { + "teal": 3986, + "source": 1074, + "pc": [ + 3996, + 3997 + ] + }, + { + "teal": 3987, + "source": 1074, + "pc": [ + 3998 + ] + }, + { + "teal": 3988, + "source": 1080, + "pc": [ + 3999, + 4000 + ] + }, + { + "teal": 3989, + "source": 1080, + "pc": [ + 4001 + ] + }, + { + "teal": 3990, + "source": 1080, + "pc": [ + 4002 + ] + }, + { + "teal": 3991, + "source": 1080, + "pc": [ + 4003, + 4004, + 4005 + ] + }, + { + "teal": 3992, + "source": 1080, + "pc": [ + 4006, + 4007 + ] + }, + { + "teal": 3993, + "source": 1080, + "pc": [ + 4008, + 4009 + ] + }, + { + "teal": 3994, + "source": 1074, + "pc": [ + 4010 + ] + }, + { + "teal": 3995, + "source": 1074, + "pc": [ + 4011, + 4012 + ] + }, + { + "teal": 3996, + "source": 1074, + "pc": [ + 4013 + ] + }, + { + "teal": 3997, + "source": 1074, + "pc": [ + 4014 + ] + }, + { + "teal": 3998, + "source": 1074, + "pc": [ + 4015, + 4016 + ] + }, + { + "teal": 3999, + "source": 1074, + "pc": [ + 4017 + ] + }, + { + "teal": 4000, + "source": 1080, + "pc": [ + 4018, + 4019 + ] + }, + { + "teal": 4001, + "source": 1080, + "pc": [ + 4020 + ] + }, + { + "teal": 4002, + "source": 1080, + "pc": [ + 4021 + ] + }, + { + "teal": 4005, + "source": 1080, + "pc": [ + 4022, + 4023, + 4024 + ] + }, + { + "teal": 4010, + "source": 1082, + "pc": [ + 4025, + 4026 + ] + }, + { + "teal": 4011, + "source": 1082, + "pc": [ + 4027, + 4028 + ] + }, + { + "teal": 4012, + "source": 1082, + "pc": [ + 4029 + ] + }, + { + "teal": 4013, + "source": 1082, + "pc": [ + 4030, + 4031 + ] + }, + { + "teal": 4014, + "source": 1082, + "pc": [ + 4032 + ] + }, + { + "teal": 4015, + "source": 1082, + "pc": [ + 4033 + ] + }, + { + "teal": 4016, + "source": 1082, + "pc": [ + 4034, + 4035 + ] + }, + { + "teal": 4017, + "source": 1082, + "pc": [ + 4036 + ] + }, + { + "teal": 4022, + "source": 1073, + "pc": [ + 4037 + ] + }, + { + "teal": 4026, + "source": 1087, + "pc": [ + 4038, + 4039, + 4040 + ] + }, + { + "teal": 4030, + "source": 1089, + "pc": [ + 4041, + 4042 + ] + }, + { + "teal": 4031, + "source": 1089, + "pc": [ + 4043, + 4044, + 4045 + ] + }, + { + "teal": 4032, + "source": 1089, + "pc": [ + 4046 + ] + }, + { + "teal": 4033, + "source": 1089, + "pc": [ + 4047 + ] + }, + { + "teal": 4034, + "source": 1089, + "pc": [ + 4048 + ] + }, + { + "teal": 4035, + "source": 1089, + "pc": [ + 4049 + ] + }, + { + "teal": 4036, + "source": 1089, + "pc": [ + 4050, + 4051, + 4052 + ] + }, + { + "teal": 4037, + "source": 1089, + "pc": [ + 4053, + 4054 + ] + }, + { + "teal": 4038, + "source": 1089, + "pc": [ + 4055, + 4056, + 4057 + ] + }, + { + "teal": 4039, + "source": 1089, + "pc": [ + 4058 + ] + }, + { + "teal": 4040, + "source": 1089, + "pc": [ + 4059, + 4060 + ] + }, + { + "teal": 4041, + "source": 1089, + "pc": [ + 4061 + ] + }, + { + "teal": 4042, + "source": 1089, + "pc": [ + 4062 + ] + }, + { + "teal": 4045, + "source": 1089, + "pc": [ + 4063 + ] + }, + { + "teal": 4049, + "source": 1090, + "pc": [ + 4064, + 4065 + ] + }, + { + "teal": 4050, + "source": 1090, + "pc": [ + 4066, + 4067, + 4068 + ] + }, + { + "teal": 4051, + "source": 1090, + "pc": [ + 4069 + ] + }, + { + "teal": 4052, + "source": 1090, + "pc": [ + 4070 + ] + }, + { + "teal": 4053, + "source": 1090, + "pc": [ + 4071 + ] + }, + { + "teal": 4054, + "source": 1090, + "pc": [ + 4072 + ] + }, + { + "teal": 4055, + "source": 1090, + "pc": [ + 4073, + 4074, + 4075 + ] + }, + { + "teal": 4056, + "source": 1090, + "pc": [ + 4076, + 4077 + ] + }, + { + "teal": 4057, + "source": 1090, + "pc": [ + 4078, + 4079, + 4080 + ] + }, + { + "teal": 4058, + "source": 1090, + "pc": [ + 4081 + ] + }, + { + "teal": 4059, + "source": 1090, + "pc": [ + 4082, + 4083, + 4084 + ] + }, + { + "teal": 4060, + "source": 1090, + "pc": [ + 4085 + ] + }, + { + "teal": 4061, + "source": 1090, + "pc": [ + 4086 + ] + }, + { + "teal": 4064, + "source": 1090, + "pc": [ + 4087 + ] + }, + { + "teal": 4068, + "source": 1091, + "pc": [ + 4088, + 4089 + ] + }, + { + "teal": 4069, + "source": 1091, + "pc": [ + 4090, + 4091, + 4092 + ] + }, + { + "teal": 4070, + "source": 1091, + "pc": [ + 4093 + ] + }, + { + "teal": 4071, + "source": 1091, + "pc": [ + 4094 + ] + }, + { + "teal": 4072, + "source": 1091, + "pc": [ + 4095 + ] + }, + { + "teal": 4073, + "source": 1091, + "pc": [ + 4096 + ] + }, + { + "teal": 4074, + "source": 1091, + "pc": [ + 4097, + 4098, + 4099 + ] + }, + { + "teal": 4075, + "source": 1091, + "pc": [ + 4100, + 4101 + ] + }, + { + "teal": 4076, + "source": 1091, + "pc": [ + 4102, + 4103, + 4104 + ] + }, + { + "teal": 4077, + "source": 1091, + "pc": [ + 4105 + ] + }, + { + "teal": 4078, + "source": 1091, + "pc": [ + 4106, + 4107 + ] + }, + { + "teal": 4079, + "source": 1091, + "pc": [ + 4108 + ] + }, + { + "teal": 4080, + "source": 1091, + "pc": [ + 4109 + ] + }, + { + "teal": 4083, + "source": 1091, + "pc": [ + 4110 + ] + }, + { + "teal": 4088, + "source": 1092, + "pc": [ + 4111, + 4112 + ] + }, + { + "teal": 4089, + "source": 1092, + "pc": [ + 4113, + 4114, + 4115 + ] + }, + { + "teal": 4090, + "source": 1092, + "pc": [ + 4116 + ] + }, + { + "teal": 4091, + "source": 1092, + "pc": [ + 4117 + ] + }, + { + "teal": 4092, + "source": 1092, + "pc": [ + 4118 + ] + }, + { + "teal": 4093, + "source": 1092, + "pc": [ + 4119, + 4120, + 4121 + ] + }, + { + "teal": 4101, + "source": 1094, + "pc": [ + 4122, + 4123 + ] + }, + { + "teal": 4102, + "source": 1094, + "pc": [ + 4124, + 4125, + 4126 + ] + }, + { + "teal": 4103, + "source": 1094, + "pc": [ + 4127, + 4128 + ] + }, + { + "teal": 4104, + "source": 1094, + "pc": [ + 4129 + ] + }, + { + "teal": 4107, + "source": 1093, + "pc": [ + 4130 + ] + }, + { + "teal": 4112, + "source": 1098, + "pc": [ + 4131, + 4132 + ] + }, + { + "teal": 4113, + "source": 1098, + "pc": [ + 4133, + 4134, + 4135 + ] + }, + { + "teal": 4114, + "source": 1098, + "pc": [ + 4136 + ] + }, + { + "teal": 4115, + "source": 1098, + "pc": [ + 4137, + 4138 + ] + }, + { + "teal": 4116, + "source": 1098, + "pc": [ + 4139 + ] + }, + { + "teal": 4117, + "source": 1098, + "pc": [ + 4140 + ] + }, + { + "teal": 4121, + "source": 1100, + "pc": [ + 4141, + 4142 + ] + }, + { + "teal": 4122, + "source": 1100, + "pc": [ + 4143, + 4144, + 4145 + ] + }, + { + "teal": 4123, + "source": 1100, + "pc": [ + 4146 + ] + }, + { + "teal": 4124, + "source": 1100, + "pc": [ + 4147 + ] + }, + { + "teal": 4125, + "source": 1100, + "pc": [ + 4148 + ] + }, + { + "teal": 4126, + "source": 1100, + "pc": [ + 4149 + ] + }, + { + "teal": 4127, + "source": 1100, + "pc": [ + 4150, + 4151, + 4152 + ] + }, + { + "teal": 4128, + "source": 1100, + "pc": [ + 4153, + 4154 + ] + }, + { + "teal": 4129, + "source": 1100, + "pc": [ + 4155, + 4156, + 4157 + ] + }, + { + "teal": 4130, + "source": 1100, + "pc": [ + 4158 + ] + }, + { + "teal": 4131, + "source": 1100, + "pc": [ + 4159, + 4160 + ] + }, + { + "teal": 4132, + "source": 1100, + "pc": [ + 4161 + ] + }, + { + "teal": 4133, + "source": 1100, + "pc": [ + 4162 + ] + }, + { + "teal": 4136, + "source": 1100, + "pc": [ + 4163 + ] + }, + { + "teal": 4137, + "source": 1087, + "pc": [ + 4164 + ] + }, + { + "teal": 4151, + "source": 1114, + "pc": [ + 4165, + 4166, + 4167 + ] + }, + { + "teal": 4154, + "source": 1114, + "pc": [ + 4168 + ] + }, + { + "teal": 4155, + "source": 1114, + "pc": [ + 4169, + 4170 + ] + }, + { + "teal": 4160, + "source": 1121, + "pc": [ + 4171, + 4172 + ] + }, + { + "teal": 4161, + "source": 1121, + "pc": [ + 4173, + 4174, + 4175 + ] + }, + { + "teal": 4162, + "source": 1121, + "pc": [ + 4176 + ] + }, + { + "teal": 4163, + "source": 1121, + "pc": [ + 4177, + 4178, + 4179 + ] + }, + { + "teal": 4168, + "source": 1122, + "pc": [ + 4180 + ] + }, + { + "teal": 4169, + "source": 1122, + "pc": [ + 4181, + 4182 + ] + }, + { + "teal": 4170, + "source": 1122, + "pc": [ + 4183, + 4184 + ] + }, + { + "teal": 4171, + "source": 1122, + "pc": [ + 4185 + ] + }, + { + "teal": 4172, + "source": 1122, + "pc": [ + 4186, + 4187 + ] + }, + { + "teal": 4173, + "source": 1122, + "pc": [ + 4188, + 4189 + ] + }, + { + "teal": 4174, + "source": 1122, + "pc": [ + 4190 + ] + }, + { + "teal": 4175, + "source": 1122, + "pc": [ + 4191, + 4192 + ] + }, + { + "teal": 4176, + "source": 1122, + "pc": [ + 4193, + 4194 + ] + }, + { + "teal": 4177, + "source": 1122, + "pc": [ + 4195, + 4196 + ] + }, + { + "teal": 4178, + "source": 1122, + "pc": [ + 4197, + 4198 + ] + }, + { + "teal": 4179, + "source": 1122, + "pc": [ + 4199 + ] + }, + { + "teal": 4184, + "source": 1124, + "pc": [ + 4200, + 4201 + ] + }, + { + "teal": 4185, + "source": 1124, + "pc": [ + 4202, + 4203 + ] + }, + { + "teal": 4186, + "source": 1124, + "pc": [ + 4204, + 4205, + 4206 + ] + }, + { + "teal": 4187, + "source": 1124, + "pc": [ + 4207 + ] + }, + { + "teal": 4188, + "source": 1124, + "pc": [ + 4208 + ] + }, + { + "teal": 4189, + "source": 1124, + "pc": [ + 4209 + ] + }, + { + "teal": 4190, + "source": 1124, + "pc": [ + 4210, + 4211 + ] + }, + { + "teal": 4191, + "source": 1124, + "pc": [ + 4212 + ] + }, + { + "teal": 4192, + "source": 1124, + "pc": [ + 4213 + ] + }, + { + "teal": 4193, + "source": 1124, + "pc": [ + 4214 + ] + }, + { + "teal": 4194, + "source": 1124, + "pc": [ + 4215 + ] + }, + { + "teal": 4195, + "source": 1124, + "pc": [ + 4216 + ] + }, + { + "teal": 4196, + "source": 1124, + "pc": [ + 4217 + ] + }, + { + "teal": 4197, + "source": 1124, + "pc": [ + 4218, + 4219 + ] + }, + { + "teal": 4198, + "source": 1124, + "pc": [ + 4220, + 4221, + 4222 + ] + }, + { + "teal": 4199, + "source": 1124, + "pc": [ + 4223 + ] + }, + { + "teal": 4200, + "source": 1124, + "pc": [ + 4224 + ] + }, + { + "teal": 4201, + "source": 1124, + "pc": [ + 4225 + ] + }, + { + "teal": 4202, + "source": 1124, + "pc": [ + 4226, + 4227 + ] + }, + { + "teal": 4203, + "source": 1124, + "pc": [ + 4228 + ] + }, + { + "teal": 4204, + "source": 1124, + "pc": [ + 4229 + ] + }, + { + "teal": 4205, + "source": 1124, + "pc": [ + 4230, + 4231 + ] + }, + { + "teal": 4218, + "source": 1133, + "pc": [ + 4232 + ] + }, + { + "teal": 4219, + "source": 1133, + "pc": [ + 4233 + ] + }, + { + "teal": 4220, + "source": 1133, + "pc": [ + 4234, + 4235 + ] + }, + { + "teal": 4224, + "source": 1133, + "pc": [ + 4236, + 4237 + ] + }, + { + "teal": 4225, + "source": 1133, + "pc": [ + 4238, + 4239 + ] + }, + { + "teal": 4226, + "source": 1133, + "pc": [ + 4240, + 4241 + ] + }, + { + "teal": 4227, + "source": 1133, + "pc": [ + 4242 + ] + }, + { + "teal": 4228, + "source": 1133, + "pc": [ + 4243, + 4244 + ] + }, + { + "teal": 4232, + "source": 1133, + "pc": [ + 4245, + 4246 + ] + }, + { + "teal": 4233, + "source": 1133, + "pc": [ + 4247, + 4248 + ] + }, + { + "teal": 4234, + "source": 1133, + "pc": [ + 4249 + ] + }, + { + "teal": 4235, + "source": 1133, + "pc": [ + 4250, + 4251 + ] + }, + { + "teal": 4238, + "source": 1133, + "pc": [ + 4252 + ] + }, + { + "teal": 4239, + "source": 1133, + "pc": [ + 4253, + 4254 + ] + }, + { + "teal": 4240, + "source": 1128, + "pc": [ + 4255 + ] + }, + { + "teal": 4241, + "source": 1128, + "pc": [ + 4256, + 4257 + ] + }, + { + "teal": 4242, + "source": 1128, + "pc": [ + 4258, + 4259 + ] + }, + { + "teal": 4243, + "source": 1128, + "pc": [ + 4260, + 4261, + 4262, + 4263, + 4264, + 4265 + ] + }, + { + "teal": 4244, + "source": 1128, + "pc": [ + 4266, + 4267 + ] + }, + { + "teal": 4248, + "source": 1129, + "pc": [ + 4268, + 4269 + ] + }, + { + "teal": 4249, + "source": 1129, + "pc": [ + 4270, + 4271 + ] + }, + { + "teal": 4259, + "source": 1135, + "pc": [ + 4272, + 4273 + ] + }, + { + "teal": 4260, + "source": 1135, + "pc": [ + 4274, + 4275 + ] + }, + { + "teal": 4261, + "source": 1135, + "pc": [ + 4276, + 4277 + ] + }, + { + "teal": 4264, + "source": 1128, + "pc": [ + 4278 + ] + }, + { + "teal": 4265, + "source": 1128, + "pc": [ + 4279, + 4280 + ] + }, + { + "teal": 4268, + "source": 1128, + "pc": [ + 4281 + ] + }, + { + "teal": 4269, + "source": 1128, + "pc": [ + 4282, + 4283 + ] + }, + { + "teal": 4270, + "source": 1128, + "pc": [ + 4284 + ] + }, + { + "teal": 4271, + "source": 1128, + "pc": [ + 4285 + ] + }, + { + "teal": 4272, + "source": 1128, + "pc": [ + 4286, + 4287 + ] + }, + { + "teal": 4273, + "source": 1128, + "pc": [ + 4288, + 4289, + 4290 + ] + }, + { + "teal": 4274, + "source": 1128, + "pc": [ + 4291 + ] + }, + { + "teal": 4278, + "source": 1140, + "pc": [ + 4292, + 4293 + ] + }, + { + "teal": 4279, + "source": 1140, + "pc": [ + 4294, + 4295 + ] + }, + { + "teal": 4280, + "source": 1140, + "pc": [ + 4296 + ] + }, + { + "teal": 4281, + "source": 1140, + "pc": [ + 4297 + ] + }, + { + "teal": 4282, + "source": 1140, + "pc": [ + 4298, + 4299 + ] + }, + { + "teal": 4286, + "source": 1141, + "pc": [ + 4300, + 4301 + ] + }, + { + "teal": 4287, + "source": 1141, + "pc": [ + 4302, + 4303 + ] + }, + { + "teal": 4288, + "source": 1141, + "pc": [ + 4304 + ] + }, + { + "teal": 4289, + "source": 1141, + "pc": [ + 4305 + ] + }, + { + "teal": 4290, + "source": 1141, + "pc": [ + 4306, + 4307 + ] + }, + { + "teal": 4294, + "source": 1142, + "pc": [ + 4308, + 4309 + ] + }, + { + "teal": 4295, + "source": 1142, + "pc": [ + 4310, + 4311 + ] + }, + { + "teal": 4296, + "source": 1142, + "pc": [ + 4312, + 4313, + 4314 + ] + }, + { + "teal": 4297, + "source": 1142, + "pc": [ + 4315 + ] + }, + { + "teal": 4298, + "source": 1142, + "pc": [ + 4316 + ] + }, + { + "teal": 4299, + "source": 1142, + "pc": [ + 4317 + ] + }, + { + "teal": 4300, + "source": 1142, + "pc": [ + 4318, + 4319 + ] + }, + { + "teal": 4301, + "source": 1142, + "pc": [ + 4320 + ] + }, + { + "teal": 4302, + "source": 1142, + "pc": [ + 4321 + ] + }, + { + "teal": 4303, + "source": 1142, + "pc": [ + 4322 + ] + }, + { + "teal": 4304, + "source": 1142, + "pc": [ + 4323 + ] + }, + { + "teal": 4305, + "source": 1142, + "pc": [ + 4324, + 4325 + ] + }, + { + "teal": 4306, + "source": 1142, + "pc": [ + 4326 + ] + }, + { + "teal": 4307, + "source": 1142, + "pc": [ + 4327, + 4328, + 4329 + ] + }, + { + "teal": 4308, + "source": 1142, + "pc": [ + 4330 + ] + }, + { + "teal": 4309, + "source": 1142, + "pc": [ + 4331, + 4332 + ] + }, + { + "teal": 4310, + "source": 1142, + "pc": [ + 4333, + 4334, + 4335 + ] + }, + { + "teal": 4311, + "source": 1142, + "pc": [ + 4336 + ] + }, + { + "teal": 4312, + "source": 1142, + "pc": [ + 4337 + ] + }, + { + "teal": 4313, + "source": 1142, + "pc": [ + 4338 + ] + }, + { + "teal": 4314, + "source": 1142, + "pc": [ + 4339, + 4340 + ] + }, + { + "teal": 4315, + "source": 1142, + "pc": [ + 4341 + ] + }, + { + "teal": 4319, + "source": 1143, + "pc": [ + 4342, + 4343 + ] + }, + { + "teal": 4320, + "source": 1143, + "pc": [ + 4344, + 4345 + ] + }, + { + "teal": 4321, + "source": 1143, + "pc": [ + 4346, + 4347, + 4348 + ] + }, + { + "teal": 4322, + "source": 1143, + "pc": [ + 4349 + ] + }, + { + "teal": 4323, + "source": 1143, + "pc": [ + 4350 + ] + }, + { + "teal": 4324, + "source": 1143, + "pc": [ + 4351 + ] + }, + { + "teal": 4325, + "source": 1143, + "pc": [ + 4352, + 4353 + ] + }, + { + "teal": 4326, + "source": 1143, + "pc": [ + 4354 + ] + }, + { + "teal": 4327, + "source": 1143, + "pc": [ + 4355 + ] + }, + { + "teal": 4328, + "source": 1143, + "pc": [ + 4356, + 4357 + ] + }, + { + "teal": 4329, + "source": 1143, + "pc": [ + 4358 + ] + }, + { + "teal": 4330, + "source": 1143, + "pc": [ + 4359, + 4360 + ] + }, + { + "teal": 4331, + "source": 1143, + "pc": [ + 4361 + ] + }, + { + "teal": 4332, + "source": 1143, + "pc": [ + 4362 + ] + }, + { + "teal": 4333, + "source": 1143, + "pc": [ + 4363, + 4364 + ] + }, + { + "teal": 4334, + "source": 1143, + "pc": [ + 4365, + 4366, + 4367 + ] + }, + { + "teal": 4335, + "source": 1143, + "pc": [ + 4368 + ] + }, + { + "teal": 4336, + "source": 1143, + "pc": [ + 4369 + ] + }, + { + "teal": 4337, + "source": 1143, + "pc": [ + 4370 + ] + }, + { + "teal": 4338, + "source": 1143, + "pc": [ + 4371, + 4372 + ] + }, + { + "teal": 4339, + "source": 1143, + "pc": [ + 4373 + ] + }, + { + "teal": 4344, + "source": 1146, + "pc": [ + 4374, + 4375 + ] + }, + { + "teal": 4345, + "source": 1146, + "pc": [ + 4376, + 4377, + 4378 + ] + }, + { + "teal": 4350, + "source": 1147, + "pc": [ + 4379, + 4380 + ] + }, + { + "teal": 4351, + "source": 1147, + "pc": [ + 4381 + ] + }, + { + "teal": 4352, + "source": 1147, + "pc": [ + 4382 + ] + }, + { + "teal": 4353, + "source": 1147, + "pc": [ + 4383 + ] + }, + { + "teal": 4354, + "source": 1147, + "pc": [ + 4384, + 4385 + ] + }, + { + "teal": 4355, + "source": 1147, + "pc": [ + 4386, + 4387, + 4388 + ] + }, + { + "teal": 4356, + "source": 1147, + "pc": [ + 4389 + ] + }, + { + "teal": 4357, + "source": 1147, + "pc": [ + 4390 + ] + }, + { + "teal": 4358, + "source": 1147, + "pc": [ + 4391 + ] + }, + { + "teal": 4359, + "source": 1147, + "pc": [ + 4392, + 4393 + ] + }, + { + "teal": 4360, + "source": 1147, + "pc": [ + 4394 + ] + }, + { + "teal": 4361, + "source": 1147, + "pc": [ + 4395 + ] + }, + { + "teal": 4362, + "source": 1147, + "pc": [ + 4396 + ] + }, + { + "teal": 4363, + "source": 1147, + "pc": [ + 4397 + ] + }, + { + "teal": 4364, + "source": 1147, + "pc": [ + 4398 + ] + }, + { + "teal": 4365, + "source": 1147, + "pc": [ + 4399 + ] + }, + { + "teal": 4366, + "source": 1147, + "pc": [ + 4400, + 4401 + ] + }, + { + "teal": 4367, + "source": 1147, + "pc": [ + 4402, + 4403, + 4404 + ] + }, + { + "teal": 4368, + "source": 1147, + "pc": [ + 4405 + ] + }, + { + "teal": 4369, + "source": 1147, + "pc": [ + 4406 + ] + }, + { + "teal": 4370, + "source": 1147, + "pc": [ + 4407 + ] + }, + { + "teal": 4371, + "source": 1147, + "pc": [ + 4408, + 4409 + ] + }, + { + "teal": 4372, + "source": 1147, + "pc": [ + 4410 + ] + }, + { + "teal": 4378, + "source": 1149, + "pc": [ + 4411, + 4412 + ] + }, + { + "teal": 4379, + "source": 1149, + "pc": [ + 4413, + 4414, + 4415 + ] + }, + { + "teal": 4384, + "source": 1150, + "pc": [ + 4416, + 4417 + ] + }, + { + "teal": 4385, + "source": 1150, + "pc": [ + 4418 + ] + }, + { + "teal": 4386, + "source": 1150, + "pc": [ + 4419 + ] + }, + { + "teal": 4387, + "source": 1150, + "pc": [ + 4420 + ] + }, + { + "teal": 4388, + "source": 1150, + "pc": [ + 4421, + 4422 + ] + }, + { + "teal": 4389, + "source": 1150, + "pc": [ + 4423 + ] + }, + { + "teal": 4390, + "source": 1150, + "pc": [ + 4424 + ] + }, + { + "teal": 4395, + "source": 1152, + "pc": [ + 4425, + 4426 + ] + }, + { + "teal": 4396, + "source": 1152, + "pc": [ + 4427 + ] + }, + { + "teal": 4397, + "source": 1152, + "pc": [ + 4428 + ] + }, + { + "teal": 4398, + "source": 1152, + "pc": [ + 4429 + ] + }, + { + "teal": 4399, + "source": 1152, + "pc": [ + 4430, + 4431 + ] + }, + { + "teal": 4400, + "source": 1152, + "pc": [ + 4432, + 4433, + 4434 + ] + }, + { + "teal": 4401, + "source": 1152, + "pc": [ + 4435 + ] + }, + { + "teal": 4402, + "source": 1152, + "pc": [ + 4436 + ] + }, + { + "teal": 4403, + "source": 1152, + "pc": [ + 4437 + ] + }, + { + "teal": 4404, + "source": 1152, + "pc": [ + 4438, + 4439 + ] + }, + { + "teal": 4405, + "source": 1152, + "pc": [ + 4440 + ] + }, + { + "teal": 4406, + "source": 1152, + "pc": [ + 4441 + ] + }, + { + "teal": 4407, + "source": 1152, + "pc": [ + 4442, + 4443 + ] + }, + { + "teal": 4408, + "source": 1152, + "pc": [ + 4444, + 4445 + ] + }, + { + "teal": 4409, + "source": 1152, + "pc": [ + 4446, + 4447 + ] + }, + { + "teal": 4410, + "source": 1152, + "pc": [ + 4448 + ] + }, + { + "teal": 4411, + "source": 1152, + "pc": [ + 4449 + ] + }, + { + "teal": 4412, + "source": 1152, + "pc": [ + 4450 + ] + }, + { + "teal": 4413, + "source": 1152, + "pc": [ + 4451 + ] + }, + { + "teal": 4414, + "source": 1152, + "pc": [ + 4452, + 4453 + ] + }, + { + "teal": 4415, + "source": 1152, + "pc": [ + 4454, + 4455, + 4456 + ] + }, + { + "teal": 4416, + "source": 1152, + "pc": [ + 4457 + ] + }, + { + "teal": 4417, + "source": 1152, + "pc": [ + 4458 + ] + }, + { + "teal": 4418, + "source": 1152, + "pc": [ + 4459 + ] + }, + { + "teal": 4419, + "source": 1152, + "pc": [ + 4460, + 4461 + ] + }, + { + "teal": 4420, + "source": 1152, + "pc": [ + 4462 + ] + }, + { + "teal": 4424, + "source": 1153, + "pc": [ + 4463, + 4464 + ] + }, + { + "teal": 4425, + "source": 1153, + "pc": [ + 4465 + ] + }, + { + "teal": 4426, + "source": 1153, + "pc": [ + 4466, + 4467 + ] + }, + { + "teal": 4427, + "source": 1153, + "pc": [ + 4468, + 4469 + ] + }, + { + "teal": 4428, + "source": 1153, + "pc": [ + 4470, + 4471 + ] + }, + { + "teal": 4429, + "source": 1153, + "pc": [ + 4472 + ] + }, + { + "teal": 4430, + "source": 1153, + "pc": [ + 4473 + ] + }, + { + "teal": 4431, + "source": 1153, + "pc": [ + 4474, + 4475 + ] + }, + { + "teal": 4432, + "source": 1153, + "pc": [ + 4476 + ] + }, + { + "teal": 4433, + "source": 1153, + "pc": [ + 4477 + ] + }, + { + "teal": 4434, + "source": 1114, + "pc": [ + 4478 + ] + }, + { + "teal": 4438, + "source": 1156, + "pc": [ + 4479, + 4480, + 4481 + ] + }, + { + "teal": 4441, + "source": 1156, + "pc": [ + 4482 + ] + }, + { + "teal": 4442, + "source": 1156, + "pc": [ + 4483 + ] + }, + { + "teal": 4446, + "source": 1157, + "pc": [ + 4484 + ] + }, + { + "teal": 4447, + "source": 1157, + "pc": [ + 4485, + 4486 + ] + }, + { + "teal": 4448, + "source": 1157, + "pc": [ + 4487 + ] + }, + { + "teal": 4449, + "source": 1157, + "pc": [ + 4488 + ] + }, + { + "teal": 4450, + "source": 1157, + "pc": [ + 4489 + ] + }, + { + "teal": 4451, + "source": 1157, + "pc": [ + 4490 + ] + }, + { + "teal": 4452, + "source": 1157, + "pc": [ + 4491 + ] + }, + { + "teal": 4456, + "source": 1159, + "pc": [ + 4492 + ] + }, + { + "teal": 4457, + "source": 1159, + "pc": [ + 4493, + 4494 + ] + }, + { + "teal": 4458, + "source": 1159, + "pc": [ + 4495 + ] + }, + { + "teal": 4459, + "source": 1159, + "pc": [ + 4496 + ] + }, + { + "teal": 4460, + "source": 1159, + "pc": [ + 4497 + ] + }, + { + "teal": 4461, + "source": 1159, + "pc": [ + 4498, + 4499 + ] + }, + { + "teal": 4465, + "source": 1160, + "pc": [ + 4500 + ] + }, + { + "teal": 4466, + "source": 1160, + "pc": [ + 4501, + 4502 + ] + }, + { + "teal": 4471, + "source": 1160, + "pc": [ + 4503, + 4504 + ] + }, + { + "teal": 4472, + "source": 1160, + "pc": [ + 4505, + 4506 + ] + }, + { + "teal": 4473, + "source": 1160, + "pc": [ + 4507 + ] + }, + { + "teal": 4474, + "source": 1160, + "pc": [ + 4508, + 4509, + 4510 + ] + }, + { + "teal": 4479, + "source": 1161, + "pc": [ + 4511, + 4512 + ] + }, + { + "teal": 4480, + "source": 1161, + "pc": [ + 4513, + 4514 + ] + }, + { + "teal": 4481, + "source": 1161, + "pc": [ + 4515 + ] + }, + { + "teal": 4482, + "source": 1161, + "pc": [ + 4516 + ] + }, + { + "teal": 4483, + "source": 1161, + "pc": [ + 4517 + ] + }, + { + "teal": 4484, + "source": 1161, + "pc": [ + 4518 + ] + }, + { + "teal": 4485, + "source": 1161, + "pc": [ + 4519, + 4520 + ] + }, + { + "teal": 4486, + "source": 1161, + "pc": [ + 4521 + ] + }, + { + "teal": 4487, + "source": 1161, + "pc": [ + 4522, + 4523, + 4524 + ] + }, + { + "teal": 4492, + "source": 1163, + "pc": [ + 4525 + ] + }, + { + "teal": 4498, + "source": 1165, + "pc": [ + 4526, + 4527 + ] + }, + { + "teal": 4499, + "source": 1165, + "pc": [ + 4528, + 4529 + ] + }, + { + "teal": 4500, + "source": 1165, + "pc": [ + 4530 + ] + }, + { + "teal": 4501, + "source": 1165, + "pc": [ + 4531 + ] + }, + { + "teal": 4502, + "source": 1165, + "pc": [ + 4532 + ] + }, + { + "teal": 4503, + "source": 1165, + "pc": [ + 4533 + ] + }, + { + "teal": 4504, + "source": 1165, + "pc": [ + 4534 + ] + }, + { + "teal": 4505, + "source": 1165, + "pc": [ + 4535 + ] + }, + { + "teal": 4506, + "source": 1165, + "pc": [ + 4536 + ] + }, + { + "teal": 4507, + "source": 1165, + "pc": [ + 4537 + ] + }, + { + "teal": 4508, + "source": 1165, + "pc": [ + 4538 + ] + }, + { + "teal": 4509, + "source": 1165, + "pc": [ + 4539, + 4540, + 4541 + ] + }, + { + "teal": 4514, + "source": 1166, + "pc": [ + 4542, + 4543 + ] + }, + { + "teal": 4515, + "source": 1166, + "pc": [ + 4544 + ] + }, + { + "teal": 4516, + "source": 1166, + "pc": [ + 4545 + ] + }, + { + "teal": 4517, + "source": 1166, + "pc": [ + 4546, + 4547 + ] + }, + { + "teal": 4518, + "source": 1166, + "pc": [ + 4548 + ] + }, + { + "teal": 4519, + "source": 1166, + "pc": [ + 4549, + 4550 + ] + }, + { + "teal": 4520, + "source": 1166, + "pc": [ + 4551 + ] + }, + { + "teal": 4521, + "source": 1166, + "pc": [ + 4552, + 4553 + ] + }, + { + "teal": 4522, + "source": 1166, + "pc": [ + 4554 + ] + }, + { + "teal": 4526, + "source": 1167, + "pc": [ + 4555 + ] + }, + { + "teal": 4533, + "source": 1160, + "pc": [ + 4556, + 4557 + ] + }, + { + "teal": 4534, + "source": 1160, + "pc": [ + 4558 + ] + }, + { + "teal": 4535, + "source": 1160, + "pc": [ + 4559 + ] + }, + { + "teal": 4536, + "source": 1160, + "pc": [ + 4560, + 4561 + ] + }, + { + "teal": 4537, + "source": 1160, + "pc": [ + 4562, + 4563, + 4564 + ] + }, + { + "teal": 4540, + "source": 1170, + "pc": [ + 4565 + ] + }, + { + "teal": 4551, + "source": 1181, + "pc": [ + 4566, + 4567, + 4568 + ] + }, + { + "teal": 4554, + "source": 1181, + "pc": [ + 4569 + ] + }, + { + "teal": 4555, + "source": 1181, + "pc": [ + 4570, + 4571 + ] + }, + { + "teal": 4559, + "source": 1183, + "pc": [ + 4572 + ] + }, + { + "teal": 4560, + "source": 1183, + "pc": [ + 4573, + 4574 + ] + }, + { + "teal": 4564, + "source": 1184, + "pc": [ + 4575 + ] + }, + { + "teal": 4565, + "source": 1184, + "pc": [ + 4576, + 4577 + ] + }, + { + "teal": 4569, + "source": 1185, + "pc": [ + 4578 + ] + }, + { + "teal": 4570, + "source": 1185, + "pc": [ + 4579, + 4580 + ] + }, + { + "teal": 4574, + "source": 1187, + "pc": [ + 4581 + ] + }, + { + "teal": 4575, + "source": 1187, + "pc": [ + 4582, + 4583 + ] + }, + { + "teal": 4576, + "source": 1187, + "pc": [ + 4584 + ] + }, + { + "teal": 4577, + "source": 1187, + "pc": [ + 4585 + ] + }, + { + "teal": 4578, + "source": 1187, + "pc": [ + 4586 + ] + }, + { + "teal": 4579, + "source": 1187, + "pc": [ + 4587, + 4588 + ] + }, + { + "teal": 4583, + "source": 1188, + "pc": [ + 4589 + ] + }, + { + "teal": 4584, + "source": 1188, + "pc": [ + 4590, + 4591 + ] + }, + { + "teal": 4589, + "source": 1188, + "pc": [ + 4592, + 4593 + ] + }, + { + "teal": 4590, + "source": 1188, + "pc": [ + 4594, + 4595 + ] + }, + { + "teal": 4591, + "source": 1188, + "pc": [ + 4596 + ] + }, + { + "teal": 4592, + "source": 1188, + "pc": [ + 4597, + 4598, + 4599 + ] + }, + { + "teal": 4597, + "source": 1189, + "pc": [ + 4600, + 4601 + ] + }, + { + "teal": 4598, + "source": 1189, + "pc": [ + 4602, + 4603 + ] + }, + { + "teal": 4599, + "source": 1189, + "pc": [ + 4604 + ] + }, + { + "teal": 4600, + "source": 1189, + "pc": [ + 4605 + ] + }, + { + "teal": 4601, + "source": 1189, + "pc": [ + 4606 + ] + }, + { + "teal": 4602, + "source": 1189, + "pc": [ + 4607 + ] + }, + { + "teal": 4603, + "source": 1189, + "pc": [ + 4608 + ] + }, + { + "teal": 4604, + "source": 1189, + "pc": [ + 4609 + ] + }, + { + "teal": 4605, + "source": 1189, + "pc": [ + 4610 + ] + }, + { + "teal": 4606, + "source": 1189, + "pc": [ + 4611 + ] + }, + { + "teal": 4607, + "source": 1189, + "pc": [ + 4612 + ] + }, + { + "teal": 4608, + "source": 1189, + "pc": [ + 4613, + 4614, + 4615 + ] + }, + { + "teal": 4611, + "source": 1190, + "pc": [ + 4616, + 4617, + 4618 + ] + }, + { + "teal": 4616, + "source": 1192, + "pc": [ + 4619, + 4620 + ] + }, + { + "teal": 4617, + "source": 1192, + "pc": [ + 4621 + ] + }, + { + "teal": 4618, + "source": 1192, + "pc": [ + 4622 + ] + }, + { + "teal": 4619, + "source": 1192, + "pc": [ + 4623, + 4624 + ] + }, + { + "teal": 4624, + "source": 1193, + "pc": [ + 4625, + 4626 + ] + }, + { + "teal": 4625, + "source": 1193, + "pc": [ + 4627, + 4628 + ] + }, + { + "teal": 4626, + "source": 1193, + "pc": [ + 4629 + ] + }, + { + "teal": 4627, + "source": 1193, + "pc": [ + 4630 + ] + }, + { + "teal": 4628, + "source": 1193, + "pc": [ + 4631 + ] + }, + { + "teal": 4629, + "source": 1193, + "pc": [ + 4632 + ] + }, + { + "teal": 4630, + "source": 1193, + "pc": [ + 4633 + ] + }, + { + "teal": 4631, + "source": 1193, + "pc": [ + 4634 + ] + }, + { + "teal": 4632, + "source": 1193, + "pc": [ + 4635 + ] + }, + { + "teal": 4633, + "source": 1193, + "pc": [ + 4636, + 4637 + ] + }, + { + "teal": 4634, + "source": 1193, + "pc": [ + 4638, + 4639, + 4640 + ] + }, + { + "teal": 4635, + "source": 1193, + "pc": [ + 4641 + ] + }, + { + "teal": 4636, + "source": 1193, + "pc": [ + 4642 + ] + }, + { + "teal": 4637, + "source": 1193, + "pc": [ + 4643, + 4644, + 4645 + ] + }, + { + "teal": 4643, + "source": 1194, + "pc": [ + 4646, + 4647 + ] + }, + { + "teal": 4644, + "source": 1194, + "pc": [ + 4648, + 4649 + ] + }, + { + "teal": 4645, + "source": 1194, + "pc": [ + 4650 + ] + }, + { + "teal": 4646, + "source": 1194, + "pc": [ + 4651 + ] + }, + { + "teal": 4647, + "source": 1194, + "pc": [ + 4652 + ] + }, + { + "teal": 4648, + "source": 1194, + "pc": [ + 4653 + ] + }, + { + "teal": 4649, + "source": 1194, + "pc": [ + 4654, + 4655 + ] + }, + { + "teal": 4650, + "source": 1194, + "pc": [ + 4656 + ] + }, + { + "teal": 4651, + "source": 1194, + "pc": [ + 4657, + 4658, + 4659 + ] + }, + { + "teal": 4656, + "source": 1195, + "pc": [ + 4660 + ] + }, + { + "teal": 4657, + "source": 1195, + "pc": [ + 4661, + 4662 + ] + }, + { + "teal": 4661, + "source": 1197, + "pc": [ + 4663, + 4664 + ] + }, + { + "teal": 4662, + "source": 1197, + "pc": [ + 4665 + ] + }, + { + "teal": 4663, + "source": 1197, + "pc": [ + 4666 + ] + }, + { + "teal": 4664, + "source": 1197, + "pc": [ + 4667, + 4668, + 4669, + 4670, + 4671, + 4672, + 4673, + 4674, + 4675, + 4676, + 4677, + 4678, + 4679, + 4680, + 4681, + 4682, + 4683, + 4684, + 4685, + 4686, + 4687, + 4688, + 4689, + 4690, + 4691, + 4692 + ] + }, + { + "teal": 4665, + "source": 1197, + "pc": [ + 4693 + ] + }, + { + "teal": 4666, + "source": 1197, + "pc": [ + 4694, + 4695 + ] + }, + { + "teal": 4667, + "source": 1197, + "pc": [ + 4696 + ] + }, + { + "teal": 4668, + "source": 1197, + "pc": [ + 4697, + 4698 + ] + }, + { + "teal": 4669, + "source": 1197, + "pc": [ + 4699 + ] + }, + { + "teal": 4670, + "source": 1194, + "pc": [ + 4700, + 4701, + 4702 + ] + }, + { + "teal": 4675, + "source": 1199, + "pc": [ + 4703, + 4704 + ] + }, + { + "teal": 4676, + "source": 1199, + "pc": [ + 4705 + ] + }, + { + "teal": 4677, + "source": 1199, + "pc": [ + 4706 + ] + }, + { + "teal": 4678, + "source": 1199, + "pc": [ + 4707, + 4708 + ] + }, + { + "teal": 4687, + "source": 1188, + "pc": [ + 4709, + 4710 + ] + }, + { + "teal": 4688, + "source": 1188, + "pc": [ + 4711 + ] + }, + { + "teal": 4689, + "source": 1188, + "pc": [ + 4712 + ] + }, + { + "teal": 4690, + "source": 1188, + "pc": [ + 4713, + 4714 + ] + }, + { + "teal": 4691, + "source": 1188, + "pc": [ + 4715, + 4716, + 4717 + ] + }, + { + "teal": 4697, + "source": 1203, + "pc": [ + 4718, + 4719 + ] + }, + { + "teal": 4698, + "source": 1203, + "pc": [ + 4720 + ] + }, + { + "teal": 4699, + "source": 1203, + "pc": [ + 4721, + 4722, + 4723 + ] + }, + { + "teal": 4702, + "source": 1204, + "pc": [ + 4724 + ] + }, + { + "teal": 4707, + "source": 1207, + "pc": [ + 4725, + 4726 + ] + }, + { + "teal": 4708, + "source": 1207, + "pc": [ + 4727 + ] + }, + { + "teal": 4709, + "source": 1207, + "pc": [ + 4728, + 4729 + ] + }, + { + "teal": 4710, + "source": 1207, + "pc": [ + 4730 + ] + }, + { + "teal": 4711, + "source": 1207, + "pc": [ + 4731 + ] + }, + { + "teal": 4712, + "source": 1207, + "pc": [ + 4732 + ] + }, + { + "teal": 4713, + "source": 1207, + "pc": [ + 4733 + ] + }, + { + "teal": 4714, + "source": 1207, + "pc": [ + 4734, + 4735 + ] + }, + { + "teal": 4715, + "source": 1207, + "pc": [ + 4736 + ] + }, + { + "teal": 4716, + "source": 1207, + "pc": [ + 4737 + ] + }, + { + "teal": 4717, + "source": 1207, + "pc": [ + 4738 + ] + }, + { + "teal": 4720, + "source": 1207, + "pc": [ + 4739, + 4740 + ] + }, + { + "teal": 4723, + "source": 1207, + "pc": [ + 4741, + 4742 + ] + }, + { + "teal": 4724, + "source": 1207, + "pc": [ + 4743 + ] + }, + { + "teal": 4728, + "source": 1210, + "pc": [ + 4744, + 4745, + 4746 + ] + }, + { + "teal": 4731, + "source": 1210, + "pc": [ + 4747 + ] + }, + { + "teal": 4732, + "source": 1210, + "pc": [ + 4748, + 4749 + ] + }, + { + "teal": 4736, + "source": 1211, + "pc": [ + 4750, + 4751 + ] + }, + { + "teal": 4737, + "source": 1211, + "pc": [ + 4752, + 4753 + ] + }, + { + "teal": 4738, + "source": 1211, + "pc": [ + 4754 + ] + }, + { + "teal": 4739, + "source": 1211, + "pc": [ + 4755, + 4756 + ] + }, + { + "teal": 4740, + "source": 1211, + "pc": [ + 4757 + ] + }, + { + "teal": 4741, + "source": 1211, + "pc": [ + 4758 + ] + }, + { + "teal": 4742, + "source": 1211, + "pc": [ + 4759, + 4760 + ] + }, + { + "teal": 4743, + "source": 1211, + "pc": [ + 4761 + ] + }, + { + "teal": 4744, + "source": 1211, + "pc": [ + 4762, + 4763 + ] + }, + { + "teal": 4748, + "source": 1212, + "pc": [ + 4764, + 4765, + 4766 + ] + }, + { + "teal": 4749, + "source": 1212, + "pc": [ + 4767 + ] + }, + { + "teal": 4750, + "source": 1212, + "pc": [ + 4768 + ] + }, + { + "teal": 4751, + "source": 1212, + "pc": [ + 4769, + 4770 + ] + }, + { + "teal": 4752, + "source": 1212, + "pc": [ + 4771 + ] + }, + { + "teal": 4753, + "source": 1212, + "pc": [ + 4772 + ] + }, + { + "teal": 4754, + "source": 1212, + "pc": [ + 4773, + 4774 + ] + }, + { + "teal": 4755, + "source": 1212, + "pc": [ + 4775 + ] + }, + { + "teal": 4756, + "source": 1212, + "pc": [ + 4776 + ] + }, + { + "teal": 4757, + "source": 1212, + "pc": [ + 4777, + 4778 + ] + }, + { + "teal": 4761, + "source": 1214, + "pc": [ + 4779, + 4780 + ] + }, + { + "teal": 4762, + "source": 1214, + "pc": [ + 4781 + ] + }, + { + "teal": 4763, + "source": 1214, + "pc": [ + 4782 + ] + }, + { + "teal": 4764, + "source": 1214, + "pc": [ + 4783 + ] + }, + { + "teal": 4765, + "source": 1214, + "pc": [ + 4784, + 4785, + 4786 + ] + }, + { + "teal": 4766, + "source": 1214, + "pc": [ + 4787, + 4788 + ] + }, + { + "teal": 4767, + "source": 1214, + "pc": [ + 4789 + ] + }, + { + "teal": 4768, + "source": 1214, + "pc": [ + 4790 + ] + }, + { + "teal": 4769, + "source": 1214, + "pc": [ + 4791 + ] + }, + { + "teal": 4772, + "source": 1214, + "pc": [ + 4792 + ] + }, + { + "teal": 4776, + "source": 1216, + "pc": [ + 4793 + ] + }, + { + "teal": 4777, + "source": 1216, + "pc": [ + 4794, + 4795 + ] + }, + { + "teal": 4782, + "source": 1216, + "pc": [ + 4796, + 4797 + ] + }, + { + "teal": 4783, + "source": 1216, + "pc": [ + 4798, + 4799 + ] + }, + { + "teal": 4784, + "source": 1216, + "pc": [ + 4800 + ] + }, + { + "teal": 4785, + "source": 1216, + "pc": [ + 4801, + 4802, + 4803 + ] + }, + { + "teal": 4790, + "source": 1217, + "pc": [ + 4804, + 4805 + ] + }, + { + "teal": 4791, + "source": 1217, + "pc": [ + 4806 + ] + }, + { + "teal": 4792, + "source": 1217, + "pc": [ + 4807, + 4808 + ] + }, + { + "teal": 4793, + "source": 1217, + "pc": [ + 4809 + ] + }, + { + "teal": 4794, + "source": 1217, + "pc": [ + 4810 + ] + }, + { + "teal": 4795, + "source": 1217, + "pc": [ + 4811 + ] + }, + { + "teal": 4796, + "source": 1217, + "pc": [ + 4812 + ] + }, + { + "teal": 4797, + "source": 1217, + "pc": [ + 4813 + ] + }, + { + "teal": 4798, + "source": 1217, + "pc": [ + 4814 + ] + }, + { + "teal": 4799, + "source": 1217, + "pc": [ + 4815 + ] + }, + { + "teal": 4800, + "source": 1217, + "pc": [ + 4816, + 4817 + ] + }, + { + "teal": 4801, + "source": 1217, + "pc": [ + 4818 + ] + }, + { + "teal": 4802, + "source": 1217, + "pc": [ + 4819 + ] + }, + { + "teal": 4803, + "source": 1217, + "pc": [ + 4820 + ] + }, + { + "teal": 4804, + "source": 1217, + "pc": [ + 4821 + ] + }, + { + "teal": 4805, + "source": 1217, + "pc": [ + 4822 + ] + }, + { + "teal": 4806, + "source": 1217, + "pc": [ + 4823 + ] + }, + { + "teal": 4807, + "source": 1217, + "pc": [ + 4824 + ] + }, + { + "teal": 4808, + "source": 1217, + "pc": [ + 4825 + ] + }, + { + "teal": 4809, + "source": 1217, + "pc": [ + 4826, + 4827, + 4828 + ] + }, + { + "teal": 4814, + "source": 1219, + "pc": [ + 4829, + 4830 + ] + }, + { + "teal": 4815, + "source": 1219, + "pc": [ + 4831, + 4832 + ] + }, + { + "teal": 4816, + "source": 1219, + "pc": [ + 4833 + ] + }, + { + "teal": 4817, + "source": 1219, + "pc": [ + 4834 + ] + }, + { + "teal": 4818, + "source": 1219, + "pc": [ + 4835 + ] + }, + { + "teal": 4819, + "source": 1219, + "pc": [ + 4836 + ] + }, + { + "teal": 4820, + "source": 1219, + "pc": [ + 4837 + ] + }, + { + "teal": 4821, + "source": 1219, + "pc": [ + 4838 + ] + }, + { + "teal": 4822, + "source": 1219, + "pc": [ + 4839 + ] + }, + { + "teal": 4823, + "source": 1219, + "pc": [ + 4840, + 4841 + ] + }, + { + "teal": 4824, + "source": 1219, + "pc": [ + 4842 + ] + }, + { + "teal": 4825, + "source": 1219, + "pc": [ + 4843 + ] + }, + { + "teal": 4826, + "source": 1219, + "pc": [ + 4844 + ] + }, + { + "teal": 4827, + "source": 1219, + "pc": [ + 4845, + 4846 + ] + }, + { + "teal": 4828, + "source": 1219, + "pc": [ + 4847 + ] + }, + { + "teal": 4829, + "source": 1219, + "pc": [ + 4848 + ] + }, + { + "teal": 4830, + "source": 1219, + "pc": [ + 4849, + 4850 + ] + }, + { + "teal": 4831, + "source": 1219, + "pc": [ + 4851 + ] + }, + { + "teal": 4832, + "source": 1219, + "pc": [ + 4852 + ] + }, + { + "teal": 4833, + "source": 1219, + "pc": [ + 4853, + 4854 + ] + }, + { + "teal": 4834, + "source": 1219, + "pc": [ + 4855 + ] + }, + { + "teal": 4838, + "source": 1220, + "pc": [ + 4856 + ] + }, + { + "teal": 4845, + "source": 1216, + "pc": [ + 4857, + 4858 + ] + }, + { + "teal": 4846, + "source": 1216, + "pc": [ + 4859 + ] + }, + { + "teal": 4847, + "source": 1216, + "pc": [ + 4860 + ] + }, + { + "teal": 4848, + "source": 1216, + "pc": [ + 4861, + 4862 + ] + }, + { + "teal": 4849, + "source": 1216, + "pc": [ + 4863, + 4864, + 4865 + ] + }, + { + "teal": 4852, + "source": 1223, + "pc": [ + 4866 + ] + }, + { + "teal": 4862, + "source": 1233, + "pc": [ + 4867, + 4868, + 4869 + ] + }, + { + "teal": 4865, + "source": 1233, + "pc": [ + 4870 + ] + }, + { + "teal": 4866, + "source": 1233, + "pc": [ + 4871, + 4872 + ] + }, + { + "teal": 4870, + "source": 1234, + "pc": [ + 4873, + 4874 + ] + }, + { + "teal": 4871, + "source": 1234, + "pc": [ + 4875 + ] + }, + { + "teal": 4872, + "source": 1234, + "pc": [ + 4876 + ] + }, + { + "teal": 4873, + "source": 1234, + "pc": [ + 4877, + 4878 + ] + }, + { + "teal": 4874, + "source": 1234, + "pc": [ + 4879 + ] + }, + { + "teal": 4875, + "source": 1234, + "pc": [ + 4880 + ] + }, + { + "teal": 4876, + "source": 1234, + "pc": [ + 4881, + 4882 + ] + }, + { + "teal": 4877, + "source": 1234, + "pc": [ + 4883 + ] + }, + { + "teal": 4878, + "source": 1234, + "pc": [ + 4884 + ] + }, + { + "teal": 4879, + "source": 1234, + "pc": [ + 4885, + 4886 + ] + }, + { + "teal": 4884, + "source": 1235, + "pc": [ + 4887, + 4888 + ] + }, + { + "teal": 4885, + "source": 1235, + "pc": [ + 4889 + ] + }, + { + "teal": 4886, + "source": 1235, + "pc": [ + 4890 + ] + }, + { + "teal": 4887, + "source": 1235, + "pc": [ + 4891, + 4892, + 4893 + ] + }, + { + "teal": 4892, + "source": 1236, + "pc": [ + 4894 + ] + }, + { + "teal": 4897, + "source": 1238, + "pc": [ + 4895, + 4896 + ] + }, + { + "teal": 4898, + "source": 1238, + "pc": [ + 4897, + 4898 + ] + }, + { + "teal": 4902, + "source": 1239, + "pc": [ + 4899, + 4900 + ] + }, + { + "teal": 4903, + "source": 1239, + "pc": [ + 4901, + 4902 + ] + }, + { + "teal": 4904, + "source": 1239, + "pc": [ + 4903 + ] + }, + { + "teal": 4905, + "source": 1239, + "pc": [ + 4904, + 4905 + ] + }, + { + "teal": 4906, + "source": 1239, + "pc": [ + 4906 + ] + }, + { + "teal": 4907, + "source": 1239, + "pc": [ + 4907 + ] + }, + { + "teal": 4908, + "source": 1239, + "pc": [ + 4908, + 4909 + ] + }, + { + "teal": 4909, + "source": 1239, + "pc": [ + 4910 + ] + }, + { + "teal": 4910, + "source": 1239, + "pc": [ + 4911, + 4912 + ] + }, + { + "teal": 4917, + "source": 1243, + "pc": [ + 4913, + 4914 + ] + }, + { + "teal": 4918, + "source": 1243, + "pc": [ + 4915 + ] + }, + { + "teal": 4919, + "source": 1243, + "pc": [ + 4916 + ] + }, + { + "teal": 4920, + "source": 1243, + "pc": [ + 4917 + ] + }, + { + "teal": 4921, + "source": 1243, + "pc": [ + 4918, + 4919, + 4920 + ] + }, + { + "teal": 4922, + "source": 1244, + "pc": [ + 4921, + 4922 + ] + }, + { + "teal": 4923, + "source": 1244, + "pc": [ + 4923, + 4924 + ] + }, + { + "teal": 4924, + "source": 1244, + "pc": [ + 4925 + ] + }, + { + "teal": 4925, + "source": 1243, + "pc": [ + 4926 + ] + }, + { + "teal": 4928, + "source": 1244, + "pc": [ + 4927 + ] + }, + { + "teal": 4929, + "source": 1244, + "pc": [ + 4928, + 4929, + 4930 + ] + }, + { + "teal": 4930, + "source": 1245, + "pc": [ + 4931, + 4932 + ] + }, + { + "teal": 4931, + "source": 1245, + "pc": [ + 4933, + 4934 + ] + }, + { + "teal": 4932, + "source": 1245, + "pc": [ + 4935 + ] + }, + { + "teal": 4933, + "source": 1244, + "pc": [ + 4936 + ] + }, + { + "teal": 4936, + "source": 1242, + "pc": [ + 4937, + 4938, + 4939 + ] + }, + { + "teal": 4941, + "source": 1247, + "pc": [ + 4940, + 4941 + ] + }, + { + "teal": 4942, + "source": 1247, + "pc": [ + 4942 + ] + }, + { + "teal": 4943, + "source": 1247, + "pc": [ + 4943 + ] + }, + { + "teal": 4944, + "source": 1247, + "pc": [ + 4944 + ] + }, + { + "teal": 4948, + "source": 1248, + "pc": [ + 4945, + 4946 + ] + }, + { + "teal": 4949, + "source": 1248, + "pc": [ + 4947 + ] + }, + { + "teal": 4950, + "source": 1248, + "pc": [ + 4948 + ] + }, + { + "teal": 4951, + "source": 1248, + "pc": [ + 4949, + 4950 + ] + }, + { + "teal": 4952, + "source": 1248, + "pc": [ + 4951 + ] + }, + { + "teal": 4953, + "source": 1248, + "pc": [ + 4952 + ] + }, + { + "teal": 4954, + "source": 1248, + "pc": [ + 4953, + 4954 + ] + }, + { + "teal": 4955, + "source": 1248, + "pc": [ + 4955 + ] + }, + { + "teal": 4956, + "source": 1248, + "pc": [ + 4956 + ] + }, + { + "teal": 4957, + "source": 1248, + "pc": [ + 4957, + 4958 + ] + }, + { + "teal": 4962, + "source": 1249, + "pc": [ + 4959, + 4960 + ] + }, + { + "teal": 4963, + "source": 1249, + "pc": [ + 4961 + ] + }, + { + "teal": 4964, + "source": 1249, + "pc": [ + 4962 + ] + }, + { + "teal": 4965, + "source": 1249, + "pc": [ + 4963, + 4964, + 4965 + ] + }, + { + "teal": 4970, + "source": 1250, + "pc": [ + 4966 + ] + }, + { + "teal": 4971, + "source": 1250, + "pc": [ + 4967, + 4968 + ] + }, + { + "teal": 4979, + "source": 1253, + "pc": [ + 4969, + 4970 + ] + }, + { + "teal": 4980, + "source": 1253, + "pc": [ + 4971, + 4972 + ] + }, + { + "teal": 4981, + "source": 1253, + "pc": [ + 4973, + 4974 + ] + }, + { + "teal": 4982, + "source": 1253, + "pc": [ + 4975 + ] + }, + { + "teal": 4983, + "source": 1253, + "pc": [ + 4976, + 4977 + ] + }, + { + "teal": 4984, + "source": 1253, + "pc": [ + 4978 + ] + }, + { + "teal": 4987, + "source": 1252, + "pc": [ + 4979 + ] + }, + { + "teal": 4993, + "source": 1257, + "pc": [ + 4980, + 4981 + ] + }, + { + "teal": 4994, + "source": 1257, + "pc": [ + 4982 + ] + }, + { + "teal": 4995, + "source": 1257, + "pc": [ + 4983 + ] + }, + { + "teal": 4996, + "source": 1257, + "pc": [ + 4984, + 4985, + 4986 + ] + }, + { + "teal": 5004, + "source": 1259, + "pc": [ + 4987, + 4988 + ] + }, + { + "teal": 5005, + "source": 1259, + "pc": [ + 4989, + 4990 + ] + }, + { + "teal": 5006, + "source": 1259, + "pc": [ + 4991 + ] + }, + { + "teal": 5007, + "source": 1259, + "pc": [ + 4992, + 4993 + ] + }, + { + "teal": 5008, + "source": 1259, + "pc": [ + 4994 + ] + }, + { + "teal": 5011, + "source": 1258, + "pc": [ + 4995 + ] + }, + { + "teal": 5017, + "source": 1263, + "pc": [ + 4996, + 4997 + ] + }, + { + "teal": 5018, + "source": 1263, + "pc": [ + 4998, + 4999 + ] + }, + { + "teal": 5019, + "source": 1263, + "pc": [ + 5000 + ] + }, + { + "teal": 5020, + "source": 1263, + "pc": [ + 5001, + 5002, + 5003 + ] + }, + { + "teal": 5025, + "source": 1264, + "pc": [ + 5004, + 5005 + ] + }, + { + "teal": 5026, + "source": 1264, + "pc": [ + 5006 + ] + }, + { + "teal": 5027, + "source": 1264, + "pc": [ + 5007 + ] + }, + { + "teal": 5028, + "source": 1264, + "pc": [ + 5008, + 5009 + ] + }, + { + "teal": 5032, + "source": 1265, + "pc": [ + 5010, + 5011 + ] + }, + { + "teal": 5033, + "source": 1265, + "pc": [ + 5012 + ] + }, + { + "teal": 5034, + "source": 1265, + "pc": [ + 5013 + ] + }, + { + "teal": 5035, + "source": 1265, + "pc": [ + 5014 + ] + }, + { + "teal": 5042, + "source": 1267, + "pc": [ + 5015, + 5016 + ] + }, + { + "teal": 5043, + "source": 1267, + "pc": [ + 5017, + 5018 + ] + }, + { + "teal": 5044, + "source": 1267, + "pc": [ + 5019 + ] + }, + { + "teal": 5047, + "source": 1266, + "pc": [ + 5020 + ] + }, + { + "teal": 5053, + "source": 1271, + "pc": [ + 5021, + 5022 + ] + }, + { + "teal": 5054, + "source": 1271, + "pc": [ + 5023, + 5024 + ] + }, + { + "teal": 5055, + "source": 1271, + "pc": [ + 5025 + ] + }, + { + "teal": 5056, + "source": 1271, + "pc": [ + 5026, + 5027, + 5028 + ] + }, + { + "teal": 5061, + "source": 1272, + "pc": [ + 5029, + 5030 + ] + }, + { + "teal": 5062, + "source": 1272, + "pc": [ + 5031 + ] + }, + { + "teal": 5063, + "source": 1272, + "pc": [ + 5032 + ] + }, + { + "teal": 5064, + "source": 1272, + "pc": [ + 5033, + 5034 + ] + }, + { + "teal": 5065, + "source": 1272, + "pc": [ + 5035 + ] + }, + { + "teal": 5066, + "source": 1272, + "pc": [ + 5036 + ] + }, + { + "teal": 5067, + "source": 1272, + "pc": [ + 5037, + 5038 + ] + }, + { + "teal": 5068, + "source": 1272, + "pc": [ + 5039 + ] + }, + { + "teal": 5069, + "source": 1272, + "pc": [ + 5040 + ] + }, + { + "teal": 5070, + "source": 1272, + "pc": [ + 5041, + 5042 + ] + }, + { + "teal": 5077, + "source": 1276, + "pc": [ + 5043, + 5044 + ] + }, + { + "teal": 5078, + "source": 1276, + "pc": [ + 5045, + 5046 + ] + }, + { + "teal": 5079, + "source": 1276, + "pc": [ + 5047 + ] + }, + { + "teal": 5080, + "source": 1276, + "pc": [ + 5048, + 5049 + ] + }, + { + "teal": 5081, + "source": 1276, + "pc": [ + 5050, + 5051, + 5052 + ] + }, + { + "teal": 5084, + "source": 1275, + "pc": [ + 5053 + ] + }, + { + "teal": 5090, + "source": 1280, + "pc": [ + 5054, + 5055 + ] + }, + { + "teal": 5091, + "source": 1280, + "pc": [ + 5056, + 5057 + ] + }, + { + "teal": 5092, + "source": 1280, + "pc": [ + 5058 + ] + }, + { + "teal": 5093, + "source": 1280, + "pc": [ + 5059, + 5060, + 5061 + ] + }, + { + "teal": 5098, + "source": 1282, + "pc": [ + 5062, + 5063 + ] + }, + { + "teal": 5099, + "source": 1282, + "pc": [ + 5064, + 5065 + ] + }, + { + "teal": 5103, + "source": 1283, + "pc": [ + 5066, + 5067 + ] + }, + { + "teal": 5104, + "source": 1283, + "pc": [ + 5068, + 5069, + 5070 + ] + }, + { + "teal": 5107, + "source": 1283, + "pc": [ + 5071 + ] + }, + { + "teal": 5115, + "source": 1287, + "pc": [ + 5072, + 5073 + ] + }, + { + "teal": 5116, + "source": 1287, + "pc": [ + 5074, + 5075 + ] + }, + { + "teal": 5117, + "source": 1287, + "pc": [ + 5076 + ] + }, + { + "teal": 5118, + "source": 1287, + "pc": [ + 5077 + ] + }, + { + "teal": 5119, + "source": 1288, + "pc": [ + 5078, + 5079 + ] + }, + { + "teal": 5120, + "source": 1287, + "pc": [ + 5080 + ] + }, + { + "teal": 5121, + "source": 1288, + "pc": [ + 5081 + ] + }, + { + "teal": 5122, + "source": 1288, + "pc": [ + 5082, + 5083, + 5084 + ] + }, + { + "teal": 5123, + "source": 1288, + "pc": [ + 5085, + 5086 + ] + }, + { + "teal": 5124, + "source": 1288, + "pc": [ + 5087, + 5088 + ] + }, + { + "teal": 5125, + "source": 1288, + "pc": [ + 5089, + 5090, + 5091 + ] + }, + { + "teal": 5126, + "source": 1288, + "pc": [ + 5092 + ] + }, + { + "teal": 5130, + "source": 1286, + "pc": [ + 5093 + ] + }, + { + "teal": 5134, + "source": 1293, + "pc": [ + 5094, + 5095 + ] + }, + { + "teal": 5135, + "source": 1293, + "pc": [ + 5096 + ] + }, + { + "teal": 5136, + "source": 1293, + "pc": [ + 5097 + ] + }, + { + "teal": 5137, + "source": 1293, + "pc": [ + 5098, + 5099 + ] + }, + { + "teal": 5144, + "source": 1296, + "pc": [ + 5100, + 5101 + ] + }, + { + "teal": 5145, + "source": 1296, + "pc": [ + 5102, + 5103, + 5104, + 5105, + 5106, + 5107, + 5108, + 5109, + 5110, + 5111, + 5112, + 5113, + 5114, + 5115, + 5116 + ] + }, + { + "teal": 5146, + "source": 1296, + "pc": [ + 5117 + ] + }, + { + "teal": 5147, + "source": 1296, + "pc": [ + 5118 + ] + }, + { + "teal": 5148, + "source": 1296, + "pc": [ + 5119, + 5120 + ] + }, + { + "teal": 5149, + "source": 1296, + "pc": [ + 5121 + ] + }, + { + "teal": 5152, + "source": 1295, + "pc": [ + 5122 + ] + }, + { + "teal": 5155, + "source": 1233, + "pc": [ + 5123 + ] + }, + { + "teal": 5167, + "source": 1311, + "pc": [ + 5124, + 5125, + 5126 + ] + }, + { + "teal": 5170, + "source": 1311, + "pc": [ + 5127 + ] + }, + { + "teal": 5174, + "source": 1313, + "pc": [ + 5128, + 5129 + ] + }, + { + "teal": 5175, + "source": 1313, + "pc": [ + 5130, + 5131, + 5132, + 5133, + 5134, + 5135, + 5136, + 5137 + ] + }, + { + "teal": 5176, + "source": 1313, + "pc": [ + 5138 + ] + }, + { + "teal": 5177, + "source": 1313, + "pc": [ + 5139 + ] + }, + { + "teal": 5178, + "source": 1313, + "pc": [ + 5140, + 5141 + ] + }, + { + "teal": 5186, + "source": 1315, + "pc": [ + 5142 + ] + }, + { + "teal": 5187, + "source": 1315, + "pc": [ + 5143, + 5144 + ] + }, + { + "teal": 5188, + "source": 1315, + "pc": [ + 5145, + 5146 + ] + }, + { + "teal": 5192, + "source": 1316, + "pc": [ + 5147, + 5148 + ] + }, + { + "teal": 5193, + "source": 1316, + "pc": [ + 5149, + 5150 + ] + }, + { + "teal": 5197, + "source": 1317, + "pc": [ + 5151, + 5152 + ] + }, + { + "teal": 5198, + "source": 1317, + "pc": [ + 5153, + 5154 + ] + }, + { + "teal": 5199, + "source": 1317, + "pc": [ + 5155, + 5156 + ] + }, + { + "teal": 5200, + "source": 1317, + "pc": [ + 5157, + 5158 + ] + }, + { + "teal": 5201, + "source": 1317, + "pc": [ + 5159, + 5160 + ] + }, + { + "teal": 5202, + "source": 1317, + "pc": [ + 5161 + ] + }, + { + "teal": 5203, + "source": 1317, + "pc": [ + 5162, + 5163 + ] + }, + { + "teal": 5207, + "source": 1318, + "pc": [ + 5164, + 5165 + ] + }, + { + "teal": 5208, + "source": 1318, + "pc": [ + 5166, + 5167 + ] + }, + { + "teal": 5211, + "source": 1315, + "pc": [ + 5168 + ] + }, + { + "teal": 5212, + "source": 1315, + "pc": [ + 5169, + 5170 + ] + }, + { + "teal": 5215, + "source": 1315, + "pc": [ + 5171 + ] + }, + { + "teal": 5219, + "source": 1320, + "pc": [ + 5172, + 5173 + ] + }, + { + "teal": 5220, + "source": 1320, + "pc": [ + 5174 + ] + }, + { + "teal": 5221, + "source": 1320, + "pc": [ + 5175 + ] + }, + { + "teal": 5222, + "source": 1320, + "pc": [ + 5176 + ] + }, + { + "teal": 5225, + "source": 1320, + "pc": [ + 5177, + 5178 + ] + }, + { + "teal": 5226, + "source": 1320, + "pc": [ + 5179 + ] + }, + { + "teal": 5237, + "source": 1331, + "pc": [ + 5180, + 5181, + 5182 + ] + }, + { + "teal": 5240, + "source": 1331, + "pc": [ + 5183 + ] + }, + { + "teal": 5241, + "source": 1331, + "pc": [ + 5184, + 5185 + ] + }, + { + "teal": 5248, + "source": 1332, + "pc": [ + 5186 + ] + }, + { + "teal": 5249, + "source": 1332, + "pc": [ + 5187, + 5188 + ] + }, + { + "teal": 5250, + "source": 1332, + "pc": [ + 5189, + 5190 + ] + }, + { + "teal": 5254, + "source": 1333, + "pc": [ + 5191, + 5192 + ] + }, + { + "teal": 5255, + "source": 1333, + "pc": [ + 5193, + 5194 + ] + }, + { + "teal": 5259, + "source": 1334, + "pc": [ + 5195, + 5196, + 5197, + 5198, + 5199, + 5200, + 5201, + 5202, + 5203, + 5204, + 5205, + 5206, + 5207, + 5208, + 5209 + ] + }, + { + "teal": 5260, + "source": 1334, + "pc": [ + 5210, + 5211 + ] + }, + { + "teal": 5261, + "source": 1334, + "pc": [ + 5212, + 5213, + 5214, + 5215, + 5216, + 5217, + 5218, + 5219, + 5220, + 5221, + 5222, + 5223, + 5224, + 5225, + 5226 + ] + }, + { + "teal": 5262, + "source": 1334, + "pc": [ + 5227, + 5228 + ] + }, + { + "teal": 5265, + "source": 1332, + "pc": [ + 5229 + ] + }, + { + "teal": 5266, + "source": 1332, + "pc": [ + 5230, + 5231 + ] + }, + { + "teal": 5269, + "source": 1332, + "pc": [ + 5232 + ] + }, + { + "teal": 5273, + "source": 1336, + "pc": [ + 5233, + 5234 + ] + }, + { + "teal": 5274, + "source": 1336, + "pc": [ + 5235, + 5236 + ] + }, + { + "teal": 5278, + "source": 1337, + "pc": [ + 5237 + ] + }, + { + "teal": 5279, + "source": 1337, + "pc": [ + 5238, + 5239 + ] + }, + { + "teal": 5284, + "source": 1337, + "pc": [ + 5240, + 5241 + ] + }, + { + "teal": 5285, + "source": 1337, + "pc": [ + 5242, + 5243 + ] + }, + { + "teal": 5286, + "source": 1337, + "pc": [ + 5244 + ] + }, + { + "teal": 5287, + "source": 1337, + "pc": [ + 5245 + ] + }, + { + "teal": 5288, + "source": 1337, + "pc": [ + 5246, + 5247, + 5248 + ] + }, + { + "teal": 5292, + "source": 1338, + "pc": [ + 5249, + 5250 + ] + }, + { + "teal": 5293, + "source": 1338, + "pc": [ + 5251, + 5252 + ] + }, + { + "teal": 5294, + "source": 1338, + "pc": [ + 5253, + 5254 + ] + }, + { + "teal": 5295, + "source": 1338, + "pc": [ + 5255 + ] + }, + { + "teal": 5296, + "source": 1338, + "pc": [ + 5256, + 5257 + ] + }, + { + "teal": 5301, + "source": 1339, + "pc": [ + 5258, + 5259 + ] + }, + { + "teal": 5302, + "source": 1339, + "pc": [ + 5260, + 5261 + ] + }, + { + "teal": 5303, + "source": 1339, + "pc": [ + 5262 + ] + }, + { + "teal": 5304, + "source": 1339, + "pc": [ + 5263 + ] + }, + { + "teal": 5305, + "source": 1339, + "pc": [ + 5264, + 5265, + 5266 + ] + }, + { + "teal": 5306, + "source": 1339, + "pc": [ + 5267, + 5268 + ] + }, + { + "teal": 5307, + "source": 1339, + "pc": [ + 5269, + 5270 + ] + }, + { + "teal": 5308, + "source": 1339, + "pc": [ + 5271 + ] + }, + { + "teal": 5309, + "source": 1339, + "pc": [ + 5272 + ] + }, + { + "teal": 5312, + "source": 1339, + "pc": [ + 5273, + 5274, + 5275 + ] + }, + { + "teal": 5317, + "source": 1340, + "pc": [ + 5276 + ] + }, + { + "teal": 5320, + "source": 1340, + "pc": [ + 5277, + 5278 + ] + }, + { + "teal": 5323, + "source": 1340, + "pc": [ + 5279, + 5280 + ] + }, + { + "teal": 5324, + "source": 1340, + "pc": [ + 5281 + ] + }, + { + "teal": 5331, + "source": 1337, + "pc": [ + 5282, + 5283 + ] + }, + { + "teal": 5332, + "source": 1337, + "pc": [ + 5284, + 5285 + ] + }, + { + "teal": 5333, + "source": 1337, + "pc": [ + 5286 + ] + }, + { + "teal": 5334, + "source": 1337, + "pc": [ + 5287, + 5288 + ] + }, + { + "teal": 5335, + "source": 1337, + "pc": [ + 5289, + 5290, + 5291 + ] + }, + { + "teal": 5340, + "source": 1343, + "pc": [ + 5292 + ] + }, + { + "teal": 5343, + "source": 1343, + "pc": [ + 5293, + 5294 + ] + }, + { + "teal": 5346, + "source": 1343, + "pc": [ + 5295, + 5296 + ] + }, + { + "teal": 5347, + "source": 1343, + "pc": [ + 5297 + ] + }, + { + "teal": 5353, + "source": 1349, + "pc": [ + 5298, + 5299, + 5300 + ] + }, + { + "teal": 5357, + "source": 1351, + "pc": [ + 5301, + 5302, + 5303, + 5304, + 5305, + 5306, + 5307, + 5308 + ] + }, + { + "teal": 5358, + "source": 1351, + "pc": [ + 5309 + ] + }, + { + "teal": 5366, + "source": 1359, + "pc": [ + 5310, + 5311, + 5312 + ] + }, + { + "teal": 5369, + "source": 1359, + "pc": [ + 5313 + ] + }, + { + "teal": 5373, + "source": 1360, + "pc": [ + 5314, + 5315, + 5316 + ] + }, + { + "teal": 5374, + "source": 1360, + "pc": [ + 5317, + 5318 + ] + }, + { + "teal": 5378, + "source": 1362, + "pc": [ + 5319, + 5320 + ] + }, + { + "teal": 5379, + "source": 1362, + "pc": [ + 5321, + 5322 + ] + }, + { + "teal": 5380, + "source": 1362, + "pc": [ + 5323 + ] + }, + { + "teal": 5381, + "source": 1362, + "pc": [ + 5324 + ] + }, + { + "teal": 5382, + "source": 1362, + "pc": [ + 5325, + 5326 + ] + }, + { + "teal": 5383, + "source": 1362, + "pc": [ + 5327 + ] + }, + { + "teal": 5384, + "source": 1362, + "pc": [ + 5328 + ] + }, + { + "teal": 5385, + "source": 1362, + "pc": [ + 5329 + ] + }, + { + "teal": 5386, + "source": 1362, + "pc": [ + 5330 + ] + }, + { + "teal": 5387, + "source": 1362, + "pc": [ + 5331 + ] + }, + { + "teal": 5388, + "source": 1362, + "pc": [ + 5332 + ] + }, + { + "teal": 5391, + "source": 1362, + "pc": [ + 5333, + 5334 + ] + }, + { + "teal": 5392, + "source": 1362, + "pc": [ + 5335 + ] + }, + { + "teal": 5399, + "source": 1369, + "pc": [ + 5336, + 5337, + 5338 + ] + }, + { + "teal": 5402, + "source": 1369, + "pc": [ + 5339 + ] + }, + { + "teal": 5406, + "source": 1370, + "pc": [ + 5340, + 5341, + 5342 + ] + }, + { + "teal": 5407, + "source": 1370, + "pc": [ + 5343, + 5344 + ] + }, + { + "teal": 5411, + "source": 1372, + "pc": [ + 5345, + 5346 + ] + }, + { + "teal": 5412, + "source": 1372, + "pc": [ + 5347, + 5348, + 5349 + ] + }, + { + "teal": 5413, + "source": 1372, + "pc": [ + 5350 + ] + }, + { + "teal": 5414, + "source": 1372, + "pc": [ + 5351 + ] + }, + { + "teal": 5415, + "source": 1372, + "pc": [ + 5352, + 5353 + ] + }, + { + "teal": 5416, + "source": 1372, + "pc": [ + 5354 + ] + }, + { + "teal": 5417, + "source": 1372, + "pc": [ + 5355 + ] + }, + { + "teal": 5418, + "source": 1372, + "pc": [ + 5356 + ] + }, + { + "teal": 5419, + "source": 1372, + "pc": [ + 5357 + ] + }, + { + "teal": 5420, + "source": 1372, + "pc": [ + 5358 + ] + }, + { + "teal": 5421, + "source": 1372, + "pc": [ + 5359 + ] + }, + { + "teal": 5424, + "source": 1372, + "pc": [ + 5360, + 5361 + ] + }, + { + "teal": 5425, + "source": 1372, + "pc": [ + 5362 + ] + }, + { + "teal": 5429, + "source": 1375, + "pc": [ + 5363, + 5364, + 5365 + ] + }, + { + "teal": 5433, + "source": 1377, + "pc": [ + 5366, + 5367, + 5368, + 5369, + 5370, + 5371, + 5372, + 5373, + 5374 + ] + }, + { + "teal": 5434, + "source": 1377, + "pc": [ + 5375 + ] + }, + { + "teal": 5438, + "source": 1380, + "pc": [ + 5376, + 5377, + 5378 + ] + }, + { + "teal": 5441, + "source": 1380, + "pc": [ + 5379 + ] + }, + { + "teal": 5445, + "source": 1389, + "pc": [ + 5380, + 5381 + ] + }, + { + "teal": 5446, + "source": 1389, + "pc": [ + 5382, + 5383 + ] + }, + { + "teal": 5450, + "source": 1390, + "pc": [ + 5384, + 5385 + ] + }, + { + "teal": 5451, + "source": 1390, + "pc": [ + 5386, + 5387 + ] + }, + { + "teal": 5452, + "source": 1390, + "pc": [ + 5388, + 5389 + ] + }, + { + "teal": 5453, + "source": 1390, + "pc": [ + 5390 + ] + }, + { + "teal": 5454, + "source": 1390, + "pc": [ + 5391 + ] + }, + { + "teal": 5455, + "source": 1390, + "pc": [ + 5392, + 5393 + ] + }, + { + "teal": 5459, + "source": 1391, + "pc": [ + 5394, + 5395 + ] + }, + { + "teal": 5460, + "source": 1391, + "pc": [ + 5396, + 5397 + ] + }, + { + "teal": 5461, + "source": 1391, + "pc": [ + 5398, + 5399 + ] + }, + { + "teal": 5462, + "source": 1391, + "pc": [ + 5400 + ] + }, + { + "teal": 5463, + "source": 1391, + "pc": [ + 5401 + ] + }, + { + "teal": 5464, + "source": 1391, + "pc": [ + 5402, + 5403 + ] + }, + { + "teal": 5468, + "source": 1392, + "pc": [ + 5404, + 5405 + ] + }, + { + "teal": 5469, + "source": 1392, + "pc": [ + 5406, + 5407 + ] + }, + { + "teal": 5470, + "source": 1392, + "pc": [ + 5408, + 5409 + ] + }, + { + "teal": 5471, + "source": 1392, + "pc": [ + 5410 + ] + }, + { + "teal": 5472, + "source": 1392, + "pc": [ + 5411 + ] + }, + { + "teal": 5473, + "source": 1392, + "pc": [ + 5412, + 5413 + ] + }, + { + "teal": 5477, + "source": 1393, + "pc": [ + 5414, + 5415 + ] + }, + { + "teal": 5478, + "source": 1393, + "pc": [ + 5416, + 5417 + ] + }, + { + "teal": 5479, + "source": 1393, + "pc": [ + 5418, + 5419 + ] + }, + { + "teal": 5480, + "source": 1393, + "pc": [ + 5420 + ] + }, + { + "teal": 5481, + "source": 1393, + "pc": [ + 5421 + ] + }, + { + "teal": 5482, + "source": 1393, + "pc": [ + 5422, + 5423 + ] + }, + { + "teal": 5486, + "source": 1394, + "pc": [ + 5424, + 5425 + ] + }, + { + "teal": 5487, + "source": 1394, + "pc": [ + 5426, + 5427 + ] + }, + { + "teal": 5488, + "source": 1394, + "pc": [ + 5428, + 5429 + ] + }, + { + "teal": 5489, + "source": 1394, + "pc": [ + 5430 + ] + }, + { + "teal": 5490, + "source": 1394, + "pc": [ + 5431 + ] + }, + { + "teal": 5491, + "source": 1394, + "pc": [ + 5432, + 5433 + ] + }, + { + "teal": 5495, + "source": 1395, + "pc": [ + 5434, + 5435 + ] + }, + { + "teal": 5496, + "source": 1395, + "pc": [ + 5436, + 5437 + ] + }, + { + "teal": 5497, + "source": 1395, + "pc": [ + 5438, + 5439 + ] + }, + { + "teal": 5498, + "source": 1395, + "pc": [ + 5440 + ] + }, + { + "teal": 5499, + "source": 1395, + "pc": [ + 5441 + ] + }, + { + "teal": 5500, + "source": 1395, + "pc": [ + 5442, + 5443 + ] + }, + { + "teal": 5504, + "source": 1396, + "pc": [ + 5444, + 5445 + ] + }, + { + "teal": 5505, + "source": 1396, + "pc": [ + 5446, + 5447 + ] + }, + { + "teal": 5506, + "source": 1396, + "pc": [ + 5448, + 5449 + ] + }, + { + "teal": 5507, + "source": 1396, + "pc": [ + 5450 + ] + }, + { + "teal": 5508, + "source": 1396, + "pc": [ + 5451 + ] + }, + { + "teal": 5509, + "source": 1396, + "pc": [ + 5452, + 5453 + ] + }, + { + "teal": 5513, + "source": 1397, + "pc": [ + 5454, + 5455 + ] + }, + { + "teal": 5516, + "source": 1397, + "pc": [ + 5456, + 5457 + ] + }, + { + "teal": 5517, + "source": 1397, + "pc": [ + 5458 + ] + }, + { + "teal": 5521, + "source": 1400, + "pc": [ + 5459, + 5460, + 5461 + ] + }, + { + "teal": 5525, + "source": 1404, + "pc": [ + 5462, + 5463, + 5464 + ] + }, + { + "teal": 5526, + "source": 1404, + "pc": [ + 5465, + 5466 + ] + }, + { + "teal": 5527, + "source": 1404, + "pc": [ + 5467, + 5468, + 5469 + ] + }, + { + "teal": 5528, + "source": 1404, + "pc": [ + 5470 + ] + }, + { + "teal": 5529, + "source": 1404, + "pc": [ + 5471 + ] + }, + { + "teal": 5530, + "source": 1404, + "pc": [ + 5472 + ] + }, + { + "teal": 5533, + "source": 163, + "pc": [ + 5473, + 5474, + 5475, + 5476, + 5477, + 5478 + ] + }, + { + "teal": 5534, + "source": 163, + "pc": [ + 5479, + 5480, + 5481 + ] + }, + { + "teal": 5535, + "source": 163, + "pc": [ + 5482, + 5483, + 5484, + 5485 + ] + }, + { + "teal": 5536, + "source": 163, + "pc": [ + 5486 + ] + }, + { + "teal": 5539, + "source": 163, + "pc": [ + 5487, + 5488, + 5489, + 5490, + 5491, + 5492 + ] + }, + { + "teal": 5540, + "source": 163, + "pc": [ + 5493, + 5494, + 5495, + 5496, + 5497, + 5498 + ] + }, + { + "teal": 5541, + "source": 163, + "pc": [ + 5499, + 5500, + 5501, + 5502, + 5503, + 5504 + ] + }, + { + "teal": 5542, + "source": 163, + "pc": [ + 5505, + 5506, + 5507, + 5508, + 5509, + 5510 + ] + }, + { + "teal": 5543, + "source": 163, + "pc": [ + 5511, + 5512, + 5513, + 5514, + 5515, + 5516 + ] + }, + { + "teal": 5544, + "source": 163, + "pc": [ + 5517, + 5518, + 5519, + 5520, + 5521, + 5522 + ] + }, + { + "teal": 5545, + "source": 163, + "pc": [ + 5523, + 5524, + 5525, + 5526, + 5527, + 5528 + ] + }, + { + "teal": 5546, + "source": 163, + "pc": [ + 5529, + 5530, + 5531, + 5532, + 5533, + 5534 + ] + }, + { + "teal": 5547, + "source": 163, + "pc": [ + 5535, + 5536, + 5537, + 5538, + 5539, + 5540 + ] + }, + { + "teal": 5548, + "source": 163, + "pc": [ + 5541, + 5542, + 5543, + 5544, + 5545, + 5546 + ] + }, + { + "teal": 5549, + "source": 163, + "pc": [ + 5547, + 5548, + 5549, + 5550, + 5551, + 5552 + ] + }, + { + "teal": 5550, + "source": 163, + "pc": [ + 5553, + 5554, + 5555, + 5556, + 5557, + 5558 + ] + }, + { + "teal": 5551, + "source": 163, + "pc": [ + 5559, + 5560, + 5561, + 5562, + 5563, + 5564 + ] + }, + { + "teal": 5552, + "source": 163, + "pc": [ + 5565, + 5566, + 5567, + 5568, + 5569, + 5570 + ] + }, + { + "teal": 5553, + "source": 163, + "pc": [ + 5571, + 5572, + 5573, + 5574, + 5575, + 5576 + ] + }, + { + "teal": 5554, + "source": 163, + "pc": [ + 5577, + 5578, + 5579, + 5580, + 5581, + 5582 + ] + }, + { + "teal": 5555, + "source": 163, + "pc": [ + 5583, + 5584, + 5585, + 5586, + 5587, + 5588 + ] + }, + { + "teal": 5556, + "source": 163, + "pc": [ + 5589, + 5590, + 5591, + 5592, + 5593, + 5594 + ] + }, + { + "teal": 5557, + "source": 163, + "pc": [ + 5595, + 5596, + 5597, + 5598, + 5599, + 5600 + ] + }, + { + "teal": 5558, + "source": 163, + "pc": [ + 5601, + 5602, + 5603, + 5604, + 5605, + 5606 + ] + }, + { + "teal": 5559, + "source": 163, + "pc": [ + 5607, + 5608, + 5609, + 5610, + 5611, + 5612 + ] + }, + { + "teal": 5560, + "source": 163, + "pc": [ + 5613, + 5614, + 5615, + 5616, + 5617, + 5618 + ] + }, + { + "teal": 5561, + "source": 163, + "pc": [ + 5619, + 5620, + 5621, + 5622, + 5623, + 5624 + ] + }, + { + "teal": 5562, + "source": 163, + "pc": [ + 5625, + 5626, + 5627, + 5628, + 5629, + 5630 + ] + }, + { + "teal": 5563, + "source": 163, + "pc": [ + 5631, + 5632, + 5633, + 5634, + 5635, + 5636 + ] + }, + { + "teal": 5564, + "source": 163, + "pc": [ + 5637, + 5638, + 5639, + 5640, + 5641, + 5642 + ] + }, + { + "teal": 5565, + "source": 163, + "pc": [ + 5643, + 5644, + 5645, + 5646, + 5647, + 5648 + ] + }, + { + "teal": 5566, + "source": 163, + "pc": [ + 5649, + 5650, + 5651, + 5652, + 5653, + 5654 + ] + }, + { + "teal": 5567, + "source": 163, + "pc": [ + 5655, + 5656, + 5657, + 5658, + 5659, + 5660 + ] + }, + { + "teal": 5568, + "source": 163, + "pc": [ + 5661, + 5662, + 5663 + ] + }, + { + "teal": 5569, + "source": 163, + "pc": [ + 5664, + 5665, + 5666, + 5667, + 5668, + 5669, + 5670, + 5671, + 5672, + 5673, + 5674, + 5675, + 5676, + 5677, + 5678, + 5679, + 5680, + 5681, + 5682, + 5683, + 5684, + 5685, + 5686, + 5687, + 5688, + 5689, + 5690, + 5691, + 5692, + 5693, + 5694, + 5695, + 5696, + 5697, + 5698, + 5699, + 5700, + 5701, + 5702, + 5703, + 5704, + 5705, + 5706, + 5707, + 5708, + 5709, + 5710, + 5711, + 5712, + 5713, + 5714, + 5715, + 5716, + 5717, + 5718, + 5719, + 5720, + 5721, + 5722, + 5723 + ] + }, + { + "teal": 5570, + "source": 163, + "pc": [ + 5724 + ] + } +] \ No newline at end of file diff --git a/contracts/contracts/clients/.gitkeep b/contracts/contracts/clients/.gitkeep new file mode 100644 index 00000000..e69de29b diff --git a/contracts/contracts/clients/StakingPoolClient.ts b/contracts/contracts/clients/StakingPoolClient.ts new file mode 100644 index 00000000..175c0dc0 --- /dev/null +++ b/contracts/contracts/clients/StakingPoolClient.ts @@ -0,0 +1,1577 @@ +/* eslint-disable */ +/** + * This file was automatically generated by @algorandfoundation/algokit-client-generator. + * DO NOT MODIFY IT BY HAND. + * requires: @algorandfoundation/algokit-utils: ^2 + */ +import * as algokit from '@algorandfoundation/algokit-utils' +import type { + ABIAppCallArg, + AppCallTransactionResult, + AppCallTransactionResultOfType, + AppCompilationResult, + AppReference, + AppState, + AppStorageSchema, + CoreAppCallArgs, + RawAppCallArgs, + TealTemplateParams, +} from '@algorandfoundation/algokit-utils/types/app' +import type { + AppClientCallCoreParams, + AppClientCompilationParams, + AppClientDeployCoreParams, + AppDetails, + ApplicationClient, +} from '@algorandfoundation/algokit-utils/types/app-client' +import type { AppSpec } from '@algorandfoundation/algokit-utils/types/app-spec' +import type { SendTransactionResult, TransactionToSign, SendTransactionFrom, SendTransactionParams } from '@algorandfoundation/algokit-utils/types/transaction' +import type { ABIResult, TransactionWithSigner } from 'algosdk' +import { Algodv2, OnApplicationComplete, Transaction, AtomicTransactionComposer, modelsv2 } from 'algosdk' +export const APP_SPEC: AppSpec = { + "hints": { + "createApplication(uint64,uint64,uint64,uint64)void": { + "call_config": { + "no_op": "CREATE" + } + }, + "gas()void": { + "call_config": { + "no_op": "CALL" + } + }, + "initStorage(pay)void": { + "call_config": { + "no_op": "CALL" + } + }, + "addStake(pay,address)uint64": { + "call_config": { + "no_op": "CALL" + } + }, + "removeStake(uint64)void": { + "call_config": { + "no_op": "CALL" + } + }, + "claimTokens()void": { + "call_config": { + "no_op": "CALL" + } + }, + "getStakerInfo(address)(address,uint64,uint64,uint64,uint64)": { + "call_config": { + "no_op": "CALL" + } + }, + "payTokenReward(address,uint64,uint64)void": { + "call_config": { + "no_op": "CALL" + } + }, + "updateAlgodVer(string)void": { + "call_config": { + "no_op": "CALL" + } + }, + "epochBalanceUpdate()void": { + "call_config": { + "no_op": "CALL" + } + }, + "goOnline(byte[],byte[],byte[],uint64,uint64,uint64)void": { + "call_config": { + "no_op": "CALL" + } + }, + "goOffline()void": { + "call_config": { + "no_op": "CALL" + } + }, + "linkToNFD(uint64,string)void": { + "call_config": { + "no_op": "CALL" + } + }, + "proxiedSetTokenPayoutRatio((uint64,uint64,uint64))(uint64[24],uint64)": { + "call_config": { + "no_op": "CALL" + } + } + }, + "bare_call_config": { + "no_op": "NEVER", + "opt_in": "NEVER", + "close_out": "NEVER", + "update_application": "NEVER", + "delete_application": "NEVER" + }, + "schema": { + "local": { + "declared": {}, + "reserved": {} + }, + "global": { + "declared": { + "creatingValidatorContractAppId": { + "type": "uint64", + "key": "creatorApp" + }, + "validatorId": { + "type": "uint64", + "key": "validatorId" + }, + "poolId": { + "type": "uint64", + "key": "poolId" + }, + "numStakers": { + "type": "uint64", + "key": "numStakers" + }, + "totalAlgoStaked": { + "type": "uint64", + "key": "staked" + }, + "minEntryStake": { + "type": "uint64", + "key": "minEntryStake" + }, + "lastPayout": { + "type": "uint64", + "key": "lastPayout" + }, + "epochNumber": { + "type": "uint64", + "key": "epochNumber" + }, + "algodVer": { + "type": "bytes", + "key": "algodVer" + } + }, + "reserved": {} + } + }, + "state": { + "global": { + "num_byte_slices": 1, + "num_uints": 8 + }, + "local": { + "num_byte_slices": 0, + "num_uints": 0 + } + }, + "source": { + "approval": "I3ByYWdtYSB2ZXJzaW9uIDEwCgovLyBUaGlzIFRFQUwgd2FzIGdlbmVyYXRlZCBieSBURUFMU2NyaXB0IHYwLjg4LjEKLy8gaHR0cHM6Ly9naXRodWIuY29tL2FsZ29yYW5kZm91bmRhdGlvbi9URUFMU2NyaXB0CgovLyBUaGlzIGNvbnRyYWN0IGlzIGNvbXBsaWFudCB3aXRoIGFuZC9vciBpbXBsZW1lbnRzIHRoZSBmb2xsb3dpbmcgQVJDczogWyBBUkM0IF0KCi8vIFRoZSBmb2xsb3dpbmcgdGVuIGxpbmVzIG9mIFRFQUwgaGFuZGxlIGluaXRpYWwgcHJvZ3JhbSBmbG93Ci8vIFRoaXMgcGF0dGVybiBpcyB1c2VkIHRvIG1ha2UgaXQgZWFzeSBmb3IgYW55b25lIHRvIHBhcnNlIHRoZSBzdGFydCBvZiB0aGUgcHJvZ3JhbSBhbmQgZGV0ZXJtaW5lIGlmIGEgc3BlY2lmaWMgYWN0aW9uIGlzIGFsbG93ZWQKLy8gSGVyZSwgYWN0aW9uIHJlZmVycyB0byB0aGUgT25Db21wbGV0ZSBpbiBjb21iaW5hdGlvbiB3aXRoIHdoZXRoZXIgdGhlIGFwcCBpcyBiZWluZyBjcmVhdGVkIG9yIGNhbGxlZAovLyBFdmVyeSBwb3NzaWJsZSBhY3Rpb24gZm9yIHRoaXMgY29udHJhY3QgaXMgcmVwcmVzZW50ZWQgaW4gdGhlIHN3aXRjaCBzdGF0ZW1lbnQKLy8gSWYgdGhlIGFjdGlvbiBpcyBub3QgaW1wbGVtZW50ZWQgaW4gdGhlIGNvbnRyYWN0LCBpdHMgcmVzcGVjdGl2ZSBicmFuY2ggd2lsbCBiZSAiKk5PVF9JTVBMRU1FTlRFRCIgd2hpY2gganVzdCBjb250YWlucyAiZXJyIgp0eG4gQXBwbGljYXRpb25JRAohCmludCA2CioKdHhuIE9uQ29tcGxldGlvbgorCnN3aXRjaCAqY2FsbF9Ob09wICpOT1RfSU1QTEVNRU5URUQgKk5PVF9JTVBMRU1FTlRFRCAqTk9UX0lNUExFTUVOVEVEICpOT1RfSU1QTEVNRU5URUQgKk5PVF9JTVBMRU1FTlRFRCAqY3JlYXRlX05vT3AgKk5PVF9JTVBMRU1FTlRFRCAqTk9UX0lNUExFTUVOVEVEICpOT1RfSU1QTEVNRU5URUQgKk5PVF9JTVBMRU1FTlRFRCAqTk9UX0lNUExFTUVOVEVECgoqTk9UX0lNUExFTUVOVEVEOgoJZXJyCgovLyBjcmVhdGVBcHBsaWNhdGlvbih1aW50NjQsdWludDY0LHVpbnQ2NCx1aW50NjQpdm9pZAoqYWJpX3JvdXRlX2NyZWF0ZUFwcGxpY2F0aW9uOgoJLy8gbWluRW50cnlTdGFrZTogdWludDY0Cgl0eG5hIEFwcGxpY2F0aW9uQXJncyA0CglidG9pCgoJLy8gcG9vbElkOiB1aW50NjQKCXR4bmEgQXBwbGljYXRpb25BcmdzIDMKCWJ0b2kKCgkvLyB2YWxpZGF0b3JJZDogdWludDY0Cgl0eG5hIEFwcGxpY2F0aW9uQXJncyAyCglidG9pCgoJLy8gY3JlYXRpbmdDb250cmFjdElkOiB1aW50NjQKCXR4bmEgQXBwbGljYXRpb25BcmdzIDEKCWJ0b2kKCgkvLyBleGVjdXRlIGNyZWF0ZUFwcGxpY2F0aW9uKHVpbnQ2NCx1aW50NjQsdWludDY0LHVpbnQ2NCl2b2lkCgljYWxsc3ViIGNyZWF0ZUFwcGxpY2F0aW9uCglpbnQgMQoJcmV0dXJuCgovLyBjcmVhdGVBcHBsaWNhdGlvbihjcmVhdGluZ0NvbnRyYWN0SWQ6IHVpbnQ2NCwgdmFsaWRhdG9ySWQ6IHVpbnQ2NCwgcG9vbElkOiB1aW50NjQsIG1pbkVudHJ5U3Rha2U6IHVpbnQ2NCk6IHZvaWQKLy8KLy8gSW5pdGlhbGl6ZSB0aGUgc3Rha2luZyBwb29sIHcvIG93bmVyIGFuZCBtYW5hZ2VyLCBidXQgY2FuIG9ubHkgYmUgY3JlYXRlZCBieSB0aGUgdmFsaWRhdG9yIGNvbnRyYWN0LgovLyBAcGFyYW0ge3VpbnQ2NH0gY3JlYXRpbmdDb250cmFjdElkIC0gaWQgb2YgY29udHJhY3QgdGhhdCBjb25zdHJ1Y3RlZCB1cyAtIHRoZSB2YWxpZGF0b3IgYXBwbGljYXRpb24gKHNpbmdsZSBnbG9iYWwgaW5zdGFuY2UpCi8vIEBwYXJhbSB7dWludDY0fSB2YWxpZGF0b3JJZCAtIGlkIG9mIHZhbGlkYXRvciB3ZSdyZSBhIHN0YWtpbmcgcG9vbCBvZgovLyBAcGFyYW0ge3VpbnQ2NH0gcG9vbElkIC0gd2hpY2ggcG9vbCBpZCBhcmUgd2UKLy8gQHBhcmFtIHt1aW50NjR9IG1pbkVudHJ5U3Rha2UgLSBtaW5pbXVtIGFtb3VudCB0byBiZSBpbiBwb29sLCBidXQgYWxzbyBtaW5pbXVtIGFtb3VudCBiYWxhbmNlIGNhbid0IGdvIGJlbG93ICh3aXRob3V0IHJlbW92aW5nIGFsbCEpCmNyZWF0ZUFwcGxpY2F0aW9uOgoJcHJvdG8gNCAwCgoJLy8gKmlmMF9jb25kaXRpb24KCS8vIGNvbnRyYWN0cy9zdGFraW5nUG9vbC5hbGdvLnRzOjg2CgkvLyBjcmVhdGluZ0NvbnRyYWN0SWQgPT09IDAKCWZyYW1lX2RpZyAtMSAvLyBjcmVhdGluZ0NvbnRyYWN0SWQ6IHVpbnQ2NAoJaW50IDAKCT09CglieiAqaWYwX2Vsc2UKCgkvLyAqaWYwX2NvbnNlcXVlbnQKCS8vIGNvbnRyYWN0cy9zdGFraW5nUG9vbC5hbGdvLnRzOjg4CgkvLyBhc3NlcnQodmFsaWRhdG9ySWQgPT09IDApCglmcmFtZV9kaWcgLTIgLy8gdmFsaWRhdG9ySWQ6IHVpbnQ2NAoJaW50IDAKCT09Cglhc3NlcnQKCgkvLyBjb250cmFjdHMvc3Rha2luZ1Bvb2wuYWxnby50czo4OQoJLy8gYXNzZXJ0KHBvb2xJZCA9PT0gMCkKCWZyYW1lX2RpZyAtMyAvLyBwb29sSWQ6IHVpbnQ2NAoJaW50IDAKCT09Cglhc3NlcnQKCWIgKmlmMF9lbmQKCippZjBfZWxzZToKCS8vIGNvbnRyYWN0cy9zdGFraW5nUG9vbC5hbGdvLnRzOjkxCgkvLyBhc3NlcnQodmFsaWRhdG9ySWQgIT09IDApCglmcmFtZV9kaWcgLTIgLy8gdmFsaWRhdG9ySWQ6IHVpbnQ2NAoJaW50IDAKCSE9Cglhc3NlcnQKCgkvLyBjb250cmFjdHMvc3Rha2luZ1Bvb2wuYWxnby50czo5MgoJLy8gYXNzZXJ0KHBvb2xJZCAhPT0gMCkKCWZyYW1lX2RpZyAtMyAvLyBwb29sSWQ6IHVpbnQ2NAoJaW50IDAKCSE9Cglhc3NlcnQKCippZjBfZW5kOgoJLy8gY29udHJhY3RzL3N0YWtpbmdQb29sLmFsZ28udHM6OTQKCS8vIGFzc2VydChtaW5FbnRyeVN0YWtlID49IE1JTl9BTEdPX1NUQUtFX1BFUl9QT09MKQoJZnJhbWVfZGlnIC00IC8vIG1pbkVudHJ5U3Rha2U6IHVpbnQ2NAoJaW50IDEwMDAwMDAKCT49Cglhc3NlcnQKCgkvLyBjb250cmFjdHMvc3Rha2luZ1Bvb2wuYWxnby50czo5NQoJLy8gdGhpcy5jcmVhdGluZ1ZhbGlkYXRvckNvbnRyYWN0QXBwSWQudmFsdWUgPSBjcmVhdGluZ0NvbnRyYWN0SWQKCWJ5dGUgMHg2MzcyNjU2MTc0NmY3MjQxNzA3MCAvLyAiY3JlYXRvckFwcCIKCWZyYW1lX2RpZyAtMSAvLyBjcmVhdGluZ0NvbnRyYWN0SWQ6IHVpbnQ2NAoJYXBwX2dsb2JhbF9wdXQKCgkvLyBjb250cmFjdHMvc3Rha2luZ1Bvb2wuYWxnby50czo5NgoJLy8gdGhpcy52YWxpZGF0b3JJZC52YWx1ZSA9IHZhbGlkYXRvcklkCglieXRlIDB4NzY2MTZjNjk2NDYxNzQ2ZjcyNDk2NCAvLyAidmFsaWRhdG9ySWQiCglmcmFtZV9kaWcgLTIgLy8gdmFsaWRhdG9ySWQ6IHVpbnQ2NAoJYXBwX2dsb2JhbF9wdXQKCgkvLyBjb250cmFjdHMvc3Rha2luZ1Bvb2wuYWxnby50czo5NwoJLy8gdGhpcy5wb29sSWQudmFsdWUgPSBwb29sSWQKCWJ5dGUgMHg3MDZmNmY2YzQ5NjQgLy8gInBvb2xJZCIKCWZyYW1lX2RpZyAtMyAvLyBwb29sSWQ6IHVpbnQ2NAoJYXBwX2dsb2JhbF9wdXQKCgkvLyBjb250cmFjdHMvc3Rha2luZ1Bvb2wuYWxnby50czo5OAoJLy8gdGhpcy5udW1TdGFrZXJzLnZhbHVlID0gMAoJYnl0ZSAweDZlNzU2ZDUzNzQ2MTZiNjU3MjczIC8vICJudW1TdGFrZXJzIgoJaW50IDAKCWFwcF9nbG9iYWxfcHV0CgoJLy8gY29udHJhY3RzL3N0YWtpbmdQb29sLmFsZ28udHM6OTkKCS8vIHRoaXMudG90YWxBbGdvU3Rha2VkLnZhbHVlID0gMAoJYnl0ZSAweDczNzQ2MTZiNjU2NCAvLyAic3Rha2VkIgoJaW50IDAKCWFwcF9nbG9iYWxfcHV0CgoJLy8gY29udHJhY3RzL3N0YWtpbmdQb29sLmFsZ28udHM6MTAwCgkvLyB0aGlzLm1pbkVudHJ5U3Rha2UudmFsdWUgPSBtaW5FbnRyeVN0YWtlCglieXRlIDB4NmQ2OTZlNDU2ZTc0NzI3OTUzNzQ2MTZiNjUgLy8gIm1pbkVudHJ5U3Rha2UiCglmcmFtZV9kaWcgLTQgLy8gbWluRW50cnlTdGFrZTogdWludDY0CglhcHBfZ2xvYmFsX3B1dAoKCS8vIGNvbnRyYWN0cy9zdGFraW5nUG9vbC5hbGdvLnRzOjEwMQoJLy8gdGhpcy5sYXN0UGF5b3V0LnZhbHVlID0gZ2xvYmFscy5sYXRlc3RUaW1lc3RhbXAKCWJ5dGUgMHg2YzYxNzM3NDUwNjE3OTZmNzU3NCAvLyAibGFzdFBheW91dCIKCWdsb2JhbCBMYXRlc3RUaW1lc3RhbXAKCWFwcF9nbG9iYWxfcHV0CgoJLy8gY29udHJhY3RzL3N0YWtpbmdQb29sLmFsZ28udHM6MTAyCgkvLyB0aGlzLmVwb2NoTnVtYmVyLnZhbHVlID0gMAoJYnl0ZSAweDY1NzA2ZjYzNjg0ZTc1NmQ2MjY1NzIgLy8gImVwb2NoTnVtYmVyIgoJaW50IDAKCWFwcF9nbG9iYWxfcHV0CglyZXRzdWIKCi8vIGdhcygpdm9pZAoqYWJpX3JvdXRlX2dhczoKCS8vIGV4ZWN1dGUgZ2FzKCl2b2lkCgljYWxsc3ViIGdhcwoJaW50IDEKCXJldHVybgoKLy8gZ2FzKCk6IHZvaWQKLy8KLy8gZ2FzIGlzIGEgZHVtbXkgbm8tb3AgY2FsbCB0aGF0IGNhbiBiZSB1c2VkIHRvIHBvb2wtdXAgcmVzb3VyY2UgcmVmZXJlbmNlcyBhbmQgb3Bjb2RlIGNvc3QKZ2FzOgoJcHJvdG8gMCAwCglyZXRzdWIKCi8vIG1pbkJhbGFuY2VGb3JBY2NvdW50KGNvbnRyYWN0czogdWludDY0LCBleHRyYVBhZ2VzOiB1aW50NjQsIGFzc2V0czogdWludDY0LCBsb2NhbEludHM6IHVpbnQ2NCwgbG9jYWxCeXRlczogdWludDY0LCBnbG9iYWxJbnRzOiB1aW50NjQsIGdsb2JhbEJ5dGVzOiB1aW50NjQpOiB1aW50NjQKbWluQmFsYW5jZUZvckFjY291bnQ6Cglwcm90byA3IDEKCgkvLyBQdXNoIGVtcHR5IGJ5dGVzIGFmdGVyIHRoZSBmcmFtZSBwb2ludGVyIHRvIHJlc2VydmUgc3BhY2UgZm9yIGxvY2FsIHZhcmlhYmxlcwoJYnl0ZSAweAoKCS8vIGNvbnRyYWN0cy9zdGFraW5nUG9vbC5hbGdvLnRzOjExOQoJLy8gbWluQmFsID0gQUxHT1JBTkRfQUNDT1VOVF9NSU5fQkFMQU5DRQoJaW50IDEwMDAwMAoJZnJhbWVfYnVyeSAwIC8vIG1pbkJhbDogdWludDY0CgoJLy8gY29udHJhY3RzL3N0YWtpbmdQb29sLmFsZ28udHM6MTIwCgkvLyBtaW5CYWwgKz0gY29udHJhY3RzICogQVBQTElDQVRJT05fQkFTRV9GRUUKCWZyYW1lX2RpZyAwIC8vIG1pbkJhbDogdWludDY0CglmcmFtZV9kaWcgLTEgLy8gY29udHJhY3RzOiB1aW50NjQKCWludCAxMDAwMDAKCSoKCSsKCWZyYW1lX2J1cnkgMCAvLyBtaW5CYWw6IHVpbnQ2NAoKCS8vIGNvbnRyYWN0cy9zdGFraW5nUG9vbC5hbGdvLnRzOjEyMQoJLy8gbWluQmFsICs9IGV4dHJhUGFnZXMgKiBBUFBMSUNBVElPTl9CQVNFX0ZFRQoJZnJhbWVfZGlnIDAgLy8gbWluQmFsOiB1aW50NjQKCWZyYW1lX2RpZyAtMiAvLyBleHRyYVBhZ2VzOiB1aW50NjQKCWludCAxMDAwMDAKCSoKCSsKCWZyYW1lX2J1cnkgMCAvLyBtaW5CYWw6IHVpbnQ2NAoKCS8vIGNvbnRyYWN0cy9zdGFraW5nUG9vbC5hbGdvLnRzOjEyMgoJLy8gbWluQmFsICs9IGFzc2V0cyAqIEFTU0VUX0hPTERJTkdfRkVFCglmcmFtZV9kaWcgMCAvLyBtaW5CYWw6IHVpbnQ2NAoJZnJhbWVfZGlnIC0zIC8vIGFzc2V0czogdWludDY0CglpbnQgMTAwMDAwCgkqCgkrCglmcmFtZV9idXJ5IDAgLy8gbWluQmFsOiB1aW50NjQKCgkvLyBjb250cmFjdHMvc3Rha2luZ1Bvb2wuYWxnby50czoxMjMKCS8vIG1pbkJhbCArPSBsb2NhbEludHMgKiBTU0NfVkFMVUVfVUlOVAoJZnJhbWVfZGlnIDAgLy8gbWluQmFsOiB1aW50NjQKCWZyYW1lX2RpZyAtNCAvLyBsb2NhbEludHM6IHVpbnQ2NAoJaW50IDI4NTAwCgkqCgkrCglmcmFtZV9idXJ5IDAgLy8gbWluQmFsOiB1aW50NjQKCgkvLyBjb250cmFjdHMvc3Rha2luZ1Bvb2wuYWxnby50czoxMjQKCS8vIG1pbkJhbCArPSBnbG9iYWxJbnRzICogU1NDX1ZBTFVFX1VJTlQKCWZyYW1lX2RpZyAwIC8vIG1pbkJhbDogdWludDY0CglmcmFtZV9kaWcgLTYgLy8gZ2xvYmFsSW50czogdWludDY0CglpbnQgMjg1MDAKCSoKCSsKCWZyYW1lX2J1cnkgMCAvLyBtaW5CYWw6IHVpbnQ2NAoKCS8vIGNvbnRyYWN0cy9zdGFraW5nUG9vbC5hbGdvLnRzOjEyNQoJLy8gbWluQmFsICs9IGxvY2FsQnl0ZXMgKiBTU0NfVkFMVUVfQllURVMKCWZyYW1lX2RpZyAwIC8vIG1pbkJhbDogdWludDY0CglmcmFtZV9kaWcgLTUgLy8gbG9jYWxCeXRlczogdWludDY0CglpbnQgNTAwMDAKCSoKCSsKCWZyYW1lX2J1cnkgMCAvLyBtaW5CYWw6IHVpbnQ2NAoKCS8vIGNvbnRyYWN0cy9zdGFraW5nUG9vbC5hbGdvLnRzOjEyNgoJLy8gbWluQmFsICs9IGdsb2JhbEJ5dGVzICogU1NDX1ZBTFVFX0JZVEVTCglmcmFtZV9kaWcgMCAvLyBtaW5CYWw6IHVpbnQ2NAoJZnJhbWVfZGlnIC03IC8vIGdsb2JhbEJ5dGVzOiB1aW50NjQKCWludCA1MDAwMAoJKgoJKwoJZnJhbWVfYnVyeSAwIC8vIG1pbkJhbDogdWludDY0CgoJLy8gY29udHJhY3RzL3N0YWtpbmdQb29sLmFsZ28udHM6MTI3CgkvLyByZXR1cm4gbWluQmFsOwoJZnJhbWVfZGlnIDAgLy8gbWluQmFsOiB1aW50NjQKCgkvLyBzZXQgdGhlIHN1YnJvdXRpbmUgcmV0dXJuIHZhbHVlCglmcmFtZV9idXJ5IDAKCXJldHN1YgoKLy8gY29zdEZvckJveFN0b3JhZ2UodG90YWxOdW1CeXRlczogdWludDY0KTogdWludDY0CmNvc3RGb3JCb3hTdG9yYWdlOgoJcHJvdG8gMSAxCgoJLy8gY29udHJhY3RzL3N0YWtpbmdQb29sLmFsZ28udHM6MTM0CgkvLyByZXR1cm4gU0NCT1hfUEVSQk9YICsgdG90YWxOdW1CeXRlcyAqIFNDQk9YX1BFUkJZVEU7CglpbnQgMjUwMAoJZnJhbWVfZGlnIC0xIC8vIHRvdGFsTnVtQnl0ZXM6IHVpbnQ2NAoJaW50IDQwMAoJKgoJKwoJcmV0c3ViCgovLyBpbml0U3RvcmFnZShwYXkpdm9pZAoqYWJpX3JvdXRlX2luaXRTdG9yYWdlOgoJLy8gbWJyUGF5bWVudDogcGF5Cgl0eG4gR3JvdXBJbmRleAoJaW50IDEKCS0KCWR1cAoJZ3R4bnMgVHlwZUVudW0KCWludCBwYXkKCT09Cglhc3NlcnQKCgkvLyBleGVjdXRlIGluaXRTdG9yYWdlKHBheSl2b2lkCgljYWxsc3ViIGluaXRTdG9yYWdlCglpbnQgMQoJcmV0dXJuCgovLyBpbml0U3RvcmFnZShtYnJQYXltZW50OiBQYXlUeG4pOiB2b2lkCi8vCi8vIENhbGxlZCBhZnRlciB3ZSdyZSBjcmVhdGVkIGFuZCB0aGVuIGZ1bmRlZCBzbyB3ZSBjYW4gY3JlYXRlIG91ciBsYXJnZSBzdGFrZXJzIGxlZGdlciBzdG9yYWdlCi8vIENhbGxlciBoYXMgdG8gZ2V0IE1CUiBhbW91bnRzIGZyb20gVmFsaWRhdG9yUmVnaXN0cnkgdG8ga25vdyBob3cgbXVjaCB0byBmdW5kIHVzIHRvIGNvdmVyIHRoZSBib3ggc3RvcmFnZSBjb3N0Ci8vIElmIHRoaXMgaXMgcG9vbCAxIEFORCB0aGUgdmFsaWRhdG9yIGhhcyBzcGVjaWZpZWQgYSByZXdhcmQgdG9rZW4sIG9wdC1pbiB0byB0aGF0IHRva2VuCi8vIHNvIHRoYXQgdGhlIHZhbGlkYXRvciBjYW4gc2VlZCB0aGUgcG9vbCB3aXRoIGZ1dHVyZSByZXdhcmRzIG9mIHRoYXQgdG9rZW4uCi8vIEBwYXJhbSBtYnJQYXltZW50IHBheW1lbnQgZnJvbSBjYWxsZXIgd2hpY2ggY292ZXJzIG1iciBpbmNyZWFzZSBvZiBuZXcgc3Rha2luZyBwb29scycgc3RvcmFnZQppbml0U3RvcmFnZToKCXByb3RvIDEgMAoKCS8vIFB1c2ggZW1wdHkgYnl0ZXMgYWZ0ZXIgdGhlIGZyYW1lIHBvaW50ZXIgdG8gcmVzZXJ2ZSBzcGFjZSBmb3IgbG9jYWwgdmFyaWFibGVzCglieXRlIDB4CglkdXBuIDMKCgkvLyBjb250cmFjdHMvc3Rha2luZ1Bvb2wuYWxnby50czoxNDUKCS8vIGFzc2VydCghdGhpcy5zdGFrZXJzLmV4aXN0cywgJ3N0YWtpbmcgcG9vbCBhbHJlYWR5IGluaXRpYWxpemVkJykKCWJ5dGUgMHg3Mzc0NjE2YjY1NzI3MyAvLyAic3Rha2VycyIKCWJveF9sZW4KCXN3YXAKCXBvcAoJIQoKCS8vIHN0YWtpbmcgcG9vbCBhbHJlYWR5IGluaXRpYWxpemVkCglhc3NlcnQKCgkvLyBjb250cmFjdHMvc3Rha2luZ1Bvb2wuYWxnby50czoxNDgKCS8vIHZhbGlkYXRvckNvbmZpZyA9IHNlbmRNZXRob2RDYWxsPHR5cGVvZiBWYWxpZGF0b3JSZWdpc3RyeS5wcm90b3R5cGUuZ2V0VmFsaWRhdG9yQ29uZmlnPih7CgkvLyAgICAgICAgICAgICBhcHBsaWNhdGlvbklEOiBBcHBJRC5mcm9tVWludDY0KHRoaXMuY3JlYXRpbmdWYWxpZGF0b3JDb250cmFjdEFwcElkLnZhbHVlKSwKCS8vICAgICAgICAgICAgIG1ldGhvZEFyZ3M6IFt0aGlzLnZhbGlkYXRvcklkLnZhbHVlXSwKCS8vICAgICAgICAgfSkKCWl0eG5fYmVnaW4KCWludCBhcHBsCglpdHhuX2ZpZWxkIFR5cGVFbnVtCgltZXRob2QgImdldFZhbGlkYXRvckNvbmZpZyh1aW50NjQpKHVpbnQ2NCxhZGRyZXNzLGFkZHJlc3MsdWludDY0LHVpbnQ4LGJ5dGVbMzJdLHVpbnQ2NCx1aW50NjQsdWludDY0LHVpbnQxNix1aW50MzIsYWRkcmVzcyx1aW50NjQsdWludDY0LHVpbnQ4LHVpbnQ2NCx1aW50NjQpIgoJaXR4bl9maWVsZCBBcHBsaWNhdGlvbkFyZ3MKCgkvLyBjb250cmFjdHMvc3Rha2luZ1Bvb2wuYWxnby50czoxNDkKCS8vIGFwcGxpY2F0aW9uSUQ6IEFwcElELmZyb21VaW50NjQodGhpcy5jcmVhdGluZ1ZhbGlkYXRvckNvbnRyYWN0QXBwSWQudmFsdWUpCglieXRlIDB4NjM3MjY1NjE3NDZmNzI0MTcwNzAgLy8gImNyZWF0b3JBcHAiCglhcHBfZ2xvYmFsX2dldAoJaXR4bl9maWVsZCBBcHBsaWNhdGlvbklECgoJLy8gY29udHJhY3RzL3N0YWtpbmdQb29sLmFsZ28udHM6MTUwCgkvLyBtZXRob2RBcmdzOiBbdGhpcy52YWxpZGF0b3JJZC52YWx1ZV0KCWJ5dGUgMHg3NjYxNmM2OTY0NjE3NDZmNzI0OTY0IC8vICJ2YWxpZGF0b3JJZCIKCWFwcF9nbG9iYWxfZ2V0CglpdG9iCglpdHhuX2ZpZWxkIEFwcGxpY2F0aW9uQXJncwoKCS8vIEZlZSBmaWVsZCBub3Qgc2V0LCBkZWZhdWx0aW5nIHRvIDAKCWludCAwCglpdHhuX2ZpZWxkIEZlZQoKCS8vIFN1Ym1pdCBpbm5lciB0cmFuc2FjdGlvbgoJaXR4bl9zdWJtaXQKCWl0eG4gTnVtTG9ncwoJaW50IDEKCS0KCWl0eG5hcyBMb2dzCglleHRyYWN0IDQgMAoJZnJhbWVfYnVyeSAwIC8vIHZhbGlkYXRvckNvbmZpZzogKHVpbnQ2NCxhZGRyZXNzLGFkZHJlc3MsdWludDY0LHVpbnQ4LGJ5dGVbMzJdLHVpbnQ2NCx1aW50NjQsdWludDY0LHVpbnQxNix1aW50MzIsYWRkcmVzcyx1aW50NjQsdWludDY0LHVpbnQ4LHVpbnQ2NCx1aW50NjQpCgoJLy8gY29udHJhY3RzL3N0YWtpbmdQb29sLmFsZ28udHM6MTUyCgkvLyBpc1Rva2VuRWxpZ2libGUgPSB2YWxpZGF0b3JDb25maWcucmV3YXJkVG9rZW5JZCAhPT0gMAoJZnJhbWVfZGlnIDAgLy8gdmFsaWRhdG9yQ29uZmlnOiAodWludDY0LGFkZHJlc3MsYWRkcmVzcyx1aW50NjQsdWludDgsYnl0ZVszMl0sdWludDY0LHVpbnQ2NCx1aW50NjQsdWludDE2LHVpbnQzMixhZGRyZXNzLHVpbnQ2NCx1aW50NjQsdWludDgsdWludDY0LHVpbnQ2NCkKCWV4dHJhY3QgMTIxIDgKCWJ0b2kKCWludCAwCgkhPQoJZnJhbWVfYnVyeSAxIC8vIGlzVG9rZW5FbGlnaWJsZTogYm9vbAoKCS8vIGNvbnRyYWN0cy9zdGFraW5nUG9vbC5hbGdvLnRzOjE1MwoJLy8gZXh0cmFNQlIgPSBpc1Rva2VuRWxpZ2libGUgJiYgdGhpcy5wb29sSWQudmFsdWUgPT09IDEgPyBBU1NFVF9IT0xESU5HX0ZFRSA6IDAKCWZyYW1lX2RpZyAxIC8vIGlzVG9rZW5FbGlnaWJsZTogYm9vbAoJZHVwCglieiAqc2tpcF9hbmQxCglieXRlIDB4NzA2ZjZmNmM0OTY0IC8vICJwb29sSWQiCglhcHBfZ2xvYmFsX2dldAoJaW50IDEKCT09CgkmJgoKKnNraXBfYW5kMToKCWJ6ICp0ZXJuYXJ5MV9mYWxzZQoJaW50IDEwMDAwMAoJYiAqdGVybmFyeTFfZW5kCgoqdGVybmFyeTFfZmFsc2U6CglpbnQgMAoKKnRlcm5hcnkxX2VuZDoKCWZyYW1lX2J1cnkgMiAvLyBleHRyYU1CUjogdWludDY0CgoJLy8gY29udHJhY3RzL3N0YWtpbmdQb29sLmFsZ28udHM6MTU0CgkvLyBQb29sSW5pdE1iciA9CgkvLyAgICAgICAgICAgICBBTEdPUkFORF9BQ0NPVU5UX01JTl9CQUxBTkNFICsKCS8vICAgICAgICAgICAgIGV4dHJhTUJSICsKCS8vICAgICAgICAgICAgIHRoaXMuY29zdEZvckJveFN0b3JhZ2UoNyAvKiAnc3Rha2VycycgbmFtZSAqLyArIGxlbjxTdGFrZWRJbmZvPigpICogTUFYX1NUQUtFUlNfUEVSX1BPT0wpCglpbnQgMTAwMDAwCglmcmFtZV9kaWcgMiAvLyBleHRyYU1CUjogdWludDY0CgkrCglpbnQgMTI4MDcKCWNhbGxzdWIgY29zdEZvckJveFN0b3JhZ2UKCSsKCWZyYW1lX2J1cnkgMyAvLyBQb29sSW5pdE1icjogdWludDY0CgoJLy8gY29udHJhY3RzL3N0YWtpbmdQb29sLmFsZ28udHM6MTYwCgkvLyB2ZXJpZnlQYXlUeG4obWJyUGF5bWVudCwgeyBhbW91bnQ6IFBvb2xJbml0TWJyIH0pCgkvLyB2ZXJpZnkgYW1vdW50CglmcmFtZV9kaWcgLTEgLy8gbWJyUGF5bWVudDogUGF5VHhuCglndHhucyBBbW91bnQKCWZyYW1lX2RpZyAzIC8vIFBvb2xJbml0TWJyOiB1aW50NjQKCT09Cglhc3NlcnQKCgkvLyBjb250cmFjdHMvc3Rha2luZ1Bvb2wuYWxnby50czoxNjEKCS8vIHRoaXMuc3Rha2Vycy5jcmVhdGUoKQoJYnl0ZSAweDczNzQ2MTZiNjU3MjczIC8vICJzdGFrZXJzIgoJaW50IDEyODAwCglib3hfY3JlYXRlCglwb3AKCgkvLyAqaWYxX2NvbmRpdGlvbgoJLy8gY29udHJhY3RzL3N0YWtpbmdQb29sLmFsZ28udHM6MTYzCgkvLyBpc1Rva2VuRWxpZ2libGUgJiYgdGhpcy5wb29sSWQudmFsdWUgPT09IDEKCWZyYW1lX2RpZyAxIC8vIGlzVG9rZW5FbGlnaWJsZTogYm9vbAoJZHVwCglieiAqc2tpcF9hbmQyCglieXRlIDB4NzA2ZjZmNmM0OTY0IC8vICJwb29sSWQiCglhcHBfZ2xvYmFsX2dldAoJaW50IDEKCT09CgkmJgoKKnNraXBfYW5kMjoKCWJ6ICppZjFfZW5kCgoJLy8gKmlmMV9jb25zZXF1ZW50CgkvLyBjb250cmFjdHMvc3Rha2luZ1Bvb2wuYWxnby50czoxNjUKCS8vIHNlbmRBc3NldFRyYW5zZmVyKHsKCS8vICAgICAgICAgICAgICAgICB4ZmVyQXNzZXQ6IEFzc2V0SUQuZnJvbVVpbnQ2NCh2YWxpZGF0b3JDb25maWcucmV3YXJkVG9rZW5JZCksCgkvLyAgICAgICAgICAgICAgICAgYXNzZXRSZWNlaXZlcjogdGhpcy5hcHAuYWRkcmVzcywKCS8vICAgICAgICAgICAgICAgICBhc3NldEFtb3VudDogMCwKCS8vICAgICAgICAgICAgIH0pCglpdHhuX2JlZ2luCglpbnQgYXhmZXIKCWl0eG5fZmllbGQgVHlwZUVudW0KCgkvLyBjb250cmFjdHMvc3Rha2luZ1Bvb2wuYWxnby50czoxNjYKCS8vIHhmZXJBc3NldDogQXNzZXRJRC5mcm9tVWludDY0KHZhbGlkYXRvckNvbmZpZy5yZXdhcmRUb2tlbklkKQoJZnJhbWVfZGlnIDAgLy8gdmFsaWRhdG9yQ29uZmlnOiAodWludDY0LGFkZHJlc3MsYWRkcmVzcyx1aW50NjQsdWludDgsYnl0ZVszMl0sdWludDY0LHVpbnQ2NCx1aW50NjQsdWludDE2LHVpbnQzMixhZGRyZXNzLHVpbnQ2NCx1aW50NjQsdWludDgsdWludDY0LHVpbnQ2NCkKCWV4dHJhY3QgMTIxIDgKCWJ0b2kKCWl0eG5fZmllbGQgWGZlckFzc2V0CgoJLy8gY29udHJhY3RzL3N0YWtpbmdQb29sLmFsZ28udHM6MTY3CgkvLyBhc3NldFJlY2VpdmVyOiB0aGlzLmFwcC5hZGRyZXNzCglnbG9iYWwgQ3VycmVudEFwcGxpY2F0aW9uQWRkcmVzcwoJaXR4bl9maWVsZCBBc3NldFJlY2VpdmVyCgoJLy8gY29udHJhY3RzL3N0YWtpbmdQb29sLmFsZ28udHM6MTY4CgkvLyBhc3NldEFtb3VudDogMAoJaW50IDAKCWl0eG5fZmllbGQgQXNzZXRBbW91bnQKCgkvLyBGZWUgZmllbGQgbm90IHNldCwgZGVmYXVsdGluZyB0byAwCglpbnQgMAoJaXR4bl9maWVsZCBGZWUKCgkvLyBTdWJtaXQgaW5uZXIgdHJhbnNhY3Rpb24KCWl0eG5fc3VibWl0CgoqaWYxX2VuZDoKCXJldHN1YgoKLy8gYWRkU3Rha2UocGF5LGFkZHJlc3MpdWludDY0CiphYmlfcm91dGVfYWRkU3Rha2U6CgkvLyBUaGUgQUJJIHJldHVybiBwcmVmaXgKCWJ5dGUgMHgxNTFmN2M3NQoKCS8vIHN0YWtlcjogYWRkcmVzcwoJdHhuYSBBcHBsaWNhdGlvbkFyZ3MgMQoJZHVwCglsZW4KCWludCAzMgoJPT0KCWFzc2VydAoKCS8vIHN0YWtlZEFtb3VudFBheW1lbnQ6IHBheQoJdHhuIEdyb3VwSW5kZXgKCWludCAxCgktCglkdXAKCWd0eG5zIFR5cGVFbnVtCglpbnQgcGF5Cgk9PQoJYXNzZXJ0CgoJLy8gZXhlY3V0ZSBhZGRTdGFrZShwYXksYWRkcmVzcyl1aW50NjQKCWNhbGxzdWIgYWRkU3Rha2UKCWl0b2IKCWNvbmNhdAoJbG9nCglpbnQgMQoJcmV0dXJuCgovLyBhZGRTdGFrZShzdGFrZWRBbW91bnRQYXltZW50OiBQYXlUeG4sIHN0YWtlcjogQWRkcmVzcyk6IHVpbnQ2NAovLwovLyBBZGRzIHN0YWtlIHRvIHRoZSBnaXZlbiBhY2NvdW50LgovLyBDYW4gT05MWSBiZSBjYWxsZWQgYnkgdGhlIHZhbGlkYXRvciBjb250cmFjdCB0aGF0IGNyZWF0ZWQgdXMKLy8gTXVzdCByZWNlaXZlIHBheW1lbnQgZnJvbSB0aGUgdmFsaWRhdG9yIGNvbnRyYWN0IGZvciBhbW91bnQgYmVpbmcgc3Rha2VkLgovLwovLyBAcGFyYW0ge1BheVR4bn0gc3Rha2VkQW1vdW50UGF5bWVudCBwcmlvciBwYXltZW50IGNvbWluZyBmcm9tIHZhbGlkYXRvciBjb250cmFjdCB0byB1cyBvbiBiZWhhbGYgb2Ygc3Rha2VyLgovLyBAcGFyYW0ge0FkZHJlc3N9IHN0YWtlciAtIFRoZSBhY2NvdW50IGFkZGluZyBuZXcgc3Rha2UKLy8gQHRocm93cyB7RXJyb3J9IC0gVGhyb3dzIGFuIGVycm9yIGlmIHRoZSBzdGFraW5nIHBvb2wgaXMgZnVsbC4KLy8gQHJldHVybnMge3VpbnQ2NH0gbmV3ICdlbnRyeSB0aW1lJyBpbiBzZWNvbmRzIG9mIHN0YWtlIGFkZC4KYWRkU3Rha2U6Cglwcm90byAyIDEKCgkvLyBQdXNoIGVtcHR5IGJ5dGVzIGFmdGVyIHRoZSBmcmFtZSBwb2ludGVyIHRvIHJlc2VydmUgc3BhY2UgZm9yIGxvY2FsIHZhcmlhYmxlcwoJYnl0ZSAweAoJZHVwbiAzCgoJLy8gY29udHJhY3RzL3N0YWtpbmdQb29sLmFsZ28udHM6MTg0CgkvLyBhc3NlcnQodGhpcy5zdGFrZXJzLmV4aXN0cykKCWJ5dGUgMHg3Mzc0NjE2YjY1NzI3MyAvLyAic3Rha2VycyIKCWJveF9sZW4KCXN3YXAKCXBvcAoJYXNzZXJ0CgoJLy8gY29udHJhY3RzL3N0YWtpbmdQb29sLmFsZ28udHM6MTg3CgkvLyBhc3NlcnQodGhpcy50eG4uc2VuZGVyID09PSBBcHBJRC5mcm9tVWludDY0KHRoaXMuY3JlYXRpbmdWYWxpZGF0b3JDb250cmFjdEFwcElkLnZhbHVlKS5hZGRyZXNzKQoJdHhuIFNlbmRlcgoJYnl0ZSAweDYzNzI2NTYxNzQ2ZjcyNDE3MDcwIC8vICJjcmVhdG9yQXBwIgoJYXBwX2dsb2JhbF9nZXQKCWFwcF9wYXJhbXNfZ2V0IEFwcEFkZHJlc3MKCXBvcAoJPT0KCWFzc2VydAoKCS8vIGNvbnRyYWN0cy9zdGFraW5nUG9vbC5hbGdvLnRzOjE4OAoJLy8gYXNzZXJ0KHN0YWtlciAhPT0gZ2xvYmFscy56ZXJvQWRkcmVzcykKCWZyYW1lX2RpZyAtMiAvLyBzdGFrZXI6IEFkZHJlc3MKCWdsb2JhbCBaZXJvQWRkcmVzcwoJIT0KCWFzc2VydAoKCS8vIGNvbnRyYWN0cy9zdGFraW5nUG9vbC5hbGdvLnRzOjE5MgoJLy8gdmVyaWZ5UGF5VHhuKHN0YWtlZEFtb3VudFBheW1lbnQsIHsKCS8vICAgICAgICAgICAgIHNlbmRlcjogQXBwSUQuZnJvbVVpbnQ2NCh0aGlzLmNyZWF0aW5nVmFsaWRhdG9yQ29udHJhY3RBcHBJZC52YWx1ZSkuYWRkcmVzcywKCS8vICAgICAgICAgICAgIHJlY2VpdmVyOiB0aGlzLmFwcC5hZGRyZXNzLAoJLy8gICAgICAgICAgICAgYW1vdW50OiBzdGFrZWRBbW91bnRQYXltZW50LmFtb3VudCwKCS8vICAgICAgICAgfSkKCS8vIHZlcmlmeSBzZW5kZXIKCWZyYW1lX2RpZyAtMSAvLyBzdGFrZWRBbW91bnRQYXltZW50OiBQYXlUeG4KCWd0eG5zIFNlbmRlcgoJYnl0ZSAweDYzNzI2NTYxNzQ2ZjcyNDE3MDcwIC8vICJjcmVhdG9yQXBwIgoJYXBwX2dsb2JhbF9nZXQKCWFwcF9wYXJhbXNfZ2V0IEFwcEFkZHJlc3MKCXBvcAoJPT0KCWFzc2VydAoKCS8vIHZlcmlmeSByZWNlaXZlcgoJZnJhbWVfZGlnIC0xIC8vIHN0YWtlZEFtb3VudFBheW1lbnQ6IFBheVR4bgoJZ3R4bnMgUmVjZWl2ZXIKCWdsb2JhbCBDdXJyZW50QXBwbGljYXRpb25BZGRyZXNzCgk9PQoJYXNzZXJ0CgoJLy8gdmVyaWZ5IGFtb3VudAoJZnJhbWVfZGlnIC0xIC8vIHN0YWtlZEFtb3VudFBheW1lbnQ6IFBheVR4bgoJZ3R4bnMgQW1vdW50CglmcmFtZV9kaWcgLTEgLy8gc3Rha2VkQW1vdW50UGF5bWVudDogUGF5VHhuCglndHhucyBBbW91bnQKCT09Cglhc3NlcnQKCgkvLyBjb250cmFjdHMvc3Rha2luZ1Bvb2wuYWxnby50czoyMDEKCS8vIGVudHJ5VGltZSA9IHRoaXMuZ2V0RW50cnlUaW1lKCkKCWNhbGxzdWIgZ2V0RW50cnlUaW1lCglmcmFtZV9idXJ5IDAgLy8gZW50cnlUaW1lOiB1aW50NjQKCgkvLyBjb250cmFjdHMvc3Rha2luZ1Bvb2wuYWxnby50czoyMDIKCS8vIGZpcnN0RW1wdHkgPSAwCglpbnQgMAoJZnJhbWVfYnVyeSAxIC8vIGZpcnN0RW1wdHk6IHVpbnQ2NAoKCS8vIGNvbnRyYWN0cy9zdGFraW5nUG9vbC5hbGdvLnRzOjIwNQoJLy8gZm9yIChsZXQgaSA9IDA7IGkgPCB0aGlzLnN0YWtlcnMudmFsdWUubGVuZ3RoOyBpICs9IDEpCglpbnQgMAoJZnJhbWVfYnVyeSAyIC8vIGk6IHVpbnQ2NAoKKmZvcl8wOgoJLy8gY29udHJhY3RzL3N0YWtpbmdQb29sLmFsZ28udHM6MjA1CgkvLyBpIDwgdGhpcy5zdGFrZXJzLnZhbHVlLmxlbmd0aAoJZnJhbWVfZGlnIDIgLy8gaTogdWludDY0CglpbnQgMjAwCgk8CglieiAqZm9yXzBfZW5kCgoJLy8gKmlmMl9jb25kaXRpb24KCS8vIGNvbnRyYWN0cy9zdGFraW5nUG9vbC5hbGdvLnRzOjIwNgoJLy8gZ2xvYmFscy5vcGNvZGVCdWRnZXQgPCAzMDAKCWdsb2JhbCBPcGNvZGVCdWRnZXQKCWludCAzMDAKCTwKCWJ6ICppZjJfZW5kCgoJLy8gKmlmMl9jb25zZXF1ZW50CgkvLyBjb250cmFjdHMvc3Rha2luZ1Bvb2wuYWxnby50czoyMDcKCS8vIGluY3JlYXNlT3Bjb2RlQnVkZ2V0KCkKCWl0eG5fYmVnaW4KCWludCBhcHBsCglpdHhuX2ZpZWxkIFR5cGVFbnVtCglpbnQgMAoJaXR4bl9maWVsZCBGZWUKCWJ5dGUgYjY0IENvRUIgLy8gI3ByYWdtYSB2ZXJzaW9uIDEwOyBpbnQgMQoJZHVwCglpdHhuX2ZpZWxkIEFwcHJvdmFsUHJvZ3JhbQoJaXR4bl9maWVsZCBDbGVhclN0YXRlUHJvZ3JhbQoJaW50IERlbGV0ZUFwcGxpY2F0aW9uCglpdHhuX2ZpZWxkIE9uQ29tcGxldGlvbgoJaXR4bl9zdWJtaXQKCippZjJfZW5kOgoJLy8gY29udHJhY3RzL3N0YWtpbmdQb29sLmFsZ28udHM6MjA5CgkvLyBjbXBTdGFrZXIgPSBjbG9uZSh0aGlzLnN0YWtlcnMudmFsdWVbaV0pCglmcmFtZV9kaWcgMiAvLyBpOiB1aW50NjQKCWludCA2NAoJKiAvLyBhY2MgKiB0eXBlTGVuZ3RoCglpbnQgNjQKCWJ5dGUgMHg3Mzc0NjE2YjY1NzI3MyAvLyAic3Rha2VycyIKCWNvdmVyIDIKCWJveF9leHRyYWN0CglmcmFtZV9idXJ5IDMgLy8gY21wU3Rha2VyOiAoYWRkcmVzcyx1aW50NjQsdWludDY0LHVpbnQ2NCx1aW50NjQpCgoJLy8gKmlmM19jb25kaXRpb24KCS8vIGNvbnRyYWN0cy9zdGFraW5nUG9vbC5hbGdvLnRzOjIxMAoJLy8gY21wU3Rha2VyLmFjY291bnQgPT09IHN0YWtlcgoJZnJhbWVfZGlnIDMgLy8gY21wU3Rha2VyOiAoYWRkcmVzcyx1aW50NjQsdWludDY0LHVpbnQ2NCx1aW50NjQpCglleHRyYWN0IDAgMzIKCWZyYW1lX2RpZyAtMiAvLyBzdGFrZXI6IEFkZHJlc3MKCT09CglieiAqaWYzX2VuZAoKCS8vICppZjNfY29uc2VxdWVudAoJLy8gY29udHJhY3RzL3N0YWtpbmdQb29sLmFsZ28udHM6MjExCgkvLyBjbXBTdGFrZXIuYmFsYW5jZSArPSBzdGFrZWRBbW91bnRQYXltZW50LmFtb3VudAoJZnJhbWVfZGlnIDMgLy8gY21wU3Rha2VyOiAoYWRkcmVzcyx1aW50NjQsdWludDY0LHVpbnQ2NCx1aW50NjQpCglpbnQgMzIgLy8gaGVhZE9mZnNldAoJZnJhbWVfZGlnIDMgLy8gY21wU3Rha2VyOiAoYWRkcmVzcyx1aW50NjQsdWludDY0LHVpbnQ2NCx1aW50NjQpCglleHRyYWN0IDMyIDgKCWJ0b2kKCWZyYW1lX2RpZyAtMSAvLyBzdGFrZWRBbW91bnRQYXltZW50OiBQYXlUeG4KCWd0eG5zIEFtb3VudAoJKwoJaXRvYgoJcmVwbGFjZTMKCWZyYW1lX2J1cnkgMyAvLyBjbXBTdGFrZXI6IChhZGRyZXNzLHVpbnQ2NCx1aW50NjQsdWludDY0LHVpbnQ2NCkKCgkvLyBjb250cmFjdHMvc3Rha2luZ1Bvb2wuYWxnby50czoyMTIKCS8vIGNtcFN0YWtlci5lbnRyeVRpbWUgPSBlbnRyeVRpbWUKCWZyYW1lX2RpZyAzIC8vIGNtcFN0YWtlcjogKGFkZHJlc3MsdWludDY0LHVpbnQ2NCx1aW50NjQsdWludDY0KQoJaW50IDU2IC8vIGhlYWRPZmZzZXQKCWZyYW1lX2RpZyAwIC8vIGVudHJ5VGltZTogdWludDY0CglpdG9iCglyZXBsYWNlMwoJZnJhbWVfYnVyeSAzIC8vIGNtcFN0YWtlcjogKGFkZHJlc3MsdWludDY0LHVpbnQ2NCx1aW50NjQsdWludDY0KQoKCS8vIGNvbnRyYWN0cy9zdGFraW5nUG9vbC5hbGdvLnRzOjIxNQoJLy8gdGhpcy5zdGFrZXJzLnZhbHVlW2ldID0gY21wU3Rha2VyCglmcmFtZV9kaWcgMiAvLyBpOiB1aW50NjQKCWludCA2NAoJKiAvLyBhY2MgKiB0eXBlTGVuZ3RoCglmcmFtZV9kaWcgMyAvLyBjbXBTdGFrZXI6IChhZGRyZXNzLHVpbnQ2NCx1aW50NjQsdWludDY0LHVpbnQ2NCkKCWJ5dGUgMHg3Mzc0NjE2YjY1NzI3MyAvLyAic3Rha2VycyIKCWNvdmVyIDIKCWJveF9yZXBsYWNlCgoJLy8gY29udHJhY3RzL3N0YWtpbmdQb29sLmFsZ28udHM6MjE3CgkvLyB0aGlzLnRvdGFsQWxnb1N0YWtlZC52YWx1ZSArPSBzdGFrZWRBbW91bnRQYXltZW50LmFtb3VudAoJYnl0ZSAweDczNzQ2MTZiNjU2NCAvLyAic3Rha2VkIgoJYXBwX2dsb2JhbF9nZXQKCWZyYW1lX2RpZyAtMSAvLyBzdGFrZWRBbW91bnRQYXltZW50OiBQYXlUeG4KCWd0eG5zIEFtb3VudAoJKwoJYnl0ZSAweDczNzQ2MTZiNjU2NCAvLyAic3Rha2VkIgoJc3dhcAoJYXBwX2dsb2JhbF9wdXQKCgkvLyBjb250cmFjdHMvc3Rha2luZ1Bvb2wuYWxnby50czoyMTgKCS8vIHJldHVybiBlbnRyeVRpbWU7CglmcmFtZV9kaWcgMCAvLyBlbnRyeVRpbWU6IHVpbnQ2NAoKCS8vIHNldCB0aGUgc3Vicm91dGluZSByZXR1cm4gdmFsdWUKCWZyYW1lX2J1cnkgMAoKCS8vIHBvcCBhbGwgbG9jYWwgdmFyaWFibGVzIGZyb20gdGhlIHN0YWNrCglwb3BuIDMKCXJldHN1YgoKKmlmM19lbmQ6CgkvLyAqaWY0X2NvbmRpdGlvbgoJLy8gY29udHJhY3RzL3N0YWtpbmdQb29sLmFsZ28udHM6MjIwCgkvLyBjbXBTdGFrZXIuYWNjb3VudCA9PT0gZ2xvYmFscy56ZXJvQWRkcmVzcwoJZnJhbWVfZGlnIDMgLy8gY21wU3Rha2VyOiAoYWRkcmVzcyx1aW50NjQsdWludDY0LHVpbnQ2NCx1aW50NjQpCglleHRyYWN0IDAgMzIKCWdsb2JhbCBaZXJvQWRkcmVzcwoJPT0KCWJ6ICppZjRfZW5kCgoJLy8gKmlmNF9jb25zZXF1ZW50CgkvLyBjb250cmFjdHMvc3Rha2luZ1Bvb2wuYWxnby50czoyMjEKCS8vIGZpcnN0RW1wdHkgPSBpICsgMQoJZnJhbWVfZGlnIDIgLy8gaTogdWludDY0CglpbnQgMQoJKwoJZnJhbWVfYnVyeSAxIC8vIGZpcnN0RW1wdHk6IHVpbnQ2NAoJYiAqZm9yXzBfZW5kCgoqaWY0X2VuZDoKCipmb3JfMF9jb250aW51ZToKCS8vIGNvbnRyYWN0cy9zdGFraW5nUG9vbC5hbGdvLnRzOjIwNQoJLy8gaSArPSAxCglmcmFtZV9kaWcgMiAvLyBpOiB1aW50NjQKCWludCAxCgkrCglmcmFtZV9idXJ5IDIgLy8gaTogdWludDY0CgliICpmb3JfMAoKKmZvcl8wX2VuZDoKCS8vICppZjVfY29uZGl0aW9uCgkvLyBjb250cmFjdHMvc3Rha2luZ1Bvb2wuYWxnby50czoyMjYKCS8vIGZpcnN0RW1wdHkgPT09IDAKCWZyYW1lX2RpZyAxIC8vIGZpcnN0RW1wdHk6IHVpbnQ2NAoJaW50IDAKCT09CglieiAqaWY1X2VuZAoKCS8vICppZjVfY29uc2VxdWVudAoJZXJyIC8vICdTdGFraW5nIHBvb2wgZnVsbCcKCippZjVfZW5kOgoJLy8gY29udHJhY3RzL3N0YWtpbmdQb29sLmFsZ28udHM6MjMzCgkvLyBhc3NlcnQoc3Rha2VkQW1vdW50UGF5bWVudC5hbW91bnQgPj0gdGhpcy5taW5FbnRyeVN0YWtlLnZhbHVlLCAnbXVzdCBzdGFrZSBhdCBsZWFzdCB0aGUgbWluaW11bSBmb3IgdGhpcyBwb29sJykKCWZyYW1lX2RpZyAtMSAvLyBzdGFrZWRBbW91bnRQYXltZW50OiBQYXlUeG4KCWd0eG5zIEFtb3VudAoJYnl0ZSAweDZkNjk2ZTQ1NmU3NDcyNzk1Mzc0NjE2YjY1IC8vICJtaW5FbnRyeVN0YWtlIgoJYXBwX2dsb2JhbF9nZXQKCT49CgoJLy8gbXVzdCBzdGFrZSBhdCBsZWFzdCB0aGUgbWluaW11bSBmb3IgdGhpcyBwb29sCglhc3NlcnQKCgkvLyBjb250cmFjdHMvc3Rha2luZ1Bvb2wuYWxnby50czoyMzUKCS8vIGFzc2VydCh0aGlzLnN0YWtlcnMudmFsdWVbZmlyc3RFbXB0eSAtIDFdLmFjY291bnQgPT09IGdsb2JhbHMuemVyb0FkZHJlc3MpCglmcmFtZV9kaWcgMSAvLyBmaXJzdEVtcHR5OiB1aW50NjQKCWludCAxCgktCglpbnQgNjQKCSogLy8gYWNjICogdHlwZUxlbmd0aAoJaW50IDAKCSsKCWludCAzMgoJYnl0ZSAweDczNzQ2MTZiNjU3MjczIC8vICJzdGFrZXJzIgoJY292ZXIgMgoJYm94X2V4dHJhY3QKCWdsb2JhbCBaZXJvQWRkcmVzcwoJPT0KCWFzc2VydAoKCS8vIGNvbnRyYWN0cy9zdGFraW5nUG9vbC5hbGdvLnRzOjIzNgoJLy8gdGhpcy5zdGFrZXJzLnZhbHVlW2ZpcnN0RW1wdHkgLSAxXSA9IHsKCS8vICAgICAgICAgICAgIGFjY291bnQ6IHN0YWtlciwKCS8vICAgICAgICAgICAgIGJhbGFuY2U6IHN0YWtlZEFtb3VudFBheW1lbnQuYW1vdW50LAoJLy8gICAgICAgICAgICAgdG90YWxSZXdhcmRlZDogMCwKCS8vICAgICAgICAgICAgIHJld2FyZFRva2VuQmFsYW5jZTogMCwKCS8vICAgICAgICAgICAgIGVudHJ5VGltZTogZW50cnlUaW1lLAoJLy8gICAgICAgICB9CglmcmFtZV9kaWcgMSAvLyBmaXJzdEVtcHR5OiB1aW50NjQKCWludCAxCgktCglpbnQgNjQKCSogLy8gYWNjICogdHlwZUxlbmd0aAoJZnJhbWVfZGlnIC0yIC8vIHN0YWtlcjogQWRkcmVzcwoJZnJhbWVfZGlnIC0xIC8vIHN0YWtlZEFtb3VudFBheW1lbnQ6IFBheVR4bgoJZ3R4bnMgQW1vdW50CglpdG9iCgljb25jYXQKCWJ5dGUgMHgwMDAwMDAwMDAwMDAwMDAwCgljb25jYXQKCWJ5dGUgMHgwMDAwMDAwMDAwMDAwMDAwCgljb25jYXQKCWZyYW1lX2RpZyAwIC8vIGVudHJ5VGltZTogdWludDY0CglpdG9iCgljb25jYXQKCWJ5dGUgMHg3Mzc0NjE2YjY1NzI3MyAvLyAic3Rha2VycyIKCWNvdmVyIDIKCWJveF9yZXBsYWNlCgoJLy8gY29udHJhY3RzL3N0YWtpbmdQb29sLmFsZ28udHM6MjQzCgkvLyB0aGlzLm51bVN0YWtlcnMudmFsdWUgKz0gMQoJYnl0ZSAweDZlNzU2ZDUzNzQ2MTZiNjU3MjczIC8vICJudW1TdGFrZXJzIgoJYXBwX2dsb2JhbF9nZXQKCWludCAxCgkrCglieXRlIDB4NmU3NTZkNTM3NDYxNmI2NTcyNzMgLy8gIm51bVN0YWtlcnMiCglzd2FwCglhcHBfZ2xvYmFsX3B1dAoKCS8vIGNvbnRyYWN0cy9zdGFraW5nUG9vbC5hbGdvLnRzOjI0NAoJLy8gdGhpcy50b3RhbEFsZ29TdGFrZWQudmFsdWUgKz0gc3Rha2VkQW1vdW50UGF5bWVudC5hbW91bnQKCWJ5dGUgMHg3Mzc0NjE2YjY1NjQgLy8gInN0YWtlZCIKCWFwcF9nbG9iYWxfZ2V0CglmcmFtZV9kaWcgLTEgLy8gc3Rha2VkQW1vdW50UGF5bWVudDogUGF5VHhuCglndHhucyBBbW91bnQKCSsKCWJ5dGUgMHg3Mzc0NjE2YjY1NjQgLy8gInN0YWtlZCIKCXN3YXAKCWFwcF9nbG9iYWxfcHV0CgoJLy8gY29udHJhY3RzL3N0YWtpbmdQb29sLmFsZ28udHM6MjQ1CgkvLyByZXR1cm4gZW50cnlUaW1lOwoJZnJhbWVfZGlnIDAgLy8gZW50cnlUaW1lOiB1aW50NjQKCgkvLyBzZXQgdGhlIHN1YnJvdXRpbmUgcmV0dXJuIHZhbHVlCglmcmFtZV9idXJ5IDAKCgkvLyBwb3AgYWxsIGxvY2FsIHZhcmlhYmxlcyBmcm9tIHRoZSBzdGFjawoJcG9wbiAzCglyZXRzdWIKCi8vIHJlbW92ZVN0YWtlKHVpbnQ2NCl2b2lkCiphYmlfcm91dGVfcmVtb3ZlU3Rha2U6CgkvLyBhbW91bnRUb1Vuc3Rha2U6IHVpbnQ2NAoJdHhuYSBBcHBsaWNhdGlvbkFyZ3MgMQoJYnRvaQoKCS8vIGV4ZWN1dGUgcmVtb3ZlU3Rha2UodWludDY0KXZvaWQKCWNhbGxzdWIgcmVtb3ZlU3Rha2UKCWludCAxCglyZXR1cm4KCi8vIHJlbW92ZVN0YWtlKGFtb3VudFRvVW5zdGFrZTogdWludDY0KTogdm9pZAovLwovLyBSZW1vdmVzIHN0YWtlIG9uIGJlaGFsZiBvZiBjYWxsZXIgKHJlbW92aW5nIG93biBzdGFrZSkuICBJZiBhbnkgdG9rZW4gcmV3YXJkcyBleGlzdCwgdGhvc2UgYXJlIGFsd2F5cyBzZW50IGluCi8vIGZ1bGwuIEFsc28gbm90aWZpZXMgdGhlIHZhbGlkYXRvciBjb250cmFjdCBmb3IgdGhpcyBwb29scyB2YWxpZGF0b3Igb2YgdGhlIHN0YWtlciAvIGJhbGFuY2UgY2hhbmdlcy4KLy8KLy8gQHBhcmFtIHt1aW50NjR9IGFtb3VudFRvVW5zdGFrZSAtIFRoZSBhbW91bnQgb2Ygc3Rha2UgdG8gYmUgcmVtb3ZlZC4gIFNwZWNpZnkgMCB0byByZW1vdmUgYWxsIHN0YWtlLgovLyBAdGhyb3dzIHtFcnJvcn0gSWYgdGhlIGFjY291bnQgaGFzIGluc3VmZmljaWVudCBiYWxhbmNlIG9yIGlmIHRoZSBhY2NvdW50IGlzIG5vdCBmb3VuZC4KcmVtb3ZlU3Rha2U6Cglwcm90byAxIDAKCgkvLyBQdXNoIGVtcHR5IGJ5dGVzIGFmdGVyIHRoZSBmcmFtZSBwb2ludGVyIHRvIHJlc2VydmUgc3BhY2UgZm9yIGxvY2FsIHZhcmlhYmxlcwoJYnl0ZSAweAoJZHVwbiA1CgoJLy8gY29udHJhY3RzL3N0YWtpbmdQb29sLmFsZ28udHM6MjU5CgkvLyBzdGFrZXIgPSB0aGlzLnR4bi5zZW5kZXIKCXR4biBTZW5kZXIKCWZyYW1lX2J1cnkgMCAvLyBzdGFrZXI6IGFkZHJlc3MKCgkvLyBjb250cmFjdHMvc3Rha2luZ1Bvb2wuYWxnby50czoyNjEKCS8vIGZvciAobGV0IGkgPSAwOyBpIDwgdGhpcy5zdGFrZXJzLnZhbHVlLmxlbmd0aDsgaSArPSAxKQoJaW50IDAKCWZyYW1lX2J1cnkgMSAvLyBpOiB1aW50NjQKCipmb3JfMToKCS8vIGNvbnRyYWN0cy9zdGFraW5nUG9vbC5hbGdvLnRzOjI2MQoJLy8gaSA8IHRoaXMuc3Rha2Vycy52YWx1ZS5sZW5ndGgKCWZyYW1lX2RpZyAxIC8vIGk6IHVpbnQ2NAoJaW50IDIwMAoJPAoJYnogKmZvcl8xX2VuZAoKCS8vICppZjZfY29uZGl0aW9uCgkvLyBjb250cmFjdHMvc3Rha2luZ1Bvb2wuYWxnby50czoyNjIKCS8vIGdsb2JhbHMub3Bjb2RlQnVkZ2V0IDwgMzAwCglnbG9iYWwgT3Bjb2RlQnVkZ2V0CglpbnQgMzAwCgk8CglieiAqaWY2X2VuZAoKCS8vICppZjZfY29uc2VxdWVudAoJLy8gY29udHJhY3RzL3N0YWtpbmdQb29sLmFsZ28udHM6MjYzCgkvLyBpbmNyZWFzZU9wY29kZUJ1ZGdldCgpCglpdHhuX2JlZ2luCglpbnQgYXBwbAoJaXR4bl9maWVsZCBUeXBlRW51bQoJaW50IDAKCWl0eG5fZmllbGQgRmVlCglieXRlIGI2NCBDb0VCIC8vICNwcmFnbWEgdmVyc2lvbiAxMDsgaW50IDEKCWR1cAoJaXR4bl9maWVsZCBBcHByb3ZhbFByb2dyYW0KCWl0eG5fZmllbGQgQ2xlYXJTdGF0ZVByb2dyYW0KCWludCBEZWxldGVBcHBsaWNhdGlvbgoJaXR4bl9maWVsZCBPbkNvbXBsZXRpb24KCWl0eG5fc3VibWl0CgoqaWY2X2VuZDoKCS8vIGNvbnRyYWN0cy9zdGFraW5nUG9vbC5hbGdvLnRzOjI2NQoJLy8gY21wU3Rha2VyID0gY2xvbmUodGhpcy5zdGFrZXJzLnZhbHVlW2ldKQoJZnJhbWVfZGlnIDEgLy8gaTogdWludDY0CglpbnQgNjQKCSogLy8gYWNjICogdHlwZUxlbmd0aAoJaW50IDY0CglieXRlIDB4NzM3NDYxNmI2NTcyNzMgLy8gInN0YWtlcnMiCgljb3ZlciAyCglib3hfZXh0cmFjdAoJZnJhbWVfYnVyeSAyIC8vIGNtcFN0YWtlcjogKGFkZHJlc3MsdWludDY0LHVpbnQ2NCx1aW50NjQsdWludDY0KQoKCS8vICppZjdfY29uZGl0aW9uCgkvLyBjb250cmFjdHMvc3Rha2luZ1Bvb2wuYWxnby50czoyNjYKCS8vIGNtcFN0YWtlci5hY2NvdW50ID09PSBzdGFrZXIKCWZyYW1lX2RpZyAyIC8vIGNtcFN0YWtlcjogKGFkZHJlc3MsdWludDY0LHVpbnQ2NCx1aW50NjQsdWludDY0KQoJZXh0cmFjdCAwIDMyCglmcmFtZV9kaWcgMCAvLyBzdGFrZXI6IGFkZHJlc3MKCT09CglieiAqaWY3X2VuZAoKCS8vICppZjdfY29uc2VxdWVudAoJLy8gKmlmOF9jb25kaXRpb24KCS8vIGNvbnRyYWN0cy9zdGFraW5nUG9vbC5hbGdvLnRzOjI2NwoJLy8gYW1vdW50VG9VbnN0YWtlID09PSAwCglmcmFtZV9kaWcgLTEgLy8gYW1vdW50VG9VbnN0YWtlOiB1aW50NjQKCWludCAwCgk9PQoJYnogKmlmOF9lbmQKCgkvLyAqaWY4X2NvbnNlcXVlbnQKCS8vIGNvbnRyYWN0cy9zdGFraW5nUG9vbC5hbGdvLnRzOjI2OQoJLy8gYW1vdW50VG9VbnN0YWtlID0gY21wU3Rha2VyLmJhbGFuY2UKCWZyYW1lX2RpZyAyIC8vIGNtcFN0YWtlcjogKGFkZHJlc3MsdWludDY0LHVpbnQ2NCx1aW50NjQsdWludDY0KQoJZXh0cmFjdCAzMiA4CglidG9pCglmcmFtZV9idXJ5IC0xIC8vIGFtb3VudFRvVW5zdGFrZTogdWludDY0CgoqaWY4X2VuZDoKCS8vICppZjlfY29uZGl0aW9uCgkvLyBjb250cmFjdHMvc3Rha2luZ1Bvb2wuYWxnby50czoyNzEKCS8vIGNtcFN0YWtlci5iYWxhbmNlIDwgYW1vdW50VG9VbnN0YWtlCglmcmFtZV9kaWcgMiAvLyBjbXBTdGFrZXI6IChhZGRyZXNzLHVpbnQ2NCx1aW50NjQsdWludDY0LHVpbnQ2NCkKCWV4dHJhY3QgMzIgOAoJYnRvaQoJZnJhbWVfZGlnIC0xIC8vIGFtb3VudFRvVW5zdGFrZTogdWludDY0Cgk8CglieiAqaWY5X2VuZAoKCS8vICppZjlfY29uc2VxdWVudAoJZXJyIC8vICdJbnN1ZmZpY2llbnQgYmFsYW5jZScKCippZjlfZW5kOgoJLy8gY29udHJhY3RzL3N0YWtpbmdQb29sLmFsZ28udHM6Mjc0CgkvLyBjbXBTdGFrZXIuYmFsYW5jZSAtPSBhbW91bnRUb1Vuc3Rha2UKCWZyYW1lX2RpZyAyIC8vIGNtcFN0YWtlcjogKGFkZHJlc3MsdWludDY0LHVpbnQ2NCx1aW50NjQsdWludDY0KQoJaW50IDMyIC8vIGhlYWRPZmZzZXQKCWZyYW1lX2RpZyAyIC8vIGNtcFN0YWtlcjogKGFkZHJlc3MsdWludDY0LHVpbnQ2NCx1aW50NjQsdWludDY0KQoJZXh0cmFjdCAzMiA4CglidG9pCglmcmFtZV9kaWcgLTEgLy8gYW1vdW50VG9VbnN0YWtlOiB1aW50NjQKCS0KCWl0b2IKCXJlcGxhY2UzCglmcmFtZV9idXJ5IDIgLy8gY21wU3Rha2VyOiAoYWRkcmVzcyx1aW50NjQsdWludDY0LHVpbnQ2NCx1aW50NjQpCgoJLy8gY29udHJhY3RzL3N0YWtpbmdQb29sLmFsZ28udHM6Mjc1CgkvLyB0aGlzLnRvdGFsQWxnb1N0YWtlZC52YWx1ZSAtPSBhbW91bnRUb1Vuc3Rha2UKCWJ5dGUgMHg3Mzc0NjE2YjY1NjQgLy8gInN0YWtlZCIKCWFwcF9nbG9iYWxfZ2V0CglmcmFtZV9kaWcgLTEgLy8gYW1vdW50VG9VbnN0YWtlOiB1aW50NjQKCS0KCWJ5dGUgMHg3Mzc0NjE2YjY1NjQgLy8gInN0YWtlZCIKCXN3YXAKCWFwcF9nbG9iYWxfcHV0CgoJLy8gY29udHJhY3RzL3N0YWtpbmdQb29sLmFsZ28udHM6Mjc3CgkvLyBhbW91bnRSZXdhcmRUb2tlblJlbW92ZWQgPSAwCglpbnQgMAoJZnJhbWVfYnVyeSAzIC8vIGFtb3VudFJld2FyZFRva2VuUmVtb3ZlZDogdWludDY0CgoJLy8gKmlmMTBfY29uZGl0aW9uCgkvLyBjb250cmFjdHMvc3Rha2luZ1Bvb2wuYWxnby50czoyNzgKCS8vIGNtcFN0YWtlci5yZXdhcmRUb2tlbkJhbGFuY2UgPiAwCglmcmFtZV9kaWcgMiAvLyBjbXBTdGFrZXI6IChhZGRyZXNzLHVpbnQ2NCx1aW50NjQsdWludDY0LHVpbnQ2NCkKCWV4dHJhY3QgNDggOAoJYnRvaQoJaW50IDAKCT4KCWJ6ICppZjEwX2VuZAoKCS8vICppZjEwX2NvbnNlcXVlbnQKCS8vICppZjExX2NvbmRpdGlvbgoJLy8gY29udHJhY3RzL3N0YWtpbmdQb29sLmFsZ28udHM6MjgwCgkvLyB0aGlzLnBvb2xJZC52YWx1ZSA9PT0gMQoJYnl0ZSAweDcwNmY2ZjZjNDk2NCAvLyAicG9vbElkIgoJYXBwX2dsb2JhbF9nZXQKCWludCAxCgk9PQoJYnogKmlmMTFfZWxzZQoKCS8vICppZjExX2NvbnNlcXVlbnQKCS8vIGNvbnRyYWN0cy9zdGFraW5nUG9vbC5hbGdvLnRzOjI4MQoJLy8gdmFsaWRhdG9yQ29uZmlnID0gc2VuZE1ldGhvZENhbGw8dHlwZW9mIFZhbGlkYXRvclJlZ2lzdHJ5LnByb3RvdHlwZS5nZXRWYWxpZGF0b3JDb25maWc+KHsKCS8vICAgICAgICAgICAgICAgICAgICAgICAgICAgICBhcHBsaWNhdGlvbklEOiBBcHBJRC5mcm9tVWludDY0KHRoaXMuY3JlYXRpbmdWYWxpZGF0b3JDb250cmFjdEFwcElkLnZhbHVlKSwKCS8vICAgICAgICAgICAgICAgICAgICAgICAgICAgICBtZXRob2RBcmdzOiBbdGhpcy52YWxpZGF0b3JJZC52YWx1ZV0sCgkvLyAgICAgICAgICAgICAgICAgICAgICAgICB9KQoJaXR4bl9iZWdpbgoJaW50IGFwcGwKCWl0eG5fZmllbGQgVHlwZUVudW0KCW1ldGhvZCAiZ2V0VmFsaWRhdG9yQ29uZmlnKHVpbnQ2NCkodWludDY0LGFkZHJlc3MsYWRkcmVzcyx1aW50NjQsdWludDgsYnl0ZVszMl0sdWludDY0LHVpbnQ2NCx1aW50NjQsdWludDE2LHVpbnQzMixhZGRyZXNzLHVpbnQ2NCx1aW50NjQsdWludDgsdWludDY0LHVpbnQ2NCkiCglpdHhuX2ZpZWxkIEFwcGxpY2F0aW9uQXJncwoKCS8vIGNvbnRyYWN0cy9zdGFraW5nUG9vbC5hbGdvLnRzOjI4MgoJLy8gYXBwbGljYXRpb25JRDogQXBwSUQuZnJvbVVpbnQ2NCh0aGlzLmNyZWF0aW5nVmFsaWRhdG9yQ29udHJhY3RBcHBJZC52YWx1ZSkKCWJ5dGUgMHg2MzcyNjU2MTc0NmY3MjQxNzA3MCAvLyAiY3JlYXRvckFwcCIKCWFwcF9nbG9iYWxfZ2V0CglpdHhuX2ZpZWxkIEFwcGxpY2F0aW9uSUQKCgkvLyBjb250cmFjdHMvc3Rha2luZ1Bvb2wuYWxnby50czoyODMKCS8vIG1ldGhvZEFyZ3M6IFt0aGlzLnZhbGlkYXRvcklkLnZhbHVlXQoJYnl0ZSAweDc2NjE2YzY5NjQ2MTc0NmY3MjQ5NjQgLy8gInZhbGlkYXRvcklkIgoJYXBwX2dsb2JhbF9nZXQKCWl0b2IKCWl0eG5fZmllbGQgQXBwbGljYXRpb25BcmdzCgoJLy8gRmVlIGZpZWxkIG5vdCBzZXQsIGRlZmF1bHRpbmcgdG8gMAoJaW50IDAKCWl0eG5fZmllbGQgRmVlCgoJLy8gU3VibWl0IGlubmVyIHRyYW5zYWN0aW9uCglpdHhuX3N1Ym1pdAoJaXR4biBOdW1Mb2dzCglpbnQgMQoJLQoJaXR4bmFzIExvZ3MKCWV4dHJhY3QgNCAwCglmcmFtZV9idXJ5IDQgLy8gdmFsaWRhdG9yQ29uZmlnOiAodWludDY0LGFkZHJlc3MsYWRkcmVzcyx1aW50NjQsdWludDgsYnl0ZVszMl0sdWludDY0LHVpbnQ2NCx1aW50NjQsdWludDE2LHVpbnQzMixhZGRyZXNzLHVpbnQ2NCx1aW50NjQsdWludDgsdWludDY0LHVpbnQ2NCkKCgkvLyBjb250cmFjdHMvc3Rha2luZ1Bvb2wuYWxnby50czoyODkKCS8vIHNlbmRBc3NldFRyYW5zZmVyKHsKCS8vICAgICAgICAgICAgICAgICAgICAgICAgICAgICB4ZmVyQXNzZXQ6IEFzc2V0SUQuZnJvbVVpbnQ2NCh2YWxpZGF0b3JDb25maWcucmV3YXJkVG9rZW5JZCksCgkvLyAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYXNzZXRSZWNlaXZlcjogc3Rha2VyLAoJLy8gICAgICAgICAgICAgICAgICAgICAgICAgICAgIGFzc2V0QW1vdW50OiBjbXBTdGFrZXIucmV3YXJkVG9rZW5CYWxhbmNlLAoJLy8gICAgICAgICAgICAgICAgICAgICAgICAgfSkKCWl0eG5fYmVnaW4KCWludCBheGZlcgoJaXR4bl9maWVsZCBUeXBlRW51bQoKCS8vIGNvbnRyYWN0cy9zdGFraW5nUG9vbC5hbGdvLnRzOjI5MAoJLy8geGZlckFzc2V0OiBBc3NldElELmZyb21VaW50NjQodmFsaWRhdG9yQ29uZmlnLnJld2FyZFRva2VuSWQpCglmcmFtZV9kaWcgNCAvLyB2YWxpZGF0b3JDb25maWc6ICh1aW50NjQsYWRkcmVzcyxhZGRyZXNzLHVpbnQ2NCx1aW50OCxieXRlWzMyXSx1aW50NjQsdWludDY0LHVpbnQ2NCx1aW50MTYsdWludDMyLGFkZHJlc3MsdWludDY0LHVpbnQ2NCx1aW50OCx1aW50NjQsdWludDY0KQoJZXh0cmFjdCAxMjEgOAoJYnRvaQoJaXR4bl9maWVsZCBYZmVyQXNzZXQKCgkvLyBjb250cmFjdHMvc3Rha2luZ1Bvb2wuYWxnby50czoyOTEKCS8vIGFzc2V0UmVjZWl2ZXI6IHN0YWtlcgoJZnJhbWVfZGlnIDAgLy8gc3Rha2VyOiBhZGRyZXNzCglpdHhuX2ZpZWxkIEFzc2V0UmVjZWl2ZXIKCgkvLyBjb250cmFjdHMvc3Rha2luZ1Bvb2wuYWxnby50czoyOTIKCS8vIGFzc2V0QW1vdW50OiBjbXBTdGFrZXIucmV3YXJkVG9rZW5CYWxhbmNlCglmcmFtZV9kaWcgMiAvLyBjbXBTdGFrZXI6IChhZGRyZXNzLHVpbnQ2NCx1aW50NjQsdWludDY0LHVpbnQ2NCkKCWV4dHJhY3QgNDggOAoJYnRvaQoJaXR4bl9maWVsZCBBc3NldEFtb3VudAoKCS8vIEZlZSBmaWVsZCBub3Qgc2V0LCBkZWZhdWx0aW5nIHRvIDAKCWludCAwCglpdHhuX2ZpZWxkIEZlZQoKCS8vIFN1Ym1pdCBpbm5lciB0cmFuc2FjdGlvbgoJaXR4bl9zdWJtaXQKCgkvLyBjb250cmFjdHMvc3Rha2luZ1Bvb2wuYWxnby50czoyOTQKCS8vIGFtb3VudFJld2FyZFRva2VuUmVtb3ZlZCA9IGNtcFN0YWtlci5yZXdhcmRUb2tlbkJhbGFuY2UKCWZyYW1lX2RpZyAyIC8vIGNtcFN0YWtlcjogKGFkZHJlc3MsdWludDY0LHVpbnQ2NCx1aW50NjQsdWludDY0KQoJZXh0cmFjdCA0OCA4CglidG9pCglmcmFtZV9idXJ5IDMgLy8gYW1vdW50UmV3YXJkVG9rZW5SZW1vdmVkOiB1aW50NjQKCgkvLyBjb250cmFjdHMvc3Rha2luZ1Bvb2wuYWxnby50czoyOTUKCS8vIGNtcFN0YWtlci5yZXdhcmRUb2tlbkJhbGFuY2UgPSAwCglmcmFtZV9kaWcgMiAvLyBjbXBTdGFrZXI6IChhZGRyZXNzLHVpbnQ2NCx1aW50NjQsdWludDY0LHVpbnQ2NCkKCWJ5dGUgMHgwMDAwMDAwMDAwMDAwMDAwCglyZXBsYWNlMiA0OAoJZnJhbWVfYnVyeSAyIC8vIGNtcFN0YWtlcjogKGFkZHJlc3MsdWludDY0LHVpbnQ2NCx1aW50NjQsdWludDY0KQoJYiAqaWYxMV9lbmQKCippZjExX2Vsc2U6CgkvLyBjb250cmFjdHMvc3Rha2luZ1Bvb2wuYWxnby50czozMDAKCS8vIGFtb3VudFJld2FyZFRva2VuUmVtb3ZlZCA9IGNtcFN0YWtlci5yZXdhcmRUb2tlbkJhbGFuY2UKCWZyYW1lX2RpZyAyIC8vIGNtcFN0YWtlcjogKGFkZHJlc3MsdWludDY0LHVpbnQ2NCx1aW50NjQsdWludDY0KQoJZXh0cmFjdCA0OCA4CglidG9pCglmcmFtZV9idXJ5IDMgLy8gYW1vdW50UmV3YXJkVG9rZW5SZW1vdmVkOiB1aW50NjQKCgkvLyBjb250cmFjdHMvc3Rha2luZ1Bvb2wuYWxnby50czozMDEKCS8vIGNtcFN0YWtlci5yZXdhcmRUb2tlbkJhbGFuY2UgPSAwCglmcmFtZV9kaWcgMiAvLyBjbXBTdGFrZXI6IChhZGRyZXNzLHVpbnQ2NCx1aW50NjQsdWludDY0LHVpbnQ2NCkKCWJ5dGUgMHgwMDAwMDAwMDAwMDAwMDAwCglyZXBsYWNlMiA0OAoJZnJhbWVfYnVyeSAyIC8vIGNtcFN0YWtlcjogKGFkZHJlc3MsdWludDY0LHVpbnQ2NCx1aW50NjQsdWludDY0KQoKKmlmMTFfZW5kOgoKKmlmMTBfZW5kOgoJLy8gY29udHJhY3RzL3N0YWtpbmdQb29sLmFsZ28udHM6MzA2CgkvLyBhc3NlcnQoCgkvLyAgICAgICAgICAgICAgICAgICAgIGNtcFN0YWtlci5iYWxhbmNlID09PSAwIHx8IGNtcFN0YWtlci5iYWxhbmNlID49IHRoaXMubWluRW50cnlTdGFrZS52YWx1ZSwKCS8vICAgICAgICAgICAgICAgICAgICAgJ2Nhbm5vdCByZWR1Y2UgYmFsYW5jZSBiZWxvdyBtaW5pbXVtIGFsbG93ZWQgc3Rha2UgdW5sZXNzIGFsbCBpcyByZW1vdmVkJwoJLy8gICAgICAgICAgICAgICAgICkKCWZyYW1lX2RpZyAyIC8vIGNtcFN0YWtlcjogKGFkZHJlc3MsdWludDY0LHVpbnQ2NCx1aW50NjQsdWludDY0KQoJZXh0cmFjdCAzMiA4CglidG9pCglpbnQgMAoJPT0KCWR1cAoJYm56ICpza2lwX29yMAoJZnJhbWVfZGlnIDIgLy8gY21wU3Rha2VyOiAoYWRkcmVzcyx1aW50NjQsdWludDY0LHVpbnQ2NCx1aW50NjQpCglleHRyYWN0IDMyIDgKCWJ0b2kKCWJ5dGUgMHg2ZDY5NmU0NTZlNzQ3Mjc5NTM3NDYxNmI2NSAvLyAibWluRW50cnlTdGFrZSIKCWFwcF9nbG9iYWxfZ2V0Cgk+PQoJfHwKCipza2lwX29yMDoKCS8vIGNhbm5vdCByZWR1Y2UgYmFsYW5jZSBiZWxvdyBtaW5pbXVtIGFsbG93ZWQgc3Rha2UgdW5sZXNzIGFsbCBpcyByZW1vdmVkCglhc3NlcnQKCgkvLyBjb250cmFjdHMvc3Rha2luZ1Bvb2wuYWxnby50czozMTQKCS8vIHNlbmRQYXltZW50KHsKCS8vICAgICAgICAgICAgICAgICAgICAgYW1vdW50OiBhbW91bnRUb1Vuc3Rha2UsCgkvLyAgICAgICAgICAgICAgICAgICAgIHJlY2VpdmVyOiBzdGFrZXIsCgkvLyAgICAgICAgICAgICAgICAgICAgIG5vdGU6ICd1bnN0YWtlZCcsCgkvLyAgICAgICAgICAgICAgICAgfSkKCWl0eG5fYmVnaW4KCWludCBwYXkKCWl0eG5fZmllbGQgVHlwZUVudW0KCgkvLyBjb250cmFjdHMvc3Rha2luZ1Bvb2wuYWxnby50czozMTUKCS8vIGFtb3VudDogYW1vdW50VG9VbnN0YWtlCglmcmFtZV9kaWcgLTEgLy8gYW1vdW50VG9VbnN0YWtlOiB1aW50NjQKCWl0eG5fZmllbGQgQW1vdW50CgoJLy8gY29udHJhY3RzL3N0YWtpbmdQb29sLmFsZ28udHM6MzE2CgkvLyByZWNlaXZlcjogc3Rha2VyCglmcmFtZV9kaWcgMCAvLyBzdGFrZXI6IGFkZHJlc3MKCWl0eG5fZmllbGQgUmVjZWl2ZXIKCgkvLyBjb250cmFjdHMvc3Rha2luZ1Bvb2wuYWxnby50czozMTcKCS8vIG5vdGU6ICd1bnN0YWtlZCcKCWJ5dGUgMHg3NTZlNzM3NDYxNmI2NTY0IC8vICJ1bnN0YWtlZCIKCWl0eG5fZmllbGQgTm90ZQoKCS8vIEZlZSBmaWVsZCBub3Qgc2V0LCBkZWZhdWx0aW5nIHRvIDAKCWludCAwCglpdHhuX2ZpZWxkIEZlZQoKCS8vIFN1Ym1pdCBpbm5lciB0cmFuc2FjdGlvbgoJaXR4bl9zdWJtaXQKCgkvLyBjb250cmFjdHMvc3Rha2luZ1Bvb2wuYWxnby50czozMTkKCS8vIHN0YWtlclJlbW92ZWQgPSBmYWxzZQoJaW50IDAKCWZyYW1lX2J1cnkgNSAvLyBzdGFrZXJSZW1vdmVkOiBib29sCgoJLy8gKmlmMTJfY29uZGl0aW9uCgkvLyBjb250cmFjdHMvc3Rha2luZ1Bvb2wuYWxnby50czozMjAKCS8vIGNtcFN0YWtlci5iYWxhbmNlID09PSAwCglmcmFtZV9kaWcgMiAvLyBjbXBTdGFrZXI6IChhZGRyZXNzLHVpbnQ2NCx1aW50NjQsdWludDY0LHVpbnQ2NCkKCWV4dHJhY3QgMzIgOAoJYnRvaQoJaW50IDAKCT09CglieiAqaWYxMl9lbmQKCgkvLyAqaWYxMl9jb25zZXF1ZW50CgkvLyBjb250cmFjdHMvc3Rha2luZ1Bvb2wuYWxnby50czozMjIKCS8vIHRoaXMubnVtU3Rha2Vycy52YWx1ZSAtPSAxCglieXRlIDB4NmU3NTZkNTM3NDYxNmI2NTcyNzMgLy8gIm51bVN0YWtlcnMiCglhcHBfZ2xvYmFsX2dldAoJaW50IDEKCS0KCWJ5dGUgMHg2ZTc1NmQ1Mzc0NjE2YjY1NzI3MyAvLyAibnVtU3Rha2VycyIKCXN3YXAKCWFwcF9nbG9iYWxfcHV0CgoJLy8gY29udHJhY3RzL3N0YWtpbmdQb29sLmFsZ28udHM6MzIzCgkvLyBjbXBTdGFrZXIuYWNjb3VudCA9IGdsb2JhbHMuemVyb0FkZHJlc3MKCWZyYW1lX2RpZyAyIC8vIGNtcFN0YWtlcjogKGFkZHJlc3MsdWludDY0LHVpbnQ2NCx1aW50NjQsdWludDY0KQoJaW50IDAKCWdsb2JhbCBaZXJvQWRkcmVzcwoJcmVwbGFjZTMKCWZyYW1lX2J1cnkgMiAvLyBjbXBTdGFrZXI6IChhZGRyZXNzLHVpbnQ2NCx1aW50NjQsdWludDY0LHVpbnQ2NCkKCgkvLyBjb250cmFjdHMvc3Rha2luZ1Bvb2wuYWxnby50czozMjQKCS8vIGNtcFN0YWtlci50b3RhbFJld2FyZGVkID0gMAoJZnJhbWVfZGlnIDIgLy8gY21wU3Rha2VyOiAoYWRkcmVzcyx1aW50NjQsdWludDY0LHVpbnQ2NCx1aW50NjQpCglieXRlIDB4MDAwMDAwMDAwMDAwMDAwMAoJcmVwbGFjZTIgNDAKCWZyYW1lX2J1cnkgMiAvLyBjbXBTdGFrZXI6IChhZGRyZXNzLHVpbnQ2NCx1aW50NjQsdWludDY0LHVpbnQ2NCkKCgkvLyBjb250cmFjdHMvc3Rha2luZ1Bvb2wuYWxnby50czozMjUKCS8vIGNtcFN0YWtlci5yZXdhcmRUb2tlbkJhbGFuY2UgPSAwCglmcmFtZV9kaWcgMiAvLyBjbXBTdGFrZXI6IChhZGRyZXNzLHVpbnQ2NCx1aW50NjQsdWludDY0LHVpbnQ2NCkKCWJ5dGUgMHgwMDAwMDAwMDAwMDAwMDAwCglyZXBsYWNlMiA0OAoJZnJhbWVfYnVyeSAyIC8vIGNtcFN0YWtlcjogKGFkZHJlc3MsdWludDY0LHVpbnQ2NCx1aW50NjQsdWludDY0KQoKCS8vIGNvbnRyYWN0cy9zdGFraW5nUG9vbC5hbGdvLnRzOjMyNgoJLy8gc3Rha2VyUmVtb3ZlZCA9IHRydWUKCWludCAxCglmcmFtZV9idXJ5IDUgLy8gc3Rha2VyUmVtb3ZlZDogYm9vbAoKKmlmMTJfZW5kOgoJLy8gY29udHJhY3RzL3N0YWtpbmdQb29sLmFsZ28udHM6MzI5CgkvLyB0aGlzLnN0YWtlcnMudmFsdWVbaV0gPSBjbXBTdGFrZXIKCWZyYW1lX2RpZyAxIC8vIGk6IHVpbnQ2NAoJaW50IDY0CgkqIC8vIGFjYyAqIHR5cGVMZW5ndGgKCWZyYW1lX2RpZyAyIC8vIGNtcFN0YWtlcjogKGFkZHJlc3MsdWludDY0LHVpbnQ2NCx1aW50NjQsdWludDY0KQoJYnl0ZSAweDczNzQ2MTZiNjU3MjczIC8vICJzdGFrZXJzIgoJY292ZXIgMgoJYm94X3JlcGxhY2UKCgkvLyBjb250cmFjdHMvc3Rha2luZ1Bvb2wuYWxnby50czozMzQKCS8vIHNlbmRNZXRob2RDYWxsPHR5cGVvZiBWYWxpZGF0b3JSZWdpc3RyeS5wcm90b3R5cGUuc3Rha2VSZW1vdmVkPih7CgkvLyAgICAgICAgICAgICAgICAgICAgIGFwcGxpY2F0aW9uSUQ6IEFwcElELmZyb21VaW50NjQodGhpcy5jcmVhdGluZ1ZhbGlkYXRvckNvbnRyYWN0QXBwSWQudmFsdWUpLAoJLy8gICAgICAgICAgICAgICAgICAgICBtZXRob2RBcmdzOiBbCgkvLyAgICAgICAgICAgICAgICAgICAgICAgICB7IGlkOiB0aGlzLnZhbGlkYXRvcklkLnZhbHVlLCBwb29sSWQ6IHRoaXMucG9vbElkLnZhbHVlLCBwb29sQXBwSWQ6IHRoaXMuYXBwLmlkIH0sCgkvLyAgICAgICAgICAgICAgICAgICAgICAgICBzdGFrZXIsCgkvLyAgICAgICAgICAgICAgICAgICAgICAgICBhbW91bnRUb1Vuc3Rha2UsCgkvLyAgICAgICAgICAgICAgICAgICAgICAgICBhbW91bnRSZXdhcmRUb2tlblJlbW92ZWQsCgkvLyAgICAgICAgICAgICAgICAgICAgICAgICBzdGFrZXJSZW1vdmVkLAoJLy8gICAgICAgICAgICAgICAgICAgICBdLAoJLy8gICAgICAgICAgICAgICAgIH0pCglpdHhuX2JlZ2luCglpbnQgYXBwbAoJaXR4bl9maWVsZCBUeXBlRW51bQoJbWV0aG9kICJzdGFrZVJlbW92ZWQoKHVpbnQ2NCx1aW50NjQsdWludDY0KSxhZGRyZXNzLHVpbnQ2NCx1aW50NjQsYm9vbCl2b2lkIgoJaXR4bl9maWVsZCBBcHBsaWNhdGlvbkFyZ3MKCgkvLyBjb250cmFjdHMvc3Rha2luZ1Bvb2wuYWxnby50czozMzUKCS8vIGFwcGxpY2F0aW9uSUQ6IEFwcElELmZyb21VaW50NjQodGhpcy5jcmVhdGluZ1ZhbGlkYXRvckNvbnRyYWN0QXBwSWQudmFsdWUpCglieXRlIDB4NjM3MjY1NjE3NDZmNzI0MTcwNzAgLy8gImNyZWF0b3JBcHAiCglhcHBfZ2xvYmFsX2dldAoJaXR4bl9maWVsZCBBcHBsaWNhdGlvbklECgoJLy8gY29udHJhY3RzL3N0YWtpbmdQb29sLmFsZ28udHM6MzM2CgkvLyBtZXRob2RBcmdzOiBbCgkvLyAgICAgICAgICAgICAgICAgICAgICAgICB7IGlkOiB0aGlzLnZhbGlkYXRvcklkLnZhbHVlLCBwb29sSWQ6IHRoaXMucG9vbElkLnZhbHVlLCBwb29sQXBwSWQ6IHRoaXMuYXBwLmlkIH0sCgkvLyAgICAgICAgICAgICAgICAgICAgICAgICBzdGFrZXIsCgkvLyAgICAgICAgICAgICAgICAgICAgICAgICBhbW91bnRUb1Vuc3Rha2UsCgkvLyAgICAgICAgICAgICAgICAgICAgICAgICBhbW91bnRSZXdhcmRUb2tlblJlbW92ZWQsCgkvLyAgICAgICAgICAgICAgICAgICAgICAgICBzdGFrZXJSZW1vdmVkLAoJLy8gICAgICAgICAgICAgICAgICAgICBdCglieXRlIDB4NzY2MTZjNjk2NDYxNzQ2ZjcyNDk2NCAvLyAidmFsaWRhdG9ySWQiCglhcHBfZ2xvYmFsX2dldAoJaXRvYgoJYnl0ZSAweDcwNmY2ZjZjNDk2NCAvLyAicG9vbElkIgoJYXBwX2dsb2JhbF9nZXQKCWl0b2IKCWNvbmNhdAoJdHhuYSBBcHBsaWNhdGlvbnMgMAoJaXRvYgoJY29uY2F0CglpdHhuX2ZpZWxkIEFwcGxpY2F0aW9uQXJncwoJZnJhbWVfZGlnIDAgLy8gc3Rha2VyOiBhZGRyZXNzCglpdHhuX2ZpZWxkIEFwcGxpY2F0aW9uQXJncwoJZnJhbWVfZGlnIC0xIC8vIGFtb3VudFRvVW5zdGFrZTogdWludDY0CglpdG9iCglpdHhuX2ZpZWxkIEFwcGxpY2F0aW9uQXJncwoJZnJhbWVfZGlnIDMgLy8gYW1vdW50UmV3YXJkVG9rZW5SZW1vdmVkOiB1aW50NjQKCWl0b2IKCWl0eG5fZmllbGQgQXBwbGljYXRpb25BcmdzCglmcmFtZV9kaWcgNSAvLyBzdGFrZXJSZW1vdmVkOiBib29sCglieXRlIDB4MDAKCWludCAwCgl1bmNvdmVyIDIKCXNldGJpdAoJaXR4bl9maWVsZCBBcHBsaWNhdGlvbkFyZ3MKCgkvLyBGZWUgZmllbGQgbm90IHNldCwgZGVmYXVsdGluZyB0byAwCglpbnQgMAoJaXR4bl9maWVsZCBGZWUKCgkvLyBTdWJtaXQgaW5uZXIgdHJhbnNhY3Rpb24KCWl0eG5fc3VibWl0CgoJLy8gY29udHJhY3RzL3N0YWtpbmdQb29sLmFsZ28udHM6MzQ0CgkvLyByZXR1cm47CglyZXRzdWIKCippZjdfZW5kOgoKKmZvcl8xX2NvbnRpbnVlOgoJLy8gY29udHJhY3RzL3N0YWtpbmdQb29sLmFsZ28udHM6MjYxCgkvLyBpICs9IDEKCWZyYW1lX2RpZyAxIC8vIGk6IHVpbnQ2NAoJaW50IDEKCSsKCWZyYW1lX2J1cnkgMSAvLyBpOiB1aW50NjQKCWIgKmZvcl8xCgoqZm9yXzFfZW5kOgoJZXJyIC8vICdhY2NvdW50IG5vdCBmb3VuZCcKCi8vIGNsYWltVG9rZW5zKCl2b2lkCiphYmlfcm91dGVfY2xhaW1Ub2tlbnM6CgkvLyBleGVjdXRlIGNsYWltVG9rZW5zKCl2b2lkCgljYWxsc3ViIGNsYWltVG9rZW5zCglpbnQgMQoJcmV0dXJuCgovLyBjbGFpbVRva2VucygpOiB2b2lkCi8vCi8vIENsYWltcyBhbGwgdGhlIGF2YWlsYWJsZSByZXdhcmQgdG9rZW5zIGEgc3Rha2VyIGhhcyBhdmFpbGFibGUsIHNlbmRpbmcgdGhlaXIgZW50aXJlIGJhbGFuY2UgdG8gdGhlIHN0YWtlciBmcm9tCi8vIHBvb2wgMSAoZWl0aGVyIGRpcmVjdGx5LCBvciB2aWEgdmFsaWRhdG9yLT5wb29sMSB0byBwYXkgaXQgb3V0KQovLyBBbHNvIG5vdGlmaWVzIHRoZSB2YWxpZGF0b3IgY29udHJhY3QgZm9yIHRoaXMgcG9vbHMgdmFsaWRhdG9yIG9mIHRoZSBzdGFrZXIgLyBiYWxhbmNlIGNoYW5nZXMuCmNsYWltVG9rZW5zOgoJcHJvdG8gMCAwCgoJLy8gUHVzaCBlbXB0eSBieXRlcyBhZnRlciB0aGUgZnJhbWUgcG9pbnRlciB0byByZXNlcnZlIHNwYWNlIGZvciBsb2NhbCB2YXJpYWJsZXMKCWJ5dGUgMHgKCWR1cG4gNAoKCS8vIGNvbnRyYWN0cy9zdGFraW5nUG9vbC5hbGdvLnRzOjM1OQoJLy8gc3Rha2VyID0gdGhpcy50eG4uc2VuZGVyCgl0eG4gU2VuZGVyCglmcmFtZV9idXJ5IDAgLy8gc3Rha2VyOiBhZGRyZXNzCgoJLy8gY29udHJhY3RzL3N0YWtpbmdQb29sLmFsZ28udHM6MzYxCgkvLyBmb3IgKGxldCBpID0gMDsgaSA8IHRoaXMuc3Rha2Vycy52YWx1ZS5sZW5ndGg7IGkgKz0gMSkKCWludCAwCglmcmFtZV9idXJ5IDEgLy8gaTogdWludDY0CgoqZm9yXzI6CgkvLyBjb250cmFjdHMvc3Rha2luZ1Bvb2wuYWxnby50czozNjEKCS8vIGkgPCB0aGlzLnN0YWtlcnMudmFsdWUubGVuZ3RoCglmcmFtZV9kaWcgMSAvLyBpOiB1aW50NjQKCWludCAyMDAKCTwKCWJ6ICpmb3JfMl9lbmQKCgkvLyAqaWYxM19jb25kaXRpb24KCS8vIGNvbnRyYWN0cy9zdGFraW5nUG9vbC5hbGdvLnRzOjM2MgoJLy8gZ2xvYmFscy5vcGNvZGVCdWRnZXQgPCAzMDAKCWdsb2JhbCBPcGNvZGVCdWRnZXQKCWludCAzMDAKCTwKCWJ6ICppZjEzX2VuZAoKCS8vICppZjEzX2NvbnNlcXVlbnQKCS8vIGNvbnRyYWN0cy9zdGFraW5nUG9vbC5hbGdvLnRzOjM2MwoJLy8gaW5jcmVhc2VPcGNvZGVCdWRnZXQoKQoJaXR4bl9iZWdpbgoJaW50IGFwcGwKCWl0eG5fZmllbGQgVHlwZUVudW0KCWludCAwCglpdHhuX2ZpZWxkIEZlZQoJYnl0ZSBiNjQgQ29FQiAvLyAjcHJhZ21hIHZlcnNpb24gMTA7IGludCAxCglkdXAKCWl0eG5fZmllbGQgQXBwcm92YWxQcm9ncmFtCglpdHhuX2ZpZWxkIENsZWFyU3RhdGVQcm9ncmFtCglpbnQgRGVsZXRlQXBwbGljYXRpb24KCWl0eG5fZmllbGQgT25Db21wbGV0aW9uCglpdHhuX3N1Ym1pdAoKKmlmMTNfZW5kOgoJLy8gY29udHJhY3RzL3N0YWtpbmdQb29sLmFsZ28udHM6MzY1CgkvLyBjbXBTdGFrZXIgPSBjbG9uZSh0aGlzLnN0YWtlcnMudmFsdWVbaV0pCglmcmFtZV9kaWcgMSAvLyBpOiB1aW50NjQKCWludCA2NAoJKiAvLyBhY2MgKiB0eXBlTGVuZ3RoCglpbnQgNjQKCWJ5dGUgMHg3Mzc0NjE2YjY1NzI3MyAvLyAic3Rha2VycyIKCWNvdmVyIDIKCWJveF9leHRyYWN0CglmcmFtZV9idXJ5IDIgLy8gY21wU3Rha2VyOiAoYWRkcmVzcyx1aW50NjQsdWludDY0LHVpbnQ2NCx1aW50NjQpCgoJLy8gKmlmMTRfY29uZGl0aW9uCgkvLyBjb250cmFjdHMvc3Rha2luZ1Bvb2wuYWxnby50czozNjYKCS8vIGNtcFN0YWtlci5hY2NvdW50ID09PSBzdGFrZXIKCWZyYW1lX2RpZyAyIC8vIGNtcFN0YWtlcjogKGFkZHJlc3MsdWludDY0LHVpbnQ2NCx1aW50NjQsdWludDY0KQoJZXh0cmFjdCAwIDMyCglmcmFtZV9kaWcgMCAvLyBzdGFrZXI6IGFkZHJlc3MKCT09CglieiAqaWYxNF9lbmQKCgkvLyAqaWYxNF9jb25zZXF1ZW50CgkvLyAqaWYxNV9jb25kaXRpb24KCS8vIGNvbnRyYWN0cy9zdGFraW5nUG9vbC5hbGdvLnRzOjM2NwoJLy8gY21wU3Rha2VyLnJld2FyZFRva2VuQmFsYW5jZSA9PT0gMAoJZnJhbWVfZGlnIDIgLy8gY21wU3Rha2VyOiAoYWRkcmVzcyx1aW50NjQsdWludDY0LHVpbnQ2NCx1aW50NjQpCglleHRyYWN0IDQ4IDgKCWJ0b2kKCWludCAwCgk9PQoJYnogKmlmMTVfZW5kCgoJLy8gKmlmMTVfY29uc2VxdWVudAoJLy8gY29udHJhY3RzL3N0YWtpbmdQb29sLmFsZ28udHM6MzY4CgkvLyByZXR1cm47CglyZXRzdWIKCippZjE1X2VuZDoKCS8vIGNvbnRyYWN0cy9zdGFraW5nUG9vbC5hbGdvLnRzOjM3MAoJLy8gYW1vdW50UmV3YXJkVG9rZW5SZW1vdmVkID0gMAoJaW50IDAKCWZyYW1lX2J1cnkgMyAvLyBhbW91bnRSZXdhcmRUb2tlblJlbW92ZWQ6IHVpbnQ2NAoKCS8vICppZjE2X2NvbmRpdGlvbgoJLy8gY29udHJhY3RzL3N0YWtpbmdQb29sLmFsZ28udHM6MzcyCgkvLyB0aGlzLnBvb2xJZC52YWx1ZSA9PT0gMQoJYnl0ZSAweDcwNmY2ZjZjNDk2NCAvLyAicG9vbElkIgoJYXBwX2dsb2JhbF9nZXQKCWludCAxCgk9PQoJYnogKmlmMTZfZWxzZQoKCS8vICppZjE2X2NvbnNlcXVlbnQKCS8vIGNvbnRyYWN0cy9zdGFraW5nUG9vbC5hbGdvLnRzOjM3MwoJLy8gdmFsaWRhdG9yQ29uZmlnID0gc2VuZE1ldGhvZENhbGw8dHlwZW9mIFZhbGlkYXRvclJlZ2lzdHJ5LnByb3RvdHlwZS5nZXRWYWxpZGF0b3JDb25maWc+KHsKCS8vICAgICAgICAgICAgICAgICAgICAgICAgIGFwcGxpY2F0aW9uSUQ6IEFwcElELmZyb21VaW50NjQodGhpcy5jcmVhdGluZ1ZhbGlkYXRvckNvbnRyYWN0QXBwSWQudmFsdWUpLAoJLy8gICAgICAgICAgICAgICAgICAgICAgICAgbWV0aG9kQXJnczogW3RoaXMudmFsaWRhdG9ySWQudmFsdWVdLAoJLy8gICAgICAgICAgICAgICAgICAgICB9KQoJaXR4bl9iZWdpbgoJaW50IGFwcGwKCWl0eG5fZmllbGQgVHlwZUVudW0KCW1ldGhvZCAiZ2V0VmFsaWRhdG9yQ29uZmlnKHVpbnQ2NCkodWludDY0LGFkZHJlc3MsYWRkcmVzcyx1aW50NjQsdWludDgsYnl0ZVszMl0sdWludDY0LHVpbnQ2NCx1aW50NjQsdWludDE2LHVpbnQzMixhZGRyZXNzLHVpbnQ2NCx1aW50NjQsdWludDgsdWludDY0LHVpbnQ2NCkiCglpdHhuX2ZpZWxkIEFwcGxpY2F0aW9uQXJncwoKCS8vIGNvbnRyYWN0cy9zdGFraW5nUG9vbC5hbGdvLnRzOjM3NAoJLy8gYXBwbGljYXRpb25JRDogQXBwSUQuZnJvbVVpbnQ2NCh0aGlzLmNyZWF0aW5nVmFsaWRhdG9yQ29udHJhY3RBcHBJZC52YWx1ZSkKCWJ5dGUgMHg2MzcyNjU2MTc0NmY3MjQxNzA3MCAvLyAiY3JlYXRvckFwcCIKCWFwcF9nbG9iYWxfZ2V0CglpdHhuX2ZpZWxkIEFwcGxpY2F0aW9uSUQKCgkvLyBjb250cmFjdHMvc3Rha2luZ1Bvb2wuYWxnby50czozNzUKCS8vIG1ldGhvZEFyZ3M6IFt0aGlzLnZhbGlkYXRvcklkLnZhbHVlXQoJYnl0ZSAweDc2NjE2YzY5NjQ2MTc0NmY3MjQ5NjQgLy8gInZhbGlkYXRvcklkIgoJYXBwX2dsb2JhbF9nZXQKCWl0b2IKCWl0eG5fZmllbGQgQXBwbGljYXRpb25BcmdzCgoJLy8gRmVlIGZpZWxkIG5vdCBzZXQsIGRlZmF1bHRpbmcgdG8gMAoJaW50IDAKCWl0eG5fZmllbGQgRmVlCgoJLy8gU3VibWl0IGlubmVyIHRyYW5zYWN0aW9uCglpdHhuX3N1Ym1pdAoJaXR4biBOdW1Mb2dzCglpbnQgMQoJLQoJaXR4bmFzIExvZ3MKCWV4dHJhY3QgNCAwCglmcmFtZV9idXJ5IDQgLy8gdmFsaWRhdG9yQ29uZmlnOiAodWludDY0LGFkZHJlc3MsYWRkcmVzcyx1aW50NjQsdWludDgsYnl0ZVszMl0sdWludDY0LHVpbnQ2NCx1aW50NjQsdWludDE2LHVpbnQzMixhZGRyZXNzLHVpbnQ2NCx1aW50NjQsdWludDgsdWludDY0LHVpbnQ2NCkKCgkvLyBjb250cmFjdHMvc3Rha2luZ1Bvb2wuYWxnby50czozODAKCS8vIHNlbmRBc3NldFRyYW5zZmVyKHsKCS8vICAgICAgICAgICAgICAgICAgICAgICAgIHhmZXJBc3NldDogQXNzZXRJRC5mcm9tVWludDY0KHZhbGlkYXRvckNvbmZpZy5yZXdhcmRUb2tlbklkKSwKCS8vICAgICAgICAgICAgICAgICAgICAgICAgIGFzc2V0UmVjZWl2ZXI6IHN0YWtlciwKCS8vICAgICAgICAgICAgICAgICAgICAgICAgIGFzc2V0QW1vdW50OiBjbXBTdGFrZXIucmV3YXJkVG9rZW5CYWxhbmNlLAoJLy8gICAgICAgICAgICAgICAgICAgICB9KQoJaXR4bl9iZWdpbgoJaW50IGF4ZmVyCglpdHhuX2ZpZWxkIFR5cGVFbnVtCgoJLy8gY29udHJhY3RzL3N0YWtpbmdQb29sLmFsZ28udHM6MzgxCgkvLyB4ZmVyQXNzZXQ6IEFzc2V0SUQuZnJvbVVpbnQ2NCh2YWxpZGF0b3JDb25maWcucmV3YXJkVG9rZW5JZCkKCWZyYW1lX2RpZyA0IC8vIHZhbGlkYXRvckNvbmZpZzogKHVpbnQ2NCxhZGRyZXNzLGFkZHJlc3MsdWludDY0LHVpbnQ4LGJ5dGVbMzJdLHVpbnQ2NCx1aW50NjQsdWludDY0LHVpbnQxNix1aW50MzIsYWRkcmVzcyx1aW50NjQsdWludDY0LHVpbnQ4LHVpbnQ2NCx1aW50NjQpCglleHRyYWN0IDEyMSA4CglidG9pCglpdHhuX2ZpZWxkIFhmZXJBc3NldAoKCS8vIGNvbnRyYWN0cy9zdGFraW5nUG9vbC5hbGdvLnRzOjM4MgoJLy8gYXNzZXRSZWNlaXZlcjogc3Rha2VyCglmcmFtZV9kaWcgMCAvLyBzdGFrZXI6IGFkZHJlc3MKCWl0eG5fZmllbGQgQXNzZXRSZWNlaXZlcgoKCS8vIGNvbnRyYWN0cy9zdGFraW5nUG9vbC5hbGdvLnRzOjM4MwoJLy8gYXNzZXRBbW91bnQ6IGNtcFN0YWtlci5yZXdhcmRUb2tlbkJhbGFuY2UKCWZyYW1lX2RpZyAyIC8vIGNtcFN0YWtlcjogKGFkZHJlc3MsdWludDY0LHVpbnQ2NCx1aW50NjQsdWludDY0KQoJZXh0cmFjdCA0OCA4CglidG9pCglpdHhuX2ZpZWxkIEFzc2V0QW1vdW50CgoJLy8gRmVlIGZpZWxkIG5vdCBzZXQsIGRlZmF1bHRpbmcgdG8gMAoJaW50IDAKCWl0eG5fZmllbGQgRmVlCgoJLy8gU3VibWl0IGlubmVyIHRyYW5zYWN0aW9uCglpdHhuX3N1Ym1pdAoKCS8vIGNvbnRyYWN0cy9zdGFraW5nUG9vbC5hbGdvLnRzOjM4NQoJLy8gYW1vdW50UmV3YXJkVG9rZW5SZW1vdmVkID0gY21wU3Rha2VyLnJld2FyZFRva2VuQmFsYW5jZQoJZnJhbWVfZGlnIDIgLy8gY21wU3Rha2VyOiAoYWRkcmVzcyx1aW50NjQsdWludDY0LHVpbnQ2NCx1aW50NjQpCglleHRyYWN0IDQ4IDgKCWJ0b2kKCWZyYW1lX2J1cnkgMyAvLyBhbW91bnRSZXdhcmRUb2tlblJlbW92ZWQ6IHVpbnQ2NAoKCS8vIGNvbnRyYWN0cy9zdGFraW5nUG9vbC5hbGdvLnRzOjM4NgoJLy8gY21wU3Rha2VyLnJld2FyZFRva2VuQmFsYW5jZSA9IDAKCWZyYW1lX2RpZyAyIC8vIGNtcFN0YWtlcjogKGFkZHJlc3MsdWludDY0LHVpbnQ2NCx1aW50NjQsdWludDY0KQoJYnl0ZSAweDAwMDAwMDAwMDAwMDAwMDAKCXJlcGxhY2UyIDQ4CglmcmFtZV9idXJ5IDIgLy8gY21wU3Rha2VyOiAoYWRkcmVzcyx1aW50NjQsdWludDY0LHVpbnQ2NCx1aW50NjQpCgliICppZjE2X2VuZAoKKmlmMTZfZWxzZToKCS8vIGNvbnRyYWN0cy9zdGFraW5nUG9vbC5hbGdvLnRzOjM5MQoJLy8gYW1vdW50UmV3YXJkVG9rZW5SZW1vdmVkID0gY21wU3Rha2VyLnJld2FyZFRva2VuQmFsYW5jZQoJZnJhbWVfZGlnIDIgLy8gY21wU3Rha2VyOiAoYWRkcmVzcyx1aW50NjQsdWludDY0LHVpbnQ2NCx1aW50NjQpCglleHRyYWN0IDQ4IDgKCWJ0b2kKCWZyYW1lX2J1cnkgMyAvLyBhbW91bnRSZXdhcmRUb2tlblJlbW92ZWQ6IHVpbnQ2NAoKCS8vIGNvbnRyYWN0cy9zdGFraW5nUG9vbC5hbGdvLnRzOjM5MgoJLy8gY21wU3Rha2VyLnJld2FyZFRva2VuQmFsYW5jZSA9IDAKCWZyYW1lX2RpZyAyIC8vIGNtcFN0YWtlcjogKGFkZHJlc3MsdWludDY0LHVpbnQ2NCx1aW50NjQsdWludDY0KQoJYnl0ZSAweDAwMDAwMDAwMDAwMDAwMDAKCXJlcGxhY2UyIDQ4CglmcmFtZV9idXJ5IDIgLy8gY21wU3Rha2VyOiAoYWRkcmVzcyx1aW50NjQsdWludDY0LHVpbnQ2NCx1aW50NjQpCgoqaWYxNl9lbmQ6CgkvLyBjb250cmFjdHMvc3Rha2luZ1Bvb2wuYWxnby50czozOTYKCS8vIHRoaXMuc3Rha2Vycy52YWx1ZVtpXSA9IGNtcFN0YWtlcgoJZnJhbWVfZGlnIDEgLy8gaTogdWludDY0CglpbnQgNjQKCSogLy8gYWNjICogdHlwZUxlbmd0aAoJZnJhbWVfZGlnIDIgLy8gY21wU3Rha2VyOiAoYWRkcmVzcyx1aW50NjQsdWludDY0LHVpbnQ2NCx1aW50NjQpCglieXRlIDB4NzM3NDYxNmI2NTcyNzMgLy8gInN0YWtlcnMiCgljb3ZlciAyCglib3hfcmVwbGFjZQoKCS8vIGNvbnRyYWN0cy9zdGFraW5nUG9vbC5hbGdvLnRzOjQwMQoJLy8gc2VuZE1ldGhvZENhbGw8dHlwZW9mIFZhbGlkYXRvclJlZ2lzdHJ5LnByb3RvdHlwZS5zdGFrZVJlbW92ZWQ+KHsKCS8vICAgICAgICAgICAgICAgICAgICAgYXBwbGljYXRpb25JRDogQXBwSUQuZnJvbVVpbnQ2NCh0aGlzLmNyZWF0aW5nVmFsaWRhdG9yQ29udHJhY3RBcHBJZC52YWx1ZSksCgkvLyAgICAgICAgICAgICAgICAgICAgIG1ldGhvZEFyZ3M6IFsKCS8vICAgICAgICAgICAgICAgICAgICAgICAgIHsgaWQ6IHRoaXMudmFsaWRhdG9ySWQudmFsdWUsIHBvb2xJZDogdGhpcy5wb29sSWQudmFsdWUsIHBvb2xBcHBJZDogdGhpcy5hcHAuaWQgfSwKCS8vICAgICAgICAgICAgICAgICAgICAgICAgIHN0YWtlciwKCS8vICAgICAgICAgICAgICAgICAgICAgICAgIDAsIC8vIG5vIGFsZ28gcmVtb3ZlZAoJLy8gICAgICAgICAgICAgICAgICAgICAgICAgYW1vdW50UmV3YXJkVG9rZW5SZW1vdmVkLAoJLy8gICAgICAgICAgICAgICAgICAgICAgICAgZmFsc2UsIC8vIHN0YWtlciBpc24ndCBiZWluZyByZW1vdmVkLgoJLy8gICAgICAgICAgICAgICAgICAgICBdLAoJLy8gICAgICAgICAgICAgICAgIH0pCglpdHhuX2JlZ2luCglpbnQgYXBwbAoJaXR4bl9maWVsZCBUeXBlRW51bQoJbWV0aG9kICJzdGFrZVJlbW92ZWQoKHVpbnQ2NCx1aW50NjQsdWludDY0KSxhZGRyZXNzLHVpbnQ2NCx1aW50NjQsYm9vbCl2b2lkIgoJaXR4bl9maWVsZCBBcHBsaWNhdGlvbkFyZ3MKCgkvLyBjb250cmFjdHMvc3Rha2luZ1Bvb2wuYWxnby50czo0MDIKCS8vIGFwcGxpY2F0aW9uSUQ6IEFwcElELmZyb21VaW50NjQodGhpcy5jcmVhdGluZ1ZhbGlkYXRvckNvbnRyYWN0QXBwSWQudmFsdWUpCglieXRlIDB4NjM3MjY1NjE3NDZmNzI0MTcwNzAgLy8gImNyZWF0b3JBcHAiCglhcHBfZ2xvYmFsX2dldAoJaXR4bl9maWVsZCBBcHBsaWNhdGlvbklECgoJLy8gY29udHJhY3RzL3N0YWtpbmdQb29sLmFsZ28udHM6NDAzCgkvLyBtZXRob2RBcmdzOiBbCgkvLyAgICAgICAgICAgICAgICAgICAgICAgICB7IGlkOiB0aGlzLnZhbGlkYXRvcklkLnZhbHVlLCBwb29sSWQ6IHRoaXMucG9vbElkLnZhbHVlLCBwb29sQXBwSWQ6IHRoaXMuYXBwLmlkIH0sCgkvLyAgICAgICAgICAgICAgICAgICAgICAgICBzdGFrZXIsCgkvLyAgICAgICAgICAgICAgICAgICAgICAgICAwLCAvLyBubyBhbGdvIHJlbW92ZWQKCS8vICAgICAgICAgICAgICAgICAgICAgICAgIGFtb3VudFJld2FyZFRva2VuUmVtb3ZlZCwKCS8vICAgICAgICAgICAgICAgICAgICAgICAgIGZhbHNlLCAvLyBzdGFrZXIgaXNuJ3QgYmVpbmcgcmVtb3ZlZC4KCS8vICAgICAgICAgICAgICAgICAgICAgXQoJYnl0ZSAweDc2NjE2YzY5NjQ2MTc0NmY3MjQ5NjQgLy8gInZhbGlkYXRvcklkIgoJYXBwX2dsb2JhbF9nZXQKCWl0b2IKCWJ5dGUgMHg3MDZmNmY2YzQ5NjQgLy8gInBvb2xJZCIKCWFwcF9nbG9iYWxfZ2V0CglpdG9iCgljb25jYXQKCXR4bmEgQXBwbGljYXRpb25zIDAKCWl0b2IKCWNvbmNhdAoJaXR4bl9maWVsZCBBcHBsaWNhdGlvbkFyZ3MKCWZyYW1lX2RpZyAwIC8vIHN0YWtlcjogYWRkcmVzcwoJaXR4bl9maWVsZCBBcHBsaWNhdGlvbkFyZ3MKCWJ5dGUgMHgwMDAwMDAwMDAwMDAwMDAwCglpdHhuX2ZpZWxkIEFwcGxpY2F0aW9uQXJncwoJZnJhbWVfZGlnIDMgLy8gYW1vdW50UmV3YXJkVG9rZW5SZW1vdmVkOiB1aW50NjQKCWl0b2IKCWl0eG5fZmllbGQgQXBwbGljYXRpb25BcmdzCglpbnQgMAoJYnl0ZSAweDAwCglpbnQgMAoJdW5jb3ZlciAyCglzZXRiaXQKCWl0eG5fZmllbGQgQXBwbGljYXRpb25BcmdzCgoJLy8gRmVlIGZpZWxkIG5vdCBzZXQsIGRlZmF1bHRpbmcgdG8gMAoJaW50IDAKCWl0eG5fZmllbGQgRmVlCgoJLy8gU3VibWl0IGlubmVyIHRyYW5zYWN0aW9uCglpdHhuX3N1Ym1pdAoKCS8vIGNvbnRyYWN0cy9zdGFraW5nUG9vbC5hbGdvLnRzOjQxMQoJLy8gcmV0dXJuOwoJcmV0c3ViCgoqaWYxNF9lbmQ6CgoqZm9yXzJfY29udGludWU6CgkvLyBjb250cmFjdHMvc3Rha2luZ1Bvb2wuYWxnby50czozNjEKCS8vIGkgKz0gMQoJZnJhbWVfZGlnIDEgLy8gaTogdWludDY0CglpbnQgMQoJKwoJZnJhbWVfYnVyeSAxIC8vIGk6IHVpbnQ2NAoJYiAqZm9yXzIKCipmb3JfMl9lbmQ6CgllcnIgLy8gJ2FjY291bnQgbm90IGZvdW5kJwoKLy8gZ2V0U3Rha2VySW5mbyhhZGRyZXNzKShhZGRyZXNzLHVpbnQ2NCx1aW50NjQsdWludDY0LHVpbnQ2NCkKKmFiaV9yb3V0ZV9nZXRTdGFrZXJJbmZvOgoJLy8gVGhlIEFCSSByZXR1cm4gcHJlZml4CglieXRlIDB4MTUxZjdjNzUKCgkvLyBzdGFrZXI6IGFkZHJlc3MKCXR4bmEgQXBwbGljYXRpb25BcmdzIDEKCWR1cAoJbGVuCglpbnQgMzIKCT09Cglhc3NlcnQKCgkvLyBleGVjdXRlIGdldFN0YWtlckluZm8oYWRkcmVzcykoYWRkcmVzcyx1aW50NjQsdWludDY0LHVpbnQ2NCx1aW50NjQpCgljYWxsc3ViIGdldFN0YWtlckluZm8KCWNvbmNhdAoJbG9nCglpbnQgMQoJcmV0dXJuCgovLyBnZXRTdGFrZXJJbmZvKHN0YWtlcjogQWRkcmVzcyk6IFN0YWtlZEluZm8KLy8KLy8gUmV0cmlldmVzIHRoZSBzdGFrZWQgaW5mb3JtYXRpb24gZm9yIGEgZ2l2ZW4gc3Rha2VyLgovLwovLyBAcGFyYW0ge0FkZHJlc3N9IHN0YWtlciAtIFRoZSBhZGRyZXNzIG9mIHRoZSBzdGFrZXIuCi8vIEByZXR1cm5zIHtTdGFrZWRJbmZvfSAtIFRoZSBzdGFrZWQgaW5mb3JtYXRpb24gZm9yIHRoZSBnaXZlbiBzdGFrZXIuCi8vIEB0aHJvd3Mge0Vycm9yfSAtIElmIHRoZSBzdGFrZXIncyBhY2NvdW50IGlzIG5vdCBmb3VuZC4KZ2V0U3Rha2VySW5mbzoKCXByb3RvIDEgMQoKCS8vIFB1c2ggZW1wdHkgYnl0ZXMgYWZ0ZXIgdGhlIGZyYW1lIHBvaW50ZXIgdG8gcmVzZXJ2ZSBzcGFjZSBmb3IgbG9jYWwgdmFyaWFibGVzCglieXRlIDB4CgoJLy8gY29udHJhY3RzL3N0YWtpbmdQb29sLmFsZ28udHM6NDI2CgkvLyBmb3IgKGxldCBpID0gMDsgaSA8IHRoaXMuc3Rha2Vycy52YWx1ZS5sZW5ndGg7IGkgKz0gMSkKCWludCAwCglmcmFtZV9idXJ5IDAgLy8gaTogdWludDY0CgoqZm9yXzM6CgkvLyBjb250cmFjdHMvc3Rha2luZ1Bvb2wuYWxnby50czo0MjYKCS8vIGkgPCB0aGlzLnN0YWtlcnMudmFsdWUubGVuZ3RoCglmcmFtZV9kaWcgMCAvLyBpOiB1aW50NjQKCWludCAyMDAKCTwKCWJ6ICpmb3JfM19lbmQKCgkvLyAqaWYxN19jb25kaXRpb24KCS8vIGNvbnRyYWN0cy9zdGFraW5nUG9vbC5hbGdvLnRzOjQyNwoJLy8gZ2xvYmFscy5vcGNvZGVCdWRnZXQgPCAyMDAKCWdsb2JhbCBPcGNvZGVCdWRnZXQKCWludCAyMDAKCTwKCWJ6ICppZjE3X2VuZAoKCS8vICppZjE3X2NvbnNlcXVlbnQKCS8vIGNvbnRyYWN0cy9zdGFraW5nUG9vbC5hbGdvLnRzOjQyOAoJLy8gaW5jcmVhc2VPcGNvZGVCdWRnZXQoKQoJaXR4bl9iZWdpbgoJaW50IGFwcGwKCWl0eG5fZmllbGQgVHlwZUVudW0KCWludCAwCglpdHhuX2ZpZWxkIEZlZQoJYnl0ZSBiNjQgQ29FQiAvLyAjcHJhZ21hIHZlcnNpb24gMTA7IGludCAxCglkdXAKCWl0eG5fZmllbGQgQXBwcm92YWxQcm9ncmFtCglpdHhuX2ZpZWxkIENsZWFyU3RhdGVQcm9ncmFtCglpbnQgRGVsZXRlQXBwbGljYXRpb24KCWl0eG5fZmllbGQgT25Db21wbGV0aW9uCglpdHhuX3N1Ym1pdAoKKmlmMTdfZW5kOgoJLy8gKmlmMThfY29uZGl0aW9uCgkvLyBjb250cmFjdHMvc3Rha2luZ1Bvb2wuYWxnby50czo0MzAKCS8vIHRoaXMuc3Rha2Vycy52YWx1ZVtpXS5hY2NvdW50ID09PSBzdGFrZXIKCWZyYW1lX2RpZyAwIC8vIGk6IHVpbnQ2NAoJaW50IDY0CgkqIC8vIGFjYyAqIHR5cGVMZW5ndGgKCWludCAwCgkrCglpbnQgMzIKCWJ5dGUgMHg3Mzc0NjE2YjY1NzI3MyAvLyAic3Rha2VycyIKCWNvdmVyIDIKCWJveF9leHRyYWN0CglmcmFtZV9kaWcgLTEgLy8gc3Rha2VyOiBBZGRyZXNzCgk9PQoJYnogKmlmMThfZW5kCgoJLy8gKmlmMThfY29uc2VxdWVudAoJLy8gY29udHJhY3RzL3N0YWtpbmdQb29sLmFsZ28udHM6NDMxCgkvLyByZXR1cm4gdGhpcy5zdGFrZXJzLnZhbHVlW2ldOwoJZnJhbWVfZGlnIDAgLy8gaTogdWludDY0CglpbnQgNjQKCSogLy8gYWNjICogdHlwZUxlbmd0aAoJaW50IDY0CglieXRlIDB4NzM3NDYxNmI2NTcyNzMgLy8gInN0YWtlcnMiCgljb3ZlciAyCglib3hfZXh0cmFjdAoKCS8vIHNldCB0aGUgc3Vicm91dGluZSByZXR1cm4gdmFsdWUKCWZyYW1lX2J1cnkgMAoJcmV0c3ViCgoqaWYxOF9lbmQ6CgoqZm9yXzNfY29udGludWU6CgkvLyBjb250cmFjdHMvc3Rha2luZ1Bvb2wuYWxnby50czo0MjYKCS8vIGkgKz0gMQoJZnJhbWVfZGlnIDAgLy8gaTogdWludDY0CglpbnQgMQoJKwoJZnJhbWVfYnVyeSAwIC8vIGk6IHVpbnQ2NAoJYiAqZm9yXzMKCipmb3JfM19lbmQ6CgllcnIgLy8gJ2FjY291bnQgbm90IGZvdW5kJwoKLy8gcGF5VG9rZW5SZXdhcmQoYWRkcmVzcyx1aW50NjQsdWludDY0KXZvaWQKKmFiaV9yb3V0ZV9wYXlUb2tlblJld2FyZDoKCS8vIGFtb3VudFRvU2VuZDogdWludDY0Cgl0eG5hIEFwcGxpY2F0aW9uQXJncyAzCglidG9pCgoJLy8gcmV3YXJkVG9rZW46IHVpbnQ2NAoJdHhuYSBBcHBsaWNhdGlvbkFyZ3MgMgoJYnRvaQoKCS8vIHN0YWtlcjogYWRkcmVzcwoJdHhuYSBBcHBsaWNhdGlvbkFyZ3MgMQoJZHVwCglsZW4KCWludCAzMgoJPT0KCWFzc2VydAoKCS8vIGV4ZWN1dGUgcGF5VG9rZW5SZXdhcmQoYWRkcmVzcyx1aW50NjQsdWludDY0KXZvaWQKCWNhbGxzdWIgcGF5VG9rZW5SZXdhcmQKCWludCAxCglyZXR1cm4KCi8vIHBheVRva2VuUmV3YXJkKHN0YWtlcjogQWRkcmVzcywgcmV3YXJkVG9rZW46IHVpbnQ2NCwgYW1vdW50VG9TZW5kOiB1aW50NjQpOiB2b2lkCi8vCi8vIFtJbnRlcm5hbCBwcm90b2NvbCBtZXRob2RdIFJlbW92ZSBhIHNwZWNpZmllZCBhbW91bnQgb2YgJ2NvbW11bml0eSB0b2tlbicgcmV3YXJkcyBmb3IgYSBzdGFrZXIuCi8vIFRoaXMgY2FuIE9OTFkgYmUgY2FsbGVkIGJ5IG91ciB2YWxpZGF0b3IgYW5kIG9ubHkgaWYgd2UncmUgcG9vbCAxIC0gd2l0aCB0aGUgdG9rZW4uCi8vIEBwYXJhbSBzdGFrZXIgLSB0aGUgc3Rha2VyIGFjY291bnQgdG8gc2VuZCByZXdhcmRzIHRvCi8vIEBwYXJhbSByZXdhcmRUb2tlbiAtIGlkIG9mIHJld2FyZCB0b2tlbiAodG8gYXZvaWQgcmUtZW50cmFuY3kgaW4gY2FsbGluZyB2YWxpZGF0b3IgYmFjayB0byBnZXQgaWQpCi8vIEBwYXJhbSBhbW91bnRUb1NlbmQgLSBhbW91bnQgdG8gc2VuZCB0aGUgc3Rha2VyICh0aGVyZSBpcyBzaWduaWZpY2FudCB0cnVzdCBoZXJlKCEpIC0gYWxzbyB3aHkgb25seSB2YWxpZGF0b3IgY2FuIGNhbGwgdXMKcGF5VG9rZW5SZXdhcmQ6Cglwcm90byAzIDAKCgkvLyBjb250cmFjdHMvc3Rha2luZ1Bvb2wuYWxnby50czo0NDYKCS8vIGFzc2VydCh0aGlzLnR4bi5zZW5kZXIgPT09IEFwcElELmZyb21VaW50NjQodGhpcy5jcmVhdGluZ1ZhbGlkYXRvckNvbnRyYWN0QXBwSWQudmFsdWUpLmFkZHJlc3MpCgl0eG4gU2VuZGVyCglieXRlIDB4NjM3MjY1NjE3NDZmNzI0MTcwNzAgLy8gImNyZWF0b3JBcHAiCglhcHBfZ2xvYmFsX2dldAoJYXBwX3BhcmFtc19nZXQgQXBwQWRkcmVzcwoJcG9wCgk9PQoJYXNzZXJ0CgoJLy8gY29udHJhY3RzL3N0YWtpbmdQb29sLmFsZ28udHM6NDQ3CgkvLyBhc3NlcnQodGhpcy5wb29sSWQudmFsdWUgPT09IDEsICdtdXN0IGJlIHBvb2wgMSBpbiBvcmRlciB0byBiZSBjYWxsZWQgdG8gcGF5IG91dCB0b2tlbiByZXdhcmRzJykKCWJ5dGUgMHg3MDZmNmY2YzQ5NjQgLy8gInBvb2xJZCIKCWFwcF9nbG9iYWxfZ2V0CglpbnQgMQoJPT0KCgkvLyBtdXN0IGJlIHBvb2wgMSBpbiBvcmRlciB0byBiZSBjYWxsZWQgdG8gcGF5IG91dCB0b2tlbiByZXdhcmRzCglhc3NlcnQKCgkvLyBjb250cmFjdHMvc3Rha2luZ1Bvb2wuYWxnby50czo0NDgKCS8vIGFzc2VydChyZXdhcmRUb2tlbiAhPT0gMCwgJ2NhbiBvbmx5IGNsYWltIHRva2VuIHJld2FyZHMgZnJvbSB2YWxpZGF0b3IgdGhhdCBoYXMgdGhlbScpCglmcmFtZV9kaWcgLTIgLy8gcmV3YXJkVG9rZW46IHVpbnQ2NAoJaW50IDAKCSE9CgoJLy8gY2FuIG9ubHkgY2xhaW0gdG9rZW4gcmV3YXJkcyBmcm9tIHZhbGlkYXRvciB0aGF0IGhhcyB0aGVtCglhc3NlcnQKCgkvLyBjb250cmFjdHMvc3Rha2luZ1Bvb2wuYWxnby50czo0NTEKCS8vIHNlbmRBc3NldFRyYW5zZmVyKHsKCS8vICAgICAgICAgICAgIHhmZXJBc3NldDogQXNzZXRJRC5mcm9tVWludDY0KHJld2FyZFRva2VuKSwKCS8vICAgICAgICAgICAgIGFzc2V0UmVjZWl2ZXI6IHN0YWtlciwKCS8vICAgICAgICAgICAgIGFzc2V0QW1vdW50OiBhbW91bnRUb1NlbmQsCgkvLyAgICAgICAgIH0pCglpdHhuX2JlZ2luCglpbnQgYXhmZXIKCWl0eG5fZmllbGQgVHlwZUVudW0KCgkvLyBjb250cmFjdHMvc3Rha2luZ1Bvb2wuYWxnby50czo0NTIKCS8vIHhmZXJBc3NldDogQXNzZXRJRC5mcm9tVWludDY0KHJld2FyZFRva2VuKQoJZnJhbWVfZGlnIC0yIC8vIHJld2FyZFRva2VuOiB1aW50NjQKCWl0eG5fZmllbGQgWGZlckFzc2V0CgoJLy8gY29udHJhY3RzL3N0YWtpbmdQb29sLmFsZ28udHM6NDUzCgkvLyBhc3NldFJlY2VpdmVyOiBzdGFrZXIKCWZyYW1lX2RpZyAtMSAvLyBzdGFrZXI6IEFkZHJlc3MKCWl0eG5fZmllbGQgQXNzZXRSZWNlaXZlcgoKCS8vIGNvbnRyYWN0cy9zdGFraW5nUG9vbC5hbGdvLnRzOjQ1NAoJLy8gYXNzZXRBbW91bnQ6IGFtb3VudFRvU2VuZAoJZnJhbWVfZGlnIC0zIC8vIGFtb3VudFRvU2VuZDogdWludDY0CglpdHhuX2ZpZWxkIEFzc2V0QW1vdW50CgoJLy8gRmVlIGZpZWxkIG5vdCBzZXQsIGRlZmF1bHRpbmcgdG8gMAoJaW50IDAKCWl0eG5fZmllbGQgRmVlCgoJLy8gU3VibWl0IGlubmVyIHRyYW5zYWN0aW9uCglpdHhuX3N1Ym1pdAoJcmV0c3ViCgovLyB1cGRhdGVBbGdvZFZlcihzdHJpbmcpdm9pZAoqYWJpX3JvdXRlX3VwZGF0ZUFsZ29kVmVyOgoJLy8gYWxnb2RWZXI6IHN0cmluZwoJdHhuYSBBcHBsaWNhdGlvbkFyZ3MgMQoJZXh0cmFjdCAyIDAKCgkvLyBleGVjdXRlIHVwZGF0ZUFsZ29kVmVyKHN0cmluZyl2b2lkCgljYWxsc3ViIHVwZGF0ZUFsZ29kVmVyCglpbnQgMQoJcmV0dXJuCgovLyB1cGRhdGVBbGdvZFZlcihhbGdvZFZlcjogc3RyaW5nKTogdm9pZAovLwovLyBVcGRhdGUgdGhlIChob25vciBzeXN0ZW0pIGFsZ29kIHZlcnNpb24gZm9yIHRoZSBub2RlIGFzc29jaWF0ZWQgdG8gdGhpcyBwb29sLiAgVGhlIG5vZGUgbWFuYWdlbWVudCBkYWVtb24KLy8gc2hvdWxkIGNvbXBhcmUgaXRzIGN1cnJlbnQgbm9kZXMgdmVyc2lvbiB0byB0aGUgdmVyc2lvbiBzdG9yZWQgaW4gZ2xvYmFsIHN0YXRlLCB1cGRhdGluZyB3aGVuIGRpZmZlcmVudC4KLy8gVGhlIHJldGkgbm9kZSBkYWVtb24gY29tcG9zZXMgaXRzIG93biB2ZXJzaW9uIHN0cmluZyB1c2luZyBmb3JtYXQ6Ci8vIHttYWpvcn0ue21pbm9yfS57YnVpbGR9IHticmFuY2h9IFt7Y29tbWl0IGhhc2h9XSwKLy8gaWU6IDMuMjIuMCByZWwvc3RhYmxlIFs2YjUwODk3NV0KLy8gWyBPTkxZIE9XTkVSIE9SIE1BTkFHRVIgQ0FOIENBTEwgXQovLyBAcGFyYW0ge3N0cmluZ30gYWxnb2RWZXIgLSBzdHJpbmcgcmVwcmVzZW50aW5nIHRoZSBhbGdvcmFuZCBub2RlIGRhZW1vbiB2ZXJzaW9uIChyZXRpIG5vZGUgZGFlbW9uIGNvbXBvc2VzIGl0cyBvd24gbWV0YSB2ZXJzaW9uKQp1cGRhdGVBbGdvZFZlcjoKCXByb3RvIDEgMAoKCS8vIGNvbnRyYWN0cy9zdGFraW5nUG9vbC5hbGdvLnRzOjQ2OAoJLy8gYXNzZXJ0KHRoaXMuaXNPd25lck9yTWFuYWdlckNhbGxlcigpKQoJY2FsbHN1YiBpc093bmVyT3JNYW5hZ2VyQ2FsbGVyCglhc3NlcnQKCgkvLyBjb250cmFjdHMvc3Rha2luZ1Bvb2wuYWxnby50czo0NjkKCS8vIHRoaXMuYWxnb2RWZXIudmFsdWUgPSBhbGdvZFZlcgoJYnl0ZSAweDYxNmM2NzZmNjQ1NjY1NzIgLy8gImFsZ29kVmVyIgoJZnJhbWVfZGlnIC0xIC8vIGFsZ29kVmVyOiBzdHJpbmcKCWFwcF9nbG9iYWxfcHV0CglyZXRzdWIKCi8vIGVwb2NoQmFsYW5jZVVwZGF0ZSgpdm9pZAoqYWJpX3JvdXRlX2Vwb2NoQmFsYW5jZVVwZGF0ZToKCS8vIGV4ZWN1dGUgZXBvY2hCYWxhbmNlVXBkYXRlKCl2b2lkCgljYWxsc3ViIGVwb2NoQmFsYW5jZVVwZGF0ZQoJaW50IDEKCXJldHVybgoKLy8gZXBvY2hCYWxhbmNlVXBkYXRlKCk6IHZvaWQKLy8KLy8gVXBkYXRlcyB0aGUgYmFsYW5jZSBvZiBzdGFrZXJzIGluIHRoZSBwb29sIGJhc2VkIG9uIHRoZSByZWNlaXZlZCAncmV3YXJkcycgKGN1cnJlbnQgYmFsYW5jZSB2cyBrbm93biBzdGFrZWQgYmFsYW5jZSkKLy8gc3Rha2VycyBvdXRzdGFuZGluZyBiYWxhbmNlIGlzIGFkanVzdGVkIGJhc2VkIG9uIHRoZWlyICUgb2Ygc3Rha2UgYW5kIHRpbWUgaW4gdGhlIGN1cnJlbnQgZXBvY2ggLSBzbyB0aGF0IGJhbGFuY2UKLy8gY29tcG91bmRzIG92ZXIgdGltZSBhbmQgc3Rha2VyIGNhbiByZW1vdmUgdGhhdCBhbW91bnQgYXQgd2lsbC4KLy8gVGhlIHZhbGlkYXRvciBpcyBwYWlkIHRoZWlyIHBlcmNlbnRhZ2UgZWFjaCBlcG9jaCBwYXlvdXQuCi8vCi8vIE5vdGU6IEFOWU9ORSBjYW4gY2FsbCB0aGlzLgplcG9jaEJhbGFuY2VVcGRhdGU6Cglwcm90byAwIDAKCgkvLyBQdXNoIGVtcHR5IGJ5dGVzIGFmdGVyIHRoZSBmcmFtZSBwb2ludGVyIHRvIHJlc2VydmUgc3BhY2UgZm9yIGxvY2FsIHZhcmlhYmxlcwoJYnl0ZSAweAoJZHVwbiAzMwoKCS8vIGNvbnRyYWN0cy9zdGFraW5nUG9vbC5hbGdvLnRzOjQ4MgoJLy8gdmFsaWRhdG9yQ29uZmlnID0gc2VuZE1ldGhvZENhbGw8dHlwZW9mIFZhbGlkYXRvclJlZ2lzdHJ5LnByb3RvdHlwZS5nZXRWYWxpZGF0b3JDb25maWc+KHsKCS8vICAgICAgICAgICAgIGFwcGxpY2F0aW9uSUQ6IEFwcElELmZyb21VaW50NjQodGhpcy5jcmVhdGluZ1ZhbGlkYXRvckNvbnRyYWN0QXBwSWQudmFsdWUpLAoJLy8gICAgICAgICAgICAgbWV0aG9kQXJnczogW3RoaXMudmFsaWRhdG9ySWQudmFsdWVdLAoJLy8gICAgICAgICB9KQoJaXR4bl9iZWdpbgoJaW50IGFwcGwKCWl0eG5fZmllbGQgVHlwZUVudW0KCW1ldGhvZCAiZ2V0VmFsaWRhdG9yQ29uZmlnKHVpbnQ2NCkodWludDY0LGFkZHJlc3MsYWRkcmVzcyx1aW50NjQsdWludDgsYnl0ZVszMl0sdWludDY0LHVpbnQ2NCx1aW50NjQsdWludDE2LHVpbnQzMixhZGRyZXNzLHVpbnQ2NCx1aW50NjQsdWludDgsdWludDY0LHVpbnQ2NCkiCglpdHhuX2ZpZWxkIEFwcGxpY2F0aW9uQXJncwoKCS8vIGNvbnRyYWN0cy9zdGFraW5nUG9vbC5hbGdvLnRzOjQ4MwoJLy8gYXBwbGljYXRpb25JRDogQXBwSUQuZnJvbVVpbnQ2NCh0aGlzLmNyZWF0aW5nVmFsaWRhdG9yQ29udHJhY3RBcHBJZC52YWx1ZSkKCWJ5dGUgMHg2MzcyNjU2MTc0NmY3MjQxNzA3MCAvLyAiY3JlYXRvckFwcCIKCWFwcF9nbG9iYWxfZ2V0CglpdHhuX2ZpZWxkIEFwcGxpY2F0aW9uSUQKCgkvLyBjb250cmFjdHMvc3Rha2luZ1Bvb2wuYWxnby50czo0ODQKCS8vIG1ldGhvZEFyZ3M6IFt0aGlzLnZhbGlkYXRvcklkLnZhbHVlXQoJYnl0ZSAweDc2NjE2YzY5NjQ2MTc0NmY3MjQ5NjQgLy8gInZhbGlkYXRvcklkIgoJYXBwX2dsb2JhbF9nZXQKCWl0b2IKCWl0eG5fZmllbGQgQXBwbGljYXRpb25BcmdzCgoJLy8gRmVlIGZpZWxkIG5vdCBzZXQsIGRlZmF1bHRpbmcgdG8gMAoJaW50IDAKCWl0eG5fZmllbGQgRmVlCgoJLy8gU3VibWl0IGlubmVyIHRyYW5zYWN0aW9uCglpdHhuX3N1Ym1pdAoJaXR4biBOdW1Mb2dzCglpbnQgMQoJLQoJaXR4bmFzIExvZ3MKCWV4dHJhY3QgNCAwCglmcmFtZV9idXJ5IDAgLy8gdmFsaWRhdG9yQ29uZmlnOiAodWludDY0LGFkZHJlc3MsYWRkcmVzcyx1aW50NjQsdWludDgsYnl0ZVszMl0sdWludDY0LHVpbnQ2NCx1aW50NjQsdWludDE2LHVpbnQzMixhZGRyZXNzLHVpbnQ2NCx1aW50NjQsdWludDgsdWludDY0LHVpbnQ2NCkKCgkvLyBjb250cmFjdHMvc3Rha2luZ1Bvb2wuYWxnby50czo0OTIKCS8vIGN1clRpbWUgPSBnbG9iYWxzLmxhdGVzdFRpbWVzdGFtcAoJZ2xvYmFsIExhdGVzdFRpbWVzdGFtcAoJZnJhbWVfYnVyeSAxIC8vIGN1clRpbWU6IHVpbnQ2NAoKCS8vIGNvbnRyYWN0cy9zdGFraW5nUG9vbC5hbGdvLnRzOjQ5NAoJLy8gZXBvY2hJblNlY3MgPSAodmFsaWRhdG9yQ29uZmlnLnBheW91dEV2ZXJ5WE1pbnMgYXMgdWludDY0KSAqIDYwCglmcmFtZV9kaWcgMCAvLyB2YWxpZGF0b3JDb25maWc6ICh1aW50NjQsYWRkcmVzcyxhZGRyZXNzLHVpbnQ2NCx1aW50OCxieXRlWzMyXSx1aW50NjQsdWludDY0LHVpbnQ2NCx1aW50MTYsdWludDMyLGFkZHJlc3MsdWludDY0LHVpbnQ2NCx1aW50OCx1aW50NjQsdWludDY0KQoJZXh0cmFjdCAxMzcgMgoJYnRvaQoJaW50IDYwCgkqCglmcmFtZV9idXJ5IDIgLy8gZXBvY2hJblNlY3M6IHVpbnQ2NAoKCS8vICppZjE5X2NvbmRpdGlvbgoJLy8gY29udHJhY3RzL3N0YWtpbmdQb29sLmFsZ28udHM6NDk1CgkvLyB0aGlzLmxhc3RQYXlvdXQuZXhpc3RzCgl0eG5hIEFwcGxpY2F0aW9ucyAwCglieXRlIDB4NmM2MTczNzQ1MDYxNzk2Zjc1NzQgLy8gImxhc3RQYXlvdXQiCglhcHBfZ2xvYmFsX2dldF9leAoJc3dhcAoJcG9wCglieiAqaWYxOV9lbmQKCgkvLyAqaWYxOV9jb25zZXF1ZW50CgkvLyBjb250cmFjdHMvc3Rha2luZ1Bvb2wuYWxnby50czo0OTYKCS8vIHNlY3NTaW5jZUxhc3RQYXlvdXQgPSBjdXJUaW1lIC0gdGhpcy5sYXN0UGF5b3V0LnZhbHVlCglmcmFtZV9kaWcgMSAvLyBjdXJUaW1lOiB1aW50NjQKCWJ5dGUgMHg2YzYxNzM3NDUwNjE3OTZmNzU3NCAvLyAibGFzdFBheW91dCIKCWFwcF9nbG9iYWxfZ2V0CgktCglmcmFtZV9idXJ5IDMgLy8gc2Vjc1NpbmNlTGFzdFBheW91dDogdWludDY0CgoJLy8gY29udHJhY3RzL3N0YWtpbmdQb29sLmFsZ28udHM6NDk3CgkvLyBsb2coY29uY2F0KCdzZWNzIHNpbmNlIGxhc3QgcGF5b3V0OiAlaScsIGl0b2Ioc2Vjc1NpbmNlTGFzdFBheW91dCkpKQoJYnl0ZSAweDczNjU2MzczMjA3MzY5NmU2MzY1MjA2YzYxNzM3NDIwNzA2MTc5NmY3NTc0M2EyMDI1NjkgLy8gInNlY3Mgc2luY2UgbGFzdCBwYXlvdXQ6ICVpIgoJZnJhbWVfZGlnIDMgLy8gc2Vjc1NpbmNlTGFzdFBheW91dDogdWludDY0CglpdG9iCgljb25jYXQKCWxvZwoKCS8vIGNvbnRyYWN0cy9zdGFraW5nUG9vbC5hbGdvLnRzOjUwMAoJLy8gYXNzZXJ0KHNlY3NTaW5jZUxhc3RQYXlvdXQgPj0gZXBvY2hJblNlY3MsICJDYW4ndCBwYXlvdXQgZWFybGllciB0aGFuIGxhc3QgcGF5b3V0ICsgZXBvY2ggdGltZSIpCglmcmFtZV9kaWcgMyAvLyBzZWNzU2luY2VMYXN0UGF5b3V0OiB1aW50NjQKCWZyYW1lX2RpZyAyIC8vIGVwb2NoSW5TZWNzOiB1aW50NjQKCT49CgoJLy8gQ2FuJ3QgcGF5b3V0IGVhcmxpZXIgdGhhbiBsYXN0IHBheW91dCArIGVwb2NoIHRpbWUKCWFzc2VydAoKKmlmMTlfZW5kOgoJLy8gY29udHJhY3RzL3N0YWtpbmdQb29sLmFsZ28udHM6NTAzCgkvLyB0aGlzLmxhc3RQYXlvdXQudmFsdWUgPSBjdXJUaW1lCglieXRlIDB4NmM2MTczNzQ1MDYxNzk2Zjc1NzQgLy8gImxhc3RQYXlvdXQiCglmcmFtZV9kaWcgMSAvLyBjdXJUaW1lOiB1aW50NjQKCWFwcF9nbG9iYWxfcHV0CgoJLy8gY29udHJhY3RzL3N0YWtpbmdQb29sLmFsZ28udHM6NTA0CgkvLyB0aGlzLmVwb2NoTnVtYmVyLnZhbHVlICs9IDEKCWJ5dGUgMHg2NTcwNmY2MzY4NGU3NTZkNjI2NTcyIC8vICJlcG9jaE51bWJlciIKCWFwcF9nbG9iYWxfZ2V0CglpbnQgMQoJKwoJYnl0ZSAweDY1NzA2ZjYzNjg0ZTc1NmQ2MjY1NzIgLy8gImVwb2NoTnVtYmVyIgoJc3dhcAoJYXBwX2dsb2JhbF9wdXQKCgkvLyBjb250cmFjdHMvc3Rha2luZ1Bvb2wuYWxnby50czo1MDkKCS8vIGlzVG9rZW5FbGlnaWJsZSA9IHZhbGlkYXRvckNvbmZpZy5yZXdhcmRUb2tlbklkICE9PSAwCglmcmFtZV9kaWcgMCAvLyB2YWxpZGF0b3JDb25maWc6ICh1aW50NjQsYWRkcmVzcyxhZGRyZXNzLHVpbnQ2NCx1aW50OCxieXRlWzMyXSx1aW50NjQsdWludDY0LHVpbnQ2NCx1aW50MTYsdWludDMyLGFkZHJlc3MsdWludDY0LHVpbnQ2NCx1aW50OCx1aW50NjQsdWludDY0KQoJZXh0cmFjdCAxMjEgOAoJYnRvaQoJaW50IDAKCSE9CglmcmFtZV9idXJ5IDQgLy8gaXNUb2tlbkVsaWdpYmxlOiBib29sCgoJLy8gY29udHJhY3RzL3N0YWtpbmdQb29sLmFsZ28udHM6NTEwCgkvLyBwb29sT25lQXBwSUQgPSB0aGlzLmFwcC5pZAoJdHhuYSBBcHBsaWNhdGlvbnMgMAoJZnJhbWVfYnVyeSA1IC8vIHBvb2xPbmVBcHBJRDogdWludDY0CgoJLy8gY29udHJhY3RzL3N0YWtpbmdQb29sLmFsZ28udHM6NTExCgkvLyBwb29sT25lQWRkcmVzcyA9IHRoaXMuYXBwLmFkZHJlc3MKCWdsb2JhbCBDdXJyZW50QXBwbGljYXRpb25BZGRyZXNzCglmcmFtZV9idXJ5IDYgLy8gcG9vbE9uZUFkZHJlc3M6IGFkZHJlc3MKCgkvLyAqaWYyMF9jb25kaXRpb24KCS8vIGNvbnRyYWN0cy9zdGFraW5nUG9vbC5hbGdvLnRzOjUxNgoJLy8gaXNUb2tlbkVsaWdpYmxlCglmcmFtZV9kaWcgNCAvLyBpc1Rva2VuRWxpZ2libGU6IGJvb2wKCWJ6ICppZjIwX2VuZAoKCS8vICppZjIwX2NvbnNlcXVlbnQKCS8vICppZjIxX2NvbmRpdGlvbgoJLy8gY29udHJhY3RzL3N0YWtpbmdQb29sLmFsZ28udHM6NTE3CgkvLyB0aGlzLnBvb2xJZC52YWx1ZSAhPT0gMQoJYnl0ZSAweDcwNmY2ZjZjNDk2NCAvLyAicG9vbElkIgoJYXBwX2dsb2JhbF9nZXQKCWludCAxCgkhPQoJYnogKmlmMjFfZW5kCgoJLy8gKmlmMjFfY29uc2VxdWVudAoJLy8gY29udHJhY3RzL3N0YWtpbmdQb29sLmFsZ28udHM6NTE5CgkvLyBwb29sT25lQXBwSUQgPSBzZW5kTWV0aG9kQ2FsbDx0eXBlb2YgVmFsaWRhdG9yUmVnaXN0cnkucHJvdG90eXBlLmdldFBvb2xBcHBJZD4oewoJLy8gICAgICAgICAgICAgICAgICAgICBhcHBsaWNhdGlvbklEOiBBcHBJRC5mcm9tVWludDY0KHRoaXMuY3JlYXRpbmdWYWxpZGF0b3JDb250cmFjdEFwcElkLnZhbHVlKSwKCS8vICAgICAgICAgICAgICAgICAgICAgbWV0aG9kQXJnczogW3RoaXMudmFsaWRhdG9ySWQudmFsdWUsIDFdLAoJLy8gICAgICAgICAgICAgICAgIH0pCglpdHhuX2JlZ2luCglpbnQgYXBwbAoJaXR4bl9maWVsZCBUeXBlRW51bQoJbWV0aG9kICJnZXRQb29sQXBwSWQodWludDY0LHVpbnQ2NCl1aW50NjQiCglpdHhuX2ZpZWxkIEFwcGxpY2F0aW9uQXJncwoKCS8vIGNvbnRyYWN0cy9zdGFraW5nUG9vbC5hbGdvLnRzOjUyMAoJLy8gYXBwbGljYXRpb25JRDogQXBwSUQuZnJvbVVpbnQ2NCh0aGlzLmNyZWF0aW5nVmFsaWRhdG9yQ29udHJhY3RBcHBJZC52YWx1ZSkKCWJ5dGUgMHg2MzcyNjU2MTc0NmY3MjQxNzA3MCAvLyAiY3JlYXRvckFwcCIKCWFwcF9nbG9iYWxfZ2V0CglpdHhuX2ZpZWxkIEFwcGxpY2F0aW9uSUQKCgkvLyBjb250cmFjdHMvc3Rha2luZ1Bvb2wuYWxnby50czo1MjEKCS8vIG1ldGhvZEFyZ3M6IFt0aGlzLnZhbGlkYXRvcklkLnZhbHVlLCAxXQoJYnl0ZSAweDc2NjE2YzY5NjQ2MTc0NmY3MjQ5NjQgLy8gInZhbGlkYXRvcklkIgoJYXBwX2dsb2JhbF9nZXQKCWl0b2IKCWl0eG5fZmllbGQgQXBwbGljYXRpb25BcmdzCglieXRlIDB4MDAwMDAwMDAwMDAwMDAwMQoJaXR4bl9maWVsZCBBcHBsaWNhdGlvbkFyZ3MKCgkvLyBGZWUgZmllbGQgbm90IHNldCwgZGVmYXVsdGluZyB0byAwCglpbnQgMAoJaXR4bl9maWVsZCBGZWUKCgkvLyBTdWJtaXQgaW5uZXIgdHJhbnNhY3Rpb24KCWl0eG5fc3VibWl0CglpdHhuIE51bUxvZ3MKCWludCAxCgktCglpdHhuYXMgTG9ncwoJZXh0cmFjdCA0IDAKCWJ0b2kKCWZyYW1lX2J1cnkgNSAvLyBwb29sT25lQXBwSUQ6IHVpbnQ2NAoKCS8vIGNvbnRyYWN0cy9zdGFraW5nUG9vbC5hbGdvLnRzOjUyMwoJLy8gcG9vbE9uZUFkZHJlc3MgPSBBcHBJRC5mcm9tVWludDY0KHBvb2xPbmVBcHBJRCkuYWRkcmVzcwoJZnJhbWVfZGlnIDUgLy8gcG9vbE9uZUFwcElEOiB1aW50NjQKCWFwcF9wYXJhbXNfZ2V0IEFwcEFkZHJlc3MKCXBvcAoJZnJhbWVfYnVyeSA2IC8vIHBvb2xPbmVBZGRyZXNzOiBhZGRyZXNzCgoqaWYyMV9lbmQ6CgkvLyAqaWYyMl9jb25kaXRpb24KCS8vIGNvbnRyYWN0cy9zdGFraW5nUG9vbC5hbGdvLnRzOjUyOAoJLy8gdGhpcy5wb29sSWQudmFsdWUgPT09IDEKCWJ5dGUgMHg3MDZmNmY2YzQ5NjQgLy8gInBvb2xJZCIKCWFwcF9nbG9iYWxfZ2V0CglpbnQgMQoJPT0KCWJ6ICppZjIyX2Vsc2UKCgkvLyAqaWYyMl9jb25zZXF1ZW50CgkvLyBjb250cmFjdHMvc3Rha2luZ1Bvb2wuYWxnby50czo1MjkKCS8vIHRva2VuUGF5b3V0UmF0aW8gPSBzZW5kTWV0aG9kQ2FsbDx0eXBlb2YgVmFsaWRhdG9yUmVnaXN0cnkucHJvdG90eXBlLnNldFRva2VuUGF5b3V0UmF0aW8+KHsKCS8vICAgICAgICAgICAgICAgICAgICAgYXBwbGljYXRpb25JRDogQXBwSUQuZnJvbVVpbnQ2NCh0aGlzLmNyZWF0aW5nVmFsaWRhdG9yQ29udHJhY3RBcHBJZC52YWx1ZSksCgkvLyAgICAgICAgICAgICAgICAgICAgIG1ldGhvZEFyZ3M6IFt0aGlzLnZhbGlkYXRvcklkLnZhbHVlXSwKCS8vICAgICAgICAgICAgICAgICB9KQoJaXR4bl9iZWdpbgoJaW50IGFwcGwKCWl0eG5fZmllbGQgVHlwZUVudW0KCW1ldGhvZCAic2V0VG9rZW5QYXlvdXRSYXRpbyh1aW50NjQpKHVpbnQ2NFsyNF0sdWludDY0KSIKCWl0eG5fZmllbGQgQXBwbGljYXRpb25BcmdzCgoJLy8gY29udHJhY3RzL3N0YWtpbmdQb29sLmFsZ28udHM6NTMwCgkvLyBhcHBsaWNhdGlvbklEOiBBcHBJRC5mcm9tVWludDY0KHRoaXMuY3JlYXRpbmdWYWxpZGF0b3JDb250cmFjdEFwcElkLnZhbHVlKQoJYnl0ZSAweDYzNzI2NTYxNzQ2ZjcyNDE3MDcwIC8vICJjcmVhdG9yQXBwIgoJYXBwX2dsb2JhbF9nZXQKCWl0eG5fZmllbGQgQXBwbGljYXRpb25JRAoKCS8vIGNvbnRyYWN0cy9zdGFraW5nUG9vbC5hbGdvLnRzOjUzMQoJLy8gbWV0aG9kQXJnczogW3RoaXMudmFsaWRhdG9ySWQudmFsdWVdCglieXRlIDB4NzY2MTZjNjk2NDYxNzQ2ZjcyNDk2NCAvLyAidmFsaWRhdG9ySWQiCglhcHBfZ2xvYmFsX2dldAoJaXRvYgoJaXR4bl9maWVsZCBBcHBsaWNhdGlvbkFyZ3MKCgkvLyBGZWUgZmllbGQgbm90IHNldCwgZGVmYXVsdGluZyB0byAwCglpbnQgMAoJaXR4bl9maWVsZCBGZWUKCgkvLyBTdWJtaXQgaW5uZXIgdHJhbnNhY3Rpb24KCWl0eG5fc3VibWl0CglpdHhuIE51bUxvZ3MKCWludCAxCgktCglpdHhuYXMgTG9ncwoJZXh0cmFjdCA0IDAKCWZyYW1lX2J1cnkgNyAvLyB0b2tlblBheW91dFJhdGlvOiBQb29sVG9rZW5QYXlvdXRSYXRpbwoJYiAqaWYyMl9lbmQKCippZjIyX2Vsc2U6CgkvLyBjb250cmFjdHMvc3Rha2luZ1Bvb2wuYWxnby50czo1MzUKCS8vIHRva2VuUGF5b3V0UmF0aW8gPSBzZW5kTWV0aG9kQ2FsbDx0eXBlb2YgU3Rha2luZ1Bvb2wucHJvdG90eXBlLnByb3hpZWRTZXRUb2tlblBheW91dFJhdGlvPih7CgkvLyAgICAgICAgICAgICAgICAgICAgIGFwcGxpY2F0aW9uSUQ6IEFwcElELmZyb21VaW50NjQocG9vbE9uZUFwcElEKSwKCS8vICAgICAgICAgICAgICAgICAgICAgbWV0aG9kQXJnczogW3sgaWQ6IHRoaXMudmFsaWRhdG9ySWQudmFsdWUsIHBvb2xJZDogdGhpcy5wb29sSWQudmFsdWUsIHBvb2xBcHBJZDogdGhpcy5hcHAuaWQgfV0sCgkvLyAgICAgICAgICAgICAgICAgfSkKCWl0eG5fYmVnaW4KCWludCBhcHBsCglpdHhuX2ZpZWxkIFR5cGVFbnVtCgltZXRob2QgInByb3hpZWRTZXRUb2tlblBheW91dFJhdGlvKCh1aW50NjQsdWludDY0LHVpbnQ2NCkpKHVpbnQ2NFsyNF0sdWludDY0KSIKCWl0eG5fZmllbGQgQXBwbGljYXRpb25BcmdzCgoJLy8gY29udHJhY3RzL3N0YWtpbmdQb29sLmFsZ28udHM6NTM2CgkvLyBhcHBsaWNhdGlvbklEOiBBcHBJRC5mcm9tVWludDY0KHBvb2xPbmVBcHBJRCkKCWZyYW1lX2RpZyA1IC8vIHBvb2xPbmVBcHBJRDogdWludDY0CglpdHhuX2ZpZWxkIEFwcGxpY2F0aW9uSUQKCgkvLyBjb250cmFjdHMvc3Rha2luZ1Bvb2wuYWxnby50czo1MzcKCS8vIG1ldGhvZEFyZ3M6IFt7IGlkOiB0aGlzLnZhbGlkYXRvcklkLnZhbHVlLCBwb29sSWQ6IHRoaXMucG9vbElkLnZhbHVlLCBwb29sQXBwSWQ6IHRoaXMuYXBwLmlkIH1dCglieXRlIDB4NzY2MTZjNjk2NDYxNzQ2ZjcyNDk2NCAvLyAidmFsaWRhdG9ySWQiCglhcHBfZ2xvYmFsX2dldAoJaXRvYgoJYnl0ZSAweDcwNmY2ZjZjNDk2NCAvLyAicG9vbElkIgoJYXBwX2dsb2JhbF9nZXQKCWl0b2IKCWNvbmNhdAoJdHhuYSBBcHBsaWNhdGlvbnMgMAoJaXRvYgoJY29uY2F0CglpdHhuX2ZpZWxkIEFwcGxpY2F0aW9uQXJncwoKCS8vIEZlZSBmaWVsZCBub3Qgc2V0LCBkZWZhdWx0aW5nIHRvIDAKCWludCAwCglpdHhuX2ZpZWxkIEZlZQoKCS8vIFN1Ym1pdCBpbm5lciB0cmFuc2FjdGlvbgoJaXR4bl9zdWJtaXQKCWl0eG4gTnVtTG9ncwoJaW50IDEKCS0KCWl0eG5hcyBMb2dzCglleHRyYWN0IDQgMAoJZnJhbWVfYnVyeSA3IC8vIHRva2VuUGF5b3V0UmF0aW86IFBvb2xUb2tlblBheW91dFJhdGlvCgoqaWYyMl9lbmQ6CgoqaWYyMF9lbmQ6CgkvLyBjb250cmFjdHMvc3Rha2luZ1Bvb2wuYWxnby50czo1NDQKCS8vIHZhbGlkYXRvclN0YXRlID0gc2VuZE1ldGhvZENhbGw8dHlwZW9mIFZhbGlkYXRvclJlZ2lzdHJ5LnByb3RvdHlwZS5nZXRWYWxpZGF0b3JTdGF0ZT4oewoJLy8gICAgICAgICAgICAgYXBwbGljYXRpb25JRDogQXBwSUQuZnJvbVVpbnQ2NCh0aGlzLmNyZWF0aW5nVmFsaWRhdG9yQ29udHJhY3RBcHBJZC52YWx1ZSksCgkvLyAgICAgICAgICAgICBtZXRob2RBcmdzOiBbdGhpcy52YWxpZGF0b3JJZC52YWx1ZV0sCgkvLyAgICAgICAgIH0pCglpdHhuX2JlZ2luCglpbnQgYXBwbAoJaXR4bl9maWVsZCBUeXBlRW51bQoJbWV0aG9kICJnZXRWYWxpZGF0b3JTdGF0ZSh1aW50NjQpKHVpbnQxNix1aW50NjQsdWludDY0LHVpbnQ2NCkiCglpdHhuX2ZpZWxkIEFwcGxpY2F0aW9uQXJncwoKCS8vIGNvbnRyYWN0cy9zdGFraW5nUG9vbC5hbGdvLnRzOjU0NQoJLy8gYXBwbGljYXRpb25JRDogQXBwSUQuZnJvbVVpbnQ2NCh0aGlzLmNyZWF0aW5nVmFsaWRhdG9yQ29udHJhY3RBcHBJZC52YWx1ZSkKCWJ5dGUgMHg2MzcyNjU2MTc0NmY3MjQxNzA3MCAvLyAiY3JlYXRvckFwcCIKCWFwcF9nbG9iYWxfZ2V0CglpdHhuX2ZpZWxkIEFwcGxpY2F0aW9uSUQKCgkvLyBjb250cmFjdHMvc3Rha2luZ1Bvb2wuYWxnby50czo1NDYKCS8vIG1ldGhvZEFyZ3M6IFt0aGlzLnZhbGlkYXRvcklkLnZhbHVlXQoJYnl0ZSAweDc2NjE2YzY5NjQ2MTc0NmY3MjQ5NjQgLy8gInZhbGlkYXRvcklkIgoJYXBwX2dsb2JhbF9nZXQKCWl0b2IKCWl0eG5fZmllbGQgQXBwbGljYXRpb25BcmdzCgoJLy8gRmVlIGZpZWxkIG5vdCBzZXQsIGRlZmF1bHRpbmcgdG8gMAoJaW50IDAKCWl0eG5fZmllbGQgRmVlCgoJLy8gU3VibWl0IGlubmVyIHRyYW5zYWN0aW9uCglpdHhuX3N1Ym1pdAoJaXR4biBOdW1Mb2dzCglpbnQgMQoJLQoJaXR4bmFzIExvZ3MKCWV4dHJhY3QgNCAwCglmcmFtZV9idXJ5IDggLy8gdmFsaWRhdG9yU3RhdGU6ICh1aW50MTYsdWludDY0LHVpbnQ2NCx1aW50NjQpCgoJLy8gY29udHJhY3RzL3N0YWtpbmdQb29sLmFsZ28udHM6NTQ4CgkvLyByZXdhcmRUb2tlbkhlbGRCYWNrID0gdmFsaWRhdG9yU3RhdGUucmV3YXJkVG9rZW5IZWxkQmFjawoJZnJhbWVfZGlnIDggLy8gdmFsaWRhdG9yU3RhdGU6ICh1aW50MTYsdWludDY0LHVpbnQ2NCx1aW50NjQpCglleHRyYWN0IDE4IDgKCWJ0b2kKCWZyYW1lX2J1cnkgOSAvLyByZXdhcmRUb2tlbkhlbGRCYWNrOiB1aW50NjQKCgkvLyBjb250cmFjdHMvc3Rha2luZ1Bvb2wuYWxnby50czo1NTQKCS8vIGFsZ29SZXdhcmRBdmFpbCA9IHRoaXMuYXBwLmFkZHJlc3MuYmFsYW5jZSAtIHRoaXMudG90YWxBbGdvU3Rha2VkLnZhbHVlIC0gdGhpcy5hcHAuYWRkcmVzcy5taW5CYWxhbmNlCglnbG9iYWwgQ3VycmVudEFwcGxpY2F0aW9uQWRkcmVzcwoJYWNjdF9wYXJhbXNfZ2V0IEFjY3RCYWxhbmNlCglwb3AKCWJ5dGUgMHg3Mzc0NjE2YjY1NjQgLy8gInN0YWtlZCIKCWFwcF9nbG9iYWxfZ2V0CgktCglnbG9iYWwgQ3VycmVudEFwcGxpY2F0aW9uQWRkcmVzcwoJYWNjdF9wYXJhbXNfZ2V0IEFjY3RNaW5CYWxhbmNlCglwb3AKCS0KCWZyYW1lX2J1cnkgMTAgLy8gYWxnb1Jld2FyZEF2YWlsOiB1aW50NjQKCgkvLyBjb250cmFjdHMvc3Rha2luZ1Bvb2wuYWxnby50czo1NTUKCS8vIGlzUG9vbFNhdHVyYXRlZCA9IGZhbHNlCglpbnQgMAoJZnJhbWVfYnVyeSAxMSAvLyBpc1Bvb2xTYXR1cmF0ZWQ6IGJvb2wKCgkvLyBjb250cmFjdHMvc3Rha2luZ1Bvb2wuYWxnby50czo1NTYKCS8vIGFsZ29TYXR1cmF0aW9uQW10ID0gdGhpcy5hbGdvU2F0dXJhdGlvbkxldmVsKCkKCWNhbGxzdWIgYWxnb1NhdHVyYXRpb25MZXZlbAoJZnJhbWVfYnVyeSAxMiAvLyBhbGdvU2F0dXJhdGlvbkFtdDogdWludDY0CgoJLy8gKmlmMjNfY29uZGl0aW9uCgkvLyBjb250cmFjdHMvc3Rha2luZ1Bvb2wuYWxnby50czo1NjQKCS8vIHZhbGlkYXRvclN0YXRlLnRvdGFsQWxnb1N0YWtlZCA+IGFsZ29TYXR1cmF0aW9uQW10CglmcmFtZV9kaWcgOCAvLyB2YWxpZGF0b3JTdGF0ZTogKHVpbnQxNix1aW50NjQsdWludDY0LHVpbnQ2NCkKCWV4dHJhY3QgMTAgOAoJYnRvaQoJZnJhbWVfZGlnIDEyIC8vIGFsZ29TYXR1cmF0aW9uQW10OiB1aW50NjQKCT4KCWJ6ICppZjIzX2VuZAoKCS8vICppZjIzX2NvbnNlcXVlbnQKCS8vIGNvbnRyYWN0cy9zdGFraW5nUG9vbC5hbGdvLnRzOjU2NQoJLy8gbG9nKCd2YWxpZGF0b3IgaW4gc2F0dXJhdGVkIHN0YXRlJykKCWJ5dGUgMHg3NjYxNmM2OTY0NjE3NDZmNzIyMDY5NmUyMDczNjE3NDc1NzI2MTc0NjU2NDIwNzM3NDYxNzQ2NSAvLyAidmFsaWRhdG9yIGluIHNhdHVyYXRlZCBzdGF0ZSIKCWxvZwoKCS8vIGNvbnRyYWN0cy9zdGFraW5nUG9vbC5hbGdvLnRzOjU2NgoJLy8gaXNQb29sU2F0dXJhdGVkID0gdHJ1ZQoJaW50IDEKCWZyYW1lX2J1cnkgMTEgLy8gaXNQb29sU2F0dXJhdGVkOiBib29sCgoqaWYyM19lbmQ6CgkvLyBjb250cmFjdHMvc3Rha2luZ1Bvb2wuYWxnby50czo1NzIKCS8vIHRva2VuUmV3YXJkQXZhaWwgPSAwCglpbnQgMAoJZnJhbWVfYnVyeSAxMyAvLyB0b2tlblJld2FyZEF2YWlsOiB1aW50NjQKCgkvLyBjb250cmFjdHMvc3Rha2luZ1Bvb2wuYWxnby50czo1NzMKCS8vIHRva2VuUmV3YXJkUGFpZE91dCA9IDAKCWludCAwCglmcmFtZV9idXJ5IDE0IC8vIHRva2VuUmV3YXJkUGFpZE91dDogdWludDY0CgoJLy8gKmlmMjRfY29uZGl0aW9uCgkvLyBjb250cmFjdHMvc3Rha2luZ1Bvb2wuYWxnby50czo1NzQKCS8vIGlzVG9rZW5FbGlnaWJsZQoJZnJhbWVfZGlnIDQgLy8gaXNUb2tlbkVsaWdpYmxlOiBib29sCglieiAqaWYyNF9lbmQKCgkvLyAqaWYyNF9jb25zZXF1ZW50CgkvLyBjb250cmFjdHMvc3Rha2luZ1Bvb2wuYWxnby50czo1NzUKCS8vIHRva2VuUmV3YXJkQmFsID0KCS8vICAgICAgICAgICAgICAgICBwb29sT25lQWRkcmVzcy5hc3NldEJhbGFuY2UoQXNzZXRJRC5mcm9tVWludDY0KHZhbGlkYXRvckNvbmZpZy5yZXdhcmRUb2tlbklkKSkgLSByZXdhcmRUb2tlbkhlbGRCYWNrCglmcmFtZV9kaWcgNiAvLyBwb29sT25lQWRkcmVzczogYWRkcmVzcwoJZnJhbWVfZGlnIDAgLy8gdmFsaWRhdG9yQ29uZmlnOiAodWludDY0LGFkZHJlc3MsYWRkcmVzcyx1aW50NjQsdWludDgsYnl0ZVszMl0sdWludDY0LHVpbnQ2NCx1aW50NjQsdWludDE2LHVpbnQzMixhZGRyZXNzLHVpbnQ2NCx1aW50NjQsdWludDgsdWludDY0LHVpbnQ2NCkKCWV4dHJhY3QgMTIxIDgKCWJ0b2kKCWFzc2V0X2hvbGRpbmdfZ2V0IEFzc2V0QmFsYW5jZQoJcG9wCglmcmFtZV9kaWcgOSAvLyByZXdhcmRUb2tlbkhlbGRCYWNrOiB1aW50NjQKCS0KCWZyYW1lX2J1cnkgMTUgLy8gdG9rZW5SZXdhcmRCYWw6IHVpbnQ2NAoKCS8vICppZjI1X2NvbmRpdGlvbgoJLy8gY29udHJhY3RzL3N0YWtpbmdQb29sLmFsZ28udHM6NTgwCgkvLyB0b2tlblJld2FyZEJhbCA+PSB2YWxpZGF0b3JDb25maWcucmV3YXJkUGVyUGF5b3V0CglmcmFtZV9kaWcgMTUgLy8gdG9rZW5SZXdhcmRCYWw6IHVpbnQ2NAoJZnJhbWVfZGlnIDAgLy8gdmFsaWRhdG9yQ29uZmlnOiAodWludDY0LGFkZHJlc3MsYWRkcmVzcyx1aW50NjQsdWludDgsYnl0ZVszMl0sdWludDY0LHVpbnQ2NCx1aW50NjQsdWludDE2LHVpbnQzMixhZGRyZXNzLHVpbnQ2NCx1aW50NjQsdWludDgsdWludDY0LHVpbnQ2NCkKCWV4dHJhY3QgMTI5IDgKCWJ0b2kKCT49CglieiAqaWYyNV9lbmQKCgkvLyAqaWYyNV9jb25zZXF1ZW50CgkvLyBjb250cmFjdHMvc3Rha2luZ1Bvb2wuYWxnby50czo1ODQKCS8vIG91clBvb2xQY3RPZldob2xlID0gdG9rZW5QYXlvdXRSYXRpby5wb29sUGN0T2ZXaG9sZVt0aGlzLnBvb2xJZC52YWx1ZSAtIDFdCglmcmFtZV9kaWcgNyAvLyB0b2tlblBheW91dFJhdGlvOiBQb29sVG9rZW5QYXlvdXRSYXRpbwoJaW50IDAKCWJ5dGUgMHg3MDZmNmY2YzQ5NjQgLy8gInBvb2xJZCIKCWFwcF9nbG9iYWxfZ2V0CglpbnQgMQoJLQoJaW50IDgKCSogLy8gYWNjICogdHlwZUxlbmd0aAoJKwoJaW50IDgKCWV4dHJhY3QzCglidG9pCglmcmFtZV9idXJ5IDE2IC8vIG91clBvb2xQY3RPZldob2xlOiB1aW50NjQKCgkvLyBjb250cmFjdHMvc3Rha2luZ1Bvb2wuYWxnby50czo1ODcKCS8vIHRva2VuUmV3YXJkQXZhaWwgPSB3aWRlUmF0aW8oW3ZhbGlkYXRvckNvbmZpZy5yZXdhcmRQZXJQYXlvdXQsIG91clBvb2xQY3RPZldob2xlXSwgWzFfMDAwXzAwMF0pCglmcmFtZV9kaWcgMCAvLyB2YWxpZGF0b3JDb25maWc6ICh1aW50NjQsYWRkcmVzcyxhZGRyZXNzLHVpbnQ2NCx1aW50OCxieXRlWzMyXSx1aW50NjQsdWludDY0LHVpbnQ2NCx1aW50MTYsdWludDMyLGFkZHJlc3MsdWludDY0LHVpbnQ2NCx1aW50OCx1aW50NjQsdWludDY0KQoJZXh0cmFjdCAxMjkgOAoJYnRvaQoJZnJhbWVfZGlnIDE2IC8vIG91clBvb2xQY3RPZldob2xlOiB1aW50NjQKCW11bHcKCWludCAwCglpbnQgMV8wMDBfMDAwCglkaXZtb2R3Cglwb3AKCXBvcAoJc3dhcAoJIQoJYXNzZXJ0CglmcmFtZV9idXJ5IDEzIC8vIHRva2VuUmV3YXJkQXZhaWw6IHVpbnQ2NAoKCS8vIGNvbnRyYWN0cy9zdGFraW5nUG9vbC5hbGdvLnRzOjU5MQoJLy8gbG9nKGNvbmNhdCgndG9rZW4gcmV3YXJkIGF2YWlsOiAnLCB0b2tlblJld2FyZEF2YWlsLnRvU3RyaW5nKCkpKQoJYnl0ZSAweDc0NmY2YjY1NmUyMDcyNjU3NzYxNzI2NDIwNjE3NjYxNjk2YzNhMjAgLy8gInRva2VuIHJld2FyZCBhdmFpbDogIgoJZnJhbWVfZGlnIDEzIC8vIHRva2VuUmV3YXJkQXZhaWw6IHVpbnQ2NAoJY2FsbHN1YiAqaXRvYQoJY29uY2F0Cglsb2cKCippZjI1X2VuZDoKCippZjI0X2VuZDoKCS8vICppZjI2X2NvbmRpdGlvbgoJLy8gY29udHJhY3RzL3N0YWtpbmdQb29sLmFsZ28udHM6NTk1CgkvLyB0b2tlblJld2FyZEF2YWlsID09PSAwCglmcmFtZV9kaWcgMTMgLy8gdG9rZW5SZXdhcmRBdmFpbDogdWludDY0CglpbnQgMAoJPT0KCWJ6ICppZjI2X2VuZAoKCS8vICppZjI2X2NvbnNlcXVlbnQKCS8vIGNvbnRyYWN0cy9zdGFraW5nUG9vbC5hbGdvLnRzOjU5OAoJLy8gYXNzZXJ0KGFsZ29SZXdhcmRBdmFpbCA+IDFfMDAwXzAwMCwgJ1Jld2FyZCBuZWVkcyB0byBiZSBhdCBsZWFzdCAxIEFMR08nKQoJZnJhbWVfZGlnIDEwIC8vIGFsZ29SZXdhcmRBdmFpbDogdWludDY0CglpbnQgMV8wMDBfMDAwCgk+CgoJLy8gUmV3YXJkIG5lZWRzIHRvIGJlIGF0IGxlYXN0IDEgQUxHTwoJYXNzZXJ0CgoqaWYyNl9lbmQ6CgkvLyBjb250cmFjdHMvc3Rha2luZ1Bvb2wuYWxnby50czo2MDAKCS8vIGxvZyhjb25jYXQoJ2FsZ28gcmV3YXJkIGF2YWlsOiAnLCBhbGdvUmV3YXJkQXZhaWwudG9TdHJpbmcoKSkpCglieXRlIDB4NjE2YzY3NmYyMDcyNjU3NzYxNzI2NDIwNjE3NjYxNjk2YzNhMjAgLy8gImFsZ28gcmV3YXJkIGF2YWlsOiAiCglmcmFtZV9kaWcgMTAgLy8gYWxnb1Jld2FyZEF2YWlsOiB1aW50NjQKCWNhbGxzdWIgKml0b2EKCWNvbmNhdAoJbG9nCgoJLy8gKmlmMjdfY29uZGl0aW9uCgkvLyBjb250cmFjdHMvc3Rha2luZ1Bvb2wuYWxnby50czo2MDMKCS8vIGlzUG9vbFNhdHVyYXRlZAoJZnJhbWVfZGlnIDExIC8vIGlzUG9vbFNhdHVyYXRlZDogYm9vbAoJYnogKmlmMjdfZWxzZWlmMV9jb25kaXRpb24KCgkvLyAqaWYyN19jb25zZXF1ZW50CgkvLyBjb250cmFjdHMvc3Rha2luZ1Bvb2wuYWxnby50czo2MDYKCS8vIGRpbWluaXNoZWRSZXdhcmQgPSB3aWRlUmF0aW8oW2FsZ29SZXdhcmRBdmFpbCwgYWxnb1NhdHVyYXRpb25BbXRdLCBbdmFsaWRhdG9yU3RhdGUudG90YWxBbGdvU3Rha2VkXSkKCWZyYW1lX2RpZyAxMCAvLyBhbGdvUmV3YXJkQXZhaWw6IHVpbnQ2NAoJZnJhbWVfZGlnIDEyIC8vIGFsZ29TYXR1cmF0aW9uQW10OiB1aW50NjQKCW11bHcKCWludCAwCglmcmFtZV9kaWcgOCAvLyB2YWxpZGF0b3JTdGF0ZTogKHVpbnQxNix1aW50NjQsdWludDY0LHVpbnQ2NCkKCWV4dHJhY3QgMTAgOAoJYnRvaQoJZGl2bW9kdwoJcG9wCglwb3AKCXN3YXAKCSEKCWFzc2VydAoJZnJhbWVfYnVyeSAxNyAvLyBkaW1pbmlzaGVkUmV3YXJkOiB1aW50NjQKCgkvLyBjb250cmFjdHMvc3Rha2luZ1Bvb2wuYWxnby50czo2MDgKCS8vIGV4Y2Vzc1RvRmVlU2luayA9IGFsZ29SZXdhcmRBdmFpbCAtIGRpbWluaXNoZWRSZXdhcmQKCWZyYW1lX2RpZyAxMCAvLyBhbGdvUmV3YXJkQXZhaWw6IHVpbnQ2NAoJZnJhbWVfZGlnIDE3IC8vIGRpbWluaXNoZWRSZXdhcmQ6IHVpbnQ2NAoJLQoJZnJhbWVfYnVyeSAxOCAvLyBleGNlc3NUb0ZlZVNpbms6IHVpbnQ2NAoKCS8vIGNvbnRyYWN0cy9zdGFraW5nUG9vbC5hbGdvLnRzOjYwOQoJLy8gaW5jcmVhc2VPcGNvZGVCdWRnZXQoKQoJaXR4bl9iZWdpbgoJaW50IGFwcGwKCWl0eG5fZmllbGQgVHlwZUVudW0KCWludCAwCglpdHhuX2ZpZWxkIEZlZQoJYnl0ZSBiNjQgQ29FQiAvLyAjcHJhZ21hIHZlcnNpb24gMTA7IGludCAxCglkdXAKCWl0eG5fZmllbGQgQXBwcm92YWxQcm9ncmFtCglpdHhuX2ZpZWxkIENsZWFyU3RhdGVQcm9ncmFtCglpbnQgRGVsZXRlQXBwbGljYXRpb24KCWl0eG5fZmllbGQgT25Db21wbGV0aW9uCglpdHhuX3N1Ym1pdAoKCS8vIGNvbnRyYWN0cy9zdGFraW5nUG9vbC5hbGdvLnRzOjYxMAoJLy8gbG9nKGNvbmNhdCgnZGltIHJ3ZDogJywgZGltaW5pc2hlZFJld2FyZC50b1N0cmluZygpKSkKCWJ5dGUgMHg2NDY5NmQyMDcyNzc2NDNhMjAgLy8gImRpbSByd2Q6ICIKCWZyYW1lX2RpZyAxNyAvLyBkaW1pbmlzaGVkUmV3YXJkOiB1aW50NjQKCWNhbGxzdWIgKml0b2EKCWNvbmNhdAoJbG9nCgoJLy8gY29udHJhY3RzL3N0YWtpbmdQb29sLmFsZ28udHM6NjExCgkvLyBsb2coY29uY2F0KCd0byBzaW5rOiAnLCBleGNlc3NUb0ZlZVNpbmsudG9TdHJpbmcoKSkpCglieXRlIDB4NzQ2ZjIwNzM2OTZlNmIzYTIwIC8vICJ0byBzaW5rOiAiCglmcmFtZV9kaWcgMTggLy8gZXhjZXNzVG9GZWVTaW5rOiB1aW50NjQKCWNhbGxzdWIgKml0b2EKCWNvbmNhdAoJbG9nCgoJLy8gY29udHJhY3RzL3N0YWtpbmdQb29sLmFsZ28udHM6NjEyCgkvLyBzZW5kUGF5bWVudCh7CgkvLyAgICAgICAgICAgICAgICAgYW1vdW50OiBleGNlc3NUb0ZlZVNpbmssCgkvLyAgICAgICAgICAgICAgICAgcmVjZWl2ZXI6IHRoaXMuZ2V0RmVlU2luaygpLAoJLy8gICAgICAgICAgICAgICAgIG5vdGU6ICdwb29sIHNhdHVyYXRlZCwgcG9ydGlvbiBzZW50IGJhY2sgdG8gZmVlIHNpbmsnLAoJLy8gICAgICAgICAgICAgfSkKCWl0eG5fYmVnaW4KCWludCBwYXkKCWl0eG5fZmllbGQgVHlwZUVudW0KCgkvLyBjb250cmFjdHMvc3Rha2luZ1Bvb2wuYWxnby50czo2MTMKCS8vIGFtb3VudDogZXhjZXNzVG9GZWVTaW5rCglmcmFtZV9kaWcgMTggLy8gZXhjZXNzVG9GZWVTaW5rOiB1aW50NjQKCWl0eG5fZmllbGQgQW1vdW50CgoJLy8gY29udHJhY3RzL3N0YWtpbmdQb29sLmFsZ28udHM6NjE0CgkvLyByZWNlaXZlcjogdGhpcy5nZXRGZWVTaW5rKCkKCWNhbGxzdWIgZ2V0RmVlU2luawoJaXR4bl9maWVsZCBSZWNlaXZlcgoKCS8vIGNvbnRyYWN0cy9zdGFraW5nUG9vbC5hbGdvLnRzOjYxNQoJLy8gbm90ZTogJ3Bvb2wgc2F0dXJhdGVkLCBwb3J0aW9uIHNlbnQgYmFjayB0byBmZWUgc2luaycKCWJ5dGUgMHg3MDZmNmY2YzIwNzM2MTc0NzU3MjYxNzQ2NTY0MmMyMDcwNmY3Mjc0Njk2ZjZlMjA3MzY1NmU3NDIwNjI2MTYzNmIyMDc0NmYyMDY2NjU2NTIwNzM2OTZlNmIgLy8gInBvb2wgc2F0dXJhdGVkLCBwb3J0aW9uIHNlbnQgYmFjayB0byBmZWUgc2luayIKCWl0eG5fZmllbGQgTm90ZQoKCS8vIEZlZSBmaWVsZCBub3Qgc2V0LCBkZWZhdWx0aW5nIHRvIDAKCWludCAwCglpdHhuX2ZpZWxkIEZlZQoKCS8vIFN1Ym1pdCBpbm5lciB0cmFuc2FjdGlvbgoJaXR4bl9zdWJtaXQKCgkvLyBjb250cmFjdHMvc3Rha2luZ1Bvb2wuYWxnby50czo2MTgKCS8vIGFsZ29SZXdhcmRBdmFpbCA9IGRpbWluaXNoZWRSZXdhcmQKCWZyYW1lX2RpZyAxNyAvLyBkaW1pbmlzaGVkUmV3YXJkOiB1aW50NjQKCWZyYW1lX2J1cnkgMTAgLy8gYWxnb1Jld2FyZEF2YWlsOiB1aW50NjQKCWIgKmlmMjdfZW5kCgoqaWYyN19lbHNlaWYxX2NvbmRpdGlvbjoKCS8vIGNvbnRyYWN0cy9zdGFraW5nUG9vbC5hbGdvLnRzOjYxOQoJLy8gdmFsaWRhdG9yQ29uZmlnLnBlcmNlbnRUb1ZhbGlkYXRvciAhPT0gMAoJZnJhbWVfZGlnIDAgLy8gdmFsaWRhdG9yQ29uZmlnOiAodWludDY0LGFkZHJlc3MsYWRkcmVzcyx1aW50NjQsdWludDgsYnl0ZVszMl0sdWludDY0LHVpbnQ2NCx1aW50NjQsdWludDE2LHVpbnQzMixhZGRyZXNzLHVpbnQ2NCx1aW50NjQsdWludDgsdWludDY0LHVpbnQ2NCkKCWV4dHJhY3QgMTM5IDQKCWJ0b2kKCWludCAwCgkhPQoJYnogKmlmMjdfZW5kCgoJLy8gKmlmMjdfZWxzZWlmMV9jb25zZXF1ZW50CgkvLyBjb250cmFjdHMvc3Rha2luZ1Bvb2wuYWxnby50czo2MjIKCS8vIHZhbGlkYXRvclBheSA9IHdpZGVSYXRpbygKCS8vICAgICAgICAgICAgICAgICBbYWxnb1Jld2FyZEF2YWlsLCB2YWxpZGF0b3JDb25maWcucGVyY2VudFRvVmFsaWRhdG9yIGFzIHVpbnQ2NF0sCgkvLyAgICAgICAgICAgICAgICAgWzFfMDAwXzAwMF0KCS8vICAgICAgICAgICAgICkKCWZyYW1lX2RpZyAxMCAvLyBhbGdvUmV3YXJkQXZhaWw6IHVpbnQ2NAoJZnJhbWVfZGlnIDAgLy8gdmFsaWRhdG9yQ29uZmlnOiAodWludDY0LGFkZHJlc3MsYWRkcmVzcyx1aW50NjQsdWludDgsYnl0ZVszMl0sdWludDY0LHVpbnQ2NCx1aW50NjQsdWludDE2LHVpbnQzMixhZGRyZXNzLHVpbnQ2NCx1aW50NjQsdWludDgsdWludDY0LHVpbnQ2NCkKCWV4dHJhY3QgMTM5IDQKCWJ0b2kKCW11bHcKCWludCAwCglpbnQgMV8wMDBfMDAwCglkaXZtb2R3Cglwb3AKCXBvcAoJc3dhcAoJIQoJYXNzZXJ0CglmcmFtZV9idXJ5IDE5IC8vIHZhbGlkYXRvclBheTogdWludDY0CgoJLy8gY29udHJhY3RzL3N0YWtpbmdQb29sLmFsZ28udHM6NjI4CgkvLyBhbGdvUmV3YXJkQXZhaWwgLT0gdmFsaWRhdG9yUGF5CglmcmFtZV9kaWcgMTAgLy8gYWxnb1Jld2FyZEF2YWlsOiB1aW50NjQKCWZyYW1lX2RpZyAxOSAvLyB2YWxpZGF0b3JQYXk6IHVpbnQ2NAoJLQoJZnJhbWVfYnVyeSAxMCAvLyBhbGdvUmV3YXJkQXZhaWw6IHVpbnQ2NAoKCS8vICppZjI4X2NvbmRpdGlvbgoJLy8gY29udHJhY3RzL3N0YWtpbmdQb29sLmFsZ28udHM6NjMyCgkvLyB2YWxpZGF0b3JQYXkgPiAwCglmcmFtZV9kaWcgMTkgLy8gdmFsaWRhdG9yUGF5OiB1aW50NjQKCWludCAwCgk+CglieiAqaWYyOF9lbmQKCgkvLyAqaWYyOF9jb25zZXF1ZW50CgkvLyBjb250cmFjdHMvc3Rha2luZ1Bvb2wuYWxnby50czo2MzMKCS8vIGxvZyhjb25jYXQoJ3BheWluZyB2YWxpZGF0b3I6ICVpJywgaXRvYih2YWxpZGF0b3JQYXkpKSkKCWJ5dGUgMHg3MDYxNzk2OTZlNjcyMDc2NjE2YzY5NjQ2MTc0NmY3MjNhMjAyNTY5IC8vICJwYXlpbmcgdmFsaWRhdG9yOiAlaSIKCWZyYW1lX2RpZyAxOSAvLyB2YWxpZGF0b3JQYXk6IHVpbnQ2NAoJaXRvYgoJY29uY2F0Cglsb2cKCgkvLyBjb250cmFjdHMvc3Rha2luZ1Bvb2wuYWxnby50czo2MzQKCS8vIHNlbmRQYXltZW50KHsKCS8vICAgICAgICAgICAgICAgICAgICAgYW1vdW50OiB2YWxpZGF0b3JQYXksCgkvLyAgICAgICAgICAgICAgICAgICAgIHJlY2VpdmVyOiB2YWxpZGF0b3JDb25maWcudmFsaWRhdG9yQ29tbWlzc2lvbkFkZHJlc3MsCgkvLyAgICAgICAgICAgICAgICAgICAgIG5vdGU6ICd2YWxpZGF0b3IgcmV3YXJkJywKCS8vICAgICAgICAgICAgICAgICB9KQoJaXR4bl9iZWdpbgoJaW50IHBheQoJaXR4bl9maWVsZCBUeXBlRW51bQoKCS8vIGNvbnRyYWN0cy9zdGFraW5nUG9vbC5hbGdvLnRzOjYzNQoJLy8gYW1vdW50OiB2YWxpZGF0b3JQYXkKCWZyYW1lX2RpZyAxOSAvLyB2YWxpZGF0b3JQYXk6IHVpbnQ2NAoJaXR4bl9maWVsZCBBbW91bnQKCgkvLyBjb250cmFjdHMvc3Rha2luZ1Bvb2wuYWxnby50czo2MzYKCS8vIHJlY2VpdmVyOiB2YWxpZGF0b3JDb25maWcudmFsaWRhdG9yQ29tbWlzc2lvbkFkZHJlc3MKCWZyYW1lX2RpZyAwIC8vIHZhbGlkYXRvckNvbmZpZzogKHVpbnQ2NCxhZGRyZXNzLGFkZHJlc3MsdWludDY0LHVpbnQ4LGJ5dGVbMzJdLHVpbnQ2NCx1aW50NjQsdWludDY0LHVpbnQxNix1aW50MzIsYWRkcmVzcyx1aW50NjQsdWludDY0LHVpbnQ4LHVpbnQ2NCx1aW50NjQpCglleHRyYWN0IDE0MyAzMgoJaXR4bl9maWVsZCBSZWNlaXZlcgoKCS8vIGNvbnRyYWN0cy9zdGFraW5nUG9vbC5hbGdvLnRzOjYzNwoJLy8gbm90ZTogJ3ZhbGlkYXRvciByZXdhcmQnCglieXRlIDB4NzY2MTZjNjk2NDYxNzQ2ZjcyMjA3MjY1Nzc2MTcyNjQgLy8gInZhbGlkYXRvciByZXdhcmQiCglpdHhuX2ZpZWxkIE5vdGUKCgkvLyBGZWUgZmllbGQgbm90IHNldCwgZGVmYXVsdGluZyB0byAwCglpbnQgMAoJaXR4bl9maWVsZCBGZWUKCgkvLyBTdWJtaXQgaW5uZXIgdHJhbnNhY3Rpb24KCWl0eG5fc3VibWl0CgoJLy8gY29udHJhY3RzL3N0YWtpbmdQb29sLmFsZ28udHM6NjM5CgkvLyBsb2coY29uY2F0KCdyZW1haW5pbmcgcmV3YXJkOiAlaScsIGl0b2IoYWxnb1Jld2FyZEF2YWlsKSkpCglieXRlIDB4NzI2NTZkNjE2OTZlNjk2ZTY3MjA3MjY1Nzc2MTcyNjQzYTIwMjU2OSAvLyAicmVtYWluaW5nIHJld2FyZDogJWkiCglmcmFtZV9kaWcgMTAgLy8gYWxnb1Jld2FyZEF2YWlsOiB1aW50NjQKCWl0b2IKCWNvbmNhdAoJbG9nCgoqaWYyOF9lbmQ6CgoqaWYyN19lbmQ6CgkvLyAqaWYyOV9jb25kaXRpb24KCS8vIGNvbnRyYWN0cy9zdGFraW5nUG9vbC5hbGdvLnRzOjY0MwoJLy8gYWxnb1Jld2FyZEF2YWlsID09PSAwICYmIHRva2VuUmV3YXJkQXZhaWwgPT09IDAKCWZyYW1lX2RpZyAxMCAvLyBhbGdvUmV3YXJkQXZhaWw6IHVpbnQ2NAoJaW50IDAKCT09CglkdXAKCWJ6ICpza2lwX2FuZDMKCWZyYW1lX2RpZyAxMyAvLyB0b2tlblJld2FyZEF2YWlsOiB1aW50NjQKCWludCAwCgk9PQoJJiYKCipza2lwX2FuZDM6CglieiAqaWYyOV9lbmQKCgkvLyAqaWYyOV9jb25zZXF1ZW50CgkvLyBjb250cmFjdHMvc3Rha2luZ1Bvb2wuYWxnby50czo2NDYKCS8vIHJldHVybjsKCXJldHN1YgoKKmlmMjlfZW5kOgoJLy8gY29udHJhY3RzL3N0YWtpbmdQb29sLmFsZ28udHM6NjU0CgkvLyBpbmNyZWFzZWRTdGFrZSA9IDAKCWludCAwCglmcmFtZV9idXJ5IDIwIC8vIGluY3JlYXNlZFN0YWtlOiB1aW50NjQKCgkvLyBjb250cmFjdHMvc3Rha2luZ1Bvb2wuYWxnby50czo2NzgKCS8vIHBhcnRpYWxTdGFrZXJzVG90YWxTdGFrZTogdWludDY0ID0gMAoJaW50IDAKCWZyYW1lX2J1cnkgMjEgLy8gcGFydGlhbFN0YWtlcnNUb3RhbFN0YWtlOiB1aW50NjQKCgkvLyBjb250cmFjdHMvc3Rha2luZ1Bvb2wuYWxnby50czo2NzkKCS8vIGZvciAobGV0IGkgPSAwOyBpIDwgdGhpcy5zdGFrZXJzLnZhbHVlLmxlbmd0aDsgaSArPSAxKQoJaW50IDAKCWZyYW1lX2J1cnkgMjIgLy8gaTogdWludDY0CgoqZm9yXzQ6CgkvLyBjb250cmFjdHMvc3Rha2luZ1Bvb2wuYWxnby50czo2NzkKCS8vIGkgPCB0aGlzLnN0YWtlcnMudmFsdWUubGVuZ3RoCglmcmFtZV9kaWcgMjIgLy8gaTogdWludDY0CglpbnQgMjAwCgk8CglieiAqZm9yXzRfZW5kCgoJLy8gKmlmMzBfY29uZGl0aW9uCgkvLyBjb250cmFjdHMvc3Rha2luZ1Bvb2wuYWxnby50czo2ODAKCS8vIGdsb2JhbHMub3Bjb2RlQnVkZ2V0IDwgNDAwCglnbG9iYWwgT3Bjb2RlQnVkZ2V0CglpbnQgNDAwCgk8CglieiAqaWYzMF9lbmQKCgkvLyAqaWYzMF9jb25zZXF1ZW50CgkvLyBjb250cmFjdHMvc3Rha2luZ1Bvb2wuYWxnby50czo2ODEKCS8vIGluY3JlYXNlT3Bjb2RlQnVkZ2V0KCkKCWl0eG5fYmVnaW4KCWludCBhcHBsCglpdHhuX2ZpZWxkIFR5cGVFbnVtCglpbnQgMAoJaXR4bl9maWVsZCBGZWUKCWJ5dGUgYjY0IENvRUIgLy8gI3ByYWdtYSB2ZXJzaW9uIDEwOyBpbnQgMQoJZHVwCglpdHhuX2ZpZWxkIEFwcHJvdmFsUHJvZ3JhbQoJaXR4bl9maWVsZCBDbGVhclN0YXRlUHJvZ3JhbQoJaW50IERlbGV0ZUFwcGxpY2F0aW9uCglpdHhuX2ZpZWxkIE9uQ29tcGxldGlvbgoJaXR4bl9zdWJtaXQKCippZjMwX2VuZDoKCS8vIGNvbnRyYWN0cy9zdGFraW5nUG9vbC5hbGdvLnRzOjY4MwoJLy8gY21wU3Rha2VyID0gY2xvbmUodGhpcy5zdGFrZXJzLnZhbHVlW2ldKQoJZnJhbWVfZGlnIDIyIC8vIGk6IHVpbnQ2NAoJaW50IDY0CgkqIC8vIGFjYyAqIHR5cGVMZW5ndGgKCWludCA2NAoJYnl0ZSAweDczNzQ2MTZiNjU3MjczIC8vICJzdGFrZXJzIgoJY292ZXIgMgoJYm94X2V4dHJhY3QKCWZyYW1lX2J1cnkgMjMgLy8gY21wU3Rha2VyOiAoYWRkcmVzcyx1aW50NjQsdWludDY0LHVpbnQ2NCx1aW50NjQpCgoJLy8gKmlmMzFfY29uZGl0aW9uCgkvLyBjb250cmFjdHMvc3Rha2luZ1Bvb2wuYWxnby50czo2ODQKCS8vIGNtcFN0YWtlci5hY2NvdW50ICE9PSBnbG9iYWxzLnplcm9BZGRyZXNzCglmcmFtZV9kaWcgMjMgLy8gY21wU3Rha2VyOiAoYWRkcmVzcyx1aW50NjQsdWludDY0LHVpbnQ2NCx1aW50NjQpCglleHRyYWN0IDAgMzIKCWdsb2JhbCBaZXJvQWRkcmVzcwoJIT0KCWJ6ICppZjMxX2VuZAoKCS8vICppZjMxX2NvbnNlcXVlbnQKCS8vICppZjMyX2NvbmRpdGlvbgoJLy8gY29udHJhY3RzL3N0YWtpbmdQb29sLmFsZ28udHM6Njg1CgkvLyBjbXBTdGFrZXIuZW50cnlUaW1lID4gY3VyVGltZQoJZnJhbWVfZGlnIDIzIC8vIGNtcFN0YWtlcjogKGFkZHJlc3MsdWludDY0LHVpbnQ2NCx1aW50NjQsdWludDY0KQoJZXh0cmFjdCA1NiA4CglidG9pCglmcmFtZV9kaWcgMSAvLyBjdXJUaW1lOiB1aW50NjQKCT4KCWJ6ICppZjMyX2Vsc2UKCgkvLyAqaWYzMl9jb25zZXF1ZW50CgkvLyBjb250cmFjdHMvc3Rha2luZ1Bvb2wuYWxnby50czo2ODgKCS8vIHBhcnRpYWxTdGFrZXJzVG90YWxTdGFrZSArPSBjbXBTdGFrZXIuYmFsYW5jZQoJZnJhbWVfZGlnIDIxIC8vIHBhcnRpYWxTdGFrZXJzVG90YWxTdGFrZTogdWludDY0CglmcmFtZV9kaWcgMjMgLy8gY21wU3Rha2VyOiAoYWRkcmVzcyx1aW50NjQsdWludDY0LHVpbnQ2NCx1aW50NjQpCglleHRyYWN0IDMyIDgKCWJ0b2kKCSsKCWZyYW1lX2J1cnkgMjEgLy8gcGFydGlhbFN0YWtlcnNUb3RhbFN0YWtlOiB1aW50NjQKCWIgKmlmMzJfZW5kCgoqaWYzMl9lbHNlOgoJLy8gY29udHJhY3RzL3N0YWtpbmdQb29sLmFsZ28udHM6NjkyCgkvLyB0aW1lSW5Qb29sID0gY3VyVGltZSAtIGNtcFN0YWtlci5lbnRyeVRpbWUKCWZyYW1lX2RpZyAxIC8vIGN1clRpbWU6IHVpbnQ2NAoJZnJhbWVfZGlnIDIzIC8vIGNtcFN0YWtlcjogKGFkZHJlc3MsdWludDY0LHVpbnQ2NCx1aW50NjQsdWludDY0KQoJZXh0cmFjdCA1NiA4CglidG9pCgktCglmcmFtZV9idXJ5IDI0IC8vIHRpbWVJblBvb2w6IHVpbnQ2NAoKCS8vICppZjMzX2NvbmRpdGlvbgoJLy8gY29udHJhY3RzL3N0YWtpbmdQb29sLmFsZ28udHM6Njk2CgkvLyB0aW1lSW5Qb29sIDwgZXBvY2hJblNlY3MKCWZyYW1lX2RpZyAyNCAvLyB0aW1lSW5Qb29sOiB1aW50NjQKCWZyYW1lX2RpZyAyIC8vIGVwb2NoSW5TZWNzOiB1aW50NjQKCTwKCWJ6ICppZjMzX2VuZAoKCS8vICppZjMzX2NvbnNlcXVlbnQKCS8vIGNvbnRyYWN0cy9zdGFraW5nUG9vbC5hbGdvLnRzOjY5NwoJLy8gcGFydGlhbFN0YWtlcnNUb3RhbFN0YWtlICs9IGNtcFN0YWtlci5iYWxhbmNlCglmcmFtZV9kaWcgMjEgLy8gcGFydGlhbFN0YWtlcnNUb3RhbFN0YWtlOiB1aW50NjQKCWZyYW1lX2RpZyAyMyAvLyBjbXBTdGFrZXI6IChhZGRyZXNzLHVpbnQ2NCx1aW50NjQsdWludDY0LHVpbnQ2NCkKCWV4dHJhY3QgMzIgOAoJYnRvaQoJKwoJZnJhbWVfYnVyeSAyMSAvLyBwYXJ0aWFsU3Rha2Vyc1RvdGFsU3Rha2U6IHVpbnQ2NAoKCS8vIGNvbnRyYWN0cy9zdGFraW5nUG9vbC5hbGdvLnRzOjY5OAoJLy8gdGltZVBlcmNlbnRhZ2UgPSAodGltZUluUG9vbCAqIDEwMDApIC8gZXBvY2hJblNlY3MKCWZyYW1lX2RpZyAyNCAvLyB0aW1lSW5Qb29sOiB1aW50NjQKCWludCAxMDAwCgkqCglmcmFtZV9kaWcgMiAvLyBlcG9jaEluU2VjczogdWludDY0CgkvCglmcmFtZV9idXJ5IDI1IC8vIHRpbWVQZXJjZW50YWdlOiB1aW50NjQKCgkvLyAqaWYzNF9jb25kaXRpb24KCS8vIGNvbnRyYWN0cy9zdGFraW5nUG9vbC5hbGdvLnRzOjcwMQoJLy8gdG9rZW5SZXdhcmRBdmFpbCA+IDAKCWZyYW1lX2RpZyAxMyAvLyB0b2tlblJld2FyZEF2YWlsOiB1aW50NjQKCWludCAwCgk+CglieiAqaWYzNF9lbmQKCgkvLyAqaWYzNF9jb25zZXF1ZW50CgkvLyBjb250cmFjdHMvc3Rha2luZ1Bvb2wuYWxnby50czo3MDMKCS8vIHN0YWtlclRva2VuUmV3YXJkID0gd2lkZVJhdGlvKAoJLy8gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBbY21wU3Rha2VyLmJhbGFuY2UsIHRva2VuUmV3YXJkQXZhaWwsIHRpbWVQZXJjZW50YWdlXSwKCS8vICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgW3RoaXMudG90YWxBbGdvU3Rha2VkLnZhbHVlLCAxMDAwXQoJLy8gICAgICAgICAgICAgICAgICAgICAgICAgICAgICkKCWZyYW1lX2RpZyAyMyAvLyBjbXBTdGFrZXI6IChhZGRyZXNzLHVpbnQ2NCx1aW50NjQsdWludDY0LHVpbnQ2NCkKCWV4dHJhY3QgMzIgOAoJYnRvaQoJZnJhbWVfZGlnIDEzIC8vIHRva2VuUmV3YXJkQXZhaWw6IHVpbnQ2NAoJbXVsdwoJZnJhbWVfZGlnIDI1IC8vIHRpbWVQZXJjZW50YWdlOiB1aW50NjQKCXVuY292ZXIgMgoJZGlnIDEKCSoKCWNvdmVyIDIKCW11bHcKCWNvdmVyIDIKCSsKCXN3YXAKCWJ5dGUgMHg3Mzc0NjE2YjY1NjQgLy8gInN0YWtlZCIKCWFwcF9nbG9iYWxfZ2V0CglpbnQgMTAwMAoJbXVsdwoJZGl2bW9kdwoJcG9wCglwb3AKCXN3YXAKCSEKCWFzc2VydAoJZnJhbWVfYnVyeSAyNiAvLyBzdGFrZXJUb2tlblJld2FyZDogdWludDY0CgoJLy8gY29udHJhY3RzL3N0YWtpbmdQb29sLmFsZ28udHM6NzEwCgkvLyB0b2tlblJld2FyZEF2YWlsIC09IHN0YWtlclRva2VuUmV3YXJkCglmcmFtZV9kaWcgMTMgLy8gdG9rZW5SZXdhcmRBdmFpbDogdWludDY0CglmcmFtZV9kaWcgMjYgLy8gc3Rha2VyVG9rZW5SZXdhcmQ6IHVpbnQ2NAoJLQoJZnJhbWVfYnVyeSAxMyAvLyB0b2tlblJld2FyZEF2YWlsOiB1aW50NjQKCgkvLyBjb250cmFjdHMvc3Rha2luZ1Bvb2wuYWxnby50czo3MTEKCS8vIGNtcFN0YWtlci5yZXdhcmRUb2tlbkJhbGFuY2UgKz0gc3Rha2VyVG9rZW5SZXdhcmQKCWZyYW1lX2RpZyAyMyAvLyBjbXBTdGFrZXI6IChhZGRyZXNzLHVpbnQ2NCx1aW50NjQsdWludDY0LHVpbnQ2NCkKCWludCA0OCAvLyBoZWFkT2Zmc2V0CglmcmFtZV9kaWcgMjMgLy8gY21wU3Rha2VyOiAoYWRkcmVzcyx1aW50NjQsdWludDY0LHVpbnQ2NCx1aW50NjQpCglleHRyYWN0IDQ4IDgKCWJ0b2kKCWZyYW1lX2RpZyAyNiAvLyBzdGFrZXJUb2tlblJld2FyZDogdWludDY0CgkrCglpdG9iCglyZXBsYWNlMwoJZnJhbWVfYnVyeSAyMyAvLyBjbXBTdGFrZXI6IChhZGRyZXNzLHVpbnQ2NCx1aW50NjQsdWludDY0LHVpbnQ2NCkKCgkvLyBjb250cmFjdHMvc3Rha2luZ1Bvb2wuYWxnby50czo3MTIKCS8vIHRva2VuUmV3YXJkUGFpZE91dCArPSBzdGFrZXJUb2tlblJld2FyZAoJZnJhbWVfZGlnIDE0IC8vIHRva2VuUmV3YXJkUGFpZE91dDogdWludDY0CglmcmFtZV9kaWcgMjYgLy8gc3Rha2VyVG9rZW5SZXdhcmQ6IHVpbnQ2NAoJKwoJZnJhbWVfYnVyeSAxNCAvLyB0b2tlblJld2FyZFBhaWRPdXQ6IHVpbnQ2NAoKKmlmMzRfZW5kOgoJLy8gKmlmMzVfY29uZGl0aW9uCgkvLyBjb250cmFjdHMvc3Rha2luZ1Bvb2wuYWxnby50czo3MTQKCS8vIGFsZ29SZXdhcmRBdmFpbCA+IDAKCWZyYW1lX2RpZyAxMCAvLyBhbGdvUmV3YXJkQXZhaWw6IHVpbnQ2NAoJaW50IDAKCT4KCWJ6ICppZjM1X2VuZAoKCS8vICppZjM1X2NvbnNlcXVlbnQKCS8vIGNvbnRyYWN0cy9zdGFraW5nUG9vbC5hbGdvLnRzOjcxNgoJLy8gc3Rha2VyUmV3YXJkID0gd2lkZVJhdGlvKAoJLy8gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBbY21wU3Rha2VyLmJhbGFuY2UsIGFsZ29SZXdhcmRBdmFpbCwgdGltZVBlcmNlbnRhZ2VdLAoJLy8gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBbdGhpcy50b3RhbEFsZ29TdGFrZWQudmFsdWUsIDEwMDBdCgkvLyAgICAgICAgICAgICAgICAgICAgICAgICAgICAgKQoJZnJhbWVfZGlnIDIzIC8vIGNtcFN0YWtlcjogKGFkZHJlc3MsdWludDY0LHVpbnQ2NCx1aW50NjQsdWludDY0KQoJZXh0cmFjdCAzMiA4CglidG9pCglmcmFtZV9kaWcgMTAgLy8gYWxnb1Jld2FyZEF2YWlsOiB1aW50NjQKCW11bHcKCWZyYW1lX2RpZyAyNSAvLyB0aW1lUGVyY2VudGFnZTogdWludDY0Cgl1bmNvdmVyIDIKCWRpZyAxCgkqCgljb3ZlciAyCgltdWx3Cgljb3ZlciAyCgkrCglzd2FwCglieXRlIDB4NzM3NDYxNmI2NTY0IC8vICJzdGFrZWQiCglhcHBfZ2xvYmFsX2dldAoJaW50IDEwMDAKCW11bHcKCWRpdm1vZHcKCXBvcAoJcG9wCglzd2FwCgkhCglhc3NlcnQKCWZyYW1lX2J1cnkgMjcgLy8gc3Rha2VyUmV3YXJkOiB1aW50NjQKCgkvLyBjb250cmFjdHMvc3Rha2luZ1Bvb2wuYWxnby50czo3MjMKCS8vIGFsZ29SZXdhcmRBdmFpbCAtPSBzdGFrZXJSZXdhcmQKCWZyYW1lX2RpZyAxMCAvLyBhbGdvUmV3YXJkQXZhaWw6IHVpbnQ2NAoJZnJhbWVfZGlnIDI3IC8vIHN0YWtlclJld2FyZDogdWludDY0CgktCglmcmFtZV9idXJ5IDEwIC8vIGFsZ29SZXdhcmRBdmFpbDogdWludDY0CgoJLy8gY29udHJhY3RzL3N0YWtpbmdQb29sLmFsZ28udHM6NzI2CgkvLyBjbXBTdGFrZXIuYmFsYW5jZSArPSBzdGFrZXJSZXdhcmQKCWZyYW1lX2RpZyAyMyAvLyBjbXBTdGFrZXI6IChhZGRyZXNzLHVpbnQ2NCx1aW50NjQsdWludDY0LHVpbnQ2NCkKCWludCAzMiAvLyBoZWFkT2Zmc2V0CglmcmFtZV9kaWcgMjMgLy8gY21wU3Rha2VyOiAoYWRkcmVzcyx1aW50NjQsdWludDY0LHVpbnQ2NCx1aW50NjQpCglleHRyYWN0IDMyIDgKCWJ0b2kKCWZyYW1lX2RpZyAyNyAvLyBzdGFrZXJSZXdhcmQ6IHVpbnQ2NAoJKwoJaXRvYgoJcmVwbGFjZTMKCWZyYW1lX2J1cnkgMjMgLy8gY21wU3Rha2VyOiAoYWRkcmVzcyx1aW50NjQsdWludDY0LHVpbnQ2NCx1aW50NjQpCgoJLy8gY29udHJhY3RzL3N0YWtpbmdQb29sLmFsZ28udHM6NzI3CgkvLyBjbXBTdGFrZXIudG90YWxSZXdhcmRlZCArPSBzdGFrZXJSZXdhcmQKCWZyYW1lX2RpZyAyMyAvLyBjbXBTdGFrZXI6IChhZGRyZXNzLHVpbnQ2NCx1aW50NjQsdWludDY0LHVpbnQ2NCkKCWludCA0MCAvLyBoZWFkT2Zmc2V0CglmcmFtZV9kaWcgMjMgLy8gY21wU3Rha2VyOiAoYWRkcmVzcyx1aW50NjQsdWludDY0LHVpbnQ2NCx1aW50NjQpCglleHRyYWN0IDQwIDgKCWJ0b2kKCWZyYW1lX2RpZyAyNyAvLyBzdGFrZXJSZXdhcmQ6IHVpbnQ2NAoJKwoJaXRvYgoJcmVwbGFjZTMKCWZyYW1lX2J1cnkgMjMgLy8gY21wU3Rha2VyOiAoYWRkcmVzcyx1aW50NjQsdWludDY0LHVpbnQ2NCx1aW50NjQpCgoJLy8gY29udHJhY3RzL3N0YWtpbmdQb29sLmFsZ28udHM6NzI4CgkvLyBpbmNyZWFzZWRTdGFrZSArPSBzdGFrZXJSZXdhcmQKCWZyYW1lX2RpZyAyMCAvLyBpbmNyZWFzZWRTdGFrZTogdWludDY0CglmcmFtZV9kaWcgMjcgLy8gc3Rha2VyUmV3YXJkOiB1aW50NjQKCSsKCWZyYW1lX2J1cnkgMjAgLy8gaW5jcmVhc2VkU3Rha2U6IHVpbnQ2NAoKKmlmMzVfZW5kOgoJLy8gY29udHJhY3RzL3N0YWtpbmdQb29sLmFsZ28udHM6NzMxCgkvLyB0aGlzLnN0YWtlcnMudmFsdWVbaV0gPSBjbXBTdGFrZXIKCWZyYW1lX2RpZyAyMiAvLyBpOiB1aW50NjQKCWludCA2NAoJKiAvLyBhY2MgKiB0eXBlTGVuZ3RoCglmcmFtZV9kaWcgMjMgLy8gY21wU3Rha2VyOiAoYWRkcmVzcyx1aW50NjQsdWludDY0LHVpbnQ2NCx1aW50NjQpCglieXRlIDB4NzM3NDYxNmI2NTcyNzMgLy8gInN0YWtlcnMiCgljb3ZlciAyCglib3hfcmVwbGFjZQoKKmlmMzNfZW5kOgoKKmlmMzJfZW5kOgoKKmlmMzFfZW5kOgoKKmZvcl80X2NvbnRpbnVlOgoJLy8gY29udHJhY3RzL3N0YWtpbmdQb29sLmFsZ28udHM6Njc5CgkvLyBpICs9IDEKCWZyYW1lX2RpZyAyMiAvLyBpOiB1aW50NjQKCWludCAxCgkrCglmcmFtZV9idXJ5IDIyIC8vIGk6IHVpbnQ2NAoJYiAqZm9yXzQKCipmb3JfNF9lbmQ6CgkvLyBjb250cmFjdHMvc3Rha2luZ1Bvb2wuYWxnby50czo3MzYKCS8vIGxvZyhjb25jYXQoJ3BhcnRpYWwgc3Rha2VyIHRvdGFsIHN0YWtlOiAlaScsIGl0b2IocGFydGlhbFN0YWtlcnNUb3RhbFN0YWtlKSkpCglieXRlIDB4NzA2MTcyNzQ2OTYxNmMyMDczNzQ2MTZiNjU3MjIwNzQ2Zjc0NjE2YzIwNzM3NDYxNmI2NTNhMjAyNTY5IC8vICJwYXJ0aWFsIHN0YWtlciB0b3RhbCBzdGFrZTogJWkiCglmcmFtZV9kaWcgMjEgLy8gcGFydGlhbFN0YWtlcnNUb3RhbFN0YWtlOiB1aW50NjQKCWl0b2IKCWNvbmNhdAoJbG9nCgoJLy8gY29udHJhY3RzL3N0YWtpbmdQb29sLmFsZ28udHM6NzQwCgkvLyBuZXdQb29sVG90YWxTdGFrZSA9IHRoaXMudG90YWxBbGdvU3Rha2VkLnZhbHVlIC0gcGFydGlhbFN0YWtlcnNUb3RhbFN0YWtlCglieXRlIDB4NzM3NDYxNmI2NTY0IC8vICJzdGFrZWQiCglhcHBfZ2xvYmFsX2dldAoJZnJhbWVfZGlnIDIxIC8vIHBhcnRpYWxTdGFrZXJzVG90YWxTdGFrZTogdWludDY0CgktCglmcmFtZV9idXJ5IDI4IC8vIG5ld1Bvb2xUb3RhbFN0YWtlOiB1aW50NjQKCgkvLyAqaWYzNl9jb25kaXRpb24KCS8vIGNvbnRyYWN0cy9zdGFraW5nUG9vbC5hbGdvLnRzOjc0NAoJLy8gbmV3UG9vbFRvdGFsU3Rha2UgPiAwCglmcmFtZV9kaWcgMjggLy8gbmV3UG9vbFRvdGFsU3Rha2U6IHVpbnQ2NAoJaW50IDAKCT4KCWJ6ICppZjM2X2VuZAoKCS8vICppZjM2X2NvbnNlcXVlbnQKCS8vIGNvbnRyYWN0cy9zdGFraW5nUG9vbC5hbGdvLnRzOjc0NgoJLy8gZm9yIChsZXQgaSA9IDA7IGkgPCB0aGlzLnN0YWtlcnMudmFsdWUubGVuZ3RoOyBpICs9IDEpCglpbnQgMAoJZnJhbWVfYnVyeSAyOSAvLyBpOiB1aW50NjQKCipmb3JfNToKCS8vIGNvbnRyYWN0cy9zdGFraW5nUG9vbC5hbGdvLnRzOjc0NgoJLy8gaSA8IHRoaXMuc3Rha2Vycy52YWx1ZS5sZW5ndGgKCWZyYW1lX2RpZyAyOSAvLyBpOiB1aW50NjQKCWludCAyMDAKCTwKCWJ6ICpmb3JfNV9lbmQKCgkvLyAqaWYzN19jb25kaXRpb24KCS8vIGNvbnRyYWN0cy9zdGFraW5nUG9vbC5hbGdvLnRzOjc0NwoJLy8gZ2xvYmFscy5vcGNvZGVCdWRnZXQgPCAyMDAKCWdsb2JhbCBPcGNvZGVCdWRnZXQKCWludCAyMDAKCTwKCWJ6ICppZjM3X2VuZAoKCS8vICppZjM3X2NvbnNlcXVlbnQKCS8vIGNvbnRyYWN0cy9zdGFraW5nUG9vbC5hbGdvLnRzOjc0OAoJLy8gaW5jcmVhc2VPcGNvZGVCdWRnZXQoKQoJaXR4bl9iZWdpbgoJaW50IGFwcGwKCWl0eG5fZmllbGQgVHlwZUVudW0KCWludCAwCglpdHhuX2ZpZWxkIEZlZQoJYnl0ZSBiNjQgQ29FQiAvLyAjcHJhZ21hIHZlcnNpb24gMTA7IGludCAxCglkdXAKCWl0eG5fZmllbGQgQXBwcm92YWxQcm9ncmFtCglpdHhuX2ZpZWxkIENsZWFyU3RhdGVQcm9ncmFtCglpbnQgRGVsZXRlQXBwbGljYXRpb24KCWl0eG5fZmllbGQgT25Db21wbGV0aW9uCglpdHhuX3N1Ym1pdAoKKmlmMzdfZW5kOgoJLy8gY29udHJhY3RzL3N0YWtpbmdQb29sLmFsZ28udHM6NzUwCgkvLyBjbXBTdGFrZXIgPSBjbG9uZSh0aGlzLnN0YWtlcnMudmFsdWVbaV0pCglmcmFtZV9kaWcgMjkgLy8gaTogdWludDY0CglpbnQgNjQKCSogLy8gYWNjICogdHlwZUxlbmd0aAoJaW50IDY0CglieXRlIDB4NzM3NDYxNmI2NTcyNzMgLy8gInN0YWtlcnMiCgljb3ZlciAyCglib3hfZXh0cmFjdAoJZnJhbWVfYnVyeSAzMCAvLyBjbXBTdGFrZXI6IChhZGRyZXNzLHVpbnQ2NCx1aW50NjQsdWludDY0LHVpbnQ2NCkKCgkvLyAqaWYzOF9jb25kaXRpb24KCS8vIGNvbnRyYWN0cy9zdGFraW5nUG9vbC5hbGdvLnRzOjc1MQoJLy8gY21wU3Rha2VyLmFjY291bnQgIT09IGdsb2JhbHMuemVyb0FkZHJlc3MgJiYgY21wU3Rha2VyLmVudHJ5VGltZSA8IGN1clRpbWUKCWZyYW1lX2RpZyAzMCAvLyBjbXBTdGFrZXI6IChhZGRyZXNzLHVpbnQ2NCx1aW50NjQsdWludDY0LHVpbnQ2NCkKCWV4dHJhY3QgMCAzMgoJZ2xvYmFsIFplcm9BZGRyZXNzCgkhPQoJZHVwCglieiAqc2tpcF9hbmQ0CglmcmFtZV9kaWcgMzAgLy8gY21wU3Rha2VyOiAoYWRkcmVzcyx1aW50NjQsdWludDY0LHVpbnQ2NCx1aW50NjQpCglleHRyYWN0IDU2IDgKCWJ0b2kKCWZyYW1lX2RpZyAxIC8vIGN1clRpbWU6IHVpbnQ2NAoJPAoJJiYKCipza2lwX2FuZDQ6CglieiAqaWYzOF9lbmQKCgkvLyAqaWYzOF9jb25zZXF1ZW50CgkvLyBjb250cmFjdHMvc3Rha2luZ1Bvb2wuYWxnby50czo3NTIKCS8vIHRpbWVJblBvb2wgPSBjdXJUaW1lIC0gY21wU3Rha2VyLmVudHJ5VGltZQoJZnJhbWVfZGlnIDEgLy8gY3VyVGltZTogdWludDY0CglmcmFtZV9kaWcgMzAgLy8gY21wU3Rha2VyOiAoYWRkcmVzcyx1aW50NjQsdWludDY0LHVpbnQ2NCx1aW50NjQpCglleHRyYWN0IDU2IDgKCWJ0b2kKCS0KCWZyYW1lX2J1cnkgMzEgLy8gdGltZUluUG9vbDogdWludDY0CgoJLy8gKmlmMzlfY29uZGl0aW9uCgkvLyBjb250cmFjdHMvc3Rha2luZ1Bvb2wuYWxnby50czo3NTQKCS8vIHRpbWVJblBvb2wgPj0gZXBvY2hJblNlY3MKCWZyYW1lX2RpZyAzMSAvLyB0aW1lSW5Qb29sOiB1aW50NjQKCWZyYW1lX2RpZyAyIC8vIGVwb2NoSW5TZWNzOiB1aW50NjQKCT49CglieiAqaWYzOV9lbmQKCgkvLyAqaWYzOV9jb25zZXF1ZW50CgkvLyAqaWY0MF9jb25kaXRpb24KCS8vIGNvbnRyYWN0cy9zdGFraW5nUG9vbC5hbGdvLnRzOjc1OQoJLy8gdG9rZW5SZXdhcmRBdmFpbCA+IDAKCWZyYW1lX2RpZyAxMyAvLyB0b2tlblJld2FyZEF2YWlsOiB1aW50NjQKCWludCAwCgk+CglieiAqaWY0MF9lbmQKCgkvLyAqaWY0MF9jb25zZXF1ZW50CgkvLyBjb250cmFjdHMvc3Rha2luZ1Bvb2wuYWxnby50czo3NjYKCS8vIHN0YWtlclRva2VuUmV3YXJkID0gd2lkZVJhdGlvKAoJLy8gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBbY21wU3Rha2VyLmJhbGFuY2UsIHRva2VuUmV3YXJkQXZhaWxdLAoJLy8gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBbbmV3UG9vbFRvdGFsU3Rha2VdCgkvLyAgICAgICAgICAgICAgICAgICAgICAgICAgICAgKQoJZnJhbWVfZGlnIDMwIC8vIGNtcFN0YWtlcjogKGFkZHJlc3MsdWludDY0LHVpbnQ2NCx1aW50NjQsdWludDY0KQoJZXh0cmFjdCAzMiA4CglidG9pCglmcmFtZV9kaWcgMTMgLy8gdG9rZW5SZXdhcmRBdmFpbDogdWludDY0CgltdWx3CglpbnQgMAoJZnJhbWVfZGlnIDI4IC8vIG5ld1Bvb2xUb3RhbFN0YWtlOiB1aW50NjQKCWRpdm1vZHcKCXBvcAoJcG9wCglzd2FwCgkhCglhc3NlcnQKCWZyYW1lX2J1cnkgMzIgLy8gc3Rha2VyVG9rZW5SZXdhcmQ6IHVpbnQ2NAoKCS8vIGNvbnRyYWN0cy9zdGFraW5nUG9vbC5hbGdvLnRzOjc3NQoJLy8gY21wU3Rha2VyLnJld2FyZFRva2VuQmFsYW5jZSArPSBzdGFrZXJUb2tlblJld2FyZAoJZnJhbWVfZGlnIDMwIC8vIGNtcFN0YWtlcjogKGFkZHJlc3MsdWludDY0LHVpbnQ2NCx1aW50NjQsdWludDY0KQoJaW50IDQ4IC8vIGhlYWRPZmZzZXQKCWZyYW1lX2RpZyAzMCAvLyBjbXBTdGFrZXI6IChhZGRyZXNzLHVpbnQ2NCx1aW50NjQsdWludDY0LHVpbnQ2NCkKCWV4dHJhY3QgNDggOAoJYnRvaQoJZnJhbWVfZGlnIDMyIC8vIHN0YWtlclRva2VuUmV3YXJkOiB1aW50NjQKCSsKCWl0b2IKCXJlcGxhY2UzCglmcmFtZV9idXJ5IDMwIC8vIGNtcFN0YWtlcjogKGFkZHJlc3MsdWludDY0LHVpbnQ2NCx1aW50NjQsdWludDY0KQoKCS8vIGNvbnRyYWN0cy9zdGFraW5nUG9vbC5hbGdvLnRzOjc3NgoJLy8gdG9rZW5SZXdhcmRQYWlkT3V0ICs9IHN0YWtlclRva2VuUmV3YXJkCglmcmFtZV9kaWcgMTQgLy8gdG9rZW5SZXdhcmRQYWlkT3V0OiB1aW50NjQKCWZyYW1lX2RpZyAzMiAvLyBzdGFrZXJUb2tlblJld2FyZDogdWludDY0CgkrCglmcmFtZV9idXJ5IDE0IC8vIHRva2VuUmV3YXJkUGFpZE91dDogdWludDY0CgoqaWY0MF9lbmQ6CgkvLyAqaWY0MV9jb25kaXRpb24KCS8vIGNvbnRyYWN0cy9zdGFraW5nUG9vbC5hbGdvLnRzOjc3OAoJLy8gYWxnb1Jld2FyZEF2YWlsID4gMAoJZnJhbWVfZGlnIDEwIC8vIGFsZ29SZXdhcmRBdmFpbDogdWludDY0CglpbnQgMAoJPgoJYnogKmlmNDFfZW5kCgoJLy8gKmlmNDFfY29uc2VxdWVudAoJLy8gY29udHJhY3RzL3N0YWtpbmdQb29sLmFsZ28udHM6Nzc5CgkvLyBzdGFrZXJSZXdhcmQgPSB3aWRlUmF0aW8oW2NtcFN0YWtlci5iYWxhbmNlLCBhbGdvUmV3YXJkQXZhaWxdLCBbbmV3UG9vbFRvdGFsU3Rha2VdKQoJZnJhbWVfZGlnIDMwIC8vIGNtcFN0YWtlcjogKGFkZHJlc3MsdWludDY0LHVpbnQ2NCx1aW50NjQsdWludDY0KQoJZXh0cmFjdCAzMiA4CglidG9pCglmcmFtZV9kaWcgMTAgLy8gYWxnb1Jld2FyZEF2YWlsOiB1aW50NjQKCW11bHcKCWludCAwCglmcmFtZV9kaWcgMjggLy8gbmV3UG9vbFRvdGFsU3Rha2U6IHVpbnQ2NAoJZGl2bW9kdwoJcG9wCglwb3AKCXN3YXAKCSEKCWFzc2VydAoJZnJhbWVfYnVyeSAzMyAvLyBzdGFrZXJSZXdhcmQ6IHVpbnQ2NAoKCS8vIGNvbnRyYWN0cy9zdGFraW5nUG9vbC5hbGdvLnRzOjc4MgoJLy8gY21wU3Rha2VyLmJhbGFuY2UgKz0gc3Rha2VyUmV3YXJkCglmcmFtZV9kaWcgMzAgLy8gY21wU3Rha2VyOiAoYWRkcmVzcyx1aW50NjQsdWludDY0LHVpbnQ2NCx1aW50NjQpCglpbnQgMzIgLy8gaGVhZE9mZnNldAoJZnJhbWVfZGlnIDMwIC8vIGNtcFN0YWtlcjogKGFkZHJlc3MsdWludDY0LHVpbnQ2NCx1aW50NjQsdWludDY0KQoJZXh0cmFjdCAzMiA4CglidG9pCglmcmFtZV9kaWcgMzMgLy8gc3Rha2VyUmV3YXJkOiB1aW50NjQKCSsKCWl0b2IKCXJlcGxhY2UzCglmcmFtZV9idXJ5IDMwIC8vIGNtcFN0YWtlcjogKGFkZHJlc3MsdWludDY0LHVpbnQ2NCx1aW50NjQsdWludDY0KQoKCS8vIGNvbnRyYWN0cy9zdGFraW5nUG9vbC5hbGdvLnRzOjc4MwoJLy8gY21wU3Rha2VyLnRvdGFsUmV3YXJkZWQgKz0gc3Rha2VyUmV3YXJkCglmcmFtZV9kaWcgMzAgLy8gY21wU3Rha2VyOiAoYWRkcmVzcyx1aW50NjQsdWludDY0LHVpbnQ2NCx1aW50NjQpCglpbnQgNDAgLy8gaGVhZE9mZnNldAoJZnJhbWVfZGlnIDMwIC8vIGNtcFN0YWtlcjogKGFkZHJlc3MsdWludDY0LHVpbnQ2NCx1aW50NjQsdWludDY0KQoJZXh0cmFjdCA0MCA4CglidG9pCglmcmFtZV9kaWcgMzMgLy8gc3Rha2VyUmV3YXJkOiB1aW50NjQKCSsKCWl0b2IKCXJlcGxhY2UzCglmcmFtZV9idXJ5IDMwIC8vIGNtcFN0YWtlcjogKGFkZHJlc3MsdWludDY0LHVpbnQ2NCx1aW50NjQsdWludDY0KQoKCS8vIGNvbnRyYWN0cy9zdGFraW5nUG9vbC5hbGdvLnRzOjc4NAoJLy8gaW5jcmVhc2VkU3Rha2UgKz0gc3Rha2VyUmV3YXJkCglmcmFtZV9kaWcgMjAgLy8gaW5jcmVhc2VkU3Rha2U6IHVpbnQ2NAoJZnJhbWVfZGlnIDMzIC8vIHN0YWtlclJld2FyZDogdWludDY0CgkrCglmcmFtZV9idXJ5IDIwIC8vIGluY3JlYXNlZFN0YWtlOiB1aW50NjQKCippZjQxX2VuZDoKCS8vIGNvbnRyYWN0cy9zdGFraW5nUG9vbC5hbGdvLnRzOjc4OAoJLy8gdGhpcy5zdGFrZXJzLnZhbHVlW2ldID0gY21wU3Rha2VyCglmcmFtZV9kaWcgMjkgLy8gaTogdWludDY0CglpbnQgNjQKCSogLy8gYWNjICogdHlwZUxlbmd0aAoJZnJhbWVfZGlnIDMwIC8vIGNtcFN0YWtlcjogKGFkZHJlc3MsdWludDY0LHVpbnQ2NCx1aW50NjQsdWludDY0KQoJYnl0ZSAweDczNzQ2MTZiNjU3MjczIC8vICJzdGFrZXJzIgoJY292ZXIgMgoJYm94X3JlcGxhY2UKCippZjM5X2VuZDoKCippZjM4X2VuZDoKCipmb3JfNV9jb250aW51ZToKCS8vIGNvbnRyYWN0cy9zdGFraW5nUG9vbC5hbGdvLnRzOjc0NgoJLy8gaSArPSAxCglmcmFtZV9kaWcgMjkgLy8gaTogdWludDY0CglpbnQgMQoJKwoJZnJhbWVfYnVyeSAyOSAvLyBpOiB1aW50NjQKCWIgKmZvcl81CgoqZm9yXzVfZW5kOgoKKmlmMzZfZW5kOgoJLy8gY29udHJhY3RzL3N0YWtpbmdQb29sLmFsZ28udHM6Nzk2CgkvLyB0aGlzLnRvdGFsQWxnb1N0YWtlZC52YWx1ZSArPSBpbmNyZWFzZWRTdGFrZQoJYnl0ZSAweDczNzQ2MTZiNjU2NCAvLyAic3Rha2VkIgoJYXBwX2dsb2JhbF9nZXQKCWZyYW1lX2RpZyAyMCAvLyBpbmNyZWFzZWRTdGFrZTogdWludDY0CgkrCglieXRlIDB4NzM3NDYxNmI2NTY0IC8vICJzdGFrZWQiCglzd2FwCglhcHBfZ2xvYmFsX3B1dAoKCS8vIGNvbnRyYWN0cy9zdGFraW5nUG9vbC5hbGdvLnRzOjc5OAoJLy8gbG9nKGNvbmNhdCgnaW5jciBzdGFrZTogJWknLCBpdG9iKGluY3JlYXNlZFN0YWtlKSkpCglieXRlIDB4Njk2ZTYzNzIyMDczNzQ2MTZiNjUzYTIwMjU2OSAvLyAiaW5jciBzdGFrZTogJWkiCglmcmFtZV9kaWcgMjAgLy8gaW5jcmVhc2VkU3Rha2U6IHVpbnQ2NAoJaXRvYgoJY29uY2F0Cglsb2cKCgkvLyBjb250cmFjdHMvc3Rha2luZ1Bvb2wuYWxnby50czo3OTkKCS8vIGxvZyhjb25jYXQoJ3Rvay4gcndkIHBhaWQ6ICVpJywgaXRvYih0b2tlblJld2FyZFBhaWRPdXQpKSkKCWJ5dGUgMHg3NDZmNmIyZTIwNzI3NzY0MjA3MDYxNjk2NDNhMjAyNTY5IC8vICJ0b2suIHJ3ZCBwYWlkOiAlaSIKCWZyYW1lX2RpZyAxNCAvLyB0b2tlblJld2FyZFBhaWRPdXQ6IHVpbnQ2NAoJaXRvYgoJY29uY2F0Cglsb2cKCgkvLyBjb250cmFjdHMvc3Rha2luZ1Bvb2wuYWxnby50czo4MDQKCS8vIHNlbmRNZXRob2RDYWxsPHR5cGVvZiBWYWxpZGF0b3JSZWdpc3RyeS5wcm90b3R5cGUuc3Rha2VVcGRhdGVkVmlhUmV3YXJkcz4oewoJLy8gICAgICAgICAgICAgYXBwbGljYXRpb25JRDogQXBwSUQuZnJvbVVpbnQ2NCh0aGlzLmNyZWF0aW5nVmFsaWRhdG9yQ29udHJhY3RBcHBJZC52YWx1ZSksCgkvLyAgICAgICAgICAgICBtZXRob2RBcmdzOiBbCgkvLyAgICAgICAgICAgICAgICAgeyBpZDogdGhpcy52YWxpZGF0b3JJZC52YWx1ZSwgcG9vbElkOiB0aGlzLnBvb2xJZC52YWx1ZSwgcG9vbEFwcElkOiB0aGlzLmFwcC5pZCB9LAoJLy8gICAgICAgICAgICAgICAgIGluY3JlYXNlZFN0YWtlLAoJLy8gICAgICAgICAgICAgICAgIHRva2VuUmV3YXJkUGFpZE91dCwKCS8vICAgICAgICAgICAgIF0sCgkvLyAgICAgICAgIH0pCglpdHhuX2JlZ2luCglpbnQgYXBwbAoJaXR4bl9maWVsZCBUeXBlRW51bQoJbWV0aG9kICJzdGFrZVVwZGF0ZWRWaWFSZXdhcmRzKCh1aW50NjQsdWludDY0LHVpbnQ2NCksdWludDY0LHVpbnQ2NCl2b2lkIgoJaXR4bl9maWVsZCBBcHBsaWNhdGlvbkFyZ3MKCgkvLyBjb250cmFjdHMvc3Rha2luZ1Bvb2wuYWxnby50czo4MDUKCS8vIGFwcGxpY2F0aW9uSUQ6IEFwcElELmZyb21VaW50NjQodGhpcy5jcmVhdGluZ1ZhbGlkYXRvckNvbnRyYWN0QXBwSWQudmFsdWUpCglieXRlIDB4NjM3MjY1NjE3NDZmNzI0MTcwNzAgLy8gImNyZWF0b3JBcHAiCglhcHBfZ2xvYmFsX2dldAoJaXR4bl9maWVsZCBBcHBsaWNhdGlvbklECgoJLy8gY29udHJhY3RzL3N0YWtpbmdQb29sLmFsZ28udHM6ODA2CgkvLyBtZXRob2RBcmdzOiBbCgkvLyAgICAgICAgICAgICAgICAgeyBpZDogdGhpcy52YWxpZGF0b3JJZC52YWx1ZSwgcG9vbElkOiB0aGlzLnBvb2xJZC52YWx1ZSwgcG9vbEFwcElkOiB0aGlzLmFwcC5pZCB9LAoJLy8gICAgICAgICAgICAgICAgIGluY3JlYXNlZFN0YWtlLAoJLy8gICAgICAgICAgICAgICAgIHRva2VuUmV3YXJkUGFpZE91dCwKCS8vICAgICAgICAgICAgIF0KCWJ5dGUgMHg3NjYxNmM2OTY0NjE3NDZmNzI0OTY0IC8vICJ2YWxpZGF0b3JJZCIKCWFwcF9nbG9iYWxfZ2V0CglpdG9iCglieXRlIDB4NzA2ZjZmNmM0OTY0IC8vICJwb29sSWQiCglhcHBfZ2xvYmFsX2dldAoJaXRvYgoJY29uY2F0Cgl0eG5hIEFwcGxpY2F0aW9ucyAwCglpdG9iCgljb25jYXQKCWl0eG5fZmllbGQgQXBwbGljYXRpb25BcmdzCglmcmFtZV9kaWcgMjAgLy8gaW5jcmVhc2VkU3Rha2U6IHVpbnQ2NAoJaXRvYgoJaXR4bl9maWVsZCBBcHBsaWNhdGlvbkFyZ3MKCWZyYW1lX2RpZyAxNCAvLyB0b2tlblJld2FyZFBhaWRPdXQ6IHVpbnQ2NAoJaXRvYgoJaXR4bl9maWVsZCBBcHBsaWNhdGlvbkFyZ3MKCgkvLyBGZWUgZmllbGQgbm90IHNldCwgZGVmYXVsdGluZyB0byAwCglpbnQgMAoJaXR4bl9maWVsZCBGZWUKCgkvLyBTdWJtaXQgaW5uZXIgdHJhbnNhY3Rpb24KCWl0eG5fc3VibWl0CglyZXRzdWIKCi8vIGdvT25saW5lKGJ5dGVbXSxieXRlW10sYnl0ZVtdLHVpbnQ2NCx1aW50NjQsdWludDY0KXZvaWQKKmFiaV9yb3V0ZV9nb09ubGluZToKCS8vIHZvdGVLZXlEaWx1dGlvbjogdWludDY0Cgl0eG5hIEFwcGxpY2F0aW9uQXJncyA2CglidG9pCgoJLy8gdm90ZUxhc3Q6IHVpbnQ2NAoJdHhuYSBBcHBsaWNhdGlvbkFyZ3MgNQoJYnRvaQoKCS8vIHZvdGVGaXJzdDogdWludDY0Cgl0eG5hIEFwcGxpY2F0aW9uQXJncyA0CglidG9pCgoJLy8gc3RhdGVQcm9vZlBLOiBieXRlW10KCXR4bmEgQXBwbGljYXRpb25BcmdzIDMKCWV4dHJhY3QgMiAwCgoJLy8gc2VsZWN0aW9uUEs6IGJ5dGVbXQoJdHhuYSBBcHBsaWNhdGlvbkFyZ3MgMgoJZXh0cmFjdCAyIDAKCgkvLyB2b3RlUEs6IGJ5dGVbXQoJdHhuYSBBcHBsaWNhdGlvbkFyZ3MgMQoJZXh0cmFjdCAyIDAKCgkvLyBleGVjdXRlIGdvT25saW5lKGJ5dGVbXSxieXRlW10sYnl0ZVtdLHVpbnQ2NCx1aW50NjQsdWludDY0KXZvaWQKCWNhbGxzdWIgZ29PbmxpbmUKCWludCAxCglyZXR1cm4KCi8vIGdvT25saW5lKHZvdGVQSzogYnl0ZXMsIHNlbGVjdGlvblBLOiBieXRlcywgc3RhdGVQcm9vZlBLOiBieXRlcywgdm90ZUZpcnN0OiB1aW50NjQsIHZvdGVMYXN0OiB1aW50NjQsIHZvdGVLZXlEaWx1dGlvbjogdWludDY0KTogdm9pZAovLwovLyBSZWdpc3RlcnMgYSBzdGFraW5nIHBvb2wga2V5IG9ubGluZSBhZ2FpbnN0IGEgcGFydGljaXBhdGlvbiBrZXkuCi8vIFsgT05MWSBPV05FUiBPUiBNQU5BR0VSIENBTiBDQUxMIF0KLy8KLy8gQHBhcmFtIHtieXRlc30gdm90ZVBLIC0gVGhlIHZvdGUgcHVibGljIGtleS4KLy8gQHBhcmFtIHtieXRlc30gc2VsZWN0aW9uUEsgLSBUaGUgc2VsZWN0aW9uIHB1YmxpYyBrZXkuCi8vIEBwYXJhbSB7Ynl0ZXN9IHN0YXRlUHJvb2ZQSyAtIFRoZSBzdGF0ZSBwcm9vZiBwdWJsaWMga2V5LgovLyBAcGFyYW0ge3VpbnQ2NH0gdm90ZUZpcnN0IC0gVGhlIGZpcnN0IHZvdGUgaW5kZXguCi8vIEBwYXJhbSB7dWludDY0fSB2b3RlTGFzdCAtIFRoZSBsYXN0IHZvdGUgaW5kZXguCi8vIEBwYXJhbSB7dWludDY0fSB2b3RlS2V5RGlsdXRpb24gLSBUaGUgdm90ZSBrZXkgZGlsdXRpb24gdmFsdWUuCi8vIEB0aHJvd3Mge0Vycm9yfSBXaWxsIHRocm93IGFuIGVycm9yIGlmIHRoZSBjYWxsZXIgaXMgbm90IHRoZSBvd25lciBvciBhIG1hbmFnZXIuCmdvT25saW5lOgoJcHJvdG8gNiAwCgoJLy8gY29udHJhY3RzL3N0YWtpbmdQb29sLmFsZ28udHM6ODM0CgkvLyBhc3NlcnQodGhpcy5pc093bmVyT3JNYW5hZ2VyQ2FsbGVyKCkpCgljYWxsc3ViIGlzT3duZXJPck1hbmFnZXJDYWxsZXIKCWFzc2VydAoKCS8vIGNvbnRyYWN0cy9zdGFraW5nUG9vbC5hbGdvLnRzOjgzNQoJLy8gc2VuZE9ubGluZUtleVJlZ2lzdHJhdGlvbih7CgkvLyAgICAgICAgICAgICB2b3RlUEs6IHZvdGVQSywKCS8vICAgICAgICAgICAgIHNlbGVjdGlvblBLOiBzZWxlY3Rpb25QSywKCS8vICAgICAgICAgICAgIHN0YXRlUHJvb2ZQSzogc3RhdGVQcm9vZlBLLAoJLy8gICAgICAgICAgICAgdm90ZUZpcnN0OiB2b3RlRmlyc3QsCgkvLyAgICAgICAgICAgICB2b3RlTGFzdDogdm90ZUxhc3QsCgkvLyAgICAgICAgICAgICB2b3RlS2V5RGlsdXRpb246IHZvdGVLZXlEaWx1dGlvbiwKCS8vICAgICAgICAgfSkKCWl0eG5fYmVnaW4KCWludCBrZXlyZWcKCWl0eG5fZmllbGQgVHlwZUVudW0KCgkvLyBjb250cmFjdHMvc3Rha2luZ1Bvb2wuYWxnby50czo4MzYKCS8vIHZvdGVQSzogdm90ZVBLCglmcmFtZV9kaWcgLTEgLy8gdm90ZVBLOiBieXRlcwoJaXR4bl9maWVsZCBWb3RlUEsKCgkvLyBjb250cmFjdHMvc3Rha2luZ1Bvb2wuYWxnby50czo4MzcKCS8vIHNlbGVjdGlvblBLOiBzZWxlY3Rpb25QSwoJZnJhbWVfZGlnIC0yIC8vIHNlbGVjdGlvblBLOiBieXRlcwoJaXR4bl9maWVsZCBTZWxlY3Rpb25QSwoKCS8vIGNvbnRyYWN0cy9zdGFraW5nUG9vbC5hbGdvLnRzOjgzOAoJLy8gc3RhdGVQcm9vZlBLOiBzdGF0ZVByb29mUEsKCWZyYW1lX2RpZyAtMyAvLyBzdGF0ZVByb29mUEs6IGJ5dGVzCglpdHhuX2ZpZWxkIFN0YXRlUHJvb2ZQSwoKCS8vIGNvbnRyYWN0cy9zdGFraW5nUG9vbC5hbGdvLnRzOjgzOQoJLy8gdm90ZUZpcnN0OiB2b3RlRmlyc3QKCWZyYW1lX2RpZyAtNCAvLyB2b3RlRmlyc3Q6IHVpbnQ2NAoJaXR4bl9maWVsZCBWb3RlRmlyc3QKCgkvLyBjb250cmFjdHMvc3Rha2luZ1Bvb2wuYWxnby50czo4NDAKCS8vIHZvdGVMYXN0OiB2b3RlTGFzdAoJZnJhbWVfZGlnIC01IC8vIHZvdGVMYXN0OiB1aW50NjQKCWl0eG5fZmllbGQgVm90ZUxhc3QKCgkvLyBjb250cmFjdHMvc3Rha2luZ1Bvb2wuYWxnby50czo4NDEKCS8vIHZvdGVLZXlEaWx1dGlvbjogdm90ZUtleURpbHV0aW9uCglmcmFtZV9kaWcgLTYgLy8gdm90ZUtleURpbHV0aW9uOiB1aW50NjQKCWl0eG5fZmllbGQgVm90ZUtleURpbHV0aW9uCgoJLy8gRmVlIGZpZWxkIG5vdCBzZXQsIGRlZmF1bHRpbmcgdG8gMAoJaW50IDAKCWl0eG5fZmllbGQgRmVlCgoJLy8gU3VibWl0IGlubmVyIHRyYW5zYWN0aW9uCglpdHhuX3N1Ym1pdAoJcmV0c3ViCgovLyBnb09mZmxpbmUoKXZvaWQKKmFiaV9yb3V0ZV9nb09mZmxpbmU6CgkvLyBleGVjdXRlIGdvT2ZmbGluZSgpdm9pZAoJY2FsbHN1YiBnb09mZmxpbmUKCWludCAxCglyZXR1cm4KCi8vIGdvT2ZmbGluZSgpOiB2b2lkCi8vCi8vIE1hcmtzIGEgc3Rha2luZyBwb29sIGtleSBPRkZMSU5FLgovLyBbIE9OTFkgT1dORVIgT1IgTUFOQUdFUiBDQU4gQ0FMTCBdCmdvT2ZmbGluZToKCXByb3RvIDAgMAoKCS8vICppZjQyX2NvbmRpdGlvbgoJLy8gY29udHJhY3RzL3N0YWtpbmdQb29sLmFsZ28udHM6ODUzCgkvLyB0aGlzLnR4bi5zZW5kZXIgIT09IEFwcElELmZyb21VaW50NjQodGhpcy5jcmVhdGluZ1ZhbGlkYXRvckNvbnRyYWN0QXBwSWQudmFsdWUpLmFkZHJlc3MKCXR4biBTZW5kZXIKCWJ5dGUgMHg2MzcyNjU2MTc0NmY3MjQxNzA3MCAvLyAiY3JlYXRvckFwcCIKCWFwcF9nbG9iYWxfZ2V0CglhcHBfcGFyYW1zX2dldCBBcHBBZGRyZXNzCglwb3AKCSE9CglieiAqaWY0Ml9lbmQKCgkvLyAqaWY0Ml9jb25zZXF1ZW50CgkvLyBjb250cmFjdHMvc3Rha2luZ1Bvb2wuYWxnby50czo4NTQKCS8vIGFzc2VydCh0aGlzLmlzT3duZXJPck1hbmFnZXJDYWxsZXIoKSkKCWNhbGxzdWIgaXNPd25lck9yTWFuYWdlckNhbGxlcgoJYXNzZXJ0CgoqaWY0Ml9lbmQ6CgkvLyBjb250cmFjdHMvc3Rha2luZ1Bvb2wuYWxnby50czo4NTcKCS8vIHNlbmRPZmZsaW5lS2V5UmVnaXN0cmF0aW9uKHt9KQoJaXR4bl9iZWdpbgoJaW50IGtleXJlZwoJaXR4bl9maWVsZCBUeXBlRW51bQoKCS8vIEZlZSBmaWVsZCBub3Qgc2V0LCBkZWZhdWx0aW5nIHRvIDAKCWludCAwCglpdHhuX2ZpZWxkIEZlZQoKCS8vIFN1Ym1pdCBpbm5lciB0cmFuc2FjdGlvbgoJaXR4bl9zdWJtaXQKCXJldHN1YgoKLy8gbGlua1RvTkZEKHVpbnQ2NCxzdHJpbmcpdm9pZAoqYWJpX3JvdXRlX2xpbmtUb05GRDoKCS8vIG5mZE5hbWU6IHN0cmluZwoJdHhuYSBBcHBsaWNhdGlvbkFyZ3MgMgoJZXh0cmFjdCAyIDAKCgkvLyBuZmRBcHBJZDogdWludDY0Cgl0eG5hIEFwcGxpY2F0aW9uQXJncyAxCglidG9pCgoJLy8gZXhlY3V0ZSBsaW5rVG9ORkQodWludDY0LHN0cmluZyl2b2lkCgljYWxsc3ViIGxpbmtUb05GRAoJaW50IDEKCXJldHVybgoKLy8gbGlua1RvTkZEKG5mZEFwcElkOiB1aW50NjQsIG5mZE5hbWU6IHN0cmluZyk6IHZvaWQKbGlua1RvTkZEOgoJcHJvdG8gMiAwCgoJLy8gY29udHJhY3RzL3N0YWtpbmdQb29sLmFsZ28udHM6ODY0CgkvLyBhc3NlcnQodGhpcy5pc093bmVyT3JNYW5hZ2VyQ2FsbGVyKCkpCgljYWxsc3ViIGlzT3duZXJPck1hbmFnZXJDYWxsZXIKCWFzc2VydAoKCS8vIGNvbnRyYWN0cy9zdGFraW5nUG9vbC5hbGdvLnRzOjg2NgoJLy8gc2VuZEFwcENhbGwoewoJLy8gICAgICAgICAgICAgYXBwbGljYXRpb25JRDogQXBwSUQuZnJvbVVpbnQ2NCh0aGlzLm5mZFJlZ2lzdHJ5QXBwSWQpLAoJLy8gICAgICAgICAgICAgYXBwbGljYXRpb25BcmdzOiBbJ3ZlcmlmeV9uZmRfYWRkcicsIG5mZE5hbWUsIGl0b2IobmZkQXBwSWQpLCByYXdCeXRlcyh0aGlzLmFwcC5hZGRyZXNzKV0sCgkvLyAgICAgICAgICAgICBhcHBsaWNhdGlvbnM6IFtBcHBJRC5mcm9tVWludDY0KG5mZEFwcElkKV0sCgkvLyAgICAgICAgIH0pCglpdHhuX2JlZ2luCglpbnQgYXBwbAoJaXR4bl9maWVsZCBUeXBlRW51bQoKCS8vIGNvbnRyYWN0cy9zdGFraW5nUG9vbC5hbGdvLnRzOjg2NwoJLy8gYXBwbGljYXRpb25JRDogQXBwSUQuZnJvbVVpbnQ2NCh0aGlzLm5mZFJlZ2lzdHJ5QXBwSWQpCglwdXNoaW50IFRNUExfbmZkUmVnaXN0cnlBcHBJZAoJaXR4bl9maWVsZCBBcHBsaWNhdGlvbklECgoJLy8gY29udHJhY3RzL3N0YWtpbmdQb29sLmFsZ28udHM6ODY4CgkvLyBhcHBsaWNhdGlvbkFyZ3M6IFsndmVyaWZ5X25mZF9hZGRyJywgbmZkTmFtZSwgaXRvYihuZmRBcHBJZCksIHJhd0J5dGVzKHRoaXMuYXBwLmFkZHJlc3MpXQoJYnl0ZSAweDc2NjU3MjY5NjY3OTVmNmU2NjY0NWY2MTY0NjQ3MiAvLyAidmVyaWZ5X25mZF9hZGRyIgoJaXR4bl9maWVsZCBBcHBsaWNhdGlvbkFyZ3MKCWZyYW1lX2RpZyAtMiAvLyBuZmROYW1lOiBzdHJpbmcKCWl0eG5fZmllbGQgQXBwbGljYXRpb25BcmdzCglmcmFtZV9kaWcgLTEgLy8gbmZkQXBwSWQ6IHVpbnQ2NAoJaXRvYgoJaXR4bl9maWVsZCBBcHBsaWNhdGlvbkFyZ3MKCWdsb2JhbCBDdXJyZW50QXBwbGljYXRpb25BZGRyZXNzCglpdHhuX2ZpZWxkIEFwcGxpY2F0aW9uQXJncwoKCS8vIGNvbnRyYWN0cy9zdGFraW5nUG9vbC5hbGdvLnRzOjg2OQoJLy8gYXBwbGljYXRpb25zOiBbQXBwSUQuZnJvbVVpbnQ2NChuZmRBcHBJZCldCglmcmFtZV9kaWcgLTEgLy8gbmZkQXBwSWQ6IHVpbnQ2NAoJaXR4bl9maWVsZCBBcHBsaWNhdGlvbnMKCgkvLyBGZWUgZmllbGQgbm90IHNldCwgZGVmYXVsdGluZyB0byAwCglpbnQgMAoJaXR4bl9maWVsZCBGZWUKCgkvLyBTdWJtaXQgaW5uZXIgdHJhbnNhY3Rpb24KCWl0eG5fc3VibWl0CglyZXRzdWIKCi8vIHByb3hpZWRTZXRUb2tlblBheW91dFJhdGlvKCh1aW50NjQsdWludDY0LHVpbnQ2NCkpKHVpbnQ2NFsyNF0sdWludDY0KQoqYWJpX3JvdXRlX3Byb3hpZWRTZXRUb2tlblBheW91dFJhdGlvOgoJLy8gVGhlIEFCSSByZXR1cm4gcHJlZml4CglieXRlIDB4MTUxZjdjNzUKCgkvLyBwb29sS2V5OiAodWludDY0LHVpbnQ2NCx1aW50NjQpCgl0eG5hIEFwcGxpY2F0aW9uQXJncyAxCglkdXAKCWxlbgoJaW50IDI0Cgk9PQoJYXNzZXJ0CgoJLy8gZXhlY3V0ZSBwcm94aWVkU2V0VG9rZW5QYXlvdXRSYXRpbygodWludDY0LHVpbnQ2NCx1aW50NjQpKSh1aW50NjRbMjRdLHVpbnQ2NCkKCWNhbGxzdWIgcHJveGllZFNldFRva2VuUGF5b3V0UmF0aW8KCWNvbmNhdAoJbG9nCglpbnQgMQoJcmV0dXJuCgovLyBwcm94aWVkU2V0VG9rZW5QYXlvdXRSYXRpbyhwb29sS2V5OiBWYWxpZGF0b3JQb29sS2V5KTogUG9vbFRva2VuUGF5b3V0UmF0aW8KLy8KLy8gcHJveGllZFNldFRva2VuUGF5b3V0UmF0aW8gaXMgbWVhbnQgdG8gYmUgY2FsbGVkIGJ5IHBvb2xzICE9IDEgLSBjYWxsaW5nIFVTLCBwb29sICMxCi8vIFdlIG5lZWQgdG8gdmVyaWZ5IHRoYXQgd2UgYXJlIGluIGZhY3QgYmVpbmcgY2FsbGVkIGJ5IGFub3RoZXIgb2YgT1VSIHBvb2xzIChub3QgdXMpCi8vIGFuZCB0aGVuIHdlJ2xsIGNhbGwgdGhlIHZhbGlkYXRvciBvbiB0aGVpciBiZWhhbGYgdG8gdXBkYXRlIHRoZSB0b2tlbiBwYXlvdXRzCi8vIEBwYXJhbSBwb29sS2V5IC0gVmFsaWRhdG9yUG9vbEtleSB0dXBsZQpwcm94aWVkU2V0VG9rZW5QYXlvdXRSYXRpbzoKCXByb3RvIDEgMQoKCS8vIFB1c2ggZW1wdHkgYnl0ZXMgYWZ0ZXIgdGhlIGZyYW1lIHBvaW50ZXIgdG8gcmVzZXJ2ZSBzcGFjZSBmb3IgbG9jYWwgdmFyaWFibGVzCglieXRlIDB4CgoJLy8gY29udHJhY3RzL3N0YWtpbmdQb29sLmFsZ28udHM6ODgwCgkvLyBhc3NlcnQodGhpcy52YWxpZGF0b3JJZC52YWx1ZSA9PT0gcG9vbEtleS5pZCwgJ2NhbGxlciBtdXN0IGJlIHBhcnQgb2Ygc2FtZSB2YWxpZGF0b3Igc2V0IScpCglieXRlIDB4NzY2MTZjNjk2NDYxNzQ2ZjcyNDk2NCAvLyAidmFsaWRhdG9ySWQiCglhcHBfZ2xvYmFsX2dldAoJZnJhbWVfZGlnIC0xIC8vIHBvb2xLZXk6IFZhbGlkYXRvclBvb2xLZXkKCWV4dHJhY3QgMCA4CglidG9pCgk9PQoKCS8vIGNhbGxlciBtdXN0IGJlIHBhcnQgb2Ygc2FtZSB2YWxpZGF0b3Igc2V0IQoJYXNzZXJ0CgoJLy8gY29udHJhY3RzL3N0YWtpbmdQb29sLmFsZ28udHM6ODgxCgkvLyBhc3NlcnQodGhpcy5wb29sSWQudmFsdWUgPT09IDEsICdjYWxsZWUgbXVzdCBiZSBwb29sIDEnKQoJYnl0ZSAweDcwNmY2ZjZjNDk2NCAvLyAicG9vbElkIgoJYXBwX2dsb2JhbF9nZXQKCWludCAxCgk9PQoKCS8vIGNhbGxlZSBtdXN0IGJlIHBvb2wgMQoJYXNzZXJ0CgoJLy8gY29udHJhY3RzL3N0YWtpbmdQb29sLmFsZ28udHM6ODgyCgkvLyBhc3NlcnQocG9vbEtleS5wb29sSWQgIT09IDEsICdjYWxsZXIgbXVzdCBOT1QgYmUgcG9vbCAxJykKCWZyYW1lX2RpZyAtMSAvLyBwb29sS2V5OiBWYWxpZGF0b3JQb29sS2V5CglleHRyYWN0IDggOAoJYnRvaQoJaW50IDEKCSE9CgoJLy8gY2FsbGVyIG11c3QgTk9UIGJlIHBvb2wgMQoJYXNzZXJ0CgoJLy8gY29udHJhY3RzL3N0YWtpbmdQb29sLmFsZ28udHM6ODg0CgkvLyBjYWxsZXJQb29sQXBwSUQgPSBzZW5kTWV0aG9kQ2FsbDx0eXBlb2YgVmFsaWRhdG9yUmVnaXN0cnkucHJvdG90eXBlLmdldFBvb2xBcHBJZD4oewoJLy8gICAgICAgICAgICAgYXBwbGljYXRpb25JRDogQXBwSUQuZnJvbVVpbnQ2NCh0aGlzLmNyZWF0aW5nVmFsaWRhdG9yQ29udHJhY3RBcHBJZC52YWx1ZSksCgkvLyAgICAgICAgICAgICBtZXRob2RBcmdzOiBbcG9vbEtleS5pZCwgcG9vbEtleS5wb29sSWRdLAoJLy8gICAgICAgICB9KQoJaXR4bl9iZWdpbgoJaW50IGFwcGwKCWl0eG5fZmllbGQgVHlwZUVudW0KCW1ldGhvZCAiZ2V0UG9vbEFwcElkKHVpbnQ2NCx1aW50NjQpdWludDY0IgoJaXR4bl9maWVsZCBBcHBsaWNhdGlvbkFyZ3MKCgkvLyBjb250cmFjdHMvc3Rha2luZ1Bvb2wuYWxnby50czo4ODUKCS8vIGFwcGxpY2F0aW9uSUQ6IEFwcElELmZyb21VaW50NjQodGhpcy5jcmVhdGluZ1ZhbGlkYXRvckNvbnRyYWN0QXBwSWQudmFsdWUpCglieXRlIDB4NjM3MjY1NjE3NDZmNzI0MTcwNzAgLy8gImNyZWF0b3JBcHAiCglhcHBfZ2xvYmFsX2dldAoJaXR4bl9maWVsZCBBcHBsaWNhdGlvbklECgoJLy8gY29udHJhY3RzL3N0YWtpbmdQb29sLmFsZ28udHM6ODg2CgkvLyBtZXRob2RBcmdzOiBbcG9vbEtleS5pZCwgcG9vbEtleS5wb29sSWRdCglmcmFtZV9kaWcgLTEgLy8gcG9vbEtleTogVmFsaWRhdG9yUG9vbEtleQoJZXh0cmFjdCAwIDgKCWJ0b2kKCWl0b2IKCWl0eG5fZmllbGQgQXBwbGljYXRpb25BcmdzCglmcmFtZV9kaWcgLTEgLy8gcG9vbEtleTogVmFsaWRhdG9yUG9vbEtleQoJZXh0cmFjdCA4IDgKCWJ0b2kKCWl0b2IKCWl0eG5fZmllbGQgQXBwbGljYXRpb25BcmdzCgoJLy8gRmVlIGZpZWxkIG5vdCBzZXQsIGRlZmF1bHRpbmcgdG8gMAoJaW50IDAKCWl0eG5fZmllbGQgRmVlCgoJLy8gU3VibWl0IGlubmVyIHRyYW5zYWN0aW9uCglpdHhuX3N1Ym1pdAoJaXR4biBOdW1Mb2dzCglpbnQgMQoJLQoJaXR4bmFzIExvZ3MKCWV4dHJhY3QgNCAwCglidG9pCglmcmFtZV9idXJ5IDAgLy8gY2FsbGVyUG9vbEFwcElEOiB1aW50NjQKCgkvLyBjb250cmFjdHMvc3Rha2luZ1Bvb2wuYWxnby50czo4ODgKCS8vIGFzc2VydChjYWxsZXJQb29sQXBwSUQgPT09IHBvb2xLZXkucG9vbEFwcElkKQoJZnJhbWVfZGlnIDAgLy8gY2FsbGVyUG9vbEFwcElEOiB1aW50NjQKCWZyYW1lX2RpZyAtMSAvLyBwb29sS2V5OiBWYWxpZGF0b3JQb29sS2V5CglleHRyYWN0IDE2IDgKCWJ0b2kKCT09Cglhc3NlcnQKCgkvLyBjb250cmFjdHMvc3Rha2luZ1Bvb2wuYWxnby50czo4ODkKCS8vIGFzc2VydCh0aGlzLnR4bi5zZW5kZXIgPT09IEFwcElELmZyb21VaW50NjQocG9vbEtleS5wb29sQXBwSWQpLmFkZHJlc3MpCgl0eG4gU2VuZGVyCglmcmFtZV9kaWcgLTEgLy8gcG9vbEtleTogVmFsaWRhdG9yUG9vbEtleQoJZXh0cmFjdCAxNiA4CglidG9pCglhcHBfcGFyYW1zX2dldCBBcHBBZGRyZXNzCglwb3AKCT09Cglhc3NlcnQKCgkvLyBjb250cmFjdHMvc3Rha2luZ1Bvb2wuYWxnby50czo4OTEKCS8vIHJldHVybiBzZW5kTWV0aG9kQ2FsbDx0eXBlb2YgVmFsaWRhdG9yUmVnaXN0cnkucHJvdG90eXBlLnNldFRva2VuUGF5b3V0UmF0aW8+KHsKCS8vICAgICAgICAgICAgIGFwcGxpY2F0aW9uSUQ6IEFwcElELmZyb21VaW50NjQodGhpcy5jcmVhdGluZ1ZhbGlkYXRvckNvbnRyYWN0QXBwSWQudmFsdWUpLAoJLy8gICAgICAgICAgICAgbWV0aG9kQXJnczogW3RoaXMudmFsaWRhdG9ySWQudmFsdWVdLAoJLy8gICAgICAgICB9KTsKCWl0eG5fYmVnaW4KCWludCBhcHBsCglpdHhuX2ZpZWxkIFR5cGVFbnVtCgltZXRob2QgInNldFRva2VuUGF5b3V0UmF0aW8odWludDY0KSh1aW50NjRbMjRdLHVpbnQ2NCkiCglpdHhuX2ZpZWxkIEFwcGxpY2F0aW9uQXJncwoKCS8vIGNvbnRyYWN0cy9zdGFraW5nUG9vbC5hbGdvLnRzOjg5MgoJLy8gYXBwbGljYXRpb25JRDogQXBwSUQuZnJvbVVpbnQ2NCh0aGlzLmNyZWF0aW5nVmFsaWRhdG9yQ29udHJhY3RBcHBJZC52YWx1ZSkKCWJ5dGUgMHg2MzcyNjU2MTc0NmY3MjQxNzA3MCAvLyAiY3JlYXRvckFwcCIKCWFwcF9nbG9iYWxfZ2V0CglpdHhuX2ZpZWxkIEFwcGxpY2F0aW9uSUQKCgkvLyBjb250cmFjdHMvc3Rha2luZ1Bvb2wuYWxnby50czo4OTMKCS8vIG1ldGhvZEFyZ3M6IFt0aGlzLnZhbGlkYXRvcklkLnZhbHVlXQoJYnl0ZSAweDc2NjE2YzY5NjQ2MTc0NmY3MjQ5NjQgLy8gInZhbGlkYXRvcklkIgoJYXBwX2dsb2JhbF9nZXQKCWl0b2IKCWl0eG5fZmllbGQgQXBwbGljYXRpb25BcmdzCgoJLy8gRmVlIGZpZWxkIG5vdCBzZXQsIGRlZmF1bHRpbmcgdG8gMAoJaW50IDAKCWl0eG5fZmllbGQgRmVlCgoJLy8gU3VibWl0IGlubmVyIHRyYW5zYWN0aW9uCglpdHhuX3N1Ym1pdAoJaXR4biBOdW1Mb2dzCglpbnQgMQoJLQoJaXR4bmFzIExvZ3MKCWV4dHJhY3QgNCAwCgoJLy8gc2V0IHRoZSBzdWJyb3V0aW5lIHJldHVybiB2YWx1ZQoJZnJhbWVfYnVyeSAwCglyZXRzdWIKCi8vIGlzT3duZXJPck1hbmFnZXJDYWxsZXIoKTogYm9vbGVhbgppc093bmVyT3JNYW5hZ2VyQ2FsbGVyOgoJcHJvdG8gMCAxCgoJLy8gUHVzaCBlbXB0eSBieXRlcyBhZnRlciB0aGUgZnJhbWUgcG9pbnRlciB0byByZXNlcnZlIHNwYWNlIGZvciBsb2NhbCB2YXJpYWJsZXMKCWJ5dGUgMHgKCgkvLyBjb250cmFjdHMvc3Rha2luZ1Bvb2wuYWxnby50czo4OTgKCS8vIE93bmVyQW5kTWFuYWdlciA9IHNlbmRNZXRob2RDYWxsPHR5cGVvZiBWYWxpZGF0b3JSZWdpc3RyeS5wcm90b3R5cGUuZ2V0VmFsaWRhdG9yT3duZXJBbmRNYW5hZ2VyPih7CgkvLyAgICAgICAgICAgICBhcHBsaWNhdGlvbklEOiBBcHBJRC5mcm9tVWludDY0KHRoaXMuY3JlYXRpbmdWYWxpZGF0b3JDb250cmFjdEFwcElkLnZhbHVlKSwKCS8vICAgICAgICAgICAgIG1ldGhvZEFyZ3M6IFt0aGlzLnZhbGlkYXRvcklkLnZhbHVlXSwKCS8vICAgICAgICAgfSkKCWl0eG5fYmVnaW4KCWludCBhcHBsCglpdHhuX2ZpZWxkIFR5cGVFbnVtCgltZXRob2QgImdldFZhbGlkYXRvck93bmVyQW5kTWFuYWdlcih1aW50NjQpKGFkZHJlc3MsYWRkcmVzcykiCglpdHhuX2ZpZWxkIEFwcGxpY2F0aW9uQXJncwoKCS8vIGNvbnRyYWN0cy9zdGFraW5nUG9vbC5hbGdvLnRzOjg5OQoJLy8gYXBwbGljYXRpb25JRDogQXBwSUQuZnJvbVVpbnQ2NCh0aGlzLmNyZWF0aW5nVmFsaWRhdG9yQ29udHJhY3RBcHBJZC52YWx1ZSkKCWJ5dGUgMHg2MzcyNjU2MTc0NmY3MjQxNzA3MCAvLyAiY3JlYXRvckFwcCIKCWFwcF9nbG9iYWxfZ2V0CglpdHhuX2ZpZWxkIEFwcGxpY2F0aW9uSUQKCgkvLyBjb250cmFjdHMvc3Rha2luZ1Bvb2wuYWxnby50czo5MDAKCS8vIG1ldGhvZEFyZ3M6IFt0aGlzLnZhbGlkYXRvcklkLnZhbHVlXQoJYnl0ZSAweDc2NjE2YzY5NjQ2MTc0NmY3MjQ5NjQgLy8gInZhbGlkYXRvcklkIgoJYXBwX2dsb2JhbF9nZXQKCWl0b2IKCWl0eG5fZmllbGQgQXBwbGljYXRpb25BcmdzCgoJLy8gRmVlIGZpZWxkIG5vdCBzZXQsIGRlZmF1bHRpbmcgdG8gMAoJaW50IDAKCWl0eG5fZmllbGQgRmVlCgoJLy8gU3VibWl0IGlubmVyIHRyYW5zYWN0aW9uCglpdHhuX3N1Ym1pdAoJaXR4biBOdW1Mb2dzCglpbnQgMQoJLQoJaXR4bmFzIExvZ3MKCWV4dHJhY3QgNCAwCglmcmFtZV9idXJ5IDAgLy8gT3duZXJBbmRNYW5hZ2VyOiAoYWRkcmVzcyxhZGRyZXNzKQoKCS8vIGNvbnRyYWN0cy9zdGFraW5nUG9vbC5hbGdvLnRzOjkwMgoJLy8gcmV0dXJuIHRoaXMudHhuLnNlbmRlciA9PT0gT3duZXJBbmRNYW5hZ2VyWzBdIHx8IHRoaXMudHhuLnNlbmRlciA9PT0gT3duZXJBbmRNYW5hZ2VyWzFdOwoJdHhuIFNlbmRlcgoJZnJhbWVfZGlnIDAgLy8gT3duZXJBbmRNYW5hZ2VyOiAoYWRkcmVzcyxhZGRyZXNzKQoJZXh0cmFjdCAwIDMyCgk9PQoJZHVwCglibnogKnNraXBfb3IxCgl0eG4gU2VuZGVyCglmcmFtZV9kaWcgMCAvLyBPd25lckFuZE1hbmFnZXI6IChhZGRyZXNzLGFkZHJlc3MpCglleHRyYWN0IDMyIDMyCgk9PQoJfHwKCipza2lwX29yMToKCS8vIHNldCB0aGUgc3Vicm91dGluZSByZXR1cm4gdmFsdWUKCWZyYW1lX2J1cnkgMAoJcmV0c3ViCgovLyBnZXRFbnRyeVRpbWUoKTogdWludDY0Ci8vCi8vIENhbGN1bGF0ZSB0aGUgZW50cnkgdGltZSBmb3IgY291bnRpbmcgYSBzdGFrZSBhcyBlbnRlcmluZyB0aGUgcG9vbC4KLy8gQWxnb3JhbmQgd29uJ3Qgc2VlIHRoZSBiYWxhbmNlIGluY3JlYXNlIGZvciBBTEdPUkFORF9TVEFLSU5HX0JMT0NLX0RFTEFZIHJvdW5kcywgc28gd2UgYXBwcm94aW1hdGUgaXQuCi8vIFRoZSBlbnRyeSB0aW1lIGlzIGNhbGN1bGF0ZWQgYnkgYWRkaW5nIGFuIGFwcHJveGltYXRlIG51bWJlciBvZiBzZWNvbmRzIGJhc2VkIG9uIGN1cnJlbnQgQVZHIGJsb2NrIHRpbWVzCi8vIHRvIHRoZSBvcmlnaW5hbCBlbnRyeSB0aW1lLiAgVGhpcyBtZWFucyB1c2VycyBkb24ndCBnZXQgcGF5b3V0cyBiYXNlZCBvbiB0aW1lIHRoZWlyIGJhbGFuY2Ugd291bGRuJ3QgaGF2ZQovLyBiZWVuIHNlZW4gYnkgdGhlIG5ldHdvcmsuCi8vCi8vIEByZXR1cm5zIHt1aW50NjR9IC0gVGhlIHVwZGF0ZWQgZW50cnkgdGltZS4KZ2V0RW50cnlUaW1lOgoJcHJvdG8gMCAxCgoJLy8gUHVzaCBlbXB0eSBieXRlcyBhZnRlciB0aGUgZnJhbWUgcG9pbnRlciB0byByZXNlcnZlIHNwYWNlIGZvciBsb2NhbCB2YXJpYWJsZXMKCWJ5dGUgMHgKCgkvLyBjb250cmFjdHMvc3Rha2luZ1Bvb2wuYWxnby50czo5MTcKCS8vIGVudHJ5VGltZSA9IGdsb2JhbHMubGF0ZXN0VGltZXN0YW1wCglnbG9iYWwgTGF0ZXN0VGltZXN0YW1wCglmcmFtZV9idXJ5IDAgLy8gZW50cnlUaW1lOiB1aW50NjQKCgkvLyBjb250cmFjdHMvc3Rha2luZ1Bvb2wuYWxnby50czo5MjAKCS8vIHJldHVybiBlbnRyeVRpbWUgKyAoQUxHT1JBTkRfU1RBS0lOR19CTE9DS19ERUxBWSAqIEFWR19CTE9DS19USU1FX1NFQ1MpIC8gMTA7CglmcmFtZV9kaWcgMCAvLyBlbnRyeVRpbWU6IHVpbnQ2NAoJaW50IDg5NgoJKwoKCS8vIHNldCB0aGUgc3Vicm91dGluZSByZXR1cm4gdmFsdWUKCWZyYW1lX2J1cnkgMAoJcmV0c3ViCgovLyBnZXRGZWVTaW5rKCk6IEFkZHJlc3MKZ2V0RmVlU2luazoKCXByb3RvIDAgMQoKCS8vIGNvbnRyYWN0cy9zdGFraW5nUG9vbC5hbGdvLnRzOjkyNAoJLy8gcmV0dXJuIHRoaXMuZmVlU2lua0FkZHI7CglwdXNoYnl0ZXMgVE1QTF9mZWVTaW5rQWRkcgoJcmV0c3ViCgovLyBhbGdvU2F0dXJhdGlvbkxldmVsKCk6IHVpbnQ2NAovLwovLyBSZXR1cm5zIHRoZSBtYXhpbXVtIGFsbG93ZWQgc3Rha2UgcGVyIHZhbGlkYXRvciBiYXNlZCBvbiBhIHBlcmNlbnRhZ2Ugb2YgYWxsIGN1cnJlbnQgb25saW5lIHN0YWtlIGJlZm9yZQovLyB0aGUgdmFsaWRhdG9yIGlzIGNvbnNpZGVyZWQgc2F0dXJhdGVkIC0gd2hlcmUgcmV3YXJkcyBhcmUgZGltaW5pc2hlZC4KYWxnb1NhdHVyYXRpb25MZXZlbDoKCXByb3RvIDAgMQoKCS8vIFB1c2ggZW1wdHkgYnl0ZXMgYWZ0ZXIgdGhlIGZyYW1lIHBvaW50ZXIgdG8gcmVzZXJ2ZSBzcGFjZSBmb3IgbG9jYWwgdmFyaWFibGVzCglieXRlIDB4CgoJLy8gY29udHJhY3RzL3N0YWtpbmdQb29sLmFsZ28udHM6OTM0CgkvLyBvbmxpbmUgPSB0aGlzLmdldEN1cnJlbnRPbmxpbmVTdGFrZSgpCgljYWxsc3ViIGdldEN1cnJlbnRPbmxpbmVTdGFrZQoJZnJhbWVfYnVyeSAwIC8vIG9ubGluZTogdWludDY0CgoJLy8gY29udHJhY3RzL3N0YWtpbmdQb29sLmFsZ28udHM6OTM2CgkvLyByZXR1cm4gd2lkZVJhdGlvKFtvbmxpbmUsIE1BWF9WQUxJREFUT1JfU09GVF9QQ1RfT0ZfT05MSU5FXzFERUNJTUFMXSwgWzEwMDBdKTsKCWZyYW1lX2RpZyAwIC8vIG9ubGluZTogdWludDY0CglpbnQgMTAwCgltdWx3CglpbnQgMAoJaW50IDEwMDAKCWRpdm1vZHcKCXBvcAoJcG9wCglzd2FwCgkhCglhc3NlcnQKCgkvLyBzZXQgdGhlIHN1YnJvdXRpbmUgcmV0dXJuIHZhbHVlCglmcmFtZV9idXJ5IDAKCXJldHN1YgoKLy8gZ2V0Q3VycmVudE9ubGluZVN0YWtlKCk6IHVpbnQ2NApnZXRDdXJyZW50T25saW5lU3Rha2U6Cglwcm90byAwIDEKCgkvLyBjb250cmFjdHMvc3Rha2luZ1Bvb2wuYWxnby50czo5NDEKCS8vIHJldHVybiAyXzAwMF8wMDBfMDAwXzAwMF8wMDA7CglpbnQgMl8wMDBfMDAwXzAwMF8wMDBfMDAwCglyZXRzdWIKCipjcmVhdGVfTm9PcDoKCW1ldGhvZCAiY3JlYXRlQXBwbGljYXRpb24odWludDY0LHVpbnQ2NCx1aW50NjQsdWludDY0KXZvaWQiCgl0eG5hIEFwcGxpY2F0aW9uQXJncyAwCgltYXRjaCAqYWJpX3JvdXRlX2NyZWF0ZUFwcGxpY2F0aW9uCgllcnIKCipjYWxsX05vT3A6CgltZXRob2QgImdhcygpdm9pZCIKCW1ldGhvZCAiaW5pdFN0b3JhZ2UocGF5KXZvaWQiCgltZXRob2QgImFkZFN0YWtlKHBheSxhZGRyZXNzKXVpbnQ2NCIKCW1ldGhvZCAicmVtb3ZlU3Rha2UodWludDY0KXZvaWQiCgltZXRob2QgImNsYWltVG9rZW5zKCl2b2lkIgoJbWV0aG9kICJnZXRTdGFrZXJJbmZvKGFkZHJlc3MpKGFkZHJlc3MsdWludDY0LHVpbnQ2NCx1aW50NjQsdWludDY0KSIKCW1ldGhvZCAicGF5VG9rZW5SZXdhcmQoYWRkcmVzcyx1aW50NjQsdWludDY0KXZvaWQiCgltZXRob2QgInVwZGF0ZUFsZ29kVmVyKHN0cmluZyl2b2lkIgoJbWV0aG9kICJlcG9jaEJhbGFuY2VVcGRhdGUoKXZvaWQiCgltZXRob2QgImdvT25saW5lKGJ5dGVbXSxieXRlW10sYnl0ZVtdLHVpbnQ2NCx1aW50NjQsdWludDY0KXZvaWQiCgltZXRob2QgImdvT2ZmbGluZSgpdm9pZCIKCW1ldGhvZCAibGlua1RvTkZEKHVpbnQ2NCxzdHJpbmcpdm9pZCIKCW1ldGhvZCAicHJveGllZFNldFRva2VuUGF5b3V0UmF0aW8oKHVpbnQ2NCx1aW50NjQsdWludDY0KSkodWludDY0WzI0XSx1aW50NjQpIgoJdHhuYSBBcHBsaWNhdGlvbkFyZ3MgMAoJbWF0Y2ggKmFiaV9yb3V0ZV9nYXMgKmFiaV9yb3V0ZV9pbml0U3RvcmFnZSAqYWJpX3JvdXRlX2FkZFN0YWtlICphYmlfcm91dGVfcmVtb3ZlU3Rha2UgKmFiaV9yb3V0ZV9jbGFpbVRva2VucyAqYWJpX3JvdXRlX2dldFN0YWtlckluZm8gKmFiaV9yb3V0ZV9wYXlUb2tlblJld2FyZCAqYWJpX3JvdXRlX3VwZGF0ZUFsZ29kVmVyICphYmlfcm91dGVfZXBvY2hCYWxhbmNlVXBkYXRlICphYmlfcm91dGVfZ29PbmxpbmUgKmFiaV9yb3V0ZV9nb09mZmxpbmUgKmFiaV9yb3V0ZV9saW5rVG9ORkQgKmFiaV9yb3V0ZV9wcm94aWVkU2V0VG9rZW5QYXlvdXRSYXRpbwoJZXJyCgoqaW50VG9Bc2NpaToKCXByb3RvIDEgMQoJYnl0ZSAweDMwMzEzMjMzMzQzNTM2MzczODM5IC8vICIwMTIzNDU2Nzg5IgoJZnJhbWVfZGlnIC0xIC8vIGk6IHVpbnQ2NAoJaW50IDEKCWV4dHJhY3QzCglyZXRzdWIKCQoKKml0b2E6Cglwcm90byAxIDEKCWZyYW1lX2RpZyAtMSAvLyBpOiB1aW50NjQKCWludCAwCgk9PQoJYnogKml0b2FfaWZfZW5kCglieXRlIDB4MzAKCXJldHN1YgoKKml0b2FfaWZfZW5kOgoJZnJhbWVfZGlnIC0xIC8vIGk6IHVpbnQ2NAoJaW50IDEwCgkvCglpbnQgMAoJPgoJYnogKml0b2FfdGVybmFyeV9mYWxzZQoJZnJhbWVfZGlnIC0xIC8vIGk6IHVpbnQ2NAoJaW50IDEwCgkvCgljYWxsc3ViICppdG9hCgliICppdG9hX3Rlcm5hcnlfZW5kCgoqaXRvYV90ZXJuYXJ5X2ZhbHNlOgoJYnl0ZSAweCAvLyAiIgoKKml0b2FfdGVybmFyeV9lbmQ6CglmcmFtZV9kaWcgLTEgLy8gaTogdWludDY0CglpbnQgMTAKCSUKCWNhbGxzdWIgKmludFRvQXNjaWkKCWNvbmNhdAoJcmV0c3Vi", + "clear": "I3ByYWdtYSB2ZXJzaW9uIDEw" + }, + "contract": { + "name": "StakingPool", + "desc": "", + "methods": [ + { + "name": "createApplication", + "desc": "Initialize the staking pool w/ owner and manager, but can only be created by the validator contract.", + "args": [ + { + "name": "creatingContractId", + "type": "uint64", + "desc": "id of contract that constructed us - the validator application (single global instance)" + }, + { + "name": "validatorId", + "type": "uint64", + "desc": "id of validator we're a staking pool of" + }, + { + "name": "poolId", + "type": "uint64", + "desc": "which pool id are we" + }, + { + "name": "minEntryStake", + "type": "uint64", + "desc": "minimum amount to be in pool, but also minimum amount balance can't go below (without removing all!)" + } + ], + "returns": { + "type": "void" + } + }, + { + "name": "gas", + "desc": "gas is a dummy no-op call that can be used to pool-up resource references and opcode cost", + "args": [], + "returns": { + "type": "void" + } + }, + { + "name": "initStorage", + "desc": "Called after we're created and then funded so we can create our large stakers ledger storageCaller has to get MBR amounts from ValidatorRegistry to know how much to fund us to cover the box storage costIf this is pool 1 AND the validator has specified a reward token, opt-in to that tokenso that the validator can seed the pool with future rewards of that token.", + "args": [ + { + "name": "mbrPayment", + "type": "pay", + "desc": "payment from caller which covers mbr increase of new staking pools' storage" + } + ], + "returns": { + "type": "void" + } + }, + { + "name": "addStake", + "desc": "Adds stake to the given account.Can ONLY be called by the validator contract that created usMust receive payment from the validator contract for amount being staked.", + "args": [ + { + "name": "stakedAmountPayment", + "type": "pay", + "desc": "prior payment coming from validator contract to us on behalf of staker." + }, + { + "name": "staker", + "type": "address", + "desc": "The account adding new stake" + } + ], + "returns": { + "type": "uint64", + "desc": "{uint64}new 'entry time' in seconds of stake add." + } + }, + { + "name": "removeStake", + "desc": "Removes stake on behalf of caller (removing own stake). If any token rewards exist, those are always sent infull. Also notifies the validator contract for this pools validator of the staker / balance changes.", + "args": [ + { + "name": "amountToUnstake", + "type": "uint64", + "desc": "The amount of stake to be removed. Specify 0 to remove all stake." + } + ], + "returns": { + "type": "void" + } + }, + { + "name": "claimTokens", + "desc": "Claims all the available reward tokens a staker has available, sending their entire balance to the staker frompool 1 (either directly, or via validator->pool1 to pay it out)Also notifies the validator contract for this pools validator of the staker / balance changes.", + "args": [], + "returns": { + "type": "void" + } + }, + { + "name": "getStakerInfo", + "desc": "Retrieves the staked information for a given staker.", + "args": [ + { + "name": "staker", + "type": "address", + "desc": "The address of the staker." + } + ], + "returns": { + "type": "(address,uint64,uint64,uint64,uint64)", + "desc": "{StakedInfo}- The staked information for the given staker." + } + }, + { + "name": "payTokenReward", + "desc": "[Internal protocol method] Remove a specified amount of 'community token' rewards for a staker.This can ONLY be called by our validator and only if we're pool 1 - with the token.", + "args": [ + { + "name": "staker", + "type": "address", + "desc": "the staker account to send rewards to" + }, + { + "name": "rewardToken", + "type": "uint64", + "desc": "id of reward token (to avoid re-entrancy in calling validator back to get id)" + }, + { + "name": "amountToSend", + "type": "uint64", + "desc": "amount to send the staker (there is significant trust here(!) - also why only validator can call us" + } + ], + "returns": { + "type": "void" + } + }, + { + "name": "updateAlgodVer", + "desc": "Update the (honor system) algod version for the node associated to this pool. The node management daemonshould compare its current nodes version to the version stored in global state, updating when different.The reti node daemon composes its own version string using format:{major}.{minor}.{build}{branch}[{commit hash}],ie: 3.22.0 rel/stable [6b508975][ ONLY OWNER OR MANAGER CAN CALL ]", + "args": [ + { + "name": "algodVer", + "type": "string", + "desc": "string representing the algorand node daemon version (reti node daemon composes its own meta version)" + } + ], + "returns": { + "type": "void" + } + }, + { + "name": "epochBalanceUpdate", + "desc": "Updates the balance of stakers in the pool based on the received 'rewards' (current balance vs known staked balance)stakers outstanding balance is adjusted based on their % of stake and time in the current epoch - so that balancecompounds over time and staker can remove that amount at will.The validator is paid their percentage each epoch payout.Note: ANYONE can call this.", + "args": [], + "returns": { + "type": "void" + } + }, + { + "name": "goOnline", + "desc": "Registers a staking pool key online against a participation key.[ ONLY OWNER OR MANAGER CAN CALL ]", + "args": [ + { + "name": "votePK", + "type": "byte[]", + "desc": "The vote public key." + }, + { + "name": "selectionPK", + "type": "byte[]", + "desc": "The selection public key." + }, + { + "name": "stateProofPK", + "type": "byte[]", + "desc": "The state proof public key." + }, + { + "name": "voteFirst", + "type": "uint64", + "desc": "The first vote index." + }, + { + "name": "voteLast", + "type": "uint64", + "desc": "The last vote index." + }, + { + "name": "voteKeyDilution", + "type": "uint64", + "desc": "The vote key dilution value." + } + ], + "returns": { + "type": "void" + } + }, + { + "name": "goOffline", + "desc": "Marks a staking pool key OFFLINE.[ ONLY OWNER OR MANAGER CAN CALL ]", + "args": [], + "returns": { + "type": "void" + } + }, + { + "name": "linkToNFD", + "args": [ + { + "name": "nfdAppId", + "type": "uint64" + }, + { + "name": "nfdName", + "type": "string" + } + ], + "returns": { + "type": "void" + } + }, + { + "name": "proxiedSetTokenPayoutRatio", + "desc": "proxiedSetTokenPayoutRatio is meant to be called by pools != 1 - calling US, pool #1We need to verify that we are in fact being called by another of OUR pools (not us)and then we'll call the validator on their behalf to update the token payouts", + "args": [ + { + "name": "poolKey", + "type": "(uint64,uint64,uint64)", + "desc": "ValidatorPoolKey tuple" + } + ], + "returns": { + "type": "(uint64[24],uint64)" + } + } + ] + } +} + +/** + * Defines an onCompletionAction of 'no_op' + */ +export type OnCompleteNoOp = { onCompleteAction?: 'no_op' | OnApplicationComplete.NoOpOC } +/** + * Defines an onCompletionAction of 'opt_in' + */ +export type OnCompleteOptIn = { onCompleteAction: 'opt_in' | OnApplicationComplete.OptInOC } +/** + * Defines an onCompletionAction of 'close_out' + */ +export type OnCompleteCloseOut = { onCompleteAction: 'close_out' | OnApplicationComplete.CloseOutOC } +/** + * Defines an onCompletionAction of 'delete_application' + */ +export type OnCompleteDelApp = { onCompleteAction: 'delete_application' | OnApplicationComplete.DeleteApplicationOC } +/** + * Defines an onCompletionAction of 'update_application' + */ +export type OnCompleteUpdApp = { onCompleteAction: 'update_application' | OnApplicationComplete.UpdateApplicationOC } +/** + * A state record containing a single unsigned integer + */ +export type IntegerState = { + /** + * Gets the state value as a BigInt. + */ + asBigInt(): bigint + /** + * Gets the state value as a number. + */ + asNumber(): number +} +/** + * A state record containing binary data + */ +export type BinaryState = { + /** + * Gets the state value as a Uint8Array + */ + asByteArray(): Uint8Array + /** + * Gets the state value as a string + */ + asString(): string +} + +export type AppCreateCallTransactionResult = AppCallTransactionResult & Partial & AppReference +export type AppUpdateCallTransactionResult = AppCallTransactionResult & Partial + +export type AppClientComposeCallCoreParams = Omit & { + sendParams?: Omit +} +export type AppClientComposeExecuteParams = Pick + +export type IncludeSchema = { + /** + * Any overrides for the storage schema to request for the created app; by default the schema indicated by the app spec is used. + */ + schema?: Partial +} + +/** + * Defines the types of available calls and state of the StakingPool smart contract. + */ +export type StakingPool = { + /** + * Maps method signatures / names to their argument and return types. + */ + methods: + & Record<'createApplication(uint64,uint64,uint64,uint64)void' | 'createApplication', { + argsObj: { + /** + * id of contract that constructed us - the validator application (single global instance) + */ + creatingContractId: bigint | number + /** + * id of validator we're a staking pool of + */ + validatorId: bigint | number + /** + * which pool id are we + */ + poolId: bigint | number + /** + * minimum amount to be in pool, but also minimum amount balance can't go below (without removing all!) + */ + minEntryStake: bigint | number + } + argsTuple: [creatingContractId: bigint | number, validatorId: bigint | number, poolId: bigint | number, minEntryStake: bigint | number] + returns: void + }> + & Record<'gas()void' | 'gas', { + argsObj: { + } + argsTuple: [] + returns: void + }> + & Record<'initStorage(pay)void' | 'initStorage', { + argsObj: { + /** + * payment from caller which covers mbr increase of new staking pools' storage + */ + mbrPayment: TransactionToSign | Transaction | Promise + } + argsTuple: [mbrPayment: TransactionToSign | Transaction | Promise] + returns: void + }> + & Record<'addStake(pay,address)uint64' | 'addStake', { + argsObj: { + /** + * prior payment coming from validator contract to us on behalf of staker. + */ + stakedAmountPayment: TransactionToSign | Transaction | Promise + /** + * The account adding new stake + */ + staker: string + } + argsTuple: [stakedAmountPayment: TransactionToSign | Transaction | Promise, staker: string] + /** + * {uint64}new 'entry time' in seconds of stake add. + */ + returns: bigint + }> + & Record<'removeStake(uint64)void' | 'removeStake', { + argsObj: { + /** + * The amount of stake to be removed. Specify 0 to remove all stake. + */ + amountToUnstake: bigint | number + } + argsTuple: [amountToUnstake: bigint | number] + returns: void + }> + & Record<'claimTokens()void' | 'claimTokens', { + argsObj: { + } + argsTuple: [] + returns: void + }> + & Record<'getStakerInfo(address)(address,uint64,uint64,uint64,uint64)' | 'getStakerInfo', { + argsObj: { + /** + * The address of the staker. + */ + staker: string + } + argsTuple: [staker: string] + /** + * {StakedInfo}- The staked information for the given staker. + */ + returns: [string, bigint, bigint, bigint, bigint] + }> + & Record<'payTokenReward(address,uint64,uint64)void' | 'payTokenReward', { + argsObj: { + /** + * the staker account to send rewards to + */ + staker: string + /** + * id of reward token (to avoid re-entrancy in calling validator back to get id) + */ + rewardToken: bigint | number + /** + * amount to send the staker (there is significant trust here(!) - also why only validator can call us + */ + amountToSend: bigint | number + } + argsTuple: [staker: string, rewardToken: bigint | number, amountToSend: bigint | number] + returns: void + }> + & Record<'updateAlgodVer(string)void' | 'updateAlgodVer', { + argsObj: { + /** + * string representing the algorand node daemon version (reti node daemon composes its own meta version) + */ + algodVer: string + } + argsTuple: [algodVer: string] + returns: void + }> + & Record<'epochBalanceUpdate()void' | 'epochBalanceUpdate', { + argsObj: { + } + argsTuple: [] + returns: void + }> + & Record<'goOnline(byte[],byte[],byte[],uint64,uint64,uint64)void' | 'goOnline', { + argsObj: { + /** + * The vote public key. + */ + votePk: Uint8Array + /** + * The selection public key. + */ + selectionPk: Uint8Array + /** + * The state proof public key. + */ + stateProofPk: Uint8Array + /** + * The first vote index. + */ + voteFirst: bigint | number + /** + * The last vote index. + */ + voteLast: bigint | number + /** + * The vote key dilution value. + */ + voteKeyDilution: bigint | number + } + argsTuple: [votePk: Uint8Array, selectionPk: Uint8Array, stateProofPk: Uint8Array, voteFirst: bigint | number, voteLast: bigint | number, voteKeyDilution: bigint | number] + returns: void + }> + & Record<'goOffline()void' | 'goOffline', { + argsObj: { + } + argsTuple: [] + returns: void + }> + & Record<'linkToNFD(uint64,string)void' | 'linkToNFD', { + argsObj: { + nfdAppId: bigint | number + nfdName: string + } + argsTuple: [nfdAppId: bigint | number, nfdName: string] + returns: void + }> + & Record<'proxiedSetTokenPayoutRatio((uint64,uint64,uint64))(uint64[24],uint64)' | 'proxiedSetTokenPayoutRatio', { + argsObj: { + /** + * ValidatorPoolKey tuple + */ + poolKey: [bigint | number, bigint | number, bigint | number] + } + argsTuple: [poolKey: [bigint | number, bigint | number, bigint | number]] + returns: [[bigint, bigint, bigint, bigint, bigint, bigint, bigint, bigint, bigint, bigint, bigint, bigint, bigint, bigint, bigint, bigint, bigint, bigint, bigint, bigint, bigint, bigint, bigint, bigint], bigint] + }> + /** + * Defines the shape of the global and local state of the application. + */ + state: { + global: { + creatorApp?: IntegerState + validatorId?: IntegerState + poolId?: IntegerState + numStakers?: IntegerState + staked?: IntegerState + minEntryStake?: IntegerState + lastPayout?: IntegerState + epochNumber?: IntegerState + algodVer?: BinaryState + } + } +} +/** + * Defines the possible abi call signatures + */ +export type StakingPoolSig = keyof StakingPool['methods'] +/** + * Defines an object containing all relevant parameters for a single call to the contract. Where TSignature is undefined, a bare call is made + */ +export type TypedCallParams = { + method: TSignature + methodArgs: TSignature extends undefined ? undefined : Array +} & AppClientCallCoreParams & CoreAppCallArgs +/** + * Defines the arguments required for a bare call + */ +export type BareCallArgs = Omit +/** + * Maps a method signature from the StakingPool smart contract to the method's arguments in either tuple of struct form + */ +export type MethodArgs = StakingPool['methods'][TSignature]['argsObj' | 'argsTuple'] +/** + * Maps a method signature from the StakingPool smart contract to the method's return type + */ +export type MethodReturn = StakingPool['methods'][TSignature]['returns'] + +/** + * A factory for available 'create' calls + */ +export type StakingPoolCreateCalls = (typeof StakingPoolCallFactory)['create'] +/** + * Defines supported create methods for this smart contract + */ +export type StakingPoolCreateCallParams = + | (TypedCallParams<'createApplication(uint64,uint64,uint64,uint64)void'> & (OnCompleteNoOp)) +/** + * Defines arguments required for the deploy method. + */ +export type StakingPoolDeployArgs = { + deployTimeParams?: TealTemplateParams + /** + * A delegate which takes a create call factory and returns the create call params for this smart contract + */ + createCall?: (callFactory: StakingPoolCreateCalls) => StakingPoolCreateCallParams +} + + +/** + * Exposes methods for constructing all available smart contract calls + */ +export abstract class StakingPoolCallFactory { + /** + * Gets available create call factories + */ + static get create() { + return { + /** + * Constructs a create call for the StakingPool smart contract using the createApplication(uint64,uint64,uint64,uint64)void ABI method + * + * @param args Any args for the contract call + * @param params Any additional parameters for the call + * @returns A TypedCallParams object for the call + */ + createApplication(args: MethodArgs<'createApplication(uint64,uint64,uint64,uint64)void'>, params: AppClientCallCoreParams & CoreAppCallArgs & AppClientCompilationParams & (OnCompleteNoOp) = {}) { + return { + method: 'createApplication(uint64,uint64,uint64,uint64)void' as const, + methodArgs: Array.isArray(args) ? args : [args.creatingContractId, args.validatorId, args.poolId, args.minEntryStake], + ...params, + } + }, + } + } + + /** + * Constructs a no op call for the gas()void ABI method + * + * gas is a dummy no-op call that can be used to pool-up resource references and opcode cost + * + * @param args Any args for the contract call + * @param params Any additional parameters for the call + * @returns A TypedCallParams object for the call + */ + static gas(args: MethodArgs<'gas()void'>, params: AppClientCallCoreParams & CoreAppCallArgs) { + return { + method: 'gas()void' as const, + methodArgs: Array.isArray(args) ? args : [], + ...params, + } + } + /** + * Constructs a no op call for the initStorage(pay)void ABI method + * + * Called after we're created and then funded so we can create our large stakers ledger storageCaller has to get MBR amounts from ValidatorRegistry to know how much to fund us to cover the box storage costIf this is pool 1 AND the validator has specified a reward token, opt-in to that tokenso that the validator can seed the pool with future rewards of that token. + * + * @param args Any args for the contract call + * @param params Any additional parameters for the call + * @returns A TypedCallParams object for the call + */ + static initStorage(args: MethodArgs<'initStorage(pay)void'>, params: AppClientCallCoreParams & CoreAppCallArgs) { + return { + method: 'initStorage(pay)void' as const, + methodArgs: Array.isArray(args) ? args : [args.mbrPayment], + ...params, + } + } + /** + * Constructs a no op call for the addStake(pay,address)uint64 ABI method + * + * Adds stake to the given account.Can ONLY be called by the validator contract that created usMust receive payment from the validator contract for amount being staked. + * + * @param args Any args for the contract call + * @param params Any additional parameters for the call + * @returns A TypedCallParams object for the call + */ + static addStake(args: MethodArgs<'addStake(pay,address)uint64'>, params: AppClientCallCoreParams & CoreAppCallArgs) { + return { + method: 'addStake(pay,address)uint64' as const, + methodArgs: Array.isArray(args) ? args : [args.stakedAmountPayment, args.staker], + ...params, + } + } + /** + * Constructs a no op call for the removeStake(uint64)void ABI method + * + * Removes stake on behalf of caller (removing own stake). If any token rewards exist, those are always sent infull. Also notifies the validator contract for this pools validator of the staker / balance changes. + * + * @param args Any args for the contract call + * @param params Any additional parameters for the call + * @returns A TypedCallParams object for the call + */ + static removeStake(args: MethodArgs<'removeStake(uint64)void'>, params: AppClientCallCoreParams & CoreAppCallArgs) { + return { + method: 'removeStake(uint64)void' as const, + methodArgs: Array.isArray(args) ? args : [args.amountToUnstake], + ...params, + } + } + /** + * Constructs a no op call for the claimTokens()void ABI method + * + * Claims all the available reward tokens a staker has available, sending their entire balance to the staker frompool 1 (either directly, or via validator->pool1 to pay it out)Also notifies the validator contract for this pools validator of the staker / balance changes. + * + * @param args Any args for the contract call + * @param params Any additional parameters for the call + * @returns A TypedCallParams object for the call + */ + static claimTokens(args: MethodArgs<'claimTokens()void'>, params: AppClientCallCoreParams & CoreAppCallArgs) { + return { + method: 'claimTokens()void' as const, + methodArgs: Array.isArray(args) ? args : [], + ...params, + } + } + /** + * Constructs a no op call for the getStakerInfo(address)(address,uint64,uint64,uint64,uint64) ABI method + * + * Retrieves the staked information for a given staker. + * + * @param args Any args for the contract call + * @param params Any additional parameters for the call + * @returns A TypedCallParams object for the call + */ + static getStakerInfo(args: MethodArgs<'getStakerInfo(address)(address,uint64,uint64,uint64,uint64)'>, params: AppClientCallCoreParams & CoreAppCallArgs) { + return { + method: 'getStakerInfo(address)(address,uint64,uint64,uint64,uint64)' as const, + methodArgs: Array.isArray(args) ? args : [args.staker], + ...params, + } + } + /** + * Constructs a no op call for the payTokenReward(address,uint64,uint64)void ABI method + * + * [Internal protocol method] Remove a specified amount of 'community token' rewards for a staker.This can ONLY be called by our validator and only if we're pool 1 - with the token. + * + * @param args Any args for the contract call + * @param params Any additional parameters for the call + * @returns A TypedCallParams object for the call + */ + static payTokenReward(args: MethodArgs<'payTokenReward(address,uint64,uint64)void'>, params: AppClientCallCoreParams & CoreAppCallArgs) { + return { + method: 'payTokenReward(address,uint64,uint64)void' as const, + methodArgs: Array.isArray(args) ? args : [args.staker, args.rewardToken, args.amountToSend], + ...params, + } + } + /** + * Constructs a no op call for the updateAlgodVer(string)void ABI method + * + * Update the (honor system) algod version for the node associated to this pool. The node management daemonshould compare its current nodes version to the version stored in global state, updating when different.The reti node daemon composes its own version string using format:{major}.{minor}.{build}{branch}[{commit hash}],ie: 3.22.0 rel/stable [6b508975][ ONLY OWNER OR MANAGER CAN CALL ] + * + * @param args Any args for the contract call + * @param params Any additional parameters for the call + * @returns A TypedCallParams object for the call + */ + static updateAlgodVer(args: MethodArgs<'updateAlgodVer(string)void'>, params: AppClientCallCoreParams & CoreAppCallArgs) { + return { + method: 'updateAlgodVer(string)void' as const, + methodArgs: Array.isArray(args) ? args : [args.algodVer], + ...params, + } + } + /** + * Constructs a no op call for the epochBalanceUpdate()void ABI method + * + * Updates the balance of stakers in the pool based on the received 'rewards' (current balance vs known staked balance)stakers outstanding balance is adjusted based on their % of stake and time in the current epoch - so that balancecompounds over time and staker can remove that amount at will.The validator is paid their percentage each epoch payout.Note: ANYONE can call this. + * + * @param args Any args for the contract call + * @param params Any additional parameters for the call + * @returns A TypedCallParams object for the call + */ + static epochBalanceUpdate(args: MethodArgs<'epochBalanceUpdate()void'>, params: AppClientCallCoreParams & CoreAppCallArgs) { + return { + method: 'epochBalanceUpdate()void' as const, + methodArgs: Array.isArray(args) ? args : [], + ...params, + } + } + /** + * Constructs a no op call for the goOnline(byte[],byte[],byte[],uint64,uint64,uint64)void ABI method + * + * Registers a staking pool key online against a participation key.[ ONLY OWNER OR MANAGER CAN CALL ] + * + * @param args Any args for the contract call + * @param params Any additional parameters for the call + * @returns A TypedCallParams object for the call + */ + static goOnline(args: MethodArgs<'goOnline(byte[],byte[],byte[],uint64,uint64,uint64)void'>, params: AppClientCallCoreParams & CoreAppCallArgs) { + return { + method: 'goOnline(byte[],byte[],byte[],uint64,uint64,uint64)void' as const, + methodArgs: Array.isArray(args) ? args : [args.votePk, args.selectionPk, args.stateProofPk, args.voteFirst, args.voteLast, args.voteKeyDilution], + ...params, + } + } + /** + * Constructs a no op call for the goOffline()void ABI method + * + * Marks a staking pool key OFFLINE.[ ONLY OWNER OR MANAGER CAN CALL ] + * + * @param args Any args for the contract call + * @param params Any additional parameters for the call + * @returns A TypedCallParams object for the call + */ + static goOffline(args: MethodArgs<'goOffline()void'>, params: AppClientCallCoreParams & CoreAppCallArgs) { + return { + method: 'goOffline()void' as const, + methodArgs: Array.isArray(args) ? args : [], + ...params, + } + } + /** + * Constructs a no op call for the linkToNFD(uint64,string)void ABI method + * + * @param args Any args for the contract call + * @param params Any additional parameters for the call + * @returns A TypedCallParams object for the call + */ + static linkToNfd(args: MethodArgs<'linkToNFD(uint64,string)void'>, params: AppClientCallCoreParams & CoreAppCallArgs) { + return { + method: 'linkToNFD(uint64,string)void' as const, + methodArgs: Array.isArray(args) ? args : [args.nfdAppId, args.nfdName], + ...params, + } + } + /** + * Constructs a no op call for the proxiedSetTokenPayoutRatio((uint64,uint64,uint64))(uint64[24],uint64) ABI method + * + * proxiedSetTokenPayoutRatio is meant to be called by pools != 1 - calling US, pool #1We need to verify that we are in fact being called by another of OUR pools (not us)and then we'll call the validator on their behalf to update the token payouts + * + * @param args Any args for the contract call + * @param params Any additional parameters for the call + * @returns A TypedCallParams object for the call + */ + static proxiedSetTokenPayoutRatio(args: MethodArgs<'proxiedSetTokenPayoutRatio((uint64,uint64,uint64))(uint64[24],uint64)'>, params: AppClientCallCoreParams & CoreAppCallArgs) { + return { + method: 'proxiedSetTokenPayoutRatio((uint64,uint64,uint64))(uint64[24],uint64)' as const, + methodArgs: Array.isArray(args) ? args : [args.poolKey], + ...params, + } + } +} + +/** + * A client to make calls to the StakingPool smart contract + */ +export class StakingPoolClient { + /** + * The underlying `ApplicationClient` for when you want to have more flexibility + */ + public readonly appClient: ApplicationClient + + private readonly sender: SendTransactionFrom | undefined + + /** + * Creates a new instance of `StakingPoolClient` + * + * @param appDetails appDetails The details to identify the app to deploy + * @param algod An algod client instance + */ + constructor(appDetails: AppDetails, private algod: Algodv2) { + this.sender = appDetails.sender + this.appClient = algokit.getAppClient({ + ...appDetails, + app: APP_SPEC + }, algod) + } + + /** + * Checks for decode errors on the AppCallTransactionResult and maps the return value to the specified generic type + * + * @param result The AppCallTransactionResult to be mapped + * @param returnValueFormatter An optional delegate to format the return value if required + * @returns The smart contract response with an updated return value + */ + protected mapReturnValue(result: AppCallTransactionResult, returnValueFormatter?: (value: any) => TReturn): AppCallTransactionResultOfType & TResult { + if(result.return?.decodeError) { + throw result.return.decodeError + } + const returnValue = result.return?.returnValue !== undefined && returnValueFormatter !== undefined + ? returnValueFormatter(result.return.returnValue) + : result.return?.returnValue as TReturn | undefined + return { ...result, return: returnValue } as AppCallTransactionResultOfType & TResult + } + + /** + * Calls the ABI method with the matching signature using an onCompletion code of NO_OP + * + * @param typedCallParams An object containing the method signature, args, and any other relevant parameters + * @param returnValueFormatter An optional delegate which when provided will be used to map non-undefined return values to the target type + * @returns The result of the smart contract call + */ + public async call(typedCallParams: TypedCallParams, returnValueFormatter?: (value: any) => MethodReturn) { + return this.mapReturnValue>(await this.appClient.call(typedCallParams), returnValueFormatter) + } + + /** + * Idempotently deploys the StakingPool smart contract. + * + * @param params The arguments for the contract calls and any additional parameters for the call + * @returns The deployment result + */ + public deploy(params: StakingPoolDeployArgs & AppClientDeployCoreParams & IncludeSchema = {}): ReturnType { + const createArgs = params.createCall?.(StakingPoolCallFactory.create) + return this.appClient.deploy({ + ...params, + createArgs, + createOnCompleteAction: createArgs?.onCompleteAction, + }) + } + + /** + * Gets available create methods + */ + public get create() { + const $this = this + return { + /** + * Creates a new instance of the StakingPool smart contract using the createApplication(uint64,uint64,uint64,uint64)void ABI method. + * + * @param args The arguments for the smart contract call + * @param params Any additional parameters for the call + * @returns The create result + */ + async createApplication(args: MethodArgs<'createApplication(uint64,uint64,uint64,uint64)void'>, params: AppClientCallCoreParams & AppClientCompilationParams & IncludeSchema & (OnCompleteNoOp) = {}) { + return $this.mapReturnValue, AppCreateCallTransactionResult>(await $this.appClient.create(StakingPoolCallFactory.create.createApplication(args, params))) + }, + } + } + + /** + * Makes a clear_state call to an existing instance of the StakingPool smart contract. + * + * @param args The arguments for the bare call + * @returns The clear_state result + */ + public clearState(args: BareCallArgs & AppClientCallCoreParams & CoreAppCallArgs = {}) { + return this.appClient.clearState(args) + } + + /** + * Calls the gas()void ABI method. + * + * gas is a dummy no-op call that can be used to pool-up resource references and opcode cost + * + * @param args The arguments for the contract call + * @param params Any additional parameters for the call + * @returns The result of the call + */ + public gas(args: MethodArgs<'gas()void'>, params: AppClientCallCoreParams & CoreAppCallArgs = {}) { + return this.call(StakingPoolCallFactory.gas(args, params)) + } + + /** + * Calls the initStorage(pay)void ABI method. + * + * Called after we're created and then funded so we can create our large stakers ledger storageCaller has to get MBR amounts from ValidatorRegistry to know how much to fund us to cover the box storage costIf this is pool 1 AND the validator has specified a reward token, opt-in to that tokenso that the validator can seed the pool with future rewards of that token. + * + * @param args The arguments for the contract call + * @param params Any additional parameters for the call + * @returns The result of the call + */ + public initStorage(args: MethodArgs<'initStorage(pay)void'>, params: AppClientCallCoreParams & CoreAppCallArgs = {}) { + return this.call(StakingPoolCallFactory.initStorage(args, params)) + } + + /** + * Calls the addStake(pay,address)uint64 ABI method. + * + * Adds stake to the given account.Can ONLY be called by the validator contract that created usMust receive payment from the validator contract for amount being staked. + * + * @param args The arguments for the contract call + * @param params Any additional parameters for the call + * @returns The result of the call: {uint64}new 'entry time' in seconds of stake add. + */ + public addStake(args: MethodArgs<'addStake(pay,address)uint64'>, params: AppClientCallCoreParams & CoreAppCallArgs = {}) { + return this.call(StakingPoolCallFactory.addStake(args, params)) + } + + /** + * Calls the removeStake(uint64)void ABI method. + * + * Removes stake on behalf of caller (removing own stake). If any token rewards exist, those are always sent infull. Also notifies the validator contract for this pools validator of the staker / balance changes. + * + * @param args The arguments for the contract call + * @param params Any additional parameters for the call + * @returns The result of the call + */ + public removeStake(args: MethodArgs<'removeStake(uint64)void'>, params: AppClientCallCoreParams & CoreAppCallArgs = {}) { + return this.call(StakingPoolCallFactory.removeStake(args, params)) + } + + /** + * Calls the claimTokens()void ABI method. + * + * Claims all the available reward tokens a staker has available, sending their entire balance to the staker frompool 1 (either directly, or via validator->pool1 to pay it out)Also notifies the validator contract for this pools validator of the staker / balance changes. + * + * @param args The arguments for the contract call + * @param params Any additional parameters for the call + * @returns The result of the call + */ + public claimTokens(args: MethodArgs<'claimTokens()void'>, params: AppClientCallCoreParams & CoreAppCallArgs = {}) { + return this.call(StakingPoolCallFactory.claimTokens(args, params)) + } + + /** + * Calls the getStakerInfo(address)(address,uint64,uint64,uint64,uint64) ABI method. + * + * Retrieves the staked information for a given staker. + * + * @param args The arguments for the contract call + * @param params Any additional parameters for the call + * @returns The result of the call: {StakedInfo}- The staked information for the given staker. + */ + public getStakerInfo(args: MethodArgs<'getStakerInfo(address)(address,uint64,uint64,uint64,uint64)'>, params: AppClientCallCoreParams & CoreAppCallArgs = {}) { + return this.call(StakingPoolCallFactory.getStakerInfo(args, params)) + } + + /** + * Calls the payTokenReward(address,uint64,uint64)void ABI method. + * + * [Internal protocol method] Remove a specified amount of 'community token' rewards for a staker.This can ONLY be called by our validator and only if we're pool 1 - with the token. + * + * @param args The arguments for the contract call + * @param params Any additional parameters for the call + * @returns The result of the call + */ + public payTokenReward(args: MethodArgs<'payTokenReward(address,uint64,uint64)void'>, params: AppClientCallCoreParams & CoreAppCallArgs = {}) { + return this.call(StakingPoolCallFactory.payTokenReward(args, params)) + } + + /** + * Calls the updateAlgodVer(string)void ABI method. + * + * Update the (honor system) algod version for the node associated to this pool. The node management daemonshould compare its current nodes version to the version stored in global state, updating when different.The reti node daemon composes its own version string using format:{major}.{minor}.{build}{branch}[{commit hash}],ie: 3.22.0 rel/stable [6b508975][ ONLY OWNER OR MANAGER CAN CALL ] + * + * @param args The arguments for the contract call + * @param params Any additional parameters for the call + * @returns The result of the call + */ + public updateAlgodVer(args: MethodArgs<'updateAlgodVer(string)void'>, params: AppClientCallCoreParams & CoreAppCallArgs = {}) { + return this.call(StakingPoolCallFactory.updateAlgodVer(args, params)) + } + + /** + * Calls the epochBalanceUpdate()void ABI method. + * + * Updates the balance of stakers in the pool based on the received 'rewards' (current balance vs known staked balance)stakers outstanding balance is adjusted based on their % of stake and time in the current epoch - so that balancecompounds over time and staker can remove that amount at will.The validator is paid their percentage each epoch payout.Note: ANYONE can call this. + * + * @param args The arguments for the contract call + * @param params Any additional parameters for the call + * @returns The result of the call + */ + public epochBalanceUpdate(args: MethodArgs<'epochBalanceUpdate()void'>, params: AppClientCallCoreParams & CoreAppCallArgs = {}) { + return this.call(StakingPoolCallFactory.epochBalanceUpdate(args, params)) + } + + /** + * Calls the goOnline(byte[],byte[],byte[],uint64,uint64,uint64)void ABI method. + * + * Registers a staking pool key online against a participation key.[ ONLY OWNER OR MANAGER CAN CALL ] + * + * @param args The arguments for the contract call + * @param params Any additional parameters for the call + * @returns The result of the call + */ + public goOnline(args: MethodArgs<'goOnline(byte[],byte[],byte[],uint64,uint64,uint64)void'>, params: AppClientCallCoreParams & CoreAppCallArgs = {}) { + return this.call(StakingPoolCallFactory.goOnline(args, params)) + } + + /** + * Calls the goOffline()void ABI method. + * + * Marks a staking pool key OFFLINE.[ ONLY OWNER OR MANAGER CAN CALL ] + * + * @param args The arguments for the contract call + * @param params Any additional parameters for the call + * @returns The result of the call + */ + public goOffline(args: MethodArgs<'goOffline()void'>, params: AppClientCallCoreParams & CoreAppCallArgs = {}) { + return this.call(StakingPoolCallFactory.goOffline(args, params)) + } + + /** + * Calls the linkToNFD(uint64,string)void ABI method. + * + * @param args The arguments for the contract call + * @param params Any additional parameters for the call + * @returns The result of the call + */ + public linkToNfd(args: MethodArgs<'linkToNFD(uint64,string)void'>, params: AppClientCallCoreParams & CoreAppCallArgs = {}) { + return this.call(StakingPoolCallFactory.linkToNfd(args, params)) + } + + /** + * Calls the proxiedSetTokenPayoutRatio((uint64,uint64,uint64))(uint64[24],uint64) ABI method. + * + * proxiedSetTokenPayoutRatio is meant to be called by pools != 1 - calling US, pool #1We need to verify that we are in fact being called by another of OUR pools (not us)and then we'll call the validator on their behalf to update the token payouts + * + * @param args The arguments for the contract call + * @param params Any additional parameters for the call + * @returns The result of the call + */ + public proxiedSetTokenPayoutRatio(args: MethodArgs<'proxiedSetTokenPayoutRatio((uint64,uint64,uint64))(uint64[24],uint64)'>, params: AppClientCallCoreParams & CoreAppCallArgs = {}) { + return this.call(StakingPoolCallFactory.proxiedSetTokenPayoutRatio(args, params)) + } + + /** + * Extracts a binary state value out of an AppState dictionary + * + * @param state The state dictionary containing the state value + * @param key The key of the state value + * @returns A BinaryState instance containing the state value, or undefined if the key was not found + */ + private static getBinaryState(state: AppState, key: string): BinaryState | undefined { + const value = state[key] + if (!value) return undefined + if (!('valueRaw' in value)) + throw new Error(`Failed to parse state value for ${key}; received an int when expected a byte array`) + return { + asString(): string { + return value.value + }, + asByteArray(): Uint8Array { + return value.valueRaw + } + } + } + + /** + * Extracts a integer state value out of an AppState dictionary + * + * @param state The state dictionary containing the state value + * @param key The key of the state value + * @returns An IntegerState instance containing the state value, or undefined if the key was not found + */ + private static getIntegerState(state: AppState, key: string): IntegerState | undefined { + const value = state[key] + if (!value) return undefined + if ('valueRaw' in value) + throw new Error(`Failed to parse state value for ${key}; received a byte array when expected a number`) + return { + asBigInt() { + return typeof value.value === 'bigint' ? value.value : BigInt(value.value) + }, + asNumber(): number { + return typeof value.value === 'bigint' ? Number(value.value) : value.value + }, + } + } + + /** + * Returns the smart contract's global state wrapped in a strongly typed accessor with options to format the stored value + */ + public async getGlobalState(): Promise { + const state = await this.appClient.getGlobalState() + return { + get creatorApp() { + return StakingPoolClient.getIntegerState(state, 'creatorApp') + }, + get validatorId() { + return StakingPoolClient.getIntegerState(state, 'validatorId') + }, + get poolId() { + return StakingPoolClient.getIntegerState(state, 'poolId') + }, + get numStakers() { + return StakingPoolClient.getIntegerState(state, 'numStakers') + }, + get staked() { + return StakingPoolClient.getIntegerState(state, 'staked') + }, + get minEntryStake() { + return StakingPoolClient.getIntegerState(state, 'minEntryStake') + }, + get lastPayout() { + return StakingPoolClient.getIntegerState(state, 'lastPayout') + }, + get epochNumber() { + return StakingPoolClient.getIntegerState(state, 'epochNumber') + }, + get algodVer() { + return StakingPoolClient.getBinaryState(state, 'algodVer') + }, + } + } + + public compose(): StakingPoolComposer { + const client = this + const atc = new AtomicTransactionComposer() + let promiseChain:Promise = Promise.resolve() + const resultMappers: Array any)> = [] + return { + gas(args: MethodArgs<'gas()void'>, params?: AppClientComposeCallCoreParams & CoreAppCallArgs) { + promiseChain = promiseChain.then(() => client.gas(args, {...params, sendParams: {...params?.sendParams, skipSending: true, atc}})) + resultMappers.push(undefined) + return this + }, + initStorage(args: MethodArgs<'initStorage(pay)void'>, params?: AppClientComposeCallCoreParams & CoreAppCallArgs) { + promiseChain = promiseChain.then(() => client.initStorage(args, {...params, sendParams: {...params?.sendParams, skipSending: true, atc}})) + resultMappers.push(undefined) + return this + }, + addStake(args: MethodArgs<'addStake(pay,address)uint64'>, params?: AppClientComposeCallCoreParams & CoreAppCallArgs) { + promiseChain = promiseChain.then(() => client.addStake(args, {...params, sendParams: {...params?.sendParams, skipSending: true, atc}})) + resultMappers.push(undefined) + return this + }, + removeStake(args: MethodArgs<'removeStake(uint64)void'>, params?: AppClientComposeCallCoreParams & CoreAppCallArgs) { + promiseChain = promiseChain.then(() => client.removeStake(args, {...params, sendParams: {...params?.sendParams, skipSending: true, atc}})) + resultMappers.push(undefined) + return this + }, + claimTokens(args: MethodArgs<'claimTokens()void'>, params?: AppClientComposeCallCoreParams & CoreAppCallArgs) { + promiseChain = promiseChain.then(() => client.claimTokens(args, {...params, sendParams: {...params?.sendParams, skipSending: true, atc}})) + resultMappers.push(undefined) + return this + }, + getStakerInfo(args: MethodArgs<'getStakerInfo(address)(address,uint64,uint64,uint64,uint64)'>, params?: AppClientComposeCallCoreParams & CoreAppCallArgs) { + promiseChain = promiseChain.then(() => client.getStakerInfo(args, {...params, sendParams: {...params?.sendParams, skipSending: true, atc}})) + resultMappers.push(undefined) + return this + }, + payTokenReward(args: MethodArgs<'payTokenReward(address,uint64,uint64)void'>, params?: AppClientComposeCallCoreParams & CoreAppCallArgs) { + promiseChain = promiseChain.then(() => client.payTokenReward(args, {...params, sendParams: {...params?.sendParams, skipSending: true, atc}})) + resultMappers.push(undefined) + return this + }, + updateAlgodVer(args: MethodArgs<'updateAlgodVer(string)void'>, params?: AppClientComposeCallCoreParams & CoreAppCallArgs) { + promiseChain = promiseChain.then(() => client.updateAlgodVer(args, {...params, sendParams: {...params?.sendParams, skipSending: true, atc}})) + resultMappers.push(undefined) + return this + }, + epochBalanceUpdate(args: MethodArgs<'epochBalanceUpdate()void'>, params?: AppClientComposeCallCoreParams & CoreAppCallArgs) { + promiseChain = promiseChain.then(() => client.epochBalanceUpdate(args, {...params, sendParams: {...params?.sendParams, skipSending: true, atc}})) + resultMappers.push(undefined) + return this + }, + goOnline(args: MethodArgs<'goOnline(byte[],byte[],byte[],uint64,uint64,uint64)void'>, params?: AppClientComposeCallCoreParams & CoreAppCallArgs) { + promiseChain = promiseChain.then(() => client.goOnline(args, {...params, sendParams: {...params?.sendParams, skipSending: true, atc}})) + resultMappers.push(undefined) + return this + }, + goOffline(args: MethodArgs<'goOffline()void'>, params?: AppClientComposeCallCoreParams & CoreAppCallArgs) { + promiseChain = promiseChain.then(() => client.goOffline(args, {...params, sendParams: {...params?.sendParams, skipSending: true, atc}})) + resultMappers.push(undefined) + return this + }, + linkToNfd(args: MethodArgs<'linkToNFD(uint64,string)void'>, params?: AppClientComposeCallCoreParams & CoreAppCallArgs) { + promiseChain = promiseChain.then(() => client.linkToNfd(args, {...params, sendParams: {...params?.sendParams, skipSending: true, atc}})) + resultMappers.push(undefined) + return this + }, + proxiedSetTokenPayoutRatio(args: MethodArgs<'proxiedSetTokenPayoutRatio((uint64,uint64,uint64))(uint64[24],uint64)'>, params?: AppClientComposeCallCoreParams & CoreAppCallArgs) { + promiseChain = promiseChain.then(() => client.proxiedSetTokenPayoutRatio(args, {...params, sendParams: {...params?.sendParams, skipSending: true, atc}})) + resultMappers.push(undefined) + return this + }, + clearState(args?: BareCallArgs & AppClientComposeCallCoreParams & CoreAppCallArgs) { + promiseChain = promiseChain.then(() => client.clearState({...args, sendParams: {...args?.sendParams, skipSending: true, atc}})) + resultMappers.push(undefined) + return this + }, + addTransaction(txn: TransactionWithSigner | TransactionToSign | Transaction | Promise, defaultSender?: SendTransactionFrom) { + promiseChain = promiseChain.then(async () => atc.addTransaction(await algokit.getTransactionWithSigner(txn, defaultSender ?? client.sender))) + return this + }, + async atc() { + await promiseChain + return atc + }, + async simulate(options?: SimulateOptions) { + await promiseChain + const result = await atc.simulate(client.algod, new modelsv2.SimulateRequest({ txnGroups: [], ...options })) + return { + ...result, + returns: result.methodResults?.map((val, i) => resultMappers[i] !== undefined ? resultMappers[i]!(val.returnValue) : val.returnValue) + } + }, + async execute(sendParams?: AppClientComposeExecuteParams) { + await promiseChain + const result = await algokit.sendAtomicTransactionComposer({ atc, sendParams }, client.algod) + return { + ...result, + returns: result.returns?.map((val, i) => resultMappers[i] !== undefined ? resultMappers[i]!(val.returnValue) : val.returnValue) + } + } + } as unknown as StakingPoolComposer + } +} +export type StakingPoolComposer = { + /** + * Calls the gas()void ABI method. + * + * gas is a dummy no-op call that can be used to pool-up resource references and opcode cost + * + * @param args The arguments for the contract call + * @param params Any additional parameters for the call + * @returns The typed transaction composer so you can fluently chain multiple calls or call execute to execute all queued up transactions + */ + gas(args: MethodArgs<'gas()void'>, params?: AppClientComposeCallCoreParams & CoreAppCallArgs): StakingPoolComposer<[...TReturns, MethodReturn<'gas()void'>]> + + /** + * Calls the initStorage(pay)void ABI method. + * + * Called after we're created and then funded so we can create our large stakers ledger storageCaller has to get MBR amounts from ValidatorRegistry to know how much to fund us to cover the box storage costIf this is pool 1 AND the validator has specified a reward token, opt-in to that tokenso that the validator can seed the pool with future rewards of that token. + * + * @param args The arguments for the contract call + * @param params Any additional parameters for the call + * @returns The typed transaction composer so you can fluently chain multiple calls or call execute to execute all queued up transactions + */ + initStorage(args: MethodArgs<'initStorage(pay)void'>, params?: AppClientComposeCallCoreParams & CoreAppCallArgs): StakingPoolComposer<[...TReturns, MethodReturn<'initStorage(pay)void'>]> + + /** + * Calls the addStake(pay,address)uint64 ABI method. + * + * Adds stake to the given account.Can ONLY be called by the validator contract that created usMust receive payment from the validator contract for amount being staked. + * + * @param args The arguments for the contract call + * @param params Any additional parameters for the call + * @returns The typed transaction composer so you can fluently chain multiple calls or call execute to execute all queued up transactions + */ + addStake(args: MethodArgs<'addStake(pay,address)uint64'>, params?: AppClientComposeCallCoreParams & CoreAppCallArgs): StakingPoolComposer<[...TReturns, MethodReturn<'addStake(pay,address)uint64'>]> + + /** + * Calls the removeStake(uint64)void ABI method. + * + * Removes stake on behalf of caller (removing own stake). If any token rewards exist, those are always sent infull. Also notifies the validator contract for this pools validator of the staker / balance changes. + * + * @param args The arguments for the contract call + * @param params Any additional parameters for the call + * @returns The typed transaction composer so you can fluently chain multiple calls or call execute to execute all queued up transactions + */ + removeStake(args: MethodArgs<'removeStake(uint64)void'>, params?: AppClientComposeCallCoreParams & CoreAppCallArgs): StakingPoolComposer<[...TReturns, MethodReturn<'removeStake(uint64)void'>]> + + /** + * Calls the claimTokens()void ABI method. + * + * Claims all the available reward tokens a staker has available, sending their entire balance to the staker frompool 1 (either directly, or via validator->pool1 to pay it out)Also notifies the validator contract for this pools validator of the staker / balance changes. + * + * @param args The arguments for the contract call + * @param params Any additional parameters for the call + * @returns The typed transaction composer so you can fluently chain multiple calls or call execute to execute all queued up transactions + */ + claimTokens(args: MethodArgs<'claimTokens()void'>, params?: AppClientComposeCallCoreParams & CoreAppCallArgs): StakingPoolComposer<[...TReturns, MethodReturn<'claimTokens()void'>]> + + /** + * Calls the getStakerInfo(address)(address,uint64,uint64,uint64,uint64) ABI method. + * + * Retrieves the staked information for a given staker. + * + * @param args The arguments for the contract call + * @param params Any additional parameters for the call + * @returns The typed transaction composer so you can fluently chain multiple calls or call execute to execute all queued up transactions + */ + getStakerInfo(args: MethodArgs<'getStakerInfo(address)(address,uint64,uint64,uint64,uint64)'>, params?: AppClientComposeCallCoreParams & CoreAppCallArgs): StakingPoolComposer<[...TReturns, MethodReturn<'getStakerInfo(address)(address,uint64,uint64,uint64,uint64)'>]> + + /** + * Calls the payTokenReward(address,uint64,uint64)void ABI method. + * + * [Internal protocol method] Remove a specified amount of 'community token' rewards for a staker.This can ONLY be called by our validator and only if we're pool 1 - with the token. + * + * @param args The arguments for the contract call + * @param params Any additional parameters for the call + * @returns The typed transaction composer so you can fluently chain multiple calls or call execute to execute all queued up transactions + */ + payTokenReward(args: MethodArgs<'payTokenReward(address,uint64,uint64)void'>, params?: AppClientComposeCallCoreParams & CoreAppCallArgs): StakingPoolComposer<[...TReturns, MethodReturn<'payTokenReward(address,uint64,uint64)void'>]> + + /** + * Calls the updateAlgodVer(string)void ABI method. + * + * Update the (honor system) algod version for the node associated to this pool. The node management daemonshould compare its current nodes version to the version stored in global state, updating when different.The reti node daemon composes its own version string using format:{major}.{minor}.{build}{branch}[{commit hash}],ie: 3.22.0 rel/stable [6b508975][ ONLY OWNER OR MANAGER CAN CALL ] + * + * @param args The arguments for the contract call + * @param params Any additional parameters for the call + * @returns The typed transaction composer so you can fluently chain multiple calls or call execute to execute all queued up transactions + */ + updateAlgodVer(args: MethodArgs<'updateAlgodVer(string)void'>, params?: AppClientComposeCallCoreParams & CoreAppCallArgs): StakingPoolComposer<[...TReturns, MethodReturn<'updateAlgodVer(string)void'>]> + + /** + * Calls the epochBalanceUpdate()void ABI method. + * + * Updates the balance of stakers in the pool based on the received 'rewards' (current balance vs known staked balance)stakers outstanding balance is adjusted based on their % of stake and time in the current epoch - so that balancecompounds over time and staker can remove that amount at will.The validator is paid their percentage each epoch payout.Note: ANYONE can call this. + * + * @param args The arguments for the contract call + * @param params Any additional parameters for the call + * @returns The typed transaction composer so you can fluently chain multiple calls or call execute to execute all queued up transactions + */ + epochBalanceUpdate(args: MethodArgs<'epochBalanceUpdate()void'>, params?: AppClientComposeCallCoreParams & CoreAppCallArgs): StakingPoolComposer<[...TReturns, MethodReturn<'epochBalanceUpdate()void'>]> + + /** + * Calls the goOnline(byte[],byte[],byte[],uint64,uint64,uint64)void ABI method. + * + * Registers a staking pool key online against a participation key.[ ONLY OWNER OR MANAGER CAN CALL ] + * + * @param args The arguments for the contract call + * @param params Any additional parameters for the call + * @returns The typed transaction composer so you can fluently chain multiple calls or call execute to execute all queued up transactions + */ + goOnline(args: MethodArgs<'goOnline(byte[],byte[],byte[],uint64,uint64,uint64)void'>, params?: AppClientComposeCallCoreParams & CoreAppCallArgs): StakingPoolComposer<[...TReturns, MethodReturn<'goOnline(byte[],byte[],byte[],uint64,uint64,uint64)void'>]> + + /** + * Calls the goOffline()void ABI method. + * + * Marks a staking pool key OFFLINE.[ ONLY OWNER OR MANAGER CAN CALL ] + * + * @param args The arguments for the contract call + * @param params Any additional parameters for the call + * @returns The typed transaction composer so you can fluently chain multiple calls or call execute to execute all queued up transactions + */ + goOffline(args: MethodArgs<'goOffline()void'>, params?: AppClientComposeCallCoreParams & CoreAppCallArgs): StakingPoolComposer<[...TReturns, MethodReturn<'goOffline()void'>]> + + /** + * Calls the linkToNFD(uint64,string)void ABI method. + * + * @param args The arguments for the contract call + * @param params Any additional parameters for the call + * @returns The typed transaction composer so you can fluently chain multiple calls or call execute to execute all queued up transactions + */ + linkToNfd(args: MethodArgs<'linkToNFD(uint64,string)void'>, params?: AppClientComposeCallCoreParams & CoreAppCallArgs): StakingPoolComposer<[...TReturns, MethodReturn<'linkToNFD(uint64,string)void'>]> + + /** + * Calls the proxiedSetTokenPayoutRatio((uint64,uint64,uint64))(uint64[24],uint64) ABI method. + * + * proxiedSetTokenPayoutRatio is meant to be called by pools != 1 - calling US, pool #1We need to verify that we are in fact being called by another of OUR pools (not us)and then we'll call the validator on their behalf to update the token payouts + * + * @param args The arguments for the contract call + * @param params Any additional parameters for the call + * @returns The typed transaction composer so you can fluently chain multiple calls or call execute to execute all queued up transactions + */ + proxiedSetTokenPayoutRatio(args: MethodArgs<'proxiedSetTokenPayoutRatio((uint64,uint64,uint64))(uint64[24],uint64)'>, params?: AppClientComposeCallCoreParams & CoreAppCallArgs): StakingPoolComposer<[...TReturns, MethodReturn<'proxiedSetTokenPayoutRatio((uint64,uint64,uint64))(uint64[24],uint64)'>]> + + /** + * Makes a clear_state call to an existing instance of the StakingPool smart contract. + * + * @param args The arguments for the bare call + * @returns The typed transaction composer so you can fluently chain multiple calls or call execute to execute all queued up transactions + */ + clearState(args?: BareCallArgs & AppClientComposeCallCoreParams & CoreAppCallArgs): StakingPoolComposer<[...TReturns, undefined]> + + /** + * Adds a transaction to the composer + * + * @param txn One of: A TransactionWithSigner object (returned as is), a TransactionToSign object (signer is obtained from the signer property), a Transaction object (signer is extracted from the defaultSender parameter), an async SendTransactionResult returned by one of algokit utils helpers (signer is obtained from the defaultSender parameter) + * @param defaultSender The default sender to be used to obtain a signer where the object provided to the transaction parameter does not include a signer. + */ + addTransaction(txn: TransactionWithSigner | TransactionToSign | Transaction | Promise, defaultSender?: SendTransactionFrom): StakingPoolComposer + /** + * Returns the underlying AtomicTransactionComposer instance + */ + atc(): Promise + /** + * Simulates the transaction group and returns the result + */ + simulate(options?: SimulateOptions): Promise> + /** + * Executes the transaction group and returns the results + */ + execute(sendParams?: AppClientComposeExecuteParams): Promise> +} +export type SimulateOptions = Omit[0], 'txnGroups'> +export type StakingPoolComposerSimulateResult = { + returns: TReturns + methodResults: ABIResult[] + simulateResponse: modelsv2.SimulateResponse +} +export type StakingPoolComposerResults = { + returns: TReturns + groupId: string + txIds: string[] + transactions: Transaction[] +} diff --git a/contracts/contracts/clients/ValidatorRegistryClient.ts b/contracts/contracts/clients/ValidatorRegistryClient.ts new file mode 100644 index 00000000..420956a0 --- /dev/null +++ b/contracts/contracts/clients/ValidatorRegistryClient.ts @@ -0,0 +1,2739 @@ +/* eslint-disable */ +/** + * This file was automatically generated by @algorandfoundation/algokit-client-generator. + * DO NOT MODIFY IT BY HAND. + * requires: @algorandfoundation/algokit-utils: ^2 + */ +import * as algokit from '@algorandfoundation/algokit-utils' +import type { + ABIAppCallArg, + AppCallTransactionResult, + AppCallTransactionResultOfType, + AppCompilationResult, + AppReference, + AppState, + AppStorageSchema, + CoreAppCallArgs, + RawAppCallArgs, + TealTemplateParams, +} from '@algorandfoundation/algokit-utils/types/app' +import type { + AppClientCallCoreParams, + AppClientCompilationParams, + AppClientDeployCoreParams, + AppDetails, + ApplicationClient, +} from '@algorandfoundation/algokit-utils/types/app-client' +import type { AppSpec } from '@algorandfoundation/algokit-utils/types/app-spec' +import type { SendTransactionResult, TransactionToSign, SendTransactionFrom, SendTransactionParams } from '@algorandfoundation/algokit-utils/types/transaction' +import type { ABIResult, TransactionWithSigner } from 'algosdk' +import { Algodv2, OnApplicationComplete, Transaction, AtomicTransactionComposer, modelsv2 } from 'algosdk' +export const APP_SPEC: AppSpec = { + "hints": { + "createApplication(uint64)void": { + "call_config": { + "no_op": "CREATE" + } + }, + "gas()void": { + "call_config": { + "no_op": "CALL" + } + }, + "getMbrAmounts()(uint64,uint64,uint64,uint64)": { + "call_config": { + "no_op": "CALL" + } + }, + "getProtocolConstraints()(uint64,uint64,uint64,uint64,uint64,uint64,uint64,uint64,uint64,uint64,uint64)": { + "call_config": { + "no_op": "CALL" + } + }, + "getNumValidators()uint64": { + "call_config": { + "no_op": "CALL" + } + }, + "getValidatorConfig(uint64)(uint64,address,address,uint64,uint8,byte[32],uint64,uint64,uint64,uint16,uint32,address,uint64,uint64,uint8,uint64,uint64)": { + "call_config": { + "no_op": "CALL" + } + }, + "getValidatorState(uint64)(uint16,uint64,uint64,uint64)": { + "call_config": { + "no_op": "CALL" + } + }, + "getValidatorOwnerAndManager(uint64)(address,address)": { + "call_config": { + "no_op": "CALL" + } + }, + "getPools(uint64)(uint64,uint16,uint64)[]": { + "call_config": { + "no_op": "CALL" + } + }, + "getPoolAppId(uint64,uint64)uint64": { + "call_config": { + "no_op": "CALL" + } + }, + "getPoolInfo((uint64,uint64,uint64))(uint64,uint16,uint64)": { + "call_config": { + "no_op": "CALL" + } + }, + "getCurMaxStakePerPool(uint64)uint64": { + "call_config": { + "no_op": "CALL" + } + }, + "doesStakerNeedToPayMBR(address)bool": { + "call_config": { + "no_op": "CALL" + } + }, + "getStakedPoolsForAccount(address)(uint64,uint64,uint64)[]": { + "call_config": { + "no_op": "CALL" + } + }, + "getTokenPayoutRatio(uint64)(uint64[24],uint64)": { + "call_config": { + "no_op": "CALL" + } + }, + "getNodePoolAssignments(uint64)((uint64[3])[8])": { + "call_config": { + "no_op": "CALL" + } + }, + "getNFDRegistryID()uint64": { + "call_config": { + "no_op": "CALL" + } + }, + "addValidator(pay,string,(uint64,address,address,uint64,uint8,byte[32],uint64,uint64,uint64,uint16,uint32,address,uint64,uint64,uint8,uint64,uint64))uint64": { + "call_config": { + "no_op": "CALL" + } + }, + "changeValidatorManager(uint64,address)void": { + "call_config": { + "no_op": "CALL" + } + }, + "changeValidatorSunsetInfo(uint64,uint64,uint64)void": { + "call_config": { + "no_op": "CALL" + } + }, + "changeValidatorNFD(uint64,uint64,string)void": { + "call_config": { + "no_op": "CALL" + } + }, + "changeValidatorCommissionAddress(uint64,address)void": { + "call_config": { + "no_op": "CALL" + } + }, + "changeValidatorRewardInfo(uint64,uint8,byte[32],uint64,uint64)void": { + "call_config": { + "no_op": "CALL" + } + }, + "addPool(pay,uint64,uint64)(uint64,uint64,uint64)": { + "call_config": { + "no_op": "CALL" + } + }, + "addStake(pay,uint64,uint64)(uint64,uint64,uint64)": { + "call_config": { + "no_op": "CALL" + } + }, + "setTokenPayoutRatio(uint64)(uint64[24],uint64)": { + "call_config": { + "no_op": "CALL" + } + }, + "stakeUpdatedViaRewards((uint64,uint64,uint64),uint64,uint64)void": { + "call_config": { + "no_op": "CALL" + } + }, + "stakeRemoved((uint64,uint64,uint64),address,uint64,uint64,bool)void": { + "call_config": { + "no_op": "CALL" + } + }, + "findPoolForStaker(uint64,address,uint64)((uint64,uint64,uint64),bool,bool)": { + "call_config": { + "no_op": "CALL" + } + }, + "movePoolToNode(uint64,uint64,uint64)void": { + "call_config": { + "no_op": "CALL" + } + } + }, + "bare_call_config": { + "no_op": "NEVER", + "opt_in": "NEVER", + "close_out": "NEVER", + "update_application": "NEVER", + "delete_application": "NEVER" + }, + "schema": { + "local": { + "declared": {}, + "reserved": {} + }, + "global": { + "declared": { + "numValidators": { + "type": "uint64", + "key": "numV" + }, + "stakingPoolTemplateAppId": { + "type": "uint64", + "key": "poolTemplateAppId" + }, + "numStakers": { + "type": "uint64", + "key": "numStakers" + }, + "totalAlgoStaked": { + "type": "uint64", + "key": "staked" + } + }, + "reserved": {} + } + }, + "state": { + "global": { + "num_byte_slices": 0, + "num_uints": 4 + }, + "local": { + "num_byte_slices": 0, + "num_uints": 0 + } + }, + "source": { + "approval": "I3ByYWdtYSB2ZXJzaW9uIDEwCgovLyBUaGlzIFRFQUwgd2FzIGdlbmVyYXRlZCBieSBURUFMU2NyaXB0IHYwLjg4LjEKLy8gaHR0cHM6Ly9naXRodWIuY29tL2FsZ29yYW5kZm91bmRhdGlvbi9URUFMU2NyaXB0CgovLyBUaGlzIGNvbnRyYWN0IGlzIGNvbXBsaWFudCB3aXRoIGFuZC9vciBpbXBsZW1lbnRzIHRoZSBmb2xsb3dpbmcgQVJDczogWyBBUkM0IF0KCi8vIFRoZSBmb2xsb3dpbmcgdGVuIGxpbmVzIG9mIFRFQUwgaGFuZGxlIGluaXRpYWwgcHJvZ3JhbSBmbG93Ci8vIFRoaXMgcGF0dGVybiBpcyB1c2VkIHRvIG1ha2UgaXQgZWFzeSBmb3IgYW55b25lIHRvIHBhcnNlIHRoZSBzdGFydCBvZiB0aGUgcHJvZ3JhbSBhbmQgZGV0ZXJtaW5lIGlmIGEgc3BlY2lmaWMgYWN0aW9uIGlzIGFsbG93ZWQKLy8gSGVyZSwgYWN0aW9uIHJlZmVycyB0byB0aGUgT25Db21wbGV0ZSBpbiBjb21iaW5hdGlvbiB3aXRoIHdoZXRoZXIgdGhlIGFwcCBpcyBiZWluZyBjcmVhdGVkIG9yIGNhbGxlZAovLyBFdmVyeSBwb3NzaWJsZSBhY3Rpb24gZm9yIHRoaXMgY29udHJhY3QgaXMgcmVwcmVzZW50ZWQgaW4gdGhlIHN3aXRjaCBzdGF0ZW1lbnQKLy8gSWYgdGhlIGFjdGlvbiBpcyBub3QgaW1wbGVtZW50ZWQgaW4gdGhlIGNvbnRyYWN0LCBpdHMgcmVzcGVjdGl2ZSBicmFuY2ggd2lsbCBiZSAiKk5PVF9JTVBMRU1FTlRFRCIgd2hpY2gganVzdCBjb250YWlucyAiZXJyIgp0eG4gQXBwbGljYXRpb25JRAohCmludCA2CioKdHhuIE9uQ29tcGxldGlvbgorCnN3aXRjaCAqY2FsbF9Ob09wICpOT1RfSU1QTEVNRU5URUQgKk5PVF9JTVBMRU1FTlRFRCAqTk9UX0lNUExFTUVOVEVEICpOT1RfSU1QTEVNRU5URUQgKk5PVF9JTVBMRU1FTlRFRCAqY3JlYXRlX05vT3AgKk5PVF9JTVBMRU1FTlRFRCAqTk9UX0lNUExFTUVOVEVEICpOT1RfSU1QTEVNRU5URUQgKk5PVF9JTVBMRU1FTlRFRCAqTk9UX0lNUExFTUVOVEVECgoqTk9UX0lNUExFTUVOVEVEOgoJZXJyCgovLyBjcmVhdGVBcHBsaWNhdGlvbih1aW50NjQpdm9pZAoqYWJpX3JvdXRlX2NyZWF0ZUFwcGxpY2F0aW9uOgoJLy8gcG9vbFRlbXBsYXRlQXBwSWQ6IHVpbnQ2NAoJdHhuYSBBcHBsaWNhdGlvbkFyZ3MgMQoJYnRvaQoKCS8vIGV4ZWN1dGUgY3JlYXRlQXBwbGljYXRpb24odWludDY0KXZvaWQKCWNhbGxzdWIgY3JlYXRlQXBwbGljYXRpb24KCWludCAxCglyZXR1cm4KCi8vIGNyZWF0ZUFwcGxpY2F0aW9uKHBvb2xUZW1wbGF0ZUFwcElkOiB1aW50NjQpOiB2b2lkCmNyZWF0ZUFwcGxpY2F0aW9uOgoJcHJvdG8gMSAwCgoJLy8gY29udHJhY3RzL3ZhbGlkYXRvclJlZ2lzdHJ5LmFsZ28udHM6MTk0CgkvLyB0aGlzLm51bVZhbGlkYXRvcnMudmFsdWUgPSAwCglieXRlIDB4NmU3NTZkNTYgLy8gIm51bVYiCglpbnQgMAoJYXBwX2dsb2JhbF9wdXQKCgkvLyBjb250cmFjdHMvdmFsaWRhdG9yUmVnaXN0cnkuYWxnby50czoxOTUKCS8vIHRoaXMuc3Rha2luZ1Bvb2xUZW1wbGF0ZUFwcElkLnZhbHVlID0gcG9vbFRlbXBsYXRlQXBwSWQKCWJ5dGUgMHg3MDZmNmY2YzU0NjU2ZDcwNmM2MTc0NjU0MTcwNzA0OTY0IC8vICJwb29sVGVtcGxhdGVBcHBJZCIKCWZyYW1lX2RpZyAtMSAvLyBwb29sVGVtcGxhdGVBcHBJZDogdWludDY0CglhcHBfZ2xvYmFsX3B1dAoKCS8vIGNvbnRyYWN0cy92YWxpZGF0b3JSZWdpc3RyeS5hbGdvLnRzOjE5NgoJLy8gdGhpcy5udW1TdGFrZXJzLnZhbHVlID0gMAoJYnl0ZSAweDZlNzU2ZDUzNzQ2MTZiNjU3MjczIC8vICJudW1TdGFrZXJzIgoJaW50IDAKCWFwcF9nbG9iYWxfcHV0CgoJLy8gY29udHJhY3RzL3ZhbGlkYXRvclJlZ2lzdHJ5LmFsZ28udHM6MTk3CgkvLyB0aGlzLnRvdGFsQWxnb1N0YWtlZC52YWx1ZSA9IDAKCWJ5dGUgMHg3Mzc0NjE2YjY1NjQgLy8gInN0YWtlZCIKCWludCAwCglhcHBfZ2xvYmFsX3B1dAoJcmV0c3ViCgovLyBnYXMoKXZvaWQKKmFiaV9yb3V0ZV9nYXM6CgkvLyBleGVjdXRlIGdhcygpdm9pZAoJY2FsbHN1YiBnYXMKCWludCAxCglyZXR1cm4KCi8vIGdhcygpOiB2b2lkCi8vCi8vIGdhcyBpcyBhIGR1bW15IG5vLW9wIGNhbGwgdGhhdCBjYW4gYmUgdXNlZCB0byBwb29sLXVwIHJlc291cmNlIHJlZmVyZW5jZXMgYW5kIG9wY29kZSBjb3N0CmdhczoKCXByb3RvIDAgMAoJcmV0c3ViCgovLyBnZXRNYnJBbW91bnRzKCkodWludDY0LHVpbnQ2NCx1aW50NjQsdWludDY0KQoqYWJpX3JvdXRlX2dldE1ickFtb3VudHM6CgkvLyBUaGUgQUJJIHJldHVybiBwcmVmaXgKCWJ5dGUgMHgxNTFmN2M3NQoKCS8vIGV4ZWN1dGUgZ2V0TWJyQW1vdW50cygpKHVpbnQ2NCx1aW50NjQsdWludDY0LHVpbnQ2NCkKCWNhbGxzdWIgZ2V0TWJyQW1vdW50cwoJY29uY2F0Cglsb2cKCWludCAxCglyZXR1cm4KCi8vIGdldE1ickFtb3VudHMoKTogTWJyQW1vdW50cwovLwovLyBSZXR1cm5zIHRoZSBNQlIgYW1vdW50cyBuZWVkZWQgZm9yIHZhcmlvdXMgYWN0aW9uczoKLy8gWwovLyBhZGRWYWxpZGF0b3JNYnI6IHVpbnQ2NCAtIG1iciBuZWVkZWQgdG8gYWRkIGEgbmV3IHZhbGlkYXRvciAtIHBhaWQgdG8gdmFsaWRhdG9yIGNvbnRyYWN0Ci8vIGFkZFBvb2xNYnI6IHVpbnQ2NCAtIG1iciBuZWVkZWQgdG8gYWRkIGEgbmV3IHBvb2wgLSBwYWlkIHRvIHZhbGlkYXRvcgovLyBwb29sSW5pdE1icjogdWludDY0IC0gbWJyIG5lZWRlZCB0byBpbml0U3RvcmFnZSgpIG9mIHBvb2wgLSBwYWlkIHRvIHBvb2wgaXRzZWxmCi8vIGFkZFN0YWtlck1icjogdWludDY0IC0gbWJyIHN0YWtlciBuZWVkcyB0byBhZGQgdG8gZmlyc3Qgc3Rha2luZyBwYXltZW50IChzdGF5cyB3LyB2YWxpZGF0b3IpCi8vIF0KZ2V0TWJyQW1vdW50czoKCXByb3RvIDAgMQoKCS8vIGNvbnRyYWN0cy92YWxpZGF0b3JSZWdpc3RyeS5hbGdvLnRzOjIxNwoJLy8gcmV0dXJuIHsKCS8vICAgICAgICAgICAgIGFkZFZhbGlkYXRvck1icjogdGhpcy5jb3N0Rm9yQm94U3RvcmFnZSgxIC8qIHYgcHJlZml4ICovICsgbGVuPFZhbGlkYXRvcklkVHlwZT4oKSArIGxlbjxWYWxpZGF0b3JJbmZvPigpKSwKCS8vICAgICAgICAgICAgIGFkZFBvb2xNYnI6IHRoaXMubWluQmFsYW5jZUZvckFjY291bnQoCgkvLyAgICAgICAgICAgICAgICAgMSwKCS8vICAgICAgICAgICAgICAgICAwLAoJLy8gICAgICAgICAgICAgICAgIDAsCgkvLyAgICAgICAgICAgICAgICAgMCwKCS8vICAgICAgICAgICAgICAgICAwLAoJLy8gICAgICAgICAgICAgICAgIFN0YWtpbmdQb29sLnNjaGVtYS5nbG9iYWwubnVtVWludCwKCS8vICAgICAgICAgICAgICAgICBTdGFraW5nUG9vbC5zY2hlbWEuZ2xvYmFsLm51bUJ5dGVTbGljZQoJLy8gICAgICAgICAgICAgKSwKCS8vICAgICAgICAgICAgIHBvb2xJbml0TWJyOgoJLy8gICAgICAgICAgICAgICAgIEFMR09SQU5EX0FDQ09VTlRfTUlOX0JBTEFOQ0UgKwoJLy8gICAgICAgICAgICAgICAgIHRoaXMuY29zdEZvckJveFN0b3JhZ2UoNyAvKiAnc3Rha2VycycgbmFtZSAqLyArIGxlbjxTdGFrZWRJbmZvPigpICogTUFYX1NUQUtFUlNfUEVSX1BPT0wpLAoJLy8gICAgICAgICAgICAgYWRkU3Rha2VyTWJyOgoJLy8gICAgICAgICAgICAgICAgIC8vIGhvdyBtdWNoIHRvIGNoYXJnZSBmb3IgZmlyc3QgdGltZSBhIHN0YWtlciBhZGRzIHN0YWtlIC0gc2luY2Ugd2UgYWRkIGEgdHJhY2tpbmcgYm94IHBlciBzdGFrZXIKCS8vICAgICAgICAgICAgICAgICB0aGlzLmNvc3RGb3JCb3hTdG9yYWdlKAoJLy8gICAgICAgICAgICAgICAgICAgICAzIC8qICdzcHMnIHByZWZpeCAqLyArIGxlbjxBZGRyZXNzPigpICsgbGVuPFZhbGlkYXRvclBvb2xLZXk+KCkgKiBNQVhfUE9PTFNfUEVSX1NUQUtFUgoJLy8gICAgICAgICAgICAgICAgICksIC8vIHNpemUgb2Yga2V5ICsgYWxsIHZhbHVlcwoJLy8gICAgICAgICB9OwoJaW50IDEwNjcKCWNhbGxzdWIgY29zdEZvckJveFN0b3JhZ2UKCWl0b2IKCWludCAxCglpbnQgOAoJaW50IDAKCWR1cG4gMwoJaW50IDEKCWNhbGxzdWIgbWluQmFsYW5jZUZvckFjY291bnQKCWl0b2IKCWNvbmNhdAoJaW50IDEwMDAwMAoJaW50IDEyODA3CgljYWxsc3ViIGNvc3RGb3JCb3hTdG9yYWdlCgkrCglpdG9iCgljb25jYXQKCWludCAxNzkKCWNhbGxzdWIgY29zdEZvckJveFN0b3JhZ2UKCWl0b2IKCWNvbmNhdAoJcmV0c3ViCgovLyBnZXRQcm90b2NvbENvbnN0cmFpbnRzKCkodWludDY0LHVpbnQ2NCx1aW50NjQsdWludDY0LHVpbnQ2NCx1aW50NjQsdWludDY0LHVpbnQ2NCx1aW50NjQsdWludDY0LHVpbnQ2NCkKKmFiaV9yb3V0ZV9nZXRQcm90b2NvbENvbnN0cmFpbnRzOgoJLy8gVGhlIEFCSSByZXR1cm4gcHJlZml4CglieXRlIDB4MTUxZjdjNzUKCgkvLyBleGVjdXRlIGdldFByb3RvY29sQ29uc3RyYWludHMoKSh1aW50NjQsdWludDY0LHVpbnQ2NCx1aW50NjQsdWludDY0LHVpbnQ2NCx1aW50NjQsdWludDY0LHVpbnQ2NCx1aW50NjQsdWludDY0KQoJY2FsbHN1YiBnZXRQcm90b2NvbENvbnN0cmFpbnRzCgljb25jYXQKCWxvZwoJaW50IDEKCXJldHVybgoKLy8gZ2V0UHJvdG9jb2xDb25zdHJhaW50cygpOiBDb25zdHJhaW50cwovLwovLyBSZXR1cm5zIHRoZSBwcm90b2NvbCBjb25zdHJhaW50cyBzbyB0aGF0IFVJcyBjYW4gbGltaXQgd2hhdCB1c2VycyBzcGVjaWZ5IGZvciB2YWxpZGF0b3IgY29uZmlndXJhdGlvbiBwYXJhbWV0ZXJzLgpnZXRQcm90b2NvbENvbnN0cmFpbnRzOgoJcHJvdG8gMCAxCgoJLy8gY29udHJhY3RzL3ZhbGlkYXRvclJlZ2lzdHJ5LmFsZ28udHM6MjQzCgkvLyByZXR1cm4gewoJLy8gICAgICAgICAgICAgZXBvY2hQYXlvdXRNaW5zTWluOiBNSU5fUEFZT1VUX01JTlMsCgkvLyAgICAgICAgICAgICBlcG9jaFBheW91dE1pbnNNYXg6IE1BWF9QQVlPVVRfTUlOUywKCS8vICAgICAgICAgICAgIG1pblBjdFRvVmFsaWRhdG9yV0ZvdXJEZWNpbWFsczogTUlOX1BDVF9UT19WQUxJREFUT1IsCgkvLyAgICAgICAgICAgICBtYXhQY3RUb1ZhbGlkYXRvcldGb3VyRGVjaW1hbHM6IE1BWF9QQ1RfVE9fVkFMSURBVE9SLAoJLy8gICAgICAgICAgICAgbWluRW50cnlTdGFrZTogTUlOX0FMR09fU1RBS0VfUEVSX1BPT0wsCgkvLyAgICAgICAgICAgICBtYXhBbGdvUGVyUG9vbDogdGhpcy5tYXhBbGdvQWxsb3dlZFBlclBvb2woKSwKCS8vICAgICAgICAgICAgIG1heEFsZ29QZXJWYWxpZGF0b3I6IHRoaXMubWF4QWxsb3dlZFN0YWtlKCksCgkvLyAgICAgICAgICAgICBhbXRDb25zaWRlcmVkU2F0dXJhdGVkOiB0aGlzLmFsZ29TYXR1cmF0aW9uTGV2ZWwoKSwKCS8vICAgICAgICAgICAgIG1heE5vZGVzOiBNQVhfTk9ERVMsCgkvLyAgICAgICAgICAgICBtYXhQb29sc1Blck5vZGU6IE1BWF9QT09MU19QRVJfTk9ERSwKCS8vICAgICAgICAgICAgIG1heFN0YWtlcnNQZXJQb29sOiBNQVhfU1RBS0VSU19QRVJfUE9PTCwKCS8vICAgICAgICAgfTsKCWJ5dGUgMHgwMDAwMDAwMDAwMDAwMDAxMDAwMDAwMDAwMDAwMjc2MDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMGY0MjQwMDAwMDAwMDAwMDBmNDI0MAoJY2FsbHN1YiBtYXhBbGdvQWxsb3dlZFBlclBvb2wKCWl0b2IKCWNvbmNhdAoJY2FsbHN1YiBtYXhBbGxvd2VkU3Rha2UKCWl0b2IKCWNvbmNhdAoJY2FsbHN1YiBhbGdvU2F0dXJhdGlvbkxldmVsCglpdG9iCgljb25jYXQKCWJ5dGUgMHgwMDAwMDAwMDAwMDAwMDA4Cgljb25jYXQKCWJ5dGUgMHgwMDAwMDAwMDAwMDAwMDAzCgljb25jYXQKCWJ5dGUgMHgwMDAwMDAwMDAwMDAwMGM4Cgljb25jYXQKCXJldHN1YgoKLy8gZ2V0TnVtVmFsaWRhdG9ycygpdWludDY0CiphYmlfcm91dGVfZ2V0TnVtVmFsaWRhdG9yczoKCS8vIFRoZSBBQkkgcmV0dXJuIHByZWZpeAoJYnl0ZSAweDE1MWY3Yzc1CgoJLy8gZXhlY3V0ZSBnZXROdW1WYWxpZGF0b3JzKCl1aW50NjQKCWNhbGxzdWIgZ2V0TnVtVmFsaWRhdG9ycwoJaXRvYgoJY29uY2F0Cglsb2cKCWludCAxCglyZXR1cm4KCi8vIGdldE51bVZhbGlkYXRvcnMoKTogdWludDY0Ci8vCi8vIFJldHVybnMgdGhlIGN1cnJlbnQgbnVtYmVyIG9mIHZhbGlkYXRvcnMKZ2V0TnVtVmFsaWRhdG9yczoKCXByb3RvIDAgMQoKCS8vIGNvbnRyYWN0cy92YWxpZGF0b3JSZWdpc3RyeS5hbGdvLnRzOjI2MwoJLy8gcmV0dXJuIHRoaXMubnVtVmFsaWRhdG9ycy52YWx1ZTsKCWJ5dGUgMHg2ZTc1NmQ1NiAvLyAibnVtViIKCWFwcF9nbG9iYWxfZ2V0CglyZXRzdWIKCi8vIGdldFZhbGlkYXRvckNvbmZpZyh1aW50NjQpKHVpbnQ2NCxhZGRyZXNzLGFkZHJlc3MsdWludDY0LHVpbnQ4LGJ5dGVbMzJdLHVpbnQ2NCx1aW50NjQsdWludDY0LHVpbnQxNix1aW50MzIsYWRkcmVzcyx1aW50NjQsdWludDY0LHVpbnQ4LHVpbnQ2NCx1aW50NjQpCiphYmlfcm91dGVfZ2V0VmFsaWRhdG9yQ29uZmlnOgoJLy8gVGhlIEFCSSByZXR1cm4gcHJlZml4CglieXRlIDB4MTUxZjdjNzUKCgkvLyB2YWxpZGF0b3JJZDogdWludDY0Cgl0eG5hIEFwcGxpY2F0aW9uQXJncyAxCglidG9pCgoJLy8gZXhlY3V0ZSBnZXRWYWxpZGF0b3JDb25maWcodWludDY0KSh1aW50NjQsYWRkcmVzcyxhZGRyZXNzLHVpbnQ2NCx1aW50OCxieXRlWzMyXSx1aW50NjQsdWludDY0LHVpbnQ2NCx1aW50MTYsdWludDMyLGFkZHJlc3MsdWludDY0LHVpbnQ2NCx1aW50OCx1aW50NjQsdWludDY0KQoJY2FsbHN1YiBnZXRWYWxpZGF0b3JDb25maWcKCWNvbmNhdAoJbG9nCglpbnQgMQoJcmV0dXJuCgovLyBnZXRWYWxpZGF0b3JDb25maWcodmFsaWRhdG9ySWQ6IFZhbGlkYXRvcklkVHlwZSk6IFZhbGlkYXRvckNvbmZpZwpnZXRWYWxpZGF0b3JDb25maWc6Cglwcm90byAxIDEKCgkvLyBjb250cmFjdHMvdmFsaWRhdG9yUmVnaXN0cnkuYWxnby50czoyNjgKCS8vIHJldHVybiB0aGlzLnZhbGlkYXRvckxpc3QodmFsaWRhdG9ySWQpLnZhbHVlLmNvbmZpZzsKCWludCAwCglpbnQgMjA4CglieXRlIDB4NzYgLy8gInYiCglmcmFtZV9kaWcgLTEgLy8gdmFsaWRhdG9ySWQ6IFZhbGlkYXRvcklkVHlwZQoJaXRvYgoJY29uY2F0Cgljb3ZlciAyCglib3hfZXh0cmFjdAoJcmV0c3ViCgovLyBnZXRWYWxpZGF0b3JTdGF0ZSh1aW50NjQpKHVpbnQxNix1aW50NjQsdWludDY0LHVpbnQ2NCkKKmFiaV9yb3V0ZV9nZXRWYWxpZGF0b3JTdGF0ZToKCS8vIFRoZSBBQkkgcmV0dXJuIHByZWZpeAoJYnl0ZSAweDE1MWY3Yzc1CgoJLy8gdmFsaWRhdG9ySWQ6IHVpbnQ2NAoJdHhuYSBBcHBsaWNhdGlvbkFyZ3MgMQoJYnRvaQoKCS8vIGV4ZWN1dGUgZ2V0VmFsaWRhdG9yU3RhdGUodWludDY0KSh1aW50MTYsdWludDY0LHVpbnQ2NCx1aW50NjQpCgljYWxsc3ViIGdldFZhbGlkYXRvclN0YXRlCgljb25jYXQKCWxvZwoJaW50IDEKCXJldHVybgoKLy8gZ2V0VmFsaWRhdG9yU3RhdGUodmFsaWRhdG9ySWQ6IFZhbGlkYXRvcklkVHlwZSk6IFZhbGlkYXRvckN1clN0YXRlCmdldFZhbGlkYXRvclN0YXRlOgoJcHJvdG8gMSAxCgoJLy8gY29udHJhY3RzL3ZhbGlkYXRvclJlZ2lzdHJ5LmFsZ28udHM6MjczCgkvLyByZXR1cm4gdGhpcy52YWxpZGF0b3JMaXN0KHZhbGlkYXRvcklkKS52YWx1ZS5zdGF0ZTsKCWludCAyMDggLy8gaGVhZE9mZnNldAoJaW50IDI2CglieXRlIDB4NzYgLy8gInYiCglmcmFtZV9kaWcgLTEgLy8gdmFsaWRhdG9ySWQ6IFZhbGlkYXRvcklkVHlwZQoJaXRvYgoJY29uY2F0Cgljb3ZlciAyCglib3hfZXh0cmFjdAoJcmV0c3ViCgovLyBnZXRWYWxpZGF0b3JPd25lckFuZE1hbmFnZXIodWludDY0KShhZGRyZXNzLGFkZHJlc3MpCiphYmlfcm91dGVfZ2V0VmFsaWRhdG9yT3duZXJBbmRNYW5hZ2VyOgoJLy8gVGhlIEFCSSByZXR1cm4gcHJlZml4CglieXRlIDB4MTUxZjdjNzUKCgkvLyB2YWxpZGF0b3JJZDogdWludDY0Cgl0eG5hIEFwcGxpY2F0aW9uQXJncyAxCglidG9pCgoJLy8gZXhlY3V0ZSBnZXRWYWxpZGF0b3JPd25lckFuZE1hbmFnZXIodWludDY0KShhZGRyZXNzLGFkZHJlc3MpCgljYWxsc3ViIGdldFZhbGlkYXRvck93bmVyQW5kTWFuYWdlcgoJY29uY2F0Cglsb2cKCWludCAxCglyZXR1cm4KCi8vIGdldFZhbGlkYXRvck93bmVyQW5kTWFuYWdlcih2YWxpZGF0b3JJZDogVmFsaWRhdG9ySWRUeXBlKTogW0FkZHJlc3MsIEFkZHJlc3NdCmdldFZhbGlkYXRvck93bmVyQW5kTWFuYWdlcjoKCXByb3RvIDEgMQoKCS8vIGNvbnRyYWN0cy92YWxpZGF0b3JSZWdpc3RyeS5hbGdvLnRzOjI3OAoJLy8gcmV0dXJuIFsKCS8vICAgICAgICAgICAgIHRoaXMudmFsaWRhdG9yTGlzdCh2YWxpZGF0b3JJZCkudmFsdWUuY29uZmlnLm93bmVyLAoJLy8gICAgICAgICAgICAgdGhpcy52YWxpZGF0b3JMaXN0KHZhbGlkYXRvcklkKS52YWx1ZS5jb25maWcubWFuYWdlciwKCS8vICAgICAgICAgXTsKCWludCA4CglpbnQgMzIKCWJ5dGUgMHg3NiAvLyAidiIKCWZyYW1lX2RpZyAtMSAvLyB2YWxpZGF0b3JJZDogVmFsaWRhdG9ySWRUeXBlCglpdG9iCgljb25jYXQKCWNvdmVyIDIKCWJveF9leHRyYWN0CglpbnQgNDAKCWludCAzMgoJYnl0ZSAweDc2IC8vICJ2IgoJZnJhbWVfZGlnIC0xIC8vIHZhbGlkYXRvcklkOiBWYWxpZGF0b3JJZFR5cGUKCWl0b2IKCWNvbmNhdAoJY292ZXIgMgoJYm94X2V4dHJhY3QKCWNvbmNhdAoJcmV0c3ViCgovLyBnZXRQb29scyh1aW50NjQpKHVpbnQ2NCx1aW50MTYsdWludDY0KVtdCiphYmlfcm91dGVfZ2V0UG9vbHM6CgkvLyBUaGUgQUJJIHJldHVybiBwcmVmaXgKCWJ5dGUgMHgxNTFmN2M3NQoKCS8vIHZhbGlkYXRvcklkOiB1aW50NjQKCXR4bmEgQXBwbGljYXRpb25BcmdzIDEKCWJ0b2kKCgkvLyBleGVjdXRlIGdldFBvb2xzKHVpbnQ2NCkodWludDY0LHVpbnQxNix1aW50NjQpW10KCWNhbGxzdWIgZ2V0UG9vbHMKCWR1cAoJbGVuCglpbnQgMTgKCS8KCWl0b2IKCWV4dHJhY3QgNiAyCglzd2FwCgljb25jYXQKCWNvbmNhdAoJbG9nCglpbnQgMQoJcmV0dXJuCgovLyBnZXRQb29scyh2YWxpZGF0b3JJZDogVmFsaWRhdG9ySWRUeXBlKTogUG9vbEluZm9bXQovLwovLyBSZXR1cm4gbGlzdCBvZiBhbGwgcG9vbHMgZm9yIHRoaXMgdmFsaWRhdG9yLgovLyBAcGFyYW0ge3VpbnQ2NH0gdmFsaWRhdG9ySWQKLy8gQHJldHVybiB7UG9vbEluZm9bXX0gLSBhcnJheSBvZiBwb29scwovLyBOb3QgY2FsbGFibGUgZnJvbSBvdGhlciBjb250cmFjdHMgYmVjYXVzZSA+MUsgcmV0dXJuIGJ1dCBjYW4gYmUgY2FsbGVkIHcvIHNpbXVsYXRlIHdoaWNoIGJ1bXBzIGxvZyByZXR1cm5zCmdldFBvb2xzOgoJcHJvdG8gMSAxCgoJLy8gUHVzaCBlbXB0eSBieXRlcyBhZnRlciB0aGUgZnJhbWUgcG9pbnRlciB0byByZXNlcnZlIHNwYWNlIGZvciBsb2NhbCB2YXJpYWJsZXMKCWJ5dGUgMHgKCWR1cG4gMgoKCS8vIGNvbnRyYWN0cy92YWxpZGF0b3JSZWdpc3RyeS5hbGdvLnRzOjI5MgoJLy8gcmV0RGF0YTogUG9vbEluZm9bXSA9IFtdCglieXRlIDB4CglmcmFtZV9idXJ5IDAgLy8gcmV0RGF0YTogUG9vbEluZm9bXQoKCS8vIGNvbnRyYWN0cy92YWxpZGF0b3JSZWdpc3RyeS5hbGdvLnRzOjI5MwoJLy8gcG9vbFNldCA9IGNsb25lKHRoaXMudmFsaWRhdG9yTGlzdCh2YWxpZGF0b3JJZCkudmFsdWUucG9vbHMpCglpbnQgMjM0IC8vIGhlYWRPZmZzZXQKCWludCA0MzIKCWJ5dGUgMHg3NiAvLyAidiIKCWZyYW1lX2RpZyAtMSAvLyB2YWxpZGF0b3JJZDogVmFsaWRhdG9ySWRUeXBlCglpdG9iCgljb25jYXQKCWNvdmVyIDIKCWJveF9leHRyYWN0CglmcmFtZV9idXJ5IDEgLy8gcG9vbFNldDogKHVpbnQ2NCx1aW50MTYsdWludDY0KVsyNF0KCgkvLyBjb250cmFjdHMvdmFsaWRhdG9yUmVnaXN0cnkuYWxnby50czoyOTQKCS8vIGZvciAobGV0IGkgPSAwOyBpIDwgcG9vbFNldC5sZW5ndGg7IGkgKz0gMSkKCWludCAwCglmcmFtZV9idXJ5IDIgLy8gaTogdWludDY0CgoqZm9yXzA6CgkvLyBjb250cmFjdHMvdmFsaWRhdG9yUmVnaXN0cnkuYWxnby50czoyOTQKCS8vIGkgPCBwb29sU2V0Lmxlbmd0aAoJZnJhbWVfZGlnIDIgLy8gaTogdWludDY0CglpbnQgMjQKCTwKCWJ6ICpmb3JfMF9lbmQKCgkvLyAqaWYwX2NvbmRpdGlvbgoJLy8gY29udHJhY3RzL3ZhbGlkYXRvclJlZ2lzdHJ5LmFsZ28udHM6Mjk1CgkvLyBwb29sU2V0W2ldLnBvb2xBcHBJZCA9PT0gMAoJZnJhbWVfZGlnIDEgLy8gcG9vbFNldDogKHVpbnQ2NCx1aW50MTYsdWludDY0KVsyNF0KCWZyYW1lX2RpZyAyIC8vIGk6IHVpbnQ2NAoJaW50IDE4CgkqIC8vIGFjYyAqIHR5cGVMZW5ndGgKCWludCAwCgkrCglpbnQgOAoJZXh0cmFjdDMKCWJ0b2kKCWludCAwCgk9PQoJYnogKmlmMF9lbmQKCgkvLyAqaWYwX2NvbnNlcXVlbnQKCWIgKmZvcl8wX2VuZAoKKmlmMF9lbmQ6CgkvLyBjb250cmFjdHMvdmFsaWRhdG9yUmVnaXN0cnkuYWxnby50czoyOTkKCS8vIHJldERhdGEucHVzaChwb29sU2V0W2ldKQoJZnJhbWVfZGlnIDAgLy8gcmV0RGF0YTogUG9vbEluZm9bXQoJZnJhbWVfZGlnIDEgLy8gcG9vbFNldDogKHVpbnQ2NCx1aW50MTYsdWludDY0KVsyNF0KCWZyYW1lX2RpZyAyIC8vIGk6IHVpbnQ2NAoJaW50IDE4CgkqIC8vIGFjYyAqIHR5cGVMZW5ndGgKCWludCAxOAoJZXh0cmFjdDMKCWNvbmNhdAoJZnJhbWVfYnVyeSAwIC8vIHJldERhdGE6IFBvb2xJbmZvW10KCipmb3JfMF9jb250aW51ZToKCS8vIGNvbnRyYWN0cy92YWxpZGF0b3JSZWdpc3RyeS5hbGdvLnRzOjI5NAoJLy8gaSArPSAxCglmcmFtZV9kaWcgMiAvLyBpOiB1aW50NjQKCWludCAxCgkrCglmcmFtZV9idXJ5IDIgLy8gaTogdWludDY0CgliICpmb3JfMAoKKmZvcl8wX2VuZDoKCS8vIGNvbnRyYWN0cy92YWxpZGF0b3JSZWdpc3RyeS5hbGdvLnRzOjMwMQoJLy8gcmV0dXJuIHJldERhdGE7CglmcmFtZV9kaWcgMCAvLyByZXREYXRhOiBQb29sSW5mb1tdCgoJLy8gc2V0IHRoZSBzdWJyb3V0aW5lIHJldHVybiB2YWx1ZQoJZnJhbWVfYnVyeSAwCgoJLy8gcG9wIGFsbCBsb2NhbCB2YXJpYWJsZXMgZnJvbSB0aGUgc3RhY2sKCXBvcG4gMgoJcmV0c3ViCgovLyBnZXRQb29sQXBwSWQodWludDY0LHVpbnQ2NCl1aW50NjQKKmFiaV9yb3V0ZV9nZXRQb29sQXBwSWQ6CgkvLyBUaGUgQUJJIHJldHVybiBwcmVmaXgKCWJ5dGUgMHgxNTFmN2M3NQoKCS8vIHBvb2xJZDogdWludDY0Cgl0eG5hIEFwcGxpY2F0aW9uQXJncyAyCglidG9pCgoJLy8gdmFsaWRhdG9ySWQ6IHVpbnQ2NAoJdHhuYSBBcHBsaWNhdGlvbkFyZ3MgMQoJYnRvaQoKCS8vIGV4ZWN1dGUgZ2V0UG9vbEFwcElkKHVpbnQ2NCx1aW50NjQpdWludDY0CgljYWxsc3ViIGdldFBvb2xBcHBJZAoJaXRvYgoJY29uY2F0Cglsb2cKCWludCAxCglyZXR1cm4KCi8vIGdldFBvb2xBcHBJZCh2YWxpZGF0b3JJZDogdWludDY0LCBwb29sSWQ6IHVpbnQ2NCk6IHVpbnQ2NApnZXRQb29sQXBwSWQ6Cglwcm90byAyIDEKCgkvLyBjb250cmFjdHMvdmFsaWRhdG9yUmVnaXN0cnkuYWxnby50czozMDkKCS8vIGFzc2VydChwb29sSWQgIT09IDAgJiYgcG9vbElkIDw9IHRoaXMudmFsaWRhdG9yTGlzdCh2YWxpZGF0b3JJZCkudmFsdWUucG9vbHMubGVuZ3RoKQoJZnJhbWVfZGlnIC0yIC8vIHBvb2xJZDogdWludDY0CglpbnQgMAoJIT0KCWR1cAoJYnogKnNraXBfYW5kMAoJZnJhbWVfZGlnIC0yIC8vIHBvb2xJZDogdWludDY0CglpbnQgMjQKCTw9CgkmJgoKKnNraXBfYW5kMDoKCWFzc2VydAoKCS8vIGNvbnRyYWN0cy92YWxpZGF0b3JSZWdpc3RyeS5hbGdvLnRzOjMxMAoJLy8gcmV0dXJuIHRoaXMudmFsaWRhdG9yTGlzdCh2YWxpZGF0b3JJZCkudmFsdWUucG9vbHNbcG9vbElkIC0gMV0ucG9vbEFwcElkOwoJaW50IDIzNCAvLyBoZWFkT2Zmc2V0CglmcmFtZV9kaWcgLTIgLy8gcG9vbElkOiB1aW50NjQKCWludCAxCgktCglpbnQgMTgKCSogLy8gYWNjICogdHlwZUxlbmd0aAoJKwoJaW50IDAKCSsKCWludCA4CglieXRlIDB4NzYgLy8gInYiCglmcmFtZV9kaWcgLTEgLy8gdmFsaWRhdG9ySWQ6IHVpbnQ2NAoJaXRvYgoJY29uY2F0Cgljb3ZlciAyCglib3hfZXh0cmFjdAoJYnRvaQoJcmV0c3ViCgovLyBnZXRQb29sSW5mbygodWludDY0LHVpbnQ2NCx1aW50NjQpKSh1aW50NjQsdWludDE2LHVpbnQ2NCkKKmFiaV9yb3V0ZV9nZXRQb29sSW5mbzoKCS8vIFRoZSBBQkkgcmV0dXJuIHByZWZpeAoJYnl0ZSAweDE1MWY3Yzc1CgoJLy8gcG9vbEtleTogKHVpbnQ2NCx1aW50NjQsdWludDY0KQoJdHhuYSBBcHBsaWNhdGlvbkFyZ3MgMQoJZHVwCglsZW4KCWludCAyNAoJPT0KCWFzc2VydAoKCS8vIGV4ZWN1dGUgZ2V0UG9vbEluZm8oKHVpbnQ2NCx1aW50NjQsdWludDY0KSkodWludDY0LHVpbnQxNix1aW50NjQpCgljYWxsc3ViIGdldFBvb2xJbmZvCgljb25jYXQKCWxvZwoJaW50IDEKCXJldHVybgoKLy8gZ2V0UG9vbEluZm8ocG9vbEtleTogVmFsaWRhdG9yUG9vbEtleSk6IFBvb2xJbmZvCmdldFBvb2xJbmZvOgoJcHJvdG8gMSAxCgoJLy8gY29udHJhY3RzL3ZhbGlkYXRvclJlZ2lzdHJ5LmFsZ28udHM6MzE1CgkvLyByZXR1cm4gdGhpcy52YWxpZGF0b3JMaXN0KHBvb2xLZXkuaWQpLnZhbHVlLnBvb2xzW3Bvb2xLZXkucG9vbElkIC0gMV07CglpbnQgMjM0IC8vIGhlYWRPZmZzZXQKCWZyYW1lX2RpZyAtMSAvLyBwb29sS2V5OiBWYWxpZGF0b3JQb29sS2V5CglleHRyYWN0IDggOAoJYnRvaQoJaW50IDEKCS0KCWludCAxOAoJKiAvLyBhY2MgKiB0eXBlTGVuZ3RoCgkrCglpbnQgMTgKCWJ5dGUgMHg3NiAvLyAidiIKCWZyYW1lX2RpZyAtMSAvLyBwb29sS2V5OiBWYWxpZGF0b3JQb29sS2V5CglleHRyYWN0IDAgOAoJYnRvaQoJaXRvYgoJY29uY2F0Cgljb3ZlciAyCglib3hfZXh0cmFjdAoJcmV0c3ViCgovLyBnZXRDdXJNYXhTdGFrZVBlclBvb2wodWludDY0KXVpbnQ2NAoqYWJpX3JvdXRlX2dldEN1ck1heFN0YWtlUGVyUG9vbDoKCS8vIFRoZSBBQkkgcmV0dXJuIHByZWZpeAoJYnl0ZSAweDE1MWY3Yzc1CgoJLy8gdmFsaWRhdG9ySWQ6IHVpbnQ2NAoJdHhuYSBBcHBsaWNhdGlvbkFyZ3MgMQoJYnRvaQoKCS8vIGV4ZWN1dGUgZ2V0Q3VyTWF4U3Rha2VQZXJQb29sKHVpbnQ2NCl1aW50NjQKCWNhbGxzdWIgZ2V0Q3VyTWF4U3Rha2VQZXJQb29sCglpdG9iCgljb25jYXQKCWxvZwoJaW50IDEKCXJldHVybgoKLy8gZ2V0Q3VyTWF4U3Rha2VQZXJQb29sKHZhbGlkYXRvcklkOiBWYWxpZGF0b3JJZFR5cGUpOiB1aW50NjQKLy8KLy8gQ2FsY3VsYXRlIHRoZSBtYXhpbXVtIHN0YWtlIHBlciBwb29sIGZvciBhIGdpdmVuIHZhbGlkYXRvci4KLy8gTm9ybWFsbHkgdGhpcyB3b3VsZCBiZSBtYXhBbGdvUGVyUG9vbCwgYnV0IGl0IHNob3VsZCBhbHNvIG5ldmVyIGdvIGFib3ZlIE1heEFsbG93ZWRTdGFrZSAvIG51bVBvb2xzIHNvCi8vIGFzIHBvb2xzIGFyZSBhZGRlZCB0aGUgbWF4IGFsbG93ZWQgcGVyIHBvb2wgY2FuIHJlZHVjZS4KLy8KLy8gQHBhcmFtIHtWYWxpZGF0b3JJZFR5cGV9IHZhbGlkYXRvcklkIC0gVGhlIGlkIG9mIHRoZSB2YWxpZGF0b3IuCmdldEN1ck1heFN0YWtlUGVyUG9vbDoKCXByb3RvIDEgMQoKCS8vIFB1c2ggZW1wdHkgYnl0ZXMgYWZ0ZXIgdGhlIGZyYW1lIHBvaW50ZXIgdG8gcmVzZXJ2ZSBzcGFjZSBmb3IgbG9jYWwgdmFyaWFibGVzCglieXRlIDB4CglkdXBuIDIKCgkvLyBjb250cmFjdHMvdmFsaWRhdG9yUmVnaXN0cnkuYWxnby50czozMjYKCS8vIG51bVBvb2xzID0gdGhpcy52YWxpZGF0b3JMaXN0KHZhbGlkYXRvcklkKS52YWx1ZS5zdGF0ZS5udW1Qb29scyBhcyB1aW50NjQKCWludCAyMDgKCWludCAyCglieXRlIDB4NzYgLy8gInYiCglmcmFtZV9kaWcgLTEgLy8gdmFsaWRhdG9ySWQ6IFZhbGlkYXRvcklkVHlwZQoJaXRvYgoJY29uY2F0Cgljb3ZlciAyCglib3hfZXh0cmFjdAoJYnRvaQoJZnJhbWVfYnVyeSAwIC8vIG51bVBvb2xzOiB1aW50NjQKCgkvLyBjb250cmFjdHMvdmFsaWRhdG9yUmVnaXN0cnkuYWxnby50czozMjcKCS8vIGhhcmRNYXhEaXZpZGVkQmV0d2VlblBvb2xzID0gdGhpcy5tYXhBbGxvd2VkU3Rha2UoKSAvIG51bVBvb2xzCgljYWxsc3ViIG1heEFsbG93ZWRTdGFrZQoJZnJhbWVfZGlnIDAgLy8gbnVtUG9vbHM6IHVpbnQ2NAoJLwoJZnJhbWVfYnVyeSAxIC8vIGhhcmRNYXhEaXZpZGVkQmV0d2VlblBvb2xzOiB1aW50NjQKCgkvLyBjb250cmFjdHMvdmFsaWRhdG9yUmVnaXN0cnkuYWxnby50czozMjgKCS8vIG1heFBlclBvb2w6IHVpbnQ2NCA9IHRoaXMudmFsaWRhdG9yTGlzdCh2YWxpZGF0b3JJZCkudmFsdWUuY29uZmlnLm1heEFsZ29QZXJQb29sCglpbnQgMTgzCglpbnQgOAoJYnl0ZSAweDc2IC8vICJ2IgoJZnJhbWVfZGlnIC0xIC8vIHZhbGlkYXRvcklkOiBWYWxpZGF0b3JJZFR5cGUKCWl0b2IKCWNvbmNhdAoJY292ZXIgMgoJYm94X2V4dHJhY3QKCWJ0b2kKCWZyYW1lX2J1cnkgMiAvLyBtYXhQZXJQb29sOiB1aW50NjQKCgkvLyAqaWYxX2NvbmRpdGlvbgoJLy8gY29udHJhY3RzL3ZhbGlkYXRvclJlZ2lzdHJ5LmFsZ28udHM6MzI5CgkvLyBtYXhQZXJQb29sID09PSAwCglmcmFtZV9kaWcgMiAvLyBtYXhQZXJQb29sOiB1aW50NjQKCWludCAwCgk9PQoJYnogKmlmMV9lbmQKCgkvLyAqaWYxX2NvbnNlcXVlbnQKCS8vIGNvbnRyYWN0cy92YWxpZGF0b3JSZWdpc3RyeS5hbGdvLnRzOjMzMAoJLy8gbWF4UGVyUG9vbCA9IHRoaXMubWF4QWxnb0FsbG93ZWRQZXJQb29sKCkKCWNhbGxzdWIgbWF4QWxnb0FsbG93ZWRQZXJQb29sCglmcmFtZV9idXJ5IDIgLy8gbWF4UGVyUG9vbDogdWludDY0CgoqaWYxX2VuZDoKCS8vICppZjJfY29uZGl0aW9uCgkvLyBjb250cmFjdHMvdmFsaWRhdG9yUmVnaXN0cnkuYWxnby50czozMzIKCS8vIGhhcmRNYXhEaXZpZGVkQmV0d2VlblBvb2xzIDwgbWF4UGVyUG9vbAoJZnJhbWVfZGlnIDEgLy8gaGFyZE1heERpdmlkZWRCZXR3ZWVuUG9vbHM6IHVpbnQ2NAoJZnJhbWVfZGlnIDIgLy8gbWF4UGVyUG9vbDogdWludDY0Cgk8CglieiAqaWYyX2VuZAoKCS8vICppZjJfY29uc2VxdWVudAoJLy8gY29udHJhY3RzL3ZhbGlkYXRvclJlZ2lzdHJ5LmFsZ28udHM6MzMzCgkvLyBtYXhQZXJQb29sID0gaGFyZE1heERpdmlkZWRCZXR3ZWVuUG9vbHMKCWZyYW1lX2RpZyAxIC8vIGhhcmRNYXhEaXZpZGVkQmV0d2VlblBvb2xzOiB1aW50NjQKCWZyYW1lX2J1cnkgMiAvLyBtYXhQZXJQb29sOiB1aW50NjQKCippZjJfZW5kOgoJLy8gY29udHJhY3RzL3ZhbGlkYXRvclJlZ2lzdHJ5LmFsZ28udHM6MzM1CgkvLyByZXR1cm4gbWF4UGVyUG9vbDsKCWZyYW1lX2RpZyAyIC8vIG1heFBlclBvb2w6IHVpbnQ2NAoKCS8vIHNldCB0aGUgc3Vicm91dGluZSByZXR1cm4gdmFsdWUKCWZyYW1lX2J1cnkgMAoKCS8vIHBvcCBhbGwgbG9jYWwgdmFyaWFibGVzIGZyb20gdGhlIHN0YWNrCglwb3BuIDIKCXJldHN1YgoKLy8gZG9lc1N0YWtlck5lZWRUb1BheU1CUihhZGRyZXNzKWJvb2wKKmFiaV9yb3V0ZV9kb2VzU3Rha2VyTmVlZFRvUGF5TUJSOgoJLy8gVGhlIEFCSSByZXR1cm4gcHJlZml4CglieXRlIDB4MTUxZjdjNzUKCgkvLyBzdGFrZXI6IGFkZHJlc3MKCXR4bmEgQXBwbGljYXRpb25BcmdzIDEKCWR1cAoJbGVuCglpbnQgMzIKCT09Cglhc3NlcnQKCgkvLyBleGVjdXRlIGRvZXNTdGFrZXJOZWVkVG9QYXlNQlIoYWRkcmVzcylib29sCgljYWxsc3ViIGRvZXNTdGFrZXJOZWVkVG9QYXlNQlIKCWJ5dGUgMHgwMAoJaW50IDAKCXVuY292ZXIgMgoJc2V0Yml0Cgljb25jYXQKCWxvZwoJaW50IDEKCXJldHVybgoKLy8gZG9lc1N0YWtlck5lZWRUb1BheU1CUihzdGFrZXI6IEFkZHJlc3MpOiBib29sZWFuCi8vCi8vIEhlbHBlciBjYWxsZXJzIGNhbiBjYWxsIHcvIHNpbXVsYXRlIHRvIGRldGVybWluZSBpZiAnQWRkU3Rha2VyJyBNQlIgc2hvdWxkIGJlIGluY2x1ZGVkIHcvIHN0YWtpbmcgYW1vdW50Ci8vIEBwYXJhbSBzdGFrZXIKZG9lc1N0YWtlck5lZWRUb1BheU1CUjoKCXByb3RvIDEgMQoKCS8vIGNvbnRyYWN0cy92YWxpZGF0b3JSZWdpc3RyeS5hbGdvLnRzOjM0NAoJLy8gcmV0dXJuICF0aGlzLnN0YWtlclBvb2xTZXQoc3Rha2VyKS5leGlzdHM7CglieXRlIDB4NzM3MDczIC8vICJzcHMiCglmcmFtZV9kaWcgLTEgLy8gc3Rha2VyOiBBZGRyZXNzCgljb25jYXQKCWJveF9sZW4KCXN3YXAKCXBvcAoJIQoJcmV0c3ViCgovLyBnZXRTdGFrZWRQb29sc0ZvckFjY291bnQoYWRkcmVzcykodWludDY0LHVpbnQ2NCx1aW50NjQpW10KKmFiaV9yb3V0ZV9nZXRTdGFrZWRQb29sc0ZvckFjY291bnQ6CgkvLyBUaGUgQUJJIHJldHVybiBwcmVmaXgKCWJ5dGUgMHgxNTFmN2M3NQoKCS8vIHN0YWtlcjogYWRkcmVzcwoJdHhuYSBBcHBsaWNhdGlvbkFyZ3MgMQoJZHVwCglsZW4KCWludCAzMgoJPT0KCWFzc2VydAoKCS8vIGV4ZWN1dGUgZ2V0U3Rha2VkUG9vbHNGb3JBY2NvdW50KGFkZHJlc3MpKHVpbnQ2NCx1aW50NjQsdWludDY0KVtdCgljYWxsc3ViIGdldFN0YWtlZFBvb2xzRm9yQWNjb3VudAoJZHVwCglsZW4KCWludCAyNAoJLwoJaXRvYgoJZXh0cmFjdCA2IDIKCXN3YXAKCWNvbmNhdAoJY29uY2F0Cglsb2cKCWludCAxCglyZXR1cm4KCi8vIGdldFN0YWtlZFBvb2xzRm9yQWNjb3VudChzdGFrZXI6IEFkZHJlc3MpOiBWYWxpZGF0b3JQb29sS2V5W10KLy8KLy8gUmV0cmlldmVzIHRoZSBzdGFrZWQgcG9vbHMgZm9yIGFuIGFjY291bnQuCi8vCi8vIEBwYXJhbSB7QWRkcmVzc30gc3Rha2VyIC0gVGhlIGFjY291bnQgdG8gcmV0cmlldmUgc3Rha2VkIHBvb2xzIGZvci4KLy8gQHJldHVybiB7VmFsaWRhdG9yUG9vbEtleVtdfSAtIFRoZSBhcnJheSBvZiBzdGFrZWQgcG9vbHMgZm9yIHRoZSBhY2NvdW50LgpnZXRTdGFrZWRQb29sc0ZvckFjY291bnQ6Cglwcm90byAxIDEKCgkvLyBQdXNoIGVtcHR5IGJ5dGVzIGFmdGVyIHRoZSBmcmFtZSBwb2ludGVyIHRvIHJlc2VydmUgc3BhY2UgZm9yIGxvY2FsIHZhcmlhYmxlcwoJYnl0ZSAweAoJZHVwbiAyCgoJLy8gKmlmM19jb25kaXRpb24KCS8vIGNvbnRyYWN0cy92YWxpZGF0b3JSZWdpc3RyeS5hbGdvLnRzOjM1NAoJLy8gIXRoaXMuc3Rha2VyUG9vbFNldChzdGFrZXIpLmV4aXN0cwoJYnl0ZSAweDczNzA3MyAvLyAic3BzIgoJZnJhbWVfZGlnIC0xIC8vIHN0YWtlcjogQWRkcmVzcwoJY29uY2F0Cglib3hfbGVuCglzd2FwCglwb3AKCSEKCWJ6ICppZjNfZW5kCgoJLy8gKmlmM19jb25zZXF1ZW50CgkvLyBjb250cmFjdHMvdmFsaWRhdG9yUmVnaXN0cnkuYWxnby50czozNTUKCS8vIHJldHVybiBbXTsKCWJ5dGUgMHgKCXJldHN1YgoKKmlmM19lbmQ6CgkvLyBjb250cmFjdHMvdmFsaWRhdG9yUmVnaXN0cnkuYWxnby50czozNTcKCS8vIHJldERhdGE6IFZhbGlkYXRvclBvb2xLZXlbXSA9IFtdCglieXRlIDB4CglmcmFtZV9idXJ5IDAgLy8gcmV0RGF0YTogVmFsaWRhdG9yUG9vbEtleVtdCgoJLy8gY29udHJhY3RzL3ZhbGlkYXRvclJlZ2lzdHJ5LmFsZ28udHM6MzU4CgkvLyBwb29sU2V0ID0gY2xvbmUodGhpcy5zdGFrZXJQb29sU2V0KHN0YWtlcikudmFsdWUpCglieXRlIDB4NzM3MDczIC8vICJzcHMiCglmcmFtZV9kaWcgLTEgLy8gc3Rha2VyOiBBZGRyZXNzCgljb25jYXQKCWJveF9nZXQKCWFzc2VydAoJZnJhbWVfYnVyeSAxIC8vIHBvb2xTZXQ6ICh1aW50NjQsdWludDY0LHVpbnQ2NClbNl0KCgkvLyBjb250cmFjdHMvdmFsaWRhdG9yUmVnaXN0cnkuYWxnby50czozNTkKCS8vIGZvciAobGV0IGkgPSAwOyBpIDwgcG9vbFNldC5sZW5ndGg7IGkgKz0gMSkKCWludCAwCglmcmFtZV9idXJ5IDIgLy8gaTogdWludDY0CgoqZm9yXzE6CgkvLyBjb250cmFjdHMvdmFsaWRhdG9yUmVnaXN0cnkuYWxnby50czozNTkKCS8vIGkgPCBwb29sU2V0Lmxlbmd0aAoJZnJhbWVfZGlnIDIgLy8gaTogdWludDY0CglpbnQgNgoJPAoJYnogKmZvcl8xX2VuZAoKCS8vICppZjRfY29uZGl0aW9uCgkvLyBjb250cmFjdHMvdmFsaWRhdG9yUmVnaXN0cnkuYWxnby50czozNjAKCS8vIHBvb2xTZXRbaV0uaWQgIT09IDAKCWZyYW1lX2RpZyAxIC8vIHBvb2xTZXQ6ICh1aW50NjQsdWludDY0LHVpbnQ2NClbNl0KCWZyYW1lX2RpZyAyIC8vIGk6IHVpbnQ2NAoJaW50IDI0CgkqIC8vIGFjYyAqIHR5cGVMZW5ndGgKCWludCAwCgkrCglpbnQgOAoJZXh0cmFjdDMKCWJ0b2kKCWludCAwCgkhPQoJYnogKmlmNF9lbmQKCgkvLyAqaWY0X2NvbnNlcXVlbnQKCS8vIGNvbnRyYWN0cy92YWxpZGF0b3JSZWdpc3RyeS5hbGdvLnRzOjM2MQoJLy8gcmV0RGF0YS5wdXNoKHBvb2xTZXRbaV0pCglmcmFtZV9kaWcgMCAvLyByZXREYXRhOiBWYWxpZGF0b3JQb29sS2V5W10KCWZyYW1lX2RpZyAxIC8vIHBvb2xTZXQ6ICh1aW50NjQsdWludDY0LHVpbnQ2NClbNl0KCWZyYW1lX2RpZyAyIC8vIGk6IHVpbnQ2NAoJaW50IDI0CgkqIC8vIGFjYyAqIHR5cGVMZW5ndGgKCWludCAyNAoJZXh0cmFjdDMKCWNvbmNhdAoJZnJhbWVfYnVyeSAwIC8vIHJldERhdGE6IFZhbGlkYXRvclBvb2xLZXlbXQoKKmlmNF9lbmQ6CgoqZm9yXzFfY29udGludWU6CgkvLyBjb250cmFjdHMvdmFsaWRhdG9yUmVnaXN0cnkuYWxnby50czozNTkKCS8vIGkgKz0gMQoJZnJhbWVfZGlnIDIgLy8gaTogdWludDY0CglpbnQgMQoJKwoJZnJhbWVfYnVyeSAyIC8vIGk6IHVpbnQ2NAoJYiAqZm9yXzEKCipmb3JfMV9lbmQ6CgkvLyBjb250cmFjdHMvdmFsaWRhdG9yUmVnaXN0cnkuYWxnby50czozNjQKCS8vIHJldHVybiByZXREYXRhOwoJZnJhbWVfZGlnIDAgLy8gcmV0RGF0YTogVmFsaWRhdG9yUG9vbEtleVtdCgoJLy8gc2V0IHRoZSBzdWJyb3V0aW5lIHJldHVybiB2YWx1ZQoJZnJhbWVfYnVyeSAwCgoJLy8gcG9wIGFsbCBsb2NhbCB2YXJpYWJsZXMgZnJvbSB0aGUgc3RhY2sKCXBvcG4gMgoJcmV0c3ViCgovLyBnZXRUb2tlblBheW91dFJhdGlvKHVpbnQ2NCkodWludDY0WzI0XSx1aW50NjQpCiphYmlfcm91dGVfZ2V0VG9rZW5QYXlvdXRSYXRpbzoKCS8vIFRoZSBBQkkgcmV0dXJuIHByZWZpeAoJYnl0ZSAweDE1MWY3Yzc1CgoJLy8gdmFsaWRhdG9ySWQ6IHVpbnQ2NAoJdHhuYSBBcHBsaWNhdGlvbkFyZ3MgMQoJYnRvaQoKCS8vIGV4ZWN1dGUgZ2V0VG9rZW5QYXlvdXRSYXRpbyh1aW50NjQpKHVpbnQ2NFsyNF0sdWludDY0KQoJY2FsbHN1YiBnZXRUb2tlblBheW91dFJhdGlvCgljb25jYXQKCWxvZwoJaW50IDEKCXJldHVybgoKLy8gZ2V0VG9rZW5QYXlvdXRSYXRpbyh2YWxpZGF0b3JJZDogVmFsaWRhdG9ySWRUeXBlKTogUG9vbFRva2VuUGF5b3V0UmF0aW8KLy8KLy8gUmV0cmlldmVzIHRoZSB0b2tlbiBwYXlvdXQgcmF0aW8gZm9yIGEgZ2l2ZW4gdmFsaWRhdG9yIC0gcmV0dXJuaW5nIHRoZSBwb29sIHJhdGlvcyBvZiB3aG9sZSBzbyB0aGF0IHRva2VuCi8vIHBheW91dHMgYWNyb3NzIHBvb2xzIGNhbiBiZSBiYXNlZCBvbiBhIHN0YWJsZSBzbmFwaG9zdCBvZiBzdGFrZS4KLy8KLy8gQHBhcmFtIHtWYWxpZGF0b3JJZFR5cGV9IHZhbGlkYXRvcklkIC0gVGhlIGlkIG9mIHRoZSB2YWxpZGF0b3IuCi8vIEByZXR1cm4ge1Bvb2xUb2tlblBheW91dFJhdGlvfSAtIFRoZSB0b2tlbiBwYXlvdXQgcmF0aW8gZm9yIHRoZSB2YWxpZGF0b3IuCmdldFRva2VuUGF5b3V0UmF0aW86Cglwcm90byAxIDEKCgkvLyBjb250cmFjdHMvdmFsaWRhdG9yUmVnaXN0cnkuYWxnby50czozNzYKCS8vIHJldHVybiB0aGlzLnZhbGlkYXRvckxpc3QodmFsaWRhdG9ySWQpLnZhbHVlLnRva2VuUGF5b3V0UmF0aW87CglpbnQgNjY2IC8vIGhlYWRPZmZzZXQKCWludCAyMDAKCWJ5dGUgMHg3NiAvLyAidiIKCWZyYW1lX2RpZyAtMSAvLyB2YWxpZGF0b3JJZDogVmFsaWRhdG9ySWRUeXBlCglpdG9iCgljb25jYXQKCWNvdmVyIDIKCWJveF9leHRyYWN0CglyZXRzdWIKCi8vIGdldE5vZGVQb29sQXNzaWdubWVudHModWludDY0KSgodWludDY0WzNdKVs4XSkKKmFiaV9yb3V0ZV9nZXROb2RlUG9vbEFzc2lnbm1lbnRzOgoJLy8gVGhlIEFCSSByZXR1cm4gcHJlZml4CglieXRlIDB4MTUxZjdjNzUKCgkvLyB2YWxpZGF0b3JJZDogdWludDY0Cgl0eG5hIEFwcGxpY2F0aW9uQXJncyAxCglidG9pCgoJLy8gZXhlY3V0ZSBnZXROb2RlUG9vbEFzc2lnbm1lbnRzKHVpbnQ2NCkoKHVpbnQ2NFszXSlbOF0pCgljYWxsc3ViIGdldE5vZGVQb29sQXNzaWdubWVudHMKCWNvbmNhdAoJbG9nCglpbnQgMQoJcmV0dXJuCgovLyBnZXROb2RlUG9vbEFzc2lnbm1lbnRzKHZhbGlkYXRvcklkOiB1aW50NjQpOiBOb2RlUG9vbEFzc2lnbm1lbnRDb25maWcKZ2V0Tm9kZVBvb2xBc3NpZ25tZW50czoKCXByb3RvIDEgMQoKCS8vIGNvbnRyYWN0cy92YWxpZGF0b3JSZWdpc3RyeS5hbGdvLnRzOjM4MQoJLy8gYXNzZXJ0KHRoaXMudmFsaWRhdG9yTGlzdCh2YWxpZGF0b3JJZCkuZXhpc3RzKQoJYnl0ZSAweDc2IC8vICJ2IgoJZnJhbWVfZGlnIC0xIC8vIHZhbGlkYXRvcklkOiB1aW50NjQKCWl0b2IKCWNvbmNhdAoJYm94X2xlbgoJc3dhcAoJcG9wCglhc3NlcnQKCgkvLyBjb250cmFjdHMvdmFsaWRhdG9yUmVnaXN0cnkuYWxnby50czozODMKCS8vIHJldHVybiB0aGlzLnZhbGlkYXRvckxpc3QodmFsaWRhdG9ySWQpLnZhbHVlLm5vZGVQb29sQXNzaWdubWVudHM7CglpbnQgODY2IC8vIGhlYWRPZmZzZXQKCWludCAxOTIKCWJ5dGUgMHg3NiAvLyAidiIKCWZyYW1lX2RpZyAtMSAvLyB2YWxpZGF0b3JJZDogdWludDY0CglpdG9iCgljb25jYXQKCWNvdmVyIDIKCWJveF9leHRyYWN0CglyZXRzdWIKCi8vIGdldE5GRFJlZ2lzdHJ5SUQoKXVpbnQ2NAoqYWJpX3JvdXRlX2dldE5GRFJlZ2lzdHJ5SUQ6CgkvLyBUaGUgQUJJIHJldHVybiBwcmVmaXgKCWJ5dGUgMHgxNTFmN2M3NQoKCS8vIGV4ZWN1dGUgZ2V0TkZEUmVnaXN0cnlJRCgpdWludDY0CgljYWxsc3ViIGdldE5GRFJlZ2lzdHJ5SUQKCWl0b2IKCWNvbmNhdAoJbG9nCglpbnQgMQoJcmV0dXJuCgovLyBnZXRORkRSZWdpc3RyeUlEKCk6IHVpbnQ2NApnZXRORkRSZWdpc3RyeUlEOgoJcHJvdG8gMCAxCgoJLy8gY29udHJhY3RzL3ZhbGlkYXRvclJlZ2lzdHJ5LmFsZ28udHM6Mzg3CgkvLyByZXR1cm4gdGhpcy5uZmRSZWdpc3RyeUFwcElkOwoJcHVzaGludCBUTVBMX25mZFJlZ2lzdHJ5QXBwSWQKCXJldHN1YgoKLy8gYWRkVmFsaWRhdG9yKHBheSxzdHJpbmcsKHVpbnQ2NCxhZGRyZXNzLGFkZHJlc3MsdWludDY0LHVpbnQ4LGJ5dGVbMzJdLHVpbnQ2NCx1aW50NjQsdWludDY0LHVpbnQxNix1aW50MzIsYWRkcmVzcyx1aW50NjQsdWludDY0LHVpbnQ4LHVpbnQ2NCx1aW50NjQpKXVpbnQ2NAoqYWJpX3JvdXRlX2FkZFZhbGlkYXRvcjoKCS8vIFRoZSBBQkkgcmV0dXJuIHByZWZpeAoJYnl0ZSAweDE1MWY3Yzc1CgoJLy8gY29uZmlnOiAodWludDY0LGFkZHJlc3MsYWRkcmVzcyx1aW50NjQsdWludDgsYnl0ZVszMl0sdWludDY0LHVpbnQ2NCx1aW50NjQsdWludDE2LHVpbnQzMixhZGRyZXNzLHVpbnQ2NCx1aW50NjQsdWludDgsdWludDY0LHVpbnQ2NCkKCXR4bmEgQXBwbGljYXRpb25BcmdzIDIKCWR1cAoJbGVuCglpbnQgMjA4Cgk9PQoJYXNzZXJ0CgoJLy8gbmZkTmFtZTogc3RyaW5nCgl0eG5hIEFwcGxpY2F0aW9uQXJncyAxCglleHRyYWN0IDIgMAoKCS8vIG1iclBheW1lbnQ6IHBheQoJdHhuIEdyb3VwSW5kZXgKCWludCAxCgktCglkdXAKCWd0eG5zIFR5cGVFbnVtCglpbnQgcGF5Cgk9PQoJYXNzZXJ0CgoJLy8gZXhlY3V0ZSBhZGRWYWxpZGF0b3IocGF5LHN0cmluZywodWludDY0LGFkZHJlc3MsYWRkcmVzcyx1aW50NjQsdWludDgsYnl0ZVszMl0sdWludDY0LHVpbnQ2NCx1aW50NjQsdWludDE2LHVpbnQzMixhZGRyZXNzLHVpbnQ2NCx1aW50NjQsdWludDgsdWludDY0LHVpbnQ2NCkpdWludDY0CgljYWxsc3ViIGFkZFZhbGlkYXRvcgoJaXRvYgoJY29uY2F0Cglsb2cKCWludCAxCglyZXR1cm4KCi8vIGFkZFZhbGlkYXRvcihtYnJQYXltZW50OiBQYXlUeG4sIG5mZE5hbWU6IHN0cmluZywgY29uZmlnOiBWYWxpZGF0b3JDb25maWcpOiB1aW50NjQKLy8KLy8gQWRkcyBhIG5ldyB2YWxpZGF0b3IKLy8gQHBhcmFtIG1iclBheW1lbnQgcGF5bWVudCBmcm9tIGNhbGxlciB3aGljaCBjb3ZlcnMgbWJyIGluY3JlYXNlIG9mIG5ldyB2YWxpZGF0b3Igc3RvcmFnZQovLyBAcGFyYW0gbmZkTmFtZSAoT3B0aW9uYWwpIE5hbWUgb2YgbmZkICh1c2VkIGFzIGRvdWJsZS1jaGVjayBhZ2FpbnN0IGlkIHNwZWNpZmllZCBpbiBjb25maWcpCi8vIEBwYXJhbSBjb25maWcgVmFsaWRhdG9yQ29uZmlnIHN0cnVjdAovLyBAcmV0dXJucyB2YWxpZGF0b3IgaWQKYWRkVmFsaWRhdG9yOgoJcHJvdG8gMyAxCgoJLy8gUHVzaCBlbXB0eSBieXRlcyBhZnRlciB0aGUgZnJhbWUgcG9pbnRlciB0byByZXNlcnZlIHNwYWNlIGZvciBsb2NhbCB2YXJpYWJsZXMKCWJ5dGUgMHgKCWR1cAoKCS8vIGNvbnRyYWN0cy92YWxpZGF0b3JSZWdpc3RyeS5hbGdvLnRzOjM5NwoJLy8gdGhpcy52YWxpZGF0ZUNvbmZpZyhjb25maWcpCglmcmFtZV9kaWcgLTMgLy8gY29uZmlnOiBWYWxpZGF0b3JDb25maWcKCWNhbGxzdWIgdmFsaWRhdGVDb25maWcKCgkvLyBjb250cmFjdHMvdmFsaWRhdG9yUmVnaXN0cnkuYWxnby50czozOTgKCS8vIGFzc2VydChjb25maWcub3duZXIgIT09IEFkZHJlc3MuemVyb0FkZHJlc3MpCglmcmFtZV9kaWcgLTMgLy8gY29uZmlnOiBWYWxpZGF0b3JDb25maWcKCWV4dHJhY3QgOCAzMgoJZ2xvYmFsIFplcm9BZGRyZXNzCgkhPQoJYXNzZXJ0CgoJLy8gY29udHJhY3RzL3ZhbGlkYXRvclJlZ2lzdHJ5LmFsZ28udHM6Mzk5CgkvLyBhc3NlcnQoY29uZmlnLm1hbmFnZXIgIT09IEFkZHJlc3MuemVyb0FkZHJlc3MpCglmcmFtZV9kaWcgLTMgLy8gY29uZmlnOiBWYWxpZGF0b3JDb25maWcKCWV4dHJhY3QgNDAgMzIKCWdsb2JhbCBaZXJvQWRkcmVzcwoJIT0KCWFzc2VydAoKCS8vIGNvbnRyYWN0cy92YWxpZGF0b3JSZWdpc3RyeS5hbGdvLnRzOjQwMAoJLy8gYXNzZXJ0KHRoaXMudHhuLnNlbmRlciA9PT0gY29uZmlnLm93bmVyLCAnc2VuZGVyIG11c3QgYmUgb3duZXIgdG8gYWRkIG5ldyB2YWxpZGF0b3InKQoJdHhuIFNlbmRlcgoJZnJhbWVfZGlnIC0zIC8vIGNvbmZpZzogVmFsaWRhdG9yQ29uZmlnCglleHRyYWN0IDggMzIKCT09CgoJLy8gc2VuZGVyIG11c3QgYmUgb3duZXIgdG8gYWRkIG5ldyB2YWxpZGF0b3IKCWFzc2VydAoKCS8vIGNvbnRyYWN0cy92YWxpZGF0b3JSZWdpc3RyeS5hbGdvLnRzOjQwMgoJLy8gdmVyaWZ5UGF5VHhuKG1iclBheW1lbnQsIHsgYW1vdW50OiB0aGlzLmdldE1ickFtb3VudHMoKS5hZGRWYWxpZGF0b3JNYnIgfSkKCS8vIHZlcmlmeSBhbW91bnQKCWZyYW1lX2RpZyAtMSAvLyBtYnJQYXltZW50OiBQYXlUeG4KCWd0eG5zIEFtb3VudAoJY2FsbHN1YiBnZXRNYnJBbW91bnRzCglleHRyYWN0IDAgOAoJYnRvaQoJPT0KCWFzc2VydAoKCS8vIGNvbnRyYWN0cy92YWxpZGF0b3JSZWdpc3RyeS5hbGdvLnRzOjQwNQoJLy8gdmFsaWRhdG9ySWQgPSB0aGlzLm51bVZhbGlkYXRvcnMudmFsdWUgKyAxCglieXRlIDB4NmU3NTZkNTYgLy8gIm51bVYiCglhcHBfZ2xvYmFsX2dldAoJaW50IDEKCSsKCWZyYW1lX2J1cnkgMCAvLyB2YWxpZGF0b3JJZDogdWludDY0CgoJLy8gY29udHJhY3RzL3ZhbGlkYXRvclJlZ2lzdHJ5LmFsZ28udHM6NDA2CgkvLyB0aGlzLm51bVZhbGlkYXRvcnMudmFsdWUgPSB2YWxpZGF0b3JJZAoJYnl0ZSAweDZlNzU2ZDU2IC8vICJudW1WIgoJZnJhbWVfZGlnIDAgLy8gdmFsaWRhdG9ySWQ6IHVpbnQ2NAoJYXBwX2dsb2JhbF9wdXQKCgkvLyBjb250cmFjdHMvdmFsaWRhdG9yUmVnaXN0cnkuYWxnby50czo0MDgKCS8vIHRoaXMudmFsaWRhdG9yTGlzdCh2YWxpZGF0b3JJZCkuY3JlYXRlKCkKCWJ5dGUgMHg3NiAvLyAidiIKCWZyYW1lX2RpZyAwIC8vIHZhbGlkYXRvcklkOiB1aW50NjQKCWl0b2IKCWNvbmNhdAoJaW50IDEwNTgKCWJveF9jcmVhdGUKCXBvcAoKCS8vIGNvbnRyYWN0cy92YWxpZGF0b3JSZWdpc3RyeS5hbGdvLnRzOjQwOQoJLy8gdGhpcy52YWxpZGF0b3JMaXN0KHZhbGlkYXRvcklkKS52YWx1ZS5jb25maWcgPSBjb25maWcKCWludCAwCglmcmFtZV9kaWcgLTMgLy8gY29uZmlnOiBWYWxpZGF0b3JDb25maWcKCWJ5dGUgMHg3NiAvLyAidiIKCWZyYW1lX2RpZyAwIC8vIHZhbGlkYXRvcklkOiB1aW50NjQKCWl0b2IKCWNvbmNhdAoJY292ZXIgMgoJYm94X3JlcGxhY2UKCgkvLyBjb250cmFjdHMvdmFsaWRhdG9yUmVnaXN0cnkuYWxnby50czo0MTAKCS8vIHRoaXMudmFsaWRhdG9yTGlzdCh2YWxpZGF0b3JJZCkudmFsdWUuY29uZmlnLmlkID0gdmFsaWRhdG9ySWQKCWludCAwCglmcmFtZV9kaWcgMCAvLyB2YWxpZGF0b3JJZDogdWludDY0CglpdG9iCglieXRlIDB4NzYgLy8gInYiCglmcmFtZV9kaWcgMCAvLyB2YWxpZGF0b3JJZDogdWludDY0CglpdG9iCgljb25jYXQKCWNvdmVyIDIKCWJveF9yZXBsYWNlCgoJLy8gKmlmNV9jb25kaXRpb24KCS8vIGNvbnRyYWN0cy92YWxpZGF0b3JSZWdpc3RyeS5hbGdvLnRzOjQxMwoJLy8gY29uZmlnLm5mZEZvckluZm8gIT09IDAKCWZyYW1lX2RpZyAtMyAvLyBjb25maWc6IFZhbGlkYXRvckNvbmZpZwoJZXh0cmFjdCA3MiA4CglidG9pCglpbnQgMAoJIT0KCWJ6ICppZjVfZW5kCgoJLy8gKmlmNV9jb25zZXF1ZW50CgkvLyBjb250cmFjdHMvdmFsaWRhdG9yUmVnaXN0cnkuYWxnby50czo0MTUKCS8vIHNlbmRBcHBDYWxsKHsKCS8vICAgICAgICAgICAgICAgICBhcHBsaWNhdGlvbklEOiBBcHBJRC5mcm9tVWludDY0KHRoaXMubmZkUmVnaXN0cnlBcHBJZCksCgkvLyAgICAgICAgICAgICAgICAgYXBwbGljYXRpb25BcmdzOiBbJ2lzX3ZhbGlkX25mZF9hcHBpZCcsIG5mZE5hbWUsIGl0b2IoY29uZmlnLm5mZEZvckluZm8pXSwKCS8vICAgICAgICAgICAgICAgICBhcHBsaWNhdGlvbnM6IFtBcHBJRC5mcm9tVWludDY0KGNvbmZpZy5uZmRGb3JJbmZvKV0sCgkvLyAgICAgICAgICAgICB9KQoJaXR4bl9iZWdpbgoJaW50IGFwcGwKCWl0eG5fZmllbGQgVHlwZUVudW0KCgkvLyBjb250cmFjdHMvdmFsaWRhdG9yUmVnaXN0cnkuYWxnby50czo0MTYKCS8vIGFwcGxpY2F0aW9uSUQ6IEFwcElELmZyb21VaW50NjQodGhpcy5uZmRSZWdpc3RyeUFwcElkKQoJcHVzaGludCBUTVBMX25mZFJlZ2lzdHJ5QXBwSWQKCWl0eG5fZmllbGQgQXBwbGljYXRpb25JRAoKCS8vIGNvbnRyYWN0cy92YWxpZGF0b3JSZWdpc3RyeS5hbGdvLnRzOjQxNwoJLy8gYXBwbGljYXRpb25BcmdzOiBbJ2lzX3ZhbGlkX25mZF9hcHBpZCcsIG5mZE5hbWUsIGl0b2IoY29uZmlnLm5mZEZvckluZm8pXQoJYnl0ZSAweDY5NzM1Zjc2NjE2YzY5NjQ1ZjZlNjY2NDVmNjE3MDcwNjk2NCAvLyAiaXNfdmFsaWRfbmZkX2FwcGlkIgoJaXR4bl9maWVsZCBBcHBsaWNhdGlvbkFyZ3MKCWZyYW1lX2RpZyAtMiAvLyBuZmROYW1lOiBzdHJpbmcKCWl0eG5fZmllbGQgQXBwbGljYXRpb25BcmdzCglmcmFtZV9kaWcgLTMgLy8gY29uZmlnOiBWYWxpZGF0b3JDb25maWcKCWV4dHJhY3QgNzIgOAoJYnRvaQoJaXRvYgoJaXR4bl9maWVsZCBBcHBsaWNhdGlvbkFyZ3MKCgkvLyBjb250cmFjdHMvdmFsaWRhdG9yUmVnaXN0cnkuYWxnby50czo0MTgKCS8vIGFwcGxpY2F0aW9uczogW0FwcElELmZyb21VaW50NjQoY29uZmlnLm5mZEZvckluZm8pXQoJZnJhbWVfZGlnIC0zIC8vIGNvbmZpZzogVmFsaWRhdG9yQ29uZmlnCglleHRyYWN0IDcyIDgKCWJ0b2kKCWl0eG5fZmllbGQgQXBwbGljYXRpb25zCgoJLy8gRmVlIGZpZWxkIG5vdCBzZXQsIGRlZmF1bHRpbmcgdG8gMAoJaW50IDAKCWl0eG5fZmllbGQgRmVlCgoJLy8gU3VibWl0IGlubmVyIHRyYW5zYWN0aW9uCglpdHhuX3N1Ym1pdAoKCS8vIGNvbnRyYWN0cy92YWxpZGF0b3JSZWdpc3RyeS5hbGdvLnRzOjQyMAoJLy8gYXNzZXJ0KGJ0b2kodGhpcy5pdHhuLmxhc3RMb2cpID09PSAxLCAicHJvdmlkZWQgTkZEIGlzbid0IHZhbGlkIikKCWl0eG4gTGFzdExvZwoJYnRvaQoJaW50IDEKCT09CgoJLy8gcHJvdmlkZWQgTkZEIGlzbid0IHZhbGlkCglhc3NlcnQKCgkvLyBjb250cmFjdHMvdmFsaWRhdG9yUmVnaXN0cnkuYWxnby50czo0MjIKCS8vIGFzc2VydCgKCS8vICAgICAgICAgICAgICAgICB0aGlzLnR4bi5zZW5kZXIgPT09IChBcHBJRC5mcm9tVWludDY0KGNvbmZpZy5uZmRGb3JJbmZvKS5nbG9iYWxTdGF0ZSgnaS5vd25lci5hJykgYXMgQWRkcmVzcyksCgkvLyAgICAgICAgICAgICAgICAgJ0lmIHNwZWNpZnlpbmcgTkZELCBhY2NvdW50IGFkZGluZyB2YWxpZGF0b3IgbXVzdCBiZSBvd25lcicKCS8vICAgICAgICAgICAgICkKCXR4biBTZW5kZXIKCWZyYW1lX2RpZyAtMyAvLyBjb25maWc6IFZhbGlkYXRvckNvbmZpZwoJZXh0cmFjdCA3MiA4CglidG9pCglieXRlIDB4NjkyZTZmNzc2ZTY1NzIyZTYxIC8vICJpLm93bmVyLmEiCglhcHBfZ2xvYmFsX2dldF9leAoJYXNzZXJ0Cgk9PQoKCS8vIElmIHNwZWNpZnlpbmcgTkZELCBhY2NvdW50IGFkZGluZyB2YWxpZGF0b3IgbXVzdCBiZSBvd25lcgoJYXNzZXJ0CgoqaWY1X2VuZDoKCS8vICppZjZfY29uZGl0aW9uCgkvLyBjb250cmFjdHMvdmFsaWRhdG9yUmVnaXN0cnkuYWxnby50czo0MjcKCS8vIGNvbmZpZy5lbnRyeUdhdGluZ1R5cGUgPT09IEdBVElOR19UWVBFX0NSRUFURURfQllfTkZEX0FERFJFU1NFUwoJZnJhbWVfZGlnIC0zIC8vIGNvbmZpZzogVmFsaWRhdG9yQ29uZmlnCglleHRyYWN0IDgwIDEKCWJ0b2kKCWludCAzCgk9PQoJYnogKmlmNl9lbmQKCgkvLyAqaWY2X2NvbnNlcXVlbnQKCS8vIGNvbnRyYWN0cy92YWxpZGF0b3JSZWdpc3RyeS5hbGdvLnRzOjQyOQoJLy8gYXNzZXJ0KGNvbmZpZy5uZmRGb3JJbmZvICE9PSAwLCAnYW4gTkZEIG11c3QgYmUgc3BlY2lmaWVkIGZvciB0aGUgdmFsaWRhdG9yIHdoZW4gZ2F0aW5nIGJ5IE5GRCBhZGRyZXNzZXMnKQoJZnJhbWVfZGlnIC0zIC8vIGNvbmZpZzogVmFsaWRhdG9yQ29uZmlnCglleHRyYWN0IDcyIDgKCWJ0b2kKCWludCAwCgkhPQoKCS8vIGFuIE5GRCBtdXN0IGJlIHNwZWNpZmllZCBmb3IgdGhlIHZhbGlkYXRvciB3aGVuIGdhdGluZyBieSBORkQgYWRkcmVzc2VzCglhc3NlcnQKCippZjZfZW5kOgoJLy8gKmlmN19jb25kaXRpb24KCS8vIGNvbnRyYWN0cy92YWxpZGF0b3JSZWdpc3RyeS5hbGdvLnRzOjQzMQoJLy8gY29uZmlnLmVudHJ5R2F0aW5nVHlwZSA9PT0gR0FUSU5HX1RZUEVfU0VHTUVOVF9PRl9ORkQKCWZyYW1lX2RpZyAtMyAvLyBjb25maWc6IFZhbGlkYXRvckNvbmZpZwoJZXh0cmFjdCA4MCAxCglidG9pCglpbnQgNAoJPT0KCWJ6ICppZjdfZW5kCgoJLy8gKmlmN19jb25zZXF1ZW50CgkvLyBjb250cmFjdHMvdmFsaWRhdG9yUmVnaXN0cnkuYWxnby50czo0MzMKCS8vIG5mZFJvb3RBcHBJRCA9IGV4dHJhY3RVaW50NjQoY29uZmlnLmVudHJ5R2F0aW5nVmFsdWUsIDApCglmcmFtZV9kaWcgLTMgLy8gY29uZmlnOiBWYWxpZGF0b3JDb25maWcKCWV4dHJhY3QgODEgMzIKCWludCAwCglleHRyYWN0X3VpbnQ2NAoJZnJhbWVfYnVyeSAxIC8vIG5mZFJvb3RBcHBJRDogdWludDY0CgoJLy8gY29udHJhY3RzL3ZhbGlkYXRvclJlZ2lzdHJ5LmFsZ28udHM6NDM0CgkvLyBhc3NlcnQodGhpcy5pc05GREFwcElEVmFsaWQobmZkUm9vdEFwcElEKSwgJ3Byb3ZpZGVkIE5GRCBBcHAgaWQgZm9yIGdhdGluZyBtdXN0IGJlIHZhbGlkIE5GRCcpCglmcmFtZV9kaWcgMSAvLyBuZmRSb290QXBwSUQ6IHVpbnQ2NAoJY2FsbHN1YiBpc05GREFwcElEVmFsaWQKCgkvLyBwcm92aWRlZCBORkQgQXBwIGlkIGZvciBnYXRpbmcgbXVzdCBiZSB2YWxpZCBORkQKCWFzc2VydAoKKmlmN19lbmQ6CgkvLyBjb250cmFjdHMvdmFsaWRhdG9yUmVnaXN0cnkuYWxnby50czo0MzcKCS8vIHJldHVybiB2YWxpZGF0b3JJZDsKCWZyYW1lX2RpZyAwIC8vIHZhbGlkYXRvcklkOiB1aW50NjQKCgkvLyBzZXQgdGhlIHN1YnJvdXRpbmUgcmV0dXJuIHZhbHVlCglmcmFtZV9idXJ5IDAKCgkvLyBwb3AgYWxsIGxvY2FsIHZhcmlhYmxlcyBmcm9tIHRoZSBzdGFjawoJcG9wbiAxCglyZXRzdWIKCi8vIGNoYW5nZVZhbGlkYXRvck1hbmFnZXIodWludDY0LGFkZHJlc3Mpdm9pZAoqYWJpX3JvdXRlX2NoYW5nZVZhbGlkYXRvck1hbmFnZXI6CgkvLyBtYW5hZ2VyOiBhZGRyZXNzCgl0eG5hIEFwcGxpY2F0aW9uQXJncyAyCglkdXAKCWxlbgoJaW50IDMyCgk9PQoJYXNzZXJ0CgoJLy8gdmFsaWRhdG9ySWQ6IHVpbnQ2NAoJdHhuYSBBcHBsaWNhdGlvbkFyZ3MgMQoJYnRvaQoKCS8vIGV4ZWN1dGUgY2hhbmdlVmFsaWRhdG9yTWFuYWdlcih1aW50NjQsYWRkcmVzcyl2b2lkCgljYWxsc3ViIGNoYW5nZVZhbGlkYXRvck1hbmFnZXIKCWludCAxCglyZXR1cm4KCi8vIGNoYW5nZVZhbGlkYXRvck1hbmFnZXIodmFsaWRhdG9ySWQ6IFZhbGlkYXRvcklkVHlwZSwgbWFuYWdlcjogQWRkcmVzcyk6IHZvaWQKLy8KLy8gQ2hhbmdlcyB0aGUgVmFsaWRhdG9yIG1hbmFnZXIgZm9yIGEgc3BlY2lmaWMgVmFsaWRhdG9yIGlkLgovLyBbIE9OTFkgT1dORVIgQ0FOIENIQU5HRSBdCi8vCi8vIEBwYXJhbSB7VmFsaWRhdG9ySWRUeXBlfSB2YWxpZGF0b3JJZCAtIFRoZSBpZCBvZiB0aGUgdmFsaWRhdG9yIHRvIGNoYW5nZSB0aGUgbWFuYWdlciBmb3IuCi8vIEBwYXJhbSB7QWRkcmVzc30gbWFuYWdlciAtIFRoZSBuZXcgbWFuYWdlciBhZGRyZXNzLgpjaGFuZ2VWYWxpZGF0b3JNYW5hZ2VyOgoJcHJvdG8gMiAwCgoJLy8gY29udHJhY3RzL3ZhbGlkYXRvclJlZ2lzdHJ5LmFsZ28udHM6NDQ4CgkvLyBhc3NlcnQodGhpcy50eG4uc2VuZGVyID09PSB0aGlzLnZhbGlkYXRvckxpc3QodmFsaWRhdG9ySWQpLnZhbHVlLmNvbmZpZy5vd25lcikKCXR4biBTZW5kZXIKCWludCA4CglpbnQgMzIKCWJ5dGUgMHg3NiAvLyAidiIKCWZyYW1lX2RpZyAtMSAvLyB2YWxpZGF0b3JJZDogVmFsaWRhdG9ySWRUeXBlCglpdG9iCgljb25jYXQKCWNvdmVyIDIKCWJveF9leHRyYWN0Cgk9PQoJYXNzZXJ0CgoJLy8gY29udHJhY3RzL3ZhbGlkYXRvclJlZ2lzdHJ5LmFsZ28udHM6NDQ5CgkvLyB0aGlzLnZhbGlkYXRvckxpc3QodmFsaWRhdG9ySWQpLnZhbHVlLmNvbmZpZy5tYW5hZ2VyID0gbWFuYWdlcgoJaW50IDQwCglmcmFtZV9kaWcgLTIgLy8gbWFuYWdlcjogQWRkcmVzcwoJYnl0ZSAweDc2IC8vICJ2IgoJZnJhbWVfZGlnIC0xIC8vIHZhbGlkYXRvcklkOiBWYWxpZGF0b3JJZFR5cGUKCWl0b2IKCWNvbmNhdAoJY292ZXIgMgoJYm94X3JlcGxhY2UKCXJldHN1YgoKLy8gY2hhbmdlVmFsaWRhdG9yU3Vuc2V0SW5mbyh1aW50NjQsdWludDY0LHVpbnQ2NCl2b2lkCiphYmlfcm91dGVfY2hhbmdlVmFsaWRhdG9yU3Vuc2V0SW5mbzoKCS8vIHN1bnNldHRpbmdUbzogdWludDY0Cgl0eG5hIEFwcGxpY2F0aW9uQXJncyAzCglidG9pCgoJLy8gc3Vuc2V0dGluZ09uOiB1aW50NjQKCXR4bmEgQXBwbGljYXRpb25BcmdzIDIKCWJ0b2kKCgkvLyB2YWxpZGF0b3JJZDogdWludDY0Cgl0eG5hIEFwcGxpY2F0aW9uQXJncyAxCglidG9pCgoJLy8gZXhlY3V0ZSBjaGFuZ2VWYWxpZGF0b3JTdW5zZXRJbmZvKHVpbnQ2NCx1aW50NjQsdWludDY0KXZvaWQKCWNhbGxzdWIgY2hhbmdlVmFsaWRhdG9yU3Vuc2V0SW5mbwoJaW50IDEKCXJldHVybgoKLy8gY2hhbmdlVmFsaWRhdG9yU3Vuc2V0SW5mbyh2YWxpZGF0b3JJZDogVmFsaWRhdG9ySWRUeXBlLCBzdW5zZXR0aW5nT246IHVpbnQ2NCwgc3Vuc2V0dGluZ1RvOiBWYWxpZGF0b3JJZFR5cGUpOiB2b2lkCi8vCi8vIFVwZGF0ZXMgdGhlIHN1bnNldCBpbmZvcm1hdGlvbiBmb3IgYSBnaXZlbiB2YWxpZGF0b3IuCi8vIFsgT05MWSBPV05FUiBDQU4gQ0hBTkdFIF0KLy8KLy8gQHBhcmFtIHtWYWxpZGF0b3JJZFR5cGV9IHZhbGlkYXRvcklkIC0gVGhlIGlkIG9mIHRoZSB2YWxpZGF0b3IgdG8gdXBkYXRlLgovLyBAcGFyYW0ge3VpbnQ2NH0gc3Vuc2V0dGluZ09uIC0gVGhlIG5ldyBzdW5zZXQgdGltZXN0YW1wLgovLyBAcGFyYW0ge3VpbnQ2NH0gc3Vuc2V0dGluZ1RvIC0gVGhlIG5ldyBzdW5zZXQgdG8gdmFsaWRhdG9yIGlkLgpjaGFuZ2VWYWxpZGF0b3JTdW5zZXRJbmZvOgoJcHJvdG8gMyAwCgoJLy8gY29udHJhY3RzL3ZhbGlkYXRvclJlZ2lzdHJ5LmFsZ28udHM6NDYxCgkvLyBhc3NlcnQodGhpcy50eG4uc2VuZGVyID09PSB0aGlzLnZhbGlkYXRvckxpc3QodmFsaWRhdG9ySWQpLnZhbHVlLmNvbmZpZy5vd25lcikKCXR4biBTZW5kZXIKCWludCA4CglpbnQgMzIKCWJ5dGUgMHg3NiAvLyAidiIKCWZyYW1lX2RpZyAtMSAvLyB2YWxpZGF0b3JJZDogVmFsaWRhdG9ySWRUeXBlCglpdG9iCgljb25jYXQKCWNvdmVyIDIKCWJveF9leHRyYWN0Cgk9PQoJYXNzZXJ0CgoJLy8gY29udHJhY3RzL3ZhbGlkYXRvclJlZ2lzdHJ5LmFsZ28udHM6NDYyCgkvLyB0aGlzLnZhbGlkYXRvckxpc3QodmFsaWRhdG9ySWQpLnZhbHVlLmNvbmZpZy5zdW5zZXR0aW5nT24gPSBzdW5zZXR0aW5nT24KCWludCAxOTIKCWZyYW1lX2RpZyAtMiAvLyBzdW5zZXR0aW5nT246IHVpbnQ2NAoJaXRvYgoJYnl0ZSAweDc2IC8vICJ2IgoJZnJhbWVfZGlnIC0xIC8vIHZhbGlkYXRvcklkOiBWYWxpZGF0b3JJZFR5cGUKCWl0b2IKCWNvbmNhdAoJY292ZXIgMgoJYm94X3JlcGxhY2UKCgkvLyBjb250cmFjdHMvdmFsaWRhdG9yUmVnaXN0cnkuYWxnby50czo0NjMKCS8vIHRoaXMudmFsaWRhdG9yTGlzdCh2YWxpZGF0b3JJZCkudmFsdWUuY29uZmlnLnN1bnNldHRpbmdUbyA9IHN1bnNldHRpbmdUbwoJaW50IDIwMAoJZnJhbWVfZGlnIC0zIC8vIHN1bnNldHRpbmdUbzogVmFsaWRhdG9ySWRUeXBlCglpdG9iCglieXRlIDB4NzYgLy8gInYiCglmcmFtZV9kaWcgLTEgLy8gdmFsaWRhdG9ySWQ6IFZhbGlkYXRvcklkVHlwZQoJaXRvYgoJY29uY2F0Cgljb3ZlciAyCglib3hfcmVwbGFjZQoJcmV0c3ViCgovLyBjaGFuZ2VWYWxpZGF0b3JORkQodWludDY0LHVpbnQ2NCxzdHJpbmcpdm9pZAoqYWJpX3JvdXRlX2NoYW5nZVZhbGlkYXRvck5GRDoKCS8vIG5mZE5hbWU6IHN0cmluZwoJdHhuYSBBcHBsaWNhdGlvbkFyZ3MgMwoJZXh0cmFjdCAyIDAKCgkvLyBuZmRBcHBJRDogdWludDY0Cgl0eG5hIEFwcGxpY2F0aW9uQXJncyAyCglidG9pCgoJLy8gdmFsaWRhdG9ySWQ6IHVpbnQ2NAoJdHhuYSBBcHBsaWNhdGlvbkFyZ3MgMQoJYnRvaQoKCS8vIGV4ZWN1dGUgY2hhbmdlVmFsaWRhdG9yTkZEKHVpbnQ2NCx1aW50NjQsc3RyaW5nKXZvaWQKCWNhbGxzdWIgY2hhbmdlVmFsaWRhdG9yTkZECglpbnQgMQoJcmV0dXJuCgovLyBjaGFuZ2VWYWxpZGF0b3JORkQodmFsaWRhdG9ySWQ6IFZhbGlkYXRvcklkVHlwZSwgbmZkQXBwSUQ6IHVpbnQ2NCwgbmZkTmFtZTogc3RyaW5nKTogdm9pZAovLwovLyBDaGFuZ2VzIHRoZSBORkQgZm9yIGEgdmFsaWRhdG9yIGluIHRoZSB2YWxpZGF0b3JMaXN0IGNvbnRyYWN0LgovLyBbIE9OTFkgT1dORVIgT1IgTUFOQUdFUiBDQU4gQ0hBTkdFIF0KLy8KLy8gQHBhcmFtIHtWYWxpZGF0b3JJZFR5cGV9IHZhbGlkYXRvcklkIC0gVGhlIGlkIG9mIHRoZSB2YWxpZGF0b3IgdG8gdXBkYXRlLgovLyBAcGFyYW0ge3VpbnQ2NH0gbmZkQXBwSUQgLSBUaGUgYXBwbGljYXRpb24gaWQgb2YgdGhlIE5GRCB0byBhc3NpZ24gdG8gdGhlIHZhbGlkYXRvci4KLy8gQHBhcmFtIHtzdHJpbmd9IG5mZE5hbWUgLSBUaGUgbmFtZSBvZiB0aGUgTkZEICh3aGljaCBtdXN0IG1hdGNoKQpjaGFuZ2VWYWxpZGF0b3JORkQ6Cglwcm90byAzIDAKCgkvLyBjb250cmFjdHMvdmFsaWRhdG9yUmVnaXN0cnkuYWxnby50czo0NzYKCS8vIGFzc2VydCgKCS8vICAgICAgICAgICAgIHRoaXMudHhuLnNlbmRlciA9PT0gdGhpcy52YWxpZGF0b3JMaXN0KHZhbGlkYXRvcklkKS52YWx1ZS5jb25maWcub3duZXIgfHwKCS8vICAgICAgICAgICAgICAgICB0aGlzLnR4bi5zZW5kZXIgPT09IHRoaXMudmFsaWRhdG9yTGlzdCh2YWxpZGF0b3JJZCkudmFsdWUuY29uZmlnLm1hbmFnZXIKCS8vICAgICAgICAgKQoJdHhuIFNlbmRlcgoJaW50IDgKCWludCAzMgoJYnl0ZSAweDc2IC8vICJ2IgoJZnJhbWVfZGlnIC0xIC8vIHZhbGlkYXRvcklkOiBWYWxpZGF0b3JJZFR5cGUKCWl0b2IKCWNvbmNhdAoJY292ZXIgMgoJYm94X2V4dHJhY3QKCT09CglkdXAKCWJueiAqc2tpcF9vcjAKCXR4biBTZW5kZXIKCWludCA0MAoJaW50IDMyCglieXRlIDB4NzYgLy8gInYiCglmcmFtZV9kaWcgLTEgLy8gdmFsaWRhdG9ySWQ6IFZhbGlkYXRvcklkVHlwZQoJaXRvYgoJY29uY2F0Cgljb3ZlciAyCglib3hfZXh0cmFjdAoJPT0KCXx8Cgoqc2tpcF9vcjA6Cglhc3NlcnQKCgkvLyBjb250cmFjdHMvdmFsaWRhdG9yUmVnaXN0cnkuYWxnby50czo0ODEKCS8vIHNlbmRBcHBDYWxsKHsKCS8vICAgICAgICAgICAgIGFwcGxpY2F0aW9uSUQ6IEFwcElELmZyb21VaW50NjQodGhpcy5uZmRSZWdpc3RyeUFwcElkKSwKCS8vICAgICAgICAgICAgIGFwcGxpY2F0aW9uQXJnczogWydpc192YWxpZF9uZmRfYXBwaWQnLCBuZmROYW1lLCBpdG9iKG5mZEFwcElEKV0sCgkvLyAgICAgICAgICAgICBhcHBsaWNhdGlvbnM6IFtBcHBJRC5mcm9tVWludDY0KG5mZEFwcElEKV0sCgkvLyAgICAgICAgIH0pCglpdHhuX2JlZ2luCglpbnQgYXBwbAoJaXR4bl9maWVsZCBUeXBlRW51bQoKCS8vIGNvbnRyYWN0cy92YWxpZGF0b3JSZWdpc3RyeS5hbGdvLnRzOjQ4MgoJLy8gYXBwbGljYXRpb25JRDogQXBwSUQuZnJvbVVpbnQ2NCh0aGlzLm5mZFJlZ2lzdHJ5QXBwSWQpCglwdXNoaW50IFRNUExfbmZkUmVnaXN0cnlBcHBJZAoJaXR4bl9maWVsZCBBcHBsaWNhdGlvbklECgoJLy8gY29udHJhY3RzL3ZhbGlkYXRvclJlZ2lzdHJ5LmFsZ28udHM6NDgzCgkvLyBhcHBsaWNhdGlvbkFyZ3M6IFsnaXNfdmFsaWRfbmZkX2FwcGlkJywgbmZkTmFtZSwgaXRvYihuZmRBcHBJRCldCglieXRlIDB4Njk3MzVmNzY2MTZjNjk2NDVmNmU2NjY0NWY2MTcwNzA2OTY0IC8vICJpc192YWxpZF9uZmRfYXBwaWQiCglpdHhuX2ZpZWxkIEFwcGxpY2F0aW9uQXJncwoJZnJhbWVfZGlnIC0zIC8vIG5mZE5hbWU6IHN0cmluZwoJaXR4bl9maWVsZCBBcHBsaWNhdGlvbkFyZ3MKCWZyYW1lX2RpZyAtMiAvLyBuZmRBcHBJRDogdWludDY0CglpdG9iCglpdHhuX2ZpZWxkIEFwcGxpY2F0aW9uQXJncwoKCS8vIGNvbnRyYWN0cy92YWxpZGF0b3JSZWdpc3RyeS5hbGdvLnRzOjQ4NAoJLy8gYXBwbGljYXRpb25zOiBbQXBwSUQuZnJvbVVpbnQ2NChuZmRBcHBJRCldCglmcmFtZV9kaWcgLTIgLy8gbmZkQXBwSUQ6IHVpbnQ2NAoJaXR4bl9maWVsZCBBcHBsaWNhdGlvbnMKCgkvLyBGZWUgZmllbGQgbm90IHNldCwgZGVmYXVsdGluZyB0byAwCglpbnQgMAoJaXR4bl9maWVsZCBGZWUKCgkvLyBTdWJtaXQgaW5uZXIgdHJhbnNhY3Rpb24KCWl0eG5fc3VibWl0CgoJLy8gY29udHJhY3RzL3ZhbGlkYXRvclJlZ2lzdHJ5LmFsZ28udHM6NDg3CgkvLyBhc3NlcnQoCgkvLyAgICAgICAgICAgICB0aGlzLnR4bi5zZW5kZXIgPT09IChBcHBJRC5mcm9tVWludDY0KG5mZEFwcElEKS5nbG9iYWxTdGF0ZSgnaS5vd25lci5hJykgYXMgQWRkcmVzcyksCgkvLyAgICAgICAgICAgICAnSWYgc3BlY2lmeWluZyBORkQsIGFjY291bnQgYWRkaW5nIHZhbGlkYXRvciBtdXN0IGJlIG93bmVyJwoJLy8gICAgICAgICApCgl0eG4gU2VuZGVyCglmcmFtZV9kaWcgLTIgLy8gbmZkQXBwSUQ6IHVpbnQ2NAoJYnl0ZSAweDY5MmU2Zjc3NmU2NTcyMmU2MSAvLyAiaS5vd25lci5hIgoJYXBwX2dsb2JhbF9nZXRfZXgKCWFzc2VydAoJPT0KCgkvLyBJZiBzcGVjaWZ5aW5nIE5GRCwgYWNjb3VudCBhZGRpbmcgdmFsaWRhdG9yIG11c3QgYmUgb3duZXIKCWFzc2VydAoKCS8vIGNvbnRyYWN0cy92YWxpZGF0b3JSZWdpc3RyeS5hbGdvLnRzOjQ5MQoJLy8gdGhpcy52YWxpZGF0b3JMaXN0KHZhbGlkYXRvcklkKS52YWx1ZS5jb25maWcubmZkRm9ySW5mbyA9IG5mZEFwcElECglpbnQgNzIKCWZyYW1lX2RpZyAtMiAvLyBuZmRBcHBJRDogdWludDY0CglpdG9iCglieXRlIDB4NzYgLy8gInYiCglmcmFtZV9kaWcgLTEgLy8gdmFsaWRhdG9ySWQ6IFZhbGlkYXRvcklkVHlwZQoJaXRvYgoJY29uY2F0Cgljb3ZlciAyCglib3hfcmVwbGFjZQoJcmV0c3ViCgovLyBjaGFuZ2VWYWxpZGF0b3JDb21taXNzaW9uQWRkcmVzcyh1aW50NjQsYWRkcmVzcyl2b2lkCiphYmlfcm91dGVfY2hhbmdlVmFsaWRhdG9yQ29tbWlzc2lvbkFkZHJlc3M6CgkvLyBjb21taXNzaW9uQWRkcmVzczogYWRkcmVzcwoJdHhuYSBBcHBsaWNhdGlvbkFyZ3MgMgoJZHVwCglsZW4KCWludCAzMgoJPT0KCWFzc2VydAoKCS8vIHZhbGlkYXRvcklkOiB1aW50NjQKCXR4bmEgQXBwbGljYXRpb25BcmdzIDEKCWJ0b2kKCgkvLyBleGVjdXRlIGNoYW5nZVZhbGlkYXRvckNvbW1pc3Npb25BZGRyZXNzKHVpbnQ2NCxhZGRyZXNzKXZvaWQKCWNhbGxzdWIgY2hhbmdlVmFsaWRhdG9yQ29tbWlzc2lvbkFkZHJlc3MKCWludCAxCglyZXR1cm4KCi8vIGNoYW5nZVZhbGlkYXRvckNvbW1pc3Npb25BZGRyZXNzKHZhbGlkYXRvcklkOiBWYWxpZGF0b3JJZFR5cGUsIGNvbW1pc3Npb25BZGRyZXNzOiBBZGRyZXNzKTogdm9pZAovLwovLyBDaGFuZ2UgdGhlIGNvbW1pc3Npb24gYWRkcmVzcyB0aGF0IHZhbGlkYXRvciByZXdhcmRzIGFyZSBzZW50IHRvLgovLyBbIE9OTFkgT1dORVIgQ0FOIENIQU5HRSBdCmNoYW5nZVZhbGlkYXRvckNvbW1pc3Npb25BZGRyZXNzOgoJcHJvdG8gMiAwCgoJLy8gY29udHJhY3RzL3ZhbGlkYXRvclJlZ2lzdHJ5LmFsZ28udHM6NDk5CgkvLyBhc3NlcnQodGhpcy50eG4uc2VuZGVyID09PSB0aGlzLnZhbGlkYXRvckxpc3QodmFsaWRhdG9ySWQpLnZhbHVlLmNvbmZpZy5vd25lcikKCXR4biBTZW5kZXIKCWludCA4CglpbnQgMzIKCWJ5dGUgMHg3NiAvLyAidiIKCWZyYW1lX2RpZyAtMSAvLyB2YWxpZGF0b3JJZDogVmFsaWRhdG9ySWRUeXBlCglpdG9iCgljb25jYXQKCWNvdmVyIDIKCWJveF9leHRyYWN0Cgk9PQoJYXNzZXJ0CgoJLy8gY29udHJhY3RzL3ZhbGlkYXRvclJlZ2lzdHJ5LmFsZ28udHM6NTAwCgkvLyBhc3NlcnQoY29tbWlzc2lvbkFkZHJlc3MgIT09IEFkZHJlc3MuemVyb0FkZHJlc3MpCglmcmFtZV9kaWcgLTIgLy8gY29tbWlzc2lvbkFkZHJlc3M6IEFkZHJlc3MKCWdsb2JhbCBaZXJvQWRkcmVzcwoJIT0KCWFzc2VydAoKCS8vIGNvbnRyYWN0cy92YWxpZGF0b3JSZWdpc3RyeS5hbGdvLnRzOjUwMQoJLy8gdGhpcy52YWxpZGF0b3JMaXN0KHZhbGlkYXRvcklkKS52YWx1ZS5jb25maWcudmFsaWRhdG9yQ29tbWlzc2lvbkFkZHJlc3MgPSBjb21taXNzaW9uQWRkcmVzcwoJaW50IDE0MwoJZnJhbWVfZGlnIC0yIC8vIGNvbW1pc3Npb25BZGRyZXNzOiBBZGRyZXNzCglieXRlIDB4NzYgLy8gInYiCglmcmFtZV9kaWcgLTEgLy8gdmFsaWRhdG9ySWQ6IFZhbGlkYXRvcklkVHlwZQoJaXRvYgoJY29uY2F0Cgljb3ZlciAyCglib3hfcmVwbGFjZQoJcmV0c3ViCgovLyBjaGFuZ2VWYWxpZGF0b3JSZXdhcmRJbmZvKHVpbnQ2NCx1aW50OCxieXRlWzMyXSx1aW50NjQsdWludDY0KXZvaWQKKmFiaV9yb3V0ZV9jaGFuZ2VWYWxpZGF0b3JSZXdhcmRJbmZvOgoJLy8gUmV3YXJkUGVyUGF5b3V0OiB1aW50NjQKCXR4bmEgQXBwbGljYXRpb25BcmdzIDUKCWJ0b2kKCgkvLyBHYXRpbmdBc3NldE1pbkJhbGFuY2U6IHVpbnQ2NAoJdHhuYSBBcHBsaWNhdGlvbkFyZ3MgNAoJYnRvaQoKCS8vIEVudHJ5R2F0aW5nVmFsdWU6IGJ5dGVbMzJdCgl0eG5hIEFwcGxpY2F0aW9uQXJncyAzCglkdXAKCWxlbgoJaW50IDMyCgk9PQoJYXNzZXJ0CgoJLy8gRW50cnlHYXRpbmdUeXBlOiB1aW50OAoJdHhuYSBBcHBsaWNhdGlvbkFyZ3MgMgoJZHVwCglsZW4KCWludCAxCgk9PQoJYXNzZXJ0CglidG9pCgoJLy8gdmFsaWRhdG9ySWQ6IHVpbnQ2NAoJdHhuYSBBcHBsaWNhdGlvbkFyZ3MgMQoJYnRvaQoKCS8vIGV4ZWN1dGUgY2hhbmdlVmFsaWRhdG9yUmV3YXJkSW5mbyh1aW50NjQsdWludDgsYnl0ZVszMl0sdWludDY0LHVpbnQ2NCl2b2lkCgljYWxsc3ViIGNoYW5nZVZhbGlkYXRvclJld2FyZEluZm8KCWludCAxCglyZXR1cm4KCi8vIGNoYW5nZVZhbGlkYXRvclJld2FyZEluZm8odmFsaWRhdG9ySWQ6IFZhbGlkYXRvcklkVHlwZSwgRW50cnlHYXRpbmdUeXBlOiB1aW50OCwgRW50cnlHYXRpbmdWYWx1ZTogYnl0ZXMzMiwgR2F0aW5nQXNzZXRNaW5CYWxhbmNlOiB1aW50NjQsIFJld2FyZFBlclBheW91dDogdWludDY0KTogdm9pZAovLwovLyBBbGxvdyB0aGUgYWRkaXRpb25hbCByZXdhcmRzIChnYXRpbmcgZW50cnksIGFkZGl0aW9uYWwgdG9rZW4gcmV3YXJkcykgaW5mb3JtYXRpb24gYmUgY2hhbmdlZCBhdCB3aWxsLgovLyBbIE9OTFkgT1dORVIgQ0FOIENIQU5HRSBdCmNoYW5nZVZhbGlkYXRvclJld2FyZEluZm86Cglwcm90byA1IDAKCgkvLyBjb250cmFjdHMvdmFsaWRhdG9yUmVnaXN0cnkuYWxnby50czo1MTUKCS8vIGFzc2VydCh0aGlzLnR4bi5zZW5kZXIgPT09IHRoaXMudmFsaWRhdG9yTGlzdCh2YWxpZGF0b3JJZCkudmFsdWUuY29uZmlnLm93bmVyKQoJdHhuIFNlbmRlcgoJaW50IDgKCWludCAzMgoJYnl0ZSAweDc2IC8vICJ2IgoJZnJhbWVfZGlnIC0xIC8vIHZhbGlkYXRvcklkOiBWYWxpZGF0b3JJZFR5cGUKCWl0b2IKCWNvbmNhdAoJY292ZXIgMgoJYm94X2V4dHJhY3QKCT09Cglhc3NlcnQKCgkvLyBjb250cmFjdHMvdmFsaWRhdG9yUmVnaXN0cnkuYWxnby50czo1MTcKCS8vIHRoaXMudmFsaWRhdG9yTGlzdCh2YWxpZGF0b3JJZCkudmFsdWUuY29uZmlnLmVudHJ5R2F0aW5nVHlwZSA9IEVudHJ5R2F0aW5nVHlwZQoJaW50IDgwCglmcmFtZV9kaWcgLTIgLy8gRW50cnlHYXRpbmdUeXBlOiB1aW50OAoJaXRvYgoJZXh0cmFjdCA3IDEKCWJ5dGUgMHg3NiAvLyAidiIKCWZyYW1lX2RpZyAtMSAvLyB2YWxpZGF0b3JJZDogVmFsaWRhdG9ySWRUeXBlCglpdG9iCgljb25jYXQKCWNvdmVyIDIKCWJveF9yZXBsYWNlCgoJLy8gY29udHJhY3RzL3ZhbGlkYXRvclJlZ2lzdHJ5LmFsZ28udHM6NTE4CgkvLyB0aGlzLnZhbGlkYXRvckxpc3QodmFsaWRhdG9ySWQpLnZhbHVlLmNvbmZpZy5lbnRyeUdhdGluZ1ZhbHVlID0gRW50cnlHYXRpbmdWYWx1ZQoJaW50IDgxCglmcmFtZV9kaWcgLTMgLy8gRW50cnlHYXRpbmdWYWx1ZTogYnl0ZXMzMgoJYnl0ZSAweDc2IC8vICJ2IgoJZnJhbWVfZGlnIC0xIC8vIHZhbGlkYXRvcklkOiBWYWxpZGF0b3JJZFR5cGUKCWl0b2IKCWNvbmNhdAoJY292ZXIgMgoJYm94X3JlcGxhY2UKCgkvLyBjb250cmFjdHMvdmFsaWRhdG9yUmVnaXN0cnkuYWxnby50czo1MTkKCS8vIHRoaXMudmFsaWRhdG9yTGlzdCh2YWxpZGF0b3JJZCkudmFsdWUuY29uZmlnLmdhdGluZ0Fzc2V0TWluQmFsYW5jZSA9IEdhdGluZ0Fzc2V0TWluQmFsYW5jZQoJaW50IDExMwoJZnJhbWVfZGlnIC00IC8vIEdhdGluZ0Fzc2V0TWluQmFsYW5jZTogdWludDY0CglpdG9iCglieXRlIDB4NzYgLy8gInYiCglmcmFtZV9kaWcgLTEgLy8gdmFsaWRhdG9ySWQ6IFZhbGlkYXRvcklkVHlwZQoJaXRvYgoJY29uY2F0Cgljb3ZlciAyCglib3hfcmVwbGFjZQoKCS8vIGNvbnRyYWN0cy92YWxpZGF0b3JSZWdpc3RyeS5hbGdvLnRzOjUyMAoJLy8gdGhpcy52YWxpZGF0b3JMaXN0KHZhbGlkYXRvcklkKS52YWx1ZS5jb25maWcucmV3YXJkUGVyUGF5b3V0ID0gUmV3YXJkUGVyUGF5b3V0CglpbnQgMTI5CglmcmFtZV9kaWcgLTUgLy8gUmV3YXJkUGVyUGF5b3V0OiB1aW50NjQKCWl0b2IKCWJ5dGUgMHg3NiAvLyAidiIKCWZyYW1lX2RpZyAtMSAvLyB2YWxpZGF0b3JJZDogVmFsaWRhdG9ySWRUeXBlCglpdG9iCgljb25jYXQKCWNvdmVyIDIKCWJveF9yZXBsYWNlCglyZXRzdWIKCi8vIGFkZFBvb2wocGF5LHVpbnQ2NCx1aW50NjQpKHVpbnQ2NCx1aW50NjQsdWludDY0KQoqYWJpX3JvdXRlX2FkZFBvb2w6CgkvLyBUaGUgQUJJIHJldHVybiBwcmVmaXgKCWJ5dGUgMHgxNTFmN2M3NQoKCS8vIG5vZGVOdW06IHVpbnQ2NAoJdHhuYSBBcHBsaWNhdGlvbkFyZ3MgMgoJYnRvaQoKCS8vIHZhbGlkYXRvcklkOiB1aW50NjQKCXR4bmEgQXBwbGljYXRpb25BcmdzIDEKCWJ0b2kKCgkvLyBtYnJQYXltZW50OiBwYXkKCXR4biBHcm91cEluZGV4CglpbnQgMQoJLQoJZHVwCglndHhucyBUeXBlRW51bQoJaW50IHBheQoJPT0KCWFzc2VydAoKCS8vIGV4ZWN1dGUgYWRkUG9vbChwYXksdWludDY0LHVpbnQ2NCkodWludDY0LHVpbnQ2NCx1aW50NjQpCgljYWxsc3ViIGFkZFBvb2wKCWNvbmNhdAoJbG9nCglpbnQgMQoJcmV0dXJuCgovLyBhZGRQb29sKG1iclBheW1lbnQ6IFBheVR4biwgdmFsaWRhdG9ySWQ6IFZhbGlkYXRvcklkVHlwZSwgbm9kZU51bTogdWludDY0KTogVmFsaWRhdG9yUG9vbEtleQovLwovLyBBZGRzIGEgbmV3IHBvb2wgdG8gYSB2YWxpZGF0b3IncyBwb29sIHNldCwgcmV0dXJuaW5nIHRoZSAna2V5JyB0byByZWZlcmVuY2UgdGhlIHBvb2wgaW4gdGhlIGZ1dHVyZSBmb3Igc3Rha2luZywgZXRjLgovLyBUaGUgY2FsbGVyIG11c3QgcGF5IHRoZSBjb3N0IG9mIHRoZSB2YWxpZGF0b3JzIE1CUiBpbmNyZWFzZSBhcyB3ZWxsIGFzIHRoZSBNQlIgdGhhdCB3aWxsIGJlIG5lZWRlZCBmb3IgdGhlIHBvb2wgaXRzZWxmLgovLwovLyBbIE9OTFkgT1dORVIgT1IgTUFOQUdFUiBDQU4gY2FsbCBdCi8vIEBwYXJhbSB7UGF5VHhufSBtYnJQYXltZW50IHBheW1lbnQgZnJvbSBjYWxsZXIgd2hpY2ggY292ZXJzIG1iciBpbmNyZWFzZSBvZiBhZGRpbmcgYSBuZXcgcG9vbAovLyBAcGFyYW0ge3VpbnQ2NH0gdmFsaWRhdG9ySWQgaXMgaWQgb2YgdmFsaWRhdG9yIHRvIHBvb2wgdG8gKG11c3QgYmUgb3duZXIgb3IgbWFuYWdlcikKLy8gQHBhcmFtIHt1aW50NjR9IG5vZGVOdW0gaXMgbm9kZSBudW1iZXIgdG8gYWRkIHRvCi8vIEByZXR1cm5zIHtWYWxpZGF0b3JQb29sS2V5fSBwb29sIGtleSB0byBjcmVhdGVkIHBvb2wKYWRkUG9vbDoKCXByb3RvIDMgMQoKCS8vIFB1c2ggZW1wdHkgYnl0ZXMgYWZ0ZXIgdGhlIGZyYW1lIHBvaW50ZXIgdG8gcmVzZXJ2ZSBzcGFjZSBmb3IgbG9jYWwgdmFyaWFibGVzCglieXRlIDB4CglkdXAKCgkvLyBjb250cmFjdHMvdmFsaWRhdG9yUmVnaXN0cnkuYWxnby50czo1MzYKCS8vIGFzc2VydCgKCS8vICAgICAgICAgICAgIHRoaXMudHhuLnNlbmRlciA9PT0gdGhpcy52YWxpZGF0b3JMaXN0KHZhbGlkYXRvcklkKS52YWx1ZS5jb25maWcub3duZXIgfHwKCS8vICAgICAgICAgICAgICAgICB0aGlzLnR4bi5zZW5kZXIgPT09IHRoaXMudmFsaWRhdG9yTGlzdCh2YWxpZGF0b3JJZCkudmFsdWUuY29uZmlnLm1hbmFnZXIKCS8vICAgICAgICAgKQoJdHhuIFNlbmRlcgoJaW50IDgKCWludCAzMgoJYnl0ZSAweDc2IC8vICJ2IgoJZnJhbWVfZGlnIC0yIC8vIHZhbGlkYXRvcklkOiBWYWxpZGF0b3JJZFR5cGUKCWl0b2IKCWNvbmNhdAoJY292ZXIgMgoJYm94X2V4dHJhY3QKCT09CglkdXAKCWJueiAqc2tpcF9vcjEKCXR4biBTZW5kZXIKCWludCA0MAoJaW50IDMyCglieXRlIDB4NzYgLy8gInYiCglmcmFtZV9kaWcgLTIgLy8gdmFsaWRhdG9ySWQ6IFZhbGlkYXRvcklkVHlwZQoJaXRvYgoJY29uY2F0Cgljb3ZlciAyCglib3hfZXh0cmFjdAoJPT0KCXx8Cgoqc2tpcF9vcjE6Cglhc3NlcnQKCgkvLyBjb250cmFjdHMvdmFsaWRhdG9yUmVnaXN0cnkuYWxnby50czo1NDIKCS8vIHZlcmlmeVBheVR4bihtYnJQYXltZW50LCB7IGFtb3VudDogdGhpcy5nZXRNYnJBbW91bnRzKCkuYWRkUG9vbE1iciwgcmVjZWl2ZXI6IHRoaXMuYXBwLmFkZHJlc3MgfSkKCS8vIHZlcmlmeSBhbW91bnQKCWZyYW1lX2RpZyAtMSAvLyBtYnJQYXltZW50OiBQYXlUeG4KCWd0eG5zIEFtb3VudAoJY2FsbHN1YiBnZXRNYnJBbW91bnRzCglleHRyYWN0IDggOAoJYnRvaQoJPT0KCWFzc2VydAoKCS8vIHZlcmlmeSByZWNlaXZlcgoJZnJhbWVfZGlnIC0xIC8vIG1iclBheW1lbnQ6IFBheVR4bgoJZ3R4bnMgUmVjZWl2ZXIKCWdsb2JhbCBDdXJyZW50QXBwbGljYXRpb25BZGRyZXNzCgk9PQoJYXNzZXJ0CgoJLy8gY29udHJhY3RzL3ZhbGlkYXRvclJlZ2lzdHJ5LmFsZ28udHM6NTQ0CgkvLyBhc3NlcnQodGhpcy52YWxpZGF0b3JMaXN0KHZhbGlkYXRvcklkKS5leGlzdHMpCglieXRlIDB4NzYgLy8gInYiCglmcmFtZV9kaWcgLTIgLy8gdmFsaWRhdG9ySWQ6IFZhbGlkYXRvcklkVHlwZQoJaXRvYgoJY29uY2F0Cglib3hfbGVuCglzd2FwCglwb3AKCWFzc2VydAoKCS8vIGNvbnRyYWN0cy92YWxpZGF0b3JSZWdpc3RyeS5hbGdvLnRzOjU0NgoJLy8gbnVtUG9vbHM6IHVpbnQ2NCA9IHRoaXMudmFsaWRhdG9yTGlzdCh2YWxpZGF0b3JJZCkudmFsdWUuc3RhdGUubnVtUG9vbHMgYXMgdWludDY0CglpbnQgMjA4CglpbnQgMgoJYnl0ZSAweDc2IC8vICJ2IgoJZnJhbWVfZGlnIC0yIC8vIHZhbGlkYXRvcklkOiBWYWxpZGF0b3JJZFR5cGUKCWl0b2IKCWNvbmNhdAoJY292ZXIgMgoJYm94X2V4dHJhY3QKCWJ0b2kKCWZyYW1lX2J1cnkgMCAvLyBudW1Qb29sczogdWludDY0CgoJLy8gKmlmOF9jb25kaXRpb24KCS8vIGNvbnRyYWN0cy92YWxpZGF0b3JSZWdpc3RyeS5hbGdvLnRzOjU0NwoJLy8gKG51bVBvb2xzIGFzIHVpbnQ2NCkgPj0gTUFYX1BPT0xTCglmcmFtZV9kaWcgMCAvLyBudW1Qb29sczogdWludDY0CglpbnQgMjQKCT49CglieiAqaWY4X2VuZAoKCS8vICppZjhfY29uc2VxdWVudAoJZXJyIC8vICdhbHJlYWR5IGF0IG1heCBwb29sIHNpemUnCgoqaWY4X2VuZDoKCS8vIGNvbnRyYWN0cy92YWxpZGF0b3JSZWdpc3RyeS5hbGdvLnRzOjU1MAoJLy8gbnVtUG9vbHMgKz0gMQoJZnJhbWVfZGlnIDAgLy8gbnVtUG9vbHM6IHVpbnQ2NAoJaW50IDEKCSsKCWZyYW1lX2J1cnkgMCAvLyBudW1Qb29sczogdWludDY0CgoJLy8gY29udHJhY3RzL3ZhbGlkYXRvclJlZ2lzdHJ5LmFsZ28udHM6NTUzCgkvLyBzZW5kQXBwQ2FsbCh7CgkvLyAgICAgICAgICAgICBvbkNvbXBsZXRpb246IE9uQ29tcGxldGlvbi5Ob09wLAoJLy8gICAgICAgICAgICAgYXBwcm92YWxQcm9ncmFtOiBBcHBJRC5mcm9tVWludDY0KHRoaXMuc3Rha2luZ1Bvb2xUZW1wbGF0ZUFwcElkLnZhbHVlKS5hcHByb3ZhbFByb2dyYW0sCgkvLyAgICAgICAgICAgICBjbGVhclN0YXRlUHJvZ3JhbTogQXBwSUQuZnJvbVVpbnQ2NCh0aGlzLnN0YWtpbmdQb29sVGVtcGxhdGVBcHBJZC52YWx1ZSkuY2xlYXJTdGF0ZVByb2dyYW0sCgkvLyAgICAgICAgICAgICBnbG9iYWxOdW1VaW50OiBBcHBJRC5mcm9tVWludDY0KHRoaXMuc3Rha2luZ1Bvb2xUZW1wbGF0ZUFwcElkLnZhbHVlKS5nbG9iYWxOdW1VaW50LAoJLy8gICAgICAgICAgICAgZ2xvYmFsTnVtQnl0ZVNsaWNlOiBBcHBJRC5mcm9tVWludDY0KHRoaXMuc3Rha2luZ1Bvb2xUZW1wbGF0ZUFwcElkLnZhbHVlKS5nbG9iYWxOdW1CeXRlU2xpY2UsCgkvLyAgICAgICAgICAgICBleHRyYVByb2dyYW1QYWdlczogQXBwSUQuZnJvbVVpbnQ2NCh0aGlzLnN0YWtpbmdQb29sVGVtcGxhdGVBcHBJZC52YWx1ZSkuZXh0cmFQcm9ncmFtUGFnZXMsCgkvLyAgICAgICAgICAgICBhcHBsaWNhdGlvbkFyZ3M6IFsKCS8vICAgICAgICAgICAgICAgICAvLyBjcmVhdGluZ0NvbnRyYWN0SUQsIHZhbGlkYXRvcklkLCBwb29sSWQsIG1pbkVudHJ5U3Rha2UKCS8vICAgICAgICAgICAgICAgICBtZXRob2QoJ2NyZWF0ZUFwcGxpY2F0aW9uKHVpbnQ2NCx1aW50NjQsdWludDY0LHVpbnQ2NCl2b2lkJyksCgkvLyAgICAgICAgICAgICAgICAgaXRvYih0aGlzLmFwcC5pZCksCgkvLyAgICAgICAgICAgICAgICAgaXRvYih2YWxpZGF0b3JJZCksCgkvLyAgICAgICAgICAgICAgICAgaXRvYihudW1Qb29scyBhcyB1aW50NjQpLAoJLy8gICAgICAgICAgICAgICAgIGl0b2IodGhpcy52YWxpZGF0b3JMaXN0KHZhbGlkYXRvcklkKS52YWx1ZS5jb25maWcubWluRW50cnlTdGFrZSksCgkvLyAgICAgICAgICAgICBdLAoJLy8gICAgICAgICB9KQoJaXR4bl9iZWdpbgoJaW50IGFwcGwKCWl0eG5fZmllbGQgVHlwZUVudW0KCgkvLyBjb250cmFjdHMvdmFsaWRhdG9yUmVnaXN0cnkuYWxnby50czo1NTQKCS8vIG9uQ29tcGxldGlvbjogT25Db21wbGV0aW9uLk5vT3AKCWludCAwIC8vIE5vT3AKCWl0eG5fZmllbGQgT25Db21wbGV0aW9uCgoJLy8gY29udHJhY3RzL3ZhbGlkYXRvclJlZ2lzdHJ5LmFsZ28udHM6NTU1CgkvLyBhcHByb3ZhbFByb2dyYW06IEFwcElELmZyb21VaW50NjQodGhpcy5zdGFraW5nUG9vbFRlbXBsYXRlQXBwSWQudmFsdWUpLmFwcHJvdmFsUHJvZ3JhbQoJYnl0ZSAweDcwNmY2ZjZjNTQ2NTZkNzA2YzYxNzQ2NTQxNzA3MDQ5NjQgLy8gInBvb2xUZW1wbGF0ZUFwcElkIgoJYXBwX2dsb2JhbF9nZXQKCWFwcF9wYXJhbXNfZ2V0IEFwcEFwcHJvdmFsUHJvZ3JhbQoJcG9wCglpdHhuX2ZpZWxkIEFwcHJvdmFsUHJvZ3JhbQoKCS8vIGNvbnRyYWN0cy92YWxpZGF0b3JSZWdpc3RyeS5hbGdvLnRzOjU1NgoJLy8gY2xlYXJTdGF0ZVByb2dyYW06IEFwcElELmZyb21VaW50NjQodGhpcy5zdGFraW5nUG9vbFRlbXBsYXRlQXBwSWQudmFsdWUpLmNsZWFyU3RhdGVQcm9ncmFtCglieXRlIDB4NzA2ZjZmNmM1NDY1NmQ3MDZjNjE3NDY1NDE3MDcwNDk2NCAvLyAicG9vbFRlbXBsYXRlQXBwSWQiCglhcHBfZ2xvYmFsX2dldAoJYXBwX3BhcmFtc19nZXQgQXBwQ2xlYXJTdGF0ZVByb2dyYW0KCXBvcAoJaXR4bl9maWVsZCBDbGVhclN0YXRlUHJvZ3JhbQoKCS8vIGNvbnRyYWN0cy92YWxpZGF0b3JSZWdpc3RyeS5hbGdvLnRzOjU1NwoJLy8gZ2xvYmFsTnVtVWludDogQXBwSUQuZnJvbVVpbnQ2NCh0aGlzLnN0YWtpbmdQb29sVGVtcGxhdGVBcHBJZC52YWx1ZSkuZ2xvYmFsTnVtVWludAoJYnl0ZSAweDcwNmY2ZjZjNTQ2NTZkNzA2YzYxNzQ2NTQxNzA3MDQ5NjQgLy8gInBvb2xUZW1wbGF0ZUFwcElkIgoJYXBwX2dsb2JhbF9nZXQKCWFwcF9wYXJhbXNfZ2V0IEFwcEdsb2JhbE51bVVpbnQKCXBvcAoJaXR4bl9maWVsZCBHbG9iYWxOdW1VaW50CgoJLy8gY29udHJhY3RzL3ZhbGlkYXRvclJlZ2lzdHJ5LmFsZ28udHM6NTU4CgkvLyBnbG9iYWxOdW1CeXRlU2xpY2U6IEFwcElELmZyb21VaW50NjQodGhpcy5zdGFraW5nUG9vbFRlbXBsYXRlQXBwSWQudmFsdWUpLmdsb2JhbE51bUJ5dGVTbGljZQoJYnl0ZSAweDcwNmY2ZjZjNTQ2NTZkNzA2YzYxNzQ2NTQxNzA3MDQ5NjQgLy8gInBvb2xUZW1wbGF0ZUFwcElkIgoJYXBwX2dsb2JhbF9nZXQKCWFwcF9wYXJhbXNfZ2V0IEFwcEdsb2JhbE51bUJ5dGVTbGljZQoJcG9wCglpdHhuX2ZpZWxkIEdsb2JhbE51bUJ5dGVTbGljZQoKCS8vIGNvbnRyYWN0cy92YWxpZGF0b3JSZWdpc3RyeS5hbGdvLnRzOjU1OQoJLy8gZXh0cmFQcm9ncmFtUGFnZXM6IEFwcElELmZyb21VaW50NjQodGhpcy5zdGFraW5nUG9vbFRlbXBsYXRlQXBwSWQudmFsdWUpLmV4dHJhUHJvZ3JhbVBhZ2VzCglieXRlIDB4NzA2ZjZmNmM1NDY1NmQ3MDZjNjE3NDY1NDE3MDcwNDk2NCAvLyAicG9vbFRlbXBsYXRlQXBwSWQiCglhcHBfZ2xvYmFsX2dldAoJYXBwX3BhcmFtc19nZXQgQXBwRXh0cmFQcm9ncmFtUGFnZXMKCXBvcAoJaXR4bl9maWVsZCBFeHRyYVByb2dyYW1QYWdlcwoKCS8vIGNvbnRyYWN0cy92YWxpZGF0b3JSZWdpc3RyeS5hbGdvLnRzOjU2MAoJLy8gYXBwbGljYXRpb25BcmdzOiBbCgkvLyAgICAgICAgICAgICAgICAgLy8gY3JlYXRpbmdDb250cmFjdElELCB2YWxpZGF0b3JJZCwgcG9vbElkLCBtaW5FbnRyeVN0YWtlCgkvLyAgICAgICAgICAgICAgICAgbWV0aG9kKCdjcmVhdGVBcHBsaWNhdGlvbih1aW50NjQsdWludDY0LHVpbnQ2NCx1aW50NjQpdm9pZCcpLAoJLy8gICAgICAgICAgICAgICAgIGl0b2IodGhpcy5hcHAuaWQpLAoJLy8gICAgICAgICAgICAgICAgIGl0b2IodmFsaWRhdG9ySWQpLAoJLy8gICAgICAgICAgICAgICAgIGl0b2IobnVtUG9vbHMgYXMgdWludDY0KSwKCS8vICAgICAgICAgICAgICAgICBpdG9iKHRoaXMudmFsaWRhdG9yTGlzdCh2YWxpZGF0b3JJZCkudmFsdWUuY29uZmlnLm1pbkVudHJ5U3Rha2UpLAoJLy8gICAgICAgICAgICAgXQoJbWV0aG9kICJjcmVhdGVBcHBsaWNhdGlvbih1aW50NjQsdWludDY0LHVpbnQ2NCx1aW50NjQpdm9pZCIKCWl0eG5fZmllbGQgQXBwbGljYXRpb25BcmdzCgl0eG5hIEFwcGxpY2F0aW9ucyAwCglpdG9iCglpdHhuX2ZpZWxkIEFwcGxpY2F0aW9uQXJncwoJZnJhbWVfZGlnIC0yIC8vIHZhbGlkYXRvcklkOiBWYWxpZGF0b3JJZFR5cGUKCWl0b2IKCWl0eG5fZmllbGQgQXBwbGljYXRpb25BcmdzCglmcmFtZV9kaWcgMCAvLyBudW1Qb29sczogdWludDY0CglpdG9iCglpdHhuX2ZpZWxkIEFwcGxpY2F0aW9uQXJncwoJaW50IDE3NQoJaW50IDgKCWJ5dGUgMHg3NiAvLyAidiIKCWZyYW1lX2RpZyAtMiAvLyB2YWxpZGF0b3JJZDogVmFsaWRhdG9ySWRUeXBlCglpdG9iCgljb25jYXQKCWNvdmVyIDIKCWJveF9leHRyYWN0CglidG9pCglpdG9iCglpdHhuX2ZpZWxkIEFwcGxpY2F0aW9uQXJncwoKCS8vIEZlZSBmaWVsZCBub3Qgc2V0LCBkZWZhdWx0aW5nIHRvIDAKCWludCAwCglpdHhuX2ZpZWxkIEZlZQoKCS8vIFN1Ym1pdCBpbm5lciB0cmFuc2FjdGlvbgoJaXR4bl9zdWJtaXQKCgkvLyBjb250cmFjdHMvdmFsaWRhdG9yUmVnaXN0cnkuYWxnby50czo1NzAKCS8vIHRoaXMudmFsaWRhdG9yTGlzdCh2YWxpZGF0b3JJZCkudmFsdWUuc3RhdGUubnVtUG9vbHMgPSBudW1Qb29scyBhcyB1aW50MTYKCWludCAyMDgKCWZyYW1lX2RpZyAwIC8vIG51bVBvb2xzOiB1aW50NjQKCWl0b2IKCWV4dHJhY3QgNiAyCglieXRlIDB4NzYgLy8gInYiCglmcmFtZV9kaWcgLTIgLy8gdmFsaWRhdG9ySWQ6IFZhbGlkYXRvcklkVHlwZQoJaXRvYgoJY29uY2F0Cgljb3ZlciAyCglib3hfcmVwbGFjZQoKCS8vIGNvbnRyYWN0cy92YWxpZGF0b3JSZWdpc3RyeS5hbGdvLnRzOjU3MwoJLy8gcG9vbEFwcElkID0gdGhpcy5pdHhuLmNyZWF0ZWRBcHBsaWNhdGlvbklELmlkCglpdHhuIENyZWF0ZWRBcHBsaWNhdGlvbklECglmcmFtZV9idXJ5IDEgLy8gcG9vbEFwcElkOiB1aW50NjQKCgkvLyBjb250cmFjdHMvdmFsaWRhdG9yUmVnaXN0cnkuYWxnby50czo1NzQKCS8vIHRoaXMudmFsaWRhdG9yTGlzdCh2YWxpZGF0b3JJZCkudmFsdWUucG9vbHNbbnVtUG9vbHMgLSAxXS5wb29sQXBwSWQgPSBwb29sQXBwSWQKCWludCAyMzQgLy8gaGVhZE9mZnNldAoJZnJhbWVfZGlnIDAgLy8gbnVtUG9vbHM6IHVpbnQ2NAoJaW50IDEKCS0KCWludCAxOAoJKiAvLyBhY2MgKiB0eXBlTGVuZ3RoCgkrCglpbnQgMAoJKwoJZnJhbWVfZGlnIDEgLy8gcG9vbEFwcElkOiB1aW50NjQKCWl0b2IKCWJ5dGUgMHg3NiAvLyAidiIKCWZyYW1lX2RpZyAtMiAvLyB2YWxpZGF0b3JJZDogVmFsaWRhdG9ySWRUeXBlCglpdG9iCgljb25jYXQKCWNvdmVyIDIKCWJveF9yZXBsYWNlCgoJLy8gY29udHJhY3RzL3ZhbGlkYXRvclJlZ2lzdHJ5LmFsZ28udHM6NTc1CgkvLyB0aGlzLmFkZFBvb2xUb05vZGUodmFsaWRhdG9ySWQsIHBvb2xBcHBJZCwgbm9kZU51bSkKCWZyYW1lX2RpZyAtMyAvLyBub2RlTnVtOiB1aW50NjQKCWZyYW1lX2RpZyAxIC8vIHBvb2xBcHBJZDogdWludDY0CglmcmFtZV9kaWcgLTIgLy8gdmFsaWRhdG9ySWQ6IFZhbGlkYXRvcklkVHlwZQoJY2FsbHN1YiBhZGRQb29sVG9Ob2RlCgoJLy8gY29udHJhY3RzL3ZhbGlkYXRvclJlZ2lzdHJ5LmFsZ28udHM6NTgzCgkvLyByZXR1cm4geyBpZDogdmFsaWRhdG9ySWQsIHBvb2xJZDogbnVtUG9vbHMgYXMgdWludDY0LCBwb29sQXBwSWQ6IHRoaXMuaXR4biEuY3JlYXRlZEFwcGxpY2F0aW9uSUQuaWQgfTsKCWZyYW1lX2RpZyAtMiAvLyB2YWxpZGF0b3JJZDogVmFsaWRhdG9ySWRUeXBlCglpdG9iCglmcmFtZV9kaWcgMCAvLyBudW1Qb29sczogdWludDY0CglpdG9iCgljb25jYXQKCWl0eG4gQ3JlYXRlZEFwcGxpY2F0aW9uSUQKCWl0b2IKCWNvbmNhdAoKCS8vIHNldCB0aGUgc3Vicm91dGluZSByZXR1cm4gdmFsdWUKCWZyYW1lX2J1cnkgMAoKCS8vIHBvcCBhbGwgbG9jYWwgdmFyaWFibGVzIGZyb20gdGhlIHN0YWNrCglwb3BuIDEKCXJldHN1YgoKLy8gYWRkU3Rha2UocGF5LHVpbnQ2NCx1aW50NjQpKHVpbnQ2NCx1aW50NjQsdWludDY0KQoqYWJpX3JvdXRlX2FkZFN0YWtlOgoJLy8gVGhlIEFCSSByZXR1cm4gcHJlZml4CglieXRlIDB4MTUxZjdjNzUKCgkvLyB2YWx1ZVRvVmVyaWZ5OiB1aW50NjQKCXR4bmEgQXBwbGljYXRpb25BcmdzIDIKCWJ0b2kKCgkvLyB2YWxpZGF0b3JJZDogdWludDY0Cgl0eG5hIEFwcGxpY2F0aW9uQXJncyAxCglidG9pCgoJLy8gc3Rha2VkQW1vdW50UGF5bWVudDogcGF5Cgl0eG4gR3JvdXBJbmRleAoJaW50IDEKCS0KCWR1cAoJZ3R4bnMgVHlwZUVudW0KCWludCBwYXkKCT09Cglhc3NlcnQKCgkvLyBleGVjdXRlIGFkZFN0YWtlKHBheSx1aW50NjQsdWludDY0KSh1aW50NjQsdWludDY0LHVpbnQ2NCkKCWNhbGxzdWIgYWRkU3Rha2UKCWNvbmNhdAoJbG9nCglpbnQgMQoJcmV0dXJuCgovLyBhZGRTdGFrZShzdGFrZWRBbW91bnRQYXltZW50OiBQYXlUeG4sIHZhbGlkYXRvcklkOiBWYWxpZGF0b3JJZFR5cGUsIHZhbHVlVG9WZXJpZnk6IHVpbnQ2NCk6IFZhbGlkYXRvclBvb2xLZXkKLy8KLy8gQWRkcyBzdGFrZSB0byBhIHZhbGlkYXRvciBwb29sLgovLwovLyBAcGFyYW0ge1BheVR4bn0gc3Rha2VkQW1vdW50UGF5bWVudCAtIHBheW1lbnQgY29taW5nIGZyb20gc3Rha2VyIHRvIHBsYWNlIGludG8gYSBwb29sCi8vIEBwYXJhbSB7VmFsaWRhdG9ySWRUeXBlfSB2YWxpZGF0b3JJZCAtIFRoZSBpZCBvZiB0aGUgdmFsaWRhdG9yLgovLyBAcGFyYW0ge3VpbnQ2NH0gdmFsdWVUb1ZlcmlmeSAtIG9ubHkgaWYgdmFsaWRhdG9yIGhhcyBnYXRpbmcgdG8gZW50ZXIgLSB0aGlzIGlzIGFzc2V0IGlkIG9yIG5mZCBpZCB0aGF0IGNvcnJlc3BvbmRzIHRvIGdhdGluZy4KLy8gVHhuIHNlbmRlciBpcyBmYWN0b3JlZCBpbiBhcyB3ZWxsIGlmIHRoYXQgaXMgcGFydCBvZiBnYXRpbmcuCi8vICogQHJldHVybnMge1ZhbGlkYXRvclBvb2xLZXl9IC0gVGhlIGtleSBvZiB0aGUgdmFsaWRhdG9yIHBvb2wuCmFkZFN0YWtlOgoJcHJvdG8gMyAxCgoJLy8gUHVzaCBlbXB0eSBieXRlcyBhZnRlciB0aGUgZnJhbWUgcG9pbnRlciB0byByZXNlcnZlIHNwYWNlIGZvciBsb2NhbCB2YXJpYWJsZXMKCWJ5dGUgMHgKCWR1cG4gNQoKCS8vIGNvbnRyYWN0cy92YWxpZGF0b3JSZWdpc3RyeS5hbGdvLnRzOjU5NgoJLy8gYXNzZXJ0KHRoaXMudmFsaWRhdG9yTGlzdCh2YWxpZGF0b3JJZCkuZXhpc3RzKQoJYnl0ZSAweDc2IC8vICJ2IgoJZnJhbWVfZGlnIC0yIC8vIHZhbGlkYXRvcklkOiBWYWxpZGF0b3JJZFR5cGUKCWl0b2IKCWNvbmNhdAoJYm94X2xlbgoJc3dhcAoJcG9wCglhc3NlcnQKCgkvLyBjb250cmFjdHMvdmFsaWRhdG9yUmVnaXN0cnkuYWxnby50czo1OTgKCS8vIHN0YWtlciA9IHRoaXMudHhuLnNlbmRlcgoJdHhuIFNlbmRlcgoJZnJhbWVfYnVyeSAwIC8vIHN0YWtlcjogYWRkcmVzcwoKCS8vIGNvbnRyYWN0cy92YWxpZGF0b3JSZWdpc3RyeS5hbGdvLnRzOjYwMgoJLy8gdmVyaWZ5UGF5VHhuKHN0YWtlZEFtb3VudFBheW1lbnQsIHsKCS8vICAgICAgICAgICAgIHNlbmRlcjogc3Rha2VyLAoJLy8gICAgICAgICAgICAgcmVjZWl2ZXI6IHRoaXMuYXBwLmFkZHJlc3MsCgkvLyAgICAgICAgIH0pCgkvLyB2ZXJpZnkgc2VuZGVyCglmcmFtZV9kaWcgLTEgLy8gc3Rha2VkQW1vdW50UGF5bWVudDogUGF5VHhuCglndHhucyBTZW5kZXIKCWZyYW1lX2RpZyAwIC8vIHN0YWtlcjogYWRkcmVzcwoJPT0KCWFzc2VydAoKCS8vIHZlcmlmeSByZWNlaXZlcgoJZnJhbWVfZGlnIC0xIC8vIHN0YWtlZEFtb3VudFBheW1lbnQ6IFBheVR4bgoJZ3R4bnMgUmVjZWl2ZXIKCWdsb2JhbCBDdXJyZW50QXBwbGljYXRpb25BZGRyZXNzCgk9PQoJYXNzZXJ0CgoJLy8gY29udHJhY3RzL3ZhbGlkYXRvclJlZ2lzdHJ5LmFsZ28udHM6NjA5CgkvLyBhc3NlcnQoCgkvLyAgICAgICAgICAgICB0aGlzLnZhbGlkYXRvckxpc3QodmFsaWRhdG9ySWQpLnZhbHVlLnN0YXRlLnRvdGFsQWxnb1N0YWtlZCA8IHRoaXMubWF4QWxsb3dlZFN0YWtlKCksCgkvLyAgICAgICAgICAgICAndG90YWwgc3Rha2VkIGZvciBhbGwgb2YgYSB2YWxpZGF0b3JzIHBvb2xzIG1heSBub3QgZXhjZWVkIGhhcmQgY2FwJwoJLy8gICAgICAgICApCglpbnQgMjE4CglpbnQgOAoJYnl0ZSAweDc2IC8vICJ2IgoJZnJhbWVfZGlnIC0yIC8vIHZhbGlkYXRvcklkOiBWYWxpZGF0b3JJZFR5cGUKCWl0b2IKCWNvbmNhdAoJY292ZXIgMgoJYm94X2V4dHJhY3QKCWJ0b2kKCWNhbGxzdWIgbWF4QWxsb3dlZFN0YWtlCgk8CgoJLy8gdG90YWwgc3Rha2VkIGZvciBhbGwgb2YgYSB2YWxpZGF0b3JzIHBvb2xzIG1heSBub3QgZXhjZWVkIGhhcmQgY2FwCglhc3NlcnQKCgkvLyBjb250cmFjdHMvdmFsaWRhdG9yUmVnaXN0cnkuYWxnby50czo2MTYKCS8vIHRoaXMuZG9lc1N0YWtlck1lZXRHYXRpbmcodmFsaWRhdG9ySWQsIHZhbHVlVG9WZXJpZnkpCglmcmFtZV9kaWcgLTMgLy8gdmFsdWVUb1ZlcmlmeTogdWludDY0CglmcmFtZV9kaWcgLTIgLy8gdmFsaWRhdG9ySWQ6IFZhbGlkYXRvcklkVHlwZQoJY2FsbHN1YiBkb2VzU3Rha2VyTWVldEdhdGluZwoKCS8vIGNvbnRyYWN0cy92YWxpZGF0b3JSZWdpc3RyeS5hbGdvLnRzOjYxOAoJLy8gcmVhbEFtb3VudCA9IHN0YWtlZEFtb3VudFBheW1lbnQuYW1vdW50CglmcmFtZV9kaWcgLTEgLy8gc3Rha2VkQW1vdW50UGF5bWVudDogUGF5VHhuCglndHhucyBBbW91bnQKCWZyYW1lX2J1cnkgMSAvLyByZWFsQW1vdW50OiB1aW50NjQKCgkvLyBjb250cmFjdHMvdmFsaWRhdG9yUmVnaXN0cnkuYWxnby50czo2MTkKCS8vIG1ickFtdExlZnRCZWhpbmQ6IHVpbnQ2NCA9IDAKCWludCAwCglmcmFtZV9idXJ5IDIgLy8gbWJyQW10TGVmdEJlaGluZDogdWludDY0CgoJLy8gKmlmOV9jb25kaXRpb24KCS8vIGNvbnRyYWN0cy92YWxpZGF0b3JSZWdpc3RyeS5hbGdvLnRzOjYyMQoJLy8gIXRoaXMuc3Rha2VyUG9vbFNldChzdGFrZXIpLmV4aXN0cwoJYnl0ZSAweDczNzA3MyAvLyAic3BzIgoJZnJhbWVfZGlnIDAgLy8gc3Rha2VyOiBhZGRyZXNzCgljb25jYXQKCWJveF9sZW4KCXN3YXAKCXBvcAoJIQoJYnogKmlmOV9lbmQKCgkvLyAqaWY5X2NvbnNlcXVlbnQKCS8vIGNvbnRyYWN0cy92YWxpZGF0b3JSZWdpc3RyeS5hbGdvLnRzOjYyNAoJLy8gbWJyQW10TGVmdEJlaGluZCA9IHRoaXMuZ2V0TWJyQW1vdW50cygpLmFkZFN0YWtlck1icgoJY2FsbHN1YiBnZXRNYnJBbW91bnRzCglleHRyYWN0IDI0IDgKCWJ0b2kKCWZyYW1lX2J1cnkgMiAvLyBtYnJBbXRMZWZ0QmVoaW5kOiB1aW50NjQKCgkvLyBjb250cmFjdHMvdmFsaWRhdG9yUmVnaXN0cnkuYWxnby50czo2MjUKCS8vIHJlYWxBbW91bnQgLT0gbWJyQW10TGVmdEJlaGluZAoJZnJhbWVfZGlnIDEgLy8gcmVhbEFtb3VudDogdWludDY0CglmcmFtZV9kaWcgMiAvLyBtYnJBbXRMZWZ0QmVoaW5kOiB1aW50NjQKCS0KCWZyYW1lX2J1cnkgMSAvLyByZWFsQW1vdW50OiB1aW50NjQKCgkvLyBjb250cmFjdHMvdmFsaWRhdG9yUmVnaXN0cnkuYWxnby50czo2MjYKCS8vIHRoaXMuc3Rha2VyUG9vbFNldChzdGFrZXIpLmNyZWF0ZSgpCglieXRlIDB4NzM3MDczIC8vICJzcHMiCglmcmFtZV9kaWcgMCAvLyBzdGFrZXI6IGFkZHJlc3MKCWNvbmNhdAoJaW50IDE0NAoJYm94X2NyZWF0ZQoJcG9wCgoqaWY5X2VuZDoKCS8vIGNvbnRyYWN0cy92YWxpZGF0b3JSZWdpc3RyeS5hbGdvLnRzOjYzMAoJLy8gZmluZFJldCA9IHRoaXMuZmluZFBvb2xGb3JTdGFrZXIodmFsaWRhdG9ySWQsIHN0YWtlciwgcmVhbEFtb3VudCkKCWZyYW1lX2RpZyAxIC8vIHJlYWxBbW91bnQ6IHVpbnQ2NAoJZnJhbWVfZGlnIDAgLy8gc3Rha2VyOiBhZGRyZXNzCglmcmFtZV9kaWcgLTIgLy8gdmFsaWRhdG9ySWQ6IFZhbGlkYXRvcklkVHlwZQoJY2FsbHN1YiBmaW5kUG9vbEZvclN0YWtlcgoJZnJhbWVfYnVyeSAzIC8vIGZpbmRSZXQ6ICgodWludDY0LHVpbnQ2NCx1aW50NjQpLGJvb2wsYm9vbCkKCgkvLyBjb250cmFjdHMvdmFsaWRhdG9yUmVnaXN0cnkuYWxnby50czo2MzEKCS8vIHBvb2xLZXkgPSBmaW5kUmV0WzBdCgkvLyBjb250cmFjdHMvdmFsaWRhdG9yUmVnaXN0cnkuYWxnby50czo2MzIKCS8vIGlzTmV3U3Rha2VyVG9WYWxpZGF0b3IgPSBmaW5kUmV0WzFdCglmcmFtZV9kaWcgMyAvLyBmaW5kUmV0OiAoKHVpbnQ2NCx1aW50NjQsdWludDY0KSxib29sLGJvb2wpCglzdG9yZSAyNTUgLy8gZnVsbCBhcnJheQoJbG9hZCAyNTUgLy8gZnVsbCBhcnJheQoJaW50IDE5MgoJZ2V0Yml0CglmcmFtZV9idXJ5IDQgLy8gaXNOZXdTdGFrZXJUb1ZhbGlkYXRvcjogYm9vbAoKCS8vIGNvbnRyYWN0cy92YWxpZGF0b3JSZWdpc3RyeS5hbGdvLnRzOjYzMwoJLy8gaXNOZXdTdGFrZXJUb1Byb3RvY29sID0gZmluZFJldFsyXQoJZnJhbWVfZGlnIDMgLy8gZmluZFJldDogKCh1aW50NjQsdWludDY0LHVpbnQ2NCksYm9vbCxib29sKQoJc3RvcmUgMjU1IC8vIGZ1bGwgYXJyYXkKCWxvYWQgMjU1IC8vIGZ1bGwgYXJyYXkKCWludCAxOTMKCWdldGJpdAoJZnJhbWVfYnVyeSA1IC8vIGlzTmV3U3Rha2VyVG9Qcm90b2NvbDogYm9vbAoKCS8vICppZjEwX2NvbmRpdGlvbgoJLy8gY29udHJhY3RzL3ZhbGlkYXRvclJlZ2lzdHJ5LmFsZ28udHM6NjM0CgkvLyBwb29sS2V5LnBvb2xJZCA9PT0gMAoJZnJhbWVfZGlnIDMgLy8gZmluZFJldDogKCh1aW50NjQsdWludDY0LHVpbnQ2NCksYm9vbCxib29sKQoJc3RvcmUgMjU1IC8vIGZ1bGwgYXJyYXkKCWxvYWQgMjU1IC8vIGZ1bGwgYXJyYXkKCWV4dHJhY3QgOCA4CglidG9pCglpbnQgMAoJPT0KCWJ6ICppZjEwX2VuZAoKCS8vICppZjEwX2NvbnNlcXVlbnQKCWVyciAvLyAnTm8gcG9vbCBhdmFpbGFibGUgd2l0aCBmcmVlIHN0YWtlLiAgVmFsaWRhdG9yIG5lZWRzIHRvIGFkZCBhbm90aGVyIHBvb2wnCgoqaWYxMF9lbmQ6CgkvLyBjb250cmFjdHMvdmFsaWRhdG9yUmVnaXN0cnkuYWxnby50czo2MzkKCS8vIHRoaXMudXBkYXRlU3Rha2VyUG9vbFNldChzdGFrZXIsIHBvb2xLZXkpCglmcmFtZV9kaWcgMyAvLyBmaW5kUmV0OiAoKHVpbnQ2NCx1aW50NjQsdWludDY0KSxib29sLGJvb2wpCglzdG9yZSAyNTUgLy8gZnVsbCBhcnJheQoJbG9hZCAyNTUgLy8gZnVsbCBhcnJheQoJZXh0cmFjdCAwIDI0CglmcmFtZV9kaWcgMCAvLyBzdGFrZXI6IGFkZHJlc3MKCWNhbGxzdWIgdXBkYXRlU3Rha2VyUG9vbFNldAoKCS8vIGNvbnRyYWN0cy92YWxpZGF0b3JSZWdpc3RyeS5hbGdvLnRzOjY0MgoJLy8gdGhpcy5jYWxsUG9vbEFkZFN0YWtlKAoJLy8gICAgICAgICAgICAgc3Rha2VkQW1vdW50UGF5bWVudCwKCS8vICAgICAgICAgICAgIHBvb2xLZXksCgkvLyAgICAgICAgICAgICBtYnJBbXRMZWZ0QmVoaW5kLAoJLy8gICAgICAgICAgICAgaXNOZXdTdGFrZXJUb1ZhbGlkYXRvciwKCS8vICAgICAgICAgICAgIGlzTmV3U3Rha2VyVG9Qcm90b2NvbAoJLy8gICAgICAgICApCglmcmFtZV9kaWcgNSAvLyBpc05ld1N0YWtlclRvUHJvdG9jb2w6IGJvb2wKCWZyYW1lX2RpZyA0IC8vIGlzTmV3U3Rha2VyVG9WYWxpZGF0b3I6IGJvb2wKCWZyYW1lX2RpZyAyIC8vIG1ickFtdExlZnRCZWhpbmQ6IHVpbnQ2NAoJZnJhbWVfZGlnIDMgLy8gZmluZFJldDogKCh1aW50NjQsdWludDY0LHVpbnQ2NCksYm9vbCxib29sKQoJc3RvcmUgMjU1IC8vIGZ1bGwgYXJyYXkKCWxvYWQgMjU1IC8vIGZ1bGwgYXJyYXkKCWV4dHJhY3QgMCAyNAoJZnJhbWVfZGlnIC0xIC8vIHN0YWtlZEFtb3VudFBheW1lbnQ6IFBheVR4bgoJY2FsbHN1YiBjYWxsUG9vbEFkZFN0YWtlCgoJLy8gY29udHJhY3RzL3ZhbGlkYXRvclJlZ2lzdHJ5LmFsZ28udHM6NjU3CgkvLyByZXR1cm4gcG9vbEtleTsKCWZyYW1lX2RpZyAzIC8vIGZpbmRSZXQ6ICgodWludDY0LHVpbnQ2NCx1aW50NjQpLGJvb2wsYm9vbCkKCXN0b3JlIDI1NSAvLyBmdWxsIGFycmF5Cglsb2FkIDI1NSAvLyBmdWxsIGFycmF5CglleHRyYWN0IDAgMjQKCgkvLyBzZXQgdGhlIHN1YnJvdXRpbmUgcmV0dXJuIHZhbHVlCglmcmFtZV9idXJ5IDAKCgkvLyBwb3AgYWxsIGxvY2FsIHZhcmlhYmxlcyBmcm9tIHRoZSBzdGFjawoJcG9wbiA1CglyZXRzdWIKCi8vIHNldFRva2VuUGF5b3V0UmF0aW8odWludDY0KSh1aW50NjRbMjRdLHVpbnQ2NCkKKmFiaV9yb3V0ZV9zZXRUb2tlblBheW91dFJhdGlvOgoJLy8gVGhlIEFCSSByZXR1cm4gcHJlZml4CglieXRlIDB4MTUxZjdjNzUKCgkvLyB2YWxpZGF0b3JJZDogdWludDY0Cgl0eG5hIEFwcGxpY2F0aW9uQXJncyAxCglidG9pCgoJLy8gZXhlY3V0ZSBzZXRUb2tlblBheW91dFJhdGlvKHVpbnQ2NCkodWludDY0WzI0XSx1aW50NjQpCgljYWxsc3ViIHNldFRva2VuUGF5b3V0UmF0aW8KCWNvbmNhdAoJbG9nCglpbnQgMQoJcmV0dXJuCgovLyBzZXRUb2tlblBheW91dFJhdGlvKHZhbGlkYXRvcklkOiBWYWxpZGF0b3JJZFR5cGUpOiBQb29sVG9rZW5QYXlvdXRSYXRpbwovLwovLyBzZXRUb2tlblBheW91dFJhdGlvIGlzIGNhbGxlZCBieSBTdGFraW5nIFBvb2wgIyAxIChPTkxZKSB0byBhc2sgdGhlIHZhbGlkYXRvciAodXMpIHRvIGNhbGN1bGF0ZSB0aGUgcmF0aW9zCi8vIG9mIHN0YWtlIGluIHRoZSBwb29scyBmb3Igc3Vic2VxdWVudCB0b2tlbiBwYXlvdXRzIChpZTogMiBwb29scywgJzEwMCcgYWxnbyB0b3RhbCBzdGFrZWQsIDYwIGluIHBvb2wgMSwgYW5kIDQwCi8vIGluIHBvb2wgMi4gIFRoaXMgaXMgZG9uZSBzbyB3ZSBoYXZlIGEgc3RhYmxlIHNuYXBzaG90IG9mIHN0YWtlIC0gdGFrZW4gb25jZSBwZXIgZXBvY2ggLSBvbmx5IHRyaWdnZXJlZCBieQovLyBwb29sIDEgZG9pbmcgcGF5b3V0LiAgcG9vbHMgb3RoZXIgdGhhbiAxIGRvaW5nIHBheW91dCBjYWxsIHBvb2wgMSB0byBhc2sgaXQgZG8gaXQgZmlyc3QuCi8vIEl0IHdvdWxkIGJlIDYwLzQwJSBpbiB0aGUgcG9vbFBjdE9mV2hvbGUgdmFsdWVzLiAgVGhlIHRva2VuIHJld2FyZCBwYXlvdXRzIHRoZW4gdXNlIHRoZXNlIHZhbHVlcyBpbnN0ZWFkIG9mCi8vIHRoZWlyICdjdXJyZW50JyBzdGFrZSB3aGljaCBjaGFuZ2VzIGFzIHBhcnQgb2YgdGhlIHBheW91dHMgdGhlbXNlbHZlcyAoYW5kIHBlb3BsZSBjb3VsZCBiZSBjaGFuZ2luZyBzdGFrZQovLyBkdXJpbmcgdGhlIGVwb2NoIHVwZGF0ZXMgYWNyb3NzIHBvb2xzKQovLwovLyBNdWx0aXBsZSBwb29scyB3aWxsIGNhbGwgdXMgdmlhIHBvb2wgMSAocG9vbDItPnBvb2wxLT52YWxkaWF0b3IsIGV0Yy4pIHNvIGRvbid0IGFzc2VydCBvbiBwb29sMSBjYWxsaW5nIG11bHRpcGxlCi8vIHRpbWVzIGluIHNhbWUgZXBvY2guICBKdXN0IHJldHVybi4KLy8KLy8gQHBhcmFtIHZhbGlkYXRvcklkIC0gdmFsaWRhdG9yIGlkIChhbmQgdGh1cyBwb29sKSBjYWxsaW5nIHVzLiAgVmVyaWZpZWQgc28gdGhhdCBzZW5kZXIgTVVTVCBiZSBwb29sIDEgb2YgdGhpcyB2YWxpZGF0b3IuCi8vIEByZXR1cm5zIFBvb2xUb2tlblBheW91dFJhdGlvIC0gdGhlIGZpbmlzaGVkIHJhdGlvIGRhdGEKc2V0VG9rZW5QYXlvdXRSYXRpbzoKCXByb3RvIDEgMQoKCS8vIFB1c2ggZW1wdHkgYnl0ZXMgYWZ0ZXIgdGhlIGZyYW1lIHBvaW50ZXIgdG8gcmVzZXJ2ZSBzcGFjZSBmb3IgbG9jYWwgdmFyaWFibGVzCglieXRlIDB4CglkdXBuIDgKCgkvLyBjb250cmFjdHMvdmFsaWRhdG9yUmVnaXN0cnkuYWxnby50czo2NzcKCS8vIHBvb2wxQXBwSUQgPSB0aGlzLnZhbGlkYXRvckxpc3QodmFsaWRhdG9ySWQpLnZhbHVlLnBvb2xzWzBdLnBvb2xBcHBJZAoJaW50IDIzNAoJaW50IDgKCWJ5dGUgMHg3NiAvLyAidiIKCWZyYW1lX2RpZyAtMSAvLyB2YWxpZGF0b3JJZDogVmFsaWRhdG9ySWRUeXBlCglpdG9iCgljb25jYXQKCWNvdmVyIDIKCWJveF9leHRyYWN0CglidG9pCglmcmFtZV9idXJ5IDAgLy8gcG9vbDFBcHBJRDogdWludDY0CgoJLy8gY29udHJhY3RzL3ZhbGlkYXRvclJlZ2lzdHJ5LmFsZ28udHM6Njc4CgkvLyBhc3NlcnQocG9vbDFBcHBJRCAhPT0gMCkKCWZyYW1lX2RpZyAwIC8vIHBvb2wxQXBwSUQ6IHVpbnQ2NAoJaW50IDAKCSE9Cglhc3NlcnQKCgkvLyAqaWYxMV9jb25kaXRpb24KCS8vIGNvbnRyYWN0cy92YWxpZGF0b3JSZWdpc3RyeS5hbGdvLnRzOjY4MAoJLy8gdGhpcy50eG4uc2VuZGVyICE9PSBBcHBJRC5mcm9tVWludDY0KHBvb2wxQXBwSUQpLmFkZHJlc3MKCXR4biBTZW5kZXIKCWZyYW1lX2RpZyAwIC8vIHBvb2wxQXBwSUQ6IHVpbnQ2NAoJYXBwX3BhcmFtc19nZXQgQXBwQWRkcmVzcwoJcG9wCgkhPQoJYnogKmlmMTFfZW5kCgoJLy8gKmlmMTFfY29uc2VxdWVudAoJLy8gY29udHJhY3RzL3ZhbGlkYXRvclJlZ2lzdHJ5LmFsZ28udHM6NjgxCgkvLyByZXR1cm4gdGhpcy52YWxpZGF0b3JMaXN0KHZhbGlkYXRvcklkKS52YWx1ZS50b2tlblBheW91dFJhdGlvOwoJaW50IDY2NiAvLyBoZWFkT2Zmc2V0CglpbnQgMjAwCglieXRlIDB4NzYgLy8gInYiCglmcmFtZV9kaWcgLTEgLy8gdmFsaWRhdG9ySWQ6IFZhbGlkYXRvcklkVHlwZQoJaXRvYgoJY29uY2F0Cgljb3ZlciAyCglib3hfZXh0cmFjdAoKCS8vIHNldCB0aGUgc3Vicm91dGluZSByZXR1cm4gdmFsdWUKCWZyYW1lX2J1cnkgMAoJcmV0c3ViCgoqaWYxMV9lbmQ6CgkvLyBjb250cmFjdHMvdmFsaWRhdG9yUmVnaXN0cnkuYWxnby50czo2ODYKCS8vIGN1clRpbWUgPSBnbG9iYWxzLmxhdGVzdFRpbWVzdGFtcAoJZ2xvYmFsIExhdGVzdFRpbWVzdGFtcAoJZnJhbWVfYnVyeSAxIC8vIGN1clRpbWU6IHVpbnQ2NAoKCS8vIGNvbnRyYWN0cy92YWxpZGF0b3JSZWdpc3RyeS5hbGdvLnRzOjY4NwoJLy8gbGFzdFBheW91dFVwZGF0ZSA9IHRoaXMudmFsaWRhdG9yTGlzdCh2YWxpZGF0b3JJZCkudmFsdWUudG9rZW5QYXlvdXRSYXRpby51cGRhdGVkRm9yUGF5b3V0CglpbnQgODU4CglpbnQgOAoJYnl0ZSAweDc2IC8vICJ2IgoJZnJhbWVfZGlnIC0xIC8vIHZhbGlkYXRvcklkOiBWYWxpZGF0b3JJZFR5cGUKCWl0b2IKCWNvbmNhdAoJY292ZXIgMgoJYm94X2V4dHJhY3QKCWJ0b2kKCWZyYW1lX2J1cnkgMiAvLyBsYXN0UGF5b3V0VXBkYXRlOiB1aW50NjQKCgkvLyAqaWYxMl9jb25kaXRpb24KCS8vIGNvbnRyYWN0cy92YWxpZGF0b3JSZWdpc3RyeS5hbGdvLnRzOjY4OAoJLy8gbGFzdFBheW91dFVwZGF0ZSAhPT0gMAoJZnJhbWVfZGlnIDIgLy8gbGFzdFBheW91dFVwZGF0ZTogdWludDY0CglpbnQgMAoJIT0KCWJ6ICppZjEyX2VuZAoKCS8vICppZjEyX2NvbnNlcXVlbnQKCS8vICppZjEzX2NvbmRpdGlvbgoJLy8gY29udHJhY3RzL3ZhbGlkYXRvclJlZ2lzdHJ5LmFsZ28udHM6NjkwCgkvLyAoQXBwSUQuZnJvbVVpbnQ2NChwb29sMUFwcElEKS5nbG9iYWxTdGF0ZSgnbGFzdFBheW91dCcpIGFzIHVpbnQ2NCkgPT09IGxhc3RQYXlvdXRVcGRhdGUKCWZyYW1lX2RpZyAwIC8vIHBvb2wxQXBwSUQ6IHVpbnQ2NAoJYnl0ZSAweDZjNjE3Mzc0NTA2MTc5NmY3NTc0IC8vICJsYXN0UGF5b3V0IgoJYXBwX2dsb2JhbF9nZXRfZXgKCWFzc2VydAoJZnJhbWVfZGlnIDIgLy8gbGFzdFBheW91dFVwZGF0ZTogdWludDY0Cgk9PQoJYnogKmlmMTNfZW5kCgoJLy8gKmlmMTNfY29uc2VxdWVudAoJLy8gY29udHJhY3RzL3ZhbGlkYXRvclJlZ2lzdHJ5LmFsZ28udHM6NjkxCgkvLyByZXR1cm4gdGhpcy52YWxpZGF0b3JMaXN0KHZhbGlkYXRvcklkKS52YWx1ZS50b2tlblBheW91dFJhdGlvOwoJaW50IDY2NiAvLyBoZWFkT2Zmc2V0CglpbnQgMjAwCglieXRlIDB4NzYgLy8gInYiCglmcmFtZV9kaWcgLTEgLy8gdmFsaWRhdG9ySWQ6IFZhbGlkYXRvcklkVHlwZQoJaXRvYgoJY29uY2F0Cgljb3ZlciAyCglib3hfZXh0cmFjdAoKCS8vIHNldCB0aGUgc3Vicm91dGluZSByZXR1cm4gdmFsdWUKCWZyYW1lX2J1cnkgMAoKCS8vIHBvcCBhbGwgbG9jYWwgdmFyaWFibGVzIGZyb20gdGhlIHN0YWNrCglwb3BuIDIKCXJldHN1YgoKKmlmMTNfZW5kOgoJLy8gY29udHJhY3RzL3ZhbGlkYXRvclJlZ2lzdHJ5LmFsZ28udHM6NjkzCgkvLyBzZWNzU2luY2VMYXN0UGF5b3V0ID0gY3VyVGltZSAtIGxhc3RQYXlvdXRVcGRhdGUKCWZyYW1lX2RpZyAxIC8vIGN1clRpbWU6IHVpbnQ2NAoJZnJhbWVfZGlnIDIgLy8gbGFzdFBheW91dFVwZGF0ZTogdWludDY0CgktCglmcmFtZV9idXJ5IDMgLy8gc2Vjc1NpbmNlTGFzdFBheW91dDogdWludDY0CgoJLy8gY29udHJhY3RzL3ZhbGlkYXRvclJlZ2lzdHJ5LmFsZ28udHM6Njk0CgkvLyBlcG9jaEluU2VjcyA9ICh0aGlzLnZhbGlkYXRvckxpc3QodmFsaWRhdG9ySWQpLnZhbHVlLmNvbmZpZy5wYXlvdXRFdmVyeVhNaW5zIGFzIHVpbnQ2NCkgKiA2MAoJaW50IDEzNwoJaW50IDIKCWJ5dGUgMHg3NiAvLyAidiIKCWZyYW1lX2RpZyAtMSAvLyB2YWxpZGF0b3JJZDogVmFsaWRhdG9ySWRUeXBlCglpdG9iCgljb25jYXQKCWNvdmVyIDIKCWJveF9leHRyYWN0CglidG9pCglpbnQgNjAKCSoKCWZyYW1lX2J1cnkgNCAvLyBlcG9jaEluU2VjczogdWludDY0CgoJLy8gKmlmMTRfY29uZGl0aW9uCgkvLyBjb250cmFjdHMvdmFsaWRhdG9yUmVnaXN0cnkuYWxnby50czo2OTYKCS8vIHNlY3NTaW5jZUxhc3RQYXlvdXQgPCBlcG9jaEluU2VjcwoJZnJhbWVfZGlnIDMgLy8gc2Vjc1NpbmNlTGFzdFBheW91dDogdWludDY0CglmcmFtZV9kaWcgNCAvLyBlcG9jaEluU2VjczogdWludDY0Cgk8CglieiAqaWYxNF9lbmQKCgkvLyAqaWYxNF9jb25zZXF1ZW50CgkvLyBjb250cmFjdHMvdmFsaWRhdG9yUmVnaXN0cnkuYWxnby50czo2OTcKCS8vIHJldHVybiB0aGlzLnZhbGlkYXRvckxpc3QodmFsaWRhdG9ySWQpLnZhbHVlLnRva2VuUGF5b3V0UmF0aW87CglpbnQgNjY2IC8vIGhlYWRPZmZzZXQKCWludCAyMDAKCWJ5dGUgMHg3NiAvLyAidiIKCWZyYW1lX2RpZyAtMSAvLyB2YWxpZGF0b3JJZDogVmFsaWRhdG9ySWRUeXBlCglpdG9iCgljb25jYXQKCWNvdmVyIDIKCWJveF9leHRyYWN0CgoJLy8gc2V0IHRoZSBzdWJyb3V0aW5lIHJldHVybiB2YWx1ZQoJZnJhbWVfYnVyeSAwCgoJLy8gcG9wIGFsbCBsb2NhbCB2YXJpYWJsZXMgZnJvbSB0aGUgc3RhY2sKCXBvcG4gNAoJcmV0c3ViCgoqaWYxNF9lbmQ6CgoqaWYxMl9lbmQ6CgkvLyBjb250cmFjdHMvdmFsaWRhdG9yUmVnaXN0cnkuYWxnby50czo3MDAKCS8vIHRoaXMudmFsaWRhdG9yTGlzdCh2YWxpZGF0b3JJZCkudmFsdWUudG9rZW5QYXlvdXRSYXRpby51cGRhdGVkRm9yUGF5b3V0ID0gY3VyVGltZQoJaW50IDg1OAoJZnJhbWVfZGlnIDEgLy8gY3VyVGltZTogdWludDY0CglpdG9iCglieXRlIDB4NzYgLy8gInYiCglmcmFtZV9kaWcgLTEgLy8gdmFsaWRhdG9ySWQ6IFZhbGlkYXRvcklkVHlwZQoJaXRvYgoJY29uY2F0Cgljb3ZlciAyCglib3hfcmVwbGFjZQoKCS8vIGNvbnRyYWN0cy92YWxpZGF0b3JSZWdpc3RyeS5hbGdvLnRzOjcwMgoJLy8gY3VyTnVtUG9vbHMgPSB0aGlzLnZhbGlkYXRvckxpc3QodmFsaWRhdG9ySWQpLnZhbHVlLnN0YXRlLm51bVBvb2xzIGFzIHVpbnQ2NAoJaW50IDIwOAoJaW50IDIKCWJ5dGUgMHg3NiAvLyAidiIKCWZyYW1lX2RpZyAtMSAvLyB2YWxpZGF0b3JJZDogVmFsaWRhdG9ySWRUeXBlCglpdG9iCgljb25jYXQKCWNvdmVyIDIKCWJveF9leHRyYWN0CglidG9pCglmcmFtZV9idXJ5IDUgLy8gY3VyTnVtUG9vbHM6IHVpbnQ2NAoKCS8vIGNvbnRyYWN0cy92YWxpZGF0b3JSZWdpc3RyeS5hbGdvLnRzOjcwMwoJLy8gdG90YWxTdGFrZUZvclZhbGlkYXRvciA9IHRoaXMudmFsaWRhdG9yTGlzdCh2YWxpZGF0b3JJZCkudmFsdWUuc3RhdGUudG90YWxBbGdvU3Rha2VkCglpbnQgMjE4CglpbnQgOAoJYnl0ZSAweDc2IC8vICJ2IgoJZnJhbWVfZGlnIC0xIC8vIHZhbGlkYXRvcklkOiBWYWxpZGF0b3JJZFR5cGUKCWl0b2IKCWNvbmNhdAoJY292ZXIgMgoJYm94X2V4dHJhY3QKCWJ0b2kKCWZyYW1lX2J1cnkgNiAvLyB0b3RhbFN0YWtlRm9yVmFsaWRhdG9yOiB1aW50NjQKCgkvLyBjb250cmFjdHMvdmFsaWRhdG9yUmVnaXN0cnkuYWxnby50czo3MDQKCS8vIGZvciAobGV0IGkgPSAwOyBpIDwgY3VyTnVtUG9vbHM7IGkgKz0gMSkKCWludCAwCglmcmFtZV9idXJ5IDcgLy8gaTogdWludDY0CgoqZm9yXzI6CgkvLyBjb250cmFjdHMvdmFsaWRhdG9yUmVnaXN0cnkuYWxnby50czo3MDQKCS8vIGkgPCBjdXJOdW1Qb29scwoJZnJhbWVfZGlnIDcgLy8gaTogdWludDY0CglmcmFtZV9kaWcgNSAvLyBjdXJOdW1Qb29sczogdWludDY0Cgk8CglieiAqZm9yXzJfZW5kCgoJLy8gY29udHJhY3RzL3ZhbGlkYXRvclJlZ2lzdHJ5LmFsZ28udHM6NzA5CgkvLyBvdXJQb29sUGN0T2ZXaG9sZSA9IHdpZGVSYXRpbygKCS8vICAgICAgICAgICAgICAgICBbdGhpcy52YWxpZGF0b3JMaXN0KHZhbGlkYXRvcklkKS52YWx1ZS5wb29sc1tpXS50b3RhbEFsZ29TdGFrZWQsIDFfMDAwXzAwMF0sCgkvLyAgICAgICAgICAgICAgICAgW3RvdGFsU3Rha2VGb3JWYWxpZGF0b3JdCgkvLyAgICAgICAgICAgICApCglpbnQgMjM0IC8vIGhlYWRPZmZzZXQKCWZyYW1lX2RpZyA3IC8vIGk6IHVpbnQ2NAoJaW50IDE4CgkqIC8vIGFjYyAqIHR5cGVMZW5ndGgKCSsKCWludCAxMCAvLyBoZWFkT2Zmc2V0CgkrCglpbnQgOAoJYnl0ZSAweDc2IC8vICJ2IgoJZnJhbWVfZGlnIC0xIC8vIHZhbGlkYXRvcklkOiBWYWxpZGF0b3JJZFR5cGUKCWl0b2IKCWNvbmNhdAoJY292ZXIgMgoJYm94X2V4dHJhY3QKCWJ0b2kKCWludCAxXzAwMF8wMDAKCW11bHcKCWludCAwCglmcmFtZV9kaWcgNiAvLyB0b3RhbFN0YWtlRm9yVmFsaWRhdG9yOiB1aW50NjQKCWRpdm1vZHcKCXBvcAoJcG9wCglzd2FwCgkhCglhc3NlcnQKCWZyYW1lX2J1cnkgOCAvLyBvdXJQb29sUGN0T2ZXaG9sZTogdWludDY0CgoJLy8gY29udHJhY3RzL3ZhbGlkYXRvclJlZ2lzdHJ5LmFsZ28udHM6NzEzCgkvLyB0aGlzLnZhbGlkYXRvckxpc3QodmFsaWRhdG9ySWQpLnZhbHVlLnRva2VuUGF5b3V0UmF0aW8ucG9vbFBjdE9mV2hvbGVbaV0gPSBvdXJQb29sUGN0T2ZXaG9sZQoJaW50IDY2NgoJZnJhbWVfZGlnIDcgLy8gaTogdWludDY0CglpbnQgOAoJKiAvLyBhY2MgKiB0eXBlTGVuZ3RoCgkrCglmcmFtZV9kaWcgOCAvLyBvdXJQb29sUGN0T2ZXaG9sZTogdWludDY0CglpdG9iCglieXRlIDB4NzYgLy8gInYiCglmcmFtZV9kaWcgLTEgLy8gdmFsaWRhdG9ySWQ6IFZhbGlkYXRvcklkVHlwZQoJaXRvYgoJY29uY2F0Cgljb3ZlciAyCglib3hfcmVwbGFjZQoKKmZvcl8yX2NvbnRpbnVlOgoJLy8gY29udHJhY3RzL3ZhbGlkYXRvclJlZ2lzdHJ5LmFsZ28udHM6NzA0CgkvLyBpICs9IDEKCWZyYW1lX2RpZyA3IC8vIGk6IHVpbnQ2NAoJaW50IDEKCSsKCWZyYW1lX2J1cnkgNyAvLyBpOiB1aW50NjQKCWIgKmZvcl8yCgoqZm9yXzJfZW5kOgoJLy8gY29udHJhY3RzL3ZhbGlkYXRvclJlZ2lzdHJ5LmFsZ28udHM6NzE1CgkvLyByZXR1cm4gdGhpcy52YWxpZGF0b3JMaXN0KHZhbGlkYXRvcklkKS52YWx1ZS50b2tlblBheW91dFJhdGlvOwoJaW50IDY2NiAvLyBoZWFkT2Zmc2V0CglpbnQgMjAwCglieXRlIDB4NzYgLy8gInYiCglmcmFtZV9kaWcgLTEgLy8gdmFsaWRhdG9ySWQ6IFZhbGlkYXRvcklkVHlwZQoJaXRvYgoJY29uY2F0Cgljb3ZlciAyCglib3hfZXh0cmFjdAoKCS8vIHNldCB0aGUgc3Vicm91dGluZSByZXR1cm4gdmFsdWUKCWZyYW1lX2J1cnkgMAoKCS8vIHBvcCBhbGwgbG9jYWwgdmFyaWFibGVzIGZyb20gdGhlIHN0YWNrCglwb3BuIDgKCXJldHN1YgoKLy8gc3Rha2VVcGRhdGVkVmlhUmV3YXJkcygodWludDY0LHVpbnQ2NCx1aW50NjQpLHVpbnQ2NCx1aW50NjQpdm9pZAoqYWJpX3JvdXRlX3N0YWtlVXBkYXRlZFZpYVJld2FyZHM6CgkvLyByZXdhcmRUb2tlbkFtb3VudFJlc2VydmVkOiB1aW50NjQKCXR4bmEgQXBwbGljYXRpb25BcmdzIDMKCWJ0b2kKCgkvLyBhbGdvVG9BZGQ6IHVpbnQ2NAoJdHhuYSBBcHBsaWNhdGlvbkFyZ3MgMgoJYnRvaQoKCS8vIHBvb2xLZXk6ICh1aW50NjQsdWludDY0LHVpbnQ2NCkKCXR4bmEgQXBwbGljYXRpb25BcmdzIDEKCWR1cAoJbGVuCglpbnQgMjQKCT09Cglhc3NlcnQKCgkvLyBleGVjdXRlIHN0YWtlVXBkYXRlZFZpYVJld2FyZHMoKHVpbnQ2NCx1aW50NjQsdWludDY0KSx1aW50NjQsdWludDY0KXZvaWQKCWNhbGxzdWIgc3Rha2VVcGRhdGVkVmlhUmV3YXJkcwoJaW50IDEKCXJldHVybgoKLy8gc3Rha2VVcGRhdGVkVmlhUmV3YXJkcyhwb29sS2V5OiBWYWxpZGF0b3JQb29sS2V5LCBhbGdvVG9BZGQ6IHVpbnQ2NCwgcmV3YXJkVG9rZW5BbW91bnRSZXNlcnZlZDogdWludDY0KTogdm9pZAovLwovLyBzdGFrZVVwZGF0ZWRWaWFSZXdhcmRzIGlzIGNhbGxlZCBieSBTdGFraW5nIHBvb2xzIHRvIGluZm9ybSB0aGUgdmFsaWRhdG9yICh1cykgdGhhdCBhIHBhcnRpY3VsYXIgYW1vdW50IG9mIHRvdGFsCi8vIHN0YWtlIGhhcyBiZWVuIGFkZGVkIHRvIHRoZSBzcGVjaWZpZWQgcG9vbC4gIFRoaXMgaXMgdXNlZCB0byB1cGRhdGUgdGhlIHN0YXRzIHdlIGhhdmUgaW4gb3VyIFBvb2xJbmZvIHN0b3JhZ2UuCi8vIFRoZSBjYWxsaW5nIEFwcCBpZCBpcyB2YWxpZGF0ZWQgYWdhaW5zdCBvdXIgcG9vbCBsaXN0IGFzIHdlbGwuCi8vIEBwYXJhbSB7VmFsaWRhdG9yUG9vbEtleX0gcG9vbEtleSAtIFZhbGlkYXRvclBvb2xLZXkgdHlwZQovLyBAcGFyYW0ge3VpbnQ2NH0gYWxnb1RvQWRkIC0gYW1vdW50IHRoaXMgdmFsaWRhdG9yJ3MgdG90YWwgc3Rha2UgaW5jcmVhc2VkIHZpYSByZXdhcmRzCi8vIEBwYXJhbSB7dWludDY0fSByZXdhcmRUb2tlbkFtb3VudFJlc2VydmVkIC0gYW1vdW50IHRoaXMgdmFsaWRhdG9yJ3MgdG90YWwgc3Rha2UgaW5jcmVhc2VkIHZpYSByZXdhcmRzICh0aGF0IHNob3VsZCBiZQovLyBzZWVuIGFzICdhY2NvdW50ZWQgZm9yL3BlbmRpbmcgc3BlbnQnKQpzdGFrZVVwZGF0ZWRWaWFSZXdhcmRzOgoJcHJvdG8gMyAwCgoJLy8gY29udHJhY3RzL3ZhbGlkYXRvclJlZ2lzdHJ5LmFsZ28udHM6NzI4CgkvLyB0aGlzLnZlcmlmeVBvb2xLZXlDYWxsZXIocG9vbEtleSkKCWZyYW1lX2RpZyAtMSAvLyBwb29sS2V5OiBWYWxpZGF0b3JQb29sS2V5CgljYWxsc3ViIHZlcmlmeVBvb2xLZXlDYWxsZXIKCgkvLyBjb250cmFjdHMvdmFsaWRhdG9yUmVnaXN0cnkuYWxnby50czo3MzEKCS8vIHRoaXMudmFsaWRhdG9yTGlzdChwb29sS2V5LmlkKS52YWx1ZS5wb29sc1twb29sS2V5LnBvb2xJZCAtIDFdLnRvdGFsQWxnb1N0YWtlZCArPSBhbGdvVG9BZGQKCWludCAyMzQgLy8gaGVhZE9mZnNldAoJZnJhbWVfZGlnIC0xIC8vIHBvb2xLZXk6IFZhbGlkYXRvclBvb2xLZXkKCWV4dHJhY3QgOCA4CglidG9pCglpbnQgMQoJLQoJaW50IDE4CgkqIC8vIGFjYyAqIHR5cGVMZW5ndGgKCSsKCWludCAxMCAvLyBoZWFkT2Zmc2V0CgkrCglpbnQgMjM0IC8vIGhlYWRPZmZzZXQKCWZyYW1lX2RpZyAtMSAvLyBwb29sS2V5OiBWYWxpZGF0b3JQb29sS2V5CglleHRyYWN0IDggOAoJYnRvaQoJaW50IDEKCS0KCWludCAxOAoJKiAvLyBhY2MgKiB0eXBlTGVuZ3RoCgkrCglpbnQgMTAgLy8gaGVhZE9mZnNldAoJKwoJaW50IDgKCWJ5dGUgMHg3NiAvLyAidiIKCWZyYW1lX2RpZyAtMSAvLyBwb29sS2V5OiBWYWxpZGF0b3JQb29sS2V5CglleHRyYWN0IDAgOAoJYnRvaQoJaXRvYgoJY29uY2F0Cgljb3ZlciAyCglib3hfZXh0cmFjdAoJYnRvaQoJZnJhbWVfZGlnIC0yIC8vIGFsZ29Ub0FkZDogdWludDY0CgkrCglpdG9iCglieXRlIDB4NzYgLy8gInYiCglmcmFtZV9kaWcgLTEgLy8gcG9vbEtleTogVmFsaWRhdG9yUG9vbEtleQoJZXh0cmFjdCAwIDgKCWJ0b2kKCWl0b2IKCWNvbmNhdAoJY292ZXIgMgoJYm94X3JlcGxhY2UKCgkvLyBjb250cmFjdHMvdmFsaWRhdG9yUmVnaXN0cnkuYWxnby50czo3MzIKCS8vIHRoaXMudmFsaWRhdG9yTGlzdChwb29sS2V5LmlkKS52YWx1ZS5zdGF0ZS50b3RhbEFsZ29TdGFrZWQgKz0gYWxnb1RvQWRkCglpbnQgMjE4CglkdXAKCWludCA4CglieXRlIDB4NzYgLy8gInYiCglmcmFtZV9kaWcgLTEgLy8gcG9vbEtleTogVmFsaWRhdG9yUG9vbEtleQoJZXh0cmFjdCAwIDgKCWJ0b2kKCWl0b2IKCWNvbmNhdAoJY292ZXIgMgoJYm94X2V4dHJhY3QKCWJ0b2kKCWZyYW1lX2RpZyAtMiAvLyBhbGdvVG9BZGQ6IHVpbnQ2NAoJKwoJaXRvYgoJYnl0ZSAweDc2IC8vICJ2IgoJZnJhbWVfZGlnIC0xIC8vIHBvb2xLZXk6IFZhbGlkYXRvclBvb2xLZXkKCWV4dHJhY3QgMCA4CglidG9pCglpdG9iCgljb25jYXQKCWNvdmVyIDIKCWJveF9yZXBsYWNlCgoJLy8gY29udHJhY3RzL3ZhbGlkYXRvclJlZ2lzdHJ5LmFsZ28udHM6NzMzCgkvLyB0aGlzLnZhbGlkYXRvckxpc3QocG9vbEtleS5pZCkudmFsdWUuc3RhdGUucmV3YXJkVG9rZW5IZWxkQmFjayArPSByZXdhcmRUb2tlbkFtb3VudFJlc2VydmVkCglpbnQgMjI2CglkdXAKCWludCA4CglieXRlIDB4NzYgLy8gInYiCglmcmFtZV9kaWcgLTEgLy8gcG9vbEtleTogVmFsaWRhdG9yUG9vbEtleQoJZXh0cmFjdCAwIDgKCWJ0b2kKCWl0b2IKCWNvbmNhdAoJY292ZXIgMgoJYm94X2V4dHJhY3QKCWJ0b2kKCWZyYW1lX2RpZyAtMyAvLyByZXdhcmRUb2tlbkFtb3VudFJlc2VydmVkOiB1aW50NjQKCSsKCWl0b2IKCWJ5dGUgMHg3NiAvLyAidiIKCWZyYW1lX2RpZyAtMSAvLyBwb29sS2V5OiBWYWxpZGF0b3JQb29sS2V5CglleHRyYWN0IDAgOAoJYnRvaQoJaXRvYgoJY29uY2F0Cgljb3ZlciAyCglib3hfcmVwbGFjZQoKCS8vIGNvbnRyYWN0cy92YWxpZGF0b3JSZWdpc3RyeS5hbGdvLnRzOjczNQoJLy8gdGhpcy50b3RhbEFsZ29TdGFrZWQudmFsdWUgKz0gYWxnb1RvQWRkCglieXRlIDB4NzM3NDYxNmI2NTY0IC8vICJzdGFrZWQiCglhcHBfZ2xvYmFsX2dldAoJZnJhbWVfZGlnIC0yIC8vIGFsZ29Ub0FkZDogdWludDY0CgkrCglieXRlIDB4NzM3NDYxNmI2NTY0IC8vICJzdGFrZWQiCglzd2FwCglhcHBfZ2xvYmFsX3B1dAoKCS8vIGNvbnRyYWN0cy92YWxpZGF0b3JSZWdpc3RyeS5hbGdvLnRzOjczOAoJLy8gdGhpcy5yZXZlcmlmeU5GRE93bmVyc2hpcChwb29sS2V5LmlkKQoJZnJhbWVfZGlnIC0xIC8vIHBvb2xLZXk6IFZhbGlkYXRvclBvb2xLZXkKCWV4dHJhY3QgMCA4CglidG9pCgljYWxsc3ViIHJldmVyaWZ5TkZET3duZXJzaGlwCglyZXRzdWIKCi8vIHN0YWtlUmVtb3ZlZCgodWludDY0LHVpbnQ2NCx1aW50NjQpLGFkZHJlc3MsdWludDY0LHVpbnQ2NCxib29sKXZvaWQKKmFiaV9yb3V0ZV9zdGFrZVJlbW92ZWQ6CgkvLyBzdGFrZXJSZW1vdmVkOiBib29sCgl0eG5hIEFwcGxpY2F0aW9uQXJncyA1CglkdXAKCWxlbgoJaW50IDEKCT09Cglhc3NlcnQKCWludCAwCglnZXRiaXQKCgkvLyByZXdhcmRSZW1vdmVkOiB1aW50NjQKCXR4bmEgQXBwbGljYXRpb25BcmdzIDQKCWJ0b2kKCgkvLyBhbW91bnRSZW1vdmVkOiB1aW50NjQKCXR4bmEgQXBwbGljYXRpb25BcmdzIDMKCWJ0b2kKCgkvLyBzdGFrZXI6IGFkZHJlc3MKCXR4bmEgQXBwbGljYXRpb25BcmdzIDIKCWR1cAoJbGVuCglpbnQgMzIKCT09Cglhc3NlcnQKCgkvLyBwb29sS2V5OiAodWludDY0LHVpbnQ2NCx1aW50NjQpCgl0eG5hIEFwcGxpY2F0aW9uQXJncyAxCglkdXAKCWxlbgoJaW50IDI0Cgk9PQoJYXNzZXJ0CgoJLy8gZXhlY3V0ZSBzdGFrZVJlbW92ZWQoKHVpbnQ2NCx1aW50NjQsdWludDY0KSxhZGRyZXNzLHVpbnQ2NCx1aW50NjQsYm9vbCl2b2lkCgljYWxsc3ViIHN0YWtlUmVtb3ZlZAoJaW50IDEKCXJldHVybgoKLy8gc3Rha2VSZW1vdmVkKHBvb2xLZXk6IFZhbGlkYXRvclBvb2xLZXksIHN0YWtlcjogQWRkcmVzcywgYW1vdW50UmVtb3ZlZDogdWludDY0LCByZXdhcmRSZW1vdmVkOiB1aW50NjQsIHN0YWtlclJlbW92ZWQ6IGJvb2xlYW4pOiB2b2lkCi8vCi8vIHN0YWtlUmVtb3ZlZCBpcyBjYWxsZWQgYnkgU3Rha2luZyBwb29scyB0byBpbmZvcm0gdGhlIHZhbGlkYXRvciAodXMpIHRoYXQgYSBwYXJ0aWN1bGFyIGFtb3VudCBvZiB0b3RhbCBzdGFrZSBoYXMgYmVlbiByZW1vdmVkCi8vIGZyb20gdGhlIHNwZWNpZmllZCBwb29sLiAgVGhpcyBpcyB1c2VkIHRvIHVwZGF0ZSB0aGUgc3RhdHMgd2UgaGF2ZSBpbiBvdXIgUG9vbEluZm8gc3RvcmFnZS4KLy8gSWYgYW55IGFtb3VudCBvZiByZXdhcmRSZW1vdmVkIGlzIHNwZWNpZmllZCwgdGhlbiB0aGF0IGFtb3VudCBvZiByZXdhcmQgaXMgc2VudCB0byB0aGUgdXNlCi8vIFRoZSBjYWxsaW5nIEFwcCBpZCBpcyB2YWxpZGF0ZWQgYWdhaW5zdCBvdXIgcG9vbCBsaXN0IGFzIHdlbGwuCi8vCi8vIEBwYXJhbSB7VmFsaWRhdG9yUG9vbEtleX0gcG9vbEtleSBjYWxsaW5nIHVzIGZyb20gd2hpY2ggc3Rha2Ugd2FzIHJlbW92ZWQKLy8gQHBhcmFtIHtBZGRyZXNzfSBzdGFrZXIKLy8gQHBhcmFtIHt1aW50NjR9IGFtb3VudFJlbW92ZWQgLSBhbGdvIGFtb3VudCByZW1vdmVkCi8vIEBwYXJhbSB7dWludDY0fSByZXdhcmRSZW1vdmVkIC0gaWYgYXBwbGljYWJsZSwgYW1vdW50IG9mIHRva2VuIHJld2FyZCByZW1vdmVkIChieSBwb29sIDEgY2FsbGVyKSBvciBUTyByZW1vdmUgYW5kIHBheSBvdXQgKHZpYSBwb29sIDEgZnJvbSBkaWZmZXJlbnQgcG9vbCBjYWxsZXIpCi8vIEBwYXJhbSB7Ym9vbGVhbn0gc3Rha2VyUmVtb3ZlZApzdGFrZVJlbW92ZWQ6Cglwcm90byA1IDAKCgkvLyBQdXNoIGVtcHR5IGJ5dGVzIGFmdGVyIHRoZSBmcmFtZSBwb2ludGVyIHRvIHJlc2VydmUgc3BhY2UgZm9yIGxvY2FsIHZhcmlhYmxlcwoJYnl0ZSAweAoJZHVwbiAzCgoJLy8gKmlmMTVfY29uZGl0aW9uCgkvLyBjb250cmFjdHMvdmFsaWRhdG9yUmVnaXN0cnkuYWxnby50czo3NjgKCS8vIGdsb2JhbHMub3Bjb2RlQnVkZ2V0IDwgMzAwCglnbG9iYWwgT3Bjb2RlQnVkZ2V0CglpbnQgMzAwCgk8CglieiAqaWYxNV9lbmQKCgkvLyAqaWYxNV9jb25zZXF1ZW50CgkvLyBjb250cmFjdHMvdmFsaWRhdG9yUmVnaXN0cnkuYWxnby50czo3NjkKCS8vIGluY3JlYXNlT3Bjb2RlQnVkZ2V0KCkKCWl0eG5fYmVnaW4KCWludCBhcHBsCglpdHhuX2ZpZWxkIFR5cGVFbnVtCglpbnQgMAoJaXR4bl9maWVsZCBGZWUKCWJ5dGUgYjY0IENvRUIgLy8gI3ByYWdtYSB2ZXJzaW9uIDEwOyBpbnQgMQoJZHVwCglpdHhuX2ZpZWxkIEFwcHJvdmFsUHJvZ3JhbQoJaXR4bl9maWVsZCBDbGVhclN0YXRlUHJvZ3JhbQoJaW50IERlbGV0ZUFwcGxpY2F0aW9uCglpdHhuX2ZpZWxkIE9uQ29tcGxldGlvbgoJaXR4bl9zdWJtaXQKCippZjE1X2VuZDoKCS8vIGNvbnRyYWN0cy92YWxpZGF0b3JSZWdpc3RyeS5hbGdvLnRzOjc3MQoJLy8gdGhpcy52ZXJpZnlQb29sS2V5Q2FsbGVyKHBvb2xLZXkpCglmcmFtZV9kaWcgLTEgLy8gcG9vbEtleTogVmFsaWRhdG9yUG9vbEtleQoJY2FsbHN1YiB2ZXJpZnlQb29sS2V5Q2FsbGVyCgoJLy8gY29udHJhY3RzL3ZhbGlkYXRvclJlZ2lzdHJ5LmFsZ28udHM6Nzc1CgkvLyBhc3NlcnQoYW1vdW50UmVtb3ZlZCA+IDAgfHwgcmV3YXJkUmVtb3ZlZCA+IDApCglmcmFtZV9kaWcgLTMgLy8gYW1vdW50UmVtb3ZlZDogdWludDY0CglpbnQgMAoJPgoJZHVwCglibnogKnNraXBfb3IyCglmcmFtZV9kaWcgLTQgLy8gcmV3YXJkUmVtb3ZlZDogdWludDY0CglpbnQgMAoJPgoJfHwKCipza2lwX29yMjoKCWFzc2VydAoKCS8vIGNvbnRyYWN0cy92YWxpZGF0b3JSZWdpc3RyeS5hbGdvLnRzOjc3OAoJLy8gdGhpcy52YWxpZGF0b3JMaXN0KHBvb2xLZXkuaWQpLnZhbHVlLnBvb2xzW3Bvb2xLZXkucG9vbElkIC0gMV0udG90YWxBbGdvU3Rha2VkIC09IGFtb3VudFJlbW92ZWQKCWludCAyMzQgLy8gaGVhZE9mZnNldAoJZnJhbWVfZGlnIC0xIC8vIHBvb2xLZXk6IFZhbGlkYXRvclBvb2xLZXkKCWV4dHJhY3QgOCA4CglidG9pCglpbnQgMQoJLQoJaW50IDE4CgkqIC8vIGFjYyAqIHR5cGVMZW5ndGgKCSsKCWludCAxMCAvLyBoZWFkT2Zmc2V0CgkrCglpbnQgMjM0IC8vIGhlYWRPZmZzZXQKCWZyYW1lX2RpZyAtMSAvLyBwb29sS2V5OiBWYWxpZGF0b3JQb29sS2V5CglleHRyYWN0IDggOAoJYnRvaQoJaW50IDEKCS0KCWludCAxOAoJKiAvLyBhY2MgKiB0eXBlTGVuZ3RoCgkrCglpbnQgMTAgLy8gaGVhZE9mZnNldAoJKwoJaW50IDgKCWJ5dGUgMHg3NiAvLyAidiIKCWZyYW1lX2RpZyAtMSAvLyBwb29sS2V5OiBWYWxpZGF0b3JQb29sS2V5CglleHRyYWN0IDAgOAoJYnRvaQoJaXRvYgoJY29uY2F0Cgljb3ZlciAyCglib3hfZXh0cmFjdAoJYnRvaQoJZnJhbWVfZGlnIC0zIC8vIGFtb3VudFJlbW92ZWQ6IHVpbnQ2NAoJLQoJaXRvYgoJYnl0ZSAweDc2IC8vICJ2IgoJZnJhbWVfZGlnIC0xIC8vIHBvb2xLZXk6IFZhbGlkYXRvclBvb2xLZXkKCWV4dHJhY3QgMCA4CglidG9pCglpdG9iCgljb25jYXQKCWNvdmVyIDIKCWJveF9yZXBsYWNlCgoJLy8gY29udHJhY3RzL3ZhbGlkYXRvclJlZ2lzdHJ5LmFsZ28udHM6Nzc5CgkvLyB0aGlzLnZhbGlkYXRvckxpc3QocG9vbEtleS5pZCkudmFsdWUuc3RhdGUudG90YWxBbGdvU3Rha2VkIC09IGFtb3VudFJlbW92ZWQKCWludCAyMTgKCWR1cAoJaW50IDgKCWJ5dGUgMHg3NiAvLyAidiIKCWZyYW1lX2RpZyAtMSAvLyBwb29sS2V5OiBWYWxpZGF0b3JQb29sS2V5CglleHRyYWN0IDAgOAoJYnRvaQoJaXRvYgoJY29uY2F0Cgljb3ZlciAyCglib3hfZXh0cmFjdAoJYnRvaQoJZnJhbWVfZGlnIC0zIC8vIGFtb3VudFJlbW92ZWQ6IHVpbnQ2NAoJLQoJaXRvYgoJYnl0ZSAweDc2IC8vICJ2IgoJZnJhbWVfZGlnIC0xIC8vIHBvb2xLZXk6IFZhbGlkYXRvclBvb2xLZXkKCWV4dHJhY3QgMCA4CglidG9pCglpdG9iCgljb25jYXQKCWNvdmVyIDIKCWJveF9yZXBsYWNlCgoJLy8gY29udHJhY3RzL3ZhbGlkYXRvclJlZ2lzdHJ5LmFsZ28udHM6NzgwCgkvLyB0aGlzLnRvdGFsQWxnb1N0YWtlZC52YWx1ZSAtPSBhbW91bnRSZW1vdmVkCglieXRlIDB4NzM3NDYxNmI2NTY0IC8vICJzdGFrZWQiCglhcHBfZ2xvYmFsX2dldAoJZnJhbWVfZGlnIC0zIC8vIGFtb3VudFJlbW92ZWQ6IHVpbnQ2NAoJLQoJYnl0ZSAweDczNzQ2MTZiNjU2NCAvLyAic3Rha2VkIgoJc3dhcAoJYXBwX2dsb2JhbF9wdXQKCgkvLyAqaWYxNl9jb25kaXRpb24KCS8vIGNvbnRyYWN0cy92YWxpZGF0b3JSZWdpc3RyeS5hbGdvLnRzOjc4MgoJLy8gcmV3YXJkUmVtb3ZlZCA+IDAKCWZyYW1lX2RpZyAtNCAvLyByZXdhcmRSZW1vdmVkOiB1aW50NjQKCWludCAwCgk+CglieiAqaWYxNl9lbHNlCgoJLy8gKmlmMTZfY29uc2VxdWVudAoJLy8gY29udHJhY3RzL3ZhbGlkYXRvclJlZ2lzdHJ5LmFsZ28udHM6NzgzCgkvLyByZXdhcmRUb2tlbklEID0gdGhpcy52YWxpZGF0b3JMaXN0KHBvb2xLZXkuaWQpLnZhbHVlLmNvbmZpZy5yZXdhcmRUb2tlbklkCglpbnQgMTIxCglpbnQgOAoJYnl0ZSAweDc2IC8vICJ2IgoJZnJhbWVfZGlnIC0xIC8vIHBvb2xLZXk6IFZhbGlkYXRvclBvb2xLZXkKCWV4dHJhY3QgMCA4CglidG9pCglpdG9iCgljb25jYXQKCWNvdmVyIDIKCWJveF9leHRyYWN0CglidG9pCglmcmFtZV9idXJ5IDAgLy8gcmV3YXJkVG9rZW5JRDogdWludDY0CgoJLy8gY29udHJhY3RzL3ZhbGlkYXRvclJlZ2lzdHJ5LmFsZ28udHM6Nzg0CgkvLyBhc3NlcnQocmV3YXJkVG9rZW5JRCAhPT0gMCwgInJld2FyZFJlbW92ZWQgY2FuJ3QgYmUgc2V0IGlmIHZhbGlkYXRvciBkb2Vzbid0IGhhdmUgcmV3YXJkIHRva2VuISIpCglmcmFtZV9kaWcgMCAvLyByZXdhcmRUb2tlbklEOiB1aW50NjQKCWludCAwCgkhPQoKCS8vIHJld2FyZFJlbW92ZWQgY2FuJ3QgYmUgc2V0IGlmIHZhbGlkYXRvciBkb2Vzbid0IGhhdmUgcmV3YXJkIHRva2VuIQoJYXNzZXJ0CgoJLy8gY29udHJhY3RzL3ZhbGlkYXRvclJlZ2lzdHJ5LmFsZ28udHM6Nzg1CgkvLyBhc3NlcnQoCgkvLyAgICAgICAgICAgICAgICAgdGhpcy52YWxpZGF0b3JMaXN0KHBvb2xLZXkuaWQpLnZhbHVlLnN0YXRlLnJld2FyZFRva2VuSGVsZEJhY2sgPj0gcmV3YXJkUmVtb3ZlZCwKCS8vICAgICAgICAgICAgICAgICAncmV3YXJkIGJlaW5nIHJlbW92ZWQgbXVzdCBiZSBjb3ZlcmVkIGJ5IGhvbGQgYmFjayBhbW91bnQnCgkvLyAgICAgICAgICAgICApCglpbnQgMjI2CglpbnQgOAoJYnl0ZSAweDc2IC8vICJ2IgoJZnJhbWVfZGlnIC0xIC8vIHBvb2xLZXk6IFZhbGlkYXRvclBvb2xLZXkKCWV4dHJhY3QgMCA4CglidG9pCglpdG9iCgljb25jYXQKCWNvdmVyIDIKCWJveF9leHRyYWN0CglidG9pCglmcmFtZV9kaWcgLTQgLy8gcmV3YXJkUmVtb3ZlZDogdWludDY0Cgk+PQoKCS8vIHJld2FyZCBiZWluZyByZW1vdmVkIG11c3QgYmUgY292ZXJlZCBieSBob2xkIGJhY2sgYW1vdW50Cglhc3NlcnQKCgkvLyBjb250cmFjdHMvdmFsaWRhdG9yUmVnaXN0cnkuYWxnby50czo3OTEKCS8vIHRoaXMudmFsaWRhdG9yTGlzdChwb29sS2V5LmlkKS52YWx1ZS5zdGF0ZS5yZXdhcmRUb2tlbkhlbGRCYWNrIC09IHJld2FyZFJlbW92ZWQKCWludCAyMjYKCWR1cAoJaW50IDgKCWJ5dGUgMHg3NiAvLyAidiIKCWZyYW1lX2RpZyAtMSAvLyBwb29sS2V5OiBWYWxpZGF0b3JQb29sS2V5CglleHRyYWN0IDAgOAoJYnRvaQoJaXRvYgoJY29uY2F0Cgljb3ZlciAyCglib3hfZXh0cmFjdAoJYnRvaQoJZnJhbWVfZGlnIC00IC8vIHJld2FyZFJlbW92ZWQ6IHVpbnQ2NAoJLQoJaXRvYgoJYnl0ZSAweDc2IC8vICJ2IgoJZnJhbWVfZGlnIC0xIC8vIHBvb2xLZXk6IFZhbGlkYXRvclBvb2xLZXkKCWV4dHJhY3QgMCA4CglidG9pCglpdG9iCgljb25jYXQKCWNvdmVyIDIKCWJveF9yZXBsYWNlCgoJLy8gKmlmMTdfY29uZGl0aW9uCgkvLyBjb250cmFjdHMvdmFsaWRhdG9yUmVnaXN0cnkuYWxnby50czo3OTYKCS8vIHBvb2xLZXkucG9vbElkICE9PSAxCglmcmFtZV9kaWcgLTEgLy8gcG9vbEtleTogVmFsaWRhdG9yUG9vbEtleQoJZXh0cmFjdCA4IDgKCWJ0b2kKCWludCAxCgkhPQoJYnogKmlmMTdfZW5kCgoJLy8gKmlmMTdfY29uc2VxdWVudAoJLy8gY29udHJhY3RzL3ZhbGlkYXRvclJlZ2lzdHJ5LmFsZ28udHM6Nzk3CgkvLyBzZW5kTWV0aG9kQ2FsbDx0eXBlb2YgU3Rha2luZ1Bvb2wucHJvdG90eXBlLnBheVRva2VuUmV3YXJkPih7CgkvLyAgICAgICAgICAgICAgICAgICAgIGFwcGxpY2F0aW9uSUQ6IEFwcElELmZyb21VaW50NjQodGhpcy52YWxpZGF0b3JMaXN0KHBvb2xLZXkuaWQpLnZhbHVlLnBvb2xzWzBdLnBvb2xBcHBJZCksCgkvLyAgICAgICAgICAgICAgICAgICAgIG1ldGhvZEFyZ3M6IFtzdGFrZXIsIHJld2FyZFRva2VuSUQsIHJld2FyZFJlbW92ZWRdLAoJLy8gICAgICAgICAgICAgICAgIH0pCglpdHhuX2JlZ2luCglpbnQgYXBwbAoJaXR4bl9maWVsZCBUeXBlRW51bQoJbWV0aG9kICJwYXlUb2tlblJld2FyZChhZGRyZXNzLHVpbnQ2NCx1aW50NjQpdm9pZCIKCWl0eG5fZmllbGQgQXBwbGljYXRpb25BcmdzCgoJLy8gY29udHJhY3RzL3ZhbGlkYXRvclJlZ2lzdHJ5LmFsZ28udHM6Nzk4CgkvLyBhcHBsaWNhdGlvbklEOiBBcHBJRC5mcm9tVWludDY0KHRoaXMudmFsaWRhdG9yTGlzdChwb29sS2V5LmlkKS52YWx1ZS5wb29sc1swXS5wb29sQXBwSWQpCglpbnQgMjM0CglpbnQgOAoJYnl0ZSAweDc2IC8vICJ2IgoJZnJhbWVfZGlnIC0xIC8vIHBvb2xLZXk6IFZhbGlkYXRvclBvb2xLZXkKCWV4dHJhY3QgMCA4CglidG9pCglpdG9iCgljb25jYXQKCWNvdmVyIDIKCWJveF9leHRyYWN0CglidG9pCglpdHhuX2ZpZWxkIEFwcGxpY2F0aW9uSUQKCgkvLyBjb250cmFjdHMvdmFsaWRhdG9yUmVnaXN0cnkuYWxnby50czo3OTkKCS8vIG1ldGhvZEFyZ3M6IFtzdGFrZXIsIHJld2FyZFRva2VuSUQsIHJld2FyZFJlbW92ZWRdCglmcmFtZV9kaWcgLTIgLy8gc3Rha2VyOiBBZGRyZXNzCglpdHhuX2ZpZWxkIEFwcGxpY2F0aW9uQXJncwoJZnJhbWVfZGlnIDAgLy8gcmV3YXJkVG9rZW5JRDogdWludDY0CglpdG9iCglpdHhuX2ZpZWxkIEFwcGxpY2F0aW9uQXJncwoJZnJhbWVfZGlnIC00IC8vIHJld2FyZFJlbW92ZWQ6IHVpbnQ2NAoJaXRvYgoJaXR4bl9maWVsZCBBcHBsaWNhdGlvbkFyZ3MKCgkvLyBGZWUgZmllbGQgbm90IHNldCwgZGVmYXVsdGluZyB0byAwCglpbnQgMAoJaXR4bl9maWVsZCBGZWUKCgkvLyBTdWJtaXQgaW5uZXIgdHJhbnNhY3Rpb24KCWl0eG5fc3VibWl0CgoqaWYxN19lbmQ6CgliICppZjE2X2VuZAoKKmlmMTZfZWxzZToKCippZjE2X2VuZDoKCS8vICppZjE4X2NvbmRpdGlvbgoJLy8gY29udHJhY3RzL3ZhbGlkYXRvclJlZ2lzdHJ5LmFsZ28udHM6ODI0CgkvLyBzdGFrZXJSZW1vdmVkCglmcmFtZV9kaWcgLTUgLy8gc3Rha2VyUmVtb3ZlZDogYm9vbGVhbgoJYnogKmlmMThfZW5kCgoJLy8gKmlmMThfY29uc2VxdWVudAoJLy8gY29udHJhY3RzL3ZhbGlkYXRvclJlZ2lzdHJ5LmFsZ28udHM6ODI2CgkvLyB0aGlzLnZhbGlkYXRvckxpc3QocG9vbEtleS5pZCkudmFsdWUucG9vbHNbcG9vbEtleS5wb29sSWQgLSAxXS50b3RhbFN0YWtlcnMgLT0gMQoJaW50IDIzNCAvLyBoZWFkT2Zmc2V0CglmcmFtZV9kaWcgLTEgLy8gcG9vbEtleTogVmFsaWRhdG9yUG9vbEtleQoJZXh0cmFjdCA4IDgKCWJ0b2kKCWludCAxCgktCglpbnQgMTgKCSogLy8gYWNjICogdHlwZUxlbmd0aAoJKwoJaW50IDggLy8gaGVhZE9mZnNldAoJKwoJaW50IDIzNCAvLyBoZWFkT2Zmc2V0CglmcmFtZV9kaWcgLTEgLy8gcG9vbEtleTogVmFsaWRhdG9yUG9vbEtleQoJZXh0cmFjdCA4IDgKCWJ0b2kKCWludCAxCgktCglpbnQgMTgKCSogLy8gYWNjICogdHlwZUxlbmd0aAoJKwoJaW50IDggLy8gaGVhZE9mZnNldAoJKwoJaW50IDIKCWJ5dGUgMHg3NiAvLyAidiIKCWZyYW1lX2RpZyAtMSAvLyBwb29sS2V5OiBWYWxpZGF0b3JQb29sS2V5CglleHRyYWN0IDAgOAoJYnRvaQoJaXRvYgoJY29uY2F0Cgljb3ZlciAyCglib3hfZXh0cmFjdAoJYnRvaQoJaW50IDEKCS0KCWl0b2IKCWV4dHJhY3QgNiAyCglieXRlIDB4NzYgLy8gInYiCglmcmFtZV9kaWcgLTEgLy8gcG9vbEtleTogVmFsaWRhdG9yUG9vbEtleQoJZXh0cmFjdCAwIDgKCWJ0b2kKCWl0b2IKCWNvbmNhdAoJY292ZXIgMgoJYm94X3JlcGxhY2UKCgkvLyBjb250cmFjdHMvdmFsaWRhdG9yUmVnaXN0cnkuYWxnby50czo4MjgKCS8vIHJlbW92ZVJldCA9IHRoaXMucmVtb3ZlRnJvbVN0YWtlclBvb2xTZXQoc3Rha2VyLCA8VmFsaWRhdG9yUG9vbEtleT57CgkvLyAgICAgICAgICAgICAgICAgaWQ6IHBvb2xLZXkuaWQsCgkvLyAgICAgICAgICAgICAgICAgcG9vbElkOiBwb29sS2V5LnBvb2xJZCwKCS8vICAgICAgICAgICAgICAgICBwb29sQXBwSWQ6IHBvb2xLZXkucG9vbEFwcElkLAoJLy8gICAgICAgICAgICAgfSkKCWZyYW1lX2RpZyAtMSAvLyBwb29sS2V5OiBWYWxpZGF0b3JQb29sS2V5CglleHRyYWN0IDAgOAoJYnRvaQoJaXRvYgoJZnJhbWVfZGlnIC0xIC8vIHBvb2xLZXk6IFZhbGlkYXRvclBvb2xLZXkKCWV4dHJhY3QgOCA4CglidG9pCglpdG9iCgljb25jYXQKCWZyYW1lX2RpZyAtMSAvLyBwb29sS2V5OiBWYWxpZGF0b3JQb29sS2V5CglleHRyYWN0IDE2IDgKCWJ0b2kKCWl0b2IKCWNvbmNhdAoJZnJhbWVfZGlnIC0yIC8vIHN0YWtlcjogQWRkcmVzcwoJY2FsbHN1YiByZW1vdmVGcm9tU3Rha2VyUG9vbFNldAoJZnJhbWVfYnVyeSAxIC8vIHJlbW92ZVJldDogKGJvb2wsYm9vbCkKCgkvLyBjb250cmFjdHMvdmFsaWRhdG9yUmVnaXN0cnkuYWxnby50czo4MzMKCS8vIHN0YWtlck91dE9mVGhpc1ZhbGlkYXRvciA9IHJlbW92ZVJldFswXQoJZnJhbWVfZGlnIDEgLy8gcmVtb3ZlUmV0OiAoYm9vbCxib29sKQoJc3RvcmUgMjU1IC8vIGZ1bGwgYXJyYXkKCWxvYWQgMjU1IC8vIGZ1bGwgYXJyYXkKCWludCAwCglnZXRiaXQKCWZyYW1lX2J1cnkgMiAvLyBzdGFrZXJPdXRPZlRoaXNWYWxpZGF0b3I6IGJvb2wKCgkvLyBjb250cmFjdHMvdmFsaWRhdG9yUmVnaXN0cnkuYWxnby50czo4MzQKCS8vIHN0YWtlck91dE9mUHJvdG9jb2wgPSByZW1vdmVSZXRbMV0KCWZyYW1lX2RpZyAxIC8vIHJlbW92ZVJldDogKGJvb2wsYm9vbCkKCXN0b3JlIDI1NSAvLyBmdWxsIGFycmF5Cglsb2FkIDI1NSAvLyBmdWxsIGFycmF5CglpbnQgMQoJZ2V0Yml0CglmcmFtZV9idXJ5IDMgLy8gc3Rha2VyT3V0T2ZQcm90b2NvbDogYm9vbAoKCS8vICppZjE5X2NvbmRpdGlvbgoJLy8gY29udHJhY3RzL3ZhbGlkYXRvclJlZ2lzdHJ5LmFsZ28udHM6ODM2CgkvLyBzdGFrZXJPdXRPZlRoaXNWYWxpZGF0b3IKCWZyYW1lX2RpZyAyIC8vIHN0YWtlck91dE9mVGhpc1ZhbGlkYXRvcjogYm9vbAoJYnogKmlmMTlfZW5kCgoJLy8gKmlmMTlfY29uc2VxdWVudAoJLy8gY29udHJhY3RzL3ZhbGlkYXRvclJlZ2lzdHJ5LmFsZ28udHM6ODM3CgkvLyB0aGlzLnZhbGlkYXRvckxpc3QocG9vbEtleS5pZCkudmFsdWUuc3RhdGUudG90YWxTdGFrZXJzIC09IDEKCWludCAyMTAKCWR1cAoJaW50IDgKCWJ5dGUgMHg3NiAvLyAidiIKCWZyYW1lX2RpZyAtMSAvLyBwb29sS2V5OiBWYWxpZGF0b3JQb29sS2V5CglleHRyYWN0IDAgOAoJYnRvaQoJaXRvYgoJY29uY2F0Cgljb3ZlciAyCglib3hfZXh0cmFjdAoJYnRvaQoJaW50IDEKCS0KCWl0b2IKCWJ5dGUgMHg3NiAvLyAidiIKCWZyYW1lX2RpZyAtMSAvLyBwb29sS2V5OiBWYWxpZGF0b3JQb29sS2V5CglleHRyYWN0IDAgOAoJYnRvaQoJaXRvYgoJY29uY2F0Cgljb3ZlciAyCglib3hfcmVwbGFjZQoKKmlmMTlfZW5kOgoJLy8gKmlmMjBfY29uZGl0aW9uCgkvLyBjb250cmFjdHMvdmFsaWRhdG9yUmVnaXN0cnkuYWxnby50czo4NDAKCS8vIHN0YWtlck91dE9mUHJvdG9jb2wKCWZyYW1lX2RpZyAzIC8vIHN0YWtlck91dE9mUHJvdG9jb2w6IGJvb2wKCWJ6ICppZjIwX2VuZAoKCS8vICppZjIwX2NvbnNlcXVlbnQKCS8vIGNvbnRyYWN0cy92YWxpZGF0b3JSZWdpc3RyeS5hbGdvLnRzOjg0MQoJLy8gdGhpcy5udW1TdGFrZXJzLnZhbHVlIC09IDEKCWJ5dGUgMHg2ZTc1NmQ1Mzc0NjE2YjY1NzI3MyAvLyAibnVtU3Rha2VycyIKCWFwcF9nbG9iYWxfZ2V0CglpbnQgMQoJLQoJYnl0ZSAweDZlNzU2ZDUzNzQ2MTZiNjU3MjczIC8vICJudW1TdGFrZXJzIgoJc3dhcAoJYXBwX2dsb2JhbF9wdXQKCippZjIwX2VuZDoKCippZjE4X2VuZDoKCXJldHN1YgoKLy8gZmluZFBvb2xGb3JTdGFrZXIodWludDY0LGFkZHJlc3MsdWludDY0KSgodWludDY0LHVpbnQ2NCx1aW50NjQpLGJvb2wsYm9vbCkKKmFiaV9yb3V0ZV9maW5kUG9vbEZvclN0YWtlcjoKCS8vIFRoZSBBQkkgcmV0dXJuIHByZWZpeAoJYnl0ZSAweDE1MWY3Yzc1CgoJLy8gYW1vdW50VG9TdGFrZTogdWludDY0Cgl0eG5hIEFwcGxpY2F0aW9uQXJncyAzCglidG9pCgoJLy8gc3Rha2VyOiBhZGRyZXNzCgl0eG5hIEFwcGxpY2F0aW9uQXJncyAyCglkdXAKCWxlbgoJaW50IDMyCgk9PQoJYXNzZXJ0CgoJLy8gdmFsaWRhdG9ySWQ6IHVpbnQ2NAoJdHhuYSBBcHBsaWNhdGlvbkFyZ3MgMQoJYnRvaQoKCS8vIGV4ZWN1dGUgZmluZFBvb2xGb3JTdGFrZXIodWludDY0LGFkZHJlc3MsdWludDY0KSgodWludDY0LHVpbnQ2NCx1aW50NjQpLGJvb2wsYm9vbCkKCWNhbGxzdWIgZmluZFBvb2xGb3JTdGFrZXIKCWNvbmNhdAoJbG9nCglpbnQgMQoJcmV0dXJuCgovLyBmaW5kUG9vbEZvclN0YWtlcih2YWxpZGF0b3JJZDogVmFsaWRhdG9ySWRUeXBlLCBzdGFrZXI6IEFkZHJlc3MsIGFtb3VudFRvU3Rha2U6IHVpbnQ2NCk6IFtWYWxpZGF0b3JQb29sS2V5LCBib29sZWFuLCBib29sZWFuXQovLwovLyBGaW5kcyB0aGUgcG9vbCBmb3IgYSBzdGFrZXIgYmFzZWQgb24gdGhlIHByb3ZpZGVkIHZhbGlkYXRvciBpZCwgc3Rha2VyIGFkZHJlc3MsIGFuZCBhbW91bnQgdG8gc3Rha2UuCi8vIEZpcnN0IGNoZWNrcyB0aGUgc3Rha2VycyAnYWxyZWFkeSBzdGFrZWQgbGlzdCcgZm9yIHRoZSB2YWxpZGF0b3IgcHJlZmVycmluZyB0aG9zZSAoYWRkaW5nIGlmIHBvc3NpYmxlKSB0aGVuIGFkZHMKLy8gdG8gbmV3IHBvb2wgaWYgbmVjZXNzYXJ5LgovLwovLyBAcGFyYW0ge1ZhbGlkYXRvcklkVHlwZX0gdmFsaWRhdG9ySWQgLSBUaGUgaWQgb2YgdGhlIHZhbGlkYXRvci4KLy8gQHBhcmFtIHtBZGRyZXNzfSBzdGFrZXIgLSBUaGUgYWRkcmVzcyBvZiB0aGUgc3Rha2VyLgovLyBAcGFyYW0ge3VpbnQ2NH0gYW1vdW50VG9TdGFrZSAtIFRoZSBhbW91bnQgdG8gc3Rha2UuCi8vIEByZXR1cm5zIHtWYWxpZGF0b3JQb29sS2V5LCBib29sZWFuLCBib29sZWFufSAtIFRoZSBwb29sIGZvciB0aGUgc3Rha2VyLCB0cnVlL2ZhbHNlIG9uIHdoZXRoZXIgdGhlIHN0YWtlciBpcyAnbmV3JwovLyB0byB0aGlzIFZBTElEQVRPUiwgYW5kIHRydWUvZmFsc2UgaWYgc3Rha2VyIGlzIG5ldyB0byB0aGUgcHJvdG9jb2wuCmZpbmRQb29sRm9yU3Rha2VyOgoJcHJvdG8gMyAxCgoJLy8gUHVzaCBlbXB0eSBieXRlcyBhZnRlciB0aGUgZnJhbWUgcG9pbnRlciB0byByZXNlcnZlIHNwYWNlIGZvciBsb2NhbCB2YXJpYWJsZXMKCWJ5dGUgMHgKCWR1cG4gNwoKCS8vIGNvbnRyYWN0cy92YWxpZGF0b3JSZWdpc3RyeS5hbGdvLnRzOjg2MgoJLy8gaXNOZXdTdGFrZXJUb1ZhbGlkYXRvciA9IHRydWUKCWludCAxCglmcmFtZV9idXJ5IDAgLy8gaXNOZXdTdGFrZXJUb1ZhbGlkYXRvcjogYm9vbAoKCS8vIGNvbnRyYWN0cy92YWxpZGF0b3JSZWdpc3RyeS5hbGdvLnRzOjg2MwoJLy8gaXNOZXdTdGFrZXJUb1Byb3RvY29sID0gdHJ1ZQoJaW50IDEKCWZyYW1lX2J1cnkgMSAvLyBpc05ld1N0YWtlclRvUHJvdG9jb2w6IGJvb2wKCgkvLyBjb250cmFjdHMvdmFsaWRhdG9yUmVnaXN0cnkuYWxnby50czo4NzEKCS8vIG1heFBlclBvb2wgPSB0aGlzLmdldEN1ck1heFN0YWtlUGVyUG9vbCh2YWxpZGF0b3JJZCkKCWZyYW1lX2RpZyAtMSAvLyB2YWxpZGF0b3JJZDogVmFsaWRhdG9ySWRUeXBlCgljYWxsc3ViIGdldEN1ck1heFN0YWtlUGVyUG9vbAoJZnJhbWVfYnVyeSAyIC8vIG1heFBlclBvb2w6IHVpbnQ2NAoKCS8vICppZjIxX2NvbmRpdGlvbgoJLy8gY29udHJhY3RzL3ZhbGlkYXRvclJlZ2lzdHJ5LmFsZ28udHM6ODc0CgkvLyB0aGlzLnN0YWtlclBvb2xTZXQoc3Rha2VyKS5leGlzdHMKCWJ5dGUgMHg3MzcwNzMgLy8gInNwcyIKCWZyYW1lX2RpZyAtMiAvLyBzdGFrZXI6IEFkZHJlc3MKCWNvbmNhdAoJYm94X2xlbgoJc3dhcAoJcG9wCglieiAqaWYyMV9lbmQKCgkvLyAqaWYyMV9jb25zZXF1ZW50CgkvLyBjb250cmFjdHMvdmFsaWRhdG9yUmVnaXN0cnkuYWxnby50czo4NzUKCS8vIHBvb2xTZXQgPSBjbG9uZSh0aGlzLnN0YWtlclBvb2xTZXQoc3Rha2VyKS52YWx1ZSkKCWJ5dGUgMHg3MzcwNzMgLy8gInNwcyIKCWZyYW1lX2RpZyAtMiAvLyBzdGFrZXI6IEFkZHJlc3MKCWNvbmNhdAoJYm94X2dldAoJYXNzZXJ0CglmcmFtZV9idXJ5IDMgLy8gcG9vbFNldDogKHVpbnQ2NCx1aW50NjQsdWludDY0KVs2XQoKCS8vIGNvbnRyYWN0cy92YWxpZGF0b3JSZWdpc3RyeS5hbGdvLnRzOjg3NgoJLy8gYXNzZXJ0KHZhbGlkYXRvcklkICE9PSAwKQoJZnJhbWVfZGlnIC0xIC8vIHZhbGlkYXRvcklkOiBWYWxpZGF0b3JJZFR5cGUKCWludCAwCgkhPQoJYXNzZXJ0CgoJLy8gY29udHJhY3RzL3ZhbGlkYXRvclJlZ2lzdHJ5LmFsZ28udHM6ODc3CgkvLyBmb3IgKGxldCBpID0gMDsgaSA8IHBvb2xTZXQubGVuZ3RoOyBpICs9IDEpCglpbnQgMAoJZnJhbWVfYnVyeSA0IC8vIGk6IHVpbnQ2NAoKKmZvcl8zOgoJLy8gY29udHJhY3RzL3ZhbGlkYXRvclJlZ2lzdHJ5LmFsZ28udHM6ODc3CgkvLyBpIDwgcG9vbFNldC5sZW5ndGgKCWZyYW1lX2RpZyA0IC8vIGk6IHVpbnQ2NAoJaW50IDYKCTwKCWJ6ICpmb3JfM19lbmQKCgkvLyAqaWYyMl9jb25kaXRpb24KCS8vIGNvbnRyYWN0cy92YWxpZGF0b3JSZWdpc3RyeS5hbGdvLnRzOjg3OAoJLy8gZ2xvYmFscy5vcGNvZGVCdWRnZXQgPCAzMDAKCWdsb2JhbCBPcGNvZGVCdWRnZXQKCWludCAzMDAKCTwKCWJ6ICppZjIyX2VuZAoKCS8vICppZjIyX2NvbnNlcXVlbnQKCS8vIGNvbnRyYWN0cy92YWxpZGF0b3JSZWdpc3RyeS5hbGdvLnRzOjg3OQoJLy8gaW5jcmVhc2VPcGNvZGVCdWRnZXQoKQoJaXR4bl9iZWdpbgoJaW50IGFwcGwKCWl0eG5fZmllbGQgVHlwZUVudW0KCWludCAwCglpdHhuX2ZpZWxkIEZlZQoJYnl0ZSBiNjQgQ29FQiAvLyAjcHJhZ21hIHZlcnNpb24gMTA7IGludCAxCglkdXAKCWl0eG5fZmllbGQgQXBwcm92YWxQcm9ncmFtCglpdHhuX2ZpZWxkIENsZWFyU3RhdGVQcm9ncmFtCglpbnQgRGVsZXRlQXBwbGljYXRpb24KCWl0eG5fZmllbGQgT25Db21wbGV0aW9uCglpdHhuX3N1Ym1pdAoKKmlmMjJfZW5kOgoJLy8gKmlmMjNfY29uZGl0aW9uCgkvLyBjb250cmFjdHMvdmFsaWRhdG9yUmVnaXN0cnkuYWxnby50czo4ODEKCS8vIHBvb2xTZXRbaV0uaWQgPT09IDAKCWZyYW1lX2RpZyAzIC8vIHBvb2xTZXQ6ICh1aW50NjQsdWludDY0LHVpbnQ2NClbNl0KCWZyYW1lX2RpZyA0IC8vIGk6IHVpbnQ2NAoJaW50IDI0CgkqIC8vIGFjYyAqIHR5cGVMZW5ndGgKCWludCAwCgkrCglpbnQgOAoJZXh0cmFjdDMKCWJ0b2kKCWludCAwCgk9PQoJYnogKmlmMjNfZW5kCgoJLy8gKmlmMjNfY29uc2VxdWVudAoJYiAqZm9yXzNfY29udGludWUKCippZjIzX2VuZDoKCS8vIGNvbnRyYWN0cy92YWxpZGF0b3JSZWdpc3RyeS5hbGdvLnRzOjg4NAoJLy8gaXNOZXdTdGFrZXJUb1Byb3RvY29sID0gZmFsc2UKCWludCAwCglmcmFtZV9idXJ5IDEgLy8gaXNOZXdTdGFrZXJUb1Byb3RvY29sOiBib29sCgoJLy8gKmlmMjRfY29uZGl0aW9uCgkvLyBjb250cmFjdHMvdmFsaWRhdG9yUmVnaXN0cnkuYWxnby50czo4ODUKCS8vIHBvb2xTZXRbaV0uaWQgPT09IHZhbGlkYXRvcklkCglmcmFtZV9kaWcgMyAvLyBwb29sU2V0OiAodWludDY0LHVpbnQ2NCx1aW50NjQpWzZdCglmcmFtZV9kaWcgNCAvLyBpOiB1aW50NjQKCWludCAyNAoJKiAvLyBhY2MgKiB0eXBlTGVuZ3RoCglpbnQgMAoJKwoJaW50IDgKCWV4dHJhY3QzCglidG9pCglmcmFtZV9kaWcgLTEgLy8gdmFsaWRhdG9ySWQ6IFZhbGlkYXRvcklkVHlwZQoJPT0KCWJ6ICppZjI0X2VuZAoKCS8vICppZjI0X2NvbnNlcXVlbnQKCS8vIGNvbnRyYWN0cy92YWxpZGF0b3JSZWdpc3RyeS5hbGdvLnRzOjg4NwoJLy8gaXNOZXdTdGFrZXJUb1ZhbGlkYXRvciA9IGZhbHNlCglpbnQgMAoJZnJhbWVfYnVyeSAwIC8vIGlzTmV3U3Rha2VyVG9WYWxpZGF0b3I6IGJvb2wKCgkvLyAqaWYyNV9jb25kaXRpb24KCS8vIGNvbnRyYWN0cy92YWxpZGF0b3JSZWdpc3RyeS5hbGdvLnRzOjg4OQoJLy8gdGhpcy52YWxpZGF0b3JMaXN0KHZhbGlkYXRvcklkKS52YWx1ZS5wb29sc1twb29sU2V0W2ldLnBvb2xJZCAtIDFdLnRvdGFsQWxnb1N0YWtlZCArCgkvLyAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYW1vdW50VG9TdGFrZSA8PQoJLy8gICAgICAgICAgICAgICAgICAgICAgICAgbWF4UGVyUG9vbAoJaW50IDIzNCAvLyBoZWFkT2Zmc2V0CglmcmFtZV9kaWcgMyAvLyBwb29sU2V0OiAodWludDY0LHVpbnQ2NCx1aW50NjQpWzZdCglmcmFtZV9kaWcgNCAvLyBpOiB1aW50NjQKCWludCAyNAoJKiAvLyBhY2MgKiB0eXBlTGVuZ3RoCglpbnQgOCAvLyBoZWFkT2Zmc2V0CgkrCglpbnQgOAoJZXh0cmFjdDMKCWJ0b2kKCWludCAxCgktCglpbnQgMTgKCSogLy8gYWNjICogdHlwZUxlbmd0aAoJKwoJaW50IDEwIC8vIGhlYWRPZmZzZXQKCSsKCWludCA4CglieXRlIDB4NzYgLy8gInYiCglmcmFtZV9kaWcgLTEgLy8gdmFsaWRhdG9ySWQ6IFZhbGlkYXRvcklkVHlwZQoJaXRvYgoJY29uY2F0Cgljb3ZlciAyCglib3hfZXh0cmFjdAoJYnRvaQoJZnJhbWVfZGlnIC0zIC8vIGFtb3VudFRvU3Rha2U6IHVpbnQ2NAoJKwoJZnJhbWVfZGlnIDIgLy8gbWF4UGVyUG9vbDogdWludDY0Cgk8PQoJYnogKmlmMjVfZW5kCgoJLy8gKmlmMjVfY29uc2VxdWVudAoJLy8gY29udHJhY3RzL3ZhbGlkYXRvclJlZ2lzdHJ5LmFsZ28udHM6ODkzCgkvLyByZXR1cm4gW3Bvb2xTZXRbaV0sIGlzTmV3U3Rha2VyVG9WYWxpZGF0b3IsIGlzTmV3U3Rha2VyVG9Qcm90b2NvbF07CglmcmFtZV9kaWcgMyAvLyBwb29sU2V0OiAodWludDY0LHVpbnQ2NCx1aW50NjQpWzZdCglmcmFtZV9kaWcgNCAvLyBpOiB1aW50NjQKCWludCAyNAoJKiAvLyBhY2MgKiB0eXBlTGVuZ3RoCglpbnQgMjQKCWV4dHJhY3QzCglieXRlIDB4MDAKCWludCAwCglmcmFtZV9kaWcgMCAvLyBpc05ld1N0YWtlclRvVmFsaWRhdG9yOiBib29sCglzZXRiaXQKCWludCAxCglmcmFtZV9kaWcgMSAvLyBpc05ld1N0YWtlclRvUHJvdG9jb2w6IGJvb2wKCXNldGJpdAoJY29uY2F0CgoJLy8gc2V0IHRoZSBzdWJyb3V0aW5lIHJldHVybiB2YWx1ZQoJZnJhbWVfYnVyeSAwCgoJLy8gcG9wIGFsbCBsb2NhbCB2YXJpYWJsZXMgZnJvbSB0aGUgc3RhY2sKCXBvcG4gNAoJcmV0c3ViCgoqaWYyNV9lbmQ6CgoqaWYyNF9lbmQ6CgoqZm9yXzNfY29udGludWU6CgkvLyBjb250cmFjdHMvdmFsaWRhdG9yUmVnaXN0cnkuYWxnby50czo4NzcKCS8vIGkgKz0gMQoJZnJhbWVfZGlnIDQgLy8gaTogdWludDY0CglpbnQgMQoJKwoJZnJhbWVfYnVyeSA0IC8vIGk6IHVpbnQ2NAoJYiAqZm9yXzMKCipmb3JfM19lbmQ6CgoqaWYyMV9lbmQ6CgkvLyBjb250cmFjdHMvdmFsaWRhdG9yUmVnaXN0cnkuYWxnby50czo5MDAKCS8vIGFzc2VydCgKCS8vICAgICAgICAgICAgIGFtb3VudFRvU3Rha2UgPj0gdGhpcy52YWxpZGF0b3JMaXN0KHZhbGlkYXRvcklkKS52YWx1ZS5jb25maWcubWluRW50cnlTdGFrZSwKCS8vICAgICAgICAgICAgICdtdXN0IHN0YWtlIGF0IGxlYXN0IHRoZSBtaW5pbXVtIGZvciB0aGlzIHBvb2wnCgkvLyAgICAgICAgICkKCWZyYW1lX2RpZyAtMyAvLyBhbW91bnRUb1N0YWtlOiB1aW50NjQKCWludCAxNzUKCWludCA4CglieXRlIDB4NzYgLy8gInYiCglmcmFtZV9kaWcgLTEgLy8gdmFsaWRhdG9ySWQ6IFZhbGlkYXRvcklkVHlwZQoJaXRvYgoJY29uY2F0Cgljb3ZlciAyCglib3hfZXh0cmFjdAoJYnRvaQoJPj0KCgkvLyBtdXN0IHN0YWtlIGF0IGxlYXN0IHRoZSBtaW5pbXVtIGZvciB0aGlzIHBvb2wKCWFzc2VydAoKCS8vIGNvbnRyYWN0cy92YWxpZGF0b3JSZWdpc3RyeS5hbGdvLnRzOjkwNgoJLy8gcG9vbHMgPSBjbG9uZSh0aGlzLnZhbGlkYXRvckxpc3QodmFsaWRhdG9ySWQpLnZhbHVlLnBvb2xzKQoJaW50IDIzNCAvLyBoZWFkT2Zmc2V0CglpbnQgNDMyCglieXRlIDB4NzYgLy8gInYiCglmcmFtZV9kaWcgLTEgLy8gdmFsaWRhdG9ySWQ6IFZhbGlkYXRvcklkVHlwZQoJaXRvYgoJY29uY2F0Cgljb3ZlciAyCglib3hfZXh0cmFjdAoJZnJhbWVfYnVyeSA1IC8vIHBvb2xzOiAodWludDY0LHVpbnQxNix1aW50NjQpWzI0XQoKCS8vIGNvbnRyYWN0cy92YWxpZGF0b3JSZWdpc3RyeS5hbGdvLnRzOjkwNwoJLy8gY3VyTnVtUG9vbHMgPSB0aGlzLnZhbGlkYXRvckxpc3QodmFsaWRhdG9ySWQpLnZhbHVlLnN0YXRlLm51bVBvb2xzIGFzIHVpbnQ2NAoJaW50IDIwOAoJaW50IDIKCWJ5dGUgMHg3NiAvLyAidiIKCWZyYW1lX2RpZyAtMSAvLyB2YWxpZGF0b3JJZDogVmFsaWRhdG9ySWRUeXBlCglpdG9iCgljb25jYXQKCWNvdmVyIDIKCWJveF9leHRyYWN0CglidG9pCglmcmFtZV9idXJ5IDYgLy8gY3VyTnVtUG9vbHM6IHVpbnQ2NAoKCS8vIGNvbnRyYWN0cy92YWxpZGF0b3JSZWdpc3RyeS5hbGdvLnRzOjkwOAoJLy8gZm9yIChsZXQgaSA9IDA7IGkgPCBjdXJOdW1Qb29sczsgaSArPSAxKQoJaW50IDAKCWZyYW1lX2J1cnkgNyAvLyBpOiB1aW50NjQKCipmb3JfNDoKCS8vIGNvbnRyYWN0cy92YWxpZGF0b3JSZWdpc3RyeS5hbGdvLnRzOjkwOAoJLy8gaSA8IGN1ck51bVBvb2xzCglmcmFtZV9kaWcgNyAvLyBpOiB1aW50NjQKCWZyYW1lX2RpZyA2IC8vIGN1ck51bVBvb2xzOiB1aW50NjQKCTwKCWJ6ICpmb3JfNF9lbmQKCgkvLyAqaWYyNl9jb25kaXRpb24KCS8vIGNvbnRyYWN0cy92YWxpZGF0b3JSZWdpc3RyeS5hbGdvLnRzOjkwOQoJLy8gcG9vbHNbaV0udG90YWxBbGdvU3Rha2VkICsgYW1vdW50VG9TdGFrZSA8PSBtYXhQZXJQb29sCglmcmFtZV9kaWcgNSAvLyBwb29sczogKHVpbnQ2NCx1aW50MTYsdWludDY0KVsyNF0KCWZyYW1lX2RpZyA3IC8vIGk6IHVpbnQ2NAoJaW50IDE4CgkqIC8vIGFjYyAqIHR5cGVMZW5ndGgKCWludCAxMCAvLyBoZWFkT2Zmc2V0CgkrCglpbnQgOAoJZXh0cmFjdDMKCWJ0b2kKCWZyYW1lX2RpZyAtMyAvLyBhbW91bnRUb1N0YWtlOiB1aW50NjQKCSsKCWZyYW1lX2RpZyAyIC8vIG1heFBlclBvb2w6IHVpbnQ2NAoJPD0KCWJ6ICppZjI2X2VuZAoKCS8vICppZjI2X2NvbnNlcXVlbnQKCS8vIGNvbnRyYWN0cy92YWxpZGF0b3JSZWdpc3RyeS5hbGdvLnRzOjkxMAoJLy8gcmV0dXJuIFsKCS8vICAgICAgICAgICAgICAgICAgICAgeyBpZDogdmFsaWRhdG9ySWQsIHBvb2xJZDogaSArIDEsIHBvb2xBcHBJZDogcG9vbHNbaV0ucG9vbEFwcElkIH0sCgkvLyAgICAgICAgICAgICAgICAgICAgIGlzTmV3U3Rha2VyVG9WYWxpZGF0b3IsCgkvLyAgICAgICAgICAgICAgICAgICAgIGlzTmV3U3Rha2VyVG9Qcm90b2NvbCwKCS8vICAgICAgICAgICAgICAgICBdOwoJZnJhbWVfZGlnIC0xIC8vIHZhbGlkYXRvcklkOiBWYWxpZGF0b3JJZFR5cGUKCWl0b2IKCWZyYW1lX2RpZyA3IC8vIGk6IHVpbnQ2NAoJaW50IDEKCSsKCWl0b2IKCWNvbmNhdAoJZnJhbWVfZGlnIDUgLy8gcG9vbHM6ICh1aW50NjQsdWludDE2LHVpbnQ2NClbMjRdCglmcmFtZV9kaWcgNyAvLyBpOiB1aW50NjQKCWludCAxOAoJKiAvLyBhY2MgKiB0eXBlTGVuZ3RoCglpbnQgMAoJKwoJaW50IDgKCWV4dHJhY3QzCglidG9pCglpdG9iCgljb25jYXQKCWJ5dGUgMHgwMAoJaW50IDAKCWZyYW1lX2RpZyAwIC8vIGlzTmV3U3Rha2VyVG9WYWxpZGF0b3I6IGJvb2wKCXNldGJpdAoJaW50IDEKCWZyYW1lX2RpZyAxIC8vIGlzTmV3U3Rha2VyVG9Qcm90b2NvbDogYm9vbAoJc2V0Yml0Cgljb25jYXQKCgkvLyBzZXQgdGhlIHN1YnJvdXRpbmUgcmV0dXJuIHZhbHVlCglmcmFtZV9idXJ5IDAKCgkvLyBwb3AgYWxsIGxvY2FsIHZhcmlhYmxlcyBmcm9tIHRoZSBzdGFjawoJcG9wbiA3CglyZXRzdWIKCippZjI2X2VuZDoKCipmb3JfNF9jb250aW51ZToKCS8vIGNvbnRyYWN0cy92YWxpZGF0b3JSZWdpc3RyeS5hbGdvLnRzOjkwOAoJLy8gaSArPSAxCglmcmFtZV9kaWcgNyAvLyBpOiB1aW50NjQKCWludCAxCgkrCglmcmFtZV9idXJ5IDcgLy8gaTogdWludDY0CgliICpmb3JfNAoKKmZvcl80X2VuZDoKCS8vIGNvbnRyYWN0cy92YWxpZGF0b3JSZWdpc3RyeS5hbGdvLnRzOjkxOAoJLy8gcmV0dXJuIFt7IGlkOiB2YWxpZGF0b3JJZCwgcG9vbElkOiAwLCBwb29sQXBwSWQ6IDAgfSwgaXNOZXdTdGFrZXJUb1ZhbGlkYXRvciwgaXNOZXdTdGFrZXJUb1Byb3RvY29sXTsKCWZyYW1lX2RpZyAtMSAvLyB2YWxpZGF0b3JJZDogVmFsaWRhdG9ySWRUeXBlCglpdG9iCglieXRlIDB4MDAwMDAwMDAwMDAwMDAwMAoJY29uY2F0CglieXRlIDB4MDAwMDAwMDAwMDAwMDAwMAoJY29uY2F0CglieXRlIDB4MDAKCWludCAwCglmcmFtZV9kaWcgMCAvLyBpc05ld1N0YWtlclRvVmFsaWRhdG9yOiBib29sCglzZXRiaXQKCWludCAxCglmcmFtZV9kaWcgMSAvLyBpc05ld1N0YWtlclRvUHJvdG9jb2w6IGJvb2wKCXNldGJpdAoJY29uY2F0CgoJLy8gc2V0IHRoZSBzdWJyb3V0aW5lIHJldHVybiB2YWx1ZQoJZnJhbWVfYnVyeSAwCgoJLy8gcG9wIGFsbCBsb2NhbCB2YXJpYWJsZXMgZnJvbSB0aGUgc3RhY2sKCXBvcG4gNwoJcmV0c3ViCgovLyBtb3ZlUG9vbFRvTm9kZSh1aW50NjQsdWludDY0LHVpbnQ2NCl2b2lkCiphYmlfcm91dGVfbW92ZVBvb2xUb05vZGU6CgkvLyBub2RlTnVtOiB1aW50NjQKCXR4bmEgQXBwbGljYXRpb25BcmdzIDMKCWJ0b2kKCgkvLyBwb29sQXBwSWQ6IHVpbnQ2NAoJdHhuYSBBcHBsaWNhdGlvbkFyZ3MgMgoJYnRvaQoKCS8vIHZhbGlkYXRvcklkOiB1aW50NjQKCXR4bmEgQXBwbGljYXRpb25BcmdzIDEKCWJ0b2kKCgkvLyBleGVjdXRlIG1vdmVQb29sVG9Ob2RlKHVpbnQ2NCx1aW50NjQsdWludDY0KXZvaWQKCWNhbGxzdWIgbW92ZVBvb2xUb05vZGUKCWludCAxCglyZXR1cm4KCi8vIG1vdmVQb29sVG9Ob2RlKHZhbGlkYXRvcklkOiBWYWxpZGF0b3JJZFR5cGUsIHBvb2xBcHBJZDogdWludDY0LCBub2RlTnVtOiB1aW50NjQpOiB2b2lkCi8vCi8vIEZpbmQgdGhlIHNwZWNpZmllZCBwb29sIChpbiBhbnkgbm9kZSBudW1iZXIpIGFuZCBtb3ZlIGl0IHRvIHRoZSBzcGVjaWZpZWQgbm9kZS4KLy8gVGhlIHBvb2wgYWNjb3VudCBpcyBmb3JjZWQgb2ZmbGluZSBpZiBtb3ZlZCBzbyBwcmlvciBub2RlIHdpbGwgc3RpbGwgcnVuIGZvciAzMjAgcm91bmRzIGJ1dAovLyBuZXcga2V5IGdvZXMgb25saW5lIG9uIG5ldyBub2RlIHNvb24gYWZ0ZXIgKDMyMCByb3VuZHMgYWZ0ZXIgaXQgZ29lcyBvbmxpbmUpCi8vIE5vLW9wIGlmIHN1Y2Nlc3MsIGFzc2VydHMgaWYgbm90IGZvdW5kIG9yIGNhbid0IG1vdmUgIChubyBzcGFjZSBpbiB0YXJnZXQpCi8vIFsgT05MWSBPV05FUiBPUiBNQU5BR0VSIENBTiBDSEFOR0UgXQovLyBPbmx5IGNhbGxhYmxlIGJ5IG93bmVyIG9yIG1hbmFnZXIKbW92ZVBvb2xUb05vZGU6Cglwcm90byAzIDAKCgkvLyBQdXNoIGVtcHR5IGJ5dGVzIGFmdGVyIHRoZSBmcmFtZSBwb2ludGVyIHRvIHJlc2VydmUgc3BhY2UgZm9yIGxvY2FsIHZhcmlhYmxlcwoJYnl0ZSAweAoJZHVwbiAyCgoJLy8gY29udHJhY3RzL3ZhbGlkYXRvclJlZ2lzdHJ5LmFsZ28udHM6OTMxCgkvLyBhc3NlcnQoCgkvLyAgICAgICAgICAgICB0aGlzLnR4bi5zZW5kZXIgPT09IHRoaXMudmFsaWRhdG9yTGlzdCh2YWxpZGF0b3JJZCkudmFsdWUuY29uZmlnLm93bmVyIHx8CgkvLyAgICAgICAgICAgICAgICAgdGhpcy50eG4uc2VuZGVyID09PSB0aGlzLnZhbGlkYXRvckxpc3QodmFsaWRhdG9ySWQpLnZhbHVlLmNvbmZpZy5tYW5hZ2VyCgkvLyAgICAgICAgICkKCXR4biBTZW5kZXIKCWludCA4CglpbnQgMzIKCWJ5dGUgMHg3NiAvLyAidiIKCWZyYW1lX2RpZyAtMSAvLyB2YWxpZGF0b3JJZDogVmFsaWRhdG9ySWRUeXBlCglpdG9iCgljb25jYXQKCWNvdmVyIDIKCWJveF9leHRyYWN0Cgk9PQoJZHVwCglibnogKnNraXBfb3IzCgl0eG4gU2VuZGVyCglpbnQgNDAKCWludCAzMgoJYnl0ZSAweDc2IC8vICJ2IgoJZnJhbWVfZGlnIC0xIC8vIHZhbGlkYXRvcklkOiBWYWxpZGF0b3JJZFR5cGUKCWl0b2IKCWNvbmNhdAoJY292ZXIgMgoJYm94X2V4dHJhY3QKCT09Cgl8fAoKKnNraXBfb3IzOgoJYXNzZXJ0CgoJLy8gY29udHJhY3RzL3ZhbGlkYXRvclJlZ2lzdHJ5LmFsZ28udHM6OTM2CgkvLyBub2RlUG9vbEFzc2lnbm1lbnRzID0gY2xvbmUodGhpcy52YWxpZGF0b3JMaXN0KHZhbGlkYXRvcklkKS52YWx1ZS5ub2RlUG9vbEFzc2lnbm1lbnRzKQoJaW50IDg2NiAvLyBoZWFkT2Zmc2V0CglpbnQgMTkyCglieXRlIDB4NzYgLy8gInYiCglmcmFtZV9kaWcgLTEgLy8gdmFsaWRhdG9ySWQ6IFZhbGlkYXRvcklkVHlwZQoJaXRvYgoJY29uY2F0Cgljb3ZlciAyCglib3hfZXh0cmFjdAoJZnJhbWVfYnVyeSAwIC8vIG5vZGVQb29sQXNzaWdubWVudHM6ICgodWludDY0WzNdKVs4XSkKCgkvLyBjb250cmFjdHMvdmFsaWRhdG9yUmVnaXN0cnkuYWxnby50czo5MzcKCS8vIGFzc2VydChub2RlTnVtID49IDEgJiYgbm9kZU51bSA8PSBNQVhfTk9ERVMpCglmcmFtZV9kaWcgLTMgLy8gbm9kZU51bTogdWludDY0CglpbnQgMQoJPj0KCWR1cAoJYnogKnNraXBfYW5kMQoJZnJhbWVfZGlnIC0zIC8vIG5vZGVOdW06IHVpbnQ2NAoJaW50IDgKCTw9CgkmJgoKKnNraXBfYW5kMToKCWFzc2VydAoKCS8vIGNvbnRyYWN0cy92YWxpZGF0b3JSZWdpc3RyeS5hbGdvLnRzOjkzOQoJLy8gZm9yIChsZXQgc3JjTm9kZUlkeCA9IDA7IHNyY05vZGVJZHggPCBNQVhfTk9ERVM7IHNyY05vZGVJZHggKz0gMSkKCWludCAwCglmcmFtZV9idXJ5IDEgLy8gc3JjTm9kZUlkeDogdWludDY0CgoqZm9yXzU6CgkvLyBjb250cmFjdHMvdmFsaWRhdG9yUmVnaXN0cnkuYWxnby50czo5MzkKCS8vIHNyY05vZGVJZHggPCBNQVhfTk9ERVMKCWZyYW1lX2RpZyAxIC8vIHNyY05vZGVJZHg6IHVpbnQ2NAoJaW50IDgKCTwKCWJ6ICpmb3JfNV9lbmQKCgkvLyBjb250cmFjdHMvdmFsaWRhdG9yUmVnaXN0cnkuYWxnby50czo5NDAKCS8vIGZvciAobGV0IGkgPSAwOyBpIDwgTUFYX1BPT0xTX1BFUl9OT0RFOyBpICs9IDEpCglpbnQgMAoJZnJhbWVfYnVyeSAyIC8vIGk6IHVpbnQ2NAoKKmZvcl82OgoJLy8gY29udHJhY3RzL3ZhbGlkYXRvclJlZ2lzdHJ5LmFsZ28udHM6OTQwCgkvLyBpIDwgTUFYX1BPT0xTX1BFUl9OT0RFCglmcmFtZV9kaWcgMiAvLyBpOiB1aW50NjQKCWludCAzCgk8CglieiAqZm9yXzZfZW5kCgoJLy8gKmlmMjdfY29uZGl0aW9uCgkvLyBjb250cmFjdHMvdmFsaWRhdG9yUmVnaXN0cnkuYWxnby50czo5NDEKCS8vIG5vZGVQb29sQXNzaWdubWVudHMubm9kZXNbc3JjTm9kZUlkeF0ucG9vbEFwcElkc1tpXSA9PT0gcG9vbEFwcElkCglmcmFtZV9kaWcgMCAvLyBub2RlUG9vbEFzc2lnbm1lbnRzOiAoKHVpbnQ2NFszXSlbOF0pCglpbnQgMAoJZnJhbWVfZGlnIDEgLy8gc3JjTm9kZUlkeDogdWludDY0CglpbnQgMjQKCSogLy8gYWNjICogdHlwZUxlbmd0aAoJKwoJaW50IDAKCSsKCWZyYW1lX2RpZyAyIC8vIGk6IHVpbnQ2NAoJaW50IDgKCSogLy8gYWNjICogdHlwZUxlbmd0aAoJKwoJaW50IDgKCWV4dHJhY3QzCglidG9pCglmcmFtZV9kaWcgLTIgLy8gcG9vbEFwcElkOiB1aW50NjQKCT09CglieiAqaWYyN19lbmQKCgkvLyAqaWYyN19jb25zZXF1ZW50CgkvLyBjb250cmFjdHMvdmFsaWRhdG9yUmVnaXN0cnkuYWxnby50czo5NDIKCS8vIGFzc2VydChub2RlTnVtIC0gMSAhPT0gc3JjTm9kZUlkeCwgImNhbid0IG1vdmUgdG8gc2FtZSBub2RlIikKCWZyYW1lX2RpZyAtMyAvLyBub2RlTnVtOiB1aW50NjQKCWludCAxCgktCglmcmFtZV9kaWcgMSAvLyBzcmNOb2RlSWR4OiB1aW50NjQKCSE9CgoJLy8gY2FuJ3QgbW92ZSB0byBzYW1lIG5vZGUKCWFzc2VydAoKCS8vIGNvbnRyYWN0cy92YWxpZGF0b3JSZWdpc3RyeS5hbGdvLnRzOjk0NAoJLy8gdGhpcy52YWxpZGF0b3JMaXN0KHZhbGlkYXRvcklkKS52YWx1ZS5ub2RlUG9vbEFzc2lnbm1lbnRzLm5vZGVzW3NyY05vZGVJZHhdLnBvb2xBcHBJZHNbaV0gPSAwCglpbnQgODY2CglmcmFtZV9kaWcgMSAvLyBzcmNOb2RlSWR4OiB1aW50NjQKCWludCAyNAoJKiAvLyBhY2MgKiB0eXBlTGVuZ3RoCgkrCglpbnQgMAoJKwoJZnJhbWVfZGlnIDIgLy8gaTogdWludDY0CglpbnQgOAoJKiAvLyBhY2MgKiB0eXBlTGVuZ3RoCgkrCglieXRlIDB4MDAwMDAwMDAwMDAwMDAwMAoJYnl0ZSAweDc2IC8vICJ2IgoJZnJhbWVfZGlnIC0xIC8vIHZhbGlkYXRvcklkOiBWYWxpZGF0b3JJZFR5cGUKCWl0b2IKCWNvbmNhdAoJY292ZXIgMgoJYm94X3JlcGxhY2UKCgkvLyBjb250cmFjdHMvdmFsaWRhdG9yUmVnaXN0cnkuYWxnby50czo5NDcKCS8vIHNlbmRNZXRob2RDYWxsPHR5cGVvZiBTdGFraW5nUG9vbC5wcm90b3R5cGUuZ29PZmZsaW5lPih7CgkvLyAgICAgICAgICAgICAgICAgICAgICAgICBhcHBsaWNhdGlvbklEOiBBcHBJRC5mcm9tVWludDY0KHBvb2xBcHBJZCksCgkvLyAgICAgICAgICAgICAgICAgICAgIH0pCglpdHhuX2JlZ2luCglpbnQgYXBwbAoJaXR4bl9maWVsZCBUeXBlRW51bQoJbWV0aG9kICJnb09mZmxpbmUoKXZvaWQiCglpdHhuX2ZpZWxkIEFwcGxpY2F0aW9uQXJncwoKCS8vIGNvbnRyYWN0cy92YWxpZGF0b3JSZWdpc3RyeS5hbGdvLnRzOjk0OAoJLy8gYXBwbGljYXRpb25JRDogQXBwSUQuZnJvbVVpbnQ2NChwb29sQXBwSWQpCglmcmFtZV9kaWcgLTIgLy8gcG9vbEFwcElkOiB1aW50NjQKCWl0eG5fZmllbGQgQXBwbGljYXRpb25JRAoKCS8vIEZlZSBmaWVsZCBub3Qgc2V0LCBkZWZhdWx0aW5nIHRvIDAKCWludCAwCglpdHhuX2ZpZWxkIEZlZQoKCS8vIFN1Ym1pdCBpbm5lciB0cmFuc2FjdGlvbgoJaXR4bl9zdWJtaXQKCgkvLyBjb250cmFjdHMvdmFsaWRhdG9yUmVnaXN0cnkuYWxnby50czo5NTIKCS8vIHRoaXMuYWRkUG9vbFRvTm9kZSh2YWxpZGF0b3JJZCwgcG9vbEFwcElkLCBub2RlTnVtKQoJZnJhbWVfZGlnIC0zIC8vIG5vZGVOdW06IHVpbnQ2NAoJZnJhbWVfZGlnIC0yIC8vIHBvb2xBcHBJZDogdWludDY0CglmcmFtZV9kaWcgLTEgLy8gdmFsaWRhdG9ySWQ6IFZhbGlkYXRvcklkVHlwZQoJY2FsbHN1YiBhZGRQb29sVG9Ob2RlCgoJLy8gY29udHJhY3RzL3ZhbGlkYXRvclJlZ2lzdHJ5LmFsZ28udHM6OTUzCgkvLyByZXR1cm47CglyZXRzdWIKCippZjI3X2VuZDoKCipmb3JfNl9jb250aW51ZToKCS8vIGNvbnRyYWN0cy92YWxpZGF0b3JSZWdpc3RyeS5hbGdvLnRzOjk0MAoJLy8gaSArPSAxCglmcmFtZV9kaWcgMiAvLyBpOiB1aW50NjQKCWludCAxCgkrCglmcmFtZV9idXJ5IDIgLy8gaTogdWludDY0CgliICpmb3JfNgoKKmZvcl82X2VuZDoKCipmb3JfNV9jb250aW51ZToKCS8vIGNvbnRyYWN0cy92YWxpZGF0b3JSZWdpc3RyeS5hbGdvLnRzOjkzOQoJLy8gc3JjTm9kZUlkeCArPSAxCglmcmFtZV9kaWcgMSAvLyBzcmNOb2RlSWR4OiB1aW50NjQKCWludCAxCgkrCglmcmFtZV9idXJ5IDEgLy8gc3JjTm9kZUlkeDogdWludDY0CgliICpmb3JfNQoKKmZvcl81X2VuZDoKCWVyciAvLyAiY291bGRuJ3QgZmluZCBwb29sIGFwcCBpZCBpbiBub2RlcyB0byBtb3ZlIgoKLy8gdmVyaWZ5UG9vbEtleUNhbGxlcihwb29sS2V5OiBWYWxpZGF0b3JQb29sS2V5KTogdm9pZAovLwovLyBMb2dzIHRoZSBhZGRpdGlvbiBvZiBhIG5ldyB2YWxpZGF0b3IgdG8gdGhlIHN5c3RlbSwgaXRzIGluaXRpYWwgb3duZXIgYW5kIG1hbmFnZXIKLy8KLy8KLy8gdmVyaWZ5UG9vbEtleUNhbGxlciB2ZXJpZmllcyB0aGUgcGFzc2VkIGluIGtleSAoZnJvbSBhIHN0YWtpbmcgcG9vbCBjYWxsaW5nIHVzIHRvIHVwZGF0ZSBtZXRyaWNzKSBpcyB2YWxpZAovLyBhbmQgbWF0Y2hlcyB0aGUgaW5mb3JtYXRpb24gd2UgaGF2ZSBpbiBvdXIgc3RhdGUuICAnRmFrZScgcG9vbHMgY291bGQgY2FsbCB1cyB0byB1cGRhdGUgb3VyIGRhdGEsIGJ1dCB0aGV5Ci8vIGNhbid0IGZha2UgdGhlIGlkcyBhbmQgbW9zdCBpbXBvcnRhbnRseSBhcHBsaWNhdGlvbiBpZCghKSBvZiB0aGUgY2FsbGVyIHRoYXQgaGFzIHRvIG1hdGNoLgp2ZXJpZnlQb29sS2V5Q2FsbGVyOgoJcHJvdG8gMSAwCgoJLy8gY29udHJhY3RzL3ZhbGlkYXRvclJlZ2lzdHJ5LmFsZ28udHM6MTA1MQoJLy8gYXNzZXJ0KHRoaXMudmFsaWRhdG9yTGlzdChwb29sS2V5LmlkKS5leGlzdHMpCglieXRlIDB4NzYgLy8gInYiCglmcmFtZV9kaWcgLTEgLy8gcG9vbEtleTogVmFsaWRhdG9yUG9vbEtleQoJZXh0cmFjdCAwIDgKCWJ0b2kKCWl0b2IKCWNvbmNhdAoJYm94X2xlbgoJc3dhcAoJcG9wCglhc3NlcnQKCgkvLyBjb250cmFjdHMvdmFsaWRhdG9yUmVnaXN0cnkuYWxnby50czoxMDUyCgkvLyBhc3NlcnQoKHBvb2xLZXkucG9vbElkIGFzIHVpbnQ2NCkgPCAyICoqIDE2KQoJZnJhbWVfZGlnIC0xIC8vIHBvb2xLZXk6IFZhbGlkYXRvclBvb2xLZXkKCWV4dHJhY3QgOCA4CglidG9pCglpbnQgMgoJaW50IDE2CglleHAKCTwKCWFzc2VydAoKCS8vIGNvbnRyYWN0cy92YWxpZGF0b3JSZWdpc3RyeS5hbGdvLnRzOjEwNTMKCS8vIGFzc2VydChwb29sS2V5LnBvb2xJZCA+IDAgJiYgKHBvb2xLZXkucG9vbElkIGFzIHVpbnQxNikgPD0gdGhpcy52YWxpZGF0b3JMaXN0KHBvb2xLZXkuaWQpLnZhbHVlLnN0YXRlLm51bVBvb2xzKQoJZnJhbWVfZGlnIC0xIC8vIHBvb2xLZXk6IFZhbGlkYXRvclBvb2xLZXkKCWV4dHJhY3QgOCA4CglidG9pCglpbnQgMAoJPgoJZHVwCglieiAqc2tpcF9hbmQyCglmcmFtZV9kaWcgLTEgLy8gcG9vbEtleTogVmFsaWRhdG9yUG9vbEtleQoJZXh0cmFjdCA4IDgKCWJ0b2kKCWludCAyMDgKCWludCAyCglieXRlIDB4NzYgLy8gInYiCglmcmFtZV9kaWcgLTEgLy8gcG9vbEtleTogVmFsaWRhdG9yUG9vbEtleQoJZXh0cmFjdCAwIDgKCWJ0b2kKCWl0b2IKCWNvbmNhdAoJY292ZXIgMgoJYm94X2V4dHJhY3QKCWJ0b2kKCTw9CgkmJgoKKnNraXBfYW5kMjoKCWFzc2VydAoKCS8vIGNvbnRyYWN0cy92YWxpZGF0b3JSZWdpc3RyeS5hbGdvLnRzOjEwNTYKCS8vIGFzc2VydCgKCS8vICAgICAgICAgICAgIHBvb2xLZXkucG9vbEFwcElkID09PSB0aGlzLnZhbGlkYXRvckxpc3QocG9vbEtleS5pZCkudmFsdWUucG9vbHNbcG9vbEtleS5wb29sSWQgLSAxXS5wb29sQXBwSWQsCgkvLyAgICAgICAgICAgICAiVGhlIHBhc3NlZCBpbiBhcHAgaWQgZG9lc24ndCBtYXRjaCB0aGUgcGFzc2VkIGluIGlkcyIKCS8vICAgICAgICAgKQoJZnJhbWVfZGlnIC0xIC8vIHBvb2xLZXk6IFZhbGlkYXRvclBvb2xLZXkKCWV4dHJhY3QgMTYgOAoJYnRvaQoJaW50IDIzNCAvLyBoZWFkT2Zmc2V0CglmcmFtZV9kaWcgLTEgLy8gcG9vbEtleTogVmFsaWRhdG9yUG9vbEtleQoJZXh0cmFjdCA4IDgKCWJ0b2kKCWludCAxCgktCglpbnQgMTgKCSogLy8gYWNjICogdHlwZUxlbmd0aAoJKwoJaW50IDAKCSsKCWludCA4CglieXRlIDB4NzYgLy8gInYiCglmcmFtZV9kaWcgLTEgLy8gcG9vbEtleTogVmFsaWRhdG9yUG9vbEtleQoJZXh0cmFjdCAwIDgKCWJ0b2kKCWl0b2IKCWNvbmNhdAoJY292ZXIgMgoJYm94X2V4dHJhY3QKCWJ0b2kKCT09CgoJLy8gVGhlIHBhc3NlZCBpbiBhcHAgaWQgZG9lc24ndCBtYXRjaCB0aGUgcGFzc2VkIGluIGlkcwoJYXNzZXJ0CgoJLy8gY29udHJhY3RzL3ZhbGlkYXRvclJlZ2lzdHJ5LmFsZ28udHM6MTA2MQoJLy8gYXNzZXJ0KHRoaXMudHhuLnNlbmRlciA9PT0gQXBwSUQuZnJvbVVpbnQ2NChwb29sS2V5LnBvb2xBcHBJZCkuYWRkcmVzcykKCXR4biBTZW5kZXIKCWZyYW1lX2RpZyAtMSAvLyBwb29sS2V5OiBWYWxpZGF0b3JQb29sS2V5CglleHRyYWN0IDE2IDgKCWJ0b2kKCWFwcF9wYXJhbXNfZ2V0IEFwcEFkZHJlc3MKCXBvcAoJPT0KCWFzc2VydAoKCS8vIGNvbnRyYWN0cy92YWxpZGF0b3JSZWdpc3RyeS5hbGdvLnRzOjEwNjMKCS8vIGFzc2VydChwb29sS2V5LmlkID09PSAoQXBwSUQuZnJvbVVpbnQ2NChwb29sS2V5LnBvb2xBcHBJZCkuZ2xvYmFsU3RhdGUoJ3ZhbGlkYXRvcklkJykgYXMgdWludDY0KSkKCWZyYW1lX2RpZyAtMSAvLyBwb29sS2V5OiBWYWxpZGF0b3JQb29sS2V5CglleHRyYWN0IDAgOAoJYnRvaQoJZnJhbWVfZGlnIC0xIC8vIHBvb2xLZXk6IFZhbGlkYXRvclBvb2xLZXkKCWV4dHJhY3QgMTYgOAoJYnRvaQoJYnl0ZSAweDc2NjE2YzY5NjQ2MTc0NmY3MjQ5NjQgLy8gInZhbGlkYXRvcklkIgoJYXBwX2dsb2JhbF9nZXRfZXgKCWFzc2VydAoJPT0KCWFzc2VydAoKCS8vIGNvbnRyYWN0cy92YWxpZGF0b3JSZWdpc3RyeS5hbGdvLnRzOjEwNjQKCS8vIGFzc2VydChwb29sS2V5LnBvb2xJZCA9PT0gKEFwcElELmZyb21VaW50NjQocG9vbEtleS5wb29sQXBwSWQpLmdsb2JhbFN0YXRlKCdwb29sSWQnKSBhcyB1aW50NjQpKQoJZnJhbWVfZGlnIC0xIC8vIHBvb2xLZXk6IFZhbGlkYXRvclBvb2xLZXkKCWV4dHJhY3QgOCA4CglidG9pCglmcmFtZV9kaWcgLTEgLy8gcG9vbEtleTogVmFsaWRhdG9yUG9vbEtleQoJZXh0cmFjdCAxNiA4CglidG9pCglieXRlIDB4NzA2ZjZmNmM0OTY0IC8vICJwb29sSWQiCglhcHBfZ2xvYmFsX2dldF9leAoJYXNzZXJ0Cgk9PQoJYXNzZXJ0CglyZXRzdWIKCi8vIHJldmVyaWZ5TkZET3duZXJzaGlwKHZhbGlkYXRvcklkOiBWYWxpZGF0b3JJZFR5cGUpOiB2b2lkCi8vCi8vIFRoaXMgbWV0aG9kIHZlcmlmaWVzIHRoZSBvd25lcnNoaXAgb2YgTkZEIChOYW1lZCBGdW5jdGlvbiBEYXRhKSBieSBhIHZhbGlkYXRvci4KLy8gSWYgdGhlIG93bmVyc2hpcCBpcyBubyBsb25nZXIgdmFsaWQsIGl0IHJlbW92ZXMgdGhlIE5GRCBmcm9tIHRoZSB2YWxpZGF0b3IncyBjb25maWd1cmF0aW9uLgovLwovLyBAcGFyYW0ge1ZhbGlkYXRvcklkVHlwZX0gdmFsaWRhdG9ySWQgLSBUaGUgaWQgb2YgdGhlIHZhbGlkYXRvciB3aG9zZSBkYXRhIHNob3VsZCBiZSByZS1ldmFsdWF0ZWQuCnJldmVyaWZ5TkZET3duZXJzaGlwOgoJcHJvdG8gMSAwCgoJLy8gUHVzaCBlbXB0eSBieXRlcyBhZnRlciB0aGUgZnJhbWUgcG9pbnRlciB0byByZXNlcnZlIHNwYWNlIGZvciBsb2NhbCB2YXJpYWJsZXMKCWJ5dGUgMHgKCWR1cAoKCS8vIGNvbnRyYWN0cy92YWxpZGF0b3JSZWdpc3RyeS5hbGdvLnRzOjEwNzQKCS8vIHZhbGlkYXRvckNvbmZpZyA9IHRoaXMudmFsaWRhdG9yTGlzdCh2YWxpZGF0b3JJZCkudmFsdWUuY29uZmlnCglieXRlIDB4NzYgLy8gInYiCglmcmFtZV9kaWcgLTEgLy8gdmFsaWRhdG9ySWQ6IFZhbGlkYXRvcklkVHlwZQoJaXRvYgoJY29uY2F0CglmcmFtZV9idXJ5IDAgLy8gc3RvcmFnZSBrZXkvL3ZhbGlkYXRvckNvbmZpZwoKCS8vICppZjI4X2NvbmRpdGlvbgoJLy8gY29udHJhY3RzL3ZhbGlkYXRvclJlZ2lzdHJ5LmFsZ28udHM6MTA3NQoJLy8gdmFsaWRhdG9yQ29uZmlnLm5mZEZvckluZm8gIT09IDAKCWludCA3MgoJaW50IDgKCWJ5dGUgMHg3NiAvLyAidiIKCWZyYW1lX2RpZyAtMSAvLyB2YWxpZGF0b3JJZDogVmFsaWRhdG9ySWRUeXBlCglpdG9iCgljb25jYXQKCWNvdmVyIDIKCWJveF9leHRyYWN0CglidG9pCglpbnQgMAoJIT0KCWJ6ICppZjI4X2VuZAoKCS8vICppZjI4X2NvbnNlcXVlbnQKCS8vIGNvbnRyYWN0cy92YWxpZGF0b3JSZWdpc3RyeS5hbGdvLnRzOjEwNzgKCS8vIG5mZE93bmVyID0gQXBwSUQuZnJvbVVpbnQ2NCh2YWxpZGF0b3JDb25maWcubmZkRm9ySW5mbykuZ2xvYmFsU3RhdGUoJ2kub3duZXIuYScpIGFzIEFkZHJlc3MKCWludCA3MgoJaW50IDgKCWJ5dGUgMHg3NiAvLyAidiIKCWZyYW1lX2RpZyAtMSAvLyB2YWxpZGF0b3JJZDogVmFsaWRhdG9ySWRUeXBlCglpdG9iCgljb25jYXQKCWNvdmVyIDIKCWJveF9leHRyYWN0CglidG9pCglieXRlIDB4NjkyZTZmNzc2ZTY1NzIyZTYxIC8vICJpLm93bmVyLmEiCglhcHBfZ2xvYmFsX2dldF9leAoJYXNzZXJ0CglmcmFtZV9idXJ5IDEgLy8gbmZkT3duZXI6IGFkZHJlc3MKCgkvLyAqaWYyOV9jb25kaXRpb24KCS8vIGNvbnRyYWN0cy92YWxpZGF0b3JSZWdpc3RyeS5hbGdvLnRzOjEwODAKCS8vIHZhbGlkYXRvckNvbmZpZy5vd25lciAhPT0gbmZkT3duZXIgJiYgdmFsaWRhdG9yQ29uZmlnLm1hbmFnZXIgIT09IG5mZE93bmVyCglpbnQgOAoJaW50IDMyCglieXRlIDB4NzYgLy8gInYiCglmcmFtZV9kaWcgLTEgLy8gdmFsaWRhdG9ySWQ6IFZhbGlkYXRvcklkVHlwZQoJaXRvYgoJY29uY2F0Cgljb3ZlciAyCglib3hfZXh0cmFjdAoJZnJhbWVfZGlnIDEgLy8gbmZkT3duZXI6IGFkZHJlc3MKCSE9CglkdXAKCWJ6ICpza2lwX2FuZDMKCWludCA0MAoJaW50IDMyCglieXRlIDB4NzYgLy8gInYiCglmcmFtZV9kaWcgLTEgLy8gdmFsaWRhdG9ySWQ6IFZhbGlkYXRvcklkVHlwZQoJaXRvYgoJY29uY2F0Cgljb3ZlciAyCglib3hfZXh0cmFjdAoJZnJhbWVfZGlnIDEgLy8gbmZkT3duZXI6IGFkZHJlc3MKCSE9CgkmJgoKKnNraXBfYW5kMzoKCWJ6ICppZjI5X2VuZAoKCS8vICppZjI5X2NvbnNlcXVlbnQKCS8vIGNvbnRyYWN0cy92YWxpZGF0b3JSZWdpc3RyeS5hbGdvLnRzOjEwODIKCS8vIHRoaXMudmFsaWRhdG9yTGlzdCh2YWxpZGF0b3JJZCkudmFsdWUuY29uZmlnLm5mZEZvckluZm8gPSAwCglpbnQgNzIKCWJ5dGUgMHgwMDAwMDAwMDAwMDAwMDAwCglieXRlIDB4NzYgLy8gInYiCglmcmFtZV9kaWcgLTEgLy8gdmFsaWRhdG9ySWQ6IFZhbGlkYXRvcklkVHlwZQoJaXRvYgoJY29uY2F0Cgljb3ZlciAyCglib3hfcmVwbGFjZQoKKmlmMjlfZW5kOgoKKmlmMjhfZW5kOgoJcmV0c3ViCgovLyB2YWxpZGF0ZUNvbmZpZyhjb25maWc6IFZhbGlkYXRvckNvbmZpZyk6IHZvaWQKdmFsaWRhdGVDb25maWc6Cglwcm90byAxIDAKCgkvLyBjb250cmFjdHMvdmFsaWRhdG9yUmVnaXN0cnkuYWxnby50czoxMDg5CgkvLyBhc3NlcnQoY29uZmlnLmVudHJ5R2F0aW5nVHlwZSA+PSBHQVRJTkdfVFlQRV9OT05FICYmIGNvbmZpZy5lbnRyeUdhdGluZ1R5cGUgPD0gR0FUSU5HX1RZUEVfQ09OU1RfTUFYKQoJZnJhbWVfZGlnIC0xIC8vIGNvbmZpZzogVmFsaWRhdG9yQ29uZmlnCglleHRyYWN0IDgwIDEKCWJ0b2kKCWludCAwCgk+PQoJZHVwCglieiAqc2tpcF9hbmQ0CglmcmFtZV9kaWcgLTEgLy8gY29uZmlnOiBWYWxpZGF0b3JDb25maWcKCWV4dHJhY3QgODAgMQoJYnRvaQoJaW50IDQKCTw9CgkmJgoKKnNraXBfYW5kNDoKCWFzc2VydAoKCS8vIGNvbnRyYWN0cy92YWxpZGF0b3JSZWdpc3RyeS5hbGdvLnRzOjEwOTAKCS8vIGFzc2VydChjb25maWcucGF5b3V0RXZlcnlYTWlucyA+PSBNSU5fUEFZT1VUX01JTlMgJiYgY29uZmlnLnBheW91dEV2ZXJ5WE1pbnMgPD0gTUFYX1BBWU9VVF9NSU5TKQoJZnJhbWVfZGlnIC0xIC8vIGNvbmZpZzogVmFsaWRhdG9yQ29uZmlnCglleHRyYWN0IDEzNyAyCglidG9pCglpbnQgMQoJPj0KCWR1cAoJYnogKnNraXBfYW5kNQoJZnJhbWVfZGlnIC0xIC8vIGNvbmZpZzogVmFsaWRhdG9yQ29uZmlnCglleHRyYWN0IDEzNyAyCglidG9pCglpbnQgMTAwODAKCTw9CgkmJgoKKnNraXBfYW5kNToKCWFzc2VydAoKCS8vIGNvbnRyYWN0cy92YWxpZGF0b3JSZWdpc3RyeS5hbGdvLnRzOjEwOTEKCS8vIGFzc2VydChjb25maWcucGVyY2VudFRvVmFsaWRhdG9yID49IE1JTl9QQ1RfVE9fVkFMSURBVE9SICYmIGNvbmZpZy5wZXJjZW50VG9WYWxpZGF0b3IgPD0gTUFYX1BDVF9UT19WQUxJREFUT1IpCglmcmFtZV9kaWcgLTEgLy8gY29uZmlnOiBWYWxpZGF0b3JDb25maWcKCWV4dHJhY3QgMTM5IDQKCWJ0b2kKCWludCAwCgk+PQoJZHVwCglieiAqc2tpcF9hbmQ2CglmcmFtZV9kaWcgLTEgLy8gY29uZmlnOiBWYWxpZGF0b3JDb25maWcKCWV4dHJhY3QgMTM5IDQKCWJ0b2kKCWludCAxMDAwMDAwCgk8PQoJJiYKCipza2lwX2FuZDY6Cglhc3NlcnQKCgkvLyAqaWYzMF9jb25kaXRpb24KCS8vIGNvbnRyYWN0cy92YWxpZGF0b3JSZWdpc3RyeS5hbGdvLnRzOjEwOTIKCS8vIGNvbmZpZy5wZXJjZW50VG9WYWxpZGF0b3IgIT09IDAKCWZyYW1lX2RpZyAtMSAvLyBjb25maWc6IFZhbGlkYXRvckNvbmZpZwoJZXh0cmFjdCAxMzkgNAoJYnRvaQoJaW50IDAKCSE9CglieiAqaWYzMF9lbmQKCgkvLyAqaWYzMF9jb25zZXF1ZW50CgkvLyBjb250cmFjdHMvdmFsaWRhdG9yUmVnaXN0cnkuYWxnby50czoxMDkzCgkvLyBhc3NlcnQoCgkvLyAgICAgICAgICAgICAgICAgY29uZmlnLnZhbGlkYXRvckNvbW1pc3Npb25BZGRyZXNzICE9PSBBZGRyZXNzLnplcm9BZGRyZXNzLAoJLy8gICAgICAgICAgICAgICAgICd2YWxpZGF0b3JDb21taXNzaW9uQWRkcmVzcyBtdXN0IGJlIHNldCBpZiBwZXJjZW50IHRvIHZhbGlkYXRvciBpcyBub3QgMCcKCS8vICAgICAgICAgICAgICkKCWZyYW1lX2RpZyAtMSAvLyBjb25maWc6IFZhbGlkYXRvckNvbmZpZwoJZXh0cmFjdCAxNDMgMzIKCWdsb2JhbCBaZXJvQWRkcmVzcwoJIT0KCgkvLyB2YWxpZGF0b3JDb21taXNzaW9uQWRkcmVzcyBtdXN0IGJlIHNldCBpZiBwZXJjZW50IHRvIHZhbGlkYXRvciBpcyBub3QgMAoJYXNzZXJ0CgoqaWYzMF9lbmQ6CgkvLyBjb250cmFjdHMvdmFsaWRhdG9yUmVnaXN0cnkuYWxnby50czoxMDk4CgkvLyBhc3NlcnQoY29uZmlnLm1pbkVudHJ5U3Rha2UgPj0gTUlOX0FMR09fU1RBS0VfUEVSX1BPT0wpCglmcmFtZV9kaWcgLTEgLy8gY29uZmlnOiBWYWxpZGF0b3JDb25maWcKCWV4dHJhY3QgMTc1IDgKCWJ0b2kKCWludCAxMDAwMDAwCgk+PQoJYXNzZXJ0CgoJLy8gY29udHJhY3RzL3ZhbGlkYXRvclJlZ2lzdHJ5LmFsZ28udHM6MTEwMAoJLy8gYXNzZXJ0KGNvbmZpZy5wb29sc1Blck5vZGUgPiAwICYmIGNvbmZpZy5wb29sc1Blck5vZGUgPD0gTUFYX1BPT0xTX1BFUl9OT0RFKQoJZnJhbWVfZGlnIC0xIC8vIGNvbmZpZzogVmFsaWRhdG9yQ29uZmlnCglleHRyYWN0IDE5MSAxCglidG9pCglpbnQgMAoJPgoJZHVwCglieiAqc2tpcF9hbmQ3CglmcmFtZV9kaWcgLTEgLy8gY29uZmlnOiBWYWxpZGF0b3JDb25maWcKCWV4dHJhY3QgMTkxIDEKCWJ0b2kKCWludCAzCgk8PQoJJiYKCipza2lwX2FuZDc6Cglhc3NlcnQKCXJldHN1YgoKLy8gY2FsbFBvb2xBZGRTdGFrZShzdGFrZWRBbW91bnRQYXltZW50OiBQYXlUeG4sIHBvb2xLZXk6IFZhbGlkYXRvclBvb2xLZXksIG1ickFtdFBhaWQ6IHVpbnQ2NCwgaXNOZXdTdGFrZXJUb1ZhbGlkYXRvcjogYm9vbGVhbiwgaXNOZXdTdGFrZXJUb1Byb3RvY29sOiBib29sZWFuKTogdm9pZAovLwovLyBBZGRzIGEgc3Rha2VycyBhbW91bnQgb2YgYWxnbyB0byBhIHZhbGlkYXRvciBwb29sLCB0cmFuc2ZlcnJpbmcgdGhlIGFsZ28gd2UgcmVjZWl2ZWQgZnJvbSB0aGVtIChhbHJlYWR5IHZlcmlmaWVkCi8vIGJ5IG91ciBjYWxsZXIpIHRvIHRoZSBzdGFraW5nIHBvb2wgYWNjb3VudCwgYW5kIHRoZW4gdGVsbGluZyBpdCBhYm91dCB0aGUgYW1vdW50IGJlaW5nIGFkZGVkIGZvciB0aGUgc3BlY2lmaWVkCi8vIHN0YWtlci4KLy8KLy8gQHBhcmFtIHtQYXlUeG59IHN0YWtlZEFtb3VudFBheW1lbnQgLSBwYXltZW50IGNvbWluZyBmcm9tIHN0YWtlciB0byBwbGFjZSBpbnRvIGEgcG9vbAovLyBAcGFyYW0ge1ZhbGlkYXRvclBvb2xLZXl9IHBvb2xLZXkgLSBUaGUga2V5IG9mIHRoZSB2YWxpZGF0b3IgcG9vbC4KLy8gQHBhcmFtIHt1aW50NjR9IG1ickFtdFBhaWQgLSBBbW91bnQgdGhlIHVzZXIgaXMgbGVhdmluZyBiZWhpbmQgaW4gdGhlIHZhbGlkYXRvciB0byBwYXkgZm9yIHRoZWlyIHN0YWtlciBNQlIgY29zdAovLyBAcGFyYW0ge2Jvb2xlYW59IGlzTmV3U3Rha2VyVG9WYWxpZGF0b3IgLSBpZiB0aGlzIGlzIGEgbmV3LCBmaXJzdC10aW1lIHN0YWtlciB0byB0aGUgdmFsaWRhdG9yCi8vIEBwYXJhbSB7Ym9vbGVhbn0gaXNOZXdTdGFrZXJUb1Byb3RvY29sIC0gaWYgdGhpcyBpcyBhIG5ldywgZmlyc3QtdGltZSBzdGFrZXIgdG8gdGhlIHByb3RvY29sCmNhbGxQb29sQWRkU3Rha2U6Cglwcm90byA1IDAKCgkvLyBQdXNoIGVtcHR5IGJ5dGVzIGFmdGVyIHRoZSBmcmFtZSBwb2ludGVyIHRvIHJlc2VydmUgc3BhY2UgZm9yIGxvY2FsIHZhcmlhYmxlcwoJYnl0ZSAweAoJZHVwbiAyCgoJLy8gKmlmMzFfY29uZGl0aW9uCgkvLyBjb250cmFjdHMvdmFsaWRhdG9yUmVnaXN0cnkuYWxnby50czoxMTIxCgkvLyBnbG9iYWxzLm9wY29kZUJ1ZGdldCA8IDUwMAoJZ2xvYmFsIE9wY29kZUJ1ZGdldAoJaW50IDUwMAoJPAoJYnogKmlmMzFfZW5kCgoJLy8gKmlmMzFfY29uc2VxdWVudAoJLy8gY29udHJhY3RzL3ZhbGlkYXRvclJlZ2lzdHJ5LmFsZ28udHM6MTEyMgoJLy8gaW5jcmVhc2VPcGNvZGVCdWRnZXQoKQoJaXR4bl9iZWdpbgoJaW50IGFwcGwKCWl0eG5fZmllbGQgVHlwZUVudW0KCWludCAwCglpdHhuX2ZpZWxkIEZlZQoJYnl0ZSBiNjQgQ29FQiAvLyAjcHJhZ21hIHZlcnNpb24gMTA7IGludCAxCglkdXAKCWl0eG5fZmllbGQgQXBwcm92YWxQcm9ncmFtCglpdHhuX2ZpZWxkIENsZWFyU3RhdGVQcm9ncmFtCglpbnQgRGVsZXRlQXBwbGljYXRpb24KCWl0eG5fZmllbGQgT25Db21wbGV0aW9uCglpdHhuX3N1Ym1pdAoKKmlmMzFfZW5kOgoJLy8gY29udHJhY3RzL3ZhbGlkYXRvclJlZ2lzdHJ5LmFsZ28udHM6MTEyNAoJLy8gcG9vbEFwcElkID0gdGhpcy52YWxpZGF0b3JMaXN0KHBvb2xLZXkuaWQpLnZhbHVlLnBvb2xzW3Bvb2xLZXkucG9vbElkIC0gMV0ucG9vbEFwcElkCglpbnQgMjM0IC8vIGhlYWRPZmZzZXQKCWZyYW1lX2RpZyAtMiAvLyBwb29sS2V5OiBWYWxpZGF0b3JQb29sS2V5CglleHRyYWN0IDggOAoJYnRvaQoJaW50IDEKCS0KCWludCAxOAoJKiAvLyBhY2MgKiB0eXBlTGVuZ3RoCgkrCglpbnQgMAoJKwoJaW50IDgKCWJ5dGUgMHg3NiAvLyAidiIKCWZyYW1lX2RpZyAtMiAvLyBwb29sS2V5OiBWYWxpZGF0b3JQb29sS2V5CglleHRyYWN0IDAgOAoJYnRvaQoJaXRvYgoJY29uY2F0Cgljb3ZlciAyCglib3hfZXh0cmFjdAoJYnRvaQoJZnJhbWVfYnVyeSAwIC8vIHBvb2xBcHBJZDogdWludDY0CgoJLy8gY29udHJhY3RzL3ZhbGlkYXRvclJlZ2lzdHJ5LmFsZ28udHM6MTEyOAoJLy8gc2VuZE1ldGhvZENhbGw8dHlwZW9mIFN0YWtpbmdQb29sLnByb3RvdHlwZS5hZGRTdGFrZT4oewoJLy8gICAgICAgICAgICAgYXBwbGljYXRpb25JRDogQXBwSUQuZnJvbVVpbnQ2NChwb29sQXBwSWQpLAoJLy8gICAgICAgICAgICAgbWV0aG9kQXJnczogWwoJLy8gICAgICAgICAgICAgICAgIC8vID09PT09PT0KCS8vICAgICAgICAgICAgICAgICAvLyBUSElTIElTIEEgU0VORCBvZiB0aGUgYW1vdW50IHJlY2VpdmVkIHJpZ2h0IGJhY2sgb3V0IGFuZCBpbnRvIHRoZSBzdGFraW5nIHBvb2wgY29udHJhY3QgYWNjb3VudC4KCS8vICAgICAgICAgICAgICAgICB7IGFtb3VudDogc3Rha2VkQW1vdW50UGF5bWVudC5hbW91bnQgLSBtYnJBbXRQYWlkLCByZWNlaXZlcjogQXBwSUQuZnJvbVVpbnQ2NChwb29sQXBwSWQpLmFkZHJlc3MgfSwKCS8vICAgICAgICAgICAgICAgICAvLyA9PT09PT09CgkvLyAgICAgICAgICAgICAgICAgc3Rha2VkQW1vdW50UGF5bWVudC5zZW5kZXIsCgkvLyAgICAgICAgICAgICBdLAoJLy8gICAgICAgICB9KQoJaXR4bl9iZWdpbgoJaW50IHBheQoJaXR4bl9maWVsZCBUeXBlRW51bQoKCS8vIGNvbnRyYWN0cy92YWxpZGF0b3JSZWdpc3RyeS5hbGdvLnRzOjExMzMKCS8vIGFtb3VudDogc3Rha2VkQW1vdW50UGF5bWVudC5hbW91bnQgLSBtYnJBbXRQYWlkCglmcmFtZV9kaWcgLTEgLy8gc3Rha2VkQW1vdW50UGF5bWVudDogUGF5VHhuCglndHhucyBBbW91bnQKCWZyYW1lX2RpZyAtMyAvLyBtYnJBbXRQYWlkOiB1aW50NjQKCS0KCWl0eG5fZmllbGQgQW1vdW50CgoJLy8gY29udHJhY3RzL3ZhbGlkYXRvclJlZ2lzdHJ5LmFsZ28udHM6MTEzMwoJLy8gcmVjZWl2ZXI6IEFwcElELmZyb21VaW50NjQocG9vbEFwcElkKS5hZGRyZXNzCglmcmFtZV9kaWcgMCAvLyBwb29sQXBwSWQ6IHVpbnQ2NAoJYXBwX3BhcmFtc19nZXQgQXBwQWRkcmVzcwoJcG9wCglpdHhuX2ZpZWxkIFJlY2VpdmVyCgoJLy8gRmVlIGZpZWxkIG5vdCBzZXQsIGRlZmF1bHRpbmcgdG8gMAoJaW50IDAKCWl0eG5fZmllbGQgRmVlCglpdHhuX25leHQKCWludCBhcHBsCglpdHhuX2ZpZWxkIFR5cGVFbnVtCgltZXRob2QgImFkZFN0YWtlKHBheSxhZGRyZXNzKXVpbnQ2NCIKCWl0eG5fZmllbGQgQXBwbGljYXRpb25BcmdzCgoJLy8gY29udHJhY3RzL3ZhbGlkYXRvclJlZ2lzdHJ5LmFsZ28udHM6MTEyOQoJLy8gYXBwbGljYXRpb25JRDogQXBwSUQuZnJvbVVpbnQ2NChwb29sQXBwSWQpCglmcmFtZV9kaWcgMCAvLyBwb29sQXBwSWQ6IHVpbnQ2NAoJaXR4bl9maWVsZCBBcHBsaWNhdGlvbklECgoJLy8gY29udHJhY3RzL3ZhbGlkYXRvclJlZ2lzdHJ5LmFsZ28udHM6MTEzMAoJLy8gbWV0aG9kQXJnczogWwoJLy8gICAgICAgICAgICAgICAgIC8vID09PT09PT0KCS8vICAgICAgICAgICAgICAgICAvLyBUSElTIElTIEEgU0VORCBvZiB0aGUgYW1vdW50IHJlY2VpdmVkIHJpZ2h0IGJhY2sgb3V0IGFuZCBpbnRvIHRoZSBzdGFraW5nIHBvb2wgY29udHJhY3QgYWNjb3VudC4KCS8vICAgICAgICAgICAgICAgICB7IGFtb3VudDogc3Rha2VkQW1vdW50UGF5bWVudC5hbW91bnQgLSBtYnJBbXRQYWlkLCByZWNlaXZlcjogQXBwSUQuZnJvbVVpbnQ2NChwb29sQXBwSWQpLmFkZHJlc3MgfSwKCS8vICAgICAgICAgICAgICAgICAvLyA9PT09PT09CgkvLyAgICAgICAgICAgICAgICAgc3Rha2VkQW1vdW50UGF5bWVudC5zZW5kZXIsCgkvLyAgICAgICAgICAgICBdCglmcmFtZV9kaWcgLTEgLy8gc3Rha2VkQW1vdW50UGF5bWVudDogUGF5VHhuCglndHhucyBTZW5kZXIKCWl0eG5fZmllbGQgQXBwbGljYXRpb25BcmdzCgoJLy8gRmVlIGZpZWxkIG5vdCBzZXQsIGRlZmF1bHRpbmcgdG8gMAoJaW50IDAKCWl0eG5fZmllbGQgRmVlCgoJLy8gU3VibWl0IGlubmVyIHRyYW5zYWN0aW9uCglpdHhuX3N1Ym1pdAoJaXR4biBOdW1Mb2dzCglpbnQgMQoJLQoJaXR4bmFzIExvZ3MKCWV4dHJhY3QgNCAwCglidG9pCgoJLy8gY29udHJhY3RzL3ZhbGlkYXRvclJlZ2lzdHJ5LmFsZ28udHM6MTE0MAoJLy8gcG9vbE51bVN0YWtlcnMgPSBBcHBJRC5mcm9tVWludDY0KHBvb2xBcHBJZCkuZ2xvYmFsU3RhdGUoJ251bVN0YWtlcnMnKSBhcyB1aW50NjQKCWZyYW1lX2RpZyAwIC8vIHBvb2xBcHBJZDogdWludDY0CglieXRlIDB4NmU3NTZkNTM3NDYxNmI2NTcyNzMgLy8gIm51bVN0YWtlcnMiCglhcHBfZ2xvYmFsX2dldF9leAoJYXNzZXJ0CglmcmFtZV9idXJ5IDEgLy8gcG9vbE51bVN0YWtlcnM6IHVpbnQ2NAoKCS8vIGNvbnRyYWN0cy92YWxpZGF0b3JSZWdpc3RyeS5hbGdvLnRzOjExNDEKCS8vIHBvb2xBbGdvU3Rha2VkID0gQXBwSUQuZnJvbVVpbnQ2NChwb29sQXBwSWQpLmdsb2JhbFN0YXRlKCdzdGFrZWQnKSBhcyB1aW50NjQKCWZyYW1lX2RpZyAwIC8vIHBvb2xBcHBJZDogdWludDY0CglieXRlIDB4NzM3NDYxNmI2NTY0IC8vICJzdGFrZWQiCglhcHBfZ2xvYmFsX2dldF9leAoJYXNzZXJ0CglmcmFtZV9idXJ5IDIgLy8gcG9vbEFsZ29TdGFrZWQ6IHVpbnQ2NAoKCS8vIGNvbnRyYWN0cy92YWxpZGF0b3JSZWdpc3RyeS5hbGdvLnRzOjExNDIKCS8vIHRoaXMudmFsaWRhdG9yTGlzdChwb29sS2V5LmlkKS52YWx1ZS5wb29sc1twb29sS2V5LnBvb2xJZCAtIDFdLnRvdGFsU3Rha2VycyA9IHBvb2xOdW1TdGFrZXJzIGFzIHVpbnQxNgoJaW50IDIzNCAvLyBoZWFkT2Zmc2V0CglmcmFtZV9kaWcgLTIgLy8gcG9vbEtleTogVmFsaWRhdG9yUG9vbEtleQoJZXh0cmFjdCA4IDgKCWJ0b2kKCWludCAxCgktCglpbnQgMTgKCSogLy8gYWNjICogdHlwZUxlbmd0aAoJKwoJaW50IDggLy8gaGVhZE9mZnNldAoJKwoJZnJhbWVfZGlnIDEgLy8gcG9vbE51bVN0YWtlcnM6IHVpbnQ2NAoJaXRvYgoJZXh0cmFjdCA2IDIKCWJ5dGUgMHg3NiAvLyAidiIKCWZyYW1lX2RpZyAtMiAvLyBwb29sS2V5OiBWYWxpZGF0b3JQb29sS2V5CglleHRyYWN0IDAgOAoJYnRvaQoJaXRvYgoJY29uY2F0Cgljb3ZlciAyCglib3hfcmVwbGFjZQoKCS8vIGNvbnRyYWN0cy92YWxpZGF0b3JSZWdpc3RyeS5hbGdvLnRzOjExNDMKCS8vIHRoaXMudmFsaWRhdG9yTGlzdChwb29sS2V5LmlkKS52YWx1ZS5wb29sc1twb29sS2V5LnBvb2xJZCAtIDFdLnRvdGFsQWxnb1N0YWtlZCA9IHBvb2xBbGdvU3Rha2VkCglpbnQgMjM0IC8vIGhlYWRPZmZzZXQKCWZyYW1lX2RpZyAtMiAvLyBwb29sS2V5OiBWYWxpZGF0b3JQb29sS2V5CglleHRyYWN0IDggOAoJYnRvaQoJaW50IDEKCS0KCWludCAxOAoJKiAvLyBhY2MgKiB0eXBlTGVuZ3RoCgkrCglpbnQgMTAgLy8gaGVhZE9mZnNldAoJKwoJZnJhbWVfZGlnIDIgLy8gcG9vbEFsZ29TdGFrZWQ6IHVpbnQ2NAoJaXRvYgoJYnl0ZSAweDc2IC8vICJ2IgoJZnJhbWVfZGlnIC0yIC8vIHBvb2xLZXk6IFZhbGlkYXRvclBvb2xLZXkKCWV4dHJhY3QgMCA4CglidG9pCglpdG9iCgljb25jYXQKCWNvdmVyIDIKCWJveF9yZXBsYWNlCgoJLy8gKmlmMzJfY29uZGl0aW9uCgkvLyBjb250cmFjdHMvdmFsaWRhdG9yUmVnaXN0cnkuYWxnby50czoxMTQ2CgkvLyBpc05ld1N0YWtlclRvVmFsaWRhdG9yCglmcmFtZV9kaWcgLTQgLy8gaXNOZXdTdGFrZXJUb1ZhbGlkYXRvcjogYm9vbGVhbgoJYnogKmlmMzJfZW5kCgoJLy8gKmlmMzJfY29uc2VxdWVudAoJLy8gY29udHJhY3RzL3ZhbGlkYXRvclJlZ2lzdHJ5LmFsZ28udHM6MTE0NwoJLy8gdGhpcy52YWxpZGF0b3JMaXN0KHBvb2xLZXkuaWQpLnZhbHVlLnN0YXRlLnRvdGFsU3Rha2VycyArPSAxCglpbnQgMjEwCglkdXAKCWludCA4CglieXRlIDB4NzYgLy8gInYiCglmcmFtZV9kaWcgLTIgLy8gcG9vbEtleTogVmFsaWRhdG9yUG9vbEtleQoJZXh0cmFjdCAwIDgKCWJ0b2kKCWl0b2IKCWNvbmNhdAoJY292ZXIgMgoJYm94X2V4dHJhY3QKCWJ0b2kKCWludCAxCgkrCglpdG9iCglieXRlIDB4NzYgLy8gInYiCglmcmFtZV9kaWcgLTIgLy8gcG9vbEtleTogVmFsaWRhdG9yUG9vbEtleQoJZXh0cmFjdCAwIDgKCWJ0b2kKCWl0b2IKCWNvbmNhdAoJY292ZXIgMgoJYm94X3JlcGxhY2UKCippZjMyX2VuZDoKCS8vICppZjMzX2NvbmRpdGlvbgoJLy8gY29udHJhY3RzL3ZhbGlkYXRvclJlZ2lzdHJ5LmFsZ28udHM6MTE0OQoJLy8gaXNOZXdTdGFrZXJUb1Byb3RvY29sCglmcmFtZV9kaWcgLTUgLy8gaXNOZXdTdGFrZXJUb1Byb3RvY29sOiBib29sZWFuCglieiAqaWYzM19lbmQKCgkvLyAqaWYzM19jb25zZXF1ZW50CgkvLyBjb250cmFjdHMvdmFsaWRhdG9yUmVnaXN0cnkuYWxnby50czoxMTUwCgkvLyB0aGlzLm51bVN0YWtlcnMudmFsdWUgKz0gMQoJYnl0ZSAweDZlNzU2ZDUzNzQ2MTZiNjU3MjczIC8vICJudW1TdGFrZXJzIgoJYXBwX2dsb2JhbF9nZXQKCWludCAxCgkrCglieXRlIDB4NmU3NTZkNTM3NDYxNmI2NTcyNzMgLy8gIm51bVN0YWtlcnMiCglzd2FwCglhcHBfZ2xvYmFsX3B1dAoKKmlmMzNfZW5kOgoJLy8gY29udHJhY3RzL3ZhbGlkYXRvclJlZ2lzdHJ5LmFsZ28udHM6MTE1MgoJLy8gdGhpcy52YWxpZGF0b3JMaXN0KHBvb2xLZXkuaWQpLnZhbHVlLnN0YXRlLnRvdGFsQWxnb1N0YWtlZCArPSBzdGFrZWRBbW91bnRQYXltZW50LmFtb3VudCAtIG1ickFtdFBhaWQKCWludCAyMTgKCWR1cAoJaW50IDgKCWJ5dGUgMHg3NiAvLyAidiIKCWZyYW1lX2RpZyAtMiAvLyBwb29sS2V5OiBWYWxpZGF0b3JQb29sS2V5CglleHRyYWN0IDAgOAoJYnRvaQoJaXRvYgoJY29uY2F0Cgljb3ZlciAyCglib3hfZXh0cmFjdAoJYnRvaQoJZnJhbWVfZGlnIC0xIC8vIHN0YWtlZEFtb3VudFBheW1lbnQ6IFBheVR4bgoJZ3R4bnMgQW1vdW50CglmcmFtZV9kaWcgLTMgLy8gbWJyQW10UGFpZDogdWludDY0CgktCgkrCglpdG9iCglieXRlIDB4NzYgLy8gInYiCglmcmFtZV9kaWcgLTIgLy8gcG9vbEtleTogVmFsaWRhdG9yUG9vbEtleQoJZXh0cmFjdCAwIDgKCWJ0b2kKCWl0b2IKCWNvbmNhdAoJY292ZXIgMgoJYm94X3JlcGxhY2UKCgkvLyBjb250cmFjdHMvdmFsaWRhdG9yUmVnaXN0cnkuYWxnby50czoxMTUzCgkvLyB0aGlzLnRvdGFsQWxnb1N0YWtlZC52YWx1ZSArPSBzdGFrZWRBbW91bnRQYXltZW50LmFtb3VudCAtIG1ickFtdFBhaWQKCWJ5dGUgMHg3Mzc0NjE2YjY1NjQgLy8gInN0YWtlZCIKCWFwcF9nbG9iYWxfZ2V0CglmcmFtZV9kaWcgLTEgLy8gc3Rha2VkQW1vdW50UGF5bWVudDogUGF5VHhuCglndHhucyBBbW91bnQKCWZyYW1lX2RpZyAtMyAvLyBtYnJBbXRQYWlkOiB1aW50NjQKCS0KCSsKCWJ5dGUgMHg3Mzc0NjE2YjY1NjQgLy8gInN0YWtlZCIKCXN3YXAKCWFwcF9nbG9iYWxfcHV0CglyZXRzdWIKCi8vIHVwZGF0ZVN0YWtlclBvb2xTZXQoc3Rha2VyOiBBZGRyZXNzLCBwb29sS2V5OiBWYWxpZGF0b3JQb29sS2V5KTogdm9pZAp1cGRhdGVTdGFrZXJQb29sU2V0OgoJcHJvdG8gMiAwCgoJLy8gUHVzaCBlbXB0eSBieXRlcyBhZnRlciB0aGUgZnJhbWUgcG9pbnRlciB0byByZXNlcnZlIHNwYWNlIGZvciBsb2NhbCB2YXJpYWJsZXMKCWJ5dGUgMHgKCWR1cAoKCS8vIGNvbnRyYWN0cy92YWxpZGF0b3JSZWdpc3RyeS5hbGdvLnRzOjExNTcKCS8vIGFzc2VydCh0aGlzLnN0YWtlclBvb2xTZXQoc3Rha2VyKS5leGlzdHMpCglieXRlIDB4NzM3MDczIC8vICJzcHMiCglmcmFtZV9kaWcgLTEgLy8gc3Rha2VyOiBBZGRyZXNzCgljb25jYXQKCWJveF9sZW4KCXN3YXAKCXBvcAoJYXNzZXJ0CgoJLy8gY29udHJhY3RzL3ZhbGlkYXRvclJlZ2lzdHJ5LmFsZ28udHM6MTE1OQoJLy8gcG9vbFNldCA9IGNsb25lKHRoaXMuc3Rha2VyUG9vbFNldChzdGFrZXIpLnZhbHVlKQoJYnl0ZSAweDczNzA3MyAvLyAic3BzIgoJZnJhbWVfZGlnIC0xIC8vIHN0YWtlcjogQWRkcmVzcwoJY29uY2F0Cglib3hfZ2V0Cglhc3NlcnQKCWZyYW1lX2J1cnkgMCAvLyBwb29sU2V0OiAodWludDY0LHVpbnQ2NCx1aW50NjQpWzZdCgoJLy8gY29udHJhY3RzL3ZhbGlkYXRvclJlZ2lzdHJ5LmFsZ28udHM6MTE2MAoJLy8gZm9yIChsZXQgaSA9IDA7IGkgPCB0aGlzLnN0YWtlclBvb2xTZXQoc3Rha2VyKS52YWx1ZS5sZW5ndGg7IGkgKz0gMSkKCWludCAwCglmcmFtZV9idXJ5IDEgLy8gaTogdWludDY0CgoqZm9yXzc6CgkvLyBjb250cmFjdHMvdmFsaWRhdG9yUmVnaXN0cnkuYWxnby50czoxMTYwCgkvLyBpIDwgdGhpcy5zdGFrZXJQb29sU2V0KHN0YWtlcikudmFsdWUubGVuZ3RoCglmcmFtZV9kaWcgMSAvLyBpOiB1aW50NjQKCWludCA2Cgk8CglieiAqZm9yXzdfZW5kCgoJLy8gKmlmMzRfY29uZGl0aW9uCgkvLyBjb250cmFjdHMvdmFsaWRhdG9yUmVnaXN0cnkuYWxnby50czoxMTYxCgkvLyBwb29sU2V0W2ldID09PSBwb29sS2V5CglmcmFtZV9kaWcgMCAvLyBwb29sU2V0OiAodWludDY0LHVpbnQ2NCx1aW50NjQpWzZdCglmcmFtZV9kaWcgMSAvLyBpOiB1aW50NjQKCWludCAyNAoJKiAvLyBhY2MgKiB0eXBlTGVuZ3RoCglpbnQgMjQKCWV4dHJhY3QzCglmcmFtZV9kaWcgLTIgLy8gcG9vbEtleTogVmFsaWRhdG9yUG9vbEtleQoJPT0KCWJ6ICppZjM0X2VuZAoKCS8vICppZjM0X2NvbnNlcXVlbnQKCS8vIGNvbnRyYWN0cy92YWxpZGF0b3JSZWdpc3RyeS5hbGdvLnRzOjExNjMKCS8vIHJldHVybjsKCXJldHN1YgoKKmlmMzRfZW5kOgoJLy8gKmlmMzVfY29uZGl0aW9uCgkvLyBjb250cmFjdHMvdmFsaWRhdG9yUmVnaXN0cnkuYWxnby50czoxMTY1CgkvLyBwb29sU2V0W2ldLmlkID09PSAwCglmcmFtZV9kaWcgMCAvLyBwb29sU2V0OiAodWludDY0LHVpbnQ2NCx1aW50NjQpWzZdCglmcmFtZV9kaWcgMSAvLyBpOiB1aW50NjQKCWludCAyNAoJKiAvLyBhY2MgKiB0eXBlTGVuZ3RoCglpbnQgMAoJKwoJaW50IDgKCWV4dHJhY3QzCglidG9pCglpbnQgMAoJPT0KCWJ6ICppZjM1X2VuZAoKCS8vICppZjM1X2NvbnNlcXVlbnQKCS8vIGNvbnRyYWN0cy92YWxpZGF0b3JSZWdpc3RyeS5hbGdvLnRzOjExNjYKCS8vIHRoaXMuc3Rha2VyUG9vbFNldChzdGFrZXIpLnZhbHVlW2ldID0gcG9vbEtleQoJZnJhbWVfZGlnIDEgLy8gaTogdWludDY0CglpbnQgMjQKCSogLy8gYWNjICogdHlwZUxlbmd0aAoJZnJhbWVfZGlnIC0yIC8vIHBvb2xLZXk6IFZhbGlkYXRvclBvb2xLZXkKCWJ5dGUgMHg3MzcwNzMgLy8gInNwcyIKCWZyYW1lX2RpZyAtMSAvLyBzdGFrZXI6IEFkZHJlc3MKCWNvbmNhdAoJY292ZXIgMgoJYm94X3JlcGxhY2UKCgkvLyBjb250cmFjdHMvdmFsaWRhdG9yUmVnaXN0cnkuYWxnby50czoxMTY3CgkvLyByZXR1cm47CglyZXRzdWIKCippZjM1X2VuZDoKCipmb3JfN19jb250aW51ZToKCS8vIGNvbnRyYWN0cy92YWxpZGF0b3JSZWdpc3RyeS5hbGdvLnRzOjExNjAKCS8vIGkgKz0gMQoJZnJhbWVfZGlnIDEgLy8gaTogdWludDY0CglpbnQgMQoJKwoJZnJhbWVfYnVyeSAxIC8vIGk6IHVpbnQ2NAoJYiAqZm9yXzcKCipmb3JfN19lbmQ6CgllcnIgLy8gJ05vIGVtcHR5IHNsb3QgYXZhaWxhYmxlIGluIHRoZSBzdGFrZXIgcG9vbCBzZXQnCgovLyByZW1vdmVGcm9tU3Rha2VyUG9vbFNldChzdGFrZXI6IEFkZHJlc3MsIHBvb2xLZXk6IFZhbGlkYXRvclBvb2xLZXkpOiBbYm9vbGVhbiwgYm9vbGVhbl0KLy8KLy8gUmVtb3ZlcyBhIHBvb2wga2V5IGZyb20gdGhlIHN0YWtlcidzIGFjdGl2ZSBwb29sIHNldCAtIGZhaWxzIGlmIG5vdCBmb3VuZCAoISkKLy8KLy8gQHBhcmFtIHtBZGRyZXNzfSBzdGFrZXIgLSBUaGUgYWRkcmVzcyBvZiB0aGUgc3Rha2VyLgovLyBAcGFyYW0ge1ZhbGlkYXRvclBvb2xLZXl9IHBvb2xLZXkgLSBUaGUgcG9vbCBrZXkgdGhleSBzaG91bGQgYmUgc3RvcmVkIGluCi8vCi8vIEByZXR1cm4gW2Jvb2xlYW4sIGJvb2xlYW5dIFtpcyB0aGUgc3Rha2VyIGdvbmUgZnJvbSBBTEwgcG9vbHMgb2YgdGhlIGdpdmVuIFZBTElEQVRPUiwgYW5kIGlzIHN0YWtlciBnb25lIGZyb20gQUxMIHBvb2xzXQpyZW1vdmVGcm9tU3Rha2VyUG9vbFNldDoKCXByb3RvIDIgMQoKCS8vIFB1c2ggZW1wdHkgYnl0ZXMgYWZ0ZXIgdGhlIGZyYW1lIHBvaW50ZXIgdG8gcmVzZXJ2ZSBzcGFjZSBmb3IgbG9jYWwgdmFyaWFibGVzCglieXRlIDB4CglkdXBuIDQKCgkvLyBjb250cmFjdHMvdmFsaWRhdG9yUmVnaXN0cnkuYWxnby50czoxMTgzCgkvLyBpblNhbWVWYWxpZGF0b3JQb29sQ291bnQgPSAwCglpbnQgMAoJZnJhbWVfYnVyeSAwIC8vIGluU2FtZVZhbGlkYXRvclBvb2xDb3VudDogdWludDY0CgoJLy8gY29udHJhY3RzL3ZhbGlkYXRvclJlZ2lzdHJ5LmFsZ28udHM6MTE4NAoJLy8gaW5BbnlQb29sQ291bnQgPSAwCglpbnQgMAoJZnJhbWVfYnVyeSAxIC8vIGluQW55UG9vbENvdW50OiB1aW50NjQKCgkvLyBjb250cmFjdHMvdmFsaWRhdG9yUmVnaXN0cnkuYWxnby50czoxMTg1CgkvLyBmb3VuZCA9IGZhbHNlCglpbnQgMAoJZnJhbWVfYnVyeSAyIC8vIGZvdW5kOiBib29sCgoJLy8gY29udHJhY3RzL3ZhbGlkYXRvclJlZ2lzdHJ5LmFsZ28udHM6MTE4NwoJLy8gcG9vbFNldCA9IGNsb25lKHRoaXMuc3Rha2VyUG9vbFNldChzdGFrZXIpLnZhbHVlKQoJYnl0ZSAweDczNzA3MyAvLyAic3BzIgoJZnJhbWVfZGlnIC0xIC8vIHN0YWtlcjogQWRkcmVzcwoJY29uY2F0Cglib3hfZ2V0Cglhc3NlcnQKCWZyYW1lX2J1cnkgMyAvLyBwb29sU2V0OiAodWludDY0LHVpbnQ2NCx1aW50NjQpWzZdCgoJLy8gY29udHJhY3RzL3ZhbGlkYXRvclJlZ2lzdHJ5LmFsZ28udHM6MTE4OAoJLy8gZm9yIChsZXQgaSA9IDA7IGkgPCB0aGlzLnN0YWtlclBvb2xTZXQoc3Rha2VyKS52YWx1ZS5sZW5ndGg7IGkgKz0gMSkKCWludCAwCglmcmFtZV9idXJ5IDQgLy8gaTogdWludDY0CgoqZm9yXzg6CgkvLyBjb250cmFjdHMvdmFsaWRhdG9yUmVnaXN0cnkuYWxnby50czoxMTg4CgkvLyBpIDwgdGhpcy5zdGFrZXJQb29sU2V0KHN0YWtlcikudmFsdWUubGVuZ3RoCglmcmFtZV9kaWcgNCAvLyBpOiB1aW50NjQKCWludCA2Cgk8CglieiAqZm9yXzhfZW5kCgoJLy8gKmlmMzZfY29uZGl0aW9uCgkvLyBjb250cmFjdHMvdmFsaWRhdG9yUmVnaXN0cnkuYWxnby50czoxMTg5CgkvLyBwb29sU2V0W2ldLmlkID09PSAwCglmcmFtZV9kaWcgMyAvLyBwb29sU2V0OiAodWludDY0LHVpbnQ2NCx1aW50NjQpWzZdCglmcmFtZV9kaWcgNCAvLyBpOiB1aW50NjQKCWludCAyNAoJKiAvLyBhY2MgKiB0eXBlTGVuZ3RoCglpbnQgMAoJKwoJaW50IDgKCWV4dHJhY3QzCglidG9pCglpbnQgMAoJPT0KCWJ6ICppZjM2X2VuZAoKCS8vICppZjM2X2NvbnNlcXVlbnQKCWIgKmZvcl84X2NvbnRpbnVlCgoqaWYzNl9lbmQ6CgkvLyBjb250cmFjdHMvdmFsaWRhdG9yUmVnaXN0cnkuYWxnby50czoxMTkyCgkvLyBpbkFueVBvb2xDb3VudCArPSAxCglmcmFtZV9kaWcgMSAvLyBpbkFueVBvb2xDb3VudDogdWludDY0CglpbnQgMQoJKwoJZnJhbWVfYnVyeSAxIC8vIGluQW55UG9vbENvdW50OiB1aW50NjQKCgkvLyAqaWYzN19jb25kaXRpb24KCS8vIGNvbnRyYWN0cy92YWxpZGF0b3JSZWdpc3RyeS5hbGdvLnRzOjExOTMKCS8vIHBvb2xTZXRbaV0uaWQgPT09IHBvb2xLZXkuaWQKCWZyYW1lX2RpZyAzIC8vIHBvb2xTZXQ6ICh1aW50NjQsdWludDY0LHVpbnQ2NClbNl0KCWZyYW1lX2RpZyA0IC8vIGk6IHVpbnQ2NAoJaW50IDI0CgkqIC8vIGFjYyAqIHR5cGVMZW5ndGgKCWludCAwCgkrCglpbnQgOAoJZXh0cmFjdDMKCWJ0b2kKCWZyYW1lX2RpZyAtMiAvLyBwb29sS2V5OiBWYWxpZGF0b3JQb29sS2V5CglleHRyYWN0IDAgOAoJYnRvaQoJPT0KCWJ6ICppZjM3X2VuZAoKCS8vICppZjM3X2NvbnNlcXVlbnQKCS8vICppZjM4X2NvbmRpdGlvbgoJLy8gY29udHJhY3RzL3ZhbGlkYXRvclJlZ2lzdHJ5LmFsZ28udHM6MTE5NAoJLy8gcG9vbFNldFtpXSA9PT0gcG9vbEtleQoJZnJhbWVfZGlnIDMgLy8gcG9vbFNldDogKHVpbnQ2NCx1aW50NjQsdWludDY0KVs2XQoJZnJhbWVfZGlnIDQgLy8gaTogdWludDY0CglpbnQgMjQKCSogLy8gYWNjICogdHlwZUxlbmd0aAoJaW50IDI0CglleHRyYWN0MwoJZnJhbWVfZGlnIC0yIC8vIHBvb2xLZXk6IFZhbGlkYXRvclBvb2xLZXkKCT09CglieiAqaWYzOF9lbHNlCgoJLy8gKmlmMzhfY29uc2VxdWVudAoJLy8gY29udHJhY3RzL3ZhbGlkYXRvclJlZ2lzdHJ5LmFsZ28udHM6MTE5NQoJLy8gZm91bmQgPSB0cnVlCglpbnQgMQoJZnJhbWVfYnVyeSAyIC8vIGZvdW5kOiBib29sCgoJLy8gY29udHJhY3RzL3ZhbGlkYXRvclJlZ2lzdHJ5LmFsZ28udHM6MTE5NwoJLy8gdGhpcy5zdGFrZXJQb29sU2V0KHN0YWtlcikudmFsdWVbaV0gPSB7IGlkOiAwLCBwb29sSWQ6IDAsIHBvb2xBcHBJZDogMCB9CglmcmFtZV9kaWcgNCAvLyBpOiB1aW50NjQKCWludCAyNAoJKiAvLyBhY2MgKiB0eXBlTGVuZ3RoCglieXRlIDB4MDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwCglieXRlIDB4NzM3MDczIC8vICJzcHMiCglmcmFtZV9kaWcgLTEgLy8gc3Rha2VyOiBBZGRyZXNzCgljb25jYXQKCWNvdmVyIDIKCWJveF9yZXBsYWNlCgliICppZjM4X2VuZAoKKmlmMzhfZWxzZToKCS8vIGNvbnRyYWN0cy92YWxpZGF0b3JSZWdpc3RyeS5hbGdvLnRzOjExOTkKCS8vIGluU2FtZVZhbGlkYXRvclBvb2xDb3VudCArPSAxCglmcmFtZV9kaWcgMCAvLyBpblNhbWVWYWxpZGF0b3JQb29sQ291bnQ6IHVpbnQ2NAoJaW50IDEKCSsKCWZyYW1lX2J1cnkgMCAvLyBpblNhbWVWYWxpZGF0b3JQb29sQ291bnQ6IHVpbnQ2NAoKKmlmMzhfZW5kOgoKKmlmMzdfZW5kOgoKKmZvcl84X2NvbnRpbnVlOgoJLy8gY29udHJhY3RzL3ZhbGlkYXRvclJlZ2lzdHJ5LmFsZ28udHM6MTE4OAoJLy8gaSArPSAxCglmcmFtZV9kaWcgNCAvLyBpOiB1aW50NjQKCWludCAxCgkrCglmcmFtZV9idXJ5IDQgLy8gaTogdWludDY0CgliICpmb3JfOAoKKmZvcl84X2VuZDoKCS8vICppZjM5X2NvbmRpdGlvbgoJLy8gY29udHJhY3RzL3ZhbGlkYXRvclJlZ2lzdHJ5LmFsZ28udHM6MTIwMwoJLy8gIWZvdW5kCglmcmFtZV9kaWcgMiAvLyBmb3VuZDogYm9vbAoJIQoJYnogKmlmMzlfZW5kCgoJLy8gKmlmMzlfY29uc2VxdWVudAoJZXJyIC8vICdObyBtYXRjaGluZyBzbG90IGZvdW5kIHdoZW4gdG9sZCB0byByZW1vdmUgYSBwb29sIGZyb20gdGhlIHN0YWtlcnMgc2V0JwoKKmlmMzlfZW5kOgoJLy8gY29udHJhY3RzL3ZhbGlkYXRvclJlZ2lzdHJ5LmFsZ28udHM6MTIwNwoJLy8gcmV0dXJuIFtpblNhbWVWYWxpZGF0b3JQb29sQ291bnQgPT09IDAsIGluQW55UG9vbENvdW50ID09PSAwXTsKCWJ5dGUgMHgwMAoJaW50IDAKCWZyYW1lX2RpZyAwIC8vIGluU2FtZVZhbGlkYXRvclBvb2xDb3VudDogdWludDY0CglpbnQgMAoJPT0KCXNldGJpdAoJaW50IDEKCWZyYW1lX2RpZyAxIC8vIGluQW55UG9vbENvdW50OiB1aW50NjQKCWludCAwCgk9PQoJc2V0Yml0CgoJLy8gc2V0IHRoZSBzdWJyb3V0aW5lIHJldHVybiB2YWx1ZQoJZnJhbWVfYnVyeSAwCgoJLy8gcG9wIGFsbCBsb2NhbCB2YXJpYWJsZXMgZnJvbSB0aGUgc3RhY2sKCXBvcG4gNAoJcmV0c3ViCgovLyBhZGRQb29sVG9Ob2RlKHZhbGlkYXRvcklkOiBWYWxpZGF0b3JJZFR5cGUsIHBvb2xBcHBJZDogdWludDY0LCBub2RlTnVtOiB1aW50NjQpOiB2b2lkCmFkZFBvb2xUb05vZGU6Cglwcm90byAzIDAKCgkvLyBQdXNoIGVtcHR5IGJ5dGVzIGFmdGVyIHRoZSBmcmFtZSBwb2ludGVyIHRvIHJlc2VydmUgc3BhY2UgZm9yIGxvY2FsIHZhcmlhYmxlcwoJYnl0ZSAweAoJZHVwbiAyCgoJLy8gY29udHJhY3RzL3ZhbGlkYXRvclJlZ2lzdHJ5LmFsZ28udHM6MTIxMQoJLy8gbm9kZVBvb2xBc3NpZ25tZW50cyA9IGNsb25lKHRoaXMudmFsaWRhdG9yTGlzdCh2YWxpZGF0b3JJZCkudmFsdWUubm9kZVBvb2xBc3NpZ25tZW50cykKCWludCA4NjYgLy8gaGVhZE9mZnNldAoJaW50IDE5MgoJYnl0ZSAweDc2IC8vICJ2IgoJZnJhbWVfZGlnIC0xIC8vIHZhbGlkYXRvcklkOiBWYWxpZGF0b3JJZFR5cGUKCWl0b2IKCWNvbmNhdAoJY292ZXIgMgoJYm94X2V4dHJhY3QKCWZyYW1lX2J1cnkgMCAvLyBub2RlUG9vbEFzc2lnbm1lbnRzOiAoKHVpbnQ2NFszXSlbOF0pCgoJLy8gY29udHJhY3RzL3ZhbGlkYXRvclJlZ2lzdHJ5LmFsZ28udHM6MTIxMgoJLy8gbWF4UG9vbHNQZXJOb2RlRm9yVGhpc1ZhbGlkYXRvciA9IHRoaXMudmFsaWRhdG9yTGlzdCh2YWxpZGF0b3JJZCkudmFsdWUuY29uZmlnLnBvb2xzUGVyTm9kZSBhcyB1aW50NjQKCWludCAxOTEKCWludCAxCglieXRlIDB4NzYgLy8gInYiCglmcmFtZV9kaWcgLTEgLy8gdmFsaWRhdG9ySWQ6IFZhbGlkYXRvcklkVHlwZQoJaXRvYgoJY29uY2F0Cgljb3ZlciAyCglib3hfZXh0cmFjdAoJYnRvaQoJZnJhbWVfYnVyeSAxIC8vIG1heFBvb2xzUGVyTm9kZUZvclRoaXNWYWxpZGF0b3I6IHVpbnQ2NAoKCS8vIGNvbnRyYWN0cy92YWxpZGF0b3JSZWdpc3RyeS5hbGdvLnRzOjEyMTQKCS8vIGFzc2VydChub2RlTnVtID49IDEgJiYgbm9kZU51bSA8PSBNQVhfTk9ERVMpCglmcmFtZV9kaWcgLTMgLy8gbm9kZU51bTogdWludDY0CglpbnQgMQoJPj0KCWR1cAoJYnogKnNraXBfYW5kOAoJZnJhbWVfZGlnIC0zIC8vIG5vZGVOdW06IHVpbnQ2NAoJaW50IDgKCTw9CgkmJgoKKnNraXBfYW5kODoKCWFzc2VydAoKCS8vIGNvbnRyYWN0cy92YWxpZGF0b3JSZWdpc3RyeS5hbGdvLnRzOjEyMTYKCS8vIGZvciAobGV0IGkgPSAwOyBpIDwgbWF4UG9vbHNQZXJOb2RlRm9yVGhpc1ZhbGlkYXRvcjsgaSArPSAxKQoJaW50IDAKCWZyYW1lX2J1cnkgMiAvLyBpOiB1aW50NjQKCipmb3JfOToKCS8vIGNvbnRyYWN0cy92YWxpZGF0b3JSZWdpc3RyeS5hbGdvLnRzOjEyMTYKCS8vIGkgPCBtYXhQb29sc1Blck5vZGVGb3JUaGlzVmFsaWRhdG9yCglmcmFtZV9kaWcgMiAvLyBpOiB1aW50NjQKCWZyYW1lX2RpZyAxIC8vIG1heFBvb2xzUGVyTm9kZUZvclRoaXNWYWxpZGF0b3I6IHVpbnQ2NAoJPAoJYnogKmZvcl85X2VuZAoKCS8vICppZjQwX2NvbmRpdGlvbgoJLy8gY29udHJhY3RzL3ZhbGlkYXRvclJlZ2lzdHJ5LmFsZ28udHM6MTIxNwoJLy8gbm9kZVBvb2xBc3NpZ25tZW50cy5ub2Rlc1tub2RlTnVtIC0gMV0ucG9vbEFwcElkc1tpXSA9PT0gMAoJZnJhbWVfZGlnIDAgLy8gbm9kZVBvb2xBc3NpZ25tZW50czogKCh1aW50NjRbM10pWzhdKQoJaW50IDAKCWZyYW1lX2RpZyAtMyAvLyBub2RlTnVtOiB1aW50NjQKCWludCAxCgktCglpbnQgMjQKCSogLy8gYWNjICogdHlwZUxlbmd0aAoJKwoJaW50IDAKCSsKCWZyYW1lX2RpZyAyIC8vIGk6IHVpbnQ2NAoJaW50IDgKCSogLy8gYWNjICogdHlwZUxlbmd0aAoJKwoJaW50IDgKCWV4dHJhY3QzCglidG9pCglpbnQgMAoJPT0KCWJ6ICppZjQwX2VuZAoKCS8vICppZjQwX2NvbnNlcXVlbnQKCS8vIGNvbnRyYWN0cy92YWxpZGF0b3JSZWdpc3RyeS5hbGdvLnRzOjEyMTkKCS8vIHRoaXMudmFsaWRhdG9yTGlzdCh2YWxpZGF0b3JJZCkudmFsdWUubm9kZVBvb2xBc3NpZ25tZW50cy5ub2Rlc1tub2RlTnVtIC0gMV0ucG9vbEFwcElkc1tpXSA9IHBvb2xBcHBJZAoJaW50IDg2NgoJZnJhbWVfZGlnIC0zIC8vIG5vZGVOdW06IHVpbnQ2NAoJaW50IDEKCS0KCWludCAyNAoJKiAvLyBhY2MgKiB0eXBlTGVuZ3RoCgkrCglpbnQgMAoJKwoJZnJhbWVfZGlnIDIgLy8gaTogdWludDY0CglpbnQgOAoJKiAvLyBhY2MgKiB0eXBlTGVuZ3RoCgkrCglmcmFtZV9kaWcgLTIgLy8gcG9vbEFwcElkOiB1aW50NjQKCWl0b2IKCWJ5dGUgMHg3NiAvLyAidiIKCWZyYW1lX2RpZyAtMSAvLyB2YWxpZGF0b3JJZDogVmFsaWRhdG9ySWRUeXBlCglpdG9iCgljb25jYXQKCWNvdmVyIDIKCWJveF9yZXBsYWNlCgoJLy8gY29udHJhY3RzL3ZhbGlkYXRvclJlZ2lzdHJ5LmFsZ28udHM6MTIyMAoJLy8gcmV0dXJuOwoJcmV0c3ViCgoqaWY0MF9lbmQ6CgoqZm9yXzlfY29udGludWU6CgkvLyBjb250cmFjdHMvdmFsaWRhdG9yUmVnaXN0cnkuYWxnby50czoxMjE2CgkvLyBpICs9IDEKCWZyYW1lX2RpZyAyIC8vIGk6IHVpbnQ2NAoJaW50IDEKCSsKCWZyYW1lX2J1cnkgMiAvLyBpOiB1aW50NjQKCWIgKmZvcl85CgoqZm9yXzlfZW5kOgoJZXJyIC8vICdubyBhdmFpbGFibGUgc3BhY2UgaW4gc3BlY2lmaWVkIG5vZGUgZm9yIHRoaXMgcG9vbCcKCi8vIGRvZXNTdGFrZXJNZWV0R2F0aW5nKHZhbGlkYXRvcklkOiBWYWxpZGF0b3JJZFR5cGUsIHZhbHVlVG9WZXJpZnk6IHVpbnQ2NCk6IHZvaWQKLy8KLy8gQ2hlY2tzIGlmIGEgc3Rha2VyIG1lZXRzIHRoZSBnYXRpbmcgcmVxdWlyZW1lbnRzIHNwZWNpZmllZCBieSB0aGUgdmFsaWRhdG9yLgovLwovLyBAcGFyYW0ge1ZhbGlkYXRvcklkVHlwZX0gdmFsaWRhdG9ySWQgLSBUaGUgaWQgb2YgdGhlIHZhbGlkYXRvci4KLy8gQHBhcmFtIHt1aW50NjR9IHZhbHVlVG9WZXJpZnkgLSBUaGUgdmFsdWUgdG8gdmVyaWZ5IGFnYWluc3QgdGhlIGdhdGluZyByZXF1aXJlbWVudHMuCi8vIEByZXR1cm5zIHt2b2lkfSBvciBhc3NlcnRzIGlmIHJlcXVpcmVtZW50cyBub3QgbWV0Lgpkb2VzU3Rha2VyTWVldEdhdGluZzoKCXByb3RvIDIgMAoKCS8vIFB1c2ggZW1wdHkgYnl0ZXMgYWZ0ZXIgdGhlIGZyYW1lIHBvaW50ZXIgdG8gcmVzZXJ2ZSBzcGFjZSBmb3IgbG9jYWwgdmFyaWFibGVzCglieXRlIDB4CglkdXBuIDcKCgkvLyBjb250cmFjdHMvdmFsaWRhdG9yUmVnaXN0cnkuYWxnby50czoxMjM0CgkvLyB0eXBlID0gdGhpcy52YWxpZGF0b3JMaXN0KHZhbGlkYXRvcklkKS52YWx1ZS5jb25maWcuZW50cnlHYXRpbmdUeXBlCglpbnQgODAKCWludCAxCglieXRlIDB4NzYgLy8gInYiCglmcmFtZV9kaWcgLTEgLy8gdmFsaWRhdG9ySWQ6IFZhbGlkYXRvcklkVHlwZQoJaXRvYgoJY29uY2F0Cgljb3ZlciAyCglib3hfZXh0cmFjdAoJYnRvaQoJZnJhbWVfYnVyeSAwIC8vIHR5cGU6IHVpbnQ4CgoJLy8gKmlmNDFfY29uZGl0aW9uCgkvLyBjb250cmFjdHMvdmFsaWRhdG9yUmVnaXN0cnkuYWxnby50czoxMjM1CgkvLyB0eXBlID09PSBHQVRJTkdfVFlQRV9OT05FCglmcmFtZV9kaWcgMCAvLyB0eXBlOiB1aW50OAoJaW50IDAKCT09CglieiAqaWY0MV9lbmQKCgkvLyAqaWY0MV9jb25zZXF1ZW50CgkvLyBjb250cmFjdHMvdmFsaWRhdG9yUmVnaXN0cnkuYWxnby50czoxMjM2CgkvLyByZXR1cm47CglyZXRzdWIKCippZjQxX2VuZDoKCS8vIGNvbnRyYWN0cy92YWxpZGF0b3JSZWdpc3RyeS5hbGdvLnRzOjEyMzgKCS8vIHN0YWtlciA9IHRoaXMudHhuLnNlbmRlcgoJdHhuIFNlbmRlcgoJZnJhbWVfYnVyeSAxIC8vIHN0YWtlcjogYWRkcmVzcwoKCS8vIGNvbnRyYWN0cy92YWxpZGF0b3JSZWdpc3RyeS5hbGdvLnRzOjEyMzkKCS8vIGdhdGVSZXEgPSBjbG9uZSh0aGlzLnZhbGlkYXRvckxpc3QodmFsaWRhdG9ySWQpLnZhbHVlLmNvbmZpZy5lbnRyeUdhdGluZ1ZhbHVlKQoJaW50IDgxCglpbnQgMzIKCWJ5dGUgMHg3NiAvLyAidiIKCWZyYW1lX2RpZyAtMSAvLyB2YWxpZGF0b3JJZDogVmFsaWRhdG9ySWRUeXBlCglpdG9iCgljb25jYXQKCWNvdmVyIDIKCWJveF9leHRyYWN0CglmcmFtZV9idXJ5IDIgLy8gZ2F0ZVJlcTogYnl0ZVszMl0KCgkvLyAqaWY0Ml9jb25kaXRpb24KCS8vIGNvbnRyYWN0cy92YWxpZGF0b3JSZWdpc3RyeS5hbGdvLnRzOjEyNDMKCS8vIHR5cGUgPT09IEdBVElOR19UWVBFX0FTU0VUU19DUkVBVEVEX0JZIHx8CgkvLyAgICAgICAgICAgICB0eXBlID09PSBHQVRJTkdfVFlQRV9BU1NFVF9JRCB8fAoJLy8gICAgICAgICAgICAgdHlwZSA9PT0gR0FUSU5HX1RZUEVfQ1JFQVRFRF9CWV9ORkRfQUREUkVTU0VTCglmcmFtZV9kaWcgMCAvLyB0eXBlOiB1aW50OAoJaW50IDEKCT09CglkdXAKCWJueiAqc2tpcF9vcjQKCWZyYW1lX2RpZyAwIC8vIHR5cGU6IHVpbnQ4CglpbnQgMgoJPT0KCXx8Cgoqc2tpcF9vcjQ6CglkdXAKCWJueiAqc2tpcF9vcjUKCWZyYW1lX2RpZyAwIC8vIHR5cGU6IHVpbnQ4CglpbnQgMwoJPT0KCXx8Cgoqc2tpcF9vcjU6CglieiAqaWY0Ml9lbmQKCgkvLyAqaWY0Ml9jb25zZXF1ZW50CgkvLyBjb250cmFjdHMvdmFsaWRhdG9yUmVnaXN0cnkuYWxnby50czoxMjQ3CgkvLyBhc3NlcnQodmFsdWVUb1ZlcmlmeSAhPT0gMCkKCWZyYW1lX2RpZyAtMiAvLyB2YWx1ZVRvVmVyaWZ5OiB1aW50NjQKCWludCAwCgkhPQoJYXNzZXJ0CgoJLy8gY29udHJhY3RzL3ZhbGlkYXRvclJlZ2lzdHJ5LmFsZ28udHM6MTI0OAoJLy8gYmFsUmVxdWlyZWQgPSB0aGlzLnZhbGlkYXRvckxpc3QodmFsaWRhdG9ySWQpLnZhbHVlLmNvbmZpZy5nYXRpbmdBc3NldE1pbkJhbGFuY2UKCWludCAxMTMKCWludCA4CglieXRlIDB4NzYgLy8gInYiCglmcmFtZV9kaWcgLTEgLy8gdmFsaWRhdG9ySWQ6IFZhbGlkYXRvcklkVHlwZQoJaXRvYgoJY29uY2F0Cgljb3ZlciAyCglib3hfZXh0cmFjdAoJYnRvaQoJZnJhbWVfYnVyeSAzIC8vIGJhbFJlcXVpcmVkOiB1aW50NjQKCgkvLyAqaWY0M19jb25kaXRpb24KCS8vIGNvbnRyYWN0cy92YWxpZGF0b3JSZWdpc3RyeS5hbGdvLnRzOjEyNDkKCS8vIGJhbFJlcXVpcmVkID09PSAwCglmcmFtZV9kaWcgMyAvLyBiYWxSZXF1aXJlZDogdWludDY0CglpbnQgMAoJPT0KCWJ6ICppZjQzX2VuZAoKCS8vICppZjQzX2NvbnNlcXVlbnQKCS8vIGNvbnRyYWN0cy92YWxpZGF0b3JSZWdpc3RyeS5hbGdvLnRzOjEyNTAKCS8vIGJhbFJlcXVpcmVkID0gMQoJaW50IDEKCWZyYW1lX2J1cnkgMyAvLyBiYWxSZXF1aXJlZDogdWludDY0CgoqaWY0M19lbmQ6CgkvLyBjb250cmFjdHMvdmFsaWRhdG9yUmVnaXN0cnkuYWxnby50czoxMjUyCgkvLyBhc3NlcnQoCgkvLyAgICAgICAgICAgICAgICAgc3Rha2VyLmFzc2V0QmFsYW5jZShBc3NldElELmZyb21VaW50NjQodmFsdWVUb1ZlcmlmeSkpID49IGJhbFJlcXVpcmVkLAoJLy8gICAgICAgICAgICAgICAgICdtdXN0IGhhdmUgcmVxdWlyZWQgbWluaW11bSBiYWxhbmNlIG9mIHZhbGlkYXRvciBkZWZpbmVkIHRva2VuIHRvIGFkZCBzdGFrZScKCS8vICAgICAgICAgICAgICkKCWZyYW1lX2RpZyAxIC8vIHN0YWtlcjogYWRkcmVzcwoJZnJhbWVfZGlnIC0yIC8vIHZhbHVlVG9WZXJpZnk6IHVpbnQ2NAoJYXNzZXRfaG9sZGluZ19nZXQgQXNzZXRCYWxhbmNlCglwb3AKCWZyYW1lX2RpZyAzIC8vIGJhbFJlcXVpcmVkOiB1aW50NjQKCT49CgoJLy8gbXVzdCBoYXZlIHJlcXVpcmVkIG1pbmltdW0gYmFsYW5jZSBvZiB2YWxpZGF0b3IgZGVmaW5lZCB0b2tlbiB0byBhZGQgc3Rha2UKCWFzc2VydAoKKmlmNDJfZW5kOgoJLy8gKmlmNDRfY29uZGl0aW9uCgkvLyBjb250cmFjdHMvdmFsaWRhdG9yUmVnaXN0cnkuYWxnby50czoxMjU3CgkvLyB0eXBlID09PSBHQVRJTkdfVFlQRV9BU1NFVFNfQ1JFQVRFRF9CWQoJZnJhbWVfZGlnIDAgLy8gdHlwZTogdWludDgKCWludCAxCgk9PQoJYnogKmlmNDRfZW5kCgoJLy8gKmlmNDRfY29uc2VxdWVudAoJLy8gY29udHJhY3RzL3ZhbGlkYXRvclJlZ2lzdHJ5LmFsZ28udHM6MTI1OAoJLy8gYXNzZXJ0KAoJLy8gICAgICAgICAgICAgICAgIEFzc2V0SUQuZnJvbVVpbnQ2NCh2YWx1ZVRvVmVyaWZ5KS5jcmVhdG9yID09PSBBZGRyZXNzLmZyb21CeXRlcyhnYXRlUmVxKSwKCS8vICAgICAgICAgICAgICAgICAnc3BlY2lmaWVkIGFzc2V0IG11c3QgYmUgY3JlYXRlZCBieSBjcmVhdG9yIHRoYXQgdGhlIHZhbGlkYXRvciBkZWZpbmVkIGFzIGEgcmVxdWlyZW1lbnQgdG8gc3Rha2UnCgkvLyAgICAgICAgICAgICApCglmcmFtZV9kaWcgLTIgLy8gdmFsdWVUb1ZlcmlmeTogdWludDY0Cglhc3NldF9wYXJhbXNfZ2V0IEFzc2V0Q3JlYXRvcgoJcG9wCglmcmFtZV9kaWcgMiAvLyBnYXRlUmVxOiBieXRlWzMyXQoJPT0KCgkvLyBzcGVjaWZpZWQgYXNzZXQgbXVzdCBiZSBjcmVhdGVkIGJ5IGNyZWF0b3IgdGhhdCB0aGUgdmFsaWRhdG9yIGRlZmluZWQgYXMgYSByZXF1aXJlbWVudCB0byBzdGFrZQoJYXNzZXJ0CgoqaWY0NF9lbmQ6CgkvLyAqaWY0NV9jb25kaXRpb24KCS8vIGNvbnRyYWN0cy92YWxpZGF0b3JSZWdpc3RyeS5hbGdvLnRzOjEyNjMKCS8vIHR5cGUgPT09IEdBVElOR19UWVBFX0FTU0VUX0lECglmcmFtZV9kaWcgMCAvLyB0eXBlOiB1aW50OAoJaW50IDIKCT09CglieiAqaWY0NV9lbmQKCgkvLyAqaWY0NV9jb25zZXF1ZW50CgkvLyBjb250cmFjdHMvdmFsaWRhdG9yUmVnaXN0cnkuYWxnby50czoxMjY0CgkvLyByZXF1aXJlZEFzc2V0ID0gZXh0cmFjdFVpbnQ2NChnYXRlUmVxLCAwKQoJZnJhbWVfZGlnIDIgLy8gZ2F0ZVJlcTogYnl0ZVszMl0KCWludCAwCglleHRyYWN0X3VpbnQ2NAoJZnJhbWVfYnVyeSA0IC8vIHJlcXVpcmVkQXNzZXQ6IHVpbnQ2NAoKCS8vIGNvbnRyYWN0cy92YWxpZGF0b3JSZWdpc3RyeS5hbGdvLnRzOjEyNjUKCS8vIGFzc2VydChyZXF1aXJlZEFzc2V0ICE9PSAwKQoJZnJhbWVfZGlnIDQgLy8gcmVxdWlyZWRBc3NldDogdWludDY0CglpbnQgMAoJIT0KCWFzc2VydAoKCS8vIGNvbnRyYWN0cy92YWxpZGF0b3JSZWdpc3RyeS5hbGdvLnRzOjEyNjYKCS8vIGFzc2VydCgKCS8vICAgICAgICAgICAgICAgICB2YWx1ZVRvVmVyaWZ5ID09PSByZXF1aXJlZEFzc2V0LAoJLy8gICAgICAgICAgICAgICAgICdzcGVjaWZpZWQgYXNzZXQgbXVzdCBiZSBpZGVudGljYWwgdG8gdGhlIGFzc2V0IGlkIGRlZmluZWQgYXMgYSByZXF1aXJlbWVudCB0byBzdGFrZScKCS8vICAgICAgICAgICAgICkKCWZyYW1lX2RpZyAtMiAvLyB2YWx1ZVRvVmVyaWZ5OiB1aW50NjQKCWZyYW1lX2RpZyA0IC8vIHJlcXVpcmVkQXNzZXQ6IHVpbnQ2NAoJPT0KCgkvLyBzcGVjaWZpZWQgYXNzZXQgbXVzdCBiZSBpZGVudGljYWwgdG8gdGhlIGFzc2V0IGlkIGRlZmluZWQgYXMgYSByZXF1aXJlbWVudCB0byBzdGFrZQoJYXNzZXJ0CgoqaWY0NV9lbmQ6CgkvLyAqaWY0Nl9jb25kaXRpb24KCS8vIGNvbnRyYWN0cy92YWxpZGF0b3JSZWdpc3RyeS5hbGdvLnRzOjEyNzEKCS8vIHR5cGUgPT09IEdBVElOR19UWVBFX0NSRUFURURfQllfTkZEX0FERFJFU1NFUwoJZnJhbWVfZGlnIDAgLy8gdHlwZTogdWludDgKCWludCAzCgk9PQoJYnogKmlmNDZfZW5kCgoJLy8gKmlmNDZfY29uc2VxdWVudAoJLy8gY29udHJhY3RzL3ZhbGlkYXRvclJlZ2lzdHJ5LmFsZ28udHM6MTI3MgoJLy8gbmZkRm9ySW5mbyA9IHRoaXMudmFsaWRhdG9yTGlzdCh2YWxpZGF0b3JJZCkudmFsdWUuY29uZmlnLm5mZEZvckluZm8KCWludCA3MgoJaW50IDgKCWJ5dGUgMHg3NiAvLyAidiIKCWZyYW1lX2RpZyAtMSAvLyB2YWxpZGF0b3JJZDogVmFsaWRhdG9ySWRUeXBlCglpdG9iCgljb25jYXQKCWNvdmVyIDIKCWJveF9leHRyYWN0CglidG9pCglmcmFtZV9idXJ5IDUgLy8gbmZkRm9ySW5mbzogdWludDY0CgoJLy8gY29udHJhY3RzL3ZhbGlkYXRvclJlZ2lzdHJ5LmFsZ28udHM6MTI3NQoJLy8gYXNzZXJ0KAoJLy8gICAgICAgICAgICAgICAgIHRoaXMuaXNBZGRyZXNzSW5ORkRDQUFsZ29MaXN0KG5mZEZvckluZm8sIEFzc2V0SUQuZnJvbVVpbnQ2NCh2YWx1ZVRvVmVyaWZ5KS5jcmVhdG9yKSwKCS8vICAgICAgICAgICAgICAgICAnc3BlY2lmaWVkIGFzc2V0IG11c3QgYmUgY3JlYXRlZCBieSBjcmVhdG9yIHRoYXQgaXMgb25lIG9mIHRoZSBsaW5rZWQgYWRkcmVzc2VzIGluIGFuIG5mZCcKCS8vICAgICAgICAgICAgICkKCWZyYW1lX2RpZyAtMiAvLyB2YWx1ZVRvVmVyaWZ5OiB1aW50NjQKCWFzc2V0X3BhcmFtc19nZXQgQXNzZXRDcmVhdG9yCglwb3AKCWZyYW1lX2RpZyA1IC8vIG5mZEZvckluZm86IHVpbnQ2NAoJY2FsbHN1YiBpc0FkZHJlc3NJbk5GRENBQWxnb0xpc3QKCgkvLyBzcGVjaWZpZWQgYXNzZXQgbXVzdCBiZSBjcmVhdGVkIGJ5IGNyZWF0b3IgdGhhdCBpcyBvbmUgb2YgdGhlIGxpbmtlZCBhZGRyZXNzZXMgaW4gYW4gbmZkCglhc3NlcnQKCippZjQ2X2VuZDoKCS8vICppZjQ3X2NvbmRpdGlvbgoJLy8gY29udHJhY3RzL3ZhbGlkYXRvclJlZ2lzdHJ5LmFsZ28udHM6MTI4MAoJLy8gdHlwZSA9PT0gR0FUSU5HX1RZUEVfU0VHTUVOVF9PRl9ORkQKCWZyYW1lX2RpZyAwIC8vIHR5cGU6IHVpbnQ4CglpbnQgNAoJPT0KCWJ6ICppZjQ3X2VuZAoKCS8vICppZjQ3X2NvbnNlcXVlbnQKCS8vIGNvbnRyYWN0cy92YWxpZGF0b3JSZWdpc3RyeS5hbGdvLnRzOjEyODIKCS8vIHVzZXJPZmZlcmVkTkZEQXBwSUQgPSB2YWx1ZVRvVmVyaWZ5CglmcmFtZV9kaWcgLTIgLy8gdmFsdWVUb1ZlcmlmeTogdWludDY0CglmcmFtZV9idXJ5IDYgLy8gdXNlck9mZmVyZWRORkRBcHBJRDogdWludDY0CgoJLy8gY29udHJhY3RzL3ZhbGlkYXRvclJlZ2lzdHJ5LmFsZ28udHM6MTI4MwoJLy8gYXNzZXJ0KHRoaXMuaXNORkRBcHBJRFZhbGlkKHVzZXJPZmZlcmVkTkZEQXBwSUQpLCAncHJvdmlkZWQgTkZEIG11c3QgYmUgdmFsaWQnKQoJZnJhbWVfZGlnIDYgLy8gdXNlck9mZmVyZWRORkRBcHBJRDogdWludDY0CgljYWxsc3ViIGlzTkZEQXBwSURWYWxpZAoKCS8vIHByb3ZpZGVkIE5GRCBtdXN0IGJlIHZhbGlkCglhc3NlcnQKCgkvLyBjb250cmFjdHMvdmFsaWRhdG9yUmVnaXN0cnkuYWxnby50czoxMjg2CgkvLyBhc3NlcnQoCgkvLyAgICAgICAgICAgICAgICAgcmF3Qnl0ZXMoQXBwSUQuZnJvbVVpbnQ2NCh1c2VyT2ZmZXJlZE5GREFwcElEKS5nbG9iYWxTdGF0ZSgnaS5vd25lci5hJykgYXMgQWRkcmVzcykgPT09CgkvLyAgICAgICAgICAgICAgICAgICAgIHJhd0J5dGVzKHN0YWtlcikgfHwgdGhpcy5pc0FkZHJlc3NJbk5GRENBQWxnb0xpc3QodXNlck9mZmVyZWRORkRBcHBJRCwgc3Rha2VyKSwKCS8vICAgICAgICAgICAgICAgICAicHJvdmlkZWQgbmZkIGZvciBlbnRyeSBpc24ndCBvd25lZCBvciBsaW5rZWQgdG8gdGhlIHN0YWtlciIKCS8vICAgICAgICAgICAgICkKCWZyYW1lX2RpZyA2IC8vIHVzZXJPZmZlcmVkTkZEQXBwSUQ6IHVpbnQ2NAoJYnl0ZSAweDY5MmU2Zjc3NmU2NTcyMmU2MSAvLyAiaS5vd25lci5hIgoJYXBwX2dsb2JhbF9nZXRfZXgKCWFzc2VydAoJZnJhbWVfZGlnIDEgLy8gc3Rha2VyOiBhZGRyZXNzCgk9PQoJZHVwCglibnogKnNraXBfb3I2CglmcmFtZV9kaWcgMSAvLyBzdGFrZXI6IGFkZHJlc3MKCWZyYW1lX2RpZyA2IC8vIHVzZXJPZmZlcmVkTkZEQXBwSUQ6IHVpbnQ2NAoJY2FsbHN1YiBpc0FkZHJlc3NJbk5GRENBQWxnb0xpc3QKCXx8Cgoqc2tpcF9vcjY6CgkvLyBwcm92aWRlZCBuZmQgZm9yIGVudHJ5IGlzbid0IG93bmVkIG9yIGxpbmtlZCB0byB0aGUgc3Rha2VyCglhc3NlcnQKCgkvLyBjb250cmFjdHMvdmFsaWRhdG9yUmVnaXN0cnkuYWxnby50czoxMjkzCgkvLyByZXF1aXJlZFBhcmVudEFwcElEID0gZXh0cmFjdFVpbnQ2NChnYXRlUmVxLCAwKQoJZnJhbWVfZGlnIDIgLy8gZ2F0ZVJlcTogYnl0ZVszMl0KCWludCAwCglleHRyYWN0X3VpbnQ2NAoJZnJhbWVfYnVyeSA3IC8vIHJlcXVpcmVkUGFyZW50QXBwSUQ6IHVpbnQ2NAoKCS8vIGNvbnRyYWN0cy92YWxpZGF0b3JSZWdpc3RyeS5hbGdvLnRzOjEyOTUKCS8vIGFzc2VydCgKCS8vICAgICAgICAgICAgICAgICAoQXBwSUQuZnJvbVVpbnQ2NCh1c2VyT2ZmZXJlZE5GREFwcElEKS5nbG9iYWxTdGF0ZSgnaS5wYXJlbnRBcHBJRCcpIGFzIHVpbnQ2NCkgPT09IHJlcXVpcmVkUGFyZW50QXBwSUQsCgkvLyAgICAgICAgICAgICAgICAgJ3NwZWNpZmllZCBuZmQgbXVzdCBiZSBhIHNlZ21lbnQgb2YgdGhlIG5mZCB0aGUgdmFsaWRhdG9yIHNwZWNpZmllZCBhcyBhIHJlcXVpcmVtZW50JwoJLy8gICAgICAgICAgICAgKQoJZnJhbWVfZGlnIDYgLy8gdXNlck9mZmVyZWRORkRBcHBJRDogdWludDY0CglieXRlIDB4NjkyZTcwNjE3MjY1NmU3NDQxNzA3MDQ5NDQgLy8gImkucGFyZW50QXBwSUQiCglhcHBfZ2xvYmFsX2dldF9leAoJYXNzZXJ0CglmcmFtZV9kaWcgNyAvLyByZXF1aXJlZFBhcmVudEFwcElEOiB1aW50NjQKCT09CgoJLy8gc3BlY2lmaWVkIG5mZCBtdXN0IGJlIGEgc2VnbWVudCBvZiB0aGUgbmZkIHRoZSB2YWxpZGF0b3Igc3BlY2lmaWVkIGFzIGEgcmVxdWlyZW1lbnQKCWFzc2VydAoKKmlmNDdfZW5kOgoJcmV0c3ViCgovLyBpc05GREFwcElEVmFsaWQobmZkQXBwSUQ6IHVpbnQ2NCk6IGJvb2xlYW4KLy8KLy8gQ2hlY2tzIGlmIHRoZSBnaXZlbiBORkQgQXBwIGlkIGlzIHZhbGlkLiAgVXNpbmcgb25seSB0aGUgQXBwIGlkIHRoZXJlJ3Mgbm8gdmFsaWRhdGlvbiBhZ2FpbnN0IHRoZSBuYW1lIChpZTogdGhhdCBuZmQgWCBpcyBuYW1lIFkpCi8vIFNvIGl0J3MgYXNzdW1lZCBmb3IgdGhlIGNhbGxlciwgdGhlIGFwcCBpZCBhbG9uZSBpcyBmaW5lLiAgVGhlIG5hbWUgaXMgZmV0Y2hlZCBmcm9tIHRoZSBzcGVjaWZpZWQgYXBwIGlkIGFuZCB0aGUgdHdvCi8vIHRvZ2V0aGVyIGFyZSB1c2VkIGZvciB2YWxpZGl0eSBjaGVjayBjYWxsIHRvIHRoZSBuZmQgcmVnaXN0cnkuCi8vCi8vIEBwYXJhbSB7dWludDY0fSBuZmRBcHBJRCAtIFRoZSBORkQgQXBwIGlkIHRvIHZlcmlmeS4KLy8KLy8gQHJldHVybnMge2Jvb2xlYW59IC0gUmV0dXJucyB0cnVlIGlmIHRoZSBORkQgQXBwIGlkIGlzIHZhbGlkLCBvdGhlcndpc2UgZmFsc2UuCmlzTkZEQXBwSURWYWxpZDoKCXByb3RvIDEgMQoKCS8vIFB1c2ggZW1wdHkgYnl0ZXMgYWZ0ZXIgdGhlIGZyYW1lIHBvaW50ZXIgdG8gcmVzZXJ2ZSBzcGFjZSBmb3IgbG9jYWwgdmFyaWFibGVzCglieXRlIDB4CgoJLy8gY29udHJhY3RzL3ZhbGlkYXRvclJlZ2lzdHJ5LmFsZ28udHM6MTMxMwoJLy8gdXNlck9mZmVyZWRORkROYW1lID0gQXBwSUQuZnJvbVVpbnQ2NChuZmRBcHBJRCkuZ2xvYmFsU3RhdGUoJ2kubmFtZScpIGFzIHN0cmluZwoJZnJhbWVfZGlnIC0xIC8vIG5mZEFwcElEOiB1aW50NjQKCWJ5dGUgMHg2OTJlNmU2MTZkNjUgLy8gImkubmFtZSIKCWFwcF9nbG9iYWxfZ2V0X2V4Cglhc3NlcnQKCWZyYW1lX2J1cnkgMCAvLyB1c2VyT2ZmZXJlZE5GRE5hbWU6IHN0cmluZwoKCS8vIGNvbnRyYWN0cy92YWxpZGF0b3JSZWdpc3RyeS5hbGdvLnRzOjEzMTUKCS8vIHNlbmRBcHBDYWxsKHsKCS8vICAgICAgICAgICAgIGFwcGxpY2F0aW9uSUQ6IEFwcElELmZyb21VaW50NjQodGhpcy5uZmRSZWdpc3RyeUFwcElkKSwKCS8vICAgICAgICAgICAgIGFwcGxpY2F0aW9uQXJnczogWydpc192YWxpZF9uZmRfYXBwaWQnLCB1c2VyT2ZmZXJlZE5GRE5hbWUsIGl0b2IobmZkQXBwSUQpXSwKCS8vICAgICAgICAgICAgIGFwcGxpY2F0aW9uczogW0FwcElELmZyb21VaW50NjQobmZkQXBwSUQpXSwKCS8vICAgICAgICAgfSkKCWl0eG5fYmVnaW4KCWludCBhcHBsCglpdHhuX2ZpZWxkIFR5cGVFbnVtCgoJLy8gY29udHJhY3RzL3ZhbGlkYXRvclJlZ2lzdHJ5LmFsZ28udHM6MTMxNgoJLy8gYXBwbGljYXRpb25JRDogQXBwSUQuZnJvbVVpbnQ2NCh0aGlzLm5mZFJlZ2lzdHJ5QXBwSWQpCglwdXNoaW50IFRNUExfbmZkUmVnaXN0cnlBcHBJZAoJaXR4bl9maWVsZCBBcHBsaWNhdGlvbklECgoJLy8gY29udHJhY3RzL3ZhbGlkYXRvclJlZ2lzdHJ5LmFsZ28udHM6MTMxNwoJLy8gYXBwbGljYXRpb25BcmdzOiBbJ2lzX3ZhbGlkX25mZF9hcHBpZCcsIHVzZXJPZmZlcmVkTkZETmFtZSwgaXRvYihuZmRBcHBJRCldCglieXRlIDB4Njk3MzVmNzY2MTZjNjk2NDVmNmU2NjY0NWY2MTcwNzA2OTY0IC8vICJpc192YWxpZF9uZmRfYXBwaWQiCglpdHhuX2ZpZWxkIEFwcGxpY2F0aW9uQXJncwoJZnJhbWVfZGlnIDAgLy8gdXNlck9mZmVyZWRORkROYW1lOiBzdHJpbmcKCWl0eG5fZmllbGQgQXBwbGljYXRpb25BcmdzCglmcmFtZV9kaWcgLTEgLy8gbmZkQXBwSUQ6IHVpbnQ2NAoJaXRvYgoJaXR4bl9maWVsZCBBcHBsaWNhdGlvbkFyZ3MKCgkvLyBjb250cmFjdHMvdmFsaWRhdG9yUmVnaXN0cnkuYWxnby50czoxMzE4CgkvLyBhcHBsaWNhdGlvbnM6IFtBcHBJRC5mcm9tVWludDY0KG5mZEFwcElEKV0KCWZyYW1lX2RpZyAtMSAvLyBuZmRBcHBJRDogdWludDY0CglpdHhuX2ZpZWxkIEFwcGxpY2F0aW9ucwoKCS8vIEZlZSBmaWVsZCBub3Qgc2V0LCBkZWZhdWx0aW5nIHRvIDAKCWludCAwCglpdHhuX2ZpZWxkIEZlZQoKCS8vIFN1Ym1pdCBpbm5lciB0cmFuc2FjdGlvbgoJaXR4bl9zdWJtaXQKCgkvLyBjb250cmFjdHMvdmFsaWRhdG9yUmVnaXN0cnkuYWxnby50czoxMzIwCgkvLyByZXR1cm4gYnRvaSh0aGlzLml0eG4ubGFzdExvZykgPT09IDE7CglpdHhuIExhc3RMb2cKCWJ0b2kKCWludCAxCgk9PQoKCS8vIHNldCB0aGUgc3Vicm91dGluZSByZXR1cm4gdmFsdWUKCWZyYW1lX2J1cnkgMAoJcmV0c3ViCgovLyBpc0FkZHJlc3NJbk5GRENBQWxnb0xpc3QobmZkQXBwSUQ6IHVpbnQ2NCwgYWRkclRvRmluZDogQWRkcmVzcyk6IGJvb2xlYW4KLy8KLy8gQ2hlY2tzIGlmIHRoZSBzcGVjaWZpZWQgYWRkcmVzcyBpcyBwcmVzZW50IGluIGFuIE5GRHMgbGlzdCBvZiB2ZXJpZmllZCBhZGRyZXNzZXMuCi8vIFRoZSBORkQgaXMgYXNzdW1lZCB0byBoYXZlIGFscmVhZHkgYmVlbiB2YWxpZGF0ZWQgYXMgb2ZmaWNpYWwuCi8vCi8vIEBwYXJhbSB7dWludDY0fSBuZmRBcHBJRCAtIFRoZSBORkQgYXBwbGljYXRpb24gaWQuCi8vIEBwYXJhbSB7QWRkcmVzc30gYWRkclRvRmluZCAtIFRoZSBhZGRyZXNzIHRvIGZpbmQgaW4gdGhlIHYuY2FBbGdvLjAuYXMgcHJvcGVydHkKLy8gQHJldHVybiB7Ym9vbGVhbn0gLSBgdHJ1ZWAgaWYgdGhlIGFkZHJlc3MgaXMgcHJlc2VudCwgYGZhbHNlYCBvdGhlcndpc2UuCmlzQWRkcmVzc0luTkZEQ0FBbGdvTGlzdDoKCXByb3RvIDIgMQoKCS8vIFB1c2ggZW1wdHkgYnl0ZXMgYWZ0ZXIgdGhlIGZyYW1lIHBvaW50ZXIgdG8gcmVzZXJ2ZSBzcGFjZSBmb3IgbG9jYWwgdmFyaWFibGVzCglieXRlIDB4CglkdXBuIDIKCgkvLyBjb250cmFjdHMvdmFsaWRhdG9yUmVnaXN0cnkuYWxnby50czoxMzMyCgkvLyBzZW5kQXBwQ2FsbCh7CgkvLyAgICAgICAgICAgICBhcHBsaWNhdGlvbklEOiBBcHBJRC5mcm9tVWludDY0KG5mZEFwcElEKSwKCS8vICAgICAgICAgICAgIGFwcGxpY2F0aW9uQXJnczogWydyZWFkX3Byb3BlcnR5JywgJ3YuY2FBbGdvLjAuYXMnXSwKCS8vICAgICAgICAgfSkKCWl0eG5fYmVnaW4KCWludCBhcHBsCglpdHhuX2ZpZWxkIFR5cGVFbnVtCgoJLy8gY29udHJhY3RzL3ZhbGlkYXRvclJlZ2lzdHJ5LmFsZ28udHM6MTMzMwoJLy8gYXBwbGljYXRpb25JRDogQXBwSUQuZnJvbVVpbnQ2NChuZmRBcHBJRCkKCWZyYW1lX2RpZyAtMSAvLyBuZmRBcHBJRDogdWludDY0CglpdHhuX2ZpZWxkIEFwcGxpY2F0aW9uSUQKCgkvLyBjb250cmFjdHMvdmFsaWRhdG9yUmVnaXN0cnkuYWxnby50czoxMzM0CgkvLyBhcHBsaWNhdGlvbkFyZ3M6IFsncmVhZF9wcm9wZXJ0eScsICd2LmNhQWxnby4wLmFzJ10KCWJ5dGUgMHg3MjY1NjE2NDVmNzA3MjZmNzA2NTcyNzQ3OSAvLyAicmVhZF9wcm9wZXJ0eSIKCWl0eG5fZmllbGQgQXBwbGljYXRpb25BcmdzCglieXRlIDB4NzYyZTYzNjE0MTZjNjc2ZjJlMzAyZTYxNzMgLy8gInYuY2FBbGdvLjAuYXMiCglpdHhuX2ZpZWxkIEFwcGxpY2F0aW9uQXJncwoKCS8vIEZlZSBmaWVsZCBub3Qgc2V0LCBkZWZhdWx0aW5nIHRvIDAKCWludCAwCglpdHhuX2ZpZWxkIEZlZQoKCS8vIFN1Ym1pdCBpbm5lciB0cmFuc2FjdGlvbgoJaXR4bl9zdWJtaXQKCgkvLyBjb250cmFjdHMvdmFsaWRhdG9yUmVnaXN0cnkuYWxnby50czoxMzM2CgkvLyBjYUFsZ29EYXRhID0gdGhpcy5pdHhuLmxhc3RMb2cKCWl0eG4gTGFzdExvZwoJZnJhbWVfYnVyeSAwIC8vIGNhQWxnb0RhdGE6IGJ5dGVbXQoKCS8vIGNvbnRyYWN0cy92YWxpZGF0b3JSZWdpc3RyeS5hbGdvLnRzOjEzMzcKCS8vIGZvciAobGV0IGkgPSAwOyBpIDwgY2FBbGdvRGF0YS5sZW5ndGg7IGkgKz0gMzIpCglpbnQgMAoJZnJhbWVfYnVyeSAxIC8vIGk6IHVpbnQ2NAoKKmZvcl8xMDoKCS8vIGNvbnRyYWN0cy92YWxpZGF0b3JSZWdpc3RyeS5hbGdvLnRzOjEzMzcKCS8vIGkgPCBjYUFsZ29EYXRhLmxlbmd0aAoJZnJhbWVfZGlnIDEgLy8gaTogdWludDY0CglmcmFtZV9kaWcgMCAvLyBjYUFsZ29EYXRhOiBieXRlW10KCWxlbgoJPAoJYnogKmZvcl8xMF9lbmQKCgkvLyBjb250cmFjdHMvdmFsaWRhdG9yUmVnaXN0cnkuYWxnby50czoxMzM4CgkvLyBhZGRyID0gZXh0cmFjdDMoY2FBbGdvRGF0YSwgaSwgMzIpCglmcmFtZV9kaWcgMCAvLyBjYUFsZ29EYXRhOiBieXRlW10KCWZyYW1lX2RpZyAxIC8vIGk6IHVpbnQ2NAoJaW50IDMyCglleHRyYWN0MwoJZnJhbWVfYnVyeSAyIC8vIGFkZHI6IGJ5dGVbXQoKCS8vICppZjQ4X2NvbmRpdGlvbgoJLy8gY29udHJhY3RzL3ZhbGlkYXRvclJlZ2lzdHJ5LmFsZ28udHM6MTMzOQoJLy8gYWRkciAhPT0gcmF3Qnl0ZXMoZ2xvYmFscy56ZXJvQWRkcmVzcykgJiYgYWRkciA9PT0gcmF3Qnl0ZXMoYWRkclRvRmluZCkKCWZyYW1lX2RpZyAyIC8vIGFkZHI6IGJ5dGVbXQoJZ2xvYmFsIFplcm9BZGRyZXNzCgkhPQoJZHVwCglieiAqc2tpcF9hbmQ5CglmcmFtZV9kaWcgMiAvLyBhZGRyOiBieXRlW10KCWZyYW1lX2RpZyAtMiAvLyBhZGRyVG9GaW5kOiBBZGRyZXNzCgk9PQoJJiYKCipza2lwX2FuZDk6CglieiAqaWY0OF9lbmQKCgkvLyAqaWY0OF9jb25zZXF1ZW50CgkvLyBjb250cmFjdHMvdmFsaWRhdG9yUmVnaXN0cnkuYWxnby50czoxMzQwCgkvLyByZXR1cm4gdHJ1ZTsKCWludCAxCgoJLy8gc2V0IHRoZSBzdWJyb3V0aW5lIHJldHVybiB2YWx1ZQoJZnJhbWVfYnVyeSAwCgoJLy8gcG9wIGFsbCBsb2NhbCB2YXJpYWJsZXMgZnJvbSB0aGUgc3RhY2sKCXBvcG4gMgoJcmV0c3ViCgoqaWY0OF9lbmQ6CgoqZm9yXzEwX2NvbnRpbnVlOgoJLy8gY29udHJhY3RzL3ZhbGlkYXRvclJlZ2lzdHJ5LmFsZ28udHM6MTMzNwoJLy8gaSArPSAzMgoJZnJhbWVfZGlnIDEgLy8gaTogdWludDY0CglpbnQgMzIKCSsKCWZyYW1lX2J1cnkgMSAvLyBpOiB1aW50NjQKCWIgKmZvcl8xMAoKKmZvcl8xMF9lbmQ6CgkvLyBjb250cmFjdHMvdmFsaWRhdG9yUmVnaXN0cnkuYWxnby50czoxMzQzCgkvLyByZXR1cm4gZmFsc2U7CglpbnQgMAoKCS8vIHNldCB0aGUgc3Vicm91dGluZSByZXR1cm4gdmFsdWUKCWZyYW1lX2J1cnkgMAoKCS8vIHBvcCBhbGwgbG9jYWwgdmFyaWFibGVzIGZyb20gdGhlIHN0YWNrCglwb3BuIDIKCXJldHN1YgoKLy8gbWF4QWxnb0FsbG93ZWRQZXJQb29sKCk6IHVpbnQ2NAovLwovLyBSZXR1cm5zIHRoZSBNQVhJTVVNIGFsbG93ZWQgc3Rha2UgcGVyIHBvb2wgYW5kIHN0aWxsIHJlY2VpdmUgaW5jZW50aXZlcyAtIHdlJ2xsIHRyZWF0IHRoaXMgYXMgdGhlICdtYXggcGVyIHBvb2wnCm1heEFsZ29BbGxvd2VkUGVyUG9vbDoKCXByb3RvIDAgMQoKCS8vIGNvbnRyYWN0cy92YWxpZGF0b3JSZWdpc3RyeS5hbGdvLnRzOjEzNTEKCS8vIHJldHVybiA3MF8wMDBfMDAwXzAwMF8wMDA7CglpbnQgNzBfMDAwXzAwMF8wMDBfMDAwCglyZXRzdWIKCi8vIGFsZ29TYXR1cmF0aW9uTGV2ZWwoKTogdWludDY0Ci8vCi8vIFJldHVybnMgdGhlIG1heGltdW0gYWxsb3dlZCBzdGFrZSBwZXIgdmFsaWRhdG9yIGJhc2VkIG9uIGEgcGVyY2VudGFnZSBvZiBhbGwgY3VycmVudCBvbmxpbmUgc3Rha2UgYmVmb3JlCi8vIHRoZSB2YWxpZGF0b3IgaXMgY29uc2lkZXJlZCBzYXR1cmF0ZWQgLSB3aGVyZSByZXdhcmRzIGFyZSBkaW1pbmlzaGVkLgovLyBOT1RFOiB0aGlzIGZ1bmN0aW9uIGlzIGRlZmluZWQgdHdpY2UgLSBoZXJlIGFuZCBpbiBzdGFraW5nIHBvb2wgY29udHJhY3QuICBCb3RoIG11c3QgYmUgaWRlbnRpY2FsLgphbGdvU2F0dXJhdGlvbkxldmVsOgoJcHJvdG8gMCAxCgoJLy8gUHVzaCBlbXB0eSBieXRlcyBhZnRlciB0aGUgZnJhbWUgcG9pbnRlciB0byByZXNlcnZlIHNwYWNlIGZvciBsb2NhbCB2YXJpYWJsZXMKCWJ5dGUgMHgKCgkvLyBjb250cmFjdHMvdmFsaWRhdG9yUmVnaXN0cnkuYWxnby50czoxMzYwCgkvLyBvbmxpbmUgPSB0aGlzLmdldEN1cnJlbnRPbmxpbmVTdGFrZSgpCgljYWxsc3ViIGdldEN1cnJlbnRPbmxpbmVTdGFrZQoJZnJhbWVfYnVyeSAwIC8vIG9ubGluZTogdWludDY0CgoJLy8gY29udHJhY3RzL3ZhbGlkYXRvclJlZ2lzdHJ5LmFsZ28udHM6MTM2MgoJLy8gcmV0dXJuIHdpZGVSYXRpbyhbb25saW5lLCBNQVhfVkFMSURBVE9SX1NPRlRfUENUX09GX09OTElORV8xREVDSU1BTF0sIFsxMDAwXSk7CglmcmFtZV9kaWcgMCAvLyBvbmxpbmU6IHVpbnQ2NAoJaW50IDEwMAoJbXVsdwoJaW50IDAKCWludCAxMDAwCglkaXZtb2R3Cglwb3AKCXBvcAoJc3dhcAoJIQoJYXNzZXJ0CgoJLy8gc2V0IHRoZSBzdWJyb3V0aW5lIHJldHVybiB2YWx1ZQoJZnJhbWVfYnVyeSAwCglyZXRzdWIKCi8vIG1heEFsbG93ZWRTdGFrZSgpOiB1aW50NjQKLy8KLy8gUmV0dXJucyB0aGUgTUFYSU1VTSBhbGxvd2VkIHN0YWtlIHBlciB2YWxpZGF0b3IgYmFzZWQgb24gYSBwZXJjZW50YWdlIG9mIGFsbCBjdXJyZW50IG9ubGluZSBzdGFrZS4KLy8gQWRkaW5nIHN0YWtlIGlzIGNvbXBsZXRlbHkgYmxvY2tlZCBhdCB0aGlzIGFtb3VudC4KbWF4QWxsb3dlZFN0YWtlOgoJcHJvdG8gMCAxCgoJLy8gUHVzaCBlbXB0eSBieXRlcyBhZnRlciB0aGUgZnJhbWUgcG9pbnRlciB0byByZXNlcnZlIHNwYWNlIGZvciBsb2NhbCB2YXJpYWJsZXMKCWJ5dGUgMHgKCgkvLyBjb250cmFjdHMvdmFsaWRhdG9yUmVnaXN0cnkuYWxnby50czoxMzcwCgkvLyBvbmxpbmUgPSB0aGlzLmdldEN1cnJlbnRPbmxpbmVTdGFrZSgpCgljYWxsc3ViIGdldEN1cnJlbnRPbmxpbmVTdGFrZQoJZnJhbWVfYnVyeSAwIC8vIG9ubGluZTogdWludDY0CgoJLy8gY29udHJhY3RzL3ZhbGlkYXRvclJlZ2lzdHJ5LmFsZ28udHM6MTM3MgoJLy8gcmV0dXJuIHdpZGVSYXRpbyhbb25saW5lLCBNQVhfVkFMSURBVE9SX0hBUkRfUENUX09GX09OTElORV8xREVDSU1BTF0sIFsxMDAwXSk7CglmcmFtZV9kaWcgMCAvLyBvbmxpbmU6IHVpbnQ2NAoJaW50IDE1MAoJbXVsdwoJaW50IDAKCWludCAxMDAwCglkaXZtb2R3Cglwb3AKCXBvcAoJc3dhcAoJIQoJYXNzZXJ0CgoJLy8gc2V0IHRoZSBzdWJyb3V0aW5lIHJldHVybiB2YWx1ZQoJZnJhbWVfYnVyeSAwCglyZXRzdWIKCi8vIGdldEN1cnJlbnRPbmxpbmVTdGFrZSgpOiB1aW50NjQKZ2V0Q3VycmVudE9ubGluZVN0YWtlOgoJcHJvdG8gMCAxCgoJLy8gY29udHJhY3RzL3ZhbGlkYXRvclJlZ2lzdHJ5LmFsZ28udHM6MTM3NwoJLy8gcmV0dXJuIDJfMDAwXzAwMF8wMDBfMDAwXzAwMDsKCWludCAyXzAwMF8wMDBfMDAwXzAwMF8wMDAKCXJldHN1YgoKLy8gbWluQmFsYW5jZUZvckFjY291bnQoY29udHJhY3RzOiB1aW50NjQsIGV4dHJhUGFnZXM6IHVpbnQ2NCwgYXNzZXRzOiB1aW50NjQsIGxvY2FsSW50czogdWludDY0LCBsb2NhbEJ5dGVzOiB1aW50NjQsIGdsb2JhbEludHM6IHVpbnQ2NCwgZ2xvYmFsQnl0ZXM6IHVpbnQ2NCk6IHVpbnQ2NAptaW5CYWxhbmNlRm9yQWNjb3VudDoKCXByb3RvIDcgMQoKCS8vIFB1c2ggZW1wdHkgYnl0ZXMgYWZ0ZXIgdGhlIGZyYW1lIHBvaW50ZXIgdG8gcmVzZXJ2ZSBzcGFjZSBmb3IgbG9jYWwgdmFyaWFibGVzCglieXRlIDB4CgoJLy8gY29udHJhY3RzL3ZhbGlkYXRvclJlZ2lzdHJ5LmFsZ28udHM6MTM4OQoJLy8gbWluQmFsID0gQUxHT1JBTkRfQUNDT1VOVF9NSU5fQkFMQU5DRQoJaW50IDEwMDAwMAoJZnJhbWVfYnVyeSAwIC8vIG1pbkJhbDogdWludDY0CgoJLy8gY29udHJhY3RzL3ZhbGlkYXRvclJlZ2lzdHJ5LmFsZ28udHM6MTM5MAoJLy8gbWluQmFsICs9IGNvbnRyYWN0cyAqIEFQUExJQ0FUSU9OX0JBU0VfRkVFCglmcmFtZV9kaWcgMCAvLyBtaW5CYWw6IHVpbnQ2NAoJZnJhbWVfZGlnIC0xIC8vIGNvbnRyYWN0czogdWludDY0CglpbnQgMTAwMDAwCgkqCgkrCglmcmFtZV9idXJ5IDAgLy8gbWluQmFsOiB1aW50NjQKCgkvLyBjb250cmFjdHMvdmFsaWRhdG9yUmVnaXN0cnkuYWxnby50czoxMzkxCgkvLyBtaW5CYWwgKz0gZXh0cmFQYWdlcyAqIEFQUExJQ0FUSU9OX0JBU0VfRkVFCglmcmFtZV9kaWcgMCAvLyBtaW5CYWw6IHVpbnQ2NAoJZnJhbWVfZGlnIC0yIC8vIGV4dHJhUGFnZXM6IHVpbnQ2NAoJaW50IDEwMDAwMAoJKgoJKwoJZnJhbWVfYnVyeSAwIC8vIG1pbkJhbDogdWludDY0CgoJLy8gY29udHJhY3RzL3ZhbGlkYXRvclJlZ2lzdHJ5LmFsZ28udHM6MTM5MgoJLy8gbWluQmFsICs9IGFzc2V0cyAqIEFTU0VUX0hPTERJTkdfRkVFCglmcmFtZV9kaWcgMCAvLyBtaW5CYWw6IHVpbnQ2NAoJZnJhbWVfZGlnIC0zIC8vIGFzc2V0czogdWludDY0CglpbnQgMTAwMDAwCgkqCgkrCglmcmFtZV9idXJ5IDAgLy8gbWluQmFsOiB1aW50NjQKCgkvLyBjb250cmFjdHMvdmFsaWRhdG9yUmVnaXN0cnkuYWxnby50czoxMzkzCgkvLyBtaW5CYWwgKz0gbG9jYWxJbnRzICogU1NDX1ZBTFVFX1VJTlQKCWZyYW1lX2RpZyAwIC8vIG1pbkJhbDogdWludDY0CglmcmFtZV9kaWcgLTQgLy8gbG9jYWxJbnRzOiB1aW50NjQKCWludCAyODUwMAoJKgoJKwoJZnJhbWVfYnVyeSAwIC8vIG1pbkJhbDogdWludDY0CgoJLy8gY29udHJhY3RzL3ZhbGlkYXRvclJlZ2lzdHJ5LmFsZ28udHM6MTM5NAoJLy8gbWluQmFsICs9IGdsb2JhbEludHMgKiBTU0NfVkFMVUVfVUlOVAoJZnJhbWVfZGlnIDAgLy8gbWluQmFsOiB1aW50NjQKCWZyYW1lX2RpZyAtNiAvLyBnbG9iYWxJbnRzOiB1aW50NjQKCWludCAyODUwMAoJKgoJKwoJZnJhbWVfYnVyeSAwIC8vIG1pbkJhbDogdWludDY0CgoJLy8gY29udHJhY3RzL3ZhbGlkYXRvclJlZ2lzdHJ5LmFsZ28udHM6MTM5NQoJLy8gbWluQmFsICs9IGxvY2FsQnl0ZXMgKiBTU0NfVkFMVUVfQllURVMKCWZyYW1lX2RpZyAwIC8vIG1pbkJhbDogdWludDY0CglmcmFtZV9kaWcgLTUgLy8gbG9jYWxCeXRlczogdWludDY0CglpbnQgNTAwMDAKCSoKCSsKCWZyYW1lX2J1cnkgMCAvLyBtaW5CYWw6IHVpbnQ2NAoKCS8vIGNvbnRyYWN0cy92YWxpZGF0b3JSZWdpc3RyeS5hbGdvLnRzOjEzOTYKCS8vIG1pbkJhbCArPSBnbG9iYWxCeXRlcyAqIFNTQ19WQUxVRV9CWVRFUwoJZnJhbWVfZGlnIDAgLy8gbWluQmFsOiB1aW50NjQKCWZyYW1lX2RpZyAtNyAvLyBnbG9iYWxCeXRlczogdWludDY0CglpbnQgNTAwMDAKCSoKCSsKCWZyYW1lX2J1cnkgMCAvLyBtaW5CYWw6IHVpbnQ2NAoKCS8vIGNvbnRyYWN0cy92YWxpZGF0b3JSZWdpc3RyeS5hbGdvLnRzOjEzOTcKCS8vIHJldHVybiBtaW5CYWw7CglmcmFtZV9kaWcgMCAvLyBtaW5CYWw6IHVpbnQ2NAoKCS8vIHNldCB0aGUgc3Vicm91dGluZSByZXR1cm4gdmFsdWUKCWZyYW1lX2J1cnkgMAoJcmV0c3ViCgovLyBjb3N0Rm9yQm94U3RvcmFnZSh0b3RhbE51bUJ5dGVzOiB1aW50NjQpOiB1aW50NjQKY29zdEZvckJveFN0b3JhZ2U6Cglwcm90byAxIDEKCgkvLyBjb250cmFjdHMvdmFsaWRhdG9yUmVnaXN0cnkuYWxnby50czoxNDA0CgkvLyByZXR1cm4gU0NCT1hfUEVSQk9YICsgdG90YWxOdW1CeXRlcyAqIFNDQk9YX1BFUkJZVEU7CglpbnQgMjUwMAoJZnJhbWVfZGlnIC0xIC8vIHRvdGFsTnVtQnl0ZXM6IHVpbnQ2NAoJaW50IDQwMAoJKgoJKwoJcmV0c3ViCgoqY3JlYXRlX05vT3A6CgltZXRob2QgImNyZWF0ZUFwcGxpY2F0aW9uKHVpbnQ2NCl2b2lkIgoJdHhuYSBBcHBsaWNhdGlvbkFyZ3MgMAoJbWF0Y2ggKmFiaV9yb3V0ZV9jcmVhdGVBcHBsaWNhdGlvbgoJZXJyCgoqY2FsbF9Ob09wOgoJbWV0aG9kICJnYXMoKXZvaWQiCgltZXRob2QgImdldE1ickFtb3VudHMoKSh1aW50NjQsdWludDY0LHVpbnQ2NCx1aW50NjQpIgoJbWV0aG9kICJnZXRQcm90b2NvbENvbnN0cmFpbnRzKCkodWludDY0LHVpbnQ2NCx1aW50NjQsdWludDY0LHVpbnQ2NCx1aW50NjQsdWludDY0LHVpbnQ2NCx1aW50NjQsdWludDY0LHVpbnQ2NCkiCgltZXRob2QgImdldE51bVZhbGlkYXRvcnMoKXVpbnQ2NCIKCW1ldGhvZCAiZ2V0VmFsaWRhdG9yQ29uZmlnKHVpbnQ2NCkodWludDY0LGFkZHJlc3MsYWRkcmVzcyx1aW50NjQsdWludDgsYnl0ZVszMl0sdWludDY0LHVpbnQ2NCx1aW50NjQsdWludDE2LHVpbnQzMixhZGRyZXNzLHVpbnQ2NCx1aW50NjQsdWludDgsdWludDY0LHVpbnQ2NCkiCgltZXRob2QgImdldFZhbGlkYXRvclN0YXRlKHVpbnQ2NCkodWludDE2LHVpbnQ2NCx1aW50NjQsdWludDY0KSIKCW1ldGhvZCAiZ2V0VmFsaWRhdG9yT3duZXJBbmRNYW5hZ2VyKHVpbnQ2NCkoYWRkcmVzcyxhZGRyZXNzKSIKCW1ldGhvZCAiZ2V0UG9vbHModWludDY0KSh1aW50NjQsdWludDE2LHVpbnQ2NClbXSIKCW1ldGhvZCAiZ2V0UG9vbEFwcElkKHVpbnQ2NCx1aW50NjQpdWludDY0IgoJbWV0aG9kICJnZXRQb29sSW5mbygodWludDY0LHVpbnQ2NCx1aW50NjQpKSh1aW50NjQsdWludDE2LHVpbnQ2NCkiCgltZXRob2QgImdldEN1ck1heFN0YWtlUGVyUG9vbCh1aW50NjQpdWludDY0IgoJbWV0aG9kICJkb2VzU3Rha2VyTmVlZFRvUGF5TUJSKGFkZHJlc3MpYm9vbCIKCW1ldGhvZCAiZ2V0U3Rha2VkUG9vbHNGb3JBY2NvdW50KGFkZHJlc3MpKHVpbnQ2NCx1aW50NjQsdWludDY0KVtdIgoJbWV0aG9kICJnZXRUb2tlblBheW91dFJhdGlvKHVpbnQ2NCkodWludDY0WzI0XSx1aW50NjQpIgoJbWV0aG9kICJnZXROb2RlUG9vbEFzc2lnbm1lbnRzKHVpbnQ2NCkoKHVpbnQ2NFszXSlbOF0pIgoJbWV0aG9kICJnZXRORkRSZWdpc3RyeUlEKCl1aW50NjQiCgltZXRob2QgImFkZFZhbGlkYXRvcihwYXksc3RyaW5nLCh1aW50NjQsYWRkcmVzcyxhZGRyZXNzLHVpbnQ2NCx1aW50OCxieXRlWzMyXSx1aW50NjQsdWludDY0LHVpbnQ2NCx1aW50MTYsdWludDMyLGFkZHJlc3MsdWludDY0LHVpbnQ2NCx1aW50OCx1aW50NjQsdWludDY0KSl1aW50NjQiCgltZXRob2QgImNoYW5nZVZhbGlkYXRvck1hbmFnZXIodWludDY0LGFkZHJlc3Mpdm9pZCIKCW1ldGhvZCAiY2hhbmdlVmFsaWRhdG9yU3Vuc2V0SW5mbyh1aW50NjQsdWludDY0LHVpbnQ2NCl2b2lkIgoJbWV0aG9kICJjaGFuZ2VWYWxpZGF0b3JORkQodWludDY0LHVpbnQ2NCxzdHJpbmcpdm9pZCIKCW1ldGhvZCAiY2hhbmdlVmFsaWRhdG9yQ29tbWlzc2lvbkFkZHJlc3ModWludDY0LGFkZHJlc3Mpdm9pZCIKCW1ldGhvZCAiY2hhbmdlVmFsaWRhdG9yUmV3YXJkSW5mbyh1aW50NjQsdWludDgsYnl0ZVszMl0sdWludDY0LHVpbnQ2NCl2b2lkIgoJbWV0aG9kICJhZGRQb29sKHBheSx1aW50NjQsdWludDY0KSh1aW50NjQsdWludDY0LHVpbnQ2NCkiCgltZXRob2QgImFkZFN0YWtlKHBheSx1aW50NjQsdWludDY0KSh1aW50NjQsdWludDY0LHVpbnQ2NCkiCgltZXRob2QgInNldFRva2VuUGF5b3V0UmF0aW8odWludDY0KSh1aW50NjRbMjRdLHVpbnQ2NCkiCgltZXRob2QgInN0YWtlVXBkYXRlZFZpYVJld2FyZHMoKHVpbnQ2NCx1aW50NjQsdWludDY0KSx1aW50NjQsdWludDY0KXZvaWQiCgltZXRob2QgInN0YWtlUmVtb3ZlZCgodWludDY0LHVpbnQ2NCx1aW50NjQpLGFkZHJlc3MsdWludDY0LHVpbnQ2NCxib29sKXZvaWQiCgltZXRob2QgImZpbmRQb29sRm9yU3Rha2VyKHVpbnQ2NCxhZGRyZXNzLHVpbnQ2NCkoKHVpbnQ2NCx1aW50NjQsdWludDY0KSxib29sLGJvb2wpIgoJbWV0aG9kICJtb3ZlUG9vbFRvTm9kZSh1aW50NjQsdWludDY0LHVpbnQ2NCl2b2lkIgoJdHhuYSBBcHBsaWNhdGlvbkFyZ3MgMAoJbWF0Y2ggKmFiaV9yb3V0ZV9nYXMgKmFiaV9yb3V0ZV9nZXRNYnJBbW91bnRzICphYmlfcm91dGVfZ2V0UHJvdG9jb2xDb25zdHJhaW50cyAqYWJpX3JvdXRlX2dldE51bVZhbGlkYXRvcnMgKmFiaV9yb3V0ZV9nZXRWYWxpZGF0b3JDb25maWcgKmFiaV9yb3V0ZV9nZXRWYWxpZGF0b3JTdGF0ZSAqYWJpX3JvdXRlX2dldFZhbGlkYXRvck93bmVyQW5kTWFuYWdlciAqYWJpX3JvdXRlX2dldFBvb2xzICphYmlfcm91dGVfZ2V0UG9vbEFwcElkICphYmlfcm91dGVfZ2V0UG9vbEluZm8gKmFiaV9yb3V0ZV9nZXRDdXJNYXhTdGFrZVBlclBvb2wgKmFiaV9yb3V0ZV9kb2VzU3Rha2VyTmVlZFRvUGF5TUJSICphYmlfcm91dGVfZ2V0U3Rha2VkUG9vbHNGb3JBY2NvdW50ICphYmlfcm91dGVfZ2V0VG9rZW5QYXlvdXRSYXRpbyAqYWJpX3JvdXRlX2dldE5vZGVQb29sQXNzaWdubWVudHMgKmFiaV9yb3V0ZV9nZXRORkRSZWdpc3RyeUlEICphYmlfcm91dGVfYWRkVmFsaWRhdG9yICphYmlfcm91dGVfY2hhbmdlVmFsaWRhdG9yTWFuYWdlciAqYWJpX3JvdXRlX2NoYW5nZVZhbGlkYXRvclN1bnNldEluZm8gKmFiaV9yb3V0ZV9jaGFuZ2VWYWxpZGF0b3JORkQgKmFiaV9yb3V0ZV9jaGFuZ2VWYWxpZGF0b3JDb21taXNzaW9uQWRkcmVzcyAqYWJpX3JvdXRlX2NoYW5nZVZhbGlkYXRvclJld2FyZEluZm8gKmFiaV9yb3V0ZV9hZGRQb29sICphYmlfcm91dGVfYWRkU3Rha2UgKmFiaV9yb3V0ZV9zZXRUb2tlblBheW91dFJhdGlvICphYmlfcm91dGVfc3Rha2VVcGRhdGVkVmlhUmV3YXJkcyAqYWJpX3JvdXRlX3N0YWtlUmVtb3ZlZCAqYWJpX3JvdXRlX2ZpbmRQb29sRm9yU3Rha2VyICphYmlfcm91dGVfbW92ZVBvb2xUb05vZGUKCWVycg==", + "clear": "I3ByYWdtYSB2ZXJzaW9uIDEw" + }, + "contract": { + "name": "ValidatorRegistry", + "desc": "", + "methods": [ + { + "name": "createApplication", + "args": [ + { + "name": "poolTemplateAppId", + "type": "uint64" + } + ], + "returns": { + "type": "void" + } + }, + { + "name": "gas", + "desc": "gas is a dummy no-op call that can be used to pool-up resource references and opcode cost", + "args": [], + "returns": { + "type": "void" + } + }, + { + "name": "getMbrAmounts", + "desc": "Returns the MBR amounts needed for various actions:[addValidatorMbr: uint64 - mbr needed to add a new validator - paid to validator contractaddPoolMbr: uint64 - mbr needed to add a new pool - paid to validatorpoolInitMbr: uint64 - mbr needed to initStorage() of pool - paid to pool itselfaddStakerMbr: uint64 - mbr staker needs to add to first staking payment (stays w/ validator)]", + "args": [], + "returns": { + "type": "(uint64,uint64,uint64,uint64)" + } + }, + { + "name": "getProtocolConstraints", + "desc": "Returns the protocol constraints so that UIs can limit what users specify for validator configuration parameters.", + "args": [], + "returns": { + "type": "(uint64,uint64,uint64,uint64,uint64,uint64,uint64,uint64,uint64,uint64,uint64)" + } + }, + { + "name": "getNumValidators", + "desc": "Returns the current number of validators", + "args": [], + "returns": { + "type": "uint64" + } + }, + { + "name": "getValidatorConfig", + "args": [ + { + "name": "validatorId", + "type": "uint64" + } + ], + "returns": { + "type": "(uint64,address,address,uint64,uint8,byte[32],uint64,uint64,uint64,uint16,uint32,address,uint64,uint64,uint8,uint64,uint64)" + } + }, + { + "name": "getValidatorState", + "args": [ + { + "name": "validatorId", + "type": "uint64" + } + ], + "returns": { + "type": "(uint16,uint64,uint64,uint64)" + } + }, + { + "name": "getValidatorOwnerAndManager", + "args": [ + { + "name": "validatorId", + "type": "uint64" + } + ], + "returns": { + "type": "(address,address)" + } + }, + { + "name": "getPools", + "desc": "Return list of all pools for this validator.", + "args": [ + { + "name": "validatorId", + "type": "uint64", + "desc": "@return{PoolInfo[]}- array of poolsNot callable from other contracts because>1K return but can be called w/ simulate which bumps log returns" + } + ], + "returns": { + "type": "(uint64,uint16,uint64)[]" + } + }, + { + "name": "getPoolAppId", + "args": [ + { + "name": "validatorId", + "type": "uint64" + }, + { + "name": "poolId", + "type": "uint64" + } + ], + "returns": { + "type": "uint64" + } + }, + { + "name": "getPoolInfo", + "args": [ + { + "name": "poolKey", + "type": "(uint64,uint64,uint64)" + } + ], + "returns": { + "type": "(uint64,uint16,uint64)" + } + }, + { + "name": "getCurMaxStakePerPool", + "desc": "Calculate the maximum stake per pool for a given validator.Normally this would be maxAlgoPerPool, but it should also never go above MaxAllowedStake / numPools soas pools are added the max allowed per pool can reduce.", + "args": [ + { + "name": "validatorId", + "type": "uint64", + "desc": "The id of the validator." + } + ], + "returns": { + "type": "uint64" + } + }, + { + "name": "doesStakerNeedToPayMBR", + "desc": "Helper callers can call w/ simulate to determine if 'AddStaker' MBR should be included w/ staking amount", + "args": [ + { + "name": "staker", + "type": "address" + } + ], + "returns": { + "type": "bool" + } + }, + { + "name": "getStakedPoolsForAccount", + "desc": "Retrieves the staked pools for an account.", + "args": [ + { + "name": "staker", + "type": "address", + "desc": "The account to retrieve staked pools for.@return{ValidatorPoolKey[]}- The array of staked pools for the account." + } + ], + "returns": { + "type": "(uint64,uint64,uint64)[]" + } + }, + { + "name": "getTokenPayoutRatio", + "desc": "Retrieves the token payout ratio for a given validator - returning the pool ratios of whole so that tokenpayouts across pools can be based on a stable snaphost of stake.", + "args": [ + { + "name": "validatorId", + "type": "uint64", + "desc": "The id of the validator.@return{PoolTokenPayoutRatio}- The token payout ratio for the validator." + } + ], + "returns": { + "type": "(uint64[24],uint64)" + } + }, + { + "name": "getNodePoolAssignments", + "args": [ + { + "name": "validatorId", + "type": "uint64" + } + ], + "returns": { + "type": "((uint64[3])[8])" + } + }, + { + "name": "getNFDRegistryID", + "args": [], + "returns": { + "type": "uint64" + } + }, + { + "name": "addValidator", + "desc": "Adds a new validator", + "args": [ + { + "name": "mbrPayment", + "type": "pay", + "desc": "payment from caller which covers mbr increase of new validator storage" + }, + { + "name": "nfdName", + "type": "string", + "desc": "(Optional) Name of nfd (used as double-check against id specified in config)" + }, + { + "name": "config", + "type": "(uint64,address,address,uint64,uint8,byte[32],uint64,uint64,uint64,uint16,uint32,address,uint64,uint64,uint8,uint64,uint64)", + "desc": "ValidatorConfig struct" + } + ], + "returns": { + "type": "uint64", + "desc": "validator id" + } + }, + { + "name": "changeValidatorManager", + "desc": "Changes the Validator manager for a specific Validator id.[ ONLY OWNER CAN CHANGE ]", + "args": [ + { + "name": "validatorId", + "type": "uint64", + "desc": "The id of the validator to change the manager for." + }, + { + "name": "manager", + "type": "address", + "desc": "The new manager address." + } + ], + "returns": { + "type": "void" + } + }, + { + "name": "changeValidatorSunsetInfo", + "desc": "Updates the sunset information for a given validator.[ ONLY OWNER CAN CHANGE ]", + "args": [ + { + "name": "validatorId", + "type": "uint64", + "desc": "The id of the validator to update." + }, + { + "name": "sunsettingOn", + "type": "uint64", + "desc": "The new sunset timestamp." + }, + { + "name": "sunsettingTo", + "type": "uint64", + "desc": "The new sunset to validator id." + } + ], + "returns": { + "type": "void" + } + }, + { + "name": "changeValidatorNFD", + "desc": "Changes the NFD for a validator in the validatorList contract.[ ONLY OWNER OR MANAGER CAN CHANGE ]", + "args": [ + { + "name": "validatorId", + "type": "uint64", + "desc": "The id of the validator to update." + }, + { + "name": "nfdAppID", + "type": "uint64", + "desc": "The application id of the NFD to assign to the validator." + }, + { + "name": "nfdName", + "type": "string", + "desc": "The name of the NFD (which must match)" + } + ], + "returns": { + "type": "void" + } + }, + { + "name": "changeValidatorCommissionAddress", + "desc": "Change the commission address that validator rewards are sent to.[ ONLY OWNER CAN CHANGE ]", + "args": [ + { + "name": "validatorId", + "type": "uint64" + }, + { + "name": "commissionAddress", + "type": "address" + } + ], + "returns": { + "type": "void" + } + }, + { + "name": "changeValidatorRewardInfo", + "desc": "Allow the additional rewards (gating entry, additional token rewards) information be changed at will.[ ONLY OWNER CAN CHANGE ]", + "args": [ + { + "name": "validatorId", + "type": "uint64" + }, + { + "name": "EntryGatingType", + "type": "uint8" + }, + { + "name": "EntryGatingValue", + "type": "byte[32]" + }, + { + "name": "GatingAssetMinBalance", + "type": "uint64" + }, + { + "name": "RewardPerPayout", + "type": "uint64" + } + ], + "returns": { + "type": "void" + } + }, + { + "name": "addPool", + "desc": "Adds a new pool to a validator's pool set, returning the 'key' to reference the pool in the future for staking, etc.The caller must pay the cost of the validators MBR increase as well as the MBR that will be needed for the pool itself.[ ONLY OWNER OR MANAGER CAN call ]", + "args": [ + { + "name": "mbrPayment", + "type": "pay", + "desc": "payment from caller which covers mbr increase of adding a new pool" + }, + { + "name": "validatorId", + "type": "uint64", + "desc": "is id of validator to pool to (must be owner or manager)" + }, + { + "name": "nodeNum", + "type": "uint64", + "desc": "is node number to add to" + } + ], + "returns": { + "type": "(uint64,uint64,uint64)", + "desc": "{ValidatorPoolKey}pool key to created pool" + } + }, + { + "name": "addStake", + "desc": "Adds stake to a validator pool.", + "args": [ + { + "name": "stakedAmountPayment", + "type": "pay", + "desc": "payment coming from staker to place into a pool" + }, + { + "name": "validatorId", + "type": "uint64", + "desc": "The id of the validator." + }, + { + "name": "valueToVerify", + "type": "uint64", + "desc": "only if validator has gating to enter - this is asset id or nfd id that corresponds to gating.Txn sender is factored in as well if that is part of gating.*" + } + ], + "returns": { + "type": "(uint64,uint64,uint64)", + "desc": "{ValidatorPoolKey}- The key of the validator pool." + } + }, + { + "name": "setTokenPayoutRatio", + "desc": "setTokenPayoutRatio is called by Staking Pool # 1 (ONLY) to ask the validator (us) to calculate the ratiosof stake in the pools for subsequent token payouts (ie: 2 pools, '100' algo total staked, 60 in pool 1, and 40in pool 2. This is done so we have a stable snapshot of stake - taken once per epoch - only triggered bypool 1 doing payout. pools other than 1 doing payout call pool 1 to ask it do it first.It would be 60/40% in the poolPctOfWhole values. The token reward payouts then use these values instead oftheir 'current' stake which changes as part of the payouts themselves (and people could be changing stakeduring the epoch updates across pools)Multiple pools will call us via pool 1 (pool2->pool1->valdiator, etc.) so don't assert on pool1 calling multipletimes in same epoch. Just return.", + "args": [ + { + "name": "validatorId", + "type": "uint64", + "desc": "validator id (and thus pool) calling us. Verified so that sender MUST be pool 1 of this validator." + } + ], + "returns": { + "type": "(uint64[24],uint64)", + "desc": "PoolTokenPayoutRatio - the finished ratio data" + } + }, + { + "name": "stakeUpdatedViaRewards", + "desc": "stakeUpdatedViaRewards is called by Staking pools to inform the validator (us) that a particular amount of totalstake has been added to the specified pool. This is used to update the stats we have in our PoolInfo storage.The calling App id is validated against our pool list as well.", + "args": [ + { + "name": "poolKey", + "type": "(uint64,uint64,uint64)", + "desc": "ValidatorPoolKey type" + }, + { + "name": "algoToAdd", + "type": "uint64", + "desc": "amount this validator's total stake increased via rewards" + }, + { + "name": "rewardTokenAmountReserved", + "type": "uint64", + "desc": "amount this validator's total stake increased via rewards (that should beseen as 'accounted for/pending spent')" + } + ], + "returns": { + "type": "void" + } + }, + { + "name": "stakeRemoved", + "desc": "stakeRemoved is called by Staking pools to inform the validator (us) that a particular amount of total stake has been removedfrom the specified pool. This is used to update the stats we have in our PoolInfo storage.If any amount of rewardRemoved is specified, then that amount of reward is sent to the useThe calling App id is validated against our pool list as well.", + "args": [ + { + "name": "poolKey", + "type": "(uint64,uint64,uint64)", + "desc": "calling us from which stake was removed" + }, + { + "name": "staker", + "type": "address" + }, + { + "name": "amountRemoved", + "type": "uint64", + "desc": "algo amount removed" + }, + { + "name": "rewardRemoved", + "type": "uint64", + "desc": "if applicable, amount of token reward removed (by pool 1 caller) or TO remove and pay out (via pool 1 from different pool caller)" + }, + { + "name": "stakerRemoved", + "type": "bool" + } + ], + "returns": { + "type": "void" + } + }, + { + "name": "findPoolForStaker", + "desc": "Finds the pool for a staker based on the provided validator id, staker address, and amount to stake.First checks the stakers 'already staked list' for the validator preferring those (adding if possible) then addsto new pool if necessary.", + "args": [ + { + "name": "validatorId", + "type": "uint64", + "desc": "The id of the validator." + }, + { + "name": "staker", + "type": "address", + "desc": "The address of the staker." + }, + { + "name": "amountToStake", + "type": "uint64", + "desc": "The amount to stake." + } + ], + "returns": { + "type": "((uint64,uint64,uint64),bool,bool)", + "desc": "{ValidatorPoolKey, boolean, boolean}- The pool for the staker, true/false on whether the staker is 'new'to this VALIDATOR, and true/false if staker is new to the protocol." + } + }, + { + "name": "movePoolToNode", + "desc": "Find the specified pool (in any node number) and move it to the specified node.The pool account is forced offline if moved so prior node will still run for 320 rounds butnew key goes online on new node soon after (320 rounds after it goes online)No-op if success, asserts if not found or can't move (no space in target)[ ONLY OWNER OR MANAGER CAN CHANGE ]Only callable by owner or manager", + "args": [ + { + "name": "validatorId", + "type": "uint64" + }, + { + "name": "poolAppId", + "type": "uint64" + }, + { + "name": "nodeNum", + "type": "uint64" + } + ], + "returns": { + "type": "void" + } + } + ] + } +} + +/** + * Defines an onCompletionAction of 'no_op' + */ +export type OnCompleteNoOp = { onCompleteAction?: 'no_op' | OnApplicationComplete.NoOpOC } +/** + * Defines an onCompletionAction of 'opt_in' + */ +export type OnCompleteOptIn = { onCompleteAction: 'opt_in' | OnApplicationComplete.OptInOC } +/** + * Defines an onCompletionAction of 'close_out' + */ +export type OnCompleteCloseOut = { onCompleteAction: 'close_out' | OnApplicationComplete.CloseOutOC } +/** + * Defines an onCompletionAction of 'delete_application' + */ +export type OnCompleteDelApp = { onCompleteAction: 'delete_application' | OnApplicationComplete.DeleteApplicationOC } +/** + * Defines an onCompletionAction of 'update_application' + */ +export type OnCompleteUpdApp = { onCompleteAction: 'update_application' | OnApplicationComplete.UpdateApplicationOC } +/** + * A state record containing a single unsigned integer + */ +export type IntegerState = { + /** + * Gets the state value as a BigInt. + */ + asBigInt(): bigint + /** + * Gets the state value as a number. + */ + asNumber(): number +} +/** + * A state record containing binary data + */ +export type BinaryState = { + /** + * Gets the state value as a Uint8Array + */ + asByteArray(): Uint8Array + /** + * Gets the state value as a string + */ + asString(): string +} + +export type AppCreateCallTransactionResult = AppCallTransactionResult & Partial & AppReference +export type AppUpdateCallTransactionResult = AppCallTransactionResult & Partial + +export type AppClientComposeCallCoreParams = Omit & { + sendParams?: Omit +} +export type AppClientComposeExecuteParams = Pick + +export type IncludeSchema = { + /** + * Any overrides for the storage schema to request for the created app; by default the schema indicated by the app spec is used. + */ + schema?: Partial +} + +/** + * Defines the types of available calls and state of the ValidatorRegistry smart contract. + */ +export type ValidatorRegistry = { + /** + * Maps method signatures / names to their argument and return types. + */ + methods: + & Record<'createApplication(uint64)void' | 'createApplication', { + argsObj: { + poolTemplateAppId: bigint | number + } + argsTuple: [poolTemplateAppId: bigint | number] + returns: void + }> + & Record<'gas()void' | 'gas', { + argsObj: { + } + argsTuple: [] + returns: void + }> + & Record<'getMbrAmounts()(uint64,uint64,uint64,uint64)' | 'getMbrAmounts', { + argsObj: { + } + argsTuple: [] + returns: [bigint, bigint, bigint, bigint] + }> + & Record<'getProtocolConstraints()(uint64,uint64,uint64,uint64,uint64,uint64,uint64,uint64,uint64,uint64,uint64)' | 'getProtocolConstraints', { + argsObj: { + } + argsTuple: [] + returns: [bigint, bigint, bigint, bigint, bigint, bigint, bigint, bigint, bigint, bigint, bigint] + }> + & Record<'getNumValidators()uint64' | 'getNumValidators', { + argsObj: { + } + argsTuple: [] + returns: bigint + }> + & Record<'getValidatorConfig(uint64)(uint64,address,address,uint64,uint8,byte[32],uint64,uint64,uint64,uint16,uint32,address,uint64,uint64,uint8,uint64,uint64)' | 'getValidatorConfig', { + argsObj: { + validatorId: bigint | number + } + argsTuple: [validatorId: bigint | number] + returns: [bigint, string, string, bigint, number, Uint8Array, bigint, bigint, bigint, number, number, string, bigint, bigint, number, bigint, bigint] + }> + & Record<'getValidatorState(uint64)(uint16,uint64,uint64,uint64)' | 'getValidatorState', { + argsObj: { + validatorId: bigint | number + } + argsTuple: [validatorId: bigint | number] + returns: [number, bigint, bigint, bigint] + }> + & Record<'getValidatorOwnerAndManager(uint64)(address,address)' | 'getValidatorOwnerAndManager', { + argsObj: { + validatorId: bigint | number + } + argsTuple: [validatorId: bigint | number] + returns: [string, string] + }> + & Record<'getPools(uint64)(uint64,uint16,uint64)[]' | 'getPools', { + argsObj: { + /** + * @return{PoolInfo[]}- array of poolsNot callable from other contracts because>1K return but can be called w/ simulate which bumps log returns + */ + validatorId: bigint | number + } + argsTuple: [validatorId: bigint | number] + returns: [bigint, number, bigint][] + }> + & Record<'getPoolAppId(uint64,uint64)uint64' | 'getPoolAppId', { + argsObj: { + validatorId: bigint | number + poolId: bigint | number + } + argsTuple: [validatorId: bigint | number, poolId: bigint | number] + returns: bigint + }> + & Record<'getPoolInfo((uint64,uint64,uint64))(uint64,uint16,uint64)' | 'getPoolInfo', { + argsObj: { + poolKey: [bigint | number, bigint | number, bigint | number] + } + argsTuple: [poolKey: [bigint | number, bigint | number, bigint | number]] + returns: [bigint, number, bigint] + }> + & Record<'getCurMaxStakePerPool(uint64)uint64' | 'getCurMaxStakePerPool', { + argsObj: { + /** + * The id of the validator. + */ + validatorId: bigint | number + } + argsTuple: [validatorId: bigint | number] + returns: bigint + }> + & Record<'doesStakerNeedToPayMBR(address)bool' | 'doesStakerNeedToPayMBR', { + argsObj: { + staker: string + } + argsTuple: [staker: string] + returns: boolean + }> + & Record<'getStakedPoolsForAccount(address)(uint64,uint64,uint64)[]' | 'getStakedPoolsForAccount', { + argsObj: { + /** + * The account to retrieve staked pools for.@return{ValidatorPoolKey[]}- The array of staked pools for the account. + */ + staker: string + } + argsTuple: [staker: string] + returns: [bigint, bigint, bigint][] + }> + & Record<'getTokenPayoutRatio(uint64)(uint64[24],uint64)' | 'getTokenPayoutRatio', { + argsObj: { + /** + * The id of the validator.@return{PoolTokenPayoutRatio}- The token payout ratio for the validator. + */ + validatorId: bigint | number + } + argsTuple: [validatorId: bigint | number] + returns: [[bigint, bigint, bigint, bigint, bigint, bigint, bigint, bigint, bigint, bigint, bigint, bigint, bigint, bigint, bigint, bigint, bigint, bigint, bigint, bigint, bigint, bigint, bigint, bigint], bigint] + }> + & Record<'getNodePoolAssignments(uint64)((uint64[3])[8])' | 'getNodePoolAssignments', { + argsObj: { + validatorId: bigint | number + } + argsTuple: [validatorId: bigint | number] + returns: [[[[bigint, bigint, bigint]], [[bigint, bigint, bigint]], [[bigint, bigint, bigint]], [[bigint, bigint, bigint]], [[bigint, bigint, bigint]], [[bigint, bigint, bigint]], [[bigint, bigint, bigint]], [[bigint, bigint, bigint]]]] + }> + & Record<'getNFDRegistryID()uint64' | 'getNFDRegistryID', { + argsObj: { + } + argsTuple: [] + returns: bigint + }> + & Record<'addValidator(pay,string,(uint64,address,address,uint64,uint8,byte[32],uint64,uint64,uint64,uint16,uint32,address,uint64,uint64,uint8,uint64,uint64))uint64' | 'addValidator', { + argsObj: { + /** + * payment from caller which covers mbr increase of new validator storage + */ + mbrPayment: TransactionToSign | Transaction | Promise + /** + * (Optional) Name of nfd (used as double-check against id specified in config) + */ + nfdName: string + /** + * ValidatorConfig struct + */ + config: [bigint | number, string, string, bigint | number, number, Uint8Array, bigint | number, bigint | number, bigint | number, number, number, string, bigint | number, bigint | number, number, bigint | number, bigint | number] + } + argsTuple: [mbrPayment: TransactionToSign | Transaction | Promise, nfdName: string, config: [bigint | number, string, string, bigint | number, number, Uint8Array, bigint | number, bigint | number, bigint | number, number, number, string, bigint | number, bigint | number, number, bigint | number, bigint | number]] + /** + * validator id + */ + returns: bigint + }> + & Record<'changeValidatorManager(uint64,address)void' | 'changeValidatorManager', { + argsObj: { + /** + * The id of the validator to change the manager for. + */ + validatorId: bigint | number + /** + * The new manager address. + */ + manager: string + } + argsTuple: [validatorId: bigint | number, manager: string] + returns: void + }> + & Record<'changeValidatorSunsetInfo(uint64,uint64,uint64)void' | 'changeValidatorSunsetInfo', { + argsObj: { + /** + * The id of the validator to update. + */ + validatorId: bigint | number + /** + * The new sunset timestamp. + */ + sunsettingOn: bigint | number + /** + * The new sunset to validator id. + */ + sunsettingTo: bigint | number + } + argsTuple: [validatorId: bigint | number, sunsettingOn: bigint | number, sunsettingTo: bigint | number] + returns: void + }> + & Record<'changeValidatorNFD(uint64,uint64,string)void' | 'changeValidatorNFD', { + argsObj: { + /** + * The id of the validator to update. + */ + validatorId: bigint | number + /** + * The application id of the NFD to assign to the validator. + */ + nfdAppId: bigint | number + /** + * The name of the NFD (which must match) + */ + nfdName: string + } + argsTuple: [validatorId: bigint | number, nfdAppId: bigint | number, nfdName: string] + returns: void + }> + & Record<'changeValidatorCommissionAddress(uint64,address)void' | 'changeValidatorCommissionAddress', { + argsObj: { + validatorId: bigint | number + commissionAddress: string + } + argsTuple: [validatorId: bigint | number, commissionAddress: string] + returns: void + }> + & Record<'changeValidatorRewardInfo(uint64,uint8,byte[32],uint64,uint64)void' | 'changeValidatorRewardInfo', { + argsObj: { + validatorId: bigint | number + entryGatingType: number + entryGatingValue: Uint8Array + gatingAssetMinBalance: bigint | number + rewardPerPayout: bigint | number + } + argsTuple: [validatorId: bigint | number, entryGatingType: number, entryGatingValue: Uint8Array, gatingAssetMinBalance: bigint | number, rewardPerPayout: bigint | number] + returns: void + }> + & Record<'addPool(pay,uint64,uint64)(uint64,uint64,uint64)' | 'addPool', { + argsObj: { + /** + * payment from caller which covers mbr increase of adding a new pool + */ + mbrPayment: TransactionToSign | Transaction | Promise + /** + * is id of validator to pool to (must be owner or manager) + */ + validatorId: bigint | number + /** + * is node number to add to + */ + nodeNum: bigint | number + } + argsTuple: [mbrPayment: TransactionToSign | Transaction | Promise, validatorId: bigint | number, nodeNum: bigint | number] + /** + * {ValidatorPoolKey}pool key to created pool + */ + returns: [bigint, bigint, bigint] + }> + & Record<'addStake(pay,uint64,uint64)(uint64,uint64,uint64)' | 'addStake', { + argsObj: { + /** + * payment coming from staker to place into a pool + */ + stakedAmountPayment: TransactionToSign | Transaction | Promise + /** + * The id of the validator. + */ + validatorId: bigint | number + /** + * only if validator has gating to enter - this is asset id or nfd id that corresponds to gating.Txn sender is factored in as well if that is part of gating.* + */ + valueToVerify: bigint | number + } + argsTuple: [stakedAmountPayment: TransactionToSign | Transaction | Promise, validatorId: bigint | number, valueToVerify: bigint | number] + /** + * {ValidatorPoolKey}- The key of the validator pool. + */ + returns: [bigint, bigint, bigint] + }> + & Record<'setTokenPayoutRatio(uint64)(uint64[24],uint64)' | 'setTokenPayoutRatio', { + argsObj: { + /** + * validator id (and thus pool) calling us. Verified so that sender MUST be pool 1 of this validator. + */ + validatorId: bigint | number + } + argsTuple: [validatorId: bigint | number] + /** + * PoolTokenPayoutRatio - the finished ratio data + */ + returns: [[bigint, bigint, bigint, bigint, bigint, bigint, bigint, bigint, bigint, bigint, bigint, bigint, bigint, bigint, bigint, bigint, bigint, bigint, bigint, bigint, bigint, bigint, bigint, bigint], bigint] + }> + & Record<'stakeUpdatedViaRewards((uint64,uint64,uint64),uint64,uint64)void' | 'stakeUpdatedViaRewards', { + argsObj: { + /** + * ValidatorPoolKey type + */ + poolKey: [bigint | number, bigint | number, bigint | number] + /** + * amount this validator's total stake increased via rewards + */ + algoToAdd: bigint | number + /** + * amount this validator's total stake increased via rewards (that should beseen as 'accounted for/pending spent') + */ + rewardTokenAmountReserved: bigint | number + } + argsTuple: [poolKey: [bigint | number, bigint | number, bigint | number], algoToAdd: bigint | number, rewardTokenAmountReserved: bigint | number] + returns: void + }> + & Record<'stakeRemoved((uint64,uint64,uint64),address,uint64,uint64,bool)void' | 'stakeRemoved', { + argsObj: { + /** + * calling us from which stake was removed + */ + poolKey: [bigint | number, bigint | number, bigint | number] + staker: string + /** + * algo amount removed + */ + amountRemoved: bigint | number + /** + * if applicable, amount of token reward removed (by pool 1 caller) or TO remove and pay out (via pool 1 from different pool caller) + */ + rewardRemoved: bigint | number + stakerRemoved: boolean + } + argsTuple: [poolKey: [bigint | number, bigint | number, bigint | number], staker: string, amountRemoved: bigint | number, rewardRemoved: bigint | number, stakerRemoved: boolean] + returns: void + }> + & Record<'findPoolForStaker(uint64,address,uint64)((uint64,uint64,uint64),bool,bool)' | 'findPoolForStaker', { + argsObj: { + /** + * The id of the validator. + */ + validatorId: bigint | number + /** + * The address of the staker. + */ + staker: string + /** + * The amount to stake. + */ + amountToStake: bigint | number + } + argsTuple: [validatorId: bigint | number, staker: string, amountToStake: bigint | number] + /** + * {ValidatorPoolKey, boolean, boolean}- The pool for the staker, true/false on whether the staker is 'new'to this VALIDATOR, and true/false if staker is new to the protocol. + */ + returns: [[bigint, bigint, bigint], boolean, boolean] + }> + & Record<'movePoolToNode(uint64,uint64,uint64)void' | 'movePoolToNode', { + argsObj: { + validatorId: bigint | number + poolAppId: bigint | number + nodeNum: bigint | number + } + argsTuple: [validatorId: bigint | number, poolAppId: bigint | number, nodeNum: bigint | number] + returns: void + }> + /** + * Defines the shape of the global and local state of the application. + */ + state: { + global: { + numV?: IntegerState + poolTemplateAppId?: IntegerState + numStakers?: IntegerState + staked?: IntegerState + } + } +} +/** + * Defines the possible abi call signatures + */ +export type ValidatorRegistrySig = keyof ValidatorRegistry['methods'] +/** + * Defines an object containing all relevant parameters for a single call to the contract. Where TSignature is undefined, a bare call is made + */ +export type TypedCallParams = { + method: TSignature + methodArgs: TSignature extends undefined ? undefined : Array +} & AppClientCallCoreParams & CoreAppCallArgs +/** + * Defines the arguments required for a bare call + */ +export type BareCallArgs = Omit +/** + * Maps a method signature from the ValidatorRegistry smart contract to the method's arguments in either tuple of struct form + */ +export type MethodArgs = ValidatorRegistry['methods'][TSignature]['argsObj' | 'argsTuple'] +/** + * Maps a method signature from the ValidatorRegistry smart contract to the method's return type + */ +export type MethodReturn = ValidatorRegistry['methods'][TSignature]['returns'] + +/** + * A factory for available 'create' calls + */ +export type ValidatorRegistryCreateCalls = (typeof ValidatorRegistryCallFactory)['create'] +/** + * Defines supported create methods for this smart contract + */ +export type ValidatorRegistryCreateCallParams = + | (TypedCallParams<'createApplication(uint64)void'> & (OnCompleteNoOp)) +/** + * Defines arguments required for the deploy method. + */ +export type ValidatorRegistryDeployArgs = { + deployTimeParams?: TealTemplateParams + /** + * A delegate which takes a create call factory and returns the create call params for this smart contract + */ + createCall?: (callFactory: ValidatorRegistryCreateCalls) => ValidatorRegistryCreateCallParams +} + + +/** + * Exposes methods for constructing all available smart contract calls + */ +export abstract class ValidatorRegistryCallFactory { + /** + * Gets available create call factories + */ + static get create() { + return { + /** + * Constructs a create call for the ValidatorRegistry smart contract using the createApplication(uint64)void ABI method + * + * @param args Any args for the contract call + * @param params Any additional parameters for the call + * @returns A TypedCallParams object for the call + */ + createApplication(args: MethodArgs<'createApplication(uint64)void'>, params: AppClientCallCoreParams & CoreAppCallArgs & AppClientCompilationParams & (OnCompleteNoOp) = {}) { + return { + method: 'createApplication(uint64)void' as const, + methodArgs: Array.isArray(args) ? args : [args.poolTemplateAppId], + ...params, + } + }, + } + } + + /** + * Constructs a no op call for the gas()void ABI method + * + * gas is a dummy no-op call that can be used to pool-up resource references and opcode cost + * + * @param args Any args for the contract call + * @param params Any additional parameters for the call + * @returns A TypedCallParams object for the call + */ + static gas(args: MethodArgs<'gas()void'>, params: AppClientCallCoreParams & CoreAppCallArgs) { + return { + method: 'gas()void' as const, + methodArgs: Array.isArray(args) ? args : [], + ...params, + } + } + /** + * Constructs a no op call for the getMbrAmounts()(uint64,uint64,uint64,uint64) ABI method + * + * Returns the MBR amounts needed for various actions:[addValidatorMbr: uint64 - mbr needed to add a new validator - paid to validator contractaddPoolMbr: uint64 - mbr needed to add a new pool - paid to validatorpoolInitMbr: uint64 - mbr needed to initStorage() of pool - paid to pool itselfaddStakerMbr: uint64 - mbr staker needs to add to first staking payment (stays w/ validator)] + * + * @param args Any args for the contract call + * @param params Any additional parameters for the call + * @returns A TypedCallParams object for the call + */ + static getMbrAmounts(args: MethodArgs<'getMbrAmounts()(uint64,uint64,uint64,uint64)'>, params: AppClientCallCoreParams & CoreAppCallArgs) { + return { + method: 'getMbrAmounts()(uint64,uint64,uint64,uint64)' as const, + methodArgs: Array.isArray(args) ? args : [], + ...params, + } + } + /** + * Constructs a no op call for the getProtocolConstraints()(uint64,uint64,uint64,uint64,uint64,uint64,uint64,uint64,uint64,uint64,uint64) ABI method + * + * Returns the protocol constraints so that UIs can limit what users specify for validator configuration parameters. + * + * @param args Any args for the contract call + * @param params Any additional parameters for the call + * @returns A TypedCallParams object for the call + */ + static getProtocolConstraints(args: MethodArgs<'getProtocolConstraints()(uint64,uint64,uint64,uint64,uint64,uint64,uint64,uint64,uint64,uint64,uint64)'>, params: AppClientCallCoreParams & CoreAppCallArgs) { + return { + method: 'getProtocolConstraints()(uint64,uint64,uint64,uint64,uint64,uint64,uint64,uint64,uint64,uint64,uint64)' as const, + methodArgs: Array.isArray(args) ? args : [], + ...params, + } + } + /** + * Constructs a no op call for the getNumValidators()uint64 ABI method + * + * Returns the current number of validators + * + * @param args Any args for the contract call + * @param params Any additional parameters for the call + * @returns A TypedCallParams object for the call + */ + static getNumValidators(args: MethodArgs<'getNumValidators()uint64'>, params: AppClientCallCoreParams & CoreAppCallArgs) { + return { + method: 'getNumValidators()uint64' as const, + methodArgs: Array.isArray(args) ? args : [], + ...params, + } + } + /** + * Constructs a no op call for the getValidatorConfig(uint64)(uint64,address,address,uint64,uint8,byte[32],uint64,uint64,uint64,uint16,uint32,address,uint64,uint64,uint8,uint64,uint64) ABI method + * + * @param args Any args for the contract call + * @param params Any additional parameters for the call + * @returns A TypedCallParams object for the call + */ + static getValidatorConfig(args: MethodArgs<'getValidatorConfig(uint64)(uint64,address,address,uint64,uint8,byte[32],uint64,uint64,uint64,uint16,uint32,address,uint64,uint64,uint8,uint64,uint64)'>, params: AppClientCallCoreParams & CoreAppCallArgs) { + return { + method: 'getValidatorConfig(uint64)(uint64,address,address,uint64,uint8,byte[32],uint64,uint64,uint64,uint16,uint32,address,uint64,uint64,uint8,uint64,uint64)' as const, + methodArgs: Array.isArray(args) ? args : [args.validatorId], + ...params, + } + } + /** + * Constructs a no op call for the getValidatorState(uint64)(uint16,uint64,uint64,uint64) ABI method + * + * @param args Any args for the contract call + * @param params Any additional parameters for the call + * @returns A TypedCallParams object for the call + */ + static getValidatorState(args: MethodArgs<'getValidatorState(uint64)(uint16,uint64,uint64,uint64)'>, params: AppClientCallCoreParams & CoreAppCallArgs) { + return { + method: 'getValidatorState(uint64)(uint16,uint64,uint64,uint64)' as const, + methodArgs: Array.isArray(args) ? args : [args.validatorId], + ...params, + } + } + /** + * Constructs a no op call for the getValidatorOwnerAndManager(uint64)(address,address) ABI method + * + * @param args Any args for the contract call + * @param params Any additional parameters for the call + * @returns A TypedCallParams object for the call + */ + static getValidatorOwnerAndManager(args: MethodArgs<'getValidatorOwnerAndManager(uint64)(address,address)'>, params: AppClientCallCoreParams & CoreAppCallArgs) { + return { + method: 'getValidatorOwnerAndManager(uint64)(address,address)' as const, + methodArgs: Array.isArray(args) ? args : [args.validatorId], + ...params, + } + } + /** + * Constructs a no op call for the getPools(uint64)(uint64,uint16,uint64)[] ABI method + * + * Return list of all pools for this validator. + * + * @param args Any args for the contract call + * @param params Any additional parameters for the call + * @returns A TypedCallParams object for the call + */ + static getPools(args: MethodArgs<'getPools(uint64)(uint64,uint16,uint64)[]'>, params: AppClientCallCoreParams & CoreAppCallArgs) { + return { + method: 'getPools(uint64)(uint64,uint16,uint64)[]' as const, + methodArgs: Array.isArray(args) ? args : [args.validatorId], + ...params, + } + } + /** + * Constructs a no op call for the getPoolAppId(uint64,uint64)uint64 ABI method + * + * @param args Any args for the contract call + * @param params Any additional parameters for the call + * @returns A TypedCallParams object for the call + */ + static getPoolAppId(args: MethodArgs<'getPoolAppId(uint64,uint64)uint64'>, params: AppClientCallCoreParams & CoreAppCallArgs) { + return { + method: 'getPoolAppId(uint64,uint64)uint64' as const, + methodArgs: Array.isArray(args) ? args : [args.validatorId, args.poolId], + ...params, + } + } + /** + * Constructs a no op call for the getPoolInfo((uint64,uint64,uint64))(uint64,uint16,uint64) ABI method + * + * @param args Any args for the contract call + * @param params Any additional parameters for the call + * @returns A TypedCallParams object for the call + */ + static getPoolInfo(args: MethodArgs<'getPoolInfo((uint64,uint64,uint64))(uint64,uint16,uint64)'>, params: AppClientCallCoreParams & CoreAppCallArgs) { + return { + method: 'getPoolInfo((uint64,uint64,uint64))(uint64,uint16,uint64)' as const, + methodArgs: Array.isArray(args) ? args : [args.poolKey], + ...params, + } + } + /** + * Constructs a no op call for the getCurMaxStakePerPool(uint64)uint64 ABI method + * + * Calculate the maximum stake per pool for a given validator.Normally this would be maxAlgoPerPool, but it should also never go above MaxAllowedStake / numPools soas pools are added the max allowed per pool can reduce. + * + * @param args Any args for the contract call + * @param params Any additional parameters for the call + * @returns A TypedCallParams object for the call + */ + static getCurMaxStakePerPool(args: MethodArgs<'getCurMaxStakePerPool(uint64)uint64'>, params: AppClientCallCoreParams & CoreAppCallArgs) { + return { + method: 'getCurMaxStakePerPool(uint64)uint64' as const, + methodArgs: Array.isArray(args) ? args : [args.validatorId], + ...params, + } + } + /** + * Constructs a no op call for the doesStakerNeedToPayMBR(address)bool ABI method + * + * Helper callers can call w/ simulate to determine if 'AddStaker' MBR should be included w/ staking amount + * + * @param args Any args for the contract call + * @param params Any additional parameters for the call + * @returns A TypedCallParams object for the call + */ + static doesStakerNeedToPayMbr(args: MethodArgs<'doesStakerNeedToPayMBR(address)bool'>, params: AppClientCallCoreParams & CoreAppCallArgs) { + return { + method: 'doesStakerNeedToPayMBR(address)bool' as const, + methodArgs: Array.isArray(args) ? args : [args.staker], + ...params, + } + } + /** + * Constructs a no op call for the getStakedPoolsForAccount(address)(uint64,uint64,uint64)[] ABI method + * + * Retrieves the staked pools for an account. + * + * @param args Any args for the contract call + * @param params Any additional parameters for the call + * @returns A TypedCallParams object for the call + */ + static getStakedPoolsForAccount(args: MethodArgs<'getStakedPoolsForAccount(address)(uint64,uint64,uint64)[]'>, params: AppClientCallCoreParams & CoreAppCallArgs) { + return { + method: 'getStakedPoolsForAccount(address)(uint64,uint64,uint64)[]' as const, + methodArgs: Array.isArray(args) ? args : [args.staker], + ...params, + } + } + /** + * Constructs a no op call for the getTokenPayoutRatio(uint64)(uint64[24],uint64) ABI method + * + * Retrieves the token payout ratio for a given validator - returning the pool ratios of whole so that tokenpayouts across pools can be based on a stable snaphost of stake. + * + * @param args Any args for the contract call + * @param params Any additional parameters for the call + * @returns A TypedCallParams object for the call + */ + static getTokenPayoutRatio(args: MethodArgs<'getTokenPayoutRatio(uint64)(uint64[24],uint64)'>, params: AppClientCallCoreParams & CoreAppCallArgs) { + return { + method: 'getTokenPayoutRatio(uint64)(uint64[24],uint64)' as const, + methodArgs: Array.isArray(args) ? args : [args.validatorId], + ...params, + } + } + /** + * Constructs a no op call for the getNodePoolAssignments(uint64)((uint64[3])[8]) ABI method + * + * @param args Any args for the contract call + * @param params Any additional parameters for the call + * @returns A TypedCallParams object for the call + */ + static getNodePoolAssignments(args: MethodArgs<'getNodePoolAssignments(uint64)((uint64[3])[8])'>, params: AppClientCallCoreParams & CoreAppCallArgs) { + return { + method: 'getNodePoolAssignments(uint64)((uint64[3])[8])' as const, + methodArgs: Array.isArray(args) ? args : [args.validatorId], + ...params, + } + } + /** + * Constructs a no op call for the getNFDRegistryID()uint64 ABI method + * + * @param args Any args for the contract call + * @param params Any additional parameters for the call + * @returns A TypedCallParams object for the call + */ + static getNfdRegistryId(args: MethodArgs<'getNFDRegistryID()uint64'>, params: AppClientCallCoreParams & CoreAppCallArgs) { + return { + method: 'getNFDRegistryID()uint64' as const, + methodArgs: Array.isArray(args) ? args : [], + ...params, + } + } + /** + * Constructs a no op call for the addValidator(pay,string,(uint64,address,address,uint64,uint8,byte[32],uint64,uint64,uint64,uint16,uint32,address,uint64,uint64,uint8,uint64,uint64))uint64 ABI method + * + * Adds a new validator + * + * @param args Any args for the contract call + * @param params Any additional parameters for the call + * @returns A TypedCallParams object for the call + */ + static addValidator(args: MethodArgs<'addValidator(pay,string,(uint64,address,address,uint64,uint8,byte[32],uint64,uint64,uint64,uint16,uint32,address,uint64,uint64,uint8,uint64,uint64))uint64'>, params: AppClientCallCoreParams & CoreAppCallArgs) { + return { + method: 'addValidator(pay,string,(uint64,address,address,uint64,uint8,byte[32],uint64,uint64,uint64,uint16,uint32,address,uint64,uint64,uint8,uint64,uint64))uint64' as const, + methodArgs: Array.isArray(args) ? args : [args.mbrPayment, args.nfdName, args.config], + ...params, + } + } + /** + * Constructs a no op call for the changeValidatorManager(uint64,address)void ABI method + * + * Changes the Validator manager for a specific Validator id.[ ONLY OWNER CAN CHANGE ] + * + * @param args Any args for the contract call + * @param params Any additional parameters for the call + * @returns A TypedCallParams object for the call + */ + static changeValidatorManager(args: MethodArgs<'changeValidatorManager(uint64,address)void'>, params: AppClientCallCoreParams & CoreAppCallArgs) { + return { + method: 'changeValidatorManager(uint64,address)void' as const, + methodArgs: Array.isArray(args) ? args : [args.validatorId, args.manager], + ...params, + } + } + /** + * Constructs a no op call for the changeValidatorSunsetInfo(uint64,uint64,uint64)void ABI method + * + * Updates the sunset information for a given validator.[ ONLY OWNER CAN CHANGE ] + * + * @param args Any args for the contract call + * @param params Any additional parameters for the call + * @returns A TypedCallParams object for the call + */ + static changeValidatorSunsetInfo(args: MethodArgs<'changeValidatorSunsetInfo(uint64,uint64,uint64)void'>, params: AppClientCallCoreParams & CoreAppCallArgs) { + return { + method: 'changeValidatorSunsetInfo(uint64,uint64,uint64)void' as const, + methodArgs: Array.isArray(args) ? args : [args.validatorId, args.sunsettingOn, args.sunsettingTo], + ...params, + } + } + /** + * Constructs a no op call for the changeValidatorNFD(uint64,uint64,string)void ABI method + * + * Changes the NFD for a validator in the validatorList contract.[ ONLY OWNER OR MANAGER CAN CHANGE ] + * + * @param args Any args for the contract call + * @param params Any additional parameters for the call + * @returns A TypedCallParams object for the call + */ + static changeValidatorNfd(args: MethodArgs<'changeValidatorNFD(uint64,uint64,string)void'>, params: AppClientCallCoreParams & CoreAppCallArgs) { + return { + method: 'changeValidatorNFD(uint64,uint64,string)void' as const, + methodArgs: Array.isArray(args) ? args : [args.validatorId, args.nfdAppId, args.nfdName], + ...params, + } + } + /** + * Constructs a no op call for the changeValidatorCommissionAddress(uint64,address)void ABI method + * + * Change the commission address that validator rewards are sent to.[ ONLY OWNER CAN CHANGE ] + * + * @param args Any args for the contract call + * @param params Any additional parameters for the call + * @returns A TypedCallParams object for the call + */ + static changeValidatorCommissionAddress(args: MethodArgs<'changeValidatorCommissionAddress(uint64,address)void'>, params: AppClientCallCoreParams & CoreAppCallArgs) { + return { + method: 'changeValidatorCommissionAddress(uint64,address)void' as const, + methodArgs: Array.isArray(args) ? args : [args.validatorId, args.commissionAddress], + ...params, + } + } + /** + * Constructs a no op call for the changeValidatorRewardInfo(uint64,uint8,byte[32],uint64,uint64)void ABI method + * + * Allow the additional rewards (gating entry, additional token rewards) information be changed at will.[ ONLY OWNER CAN CHANGE ] + * + * @param args Any args for the contract call + * @param params Any additional parameters for the call + * @returns A TypedCallParams object for the call + */ + static changeValidatorRewardInfo(args: MethodArgs<'changeValidatorRewardInfo(uint64,uint8,byte[32],uint64,uint64)void'>, params: AppClientCallCoreParams & CoreAppCallArgs) { + return { + method: 'changeValidatorRewardInfo(uint64,uint8,byte[32],uint64,uint64)void' as const, + methodArgs: Array.isArray(args) ? args : [args.validatorId, args.entryGatingType, args.entryGatingValue, args.gatingAssetMinBalance, args.rewardPerPayout], + ...params, + } + } + /** + * Constructs a no op call for the addPool(pay,uint64,uint64)(uint64,uint64,uint64) ABI method + * + * Adds a new pool to a validator's pool set, returning the 'key' to reference the pool in the future for staking, etc.The caller must pay the cost of the validators MBR increase as well as the MBR that will be needed for the pool itself.[ ONLY OWNER OR MANAGER CAN call ] + * + * @param args Any args for the contract call + * @param params Any additional parameters for the call + * @returns A TypedCallParams object for the call + */ + static addPool(args: MethodArgs<'addPool(pay,uint64,uint64)(uint64,uint64,uint64)'>, params: AppClientCallCoreParams & CoreAppCallArgs) { + return { + method: 'addPool(pay,uint64,uint64)(uint64,uint64,uint64)' as const, + methodArgs: Array.isArray(args) ? args : [args.mbrPayment, args.validatorId, args.nodeNum], + ...params, + } + } + /** + * Constructs a no op call for the addStake(pay,uint64,uint64)(uint64,uint64,uint64) ABI method + * + * Adds stake to a validator pool. + * + * @param args Any args for the contract call + * @param params Any additional parameters for the call + * @returns A TypedCallParams object for the call + */ + static addStake(args: MethodArgs<'addStake(pay,uint64,uint64)(uint64,uint64,uint64)'>, params: AppClientCallCoreParams & CoreAppCallArgs) { + return { + method: 'addStake(pay,uint64,uint64)(uint64,uint64,uint64)' as const, + methodArgs: Array.isArray(args) ? args : [args.stakedAmountPayment, args.validatorId, args.valueToVerify], + ...params, + } + } + /** + * Constructs a no op call for the setTokenPayoutRatio(uint64)(uint64[24],uint64) ABI method + * + * setTokenPayoutRatio is called by Staking Pool # 1 (ONLY) to ask the validator (us) to calculate the ratiosof stake in the pools for subsequent token payouts (ie: 2 pools, '100' algo total staked, 60 in pool 1, and 40in pool 2. This is done so we have a stable snapshot of stake - taken once per epoch - only triggered bypool 1 doing payout. pools other than 1 doing payout call pool 1 to ask it do it first.It would be 60/40% in the poolPctOfWhole values. The token reward payouts then use these values instead oftheir 'current' stake which changes as part of the payouts themselves (and people could be changing stakeduring the epoch updates across pools)Multiple pools will call us via pool 1 (pool2->pool1->valdiator, etc.) so don't assert on pool1 calling multipletimes in same epoch. Just return. + * + * @param args Any args for the contract call + * @param params Any additional parameters for the call + * @returns A TypedCallParams object for the call + */ + static setTokenPayoutRatio(args: MethodArgs<'setTokenPayoutRatio(uint64)(uint64[24],uint64)'>, params: AppClientCallCoreParams & CoreAppCallArgs) { + return { + method: 'setTokenPayoutRatio(uint64)(uint64[24],uint64)' as const, + methodArgs: Array.isArray(args) ? args : [args.validatorId], + ...params, + } + } + /** + * Constructs a no op call for the stakeUpdatedViaRewards((uint64,uint64,uint64),uint64,uint64)void ABI method + * + * stakeUpdatedViaRewards is called by Staking pools to inform the validator (us) that a particular amount of totalstake has been added to the specified pool. This is used to update the stats we have in our PoolInfo storage.The calling App id is validated against our pool list as well. + * + * @param args Any args for the contract call + * @param params Any additional parameters for the call + * @returns A TypedCallParams object for the call + */ + static stakeUpdatedViaRewards(args: MethodArgs<'stakeUpdatedViaRewards((uint64,uint64,uint64),uint64,uint64)void'>, params: AppClientCallCoreParams & CoreAppCallArgs) { + return { + method: 'stakeUpdatedViaRewards((uint64,uint64,uint64),uint64,uint64)void' as const, + methodArgs: Array.isArray(args) ? args : [args.poolKey, args.algoToAdd, args.rewardTokenAmountReserved], + ...params, + } + } + /** + * Constructs a no op call for the stakeRemoved((uint64,uint64,uint64),address,uint64,uint64,bool)void ABI method + * + * stakeRemoved is called by Staking pools to inform the validator (us) that a particular amount of total stake has been removedfrom the specified pool. This is used to update the stats we have in our PoolInfo storage.If any amount of rewardRemoved is specified, then that amount of reward is sent to the useThe calling App id is validated against our pool list as well. + * + * @param args Any args for the contract call + * @param params Any additional parameters for the call + * @returns A TypedCallParams object for the call + */ + static stakeRemoved(args: MethodArgs<'stakeRemoved((uint64,uint64,uint64),address,uint64,uint64,bool)void'>, params: AppClientCallCoreParams & CoreAppCallArgs) { + return { + method: 'stakeRemoved((uint64,uint64,uint64),address,uint64,uint64,bool)void' as const, + methodArgs: Array.isArray(args) ? args : [args.poolKey, args.staker, args.amountRemoved, args.rewardRemoved, args.stakerRemoved], + ...params, + } + } + /** + * Constructs a no op call for the findPoolForStaker(uint64,address,uint64)((uint64,uint64,uint64),bool,bool) ABI method + * + * Finds the pool for a staker based on the provided validator id, staker address, and amount to stake.First checks the stakers 'already staked list' for the validator preferring those (adding if possible) then addsto new pool if necessary. + * + * @param args Any args for the contract call + * @param params Any additional parameters for the call + * @returns A TypedCallParams object for the call + */ + static findPoolForStaker(args: MethodArgs<'findPoolForStaker(uint64,address,uint64)((uint64,uint64,uint64),bool,bool)'>, params: AppClientCallCoreParams & CoreAppCallArgs) { + return { + method: 'findPoolForStaker(uint64,address,uint64)((uint64,uint64,uint64),bool,bool)' as const, + methodArgs: Array.isArray(args) ? args : [args.validatorId, args.staker, args.amountToStake], + ...params, + } + } + /** + * Constructs a no op call for the movePoolToNode(uint64,uint64,uint64)void ABI method + * + * Find the specified pool (in any node number) and move it to the specified node.The pool account is forced offline if moved so prior node will still run for 320 rounds butnew key goes online on new node soon after (320 rounds after it goes online)No-op if success, asserts if not found or can't move (no space in target)[ ONLY OWNER OR MANAGER CAN CHANGE ]Only callable by owner or manager + * + * @param args Any args for the contract call + * @param params Any additional parameters for the call + * @returns A TypedCallParams object for the call + */ + static movePoolToNode(args: MethodArgs<'movePoolToNode(uint64,uint64,uint64)void'>, params: AppClientCallCoreParams & CoreAppCallArgs) { + return { + method: 'movePoolToNode(uint64,uint64,uint64)void' as const, + methodArgs: Array.isArray(args) ? args : [args.validatorId, args.poolAppId, args.nodeNum], + ...params, + } + } +} + +/** + * A client to make calls to the ValidatorRegistry smart contract + */ +export class ValidatorRegistryClient { + /** + * The underlying `ApplicationClient` for when you want to have more flexibility + */ + public readonly appClient: ApplicationClient + + private readonly sender: SendTransactionFrom | undefined + + /** + * Creates a new instance of `ValidatorRegistryClient` + * + * @param appDetails appDetails The details to identify the app to deploy + * @param algod An algod client instance + */ + constructor(appDetails: AppDetails, private algod: Algodv2) { + this.sender = appDetails.sender + this.appClient = algokit.getAppClient({ + ...appDetails, + app: APP_SPEC + }, algod) + } + + /** + * Checks for decode errors on the AppCallTransactionResult and maps the return value to the specified generic type + * + * @param result The AppCallTransactionResult to be mapped + * @param returnValueFormatter An optional delegate to format the return value if required + * @returns The smart contract response with an updated return value + */ + protected mapReturnValue(result: AppCallTransactionResult, returnValueFormatter?: (value: any) => TReturn): AppCallTransactionResultOfType & TResult { + if(result.return?.decodeError) { + throw result.return.decodeError + } + const returnValue = result.return?.returnValue !== undefined && returnValueFormatter !== undefined + ? returnValueFormatter(result.return.returnValue) + : result.return?.returnValue as TReturn | undefined + return { ...result, return: returnValue } as AppCallTransactionResultOfType & TResult + } + + /** + * Calls the ABI method with the matching signature using an onCompletion code of NO_OP + * + * @param typedCallParams An object containing the method signature, args, and any other relevant parameters + * @param returnValueFormatter An optional delegate which when provided will be used to map non-undefined return values to the target type + * @returns The result of the smart contract call + */ + public async call(typedCallParams: TypedCallParams, returnValueFormatter?: (value: any) => MethodReturn) { + return this.mapReturnValue>(await this.appClient.call(typedCallParams), returnValueFormatter) + } + + /** + * Idempotently deploys the ValidatorRegistry smart contract. + * + * @param params The arguments for the contract calls and any additional parameters for the call + * @returns The deployment result + */ + public deploy(params: ValidatorRegistryDeployArgs & AppClientDeployCoreParams & IncludeSchema = {}): ReturnType { + const createArgs = params.createCall?.(ValidatorRegistryCallFactory.create) + return this.appClient.deploy({ + ...params, + createArgs, + createOnCompleteAction: createArgs?.onCompleteAction, + }) + } + + /** + * Gets available create methods + */ + public get create() { + const $this = this + return { + /** + * Creates a new instance of the ValidatorRegistry smart contract using the createApplication(uint64)void ABI method. + * + * @param args The arguments for the smart contract call + * @param params Any additional parameters for the call + * @returns The create result + */ + async createApplication(args: MethodArgs<'createApplication(uint64)void'>, params: AppClientCallCoreParams & AppClientCompilationParams & IncludeSchema & (OnCompleteNoOp) = {}) { + return $this.mapReturnValue, AppCreateCallTransactionResult>(await $this.appClient.create(ValidatorRegistryCallFactory.create.createApplication(args, params))) + }, + } + } + + /** + * Makes a clear_state call to an existing instance of the ValidatorRegistry smart contract. + * + * @param args The arguments for the bare call + * @returns The clear_state result + */ + public clearState(args: BareCallArgs & AppClientCallCoreParams & CoreAppCallArgs = {}) { + return this.appClient.clearState(args) + } + + /** + * Calls the gas()void ABI method. + * + * gas is a dummy no-op call that can be used to pool-up resource references and opcode cost + * + * @param args The arguments for the contract call + * @param params Any additional parameters for the call + * @returns The result of the call + */ + public gas(args: MethodArgs<'gas()void'>, params: AppClientCallCoreParams & CoreAppCallArgs = {}) { + return this.call(ValidatorRegistryCallFactory.gas(args, params)) + } + + /** + * Calls the getMbrAmounts()(uint64,uint64,uint64,uint64) ABI method. + * + * Returns the MBR amounts needed for various actions:[addValidatorMbr: uint64 - mbr needed to add a new validator - paid to validator contractaddPoolMbr: uint64 - mbr needed to add a new pool - paid to validatorpoolInitMbr: uint64 - mbr needed to initStorage() of pool - paid to pool itselfaddStakerMbr: uint64 - mbr staker needs to add to first staking payment (stays w/ validator)] + * + * @param args The arguments for the contract call + * @param params Any additional parameters for the call + * @returns The result of the call + */ + public getMbrAmounts(args: MethodArgs<'getMbrAmounts()(uint64,uint64,uint64,uint64)'>, params: AppClientCallCoreParams & CoreAppCallArgs = {}) { + return this.call(ValidatorRegistryCallFactory.getMbrAmounts(args, params)) + } + + /** + * Calls the getProtocolConstraints()(uint64,uint64,uint64,uint64,uint64,uint64,uint64,uint64,uint64,uint64,uint64) ABI method. + * + * Returns the protocol constraints so that UIs can limit what users specify for validator configuration parameters. + * + * @param args The arguments for the contract call + * @param params Any additional parameters for the call + * @returns The result of the call + */ + public getProtocolConstraints(args: MethodArgs<'getProtocolConstraints()(uint64,uint64,uint64,uint64,uint64,uint64,uint64,uint64,uint64,uint64,uint64)'>, params: AppClientCallCoreParams & CoreAppCallArgs = {}) { + return this.call(ValidatorRegistryCallFactory.getProtocolConstraints(args, params)) + } + + /** + * Calls the getNumValidators()uint64 ABI method. + * + * Returns the current number of validators + * + * @param args The arguments for the contract call + * @param params Any additional parameters for the call + * @returns The result of the call + */ + public getNumValidators(args: MethodArgs<'getNumValidators()uint64'>, params: AppClientCallCoreParams & CoreAppCallArgs = {}) { + return this.call(ValidatorRegistryCallFactory.getNumValidators(args, params)) + } + + /** + * Calls the getValidatorConfig(uint64)(uint64,address,address,uint64,uint8,byte[32],uint64,uint64,uint64,uint16,uint32,address,uint64,uint64,uint8,uint64,uint64) ABI method. + * + * @param args The arguments for the contract call + * @param params Any additional parameters for the call + * @returns The result of the call + */ + public getValidatorConfig(args: MethodArgs<'getValidatorConfig(uint64)(uint64,address,address,uint64,uint8,byte[32],uint64,uint64,uint64,uint16,uint32,address,uint64,uint64,uint8,uint64,uint64)'>, params: AppClientCallCoreParams & CoreAppCallArgs = {}) { + return this.call(ValidatorRegistryCallFactory.getValidatorConfig(args, params)) + } + + /** + * Calls the getValidatorState(uint64)(uint16,uint64,uint64,uint64) ABI method. + * + * @param args The arguments for the contract call + * @param params Any additional parameters for the call + * @returns The result of the call + */ + public getValidatorState(args: MethodArgs<'getValidatorState(uint64)(uint16,uint64,uint64,uint64)'>, params: AppClientCallCoreParams & CoreAppCallArgs = {}) { + return this.call(ValidatorRegistryCallFactory.getValidatorState(args, params)) + } + + /** + * Calls the getValidatorOwnerAndManager(uint64)(address,address) ABI method. + * + * @param args The arguments for the contract call + * @param params Any additional parameters for the call + * @returns The result of the call + */ + public getValidatorOwnerAndManager(args: MethodArgs<'getValidatorOwnerAndManager(uint64)(address,address)'>, params: AppClientCallCoreParams & CoreAppCallArgs = {}) { + return this.call(ValidatorRegistryCallFactory.getValidatorOwnerAndManager(args, params)) + } + + /** + * Calls the getPools(uint64)(uint64,uint16,uint64)[] ABI method. + * + * Return list of all pools for this validator. + * + * @param args The arguments for the contract call + * @param params Any additional parameters for the call + * @returns The result of the call + */ + public getPools(args: MethodArgs<'getPools(uint64)(uint64,uint16,uint64)[]'>, params: AppClientCallCoreParams & CoreAppCallArgs = {}) { + return this.call(ValidatorRegistryCallFactory.getPools(args, params)) + } + + /** + * Calls the getPoolAppId(uint64,uint64)uint64 ABI method. + * + * @param args The arguments for the contract call + * @param params Any additional parameters for the call + * @returns The result of the call + */ + public getPoolAppId(args: MethodArgs<'getPoolAppId(uint64,uint64)uint64'>, params: AppClientCallCoreParams & CoreAppCallArgs = {}) { + return this.call(ValidatorRegistryCallFactory.getPoolAppId(args, params)) + } + + /** + * Calls the getPoolInfo((uint64,uint64,uint64))(uint64,uint16,uint64) ABI method. + * + * @param args The arguments for the contract call + * @param params Any additional parameters for the call + * @returns The result of the call + */ + public getPoolInfo(args: MethodArgs<'getPoolInfo((uint64,uint64,uint64))(uint64,uint16,uint64)'>, params: AppClientCallCoreParams & CoreAppCallArgs = {}) { + return this.call(ValidatorRegistryCallFactory.getPoolInfo(args, params)) + } + + /** + * Calls the getCurMaxStakePerPool(uint64)uint64 ABI method. + * + * Calculate the maximum stake per pool for a given validator.Normally this would be maxAlgoPerPool, but it should also never go above MaxAllowedStake / numPools soas pools are added the max allowed per pool can reduce. + * + * @param args The arguments for the contract call + * @param params Any additional parameters for the call + * @returns The result of the call + */ + public getCurMaxStakePerPool(args: MethodArgs<'getCurMaxStakePerPool(uint64)uint64'>, params: AppClientCallCoreParams & CoreAppCallArgs = {}) { + return this.call(ValidatorRegistryCallFactory.getCurMaxStakePerPool(args, params)) + } + + /** + * Calls the doesStakerNeedToPayMBR(address)bool ABI method. + * + * Helper callers can call w/ simulate to determine if 'AddStaker' MBR should be included w/ staking amount + * + * @param args The arguments for the contract call + * @param params Any additional parameters for the call + * @returns The result of the call + */ + public doesStakerNeedToPayMbr(args: MethodArgs<'doesStakerNeedToPayMBR(address)bool'>, params: AppClientCallCoreParams & CoreAppCallArgs = {}) { + return this.call(ValidatorRegistryCallFactory.doesStakerNeedToPayMbr(args, params)) + } + + /** + * Calls the getStakedPoolsForAccount(address)(uint64,uint64,uint64)[] ABI method. + * + * Retrieves the staked pools for an account. + * + * @param args The arguments for the contract call + * @param params Any additional parameters for the call + * @returns The result of the call + */ + public getStakedPoolsForAccount(args: MethodArgs<'getStakedPoolsForAccount(address)(uint64,uint64,uint64)[]'>, params: AppClientCallCoreParams & CoreAppCallArgs = {}) { + return this.call(ValidatorRegistryCallFactory.getStakedPoolsForAccount(args, params)) + } + + /** + * Calls the getTokenPayoutRatio(uint64)(uint64[24],uint64) ABI method. + * + * Retrieves the token payout ratio for a given validator - returning the pool ratios of whole so that tokenpayouts across pools can be based on a stable snaphost of stake. + * + * @param args The arguments for the contract call + * @param params Any additional parameters for the call + * @returns The result of the call + */ + public getTokenPayoutRatio(args: MethodArgs<'getTokenPayoutRatio(uint64)(uint64[24],uint64)'>, params: AppClientCallCoreParams & CoreAppCallArgs = {}) { + return this.call(ValidatorRegistryCallFactory.getTokenPayoutRatio(args, params)) + } + + /** + * Calls the getNodePoolAssignments(uint64)((uint64[3])[8]) ABI method. + * + * @param args The arguments for the contract call + * @param params Any additional parameters for the call + * @returns The result of the call + */ + public getNodePoolAssignments(args: MethodArgs<'getNodePoolAssignments(uint64)((uint64[3])[8])'>, params: AppClientCallCoreParams & CoreAppCallArgs = {}) { + return this.call(ValidatorRegistryCallFactory.getNodePoolAssignments(args, params)) + } + + /** + * Calls the getNFDRegistryID()uint64 ABI method. + * + * @param args The arguments for the contract call + * @param params Any additional parameters for the call + * @returns The result of the call + */ + public getNfdRegistryId(args: MethodArgs<'getNFDRegistryID()uint64'>, params: AppClientCallCoreParams & CoreAppCallArgs = {}) { + return this.call(ValidatorRegistryCallFactory.getNfdRegistryId(args, params)) + } + + /** + * Calls the addValidator(pay,string,(uint64,address,address,uint64,uint8,byte[32],uint64,uint64,uint64,uint16,uint32,address,uint64,uint64,uint8,uint64,uint64))uint64 ABI method. + * + * Adds a new validator + * + * @param args The arguments for the contract call + * @param params Any additional parameters for the call + * @returns The result of the call: validator id + */ + public addValidator(args: MethodArgs<'addValidator(pay,string,(uint64,address,address,uint64,uint8,byte[32],uint64,uint64,uint64,uint16,uint32,address,uint64,uint64,uint8,uint64,uint64))uint64'>, params: AppClientCallCoreParams & CoreAppCallArgs = {}) { + return this.call(ValidatorRegistryCallFactory.addValidator(args, params)) + } + + /** + * Calls the changeValidatorManager(uint64,address)void ABI method. + * + * Changes the Validator manager for a specific Validator id.[ ONLY OWNER CAN CHANGE ] + * + * @param args The arguments for the contract call + * @param params Any additional parameters for the call + * @returns The result of the call + */ + public changeValidatorManager(args: MethodArgs<'changeValidatorManager(uint64,address)void'>, params: AppClientCallCoreParams & CoreAppCallArgs = {}) { + return this.call(ValidatorRegistryCallFactory.changeValidatorManager(args, params)) + } + + /** + * Calls the changeValidatorSunsetInfo(uint64,uint64,uint64)void ABI method. + * + * Updates the sunset information for a given validator.[ ONLY OWNER CAN CHANGE ] + * + * @param args The arguments for the contract call + * @param params Any additional parameters for the call + * @returns The result of the call + */ + public changeValidatorSunsetInfo(args: MethodArgs<'changeValidatorSunsetInfo(uint64,uint64,uint64)void'>, params: AppClientCallCoreParams & CoreAppCallArgs = {}) { + return this.call(ValidatorRegistryCallFactory.changeValidatorSunsetInfo(args, params)) + } + + /** + * Calls the changeValidatorNFD(uint64,uint64,string)void ABI method. + * + * Changes the NFD for a validator in the validatorList contract.[ ONLY OWNER OR MANAGER CAN CHANGE ] + * + * @param args The arguments for the contract call + * @param params Any additional parameters for the call + * @returns The result of the call + */ + public changeValidatorNfd(args: MethodArgs<'changeValidatorNFD(uint64,uint64,string)void'>, params: AppClientCallCoreParams & CoreAppCallArgs = {}) { + return this.call(ValidatorRegistryCallFactory.changeValidatorNfd(args, params)) + } + + /** + * Calls the changeValidatorCommissionAddress(uint64,address)void ABI method. + * + * Change the commission address that validator rewards are sent to.[ ONLY OWNER CAN CHANGE ] + * + * @param args The arguments for the contract call + * @param params Any additional parameters for the call + * @returns The result of the call + */ + public changeValidatorCommissionAddress(args: MethodArgs<'changeValidatorCommissionAddress(uint64,address)void'>, params: AppClientCallCoreParams & CoreAppCallArgs = {}) { + return this.call(ValidatorRegistryCallFactory.changeValidatorCommissionAddress(args, params)) + } + + /** + * Calls the changeValidatorRewardInfo(uint64,uint8,byte[32],uint64,uint64)void ABI method. + * + * Allow the additional rewards (gating entry, additional token rewards) information be changed at will.[ ONLY OWNER CAN CHANGE ] + * + * @param args The arguments for the contract call + * @param params Any additional parameters for the call + * @returns The result of the call + */ + public changeValidatorRewardInfo(args: MethodArgs<'changeValidatorRewardInfo(uint64,uint8,byte[32],uint64,uint64)void'>, params: AppClientCallCoreParams & CoreAppCallArgs = {}) { + return this.call(ValidatorRegistryCallFactory.changeValidatorRewardInfo(args, params)) + } + + /** + * Calls the addPool(pay,uint64,uint64)(uint64,uint64,uint64) ABI method. + * + * Adds a new pool to a validator's pool set, returning the 'key' to reference the pool in the future for staking, etc.The caller must pay the cost of the validators MBR increase as well as the MBR that will be needed for the pool itself.[ ONLY OWNER OR MANAGER CAN call ] + * + * @param args The arguments for the contract call + * @param params Any additional parameters for the call + * @returns The result of the call: {ValidatorPoolKey}pool key to created pool + */ + public addPool(args: MethodArgs<'addPool(pay,uint64,uint64)(uint64,uint64,uint64)'>, params: AppClientCallCoreParams & CoreAppCallArgs = {}) { + return this.call(ValidatorRegistryCallFactory.addPool(args, params)) + } + + /** + * Calls the addStake(pay,uint64,uint64)(uint64,uint64,uint64) ABI method. + * + * Adds stake to a validator pool. + * + * @param args The arguments for the contract call + * @param params Any additional parameters for the call + * @returns The result of the call: {ValidatorPoolKey}- The key of the validator pool. + */ + public addStake(args: MethodArgs<'addStake(pay,uint64,uint64)(uint64,uint64,uint64)'>, params: AppClientCallCoreParams & CoreAppCallArgs = {}) { + return this.call(ValidatorRegistryCallFactory.addStake(args, params)) + } + + /** + * Calls the setTokenPayoutRatio(uint64)(uint64[24],uint64) ABI method. + * + * setTokenPayoutRatio is called by Staking Pool # 1 (ONLY) to ask the validator (us) to calculate the ratiosof stake in the pools for subsequent token payouts (ie: 2 pools, '100' algo total staked, 60 in pool 1, and 40in pool 2. This is done so we have a stable snapshot of stake - taken once per epoch - only triggered bypool 1 doing payout. pools other than 1 doing payout call pool 1 to ask it do it first.It would be 60/40% in the poolPctOfWhole values. The token reward payouts then use these values instead oftheir 'current' stake which changes as part of the payouts themselves (and people could be changing stakeduring the epoch updates across pools)Multiple pools will call us via pool 1 (pool2->pool1->valdiator, etc.) so don't assert on pool1 calling multipletimes in same epoch. Just return. + * + * @param args The arguments for the contract call + * @param params Any additional parameters for the call + * @returns The result of the call: PoolTokenPayoutRatio - the finished ratio data + */ + public setTokenPayoutRatio(args: MethodArgs<'setTokenPayoutRatio(uint64)(uint64[24],uint64)'>, params: AppClientCallCoreParams & CoreAppCallArgs = {}) { + return this.call(ValidatorRegistryCallFactory.setTokenPayoutRatio(args, params)) + } + + /** + * Calls the stakeUpdatedViaRewards((uint64,uint64,uint64),uint64,uint64)void ABI method. + * + * stakeUpdatedViaRewards is called by Staking pools to inform the validator (us) that a particular amount of totalstake has been added to the specified pool. This is used to update the stats we have in our PoolInfo storage.The calling App id is validated against our pool list as well. + * + * @param args The arguments for the contract call + * @param params Any additional parameters for the call + * @returns The result of the call + */ + public stakeUpdatedViaRewards(args: MethodArgs<'stakeUpdatedViaRewards((uint64,uint64,uint64),uint64,uint64)void'>, params: AppClientCallCoreParams & CoreAppCallArgs = {}) { + return this.call(ValidatorRegistryCallFactory.stakeUpdatedViaRewards(args, params)) + } + + /** + * Calls the stakeRemoved((uint64,uint64,uint64),address,uint64,uint64,bool)void ABI method. + * + * stakeRemoved is called by Staking pools to inform the validator (us) that a particular amount of total stake has been removedfrom the specified pool. This is used to update the stats we have in our PoolInfo storage.If any amount of rewardRemoved is specified, then that amount of reward is sent to the useThe calling App id is validated against our pool list as well. + * + * @param args The arguments for the contract call + * @param params Any additional parameters for the call + * @returns The result of the call + */ + public stakeRemoved(args: MethodArgs<'stakeRemoved((uint64,uint64,uint64),address,uint64,uint64,bool)void'>, params: AppClientCallCoreParams & CoreAppCallArgs = {}) { + return this.call(ValidatorRegistryCallFactory.stakeRemoved(args, params)) + } + + /** + * Calls the findPoolForStaker(uint64,address,uint64)((uint64,uint64,uint64),bool,bool) ABI method. + * + * Finds the pool for a staker based on the provided validator id, staker address, and amount to stake.First checks the stakers 'already staked list' for the validator preferring those (adding if possible) then addsto new pool if necessary. + * + * @param args The arguments for the contract call + * @param params Any additional parameters for the call + * @returns The result of the call: {ValidatorPoolKey, boolean, boolean}- The pool for the staker, true/false on whether the staker is 'new'to this VALIDATOR, and true/false if staker is new to the protocol. + */ + public findPoolForStaker(args: MethodArgs<'findPoolForStaker(uint64,address,uint64)((uint64,uint64,uint64),bool,bool)'>, params: AppClientCallCoreParams & CoreAppCallArgs = {}) { + return this.call(ValidatorRegistryCallFactory.findPoolForStaker(args, params)) + } + + /** + * Calls the movePoolToNode(uint64,uint64,uint64)void ABI method. + * + * Find the specified pool (in any node number) and move it to the specified node.The pool account is forced offline if moved so prior node will still run for 320 rounds butnew key goes online on new node soon after (320 rounds after it goes online)No-op if success, asserts if not found or can't move (no space in target)[ ONLY OWNER OR MANAGER CAN CHANGE ]Only callable by owner or manager + * + * @param args The arguments for the contract call + * @param params Any additional parameters for the call + * @returns The result of the call + */ + public movePoolToNode(args: MethodArgs<'movePoolToNode(uint64,uint64,uint64)void'>, params: AppClientCallCoreParams & CoreAppCallArgs = {}) { + return this.call(ValidatorRegistryCallFactory.movePoolToNode(args, params)) + } + + /** + * Extracts a binary state value out of an AppState dictionary + * + * @param state The state dictionary containing the state value + * @param key The key of the state value + * @returns A BinaryState instance containing the state value, or undefined if the key was not found + */ + private static getBinaryState(state: AppState, key: string): BinaryState | undefined { + const value = state[key] + if (!value) return undefined + if (!('valueRaw' in value)) + throw new Error(`Failed to parse state value for ${key}; received an int when expected a byte array`) + return { + asString(): string { + return value.value + }, + asByteArray(): Uint8Array { + return value.valueRaw + } + } + } + + /** + * Extracts a integer state value out of an AppState dictionary + * + * @param state The state dictionary containing the state value + * @param key The key of the state value + * @returns An IntegerState instance containing the state value, or undefined if the key was not found + */ + private static getIntegerState(state: AppState, key: string): IntegerState | undefined { + const value = state[key] + if (!value) return undefined + if ('valueRaw' in value) + throw new Error(`Failed to parse state value for ${key}; received a byte array when expected a number`) + return { + asBigInt() { + return typeof value.value === 'bigint' ? value.value : BigInt(value.value) + }, + asNumber(): number { + return typeof value.value === 'bigint' ? Number(value.value) : value.value + }, + } + } + + /** + * Returns the smart contract's global state wrapped in a strongly typed accessor with options to format the stored value + */ + public async getGlobalState(): Promise { + const state = await this.appClient.getGlobalState() + return { + get numV() { + return ValidatorRegistryClient.getIntegerState(state, 'numV') + }, + get poolTemplateAppId() { + return ValidatorRegistryClient.getIntegerState(state, 'poolTemplateAppId') + }, + get numStakers() { + return ValidatorRegistryClient.getIntegerState(state, 'numStakers') + }, + get staked() { + return ValidatorRegistryClient.getIntegerState(state, 'staked') + }, + } + } + + public compose(): ValidatorRegistryComposer { + const client = this + const atc = new AtomicTransactionComposer() + let promiseChain:Promise = Promise.resolve() + const resultMappers: Array any)> = [] + return { + gas(args: MethodArgs<'gas()void'>, params?: AppClientComposeCallCoreParams & CoreAppCallArgs) { + promiseChain = promiseChain.then(() => client.gas(args, {...params, sendParams: {...params?.sendParams, skipSending: true, atc}})) + resultMappers.push(undefined) + return this + }, + getMbrAmounts(args: MethodArgs<'getMbrAmounts()(uint64,uint64,uint64,uint64)'>, params?: AppClientComposeCallCoreParams & CoreAppCallArgs) { + promiseChain = promiseChain.then(() => client.getMbrAmounts(args, {...params, sendParams: {...params?.sendParams, skipSending: true, atc}})) + resultMappers.push(undefined) + return this + }, + getProtocolConstraints(args: MethodArgs<'getProtocolConstraints()(uint64,uint64,uint64,uint64,uint64,uint64,uint64,uint64,uint64,uint64,uint64)'>, params?: AppClientComposeCallCoreParams & CoreAppCallArgs) { + promiseChain = promiseChain.then(() => client.getProtocolConstraints(args, {...params, sendParams: {...params?.sendParams, skipSending: true, atc}})) + resultMappers.push(undefined) + return this + }, + getNumValidators(args: MethodArgs<'getNumValidators()uint64'>, params?: AppClientComposeCallCoreParams & CoreAppCallArgs) { + promiseChain = promiseChain.then(() => client.getNumValidators(args, {...params, sendParams: {...params?.sendParams, skipSending: true, atc}})) + resultMappers.push(undefined) + return this + }, + getValidatorConfig(args: MethodArgs<'getValidatorConfig(uint64)(uint64,address,address,uint64,uint8,byte[32],uint64,uint64,uint64,uint16,uint32,address,uint64,uint64,uint8,uint64,uint64)'>, params?: AppClientComposeCallCoreParams & CoreAppCallArgs) { + promiseChain = promiseChain.then(() => client.getValidatorConfig(args, {...params, sendParams: {...params?.sendParams, skipSending: true, atc}})) + resultMappers.push(undefined) + return this + }, + getValidatorState(args: MethodArgs<'getValidatorState(uint64)(uint16,uint64,uint64,uint64)'>, params?: AppClientComposeCallCoreParams & CoreAppCallArgs) { + promiseChain = promiseChain.then(() => client.getValidatorState(args, {...params, sendParams: {...params?.sendParams, skipSending: true, atc}})) + resultMappers.push(undefined) + return this + }, + getValidatorOwnerAndManager(args: MethodArgs<'getValidatorOwnerAndManager(uint64)(address,address)'>, params?: AppClientComposeCallCoreParams & CoreAppCallArgs) { + promiseChain = promiseChain.then(() => client.getValidatorOwnerAndManager(args, {...params, sendParams: {...params?.sendParams, skipSending: true, atc}})) + resultMappers.push(undefined) + return this + }, + getPools(args: MethodArgs<'getPools(uint64)(uint64,uint16,uint64)[]'>, params?: AppClientComposeCallCoreParams & CoreAppCallArgs) { + promiseChain = promiseChain.then(() => client.getPools(args, {...params, sendParams: {...params?.sendParams, skipSending: true, atc}})) + resultMappers.push(undefined) + return this + }, + getPoolAppId(args: MethodArgs<'getPoolAppId(uint64,uint64)uint64'>, params?: AppClientComposeCallCoreParams & CoreAppCallArgs) { + promiseChain = promiseChain.then(() => client.getPoolAppId(args, {...params, sendParams: {...params?.sendParams, skipSending: true, atc}})) + resultMappers.push(undefined) + return this + }, + getPoolInfo(args: MethodArgs<'getPoolInfo((uint64,uint64,uint64))(uint64,uint16,uint64)'>, params?: AppClientComposeCallCoreParams & CoreAppCallArgs) { + promiseChain = promiseChain.then(() => client.getPoolInfo(args, {...params, sendParams: {...params?.sendParams, skipSending: true, atc}})) + resultMappers.push(undefined) + return this + }, + getCurMaxStakePerPool(args: MethodArgs<'getCurMaxStakePerPool(uint64)uint64'>, params?: AppClientComposeCallCoreParams & CoreAppCallArgs) { + promiseChain = promiseChain.then(() => client.getCurMaxStakePerPool(args, {...params, sendParams: {...params?.sendParams, skipSending: true, atc}})) + resultMappers.push(undefined) + return this + }, + doesStakerNeedToPayMbr(args: MethodArgs<'doesStakerNeedToPayMBR(address)bool'>, params?: AppClientComposeCallCoreParams & CoreAppCallArgs) { + promiseChain = promiseChain.then(() => client.doesStakerNeedToPayMbr(args, {...params, sendParams: {...params?.sendParams, skipSending: true, atc}})) + resultMappers.push(undefined) + return this + }, + getStakedPoolsForAccount(args: MethodArgs<'getStakedPoolsForAccount(address)(uint64,uint64,uint64)[]'>, params?: AppClientComposeCallCoreParams & CoreAppCallArgs) { + promiseChain = promiseChain.then(() => client.getStakedPoolsForAccount(args, {...params, sendParams: {...params?.sendParams, skipSending: true, atc}})) + resultMappers.push(undefined) + return this + }, + getTokenPayoutRatio(args: MethodArgs<'getTokenPayoutRatio(uint64)(uint64[24],uint64)'>, params?: AppClientComposeCallCoreParams & CoreAppCallArgs) { + promiseChain = promiseChain.then(() => client.getTokenPayoutRatio(args, {...params, sendParams: {...params?.sendParams, skipSending: true, atc}})) + resultMappers.push(undefined) + return this + }, + getNodePoolAssignments(args: MethodArgs<'getNodePoolAssignments(uint64)((uint64[3])[8])'>, params?: AppClientComposeCallCoreParams & CoreAppCallArgs) { + promiseChain = promiseChain.then(() => client.getNodePoolAssignments(args, {...params, sendParams: {...params?.sendParams, skipSending: true, atc}})) + resultMappers.push(undefined) + return this + }, + getNfdRegistryId(args: MethodArgs<'getNFDRegistryID()uint64'>, params?: AppClientComposeCallCoreParams & CoreAppCallArgs) { + promiseChain = promiseChain.then(() => client.getNfdRegistryId(args, {...params, sendParams: {...params?.sendParams, skipSending: true, atc}})) + resultMappers.push(undefined) + return this + }, + addValidator(args: MethodArgs<'addValidator(pay,string,(uint64,address,address,uint64,uint8,byte[32],uint64,uint64,uint64,uint16,uint32,address,uint64,uint64,uint8,uint64,uint64))uint64'>, params?: AppClientComposeCallCoreParams & CoreAppCallArgs) { + promiseChain = promiseChain.then(() => client.addValidator(args, {...params, sendParams: {...params?.sendParams, skipSending: true, atc}})) + resultMappers.push(undefined) + return this + }, + changeValidatorManager(args: MethodArgs<'changeValidatorManager(uint64,address)void'>, params?: AppClientComposeCallCoreParams & CoreAppCallArgs) { + promiseChain = promiseChain.then(() => client.changeValidatorManager(args, {...params, sendParams: {...params?.sendParams, skipSending: true, atc}})) + resultMappers.push(undefined) + return this + }, + changeValidatorSunsetInfo(args: MethodArgs<'changeValidatorSunsetInfo(uint64,uint64,uint64)void'>, params?: AppClientComposeCallCoreParams & CoreAppCallArgs) { + promiseChain = promiseChain.then(() => client.changeValidatorSunsetInfo(args, {...params, sendParams: {...params?.sendParams, skipSending: true, atc}})) + resultMappers.push(undefined) + return this + }, + changeValidatorNfd(args: MethodArgs<'changeValidatorNFD(uint64,uint64,string)void'>, params?: AppClientComposeCallCoreParams & CoreAppCallArgs) { + promiseChain = promiseChain.then(() => client.changeValidatorNfd(args, {...params, sendParams: {...params?.sendParams, skipSending: true, atc}})) + resultMappers.push(undefined) + return this + }, + changeValidatorCommissionAddress(args: MethodArgs<'changeValidatorCommissionAddress(uint64,address)void'>, params?: AppClientComposeCallCoreParams & CoreAppCallArgs) { + promiseChain = promiseChain.then(() => client.changeValidatorCommissionAddress(args, {...params, sendParams: {...params?.sendParams, skipSending: true, atc}})) + resultMappers.push(undefined) + return this + }, + changeValidatorRewardInfo(args: MethodArgs<'changeValidatorRewardInfo(uint64,uint8,byte[32],uint64,uint64)void'>, params?: AppClientComposeCallCoreParams & CoreAppCallArgs) { + promiseChain = promiseChain.then(() => client.changeValidatorRewardInfo(args, {...params, sendParams: {...params?.sendParams, skipSending: true, atc}})) + resultMappers.push(undefined) + return this + }, + addPool(args: MethodArgs<'addPool(pay,uint64,uint64)(uint64,uint64,uint64)'>, params?: AppClientComposeCallCoreParams & CoreAppCallArgs) { + promiseChain = promiseChain.then(() => client.addPool(args, {...params, sendParams: {...params?.sendParams, skipSending: true, atc}})) + resultMappers.push(undefined) + return this + }, + addStake(args: MethodArgs<'addStake(pay,uint64,uint64)(uint64,uint64,uint64)'>, params?: AppClientComposeCallCoreParams & CoreAppCallArgs) { + promiseChain = promiseChain.then(() => client.addStake(args, {...params, sendParams: {...params?.sendParams, skipSending: true, atc}})) + resultMappers.push(undefined) + return this + }, + setTokenPayoutRatio(args: MethodArgs<'setTokenPayoutRatio(uint64)(uint64[24],uint64)'>, params?: AppClientComposeCallCoreParams & CoreAppCallArgs) { + promiseChain = promiseChain.then(() => client.setTokenPayoutRatio(args, {...params, sendParams: {...params?.sendParams, skipSending: true, atc}})) + resultMappers.push(undefined) + return this + }, + stakeUpdatedViaRewards(args: MethodArgs<'stakeUpdatedViaRewards((uint64,uint64,uint64),uint64,uint64)void'>, params?: AppClientComposeCallCoreParams & CoreAppCallArgs) { + promiseChain = promiseChain.then(() => client.stakeUpdatedViaRewards(args, {...params, sendParams: {...params?.sendParams, skipSending: true, atc}})) + resultMappers.push(undefined) + return this + }, + stakeRemoved(args: MethodArgs<'stakeRemoved((uint64,uint64,uint64),address,uint64,uint64,bool)void'>, params?: AppClientComposeCallCoreParams & CoreAppCallArgs) { + promiseChain = promiseChain.then(() => client.stakeRemoved(args, {...params, sendParams: {...params?.sendParams, skipSending: true, atc}})) + resultMappers.push(undefined) + return this + }, + findPoolForStaker(args: MethodArgs<'findPoolForStaker(uint64,address,uint64)((uint64,uint64,uint64),bool,bool)'>, params?: AppClientComposeCallCoreParams & CoreAppCallArgs) { + promiseChain = promiseChain.then(() => client.findPoolForStaker(args, {...params, sendParams: {...params?.sendParams, skipSending: true, atc}})) + resultMappers.push(undefined) + return this + }, + movePoolToNode(args: MethodArgs<'movePoolToNode(uint64,uint64,uint64)void'>, params?: AppClientComposeCallCoreParams & CoreAppCallArgs) { + promiseChain = promiseChain.then(() => client.movePoolToNode(args, {...params, sendParams: {...params?.sendParams, skipSending: true, atc}})) + resultMappers.push(undefined) + return this + }, + clearState(args?: BareCallArgs & AppClientComposeCallCoreParams & CoreAppCallArgs) { + promiseChain = promiseChain.then(() => client.clearState({...args, sendParams: {...args?.sendParams, skipSending: true, atc}})) + resultMappers.push(undefined) + return this + }, + addTransaction(txn: TransactionWithSigner | TransactionToSign | Transaction | Promise, defaultSender?: SendTransactionFrom) { + promiseChain = promiseChain.then(async () => atc.addTransaction(await algokit.getTransactionWithSigner(txn, defaultSender ?? client.sender))) + return this + }, + async atc() { + await promiseChain + return atc + }, + async simulate(options?: SimulateOptions) { + await promiseChain + const result = await atc.simulate(client.algod, new modelsv2.SimulateRequest({ txnGroups: [], ...options })) + return { + ...result, + returns: result.methodResults?.map((val, i) => resultMappers[i] !== undefined ? resultMappers[i]!(val.returnValue) : val.returnValue) + } + }, + async execute(sendParams?: AppClientComposeExecuteParams) { + await promiseChain + const result = await algokit.sendAtomicTransactionComposer({ atc, sendParams }, client.algod) + return { + ...result, + returns: result.returns?.map((val, i) => resultMappers[i] !== undefined ? resultMappers[i]!(val.returnValue) : val.returnValue) + } + } + } as unknown as ValidatorRegistryComposer + } +} +export type ValidatorRegistryComposer = { + /** + * Calls the gas()void ABI method. + * + * gas is a dummy no-op call that can be used to pool-up resource references and opcode cost + * + * @param args The arguments for the contract call + * @param params Any additional parameters for the call + * @returns The typed transaction composer so you can fluently chain multiple calls or call execute to execute all queued up transactions + */ + gas(args: MethodArgs<'gas()void'>, params?: AppClientComposeCallCoreParams & CoreAppCallArgs): ValidatorRegistryComposer<[...TReturns, MethodReturn<'gas()void'>]> + + /** + * Calls the getMbrAmounts()(uint64,uint64,uint64,uint64) ABI method. + * + * Returns the MBR amounts needed for various actions:[addValidatorMbr: uint64 - mbr needed to add a new validator - paid to validator contractaddPoolMbr: uint64 - mbr needed to add a new pool - paid to validatorpoolInitMbr: uint64 - mbr needed to initStorage() of pool - paid to pool itselfaddStakerMbr: uint64 - mbr staker needs to add to first staking payment (stays w/ validator)] + * + * @param args The arguments for the contract call + * @param params Any additional parameters for the call + * @returns The typed transaction composer so you can fluently chain multiple calls or call execute to execute all queued up transactions + */ + getMbrAmounts(args: MethodArgs<'getMbrAmounts()(uint64,uint64,uint64,uint64)'>, params?: AppClientComposeCallCoreParams & CoreAppCallArgs): ValidatorRegistryComposer<[...TReturns, MethodReturn<'getMbrAmounts()(uint64,uint64,uint64,uint64)'>]> + + /** + * Calls the getProtocolConstraints()(uint64,uint64,uint64,uint64,uint64,uint64,uint64,uint64,uint64,uint64,uint64) ABI method. + * + * Returns the protocol constraints so that UIs can limit what users specify for validator configuration parameters. + * + * @param args The arguments for the contract call + * @param params Any additional parameters for the call + * @returns The typed transaction composer so you can fluently chain multiple calls or call execute to execute all queued up transactions + */ + getProtocolConstraints(args: MethodArgs<'getProtocolConstraints()(uint64,uint64,uint64,uint64,uint64,uint64,uint64,uint64,uint64,uint64,uint64)'>, params?: AppClientComposeCallCoreParams & CoreAppCallArgs): ValidatorRegistryComposer<[...TReturns, MethodReturn<'getProtocolConstraints()(uint64,uint64,uint64,uint64,uint64,uint64,uint64,uint64,uint64,uint64,uint64)'>]> + + /** + * Calls the getNumValidators()uint64 ABI method. + * + * Returns the current number of validators + * + * @param args The arguments for the contract call + * @param params Any additional parameters for the call + * @returns The typed transaction composer so you can fluently chain multiple calls or call execute to execute all queued up transactions + */ + getNumValidators(args: MethodArgs<'getNumValidators()uint64'>, params?: AppClientComposeCallCoreParams & CoreAppCallArgs): ValidatorRegistryComposer<[...TReturns, MethodReturn<'getNumValidators()uint64'>]> + + /** + * Calls the getValidatorConfig(uint64)(uint64,address,address,uint64,uint8,byte[32],uint64,uint64,uint64,uint16,uint32,address,uint64,uint64,uint8,uint64,uint64) ABI method. + * + * @param args The arguments for the contract call + * @param params Any additional parameters for the call + * @returns The typed transaction composer so you can fluently chain multiple calls or call execute to execute all queued up transactions + */ + getValidatorConfig(args: MethodArgs<'getValidatorConfig(uint64)(uint64,address,address,uint64,uint8,byte[32],uint64,uint64,uint64,uint16,uint32,address,uint64,uint64,uint8,uint64,uint64)'>, params?: AppClientComposeCallCoreParams & CoreAppCallArgs): ValidatorRegistryComposer<[...TReturns, MethodReturn<'getValidatorConfig(uint64)(uint64,address,address,uint64,uint8,byte[32],uint64,uint64,uint64,uint16,uint32,address,uint64,uint64,uint8,uint64,uint64)'>]> + + /** + * Calls the getValidatorState(uint64)(uint16,uint64,uint64,uint64) ABI method. + * + * @param args The arguments for the contract call + * @param params Any additional parameters for the call + * @returns The typed transaction composer so you can fluently chain multiple calls or call execute to execute all queued up transactions + */ + getValidatorState(args: MethodArgs<'getValidatorState(uint64)(uint16,uint64,uint64,uint64)'>, params?: AppClientComposeCallCoreParams & CoreAppCallArgs): ValidatorRegistryComposer<[...TReturns, MethodReturn<'getValidatorState(uint64)(uint16,uint64,uint64,uint64)'>]> + + /** + * Calls the getValidatorOwnerAndManager(uint64)(address,address) ABI method. + * + * @param args The arguments for the contract call + * @param params Any additional parameters for the call + * @returns The typed transaction composer so you can fluently chain multiple calls or call execute to execute all queued up transactions + */ + getValidatorOwnerAndManager(args: MethodArgs<'getValidatorOwnerAndManager(uint64)(address,address)'>, params?: AppClientComposeCallCoreParams & CoreAppCallArgs): ValidatorRegistryComposer<[...TReturns, MethodReturn<'getValidatorOwnerAndManager(uint64)(address,address)'>]> + + /** + * Calls the getPools(uint64)(uint64,uint16,uint64)[] ABI method. + * + * Return list of all pools for this validator. + * + * @param args The arguments for the contract call + * @param params Any additional parameters for the call + * @returns The typed transaction composer so you can fluently chain multiple calls or call execute to execute all queued up transactions + */ + getPools(args: MethodArgs<'getPools(uint64)(uint64,uint16,uint64)[]'>, params?: AppClientComposeCallCoreParams & CoreAppCallArgs): ValidatorRegistryComposer<[...TReturns, MethodReturn<'getPools(uint64)(uint64,uint16,uint64)[]'>]> + + /** + * Calls the getPoolAppId(uint64,uint64)uint64 ABI method. + * + * @param args The arguments for the contract call + * @param params Any additional parameters for the call + * @returns The typed transaction composer so you can fluently chain multiple calls or call execute to execute all queued up transactions + */ + getPoolAppId(args: MethodArgs<'getPoolAppId(uint64,uint64)uint64'>, params?: AppClientComposeCallCoreParams & CoreAppCallArgs): ValidatorRegistryComposer<[...TReturns, MethodReturn<'getPoolAppId(uint64,uint64)uint64'>]> + + /** + * Calls the getPoolInfo((uint64,uint64,uint64))(uint64,uint16,uint64) ABI method. + * + * @param args The arguments for the contract call + * @param params Any additional parameters for the call + * @returns The typed transaction composer so you can fluently chain multiple calls or call execute to execute all queued up transactions + */ + getPoolInfo(args: MethodArgs<'getPoolInfo((uint64,uint64,uint64))(uint64,uint16,uint64)'>, params?: AppClientComposeCallCoreParams & CoreAppCallArgs): ValidatorRegistryComposer<[...TReturns, MethodReturn<'getPoolInfo((uint64,uint64,uint64))(uint64,uint16,uint64)'>]> + + /** + * Calls the getCurMaxStakePerPool(uint64)uint64 ABI method. + * + * Calculate the maximum stake per pool for a given validator.Normally this would be maxAlgoPerPool, but it should also never go above MaxAllowedStake / numPools soas pools are added the max allowed per pool can reduce. + * + * @param args The arguments for the contract call + * @param params Any additional parameters for the call + * @returns The typed transaction composer so you can fluently chain multiple calls or call execute to execute all queued up transactions + */ + getCurMaxStakePerPool(args: MethodArgs<'getCurMaxStakePerPool(uint64)uint64'>, params?: AppClientComposeCallCoreParams & CoreAppCallArgs): ValidatorRegistryComposer<[...TReturns, MethodReturn<'getCurMaxStakePerPool(uint64)uint64'>]> + + /** + * Calls the doesStakerNeedToPayMBR(address)bool ABI method. + * + * Helper callers can call w/ simulate to determine if 'AddStaker' MBR should be included w/ staking amount + * + * @param args The arguments for the contract call + * @param params Any additional parameters for the call + * @returns The typed transaction composer so you can fluently chain multiple calls or call execute to execute all queued up transactions + */ + doesStakerNeedToPayMbr(args: MethodArgs<'doesStakerNeedToPayMBR(address)bool'>, params?: AppClientComposeCallCoreParams & CoreAppCallArgs): ValidatorRegistryComposer<[...TReturns, MethodReturn<'doesStakerNeedToPayMBR(address)bool'>]> + + /** + * Calls the getStakedPoolsForAccount(address)(uint64,uint64,uint64)[] ABI method. + * + * Retrieves the staked pools for an account. + * + * @param args The arguments for the contract call + * @param params Any additional parameters for the call + * @returns The typed transaction composer so you can fluently chain multiple calls or call execute to execute all queued up transactions + */ + getStakedPoolsForAccount(args: MethodArgs<'getStakedPoolsForAccount(address)(uint64,uint64,uint64)[]'>, params?: AppClientComposeCallCoreParams & CoreAppCallArgs): ValidatorRegistryComposer<[...TReturns, MethodReturn<'getStakedPoolsForAccount(address)(uint64,uint64,uint64)[]'>]> + + /** + * Calls the getTokenPayoutRatio(uint64)(uint64[24],uint64) ABI method. + * + * Retrieves the token payout ratio for a given validator - returning the pool ratios of whole so that tokenpayouts across pools can be based on a stable snaphost of stake. + * + * @param args The arguments for the contract call + * @param params Any additional parameters for the call + * @returns The typed transaction composer so you can fluently chain multiple calls or call execute to execute all queued up transactions + */ + getTokenPayoutRatio(args: MethodArgs<'getTokenPayoutRatio(uint64)(uint64[24],uint64)'>, params?: AppClientComposeCallCoreParams & CoreAppCallArgs): ValidatorRegistryComposer<[...TReturns, MethodReturn<'getTokenPayoutRatio(uint64)(uint64[24],uint64)'>]> + + /** + * Calls the getNodePoolAssignments(uint64)((uint64[3])[8]) ABI method. + * + * @param args The arguments for the contract call + * @param params Any additional parameters for the call + * @returns The typed transaction composer so you can fluently chain multiple calls or call execute to execute all queued up transactions + */ + getNodePoolAssignments(args: MethodArgs<'getNodePoolAssignments(uint64)((uint64[3])[8])'>, params?: AppClientComposeCallCoreParams & CoreAppCallArgs): ValidatorRegistryComposer<[...TReturns, MethodReturn<'getNodePoolAssignments(uint64)((uint64[3])[8])'>]> + + /** + * Calls the getNFDRegistryID()uint64 ABI method. + * + * @param args The arguments for the contract call + * @param params Any additional parameters for the call + * @returns The typed transaction composer so you can fluently chain multiple calls or call execute to execute all queued up transactions + */ + getNfdRegistryId(args: MethodArgs<'getNFDRegistryID()uint64'>, params?: AppClientComposeCallCoreParams & CoreAppCallArgs): ValidatorRegistryComposer<[...TReturns, MethodReturn<'getNFDRegistryID()uint64'>]> + + /** + * Calls the addValidator(pay,string,(uint64,address,address,uint64,uint8,byte[32],uint64,uint64,uint64,uint16,uint32,address,uint64,uint64,uint8,uint64,uint64))uint64 ABI method. + * + * Adds a new validator + * + * @param args The arguments for the contract call + * @param params Any additional parameters for the call + * @returns The typed transaction composer so you can fluently chain multiple calls or call execute to execute all queued up transactions + */ + addValidator(args: MethodArgs<'addValidator(pay,string,(uint64,address,address,uint64,uint8,byte[32],uint64,uint64,uint64,uint16,uint32,address,uint64,uint64,uint8,uint64,uint64))uint64'>, params?: AppClientComposeCallCoreParams & CoreAppCallArgs): ValidatorRegistryComposer<[...TReturns, MethodReturn<'addValidator(pay,string,(uint64,address,address,uint64,uint8,byte[32],uint64,uint64,uint64,uint16,uint32,address,uint64,uint64,uint8,uint64,uint64))uint64'>]> + + /** + * Calls the changeValidatorManager(uint64,address)void ABI method. + * + * Changes the Validator manager for a specific Validator id.[ ONLY OWNER CAN CHANGE ] + * + * @param args The arguments for the contract call + * @param params Any additional parameters for the call + * @returns The typed transaction composer so you can fluently chain multiple calls or call execute to execute all queued up transactions + */ + changeValidatorManager(args: MethodArgs<'changeValidatorManager(uint64,address)void'>, params?: AppClientComposeCallCoreParams & CoreAppCallArgs): ValidatorRegistryComposer<[...TReturns, MethodReturn<'changeValidatorManager(uint64,address)void'>]> + + /** + * Calls the changeValidatorSunsetInfo(uint64,uint64,uint64)void ABI method. + * + * Updates the sunset information for a given validator.[ ONLY OWNER CAN CHANGE ] + * + * @param args The arguments for the contract call + * @param params Any additional parameters for the call + * @returns The typed transaction composer so you can fluently chain multiple calls or call execute to execute all queued up transactions + */ + changeValidatorSunsetInfo(args: MethodArgs<'changeValidatorSunsetInfo(uint64,uint64,uint64)void'>, params?: AppClientComposeCallCoreParams & CoreAppCallArgs): ValidatorRegistryComposer<[...TReturns, MethodReturn<'changeValidatorSunsetInfo(uint64,uint64,uint64)void'>]> + + /** + * Calls the changeValidatorNFD(uint64,uint64,string)void ABI method. + * + * Changes the NFD for a validator in the validatorList contract.[ ONLY OWNER OR MANAGER CAN CHANGE ] + * + * @param args The arguments for the contract call + * @param params Any additional parameters for the call + * @returns The typed transaction composer so you can fluently chain multiple calls or call execute to execute all queued up transactions + */ + changeValidatorNfd(args: MethodArgs<'changeValidatorNFD(uint64,uint64,string)void'>, params?: AppClientComposeCallCoreParams & CoreAppCallArgs): ValidatorRegistryComposer<[...TReturns, MethodReturn<'changeValidatorNFD(uint64,uint64,string)void'>]> + + /** + * Calls the changeValidatorCommissionAddress(uint64,address)void ABI method. + * + * Change the commission address that validator rewards are sent to.[ ONLY OWNER CAN CHANGE ] + * + * @param args The arguments for the contract call + * @param params Any additional parameters for the call + * @returns The typed transaction composer so you can fluently chain multiple calls or call execute to execute all queued up transactions + */ + changeValidatorCommissionAddress(args: MethodArgs<'changeValidatorCommissionAddress(uint64,address)void'>, params?: AppClientComposeCallCoreParams & CoreAppCallArgs): ValidatorRegistryComposer<[...TReturns, MethodReturn<'changeValidatorCommissionAddress(uint64,address)void'>]> + + /** + * Calls the changeValidatorRewardInfo(uint64,uint8,byte[32],uint64,uint64)void ABI method. + * + * Allow the additional rewards (gating entry, additional token rewards) information be changed at will.[ ONLY OWNER CAN CHANGE ] + * + * @param args The arguments for the contract call + * @param params Any additional parameters for the call + * @returns The typed transaction composer so you can fluently chain multiple calls or call execute to execute all queued up transactions + */ + changeValidatorRewardInfo(args: MethodArgs<'changeValidatorRewardInfo(uint64,uint8,byte[32],uint64,uint64)void'>, params?: AppClientComposeCallCoreParams & CoreAppCallArgs): ValidatorRegistryComposer<[...TReturns, MethodReturn<'changeValidatorRewardInfo(uint64,uint8,byte[32],uint64,uint64)void'>]> + + /** + * Calls the addPool(pay,uint64,uint64)(uint64,uint64,uint64) ABI method. + * + * Adds a new pool to a validator's pool set, returning the 'key' to reference the pool in the future for staking, etc.The caller must pay the cost of the validators MBR increase as well as the MBR that will be needed for the pool itself.[ ONLY OWNER OR MANAGER CAN call ] + * + * @param args The arguments for the contract call + * @param params Any additional parameters for the call + * @returns The typed transaction composer so you can fluently chain multiple calls or call execute to execute all queued up transactions + */ + addPool(args: MethodArgs<'addPool(pay,uint64,uint64)(uint64,uint64,uint64)'>, params?: AppClientComposeCallCoreParams & CoreAppCallArgs): ValidatorRegistryComposer<[...TReturns, MethodReturn<'addPool(pay,uint64,uint64)(uint64,uint64,uint64)'>]> + + /** + * Calls the addStake(pay,uint64,uint64)(uint64,uint64,uint64) ABI method. + * + * Adds stake to a validator pool. + * + * @param args The arguments for the contract call + * @param params Any additional parameters for the call + * @returns The typed transaction composer so you can fluently chain multiple calls or call execute to execute all queued up transactions + */ + addStake(args: MethodArgs<'addStake(pay,uint64,uint64)(uint64,uint64,uint64)'>, params?: AppClientComposeCallCoreParams & CoreAppCallArgs): ValidatorRegistryComposer<[...TReturns, MethodReturn<'addStake(pay,uint64,uint64)(uint64,uint64,uint64)'>]> + + /** + * Calls the setTokenPayoutRatio(uint64)(uint64[24],uint64) ABI method. + * + * setTokenPayoutRatio is called by Staking Pool # 1 (ONLY) to ask the validator (us) to calculate the ratiosof stake in the pools for subsequent token payouts (ie: 2 pools, '100' algo total staked, 60 in pool 1, and 40in pool 2. This is done so we have a stable snapshot of stake - taken once per epoch - only triggered bypool 1 doing payout. pools other than 1 doing payout call pool 1 to ask it do it first.It would be 60/40% in the poolPctOfWhole values. The token reward payouts then use these values instead oftheir 'current' stake which changes as part of the payouts themselves (and people could be changing stakeduring the epoch updates across pools)Multiple pools will call us via pool 1 (pool2->pool1->valdiator, etc.) so don't assert on pool1 calling multipletimes in same epoch. Just return. + * + * @param args The arguments for the contract call + * @param params Any additional parameters for the call + * @returns The typed transaction composer so you can fluently chain multiple calls or call execute to execute all queued up transactions + */ + setTokenPayoutRatio(args: MethodArgs<'setTokenPayoutRatio(uint64)(uint64[24],uint64)'>, params?: AppClientComposeCallCoreParams & CoreAppCallArgs): ValidatorRegistryComposer<[...TReturns, MethodReturn<'setTokenPayoutRatio(uint64)(uint64[24],uint64)'>]> + + /** + * Calls the stakeUpdatedViaRewards((uint64,uint64,uint64),uint64,uint64)void ABI method. + * + * stakeUpdatedViaRewards is called by Staking pools to inform the validator (us) that a particular amount of totalstake has been added to the specified pool. This is used to update the stats we have in our PoolInfo storage.The calling App id is validated against our pool list as well. + * + * @param args The arguments for the contract call + * @param params Any additional parameters for the call + * @returns The typed transaction composer so you can fluently chain multiple calls or call execute to execute all queued up transactions + */ + stakeUpdatedViaRewards(args: MethodArgs<'stakeUpdatedViaRewards((uint64,uint64,uint64),uint64,uint64)void'>, params?: AppClientComposeCallCoreParams & CoreAppCallArgs): ValidatorRegistryComposer<[...TReturns, MethodReturn<'stakeUpdatedViaRewards((uint64,uint64,uint64),uint64,uint64)void'>]> + + /** + * Calls the stakeRemoved((uint64,uint64,uint64),address,uint64,uint64,bool)void ABI method. + * + * stakeRemoved is called by Staking pools to inform the validator (us) that a particular amount of total stake has been removedfrom the specified pool. This is used to update the stats we have in our PoolInfo storage.If any amount of rewardRemoved is specified, then that amount of reward is sent to the useThe calling App id is validated against our pool list as well. + * + * @param args The arguments for the contract call + * @param params Any additional parameters for the call + * @returns The typed transaction composer so you can fluently chain multiple calls or call execute to execute all queued up transactions + */ + stakeRemoved(args: MethodArgs<'stakeRemoved((uint64,uint64,uint64),address,uint64,uint64,bool)void'>, params?: AppClientComposeCallCoreParams & CoreAppCallArgs): ValidatorRegistryComposer<[...TReturns, MethodReturn<'stakeRemoved((uint64,uint64,uint64),address,uint64,uint64,bool)void'>]> + + /** + * Calls the findPoolForStaker(uint64,address,uint64)((uint64,uint64,uint64),bool,bool) ABI method. + * + * Finds the pool for a staker based on the provided validator id, staker address, and amount to stake.First checks the stakers 'already staked list' for the validator preferring those (adding if possible) then addsto new pool if necessary. + * + * @param args The arguments for the contract call + * @param params Any additional parameters for the call + * @returns The typed transaction composer so you can fluently chain multiple calls or call execute to execute all queued up transactions + */ + findPoolForStaker(args: MethodArgs<'findPoolForStaker(uint64,address,uint64)((uint64,uint64,uint64),bool,bool)'>, params?: AppClientComposeCallCoreParams & CoreAppCallArgs): ValidatorRegistryComposer<[...TReturns, MethodReturn<'findPoolForStaker(uint64,address,uint64)((uint64,uint64,uint64),bool,bool)'>]> + + /** + * Calls the movePoolToNode(uint64,uint64,uint64)void ABI method. + * + * Find the specified pool (in any node number) and move it to the specified node.The pool account is forced offline if moved so prior node will still run for 320 rounds butnew key goes online on new node soon after (320 rounds after it goes online)No-op if success, asserts if not found or can't move (no space in target)[ ONLY OWNER OR MANAGER CAN CHANGE ]Only callable by owner or manager + * + * @param args The arguments for the contract call + * @param params Any additional parameters for the call + * @returns The typed transaction composer so you can fluently chain multiple calls or call execute to execute all queued up transactions + */ + movePoolToNode(args: MethodArgs<'movePoolToNode(uint64,uint64,uint64)void'>, params?: AppClientComposeCallCoreParams & CoreAppCallArgs): ValidatorRegistryComposer<[...TReturns, MethodReturn<'movePoolToNode(uint64,uint64,uint64)void'>]> + + /** + * Makes a clear_state call to an existing instance of the ValidatorRegistry smart contract. + * + * @param args The arguments for the bare call + * @returns The typed transaction composer so you can fluently chain multiple calls or call execute to execute all queued up transactions + */ + clearState(args?: BareCallArgs & AppClientComposeCallCoreParams & CoreAppCallArgs): ValidatorRegistryComposer<[...TReturns, undefined]> + + /** + * Adds a transaction to the composer + * + * @param txn One of: A TransactionWithSigner object (returned as is), a TransactionToSign object (signer is obtained from the signer property), a Transaction object (signer is extracted from the defaultSender parameter), an async SendTransactionResult returned by one of algokit utils helpers (signer is obtained from the defaultSender parameter) + * @param defaultSender The default sender to be used to obtain a signer where the object provided to the transaction parameter does not include a signer. + */ + addTransaction(txn: TransactionWithSigner | TransactionToSign | Transaction | Promise, defaultSender?: SendTransactionFrom): ValidatorRegistryComposer + /** + * Returns the underlying AtomicTransactionComposer instance + */ + atc(): Promise + /** + * Simulates the transaction group and returns the result + */ + simulate(options?: SimulateOptions): Promise> + /** + * Executes the transaction group and returns the results + */ + execute(sendParams?: AppClientComposeExecuteParams): Promise> +} +export type SimulateOptions = Omit[0], 'txnGroups'> +export type ValidatorRegistryComposerSimulateResult = { + returns: TReturns + methodResults: ABIResult[] + simulateResponse: modelsv2.SimulateResponse +} +export type ValidatorRegistryComposerResults = { + returns: TReturns + groupId: string + txIds: string[] + transactions: Transaction[] +} diff --git a/contracts/contracts/constants.algo.ts b/contracts/contracts/constants.algo.ts new file mode 100644 index 00000000..3f9ebcdc --- /dev/null +++ b/contracts/contracts/constants.algo.ts @@ -0,0 +1,23 @@ +export const MAX_STAKERS_PER_POOL = 200; // *64 (size of StakeInfo) = 12,800 bytes +export const MIN_ALGO_STAKE_PER_POOL = 1_000_000; // 1 ALGO + +export const MAX_VALIDATOR_SOFT_PCT_OF_ONLINE_1DECIMAL = 100; // this is 10.0%, not 100... and represents the SOFT cap where validator is considered saturated +export const MAX_VALIDATOR_HARD_PCT_OF_ONLINE_1DECIMAL = 150; // 15% is HARD cap - no new stake if this reached + +export const MIN_PCT_TO_VALIDATOR = 0; // minimum percentage is 0 - let the market decide +export const MAX_PCT_TO_VALIDATOR = 1000000; // 100% w/ four decimals (would be someone's own node for eg) + +export const ALGORAND_ACCOUNT_MIN_BALANCE = 100000; +// values taken from: https://developer.algorand.org/docs/features/asc1/stateful/#minimum-balance-requirement-for-a-smart-contract +export const APPLICATION_BASE_FEE = 100000; // base fee for creating or opt-in to application +export const ASSET_HOLDING_FEE = 100000; // creation/holding fee for asset +export const SSC_VALUE_UINT = 28500; // cost for value as uint64 +export const SSC_VALUE_BYTES = 50000; // cost for value as bytes + +export const GATING_TYPE_NONE = 0; +export const GATING_TYPE_ASSETS_CREATED_BY = 1; +export const GATING_TYPE_ASSET_ID = 2; +export const GATING_TYPE_CREATED_BY_NFD_ADDRESSES = 3; +export const GATING_TYPE_SEGMENT_OF_NFD = 4; +// This constant needs to always be set to the highest value of the constants +export const GATING_TYPE_CONST_MAX = 4; diff --git a/contracts/contracts/stakingPool.algo.ts b/contracts/contracts/stakingPool.algo.ts new file mode 100644 index 00000000..898a03f8 --- /dev/null +++ b/contracts/contracts/stakingPool.algo.ts @@ -0,0 +1,943 @@ +import { Contract } from '@algorandfoundation/tealscript'; +// eslint-disable-next-line import/no-cycle +import { PoolTokenPayoutRatio, ValidatorPoolKey, ValidatorRegistry } from './validatorRegistry.algo'; +import { + ALGORAND_ACCOUNT_MIN_BALANCE, + APPLICATION_BASE_FEE, + ASSET_HOLDING_FEE, + MAX_STAKERS_PER_POOL, + MAX_VALIDATOR_SOFT_PCT_OF_ONLINE_1DECIMAL, + MIN_ALGO_STAKE_PER_POOL, + SSC_VALUE_BYTES, + SSC_VALUE_UINT, +} from './constants.algo'; + +const ALGORAND_STAKING_BLOCK_DELAY = 320; // # of blocks until algorand sees online balance changes in staking +const AVG_BLOCK_TIME_SECS = 28; // in tenths - 28 = 2.8 + +export type StakedInfo = { + account: Address; + balance: uint64; + totalRewarded: uint64; + rewardTokenBalance: uint64; + entryTime: uint64; +}; + +// eslint-disable-next-line no-unused-vars +/** + * StakingPool contract has a new instance deployed per staking pool added by any validator. A single instance + * is initially immutably deployed, and the id of that instance is used as a construction parameter in the immutable + * instance of the master ValidatoryRegistry contract. It then uses that StakingPool instance as a 'factory template' + * for subsequent pool creations - using the on-chain bytecode of that deployed instance to create a new identical + * instance. + * + * Each instance is explicitly 'linked' to the validator master via its creation parameters. The validator master + * contract only allows calls from staking pool contract instances that match data that only the validator master + * authoritatively has (validator id X, pool Y - has to come from contract address of that pool). Calls the pools + * validate coming from the validator are only allowed if it matches the validator id it was created with. + */ +export class StakingPool extends Contract { + programVersion = 10; + + // When created, we track our creating validator contract so that only this contract can call us. Independent + // copies of this contract could be created but only the 'official' validator contract would be considered valid + // and official. Calls from these pools back to the validator contract are also validated, ensuring the pool + // calling the validator is one of the pools it created. + creatingValidatorContractAppId = GlobalStateKey({ key: 'creatorApp' }); + + // The 'id' of the validator our pool belongs to + validatorId = GlobalStateKey({ key: 'validatorId' }); + + // The pool id we were assigned by the validator contract - sequential id per validator + poolId = GlobalStateKey({ key: 'poolId' }); + + // number of stakers in THIS pool + numStakers = GlobalStateKey({ key: 'numStakers' }); + + // totalAlgoStaked is total amount staked in THIS pool. + totalAlgoStaked = GlobalStateKey({ key: 'staked' }); + + minEntryStake = GlobalStateKey({ key: 'minEntryStake' }); + + // Last timestamp of a payout - used to ensure payout call isn't cheated and called prior to agreed upon schedule + lastPayout = GlobalStateKey({ key: 'lastPayout' }); + + // Epoch number this staking pool is on, with epoch 1 being the 'first' payout + epochNumber = GlobalStateKey({ key: 'epochNumber' }); + + // Version of algod this pool is connected to - should be updated regularly + algodVer = GlobalStateKey({ key: 'algodVer' }); + + // Our 'ledger' of stakers, tracking each staker account and its balance, total rewards, and last entry time + stakers = BoxKey>({ key: 'stakers' }); + + nfdRegistryAppId = TemplateVar(); + + feeSinkAddr = TemplateVar
(); + + /** + * Initialize the staking pool w/ owner and manager, but can only be created by the validator contract. + * @param {uint64} creatingContractId - id of contract that constructed us - the validator application (single global instance) + * @param {uint64} validatorId - id of validator we're a staking pool of + * @param {uint64} poolId - which pool id are we + * @param {uint64} minEntryStake - minimum amount to be in pool, but also minimum amount balance can't go below (without removing all!) + */ + createApplication(creatingContractId: uint64, validatorId: uint64, poolId: uint64, minEntryStake: uint64): void { + if (creatingContractId === 0) { + // this is likely initial template setup - everything should basically be zero... + assert(validatorId === 0); + assert(poolId === 0); + } else { + assert(validatorId !== 0); + assert(poolId !== 0); + } + assert(minEntryStake >= MIN_ALGO_STAKE_PER_POOL); + this.creatingValidatorContractAppId.value = creatingContractId; + this.validatorId.value = validatorId; + this.poolId.value = poolId; + this.numStakers.value = 0; + this.totalAlgoStaked.value = 0; + this.minEntryStake.value = minEntryStake; + this.lastPayout.value = globals.latestTimestamp; // set 'last payout' to init time of pool to establish baseline + this.epochNumber.value = 0; + } + + /** + * gas is a dummy no-op call that can be used to pool-up resource references and opcode cost + */ + gas(): void {} + + private minBalanceForAccount( + contracts: uint64, + extraPages: uint64, + assets: uint64, + localInts: uint64, + localBytes: uint64, + globalInts: uint64, + globalBytes: uint64 + ): uint64 { + let minBal = ALGORAND_ACCOUNT_MIN_BALANCE; + minBal += contracts * APPLICATION_BASE_FEE; + minBal += extraPages * APPLICATION_BASE_FEE; + minBal += assets * ASSET_HOLDING_FEE; + minBal += localInts * SSC_VALUE_UINT; + minBal += globalInts * SSC_VALUE_UINT; + minBal += localBytes * SSC_VALUE_BYTES; + minBal += globalBytes * SSC_VALUE_BYTES; + return minBal; + } + + private costForBoxStorage(totalNumBytes: uint64): uint64 { + const SCBOX_PERBOX = 2500; + const SCBOX_PERBYTE = 400; + + return SCBOX_PERBOX + totalNumBytes * SCBOX_PERBYTE; + } + + /** + * Called after we're created and then funded so we can create our large stakers ledger storage + * Caller has to get MBR amounts from ValidatorRegistry to know how much to fund us to cover the box storage cost + * If this is pool 1 AND the validator has specified a reward token, opt-in to that token + * so that the validator can seed the pool with future rewards of that token. + * @param mbrPayment payment from caller which covers mbr increase of new staking pools' storage + */ + initStorage(mbrPayment: PayTxn): void { + assert(!this.stakers.exists, 'staking pool already initialized'); + + // Get the config of our validator to determine if we issue reward tokens + const validatorConfig = sendMethodCall({ + applicationID: AppID.fromUint64(this.creatingValidatorContractAppId.value), + methodArgs: [this.validatorId.value], + }); + const isTokenEligible = validatorConfig.rewardTokenId !== 0; + const extraMBR = isTokenEligible && this.poolId.value === 1 ? ASSET_HOLDING_FEE : 0; + const PoolInitMbr = + ALGORAND_ACCOUNT_MIN_BALANCE + + extraMBR + + this.costForBoxStorage(7 /* 'stakers' name */ + len() * MAX_STAKERS_PER_POOL); + + // the pay transaction must exactly match our MBR requirement. + verifyPayTxn(mbrPayment, { amount: PoolInitMbr }); + this.stakers.create(); + + if (isTokenEligible && this.poolId.value === 1) { + // opt ourselves in to the reward token if we're pool 1 + sendAssetTransfer({ + xferAsset: AssetID.fromUint64(validatorConfig.rewardTokenId), + assetReceiver: this.app.address, + assetAmount: 0, + }); + } + } + + /** + * Adds stake to the given account. + * Can ONLY be called by the validator contract that created us + * Must receive payment from the validator contract for amount being staked. + * + * @param {PayTxn} stakedAmountPayment prior payment coming from validator contract to us on behalf of staker. + * @param {Address} staker - The account adding new stake + * @throws {Error} - Throws an error if the staking pool is full. + * @returns {uint64} new 'entry time' in seconds of stake add. + */ + addStake(stakedAmountPayment: PayTxn, staker: Address): uint64 { + assert(this.stakers.exists); + + // The contract account calling us has to be our creating validator contract + assert(this.txn.sender === AppID.fromUint64(this.creatingValidatorContractAppId.value).address); + assert(staker !== globals.zeroAddress); + + // Verify the payment of stake also came from the validator - as it receives the stake from the staker, holds + // any MBR (if needed) and then sends the stake on to us in the stakedAmountPayment transaction. + verifyPayTxn(stakedAmountPayment, { + sender: AppID.fromUint64(this.creatingValidatorContractAppId.value).address, + receiver: this.app.address, + amount: stakedAmountPayment.amount, + }); + // Stake 'maximums' are handled at the validator level - pre-add - so no checks needed here. + + // See if the account staking is already in our ledger of stakers - if so, they're just adding to their stake + // track first empty slot as we go along as well. + const entryTime = this.getEntryTime(); + let firstEmpty = 0; + + // firstEmpty should represent 1-based index to first empty slot we find - 0 means none were found + for (let i = 0; i < this.stakers.value.length; i += 1) { + if (globals.opcodeBudget < 300) { + increaseOpcodeBudget(); + } + const cmpStaker = clone(this.stakers.value[i]); + if (cmpStaker.account === staker) { + cmpStaker.balance += stakedAmountPayment.amount; + cmpStaker.entryTime = entryTime; + + // Update the box w/ the new data + this.stakers.value[i] = cmpStaker; + + this.totalAlgoStaked.value += stakedAmountPayment.amount; + return entryTime; + } + if (cmpStaker.account === globals.zeroAddress) { + firstEmpty = i + 1; + break; + } + } + + if (firstEmpty === 0) { + // nothing was found - pool is full and this staker can't fit + throw Error('Staking pool full'); + } + // This is a new staker to the pool, so first ensure they're adding required minimum, then + // initialize slot and add to the stakers. + // our caller will see stakers increase in state and increase in their state as well. + assert(stakedAmountPayment.amount >= this.minEntryStake.value, 'must stake at least the minimum for this pool'); + + assert(this.stakers.value[firstEmpty - 1].account === globals.zeroAddress); + this.stakers.value[firstEmpty - 1] = { + account: staker, + balance: stakedAmountPayment.amount, + totalRewarded: 0, + rewardTokenBalance: 0, + entryTime: entryTime, + }; + this.numStakers.value += 1; + this.totalAlgoStaked.value += stakedAmountPayment.amount; + return entryTime; + } + + /** + * Removes stake on behalf of caller (removing own stake). If any token rewards exist, those are always sent in + * full. Also notifies the validator contract for this pools validator of the staker / balance changes. + * + * @param {uint64} amountToUnstake - The amount of stake to be removed. Specify 0 to remove all stake. + * @throws {Error} If the account has insufficient balance or if the account is not found. + */ + removeStake(amountToUnstake: uint64): void { + // We want to preserve the sanctity that the ONLY account that can call us is the staking account + // It makes it a bit awkward this way to update the state in the validator, but it's safer + // account calling us has to be account removing stake + const staker = this.txn.sender; + + for (let i = 0; i < this.stakers.value.length; i += 1) { + if (globals.opcodeBudget < 300) { + increaseOpcodeBudget(); + } + const cmpStaker = clone(this.stakers.value[i]); + if (cmpStaker.account === staker) { + if (amountToUnstake === 0) { + // specifying 0 for unstake amount is requesting to UNSTAKE ALL + amountToUnstake = cmpStaker.balance; + } + if (cmpStaker.balance < amountToUnstake) { + throw Error('Insufficient balance'); + } + cmpStaker.balance -= amountToUnstake; + this.totalAlgoStaked.value -= amountToUnstake; + + let amountRewardTokenRemoved = 0; + if (cmpStaker.rewardTokenBalance > 0) { + // If and only if this is pool 1 (where the reward token is held - then we can pay it out) + if (this.poolId.value === 1) { + const validatorConfig = sendMethodCall({ + applicationID: AppID.fromUint64(this.creatingValidatorContractAppId.value), + methodArgs: [this.validatorId.value], + }); + + // --------- + // SEND THE REWARD TOKEN NOW - it's in our pool + // --------- + sendAssetTransfer({ + xferAsset: AssetID.fromUint64(validatorConfig.rewardTokenId), + assetReceiver: staker, + assetAmount: cmpStaker.rewardTokenBalance, + }); + amountRewardTokenRemoved = cmpStaker.rewardTokenBalance; + cmpStaker.rewardTokenBalance = 0; + } else { + // If we're in different pool, then we set amountRewardTokenRemoved to amount of reward token to remove + // but the stakeRemoved call to the validator will see that a pool other than 1 called it, and + // then issues call to pool 1 to do the token payout via 'payTokenReward' method in our contract + amountRewardTokenRemoved = cmpStaker.rewardTokenBalance; + cmpStaker.rewardTokenBalance = 0; + } + } + + // don't let them reduce their balance below the minEntryStake UNLESS they're removing it all! + assert( + cmpStaker.balance === 0 || cmpStaker.balance >= this.minEntryStake.value, + 'cannot reduce balance below minimum allowed stake unless all is removed' + ); + + // --------- + // Pay the staker back + // --------- + sendPayment({ + amount: amountToUnstake, + receiver: staker, + note: 'unstaked', + }); + let stakerRemoved = false; + if (cmpStaker.balance === 0) { + // staker has been 'removed' - zero out record + this.numStakers.value -= 1; + cmpStaker.account = globals.zeroAddress; + cmpStaker.totalRewarded = 0; + cmpStaker.rewardTokenBalance = 0; + stakerRemoved = true; + } + // Update the box w/ the new staker data + this.stakers.value[i] = cmpStaker; + + // Call the validator contract and tell it we're removing stake + // It'll verify we're a valid staking pool id and update it + // stakeRemoved(poolKey: ValidatorPoolKey, staker: Address, amountRemoved: uint64, rewardRemoved: uint64, stakerRemoved: boolean): void + sendMethodCall({ + applicationID: AppID.fromUint64(this.creatingValidatorContractAppId.value), + methodArgs: [ + { id: this.validatorId.value, poolId: this.poolId.value, poolAppId: this.app.id }, + staker, + amountToUnstake, + amountRewardTokenRemoved, + stakerRemoved, + ], + }); + return; + } + } + throw Error('account not found'); + } + + /** + * Claims all the available reward tokens a staker has available, sending their entire balance to the staker from + * pool 1 (either directly, or via validator->pool1 to pay it out) + * Also notifies the validator contract for this pools validator of the staker / balance changes. + */ + claimTokens(): void { + // We want to preserve the sanctity that the ONLY account that can call us is the staking account + // It makes it a bit awkward this way to update the state in the validator, but it's safer + // account calling us has to be account removing stake + const staker = this.txn.sender; + + for (let i = 0; i < this.stakers.value.length; i += 1) { + if (globals.opcodeBudget < 300) { + increaseOpcodeBudget(); + } + const cmpStaker = clone(this.stakers.value[i]); + if (cmpStaker.account === staker) { + if (cmpStaker.rewardTokenBalance === 0) { + return; + } + let amountRewardTokenRemoved = 0; + // If and only if this is pool 1 (where the reward token is held - then we can pay it out) + if (this.poolId.value === 1) { + const validatorConfig = sendMethodCall({ + applicationID: AppID.fromUint64(this.creatingValidatorContractAppId.value), + methodArgs: [this.validatorId.value], + }); + // --------- + // SEND THE REWARD TOKEN NOW - it's in our pool + // --------- + sendAssetTransfer({ + xferAsset: AssetID.fromUint64(validatorConfig.rewardTokenId), + assetReceiver: staker, + assetAmount: cmpStaker.rewardTokenBalance, + }); + amountRewardTokenRemoved = cmpStaker.rewardTokenBalance; + cmpStaker.rewardTokenBalance = 0; + } else { + // If we're in different pool, then we set amountRewardTokenRemoved to amount of reward token to remove + // but the stakeRemoved call to the validator will see that a pool other than 1 called it, and + // then issues call to pool 1 to do the token payout via 'payTokenReward' method in our contract + amountRewardTokenRemoved = cmpStaker.rewardTokenBalance; + cmpStaker.rewardTokenBalance = 0; + } + + // Update the box w/ the new staker balance data (rewardTokenBalance being zeroed) + this.stakers.value[i] = cmpStaker; + + // Call the validator contract and tell it we're removing stake + // It'll verify we're a valid staking pool id and update it + // stakeRemoved(poolKey: ValidatorPoolKey, staker: Address, amountRemoved: uint64, rewardRemoved: uint64, stakerRemoved: boolean): void + sendMethodCall({ + applicationID: AppID.fromUint64(this.creatingValidatorContractAppId.value), + methodArgs: [ + { id: this.validatorId.value, poolId: this.poolId.value, poolAppId: this.app.id }, + staker, + 0, // no algo removed + amountRewardTokenRemoved, + false, // staker isn't being removed. + ], + }); + return; + } + } + throw Error('account not found'); + } + + /** + * Retrieves the staked information for a given staker. + * + * @param {Address} staker - The address of the staker. + * @returns {StakedInfo} - The staked information for the given staker. + * @throws {Error} - If the staker's account is not found. + */ + // @abi.readonly + getStakerInfo(staker: Address): StakedInfo { + for (let i = 0; i < this.stakers.value.length; i += 1) { + if (globals.opcodeBudget < 200) { + increaseOpcodeBudget(); + } + if (this.stakers.value[i].account === staker) { + return this.stakers.value[i]; + } + } + throw Error('account not found'); + } + + /** + * [Internal protocol method] Remove a specified amount of 'community token' rewards for a staker. + * This can ONLY be called by our validator and only if we're pool 1 - with the token. + * @param staker - the staker account to send rewards to + * @param rewardToken - id of reward token (to avoid re-entrancy in calling validator back to get id) + * @param amountToSend - amount to send the staker (there is significant trust here(!) - also why only validator can call us + */ + payTokenReward(staker: Address, rewardToken: uint64, amountToSend: uint64): void { + // account calling us has to be our creating validator contract + assert(this.txn.sender === AppID.fromUint64(this.creatingValidatorContractAppId.value).address); + assert(this.poolId.value === 1, 'must be pool 1 in order to be called to pay out token rewards'); + assert(rewardToken !== 0, 'can only claim token rewards from validator that has them'); + + // Send the reward tokens to the staker + sendAssetTransfer({ + xferAsset: AssetID.fromUint64(rewardToken), + assetReceiver: staker, + assetAmount: amountToSend, + }); + } + + /** + * Update the (honor system) algod version for the node associated to this pool. The node management daemon + * should compare its current nodes version to the version stored in global state, updating when different. + * The reti node daemon composes its own version string using format: + * {major}.{minor}.{build} {branch} [{commit hash}], + * ie: 3.22.0 rel/stable [6b508975] + * [ ONLY OWNER OR MANAGER CAN CALL ] + * @param {string} algodVer - string representing the algorand node daemon version (reti node daemon composes its own meta version) + */ + updateAlgodVer(algodVer: string): void { + assert(this.isOwnerOrManagerCaller()); + this.algodVer.value = algodVer; + } + + /** + * Updates the balance of stakers in the pool based on the received 'rewards' (current balance vs known staked balance) + * stakers outstanding balance is adjusted based on their % of stake and time in the current epoch - so that balance + * compounds over time and staker can remove that amount at will. + * The validator is paid their percentage each epoch payout. + * + * Note: ANYONE can call this. + */ + epochBalanceUpdate(): void { + // call the validator contract to get our payout config data + const validatorConfig = sendMethodCall({ + applicationID: AppID.fromUint64(this.creatingValidatorContractAppId.value), + methodArgs: [this.validatorId.value], + }); + + // ===== + // Ensure full Epoch has passed before allowing a new Epoch update to occur + // ===== + // Since we're being told to payout, we're at epoch 'end' presumably - or close enough + // but what if we're told to pay really early? we need to verify that as well. + const curTime = globals.latestTimestamp; + // Get configured epoch as seconds since we're block time comparisons will be in seconds + const epochInSecs = (validatorConfig.payoutEveryXMins as uint64) * 60; + if (this.lastPayout.exists) { + const secsSinceLastPayout = curTime - this.lastPayout.value; + log(concat('secs since last payout: %i', itob(secsSinceLastPayout))); + + // We've had one payout - so we need to be at least one epoch past the last payout. + assert(secsSinceLastPayout >= epochInSecs, "Can't payout earlier than last payout + epoch time"); + } + // Update our payout time - required to match + this.lastPayout.value = curTime; + this.epochNumber.value += 1; + + // Determine Token rewards if applicable + // ===== + // Do we handle token rewards... ? if so, we need the app address of pool # 1 + const isTokenEligible = validatorConfig.rewardTokenId !== 0; + let poolOneAppID = this.app.id; + let poolOneAddress = this.app.address; + let tokenPayoutRatio: PoolTokenPayoutRatio; + + // Call validator to update our token payout ratio (snapshotting % of whole of all pools so token payout can + // be divided between pools properly) + if (isTokenEligible) { + if (this.poolId.value !== 1) { + // If we're not pool 1 - figure out its address.. + poolOneAppID = sendMethodCall({ + applicationID: AppID.fromUint64(this.creatingValidatorContractAppId.value), + methodArgs: [this.validatorId.value, 1], + }); + poolOneAddress = AppID.fromUint64(poolOneAppID).address; + } + + // Snapshot the ratio of token stake per pool across the pools so the token rewards across pools + // can be based on a stable cross-pool ratio. + if (this.poolId.value === 1) { + tokenPayoutRatio = sendMethodCall({ + applicationID: AppID.fromUint64(this.creatingValidatorContractAppId.value), + methodArgs: [this.validatorId.value], + }); + } else { + // This isn't pool 2 - so call pool 1 to then ask IT to call the validator to call setTokenPayoutRatio + tokenPayoutRatio = sendMethodCall({ + applicationID: AppID.fromUint64(poolOneAppID), + methodArgs: [{ id: this.validatorId.value, poolId: this.poolId.value, poolAppId: this.app.id }], + }); + } + } + + // Get the validator state as well - so we know the total staked for the entire validator, and how much token + // has been held back + const validatorState = sendMethodCall({ + applicationID: AppID.fromUint64(this.creatingValidatorContractAppId.value), + methodArgs: [this.validatorId.value], + }); + const rewardTokenHeldBack = validatorState.rewardTokenHeldBack; + + // Determine ALGO rewards if available + // ===== + // total reward available is current balance - amount staked (so if 100 was staked but balance is 120 - reward is 20) + // [not counting MBR which should never be counted - it's not payable] + let algoRewardAvail = this.app.address.balance - this.totalAlgoStaked.value - this.app.address.minBalance; + let isPoolSaturated = false; + const algoSaturationAmt = this.algoSaturationLevel(); + + // Now verify if our validator has exceeded the saturation level for the 'protocol' (across all pools) - if so, + // then we want to: + // 1) not send the validator any rewards + // 2) send rewards to the stakers, but diminished - just use ratio of amount over the saturation threshold + // ie: diminishedReward = (algoRewardAvail * algoSaturationLevel [max per validator]) / totalAlgoStaked [for validator] + // 3) The excess is sent to the fee sink. + if (validatorState.totalAlgoStaked > algoSaturationAmt) { + log('validator in saturated state'); + isPoolSaturated = true; + } + + // if tokens are rewarded by this validator and determine how much we have to hand out + // we'll track amount we actually assign out and let our validator know so it can mark that amount + // as being held back (for tracking what has been assigned for payout) + let tokenRewardAvail = 0; + let tokenRewardPaidOut = 0; + if (isTokenEligible) { + const tokenRewardBal = + poolOneAddress.assetBalance(AssetID.fromUint64(validatorConfig.rewardTokenId)) - rewardTokenHeldBack; + + // if they have less tokens available then min payout - just ignore and act like no reward is avail + // leaving tokenRewardAvail as 0 + if (tokenRewardBal >= validatorConfig.rewardPerPayout) { + // Now - adjust the token rewards to be relative based on this pools stake as % of 'total validator stake' + // using our prior snapshotted data + // @ts-ignore typescript thinks tokenPayoutRatio might not be set prior to this call but it has to be, based on isTokenEligible + const ourPoolPctOfWhole = tokenPayoutRatio.poolPctOfWhole[this.poolId.value - 1]; + + // now adjust the total reward to hand out for this pool based on this pools % of the whole + tokenRewardAvail = wideRatio([validatorConfig.rewardPerPayout, ourPoolPctOfWhole], [1_000_000]); + // increaseOpcodeBudget(); + // log(concat('token ourPctOfWhole: ', (ourPoolPctOfWhole / 10000).toString())); + // log(concat('token reward held back: ', rewardTokenHeldBack.toString())); + log(concat('token reward avail: ', tokenRewardAvail.toString())); + // log(concat('token reward avail: %i', itob(tokenRewardAvail))); + } + } + if (tokenRewardAvail === 0) { + // no token reward - then algo MUST be paid out as we have to do 'something' ! + // Reward available needs to be at lest 1 algo if an algo reward HAS to be paid out (no token reward) + assert(algoRewardAvail > 1_000_000, 'Reward needs to be at least 1 ALGO'); + } + log(concat('algo reward avail: ', algoRewardAvail.toString())); + // log(concat('algo reward avail: %i', itob(algoRewardAvail))); + + if (isPoolSaturated) { + // see comment where isPoolSaturated is set for changes in rewards... + // diminishedReward = (reward * maxStakePerPool) / stakeForValidator + const diminishedReward = wideRatio([algoRewardAvail, algoSaturationAmt], [validatorState.totalAlgoStaked]); + // send excess to fee sink... + const excessToFeeSink = algoRewardAvail - diminishedReward; + increaseOpcodeBudget(); + log(concat('dim rwd: ', diminishedReward.toString())); + log(concat('to sink: ', excessToFeeSink.toString())); + sendPayment({ + amount: excessToFeeSink, + receiver: this.getFeeSink(), + note: 'pool saturated, portion sent back to fee sink', + }); + // then distribute the smaller reward amount like normal (skipping validator payout entirely) + algoRewardAvail = diminishedReward; + } else if (validatorConfig.percentToValidator !== 0) { + // determine the % that goes to validator... + // ie: 100[algo] * 50_000 (5% w/4 decimals) / 1_000_000 == 5 [algo] + const validatorPay = wideRatio( + [algoRewardAvail, validatorConfig.percentToValidator as uint64], + [1_000_000] + ); + + // and adjust reward for entire pool accordingly + algoRewardAvail -= validatorPay; + + // --- + // pay the validator their cut... + if (validatorPay > 0) { + log(concat('paying validator: %i', itob(validatorPay))); + sendPayment({ + amount: validatorPay, + receiver: validatorConfig.validatorCommissionAddress, + note: 'validator reward', + }); + log(concat('remaining reward: %i', itob(algoRewardAvail))); + } + } + + if (algoRewardAvail === 0 && tokenRewardAvail === 0) { + // likely a personal validator node - probably had validator % at 1000 and we just issued the entire reward + // to them. Since we also have no token reward to assign - we're done + return; + } + + // Now we "pay" (but really just update their tracked balance) the stakers the remainder based on their % of + // pool and time in this epoch. + + // We'll track the amount of stake we add to stakers based on payouts + // If any dust is remaining in account it'll be considered part of reward in next epoch. + let increasedStake = 0; + + /** + * assume A)lice and B)ob have equal stake... and there is a reward of 100 to divide + * |------|-------|... + * A B + * ^ B gets 50% (or 25 of the 50) + * at end - we now have 75 'left' - which gets divided across the people at >=100% of epoch time + * * intended result for 100 reward: + * if A and B have equal stake... they're each 50% of the 'pool' - call that PP (pool percent) + * Time in the epoch - TIE (100% would mean entire epoch - 50% TIE means entered halfway in) + * So, we first pay all partials (<100 TIE) + * B gets 25.... (100 REWARD * 50 PP (.5) * 50 TIE (.5)) or 25. + * -- keep total of stake from each of partial - adding into PartialStake value. + * -- we then see that 25 got paid out - so 25 'excess' needs distributed to the 100 TIE stakers on top of their reward. + * - reward available is now 75 ALGO to distribute - and PP value is based on percent against new total (TotalStaked-PartialStake) + * - so A's PP is now 100% not 50% because their stake is equal to the new reduced stake amount + * so A gets 75 (75 REWARD * 100 PP (1) * 100 TIE (1)) or 75 + * next epoch if nothing else changes - each would get 50% of reward. + */ + // Iterate all stakers - determine which haven't been for entire epoch - pay them proportionally less for having + // less time in pool. We keep track of their stake and then will later reduce the effective 'total staked' amount + // by that so that the remaining stakers get the remaining reward + excess based on their % of stake against + // remaining participants. + let partialStakersTotalStake: uint64 = 0; + for (let i = 0; i < this.stakers.value.length; i += 1) { + if (globals.opcodeBudget < 400) { + increaseOpcodeBudget(); + } + const cmpStaker = clone(this.stakers.value[i]); + if (cmpStaker.account !== globals.zeroAddress) { + if (cmpStaker.entryTime > curTime) { + // due to 'forward dating' entry time this could be possible + // in this case it definitely means they get 0% + partialStakersTotalStake += cmpStaker.balance; + } else { + // Reward is % of users stake in pool, + // but we deduct based on time away from our payout time + const timeInPool = curTime - cmpStaker.entryTime; + let timePercentage: uint64; + // get % of time in pool (in tenths precision) + // ie: 34.7% becomes 347 + if (timeInPool < epochInSecs) { + partialStakersTotalStake += cmpStaker.balance; + timePercentage = (timeInPool * 1000) / epochInSecs; + + // log(concat('% in pool: ', (timePercentage / 10).toString())); + if (tokenRewardAvail > 0) { + // calc: (balance * avail reward * percent in tenths) / (total staked * 1000) + const stakerTokenReward = wideRatio( + [cmpStaker.balance, tokenRewardAvail, timePercentage], + [this.totalAlgoStaked.value, 1000] + ); + + // reduce the reward available (that we're accounting for) so that the subsequent + // 'full' pays are based on what's left + tokenRewardAvail -= stakerTokenReward; + cmpStaker.rewardTokenBalance += stakerTokenReward; + tokenRewardPaidOut += stakerTokenReward; + } + if (algoRewardAvail > 0) { + // calc: (balance * avail reward * percent in tenths) / (total staked * 1000) + const stakerReward = wideRatio( + [cmpStaker.balance, algoRewardAvail, timePercentage], + [this.totalAlgoStaked.value, 1000] + ); + + // reduce the reward available (that we're accounting for) so that the subsequent + // 'full' pays are based on what's left + algoRewardAvail -= stakerReward; + // instead of sending them algo now - just increase their ledger balance, so they can claim + // it at any time. + cmpStaker.balance += stakerReward; + cmpStaker.totalRewarded += stakerReward; + increasedStake += stakerReward; + } + // Update the box w/ the new data + this.stakers.value[i] = cmpStaker; + } + } + } + } + log(concat('partial staker total stake: %i', itob(partialStakersTotalStake))); + + // Reduce the virtual 'total staked in pool' amount based on removing the totals of the stakers we just paid + // partial amounts. This is so that all that remains is the stake of the 100% 'time in epoch' people. + const newPoolTotalStake = this.totalAlgoStaked.value - partialStakersTotalStake; + + // It's technically possible for newPoolTotalStake to be 0, if EVERY staker is new then there'll be nothing to + // hand out this epoch because we'll have reduced the amount to 'count' towards stake by the entire stake + if (newPoolTotalStake > 0) { + // Now go back through the list AGAIN and pay out the full-timers their rewards + excess + for (let i = 0; i < this.stakers.value.length; i += 1) { + if (globals.opcodeBudget < 200) { + increaseOpcodeBudget(); + } + const cmpStaker = clone(this.stakers.value[i]); + if (cmpStaker.account !== globals.zeroAddress && cmpStaker.entryTime < curTime) { + const timeInPool = curTime - cmpStaker.entryTime; + // We're now only paying out people who've been in pool an entire epoch. + if (timeInPool >= epochInSecs) { + // we're in for 100%, so it's just % of stakers balance vs 'new total' for their + // payment + + // Handle token payouts first - as we don't want to use existin balance, not post algo-reward balance + if (tokenRewardAvail > 0) { + // increaseOpcodeBudget(); + // log(concat('staker balance: ', cmpStaker.balance.toString())); + // log(concat('tkn rwd avail: ', tokenRewardAvail.toString())); + // increaseOpcodeBudget(); + // log(concat('new pool stake: ', newPoolTotalStake.toString())); + + const stakerTokenReward = wideRatio( + [cmpStaker.balance, tokenRewardAvail], + [newPoolTotalStake] + ); + // increaseOpcodeBudget(); + // log(concat('paying staker token reward: ', stakerTokenReward.toString())); + + // instead of sending them algo now - just increase their ledger balance, so they can claim + // it at any time. + cmpStaker.rewardTokenBalance += stakerTokenReward; + tokenRewardPaidOut += stakerTokenReward; + } + if (algoRewardAvail > 0) { + const stakerReward = wideRatio([cmpStaker.balance, algoRewardAvail], [newPoolTotalStake]); + // instead of sending them algo now - just increase their ledger balance, so they can claim + // it at any time. + cmpStaker.balance += stakerReward; + cmpStaker.totalRewarded += stakerReward; + increasedStake += stakerReward; + } + + // Update the box w/ the new data + this.stakers.value[i] = cmpStaker; + } + } + } + } + // We've paid out the validator and updated the stakers new balances to reflect the rewards, now update + // our 'total staked' value as well based on what we paid to validator and updated in staker balances as we + // determined stake increases + this.totalAlgoStaked.value += increasedStake; + + log(concat('incr stake: %i', itob(increasedStake))); + log(concat('tok. rwd paid: %i', itob(tokenRewardPaidOut))); + + // Call the validator contract and tell it we've got new stake added + // It'll verify we're a valid staking pool id and update it + // stakeUpdatedViaRewards((uint64,uint64,uint64),uint64)void + sendMethodCall({ + applicationID: AppID.fromUint64(this.creatingValidatorContractAppId.value), + methodArgs: [ + { id: this.validatorId.value, poolId: this.poolId.value, poolAppId: this.app.id }, + increasedStake, + tokenRewardPaidOut, + ], + }); + } + + /** + * Registers a staking pool key online against a participation key. + * [ ONLY OWNER OR MANAGER CAN CALL ] + * + * @param {bytes} votePK - The vote public key. + * @param {bytes} selectionPK - The selection public key. + * @param {bytes} stateProofPK - The state proof public key. + * @param {uint64} voteFirst - The first vote index. + * @param {uint64} voteLast - The last vote index. + * @param {uint64} voteKeyDilution - The vote key dilution value. + * @throws {Error} Will throw an error if the caller is not the owner or a manager. + */ + goOnline( + votePK: bytes, + selectionPK: bytes, + stateProofPK: bytes, + voteFirst: uint64, + voteLast: uint64, + voteKeyDilution: uint64 + ): void { + assert(this.isOwnerOrManagerCaller()); + sendOnlineKeyRegistration({ + votePK: votePK, + selectionPK: selectionPK, + stateProofPK: stateProofPK, + voteFirst: voteFirst, + voteLast: voteLast, + voteKeyDilution: voteKeyDilution, + }); + } + + /** + * Marks a staking pool key OFFLINE. + * [ ONLY OWNER OR MANAGER CAN CALL ] + * + */ + goOffline(): void { + // we can be called by validator contract if we're being moved (which in turn only is allowed to be called + // by validator owner or manager), but if not - must be owner or manager + if (this.txn.sender !== AppID.fromUint64(this.creatingValidatorContractAppId.value).address) { + assert(this.isOwnerOrManagerCaller()); + } + + sendOfflineKeyRegistration({}); + } + + // Links the staking pool's account address to an NFD + // the contract account address must already be set into the NFD's u.cav.algo.a field pending verification + // [ ONLY OWNER OR MANAGER CAN CALL ] + linkToNFD(nfdAppId: uint64, nfdName: string): void { + assert(this.isOwnerOrManagerCaller()); + + sendAppCall({ + applicationID: AppID.fromUint64(this.nfdRegistryAppId), + applicationArgs: ['verify_nfd_addr', nfdName, itob(nfdAppId), rawBytes(this.app.address)], + applications: [AppID.fromUint64(nfdAppId)], + }); + } + + /** + * proxiedSetTokenPayoutRatio is meant to be called by pools != 1 - calling US, pool #1 + * We need to verify that we are in fact being called by another of OUR pools (not us) + * and then we'll call the validator on their behalf to update the token payouts + * @param poolKey - ValidatorPoolKey tuple + */ + proxiedSetTokenPayoutRatio(poolKey: ValidatorPoolKey): PoolTokenPayoutRatio { + assert(this.validatorId.value === poolKey.id, 'caller must be part of same validator set!'); + assert(this.poolId.value === 1, 'callee must be pool 1'); + assert(poolKey.poolId !== 1, 'caller must NOT be pool 1'); + + const callerPoolAppID = sendMethodCall({ + applicationID: AppID.fromUint64(this.creatingValidatorContractAppId.value), + methodArgs: [poolKey.id, poolKey.poolId], + }); + assert(callerPoolAppID === poolKey.poolAppId); + assert(this.txn.sender === AppID.fromUint64(poolKey.poolAppId).address); + + return sendMethodCall({ + applicationID: AppID.fromUint64(this.creatingValidatorContractAppId.value), + methodArgs: [this.validatorId.value], + }); + } + + private isOwnerOrManagerCaller(): boolean { + const OwnerAndManager = sendMethodCall({ + applicationID: AppID.fromUint64(this.creatingValidatorContractAppId.value), + methodArgs: [this.validatorId.value], + }); + return this.txn.sender === OwnerAndManager[0] || this.txn.sender === OwnerAndManager[1]; + } + + /** + * Calculate the entry time for counting a stake as entering the pool. + * Algorand won't see the balance increase for ALGORAND_STAKING_BLOCK_DELAY rounds, so we approximate it. + * The entry time is calculated by adding an approximate number of seconds based on current AVG block times + * to the original entry time. This means users don't get payouts based on time their balance wouldn't have + * been seen by the network. + * + * @returns {uint64} - The updated entry time. + */ + private getEntryTime(): uint64 { + // entry time is the time we want to count this stake as entering the pool. Algorand won't see the balance + // increase for 320 rounds so approximate it as best we can + const entryTime = globals.latestTimestamp; + // we add 320 blocks * AVG_BLOCK_TIME_SECS (which is in tenths, where 30 represents 3 seconds) + // adding that approximate number of seconds to the entry time. + return entryTime + (ALGORAND_STAKING_BLOCK_DELAY * AVG_BLOCK_TIME_SECS) / 10; + } + + private getFeeSink(): Address { + return this.feeSinkAddr; + // will be like: txn FirstValid; int 1; -; block BlkFeeSink + // once available in AVM + } + + /** + * Returns the maximum allowed stake per validator based on a percentage of all current online stake before + * the validator is considered saturated - where rewards are diminished. + */ + private algoSaturationLevel(): uint64 { + const online = this.getCurrentOnlineStake(); + + return wideRatio([online, MAX_VALIDATOR_SOFT_PCT_OF_ONLINE_1DECIMAL], [1000]); + } + + private getCurrentOnlineStake(): uint64 { + // TODO - replace w/ appropriate AVM call once available but return fixed 2 billion for now. + return 2_000_000_000_000_000; + } +} diff --git a/contracts/contracts/validatorRegistry.algo.ts b/contracts/contracts/validatorRegistry.algo.ts new file mode 100644 index 00000000..a5bee947 --- /dev/null +++ b/contracts/contracts/validatorRegistry.algo.ts @@ -0,0 +1,1406 @@ +import { Contract } from '@algorandfoundation/tealscript'; +// eslint-disable-next-line import/no-cycle +import { StakedInfo, StakingPool } from './stakingPool.algo'; +import { + ALGORAND_ACCOUNT_MIN_BALANCE, + APPLICATION_BASE_FEE, + ASSET_HOLDING_FEE, + GATING_TYPE_NONE, + GATING_TYPE_ASSETS_CREATED_BY, + GATING_TYPE_ASSET_ID, + GATING_TYPE_CREATED_BY_NFD_ADDRESSES, + GATING_TYPE_SEGMENT_OF_NFD, + GATING_TYPE_CONST_MAX, + MAX_PCT_TO_VALIDATOR, + MAX_STAKERS_PER_POOL, + MIN_ALGO_STAKE_PER_POOL, + MIN_PCT_TO_VALIDATOR, + SSC_VALUE_BYTES, + SSC_VALUE_UINT, + MAX_VALIDATOR_SOFT_PCT_OF_ONLINE_1DECIMAL, + MAX_VALIDATOR_HARD_PCT_OF_ONLINE_1DECIMAL, +} from './constants.algo'; + +const MAX_NODES = 8; // more just as a reasonable limit and cap on contract storage +const MAX_POOLS_PER_NODE = 3; // max number of pools per node +// This MAX_POOLS constant has to be explicitly specified in ValidatorInfo.pools[ xxx ] StaticArray! +// if this constant is changed, the calculated value must be put in manually into the StaticArray definition. +const MAX_POOLS = MAX_NODES * MAX_POOLS_PER_NODE; + +const MIN_PAYOUT_MINS = 1; +const MAX_PAYOUT_MINS = 10080; // 7 days in minutes +const MAX_POOLS_PER_STAKER = 6; + +type ValidatorIdType = uint64; +export type ValidatorPoolKey = { + id: ValidatorIdType; // 0 is invalid - should start at 1 (but is direct key in box) + poolId: uint64; // 0 means INVALID ! - so 1 is index, technically of [0] + poolAppId: uint64; +}; + +export type ValidatorConfig = { + id: ValidatorIdType; // id of this validator (sequentially assigned) + owner: Address; // account that controls config - presumably cold-wallet + + // [CHANGEABLE] account that triggers/pays for payouts and keyreg transactions - needs to be hotwallet as node has to sign + // for the transactions + manager: Address; + + // [CHANGEABLE] Optional NFD AppID which the validator uses to describe their validator pool + // NFD must be currently OWNED by address that adds the validator + nfdForInfo: uint64; + + // [CHANGEABLE] entryGatingType / entryGatingValue specifies an optional gating mechanism - whose criteria + // the staker must meet. + // It will be the responsibility of the staker (txn composer really) to pick the right thing to check (as argument + // to adding stake) that meets the criteria if this is set. + // Allowed types: + // 1: assets created by address X (val is address of creator) + // 2: specific asset id (val is asset id) + // 3: asset in nfd linked addresses (value is nfd appid) + // 4: segment of a particular NFD (value is root appid) + entryGatingType: uint8; + entryGatingValue: bytes32; + + // [CHANGEABLE] gatingAssetMinBalance specifies a minimum token base units amount needed of an asset owned by the specified + // creator (if defined). If 0, then they need to hold at lest 1 unit, but its assumed this is for tokens, ie: hold + // 10000[.000000] of token + gatingAssetMinBalance: uint64; + + // Optional reward token info + // Reward token ASA id: A validator can define a token that users are awarded in addition to + // the ALGO they receive for being in the pool. This will allow projects to allow rewarding members their own + // token. Hold at least 5000 VEST to enter a Vestige staking pool, they have 1 day epochs and all + // stakers get X amount of VEST as daily rewards (added to stakers ‘available’ balance) for removal at any time. + rewardTokenId: uint64; + // [CHANGEABLE] Reward rate : Defines the amount of rewardTokenId that is rewarded per epoch across all pools + // (by their % stake of the validators total) + rewardPerPayout: uint64; + + payoutEveryXMins: uint16; // Payout frequency in minutes (can be no shorter than this) + percentToValidator: uint32; // Payout percentage expressed w/ four decimals - ie: 50000 = 5% -> .0005 - + + validatorCommissionAddress: Address; // [CHANGEABLE] account that receives the validation commission each epoch payout (can be ZeroAddress) + minEntryStake: uint64; // minimum stake required to enter pool - but must withdraw all if they want to go below this amount as well(!) + maxAlgoPerPool: uint64; // maximum stake allowed per pool - if validator wants to restrict it. 0 means to use 'current' limits. + poolsPerNode: uint8; // Number of pools to allow per node (max of 3 is recommended) + + sunsettingOn: uint64; // [CHANGEABLE] timestamp when validator will sunset (if != 0) + sunsettingTo: ValidatorIdType; // [CHANGEABLE] validator id that validator is 'moving' to (if known) +}; + +type ValidatorCurState = { + numPools: uint16; // current number of pools this validator has - capped at MaxPools + totalStakers: uint64; // total number of stakers across all pools of THIS validator + totalAlgoStaked: uint64; // total amount staked to this validator across ALL of its pools + // amount of the reward token held back in pool 1 for paying out stakers their rewards. + // as reward tokens are assigned to stakers - the amount as part of each epoch will be updated + // in this value and this amount has to be assumed 'spent' - only reducing this number as the token + // is actually sent out by request of the validator itself + rewardTokenHeldBack: uint64; +}; + +type PoolInfo = { + poolAppId: uint64; // The App id of this staking pool contract instance + totalStakers: uint16; + totalAlgoStaked: uint64; +}; + +type NodeConfig = { + poolAppIds: StaticArray; +}; + +type NodePoolAssignmentConfig = { + nodes: StaticArray; +}; + +export type PoolTokenPayoutRatio = { + // MUST TRACK THE MAX_POOLS CONSTANT (MAX_POOLS_PER_NODE * MAX_NODES) ! + poolPctOfWhole: StaticArray; + // epoch timestmap when set - only pool 1 caller can trigger/calculate this and only once per epoch + // set and compared against pool 1's lastPayout property. + updatedForPayout: uint64; +}; + +type ValidatorInfo = { + config: ValidatorConfig; + state: ValidatorCurState; + // MUST TRACK THE MAX_POOLS CONSTANT (MAX_POOLS_PER_NODE * MAX_NODES) ! + pools: StaticArray; + tokenPayoutRatio: PoolTokenPayoutRatio; + nodePoolAssignments: NodePoolAssignmentConfig; +}; + +type MbrAmounts = { + addValidatorMbr: uint64; + addPoolMbr: uint64; + poolInitMbr: uint64; + addStakerMbr: uint64; +}; + +type Constraints = { + epochPayoutMinsMin: uint64; + epochPayoutMinsMax: uint64; + minPctToValidatorWFourDecimals: uint64; + maxPctToValidatorWFourDecimals: uint64; + minEntryStake: uint64; // in microAlgo + maxAlgoPerPool: uint64; // in microAlgo + maxAlgoPerValidator: uint64; // in microAlgo + amtConsideredSaturated: uint64; // soft stake - when saturation starts - in microAlgo + maxNodes: uint64; + maxPoolsPerNode: uint64; + maxStakersPerPool: uint64; +}; + +// eslint-disable-next-line no-unused-vars +/** + * ValidatorRegistry is the 'master contract' for the reti pooling protocol. + * A single immutable instance of this is deployed. All state for all validators including information about their + * pools and nodes is stored via this contract in global state and box storage. Data in the pools themselves is stored + * within the StakingPool contract instance, also in global state and box storage. + * See the StakingPool contract comments for details on how this contract creates new instances of them. + */ +export class ValidatorRegistry extends Contract { + programVersion = 10; + + // ====== + // GLOBAL STATE AND TEMPLATES + // ====== + numValidators = GlobalStateKey({ key: 'numV' }); + + // The app id of a staking pool contract instance to use as template for newly created pools + stakingPoolTemplateAppId = GlobalStateKey({ key: 'poolTemplateAppId' }); + + // Track the 'global' protocol number of stakers + numStakers = GlobalStateKey({ key: 'numStakers' }); + + // Track the 'global' protocol amount of stake + totalAlgoStaked = GlobalStateKey({ key: 'staked' }); + + // Validator list - simply incremental id - direct access to info for validator + // and also contains all pool information (but not user-account ledger per pool) + validatorList = BoxMap({ prefix: 'v' }); + + // For given user staker address, which of up to MAX_POOLS_PER_STAKER validator/pools are they in + // We use this to find a particular addresses deposits (in up to X independent pools w/ any validators) + stakerPoolSet = BoxMap>({ prefix: 'sps' }); + + nfdRegistryAppId = TemplateVar(); + + // ====== + // PUBLIC CONTRACT METHODS + // ====== + createApplication(poolTemplateAppId: uint64): void { + this.numValidators.value = 0; + this.stakingPoolTemplateAppId.value = poolTemplateAppId; + this.numStakers.value = 0; + this.totalAlgoStaked.value = 0; + } + + /** + * gas is a dummy no-op call that can be used to pool-up resource references and opcode cost + */ + gas(): void {} + + /** + * Returns the MBR amounts needed for various actions: + * [ + * addValidatorMbr: uint64 - mbr needed to add a new validator - paid to validator contract + * addPoolMbr: uint64 - mbr needed to add a new pool - paid to validator + * poolInitMbr: uint64 - mbr needed to initStorage() of pool - paid to pool itself + * addStakerMbr: uint64 - mbr staker needs to add to first staking payment (stays w/ validator) + * ] + */ + getMbrAmounts(): MbrAmounts { + // Cost for creator of validator contract itself is (but not really our problem - it's a bootstrap issue only) + // this.minBalanceForAccount(0, 0, 0, 0, 0, 4, 0) + return { + addValidatorMbr: this.costForBoxStorage(1 /* v prefix */ + len() + len()), + addPoolMbr: this.minBalanceForAccount( + 1, + 0, + 0, + 0, + 0, + StakingPool.schema.global.numUint, + StakingPool.schema.global.numByteSlice + ), + poolInitMbr: + ALGORAND_ACCOUNT_MIN_BALANCE + + this.costForBoxStorage(7 /* 'stakers' name */ + len() * MAX_STAKERS_PER_POOL), + addStakerMbr: + // how much to charge for first time a staker adds stake - since we add a tracking box per staker + this.costForBoxStorage( + 3 /* 'sps' prefix */ + len
() + len() * MAX_POOLS_PER_STAKER + ), // size of key + all values + }; + } + + /** + * Returns the protocol constraints so that UIs can limit what users specify for validator configuration parameters. + */ + getProtocolConstraints(): Constraints { + return { + epochPayoutMinsMin: MIN_PAYOUT_MINS, + epochPayoutMinsMax: MAX_PAYOUT_MINS, + minPctToValidatorWFourDecimals: MIN_PCT_TO_VALIDATOR, + maxPctToValidatorWFourDecimals: MAX_PCT_TO_VALIDATOR, + minEntryStake: MIN_ALGO_STAKE_PER_POOL, + maxAlgoPerPool: this.maxAlgoAllowedPerPool(), + maxAlgoPerValidator: this.maxAllowedStake(), + amtConsideredSaturated: this.algoSaturationLevel(), + maxNodes: MAX_NODES, + maxPoolsPerNode: MAX_POOLS_PER_NODE, + maxStakersPerPool: MAX_STAKERS_PER_POOL, + }; + } + + /** + * Returns the current number of validators + */ + // @abi.readonly + getNumValidators(): uint64 { + return this.numValidators.value; + } + + // @abi.readonly + getValidatorConfig(validatorId: ValidatorIdType): ValidatorConfig { + return this.validatorList(validatorId).value.config; + } + + // @abi.readonly + getValidatorState(validatorId: ValidatorIdType): ValidatorCurState { + return this.validatorList(validatorId).value.state; + } + + // @abi.readonly + getValidatorOwnerAndManager(validatorId: ValidatorIdType): [Address, Address] { + return [ + this.validatorList(validatorId).value.config.owner, + this.validatorList(validatorId).value.config.manager, + ]; + } + + // @abi.readonly + /** + * Return list of all pools for this validator. + * @param {uint64} validatorId + * @return {PoolInfo[]} - array of pools + * Not callable from other contracts because >1K return but can be called w/ simulate which bumps log returns + */ + getPools(validatorId: ValidatorIdType): PoolInfo[] { + const retData: PoolInfo[] = []; + const poolSet = clone(this.validatorList(validatorId).value.pools); + for (let i = 0; i < poolSet.length; i += 1) { + if (poolSet[i].poolAppId === 0) { + // reached end of list... we don't replace values here because pools can't be removed + break; + } + retData.push(poolSet[i]); + } + return retData; + } + + // @abi.readonly + // getPoolAppId is useful for callers to determine app to call for removing stake if they don't have staking or + // want to get staker list for an account. The staking pool also uses it to get the app id of staking pool 1 + // (which contains reward tokens if being used) so that the amount available can be determined. + getPoolAppId(validatorId: uint64, poolId: uint64): uint64 { + assert(poolId !== 0 && poolId <= this.validatorList(validatorId).value.pools.length); + return this.validatorList(validatorId).value.pools[poolId - 1].poolAppId; + } + + // @abi.readonly + getPoolInfo(poolKey: ValidatorPoolKey): PoolInfo { + return this.validatorList(poolKey.id).value.pools[poolKey.poolId - 1]; + } + + /** + * Calculate the maximum stake per pool for a given validator. + * Normally this would be maxAlgoPerPool, but it should also never go above MaxAllowedStake / numPools so + * as pools are added the max allowed per pool can reduce. + * + * @param {ValidatorIdType} validatorId - The id of the validator. + */ + getCurMaxStakePerPool(validatorId: ValidatorIdType): uint64 { + const numPools = this.validatorList(validatorId).value.state.numPools as uint64; + const hardMaxDividedBetweenPools = this.maxAllowedStake() / numPools; + let maxPerPool: uint64 = this.validatorList(validatorId).value.config.maxAlgoPerPool; + if (maxPerPool === 0) { + maxPerPool = this.maxAlgoAllowedPerPool(); + } + if (hardMaxDividedBetweenPools < maxPerPool) { + maxPerPool = hardMaxDividedBetweenPools; + } + return maxPerPool; + } + + // @abi.readonly + /** + * Helper callers can call w/ simulate to determine if 'AddStaker' MBR should be included w/ staking amount + * @param staker + */ + doesStakerNeedToPayMBR(staker: Address): boolean { + return !this.stakerPoolSet(staker).exists; + } + + /** + * Retrieves the staked pools for an account. + * + * @param {Address} staker - The account to retrieve staked pools for. + * @return {ValidatorPoolKey[]} - The array of staked pools for the account. + */ + getStakedPoolsForAccount(staker: Address): ValidatorPoolKey[] { + if (!this.stakerPoolSet(staker).exists) { + return []; + } + const retData: ValidatorPoolKey[] = []; + const poolSet = clone(this.stakerPoolSet(staker).value); + for (let i = 0; i < poolSet.length; i += 1) { + if (poolSet[i].id !== 0) { + retData.push(poolSet[i]); + } + } + return retData; + } + + // @abi.readonly + /** + * Retrieves the token payout ratio for a given validator - returning the pool ratios of whole so that token + * payouts across pools can be based on a stable snaphost of stake. + * + * @param {ValidatorIdType} validatorId - The id of the validator. + * @return {PoolTokenPayoutRatio} - The token payout ratio for the validator. + */ + getTokenPayoutRatio(validatorId: ValidatorIdType): PoolTokenPayoutRatio { + return this.validatorList(validatorId).value.tokenPayoutRatio; + } + + // @abi.readonly + getNodePoolAssignments(validatorId: uint64): NodePoolAssignmentConfig { + assert(this.validatorList(validatorId).exists); + + return this.validatorList(validatorId).value.nodePoolAssignments; + } + + getNFDRegistryID(): uint64 { + return this.nfdRegistryAppId; + } + + /** Adds a new validator + * @param mbrPayment payment from caller which covers mbr increase of new validator storage + * @param nfdName (Optional) Name of nfd (used as double-check against id specified in config) + * @param config ValidatorConfig struct + * @returns validator id + */ + addValidator(mbrPayment: PayTxn, nfdName: string, config: ValidatorConfig): uint64 { + this.validateConfig(config); + assert(config.owner !== Address.zeroAddress); + assert(config.manager !== Address.zeroAddress); + assert(this.txn.sender === config.owner, 'sender must be owner to add new validator'); + + verifyPayTxn(mbrPayment, { amount: this.getMbrAmounts().addValidatorMbr }); + + // We're adding a new validator - same owner might have multiple - we don't care. + const validatorId = this.numValidators.value + 1; + this.numValidators.value = validatorId; + + this.validatorList(validatorId).create(); + this.validatorList(validatorId).value.config = config; + this.validatorList(validatorId).value.config.id = validatorId; + // all other values being 0 is correct (for 'state' for eg) + + if (config.nfdForInfo !== 0) { + // verify nfd is real, matches provided name, and owned by sender + sendAppCall({ + applicationID: AppID.fromUint64(this.nfdRegistryAppId), + applicationArgs: ['is_valid_nfd_appid', nfdName, itob(config.nfdForInfo)], + applications: [AppID.fromUint64(config.nfdForInfo)], + }); + assert(btoi(this.itxn.lastLog) === 1, "provided NFD isn't valid"); + // Verify the NFDs owner is same as our sender (presumably either owner or manager) + assert( + this.txn.sender === (AppID.fromUint64(config.nfdForInfo).globalState('i.owner.a') as Address), + 'If specifying NFD, account adding validator must be owner' + ); + } + if (config.entryGatingType === GATING_TYPE_CREATED_BY_NFD_ADDRESSES) { + // we require the NFD we compare against to be the one set in nfdForInfo + assert(config.nfdForInfo !== 0, 'an NFD must be specified for the validator when gating by NFD addresses'); + } + if (config.entryGatingType === GATING_TYPE_SEGMENT_OF_NFD) { + // verify gating NFD is at least 'real' - since we just have app id - fetch its name then do is valid call + const nfdRootAppID = extractUint64(config.entryGatingValue, 0); + assert(this.isNFDAppIDValid(nfdRootAppID), 'provided NFD App id for gating must be valid NFD'); + } + // this.retiOP_addedValidator.log({ id: validatorId, owner: config.owner, manager: config.manager }); + return validatorId; + } + + /** + * Changes the Validator manager for a specific Validator id. + * [ ONLY OWNER CAN CHANGE ] + * + * @param {ValidatorIdType} validatorId - The id of the validator to change the manager for. + * @param {Address} manager - The new manager address. + */ + changeValidatorManager(validatorId: ValidatorIdType, manager: Address): void { + assert(this.txn.sender === this.validatorList(validatorId).value.config.owner); + this.validatorList(validatorId).value.config.manager = manager; + } + + /** + * Updates the sunset information for a given validator. + * [ ONLY OWNER CAN CHANGE ] + * + * @param {ValidatorIdType} validatorId - The id of the validator to update. + * @param {uint64} sunsettingOn - The new sunset timestamp. + * @param {uint64} sunsettingTo - The new sunset to validator id. + */ + changeValidatorSunsetInfo(validatorId: ValidatorIdType, sunsettingOn: uint64, sunsettingTo: ValidatorIdType): void { + assert(this.txn.sender === this.validatorList(validatorId).value.config.owner); + this.validatorList(validatorId).value.config.sunsettingOn = sunsettingOn; + this.validatorList(validatorId).value.config.sunsettingTo = sunsettingTo; + } + + /** + * Changes the NFD for a validator in the validatorList contract. + * [ ONLY OWNER OR MANAGER CAN CHANGE ] + * + * @param {ValidatorIdType} validatorId - The id of the validator to update. + * @param {uint64} nfdAppID - The application id of the NFD to assign to the validator. + * @param {string} nfdName - The name of the NFD (which must match) + */ + changeValidatorNFD(validatorId: ValidatorIdType, nfdAppID: uint64, nfdName: string): void { + // Must be called by the owner or manager of the validator. + assert( + this.txn.sender === this.validatorList(validatorId).value.config.owner || + this.txn.sender === this.validatorList(validatorId).value.config.manager + ); + // verify nfd is real, and owned by owner or manager + sendAppCall({ + applicationID: AppID.fromUint64(this.nfdRegistryAppId), + applicationArgs: ['is_valid_nfd_appid', nfdName, itob(nfdAppID)], + applications: [AppID.fromUint64(nfdAppID)], + }); + // we know sender is owner or manager - so if sender is owner of nfd - we're fine. + assert( + this.txn.sender === (AppID.fromUint64(nfdAppID).globalState('i.owner.a') as Address), + 'If specifying NFD, account adding validator must be owner' + ); + this.validatorList(validatorId).value.config.nfdForInfo = nfdAppID; + } + + /** + * Change the commission address that validator rewards are sent to. + [ ONLY OWNER CAN CHANGE ] + */ + changeValidatorCommissionAddress(validatorId: ValidatorIdType, commissionAddress: Address): void { + assert(this.txn.sender === this.validatorList(validatorId).value.config.owner); + assert(commissionAddress !== Address.zeroAddress); + this.validatorList(validatorId).value.config.validatorCommissionAddress = commissionAddress; + } + + /** + * Allow the additional rewards (gating entry, additional token rewards) information be changed at will. + * [ ONLY OWNER CAN CHANGE ] + */ + changeValidatorRewardInfo( + validatorId: ValidatorIdType, + EntryGatingType: uint8, + EntryGatingValue: bytes32, + GatingAssetMinBalance: uint64, + RewardPerPayout: uint64 + ): void { + assert(this.txn.sender === this.validatorList(validatorId).value.config.owner); + + this.validatorList(validatorId).value.config.entryGatingType = EntryGatingType; + this.validatorList(validatorId).value.config.entryGatingValue = EntryGatingValue; + this.validatorList(validatorId).value.config.gatingAssetMinBalance = GatingAssetMinBalance; + this.validatorList(validatorId).value.config.rewardPerPayout = RewardPerPayout; + } + + /** + * Adds a new pool to a validator's pool set, returning the 'key' to reference the pool in the future for staking, etc. + * The caller must pay the cost of the validators MBR increase as well as the MBR that will be needed for the pool itself. + * + * [ ONLY OWNER OR MANAGER CAN call ] + * @param {PayTxn} mbrPayment payment from caller which covers mbr increase of adding a new pool + * @param {uint64} validatorId is id of validator to pool to (must be owner or manager) + * @param {uint64} nodeNum is node number to add to + * @returns {ValidatorPoolKey} pool key to created pool + * + */ + addPool(mbrPayment: PayTxn, validatorId: ValidatorIdType, nodeNum: uint64): ValidatorPoolKey { + // Must be called by the owner or manager of the validator. + assert( + this.txn.sender === this.validatorList(validatorId).value.config.owner || + this.txn.sender === this.validatorList(validatorId).value.config.manager + ); + + // must match MBR exactly + verifyPayTxn(mbrPayment, { amount: this.getMbrAmounts().addPoolMbr, receiver: this.app.address }); + + assert(this.validatorList(validatorId).exists); + + let numPools: uint64 = this.validatorList(validatorId).value.state.numPools as uint64; + if ((numPools as uint64) >= MAX_POOLS) { + throw Error('already at max pool size'); + } + numPools += 1; + + // Create the actual staker pool contract instance + sendAppCall({ + onCompletion: OnCompletion.NoOp, + approvalProgram: AppID.fromUint64(this.stakingPoolTemplateAppId.value).approvalProgram, + clearStateProgram: AppID.fromUint64(this.stakingPoolTemplateAppId.value).clearStateProgram, + globalNumUint: AppID.fromUint64(this.stakingPoolTemplateAppId.value).globalNumUint, + globalNumByteSlice: AppID.fromUint64(this.stakingPoolTemplateAppId.value).globalNumByteSlice, + extraProgramPages: AppID.fromUint64(this.stakingPoolTemplateAppId.value).extraProgramPages, + applicationArgs: [ + // creatingContractID, validatorId, poolId, minEntryStake + method('createApplication(uint64,uint64,uint64,uint64)void'), + itob(this.app.id), + itob(validatorId), + itob(numPools as uint64), + itob(this.validatorList(validatorId).value.config.minEntryStake), + ], + }); + + this.validatorList(validatorId).value.state.numPools = numPools as uint16; + // We don't need to manipulate anything in the pools array as the '0' values are all correct for PoolInfo + // No stakers, no algo staked + const poolAppId = this.itxn.createdApplicationID.id; + this.validatorList(validatorId).value.pools[numPools - 1].poolAppId = poolAppId; + this.addPoolToNode(validatorId, poolAppId, nodeNum); + + // this.retiOP_validatorAddedPool.log({ + // id: validatorId, + // num: numPools as uint16, + // poolAppId: AppID.fromUint64(poolAppId), + // }); + // PoolID is 1-based, 0 is invalid id + return { id: validatorId, poolId: numPools as uint64, poolAppId: this.itxn!.createdApplicationID.id }; + } + + /** + * Adds stake to a validator pool. + * + * @param {PayTxn} stakedAmountPayment - payment coming from staker to place into a pool + * @param {ValidatorIdType} validatorId - The id of the validator. + * @param {uint64} valueToVerify - only if validator has gating to enter - this is asset id or nfd id that corresponds to gating. + * Txn sender is factored in as well if that is part of gating. + * * @returns {ValidatorPoolKey} - The key of the validator pool. + */ + addStake(stakedAmountPayment: PayTxn, validatorId: ValidatorIdType, valueToVerify: uint64): ValidatorPoolKey { + assert(this.validatorList(validatorId).exists); + + const staker = this.txn.sender; + // The prior transaction should be a payment to this pool for the amount specified. If this is stakers + // first time staking, then we subtract the required MBR from their payment as that MBR amount needs to stay + // behind in this contract to cover the MBR needed for creating the 'stakerPoolSet' storage. + verifyPayTxn(stakedAmountPayment, { + sender: staker, + receiver: this.app.address, + }); + + // Ensure we're not over our protocol maximum for combined stake in all pools using the + // MAX_VALIDATOR_HARD_PCT_OF_ONLINE_1DECIMAL percentage + assert( + this.validatorList(validatorId).value.state.totalAlgoStaked < this.maxAllowedStake(), + 'total staked for all of a validators pools may not exceed hard cap' + ); + // If the validator specified that a specific token creator is required to stake, verify that the required + // balance is held by the staker, and that the asset they offered up to validate was created by the account + // the validator defined as its creator requirement. + this.doesStakerMeetGating(validatorId, valueToVerify); + + let realAmount = stakedAmountPayment.amount; + let mbrAmtLeftBehind: uint64 = 0; + // determine if this is FIRST time this user has ever staked - they need to pay MBR + if (!this.stakerPoolSet(staker).exists) { + // We'll deduct the required MBR from what the user is depositing by telling callPoolAddState to leave + // that amount behind and subtract from their depositing stake. + mbrAmtLeftBehind = this.getMbrAmounts().addStakerMbr; + realAmount -= mbrAmtLeftBehind; + this.stakerPoolSet(staker).create(); + } + // find existing slot where staker is already in a pool w/ this validator, or if none found, then ensure they're + // putting in minimum amount for this validator. + const findRet = this.findPoolForStaker(validatorId, staker, realAmount); + const poolKey = findRet[0]; + const isNewStakerToValidator = findRet[1]; + const isNewStakerToProtocol = findRet[2]; + if (poolKey.poolId === 0) { + throw Error('No pool available with free stake. Validator needs to add another pool'); + } + + // Update StakerPoolList for this found pool (new or existing) + this.updateStakerPoolSet(staker, poolKey); + // Send the callers algo amount (- mbrAmtLeftBehind) to the specified staking pool, and it then updates + // the staker data. + this.callPoolAddStake( + stakedAmountPayment, + poolKey, + mbrAmtLeftBehind, + isNewStakerToValidator, + isNewStakerToProtocol + ); + // this.retiOP_stakeAdded.log({ + // id: validatorId, + // poolNum: poolKey.poolId as uint16, + // poolAppId: AppID.fromUint64(poolKey.poolAppId), + // amountStaked: realAmount, + // staker: staker, + // }); + + return poolKey; + } + + /** + * setTokenPayoutRatio is called by Staking Pool # 1 (ONLY) to ask the validator (us) to calculate the ratios + * of stake in the pools for subsequent token payouts (ie: 2 pools, '100' algo total staked, 60 in pool 1, and 40 + * in pool 2. This is done so we have a stable snapshot of stake - taken once per epoch - only triggered by + * pool 1 doing payout. pools other than 1 doing payout call pool 1 to ask it do it first. + * It would be 60/40% in the poolPctOfWhole values. The token reward payouts then use these values instead of + * their 'current' stake which changes as part of the payouts themselves (and people could be changing stake + * during the epoch updates across pools) + * + * Multiple pools will call us via pool 1 (pool2->pool1->valdiator, etc.) so don't assert on pool1 calling multiple + * times in same epoch. Just return. + * + * @param validatorId - validator id (and thus pool) calling us. Verified so that sender MUST be pool 1 of this validator. + * @returns PoolTokenPayoutRatio - the finished ratio data + */ + setTokenPayoutRatio(validatorId: ValidatorIdType): PoolTokenPayoutRatio { + // Get pool 1 for this validator - caller MUST MATCH! + const pool1AppID = this.validatorList(validatorId).value.pools[0].poolAppId; + assert(pool1AppID !== 0); + // Sender has to match the pool app id passed in - so we ensure only pool 1 can call us. + if (this.txn.sender !== AppID.fromUint64(pool1AppID).address) { + return this.validatorList(validatorId).value.tokenPayoutRatio; + } + + // They can only call us if the epoch update time doesn't match what pool 1 already has - and it has to be at least + // a full epoch since last update (unless not set). Same check as pools themselves perform. + const curTime = globals.latestTimestamp; + const lastPayoutUpdate = this.validatorList(validatorId).value.tokenPayoutRatio.updatedForPayout; + if (lastPayoutUpdate !== 0) { + // We've already done the calcs - return what we already have. + if ((AppID.fromUint64(pool1AppID).globalState('lastPayout') as uint64) === lastPayoutUpdate) { + return this.validatorList(validatorId).value.tokenPayoutRatio; + } + const secsSinceLastPayout = curTime - lastPayoutUpdate; + const epochInSecs = (this.validatorList(validatorId).value.config.payoutEveryXMins as uint64) * 60; + // We've had one payout - so we need to be at least one epoch past the last payout. + if (secsSinceLastPayout < epochInSecs) { + return this.validatorList(validatorId).value.tokenPayoutRatio; + } + } + this.validatorList(validatorId).value.tokenPayoutRatio.updatedForPayout = curTime; + + const curNumPools = this.validatorList(validatorId).value.state.numPools as uint64; + const totalStakeForValidator = this.validatorList(validatorId).value.state.totalAlgoStaked; + for (let i = 0; i < curNumPools; i += 1) { + // ie: this pool 2 has 1000 algo staked and the validator has 10,000 staked total (9000 pool 1, 1000 pool 2) + // so this pool is 10% of the total and thus it gets 10% of the avail community token reward. + // Get our pools pct of all stake w/ 4 decimals + // ie, based on prior eg - (1000 * 1e6) / 10000 = 100,000 (or 10%) + const ourPoolPctOfWhole = wideRatio( + [this.validatorList(validatorId).value.pools[i].totalAlgoStaked, 1_000_000], + [totalStakeForValidator] + ); + this.validatorList(validatorId).value.tokenPayoutRatio.poolPctOfWhole[i] = ourPoolPctOfWhole; + } + return this.validatorList(validatorId).value.tokenPayoutRatio; + } + + /** + * stakeUpdatedViaRewards is called by Staking pools to inform the validator (us) that a particular amount of total + * stake has been added to the specified pool. This is used to update the stats we have in our PoolInfo storage. + * The calling App id is validated against our pool list as well. + * @param {ValidatorPoolKey} poolKey - ValidatorPoolKey type + * @param {uint64} algoToAdd - amount this validator's total stake increased via rewards + * @param {uint64} rewardTokenAmountReserved - amount this validator's total stake increased via rewards (that should be + * seen as 'accounted for/pending spent') + */ + stakeUpdatedViaRewards(poolKey: ValidatorPoolKey, algoToAdd: uint64, rewardTokenAmountReserved: uint64): void { + this.verifyPoolKeyCaller(poolKey); + + // Update the specified amount of stake (+reward tokens reserved) - update pool stats, then total validator stats + this.validatorList(poolKey.id).value.pools[poolKey.poolId - 1].totalAlgoStaked += algoToAdd; + this.validatorList(poolKey.id).value.state.totalAlgoStaked += algoToAdd; + this.validatorList(poolKey.id).value.state.rewardTokenHeldBack += rewardTokenAmountReserved; + + this.totalAlgoStaked.value += algoToAdd; + + // Re-validate the NFD as well while we're here, removing as associated nfd if no longer owner + this.reverifyNFDOwnership(poolKey.id); + + // this.retiOP_epochRewardUpdate.log({ + // id: poolKey.id, + // poolNum: poolKey.poolId as uint16, + // poolAppId: AppID.fromUint64(poolKey.poolAppId), + // algoAdded: algoToAdd, + // rewardTokenHeldBack: rewardTokenAmountReserved, + // }); + } + + /** + * stakeRemoved is called by Staking pools to inform the validator (us) that a particular amount of total stake has been removed + * from the specified pool. This is used to update the stats we have in our PoolInfo storage. + * If any amount of rewardRemoved is specified, then that amount of reward is sent to the use + * The calling App id is validated against our pool list as well. + + * @param {ValidatorPoolKey} poolKey calling us from which stake was removed + * @param {Address} staker + * @param {uint64} amountRemoved - algo amount removed + * @param {uint64} rewardRemoved - if applicable, amount of token reward removed (by pool 1 caller) or TO remove and pay out (via pool 1 from different pool caller) + * @param {boolean} stakerRemoved + */ + stakeRemoved( + poolKey: ValidatorPoolKey, + staker: Address, + amountRemoved: uint64, + rewardRemoved: uint64, + stakerRemoved: boolean + ): void { + if (globals.opcodeBudget < 300) { + increaseOpcodeBudget(); + } + this.verifyPoolKeyCaller(poolKey); + + // Yup - we've been called by an official staking pool telling us about stake that was removed from it, + // so we can update our validator's staking stats. + assert(amountRemoved > 0 || rewardRemoved > 0); + + // Remove the specified amount of stake - update pool stats, then total validator stats + this.validatorList(poolKey.id).value.pools[poolKey.poolId - 1].totalAlgoStaked -= amountRemoved; + this.validatorList(poolKey.id).value.state.totalAlgoStaked -= amountRemoved; + this.totalAlgoStaked.value -= amountRemoved; + + if (rewardRemoved > 0) { + const rewardTokenID = this.validatorList(poolKey.id).value.config.rewardTokenId; + assert(rewardTokenID !== 0, "rewardRemoved can't be set if validator doesn't have reward token!"); + assert( + this.validatorList(poolKey.id).value.state.rewardTokenHeldBack >= rewardRemoved, + 'reward being removed must be covered by hold back amount' + ); + // If pool 1 is calling us, then they already sent the reward token to the staker and we just need to + // update the rewardTokenHeldBack value and that's it. + this.validatorList(poolKey.id).value.state.rewardTokenHeldBack -= rewardRemoved; + + // If a different pool called us, then they CAN'T send the token - we've already updated the + // rewardTokenHeldBack value and then call method in the pool that can only be called by us (the + // validator), and can only be called on pool 1 [Index 0] - to have it do the token payout. + if (poolKey.poolId !== 1) { + sendMethodCall({ + applicationID: AppID.fromUint64(this.validatorList(poolKey.id).value.pools[0].poolAppId), + methodArgs: [staker, rewardTokenID, rewardRemoved], + }); + } + // this.retiOP_stakeRemoved.log({ + // id: poolKey.id, + // poolNum: poolKey.poolId as uint16, + // poolAppId: AppID.fromUint64(poolKey.poolAppId), + // staker: staker, + // amountUnstaked: amountRemoved, + // rewardTokenAssetId: AssetID.fromUint64(rewardTokenID), + // rewardTokensReceived: rewardRemoved, + // }); + } else { + // this.retiOP_stakeRemoved.log({ + // id: poolKey.id, + // poolNum: poolKey.poolId as uint16, + // poolAppId: AppID.fromUint64(poolKey.poolAppId), + // staker: staker, + // amountUnstaked: amountRemoved, + // // no tokens rewarded.. + // rewardTokenAssetId: AssetID.zeroIndex, + // rewardTokensReceived: 0, + // }); + } + + if (stakerRemoved) { + // remove from that pool + this.validatorList(poolKey.id).value.pools[poolKey.poolId - 1].totalStakers -= 1; + // then update the staker set. + const removeRet = this.removeFromStakerPoolSet(staker, { + id: poolKey.id, + poolId: poolKey.poolId, + poolAppId: poolKey.poolAppId, + }); + const stakerOutOfThisValidator = removeRet[0]; + const stakerOutOfProtocol = removeRet[1]; + // then remove as a staker from validator stats if they're 'out' of that validators pools + if (stakerOutOfThisValidator) { + this.validatorList(poolKey.id).value.state.totalStakers -= 1; + } + // and remove from count of stakers in 'protocol' stats if they're out of ALL pools + if (stakerOutOfProtocol) { + this.numStakers.value -= 1; + } + } + } + + /** + * Finds the pool for a staker based on the provided validator id, staker address, and amount to stake. + * First checks the stakers 'already staked list' for the validator preferring those (adding if possible) then adds + * to new pool if necessary. + * + * @param {ValidatorIdType} validatorId - The id of the validator. + * @param {Address} staker - The address of the staker. + * @param {uint64} amountToStake - The amount to stake. + * @returns {ValidatorPoolKey, boolean, boolean} - The pool for the staker, true/false on whether the staker is 'new' + * to this VALIDATOR, and true/false if staker is new to the protocol. + */ + findPoolForStaker( + validatorId: ValidatorIdType, + staker: Address, + amountToStake: uint64 + ): [ValidatorPoolKey, boolean, boolean] { + let isNewStakerToValidator = true; + let isNewStakerToProtocol = true; + // We have max per pool per validator - this value is stored in the pools as well, and they enforce it on their + // addStake calls but the values should be the same, and we shouldn't even try to add stake if it won't even + // be accepted. + // However, one thing extra we also handle is have a 'soft' maximum per pool so that the amounts balance out based on + // maxAllowedStake() (hard x % of all online stake) - taking that max / numPools. This way as pools are added + // to go beyond the individual pool maximum, the maximum for each pool starts to reflect the max allowed but + // balanced across the pools. + const maxPerPool = this.getCurMaxStakePerPool(validatorId); + // If there's already a stake list for this account, walk that first, so if the staker is already in THIS + // validator, then go to the stakers existing pool(s) w/ this validator first. + if (this.stakerPoolSet(staker).exists) { + const poolSet = clone(this.stakerPoolSet(staker).value); + assert(validatorId !== 0); + for (let i = 0; i < poolSet.length; i += 1) { + if (globals.opcodeBudget < 300) { + increaseOpcodeBudget(); + } + if (poolSet[i].id === 0) { + continue; + } + isNewStakerToProtocol = false; + if (poolSet[i].id === validatorId) { + // staker isn't new to this validator - but might still be out of room in this slot. + isNewStakerToValidator = false; + if ( + this.validatorList(validatorId).value.pools[poolSet[i].poolId - 1].totalAlgoStaked + + amountToStake <= + maxPerPool + ) { + return [poolSet[i], isNewStakerToValidator, isNewStakerToProtocol]; + } + } + } + } + + // No existing stake found or that we fit in to, so ensure the stake meets the 'minimum entry' amount + assert( + amountToStake >= this.validatorList(validatorId).value.config.minEntryStake, + 'must stake at least the minimum for this pool' + ); + + // Walk their desired validators pools and find free space + const pools = clone(this.validatorList(validatorId).value.pools); + const curNumPools = this.validatorList(validatorId).value.state.numPools as uint64; + for (let i = 0; i < curNumPools; i += 1) { + if (pools[i].totalAlgoStaked + amountToStake <= maxPerPool) { + return [ + { id: validatorId, poolId: i + 1, poolAppId: pools[i].poolAppId }, + isNewStakerToValidator, + isNewStakerToProtocol, + ]; + } + } + // Not found is poolId 0 + return [{ id: validatorId, poolId: 0, poolAppId: 0 }, isNewStakerToValidator, isNewStakerToProtocol]; + } + + /** + * Find the specified pool (in any node number) and move it to the specified node. + * The pool account is forced offline if moved so prior node will still run for 320 rounds but + * new key goes online on new node soon after (320 rounds after it goes online) + * No-op if success, asserts if not found or can't move (no space in target) + * [ ONLY OWNER OR MANAGER CAN CHANGE ] + * Only callable by owner or manager + */ + movePoolToNode(validatorId: ValidatorIdType, poolAppId: uint64, nodeNum: uint64): void { + // Must be called by the owner or manager of the validator. + assert( + this.txn.sender === this.validatorList(validatorId).value.config.owner || + this.txn.sender === this.validatorList(validatorId).value.config.manager + ); + + const nodePoolAssignments = clone(this.validatorList(validatorId).value.nodePoolAssignments); + assert(nodeNum >= 1 && nodeNum <= MAX_NODES); + // iterate all the poolAppIds slots to find the specified poolAppId + for (let srcNodeIdx = 0; srcNodeIdx < MAX_NODES; srcNodeIdx += 1) { + for (let i = 0; i < MAX_POOLS_PER_NODE; i += 1) { + if (nodePoolAssignments.nodes[srcNodeIdx].poolAppIds[i] === poolAppId) { + assert(nodeNum - 1 !== srcNodeIdx, "can't move to same node"); + // found it - clear this slot + this.validatorList(validatorId).value.nodePoolAssignments.nodes[srcNodeIdx].poolAppIds[i] = 0; + + // Force that pool offline since it's moving nodes ! + sendMethodCall({ + applicationID: AppID.fromUint64(poolAppId), + }); + + // now - add it to desired node + this.addPoolToNode(validatorId, poolAppId, nodeNum); + return; + } + } + } + throw Error("couldn't find pool app id in nodes to move"); + } + + // ====== + // EVENTS - logged for notable changes + // ====== + + /** + * Logs the addition of a new validator to the system, its initial owner and manager + */ + // retiOP_addedValidator = new EventLogger<{ + // // Assigned Validator ID + // id: uint64; + // // Owner account + // owner: Address; + // // Manager account + // manager: Address; + // }>(); + // + // /** + // * Logs the addition of a new pool to a particular validator ID + // */ + // retiOP_validatorAddedPool = new EventLogger<{ + // // Validator ID + // id: uint64; + // // Pool number + // num: uint16; + // // Pool application ID + // poolAppId: AppID; + // }>(); + // + // /** + // * Logs how much stake was added by a staker to a particular staking pool + // */ + // retiOP_stakeAdded = new EventLogger<{ + // // Validator ID staker staked with + // id: uint64; + // // Pool number stake went to + // poolNum: uint16; + // // Pool application ID + // poolAppId: AppID; + // // Staker account + // staker: Address; + // // Amount staked + // amountStaked: uint64; + // }>(); + // + // /** + // * Logs how much algo was detected as being added to a staking pool as part of epoch reward calculations. + // * If the validator pays out reward tokens, the amount of tokens held back are logged as well. + // */ + // retiOP_epochRewardUpdate = new EventLogger<{ + // // Validator ID + // id: uint64; + // // Pool number rewards were accounted for + // poolNum: uint16; + // // Pool application ID + // poolAppId: AppID; + // // Algo amount added + // algoAdded: uint64; + // // Reward token amount held back for future payout + // rewardTokenHeldBack: uint64; + // }>(); + // + // /** + // * Logs how much stake was removed by a staker from a particular staking pool + // */ + // retiOP_stakeRemoved = new EventLogger<{ + // // Validator ID staker staked with + // id: uint64; + // // Pool number stake was removed from + // poolNum: uint16; + // // Pool application ID + // poolAppId: AppID; + // // Staker account + // staker: Address; + // // Amount of stake removed + // amountUnstaked: uint64; + // // Number of reward tokens also received + // rewardTokensReceived: uint64; + // // Reward token (if applicable) asset id + // rewardTokenAssetId: AssetID; + // }>(); + + // ====== + // PRIVATE CONTRACT METHODS + // Callable only internally + // ====== + /** + * verifyPoolKeyCaller verifies the passed in key (from a staking pool calling us to update metrics) is valid + * and matches the information we have in our state. 'Fake' pools could call us to update our data, but they + * can't fake the ids and most importantly application id(!) of the caller that has to match. + */ + private verifyPoolKeyCaller(poolKey: ValidatorPoolKey): void { + assert(this.validatorList(poolKey.id).exists); + assert((poolKey.poolId as uint64) < 2 ** 16); // since we limit max pools but keep the interface broad + assert(poolKey.poolId > 0 && (poolKey.poolId as uint16) <= this.validatorList(poolKey.id).value.state.numPools); + // validator id, pool id, pool app id might still be kind of spoofed, but they can't spoof us verifying they called us from + // the contract address of the pool app id they represent. + assert( + poolKey.poolAppId === this.validatorList(poolKey.id).value.pools[poolKey.poolId - 1].poolAppId, + "The passed in app id doesn't match the passed in ids" + ); + // Sender has to match the pool app id passed in as well. + assert(this.txn.sender === AppID.fromUint64(poolKey.poolAppId).address); + // verify the state of the specified app (the staking pool itself) state matches as well ! + assert(poolKey.id === (AppID.fromUint64(poolKey.poolAppId).globalState('validatorId') as uint64)); + assert(poolKey.poolId === (AppID.fromUint64(poolKey.poolAppId).globalState('poolId') as uint64)); + } + + /** + * This method verifies the ownership of NFD (Named Function Data) by a validator. + * If the ownership is no longer valid, it removes the NFD from the validator's configuration. + * + * @param {ValidatorIdType} validatorId - The id of the validator whose data should be re-evaluated. + */ + private reverifyNFDOwnership(validatorId: ValidatorIdType): void { + const validatorConfig = this.validatorList(validatorId).value.config; + if (validatorConfig.nfdForInfo !== 0) { + // We already verified the nfd id and name were correct at creation time - so we don't need to verify + // the nfd is real anymore, just that its still owned by the validator. + const nfdOwner = AppID.fromUint64(validatorConfig.nfdForInfo).globalState('i.owner.a') as Address; + // If they no longer own the nfd - remove it (!) from the validator config + if (validatorConfig.owner !== nfdOwner && validatorConfig.manager !== nfdOwner) { + // Remove the NFD from this validator ! + this.validatorList(validatorId).value.config.nfdForInfo = 0; + } + } + } + + private validateConfig(config: ValidatorConfig): void { + // Verify all the values in the ValidatorConfig are correct + assert(config.entryGatingType >= GATING_TYPE_NONE && config.entryGatingType <= GATING_TYPE_CONST_MAX); + assert(config.payoutEveryXMins >= MIN_PAYOUT_MINS && config.payoutEveryXMins <= MAX_PAYOUT_MINS); + assert(config.percentToValidator >= MIN_PCT_TO_VALIDATOR && config.percentToValidator <= MAX_PCT_TO_VALIDATOR); + if (config.percentToValidator !== 0) { + assert( + config.validatorCommissionAddress !== Address.zeroAddress, + 'validatorCommissionAddress must be set if percent to validator is not 0' + ); + } + assert(config.minEntryStake >= MIN_ALGO_STAKE_PER_POOL); + // we don't care about maxAlgoPerPool - if set to 0 it floats w/ network incentive values: maxAlgoAllowedPerPool() + assert(config.poolsPerNode > 0 && config.poolsPerNode <= MAX_POOLS_PER_NODE); + } + + /** + * Adds a stakers amount of algo to a validator pool, transferring the algo we received from them (already verified + * by our caller) to the staking pool account, and then telling it about the amount being added for the specified + * staker. + * + * @param {PayTxn} stakedAmountPayment - payment coming from staker to place into a pool + * @param {ValidatorPoolKey} poolKey - The key of the validator pool. + * @param {uint64} mbrAmtPaid - Amount the user is leaving behind in the validator to pay for their staker MBR cost + * @param {boolean} isNewStakerToValidator - if this is a new, first-time staker to the validator + * @param {boolean} isNewStakerToProtocol - if this is a new, first-time staker to the protocol + */ + private callPoolAddStake( + stakedAmountPayment: PayTxn, + poolKey: ValidatorPoolKey, + mbrAmtPaid: uint64, + isNewStakerToValidator: boolean, + isNewStakerToProtocol: boolean + ): void { + if (globals.opcodeBudget < 500) { + increaseOpcodeBudget(); + } + const poolAppId = this.validatorList(poolKey.id).value.pools[poolKey.poolId - 1].poolAppId; + + // forward the payment on to the pool via 2 txns + // payment + 'add stake' call + sendMethodCall({ + applicationID: AppID.fromUint64(poolAppId), + methodArgs: [ + // ======= + // THIS IS A SEND of the amount received right back out and into the staking pool contract account. + { amount: stakedAmountPayment.amount - mbrAmtPaid, receiver: AppID.fromUint64(poolAppId).address }, + // ======= + stakedAmountPayment.sender, + ], + }); + + // Stake has been added to the pool - get its new totals and add to our own tracking data + const poolNumStakers = AppID.fromUint64(poolAppId).globalState('numStakers') as uint64; + const poolAlgoStaked = AppID.fromUint64(poolAppId).globalState('staked') as uint64; + this.validatorList(poolKey.id).value.pools[poolKey.poolId - 1].totalStakers = poolNumStakers as uint16; + this.validatorList(poolKey.id).value.pools[poolKey.poolId - 1].totalAlgoStaked = poolAlgoStaked; + + // now update our validator and global totals + if (isNewStakerToValidator) { + this.validatorList(poolKey.id).value.state.totalStakers += 1; + } + if (isNewStakerToProtocol) { + this.numStakers.value += 1; + } + this.validatorList(poolKey.id).value.state.totalAlgoStaked += stakedAmountPayment.amount - mbrAmtPaid; + this.totalAlgoStaked.value += stakedAmountPayment.amount - mbrAmtPaid; + } + + private updateStakerPoolSet(staker: Address, poolKey: ValidatorPoolKey) { + assert(this.stakerPoolSet(staker).exists); + + const poolSet = clone(this.stakerPoolSet(staker).value); + for (let i = 0; i < this.stakerPoolSet(staker).value.length; i += 1) { + if (poolSet[i] === poolKey) { + // already in pool set + return; + } + if (poolSet[i].id === 0) { + this.stakerPoolSet(staker).value[i] = poolKey; + return; + } + } + throw Error('No empty slot available in the staker pool set'); + } + + /** + * Removes a pool key from the staker's active pool set - fails if not found (!) + * + * @param {Address} staker - The address of the staker. + * @param {ValidatorPoolKey} poolKey - The pool key they should be stored in + * + * @return [boolean, boolean] [is the staker gone from ALL pools of the given VALIDATOR, and is staker gone from ALL pools] + */ + private removeFromStakerPoolSet(staker: Address, poolKey: ValidatorPoolKey): [boolean, boolean] { + // track how many pools staker is in, so we can know if they remove all stake from all pools of this validator + let inSameValidatorPoolCount = 0; + let inAnyPoolCount = 0; + let found = false; + + const poolSet = clone(this.stakerPoolSet(staker).value); + for (let i = 0; i < this.stakerPoolSet(staker).value.length; i += 1) { + if (poolSet[i].id === 0) { + continue; + } + inAnyPoolCount += 1; + if (poolSet[i].id === poolKey.id) { + if (poolSet[i] === poolKey) { + found = true; + // 'zero' it out + this.stakerPoolSet(staker).value[i] = { id: 0, poolId: 0, poolAppId: 0 }; + } else { + inSameValidatorPoolCount += 1; + } + } + } + if (!found) { + throw Error('No matching slot found when told to remove a pool from the stakers set'); + } + // Are they completely out of the staking pool ? + return [inSameValidatorPoolCount === 0, inAnyPoolCount === 0]; + } + + private addPoolToNode(validatorId: ValidatorIdType, poolAppId: uint64, nodeNum: uint64) { + const nodePoolAssignments = clone(this.validatorList(validatorId).value.nodePoolAssignments); + const maxPoolsPerNodeForThisValidator = this.validatorList(validatorId).value.config.poolsPerNode as uint64; + // add the new staking pool to the specified node number - if there is room + assert(nodeNum >= 1 && nodeNum <= MAX_NODES); + // iterate all the poolAppIds slots to see if any are free (appid of 0) + for (let i = 0; i < maxPoolsPerNodeForThisValidator; i += 1) { + if (nodePoolAssignments.nodes[nodeNum - 1].poolAppIds[i] === 0) { + // update box data + this.validatorList(validatorId).value.nodePoolAssignments.nodes[nodeNum - 1].poolAppIds[i] = poolAppId; + return; + } + } + throw Error('no available space in specified node for this pool'); + } + + /** + * Checks if a staker meets the gating requirements specified by the validator. + * + * @param {ValidatorIdType} validatorId - The id of the validator. + * @param {uint64} valueToVerify - The value to verify against the gating requirements. + * @returns {void} or asserts if requirements not met. + */ + private doesStakerMeetGating(validatorId: ValidatorIdType, valueToVerify: uint64): void { + const type = this.validatorList(validatorId).value.config.entryGatingType; + if (type === GATING_TYPE_NONE) { + return; + } + const staker = this.txn.sender; + const gateReq = clone(this.validatorList(validatorId).value.config.entryGatingValue); + + // If an asset gating - check the balance requirement - can handle whether right asset afterward + if ( + type === GATING_TYPE_ASSETS_CREATED_BY || + type === GATING_TYPE_ASSET_ID || + type === GATING_TYPE_CREATED_BY_NFD_ADDRESSES + ) { + assert(valueToVerify !== 0); + let balRequired = this.validatorList(validatorId).value.config.gatingAssetMinBalance; + if (balRequired === 0) { + balRequired = 1; + } + assert( + staker.assetBalance(AssetID.fromUint64(valueToVerify)) >= balRequired, + 'must have required minimum balance of validator defined token to add stake' + ); + } + if (type === GATING_TYPE_ASSETS_CREATED_BY) { + assert( + AssetID.fromUint64(valueToVerify).creator === Address.fromBytes(gateReq), + 'specified asset must be created by creator that the validator defined as a requirement to stake' + ); + } + if (type === GATING_TYPE_ASSET_ID) { + const requiredAsset = extractUint64(gateReq, 0); + assert(requiredAsset !== 0); + assert( + valueToVerify === requiredAsset, + 'specified asset must be identical to the asset id defined as a requirement to stake' + ); + } + if (type === GATING_TYPE_CREATED_BY_NFD_ADDRESSES) { + const nfdForInfo = this.validatorList(validatorId).value.config.nfdForInfo; + // Walk all the linked addresses defined by this NFD (stored packed in v.caAlgo.0.as as a 'set' of 32-byte PKs) + // if any are the creator of the specified asset then we pass. + assert( + this.isAddressInNFDCAAlgoList(nfdForInfo, AssetID.fromUint64(valueToVerify).creator), + 'specified asset must be created by creator that is one of the linked addresses in an nfd' + ); + } + if (type === GATING_TYPE_SEGMENT_OF_NFD) { + // verify NFD user wants to offer up for testing is at least 'real' - since we just have app id - fetch its name then do is valid call + const userOfferedNFDAppID = valueToVerify; + assert(this.isNFDAppIDValid(userOfferedNFDAppID), 'provided NFD must be valid'); + + // now see if specified NFD's owner, or any of its caAlgo fields matches the staker's address + assert( + rawBytes(AppID.fromUint64(userOfferedNFDAppID).globalState('i.owner.a') as Address) === + rawBytes(staker) || this.isAddressInNFDCAAlgoList(userOfferedNFDAppID, staker), + "provided nfd for entry isn't owned or linked to the staker" + ); + + // We at least know it's a real NFD - now.. is it a segment of the root NFD the validator defined ? + const requiredParentAppID = extractUint64(gateReq, 0); + + assert( + (AppID.fromUint64(userOfferedNFDAppID).globalState('i.parentAppID') as uint64) === requiredParentAppID, + 'specified nfd must be a segment of the nfd the validator specified as a requirement' + ); + } + } + + /** + * Checks if the given NFD App id is valid. Using only the App id there's no validation against the name (ie: that nfd X is name Y) + * So it's assumed for the caller, the app id alone is fine. The name is fetched from the specified app id and the two + * together are used for validity check call to the nfd registry. + * + * @param {uint64} nfdAppID - The NFD App id to verify. + * + * @returns {boolean} - Returns true if the NFD App id is valid, otherwise false. + */ + private isNFDAppIDValid(nfdAppID: uint64): boolean { + // verify NFD user wants to offer up for testing is at least 'real' - since we just have app id - fetch its name then do is valid call + const userOfferedNFDName = AppID.fromUint64(nfdAppID).globalState('i.name') as string; + + sendAppCall({ + applicationID: AppID.fromUint64(this.nfdRegistryAppId), + applicationArgs: ['is_valid_nfd_appid', userOfferedNFDName, itob(nfdAppID)], + applications: [AppID.fromUint64(nfdAppID)], + }); + return btoi(this.itxn.lastLog) === 1; + } + + /** + * Checks if the specified address is present in an NFDs list of verified addresses. + * The NFD is assumed to have already been validated as official. + * + * @param {uint64} nfdAppID - The NFD application id. + * @param {Address} addrToFind - The address to find in the v.caAlgo.0.as property + * @return {boolean} - `true` if the address is present, `false` otherwise. + */ + private isAddressInNFDCAAlgoList(nfdAppID: uint64, addrToFind: Address): boolean { + sendAppCall({ + applicationID: AppID.fromUint64(nfdAppID), + applicationArgs: ['read_property', 'v.caAlgo.0.as'], + }); + const caAlgoData = this.itxn.lastLog; + for (let i = 0; i < caAlgoData.length; i += 32) { + const addr = extract3(caAlgoData, i, 32); + if (addr !== rawBytes(globals.zeroAddress) && addr === rawBytes(addrToFind)) { + return true; + } + } + return false; + } + + /** + * Returns the MAXIMUM allowed stake per pool and still receive incentives - we'll treat this as the 'max per pool' + */ + private maxAlgoAllowedPerPool(): uint64 { + // TODO replace w/ appropriate AVM call once available + return 70_000_000_000_000; // 70m ALGO in microAlgo + } + + /** + * Returns the maximum allowed stake per validator based on a percentage of all current online stake before + * the validator is considered saturated - where rewards are diminished. + * NOTE: this function is defined twice - here and in staking pool contract. Both must be identical. + */ + private algoSaturationLevel(): uint64 { + const online = this.getCurrentOnlineStake(); + + return wideRatio([online, MAX_VALIDATOR_SOFT_PCT_OF_ONLINE_1DECIMAL], [1000]); + } + + /** + * Returns the MAXIMUM allowed stake per validator based on a percentage of all current online stake. + * Adding stake is completely blocked at this amount. + */ + private maxAllowedStake(): uint64 { + const online = this.getCurrentOnlineStake(); + + return wideRatio([online, MAX_VALIDATOR_HARD_PCT_OF_ONLINE_1DECIMAL], [1000]); + } + + private getCurrentOnlineStake(): uint64 { + // TODO - replace w/ appropriate AVM call once available but return fixed 2 billion for now. + return 2_000_000_000_000_000; + } + + private minBalanceForAccount( + contracts: uint64, + extraPages: uint64, + assets: uint64, + localInts: uint64, + localBytes: uint64, + globalInts: uint64, + globalBytes: uint64 + ): uint64 { + let minBal = ALGORAND_ACCOUNT_MIN_BALANCE; + minBal += contracts * APPLICATION_BASE_FEE; + minBal += extraPages * APPLICATION_BASE_FEE; + minBal += assets * ASSET_HOLDING_FEE; + minBal += localInts * SSC_VALUE_UINT; + minBal += globalInts * SSC_VALUE_UINT; + minBal += localBytes * SSC_VALUE_BYTES; + minBal += globalBytes * SSC_VALUE_BYTES; + return minBal; + } + + private costForBoxStorage(totalNumBytes: uint64): uint64 { + const SCBOX_PERBOX = 2500; + const SCBOX_PERBYTE = 400; + + return SCBOX_PERBOX + totalNumBytes * SCBOX_PERBYTE; + } +} diff --git a/contracts/jest.config.js b/contracts/jest.config.js new file mode 100644 index 00000000..6f5ef4eb --- /dev/null +++ b/contracts/jest.config.js @@ -0,0 +1,6 @@ +/** @type {import('ts-jest').JestConfigWithTsJest} */ +module.exports = { + preset: 'ts-jest', + testEnvironment: 'node', + testTimeout: 60000 +}; diff --git a/contracts/package.json b/contracts/package.json new file mode 100644 index 00000000..932619e2 --- /dev/null +++ b/contracts/package.json @@ -0,0 +1,38 @@ +{ + "name": "ValidatorRegistry", + "version": "0.1.0", + "license": "MIT", + "scripts": { + "generate-client": "algokit generate client contracts/artifacts/ --language typescript --output contracts/clients/{contract_name}Client.ts && ./update_contract_artifacts.sh``", + "compile-contract": "tealscript contracts/*.algo.ts contracts/artifacts", + "generate-components": "algokit-generate-component contracts/artifacts/validatorRegistry.arc32.json contracts/artifacts/components", + "noalgobuild": "pnpm run compile-contract -- --skip-algod && pnpm run generate-client", + "build": "pnpm run compile-contract && pnpm run generate-client", + "test": "pnpm run build && jest", + "retest": "jest", + "lint": "eslint . --ext .ts", + "fix": "eslint . --ext .ts --fix" + }, + "dependencies": { + "@algorandfoundation/algokit-utils": "^5.8.0", + "algosdk": "^2.7.0" + }, + "devDependencies": { + "@algorandfoundation/algokit-client-generator": "^3.0.1", + "@algorandfoundation/tealscript": "^0.88.1", + "@jest/globals": "^29.7.0", + "@joe-p/algokit-generate-component": "^0.2.1", + "@typescript-eslint/eslint-plugin": "^5.62.0", + "@typescript-eslint/parser": "^5.62.0", + "eslint": "^8.57.0", + "eslint-config-airbnb-base": "^15.0.0", + "eslint-config-airbnb-typescript": "^17.1.0", + "eslint-config-prettier": "^9.1.0", + "eslint-plugin-import": "^2.29.1", + "eslint-plugin-prettier": "^5.1.3", + "jest": "^29.7.0", + "prettier": "^3.2.5", + "ts-jest": "^29.1.2", + "typescript": "^5.4.3" + } +} diff --git a/contracts/pnpm-lock.yaml b/contracts/pnpm-lock.yaml new file mode 100644 index 00000000..fc126834 --- /dev/null +++ b/contracts/pnpm-lock.yaml @@ -0,0 +1,4383 @@ +lockfileVersion: '6.0' + +settings: + autoInstallPeers: true + excludeLinksFromLockfile: false + +dependencies: + '@algorandfoundation/algokit-utils': + specifier: ^5.8.0 + version: 5.8.0(algosdk@2.7.0) + algosdk: + specifier: ^2.7.0 + version: 2.7.0 + +devDependencies: + '@algorandfoundation/algokit-client-generator': + specifier: ^3.0.1 + version: 3.0.1 + '@algorandfoundation/tealscript': + specifier: ^0.88.1 + version: 0.88.1 + '@jest/globals': + specifier: ^29.7.0 + version: 29.7.0 + '@joe-p/algokit-generate-component': + specifier: ^0.2.1 + version: 0.2.1 + '@typescript-eslint/eslint-plugin': + specifier: ^5.62.0 + version: 5.62.0(@typescript-eslint/parser@5.62.0)(eslint@8.57.0)(typescript@5.4.3) + '@typescript-eslint/parser': + specifier: ^5.62.0 + version: 5.62.0(eslint@8.57.0)(typescript@5.4.3) + eslint: + specifier: ^8.57.0 + version: 8.57.0 + eslint-config-airbnb-base: + specifier: ^15.0.0 + version: 15.0.0(eslint-plugin-import@2.29.1)(eslint@8.57.0) + eslint-config-airbnb-typescript: + specifier: ^17.1.0 + version: 17.1.0(@typescript-eslint/eslint-plugin@5.62.0)(@typescript-eslint/parser@5.62.0)(eslint-plugin-import@2.29.1)(eslint@8.57.0) + eslint-config-prettier: + specifier: ^9.1.0 + version: 9.1.0(eslint@8.57.0) + eslint-plugin-import: + specifier: ^2.29.1 + version: 2.29.1(@typescript-eslint/parser@5.62.0)(eslint@8.57.0) + eslint-plugin-prettier: + specifier: ^5.1.3 + version: 5.1.3(eslint-config-prettier@9.1.0)(eslint@8.57.0)(prettier@3.2.5) + jest: + specifier: ^29.7.0 + version: 29.7.0 + prettier: + specifier: ^3.2.5 + version: 3.2.5 + ts-jest: + specifier: ^29.1.2 + version: 29.1.2(@babel/core@7.24.3)(jest@29.7.0)(typescript@5.4.3) + typescript: + specifier: ^5.4.3 + version: 5.4.3 + +packages: + + /@aashutoshrathi/word-wrap@1.2.6: + resolution: {integrity: sha512-1Yjs2SvM8TflER/OD3cOjhWWOZb58A2t7wpE2S9XfBYTiIl+XFhQG2bjy4Pu1I+EAlCNUzRDYDdFwFYUKvXcIA==} + engines: {node: '>=0.10.0'} + dev: true + + /@algorandfoundation/algokit-client-generator@3.0.1: + resolution: {integrity: sha512-9k4pJRvU4KI0YAYOSvWYyRdQxpPkTPQDSYOCZyxaMwosznZDzRAiHJ7c7fXBixL52cYOBq6FDl4CeOlnYf1NyQ==} + engines: {node: '>=19.0'} + hasBin: true + dependencies: + '@algorandfoundation/algokit-utils': 5.8.0(algosdk@2.7.0) + algosdk: 2.7.0 + chalk: 4.1.2 + change-case: 4.1.2 + commander: 11.1.0 + jsonschema: 1.4.1 + dev: true + + /@algorandfoundation/algokit-utils@5.8.0(algosdk@2.7.0): + resolution: {integrity: sha512-BxwUBQ0BaAPpOZt7e2kwP0pfvG2W2AqOBBI6Y3AbJ01a9P7yJ1wIaJfqG02aiG4mpKbLgz84WBQij+0DqGK80Q==} + engines: {node: '>=18.0'} + peerDependencies: + algosdk: ^2.7.0 + dependencies: + algosdk: 2.7.0 + buffer: 6.0.3 + + /@algorandfoundation/tealscript@0.88.1: + resolution: {integrity: sha512-n2au2w8auvit70Teb4Enxr8eTG0FBcCnZqUXdAdt7y+Ex3mRiQQq/3dkI7Dy9UlvIzFqNzb/9RlaJZKG9ElmFw==} + hasBin: true + dependencies: + '@microsoft/tsdoc': 0.14.2 + '@playwright/test': 1.42.1 + argparse: 2.0.1 + dotenv: 16.4.5 + glob: 10.3.12 + js-sha512: 0.8.0 + node-fetch: 2.7.0 + polytype: 0.17.0 + source-map: 0.7.4 + ts-morph: 20.0.0 + typescript: 4.9.5 + vlq: 2.0.4 + transitivePeerDependencies: + - encoding + dev: true + + /@ampproject/remapping@2.3.0: + resolution: {integrity: sha512-30iZtAPgz+LTIYoeivqYo853f02jBYSd5uGnGpkFV0M3xOt9aN73erkgYAmZU43x4VfqcnLxW9Kpg3R5LC4YYw==} + engines: {node: '>=6.0.0'} + dependencies: + '@jridgewell/gen-mapping': 0.3.5 + '@jridgewell/trace-mapping': 0.3.25 + dev: true + + /@babel/code-frame@7.24.2: + resolution: {integrity: sha512-y5+tLQyV8pg3fsiln67BVLD1P13Eg4lh5RW9mF0zUuvLrv9uIQ4MCL+CRT+FTsBlBjcIan6PGsLcBN0m3ClUyQ==} + engines: {node: '>=6.9.0'} + dependencies: + '@babel/highlight': 7.24.2 + picocolors: 1.0.0 + dev: true + + /@babel/compat-data@7.24.1: + resolution: {integrity: sha512-Pc65opHDliVpRHuKfzI+gSA4zcgr65O4cl64fFJIWEEh8JoHIHh0Oez1Eo8Arz8zq/JhgKodQaxEwUPRtZylVA==} + engines: {node: '>=6.9.0'} + dev: true + + /@babel/core@7.24.3: + resolution: {integrity: sha512-5FcvN1JHw2sHJChotgx8Ek0lyuh4kCKelgMTTqhYJJtloNvUfpAFMeNQUtdlIaktwrSV9LtCdqwk48wL2wBacQ==} + engines: {node: '>=6.9.0'} + dependencies: + '@ampproject/remapping': 2.3.0 + '@babel/code-frame': 7.24.2 + '@babel/generator': 7.24.1 + '@babel/helper-compilation-targets': 7.23.6 + '@babel/helper-module-transforms': 7.23.3(@babel/core@7.24.3) + '@babel/helpers': 7.24.1 + '@babel/parser': 7.24.1 + '@babel/template': 7.24.0 + '@babel/traverse': 7.24.1 + '@babel/types': 7.24.0 + convert-source-map: 2.0.0 + debug: 4.3.4 + gensync: 1.0.0-beta.2 + json5: 2.2.3 + semver: 6.3.1 + transitivePeerDependencies: + - supports-color + dev: true + + /@babel/generator@7.24.1: + resolution: {integrity: sha512-DfCRfZsBcrPEHUfuBMgbJ1Ut01Y/itOs+hY2nFLgqsqXd52/iSiVq5TITtUasIUgm+IIKdY2/1I7auiQOEeC9A==} + engines: {node: '>=6.9.0'} + dependencies: + '@babel/types': 7.24.0 + '@jridgewell/gen-mapping': 0.3.5 + '@jridgewell/trace-mapping': 0.3.25 + jsesc: 2.5.2 + dev: true + + /@babel/helper-compilation-targets@7.23.6: + resolution: {integrity: sha512-9JB548GZoQVmzrFgp8o7KxdgkTGm6xs9DW0o/Pim72UDjzr5ObUQ6ZzYPqA+g9OTS2bBQoctLJrky0RDCAWRgQ==} + engines: {node: '>=6.9.0'} + dependencies: + '@babel/compat-data': 7.24.1 + '@babel/helper-validator-option': 7.23.5 + browserslist: 4.23.0 + lru-cache: 5.1.1 + semver: 6.3.1 + dev: true + + /@babel/helper-environment-visitor@7.22.20: + resolution: {integrity: sha512-zfedSIzFhat/gFhWfHtgWvlec0nqB9YEIVrpuwjruLlXfUSnA8cJB0miHKwqDnQ7d32aKo2xt88/xZptwxbfhA==} + engines: {node: '>=6.9.0'} + dev: true + + /@babel/helper-function-name@7.23.0: + resolution: {integrity: sha512-OErEqsrxjZTJciZ4Oo+eoZqeW9UIiOcuYKRJA4ZAgV9myA+pOXhhmpfNCKjEH/auVfEYVFJ6y1Tc4r0eIApqiw==} + engines: {node: '>=6.9.0'} + dependencies: + '@babel/template': 7.24.0 + '@babel/types': 7.24.0 + dev: true + + /@babel/helper-hoist-variables@7.22.5: + resolution: {integrity: sha512-wGjk9QZVzvknA6yKIUURb8zY3grXCcOZt+/7Wcy8O2uctxhplmUPkOdlgoNhmdVee2c92JXbf1xpMtVNbfoxRw==} + engines: {node: '>=6.9.0'} + dependencies: + '@babel/types': 7.24.0 + dev: true + + /@babel/helper-module-imports@7.24.3: + resolution: {integrity: sha512-viKb0F9f2s0BCS22QSF308z/+1YWKV/76mwt61NBzS5izMzDPwdq1pTrzf+Li3npBWX9KdQbkeCt1jSAM7lZqg==} + engines: {node: '>=6.9.0'} + dependencies: + '@babel/types': 7.24.0 + dev: true + + /@babel/helper-module-transforms@7.23.3(@babel/core@7.24.3): + resolution: {integrity: sha512-7bBs4ED9OmswdfDzpz4MpWgSrV7FXlc3zIagvLFjS5H+Mk7Snr21vQ6QwrsoCGMfNC4e4LQPdoULEt4ykz0SRQ==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0 + dependencies: + '@babel/core': 7.24.3 + '@babel/helper-environment-visitor': 7.22.20 + '@babel/helper-module-imports': 7.24.3 + '@babel/helper-simple-access': 7.22.5 + '@babel/helper-split-export-declaration': 7.22.6 + '@babel/helper-validator-identifier': 7.22.20 + dev: true + + /@babel/helper-plugin-utils@7.24.0: + resolution: {integrity: sha512-9cUznXMG0+FxRuJfvL82QlTqIzhVW9sL0KjMPHhAOOvpQGL8QtdxnBKILjBqxlHyliz0yCa1G903ZXI/FuHy2w==} + engines: {node: '>=6.9.0'} + dev: true + + /@babel/helper-simple-access@7.22.5: + resolution: {integrity: sha512-n0H99E/K+Bika3++WNL17POvo4rKWZ7lZEp1Q+fStVbUi8nxPQEBOlTmCOxW/0JsS56SKKQ+ojAe2pHKJHN35w==} + engines: {node: '>=6.9.0'} + dependencies: + '@babel/types': 7.24.0 + dev: true + + /@babel/helper-split-export-declaration@7.22.6: + resolution: {integrity: sha512-AsUnxuLhRYsisFiaJwvp1QF+I3KjD5FOxut14q/GzovUe6orHLesW2C7d754kRm53h5gqrz6sFl6sxc4BVtE/g==} + engines: {node: '>=6.9.0'} + dependencies: + '@babel/types': 7.24.0 + dev: true + + /@babel/helper-string-parser@7.24.1: + resolution: {integrity: sha512-2ofRCjnnA9y+wk8b9IAREroeUP02KHp431N2mhKniy2yKIDKpbrHv9eXwm8cBeWQYcJmzv5qKCu65P47eCF7CQ==} + engines: {node: '>=6.9.0'} + dev: true + + /@babel/helper-validator-identifier@7.22.20: + resolution: {integrity: sha512-Y4OZ+ytlatR8AI+8KZfKuL5urKp7qey08ha31L8b3BwewJAoJamTzyvxPR/5D+KkdJCGPq/+8TukHBlY10FX9A==} + engines: {node: '>=6.9.0'} + dev: true + + /@babel/helper-validator-option@7.23.5: + resolution: {integrity: sha512-85ttAOMLsr53VgXkTbkx8oA6YTfT4q7/HzXSLEYmjcSTJPMPQtvq1BD79Byep5xMUYbGRzEpDsjUf3dyp54IKw==} + engines: {node: '>=6.9.0'} + dev: true + + /@babel/helpers@7.24.1: + resolution: {integrity: sha512-BpU09QqEe6ZCHuIHFphEFgvNSrubve1FtyMton26ekZ85gRGi6LrTF7zArARp2YvyFxloeiRmtSCq5sjh1WqIg==} + engines: {node: '>=6.9.0'} + dependencies: + '@babel/template': 7.24.0 + '@babel/traverse': 7.24.1 + '@babel/types': 7.24.0 + transitivePeerDependencies: + - supports-color + dev: true + + /@babel/highlight@7.24.2: + resolution: {integrity: sha512-Yac1ao4flkTxTteCDZLEvdxg2fZfz1v8M4QpaGypq/WPDqg3ijHYbDfs+LG5hvzSoqaSZ9/Z9lKSP3CjZjv+pA==} + engines: {node: '>=6.9.0'} + dependencies: + '@babel/helper-validator-identifier': 7.22.20 + chalk: 2.4.2 + js-tokens: 4.0.0 + picocolors: 1.0.0 + dev: true + + /@babel/parser@7.24.1: + resolution: {integrity: sha512-Zo9c7N3xdOIQrNip7Lc9wvRPzlRtovHVE4lkz8WEDr7uYh/GMQhSiIgFxGIArRHYdJE5kxtZjAf8rT0xhdLCzg==} + engines: {node: '>=6.0.0'} + hasBin: true + dependencies: + '@babel/types': 7.24.0 + dev: true + + /@babel/plugin-syntax-async-generators@7.8.4(@babel/core@7.24.3): + resolution: {integrity: sha512-tycmZxkGfZaxhMRbXlPXuVFpdWlXpir2W4AMhSJgRKzk/eDlIXOhb2LHWoLpDF7TEHylV5zNhykX6KAgHJmTNw==} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.24.3 + '@babel/helper-plugin-utils': 7.24.0 + dev: true + + /@babel/plugin-syntax-bigint@7.8.3(@babel/core@7.24.3): + resolution: {integrity: sha512-wnTnFlG+YxQm3vDxpGE57Pj0srRU4sHE/mDkt1qv2YJJSeUAec2ma4WLUnUPeKjyrfntVwe/N6dCXpU+zL3Npg==} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.24.3 + '@babel/helper-plugin-utils': 7.24.0 + dev: true + + /@babel/plugin-syntax-class-properties@7.12.13(@babel/core@7.24.3): + resolution: {integrity: sha512-fm4idjKla0YahUNgFNLCB0qySdsoPiZP3iQE3rky0mBUtMZ23yDJ9SJdg6dXTSDnulOVqiF3Hgr9nbXvXTQZYA==} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.24.3 + '@babel/helper-plugin-utils': 7.24.0 + dev: true + + /@babel/plugin-syntax-import-meta@7.10.4(@babel/core@7.24.3): + resolution: {integrity: sha512-Yqfm+XDx0+Prh3VSeEQCPU81yC+JWZ2pDPFSS4ZdpfZhp4MkFMaDC1UqseovEKwSUpnIL7+vK+Clp7bfh0iD7g==} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.24.3 + '@babel/helper-plugin-utils': 7.24.0 + dev: true + + /@babel/plugin-syntax-json-strings@7.8.3(@babel/core@7.24.3): + resolution: {integrity: sha512-lY6kdGpWHvjoe2vk4WrAapEuBR69EMxZl+RoGRhrFGNYVK8mOPAW8VfbT/ZgrFbXlDNiiaxQnAtgVCZ6jv30EA==} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.24.3 + '@babel/helper-plugin-utils': 7.24.0 + dev: true + + /@babel/plugin-syntax-jsx@7.24.1(@babel/core@7.24.3): + resolution: {integrity: sha512-2eCtxZXf+kbkMIsXS4poTvT4Yu5rXiRa+9xGVT56raghjmBTKMpFNc9R4IDiB4emao9eO22Ox7CxuJG7BgExqA==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.24.3 + '@babel/helper-plugin-utils': 7.24.0 + dev: true + + /@babel/plugin-syntax-logical-assignment-operators@7.10.4(@babel/core@7.24.3): + resolution: {integrity: sha512-d8waShlpFDinQ5MtvGU9xDAOzKH47+FFoney2baFIoMr952hKOLp1HR7VszoZvOsV/4+RRszNY7D17ba0te0ig==} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.24.3 + '@babel/helper-plugin-utils': 7.24.0 + dev: true + + /@babel/plugin-syntax-nullish-coalescing-operator@7.8.3(@babel/core@7.24.3): + resolution: {integrity: sha512-aSff4zPII1u2QD7y+F8oDsz19ew4IGEJg9SVW+bqwpwtfFleiQDMdzA/R+UlWDzfnHFCxxleFT0PMIrR36XLNQ==} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.24.3 + '@babel/helper-plugin-utils': 7.24.0 + dev: true + + /@babel/plugin-syntax-numeric-separator@7.10.4(@babel/core@7.24.3): + resolution: {integrity: sha512-9H6YdfkcK/uOnY/K7/aA2xpzaAgkQn37yzWUMRK7OaPOqOpGS1+n0H5hxT9AUw9EsSjPW8SVyMJwYRtWs3X3ug==} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.24.3 + '@babel/helper-plugin-utils': 7.24.0 + dev: true + + /@babel/plugin-syntax-object-rest-spread@7.8.3(@babel/core@7.24.3): + resolution: {integrity: sha512-XoqMijGZb9y3y2XskN+P1wUGiVwWZ5JmoDRwx5+3GmEplNyVM2s2Dg8ILFQm8rWM48orGy5YpI5Bl8U1y7ydlA==} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.24.3 + '@babel/helper-plugin-utils': 7.24.0 + dev: true + + /@babel/plugin-syntax-optional-catch-binding@7.8.3(@babel/core@7.24.3): + resolution: {integrity: sha512-6VPD0Pc1lpTqw0aKoeRTMiB+kWhAoT24PA+ksWSBrFtl5SIRVpZlwN3NNPQjehA2E/91FV3RjLWoVTglWcSV3Q==} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.24.3 + '@babel/helper-plugin-utils': 7.24.0 + dev: true + + /@babel/plugin-syntax-optional-chaining@7.8.3(@babel/core@7.24.3): + resolution: {integrity: sha512-KoK9ErH1MBlCPxV0VANkXW2/dw4vlbGDrFgz8bmUsBGYkFRcbRwMh6cIJubdPrkxRwuGdtCk0v/wPTKbQgBjkg==} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.24.3 + '@babel/helper-plugin-utils': 7.24.0 + dev: true + + /@babel/plugin-syntax-top-level-await@7.14.5(@babel/core@7.24.3): + resolution: {integrity: sha512-hx++upLv5U1rgYfwe1xBQUhRmU41NEvpUvrp8jkrSCdvGSnM5/qdRMtylJ6PG5OFkBaHkbTAKTnd3/YyESRHFw==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.24.3 + '@babel/helper-plugin-utils': 7.24.0 + dev: true + + /@babel/plugin-syntax-typescript@7.24.1(@babel/core@7.24.3): + resolution: {integrity: sha512-Yhnmvy5HZEnHUty6i++gcfH1/l68AHnItFHnaCv6hn9dNh0hQvvQJsxpi4BMBFN5DLeHBuucT/0DgzXif/OyRw==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.24.3 + '@babel/helper-plugin-utils': 7.24.0 + dev: true + + /@babel/template@7.24.0: + resolution: {integrity: sha512-Bkf2q8lMB0AFpX0NFEqSbx1OkTHf0f+0j82mkw+ZpzBnkk7e9Ql0891vlfgi+kHwOk8tQjiQHpqh4LaSa0fKEA==} + engines: {node: '>=6.9.0'} + dependencies: + '@babel/code-frame': 7.24.2 + '@babel/parser': 7.24.1 + '@babel/types': 7.24.0 + dev: true + + /@babel/traverse@7.24.1: + resolution: {integrity: sha512-xuU6o9m68KeqZbQuDt2TcKSxUw/mrsvavlEqQ1leZ/B+C9tk6E4sRWy97WaXgvq5E+nU3cXMxv3WKOCanVMCmQ==} + engines: {node: '>=6.9.0'} + dependencies: + '@babel/code-frame': 7.24.2 + '@babel/generator': 7.24.1 + '@babel/helper-environment-visitor': 7.22.20 + '@babel/helper-function-name': 7.23.0 + '@babel/helper-hoist-variables': 7.22.5 + '@babel/helper-split-export-declaration': 7.22.6 + '@babel/parser': 7.24.1 + '@babel/types': 7.24.0 + debug: 4.3.4 + globals: 11.12.0 + transitivePeerDependencies: + - supports-color + dev: true + + /@babel/types@7.24.0: + resolution: {integrity: sha512-+j7a5c253RfKh8iABBhywc8NSfP5LURe7Uh4qpsh6jc+aLJguvmIUBdjSdEMQv2bENrCR5MfRdjGo7vzS/ob7w==} + engines: {node: '>=6.9.0'} + dependencies: + '@babel/helper-string-parser': 7.24.1 + '@babel/helper-validator-identifier': 7.22.20 + to-fast-properties: 2.0.0 + dev: true + + /@bcoe/v8-coverage@0.2.3: + resolution: {integrity: sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==} + dev: true + + /@eslint-community/eslint-utils@4.4.0(eslint@8.57.0): + resolution: {integrity: sha512-1/sA4dwrzBAyeUoQ6oxahHKmrZvsnLCg4RfxW3ZFGGmQkSNQPFNLV9CUEFQP1x9EYXHTo5p6xdhZM1Ne9p/AfA==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + peerDependencies: + eslint: ^6.0.0 || ^7.0.0 || >=8.0.0 + dependencies: + eslint: 8.57.0 + eslint-visitor-keys: 3.4.3 + dev: true + + /@eslint-community/regexpp@4.10.0: + resolution: {integrity: sha512-Cu96Sd2By9mCNTx2iyKOmq10v22jUVQv0lQnlGNy16oE9589yE+QADPbrMGCkA51cKZSg3Pu/aTJVTGfL/qjUA==} + engines: {node: ^12.0.0 || ^14.0.0 || >=16.0.0} + dev: true + + /@eslint/eslintrc@2.1.4: + resolution: {integrity: sha512-269Z39MS6wVJtsoUl10L60WdkhJVdPG24Q4eZTH3nnF6lpvSShEK3wQjDX9JRWAUPvPh7COouPpU9IrqaZFvtQ==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + dependencies: + ajv: 6.12.6 + debug: 4.3.4 + espree: 9.6.1 + globals: 13.24.0 + ignore: 5.3.1 + import-fresh: 3.3.0 + js-yaml: 4.1.0 + minimatch: 3.1.2 + strip-json-comments: 3.1.1 + transitivePeerDependencies: + - supports-color + dev: true + + /@eslint/js@8.57.0: + resolution: {integrity: sha512-Ys+3g2TaW7gADOJzPt83SJtCDhMjndcDMFVQ/Tj9iA1BfJzFKD9mAUXT3OenpuPHbI6P/myECxRJrofUsDx/5g==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + dev: true + + /@humanwhocodes/config-array@0.11.14: + resolution: {integrity: sha512-3T8LkOmg45BV5FICb15QQMsyUSWrQ8AygVfC7ZG32zOalnqrilm018ZVCw0eapXux8FtA33q8PSRSstjee3jSg==} + engines: {node: '>=10.10.0'} + dependencies: + '@humanwhocodes/object-schema': 2.0.3 + debug: 4.3.4 + minimatch: 3.1.2 + transitivePeerDependencies: + - supports-color + dev: true + + /@humanwhocodes/module-importer@1.0.1: + resolution: {integrity: sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==} + engines: {node: '>=12.22'} + dev: true + + /@humanwhocodes/object-schema@2.0.3: + resolution: {integrity: sha512-93zYdMES/c1D69yZiKDBj0V24vqNzB/koF26KPaagAfd3P/4gUlh3Dys5ogAK+Exi9QyzlD8x/08Zt7wIKcDcA==} + dev: true + + /@isaacs/cliui@8.0.2: + resolution: {integrity: sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==} + engines: {node: '>=12'} + dependencies: + string-width: 5.1.2 + string-width-cjs: /string-width@4.2.3 + strip-ansi: 7.1.0 + strip-ansi-cjs: /strip-ansi@6.0.1 + wrap-ansi: 8.1.0 + wrap-ansi-cjs: /wrap-ansi@7.0.0 + dev: true + + /@istanbuljs/load-nyc-config@1.1.0: + resolution: {integrity: sha512-VjeHSlIzpv/NyD3N0YuHfXOPDIixcA1q2ZV98wsMqcYlPmv2n3Yb2lYP9XMElnaFVXg5A7YLTeLu6V84uQDjmQ==} + engines: {node: '>=8'} + dependencies: + camelcase: 5.3.1 + find-up: 4.1.0 + get-package-type: 0.1.0 + js-yaml: 3.14.1 + resolve-from: 5.0.0 + dev: true + + /@istanbuljs/schema@0.1.3: + resolution: {integrity: sha512-ZXRY4jNvVgSVQ8DL3LTcakaAtXwTVUxE81hslsyD2AtoXW/wVob10HkOJ1X/pAlcI7D+2YoZKg5do8G/w6RYgA==} + engines: {node: '>=8'} + dev: true + + /@jest/console@29.7.0: + resolution: {integrity: sha512-5Ni4CU7XHQi32IJ398EEP4RrB8eV09sXP2ROqD4bksHrnTree52PsxvX8tpL8LvTZ3pFzXyPbNQReSN41CAhOg==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + dependencies: + '@jest/types': 29.6.3 + '@types/node': 20.12.2 + chalk: 4.1.2 + jest-message-util: 29.7.0 + jest-util: 29.7.0 + slash: 3.0.0 + dev: true + + /@jest/core@29.7.0: + resolution: {integrity: sha512-n7aeXWKMnGtDA48y8TLWJPJmLmmZ642Ceo78cYWEpiD7FzDgmNDV/GCVRorPABdXLJZ/9wzzgZAlHjXjxDHGsg==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + peerDependencies: + node-notifier: ^8.0.1 || ^9.0.0 || ^10.0.0 + peerDependenciesMeta: + node-notifier: + optional: true + dependencies: + '@jest/console': 29.7.0 + '@jest/reporters': 29.7.0 + '@jest/test-result': 29.7.0 + '@jest/transform': 29.7.0 + '@jest/types': 29.6.3 + '@types/node': 20.12.2 + ansi-escapes: 4.3.2 + chalk: 4.1.2 + ci-info: 3.9.0 + exit: 0.1.2 + graceful-fs: 4.2.11 + jest-changed-files: 29.7.0 + jest-config: 29.7.0(@types/node@20.12.2) + jest-haste-map: 29.7.0 + jest-message-util: 29.7.0 + jest-regex-util: 29.6.3 + jest-resolve: 29.7.0 + jest-resolve-dependencies: 29.7.0 + jest-runner: 29.7.0 + jest-runtime: 29.7.0 + jest-snapshot: 29.7.0 + jest-util: 29.7.0 + jest-validate: 29.7.0 + jest-watcher: 29.7.0 + micromatch: 4.0.5 + pretty-format: 29.7.0 + slash: 3.0.0 + strip-ansi: 6.0.1 + transitivePeerDependencies: + - babel-plugin-macros + - supports-color + - ts-node + dev: true + + /@jest/environment@29.7.0: + resolution: {integrity: sha512-aQIfHDq33ExsN4jP1NWGXhxgQ/wixs60gDiKO+XVMd8Mn0NWPWgc34ZQDTb2jKaUWQ7MuwoitXAsN2XVXNMpAw==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + dependencies: + '@jest/fake-timers': 29.7.0 + '@jest/types': 29.6.3 + '@types/node': 20.12.2 + jest-mock: 29.7.0 + dev: true + + /@jest/expect-utils@29.7.0: + resolution: {integrity: sha512-GlsNBWiFQFCVi9QVSx7f5AgMeLxe9YCCs5PuP2O2LdjDAA8Jh9eX7lA1Jq/xdXw3Wb3hyvlFNfZIfcRetSzYcA==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + dependencies: + jest-get-type: 29.6.3 + dev: true + + /@jest/expect@29.7.0: + resolution: {integrity: sha512-8uMeAMycttpva3P1lBHB8VciS9V0XAr3GymPpipdyQXbBcuhkLQOSe8E/p92RyAdToS6ZD1tFkX+CkhoECE0dQ==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + dependencies: + expect: 29.7.0 + jest-snapshot: 29.7.0 + transitivePeerDependencies: + - supports-color + dev: true + + /@jest/fake-timers@29.7.0: + resolution: {integrity: sha512-q4DH1Ha4TTFPdxLsqDXK1d3+ioSL7yL5oCMJZgDYm6i+6CygW5E5xVr/D1HdsGxjt1ZWSfUAs9OxSB/BNelWrQ==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + dependencies: + '@jest/types': 29.6.3 + '@sinonjs/fake-timers': 10.3.0 + '@types/node': 20.12.2 + jest-message-util: 29.7.0 + jest-mock: 29.7.0 + jest-util: 29.7.0 + dev: true + + /@jest/globals@29.7.0: + resolution: {integrity: sha512-mpiz3dutLbkW2MNFubUGUEVLkTGiqW6yLVTA+JbP6fI6J5iL9Y0Nlg8k95pcF8ctKwCS7WVxteBs29hhfAotzQ==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + dependencies: + '@jest/environment': 29.7.0 + '@jest/expect': 29.7.0 + '@jest/types': 29.6.3 + jest-mock: 29.7.0 + transitivePeerDependencies: + - supports-color + dev: true + + /@jest/reporters@29.7.0: + resolution: {integrity: sha512-DApq0KJbJOEzAFYjHADNNxAE3KbhxQB1y5Kplb5Waqw6zVbuWatSnMjE5gs8FUgEPmNsnZA3NCWl9NG0ia04Pg==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + peerDependencies: + node-notifier: ^8.0.1 || ^9.0.0 || ^10.0.0 + peerDependenciesMeta: + node-notifier: + optional: true + dependencies: + '@bcoe/v8-coverage': 0.2.3 + '@jest/console': 29.7.0 + '@jest/test-result': 29.7.0 + '@jest/transform': 29.7.0 + '@jest/types': 29.6.3 + '@jridgewell/trace-mapping': 0.3.25 + '@types/node': 20.12.2 + chalk: 4.1.2 + collect-v8-coverage: 1.0.2 + exit: 0.1.2 + glob: 7.2.3 + graceful-fs: 4.2.11 + istanbul-lib-coverage: 3.2.2 + istanbul-lib-instrument: 6.0.2 + istanbul-lib-report: 3.0.1 + istanbul-lib-source-maps: 4.0.1 + istanbul-reports: 3.1.7 + jest-message-util: 29.7.0 + jest-util: 29.7.0 + jest-worker: 29.7.0 + slash: 3.0.0 + string-length: 4.0.2 + strip-ansi: 6.0.1 + v8-to-istanbul: 9.2.0 + transitivePeerDependencies: + - supports-color + dev: true + + /@jest/schemas@29.6.3: + resolution: {integrity: sha512-mo5j5X+jIZmJQveBKeS/clAueipV7KgiX1vMgCxam1RNYiqE1w62n0/tJJnHtjW8ZHcQco5gY85jA3mi0L+nSA==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + dependencies: + '@sinclair/typebox': 0.27.8 + dev: true + + /@jest/source-map@29.6.3: + resolution: {integrity: sha512-MHjT95QuipcPrpLM+8JMSzFx6eHp5Bm+4XeFDJlwsvVBjmKNiIAvasGK2fxz2WbGRlnvqehFbh07MMa7n3YJnw==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + dependencies: + '@jridgewell/trace-mapping': 0.3.25 + callsites: 3.1.0 + graceful-fs: 4.2.11 + dev: true + + /@jest/test-result@29.7.0: + resolution: {integrity: sha512-Fdx+tv6x1zlkJPcWXmMDAG2HBnaR9XPSd5aDWQVsfrZmLVT3lU1cwyxLgRmXR9yrq4NBoEm9BMsfgFzTQAbJYA==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + dependencies: + '@jest/console': 29.7.0 + '@jest/types': 29.6.3 + '@types/istanbul-lib-coverage': 2.0.6 + collect-v8-coverage: 1.0.2 + dev: true + + /@jest/test-sequencer@29.7.0: + resolution: {integrity: sha512-GQwJ5WZVrKnOJuiYiAF52UNUJXgTZx1NHjFSEB0qEMmSZKAkdMoIzw/Cj6x6NF4AvV23AUqDpFzQkN/eYCYTxw==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + dependencies: + '@jest/test-result': 29.7.0 + graceful-fs: 4.2.11 + jest-haste-map: 29.7.0 + slash: 3.0.0 + dev: true + + /@jest/transform@29.7.0: + resolution: {integrity: sha512-ok/BTPFzFKVMwO5eOHRrvnBVHdRy9IrsrW1GpMaQ9MCnilNLXQKmAX8s1YXDFaai9xJpac2ySzV0YeRRECr2Vw==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + dependencies: + '@babel/core': 7.24.3 + '@jest/types': 29.6.3 + '@jridgewell/trace-mapping': 0.3.25 + babel-plugin-istanbul: 6.1.1 + chalk: 4.1.2 + convert-source-map: 2.0.0 + fast-json-stable-stringify: 2.1.0 + graceful-fs: 4.2.11 + jest-haste-map: 29.7.0 + jest-regex-util: 29.6.3 + jest-util: 29.7.0 + micromatch: 4.0.5 + pirates: 4.0.6 + slash: 3.0.0 + write-file-atomic: 4.0.2 + transitivePeerDependencies: + - supports-color + dev: true + + /@jest/types@29.6.3: + resolution: {integrity: sha512-u3UPsIilWKOM3F9CXtrG8LEJmNxwoCQC/XVj4IKYXvvpx7QIi/Kg1LI5uDmDpKlac62NUtX7eLjRh+jVZcLOzw==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + dependencies: + '@jest/schemas': 29.6.3 + '@types/istanbul-lib-coverage': 2.0.6 + '@types/istanbul-reports': 3.0.4 + '@types/node': 20.12.2 + '@types/yargs': 17.0.32 + chalk: 4.1.2 + dev: true + + /@joe-p/algokit-generate-component@0.2.1: + resolution: {integrity: sha512-CErohoA88/Oxuo3L6VbV0raFepUlLR5wdOS+BNQkQx+X7uwl/vZhOt2ZKnRav4P1Ueu6glUBXU0rvn1wQ3uB9w==} + hasBin: true + dependencies: + nunjucks: 3.2.4 + transitivePeerDependencies: + - chokidar + dev: true + + /@jridgewell/gen-mapping@0.3.5: + resolution: {integrity: sha512-IzL8ZoEDIBRWEzlCcRhOaCupYyN5gdIK+Q6fbFdPDg6HqX6jpkItn7DFIpW9LQzXG6Df9sA7+OKnq0qlz/GaQg==} + engines: {node: '>=6.0.0'} + dependencies: + '@jridgewell/set-array': 1.2.1 + '@jridgewell/sourcemap-codec': 1.4.15 + '@jridgewell/trace-mapping': 0.3.25 + dev: true + + /@jridgewell/resolve-uri@3.1.2: + resolution: {integrity: sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==} + engines: {node: '>=6.0.0'} + dev: true + + /@jridgewell/set-array@1.2.1: + resolution: {integrity: sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A==} + engines: {node: '>=6.0.0'} + dev: true + + /@jridgewell/sourcemap-codec@1.4.15: + resolution: {integrity: sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==} + dev: true + + /@jridgewell/trace-mapping@0.3.25: + resolution: {integrity: sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==} + dependencies: + '@jridgewell/resolve-uri': 3.1.2 + '@jridgewell/sourcemap-codec': 1.4.15 + dev: true + + /@microsoft/tsdoc@0.14.2: + resolution: {integrity: sha512-9b8mPpKrfeGRuhFH5iO1iwCLeIIsV6+H1sRfxbkoGXIyQE2BTsPd9zqSqQJ+pv5sJ/hT5M1zvOFL02MnEezFug==} + dev: true + + /@nodelib/fs.scandir@2.1.5: + resolution: {integrity: sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==} + engines: {node: '>= 8'} + dependencies: + '@nodelib/fs.stat': 2.0.5 + run-parallel: 1.2.0 + dev: true + + /@nodelib/fs.stat@2.0.5: + resolution: {integrity: sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==} + engines: {node: '>= 8'} + dev: true + + /@nodelib/fs.walk@1.2.8: + resolution: {integrity: sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==} + engines: {node: '>= 8'} + dependencies: + '@nodelib/fs.scandir': 2.1.5 + fastq: 1.17.1 + dev: true + + /@pkgjs/parseargs@0.11.0: + resolution: {integrity: sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==} + engines: {node: '>=14'} + requiresBuild: true + dev: true + optional: true + + /@pkgr/core@0.1.1: + resolution: {integrity: sha512-cq8o4cWH0ibXh9VGi5P20Tu9XF/0fFXl9EUinr9QfTM7a7p0oTA4iJRCQWppXR1Pg8dSM0UCItCkPwsk9qWWYA==} + engines: {node: ^12.20.0 || ^14.18.0 || >=16.0.0} + dev: true + + /@playwright/test@1.42.1: + resolution: {integrity: sha512-Gq9rmS54mjBL/7/MvBaNOBwbfnh7beHvS6oS4srqXFcQHpQCV1+c8JXWE8VLPyRDhgS3H8x8A7hztqI9VnwrAQ==} + engines: {node: '>=16'} + hasBin: true + dependencies: + playwright: 1.42.1 + dev: true + + /@sinclair/typebox@0.27.8: + resolution: {integrity: sha512-+Fj43pSMwJs4KRrH/938Uf+uAELIgVBmQzg/q1YG10djyfA3TnrU8N8XzqCh/okZdszqBQTZf96idMfE5lnwTA==} + dev: true + + /@sinonjs/commons@3.0.1: + resolution: {integrity: sha512-K3mCHKQ9sVh8o1C9cxkwxaOmXoAMlDxC1mYyHrjqOWEcBjYr76t96zL2zlj5dUGZ3HSw240X1qgH3Mjf1yJWpQ==} + dependencies: + type-detect: 4.0.8 + dev: true + + /@sinonjs/fake-timers@10.3.0: + resolution: {integrity: sha512-V4BG07kuYSUkTCSBHG8G8TNhM+F19jXFWnQtzj+we8DrkpSBCee9Z3Ms8yiGer/dlmhe35/Xdgyo3/0rQKg7YA==} + dependencies: + '@sinonjs/commons': 3.0.1 + dev: true + + /@ts-morph/common@0.21.0: + resolution: {integrity: sha512-ES110Mmne5Vi4ypUKrtVQfXFDtCsDXiUiGxF6ILVlE90dDD4fdpC1LSjydl/ml7xJWKSDZwUYD2zkOePMSrPBA==} + dependencies: + fast-glob: 3.3.2 + minimatch: 7.4.6 + mkdirp: 2.1.6 + path-browserify: 1.0.1 + dev: true + + /@types/babel__core@7.20.5: + resolution: {integrity: sha512-qoQprZvz5wQFJwMDqeseRXWv3rqMvhgpbXFfVyWhbx9X47POIA6i/+dXefEmZKoAgOaTdaIgNSMqMIU61yRyzA==} + dependencies: + '@babel/parser': 7.24.1 + '@babel/types': 7.24.0 + '@types/babel__generator': 7.6.8 + '@types/babel__template': 7.4.4 + '@types/babel__traverse': 7.20.5 + dev: true + + /@types/babel__generator@7.6.8: + resolution: {integrity: sha512-ASsj+tpEDsEiFr1arWrlN6V3mdfjRMZt6LtK/Vp/kreFLnr5QH5+DhvD5nINYZXzwJvXeGq+05iUXcAzVrqWtw==} + dependencies: + '@babel/types': 7.24.0 + dev: true + + /@types/babel__template@7.4.4: + resolution: {integrity: sha512-h/NUaSyG5EyxBIp8YRxo4RMe2/qQgvyowRwVMzhYhBCONbW8PUsg4lkFMrhgZhUe5z3L3MiLDuvyJ/CaPa2A8A==} + dependencies: + '@babel/parser': 7.24.1 + '@babel/types': 7.24.0 + dev: true + + /@types/babel__traverse@7.20.5: + resolution: {integrity: sha512-WXCyOcRtH37HAUkpXhUduaxdm82b4GSlyTqajXviN4EfiuPgNYR109xMCKvpl6zPIpua0DGlMEDCq+g8EdoheQ==} + dependencies: + '@babel/types': 7.24.0 + dev: true + + /@types/graceful-fs@4.1.9: + resolution: {integrity: sha512-olP3sd1qOEe5dXTSaFvQG+02VdRXcdytWLAZsAq1PecU8uqQAhkrnbli7DagjtXKW/Bl7YJbUsa8MPcuc8LHEQ==} + dependencies: + '@types/node': 20.12.2 + dev: true + + /@types/istanbul-lib-coverage@2.0.6: + resolution: {integrity: sha512-2QF/t/auWm0lsy8XtKVPG19v3sSOQlJe/YHZgfjb/KBBHOGSV+J2q/S671rcq9uTBrLAXmZpqJiaQbMT+zNU1w==} + dev: true + + /@types/istanbul-lib-report@3.0.3: + resolution: {integrity: sha512-NQn7AHQnk/RSLOxrBbGyJM/aVQ+pjj5HCgasFxc0K/KhoATfQ/47AyUl15I2yBUpihjmas+a+VJBOqecrFH+uA==} + dependencies: + '@types/istanbul-lib-coverage': 2.0.6 + dev: true + + /@types/istanbul-reports@3.0.4: + resolution: {integrity: sha512-pk2B1NWalF9toCRu6gjBzR69syFjP4Od8WRAX+0mmf9lAjCRicLOWc+ZrxZHx/0XRjotgkF9t6iaMJ+aXcOdZQ==} + dependencies: + '@types/istanbul-lib-report': 3.0.3 + dev: true + + /@types/json-schema@7.0.15: + resolution: {integrity: sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==} + dev: true + + /@types/json5@0.0.29: + resolution: {integrity: sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ==} + dev: true + + /@types/node@20.12.2: + resolution: {integrity: sha512-zQ0NYO87hyN6Xrclcqp7f8ZbXNbRfoGWNcMvHTPQp9UUrwI0mI7XBz+cu7/W6/VClYo2g63B0cjull/srU7LgQ==} + dependencies: + undici-types: 5.26.5 + dev: true + + /@types/semver@7.5.8: + resolution: {integrity: sha512-I8EUhyrgfLrcTkzV3TSsGyl1tSuPrEDzr0yd5m90UgNxQkyDXULk3b6MlQqTCpZpNtWe1K0hzclnZkTcLBe2UQ==} + dev: true + + /@types/stack-utils@2.0.3: + resolution: {integrity: sha512-9aEbYZ3TbYMznPdcdr3SmIrLXwC/AKZXQeCf9Pgao5CKb8CyHuEX5jzWPTkvregvhRJHcpRO6BFoGW9ycaOkYw==} + dev: true + + /@types/yargs-parser@21.0.3: + resolution: {integrity: sha512-I4q9QU9MQv4oEOz4tAHJtNz1cwuLxn2F3xcc2iV5WdqLPpUnj30aUuxt1mAxYTG+oe8CZMV/+6rU4S4gRDzqtQ==} + dev: true + + /@types/yargs@17.0.32: + resolution: {integrity: sha512-xQ67Yc/laOG5uMfX/093MRlGGCIBzZMarVa+gfNKJxWAIgykYpVGkBdbqEzGDDfCrVUj6Hiff4mTZ5BA6TmAog==} + dependencies: + '@types/yargs-parser': 21.0.3 + dev: true + + /@typescript-eslint/eslint-plugin@5.62.0(@typescript-eslint/parser@5.62.0)(eslint@8.57.0)(typescript@5.4.3): + resolution: {integrity: sha512-TiZzBSJja/LbhNPvk6yc0JrX9XqhQ0hdh6M2svYfsHGejaKFIAGd9MQ+ERIMzLGlN/kZoYIgdxFV0PuljTKXag==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + peerDependencies: + '@typescript-eslint/parser': ^5.0.0 + eslint: ^6.0.0 || ^7.0.0 || ^8.0.0 + typescript: '*' + peerDependenciesMeta: + typescript: + optional: true + dependencies: + '@eslint-community/regexpp': 4.10.0 + '@typescript-eslint/parser': 5.62.0(eslint@8.57.0)(typescript@5.4.3) + '@typescript-eslint/scope-manager': 5.62.0 + '@typescript-eslint/type-utils': 5.62.0(eslint@8.57.0)(typescript@5.4.3) + '@typescript-eslint/utils': 5.62.0(eslint@8.57.0)(typescript@5.4.3) + debug: 4.3.4 + eslint: 8.57.0 + graphemer: 1.4.0 + ignore: 5.3.1 + natural-compare-lite: 1.4.0 + semver: 7.6.0 + tsutils: 3.21.0(typescript@5.4.3) + typescript: 5.4.3 + transitivePeerDependencies: + - supports-color + dev: true + + /@typescript-eslint/parser@5.62.0(eslint@8.57.0)(typescript@5.4.3): + resolution: {integrity: sha512-VlJEV0fOQ7BExOsHYAGrgbEiZoi8D+Bl2+f6V2RrXerRSylnp+ZBHmPvaIa8cz0Ajx7WO7Z5RqfgYg7ED1nRhA==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + peerDependencies: + eslint: ^6.0.0 || ^7.0.0 || ^8.0.0 + typescript: '*' + peerDependenciesMeta: + typescript: + optional: true + dependencies: + '@typescript-eslint/scope-manager': 5.62.0 + '@typescript-eslint/types': 5.62.0 + '@typescript-eslint/typescript-estree': 5.62.0(typescript@5.4.3) + debug: 4.3.4 + eslint: 8.57.0 + typescript: 5.4.3 + transitivePeerDependencies: + - supports-color + dev: true + + /@typescript-eslint/scope-manager@5.62.0: + resolution: {integrity: sha512-VXuvVvZeQCQb5Zgf4HAxc04q5j+WrNAtNh9OwCsCgpKqESMTu3tF/jhZ3xG6T4NZwWl65Bg8KuS2uEvhSfLl0w==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + dependencies: + '@typescript-eslint/types': 5.62.0 + '@typescript-eslint/visitor-keys': 5.62.0 + dev: true + + /@typescript-eslint/type-utils@5.62.0(eslint@8.57.0)(typescript@5.4.3): + resolution: {integrity: sha512-xsSQreu+VnfbqQpW5vnCJdq1Z3Q0U31qiWmRhr98ONQmcp/yhiPJFPq8MXiJVLiksmOKSjIldZzkebzHuCGzew==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + peerDependencies: + eslint: '*' + typescript: '*' + peerDependenciesMeta: + typescript: + optional: true + dependencies: + '@typescript-eslint/typescript-estree': 5.62.0(typescript@5.4.3) + '@typescript-eslint/utils': 5.62.0(eslint@8.57.0)(typescript@5.4.3) + debug: 4.3.4 + eslint: 8.57.0 + tsutils: 3.21.0(typescript@5.4.3) + typescript: 5.4.3 + transitivePeerDependencies: + - supports-color + dev: true + + /@typescript-eslint/types@5.62.0: + resolution: {integrity: sha512-87NVngcbVXUahrRTqIK27gD2t5Cu1yuCXxbLcFtCzZGlfyVWWh8mLHkoxzjsB6DDNnvdL+fW8MiwPEJyGJQDgQ==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + dev: true + + /@typescript-eslint/typescript-estree@5.62.0(typescript@5.4.3): + resolution: {integrity: sha512-CmcQ6uY7b9y694lKdRB8FEel7JbU/40iSAPomu++SjLMntB+2Leay2LO6i8VnJk58MtE9/nQSFIH6jpyRWyYzA==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + peerDependencies: + typescript: '*' + peerDependenciesMeta: + typescript: + optional: true + dependencies: + '@typescript-eslint/types': 5.62.0 + '@typescript-eslint/visitor-keys': 5.62.0 + debug: 4.3.4 + globby: 11.1.0 + is-glob: 4.0.3 + semver: 7.6.0 + tsutils: 3.21.0(typescript@5.4.3) + typescript: 5.4.3 + transitivePeerDependencies: + - supports-color + dev: true + + /@typescript-eslint/utils@5.62.0(eslint@8.57.0)(typescript@5.4.3): + resolution: {integrity: sha512-n8oxjeb5aIbPFEtmQxQYOLI0i9n5ySBEY/ZEHHZqKQSFnxio1rv6dthascc9dLuwrL0RC5mPCxB7vnAVGAYWAQ==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + peerDependencies: + eslint: ^6.0.0 || ^7.0.0 || ^8.0.0 + dependencies: + '@eslint-community/eslint-utils': 4.4.0(eslint@8.57.0) + '@types/json-schema': 7.0.15 + '@types/semver': 7.5.8 + '@typescript-eslint/scope-manager': 5.62.0 + '@typescript-eslint/types': 5.62.0 + '@typescript-eslint/typescript-estree': 5.62.0(typescript@5.4.3) + eslint: 8.57.0 + eslint-scope: 5.1.1 + semver: 7.6.0 + transitivePeerDependencies: + - supports-color + - typescript + dev: true + + /@typescript-eslint/visitor-keys@5.62.0: + resolution: {integrity: sha512-07ny+LHRzQXepkGg6w0mFY41fVUNBrL2Roj/++7V1txKugfjm/Ci/qSND03r2RhlJhJYMcTn9AhhSSqQp0Ysyw==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + dependencies: + '@typescript-eslint/types': 5.62.0 + eslint-visitor-keys: 3.4.3 + dev: true + + /@ungap/structured-clone@1.2.0: + resolution: {integrity: sha512-zuVdFrMJiuCDQUMCzQaD6KL28MjnqqN8XnAqiEq9PNm/hCPTSGfrXCOfwj1ow4LFb/tNymJPwsNbVePc1xFqrQ==} + dev: true + + /a-sync-waterfall@1.0.1: + resolution: {integrity: sha512-RYTOHHdWipFUliRFMCS4X2Yn2X8M87V/OpSqWzKKOGhzqyUxzyVmhHDH9sAvG+ZuQf/TAOFsLCpMw09I1ufUnA==} + dev: true + + /acorn-jsx@5.3.2(acorn@8.11.3): + resolution: {integrity: sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==} + peerDependencies: + acorn: ^6.0.0 || ^7.0.0 || ^8.0.0 + dependencies: + acorn: 8.11.3 + dev: true + + /acorn@8.11.3: + resolution: {integrity: sha512-Y9rRfJG5jcKOE0CLisYbojUjIrIEE7AGMzA/Sm4BslANhbS+cDMpgBdcPT91oJ7OuJ9hYJBx59RjbhxVnrF8Xg==} + engines: {node: '>=0.4.0'} + hasBin: true + dev: true + + /ajv@6.12.6: + resolution: {integrity: sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==} + dependencies: + fast-deep-equal: 3.1.3 + fast-json-stable-stringify: 2.1.0 + json-schema-traverse: 0.4.1 + uri-js: 4.4.1 + dev: true + + /algo-msgpack-with-bigint@2.1.1: + resolution: {integrity: sha512-F1tGh056XczEaEAqu7s+hlZUDWwOBT70Eq0lfMpBP2YguSQVyxRbprLq5rELXKQOyOaixTWYhMeMQMzP0U5FoQ==} + engines: {node: '>= 10'} + + /algosdk@2.7.0: + resolution: {integrity: sha512-sBE9lpV7bup3rZ+q2j3JQaFAE9JwZvjWKX00vPlG8e9txctXbgLL56jZhSWZndqhDI9oI+0P4NldkuQIWdrUyg==} + engines: {node: '>=18.0.0'} + dependencies: + algo-msgpack-with-bigint: 2.1.1 + buffer: 6.0.3 + hi-base32: 0.5.1 + js-sha256: 0.9.0 + js-sha3: 0.8.0 + js-sha512: 0.8.0 + json-bigint: 1.0.0 + tweetnacl: 1.0.3 + vlq: 2.0.4 + + /ansi-escapes@4.3.2: + resolution: {integrity: sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ==} + engines: {node: '>=8'} + dependencies: + type-fest: 0.21.3 + dev: true + + /ansi-regex@5.0.1: + resolution: {integrity: sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==} + engines: {node: '>=8'} + dev: true + + /ansi-regex@6.0.1: + resolution: {integrity: sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA==} + engines: {node: '>=12'} + dev: true + + /ansi-styles@3.2.1: + resolution: {integrity: sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==} + engines: {node: '>=4'} + dependencies: + color-convert: 1.9.3 + dev: true + + /ansi-styles@4.3.0: + resolution: {integrity: sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==} + engines: {node: '>=8'} + dependencies: + color-convert: 2.0.1 + dev: true + + /ansi-styles@5.2.0: + resolution: {integrity: sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==} + engines: {node: '>=10'} + dev: true + + /ansi-styles@6.2.1: + resolution: {integrity: sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==} + engines: {node: '>=12'} + dev: true + + /anymatch@3.1.3: + resolution: {integrity: sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==} + engines: {node: '>= 8'} + dependencies: + normalize-path: 3.0.0 + picomatch: 2.3.1 + dev: true + + /argparse@1.0.10: + resolution: {integrity: sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==} + dependencies: + sprintf-js: 1.0.3 + dev: true + + /argparse@2.0.1: + resolution: {integrity: sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==} + dev: true + + /array-buffer-byte-length@1.0.1: + resolution: {integrity: sha512-ahC5W1xgou+KTXix4sAO8Ki12Q+jf4i0+tmk3sC+zgcynshkHxzpXdImBehiUYKKKDwvfFiJl1tZt6ewscS1Mg==} + engines: {node: '>= 0.4'} + dependencies: + call-bind: 1.0.7 + is-array-buffer: 3.0.4 + dev: true + + /array-includes@3.1.8: + resolution: {integrity: sha512-itaWrbYbqpGXkGhZPGUulwnhVf5Hpy1xiCFsGqyIGglbBxmG5vSjxQen3/WGOjPpNEv1RtBLKxbmVXm8HpJStQ==} + engines: {node: '>= 0.4'} + dependencies: + call-bind: 1.0.7 + define-properties: 1.2.1 + es-abstract: 1.23.3 + es-object-atoms: 1.0.0 + get-intrinsic: 1.2.4 + is-string: 1.0.7 + dev: true + + /array-union@2.1.0: + resolution: {integrity: sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==} + engines: {node: '>=8'} + dev: true + + /array.prototype.findlastindex@1.2.5: + resolution: {integrity: sha512-zfETvRFA8o7EiNn++N5f/kaCw221hrpGsDmcpndVupkPzEc1Wuf3VgC0qby1BbHs7f5DVYjgtEU2LLh5bqeGfQ==} + engines: {node: '>= 0.4'} + dependencies: + call-bind: 1.0.7 + define-properties: 1.2.1 + es-abstract: 1.23.3 + es-errors: 1.3.0 + es-object-atoms: 1.0.0 + es-shim-unscopables: 1.0.2 + dev: true + + /array.prototype.flat@1.3.2: + resolution: {integrity: sha512-djYB+Zx2vLewY8RWlNCUdHjDXs2XOgm602S9E7P/UpHgfeHL00cRiIF+IN/G/aUJ7kGPb6yO/ErDI5V2s8iycA==} + engines: {node: '>= 0.4'} + dependencies: + call-bind: 1.0.7 + define-properties: 1.2.1 + es-abstract: 1.23.3 + es-shim-unscopables: 1.0.2 + dev: true + + /array.prototype.flatmap@1.3.2: + resolution: {integrity: sha512-Ewyx0c9PmpcsByhSW4r+9zDU7sGjFc86qf/kKtuSCRdhfbk0SNLLkaT5qvcHnRGgc5NP/ly/y+qkXkqONX54CQ==} + engines: {node: '>= 0.4'} + dependencies: + call-bind: 1.0.7 + define-properties: 1.2.1 + es-abstract: 1.23.3 + es-shim-unscopables: 1.0.2 + dev: true + + /arraybuffer.prototype.slice@1.0.3: + resolution: {integrity: sha512-bMxMKAjg13EBSVscxTaYA4mRc5t1UAXa2kXiGTNfZ079HIWXEkKmkgFrh/nJqamaLSrXO5H4WFFkPEaLJWbs3A==} + engines: {node: '>= 0.4'} + dependencies: + array-buffer-byte-length: 1.0.1 + call-bind: 1.0.7 + define-properties: 1.2.1 + es-abstract: 1.23.3 + es-errors: 1.3.0 + get-intrinsic: 1.2.4 + is-array-buffer: 3.0.4 + is-shared-array-buffer: 1.0.3 + dev: true + + /asap@2.0.6: + resolution: {integrity: sha512-BSHWgDSAiKs50o2Re8ppvp3seVHXSRM44cdSsT9FfNEUUZLOGWVCsiWaRPWM1Znn+mqZ1OfVZ3z3DWEzSp7hRA==} + dev: true + + /available-typed-arrays@1.0.7: + resolution: {integrity: sha512-wvUjBtSGN7+7SjNpq/9M2Tg350UZD3q62IFZLbRAR1bSMlCo1ZaeW+BJ+D090e4hIIZLBcTDWe4Mh4jvUDajzQ==} + engines: {node: '>= 0.4'} + dependencies: + possible-typed-array-names: 1.0.0 + dev: true + + /babel-jest@29.7.0(@babel/core@7.24.3): + resolution: {integrity: sha512-BrvGY3xZSwEcCzKvKsCi2GgHqDqsYkOP4/by5xCgIwGXQxIEh+8ew3gmrE1y7XRR6LHZIj6yLYnUi/mm2KXKBg==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + peerDependencies: + '@babel/core': ^7.8.0 + dependencies: + '@babel/core': 7.24.3 + '@jest/transform': 29.7.0 + '@types/babel__core': 7.20.5 + babel-plugin-istanbul: 6.1.1 + babel-preset-jest: 29.6.3(@babel/core@7.24.3) + chalk: 4.1.2 + graceful-fs: 4.2.11 + slash: 3.0.0 + transitivePeerDependencies: + - supports-color + dev: true + + /babel-plugin-istanbul@6.1.1: + resolution: {integrity: sha512-Y1IQok9821cC9onCx5otgFfRm7Lm+I+wwxOx738M/WLPZ9Q42m4IG5W0FNX8WLL2gYMZo3JkuXIH2DOpWM+qwA==} + engines: {node: '>=8'} + dependencies: + '@babel/helper-plugin-utils': 7.24.0 + '@istanbuljs/load-nyc-config': 1.1.0 + '@istanbuljs/schema': 0.1.3 + istanbul-lib-instrument: 5.2.1 + test-exclude: 6.0.0 + transitivePeerDependencies: + - supports-color + dev: true + + /babel-plugin-jest-hoist@29.6.3: + resolution: {integrity: sha512-ESAc/RJvGTFEzRwOTT4+lNDk/GNHMkKbNzsvT0qKRfDyyYTskxB5rnU2njIDYVxXCBHHEI1c0YwHob3WaYujOg==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + dependencies: + '@babel/template': 7.24.0 + '@babel/types': 7.24.0 + '@types/babel__core': 7.20.5 + '@types/babel__traverse': 7.20.5 + dev: true + + /babel-preset-current-node-syntax@1.0.1(@babel/core@7.24.3): + resolution: {integrity: sha512-M7LQ0bxarkxQoN+vz5aJPsLBn77n8QgTFmo8WK0/44auK2xlCXrYcUxHFxgU7qW5Yzw/CjmLRK2uJzaCd7LvqQ==} + peerDependencies: + '@babel/core': ^7.0.0 + dependencies: + '@babel/core': 7.24.3 + '@babel/plugin-syntax-async-generators': 7.8.4(@babel/core@7.24.3) + '@babel/plugin-syntax-bigint': 7.8.3(@babel/core@7.24.3) + '@babel/plugin-syntax-class-properties': 7.12.13(@babel/core@7.24.3) + '@babel/plugin-syntax-import-meta': 7.10.4(@babel/core@7.24.3) + '@babel/plugin-syntax-json-strings': 7.8.3(@babel/core@7.24.3) + '@babel/plugin-syntax-logical-assignment-operators': 7.10.4(@babel/core@7.24.3) + '@babel/plugin-syntax-nullish-coalescing-operator': 7.8.3(@babel/core@7.24.3) + '@babel/plugin-syntax-numeric-separator': 7.10.4(@babel/core@7.24.3) + '@babel/plugin-syntax-object-rest-spread': 7.8.3(@babel/core@7.24.3) + '@babel/plugin-syntax-optional-catch-binding': 7.8.3(@babel/core@7.24.3) + '@babel/plugin-syntax-optional-chaining': 7.8.3(@babel/core@7.24.3) + '@babel/plugin-syntax-top-level-await': 7.14.5(@babel/core@7.24.3) + dev: true + + /babel-preset-jest@29.6.3(@babel/core@7.24.3): + resolution: {integrity: sha512-0B3bhxR6snWXJZtR/RliHTDPRgn1sNHOR0yVtq/IiQFyuOVjFS+wuio/R4gSNkyYmKmJB4wGZv2NZanmKmTnNA==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + peerDependencies: + '@babel/core': ^7.0.0 + dependencies: + '@babel/core': 7.24.3 + babel-plugin-jest-hoist: 29.6.3 + babel-preset-current-node-syntax: 1.0.1(@babel/core@7.24.3) + dev: true + + /balanced-match@1.0.2: + resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==} + dev: true + + /base64-js@1.5.1: + resolution: {integrity: sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==} + + /bignumber.js@9.1.2: + resolution: {integrity: sha512-2/mKyZH9K85bzOEfhXDBFZTGd1CTs+5IHpeFQo9luiBG7hghdC851Pj2WAhb6E3R6b9tZj/XKhbg4fum+Kepug==} + + /brace-expansion@1.1.11: + resolution: {integrity: sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==} + dependencies: + balanced-match: 1.0.2 + concat-map: 0.0.1 + dev: true + + /brace-expansion@2.0.1: + resolution: {integrity: sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==} + dependencies: + balanced-match: 1.0.2 + dev: true + + /braces@3.0.2: + resolution: {integrity: sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==} + engines: {node: '>=8'} + dependencies: + fill-range: 7.0.1 + dev: true + + /browserslist@4.23.0: + resolution: {integrity: sha512-QW8HiM1shhT2GuzkvklfjcKDiWFXHOeFCIA/huJPwHsslwcydgk7X+z2zXpEijP98UCY7HbubZt5J2Zgvf0CaQ==} + engines: {node: ^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7} + hasBin: true + dependencies: + caniuse-lite: 1.0.30001603 + electron-to-chromium: 1.4.723 + node-releases: 2.0.14 + update-browserslist-db: 1.0.13(browserslist@4.23.0) + dev: true + + /bs-logger@0.2.6: + resolution: {integrity: sha512-pd8DCoxmbgc7hyPKOvxtqNcjYoOsABPQdcCUjGp3d42VR2CX1ORhk2A87oqqu5R1kk+76nsxZupkmyd+MVtCog==} + engines: {node: '>= 6'} + dependencies: + fast-json-stable-stringify: 2.1.0 + dev: true + + /bser@2.1.1: + resolution: {integrity: sha512-gQxTNE/GAfIIrmHLUE3oJyp5FO6HRBfhjnw4/wMmA63ZGDJnWBmgY/lyQBpnDUkGmAhbSe39tx2d/iTOAfglwQ==} + dependencies: + node-int64: 0.4.0 + dev: true + + /buffer-from@1.1.2: + resolution: {integrity: sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==} + dev: true + + /buffer@6.0.3: + resolution: {integrity: sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==} + dependencies: + base64-js: 1.5.1 + ieee754: 1.2.1 + + /call-bind@1.0.7: + resolution: {integrity: sha512-GHTSNSYICQ7scH7sZ+M2rFopRoLh8t2bLSW6BbgrtLsahOIB5iyAVJf9GjWK3cYTDaMj4XdBpM1cA6pIS0Kv2w==} + engines: {node: '>= 0.4'} + dependencies: + es-define-property: 1.0.0 + es-errors: 1.3.0 + function-bind: 1.1.2 + get-intrinsic: 1.2.4 + set-function-length: 1.2.2 + dev: true + + /callsites@3.1.0: + resolution: {integrity: sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==} + engines: {node: '>=6'} + dev: true + + /camel-case@4.1.2: + resolution: {integrity: sha512-gxGWBrTT1JuMx6R+o5PTXMmUnhnVzLQ9SNutD4YqKtI6ap897t3tKECYla6gCWEkplXnlNybEkZg9GEGxKFCgw==} + dependencies: + pascal-case: 3.1.2 + tslib: 2.6.2 + dev: true + + /camelcase@5.3.1: + resolution: {integrity: sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==} + engines: {node: '>=6'} + dev: true + + /camelcase@6.3.0: + resolution: {integrity: sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==} + engines: {node: '>=10'} + dev: true + + /caniuse-lite@1.0.30001603: + resolution: {integrity: sha512-iL2iSS0eDILMb9n5yKQoTBim9jMZ0Yrk8g0N9K7UzYyWnfIKzXBZD5ngpM37ZcL/cv0Mli8XtVMRYMQAfFpi5Q==} + dev: true + + /capital-case@1.0.4: + resolution: {integrity: sha512-ds37W8CytHgwnhGGTi88pcPyR15qoNkOpYwmMMfnWqqWgESapLqvDx6huFjQ5vqWSn2Z06173XNA7LtMOeUh1A==} + dependencies: + no-case: 3.0.4 + tslib: 2.6.2 + upper-case-first: 2.0.2 + dev: true + + /chalk@2.4.2: + resolution: {integrity: sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==} + engines: {node: '>=4'} + dependencies: + ansi-styles: 3.2.1 + escape-string-regexp: 1.0.5 + supports-color: 5.5.0 + dev: true + + /chalk@4.1.2: + resolution: {integrity: sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==} + engines: {node: '>=10'} + dependencies: + ansi-styles: 4.3.0 + supports-color: 7.2.0 + dev: true + + /change-case@4.1.2: + resolution: {integrity: sha512-bSxY2ws9OtviILG1EiY5K7NNxkqg/JnRnFxLtKQ96JaviiIxi7djMrSd0ECT9AC+lttClmYwKw53BWpOMblo7A==} + dependencies: + camel-case: 4.1.2 + capital-case: 1.0.4 + constant-case: 3.0.4 + dot-case: 3.0.4 + header-case: 2.0.4 + no-case: 3.0.4 + param-case: 3.0.4 + pascal-case: 3.1.2 + path-case: 3.0.4 + sentence-case: 3.0.4 + snake-case: 3.0.4 + tslib: 2.6.2 + dev: true + + /char-regex@1.0.2: + resolution: {integrity: sha512-kWWXztvZ5SBQV+eRgKFeh8q5sLuZY2+8WUIzlxWVTg+oGwY14qylx1KbKzHd8P6ZYkAg0xyIDU9JMHhyJMZ1jw==} + engines: {node: '>=10'} + dev: true + + /ci-info@3.9.0: + resolution: {integrity: sha512-NIxF55hv4nSqQswkAeiOi1r83xy8JldOFDTWiug55KBu9Jnblncd2U6ViHmYgHf01TPZS77NJBhBMKdWj9HQMQ==} + engines: {node: '>=8'} + dev: true + + /cjs-module-lexer@1.2.3: + resolution: {integrity: sha512-0TNiGstbQmCFwt4akjjBg5pLRTSyj/PkWQ1ZoO2zntmg9yLqSRxwEa4iCfQLGjqhiqBfOJa7W/E8wfGrTDmlZQ==} + dev: true + + /cliui@8.0.1: + resolution: {integrity: sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==} + engines: {node: '>=12'} + dependencies: + string-width: 4.2.3 + strip-ansi: 6.0.1 + wrap-ansi: 7.0.0 + dev: true + + /co@4.6.0: + resolution: {integrity: sha512-QVb0dM5HvG+uaxitm8wONl7jltx8dqhfU33DcqtOZcLSVIKSDDLDi7+0LbAKiyI8hD9u42m2YxXSkMGWThaecQ==} + engines: {iojs: '>= 1.0.0', node: '>= 0.12.0'} + dev: true + + /code-block-writer@12.0.0: + resolution: {integrity: sha512-q4dMFMlXtKR3XNBHyMHt/3pwYNA69EDk00lloMOaaUMKPUXBw6lpXtbu3MMVG6/uOihGnRDOlkyqsONEUj60+w==} + dev: true + + /collect-v8-coverage@1.0.2: + resolution: {integrity: sha512-lHl4d5/ONEbLlJvaJNtsF/Lz+WvB07u2ycqTYbdrq7UypDXailES4valYb2eWiJFxZlVmpGekfqoxQhzyFdT4Q==} + dev: true + + /color-convert@1.9.3: + resolution: {integrity: sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==} + dependencies: + color-name: 1.1.3 + dev: true + + /color-convert@2.0.1: + resolution: {integrity: sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==} + engines: {node: '>=7.0.0'} + dependencies: + color-name: 1.1.4 + dev: true + + /color-name@1.1.3: + resolution: {integrity: sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==} + dev: true + + /color-name@1.1.4: + resolution: {integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==} + dev: true + + /commander@11.1.0: + resolution: {integrity: sha512-yPVavfyCcRhmorC7rWlkHn15b4wDVgVmBA7kV4QVBsF7kv/9TKJAbAXVTxvTnwP8HHKjRCJDClKbciiYS7p0DQ==} + engines: {node: '>=16'} + dev: true + + /commander@5.1.0: + resolution: {integrity: sha512-P0CysNDQ7rtVw4QIQtm+MRxV66vKFSvlsQvGYXZWR3qFU0jlMKHZZZgw8e+8DSah4UDKMqnknRDQz+xuQXQ/Zg==} + engines: {node: '>= 6'} + dev: true + + /concat-map@0.0.1: + resolution: {integrity: sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==} + dev: true + + /confusing-browser-globals@1.0.11: + resolution: {integrity: sha512-JsPKdmh8ZkmnHxDk55FZ1TqVLvEQTvoByJZRN9jzI0UjxK/QgAmsphz7PGtqgPieQZ/CQcHWXCR7ATDNhGe+YA==} + dev: true + + /constant-case@3.0.4: + resolution: {integrity: sha512-I2hSBi7Vvs7BEuJDr5dDHfzb/Ruj3FyvFyh7KLilAjNQw3Be+xgqUBA2W6scVEcL0hL1dwPRtIqEPVUCKkSsyQ==} + dependencies: + no-case: 3.0.4 + tslib: 2.6.2 + upper-case: 2.0.2 + dev: true + + /convert-source-map@2.0.0: + resolution: {integrity: sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==} + dev: true + + /create-jest@29.7.0: + resolution: {integrity: sha512-Adz2bdH0Vq3F53KEMJOoftQFutWCukm6J24wbPWRO4k1kMY7gS7ds/uoJkNuV8wDCtWWnuwGcJwpWcih+zEW1Q==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + hasBin: true + dependencies: + '@jest/types': 29.6.3 + chalk: 4.1.2 + exit: 0.1.2 + graceful-fs: 4.2.11 + jest-config: 29.7.0(@types/node@20.12.2) + jest-util: 29.7.0 + prompts: 2.4.2 + transitivePeerDependencies: + - '@types/node' + - babel-plugin-macros + - supports-color + - ts-node + dev: true + + /cross-spawn@7.0.3: + resolution: {integrity: sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==} + engines: {node: '>= 8'} + dependencies: + path-key: 3.1.1 + shebang-command: 2.0.0 + which: 2.0.2 + dev: true + + /data-view-buffer@1.0.1: + resolution: {integrity: sha512-0lht7OugA5x3iJLOWFhWK/5ehONdprk0ISXqVFn/NFrDu+cuc8iADFrGQz5BnRK7LLU3JmkbXSxaqX+/mXYtUA==} + engines: {node: '>= 0.4'} + dependencies: + call-bind: 1.0.7 + es-errors: 1.3.0 + is-data-view: 1.0.1 + dev: true + + /data-view-byte-length@1.0.1: + resolution: {integrity: sha512-4J7wRJD3ABAzr8wP+OcIcqq2dlUKp4DVflx++hs5h5ZKydWMI6/D/fAot+yh6g2tHh8fLFTvNOaVN357NvSrOQ==} + engines: {node: '>= 0.4'} + dependencies: + call-bind: 1.0.7 + es-errors: 1.3.0 + is-data-view: 1.0.1 + dev: true + + /data-view-byte-offset@1.0.0: + resolution: {integrity: sha512-t/Ygsytq+R995EJ5PZlD4Cu56sWa8InXySaViRzw9apusqsOO2bQP+SbYzAhR0pFKoB+43lYy8rWban9JSuXnA==} + engines: {node: '>= 0.4'} + dependencies: + call-bind: 1.0.7 + es-errors: 1.3.0 + is-data-view: 1.0.1 + dev: true + + /debug@3.2.7: + resolution: {integrity: sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==} + peerDependencies: + supports-color: '*' + peerDependenciesMeta: + supports-color: + optional: true + dependencies: + ms: 2.1.3 + dev: true + + /debug@4.3.4: + resolution: {integrity: sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==} + engines: {node: '>=6.0'} + peerDependencies: + supports-color: '*' + peerDependenciesMeta: + supports-color: + optional: true + dependencies: + ms: 2.1.2 + dev: true + + /dedent@1.5.1: + resolution: {integrity: sha512-+LxW+KLWxu3HW3M2w2ympwtqPrqYRzU8fqi6Fhd18fBALe15blJPI/I4+UHveMVG6lJqB4JNd4UG0S5cnVHwIg==} + peerDependencies: + babel-plugin-macros: ^3.1.0 + peerDependenciesMeta: + babel-plugin-macros: + optional: true + dev: true + + /deep-is@0.1.4: + resolution: {integrity: sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==} + dev: true + + /deepmerge@4.3.1: + resolution: {integrity: sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==} + engines: {node: '>=0.10.0'} + dev: true + + /define-data-property@1.1.4: + resolution: {integrity: sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==} + engines: {node: '>= 0.4'} + dependencies: + es-define-property: 1.0.0 + es-errors: 1.3.0 + gopd: 1.0.1 + dev: true + + /define-properties@1.2.1: + resolution: {integrity: sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg==} + engines: {node: '>= 0.4'} + dependencies: + define-data-property: 1.1.4 + has-property-descriptors: 1.0.2 + object-keys: 1.1.1 + dev: true + + /detect-newline@3.1.0: + resolution: {integrity: sha512-TLz+x/vEXm/Y7P7wn1EJFNLxYpUD4TgMosxY6fAVJUnJMbupHBOncxyWUG9OpTaH9EBD7uFI5LfEgmMOc54DsA==} + engines: {node: '>=8'} + dev: true + + /diff-sequences@29.6.3: + resolution: {integrity: sha512-EjePK1srD3P08o2j4f0ExnylqRs5B9tJjcp9t1krH2qRi8CCdsYfwe9JgSLurFBWwq4uOlipzfk5fHNvwFKr8Q==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + dev: true + + /dir-glob@3.0.1: + resolution: {integrity: sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==} + engines: {node: '>=8'} + dependencies: + path-type: 4.0.0 + dev: true + + /doctrine@2.1.0: + resolution: {integrity: sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==} + engines: {node: '>=0.10.0'} + dependencies: + esutils: 2.0.3 + dev: true + + /doctrine@3.0.0: + resolution: {integrity: sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==} + engines: {node: '>=6.0.0'} + dependencies: + esutils: 2.0.3 + dev: true + + /dot-case@3.0.4: + resolution: {integrity: sha512-Kv5nKlh6yRrdrGvxeJ2e5y2eRUpkUosIW4A2AS38zwSz27zu7ufDwQPi5Jhs3XAlGNetl3bmnGhQsMtkKJnj3w==} + dependencies: + no-case: 3.0.4 + tslib: 2.6.2 + dev: true + + /dotenv@16.4.5: + resolution: {integrity: sha512-ZmdL2rui+eB2YwhsWzjInR8LldtZHGDoQ1ugH85ppHKwpUHL7j7rN0Ti9NCnGiQbhaZ11FpR+7ao1dNsmduNUg==} + engines: {node: '>=12'} + dev: true + + /eastasianwidth@0.2.0: + resolution: {integrity: sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==} + dev: true + + /electron-to-chromium@1.4.723: + resolution: {integrity: sha512-rxFVtrMGMFROr4qqU6n95rUi9IlfIm+lIAt+hOToy/9r6CDv0XiEcQdC3VP71y1pE5CFTzKV0RvxOGYCPWWHPw==} + dev: true + + /emittery@0.13.1: + resolution: {integrity: sha512-DeWwawk6r5yR9jFgnDKYt4sLS0LmHJJi3ZOnb5/JdbYwj3nW+FxQnHIjhBKz8YLC7oRNPVM9NQ47I3CVx34eqQ==} + engines: {node: '>=12'} + dev: true + + /emoji-regex@8.0.0: + resolution: {integrity: sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==} + dev: true + + /emoji-regex@9.2.2: + resolution: {integrity: sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==} + dev: true + + /error-ex@1.3.2: + resolution: {integrity: sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==} + dependencies: + is-arrayish: 0.2.1 + dev: true + + /es-abstract@1.23.3: + resolution: {integrity: sha512-e+HfNH61Bj1X9/jLc5v1owaLYuHdeHHSQlkhCBiTK8rBvKaULl/beGMxwrMXjpYrv4pz22BlY570vVePA2ho4A==} + engines: {node: '>= 0.4'} + dependencies: + array-buffer-byte-length: 1.0.1 + arraybuffer.prototype.slice: 1.0.3 + available-typed-arrays: 1.0.7 + call-bind: 1.0.7 + data-view-buffer: 1.0.1 + data-view-byte-length: 1.0.1 + data-view-byte-offset: 1.0.0 + es-define-property: 1.0.0 + es-errors: 1.3.0 + es-object-atoms: 1.0.0 + es-set-tostringtag: 2.0.3 + es-to-primitive: 1.2.1 + function.prototype.name: 1.1.6 + get-intrinsic: 1.2.4 + get-symbol-description: 1.0.2 + globalthis: 1.0.3 + gopd: 1.0.1 + has-property-descriptors: 1.0.2 + has-proto: 1.0.3 + has-symbols: 1.0.3 + hasown: 2.0.2 + internal-slot: 1.0.7 + is-array-buffer: 3.0.4 + is-callable: 1.2.7 + is-data-view: 1.0.1 + is-negative-zero: 2.0.3 + is-regex: 1.1.4 + is-shared-array-buffer: 1.0.3 + is-string: 1.0.7 + is-typed-array: 1.1.13 + is-weakref: 1.0.2 + object-inspect: 1.13.1 + object-keys: 1.1.1 + object.assign: 4.1.5 + regexp.prototype.flags: 1.5.2 + safe-array-concat: 1.1.2 + safe-regex-test: 1.0.3 + string.prototype.trim: 1.2.9 + string.prototype.trimend: 1.0.8 + string.prototype.trimstart: 1.0.8 + typed-array-buffer: 1.0.2 + typed-array-byte-length: 1.0.1 + typed-array-byte-offset: 1.0.2 + typed-array-length: 1.0.6 + unbox-primitive: 1.0.2 + which-typed-array: 1.1.15 + dev: true + + /es-define-property@1.0.0: + resolution: {integrity: sha512-jxayLKShrEqqzJ0eumQbVhTYQM27CfT1T35+gCgDFoL82JLsXqTJ76zv6A0YLOgEnLUMvLzsDsGIrl8NFpT2gQ==} + engines: {node: '>= 0.4'} + dependencies: + get-intrinsic: 1.2.4 + dev: true + + /es-errors@1.3.0: + resolution: {integrity: sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==} + engines: {node: '>= 0.4'} + dev: true + + /es-object-atoms@1.0.0: + resolution: {integrity: sha512-MZ4iQ6JwHOBQjahnjwaC1ZtIBH+2ohjamzAO3oaHcXYup7qxjF2fixyH+Q71voWHeOkI2q/TnJao/KfXYIZWbw==} + engines: {node: '>= 0.4'} + dependencies: + es-errors: 1.3.0 + dev: true + + /es-set-tostringtag@2.0.3: + resolution: {integrity: sha512-3T8uNMC3OQTHkFUsFq8r/BwAXLHvU/9O9mE0fBc/MY5iq/8H7ncvO947LmYA6ldWw9Uh8Yhf25zu6n7nML5QWQ==} + engines: {node: '>= 0.4'} + dependencies: + get-intrinsic: 1.2.4 + has-tostringtag: 1.0.2 + hasown: 2.0.2 + dev: true + + /es-shim-unscopables@1.0.2: + resolution: {integrity: sha512-J3yBRXCzDu4ULnQwxyToo/OjdMx6akgVC7K6few0a7F/0wLtmKKN7I73AH5T2836UuXRqN7Qg+IIUw/+YJksRw==} + dependencies: + hasown: 2.0.2 + dev: true + + /es-to-primitive@1.2.1: + resolution: {integrity: sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==} + engines: {node: '>= 0.4'} + dependencies: + is-callable: 1.2.7 + is-date-object: 1.0.5 + is-symbol: 1.0.4 + dev: true + + /escalade@3.1.2: + resolution: {integrity: sha512-ErCHMCae19vR8vQGe50xIsVomy19rg6gFu3+r3jkEO46suLMWBksvVyoGgQV+jOfl84ZSOSlmv6Gxa89PmTGmA==} + engines: {node: '>=6'} + dev: true + + /escape-string-regexp@1.0.5: + resolution: {integrity: sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==} + engines: {node: '>=0.8.0'} + dev: true + + /escape-string-regexp@2.0.0: + resolution: {integrity: sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w==} + engines: {node: '>=8'} + dev: true + + /escape-string-regexp@4.0.0: + resolution: {integrity: sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==} + engines: {node: '>=10'} + dev: true + + /eslint-config-airbnb-base@15.0.0(eslint-plugin-import@2.29.1)(eslint@8.57.0): + resolution: {integrity: sha512-xaX3z4ZZIcFLvh2oUNvcX5oEofXda7giYmuplVxoOg5A7EXJMrUyqRgR+mhDhPK8LZ4PttFOBvCYDbX3sUoUig==} + engines: {node: ^10.12.0 || >=12.0.0} + peerDependencies: + eslint: ^7.32.0 || ^8.2.0 + eslint-plugin-import: ^2.25.2 + dependencies: + confusing-browser-globals: 1.0.11 + eslint: 8.57.0 + eslint-plugin-import: 2.29.1(@typescript-eslint/parser@5.62.0)(eslint@8.57.0) + object.assign: 4.1.5 + object.entries: 1.1.8 + semver: 6.3.1 + dev: true + + /eslint-config-airbnb-typescript@17.1.0(@typescript-eslint/eslint-plugin@5.62.0)(@typescript-eslint/parser@5.62.0)(eslint-plugin-import@2.29.1)(eslint@8.57.0): + resolution: {integrity: sha512-GPxI5URre6dDpJ0CtcthSZVBAfI+Uw7un5OYNVxP2EYi3H81Jw701yFP7AU+/vCE7xBtFmjge7kfhhk4+RAiig==} + peerDependencies: + '@typescript-eslint/eslint-plugin': ^5.13.0 || ^6.0.0 + '@typescript-eslint/parser': ^5.0.0 || ^6.0.0 + eslint: ^7.32.0 || ^8.2.0 + eslint-plugin-import: ^2.25.3 + dependencies: + '@typescript-eslint/eslint-plugin': 5.62.0(@typescript-eslint/parser@5.62.0)(eslint@8.57.0)(typescript@5.4.3) + '@typescript-eslint/parser': 5.62.0(eslint@8.57.0)(typescript@5.4.3) + eslint: 8.57.0 + eslint-config-airbnb-base: 15.0.0(eslint-plugin-import@2.29.1)(eslint@8.57.0) + eslint-plugin-import: 2.29.1(@typescript-eslint/parser@5.62.0)(eslint@8.57.0) + dev: true + + /eslint-config-prettier@9.1.0(eslint@8.57.0): + resolution: {integrity: sha512-NSWl5BFQWEPi1j4TjVNItzYV7dZXZ+wP6I6ZhrBGpChQhZRUaElihE9uRRkcbRnNb76UMKDF3r+WTmNcGPKsqw==} + hasBin: true + peerDependencies: + eslint: '>=7.0.0' + dependencies: + eslint: 8.57.0 + dev: true + + /eslint-import-resolver-node@0.3.9: + resolution: {integrity: sha512-WFj2isz22JahUv+B788TlO3N6zL3nNJGU8CcZbPZvVEkBPaJdCV4vy5wyghty5ROFbCRnm132v8BScu5/1BQ8g==} + dependencies: + debug: 3.2.7 + is-core-module: 2.13.1 + resolve: 1.22.8 + transitivePeerDependencies: + - supports-color + dev: true + + /eslint-module-utils@2.8.1(@typescript-eslint/parser@5.62.0)(eslint-import-resolver-node@0.3.9)(eslint@8.57.0): + resolution: {integrity: sha512-rXDXR3h7cs7dy9RNpUlQf80nX31XWJEyGq1tRMo+6GsO5VmTe4UTwtmonAD4ZkAsrfMVDA2wlGJ3790Ys+D49Q==} + engines: {node: '>=4'} + peerDependencies: + '@typescript-eslint/parser': '*' + eslint: '*' + eslint-import-resolver-node: '*' + eslint-import-resolver-typescript: '*' + eslint-import-resolver-webpack: '*' + peerDependenciesMeta: + '@typescript-eslint/parser': + optional: true + eslint: + optional: true + eslint-import-resolver-node: + optional: true + eslint-import-resolver-typescript: + optional: true + eslint-import-resolver-webpack: + optional: true + dependencies: + '@typescript-eslint/parser': 5.62.0(eslint@8.57.0)(typescript@5.4.3) + debug: 3.2.7 + eslint: 8.57.0 + eslint-import-resolver-node: 0.3.9 + transitivePeerDependencies: + - supports-color + dev: true + + /eslint-plugin-import@2.29.1(@typescript-eslint/parser@5.62.0)(eslint@8.57.0): + resolution: {integrity: sha512-BbPC0cuExzhiMo4Ff1BTVwHpjjv28C5R+btTOGaCRC7UEz801up0JadwkeSk5Ued6TG34uaczuVuH6qyy5YUxw==} + engines: {node: '>=4'} + peerDependencies: + '@typescript-eslint/parser': '*' + eslint: ^2 || ^3 || ^4 || ^5 || ^6 || ^7.2.0 || ^8 + peerDependenciesMeta: + '@typescript-eslint/parser': + optional: true + dependencies: + '@typescript-eslint/parser': 5.62.0(eslint@8.57.0)(typescript@5.4.3) + array-includes: 3.1.8 + array.prototype.findlastindex: 1.2.5 + array.prototype.flat: 1.3.2 + array.prototype.flatmap: 1.3.2 + debug: 3.2.7 + doctrine: 2.1.0 + eslint: 8.57.0 + eslint-import-resolver-node: 0.3.9 + eslint-module-utils: 2.8.1(@typescript-eslint/parser@5.62.0)(eslint-import-resolver-node@0.3.9)(eslint@8.57.0) + hasown: 2.0.2 + is-core-module: 2.13.1 + is-glob: 4.0.3 + minimatch: 3.1.2 + object.fromentries: 2.0.8 + object.groupby: 1.0.3 + object.values: 1.2.0 + semver: 6.3.1 + tsconfig-paths: 3.15.0 + transitivePeerDependencies: + - eslint-import-resolver-typescript + - eslint-import-resolver-webpack + - supports-color + dev: true + + /eslint-plugin-prettier@5.1.3(eslint-config-prettier@9.1.0)(eslint@8.57.0)(prettier@3.2.5): + resolution: {integrity: sha512-C9GCVAs4Eq7ZC/XFQHITLiHJxQngdtraXaM+LoUFoFp/lHNl2Zn8f3WQbe9HvTBBQ9YnKFB0/2Ajdqwo5D1EAw==} + engines: {node: ^14.18.0 || >=16.0.0} + peerDependencies: + '@types/eslint': '>=8.0.0' + eslint: '>=8.0.0' + eslint-config-prettier: '*' + prettier: '>=3.0.0' + peerDependenciesMeta: + '@types/eslint': + optional: true + eslint-config-prettier: + optional: true + dependencies: + eslint: 8.57.0 + eslint-config-prettier: 9.1.0(eslint@8.57.0) + prettier: 3.2.5 + prettier-linter-helpers: 1.0.0 + synckit: 0.8.8 + dev: true + + /eslint-scope@5.1.1: + resolution: {integrity: sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==} + engines: {node: '>=8.0.0'} + dependencies: + esrecurse: 4.3.0 + estraverse: 4.3.0 + dev: true + + /eslint-scope@7.2.2: + resolution: {integrity: sha512-dOt21O7lTMhDM+X9mB4GX+DZrZtCUJPL/wlcTqxyrx5IvO0IYtILdtrQGQp+8n5S0gwSVmOf9NQrjMOgfQZlIg==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + dependencies: + esrecurse: 4.3.0 + estraverse: 5.3.0 + dev: true + + /eslint-visitor-keys@3.4.3: + resolution: {integrity: sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + dev: true + + /eslint@8.57.0: + resolution: {integrity: sha512-dZ6+mexnaTIbSBZWgou51U6OmzIhYM2VcNdtiTtI7qPNZm35Akpr0f6vtw3w1Kmn5PYo+tZVfh13WrhpS6oLqQ==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + hasBin: true + dependencies: + '@eslint-community/eslint-utils': 4.4.0(eslint@8.57.0) + '@eslint-community/regexpp': 4.10.0 + '@eslint/eslintrc': 2.1.4 + '@eslint/js': 8.57.0 + '@humanwhocodes/config-array': 0.11.14 + '@humanwhocodes/module-importer': 1.0.1 + '@nodelib/fs.walk': 1.2.8 + '@ungap/structured-clone': 1.2.0 + ajv: 6.12.6 + chalk: 4.1.2 + cross-spawn: 7.0.3 + debug: 4.3.4 + doctrine: 3.0.0 + escape-string-regexp: 4.0.0 + eslint-scope: 7.2.2 + eslint-visitor-keys: 3.4.3 + espree: 9.6.1 + esquery: 1.5.0 + esutils: 2.0.3 + fast-deep-equal: 3.1.3 + file-entry-cache: 6.0.1 + find-up: 5.0.0 + glob-parent: 6.0.2 + globals: 13.24.0 + graphemer: 1.4.0 + ignore: 5.3.1 + imurmurhash: 0.1.4 + is-glob: 4.0.3 + is-path-inside: 3.0.3 + js-yaml: 4.1.0 + json-stable-stringify-without-jsonify: 1.0.1 + levn: 0.4.1 + lodash.merge: 4.6.2 + minimatch: 3.1.2 + natural-compare: 1.4.0 + optionator: 0.9.3 + strip-ansi: 6.0.1 + text-table: 0.2.0 + transitivePeerDependencies: + - supports-color + dev: true + + /espree@9.6.1: + resolution: {integrity: sha512-oruZaFkjorTpF32kDSI5/75ViwGeZginGGy2NoOSg3Q9bnwlnmDm4HLnkl0RE3n+njDXR037aY1+x58Z/zFdwQ==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + dependencies: + acorn: 8.11.3 + acorn-jsx: 5.3.2(acorn@8.11.3) + eslint-visitor-keys: 3.4.3 + dev: true + + /esprima@4.0.1: + resolution: {integrity: sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==} + engines: {node: '>=4'} + hasBin: true + dev: true + + /esquery@1.5.0: + resolution: {integrity: sha512-YQLXUplAwJgCydQ78IMJywZCceoqk1oH01OERdSAJc/7U2AylwjhSCLDEtqwg811idIS/9fIU5GjG73IgjKMVg==} + engines: {node: '>=0.10'} + dependencies: + estraverse: 5.3.0 + dev: true + + /esrecurse@4.3.0: + resolution: {integrity: sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==} + engines: {node: '>=4.0'} + dependencies: + estraverse: 5.3.0 + dev: true + + /estraverse@4.3.0: + resolution: {integrity: sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==} + engines: {node: '>=4.0'} + dev: true + + /estraverse@5.3.0: + resolution: {integrity: sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==} + engines: {node: '>=4.0'} + dev: true + + /esutils@2.0.3: + resolution: {integrity: sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==} + engines: {node: '>=0.10.0'} + dev: true + + /execa@5.1.1: + resolution: {integrity: sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==} + engines: {node: '>=10'} + dependencies: + cross-spawn: 7.0.3 + get-stream: 6.0.1 + human-signals: 2.1.0 + is-stream: 2.0.1 + merge-stream: 2.0.0 + npm-run-path: 4.0.1 + onetime: 5.1.2 + signal-exit: 3.0.7 + strip-final-newline: 2.0.0 + dev: true + + /exit@0.1.2: + resolution: {integrity: sha512-Zk/eNKV2zbjpKzrsQ+n1G6poVbErQxJ0LBOJXaKZ1EViLzH+hrLu9cdXI4zw9dBQJslwBEpbQ2P1oS7nDxs6jQ==} + engines: {node: '>= 0.8.0'} + dev: true + + /expect@29.7.0: + resolution: {integrity: sha512-2Zks0hf1VLFYI1kbh0I5jP3KHHyCHpkfyHBzsSXRFgl/Bg9mWYfMW8oD+PdMPlEwy5HNsR9JutYy6pMeOh61nw==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + dependencies: + '@jest/expect-utils': 29.7.0 + jest-get-type: 29.6.3 + jest-matcher-utils: 29.7.0 + jest-message-util: 29.7.0 + jest-util: 29.7.0 + dev: true + + /fast-deep-equal@3.1.3: + resolution: {integrity: sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==} + dev: true + + /fast-diff@1.3.0: + resolution: {integrity: sha512-VxPP4NqbUjj6MaAOafWeUn2cXWLcCtljklUtZf0Ind4XQ+QPtmA0b18zZy0jIQx+ExRVCR/ZQpBmik5lXshNsw==} + dev: true + + /fast-glob@3.3.2: + resolution: {integrity: sha512-oX2ruAFQwf/Orj8m737Y5adxDQO0LAB7/S5MnxCdTNDd4p6BsyIVsv9JQsATbTSq8KHRpLwIHbVlUNatxd+1Ow==} + engines: {node: '>=8.6.0'} + dependencies: + '@nodelib/fs.stat': 2.0.5 + '@nodelib/fs.walk': 1.2.8 + glob-parent: 5.1.2 + merge2: 1.4.1 + micromatch: 4.0.5 + dev: true + + /fast-json-stable-stringify@2.1.0: + resolution: {integrity: sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==} + dev: true + + /fast-levenshtein@2.0.6: + resolution: {integrity: sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==} + dev: true + + /fastq@1.17.1: + resolution: {integrity: sha512-sRVD3lWVIXWg6By68ZN7vho9a1pQcN/WBFaAAsDDFzlJjvoGx0P8z7V1t72grFJfJhu3YPZBuu25f7Kaw2jN1w==} + dependencies: + reusify: 1.0.4 + dev: true + + /fb-watchman@2.0.2: + resolution: {integrity: sha512-p5161BqbuCaSnB8jIbzQHOlpgsPmK5rJVDfDKO91Axs5NC1uu3HRQm6wt9cd9/+GtQQIO53JdGXXoyDpTAsgYA==} + dependencies: + bser: 2.1.1 + dev: true + + /file-entry-cache@6.0.1: + resolution: {integrity: sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==} + engines: {node: ^10.12.0 || >=12.0.0} + dependencies: + flat-cache: 3.2.0 + dev: true + + /fill-range@7.0.1: + resolution: {integrity: sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==} + engines: {node: '>=8'} + dependencies: + to-regex-range: 5.0.1 + dev: true + + /find-up@4.1.0: + resolution: {integrity: sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==} + engines: {node: '>=8'} + dependencies: + locate-path: 5.0.0 + path-exists: 4.0.0 + dev: true + + /find-up@5.0.0: + resolution: {integrity: sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==} + engines: {node: '>=10'} + dependencies: + locate-path: 6.0.0 + path-exists: 4.0.0 + dev: true + + /flat-cache@3.2.0: + resolution: {integrity: sha512-CYcENa+FtcUKLmhhqyctpclsq7QF38pKjZHsGNiSQF5r4FtoKDWabFDl3hzaEQMvT1LHEysw5twgLvpYYb4vbw==} + engines: {node: ^10.12.0 || >=12.0.0} + dependencies: + flatted: 3.3.1 + keyv: 4.5.4 + rimraf: 3.0.2 + dev: true + + /flatted@3.3.1: + resolution: {integrity: sha512-X8cqMLLie7KsNUDSdzeN8FYK9rEt4Dt67OsG/DNGnYTSDBG4uFAJFBnUeiV+zCVAvwFy56IjM9sH51jVaEhNxw==} + dev: true + + /for-each@0.3.3: + resolution: {integrity: sha512-jqYfLp7mo9vIyQf8ykW2v7A+2N4QjeCeI5+Dz9XraiO1ign81wjiH7Fb9vSOWvQfNtmSa4H2RoQTrrXivdUZmw==} + dependencies: + is-callable: 1.2.7 + dev: true + + /foreground-child@3.1.1: + resolution: {integrity: sha512-TMKDUnIte6bfb5nWv7V/caI169OHgvwjb7V4WkeUvbQQdjr5rWKqHFiKWb/fcOwB+CzBT+qbWjvj+DVwRskpIg==} + engines: {node: '>=14'} + dependencies: + cross-spawn: 7.0.3 + signal-exit: 4.1.0 + dev: true + + /fs.realpath@1.0.0: + resolution: {integrity: sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==} + dev: true + + /fsevents@2.3.2: + resolution: {integrity: sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==} + engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0} + os: [darwin] + requiresBuild: true + dev: true + optional: true + + /fsevents@2.3.3: + resolution: {integrity: sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==} + engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0} + os: [darwin] + requiresBuild: true + dev: true + optional: true + + /function-bind@1.1.2: + resolution: {integrity: sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==} + dev: true + + /function.prototype.name@1.1.6: + resolution: {integrity: sha512-Z5kx79swU5P27WEayXM1tBi5Ze/lbIyiNgU3qyXUOf9b2rgXYyF9Dy9Cx+IQv/Lc8WCG6L82zwUPpSS9hGehIg==} + engines: {node: '>= 0.4'} + dependencies: + call-bind: 1.0.7 + define-properties: 1.2.1 + es-abstract: 1.23.3 + functions-have-names: 1.2.3 + dev: true + + /functions-have-names@1.2.3: + resolution: {integrity: sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==} + dev: true + + /gensync@1.0.0-beta.2: + resolution: {integrity: sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==} + engines: {node: '>=6.9.0'} + dev: true + + /get-caller-file@2.0.5: + resolution: {integrity: sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==} + engines: {node: 6.* || 8.* || >= 10.*} + dev: true + + /get-intrinsic@1.2.4: + resolution: {integrity: sha512-5uYhsJH8VJBTv7oslg4BznJYhDoRI6waYCxMmCdnTrcCrHA/fCFKoTFz2JKKE0HdDFUF7/oQuhzumXJK7paBRQ==} + engines: {node: '>= 0.4'} + dependencies: + es-errors: 1.3.0 + function-bind: 1.1.2 + has-proto: 1.0.3 + has-symbols: 1.0.3 + hasown: 2.0.2 + dev: true + + /get-package-type@0.1.0: + resolution: {integrity: sha512-pjzuKtY64GYfWizNAJ0fr9VqttZkNiK2iS430LtIHzjBEr6bX8Am2zm4sW4Ro5wjWW5cAlRL1qAMTcXbjNAO2Q==} + engines: {node: '>=8.0.0'} + dev: true + + /get-stream@6.0.1: + resolution: {integrity: sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==} + engines: {node: '>=10'} + dev: true + + /get-symbol-description@1.0.2: + resolution: {integrity: sha512-g0QYk1dZBxGwk+Ngc+ltRH2IBp2f7zBkBMBJZCDerh6EhlhSR6+9irMCuT/09zD6qkarHUSn529sK/yL4S27mg==} + engines: {node: '>= 0.4'} + dependencies: + call-bind: 1.0.7 + es-errors: 1.3.0 + get-intrinsic: 1.2.4 + dev: true + + /glob-parent@5.1.2: + resolution: {integrity: sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==} + engines: {node: '>= 6'} + dependencies: + is-glob: 4.0.3 + dev: true + + /glob-parent@6.0.2: + resolution: {integrity: sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==} + engines: {node: '>=10.13.0'} + dependencies: + is-glob: 4.0.3 + dev: true + + /glob@10.3.12: + resolution: {integrity: sha512-TCNv8vJ+xz4QiqTpfOJA7HvYv+tNIRHKfUWw/q+v2jdgN4ebz+KY9tGx5J4rHP0o84mNP+ApH66HRX8us3Khqg==} + engines: {node: '>=16 || 14 >=14.17'} + hasBin: true + dependencies: + foreground-child: 3.1.1 + jackspeak: 2.3.6 + minimatch: 9.0.4 + minipass: 7.0.4 + path-scurry: 1.10.2 + dev: true + + /glob@7.2.3: + resolution: {integrity: sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==} + dependencies: + fs.realpath: 1.0.0 + inflight: 1.0.6 + inherits: 2.0.4 + minimatch: 3.1.2 + once: 1.4.0 + path-is-absolute: 1.0.1 + dev: true + + /globals@11.12.0: + resolution: {integrity: sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==} + engines: {node: '>=4'} + dev: true + + /globals@13.24.0: + resolution: {integrity: sha512-AhO5QUcj8llrbG09iWhPU2B204J1xnPeL8kQmVorSsy+Sjj1sk8gIyh6cUocGmH4L0UuhAJy+hJMRA4mgA4mFQ==} + engines: {node: '>=8'} + dependencies: + type-fest: 0.20.2 + dev: true + + /globalthis@1.0.3: + resolution: {integrity: sha512-sFdI5LyBiNTHjRd7cGPWapiHWMOXKyuBNX/cWJ3NfzrZQVa8GI/8cofCl74AOVqq9W5kNmguTIzJ/1s2gyI9wA==} + engines: {node: '>= 0.4'} + dependencies: + define-properties: 1.2.1 + dev: true + + /globby@11.1.0: + resolution: {integrity: sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==} + engines: {node: '>=10'} + dependencies: + array-union: 2.1.0 + dir-glob: 3.0.1 + fast-glob: 3.3.2 + ignore: 5.3.1 + merge2: 1.4.1 + slash: 3.0.0 + dev: true + + /gopd@1.0.1: + resolution: {integrity: sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==} + dependencies: + get-intrinsic: 1.2.4 + dev: true + + /graceful-fs@4.2.11: + resolution: {integrity: sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==} + dev: true + + /graphemer@1.4.0: + resolution: {integrity: sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==} + dev: true + + /has-bigints@1.0.2: + resolution: {integrity: sha512-tSvCKtBr9lkF0Ex0aQiP9N+OpV4zi2r/Nee5VkRDbaqv35RLYMzbwQfFSZZH0kR+Rd6302UJZ2p/bJCEoR3VoQ==} + dev: true + + /has-flag@3.0.0: + resolution: {integrity: sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==} + engines: {node: '>=4'} + dev: true + + /has-flag@4.0.0: + resolution: {integrity: sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==} + engines: {node: '>=8'} + dev: true + + /has-property-descriptors@1.0.2: + resolution: {integrity: sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==} + dependencies: + es-define-property: 1.0.0 + dev: true + + /has-proto@1.0.3: + resolution: {integrity: sha512-SJ1amZAJUiZS+PhsVLf5tGydlaVB8EdFpaSO4gmiUKUOxk8qzn5AIy4ZeJUmh22znIdk/uMAUT2pl3FxzVUH+Q==} + engines: {node: '>= 0.4'} + dev: true + + /has-symbols@1.0.3: + resolution: {integrity: sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==} + engines: {node: '>= 0.4'} + dev: true + + /has-tostringtag@1.0.2: + resolution: {integrity: sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==} + engines: {node: '>= 0.4'} + dependencies: + has-symbols: 1.0.3 + dev: true + + /hasown@2.0.2: + resolution: {integrity: sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==} + engines: {node: '>= 0.4'} + dependencies: + function-bind: 1.1.2 + dev: true + + /header-case@2.0.4: + resolution: {integrity: sha512-H/vuk5TEEVZwrR0lp2zed9OCo1uAILMlx0JEMgC26rzyJJ3N1v6XkwHHXJQdR2doSjcGPM6OKPYoJgf0plJ11Q==} + dependencies: + capital-case: 1.0.4 + tslib: 2.6.2 + dev: true + + /hi-base32@0.5.1: + resolution: {integrity: sha512-EmBBpvdYh/4XxsnUybsPag6VikPYnN30td+vQk+GI3qpahVEG9+gTkG0aXVxTjBqQ5T6ijbWIu77O+C5WFWsnA==} + + /html-escaper@2.0.2: + resolution: {integrity: sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==} + dev: true + + /human-signals@2.1.0: + resolution: {integrity: sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==} + engines: {node: '>=10.17.0'} + dev: true + + /ieee754@1.2.1: + resolution: {integrity: sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==} + + /ignore@5.3.1: + resolution: {integrity: sha512-5Fytz/IraMjqpwfd34ke28PTVMjZjJG2MPn5t7OE4eUCUNf8BAa7b5WUS9/Qvr6mwOQS7Mk6vdsMno5he+T8Xw==} + engines: {node: '>= 4'} + dev: true + + /import-fresh@3.3.0: + resolution: {integrity: sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==} + engines: {node: '>=6'} + dependencies: + parent-module: 1.0.1 + resolve-from: 4.0.0 + dev: true + + /import-local@3.1.0: + resolution: {integrity: sha512-ASB07uLtnDs1o6EHjKpX34BKYDSqnFerfTOJL2HvMqF70LnxpjkzDB8J44oT9pu4AMPkQwf8jl6szgvNd2tRIg==} + engines: {node: '>=8'} + hasBin: true + dependencies: + pkg-dir: 4.2.0 + resolve-cwd: 3.0.0 + dev: true + + /imurmurhash@0.1.4: + resolution: {integrity: sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==} + engines: {node: '>=0.8.19'} + dev: true + + /inflight@1.0.6: + resolution: {integrity: sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==} + dependencies: + once: 1.4.0 + wrappy: 1.0.2 + dev: true + + /inherits@2.0.4: + resolution: {integrity: sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==} + dev: true + + /internal-slot@1.0.7: + resolution: {integrity: sha512-NGnrKwXzSms2qUUih/ILZ5JBqNTSa1+ZmP6flaIp6KmSElgE9qdndzS3cqjrDovwFdmwsGsLdeFgB6suw+1e9g==} + engines: {node: '>= 0.4'} + dependencies: + es-errors: 1.3.0 + hasown: 2.0.2 + side-channel: 1.0.6 + dev: true + + /is-array-buffer@3.0.4: + resolution: {integrity: sha512-wcjaerHw0ydZwfhiKbXJWLDY8A7yV7KhjQOpb83hGgGfId/aQa4TOvwyzn2PuswW2gPCYEL/nEAiSVpdOj1lXw==} + engines: {node: '>= 0.4'} + dependencies: + call-bind: 1.0.7 + get-intrinsic: 1.2.4 + dev: true + + /is-arrayish@0.2.1: + resolution: {integrity: sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==} + dev: true + + /is-bigint@1.0.4: + resolution: {integrity: sha512-zB9CruMamjym81i2JZ3UMn54PKGsQzsJeo6xvN3HJJ4CAsQNB6iRutp2To77OfCNuoxspsIhzaPoO1zyCEhFOg==} + dependencies: + has-bigints: 1.0.2 + dev: true + + /is-boolean-object@1.1.2: + resolution: {integrity: sha512-gDYaKHJmnj4aWxyj6YHyXVpdQawtVLHU5cb+eztPGczf6cjuTdwve5ZIEfgXqH4e57An1D1AKf8CZ3kYrQRqYA==} + engines: {node: '>= 0.4'} + dependencies: + call-bind: 1.0.7 + has-tostringtag: 1.0.2 + dev: true + + /is-callable@1.2.7: + resolution: {integrity: sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==} + engines: {node: '>= 0.4'} + dev: true + + /is-core-module@2.13.1: + resolution: {integrity: sha512-hHrIjvZsftOsvKSn2TRYl63zvxsgE0K+0mYMoH6gD4omR5IWB2KynivBQczo3+wF1cCkjzvptnI9Q0sPU66ilw==} + dependencies: + hasown: 2.0.2 + dev: true + + /is-data-view@1.0.1: + resolution: {integrity: sha512-AHkaJrsUVW6wq6JS8y3JnM/GJF/9cf+k20+iDzlSaJrinEo5+7vRiteOSwBhHRiAyQATN1AmY4hwzxJKPmYf+w==} + engines: {node: '>= 0.4'} + dependencies: + is-typed-array: 1.1.13 + dev: true + + /is-date-object@1.0.5: + resolution: {integrity: sha512-9YQaSxsAiSwcvS33MBk3wTCVnWK+HhF8VZR2jRxehM16QcVOdHqPn4VPHmRK4lSr38n9JriurInLcP90xsYNfQ==} + engines: {node: '>= 0.4'} + dependencies: + has-tostringtag: 1.0.2 + dev: true + + /is-extglob@2.1.1: + resolution: {integrity: sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==} + engines: {node: '>=0.10.0'} + dev: true + + /is-fullwidth-code-point@3.0.0: + resolution: {integrity: sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==} + engines: {node: '>=8'} + dev: true + + /is-generator-fn@2.1.0: + resolution: {integrity: sha512-cTIB4yPYL/Grw0EaSzASzg6bBy9gqCofvWN8okThAYIxKJZC+udlRAmGbM0XLeniEJSs8uEgHPGuHSe1XsOLSQ==} + engines: {node: '>=6'} + dev: true + + /is-glob@4.0.3: + resolution: {integrity: sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==} + engines: {node: '>=0.10.0'} + dependencies: + is-extglob: 2.1.1 + dev: true + + /is-negative-zero@2.0.3: + resolution: {integrity: sha512-5KoIu2Ngpyek75jXodFvnafB6DJgr3u8uuK0LEZJjrU19DrMD3EVERaR8sjz8CCGgpZvxPl9SuE1GMVPFHx1mw==} + engines: {node: '>= 0.4'} + dev: true + + /is-number-object@1.0.7: + resolution: {integrity: sha512-k1U0IRzLMo7ZlYIfzRu23Oh6MiIFasgpb9X76eqfFZAqwH44UI4KTBvBYIZ1dSL9ZzChTB9ShHfLkR4pdW5krQ==} + engines: {node: '>= 0.4'} + dependencies: + has-tostringtag: 1.0.2 + dev: true + + /is-number@7.0.0: + resolution: {integrity: sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==} + engines: {node: '>=0.12.0'} + dev: true + + /is-path-inside@3.0.3: + resolution: {integrity: sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==} + engines: {node: '>=8'} + dev: true + + /is-regex@1.1.4: + resolution: {integrity: sha512-kvRdxDsxZjhzUX07ZnLydzS1TU/TJlTUHHY4YLL87e37oUA49DfkLqgy+VjFocowy29cKvcSiu+kIv728jTTVg==} + engines: {node: '>= 0.4'} + dependencies: + call-bind: 1.0.7 + has-tostringtag: 1.0.2 + dev: true + + /is-shared-array-buffer@1.0.3: + resolution: {integrity: sha512-nA2hv5XIhLR3uVzDDfCIknerhx8XUKnstuOERPNNIinXG7v9u+ohXF67vxm4TPTEPU6lm61ZkwP3c9PCB97rhg==} + engines: {node: '>= 0.4'} + dependencies: + call-bind: 1.0.7 + dev: true + + /is-stream@2.0.1: + resolution: {integrity: sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==} + engines: {node: '>=8'} + dev: true + + /is-string@1.0.7: + resolution: {integrity: sha512-tE2UXzivje6ofPW7l23cjDOMa09gb7xlAqG6jG5ej6uPV32TlWP3NKPigtaGeHNu9fohccRYvIiZMfOOnOYUtg==} + engines: {node: '>= 0.4'} + dependencies: + has-tostringtag: 1.0.2 + dev: true + + /is-symbol@1.0.4: + resolution: {integrity: sha512-C/CPBqKWnvdcxqIARxyOh4v1UUEOCHpgDa0WYgpKDFMszcrPcffg5uhwSgPCLD2WWxmq6isisz87tzT01tuGhg==} + engines: {node: '>= 0.4'} + dependencies: + has-symbols: 1.0.3 + dev: true + + /is-typed-array@1.1.13: + resolution: {integrity: sha512-uZ25/bUAlUY5fR4OKT4rZQEBrzQWYV9ZJYGGsUmEJ6thodVJ1HX64ePQ6Z0qPWP+m+Uq6e9UugrE38jeYsDSMw==} + engines: {node: '>= 0.4'} + dependencies: + which-typed-array: 1.1.15 + dev: true + + /is-weakref@1.0.2: + resolution: {integrity: sha512-qctsuLZmIQ0+vSSMfoVvyFe2+GSEvnmZ2ezTup1SBse9+twCCeial6EEi3Nc2KFcf6+qz2FBPnjXsk8xhKSaPQ==} + dependencies: + call-bind: 1.0.7 + dev: true + + /isarray@2.0.5: + resolution: {integrity: sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==} + dev: true + + /isexe@2.0.0: + resolution: {integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==} + dev: true + + /istanbul-lib-coverage@3.2.2: + resolution: {integrity: sha512-O8dpsF+r0WV/8MNRKfnmrtCWhuKjxrq2w+jpzBL5UZKTi2LeVWnWOmWRxFlesJONmc+wLAGvKQZEOanko0LFTg==} + engines: {node: '>=8'} + dev: true + + /istanbul-lib-instrument@5.2.1: + resolution: {integrity: sha512-pzqtp31nLv/XFOzXGuvhCb8qhjmTVo5vjVk19XE4CRlSWz0KoeJ3bw9XsA7nOp9YBf4qHjwBxkDzKcME/J29Yg==} + engines: {node: '>=8'} + dependencies: + '@babel/core': 7.24.3 + '@babel/parser': 7.24.1 + '@istanbuljs/schema': 0.1.3 + istanbul-lib-coverage: 3.2.2 + semver: 6.3.1 + transitivePeerDependencies: + - supports-color + dev: true + + /istanbul-lib-instrument@6.0.2: + resolution: {integrity: sha512-1WUsZ9R1lA0HtBSohTkm39WTPlNKSJ5iFk7UwqXkBLoHQT+hfqPsfsTDVuZdKGaBwn7din9bS7SsnoAr943hvw==} + engines: {node: '>=10'} + dependencies: + '@babel/core': 7.24.3 + '@babel/parser': 7.24.1 + '@istanbuljs/schema': 0.1.3 + istanbul-lib-coverage: 3.2.2 + semver: 7.6.0 + transitivePeerDependencies: + - supports-color + dev: true + + /istanbul-lib-report@3.0.1: + resolution: {integrity: sha512-GCfE1mtsHGOELCU8e/Z7YWzpmybrx/+dSTfLrvY8qRmaY6zXTKWn6WQIjaAFw069icm6GVMNkgu0NzI4iPZUNw==} + engines: {node: '>=10'} + dependencies: + istanbul-lib-coverage: 3.2.2 + make-dir: 4.0.0 + supports-color: 7.2.0 + dev: true + + /istanbul-lib-source-maps@4.0.1: + resolution: {integrity: sha512-n3s8EwkdFIJCG3BPKBYvskgXGoy88ARzvegkitk60NxRdwltLOTaH7CUiMRXvwYorl0Q712iEjcWB+fK/MrWVw==} + engines: {node: '>=10'} + dependencies: + debug: 4.3.4 + istanbul-lib-coverage: 3.2.2 + source-map: 0.6.1 + transitivePeerDependencies: + - supports-color + dev: true + + /istanbul-reports@3.1.7: + resolution: {integrity: sha512-BewmUXImeuRk2YY0PVbxgKAysvhRPUQE0h5QRM++nVWyubKGV0l8qQ5op8+B2DOmwSe63Jivj0BjkPQVf8fP5g==} + engines: {node: '>=8'} + dependencies: + html-escaper: 2.0.2 + istanbul-lib-report: 3.0.1 + dev: true + + /jackspeak@2.3.6: + resolution: {integrity: sha512-N3yCS/NegsOBokc8GAdM8UcmfsKiSS8cipheD/nivzr700H+nsMOxJjQnvwOcRYVuFkdH0wGUvW2WbXGmrZGbQ==} + engines: {node: '>=14'} + dependencies: + '@isaacs/cliui': 8.0.2 + optionalDependencies: + '@pkgjs/parseargs': 0.11.0 + dev: true + + /jest-changed-files@29.7.0: + resolution: {integrity: sha512-fEArFiwf1BpQ+4bXSprcDc3/x4HSzL4al2tozwVpDFpsxALjLYdyiIK4e5Vz66GQJIbXJ82+35PtysofptNX2w==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + dependencies: + execa: 5.1.1 + jest-util: 29.7.0 + p-limit: 3.1.0 + dev: true + + /jest-circus@29.7.0: + resolution: {integrity: sha512-3E1nCMgipcTkCocFwM90XXQab9bS+GMsjdpmPrlelaxwD93Ad8iVEjX/vvHPdLPnFf+L40u+5+iutRdA1N9myw==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + dependencies: + '@jest/environment': 29.7.0 + '@jest/expect': 29.7.0 + '@jest/test-result': 29.7.0 + '@jest/types': 29.6.3 + '@types/node': 20.12.2 + chalk: 4.1.2 + co: 4.6.0 + dedent: 1.5.1 + is-generator-fn: 2.1.0 + jest-each: 29.7.0 + jest-matcher-utils: 29.7.0 + jest-message-util: 29.7.0 + jest-runtime: 29.7.0 + jest-snapshot: 29.7.0 + jest-util: 29.7.0 + p-limit: 3.1.0 + pretty-format: 29.7.0 + pure-rand: 6.1.0 + slash: 3.0.0 + stack-utils: 2.0.6 + transitivePeerDependencies: + - babel-plugin-macros + - supports-color + dev: true + + /jest-cli@29.7.0: + resolution: {integrity: sha512-OVVobw2IubN/GSYsxETi+gOe7Ka59EFMR/twOU3Jb2GnKKeMGJB5SGUUrEz3SFVmJASUdZUzy83sLNNQ2gZslg==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + hasBin: true + peerDependencies: + node-notifier: ^8.0.1 || ^9.0.0 || ^10.0.0 + peerDependenciesMeta: + node-notifier: + optional: true + dependencies: + '@jest/core': 29.7.0 + '@jest/test-result': 29.7.0 + '@jest/types': 29.6.3 + chalk: 4.1.2 + create-jest: 29.7.0 + exit: 0.1.2 + import-local: 3.1.0 + jest-config: 29.7.0(@types/node@20.12.2) + jest-util: 29.7.0 + jest-validate: 29.7.0 + yargs: 17.7.2 + transitivePeerDependencies: + - '@types/node' + - babel-plugin-macros + - supports-color + - ts-node + dev: true + + /jest-config@29.7.0(@types/node@20.12.2): + resolution: {integrity: sha512-uXbpfeQ7R6TZBqI3/TxCU4q4ttk3u0PJeC+E0zbfSoSjq6bJ7buBPxzQPL0ifrkY4DNu4JUdk0ImlBUYi840eQ==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + peerDependencies: + '@types/node': '*' + ts-node: '>=9.0.0' + peerDependenciesMeta: + '@types/node': + optional: true + ts-node: + optional: true + dependencies: + '@babel/core': 7.24.3 + '@jest/test-sequencer': 29.7.0 + '@jest/types': 29.6.3 + '@types/node': 20.12.2 + babel-jest: 29.7.0(@babel/core@7.24.3) + chalk: 4.1.2 + ci-info: 3.9.0 + deepmerge: 4.3.1 + glob: 7.2.3 + graceful-fs: 4.2.11 + jest-circus: 29.7.0 + jest-environment-node: 29.7.0 + jest-get-type: 29.6.3 + jest-regex-util: 29.6.3 + jest-resolve: 29.7.0 + jest-runner: 29.7.0 + jest-util: 29.7.0 + jest-validate: 29.7.0 + micromatch: 4.0.5 + parse-json: 5.2.0 + pretty-format: 29.7.0 + slash: 3.0.0 + strip-json-comments: 3.1.1 + transitivePeerDependencies: + - babel-plugin-macros + - supports-color + dev: true + + /jest-diff@29.7.0: + resolution: {integrity: sha512-LMIgiIrhigmPrs03JHpxUh2yISK3vLFPkAodPeo0+BuF7wA2FoQbkEg1u8gBYBThncu7e1oEDUfIXVuTqLRUjw==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + dependencies: + chalk: 4.1.2 + diff-sequences: 29.6.3 + jest-get-type: 29.6.3 + pretty-format: 29.7.0 + dev: true + + /jest-docblock@29.7.0: + resolution: {integrity: sha512-q617Auw3A612guyaFgsbFeYpNP5t2aoUNLwBUbc/0kD1R4t9ixDbyFTHd1nok4epoVFpr7PmeWHrhvuV3XaJ4g==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + dependencies: + detect-newline: 3.1.0 + dev: true + + /jest-each@29.7.0: + resolution: {integrity: sha512-gns+Er14+ZrEoC5fhOfYCY1LOHHr0TI+rQUHZS8Ttw2l7gl+80eHc/gFf2Ktkw0+SIACDTeWvpFcv3B04VembQ==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + dependencies: + '@jest/types': 29.6.3 + chalk: 4.1.2 + jest-get-type: 29.6.3 + jest-util: 29.7.0 + pretty-format: 29.7.0 + dev: true + + /jest-environment-node@29.7.0: + resolution: {integrity: sha512-DOSwCRqXirTOyheM+4d5YZOrWcdu0LNZ87ewUoywbcb2XR4wKgqiG8vNeYwhjFMbEkfju7wx2GYH0P2gevGvFw==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + dependencies: + '@jest/environment': 29.7.0 + '@jest/fake-timers': 29.7.0 + '@jest/types': 29.6.3 + '@types/node': 20.12.2 + jest-mock: 29.7.0 + jest-util: 29.7.0 + dev: true + + /jest-get-type@29.6.3: + resolution: {integrity: sha512-zrteXnqYxfQh7l5FHyL38jL39di8H8rHoecLH3JNxH3BwOrBsNeabdap5e0I23lD4HHI8W5VFBZqG4Eaq5LNcw==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + dev: true + + /jest-haste-map@29.7.0: + resolution: {integrity: sha512-fP8u2pyfqx0K1rGn1R9pyE0/KTn+G7PxktWidOBTqFPLYX0b9ksaMFkhK5vrS3DVun09pckLdlx90QthlW7AmA==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + dependencies: + '@jest/types': 29.6.3 + '@types/graceful-fs': 4.1.9 + '@types/node': 20.12.2 + anymatch: 3.1.3 + fb-watchman: 2.0.2 + graceful-fs: 4.2.11 + jest-regex-util: 29.6.3 + jest-util: 29.7.0 + jest-worker: 29.7.0 + micromatch: 4.0.5 + walker: 1.0.8 + optionalDependencies: + fsevents: 2.3.3 + dev: true + + /jest-leak-detector@29.7.0: + resolution: {integrity: sha512-kYA8IJcSYtST2BY9I+SMC32nDpBT3J2NvWJx8+JCuCdl/CR1I4EKUJROiP8XtCcxqgTTBGJNdbB1A8XRKbTetw==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + dependencies: + jest-get-type: 29.6.3 + pretty-format: 29.7.0 + dev: true + + /jest-matcher-utils@29.7.0: + resolution: {integrity: sha512-sBkD+Xi9DtcChsI3L3u0+N0opgPYnCRPtGcQYrgXmR+hmt/fYfWAL0xRXYU8eWOdfuLgBe0YCW3AFtnRLagq/g==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + dependencies: + chalk: 4.1.2 + jest-diff: 29.7.0 + jest-get-type: 29.6.3 + pretty-format: 29.7.0 + dev: true + + /jest-message-util@29.7.0: + resolution: {integrity: sha512-GBEV4GRADeP+qtB2+6u61stea8mGcOT4mCtrYISZwfu9/ISHFJ/5zOMXYbpBE9RsS5+Gb63DW4FgmnKJ79Kf6w==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + dependencies: + '@babel/code-frame': 7.24.2 + '@jest/types': 29.6.3 + '@types/stack-utils': 2.0.3 + chalk: 4.1.2 + graceful-fs: 4.2.11 + micromatch: 4.0.5 + pretty-format: 29.7.0 + slash: 3.0.0 + stack-utils: 2.0.6 + dev: true + + /jest-mock@29.7.0: + resolution: {integrity: sha512-ITOMZn+UkYS4ZFh83xYAOzWStloNzJFO2s8DWrE4lhtGD+AorgnbkiKERe4wQVBydIGPx059g6riW5Btp6Llnw==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + dependencies: + '@jest/types': 29.6.3 + '@types/node': 20.12.2 + jest-util: 29.7.0 + dev: true + + /jest-pnp-resolver@1.2.3(jest-resolve@29.7.0): + resolution: {integrity: sha512-+3NpwQEnRoIBtx4fyhblQDPgJI0H1IEIkX7ShLUjPGA7TtUTvI1oiKi3SR4oBR0hQhQR80l4WAe5RrXBwWMA8w==} + engines: {node: '>=6'} + peerDependencies: + jest-resolve: '*' + peerDependenciesMeta: + jest-resolve: + optional: true + dependencies: + jest-resolve: 29.7.0 + dev: true + + /jest-regex-util@29.6.3: + resolution: {integrity: sha512-KJJBsRCyyLNWCNBOvZyRDnAIfUiRJ8v+hOBQYGn8gDyF3UegwiP4gwRR3/SDa42g1YbVycTidUF3rKjyLFDWbg==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + dev: true + + /jest-resolve-dependencies@29.7.0: + resolution: {integrity: sha512-un0zD/6qxJ+S0et7WxeI3H5XSe9lTBBR7bOHCHXkKR6luG5mwDDlIzVQ0V5cZCuoTgEdcdwzTghYkTWfubi+nA==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + dependencies: + jest-regex-util: 29.6.3 + jest-snapshot: 29.7.0 + transitivePeerDependencies: + - supports-color + dev: true + + /jest-resolve@29.7.0: + resolution: {integrity: sha512-IOVhZSrg+UvVAshDSDtHyFCCBUl/Q3AAJv8iZ6ZjnZ74xzvwuzLXid9IIIPgTnY62SJjfuupMKZsZQRsCvxEgA==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + dependencies: + chalk: 4.1.2 + graceful-fs: 4.2.11 + jest-haste-map: 29.7.0 + jest-pnp-resolver: 1.2.3(jest-resolve@29.7.0) + jest-util: 29.7.0 + jest-validate: 29.7.0 + resolve: 1.22.8 + resolve.exports: 2.0.2 + slash: 3.0.0 + dev: true + + /jest-runner@29.7.0: + resolution: {integrity: sha512-fsc4N6cPCAahybGBfTRcq5wFR6fpLznMg47sY5aDpsoejOcVYFb07AHuSnR0liMcPTgBsA3ZJL6kFOjPdoNipQ==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + dependencies: + '@jest/console': 29.7.0 + '@jest/environment': 29.7.0 + '@jest/test-result': 29.7.0 + '@jest/transform': 29.7.0 + '@jest/types': 29.6.3 + '@types/node': 20.12.2 + chalk: 4.1.2 + emittery: 0.13.1 + graceful-fs: 4.2.11 + jest-docblock: 29.7.0 + jest-environment-node: 29.7.0 + jest-haste-map: 29.7.0 + jest-leak-detector: 29.7.0 + jest-message-util: 29.7.0 + jest-resolve: 29.7.0 + jest-runtime: 29.7.0 + jest-util: 29.7.0 + jest-watcher: 29.7.0 + jest-worker: 29.7.0 + p-limit: 3.1.0 + source-map-support: 0.5.13 + transitivePeerDependencies: + - supports-color + dev: true + + /jest-runtime@29.7.0: + resolution: {integrity: sha512-gUnLjgwdGqW7B4LvOIkbKs9WGbn+QLqRQQ9juC6HndeDiezIwhDP+mhMwHWCEcfQ5RUXa6OPnFF8BJh5xegwwQ==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + dependencies: + '@jest/environment': 29.7.0 + '@jest/fake-timers': 29.7.0 + '@jest/globals': 29.7.0 + '@jest/source-map': 29.6.3 + '@jest/test-result': 29.7.0 + '@jest/transform': 29.7.0 + '@jest/types': 29.6.3 + '@types/node': 20.12.2 + chalk: 4.1.2 + cjs-module-lexer: 1.2.3 + collect-v8-coverage: 1.0.2 + glob: 7.2.3 + graceful-fs: 4.2.11 + jest-haste-map: 29.7.0 + jest-message-util: 29.7.0 + jest-mock: 29.7.0 + jest-regex-util: 29.6.3 + jest-resolve: 29.7.0 + jest-snapshot: 29.7.0 + jest-util: 29.7.0 + slash: 3.0.0 + strip-bom: 4.0.0 + transitivePeerDependencies: + - supports-color + dev: true + + /jest-snapshot@29.7.0: + resolution: {integrity: sha512-Rm0BMWtxBcioHr1/OX5YCP8Uov4riHvKPknOGs804Zg9JGZgmIBkbtlxJC/7Z4msKYVbIJtfU+tKb8xlYNfdkw==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + dependencies: + '@babel/core': 7.24.3 + '@babel/generator': 7.24.1 + '@babel/plugin-syntax-jsx': 7.24.1(@babel/core@7.24.3) + '@babel/plugin-syntax-typescript': 7.24.1(@babel/core@7.24.3) + '@babel/types': 7.24.0 + '@jest/expect-utils': 29.7.0 + '@jest/transform': 29.7.0 + '@jest/types': 29.6.3 + babel-preset-current-node-syntax: 1.0.1(@babel/core@7.24.3) + chalk: 4.1.2 + expect: 29.7.0 + graceful-fs: 4.2.11 + jest-diff: 29.7.0 + jest-get-type: 29.6.3 + jest-matcher-utils: 29.7.0 + jest-message-util: 29.7.0 + jest-util: 29.7.0 + natural-compare: 1.4.0 + pretty-format: 29.7.0 + semver: 7.6.0 + transitivePeerDependencies: + - supports-color + dev: true + + /jest-util@29.7.0: + resolution: {integrity: sha512-z6EbKajIpqGKU56y5KBUgy1dt1ihhQJgWzUlZHArA/+X2ad7Cb5iF+AK1EWVL/Bo7Rz9uurpqw6SiBCefUbCGA==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + dependencies: + '@jest/types': 29.6.3 + '@types/node': 20.12.2 + chalk: 4.1.2 + ci-info: 3.9.0 + graceful-fs: 4.2.11 + picomatch: 2.3.1 + dev: true + + /jest-validate@29.7.0: + resolution: {integrity: sha512-ZB7wHqaRGVw/9hST/OuFUReG7M8vKeq0/J2egIGLdvjHCmYqGARhzXmtgi+gVeZ5uXFF219aOc3Ls2yLg27tkw==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + dependencies: + '@jest/types': 29.6.3 + camelcase: 6.3.0 + chalk: 4.1.2 + jest-get-type: 29.6.3 + leven: 3.1.0 + pretty-format: 29.7.0 + dev: true + + /jest-watcher@29.7.0: + resolution: {integrity: sha512-49Fg7WXkU3Vl2h6LbLtMQ/HyB6rXSIX7SqvBLQmssRBGN9I0PNvPmAmCWSOY6SOvrjhI/F7/bGAv9RtnsPA03g==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + dependencies: + '@jest/test-result': 29.7.0 + '@jest/types': 29.6.3 + '@types/node': 20.12.2 + ansi-escapes: 4.3.2 + chalk: 4.1.2 + emittery: 0.13.1 + jest-util: 29.7.0 + string-length: 4.0.2 + dev: true + + /jest-worker@29.7.0: + resolution: {integrity: sha512-eIz2msL/EzL9UFTFFx7jBTkeZfku0yUAyZZZmJ93H2TYEiroIx2PQjEXcwYtYl8zXCxb+PAmA2hLIt/6ZEkPHw==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + dependencies: + '@types/node': 20.12.2 + jest-util: 29.7.0 + merge-stream: 2.0.0 + supports-color: 8.1.1 + dev: true + + /jest@29.7.0: + resolution: {integrity: sha512-NIy3oAFp9shda19hy4HK0HRTWKtPJmGdnvywu01nOqNC2vZg+Z+fvJDxpMQA88eb2I9EcafcdjYgsDthnYTvGw==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + hasBin: true + peerDependencies: + node-notifier: ^8.0.1 || ^9.0.0 || ^10.0.0 + peerDependenciesMeta: + node-notifier: + optional: true + dependencies: + '@jest/core': 29.7.0 + '@jest/types': 29.6.3 + import-local: 3.1.0 + jest-cli: 29.7.0 + transitivePeerDependencies: + - '@types/node' + - babel-plugin-macros + - supports-color + - ts-node + dev: true + + /js-sha256@0.9.0: + resolution: {integrity: sha512-sga3MHh9sgQN2+pJ9VYZ+1LPwXOxuBJBA5nrR5/ofPfuiJBE2hnjsaN8se8JznOmGLN2p49Pe5U/ttafcs/apA==} + + /js-sha3@0.8.0: + resolution: {integrity: sha512-gF1cRrHhIzNfToc802P800N8PpXS+evLLXfsVpowqmAFR9uwbi89WvXg2QspOmXL8QL86J4T1EpFu+yUkwJY3Q==} + + /js-sha512@0.8.0: + resolution: {integrity: sha512-PWsmefG6Jkodqt+ePTvBZCSMFgN7Clckjd0O7su3I0+BW2QWUTJNzjktHsztGLhncP2h8mcF9V9Y2Ha59pAViQ==} + + /js-tokens@4.0.0: + resolution: {integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==} + dev: true + + /js-yaml@3.14.1: + resolution: {integrity: sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==} + hasBin: true + dependencies: + argparse: 1.0.10 + esprima: 4.0.1 + dev: true + + /js-yaml@4.1.0: + resolution: {integrity: sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==} + hasBin: true + dependencies: + argparse: 2.0.1 + dev: true + + /jsesc@2.5.2: + resolution: {integrity: sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==} + engines: {node: '>=4'} + hasBin: true + dev: true + + /json-bigint@1.0.0: + resolution: {integrity: sha512-SiPv/8VpZuWbvLSMtTDU8hEfrZWg/mH/nV/b4o0CYbSxu1UIQPLdwKOCIyLQX+VIPO5vrLX3i8qtqFyhdPSUSQ==} + dependencies: + bignumber.js: 9.1.2 + + /json-buffer@3.0.1: + resolution: {integrity: sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==} + dev: true + + /json-parse-even-better-errors@2.3.1: + resolution: {integrity: sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==} + dev: true + + /json-schema-traverse@0.4.1: + resolution: {integrity: sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==} + dev: true + + /json-stable-stringify-without-jsonify@1.0.1: + resolution: {integrity: sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==} + dev: true + + /json5@1.0.2: + resolution: {integrity: sha512-g1MWMLBiz8FKi1e4w0UyVL3w+iJceWAFBAaBnnGKOpNa5f8TLktkbre1+s6oICydWAm+HRUGTmI+//xv2hvXYA==} + hasBin: true + dependencies: + minimist: 1.2.8 + dev: true + + /json5@2.2.3: + resolution: {integrity: sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==} + engines: {node: '>=6'} + hasBin: true + dev: true + + /jsonschema@1.4.1: + resolution: {integrity: sha512-S6cATIPVv1z0IlxdN+zUk5EPjkGCdnhN4wVSBlvoUO1tOLJootbo9CquNJmbIh4yikWHiUedhRYrNPn1arpEmQ==} + dev: true + + /keyv@4.5.4: + resolution: {integrity: sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==} + dependencies: + json-buffer: 3.0.1 + dev: true + + /kleur@3.0.3: + resolution: {integrity: sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w==} + engines: {node: '>=6'} + dev: true + + /leven@3.1.0: + resolution: {integrity: sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A==} + engines: {node: '>=6'} + dev: true + + /levn@0.4.1: + resolution: {integrity: sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==} + engines: {node: '>= 0.8.0'} + dependencies: + prelude-ls: 1.2.1 + type-check: 0.4.0 + dev: true + + /lines-and-columns@1.2.4: + resolution: {integrity: sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==} + dev: true + + /locate-path@5.0.0: + resolution: {integrity: sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==} + engines: {node: '>=8'} + dependencies: + p-locate: 4.1.0 + dev: true + + /locate-path@6.0.0: + resolution: {integrity: sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==} + engines: {node: '>=10'} + dependencies: + p-locate: 5.0.0 + dev: true + + /lodash.memoize@4.1.2: + resolution: {integrity: sha512-t7j+NzmgnQzTAYXcsHYLgimltOV1MXHtlOWf6GjL9Kj8GK5FInw5JotxvbOs+IvV1/Dzo04/fCGfLVs7aXb4Ag==} + dev: true + + /lodash.merge@4.6.2: + resolution: {integrity: sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==} + dev: true + + /lower-case@2.0.2: + resolution: {integrity: sha512-7fm3l3NAF9WfN6W3JOmf5drwpVqX78JtoGJ3A6W0a6ZnldM41w2fV5D490psKFTpMds8TJse/eHLFFsNHHjHgg==} + dependencies: + tslib: 2.6.2 + dev: true + + /lru-cache@10.2.0: + resolution: {integrity: sha512-2bIM8x+VAf6JT4bKAljS1qUWgMsqZRPGJS6FSahIMPVvctcNhyVp7AJu7quxOW9jwkryBReKZY5tY5JYv2n/7Q==} + engines: {node: 14 || >=16.14} + dev: true + + /lru-cache@5.1.1: + resolution: {integrity: sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==} + dependencies: + yallist: 3.1.1 + dev: true + + /lru-cache@6.0.0: + resolution: {integrity: sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==} + engines: {node: '>=10'} + dependencies: + yallist: 4.0.0 + dev: true + + /make-dir@4.0.0: + resolution: {integrity: sha512-hXdUTZYIVOt1Ex//jAQi+wTZZpUpwBj/0QsOzqegb3rGMMeJiSEu5xLHnYfBrRV4RH2+OCSOO95Is/7x1WJ4bw==} + engines: {node: '>=10'} + dependencies: + semver: 7.6.0 + dev: true + + /make-error@1.3.6: + resolution: {integrity: sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==} + dev: true + + /makeerror@1.0.12: + resolution: {integrity: sha512-JmqCvUhmt43madlpFzG4BQzG2Z3m6tvQDNKdClZnO3VbIudJYmxsT0FNJMeiB2+JTSlTQTSbU8QdesVmwJcmLg==} + dependencies: + tmpl: 1.0.5 + dev: true + + /merge-stream@2.0.0: + resolution: {integrity: sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==} + dev: true + + /merge2@1.4.1: + resolution: {integrity: sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==} + engines: {node: '>= 8'} + dev: true + + /micromatch@4.0.5: + resolution: {integrity: sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==} + engines: {node: '>=8.6'} + dependencies: + braces: 3.0.2 + picomatch: 2.3.1 + dev: true + + /mimic-fn@2.1.0: + resolution: {integrity: sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==} + engines: {node: '>=6'} + dev: true + + /minimatch@3.1.2: + resolution: {integrity: sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==} + dependencies: + brace-expansion: 1.1.11 + dev: true + + /minimatch@7.4.6: + resolution: {integrity: sha512-sBz8G/YjVniEz6lKPNpKxXwazJe4c19fEfV2GDMX6AjFz+MX9uDWIZW8XreVhkFW3fkIdTv/gxWr/Kks5FFAVw==} + engines: {node: '>=10'} + dependencies: + brace-expansion: 2.0.1 + dev: true + + /minimatch@9.0.4: + resolution: {integrity: sha512-KqWh+VchfxcMNRAJjj2tnsSJdNbHsVgnkBhTNrW7AjVo6OvLtxw8zfT9oLw1JSohlFzJ8jCoTgaoXvJ+kHt6fw==} + engines: {node: '>=16 || 14 >=14.17'} + dependencies: + brace-expansion: 2.0.1 + dev: true + + /minimist@1.2.8: + resolution: {integrity: sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==} + dev: true + + /minipass@7.0.4: + resolution: {integrity: sha512-jYofLM5Dam9279rdkWzqHozUo4ybjdZmCsDHePy5V/PbBcVMiSZR97gmAy45aqi8CK1lG2ECd356FU86avfwUQ==} + engines: {node: '>=16 || 14 >=14.17'} + dev: true + + /mkdirp@2.1.6: + resolution: {integrity: sha512-+hEnITedc8LAtIP9u3HJDFIdcLV2vXP33sqLLIzkv1Db1zO/1OxbvYf0Y1OC/S/Qo5dxHXepofhmxL02PsKe+A==} + engines: {node: '>=10'} + hasBin: true + dev: true + + /ms@2.1.2: + resolution: {integrity: sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==} + dev: true + + /ms@2.1.3: + resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==} + dev: true + + /natural-compare-lite@1.4.0: + resolution: {integrity: sha512-Tj+HTDSJJKaZnfiuw+iaF9skdPpTo2GtEly5JHnWV/hfv2Qj/9RKsGISQtLh2ox3l5EAGw487hnBee0sIJ6v2g==} + dev: true + + /natural-compare@1.4.0: + resolution: {integrity: sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==} + dev: true + + /no-case@3.0.4: + resolution: {integrity: sha512-fgAN3jGAh+RoxUGZHTSOLJIqUc2wmoBwGR4tbpNAKmmovFoWq0OdRkb0VkldReO2a2iBT/OEulG9XSUc10r3zg==} + dependencies: + lower-case: 2.0.2 + tslib: 2.6.2 + dev: true + + /node-fetch@2.7.0: + resolution: {integrity: sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==} + engines: {node: 4.x || >=6.0.0} + peerDependencies: + encoding: ^0.1.0 + peerDependenciesMeta: + encoding: + optional: true + dependencies: + whatwg-url: 5.0.0 + dev: true + + /node-int64@0.4.0: + resolution: {integrity: sha512-O5lz91xSOeoXP6DulyHfllpq+Eg00MWitZIbtPfoSEvqIHdl5gfcY6hYzDWnj0qD5tz52PI08u9qUvSVeUBeHw==} + dev: true + + /node-releases@2.0.14: + resolution: {integrity: sha512-y10wOWt8yZpqXmOgRo77WaHEmhYQYGNA6y421PKsKYWEK8aW+cqAphborZDhqfyKrbZEN92CN1X2KbafY2s7Yw==} + dev: true + + /normalize-path@3.0.0: + resolution: {integrity: sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==} + engines: {node: '>=0.10.0'} + dev: true + + /npm-run-path@4.0.1: + resolution: {integrity: sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==} + engines: {node: '>=8'} + dependencies: + path-key: 3.1.1 + dev: true + + /nunjucks@3.2.4: + resolution: {integrity: sha512-26XRV6BhkgK0VOxfbU5cQI+ICFUtMLixv1noZn1tGU38kQH5A5nmmbk/O45xdyBhD1esk47nKrY0mvQpZIhRjQ==} + engines: {node: '>= 6.9.0'} + hasBin: true + peerDependencies: + chokidar: ^3.3.0 + peerDependenciesMeta: + chokidar: + optional: true + dependencies: + a-sync-waterfall: 1.0.1 + asap: 2.0.6 + commander: 5.1.0 + dev: true + + /object-inspect@1.13.1: + resolution: {integrity: sha512-5qoj1RUiKOMsCCNLV1CBiPYE10sziTsnmNxkAI/rZhiD63CF7IqdFGC/XzjWjpSgLf0LxXX3bDFIh0E18f6UhQ==} + dev: true + + /object-keys@1.1.1: + resolution: {integrity: sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==} + engines: {node: '>= 0.4'} + dev: true + + /object.assign@4.1.5: + resolution: {integrity: sha512-byy+U7gp+FVwmyzKPYhW2h5l3crpmGsxl7X2s8y43IgxvG4g3QZ6CffDtsNQy1WsmZpQbO+ybo0AlW7TY6DcBQ==} + engines: {node: '>= 0.4'} + dependencies: + call-bind: 1.0.7 + define-properties: 1.2.1 + has-symbols: 1.0.3 + object-keys: 1.1.1 + dev: true + + /object.entries@1.1.8: + resolution: {integrity: sha512-cmopxi8VwRIAw/fkijJohSfpef5PdN0pMQJN6VC/ZKvn0LIknWD8KtgY6KlQdEc4tIjcQ3HxSMmnvtzIscdaYQ==} + engines: {node: '>= 0.4'} + dependencies: + call-bind: 1.0.7 + define-properties: 1.2.1 + es-object-atoms: 1.0.0 + dev: true + + /object.fromentries@2.0.8: + resolution: {integrity: sha512-k6E21FzySsSK5a21KRADBd/NGneRegFO5pLHfdQLpRDETUNJueLXs3WCzyQ3tFRDYgbq3KHGXfTbi2bs8WQ6rQ==} + engines: {node: '>= 0.4'} + dependencies: + call-bind: 1.0.7 + define-properties: 1.2.1 + es-abstract: 1.23.3 + es-object-atoms: 1.0.0 + dev: true + + /object.groupby@1.0.3: + resolution: {integrity: sha512-+Lhy3TQTuzXI5hevh8sBGqbmurHbbIjAi0Z4S63nthVLmLxfbj4T54a4CfZrXIrt9iP4mVAPYMo/v99taj3wjQ==} + engines: {node: '>= 0.4'} + dependencies: + call-bind: 1.0.7 + define-properties: 1.2.1 + es-abstract: 1.23.3 + dev: true + + /object.values@1.2.0: + resolution: {integrity: sha512-yBYjY9QX2hnRmZHAjG/f13MzmBzxzYgQhFrke06TTyKY5zSTEqkOeukBzIdVA3j3ulu8Qa3MbVFShV7T2RmGtQ==} + engines: {node: '>= 0.4'} + dependencies: + call-bind: 1.0.7 + define-properties: 1.2.1 + es-object-atoms: 1.0.0 + dev: true + + /once@1.4.0: + resolution: {integrity: sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==} + dependencies: + wrappy: 1.0.2 + dev: true + + /onetime@5.1.2: + resolution: {integrity: sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==} + engines: {node: '>=6'} + dependencies: + mimic-fn: 2.1.0 + dev: true + + /optionator@0.9.3: + resolution: {integrity: sha512-JjCoypp+jKn1ttEFExxhetCKeJt9zhAgAve5FXHixTvFDW/5aEktX9bufBKLRRMdU7bNtpLfcGu94B3cdEJgjg==} + engines: {node: '>= 0.8.0'} + dependencies: + '@aashutoshrathi/word-wrap': 1.2.6 + deep-is: 0.1.4 + fast-levenshtein: 2.0.6 + levn: 0.4.1 + prelude-ls: 1.2.1 + type-check: 0.4.0 + dev: true + + /p-limit@2.3.0: + resolution: {integrity: sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==} + engines: {node: '>=6'} + dependencies: + p-try: 2.2.0 + dev: true + + /p-limit@3.1.0: + resolution: {integrity: sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==} + engines: {node: '>=10'} + dependencies: + yocto-queue: 0.1.0 + dev: true + + /p-locate@4.1.0: + resolution: {integrity: sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==} + engines: {node: '>=8'} + dependencies: + p-limit: 2.3.0 + dev: true + + /p-locate@5.0.0: + resolution: {integrity: sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==} + engines: {node: '>=10'} + dependencies: + p-limit: 3.1.0 + dev: true + + /p-try@2.2.0: + resolution: {integrity: sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==} + engines: {node: '>=6'} + dev: true + + /param-case@3.0.4: + resolution: {integrity: sha512-RXlj7zCYokReqWpOPH9oYivUzLYZ5vAPIfEmCTNViosC78F8F0H9y7T7gG2M39ymgutxF5gcFEsyZQSph9Bp3A==} + dependencies: + dot-case: 3.0.4 + tslib: 2.6.2 + dev: true + + /parent-module@1.0.1: + resolution: {integrity: sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==} + engines: {node: '>=6'} + dependencies: + callsites: 3.1.0 + dev: true + + /parse-json@5.2.0: + resolution: {integrity: sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==} + engines: {node: '>=8'} + dependencies: + '@babel/code-frame': 7.24.2 + error-ex: 1.3.2 + json-parse-even-better-errors: 2.3.1 + lines-and-columns: 1.2.4 + dev: true + + /pascal-case@3.1.2: + resolution: {integrity: sha512-uWlGT3YSnK9x3BQJaOdcZwrnV6hPpd8jFH1/ucpiLRPh/2zCVJKS19E4GvYHvaCcACn3foXZ0cLB9Wrx1KGe5g==} + dependencies: + no-case: 3.0.4 + tslib: 2.6.2 + dev: true + + /path-browserify@1.0.1: + resolution: {integrity: sha512-b7uo2UCUOYZcnF/3ID0lulOJi/bafxa1xPe7ZPsammBSpjSWQkjNxlt635YGS2MiR9GjvuXCtz2emr3jbsz98g==} + dev: true + + /path-case@3.0.4: + resolution: {integrity: sha512-qO4qCFjXqVTrcbPt/hQfhTQ+VhFsqNKOPtytgNKkKxSoEp3XPUQ8ObFuePylOIok5gjn69ry8XiULxCwot3Wfg==} + dependencies: + dot-case: 3.0.4 + tslib: 2.6.2 + dev: true + + /path-exists@4.0.0: + resolution: {integrity: sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==} + engines: {node: '>=8'} + dev: true + + /path-is-absolute@1.0.1: + resolution: {integrity: sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==} + engines: {node: '>=0.10.0'} + dev: true + + /path-key@3.1.1: + resolution: {integrity: sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==} + engines: {node: '>=8'} + dev: true + + /path-parse@1.0.7: + resolution: {integrity: sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==} + dev: true + + /path-scurry@1.10.2: + resolution: {integrity: sha512-7xTavNy5RQXnsjANvVvMkEjvloOinkAjv/Z6Ildz9v2RinZ4SBKTWFOVRbaF8p0vpHnyjV/UwNDdKuUv6M5qcA==} + engines: {node: '>=16 || 14 >=14.17'} + dependencies: + lru-cache: 10.2.0 + minipass: 7.0.4 + dev: true + + /path-type@4.0.0: + resolution: {integrity: sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==} + engines: {node: '>=8'} + dev: true + + /picocolors@1.0.0: + resolution: {integrity: sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==} + dev: true + + /picomatch@2.3.1: + resolution: {integrity: sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==} + engines: {node: '>=8.6'} + dev: true + + /pirates@4.0.6: + resolution: {integrity: sha512-saLsH7WeYYPiD25LDuLRRY/i+6HaPYr6G1OUlN39otzkSTxKnubR9RTxS3/Kk50s1g2JTgFwWQDQyplC5/SHZg==} + engines: {node: '>= 6'} + dev: true + + /pkg-dir@4.2.0: + resolution: {integrity: sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==} + engines: {node: '>=8'} + dependencies: + find-up: 4.1.0 + dev: true + + /playwright-core@1.42.1: + resolution: {integrity: sha512-mxz6zclokgrke9p1vtdy/COWBH+eOZgYUVVU34C73M+4j4HLlQJHtfcqiqqxpP0o8HhMkflvfbquLX5dg6wlfA==} + engines: {node: '>=16'} + hasBin: true + dev: true + + /playwright@1.42.1: + resolution: {integrity: sha512-PgwB03s2DZBcNRoW+1w9E+VkLBxweib6KTXM0M3tkiT4jVxKSi6PmVJ591J+0u10LUrgxB7dLRbiJqO5s2QPMg==} + engines: {node: '>=16'} + hasBin: true + dependencies: + playwright-core: 1.42.1 + optionalDependencies: + fsevents: 2.3.2 + dev: true + + /polytype@0.17.0: + resolution: {integrity: sha512-Q1y07MZqHPlGRJs8qI8bnxrQs+W3r24v25cmhbQV/lC9VNNtd+smi/2m3CUHNBDTfLtl+6SpA0EsL/J1oVsEag==} + engines: {node: '>=16.0.0'} + dev: true + + /possible-typed-array-names@1.0.0: + resolution: {integrity: sha512-d7Uw+eZoloe0EHDIYoe+bQ5WXnGMOpmiZFTuMWCwpjzzkL2nTjcKiAk4hh8TjnGye2TwWOk3UXucZ+3rbmBa8Q==} + engines: {node: '>= 0.4'} + dev: true + + /prelude-ls@1.2.1: + resolution: {integrity: sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==} + engines: {node: '>= 0.8.0'} + dev: true + + /prettier-linter-helpers@1.0.0: + resolution: {integrity: sha512-GbK2cP9nraSSUF9N2XwUwqfzlAFlMNYYl+ShE/V+H8a9uNl/oUqB1w2EL54Jh0OlyRSd8RfWYJ3coVS4TROP2w==} + engines: {node: '>=6.0.0'} + dependencies: + fast-diff: 1.3.0 + dev: true + + /prettier@3.2.5: + resolution: {integrity: sha512-3/GWa9aOC0YeD7LUfvOG2NiDyhOWRvt1k+rcKhOuYnMY24iiCphgneUfJDyFXd6rZCAnuLBv6UeAULtrhT/F4A==} + engines: {node: '>=14'} + hasBin: true + dev: true + + /pretty-format@29.7.0: + resolution: {integrity: sha512-Pdlw/oPxN+aXdmM9R00JVC9WVFoCLTKJvDVLgmJ+qAffBMxsV85l/Lu7sNx4zSzPyoL2euImuEwHhOXdEgNFZQ==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + dependencies: + '@jest/schemas': 29.6.3 + ansi-styles: 5.2.0 + react-is: 18.2.0 + dev: true + + /prompts@2.4.2: + resolution: {integrity: sha512-NxNv/kLguCA7p3jE8oL2aEBsrJWgAakBpgmgK6lpPWV+WuOmY6r2/zbAVnP+T8bQlA0nzHXSJSJW0Hq7ylaD2Q==} + engines: {node: '>= 6'} + dependencies: + kleur: 3.0.3 + sisteransi: 1.0.5 + dev: true + + /punycode@2.3.1: + resolution: {integrity: sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==} + engines: {node: '>=6'} + dev: true + + /pure-rand@6.1.0: + resolution: {integrity: sha512-bVWawvoZoBYpp6yIoQtQXHZjmz35RSVHnUOTefl8Vcjr8snTPY1wnpSPMWekcFwbxI6gtmT7rSYPFvz71ldiOA==} + dev: true + + /queue-microtask@1.2.3: + resolution: {integrity: sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==} + dev: true + + /react-is@18.2.0: + resolution: {integrity: sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w==} + dev: true + + /regexp.prototype.flags@1.5.2: + resolution: {integrity: sha512-NcDiDkTLuPR+++OCKB0nWafEmhg/Da8aUPLPMQbK+bxKKCm1/S5he+AqYa4PlMCVBalb4/yxIRub6qkEx5yJbw==} + engines: {node: '>= 0.4'} + dependencies: + call-bind: 1.0.7 + define-properties: 1.2.1 + es-errors: 1.3.0 + set-function-name: 2.0.2 + dev: true + + /require-directory@2.1.1: + resolution: {integrity: sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==} + engines: {node: '>=0.10.0'} + dev: true + + /resolve-cwd@3.0.0: + resolution: {integrity: sha512-OrZaX2Mb+rJCpH/6CpSqt9xFVpN++x01XnN2ie9g6P5/3xelLAkXWVADpdz1IHD/KFfEXyE6V0U01OQ3UO2rEg==} + engines: {node: '>=8'} + dependencies: + resolve-from: 5.0.0 + dev: true + + /resolve-from@4.0.0: + resolution: {integrity: sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==} + engines: {node: '>=4'} + dev: true + + /resolve-from@5.0.0: + resolution: {integrity: sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==} + engines: {node: '>=8'} + dev: true + + /resolve.exports@2.0.2: + resolution: {integrity: sha512-X2UW6Nw3n/aMgDVy+0rSqgHlv39WZAlZrXCdnbyEiKm17DSqHX4MmQMaST3FbeWR5FTuRcUwYAziZajji0Y7mg==} + engines: {node: '>=10'} + dev: true + + /resolve@1.22.8: + resolution: {integrity: sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw==} + hasBin: true + dependencies: + is-core-module: 2.13.1 + path-parse: 1.0.7 + supports-preserve-symlinks-flag: 1.0.0 + dev: true + + /reusify@1.0.4: + resolution: {integrity: sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==} + engines: {iojs: '>=1.0.0', node: '>=0.10.0'} + dev: true + + /rimraf@3.0.2: + resolution: {integrity: sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==} + hasBin: true + dependencies: + glob: 7.2.3 + dev: true + + /run-parallel@1.2.0: + resolution: {integrity: sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==} + dependencies: + queue-microtask: 1.2.3 + dev: true + + /safe-array-concat@1.1.2: + resolution: {integrity: sha512-vj6RsCsWBCf19jIeHEfkRMw8DPiBb+DMXklQ/1SGDHOMlHdPUkZXFQ2YdplS23zESTijAcurb1aSgJA3AgMu1Q==} + engines: {node: '>=0.4'} + dependencies: + call-bind: 1.0.7 + get-intrinsic: 1.2.4 + has-symbols: 1.0.3 + isarray: 2.0.5 + dev: true + + /safe-regex-test@1.0.3: + resolution: {integrity: sha512-CdASjNJPvRa7roO6Ra/gLYBTzYzzPyyBXxIMdGW3USQLyjWEls2RgW5UBTXaQVp+OrpeCK3bLem8smtmheoRuw==} + engines: {node: '>= 0.4'} + dependencies: + call-bind: 1.0.7 + es-errors: 1.3.0 + is-regex: 1.1.4 + dev: true + + /semver@6.3.1: + resolution: {integrity: sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==} + hasBin: true + dev: true + + /semver@7.6.0: + resolution: {integrity: sha512-EnwXhrlwXMk9gKu5/flx5sv/an57AkRplG3hTK68W7FRDN+k+OWBj65M7719OkA82XLBxrcX0KSHj+X5COhOVg==} + engines: {node: '>=10'} + hasBin: true + dependencies: + lru-cache: 6.0.0 + dev: true + + /sentence-case@3.0.4: + resolution: {integrity: sha512-8LS0JInaQMCRoQ7YUytAo/xUu5W2XnQxV2HI/6uM6U7CITS1RqPElr30V6uIqyMKM9lJGRVFy5/4CuzcixNYSg==} + dependencies: + no-case: 3.0.4 + tslib: 2.6.2 + upper-case-first: 2.0.2 + dev: true + + /set-function-length@1.2.2: + resolution: {integrity: sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==} + engines: {node: '>= 0.4'} + dependencies: + define-data-property: 1.1.4 + es-errors: 1.3.0 + function-bind: 1.1.2 + get-intrinsic: 1.2.4 + gopd: 1.0.1 + has-property-descriptors: 1.0.2 + dev: true + + /set-function-name@2.0.2: + resolution: {integrity: sha512-7PGFlmtwsEADb0WYyvCMa1t+yke6daIG4Wirafur5kcf+MhUnPms1UeR0CKQdTZD81yESwMHbtn+TR+dMviakQ==} + engines: {node: '>= 0.4'} + dependencies: + define-data-property: 1.1.4 + es-errors: 1.3.0 + functions-have-names: 1.2.3 + has-property-descriptors: 1.0.2 + dev: true + + /shebang-command@2.0.0: + resolution: {integrity: sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==} + engines: {node: '>=8'} + dependencies: + shebang-regex: 3.0.0 + dev: true + + /shebang-regex@3.0.0: + resolution: {integrity: sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==} + engines: {node: '>=8'} + dev: true + + /side-channel@1.0.6: + resolution: {integrity: sha512-fDW/EZ6Q9RiO8eFG8Hj+7u/oW+XrPTIChwCOM2+th2A6OblDtYYIpve9m+KvI9Z4C9qSEXlaGR6bTEYHReuglA==} + engines: {node: '>= 0.4'} + dependencies: + call-bind: 1.0.7 + es-errors: 1.3.0 + get-intrinsic: 1.2.4 + object-inspect: 1.13.1 + dev: true + + /signal-exit@3.0.7: + resolution: {integrity: sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==} + dev: true + + /signal-exit@4.1.0: + resolution: {integrity: sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==} + engines: {node: '>=14'} + dev: true + + /sisteransi@1.0.5: + resolution: {integrity: sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg==} + dev: true + + /slash@3.0.0: + resolution: {integrity: sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==} + engines: {node: '>=8'} + dev: true + + /snake-case@3.0.4: + resolution: {integrity: sha512-LAOh4z89bGQvl9pFfNF8V146i7o7/CqFPbqzYgP+yYzDIDeS9HaNFtXABamRW+AQzEVODcvE79ljJ+8a9YSdMg==} + dependencies: + dot-case: 3.0.4 + tslib: 2.6.2 + dev: true + + /source-map-support@0.5.13: + resolution: {integrity: sha512-SHSKFHadjVA5oR4PPqhtAVdcBWwRYVd6g6cAXnIbRiIwc2EhPrTuKUBdSLvlEKyIP3GCf89fltvcZiP9MMFA1w==} + dependencies: + buffer-from: 1.1.2 + source-map: 0.6.1 + dev: true + + /source-map@0.6.1: + resolution: {integrity: sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==} + engines: {node: '>=0.10.0'} + dev: true + + /source-map@0.7.4: + resolution: {integrity: sha512-l3BikUxvPOcn5E74dZiq5BGsTb5yEwhaTSzccU6t4sDOH8NWJCstKO5QT2CvtFoK6F0saL7p9xHAqHOlCPJygA==} + engines: {node: '>= 8'} + dev: true + + /sprintf-js@1.0.3: + resolution: {integrity: sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==} + dev: true + + /stack-utils@2.0.6: + resolution: {integrity: sha512-XlkWvfIm6RmsWtNJx+uqtKLS8eqFbxUg0ZzLXqY0caEy9l7hruX8IpiDnjsLavoBgqCCR71TqWO8MaXYheJ3RQ==} + engines: {node: '>=10'} + dependencies: + escape-string-regexp: 2.0.0 + dev: true + + /string-length@4.0.2: + resolution: {integrity: sha512-+l6rNN5fYHNhZZy41RXsYptCjA2Igmq4EG7kZAYFQI1E1VTXarr6ZPXBg6eq7Y6eK4FEhY6AJlyuFIb/v/S0VQ==} + engines: {node: '>=10'} + dependencies: + char-regex: 1.0.2 + strip-ansi: 6.0.1 + dev: true + + /string-width@4.2.3: + resolution: {integrity: sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==} + engines: {node: '>=8'} + dependencies: + emoji-regex: 8.0.0 + is-fullwidth-code-point: 3.0.0 + strip-ansi: 6.0.1 + dev: true + + /string-width@5.1.2: + resolution: {integrity: sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==} + engines: {node: '>=12'} + dependencies: + eastasianwidth: 0.2.0 + emoji-regex: 9.2.2 + strip-ansi: 7.1.0 + dev: true + + /string.prototype.trim@1.2.9: + resolution: {integrity: sha512-klHuCNxiMZ8MlsOihJhJEBJAiMVqU3Z2nEXWfWnIqjN0gEFS9J9+IxKozWWtQGcgoa1WUZzLjKPTr4ZHNFTFxw==} + engines: {node: '>= 0.4'} + dependencies: + call-bind: 1.0.7 + define-properties: 1.2.1 + es-abstract: 1.23.3 + es-object-atoms: 1.0.0 + dev: true + + /string.prototype.trimend@1.0.8: + resolution: {integrity: sha512-p73uL5VCHCO2BZZ6krwwQE3kCzM7NKmis8S//xEC6fQonchbum4eP6kR4DLEjQFO3Wnj3Fuo8NM0kOSjVdHjZQ==} + dependencies: + call-bind: 1.0.7 + define-properties: 1.2.1 + es-object-atoms: 1.0.0 + dev: true + + /string.prototype.trimstart@1.0.8: + resolution: {integrity: sha512-UXSH262CSZY1tfu3G3Secr6uGLCFVPMhIqHjlgCUtCCcgihYc/xKs9djMTMUOb2j1mVSeU8EU6NWc/iQKU6Gfg==} + engines: {node: '>= 0.4'} + dependencies: + call-bind: 1.0.7 + define-properties: 1.2.1 + es-object-atoms: 1.0.0 + dev: true + + /strip-ansi@6.0.1: + resolution: {integrity: sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==} + engines: {node: '>=8'} + dependencies: + ansi-regex: 5.0.1 + dev: true + + /strip-ansi@7.1.0: + resolution: {integrity: sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==} + engines: {node: '>=12'} + dependencies: + ansi-regex: 6.0.1 + dev: true + + /strip-bom@3.0.0: + resolution: {integrity: sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==} + engines: {node: '>=4'} + dev: true + + /strip-bom@4.0.0: + resolution: {integrity: sha512-3xurFv5tEgii33Zi8Jtp55wEIILR9eh34FAW00PZf+JnSsTmV/ioewSgQl97JHvgjoRGwPShsWm+IdrxB35d0w==} + engines: {node: '>=8'} + dev: true + + /strip-final-newline@2.0.0: + resolution: {integrity: sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==} + engines: {node: '>=6'} + dev: true + + /strip-json-comments@3.1.1: + resolution: {integrity: sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==} + engines: {node: '>=8'} + dev: true + + /supports-color@5.5.0: + resolution: {integrity: sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==} + engines: {node: '>=4'} + dependencies: + has-flag: 3.0.0 + dev: true + + /supports-color@7.2.0: + resolution: {integrity: sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==} + engines: {node: '>=8'} + dependencies: + has-flag: 4.0.0 + dev: true + + /supports-color@8.1.1: + resolution: {integrity: sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==} + engines: {node: '>=10'} + dependencies: + has-flag: 4.0.0 + dev: true + + /supports-preserve-symlinks-flag@1.0.0: + resolution: {integrity: sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==} + engines: {node: '>= 0.4'} + dev: true + + /synckit@0.8.8: + resolution: {integrity: sha512-HwOKAP7Wc5aRGYdKH+dw0PRRpbO841v2DENBtjnR5HFWoiNByAl7vrx3p0G/rCyYXQsrxqtX48TImFtPcIHSpQ==} + engines: {node: ^14.18.0 || >=16.0.0} + dependencies: + '@pkgr/core': 0.1.1 + tslib: 2.6.2 + dev: true + + /test-exclude@6.0.0: + resolution: {integrity: sha512-cAGWPIyOHU6zlmg88jwm7VRyXnMN7iV68OGAbYDk/Mh/xC/pzVPlQtY6ngoIH/5/tciuhGfvESU8GrHrcxD56w==} + engines: {node: '>=8'} + dependencies: + '@istanbuljs/schema': 0.1.3 + glob: 7.2.3 + minimatch: 3.1.2 + dev: true + + /text-table@0.2.0: + resolution: {integrity: sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==} + dev: true + + /tmpl@1.0.5: + resolution: {integrity: sha512-3f0uOEAQwIqGuWW2MVzYg8fV/QNnc/IpuJNG837rLuczAaLVHslWHZQj4IGiEl5Hs3kkbhwL9Ab7Hrsmuj+Smw==} + dev: true + + /to-fast-properties@2.0.0: + resolution: {integrity: sha512-/OaKK0xYrs3DmxRYqL/yDc+FxFUVYhDlXMhRmv3z915w2HF1tnN1omB354j8VUGO/hbRzyD6Y3sA7v7GS/ceog==} + engines: {node: '>=4'} + dev: true + + /to-regex-range@5.0.1: + resolution: {integrity: sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==} + engines: {node: '>=8.0'} + dependencies: + is-number: 7.0.0 + dev: true + + /tr46@0.0.3: + resolution: {integrity: sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==} + dev: true + + /ts-jest@29.1.2(@babel/core@7.24.3)(jest@29.7.0)(typescript@5.4.3): + resolution: {integrity: sha512-br6GJoH/WUX4pu7FbZXuWGKGNDuU7b8Uj77g/Sp7puZV6EXzuByl6JrECvm0MzVzSTkSHWTihsXt+5XYER5b+g==} + engines: {node: ^16.10.0 || ^18.0.0 || >=20.0.0} + hasBin: true + peerDependencies: + '@babel/core': '>=7.0.0-beta.0 <8' + '@jest/types': ^29.0.0 + babel-jest: ^29.0.0 + esbuild: '*' + jest: ^29.0.0 + typescript: '>=4.3 <6' + peerDependenciesMeta: + '@babel/core': + optional: true + '@jest/types': + optional: true + babel-jest: + optional: true + esbuild: + optional: true + dependencies: + '@babel/core': 7.24.3 + bs-logger: 0.2.6 + fast-json-stable-stringify: 2.1.0 + jest: 29.7.0 + jest-util: 29.7.0 + json5: 2.2.3 + lodash.memoize: 4.1.2 + make-error: 1.3.6 + semver: 7.6.0 + typescript: 5.4.3 + yargs-parser: 21.1.1 + dev: true + + /ts-morph@20.0.0: + resolution: {integrity: sha512-JVmEJy2Wow5n/84I3igthL9sudQ8qzjh/6i4tmYCm6IqYyKFlNbJZi7oBdjyqcWSWYRu3CtL0xbT6fS03ESZIg==} + dependencies: + '@ts-morph/common': 0.21.0 + code-block-writer: 12.0.0 + dev: true + + /tsconfig-paths@3.15.0: + resolution: {integrity: sha512-2Ac2RgzDe/cn48GvOe3M+o82pEFewD3UPbyoUHHdKasHwJKjds4fLXWf/Ux5kATBKN20oaFGu+jbElp1pos0mg==} + dependencies: + '@types/json5': 0.0.29 + json5: 1.0.2 + minimist: 1.2.8 + strip-bom: 3.0.0 + dev: true + + /tslib@1.14.1: + resolution: {integrity: sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==} + dev: true + + /tslib@2.6.2: + resolution: {integrity: sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==} + dev: true + + /tsutils@3.21.0(typescript@5.4.3): + resolution: {integrity: sha512-mHKK3iUXL+3UF6xL5k0PEhKRUBKPBCv/+RkEOpjRWxxx27KKRBmmA60A9pgOUvMi8GKhRMPEmjBRPzs2W7O1OA==} + engines: {node: '>= 6'} + peerDependencies: + typescript: '>=2.8.0 || >= 3.2.0-dev || >= 3.3.0-dev || >= 3.4.0-dev || >= 3.5.0-dev || >= 3.6.0-dev || >= 3.6.0-beta || >= 3.7.0-dev || >= 3.7.0-beta' + dependencies: + tslib: 1.14.1 + typescript: 5.4.3 + dev: true + + /tweetnacl@1.0.3: + resolution: {integrity: sha512-6rt+RN7aOi1nGMyC4Xa5DdYiukl2UWCbcJft7YhxReBGQD7OAM8Pbxw6YMo4r2diNEA8FEmu32YOn9rhaiE5yw==} + + /type-check@0.4.0: + resolution: {integrity: sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==} + engines: {node: '>= 0.8.0'} + dependencies: + prelude-ls: 1.2.1 + dev: true + + /type-detect@4.0.8: + resolution: {integrity: sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==} + engines: {node: '>=4'} + dev: true + + /type-fest@0.20.2: + resolution: {integrity: sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==} + engines: {node: '>=10'} + dev: true + + /type-fest@0.21.3: + resolution: {integrity: sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==} + engines: {node: '>=10'} + dev: true + + /typed-array-buffer@1.0.2: + resolution: {integrity: sha512-gEymJYKZtKXzzBzM4jqa9w6Q1Jjm7x2d+sh19AdsD4wqnMPDYyvwpsIc2Q/835kHuo3BEQ7CjelGhfTsoBb2MQ==} + engines: {node: '>= 0.4'} + dependencies: + call-bind: 1.0.7 + es-errors: 1.3.0 + is-typed-array: 1.1.13 + dev: true + + /typed-array-byte-length@1.0.1: + resolution: {integrity: sha512-3iMJ9q0ao7WE9tWcaYKIptkNBuOIcZCCT0d4MRvuuH88fEoEH62IuQe0OtraD3ebQEoTRk8XCBoknUNc1Y67pw==} + engines: {node: '>= 0.4'} + dependencies: + call-bind: 1.0.7 + for-each: 0.3.3 + gopd: 1.0.1 + has-proto: 1.0.3 + is-typed-array: 1.1.13 + dev: true + + /typed-array-byte-offset@1.0.2: + resolution: {integrity: sha512-Ous0vodHa56FviZucS2E63zkgtgrACj7omjwd/8lTEMEPFFyjfixMZ1ZXenpgCFBBt4EC1J2XsyVS2gkG0eTFA==} + engines: {node: '>= 0.4'} + dependencies: + available-typed-arrays: 1.0.7 + call-bind: 1.0.7 + for-each: 0.3.3 + gopd: 1.0.1 + has-proto: 1.0.3 + is-typed-array: 1.1.13 + dev: true + + /typed-array-length@1.0.6: + resolution: {integrity: sha512-/OxDN6OtAk5KBpGb28T+HZc2M+ADtvRxXrKKbUwtsLgdoxgX13hyy7ek6bFRl5+aBs2yZzB0c4CnQfAtVypW/g==} + engines: {node: '>= 0.4'} + dependencies: + call-bind: 1.0.7 + for-each: 0.3.3 + gopd: 1.0.1 + has-proto: 1.0.3 + is-typed-array: 1.1.13 + possible-typed-array-names: 1.0.0 + dev: true + + /typescript@4.9.5: + resolution: {integrity: sha512-1FXk9E2Hm+QzZQ7z+McJiHL4NW1F2EzMu9Nq9i3zAaGqibafqYwCVU6WyWAuyQRRzOlxou8xZSyXLEN8oKj24g==} + engines: {node: '>=4.2.0'} + hasBin: true + dev: true + + /typescript@5.4.3: + resolution: {integrity: sha512-KrPd3PKaCLr78MalgiwJnA25Nm8HAmdwN3mYUYZgG/wizIo9EainNVQI9/yDavtVFRN2h3k8uf3GLHuhDMgEHg==} + engines: {node: '>=14.17'} + hasBin: true + dev: true + + /unbox-primitive@1.0.2: + resolution: {integrity: sha512-61pPlCD9h51VoreyJ0BReideM3MDKMKnh6+V9L08331ipq6Q8OFXZYiqP6n/tbHx4s5I9uRhcye6BrbkizkBDw==} + dependencies: + call-bind: 1.0.7 + has-bigints: 1.0.2 + has-symbols: 1.0.3 + which-boxed-primitive: 1.0.2 + dev: true + + /undici-types@5.26.5: + resolution: {integrity: sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==} + dev: true + + /update-browserslist-db@1.0.13(browserslist@4.23.0): + resolution: {integrity: sha512-xebP81SNcPuNpPP3uzeW1NYXxI3rxyJzF3pD6sH4jE7o/IX+WtSpwnVU+qIsDPyk0d3hmFQ7mjqc6AtV604hbg==} + hasBin: true + peerDependencies: + browserslist: '>= 4.21.0' + dependencies: + browserslist: 4.23.0 + escalade: 3.1.2 + picocolors: 1.0.0 + dev: true + + /upper-case-first@2.0.2: + resolution: {integrity: sha512-514ppYHBaKwfJRK/pNC6c/OxfGa0obSnAl106u97Ed0I625Nin96KAjttZF6ZL3e1XLtphxnqrOi9iWgm+u+bg==} + dependencies: + tslib: 2.6.2 + dev: true + + /upper-case@2.0.2: + resolution: {integrity: sha512-KgdgDGJt2TpuwBUIjgG6lzw2GWFRCW9Qkfkiv0DxqHHLYJHmtmdUIKcZd8rHgFSjopVTlw6ggzCm1b8MFQwikg==} + dependencies: + tslib: 2.6.2 + dev: true + + /uri-js@4.4.1: + resolution: {integrity: sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==} + dependencies: + punycode: 2.3.1 + dev: true + + /v8-to-istanbul@9.2.0: + resolution: {integrity: sha512-/EH/sDgxU2eGxajKdwLCDmQ4FWq+kpi3uCmBGpw1xJtnAxEjlD8j8PEiGWpCIMIs3ciNAgH0d3TTJiUkYzyZjA==} + engines: {node: '>=10.12.0'} + dependencies: + '@jridgewell/trace-mapping': 0.3.25 + '@types/istanbul-lib-coverage': 2.0.6 + convert-source-map: 2.0.0 + dev: true + + /vlq@2.0.4: + resolution: {integrity: sha512-aodjPa2wPQFkra1G8CzJBTHXhgk3EVSwxSWXNPr1fgdFLUb8kvLV1iEb6rFgasIsjP82HWI6dsb5Io26DDnasA==} + + /walker@1.0.8: + resolution: {integrity: sha512-ts/8E8l5b7kY0vlWLewOkDXMmPdLcVV4GmOQLyxuSswIJsweeFZtAsMF7k1Nszz+TYBQrlYRmzOnr398y1JemQ==} + dependencies: + makeerror: 1.0.12 + dev: true + + /webidl-conversions@3.0.1: + resolution: {integrity: sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==} + dev: true + + /whatwg-url@5.0.0: + resolution: {integrity: sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==} + dependencies: + tr46: 0.0.3 + webidl-conversions: 3.0.1 + dev: true + + /which-boxed-primitive@1.0.2: + resolution: {integrity: sha512-bwZdv0AKLpplFY2KZRX6TvyuN7ojjr7lwkg6ml0roIy9YeuSr7JS372qlNW18UQYzgYK9ziGcerWqZOmEn9VNg==} + dependencies: + is-bigint: 1.0.4 + is-boolean-object: 1.1.2 + is-number-object: 1.0.7 + is-string: 1.0.7 + is-symbol: 1.0.4 + dev: true + + /which-typed-array@1.1.15: + resolution: {integrity: sha512-oV0jmFtUky6CXfkqehVvBP/LSWJ2sy4vWMioiENyJLePrBO/yKyV9OyJySfAKosh+RYkIl5zJCNZ8/4JncrpdA==} + engines: {node: '>= 0.4'} + dependencies: + available-typed-arrays: 1.0.7 + call-bind: 1.0.7 + for-each: 0.3.3 + gopd: 1.0.1 + has-tostringtag: 1.0.2 + dev: true + + /which@2.0.2: + resolution: {integrity: sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==} + engines: {node: '>= 8'} + hasBin: true + dependencies: + isexe: 2.0.0 + dev: true + + /wrap-ansi@7.0.0: + resolution: {integrity: sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==} + engines: {node: '>=10'} + dependencies: + ansi-styles: 4.3.0 + string-width: 4.2.3 + strip-ansi: 6.0.1 + dev: true + + /wrap-ansi@8.1.0: + resolution: {integrity: sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==} + engines: {node: '>=12'} + dependencies: + ansi-styles: 6.2.1 + string-width: 5.1.2 + strip-ansi: 7.1.0 + dev: true + + /wrappy@1.0.2: + resolution: {integrity: sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==} + dev: true + + /write-file-atomic@4.0.2: + resolution: {integrity: sha512-7KxauUdBmSdWnmpaGFg+ppNjKF8uNLry8LyzjauQDOVONfFLNKrKvQOxZ/VuTIcS/gge/YNahf5RIIQWTSarlg==} + engines: {node: ^12.13.0 || ^14.15.0 || >=16.0.0} + dependencies: + imurmurhash: 0.1.4 + signal-exit: 3.0.7 + dev: true + + /y18n@5.0.8: + resolution: {integrity: sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==} + engines: {node: '>=10'} + dev: true + + /yallist@3.1.1: + resolution: {integrity: sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==} + dev: true + + /yallist@4.0.0: + resolution: {integrity: sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==} + dev: true + + /yargs-parser@21.1.1: + resolution: {integrity: sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==} + engines: {node: '>=12'} + dev: true + + /yargs@17.7.2: + resolution: {integrity: sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==} + engines: {node: '>=12'} + dependencies: + cliui: 8.0.1 + escalade: 3.1.2 + get-caller-file: 2.0.5 + require-directory: 2.1.1 + string-width: 4.2.3 + y18n: 5.0.8 + yargs-parser: 21.1.1 + dev: true + + /yocto-queue@0.1.0: + resolution: {integrity: sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==} + engines: {node: '>=10'} + dev: true diff --git a/contracts/tsconfig.json b/contracts/tsconfig.json new file mode 100644 index 00000000..11a7c665 --- /dev/null +++ b/contracts/tsconfig.json @@ -0,0 +1,103 @@ +{ + "compilerOptions": { + /* Visit https://aka.ms/tsconfig to read more about this file */ + + /* Projects */ + // "incremental": true, /* Save .tsbuildinfo files to allow for incremental compilation of projects. */ + // "composite": true, /* Enable constraints that allow a TypeScript project to be used with project references. */ + // "tsBuildInfoFile": "./.tsbuildinfo", /* Specify the path to .tsbuildinfo incremental compilation file. */ + // "disableSourceOfProjectReferenceRedirect": true, /* Disable preferring source files instead of declaration files when referencing composite projects. */ + // "disableSolutionSearching": true, /* Opt a project out of multi-project reference checking when editing. */ + // "disableReferencedProjectLoad": true, /* Reduce the number of projects loaded automatically by TypeScript. */ + + /* Language and Environment */ + "target": "ES2020", + "lib": ["ES2020", "DOM"], + // "jsx": "preserve", /* Specify what JSX code is generated. */ + "experimentalDecorators": true, /* Enable experimental support for TC39 stage 2 draft decorators. */ + // "emitDecoratorMetadata": true, /* Emit design-type metadata for decorated declarations in source files. */ + // "jsxFactory": "", /* Specify the JSX factory function used when targeting React JSX emit, e.g. 'React.createElement' or 'h'. */ + // "jsxFragmentFactory": "", /* Specify the JSX Fragment reference used for fragments when targeting React JSX emit e.g. 'React.Fragment' or 'Fragment'. */ + // "jsxImportSource": "", /* Specify module specifier used to import the JSX factory functions when using 'jsx: react-jsx*'. */ + // "reactNamespace": "", /* Specify the object invoked for 'createElement'. This only applies when targeting 'react' JSX emit. */ + // "noLib": true, /* Disable including any library files, including the default lib.d.ts. */ + // "useDefineForClassFields": true, /* Emit ECMAScript-standard-compliant class fields. */ + // "moduleDetection": "auto", /* Control what method is used to detect module-format JS files. */ + + /* Modules */ + "module": "commonjs", /* Specify what module code is generated. */ + // "rootDir": "./", /* Specify the root folder within your source files. */ + // "moduleResolution": "node", /* Specify how TypeScript looks up a file from a given module specifier. */ + // "baseUrl": "./", /* Specify the base directory to resolve non-relative module names. */ + // "paths": {}, /* Specify a set of entries that re-map imports to additional lookup locations. */ + // "rootDirs": [], /* Allow multiple folders to be treated as one when resolving modules. */ + // "typeRoots": [], /* Specify multiple folders that act like './node_modules/@types'. */ + // "types": [], /* Specify type package names to be included without being referenced in a source file. */ + // "allowUmdGlobalAccess": true, /* Allow accessing UMD globals from modules. */ + // "moduleSuffixes": [], /* List of file name suffixes to search when resolving a module. */ + // "resolveJsonModule": true, /* Enable importing .json files. */ + // "noResolve": true, /* Disallow 'import's, 'require's or ''s from expanding the number of files TypeScript should add to a project. */ + + /* JavaScript Support */ + // "allowJs": true, /* Allow JavaScript files to be a part of your program. Use the 'checkJS' option to get errors from these files. */ + // "checkJs": true, /* Enable error reporting in type-checked JavaScript files. */ + // "maxNodeModuleJsDepth": 1, /* Specify the maximum folder depth used for checking JavaScript files from 'node_modules'. Only applicable with 'allowJs'. */ + + /* Emit */ + // "declaration": true, /* Generate .d.ts files from TypeScript and JavaScript files in your project. */ + // "declarationMap": true, /* Create sourcemaps for d.ts files. */ + // "emitDeclarationOnly": true, /* Only output d.ts files and not JavaScript files. */ + // "sourceMap": true, /* Create source map files for emitted JavaScript files. */ + // "outFile": "./", /* Specify a file that bundles all outputs into one JavaScript file. If 'declaration' is true, also designates a file that bundles all .d.ts output. */ + // "outDir": "./", /* Specify an output folder for all emitted files. */ + // "removeComments": true, /* Disable emitting comments. */ + // "noEmit": true, /* Disable emitting files from a compilation. */ + // "importHelpers": true, /* Allow importing helper functions from tslib once per project, instead of including them per-file. */ + // "importsNotUsedAsValues": "remove", /* Specify emit/checking behavior for imports that are only used for types. */ + // "downlevelIteration": true, /* Emit more compliant, but verbose and less performant JavaScript for iteration. */ + // "sourceRoot": "", /* Specify the root path for debuggers to find the reference source code. */ + // "mapRoot": "", /* Specify the location where debugger should locate map files instead of generated locations. */ + // "inlineSourceMap": true, /* Include sourcemap files inside the emitted JavaScript. */ + // "inlineSources": true, /* Include source code in the sourcemaps inside the emitted JavaScript. */ + // "emitBOM": true, /* Emit a UTF-8 Byte Order Mark (BOM) in the beginning of output files. */ + // "newLine": "crlf", /* Set the newline character for emitting files. */ + // "stripInternal": true, /* Disable emitting declarations that have '@internal' in their JSDoc comments. */ + // "noEmitHelpers": true, /* Disable generating custom helper functions like '__extends' in compiled output. */ + // "noEmitOnError": true, /* Disable emitting files if any type checking errors are reported. */ + // "preserveConstEnums": true, /* Disable erasing 'const enum' declarations in generated code. */ + // "declarationDir": "./", /* Specify the output directory for generated declaration files. */ + // "preserveValueImports": true, /* Preserve unused imported values in the JavaScript output that would otherwise be removed. */ + + /* Interop Constraints */ + // "isolatedModules": true, /* Ensure that each file can be safely transpiled without relying on other imports. */ + // "allowSyntheticDefaultImports": true, /* Allow 'import x from y' when a module doesn't have a default export. */ + "esModuleInterop": true, /* Emit additional JavaScript to ease support for importing CommonJS modules. This enables 'allowSyntheticDefaultImports' for type compatibility. */ + // "preserveSymlinks": true, /* Disable resolving symlinks to their realpath. This correlates to the same flag in node. */ + "forceConsistentCasingInFileNames": true, /* Ensure that casing is correct in imports. */ + + /* Type Checking */ + "strict": true, /* Enable all strict type-checking options. */ + // "noImplicitAny": true, /* Enable error reporting for expressions and declarations with an implied 'any' type. */ + // "strictNullChecks": true, /* When type checking, take into account 'null' and 'undefined'. */ + // "strictFunctionTypes": true, /* When assigning functions, check to ensure parameters and the return values are subtype-compatible. */ + // "strictBindCallApply": true, /* Check that the arguments for 'bind', 'call', and 'apply' methods match the original function. */ + // "strictPropertyInitialization": true, /* Check for class properties that are declared but not set in the constructor. */ + // "noImplicitThis": true, /* Enable error reporting when 'this' is given the type 'any'. */ + // "useUnknownInCatchVariables": true, /* Default catch clause variables as 'unknown' instead of 'any'. */ + // "alwaysStrict": true, /* Ensure 'use strict' is always emitted. */ + // "noUnusedLocals": true, /* Enable error reporting when local variables aren't read. */ + // "noUnusedParameters": true, /* Raise an error when a function parameter isn't read. */ + // "exactOptionalPropertyTypes": true, /* Interpret optional property types as written, rather than adding 'undefined'. */ + // "noImplicitReturns": true, /* Enable error reporting for codepaths that do not explicitly return in a function. */ + // "noFallthroughCasesInSwitch": true, /* Enable error reporting for fallthrough cases in switch statements. */ + // "noUncheckedIndexedAccess": true, /* Add 'undefined' to a type when accessed using an index. */ + // "noImplicitOverride": true, /* Ensure overriding members in derived classes are marked with an override modifier. */ + // "noPropertyAccessFromIndexSignature": true, /* Enforces using indexed accessors for keys declared using an indexed type. */ + // "allowUnusedLabels": true, /* Disable error reporting for unused labels. */ + // "allowUnreachableCode": true, /* Disable error reporting for unreachable code. */ + + /* Completeness */ + // "skipDefaultLibCheck": true, /* Skip type checking .d.ts files that are included with TypeScript. */ + "skipLibCheck": true /* Skip type checking all .d.ts files. */ + } +} diff --git a/contracts/update_contract_artifacts.sh b/contracts/update_contract_artifacts.sh new file mode 100755 index 00000000..c8627080 --- /dev/null +++ b/contracts/update_contract_artifacts.sh @@ -0,0 +1,10 @@ +#!/bin/bash +rm -rf ../nodemgr/internal/lib/reti/artifacts/contracts/ +set -e +mkdir -p ../nodemgr/internal/lib/reti/artifacts/contracts/ +cp ./contracts/artifacts/*arc32* ../nodemgr/internal/lib/reti/artifacts/contracts/ + +# Update UI contract clients +rm -rf ../ui/src/contracts/ +mkdir -p ../ui/src/contracts/ +cp ./contracts/clients/*.ts ../ui/src/contracts/ diff --git a/docs/.gitbook/assets/Reti_Validator_Pools_Page_1.png b/docs/.gitbook/assets/Reti_Validator_Pools_Page_1.png new file mode 100644 index 00000000..897fecc8 Binary files /dev/null and b/docs/.gitbook/assets/Reti_Validator_Pools_Page_1.png differ diff --git a/docs/.gitbook/assets/Reti_Validator_Pools_Page_2.png b/docs/.gitbook/assets/Reti_Validator_Pools_Page_2.png new file mode 100644 index 00000000..f2814598 Binary files /dev/null and b/docs/.gitbook/assets/Reti_Validator_Pools_Page_2.png differ diff --git a/docs/.gitbook/assets/horizline.png b/docs/.gitbook/assets/horizline.png new file mode 100644 index 00000000..c7306222 Binary files /dev/null and b/docs/.gitbook/assets/horizline.png differ diff --git a/docs/.gitbook/assets/staker.png b/docs/.gitbook/assets/staker.png new file mode 100644 index 00000000..ba025a5e Binary files /dev/null and b/docs/.gitbook/assets/staker.png differ diff --git a/docs/.gitbook/assets/staker.puml b/docs/.gitbook/assets/staker.puml new file mode 100644 index 00000000..dc95fe64 --- /dev/null +++ b/docs/.gitbook/assets/staker.puml @@ -0,0 +1,49 @@ +@startuml +actor "Staker" as staker +actor "Validator" as validator +actor "Master Contract" as master +database "Staking pool(*)" as pool +group Add stake to validator +autonumber 0 +staker -> master: [payment of stake (portion stays as MBR if first-time in protocol) +staker -> master: addStake(stakedAmountPayment: PayTxn, validatorId: ValidatorID, tokenToVerify: uint64): ValidatorPoolKey +note right: updating totals for validator and protocol +autonumber stop +master -> master: checks stakers existing staked pools w/ validator\nthen checks avail pools +autonumber 0 +master -> pool: [itxn] [payment of user stake minus MBR portion had\nto be left behind in vaidator] +master -> pool: [itxn] addStake(stakedAmountPayment: PayTxn, staker: Address): uint64 +note left: can only be called by validator +autonumber stop +pool -> pool: updates 'ledger' for staker updating balance +end +group Remove stake from pool (no reward token)) +autonumber 0 +staker -> pool: removeStake(amountToUnstake: uint64) +autonumber 0 +pool -> staker: [itxn] [payment of amountToUnstake from pool, updating ledger balance as welll] +pool -> master: [itxn] stakeRemoved(poolKey: ValidatorPoolKey, staker: Address,\namountRemoved: uint64, rewardRemoved: uint64, stakerRemoved: boolean) +note left: updates totals for validator for removed stake/staker +end +group Remove stake from pool (W/ reward token)) +autonumber 0 +staker -> pool: removeStake(amountToUnstake: uint64) +autonumber 0 +pool -> staker: [itxn] [Only if unstaking from Pool 1!] Sends all of accumulated rewarded token to staker +pool -> staker: [itxn] [payment of amountToUnstake from pool, updating ledger balance as welll] +pool -> master: [itxn] stakeRemoved(poolKey: ValidatorPoolKey, staker: Address,\namountRemoved: uint64, rewardRemoved: uint64, stakerRemoved: boolean) +note left: updates totals for validator for removed stake/staker +master -> pool: [itxn] [only if called by pool other than 1!]\ncall Pool 1\npayTokenReward(staker; Address, rewardToken: uint64, amountToSend: uint64) +pool -> staker: [itxn] [IF Pool 1!] Sends reward token to staker +end +group Claim reward tokens only +autonumber 0 +staker -> pool: claimTokens() +autonumber 0 +pool -> staker: [itxn] [Only if unstaking from Pool 1!] Sends all of accumulated rewarded token to staker +pool -> master: [itxn] stakeRemoved(poolKey: ValidatorPoolKey, staker: Address,\namountRemoved: uint64, rewardRemoved: uint64, stakerRemoved: boolean) +note left: updates totals for validator for removed stake/staker +master -> pool: [itxn] [only if called by pool other than 1!]\ncall Pool 1\npayTokenReward(staker; Address, rewardToken: uint64, amountToSend: uint64) +pool -> staker: [itxn] [IF Pool 1!] Sends reward token to staker +end +@enduml diff --git a/docs/.gitbook/assets/validator.png b/docs/.gitbook/assets/validator.png new file mode 100644 index 00000000..0a1455dc Binary files /dev/null and b/docs/.gitbook/assets/validator.png differ diff --git a/docs/.gitbook/assets/validator.puml b/docs/.gitbook/assets/validator.puml new file mode 100644 index 00000000..e09c4ac0 --- /dev/null +++ b/docs/.gitbook/assets/validator.puml @@ -0,0 +1,52 @@ +@startuml +actor "Staker" as staker +actor "Validator" as validator +actor "Master Contract" as master +database "Staking pool(*)" as pool +group get mbr data +validator -> master: [SIMULATE] getMbrAmounts()(uint64,uint64,uint64,uint64) +master->validator: returns MBRs to add Validator, add Pool, pool init, dnew first-time Staker +end +group Add self as new validator +autonumber 0 +validator -> master: [payment of Validator MBR for new validator] +validator -> master: addValidator(mbrPayment: PayTxn, nfdName: string, config: ValidatorConfig): uint64 +autonumber stop +master -> validator: initializes new validator record, returns validator ID +end + +group Add pool for validator +autonumber 0 +validator -> master: [payment of mbr for new pool] +validator -> master: addPool(mbrPayment: PayTxn, validatorId: ValidatorID): ValidatorPoolKey +autonumber stop +master -> pool: [itxn] creates new staking pool contract instance +master -> validator: returns {Validator ID, Pool ID, Pool App ID} +... - Initialize Pool Storage - ... +autonumber 0 +validator -> pool: [payment of box storage mbr for stakers ledger in pool] +validator -> pool: initStorage(mbrPayment: PayTxn) +autonumber stop +pool -> pool: [If Pool 1 &\nif reward token set]\nOpt-In to Reward Token +... - If Reward Token Defined - ... +validator -> pool: (sends reward token [at any time] to Pool 1 or future Reward Token rewards) +end + +group Execute Epoch payouts +autonumber 0 +validator -> pool: [dummy gas() txn for ref filling] +validator -> pool: [dummy gas() txn for ref filling] +validator -> pool: [technically, anyone can call] - epochBalanceUpdate() - can only be called every X minutes as defined by validator) +autonumber 0 +pool -> validator: [itxn] getValidatorConfig() +pool -> validator: [itxn] [TokenEligible && POOL 1] setTokenPayoutRatio +autonumber 2 +pool -> validator: [itxn] [TokenEligible && POOL != 1] getPoolAppID of pool 1 +pool -> pool: [itxn] [TokenEligible && POOL != 1]\ncalls Pool 1: setTokenPayoutRatio (if pool 1) +pool -> validator: [itxn] getValidatorState() +pool -> validator: [itxn] (to validator's commission address) PAYMENT of validator's per-epoch commission - x% of available reward in pool. +autonumber stop +pool -> validator: [itxn] stakeUpdatedViaRewards() +pool -> pool: updates 'ledger' for all stakers based on\ntime in epoch & stake % +end +@enduml diff --git a/docs/README.md b/docs/README.md new file mode 100644 index 00000000..c285c722 --- /dev/null +++ b/docs/README.md @@ -0,0 +1,28 @@ +# Réti Open Pooling Overview + +## Protocol Overview + +The Réti Open Pooling protocol facilitates the creation of decentralized staking pools on the Algorand network, enabling broader participation in its consensus mechanism. + +* The minimum stake to receive node rewards on Algorand is 30,000 ALGO. +* The protocol allows anyone to create or join staking pools to collectively meet this threshold. +* It provides an open-source foundation with smart contracts, backend infrastructure, and customizable front-end interfaces. +* Validators can configure pools to suit varied needs while maintaining core immutable parameters. +* The protocol is completely decentralized and non-custodial. + +*** + +#### Key Objectives + +1. **Increase Participation in Algorand Consensus** + * Provides an option for permissionless staking pools. + * Allows small stakeholders to directly participate in consensus by pooling stakes. + * Users and validators can earn yield and secure the network. +2. **Enhance Overall Security with Decentralization** + * Promotes a variety of independent validators and staking pools. + * Offers a decentralized alternative to centralized liquid staking solutions. + * Helps diversify stake across numerous nodes for better security. +3. **Incentivize Many Validators** + * Enables smaller developers and communities to launch and operate staking pools. + * Provides a reliable revenue stream for projects to benefit from staking. + * Caters to meme coin, NFT communities, and other niche groups. diff --git a/docs/SUMMARY.md b/docs/SUMMARY.md new file mode 100644 index 00000000..50fd37b6 --- /dev/null +++ b/docs/SUMMARY.md @@ -0,0 +1,37 @@ +# Table of contents + +## Introduction + +* [Réti Open Pooling Overview](README.md) +* [Key Features](introduction/key-features.md) + +## Getting Started + +* [Quick Start For stakers](getting-started/quick-start-for-stakers.md) +* [Quick Start For Validators](getting-started/quick-start-for-validators.md) + +## Core Concepts + +* [Rewards](core-concepts/rewards.md) +* [Staking pools](core-concepts/staking-pools.md) +* [Validators](core-concepts/validators.md) + +## Technical Implementation + +* [Smart Contracts](technical-implementation/smart-contracts.md) +* [Reti Node Daemon](technical-implementation/reti-node-daemon/README.md) + * [Configuration](technical-implementation/reti-node-daemon/configuration.md) + * [Metrics](technical-implementation/reti-node-daemon/metrics.md) +* [Front End](technical-implementation/front-end.md) + +## Resources + +* [FAQ](resources/faq.md) +* [Contribute](resources/contribute.md) +* [Monitoring](resources/monitoring.md) +* [Report Bugs](resources/report-bugs.md) +* [Running A Node](resources/running-a-node.md) + +*** + +* [Discord](https://discord.gg/algorand) diff --git a/docs/core-concepts/rewards.md b/docs/core-concepts/rewards.md new file mode 100644 index 00000000..20c869c5 --- /dev/null +++ b/docs/core-concepts/rewards.md @@ -0,0 +1,67 @@ +# Rewards + +Staking pools will receive rewards when they propose blocks, as long as they're above the 30K ALGO threshold and below the maximum amount defined by the protocl (around 70M currently) and have good performance. Rewards for stakers and validators are distributed periodically at the end of each epoch, which is a fixed period of time determined by the validator. The reward distribution and calculation is designed to prevent gaming of the system. + +There is a special limit per-validator of 10% of all online stake. A type of slashing occurs if this is reached. See **Saturation** below. + +#### Reward Calculation + +The total reward for the pool is calculated based on the current pool balance and the known staked amount. This reward is then distributed between the validator and stakers according to the following process: + +1. **Validator Commission**: The validator receives their predefined commission, which is an immutable percentage set when defining the validator record (unless saturated). +2. **Staker Reward Distribution**: The remaining reward is distributed among the stakers proportionally based on their stake and the duration they were active in the epoch. + * Stakers who were active for the entire epoch receive their full share of the reward based on their percentage of the total staked amount. + * Stakers who added or removed stake during the epoch receive a partial reward proportional to the time they were active in the epoch. +3. **Compounding**: Staker rewards are directly added to their staked balance, compounding their future rewards. + +#### Soft caps and Validator Saturation + +* While developing this solution, [Stefano De Angelis](https://github.com/deanstef) suggested a Saturation model whereby stake is still allowed to be added to pools, but a **Saturated** validator starts to have diminished rewards. +* This Saturation level is a _soft_ limit designed to prevent too much stake going to one validator and which scales with the total online stake. + + **More than 10% of the currently online stake** **will be considered a Saturated validator.** The AVM will have a new opcode so that contracts may query the current online stake value. The pools will use this value for the soft limit. +* **Any validator exceeding this total threshold will be considered over-saturated and be negatively impacted.** The effective APR is reduced. In this state, the following changes: + * **Rewards accrued in each epoch are reduced proportionally to the amount 'over' the threshold.** + * **The validator receives no rewards** + * The remainder (rewards - paid outreduced rewards) is sent back to the fee sink where it will accrue for future payout to the protocol and node runners. + * The intended result is that this will encourage stakers to exit the pool or at least lower their stake to be within the thresholds. + * For example, if the current saturation limit for a validator is twice the amount staked in the pool, the reward will be halved. The below example showing a fictional 200 ALGO reward being available, with 100,000 ALGO being the 'soft limit' per validator and 200,000 ALGO currently staked to the validator. The 200 reward becomes 100 ALGO in this example. + +$$ +reward = \frac{algoReward * maxStakePerValidator}{totalStakeInValidator} = \frac{200*100000}{200000} = 100 +$$ + +#### Hard caps + +* **There is a 15% of online stake 'hard' cap** - where new stakers or additional stake can no longer be added to a validator. This is to help safeguard the protocol. + +#### Partial Epoch Staking + +To prevent gaming of the system, stakers who add or remove stake during an epoch receive only a partial reward for that epoch. The partial reward is calculated based on the percentage of time the staker was active in the epoch. + +For example, if a staker adds stake 95% of the way through an epoch, they would only receive 5% of the reward they would have received if they had been staked for the entire epoch. + +After receiving their partial reward, these stakers become full stakers for the subsequent epoch, assuming they do not add stake again. Each time a staker adds stake, their "clock" in the epoch resets. Accrued stake can always be removed without penalty however removing before an epoch forfeits any rewards accrued so far for that epoch. + +#### Epoch Duration + +Epochs can vary in duration, with some validators having extremely short epochs (as low as one minute). While the differences in partial rewards may be small for short epochs, preventing gaming of the system remains critical, particularly for larger epoch settings. + +#### Token Rewards + +Some validators may offer additional token rewards to incentivize staking. If a validator offers such rewards, the entire balance of any rewarded tokens is paid out to the staker when they remove any amount of stake from the pool. + +#### Stake Removal + +Stakers can remove their stake from the pool at any time. When stake is removed, the staker can decide how much they want to withdraw. It must either be the entire stake, or a balance above the minimum entry for the pool. + +## Payout Process + +* Determines the 'reward' amount based on the current pool balance vs the known 'staked' amount. +* Directly pays the validator their commission, which is immutable and part of defining the validator record itself. +* Walks the 'ledger' of stakers, and updates their balance to include their percentage of the shared reward (and thus compounding) +* The % share the user gets is based on their stake and is adjusted based on the % of time they were 'in the epoch'. A staker adding/entering stake 95% of the way through an epoch would only receive 5% of the reward they would have received had they been in the pool for the entire epoch. +* After paying 'partial' epoch holders, the remaining reward (which now has extra) is divided across the 'in pool 100% of the epoch' stakers with their relative % of the pool being based on their % of the total (minus the stake of the partial epoch stakers). +* The partial epoch holders will be full holders in the next epoch, assuming they don't add stake again. Each time adding stake resets their clock in the epoch. +* Some validators epochs might be extremely short (can be as low as minute), so the differences will be small but preventing gaming is still critical, particularly for larger epoch settings. +* Users can remove stake at will. If a validator offers a token as additional rewards, the entire balance of any rewarded tokens are paid out when removing any amount of stake. diff --git a/docs/core-concepts/staking-pools.md b/docs/core-concepts/staking-pools.md new file mode 100644 index 00000000..020cf643 --- /dev/null +++ b/docs/core-concepts/staking-pools.md @@ -0,0 +1,21 @@ +# Staking pools + +**Pool Creation:** Validators have the ability to create new staking pools on each node, up to a defined limit. Each pool originates as a unique staking pool contract, created by the master Validator contract from a pre-defined template. This ensures each pool operates as a distinct Algorand account eligible for consensus participation. + +**Stake Addition:** Users participate by directing their stake to specific validators, chosen by id through the master validator contract. The system intelligently allocates the user's stake to the appropriate pool within the chosen validator's portfolio. If the staker is already in a particular pool for that validator, their stake will be added their first unless the pool is full. + +Pools are considered full based on taking the LESSER of: + +* 15% of online stake / number of pools +* The max Algo per account allowed that still receives incentive rewards. + +No new stake can be added to a validator if the total Algo staked across all of the validators pools reaches 15% of online stake. + +**Ledger System:** A comprehensive ledger within each pool tracks up to 200 stakers. This ledger records crucial details such as the staker's account, the timing of their stake entry, the amount staked, and accumulated rewards. The design of the ledger aims to: + +* Prevent manipulation of reward distribution by adjusting entry times to neutralize advantage gained from last-minute large stakes. +* Provide transparency through on-chain visibility of all staker data and their compounded balances. +* Encourage a broad distribution of stakes and prevent minimal contributions by setting a minimum stake requirement (e.g., 1,000 ALGO), which guards against the dilution of pool value and competitive disruptions. +* Ensure that large numbers of stakers forces more pools to be created, forcing more nodes, and ultimately, more validators. + +**Payout Mechanism:** Rewards are computed based on the pool's current total balance. A defined percentage is allocated to the validator as commission, with the remaining balance compounded and distributed among stakers. This calculation takes into account the duration of each staker's participation within the payout epoch, ensuring a fair reward system that reflects the staker's commitment to the pool. Find more about the payout mechanism in [Rewards](rewards.md). diff --git a/docs/core-concepts/validators.md b/docs/core-concepts/validators.md new file mode 100644 index 00000000..e78ece0c --- /dev/null +++ b/docs/core-concepts/validators.md @@ -0,0 +1,36 @@ +# Validators + +{% hint style="warning" %} +Many parameters can ONLY be set up front, when defining the validator. + +Allowing them to be changed at will would be dangerous for stakers. +{% endhint %} + +**General Process:** Anyone is able to add themselves as a Validator. The protocol has safeguards in place to ensure Validators can't amass a dangerous amount of stake in a single pool, or combined across all pools for a single validator. + +*** + +**Key Elements Defined by Validators:** + +* **Owner Address:** Ideally, a cold-wallet address for security. +* **Management Address:** A hot-wallet address accessible by the 'reti node daemon' for operational commands. +* **Payout Epoch Time (in minutes):** Frequency of payout balance adjustments (daily, weekly, etc.). The node daemon will honor this time and trigger the 'epoch' based on the specified schedule for all pools. The commission is paid out every epoch. If the epoch is per day, then the commission % is that amount, per day. +* **Validator Commission Percentage:** Percentage the validator takes out of earned rewards per-epoch for covering operating costs. +* **Commission Address:** An Algorand address designated for receiving the validator commission, changeable by the owner. +* **Minimum Stake:** Establishes a lower limit for participation to avoid minimal contributions. +* **Maximum Stake Per Pool:** Can be set by validator to a lower amount than protocol maximum, or left as unset (0). + * The default maximum is based on taking the LESSER of: + * 15% of online stake / number of pools + * The max Algo per account allowed that still receives incentive rewards. This amount is currently 70 million algo but will likely change over time. +* **Pools Per Node:** There is a hard limit of 3 pools per node but the validator can define a smaller amount as a signal of how they will run deploy and limit their pools. +* **NFD ID (Optional):** For associating validators with detailed information for transparency. +* **Token / NFD Gating:** Validators can require that stakers hold certain types of assets in order to join their pools. This can be used to restrict validator pools to members of a particular community - NFT holders, special 'membership' tokens, etc. Supported options are: + * **Tokens/NFTs** by Creator and min amount (Optional): Can set a creator account such that all stakers must hold an ASA created by this account (w/ optional minimum amount for tokens). + * **Specific ASA ID**. + * **Tokens/NFTs created by any address linked within a particular NFD**. This is so NFT projects with multiple creation wallets can just reference their NFD and then anyone holding an asset created by any account linked w/in the NFD is eligible. + * **Owning a segment (including via linked addresses) of a particular NFD Root.** A project could have its own project root NFD, e.g., orange.algo, barb.algo, voi.algo, etc., and specify that only people owning a segment of a specific root can join. + * **Reward token and reward rate (Optional)** : A validator can define a token that users are awarded in addition to the ALGO they receive for being in the pool. This will allow projects to allow rewarding members their own token, e.g., hold at least 5000 VEST/COOP/AKTA, etc., to enter a staking pool, with 1 day epochs, and all stakers get X amount of their token as daily rewards (added to stakers' available balance) for removal at any time. +* **Sunsetting information** : Validators will be able to sunset their validators, leaving guidance for stakers that they're going away or moving to a new validator configuration. + +*** + diff --git a/docs/getting-started/quick-start-for-stakers.md b/docs/getting-started/quick-start-for-stakers.md new file mode 100644 index 00000000..010410f2 --- /dev/null +++ b/docs/getting-started/quick-start-for-stakers.md @@ -0,0 +1,50 @@ +# Quick Start For stakers + +## Comparing Validators + +Validators are not all created equal! They can vary greatly in their performance, incentives, fees, payout frequency, and restrictions. It's important to do due diligence on each Validator before attempting to stake. These details can be found in the Validator's linked NFD. + +**Performance** + +Not measured directly by the protocol; third parties such as Allo plan to monitor these metrics. + +If a node is slow and missing votes, those rewards are 'missed', resulting in a lower yield than if it was a healthy node participating with the same stake. Slow nodes are not 'doing their job' and so they aren't rewarded. + +**Incentives** + +Some pools have extra token rewards distributed to stakers on top of the ALGO received from participating in consensus. If these extra rewards have any market value, these pools could be providing higher yield than pools without extra rewards. It's important to always do due diligence on any validator incentives. + +**Fees** + +Validators can set a commission rate which is paid out as a percentage of rewards. The record is stored in the Validator record and is immutable (cannot be changed once created). + +**Payout Frequency** + +The frequency which epochs occur may effect the yield received due to txn fees and compounding returns. + +**Restrictions** + +Validator's may have restrictions set on their pools including: + +* Min entry amount +* Max entry amount +* Token / NFD Gating: + * Supported gating options include: + * Tokens/NFTs by creator and minimum amount + * Specific ASA id + * Tokens/NFTs created by any address linked within a particular NFD + * Owning a segment of a particular NFD Root + +## Staking + +To stake, find the Validator you want to stake with and select 'Stake'. + +Enter at least the minimum entry amount of ALGO and sign the transaction. + +You will now be able to see your staked amount with that Validator in the 'Staked' section. + +## Unstaking + +To unstake, find the Validator you want to unstake with in the 'Staked' section, and select 'Unstake'. + +When specifying the amount to unstake, it must be above the minimum entry amount, or the entire amount. diff --git a/docs/getting-started/quick-start-for-validators.md b/docs/getting-started/quick-start-for-validators.md new file mode 100644 index 00000000..066439d0 --- /dev/null +++ b/docs/getting-started/quick-start-for-validators.md @@ -0,0 +1,35 @@ +# Quick Start For Validators + +## Setting Up a Node + +The first step is to run a node. Find a number of different resources in [Running a Node](../resources/running-a-node.md) if you don't already have one running. + +## Define Validator + +Validators can define a number of parameters - some of which are immutable. More information on each parameter can be found in [Validators](../core-concepts/validators.md). + +**Mandatory Parameters** + +* owner address +* manager address +* Payout frequency +* Validator commission rate +* Validator fee address +* Minimum entry amount +* Maximum stake per pool (if the validator wants to limit it in some way). Default value will have max stake be same as max allowed and still receive incentives. +* Number of pools per node (participation keys) - Maximum of 3 +* Max number of nodes - Maximum of 8 + * This means a maximum of 24 pools can be created. + +**Optional Parameters** + +* Link an NFD to the Validator +* Reward token / reward rate +* Sunsetting information +* Token / NFD Gating: + * Supported gating options include: + * Tokens/NFTs by creator and min amount + * Specific ASA id + * Tokens/NFTs created by any address linked within a particular NFD. + * Owning a segment of a particular NFD Root + diff --git a/docs/introduction/key-features.md b/docs/introduction/key-features.md new file mode 100644 index 00000000..dfb2c3c6 --- /dev/null +++ b/docs/introduction/key-features.md @@ -0,0 +1,11 @@ +# Key Features + +The Réti open pooling protocol offers a framework for creating and managing Algorand staking pools, emphasizing flexibility, security, and community engagement. Key features include: + +* **Open Participation for Validators**: Anyone can register as a validator, promoting inclusivity and network decentralization. Validators are responsible for managing staking pools, including setting operational parameters such as payout frequencies and fee structures. +* **Secure account Management**: Validators must specify an owner address (preferably a cold wallet) and a management address (hot wallet) for operational tasks. This dual-account system ensures stronger security while facilitating pool management. +* **Flexible Staking Pool Configuration**: Validators have the autonomy to define various parameters for their staking pools, such as minimum and maximum stake amounts. They can also specify participation requirements, such as holding certain assets or NFTs, to create community-specific pools. Find more in [Validators](../core-concepts/validators.md). +* **Dynamic Reward Distribution**: The protocol supports adjustable payout intervals and reward distribution mechanisms, ensuring validators and stakers receive their earnings according to the staked amount and pool performance. This includes the option for validators to offer additional reward tokens alongside ALGO earnings. Find more in [Rewards](../core-concepts/rewards.md). +* **Automated Participation Key Management**: The Réti node daemon automates the generation and renewal of participation keys, maintaining pool activity and ensuring continuous consensus participation. This process is critical for keeping the pools operational and compliant with network protocols. +* **Decentralized Pool Creation and Management**: Each pool operates as a separate Algorand account, with its contract instance allowing for decentralized consensus participation. Validators can create new pools up to their limit, manage staker contributions through a master validator contract, and track staker investments via an on-chain ledger system. +* **Transparent and Fair Reward System**: A ledger within each pool tracks staker contributions and rewards, adjusting for the timing of stakes to prevent gaming of the reward system. Rewards are calculated based on the pool's performance, with mechanisms in place to ensure a fair distribution among all participants. diff --git a/docs/resources/contribute.md b/docs/resources/contribute.md new file mode 100644 index 00000000..5d6ee650 --- /dev/null +++ b/docs/resources/contribute.md @@ -0,0 +1,7 @@ +# Contribute + +Anyone is welcome to open a pull-request or fork the repo. The smart contracts are immutable, but the Node Daemon may be periodically improved. + +Come chat in the Algorand #node-runners discord channel. + +[https://discord.gg/algorand](https://discord.gg/algorand) diff --git a/docs/resources/faq.md b/docs/resources/faq.md new file mode 100644 index 00000000..a39c1bc0 --- /dev/null +++ b/docs/resources/faq.md @@ -0,0 +1,2 @@ +# FAQ + diff --git a/docs/resources/monitoring.md b/docs/resources/monitoring.md new file mode 100644 index 00000000..94b59330 --- /dev/null +++ b/docs/resources/monitoring.md @@ -0,0 +1,7 @@ +# Monitoring + +Monitoring of validator performance will be handled by third parties. + +List of monitoring sites: + +[allo.info](https://allo.info/) diff --git a/docs/resources/report-bugs.md b/docs/resources/report-bugs.md new file mode 100644 index 00000000..78f84dfd --- /dev/null +++ b/docs/resources/report-bugs.md @@ -0,0 +1,3 @@ +# Report Bugs + +Please report any bugs or issues found to: \ diff --git a/docs/resources/running-a-node.md b/docs/resources/running-a-node.md new file mode 100644 index 00000000..e013eafe --- /dev/null +++ b/docs/resources/running-a-node.md @@ -0,0 +1,14 @@ +# Running A Node + +Algorand developer docs:\ +[https://developer.algorand.org/docs/run-a-node/participate/](https://developer.algorand.org/docs/run-a-node/participate/) + +Community tutorials:\ +[https://medium.com/@alexbagdadi/how-i-set-up-my-algorand-node-6ccd5209d77d](https://medium.com/@alexbagdadi/how-i-set-up-my-algorand-node-6ccd5209d77d) + + + +One click node options: + +* Austs One Click Node: [https://github.com/AustP/austs-one-click-node/releases/](https://github.com/AustP/austs-one-click-node/releases/) +* Pixelnode: [https://www.pixelnode.org/](https://www.pixelnode.org/) diff --git a/docs/technical-implementation/front-end.md b/docs/technical-implementation/front-end.md new file mode 100644 index 00000000..03d2e8ff --- /dev/null +++ b/docs/technical-implementation/front-end.md @@ -0,0 +1,2 @@ +# Front End + diff --git a/docs/technical-implementation/reti-node-daemon/README.md b/docs/technical-implementation/reti-node-daemon/README.md new file mode 100644 index 00000000..7d10fd9f --- /dev/null +++ b/docs/technical-implementation/reti-node-daemon/README.md @@ -0,0 +1,20 @@ +# Reti Node Daemon + +## Overview + +* **Functionality:** Acts as both a command-line interface and a service daemon, compatible across Linux and OSX platforms. Windows may be supported in the future. +* **Management:** Facilitates minimal validator and pool configuration, leveraging a 'manager' account for transaction signatures. The included UI is the preferred method of management. +* **Participation Key Management:** Automates the creation and renewal of participation keys to maintain pool activity and online status. + +*** + +## Details + +* The Reti Node Daemon Is a combination CLI / Service daemon that will run on Linux / OSX and which node runners will run as a background service. +* This service can act as the configuration agent, letting users configure the validator, add pools, etc. but the UI for it will be easiest choice due to wallet integrations. +* Each node daemon will have access to a 'manager' account hot-wallet which it can sign transactions with. This manager account can be switched out by the owner of that validator to a new account at will if there is a compromise. +* The only accounts that can ever remove user funds are stakers removing only their (compounded) balance. The 'epoch update' call is made by the daemon for all pools, all aligned by the epoch time. This epoch update is what initiates the payout to the validator for their commission as well as updating the balances of all stakers. Any account can trigger this contract call, as it allows anyone to update eligible rewards even if the validator goes offline somehow. +* On each node, it will monitor the staking pools defined and automatically create short-lived (no more than 30 day) participation keys with that nodes algod instance. +* The participation keys will be monitored for expiration and new keys will be created in advance so that its always online. +* As participation keys are created, the paired staking pool will be instructed via the 'manager' to issue a transaction to go online against that participation key. +* The node daemon will likely provide a number of prometheus compatible metrics for scraping into compatible agents (staking amounts, etc.) but broader monitoring will be best handled independently. diff --git a/docs/technical-implementation/reti-node-daemon/configuration.md b/docs/technical-implementation/reti-node-daemon/configuration.md new file mode 100644 index 00000000..820fa91b --- /dev/null +++ b/docs/technical-implementation/reti-node-daemon/configuration.md @@ -0,0 +1,58 @@ +# Configuration + +Very few configuration parameters are actually required for running the node daemon (running with the 'daemon' command). The only requirements are: + +* The Algorand node to connect to for 'this' node (ALGO\_ALGOD\_URL env var)\ + Each Reti node MUST connect to a distinct Algorand node as the participation keys per-node are 1:1 mapped to specific pools you've assigned for your validator.\ + If running on same machine, this will likely be:\ + ALGO\_ALGOD\_URL=http://localhost:8080 +* Validator ID + * The validator ID assigned to you when yuo added yourself as a validator. This is simply a sequential number in the protocol. +* Node Number + * A number from 1 - X (the maximum number of nodes allowed in the protoclo) + * This can be set automatically for kubernetes installations using the (--usehostname flag) +* Mnemonics for the owner or manager address. + * The manager address is always preferred as it has fewer rights. Because the node daemon needs the keys to an address it can issue transactions to the validator/pool contracts with, and is thus a 'hot wallet', it needs to be an account with minimal rights. The manager address can only trigger epoch payouts, adding new pools, and having a pool going online or offline. + * The owner of a validator can change the manager address at any time. + +When starting, the specified mnemonics are checked and must correspond to an account that is either the owner or manager of the specified Validator. + +#### Environment loading + +There are a number of environment variables that can be specified. Any of these can be specified as **environment variables,** **command line flags** (in many cases), or in **environment files**. + +The following files are checked and loaded (if found in working directory) in the following order: + +.env.local\ +.env\ +.env.{network} (the name of the specified network - defaulting to mainnet)\ +{envfile} (if an environment file override was speciied on command line or via RETI\_ENVFILE env. var) + +#### Mnemonics + +Mnemonics for the manager address at the moment are read from the environment (in any manner defined above), by reading all environment variables with '\_MNEMONIC' as part of the environment variable name. The value is expected to be a space-delimited 25 word Algorand mnemoic. + +If none of the addresses loaded via these mnemonics match the owenr or manager of the specified validator ID, the node daemon will refuse to run. + +#### Global Command Line options + +
Command Line OptionEnvironment Variable
--envfile {file}RETI_ENVFILESpecify an additional file to process like an .env file.
--validatorRETI_VALIDATORIDThe validator ID of the validator running commands like the daemon
--nodeRETI_NODENUMThe node number (1 - 6)
--usehostnameWhen running in Kubernetes environments, this sets the node number assuming the node daemon is running as a sidecar alongside an algod container. The suffix of the (presumed statefulset) hostname is used for the node number. Since stateful sets are sequentially numbered starting from 0, the node number will be the hostname suffix + 1.
--networkALGO_NETWORKOverride the network to use (sandbox, betanet, testnet, mainnet, voitestnet)
+ +#### Options for 'Daemon' mode + +| Command Line Option | | +| ------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------- | +| --port |

Defaults to 6260.
Specifies the port the Node Daemon listens on for its HTTP endpoint.
The paths:
/ready
/metrics
are exposed.

| + +#### Environment only overrides + +Some options are only overriden through environment variables as they're more low-level. + +* ALGORAND\_DATA + * If detected, the address to connect to will be read from $ALGORAND\_DATA/algod.net and the admin token will be read from $ALGORAN\_DATA/algod.admin.token. +* ALGO\_ALGOD\_URL + * The Algorand node address (ie: http://localhost:8080) to connect to for this daemon's node. Each node daemon should connect to its own independent algorand node. +* ALGO\_ALGOD\_TOKEN + * The ADMIN token to use when making calls to the Algorand node for this daemon +* ALGO\_ALGOD\_HEADERS + * Comma delimiter key:value pairs to set in the headers passed in calls to the algod API. diff --git a/docs/technical-implementation/reti-node-daemon/metrics.md b/docs/technical-implementation/reti-node-daemon/metrics.md new file mode 100644 index 00000000..63b0dd1c --- /dev/null +++ b/docs/technical-implementation/reti-node-daemon/metrics.md @@ -0,0 +1,9 @@ +# Metrics + +When running as a daemon, using the 'daemon' command, some simple Prometheus compatible metrics are exposed via the standard /metrics HTTP endpoint (defaulting on port 6260): + +These metrics are reported \*per node\* and the assumption is that you fetch these metrics from all of your nodes and sum / max them. + +The current Prometheus metrics are: + +
MetricTypeDescription
reti_max_stake_allowed_totalgaugeCurrent maximum stake per validator allowed by the protocol. This is defined as 15% of online stake.
reti_max_stake_before_saturated_totalgaugeCurrent stake per validator allowed by the protocol before the validator is considered 'saturated' and rewards are diminished. This is defined as 10% of online stake.
reti_pool_countgaugeTotal number of pools assigned to this node.
reti_reward_available_totalgaugeRewards currently available for the pools on this node. This will be the amount in excess of known stake (minus MBR)
reti_staked_totalgaugeThe total amount of stake in the pools on this node.
reti_staker_countgaugeThe total number of stakes in pools on this node.
diff --git a/docs/technical-implementation/smart-contracts.md b/docs/technical-implementation/smart-contracts.md new file mode 100644 index 00000000..bb54e0a5 --- /dev/null +++ b/docs/technical-implementation/smart-contracts.md @@ -0,0 +1,19 @@ +# Smart Contracts + +The contracts are written using AlgoKit and TEALScript. See [Tealscript](https://tealscript.algo.xyz) for details. + +See the README in the contracts/ directory for build / testing details. + +

General Overview

+ +

Basic Operations

+ +*** + +## **Validator Operations** + +
+ +## **Staking Operations** + +
diff --git a/nodemgr/app.go b/nodemgr/app.go new file mode 100644 index 00000000..be0c5c9c --- /dev/null +++ b/nodemgr/app.go @@ -0,0 +1,242 @@ +package main + +import ( + "context" + "errors" + "fmt" + "log" + "log/slog" + "os" + "strconv" + "strings" + + "github.com/algorand/go-algorand-sdk/v2/client/v2/algod" + "github.com/joho/godotenv" + "github.com/urfave/cli/v3" + "golang.org/x/term" + + "github.com/TxnLab/reti/internal/lib/algo" + "github.com/TxnLab/reti/internal/lib/misc" + "github.com/TxnLab/reti/internal/lib/nfdapi/swagger" + "github.com/TxnLab/reti/internal/lib/reti" +) + +var logLevel = new(slog.LevelVar) // Info by default + +func initApp() *RetiApp { + log.SetFlags(0) + var logger *slog.Logger + if term.IsTerminal(int(os.Stdout.Fd())) { + // Are we running on something where output is a tty - so we're being run as CLI vs as a daemon + logger = slog.New(misc.NewMinimalHandler(os.Stdout, + misc.MinimalHandlerOptions{SlogOpts: slog.HandlerOptions{Level: logLevel, AddSource: true}})) + } else { + // not on console - output as json, but change json key names to be more compatibl w/ what google logging + // expects + opts := &slog.HandlerOptions{ + AddSource: true, + Level: logLevel, + ReplaceAttr: func(groups []string, a slog.Attr) slog.Attr { + if a.Key == slog.MessageKey { + a.Key = "message" + } else if a.Key == slog.LevelKey && len(groups) == 0 { + a.Key = "severity" + } + return a + }, + } + logger = slog.New(slog.NewJSONHandler(os.Stdout, opts)) + } + slog.SetDefault(logger) + if os.Getenv("DEBUG") == "1" { + logLevel.Set(slog.LevelDebug) + } + // We initialize our wrapper instance first, so we can call its methods in the 'Before' lambda func + // in initialization of cli App instance. + // signer will be set in the initClients method. + appConfig := &RetiApp{logger: logger} + + appConfig.cliCmd = &cli.Command{ + Name: "réti node manager", + Usage: "Configuration tool and background daemon for Algorand validator pools", + Version: misc.GetVersionInfo(), + Before: func(ctx context.Context, cmd *cli.Command) error { + // This is further bootstrap of the 'app' but within context of 'cli' helper as it will + // have access to flags and options (network to use for eg) already set. + return appConfig.initClients(ctx, cmd) + }, + Flags: []cli.Flag{ + &cli.StringFlag{ + Name: "envfile", + Usage: "env file to load", + Sources: cli.EnvVars("RETI_ENVFILE"), + Aliases: []string{"e"}, + }, + &cli.StringFlag{ + Name: "network", + Usage: "Algorand network to use", + Value: "mainnet", + Aliases: []string{"n"}, + Sources: cli.EnvVars("ALGO_NETWORK"), + }, + &cli.UintFlag{ + Name: "retiid", + Usage: "[DEV ONLY] The application id of the Reti master validator contract.", + Sources: cli.EnvVars("RETI_APPID"), + Destination: &appConfig.retiAppID, + OnlyOnce: true, + }, + &cli.UintFlag{ + Name: "validator", + Usage: "The Validator id for your validator. Can be unset if defining for first time.", + Sources: cli.EnvVars("RETI_VALIDATORID"), + Value: 0, + Destination: &appConfig.retiValidatorID, + OnlyOnce: true, + }, + &cli.BoolFlag{ + Name: "usehostname", + Usage: "Use the hostname (assuming -0, -1, -2, etc. suffix) as node number. For use when paired w/ Kubernetes statefulsets", + Value: false, + }, + &cli.UintFlag{ + Name: "node", + Usage: "The node number (1+) this node represents in those configured for this validator. Configuration is updated/configured based on this node", + Sources: cli.EnvVars("RETI_NODENUM"), + Value: 0, + Destination: &appConfig.retiNodeNum, + OnlyOnce: true, + }, + }, + Commands: []*cli.Command{ + GetDaemonCmdOpts(), + GetValidatorCmdOpts(), + GetPoolCmdOpts(), + GetKeyCmdOpts(), + }, + } + return appConfig +} + +type RetiApp struct { + cliCmd *cli.Command + logger *slog.Logger + signer algo.MultipleWalletSigner + algoClient *algod.Client + nfdApi *swagger.APIClient + retiClient *reti.Reti + + // just here for flag bootstrapping destination + retiAppID uint64 + retiValidatorID uint64 + retiNodeNum uint64 +} + +// initClients initializes both an an algod client (to correct network - which it +// also validates) and an nfd nfdApi clinet - for nfd updates or fetches if caller +// desires +func (ac *RetiApp) initClients(ctx context.Context, cmd *cli.Command) error { + network := cmd.String("network") + + if envfile := cmd.String("envfile"); envfile != "" { + err := loadNamedEnvFile(ctx, envfile) + if err != nil { + return err + } + } + // quick validity check on possible network names... + switch network { + case "sandbox", "betanet", "testnet", "mainnet", "voitestnet": + default: + return fmt.Errorf("unknown network:%s", network) + } + var ( + algoClient *algod.Client + api *swagger.APIClient + err error + ) + + // Now load .env.{network} overrides -ie: .env.sandbox containing generated mnemonics + // by bootstrap testing script + misc.LoadEnvForNetwork(network) + + // Initialize algod client / networks / reti validator app id (testing connectivity as well) + cfg := algo.GetNetworkConfig(network) + algoClient, err = algo.GetAlgoClient(ac.logger, cfg) + if err != nil { + return err + } + ac.retiAppID = cfg.RetiAppID + // allow secondary override of the IDs via the network specific .env file we just loaded which we couldn't + // have known until we'd processed the 'network' override - but only if not already set via CLI, etc. + if ac.retiAppID == 0 { + setIntFromEnv(&ac.retiAppID, "RETI_APPID") + } + if ac.retiValidatorID == 0 { + setIntFromEnv(&ac.retiValidatorID, "RETI_VALIDATORID") + } + if ac.retiNodeNum == 0 { + setIntFromEnv(&ac.retiNodeNum, "RETI_NODENUM") + } + if ac.retiNodeNum == 0 && cmd.Bool("usehostname") { + // we're assumed in kubernetes environment, try getting the node number from our hostname suffix + // ie: somehost-0 - where the node num would be 0 (and we add 1) + if hostname, err := os.Hostname(); err == nil { + parts := strings.Split(hostname, "-") + if len(parts) > 1 { + nodeNum, err := strconv.ParseUint(parts[len(parts)-1], 10, 64) + if err == nil { + ac.retiNodeNum = nodeNum + 1 + misc.Infof(ac.logger, "used hostname %s to set node number to:%d", hostname, ac.retiNodeNum) + } + } + } + } + + if ac.retiAppID == 0 { + return fmt.Errorf("the id of the Reti Validator contract must be set using either -id or RETI_APPID env var!") + } + + // This will load and initialize mnemonics from the environment - and handles all 'local' signing for the app + ac.signer = algo.NewLocalKeyStore(ac.logger) + + // Inititialize NFD API (if even used) + nfdApiCfg := swagger.NewConfiguration() + nfdApiCfg.BasePath = cfg.NFDAPIUrl + api = swagger.NewAPIClient(nfdApiCfg) + _, _ = algoClient, api + + ac.algoClient = algoClient + ac.nfdApi = api + + // Initialize the 'reti' client + retiClient, err := reti.New(ac.retiAppID, ac.logger, ac.algoClient, ac.signer, ac.retiValidatorID, ac.retiNodeNum) + if err != nil { + return err + } + ac.retiClient = retiClient + return retiClient.LoadState(ctx) +} + +func setIntFromEnv(val *uint64, envName string) error { + if strVal := os.Getenv(envName); strVal != "" { + intVal, err := strconv.ParseUint(strVal, 10, 64) + if err != nil { + return err + } + *val = intVal + } + return nil +} + +func checkConfigured(ctx context.Context, command *cli.Command) error { + if !App.retiClient.IsConfigured() { + return errors.New("validator not configured") + } + return nil +} + +func loadNamedEnvFile(ctx context.Context, envFile string) error { + misc.Infof(App.logger, "loading env file:%s", envFile) + return godotenv.Load(envFile) +} diff --git a/nodemgr/daemon.go b/nodemgr/daemon.go new file mode 100644 index 00000000..3f7123c0 --- /dev/null +++ b/nodemgr/daemon.go @@ -0,0 +1,568 @@ +package main + +import ( + "bytes" + "context" + "errors" + "fmt" + "log/slog" + "maps" + "net/http" + "os" + "sort" + "sync" + "time" + + "github.com/algorand/go-algorand-sdk/v2/client/v2/algod" + "github.com/algorand/go-algorand-sdk/v2/crypto" + "github.com/algorand/go-algorand-sdk/v2/types" + "github.com/mailgun/holster/v4/syncutil" + "github.com/prometheus/client_golang/prometheus/promhttp" + "github.com/ssgreg/repeat" + + "github.com/TxnLab/reti/internal/lib/algo" + "github.com/TxnLab/reti/internal/lib/misc" + "github.com/TxnLab/reti/internal/lib/reti" +) + +const ( + OnlineStatus = "Online" + GeneratedKeyLengthInDays = 7 +) + +// Daemon provides a 'little' separation in that we initalize it with some data from the App global set up by +// the process startup, but the Daemon tries to be fairly retrieval with its data retrieval and use. +type Daemon struct { + logger *slog.Logger + algoClient *algod.Client + + // embed mutex for locking state for members below the mutex + sync.RWMutex + avgBlockTime time.Duration +} + +func newDaemon() *Daemon { + return &Daemon{ + logger: App.retiClient.Logger, + algoClient: App.algoClient, + } +} + +func (d *Daemon) start(ctx context.Context, wg *sync.WaitGroup, listenPort int) { + d.logger.Info("Réti daemon started") + wg.Add(1) + go func() { + defer wg.Done() + d.KeyWatcher(ctx) + }() + + wg.Add(1) + go func() { + defer wg.Done() + d.EpochUpdater(ctx) + }() + + wg.Add(1) + go func() { + defer wg.Done() + http.Handle("/ready", isReady()) + http.Handle("/metrics", promhttp.Handler()) + + host := fmt.Sprintf(":%d", listenPort) + srv := &http.Server{Addr: host} + go func() { + misc.Infof(d.logger, "HTTP server listening on %q", host) + srv.ListenAndServe() + }() + + <-ctx.Done() + misc.Infof(d.logger, "shutting down HTTP server at %q", host) + + // Shutdown gracefully with a 30s max wait. + ctx, cancel := context.WithTimeout(ctx, 30*time.Second) + defer cancel() + + _ = srv.Shutdown(ctx) + }() +} + +func isReady() http.Handler { + return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + w.WriteHeader(http.StatusOK) + }) +} + +// KeyWatcher keeps track of both active pools for this node (updated via configuration file) as well +// as participation keys with the algod daemon. It creates and maintains participation keys as necessary. +func (d *Daemon) KeyWatcher(ctx context.Context) { + defer d.logger.Info("Exiting KeyWatcher") + d.logger.Info("Starting KeyWatcher") + + // make sure avg block time is set first + err := d.setAverageBlockTime(ctx) + if err != nil { + misc.Errorf(d.logger, "unable to fetch blocks to determine block times: %v", err) + os.Exit(1) + } + d.checkPools(ctx) + + checkTime := time.NewTicker(1 * time.Minute) + blockTimeUpdate := time.NewTicker(30 * time.Minute) + defer checkTime.Stop() + defer blockTimeUpdate.Stop() + + // Check our key validity once a minute + for { + select { + case <-ctx.Done(): + return + case <-checkTime.C: + // Make sure our 'config' is fresh in case the user updated it + // they could have added new pools, moved them between nodes, etc. + err := d.refetchConfig() + if err != nil { + misc.Warnf(d.logger, "error in fetching configuration, will retry. err:%v", err) + // try later. + break + } + + d.updatePoolVersions(ctx) + d.checkPools(ctx) + case <-blockTimeUpdate.C: + d.setAverageBlockTime(ctx) + } + } +} + +type onlineInfo struct { + poolAppId uint64 + isOnline bool + selectionParticipationKey []byte + firstValid uint64 +} + +func (d *Daemon) checkPools(ctx context.Context) { + // get online status and partkey info for all our accounts (ignoring any that don't have balances yet) + var poolAccounts = map[string]onlineInfo{} + for poolId, poolAppId := range App.retiClient.Info().LocalPools { + acctInfo, err := algo.GetBareAccount(context.Background(), d.algoClient, crypto.GetApplicationAddress(poolAppId).String()) + if err != nil { + d.logger.Warn("account fetch error", "account", crypto.GetApplicationAddress(poolAppId).String(), "error", err) + return + } + info := onlineInfo{ + poolAppId: poolAppId, + isOnline: acctInfo.Status == OnlineStatus, + selectionParticipationKey: acctInfo.Participation.SelectionParticipationKey, + firstValid: acctInfo.Participation.VoteFirstValid, + } + if acctInfo.Amount-acctInfo.MinBalance > 1e6 { + poolAccounts[crypto.GetApplicationAddress(poolAppId).String()] = info + } + // ensure pools were initialized properly (since it's a two-step process - the second step may have been skipped?) + err = App.retiClient.CheckAndInitStakingPoolStorage(&reti.ValidatorPoolKey{ + ID: App.retiClient.Info().Config.ID, + PoolId: poolId, + PoolAppId: poolAppId, + }) + if err != nil { + misc.Errorf(d.logger, "error ensuring participation init: %v", err) + return + } + } + // now get all the current participation keys for our node + partKeys, err := algo.GetParticipationKeys(ctx, d.algoClient) + if err != nil { + d.logger.Warn("participation key fetch error", "error", err) + return + } + // first, remove all expired keys ! (regardless if currently for our node or not) + anyRemoved, err := d.removeExpiredKeys(ctx, partKeys) + if err != nil { + misc.Errorf(d.logger, "error removing an expired key: %v", err) + return + } + if anyRemoved { + // get part key list again because we removed some... + partKeys, err = algo.GetParticipationKeys(ctx, d.algoClient) + if err != nil { + d.logger.Warn("participation key fetch error", "error", err) + return + } + } + // filter partKeys to just the accounts matching our pools. + // Other accounts aren't our problem or under our control at this point + maps.DeleteFunc(partKeys, func(address string, keys []algo.ParticipationKey) bool { + _, found := poolAccounts[address] + return !found + }) + + err = d.ensureParticipation(ctx, poolAccounts, partKeys) + if err != nil { + misc.Errorf(d.logger, "error ensuring participation: %v", err) + return + } +} + +func (d *Daemon) updatePoolVersions(ctx context.Context) { + managerAddr, _ := types.DecodeAddress(App.retiClient.Info().Config.Manager) + + versString, err := algo.GetVersionString(ctx, d.algoClient) + if err != nil { + misc.Errorf(d.logger, "unable to fetch version string from algod instance, err:%v", err) + return + } + for _, poolAppId := range App.retiClient.Info().LocalPools { + algodVer, err := App.retiClient.GetAlgodVer(poolAppId) + if err != nil && !errors.Is(err, algo.ErrStateKeyNotFound) { + misc.Errorf(d.logger, "unable to fetch algod version from staking pool app id:%d, err:%v", poolAppId, err) + return + } + if algodVer != versString { + // Update version in staking pool + err = App.retiClient.UpdateAlgodVer(poolAppId, versString, managerAddr) + if err != nil { + misc.Errorf(d.logger, "unable to update algod version in staking pool app id:%d, err:%v", poolAppId, err) + return + } + } + } +} + +func (d *Daemon) AverageBlockTime() time.Duration { + d.RLock() + defer d.RUnlock() + return d.avgBlockTime +} + +func (d *Daemon) setAverageBlockTime(ctx context.Context) error { + // Get the latest block via the algoClient.Status() call, then + // fetch the most recent X blocks - fetching the timestamps from each and + // determining the approximate current average block time. + const numRounds = 10 + + status, err := d.algoClient.Status().Do(context.Background()) + if err != nil { + return fmt.Errorf("unable to fetch node status: %w", err) + } + var blockTimes []time.Time + for round := status.LastRound - numRounds; round < status.LastRound; round++ { + block, err := d.algoClient.Block(round).Do(ctx) + if err != nil { + return fmt.Errorf("unable to fetch block in getAverageBlockTime, err:%w", err) + } + blockTimes = append(blockTimes, time.Unix(block.TimeStamp, 0)) + } + var totalBlockTime time.Duration + for i := 1; i < len(blockTimes); i++ { + totalBlockTime += blockTimes[i].Sub(blockTimes[i-1]) + } + d.Lock() + d.avgBlockTime = totalBlockTime / time.Duration(len(blockTimes)-1) + d.Unlock() + misc.Infof(d.logger, "average block time set to:%v", d.AverageBlockTime()) + return nil +} + +func (d *Daemon) refetchConfig() error { + var err error + err = repeat.Repeat( + repeat.Fn(func() error { + err = App.retiClient.LoadState(context.Background()) + if err != nil { + return repeat.HintTemporary(err) + } + return nil + }), + repeat.StopOnSuccess(), + repeat.LimitMaxTries(10), + repeat.FnOnError(func(err error) error { + misc.Warnf(d.logger, "retrying fetch of validator info, error:%v", err.Error()) + return err + }), + repeat.WithDelay( + repeat.SetContextHintStop(), + (&repeat.FullJitterBackoffBuilder{ + BaseDelay: 5 * time.Second, + MaxDelay: 10 * time.Second, + }).Set(), + ), + ) + return err +} + +func (d *Daemon) createPartKey(ctx context.Context, account string, firstValid uint64) (*algo.ParticipationKey, error) { + // generate keys good for one month based on current avg block time - nothing is returned until key is actually created + status, err := d.algoClient.Status().Do(context.Background()) + if err != nil { + return nil, fmt.Errorf("unable to fetch node status: %w", err) + } + if firstValid == 0 { + firstValid = status.LastRound + } + keyDurationInSeconds := GeneratedKeyLengthInDays * 60 * 60 * 24 + lastValid := firstValid + uint64(float64(keyDurationInSeconds)/d.AverageBlockTime().Seconds()) + return algo.GenerateParticipationKey(ctx, d.algoClient, d.logger, account, firstValid, lastValid) +} + +// 1) Part key found but expired - delete it +func (d *Daemon) removeExpiredKeys(ctx context.Context, partKeys algo.PartKeysByAddress) (bool, error) { + status, err := d.algoClient.Status().Do(ctx) + if err != nil { + return false, fmt.Errorf("unable to fetch node status: %w", err) + } + var anyRemoved bool + for _, keys := range partKeys { + for _, key := range keys { + if key.Key.VoteLastValid < status.LastRound { + misc.Infof(d.logger, "key:%s for account:%s is expired, removing", key.Id, key.Address) + err = algo.DeleteParticipationKey(ctx, d.algoClient, d.logger, key.Id) + if err != nil { + if err != nil { + return false, fmt.Errorf("error deleting participation key for id:%s, err:%w", key.Id, err) + } + } + anyRemoved = true + } + } + } + return anyRemoved, nil +} + +func (d *Daemon) ensureParticipation(ctx context.Context, poolAccounts map[string]onlineInfo, partKeys algo.PartKeysByAddress) error { + /** conditions to cover for participation keys / accounts + 1) account has NO local participation key (online or offline) (ie: they could've moved to new node) + Create brand new 1-month key - will go online as part of subsequent checks once part key becomes visible + 2) account is NOT online but has one or more part keys + Go online against newest part key - done + 3) account has ONE local part key AND IS ONLINE + Assumed 'steady state' - check lifetime of CURRENT key and if expiring within 1 day + If expiring soon, create new key w/ firstValid set to existing key's lastValid - 1 day of rounds. + 4) account is online and has multiple local part keys + If Online (assumed steady state when a future pending part key has been created) + Sort keys descending by first valid + If part key first valid is >= current round AND not current part. key id for account + Go online against this new key - done. prior key will be removed a week later when it's out of valid range + */ + // get accounts without (local) part. keys at all. + if err := d.ensureParticipationNoKeysYet(ctx, poolAccounts, partKeys); err != nil { + return err + } + // Not online... + if err := d.ensureParticipationNotOnline(ctx, poolAccounts, partKeys); err != nil { + return err + } + // account has 1 part key, IS ONLINE and might expire soon (needing to generate new key) + if err := d.ensureParticipationCheckNeedsRenewed(ctx, poolAccounts, partKeys); err != nil { + return err + } + // account is online - see if there's a newer key to 'switch' to + if err := d.ensureParticipationCheckNeedsSwitched(ctx, poolAccounts, partKeys); err != nil { + return err + } + return nil +} + +// Handle: account has NO local participation key (online or offline) +func (d *Daemon) ensureParticipationNoKeysYet(ctx context.Context, poolAccounts map[string]onlineInfo, partKeys algo.PartKeysByAddress) error { + for account, _ := range poolAccounts { + // for accounts w/ no keys at all - we just create keys - we'll go online as part of later checks + if _, found := partKeys[account]; !found { + _, err := d.createPartKey(ctx, account, 0) + if err != nil { + misc.Errorf(d.logger, "error generating part key for missing account:%s, err:%v", account, err) + return nil + } + } + } + // go online, etc. as part of normal checks - so just return now and next pass will fix + return nil +} + +// Handle: account is NOT online but has one or more part keys - go online against newest +func (d *Daemon) ensureParticipationNotOnline(ctx context.Context, poolAccounts map[string]onlineInfo, partKeys algo.PartKeysByAddress) error { + var ( + err error + managerAddr, _ = types.DecodeAddress(App.retiClient.Info().Config.Manager) + ) + + for account, info := range poolAccounts { + if !info.isOnline { + keysForAccount, found := partKeys[account] + if !found { + continue + } + // sort the part keys by whichever has highest firstValid + sort.Slice(keysForAccount, func(i, j int) bool { + return keysForAccount[i].Key.VoteFirstValid > keysForAccount[j].Key.VoteFirstValid + }) + keyToUse := keysForAccount[0] + misc.Infof(d.logger, "account:%s is NOT online, going online against newest of %d part keys, id:%s", account, len(keysForAccount), keyToUse.Id) + + err = App.retiClient.GoOnline(info.poolAppId, managerAddr, keyToUse.Key.VoteParticipationKey, keyToUse.Key.SelectionParticipationKey, keyToUse.Key.StateProofKey, keyToUse.Key.VoteFirstValid, keyToUse.Key.VoteLastValid, keyToUse.Key.VoteKeyDilution) + if err != nil { + return fmt.Errorf("unable to go online for account:%s [pool app id:%d], err:%w", account, info.poolAppId, err) + } + misc.Infof(d.logger, "participation key went online for account:%s [pool app id:%d]", account, info.poolAppId) + } + } + return nil +} + +/* +account has 1 part key AND IS ONLINE + + We only allow 1 part key so we don't keep trying to create new key when we're close to expiration. + Assumed 'steady state' - check lifetime of key and if expiring within 1 day + If expiring soon, create new key w/ firstValid set to existing key's lastValid - 1 day of rounds. done +*/ +func (d *Daemon) ensureParticipationCheckNeedsRenewed(ctx context.Context, poolAccounts map[string]onlineInfo, partKeys algo.PartKeysByAddress) error { + status, err := d.algoClient.Status().Do(ctx) + if err != nil { + d.logger.Warn("failure in getting current node status w/in getExpiringKeys", "error", err) + return nil + } + curRound := status.LastRound + avgBlockTime := d.AverageBlockTime() + + for account, info := range poolAccounts { + if !info.isOnline { + continue + } + if len(partKeys[account]) != 1 { + continue + } + activeKey := partKeys[account][0] + if bytes.Compare(activeKey.Key.SelectionParticipationKey, info.selectionParticipationKey) == 0 { + if activeKey.EffectiveFirstValid > curRound { + // activeKey isn't even in range yet ignore for now + continue + } + expValidDistance := time.Duration(activeKey.Key.VoteLastValid-curRound) * avgBlockTime + if expValidDistance.Hours() < 24*7 { + oneDayOfBlocks := (24 * time.Hour) / avgBlockTime + misc.Infof(d.logger, "activeKey: %s for %s expiring in %v, creating new key with ~1 day lead-time", activeKey.Id, activeKey.Address, expValidDistance) + d.createPartKey(ctx, account, activeKey.Key.VoteLastValid-uint64(oneDayOfBlocks)) + } + } + } + return nil + +} + +/* +Handle: account is online and has multiple local part keys + + If Online (assumed steady state when a future pending part key has been created) + Sort keys descending by first valid + If part key first valid is >= current round AND not current part. key id for account + Go online against this new key - done. prior key will be removed a week later when it's out of valid range +*/ +func (d *Daemon) ensureParticipationCheckNeedsSwitched(ctx context.Context, poolAccounts map[string]onlineInfo, partKeys algo.PartKeysByAddress) error { + managerAddr, _ := types.DecodeAddress(App.retiClient.Info().Config.Manager) + + status, err := d.algoClient.Status().Do(ctx) + if err != nil { + d.logger.Warn("failure in getting current node status w/in getExpiringKeys", "error", err) + return nil + } + curRound := status.LastRound + + for account, info := range poolAccounts { + if !info.isOnline { + continue + } + keysForAccount, found := partKeys[account] + if !found { + continue + } + // get the CURRENTLY active key for this account by finding the key w/in keysForAccount that matches the + // selection key w/in info + var activeKey algo.ParticipationKey + for _, key := range keysForAccount { + if bytes.Compare(key.Key.SelectionParticipationKey, info.selectionParticipationKey) == 0 { + activeKey = key + break + } + } + if activeKey.Id == "" { + return fmt.Errorf("unable to find the participation key that is online against account:%s", account) + } + // sort the part keys by whichever has highest firstValid + sort.Slice(keysForAccount, func(i, j int) bool { + return keysForAccount[i].Key.VoteFirstValid > keysForAccount[j].Key.VoteFirstValid + }) + keyToCheck := keysForAccount[0] + if keyToCheck.Id == activeKey.Id { + // newest key is key we're already online with... done + continue + } + if keyToCheck.EffectiveFirstValid > curRound { + // activeKey isn't even in range yet ignore for now + continue + } + // Ok, time to switch to the new key - it's in valid range + misc.Infof(d.logger, "account:%s is NOT online, going online against newest of %d part keys, id:%s", account, len(keysForAccount), keyToCheck.Id) + err = App.retiClient.GoOnline(info.poolAppId, managerAddr, keyToCheck.Key.VoteParticipationKey, keyToCheck.Key.SelectionParticipationKey, keyToCheck.Key.StateProofKey, keyToCheck.Key.VoteFirstValid, keyToCheck.Key.VoteLastValid, keyToCheck.Key.VoteKeyDilution) + if err != nil { + return fmt.Errorf("unable to go online for account:%s [pool app id:%d]", account, info.poolAppId) + } + misc.Infof(d.logger, "participation key went online for account:%s [pool app id:%d]", account, info.poolAppId) + } + return nil + +} + +func (d *Daemon) EpochUpdater(ctx context.Context) { + d.logger.Info("EpochUpdater started") + defer d.logger.Info("EpochUpdater stopped") + + epochMinutes := App.retiClient.Info().Config.PayoutEveryXMins + + epochTimer := time.NewTimer(durationToNextEpoch(time.Now(), epochMinutes)) + defer epochTimer.Stop() + + for { + select { + case <-ctx.Done(): + return + case <-epochTimer.C: + signerAddr, _ := types.DecodeAddress(App.retiClient.Info().Config.Manager) + epochTimer.Reset(durationToNextEpoch(time.Now(), epochMinutes)) + var ( + eg syncutil.WaitGroup + info = App.retiClient.Info() + ) + for i, pool := range info.Pools { + // usual go hack so we don't reference pointers of the iterators + i := i + appid := pool.PoolAppId + if _, found := info.LocalPools[uint64(i+1)]; !found { + continue + } + eg.Run(func(val any) error { + err := App.retiClient.EpochBalanceUpdate(i+1, appid, signerAddr) + if err != nil { + if !errors.Is(err, reti.ErrNotEnoughRewardAvailable) { + return fmt.Errorf("epoch balance update failed for pool app id:%d, err:%w", i+1, err) + } + } + return nil + }, nil) + } + errs := eg.Wait() + for _, err := range errs { + d.logger.Error("error returned from EpochUpdater", "error", err) + } + } + } +} + +func durationToNextEpoch(curTime time.Time, epochMinutes int) time.Duration { + dur := curTime.Round(time.Duration(epochMinutes) * time.Minute).Sub(curTime) + if dur <= 0 { + dur = time.Duration(epochMinutes) * time.Minute + } + slog.Debug(fmt.Sprintf("%v epoch duration in mins:%d, dur to next epoch:%v", curTime, epochMinutes, dur)) + return dur +} diff --git a/nodemgr/daemon_test.go b/nodemgr/daemon_test.go new file mode 100644 index 00000000..f4b810fa --- /dev/null +++ b/nodemgr/daemon_test.go @@ -0,0 +1,38 @@ +package main + +import ( + "testing" + "time" + + "github.com/stretchr/testify/assert" +) + +func TestDurationToNextEpochRefactored(t *testing.T) { + testCases := []struct { + name string + epochMinutes int + currentTime time.Time + expectedDurMin float64 + }{ + {"11:10:15->12:00:00", 60, time.Date(2024, 1, 1, 11, 10, 15, 0, time.UTC), 60.0}, + {"11:55:55->12:00:00", 60, time.Date(2024, 1, 1, 11, 55, 15, 0, time.UTC), 4.75}, + {"00:00:00->01:00:00", 15, time.Date(2024, 1, 1, 0, 0, 0, 0, time.UTC), 15.0}, + {"00:15:30->00:30:00", 15, time.Date(2024, 1, 1, 0, 15, 30, 0, time.UTC), 15.0}, + {"00:30:45->00:45:00", 15, time.Date(2024, 1, 1, 0, 30, 45, 0, time.UTC), 15.0}, + {"00:45:00->01:00:00", 15, time.Date(2024, 1, 1, 0, 45, 0, 0, time.UTC), 15.0}, + {"00:07:30->00:15:00", 15, time.Date(2024, 1, 1, 0, 7, 30, 0, time.UTC), 7.5}, + {"00:15:00->00:30:00", 30, time.Date(2024, 1, 1, 0, 15, 0, 0, time.UTC), 15.0}, + {"00:30:00->01:00:00", 60, time.Date(2024, 1, 1, 0, 30, 0, 0, time.UTC), 30.0}, + {"01 12:00:00->02 00:00:00", 24 * 60, time.Date(2024, 1, 1, 12, 0, 0, 0, time.UTC), 12 * 60.0}, + } + + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + actualDur := durationToNextEpoch(tc.currentTime, tc.epochMinutes) + //fmt.Printf("dur:%v from:%v to:%v", tc.epochMinutes, tc.currentTime, tc.currentTime.Add(actualDur)) + + assert.InDelta(t, tc.expectedDurMin, actualDur.Minutes(), 0.01, + "case: %s, expected duration of around %f minutes, but got duration of %v", tc.name, tc.expectedDurMin, actualDur) + }) + } +} diff --git a/nodemgr/dockerdaemon.sh b/nodemgr/dockerdaemon.sh new file mode 100755 index 00000000..b0790bb6 --- /dev/null +++ b/nodemgr/dockerdaemon.sh @@ -0,0 +1 @@ +@docker run -d --env-file .env.docker --network algokit_sandbox_regular_default reti d diff --git a/nodemgr/go.mod b/nodemgr/go.mod new file mode 100644 index 00000000..dae1024f --- /dev/null +++ b/nodemgr/go.mod @@ -0,0 +1,39 @@ +module github.com/TxnLab/reti + +go 1.21.4 + +require ( + github.com/algorand/go-algorand-sdk/v2 v2.4.0 + github.com/antihax/optional v1.0.0 + github.com/joho/godotenv v1.5.1 + github.com/mailgun/holster/v4 v4.17.0 + github.com/manifoldco/promptui v0.9.0 + github.com/prometheus/client_golang v1.19.0 + github.com/ssgreg/repeat v1.5.1 + github.com/stretchr/testify v1.8.4 + github.com/urfave/cli/v3 v3.0.0-alpha9 + golang.org/x/crypto v0.21.0 + golang.org/x/oauth2 v0.18.0 + golang.org/x/term v0.18.0 +) + +require ( + github.com/algorand/avm-abi v0.2.0 // indirect + github.com/algorand/go-codec/codec v1.1.10 // indirect + github.com/beorn7/perks v1.0.1 // indirect + github.com/cespare/xxhash/v2 v2.2.0 // indirect + github.com/chzyer/readline v1.5.1 // indirect + github.com/davecgh/go-spew v1.1.1 // indirect + github.com/golang/protobuf v1.5.4 // indirect + github.com/google/go-querystring v1.1.0 // indirect + github.com/kr/text v0.2.0 // indirect + github.com/pmezard/go-difflib v1.0.0 // indirect + github.com/prometheus/client_model v0.6.0 // indirect + github.com/prometheus/common v0.50.0 // indirect + github.com/prometheus/procfs v0.13.0 // indirect + github.com/xrash/smetrics v0.0.0-20231213231151-1d8dd44e695e // indirect + golang.org/x/sys v0.18.0 // indirect + google.golang.org/appengine v1.6.8 // indirect + google.golang.org/protobuf v1.33.0 // indirect + gopkg.in/yaml.v3 v3.0.1 // indirect +) diff --git a/nodemgr/go.sum b/nodemgr/go.sum new file mode 100644 index 00000000..20b20053 --- /dev/null +++ b/nodemgr/go.sum @@ -0,0 +1,131 @@ +github.com/ahmetb/go-linq v3.0.0+incompatible h1:qQkjjOXKrKOTy83X8OpRmnKflXKQIL/mC/gMVVDMhOA= +github.com/ahmetb/go-linq v3.0.0+incompatible/go.mod h1:PFffvbdbtw+QTB0WKRP0cNht7vnCfnGlEpak/DVg5cY= +github.com/algorand/avm-abi v0.2.0 h1:bkjsG+BOEcxUcnGSALLosmltE0JZdg+ZisXKx0UDX2k= +github.com/algorand/avm-abi v0.2.0/go.mod h1:+CgwM46dithy850bpTeHh9MC99zpn2Snirb3QTl2O/g= +github.com/algorand/go-algorand-sdk/v2 v2.4.0 h1:R9ykarfk0ojAZlXlrysViDwWjHrvUMA0HmFHg9PmECw= +github.com/algorand/go-algorand-sdk/v2 v2.4.0/go.mod h1:Xk569fTpBTV0QtE74+79NTl6Rz3OC1K3iods4uG0ffU= +github.com/algorand/go-codec/codec v1.1.10 h1:zmWYU1cp64jQVTOG8Tw8wa+k0VfwgXIPbnDfiVa+5QA= +github.com/algorand/go-codec/codec v1.1.10/go.mod h1:YkEx5nmr/zuCeaDYOIhlDg92Lxju8tj2d2NrYqP7g7k= +github.com/antihax/optional v1.0.0 h1:xK2lYat7ZLaVVcIuj82J8kIro4V6kDe0AUDFboUCwcg= +github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY= +github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= +github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= +github.com/cespare/xxhash/v2 v2.2.0 h1:DC2CZ1Ep5Y4k3ZQ899DldepgrayRUGE6BBZ/cd9Cj44= +github.com/cespare/xxhash/v2 v2.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= +github.com/chrismcguire/gobberish v0.0.0-20150821175641-1d8adb509a0e h1:CHPYEbz71w8DqJ7DRIq+MXyCQsdibK08vdcQTY4ufas= +github.com/chrismcguire/gobberish v0.0.0-20150821175641-1d8adb509a0e/go.mod h1:6Xhs0ZlsRjXLIiSMLKafbZxML/j30pg9Z1priLuha5s= +github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= +github.com/chzyer/logex v1.2.1 h1:XHDu3E6q+gdHgsdTPH6ImJMIp436vR6MPtH8gP05QzM= +github.com/chzyer/logex v1.2.1/go.mod h1:JLbx6lG2kDbNRFnfkgvh4eRJRPX1QCoOIWomwysCBrQ= +github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI= +github.com/chzyer/readline v1.5.1 h1:upd/6fQk4src78LMRzh5vItIt361/o4uq553V8B5sGI= +github.com/chzyer/readline v1.5.1/go.mod h1:Eh+b79XXUwfKfcPLepksvw2tcLE/Ct21YObkaSkeBlk= +github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= +github.com/chzyer/test v1.0.0 h1:p3BQDXSxOhOG0P9z6/hGnII4LGiEPOYBhs8asl/fC04= +github.com/chzyer/test v1.0.0/go.mod h1:2JlltgoNkt4TW/z9V/IzDdFaMTM2JPIi26O1pF38GC8= +github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= +github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= +github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek= +github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps= +github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= +github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= +github.com/google/go-querystring v1.1.0 h1:AnCroh3fv4ZBgVIf1Iwtovgjaw/GiKJo8M8yD/fhyJ8= +github.com/google/go-querystring v1.1.0/go.mod h1:Kcdr2DB4koayq7X8pmAG4sNG59So17icRSOU623lUBU= +github.com/joho/godotenv v1.5.1 h1:7eLL/+HRGLY0ldzfGMeQkb7vMd0as4CfYvUVzLqw0N0= +github.com/joho/godotenv v1.5.1/go.mod h1:f4LDr5Voq0i2e/R5DDNOoa2zzDfwtkZa6DnEwAbqwq4= +github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= +github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= +github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= +github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= +github.com/mailgun/holster/v4 v4.17.0 h1:+Zj3bunQFx3QkMWNlaeLolp7kyBteDnaPx7BT5hJidE= +github.com/mailgun/holster/v4 v4.17.0/go.mod h1:UeI3ynFAjOApzf/INq881b9WKM3eRNXp3oPFwJoJBMc= +github.com/manifoldco/promptui v0.9.0 h1:3V4HzJk1TtXW1MTZMP7mdlwbBpIinw3HztaIlYthEiA= +github.com/manifoldco/promptui v0.9.0/go.mod h1:ka04sppxSGFAtxX0qhlYQjISsg9mR4GWtQEhdbn6Pgg= +github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= +github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/prometheus/client_golang v1.19.0 h1:ygXvpU1AoN1MhdzckN+PyD9QJOSD4x7kmXYlnfbA6JU= +github.com/prometheus/client_golang v1.19.0/go.mod h1:ZRM9uEAypZakd+q/x7+gmsvXdURP+DABIEIjnmDdp+k= +github.com/prometheus/client_model v0.6.0 h1:k1v3CzpSRUTrKMppY35TLwPvxHqBu0bYgxZzqGIgaos= +github.com/prometheus/client_model v0.6.0/go.mod h1:NTQHnmxFpouOD0DpvP4XujX3CdOAGQPoaGhyTchlyt8= +github.com/prometheus/common v0.50.0 h1:YSZE6aa9+luNa2da6/Tik0q0A5AbR+U003TItK57CPQ= +github.com/prometheus/common v0.50.0/go.mod h1:wHFBCEVWVmHMUpg7pYcOm2QUR/ocQdYSJVQJKnHc3xQ= +github.com/prometheus/procfs v0.13.0 h1:GqzLlQyfsPbaEHaQkO7tbDlriv/4o5Hudv6OXHGKX7o= +github.com/prometheus/procfs v0.13.0/go.mod h1:cd4PFCR54QLnGKPaKGA6l+cfuNXtht43ZKY6tow0Y1g= +github.com/rogpeppe/go-internal v1.10.0 h1:TMyTOH3F/DB16zRVcYyreMH6GnZZrwQVAoYjRBZyWFQ= +github.com/rogpeppe/go-internal v1.10.0/go.mod h1:UQnix2H7Ngw/k4C5ijL5+65zddjncjaFoBhdsK/akog= +github.com/sirupsen/logrus v1.9.2 h1:oxx1eChJGI6Uks2ZC4W1zpLlVgqB8ner4EuQwV4Ik1Y= +github.com/sirupsen/logrus v1.9.2/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= +github.com/ssgreg/repeat v1.5.1 h1:8OjfXKWnFU9cL1cI+2UCdPpOpGOEax1oZ1FQdylri+8= +github.com/ssgreg/repeat v1.5.1/go.mod h1:V1zMJmma0AQitsevwH3wM/uFcIw6VxW0dHBJBhajl/o= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= +github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= +github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= +github.com/urfave/cli/v3 v3.0.0-alpha9 h1:P0RMy5fQm1AslQS+XCmy9UknDXctOmG/q/FZkUFnJSo= +github.com/urfave/cli/v3 v3.0.0-alpha9/go.mod h1:0kK/RUFHyh+yIKSfWxwheGndfnrvYSmYFVeKCh03ZUc= +github.com/xrash/smetrics v0.0.0-20231213231151-1d8dd44e695e h1:+SOyEddqYF09QP7vr7CgJ1eti3pY9Fn3LHO1M1r/0sI= +github.com/xrash/smetrics v0.0.0-20231213231151-1d8dd44e695e/go.mod h1:N3UwUGtsrSj3ccvlPHLoLsHnpR27oXr4ZE984MbSER8= +github.com/yuin/goldmark v1.4.1/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= +github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= +golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= +golang.org/x/crypto v0.21.0 h1:X31++rzVUdKhX5sWmSOFZxx8UW/ldWx55cbf08iNAMA= +golang.org/x/crypto v0.21.0/go.mod h1:0BP7YvVV9gBbVKyeTG0Gyn+gZm94bibOW5BjDEYAOMs= +golang.org/x/mod v0.6.0-dev.0.20220106191415-9b9b3d81d5e3/go.mod h1:3p9vT2HGsQu2K1YbXdKPJLVgG5VJdoTa1poYQBtP1AY= +golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= +golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= +golang.org/x/net v0.0.0-20211015210444-4f30a5c0130f/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= +golang.org/x/oauth2 v0.18.0 h1:09qnuIAgzdx1XplqJvW6CQqMCtGZykZWcXzPMPUusvI= +golang.org/x/oauth2 v0.18.0/go.mod h1:Wf7knwG0MPoWIMMBgFlEaSUDaKskp0dCfrlJRJXbBi8= +golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sys v0.0.0-20181122145206-62eef0e2fa9b/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20211019181941-9d821ace8654/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220310020820-b874c991c1a5/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.18.0 h1:DBdB3niSjOA/O0blCZBqDefyWNYveAYMNF1Wum0DYQ4= +golang.org/x/sys v0.18.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= +golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= +golang.org/x/term v0.18.0 h1:FcHjZXDMxI8mM3nwhX9HlKop4C0YQvCVCdwYl2wOtE8= +golang.org/x/term v0.18.0/go.mod h1:ILwASektA3OnRv7amZ1xhE/KTR+u50pbXfZ03+6Nx58= +golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= +golang.org/x/text v0.3.8/go.mod h1:E6s5w1FMmriuDzIBO73fBruAKo1PCIq6d2Q6DHfQ8WQ= +golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.1.10/go.mod h1:Uh6Zz+xoGYZom868N8YTex3t7RhtHDBrE8Gzo9bV56E= +golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= +golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +google.golang.org/appengine v1.6.8 h1:IhEN5q69dyKagZPYMSdIjS2HqprW324FRQZJcGqPAsM= +google.golang.org/appengine v1.6.8/go.mod h1:1jJ3jBArFh5pcgW8gCtRJnepW8FzD1V44FJffLiz/Ds= +google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= +google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= +google.golang.org/protobuf v1.33.0 h1:uNO2rsAINq/JlFpSdYEKIZ0uKD/R9cpdv0T+yoGwGmI= +google.golang.org/protobuf v1.33.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= +gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= +gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= +gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/nodemgr/internal/lib/algo/algo.go b/nodemgr/internal/lib/algo/algo.go new file mode 100644 index 00000000..5a3215d0 --- /dev/null +++ b/nodemgr/internal/lib/algo/algo.go @@ -0,0 +1,169 @@ +package algo + +import ( + "context" + "encoding/base64" + "fmt" + "log/slog" + "net/http" + "net/url" + "path/filepath" + "strings" + "time" + + "github.com/algorand/go-algorand-sdk/v2/client/v2/algod" + "github.com/algorand/go-algorand-sdk/v2/client/v2/common" + "github.com/algorand/go-algorand-sdk/v2/client/v2/common/models" + "github.com/algorand/go-algorand-sdk/v2/types" + "github.com/ssgreg/repeat" + + "github.com/TxnLab/reti/internal/lib/misc" +) + +// DefaultValidRoundRange - max valid round range to have transactions be valid for (and to check for confirmation) +const DefaultValidRoundRange = 100 + +func FormattedAlgoAmount(microAlgos uint64) string { + formattedAmount := fmt.Sprintf("%.6f", float64(microAlgos)/1000000) + // chop trailing 0's and decimal (if nothing else) + formattedAmount = strings.TrimRight(formattedAmount, "0") + formattedAmount = strings.TrimRight(formattedAmount, ".") + return formattedAmount +} + +func GetAlgoClient(log *slog.Logger, config NetworkConfig) (*algod.Client, error) { + var ( + apiURL string + apiToken string + apiHeaders []*common.Header + serverAddr *url.URL + err error + ) + if config.NodeDataDir != "" { + // Read address and admin token from main-net directory + apiURL, apiToken, err = GetNetAndTokenFromFiles( + filepath.Join(config.NodeDataDir, "algod.net"), + filepath.Join(config.NodeDataDir, "algod.admin.token")) + if err != nil { + return nil, fmt.Errorf("error reading config: %w", err) + } + } else { + apiURL = config.NodeURL + apiToken = config.NodeToken + // Convert config.NodeHeaders map into []*common.Header slice + for key, value := range config.NodeHeaders { + apiHeaders = append(apiHeaders, &common.Header{ + Key: key, + Value: value, + }) + } + // Strip off trailing slash if present in url which the Algorand client doesn't handle properly + apiURL = strings.TrimRight(apiURL, "/") + } + serverAddr, err = url.Parse(apiURL) + if err != nil { + return nil, fmt.Errorf("failed to parse url:%v, error:%w", apiURL, err) + } + if serverAddr.Scheme == "tcp" { + serverAddr.Scheme = "http" + } + misc.Infof(log, "Connecting to Algorand node at:%s", serverAddr.String()) + + // Override the default transport so we can properly support multiple parallel connections to same + // host (and allow connection resuse) + customTransport := http.DefaultTransport.(*http.Transport).Clone() + customTransport.MaxIdleConns = 100 + customTransport.MaxConnsPerHost = 100 + customTransport.MaxIdleConnsPerHost = 100 + client, err := algod.MakeClientWithTransport(serverAddr.String(), apiToken, apiHeaders, customTransport) + if err != nil { + return nil, fmt.Errorf(`failed to make algod client (url:%s), error:%w`, serverAddr.String(), err) + } + // Immediately hit server to verify connectivity + _, err = client.SuggestedParams().Do(context.Background()) + if err != nil { + return nil, fmt.Errorf("failed to get suggested params from algod client, error:%w", err) + } + return client, nil +} + +func SuggestedParams(ctx context.Context, logger *slog.Logger, client *algod.Client) types.SuggestedParams { + var ( + txParams types.SuggestedParams + err error + ) + // don't accept no for an answer from this api ! just keep trying + err = repeat.Repeat( + repeat.Fn(func() error { + txParams, err = client.SuggestedParams().Do(ctx) + if err != nil { + return repeat.HintTemporary(err) + } + return nil + }), + repeat.StopOnSuccess(), + repeat.FnOnError(func(err error) error { + misc.Infof(logger, "retrying suggestedparams call, error:%s", err.Error()) + return err + }), + repeat.WithDelay(repeat.ExponentialBackoff(1*time.Second).Set()), + ) + + // move FirstRoundValid back 1 just to cover for different nodes maybe being 'slightly' behind - so we + // don't create a transaction starting at round 100 but the node we submit to is only at round 99 + txParams.FirstRoundValid-- + txParams.LastRoundValid = txParams.FirstRoundValid + DefaultValidRoundRange + // Just set fixed fee for now - we don't want to send during high cost periods anyway. + txParams.FlatFee = true + txParams.Fee = types.MicroAlgos(txParams.MinFee) + return txParams +} + +type AccountWithMinBalance struct { + models.Account + MinBalance uint64 `json:"min-balance,omitempty"` +} + +func GetIntFromGlobalState(globalState []models.TealKeyValue, keyName string) (uint64, error) { + for _, gs := range globalState { + rawKey, _ := base64.StdEncoding.DecodeString(gs.Key) + if string(rawKey) == keyName && gs.Value.Type == 2 { + return gs.Value.Uint, nil + } + } + return 0, ErrStateKeyNotFound +} + +func GetStringFromGlobalState(globalState []models.TealKeyValue, keyName string) (string, error) { + for _, gs := range globalState { + rawKey, _ := base64.StdEncoding.DecodeString(gs.Key) + if string(rawKey) == keyName && gs.Value.Type == 1 { + value, _ := base64.StdEncoding.DecodeString(gs.Value.Bytes) + return string(value), nil + } + } + return "", ErrStateKeyNotFound +} + +// GetBareAccount just returns account information without asset data, but also includes the minimum balance that's +// missing from the SDKs. +func GetBareAccount(ctx context.Context, algoClient *algod.Client, account string) (AccountWithMinBalance, error) { + var response AccountWithMinBalance + var params = algod.AccountInformationParams{ + Exclude: "all", + } + + err := (*common.Client)(algoClient).Get(ctx, &response, fmt.Sprintf("/v2/accounts/%s", account), params, nil) + if err != nil { + return AccountWithMinBalance{}, err + } + return response, nil +} + +func GetVersionString(ctx context.Context, algoClient *algod.Client) (string, error) { + vers, err := algoClient.Versions().Do(ctx) + if err != nil { + return "", fmt.Errorf("error fetching /versions from algod: %w", err) + } + return fmt.Sprintf("%d.%d.%d %s [%s]", vers.Build.Major, vers.Build.Minor, vers.Build.BuildNumber, vers.Build.Branch, vers.Build.CommitHash), nil +} diff --git a/nodemgr/internal/lib/algo/algolocalkeysigning.go b/nodemgr/internal/lib/algo/algolocalkeysigning.go new file mode 100644 index 00000000..d82a4137 --- /dev/null +++ b/nodemgr/internal/lib/algo/algolocalkeysigning.go @@ -0,0 +1,103 @@ +package algo + +import ( + "context" + "fmt" + "log/slog" + "os" + "strings" + + "golang.org/x/crypto/ed25519" + + "github.com/algorand/go-algorand-sdk/v2/crypto" + "github.com/algorand/go-algorand-sdk/v2/mnemonic" + "github.com/algorand/go-algorand-sdk/v2/types" + + "github.com/TxnLab/reti/internal/lib/misc" +) + +func NewLocalKeyStore(log *slog.Logger) MultipleWalletSigner { + keyStore := &localKeyStore{ + log: log, + keys: map[string]ed25519.PrivateKey{}, + } + keyStore.loadFromEnvironment() + return keyStore +} + +type localKeyStore struct { + log *slog.Logger + + keys map[string]ed25519.PrivateKey +} + +func (lk *localKeyStore) HasAccount(publicAddress string) bool { + _, found := lk.keys[publicAddress] + return found +} + +// FindFirstSigner finds the first signer among the given addresses. +// If addresses slice is empty, it returns the first signer from the localKeyStore's keys map. +// Otherwise, it checks each address in the addresses slice against the localKeyStore's keys map. +// If a signer is found, it returns the signer's address. +// If no signer is found for any of the addresses, it returns an error. +func (lk *localKeyStore) FindFirstSigner(addresses []string) (string, error) { + if len(addresses) == 0 { + // just grab first + for addr, _ := range lk.keys { + return addr, nil + } + } + for _, address := range addresses { + if lk.HasAccount(address) { + return address, nil + } + } + return "", fmt.Errorf("no signer found for any of the addresses") +} + +func (lk *localKeyStore) SignWithAccount(ctx context.Context, tx types.Transaction, publicAddress string) (string, []byte, error) { + key, found := lk.keys[publicAddress] + if !found { + return "", nil, fmt.Errorf("key not found for address %s", publicAddress) + } + return crypto.SignTransaction(key, tx) +} + +// loadFromEnvironment loads mnemonics from environment variables (can be in .env files as well) containing "xxxxxx_MNEMONIC=(mnemonic string)" +// and adds them to the localKeyStore's keys map. The number of loaded mnemonics is logged as well as the pks of each. +// If an error occurs while adding a mnemonic, a fatal error is logged and the application exits. +func (lk *localKeyStore) loadFromEnvironment() { + var numMnemonics int + for _, envVal := range os.Environ() { + if !strings.Contains(envVal, "_MNEMONIC") { + continue + } + key := envVal[0:strings.IndexByte(envVal, '=')] + envMnemonic := os.Getenv(key) + // Skip empty keys - ie: blank demonstration env examples + if envMnemonic == "" { + break + } + if err := lk.addMnemonic(envMnemonic); err != nil { + lk.log.Error(fmt.Sprintf("fatal error in envMnemonic load, idx key:%s, err:%v", key, err)) + os.Exit(1) + } + numMnemonics++ + } + misc.Debugf(lk.log, "loaded %d mnemonics", numMnemonics) +} + +func (lk *localKeyStore) addMnemonic(mnemonicPhrase string) error { + key, err := mnemonic.ToPrivateKey(mnemonicPhrase) + if err != nil { + return fmt.Errorf("failed to add mnemonic: %w", err) + } + account, err := crypto.AccountFromPrivateKey(key) + if err != nil { + return fmt.Errorf("failed to add mnemonic: %w", err) + } + lk.keys[account.Address.String()] = key + misc.Infof(lk.log, "Mnemonics available for account:%s", account.Address.String()) + return nil +} diff --git a/nodemgr/internal/lib/algo/algosigning.go b/nodemgr/internal/lib/algo/algosigning.go new file mode 100644 index 00000000..caf3431a --- /dev/null +++ b/nodemgr/internal/lib/algo/algosigning.go @@ -0,0 +1,187 @@ +package algo + +import ( + "context" + "encoding/base64" + "encoding/json" + "fmt" + "log/slog" + + "golang.org/x/crypto/ed25519" + + "github.com/algorand/go-algorand-sdk/v2/crypto" + "github.com/algorand/go-algorand-sdk/v2/encoding/msgpack" + "github.com/algorand/go-algorand-sdk/v2/transaction" + "github.com/algorand/go-algorand-sdk/v2/types" + + "github.com/TxnLab/reti/internal/lib/misc" +) + +type TxnSigner interface { + // SignTxn signs the specified transaction, returning Transaction id, signed transaction bytes, and error + SignTxn(ctx context.Context, tx types.Transaction) (string, []byte, error) +} + +type MultipleWalletSigner interface { + HasAccount(publicAddress string) bool + FindFirstSigner(addresses []string) (string, error) + SignWithAccount(ctx context.Context, tx types.Transaction, publicAddress string) (string, []byte, error) +} + +// SignGroupTransactions takes the slice of Transactions and of TxnSigner implementations and signs each according to the +// matching TxnSigner implementation for each transaction. +func SignGroupTransactions(ctx context.Context, txns []types.Transaction, signers []TxnSigner) ([]byte, []string, error) { + var ( + txIDs []string + gid types.Digest + err error + ) + if len(txns) != len(signers) { + return nil, nil, fmt.Errorf("number of transactions (%d) does not match number of signers (%d)", len(txns), len(signers)) + } + // now we have to compose the group transactions [if more than 1 transaction] + if len(txns) > 1 { + gid, err = crypto.ComputeGroupID(txns) + if err != nil { + return nil, nil, fmt.Errorf("failed to compute group id: %w", err) + } + } + var signedTxns []byte + for i, txn := range txns { + if len(txns) > 1 { + txn.Group = gid + } + + txid, bytes, err := signers[i].SignTxn(ctx, txn) + if err != nil { + return nil, nil, fmt.Errorf("error signing txn %d: %w", i, err) // TOOD - get better txn printer + } + signedTxns = append(signedTxns, bytes...) + txIDs = append(txIDs, txid) + } + return signedTxns, txIDs, nil +} + +// SignGroupTransactionsForFrontend takes the slice of Transactions and of TxnSigner implementations and signs each according to the +// matching TxnSigner implementation for each transaction - returning as a json array of base64 encoded strings +func SignGroupTransactionsForFrontend(ctx context.Context, log *slog.Logger, txns []types.Transaction, signers []TxnSigner) ([]byte, error) { + var ( + txIDs []string + gid types.Digest + err error + jsonResp [][]string + ) + + if len(txns) == 0 { + // Return 'empty' json array - nothing to sign... + return []byte("[]"), nil + } + // now we have to compose the group transactions [if more than 1 transaction] + if len(txns) > 1 { + gid, err = crypto.ComputeGroupID(txns) + if err != nil { + return nil, fmt.Errorf("failed to compute group id: %w", err) + } + } + for i, txn := range txns { + if len(txns) > 1 { + txn.Group = gid + } + txID, bytes, err := signers[i].SignTxn(ctx, txn) + if err != nil { + return nil, fmt.Errorf("error signing txn %d: %w", i, err) // TOOD - get better txn printer + } + var signType = "s" + if _, isUnsigned := signers[i].(*noSigner); isUnsigned { + signType = "u" + } + txnTuple := []string{signType, base64.StdEncoding.EncodeToString(bytes)} + jsonResp = append(jsonResp, txnTuple) + txIDs = append(txIDs, txID) + } + misc.Infof(log, "SignGroupTransactionsForFrontend: txids:%#v", txIDs) + + return json.Marshal(jsonResp) +} + +func SignByUser(signers []TxnSigner) []TxnSigner { + return append(signers, &noSigner{}) +} + +func SignWithKey(signers []TxnSigner, privateKey ed25519.PrivateKey) []TxnSigner { + return append(signers, &skSigner{ + sk: privateKey, + }) +} + +func SignWithAccountForATC(keyManager MultipleWalletSigner, publicAddress string) transaction.TransactionSigner { + return &kmdSigner{ + keyManager: keyManager, + address: publicAddress, + } +} + +func SignWithAccount(signers []TxnSigner, keyManager MultipleWalletSigner, publicAddress string) []TxnSigner { + return append(signers, &kmdSigner{ + keyManager: keyManager, + address: publicAddress, + }) +} + +func SignWithLogicSig(signers []TxnSigner, logicSigAccount crypto.LogicSigAccount) []TxnSigner { + return append(signers, &logicSigSigner{ + logicSigAccount: logicSigAccount, + }) +} + +type noSigner struct{} + +func (n *noSigner) SignTxn(ctx context.Context, tx types.Transaction) (string, []byte, error) { + return crypto.GetTxID(tx), msgpack.Encode(tx), nil +} + +type skSigner struct { + sk ed25519.PrivateKey +} + +func (s *skSigner) SignTxn(ctx context.Context, tx types.Transaction) (string, []byte, error) { + return crypto.SignTransaction(s.sk, tx) +} + +type kmdSigner struct { + keyManager MultipleWalletSigner + address string +} + +func (k *kmdSigner) SignTxn(ctx context.Context, tx types.Transaction) (string, []byte, error) { + return k.keyManager.SignWithAccount(ctx, tx, k.address) +} + +func (k *kmdSigner) SignTransactions(txGroup []types.Transaction, indexesToSign []int) ([][]byte, error) { + stxs := make([][]byte, len(indexesToSign)) + for i, pos := range indexesToSign { + _, stxBytes, err := k.keyManager.SignWithAccount(context.Background(), txGroup[pos], k.address) + if err != nil { + return nil, err + } + + stxs[i] = stxBytes + } + + return stxs, nil +} + +func (k *kmdSigner) Equals(other transaction.TransactionSigner) bool { + if castedSigner, ok := other.(*kmdSigner); ok { + return castedSigner.address == k.address + } + return false +} + +type logicSigSigner struct { + logicSigAccount crypto.LogicSigAccount +} + +func (l *logicSigSigner) SignTxn(_ context.Context, tx types.Transaction) (string, []byte, error) { + return crypto.SignLogicSigAccountTransaction(l.logicSigAccount, tx) +} diff --git a/nodemgr/internal/lib/algo/errors.go b/nodemgr/internal/lib/algo/errors.go new file mode 100644 index 00000000..ea02bf56 --- /dev/null +++ b/nodemgr/internal/lib/algo/errors.go @@ -0,0 +1,7 @@ +package algo + +import "errors" + +var ( + ErrStateKeyNotFound = errors.New("key in global state not found") +) diff --git a/nodemgr/internal/lib/algo/keys.go b/nodemgr/internal/lib/algo/keys.go new file mode 100644 index 00000000..eccf8ba4 --- /dev/null +++ b/nodemgr/internal/lib/algo/keys.go @@ -0,0 +1,112 @@ +package algo + +import ( + "context" + "fmt" + "log/slog" + "time" + + "github.com/algorand/go-algorand-sdk/v2/client/v2/algod" + "github.com/algorand/go-algorand-sdk/v2/client/v2/common" + + "github.com/TxnLab/reti/internal/lib/misc" +) + +type ParticipationKey struct { + Address string `json:"address"` + EffectiveFirstValid uint64 `json:"effective-first-valid"` + EffectiveLastValid uint64 `json:"effective-last-valid"` + Id string `json:"id"` + Key struct { + SelectionParticipationKey []byte `json:"selection-participation-key"` + StateProofKey []byte `json:"state-proof-key"` + VoteFirstValid uint64 `json:"vote-first-valid"` + VoteKeyDilution uint64 `json:"vote-key-dilution"` + VoteLastValid uint64 `json:"vote-last-valid"` + VoteParticipationKey []byte `json:"vote-participation-key"` + } `json:"key"` + LastBlockProposal uint64 `json:"last-block-proposal"` + LastVote uint64 `json:"last-vote"` +} + +type PartKeysByAddress map[string][]ParticipationKey + +func GetParticipationKeys(ctx context.Context, algoClient *algod.Client) (PartKeysByAddress, error) { + var response []ParticipationKey + + err := (*common.Client)(algoClient).Get(ctx, &response, fmt.Sprintf("/v2/participation"), nil, nil) + if err != nil { + return nil, fmt.Errorf("unable to get participation keys") + } + // collate and return the ParticipationKey slice into a map by 'Address' within the ParticipationKey + participationKeys := PartKeysByAddress{} + for _, key := range response { + participationKeys[key.Address] = append(participationKeys[key.Address], key) + } + return participationKeys, nil +} + +type GenerateParticipationKeysParams struct { + // Dilution Key dilution for two-level participation keys (defaults to sqrt of validity window). + //Dilution *uint64 `form:"dilution,omitempty" json:"dilution,omitempty"` + + // First First round for participation key. + First uint64 `form:"first" url:"first" json:"first"` + + // Last Last round for participation key. + Last uint64 `form:"last" url:"last" json:"last"` +} + +// GenerateParticipationKey generates a participation key for an account within a specific validity window. +// It sends a POST request to the Algorand node API to generate the participation key. +// After the request is sent, it polls the node every 10 seconds to check if the key has been generated. +// If the key is successfully generated, it returns the participation key. +// If the key is not generated within 30 minutes, it returns an error. +func GenerateParticipationKey(ctx context.Context, algoClient *algod.Client, logger *slog.Logger, account string, firstValid, lastValid uint64) (*ParticipationKey, error) { + var response struct{} + var params = GenerateParticipationKeysParams{ + First: firstValid, + Last: lastValid, + } + + misc.Infof(logger, "generating part key for account:%s, first/last valid of %d - %d", account, firstValid, lastValid) + err := (*common.Client)(algoClient).Post(ctx, &response, fmt.Sprintf("/v2/participation/generate/%s", account), params, nil, nil) + if err != nil { + return nil, fmt.Errorf("error generating participation key for account:%s, err:%w", account, err) + } + // now we poll, waiting for the key to be generated + for { + select { + case <-ctx.Done(): + return nil, context.Canceled + case <-time.After(10 * time.Second): + // poll every 10 seconds checking to see if key has been generated + partKeys, err := GetParticipationKeys(ctx, algoClient) + if err != nil { + return nil, fmt.Errorf("unable to get part keys as part of polling after key generation request, err:%w", err) + } + for _, keys := range partKeys { + for _, key := range keys { + if key.Address == account && key.Key.VoteFirstValid == firstValid { + // this is our key - we're good, it's been successfully created ! + misc.Infof(logger, "Participation key generated for account:%s, first valid:%d", account, firstValid) + return &key, nil + } + } + } + case <-time.After(30 * time.Minute): + misc.Errorf(logger, "something went wrong - 30 minutes and no key was generated for:%s - aborting", account) + return nil, fmt.Errorf("something went wrong - 30 minutes and no key was generated for:%s - aborting", account) + } + } +} + +func DeleteParticipationKey(ctx context.Context, algoClient *algod.Client, logger *slog.Logger, partKeyID string) error { + var response string + misc.Infof(logger, "delete part key id:%s", partKeyID) + err := (*common.Client)(algoClient).Delete(ctx, &response, fmt.Sprintf("/v2/participation/%s", partKeyID), nil, nil) + if err != nil { + return fmt.Errorf("error delete participation key for id:%s, err:%w", partKeyID, err) + } + return nil +} diff --git a/nodemgr/internal/lib/algo/networks.go b/nodemgr/internal/lib/algo/networks.go new file mode 100644 index 00000000..042e48f0 --- /dev/null +++ b/nodemgr/internal/lib/algo/networks.go @@ -0,0 +1,111 @@ +package algo + +import ( + "fmt" + "os" + "strconv" + "strings" + + "github.com/TxnLab/reti/internal/lib/misc" +) + +type NetworkConfig struct { + NodeDataDir string + + NFDAPIUrl string + + NodeURL string + NodeToken string + NodeHeaders map[string]string + + RetiAppID uint64 +} + +func GetNetworkConfig(network string) NetworkConfig { + cfg := getDefaults(network) + + nodeDataDir := os.Getenv("ALGORAND_DATA") + if nodeDataDir != "" { + cfg.NodeDataDir = nodeDataDir + } + + nfdAPIUrl := os.Getenv("ALGO_NFD_URL") + if nfdAPIUrl != "" { + cfg.NFDAPIUrl = nfdAPIUrl + } + + if appIDEnv := os.Getenv("RETI_APPID"); appIDEnv != "" { + cfg.RetiAppID, _ = strconv.ParseUint(appIDEnv, 10, 64) + } + + nodeURL := misc.GetSecret("ALGO_ALGOD_URL") + if nodeURL != "" { + cfg.NodeURL = nodeURL + } + + nodeToken := misc.GetSecret("ALGO_ALGOD_TOKEN") + if nodeToken != "" { + cfg.NodeToken = nodeToken + } + NodeHeaders := misc.GetSecret("ALGO_ALGOD_HEADERS") + // parse NodeHeaders from key:value,[key:value...] pairs and put into cfg.NodeHeaders map + cfg.NodeHeaders = map[string]string{} + for _, header := range strings.Split(NodeHeaders, ",") { + parts := strings.SplitN(header, ":", 2) // Just split on first : - they can have :'s in value. + if len(parts) == 2 { + key := strings.TrimSpace(parts[0]) + value := strings.TrimSpace(parts[1]) + cfg.NodeHeaders[key] = value + } + } + + return cfg +} + +func getDefaults(network string) NetworkConfig { + cfg := NetworkConfig{} + switch network { + case "mainnet": + cfg.RetiAppID = 0 // TODO + cfg.NFDAPIUrl = "https://api.nf.domains" + cfg.NodeURL = "https://mainnet-api.algonode.cloud" + case "testnet": + cfg.RetiAppID = 629427552 + cfg.NFDAPIUrl = "https://api.testnet.nf.domains" + cfg.NodeURL = "https://testnet-api.algonode.cloud" + case "betanet": + cfg.RetiAppID = 2019345668 + cfg.NFDAPIUrl = "https://api.betanet.nf.domains" + cfg.NodeURL = "https://betanet-api.algonode.cloud" + case "sandbox": + cfg.RetiAppID = 0 // should come from .env.sandbox !! + cfg.NFDAPIUrl = "https://api.testnet.nf.domains" + cfg.NodeURL = "http://localhost:4001" + cfg.NodeToken = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" + //----- + // VOI + //----- + case "voitestnet": + cfg.NFDAPIUrl = "https://api.nf.domains" + cfg.NodeURL = "https://testnet-api.voi.nodely.io" + } + return cfg +} + +// GetNetAndTokenFromFiles reads the address and token from files in the local Algorand data directory. +// It takes two parameters: netFile (file path of the address file) and tokenFile (file path of the token file). +// It returns apiURL (the API URL), apiToken (the API token), and an error (if any). +func GetNetAndTokenFromFiles(netFile, tokenFile string) (string, string, error) { + // Read address and token from (local) algorand data directory + netPath, err := os.ReadFile(netFile) + if err != nil { + return "", "", fmt.Errorf("error reading file: %s: %w", netFile, err) + } + apiKeyBytes, err := os.ReadFile(tokenFile) + if err != nil { + return "", "", fmt.Errorf("error reading file: %s: %w", tokenFile, err) + } + apiURL := fmt.Sprintf("http://%s", strings.TrimSpace(string(netPath))) + apiToken := strings.TrimSpace(string(apiKeyBytes)) + return apiURL, apiToken, nil +} diff --git a/nodemgr/internal/lib/algo/signing.go b/nodemgr/internal/lib/algo/signing.go new file mode 100644 index 00000000..09626f89 --- /dev/null +++ b/nodemgr/internal/lib/algo/signing.go @@ -0,0 +1,85 @@ +package algo + +import ( + "bytes" + "context" + "encoding/base64" + "encoding/json" + "fmt" + "log" + "log/slog" + + "github.com/algorand/go-algorand-sdk/v2/client/v2/algod" + "github.com/algorand/go-algorand-sdk/v2/client/v2/common/models" + "github.com/algorand/go-algorand-sdk/v2/encoding/msgpack" + "github.com/algorand/go-algorand-sdk/v2/transaction" + "github.com/algorand/go-algorand-sdk/v2/types" +) + +// DecodeAndSignNFDTransactions decodes and signs transactions that came from an NFD API for user signing, signing each +// transaction which needs signed using the given signer +func DecodeAndSignNFDTransactions(nfdnTxnResponse string, signer MultipleWalletSigner) (string, []byte, error) { + type TxnPair [2]string + var ( + txns []TxnPair + err error + resp []byte + firstTxnId string + ) + + // First trim/unquote the string. + err = json.Unmarshal([]byte(nfdnTxnResponse), &txns) + if err != nil { + return "", nil, err + } + for i, txn := range txns { + rawBytes, err := base64.StdEncoding.DecodeString(txn[1]) + if err != nil { + log.Fatal("Error decoding txn:", i, " error:", err) + } + txnId, bytes, err := decodeAndSignTransaction(signer, txn[0], rawBytes) + if err != nil { + return "", nil, err + } + resp = append(resp, bytes...) + if i == 0 { + firstTxnId = txnId + } + } + return firstTxnId, resp, nil +} + +func decodeAndSignTransaction(signer MultipleWalletSigner, txnType string, msgPackBytes []byte) (string, []byte, error) { + var ( + uTxn types.Transaction + ) + + if txnType == "s" { + // Already a signed txn + return "", msgPackBytes, nil + } + dec := msgpack.NewDecoder(bytes.NewReader(msgPackBytes)) + err := dec.Decode(&uTxn) + if err != nil { + return "", nil, fmt.Errorf("error in unmarshalling, error: %w", err) + } + txnid, bytes, err := signer.SignWithAccount(context.Background(), uTxn, uTxn.Sender.String()) + if err != nil { + return "", nil, fmt.Errorf("error signing txn for sender:%s, error: %w", uTxn.Sender.String(), err) + } + return txnid, bytes, nil +} + +func sendAndWaitTxns(ctx context.Context, log *slog.Logger, algoClient *algod.Client, txnBytes []byte) (models.PendingTransactionInfoResponse, error) { + txid, err := algoClient.SendRawTransaction(txnBytes).Do(ctx) + if err != nil { + return models.PendingTransactionInfoResponse{}, fmt.Errorf("sendAndWaitTxns failed to send txns: %w", err) + } + log.Info("sendAndWaitTxns", "txid", txid) + resp, err := transaction.WaitForConfirmation(algoClient, txid, 100, ctx) + if err != nil { + return models.PendingTransactionInfoResponse{}, fmt.Errorf("sendAndWaitTxns failure in confirmation wait: %w", err) + } + log.Info("sendAndWaitTxns", "confirmed-round", resp.ConfirmedRound) + return resp, nil +} diff --git a/nodemgr/internal/lib/misc/env.go b/nodemgr/internal/lib/misc/env.go new file mode 100644 index 00000000..7b74d627 --- /dev/null +++ b/nodemgr/internal/lib/misc/env.go @@ -0,0 +1,14 @@ +package misc + +import ( + "github.com/joho/godotenv" +) + +func LoadEnvSettings() { + godotenv.Load(".env.local") + godotenv.Load() // .env +} + +func LoadEnvForNetwork(network string) { + godotenv.Load(".env." + network) +} diff --git a/nodemgr/internal/lib/misc/logging.go b/nodemgr/internal/lib/misc/logging.go new file mode 100644 index 00000000..9b368057 --- /dev/null +++ b/nodemgr/internal/lib/misc/logging.go @@ -0,0 +1,94 @@ +package misc + +import ( + "context" + "encoding/json" + "fmt" + "io" + "log" + "log/slog" + "runtime" + "time" +) + +func Errorf(logger *slog.Logger, format string, args ...any) { + helperf(logger, slog.LevelError, format, args...) +} + +func Warnf(logger *slog.Logger, format string, args ...any) { + helperf(logger, slog.LevelWarn, format, args...) +} + +func Infof(logger *slog.Logger, format string, args ...any) { + helperf(logger, slog.LevelInfo, format, args...) +} + +func Debugf(logger *slog.Logger, format string, args ...any) { + helperf(logger, slog.LevelDebug, format, args...) +} + +func helperf(logger *slog.Logger, level slog.Level, format string, args ...any) { + if !logger.Enabled(context.Background(), level) { + return + } + var pcs [1]uintptr + runtime.Callers(3, pcs[:]) // skip [Callers, helperf, [info/warn/debug]f] + r := slog.NewRecord(time.Now(), level, fmt.Sprintf(format, args...), pcs[0]) + _ = logger.Handler().Handle(context.Background(), r) +} + +type MinimalHandlerOptions struct { + SlogOpts slog.HandlerOptions +} + +type MinimalHandler struct { + handler slog.Handler + l *log.Logger +} + +func (h *MinimalHandler) Enabled(ctx context.Context, level slog.Level) bool { + return h.handler.Enabled(ctx, level) +} + +func (h *MinimalHandler) WithGroup(name string) slog.Handler { + return &MinimalHandler{l: h.l, handler: h.handler.WithGroup(name)} +} + +func (h *MinimalHandler) WithAttrs(attrs []slog.Attr) slog.Handler { + return &MinimalHandler{l: h.l, handler: h.handler.WithAttrs(attrs)} //return NewMinimalHandler(h.level, h.handler.WithAttrs(attrs)) +} + +func (h *MinimalHandler) Handle(ctx context.Context, r slog.Record) error { + var ( + extra string + ) + if r.NumAttrs() > 0 { + fields := make(map[string]any, r.NumAttrs()) + r.Attrs(func(a slog.Attr) bool { + fields[a.Key] = fmt.Sprintf("%v", a.Value.Any()) + + return true + }) + + //extra = fmt.Sprintf("%s", fields) + b, err := json.Marshal(fields) + if err != nil { + return err + } + extra = string(b) + } + + h.l.Println(r.Message, string(extra)) + + return nil +} + +func NewMinimalHandler(out io.Writer, opts MinimalHandlerOptions) *MinimalHandler { + h := &MinimalHandler{ + //handler: slog.NewTextHandler(out, &opts.SlogOpts), + handler: slog.NewJSONHandler(out, &opts.SlogOpts), + l: log.New(out, "", 0), + } + + return h +} diff --git a/nodemgr/internal/lib/misc/secrets.go b/nodemgr/internal/lib/misc/secrets.go new file mode 100644 index 00000000..81d0eb0a --- /dev/null +++ b/nodemgr/internal/lib/misc/secrets.go @@ -0,0 +1,31 @@ +package misc + +import ( + "os" + "strings" +) + +var secretsMap = map[string]string{} + +func SecretKeys() []string { + var uniqKeys = map[string]bool{} + for _, envVal := range os.Environ() { + key := envVal[0:strings.IndexByte(envVal, '=')] + uniqKeys[key] = true + } + for k, _ := range secretsMap { + uniqKeys[k] = true + } + var retStrings []string + for k, _ := range uniqKeys { + retStrings = append(retStrings, k) + } + return retStrings +} + +func GetSecret(key string) string { + if value := os.Getenv(key); value != "" { + return value + } + return secretsMap[key] +} diff --git a/nodemgr/internal/lib/misc/vers.go b/nodemgr/internal/lib/misc/vers.go new file mode 100644 index 00000000..193e0218 --- /dev/null +++ b/nodemgr/internal/lib/misc/vers.go @@ -0,0 +1,20 @@ +package misc + +import ( + "runtime/debug" + "slices" +) + +const version = "v0.0.1" + +func GetVersionInfo() string { + info, ok := debug.ReadBuildInfo() + if !ok { + return "The version information could not be determined" + } + var vcsRev = "(unknown)" + if fnd := slices.IndexFunc(info.Settings, func(v debug.BuildSetting) bool { return v.Key == "vcs.revision" }); fnd != -1 { + vcsRev = info.Settings[fnd].Value[0:7] + } + return vcsRev +} diff --git a/nodemgr/internal/lib/nfdapi/readme.me b/nodemgr/internal/lib/nfdapi/readme.me new file mode 100644 index 00000000..05f68796 --- /dev/null +++ b/nodemgr/internal/lib/nfdapi/readme.me @@ -0,0 +1 @@ +Created via https://editor.swagger.io/?url=https://api.nf.domains/info/openapi3.yaml and its generate code option with some minimal file cleanup diff --git a/nodemgr/internal/lib/nfdapi/swagger/README.md b/nodemgr/internal/lib/nfdapi/swagger/README.md new file mode 100644 index 00000000..a7bf29b3 --- /dev/null +++ b/nodemgr/internal/lib/nfdapi/swagger/README.md @@ -0,0 +1,143 @@ +# Go API client for swagger + +Service for querying and managing NFDs + +## Overview +This API client was generated by the [swagger-codegen](https://github.com/swagger-api/swagger-codegen) project. By using the [swagger-spec](https://github.com/swagger-api/swagger-spec) from a remote server, you can easily generate an API client. + +- API version: 1.0 +- Package version: 1.0.0 +- Build package: io.swagger.codegen.v3.generators.go.GoClientCodegen +For more information, please visit [https://discord.gg/7XcuMTfeZP](https://discord.gg/7XcuMTfeZP) + +## Installation +Put the package under your project folder and add the following in import: +```golang +import "./swagger" +``` + +## Documentation for API Endpoints + +All URIs are relative to *https://api.nf.domains* + +Class | Method | HTTP request | Description +------------ | ------------- | ------------- | ------------- +*InfoApi* | [**InfoVersion**](docs/InfoApi.md#infoversion) | **Get** /info/version | version info +*InfoApi* | [**Infoinfoopenapi3Yaml**](docs/InfoApi.md#infoinfoopenapi3yaml) | **Get** /info/openapi3.yaml | Download ./pubfiles/openapi3.yaml +*NfdApi* | [**NfdActivity**](docs/NfdApi.md#nfdactivity) | **Get** /nfd/activity | Fetch change activity for an NFD +*NfdApi* | [**NfdAnalytics**](docs/NfdApi.md#nfdanalytics) | **Get** /nfd/analytics | Fetch NFD analytics via various filters +*NfdApi* | [**NfdBadges**](docs/NfdApi.md#nfdbadges) | **Get** /nfd/badges/{name} | Fetch badge information (donations/etc) for an NFD +*NfdApi* | [**NfdBrowse**](docs/NfdApi.md#nfdbrowse) | **Get** /nfd/browse | Browse NFDs via various filters +*NfdApi* | [**NfdConsensusLeaders**](docs/NfdApi.md#nfdconsensusleaders) | **Get** /nfd/consensus/leaders | consensusLeaders nfd +*NfdApi* | [**NfdConsensusMetrics**](docs/NfdApi.md#nfdconsensusmetrics) | **Get** /nfd/consensus/metrics | consensusMetrics nfd +*NfdApi* | [**NfdContractLock**](docs/NfdApi.md#nfdcontractlock) | **Post** /nfd/contract/lock/{name} | contractLock nfd +*NfdApi* | [**NfdContractUpgrade**](docs/NfdApi.md#nfdcontractupgrade) | **Post** /nfd/contract/upgrade/{name} | contractUpgrade nfd +*NfdApi* | [**NfdDonationLeaders**](docs/NfdApi.md#nfddonationleaders) | **Get** /nfd/donations/leaders/{address} | donationLeaders nfd +*NfdApi* | [**NfdDonationLeadersV2**](docs/NfdApi.md#nfddonationleadersv2) | **Get** /nfd/v2/donations/leaders/{name} | donationLeadersV2 nfd +*NfdApi* | [**NfdDonationList**](docs/NfdApi.md#nfddonationlist) | **Get** /nfd/donations/list | donationList nfd +*NfdApi* | [**NfdDonationListV2**](docs/NfdApi.md#nfddonationlistv2) | **Get** /nfd/v2/donations/list | donationListV2 nfd +*NfdApi* | [**NfdDonations**](docs/NfdApi.md#nfddonations) | **Get** /nfd/donations/{name} | donations nfd +*NfdApi* | [**NfdEscrowOffer**](docs/NfdApi.md#nfdescrowoffer) | **Post** /nfd/escrowOffer/{name} | escrowOffer nfd +*NfdApi* | [**NfdGetLookup**](docs/NfdApi.md#nfdgetlookup) | **Get** /nfd/lookup | Reverse Address lookup with results returned per address +*NfdApi* | [**NfdGetNFD**](docs/NfdApi.md#nfdgetnfd) | **Get** /nfd/{nameOrID} | Get a specific NFD by name or by its application id +*NfdApi* | [**NfdGetNFDsForAddresses**](docs/NfdApi.md#nfdgetnfdsforaddresses) | **Get** /nfd/address | [DEPRECATED] Reverse Address lookup +*NfdApi* | [**NfdGetNFDsForAddressesV2**](docs/NfdApi.md#nfdgetnfdsforaddressesv2) | **Get** /nfd/v2/address | Reverse Address lookup with results returned per address +*NfdApi* | [**NfdGetNameSig**](docs/NfdApi.md#nfdgetnamesig) | **Get** /nfd/nameSig/{name} | getNameSig nfd +*NfdApi* | [**NfdGetOpenAuctions**](docs/NfdApi.md#nfdgetopenauctions) | **Get** /nfd/auction | Get all open auctions or those open for a particular name +*NfdApi* | [**NfdGetRevAddressSig**](docs/NfdApi.md#nfdgetrevaddresssig) | **Get** /nfd/revAddressSig/{address} | getRevAddressSig nfd +*NfdApi* | [**NfdIsValidASA**](docs/NfdApi.md#nfdisvalidasa) | **Get** /nfd/isValidASA/{asaID} | isValidASA nfd +*NfdApi* | [**NfdIsValidNFD**](docs/NfdApi.md#nfdisvalidnfd) | **Get** /nfd/isValid/{appID} | isValidNFD nfd +*NfdApi* | [**NfdKickoff**](docs/NfdApi.md#nfdkickoff) | **Post** /nfd/kickoff | kickoff nfd +*NfdApi* | [**NfdLinkAddress**](docs/NfdApi.md#nfdlinkaddress) | **Post** /nfd/links/addAddress/{name} | linkAddress nfd +*NfdApi* | [**NfdOffer**](docs/NfdApi.md#nfdoffer) | **Post** /nfd/offer/{name} | offer nfd +*NfdApi* | [**NfdPartnerKickoff**](docs/NfdApi.md#nfdpartnerkickoff) | **Post** /nfd/partnerKickoff | partnerKickoff nfd +*NfdApi* | [**NfdPostOfferToOwner**](docs/NfdApi.md#nfdpostoffertoowner) | **Post** /nfd/postOfferToOwner/{name} | postOfferToOwner nfd +*NfdApi* | [**NfdPurchase**](docs/NfdApi.md#nfdpurchase) | **Post** /nfd/purchase/{name} | purchase nfd +*NfdApi* | [**NfdRescindOffer**](docs/NfdApi.md#nfdrescindoffer) | **Post** /nfd/rescindOffer/{name} | rescindOffer nfd +*NfdApi* | [**NfdSearchV1**](docs/NfdApi.md#nfdsearchv1) | **Get** /nfd | [DEPRECATED] Search for NFDs based on select lookup criteria +*NfdApi* | [**NfdSearchV2**](docs/NfdApi.md#nfdsearchv2) | **Get** /nfd/v2/search | Search NFDs via various filters +*NfdApi* | [**NfdSegmentLeaders**](docs/NfdApi.md#nfdsegmentleaders) | **Get** /nfd/segment/leaders | segmentLeaders nfd +*NfdApi* | [**NfdSegmentLock**](docs/NfdApi.md#nfdsegmentlock) | **Post** /nfd/segment/lock/{name} | Lock/Unlock an NFD segment - specifying open price if unlocking +*NfdApi* | [**NfdSegmentPrice**](docs/NfdApi.md#nfdsegmentprice) | **Get** /nfd/segment/price/{name} | Returns cost to mint a named segment off a particular root. +*NfdApi* | [**NfdSendFromVault**](docs/NfdApi.md#nfdsendfromvault) | **Post** /nfd/vault/sendFrom/{name} | sendFromVault nfd +*NfdApi* | [**NfdSendToVault**](docs/NfdApi.md#nfdsendtovault) | **Post** /nfd/vault/sendTo/{name} | sendToVault nfd +*NfdApi* | [**NfdSetPrimaryAddress**](docs/NfdApi.md#nfdsetprimaryaddress) | **Post** /nfd/links/setPrimaryAddress/{name} | setPrimaryAddress nfd +*NfdApi* | [**NfdSetPrimaryNFD**](docs/NfdApi.md#nfdsetprimarynfd) | **Post** /nfd/links/setPrimaryNFD/{name} | setPrimaryNFD nfd +*NfdApi* | [**NfdSuggest**](docs/NfdApi.md#nfdsuggest) | **Get** /nfd/suggest/{name} | suggest nfd +*NfdApi* | [**NfdTotals**](docs/NfdApi.md#nfdtotals) | **Get** /nfd/totals | totals nfd +*NfdApi* | [**NfdTwitterLeaders**](docs/NfdApi.md#nfdtwitterleaders) | **Get** /nfd/twitter/leaders | twitterLeaders nfd +*NfdApi* | [**NfdUnlinkAddress**](docs/NfdApi.md#nfdunlinkaddress) | **Post** /nfd/links/removeAddress/{name} | unlinkAddress nfd +*NfdApi* | [**NfdUpdateAll**](docs/NfdApi.md#nfdupdateall) | **Put** /nfd/update/{name} | updateAll nfd +*NfdApi* | [**NfdUpdateImage**](docs/NfdApi.md#nfdupdateimage) | **Post** /nfd/updateImage/{name}/{sender}/{which} | updateImage nfd +*NfdApi* | [**NfdUpdatePartial**](docs/NfdApi.md#nfdupdatepartial) | **Patch** /nfd/update/{name} | updatePartial nfd +*NfdApi* | [**NfdVaultOptInLock**](docs/NfdApi.md#nfdvaultoptinlock) | **Post** /nfd/vault/lock/{name} | vaultOptInLock nfd +*NfdApi* | [**NfdVerifyConfirm**](docs/NfdApi.md#nfdverifyconfirm) | **Post** /nfd/verify/confirm/{id} | verifyConfirm nfd +*NfdApi* | [**NfdVerifyRequest**](docs/NfdApi.md#nfdverifyrequest) | **Post** /nfd/verify/request | verifyRequest nfd + +## Documentation For Models + + - [ConsensusRecord](docs/ConsensusRecord.md) + - [ContractLockRequestBody](docs/ContractLockRequestBody.md) + - [Donation](docs/Donation.md) + - [DonationAccount](docs/DonationAccount.md) + - [EscrowOfferRequestBody](docs/EscrowOfferRequestBody.md) + - [IsValidAsaResponseBody](docs/IsValidAsaResponseBody.md) + - [IsValidNfdResponseBody](docs/IsValidNfdResponseBody.md) + - [KickoffRequestBody](docs/KickoffRequestBody.md) + - [LinkAddressRequestBody](docs/LinkAddressRequestBody.md) + - [ModelError](docs/ModelError.md) + - [Nfd](docs/Nfd.md) + - [NfdActivity](docs/NfdActivity.md) + - [NfdAnalyticEvent](docs/NfdAnalyticEvent.md) + - [NfdAnalyticRecord](docs/NfdAnalyticRecord.md) + - [NfdAnalyticRecords](docs/NfdAnalyticRecords.md) + - [NfdAuction](docs/NfdAuction.md) + - [NfdAuctionAndPrice](docs/NfdAuctionAndPrice.md) + - [NfdProperties](docs/NfdProperties.md) + - [NfdRecord](docs/NfdRecord.md) + - [NfdRecordResponseFull](docs/NfdRecordResponseFull.md) + - [NfdRecordinaddress](docs/NfdRecordinaddress.md) + - [NfdV2SearchRecords](docs/NfdV2SearchRecords.md) + - [OfferRequestBody](docs/OfferRequestBody.md) + - [PartnerKickoffRequestBody](docs/PartnerKickoffRequestBody.md) + - [PostOfferToOwnerRequestBody](docs/PostOfferToOwnerRequestBody.md) + - [PurchaseRequestBody](docs/PurchaseRequestBody.md) + - [RateLimited](docs/RateLimited.md) + - [RescindOfferRequestBody](docs/RescindOfferRequestBody.md) + - [SegmentLockRequestBody](docs/SegmentLockRequestBody.md) + - [SegmentPriceResponseBody](docs/SegmentPriceResponseBody.md) + - [SendFromVaultRequestBody](docs/SendFromVaultRequestBody.md) + - [SendToVaultRequestBody](docs/SendToVaultRequestBody.md) + - [SetPrimaryAddressRequestBody](docs/SetPrimaryAddressRequestBody.md) + - [TotalsOkResponseBody](docs/TotalsOkResponseBody.md) + - [TotalsOkResponseBodyMintedTotals](docs/TotalsOkResponseBodyMintedTotals.md) + - [TotalsOkResponseBodySegmentTotals](docs/TotalsOkResponseBodySegmentTotals.md) + - [TotalsOkResponseBodySoldTotals](docs/TotalsOkResponseBodySoldTotals.md) + - [TwitterRecord](docs/TwitterRecord.md) + - [UpdatePartialRequestBody](docs/UpdatePartialRequestBody.md) + - [VaultOptInLockRequestBody](docs/VaultOptInLockRequestBody.md) + - [VerifyConfirmRequestBody](docs/VerifyConfirmRequestBody.md) + - [VerifyConfirmResponseBody](docs/VerifyConfirmResponseBody.md) + - [VerifyRequestRequestBody](docs/VerifyRequestRequestBody.md) + - [VerifyRequestResponseBody](docs/VerifyRequestResponseBody.md) + - [VersionResponseBody](docs/VersionResponseBody.md) + +## Documentation For Authorization + +## basic_header_Authorization +- **Type**: HTTP basic authentication + +Example +```golang +auth := context.WithValue(context.Background(), sw.ContextBasicAuth, sw.BasicAuth{ + UserName: "username", + Password: "password", +}) +r, err := client.Service.Operation(auth, args) +``` +## jwt_header_Authorization +## jwt_query_token + +## Author + +feedback@txnlab.dev diff --git a/nodemgr/internal/lib/nfdapi/swagger/api_info.go b/nodemgr/internal/lib/nfdapi/swagger/api_info.go new file mode 100644 index 00000000..54e06621 --- /dev/null +++ b/nodemgr/internal/lib/nfdapi/swagger/api_info.go @@ -0,0 +1,174 @@ +/* + * NFD Management Service + * + * Service for querying and managing NFDs + * + * API version: 1.0 + * Contact: feedback@txnlab.dev + * Generated by: Swagger Codegen (https://github.com/swagger-api/swagger-codegen.git) + */ +package swagger + +import ( + "context" + "io/ioutil" + "net/http" + "net/url" + "strings" +) + +// Linger please +var ( + _ context.Context +) + +type InfoApiService service + +/* +InfoApiService version info +Returns version information for the service + - @param ctx context.Context - for authentication, logging, cancellation, deadlines, tracing, etc. Passed from http.Request or context.Background(). + +@return VersionResponseBody +*/ +func (a *InfoApiService) InfoVersion(ctx context.Context) (VersionResponseBody, *http.Response, error) { + var ( + localVarHttpMethod = strings.ToUpper("Get") + localVarPostBody interface{} + localVarFileName string + localVarFileBytes []byte + localVarReturnValue VersionResponseBody + ) + + // create path and map variables + localVarPath := a.client.cfg.BasePath + "/info/version" + + localVarHeaderParams := make(map[string]string) + localVarQueryParams := url.Values{} + localVarFormParams := url.Values{} + + // to determine the Content-Type header + localVarHttpContentTypes := []string{} + + // set Content-Type header + localVarHttpContentType := selectHeaderContentType(localVarHttpContentTypes) + if localVarHttpContentType != "" { + localVarHeaderParams["Content-Type"] = localVarHttpContentType + } + + // to determine the Accept header + localVarHttpHeaderAccepts := []string{"application/json"} + + // set Accept header + localVarHttpHeaderAccept := selectHeaderAccept(localVarHttpHeaderAccepts) + if localVarHttpHeaderAccept != "" { + localVarHeaderParams["Accept"] = localVarHttpHeaderAccept + } + r, err := a.client.prepareRequest(ctx, localVarPath, localVarHttpMethod, localVarPostBody, localVarHeaderParams, localVarQueryParams, localVarFormParams, localVarFileName, localVarFileBytes) + if err != nil { + return localVarReturnValue, nil, err + } + + localVarHttpResponse, err := a.client.callAPI(r) + if err != nil || localVarHttpResponse == nil { + return localVarReturnValue, localVarHttpResponse, err + } + + localVarBody, err := ioutil.ReadAll(localVarHttpResponse.Body) + localVarHttpResponse.Body.Close() + if err != nil { + return localVarReturnValue, localVarHttpResponse, err + } + + if localVarHttpResponse.StatusCode < 300 { + // If we succeed, return the data, otherwise pass on to decode error. + err = a.client.decode(&localVarReturnValue, localVarBody, localVarHttpResponse.Header.Get("Content-Type")) + if err == nil { + return localVarReturnValue, localVarHttpResponse, err + } + } + + if localVarHttpResponse.StatusCode >= 300 { + newErr := GenericSwaggerError{ + body: localVarBody, + error: localVarHttpResponse.Status, + } + if localVarHttpResponse.StatusCode == 200 { + var v VersionResponseBody + err = a.client.decode(&v, localVarBody, localVarHttpResponse.Header.Get("Content-Type")) + if err != nil { + newErr.error = err.Error() + return localVarReturnValue, localVarHttpResponse, newErr + } + newErr.model = v + return localVarReturnValue, localVarHttpResponse, newErr + } + return localVarReturnValue, localVarHttpResponse, newErr + } + + return localVarReturnValue, localVarHttpResponse, nil +} + +/* +InfoApiService Download ./pubfiles/openapi3.yaml +YAML document containing the API swagger definition + - @param ctx context.Context - for authentication, logging, cancellation, deadlines, tracing, etc. Passed from http.Request or context.Background(). +*/ +func (a *InfoApiService) Infoinfoopenapi3Yaml(ctx context.Context) (*http.Response, error) { + var ( + localVarHttpMethod = strings.ToUpper("Get") + localVarPostBody interface{} + localVarFileName string + localVarFileBytes []byte + ) + + // create path and map variables + localVarPath := a.client.cfg.BasePath + "/info/openapi3.yaml" + + localVarHeaderParams := make(map[string]string) + localVarQueryParams := url.Values{} + localVarFormParams := url.Values{} + + // to determine the Content-Type header + localVarHttpContentTypes := []string{} + + // set Content-Type header + localVarHttpContentType := selectHeaderContentType(localVarHttpContentTypes) + if localVarHttpContentType != "" { + localVarHeaderParams["Content-Type"] = localVarHttpContentType + } + + // to determine the Accept header + localVarHttpHeaderAccepts := []string{} + + // set Accept header + localVarHttpHeaderAccept := selectHeaderAccept(localVarHttpHeaderAccepts) + if localVarHttpHeaderAccept != "" { + localVarHeaderParams["Accept"] = localVarHttpHeaderAccept + } + r, err := a.client.prepareRequest(ctx, localVarPath, localVarHttpMethod, localVarPostBody, localVarHeaderParams, localVarQueryParams, localVarFormParams, localVarFileName, localVarFileBytes) + if err != nil { + return nil, err + } + + localVarHttpResponse, err := a.client.callAPI(r) + if err != nil || localVarHttpResponse == nil { + return localVarHttpResponse, err + } + + localVarBody, err := ioutil.ReadAll(localVarHttpResponse.Body) + localVarHttpResponse.Body.Close() + if err != nil { + return localVarHttpResponse, err + } + + if localVarHttpResponse.StatusCode >= 300 { + newErr := GenericSwaggerError{ + body: localVarBody, + error: localVarHttpResponse.Status, + } + return localVarHttpResponse, newErr + } + + return localVarHttpResponse, nil +} diff --git a/nodemgr/internal/lib/nfdapi/swagger/api_nfd.go b/nodemgr/internal/lib/nfdapi/swagger/api_nfd.go new file mode 100644 index 00000000..abf1b6c9 --- /dev/null +++ b/nodemgr/internal/lib/nfdapi/swagger/api_nfd.go @@ -0,0 +1,6401 @@ +/* + * NFD Management Service + * + * Service for querying and managing NFDs + * + * API version: 1.0 + * Contact: feedback@txnlab.dev + * Generated by: Swagger Codegen (https://github.com/swagger-api/swagger-codegen.git) + */ +package swagger + +import ( + "context" + "fmt" + "io/ioutil" + "net/http" + "net/url" + "strings" + + "github.com/antihax/optional" +) + +// Linger please +var ( + _ context.Context +) + +type NfdApiService service + +/* +NfdApiService Fetch change activity for an NFD +Fetch change activity for an NFD, specifically general 'block-level' deltas for an NFD + * @param ctx context.Context - for authentication, logging, cancellation, deadlines, tracing, etc. Passed from http.Request or context.Background(). + * @param name Name(s) of NFDs to fetch activity for. Specify the same query parameter multiple times for each nane, ie: name=xxx&name=yyy&name=zzz\") + * @param optional nil or *NfdApiNfdActivityOpts - Optional Parameters: + * @param "Type_" (optional.String) - type of activity to retrieve + * @param "AfterTime" (optional.Time) - Fetch events that occurred only after the specified time + * @param "Limit" (optional.Int64) - Limit the number of results returned, per NFD - max 50 + * @param "Sort" (optional.String) - What to sort on - descending timestamp is default + * @param "IfNoneMatch" (optional.String) - etag +@return []NfdActivity +*/ + +type NfdApiNfdActivityOpts struct { + Type_ optional.String + AfterTime optional.Time + Limit optional.Int64 + Sort optional.String + IfNoneMatch optional.String +} + +func (a *NfdApiService) NfdActivity(ctx context.Context, name []string, localVarOptionals *NfdApiNfdActivityOpts) ([]NfdActivity, *http.Response, error) { + var ( + localVarHttpMethod = strings.ToUpper("Get") + localVarPostBody interface{} + localVarFileName string + localVarFileBytes []byte + localVarReturnValue []NfdActivity + ) + + // create path and map variables + localVarPath := a.client.cfg.BasePath + "/nfd/activity" + + localVarHeaderParams := make(map[string]string) + localVarQueryParams := url.Values{} + localVarFormParams := url.Values{} + if len(name) < 1 { + return localVarReturnValue, nil, reportError("name must have at least 1 elements") + } + if len(name) > 20 { + return localVarReturnValue, nil, reportError("name must have less than 20 elements") + } + + localVarQueryParams.Add("name", parameterToString(name, "multi")) + if localVarOptionals != nil && localVarOptionals.Type_.IsSet() { + localVarQueryParams.Add("type", parameterToString(localVarOptionals.Type_.Value(), "")) + } + if localVarOptionals != nil && localVarOptionals.AfterTime.IsSet() { + localVarQueryParams.Add("afterTime", parameterToString(localVarOptionals.AfterTime.Value(), "")) + } + if localVarOptionals != nil && localVarOptionals.Limit.IsSet() { + localVarQueryParams.Add("limit", parameterToString(localVarOptionals.Limit.Value(), "")) + } + if localVarOptionals != nil && localVarOptionals.Sort.IsSet() { + localVarQueryParams.Add("sort", parameterToString(localVarOptionals.Sort.Value(), "")) + } + // to determine the Content-Type header + localVarHttpContentTypes := []string{} + + // set Content-Type header + localVarHttpContentType := selectHeaderContentType(localVarHttpContentTypes) + if localVarHttpContentType != "" { + localVarHeaderParams["Content-Type"] = localVarHttpContentType + } + + // to determine the Accept header + localVarHttpHeaderAccepts := []string{"application/json", "application/vnd.goa.error"} + + // set Accept header + localVarHttpHeaderAccept := selectHeaderAccept(localVarHttpHeaderAccepts) + if localVarHttpHeaderAccept != "" { + localVarHeaderParams["Accept"] = localVarHttpHeaderAccept + } + if localVarOptionals != nil && localVarOptionals.IfNoneMatch.IsSet() { + localVarHeaderParams["if-none-match"] = parameterToString(localVarOptionals.IfNoneMatch.Value(), "") + } + r, err := a.client.prepareRequest(ctx, localVarPath, localVarHttpMethod, localVarPostBody, localVarHeaderParams, localVarQueryParams, localVarFormParams, localVarFileName, localVarFileBytes) + if err != nil { + return localVarReturnValue, nil, err + } + + localVarHttpResponse, err := a.client.callAPI(r) + if err != nil || localVarHttpResponse == nil { + return localVarReturnValue, localVarHttpResponse, err + } + + localVarBody, err := ioutil.ReadAll(localVarHttpResponse.Body) + localVarHttpResponse.Body.Close() + if err != nil { + return localVarReturnValue, localVarHttpResponse, err + } + + if localVarHttpResponse.StatusCode < 300 { + // If we succeed, return the data, otherwise pass on to decode error. + err = a.client.decode(&localVarReturnValue, localVarBody, localVarHttpResponse.Header.Get("Content-Type")) + if err == nil { + return localVarReturnValue, localVarHttpResponse, err + } + } + + if localVarHttpResponse.StatusCode >= 300 { + newErr := GenericSwaggerError{ + body: localVarBody, + error: localVarHttpResponse.Status, + } + if localVarHttpResponse.StatusCode == 200 { + var v []NfdActivity + err = a.client.decode(&v, localVarBody, localVarHttpResponse.Header.Get("Content-Type")) + if err != nil { + newErr.error = err.Error() + return localVarReturnValue, localVarHttpResponse, newErr + } + newErr.model = v + return localVarReturnValue, localVarHttpResponse, newErr + } + if localVarHttpResponse.StatusCode == 400 { + var v ModelError + err = a.client.decode(&v, localVarBody, localVarHttpResponse.Header.Get("Content-Type")) + if err != nil { + newErr.error = err.Error() + return localVarReturnValue, localVarHttpResponse, newErr + } + newErr.model = v + return localVarReturnValue, localVarHttpResponse, newErr + } + if localVarHttpResponse.StatusCode == 404 { + var v ModelError + err = a.client.decode(&v, localVarBody, localVarHttpResponse.Header.Get("Content-Type")) + if err != nil { + newErr.error = err.Error() + return localVarReturnValue, localVarHttpResponse, newErr + } + newErr.model = v + return localVarReturnValue, localVarHttpResponse, newErr + } + if localVarHttpResponse.StatusCode == 429 { + var v RateLimited + err = a.client.decode(&v, localVarBody, localVarHttpResponse.Header.Get("Content-Type")) + if err != nil { + newErr.error = err.Error() + return localVarReturnValue, localVarHttpResponse, newErr + } + newErr.model = v + return localVarReturnValue, localVarHttpResponse, newErr + } + return localVarReturnValue, localVarHttpResponse, newErr + } + + return localVarReturnValue, localVarHttpResponse, nil +} + +/* +NfdApiService Fetch NFD analytics via various filters +Fetch NFD analytics via various filters + * @param ctx context.Context - for authentication, logging, cancellation, deadlines, tracing, etc. Passed from http.Request or context.Background(). + * @param optional nil or *NfdApiNfdAnalyticsOpts - Optional Parameters: + * @param "Name" (optional.String) - name or partial match of NFD name to filter on + * @param "Buyer" (optional.String) - Buyer address to filter on + * @param "Seller" (optional.String) - Seller address to filter on + * @param "Event" (optional.Interface of []string) - one or more events to filter on + * @param "RequireBuyer" (optional.Bool) - Whether the buyer property must be present in the data. Setting this will exclude auction mint events for eg + * @param "IncludeOwner" (optional.Bool) - Whether to add a currentOwner property to each event with the 'current' owner of the NFD referenced by that event + * @param "ExcludeNFDAsSeller" (optional.Bool) - Whether to exclude events where NFDomains is the seller. If set to true, and filtering on 'sold' event for eg, returned items will will be secondary sales only. + * @param "Category" (optional.Interface of []string) - + * @param "SaleType" (optional.Interface of []string) - + * @param "Length" (optional.Interface of []string) - Length of NFD + * @param "Traits" (optional.Interface of []string) - Traits of NFD + * @param "ParentAppID" (optional.Int64) - The parent NFD Application id to find. Used for fetching segments of an NFD + * @param "MinPrice" (optional.Int64) - Minimum price of NFD + * @param "MaxPrice" (optional.Int64) - Maximum price of NFD + * @param "AfterTime" (optional.Time) - Fetch analytics events that occurred only after the specified time + * @param "Limit" (optional.Int64) - Limit the number of results returned - max 200 + * @param "Offset" (optional.Int64) - Starting document in large list. Fetch 1-100 [limit 100], pass offset 100 to fetch 100-200 + * @param "Sort" (optional.String) - What to sort on - descending timestamp is default + * @param "IfNoneMatch" (optional.String) - etag +@return NfdAnalyticRecords +*/ + +type NfdApiNfdAnalyticsOpts struct { + Name optional.String + Buyer optional.String + Seller optional.String + Event optional.Interface + RequireBuyer optional.Bool + IncludeOwner optional.Bool + ExcludeNFDAsSeller optional.Bool + Category optional.Interface + SaleType optional.Interface + Length optional.Interface + Traits optional.Interface + ParentAppID optional.Int64 + MinPrice optional.Int64 + MaxPrice optional.Int64 + AfterTime optional.Time + Limit optional.Int64 + Offset optional.Int64 + Sort optional.String + IfNoneMatch optional.String +} + +func (a *NfdApiService) NfdAnalytics(ctx context.Context, localVarOptionals *NfdApiNfdAnalyticsOpts) (NfdAnalyticRecords, *http.Response, error) { + var ( + localVarHttpMethod = strings.ToUpper("Get") + localVarPostBody interface{} + localVarFileName string + localVarFileBytes []byte + localVarReturnValue NfdAnalyticRecords + ) + + // create path and map variables + localVarPath := a.client.cfg.BasePath + "/nfd/analytics" + + localVarHeaderParams := make(map[string]string) + localVarQueryParams := url.Values{} + localVarFormParams := url.Values{} + + if localVarOptionals != nil && localVarOptionals.Name.IsSet() { + localVarQueryParams.Add("name", parameterToString(localVarOptionals.Name.Value(), "")) + } + if localVarOptionals != nil && localVarOptionals.Buyer.IsSet() { + localVarQueryParams.Add("buyer", parameterToString(localVarOptionals.Buyer.Value(), "")) + } + if localVarOptionals != nil && localVarOptionals.Seller.IsSet() { + localVarQueryParams.Add("seller", parameterToString(localVarOptionals.Seller.Value(), "")) + } + if localVarOptionals != nil && localVarOptionals.Event.IsSet() { + localVarQueryParams.Add("event", parameterToString(localVarOptionals.Event.Value(), "multi")) + } + if localVarOptionals != nil && localVarOptionals.RequireBuyer.IsSet() { + localVarQueryParams.Add("requireBuyer", parameterToString(localVarOptionals.RequireBuyer.Value(), "")) + } + if localVarOptionals != nil && localVarOptionals.IncludeOwner.IsSet() { + localVarQueryParams.Add("includeOwner", parameterToString(localVarOptionals.IncludeOwner.Value(), "")) + } + if localVarOptionals != nil && localVarOptionals.ExcludeNFDAsSeller.IsSet() { + localVarQueryParams.Add("excludeNFDAsSeller", parameterToString(localVarOptionals.ExcludeNFDAsSeller.Value(), "")) + } + if localVarOptionals != nil && localVarOptionals.Category.IsSet() { + localVarQueryParams.Add("category", parameterToString(localVarOptionals.Category.Value(), "multi")) + } + if localVarOptionals != nil && localVarOptionals.SaleType.IsSet() { + localVarQueryParams.Add("saleType", parameterToString(localVarOptionals.SaleType.Value(), "multi")) + } + if localVarOptionals != nil && localVarOptionals.Length.IsSet() { + localVarQueryParams.Add("length", parameterToString(localVarOptionals.Length.Value(), "multi")) + } + if localVarOptionals != nil && localVarOptionals.Traits.IsSet() { + localVarQueryParams.Add("traits", parameterToString(localVarOptionals.Traits.Value(), "multi")) + } + if localVarOptionals != nil && localVarOptionals.ParentAppID.IsSet() { + localVarQueryParams.Add("parentAppID", parameterToString(localVarOptionals.ParentAppID.Value(), "")) + } + if localVarOptionals != nil && localVarOptionals.MinPrice.IsSet() { + localVarQueryParams.Add("minPrice", parameterToString(localVarOptionals.MinPrice.Value(), "")) + } + if localVarOptionals != nil && localVarOptionals.MaxPrice.IsSet() { + localVarQueryParams.Add("maxPrice", parameterToString(localVarOptionals.MaxPrice.Value(), "")) + } + if localVarOptionals != nil && localVarOptionals.AfterTime.IsSet() { + localVarQueryParams.Add("afterTime", parameterToString(localVarOptionals.AfterTime.Value(), "")) + } + if localVarOptionals != nil && localVarOptionals.Limit.IsSet() { + localVarQueryParams.Add("limit", parameterToString(localVarOptionals.Limit.Value(), "")) + } + if localVarOptionals != nil && localVarOptionals.Offset.IsSet() { + localVarQueryParams.Add("offset", parameterToString(localVarOptionals.Offset.Value(), "")) + } + if localVarOptionals != nil && localVarOptionals.Sort.IsSet() { + localVarQueryParams.Add("sort", parameterToString(localVarOptionals.Sort.Value(), "")) + } + // to determine the Content-Type header + localVarHttpContentTypes := []string{} + + // set Content-Type header + localVarHttpContentType := selectHeaderContentType(localVarHttpContentTypes) + if localVarHttpContentType != "" { + localVarHeaderParams["Content-Type"] = localVarHttpContentType + } + + // to determine the Accept header + localVarHttpHeaderAccepts := []string{"application/json", "application/vnd.goa.error"} + + // set Accept header + localVarHttpHeaderAccept := selectHeaderAccept(localVarHttpHeaderAccepts) + if localVarHttpHeaderAccept != "" { + localVarHeaderParams["Accept"] = localVarHttpHeaderAccept + } + if localVarOptionals != nil && localVarOptionals.IfNoneMatch.IsSet() { + localVarHeaderParams["if-none-match"] = parameterToString(localVarOptionals.IfNoneMatch.Value(), "") + } + r, err := a.client.prepareRequest(ctx, localVarPath, localVarHttpMethod, localVarPostBody, localVarHeaderParams, localVarQueryParams, localVarFormParams, localVarFileName, localVarFileBytes) + if err != nil { + return localVarReturnValue, nil, err + } + + localVarHttpResponse, err := a.client.callAPI(r) + if err != nil || localVarHttpResponse == nil { + return localVarReturnValue, localVarHttpResponse, err + } + + localVarBody, err := ioutil.ReadAll(localVarHttpResponse.Body) + localVarHttpResponse.Body.Close() + if err != nil { + return localVarReturnValue, localVarHttpResponse, err + } + + if localVarHttpResponse.StatusCode < 300 { + // If we succeed, return the data, otherwise pass on to decode error. + err = a.client.decode(&localVarReturnValue, localVarBody, localVarHttpResponse.Header.Get("Content-Type")) + if err == nil { + return localVarReturnValue, localVarHttpResponse, err + } + } + + if localVarHttpResponse.StatusCode >= 300 { + newErr := GenericSwaggerError{ + body: localVarBody, + error: localVarHttpResponse.Status, + } + if localVarHttpResponse.StatusCode == 200 { + var v NfdAnalyticRecords + err = a.client.decode(&v, localVarBody, localVarHttpResponse.Header.Get("Content-Type")) + if err != nil { + newErr.error = err.Error() + return localVarReturnValue, localVarHttpResponse, newErr + } + newErr.model = v + return localVarReturnValue, localVarHttpResponse, newErr + } + if localVarHttpResponse.StatusCode == 400 { + var v ModelError + err = a.client.decode(&v, localVarBody, localVarHttpResponse.Header.Get("Content-Type")) + if err != nil { + newErr.error = err.Error() + return localVarReturnValue, localVarHttpResponse, newErr + } + newErr.model = v + return localVarReturnValue, localVarHttpResponse, newErr + } + if localVarHttpResponse.StatusCode == 404 { + var v ModelError + err = a.client.decode(&v, localVarBody, localVarHttpResponse.Header.Get("Content-Type")) + if err != nil { + newErr.error = err.Error() + return localVarReturnValue, localVarHttpResponse, newErr + } + newErr.model = v + return localVarReturnValue, localVarHttpResponse, newErr + } + if localVarHttpResponse.StatusCode == 429 { + var v RateLimited + err = a.client.decode(&v, localVarBody, localVarHttpResponse.Header.Get("Content-Type")) + if err != nil { + newErr.error = err.Error() + return localVarReturnValue, localVarHttpResponse, newErr + } + newErr.model = v + return localVarReturnValue, localVarHttpResponse, newErr + } + return localVarReturnValue, localVarHttpResponse, newErr + } + + return localVarReturnValue, localVarHttpResponse, nil +} + +/* +NfdApiService Fetch badge information (donations/etc) for an NFD +Fetch badge information (ie: donations) for an NFD + * @param ctx context.Context - for authentication, logging, cancellation, deadlines, tracing, etc. Passed from http.Request or context.Background(). + * @param name + * @param optional nil or *NfdApiNfdBadgesOpts - Optional Parameters: + * @param "IfNoneMatch" (optional.String) - etag +@return map[string][]map[string]string +*/ + +type NfdApiNfdBadgesOpts struct { + IfNoneMatch optional.String +} + +func (a *NfdApiService) NfdBadges(ctx context.Context, name string, localVarOptionals *NfdApiNfdBadgesOpts) (map[string][]map[string]string, *http.Response, error) { + var ( + localVarHttpMethod = strings.ToUpper("Get") + localVarPostBody interface{} + localVarFileName string + localVarFileBytes []byte + localVarReturnValue map[string][]map[string]string + ) + + // create path and map variables + localVarPath := a.client.cfg.BasePath + "/nfd/badges/{name}" + localVarPath = strings.Replace(localVarPath, "{"+"name"+"}", fmt.Sprintf("%v", name), -1) + + localVarHeaderParams := make(map[string]string) + localVarQueryParams := url.Values{} + localVarFormParams := url.Values{} + if strlen(name) < 1 { + return localVarReturnValue, nil, reportError("name must have at least 1 elements") + } + if strlen(name) > 120 { + return localVarReturnValue, nil, reportError("name must have less than 120 elements") + } + + // to determine the Content-Type header + localVarHttpContentTypes := []string{} + + // set Content-Type header + localVarHttpContentType := selectHeaderContentType(localVarHttpContentTypes) + if localVarHttpContentType != "" { + localVarHeaderParams["Content-Type"] = localVarHttpContentType + } + + // to determine the Accept header + localVarHttpHeaderAccepts := []string{"application/json", "application/vnd.goa.error"} + + // set Accept header + localVarHttpHeaderAccept := selectHeaderAccept(localVarHttpHeaderAccepts) + if localVarHttpHeaderAccept != "" { + localVarHeaderParams["Accept"] = localVarHttpHeaderAccept + } + if localVarOptionals != nil && localVarOptionals.IfNoneMatch.IsSet() { + localVarHeaderParams["if-none-match"] = parameterToString(localVarOptionals.IfNoneMatch.Value(), "") + } + r, err := a.client.prepareRequest(ctx, localVarPath, localVarHttpMethod, localVarPostBody, localVarHeaderParams, localVarQueryParams, localVarFormParams, localVarFileName, localVarFileBytes) + if err != nil { + return localVarReturnValue, nil, err + } + + localVarHttpResponse, err := a.client.callAPI(r) + if err != nil || localVarHttpResponse == nil { + return localVarReturnValue, localVarHttpResponse, err + } + + localVarBody, err := ioutil.ReadAll(localVarHttpResponse.Body) + localVarHttpResponse.Body.Close() + if err != nil { + return localVarReturnValue, localVarHttpResponse, err + } + + if localVarHttpResponse.StatusCode < 300 { + // If we succeed, return the data, otherwise pass on to decode error. + err = a.client.decode(&localVarReturnValue, localVarBody, localVarHttpResponse.Header.Get("Content-Type")) + if err == nil { + return localVarReturnValue, localVarHttpResponse, err + } + } + + if localVarHttpResponse.StatusCode >= 300 { + newErr := GenericSwaggerError{ + body: localVarBody, + error: localVarHttpResponse.Status, + } + if localVarHttpResponse.StatusCode == 200 { + var v map[string][]map[string]string + err = a.client.decode(&v, localVarBody, localVarHttpResponse.Header.Get("Content-Type")) + if err != nil { + newErr.error = err.Error() + return localVarReturnValue, localVarHttpResponse, newErr + } + newErr.model = v + return localVarReturnValue, localVarHttpResponse, newErr + } + if localVarHttpResponse.StatusCode == 400 { + var v ModelError + err = a.client.decode(&v, localVarBody, localVarHttpResponse.Header.Get("Content-Type")) + if err != nil { + newErr.error = err.Error() + return localVarReturnValue, localVarHttpResponse, newErr + } + newErr.model = v + return localVarReturnValue, localVarHttpResponse, newErr + } + if localVarHttpResponse.StatusCode == 404 { + var v ModelError + err = a.client.decode(&v, localVarBody, localVarHttpResponse.Header.Get("Content-Type")) + if err != nil { + newErr.error = err.Error() + return localVarReturnValue, localVarHttpResponse, newErr + } + newErr.model = v + return localVarReturnValue, localVarHttpResponse, newErr + } + if localVarHttpResponse.StatusCode == 429 { + var v RateLimited + err = a.client.decode(&v, localVarBody, localVarHttpResponse.Header.Get("Content-Type")) + if err != nil { + newErr.error = err.Error() + return localVarReturnValue, localVarHttpResponse, newErr + } + newErr.model = v + return localVarReturnValue, localVarHttpResponse, newErr + } + return localVarReturnValue, localVarHttpResponse, newErr + } + + return localVarReturnValue, localVarHttpResponse, nil +} + +/* +NfdApiService Browse NFDs via various filters + * @param ctx context.Context - for authentication, logging, cancellation, deadlines, tracing, etc. Passed from http.Request or context.Background(). + * @param optional nil or *NfdApiNfdBrowseOpts - Optional Parameters: + * @param "Name" (optional.String) - name or partial match of NFD name to filter on + * @param "Category" (optional.Interface of []string) - + * @param "SaleType" (optional.Interface of []string) - + * @param "state" (optional.Interface of []string) - + * @param "ParentAppID" (optional.Int64) - The parent NFD Application id to find. Used for fetching segments of an NFD + * @param "Length" (optional.Interface of []string) - Length of NFD + * @param "Traits" (optional.Interface of []string) - Traits of NFD + * @param "owner" (optional.String) - An Algorand account address to find all NFDs owned by that address + * @param "ReservedFor" (optional.String) - An Algorand account address to find all NFDs reserved for that address + * @param "Prefix" (optional.String) - The start of an NFD name, fetching multiple NFDs that have that prefix + * @param "Substring" (optional.String) - Part of an NFD name, fetching multiple NFDs that have that substring (minimum 3 characters) + * @param "Vproperty" (optional.String) - Verified property name to search on - specify value with vvalue + * @param "Vvalue" (optional.String) - Value to find in the vproperty field specified with the vproperty parameter + * @param "MinPrice" (optional.Int64) - Minimum price of NFD + * @param "MaxPrice" (optional.Int64) - Maximum price of NFD + * @param "ChangedAfter" (optional.Time) - Fetch NFDs that changed after the specified timestamp + * @param "Limit" (optional.Int64) - Limit the number of results returned - max 200 + * @param "Offset" (optional.Int64) - Starting document in large list. Fetch 1-100 [limit 100], pass offset 100 to fetch 100-200 + * @param "Sort" (optional.String) - What to sort on + * @param "View" (optional.String) - View of data to return, tiny (name, owner, caAlgo, unverifiedCaAlgo only), brief (default), or full + * @param "IfNoneMatch" (optional.String) - etag +@return []NfdRecord +*/ + +type NfdApiNfdBrowseOpts struct { + Name optional.String + Category optional.Interface + SaleType optional.Interface + State optional.Interface + ParentAppID optional.Int64 + Length optional.Interface + Traits optional.Interface + Owner optional.String + ReservedFor optional.String + Prefix optional.String + Substring optional.String + Vproperty optional.String + Vvalue optional.String + MinPrice optional.Int64 + MaxPrice optional.Int64 + ChangedAfter optional.Time + Limit optional.Int64 + Offset optional.Int64 + Sort optional.String + View optional.String + IfNoneMatch optional.String +} + +func (a *NfdApiService) NfdBrowse(ctx context.Context, localVarOptionals *NfdApiNfdBrowseOpts) ([]NfdRecord, *http.Response, error) { + var ( + localVarHttpMethod = strings.ToUpper("Get") + localVarPostBody interface{} + localVarFileName string + localVarFileBytes []byte + localVarReturnValue []NfdRecord + ) + + // create path and map variables + localVarPath := a.client.cfg.BasePath + "/nfd/browse" + + localVarHeaderParams := make(map[string]string) + localVarQueryParams := url.Values{} + localVarFormParams := url.Values{} + + if localVarOptionals != nil && localVarOptionals.Name.IsSet() { + localVarQueryParams.Add("name", parameterToString(localVarOptionals.Name.Value(), "")) + } + if localVarOptionals != nil && localVarOptionals.Category.IsSet() { + localVarQueryParams.Add("category", parameterToString(localVarOptionals.Category.Value(), "multi")) + } + if localVarOptionals != nil && localVarOptionals.SaleType.IsSet() { + localVarQueryParams.Add("saleType", parameterToString(localVarOptionals.SaleType.Value(), "multi")) + } + if localVarOptionals != nil && localVarOptionals.State.IsSet() { + localVarQueryParams.Add("state", parameterToString(localVarOptionals.State.Value(), "multi")) + } + if localVarOptionals != nil && localVarOptionals.ParentAppID.IsSet() { + localVarQueryParams.Add("parentAppID", parameterToString(localVarOptionals.ParentAppID.Value(), "")) + } + if localVarOptionals != nil && localVarOptionals.Length.IsSet() { + localVarQueryParams.Add("length", parameterToString(localVarOptionals.Length.Value(), "multi")) + } + if localVarOptionals != nil && localVarOptionals.Traits.IsSet() { + localVarQueryParams.Add("traits", parameterToString(localVarOptionals.Traits.Value(), "multi")) + } + if localVarOptionals != nil && localVarOptionals.Owner.IsSet() { + localVarQueryParams.Add("owner", parameterToString(localVarOptionals.Owner.Value(), "")) + } + if localVarOptionals != nil && localVarOptionals.ReservedFor.IsSet() { + localVarQueryParams.Add("reservedFor", parameterToString(localVarOptionals.ReservedFor.Value(), "")) + } + if localVarOptionals != nil && localVarOptionals.Prefix.IsSet() { + localVarQueryParams.Add("prefix", parameterToString(localVarOptionals.Prefix.Value(), "")) + } + if localVarOptionals != nil && localVarOptionals.Substring.IsSet() { + localVarQueryParams.Add("substring", parameterToString(localVarOptionals.Substring.Value(), "")) + } + if localVarOptionals != nil && localVarOptionals.Vproperty.IsSet() { + localVarQueryParams.Add("vproperty", parameterToString(localVarOptionals.Vproperty.Value(), "")) + } + if localVarOptionals != nil && localVarOptionals.Vvalue.IsSet() { + localVarQueryParams.Add("vvalue", parameterToString(localVarOptionals.Vvalue.Value(), "")) + } + if localVarOptionals != nil && localVarOptionals.MinPrice.IsSet() { + localVarQueryParams.Add("minPrice", parameterToString(localVarOptionals.MinPrice.Value(), "")) + } + if localVarOptionals != nil && localVarOptionals.MaxPrice.IsSet() { + localVarQueryParams.Add("maxPrice", parameterToString(localVarOptionals.MaxPrice.Value(), "")) + } + if localVarOptionals != nil && localVarOptionals.ChangedAfter.IsSet() { + localVarQueryParams.Add("changedAfter", parameterToString(localVarOptionals.ChangedAfter.Value(), "")) + } + if localVarOptionals != nil && localVarOptionals.Limit.IsSet() { + localVarQueryParams.Add("limit", parameterToString(localVarOptionals.Limit.Value(), "")) + } + if localVarOptionals != nil && localVarOptionals.Offset.IsSet() { + localVarQueryParams.Add("offset", parameterToString(localVarOptionals.Offset.Value(), "")) + } + if localVarOptionals != nil && localVarOptionals.Sort.IsSet() { + localVarQueryParams.Add("sort", parameterToString(localVarOptionals.Sort.Value(), "")) + } + if localVarOptionals != nil && localVarOptionals.View.IsSet() { + localVarQueryParams.Add("view", parameterToString(localVarOptionals.View.Value(), "")) + } + // to determine the Content-Type header + localVarHttpContentTypes := []string{} + + // set Content-Type header + localVarHttpContentType := selectHeaderContentType(localVarHttpContentTypes) + if localVarHttpContentType != "" { + localVarHeaderParams["Content-Type"] = localVarHttpContentType + } + + // to determine the Accept header + localVarHttpHeaderAccepts := []string{"application/json", "application/vnd.goa.error"} + + // set Accept header + localVarHttpHeaderAccept := selectHeaderAccept(localVarHttpHeaderAccepts) + if localVarHttpHeaderAccept != "" { + localVarHeaderParams["Accept"] = localVarHttpHeaderAccept + } + if localVarOptionals != nil && localVarOptionals.IfNoneMatch.IsSet() { + localVarHeaderParams["if-none-match"] = parameterToString(localVarOptionals.IfNoneMatch.Value(), "") + } + r, err := a.client.prepareRequest(ctx, localVarPath, localVarHttpMethod, localVarPostBody, localVarHeaderParams, localVarQueryParams, localVarFormParams, localVarFileName, localVarFileBytes) + if err != nil { + return localVarReturnValue, nil, err + } + + localVarHttpResponse, err := a.client.callAPI(r) + if err != nil || localVarHttpResponse == nil { + return localVarReturnValue, localVarHttpResponse, err + } + + localVarBody, err := ioutil.ReadAll(localVarHttpResponse.Body) + localVarHttpResponse.Body.Close() + if err != nil { + return localVarReturnValue, localVarHttpResponse, err + } + + if localVarHttpResponse.StatusCode < 300 { + // If we succeed, return the data, otherwise pass on to decode error. + err = a.client.decode(&localVarReturnValue, localVarBody, localVarHttpResponse.Header.Get("Content-Type")) + if err == nil { + return localVarReturnValue, localVarHttpResponse, err + } + } + + if localVarHttpResponse.StatusCode >= 300 { + newErr := GenericSwaggerError{ + body: localVarBody, + error: localVarHttpResponse.Status, + } + if localVarHttpResponse.StatusCode == 200 { + var v []NfdRecord + err = a.client.decode(&v, localVarBody, localVarHttpResponse.Header.Get("Content-Type")) + if err != nil { + newErr.error = err.Error() + return localVarReturnValue, localVarHttpResponse, newErr + } + newErr.model = v + return localVarReturnValue, localVarHttpResponse, newErr + } + if localVarHttpResponse.StatusCode == 400 { + var v ModelError + err = a.client.decode(&v, localVarBody, localVarHttpResponse.Header.Get("Content-Type")) + if err != nil { + newErr.error = err.Error() + return localVarReturnValue, localVarHttpResponse, newErr + } + newErr.model = v + return localVarReturnValue, localVarHttpResponse, newErr + } + if localVarHttpResponse.StatusCode == 404 { + var v ModelError + err = a.client.decode(&v, localVarBody, localVarHttpResponse.Header.Get("Content-Type")) + if err != nil { + newErr.error = err.Error() + return localVarReturnValue, localVarHttpResponse, newErr + } + newErr.model = v + return localVarReturnValue, localVarHttpResponse, newErr + } + if localVarHttpResponse.StatusCode == 429 { + var v RateLimited + err = a.client.decode(&v, localVarBody, localVarHttpResponse.Header.Get("Content-Type")) + if err != nil { + newErr.error = err.Error() + return localVarReturnValue, localVarHttpResponse, newErr + } + newErr.model = v + return localVarReturnValue, localVarHttpResponse, newErr + } + return localVarReturnValue, localVarHttpResponse, newErr + } + + return localVarReturnValue, localVarHttpResponse, nil +} + +/* +NfdApiService consensusLeaders nfd +Get top consensus leaders + * @param ctx context.Context - for authentication, logging, cancellation, deadlines, tracing, etc. Passed from http.Request or context.Background(). + * @param optional nil or *NfdApiNfdConsensusLeadersOpts - Optional Parameters: + * @param "RequireNFD" (optional.Bool) - should it only match against accounts matching NFD linked addresses + * @param "IfNoneMatch" (optional.String) - etag +@return []ConsensusRecord +*/ + +type NfdApiNfdConsensusLeadersOpts struct { + RequireNFD optional.Bool + IfNoneMatch optional.String +} + +func (a *NfdApiService) NfdConsensusLeaders(ctx context.Context, localVarOptionals *NfdApiNfdConsensusLeadersOpts) ([]ConsensusRecord, *http.Response, error) { + var ( + localVarHttpMethod = strings.ToUpper("Get") + localVarPostBody interface{} + localVarFileName string + localVarFileBytes []byte + localVarReturnValue []ConsensusRecord + ) + + // create path and map variables + localVarPath := a.client.cfg.BasePath + "/nfd/consensus/leaders" + + localVarHeaderParams := make(map[string]string) + localVarQueryParams := url.Values{} + localVarFormParams := url.Values{} + + if localVarOptionals != nil && localVarOptionals.RequireNFD.IsSet() { + localVarQueryParams.Add("requireNFD", parameterToString(localVarOptionals.RequireNFD.Value(), "")) + } + // to determine the Content-Type header + localVarHttpContentTypes := []string{} + + // set Content-Type header + localVarHttpContentType := selectHeaderContentType(localVarHttpContentTypes) + if localVarHttpContentType != "" { + localVarHeaderParams["Content-Type"] = localVarHttpContentType + } + + // to determine the Accept header + localVarHttpHeaderAccepts := []string{"application/json", "application/vnd.goa.error"} + + // set Accept header + localVarHttpHeaderAccept := selectHeaderAccept(localVarHttpHeaderAccepts) + if localVarHttpHeaderAccept != "" { + localVarHeaderParams["Accept"] = localVarHttpHeaderAccept + } + if localVarOptionals != nil && localVarOptionals.IfNoneMatch.IsSet() { + localVarHeaderParams["if-none-match"] = parameterToString(localVarOptionals.IfNoneMatch.Value(), "") + } + r, err := a.client.prepareRequest(ctx, localVarPath, localVarHttpMethod, localVarPostBody, localVarHeaderParams, localVarQueryParams, localVarFormParams, localVarFileName, localVarFileBytes) + if err != nil { + return localVarReturnValue, nil, err + } + + localVarHttpResponse, err := a.client.callAPI(r) + if err != nil || localVarHttpResponse == nil { + return localVarReturnValue, localVarHttpResponse, err + } + + localVarBody, err := ioutil.ReadAll(localVarHttpResponse.Body) + localVarHttpResponse.Body.Close() + if err != nil { + return localVarReturnValue, localVarHttpResponse, err + } + + if localVarHttpResponse.StatusCode < 300 { + // If we succeed, return the data, otherwise pass on to decode error. + err = a.client.decode(&localVarReturnValue, localVarBody, localVarHttpResponse.Header.Get("Content-Type")) + if err == nil { + return localVarReturnValue, localVarHttpResponse, err + } + } + + if localVarHttpResponse.StatusCode >= 300 { + newErr := GenericSwaggerError{ + body: localVarBody, + error: localVarHttpResponse.Status, + } + if localVarHttpResponse.StatusCode == 200 { + var v []ConsensusRecord + err = a.client.decode(&v, localVarBody, localVarHttpResponse.Header.Get("Content-Type")) + if err != nil { + newErr.error = err.Error() + return localVarReturnValue, localVarHttpResponse, newErr + } + newErr.model = v + return localVarReturnValue, localVarHttpResponse, newErr + } + if localVarHttpResponse.StatusCode == 400 { + var v ModelError + err = a.client.decode(&v, localVarBody, localVarHttpResponse.Header.Get("Content-Type")) + if err != nil { + newErr.error = err.Error() + return localVarReturnValue, localVarHttpResponse, newErr + } + newErr.model = v + return localVarReturnValue, localVarHttpResponse, newErr + } + if localVarHttpResponse.StatusCode == 404 { + var v ModelError + err = a.client.decode(&v, localVarBody, localVarHttpResponse.Header.Get("Content-Type")) + if err != nil { + newErr.error = err.Error() + return localVarReturnValue, localVarHttpResponse, newErr + } + newErr.model = v + return localVarReturnValue, localVarHttpResponse, newErr + } + if localVarHttpResponse.StatusCode == 429 { + var v RateLimited + err = a.client.decode(&v, localVarBody, localVarHttpResponse.Header.Get("Content-Type")) + if err != nil { + newErr.error = err.Error() + return localVarReturnValue, localVarHttpResponse, newErr + } + newErr.model = v + return localVarReturnValue, localVarHttpResponse, newErr + } + return localVarReturnValue, localVarHttpResponse, newErr + } + + return localVarReturnValue, localVarHttpResponse, nil +} + +/* +NfdApiService consensusMetrics nfd +Get general metrics about Algorand consensus + * @param ctx context.Context - for authentication, logging, cancellation, deadlines, tracing, etc. Passed from http.Request or context.Background(). + * @param optional nil or *NfdApiNfdConsensusMetricsOpts - Optional Parameters: + * @param "IfNoneMatch" (optional.String) - etag +@return map[string][]map[string]string +*/ + +type NfdApiNfdConsensusMetricsOpts struct { + IfNoneMatch optional.String +} + +func (a *NfdApiService) NfdConsensusMetrics(ctx context.Context, localVarOptionals *NfdApiNfdConsensusMetricsOpts) (map[string][]map[string]string, *http.Response, error) { + var ( + localVarHttpMethod = strings.ToUpper("Get") + localVarPostBody interface{} + localVarFileName string + localVarFileBytes []byte + localVarReturnValue map[string][]map[string]string + ) + + // create path and map variables + localVarPath := a.client.cfg.BasePath + "/nfd/consensus/metrics" + + localVarHeaderParams := make(map[string]string) + localVarQueryParams := url.Values{} + localVarFormParams := url.Values{} + + // to determine the Content-Type header + localVarHttpContentTypes := []string{} + + // set Content-Type header + localVarHttpContentType := selectHeaderContentType(localVarHttpContentTypes) + if localVarHttpContentType != "" { + localVarHeaderParams["Content-Type"] = localVarHttpContentType + } + + // to determine the Accept header + localVarHttpHeaderAccepts := []string{"application/json", "application/vnd.goa.error"} + + // set Accept header + localVarHttpHeaderAccept := selectHeaderAccept(localVarHttpHeaderAccepts) + if localVarHttpHeaderAccept != "" { + localVarHeaderParams["Accept"] = localVarHttpHeaderAccept + } + if localVarOptionals != nil && localVarOptionals.IfNoneMatch.IsSet() { + localVarHeaderParams["if-none-match"] = parameterToString(localVarOptionals.IfNoneMatch.Value(), "") + } + r, err := a.client.prepareRequest(ctx, localVarPath, localVarHttpMethod, localVarPostBody, localVarHeaderParams, localVarQueryParams, localVarFormParams, localVarFileName, localVarFileBytes) + if err != nil { + return localVarReturnValue, nil, err + } + + localVarHttpResponse, err := a.client.callAPI(r) + if err != nil || localVarHttpResponse == nil { + return localVarReturnValue, localVarHttpResponse, err + } + + localVarBody, err := ioutil.ReadAll(localVarHttpResponse.Body) + localVarHttpResponse.Body.Close() + if err != nil { + return localVarReturnValue, localVarHttpResponse, err + } + + if localVarHttpResponse.StatusCode < 300 { + // If we succeed, return the data, otherwise pass on to decode error. + err = a.client.decode(&localVarReturnValue, localVarBody, localVarHttpResponse.Header.Get("Content-Type")) + if err == nil { + return localVarReturnValue, localVarHttpResponse, err + } + } + + if localVarHttpResponse.StatusCode >= 300 { + newErr := GenericSwaggerError{ + body: localVarBody, + error: localVarHttpResponse.Status, + } + if localVarHttpResponse.StatusCode == 200 { + var v map[string][]map[string]string + err = a.client.decode(&v, localVarBody, localVarHttpResponse.Header.Get("Content-Type")) + if err != nil { + newErr.error = err.Error() + return localVarReturnValue, localVarHttpResponse, newErr + } + newErr.model = v + return localVarReturnValue, localVarHttpResponse, newErr + } + if localVarHttpResponse.StatusCode == 400 { + var v ModelError + err = a.client.decode(&v, localVarBody, localVarHttpResponse.Header.Get("Content-Type")) + if err != nil { + newErr.error = err.Error() + return localVarReturnValue, localVarHttpResponse, newErr + } + newErr.model = v + return localVarReturnValue, localVarHttpResponse, newErr + } + if localVarHttpResponse.StatusCode == 404 { + var v ModelError + err = a.client.decode(&v, localVarBody, localVarHttpResponse.Header.Get("Content-Type")) + if err != nil { + newErr.error = err.Error() + return localVarReturnValue, localVarHttpResponse, newErr + } + newErr.model = v + return localVarReturnValue, localVarHttpResponse, newErr + } + if localVarHttpResponse.StatusCode == 429 { + var v RateLimited + err = a.client.decode(&v, localVarBody, localVarHttpResponse.Header.Get("Content-Type")) + if err != nil { + newErr.error = err.Error() + return localVarReturnValue, localVarHttpResponse, newErr + } + newErr.model = v + return localVarReturnValue, localVarHttpResponse, newErr + } + return localVarReturnValue, localVarHttpResponse, newErr + } + + return localVarReturnValue, localVarHttpResponse, nil +} + +/* +NfdApiService contractLock nfd +Lock/Unlock an NFD contract - if locked, the contract can never being modified until unlocked again by the owner. + - @param ctx context.Context - for authentication, logging, cancellation, deadlines, tracing, etc. Passed from http.Request or context.Background(). + - @param body + - @param name + +@return string +*/ +func (a *NfdApiService) NfdContractLock(ctx context.Context, body ContractLockRequestBody, name string) (string, *http.Response, error) { + var ( + localVarHttpMethod = strings.ToUpper("Post") + localVarPostBody interface{} + localVarFileName string + localVarFileBytes []byte + localVarReturnValue string + ) + + // create path and map variables + localVarPath := a.client.cfg.BasePath + "/nfd/contract/lock/{name}" + localVarPath = strings.Replace(localVarPath, "{"+"name"+"}", fmt.Sprintf("%v", name), -1) + + localVarHeaderParams := make(map[string]string) + localVarQueryParams := url.Values{} + localVarFormParams := url.Values{} + if strlen(name) < 1 { + return localVarReturnValue, nil, reportError("name must have at least 1 elements") + } + if strlen(name) > 120 { + return localVarReturnValue, nil, reportError("name must have less than 120 elements") + } + + // to determine the Content-Type header + localVarHttpContentTypes := []string{"application/json"} + + // set Content-Type header + localVarHttpContentType := selectHeaderContentType(localVarHttpContentTypes) + if localVarHttpContentType != "" { + localVarHeaderParams["Content-Type"] = localVarHttpContentType + } + + // to determine the Accept header + localVarHttpHeaderAccepts := []string{"application/json", "application/vnd.goa.error"} + + // set Accept header + localVarHttpHeaderAccept := selectHeaderAccept(localVarHttpHeaderAccepts) + if localVarHttpHeaderAccept != "" { + localVarHeaderParams["Accept"] = localVarHttpHeaderAccept + } + // body params + localVarPostBody = &body + r, err := a.client.prepareRequest(ctx, localVarPath, localVarHttpMethod, localVarPostBody, localVarHeaderParams, localVarQueryParams, localVarFormParams, localVarFileName, localVarFileBytes) + if err != nil { + return localVarReturnValue, nil, err + } + + localVarHttpResponse, err := a.client.callAPI(r) + if err != nil || localVarHttpResponse == nil { + return localVarReturnValue, localVarHttpResponse, err + } + + localVarBody, err := ioutil.ReadAll(localVarHttpResponse.Body) + localVarHttpResponse.Body.Close() + if err != nil { + return localVarReturnValue, localVarHttpResponse, err + } + + if localVarHttpResponse.StatusCode < 300 { + // If we succeed, return the data, otherwise pass on to decode error. + err = a.client.decode(&localVarReturnValue, localVarBody, localVarHttpResponse.Header.Get("Content-Type")) + if err == nil { + return localVarReturnValue, localVarHttpResponse, err + } + } + + if localVarHttpResponse.StatusCode >= 300 { + newErr := GenericSwaggerError{ + body: localVarBody, + error: localVarHttpResponse.Status, + } + if localVarHttpResponse.StatusCode == 200 { + var v string + err = a.client.decode(&v, localVarBody, localVarHttpResponse.Header.Get("Content-Type")) + if err != nil { + newErr.error = err.Error() + return localVarReturnValue, localVarHttpResponse, newErr + } + newErr.model = v + return localVarReturnValue, localVarHttpResponse, newErr + } + if localVarHttpResponse.StatusCode == 400 { + var v ModelError + err = a.client.decode(&v, localVarBody, localVarHttpResponse.Header.Get("Content-Type")) + if err != nil { + newErr.error = err.Error() + return localVarReturnValue, localVarHttpResponse, newErr + } + newErr.model = v + return localVarReturnValue, localVarHttpResponse, newErr + } + if localVarHttpResponse.StatusCode == 404 { + var v ModelError + err = a.client.decode(&v, localVarBody, localVarHttpResponse.Header.Get("Content-Type")) + if err != nil { + newErr.error = err.Error() + return localVarReturnValue, localVarHttpResponse, newErr + } + newErr.model = v + return localVarReturnValue, localVarHttpResponse, newErr + } + if localVarHttpResponse.StatusCode == 429 { + var v RateLimited + err = a.client.decode(&v, localVarBody, localVarHttpResponse.Header.Get("Content-Type")) + if err != nil { + newErr.error = err.Error() + return localVarReturnValue, localVarHttpResponse, newErr + } + newErr.model = v + return localVarReturnValue, localVarHttpResponse, newErr + } + return localVarReturnValue, localVarHttpResponse, newErr + } + + return localVarReturnValue, localVarHttpResponse, nil +} + +/* +NfdApiService contractUpgrade nfd +Request upgrade of the contract on an NFD + - @param ctx context.Context - for authentication, logging, cancellation, deadlines, tracing, etc. Passed from http.Request or context.Background(). + - @param body + - @param name + +@return string +*/ +func (a *NfdApiService) NfdContractUpgrade(ctx context.Context, body RescindOfferRequestBody, name string) (string, *http.Response, error) { + var ( + localVarHttpMethod = strings.ToUpper("Post") + localVarPostBody interface{} + localVarFileName string + localVarFileBytes []byte + localVarReturnValue string + ) + + // create path and map variables + localVarPath := a.client.cfg.BasePath + "/nfd/contract/upgrade/{name}" + localVarPath = strings.Replace(localVarPath, "{"+"name"+"}", fmt.Sprintf("%v", name), -1) + + localVarHeaderParams := make(map[string]string) + localVarQueryParams := url.Values{} + localVarFormParams := url.Values{} + if strlen(name) < 1 { + return localVarReturnValue, nil, reportError("name must have at least 1 elements") + } + if strlen(name) > 120 { + return localVarReturnValue, nil, reportError("name must have less than 120 elements") + } + + // to determine the Content-Type header + localVarHttpContentTypes := []string{"application/json"} + + // set Content-Type header + localVarHttpContentType := selectHeaderContentType(localVarHttpContentTypes) + if localVarHttpContentType != "" { + localVarHeaderParams["Content-Type"] = localVarHttpContentType + } + + // to determine the Accept header + localVarHttpHeaderAccepts := []string{"application/json", "application/vnd.goa.error"} + + // set Accept header + localVarHttpHeaderAccept := selectHeaderAccept(localVarHttpHeaderAccepts) + if localVarHttpHeaderAccept != "" { + localVarHeaderParams["Accept"] = localVarHttpHeaderAccept + } + // body params + localVarPostBody = &body + r, err := a.client.prepareRequest(ctx, localVarPath, localVarHttpMethod, localVarPostBody, localVarHeaderParams, localVarQueryParams, localVarFormParams, localVarFileName, localVarFileBytes) + if err != nil { + return localVarReturnValue, nil, err + } + + localVarHttpResponse, err := a.client.callAPI(r) + if err != nil || localVarHttpResponse == nil { + return localVarReturnValue, localVarHttpResponse, err + } + + localVarBody, err := ioutil.ReadAll(localVarHttpResponse.Body) + localVarHttpResponse.Body.Close() + if err != nil { + return localVarReturnValue, localVarHttpResponse, err + } + + if localVarHttpResponse.StatusCode < 300 { + // If we succeed, return the data, otherwise pass on to decode error. + err = a.client.decode(&localVarReturnValue, localVarBody, localVarHttpResponse.Header.Get("Content-Type")) + if err == nil { + return localVarReturnValue, localVarHttpResponse, err + } + } + + if localVarHttpResponse.StatusCode >= 300 { + newErr := GenericSwaggerError{ + body: localVarBody, + error: localVarHttpResponse.Status, + } + if localVarHttpResponse.StatusCode == 200 { + var v string + err = a.client.decode(&v, localVarBody, localVarHttpResponse.Header.Get("Content-Type")) + if err != nil { + newErr.error = err.Error() + return localVarReturnValue, localVarHttpResponse, newErr + } + newErr.model = v + return localVarReturnValue, localVarHttpResponse, newErr + } + if localVarHttpResponse.StatusCode == 400 { + var v ModelError + err = a.client.decode(&v, localVarBody, localVarHttpResponse.Header.Get("Content-Type")) + if err != nil { + newErr.error = err.Error() + return localVarReturnValue, localVarHttpResponse, newErr + } + newErr.model = v + return localVarReturnValue, localVarHttpResponse, newErr + } + if localVarHttpResponse.StatusCode == 404 { + var v ModelError + err = a.client.decode(&v, localVarBody, localVarHttpResponse.Header.Get("Content-Type")) + if err != nil { + newErr.error = err.Error() + return localVarReturnValue, localVarHttpResponse, newErr + } + newErr.model = v + return localVarReturnValue, localVarHttpResponse, newErr + } + if localVarHttpResponse.StatusCode == 429 { + var v RateLimited + err = a.client.decode(&v, localVarBody, localVarHttpResponse.Header.Get("Content-Type")) + if err != nil { + newErr.error = err.Error() + return localVarReturnValue, localVarHttpResponse, newErr + } + newErr.model = v + return localVarReturnValue, localVarHttpResponse, newErr + } + return localVarReturnValue, localVarHttpResponse, newErr + } + + return localVarReturnValue, localVarHttpResponse, nil +} + +/* +NfdApiService donationLeaders nfd +[DEPRECATED] Get top donors to a specific account + - @param ctx context.Context - for authentication, logging, cancellation, deadlines, tracing, etc. Passed from http.Request or context.Background(). + - @param address Donation address to get leaderboard for + +@return []Donation +*/ +func (a *NfdApiService) NfdDonationLeaders(ctx context.Context, address string) ([]Donation, *http.Response, error) { + var ( + localVarHttpMethod = strings.ToUpper("Get") + localVarPostBody interface{} + localVarFileName string + localVarFileBytes []byte + localVarReturnValue []Donation + ) + + // create path and map variables + localVarPath := a.client.cfg.BasePath + "/nfd/donations/leaders/{address}" + localVarPath = strings.Replace(localVarPath, "{"+"address"+"}", fmt.Sprintf("%v", address), -1) + + localVarHeaderParams := make(map[string]string) + localVarQueryParams := url.Values{} + localVarFormParams := url.Values{} + + // to determine the Content-Type header + localVarHttpContentTypes := []string{} + + // set Content-Type header + localVarHttpContentType := selectHeaderContentType(localVarHttpContentTypes) + if localVarHttpContentType != "" { + localVarHeaderParams["Content-Type"] = localVarHttpContentType + } + + // to determine the Accept header + localVarHttpHeaderAccepts := []string{"application/json", "application/vnd.goa.error"} + + // set Accept header + localVarHttpHeaderAccept := selectHeaderAccept(localVarHttpHeaderAccepts) + if localVarHttpHeaderAccept != "" { + localVarHeaderParams["Accept"] = localVarHttpHeaderAccept + } + r, err := a.client.prepareRequest(ctx, localVarPath, localVarHttpMethod, localVarPostBody, localVarHeaderParams, localVarQueryParams, localVarFormParams, localVarFileName, localVarFileBytes) + if err != nil { + return localVarReturnValue, nil, err + } + + localVarHttpResponse, err := a.client.callAPI(r) + if err != nil || localVarHttpResponse == nil { + return localVarReturnValue, localVarHttpResponse, err + } + + localVarBody, err := ioutil.ReadAll(localVarHttpResponse.Body) + localVarHttpResponse.Body.Close() + if err != nil { + return localVarReturnValue, localVarHttpResponse, err + } + + if localVarHttpResponse.StatusCode < 300 { + // If we succeed, return the data, otherwise pass on to decode error. + err = a.client.decode(&localVarReturnValue, localVarBody, localVarHttpResponse.Header.Get("Content-Type")) + if err == nil { + return localVarReturnValue, localVarHttpResponse, err + } + } + + if localVarHttpResponse.StatusCode >= 300 { + newErr := GenericSwaggerError{ + body: localVarBody, + error: localVarHttpResponse.Status, + } + if localVarHttpResponse.StatusCode == 200 { + var v []Donation + err = a.client.decode(&v, localVarBody, localVarHttpResponse.Header.Get("Content-Type")) + if err != nil { + newErr.error = err.Error() + return localVarReturnValue, localVarHttpResponse, newErr + } + newErr.model = v + return localVarReturnValue, localVarHttpResponse, newErr + } + if localVarHttpResponse.StatusCode == 400 { + var v ModelError + err = a.client.decode(&v, localVarBody, localVarHttpResponse.Header.Get("Content-Type")) + if err != nil { + newErr.error = err.Error() + return localVarReturnValue, localVarHttpResponse, newErr + } + newErr.model = v + return localVarReturnValue, localVarHttpResponse, newErr + } + if localVarHttpResponse.StatusCode == 404 { + var v ModelError + err = a.client.decode(&v, localVarBody, localVarHttpResponse.Header.Get("Content-Type")) + if err != nil { + newErr.error = err.Error() + return localVarReturnValue, localVarHttpResponse, newErr + } + newErr.model = v + return localVarReturnValue, localVarHttpResponse, newErr + } + if localVarHttpResponse.StatusCode == 429 { + var v RateLimited + err = a.client.decode(&v, localVarBody, localVarHttpResponse.Header.Get("Content-Type")) + if err != nil { + newErr.error = err.Error() + return localVarReturnValue, localVarHttpResponse, newErr + } + newErr.model = v + return localVarReturnValue, localVarHttpResponse, newErr + } + return localVarReturnValue, localVarHttpResponse, newErr + } + + return localVarReturnValue, localVarHttpResponse, nil +} + +/* +NfdApiService donationLeadersV2 nfd +Get top donors to a specific NFD Donation target + - @param ctx context.Context - for authentication, logging, cancellation, deadlines, tracing, etc. Passed from http.Request or context.Background(). + - @param name + +@return []Donation +*/ +func (a *NfdApiService) NfdDonationLeadersV2(ctx context.Context, name string) ([]Donation, *http.Response, error) { + var ( + localVarHttpMethod = strings.ToUpper("Get") + localVarPostBody interface{} + localVarFileName string + localVarFileBytes []byte + localVarReturnValue []Donation + ) + + // create path and map variables + localVarPath := a.client.cfg.BasePath + "/nfd/v2/donations/leaders/{name}" + localVarPath = strings.Replace(localVarPath, "{"+"name"+"}", fmt.Sprintf("%v", name), -1) + + localVarHeaderParams := make(map[string]string) + localVarQueryParams := url.Values{} + localVarFormParams := url.Values{} + if strlen(name) < 1 { + return localVarReturnValue, nil, reportError("name must have at least 1 elements") + } + if strlen(name) > 120 { + return localVarReturnValue, nil, reportError("name must have less than 120 elements") + } + + // to determine the Content-Type header + localVarHttpContentTypes := []string{} + + // set Content-Type header + localVarHttpContentType := selectHeaderContentType(localVarHttpContentTypes) + if localVarHttpContentType != "" { + localVarHeaderParams["Content-Type"] = localVarHttpContentType + } + + // to determine the Accept header + localVarHttpHeaderAccepts := []string{"application/json", "application/vnd.goa.error"} + + // set Accept header + localVarHttpHeaderAccept := selectHeaderAccept(localVarHttpHeaderAccepts) + if localVarHttpHeaderAccept != "" { + localVarHeaderParams["Accept"] = localVarHttpHeaderAccept + } + r, err := a.client.prepareRequest(ctx, localVarPath, localVarHttpMethod, localVarPostBody, localVarHeaderParams, localVarQueryParams, localVarFormParams, localVarFileName, localVarFileBytes) + if err != nil { + return localVarReturnValue, nil, err + } + + localVarHttpResponse, err := a.client.callAPI(r) + if err != nil || localVarHttpResponse == nil { + return localVarReturnValue, localVarHttpResponse, err + } + + localVarBody, err := ioutil.ReadAll(localVarHttpResponse.Body) + localVarHttpResponse.Body.Close() + if err != nil { + return localVarReturnValue, localVarHttpResponse, err + } + + if localVarHttpResponse.StatusCode < 300 { + // If we succeed, return the data, otherwise pass on to decode error. + err = a.client.decode(&localVarReturnValue, localVarBody, localVarHttpResponse.Header.Get("Content-Type")) + if err == nil { + return localVarReturnValue, localVarHttpResponse, err + } + } + + if localVarHttpResponse.StatusCode >= 300 { + newErr := GenericSwaggerError{ + body: localVarBody, + error: localVarHttpResponse.Status, + } + if localVarHttpResponse.StatusCode == 200 { + var v []Donation + err = a.client.decode(&v, localVarBody, localVarHttpResponse.Header.Get("Content-Type")) + if err != nil { + newErr.error = err.Error() + return localVarReturnValue, localVarHttpResponse, newErr + } + newErr.model = v + return localVarReturnValue, localVarHttpResponse, newErr + } + if localVarHttpResponse.StatusCode == 400 { + var v ModelError + err = a.client.decode(&v, localVarBody, localVarHttpResponse.Header.Get("Content-Type")) + if err != nil { + newErr.error = err.Error() + return localVarReturnValue, localVarHttpResponse, newErr + } + newErr.model = v + return localVarReturnValue, localVarHttpResponse, newErr + } + if localVarHttpResponse.StatusCode == 404 { + var v ModelError + err = a.client.decode(&v, localVarBody, localVarHttpResponse.Header.Get("Content-Type")) + if err != nil { + newErr.error = err.Error() + return localVarReturnValue, localVarHttpResponse, newErr + } + newErr.model = v + return localVarReturnValue, localVarHttpResponse, newErr + } + if localVarHttpResponse.StatusCode == 429 { + var v RateLimited + err = a.client.decode(&v, localVarBody, localVarHttpResponse.Header.Get("Content-Type")) + if err != nil { + newErr.error = err.Error() + return localVarReturnValue, localVarHttpResponse, newErr + } + newErr.model = v + return localVarReturnValue, localVarHttpResponse, newErr + } + return localVarReturnValue, localVarHttpResponse, newErr + } + + return localVarReturnValue, localVarHttpResponse, nil +} + +/* +NfdApiService donationList nfd +[DEPRECATED] Fetch list of tracked Donation 'targets'. Getting name/address for each. + - @param ctx context.Context - for authentication, logging, cancellation, deadlines, tracing, etc. Passed from http.Request or context.Background(). + +@return []DonationAccount +*/ +func (a *NfdApiService) NfdDonationList(ctx context.Context) ([]DonationAccount, *http.Response, error) { + var ( + localVarHttpMethod = strings.ToUpper("Get") + localVarPostBody interface{} + localVarFileName string + localVarFileBytes []byte + localVarReturnValue []DonationAccount + ) + + // create path and map variables + localVarPath := a.client.cfg.BasePath + "/nfd/donations/list" + + localVarHeaderParams := make(map[string]string) + localVarQueryParams := url.Values{} + localVarFormParams := url.Values{} + + // to determine the Content-Type header + localVarHttpContentTypes := []string{} + + // set Content-Type header + localVarHttpContentType := selectHeaderContentType(localVarHttpContentTypes) + if localVarHttpContentType != "" { + localVarHeaderParams["Content-Type"] = localVarHttpContentType + } + + // to determine the Accept header + localVarHttpHeaderAccepts := []string{"application/json", "application/vnd.goa.error"} + + // set Accept header + localVarHttpHeaderAccept := selectHeaderAccept(localVarHttpHeaderAccepts) + if localVarHttpHeaderAccept != "" { + localVarHeaderParams["Accept"] = localVarHttpHeaderAccept + } + r, err := a.client.prepareRequest(ctx, localVarPath, localVarHttpMethod, localVarPostBody, localVarHeaderParams, localVarQueryParams, localVarFormParams, localVarFileName, localVarFileBytes) + if err != nil { + return localVarReturnValue, nil, err + } + + localVarHttpResponse, err := a.client.callAPI(r) + if err != nil || localVarHttpResponse == nil { + return localVarReturnValue, localVarHttpResponse, err + } + + localVarBody, err := ioutil.ReadAll(localVarHttpResponse.Body) + localVarHttpResponse.Body.Close() + if err != nil { + return localVarReturnValue, localVarHttpResponse, err + } + + if localVarHttpResponse.StatusCode < 300 { + // If we succeed, return the data, otherwise pass on to decode error. + err = a.client.decode(&localVarReturnValue, localVarBody, localVarHttpResponse.Header.Get("Content-Type")) + if err == nil { + return localVarReturnValue, localVarHttpResponse, err + } + } + + if localVarHttpResponse.StatusCode >= 300 { + newErr := GenericSwaggerError{ + body: localVarBody, + error: localVarHttpResponse.Status, + } + if localVarHttpResponse.StatusCode == 200 { + var v []DonationAccount + err = a.client.decode(&v, localVarBody, localVarHttpResponse.Header.Get("Content-Type")) + if err != nil { + newErr.error = err.Error() + return localVarReturnValue, localVarHttpResponse, newErr + } + newErr.model = v + return localVarReturnValue, localVarHttpResponse, newErr + } + if localVarHttpResponse.StatusCode == 400 { + var v ModelError + err = a.client.decode(&v, localVarBody, localVarHttpResponse.Header.Get("Content-Type")) + if err != nil { + newErr.error = err.Error() + return localVarReturnValue, localVarHttpResponse, newErr + } + newErr.model = v + return localVarReturnValue, localVarHttpResponse, newErr + } + if localVarHttpResponse.StatusCode == 404 { + var v ModelError + err = a.client.decode(&v, localVarBody, localVarHttpResponse.Header.Get("Content-Type")) + if err != nil { + newErr.error = err.Error() + return localVarReturnValue, localVarHttpResponse, newErr + } + newErr.model = v + return localVarReturnValue, localVarHttpResponse, newErr + } + if localVarHttpResponse.StatusCode == 429 { + var v RateLimited + err = a.client.decode(&v, localVarBody, localVarHttpResponse.Header.Get("Content-Type")) + if err != nil { + newErr.error = err.Error() + return localVarReturnValue, localVarHttpResponse, newErr + } + newErr.model = v + return localVarReturnValue, localVarHttpResponse, newErr + } + return localVarReturnValue, localVarHttpResponse, newErr + } + + return localVarReturnValue, localVarHttpResponse, nil +} + +/* +NfdApiService donationListV2 nfd +Fetch list of tracked Donation NFD 'targets'. + - @param ctx context.Context - for authentication, logging, cancellation, deadlines, tracing, etc. Passed from http.Request or context.Background(). + +@return []NfdRecordResponseFull +*/ +func (a *NfdApiService) NfdDonationListV2(ctx context.Context) ([]NfdRecordResponseFull, *http.Response, error) { + var ( + localVarHttpMethod = strings.ToUpper("Get") + localVarPostBody interface{} + localVarFileName string + localVarFileBytes []byte + localVarReturnValue []NfdRecordResponseFull + ) + + // create path and map variables + localVarPath := a.client.cfg.BasePath + "/nfd/v2/donations/list" + + localVarHeaderParams := make(map[string]string) + localVarQueryParams := url.Values{} + localVarFormParams := url.Values{} + + // to determine the Content-Type header + localVarHttpContentTypes := []string{} + + // set Content-Type header + localVarHttpContentType := selectHeaderContentType(localVarHttpContentTypes) + if localVarHttpContentType != "" { + localVarHeaderParams["Content-Type"] = localVarHttpContentType + } + + // to determine the Accept header + localVarHttpHeaderAccepts := []string{"application/json", "application/vnd.goa.error"} + + // set Accept header + localVarHttpHeaderAccept := selectHeaderAccept(localVarHttpHeaderAccepts) + if localVarHttpHeaderAccept != "" { + localVarHeaderParams["Accept"] = localVarHttpHeaderAccept + } + r, err := a.client.prepareRequest(ctx, localVarPath, localVarHttpMethod, localVarPostBody, localVarHeaderParams, localVarQueryParams, localVarFormParams, localVarFileName, localVarFileBytes) + if err != nil { + return localVarReturnValue, nil, err + } + + localVarHttpResponse, err := a.client.callAPI(r) + if err != nil || localVarHttpResponse == nil { + return localVarReturnValue, localVarHttpResponse, err + } + + localVarBody, err := ioutil.ReadAll(localVarHttpResponse.Body) + localVarHttpResponse.Body.Close() + if err != nil { + return localVarReturnValue, localVarHttpResponse, err + } + + if localVarHttpResponse.StatusCode < 300 { + // If we succeed, return the data, otherwise pass on to decode error. + err = a.client.decode(&localVarReturnValue, localVarBody, localVarHttpResponse.Header.Get("Content-Type")) + if err == nil { + return localVarReturnValue, localVarHttpResponse, err + } + } + + if localVarHttpResponse.StatusCode >= 300 { + newErr := GenericSwaggerError{ + body: localVarBody, + error: localVarHttpResponse.Status, + } + if localVarHttpResponse.StatusCode == 200 { + var v []NfdRecordResponseFull + err = a.client.decode(&v, localVarBody, localVarHttpResponse.Header.Get("Content-Type")) + if err != nil { + newErr.error = err.Error() + return localVarReturnValue, localVarHttpResponse, newErr + } + newErr.model = v + return localVarReturnValue, localVarHttpResponse, newErr + } + if localVarHttpResponse.StatusCode == 400 { + var v ModelError + err = a.client.decode(&v, localVarBody, localVarHttpResponse.Header.Get("Content-Type")) + if err != nil { + newErr.error = err.Error() + return localVarReturnValue, localVarHttpResponse, newErr + } + newErr.model = v + return localVarReturnValue, localVarHttpResponse, newErr + } + if localVarHttpResponse.StatusCode == 404 { + var v ModelError + err = a.client.decode(&v, localVarBody, localVarHttpResponse.Header.Get("Content-Type")) + if err != nil { + newErr.error = err.Error() + return localVarReturnValue, localVarHttpResponse, newErr + } + newErr.model = v + return localVarReturnValue, localVarHttpResponse, newErr + } + if localVarHttpResponse.StatusCode == 429 { + var v RateLimited + err = a.client.decode(&v, localVarBody, localVarHttpResponse.Header.Get("Content-Type")) + if err != nil { + newErr.error = err.Error() + return localVarReturnValue, localVarHttpResponse, newErr + } + newErr.model = v + return localVarReturnValue, localVarHttpResponse, newErr + } + return localVarReturnValue, localVarHttpResponse, newErr + } + + return localVarReturnValue, localVarHttpResponse, nil +} + +/* +NfdApiService donations nfd +Fetch donation activity for an NFD, totalling amounts sent 'to' designated donation accounts + - @param ctx context.Context - for authentication, logging, cancellation, deadlines, tracing, etc. Passed from http.Request or context.Background(). + - @param name + +@return []Donation +*/ +func (a *NfdApiService) NfdDonations(ctx context.Context, name string) ([]Donation, *http.Response, error) { + var ( + localVarHttpMethod = strings.ToUpper("Get") + localVarPostBody interface{} + localVarFileName string + localVarFileBytes []byte + localVarReturnValue []Donation + ) + + // create path and map variables + localVarPath := a.client.cfg.BasePath + "/nfd/donations/{name}" + localVarPath = strings.Replace(localVarPath, "{"+"name"+"}", fmt.Sprintf("%v", name), -1) + + localVarHeaderParams := make(map[string]string) + localVarQueryParams := url.Values{} + localVarFormParams := url.Values{} + if strlen(name) < 1 { + return localVarReturnValue, nil, reportError("name must have at least 1 elements") + } + if strlen(name) > 120 { + return localVarReturnValue, nil, reportError("name must have less than 120 elements") + } + + // to determine the Content-Type header + localVarHttpContentTypes := []string{} + + // set Content-Type header + localVarHttpContentType := selectHeaderContentType(localVarHttpContentTypes) + if localVarHttpContentType != "" { + localVarHeaderParams["Content-Type"] = localVarHttpContentType + } + + // to determine the Accept header + localVarHttpHeaderAccepts := []string{"application/json", "application/vnd.goa.error"} + + // set Accept header + localVarHttpHeaderAccept := selectHeaderAccept(localVarHttpHeaderAccepts) + if localVarHttpHeaderAccept != "" { + localVarHeaderParams["Accept"] = localVarHttpHeaderAccept + } + r, err := a.client.prepareRequest(ctx, localVarPath, localVarHttpMethod, localVarPostBody, localVarHeaderParams, localVarQueryParams, localVarFormParams, localVarFileName, localVarFileBytes) + if err != nil { + return localVarReturnValue, nil, err + } + + localVarHttpResponse, err := a.client.callAPI(r) + if err != nil || localVarHttpResponse == nil { + return localVarReturnValue, localVarHttpResponse, err + } + + localVarBody, err := ioutil.ReadAll(localVarHttpResponse.Body) + localVarHttpResponse.Body.Close() + if err != nil { + return localVarReturnValue, localVarHttpResponse, err + } + + if localVarHttpResponse.StatusCode < 300 { + // If we succeed, return the data, otherwise pass on to decode error. + err = a.client.decode(&localVarReturnValue, localVarBody, localVarHttpResponse.Header.Get("Content-Type")) + if err == nil { + return localVarReturnValue, localVarHttpResponse, err + } + } + + if localVarHttpResponse.StatusCode >= 300 { + newErr := GenericSwaggerError{ + body: localVarBody, + error: localVarHttpResponse.Status, + } + if localVarHttpResponse.StatusCode == 200 { + var v []Donation + err = a.client.decode(&v, localVarBody, localVarHttpResponse.Header.Get("Content-Type")) + if err != nil { + newErr.error = err.Error() + return localVarReturnValue, localVarHttpResponse, newErr + } + newErr.model = v + return localVarReturnValue, localVarHttpResponse, newErr + } + if localVarHttpResponse.StatusCode == 400 { + var v ModelError + err = a.client.decode(&v, localVarBody, localVarHttpResponse.Header.Get("Content-Type")) + if err != nil { + newErr.error = err.Error() + return localVarReturnValue, localVarHttpResponse, newErr + } + newErr.model = v + return localVarReturnValue, localVarHttpResponse, newErr + } + if localVarHttpResponse.StatusCode == 404 { + var v ModelError + err = a.client.decode(&v, localVarBody, localVarHttpResponse.Header.Get("Content-Type")) + if err != nil { + newErr.error = err.Error() + return localVarReturnValue, localVarHttpResponse, newErr + } + newErr.model = v + return localVarReturnValue, localVarHttpResponse, newErr + } + if localVarHttpResponse.StatusCode == 429 { + var v RateLimited + err = a.client.decode(&v, localVarBody, localVarHttpResponse.Header.Get("Content-Type")) + if err != nil { + newErr.error = err.Error() + return localVarReturnValue, localVarHttpResponse, newErr + } + newErr.model = v + return localVarReturnValue, localVarHttpResponse, newErr + } + return localVarReturnValue, localVarHttpResponse, newErr + } + + return localVarReturnValue, localVarHttpResponse, nil +} + +/* +NfdApiService escrowOffer nfd +Make escrowed bid for a new 'floor' price of an ongoing auction. Higher bidder refunds you, if price drops to your escrow, you win auction with it being reserved for you + - @param ctx context.Context - for authentication, logging, cancellation, deadlines, tracing, etc. Passed from http.Request or context.Background(). + - @param body + - @param name + +@return string +*/ +func (a *NfdApiService) NfdEscrowOffer(ctx context.Context, body EscrowOfferRequestBody, name string) (string, *http.Response, error) { + var ( + localVarHttpMethod = strings.ToUpper("Post") + localVarPostBody interface{} + localVarFileName string + localVarFileBytes []byte + localVarReturnValue string + ) + + // create path and map variables + localVarPath := a.client.cfg.BasePath + "/nfd/escrowOffer/{name}" + localVarPath = strings.Replace(localVarPath, "{"+"name"+"}", fmt.Sprintf("%v", name), -1) + + localVarHeaderParams := make(map[string]string) + localVarQueryParams := url.Values{} + localVarFormParams := url.Values{} + if strlen(name) < 1 { + return localVarReturnValue, nil, reportError("name must have at least 1 elements") + } + if strlen(name) > 120 { + return localVarReturnValue, nil, reportError("name must have less than 120 elements") + } + + // to determine the Content-Type header + localVarHttpContentTypes := []string{"application/json"} + + // set Content-Type header + localVarHttpContentType := selectHeaderContentType(localVarHttpContentTypes) + if localVarHttpContentType != "" { + localVarHeaderParams["Content-Type"] = localVarHttpContentType + } + + // to determine the Accept header + localVarHttpHeaderAccepts := []string{"application/json", "application/vnd.goa.error"} + + // set Accept header + localVarHttpHeaderAccept := selectHeaderAccept(localVarHttpHeaderAccepts) + if localVarHttpHeaderAccept != "" { + localVarHeaderParams["Accept"] = localVarHttpHeaderAccept + } + // body params + localVarPostBody = &body + r, err := a.client.prepareRequest(ctx, localVarPath, localVarHttpMethod, localVarPostBody, localVarHeaderParams, localVarQueryParams, localVarFormParams, localVarFileName, localVarFileBytes) + if err != nil { + return localVarReturnValue, nil, err + } + + localVarHttpResponse, err := a.client.callAPI(r) + if err != nil || localVarHttpResponse == nil { + return localVarReturnValue, localVarHttpResponse, err + } + + localVarBody, err := ioutil.ReadAll(localVarHttpResponse.Body) + localVarHttpResponse.Body.Close() + if err != nil { + return localVarReturnValue, localVarHttpResponse, err + } + + if localVarHttpResponse.StatusCode < 300 { + // If we succeed, return the data, otherwise pass on to decode error. + err = a.client.decode(&localVarReturnValue, localVarBody, localVarHttpResponse.Header.Get("Content-Type")) + if err == nil { + return localVarReturnValue, localVarHttpResponse, err + } + } + + if localVarHttpResponse.StatusCode >= 300 { + newErr := GenericSwaggerError{ + body: localVarBody, + error: localVarHttpResponse.Status, + } + if localVarHttpResponse.StatusCode == 200 { + var v string + err = a.client.decode(&v, localVarBody, localVarHttpResponse.Header.Get("Content-Type")) + if err != nil { + newErr.error = err.Error() + return localVarReturnValue, localVarHttpResponse, newErr + } + newErr.model = v + return localVarReturnValue, localVarHttpResponse, newErr + } + if localVarHttpResponse.StatusCode == 404 { + var v ModelError + err = a.client.decode(&v, localVarBody, localVarHttpResponse.Header.Get("Content-Type")) + if err != nil { + newErr.error = err.Error() + return localVarReturnValue, localVarHttpResponse, newErr + } + newErr.model = v + return localVarReturnValue, localVarHttpResponse, newErr + } + if localVarHttpResponse.StatusCode == 429 { + var v RateLimited + err = a.client.decode(&v, localVarBody, localVarHttpResponse.Header.Get("Content-Type")) + if err != nil { + newErr.error = err.Error() + return localVarReturnValue, localVarHttpResponse, newErr + } + newErr.model = v + return localVarReturnValue, localVarHttpResponse, newErr + } + return localVarReturnValue, localVarHttpResponse, newErr + } + + return localVarReturnValue, localVarHttpResponse, nil +} + +/* +NfdApiService Reverse Address lookup with results returned per address +Get the primary NFD for an address. Must be verified address, or if allowUnverified is set, it may match against an unverified address + * @param ctx context.Context - for authentication, logging, cancellation, deadlines, tracing, etc. Passed from http.Request or context.Background(). + * @param address one or more addresses (algo or otherwise) to look up, maximum of 20 can be defined. Specify the same query parameter multiple times for each address, ie: address=xxx&address=yyy&address=zzz + * @param optional nil or *NfdApiNfdGetLookupOpts - Optional Parameters: + * @param "View" (optional.String) - View of data to return, tiny (name, owner, caAlgo, unverifiedCaAlgo only [default]), thumbnail (tiny + avatar), brief, or full + * @param "AllowUnverified" (optional.Bool) - Whether to allow unverified addresses to match (and only if its only match). Defaults to false + * @param "IfNoneMatch" (optional.String) - etag +@return map[string]NfdRecordinaddress +*/ + +type NfdApiNfdGetLookupOpts struct { + View optional.String + AllowUnverified optional.Bool + IfNoneMatch optional.String +} + +func (a *NfdApiService) NfdGetLookup(ctx context.Context, address []string, localVarOptionals *NfdApiNfdGetLookupOpts) (map[string]NfdRecordinaddress, *http.Response, error) { + var ( + localVarHttpMethod = strings.ToUpper("Get") + localVarPostBody interface{} + localVarFileName string + localVarFileBytes []byte + localVarReturnValue map[string]NfdRecordinaddress + ) + + // create path and map variables + localVarPath := a.client.cfg.BasePath + "/nfd/lookup" + + localVarHeaderParams := make(map[string]string) + localVarQueryParams := url.Values{} + localVarFormParams := url.Values{} + if len(address) < 1 { + return localVarReturnValue, nil, reportError("address must have at least 1 elements") + } + if len(address) > 20 { + return localVarReturnValue, nil, reportError("address must have less than 20 elements") + } + + localVarQueryParams.Add("address", parameterToString(address, "multi")) + if localVarOptionals != nil && localVarOptionals.View.IsSet() { + localVarQueryParams.Add("view", parameterToString(localVarOptionals.View.Value(), "")) + } + if localVarOptionals != nil && localVarOptionals.AllowUnverified.IsSet() { + localVarQueryParams.Add("allowUnverified", parameterToString(localVarOptionals.AllowUnverified.Value(), "")) + } + // to determine the Content-Type header + localVarHttpContentTypes := []string{} + + // set Content-Type header + localVarHttpContentType := selectHeaderContentType(localVarHttpContentTypes) + if localVarHttpContentType != "" { + localVarHeaderParams["Content-Type"] = localVarHttpContentType + } + + // to determine the Accept header + localVarHttpHeaderAccepts := []string{"application/json", "application/vnd.goa.error"} + + // set Accept header + localVarHttpHeaderAccept := selectHeaderAccept(localVarHttpHeaderAccepts) + if localVarHttpHeaderAccept != "" { + localVarHeaderParams["Accept"] = localVarHttpHeaderAccept + } + if localVarOptionals != nil && localVarOptionals.IfNoneMatch.IsSet() { + localVarHeaderParams["if-none-match"] = parameterToString(localVarOptionals.IfNoneMatch.Value(), "") + } + r, err := a.client.prepareRequest(ctx, localVarPath, localVarHttpMethod, localVarPostBody, localVarHeaderParams, localVarQueryParams, localVarFormParams, localVarFileName, localVarFileBytes) + if err != nil { + return localVarReturnValue, nil, err + } + + localVarHttpResponse, err := a.client.callAPI(r) + if err != nil || localVarHttpResponse == nil { + return localVarReturnValue, localVarHttpResponse, err + } + + localVarBody, err := ioutil.ReadAll(localVarHttpResponse.Body) + localVarHttpResponse.Body.Close() + if err != nil { + return localVarReturnValue, localVarHttpResponse, err + } + + if localVarHttpResponse.StatusCode < 300 { + // If we succeed, return the data, otherwise pass on to decode error. + err = a.client.decode(&localVarReturnValue, localVarBody, localVarHttpResponse.Header.Get("Content-Type")) + if err == nil { + return localVarReturnValue, localVarHttpResponse, err + } + } + + if localVarHttpResponse.StatusCode >= 300 { + newErr := GenericSwaggerError{ + body: localVarBody, + error: localVarHttpResponse.Status, + } + if localVarHttpResponse.StatusCode == 200 { + var v map[string]NfdRecordinaddress + err = a.client.decode(&v, localVarBody, localVarHttpResponse.Header.Get("Content-Type")) + if err != nil { + newErr.error = err.Error() + return localVarReturnValue, localVarHttpResponse, newErr + } + newErr.model = v + return localVarReturnValue, localVarHttpResponse, newErr + } + if localVarHttpResponse.StatusCode == 429 { + var v RateLimited + err = a.client.decode(&v, localVarBody, localVarHttpResponse.Header.Get("Content-Type")) + if err != nil { + newErr.error = err.Error() + return localVarReturnValue, localVarHttpResponse, newErr + } + newErr.model = v + return localVarReturnValue, localVarHttpResponse, newErr + } + return localVarReturnValue, localVarHttpResponse, newErr + } + + return localVarReturnValue, localVarHttpResponse, nil +} + +/* +NfdApiService Get a specific NFD by name or by its application id +Get a specific NFD by name or by its application id + * @param ctx context.Context - for authentication, logging, cancellation, deadlines, tracing, etc. Passed from http.Request or context.Background(). + * @param nameOrID + * @param optional nil or *NfdApiNfdGetNFDOpts - Optional Parameters: + * @param "View" (optional.String) - View of data to return, tiny, brief (default), or full + * @param "Poll" (optional.Bool) - Use if polling waiting for state change - causes notFound to return as 204 instead of 404. Should only be used when waiting for an NFD to transition from not-existing to being reserved for user to claim + * @param "Nocache" (optional.Bool) - Set to true to return a never-cached result. Use sparingly and only during certain 'NFD already exists' UX state transitions. + * @param "IfNoneMatch" (optional.String) - etag +@return NfdRecord +*/ + +type NfdApiNfdGetNFDOpts struct { + View optional.String + Poll optional.Bool + Nocache optional.Bool + IfNoneMatch optional.String +} + +func (a *NfdApiService) NfdGetNFD(ctx context.Context, nameOrID string, localVarOptionals *NfdApiNfdGetNFDOpts) (NfdRecord, *http.Response, error) { + var ( + localVarHttpMethod = strings.ToUpper("Get") + localVarPostBody interface{} + localVarFileName string + localVarFileBytes []byte + localVarReturnValue NfdRecord + ) + + // create path and map variables + localVarPath := a.client.cfg.BasePath + "/nfd/{nameOrID}" + localVarPath = strings.Replace(localVarPath, "{"+"nameOrID"+"}", fmt.Sprintf("%v", nameOrID), -1) + + localVarHeaderParams := make(map[string]string) + localVarQueryParams := url.Values{} + localVarFormParams := url.Values{} + if strlen(nameOrID) < 1 { + return localVarReturnValue, nil, reportError("nameOrID must have at least 1 elements") + } + if strlen(nameOrID) > 120 { + return localVarReturnValue, nil, reportError("nameOrID must have less than 120 elements") + } + + if localVarOptionals != nil && localVarOptionals.View.IsSet() { + localVarQueryParams.Add("view", parameterToString(localVarOptionals.View.Value(), "")) + } + if localVarOptionals != nil && localVarOptionals.Poll.IsSet() { + localVarQueryParams.Add("poll", parameterToString(localVarOptionals.Poll.Value(), "")) + } + if localVarOptionals != nil && localVarOptionals.Nocache.IsSet() { + localVarQueryParams.Add("nocache", parameterToString(localVarOptionals.Nocache.Value(), "")) + } + // to determine the Content-Type header + localVarHttpContentTypes := []string{} + + // set Content-Type header + localVarHttpContentType := selectHeaderContentType(localVarHttpContentTypes) + if localVarHttpContentType != "" { + localVarHeaderParams["Content-Type"] = localVarHttpContentType + } + + // to determine the Accept header + localVarHttpHeaderAccepts := []string{"application/json", "application/vnd.goa.error"} + + // set Accept header + localVarHttpHeaderAccept := selectHeaderAccept(localVarHttpHeaderAccepts) + if localVarHttpHeaderAccept != "" { + localVarHeaderParams["Accept"] = localVarHttpHeaderAccept + } + if localVarOptionals != nil && localVarOptionals.IfNoneMatch.IsSet() { + localVarHeaderParams["if-none-match"] = parameterToString(localVarOptionals.IfNoneMatch.Value(), "") + } + r, err := a.client.prepareRequest(ctx, localVarPath, localVarHttpMethod, localVarPostBody, localVarHeaderParams, localVarQueryParams, localVarFormParams, localVarFileName, localVarFileBytes) + if err != nil { + return localVarReturnValue, nil, err + } + + localVarHttpResponse, err := a.client.callAPI(r) + if err != nil || localVarHttpResponse == nil { + return localVarReturnValue, localVarHttpResponse, err + } + + localVarBody, err := ioutil.ReadAll(localVarHttpResponse.Body) + localVarHttpResponse.Body.Close() + if err != nil { + return localVarReturnValue, localVarHttpResponse, err + } + + if localVarHttpResponse.StatusCode < 300 { + // If we succeed, return the data, otherwise pass on to decode error. + err = a.client.decode(&localVarReturnValue, localVarBody, localVarHttpResponse.Header.Get("Content-Type")) + if err == nil { + return localVarReturnValue, localVarHttpResponse, err + } + } + + if localVarHttpResponse.StatusCode >= 300 { + newErr := GenericSwaggerError{ + body: localVarBody, + error: localVarHttpResponse.Status, + } + if localVarHttpResponse.StatusCode == 200 { + var v NfdRecord + err = a.client.decode(&v, localVarBody, localVarHttpResponse.Header.Get("Content-Type")) + if err != nil { + newErr.error = err.Error() + return localVarReturnValue, localVarHttpResponse, newErr + } + newErr.model = v + return localVarReturnValue, localVarHttpResponse, newErr + } + if localVarHttpResponse.StatusCode == 400 { + var v ModelError + err = a.client.decode(&v, localVarBody, localVarHttpResponse.Header.Get("Content-Type")) + if err != nil { + newErr.error = err.Error() + return localVarReturnValue, localVarHttpResponse, newErr + } + newErr.model = v + return localVarReturnValue, localVarHttpResponse, newErr + } + if localVarHttpResponse.StatusCode == 404 { + var v ModelError + err = a.client.decode(&v, localVarBody, localVarHttpResponse.Header.Get("Content-Type")) + if err != nil { + newErr.error = err.Error() + return localVarReturnValue, localVarHttpResponse, newErr + } + newErr.model = v + return localVarReturnValue, localVarHttpResponse, newErr + } + if localVarHttpResponse.StatusCode == 429 { + var v RateLimited + err = a.client.decode(&v, localVarBody, localVarHttpResponse.Header.Get("Content-Type")) + if err != nil { + newErr.error = err.Error() + return localVarReturnValue, localVarHttpResponse, newErr + } + newErr.model = v + return localVarReturnValue, localVarHttpResponse, newErr + } + return localVarReturnValue, localVarHttpResponse, newErr + } + + return localVarReturnValue, localVarHttpResponse, nil +} + +/* +NfdApiService Reverse Address lookup with results returned per address +Get all NFDs which have been explicitly linked to one or more verified [or unverified] Algorand address(es). Unverified addresses will match but return as unverifiedCaAlgo array. These should be treated specially and not have the same trust level as verified addresses as they can be falsely attributed. The caAlgo array is what should be trusted for things like NFT creation addresses. For reverse lookups returning multiple NFDs, the first result should be used. + * @param ctx context.Context - for authentication, logging, cancellation, deadlines, tracing, etc. Passed from http.Request or context.Background(). + * @param address one or more addresses (algo or otherwise) to look up, maximum of 20 can be defined. Specify the same query parameter multiple times for each address, ie: address=xxx&address=yyy&address=zzz + * @param optional nil or *NfdApiNfdGetNFDsForAddressesV2Opts - Optional Parameters: + * @param "Limit" (optional.Int64) - Limit the total number of NFDs returned - automatically changed to at least be 1 per address + * @param "View" (optional.String) - View of data to return, tiny (name, owner, caAlgo, unverifiedCaAlgo only [default]), thumbnail (tiny + avatar), brief, or full + * @param "IfNoneMatch" (optional.String) - etag +@return map[string][]NfdRecordinaddress +*/ + +type NfdApiNfdGetNFDsForAddressesV2Opts struct { + Limit optional.Int64 + View optional.String + IfNoneMatch optional.String +} + +func (a *NfdApiService) NfdGetNFDsForAddressesV2(ctx context.Context, address []string, localVarOptionals *NfdApiNfdGetNFDsForAddressesV2Opts) (map[string][]NfdRecordinaddress, *http.Response, error) { + var ( + localVarHttpMethod = strings.ToUpper("Get") + localVarPostBody interface{} + localVarFileName string + localVarFileBytes []byte + localVarReturnValue map[string][]NfdRecordinaddress + ) + + // create path and map variables + localVarPath := a.client.cfg.BasePath + "/nfd/v2/address" + + localVarHeaderParams := make(map[string]string) + localVarQueryParams := url.Values{} + localVarFormParams := url.Values{} + if len(address) < 1 { + return localVarReturnValue, nil, reportError("address must have at least 1 elements") + } + if len(address) > 20 { + return localVarReturnValue, nil, reportError("address must have less than 20 elements") + } + + localVarQueryParams.Add("address", parameterToString(address, "multi")) + if localVarOptionals != nil && localVarOptionals.Limit.IsSet() { + localVarQueryParams.Add("limit", parameterToString(localVarOptionals.Limit.Value(), "")) + } + if localVarOptionals != nil && localVarOptionals.View.IsSet() { + localVarQueryParams.Add("view", parameterToString(localVarOptionals.View.Value(), "")) + } + // to determine the Content-Type header + localVarHttpContentTypes := []string{} + + // set Content-Type header + localVarHttpContentType := selectHeaderContentType(localVarHttpContentTypes) + if localVarHttpContentType != "" { + localVarHeaderParams["Content-Type"] = localVarHttpContentType + } + + // to determine the Accept header + localVarHttpHeaderAccepts := []string{"application/json", "application/vnd.goa.error"} + + // set Accept header + localVarHttpHeaderAccept := selectHeaderAccept(localVarHttpHeaderAccepts) + if localVarHttpHeaderAccept != "" { + localVarHeaderParams["Accept"] = localVarHttpHeaderAccept + } + if localVarOptionals != nil && localVarOptionals.IfNoneMatch.IsSet() { + localVarHeaderParams["if-none-match"] = parameterToString(localVarOptionals.IfNoneMatch.Value(), "") + } + r, err := a.client.prepareRequest(ctx, localVarPath, localVarHttpMethod, localVarPostBody, localVarHeaderParams, localVarQueryParams, localVarFormParams, localVarFileName, localVarFileBytes) + if err != nil { + return localVarReturnValue, nil, err + } + + localVarHttpResponse, err := a.client.callAPI(r) + if err != nil || localVarHttpResponse == nil { + return localVarReturnValue, localVarHttpResponse, err + } + + localVarBody, err := ioutil.ReadAll(localVarHttpResponse.Body) + localVarHttpResponse.Body.Close() + if err != nil { + return localVarReturnValue, localVarHttpResponse, err + } + + if localVarHttpResponse.StatusCode < 300 { + // If we succeed, return the data, otherwise pass on to decode error. + err = a.client.decode(&localVarReturnValue, localVarBody, localVarHttpResponse.Header.Get("Content-Type")) + if err == nil { + return localVarReturnValue, localVarHttpResponse, err + } + } + + if localVarHttpResponse.StatusCode >= 300 { + newErr := GenericSwaggerError{ + body: localVarBody, + error: localVarHttpResponse.Status, + } + if localVarHttpResponse.StatusCode == 200 { + var v map[string][]NfdRecordinaddress + err = a.client.decode(&v, localVarBody, localVarHttpResponse.Header.Get("Content-Type")) + if err != nil { + newErr.error = err.Error() + return localVarReturnValue, localVarHttpResponse, newErr + } + newErr.model = v + return localVarReturnValue, localVarHttpResponse, newErr + } + if localVarHttpResponse.StatusCode == 429 { + var v RateLimited + err = a.client.decode(&v, localVarBody, localVarHttpResponse.Header.Get("Content-Type")) + if err != nil { + newErr.error = err.Error() + return localVarReturnValue, localVarHttpResponse, newErr + } + newErr.model = v + return localVarReturnValue, localVarHttpResponse, newErr + } + return localVarReturnValue, localVarHttpResponse, newErr + } + + return localVarReturnValue, localVarHttpResponse, nil +} + +/* +NfdApiService getNameSig nfd +Returns NameSig address for an NFD name (usable for V1 only) + - @param ctx context.Context - for authentication, logging, cancellation, deadlines, tracing, etc. Passed from http.Request or context.Background(). + - @param name + +@return string +*/ +func (a *NfdApiService) NfdGetNameSig(ctx context.Context, name string) (string, *http.Response, error) { + var ( + localVarHttpMethod = strings.ToUpper("Get") + localVarPostBody interface{} + localVarFileName string + localVarFileBytes []byte + localVarReturnValue string + ) + + // create path and map variables + localVarPath := a.client.cfg.BasePath + "/nfd/nameSig/{name}" + localVarPath = strings.Replace(localVarPath, "{"+"name"+"}", fmt.Sprintf("%v", name), -1) + + localVarHeaderParams := make(map[string]string) + localVarQueryParams := url.Values{} + localVarFormParams := url.Values{} + if strlen(name) < 1 { + return localVarReturnValue, nil, reportError("name must have at least 1 elements") + } + if strlen(name) > 120 { + return localVarReturnValue, nil, reportError("name must have less than 120 elements") + } + + // to determine the Content-Type header + localVarHttpContentTypes := []string{} + + // set Content-Type header + localVarHttpContentType := selectHeaderContentType(localVarHttpContentTypes) + if localVarHttpContentType != "" { + localVarHeaderParams["Content-Type"] = localVarHttpContentType + } + + // to determine the Accept header + localVarHttpHeaderAccepts := []string{"application/json", "application/vnd.goa.error"} + + // set Accept header + localVarHttpHeaderAccept := selectHeaderAccept(localVarHttpHeaderAccepts) + if localVarHttpHeaderAccept != "" { + localVarHeaderParams["Accept"] = localVarHttpHeaderAccept + } + r, err := a.client.prepareRequest(ctx, localVarPath, localVarHttpMethod, localVarPostBody, localVarHeaderParams, localVarQueryParams, localVarFormParams, localVarFileName, localVarFileBytes) + if err != nil { + return localVarReturnValue, nil, err + } + + localVarHttpResponse, err := a.client.callAPI(r) + if err != nil || localVarHttpResponse == nil { + return localVarReturnValue, localVarHttpResponse, err + } + + localVarBody, err := ioutil.ReadAll(localVarHttpResponse.Body) + localVarHttpResponse.Body.Close() + if err != nil { + return localVarReturnValue, localVarHttpResponse, err + } + + if localVarHttpResponse.StatusCode < 300 { + // If we succeed, return the data, otherwise pass on to decode error. + err = a.client.decode(&localVarReturnValue, localVarBody, localVarHttpResponse.Header.Get("Content-Type")) + if err == nil { + return localVarReturnValue, localVarHttpResponse, err + } + } + + if localVarHttpResponse.StatusCode >= 300 { + newErr := GenericSwaggerError{ + body: localVarBody, + error: localVarHttpResponse.Status, + } + if localVarHttpResponse.StatusCode == 200 { + var v string + err = a.client.decode(&v, localVarBody, localVarHttpResponse.Header.Get("Content-Type")) + if err != nil { + newErr.error = err.Error() + return localVarReturnValue, localVarHttpResponse, newErr + } + newErr.model = v + return localVarReturnValue, localVarHttpResponse, newErr + } + if localVarHttpResponse.StatusCode == 400 { + var v ModelError + err = a.client.decode(&v, localVarBody, localVarHttpResponse.Header.Get("Content-Type")) + if err != nil { + newErr.error = err.Error() + return localVarReturnValue, localVarHttpResponse, newErr + } + newErr.model = v + return localVarReturnValue, localVarHttpResponse, newErr + } + if localVarHttpResponse.StatusCode == 404 { + var v ModelError + err = a.client.decode(&v, localVarBody, localVarHttpResponse.Header.Get("Content-Type")) + if err != nil { + newErr.error = err.Error() + return localVarReturnValue, localVarHttpResponse, newErr + } + newErr.model = v + return localVarReturnValue, localVarHttpResponse, newErr + } + if localVarHttpResponse.StatusCode == 429 { + var v RateLimited + err = a.client.decode(&v, localVarBody, localVarHttpResponse.Header.Get("Content-Type")) + if err != nil { + newErr.error = err.Error() + return localVarReturnValue, localVarHttpResponse, newErr + } + newErr.model = v + return localVarReturnValue, localVarHttpResponse, newErr + } + return localVarReturnValue, localVarHttpResponse, newErr + } + + return localVarReturnValue, localVarHttpResponse, nil +} + +/* +NfdApiService Get all open auctions or those open for a particular name + * @param ctx context.Context - for authentication, logging, cancellation, deadlines, tracing, etc. Passed from http.Request or context.Background(). + * @param optional nil or *NfdApiNfdGetOpenAuctionsOpts - Optional Parameters: + * @param "Name" (optional.String) - NFD Name to restrict open auction list to + * @param "StartingSoon" (optional.Bool) - Changes view to show those auctions starting in the next 6 days, or those currently running +@return []NfdAuctionAndPrice +*/ + +type NfdApiNfdGetOpenAuctionsOpts struct { + Name optional.String + StartingSoon optional.Bool +} + +func (a *NfdApiService) NfdGetOpenAuctions(ctx context.Context, localVarOptionals *NfdApiNfdGetOpenAuctionsOpts) ([]NfdAuctionAndPrice, *http.Response, error) { + var ( + localVarHttpMethod = strings.ToUpper("Get") + localVarPostBody interface{} + localVarFileName string + localVarFileBytes []byte + localVarReturnValue []NfdAuctionAndPrice + ) + + // create path and map variables + localVarPath := a.client.cfg.BasePath + "/nfd/auction" + + localVarHeaderParams := make(map[string]string) + localVarQueryParams := url.Values{} + localVarFormParams := url.Values{} + + if localVarOptionals != nil && localVarOptionals.Name.IsSet() { + localVarQueryParams.Add("name", parameterToString(localVarOptionals.Name.Value(), "")) + } + if localVarOptionals != nil && localVarOptionals.StartingSoon.IsSet() { + localVarQueryParams.Add("startingSoon", parameterToString(localVarOptionals.StartingSoon.Value(), "")) + } + // to determine the Content-Type header + localVarHttpContentTypes := []string{} + + // set Content-Type header + localVarHttpContentType := selectHeaderContentType(localVarHttpContentTypes) + if localVarHttpContentType != "" { + localVarHeaderParams["Content-Type"] = localVarHttpContentType + } + + // to determine the Accept header + localVarHttpHeaderAccepts := []string{"application/json", "application/vnd.goa.error"} + + // set Accept header + localVarHttpHeaderAccept := selectHeaderAccept(localVarHttpHeaderAccepts) + if localVarHttpHeaderAccept != "" { + localVarHeaderParams["Accept"] = localVarHttpHeaderAccept + } + r, err := a.client.prepareRequest(ctx, localVarPath, localVarHttpMethod, localVarPostBody, localVarHeaderParams, localVarQueryParams, localVarFormParams, localVarFileName, localVarFileBytes) + if err != nil { + return localVarReturnValue, nil, err + } + + localVarHttpResponse, err := a.client.callAPI(r) + if err != nil || localVarHttpResponse == nil { + return localVarReturnValue, localVarHttpResponse, err + } + + localVarBody, err := ioutil.ReadAll(localVarHttpResponse.Body) + localVarHttpResponse.Body.Close() + if err != nil { + return localVarReturnValue, localVarHttpResponse, err + } + + if localVarHttpResponse.StatusCode < 300 { + // If we succeed, return the data, otherwise pass on to decode error. + err = a.client.decode(&localVarReturnValue, localVarBody, localVarHttpResponse.Header.Get("Content-Type")) + if err == nil { + return localVarReturnValue, localVarHttpResponse, err + } + } + + if localVarHttpResponse.StatusCode >= 300 { + newErr := GenericSwaggerError{ + body: localVarBody, + error: localVarHttpResponse.Status, + } + if localVarHttpResponse.StatusCode == 200 { + var v []NfdAuctionAndPrice + err = a.client.decode(&v, localVarBody, localVarHttpResponse.Header.Get("Content-Type")) + if err != nil { + newErr.error = err.Error() + return localVarReturnValue, localVarHttpResponse, newErr + } + newErr.model = v + return localVarReturnValue, localVarHttpResponse, newErr + } + if localVarHttpResponse.StatusCode == 400 { + var v ModelError + err = a.client.decode(&v, localVarBody, localVarHttpResponse.Header.Get("Content-Type")) + if err != nil { + newErr.error = err.Error() + return localVarReturnValue, localVarHttpResponse, newErr + } + newErr.model = v + return localVarReturnValue, localVarHttpResponse, newErr + } + if localVarHttpResponse.StatusCode == 404 { + var v ModelError + err = a.client.decode(&v, localVarBody, localVarHttpResponse.Header.Get("Content-Type")) + if err != nil { + newErr.error = err.Error() + return localVarReturnValue, localVarHttpResponse, newErr + } + newErr.model = v + return localVarReturnValue, localVarHttpResponse, newErr + } + if localVarHttpResponse.StatusCode == 429 { + var v RateLimited + err = a.client.decode(&v, localVarBody, localVarHttpResponse.Header.Get("Content-Type")) + if err != nil { + newErr.error = err.Error() + return localVarReturnValue, localVarHttpResponse, newErr + } + newErr.model = v + return localVarReturnValue, localVarHttpResponse, newErr + } + return localVarReturnValue, localVarHttpResponse, newErr + } + + return localVarReturnValue, localVarHttpResponse, nil +} + +/* +NfdApiService getRevAddressSig nfd +Returns RevAddress address for an NFD name (usable for V1 only) + - @param ctx context.Context - for authentication, logging, cancellation, deadlines, tracing, etc. Passed from http.Request or context.Background(). + - @param address + +@return string +*/ +func (a *NfdApiService) NfdGetRevAddressSig(ctx context.Context, address string) (string, *http.Response, error) { + var ( + localVarHttpMethod = strings.ToUpper("Get") + localVarPostBody interface{} + localVarFileName string + localVarFileBytes []byte + localVarReturnValue string + ) + + // create path and map variables + localVarPath := a.client.cfg.BasePath + "/nfd/revAddressSig/{address}" + localVarPath = strings.Replace(localVarPath, "{"+"address"+"}", fmt.Sprintf("%v", address), -1) + + localVarHeaderParams := make(map[string]string) + localVarQueryParams := url.Values{} + localVarFormParams := url.Values{} + + // to determine the Content-Type header + localVarHttpContentTypes := []string{} + + // set Content-Type header + localVarHttpContentType := selectHeaderContentType(localVarHttpContentTypes) + if localVarHttpContentType != "" { + localVarHeaderParams["Content-Type"] = localVarHttpContentType + } + + // to determine the Accept header + localVarHttpHeaderAccepts := []string{"application/json", "application/vnd.goa.error"} + + // set Accept header + localVarHttpHeaderAccept := selectHeaderAccept(localVarHttpHeaderAccepts) + if localVarHttpHeaderAccept != "" { + localVarHeaderParams["Accept"] = localVarHttpHeaderAccept + } + r, err := a.client.prepareRequest(ctx, localVarPath, localVarHttpMethod, localVarPostBody, localVarHeaderParams, localVarQueryParams, localVarFormParams, localVarFileName, localVarFileBytes) + if err != nil { + return localVarReturnValue, nil, err + } + + localVarHttpResponse, err := a.client.callAPI(r) + if err != nil || localVarHttpResponse == nil { + return localVarReturnValue, localVarHttpResponse, err + } + + localVarBody, err := ioutil.ReadAll(localVarHttpResponse.Body) + localVarHttpResponse.Body.Close() + if err != nil { + return localVarReturnValue, localVarHttpResponse, err + } + + if localVarHttpResponse.StatusCode < 300 { + // If we succeed, return the data, otherwise pass on to decode error. + err = a.client.decode(&localVarReturnValue, localVarBody, localVarHttpResponse.Header.Get("Content-Type")) + if err == nil { + return localVarReturnValue, localVarHttpResponse, err + } + } + + if localVarHttpResponse.StatusCode >= 300 { + newErr := GenericSwaggerError{ + body: localVarBody, + error: localVarHttpResponse.Status, + } + if localVarHttpResponse.StatusCode == 200 { + var v string + err = a.client.decode(&v, localVarBody, localVarHttpResponse.Header.Get("Content-Type")) + if err != nil { + newErr.error = err.Error() + return localVarReturnValue, localVarHttpResponse, newErr + } + newErr.model = v + return localVarReturnValue, localVarHttpResponse, newErr + } + if localVarHttpResponse.StatusCode == 400 { + var v ModelError + err = a.client.decode(&v, localVarBody, localVarHttpResponse.Header.Get("Content-Type")) + if err != nil { + newErr.error = err.Error() + return localVarReturnValue, localVarHttpResponse, newErr + } + newErr.model = v + return localVarReturnValue, localVarHttpResponse, newErr + } + if localVarHttpResponse.StatusCode == 404 { + var v ModelError + err = a.client.decode(&v, localVarBody, localVarHttpResponse.Header.Get("Content-Type")) + if err != nil { + newErr.error = err.Error() + return localVarReturnValue, localVarHttpResponse, newErr + } + newErr.model = v + return localVarReturnValue, localVarHttpResponse, newErr + } + if localVarHttpResponse.StatusCode == 429 { + var v RateLimited + err = a.client.decode(&v, localVarBody, localVarHttpResponse.Header.Get("Content-Type")) + if err != nil { + newErr.error = err.Error() + return localVarReturnValue, localVarHttpResponse, newErr + } + newErr.model = v + return localVarReturnValue, localVarHttpResponse, newErr + } + return localVarReturnValue, localVarHttpResponse, newErr + } + + return localVarReturnValue, localVarHttpResponse, nil +} + +/* +NfdApiService isValidASA nfd +Determines if specified NFD NFT ASA id is authentic NFD + - @param ctx context.Context - for authentication, logging, cancellation, deadlines, tracing, etc. Passed from http.Request or context.Background(). + - @param asaID Asset id of a presumed NFD ASA to verify. The API will verify the found asset references an NFD that in turn references that asset. + +@return IsValidAsaResponseBody +*/ +func (a *NfdApiService) NfdIsValidASA(ctx context.Context, asaID int64) (IsValidAsaResponseBody, *http.Response, error) { + var ( + localVarHttpMethod = strings.ToUpper("Get") + localVarPostBody interface{} + localVarFileName string + localVarFileBytes []byte + localVarReturnValue IsValidAsaResponseBody + ) + + // create path and map variables + localVarPath := a.client.cfg.BasePath + "/nfd/isValidASA/{asaID}" + localVarPath = strings.Replace(localVarPath, "{"+"asaID"+"}", fmt.Sprintf("%v", asaID), -1) + + localVarHeaderParams := make(map[string]string) + localVarQueryParams := url.Values{} + localVarFormParams := url.Values{} + + // to determine the Content-Type header + localVarHttpContentTypes := []string{} + + // set Content-Type header + localVarHttpContentType := selectHeaderContentType(localVarHttpContentTypes) + if localVarHttpContentType != "" { + localVarHeaderParams["Content-Type"] = localVarHttpContentType + } + + // to determine the Accept header + localVarHttpHeaderAccepts := []string{"application/json", "application/vnd.goa.error"} + + // set Accept header + localVarHttpHeaderAccept := selectHeaderAccept(localVarHttpHeaderAccepts) + if localVarHttpHeaderAccept != "" { + localVarHeaderParams["Accept"] = localVarHttpHeaderAccept + } + r, err := a.client.prepareRequest(ctx, localVarPath, localVarHttpMethod, localVarPostBody, localVarHeaderParams, localVarQueryParams, localVarFormParams, localVarFileName, localVarFileBytes) + if err != nil { + return localVarReturnValue, nil, err + } + + localVarHttpResponse, err := a.client.callAPI(r) + if err != nil || localVarHttpResponse == nil { + return localVarReturnValue, localVarHttpResponse, err + } + + localVarBody, err := ioutil.ReadAll(localVarHttpResponse.Body) + localVarHttpResponse.Body.Close() + if err != nil { + return localVarReturnValue, localVarHttpResponse, err + } + + if localVarHttpResponse.StatusCode < 300 { + // If we succeed, return the data, otherwise pass on to decode error. + err = a.client.decode(&localVarReturnValue, localVarBody, localVarHttpResponse.Header.Get("Content-Type")) + if err == nil { + return localVarReturnValue, localVarHttpResponse, err + } + } + + if localVarHttpResponse.StatusCode >= 300 { + newErr := GenericSwaggerError{ + body: localVarBody, + error: localVarHttpResponse.Status, + } + if localVarHttpResponse.StatusCode == 200 { + var v IsValidAsaResponseBody + err = a.client.decode(&v, localVarBody, localVarHttpResponse.Header.Get("Content-Type")) + if err != nil { + newErr.error = err.Error() + return localVarReturnValue, localVarHttpResponse, newErr + } + newErr.model = v + return localVarReturnValue, localVarHttpResponse, newErr + } + if localVarHttpResponse.StatusCode == 400 { + var v ModelError + err = a.client.decode(&v, localVarBody, localVarHttpResponse.Header.Get("Content-Type")) + if err != nil { + newErr.error = err.Error() + return localVarReturnValue, localVarHttpResponse, newErr + } + newErr.model = v + return localVarReturnValue, localVarHttpResponse, newErr + } + if localVarHttpResponse.StatusCode == 404 { + var v ModelError + err = a.client.decode(&v, localVarBody, localVarHttpResponse.Header.Get("Content-Type")) + if err != nil { + newErr.error = err.Error() + return localVarReturnValue, localVarHttpResponse, newErr + } + newErr.model = v + return localVarReturnValue, localVarHttpResponse, newErr + } + if localVarHttpResponse.StatusCode == 429 { + var v RateLimited + err = a.client.decode(&v, localVarBody, localVarHttpResponse.Header.Get("Content-Type")) + if err != nil { + newErr.error = err.Error() + return localVarReturnValue, localVarHttpResponse, newErr + } + newErr.model = v + return localVarReturnValue, localVarHttpResponse, newErr + } + return localVarReturnValue, localVarHttpResponse, newErr + } + + return localVarReturnValue, localVarHttpResponse, nil +} + +/* +NfdApiService isValidNFD nfd +Determines if specified NFD Application id is authentic + - @param ctx context.Context - for authentication, logging, cancellation, deadlines, tracing, etc. Passed from http.Request or context.Background(). + - @param appID Application id of a presumed NFD to verify. The API will perform a forward-name lookup of the name within the NFD to verify it points to the same id + +@return IsValidNfdResponseBody +*/ +func (a *NfdApiService) NfdIsValidNFD(ctx context.Context, appID int64) (IsValidNfdResponseBody, *http.Response, error) { + var ( + localVarHttpMethod = strings.ToUpper("Get") + localVarPostBody interface{} + localVarFileName string + localVarFileBytes []byte + localVarReturnValue IsValidNfdResponseBody + ) + + // create path and map variables + localVarPath := a.client.cfg.BasePath + "/nfd/isValid/{appID}" + localVarPath = strings.Replace(localVarPath, "{"+"appID"+"}", fmt.Sprintf("%v", appID), -1) + + localVarHeaderParams := make(map[string]string) + localVarQueryParams := url.Values{} + localVarFormParams := url.Values{} + + // to determine the Content-Type header + localVarHttpContentTypes := []string{} + + // set Content-Type header + localVarHttpContentType := selectHeaderContentType(localVarHttpContentTypes) + if localVarHttpContentType != "" { + localVarHeaderParams["Content-Type"] = localVarHttpContentType + } + + // to determine the Accept header + localVarHttpHeaderAccepts := []string{"application/json", "application/vnd.goa.error"} + + // set Accept header + localVarHttpHeaderAccept := selectHeaderAccept(localVarHttpHeaderAccepts) + if localVarHttpHeaderAccept != "" { + localVarHeaderParams["Accept"] = localVarHttpHeaderAccept + } + r, err := a.client.prepareRequest(ctx, localVarPath, localVarHttpMethod, localVarPostBody, localVarHeaderParams, localVarQueryParams, localVarFormParams, localVarFileName, localVarFileBytes) + if err != nil { + return localVarReturnValue, nil, err + } + + localVarHttpResponse, err := a.client.callAPI(r) + if err != nil || localVarHttpResponse == nil { + return localVarReturnValue, localVarHttpResponse, err + } + + localVarBody, err := ioutil.ReadAll(localVarHttpResponse.Body) + localVarHttpResponse.Body.Close() + if err != nil { + return localVarReturnValue, localVarHttpResponse, err + } + + if localVarHttpResponse.StatusCode < 300 { + // If we succeed, return the data, otherwise pass on to decode error. + err = a.client.decode(&localVarReturnValue, localVarBody, localVarHttpResponse.Header.Get("Content-Type")) + if err == nil { + return localVarReturnValue, localVarHttpResponse, err + } + } + + if localVarHttpResponse.StatusCode >= 300 { + newErr := GenericSwaggerError{ + body: localVarBody, + error: localVarHttpResponse.Status, + } + if localVarHttpResponse.StatusCode == 200 { + var v IsValidNfdResponseBody + err = a.client.decode(&v, localVarBody, localVarHttpResponse.Header.Get("Content-Type")) + if err != nil { + newErr.error = err.Error() + return localVarReturnValue, localVarHttpResponse, newErr + } + newErr.model = v + return localVarReturnValue, localVarHttpResponse, newErr + } + if localVarHttpResponse.StatusCode == 400 { + var v ModelError + err = a.client.decode(&v, localVarBody, localVarHttpResponse.Header.Get("Content-Type")) + if err != nil { + newErr.error = err.Error() + return localVarReturnValue, localVarHttpResponse, newErr + } + newErr.model = v + return localVarReturnValue, localVarHttpResponse, newErr + } + if localVarHttpResponse.StatusCode == 404 { + var v ModelError + err = a.client.decode(&v, localVarBody, localVarHttpResponse.Header.Get("Content-Type")) + if err != nil { + newErr.error = err.Error() + return localVarReturnValue, localVarHttpResponse, newErr + } + newErr.model = v + return localVarReturnValue, localVarHttpResponse, newErr + } + if localVarHttpResponse.StatusCode == 429 { + var v RateLimited + err = a.client.decode(&v, localVarBody, localVarHttpResponse.Header.Get("Content-Type")) + if err != nil { + newErr.error = err.Error() + return localVarReturnValue, localVarHttpResponse, newErr + } + newErr.model = v + return localVarReturnValue, localVarHttpResponse, newErr + } + return localVarReturnValue, localVarHttpResponse, newErr + } + + return localVarReturnValue, localVarHttpResponse, nil +} + +/* +NfdApiService kickoff nfd +Kickoff NFD minting process, with user buying specified NFD (or kicking off auction) as appropriate. Purchase price is set by TxnLab + - @param ctx context.Context - for authentication, logging, cancellation, deadlines, tracing, etc. Passed from http.Request or context.Background(). + - @param body + +@return string +*/ +func (a *NfdApiService) NfdKickoff(ctx context.Context, body KickoffRequestBody) (string, *http.Response, error) { + var ( + localVarHttpMethod = strings.ToUpper("Post") + localVarPostBody interface{} + localVarFileName string + localVarFileBytes []byte + localVarReturnValue string + ) + + // create path and map variables + localVarPath := a.client.cfg.BasePath + "/nfd/kickoff" + + localVarHeaderParams := make(map[string]string) + localVarQueryParams := url.Values{} + localVarFormParams := url.Values{} + + // to determine the Content-Type header + localVarHttpContentTypes := []string{"application/json"} + + // set Content-Type header + localVarHttpContentType := selectHeaderContentType(localVarHttpContentTypes) + if localVarHttpContentType != "" { + localVarHeaderParams["Content-Type"] = localVarHttpContentType + } + + // to determine the Accept header + localVarHttpHeaderAccepts := []string{"application/json", "application/vnd.goa.error"} + + // set Accept header + localVarHttpHeaderAccept := selectHeaderAccept(localVarHttpHeaderAccepts) + if localVarHttpHeaderAccept != "" { + localVarHeaderParams["Accept"] = localVarHttpHeaderAccept + } + // body params + localVarPostBody = &body + r, err := a.client.prepareRequest(ctx, localVarPath, localVarHttpMethod, localVarPostBody, localVarHeaderParams, localVarQueryParams, localVarFormParams, localVarFileName, localVarFileBytes) + if err != nil { + return localVarReturnValue, nil, err + } + + localVarHttpResponse, err := a.client.callAPI(r) + if err != nil || localVarHttpResponse == nil { + return localVarReturnValue, localVarHttpResponse, err + } + + localVarBody, err := ioutil.ReadAll(localVarHttpResponse.Body) + localVarHttpResponse.Body.Close() + if err != nil { + return localVarReturnValue, localVarHttpResponse, err + } + + if localVarHttpResponse.StatusCode < 300 { + // If we succeed, return the data, otherwise pass on to decode error. + err = a.client.decode(&localVarReturnValue, localVarBody, localVarHttpResponse.Header.Get("Content-Type")) + if err == nil { + return localVarReturnValue, localVarHttpResponse, err + } + } + + if localVarHttpResponse.StatusCode >= 300 { + newErr := GenericSwaggerError{ + body: localVarBody, + error: localVarHttpResponse.Status, + } + if localVarHttpResponse.StatusCode == 201 { + var v string + err = a.client.decode(&v, localVarBody, localVarHttpResponse.Header.Get("Content-Type")) + if err != nil { + newErr.error = err.Error() + return localVarReturnValue, localVarHttpResponse, newErr + } + newErr.model = v + return localVarReturnValue, localVarHttpResponse, newErr + } + if localVarHttpResponse.StatusCode == 400 { + var v ModelError + err = a.client.decode(&v, localVarBody, localVarHttpResponse.Header.Get("Content-Type")) + if err != nil { + newErr.error = err.Error() + return localVarReturnValue, localVarHttpResponse, newErr + } + newErr.model = v + return localVarReturnValue, localVarHttpResponse, newErr + } + if localVarHttpResponse.StatusCode == 404 { + var v ModelError + err = a.client.decode(&v, localVarBody, localVarHttpResponse.Header.Get("Content-Type")) + if err != nil { + newErr.error = err.Error() + return localVarReturnValue, localVarHttpResponse, newErr + } + newErr.model = v + return localVarReturnValue, localVarHttpResponse, newErr + } + if localVarHttpResponse.StatusCode == 429 { + var v RateLimited + err = a.client.decode(&v, localVarBody, localVarHttpResponse.Header.Get("Content-Type")) + if err != nil { + newErr.error = err.Error() + return localVarReturnValue, localVarHttpResponse, newErr + } + newErr.model = v + return localVarReturnValue, localVarHttpResponse, newErr + } + return localVarReturnValue, localVarHttpResponse, newErr + } + + return localVarReturnValue, localVarHttpResponse, nil +} + +/* +NfdApiService linkAddress nfd +Link one or more addresses to an NFD, adding to the reverse-address lookups as well as to this NFD. Sender must be owner, and each added address must be able to be signed for. + - @param ctx context.Context - for authentication, logging, cancellation, deadlines, tracing, etc. Passed from http.Request or context.Background(). + - @param body + - @param name + +@return string +*/ +func (a *NfdApiService) NfdLinkAddress(ctx context.Context, body LinkAddressRequestBody, name string) (string, *http.Response, error) { + var ( + localVarHttpMethod = strings.ToUpper("Post") + localVarPostBody interface{} + localVarFileName string + localVarFileBytes []byte + localVarReturnValue string + ) + + // create path and map variables + localVarPath := a.client.cfg.BasePath + "/nfd/links/addAddress/{name}" + localVarPath = strings.Replace(localVarPath, "{"+"name"+"}", fmt.Sprintf("%v", name), -1) + + localVarHeaderParams := make(map[string]string) + localVarQueryParams := url.Values{} + localVarFormParams := url.Values{} + if strlen(name) < 1 { + return localVarReturnValue, nil, reportError("name must have at least 1 elements") + } + if strlen(name) > 120 { + return localVarReturnValue, nil, reportError("name must have less than 120 elements") + } + + // to determine the Content-Type header + localVarHttpContentTypes := []string{"application/json"} + + // set Content-Type header + localVarHttpContentType := selectHeaderContentType(localVarHttpContentTypes) + if localVarHttpContentType != "" { + localVarHeaderParams["Content-Type"] = localVarHttpContentType + } + + // to determine the Accept header + localVarHttpHeaderAccepts := []string{"application/json", "application/vnd.goa.error"} + + // set Accept header + localVarHttpHeaderAccept := selectHeaderAccept(localVarHttpHeaderAccepts) + if localVarHttpHeaderAccept != "" { + localVarHeaderParams["Accept"] = localVarHttpHeaderAccept + } + // body params + localVarPostBody = &body + r, err := a.client.prepareRequest(ctx, localVarPath, localVarHttpMethod, localVarPostBody, localVarHeaderParams, localVarQueryParams, localVarFormParams, localVarFileName, localVarFileBytes) + if err != nil { + return localVarReturnValue, nil, err + } + + localVarHttpResponse, err := a.client.callAPI(r) + if err != nil || localVarHttpResponse == nil { + return localVarReturnValue, localVarHttpResponse, err + } + + localVarBody, err := ioutil.ReadAll(localVarHttpResponse.Body) + localVarHttpResponse.Body.Close() + if err != nil { + return localVarReturnValue, localVarHttpResponse, err + } + + if localVarHttpResponse.StatusCode < 300 { + // If we succeed, return the data, otherwise pass on to decode error. + err = a.client.decode(&localVarReturnValue, localVarBody, localVarHttpResponse.Header.Get("Content-Type")) + if err == nil { + return localVarReturnValue, localVarHttpResponse, err + } + } + + if localVarHttpResponse.StatusCode >= 300 { + newErr := GenericSwaggerError{ + body: localVarBody, + error: localVarHttpResponse.Status, + } + if localVarHttpResponse.StatusCode == 202 { + var v string + err = a.client.decode(&v, localVarBody, localVarHttpResponse.Header.Get("Content-Type")) + if err != nil { + newErr.error = err.Error() + return localVarReturnValue, localVarHttpResponse, newErr + } + newErr.model = v + return localVarReturnValue, localVarHttpResponse, newErr + } + if localVarHttpResponse.StatusCode == 400 { + var v ModelError + err = a.client.decode(&v, localVarBody, localVarHttpResponse.Header.Get("Content-Type")) + if err != nil { + newErr.error = err.Error() + return localVarReturnValue, localVarHttpResponse, newErr + } + newErr.model = v + return localVarReturnValue, localVarHttpResponse, newErr + } + if localVarHttpResponse.StatusCode == 403 { + var v ModelError + err = a.client.decode(&v, localVarBody, localVarHttpResponse.Header.Get("Content-Type")) + if err != nil { + newErr.error = err.Error() + return localVarReturnValue, localVarHttpResponse, newErr + } + newErr.model = v + return localVarReturnValue, localVarHttpResponse, newErr + } + if localVarHttpResponse.StatusCode == 404 { + var v ModelError + err = a.client.decode(&v, localVarBody, localVarHttpResponse.Header.Get("Content-Type")) + if err != nil { + newErr.error = err.Error() + return localVarReturnValue, localVarHttpResponse, newErr + } + newErr.model = v + return localVarReturnValue, localVarHttpResponse, newErr + } + if localVarHttpResponse.StatusCode == 429 { + var v RateLimited + err = a.client.decode(&v, localVarBody, localVarHttpResponse.Header.Get("Content-Type")) + if err != nil { + newErr.error = err.Error() + return localVarReturnValue, localVarHttpResponse, newErr + } + newErr.model = v + return localVarReturnValue, localVarHttpResponse, newErr + } + return localVarReturnValue, localVarHttpResponse, newErr + } + + return localVarReturnValue, localVarHttpResponse, nil +} + +/* +NfdApiService offer nfd +Offer up an NFD for sale - specifying price and optionally an address it is reserved for. + - @param ctx context.Context - for authentication, logging, cancellation, deadlines, tracing, etc. Passed from http.Request or context.Background(). + - @param body + - @param name + +@return string +*/ +func (a *NfdApiService) NfdOffer(ctx context.Context, body OfferRequestBody, name string) (string, *http.Response, error) { + var ( + localVarHttpMethod = strings.ToUpper("Post") + localVarPostBody interface{} + localVarFileName string + localVarFileBytes []byte + localVarReturnValue string + ) + + // create path and map variables + localVarPath := a.client.cfg.BasePath + "/nfd/offer/{name}" + localVarPath = strings.Replace(localVarPath, "{"+"name"+"}", fmt.Sprintf("%v", name), -1) + + localVarHeaderParams := make(map[string]string) + localVarQueryParams := url.Values{} + localVarFormParams := url.Values{} + if strlen(name) < 1 { + return localVarReturnValue, nil, reportError("name must have at least 1 elements") + } + if strlen(name) > 120 { + return localVarReturnValue, nil, reportError("name must have less than 120 elements") + } + + // to determine the Content-Type header + localVarHttpContentTypes := []string{"application/json"} + + // set Content-Type header + localVarHttpContentType := selectHeaderContentType(localVarHttpContentTypes) + if localVarHttpContentType != "" { + localVarHeaderParams["Content-Type"] = localVarHttpContentType + } + + // to determine the Accept header + localVarHttpHeaderAccepts := []string{"application/json", "application/vnd.goa.error"} + + // set Accept header + localVarHttpHeaderAccept := selectHeaderAccept(localVarHttpHeaderAccepts) + if localVarHttpHeaderAccept != "" { + localVarHeaderParams["Accept"] = localVarHttpHeaderAccept + } + // body params + localVarPostBody = &body + r, err := a.client.prepareRequest(ctx, localVarPath, localVarHttpMethod, localVarPostBody, localVarHeaderParams, localVarQueryParams, localVarFormParams, localVarFileName, localVarFileBytes) + if err != nil { + return localVarReturnValue, nil, err + } + + localVarHttpResponse, err := a.client.callAPI(r) + if err != nil || localVarHttpResponse == nil { + return localVarReturnValue, localVarHttpResponse, err + } + + localVarBody, err := ioutil.ReadAll(localVarHttpResponse.Body) + localVarHttpResponse.Body.Close() + if err != nil { + return localVarReturnValue, localVarHttpResponse, err + } + + if localVarHttpResponse.StatusCode < 300 { + // If we succeed, return the data, otherwise pass on to decode error. + err = a.client.decode(&localVarReturnValue, localVarBody, localVarHttpResponse.Header.Get("Content-Type")) + if err == nil { + return localVarReturnValue, localVarHttpResponse, err + } + } + + if localVarHttpResponse.StatusCode >= 300 { + newErr := GenericSwaggerError{ + body: localVarBody, + error: localVarHttpResponse.Status, + } + if localVarHttpResponse.StatusCode == 200 { + var v string + err = a.client.decode(&v, localVarBody, localVarHttpResponse.Header.Get("Content-Type")) + if err != nil { + newErr.error = err.Error() + return localVarReturnValue, localVarHttpResponse, newErr + } + newErr.model = v + return localVarReturnValue, localVarHttpResponse, newErr + } + if localVarHttpResponse.StatusCode == 400 { + var v ModelError + err = a.client.decode(&v, localVarBody, localVarHttpResponse.Header.Get("Content-Type")) + if err != nil { + newErr.error = err.Error() + return localVarReturnValue, localVarHttpResponse, newErr + } + newErr.model = v + return localVarReturnValue, localVarHttpResponse, newErr + } + if localVarHttpResponse.StatusCode == 403 { + var v ModelError + err = a.client.decode(&v, localVarBody, localVarHttpResponse.Header.Get("Content-Type")) + if err != nil { + newErr.error = err.Error() + return localVarReturnValue, localVarHttpResponse, newErr + } + newErr.model = v + return localVarReturnValue, localVarHttpResponse, newErr + } + if localVarHttpResponse.StatusCode == 404 { + var v ModelError + err = a.client.decode(&v, localVarBody, localVarHttpResponse.Header.Get("Content-Type")) + if err != nil { + newErr.error = err.Error() + return localVarReturnValue, localVarHttpResponse, newErr + } + newErr.model = v + return localVarReturnValue, localVarHttpResponse, newErr + } + if localVarHttpResponse.StatusCode == 413 { + var v ModelError + err = a.client.decode(&v, localVarBody, localVarHttpResponse.Header.Get("Content-Type")) + if err != nil { + newErr.error = err.Error() + return localVarReturnValue, localVarHttpResponse, newErr + } + newErr.model = v + return localVarReturnValue, localVarHttpResponse, newErr + } + if localVarHttpResponse.StatusCode == 429 { + var v RateLimited + err = a.client.decode(&v, localVarBody, localVarHttpResponse.Header.Get("Content-Type")) + if err != nil { + newErr.error = err.Error() + return localVarReturnValue, localVarHttpResponse, newErr + } + newErr.model = v + return localVarReturnValue, localVarHttpResponse, newErr + } + return localVarReturnValue, localVarHttpResponse, newErr + } + + return localVarReturnValue, localVarHttpResponse, nil +} + +/* +NfdApiService postOfferToOwner nfd +Post an offer to buy to the owner of an NFD, offering up a particular amount with optional note for them to consider + - @param ctx context.Context - for authentication, logging, cancellation, deadlines, tracing, etc. Passed from http.Request or context.Background(). + - @param body + - @param name + +@return string +*/ +func (a *NfdApiService) NfdPostOfferToOwner(ctx context.Context, body PostOfferToOwnerRequestBody, name string) (string, *http.Response, error) { + var ( + localVarHttpMethod = strings.ToUpper("Post") + localVarPostBody interface{} + localVarFileName string + localVarFileBytes []byte + localVarReturnValue string + ) + + // create path and map variables + localVarPath := a.client.cfg.BasePath + "/nfd/postOfferToOwner/{name}" + localVarPath = strings.Replace(localVarPath, "{"+"name"+"}", fmt.Sprintf("%v", name), -1) + + localVarHeaderParams := make(map[string]string) + localVarQueryParams := url.Values{} + localVarFormParams := url.Values{} + if strlen(name) < 1 { + return localVarReturnValue, nil, reportError("name must have at least 1 elements") + } + if strlen(name) > 120 { + return localVarReturnValue, nil, reportError("name must have less than 120 elements") + } + + // to determine the Content-Type header + localVarHttpContentTypes := []string{"application/json"} + + // set Content-Type header + localVarHttpContentType := selectHeaderContentType(localVarHttpContentTypes) + if localVarHttpContentType != "" { + localVarHeaderParams["Content-Type"] = localVarHttpContentType + } + + // to determine the Accept header + localVarHttpHeaderAccepts := []string{"application/json", "application/vnd.goa.error"} + + // set Accept header + localVarHttpHeaderAccept := selectHeaderAccept(localVarHttpHeaderAccepts) + if localVarHttpHeaderAccept != "" { + localVarHeaderParams["Accept"] = localVarHttpHeaderAccept + } + // body params + localVarPostBody = &body + r, err := a.client.prepareRequest(ctx, localVarPath, localVarHttpMethod, localVarPostBody, localVarHeaderParams, localVarQueryParams, localVarFormParams, localVarFileName, localVarFileBytes) + if err != nil { + return localVarReturnValue, nil, err + } + + localVarHttpResponse, err := a.client.callAPI(r) + if err != nil || localVarHttpResponse == nil { + return localVarReturnValue, localVarHttpResponse, err + } + + localVarBody, err := ioutil.ReadAll(localVarHttpResponse.Body) + localVarHttpResponse.Body.Close() + if err != nil { + return localVarReturnValue, localVarHttpResponse, err + } + + if localVarHttpResponse.StatusCode < 300 { + // If we succeed, return the data, otherwise pass on to decode error. + err = a.client.decode(&localVarReturnValue, localVarBody, localVarHttpResponse.Header.Get("Content-Type")) + if err == nil { + return localVarReturnValue, localVarHttpResponse, err + } + } + + if localVarHttpResponse.StatusCode >= 300 { + newErr := GenericSwaggerError{ + body: localVarBody, + error: localVarHttpResponse.Status, + } + if localVarHttpResponse.StatusCode == 200 { + var v string + err = a.client.decode(&v, localVarBody, localVarHttpResponse.Header.Get("Content-Type")) + if err != nil { + newErr.error = err.Error() + return localVarReturnValue, localVarHttpResponse, newErr + } + newErr.model = v + return localVarReturnValue, localVarHttpResponse, newErr + } + if localVarHttpResponse.StatusCode == 400 { + var v ModelError + err = a.client.decode(&v, localVarBody, localVarHttpResponse.Header.Get("Content-Type")) + if err != nil { + newErr.error = err.Error() + return localVarReturnValue, localVarHttpResponse, newErr + } + newErr.model = v + return localVarReturnValue, localVarHttpResponse, newErr + } + if localVarHttpResponse.StatusCode == 404 { + var v ModelError + err = a.client.decode(&v, localVarBody, localVarHttpResponse.Header.Get("Content-Type")) + if err != nil { + newErr.error = err.Error() + return localVarReturnValue, localVarHttpResponse, newErr + } + newErr.model = v + return localVarReturnValue, localVarHttpResponse, newErr + } + if localVarHttpResponse.StatusCode == 429 { + var v RateLimited + err = a.client.decode(&v, localVarBody, localVarHttpResponse.Header.Get("Content-Type")) + if err != nil { + newErr.error = err.Error() + return localVarReturnValue, localVarHttpResponse, newErr + } + newErr.model = v + return localVarReturnValue, localVarHttpResponse, newErr + } + return localVarReturnValue, localVarHttpResponse, newErr + } + + return localVarReturnValue, localVarHttpResponse, nil +} + +/* +NfdApiService purchase nfd +Purchase an NFD for sale - specifying buyer (to sign transaction) and price + - @param ctx context.Context - for authentication, logging, cancellation, deadlines, tracing, etc. Passed from http.Request or context.Background(). + - @param body + - @param name + +@return string +*/ +func (a *NfdApiService) NfdPurchase(ctx context.Context, body PurchaseRequestBody, name string) (string, *http.Response, error) { + var ( + localVarHttpMethod = strings.ToUpper("Post") + localVarPostBody interface{} + localVarFileName string + localVarFileBytes []byte + localVarReturnValue string + ) + + // create path and map variables + localVarPath := a.client.cfg.BasePath + "/nfd/purchase/{name}" + localVarPath = strings.Replace(localVarPath, "{"+"name"+"}", fmt.Sprintf("%v", name), -1) + + localVarHeaderParams := make(map[string]string) + localVarQueryParams := url.Values{} + localVarFormParams := url.Values{} + if strlen(name) < 1 { + return localVarReturnValue, nil, reportError("name must have at least 1 elements") + } + if strlen(name) > 120 { + return localVarReturnValue, nil, reportError("name must have less than 120 elements") + } + + // to determine the Content-Type header + localVarHttpContentTypes := []string{"application/json"} + + // set Content-Type header + localVarHttpContentType := selectHeaderContentType(localVarHttpContentTypes) + if localVarHttpContentType != "" { + localVarHeaderParams["Content-Type"] = localVarHttpContentType + } + + // to determine the Accept header + localVarHttpHeaderAccepts := []string{"application/json", "application/vnd.goa.error"} + + // set Accept header + localVarHttpHeaderAccept := selectHeaderAccept(localVarHttpHeaderAccepts) + if localVarHttpHeaderAccept != "" { + localVarHeaderParams["Accept"] = localVarHttpHeaderAccept + } + // body params + localVarPostBody = &body + r, err := a.client.prepareRequest(ctx, localVarPath, localVarHttpMethod, localVarPostBody, localVarHeaderParams, localVarQueryParams, localVarFormParams, localVarFileName, localVarFileBytes) + if err != nil { + return localVarReturnValue, nil, err + } + + localVarHttpResponse, err := a.client.callAPI(r) + if err != nil || localVarHttpResponse == nil { + return localVarReturnValue, localVarHttpResponse, err + } + + localVarBody, err := ioutil.ReadAll(localVarHttpResponse.Body) + localVarHttpResponse.Body.Close() + if err != nil { + return localVarReturnValue, localVarHttpResponse, err + } + + if localVarHttpResponse.StatusCode < 300 { + // If we succeed, return the data, otherwise pass on to decode error. + err = a.client.decode(&localVarReturnValue, localVarBody, localVarHttpResponse.Header.Get("Content-Type")) + if err == nil { + return localVarReturnValue, localVarHttpResponse, err + } + } + + if localVarHttpResponse.StatusCode >= 300 { + newErr := GenericSwaggerError{ + body: localVarBody, + error: localVarHttpResponse.Status, + } + if localVarHttpResponse.StatusCode == 200 { + var v string + err = a.client.decode(&v, localVarBody, localVarHttpResponse.Header.Get("Content-Type")) + if err != nil { + newErr.error = err.Error() + return localVarReturnValue, localVarHttpResponse, newErr + } + newErr.model = v + return localVarReturnValue, localVarHttpResponse, newErr + } + if localVarHttpResponse.StatusCode == 404 { + var v ModelError + err = a.client.decode(&v, localVarBody, localVarHttpResponse.Header.Get("Content-Type")) + if err != nil { + newErr.error = err.Error() + return localVarReturnValue, localVarHttpResponse, newErr + } + newErr.model = v + return localVarReturnValue, localVarHttpResponse, newErr + } + if localVarHttpResponse.StatusCode == 429 { + var v RateLimited + err = a.client.decode(&v, localVarBody, localVarHttpResponse.Header.Get("Content-Type")) + if err != nil { + newErr.error = err.Error() + return localVarReturnValue, localVarHttpResponse, newErr + } + newErr.model = v + return localVarReturnValue, localVarHttpResponse, newErr + } + return localVarReturnValue, localVarHttpResponse, newErr + } + + return localVarReturnValue, localVarHttpResponse, nil +} + +/* +NfdApiService rescindOffer nfd +Rescind offer of sale. Claiming NFD back for self, and removing it for sale. + - @param ctx context.Context - for authentication, logging, cancellation, deadlines, tracing, etc. Passed from http.Request or context.Background(). + - @param body + - @param name + +@return string +*/ +func (a *NfdApiService) NfdRescindOffer(ctx context.Context, body RescindOfferRequestBody, name string) (string, *http.Response, error) { + var ( + localVarHttpMethod = strings.ToUpper("Post") + localVarPostBody interface{} + localVarFileName string + localVarFileBytes []byte + localVarReturnValue string + ) + + // create path and map variables + localVarPath := a.client.cfg.BasePath + "/nfd/rescindOffer/{name}" + localVarPath = strings.Replace(localVarPath, "{"+"name"+"}", fmt.Sprintf("%v", name), -1) + + localVarHeaderParams := make(map[string]string) + localVarQueryParams := url.Values{} + localVarFormParams := url.Values{} + if strlen(name) < 1 { + return localVarReturnValue, nil, reportError("name must have at least 1 elements") + } + if strlen(name) > 120 { + return localVarReturnValue, nil, reportError("name must have less than 120 elements") + } + + // to determine the Content-Type header + localVarHttpContentTypes := []string{"application/json"} + + // set Content-Type header + localVarHttpContentType := selectHeaderContentType(localVarHttpContentTypes) + if localVarHttpContentType != "" { + localVarHeaderParams["Content-Type"] = localVarHttpContentType + } + + // to determine the Accept header + localVarHttpHeaderAccepts := []string{"application/json", "application/vnd.goa.error"} + + // set Accept header + localVarHttpHeaderAccept := selectHeaderAccept(localVarHttpHeaderAccepts) + if localVarHttpHeaderAccept != "" { + localVarHeaderParams["Accept"] = localVarHttpHeaderAccept + } + // body params + localVarPostBody = &body + r, err := a.client.prepareRequest(ctx, localVarPath, localVarHttpMethod, localVarPostBody, localVarHeaderParams, localVarQueryParams, localVarFormParams, localVarFileName, localVarFileBytes) + if err != nil { + return localVarReturnValue, nil, err + } + + localVarHttpResponse, err := a.client.callAPI(r) + if err != nil || localVarHttpResponse == nil { + return localVarReturnValue, localVarHttpResponse, err + } + + localVarBody, err := ioutil.ReadAll(localVarHttpResponse.Body) + localVarHttpResponse.Body.Close() + if err != nil { + return localVarReturnValue, localVarHttpResponse, err + } + + if localVarHttpResponse.StatusCode < 300 { + // If we succeed, return the data, otherwise pass on to decode error. + err = a.client.decode(&localVarReturnValue, localVarBody, localVarHttpResponse.Header.Get("Content-Type")) + if err == nil { + return localVarReturnValue, localVarHttpResponse, err + } + } + + if localVarHttpResponse.StatusCode >= 300 { + newErr := GenericSwaggerError{ + body: localVarBody, + error: localVarHttpResponse.Status, + } + if localVarHttpResponse.StatusCode == 200 { + var v string + err = a.client.decode(&v, localVarBody, localVarHttpResponse.Header.Get("Content-Type")) + if err != nil { + newErr.error = err.Error() + return localVarReturnValue, localVarHttpResponse, newErr + } + newErr.model = v + return localVarReturnValue, localVarHttpResponse, newErr + } + if localVarHttpResponse.StatusCode == 400 { + var v ModelError + err = a.client.decode(&v, localVarBody, localVarHttpResponse.Header.Get("Content-Type")) + if err != nil { + newErr.error = err.Error() + return localVarReturnValue, localVarHttpResponse, newErr + } + newErr.model = v + return localVarReturnValue, localVarHttpResponse, newErr + } + if localVarHttpResponse.StatusCode == 404 { + var v ModelError + err = a.client.decode(&v, localVarBody, localVarHttpResponse.Header.Get("Content-Type")) + if err != nil { + newErr.error = err.Error() + return localVarReturnValue, localVarHttpResponse, newErr + } + newErr.model = v + return localVarReturnValue, localVarHttpResponse, newErr + } + if localVarHttpResponse.StatusCode == 429 { + var v RateLimited + err = a.client.decode(&v, localVarBody, localVarHttpResponse.Header.Get("Content-Type")) + if err != nil { + newErr.error = err.Error() + return localVarReturnValue, localVarHttpResponse, newErr + } + newErr.model = v + return localVarReturnValue, localVarHttpResponse, newErr + } + return localVarReturnValue, localVarHttpResponse, newErr + } + + return localVarReturnValue, localVarHttpResponse, nil +} + +/* +NfdApiService [DEPRECATED] Search for NFDs based on select lookup criteria +[DEPRECATED] Find NFDs based on owner and/or reservations, name search (prefix or substring), or verified property search. For typical 'reverse-lookup' functionality see the getNFDsForAddresses method (/nfd/address?address=xx...). Fetching a specific NFD, use nfd/{name}. Prefix search is useful for interactive lookups. + * @param ctx context.Context - for authentication, logging, cancellation, deadlines, tracing, etc. Passed from http.Request or context.Background(). + * @param optional nil or *NfdApiNfdSearchV1Opts - Optional Parameters: + * @param "owner" (optional.String) - An Algorand account address to find all NFDs owned by that address + * @param "ReservedFor" (optional.String) - An Algorand account address to find all NFDs reserved for that address + * @param "Prefix" (optional.String) - The start of an NFD name, fetching multiple NFDs that have that prefix - forces 'thumbnail' view ! + * @param "Substring" (optional.String) - Part of an NFD name, fetching multiple NFDs that have that substring (minimum 3 characters) - forces 'thumbnail' view ! + * @param "Vproperty" (optional.String) - Verified property name to search on - specify value with vvalue + * @param "Vvalue" (optional.String) - Value to find in the vproperty field specified with the vproperty parameter + * @param "RequireAddresses" (optional.Bool) - Whether returned NFDs (only in prefix/substring search) must have linked addresses (caAlgo) defined in order to be returned. This is useful for callers wanting to lookup a name for the purposes of transferring assets to that NFD holder and they want to exclude names not linked for deposits. + * @param "Limit" (optional.Int64) - Limit the number of results returned - max 240 + * @param "View" (optional.String) - View of data to return, tiny (name, owner, caAlgo, unverifiedCaAlgo only), thumbnail (tiny + avatar), (brief (default), or full + * @param "Test00r" (optional.Bool) - + * @param "IfNoneMatch" (optional.String) - etag +@return []NfdRecord +*/ + +type NfdApiNfdSearchV1Opts struct { + Owner optional.String + ReservedFor optional.String + Prefix optional.String + Substring optional.String + Vproperty optional.String + Vvalue optional.String + RequireAddresses optional.Bool + Limit optional.Int64 + View optional.String + Test00r optional.Bool + IfNoneMatch optional.String +} + +func (a *NfdApiService) NfdSearchV1(ctx context.Context, localVarOptionals *NfdApiNfdSearchV1Opts) ([]NfdRecord, *http.Response, error) { + var ( + localVarHttpMethod = strings.ToUpper("Get") + localVarPostBody interface{} + localVarFileName string + localVarFileBytes []byte + localVarReturnValue []NfdRecord + ) + + // create path and map variables + localVarPath := a.client.cfg.BasePath + "/nfd" + + localVarHeaderParams := make(map[string]string) + localVarQueryParams := url.Values{} + localVarFormParams := url.Values{} + + if localVarOptionals != nil && localVarOptionals.Owner.IsSet() { + localVarQueryParams.Add("owner", parameterToString(localVarOptionals.Owner.Value(), "")) + } + if localVarOptionals != nil && localVarOptionals.ReservedFor.IsSet() { + localVarQueryParams.Add("reservedFor", parameterToString(localVarOptionals.ReservedFor.Value(), "")) + } + if localVarOptionals != nil && localVarOptionals.Prefix.IsSet() { + localVarQueryParams.Add("prefix", parameterToString(localVarOptionals.Prefix.Value(), "")) + } + if localVarOptionals != nil && localVarOptionals.Substring.IsSet() { + localVarQueryParams.Add("substring", parameterToString(localVarOptionals.Substring.Value(), "")) + } + if localVarOptionals != nil && localVarOptionals.Vproperty.IsSet() { + localVarQueryParams.Add("vproperty", parameterToString(localVarOptionals.Vproperty.Value(), "")) + } + if localVarOptionals != nil && localVarOptionals.Vvalue.IsSet() { + localVarQueryParams.Add("vvalue", parameterToString(localVarOptionals.Vvalue.Value(), "")) + } + if localVarOptionals != nil && localVarOptionals.RequireAddresses.IsSet() { + localVarQueryParams.Add("requireAddresses", parameterToString(localVarOptionals.RequireAddresses.Value(), "")) + } + if localVarOptionals != nil && localVarOptionals.Limit.IsSet() { + localVarQueryParams.Add("limit", parameterToString(localVarOptionals.Limit.Value(), "")) + } + if localVarOptionals != nil && localVarOptionals.View.IsSet() { + localVarQueryParams.Add("view", parameterToString(localVarOptionals.View.Value(), "")) + } + if localVarOptionals != nil && localVarOptionals.Test00r.IsSet() { + localVarQueryParams.Add("test00r", parameterToString(localVarOptionals.Test00r.Value(), "")) + } + // to determine the Content-Type header + localVarHttpContentTypes := []string{} + + // set Content-Type header + localVarHttpContentType := selectHeaderContentType(localVarHttpContentTypes) + if localVarHttpContentType != "" { + localVarHeaderParams["Content-Type"] = localVarHttpContentType + } + + // to determine the Accept header + localVarHttpHeaderAccepts := []string{"application/json", "application/vnd.goa.error"} + + // set Accept header + localVarHttpHeaderAccept := selectHeaderAccept(localVarHttpHeaderAccepts) + if localVarHttpHeaderAccept != "" { + localVarHeaderParams["Accept"] = localVarHttpHeaderAccept + } + if localVarOptionals != nil && localVarOptionals.IfNoneMatch.IsSet() { + localVarHeaderParams["if-none-match"] = parameterToString(localVarOptionals.IfNoneMatch.Value(), "") + } + r, err := a.client.prepareRequest(ctx, localVarPath, localVarHttpMethod, localVarPostBody, localVarHeaderParams, localVarQueryParams, localVarFormParams, localVarFileName, localVarFileBytes) + if err != nil { + return localVarReturnValue, nil, err + } + + localVarHttpResponse, err := a.client.callAPI(r) + if err != nil || localVarHttpResponse == nil { + return localVarReturnValue, localVarHttpResponse, err + } + + localVarBody, err := ioutil.ReadAll(localVarHttpResponse.Body) + localVarHttpResponse.Body.Close() + if err != nil { + return localVarReturnValue, localVarHttpResponse, err + } + + if localVarHttpResponse.StatusCode < 300 { + // If we succeed, return the data, otherwise pass on to decode error. + err = a.client.decode(&localVarReturnValue, localVarBody, localVarHttpResponse.Header.Get("Content-Type")) + if err == nil { + return localVarReturnValue, localVarHttpResponse, err + } + } + + if localVarHttpResponse.StatusCode >= 300 { + newErr := GenericSwaggerError{ + body: localVarBody, + error: localVarHttpResponse.Status, + } + if localVarHttpResponse.StatusCode == 200 { + var v []NfdRecord + err = a.client.decode(&v, localVarBody, localVarHttpResponse.Header.Get("Content-Type")) + if err != nil { + newErr.error = err.Error() + return localVarReturnValue, localVarHttpResponse, newErr + } + newErr.model = v + return localVarReturnValue, localVarHttpResponse, newErr + } + if localVarHttpResponse.StatusCode == 404 { + var v ModelError + err = a.client.decode(&v, localVarBody, localVarHttpResponse.Header.Get("Content-Type")) + if err != nil { + newErr.error = err.Error() + return localVarReturnValue, localVarHttpResponse, newErr + } + newErr.model = v + return localVarReturnValue, localVarHttpResponse, newErr + } + if localVarHttpResponse.StatusCode == 429 { + var v RateLimited + err = a.client.decode(&v, localVarBody, localVarHttpResponse.Header.Get("Content-Type")) + if err != nil { + newErr.error = err.Error() + return localVarReturnValue, localVarHttpResponse, newErr + } + newErr.model = v + return localVarReturnValue, localVarHttpResponse, newErr + } + return localVarReturnValue, localVarHttpResponse, newErr + } + + return localVarReturnValue, localVarHttpResponse, nil +} + +/* +NfdApiService Search NFDs via various filters +Search NFDs via various filters + * @param ctx context.Context - for authentication, logging, cancellation, deadlines, tracing, etc. Passed from http.Request or context.Background(). + * @param optional nil or *NfdApiNfdSearchV2Opts - Optional Parameters: + * @param "Name" (optional.String) - name or partial match of NFD name to filter on + * @param "Category" (optional.Interface of []string) - + * @param "SaleType" (optional.Interface of []string) - + * @param "state" (optional.Interface of []string) - + * @param "ParentAppID" (optional.Int64) - The parent NFD Application id to find. Used for fetching segments of an NFD + * @param "Length" (optional.Interface of []string) - Length of NFD + * @param "Traits" (optional.Interface of []string) - Traits of NFD + * @param "owner" (optional.String) - An Algorand account address to find all NFDs owned by that address + * @param "ReservedFor" (optional.String) - An Algorand account address to find all NFDs reserved for that address + * @param "ExcludeUserReserved" (optional.Bool) - Should NFDs reserved for an account (transfers for example or unclaimed winning auctions) be excluded + * @param "Prefix" (optional.String) - The start of an NFD name, fetching multiple NFDs that have that prefix + * @param "Substring" (optional.String) - Part of an NFD name, fetching multiple NFDs that have that substring (minimum 3 characters) + * @param "Vproperty" (optional.String) - Verified property name to search on - specify value with vvalue + * @param "Vvalue" (optional.String) - Value to find in the vproperty field specified with the vproperty parameter + * @param "SegmentLocked" (optional.Bool) - Whether to explicitly filter on segments being locked or unlocked. Typically only valuable when filtering on unlocked + * @param "SegmentRoot" (optional.Bool) - Whether to explicitly filter on NFD roots or segments. True to only see roots, False to only see segments. + * @param "MinPrice" (optional.Int64) - Minimum price of NFD + * @param "MaxPrice" (optional.Int64) - Maximum price of NFD + * @param "MinPriceUsd" (optional.Int64) - Minimum price of NFD Segment in USD (cents) + * @param "MaxPriceUsd" (optional.Int64) - Maximum price of NFD Segment in USD (cents) + * @param "ChangedAfter" (optional.Time) - Fetch NFDs that changed after the specified timestamp + * @param "Limit" (optional.Int64) - Limit the number of results returned - max 200 + * @param "Offset" (optional.Int64) - Starting document in large list. Fetch 1-100 [limit 100], pass offset 100 to fetch 100-200 + * @param "Sort" (optional.String) - What to sort on + * @param "View" (optional.String) - View of data to return, tiny (name, owner, caAlgo, unverifiedCaAlgo only), brief (default), or full + * @param "IfNoneMatch" (optional.String) - etag +@return NfdV2SearchRecords +*/ + +type NfdApiNfdSearchV2Opts struct { + Name optional.String + Category optional.Interface + SaleType optional.Interface + State optional.Interface + ParentAppID optional.Int64 + Length optional.Interface + Traits optional.Interface + Owner optional.String + ReservedFor optional.String + ExcludeUserReserved optional.Bool + Prefix optional.String + Substring optional.String + Vproperty optional.String + Vvalue optional.String + SegmentLocked optional.Bool + SegmentRoot optional.Bool + MinPrice optional.Int64 + MaxPrice optional.Int64 + MinPriceUsd optional.Int64 + MaxPriceUsd optional.Int64 + ChangedAfter optional.Time + Limit optional.Int64 + Offset optional.Int64 + Sort optional.String + View optional.String + IfNoneMatch optional.String +} + +func (a *NfdApiService) NfdSearchV2(ctx context.Context, localVarOptionals *NfdApiNfdSearchV2Opts) (NfdV2SearchRecords, *http.Response, error) { + var ( + localVarHttpMethod = strings.ToUpper("Get") + localVarPostBody interface{} + localVarFileName string + localVarFileBytes []byte + localVarReturnValue NfdV2SearchRecords + ) + + // create path and map variables + localVarPath := a.client.cfg.BasePath + "/nfd/v2/search" + + localVarHeaderParams := make(map[string]string) + localVarQueryParams := url.Values{} + localVarFormParams := url.Values{} + + if localVarOptionals != nil && localVarOptionals.Name.IsSet() { + localVarQueryParams.Add("name", parameterToString(localVarOptionals.Name.Value(), "")) + } + if localVarOptionals != nil && localVarOptionals.Category.IsSet() { + localVarQueryParams.Add("category", parameterToString(localVarOptionals.Category.Value(), "multi")) + } + if localVarOptionals != nil && localVarOptionals.SaleType.IsSet() { + localVarQueryParams.Add("saleType", parameterToString(localVarOptionals.SaleType.Value(), "multi")) + } + if localVarOptionals != nil && localVarOptionals.State.IsSet() { + localVarQueryParams.Add("state", parameterToString(localVarOptionals.State.Value(), "multi")) + } + if localVarOptionals != nil && localVarOptionals.ParentAppID.IsSet() { + localVarQueryParams.Add("parentAppID", parameterToString(localVarOptionals.ParentAppID.Value(), "")) + } + if localVarOptionals != nil && localVarOptionals.Length.IsSet() { + localVarQueryParams.Add("length", parameterToString(localVarOptionals.Length.Value(), "multi")) + } + if localVarOptionals != nil && localVarOptionals.Traits.IsSet() { + localVarQueryParams.Add("traits", parameterToString(localVarOptionals.Traits.Value(), "multi")) + } + if localVarOptionals != nil && localVarOptionals.Owner.IsSet() { + localVarQueryParams.Add("owner", parameterToString(localVarOptionals.Owner.Value(), "")) + } + if localVarOptionals != nil && localVarOptionals.ReservedFor.IsSet() { + localVarQueryParams.Add("reservedFor", parameterToString(localVarOptionals.ReservedFor.Value(), "")) + } + if localVarOptionals != nil && localVarOptionals.ExcludeUserReserved.IsSet() { + localVarQueryParams.Add("excludeUserReserved", parameterToString(localVarOptionals.ExcludeUserReserved.Value(), "")) + } + if localVarOptionals != nil && localVarOptionals.Prefix.IsSet() { + localVarQueryParams.Add("prefix", parameterToString(localVarOptionals.Prefix.Value(), "")) + } + if localVarOptionals != nil && localVarOptionals.Substring.IsSet() { + localVarQueryParams.Add("substring", parameterToString(localVarOptionals.Substring.Value(), "")) + } + if localVarOptionals != nil && localVarOptionals.Vproperty.IsSet() { + localVarQueryParams.Add("vproperty", parameterToString(localVarOptionals.Vproperty.Value(), "")) + } + if localVarOptionals != nil && localVarOptionals.Vvalue.IsSet() { + localVarQueryParams.Add("vvalue", parameterToString(localVarOptionals.Vvalue.Value(), "")) + } + if localVarOptionals != nil && localVarOptionals.SegmentLocked.IsSet() { + localVarQueryParams.Add("segmentLocked", parameterToString(localVarOptionals.SegmentLocked.Value(), "")) + } + if localVarOptionals != nil && localVarOptionals.SegmentRoot.IsSet() { + localVarQueryParams.Add("segmentRoot", parameterToString(localVarOptionals.SegmentRoot.Value(), "")) + } + if localVarOptionals != nil && localVarOptionals.MinPrice.IsSet() { + localVarQueryParams.Add("minPrice", parameterToString(localVarOptionals.MinPrice.Value(), "")) + } + if localVarOptionals != nil && localVarOptionals.MaxPrice.IsSet() { + localVarQueryParams.Add("maxPrice", parameterToString(localVarOptionals.MaxPrice.Value(), "")) + } + if localVarOptionals != nil && localVarOptionals.MinPriceUsd.IsSet() { + localVarQueryParams.Add("minPriceUsd", parameterToString(localVarOptionals.MinPriceUsd.Value(), "")) + } + if localVarOptionals != nil && localVarOptionals.MaxPriceUsd.IsSet() { + localVarQueryParams.Add("maxPriceUsd", parameterToString(localVarOptionals.MaxPriceUsd.Value(), "")) + } + if localVarOptionals != nil && localVarOptionals.ChangedAfter.IsSet() { + localVarQueryParams.Add("changedAfter", parameterToString(localVarOptionals.ChangedAfter.Value(), "")) + } + if localVarOptionals != nil && localVarOptionals.Limit.IsSet() { + localVarQueryParams.Add("limit", parameterToString(localVarOptionals.Limit.Value(), "")) + } + if localVarOptionals != nil && localVarOptionals.Offset.IsSet() { + localVarQueryParams.Add("offset", parameterToString(localVarOptionals.Offset.Value(), "")) + } + if localVarOptionals != nil && localVarOptionals.Sort.IsSet() { + localVarQueryParams.Add("sort", parameterToString(localVarOptionals.Sort.Value(), "")) + } + if localVarOptionals != nil && localVarOptionals.View.IsSet() { + localVarQueryParams.Add("view", parameterToString(localVarOptionals.View.Value(), "")) + } + // to determine the Content-Type header + localVarHttpContentTypes := []string{} + + // set Content-Type header + localVarHttpContentType := selectHeaderContentType(localVarHttpContentTypes) + if localVarHttpContentType != "" { + localVarHeaderParams["Content-Type"] = localVarHttpContentType + } + + // to determine the Accept header + localVarHttpHeaderAccepts := []string{"application/json", "application/vnd.goa.error"} + + // set Accept header + localVarHttpHeaderAccept := selectHeaderAccept(localVarHttpHeaderAccepts) + if localVarHttpHeaderAccept != "" { + localVarHeaderParams["Accept"] = localVarHttpHeaderAccept + } + if localVarOptionals != nil && localVarOptionals.IfNoneMatch.IsSet() { + localVarHeaderParams["if-none-match"] = parameterToString(localVarOptionals.IfNoneMatch.Value(), "") + } + r, err := a.client.prepareRequest(ctx, localVarPath, localVarHttpMethod, localVarPostBody, localVarHeaderParams, localVarQueryParams, localVarFormParams, localVarFileName, localVarFileBytes) + if err != nil { + return localVarReturnValue, nil, err + } + + localVarHttpResponse, err := a.client.callAPI(r) + if err != nil || localVarHttpResponse == nil { + return localVarReturnValue, localVarHttpResponse, err + } + + localVarBody, err := ioutil.ReadAll(localVarHttpResponse.Body) + localVarHttpResponse.Body.Close() + if err != nil { + return localVarReturnValue, localVarHttpResponse, err + } + + if localVarHttpResponse.StatusCode < 300 { + // If we succeed, return the data, otherwise pass on to decode error. + err = a.client.decode(&localVarReturnValue, localVarBody, localVarHttpResponse.Header.Get("Content-Type")) + if err == nil { + return localVarReturnValue, localVarHttpResponse, err + } + } + + if localVarHttpResponse.StatusCode >= 300 { + newErr := GenericSwaggerError{ + body: localVarBody, + error: localVarHttpResponse.Status, + } + if localVarHttpResponse.StatusCode == 200 { + var v NfdV2SearchRecords + err = a.client.decode(&v, localVarBody, localVarHttpResponse.Header.Get("Content-Type")) + if err != nil { + newErr.error = err.Error() + return localVarReturnValue, localVarHttpResponse, newErr + } + newErr.model = v + return localVarReturnValue, localVarHttpResponse, newErr + } + if localVarHttpResponse.StatusCode == 400 { + var v ModelError + err = a.client.decode(&v, localVarBody, localVarHttpResponse.Header.Get("Content-Type")) + if err != nil { + newErr.error = err.Error() + return localVarReturnValue, localVarHttpResponse, newErr + } + newErr.model = v + return localVarReturnValue, localVarHttpResponse, newErr + } + if localVarHttpResponse.StatusCode == 404 { + var v ModelError + err = a.client.decode(&v, localVarBody, localVarHttpResponse.Header.Get("Content-Type")) + if err != nil { + newErr.error = err.Error() + return localVarReturnValue, localVarHttpResponse, newErr + } + newErr.model = v + return localVarReturnValue, localVarHttpResponse, newErr + } + if localVarHttpResponse.StatusCode == 429 { + var v RateLimited + err = a.client.decode(&v, localVarBody, localVarHttpResponse.Header.Get("Content-Type")) + if err != nil { + newErr.error = err.Error() + return localVarReturnValue, localVarHttpResponse, newErr + } + newErr.model = v + return localVarReturnValue, localVarHttpResponse, newErr + } + return localVarReturnValue, localVarHttpResponse, newErr + } + + return localVarReturnValue, localVarHttpResponse, nil +} + +/* +NfdApiService segmentLeaders nfd +Get top segment roots + * @param ctx context.Context - for authentication, logging, cancellation, deadlines, tracing, etc. Passed from http.Request or context.Background(). + * @param optional nil or *NfdApiNfdSegmentLeadersOpts - Optional Parameters: + * @param "IfNoneMatch" (optional.String) - etag +@return []NfdRecord +*/ + +type NfdApiNfdSegmentLeadersOpts struct { + IfNoneMatch optional.String +} + +func (a *NfdApiService) NfdSegmentLeaders(ctx context.Context, localVarOptionals *NfdApiNfdSegmentLeadersOpts) ([]NfdRecord, *http.Response, error) { + var ( + localVarHttpMethod = strings.ToUpper("Get") + localVarPostBody interface{} + localVarFileName string + localVarFileBytes []byte + localVarReturnValue []NfdRecord + ) + + // create path and map variables + localVarPath := a.client.cfg.BasePath + "/nfd/segment/leaders" + + localVarHeaderParams := make(map[string]string) + localVarQueryParams := url.Values{} + localVarFormParams := url.Values{} + + // to determine the Content-Type header + localVarHttpContentTypes := []string{} + + // set Content-Type header + localVarHttpContentType := selectHeaderContentType(localVarHttpContentTypes) + if localVarHttpContentType != "" { + localVarHeaderParams["Content-Type"] = localVarHttpContentType + } + + // to determine the Accept header + localVarHttpHeaderAccepts := []string{"application/json", "application/vnd.goa.error"} + + // set Accept header + localVarHttpHeaderAccept := selectHeaderAccept(localVarHttpHeaderAccepts) + if localVarHttpHeaderAccept != "" { + localVarHeaderParams["Accept"] = localVarHttpHeaderAccept + } + if localVarOptionals != nil && localVarOptionals.IfNoneMatch.IsSet() { + localVarHeaderParams["if-none-match"] = parameterToString(localVarOptionals.IfNoneMatch.Value(), "") + } + r, err := a.client.prepareRequest(ctx, localVarPath, localVarHttpMethod, localVarPostBody, localVarHeaderParams, localVarQueryParams, localVarFormParams, localVarFileName, localVarFileBytes) + if err != nil { + return localVarReturnValue, nil, err + } + + localVarHttpResponse, err := a.client.callAPI(r) + if err != nil || localVarHttpResponse == nil { + return localVarReturnValue, localVarHttpResponse, err + } + + localVarBody, err := ioutil.ReadAll(localVarHttpResponse.Body) + localVarHttpResponse.Body.Close() + if err != nil { + return localVarReturnValue, localVarHttpResponse, err + } + + if localVarHttpResponse.StatusCode < 300 { + // If we succeed, return the data, otherwise pass on to decode error. + err = a.client.decode(&localVarReturnValue, localVarBody, localVarHttpResponse.Header.Get("Content-Type")) + if err == nil { + return localVarReturnValue, localVarHttpResponse, err + } + } + + if localVarHttpResponse.StatusCode >= 300 { + newErr := GenericSwaggerError{ + body: localVarBody, + error: localVarHttpResponse.Status, + } + if localVarHttpResponse.StatusCode == 200 { + var v []NfdRecord + err = a.client.decode(&v, localVarBody, localVarHttpResponse.Header.Get("Content-Type")) + if err != nil { + newErr.error = err.Error() + return localVarReturnValue, localVarHttpResponse, newErr + } + newErr.model = v + return localVarReturnValue, localVarHttpResponse, newErr + } + if localVarHttpResponse.StatusCode == 400 { + var v ModelError + err = a.client.decode(&v, localVarBody, localVarHttpResponse.Header.Get("Content-Type")) + if err != nil { + newErr.error = err.Error() + return localVarReturnValue, localVarHttpResponse, newErr + } + newErr.model = v + return localVarReturnValue, localVarHttpResponse, newErr + } + if localVarHttpResponse.StatusCode == 404 { + var v ModelError + err = a.client.decode(&v, localVarBody, localVarHttpResponse.Header.Get("Content-Type")) + if err != nil { + newErr.error = err.Error() + return localVarReturnValue, localVarHttpResponse, newErr + } + newErr.model = v + return localVarReturnValue, localVarHttpResponse, newErr + } + if localVarHttpResponse.StatusCode == 429 { + var v RateLimited + err = a.client.decode(&v, localVarBody, localVarHttpResponse.Header.Get("Content-Type")) + if err != nil { + newErr.error = err.Error() + return localVarReturnValue, localVarHttpResponse, newErr + } + newErr.model = v + return localVarReturnValue, localVarHttpResponse, newErr + } + return localVarReturnValue, localVarHttpResponse, newErr + } + + return localVarReturnValue, localVarHttpResponse, nil +} + +/* +NfdApiService Lock/Unlock an NFD segment - specifying open price if unlocking +Lock/Unlock an NFD segment - if locked, the segment only allows minted names created by the segment owner. If unlocked, anyone can mint off the segment for the price (in USD) the owner sets + - @param ctx context.Context - for authentication, logging, cancellation, deadlines, tracing, etc. Passed from http.Request or context.Background(). + - @param body + - @param name + +@return string +*/ +func (a *NfdApiService) NfdSegmentLock(ctx context.Context, body SegmentLockRequestBody, name string) (string, *http.Response, error) { + var ( + localVarHttpMethod = strings.ToUpper("Post") + localVarPostBody interface{} + localVarFileName string + localVarFileBytes []byte + localVarReturnValue string + ) + + // create path and map variables + localVarPath := a.client.cfg.BasePath + "/nfd/segment/lock/{name}" + localVarPath = strings.Replace(localVarPath, "{"+"name"+"}", fmt.Sprintf("%v", name), -1) + + localVarHeaderParams := make(map[string]string) + localVarQueryParams := url.Values{} + localVarFormParams := url.Values{} + if strlen(name) < 1 { + return localVarReturnValue, nil, reportError("name must have at least 1 elements") + } + if strlen(name) > 120 { + return localVarReturnValue, nil, reportError("name must have less than 120 elements") + } + + // to determine the Content-Type header + localVarHttpContentTypes := []string{"application/json"} + + // set Content-Type header + localVarHttpContentType := selectHeaderContentType(localVarHttpContentTypes) + if localVarHttpContentType != "" { + localVarHeaderParams["Content-Type"] = localVarHttpContentType + } + + // to determine the Accept header + localVarHttpHeaderAccepts := []string{"application/json", "application/vnd.goa.error"} + + // set Accept header + localVarHttpHeaderAccept := selectHeaderAccept(localVarHttpHeaderAccepts) + if localVarHttpHeaderAccept != "" { + localVarHeaderParams["Accept"] = localVarHttpHeaderAccept + } + // body params + localVarPostBody = &body + r, err := a.client.prepareRequest(ctx, localVarPath, localVarHttpMethod, localVarPostBody, localVarHeaderParams, localVarQueryParams, localVarFormParams, localVarFileName, localVarFileBytes) + if err != nil { + return localVarReturnValue, nil, err + } + + localVarHttpResponse, err := a.client.callAPI(r) + if err != nil || localVarHttpResponse == nil { + return localVarReturnValue, localVarHttpResponse, err + } + + localVarBody, err := ioutil.ReadAll(localVarHttpResponse.Body) + localVarHttpResponse.Body.Close() + if err != nil { + return localVarReturnValue, localVarHttpResponse, err + } + + if localVarHttpResponse.StatusCode < 300 { + // If we succeed, return the data, otherwise pass on to decode error. + err = a.client.decode(&localVarReturnValue, localVarBody, localVarHttpResponse.Header.Get("Content-Type")) + if err == nil { + return localVarReturnValue, localVarHttpResponse, err + } + } + + if localVarHttpResponse.StatusCode >= 300 { + newErr := GenericSwaggerError{ + body: localVarBody, + error: localVarHttpResponse.Status, + } + if localVarHttpResponse.StatusCode == 200 { + var v string + err = a.client.decode(&v, localVarBody, localVarHttpResponse.Header.Get("Content-Type")) + if err != nil { + newErr.error = err.Error() + return localVarReturnValue, localVarHttpResponse, newErr + } + newErr.model = v + return localVarReturnValue, localVarHttpResponse, newErr + } + if localVarHttpResponse.StatusCode == 400 { + var v ModelError + err = a.client.decode(&v, localVarBody, localVarHttpResponse.Header.Get("Content-Type")) + if err != nil { + newErr.error = err.Error() + return localVarReturnValue, localVarHttpResponse, newErr + } + newErr.model = v + return localVarReturnValue, localVarHttpResponse, newErr + } + if localVarHttpResponse.StatusCode == 404 { + var v ModelError + err = a.client.decode(&v, localVarBody, localVarHttpResponse.Header.Get("Content-Type")) + if err != nil { + newErr.error = err.Error() + return localVarReturnValue, localVarHttpResponse, newErr + } + newErr.model = v + return localVarReturnValue, localVarHttpResponse, newErr + } + if localVarHttpResponse.StatusCode == 429 { + var v RateLimited + err = a.client.decode(&v, localVarBody, localVarHttpResponse.Header.Get("Content-Type")) + if err != nil { + newErr.error = err.Error() + return localVarReturnValue, localVarHttpResponse, newErr + } + newErr.model = v + return localVarReturnValue, localVarHttpResponse, newErr + } + return localVarReturnValue, localVarHttpResponse, newErr + } + + return localVarReturnValue, localVarHttpResponse, nil +} + +/* +NfdApiService Returns cost to mint a named segment off a particular root. +Buyer is used for validation if segment is allowed to be minted (locked vs unlocked). Can pass full segment name, or just root. + - @param ctx context.Context - for authentication, logging, cancellation, deadlines, tracing, etc. Passed from http.Request or context.Background(). + - @param buyer Expected buyer of segment + - @param name + +@return SegmentPriceResponseBody +*/ +func (a *NfdApiService) NfdSegmentPrice(ctx context.Context, buyer string, name string) (SegmentPriceResponseBody, *http.Response, error) { + var ( + localVarHttpMethod = strings.ToUpper("Get") + localVarPostBody interface{} + localVarFileName string + localVarFileBytes []byte + localVarReturnValue SegmentPriceResponseBody + ) + + // create path and map variables + localVarPath := a.client.cfg.BasePath + "/nfd/segment/price/{name}" + localVarPath = strings.Replace(localVarPath, "{"+"name"+"}", fmt.Sprintf("%v", name), -1) + + localVarHeaderParams := make(map[string]string) + localVarQueryParams := url.Values{} + localVarFormParams := url.Values{} + if strlen(name) < 1 { + return localVarReturnValue, nil, reportError("name must have at least 1 elements") + } + if strlen(name) > 120 { + return localVarReturnValue, nil, reportError("name must have less than 120 elements") + } + + localVarQueryParams.Add("buyer", parameterToString(buyer, "")) + // to determine the Content-Type header + localVarHttpContentTypes := []string{} + + // set Content-Type header + localVarHttpContentType := selectHeaderContentType(localVarHttpContentTypes) + if localVarHttpContentType != "" { + localVarHeaderParams["Content-Type"] = localVarHttpContentType + } + + // to determine the Accept header + localVarHttpHeaderAccepts := []string{"application/json", "application/vnd.goa.error"} + + // set Accept header + localVarHttpHeaderAccept := selectHeaderAccept(localVarHttpHeaderAccepts) + if localVarHttpHeaderAccept != "" { + localVarHeaderParams["Accept"] = localVarHttpHeaderAccept + } + r, err := a.client.prepareRequest(ctx, localVarPath, localVarHttpMethod, localVarPostBody, localVarHeaderParams, localVarQueryParams, localVarFormParams, localVarFileName, localVarFileBytes) + if err != nil { + return localVarReturnValue, nil, err + } + + localVarHttpResponse, err := a.client.callAPI(r) + if err != nil || localVarHttpResponse == nil { + return localVarReturnValue, localVarHttpResponse, err + } + + localVarBody, err := ioutil.ReadAll(localVarHttpResponse.Body) + localVarHttpResponse.Body.Close() + if err != nil { + return localVarReturnValue, localVarHttpResponse, err + } + + if localVarHttpResponse.StatusCode < 300 { + // If we succeed, return the data, otherwise pass on to decode error. + err = a.client.decode(&localVarReturnValue, localVarBody, localVarHttpResponse.Header.Get("Content-Type")) + if err == nil { + return localVarReturnValue, localVarHttpResponse, err + } + } + + if localVarHttpResponse.StatusCode >= 300 { + newErr := GenericSwaggerError{ + body: localVarBody, + error: localVarHttpResponse.Status, + } + if localVarHttpResponse.StatusCode == 200 { + var v SegmentPriceResponseBody + err = a.client.decode(&v, localVarBody, localVarHttpResponse.Header.Get("Content-Type")) + if err != nil { + newErr.error = err.Error() + return localVarReturnValue, localVarHttpResponse, newErr + } + newErr.model = v + return localVarReturnValue, localVarHttpResponse, newErr + } + if localVarHttpResponse.StatusCode == 400 { + var v ModelError + err = a.client.decode(&v, localVarBody, localVarHttpResponse.Header.Get("Content-Type")) + if err != nil { + newErr.error = err.Error() + return localVarReturnValue, localVarHttpResponse, newErr + } + newErr.model = v + return localVarReturnValue, localVarHttpResponse, newErr + } + if localVarHttpResponse.StatusCode == 404 { + var v ModelError + err = a.client.decode(&v, localVarBody, localVarHttpResponse.Header.Get("Content-Type")) + if err != nil { + newErr.error = err.Error() + return localVarReturnValue, localVarHttpResponse, newErr + } + newErr.model = v + return localVarReturnValue, localVarHttpResponse, newErr + } + if localVarHttpResponse.StatusCode == 429 { + var v RateLimited + err = a.client.decode(&v, localVarBody, localVarHttpResponse.Header.Get("Content-Type")) + if err != nil { + newErr.error = err.Error() + return localVarReturnValue, localVarHttpResponse, newErr + } + newErr.model = v + return localVarReturnValue, localVarHttpResponse, newErr + } + return localVarReturnValue, localVarHttpResponse, newErr + } + + return localVarReturnValue, localVarHttpResponse, nil +} + +/* +NfdApiService sendFromVault nfd +Send an amount of an asset [0 == ALGO] to another account FROM the NFD Vault. Only owner of NFD can send. + - @param ctx context.Context - for authentication, logging, cancellation, deadlines, tracing, etc. Passed from http.Request or context.Background(). + - @param body + - @param name + +@return string +*/ +func (a *NfdApiService) NfdSendFromVault(ctx context.Context, body SendFromVaultRequestBody, name string) (string, *http.Response, error) { + var ( + localVarHttpMethod = strings.ToUpper("Post") + localVarPostBody interface{} + localVarFileName string + localVarFileBytes []byte + localVarReturnValue string + ) + + // create path and map variables + localVarPath := a.client.cfg.BasePath + "/nfd/vault/sendFrom/{name}" + localVarPath = strings.Replace(localVarPath, "{"+"name"+"}", fmt.Sprintf("%v", name), -1) + + localVarHeaderParams := make(map[string]string) + localVarQueryParams := url.Values{} + localVarFormParams := url.Values{} + if strlen(name) < 1 { + return localVarReturnValue, nil, reportError("name must have at least 1 elements") + } + if strlen(name) > 120 { + return localVarReturnValue, nil, reportError("name must have less than 120 elements") + } + + // to determine the Content-Type header + localVarHttpContentTypes := []string{"application/json"} + + // set Content-Type header + localVarHttpContentType := selectHeaderContentType(localVarHttpContentTypes) + if localVarHttpContentType != "" { + localVarHeaderParams["Content-Type"] = localVarHttpContentType + } + + // to determine the Accept header + localVarHttpHeaderAccepts := []string{"application/json", "application/vnd.goa.error"} + + // set Accept header + localVarHttpHeaderAccept := selectHeaderAccept(localVarHttpHeaderAccepts) + if localVarHttpHeaderAccept != "" { + localVarHeaderParams["Accept"] = localVarHttpHeaderAccept + } + // body params + localVarPostBody = &body + r, err := a.client.prepareRequest(ctx, localVarPath, localVarHttpMethod, localVarPostBody, localVarHeaderParams, localVarQueryParams, localVarFormParams, localVarFileName, localVarFileBytes) + if err != nil { + return localVarReturnValue, nil, err + } + + localVarHttpResponse, err := a.client.callAPI(r) + if err != nil || localVarHttpResponse == nil { + return localVarReturnValue, localVarHttpResponse, err + } + + localVarBody, err := ioutil.ReadAll(localVarHttpResponse.Body) + localVarHttpResponse.Body.Close() + if err != nil { + return localVarReturnValue, localVarHttpResponse, err + } + + if localVarHttpResponse.StatusCode < 300 { + // If we succeed, return the data, otherwise pass on to decode error. + err = a.client.decode(&localVarReturnValue, localVarBody, localVarHttpResponse.Header.Get("Content-Type")) + if err == nil { + return localVarReturnValue, localVarHttpResponse, err + } + } + + if localVarHttpResponse.StatusCode >= 300 { + newErr := GenericSwaggerError{ + body: localVarBody, + error: localVarHttpResponse.Status, + } + if localVarHttpResponse.StatusCode == 200 { + var v string + err = a.client.decode(&v, localVarBody, localVarHttpResponse.Header.Get("Content-Type")) + if err != nil { + newErr.error = err.Error() + return localVarReturnValue, localVarHttpResponse, newErr + } + newErr.model = v + return localVarReturnValue, localVarHttpResponse, newErr + } + if localVarHttpResponse.StatusCode == 400 { + var v ModelError + err = a.client.decode(&v, localVarBody, localVarHttpResponse.Header.Get("Content-Type")) + if err != nil { + newErr.error = err.Error() + return localVarReturnValue, localVarHttpResponse, newErr + } + newErr.model = v + return localVarReturnValue, localVarHttpResponse, newErr + } + if localVarHttpResponse.StatusCode == 403 { + var v ModelError + err = a.client.decode(&v, localVarBody, localVarHttpResponse.Header.Get("Content-Type")) + if err != nil { + newErr.error = err.Error() + return localVarReturnValue, localVarHttpResponse, newErr + } + newErr.model = v + return localVarReturnValue, localVarHttpResponse, newErr + } + if localVarHttpResponse.StatusCode == 404 { + var v ModelError + err = a.client.decode(&v, localVarBody, localVarHttpResponse.Header.Get("Content-Type")) + if err != nil { + newErr.error = err.Error() + return localVarReturnValue, localVarHttpResponse, newErr + } + newErr.model = v + return localVarReturnValue, localVarHttpResponse, newErr + } + if localVarHttpResponse.StatusCode == 429 { + var v RateLimited + err = a.client.decode(&v, localVarBody, localVarHttpResponse.Header.Get("Content-Type")) + if err != nil { + newErr.error = err.Error() + return localVarReturnValue, localVarHttpResponse, newErr + } + newErr.model = v + return localVarReturnValue, localVarHttpResponse, newErr + } + return localVarReturnValue, localVarHttpResponse, newErr + } + + return localVarReturnValue, localVarHttpResponse, nil +} + +/* +NfdApiService sendToVault nfd +Provide transaction to send an asset owned by sender account to an NFD vault. Call to have opt-in to vault will be included if necessary. Callable by NFD owner, or if Opt-in is UNLOCKED (or asset already opted-in), anyone can call + - @param ctx context.Context - for authentication, logging, cancellation, deadlines, tracing, etc. Passed from http.Request or context.Background(). + - @param body + - @param name + +@return string +*/ +func (a *NfdApiService) NfdSendToVault(ctx context.Context, body SendToVaultRequestBody, name string) (string, *http.Response, error) { + var ( + localVarHttpMethod = strings.ToUpper("Post") + localVarPostBody interface{} + localVarFileName string + localVarFileBytes []byte + localVarReturnValue string + ) + + // create path and map variables + localVarPath := a.client.cfg.BasePath + "/nfd/vault/sendTo/{name}" + localVarPath = strings.Replace(localVarPath, "{"+"name"+"}", fmt.Sprintf("%v", name), -1) + + localVarHeaderParams := make(map[string]string) + localVarQueryParams := url.Values{} + localVarFormParams := url.Values{} + if strlen(name) < 1 { + return localVarReturnValue, nil, reportError("name must have at least 1 elements") + } + if strlen(name) > 120 { + return localVarReturnValue, nil, reportError("name must have less than 120 elements") + } + + // to determine the Content-Type header + localVarHttpContentTypes := []string{"application/json"} + + // set Content-Type header + localVarHttpContentType := selectHeaderContentType(localVarHttpContentTypes) + if localVarHttpContentType != "" { + localVarHeaderParams["Content-Type"] = localVarHttpContentType + } + + // to determine the Accept header + localVarHttpHeaderAccepts := []string{"application/json", "application/vnd.goa.error"} + + // set Accept header + localVarHttpHeaderAccept := selectHeaderAccept(localVarHttpHeaderAccepts) + if localVarHttpHeaderAccept != "" { + localVarHeaderParams["Accept"] = localVarHttpHeaderAccept + } + // body params + localVarPostBody = &body + r, err := a.client.prepareRequest(ctx, localVarPath, localVarHttpMethod, localVarPostBody, localVarHeaderParams, localVarQueryParams, localVarFormParams, localVarFileName, localVarFileBytes) + if err != nil { + return localVarReturnValue, nil, err + } + + localVarHttpResponse, err := a.client.callAPI(r) + if err != nil || localVarHttpResponse == nil { + return localVarReturnValue, localVarHttpResponse, err + } + + localVarBody, err := ioutil.ReadAll(localVarHttpResponse.Body) + localVarHttpResponse.Body.Close() + if err != nil { + return localVarReturnValue, localVarHttpResponse, err + } + + if localVarHttpResponse.StatusCode < 300 { + // If we succeed, return the data, otherwise pass on to decode error. + err = a.client.decode(&localVarReturnValue, localVarBody, localVarHttpResponse.Header.Get("Content-Type")) + if err == nil { + return localVarReturnValue, localVarHttpResponse, err + } + } + + if localVarHttpResponse.StatusCode >= 300 { + newErr := GenericSwaggerError{ + body: localVarBody, + error: localVarHttpResponse.Status, + } + if localVarHttpResponse.StatusCode == 200 { + var v string + err = a.client.decode(&v, localVarBody, localVarHttpResponse.Header.Get("Content-Type")) + if err != nil { + newErr.error = err.Error() + return localVarReturnValue, localVarHttpResponse, newErr + } + newErr.model = v + return localVarReturnValue, localVarHttpResponse, newErr + } + if localVarHttpResponse.StatusCode == 400 { + var v ModelError + err = a.client.decode(&v, localVarBody, localVarHttpResponse.Header.Get("Content-Type")) + if err != nil { + newErr.error = err.Error() + return localVarReturnValue, localVarHttpResponse, newErr + } + newErr.model = v + return localVarReturnValue, localVarHttpResponse, newErr + } + if localVarHttpResponse.StatusCode == 403 { + var v ModelError + err = a.client.decode(&v, localVarBody, localVarHttpResponse.Header.Get("Content-Type")) + if err != nil { + newErr.error = err.Error() + return localVarReturnValue, localVarHttpResponse, newErr + } + newErr.model = v + return localVarReturnValue, localVarHttpResponse, newErr + } + if localVarHttpResponse.StatusCode == 404 { + var v ModelError + err = a.client.decode(&v, localVarBody, localVarHttpResponse.Header.Get("Content-Type")) + if err != nil { + newErr.error = err.Error() + return localVarReturnValue, localVarHttpResponse, newErr + } + newErr.model = v + return localVarReturnValue, localVarHttpResponse, newErr + } + if localVarHttpResponse.StatusCode == 413 { + var v ModelError + err = a.client.decode(&v, localVarBody, localVarHttpResponse.Header.Get("Content-Type")) + if err != nil { + newErr.error = err.Error() + return localVarReturnValue, localVarHttpResponse, newErr + } + newErr.model = v + return localVarReturnValue, localVarHttpResponse, newErr + } + if localVarHttpResponse.StatusCode == 429 { + var v RateLimited + err = a.client.decode(&v, localVarBody, localVarHttpResponse.Header.Get("Content-Type")) + if err != nil { + newErr.error = err.Error() + return localVarReturnValue, localVarHttpResponse, newErr + } + newErr.model = v + return localVarReturnValue, localVarHttpResponse, newErr + } + return localVarReturnValue, localVarHttpResponse, newErr + } + + return localVarReturnValue, localVarHttpResponse, nil +} + +/* +NfdApiService setPrimaryAddress nfd +Set which of the currently verified addresses should be the first in the list (swapping positions as necessary) + - @param ctx context.Context - for authentication, logging, cancellation, deadlines, tracing, etc. Passed from http.Request or context.Background(). + - @param body + - @param name + +@return string +*/ +func (a *NfdApiService) NfdSetPrimaryAddress(ctx context.Context, body SetPrimaryAddressRequestBody, name string) (string, *http.Response, error) { + var ( + localVarHttpMethod = strings.ToUpper("Post") + localVarPostBody interface{} + localVarFileName string + localVarFileBytes []byte + localVarReturnValue string + ) + + // create path and map variables + localVarPath := a.client.cfg.BasePath + "/nfd/links/setPrimaryAddress/{name}" + localVarPath = strings.Replace(localVarPath, "{"+"name"+"}", fmt.Sprintf("%v", name), -1) + + localVarHeaderParams := make(map[string]string) + localVarQueryParams := url.Values{} + localVarFormParams := url.Values{} + if strlen(name) < 1 { + return localVarReturnValue, nil, reportError("name must have at least 1 elements") + } + if strlen(name) > 120 { + return localVarReturnValue, nil, reportError("name must have less than 120 elements") + } + + // to determine the Content-Type header + localVarHttpContentTypes := []string{"application/json"} + + // set Content-Type header + localVarHttpContentType := selectHeaderContentType(localVarHttpContentTypes) + if localVarHttpContentType != "" { + localVarHeaderParams["Content-Type"] = localVarHttpContentType + } + + // to determine the Accept header + localVarHttpHeaderAccepts := []string{"application/json", "application/vnd.goa.error"} + + // set Accept header + localVarHttpHeaderAccept := selectHeaderAccept(localVarHttpHeaderAccepts) + if localVarHttpHeaderAccept != "" { + localVarHeaderParams["Accept"] = localVarHttpHeaderAccept + } + // body params + localVarPostBody = &body + r, err := a.client.prepareRequest(ctx, localVarPath, localVarHttpMethod, localVarPostBody, localVarHeaderParams, localVarQueryParams, localVarFormParams, localVarFileName, localVarFileBytes) + if err != nil { + return localVarReturnValue, nil, err + } + + localVarHttpResponse, err := a.client.callAPI(r) + if err != nil || localVarHttpResponse == nil { + return localVarReturnValue, localVarHttpResponse, err + } + + localVarBody, err := ioutil.ReadAll(localVarHttpResponse.Body) + localVarHttpResponse.Body.Close() + if err != nil { + return localVarReturnValue, localVarHttpResponse, err + } + + if localVarHttpResponse.StatusCode < 300 { + // If we succeed, return the data, otherwise pass on to decode error. + err = a.client.decode(&localVarReturnValue, localVarBody, localVarHttpResponse.Header.Get("Content-Type")) + if err == nil { + return localVarReturnValue, localVarHttpResponse, err + } + } + + if localVarHttpResponse.StatusCode >= 300 { + newErr := GenericSwaggerError{ + body: localVarBody, + error: localVarHttpResponse.Status, + } + if localVarHttpResponse.StatusCode == 202 { + var v string + err = a.client.decode(&v, localVarBody, localVarHttpResponse.Header.Get("Content-Type")) + if err != nil { + newErr.error = err.Error() + return localVarReturnValue, localVarHttpResponse, newErr + } + newErr.model = v + return localVarReturnValue, localVarHttpResponse, newErr + } + if localVarHttpResponse.StatusCode == 400 { + var v ModelError + err = a.client.decode(&v, localVarBody, localVarHttpResponse.Header.Get("Content-Type")) + if err != nil { + newErr.error = err.Error() + return localVarReturnValue, localVarHttpResponse, newErr + } + newErr.model = v + return localVarReturnValue, localVarHttpResponse, newErr + } + if localVarHttpResponse.StatusCode == 403 { + var v ModelError + err = a.client.decode(&v, localVarBody, localVarHttpResponse.Header.Get("Content-Type")) + if err != nil { + newErr.error = err.Error() + return localVarReturnValue, localVarHttpResponse, newErr + } + newErr.model = v + return localVarReturnValue, localVarHttpResponse, newErr + } + if localVarHttpResponse.StatusCode == 404 { + var v ModelError + err = a.client.decode(&v, localVarBody, localVarHttpResponse.Header.Get("Content-Type")) + if err != nil { + newErr.error = err.Error() + return localVarReturnValue, localVarHttpResponse, newErr + } + newErr.model = v + return localVarReturnValue, localVarHttpResponse, newErr + } + if localVarHttpResponse.StatusCode == 429 { + var v RateLimited + err = a.client.decode(&v, localVarBody, localVarHttpResponse.Header.Get("Content-Type")) + if err != nil { + newErr.error = err.Error() + return localVarReturnValue, localVarHttpResponse, newErr + } + newErr.model = v + return localVarReturnValue, localVarHttpResponse, newErr + } + return localVarReturnValue, localVarHttpResponse, newErr + } + + return localVarReturnValue, localVarHttpResponse, nil +} + +/* +NfdApiService setPrimaryNFD nfd +Set the specified NFD as the primary NFD to return for the specified address via its reverse lookup + - @param ctx context.Context - for authentication, logging, cancellation, deadlines, tracing, etc. Passed from http.Request or context.Background(). + - @param body + - @param name + +@return string +*/ +func (a *NfdApiService) NfdSetPrimaryNFD(ctx context.Context, body SetPrimaryAddressRequestBody, name string) (string, *http.Response, error) { + var ( + localVarHttpMethod = strings.ToUpper("Post") + localVarPostBody interface{} + localVarFileName string + localVarFileBytes []byte + localVarReturnValue string + ) + + // create path and map variables + localVarPath := a.client.cfg.BasePath + "/nfd/links/setPrimaryNFD/{name}" + localVarPath = strings.Replace(localVarPath, "{"+"name"+"}", fmt.Sprintf("%v", name), -1) + + localVarHeaderParams := make(map[string]string) + localVarQueryParams := url.Values{} + localVarFormParams := url.Values{} + if strlen(name) < 1 { + return localVarReturnValue, nil, reportError("name must have at least 1 elements") + } + if strlen(name) > 120 { + return localVarReturnValue, nil, reportError("name must have less than 120 elements") + } + + // to determine the Content-Type header + localVarHttpContentTypes := []string{"application/json"} + + // set Content-Type header + localVarHttpContentType := selectHeaderContentType(localVarHttpContentTypes) + if localVarHttpContentType != "" { + localVarHeaderParams["Content-Type"] = localVarHttpContentType + } + + // to determine the Accept header + localVarHttpHeaderAccepts := []string{"application/json", "application/vnd.goa.error"} + + // set Accept header + localVarHttpHeaderAccept := selectHeaderAccept(localVarHttpHeaderAccepts) + if localVarHttpHeaderAccept != "" { + localVarHeaderParams["Accept"] = localVarHttpHeaderAccept + } + // body params + localVarPostBody = &body + r, err := a.client.prepareRequest(ctx, localVarPath, localVarHttpMethod, localVarPostBody, localVarHeaderParams, localVarQueryParams, localVarFormParams, localVarFileName, localVarFileBytes) + if err != nil { + return localVarReturnValue, nil, err + } + + localVarHttpResponse, err := a.client.callAPI(r) + if err != nil || localVarHttpResponse == nil { + return localVarReturnValue, localVarHttpResponse, err + } + + localVarBody, err := ioutil.ReadAll(localVarHttpResponse.Body) + localVarHttpResponse.Body.Close() + if err != nil { + return localVarReturnValue, localVarHttpResponse, err + } + + if localVarHttpResponse.StatusCode < 300 { + // If we succeed, return the data, otherwise pass on to decode error. + err = a.client.decode(&localVarReturnValue, localVarBody, localVarHttpResponse.Header.Get("Content-Type")) + if err == nil { + return localVarReturnValue, localVarHttpResponse, err + } + } + + if localVarHttpResponse.StatusCode >= 300 { + newErr := GenericSwaggerError{ + body: localVarBody, + error: localVarHttpResponse.Status, + } + if localVarHttpResponse.StatusCode == 202 { + var v string + err = a.client.decode(&v, localVarBody, localVarHttpResponse.Header.Get("Content-Type")) + if err != nil { + newErr.error = err.Error() + return localVarReturnValue, localVarHttpResponse, newErr + } + newErr.model = v + return localVarReturnValue, localVarHttpResponse, newErr + } + if localVarHttpResponse.StatusCode == 400 { + var v ModelError + err = a.client.decode(&v, localVarBody, localVarHttpResponse.Header.Get("Content-Type")) + if err != nil { + newErr.error = err.Error() + return localVarReturnValue, localVarHttpResponse, newErr + } + newErr.model = v + return localVarReturnValue, localVarHttpResponse, newErr + } + if localVarHttpResponse.StatusCode == 403 { + var v ModelError + err = a.client.decode(&v, localVarBody, localVarHttpResponse.Header.Get("Content-Type")) + if err != nil { + newErr.error = err.Error() + return localVarReturnValue, localVarHttpResponse, newErr + } + newErr.model = v + return localVarReturnValue, localVarHttpResponse, newErr + } + if localVarHttpResponse.StatusCode == 404 { + var v ModelError + err = a.client.decode(&v, localVarBody, localVarHttpResponse.Header.Get("Content-Type")) + if err != nil { + newErr.error = err.Error() + return localVarReturnValue, localVarHttpResponse, newErr + } + newErr.model = v + return localVarReturnValue, localVarHttpResponse, newErr + } + if localVarHttpResponse.StatusCode == 429 { + var v RateLimited + err = a.client.decode(&v, localVarBody, localVarHttpResponse.Header.Get("Content-Type")) + if err != nil { + newErr.error = err.Error() + return localVarReturnValue, localVarHttpResponse, newErr + } + newErr.model = v + return localVarReturnValue, localVarHttpResponse, newErr + } + return localVarReturnValue, localVarHttpResponse, newErr + } + + return localVarReturnValue, localVarHttpResponse, nil +} + +/* +NfdApiService suggest nfd +Suggest NFDs to purchase + * @param ctx context.Context - for authentication, logging, cancellation, deadlines, tracing, etc. Passed from http.Request or context.Background(). + * @param name A name (even partial) to search for [receiving suggestions as well] + * @param optional nil or *NfdApiNfdSuggestOpts - Optional Parameters: + * @param "Limit" (optional.Int64) - Limit the number of results returned - max 40 + * @param "View" (optional.String) - View of data to return, brief (default), or full + * @param "Buyer" (optional.String) - Expected buyer of name. Used for segment minting as additional check on availability of mint +@return []NfdRecord +*/ + +type NfdApiNfdSuggestOpts struct { + Limit optional.Int64 + View optional.String + Buyer optional.String +} + +func (a *NfdApiService) NfdSuggest(ctx context.Context, name string, localVarOptionals *NfdApiNfdSuggestOpts) ([]NfdRecord, *http.Response, error) { + var ( + localVarHttpMethod = strings.ToUpper("Get") + localVarPostBody interface{} + localVarFileName string + localVarFileBytes []byte + localVarReturnValue []NfdRecord + ) + + // create path and map variables + localVarPath := a.client.cfg.BasePath + "/nfd/suggest/{name}" + localVarPath = strings.Replace(localVarPath, "{"+"name"+"}", fmt.Sprintf("%v", name), -1) + + localVarHeaderParams := make(map[string]string) + localVarQueryParams := url.Values{} + localVarFormParams := url.Values{} + if strlen(name) > 60 { + return localVarReturnValue, nil, reportError("name must have less than 60 elements") + } + + if localVarOptionals != nil && localVarOptionals.Limit.IsSet() { + localVarQueryParams.Add("limit", parameterToString(localVarOptionals.Limit.Value(), "")) + } + if localVarOptionals != nil && localVarOptionals.View.IsSet() { + localVarQueryParams.Add("view", parameterToString(localVarOptionals.View.Value(), "")) + } + if localVarOptionals != nil && localVarOptionals.Buyer.IsSet() { + localVarQueryParams.Add("buyer", parameterToString(localVarOptionals.Buyer.Value(), "")) + } + // to determine the Content-Type header + localVarHttpContentTypes := []string{} + + // set Content-Type header + localVarHttpContentType := selectHeaderContentType(localVarHttpContentTypes) + if localVarHttpContentType != "" { + localVarHeaderParams["Content-Type"] = localVarHttpContentType + } + + // to determine the Accept header + localVarHttpHeaderAccepts := []string{"application/json", "application/vnd.goa.error"} + + // set Accept header + localVarHttpHeaderAccept := selectHeaderAccept(localVarHttpHeaderAccepts) + if localVarHttpHeaderAccept != "" { + localVarHeaderParams["Accept"] = localVarHttpHeaderAccept + } + r, err := a.client.prepareRequest(ctx, localVarPath, localVarHttpMethod, localVarPostBody, localVarHeaderParams, localVarQueryParams, localVarFormParams, localVarFileName, localVarFileBytes) + if err != nil { + return localVarReturnValue, nil, err + } + + localVarHttpResponse, err := a.client.callAPI(r) + if err != nil || localVarHttpResponse == nil { + return localVarReturnValue, localVarHttpResponse, err + } + + localVarBody, err := ioutil.ReadAll(localVarHttpResponse.Body) + localVarHttpResponse.Body.Close() + if err != nil { + return localVarReturnValue, localVarHttpResponse, err + } + + if localVarHttpResponse.StatusCode < 300 { + // If we succeed, return the data, otherwise pass on to decode error. + err = a.client.decode(&localVarReturnValue, localVarBody, localVarHttpResponse.Header.Get("Content-Type")) + if err == nil { + return localVarReturnValue, localVarHttpResponse, err + } + } + + if localVarHttpResponse.StatusCode >= 300 { + newErr := GenericSwaggerError{ + body: localVarBody, + error: localVarHttpResponse.Status, + } + if localVarHttpResponse.StatusCode == 200 { + var v []NfdRecord + err = a.client.decode(&v, localVarBody, localVarHttpResponse.Header.Get("Content-Type")) + if err != nil { + newErr.error = err.Error() + return localVarReturnValue, localVarHttpResponse, newErr + } + newErr.model = v + return localVarReturnValue, localVarHttpResponse, newErr + } + if localVarHttpResponse.StatusCode == 400 { + var v ModelError + err = a.client.decode(&v, localVarBody, localVarHttpResponse.Header.Get("Content-Type")) + if err != nil { + newErr.error = err.Error() + return localVarReturnValue, localVarHttpResponse, newErr + } + newErr.model = v + return localVarReturnValue, localVarHttpResponse, newErr + } + if localVarHttpResponse.StatusCode == 404 { + var v ModelError + err = a.client.decode(&v, localVarBody, localVarHttpResponse.Header.Get("Content-Type")) + if err != nil { + newErr.error = err.Error() + return localVarReturnValue, localVarHttpResponse, newErr + } + newErr.model = v + return localVarReturnValue, localVarHttpResponse, newErr + } + if localVarHttpResponse.StatusCode == 429 { + var v RateLimited + err = a.client.decode(&v, localVarBody, localVarHttpResponse.Header.Get("Content-Type")) + if err != nil { + newErr.error = err.Error() + return localVarReturnValue, localVarHttpResponse, newErr + } + newErr.model = v + return localVarReturnValue, localVarHttpResponse, newErr + } + return localVarReturnValue, localVarHttpResponse, newErr + } + + return localVarReturnValue, localVarHttpResponse, nil +} + +/* +NfdApiService totals nfd +Fetch NFD summary data - results subject to change in the future + * @param ctx context.Context - for authentication, logging, cancellation, deadlines, tracing, etc. Passed from http.Request or context.Background(). + * @param optional nil or *NfdApiNfdTotalsOpts - Optional Parameters: + * @param "IfNoneMatch" (optional.String) - etag +@return TotalsOkResponseBody +*/ + +type NfdApiNfdTotalsOpts struct { + IfNoneMatch optional.String +} + +func (a *NfdApiService) NfdTotals(ctx context.Context, localVarOptionals *NfdApiNfdTotalsOpts) (TotalsOkResponseBody, *http.Response, error) { + var ( + localVarHttpMethod = strings.ToUpper("Get") + localVarPostBody interface{} + localVarFileName string + localVarFileBytes []byte + localVarReturnValue TotalsOkResponseBody + ) + + // create path and map variables + localVarPath := a.client.cfg.BasePath + "/nfd/totals" + + localVarHeaderParams := make(map[string]string) + localVarQueryParams := url.Values{} + localVarFormParams := url.Values{} + + // to determine the Content-Type header + localVarHttpContentTypes := []string{} + + // set Content-Type header + localVarHttpContentType := selectHeaderContentType(localVarHttpContentTypes) + if localVarHttpContentType != "" { + localVarHeaderParams["Content-Type"] = localVarHttpContentType + } + + // to determine the Accept header + localVarHttpHeaderAccepts := []string{"application/json", "application/vnd.goa.error"} + + // set Accept header + localVarHttpHeaderAccept := selectHeaderAccept(localVarHttpHeaderAccepts) + if localVarHttpHeaderAccept != "" { + localVarHeaderParams["Accept"] = localVarHttpHeaderAccept + } + if localVarOptionals != nil && localVarOptionals.IfNoneMatch.IsSet() { + localVarHeaderParams["if-none-match"] = parameterToString(localVarOptionals.IfNoneMatch.Value(), "") + } + r, err := a.client.prepareRequest(ctx, localVarPath, localVarHttpMethod, localVarPostBody, localVarHeaderParams, localVarQueryParams, localVarFormParams, localVarFileName, localVarFileBytes) + if err != nil { + return localVarReturnValue, nil, err + } + + localVarHttpResponse, err := a.client.callAPI(r) + if err != nil || localVarHttpResponse == nil { + return localVarReturnValue, localVarHttpResponse, err + } + + localVarBody, err := ioutil.ReadAll(localVarHttpResponse.Body) + localVarHttpResponse.Body.Close() + if err != nil { + return localVarReturnValue, localVarHttpResponse, err + } + + if localVarHttpResponse.StatusCode < 300 { + // If we succeed, return the data, otherwise pass on to decode error. + err = a.client.decode(&localVarReturnValue, localVarBody, localVarHttpResponse.Header.Get("Content-Type")) + if err == nil { + return localVarReturnValue, localVarHttpResponse, err + } + } + + if localVarHttpResponse.StatusCode >= 300 { + newErr := GenericSwaggerError{ + body: localVarBody, + error: localVarHttpResponse.Status, + } + if localVarHttpResponse.StatusCode == 200 { + var v TotalsOkResponseBody + err = a.client.decode(&v, localVarBody, localVarHttpResponse.Header.Get("Content-Type")) + if err != nil { + newErr.error = err.Error() + return localVarReturnValue, localVarHttpResponse, newErr + } + newErr.model = v + return localVarReturnValue, localVarHttpResponse, newErr + } + if localVarHttpResponse.StatusCode == 400 { + var v ModelError + err = a.client.decode(&v, localVarBody, localVarHttpResponse.Header.Get("Content-Type")) + if err != nil { + newErr.error = err.Error() + return localVarReturnValue, localVarHttpResponse, newErr + } + newErr.model = v + return localVarReturnValue, localVarHttpResponse, newErr + } + if localVarHttpResponse.StatusCode == 404 { + var v ModelError + err = a.client.decode(&v, localVarBody, localVarHttpResponse.Header.Get("Content-Type")) + if err != nil { + newErr.error = err.Error() + return localVarReturnValue, localVarHttpResponse, newErr + } + newErr.model = v + return localVarReturnValue, localVarHttpResponse, newErr + } + if localVarHttpResponse.StatusCode == 429 { + var v RateLimited + err = a.client.decode(&v, localVarBody, localVarHttpResponse.Header.Get("Content-Type")) + if err != nil { + newErr.error = err.Error() + return localVarReturnValue, localVarHttpResponse, newErr + } + newErr.model = v + return localVarReturnValue, localVarHttpResponse, newErr + } + return localVarReturnValue, localVarHttpResponse, newErr + } + + return localVarReturnValue, localVarHttpResponse, nil +} + +/* +NfdApiService twitterLeaders nfd +Get top twitter influencers + * @param ctx context.Context - for authentication, logging, cancellation, deadlines, tracing, etc. Passed from http.Request or context.Background(). + * @param optional nil or *NfdApiNfdTwitterLeadersOpts - Optional Parameters: + * @param "IfNoneMatch" (optional.String) - etag +@return []TwitterRecord +*/ + +type NfdApiNfdTwitterLeadersOpts struct { + IfNoneMatch optional.String +} + +func (a *NfdApiService) NfdTwitterLeaders(ctx context.Context, localVarOptionals *NfdApiNfdTwitterLeadersOpts) ([]TwitterRecord, *http.Response, error) { + var ( + localVarHttpMethod = strings.ToUpper("Get") + localVarPostBody interface{} + localVarFileName string + localVarFileBytes []byte + localVarReturnValue []TwitterRecord + ) + + // create path and map variables + localVarPath := a.client.cfg.BasePath + "/nfd/twitter/leaders" + + localVarHeaderParams := make(map[string]string) + localVarQueryParams := url.Values{} + localVarFormParams := url.Values{} + + // to determine the Content-Type header + localVarHttpContentTypes := []string{} + + // set Content-Type header + localVarHttpContentType := selectHeaderContentType(localVarHttpContentTypes) + if localVarHttpContentType != "" { + localVarHeaderParams["Content-Type"] = localVarHttpContentType + } + + // to determine the Accept header + localVarHttpHeaderAccepts := []string{"application/json", "application/vnd.goa.error"} + + // set Accept header + localVarHttpHeaderAccept := selectHeaderAccept(localVarHttpHeaderAccepts) + if localVarHttpHeaderAccept != "" { + localVarHeaderParams["Accept"] = localVarHttpHeaderAccept + } + if localVarOptionals != nil && localVarOptionals.IfNoneMatch.IsSet() { + localVarHeaderParams["if-none-match"] = parameterToString(localVarOptionals.IfNoneMatch.Value(), "") + } + r, err := a.client.prepareRequest(ctx, localVarPath, localVarHttpMethod, localVarPostBody, localVarHeaderParams, localVarQueryParams, localVarFormParams, localVarFileName, localVarFileBytes) + if err != nil { + return localVarReturnValue, nil, err + } + + localVarHttpResponse, err := a.client.callAPI(r) + if err != nil || localVarHttpResponse == nil { + return localVarReturnValue, localVarHttpResponse, err + } + + localVarBody, err := ioutil.ReadAll(localVarHttpResponse.Body) + localVarHttpResponse.Body.Close() + if err != nil { + return localVarReturnValue, localVarHttpResponse, err + } + + if localVarHttpResponse.StatusCode < 300 { + // If we succeed, return the data, otherwise pass on to decode error. + err = a.client.decode(&localVarReturnValue, localVarBody, localVarHttpResponse.Header.Get("Content-Type")) + if err == nil { + return localVarReturnValue, localVarHttpResponse, err + } + } + + if localVarHttpResponse.StatusCode >= 300 { + newErr := GenericSwaggerError{ + body: localVarBody, + error: localVarHttpResponse.Status, + } + if localVarHttpResponse.StatusCode == 200 { + var v []TwitterRecord + err = a.client.decode(&v, localVarBody, localVarHttpResponse.Header.Get("Content-Type")) + if err != nil { + newErr.error = err.Error() + return localVarReturnValue, localVarHttpResponse, newErr + } + newErr.model = v + return localVarReturnValue, localVarHttpResponse, newErr + } + if localVarHttpResponse.StatusCode == 400 { + var v ModelError + err = a.client.decode(&v, localVarBody, localVarHttpResponse.Header.Get("Content-Type")) + if err != nil { + newErr.error = err.Error() + return localVarReturnValue, localVarHttpResponse, newErr + } + newErr.model = v + return localVarReturnValue, localVarHttpResponse, newErr + } + if localVarHttpResponse.StatusCode == 404 { + var v ModelError + err = a.client.decode(&v, localVarBody, localVarHttpResponse.Header.Get("Content-Type")) + if err != nil { + newErr.error = err.Error() + return localVarReturnValue, localVarHttpResponse, newErr + } + newErr.model = v + return localVarReturnValue, localVarHttpResponse, newErr + } + if localVarHttpResponse.StatusCode == 429 { + var v RateLimited + err = a.client.decode(&v, localVarBody, localVarHttpResponse.Header.Get("Content-Type")) + if err != nil { + newErr.error = err.Error() + return localVarReturnValue, localVarHttpResponse, newErr + } + newErr.model = v + return localVarReturnValue, localVarHttpResponse, newErr + } + return localVarReturnValue, localVarHttpResponse, newErr + } + + return localVarReturnValue, localVarHttpResponse, nil +} + +/* +NfdApiService unlinkAddress nfd +UnLink one or more addresses to an NFD, adding to the reverse-address lookups as well as to this NFD. Sender must be owner, and each added address must be able to be signed for. + - @param ctx context.Context - for authentication, logging, cancellation, deadlines, tracing, etc. Passed from http.Request or context.Background(). + - @param body + - @param name + +@return string +*/ +func (a *NfdApiService) NfdUnlinkAddress(ctx context.Context, body LinkAddressRequestBody, name string) (string, *http.Response, error) { + var ( + localVarHttpMethod = strings.ToUpper("Post") + localVarPostBody interface{} + localVarFileName string + localVarFileBytes []byte + localVarReturnValue string + ) + + // create path and map variables + localVarPath := a.client.cfg.BasePath + "/nfd/links/removeAddress/{name}" + localVarPath = strings.Replace(localVarPath, "{"+"name"+"}", fmt.Sprintf("%v", name), -1) + + localVarHeaderParams := make(map[string]string) + localVarQueryParams := url.Values{} + localVarFormParams := url.Values{} + if strlen(name) < 1 { + return localVarReturnValue, nil, reportError("name must have at least 1 elements") + } + if strlen(name) > 120 { + return localVarReturnValue, nil, reportError("name must have less than 120 elements") + } + + // to determine the Content-Type header + localVarHttpContentTypes := []string{"application/json"} + + // set Content-Type header + localVarHttpContentType := selectHeaderContentType(localVarHttpContentTypes) + if localVarHttpContentType != "" { + localVarHeaderParams["Content-Type"] = localVarHttpContentType + } + + // to determine the Accept header + localVarHttpHeaderAccepts := []string{"application/json", "application/vnd.goa.error"} + + // set Accept header + localVarHttpHeaderAccept := selectHeaderAccept(localVarHttpHeaderAccepts) + if localVarHttpHeaderAccept != "" { + localVarHeaderParams["Accept"] = localVarHttpHeaderAccept + } + // body params + localVarPostBody = &body + r, err := a.client.prepareRequest(ctx, localVarPath, localVarHttpMethod, localVarPostBody, localVarHeaderParams, localVarQueryParams, localVarFormParams, localVarFileName, localVarFileBytes) + if err != nil { + return localVarReturnValue, nil, err + } + + localVarHttpResponse, err := a.client.callAPI(r) + if err != nil || localVarHttpResponse == nil { + return localVarReturnValue, localVarHttpResponse, err + } + + localVarBody, err := ioutil.ReadAll(localVarHttpResponse.Body) + localVarHttpResponse.Body.Close() + if err != nil { + return localVarReturnValue, localVarHttpResponse, err + } + + if localVarHttpResponse.StatusCode < 300 { + // If we succeed, return the data, otherwise pass on to decode error. + err = a.client.decode(&localVarReturnValue, localVarBody, localVarHttpResponse.Header.Get("Content-Type")) + if err == nil { + return localVarReturnValue, localVarHttpResponse, err + } + } + + if localVarHttpResponse.StatusCode >= 300 { + newErr := GenericSwaggerError{ + body: localVarBody, + error: localVarHttpResponse.Status, + } + if localVarHttpResponse.StatusCode == 202 { + var v string + err = a.client.decode(&v, localVarBody, localVarHttpResponse.Header.Get("Content-Type")) + if err != nil { + newErr.error = err.Error() + return localVarReturnValue, localVarHttpResponse, newErr + } + newErr.model = v + return localVarReturnValue, localVarHttpResponse, newErr + } + if localVarHttpResponse.StatusCode == 400 { + var v ModelError + err = a.client.decode(&v, localVarBody, localVarHttpResponse.Header.Get("Content-Type")) + if err != nil { + newErr.error = err.Error() + return localVarReturnValue, localVarHttpResponse, newErr + } + newErr.model = v + return localVarReturnValue, localVarHttpResponse, newErr + } + if localVarHttpResponse.StatusCode == 403 { + var v ModelError + err = a.client.decode(&v, localVarBody, localVarHttpResponse.Header.Get("Content-Type")) + if err != nil { + newErr.error = err.Error() + return localVarReturnValue, localVarHttpResponse, newErr + } + newErr.model = v + return localVarReturnValue, localVarHttpResponse, newErr + } + if localVarHttpResponse.StatusCode == 404 { + var v ModelError + err = a.client.decode(&v, localVarBody, localVarHttpResponse.Header.Get("Content-Type")) + if err != nil { + newErr.error = err.Error() + return localVarReturnValue, localVarHttpResponse, newErr + } + newErr.model = v + return localVarReturnValue, localVarHttpResponse, newErr + } + if localVarHttpResponse.StatusCode == 429 { + var v RateLimited + err = a.client.decode(&v, localVarBody, localVarHttpResponse.Header.Get("Content-Type")) + if err != nil { + newErr.error = err.Error() + return localVarReturnValue, localVarHttpResponse, newErr + } + newErr.model = v + return localVarReturnValue, localVarHttpResponse, newErr + } + return localVarReturnValue, localVarHttpResponse, newErr + } + + return localVarReturnValue, localVarHttpResponse, nil +} + +/* +NfdApiService updateAll nfd +Replace all NFD user-settable attributes with those passed-in, removing, adding and replacing on behalf of a particular sender (who must be the owner). Returns transaction group of transactions to sign + - @param ctx context.Context - for authentication, logging, cancellation, deadlines, tracing, etc. Passed from http.Request or context.Background(). + - @param body + - @param name + +@return string +*/ +func (a *NfdApiService) NfdUpdateAll(ctx context.Context, body UpdatePartialRequestBody, name string) (string, *http.Response, error) { + var ( + localVarHttpMethod = strings.ToUpper("Put") + localVarPostBody interface{} + localVarFileName string + localVarFileBytes []byte + localVarReturnValue string + ) + + // create path and map variables + localVarPath := a.client.cfg.BasePath + "/nfd/update/{name}" + localVarPath = strings.Replace(localVarPath, "{"+"name"+"}", fmt.Sprintf("%v", name), -1) + + localVarHeaderParams := make(map[string]string) + localVarQueryParams := url.Values{} + localVarFormParams := url.Values{} + if strlen(name) < 1 { + return localVarReturnValue, nil, reportError("name must have at least 1 elements") + } + if strlen(name) > 120 { + return localVarReturnValue, nil, reportError("name must have less than 120 elements") + } + + // to determine the Content-Type header + localVarHttpContentTypes := []string{"application/json"} + + // set Content-Type header + localVarHttpContentType := selectHeaderContentType(localVarHttpContentTypes) + if localVarHttpContentType != "" { + localVarHeaderParams["Content-Type"] = localVarHttpContentType + } + + // to determine the Accept header + localVarHttpHeaderAccepts := []string{"application/json", "application/vnd.goa.error"} + + // set Accept header + localVarHttpHeaderAccept := selectHeaderAccept(localVarHttpHeaderAccepts) + if localVarHttpHeaderAccept != "" { + localVarHeaderParams["Accept"] = localVarHttpHeaderAccept + } + // body params + localVarPostBody = &body + r, err := a.client.prepareRequest(ctx, localVarPath, localVarHttpMethod, localVarPostBody, localVarHeaderParams, localVarQueryParams, localVarFormParams, localVarFileName, localVarFileBytes) + if err != nil { + return localVarReturnValue, nil, err + } + + localVarHttpResponse, err := a.client.callAPI(r) + if err != nil || localVarHttpResponse == nil { + return localVarReturnValue, localVarHttpResponse, err + } + + localVarBody, err := ioutil.ReadAll(localVarHttpResponse.Body) + localVarHttpResponse.Body.Close() + if err != nil { + return localVarReturnValue, localVarHttpResponse, err + } + + if localVarHttpResponse.StatusCode < 300 { + // If we succeed, return the data, otherwise pass on to decode error. + err = a.client.decode(&localVarReturnValue, localVarBody, localVarHttpResponse.Header.Get("Content-Type")) + if err == nil { + return localVarReturnValue, localVarHttpResponse, err + } + } + + if localVarHttpResponse.StatusCode >= 300 { + newErr := GenericSwaggerError{ + body: localVarBody, + error: localVarHttpResponse.Status, + } + if localVarHttpResponse.StatusCode == 202 { + var v string + err = a.client.decode(&v, localVarBody, localVarHttpResponse.Header.Get("Content-Type")) + if err != nil { + newErr.error = err.Error() + return localVarReturnValue, localVarHttpResponse, newErr + } + newErr.model = v + return localVarReturnValue, localVarHttpResponse, newErr + } + if localVarHttpResponse.StatusCode == 400 { + var v ModelError + err = a.client.decode(&v, localVarBody, localVarHttpResponse.Header.Get("Content-Type")) + if err != nil { + newErr.error = err.Error() + return localVarReturnValue, localVarHttpResponse, newErr + } + newErr.model = v + return localVarReturnValue, localVarHttpResponse, newErr + } + if localVarHttpResponse.StatusCode == 403 { + var v ModelError + err = a.client.decode(&v, localVarBody, localVarHttpResponse.Header.Get("Content-Type")) + if err != nil { + newErr.error = err.Error() + return localVarReturnValue, localVarHttpResponse, newErr + } + newErr.model = v + return localVarReturnValue, localVarHttpResponse, newErr + } + if localVarHttpResponse.StatusCode == 404 { + var v ModelError + err = a.client.decode(&v, localVarBody, localVarHttpResponse.Header.Get("Content-Type")) + if err != nil { + newErr.error = err.Error() + return localVarReturnValue, localVarHttpResponse, newErr + } + newErr.model = v + return localVarReturnValue, localVarHttpResponse, newErr + } + if localVarHttpResponse.StatusCode == 413 { + var v ModelError + err = a.client.decode(&v, localVarBody, localVarHttpResponse.Header.Get("Content-Type")) + if err != nil { + newErr.error = err.Error() + return localVarReturnValue, localVarHttpResponse, newErr + } + newErr.model = v + return localVarReturnValue, localVarHttpResponse, newErr + } + if localVarHttpResponse.StatusCode == 429 { + var v RateLimited + err = a.client.decode(&v, localVarBody, localVarHttpResponse.Header.Get("Content-Type")) + if err != nil { + newErr.error = err.Error() + return localVarReturnValue, localVarHttpResponse, newErr + } + newErr.model = v + return localVarReturnValue, localVarHttpResponse, newErr + } + return localVarReturnValue, localVarHttpResponse, newErr + } + + return localVarReturnValue, localVarHttpResponse, nil +} + +/* +NfdApiService updateImage nfd +Update the avatar or banner image associated with an NFD by uploading new image content + * @param ctx context.Context - for authentication, logging, cancellation, deadlines, tracing, etc. Passed from http.Request or context.Background(). + * @param name + * @param sender Address that will be signing the returned transactions. Should be owner of NFD + * @param which Which image to update, avatar or banner + * @param optional nil or *NfdApiNfdUpdateImageOpts - Optional Parameters: + * @param "WantTxn" (optional.Bool) - Whether to return transactions to sign to update the specified image attribute within the NFD +@return string +*/ + +type NfdApiNfdUpdateImageOpts struct { + WantTxn optional.Bool +} + +func (a *NfdApiService) NfdUpdateImage(ctx context.Context, name string, sender string, which string, localVarOptionals *NfdApiNfdUpdateImageOpts) (string, *http.Response, error) { + var ( + localVarHttpMethod = strings.ToUpper("Post") + localVarPostBody interface{} + localVarFileName string + localVarFileBytes []byte + localVarReturnValue string + ) + + // create path and map variables + localVarPath := a.client.cfg.BasePath + "/nfd/updateImage/{name}/{sender}/{which}" + localVarPath = strings.Replace(localVarPath, "{"+"name"+"}", fmt.Sprintf("%v", name), -1) + localVarPath = strings.Replace(localVarPath, "{"+"sender"+"}", fmt.Sprintf("%v", sender), -1) + localVarPath = strings.Replace(localVarPath, "{"+"which"+"}", fmt.Sprintf("%v", which), -1) + + localVarHeaderParams := make(map[string]string) + localVarQueryParams := url.Values{} + localVarFormParams := url.Values{} + if strlen(name) < 1 { + return localVarReturnValue, nil, reportError("name must have at least 1 elements") + } + if strlen(name) > 120 { + return localVarReturnValue, nil, reportError("name must have less than 120 elements") + } + + if localVarOptionals != nil && localVarOptionals.WantTxn.IsSet() { + localVarQueryParams.Add("wantTxn", parameterToString(localVarOptionals.WantTxn.Value(), "")) + } + // to determine the Content-Type header + localVarHttpContentTypes := []string{} + + // set Content-Type header + localVarHttpContentType := selectHeaderContentType(localVarHttpContentTypes) + if localVarHttpContentType != "" { + localVarHeaderParams["Content-Type"] = localVarHttpContentType + } + + // to determine the Accept header + localVarHttpHeaderAccepts := []string{"application/json", "application/vnd.goa.error"} + + // set Accept header + localVarHttpHeaderAccept := selectHeaderAccept(localVarHttpHeaderAccepts) + if localVarHttpHeaderAccept != "" { + localVarHeaderParams["Accept"] = localVarHttpHeaderAccept + } + r, err := a.client.prepareRequest(ctx, localVarPath, localVarHttpMethod, localVarPostBody, localVarHeaderParams, localVarQueryParams, localVarFormParams, localVarFileName, localVarFileBytes) + if err != nil { + return localVarReturnValue, nil, err + } + + localVarHttpResponse, err := a.client.callAPI(r) + if err != nil || localVarHttpResponse == nil { + return localVarReturnValue, localVarHttpResponse, err + } + + localVarBody, err := ioutil.ReadAll(localVarHttpResponse.Body) + localVarHttpResponse.Body.Close() + if err != nil { + return localVarReturnValue, localVarHttpResponse, err + } + + if localVarHttpResponse.StatusCode < 300 { + // If we succeed, return the data, otherwise pass on to decode error. + err = a.client.decode(&localVarReturnValue, localVarBody, localVarHttpResponse.Header.Get("Content-Type")) + if err == nil { + return localVarReturnValue, localVarHttpResponse, err + } + } + + if localVarHttpResponse.StatusCode >= 300 { + newErr := GenericSwaggerError{ + body: localVarBody, + error: localVarHttpResponse.Status, + } + if localVarHttpResponse.StatusCode == 200 { + var v string + err = a.client.decode(&v, localVarBody, localVarHttpResponse.Header.Get("Content-Type")) + if err != nil { + newErr.error = err.Error() + return localVarReturnValue, localVarHttpResponse, newErr + } + newErr.model = v + return localVarReturnValue, localVarHttpResponse, newErr + } + if localVarHttpResponse.StatusCode == 400 { + var v ModelError + err = a.client.decode(&v, localVarBody, localVarHttpResponse.Header.Get("Content-Type")) + if err != nil { + newErr.error = err.Error() + return localVarReturnValue, localVarHttpResponse, newErr + } + newErr.model = v + return localVarReturnValue, localVarHttpResponse, newErr + } + if localVarHttpResponse.StatusCode == 403 { + var v ModelError + err = a.client.decode(&v, localVarBody, localVarHttpResponse.Header.Get("Content-Type")) + if err != nil { + newErr.error = err.Error() + return localVarReturnValue, localVarHttpResponse, newErr + } + newErr.model = v + return localVarReturnValue, localVarHttpResponse, newErr + } + if localVarHttpResponse.StatusCode == 404 { + var v ModelError + err = a.client.decode(&v, localVarBody, localVarHttpResponse.Header.Get("Content-Type")) + if err != nil { + newErr.error = err.Error() + return localVarReturnValue, localVarHttpResponse, newErr + } + newErr.model = v + return localVarReturnValue, localVarHttpResponse, newErr + } + if localVarHttpResponse.StatusCode == 413 { + var v ModelError + err = a.client.decode(&v, localVarBody, localVarHttpResponse.Header.Get("Content-Type")) + if err != nil { + newErr.error = err.Error() + return localVarReturnValue, localVarHttpResponse, newErr + } + newErr.model = v + return localVarReturnValue, localVarHttpResponse, newErr + } + if localVarHttpResponse.StatusCode == 429 { + var v RateLimited + err = a.client.decode(&v, localVarBody, localVarHttpResponse.Header.Get("Content-Type")) + if err != nil { + newErr.error = err.Error() + return localVarReturnValue, localVarHttpResponse, newErr + } + newErr.model = v + return localVarReturnValue, localVarHttpResponse, newErr + } + return localVarReturnValue, localVarHttpResponse, newErr + } + + return localVarReturnValue, localVarHttpResponse, nil +} + +/* +NfdApiService updatePartial nfd +Set an attribute in an NFD on behalf of a particular sender (who must be the owner). Can set user-defined fields, or clear verified fields (except v.ca*) + - @param ctx context.Context - for authentication, logging, cancellation, deadlines, tracing, etc. Passed from http.Request or context.Background(). + - @param body + - @param name + +@return string +*/ +func (a *NfdApiService) NfdUpdatePartial(ctx context.Context, body UpdatePartialRequestBody, name string) (string, *http.Response, error) { + var ( + localVarHttpMethod = strings.ToUpper("Patch") + localVarPostBody interface{} + localVarFileName string + localVarFileBytes []byte + localVarReturnValue string + ) + + // create path and map variables + localVarPath := a.client.cfg.BasePath + "/nfd/update/{name}" + localVarPath = strings.Replace(localVarPath, "{"+"name"+"}", fmt.Sprintf("%v", name), -1) + + localVarHeaderParams := make(map[string]string) + localVarQueryParams := url.Values{} + localVarFormParams := url.Values{} + if strlen(name) < 1 { + return localVarReturnValue, nil, reportError("name must have at least 1 elements") + } + if strlen(name) > 120 { + return localVarReturnValue, nil, reportError("name must have less than 120 elements") + } + + // to determine the Content-Type header + localVarHttpContentTypes := []string{"application/json"} + + // set Content-Type header + localVarHttpContentType := selectHeaderContentType(localVarHttpContentTypes) + if localVarHttpContentType != "" { + localVarHeaderParams["Content-Type"] = localVarHttpContentType + } + + // to determine the Accept header + localVarHttpHeaderAccepts := []string{"application/json", "application/vnd.goa.error"} + + // set Accept header + localVarHttpHeaderAccept := selectHeaderAccept(localVarHttpHeaderAccepts) + if localVarHttpHeaderAccept != "" { + localVarHeaderParams["Accept"] = localVarHttpHeaderAccept + } + // body params + localVarPostBody = &body + r, err := a.client.prepareRequest(ctx, localVarPath, localVarHttpMethod, localVarPostBody, localVarHeaderParams, localVarQueryParams, localVarFormParams, localVarFileName, localVarFileBytes) + if err != nil { + return localVarReturnValue, nil, err + } + + localVarHttpResponse, err := a.client.callAPI(r) + if err != nil || localVarHttpResponse == nil { + return localVarReturnValue, localVarHttpResponse, err + } + + localVarBody, err := ioutil.ReadAll(localVarHttpResponse.Body) + localVarHttpResponse.Body.Close() + if err != nil { + return localVarReturnValue, localVarHttpResponse, err + } + + if localVarHttpResponse.StatusCode < 300 { + // If we succeed, return the data, otherwise pass on to decode error. + err = a.client.decode(&localVarReturnValue, localVarBody, localVarHttpResponse.Header.Get("Content-Type")) + if err == nil { + return localVarReturnValue, localVarHttpResponse, err + } + } + + if localVarHttpResponse.StatusCode >= 300 { + newErr := GenericSwaggerError{ + body: localVarBody, + error: localVarHttpResponse.Status, + } + if localVarHttpResponse.StatusCode == 202 { + var v string + err = a.client.decode(&v, localVarBody, localVarHttpResponse.Header.Get("Content-Type")) + if err != nil { + newErr.error = err.Error() + return localVarReturnValue, localVarHttpResponse, newErr + } + newErr.model = v + return localVarReturnValue, localVarHttpResponse, newErr + } + if localVarHttpResponse.StatusCode == 400 { + var v ModelError + err = a.client.decode(&v, localVarBody, localVarHttpResponse.Header.Get("Content-Type")) + if err != nil { + newErr.error = err.Error() + return localVarReturnValue, localVarHttpResponse, newErr + } + newErr.model = v + return localVarReturnValue, localVarHttpResponse, newErr + } + if localVarHttpResponse.StatusCode == 403 { + var v ModelError + err = a.client.decode(&v, localVarBody, localVarHttpResponse.Header.Get("Content-Type")) + if err != nil { + newErr.error = err.Error() + return localVarReturnValue, localVarHttpResponse, newErr + } + newErr.model = v + return localVarReturnValue, localVarHttpResponse, newErr + } + if localVarHttpResponse.StatusCode == 404 { + var v ModelError + err = a.client.decode(&v, localVarBody, localVarHttpResponse.Header.Get("Content-Type")) + if err != nil { + newErr.error = err.Error() + return localVarReturnValue, localVarHttpResponse, newErr + } + newErr.model = v + return localVarReturnValue, localVarHttpResponse, newErr + } + if localVarHttpResponse.StatusCode == 413 { + var v ModelError + err = a.client.decode(&v, localVarBody, localVarHttpResponse.Header.Get("Content-Type")) + if err != nil { + newErr.error = err.Error() + return localVarReturnValue, localVarHttpResponse, newErr + } + newErr.model = v + return localVarReturnValue, localVarHttpResponse, newErr + } + if localVarHttpResponse.StatusCode == 429 { + var v RateLimited + err = a.client.decode(&v, localVarBody, localVarHttpResponse.Header.Get("Content-Type")) + if err != nil { + newErr.error = err.Error() + return localVarReturnValue, localVarHttpResponse, newErr + } + newErr.model = v + return localVarReturnValue, localVarHttpResponse, newErr + } + return localVarReturnValue, localVarHttpResponse, newErr + } + + return localVarReturnValue, localVarHttpResponse, nil +} + +/* +NfdApiService vaultOptInLock nfd +Lock/Unlock ability for the specified NFD Vault to auto opt-in to assets, allowing airdrops from other accounts + - @param ctx context.Context - for authentication, logging, cancellation, deadlines, tracing, etc. Passed from http.Request or context.Background(). + - @param body + - @param name + +@return string +*/ +func (a *NfdApiService) NfdVaultOptInLock(ctx context.Context, body VaultOptInLockRequestBody, name string) (string, *http.Response, error) { + var ( + localVarHttpMethod = strings.ToUpper("Post") + localVarPostBody interface{} + localVarFileName string + localVarFileBytes []byte + localVarReturnValue string + ) + + // create path and map variables + localVarPath := a.client.cfg.BasePath + "/nfd/vault/lock/{name}" + localVarPath = strings.Replace(localVarPath, "{"+"name"+"}", fmt.Sprintf("%v", name), -1) + + localVarHeaderParams := make(map[string]string) + localVarQueryParams := url.Values{} + localVarFormParams := url.Values{} + if strlen(name) < 1 { + return localVarReturnValue, nil, reportError("name must have at least 1 elements") + } + if strlen(name) > 120 { + return localVarReturnValue, nil, reportError("name must have less than 120 elements") + } + + // to determine the Content-Type header + localVarHttpContentTypes := []string{"application/json"} + + // set Content-Type header + localVarHttpContentType := selectHeaderContentType(localVarHttpContentTypes) + if localVarHttpContentType != "" { + localVarHeaderParams["Content-Type"] = localVarHttpContentType + } + + // to determine the Accept header + localVarHttpHeaderAccepts := []string{"application/json", "application/vnd.goa.error"} + + // set Accept header + localVarHttpHeaderAccept := selectHeaderAccept(localVarHttpHeaderAccepts) + if localVarHttpHeaderAccept != "" { + localVarHeaderParams["Accept"] = localVarHttpHeaderAccept + } + // body params + localVarPostBody = &body + r, err := a.client.prepareRequest(ctx, localVarPath, localVarHttpMethod, localVarPostBody, localVarHeaderParams, localVarQueryParams, localVarFormParams, localVarFileName, localVarFileBytes) + if err != nil { + return localVarReturnValue, nil, err + } + + localVarHttpResponse, err := a.client.callAPI(r) + if err != nil || localVarHttpResponse == nil { + return localVarReturnValue, localVarHttpResponse, err + } + + localVarBody, err := ioutil.ReadAll(localVarHttpResponse.Body) + localVarHttpResponse.Body.Close() + if err != nil { + return localVarReturnValue, localVarHttpResponse, err + } + + if localVarHttpResponse.StatusCode < 300 { + // If we succeed, return the data, otherwise pass on to decode error. + err = a.client.decode(&localVarReturnValue, localVarBody, localVarHttpResponse.Header.Get("Content-Type")) + if err == nil { + return localVarReturnValue, localVarHttpResponse, err + } + } + + if localVarHttpResponse.StatusCode >= 300 { + newErr := GenericSwaggerError{ + body: localVarBody, + error: localVarHttpResponse.Status, + } + if localVarHttpResponse.StatusCode == 200 { + var v string + err = a.client.decode(&v, localVarBody, localVarHttpResponse.Header.Get("Content-Type")) + if err != nil { + newErr.error = err.Error() + return localVarReturnValue, localVarHttpResponse, newErr + } + newErr.model = v + return localVarReturnValue, localVarHttpResponse, newErr + } + if localVarHttpResponse.StatusCode == 400 { + var v ModelError + err = a.client.decode(&v, localVarBody, localVarHttpResponse.Header.Get("Content-Type")) + if err != nil { + newErr.error = err.Error() + return localVarReturnValue, localVarHttpResponse, newErr + } + newErr.model = v + return localVarReturnValue, localVarHttpResponse, newErr + } + if localVarHttpResponse.StatusCode == 404 { + var v ModelError + err = a.client.decode(&v, localVarBody, localVarHttpResponse.Header.Get("Content-Type")) + if err != nil { + newErr.error = err.Error() + return localVarReturnValue, localVarHttpResponse, newErr + } + newErr.model = v + return localVarReturnValue, localVarHttpResponse, newErr + } + if localVarHttpResponse.StatusCode == 429 { + var v RateLimited + err = a.client.decode(&v, localVarBody, localVarHttpResponse.Header.Get("Content-Type")) + if err != nil { + newErr.error = err.Error() + return localVarReturnValue, localVarHttpResponse, newErr + } + newErr.model = v + return localVarReturnValue, localVarHttpResponse, newErr + } + return localVarReturnValue, localVarHttpResponse, newErr + } + + return localVarReturnValue, localVarHttpResponse, nil +} + +/* +NfdApiService verifyConfirm nfd +Verify a particular piece of data on, or off-chain. Each verification differs in its requirements + - @param ctx context.Context - for authentication, logging, cancellation, deadlines, tracing, etc. Passed from http.Request or context.Background(). + - @param body + - @param id id of challenge, must be used in subsequent confirmation call + +@return VerifyConfirmResponseBody +*/ +func (a *NfdApiService) NfdVerifyConfirm(ctx context.Context, body VerifyConfirmRequestBody, id string) (VerifyConfirmResponseBody, *http.Response, error) { + var ( + localVarHttpMethod = strings.ToUpper("Post") + localVarPostBody interface{} + localVarFileName string + localVarFileBytes []byte + localVarReturnValue VerifyConfirmResponseBody + ) + + // create path and map variables + localVarPath := a.client.cfg.BasePath + "/nfd/verify/confirm/{id}" + localVarPath = strings.Replace(localVarPath, "{"+"id"+"}", fmt.Sprintf("%v", id), -1) + + localVarHeaderParams := make(map[string]string) + localVarQueryParams := url.Values{} + localVarFormParams := url.Values{} + + // to determine the Content-Type header + localVarHttpContentTypes := []string{"application/json"} + + // set Content-Type header + localVarHttpContentType := selectHeaderContentType(localVarHttpContentTypes) + if localVarHttpContentType != "" { + localVarHeaderParams["Content-Type"] = localVarHttpContentType + } + + // to determine the Accept header + localVarHttpHeaderAccepts := []string{"application/json", "application/vnd.goa.error"} + + // set Accept header + localVarHttpHeaderAccept := selectHeaderAccept(localVarHttpHeaderAccepts) + if localVarHttpHeaderAccept != "" { + localVarHeaderParams["Accept"] = localVarHttpHeaderAccept + } + // body params + localVarPostBody = &body + r, err := a.client.prepareRequest(ctx, localVarPath, localVarHttpMethod, localVarPostBody, localVarHeaderParams, localVarQueryParams, localVarFormParams, localVarFileName, localVarFileBytes) + if err != nil { + return localVarReturnValue, nil, err + } + + localVarHttpResponse, err := a.client.callAPI(r) + if err != nil || localVarHttpResponse == nil { + return localVarReturnValue, localVarHttpResponse, err + } + + localVarBody, err := ioutil.ReadAll(localVarHttpResponse.Body) + localVarHttpResponse.Body.Close() + if err != nil { + return localVarReturnValue, localVarHttpResponse, err + } + + if localVarHttpResponse.StatusCode < 300 { + // If we succeed, return the data, otherwise pass on to decode error. + err = a.client.decode(&localVarReturnValue, localVarBody, localVarHttpResponse.Header.Get("Content-Type")) + if err == nil { + return localVarReturnValue, localVarHttpResponse, err + } + } + + if localVarHttpResponse.StatusCode >= 300 { + newErr := GenericSwaggerError{ + body: localVarBody, + error: localVarHttpResponse.Status, + } + if localVarHttpResponse.StatusCode == 200 { + var v VerifyConfirmResponseBody + err = a.client.decode(&v, localVarBody, localVarHttpResponse.Header.Get("Content-Type")) + if err != nil { + newErr.error = err.Error() + return localVarReturnValue, localVarHttpResponse, newErr + } + newErr.model = v + return localVarReturnValue, localVarHttpResponse, newErr + } + if localVarHttpResponse.StatusCode == 400 { + var v ModelError + err = a.client.decode(&v, localVarBody, localVarHttpResponse.Header.Get("Content-Type")) + if err != nil { + newErr.error = err.Error() + return localVarReturnValue, localVarHttpResponse, newErr + } + newErr.model = v + return localVarReturnValue, localVarHttpResponse, newErr + } + if localVarHttpResponse.StatusCode == 404 { + var v ModelError + err = a.client.decode(&v, localVarBody, localVarHttpResponse.Header.Get("Content-Type")) + if err != nil { + newErr.error = err.Error() + return localVarReturnValue, localVarHttpResponse, newErr + } + newErr.model = v + return localVarReturnValue, localVarHttpResponse, newErr + } + if localVarHttpResponse.StatusCode == 429 { + var v RateLimited + err = a.client.decode(&v, localVarBody, localVarHttpResponse.Header.Get("Content-Type")) + if err != nil { + newErr.error = err.Error() + return localVarReturnValue, localVarHttpResponse, newErr + } + newErr.model = v + return localVarReturnValue, localVarHttpResponse, newErr + } + return localVarReturnValue, localVarHttpResponse, newErr + } + + return localVarReturnValue, localVarHttpResponse, nil +} + +/* +NfdApiService verifyRequest nfd +Request Verification for particular piece of data on, or off-chain. Each verification differs in its requirements. Returns data to be used in challenge + - @param ctx context.Context - for authentication, logging, cancellation, deadlines, tracing, etc. Passed from http.Request or context.Background(). + - @param body + +@return VerifyRequestResponseBody +*/ +func (a *NfdApiService) NfdVerifyRequest(ctx context.Context, body VerifyRequestRequestBody) (VerifyRequestResponseBody, *http.Response, error) { + var ( + localVarHttpMethod = strings.ToUpper("Post") + localVarPostBody interface{} + localVarFileName string + localVarFileBytes []byte + localVarReturnValue VerifyRequestResponseBody + ) + + // create path and map variables + localVarPath := a.client.cfg.BasePath + "/nfd/verify/request" + + localVarHeaderParams := make(map[string]string) + localVarQueryParams := url.Values{} + localVarFormParams := url.Values{} + + // to determine the Content-Type header + localVarHttpContentTypes := []string{"application/json"} + + // set Content-Type header + localVarHttpContentType := selectHeaderContentType(localVarHttpContentTypes) + if localVarHttpContentType != "" { + localVarHeaderParams["Content-Type"] = localVarHttpContentType + } + + // to determine the Accept header + localVarHttpHeaderAccepts := []string{"application/json", "application/vnd.goa.error"} + + // set Accept header + localVarHttpHeaderAccept := selectHeaderAccept(localVarHttpHeaderAccepts) + if localVarHttpHeaderAccept != "" { + localVarHeaderParams["Accept"] = localVarHttpHeaderAccept + } + // body params + localVarPostBody = &body + r, err := a.client.prepareRequest(ctx, localVarPath, localVarHttpMethod, localVarPostBody, localVarHeaderParams, localVarQueryParams, localVarFormParams, localVarFileName, localVarFileBytes) + if err != nil { + return localVarReturnValue, nil, err + } + + localVarHttpResponse, err := a.client.callAPI(r) + if err != nil || localVarHttpResponse == nil { + return localVarReturnValue, localVarHttpResponse, err + } + + localVarBody, err := ioutil.ReadAll(localVarHttpResponse.Body) + localVarHttpResponse.Body.Close() + if err != nil { + return localVarReturnValue, localVarHttpResponse, err + } + + if localVarHttpResponse.StatusCode < 300 { + // If we succeed, return the data, otherwise pass on to decode error. + err = a.client.decode(&localVarReturnValue, localVarBody, localVarHttpResponse.Header.Get("Content-Type")) + if err == nil { + return localVarReturnValue, localVarHttpResponse, err + } + } + + if localVarHttpResponse.StatusCode >= 300 { + newErr := GenericSwaggerError{ + body: localVarBody, + error: localVarHttpResponse.Status, + } + if localVarHttpResponse.StatusCode == 200 { + var v VerifyRequestResponseBody + err = a.client.decode(&v, localVarBody, localVarHttpResponse.Header.Get("Content-Type")) + if err != nil { + newErr.error = err.Error() + return localVarReturnValue, localVarHttpResponse, newErr + } + newErr.model = v + return localVarReturnValue, localVarHttpResponse, newErr + } + if localVarHttpResponse.StatusCode == 400 { + var v ModelError + err = a.client.decode(&v, localVarBody, localVarHttpResponse.Header.Get("Content-Type")) + if err != nil { + newErr.error = err.Error() + return localVarReturnValue, localVarHttpResponse, newErr + } + newErr.model = v + return localVarReturnValue, localVarHttpResponse, newErr + } + if localVarHttpResponse.StatusCode == 404 { + var v ModelError + err = a.client.decode(&v, localVarBody, localVarHttpResponse.Header.Get("Content-Type")) + if err != nil { + newErr.error = err.Error() + return localVarReturnValue, localVarHttpResponse, newErr + } + newErr.model = v + return localVarReturnValue, localVarHttpResponse, newErr + } + if localVarHttpResponse.StatusCode == 429 { + var v RateLimited + err = a.client.decode(&v, localVarBody, localVarHttpResponse.Header.Get("Content-Type")) + if err != nil { + newErr.error = err.Error() + return localVarReturnValue, localVarHttpResponse, newErr + } + newErr.model = v + return localVarReturnValue, localVarHttpResponse, newErr + } + return localVarReturnValue, localVarHttpResponse, newErr + } + + return localVarReturnValue, localVarHttpResponse, nil +} diff --git a/nodemgr/internal/lib/nfdapi/swagger/client.go b/nodemgr/internal/lib/nfdapi/swagger/client.go new file mode 100644 index 00000000..ca2e9b86 --- /dev/null +++ b/nodemgr/internal/lib/nfdapi/swagger/client.go @@ -0,0 +1,477 @@ +/* + * NFD Management Service + * + * Service for querying and managing NFDs + * + * API version: 1.0 + * Contact: feedback@txnlab.dev + * Generated by: Swagger Codegen (https://github.com/swagger-api/swagger-codegen.git) + */ +package swagger + +import ( + "bytes" + "context" + "encoding/json" + "encoding/xml" + "errors" + "fmt" + "io" + "mime/multipart" + "net/http" + "net/url" + "os" + "path/filepath" + "reflect" + "regexp" + "strconv" + "strings" + "time" + "unicode/utf8" + + "golang.org/x/oauth2" +) + +var ( + jsonCheck = regexp.MustCompile("(?i:[application|text]/json)") + xmlCheck = regexp.MustCompile("(?i:[application|text]/xml)") +) + +// APIClient manages communication with the NFD Management Service API v1.0 +// In most cases there should be only one, shared, APIClient. +type APIClient struct { + cfg *Configuration + common service // Reuse a single struct instead of allocating one for each service on the heap. + + // API Services + + InfoApi *InfoApiService + + NfdApi *NfdApiService +} + +type service struct { + client *APIClient +} + +// NewAPIClient creates a new API client. Requires a userAgent string describing your application. +// optionally a custom http.Client to allow for advanced features such as caching. +func NewAPIClient(cfg *Configuration) *APIClient { + if cfg.HTTPClient == nil { + cfg.HTTPClient = http.DefaultClient + } + + c := &APIClient{} + c.cfg = cfg + c.common.client = c + + // API Services + c.InfoApi = (*InfoApiService)(&c.common) + c.NfdApi = (*NfdApiService)(&c.common) + + return c +} + +func atoi(in string) (int, error) { + return strconv.Atoi(in) +} + +// selectHeaderContentType select a content type from the available list. +func selectHeaderContentType(contentTypes []string) string { + if len(contentTypes) == 0 { + return "" + } + if contains(contentTypes, "application/json") { + return "application/json" + } + return contentTypes[0] // use the first content type specified in 'consumes' +} + +// selectHeaderAccept join all accept types and return +func selectHeaderAccept(accepts []string) string { + if len(accepts) == 0 { + return "" + } + + if contains(accepts, "application/json") { + return "application/json" + } + + return strings.Join(accepts, ",") +} + +// contains is a case insenstive match, finding needle in a haystack +func contains(haystack []string, needle string) bool { + for _, a := range haystack { + if strings.ToLower(a) == strings.ToLower(needle) { + return true + } + } + return false +} + +// Verify optional parameters are of the correct type. +func typeCheckParameter(obj interface{}, expected string, name string) error { + // Make sure there is an object. + if obj == nil { + return nil + } + + // Check the type is as expected. + if reflect.TypeOf(obj).String() != expected { + return fmt.Errorf("Expected %s to be of type %s but received %s.", name, expected, reflect.TypeOf(obj).String()) + } + return nil +} + +// parameterToString convert interface{} parameters to string, using a delimiter if format is provided. +func parameterToString(obj interface{}, collectionFormat string) string { + var delimiter string + + switch collectionFormat { + case "pipes": + delimiter = "|" + case "ssv": + delimiter = " " + case "tsv": + delimiter = "\t" + case "csv": + delimiter = "," + } + + if reflect.TypeOf(obj).Kind() == reflect.Slice { + return strings.Trim(strings.Replace(fmt.Sprint(obj), " ", delimiter, -1), "[]") + } + + return fmt.Sprintf("%v", obj) +} + +// callAPI do the request. +func (c *APIClient) callAPI(request *http.Request) (*http.Response, error) { + return c.cfg.HTTPClient.Do(request) +} + +// Change base path to allow switching to mocks +func (c *APIClient) ChangeBasePath(path string) { + c.cfg.BasePath = path +} + +// prepareRequest build the request +func (c *APIClient) prepareRequest( + ctx context.Context, + path string, method string, + postBody interface{}, + headerParams map[string]string, + queryParams url.Values, + formParams url.Values, + fileName string, + fileBytes []byte) (localVarRequest *http.Request, err error) { + + var body *bytes.Buffer + + // Detect postBody type and post. + if postBody != nil { + contentType := headerParams["Content-Type"] + if contentType == "" { + contentType = detectContentType(postBody) + headerParams["Content-Type"] = contentType + } + + body, err = setBody(postBody, contentType) + if err != nil { + return nil, err + } + } + + // add form parameters and file if available. + if strings.HasPrefix(headerParams["Content-Type"], "multipart/form-data") && len(formParams) > 0 || (len(fileBytes) > 0 && fileName != "") { + if body != nil { + return nil, errors.New("Cannot specify postBody and multipart form at the same time.") + } + body = &bytes.Buffer{} + w := multipart.NewWriter(body) + + for k, v := range formParams { + for _, iv := range v { + if strings.HasPrefix(k, "@") { // file + err = addFile(w, k[1:], iv) + if err != nil { + return nil, err + } + } else { // form value + w.WriteField(k, iv) + } + } + } + if len(fileBytes) > 0 && fileName != "" { + w.Boundary() + //_, fileNm := filepath.Split(fileName) + part, err := w.CreateFormFile("file", filepath.Base(fileName)) + if err != nil { + return nil, err + } + _, err = part.Write(fileBytes) + if err != nil { + return nil, err + } + // Set the Boundary in the Content-Type + headerParams["Content-Type"] = w.FormDataContentType() + } + + // Set Content-Length + headerParams["Content-Length"] = fmt.Sprintf("%d", body.Len()) + w.Close() + } + + if strings.HasPrefix(headerParams["Content-Type"], "application/x-www-form-urlencoded") && len(formParams) > 0 { + if body != nil { + return nil, errors.New("Cannot specify postBody and x-www-form-urlencoded form at the same time.") + } + body = &bytes.Buffer{} + body.WriteString(formParams.Encode()) + // Set Content-Length + headerParams["Content-Length"] = fmt.Sprintf("%d", body.Len()) + } + + // Setup path and query parameters + url, err := url.Parse(path) + if err != nil { + return nil, err + } + + // Adding Query Param + query := url.Query() + for k, v := range queryParams { + for _, iv := range v { + query.Add(k, iv) + } + } + + // Encode the parameters. + url.RawQuery = query.Encode() + + // Generate a new request + if body != nil { + localVarRequest, err = http.NewRequest(method, url.String(), body) + } else { + localVarRequest, err = http.NewRequest(method, url.String(), nil) + } + if err != nil { + return nil, err + } + + // add header parameters, if any + if len(headerParams) > 0 { + headers := http.Header{} + for h, v := range headerParams { + headers.Set(h, v) + } + localVarRequest.Header = headers + } + + // Override request host, if applicable + if c.cfg.Host != "" { + localVarRequest.Host = c.cfg.Host + } + + // Add the user agent to the request. + localVarRequest.Header.Add("User-Agent", c.cfg.UserAgent) + + if ctx != nil { + // add context to the request + localVarRequest = localVarRequest.WithContext(ctx) + + // Walk through any authentication. + + // OAuth2 authentication + if tok, ok := ctx.Value(ContextOAuth2).(oauth2.TokenSource); ok { + // We were able to grab an oauth2 token from the context + var latestToken *oauth2.Token + if latestToken, err = tok.Token(); err != nil { + return nil, err + } + + latestToken.SetAuthHeader(localVarRequest) + } + + // Basic HTTP Authentication + if auth, ok := ctx.Value(ContextBasicAuth).(BasicAuth); ok { + localVarRequest.SetBasicAuth(auth.UserName, auth.Password) + } + + // AccessToken Authentication + if auth, ok := ctx.Value(ContextAccessToken).(string); ok { + localVarRequest.Header.Add("Authorization", "Bearer "+auth) + } + } + + for header, value := range c.cfg.DefaultHeader { + localVarRequest.Header.Add(header, value) + } + + return localVarRequest, nil +} + +func (c *APIClient) decode(v interface{}, b []byte, contentType string) (err error) { + if strings.Contains(contentType, "application/xml") { + if err = xml.Unmarshal(b, v); err != nil { + return err + } + return nil + } else if strings.Contains(contentType, "application/json") { + if err = json.Unmarshal(b, v); err != nil { + return err + } + return nil + } + return errors.New("undefined response type") +} + +// Add a file to the multipart request +func addFile(w *multipart.Writer, fieldName, path string) error { + file, err := os.Open(path) + if err != nil { + return err + } + defer file.Close() + + part, err := w.CreateFormFile(fieldName, filepath.Base(path)) + if err != nil { + return err + } + _, err = io.Copy(part, file) + + return err +} + +// Prevent trying to import "fmt" +func reportError(format string, a ...interface{}) error { + return fmt.Errorf(format, a...) +} + +// Set request body from an interface{} +func setBody(body interface{}, contentType string) (bodyBuf *bytes.Buffer, err error) { + if bodyBuf == nil { + bodyBuf = &bytes.Buffer{} + } + + if reader, ok := body.(io.Reader); ok { + _, err = bodyBuf.ReadFrom(reader) + } else if b, ok := body.([]byte); ok { + _, err = bodyBuf.Write(b) + } else if s, ok := body.(string); ok { + _, err = bodyBuf.WriteString(s) + } else if s, ok := body.(*string); ok { + _, err = bodyBuf.WriteString(*s) + } else if jsonCheck.MatchString(contentType) { + err = json.NewEncoder(bodyBuf).Encode(body) + } else if xmlCheck.MatchString(contentType) { + xml.NewEncoder(bodyBuf).Encode(body) + } + + if err != nil { + return nil, err + } + + if bodyBuf.Len() == 0 { + err = fmt.Errorf("Invalid body type %s\n", contentType) + return nil, err + } + return bodyBuf, nil +} + +// detectContentType method is used to figure out `Request.Body` content type for request header +func detectContentType(body interface{}) string { + contentType := "text/plain; charset=utf-8" + kind := reflect.TypeOf(body).Kind() + + switch kind { + case reflect.Struct, reflect.Map, reflect.Ptr: + contentType = "application/json; charset=utf-8" + case reflect.String: + contentType = "text/plain; charset=utf-8" + default: + if b, ok := body.([]byte); ok { + contentType = http.DetectContentType(b) + } else if kind == reflect.Slice { + contentType = "application/json; charset=utf-8" + } + } + + return contentType +} + +// Ripped from https://github.com/gregjones/httpcache/blob/master/httpcache.go +type cacheControl map[string]string + +func parseCacheControl(headers http.Header) cacheControl { + cc := cacheControl{} + ccHeader := headers.Get("Cache-Control") + for _, part := range strings.Split(ccHeader, ",") { + part = strings.Trim(part, " ") + if part == "" { + continue + } + if strings.ContainsRune(part, '=') { + keyval := strings.Split(part, "=") + cc[strings.Trim(keyval[0], " ")] = strings.Trim(keyval[1], ",") + } else { + cc[part] = "" + } + } + return cc +} + +// CacheExpires helper function to determine remaining time before repeating a request. +func CacheExpires(r *http.Response) time.Time { + // Figure out when the cache expires. + var expires time.Time + now, err := time.Parse(time.RFC1123, r.Header.Get("date")) + if err != nil { + return time.Now() + } + respCacheControl := parseCacheControl(r.Header) + + if maxAge, ok := respCacheControl["max-age"]; ok { + lifetime, err := time.ParseDuration(maxAge + "s") + if err != nil { + expires = now + } + expires = now.Add(lifetime) + } else { + expiresHeader := r.Header.Get("Expires") + if expiresHeader != "" { + expires, err = time.Parse(time.RFC1123, expiresHeader) + if err != nil { + expires = now + } + } + } + return expires +} + +func strlen(s string) int { + return utf8.RuneCountInString(s) +} + +// GenericSwaggerError Provides access to the body, error and model on returned errors. +type GenericSwaggerError struct { + body []byte + error string + model interface{} +} + +// Error returns non-empty string if there was an error. +func (e GenericSwaggerError) Error() string { + return e.error +} + +// Body returns the raw bytes of the response +func (e GenericSwaggerError) Body() []byte { + return e.body +} + +// Model returns the unpacked model of the error +func (e GenericSwaggerError) Model() interface{} { + return e.model +} diff --git a/nodemgr/internal/lib/nfdapi/swagger/configuration.go b/nodemgr/internal/lib/nfdapi/swagger/configuration.go new file mode 100644 index 00000000..3f1f23f2 --- /dev/null +++ b/nodemgr/internal/lib/nfdapi/swagger/configuration.go @@ -0,0 +1,72 @@ +/* + * NFD Management Service + * + * Service for querying and managing NFDs + * + * API version: 1.0 + * Contact: feedback@txnlab.dev + * Generated by: Swagger Codegen (https://github.com/swagger-api/swagger-codegen.git) + */ +package swagger + +import ( + "net/http" +) + +// contextKeys are used to identify the type of value in the context. +// Since these are string, it is possible to get a short description of the +// context key for logging and debugging using key.String(). + +type contextKey string + +func (c contextKey) String() string { + return "auth " + string(c) +} + +var ( + // ContextOAuth2 takes a oauth2.TokenSource as authentication for the request. + ContextOAuth2 = contextKey("token") + + // ContextBasicAuth takes BasicAuth as authentication for the request. + ContextBasicAuth = contextKey("basic") + + // ContextAccessToken takes a string oauth2 access token as authentication for the request. + ContextAccessToken = contextKey("accesstoken") + + // ContextAPIKey takes an APIKey as authentication for the request + ContextAPIKey = contextKey("apikey") +) + +// BasicAuth provides basic http authentication to a request passed via context using ContextBasicAuth +type BasicAuth struct { + UserName string `json:"userName,omitempty"` + Password string `json:"password,omitempty"` +} + +// APIKey provides API key based authentication to a request passed via context using ContextAPIKey +type APIKey struct { + Key string + Prefix string +} + +type Configuration struct { + BasePath string `json:"basePath,omitempty"` + Host string `json:"host,omitempty"` + Scheme string `json:"scheme,omitempty"` + DefaultHeader map[string]string `json:"defaultHeader,omitempty"` + UserAgent string `json:"userAgent,omitempty"` + HTTPClient *http.Client +} + +func NewConfiguration() *Configuration { + cfg := &Configuration{ + BasePath: "https://api.nf.domains", + DefaultHeader: make(map[string]string), + UserAgent: "Swagger-Codegen/1.0.0/go", + } + return cfg +} + +func (c *Configuration) AddDefaultHeader(key string, value string) { + c.DefaultHeader[key] = value +} diff --git a/nodemgr/internal/lib/nfdapi/swagger/model_consensus_record.go b/nodemgr/internal/lib/nfdapi/swagger/model_consensus_record.go new file mode 100644 index 00000000..de4fd68d --- /dev/null +++ b/nodemgr/internal/lib/nfdapi/swagger/model_consensus_record.go @@ -0,0 +1,29 @@ +/* + * NFD Management Service + * + * Service for querying and managing NFDs + * + * API version: 1.0 + * Contact: feedback@txnlab.dev + * Generated by: Swagger Codegen (https://github.com/swagger-api/swagger-codegen.git) + */ +package swagger + +import ( + "time" +) + +// ConsensusRecord contains information about an account that participated in consensus +type ConsensusRecord struct { + Account string `json:"account"` + LastPropBlock int64 `json:"lastPropBlock,omitempty"` + LastPropTime time.Time `json:"lastPropTime,omitempty"` + LastVoteBlock int64 `json:"lastVoteBlock,omitempty"` + LastVoteTime time.Time `json:"lastVoteTime,omitempty"` + LinkType string `json:"linkType,omitempty"` + OwnerAccount string `json:"ownerAccount"` + PctOfOnline float64 `json:"pctOfOnline"` + Proposals int64 `json:"proposals,omitempty"` + Rank int64 `json:"rank,omitempty"` + Votes int64 `json:"votes,omitempty"` +} diff --git a/nodemgr/internal/lib/nfdapi/swagger/model_contract_lock_request_body.go b/nodemgr/internal/lib/nfdapi/swagger/model_contract_lock_request_body.go new file mode 100644 index 00000000..32cf4c27 --- /dev/null +++ b/nodemgr/internal/lib/nfdapi/swagger/model_contract_lock_request_body.go @@ -0,0 +1,17 @@ +/* + * NFD Management Service + * + * Service for querying and managing NFDs + * + * API version: 1.0 + * Contact: feedback@txnlab.dev + * Generated by: Swagger Codegen (https://github.com/swagger-api/swagger-codegen.git) + */ +package swagger + +type ContractLockRequestBody struct { + // Whether to lock (true), or unlock (false) + Lock bool `json:"lock"` + // Sender of transaction - needs to be owner of NFD + Sender string `json:"sender"` +} diff --git a/nodemgr/internal/lib/nfdapi/swagger/model_donation.go b/nodemgr/internal/lib/nfdapi/swagger/model_donation.go new file mode 100644 index 00000000..8eac033f --- /dev/null +++ b/nodemgr/internal/lib/nfdapi/swagger/model_donation.go @@ -0,0 +1,18 @@ +/* + * NFD Management Service + * + * Service for querying and managing NFDs + * + * API version: 1.0 + * Contact: feedback@txnlab.dev + * Generated by: Swagger Codegen (https://github.com/swagger-api/swagger-codegen.git) + */ +package swagger + +// Donation contains basic information about donation totals to specific addresses from accounts related to an NFD +type Donation struct { + // Sender or Receiver Algorand address depending on request + Address string `json:"address"` + // Total donation in microAlgos + Total int64 `json:"total"` +} diff --git a/nodemgr/internal/lib/nfdapi/swagger/model_donation_account.go b/nodemgr/internal/lib/nfdapi/swagger/model_donation_account.go new file mode 100644 index 00000000..4bad6cb4 --- /dev/null +++ b/nodemgr/internal/lib/nfdapi/swagger/model_donation_account.go @@ -0,0 +1,21 @@ +/* + * NFD Management Service + * + * Service for querying and managing NFDs + * + * API version: 1.0 + * Contact: feedback@txnlab.dev + * Generated by: Swagger Codegen (https://github.com/swagger-api/swagger-codegen.git) + */ +package swagger + +// Name and account defined as a donation target +type DonationAccount struct { + // Algorand account address for this donation account + Address string `json:"address"` + // url of image for this donation target + Image string `json:"image"` + Name string `json:"name"` + // name of NFD for this cause + Nfd string `json:"nfd"` +} diff --git a/nodemgr/internal/lib/nfdapi/swagger/model_error.go b/nodemgr/internal/lib/nfdapi/swagger/model_error.go new file mode 100644 index 00000000..da156f26 --- /dev/null +++ b/nodemgr/internal/lib/nfdapi/swagger/model_error.go @@ -0,0 +1,25 @@ +/* + * NFD Management Service + * + * Service for querying and managing NFDs + * + * API version: 1.0 + * Contact: feedback@txnlab.dev + * Generated by: Swagger Codegen (https://github.com/swagger-api/swagger-codegen.git) + */ +package swagger + +type ModelError struct { + // Is the error a server-side fault? + Fault bool `json:"fault"` + // id is a unique identifier for this particular occurrence of the problem. + Id string `json:"id"` + // Message is a human-readable explanation specific to this occurrence of the problem. + Message string `json:"message"` + // Name is the name of this class of errors. + Name string `json:"name"` + // Is the error temporary? + Temporary bool `json:"temporary"` + // Is the error a timeout? + Timeout bool `json:"timeout"` +} diff --git a/nodemgr/internal/lib/nfdapi/swagger/model_escrow_offer_request_body.go b/nodemgr/internal/lib/nfdapi/swagger/model_escrow_offer_request_body.go new file mode 100644 index 00000000..9bab568d --- /dev/null +++ b/nodemgr/internal/lib/nfdapi/swagger/model_escrow_offer_request_body.go @@ -0,0 +1,16 @@ +/* + * NFD Management Service + * + * Service for querying and managing NFDs + * + * API version: 1.0 + * Contact: feedback@txnlab.dev + * Generated by: Swagger Codegen (https://github.com/swagger-api/swagger-codegen.git) + */ +package swagger + +type EscrowOfferRequestBody struct { + Buyer string `json:"buyer"` + // Amount in microAlgo to escrow as new floor price + Offer int64 `json:"offer"` +} diff --git a/nodemgr/internal/lib/nfdapi/swagger/model_is_valid_asa_response_body.go b/nodemgr/internal/lib/nfdapi/swagger/model_is_valid_asa_response_body.go new file mode 100644 index 00000000..528f6518 --- /dev/null +++ b/nodemgr/internal/lib/nfdapi/swagger/model_is_valid_asa_response_body.go @@ -0,0 +1,18 @@ +/* + * NFD Management Service + * + * Service for querying and managing NFDs + * + * API version: 1.0 + * Contact: feedback@txnlab.dev + * Generated by: Swagger Codegen (https://github.com/swagger-api/swagger-codegen.git) + */ +package swagger + +// Whether NFD NFT ASA id is for authentic NFD +type IsValidAsaResponseBody struct { + AppID int64 `json:"appID"` + IsValid bool `json:"isValid"` + Message string `json:"message"` + Name string `json:"name"` +} diff --git a/nodemgr/internal/lib/nfdapi/swagger/model_is_valid_nfd_response_body.go b/nodemgr/internal/lib/nfdapi/swagger/model_is_valid_nfd_response_body.go new file mode 100644 index 00000000..47fc9c59 --- /dev/null +++ b/nodemgr/internal/lib/nfdapi/swagger/model_is_valid_nfd_response_body.go @@ -0,0 +1,18 @@ +/* + * NFD Management Service + * + * Service for querying and managing NFDs + * + * API version: 1.0 + * Contact: feedback@txnlab.dev + * Generated by: Swagger Codegen (https://github.com/swagger-api/swagger-codegen.git) + */ +package swagger + +// Whether NFD App id is for authentic NFD +type IsValidNfdResponseBody struct { + IsValid bool `json:"isValid"` + Message string `json:"message"` + Name string `json:"name"` + SigNameAddress string `json:"sigNameAddress,omitempty"` +} diff --git a/nodemgr/internal/lib/nfdapi/swagger/model_kickoff_request_body.go b/nodemgr/internal/lib/nfdapi/swagger/model_kickoff_request_body.go new file mode 100644 index 00000000..64d5cfe8 --- /dev/null +++ b/nodemgr/internal/lib/nfdapi/swagger/model_kickoff_request_body.go @@ -0,0 +1,15 @@ +/* + * NFD Management Service + * + * Service for querying and managing NFDs + * + * API version: 1.0 + * Contact: feedback@txnlab.dev + * Generated by: Swagger Codegen (https://github.com/swagger-api/swagger-codegen.git) + */ +package swagger + +type KickoffRequestBody struct { + Buyer string `json:"buyer"` + Name string `json:"name"` +} diff --git a/nodemgr/internal/lib/nfdapi/swagger/model_link_address_request_body.go b/nodemgr/internal/lib/nfdapi/swagger/model_link_address_request_body.go new file mode 100644 index 00000000..a6b85e86 --- /dev/null +++ b/nodemgr/internal/lib/nfdapi/swagger/model_link_address_request_body.go @@ -0,0 +1,17 @@ +/* + * NFD Management Service + * + * Service for querying and managing NFDs + * + * API version: 1.0 + * Contact: feedback@txnlab.dev + * Generated by: Swagger Codegen (https://github.com/swagger-api/swagger-codegen.git) + */ +package swagger + +type LinkAddressRequestBody struct { + // Address(es) to link to the NFD (must be able to sign for each) + Address []string `json:"address"` + // Address that will be signing the returned transactions. Should be owner of NFD + Sender string `json:"sender"` +} diff --git a/nodemgr/internal/lib/nfdapi/swagger/model_nfd.go b/nodemgr/internal/lib/nfdapi/swagger/model_nfd.go new file mode 100644 index 00000000..dcc7e5a9 --- /dev/null +++ b/nodemgr/internal/lib/nfdapi/swagger/model_nfd.go @@ -0,0 +1,62 @@ +/* + * NFD Management Service + * + * Service for querying and managing NFDs + * + * API version: 1.0 + * Contact: feedback@txnlab.dev + * Generated by: Swagger Codegen (https://github.com/swagger-api/swagger-codegen.git) + */ +package swagger + +import ( + "time" +) + +// NFD contains all known information about an NFD record +type Nfd struct { + // NFD Application id + AppID int64 `json:"appID,omitempty"` + // NFD ASA id + AsaID int64 `json:"asaID,omitempty"` + // Whether the verified Avatar set in this NFD is newer (arc19) then is set into the NFD. This will only be present on direct NFD fetch and if true + AvatarOutdated bool `json:"avatarOutdated,omitempty"` + // Verified Algorand addresses for this NFD + CaAlgo []string `json:"caAlgo,omitempty"` + // Cache-Control header + CacheControl string `json:"cache-control,omitempty"` + Category string `json:"category,omitempty"` + // Round this data was last fetched from + CurrentAsOfBlock int64 `json:"currentAsOfBlock,omitempty"` + // account wallets should send funds to - precedence is: caAlgo[0], unverifiedCaAlgo[0], owner + DepositAccount string `json:"depositAccount,omitempty"` + // ETag + Etag string `json:"etag,omitempty"` + // Tags set by the system for tracking/analytics + MetaTags []string `json:"metaTags,omitempty"` + Name string `json:"name"` + NfdAccount string `json:"nfdAccount,omitempty"` + // Owner of NFD + Owner string `json:"owner,omitempty"` + // NFD Application id of Parent if this is a segment + ParentAppID int64 `json:"parentAppID,omitempty"` + Properties *NfdProperties `json:"properties,omitempty"` + // Reserved owner of NFD + ReservedFor string `json:"reservedFor,omitempty"` + SaleType string `json:"saleType,omitempty"` + // amount NFD is being sold for (microAlgos) + SellAmount int64 `json:"sellAmount,omitempty"` + // RecipientUid of NFD sales + Seller string `json:"seller,omitempty"` + SigNameAddress string `json:"sigNameAddress,omitempty"` + State string `json:"state,omitempty"` + // Tags assigned to this NFD + Tags []string `json:"tags,omitempty"` + TimeChanged time.Time `json:"timeChanged,omitempty"` + TimeCreated time.Time `json:"timeCreated,omitempty"` + TimePurchased time.Time `json:"timePurchased,omitempty"` + // Unverified (non-algo) Crypto addresses for this NFD + UnverifiedCa map[string][]string `json:"unverifiedCa,omitempty"` + // Unverified Algorand addresses for this NFD + UnverifiedCaAlgo []string `json:"unverifiedCaAlgo,omitempty"` +} diff --git a/nodemgr/internal/lib/nfdapi/swagger/model_nfd_activity.go b/nodemgr/internal/lib/nfdapi/swagger/model_nfd_activity.go new file mode 100644 index 00000000..23b0dccb --- /dev/null +++ b/nodemgr/internal/lib/nfdapi/swagger/model_nfd_activity.go @@ -0,0 +1,29 @@ +/* + * NFD Management Service + * + * Service for querying and managing NFDs + * + * API version: 1.0 + * Contact: feedback@txnlab.dev + * Generated by: Swagger Codegen (https://github.com/swagger-api/swagger-codegen.git) + */ +package swagger + +import ( + "time" +) + +// NFDActivity contains the property changes made in a particular NFD contract update call +type NfdActivity struct { + // Algorand Block number of change + Block int64 `json:"block"` + CacheControl string `json:"cache-control,omitempty"` + // Changed properties + Changes map[string]string `json:"changes,omitempty"` + Etag string `json:"etag,omitempty"` + // Not returned, used in tagging for response to indicate if-none-match etag matched + MatchCheck string `json:"match-check,omitempty"` + // NFD Name + Name string `json:"name"` + TimeChanged time.Time `json:"timeChanged"` +} diff --git a/nodemgr/internal/lib/nfdapi/swagger/model_nfd_analytic_event.go b/nodemgr/internal/lib/nfdapi/swagger/model_nfd_analytic_event.go new file mode 100644 index 00000000..8bf8600f --- /dev/null +++ b/nodemgr/internal/lib/nfdapi/swagger/model_nfd_analytic_event.go @@ -0,0 +1,29 @@ +/* + * NFD Management Service + * + * Service for querying and managing NFDs + * + * API version: 1.0 + * Contact: feedback@txnlab.dev + * Generated by: Swagger Codegen (https://github.com/swagger-api/swagger-codegen.git) + */ +package swagger + +// NFDAnalyticEvent contains a price history record for a point in time of an NFD +type NfdAnalyticEvent struct { + Block int64 `json:"block,omitempty"` + Buyer string `json:"buyer,omitempty"` + // extra amount paid to cover minimum balance requirements - add to price to determine total amount paid + CarryCost int64 `json:"carryCost,omitempty"` + Category string `json:"category,omitempty"` + // NFD current owner - if set via includeOwner property + CurrentOwner string `json:"currentOwner,omitempty"` + Event string `json:"event,omitempty"` + GroupID string `json:"groupID,omitempty"` + MetaTags []string `json:"metaTags,omitempty"` + // NFD Name + Name string `json:"name,omitempty"` + Note string `json:"note,omitempty"` + SaleType string `json:"saleType,omitempty"` + Seller string `json:"seller,omitempty"` +} diff --git a/nodemgr/internal/lib/nfdapi/swagger/model_nfd_analytic_record.go b/nodemgr/internal/lib/nfdapi/swagger/model_nfd_analytic_record.go new file mode 100644 index 00000000..c66d3064 --- /dev/null +++ b/nodemgr/internal/lib/nfdapi/swagger/model_nfd_analytic_record.go @@ -0,0 +1,24 @@ +/* + * NFD Management Service + * + * Service for querying and managing NFDs + * + * API version: 1.0 + * Contact: feedback@txnlab.dev + * Generated by: Swagger Codegen (https://github.com/swagger-api/swagger-codegen.git) + */ +package swagger + +import ( + "time" +) + +// NFDAnalyticRecord is an NFD Analytics record in a time-series collection, with timestamp, price, and event data for that point in time. +type NfdAnalyticRecord struct { + Data *NfdAnalyticEvent `json:"data,omitempty"` + // price of event in microAlgos + Price int64 `json:"price,omitempty"` + // price of event in USD + PriceUsd float64 `json:"priceUsd,omitempty"` + Timestamp time.Time `json:"timestamp,omitempty"` +} diff --git a/nodemgr/internal/lib/nfdapi/swagger/model_nfd_analytic_records.go b/nodemgr/internal/lib/nfdapi/swagger/model_nfd_analytic_records.go new file mode 100644 index 00000000..754ccb32 --- /dev/null +++ b/nodemgr/internal/lib/nfdapi/swagger/model_nfd_analytic_records.go @@ -0,0 +1,18 @@ +/* + * NFD Management Service + * + * Service for querying and managing NFDs + * + * API version: 1.0 + * Contact: feedback@txnlab.dev + * Generated by: Swagger Codegen (https://github.com/swagger-api/swagger-codegen.git) + */ +package swagger + +type NfdAnalyticRecords struct { + // Not returned, used in tagging for response to indicate if-none-match etag matched + MatchCheck string `json:"match-check,omitempty"` + Results []NfdAnalyticRecord `json:"results"` + // total number of results, with data containing paged amount based on offset/limit + Total int64 `json:"total"` +} diff --git a/nodemgr/internal/lib/nfdapi/swagger/model_nfd_auction.go b/nodemgr/internal/lib/nfdapi/swagger/model_nfd_auction.go new file mode 100644 index 00000000..57373bea --- /dev/null +++ b/nodemgr/internal/lib/nfdapi/swagger/model_nfd_auction.go @@ -0,0 +1,29 @@ +/* + * NFD Management Service + * + * Service for querying and managing NFDs + * + * API version: 1.0 + * Contact: feedback@txnlab.dev + * Generated by: Swagger Codegen (https://github.com/swagger-api/swagger-codegen.git) + */ +package swagger + +import ( + "time" +) + +type NfdAuction struct { + // Price in microAlgos + CeilingPrice int64 `json:"ceilingPrice"` + // Price in microAlgos + CurrentPrice int64 `json:"currentPrice,omitempty"` + EndTime time.Time `json:"endTime"` + // Price in microAlgos + FloorPrice int64 `json:"floorPrice"` + Name string `json:"name"` + NewEndTime time.Time `json:"newEndTime,omitempty"` + // Escrowed floor price in microAlgos + NewFloorPrice int64 `json:"newFloorPrice,omitempty"` + StartTime time.Time `json:"startTime"` +} diff --git a/nodemgr/internal/lib/nfdapi/swagger/model_nfd_auction_and_price.go b/nodemgr/internal/lib/nfdapi/swagger/model_nfd_auction_and_price.go new file mode 100644 index 00000000..b6c0e3c8 --- /dev/null +++ b/nodemgr/internal/lib/nfdapi/swagger/model_nfd_auction_and_price.go @@ -0,0 +1,22 @@ +/* + * NFD Management Service + * + * Service for querying and managing NFDs + * + * API version: 1.0 + * Contact: feedback@txnlab.dev + * Generated by: Swagger Codegen (https://github.com/swagger-api/swagger-codegen.git) + */ +package swagger + +type NfdAuctionAndPrice struct { + AuctionInfo *NfdAuction `json:"auctionInfo"` + // Change in price per minute + ChangePerMinute int64 `json:"changePerMinute,omitempty"` + // Minutes elapsed so far in Auction + ElapsedMinutes int64 `json:"elapsedMinutes,omitempty"` + // Current price in microAlgos + Price int64 `json:"price,omitempty"` + // Total number of minutes in Auction + TotalMinutes int64 `json:"totalMinutes,omitempty"` +} diff --git a/nodemgr/internal/lib/nfdapi/swagger/model_nfd_properties.go b/nodemgr/internal/lib/nfdapi/swagger/model_nfd_properties.go new file mode 100644 index 00000000..70987d99 --- /dev/null +++ b/nodemgr/internal/lib/nfdapi/swagger/model_nfd_properties.go @@ -0,0 +1,20 @@ +/* + * NFD Management Service + * + * Service for querying and managing NFDs + * + * API version: 1.0 + * Contact: feedback@txnlab.dev + * Generated by: Swagger Codegen (https://github.com/swagger-api/swagger-codegen.git) + */ +package swagger + +// NFDProperties contains the expanded metadata stored within an NFD contracts' global-state +type NfdProperties struct { + // Internal properties + Internal map[string]string `json:"internal,omitempty"` + // User properties + UserDefined map[string]string `json:"userDefined,omitempty"` + // Verified properties + Verified map[string]string `json:"verified,omitempty"` +} diff --git a/nodemgr/internal/lib/nfdapi/swagger/model_nfd_record.go b/nodemgr/internal/lib/nfdapi/swagger/model_nfd_record.go new file mode 100644 index 00000000..4812270d --- /dev/null +++ b/nodemgr/internal/lib/nfdapi/swagger/model_nfd_record.go @@ -0,0 +1,59 @@ +/* + * NFD Management Service + * + * Service for querying and managing NFDs + * + * API version: 1.0 + * Contact: feedback@txnlab.dev + * Generated by: Swagger Codegen (https://github.com/swagger-api/swagger-codegen.git) + */ +package swagger + +import ( + "time" +) + +type NfdRecord struct { + // NFD Application id + AppID int64 `json:"appID,omitempty"` + // NFD ASA id + AsaID int64 `json:"asaID,omitempty"` + // Whether the verified Avatar set in this NFD is newer (arc19) then is set into the NFD. This will only be present on direct NFD fetch and if true + AvatarOutdated bool `json:"avatarOutdated,omitempty"` + // Verified Algorand addresses for this NFD + CaAlgo []string `json:"caAlgo,omitempty"` + Category string `json:"category,omitempty"` + // Round this data was last fetched from + CurrentAsOfBlock int64 `json:"currentAsOfBlock,omitempty"` + // account wallets should send funds to - precedence is: caAlgo[0], unverifiedCaAlgo[0], owner + DepositAccount string `json:"depositAccount,omitempty"` + // Not returned, used in tagging for response to indicate if-none-match etag matched + MatchCheck string `json:"match-check,omitempty"` + // Tags set by the system for tracking/analytics + MetaTags []string `json:"metaTags,omitempty"` + Name string `json:"name"` + NfdAccount string `json:"nfdAccount,omitempty"` + // Owner of NFD + Owner string `json:"owner,omitempty"` + // NFD Application id of Parent if this is a segment + ParentAppID int64 `json:"parentAppID,omitempty"` + Properties *NfdProperties `json:"properties,omitempty"` + // Reserved owner of NFD + ReservedFor string `json:"reservedFor,omitempty"` + SaleType string `json:"saleType,omitempty"` + // amount NFD is being sold for (microAlgos) + SellAmount int64 `json:"sellAmount,omitempty"` + // RecipientUid of NFD sales + Seller string `json:"seller,omitempty"` + SigNameAddress string `json:"sigNameAddress,omitempty"` + State string `json:"state,omitempty"` + // Tags assigned to this NFD + Tags []string `json:"tags,omitempty"` + TimeChanged time.Time `json:"timeChanged,omitempty"` + TimeCreated time.Time `json:"timeCreated,omitempty"` + TimePurchased time.Time `json:"timePurchased,omitempty"` + // Unverified (non-algo) Crypto addresses for this NFD + UnverifiedCa map[string][]string `json:"unverifiedCa,omitempty"` + // Unverified Algorand addresses for this NFD + UnverifiedCaAlgo []string `json:"unverifiedCaAlgo,omitempty"` +} diff --git a/nodemgr/internal/lib/nfdapi/swagger/model_nfd_record_response_full.go b/nodemgr/internal/lib/nfdapi/swagger/model_nfd_record_response_full.go new file mode 100644 index 00000000..6a5af21a --- /dev/null +++ b/nodemgr/internal/lib/nfdapi/swagger/model_nfd_record_response_full.go @@ -0,0 +1,64 @@ +/* + * NFD Management Service + * + * Service for querying and managing NFDs + * + * API version: 1.0 + * Contact: feedback@txnlab.dev + * Generated by: Swagger Codegen (https://github.com/swagger-api/swagger-codegen.git) + */ +package swagger + +import ( + "time" +) + +// NFD contains all known information about an NFD record (full view) +type NfdRecordResponseFull struct { + // NFD Application id + AppID int64 `json:"appID,omitempty"` + // NFD ASA id + AsaID int64 `json:"asaID,omitempty"` + // Whether the verified Avatar set in this NFD is newer (arc19) then is set into the NFD. This will only be present on direct NFD fetch and if true + AvatarOutdated bool `json:"avatarOutdated,omitempty"` + // Verified Algorand addresses for this NFD + CaAlgo []string `json:"caAlgo,omitempty"` + // Cache-Control header + CacheControl string `json:"cache-control,omitempty"` + Category string `json:"category,omitempty"` + // Round this data was last fetched from + CurrentAsOfBlock int64 `json:"currentAsOfBlock,omitempty"` + // account wallets should send funds to - precedence is: caAlgo[0], unverifiedCaAlgo[0], owner + DepositAccount string `json:"depositAccount,omitempty"` + // ETag + Etag string `json:"etag,omitempty"` + // Not returned, used in tagging for response to indicate if-none-match etag matched + MatchCheck string `json:"match-check,omitempty"` + // Tags set by the system for tracking/analytics + MetaTags []string `json:"metaTags,omitempty"` + Name string `json:"name"` + NfdAccount string `json:"nfdAccount,omitempty"` + // Owner of NFD + Owner string `json:"owner,omitempty"` + // NFD Application id of Parent if this is a segment + ParentAppID int64 `json:"parentAppID,omitempty"` + Properties *NfdProperties `json:"properties,omitempty"` + // Reserved owner of NFD + ReservedFor string `json:"reservedFor,omitempty"` + SaleType string `json:"saleType,omitempty"` + // amount NFD is being sold for (microAlgos) + SellAmount int64 `json:"sellAmount,omitempty"` + // RecipientUid of NFD sales + Seller string `json:"seller,omitempty"` + SigNameAddress string `json:"sigNameAddress,omitempty"` + State string `json:"state,omitempty"` + // Tags assigned to this NFD + Tags []string `json:"tags,omitempty"` + TimeChanged time.Time `json:"timeChanged,omitempty"` + TimeCreated time.Time `json:"timeCreated,omitempty"` + TimePurchased time.Time `json:"timePurchased,omitempty"` + // Unverified (non-algo) Crypto addresses for this NFD + UnverifiedCa map[string][]string `json:"unverifiedCa,omitempty"` + // Unverified Algorand addresses for this NFD + UnverifiedCaAlgo []string `json:"unverifiedCaAlgo,omitempty"` +} diff --git a/nodemgr/internal/lib/nfdapi/swagger/model_nfd_recordinaddress.go b/nodemgr/internal/lib/nfdapi/swagger/model_nfd_recordinaddress.go new file mode 100644 index 00000000..3e5afe19 --- /dev/null +++ b/nodemgr/internal/lib/nfdapi/swagger/model_nfd_recordinaddress.go @@ -0,0 +1,64 @@ +/* + * NFD Management Service + * + * Service for querying and managing NFDs + * + * API version: 1.0 + * Contact: feedback@txnlab.dev + * Generated by: Swagger Codegen (https://github.com/swagger-api/swagger-codegen.git) + */ +package swagger + +import ( + "time" +) + +// NFD contains all known information about an NFD record +type NfdRecordinaddress struct { + // NFD Application id + AppID int64 `json:"appID,omitempty"` + // NFD ASA id + AsaID int64 `json:"asaID,omitempty"` + // Whether the verified Avatar set in this NFD is newer (arc19) then is set into the NFD. This will only be present on direct NFD fetch and if true + AvatarOutdated bool `json:"avatarOutdated,omitempty"` + // Verified Algorand addresses for this NFD + CaAlgo []string `json:"caAlgo,omitempty"` + // Cache-Control header + CacheControl string `json:"cache-control,omitempty"` + Category string `json:"category,omitempty"` + // Round this data was last fetched from + CurrentAsOfBlock int64 `json:"currentAsOfBlock,omitempty"` + // account wallets should send funds to - precedence is: caAlgo[0], unverifiedCaAlgo[0], owner + DepositAccount string `json:"depositAccount,omitempty"` + // ETag + Etag string `json:"etag,omitempty"` + // Not returned, used in tagging for response to indicate if-none-match etag matched + MatchCheck string `json:"match-check,omitempty"` + // Tags set by the system for tracking/analytics + MetaTags []string `json:"metaTags,omitempty"` + Name string `json:"name"` + NfdAccount string `json:"nfdAccount,omitempty"` + // Owner of NFD + Owner string `json:"owner,omitempty"` + // NFD Application id of Parent if this is a segment + ParentAppID int64 `json:"parentAppID,omitempty"` + Properties *NfdProperties `json:"properties,omitempty"` + // Reserved owner of NFD + ReservedFor string `json:"reservedFor,omitempty"` + SaleType string `json:"saleType,omitempty"` + // amount NFD is being sold for (microAlgos) + SellAmount int64 `json:"sellAmount,omitempty"` + // RecipientUid of NFD sales + Seller string `json:"seller,omitempty"` + SigNameAddress string `json:"sigNameAddress,omitempty"` + State string `json:"state,omitempty"` + // Tags assigned to this NFD + Tags []string `json:"tags,omitempty"` + TimeChanged time.Time `json:"timeChanged,omitempty"` + TimeCreated time.Time `json:"timeCreated,omitempty"` + TimePurchased time.Time `json:"timePurchased,omitempty"` + // Unverified (non-algo) Crypto addresses for this NFD + UnverifiedCa map[string][]string `json:"unverifiedCa,omitempty"` + // Unverified Algorand addresses for this NFD + UnverifiedCaAlgo []string `json:"unverifiedCaAlgo,omitempty"` +} diff --git a/nodemgr/internal/lib/nfdapi/swagger/model_nfd_v2_search_records.go b/nodemgr/internal/lib/nfdapi/swagger/model_nfd_v2_search_records.go new file mode 100644 index 00000000..80a4b3cf --- /dev/null +++ b/nodemgr/internal/lib/nfdapi/swagger/model_nfd_v2_search_records.go @@ -0,0 +1,18 @@ +/* + * NFD Management Service + * + * Service for querying and managing NFDs + * + * API version: 1.0 + * Contact: feedback@txnlab.dev + * Generated by: Swagger Codegen (https://github.com/swagger-api/swagger-codegen.git) + */ +package swagger + +type NfdV2SearchRecords struct { + // Not returned, used in tagging for response to indicate if-none-match etag matched + MatchCheck string `json:"match-check,omitempty"` + Nfds *[]NfdRecord `json:"nfds"` + // total number of results, with data containing paged amount based on offset/limit + Total int64 `json:"total"` +} diff --git a/nodemgr/internal/lib/nfdapi/swagger/model_offer_request_body.go b/nodemgr/internal/lib/nfdapi/swagger/model_offer_request_body.go new file mode 100644 index 00000000..95ffbf61 --- /dev/null +++ b/nodemgr/internal/lib/nfdapi/swagger/model_offer_request_body.go @@ -0,0 +1,20 @@ +/* + * NFD Management Service + * + * Service for querying and managing NFDs + * + * API version: 1.0 + * Contact: feedback@txnlab.dev + * Generated by: Swagger Codegen (https://github.com/swagger-api/swagger-codegen.git) + */ +package swagger + +type OfferRequestBody struct { + // Amount in microAlgo to sell the NFD for. 1 ALGO is 1,000,000 microAlgo. 1 ALGO minimum, 100 million maximum. + Offer int64 `json:"offer"` + // Whether to pay the offer amount + fees to the account the NFD is reserved for. Equivalent to 'gifting' the NFD + PayReceiver bool `json:"payReceiver,omitempty"` + ReservedFor string `json:"reservedFor,omitempty"` + // Sender of transaction - needs to be owner of NFD + Sender string `json:"sender"` +} diff --git a/nodemgr/internal/lib/nfdapi/swagger/model_partner_kickoff_request_body.go b/nodemgr/internal/lib/nfdapi/swagger/model_partner_kickoff_request_body.go new file mode 100644 index 00000000..cc2327de --- /dev/null +++ b/nodemgr/internal/lib/nfdapi/swagger/model_partner_kickoff_request_body.go @@ -0,0 +1,17 @@ +/* + * NFD Management Service + * + * Service for querying and managing NFDs + * + * API version: 1.0 + * Contact: feedback@txnlab.dev + * Generated by: Swagger Codegen (https://github.com/swagger-api/swagger-codegen.git) + */ +package swagger + +type PartnerKickoffRequestBody struct { + Buyer string `json:"buyer"` + // a convenience fee percentage to add 'on top' of the NFD price - 10 is 1%, 150 is 15% + ConveniencePct int64 `json:"conveniencePct,omitempty"` + Name string `json:"name"` +} diff --git a/nodemgr/internal/lib/nfdapi/swagger/model_post_offer_to_owner_request_body.go b/nodemgr/internal/lib/nfdapi/swagger/model_post_offer_to_owner_request_body.go new file mode 100644 index 00000000..8ff7917d --- /dev/null +++ b/nodemgr/internal/lib/nfdapi/swagger/model_post_offer_to_owner_request_body.go @@ -0,0 +1,18 @@ +/* + * NFD Management Service + * + * Service for querying and managing NFDs + * + * API version: 1.0 + * Contact: feedback@txnlab.dev + * Generated by: Swagger Codegen (https://github.com/swagger-api/swagger-codegen.git) + */ +package swagger + +type PostOfferToOwnerRequestBody struct { + // Note to pass along to the NFD owner. Must be provided but can be blank + Note string `json:"note"` + // Amount in microAlgo being offered to the NFD owner + Offer int64 `json:"offer"` + Sender string `json:"sender"` +} diff --git a/nodemgr/internal/lib/nfdapi/swagger/model_purchase_request_body.go b/nodemgr/internal/lib/nfdapi/swagger/model_purchase_request_body.go new file mode 100644 index 00000000..b64ced55 --- /dev/null +++ b/nodemgr/internal/lib/nfdapi/swagger/model_purchase_request_body.go @@ -0,0 +1,18 @@ +/* + * NFD Management Service + * + * Service for querying and managing NFDs + * + * API version: 1.0 + * Contact: feedback@txnlab.dev + * Generated by: Swagger Codegen (https://github.com/swagger-api/swagger-codegen.git) + */ +package swagger + +type PurchaseRequestBody struct { + Buyer string `json:"buyer"` + // Amount in microAlgo to purchase/claim the NFD for + Offer int64 `json:"offer"` + // Whether to reject receiving the NFT into the purchasers account, leaving or returning it to the NFDs vault instead + RejectNFT bool `json:"rejectNFT,omitempty"` +} diff --git a/nodemgr/internal/lib/nfdapi/swagger/model_rate_limited.go b/nodemgr/internal/lib/nfdapi/swagger/model_rate_limited.go new file mode 100644 index 00000000..e1973664 --- /dev/null +++ b/nodemgr/internal/lib/nfdapi/swagger/model_rate_limited.go @@ -0,0 +1,15 @@ +/* + * NFD Management Service + * + * Service for querying and managing NFDs + * + * API version: 1.0 + * Contact: feedback@txnlab.dev + * Generated by: Swagger Codegen (https://github.com/swagger-api/swagger-codegen.git) + */ +package swagger + +type RateLimited struct { + Limit int64 `json:"limit"` + SecsRemaining int64 `json:"secsRemaining"` +} diff --git a/nodemgr/internal/lib/nfdapi/swagger/model_rescind_offer_request_body.go b/nodemgr/internal/lib/nfdapi/swagger/model_rescind_offer_request_body.go new file mode 100644 index 00000000..83ab7246 --- /dev/null +++ b/nodemgr/internal/lib/nfdapi/swagger/model_rescind_offer_request_body.go @@ -0,0 +1,15 @@ +/* + * NFD Management Service + * + * Service for querying and managing NFDs + * + * API version: 1.0 + * Contact: feedback@txnlab.dev + * Generated by: Swagger Codegen (https://github.com/swagger-api/swagger-codegen.git) + */ +package swagger + +type RescindOfferRequestBody struct { + // Sender of transaction - needs to be owner of NFD + Sender string `json:"sender"` +} diff --git a/nodemgr/internal/lib/nfdapi/swagger/model_segment_lock_request_body.go b/nodemgr/internal/lib/nfdapi/swagger/model_segment_lock_request_body.go new file mode 100644 index 00000000..509985e4 --- /dev/null +++ b/nodemgr/internal/lib/nfdapi/swagger/model_segment_lock_request_body.go @@ -0,0 +1,19 @@ +/* + * NFD Management Service + * + * Service for querying and managing NFDs + * + * API version: 1.0 + * Contact: feedback@txnlab.dev + * Generated by: Swagger Codegen (https://github.com/swagger-api/swagger-codegen.git) + */ +package swagger + +type SegmentLockRequestBody struct { + // Whether to lock (true), or unlock (false) + Lock bool `json:"lock"` + // amount users minting off the segment have to pay to mint in USD (in cents - ie: 300 = $3.00). Set to 0 if locking + SellAmount int64 `json:"sellAmount"` + // Sender of transaction - needs to be owner of NFD + Sender string `json:"sender"` +} diff --git a/nodemgr/internal/lib/nfdapi/swagger/model_segment_price_response_body.go b/nodemgr/internal/lib/nfdapi/swagger/model_segment_price_response_body.go new file mode 100644 index 00000000..37791254 --- /dev/null +++ b/nodemgr/internal/lib/nfdapi/swagger/model_segment_price_response_body.go @@ -0,0 +1,28 @@ +/* + * NFD Management Service + * + * Service for querying and managing NFDs + * + * API version: 1.0 + * Contact: feedback@txnlab.dev + * Generated by: Swagger Codegen (https://github.com/swagger-api/swagger-codegen.git) + */ +package swagger + +// Price breakdown on minting a segment off another NFD +type SegmentPriceResponseBody struct { + // Price of ALGO in USD + AlgoUsd float64 `json:"algoUsd"` + // Algorand carry cost - amount required for MBR (Minimum balance Requirement) of contracts, escrows, etc + CarryCost int64 `json:"carryCost"` + // Discount rate % that is applied for this segment name - 0 if discount point not reached - starting after 2500 NFDs + DiscountRate float64 `json:"discountRate"` + // Number of segments minted off of parent NFD + ParentSegmentCount int64 `json:"parentSegmentCount"` + // Total Price in microAlgo to mint including ALGO carry cost + SellAmount int64 `json:"sellAmount"` + // Price in USD for unlocked mint of this segment + UnlockedSellPrice float64 `json:"unlockedSellPrice,omitempty"` + // Minimum price in USD the segment has to be (not including ALGO carry cost). If locked, the fixed price, or if unlocked, the platform price + UsdMinCost float64 `json:"usdMinCost"` +} diff --git a/nodemgr/internal/lib/nfdapi/swagger/model_send_from_vault_request_body.go b/nodemgr/internal/lib/nfdapi/swagger/model_send_from_vault_request_body.go new file mode 100644 index 00000000..bc9c1e2c --- /dev/null +++ b/nodemgr/internal/lib/nfdapi/swagger/model_send_from_vault_request_body.go @@ -0,0 +1,27 @@ +/* + * NFD Management Service + * + * Service for querying and managing NFDs + * + * API version: 1.0 + * Contact: feedback@txnlab.dev + * Generated by: Swagger Codegen (https://github.com/swagger-api/swagger-codegen.git) + */ +package swagger + +type SendFromVaultRequestBody struct { + // Base amount (in base units of specified asset - so decimals must be considered) of asset to send. If multiple assets are specified, amount is should be 0 as ALL of each are sent and closed out + Amount int64 `json:"amount"` + // Algorand ASA IDs to transfer FROM vault - use asset 0 to send ALGO. Specifying multiple assets means ALL of each are sent and amount is ignored. If receiver is a vault and needs to opt-in, then need MBR/opt-in pairs (5 pairs - 8 opt-ins each - 40 assets), then 6 send calls of 7 assets w/ 5 at end for total of 40. If receiver is already opted-in, then 112 (7 per txn, 16 tnxs) is max. + Assets []int64 `json:"assets"` + // Optional note to include in asset send transaction + Note string `json:"note,omitempty"` + // Algorand account or NFD Name (if vault receiver) the asset(s) should be sent to + Receiver string `json:"receiver"` + // Specifies that the receiver account is something the caller can sign for. If specified, then opt-in transactions it signs may be included + ReceiverCanSign bool `json:"receiverCanSign,omitempty"` + // account or NFD Vault the asset should be sent to (if allowed) + ReceiverType string `json:"receiverType,omitempty"` + // Sender of transaction, must be NFD owner + Sender string `json:"sender"` +} diff --git a/nodemgr/internal/lib/nfdapi/swagger/model_send_to_vault_request_body.go b/nodemgr/internal/lib/nfdapi/swagger/model_send_to_vault_request_body.go new file mode 100644 index 00000000..3cc51806 --- /dev/null +++ b/nodemgr/internal/lib/nfdapi/swagger/model_send_to_vault_request_body.go @@ -0,0 +1,22 @@ +/* + * NFD Management Service + * + * Service for querying and managing NFDs + * + * API version: 1.0 + * Contact: feedback@txnlab.dev + * Generated by: Swagger Codegen (https://github.com/swagger-api/swagger-codegen.git) + */ +package swagger + +type SendToVaultRequestBody struct { + // Base amount (in base units of specified asset - so decimals must be considered) of asset to send. If multiple assets specified, amount is ignored and ALL of each are sent + Amount int64 `json:"amount"` + // Algorand ASA IDs to transfer (and opt-in inside vault if necessary) - use asset 0 to send ALGO. Specifying multiple assets means ALL of each are sent and amount is ignored. 13 is max assets that can be specified if they're being sent (2 for MBR payments, 2 for opt-in txns (8+4 asset opt-ins), 12 asset transfers). If opt-in only then 64 is maximum (1 MBR per 8 assets, 8 assets per txn * 8 txns) + Assets []int64 `json:"assets"` + // Optional note to include in asset send transaction + Note string `json:"note,omitempty"` + // Whether to only opt-in to the asset, instead of including asset transfer txn + OptInOnly bool `json:"optInOnly"` + Sender string `json:"sender"` +} diff --git a/nodemgr/internal/lib/nfdapi/swagger/model_set_primary_address_request_body.go b/nodemgr/internal/lib/nfdapi/swagger/model_set_primary_address_request_body.go new file mode 100644 index 00000000..2e8111b1 --- /dev/null +++ b/nodemgr/internal/lib/nfdapi/swagger/model_set_primary_address_request_body.go @@ -0,0 +1,17 @@ +/* + * NFD Management Service + * + * Service for querying and managing NFDs + * + * API version: 1.0 + * Contact: feedback@txnlab.dev + * Generated by: Swagger Codegen (https://github.com/swagger-api/swagger-codegen.git) + */ +package swagger + +type SetPrimaryAddressRequestBody struct { + // The address (already linked) to make primary - swapping into position if necessary + Address string `json:"address"` + // Address that will be signing the returned transactions. Should be owner of NFD + Sender string `json:"sender"` +} diff --git a/nodemgr/internal/lib/nfdapi/swagger/model_totals_ok_response_body.go b/nodemgr/internal/lib/nfdapi/swagger/model_totals_ok_response_body.go new file mode 100644 index 00000000..758ebbe0 --- /dev/null +++ b/nodemgr/internal/lib/nfdapi/swagger/model_totals_ok_response_body.go @@ -0,0 +1,22 @@ +/* + * NFD Management Service + * + * Service for querying and managing NFDs + * + * API version: 1.0 + * Contact: feedback@txnlab.dev + * Generated by: Swagger Codegen (https://github.com/swagger-api/swagger-codegen.git) + */ +package swagger + +type TotalsOkResponseBody struct { + ForSale int64 `json:"forSale"` + // Not returned, used in tagging for response to indicate if-none-match etag matched + MatchCheck string `json:"match-check,omitempty"` + MintedTotals *TotalsOkResponseBodyMintedTotals `json:"mintedTotals"` + SegmentTotals *TotalsOkResponseBodyMintedTotals `json:"segmentTotals"` + SoldTotals *TotalsOkResponseBodyMintedTotals `json:"soldTotals"` + Total int64 `json:"total"` + TotalSegments int64 `json:"totalSegments"` + UniqueOwners int64 `json:"uniqueOwners"` +} diff --git a/nodemgr/internal/lib/nfdapi/swagger/model_totals_ok_response_body_minted_totals.go b/nodemgr/internal/lib/nfdapi/swagger/model_totals_ok_response_body_minted_totals.go new file mode 100644 index 00000000..a33ecf20 --- /dev/null +++ b/nodemgr/internal/lib/nfdapi/swagger/model_totals_ok_response_body_minted_totals.go @@ -0,0 +1,17 @@ +/* + * NFD Management Service + * + * Service for querying and managing NFDs + * + * API version: 1.0 + * Contact: feedback@txnlab.dev + * Generated by: Swagger Codegen (https://github.com/swagger-api/swagger-codegen.git) + */ +package swagger + +type TotalsOkResponseBodyMintedTotals struct { + Day int64 `json:"day,omitempty"` + Lifetime int64 `json:"lifetime,omitempty"` + Month int64 `json:"month,omitempty"` + Week int64 `json:"week,omitempty"` +} diff --git a/nodemgr/internal/lib/nfdapi/swagger/model_totals_ok_response_body_segment_totals.go b/nodemgr/internal/lib/nfdapi/swagger/model_totals_ok_response_body_segment_totals.go new file mode 100644 index 00000000..01c2b079 --- /dev/null +++ b/nodemgr/internal/lib/nfdapi/swagger/model_totals_ok_response_body_segment_totals.go @@ -0,0 +1,17 @@ +/* + * NFD Management Service + * + * Service for querying and managing NFDs + * + * API version: 1.0 + * Contact: feedback@txnlab.dev + * Generated by: Swagger Codegen (https://github.com/swagger-api/swagger-codegen.git) + */ +package swagger + +type TotalsOkResponseBodySegmentTotals struct { + Day int32 `json:"day,omitempty"` + Lifetime int32 `json:"lifetime,omitempty"` + Month int32 `json:"month,omitempty"` + Week int32 `json:"week,omitempty"` +} diff --git a/nodemgr/internal/lib/nfdapi/swagger/model_totals_ok_response_body_sold_totals.go b/nodemgr/internal/lib/nfdapi/swagger/model_totals_ok_response_body_sold_totals.go new file mode 100644 index 00000000..ed460ae2 --- /dev/null +++ b/nodemgr/internal/lib/nfdapi/swagger/model_totals_ok_response_body_sold_totals.go @@ -0,0 +1,17 @@ +/* + * NFD Management Service + * + * Service for querying and managing NFDs + * + * API version: 1.0 + * Contact: feedback@txnlab.dev + * Generated by: Swagger Codegen (https://github.com/swagger-api/swagger-codegen.git) + */ +package swagger + +type TotalsOkResponseBodySoldTotals struct { + Day int32 `json:"day,omitempty"` + Lifetime int32 `json:"lifetime,omitempty"` + Month int32 `json:"month,omitempty"` + Week int32 `json:"week,omitempty"` +} diff --git a/nodemgr/internal/lib/nfdapi/swagger/model_twitter_record.go b/nodemgr/internal/lib/nfdapi/swagger/model_twitter_record.go new file mode 100644 index 00000000..aa11877d --- /dev/null +++ b/nodemgr/internal/lib/nfdapi/swagger/model_twitter_record.go @@ -0,0 +1,24 @@ +/* + * NFD Management Service + * + * Service for querying and managing NFDs + * + * API version: 1.0 + * Contact: feedback@txnlab.dev + * Generated by: Swagger Codegen (https://github.com/swagger-api/swagger-codegen.git) + */ +package swagger + +import ( + "time" +) + +// TwitterRecord contains information about an NFD w/ Verified Twitter account and basic info on its twitter metrics +type TwitterRecord struct { + Followers int64 `json:"followers"` + Following int64 `json:"following"` + Nfd *Nfd `json:"nfd"` + TimeChanged time.Time `json:"timeChanged"` + Tweets int64 `json:"tweets"` + TwitterHandle string `json:"twitterHandle"` +} diff --git a/nodemgr/internal/lib/nfdapi/swagger/model_update_partial_request_body.go b/nodemgr/internal/lib/nfdapi/swagger/model_update_partial_request_body.go new file mode 100644 index 00000000..afe11e15 --- /dev/null +++ b/nodemgr/internal/lib/nfdapi/swagger/model_update_partial_request_body.go @@ -0,0 +1,16 @@ +/* + * NFD Management Service + * + * Service for querying and managing NFDs + * + * API version: 1.0 + * Contact: feedback@txnlab.dev + * Generated by: Swagger Codegen (https://github.com/swagger-api/swagger-codegen.git) + */ +package swagger + +type UpdatePartialRequestBody struct { + Properties *NfdProperties `json:"properties"` + // Address that will be signing the returned transactions. Should be owner of NFD + Sender string `json:"sender"` +} diff --git a/nodemgr/internal/lib/nfdapi/swagger/model_vault_opt_in_lock_request_body.go b/nodemgr/internal/lib/nfdapi/swagger/model_vault_opt_in_lock_request_body.go new file mode 100644 index 00000000..bf278e12 --- /dev/null +++ b/nodemgr/internal/lib/nfdapi/swagger/model_vault_opt_in_lock_request_body.go @@ -0,0 +1,23 @@ +/* + * NFD Management Service + * + * Service for querying and managing NFDs + * + * API version: 1.0 + * Contact: feedback@txnlab.dev + * Generated by: Swagger Codegen (https://github.com/swagger-api/swagger-codegen.git) + */ +package swagger + +import ( + "time" +) + +type VaultOptInLockRequestBody struct { + // Whether to lock (true), or unlock (false) + Lock bool `json:"lock"` + // If unlocking vault, specify a time to automatically re-lock the vault. This allows an unlock that only lasts for a paticular amount of time. The time specifies the moment the vault should re-lock. + ReLockAt time.Time `json:"reLockAt,omitempty"` + // Sender of transaction - needs to be owner of NFD + Sender string `json:"sender"` +} diff --git a/nodemgr/internal/lib/nfdapi/swagger/model_verify_confirm_request_body.go b/nodemgr/internal/lib/nfdapi/swagger/model_verify_confirm_request_body.go new file mode 100644 index 00000000..120ec588 --- /dev/null +++ b/nodemgr/internal/lib/nfdapi/swagger/model_verify_confirm_request_body.go @@ -0,0 +1,15 @@ +/* + * NFD Management Service + * + * Service for querying and managing NFDs + * + * API version: 1.0 + * Contact: feedback@txnlab.dev + * Generated by: Swagger Codegen (https://github.com/swagger-api/swagger-codegen.git) + */ +package swagger + +type VerifyConfirmRequestBody struct { + // Challenge value, optional depending on verification type + Challenge string `json:"challenge,omitempty"` +} diff --git a/nodemgr/internal/lib/nfdapi/swagger/model_verify_confirm_response_body.go b/nodemgr/internal/lib/nfdapi/swagger/model_verify_confirm_response_body.go new file mode 100644 index 00000000..52fbbf73 --- /dev/null +++ b/nodemgr/internal/lib/nfdapi/swagger/model_verify_confirm_response_body.go @@ -0,0 +1,15 @@ +/* + * NFD Management Service + * + * Service for querying and managing NFDs + * + * API version: 1.0 + * Contact: feedback@txnlab.dev + * Generated by: Swagger Codegen (https://github.com/swagger-api/swagger-codegen.git) + */ +package swagger + +// Whether verification was successful +type VerifyConfirmResponseBody struct { + Confirmed bool `json:"confirmed"` +} diff --git a/nodemgr/internal/lib/nfdapi/swagger/model_verify_request_request_body.go b/nodemgr/internal/lib/nfdapi/swagger/model_verify_request_request_body.go new file mode 100644 index 00000000..73ec0783 --- /dev/null +++ b/nodemgr/internal/lib/nfdapi/swagger/model_verify_request_request_body.go @@ -0,0 +1,18 @@ +/* + * NFD Management Service + * + * Service for querying and managing NFDs + * + * API version: 1.0 + * Contact: feedback@txnlab.dev + * Generated by: Swagger Codegen (https://github.com/swagger-api/swagger-codegen.git) + */ +package swagger + +type VerifyRequestRequestBody struct { + // User defined field name to verify + FieldToVerify string `json:"fieldToVerify"` + Name string `json:"name"` + // Sender of transaction - needs to be owner of NFD + Sender string `json:"sender"` +} diff --git a/nodemgr/internal/lib/nfdapi/swagger/model_verify_request_response_body.go b/nodemgr/internal/lib/nfdapi/swagger/model_verify_request_response_body.go new file mode 100644 index 00000000..f0b55f3d --- /dev/null +++ b/nodemgr/internal/lib/nfdapi/swagger/model_verify_request_response_body.go @@ -0,0 +1,20 @@ +/* + * NFD Management Service + * + * Service for querying and managing NFDs + * + * API version: 1.0 + * Contact: feedback@txnlab.dev + * Generated by: Swagger Codegen (https://github.com/swagger-api/swagger-codegen.git) + */ +package swagger + +// Data to use as part of verification +type VerifyRequestResponseBody struct { + // Challenge to be used as part of verification process, with use specific to each field + Challenge string `json:"challenge"` + // id of challenge, must be used in subsequent confirmation call but may be blank + Id string `json:"id"` + // If set, no confirmation is required, the verify call was sufficient + Validated bool `json:"validated,omitempty"` +} diff --git a/nodemgr/internal/lib/nfdapi/swagger/model_version_response_body.go b/nodemgr/internal/lib/nfdapi/swagger/model_version_response_body.go new file mode 100644 index 00000000..e934b2aa --- /dev/null +++ b/nodemgr/internal/lib/nfdapi/swagger/model_version_response_body.go @@ -0,0 +1,15 @@ +/* + * NFD Management Service + * + * Service for querying and managing NFDs + * + * API version: 1.0 + * Contact: feedback@txnlab.dev + * Generated by: Swagger Codegen (https://github.com/swagger-api/swagger-codegen.git) + */ +package swagger + +type VersionResponseBody struct { + AppVersion string `json:"appVersion"` + ContractVersion string `json:"contractVersion"` +} diff --git a/nodemgr/internal/lib/nfdapi/swagger/response.go b/nodemgr/internal/lib/nfdapi/swagger/response.go new file mode 100644 index 00000000..ae369767 --- /dev/null +++ b/nodemgr/internal/lib/nfdapi/swagger/response.go @@ -0,0 +1,43 @@ +/* + * NFD Management Service + * + * Service for querying and managing NFDs + * + * API version: 1.0 + * Contact: feedback@txnlab.dev + * Generated by: Swagger Codegen (https://github.com/swagger-api/swagger-codegen.git) + */ +package swagger + +import ( + "net/http" +) + +type APIResponse struct { + *http.Response `json:"-"` + Message string `json:"message,omitempty"` + // Operation is the name of the swagger operation. + Operation string `json:"operation,omitempty"` + // RequestURL is the request URL. This value is always available, even if the + // embedded *http.Response is nil. + RequestURL string `json:"url,omitempty"` + // Method is the HTTP method used for the request. This value is always + // available, even if the embedded *http.Response is nil. + Method string `json:"method,omitempty"` + // Payload holds the contents of the response body (which may be nil or empty). + // This is provided here as the raw response.Body() reader will have already + // been drained. + Payload []byte `json:"-"` +} + +func NewAPIResponse(r *http.Response) *APIResponse { + + response := &APIResponse{Response: r} + return response +} + +func NewAPIResponseWithError(errorMessage string) *APIResponse { + + response := &APIResponse{Message: errorMessage} + return response +} diff --git a/nodemgr/internal/lib/reti/artifacts/contracts/StakingPool.arc32.json b/nodemgr/internal/lib/reti/artifacts/contracts/StakingPool.arc32.json new file mode 100644 index 00000000..25e0d3f7 --- /dev/null +++ b/nodemgr/internal/lib/reti/artifacts/contracts/StakingPool.arc32.json @@ -0,0 +1,379 @@ +{ + "hints": { + "createApplication(uint64,uint64,uint64,uint64)void": { + "call_config": { + "no_op": "CREATE" + } + }, + "gas()void": { + "call_config": { + "no_op": "CALL" + } + }, + "initStorage(pay)void": { + "call_config": { + "no_op": "CALL" + } + }, + "addStake(pay,address)uint64": { + "call_config": { + "no_op": "CALL" + } + }, + "removeStake(uint64)void": { + "call_config": { + "no_op": "CALL" + } + }, + "claimTokens()void": { + "call_config": { + "no_op": "CALL" + } + }, + "getStakerInfo(address)(address,uint64,uint64,uint64,uint64)": { + "call_config": { + "no_op": "CALL" + } + }, + "payTokenReward(address,uint64,uint64)void": { + "call_config": { + "no_op": "CALL" + } + }, + "updateAlgodVer(string)void": { + "call_config": { + "no_op": "CALL" + } + }, + "epochBalanceUpdate()void": { + "call_config": { + "no_op": "CALL" + } + }, + "goOnline(byte[],byte[],byte[],uint64,uint64,uint64)void": { + "call_config": { + "no_op": "CALL" + } + }, + "goOffline()void": { + "call_config": { + "no_op": "CALL" + } + }, + "linkToNFD(uint64,string)void": { + "call_config": { + "no_op": "CALL" + } + }, + "proxiedSetTokenPayoutRatio((uint64,uint64,uint64))(uint64[24],uint64)": { + "call_config": { + "no_op": "CALL" + } + } + }, + "bare_call_config": { + "no_op": "NEVER", + "opt_in": "NEVER", + "close_out": "NEVER", + "update_application": "NEVER", + "delete_application": "NEVER" + }, + "schema": { + "local": { + "declared": {}, + "reserved": {} + }, + "global": { + "declared": { + "creatingValidatorContractAppId": { + "type": "uint64", + "key": "creatorApp" + }, + "validatorId": { + "type": "uint64", + "key": "validatorId" + }, + "poolId": { + "type": "uint64", + "key": "poolId" + }, + "numStakers": { + "type": "uint64", + "key": "numStakers" + }, + "totalAlgoStaked": { + "type": "uint64", + "key": "staked" + }, + "minEntryStake": { + "type": "uint64", + "key": "minEntryStake" + }, + "lastPayout": { + "type": "uint64", + "key": "lastPayout" + }, + "epochNumber": { + "type": "uint64", + "key": "epochNumber" + }, + "algodVer": { + "type": "bytes", + "key": "algodVer" + } + }, + "reserved": {} + } + }, + "state": { + "global": { + "num_byte_slices": 1, + "num_uints": 8 + }, + "local": { + "num_byte_slices": 0, + "num_uints": 0 + } + }, + "source": { + "approval": "I3ByYWdtYSB2ZXJzaW9uIDEwCgovLyBUaGlzIFRFQUwgd2FzIGdlbmVyYXRlZCBieSBURUFMU2NyaXB0IHYwLjg4LjEKLy8gaHR0cHM6Ly9naXRodWIuY29tL2FsZ29yYW5kZm91bmRhdGlvbi9URUFMU2NyaXB0CgovLyBUaGlzIGNvbnRyYWN0IGlzIGNvbXBsaWFudCB3aXRoIGFuZC9vciBpbXBsZW1lbnRzIHRoZSBmb2xsb3dpbmcgQVJDczogWyBBUkM0IF0KCi8vIFRoZSBmb2xsb3dpbmcgdGVuIGxpbmVzIG9mIFRFQUwgaGFuZGxlIGluaXRpYWwgcHJvZ3JhbSBmbG93Ci8vIFRoaXMgcGF0dGVybiBpcyB1c2VkIHRvIG1ha2UgaXQgZWFzeSBmb3IgYW55b25lIHRvIHBhcnNlIHRoZSBzdGFydCBvZiB0aGUgcHJvZ3JhbSBhbmQgZGV0ZXJtaW5lIGlmIGEgc3BlY2lmaWMgYWN0aW9uIGlzIGFsbG93ZWQKLy8gSGVyZSwgYWN0aW9uIHJlZmVycyB0byB0aGUgT25Db21wbGV0ZSBpbiBjb21iaW5hdGlvbiB3aXRoIHdoZXRoZXIgdGhlIGFwcCBpcyBiZWluZyBjcmVhdGVkIG9yIGNhbGxlZAovLyBFdmVyeSBwb3NzaWJsZSBhY3Rpb24gZm9yIHRoaXMgY29udHJhY3QgaXMgcmVwcmVzZW50ZWQgaW4gdGhlIHN3aXRjaCBzdGF0ZW1lbnQKLy8gSWYgdGhlIGFjdGlvbiBpcyBub3QgaW1wbGVtZW50ZWQgaW4gdGhlIGNvbnRyYWN0LCBpdHMgcmVzcGVjdGl2ZSBicmFuY2ggd2lsbCBiZSAiKk5PVF9JTVBMRU1FTlRFRCIgd2hpY2gganVzdCBjb250YWlucyAiZXJyIgp0eG4gQXBwbGljYXRpb25JRAohCmludCA2CioKdHhuIE9uQ29tcGxldGlvbgorCnN3aXRjaCAqY2FsbF9Ob09wICpOT1RfSU1QTEVNRU5URUQgKk5PVF9JTVBMRU1FTlRFRCAqTk9UX0lNUExFTUVOVEVEICpOT1RfSU1QTEVNRU5URUQgKk5PVF9JTVBMRU1FTlRFRCAqY3JlYXRlX05vT3AgKk5PVF9JTVBMRU1FTlRFRCAqTk9UX0lNUExFTUVOVEVEICpOT1RfSU1QTEVNRU5URUQgKk5PVF9JTVBMRU1FTlRFRCAqTk9UX0lNUExFTUVOVEVECgoqTk9UX0lNUExFTUVOVEVEOgoJZXJyCgovLyBjcmVhdGVBcHBsaWNhdGlvbih1aW50NjQsdWludDY0LHVpbnQ2NCx1aW50NjQpdm9pZAoqYWJpX3JvdXRlX2NyZWF0ZUFwcGxpY2F0aW9uOgoJLy8gbWluRW50cnlTdGFrZTogdWludDY0Cgl0eG5hIEFwcGxpY2F0aW9uQXJncyA0CglidG9pCgoJLy8gcG9vbElkOiB1aW50NjQKCXR4bmEgQXBwbGljYXRpb25BcmdzIDMKCWJ0b2kKCgkvLyB2YWxpZGF0b3JJZDogdWludDY0Cgl0eG5hIEFwcGxpY2F0aW9uQXJncyAyCglidG9pCgoJLy8gY3JlYXRpbmdDb250cmFjdElkOiB1aW50NjQKCXR4bmEgQXBwbGljYXRpb25BcmdzIDEKCWJ0b2kKCgkvLyBleGVjdXRlIGNyZWF0ZUFwcGxpY2F0aW9uKHVpbnQ2NCx1aW50NjQsdWludDY0LHVpbnQ2NCl2b2lkCgljYWxsc3ViIGNyZWF0ZUFwcGxpY2F0aW9uCglpbnQgMQoJcmV0dXJuCgovLyBjcmVhdGVBcHBsaWNhdGlvbihjcmVhdGluZ0NvbnRyYWN0SWQ6IHVpbnQ2NCwgdmFsaWRhdG9ySWQ6IHVpbnQ2NCwgcG9vbElkOiB1aW50NjQsIG1pbkVudHJ5U3Rha2U6IHVpbnQ2NCk6IHZvaWQKLy8KLy8gSW5pdGlhbGl6ZSB0aGUgc3Rha2luZyBwb29sIHcvIG93bmVyIGFuZCBtYW5hZ2VyLCBidXQgY2FuIG9ubHkgYmUgY3JlYXRlZCBieSB0aGUgdmFsaWRhdG9yIGNvbnRyYWN0LgovLyBAcGFyYW0ge3VpbnQ2NH0gY3JlYXRpbmdDb250cmFjdElkIC0gaWQgb2YgY29udHJhY3QgdGhhdCBjb25zdHJ1Y3RlZCB1cyAtIHRoZSB2YWxpZGF0b3IgYXBwbGljYXRpb24gKHNpbmdsZSBnbG9iYWwgaW5zdGFuY2UpCi8vIEBwYXJhbSB7dWludDY0fSB2YWxpZGF0b3JJZCAtIGlkIG9mIHZhbGlkYXRvciB3ZSdyZSBhIHN0YWtpbmcgcG9vbCBvZgovLyBAcGFyYW0ge3VpbnQ2NH0gcG9vbElkIC0gd2hpY2ggcG9vbCBpZCBhcmUgd2UKLy8gQHBhcmFtIHt1aW50NjR9IG1pbkVudHJ5U3Rha2UgLSBtaW5pbXVtIGFtb3VudCB0byBiZSBpbiBwb29sLCBidXQgYWxzbyBtaW5pbXVtIGFtb3VudCBiYWxhbmNlIGNhbid0IGdvIGJlbG93ICh3aXRob3V0IHJlbW92aW5nIGFsbCEpCmNyZWF0ZUFwcGxpY2F0aW9uOgoJcHJvdG8gNCAwCgoJLy8gKmlmMF9jb25kaXRpb24KCS8vIGNvbnRyYWN0cy9zdGFraW5nUG9vbC5hbGdvLnRzOjg2CgkvLyBjcmVhdGluZ0NvbnRyYWN0SWQgPT09IDAKCWZyYW1lX2RpZyAtMSAvLyBjcmVhdGluZ0NvbnRyYWN0SWQ6IHVpbnQ2NAoJaW50IDAKCT09CglieiAqaWYwX2Vsc2UKCgkvLyAqaWYwX2NvbnNlcXVlbnQKCS8vIGNvbnRyYWN0cy9zdGFraW5nUG9vbC5hbGdvLnRzOjg4CgkvLyBhc3NlcnQodmFsaWRhdG9ySWQgPT09IDApCglmcmFtZV9kaWcgLTIgLy8gdmFsaWRhdG9ySWQ6IHVpbnQ2NAoJaW50IDAKCT09Cglhc3NlcnQKCgkvLyBjb250cmFjdHMvc3Rha2luZ1Bvb2wuYWxnby50czo4OQoJLy8gYXNzZXJ0KHBvb2xJZCA9PT0gMCkKCWZyYW1lX2RpZyAtMyAvLyBwb29sSWQ6IHVpbnQ2NAoJaW50IDAKCT09Cglhc3NlcnQKCWIgKmlmMF9lbmQKCippZjBfZWxzZToKCS8vIGNvbnRyYWN0cy9zdGFraW5nUG9vbC5hbGdvLnRzOjkxCgkvLyBhc3NlcnQodmFsaWRhdG9ySWQgIT09IDApCglmcmFtZV9kaWcgLTIgLy8gdmFsaWRhdG9ySWQ6IHVpbnQ2NAoJaW50IDAKCSE9Cglhc3NlcnQKCgkvLyBjb250cmFjdHMvc3Rha2luZ1Bvb2wuYWxnby50czo5MgoJLy8gYXNzZXJ0KHBvb2xJZCAhPT0gMCkKCWZyYW1lX2RpZyAtMyAvLyBwb29sSWQ6IHVpbnQ2NAoJaW50IDAKCSE9Cglhc3NlcnQKCippZjBfZW5kOgoJLy8gY29udHJhY3RzL3N0YWtpbmdQb29sLmFsZ28udHM6OTQKCS8vIGFzc2VydChtaW5FbnRyeVN0YWtlID49IE1JTl9BTEdPX1NUQUtFX1BFUl9QT09MKQoJZnJhbWVfZGlnIC00IC8vIG1pbkVudHJ5U3Rha2U6IHVpbnQ2NAoJaW50IDEwMDAwMDAKCT49Cglhc3NlcnQKCgkvLyBjb250cmFjdHMvc3Rha2luZ1Bvb2wuYWxnby50czo5NQoJLy8gdGhpcy5jcmVhdGluZ1ZhbGlkYXRvckNvbnRyYWN0QXBwSWQudmFsdWUgPSBjcmVhdGluZ0NvbnRyYWN0SWQKCWJ5dGUgMHg2MzcyNjU2MTc0NmY3MjQxNzA3MCAvLyAiY3JlYXRvckFwcCIKCWZyYW1lX2RpZyAtMSAvLyBjcmVhdGluZ0NvbnRyYWN0SWQ6IHVpbnQ2NAoJYXBwX2dsb2JhbF9wdXQKCgkvLyBjb250cmFjdHMvc3Rha2luZ1Bvb2wuYWxnby50czo5NgoJLy8gdGhpcy52YWxpZGF0b3JJZC52YWx1ZSA9IHZhbGlkYXRvcklkCglieXRlIDB4NzY2MTZjNjk2NDYxNzQ2ZjcyNDk2NCAvLyAidmFsaWRhdG9ySWQiCglmcmFtZV9kaWcgLTIgLy8gdmFsaWRhdG9ySWQ6IHVpbnQ2NAoJYXBwX2dsb2JhbF9wdXQKCgkvLyBjb250cmFjdHMvc3Rha2luZ1Bvb2wuYWxnby50czo5NwoJLy8gdGhpcy5wb29sSWQudmFsdWUgPSBwb29sSWQKCWJ5dGUgMHg3MDZmNmY2YzQ5NjQgLy8gInBvb2xJZCIKCWZyYW1lX2RpZyAtMyAvLyBwb29sSWQ6IHVpbnQ2NAoJYXBwX2dsb2JhbF9wdXQKCgkvLyBjb250cmFjdHMvc3Rha2luZ1Bvb2wuYWxnby50czo5OAoJLy8gdGhpcy5udW1TdGFrZXJzLnZhbHVlID0gMAoJYnl0ZSAweDZlNzU2ZDUzNzQ2MTZiNjU3MjczIC8vICJudW1TdGFrZXJzIgoJaW50IDAKCWFwcF9nbG9iYWxfcHV0CgoJLy8gY29udHJhY3RzL3N0YWtpbmdQb29sLmFsZ28udHM6OTkKCS8vIHRoaXMudG90YWxBbGdvU3Rha2VkLnZhbHVlID0gMAoJYnl0ZSAweDczNzQ2MTZiNjU2NCAvLyAic3Rha2VkIgoJaW50IDAKCWFwcF9nbG9iYWxfcHV0CgoJLy8gY29udHJhY3RzL3N0YWtpbmdQb29sLmFsZ28udHM6MTAwCgkvLyB0aGlzLm1pbkVudHJ5U3Rha2UudmFsdWUgPSBtaW5FbnRyeVN0YWtlCglieXRlIDB4NmQ2OTZlNDU2ZTc0NzI3OTUzNzQ2MTZiNjUgLy8gIm1pbkVudHJ5U3Rha2UiCglmcmFtZV9kaWcgLTQgLy8gbWluRW50cnlTdGFrZTogdWludDY0CglhcHBfZ2xvYmFsX3B1dAoKCS8vIGNvbnRyYWN0cy9zdGFraW5nUG9vbC5hbGdvLnRzOjEwMQoJLy8gdGhpcy5sYXN0UGF5b3V0LnZhbHVlID0gZ2xvYmFscy5sYXRlc3RUaW1lc3RhbXAKCWJ5dGUgMHg2YzYxNzM3NDUwNjE3OTZmNzU3NCAvLyAibGFzdFBheW91dCIKCWdsb2JhbCBMYXRlc3RUaW1lc3RhbXAKCWFwcF9nbG9iYWxfcHV0CgoJLy8gY29udHJhY3RzL3N0YWtpbmdQb29sLmFsZ28udHM6MTAyCgkvLyB0aGlzLmVwb2NoTnVtYmVyLnZhbHVlID0gMAoJYnl0ZSAweDY1NzA2ZjYzNjg0ZTc1NmQ2MjY1NzIgLy8gImVwb2NoTnVtYmVyIgoJaW50IDAKCWFwcF9nbG9iYWxfcHV0CglyZXRzdWIKCi8vIGdhcygpdm9pZAoqYWJpX3JvdXRlX2dhczoKCS8vIGV4ZWN1dGUgZ2FzKCl2b2lkCgljYWxsc3ViIGdhcwoJaW50IDEKCXJldHVybgoKLy8gZ2FzKCk6IHZvaWQKLy8KLy8gZ2FzIGlzIGEgZHVtbXkgbm8tb3AgY2FsbCB0aGF0IGNhbiBiZSB1c2VkIHRvIHBvb2wtdXAgcmVzb3VyY2UgcmVmZXJlbmNlcyBhbmQgb3Bjb2RlIGNvc3QKZ2FzOgoJcHJvdG8gMCAwCglyZXRzdWIKCi8vIG1pbkJhbGFuY2VGb3JBY2NvdW50KGNvbnRyYWN0czogdWludDY0LCBleHRyYVBhZ2VzOiB1aW50NjQsIGFzc2V0czogdWludDY0LCBsb2NhbEludHM6IHVpbnQ2NCwgbG9jYWxCeXRlczogdWludDY0LCBnbG9iYWxJbnRzOiB1aW50NjQsIGdsb2JhbEJ5dGVzOiB1aW50NjQpOiB1aW50NjQKbWluQmFsYW5jZUZvckFjY291bnQ6Cglwcm90byA3IDEKCgkvLyBQdXNoIGVtcHR5IGJ5dGVzIGFmdGVyIHRoZSBmcmFtZSBwb2ludGVyIHRvIHJlc2VydmUgc3BhY2UgZm9yIGxvY2FsIHZhcmlhYmxlcwoJYnl0ZSAweAoKCS8vIGNvbnRyYWN0cy9zdGFraW5nUG9vbC5hbGdvLnRzOjExOQoJLy8gbWluQmFsID0gQUxHT1JBTkRfQUNDT1VOVF9NSU5fQkFMQU5DRQoJaW50IDEwMDAwMAoJZnJhbWVfYnVyeSAwIC8vIG1pbkJhbDogdWludDY0CgoJLy8gY29udHJhY3RzL3N0YWtpbmdQb29sLmFsZ28udHM6MTIwCgkvLyBtaW5CYWwgKz0gY29udHJhY3RzICogQVBQTElDQVRJT05fQkFTRV9GRUUKCWZyYW1lX2RpZyAwIC8vIG1pbkJhbDogdWludDY0CglmcmFtZV9kaWcgLTEgLy8gY29udHJhY3RzOiB1aW50NjQKCWludCAxMDAwMDAKCSoKCSsKCWZyYW1lX2J1cnkgMCAvLyBtaW5CYWw6IHVpbnQ2NAoKCS8vIGNvbnRyYWN0cy9zdGFraW5nUG9vbC5hbGdvLnRzOjEyMQoJLy8gbWluQmFsICs9IGV4dHJhUGFnZXMgKiBBUFBMSUNBVElPTl9CQVNFX0ZFRQoJZnJhbWVfZGlnIDAgLy8gbWluQmFsOiB1aW50NjQKCWZyYW1lX2RpZyAtMiAvLyBleHRyYVBhZ2VzOiB1aW50NjQKCWludCAxMDAwMDAKCSoKCSsKCWZyYW1lX2J1cnkgMCAvLyBtaW5CYWw6IHVpbnQ2NAoKCS8vIGNvbnRyYWN0cy9zdGFraW5nUG9vbC5hbGdvLnRzOjEyMgoJLy8gbWluQmFsICs9IGFzc2V0cyAqIEFTU0VUX0hPTERJTkdfRkVFCglmcmFtZV9kaWcgMCAvLyBtaW5CYWw6IHVpbnQ2NAoJZnJhbWVfZGlnIC0zIC8vIGFzc2V0czogdWludDY0CglpbnQgMTAwMDAwCgkqCgkrCglmcmFtZV9idXJ5IDAgLy8gbWluQmFsOiB1aW50NjQKCgkvLyBjb250cmFjdHMvc3Rha2luZ1Bvb2wuYWxnby50czoxMjMKCS8vIG1pbkJhbCArPSBsb2NhbEludHMgKiBTU0NfVkFMVUVfVUlOVAoJZnJhbWVfZGlnIDAgLy8gbWluQmFsOiB1aW50NjQKCWZyYW1lX2RpZyAtNCAvLyBsb2NhbEludHM6IHVpbnQ2NAoJaW50IDI4NTAwCgkqCgkrCglmcmFtZV9idXJ5IDAgLy8gbWluQmFsOiB1aW50NjQKCgkvLyBjb250cmFjdHMvc3Rha2luZ1Bvb2wuYWxnby50czoxMjQKCS8vIG1pbkJhbCArPSBnbG9iYWxJbnRzICogU1NDX1ZBTFVFX1VJTlQKCWZyYW1lX2RpZyAwIC8vIG1pbkJhbDogdWludDY0CglmcmFtZV9kaWcgLTYgLy8gZ2xvYmFsSW50czogdWludDY0CglpbnQgMjg1MDAKCSoKCSsKCWZyYW1lX2J1cnkgMCAvLyBtaW5CYWw6IHVpbnQ2NAoKCS8vIGNvbnRyYWN0cy9zdGFraW5nUG9vbC5hbGdvLnRzOjEyNQoJLy8gbWluQmFsICs9IGxvY2FsQnl0ZXMgKiBTU0NfVkFMVUVfQllURVMKCWZyYW1lX2RpZyAwIC8vIG1pbkJhbDogdWludDY0CglmcmFtZV9kaWcgLTUgLy8gbG9jYWxCeXRlczogdWludDY0CglpbnQgNTAwMDAKCSoKCSsKCWZyYW1lX2J1cnkgMCAvLyBtaW5CYWw6IHVpbnQ2NAoKCS8vIGNvbnRyYWN0cy9zdGFraW5nUG9vbC5hbGdvLnRzOjEyNgoJLy8gbWluQmFsICs9IGdsb2JhbEJ5dGVzICogU1NDX1ZBTFVFX0JZVEVTCglmcmFtZV9kaWcgMCAvLyBtaW5CYWw6IHVpbnQ2NAoJZnJhbWVfZGlnIC03IC8vIGdsb2JhbEJ5dGVzOiB1aW50NjQKCWludCA1MDAwMAoJKgoJKwoJZnJhbWVfYnVyeSAwIC8vIG1pbkJhbDogdWludDY0CgoJLy8gY29udHJhY3RzL3N0YWtpbmdQb29sLmFsZ28udHM6MTI3CgkvLyByZXR1cm4gbWluQmFsOwoJZnJhbWVfZGlnIDAgLy8gbWluQmFsOiB1aW50NjQKCgkvLyBzZXQgdGhlIHN1YnJvdXRpbmUgcmV0dXJuIHZhbHVlCglmcmFtZV9idXJ5IDAKCXJldHN1YgoKLy8gY29zdEZvckJveFN0b3JhZ2UodG90YWxOdW1CeXRlczogdWludDY0KTogdWludDY0CmNvc3RGb3JCb3hTdG9yYWdlOgoJcHJvdG8gMSAxCgoJLy8gY29udHJhY3RzL3N0YWtpbmdQb29sLmFsZ28udHM6MTM0CgkvLyByZXR1cm4gU0NCT1hfUEVSQk9YICsgdG90YWxOdW1CeXRlcyAqIFNDQk9YX1BFUkJZVEU7CglpbnQgMjUwMAoJZnJhbWVfZGlnIC0xIC8vIHRvdGFsTnVtQnl0ZXM6IHVpbnQ2NAoJaW50IDQwMAoJKgoJKwoJcmV0c3ViCgovLyBpbml0U3RvcmFnZShwYXkpdm9pZAoqYWJpX3JvdXRlX2luaXRTdG9yYWdlOgoJLy8gbWJyUGF5bWVudDogcGF5Cgl0eG4gR3JvdXBJbmRleAoJaW50IDEKCS0KCWR1cAoJZ3R4bnMgVHlwZUVudW0KCWludCBwYXkKCT09Cglhc3NlcnQKCgkvLyBleGVjdXRlIGluaXRTdG9yYWdlKHBheSl2b2lkCgljYWxsc3ViIGluaXRTdG9yYWdlCglpbnQgMQoJcmV0dXJuCgovLyBpbml0U3RvcmFnZShtYnJQYXltZW50OiBQYXlUeG4pOiB2b2lkCi8vCi8vIENhbGxlZCBhZnRlciB3ZSdyZSBjcmVhdGVkIGFuZCB0aGVuIGZ1bmRlZCBzbyB3ZSBjYW4gY3JlYXRlIG91ciBsYXJnZSBzdGFrZXJzIGxlZGdlciBzdG9yYWdlCi8vIENhbGxlciBoYXMgdG8gZ2V0IE1CUiBhbW91bnRzIGZyb20gVmFsaWRhdG9yUmVnaXN0cnkgdG8ga25vdyBob3cgbXVjaCB0byBmdW5kIHVzIHRvIGNvdmVyIHRoZSBib3ggc3RvcmFnZSBjb3N0Ci8vIElmIHRoaXMgaXMgcG9vbCAxIEFORCB0aGUgdmFsaWRhdG9yIGhhcyBzcGVjaWZpZWQgYSByZXdhcmQgdG9rZW4sIG9wdC1pbiB0byB0aGF0IHRva2VuCi8vIHNvIHRoYXQgdGhlIHZhbGlkYXRvciBjYW4gc2VlZCB0aGUgcG9vbCB3aXRoIGZ1dHVyZSByZXdhcmRzIG9mIHRoYXQgdG9rZW4uCi8vIEBwYXJhbSBtYnJQYXltZW50IHBheW1lbnQgZnJvbSBjYWxsZXIgd2hpY2ggY292ZXJzIG1iciBpbmNyZWFzZSBvZiBuZXcgc3Rha2luZyBwb29scycgc3RvcmFnZQppbml0U3RvcmFnZToKCXByb3RvIDEgMAoKCS8vIFB1c2ggZW1wdHkgYnl0ZXMgYWZ0ZXIgdGhlIGZyYW1lIHBvaW50ZXIgdG8gcmVzZXJ2ZSBzcGFjZSBmb3IgbG9jYWwgdmFyaWFibGVzCglieXRlIDB4CglkdXBuIDMKCgkvLyBjb250cmFjdHMvc3Rha2luZ1Bvb2wuYWxnby50czoxNDUKCS8vIGFzc2VydCghdGhpcy5zdGFrZXJzLmV4aXN0cywgJ3N0YWtpbmcgcG9vbCBhbHJlYWR5IGluaXRpYWxpemVkJykKCWJ5dGUgMHg3Mzc0NjE2YjY1NzI3MyAvLyAic3Rha2VycyIKCWJveF9sZW4KCXN3YXAKCXBvcAoJIQoKCS8vIHN0YWtpbmcgcG9vbCBhbHJlYWR5IGluaXRpYWxpemVkCglhc3NlcnQKCgkvLyBjb250cmFjdHMvc3Rha2luZ1Bvb2wuYWxnby50czoxNDgKCS8vIHZhbGlkYXRvckNvbmZpZyA9IHNlbmRNZXRob2RDYWxsPHR5cGVvZiBWYWxpZGF0b3JSZWdpc3RyeS5wcm90b3R5cGUuZ2V0VmFsaWRhdG9yQ29uZmlnPih7CgkvLyAgICAgICAgICAgICBhcHBsaWNhdGlvbklEOiBBcHBJRC5mcm9tVWludDY0KHRoaXMuY3JlYXRpbmdWYWxpZGF0b3JDb250cmFjdEFwcElkLnZhbHVlKSwKCS8vICAgICAgICAgICAgIG1ldGhvZEFyZ3M6IFt0aGlzLnZhbGlkYXRvcklkLnZhbHVlXSwKCS8vICAgICAgICAgfSkKCWl0eG5fYmVnaW4KCWludCBhcHBsCglpdHhuX2ZpZWxkIFR5cGVFbnVtCgltZXRob2QgImdldFZhbGlkYXRvckNvbmZpZyh1aW50NjQpKHVpbnQ2NCxhZGRyZXNzLGFkZHJlc3MsdWludDY0LHVpbnQ4LGJ5dGVbMzJdLHVpbnQ2NCx1aW50NjQsdWludDY0LHVpbnQxNix1aW50MzIsYWRkcmVzcyx1aW50NjQsdWludDY0LHVpbnQ4LHVpbnQ2NCx1aW50NjQpIgoJaXR4bl9maWVsZCBBcHBsaWNhdGlvbkFyZ3MKCgkvLyBjb250cmFjdHMvc3Rha2luZ1Bvb2wuYWxnby50czoxNDkKCS8vIGFwcGxpY2F0aW9uSUQ6IEFwcElELmZyb21VaW50NjQodGhpcy5jcmVhdGluZ1ZhbGlkYXRvckNvbnRyYWN0QXBwSWQudmFsdWUpCglieXRlIDB4NjM3MjY1NjE3NDZmNzI0MTcwNzAgLy8gImNyZWF0b3JBcHAiCglhcHBfZ2xvYmFsX2dldAoJaXR4bl9maWVsZCBBcHBsaWNhdGlvbklECgoJLy8gY29udHJhY3RzL3N0YWtpbmdQb29sLmFsZ28udHM6MTUwCgkvLyBtZXRob2RBcmdzOiBbdGhpcy52YWxpZGF0b3JJZC52YWx1ZV0KCWJ5dGUgMHg3NjYxNmM2OTY0NjE3NDZmNzI0OTY0IC8vICJ2YWxpZGF0b3JJZCIKCWFwcF9nbG9iYWxfZ2V0CglpdG9iCglpdHhuX2ZpZWxkIEFwcGxpY2F0aW9uQXJncwoKCS8vIEZlZSBmaWVsZCBub3Qgc2V0LCBkZWZhdWx0aW5nIHRvIDAKCWludCAwCglpdHhuX2ZpZWxkIEZlZQoKCS8vIFN1Ym1pdCBpbm5lciB0cmFuc2FjdGlvbgoJaXR4bl9zdWJtaXQKCWl0eG4gTnVtTG9ncwoJaW50IDEKCS0KCWl0eG5hcyBMb2dzCglleHRyYWN0IDQgMAoJZnJhbWVfYnVyeSAwIC8vIHZhbGlkYXRvckNvbmZpZzogKHVpbnQ2NCxhZGRyZXNzLGFkZHJlc3MsdWludDY0LHVpbnQ4LGJ5dGVbMzJdLHVpbnQ2NCx1aW50NjQsdWludDY0LHVpbnQxNix1aW50MzIsYWRkcmVzcyx1aW50NjQsdWludDY0LHVpbnQ4LHVpbnQ2NCx1aW50NjQpCgoJLy8gY29udHJhY3RzL3N0YWtpbmdQb29sLmFsZ28udHM6MTUyCgkvLyBpc1Rva2VuRWxpZ2libGUgPSB2YWxpZGF0b3JDb25maWcucmV3YXJkVG9rZW5JZCAhPT0gMAoJZnJhbWVfZGlnIDAgLy8gdmFsaWRhdG9yQ29uZmlnOiAodWludDY0LGFkZHJlc3MsYWRkcmVzcyx1aW50NjQsdWludDgsYnl0ZVszMl0sdWludDY0LHVpbnQ2NCx1aW50NjQsdWludDE2LHVpbnQzMixhZGRyZXNzLHVpbnQ2NCx1aW50NjQsdWludDgsdWludDY0LHVpbnQ2NCkKCWV4dHJhY3QgMTIxIDgKCWJ0b2kKCWludCAwCgkhPQoJZnJhbWVfYnVyeSAxIC8vIGlzVG9rZW5FbGlnaWJsZTogYm9vbAoKCS8vIGNvbnRyYWN0cy9zdGFraW5nUG9vbC5hbGdvLnRzOjE1MwoJLy8gZXh0cmFNQlIgPSBpc1Rva2VuRWxpZ2libGUgJiYgdGhpcy5wb29sSWQudmFsdWUgPT09IDEgPyBBU1NFVF9IT0xESU5HX0ZFRSA6IDAKCWZyYW1lX2RpZyAxIC8vIGlzVG9rZW5FbGlnaWJsZTogYm9vbAoJZHVwCglieiAqc2tpcF9hbmQxCglieXRlIDB4NzA2ZjZmNmM0OTY0IC8vICJwb29sSWQiCglhcHBfZ2xvYmFsX2dldAoJaW50IDEKCT09CgkmJgoKKnNraXBfYW5kMToKCWJ6ICp0ZXJuYXJ5MV9mYWxzZQoJaW50IDEwMDAwMAoJYiAqdGVybmFyeTFfZW5kCgoqdGVybmFyeTFfZmFsc2U6CglpbnQgMAoKKnRlcm5hcnkxX2VuZDoKCWZyYW1lX2J1cnkgMiAvLyBleHRyYU1CUjogdWludDY0CgoJLy8gY29udHJhY3RzL3N0YWtpbmdQb29sLmFsZ28udHM6MTU0CgkvLyBQb29sSW5pdE1iciA9CgkvLyAgICAgICAgICAgICBBTEdPUkFORF9BQ0NPVU5UX01JTl9CQUxBTkNFICsKCS8vICAgICAgICAgICAgIGV4dHJhTUJSICsKCS8vICAgICAgICAgICAgIHRoaXMuY29zdEZvckJveFN0b3JhZ2UoNyAvKiAnc3Rha2VycycgbmFtZSAqLyArIGxlbjxTdGFrZWRJbmZvPigpICogTUFYX1NUQUtFUlNfUEVSX1BPT0wpCglpbnQgMTAwMDAwCglmcmFtZV9kaWcgMiAvLyBleHRyYU1CUjogdWludDY0CgkrCglpbnQgMTI4MDcKCWNhbGxzdWIgY29zdEZvckJveFN0b3JhZ2UKCSsKCWZyYW1lX2J1cnkgMyAvLyBQb29sSW5pdE1icjogdWludDY0CgoJLy8gY29udHJhY3RzL3N0YWtpbmdQb29sLmFsZ28udHM6MTYwCgkvLyB2ZXJpZnlQYXlUeG4obWJyUGF5bWVudCwgeyBhbW91bnQ6IFBvb2xJbml0TWJyIH0pCgkvLyB2ZXJpZnkgYW1vdW50CglmcmFtZV9kaWcgLTEgLy8gbWJyUGF5bWVudDogUGF5VHhuCglndHhucyBBbW91bnQKCWZyYW1lX2RpZyAzIC8vIFBvb2xJbml0TWJyOiB1aW50NjQKCT09Cglhc3NlcnQKCgkvLyBjb250cmFjdHMvc3Rha2luZ1Bvb2wuYWxnby50czoxNjEKCS8vIHRoaXMuc3Rha2Vycy5jcmVhdGUoKQoJYnl0ZSAweDczNzQ2MTZiNjU3MjczIC8vICJzdGFrZXJzIgoJaW50IDEyODAwCglib3hfY3JlYXRlCglwb3AKCgkvLyAqaWYxX2NvbmRpdGlvbgoJLy8gY29udHJhY3RzL3N0YWtpbmdQb29sLmFsZ28udHM6MTYzCgkvLyBpc1Rva2VuRWxpZ2libGUgJiYgdGhpcy5wb29sSWQudmFsdWUgPT09IDEKCWZyYW1lX2RpZyAxIC8vIGlzVG9rZW5FbGlnaWJsZTogYm9vbAoJZHVwCglieiAqc2tpcF9hbmQyCglieXRlIDB4NzA2ZjZmNmM0OTY0IC8vICJwb29sSWQiCglhcHBfZ2xvYmFsX2dldAoJaW50IDEKCT09CgkmJgoKKnNraXBfYW5kMjoKCWJ6ICppZjFfZW5kCgoJLy8gKmlmMV9jb25zZXF1ZW50CgkvLyBjb250cmFjdHMvc3Rha2luZ1Bvb2wuYWxnby50czoxNjUKCS8vIHNlbmRBc3NldFRyYW5zZmVyKHsKCS8vICAgICAgICAgICAgICAgICB4ZmVyQXNzZXQ6IEFzc2V0SUQuZnJvbVVpbnQ2NCh2YWxpZGF0b3JDb25maWcucmV3YXJkVG9rZW5JZCksCgkvLyAgICAgICAgICAgICAgICAgYXNzZXRSZWNlaXZlcjogdGhpcy5hcHAuYWRkcmVzcywKCS8vICAgICAgICAgICAgICAgICBhc3NldEFtb3VudDogMCwKCS8vICAgICAgICAgICAgIH0pCglpdHhuX2JlZ2luCglpbnQgYXhmZXIKCWl0eG5fZmllbGQgVHlwZUVudW0KCgkvLyBjb250cmFjdHMvc3Rha2luZ1Bvb2wuYWxnby50czoxNjYKCS8vIHhmZXJBc3NldDogQXNzZXRJRC5mcm9tVWludDY0KHZhbGlkYXRvckNvbmZpZy5yZXdhcmRUb2tlbklkKQoJZnJhbWVfZGlnIDAgLy8gdmFsaWRhdG9yQ29uZmlnOiAodWludDY0LGFkZHJlc3MsYWRkcmVzcyx1aW50NjQsdWludDgsYnl0ZVszMl0sdWludDY0LHVpbnQ2NCx1aW50NjQsdWludDE2LHVpbnQzMixhZGRyZXNzLHVpbnQ2NCx1aW50NjQsdWludDgsdWludDY0LHVpbnQ2NCkKCWV4dHJhY3QgMTIxIDgKCWJ0b2kKCWl0eG5fZmllbGQgWGZlckFzc2V0CgoJLy8gY29udHJhY3RzL3N0YWtpbmdQb29sLmFsZ28udHM6MTY3CgkvLyBhc3NldFJlY2VpdmVyOiB0aGlzLmFwcC5hZGRyZXNzCglnbG9iYWwgQ3VycmVudEFwcGxpY2F0aW9uQWRkcmVzcwoJaXR4bl9maWVsZCBBc3NldFJlY2VpdmVyCgoJLy8gY29udHJhY3RzL3N0YWtpbmdQb29sLmFsZ28udHM6MTY4CgkvLyBhc3NldEFtb3VudDogMAoJaW50IDAKCWl0eG5fZmllbGQgQXNzZXRBbW91bnQKCgkvLyBGZWUgZmllbGQgbm90IHNldCwgZGVmYXVsdGluZyB0byAwCglpbnQgMAoJaXR4bl9maWVsZCBGZWUKCgkvLyBTdWJtaXQgaW5uZXIgdHJhbnNhY3Rpb24KCWl0eG5fc3VibWl0CgoqaWYxX2VuZDoKCXJldHN1YgoKLy8gYWRkU3Rha2UocGF5LGFkZHJlc3MpdWludDY0CiphYmlfcm91dGVfYWRkU3Rha2U6CgkvLyBUaGUgQUJJIHJldHVybiBwcmVmaXgKCWJ5dGUgMHgxNTFmN2M3NQoKCS8vIHN0YWtlcjogYWRkcmVzcwoJdHhuYSBBcHBsaWNhdGlvbkFyZ3MgMQoJZHVwCglsZW4KCWludCAzMgoJPT0KCWFzc2VydAoKCS8vIHN0YWtlZEFtb3VudFBheW1lbnQ6IHBheQoJdHhuIEdyb3VwSW5kZXgKCWludCAxCgktCglkdXAKCWd0eG5zIFR5cGVFbnVtCglpbnQgcGF5Cgk9PQoJYXNzZXJ0CgoJLy8gZXhlY3V0ZSBhZGRTdGFrZShwYXksYWRkcmVzcyl1aW50NjQKCWNhbGxzdWIgYWRkU3Rha2UKCWl0b2IKCWNvbmNhdAoJbG9nCglpbnQgMQoJcmV0dXJuCgovLyBhZGRTdGFrZShzdGFrZWRBbW91bnRQYXltZW50OiBQYXlUeG4sIHN0YWtlcjogQWRkcmVzcyk6IHVpbnQ2NAovLwovLyBBZGRzIHN0YWtlIHRvIHRoZSBnaXZlbiBhY2NvdW50LgovLyBDYW4gT05MWSBiZSBjYWxsZWQgYnkgdGhlIHZhbGlkYXRvciBjb250cmFjdCB0aGF0IGNyZWF0ZWQgdXMKLy8gTXVzdCByZWNlaXZlIHBheW1lbnQgZnJvbSB0aGUgdmFsaWRhdG9yIGNvbnRyYWN0IGZvciBhbW91bnQgYmVpbmcgc3Rha2VkLgovLwovLyBAcGFyYW0ge1BheVR4bn0gc3Rha2VkQW1vdW50UGF5bWVudCBwcmlvciBwYXltZW50IGNvbWluZyBmcm9tIHZhbGlkYXRvciBjb250cmFjdCB0byB1cyBvbiBiZWhhbGYgb2Ygc3Rha2VyLgovLyBAcGFyYW0ge0FkZHJlc3N9IHN0YWtlciAtIFRoZSBhY2NvdW50IGFkZGluZyBuZXcgc3Rha2UKLy8gQHRocm93cyB7RXJyb3J9IC0gVGhyb3dzIGFuIGVycm9yIGlmIHRoZSBzdGFraW5nIHBvb2wgaXMgZnVsbC4KLy8gQHJldHVybnMge3VpbnQ2NH0gbmV3ICdlbnRyeSB0aW1lJyBpbiBzZWNvbmRzIG9mIHN0YWtlIGFkZC4KYWRkU3Rha2U6Cglwcm90byAyIDEKCgkvLyBQdXNoIGVtcHR5IGJ5dGVzIGFmdGVyIHRoZSBmcmFtZSBwb2ludGVyIHRvIHJlc2VydmUgc3BhY2UgZm9yIGxvY2FsIHZhcmlhYmxlcwoJYnl0ZSAweAoJZHVwbiAzCgoJLy8gY29udHJhY3RzL3N0YWtpbmdQb29sLmFsZ28udHM6MTg0CgkvLyBhc3NlcnQodGhpcy5zdGFrZXJzLmV4aXN0cykKCWJ5dGUgMHg3Mzc0NjE2YjY1NzI3MyAvLyAic3Rha2VycyIKCWJveF9sZW4KCXN3YXAKCXBvcAoJYXNzZXJ0CgoJLy8gY29udHJhY3RzL3N0YWtpbmdQb29sLmFsZ28udHM6MTg3CgkvLyBhc3NlcnQodGhpcy50eG4uc2VuZGVyID09PSBBcHBJRC5mcm9tVWludDY0KHRoaXMuY3JlYXRpbmdWYWxpZGF0b3JDb250cmFjdEFwcElkLnZhbHVlKS5hZGRyZXNzKQoJdHhuIFNlbmRlcgoJYnl0ZSAweDYzNzI2NTYxNzQ2ZjcyNDE3MDcwIC8vICJjcmVhdG9yQXBwIgoJYXBwX2dsb2JhbF9nZXQKCWFwcF9wYXJhbXNfZ2V0IEFwcEFkZHJlc3MKCXBvcAoJPT0KCWFzc2VydAoKCS8vIGNvbnRyYWN0cy9zdGFraW5nUG9vbC5hbGdvLnRzOjE4OAoJLy8gYXNzZXJ0KHN0YWtlciAhPT0gZ2xvYmFscy56ZXJvQWRkcmVzcykKCWZyYW1lX2RpZyAtMiAvLyBzdGFrZXI6IEFkZHJlc3MKCWdsb2JhbCBaZXJvQWRkcmVzcwoJIT0KCWFzc2VydAoKCS8vIGNvbnRyYWN0cy9zdGFraW5nUG9vbC5hbGdvLnRzOjE5MgoJLy8gdmVyaWZ5UGF5VHhuKHN0YWtlZEFtb3VudFBheW1lbnQsIHsKCS8vICAgICAgICAgICAgIHNlbmRlcjogQXBwSUQuZnJvbVVpbnQ2NCh0aGlzLmNyZWF0aW5nVmFsaWRhdG9yQ29udHJhY3RBcHBJZC52YWx1ZSkuYWRkcmVzcywKCS8vICAgICAgICAgICAgIHJlY2VpdmVyOiB0aGlzLmFwcC5hZGRyZXNzLAoJLy8gICAgICAgICAgICAgYW1vdW50OiBzdGFrZWRBbW91bnRQYXltZW50LmFtb3VudCwKCS8vICAgICAgICAgfSkKCS8vIHZlcmlmeSBzZW5kZXIKCWZyYW1lX2RpZyAtMSAvLyBzdGFrZWRBbW91bnRQYXltZW50OiBQYXlUeG4KCWd0eG5zIFNlbmRlcgoJYnl0ZSAweDYzNzI2NTYxNzQ2ZjcyNDE3MDcwIC8vICJjcmVhdG9yQXBwIgoJYXBwX2dsb2JhbF9nZXQKCWFwcF9wYXJhbXNfZ2V0IEFwcEFkZHJlc3MKCXBvcAoJPT0KCWFzc2VydAoKCS8vIHZlcmlmeSByZWNlaXZlcgoJZnJhbWVfZGlnIC0xIC8vIHN0YWtlZEFtb3VudFBheW1lbnQ6IFBheVR4bgoJZ3R4bnMgUmVjZWl2ZXIKCWdsb2JhbCBDdXJyZW50QXBwbGljYXRpb25BZGRyZXNzCgk9PQoJYXNzZXJ0CgoJLy8gdmVyaWZ5IGFtb3VudAoJZnJhbWVfZGlnIC0xIC8vIHN0YWtlZEFtb3VudFBheW1lbnQ6IFBheVR4bgoJZ3R4bnMgQW1vdW50CglmcmFtZV9kaWcgLTEgLy8gc3Rha2VkQW1vdW50UGF5bWVudDogUGF5VHhuCglndHhucyBBbW91bnQKCT09Cglhc3NlcnQKCgkvLyBjb250cmFjdHMvc3Rha2luZ1Bvb2wuYWxnby50czoyMDEKCS8vIGVudHJ5VGltZSA9IHRoaXMuZ2V0RW50cnlUaW1lKCkKCWNhbGxzdWIgZ2V0RW50cnlUaW1lCglmcmFtZV9idXJ5IDAgLy8gZW50cnlUaW1lOiB1aW50NjQKCgkvLyBjb250cmFjdHMvc3Rha2luZ1Bvb2wuYWxnby50czoyMDIKCS8vIGZpcnN0RW1wdHkgPSAwCglpbnQgMAoJZnJhbWVfYnVyeSAxIC8vIGZpcnN0RW1wdHk6IHVpbnQ2NAoKCS8vIGNvbnRyYWN0cy9zdGFraW5nUG9vbC5hbGdvLnRzOjIwNQoJLy8gZm9yIChsZXQgaSA9IDA7IGkgPCB0aGlzLnN0YWtlcnMudmFsdWUubGVuZ3RoOyBpICs9IDEpCglpbnQgMAoJZnJhbWVfYnVyeSAyIC8vIGk6IHVpbnQ2NAoKKmZvcl8wOgoJLy8gY29udHJhY3RzL3N0YWtpbmdQb29sLmFsZ28udHM6MjA1CgkvLyBpIDwgdGhpcy5zdGFrZXJzLnZhbHVlLmxlbmd0aAoJZnJhbWVfZGlnIDIgLy8gaTogdWludDY0CglpbnQgMjAwCgk8CglieiAqZm9yXzBfZW5kCgoJLy8gKmlmMl9jb25kaXRpb24KCS8vIGNvbnRyYWN0cy9zdGFraW5nUG9vbC5hbGdvLnRzOjIwNgoJLy8gZ2xvYmFscy5vcGNvZGVCdWRnZXQgPCAzMDAKCWdsb2JhbCBPcGNvZGVCdWRnZXQKCWludCAzMDAKCTwKCWJ6ICppZjJfZW5kCgoJLy8gKmlmMl9jb25zZXF1ZW50CgkvLyBjb250cmFjdHMvc3Rha2luZ1Bvb2wuYWxnby50czoyMDcKCS8vIGluY3JlYXNlT3Bjb2RlQnVkZ2V0KCkKCWl0eG5fYmVnaW4KCWludCBhcHBsCglpdHhuX2ZpZWxkIFR5cGVFbnVtCglpbnQgMAoJaXR4bl9maWVsZCBGZWUKCWJ5dGUgYjY0IENvRUIgLy8gI3ByYWdtYSB2ZXJzaW9uIDEwOyBpbnQgMQoJZHVwCglpdHhuX2ZpZWxkIEFwcHJvdmFsUHJvZ3JhbQoJaXR4bl9maWVsZCBDbGVhclN0YXRlUHJvZ3JhbQoJaW50IERlbGV0ZUFwcGxpY2F0aW9uCglpdHhuX2ZpZWxkIE9uQ29tcGxldGlvbgoJaXR4bl9zdWJtaXQKCippZjJfZW5kOgoJLy8gY29udHJhY3RzL3N0YWtpbmdQb29sLmFsZ28udHM6MjA5CgkvLyBjbXBTdGFrZXIgPSBjbG9uZSh0aGlzLnN0YWtlcnMudmFsdWVbaV0pCglmcmFtZV9kaWcgMiAvLyBpOiB1aW50NjQKCWludCA2NAoJKiAvLyBhY2MgKiB0eXBlTGVuZ3RoCglpbnQgNjQKCWJ5dGUgMHg3Mzc0NjE2YjY1NzI3MyAvLyAic3Rha2VycyIKCWNvdmVyIDIKCWJveF9leHRyYWN0CglmcmFtZV9idXJ5IDMgLy8gY21wU3Rha2VyOiAoYWRkcmVzcyx1aW50NjQsdWludDY0LHVpbnQ2NCx1aW50NjQpCgoJLy8gKmlmM19jb25kaXRpb24KCS8vIGNvbnRyYWN0cy9zdGFraW5nUG9vbC5hbGdvLnRzOjIxMAoJLy8gY21wU3Rha2VyLmFjY291bnQgPT09IHN0YWtlcgoJZnJhbWVfZGlnIDMgLy8gY21wU3Rha2VyOiAoYWRkcmVzcyx1aW50NjQsdWludDY0LHVpbnQ2NCx1aW50NjQpCglleHRyYWN0IDAgMzIKCWZyYW1lX2RpZyAtMiAvLyBzdGFrZXI6IEFkZHJlc3MKCT09CglieiAqaWYzX2VuZAoKCS8vICppZjNfY29uc2VxdWVudAoJLy8gY29udHJhY3RzL3N0YWtpbmdQb29sLmFsZ28udHM6MjExCgkvLyBjbXBTdGFrZXIuYmFsYW5jZSArPSBzdGFrZWRBbW91bnRQYXltZW50LmFtb3VudAoJZnJhbWVfZGlnIDMgLy8gY21wU3Rha2VyOiAoYWRkcmVzcyx1aW50NjQsdWludDY0LHVpbnQ2NCx1aW50NjQpCglpbnQgMzIgLy8gaGVhZE9mZnNldAoJZnJhbWVfZGlnIDMgLy8gY21wU3Rha2VyOiAoYWRkcmVzcyx1aW50NjQsdWludDY0LHVpbnQ2NCx1aW50NjQpCglleHRyYWN0IDMyIDgKCWJ0b2kKCWZyYW1lX2RpZyAtMSAvLyBzdGFrZWRBbW91bnRQYXltZW50OiBQYXlUeG4KCWd0eG5zIEFtb3VudAoJKwoJaXRvYgoJcmVwbGFjZTMKCWZyYW1lX2J1cnkgMyAvLyBjbXBTdGFrZXI6IChhZGRyZXNzLHVpbnQ2NCx1aW50NjQsdWludDY0LHVpbnQ2NCkKCgkvLyBjb250cmFjdHMvc3Rha2luZ1Bvb2wuYWxnby50czoyMTIKCS8vIGNtcFN0YWtlci5lbnRyeVRpbWUgPSBlbnRyeVRpbWUKCWZyYW1lX2RpZyAzIC8vIGNtcFN0YWtlcjogKGFkZHJlc3MsdWludDY0LHVpbnQ2NCx1aW50NjQsdWludDY0KQoJaW50IDU2IC8vIGhlYWRPZmZzZXQKCWZyYW1lX2RpZyAwIC8vIGVudHJ5VGltZTogdWludDY0CglpdG9iCglyZXBsYWNlMwoJZnJhbWVfYnVyeSAzIC8vIGNtcFN0YWtlcjogKGFkZHJlc3MsdWludDY0LHVpbnQ2NCx1aW50NjQsdWludDY0KQoKCS8vIGNvbnRyYWN0cy9zdGFraW5nUG9vbC5hbGdvLnRzOjIxNQoJLy8gdGhpcy5zdGFrZXJzLnZhbHVlW2ldID0gY21wU3Rha2VyCglmcmFtZV9kaWcgMiAvLyBpOiB1aW50NjQKCWludCA2NAoJKiAvLyBhY2MgKiB0eXBlTGVuZ3RoCglmcmFtZV9kaWcgMyAvLyBjbXBTdGFrZXI6IChhZGRyZXNzLHVpbnQ2NCx1aW50NjQsdWludDY0LHVpbnQ2NCkKCWJ5dGUgMHg3Mzc0NjE2YjY1NzI3MyAvLyAic3Rha2VycyIKCWNvdmVyIDIKCWJveF9yZXBsYWNlCgoJLy8gY29udHJhY3RzL3N0YWtpbmdQb29sLmFsZ28udHM6MjE3CgkvLyB0aGlzLnRvdGFsQWxnb1N0YWtlZC52YWx1ZSArPSBzdGFrZWRBbW91bnRQYXltZW50LmFtb3VudAoJYnl0ZSAweDczNzQ2MTZiNjU2NCAvLyAic3Rha2VkIgoJYXBwX2dsb2JhbF9nZXQKCWZyYW1lX2RpZyAtMSAvLyBzdGFrZWRBbW91bnRQYXltZW50OiBQYXlUeG4KCWd0eG5zIEFtb3VudAoJKwoJYnl0ZSAweDczNzQ2MTZiNjU2NCAvLyAic3Rha2VkIgoJc3dhcAoJYXBwX2dsb2JhbF9wdXQKCgkvLyBjb250cmFjdHMvc3Rha2luZ1Bvb2wuYWxnby50czoyMTgKCS8vIHJldHVybiBlbnRyeVRpbWU7CglmcmFtZV9kaWcgMCAvLyBlbnRyeVRpbWU6IHVpbnQ2NAoKCS8vIHNldCB0aGUgc3Vicm91dGluZSByZXR1cm4gdmFsdWUKCWZyYW1lX2J1cnkgMAoKCS8vIHBvcCBhbGwgbG9jYWwgdmFyaWFibGVzIGZyb20gdGhlIHN0YWNrCglwb3BuIDMKCXJldHN1YgoKKmlmM19lbmQ6CgkvLyAqaWY0X2NvbmRpdGlvbgoJLy8gY29udHJhY3RzL3N0YWtpbmdQb29sLmFsZ28udHM6MjIwCgkvLyBjbXBTdGFrZXIuYWNjb3VudCA9PT0gZ2xvYmFscy56ZXJvQWRkcmVzcwoJZnJhbWVfZGlnIDMgLy8gY21wU3Rha2VyOiAoYWRkcmVzcyx1aW50NjQsdWludDY0LHVpbnQ2NCx1aW50NjQpCglleHRyYWN0IDAgMzIKCWdsb2JhbCBaZXJvQWRkcmVzcwoJPT0KCWJ6ICppZjRfZW5kCgoJLy8gKmlmNF9jb25zZXF1ZW50CgkvLyBjb250cmFjdHMvc3Rha2luZ1Bvb2wuYWxnby50czoyMjEKCS8vIGZpcnN0RW1wdHkgPSBpICsgMQoJZnJhbWVfZGlnIDIgLy8gaTogdWludDY0CglpbnQgMQoJKwoJZnJhbWVfYnVyeSAxIC8vIGZpcnN0RW1wdHk6IHVpbnQ2NAoJYiAqZm9yXzBfZW5kCgoqaWY0X2VuZDoKCipmb3JfMF9jb250aW51ZToKCS8vIGNvbnRyYWN0cy9zdGFraW5nUG9vbC5hbGdvLnRzOjIwNQoJLy8gaSArPSAxCglmcmFtZV9kaWcgMiAvLyBpOiB1aW50NjQKCWludCAxCgkrCglmcmFtZV9idXJ5IDIgLy8gaTogdWludDY0CgliICpmb3JfMAoKKmZvcl8wX2VuZDoKCS8vICppZjVfY29uZGl0aW9uCgkvLyBjb250cmFjdHMvc3Rha2luZ1Bvb2wuYWxnby50czoyMjYKCS8vIGZpcnN0RW1wdHkgPT09IDAKCWZyYW1lX2RpZyAxIC8vIGZpcnN0RW1wdHk6IHVpbnQ2NAoJaW50IDAKCT09CglieiAqaWY1X2VuZAoKCS8vICppZjVfY29uc2VxdWVudAoJZXJyIC8vICdTdGFraW5nIHBvb2wgZnVsbCcKCippZjVfZW5kOgoJLy8gY29udHJhY3RzL3N0YWtpbmdQb29sLmFsZ28udHM6MjMzCgkvLyBhc3NlcnQoc3Rha2VkQW1vdW50UGF5bWVudC5hbW91bnQgPj0gdGhpcy5taW5FbnRyeVN0YWtlLnZhbHVlLCAnbXVzdCBzdGFrZSBhdCBsZWFzdCB0aGUgbWluaW11bSBmb3IgdGhpcyBwb29sJykKCWZyYW1lX2RpZyAtMSAvLyBzdGFrZWRBbW91bnRQYXltZW50OiBQYXlUeG4KCWd0eG5zIEFtb3VudAoJYnl0ZSAweDZkNjk2ZTQ1NmU3NDcyNzk1Mzc0NjE2YjY1IC8vICJtaW5FbnRyeVN0YWtlIgoJYXBwX2dsb2JhbF9nZXQKCT49CgoJLy8gbXVzdCBzdGFrZSBhdCBsZWFzdCB0aGUgbWluaW11bSBmb3IgdGhpcyBwb29sCglhc3NlcnQKCgkvLyBjb250cmFjdHMvc3Rha2luZ1Bvb2wuYWxnby50czoyMzUKCS8vIGFzc2VydCh0aGlzLnN0YWtlcnMudmFsdWVbZmlyc3RFbXB0eSAtIDFdLmFjY291bnQgPT09IGdsb2JhbHMuemVyb0FkZHJlc3MpCglmcmFtZV9kaWcgMSAvLyBmaXJzdEVtcHR5OiB1aW50NjQKCWludCAxCgktCglpbnQgNjQKCSogLy8gYWNjICogdHlwZUxlbmd0aAoJaW50IDAKCSsKCWludCAzMgoJYnl0ZSAweDczNzQ2MTZiNjU3MjczIC8vICJzdGFrZXJzIgoJY292ZXIgMgoJYm94X2V4dHJhY3QKCWdsb2JhbCBaZXJvQWRkcmVzcwoJPT0KCWFzc2VydAoKCS8vIGNvbnRyYWN0cy9zdGFraW5nUG9vbC5hbGdvLnRzOjIzNgoJLy8gdGhpcy5zdGFrZXJzLnZhbHVlW2ZpcnN0RW1wdHkgLSAxXSA9IHsKCS8vICAgICAgICAgICAgIGFjY291bnQ6IHN0YWtlciwKCS8vICAgICAgICAgICAgIGJhbGFuY2U6IHN0YWtlZEFtb3VudFBheW1lbnQuYW1vdW50LAoJLy8gICAgICAgICAgICAgdG90YWxSZXdhcmRlZDogMCwKCS8vICAgICAgICAgICAgIHJld2FyZFRva2VuQmFsYW5jZTogMCwKCS8vICAgICAgICAgICAgIGVudHJ5VGltZTogZW50cnlUaW1lLAoJLy8gICAgICAgICB9CglmcmFtZV9kaWcgMSAvLyBmaXJzdEVtcHR5OiB1aW50NjQKCWludCAxCgktCglpbnQgNjQKCSogLy8gYWNjICogdHlwZUxlbmd0aAoJZnJhbWVfZGlnIC0yIC8vIHN0YWtlcjogQWRkcmVzcwoJZnJhbWVfZGlnIC0xIC8vIHN0YWtlZEFtb3VudFBheW1lbnQ6IFBheVR4bgoJZ3R4bnMgQW1vdW50CglpdG9iCgljb25jYXQKCWJ5dGUgMHgwMDAwMDAwMDAwMDAwMDAwCgljb25jYXQKCWJ5dGUgMHgwMDAwMDAwMDAwMDAwMDAwCgljb25jYXQKCWZyYW1lX2RpZyAwIC8vIGVudHJ5VGltZTogdWludDY0CglpdG9iCgljb25jYXQKCWJ5dGUgMHg3Mzc0NjE2YjY1NzI3MyAvLyAic3Rha2VycyIKCWNvdmVyIDIKCWJveF9yZXBsYWNlCgoJLy8gY29udHJhY3RzL3N0YWtpbmdQb29sLmFsZ28udHM6MjQzCgkvLyB0aGlzLm51bVN0YWtlcnMudmFsdWUgKz0gMQoJYnl0ZSAweDZlNzU2ZDUzNzQ2MTZiNjU3MjczIC8vICJudW1TdGFrZXJzIgoJYXBwX2dsb2JhbF9nZXQKCWludCAxCgkrCglieXRlIDB4NmU3NTZkNTM3NDYxNmI2NTcyNzMgLy8gIm51bVN0YWtlcnMiCglzd2FwCglhcHBfZ2xvYmFsX3B1dAoKCS8vIGNvbnRyYWN0cy9zdGFraW5nUG9vbC5hbGdvLnRzOjI0NAoJLy8gdGhpcy50b3RhbEFsZ29TdGFrZWQudmFsdWUgKz0gc3Rha2VkQW1vdW50UGF5bWVudC5hbW91bnQKCWJ5dGUgMHg3Mzc0NjE2YjY1NjQgLy8gInN0YWtlZCIKCWFwcF9nbG9iYWxfZ2V0CglmcmFtZV9kaWcgLTEgLy8gc3Rha2VkQW1vdW50UGF5bWVudDogUGF5VHhuCglndHhucyBBbW91bnQKCSsKCWJ5dGUgMHg3Mzc0NjE2YjY1NjQgLy8gInN0YWtlZCIKCXN3YXAKCWFwcF9nbG9iYWxfcHV0CgoJLy8gY29udHJhY3RzL3N0YWtpbmdQb29sLmFsZ28udHM6MjQ1CgkvLyByZXR1cm4gZW50cnlUaW1lOwoJZnJhbWVfZGlnIDAgLy8gZW50cnlUaW1lOiB1aW50NjQKCgkvLyBzZXQgdGhlIHN1YnJvdXRpbmUgcmV0dXJuIHZhbHVlCglmcmFtZV9idXJ5IDAKCgkvLyBwb3AgYWxsIGxvY2FsIHZhcmlhYmxlcyBmcm9tIHRoZSBzdGFjawoJcG9wbiAzCglyZXRzdWIKCi8vIHJlbW92ZVN0YWtlKHVpbnQ2NCl2b2lkCiphYmlfcm91dGVfcmVtb3ZlU3Rha2U6CgkvLyBhbW91bnRUb1Vuc3Rha2U6IHVpbnQ2NAoJdHhuYSBBcHBsaWNhdGlvbkFyZ3MgMQoJYnRvaQoKCS8vIGV4ZWN1dGUgcmVtb3ZlU3Rha2UodWludDY0KXZvaWQKCWNhbGxzdWIgcmVtb3ZlU3Rha2UKCWludCAxCglyZXR1cm4KCi8vIHJlbW92ZVN0YWtlKGFtb3VudFRvVW5zdGFrZTogdWludDY0KTogdm9pZAovLwovLyBSZW1vdmVzIHN0YWtlIG9uIGJlaGFsZiBvZiBjYWxsZXIgKHJlbW92aW5nIG93biBzdGFrZSkuICBJZiBhbnkgdG9rZW4gcmV3YXJkcyBleGlzdCwgdGhvc2UgYXJlIGFsd2F5cyBzZW50IGluCi8vIGZ1bGwuIEFsc28gbm90aWZpZXMgdGhlIHZhbGlkYXRvciBjb250cmFjdCBmb3IgdGhpcyBwb29scyB2YWxpZGF0b3Igb2YgdGhlIHN0YWtlciAvIGJhbGFuY2UgY2hhbmdlcy4KLy8KLy8gQHBhcmFtIHt1aW50NjR9IGFtb3VudFRvVW5zdGFrZSAtIFRoZSBhbW91bnQgb2Ygc3Rha2UgdG8gYmUgcmVtb3ZlZC4gIFNwZWNpZnkgMCB0byByZW1vdmUgYWxsIHN0YWtlLgovLyBAdGhyb3dzIHtFcnJvcn0gSWYgdGhlIGFjY291bnQgaGFzIGluc3VmZmljaWVudCBiYWxhbmNlIG9yIGlmIHRoZSBhY2NvdW50IGlzIG5vdCBmb3VuZC4KcmVtb3ZlU3Rha2U6Cglwcm90byAxIDAKCgkvLyBQdXNoIGVtcHR5IGJ5dGVzIGFmdGVyIHRoZSBmcmFtZSBwb2ludGVyIHRvIHJlc2VydmUgc3BhY2UgZm9yIGxvY2FsIHZhcmlhYmxlcwoJYnl0ZSAweAoJZHVwbiA1CgoJLy8gY29udHJhY3RzL3N0YWtpbmdQb29sLmFsZ28udHM6MjU5CgkvLyBzdGFrZXIgPSB0aGlzLnR4bi5zZW5kZXIKCXR4biBTZW5kZXIKCWZyYW1lX2J1cnkgMCAvLyBzdGFrZXI6IGFkZHJlc3MKCgkvLyBjb250cmFjdHMvc3Rha2luZ1Bvb2wuYWxnby50czoyNjEKCS8vIGZvciAobGV0IGkgPSAwOyBpIDwgdGhpcy5zdGFrZXJzLnZhbHVlLmxlbmd0aDsgaSArPSAxKQoJaW50IDAKCWZyYW1lX2J1cnkgMSAvLyBpOiB1aW50NjQKCipmb3JfMToKCS8vIGNvbnRyYWN0cy9zdGFraW5nUG9vbC5hbGdvLnRzOjI2MQoJLy8gaSA8IHRoaXMuc3Rha2Vycy52YWx1ZS5sZW5ndGgKCWZyYW1lX2RpZyAxIC8vIGk6IHVpbnQ2NAoJaW50IDIwMAoJPAoJYnogKmZvcl8xX2VuZAoKCS8vICppZjZfY29uZGl0aW9uCgkvLyBjb250cmFjdHMvc3Rha2luZ1Bvb2wuYWxnby50czoyNjIKCS8vIGdsb2JhbHMub3Bjb2RlQnVkZ2V0IDwgMzAwCglnbG9iYWwgT3Bjb2RlQnVkZ2V0CglpbnQgMzAwCgk8CglieiAqaWY2X2VuZAoKCS8vICppZjZfY29uc2VxdWVudAoJLy8gY29udHJhY3RzL3N0YWtpbmdQb29sLmFsZ28udHM6MjYzCgkvLyBpbmNyZWFzZU9wY29kZUJ1ZGdldCgpCglpdHhuX2JlZ2luCglpbnQgYXBwbAoJaXR4bl9maWVsZCBUeXBlRW51bQoJaW50IDAKCWl0eG5fZmllbGQgRmVlCglieXRlIGI2NCBDb0VCIC8vICNwcmFnbWEgdmVyc2lvbiAxMDsgaW50IDEKCWR1cAoJaXR4bl9maWVsZCBBcHByb3ZhbFByb2dyYW0KCWl0eG5fZmllbGQgQ2xlYXJTdGF0ZVByb2dyYW0KCWludCBEZWxldGVBcHBsaWNhdGlvbgoJaXR4bl9maWVsZCBPbkNvbXBsZXRpb24KCWl0eG5fc3VibWl0CgoqaWY2X2VuZDoKCS8vIGNvbnRyYWN0cy9zdGFraW5nUG9vbC5hbGdvLnRzOjI2NQoJLy8gY21wU3Rha2VyID0gY2xvbmUodGhpcy5zdGFrZXJzLnZhbHVlW2ldKQoJZnJhbWVfZGlnIDEgLy8gaTogdWludDY0CglpbnQgNjQKCSogLy8gYWNjICogdHlwZUxlbmd0aAoJaW50IDY0CglieXRlIDB4NzM3NDYxNmI2NTcyNzMgLy8gInN0YWtlcnMiCgljb3ZlciAyCglib3hfZXh0cmFjdAoJZnJhbWVfYnVyeSAyIC8vIGNtcFN0YWtlcjogKGFkZHJlc3MsdWludDY0LHVpbnQ2NCx1aW50NjQsdWludDY0KQoKCS8vICppZjdfY29uZGl0aW9uCgkvLyBjb250cmFjdHMvc3Rha2luZ1Bvb2wuYWxnby50czoyNjYKCS8vIGNtcFN0YWtlci5hY2NvdW50ID09PSBzdGFrZXIKCWZyYW1lX2RpZyAyIC8vIGNtcFN0YWtlcjogKGFkZHJlc3MsdWludDY0LHVpbnQ2NCx1aW50NjQsdWludDY0KQoJZXh0cmFjdCAwIDMyCglmcmFtZV9kaWcgMCAvLyBzdGFrZXI6IGFkZHJlc3MKCT09CglieiAqaWY3X2VuZAoKCS8vICppZjdfY29uc2VxdWVudAoJLy8gKmlmOF9jb25kaXRpb24KCS8vIGNvbnRyYWN0cy9zdGFraW5nUG9vbC5hbGdvLnRzOjI2NwoJLy8gYW1vdW50VG9VbnN0YWtlID09PSAwCglmcmFtZV9kaWcgLTEgLy8gYW1vdW50VG9VbnN0YWtlOiB1aW50NjQKCWludCAwCgk9PQoJYnogKmlmOF9lbmQKCgkvLyAqaWY4X2NvbnNlcXVlbnQKCS8vIGNvbnRyYWN0cy9zdGFraW5nUG9vbC5hbGdvLnRzOjI2OQoJLy8gYW1vdW50VG9VbnN0YWtlID0gY21wU3Rha2VyLmJhbGFuY2UKCWZyYW1lX2RpZyAyIC8vIGNtcFN0YWtlcjogKGFkZHJlc3MsdWludDY0LHVpbnQ2NCx1aW50NjQsdWludDY0KQoJZXh0cmFjdCAzMiA4CglidG9pCglmcmFtZV9idXJ5IC0xIC8vIGFtb3VudFRvVW5zdGFrZTogdWludDY0CgoqaWY4X2VuZDoKCS8vICppZjlfY29uZGl0aW9uCgkvLyBjb250cmFjdHMvc3Rha2luZ1Bvb2wuYWxnby50czoyNzEKCS8vIGNtcFN0YWtlci5iYWxhbmNlIDwgYW1vdW50VG9VbnN0YWtlCglmcmFtZV9kaWcgMiAvLyBjbXBTdGFrZXI6IChhZGRyZXNzLHVpbnQ2NCx1aW50NjQsdWludDY0LHVpbnQ2NCkKCWV4dHJhY3QgMzIgOAoJYnRvaQoJZnJhbWVfZGlnIC0xIC8vIGFtb3VudFRvVW5zdGFrZTogdWludDY0Cgk8CglieiAqaWY5X2VuZAoKCS8vICppZjlfY29uc2VxdWVudAoJZXJyIC8vICdJbnN1ZmZpY2llbnQgYmFsYW5jZScKCippZjlfZW5kOgoJLy8gY29udHJhY3RzL3N0YWtpbmdQb29sLmFsZ28udHM6Mjc0CgkvLyBjbXBTdGFrZXIuYmFsYW5jZSAtPSBhbW91bnRUb1Vuc3Rha2UKCWZyYW1lX2RpZyAyIC8vIGNtcFN0YWtlcjogKGFkZHJlc3MsdWludDY0LHVpbnQ2NCx1aW50NjQsdWludDY0KQoJaW50IDMyIC8vIGhlYWRPZmZzZXQKCWZyYW1lX2RpZyAyIC8vIGNtcFN0YWtlcjogKGFkZHJlc3MsdWludDY0LHVpbnQ2NCx1aW50NjQsdWludDY0KQoJZXh0cmFjdCAzMiA4CglidG9pCglmcmFtZV9kaWcgLTEgLy8gYW1vdW50VG9VbnN0YWtlOiB1aW50NjQKCS0KCWl0b2IKCXJlcGxhY2UzCglmcmFtZV9idXJ5IDIgLy8gY21wU3Rha2VyOiAoYWRkcmVzcyx1aW50NjQsdWludDY0LHVpbnQ2NCx1aW50NjQpCgoJLy8gY29udHJhY3RzL3N0YWtpbmdQb29sLmFsZ28udHM6Mjc1CgkvLyB0aGlzLnRvdGFsQWxnb1N0YWtlZC52YWx1ZSAtPSBhbW91bnRUb1Vuc3Rha2UKCWJ5dGUgMHg3Mzc0NjE2YjY1NjQgLy8gInN0YWtlZCIKCWFwcF9nbG9iYWxfZ2V0CglmcmFtZV9kaWcgLTEgLy8gYW1vdW50VG9VbnN0YWtlOiB1aW50NjQKCS0KCWJ5dGUgMHg3Mzc0NjE2YjY1NjQgLy8gInN0YWtlZCIKCXN3YXAKCWFwcF9nbG9iYWxfcHV0CgoJLy8gY29udHJhY3RzL3N0YWtpbmdQb29sLmFsZ28udHM6Mjc3CgkvLyBhbW91bnRSZXdhcmRUb2tlblJlbW92ZWQgPSAwCglpbnQgMAoJZnJhbWVfYnVyeSAzIC8vIGFtb3VudFJld2FyZFRva2VuUmVtb3ZlZDogdWludDY0CgoJLy8gKmlmMTBfY29uZGl0aW9uCgkvLyBjb250cmFjdHMvc3Rha2luZ1Bvb2wuYWxnby50czoyNzgKCS8vIGNtcFN0YWtlci5yZXdhcmRUb2tlbkJhbGFuY2UgPiAwCglmcmFtZV9kaWcgMiAvLyBjbXBTdGFrZXI6IChhZGRyZXNzLHVpbnQ2NCx1aW50NjQsdWludDY0LHVpbnQ2NCkKCWV4dHJhY3QgNDggOAoJYnRvaQoJaW50IDAKCT4KCWJ6ICppZjEwX2VuZAoKCS8vICppZjEwX2NvbnNlcXVlbnQKCS8vICppZjExX2NvbmRpdGlvbgoJLy8gY29udHJhY3RzL3N0YWtpbmdQb29sLmFsZ28udHM6MjgwCgkvLyB0aGlzLnBvb2xJZC52YWx1ZSA9PT0gMQoJYnl0ZSAweDcwNmY2ZjZjNDk2NCAvLyAicG9vbElkIgoJYXBwX2dsb2JhbF9nZXQKCWludCAxCgk9PQoJYnogKmlmMTFfZWxzZQoKCS8vICppZjExX2NvbnNlcXVlbnQKCS8vIGNvbnRyYWN0cy9zdGFraW5nUG9vbC5hbGdvLnRzOjI4MQoJLy8gdmFsaWRhdG9yQ29uZmlnID0gc2VuZE1ldGhvZENhbGw8dHlwZW9mIFZhbGlkYXRvclJlZ2lzdHJ5LnByb3RvdHlwZS5nZXRWYWxpZGF0b3JDb25maWc+KHsKCS8vICAgICAgICAgICAgICAgICAgICAgICAgICAgICBhcHBsaWNhdGlvbklEOiBBcHBJRC5mcm9tVWludDY0KHRoaXMuY3JlYXRpbmdWYWxpZGF0b3JDb250cmFjdEFwcElkLnZhbHVlKSwKCS8vICAgICAgICAgICAgICAgICAgICAgICAgICAgICBtZXRob2RBcmdzOiBbdGhpcy52YWxpZGF0b3JJZC52YWx1ZV0sCgkvLyAgICAgICAgICAgICAgICAgICAgICAgICB9KQoJaXR4bl9iZWdpbgoJaW50IGFwcGwKCWl0eG5fZmllbGQgVHlwZUVudW0KCW1ldGhvZCAiZ2V0VmFsaWRhdG9yQ29uZmlnKHVpbnQ2NCkodWludDY0LGFkZHJlc3MsYWRkcmVzcyx1aW50NjQsdWludDgsYnl0ZVszMl0sdWludDY0LHVpbnQ2NCx1aW50NjQsdWludDE2LHVpbnQzMixhZGRyZXNzLHVpbnQ2NCx1aW50NjQsdWludDgsdWludDY0LHVpbnQ2NCkiCglpdHhuX2ZpZWxkIEFwcGxpY2F0aW9uQXJncwoKCS8vIGNvbnRyYWN0cy9zdGFraW5nUG9vbC5hbGdvLnRzOjI4MgoJLy8gYXBwbGljYXRpb25JRDogQXBwSUQuZnJvbVVpbnQ2NCh0aGlzLmNyZWF0aW5nVmFsaWRhdG9yQ29udHJhY3RBcHBJZC52YWx1ZSkKCWJ5dGUgMHg2MzcyNjU2MTc0NmY3MjQxNzA3MCAvLyAiY3JlYXRvckFwcCIKCWFwcF9nbG9iYWxfZ2V0CglpdHhuX2ZpZWxkIEFwcGxpY2F0aW9uSUQKCgkvLyBjb250cmFjdHMvc3Rha2luZ1Bvb2wuYWxnby50czoyODMKCS8vIG1ldGhvZEFyZ3M6IFt0aGlzLnZhbGlkYXRvcklkLnZhbHVlXQoJYnl0ZSAweDc2NjE2YzY5NjQ2MTc0NmY3MjQ5NjQgLy8gInZhbGlkYXRvcklkIgoJYXBwX2dsb2JhbF9nZXQKCWl0b2IKCWl0eG5fZmllbGQgQXBwbGljYXRpb25BcmdzCgoJLy8gRmVlIGZpZWxkIG5vdCBzZXQsIGRlZmF1bHRpbmcgdG8gMAoJaW50IDAKCWl0eG5fZmllbGQgRmVlCgoJLy8gU3VibWl0IGlubmVyIHRyYW5zYWN0aW9uCglpdHhuX3N1Ym1pdAoJaXR4biBOdW1Mb2dzCglpbnQgMQoJLQoJaXR4bmFzIExvZ3MKCWV4dHJhY3QgNCAwCglmcmFtZV9idXJ5IDQgLy8gdmFsaWRhdG9yQ29uZmlnOiAodWludDY0LGFkZHJlc3MsYWRkcmVzcyx1aW50NjQsdWludDgsYnl0ZVszMl0sdWludDY0LHVpbnQ2NCx1aW50NjQsdWludDE2LHVpbnQzMixhZGRyZXNzLHVpbnQ2NCx1aW50NjQsdWludDgsdWludDY0LHVpbnQ2NCkKCgkvLyBjb250cmFjdHMvc3Rha2luZ1Bvb2wuYWxnby50czoyODkKCS8vIHNlbmRBc3NldFRyYW5zZmVyKHsKCS8vICAgICAgICAgICAgICAgICAgICAgICAgICAgICB4ZmVyQXNzZXQ6IEFzc2V0SUQuZnJvbVVpbnQ2NCh2YWxpZGF0b3JDb25maWcucmV3YXJkVG9rZW5JZCksCgkvLyAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYXNzZXRSZWNlaXZlcjogc3Rha2VyLAoJLy8gICAgICAgICAgICAgICAgICAgICAgICAgICAgIGFzc2V0QW1vdW50OiBjbXBTdGFrZXIucmV3YXJkVG9rZW5CYWxhbmNlLAoJLy8gICAgICAgICAgICAgICAgICAgICAgICAgfSkKCWl0eG5fYmVnaW4KCWludCBheGZlcgoJaXR4bl9maWVsZCBUeXBlRW51bQoKCS8vIGNvbnRyYWN0cy9zdGFraW5nUG9vbC5hbGdvLnRzOjI5MAoJLy8geGZlckFzc2V0OiBBc3NldElELmZyb21VaW50NjQodmFsaWRhdG9yQ29uZmlnLnJld2FyZFRva2VuSWQpCglmcmFtZV9kaWcgNCAvLyB2YWxpZGF0b3JDb25maWc6ICh1aW50NjQsYWRkcmVzcyxhZGRyZXNzLHVpbnQ2NCx1aW50OCxieXRlWzMyXSx1aW50NjQsdWludDY0LHVpbnQ2NCx1aW50MTYsdWludDMyLGFkZHJlc3MsdWludDY0LHVpbnQ2NCx1aW50OCx1aW50NjQsdWludDY0KQoJZXh0cmFjdCAxMjEgOAoJYnRvaQoJaXR4bl9maWVsZCBYZmVyQXNzZXQKCgkvLyBjb250cmFjdHMvc3Rha2luZ1Bvb2wuYWxnby50czoyOTEKCS8vIGFzc2V0UmVjZWl2ZXI6IHN0YWtlcgoJZnJhbWVfZGlnIDAgLy8gc3Rha2VyOiBhZGRyZXNzCglpdHhuX2ZpZWxkIEFzc2V0UmVjZWl2ZXIKCgkvLyBjb250cmFjdHMvc3Rha2luZ1Bvb2wuYWxnby50czoyOTIKCS8vIGFzc2V0QW1vdW50OiBjbXBTdGFrZXIucmV3YXJkVG9rZW5CYWxhbmNlCglmcmFtZV9kaWcgMiAvLyBjbXBTdGFrZXI6IChhZGRyZXNzLHVpbnQ2NCx1aW50NjQsdWludDY0LHVpbnQ2NCkKCWV4dHJhY3QgNDggOAoJYnRvaQoJaXR4bl9maWVsZCBBc3NldEFtb3VudAoKCS8vIEZlZSBmaWVsZCBub3Qgc2V0LCBkZWZhdWx0aW5nIHRvIDAKCWludCAwCglpdHhuX2ZpZWxkIEZlZQoKCS8vIFN1Ym1pdCBpbm5lciB0cmFuc2FjdGlvbgoJaXR4bl9zdWJtaXQKCgkvLyBjb250cmFjdHMvc3Rha2luZ1Bvb2wuYWxnby50czoyOTQKCS8vIGFtb3VudFJld2FyZFRva2VuUmVtb3ZlZCA9IGNtcFN0YWtlci5yZXdhcmRUb2tlbkJhbGFuY2UKCWZyYW1lX2RpZyAyIC8vIGNtcFN0YWtlcjogKGFkZHJlc3MsdWludDY0LHVpbnQ2NCx1aW50NjQsdWludDY0KQoJZXh0cmFjdCA0OCA4CglidG9pCglmcmFtZV9idXJ5IDMgLy8gYW1vdW50UmV3YXJkVG9rZW5SZW1vdmVkOiB1aW50NjQKCgkvLyBjb250cmFjdHMvc3Rha2luZ1Bvb2wuYWxnby50czoyOTUKCS8vIGNtcFN0YWtlci5yZXdhcmRUb2tlbkJhbGFuY2UgPSAwCglmcmFtZV9kaWcgMiAvLyBjbXBTdGFrZXI6IChhZGRyZXNzLHVpbnQ2NCx1aW50NjQsdWludDY0LHVpbnQ2NCkKCWJ5dGUgMHgwMDAwMDAwMDAwMDAwMDAwCglyZXBsYWNlMiA0OAoJZnJhbWVfYnVyeSAyIC8vIGNtcFN0YWtlcjogKGFkZHJlc3MsdWludDY0LHVpbnQ2NCx1aW50NjQsdWludDY0KQoJYiAqaWYxMV9lbmQKCippZjExX2Vsc2U6CgkvLyBjb250cmFjdHMvc3Rha2luZ1Bvb2wuYWxnby50czozMDAKCS8vIGFtb3VudFJld2FyZFRva2VuUmVtb3ZlZCA9IGNtcFN0YWtlci5yZXdhcmRUb2tlbkJhbGFuY2UKCWZyYW1lX2RpZyAyIC8vIGNtcFN0YWtlcjogKGFkZHJlc3MsdWludDY0LHVpbnQ2NCx1aW50NjQsdWludDY0KQoJZXh0cmFjdCA0OCA4CglidG9pCglmcmFtZV9idXJ5IDMgLy8gYW1vdW50UmV3YXJkVG9rZW5SZW1vdmVkOiB1aW50NjQKCgkvLyBjb250cmFjdHMvc3Rha2luZ1Bvb2wuYWxnby50czozMDEKCS8vIGNtcFN0YWtlci5yZXdhcmRUb2tlbkJhbGFuY2UgPSAwCglmcmFtZV9kaWcgMiAvLyBjbXBTdGFrZXI6IChhZGRyZXNzLHVpbnQ2NCx1aW50NjQsdWludDY0LHVpbnQ2NCkKCWJ5dGUgMHgwMDAwMDAwMDAwMDAwMDAwCglyZXBsYWNlMiA0OAoJZnJhbWVfYnVyeSAyIC8vIGNtcFN0YWtlcjogKGFkZHJlc3MsdWludDY0LHVpbnQ2NCx1aW50NjQsdWludDY0KQoKKmlmMTFfZW5kOgoKKmlmMTBfZW5kOgoJLy8gY29udHJhY3RzL3N0YWtpbmdQb29sLmFsZ28udHM6MzA2CgkvLyBhc3NlcnQoCgkvLyAgICAgICAgICAgICAgICAgICAgIGNtcFN0YWtlci5iYWxhbmNlID09PSAwIHx8IGNtcFN0YWtlci5iYWxhbmNlID49IHRoaXMubWluRW50cnlTdGFrZS52YWx1ZSwKCS8vICAgICAgICAgICAgICAgICAgICAgJ2Nhbm5vdCByZWR1Y2UgYmFsYW5jZSBiZWxvdyBtaW5pbXVtIGFsbG93ZWQgc3Rha2UgdW5sZXNzIGFsbCBpcyByZW1vdmVkJwoJLy8gICAgICAgICAgICAgICAgICkKCWZyYW1lX2RpZyAyIC8vIGNtcFN0YWtlcjogKGFkZHJlc3MsdWludDY0LHVpbnQ2NCx1aW50NjQsdWludDY0KQoJZXh0cmFjdCAzMiA4CglidG9pCglpbnQgMAoJPT0KCWR1cAoJYm56ICpza2lwX29yMAoJZnJhbWVfZGlnIDIgLy8gY21wU3Rha2VyOiAoYWRkcmVzcyx1aW50NjQsdWludDY0LHVpbnQ2NCx1aW50NjQpCglleHRyYWN0IDMyIDgKCWJ0b2kKCWJ5dGUgMHg2ZDY5NmU0NTZlNzQ3Mjc5NTM3NDYxNmI2NSAvLyAibWluRW50cnlTdGFrZSIKCWFwcF9nbG9iYWxfZ2V0Cgk+PQoJfHwKCipza2lwX29yMDoKCS8vIGNhbm5vdCByZWR1Y2UgYmFsYW5jZSBiZWxvdyBtaW5pbXVtIGFsbG93ZWQgc3Rha2UgdW5sZXNzIGFsbCBpcyByZW1vdmVkCglhc3NlcnQKCgkvLyBjb250cmFjdHMvc3Rha2luZ1Bvb2wuYWxnby50czozMTQKCS8vIHNlbmRQYXltZW50KHsKCS8vICAgICAgICAgICAgICAgICAgICAgYW1vdW50OiBhbW91bnRUb1Vuc3Rha2UsCgkvLyAgICAgICAgICAgICAgICAgICAgIHJlY2VpdmVyOiBzdGFrZXIsCgkvLyAgICAgICAgICAgICAgICAgICAgIG5vdGU6ICd1bnN0YWtlZCcsCgkvLyAgICAgICAgICAgICAgICAgfSkKCWl0eG5fYmVnaW4KCWludCBwYXkKCWl0eG5fZmllbGQgVHlwZUVudW0KCgkvLyBjb250cmFjdHMvc3Rha2luZ1Bvb2wuYWxnby50czozMTUKCS8vIGFtb3VudDogYW1vdW50VG9VbnN0YWtlCglmcmFtZV9kaWcgLTEgLy8gYW1vdW50VG9VbnN0YWtlOiB1aW50NjQKCWl0eG5fZmllbGQgQW1vdW50CgoJLy8gY29udHJhY3RzL3N0YWtpbmdQb29sLmFsZ28udHM6MzE2CgkvLyByZWNlaXZlcjogc3Rha2VyCglmcmFtZV9kaWcgMCAvLyBzdGFrZXI6IGFkZHJlc3MKCWl0eG5fZmllbGQgUmVjZWl2ZXIKCgkvLyBjb250cmFjdHMvc3Rha2luZ1Bvb2wuYWxnby50czozMTcKCS8vIG5vdGU6ICd1bnN0YWtlZCcKCWJ5dGUgMHg3NTZlNzM3NDYxNmI2NTY0IC8vICJ1bnN0YWtlZCIKCWl0eG5fZmllbGQgTm90ZQoKCS8vIEZlZSBmaWVsZCBub3Qgc2V0LCBkZWZhdWx0aW5nIHRvIDAKCWludCAwCglpdHhuX2ZpZWxkIEZlZQoKCS8vIFN1Ym1pdCBpbm5lciB0cmFuc2FjdGlvbgoJaXR4bl9zdWJtaXQKCgkvLyBjb250cmFjdHMvc3Rha2luZ1Bvb2wuYWxnby50czozMTkKCS8vIHN0YWtlclJlbW92ZWQgPSBmYWxzZQoJaW50IDAKCWZyYW1lX2J1cnkgNSAvLyBzdGFrZXJSZW1vdmVkOiBib29sCgoJLy8gKmlmMTJfY29uZGl0aW9uCgkvLyBjb250cmFjdHMvc3Rha2luZ1Bvb2wuYWxnby50czozMjAKCS8vIGNtcFN0YWtlci5iYWxhbmNlID09PSAwCglmcmFtZV9kaWcgMiAvLyBjbXBTdGFrZXI6IChhZGRyZXNzLHVpbnQ2NCx1aW50NjQsdWludDY0LHVpbnQ2NCkKCWV4dHJhY3QgMzIgOAoJYnRvaQoJaW50IDAKCT09CglieiAqaWYxMl9lbmQKCgkvLyAqaWYxMl9jb25zZXF1ZW50CgkvLyBjb250cmFjdHMvc3Rha2luZ1Bvb2wuYWxnby50czozMjIKCS8vIHRoaXMubnVtU3Rha2Vycy52YWx1ZSAtPSAxCglieXRlIDB4NmU3NTZkNTM3NDYxNmI2NTcyNzMgLy8gIm51bVN0YWtlcnMiCglhcHBfZ2xvYmFsX2dldAoJaW50IDEKCS0KCWJ5dGUgMHg2ZTc1NmQ1Mzc0NjE2YjY1NzI3MyAvLyAibnVtU3Rha2VycyIKCXN3YXAKCWFwcF9nbG9iYWxfcHV0CgoJLy8gY29udHJhY3RzL3N0YWtpbmdQb29sLmFsZ28udHM6MzIzCgkvLyBjbXBTdGFrZXIuYWNjb3VudCA9IGdsb2JhbHMuemVyb0FkZHJlc3MKCWZyYW1lX2RpZyAyIC8vIGNtcFN0YWtlcjogKGFkZHJlc3MsdWludDY0LHVpbnQ2NCx1aW50NjQsdWludDY0KQoJaW50IDAKCWdsb2JhbCBaZXJvQWRkcmVzcwoJcmVwbGFjZTMKCWZyYW1lX2J1cnkgMiAvLyBjbXBTdGFrZXI6IChhZGRyZXNzLHVpbnQ2NCx1aW50NjQsdWludDY0LHVpbnQ2NCkKCgkvLyBjb250cmFjdHMvc3Rha2luZ1Bvb2wuYWxnby50czozMjQKCS8vIGNtcFN0YWtlci50b3RhbFJld2FyZGVkID0gMAoJZnJhbWVfZGlnIDIgLy8gY21wU3Rha2VyOiAoYWRkcmVzcyx1aW50NjQsdWludDY0LHVpbnQ2NCx1aW50NjQpCglieXRlIDB4MDAwMDAwMDAwMDAwMDAwMAoJcmVwbGFjZTIgNDAKCWZyYW1lX2J1cnkgMiAvLyBjbXBTdGFrZXI6IChhZGRyZXNzLHVpbnQ2NCx1aW50NjQsdWludDY0LHVpbnQ2NCkKCgkvLyBjb250cmFjdHMvc3Rha2luZ1Bvb2wuYWxnby50czozMjUKCS8vIGNtcFN0YWtlci5yZXdhcmRUb2tlbkJhbGFuY2UgPSAwCglmcmFtZV9kaWcgMiAvLyBjbXBTdGFrZXI6IChhZGRyZXNzLHVpbnQ2NCx1aW50NjQsdWludDY0LHVpbnQ2NCkKCWJ5dGUgMHgwMDAwMDAwMDAwMDAwMDAwCglyZXBsYWNlMiA0OAoJZnJhbWVfYnVyeSAyIC8vIGNtcFN0YWtlcjogKGFkZHJlc3MsdWludDY0LHVpbnQ2NCx1aW50NjQsdWludDY0KQoKCS8vIGNvbnRyYWN0cy9zdGFraW5nUG9vbC5hbGdvLnRzOjMyNgoJLy8gc3Rha2VyUmVtb3ZlZCA9IHRydWUKCWludCAxCglmcmFtZV9idXJ5IDUgLy8gc3Rha2VyUmVtb3ZlZDogYm9vbAoKKmlmMTJfZW5kOgoJLy8gY29udHJhY3RzL3N0YWtpbmdQb29sLmFsZ28udHM6MzI5CgkvLyB0aGlzLnN0YWtlcnMudmFsdWVbaV0gPSBjbXBTdGFrZXIKCWZyYW1lX2RpZyAxIC8vIGk6IHVpbnQ2NAoJaW50IDY0CgkqIC8vIGFjYyAqIHR5cGVMZW5ndGgKCWZyYW1lX2RpZyAyIC8vIGNtcFN0YWtlcjogKGFkZHJlc3MsdWludDY0LHVpbnQ2NCx1aW50NjQsdWludDY0KQoJYnl0ZSAweDczNzQ2MTZiNjU3MjczIC8vICJzdGFrZXJzIgoJY292ZXIgMgoJYm94X3JlcGxhY2UKCgkvLyBjb250cmFjdHMvc3Rha2luZ1Bvb2wuYWxnby50czozMzQKCS8vIHNlbmRNZXRob2RDYWxsPHR5cGVvZiBWYWxpZGF0b3JSZWdpc3RyeS5wcm90b3R5cGUuc3Rha2VSZW1vdmVkPih7CgkvLyAgICAgICAgICAgICAgICAgICAgIGFwcGxpY2F0aW9uSUQ6IEFwcElELmZyb21VaW50NjQodGhpcy5jcmVhdGluZ1ZhbGlkYXRvckNvbnRyYWN0QXBwSWQudmFsdWUpLAoJLy8gICAgICAgICAgICAgICAgICAgICBtZXRob2RBcmdzOiBbCgkvLyAgICAgICAgICAgICAgICAgICAgICAgICB7IGlkOiB0aGlzLnZhbGlkYXRvcklkLnZhbHVlLCBwb29sSWQ6IHRoaXMucG9vbElkLnZhbHVlLCBwb29sQXBwSWQ6IHRoaXMuYXBwLmlkIH0sCgkvLyAgICAgICAgICAgICAgICAgICAgICAgICBzdGFrZXIsCgkvLyAgICAgICAgICAgICAgICAgICAgICAgICBhbW91bnRUb1Vuc3Rha2UsCgkvLyAgICAgICAgICAgICAgICAgICAgICAgICBhbW91bnRSZXdhcmRUb2tlblJlbW92ZWQsCgkvLyAgICAgICAgICAgICAgICAgICAgICAgICBzdGFrZXJSZW1vdmVkLAoJLy8gICAgICAgICAgICAgICAgICAgICBdLAoJLy8gICAgICAgICAgICAgICAgIH0pCglpdHhuX2JlZ2luCglpbnQgYXBwbAoJaXR4bl9maWVsZCBUeXBlRW51bQoJbWV0aG9kICJzdGFrZVJlbW92ZWQoKHVpbnQ2NCx1aW50NjQsdWludDY0KSxhZGRyZXNzLHVpbnQ2NCx1aW50NjQsYm9vbCl2b2lkIgoJaXR4bl9maWVsZCBBcHBsaWNhdGlvbkFyZ3MKCgkvLyBjb250cmFjdHMvc3Rha2luZ1Bvb2wuYWxnby50czozMzUKCS8vIGFwcGxpY2F0aW9uSUQ6IEFwcElELmZyb21VaW50NjQodGhpcy5jcmVhdGluZ1ZhbGlkYXRvckNvbnRyYWN0QXBwSWQudmFsdWUpCglieXRlIDB4NjM3MjY1NjE3NDZmNzI0MTcwNzAgLy8gImNyZWF0b3JBcHAiCglhcHBfZ2xvYmFsX2dldAoJaXR4bl9maWVsZCBBcHBsaWNhdGlvbklECgoJLy8gY29udHJhY3RzL3N0YWtpbmdQb29sLmFsZ28udHM6MzM2CgkvLyBtZXRob2RBcmdzOiBbCgkvLyAgICAgICAgICAgICAgICAgICAgICAgICB7IGlkOiB0aGlzLnZhbGlkYXRvcklkLnZhbHVlLCBwb29sSWQ6IHRoaXMucG9vbElkLnZhbHVlLCBwb29sQXBwSWQ6IHRoaXMuYXBwLmlkIH0sCgkvLyAgICAgICAgICAgICAgICAgICAgICAgICBzdGFrZXIsCgkvLyAgICAgICAgICAgICAgICAgICAgICAgICBhbW91bnRUb1Vuc3Rha2UsCgkvLyAgICAgICAgICAgICAgICAgICAgICAgICBhbW91bnRSZXdhcmRUb2tlblJlbW92ZWQsCgkvLyAgICAgICAgICAgICAgICAgICAgICAgICBzdGFrZXJSZW1vdmVkLAoJLy8gICAgICAgICAgICAgICAgICAgICBdCglieXRlIDB4NzY2MTZjNjk2NDYxNzQ2ZjcyNDk2NCAvLyAidmFsaWRhdG9ySWQiCglhcHBfZ2xvYmFsX2dldAoJaXRvYgoJYnl0ZSAweDcwNmY2ZjZjNDk2NCAvLyAicG9vbElkIgoJYXBwX2dsb2JhbF9nZXQKCWl0b2IKCWNvbmNhdAoJdHhuYSBBcHBsaWNhdGlvbnMgMAoJaXRvYgoJY29uY2F0CglpdHhuX2ZpZWxkIEFwcGxpY2F0aW9uQXJncwoJZnJhbWVfZGlnIDAgLy8gc3Rha2VyOiBhZGRyZXNzCglpdHhuX2ZpZWxkIEFwcGxpY2F0aW9uQXJncwoJZnJhbWVfZGlnIC0xIC8vIGFtb3VudFRvVW5zdGFrZTogdWludDY0CglpdG9iCglpdHhuX2ZpZWxkIEFwcGxpY2F0aW9uQXJncwoJZnJhbWVfZGlnIDMgLy8gYW1vdW50UmV3YXJkVG9rZW5SZW1vdmVkOiB1aW50NjQKCWl0b2IKCWl0eG5fZmllbGQgQXBwbGljYXRpb25BcmdzCglmcmFtZV9kaWcgNSAvLyBzdGFrZXJSZW1vdmVkOiBib29sCglieXRlIDB4MDAKCWludCAwCgl1bmNvdmVyIDIKCXNldGJpdAoJaXR4bl9maWVsZCBBcHBsaWNhdGlvbkFyZ3MKCgkvLyBGZWUgZmllbGQgbm90IHNldCwgZGVmYXVsdGluZyB0byAwCglpbnQgMAoJaXR4bl9maWVsZCBGZWUKCgkvLyBTdWJtaXQgaW5uZXIgdHJhbnNhY3Rpb24KCWl0eG5fc3VibWl0CgoJLy8gY29udHJhY3RzL3N0YWtpbmdQb29sLmFsZ28udHM6MzQ0CgkvLyByZXR1cm47CglyZXRzdWIKCippZjdfZW5kOgoKKmZvcl8xX2NvbnRpbnVlOgoJLy8gY29udHJhY3RzL3N0YWtpbmdQb29sLmFsZ28udHM6MjYxCgkvLyBpICs9IDEKCWZyYW1lX2RpZyAxIC8vIGk6IHVpbnQ2NAoJaW50IDEKCSsKCWZyYW1lX2J1cnkgMSAvLyBpOiB1aW50NjQKCWIgKmZvcl8xCgoqZm9yXzFfZW5kOgoJZXJyIC8vICdhY2NvdW50IG5vdCBmb3VuZCcKCi8vIGNsYWltVG9rZW5zKCl2b2lkCiphYmlfcm91dGVfY2xhaW1Ub2tlbnM6CgkvLyBleGVjdXRlIGNsYWltVG9rZW5zKCl2b2lkCgljYWxsc3ViIGNsYWltVG9rZW5zCglpbnQgMQoJcmV0dXJuCgovLyBjbGFpbVRva2VucygpOiB2b2lkCi8vCi8vIENsYWltcyBhbGwgdGhlIGF2YWlsYWJsZSByZXdhcmQgdG9rZW5zIGEgc3Rha2VyIGhhcyBhdmFpbGFibGUsIHNlbmRpbmcgdGhlaXIgZW50aXJlIGJhbGFuY2UgdG8gdGhlIHN0YWtlciBmcm9tCi8vIHBvb2wgMSAoZWl0aGVyIGRpcmVjdGx5LCBvciB2aWEgdmFsaWRhdG9yLT5wb29sMSB0byBwYXkgaXQgb3V0KQovLyBBbHNvIG5vdGlmaWVzIHRoZSB2YWxpZGF0b3IgY29udHJhY3QgZm9yIHRoaXMgcG9vbHMgdmFsaWRhdG9yIG9mIHRoZSBzdGFrZXIgLyBiYWxhbmNlIGNoYW5nZXMuCmNsYWltVG9rZW5zOgoJcHJvdG8gMCAwCgoJLy8gUHVzaCBlbXB0eSBieXRlcyBhZnRlciB0aGUgZnJhbWUgcG9pbnRlciB0byByZXNlcnZlIHNwYWNlIGZvciBsb2NhbCB2YXJpYWJsZXMKCWJ5dGUgMHgKCWR1cG4gNAoKCS8vIGNvbnRyYWN0cy9zdGFraW5nUG9vbC5hbGdvLnRzOjM1OQoJLy8gc3Rha2VyID0gdGhpcy50eG4uc2VuZGVyCgl0eG4gU2VuZGVyCglmcmFtZV9idXJ5IDAgLy8gc3Rha2VyOiBhZGRyZXNzCgoJLy8gY29udHJhY3RzL3N0YWtpbmdQb29sLmFsZ28udHM6MzYxCgkvLyBmb3IgKGxldCBpID0gMDsgaSA8IHRoaXMuc3Rha2Vycy52YWx1ZS5sZW5ndGg7IGkgKz0gMSkKCWludCAwCglmcmFtZV9idXJ5IDEgLy8gaTogdWludDY0CgoqZm9yXzI6CgkvLyBjb250cmFjdHMvc3Rha2luZ1Bvb2wuYWxnby50czozNjEKCS8vIGkgPCB0aGlzLnN0YWtlcnMudmFsdWUubGVuZ3RoCglmcmFtZV9kaWcgMSAvLyBpOiB1aW50NjQKCWludCAyMDAKCTwKCWJ6ICpmb3JfMl9lbmQKCgkvLyAqaWYxM19jb25kaXRpb24KCS8vIGNvbnRyYWN0cy9zdGFraW5nUG9vbC5hbGdvLnRzOjM2MgoJLy8gZ2xvYmFscy5vcGNvZGVCdWRnZXQgPCAzMDAKCWdsb2JhbCBPcGNvZGVCdWRnZXQKCWludCAzMDAKCTwKCWJ6ICppZjEzX2VuZAoKCS8vICppZjEzX2NvbnNlcXVlbnQKCS8vIGNvbnRyYWN0cy9zdGFraW5nUG9vbC5hbGdvLnRzOjM2MwoJLy8gaW5jcmVhc2VPcGNvZGVCdWRnZXQoKQoJaXR4bl9iZWdpbgoJaW50IGFwcGwKCWl0eG5fZmllbGQgVHlwZUVudW0KCWludCAwCglpdHhuX2ZpZWxkIEZlZQoJYnl0ZSBiNjQgQ29FQiAvLyAjcHJhZ21hIHZlcnNpb24gMTA7IGludCAxCglkdXAKCWl0eG5fZmllbGQgQXBwcm92YWxQcm9ncmFtCglpdHhuX2ZpZWxkIENsZWFyU3RhdGVQcm9ncmFtCglpbnQgRGVsZXRlQXBwbGljYXRpb24KCWl0eG5fZmllbGQgT25Db21wbGV0aW9uCglpdHhuX3N1Ym1pdAoKKmlmMTNfZW5kOgoJLy8gY29udHJhY3RzL3N0YWtpbmdQb29sLmFsZ28udHM6MzY1CgkvLyBjbXBTdGFrZXIgPSBjbG9uZSh0aGlzLnN0YWtlcnMudmFsdWVbaV0pCglmcmFtZV9kaWcgMSAvLyBpOiB1aW50NjQKCWludCA2NAoJKiAvLyBhY2MgKiB0eXBlTGVuZ3RoCglpbnQgNjQKCWJ5dGUgMHg3Mzc0NjE2YjY1NzI3MyAvLyAic3Rha2VycyIKCWNvdmVyIDIKCWJveF9leHRyYWN0CglmcmFtZV9idXJ5IDIgLy8gY21wU3Rha2VyOiAoYWRkcmVzcyx1aW50NjQsdWludDY0LHVpbnQ2NCx1aW50NjQpCgoJLy8gKmlmMTRfY29uZGl0aW9uCgkvLyBjb250cmFjdHMvc3Rha2luZ1Bvb2wuYWxnby50czozNjYKCS8vIGNtcFN0YWtlci5hY2NvdW50ID09PSBzdGFrZXIKCWZyYW1lX2RpZyAyIC8vIGNtcFN0YWtlcjogKGFkZHJlc3MsdWludDY0LHVpbnQ2NCx1aW50NjQsdWludDY0KQoJZXh0cmFjdCAwIDMyCglmcmFtZV9kaWcgMCAvLyBzdGFrZXI6IGFkZHJlc3MKCT09CglieiAqaWYxNF9lbmQKCgkvLyAqaWYxNF9jb25zZXF1ZW50CgkvLyAqaWYxNV9jb25kaXRpb24KCS8vIGNvbnRyYWN0cy9zdGFraW5nUG9vbC5hbGdvLnRzOjM2NwoJLy8gY21wU3Rha2VyLnJld2FyZFRva2VuQmFsYW5jZSA9PT0gMAoJZnJhbWVfZGlnIDIgLy8gY21wU3Rha2VyOiAoYWRkcmVzcyx1aW50NjQsdWludDY0LHVpbnQ2NCx1aW50NjQpCglleHRyYWN0IDQ4IDgKCWJ0b2kKCWludCAwCgk9PQoJYnogKmlmMTVfZW5kCgoJLy8gKmlmMTVfY29uc2VxdWVudAoJLy8gY29udHJhY3RzL3N0YWtpbmdQb29sLmFsZ28udHM6MzY4CgkvLyByZXR1cm47CglyZXRzdWIKCippZjE1X2VuZDoKCS8vIGNvbnRyYWN0cy9zdGFraW5nUG9vbC5hbGdvLnRzOjM3MAoJLy8gYW1vdW50UmV3YXJkVG9rZW5SZW1vdmVkID0gMAoJaW50IDAKCWZyYW1lX2J1cnkgMyAvLyBhbW91bnRSZXdhcmRUb2tlblJlbW92ZWQ6IHVpbnQ2NAoKCS8vICppZjE2X2NvbmRpdGlvbgoJLy8gY29udHJhY3RzL3N0YWtpbmdQb29sLmFsZ28udHM6MzcyCgkvLyB0aGlzLnBvb2xJZC52YWx1ZSA9PT0gMQoJYnl0ZSAweDcwNmY2ZjZjNDk2NCAvLyAicG9vbElkIgoJYXBwX2dsb2JhbF9nZXQKCWludCAxCgk9PQoJYnogKmlmMTZfZWxzZQoKCS8vICppZjE2X2NvbnNlcXVlbnQKCS8vIGNvbnRyYWN0cy9zdGFraW5nUG9vbC5hbGdvLnRzOjM3MwoJLy8gdmFsaWRhdG9yQ29uZmlnID0gc2VuZE1ldGhvZENhbGw8dHlwZW9mIFZhbGlkYXRvclJlZ2lzdHJ5LnByb3RvdHlwZS5nZXRWYWxpZGF0b3JDb25maWc+KHsKCS8vICAgICAgICAgICAgICAgICAgICAgICAgIGFwcGxpY2F0aW9uSUQ6IEFwcElELmZyb21VaW50NjQodGhpcy5jcmVhdGluZ1ZhbGlkYXRvckNvbnRyYWN0QXBwSWQudmFsdWUpLAoJLy8gICAgICAgICAgICAgICAgICAgICAgICAgbWV0aG9kQXJnczogW3RoaXMudmFsaWRhdG9ySWQudmFsdWVdLAoJLy8gICAgICAgICAgICAgICAgICAgICB9KQoJaXR4bl9iZWdpbgoJaW50IGFwcGwKCWl0eG5fZmllbGQgVHlwZUVudW0KCW1ldGhvZCAiZ2V0VmFsaWRhdG9yQ29uZmlnKHVpbnQ2NCkodWludDY0LGFkZHJlc3MsYWRkcmVzcyx1aW50NjQsdWludDgsYnl0ZVszMl0sdWludDY0LHVpbnQ2NCx1aW50NjQsdWludDE2LHVpbnQzMixhZGRyZXNzLHVpbnQ2NCx1aW50NjQsdWludDgsdWludDY0LHVpbnQ2NCkiCglpdHhuX2ZpZWxkIEFwcGxpY2F0aW9uQXJncwoKCS8vIGNvbnRyYWN0cy9zdGFraW5nUG9vbC5hbGdvLnRzOjM3NAoJLy8gYXBwbGljYXRpb25JRDogQXBwSUQuZnJvbVVpbnQ2NCh0aGlzLmNyZWF0aW5nVmFsaWRhdG9yQ29udHJhY3RBcHBJZC52YWx1ZSkKCWJ5dGUgMHg2MzcyNjU2MTc0NmY3MjQxNzA3MCAvLyAiY3JlYXRvckFwcCIKCWFwcF9nbG9iYWxfZ2V0CglpdHhuX2ZpZWxkIEFwcGxpY2F0aW9uSUQKCgkvLyBjb250cmFjdHMvc3Rha2luZ1Bvb2wuYWxnby50czozNzUKCS8vIG1ldGhvZEFyZ3M6IFt0aGlzLnZhbGlkYXRvcklkLnZhbHVlXQoJYnl0ZSAweDc2NjE2YzY5NjQ2MTc0NmY3MjQ5NjQgLy8gInZhbGlkYXRvcklkIgoJYXBwX2dsb2JhbF9nZXQKCWl0b2IKCWl0eG5fZmllbGQgQXBwbGljYXRpb25BcmdzCgoJLy8gRmVlIGZpZWxkIG5vdCBzZXQsIGRlZmF1bHRpbmcgdG8gMAoJaW50IDAKCWl0eG5fZmllbGQgRmVlCgoJLy8gU3VibWl0IGlubmVyIHRyYW5zYWN0aW9uCglpdHhuX3N1Ym1pdAoJaXR4biBOdW1Mb2dzCglpbnQgMQoJLQoJaXR4bmFzIExvZ3MKCWV4dHJhY3QgNCAwCglmcmFtZV9idXJ5IDQgLy8gdmFsaWRhdG9yQ29uZmlnOiAodWludDY0LGFkZHJlc3MsYWRkcmVzcyx1aW50NjQsdWludDgsYnl0ZVszMl0sdWludDY0LHVpbnQ2NCx1aW50NjQsdWludDE2LHVpbnQzMixhZGRyZXNzLHVpbnQ2NCx1aW50NjQsdWludDgsdWludDY0LHVpbnQ2NCkKCgkvLyBjb250cmFjdHMvc3Rha2luZ1Bvb2wuYWxnby50czozODAKCS8vIHNlbmRBc3NldFRyYW5zZmVyKHsKCS8vICAgICAgICAgICAgICAgICAgICAgICAgIHhmZXJBc3NldDogQXNzZXRJRC5mcm9tVWludDY0KHZhbGlkYXRvckNvbmZpZy5yZXdhcmRUb2tlbklkKSwKCS8vICAgICAgICAgICAgICAgICAgICAgICAgIGFzc2V0UmVjZWl2ZXI6IHN0YWtlciwKCS8vICAgICAgICAgICAgICAgICAgICAgICAgIGFzc2V0QW1vdW50OiBjbXBTdGFrZXIucmV3YXJkVG9rZW5CYWxhbmNlLAoJLy8gICAgICAgICAgICAgICAgICAgICB9KQoJaXR4bl9iZWdpbgoJaW50IGF4ZmVyCglpdHhuX2ZpZWxkIFR5cGVFbnVtCgoJLy8gY29udHJhY3RzL3N0YWtpbmdQb29sLmFsZ28udHM6MzgxCgkvLyB4ZmVyQXNzZXQ6IEFzc2V0SUQuZnJvbVVpbnQ2NCh2YWxpZGF0b3JDb25maWcucmV3YXJkVG9rZW5JZCkKCWZyYW1lX2RpZyA0IC8vIHZhbGlkYXRvckNvbmZpZzogKHVpbnQ2NCxhZGRyZXNzLGFkZHJlc3MsdWludDY0LHVpbnQ4LGJ5dGVbMzJdLHVpbnQ2NCx1aW50NjQsdWludDY0LHVpbnQxNix1aW50MzIsYWRkcmVzcyx1aW50NjQsdWludDY0LHVpbnQ4LHVpbnQ2NCx1aW50NjQpCglleHRyYWN0IDEyMSA4CglidG9pCglpdHhuX2ZpZWxkIFhmZXJBc3NldAoKCS8vIGNvbnRyYWN0cy9zdGFraW5nUG9vbC5hbGdvLnRzOjM4MgoJLy8gYXNzZXRSZWNlaXZlcjogc3Rha2VyCglmcmFtZV9kaWcgMCAvLyBzdGFrZXI6IGFkZHJlc3MKCWl0eG5fZmllbGQgQXNzZXRSZWNlaXZlcgoKCS8vIGNvbnRyYWN0cy9zdGFraW5nUG9vbC5hbGdvLnRzOjM4MwoJLy8gYXNzZXRBbW91bnQ6IGNtcFN0YWtlci5yZXdhcmRUb2tlbkJhbGFuY2UKCWZyYW1lX2RpZyAyIC8vIGNtcFN0YWtlcjogKGFkZHJlc3MsdWludDY0LHVpbnQ2NCx1aW50NjQsdWludDY0KQoJZXh0cmFjdCA0OCA4CglidG9pCglpdHhuX2ZpZWxkIEFzc2V0QW1vdW50CgoJLy8gRmVlIGZpZWxkIG5vdCBzZXQsIGRlZmF1bHRpbmcgdG8gMAoJaW50IDAKCWl0eG5fZmllbGQgRmVlCgoJLy8gU3VibWl0IGlubmVyIHRyYW5zYWN0aW9uCglpdHhuX3N1Ym1pdAoKCS8vIGNvbnRyYWN0cy9zdGFraW5nUG9vbC5hbGdvLnRzOjM4NQoJLy8gYW1vdW50UmV3YXJkVG9rZW5SZW1vdmVkID0gY21wU3Rha2VyLnJld2FyZFRva2VuQmFsYW5jZQoJZnJhbWVfZGlnIDIgLy8gY21wU3Rha2VyOiAoYWRkcmVzcyx1aW50NjQsdWludDY0LHVpbnQ2NCx1aW50NjQpCglleHRyYWN0IDQ4IDgKCWJ0b2kKCWZyYW1lX2J1cnkgMyAvLyBhbW91bnRSZXdhcmRUb2tlblJlbW92ZWQ6IHVpbnQ2NAoKCS8vIGNvbnRyYWN0cy9zdGFraW5nUG9vbC5hbGdvLnRzOjM4NgoJLy8gY21wU3Rha2VyLnJld2FyZFRva2VuQmFsYW5jZSA9IDAKCWZyYW1lX2RpZyAyIC8vIGNtcFN0YWtlcjogKGFkZHJlc3MsdWludDY0LHVpbnQ2NCx1aW50NjQsdWludDY0KQoJYnl0ZSAweDAwMDAwMDAwMDAwMDAwMDAKCXJlcGxhY2UyIDQ4CglmcmFtZV9idXJ5IDIgLy8gY21wU3Rha2VyOiAoYWRkcmVzcyx1aW50NjQsdWludDY0LHVpbnQ2NCx1aW50NjQpCgliICppZjE2X2VuZAoKKmlmMTZfZWxzZToKCS8vIGNvbnRyYWN0cy9zdGFraW5nUG9vbC5hbGdvLnRzOjM5MQoJLy8gYW1vdW50UmV3YXJkVG9rZW5SZW1vdmVkID0gY21wU3Rha2VyLnJld2FyZFRva2VuQmFsYW5jZQoJZnJhbWVfZGlnIDIgLy8gY21wU3Rha2VyOiAoYWRkcmVzcyx1aW50NjQsdWludDY0LHVpbnQ2NCx1aW50NjQpCglleHRyYWN0IDQ4IDgKCWJ0b2kKCWZyYW1lX2J1cnkgMyAvLyBhbW91bnRSZXdhcmRUb2tlblJlbW92ZWQ6IHVpbnQ2NAoKCS8vIGNvbnRyYWN0cy9zdGFraW5nUG9vbC5hbGdvLnRzOjM5MgoJLy8gY21wU3Rha2VyLnJld2FyZFRva2VuQmFsYW5jZSA9IDAKCWZyYW1lX2RpZyAyIC8vIGNtcFN0YWtlcjogKGFkZHJlc3MsdWludDY0LHVpbnQ2NCx1aW50NjQsdWludDY0KQoJYnl0ZSAweDAwMDAwMDAwMDAwMDAwMDAKCXJlcGxhY2UyIDQ4CglmcmFtZV9idXJ5IDIgLy8gY21wU3Rha2VyOiAoYWRkcmVzcyx1aW50NjQsdWludDY0LHVpbnQ2NCx1aW50NjQpCgoqaWYxNl9lbmQ6CgkvLyBjb250cmFjdHMvc3Rha2luZ1Bvb2wuYWxnby50czozOTYKCS8vIHRoaXMuc3Rha2Vycy52YWx1ZVtpXSA9IGNtcFN0YWtlcgoJZnJhbWVfZGlnIDEgLy8gaTogdWludDY0CglpbnQgNjQKCSogLy8gYWNjICogdHlwZUxlbmd0aAoJZnJhbWVfZGlnIDIgLy8gY21wU3Rha2VyOiAoYWRkcmVzcyx1aW50NjQsdWludDY0LHVpbnQ2NCx1aW50NjQpCglieXRlIDB4NzM3NDYxNmI2NTcyNzMgLy8gInN0YWtlcnMiCgljb3ZlciAyCglib3hfcmVwbGFjZQoKCS8vIGNvbnRyYWN0cy9zdGFraW5nUG9vbC5hbGdvLnRzOjQwMQoJLy8gc2VuZE1ldGhvZENhbGw8dHlwZW9mIFZhbGlkYXRvclJlZ2lzdHJ5LnByb3RvdHlwZS5zdGFrZVJlbW92ZWQ+KHsKCS8vICAgICAgICAgICAgICAgICAgICAgYXBwbGljYXRpb25JRDogQXBwSUQuZnJvbVVpbnQ2NCh0aGlzLmNyZWF0aW5nVmFsaWRhdG9yQ29udHJhY3RBcHBJZC52YWx1ZSksCgkvLyAgICAgICAgICAgICAgICAgICAgIG1ldGhvZEFyZ3M6IFsKCS8vICAgICAgICAgICAgICAgICAgICAgICAgIHsgaWQ6IHRoaXMudmFsaWRhdG9ySWQudmFsdWUsIHBvb2xJZDogdGhpcy5wb29sSWQudmFsdWUsIHBvb2xBcHBJZDogdGhpcy5hcHAuaWQgfSwKCS8vICAgICAgICAgICAgICAgICAgICAgICAgIHN0YWtlciwKCS8vICAgICAgICAgICAgICAgICAgICAgICAgIDAsIC8vIG5vIGFsZ28gcmVtb3ZlZAoJLy8gICAgICAgICAgICAgICAgICAgICAgICAgYW1vdW50UmV3YXJkVG9rZW5SZW1vdmVkLAoJLy8gICAgICAgICAgICAgICAgICAgICAgICAgZmFsc2UsIC8vIHN0YWtlciBpc24ndCBiZWluZyByZW1vdmVkLgoJLy8gICAgICAgICAgICAgICAgICAgICBdLAoJLy8gICAgICAgICAgICAgICAgIH0pCglpdHhuX2JlZ2luCglpbnQgYXBwbAoJaXR4bl9maWVsZCBUeXBlRW51bQoJbWV0aG9kICJzdGFrZVJlbW92ZWQoKHVpbnQ2NCx1aW50NjQsdWludDY0KSxhZGRyZXNzLHVpbnQ2NCx1aW50NjQsYm9vbCl2b2lkIgoJaXR4bl9maWVsZCBBcHBsaWNhdGlvbkFyZ3MKCgkvLyBjb250cmFjdHMvc3Rha2luZ1Bvb2wuYWxnby50czo0MDIKCS8vIGFwcGxpY2F0aW9uSUQ6IEFwcElELmZyb21VaW50NjQodGhpcy5jcmVhdGluZ1ZhbGlkYXRvckNvbnRyYWN0QXBwSWQudmFsdWUpCglieXRlIDB4NjM3MjY1NjE3NDZmNzI0MTcwNzAgLy8gImNyZWF0b3JBcHAiCglhcHBfZ2xvYmFsX2dldAoJaXR4bl9maWVsZCBBcHBsaWNhdGlvbklECgoJLy8gY29udHJhY3RzL3N0YWtpbmdQb29sLmFsZ28udHM6NDAzCgkvLyBtZXRob2RBcmdzOiBbCgkvLyAgICAgICAgICAgICAgICAgICAgICAgICB7IGlkOiB0aGlzLnZhbGlkYXRvcklkLnZhbHVlLCBwb29sSWQ6IHRoaXMucG9vbElkLnZhbHVlLCBwb29sQXBwSWQ6IHRoaXMuYXBwLmlkIH0sCgkvLyAgICAgICAgICAgICAgICAgICAgICAgICBzdGFrZXIsCgkvLyAgICAgICAgICAgICAgICAgICAgICAgICAwLCAvLyBubyBhbGdvIHJlbW92ZWQKCS8vICAgICAgICAgICAgICAgICAgICAgICAgIGFtb3VudFJld2FyZFRva2VuUmVtb3ZlZCwKCS8vICAgICAgICAgICAgICAgICAgICAgICAgIGZhbHNlLCAvLyBzdGFrZXIgaXNuJ3QgYmVpbmcgcmVtb3ZlZC4KCS8vICAgICAgICAgICAgICAgICAgICAgXQoJYnl0ZSAweDc2NjE2YzY5NjQ2MTc0NmY3MjQ5NjQgLy8gInZhbGlkYXRvcklkIgoJYXBwX2dsb2JhbF9nZXQKCWl0b2IKCWJ5dGUgMHg3MDZmNmY2YzQ5NjQgLy8gInBvb2xJZCIKCWFwcF9nbG9iYWxfZ2V0CglpdG9iCgljb25jYXQKCXR4bmEgQXBwbGljYXRpb25zIDAKCWl0b2IKCWNvbmNhdAoJaXR4bl9maWVsZCBBcHBsaWNhdGlvbkFyZ3MKCWZyYW1lX2RpZyAwIC8vIHN0YWtlcjogYWRkcmVzcwoJaXR4bl9maWVsZCBBcHBsaWNhdGlvbkFyZ3MKCWJ5dGUgMHgwMDAwMDAwMDAwMDAwMDAwCglpdHhuX2ZpZWxkIEFwcGxpY2F0aW9uQXJncwoJZnJhbWVfZGlnIDMgLy8gYW1vdW50UmV3YXJkVG9rZW5SZW1vdmVkOiB1aW50NjQKCWl0b2IKCWl0eG5fZmllbGQgQXBwbGljYXRpb25BcmdzCglpbnQgMAoJYnl0ZSAweDAwCglpbnQgMAoJdW5jb3ZlciAyCglzZXRiaXQKCWl0eG5fZmllbGQgQXBwbGljYXRpb25BcmdzCgoJLy8gRmVlIGZpZWxkIG5vdCBzZXQsIGRlZmF1bHRpbmcgdG8gMAoJaW50IDAKCWl0eG5fZmllbGQgRmVlCgoJLy8gU3VibWl0IGlubmVyIHRyYW5zYWN0aW9uCglpdHhuX3N1Ym1pdAoKCS8vIGNvbnRyYWN0cy9zdGFraW5nUG9vbC5hbGdvLnRzOjQxMQoJLy8gcmV0dXJuOwoJcmV0c3ViCgoqaWYxNF9lbmQ6CgoqZm9yXzJfY29udGludWU6CgkvLyBjb250cmFjdHMvc3Rha2luZ1Bvb2wuYWxnby50czozNjEKCS8vIGkgKz0gMQoJZnJhbWVfZGlnIDEgLy8gaTogdWludDY0CglpbnQgMQoJKwoJZnJhbWVfYnVyeSAxIC8vIGk6IHVpbnQ2NAoJYiAqZm9yXzIKCipmb3JfMl9lbmQ6CgllcnIgLy8gJ2FjY291bnQgbm90IGZvdW5kJwoKLy8gZ2V0U3Rha2VySW5mbyhhZGRyZXNzKShhZGRyZXNzLHVpbnQ2NCx1aW50NjQsdWludDY0LHVpbnQ2NCkKKmFiaV9yb3V0ZV9nZXRTdGFrZXJJbmZvOgoJLy8gVGhlIEFCSSByZXR1cm4gcHJlZml4CglieXRlIDB4MTUxZjdjNzUKCgkvLyBzdGFrZXI6IGFkZHJlc3MKCXR4bmEgQXBwbGljYXRpb25BcmdzIDEKCWR1cAoJbGVuCglpbnQgMzIKCT09Cglhc3NlcnQKCgkvLyBleGVjdXRlIGdldFN0YWtlckluZm8oYWRkcmVzcykoYWRkcmVzcyx1aW50NjQsdWludDY0LHVpbnQ2NCx1aW50NjQpCgljYWxsc3ViIGdldFN0YWtlckluZm8KCWNvbmNhdAoJbG9nCglpbnQgMQoJcmV0dXJuCgovLyBnZXRTdGFrZXJJbmZvKHN0YWtlcjogQWRkcmVzcyk6IFN0YWtlZEluZm8KLy8KLy8gUmV0cmlldmVzIHRoZSBzdGFrZWQgaW5mb3JtYXRpb24gZm9yIGEgZ2l2ZW4gc3Rha2VyLgovLwovLyBAcGFyYW0ge0FkZHJlc3N9IHN0YWtlciAtIFRoZSBhZGRyZXNzIG9mIHRoZSBzdGFrZXIuCi8vIEByZXR1cm5zIHtTdGFrZWRJbmZvfSAtIFRoZSBzdGFrZWQgaW5mb3JtYXRpb24gZm9yIHRoZSBnaXZlbiBzdGFrZXIuCi8vIEB0aHJvd3Mge0Vycm9yfSAtIElmIHRoZSBzdGFrZXIncyBhY2NvdW50IGlzIG5vdCBmb3VuZC4KZ2V0U3Rha2VySW5mbzoKCXByb3RvIDEgMQoKCS8vIFB1c2ggZW1wdHkgYnl0ZXMgYWZ0ZXIgdGhlIGZyYW1lIHBvaW50ZXIgdG8gcmVzZXJ2ZSBzcGFjZSBmb3IgbG9jYWwgdmFyaWFibGVzCglieXRlIDB4CgoJLy8gY29udHJhY3RzL3N0YWtpbmdQb29sLmFsZ28udHM6NDI2CgkvLyBmb3IgKGxldCBpID0gMDsgaSA8IHRoaXMuc3Rha2Vycy52YWx1ZS5sZW5ndGg7IGkgKz0gMSkKCWludCAwCglmcmFtZV9idXJ5IDAgLy8gaTogdWludDY0CgoqZm9yXzM6CgkvLyBjb250cmFjdHMvc3Rha2luZ1Bvb2wuYWxnby50czo0MjYKCS8vIGkgPCB0aGlzLnN0YWtlcnMudmFsdWUubGVuZ3RoCglmcmFtZV9kaWcgMCAvLyBpOiB1aW50NjQKCWludCAyMDAKCTwKCWJ6ICpmb3JfM19lbmQKCgkvLyAqaWYxN19jb25kaXRpb24KCS8vIGNvbnRyYWN0cy9zdGFraW5nUG9vbC5hbGdvLnRzOjQyNwoJLy8gZ2xvYmFscy5vcGNvZGVCdWRnZXQgPCAyMDAKCWdsb2JhbCBPcGNvZGVCdWRnZXQKCWludCAyMDAKCTwKCWJ6ICppZjE3X2VuZAoKCS8vICppZjE3X2NvbnNlcXVlbnQKCS8vIGNvbnRyYWN0cy9zdGFraW5nUG9vbC5hbGdvLnRzOjQyOAoJLy8gaW5jcmVhc2VPcGNvZGVCdWRnZXQoKQoJaXR4bl9iZWdpbgoJaW50IGFwcGwKCWl0eG5fZmllbGQgVHlwZUVudW0KCWludCAwCglpdHhuX2ZpZWxkIEZlZQoJYnl0ZSBiNjQgQ29FQiAvLyAjcHJhZ21hIHZlcnNpb24gMTA7IGludCAxCglkdXAKCWl0eG5fZmllbGQgQXBwcm92YWxQcm9ncmFtCglpdHhuX2ZpZWxkIENsZWFyU3RhdGVQcm9ncmFtCglpbnQgRGVsZXRlQXBwbGljYXRpb24KCWl0eG5fZmllbGQgT25Db21wbGV0aW9uCglpdHhuX3N1Ym1pdAoKKmlmMTdfZW5kOgoJLy8gKmlmMThfY29uZGl0aW9uCgkvLyBjb250cmFjdHMvc3Rha2luZ1Bvb2wuYWxnby50czo0MzAKCS8vIHRoaXMuc3Rha2Vycy52YWx1ZVtpXS5hY2NvdW50ID09PSBzdGFrZXIKCWZyYW1lX2RpZyAwIC8vIGk6IHVpbnQ2NAoJaW50IDY0CgkqIC8vIGFjYyAqIHR5cGVMZW5ndGgKCWludCAwCgkrCglpbnQgMzIKCWJ5dGUgMHg3Mzc0NjE2YjY1NzI3MyAvLyAic3Rha2VycyIKCWNvdmVyIDIKCWJveF9leHRyYWN0CglmcmFtZV9kaWcgLTEgLy8gc3Rha2VyOiBBZGRyZXNzCgk9PQoJYnogKmlmMThfZW5kCgoJLy8gKmlmMThfY29uc2VxdWVudAoJLy8gY29udHJhY3RzL3N0YWtpbmdQb29sLmFsZ28udHM6NDMxCgkvLyByZXR1cm4gdGhpcy5zdGFrZXJzLnZhbHVlW2ldOwoJZnJhbWVfZGlnIDAgLy8gaTogdWludDY0CglpbnQgNjQKCSogLy8gYWNjICogdHlwZUxlbmd0aAoJaW50IDY0CglieXRlIDB4NzM3NDYxNmI2NTcyNzMgLy8gInN0YWtlcnMiCgljb3ZlciAyCglib3hfZXh0cmFjdAoKCS8vIHNldCB0aGUgc3Vicm91dGluZSByZXR1cm4gdmFsdWUKCWZyYW1lX2J1cnkgMAoJcmV0c3ViCgoqaWYxOF9lbmQ6CgoqZm9yXzNfY29udGludWU6CgkvLyBjb250cmFjdHMvc3Rha2luZ1Bvb2wuYWxnby50czo0MjYKCS8vIGkgKz0gMQoJZnJhbWVfZGlnIDAgLy8gaTogdWludDY0CglpbnQgMQoJKwoJZnJhbWVfYnVyeSAwIC8vIGk6IHVpbnQ2NAoJYiAqZm9yXzMKCipmb3JfM19lbmQ6CgllcnIgLy8gJ2FjY291bnQgbm90IGZvdW5kJwoKLy8gcGF5VG9rZW5SZXdhcmQoYWRkcmVzcyx1aW50NjQsdWludDY0KXZvaWQKKmFiaV9yb3V0ZV9wYXlUb2tlblJld2FyZDoKCS8vIGFtb3VudFRvU2VuZDogdWludDY0Cgl0eG5hIEFwcGxpY2F0aW9uQXJncyAzCglidG9pCgoJLy8gcmV3YXJkVG9rZW46IHVpbnQ2NAoJdHhuYSBBcHBsaWNhdGlvbkFyZ3MgMgoJYnRvaQoKCS8vIHN0YWtlcjogYWRkcmVzcwoJdHhuYSBBcHBsaWNhdGlvbkFyZ3MgMQoJZHVwCglsZW4KCWludCAzMgoJPT0KCWFzc2VydAoKCS8vIGV4ZWN1dGUgcGF5VG9rZW5SZXdhcmQoYWRkcmVzcyx1aW50NjQsdWludDY0KXZvaWQKCWNhbGxzdWIgcGF5VG9rZW5SZXdhcmQKCWludCAxCglyZXR1cm4KCi8vIHBheVRva2VuUmV3YXJkKHN0YWtlcjogQWRkcmVzcywgcmV3YXJkVG9rZW46IHVpbnQ2NCwgYW1vdW50VG9TZW5kOiB1aW50NjQpOiB2b2lkCi8vCi8vIFtJbnRlcm5hbCBwcm90b2NvbCBtZXRob2RdIFJlbW92ZSBhIHNwZWNpZmllZCBhbW91bnQgb2YgJ2NvbW11bml0eSB0b2tlbicgcmV3YXJkcyBmb3IgYSBzdGFrZXIuCi8vIFRoaXMgY2FuIE9OTFkgYmUgY2FsbGVkIGJ5IG91ciB2YWxpZGF0b3IgYW5kIG9ubHkgaWYgd2UncmUgcG9vbCAxIC0gd2l0aCB0aGUgdG9rZW4uCi8vIEBwYXJhbSBzdGFrZXIgLSB0aGUgc3Rha2VyIGFjY291bnQgdG8gc2VuZCByZXdhcmRzIHRvCi8vIEBwYXJhbSByZXdhcmRUb2tlbiAtIGlkIG9mIHJld2FyZCB0b2tlbiAodG8gYXZvaWQgcmUtZW50cmFuY3kgaW4gY2FsbGluZyB2YWxpZGF0b3IgYmFjayB0byBnZXQgaWQpCi8vIEBwYXJhbSBhbW91bnRUb1NlbmQgLSBhbW91bnQgdG8gc2VuZCB0aGUgc3Rha2VyICh0aGVyZSBpcyBzaWduaWZpY2FudCB0cnVzdCBoZXJlKCEpIC0gYWxzbyB3aHkgb25seSB2YWxpZGF0b3IgY2FuIGNhbGwgdXMKcGF5VG9rZW5SZXdhcmQ6Cglwcm90byAzIDAKCgkvLyBjb250cmFjdHMvc3Rha2luZ1Bvb2wuYWxnby50czo0NDYKCS8vIGFzc2VydCh0aGlzLnR4bi5zZW5kZXIgPT09IEFwcElELmZyb21VaW50NjQodGhpcy5jcmVhdGluZ1ZhbGlkYXRvckNvbnRyYWN0QXBwSWQudmFsdWUpLmFkZHJlc3MpCgl0eG4gU2VuZGVyCglieXRlIDB4NjM3MjY1NjE3NDZmNzI0MTcwNzAgLy8gImNyZWF0b3JBcHAiCglhcHBfZ2xvYmFsX2dldAoJYXBwX3BhcmFtc19nZXQgQXBwQWRkcmVzcwoJcG9wCgk9PQoJYXNzZXJ0CgoJLy8gY29udHJhY3RzL3N0YWtpbmdQb29sLmFsZ28udHM6NDQ3CgkvLyBhc3NlcnQodGhpcy5wb29sSWQudmFsdWUgPT09IDEsICdtdXN0IGJlIHBvb2wgMSBpbiBvcmRlciB0byBiZSBjYWxsZWQgdG8gcGF5IG91dCB0b2tlbiByZXdhcmRzJykKCWJ5dGUgMHg3MDZmNmY2YzQ5NjQgLy8gInBvb2xJZCIKCWFwcF9nbG9iYWxfZ2V0CglpbnQgMQoJPT0KCgkvLyBtdXN0IGJlIHBvb2wgMSBpbiBvcmRlciB0byBiZSBjYWxsZWQgdG8gcGF5IG91dCB0b2tlbiByZXdhcmRzCglhc3NlcnQKCgkvLyBjb250cmFjdHMvc3Rha2luZ1Bvb2wuYWxnby50czo0NDgKCS8vIGFzc2VydChyZXdhcmRUb2tlbiAhPT0gMCwgJ2NhbiBvbmx5IGNsYWltIHRva2VuIHJld2FyZHMgZnJvbSB2YWxpZGF0b3IgdGhhdCBoYXMgdGhlbScpCglmcmFtZV9kaWcgLTIgLy8gcmV3YXJkVG9rZW46IHVpbnQ2NAoJaW50IDAKCSE9CgoJLy8gY2FuIG9ubHkgY2xhaW0gdG9rZW4gcmV3YXJkcyBmcm9tIHZhbGlkYXRvciB0aGF0IGhhcyB0aGVtCglhc3NlcnQKCgkvLyBjb250cmFjdHMvc3Rha2luZ1Bvb2wuYWxnby50czo0NTEKCS8vIHNlbmRBc3NldFRyYW5zZmVyKHsKCS8vICAgICAgICAgICAgIHhmZXJBc3NldDogQXNzZXRJRC5mcm9tVWludDY0KHJld2FyZFRva2VuKSwKCS8vICAgICAgICAgICAgIGFzc2V0UmVjZWl2ZXI6IHN0YWtlciwKCS8vICAgICAgICAgICAgIGFzc2V0QW1vdW50OiBhbW91bnRUb1NlbmQsCgkvLyAgICAgICAgIH0pCglpdHhuX2JlZ2luCglpbnQgYXhmZXIKCWl0eG5fZmllbGQgVHlwZUVudW0KCgkvLyBjb250cmFjdHMvc3Rha2luZ1Bvb2wuYWxnby50czo0NTIKCS8vIHhmZXJBc3NldDogQXNzZXRJRC5mcm9tVWludDY0KHJld2FyZFRva2VuKQoJZnJhbWVfZGlnIC0yIC8vIHJld2FyZFRva2VuOiB1aW50NjQKCWl0eG5fZmllbGQgWGZlckFzc2V0CgoJLy8gY29udHJhY3RzL3N0YWtpbmdQb29sLmFsZ28udHM6NDUzCgkvLyBhc3NldFJlY2VpdmVyOiBzdGFrZXIKCWZyYW1lX2RpZyAtMSAvLyBzdGFrZXI6IEFkZHJlc3MKCWl0eG5fZmllbGQgQXNzZXRSZWNlaXZlcgoKCS8vIGNvbnRyYWN0cy9zdGFraW5nUG9vbC5hbGdvLnRzOjQ1NAoJLy8gYXNzZXRBbW91bnQ6IGFtb3VudFRvU2VuZAoJZnJhbWVfZGlnIC0zIC8vIGFtb3VudFRvU2VuZDogdWludDY0CglpdHhuX2ZpZWxkIEFzc2V0QW1vdW50CgoJLy8gRmVlIGZpZWxkIG5vdCBzZXQsIGRlZmF1bHRpbmcgdG8gMAoJaW50IDAKCWl0eG5fZmllbGQgRmVlCgoJLy8gU3VibWl0IGlubmVyIHRyYW5zYWN0aW9uCglpdHhuX3N1Ym1pdAoJcmV0c3ViCgovLyB1cGRhdGVBbGdvZFZlcihzdHJpbmcpdm9pZAoqYWJpX3JvdXRlX3VwZGF0ZUFsZ29kVmVyOgoJLy8gYWxnb2RWZXI6IHN0cmluZwoJdHhuYSBBcHBsaWNhdGlvbkFyZ3MgMQoJZXh0cmFjdCAyIDAKCgkvLyBleGVjdXRlIHVwZGF0ZUFsZ29kVmVyKHN0cmluZyl2b2lkCgljYWxsc3ViIHVwZGF0ZUFsZ29kVmVyCglpbnQgMQoJcmV0dXJuCgovLyB1cGRhdGVBbGdvZFZlcihhbGdvZFZlcjogc3RyaW5nKTogdm9pZAovLwovLyBVcGRhdGUgdGhlIChob25vciBzeXN0ZW0pIGFsZ29kIHZlcnNpb24gZm9yIHRoZSBub2RlIGFzc29jaWF0ZWQgdG8gdGhpcyBwb29sLiAgVGhlIG5vZGUgbWFuYWdlbWVudCBkYWVtb24KLy8gc2hvdWxkIGNvbXBhcmUgaXRzIGN1cnJlbnQgbm9kZXMgdmVyc2lvbiB0byB0aGUgdmVyc2lvbiBzdG9yZWQgaW4gZ2xvYmFsIHN0YXRlLCB1cGRhdGluZyB3aGVuIGRpZmZlcmVudC4KLy8gVGhlIHJldGkgbm9kZSBkYWVtb24gY29tcG9zZXMgaXRzIG93biB2ZXJzaW9uIHN0cmluZyB1c2luZyBmb3JtYXQ6Ci8vIHttYWpvcn0ue21pbm9yfS57YnVpbGR9IHticmFuY2h9IFt7Y29tbWl0IGhhc2h9XSwKLy8gaWU6IDMuMjIuMCByZWwvc3RhYmxlIFs2YjUwODk3NV0KLy8gWyBPTkxZIE9XTkVSIE9SIE1BTkFHRVIgQ0FOIENBTEwgXQovLyBAcGFyYW0ge3N0cmluZ30gYWxnb2RWZXIgLSBzdHJpbmcgcmVwcmVzZW50aW5nIHRoZSBhbGdvcmFuZCBub2RlIGRhZW1vbiB2ZXJzaW9uIChyZXRpIG5vZGUgZGFlbW9uIGNvbXBvc2VzIGl0cyBvd24gbWV0YSB2ZXJzaW9uKQp1cGRhdGVBbGdvZFZlcjoKCXByb3RvIDEgMAoKCS8vIGNvbnRyYWN0cy9zdGFraW5nUG9vbC5hbGdvLnRzOjQ2OAoJLy8gYXNzZXJ0KHRoaXMuaXNPd25lck9yTWFuYWdlckNhbGxlcigpKQoJY2FsbHN1YiBpc093bmVyT3JNYW5hZ2VyQ2FsbGVyCglhc3NlcnQKCgkvLyBjb250cmFjdHMvc3Rha2luZ1Bvb2wuYWxnby50czo0NjkKCS8vIHRoaXMuYWxnb2RWZXIudmFsdWUgPSBhbGdvZFZlcgoJYnl0ZSAweDYxNmM2NzZmNjQ1NjY1NzIgLy8gImFsZ29kVmVyIgoJZnJhbWVfZGlnIC0xIC8vIGFsZ29kVmVyOiBzdHJpbmcKCWFwcF9nbG9iYWxfcHV0CglyZXRzdWIKCi8vIGVwb2NoQmFsYW5jZVVwZGF0ZSgpdm9pZAoqYWJpX3JvdXRlX2Vwb2NoQmFsYW5jZVVwZGF0ZToKCS8vIGV4ZWN1dGUgZXBvY2hCYWxhbmNlVXBkYXRlKCl2b2lkCgljYWxsc3ViIGVwb2NoQmFsYW5jZVVwZGF0ZQoJaW50IDEKCXJldHVybgoKLy8gZXBvY2hCYWxhbmNlVXBkYXRlKCk6IHZvaWQKLy8KLy8gVXBkYXRlcyB0aGUgYmFsYW5jZSBvZiBzdGFrZXJzIGluIHRoZSBwb29sIGJhc2VkIG9uIHRoZSByZWNlaXZlZCAncmV3YXJkcycgKGN1cnJlbnQgYmFsYW5jZSB2cyBrbm93biBzdGFrZWQgYmFsYW5jZSkKLy8gc3Rha2VycyBvdXRzdGFuZGluZyBiYWxhbmNlIGlzIGFkanVzdGVkIGJhc2VkIG9uIHRoZWlyICUgb2Ygc3Rha2UgYW5kIHRpbWUgaW4gdGhlIGN1cnJlbnQgZXBvY2ggLSBzbyB0aGF0IGJhbGFuY2UKLy8gY29tcG91bmRzIG92ZXIgdGltZSBhbmQgc3Rha2VyIGNhbiByZW1vdmUgdGhhdCBhbW91bnQgYXQgd2lsbC4KLy8gVGhlIHZhbGlkYXRvciBpcyBwYWlkIHRoZWlyIHBlcmNlbnRhZ2UgZWFjaCBlcG9jaCBwYXlvdXQuCi8vCi8vIE5vdGU6IEFOWU9ORSBjYW4gY2FsbCB0aGlzLgplcG9jaEJhbGFuY2VVcGRhdGU6Cglwcm90byAwIDAKCgkvLyBQdXNoIGVtcHR5IGJ5dGVzIGFmdGVyIHRoZSBmcmFtZSBwb2ludGVyIHRvIHJlc2VydmUgc3BhY2UgZm9yIGxvY2FsIHZhcmlhYmxlcwoJYnl0ZSAweAoJZHVwbiAzMwoKCS8vIGNvbnRyYWN0cy9zdGFraW5nUG9vbC5hbGdvLnRzOjQ4MgoJLy8gdmFsaWRhdG9yQ29uZmlnID0gc2VuZE1ldGhvZENhbGw8dHlwZW9mIFZhbGlkYXRvclJlZ2lzdHJ5LnByb3RvdHlwZS5nZXRWYWxpZGF0b3JDb25maWc+KHsKCS8vICAgICAgICAgICAgIGFwcGxpY2F0aW9uSUQ6IEFwcElELmZyb21VaW50NjQodGhpcy5jcmVhdGluZ1ZhbGlkYXRvckNvbnRyYWN0QXBwSWQudmFsdWUpLAoJLy8gICAgICAgICAgICAgbWV0aG9kQXJnczogW3RoaXMudmFsaWRhdG9ySWQudmFsdWVdLAoJLy8gICAgICAgICB9KQoJaXR4bl9iZWdpbgoJaW50IGFwcGwKCWl0eG5fZmllbGQgVHlwZUVudW0KCW1ldGhvZCAiZ2V0VmFsaWRhdG9yQ29uZmlnKHVpbnQ2NCkodWludDY0LGFkZHJlc3MsYWRkcmVzcyx1aW50NjQsdWludDgsYnl0ZVszMl0sdWludDY0LHVpbnQ2NCx1aW50NjQsdWludDE2LHVpbnQzMixhZGRyZXNzLHVpbnQ2NCx1aW50NjQsdWludDgsdWludDY0LHVpbnQ2NCkiCglpdHhuX2ZpZWxkIEFwcGxpY2F0aW9uQXJncwoKCS8vIGNvbnRyYWN0cy9zdGFraW5nUG9vbC5hbGdvLnRzOjQ4MwoJLy8gYXBwbGljYXRpb25JRDogQXBwSUQuZnJvbVVpbnQ2NCh0aGlzLmNyZWF0aW5nVmFsaWRhdG9yQ29udHJhY3RBcHBJZC52YWx1ZSkKCWJ5dGUgMHg2MzcyNjU2MTc0NmY3MjQxNzA3MCAvLyAiY3JlYXRvckFwcCIKCWFwcF9nbG9iYWxfZ2V0CglpdHhuX2ZpZWxkIEFwcGxpY2F0aW9uSUQKCgkvLyBjb250cmFjdHMvc3Rha2luZ1Bvb2wuYWxnby50czo0ODQKCS8vIG1ldGhvZEFyZ3M6IFt0aGlzLnZhbGlkYXRvcklkLnZhbHVlXQoJYnl0ZSAweDc2NjE2YzY5NjQ2MTc0NmY3MjQ5NjQgLy8gInZhbGlkYXRvcklkIgoJYXBwX2dsb2JhbF9nZXQKCWl0b2IKCWl0eG5fZmllbGQgQXBwbGljYXRpb25BcmdzCgoJLy8gRmVlIGZpZWxkIG5vdCBzZXQsIGRlZmF1bHRpbmcgdG8gMAoJaW50IDAKCWl0eG5fZmllbGQgRmVlCgoJLy8gU3VibWl0IGlubmVyIHRyYW5zYWN0aW9uCglpdHhuX3N1Ym1pdAoJaXR4biBOdW1Mb2dzCglpbnQgMQoJLQoJaXR4bmFzIExvZ3MKCWV4dHJhY3QgNCAwCglmcmFtZV9idXJ5IDAgLy8gdmFsaWRhdG9yQ29uZmlnOiAodWludDY0LGFkZHJlc3MsYWRkcmVzcyx1aW50NjQsdWludDgsYnl0ZVszMl0sdWludDY0LHVpbnQ2NCx1aW50NjQsdWludDE2LHVpbnQzMixhZGRyZXNzLHVpbnQ2NCx1aW50NjQsdWludDgsdWludDY0LHVpbnQ2NCkKCgkvLyBjb250cmFjdHMvc3Rha2luZ1Bvb2wuYWxnby50czo0OTIKCS8vIGN1clRpbWUgPSBnbG9iYWxzLmxhdGVzdFRpbWVzdGFtcAoJZ2xvYmFsIExhdGVzdFRpbWVzdGFtcAoJZnJhbWVfYnVyeSAxIC8vIGN1clRpbWU6IHVpbnQ2NAoKCS8vIGNvbnRyYWN0cy9zdGFraW5nUG9vbC5hbGdvLnRzOjQ5NAoJLy8gZXBvY2hJblNlY3MgPSAodmFsaWRhdG9yQ29uZmlnLnBheW91dEV2ZXJ5WE1pbnMgYXMgdWludDY0KSAqIDYwCglmcmFtZV9kaWcgMCAvLyB2YWxpZGF0b3JDb25maWc6ICh1aW50NjQsYWRkcmVzcyxhZGRyZXNzLHVpbnQ2NCx1aW50OCxieXRlWzMyXSx1aW50NjQsdWludDY0LHVpbnQ2NCx1aW50MTYsdWludDMyLGFkZHJlc3MsdWludDY0LHVpbnQ2NCx1aW50OCx1aW50NjQsdWludDY0KQoJZXh0cmFjdCAxMzcgMgoJYnRvaQoJaW50IDYwCgkqCglmcmFtZV9idXJ5IDIgLy8gZXBvY2hJblNlY3M6IHVpbnQ2NAoKCS8vICppZjE5X2NvbmRpdGlvbgoJLy8gY29udHJhY3RzL3N0YWtpbmdQb29sLmFsZ28udHM6NDk1CgkvLyB0aGlzLmxhc3RQYXlvdXQuZXhpc3RzCgl0eG5hIEFwcGxpY2F0aW9ucyAwCglieXRlIDB4NmM2MTczNzQ1MDYxNzk2Zjc1NzQgLy8gImxhc3RQYXlvdXQiCglhcHBfZ2xvYmFsX2dldF9leAoJc3dhcAoJcG9wCglieiAqaWYxOV9lbmQKCgkvLyAqaWYxOV9jb25zZXF1ZW50CgkvLyBjb250cmFjdHMvc3Rha2luZ1Bvb2wuYWxnby50czo0OTYKCS8vIHNlY3NTaW5jZUxhc3RQYXlvdXQgPSBjdXJUaW1lIC0gdGhpcy5sYXN0UGF5b3V0LnZhbHVlCglmcmFtZV9kaWcgMSAvLyBjdXJUaW1lOiB1aW50NjQKCWJ5dGUgMHg2YzYxNzM3NDUwNjE3OTZmNzU3NCAvLyAibGFzdFBheW91dCIKCWFwcF9nbG9iYWxfZ2V0CgktCglmcmFtZV9idXJ5IDMgLy8gc2Vjc1NpbmNlTGFzdFBheW91dDogdWludDY0CgoJLy8gY29udHJhY3RzL3N0YWtpbmdQb29sLmFsZ28udHM6NDk3CgkvLyBsb2coY29uY2F0KCdzZWNzIHNpbmNlIGxhc3QgcGF5b3V0OiAlaScsIGl0b2Ioc2Vjc1NpbmNlTGFzdFBheW91dCkpKQoJYnl0ZSAweDczNjU2MzczMjA3MzY5NmU2MzY1MjA2YzYxNzM3NDIwNzA2MTc5NmY3NTc0M2EyMDI1NjkgLy8gInNlY3Mgc2luY2UgbGFzdCBwYXlvdXQ6ICVpIgoJZnJhbWVfZGlnIDMgLy8gc2Vjc1NpbmNlTGFzdFBheW91dDogdWludDY0CglpdG9iCgljb25jYXQKCWxvZwoKCS8vIGNvbnRyYWN0cy9zdGFraW5nUG9vbC5hbGdvLnRzOjUwMAoJLy8gYXNzZXJ0KHNlY3NTaW5jZUxhc3RQYXlvdXQgPj0gZXBvY2hJblNlY3MsICJDYW4ndCBwYXlvdXQgZWFybGllciB0aGFuIGxhc3QgcGF5b3V0ICsgZXBvY2ggdGltZSIpCglmcmFtZV9kaWcgMyAvLyBzZWNzU2luY2VMYXN0UGF5b3V0OiB1aW50NjQKCWZyYW1lX2RpZyAyIC8vIGVwb2NoSW5TZWNzOiB1aW50NjQKCT49CgoJLy8gQ2FuJ3QgcGF5b3V0IGVhcmxpZXIgdGhhbiBsYXN0IHBheW91dCArIGVwb2NoIHRpbWUKCWFzc2VydAoKKmlmMTlfZW5kOgoJLy8gY29udHJhY3RzL3N0YWtpbmdQb29sLmFsZ28udHM6NTAzCgkvLyB0aGlzLmxhc3RQYXlvdXQudmFsdWUgPSBjdXJUaW1lCglieXRlIDB4NmM2MTczNzQ1MDYxNzk2Zjc1NzQgLy8gImxhc3RQYXlvdXQiCglmcmFtZV9kaWcgMSAvLyBjdXJUaW1lOiB1aW50NjQKCWFwcF9nbG9iYWxfcHV0CgoJLy8gY29udHJhY3RzL3N0YWtpbmdQb29sLmFsZ28udHM6NTA0CgkvLyB0aGlzLmVwb2NoTnVtYmVyLnZhbHVlICs9IDEKCWJ5dGUgMHg2NTcwNmY2MzY4NGU3NTZkNjI2NTcyIC8vICJlcG9jaE51bWJlciIKCWFwcF9nbG9iYWxfZ2V0CglpbnQgMQoJKwoJYnl0ZSAweDY1NzA2ZjYzNjg0ZTc1NmQ2MjY1NzIgLy8gImVwb2NoTnVtYmVyIgoJc3dhcAoJYXBwX2dsb2JhbF9wdXQKCgkvLyBjb250cmFjdHMvc3Rha2luZ1Bvb2wuYWxnby50czo1MDkKCS8vIGlzVG9rZW5FbGlnaWJsZSA9IHZhbGlkYXRvckNvbmZpZy5yZXdhcmRUb2tlbklkICE9PSAwCglmcmFtZV9kaWcgMCAvLyB2YWxpZGF0b3JDb25maWc6ICh1aW50NjQsYWRkcmVzcyxhZGRyZXNzLHVpbnQ2NCx1aW50OCxieXRlWzMyXSx1aW50NjQsdWludDY0LHVpbnQ2NCx1aW50MTYsdWludDMyLGFkZHJlc3MsdWludDY0LHVpbnQ2NCx1aW50OCx1aW50NjQsdWludDY0KQoJZXh0cmFjdCAxMjEgOAoJYnRvaQoJaW50IDAKCSE9CglmcmFtZV9idXJ5IDQgLy8gaXNUb2tlbkVsaWdpYmxlOiBib29sCgoJLy8gY29udHJhY3RzL3N0YWtpbmdQb29sLmFsZ28udHM6NTEwCgkvLyBwb29sT25lQXBwSUQgPSB0aGlzLmFwcC5pZAoJdHhuYSBBcHBsaWNhdGlvbnMgMAoJZnJhbWVfYnVyeSA1IC8vIHBvb2xPbmVBcHBJRDogdWludDY0CgoJLy8gY29udHJhY3RzL3N0YWtpbmdQb29sLmFsZ28udHM6NTExCgkvLyBwb29sT25lQWRkcmVzcyA9IHRoaXMuYXBwLmFkZHJlc3MKCWdsb2JhbCBDdXJyZW50QXBwbGljYXRpb25BZGRyZXNzCglmcmFtZV9idXJ5IDYgLy8gcG9vbE9uZUFkZHJlc3M6IGFkZHJlc3MKCgkvLyAqaWYyMF9jb25kaXRpb24KCS8vIGNvbnRyYWN0cy9zdGFraW5nUG9vbC5hbGdvLnRzOjUxNgoJLy8gaXNUb2tlbkVsaWdpYmxlCglmcmFtZV9kaWcgNCAvLyBpc1Rva2VuRWxpZ2libGU6IGJvb2wKCWJ6ICppZjIwX2VuZAoKCS8vICppZjIwX2NvbnNlcXVlbnQKCS8vICppZjIxX2NvbmRpdGlvbgoJLy8gY29udHJhY3RzL3N0YWtpbmdQb29sLmFsZ28udHM6NTE3CgkvLyB0aGlzLnBvb2xJZC52YWx1ZSAhPT0gMQoJYnl0ZSAweDcwNmY2ZjZjNDk2NCAvLyAicG9vbElkIgoJYXBwX2dsb2JhbF9nZXQKCWludCAxCgkhPQoJYnogKmlmMjFfZW5kCgoJLy8gKmlmMjFfY29uc2VxdWVudAoJLy8gY29udHJhY3RzL3N0YWtpbmdQb29sLmFsZ28udHM6NTE5CgkvLyBwb29sT25lQXBwSUQgPSBzZW5kTWV0aG9kQ2FsbDx0eXBlb2YgVmFsaWRhdG9yUmVnaXN0cnkucHJvdG90eXBlLmdldFBvb2xBcHBJZD4oewoJLy8gICAgICAgICAgICAgICAgICAgICBhcHBsaWNhdGlvbklEOiBBcHBJRC5mcm9tVWludDY0KHRoaXMuY3JlYXRpbmdWYWxpZGF0b3JDb250cmFjdEFwcElkLnZhbHVlKSwKCS8vICAgICAgICAgICAgICAgICAgICAgbWV0aG9kQXJnczogW3RoaXMudmFsaWRhdG9ySWQudmFsdWUsIDFdLAoJLy8gICAgICAgICAgICAgICAgIH0pCglpdHhuX2JlZ2luCglpbnQgYXBwbAoJaXR4bl9maWVsZCBUeXBlRW51bQoJbWV0aG9kICJnZXRQb29sQXBwSWQodWludDY0LHVpbnQ2NCl1aW50NjQiCglpdHhuX2ZpZWxkIEFwcGxpY2F0aW9uQXJncwoKCS8vIGNvbnRyYWN0cy9zdGFraW5nUG9vbC5hbGdvLnRzOjUyMAoJLy8gYXBwbGljYXRpb25JRDogQXBwSUQuZnJvbVVpbnQ2NCh0aGlzLmNyZWF0aW5nVmFsaWRhdG9yQ29udHJhY3RBcHBJZC52YWx1ZSkKCWJ5dGUgMHg2MzcyNjU2MTc0NmY3MjQxNzA3MCAvLyAiY3JlYXRvckFwcCIKCWFwcF9nbG9iYWxfZ2V0CglpdHhuX2ZpZWxkIEFwcGxpY2F0aW9uSUQKCgkvLyBjb250cmFjdHMvc3Rha2luZ1Bvb2wuYWxnby50czo1MjEKCS8vIG1ldGhvZEFyZ3M6IFt0aGlzLnZhbGlkYXRvcklkLnZhbHVlLCAxXQoJYnl0ZSAweDc2NjE2YzY5NjQ2MTc0NmY3MjQ5NjQgLy8gInZhbGlkYXRvcklkIgoJYXBwX2dsb2JhbF9nZXQKCWl0b2IKCWl0eG5fZmllbGQgQXBwbGljYXRpb25BcmdzCglieXRlIDB4MDAwMDAwMDAwMDAwMDAwMQoJaXR4bl9maWVsZCBBcHBsaWNhdGlvbkFyZ3MKCgkvLyBGZWUgZmllbGQgbm90IHNldCwgZGVmYXVsdGluZyB0byAwCglpbnQgMAoJaXR4bl9maWVsZCBGZWUKCgkvLyBTdWJtaXQgaW5uZXIgdHJhbnNhY3Rpb24KCWl0eG5fc3VibWl0CglpdHhuIE51bUxvZ3MKCWludCAxCgktCglpdHhuYXMgTG9ncwoJZXh0cmFjdCA0IDAKCWJ0b2kKCWZyYW1lX2J1cnkgNSAvLyBwb29sT25lQXBwSUQ6IHVpbnQ2NAoKCS8vIGNvbnRyYWN0cy9zdGFraW5nUG9vbC5hbGdvLnRzOjUyMwoJLy8gcG9vbE9uZUFkZHJlc3MgPSBBcHBJRC5mcm9tVWludDY0KHBvb2xPbmVBcHBJRCkuYWRkcmVzcwoJZnJhbWVfZGlnIDUgLy8gcG9vbE9uZUFwcElEOiB1aW50NjQKCWFwcF9wYXJhbXNfZ2V0IEFwcEFkZHJlc3MKCXBvcAoJZnJhbWVfYnVyeSA2IC8vIHBvb2xPbmVBZGRyZXNzOiBhZGRyZXNzCgoqaWYyMV9lbmQ6CgkvLyAqaWYyMl9jb25kaXRpb24KCS8vIGNvbnRyYWN0cy9zdGFraW5nUG9vbC5hbGdvLnRzOjUyOAoJLy8gdGhpcy5wb29sSWQudmFsdWUgPT09IDEKCWJ5dGUgMHg3MDZmNmY2YzQ5NjQgLy8gInBvb2xJZCIKCWFwcF9nbG9iYWxfZ2V0CglpbnQgMQoJPT0KCWJ6ICppZjIyX2Vsc2UKCgkvLyAqaWYyMl9jb25zZXF1ZW50CgkvLyBjb250cmFjdHMvc3Rha2luZ1Bvb2wuYWxnby50czo1MjkKCS8vIHRva2VuUGF5b3V0UmF0aW8gPSBzZW5kTWV0aG9kQ2FsbDx0eXBlb2YgVmFsaWRhdG9yUmVnaXN0cnkucHJvdG90eXBlLnNldFRva2VuUGF5b3V0UmF0aW8+KHsKCS8vICAgICAgICAgICAgICAgICAgICAgYXBwbGljYXRpb25JRDogQXBwSUQuZnJvbVVpbnQ2NCh0aGlzLmNyZWF0aW5nVmFsaWRhdG9yQ29udHJhY3RBcHBJZC52YWx1ZSksCgkvLyAgICAgICAgICAgICAgICAgICAgIG1ldGhvZEFyZ3M6IFt0aGlzLnZhbGlkYXRvcklkLnZhbHVlXSwKCS8vICAgICAgICAgICAgICAgICB9KQoJaXR4bl9iZWdpbgoJaW50IGFwcGwKCWl0eG5fZmllbGQgVHlwZUVudW0KCW1ldGhvZCAic2V0VG9rZW5QYXlvdXRSYXRpbyh1aW50NjQpKHVpbnQ2NFsyNF0sdWludDY0KSIKCWl0eG5fZmllbGQgQXBwbGljYXRpb25BcmdzCgoJLy8gY29udHJhY3RzL3N0YWtpbmdQb29sLmFsZ28udHM6NTMwCgkvLyBhcHBsaWNhdGlvbklEOiBBcHBJRC5mcm9tVWludDY0KHRoaXMuY3JlYXRpbmdWYWxpZGF0b3JDb250cmFjdEFwcElkLnZhbHVlKQoJYnl0ZSAweDYzNzI2NTYxNzQ2ZjcyNDE3MDcwIC8vICJjcmVhdG9yQXBwIgoJYXBwX2dsb2JhbF9nZXQKCWl0eG5fZmllbGQgQXBwbGljYXRpb25JRAoKCS8vIGNvbnRyYWN0cy9zdGFraW5nUG9vbC5hbGdvLnRzOjUzMQoJLy8gbWV0aG9kQXJnczogW3RoaXMudmFsaWRhdG9ySWQudmFsdWVdCglieXRlIDB4NzY2MTZjNjk2NDYxNzQ2ZjcyNDk2NCAvLyAidmFsaWRhdG9ySWQiCglhcHBfZ2xvYmFsX2dldAoJaXRvYgoJaXR4bl9maWVsZCBBcHBsaWNhdGlvbkFyZ3MKCgkvLyBGZWUgZmllbGQgbm90IHNldCwgZGVmYXVsdGluZyB0byAwCglpbnQgMAoJaXR4bl9maWVsZCBGZWUKCgkvLyBTdWJtaXQgaW5uZXIgdHJhbnNhY3Rpb24KCWl0eG5fc3VibWl0CglpdHhuIE51bUxvZ3MKCWludCAxCgktCglpdHhuYXMgTG9ncwoJZXh0cmFjdCA0IDAKCWZyYW1lX2J1cnkgNyAvLyB0b2tlblBheW91dFJhdGlvOiBQb29sVG9rZW5QYXlvdXRSYXRpbwoJYiAqaWYyMl9lbmQKCippZjIyX2Vsc2U6CgkvLyBjb250cmFjdHMvc3Rha2luZ1Bvb2wuYWxnby50czo1MzUKCS8vIHRva2VuUGF5b3V0UmF0aW8gPSBzZW5kTWV0aG9kQ2FsbDx0eXBlb2YgU3Rha2luZ1Bvb2wucHJvdG90eXBlLnByb3hpZWRTZXRUb2tlblBheW91dFJhdGlvPih7CgkvLyAgICAgICAgICAgICAgICAgICAgIGFwcGxpY2F0aW9uSUQ6IEFwcElELmZyb21VaW50NjQocG9vbE9uZUFwcElEKSwKCS8vICAgICAgICAgICAgICAgICAgICAgbWV0aG9kQXJnczogW3sgaWQ6IHRoaXMudmFsaWRhdG9ySWQudmFsdWUsIHBvb2xJZDogdGhpcy5wb29sSWQudmFsdWUsIHBvb2xBcHBJZDogdGhpcy5hcHAuaWQgfV0sCgkvLyAgICAgICAgICAgICAgICAgfSkKCWl0eG5fYmVnaW4KCWludCBhcHBsCglpdHhuX2ZpZWxkIFR5cGVFbnVtCgltZXRob2QgInByb3hpZWRTZXRUb2tlblBheW91dFJhdGlvKCh1aW50NjQsdWludDY0LHVpbnQ2NCkpKHVpbnQ2NFsyNF0sdWludDY0KSIKCWl0eG5fZmllbGQgQXBwbGljYXRpb25BcmdzCgoJLy8gY29udHJhY3RzL3N0YWtpbmdQb29sLmFsZ28udHM6NTM2CgkvLyBhcHBsaWNhdGlvbklEOiBBcHBJRC5mcm9tVWludDY0KHBvb2xPbmVBcHBJRCkKCWZyYW1lX2RpZyA1IC8vIHBvb2xPbmVBcHBJRDogdWludDY0CglpdHhuX2ZpZWxkIEFwcGxpY2F0aW9uSUQKCgkvLyBjb250cmFjdHMvc3Rha2luZ1Bvb2wuYWxnby50czo1MzcKCS8vIG1ldGhvZEFyZ3M6IFt7IGlkOiB0aGlzLnZhbGlkYXRvcklkLnZhbHVlLCBwb29sSWQ6IHRoaXMucG9vbElkLnZhbHVlLCBwb29sQXBwSWQ6IHRoaXMuYXBwLmlkIH1dCglieXRlIDB4NzY2MTZjNjk2NDYxNzQ2ZjcyNDk2NCAvLyAidmFsaWRhdG9ySWQiCglhcHBfZ2xvYmFsX2dldAoJaXRvYgoJYnl0ZSAweDcwNmY2ZjZjNDk2NCAvLyAicG9vbElkIgoJYXBwX2dsb2JhbF9nZXQKCWl0b2IKCWNvbmNhdAoJdHhuYSBBcHBsaWNhdGlvbnMgMAoJaXRvYgoJY29uY2F0CglpdHhuX2ZpZWxkIEFwcGxpY2F0aW9uQXJncwoKCS8vIEZlZSBmaWVsZCBub3Qgc2V0LCBkZWZhdWx0aW5nIHRvIDAKCWludCAwCglpdHhuX2ZpZWxkIEZlZQoKCS8vIFN1Ym1pdCBpbm5lciB0cmFuc2FjdGlvbgoJaXR4bl9zdWJtaXQKCWl0eG4gTnVtTG9ncwoJaW50IDEKCS0KCWl0eG5hcyBMb2dzCglleHRyYWN0IDQgMAoJZnJhbWVfYnVyeSA3IC8vIHRva2VuUGF5b3V0UmF0aW86IFBvb2xUb2tlblBheW91dFJhdGlvCgoqaWYyMl9lbmQ6CgoqaWYyMF9lbmQ6CgkvLyBjb250cmFjdHMvc3Rha2luZ1Bvb2wuYWxnby50czo1NDQKCS8vIHZhbGlkYXRvclN0YXRlID0gc2VuZE1ldGhvZENhbGw8dHlwZW9mIFZhbGlkYXRvclJlZ2lzdHJ5LnByb3RvdHlwZS5nZXRWYWxpZGF0b3JTdGF0ZT4oewoJLy8gICAgICAgICAgICAgYXBwbGljYXRpb25JRDogQXBwSUQuZnJvbVVpbnQ2NCh0aGlzLmNyZWF0aW5nVmFsaWRhdG9yQ29udHJhY3RBcHBJZC52YWx1ZSksCgkvLyAgICAgICAgICAgICBtZXRob2RBcmdzOiBbdGhpcy52YWxpZGF0b3JJZC52YWx1ZV0sCgkvLyAgICAgICAgIH0pCglpdHhuX2JlZ2luCglpbnQgYXBwbAoJaXR4bl9maWVsZCBUeXBlRW51bQoJbWV0aG9kICJnZXRWYWxpZGF0b3JTdGF0ZSh1aW50NjQpKHVpbnQxNix1aW50NjQsdWludDY0LHVpbnQ2NCkiCglpdHhuX2ZpZWxkIEFwcGxpY2F0aW9uQXJncwoKCS8vIGNvbnRyYWN0cy9zdGFraW5nUG9vbC5hbGdvLnRzOjU0NQoJLy8gYXBwbGljYXRpb25JRDogQXBwSUQuZnJvbVVpbnQ2NCh0aGlzLmNyZWF0aW5nVmFsaWRhdG9yQ29udHJhY3RBcHBJZC52YWx1ZSkKCWJ5dGUgMHg2MzcyNjU2MTc0NmY3MjQxNzA3MCAvLyAiY3JlYXRvckFwcCIKCWFwcF9nbG9iYWxfZ2V0CglpdHhuX2ZpZWxkIEFwcGxpY2F0aW9uSUQKCgkvLyBjb250cmFjdHMvc3Rha2luZ1Bvb2wuYWxnby50czo1NDYKCS8vIG1ldGhvZEFyZ3M6IFt0aGlzLnZhbGlkYXRvcklkLnZhbHVlXQoJYnl0ZSAweDc2NjE2YzY5NjQ2MTc0NmY3MjQ5NjQgLy8gInZhbGlkYXRvcklkIgoJYXBwX2dsb2JhbF9nZXQKCWl0b2IKCWl0eG5fZmllbGQgQXBwbGljYXRpb25BcmdzCgoJLy8gRmVlIGZpZWxkIG5vdCBzZXQsIGRlZmF1bHRpbmcgdG8gMAoJaW50IDAKCWl0eG5fZmllbGQgRmVlCgoJLy8gU3VibWl0IGlubmVyIHRyYW5zYWN0aW9uCglpdHhuX3N1Ym1pdAoJaXR4biBOdW1Mb2dzCglpbnQgMQoJLQoJaXR4bmFzIExvZ3MKCWV4dHJhY3QgNCAwCglmcmFtZV9idXJ5IDggLy8gdmFsaWRhdG9yU3RhdGU6ICh1aW50MTYsdWludDY0LHVpbnQ2NCx1aW50NjQpCgoJLy8gY29udHJhY3RzL3N0YWtpbmdQb29sLmFsZ28udHM6NTQ4CgkvLyByZXdhcmRUb2tlbkhlbGRCYWNrID0gdmFsaWRhdG9yU3RhdGUucmV3YXJkVG9rZW5IZWxkQmFjawoJZnJhbWVfZGlnIDggLy8gdmFsaWRhdG9yU3RhdGU6ICh1aW50MTYsdWludDY0LHVpbnQ2NCx1aW50NjQpCglleHRyYWN0IDE4IDgKCWJ0b2kKCWZyYW1lX2J1cnkgOSAvLyByZXdhcmRUb2tlbkhlbGRCYWNrOiB1aW50NjQKCgkvLyBjb250cmFjdHMvc3Rha2luZ1Bvb2wuYWxnby50czo1NTQKCS8vIGFsZ29SZXdhcmRBdmFpbCA9IHRoaXMuYXBwLmFkZHJlc3MuYmFsYW5jZSAtIHRoaXMudG90YWxBbGdvU3Rha2VkLnZhbHVlIC0gdGhpcy5hcHAuYWRkcmVzcy5taW5CYWxhbmNlCglnbG9iYWwgQ3VycmVudEFwcGxpY2F0aW9uQWRkcmVzcwoJYWNjdF9wYXJhbXNfZ2V0IEFjY3RCYWxhbmNlCglwb3AKCWJ5dGUgMHg3Mzc0NjE2YjY1NjQgLy8gInN0YWtlZCIKCWFwcF9nbG9iYWxfZ2V0CgktCglnbG9iYWwgQ3VycmVudEFwcGxpY2F0aW9uQWRkcmVzcwoJYWNjdF9wYXJhbXNfZ2V0IEFjY3RNaW5CYWxhbmNlCglwb3AKCS0KCWZyYW1lX2J1cnkgMTAgLy8gYWxnb1Jld2FyZEF2YWlsOiB1aW50NjQKCgkvLyBjb250cmFjdHMvc3Rha2luZ1Bvb2wuYWxnby50czo1NTUKCS8vIGlzUG9vbFNhdHVyYXRlZCA9IGZhbHNlCglpbnQgMAoJZnJhbWVfYnVyeSAxMSAvLyBpc1Bvb2xTYXR1cmF0ZWQ6IGJvb2wKCgkvLyBjb250cmFjdHMvc3Rha2luZ1Bvb2wuYWxnby50czo1NTYKCS8vIGFsZ29TYXR1cmF0aW9uQW10ID0gdGhpcy5hbGdvU2F0dXJhdGlvbkxldmVsKCkKCWNhbGxzdWIgYWxnb1NhdHVyYXRpb25MZXZlbAoJZnJhbWVfYnVyeSAxMiAvLyBhbGdvU2F0dXJhdGlvbkFtdDogdWludDY0CgoJLy8gKmlmMjNfY29uZGl0aW9uCgkvLyBjb250cmFjdHMvc3Rha2luZ1Bvb2wuYWxnby50czo1NjQKCS8vIHZhbGlkYXRvclN0YXRlLnRvdGFsQWxnb1N0YWtlZCA+IGFsZ29TYXR1cmF0aW9uQW10CglmcmFtZV9kaWcgOCAvLyB2YWxpZGF0b3JTdGF0ZTogKHVpbnQxNix1aW50NjQsdWludDY0LHVpbnQ2NCkKCWV4dHJhY3QgMTAgOAoJYnRvaQoJZnJhbWVfZGlnIDEyIC8vIGFsZ29TYXR1cmF0aW9uQW10OiB1aW50NjQKCT4KCWJ6ICppZjIzX2VuZAoKCS8vICppZjIzX2NvbnNlcXVlbnQKCS8vIGNvbnRyYWN0cy9zdGFraW5nUG9vbC5hbGdvLnRzOjU2NQoJLy8gbG9nKCd2YWxpZGF0b3IgaW4gc2F0dXJhdGVkIHN0YXRlJykKCWJ5dGUgMHg3NjYxNmM2OTY0NjE3NDZmNzIyMDY5NmUyMDczNjE3NDc1NzI2MTc0NjU2NDIwNzM3NDYxNzQ2NSAvLyAidmFsaWRhdG9yIGluIHNhdHVyYXRlZCBzdGF0ZSIKCWxvZwoKCS8vIGNvbnRyYWN0cy9zdGFraW5nUG9vbC5hbGdvLnRzOjU2NgoJLy8gaXNQb29sU2F0dXJhdGVkID0gdHJ1ZQoJaW50IDEKCWZyYW1lX2J1cnkgMTEgLy8gaXNQb29sU2F0dXJhdGVkOiBib29sCgoqaWYyM19lbmQ6CgkvLyBjb250cmFjdHMvc3Rha2luZ1Bvb2wuYWxnby50czo1NzIKCS8vIHRva2VuUmV3YXJkQXZhaWwgPSAwCglpbnQgMAoJZnJhbWVfYnVyeSAxMyAvLyB0b2tlblJld2FyZEF2YWlsOiB1aW50NjQKCgkvLyBjb250cmFjdHMvc3Rha2luZ1Bvb2wuYWxnby50czo1NzMKCS8vIHRva2VuUmV3YXJkUGFpZE91dCA9IDAKCWludCAwCglmcmFtZV9idXJ5IDE0IC8vIHRva2VuUmV3YXJkUGFpZE91dDogdWludDY0CgoJLy8gKmlmMjRfY29uZGl0aW9uCgkvLyBjb250cmFjdHMvc3Rha2luZ1Bvb2wuYWxnby50czo1NzQKCS8vIGlzVG9rZW5FbGlnaWJsZQoJZnJhbWVfZGlnIDQgLy8gaXNUb2tlbkVsaWdpYmxlOiBib29sCglieiAqaWYyNF9lbmQKCgkvLyAqaWYyNF9jb25zZXF1ZW50CgkvLyBjb250cmFjdHMvc3Rha2luZ1Bvb2wuYWxnby50czo1NzUKCS8vIHRva2VuUmV3YXJkQmFsID0KCS8vICAgICAgICAgICAgICAgICBwb29sT25lQWRkcmVzcy5hc3NldEJhbGFuY2UoQXNzZXRJRC5mcm9tVWludDY0KHZhbGlkYXRvckNvbmZpZy5yZXdhcmRUb2tlbklkKSkgLSByZXdhcmRUb2tlbkhlbGRCYWNrCglmcmFtZV9kaWcgNiAvLyBwb29sT25lQWRkcmVzczogYWRkcmVzcwoJZnJhbWVfZGlnIDAgLy8gdmFsaWRhdG9yQ29uZmlnOiAodWludDY0LGFkZHJlc3MsYWRkcmVzcyx1aW50NjQsdWludDgsYnl0ZVszMl0sdWludDY0LHVpbnQ2NCx1aW50NjQsdWludDE2LHVpbnQzMixhZGRyZXNzLHVpbnQ2NCx1aW50NjQsdWludDgsdWludDY0LHVpbnQ2NCkKCWV4dHJhY3QgMTIxIDgKCWJ0b2kKCWFzc2V0X2hvbGRpbmdfZ2V0IEFzc2V0QmFsYW5jZQoJcG9wCglmcmFtZV9kaWcgOSAvLyByZXdhcmRUb2tlbkhlbGRCYWNrOiB1aW50NjQKCS0KCWZyYW1lX2J1cnkgMTUgLy8gdG9rZW5SZXdhcmRCYWw6IHVpbnQ2NAoKCS8vICppZjI1X2NvbmRpdGlvbgoJLy8gY29udHJhY3RzL3N0YWtpbmdQb29sLmFsZ28udHM6NTgwCgkvLyB0b2tlblJld2FyZEJhbCA+PSB2YWxpZGF0b3JDb25maWcucmV3YXJkUGVyUGF5b3V0CglmcmFtZV9kaWcgMTUgLy8gdG9rZW5SZXdhcmRCYWw6IHVpbnQ2NAoJZnJhbWVfZGlnIDAgLy8gdmFsaWRhdG9yQ29uZmlnOiAodWludDY0LGFkZHJlc3MsYWRkcmVzcyx1aW50NjQsdWludDgsYnl0ZVszMl0sdWludDY0LHVpbnQ2NCx1aW50NjQsdWludDE2LHVpbnQzMixhZGRyZXNzLHVpbnQ2NCx1aW50NjQsdWludDgsdWludDY0LHVpbnQ2NCkKCWV4dHJhY3QgMTI5IDgKCWJ0b2kKCT49CglieiAqaWYyNV9lbmQKCgkvLyAqaWYyNV9jb25zZXF1ZW50CgkvLyBjb250cmFjdHMvc3Rha2luZ1Bvb2wuYWxnby50czo1ODQKCS8vIG91clBvb2xQY3RPZldob2xlID0gdG9rZW5QYXlvdXRSYXRpby5wb29sUGN0T2ZXaG9sZVt0aGlzLnBvb2xJZC52YWx1ZSAtIDFdCglmcmFtZV9kaWcgNyAvLyB0b2tlblBheW91dFJhdGlvOiBQb29sVG9rZW5QYXlvdXRSYXRpbwoJaW50IDAKCWJ5dGUgMHg3MDZmNmY2YzQ5NjQgLy8gInBvb2xJZCIKCWFwcF9nbG9iYWxfZ2V0CglpbnQgMQoJLQoJaW50IDgKCSogLy8gYWNjICogdHlwZUxlbmd0aAoJKwoJaW50IDgKCWV4dHJhY3QzCglidG9pCglmcmFtZV9idXJ5IDE2IC8vIG91clBvb2xQY3RPZldob2xlOiB1aW50NjQKCgkvLyBjb250cmFjdHMvc3Rha2luZ1Bvb2wuYWxnby50czo1ODcKCS8vIHRva2VuUmV3YXJkQXZhaWwgPSB3aWRlUmF0aW8oW3ZhbGlkYXRvckNvbmZpZy5yZXdhcmRQZXJQYXlvdXQsIG91clBvb2xQY3RPZldob2xlXSwgWzFfMDAwXzAwMF0pCglmcmFtZV9kaWcgMCAvLyB2YWxpZGF0b3JDb25maWc6ICh1aW50NjQsYWRkcmVzcyxhZGRyZXNzLHVpbnQ2NCx1aW50OCxieXRlWzMyXSx1aW50NjQsdWludDY0LHVpbnQ2NCx1aW50MTYsdWludDMyLGFkZHJlc3MsdWludDY0LHVpbnQ2NCx1aW50OCx1aW50NjQsdWludDY0KQoJZXh0cmFjdCAxMjkgOAoJYnRvaQoJZnJhbWVfZGlnIDE2IC8vIG91clBvb2xQY3RPZldob2xlOiB1aW50NjQKCW11bHcKCWludCAwCglpbnQgMV8wMDBfMDAwCglkaXZtb2R3Cglwb3AKCXBvcAoJc3dhcAoJIQoJYXNzZXJ0CglmcmFtZV9idXJ5IDEzIC8vIHRva2VuUmV3YXJkQXZhaWw6IHVpbnQ2NAoKCS8vIGNvbnRyYWN0cy9zdGFraW5nUG9vbC5hbGdvLnRzOjU5MQoJLy8gbG9nKGNvbmNhdCgndG9rZW4gcmV3YXJkIGF2YWlsOiAnLCB0b2tlblJld2FyZEF2YWlsLnRvU3RyaW5nKCkpKQoJYnl0ZSAweDc0NmY2YjY1NmUyMDcyNjU3NzYxNzI2NDIwNjE3NjYxNjk2YzNhMjAgLy8gInRva2VuIHJld2FyZCBhdmFpbDogIgoJZnJhbWVfZGlnIDEzIC8vIHRva2VuUmV3YXJkQXZhaWw6IHVpbnQ2NAoJY2FsbHN1YiAqaXRvYQoJY29uY2F0Cglsb2cKCippZjI1X2VuZDoKCippZjI0X2VuZDoKCS8vICppZjI2X2NvbmRpdGlvbgoJLy8gY29udHJhY3RzL3N0YWtpbmdQb29sLmFsZ28udHM6NTk1CgkvLyB0b2tlblJld2FyZEF2YWlsID09PSAwCglmcmFtZV9kaWcgMTMgLy8gdG9rZW5SZXdhcmRBdmFpbDogdWludDY0CglpbnQgMAoJPT0KCWJ6ICppZjI2X2VuZAoKCS8vICppZjI2X2NvbnNlcXVlbnQKCS8vIGNvbnRyYWN0cy9zdGFraW5nUG9vbC5hbGdvLnRzOjU5OAoJLy8gYXNzZXJ0KGFsZ29SZXdhcmRBdmFpbCA+IDFfMDAwXzAwMCwgJ1Jld2FyZCBuZWVkcyB0byBiZSBhdCBsZWFzdCAxIEFMR08nKQoJZnJhbWVfZGlnIDEwIC8vIGFsZ29SZXdhcmRBdmFpbDogdWludDY0CglpbnQgMV8wMDBfMDAwCgk+CgoJLy8gUmV3YXJkIG5lZWRzIHRvIGJlIGF0IGxlYXN0IDEgQUxHTwoJYXNzZXJ0CgoqaWYyNl9lbmQ6CgkvLyBjb250cmFjdHMvc3Rha2luZ1Bvb2wuYWxnby50czo2MDAKCS8vIGxvZyhjb25jYXQoJ2FsZ28gcmV3YXJkIGF2YWlsOiAnLCBhbGdvUmV3YXJkQXZhaWwudG9TdHJpbmcoKSkpCglieXRlIDB4NjE2YzY3NmYyMDcyNjU3NzYxNzI2NDIwNjE3NjYxNjk2YzNhMjAgLy8gImFsZ28gcmV3YXJkIGF2YWlsOiAiCglmcmFtZV9kaWcgMTAgLy8gYWxnb1Jld2FyZEF2YWlsOiB1aW50NjQKCWNhbGxzdWIgKml0b2EKCWNvbmNhdAoJbG9nCgoJLy8gKmlmMjdfY29uZGl0aW9uCgkvLyBjb250cmFjdHMvc3Rha2luZ1Bvb2wuYWxnby50czo2MDMKCS8vIGlzUG9vbFNhdHVyYXRlZAoJZnJhbWVfZGlnIDExIC8vIGlzUG9vbFNhdHVyYXRlZDogYm9vbAoJYnogKmlmMjdfZWxzZWlmMV9jb25kaXRpb24KCgkvLyAqaWYyN19jb25zZXF1ZW50CgkvLyBjb250cmFjdHMvc3Rha2luZ1Bvb2wuYWxnby50czo2MDYKCS8vIGRpbWluaXNoZWRSZXdhcmQgPSB3aWRlUmF0aW8oW2FsZ29SZXdhcmRBdmFpbCwgYWxnb1NhdHVyYXRpb25BbXRdLCBbdmFsaWRhdG9yU3RhdGUudG90YWxBbGdvU3Rha2VkXSkKCWZyYW1lX2RpZyAxMCAvLyBhbGdvUmV3YXJkQXZhaWw6IHVpbnQ2NAoJZnJhbWVfZGlnIDEyIC8vIGFsZ29TYXR1cmF0aW9uQW10OiB1aW50NjQKCW11bHcKCWludCAwCglmcmFtZV9kaWcgOCAvLyB2YWxpZGF0b3JTdGF0ZTogKHVpbnQxNix1aW50NjQsdWludDY0LHVpbnQ2NCkKCWV4dHJhY3QgMTAgOAoJYnRvaQoJZGl2bW9kdwoJcG9wCglwb3AKCXN3YXAKCSEKCWFzc2VydAoJZnJhbWVfYnVyeSAxNyAvLyBkaW1pbmlzaGVkUmV3YXJkOiB1aW50NjQKCgkvLyBjb250cmFjdHMvc3Rha2luZ1Bvb2wuYWxnby50czo2MDgKCS8vIGV4Y2Vzc1RvRmVlU2luayA9IGFsZ29SZXdhcmRBdmFpbCAtIGRpbWluaXNoZWRSZXdhcmQKCWZyYW1lX2RpZyAxMCAvLyBhbGdvUmV3YXJkQXZhaWw6IHVpbnQ2NAoJZnJhbWVfZGlnIDE3IC8vIGRpbWluaXNoZWRSZXdhcmQ6IHVpbnQ2NAoJLQoJZnJhbWVfYnVyeSAxOCAvLyBleGNlc3NUb0ZlZVNpbms6IHVpbnQ2NAoKCS8vIGNvbnRyYWN0cy9zdGFraW5nUG9vbC5hbGdvLnRzOjYwOQoJLy8gaW5jcmVhc2VPcGNvZGVCdWRnZXQoKQoJaXR4bl9iZWdpbgoJaW50IGFwcGwKCWl0eG5fZmllbGQgVHlwZUVudW0KCWludCAwCglpdHhuX2ZpZWxkIEZlZQoJYnl0ZSBiNjQgQ29FQiAvLyAjcHJhZ21hIHZlcnNpb24gMTA7IGludCAxCglkdXAKCWl0eG5fZmllbGQgQXBwcm92YWxQcm9ncmFtCglpdHhuX2ZpZWxkIENsZWFyU3RhdGVQcm9ncmFtCglpbnQgRGVsZXRlQXBwbGljYXRpb24KCWl0eG5fZmllbGQgT25Db21wbGV0aW9uCglpdHhuX3N1Ym1pdAoKCS8vIGNvbnRyYWN0cy9zdGFraW5nUG9vbC5hbGdvLnRzOjYxMAoJLy8gbG9nKGNvbmNhdCgnZGltIHJ3ZDogJywgZGltaW5pc2hlZFJld2FyZC50b1N0cmluZygpKSkKCWJ5dGUgMHg2NDY5NmQyMDcyNzc2NDNhMjAgLy8gImRpbSByd2Q6ICIKCWZyYW1lX2RpZyAxNyAvLyBkaW1pbmlzaGVkUmV3YXJkOiB1aW50NjQKCWNhbGxzdWIgKml0b2EKCWNvbmNhdAoJbG9nCgoJLy8gY29udHJhY3RzL3N0YWtpbmdQb29sLmFsZ28udHM6NjExCgkvLyBsb2coY29uY2F0KCd0byBzaW5rOiAnLCBleGNlc3NUb0ZlZVNpbmsudG9TdHJpbmcoKSkpCglieXRlIDB4NzQ2ZjIwNzM2OTZlNmIzYTIwIC8vICJ0byBzaW5rOiAiCglmcmFtZV9kaWcgMTggLy8gZXhjZXNzVG9GZWVTaW5rOiB1aW50NjQKCWNhbGxzdWIgKml0b2EKCWNvbmNhdAoJbG9nCgoJLy8gY29udHJhY3RzL3N0YWtpbmdQb29sLmFsZ28udHM6NjEyCgkvLyBzZW5kUGF5bWVudCh7CgkvLyAgICAgICAgICAgICAgICAgYW1vdW50OiBleGNlc3NUb0ZlZVNpbmssCgkvLyAgICAgICAgICAgICAgICAgcmVjZWl2ZXI6IHRoaXMuZ2V0RmVlU2luaygpLAoJLy8gICAgICAgICAgICAgICAgIG5vdGU6ICdwb29sIHNhdHVyYXRlZCwgcG9ydGlvbiBzZW50IGJhY2sgdG8gZmVlIHNpbmsnLAoJLy8gICAgICAgICAgICAgfSkKCWl0eG5fYmVnaW4KCWludCBwYXkKCWl0eG5fZmllbGQgVHlwZUVudW0KCgkvLyBjb250cmFjdHMvc3Rha2luZ1Bvb2wuYWxnby50czo2MTMKCS8vIGFtb3VudDogZXhjZXNzVG9GZWVTaW5rCglmcmFtZV9kaWcgMTggLy8gZXhjZXNzVG9GZWVTaW5rOiB1aW50NjQKCWl0eG5fZmllbGQgQW1vdW50CgoJLy8gY29udHJhY3RzL3N0YWtpbmdQb29sLmFsZ28udHM6NjE0CgkvLyByZWNlaXZlcjogdGhpcy5nZXRGZWVTaW5rKCkKCWNhbGxzdWIgZ2V0RmVlU2luawoJaXR4bl9maWVsZCBSZWNlaXZlcgoKCS8vIGNvbnRyYWN0cy9zdGFraW5nUG9vbC5hbGdvLnRzOjYxNQoJLy8gbm90ZTogJ3Bvb2wgc2F0dXJhdGVkLCBwb3J0aW9uIHNlbnQgYmFjayB0byBmZWUgc2luaycKCWJ5dGUgMHg3MDZmNmY2YzIwNzM2MTc0NzU3MjYxNzQ2NTY0MmMyMDcwNmY3Mjc0Njk2ZjZlMjA3MzY1NmU3NDIwNjI2MTYzNmIyMDc0NmYyMDY2NjU2NTIwNzM2OTZlNmIgLy8gInBvb2wgc2F0dXJhdGVkLCBwb3J0aW9uIHNlbnQgYmFjayB0byBmZWUgc2luayIKCWl0eG5fZmllbGQgTm90ZQoKCS8vIEZlZSBmaWVsZCBub3Qgc2V0LCBkZWZhdWx0aW5nIHRvIDAKCWludCAwCglpdHhuX2ZpZWxkIEZlZQoKCS8vIFN1Ym1pdCBpbm5lciB0cmFuc2FjdGlvbgoJaXR4bl9zdWJtaXQKCgkvLyBjb250cmFjdHMvc3Rha2luZ1Bvb2wuYWxnby50czo2MTgKCS8vIGFsZ29SZXdhcmRBdmFpbCA9IGRpbWluaXNoZWRSZXdhcmQKCWZyYW1lX2RpZyAxNyAvLyBkaW1pbmlzaGVkUmV3YXJkOiB1aW50NjQKCWZyYW1lX2J1cnkgMTAgLy8gYWxnb1Jld2FyZEF2YWlsOiB1aW50NjQKCWIgKmlmMjdfZW5kCgoqaWYyN19lbHNlaWYxX2NvbmRpdGlvbjoKCS8vIGNvbnRyYWN0cy9zdGFraW5nUG9vbC5hbGdvLnRzOjYxOQoJLy8gdmFsaWRhdG9yQ29uZmlnLnBlcmNlbnRUb1ZhbGlkYXRvciAhPT0gMAoJZnJhbWVfZGlnIDAgLy8gdmFsaWRhdG9yQ29uZmlnOiAodWludDY0LGFkZHJlc3MsYWRkcmVzcyx1aW50NjQsdWludDgsYnl0ZVszMl0sdWludDY0LHVpbnQ2NCx1aW50NjQsdWludDE2LHVpbnQzMixhZGRyZXNzLHVpbnQ2NCx1aW50NjQsdWludDgsdWludDY0LHVpbnQ2NCkKCWV4dHJhY3QgMTM5IDQKCWJ0b2kKCWludCAwCgkhPQoJYnogKmlmMjdfZW5kCgoJLy8gKmlmMjdfZWxzZWlmMV9jb25zZXF1ZW50CgkvLyBjb250cmFjdHMvc3Rha2luZ1Bvb2wuYWxnby50czo2MjIKCS8vIHZhbGlkYXRvclBheSA9IHdpZGVSYXRpbygKCS8vICAgICAgICAgICAgICAgICBbYWxnb1Jld2FyZEF2YWlsLCB2YWxpZGF0b3JDb25maWcucGVyY2VudFRvVmFsaWRhdG9yIGFzIHVpbnQ2NF0sCgkvLyAgICAgICAgICAgICAgICAgWzFfMDAwXzAwMF0KCS8vICAgICAgICAgICAgICkKCWZyYW1lX2RpZyAxMCAvLyBhbGdvUmV3YXJkQXZhaWw6IHVpbnQ2NAoJZnJhbWVfZGlnIDAgLy8gdmFsaWRhdG9yQ29uZmlnOiAodWludDY0LGFkZHJlc3MsYWRkcmVzcyx1aW50NjQsdWludDgsYnl0ZVszMl0sdWludDY0LHVpbnQ2NCx1aW50NjQsdWludDE2LHVpbnQzMixhZGRyZXNzLHVpbnQ2NCx1aW50NjQsdWludDgsdWludDY0LHVpbnQ2NCkKCWV4dHJhY3QgMTM5IDQKCWJ0b2kKCW11bHcKCWludCAwCglpbnQgMV8wMDBfMDAwCglkaXZtb2R3Cglwb3AKCXBvcAoJc3dhcAoJIQoJYXNzZXJ0CglmcmFtZV9idXJ5IDE5IC8vIHZhbGlkYXRvclBheTogdWludDY0CgoJLy8gY29udHJhY3RzL3N0YWtpbmdQb29sLmFsZ28udHM6NjI4CgkvLyBhbGdvUmV3YXJkQXZhaWwgLT0gdmFsaWRhdG9yUGF5CglmcmFtZV9kaWcgMTAgLy8gYWxnb1Jld2FyZEF2YWlsOiB1aW50NjQKCWZyYW1lX2RpZyAxOSAvLyB2YWxpZGF0b3JQYXk6IHVpbnQ2NAoJLQoJZnJhbWVfYnVyeSAxMCAvLyBhbGdvUmV3YXJkQXZhaWw6IHVpbnQ2NAoKCS8vICppZjI4X2NvbmRpdGlvbgoJLy8gY29udHJhY3RzL3N0YWtpbmdQb29sLmFsZ28udHM6NjMyCgkvLyB2YWxpZGF0b3JQYXkgPiAwCglmcmFtZV9kaWcgMTkgLy8gdmFsaWRhdG9yUGF5OiB1aW50NjQKCWludCAwCgk+CglieiAqaWYyOF9lbmQKCgkvLyAqaWYyOF9jb25zZXF1ZW50CgkvLyBjb250cmFjdHMvc3Rha2luZ1Bvb2wuYWxnby50czo2MzMKCS8vIGxvZyhjb25jYXQoJ3BheWluZyB2YWxpZGF0b3I6ICVpJywgaXRvYih2YWxpZGF0b3JQYXkpKSkKCWJ5dGUgMHg3MDYxNzk2OTZlNjcyMDc2NjE2YzY5NjQ2MTc0NmY3MjNhMjAyNTY5IC8vICJwYXlpbmcgdmFsaWRhdG9yOiAlaSIKCWZyYW1lX2RpZyAxOSAvLyB2YWxpZGF0b3JQYXk6IHVpbnQ2NAoJaXRvYgoJY29uY2F0Cglsb2cKCgkvLyBjb250cmFjdHMvc3Rha2luZ1Bvb2wuYWxnby50czo2MzQKCS8vIHNlbmRQYXltZW50KHsKCS8vICAgICAgICAgICAgICAgICAgICAgYW1vdW50OiB2YWxpZGF0b3JQYXksCgkvLyAgICAgICAgICAgICAgICAgICAgIHJlY2VpdmVyOiB2YWxpZGF0b3JDb25maWcudmFsaWRhdG9yQ29tbWlzc2lvbkFkZHJlc3MsCgkvLyAgICAgICAgICAgICAgICAgICAgIG5vdGU6ICd2YWxpZGF0b3IgcmV3YXJkJywKCS8vICAgICAgICAgICAgICAgICB9KQoJaXR4bl9iZWdpbgoJaW50IHBheQoJaXR4bl9maWVsZCBUeXBlRW51bQoKCS8vIGNvbnRyYWN0cy9zdGFraW5nUG9vbC5hbGdvLnRzOjYzNQoJLy8gYW1vdW50OiB2YWxpZGF0b3JQYXkKCWZyYW1lX2RpZyAxOSAvLyB2YWxpZGF0b3JQYXk6IHVpbnQ2NAoJaXR4bl9maWVsZCBBbW91bnQKCgkvLyBjb250cmFjdHMvc3Rha2luZ1Bvb2wuYWxnby50czo2MzYKCS8vIHJlY2VpdmVyOiB2YWxpZGF0b3JDb25maWcudmFsaWRhdG9yQ29tbWlzc2lvbkFkZHJlc3MKCWZyYW1lX2RpZyAwIC8vIHZhbGlkYXRvckNvbmZpZzogKHVpbnQ2NCxhZGRyZXNzLGFkZHJlc3MsdWludDY0LHVpbnQ4LGJ5dGVbMzJdLHVpbnQ2NCx1aW50NjQsdWludDY0LHVpbnQxNix1aW50MzIsYWRkcmVzcyx1aW50NjQsdWludDY0LHVpbnQ4LHVpbnQ2NCx1aW50NjQpCglleHRyYWN0IDE0MyAzMgoJaXR4bl9maWVsZCBSZWNlaXZlcgoKCS8vIGNvbnRyYWN0cy9zdGFraW5nUG9vbC5hbGdvLnRzOjYzNwoJLy8gbm90ZTogJ3ZhbGlkYXRvciByZXdhcmQnCglieXRlIDB4NzY2MTZjNjk2NDYxNzQ2ZjcyMjA3MjY1Nzc2MTcyNjQgLy8gInZhbGlkYXRvciByZXdhcmQiCglpdHhuX2ZpZWxkIE5vdGUKCgkvLyBGZWUgZmllbGQgbm90IHNldCwgZGVmYXVsdGluZyB0byAwCglpbnQgMAoJaXR4bl9maWVsZCBGZWUKCgkvLyBTdWJtaXQgaW5uZXIgdHJhbnNhY3Rpb24KCWl0eG5fc3VibWl0CgoJLy8gY29udHJhY3RzL3N0YWtpbmdQb29sLmFsZ28udHM6NjM5CgkvLyBsb2coY29uY2F0KCdyZW1haW5pbmcgcmV3YXJkOiAlaScsIGl0b2IoYWxnb1Jld2FyZEF2YWlsKSkpCglieXRlIDB4NzI2NTZkNjE2OTZlNjk2ZTY3MjA3MjY1Nzc2MTcyNjQzYTIwMjU2OSAvLyAicmVtYWluaW5nIHJld2FyZDogJWkiCglmcmFtZV9kaWcgMTAgLy8gYWxnb1Jld2FyZEF2YWlsOiB1aW50NjQKCWl0b2IKCWNvbmNhdAoJbG9nCgoqaWYyOF9lbmQ6CgoqaWYyN19lbmQ6CgkvLyAqaWYyOV9jb25kaXRpb24KCS8vIGNvbnRyYWN0cy9zdGFraW5nUG9vbC5hbGdvLnRzOjY0MwoJLy8gYWxnb1Jld2FyZEF2YWlsID09PSAwICYmIHRva2VuUmV3YXJkQXZhaWwgPT09IDAKCWZyYW1lX2RpZyAxMCAvLyBhbGdvUmV3YXJkQXZhaWw6IHVpbnQ2NAoJaW50IDAKCT09CglkdXAKCWJ6ICpza2lwX2FuZDMKCWZyYW1lX2RpZyAxMyAvLyB0b2tlblJld2FyZEF2YWlsOiB1aW50NjQKCWludCAwCgk9PQoJJiYKCipza2lwX2FuZDM6CglieiAqaWYyOV9lbmQKCgkvLyAqaWYyOV9jb25zZXF1ZW50CgkvLyBjb250cmFjdHMvc3Rha2luZ1Bvb2wuYWxnby50czo2NDYKCS8vIHJldHVybjsKCXJldHN1YgoKKmlmMjlfZW5kOgoJLy8gY29udHJhY3RzL3N0YWtpbmdQb29sLmFsZ28udHM6NjU0CgkvLyBpbmNyZWFzZWRTdGFrZSA9IDAKCWludCAwCglmcmFtZV9idXJ5IDIwIC8vIGluY3JlYXNlZFN0YWtlOiB1aW50NjQKCgkvLyBjb250cmFjdHMvc3Rha2luZ1Bvb2wuYWxnby50czo2NzgKCS8vIHBhcnRpYWxTdGFrZXJzVG90YWxTdGFrZTogdWludDY0ID0gMAoJaW50IDAKCWZyYW1lX2J1cnkgMjEgLy8gcGFydGlhbFN0YWtlcnNUb3RhbFN0YWtlOiB1aW50NjQKCgkvLyBjb250cmFjdHMvc3Rha2luZ1Bvb2wuYWxnby50czo2NzkKCS8vIGZvciAobGV0IGkgPSAwOyBpIDwgdGhpcy5zdGFrZXJzLnZhbHVlLmxlbmd0aDsgaSArPSAxKQoJaW50IDAKCWZyYW1lX2J1cnkgMjIgLy8gaTogdWludDY0CgoqZm9yXzQ6CgkvLyBjb250cmFjdHMvc3Rha2luZ1Bvb2wuYWxnby50czo2NzkKCS8vIGkgPCB0aGlzLnN0YWtlcnMudmFsdWUubGVuZ3RoCglmcmFtZV9kaWcgMjIgLy8gaTogdWludDY0CglpbnQgMjAwCgk8CglieiAqZm9yXzRfZW5kCgoJLy8gKmlmMzBfY29uZGl0aW9uCgkvLyBjb250cmFjdHMvc3Rha2luZ1Bvb2wuYWxnby50czo2ODAKCS8vIGdsb2JhbHMub3Bjb2RlQnVkZ2V0IDwgNDAwCglnbG9iYWwgT3Bjb2RlQnVkZ2V0CglpbnQgNDAwCgk8CglieiAqaWYzMF9lbmQKCgkvLyAqaWYzMF9jb25zZXF1ZW50CgkvLyBjb250cmFjdHMvc3Rha2luZ1Bvb2wuYWxnby50czo2ODEKCS8vIGluY3JlYXNlT3Bjb2RlQnVkZ2V0KCkKCWl0eG5fYmVnaW4KCWludCBhcHBsCglpdHhuX2ZpZWxkIFR5cGVFbnVtCglpbnQgMAoJaXR4bl9maWVsZCBGZWUKCWJ5dGUgYjY0IENvRUIgLy8gI3ByYWdtYSB2ZXJzaW9uIDEwOyBpbnQgMQoJZHVwCglpdHhuX2ZpZWxkIEFwcHJvdmFsUHJvZ3JhbQoJaXR4bl9maWVsZCBDbGVhclN0YXRlUHJvZ3JhbQoJaW50IERlbGV0ZUFwcGxpY2F0aW9uCglpdHhuX2ZpZWxkIE9uQ29tcGxldGlvbgoJaXR4bl9zdWJtaXQKCippZjMwX2VuZDoKCS8vIGNvbnRyYWN0cy9zdGFraW5nUG9vbC5hbGdvLnRzOjY4MwoJLy8gY21wU3Rha2VyID0gY2xvbmUodGhpcy5zdGFrZXJzLnZhbHVlW2ldKQoJZnJhbWVfZGlnIDIyIC8vIGk6IHVpbnQ2NAoJaW50IDY0CgkqIC8vIGFjYyAqIHR5cGVMZW5ndGgKCWludCA2NAoJYnl0ZSAweDczNzQ2MTZiNjU3MjczIC8vICJzdGFrZXJzIgoJY292ZXIgMgoJYm94X2V4dHJhY3QKCWZyYW1lX2J1cnkgMjMgLy8gY21wU3Rha2VyOiAoYWRkcmVzcyx1aW50NjQsdWludDY0LHVpbnQ2NCx1aW50NjQpCgoJLy8gKmlmMzFfY29uZGl0aW9uCgkvLyBjb250cmFjdHMvc3Rha2luZ1Bvb2wuYWxnby50czo2ODQKCS8vIGNtcFN0YWtlci5hY2NvdW50ICE9PSBnbG9iYWxzLnplcm9BZGRyZXNzCglmcmFtZV9kaWcgMjMgLy8gY21wU3Rha2VyOiAoYWRkcmVzcyx1aW50NjQsdWludDY0LHVpbnQ2NCx1aW50NjQpCglleHRyYWN0IDAgMzIKCWdsb2JhbCBaZXJvQWRkcmVzcwoJIT0KCWJ6ICppZjMxX2VuZAoKCS8vICppZjMxX2NvbnNlcXVlbnQKCS8vICppZjMyX2NvbmRpdGlvbgoJLy8gY29udHJhY3RzL3N0YWtpbmdQb29sLmFsZ28udHM6Njg1CgkvLyBjbXBTdGFrZXIuZW50cnlUaW1lID4gY3VyVGltZQoJZnJhbWVfZGlnIDIzIC8vIGNtcFN0YWtlcjogKGFkZHJlc3MsdWludDY0LHVpbnQ2NCx1aW50NjQsdWludDY0KQoJZXh0cmFjdCA1NiA4CglidG9pCglmcmFtZV9kaWcgMSAvLyBjdXJUaW1lOiB1aW50NjQKCT4KCWJ6ICppZjMyX2Vsc2UKCgkvLyAqaWYzMl9jb25zZXF1ZW50CgkvLyBjb250cmFjdHMvc3Rha2luZ1Bvb2wuYWxnby50czo2ODgKCS8vIHBhcnRpYWxTdGFrZXJzVG90YWxTdGFrZSArPSBjbXBTdGFrZXIuYmFsYW5jZQoJZnJhbWVfZGlnIDIxIC8vIHBhcnRpYWxTdGFrZXJzVG90YWxTdGFrZTogdWludDY0CglmcmFtZV9kaWcgMjMgLy8gY21wU3Rha2VyOiAoYWRkcmVzcyx1aW50NjQsdWludDY0LHVpbnQ2NCx1aW50NjQpCglleHRyYWN0IDMyIDgKCWJ0b2kKCSsKCWZyYW1lX2J1cnkgMjEgLy8gcGFydGlhbFN0YWtlcnNUb3RhbFN0YWtlOiB1aW50NjQKCWIgKmlmMzJfZW5kCgoqaWYzMl9lbHNlOgoJLy8gY29udHJhY3RzL3N0YWtpbmdQb29sLmFsZ28udHM6NjkyCgkvLyB0aW1lSW5Qb29sID0gY3VyVGltZSAtIGNtcFN0YWtlci5lbnRyeVRpbWUKCWZyYW1lX2RpZyAxIC8vIGN1clRpbWU6IHVpbnQ2NAoJZnJhbWVfZGlnIDIzIC8vIGNtcFN0YWtlcjogKGFkZHJlc3MsdWludDY0LHVpbnQ2NCx1aW50NjQsdWludDY0KQoJZXh0cmFjdCA1NiA4CglidG9pCgktCglmcmFtZV9idXJ5IDI0IC8vIHRpbWVJblBvb2w6IHVpbnQ2NAoKCS8vICppZjMzX2NvbmRpdGlvbgoJLy8gY29udHJhY3RzL3N0YWtpbmdQb29sLmFsZ28udHM6Njk2CgkvLyB0aW1lSW5Qb29sIDwgZXBvY2hJblNlY3MKCWZyYW1lX2RpZyAyNCAvLyB0aW1lSW5Qb29sOiB1aW50NjQKCWZyYW1lX2RpZyAyIC8vIGVwb2NoSW5TZWNzOiB1aW50NjQKCTwKCWJ6ICppZjMzX2VuZAoKCS8vICppZjMzX2NvbnNlcXVlbnQKCS8vIGNvbnRyYWN0cy9zdGFraW5nUG9vbC5hbGdvLnRzOjY5NwoJLy8gcGFydGlhbFN0YWtlcnNUb3RhbFN0YWtlICs9IGNtcFN0YWtlci5iYWxhbmNlCglmcmFtZV9kaWcgMjEgLy8gcGFydGlhbFN0YWtlcnNUb3RhbFN0YWtlOiB1aW50NjQKCWZyYW1lX2RpZyAyMyAvLyBjbXBTdGFrZXI6IChhZGRyZXNzLHVpbnQ2NCx1aW50NjQsdWludDY0LHVpbnQ2NCkKCWV4dHJhY3QgMzIgOAoJYnRvaQoJKwoJZnJhbWVfYnVyeSAyMSAvLyBwYXJ0aWFsU3Rha2Vyc1RvdGFsU3Rha2U6IHVpbnQ2NAoKCS8vIGNvbnRyYWN0cy9zdGFraW5nUG9vbC5hbGdvLnRzOjY5OAoJLy8gdGltZVBlcmNlbnRhZ2UgPSAodGltZUluUG9vbCAqIDEwMDApIC8gZXBvY2hJblNlY3MKCWZyYW1lX2RpZyAyNCAvLyB0aW1lSW5Qb29sOiB1aW50NjQKCWludCAxMDAwCgkqCglmcmFtZV9kaWcgMiAvLyBlcG9jaEluU2VjczogdWludDY0CgkvCglmcmFtZV9idXJ5IDI1IC8vIHRpbWVQZXJjZW50YWdlOiB1aW50NjQKCgkvLyAqaWYzNF9jb25kaXRpb24KCS8vIGNvbnRyYWN0cy9zdGFraW5nUG9vbC5hbGdvLnRzOjcwMQoJLy8gdG9rZW5SZXdhcmRBdmFpbCA+IDAKCWZyYW1lX2RpZyAxMyAvLyB0b2tlblJld2FyZEF2YWlsOiB1aW50NjQKCWludCAwCgk+CglieiAqaWYzNF9lbmQKCgkvLyAqaWYzNF9jb25zZXF1ZW50CgkvLyBjb250cmFjdHMvc3Rha2luZ1Bvb2wuYWxnby50czo3MDMKCS8vIHN0YWtlclRva2VuUmV3YXJkID0gd2lkZVJhdGlvKAoJLy8gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBbY21wU3Rha2VyLmJhbGFuY2UsIHRva2VuUmV3YXJkQXZhaWwsIHRpbWVQZXJjZW50YWdlXSwKCS8vICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgW3RoaXMudG90YWxBbGdvU3Rha2VkLnZhbHVlLCAxMDAwXQoJLy8gICAgICAgICAgICAgICAgICAgICAgICAgICAgICkKCWZyYW1lX2RpZyAyMyAvLyBjbXBTdGFrZXI6IChhZGRyZXNzLHVpbnQ2NCx1aW50NjQsdWludDY0LHVpbnQ2NCkKCWV4dHJhY3QgMzIgOAoJYnRvaQoJZnJhbWVfZGlnIDEzIC8vIHRva2VuUmV3YXJkQXZhaWw6IHVpbnQ2NAoJbXVsdwoJZnJhbWVfZGlnIDI1IC8vIHRpbWVQZXJjZW50YWdlOiB1aW50NjQKCXVuY292ZXIgMgoJZGlnIDEKCSoKCWNvdmVyIDIKCW11bHcKCWNvdmVyIDIKCSsKCXN3YXAKCWJ5dGUgMHg3Mzc0NjE2YjY1NjQgLy8gInN0YWtlZCIKCWFwcF9nbG9iYWxfZ2V0CglpbnQgMTAwMAoJbXVsdwoJZGl2bW9kdwoJcG9wCglwb3AKCXN3YXAKCSEKCWFzc2VydAoJZnJhbWVfYnVyeSAyNiAvLyBzdGFrZXJUb2tlblJld2FyZDogdWludDY0CgoJLy8gY29udHJhY3RzL3N0YWtpbmdQb29sLmFsZ28udHM6NzEwCgkvLyB0b2tlblJld2FyZEF2YWlsIC09IHN0YWtlclRva2VuUmV3YXJkCglmcmFtZV9kaWcgMTMgLy8gdG9rZW5SZXdhcmRBdmFpbDogdWludDY0CglmcmFtZV9kaWcgMjYgLy8gc3Rha2VyVG9rZW5SZXdhcmQ6IHVpbnQ2NAoJLQoJZnJhbWVfYnVyeSAxMyAvLyB0b2tlblJld2FyZEF2YWlsOiB1aW50NjQKCgkvLyBjb250cmFjdHMvc3Rha2luZ1Bvb2wuYWxnby50czo3MTEKCS8vIGNtcFN0YWtlci5yZXdhcmRUb2tlbkJhbGFuY2UgKz0gc3Rha2VyVG9rZW5SZXdhcmQKCWZyYW1lX2RpZyAyMyAvLyBjbXBTdGFrZXI6IChhZGRyZXNzLHVpbnQ2NCx1aW50NjQsdWludDY0LHVpbnQ2NCkKCWludCA0OCAvLyBoZWFkT2Zmc2V0CglmcmFtZV9kaWcgMjMgLy8gY21wU3Rha2VyOiAoYWRkcmVzcyx1aW50NjQsdWludDY0LHVpbnQ2NCx1aW50NjQpCglleHRyYWN0IDQ4IDgKCWJ0b2kKCWZyYW1lX2RpZyAyNiAvLyBzdGFrZXJUb2tlblJld2FyZDogdWludDY0CgkrCglpdG9iCglyZXBsYWNlMwoJZnJhbWVfYnVyeSAyMyAvLyBjbXBTdGFrZXI6IChhZGRyZXNzLHVpbnQ2NCx1aW50NjQsdWludDY0LHVpbnQ2NCkKCgkvLyBjb250cmFjdHMvc3Rha2luZ1Bvb2wuYWxnby50czo3MTIKCS8vIHRva2VuUmV3YXJkUGFpZE91dCArPSBzdGFrZXJUb2tlblJld2FyZAoJZnJhbWVfZGlnIDE0IC8vIHRva2VuUmV3YXJkUGFpZE91dDogdWludDY0CglmcmFtZV9kaWcgMjYgLy8gc3Rha2VyVG9rZW5SZXdhcmQ6IHVpbnQ2NAoJKwoJZnJhbWVfYnVyeSAxNCAvLyB0b2tlblJld2FyZFBhaWRPdXQ6IHVpbnQ2NAoKKmlmMzRfZW5kOgoJLy8gKmlmMzVfY29uZGl0aW9uCgkvLyBjb250cmFjdHMvc3Rha2luZ1Bvb2wuYWxnby50czo3MTQKCS8vIGFsZ29SZXdhcmRBdmFpbCA+IDAKCWZyYW1lX2RpZyAxMCAvLyBhbGdvUmV3YXJkQXZhaWw6IHVpbnQ2NAoJaW50IDAKCT4KCWJ6ICppZjM1X2VuZAoKCS8vICppZjM1X2NvbnNlcXVlbnQKCS8vIGNvbnRyYWN0cy9zdGFraW5nUG9vbC5hbGdvLnRzOjcxNgoJLy8gc3Rha2VyUmV3YXJkID0gd2lkZVJhdGlvKAoJLy8gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBbY21wU3Rha2VyLmJhbGFuY2UsIGFsZ29SZXdhcmRBdmFpbCwgdGltZVBlcmNlbnRhZ2VdLAoJLy8gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBbdGhpcy50b3RhbEFsZ29TdGFrZWQudmFsdWUsIDEwMDBdCgkvLyAgICAgICAgICAgICAgICAgICAgICAgICAgICAgKQoJZnJhbWVfZGlnIDIzIC8vIGNtcFN0YWtlcjogKGFkZHJlc3MsdWludDY0LHVpbnQ2NCx1aW50NjQsdWludDY0KQoJZXh0cmFjdCAzMiA4CglidG9pCglmcmFtZV9kaWcgMTAgLy8gYWxnb1Jld2FyZEF2YWlsOiB1aW50NjQKCW11bHcKCWZyYW1lX2RpZyAyNSAvLyB0aW1lUGVyY2VudGFnZTogdWludDY0Cgl1bmNvdmVyIDIKCWRpZyAxCgkqCgljb3ZlciAyCgltdWx3Cgljb3ZlciAyCgkrCglzd2FwCglieXRlIDB4NzM3NDYxNmI2NTY0IC8vICJzdGFrZWQiCglhcHBfZ2xvYmFsX2dldAoJaW50IDEwMDAKCW11bHcKCWRpdm1vZHcKCXBvcAoJcG9wCglzd2FwCgkhCglhc3NlcnQKCWZyYW1lX2J1cnkgMjcgLy8gc3Rha2VyUmV3YXJkOiB1aW50NjQKCgkvLyBjb250cmFjdHMvc3Rha2luZ1Bvb2wuYWxnby50czo3MjMKCS8vIGFsZ29SZXdhcmRBdmFpbCAtPSBzdGFrZXJSZXdhcmQKCWZyYW1lX2RpZyAxMCAvLyBhbGdvUmV3YXJkQXZhaWw6IHVpbnQ2NAoJZnJhbWVfZGlnIDI3IC8vIHN0YWtlclJld2FyZDogdWludDY0CgktCglmcmFtZV9idXJ5IDEwIC8vIGFsZ29SZXdhcmRBdmFpbDogdWludDY0CgoJLy8gY29udHJhY3RzL3N0YWtpbmdQb29sLmFsZ28udHM6NzI2CgkvLyBjbXBTdGFrZXIuYmFsYW5jZSArPSBzdGFrZXJSZXdhcmQKCWZyYW1lX2RpZyAyMyAvLyBjbXBTdGFrZXI6IChhZGRyZXNzLHVpbnQ2NCx1aW50NjQsdWludDY0LHVpbnQ2NCkKCWludCAzMiAvLyBoZWFkT2Zmc2V0CglmcmFtZV9kaWcgMjMgLy8gY21wU3Rha2VyOiAoYWRkcmVzcyx1aW50NjQsdWludDY0LHVpbnQ2NCx1aW50NjQpCglleHRyYWN0IDMyIDgKCWJ0b2kKCWZyYW1lX2RpZyAyNyAvLyBzdGFrZXJSZXdhcmQ6IHVpbnQ2NAoJKwoJaXRvYgoJcmVwbGFjZTMKCWZyYW1lX2J1cnkgMjMgLy8gY21wU3Rha2VyOiAoYWRkcmVzcyx1aW50NjQsdWludDY0LHVpbnQ2NCx1aW50NjQpCgoJLy8gY29udHJhY3RzL3N0YWtpbmdQb29sLmFsZ28udHM6NzI3CgkvLyBjbXBTdGFrZXIudG90YWxSZXdhcmRlZCArPSBzdGFrZXJSZXdhcmQKCWZyYW1lX2RpZyAyMyAvLyBjbXBTdGFrZXI6IChhZGRyZXNzLHVpbnQ2NCx1aW50NjQsdWludDY0LHVpbnQ2NCkKCWludCA0MCAvLyBoZWFkT2Zmc2V0CglmcmFtZV9kaWcgMjMgLy8gY21wU3Rha2VyOiAoYWRkcmVzcyx1aW50NjQsdWludDY0LHVpbnQ2NCx1aW50NjQpCglleHRyYWN0IDQwIDgKCWJ0b2kKCWZyYW1lX2RpZyAyNyAvLyBzdGFrZXJSZXdhcmQ6IHVpbnQ2NAoJKwoJaXRvYgoJcmVwbGFjZTMKCWZyYW1lX2J1cnkgMjMgLy8gY21wU3Rha2VyOiAoYWRkcmVzcyx1aW50NjQsdWludDY0LHVpbnQ2NCx1aW50NjQpCgoJLy8gY29udHJhY3RzL3N0YWtpbmdQb29sLmFsZ28udHM6NzI4CgkvLyBpbmNyZWFzZWRTdGFrZSArPSBzdGFrZXJSZXdhcmQKCWZyYW1lX2RpZyAyMCAvLyBpbmNyZWFzZWRTdGFrZTogdWludDY0CglmcmFtZV9kaWcgMjcgLy8gc3Rha2VyUmV3YXJkOiB1aW50NjQKCSsKCWZyYW1lX2J1cnkgMjAgLy8gaW5jcmVhc2VkU3Rha2U6IHVpbnQ2NAoKKmlmMzVfZW5kOgoJLy8gY29udHJhY3RzL3N0YWtpbmdQb29sLmFsZ28udHM6NzMxCgkvLyB0aGlzLnN0YWtlcnMudmFsdWVbaV0gPSBjbXBTdGFrZXIKCWZyYW1lX2RpZyAyMiAvLyBpOiB1aW50NjQKCWludCA2NAoJKiAvLyBhY2MgKiB0eXBlTGVuZ3RoCglmcmFtZV9kaWcgMjMgLy8gY21wU3Rha2VyOiAoYWRkcmVzcyx1aW50NjQsdWludDY0LHVpbnQ2NCx1aW50NjQpCglieXRlIDB4NzM3NDYxNmI2NTcyNzMgLy8gInN0YWtlcnMiCgljb3ZlciAyCglib3hfcmVwbGFjZQoKKmlmMzNfZW5kOgoKKmlmMzJfZW5kOgoKKmlmMzFfZW5kOgoKKmZvcl80X2NvbnRpbnVlOgoJLy8gY29udHJhY3RzL3N0YWtpbmdQb29sLmFsZ28udHM6Njc5CgkvLyBpICs9IDEKCWZyYW1lX2RpZyAyMiAvLyBpOiB1aW50NjQKCWludCAxCgkrCglmcmFtZV9idXJ5IDIyIC8vIGk6IHVpbnQ2NAoJYiAqZm9yXzQKCipmb3JfNF9lbmQ6CgkvLyBjb250cmFjdHMvc3Rha2luZ1Bvb2wuYWxnby50czo3MzYKCS8vIGxvZyhjb25jYXQoJ3BhcnRpYWwgc3Rha2VyIHRvdGFsIHN0YWtlOiAlaScsIGl0b2IocGFydGlhbFN0YWtlcnNUb3RhbFN0YWtlKSkpCglieXRlIDB4NzA2MTcyNzQ2OTYxNmMyMDczNzQ2MTZiNjU3MjIwNzQ2Zjc0NjE2YzIwNzM3NDYxNmI2NTNhMjAyNTY5IC8vICJwYXJ0aWFsIHN0YWtlciB0b3RhbCBzdGFrZTogJWkiCglmcmFtZV9kaWcgMjEgLy8gcGFydGlhbFN0YWtlcnNUb3RhbFN0YWtlOiB1aW50NjQKCWl0b2IKCWNvbmNhdAoJbG9nCgoJLy8gY29udHJhY3RzL3N0YWtpbmdQb29sLmFsZ28udHM6NzQwCgkvLyBuZXdQb29sVG90YWxTdGFrZSA9IHRoaXMudG90YWxBbGdvU3Rha2VkLnZhbHVlIC0gcGFydGlhbFN0YWtlcnNUb3RhbFN0YWtlCglieXRlIDB4NzM3NDYxNmI2NTY0IC8vICJzdGFrZWQiCglhcHBfZ2xvYmFsX2dldAoJZnJhbWVfZGlnIDIxIC8vIHBhcnRpYWxTdGFrZXJzVG90YWxTdGFrZTogdWludDY0CgktCglmcmFtZV9idXJ5IDI4IC8vIG5ld1Bvb2xUb3RhbFN0YWtlOiB1aW50NjQKCgkvLyAqaWYzNl9jb25kaXRpb24KCS8vIGNvbnRyYWN0cy9zdGFraW5nUG9vbC5hbGdvLnRzOjc0NAoJLy8gbmV3UG9vbFRvdGFsU3Rha2UgPiAwCglmcmFtZV9kaWcgMjggLy8gbmV3UG9vbFRvdGFsU3Rha2U6IHVpbnQ2NAoJaW50IDAKCT4KCWJ6ICppZjM2X2VuZAoKCS8vICppZjM2X2NvbnNlcXVlbnQKCS8vIGNvbnRyYWN0cy9zdGFraW5nUG9vbC5hbGdvLnRzOjc0NgoJLy8gZm9yIChsZXQgaSA9IDA7IGkgPCB0aGlzLnN0YWtlcnMudmFsdWUubGVuZ3RoOyBpICs9IDEpCglpbnQgMAoJZnJhbWVfYnVyeSAyOSAvLyBpOiB1aW50NjQKCipmb3JfNToKCS8vIGNvbnRyYWN0cy9zdGFraW5nUG9vbC5hbGdvLnRzOjc0NgoJLy8gaSA8IHRoaXMuc3Rha2Vycy52YWx1ZS5sZW5ndGgKCWZyYW1lX2RpZyAyOSAvLyBpOiB1aW50NjQKCWludCAyMDAKCTwKCWJ6ICpmb3JfNV9lbmQKCgkvLyAqaWYzN19jb25kaXRpb24KCS8vIGNvbnRyYWN0cy9zdGFraW5nUG9vbC5hbGdvLnRzOjc0NwoJLy8gZ2xvYmFscy5vcGNvZGVCdWRnZXQgPCAyMDAKCWdsb2JhbCBPcGNvZGVCdWRnZXQKCWludCAyMDAKCTwKCWJ6ICppZjM3X2VuZAoKCS8vICppZjM3X2NvbnNlcXVlbnQKCS8vIGNvbnRyYWN0cy9zdGFraW5nUG9vbC5hbGdvLnRzOjc0OAoJLy8gaW5jcmVhc2VPcGNvZGVCdWRnZXQoKQoJaXR4bl9iZWdpbgoJaW50IGFwcGwKCWl0eG5fZmllbGQgVHlwZUVudW0KCWludCAwCglpdHhuX2ZpZWxkIEZlZQoJYnl0ZSBiNjQgQ29FQiAvLyAjcHJhZ21hIHZlcnNpb24gMTA7IGludCAxCglkdXAKCWl0eG5fZmllbGQgQXBwcm92YWxQcm9ncmFtCglpdHhuX2ZpZWxkIENsZWFyU3RhdGVQcm9ncmFtCglpbnQgRGVsZXRlQXBwbGljYXRpb24KCWl0eG5fZmllbGQgT25Db21wbGV0aW9uCglpdHhuX3N1Ym1pdAoKKmlmMzdfZW5kOgoJLy8gY29udHJhY3RzL3N0YWtpbmdQb29sLmFsZ28udHM6NzUwCgkvLyBjbXBTdGFrZXIgPSBjbG9uZSh0aGlzLnN0YWtlcnMudmFsdWVbaV0pCglmcmFtZV9kaWcgMjkgLy8gaTogdWludDY0CglpbnQgNjQKCSogLy8gYWNjICogdHlwZUxlbmd0aAoJaW50IDY0CglieXRlIDB4NzM3NDYxNmI2NTcyNzMgLy8gInN0YWtlcnMiCgljb3ZlciAyCglib3hfZXh0cmFjdAoJZnJhbWVfYnVyeSAzMCAvLyBjbXBTdGFrZXI6IChhZGRyZXNzLHVpbnQ2NCx1aW50NjQsdWludDY0LHVpbnQ2NCkKCgkvLyAqaWYzOF9jb25kaXRpb24KCS8vIGNvbnRyYWN0cy9zdGFraW5nUG9vbC5hbGdvLnRzOjc1MQoJLy8gY21wU3Rha2VyLmFjY291bnQgIT09IGdsb2JhbHMuemVyb0FkZHJlc3MgJiYgY21wU3Rha2VyLmVudHJ5VGltZSA8IGN1clRpbWUKCWZyYW1lX2RpZyAzMCAvLyBjbXBTdGFrZXI6IChhZGRyZXNzLHVpbnQ2NCx1aW50NjQsdWludDY0LHVpbnQ2NCkKCWV4dHJhY3QgMCAzMgoJZ2xvYmFsIFplcm9BZGRyZXNzCgkhPQoJZHVwCglieiAqc2tpcF9hbmQ0CglmcmFtZV9kaWcgMzAgLy8gY21wU3Rha2VyOiAoYWRkcmVzcyx1aW50NjQsdWludDY0LHVpbnQ2NCx1aW50NjQpCglleHRyYWN0IDU2IDgKCWJ0b2kKCWZyYW1lX2RpZyAxIC8vIGN1clRpbWU6IHVpbnQ2NAoJPAoJJiYKCipza2lwX2FuZDQ6CglieiAqaWYzOF9lbmQKCgkvLyAqaWYzOF9jb25zZXF1ZW50CgkvLyBjb250cmFjdHMvc3Rha2luZ1Bvb2wuYWxnby50czo3NTIKCS8vIHRpbWVJblBvb2wgPSBjdXJUaW1lIC0gY21wU3Rha2VyLmVudHJ5VGltZQoJZnJhbWVfZGlnIDEgLy8gY3VyVGltZTogdWludDY0CglmcmFtZV9kaWcgMzAgLy8gY21wU3Rha2VyOiAoYWRkcmVzcyx1aW50NjQsdWludDY0LHVpbnQ2NCx1aW50NjQpCglleHRyYWN0IDU2IDgKCWJ0b2kKCS0KCWZyYW1lX2J1cnkgMzEgLy8gdGltZUluUG9vbDogdWludDY0CgoJLy8gKmlmMzlfY29uZGl0aW9uCgkvLyBjb250cmFjdHMvc3Rha2luZ1Bvb2wuYWxnby50czo3NTQKCS8vIHRpbWVJblBvb2wgPj0gZXBvY2hJblNlY3MKCWZyYW1lX2RpZyAzMSAvLyB0aW1lSW5Qb29sOiB1aW50NjQKCWZyYW1lX2RpZyAyIC8vIGVwb2NoSW5TZWNzOiB1aW50NjQKCT49CglieiAqaWYzOV9lbmQKCgkvLyAqaWYzOV9jb25zZXF1ZW50CgkvLyAqaWY0MF9jb25kaXRpb24KCS8vIGNvbnRyYWN0cy9zdGFraW5nUG9vbC5hbGdvLnRzOjc1OQoJLy8gdG9rZW5SZXdhcmRBdmFpbCA+IDAKCWZyYW1lX2RpZyAxMyAvLyB0b2tlblJld2FyZEF2YWlsOiB1aW50NjQKCWludCAwCgk+CglieiAqaWY0MF9lbmQKCgkvLyAqaWY0MF9jb25zZXF1ZW50CgkvLyBjb250cmFjdHMvc3Rha2luZ1Bvb2wuYWxnby50czo3NjYKCS8vIHN0YWtlclRva2VuUmV3YXJkID0gd2lkZVJhdGlvKAoJLy8gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBbY21wU3Rha2VyLmJhbGFuY2UsIHRva2VuUmV3YXJkQXZhaWxdLAoJLy8gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBbbmV3UG9vbFRvdGFsU3Rha2VdCgkvLyAgICAgICAgICAgICAgICAgICAgICAgICAgICAgKQoJZnJhbWVfZGlnIDMwIC8vIGNtcFN0YWtlcjogKGFkZHJlc3MsdWludDY0LHVpbnQ2NCx1aW50NjQsdWludDY0KQoJZXh0cmFjdCAzMiA4CglidG9pCglmcmFtZV9kaWcgMTMgLy8gdG9rZW5SZXdhcmRBdmFpbDogdWludDY0CgltdWx3CglpbnQgMAoJZnJhbWVfZGlnIDI4IC8vIG5ld1Bvb2xUb3RhbFN0YWtlOiB1aW50NjQKCWRpdm1vZHcKCXBvcAoJcG9wCglzd2FwCgkhCglhc3NlcnQKCWZyYW1lX2J1cnkgMzIgLy8gc3Rha2VyVG9rZW5SZXdhcmQ6IHVpbnQ2NAoKCS8vIGNvbnRyYWN0cy9zdGFraW5nUG9vbC5hbGdvLnRzOjc3NQoJLy8gY21wU3Rha2VyLnJld2FyZFRva2VuQmFsYW5jZSArPSBzdGFrZXJUb2tlblJld2FyZAoJZnJhbWVfZGlnIDMwIC8vIGNtcFN0YWtlcjogKGFkZHJlc3MsdWludDY0LHVpbnQ2NCx1aW50NjQsdWludDY0KQoJaW50IDQ4IC8vIGhlYWRPZmZzZXQKCWZyYW1lX2RpZyAzMCAvLyBjbXBTdGFrZXI6IChhZGRyZXNzLHVpbnQ2NCx1aW50NjQsdWludDY0LHVpbnQ2NCkKCWV4dHJhY3QgNDggOAoJYnRvaQoJZnJhbWVfZGlnIDMyIC8vIHN0YWtlclRva2VuUmV3YXJkOiB1aW50NjQKCSsKCWl0b2IKCXJlcGxhY2UzCglmcmFtZV9idXJ5IDMwIC8vIGNtcFN0YWtlcjogKGFkZHJlc3MsdWludDY0LHVpbnQ2NCx1aW50NjQsdWludDY0KQoKCS8vIGNvbnRyYWN0cy9zdGFraW5nUG9vbC5hbGdvLnRzOjc3NgoJLy8gdG9rZW5SZXdhcmRQYWlkT3V0ICs9IHN0YWtlclRva2VuUmV3YXJkCglmcmFtZV9kaWcgMTQgLy8gdG9rZW5SZXdhcmRQYWlkT3V0OiB1aW50NjQKCWZyYW1lX2RpZyAzMiAvLyBzdGFrZXJUb2tlblJld2FyZDogdWludDY0CgkrCglmcmFtZV9idXJ5IDE0IC8vIHRva2VuUmV3YXJkUGFpZE91dDogdWludDY0CgoqaWY0MF9lbmQ6CgkvLyAqaWY0MV9jb25kaXRpb24KCS8vIGNvbnRyYWN0cy9zdGFraW5nUG9vbC5hbGdvLnRzOjc3OAoJLy8gYWxnb1Jld2FyZEF2YWlsID4gMAoJZnJhbWVfZGlnIDEwIC8vIGFsZ29SZXdhcmRBdmFpbDogdWludDY0CglpbnQgMAoJPgoJYnogKmlmNDFfZW5kCgoJLy8gKmlmNDFfY29uc2VxdWVudAoJLy8gY29udHJhY3RzL3N0YWtpbmdQb29sLmFsZ28udHM6Nzc5CgkvLyBzdGFrZXJSZXdhcmQgPSB3aWRlUmF0aW8oW2NtcFN0YWtlci5iYWxhbmNlLCBhbGdvUmV3YXJkQXZhaWxdLCBbbmV3UG9vbFRvdGFsU3Rha2VdKQoJZnJhbWVfZGlnIDMwIC8vIGNtcFN0YWtlcjogKGFkZHJlc3MsdWludDY0LHVpbnQ2NCx1aW50NjQsdWludDY0KQoJZXh0cmFjdCAzMiA4CglidG9pCglmcmFtZV9kaWcgMTAgLy8gYWxnb1Jld2FyZEF2YWlsOiB1aW50NjQKCW11bHcKCWludCAwCglmcmFtZV9kaWcgMjggLy8gbmV3UG9vbFRvdGFsU3Rha2U6IHVpbnQ2NAoJZGl2bW9kdwoJcG9wCglwb3AKCXN3YXAKCSEKCWFzc2VydAoJZnJhbWVfYnVyeSAzMyAvLyBzdGFrZXJSZXdhcmQ6IHVpbnQ2NAoKCS8vIGNvbnRyYWN0cy9zdGFraW5nUG9vbC5hbGdvLnRzOjc4MgoJLy8gY21wU3Rha2VyLmJhbGFuY2UgKz0gc3Rha2VyUmV3YXJkCglmcmFtZV9kaWcgMzAgLy8gY21wU3Rha2VyOiAoYWRkcmVzcyx1aW50NjQsdWludDY0LHVpbnQ2NCx1aW50NjQpCglpbnQgMzIgLy8gaGVhZE9mZnNldAoJZnJhbWVfZGlnIDMwIC8vIGNtcFN0YWtlcjogKGFkZHJlc3MsdWludDY0LHVpbnQ2NCx1aW50NjQsdWludDY0KQoJZXh0cmFjdCAzMiA4CglidG9pCglmcmFtZV9kaWcgMzMgLy8gc3Rha2VyUmV3YXJkOiB1aW50NjQKCSsKCWl0b2IKCXJlcGxhY2UzCglmcmFtZV9idXJ5IDMwIC8vIGNtcFN0YWtlcjogKGFkZHJlc3MsdWludDY0LHVpbnQ2NCx1aW50NjQsdWludDY0KQoKCS8vIGNvbnRyYWN0cy9zdGFraW5nUG9vbC5hbGdvLnRzOjc4MwoJLy8gY21wU3Rha2VyLnRvdGFsUmV3YXJkZWQgKz0gc3Rha2VyUmV3YXJkCglmcmFtZV9kaWcgMzAgLy8gY21wU3Rha2VyOiAoYWRkcmVzcyx1aW50NjQsdWludDY0LHVpbnQ2NCx1aW50NjQpCglpbnQgNDAgLy8gaGVhZE9mZnNldAoJZnJhbWVfZGlnIDMwIC8vIGNtcFN0YWtlcjogKGFkZHJlc3MsdWludDY0LHVpbnQ2NCx1aW50NjQsdWludDY0KQoJZXh0cmFjdCA0MCA4CglidG9pCglmcmFtZV9kaWcgMzMgLy8gc3Rha2VyUmV3YXJkOiB1aW50NjQKCSsKCWl0b2IKCXJlcGxhY2UzCglmcmFtZV9idXJ5IDMwIC8vIGNtcFN0YWtlcjogKGFkZHJlc3MsdWludDY0LHVpbnQ2NCx1aW50NjQsdWludDY0KQoKCS8vIGNvbnRyYWN0cy9zdGFraW5nUG9vbC5hbGdvLnRzOjc4NAoJLy8gaW5jcmVhc2VkU3Rha2UgKz0gc3Rha2VyUmV3YXJkCglmcmFtZV9kaWcgMjAgLy8gaW5jcmVhc2VkU3Rha2U6IHVpbnQ2NAoJZnJhbWVfZGlnIDMzIC8vIHN0YWtlclJld2FyZDogdWludDY0CgkrCglmcmFtZV9idXJ5IDIwIC8vIGluY3JlYXNlZFN0YWtlOiB1aW50NjQKCippZjQxX2VuZDoKCS8vIGNvbnRyYWN0cy9zdGFraW5nUG9vbC5hbGdvLnRzOjc4OAoJLy8gdGhpcy5zdGFrZXJzLnZhbHVlW2ldID0gY21wU3Rha2VyCglmcmFtZV9kaWcgMjkgLy8gaTogdWludDY0CglpbnQgNjQKCSogLy8gYWNjICogdHlwZUxlbmd0aAoJZnJhbWVfZGlnIDMwIC8vIGNtcFN0YWtlcjogKGFkZHJlc3MsdWludDY0LHVpbnQ2NCx1aW50NjQsdWludDY0KQoJYnl0ZSAweDczNzQ2MTZiNjU3MjczIC8vICJzdGFrZXJzIgoJY292ZXIgMgoJYm94X3JlcGxhY2UKCippZjM5X2VuZDoKCippZjM4X2VuZDoKCipmb3JfNV9jb250aW51ZToKCS8vIGNvbnRyYWN0cy9zdGFraW5nUG9vbC5hbGdvLnRzOjc0NgoJLy8gaSArPSAxCglmcmFtZV9kaWcgMjkgLy8gaTogdWludDY0CglpbnQgMQoJKwoJZnJhbWVfYnVyeSAyOSAvLyBpOiB1aW50NjQKCWIgKmZvcl81CgoqZm9yXzVfZW5kOgoKKmlmMzZfZW5kOgoJLy8gY29udHJhY3RzL3N0YWtpbmdQb29sLmFsZ28udHM6Nzk2CgkvLyB0aGlzLnRvdGFsQWxnb1N0YWtlZC52YWx1ZSArPSBpbmNyZWFzZWRTdGFrZQoJYnl0ZSAweDczNzQ2MTZiNjU2NCAvLyAic3Rha2VkIgoJYXBwX2dsb2JhbF9nZXQKCWZyYW1lX2RpZyAyMCAvLyBpbmNyZWFzZWRTdGFrZTogdWludDY0CgkrCglieXRlIDB4NzM3NDYxNmI2NTY0IC8vICJzdGFrZWQiCglzd2FwCglhcHBfZ2xvYmFsX3B1dAoKCS8vIGNvbnRyYWN0cy9zdGFraW5nUG9vbC5hbGdvLnRzOjc5OAoJLy8gbG9nKGNvbmNhdCgnaW5jciBzdGFrZTogJWknLCBpdG9iKGluY3JlYXNlZFN0YWtlKSkpCglieXRlIDB4Njk2ZTYzNzIyMDczNzQ2MTZiNjUzYTIwMjU2OSAvLyAiaW5jciBzdGFrZTogJWkiCglmcmFtZV9kaWcgMjAgLy8gaW5jcmVhc2VkU3Rha2U6IHVpbnQ2NAoJaXRvYgoJY29uY2F0Cglsb2cKCgkvLyBjb250cmFjdHMvc3Rha2luZ1Bvb2wuYWxnby50czo3OTkKCS8vIGxvZyhjb25jYXQoJ3Rvay4gcndkIHBhaWQ6ICVpJywgaXRvYih0b2tlblJld2FyZFBhaWRPdXQpKSkKCWJ5dGUgMHg3NDZmNmIyZTIwNzI3NzY0MjA3MDYxNjk2NDNhMjAyNTY5IC8vICJ0b2suIHJ3ZCBwYWlkOiAlaSIKCWZyYW1lX2RpZyAxNCAvLyB0b2tlblJld2FyZFBhaWRPdXQ6IHVpbnQ2NAoJaXRvYgoJY29uY2F0Cglsb2cKCgkvLyBjb250cmFjdHMvc3Rha2luZ1Bvb2wuYWxnby50czo4MDQKCS8vIHNlbmRNZXRob2RDYWxsPHR5cGVvZiBWYWxpZGF0b3JSZWdpc3RyeS5wcm90b3R5cGUuc3Rha2VVcGRhdGVkVmlhUmV3YXJkcz4oewoJLy8gICAgICAgICAgICAgYXBwbGljYXRpb25JRDogQXBwSUQuZnJvbVVpbnQ2NCh0aGlzLmNyZWF0aW5nVmFsaWRhdG9yQ29udHJhY3RBcHBJZC52YWx1ZSksCgkvLyAgICAgICAgICAgICBtZXRob2RBcmdzOiBbCgkvLyAgICAgICAgICAgICAgICAgeyBpZDogdGhpcy52YWxpZGF0b3JJZC52YWx1ZSwgcG9vbElkOiB0aGlzLnBvb2xJZC52YWx1ZSwgcG9vbEFwcElkOiB0aGlzLmFwcC5pZCB9LAoJLy8gICAgICAgICAgICAgICAgIGluY3JlYXNlZFN0YWtlLAoJLy8gICAgICAgICAgICAgICAgIHRva2VuUmV3YXJkUGFpZE91dCwKCS8vICAgICAgICAgICAgIF0sCgkvLyAgICAgICAgIH0pCglpdHhuX2JlZ2luCglpbnQgYXBwbAoJaXR4bl9maWVsZCBUeXBlRW51bQoJbWV0aG9kICJzdGFrZVVwZGF0ZWRWaWFSZXdhcmRzKCh1aW50NjQsdWludDY0LHVpbnQ2NCksdWludDY0LHVpbnQ2NCl2b2lkIgoJaXR4bl9maWVsZCBBcHBsaWNhdGlvbkFyZ3MKCgkvLyBjb250cmFjdHMvc3Rha2luZ1Bvb2wuYWxnby50czo4MDUKCS8vIGFwcGxpY2F0aW9uSUQ6IEFwcElELmZyb21VaW50NjQodGhpcy5jcmVhdGluZ1ZhbGlkYXRvckNvbnRyYWN0QXBwSWQudmFsdWUpCglieXRlIDB4NjM3MjY1NjE3NDZmNzI0MTcwNzAgLy8gImNyZWF0b3JBcHAiCglhcHBfZ2xvYmFsX2dldAoJaXR4bl9maWVsZCBBcHBsaWNhdGlvbklECgoJLy8gY29udHJhY3RzL3N0YWtpbmdQb29sLmFsZ28udHM6ODA2CgkvLyBtZXRob2RBcmdzOiBbCgkvLyAgICAgICAgICAgICAgICAgeyBpZDogdGhpcy52YWxpZGF0b3JJZC52YWx1ZSwgcG9vbElkOiB0aGlzLnBvb2xJZC52YWx1ZSwgcG9vbEFwcElkOiB0aGlzLmFwcC5pZCB9LAoJLy8gICAgICAgICAgICAgICAgIGluY3JlYXNlZFN0YWtlLAoJLy8gICAgICAgICAgICAgICAgIHRva2VuUmV3YXJkUGFpZE91dCwKCS8vICAgICAgICAgICAgIF0KCWJ5dGUgMHg3NjYxNmM2OTY0NjE3NDZmNzI0OTY0IC8vICJ2YWxpZGF0b3JJZCIKCWFwcF9nbG9iYWxfZ2V0CglpdG9iCglieXRlIDB4NzA2ZjZmNmM0OTY0IC8vICJwb29sSWQiCglhcHBfZ2xvYmFsX2dldAoJaXRvYgoJY29uY2F0Cgl0eG5hIEFwcGxpY2F0aW9ucyAwCglpdG9iCgljb25jYXQKCWl0eG5fZmllbGQgQXBwbGljYXRpb25BcmdzCglmcmFtZV9kaWcgMjAgLy8gaW5jcmVhc2VkU3Rha2U6IHVpbnQ2NAoJaXRvYgoJaXR4bl9maWVsZCBBcHBsaWNhdGlvbkFyZ3MKCWZyYW1lX2RpZyAxNCAvLyB0b2tlblJld2FyZFBhaWRPdXQ6IHVpbnQ2NAoJaXRvYgoJaXR4bl9maWVsZCBBcHBsaWNhdGlvbkFyZ3MKCgkvLyBGZWUgZmllbGQgbm90IHNldCwgZGVmYXVsdGluZyB0byAwCglpbnQgMAoJaXR4bl9maWVsZCBGZWUKCgkvLyBTdWJtaXQgaW5uZXIgdHJhbnNhY3Rpb24KCWl0eG5fc3VibWl0CglyZXRzdWIKCi8vIGdvT25saW5lKGJ5dGVbXSxieXRlW10sYnl0ZVtdLHVpbnQ2NCx1aW50NjQsdWludDY0KXZvaWQKKmFiaV9yb3V0ZV9nb09ubGluZToKCS8vIHZvdGVLZXlEaWx1dGlvbjogdWludDY0Cgl0eG5hIEFwcGxpY2F0aW9uQXJncyA2CglidG9pCgoJLy8gdm90ZUxhc3Q6IHVpbnQ2NAoJdHhuYSBBcHBsaWNhdGlvbkFyZ3MgNQoJYnRvaQoKCS8vIHZvdGVGaXJzdDogdWludDY0Cgl0eG5hIEFwcGxpY2F0aW9uQXJncyA0CglidG9pCgoJLy8gc3RhdGVQcm9vZlBLOiBieXRlW10KCXR4bmEgQXBwbGljYXRpb25BcmdzIDMKCWV4dHJhY3QgMiAwCgoJLy8gc2VsZWN0aW9uUEs6IGJ5dGVbXQoJdHhuYSBBcHBsaWNhdGlvbkFyZ3MgMgoJZXh0cmFjdCAyIDAKCgkvLyB2b3RlUEs6IGJ5dGVbXQoJdHhuYSBBcHBsaWNhdGlvbkFyZ3MgMQoJZXh0cmFjdCAyIDAKCgkvLyBleGVjdXRlIGdvT25saW5lKGJ5dGVbXSxieXRlW10sYnl0ZVtdLHVpbnQ2NCx1aW50NjQsdWludDY0KXZvaWQKCWNhbGxzdWIgZ29PbmxpbmUKCWludCAxCglyZXR1cm4KCi8vIGdvT25saW5lKHZvdGVQSzogYnl0ZXMsIHNlbGVjdGlvblBLOiBieXRlcywgc3RhdGVQcm9vZlBLOiBieXRlcywgdm90ZUZpcnN0OiB1aW50NjQsIHZvdGVMYXN0OiB1aW50NjQsIHZvdGVLZXlEaWx1dGlvbjogdWludDY0KTogdm9pZAovLwovLyBSZWdpc3RlcnMgYSBzdGFraW5nIHBvb2wga2V5IG9ubGluZSBhZ2FpbnN0IGEgcGFydGljaXBhdGlvbiBrZXkuCi8vIFsgT05MWSBPV05FUiBPUiBNQU5BR0VSIENBTiBDQUxMIF0KLy8KLy8gQHBhcmFtIHtieXRlc30gdm90ZVBLIC0gVGhlIHZvdGUgcHVibGljIGtleS4KLy8gQHBhcmFtIHtieXRlc30gc2VsZWN0aW9uUEsgLSBUaGUgc2VsZWN0aW9uIHB1YmxpYyBrZXkuCi8vIEBwYXJhbSB7Ynl0ZXN9IHN0YXRlUHJvb2ZQSyAtIFRoZSBzdGF0ZSBwcm9vZiBwdWJsaWMga2V5LgovLyBAcGFyYW0ge3VpbnQ2NH0gdm90ZUZpcnN0IC0gVGhlIGZpcnN0IHZvdGUgaW5kZXguCi8vIEBwYXJhbSB7dWludDY0fSB2b3RlTGFzdCAtIFRoZSBsYXN0IHZvdGUgaW5kZXguCi8vIEBwYXJhbSB7dWludDY0fSB2b3RlS2V5RGlsdXRpb24gLSBUaGUgdm90ZSBrZXkgZGlsdXRpb24gdmFsdWUuCi8vIEB0aHJvd3Mge0Vycm9yfSBXaWxsIHRocm93IGFuIGVycm9yIGlmIHRoZSBjYWxsZXIgaXMgbm90IHRoZSBvd25lciBvciBhIG1hbmFnZXIuCmdvT25saW5lOgoJcHJvdG8gNiAwCgoJLy8gY29udHJhY3RzL3N0YWtpbmdQb29sLmFsZ28udHM6ODM0CgkvLyBhc3NlcnQodGhpcy5pc093bmVyT3JNYW5hZ2VyQ2FsbGVyKCkpCgljYWxsc3ViIGlzT3duZXJPck1hbmFnZXJDYWxsZXIKCWFzc2VydAoKCS8vIGNvbnRyYWN0cy9zdGFraW5nUG9vbC5hbGdvLnRzOjgzNQoJLy8gc2VuZE9ubGluZUtleVJlZ2lzdHJhdGlvbih7CgkvLyAgICAgICAgICAgICB2b3RlUEs6IHZvdGVQSywKCS8vICAgICAgICAgICAgIHNlbGVjdGlvblBLOiBzZWxlY3Rpb25QSywKCS8vICAgICAgICAgICAgIHN0YXRlUHJvb2ZQSzogc3RhdGVQcm9vZlBLLAoJLy8gICAgICAgICAgICAgdm90ZUZpcnN0OiB2b3RlRmlyc3QsCgkvLyAgICAgICAgICAgICB2b3RlTGFzdDogdm90ZUxhc3QsCgkvLyAgICAgICAgICAgICB2b3RlS2V5RGlsdXRpb246IHZvdGVLZXlEaWx1dGlvbiwKCS8vICAgICAgICAgfSkKCWl0eG5fYmVnaW4KCWludCBrZXlyZWcKCWl0eG5fZmllbGQgVHlwZUVudW0KCgkvLyBjb250cmFjdHMvc3Rha2luZ1Bvb2wuYWxnby50czo4MzYKCS8vIHZvdGVQSzogdm90ZVBLCglmcmFtZV9kaWcgLTEgLy8gdm90ZVBLOiBieXRlcwoJaXR4bl9maWVsZCBWb3RlUEsKCgkvLyBjb250cmFjdHMvc3Rha2luZ1Bvb2wuYWxnby50czo4MzcKCS8vIHNlbGVjdGlvblBLOiBzZWxlY3Rpb25QSwoJZnJhbWVfZGlnIC0yIC8vIHNlbGVjdGlvblBLOiBieXRlcwoJaXR4bl9maWVsZCBTZWxlY3Rpb25QSwoKCS8vIGNvbnRyYWN0cy9zdGFraW5nUG9vbC5hbGdvLnRzOjgzOAoJLy8gc3RhdGVQcm9vZlBLOiBzdGF0ZVByb29mUEsKCWZyYW1lX2RpZyAtMyAvLyBzdGF0ZVByb29mUEs6IGJ5dGVzCglpdHhuX2ZpZWxkIFN0YXRlUHJvb2ZQSwoKCS8vIGNvbnRyYWN0cy9zdGFraW5nUG9vbC5hbGdvLnRzOjgzOQoJLy8gdm90ZUZpcnN0OiB2b3RlRmlyc3QKCWZyYW1lX2RpZyAtNCAvLyB2b3RlRmlyc3Q6IHVpbnQ2NAoJaXR4bl9maWVsZCBWb3RlRmlyc3QKCgkvLyBjb250cmFjdHMvc3Rha2luZ1Bvb2wuYWxnby50czo4NDAKCS8vIHZvdGVMYXN0OiB2b3RlTGFzdAoJZnJhbWVfZGlnIC01IC8vIHZvdGVMYXN0OiB1aW50NjQKCWl0eG5fZmllbGQgVm90ZUxhc3QKCgkvLyBjb250cmFjdHMvc3Rha2luZ1Bvb2wuYWxnby50czo4NDEKCS8vIHZvdGVLZXlEaWx1dGlvbjogdm90ZUtleURpbHV0aW9uCglmcmFtZV9kaWcgLTYgLy8gdm90ZUtleURpbHV0aW9uOiB1aW50NjQKCWl0eG5fZmllbGQgVm90ZUtleURpbHV0aW9uCgoJLy8gRmVlIGZpZWxkIG5vdCBzZXQsIGRlZmF1bHRpbmcgdG8gMAoJaW50IDAKCWl0eG5fZmllbGQgRmVlCgoJLy8gU3VibWl0IGlubmVyIHRyYW5zYWN0aW9uCglpdHhuX3N1Ym1pdAoJcmV0c3ViCgovLyBnb09mZmxpbmUoKXZvaWQKKmFiaV9yb3V0ZV9nb09mZmxpbmU6CgkvLyBleGVjdXRlIGdvT2ZmbGluZSgpdm9pZAoJY2FsbHN1YiBnb09mZmxpbmUKCWludCAxCglyZXR1cm4KCi8vIGdvT2ZmbGluZSgpOiB2b2lkCi8vCi8vIE1hcmtzIGEgc3Rha2luZyBwb29sIGtleSBPRkZMSU5FLgovLyBbIE9OTFkgT1dORVIgT1IgTUFOQUdFUiBDQU4gQ0FMTCBdCmdvT2ZmbGluZToKCXByb3RvIDAgMAoKCS8vICppZjQyX2NvbmRpdGlvbgoJLy8gY29udHJhY3RzL3N0YWtpbmdQb29sLmFsZ28udHM6ODUzCgkvLyB0aGlzLnR4bi5zZW5kZXIgIT09IEFwcElELmZyb21VaW50NjQodGhpcy5jcmVhdGluZ1ZhbGlkYXRvckNvbnRyYWN0QXBwSWQudmFsdWUpLmFkZHJlc3MKCXR4biBTZW5kZXIKCWJ5dGUgMHg2MzcyNjU2MTc0NmY3MjQxNzA3MCAvLyAiY3JlYXRvckFwcCIKCWFwcF9nbG9iYWxfZ2V0CglhcHBfcGFyYW1zX2dldCBBcHBBZGRyZXNzCglwb3AKCSE9CglieiAqaWY0Ml9lbmQKCgkvLyAqaWY0Ml9jb25zZXF1ZW50CgkvLyBjb250cmFjdHMvc3Rha2luZ1Bvb2wuYWxnby50czo4NTQKCS8vIGFzc2VydCh0aGlzLmlzT3duZXJPck1hbmFnZXJDYWxsZXIoKSkKCWNhbGxzdWIgaXNPd25lck9yTWFuYWdlckNhbGxlcgoJYXNzZXJ0CgoqaWY0Ml9lbmQ6CgkvLyBjb250cmFjdHMvc3Rha2luZ1Bvb2wuYWxnby50czo4NTcKCS8vIHNlbmRPZmZsaW5lS2V5UmVnaXN0cmF0aW9uKHt9KQoJaXR4bl9iZWdpbgoJaW50IGtleXJlZwoJaXR4bl9maWVsZCBUeXBlRW51bQoKCS8vIEZlZSBmaWVsZCBub3Qgc2V0LCBkZWZhdWx0aW5nIHRvIDAKCWludCAwCglpdHhuX2ZpZWxkIEZlZQoKCS8vIFN1Ym1pdCBpbm5lciB0cmFuc2FjdGlvbgoJaXR4bl9zdWJtaXQKCXJldHN1YgoKLy8gbGlua1RvTkZEKHVpbnQ2NCxzdHJpbmcpdm9pZAoqYWJpX3JvdXRlX2xpbmtUb05GRDoKCS8vIG5mZE5hbWU6IHN0cmluZwoJdHhuYSBBcHBsaWNhdGlvbkFyZ3MgMgoJZXh0cmFjdCAyIDAKCgkvLyBuZmRBcHBJZDogdWludDY0Cgl0eG5hIEFwcGxpY2F0aW9uQXJncyAxCglidG9pCgoJLy8gZXhlY3V0ZSBsaW5rVG9ORkQodWludDY0LHN0cmluZyl2b2lkCgljYWxsc3ViIGxpbmtUb05GRAoJaW50IDEKCXJldHVybgoKLy8gbGlua1RvTkZEKG5mZEFwcElkOiB1aW50NjQsIG5mZE5hbWU6IHN0cmluZyk6IHZvaWQKbGlua1RvTkZEOgoJcHJvdG8gMiAwCgoJLy8gY29udHJhY3RzL3N0YWtpbmdQb29sLmFsZ28udHM6ODY0CgkvLyBhc3NlcnQodGhpcy5pc093bmVyT3JNYW5hZ2VyQ2FsbGVyKCkpCgljYWxsc3ViIGlzT3duZXJPck1hbmFnZXJDYWxsZXIKCWFzc2VydAoKCS8vIGNvbnRyYWN0cy9zdGFraW5nUG9vbC5hbGdvLnRzOjg2NgoJLy8gc2VuZEFwcENhbGwoewoJLy8gICAgICAgICAgICAgYXBwbGljYXRpb25JRDogQXBwSUQuZnJvbVVpbnQ2NCh0aGlzLm5mZFJlZ2lzdHJ5QXBwSWQpLAoJLy8gICAgICAgICAgICAgYXBwbGljYXRpb25BcmdzOiBbJ3ZlcmlmeV9uZmRfYWRkcicsIG5mZE5hbWUsIGl0b2IobmZkQXBwSWQpLCByYXdCeXRlcyh0aGlzLmFwcC5hZGRyZXNzKV0sCgkvLyAgICAgICAgICAgICBhcHBsaWNhdGlvbnM6IFtBcHBJRC5mcm9tVWludDY0KG5mZEFwcElkKV0sCgkvLyAgICAgICAgIH0pCglpdHhuX2JlZ2luCglpbnQgYXBwbAoJaXR4bl9maWVsZCBUeXBlRW51bQoKCS8vIGNvbnRyYWN0cy9zdGFraW5nUG9vbC5hbGdvLnRzOjg2NwoJLy8gYXBwbGljYXRpb25JRDogQXBwSUQuZnJvbVVpbnQ2NCh0aGlzLm5mZFJlZ2lzdHJ5QXBwSWQpCglwdXNoaW50IFRNUExfbmZkUmVnaXN0cnlBcHBJZAoJaXR4bl9maWVsZCBBcHBsaWNhdGlvbklECgoJLy8gY29udHJhY3RzL3N0YWtpbmdQb29sLmFsZ28udHM6ODY4CgkvLyBhcHBsaWNhdGlvbkFyZ3M6IFsndmVyaWZ5X25mZF9hZGRyJywgbmZkTmFtZSwgaXRvYihuZmRBcHBJZCksIHJhd0J5dGVzKHRoaXMuYXBwLmFkZHJlc3MpXQoJYnl0ZSAweDc2NjU3MjY5NjY3OTVmNmU2NjY0NWY2MTY0NjQ3MiAvLyAidmVyaWZ5X25mZF9hZGRyIgoJaXR4bl9maWVsZCBBcHBsaWNhdGlvbkFyZ3MKCWZyYW1lX2RpZyAtMiAvLyBuZmROYW1lOiBzdHJpbmcKCWl0eG5fZmllbGQgQXBwbGljYXRpb25BcmdzCglmcmFtZV9kaWcgLTEgLy8gbmZkQXBwSWQ6IHVpbnQ2NAoJaXRvYgoJaXR4bl9maWVsZCBBcHBsaWNhdGlvbkFyZ3MKCWdsb2JhbCBDdXJyZW50QXBwbGljYXRpb25BZGRyZXNzCglpdHhuX2ZpZWxkIEFwcGxpY2F0aW9uQXJncwoKCS8vIGNvbnRyYWN0cy9zdGFraW5nUG9vbC5hbGdvLnRzOjg2OQoJLy8gYXBwbGljYXRpb25zOiBbQXBwSUQuZnJvbVVpbnQ2NChuZmRBcHBJZCldCglmcmFtZV9kaWcgLTEgLy8gbmZkQXBwSWQ6IHVpbnQ2NAoJaXR4bl9maWVsZCBBcHBsaWNhdGlvbnMKCgkvLyBGZWUgZmllbGQgbm90IHNldCwgZGVmYXVsdGluZyB0byAwCglpbnQgMAoJaXR4bl9maWVsZCBGZWUKCgkvLyBTdWJtaXQgaW5uZXIgdHJhbnNhY3Rpb24KCWl0eG5fc3VibWl0CglyZXRzdWIKCi8vIHByb3hpZWRTZXRUb2tlblBheW91dFJhdGlvKCh1aW50NjQsdWludDY0LHVpbnQ2NCkpKHVpbnQ2NFsyNF0sdWludDY0KQoqYWJpX3JvdXRlX3Byb3hpZWRTZXRUb2tlblBheW91dFJhdGlvOgoJLy8gVGhlIEFCSSByZXR1cm4gcHJlZml4CglieXRlIDB4MTUxZjdjNzUKCgkvLyBwb29sS2V5OiAodWludDY0LHVpbnQ2NCx1aW50NjQpCgl0eG5hIEFwcGxpY2F0aW9uQXJncyAxCglkdXAKCWxlbgoJaW50IDI0Cgk9PQoJYXNzZXJ0CgoJLy8gZXhlY3V0ZSBwcm94aWVkU2V0VG9rZW5QYXlvdXRSYXRpbygodWludDY0LHVpbnQ2NCx1aW50NjQpKSh1aW50NjRbMjRdLHVpbnQ2NCkKCWNhbGxzdWIgcHJveGllZFNldFRva2VuUGF5b3V0UmF0aW8KCWNvbmNhdAoJbG9nCglpbnQgMQoJcmV0dXJuCgovLyBwcm94aWVkU2V0VG9rZW5QYXlvdXRSYXRpbyhwb29sS2V5OiBWYWxpZGF0b3JQb29sS2V5KTogUG9vbFRva2VuUGF5b3V0UmF0aW8KLy8KLy8gcHJveGllZFNldFRva2VuUGF5b3V0UmF0aW8gaXMgbWVhbnQgdG8gYmUgY2FsbGVkIGJ5IHBvb2xzICE9IDEgLSBjYWxsaW5nIFVTLCBwb29sICMxCi8vIFdlIG5lZWQgdG8gdmVyaWZ5IHRoYXQgd2UgYXJlIGluIGZhY3QgYmVpbmcgY2FsbGVkIGJ5IGFub3RoZXIgb2YgT1VSIHBvb2xzIChub3QgdXMpCi8vIGFuZCB0aGVuIHdlJ2xsIGNhbGwgdGhlIHZhbGlkYXRvciBvbiB0aGVpciBiZWhhbGYgdG8gdXBkYXRlIHRoZSB0b2tlbiBwYXlvdXRzCi8vIEBwYXJhbSBwb29sS2V5IC0gVmFsaWRhdG9yUG9vbEtleSB0dXBsZQpwcm94aWVkU2V0VG9rZW5QYXlvdXRSYXRpbzoKCXByb3RvIDEgMQoKCS8vIFB1c2ggZW1wdHkgYnl0ZXMgYWZ0ZXIgdGhlIGZyYW1lIHBvaW50ZXIgdG8gcmVzZXJ2ZSBzcGFjZSBmb3IgbG9jYWwgdmFyaWFibGVzCglieXRlIDB4CgoJLy8gY29udHJhY3RzL3N0YWtpbmdQb29sLmFsZ28udHM6ODgwCgkvLyBhc3NlcnQodGhpcy52YWxpZGF0b3JJZC52YWx1ZSA9PT0gcG9vbEtleS5pZCwgJ2NhbGxlciBtdXN0IGJlIHBhcnQgb2Ygc2FtZSB2YWxpZGF0b3Igc2V0IScpCglieXRlIDB4NzY2MTZjNjk2NDYxNzQ2ZjcyNDk2NCAvLyAidmFsaWRhdG9ySWQiCglhcHBfZ2xvYmFsX2dldAoJZnJhbWVfZGlnIC0xIC8vIHBvb2xLZXk6IFZhbGlkYXRvclBvb2xLZXkKCWV4dHJhY3QgMCA4CglidG9pCgk9PQoKCS8vIGNhbGxlciBtdXN0IGJlIHBhcnQgb2Ygc2FtZSB2YWxpZGF0b3Igc2V0IQoJYXNzZXJ0CgoJLy8gY29udHJhY3RzL3N0YWtpbmdQb29sLmFsZ28udHM6ODgxCgkvLyBhc3NlcnQodGhpcy5wb29sSWQudmFsdWUgPT09IDEsICdjYWxsZWUgbXVzdCBiZSBwb29sIDEnKQoJYnl0ZSAweDcwNmY2ZjZjNDk2NCAvLyAicG9vbElkIgoJYXBwX2dsb2JhbF9nZXQKCWludCAxCgk9PQoKCS8vIGNhbGxlZSBtdXN0IGJlIHBvb2wgMQoJYXNzZXJ0CgoJLy8gY29udHJhY3RzL3N0YWtpbmdQb29sLmFsZ28udHM6ODgyCgkvLyBhc3NlcnQocG9vbEtleS5wb29sSWQgIT09IDEsICdjYWxsZXIgbXVzdCBOT1QgYmUgcG9vbCAxJykKCWZyYW1lX2RpZyAtMSAvLyBwb29sS2V5OiBWYWxpZGF0b3JQb29sS2V5CglleHRyYWN0IDggOAoJYnRvaQoJaW50IDEKCSE9CgoJLy8gY2FsbGVyIG11c3QgTk9UIGJlIHBvb2wgMQoJYXNzZXJ0CgoJLy8gY29udHJhY3RzL3N0YWtpbmdQb29sLmFsZ28udHM6ODg0CgkvLyBjYWxsZXJQb29sQXBwSUQgPSBzZW5kTWV0aG9kQ2FsbDx0eXBlb2YgVmFsaWRhdG9yUmVnaXN0cnkucHJvdG90eXBlLmdldFBvb2xBcHBJZD4oewoJLy8gICAgICAgICAgICAgYXBwbGljYXRpb25JRDogQXBwSUQuZnJvbVVpbnQ2NCh0aGlzLmNyZWF0aW5nVmFsaWRhdG9yQ29udHJhY3RBcHBJZC52YWx1ZSksCgkvLyAgICAgICAgICAgICBtZXRob2RBcmdzOiBbcG9vbEtleS5pZCwgcG9vbEtleS5wb29sSWRdLAoJLy8gICAgICAgICB9KQoJaXR4bl9iZWdpbgoJaW50IGFwcGwKCWl0eG5fZmllbGQgVHlwZUVudW0KCW1ldGhvZCAiZ2V0UG9vbEFwcElkKHVpbnQ2NCx1aW50NjQpdWludDY0IgoJaXR4bl9maWVsZCBBcHBsaWNhdGlvbkFyZ3MKCgkvLyBjb250cmFjdHMvc3Rha2luZ1Bvb2wuYWxnby50czo4ODUKCS8vIGFwcGxpY2F0aW9uSUQ6IEFwcElELmZyb21VaW50NjQodGhpcy5jcmVhdGluZ1ZhbGlkYXRvckNvbnRyYWN0QXBwSWQudmFsdWUpCglieXRlIDB4NjM3MjY1NjE3NDZmNzI0MTcwNzAgLy8gImNyZWF0b3JBcHAiCglhcHBfZ2xvYmFsX2dldAoJaXR4bl9maWVsZCBBcHBsaWNhdGlvbklECgoJLy8gY29udHJhY3RzL3N0YWtpbmdQb29sLmFsZ28udHM6ODg2CgkvLyBtZXRob2RBcmdzOiBbcG9vbEtleS5pZCwgcG9vbEtleS5wb29sSWRdCglmcmFtZV9kaWcgLTEgLy8gcG9vbEtleTogVmFsaWRhdG9yUG9vbEtleQoJZXh0cmFjdCAwIDgKCWJ0b2kKCWl0b2IKCWl0eG5fZmllbGQgQXBwbGljYXRpb25BcmdzCglmcmFtZV9kaWcgLTEgLy8gcG9vbEtleTogVmFsaWRhdG9yUG9vbEtleQoJZXh0cmFjdCA4IDgKCWJ0b2kKCWl0b2IKCWl0eG5fZmllbGQgQXBwbGljYXRpb25BcmdzCgoJLy8gRmVlIGZpZWxkIG5vdCBzZXQsIGRlZmF1bHRpbmcgdG8gMAoJaW50IDAKCWl0eG5fZmllbGQgRmVlCgoJLy8gU3VibWl0IGlubmVyIHRyYW5zYWN0aW9uCglpdHhuX3N1Ym1pdAoJaXR4biBOdW1Mb2dzCglpbnQgMQoJLQoJaXR4bmFzIExvZ3MKCWV4dHJhY3QgNCAwCglidG9pCglmcmFtZV9idXJ5IDAgLy8gY2FsbGVyUG9vbEFwcElEOiB1aW50NjQKCgkvLyBjb250cmFjdHMvc3Rha2luZ1Bvb2wuYWxnby50czo4ODgKCS8vIGFzc2VydChjYWxsZXJQb29sQXBwSUQgPT09IHBvb2xLZXkucG9vbEFwcElkKQoJZnJhbWVfZGlnIDAgLy8gY2FsbGVyUG9vbEFwcElEOiB1aW50NjQKCWZyYW1lX2RpZyAtMSAvLyBwb29sS2V5OiBWYWxpZGF0b3JQb29sS2V5CglleHRyYWN0IDE2IDgKCWJ0b2kKCT09Cglhc3NlcnQKCgkvLyBjb250cmFjdHMvc3Rha2luZ1Bvb2wuYWxnby50czo4ODkKCS8vIGFzc2VydCh0aGlzLnR4bi5zZW5kZXIgPT09IEFwcElELmZyb21VaW50NjQocG9vbEtleS5wb29sQXBwSWQpLmFkZHJlc3MpCgl0eG4gU2VuZGVyCglmcmFtZV9kaWcgLTEgLy8gcG9vbEtleTogVmFsaWRhdG9yUG9vbEtleQoJZXh0cmFjdCAxNiA4CglidG9pCglhcHBfcGFyYW1zX2dldCBBcHBBZGRyZXNzCglwb3AKCT09Cglhc3NlcnQKCgkvLyBjb250cmFjdHMvc3Rha2luZ1Bvb2wuYWxnby50czo4OTEKCS8vIHJldHVybiBzZW5kTWV0aG9kQ2FsbDx0eXBlb2YgVmFsaWRhdG9yUmVnaXN0cnkucHJvdG90eXBlLnNldFRva2VuUGF5b3V0UmF0aW8+KHsKCS8vICAgICAgICAgICAgIGFwcGxpY2F0aW9uSUQ6IEFwcElELmZyb21VaW50NjQodGhpcy5jcmVhdGluZ1ZhbGlkYXRvckNvbnRyYWN0QXBwSWQudmFsdWUpLAoJLy8gICAgICAgICAgICAgbWV0aG9kQXJnczogW3RoaXMudmFsaWRhdG9ySWQudmFsdWVdLAoJLy8gICAgICAgICB9KTsKCWl0eG5fYmVnaW4KCWludCBhcHBsCglpdHhuX2ZpZWxkIFR5cGVFbnVtCgltZXRob2QgInNldFRva2VuUGF5b3V0UmF0aW8odWludDY0KSh1aW50NjRbMjRdLHVpbnQ2NCkiCglpdHhuX2ZpZWxkIEFwcGxpY2F0aW9uQXJncwoKCS8vIGNvbnRyYWN0cy9zdGFraW5nUG9vbC5hbGdvLnRzOjg5MgoJLy8gYXBwbGljYXRpb25JRDogQXBwSUQuZnJvbVVpbnQ2NCh0aGlzLmNyZWF0aW5nVmFsaWRhdG9yQ29udHJhY3RBcHBJZC52YWx1ZSkKCWJ5dGUgMHg2MzcyNjU2MTc0NmY3MjQxNzA3MCAvLyAiY3JlYXRvckFwcCIKCWFwcF9nbG9iYWxfZ2V0CglpdHhuX2ZpZWxkIEFwcGxpY2F0aW9uSUQKCgkvLyBjb250cmFjdHMvc3Rha2luZ1Bvb2wuYWxnby50czo4OTMKCS8vIG1ldGhvZEFyZ3M6IFt0aGlzLnZhbGlkYXRvcklkLnZhbHVlXQoJYnl0ZSAweDc2NjE2YzY5NjQ2MTc0NmY3MjQ5NjQgLy8gInZhbGlkYXRvcklkIgoJYXBwX2dsb2JhbF9nZXQKCWl0b2IKCWl0eG5fZmllbGQgQXBwbGljYXRpb25BcmdzCgoJLy8gRmVlIGZpZWxkIG5vdCBzZXQsIGRlZmF1bHRpbmcgdG8gMAoJaW50IDAKCWl0eG5fZmllbGQgRmVlCgoJLy8gU3VibWl0IGlubmVyIHRyYW5zYWN0aW9uCglpdHhuX3N1Ym1pdAoJaXR4biBOdW1Mb2dzCglpbnQgMQoJLQoJaXR4bmFzIExvZ3MKCWV4dHJhY3QgNCAwCgoJLy8gc2V0IHRoZSBzdWJyb3V0aW5lIHJldHVybiB2YWx1ZQoJZnJhbWVfYnVyeSAwCglyZXRzdWIKCi8vIGlzT3duZXJPck1hbmFnZXJDYWxsZXIoKTogYm9vbGVhbgppc093bmVyT3JNYW5hZ2VyQ2FsbGVyOgoJcHJvdG8gMCAxCgoJLy8gUHVzaCBlbXB0eSBieXRlcyBhZnRlciB0aGUgZnJhbWUgcG9pbnRlciB0byByZXNlcnZlIHNwYWNlIGZvciBsb2NhbCB2YXJpYWJsZXMKCWJ5dGUgMHgKCgkvLyBjb250cmFjdHMvc3Rha2luZ1Bvb2wuYWxnby50czo4OTgKCS8vIE93bmVyQW5kTWFuYWdlciA9IHNlbmRNZXRob2RDYWxsPHR5cGVvZiBWYWxpZGF0b3JSZWdpc3RyeS5wcm90b3R5cGUuZ2V0VmFsaWRhdG9yT3duZXJBbmRNYW5hZ2VyPih7CgkvLyAgICAgICAgICAgICBhcHBsaWNhdGlvbklEOiBBcHBJRC5mcm9tVWludDY0KHRoaXMuY3JlYXRpbmdWYWxpZGF0b3JDb250cmFjdEFwcElkLnZhbHVlKSwKCS8vICAgICAgICAgICAgIG1ldGhvZEFyZ3M6IFt0aGlzLnZhbGlkYXRvcklkLnZhbHVlXSwKCS8vICAgICAgICAgfSkKCWl0eG5fYmVnaW4KCWludCBhcHBsCglpdHhuX2ZpZWxkIFR5cGVFbnVtCgltZXRob2QgImdldFZhbGlkYXRvck93bmVyQW5kTWFuYWdlcih1aW50NjQpKGFkZHJlc3MsYWRkcmVzcykiCglpdHhuX2ZpZWxkIEFwcGxpY2F0aW9uQXJncwoKCS8vIGNvbnRyYWN0cy9zdGFraW5nUG9vbC5hbGdvLnRzOjg5OQoJLy8gYXBwbGljYXRpb25JRDogQXBwSUQuZnJvbVVpbnQ2NCh0aGlzLmNyZWF0aW5nVmFsaWRhdG9yQ29udHJhY3RBcHBJZC52YWx1ZSkKCWJ5dGUgMHg2MzcyNjU2MTc0NmY3MjQxNzA3MCAvLyAiY3JlYXRvckFwcCIKCWFwcF9nbG9iYWxfZ2V0CglpdHhuX2ZpZWxkIEFwcGxpY2F0aW9uSUQKCgkvLyBjb250cmFjdHMvc3Rha2luZ1Bvb2wuYWxnby50czo5MDAKCS8vIG1ldGhvZEFyZ3M6IFt0aGlzLnZhbGlkYXRvcklkLnZhbHVlXQoJYnl0ZSAweDc2NjE2YzY5NjQ2MTc0NmY3MjQ5NjQgLy8gInZhbGlkYXRvcklkIgoJYXBwX2dsb2JhbF9nZXQKCWl0b2IKCWl0eG5fZmllbGQgQXBwbGljYXRpb25BcmdzCgoJLy8gRmVlIGZpZWxkIG5vdCBzZXQsIGRlZmF1bHRpbmcgdG8gMAoJaW50IDAKCWl0eG5fZmllbGQgRmVlCgoJLy8gU3VibWl0IGlubmVyIHRyYW5zYWN0aW9uCglpdHhuX3N1Ym1pdAoJaXR4biBOdW1Mb2dzCglpbnQgMQoJLQoJaXR4bmFzIExvZ3MKCWV4dHJhY3QgNCAwCglmcmFtZV9idXJ5IDAgLy8gT3duZXJBbmRNYW5hZ2VyOiAoYWRkcmVzcyxhZGRyZXNzKQoKCS8vIGNvbnRyYWN0cy9zdGFraW5nUG9vbC5hbGdvLnRzOjkwMgoJLy8gcmV0dXJuIHRoaXMudHhuLnNlbmRlciA9PT0gT3duZXJBbmRNYW5hZ2VyWzBdIHx8IHRoaXMudHhuLnNlbmRlciA9PT0gT3duZXJBbmRNYW5hZ2VyWzFdOwoJdHhuIFNlbmRlcgoJZnJhbWVfZGlnIDAgLy8gT3duZXJBbmRNYW5hZ2VyOiAoYWRkcmVzcyxhZGRyZXNzKQoJZXh0cmFjdCAwIDMyCgk9PQoJZHVwCglibnogKnNraXBfb3IxCgl0eG4gU2VuZGVyCglmcmFtZV9kaWcgMCAvLyBPd25lckFuZE1hbmFnZXI6IChhZGRyZXNzLGFkZHJlc3MpCglleHRyYWN0IDMyIDMyCgk9PQoJfHwKCipza2lwX29yMToKCS8vIHNldCB0aGUgc3Vicm91dGluZSByZXR1cm4gdmFsdWUKCWZyYW1lX2J1cnkgMAoJcmV0c3ViCgovLyBnZXRFbnRyeVRpbWUoKTogdWludDY0Ci8vCi8vIENhbGN1bGF0ZSB0aGUgZW50cnkgdGltZSBmb3IgY291bnRpbmcgYSBzdGFrZSBhcyBlbnRlcmluZyB0aGUgcG9vbC4KLy8gQWxnb3JhbmQgd29uJ3Qgc2VlIHRoZSBiYWxhbmNlIGluY3JlYXNlIGZvciBBTEdPUkFORF9TVEFLSU5HX0JMT0NLX0RFTEFZIHJvdW5kcywgc28gd2UgYXBwcm94aW1hdGUgaXQuCi8vIFRoZSBlbnRyeSB0aW1lIGlzIGNhbGN1bGF0ZWQgYnkgYWRkaW5nIGFuIGFwcHJveGltYXRlIG51bWJlciBvZiBzZWNvbmRzIGJhc2VkIG9uIGN1cnJlbnQgQVZHIGJsb2NrIHRpbWVzCi8vIHRvIHRoZSBvcmlnaW5hbCBlbnRyeSB0aW1lLiAgVGhpcyBtZWFucyB1c2VycyBkb24ndCBnZXQgcGF5b3V0cyBiYXNlZCBvbiB0aW1lIHRoZWlyIGJhbGFuY2Ugd291bGRuJ3QgaGF2ZQovLyBiZWVuIHNlZW4gYnkgdGhlIG5ldHdvcmsuCi8vCi8vIEByZXR1cm5zIHt1aW50NjR9IC0gVGhlIHVwZGF0ZWQgZW50cnkgdGltZS4KZ2V0RW50cnlUaW1lOgoJcHJvdG8gMCAxCgoJLy8gUHVzaCBlbXB0eSBieXRlcyBhZnRlciB0aGUgZnJhbWUgcG9pbnRlciB0byByZXNlcnZlIHNwYWNlIGZvciBsb2NhbCB2YXJpYWJsZXMKCWJ5dGUgMHgKCgkvLyBjb250cmFjdHMvc3Rha2luZ1Bvb2wuYWxnby50czo5MTcKCS8vIGVudHJ5VGltZSA9IGdsb2JhbHMubGF0ZXN0VGltZXN0YW1wCglnbG9iYWwgTGF0ZXN0VGltZXN0YW1wCglmcmFtZV9idXJ5IDAgLy8gZW50cnlUaW1lOiB1aW50NjQKCgkvLyBjb250cmFjdHMvc3Rha2luZ1Bvb2wuYWxnby50czo5MjAKCS8vIHJldHVybiBlbnRyeVRpbWUgKyAoQUxHT1JBTkRfU1RBS0lOR19CTE9DS19ERUxBWSAqIEFWR19CTE9DS19USU1FX1NFQ1MpIC8gMTA7CglmcmFtZV9kaWcgMCAvLyBlbnRyeVRpbWU6IHVpbnQ2NAoJaW50IDg5NgoJKwoKCS8vIHNldCB0aGUgc3Vicm91dGluZSByZXR1cm4gdmFsdWUKCWZyYW1lX2J1cnkgMAoJcmV0c3ViCgovLyBnZXRGZWVTaW5rKCk6IEFkZHJlc3MKZ2V0RmVlU2luazoKCXByb3RvIDAgMQoKCS8vIGNvbnRyYWN0cy9zdGFraW5nUG9vbC5hbGdvLnRzOjkyNAoJLy8gcmV0dXJuIHRoaXMuZmVlU2lua0FkZHI7CglwdXNoYnl0ZXMgVE1QTF9mZWVTaW5rQWRkcgoJcmV0c3ViCgovLyBhbGdvU2F0dXJhdGlvbkxldmVsKCk6IHVpbnQ2NAovLwovLyBSZXR1cm5zIHRoZSBtYXhpbXVtIGFsbG93ZWQgc3Rha2UgcGVyIHZhbGlkYXRvciBiYXNlZCBvbiBhIHBlcmNlbnRhZ2Ugb2YgYWxsIGN1cnJlbnQgb25saW5lIHN0YWtlIGJlZm9yZQovLyB0aGUgdmFsaWRhdG9yIGlzIGNvbnNpZGVyZWQgc2F0dXJhdGVkIC0gd2hlcmUgcmV3YXJkcyBhcmUgZGltaW5pc2hlZC4KYWxnb1NhdHVyYXRpb25MZXZlbDoKCXByb3RvIDAgMQoKCS8vIFB1c2ggZW1wdHkgYnl0ZXMgYWZ0ZXIgdGhlIGZyYW1lIHBvaW50ZXIgdG8gcmVzZXJ2ZSBzcGFjZSBmb3IgbG9jYWwgdmFyaWFibGVzCglieXRlIDB4CgoJLy8gY29udHJhY3RzL3N0YWtpbmdQb29sLmFsZ28udHM6OTM0CgkvLyBvbmxpbmUgPSB0aGlzLmdldEN1cnJlbnRPbmxpbmVTdGFrZSgpCgljYWxsc3ViIGdldEN1cnJlbnRPbmxpbmVTdGFrZQoJZnJhbWVfYnVyeSAwIC8vIG9ubGluZTogdWludDY0CgoJLy8gY29udHJhY3RzL3N0YWtpbmdQb29sLmFsZ28udHM6OTM2CgkvLyByZXR1cm4gd2lkZVJhdGlvKFtvbmxpbmUsIE1BWF9WQUxJREFUT1JfU09GVF9QQ1RfT0ZfT05MSU5FXzFERUNJTUFMXSwgWzEwMDBdKTsKCWZyYW1lX2RpZyAwIC8vIG9ubGluZTogdWludDY0CglpbnQgMTAwCgltdWx3CglpbnQgMAoJaW50IDEwMDAKCWRpdm1vZHcKCXBvcAoJcG9wCglzd2FwCgkhCglhc3NlcnQKCgkvLyBzZXQgdGhlIHN1YnJvdXRpbmUgcmV0dXJuIHZhbHVlCglmcmFtZV9idXJ5IDAKCXJldHN1YgoKLy8gZ2V0Q3VycmVudE9ubGluZVN0YWtlKCk6IHVpbnQ2NApnZXRDdXJyZW50T25saW5lU3Rha2U6Cglwcm90byAwIDEKCgkvLyBjb250cmFjdHMvc3Rha2luZ1Bvb2wuYWxnby50czo5NDEKCS8vIHJldHVybiAyXzAwMF8wMDBfMDAwXzAwMF8wMDA7CglpbnQgMl8wMDBfMDAwXzAwMF8wMDBfMDAwCglyZXRzdWIKCipjcmVhdGVfTm9PcDoKCW1ldGhvZCAiY3JlYXRlQXBwbGljYXRpb24odWludDY0LHVpbnQ2NCx1aW50NjQsdWludDY0KXZvaWQiCgl0eG5hIEFwcGxpY2F0aW9uQXJncyAwCgltYXRjaCAqYWJpX3JvdXRlX2NyZWF0ZUFwcGxpY2F0aW9uCgllcnIKCipjYWxsX05vT3A6CgltZXRob2QgImdhcygpdm9pZCIKCW1ldGhvZCAiaW5pdFN0b3JhZ2UocGF5KXZvaWQiCgltZXRob2QgImFkZFN0YWtlKHBheSxhZGRyZXNzKXVpbnQ2NCIKCW1ldGhvZCAicmVtb3ZlU3Rha2UodWludDY0KXZvaWQiCgltZXRob2QgImNsYWltVG9rZW5zKCl2b2lkIgoJbWV0aG9kICJnZXRTdGFrZXJJbmZvKGFkZHJlc3MpKGFkZHJlc3MsdWludDY0LHVpbnQ2NCx1aW50NjQsdWludDY0KSIKCW1ldGhvZCAicGF5VG9rZW5SZXdhcmQoYWRkcmVzcyx1aW50NjQsdWludDY0KXZvaWQiCgltZXRob2QgInVwZGF0ZUFsZ29kVmVyKHN0cmluZyl2b2lkIgoJbWV0aG9kICJlcG9jaEJhbGFuY2VVcGRhdGUoKXZvaWQiCgltZXRob2QgImdvT25saW5lKGJ5dGVbXSxieXRlW10sYnl0ZVtdLHVpbnQ2NCx1aW50NjQsdWludDY0KXZvaWQiCgltZXRob2QgImdvT2ZmbGluZSgpdm9pZCIKCW1ldGhvZCAibGlua1RvTkZEKHVpbnQ2NCxzdHJpbmcpdm9pZCIKCW1ldGhvZCAicHJveGllZFNldFRva2VuUGF5b3V0UmF0aW8oKHVpbnQ2NCx1aW50NjQsdWludDY0KSkodWludDY0WzI0XSx1aW50NjQpIgoJdHhuYSBBcHBsaWNhdGlvbkFyZ3MgMAoJbWF0Y2ggKmFiaV9yb3V0ZV9nYXMgKmFiaV9yb3V0ZV9pbml0U3RvcmFnZSAqYWJpX3JvdXRlX2FkZFN0YWtlICphYmlfcm91dGVfcmVtb3ZlU3Rha2UgKmFiaV9yb3V0ZV9jbGFpbVRva2VucyAqYWJpX3JvdXRlX2dldFN0YWtlckluZm8gKmFiaV9yb3V0ZV9wYXlUb2tlblJld2FyZCAqYWJpX3JvdXRlX3VwZGF0ZUFsZ29kVmVyICphYmlfcm91dGVfZXBvY2hCYWxhbmNlVXBkYXRlICphYmlfcm91dGVfZ29PbmxpbmUgKmFiaV9yb3V0ZV9nb09mZmxpbmUgKmFiaV9yb3V0ZV9saW5rVG9ORkQgKmFiaV9yb3V0ZV9wcm94aWVkU2V0VG9rZW5QYXlvdXRSYXRpbwoJZXJyCgoqaW50VG9Bc2NpaToKCXByb3RvIDEgMQoJYnl0ZSAweDMwMzEzMjMzMzQzNTM2MzczODM5IC8vICIwMTIzNDU2Nzg5IgoJZnJhbWVfZGlnIC0xIC8vIGk6IHVpbnQ2NAoJaW50IDEKCWV4dHJhY3QzCglyZXRzdWIKCQoKKml0b2E6Cglwcm90byAxIDEKCWZyYW1lX2RpZyAtMSAvLyBpOiB1aW50NjQKCWludCAwCgk9PQoJYnogKml0b2FfaWZfZW5kCglieXRlIDB4MzAKCXJldHN1YgoKKml0b2FfaWZfZW5kOgoJZnJhbWVfZGlnIC0xIC8vIGk6IHVpbnQ2NAoJaW50IDEwCgkvCglpbnQgMAoJPgoJYnogKml0b2FfdGVybmFyeV9mYWxzZQoJZnJhbWVfZGlnIC0xIC8vIGk6IHVpbnQ2NAoJaW50IDEwCgkvCgljYWxsc3ViICppdG9hCgliICppdG9hX3Rlcm5hcnlfZW5kCgoqaXRvYV90ZXJuYXJ5X2ZhbHNlOgoJYnl0ZSAweCAvLyAiIgoKKml0b2FfdGVybmFyeV9lbmQ6CglmcmFtZV9kaWcgLTEgLy8gaTogdWludDY0CglpbnQgMTAKCSUKCWNhbGxzdWIgKmludFRvQXNjaWkKCWNvbmNhdAoJcmV0c3Vi", + "clear": "I3ByYWdtYSB2ZXJzaW9uIDEw" + }, + "contract": { + "name": "StakingPool", + "desc": "", + "methods": [ + { + "name": "createApplication", + "desc": "Initialize the staking pool w/ owner and manager, but can only be created by the validator contract.", + "args": [ + { + "name": "creatingContractId", + "type": "uint64", + "desc": "id of contract that constructed us - the validator application (single global instance)" + }, + { + "name": "validatorId", + "type": "uint64", + "desc": "id of validator we're a staking pool of" + }, + { + "name": "poolId", + "type": "uint64", + "desc": "which pool id are we" + }, + { + "name": "minEntryStake", + "type": "uint64", + "desc": "minimum amount to be in pool, but also minimum amount balance can't go below (without removing all!)" + } + ], + "returns": { + "type": "void" + } + }, + { + "name": "gas", + "desc": "gas is a dummy no-op call that can be used to pool-up resource references and opcode cost", + "args": [], + "returns": { + "type": "void" + } + }, + { + "name": "initStorage", + "desc": "Called after we're created and then funded so we can create our large stakers ledger storageCaller has to get MBR amounts from ValidatorRegistry to know how much to fund us to cover the box storage costIf this is pool 1 AND the validator has specified a reward token, opt-in to that tokenso that the validator can seed the pool with future rewards of that token.", + "args": [ + { + "name": "mbrPayment", + "type": "pay", + "desc": "payment from caller which covers mbr increase of new staking pools' storage" + } + ], + "returns": { + "type": "void" + } + }, + { + "name": "addStake", + "desc": "Adds stake to the given account.Can ONLY be called by the validator contract that created usMust receive payment from the validator contract for amount being staked.", + "args": [ + { + "name": "stakedAmountPayment", + "type": "pay", + "desc": "prior payment coming from validator contract to us on behalf of staker." + }, + { + "name": "staker", + "type": "address", + "desc": "The account adding new stake" + } + ], + "returns": { + "type": "uint64", + "desc": "{uint64}new 'entry time' in seconds of stake add." + } + }, + { + "name": "removeStake", + "desc": "Removes stake on behalf of caller (removing own stake). If any token rewards exist, those are always sent infull. Also notifies the validator contract for this pools validator of the staker / balance changes.", + "args": [ + { + "name": "amountToUnstake", + "type": "uint64", + "desc": "The amount of stake to be removed. Specify 0 to remove all stake." + } + ], + "returns": { + "type": "void" + } + }, + { + "name": "claimTokens", + "desc": "Claims all the available reward tokens a staker has available, sending their entire balance to the staker frompool 1 (either directly, or via validator->pool1 to pay it out)Also notifies the validator contract for this pools validator of the staker / balance changes.", + "args": [], + "returns": { + "type": "void" + } + }, + { + "name": "getStakerInfo", + "desc": "Retrieves the staked information for a given staker.", + "args": [ + { + "name": "staker", + "type": "address", + "desc": "The address of the staker." + } + ], + "returns": { + "type": "(address,uint64,uint64,uint64,uint64)", + "desc": "{StakedInfo}- The staked information for the given staker." + } + }, + { + "name": "payTokenReward", + "desc": "[Internal protocol method] Remove a specified amount of 'community token' rewards for a staker.This can ONLY be called by our validator and only if we're pool 1 - with the token.", + "args": [ + { + "name": "staker", + "type": "address", + "desc": "the staker account to send rewards to" + }, + { + "name": "rewardToken", + "type": "uint64", + "desc": "id of reward token (to avoid re-entrancy in calling validator back to get id)" + }, + { + "name": "amountToSend", + "type": "uint64", + "desc": "amount to send the staker (there is significant trust here(!) - also why only validator can call us" + } + ], + "returns": { + "type": "void" + } + }, + { + "name": "updateAlgodVer", + "desc": "Update the (honor system) algod version for the node associated to this pool. The node management daemonshould compare its current nodes version to the version stored in global state, updating when different.The reti node daemon composes its own version string using format:{major}.{minor}.{build}{branch}[{commit hash}],ie: 3.22.0 rel/stable [6b508975][ ONLY OWNER OR MANAGER CAN CALL ]", + "args": [ + { + "name": "algodVer", + "type": "string", + "desc": "string representing the algorand node daemon version (reti node daemon composes its own meta version)" + } + ], + "returns": { + "type": "void" + } + }, + { + "name": "epochBalanceUpdate", + "desc": "Updates the balance of stakers in the pool based on the received 'rewards' (current balance vs known staked balance)stakers outstanding balance is adjusted based on their % of stake and time in the current epoch - so that balancecompounds over time and staker can remove that amount at will.The validator is paid their percentage each epoch payout.Note: ANYONE can call this.", + "args": [], + "returns": { + "type": "void" + } + }, + { + "name": "goOnline", + "desc": "Registers a staking pool key online against a participation key.[ ONLY OWNER OR MANAGER CAN CALL ]", + "args": [ + { + "name": "votePK", + "type": "byte[]", + "desc": "The vote public key." + }, + { + "name": "selectionPK", + "type": "byte[]", + "desc": "The selection public key." + }, + { + "name": "stateProofPK", + "type": "byte[]", + "desc": "The state proof public key." + }, + { + "name": "voteFirst", + "type": "uint64", + "desc": "The first vote index." + }, + { + "name": "voteLast", + "type": "uint64", + "desc": "The last vote index." + }, + { + "name": "voteKeyDilution", + "type": "uint64", + "desc": "The vote key dilution value." + } + ], + "returns": { + "type": "void" + } + }, + { + "name": "goOffline", + "desc": "Marks a staking pool key OFFLINE.[ ONLY OWNER OR MANAGER CAN CALL ]", + "args": [], + "returns": { + "type": "void" + } + }, + { + "name": "linkToNFD", + "args": [ + { + "name": "nfdAppId", + "type": "uint64" + }, + { + "name": "nfdName", + "type": "string" + } + ], + "returns": { + "type": "void" + } + }, + { + "name": "proxiedSetTokenPayoutRatio", + "desc": "proxiedSetTokenPayoutRatio is meant to be called by pools != 1 - calling US, pool #1We need to verify that we are in fact being called by another of OUR pools (not us)and then we'll call the validator on their behalf to update the token payouts", + "args": [ + { + "name": "poolKey", + "type": "(uint64,uint64,uint64)", + "desc": "ValidatorPoolKey tuple" + } + ], + "returns": { + "type": "(uint64[24],uint64)" + } + } + ] + } +} \ No newline at end of file diff --git a/nodemgr/internal/lib/reti/artifacts/contracts/ValidatorRegistry.arc32.json b/nodemgr/internal/lib/reti/artifacts/contracts/ValidatorRegistry.arc32.json new file mode 100644 index 00000000..a49b3069 --- /dev/null +++ b/nodemgr/internal/lib/reti/artifacts/contracts/ValidatorRegistry.arc32.json @@ -0,0 +1,709 @@ +{ + "hints": { + "createApplication(uint64)void": { + "call_config": { + "no_op": "CREATE" + } + }, + "gas()void": { + "call_config": { + "no_op": "CALL" + } + }, + "getMbrAmounts()(uint64,uint64,uint64,uint64)": { + "call_config": { + "no_op": "CALL" + } + }, + "getProtocolConstraints()(uint64,uint64,uint64,uint64,uint64,uint64,uint64,uint64,uint64,uint64,uint64)": { + "call_config": { + "no_op": "CALL" + } + }, + "getNumValidators()uint64": { + "call_config": { + "no_op": "CALL" + } + }, + "getValidatorConfig(uint64)(uint64,address,address,uint64,uint8,byte[32],uint64,uint64,uint64,uint16,uint32,address,uint64,uint64,uint8,uint64,uint64)": { + "call_config": { + "no_op": "CALL" + } + }, + "getValidatorState(uint64)(uint16,uint64,uint64,uint64)": { + "call_config": { + "no_op": "CALL" + } + }, + "getValidatorOwnerAndManager(uint64)(address,address)": { + "call_config": { + "no_op": "CALL" + } + }, + "getPools(uint64)(uint64,uint16,uint64)[]": { + "call_config": { + "no_op": "CALL" + } + }, + "getPoolAppId(uint64,uint64)uint64": { + "call_config": { + "no_op": "CALL" + } + }, + "getPoolInfo((uint64,uint64,uint64))(uint64,uint16,uint64)": { + "call_config": { + "no_op": "CALL" + } + }, + "getCurMaxStakePerPool(uint64)uint64": { + "call_config": { + "no_op": "CALL" + } + }, + "doesStakerNeedToPayMBR(address)bool": { + "call_config": { + "no_op": "CALL" + } + }, + "getStakedPoolsForAccount(address)(uint64,uint64,uint64)[]": { + "call_config": { + "no_op": "CALL" + } + }, + "getTokenPayoutRatio(uint64)(uint64[24],uint64)": { + "call_config": { + "no_op": "CALL" + } + }, + "getNodePoolAssignments(uint64)((uint64[3])[8])": { + "call_config": { + "no_op": "CALL" + } + }, + "getNFDRegistryID()uint64": { + "call_config": { + "no_op": "CALL" + } + }, + "addValidator(pay,string,(uint64,address,address,uint64,uint8,byte[32],uint64,uint64,uint64,uint16,uint32,address,uint64,uint64,uint8,uint64,uint64))uint64": { + "call_config": { + "no_op": "CALL" + } + }, + "changeValidatorManager(uint64,address)void": { + "call_config": { + "no_op": "CALL" + } + }, + "changeValidatorSunsetInfo(uint64,uint64,uint64)void": { + "call_config": { + "no_op": "CALL" + } + }, + "changeValidatorNFD(uint64,uint64,string)void": { + "call_config": { + "no_op": "CALL" + } + }, + "changeValidatorCommissionAddress(uint64,address)void": { + "call_config": { + "no_op": "CALL" + } + }, + "changeValidatorRewardInfo(uint64,uint8,byte[32],uint64,uint64)void": { + "call_config": { + "no_op": "CALL" + } + }, + "addPool(pay,uint64,uint64)(uint64,uint64,uint64)": { + "call_config": { + "no_op": "CALL" + } + }, + "addStake(pay,uint64,uint64)(uint64,uint64,uint64)": { + "call_config": { + "no_op": "CALL" + } + }, + "setTokenPayoutRatio(uint64)(uint64[24],uint64)": { + "call_config": { + "no_op": "CALL" + } + }, + "stakeUpdatedViaRewards((uint64,uint64,uint64),uint64,uint64)void": { + "call_config": { + "no_op": "CALL" + } + }, + "stakeRemoved((uint64,uint64,uint64),address,uint64,uint64,bool)void": { + "call_config": { + "no_op": "CALL" + } + }, + "findPoolForStaker(uint64,address,uint64)((uint64,uint64,uint64),bool,bool)": { + "call_config": { + "no_op": "CALL" + } + }, + "movePoolToNode(uint64,uint64,uint64)void": { + "call_config": { + "no_op": "CALL" + } + } + }, + "bare_call_config": { + "no_op": "NEVER", + "opt_in": "NEVER", + "close_out": "NEVER", + "update_application": "NEVER", + "delete_application": "NEVER" + }, + "schema": { + "local": { + "declared": {}, + "reserved": {} + }, + "global": { + "declared": { + "numValidators": { + "type": "uint64", + "key": "numV" + }, + "stakingPoolTemplateAppId": { + "type": "uint64", + "key": "poolTemplateAppId" + }, + "numStakers": { + "type": "uint64", + "key": "numStakers" + }, + "totalAlgoStaked": { + "type": "uint64", + "key": "staked" + } + }, + "reserved": {} + } + }, + "state": { + "global": { + "num_byte_slices": 0, + "num_uints": 4 + }, + "local": { + "num_byte_slices": 0, + "num_uints": 0 + } + }, + "source": { + "approval": "I3ByYWdtYSB2ZXJzaW9uIDEwCgovLyBUaGlzIFRFQUwgd2FzIGdlbmVyYXRlZCBieSBURUFMU2NyaXB0IHYwLjg4LjEKLy8gaHR0cHM6Ly9naXRodWIuY29tL2FsZ29yYW5kZm91bmRhdGlvbi9URUFMU2NyaXB0CgovLyBUaGlzIGNvbnRyYWN0IGlzIGNvbXBsaWFudCB3aXRoIGFuZC9vciBpbXBsZW1lbnRzIHRoZSBmb2xsb3dpbmcgQVJDczogWyBBUkM0IF0KCi8vIFRoZSBmb2xsb3dpbmcgdGVuIGxpbmVzIG9mIFRFQUwgaGFuZGxlIGluaXRpYWwgcHJvZ3JhbSBmbG93Ci8vIFRoaXMgcGF0dGVybiBpcyB1c2VkIHRvIG1ha2UgaXQgZWFzeSBmb3IgYW55b25lIHRvIHBhcnNlIHRoZSBzdGFydCBvZiB0aGUgcHJvZ3JhbSBhbmQgZGV0ZXJtaW5lIGlmIGEgc3BlY2lmaWMgYWN0aW9uIGlzIGFsbG93ZWQKLy8gSGVyZSwgYWN0aW9uIHJlZmVycyB0byB0aGUgT25Db21wbGV0ZSBpbiBjb21iaW5hdGlvbiB3aXRoIHdoZXRoZXIgdGhlIGFwcCBpcyBiZWluZyBjcmVhdGVkIG9yIGNhbGxlZAovLyBFdmVyeSBwb3NzaWJsZSBhY3Rpb24gZm9yIHRoaXMgY29udHJhY3QgaXMgcmVwcmVzZW50ZWQgaW4gdGhlIHN3aXRjaCBzdGF0ZW1lbnQKLy8gSWYgdGhlIGFjdGlvbiBpcyBub3QgaW1wbGVtZW50ZWQgaW4gdGhlIGNvbnRyYWN0LCBpdHMgcmVzcGVjdGl2ZSBicmFuY2ggd2lsbCBiZSAiKk5PVF9JTVBMRU1FTlRFRCIgd2hpY2gganVzdCBjb250YWlucyAiZXJyIgp0eG4gQXBwbGljYXRpb25JRAohCmludCA2CioKdHhuIE9uQ29tcGxldGlvbgorCnN3aXRjaCAqY2FsbF9Ob09wICpOT1RfSU1QTEVNRU5URUQgKk5PVF9JTVBMRU1FTlRFRCAqTk9UX0lNUExFTUVOVEVEICpOT1RfSU1QTEVNRU5URUQgKk5PVF9JTVBMRU1FTlRFRCAqY3JlYXRlX05vT3AgKk5PVF9JTVBMRU1FTlRFRCAqTk9UX0lNUExFTUVOVEVEICpOT1RfSU1QTEVNRU5URUQgKk5PVF9JTVBMRU1FTlRFRCAqTk9UX0lNUExFTUVOVEVECgoqTk9UX0lNUExFTUVOVEVEOgoJZXJyCgovLyBjcmVhdGVBcHBsaWNhdGlvbih1aW50NjQpdm9pZAoqYWJpX3JvdXRlX2NyZWF0ZUFwcGxpY2F0aW9uOgoJLy8gcG9vbFRlbXBsYXRlQXBwSWQ6IHVpbnQ2NAoJdHhuYSBBcHBsaWNhdGlvbkFyZ3MgMQoJYnRvaQoKCS8vIGV4ZWN1dGUgY3JlYXRlQXBwbGljYXRpb24odWludDY0KXZvaWQKCWNhbGxzdWIgY3JlYXRlQXBwbGljYXRpb24KCWludCAxCglyZXR1cm4KCi8vIGNyZWF0ZUFwcGxpY2F0aW9uKHBvb2xUZW1wbGF0ZUFwcElkOiB1aW50NjQpOiB2b2lkCmNyZWF0ZUFwcGxpY2F0aW9uOgoJcHJvdG8gMSAwCgoJLy8gY29udHJhY3RzL3ZhbGlkYXRvclJlZ2lzdHJ5LmFsZ28udHM6MTk0CgkvLyB0aGlzLm51bVZhbGlkYXRvcnMudmFsdWUgPSAwCglieXRlIDB4NmU3NTZkNTYgLy8gIm51bVYiCglpbnQgMAoJYXBwX2dsb2JhbF9wdXQKCgkvLyBjb250cmFjdHMvdmFsaWRhdG9yUmVnaXN0cnkuYWxnby50czoxOTUKCS8vIHRoaXMuc3Rha2luZ1Bvb2xUZW1wbGF0ZUFwcElkLnZhbHVlID0gcG9vbFRlbXBsYXRlQXBwSWQKCWJ5dGUgMHg3MDZmNmY2YzU0NjU2ZDcwNmM2MTc0NjU0MTcwNzA0OTY0IC8vICJwb29sVGVtcGxhdGVBcHBJZCIKCWZyYW1lX2RpZyAtMSAvLyBwb29sVGVtcGxhdGVBcHBJZDogdWludDY0CglhcHBfZ2xvYmFsX3B1dAoKCS8vIGNvbnRyYWN0cy92YWxpZGF0b3JSZWdpc3RyeS5hbGdvLnRzOjE5NgoJLy8gdGhpcy5udW1TdGFrZXJzLnZhbHVlID0gMAoJYnl0ZSAweDZlNzU2ZDUzNzQ2MTZiNjU3MjczIC8vICJudW1TdGFrZXJzIgoJaW50IDAKCWFwcF9nbG9iYWxfcHV0CgoJLy8gY29udHJhY3RzL3ZhbGlkYXRvclJlZ2lzdHJ5LmFsZ28udHM6MTk3CgkvLyB0aGlzLnRvdGFsQWxnb1N0YWtlZC52YWx1ZSA9IDAKCWJ5dGUgMHg3Mzc0NjE2YjY1NjQgLy8gInN0YWtlZCIKCWludCAwCglhcHBfZ2xvYmFsX3B1dAoJcmV0c3ViCgovLyBnYXMoKXZvaWQKKmFiaV9yb3V0ZV9nYXM6CgkvLyBleGVjdXRlIGdhcygpdm9pZAoJY2FsbHN1YiBnYXMKCWludCAxCglyZXR1cm4KCi8vIGdhcygpOiB2b2lkCi8vCi8vIGdhcyBpcyBhIGR1bW15IG5vLW9wIGNhbGwgdGhhdCBjYW4gYmUgdXNlZCB0byBwb29sLXVwIHJlc291cmNlIHJlZmVyZW5jZXMgYW5kIG9wY29kZSBjb3N0CmdhczoKCXByb3RvIDAgMAoJcmV0c3ViCgovLyBnZXRNYnJBbW91bnRzKCkodWludDY0LHVpbnQ2NCx1aW50NjQsdWludDY0KQoqYWJpX3JvdXRlX2dldE1ickFtb3VudHM6CgkvLyBUaGUgQUJJIHJldHVybiBwcmVmaXgKCWJ5dGUgMHgxNTFmN2M3NQoKCS8vIGV4ZWN1dGUgZ2V0TWJyQW1vdW50cygpKHVpbnQ2NCx1aW50NjQsdWludDY0LHVpbnQ2NCkKCWNhbGxzdWIgZ2V0TWJyQW1vdW50cwoJY29uY2F0Cglsb2cKCWludCAxCglyZXR1cm4KCi8vIGdldE1ickFtb3VudHMoKTogTWJyQW1vdW50cwovLwovLyBSZXR1cm5zIHRoZSBNQlIgYW1vdW50cyBuZWVkZWQgZm9yIHZhcmlvdXMgYWN0aW9uczoKLy8gWwovLyBhZGRWYWxpZGF0b3JNYnI6IHVpbnQ2NCAtIG1iciBuZWVkZWQgdG8gYWRkIGEgbmV3IHZhbGlkYXRvciAtIHBhaWQgdG8gdmFsaWRhdG9yIGNvbnRyYWN0Ci8vIGFkZFBvb2xNYnI6IHVpbnQ2NCAtIG1iciBuZWVkZWQgdG8gYWRkIGEgbmV3IHBvb2wgLSBwYWlkIHRvIHZhbGlkYXRvcgovLyBwb29sSW5pdE1icjogdWludDY0IC0gbWJyIG5lZWRlZCB0byBpbml0U3RvcmFnZSgpIG9mIHBvb2wgLSBwYWlkIHRvIHBvb2wgaXRzZWxmCi8vIGFkZFN0YWtlck1icjogdWludDY0IC0gbWJyIHN0YWtlciBuZWVkcyB0byBhZGQgdG8gZmlyc3Qgc3Rha2luZyBwYXltZW50IChzdGF5cyB3LyB2YWxpZGF0b3IpCi8vIF0KZ2V0TWJyQW1vdW50czoKCXByb3RvIDAgMQoKCS8vIGNvbnRyYWN0cy92YWxpZGF0b3JSZWdpc3RyeS5hbGdvLnRzOjIxNwoJLy8gcmV0dXJuIHsKCS8vICAgICAgICAgICAgIGFkZFZhbGlkYXRvck1icjogdGhpcy5jb3N0Rm9yQm94U3RvcmFnZSgxIC8qIHYgcHJlZml4ICovICsgbGVuPFZhbGlkYXRvcklkVHlwZT4oKSArIGxlbjxWYWxpZGF0b3JJbmZvPigpKSwKCS8vICAgICAgICAgICAgIGFkZFBvb2xNYnI6IHRoaXMubWluQmFsYW5jZUZvckFjY291bnQoCgkvLyAgICAgICAgICAgICAgICAgMSwKCS8vICAgICAgICAgICAgICAgICAwLAoJLy8gICAgICAgICAgICAgICAgIDAsCgkvLyAgICAgICAgICAgICAgICAgMCwKCS8vICAgICAgICAgICAgICAgICAwLAoJLy8gICAgICAgICAgICAgICAgIFN0YWtpbmdQb29sLnNjaGVtYS5nbG9iYWwubnVtVWludCwKCS8vICAgICAgICAgICAgICAgICBTdGFraW5nUG9vbC5zY2hlbWEuZ2xvYmFsLm51bUJ5dGVTbGljZQoJLy8gICAgICAgICAgICAgKSwKCS8vICAgICAgICAgICAgIHBvb2xJbml0TWJyOgoJLy8gICAgICAgICAgICAgICAgIEFMR09SQU5EX0FDQ09VTlRfTUlOX0JBTEFOQ0UgKwoJLy8gICAgICAgICAgICAgICAgIHRoaXMuY29zdEZvckJveFN0b3JhZ2UoNyAvKiAnc3Rha2VycycgbmFtZSAqLyArIGxlbjxTdGFrZWRJbmZvPigpICogTUFYX1NUQUtFUlNfUEVSX1BPT0wpLAoJLy8gICAgICAgICAgICAgYWRkU3Rha2VyTWJyOgoJLy8gICAgICAgICAgICAgICAgIC8vIGhvdyBtdWNoIHRvIGNoYXJnZSBmb3IgZmlyc3QgdGltZSBhIHN0YWtlciBhZGRzIHN0YWtlIC0gc2luY2Ugd2UgYWRkIGEgdHJhY2tpbmcgYm94IHBlciBzdGFrZXIKCS8vICAgICAgICAgICAgICAgICB0aGlzLmNvc3RGb3JCb3hTdG9yYWdlKAoJLy8gICAgICAgICAgICAgICAgICAgICAzIC8qICdzcHMnIHByZWZpeCAqLyArIGxlbjxBZGRyZXNzPigpICsgbGVuPFZhbGlkYXRvclBvb2xLZXk+KCkgKiBNQVhfUE9PTFNfUEVSX1NUQUtFUgoJLy8gICAgICAgICAgICAgICAgICksIC8vIHNpemUgb2Yga2V5ICsgYWxsIHZhbHVlcwoJLy8gICAgICAgICB9OwoJaW50IDEwNjcKCWNhbGxzdWIgY29zdEZvckJveFN0b3JhZ2UKCWl0b2IKCWludCAxCglpbnQgOAoJaW50IDAKCWR1cG4gMwoJaW50IDEKCWNhbGxzdWIgbWluQmFsYW5jZUZvckFjY291bnQKCWl0b2IKCWNvbmNhdAoJaW50IDEwMDAwMAoJaW50IDEyODA3CgljYWxsc3ViIGNvc3RGb3JCb3hTdG9yYWdlCgkrCglpdG9iCgljb25jYXQKCWludCAxNzkKCWNhbGxzdWIgY29zdEZvckJveFN0b3JhZ2UKCWl0b2IKCWNvbmNhdAoJcmV0c3ViCgovLyBnZXRQcm90b2NvbENvbnN0cmFpbnRzKCkodWludDY0LHVpbnQ2NCx1aW50NjQsdWludDY0LHVpbnQ2NCx1aW50NjQsdWludDY0LHVpbnQ2NCx1aW50NjQsdWludDY0LHVpbnQ2NCkKKmFiaV9yb3V0ZV9nZXRQcm90b2NvbENvbnN0cmFpbnRzOgoJLy8gVGhlIEFCSSByZXR1cm4gcHJlZml4CglieXRlIDB4MTUxZjdjNzUKCgkvLyBleGVjdXRlIGdldFByb3RvY29sQ29uc3RyYWludHMoKSh1aW50NjQsdWludDY0LHVpbnQ2NCx1aW50NjQsdWludDY0LHVpbnQ2NCx1aW50NjQsdWludDY0LHVpbnQ2NCx1aW50NjQsdWludDY0KQoJY2FsbHN1YiBnZXRQcm90b2NvbENvbnN0cmFpbnRzCgljb25jYXQKCWxvZwoJaW50IDEKCXJldHVybgoKLy8gZ2V0UHJvdG9jb2xDb25zdHJhaW50cygpOiBDb25zdHJhaW50cwovLwovLyBSZXR1cm5zIHRoZSBwcm90b2NvbCBjb25zdHJhaW50cyBzbyB0aGF0IFVJcyBjYW4gbGltaXQgd2hhdCB1c2VycyBzcGVjaWZ5IGZvciB2YWxpZGF0b3IgY29uZmlndXJhdGlvbiBwYXJhbWV0ZXJzLgpnZXRQcm90b2NvbENvbnN0cmFpbnRzOgoJcHJvdG8gMCAxCgoJLy8gY29udHJhY3RzL3ZhbGlkYXRvclJlZ2lzdHJ5LmFsZ28udHM6MjQzCgkvLyByZXR1cm4gewoJLy8gICAgICAgICAgICAgZXBvY2hQYXlvdXRNaW5zTWluOiBNSU5fUEFZT1VUX01JTlMsCgkvLyAgICAgICAgICAgICBlcG9jaFBheW91dE1pbnNNYXg6IE1BWF9QQVlPVVRfTUlOUywKCS8vICAgICAgICAgICAgIG1pblBjdFRvVmFsaWRhdG9yV0ZvdXJEZWNpbWFsczogTUlOX1BDVF9UT19WQUxJREFUT1IsCgkvLyAgICAgICAgICAgICBtYXhQY3RUb1ZhbGlkYXRvcldGb3VyRGVjaW1hbHM6IE1BWF9QQ1RfVE9fVkFMSURBVE9SLAoJLy8gICAgICAgICAgICAgbWluRW50cnlTdGFrZTogTUlOX0FMR09fU1RBS0VfUEVSX1BPT0wsCgkvLyAgICAgICAgICAgICBtYXhBbGdvUGVyUG9vbDogdGhpcy5tYXhBbGdvQWxsb3dlZFBlclBvb2woKSwKCS8vICAgICAgICAgICAgIG1heEFsZ29QZXJWYWxpZGF0b3I6IHRoaXMubWF4QWxsb3dlZFN0YWtlKCksCgkvLyAgICAgICAgICAgICBhbXRDb25zaWRlcmVkU2F0dXJhdGVkOiB0aGlzLmFsZ29TYXR1cmF0aW9uTGV2ZWwoKSwKCS8vICAgICAgICAgICAgIG1heE5vZGVzOiBNQVhfTk9ERVMsCgkvLyAgICAgICAgICAgICBtYXhQb29sc1Blck5vZGU6IE1BWF9QT09MU19QRVJfTk9ERSwKCS8vICAgICAgICAgICAgIG1heFN0YWtlcnNQZXJQb29sOiBNQVhfU1RBS0VSU19QRVJfUE9PTCwKCS8vICAgICAgICAgfTsKCWJ5dGUgMHgwMDAwMDAwMDAwMDAwMDAxMDAwMDAwMDAwMDAwMjc2MDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMGY0MjQwMDAwMDAwMDAwMDBmNDI0MAoJY2FsbHN1YiBtYXhBbGdvQWxsb3dlZFBlclBvb2wKCWl0b2IKCWNvbmNhdAoJY2FsbHN1YiBtYXhBbGxvd2VkU3Rha2UKCWl0b2IKCWNvbmNhdAoJY2FsbHN1YiBhbGdvU2F0dXJhdGlvbkxldmVsCglpdG9iCgljb25jYXQKCWJ5dGUgMHgwMDAwMDAwMDAwMDAwMDA4Cgljb25jYXQKCWJ5dGUgMHgwMDAwMDAwMDAwMDAwMDAzCgljb25jYXQKCWJ5dGUgMHgwMDAwMDAwMDAwMDAwMGM4Cgljb25jYXQKCXJldHN1YgoKLy8gZ2V0TnVtVmFsaWRhdG9ycygpdWludDY0CiphYmlfcm91dGVfZ2V0TnVtVmFsaWRhdG9yczoKCS8vIFRoZSBBQkkgcmV0dXJuIHByZWZpeAoJYnl0ZSAweDE1MWY3Yzc1CgoJLy8gZXhlY3V0ZSBnZXROdW1WYWxpZGF0b3JzKCl1aW50NjQKCWNhbGxzdWIgZ2V0TnVtVmFsaWRhdG9ycwoJaXRvYgoJY29uY2F0Cglsb2cKCWludCAxCglyZXR1cm4KCi8vIGdldE51bVZhbGlkYXRvcnMoKTogdWludDY0Ci8vCi8vIFJldHVybnMgdGhlIGN1cnJlbnQgbnVtYmVyIG9mIHZhbGlkYXRvcnMKZ2V0TnVtVmFsaWRhdG9yczoKCXByb3RvIDAgMQoKCS8vIGNvbnRyYWN0cy92YWxpZGF0b3JSZWdpc3RyeS5hbGdvLnRzOjI2MwoJLy8gcmV0dXJuIHRoaXMubnVtVmFsaWRhdG9ycy52YWx1ZTsKCWJ5dGUgMHg2ZTc1NmQ1NiAvLyAibnVtViIKCWFwcF9nbG9iYWxfZ2V0CglyZXRzdWIKCi8vIGdldFZhbGlkYXRvckNvbmZpZyh1aW50NjQpKHVpbnQ2NCxhZGRyZXNzLGFkZHJlc3MsdWludDY0LHVpbnQ4LGJ5dGVbMzJdLHVpbnQ2NCx1aW50NjQsdWludDY0LHVpbnQxNix1aW50MzIsYWRkcmVzcyx1aW50NjQsdWludDY0LHVpbnQ4LHVpbnQ2NCx1aW50NjQpCiphYmlfcm91dGVfZ2V0VmFsaWRhdG9yQ29uZmlnOgoJLy8gVGhlIEFCSSByZXR1cm4gcHJlZml4CglieXRlIDB4MTUxZjdjNzUKCgkvLyB2YWxpZGF0b3JJZDogdWludDY0Cgl0eG5hIEFwcGxpY2F0aW9uQXJncyAxCglidG9pCgoJLy8gZXhlY3V0ZSBnZXRWYWxpZGF0b3JDb25maWcodWludDY0KSh1aW50NjQsYWRkcmVzcyxhZGRyZXNzLHVpbnQ2NCx1aW50OCxieXRlWzMyXSx1aW50NjQsdWludDY0LHVpbnQ2NCx1aW50MTYsdWludDMyLGFkZHJlc3MsdWludDY0LHVpbnQ2NCx1aW50OCx1aW50NjQsdWludDY0KQoJY2FsbHN1YiBnZXRWYWxpZGF0b3JDb25maWcKCWNvbmNhdAoJbG9nCglpbnQgMQoJcmV0dXJuCgovLyBnZXRWYWxpZGF0b3JDb25maWcodmFsaWRhdG9ySWQ6IFZhbGlkYXRvcklkVHlwZSk6IFZhbGlkYXRvckNvbmZpZwpnZXRWYWxpZGF0b3JDb25maWc6Cglwcm90byAxIDEKCgkvLyBjb250cmFjdHMvdmFsaWRhdG9yUmVnaXN0cnkuYWxnby50czoyNjgKCS8vIHJldHVybiB0aGlzLnZhbGlkYXRvckxpc3QodmFsaWRhdG9ySWQpLnZhbHVlLmNvbmZpZzsKCWludCAwCglpbnQgMjA4CglieXRlIDB4NzYgLy8gInYiCglmcmFtZV9kaWcgLTEgLy8gdmFsaWRhdG9ySWQ6IFZhbGlkYXRvcklkVHlwZQoJaXRvYgoJY29uY2F0Cgljb3ZlciAyCglib3hfZXh0cmFjdAoJcmV0c3ViCgovLyBnZXRWYWxpZGF0b3JTdGF0ZSh1aW50NjQpKHVpbnQxNix1aW50NjQsdWludDY0LHVpbnQ2NCkKKmFiaV9yb3V0ZV9nZXRWYWxpZGF0b3JTdGF0ZToKCS8vIFRoZSBBQkkgcmV0dXJuIHByZWZpeAoJYnl0ZSAweDE1MWY3Yzc1CgoJLy8gdmFsaWRhdG9ySWQ6IHVpbnQ2NAoJdHhuYSBBcHBsaWNhdGlvbkFyZ3MgMQoJYnRvaQoKCS8vIGV4ZWN1dGUgZ2V0VmFsaWRhdG9yU3RhdGUodWludDY0KSh1aW50MTYsdWludDY0LHVpbnQ2NCx1aW50NjQpCgljYWxsc3ViIGdldFZhbGlkYXRvclN0YXRlCgljb25jYXQKCWxvZwoJaW50IDEKCXJldHVybgoKLy8gZ2V0VmFsaWRhdG9yU3RhdGUodmFsaWRhdG9ySWQ6IFZhbGlkYXRvcklkVHlwZSk6IFZhbGlkYXRvckN1clN0YXRlCmdldFZhbGlkYXRvclN0YXRlOgoJcHJvdG8gMSAxCgoJLy8gY29udHJhY3RzL3ZhbGlkYXRvclJlZ2lzdHJ5LmFsZ28udHM6MjczCgkvLyByZXR1cm4gdGhpcy52YWxpZGF0b3JMaXN0KHZhbGlkYXRvcklkKS52YWx1ZS5zdGF0ZTsKCWludCAyMDggLy8gaGVhZE9mZnNldAoJaW50IDI2CglieXRlIDB4NzYgLy8gInYiCglmcmFtZV9kaWcgLTEgLy8gdmFsaWRhdG9ySWQ6IFZhbGlkYXRvcklkVHlwZQoJaXRvYgoJY29uY2F0Cgljb3ZlciAyCglib3hfZXh0cmFjdAoJcmV0c3ViCgovLyBnZXRWYWxpZGF0b3JPd25lckFuZE1hbmFnZXIodWludDY0KShhZGRyZXNzLGFkZHJlc3MpCiphYmlfcm91dGVfZ2V0VmFsaWRhdG9yT3duZXJBbmRNYW5hZ2VyOgoJLy8gVGhlIEFCSSByZXR1cm4gcHJlZml4CglieXRlIDB4MTUxZjdjNzUKCgkvLyB2YWxpZGF0b3JJZDogdWludDY0Cgl0eG5hIEFwcGxpY2F0aW9uQXJncyAxCglidG9pCgoJLy8gZXhlY3V0ZSBnZXRWYWxpZGF0b3JPd25lckFuZE1hbmFnZXIodWludDY0KShhZGRyZXNzLGFkZHJlc3MpCgljYWxsc3ViIGdldFZhbGlkYXRvck93bmVyQW5kTWFuYWdlcgoJY29uY2F0Cglsb2cKCWludCAxCglyZXR1cm4KCi8vIGdldFZhbGlkYXRvck93bmVyQW5kTWFuYWdlcih2YWxpZGF0b3JJZDogVmFsaWRhdG9ySWRUeXBlKTogW0FkZHJlc3MsIEFkZHJlc3NdCmdldFZhbGlkYXRvck93bmVyQW5kTWFuYWdlcjoKCXByb3RvIDEgMQoKCS8vIGNvbnRyYWN0cy92YWxpZGF0b3JSZWdpc3RyeS5hbGdvLnRzOjI3OAoJLy8gcmV0dXJuIFsKCS8vICAgICAgICAgICAgIHRoaXMudmFsaWRhdG9yTGlzdCh2YWxpZGF0b3JJZCkudmFsdWUuY29uZmlnLm93bmVyLAoJLy8gICAgICAgICAgICAgdGhpcy52YWxpZGF0b3JMaXN0KHZhbGlkYXRvcklkKS52YWx1ZS5jb25maWcubWFuYWdlciwKCS8vICAgICAgICAgXTsKCWludCA4CglpbnQgMzIKCWJ5dGUgMHg3NiAvLyAidiIKCWZyYW1lX2RpZyAtMSAvLyB2YWxpZGF0b3JJZDogVmFsaWRhdG9ySWRUeXBlCglpdG9iCgljb25jYXQKCWNvdmVyIDIKCWJveF9leHRyYWN0CglpbnQgNDAKCWludCAzMgoJYnl0ZSAweDc2IC8vICJ2IgoJZnJhbWVfZGlnIC0xIC8vIHZhbGlkYXRvcklkOiBWYWxpZGF0b3JJZFR5cGUKCWl0b2IKCWNvbmNhdAoJY292ZXIgMgoJYm94X2V4dHJhY3QKCWNvbmNhdAoJcmV0c3ViCgovLyBnZXRQb29scyh1aW50NjQpKHVpbnQ2NCx1aW50MTYsdWludDY0KVtdCiphYmlfcm91dGVfZ2V0UG9vbHM6CgkvLyBUaGUgQUJJIHJldHVybiBwcmVmaXgKCWJ5dGUgMHgxNTFmN2M3NQoKCS8vIHZhbGlkYXRvcklkOiB1aW50NjQKCXR4bmEgQXBwbGljYXRpb25BcmdzIDEKCWJ0b2kKCgkvLyBleGVjdXRlIGdldFBvb2xzKHVpbnQ2NCkodWludDY0LHVpbnQxNix1aW50NjQpW10KCWNhbGxzdWIgZ2V0UG9vbHMKCWR1cAoJbGVuCglpbnQgMTgKCS8KCWl0b2IKCWV4dHJhY3QgNiAyCglzd2FwCgljb25jYXQKCWNvbmNhdAoJbG9nCglpbnQgMQoJcmV0dXJuCgovLyBnZXRQb29scyh2YWxpZGF0b3JJZDogVmFsaWRhdG9ySWRUeXBlKTogUG9vbEluZm9bXQovLwovLyBSZXR1cm4gbGlzdCBvZiBhbGwgcG9vbHMgZm9yIHRoaXMgdmFsaWRhdG9yLgovLyBAcGFyYW0ge3VpbnQ2NH0gdmFsaWRhdG9ySWQKLy8gQHJldHVybiB7UG9vbEluZm9bXX0gLSBhcnJheSBvZiBwb29scwovLyBOb3QgY2FsbGFibGUgZnJvbSBvdGhlciBjb250cmFjdHMgYmVjYXVzZSA+MUsgcmV0dXJuIGJ1dCBjYW4gYmUgY2FsbGVkIHcvIHNpbXVsYXRlIHdoaWNoIGJ1bXBzIGxvZyByZXR1cm5zCmdldFBvb2xzOgoJcHJvdG8gMSAxCgoJLy8gUHVzaCBlbXB0eSBieXRlcyBhZnRlciB0aGUgZnJhbWUgcG9pbnRlciB0byByZXNlcnZlIHNwYWNlIGZvciBsb2NhbCB2YXJpYWJsZXMKCWJ5dGUgMHgKCWR1cG4gMgoKCS8vIGNvbnRyYWN0cy92YWxpZGF0b3JSZWdpc3RyeS5hbGdvLnRzOjI5MgoJLy8gcmV0RGF0YTogUG9vbEluZm9bXSA9IFtdCglieXRlIDB4CglmcmFtZV9idXJ5IDAgLy8gcmV0RGF0YTogUG9vbEluZm9bXQoKCS8vIGNvbnRyYWN0cy92YWxpZGF0b3JSZWdpc3RyeS5hbGdvLnRzOjI5MwoJLy8gcG9vbFNldCA9IGNsb25lKHRoaXMudmFsaWRhdG9yTGlzdCh2YWxpZGF0b3JJZCkudmFsdWUucG9vbHMpCglpbnQgMjM0IC8vIGhlYWRPZmZzZXQKCWludCA0MzIKCWJ5dGUgMHg3NiAvLyAidiIKCWZyYW1lX2RpZyAtMSAvLyB2YWxpZGF0b3JJZDogVmFsaWRhdG9ySWRUeXBlCglpdG9iCgljb25jYXQKCWNvdmVyIDIKCWJveF9leHRyYWN0CglmcmFtZV9idXJ5IDEgLy8gcG9vbFNldDogKHVpbnQ2NCx1aW50MTYsdWludDY0KVsyNF0KCgkvLyBjb250cmFjdHMvdmFsaWRhdG9yUmVnaXN0cnkuYWxnby50czoyOTQKCS8vIGZvciAobGV0IGkgPSAwOyBpIDwgcG9vbFNldC5sZW5ndGg7IGkgKz0gMSkKCWludCAwCglmcmFtZV9idXJ5IDIgLy8gaTogdWludDY0CgoqZm9yXzA6CgkvLyBjb250cmFjdHMvdmFsaWRhdG9yUmVnaXN0cnkuYWxnby50czoyOTQKCS8vIGkgPCBwb29sU2V0Lmxlbmd0aAoJZnJhbWVfZGlnIDIgLy8gaTogdWludDY0CglpbnQgMjQKCTwKCWJ6ICpmb3JfMF9lbmQKCgkvLyAqaWYwX2NvbmRpdGlvbgoJLy8gY29udHJhY3RzL3ZhbGlkYXRvclJlZ2lzdHJ5LmFsZ28udHM6Mjk1CgkvLyBwb29sU2V0W2ldLnBvb2xBcHBJZCA9PT0gMAoJZnJhbWVfZGlnIDEgLy8gcG9vbFNldDogKHVpbnQ2NCx1aW50MTYsdWludDY0KVsyNF0KCWZyYW1lX2RpZyAyIC8vIGk6IHVpbnQ2NAoJaW50IDE4CgkqIC8vIGFjYyAqIHR5cGVMZW5ndGgKCWludCAwCgkrCglpbnQgOAoJZXh0cmFjdDMKCWJ0b2kKCWludCAwCgk9PQoJYnogKmlmMF9lbmQKCgkvLyAqaWYwX2NvbnNlcXVlbnQKCWIgKmZvcl8wX2VuZAoKKmlmMF9lbmQ6CgkvLyBjb250cmFjdHMvdmFsaWRhdG9yUmVnaXN0cnkuYWxnby50czoyOTkKCS8vIHJldERhdGEucHVzaChwb29sU2V0W2ldKQoJZnJhbWVfZGlnIDAgLy8gcmV0RGF0YTogUG9vbEluZm9bXQoJZnJhbWVfZGlnIDEgLy8gcG9vbFNldDogKHVpbnQ2NCx1aW50MTYsdWludDY0KVsyNF0KCWZyYW1lX2RpZyAyIC8vIGk6IHVpbnQ2NAoJaW50IDE4CgkqIC8vIGFjYyAqIHR5cGVMZW5ndGgKCWludCAxOAoJZXh0cmFjdDMKCWNvbmNhdAoJZnJhbWVfYnVyeSAwIC8vIHJldERhdGE6IFBvb2xJbmZvW10KCipmb3JfMF9jb250aW51ZToKCS8vIGNvbnRyYWN0cy92YWxpZGF0b3JSZWdpc3RyeS5hbGdvLnRzOjI5NAoJLy8gaSArPSAxCglmcmFtZV9kaWcgMiAvLyBpOiB1aW50NjQKCWludCAxCgkrCglmcmFtZV9idXJ5IDIgLy8gaTogdWludDY0CgliICpmb3JfMAoKKmZvcl8wX2VuZDoKCS8vIGNvbnRyYWN0cy92YWxpZGF0b3JSZWdpc3RyeS5hbGdvLnRzOjMwMQoJLy8gcmV0dXJuIHJldERhdGE7CglmcmFtZV9kaWcgMCAvLyByZXREYXRhOiBQb29sSW5mb1tdCgoJLy8gc2V0IHRoZSBzdWJyb3V0aW5lIHJldHVybiB2YWx1ZQoJZnJhbWVfYnVyeSAwCgoJLy8gcG9wIGFsbCBsb2NhbCB2YXJpYWJsZXMgZnJvbSB0aGUgc3RhY2sKCXBvcG4gMgoJcmV0c3ViCgovLyBnZXRQb29sQXBwSWQodWludDY0LHVpbnQ2NCl1aW50NjQKKmFiaV9yb3V0ZV9nZXRQb29sQXBwSWQ6CgkvLyBUaGUgQUJJIHJldHVybiBwcmVmaXgKCWJ5dGUgMHgxNTFmN2M3NQoKCS8vIHBvb2xJZDogdWludDY0Cgl0eG5hIEFwcGxpY2F0aW9uQXJncyAyCglidG9pCgoJLy8gdmFsaWRhdG9ySWQ6IHVpbnQ2NAoJdHhuYSBBcHBsaWNhdGlvbkFyZ3MgMQoJYnRvaQoKCS8vIGV4ZWN1dGUgZ2V0UG9vbEFwcElkKHVpbnQ2NCx1aW50NjQpdWludDY0CgljYWxsc3ViIGdldFBvb2xBcHBJZAoJaXRvYgoJY29uY2F0Cglsb2cKCWludCAxCglyZXR1cm4KCi8vIGdldFBvb2xBcHBJZCh2YWxpZGF0b3JJZDogdWludDY0LCBwb29sSWQ6IHVpbnQ2NCk6IHVpbnQ2NApnZXRQb29sQXBwSWQ6Cglwcm90byAyIDEKCgkvLyBjb250cmFjdHMvdmFsaWRhdG9yUmVnaXN0cnkuYWxnby50czozMDkKCS8vIGFzc2VydChwb29sSWQgIT09IDAgJiYgcG9vbElkIDw9IHRoaXMudmFsaWRhdG9yTGlzdCh2YWxpZGF0b3JJZCkudmFsdWUucG9vbHMubGVuZ3RoKQoJZnJhbWVfZGlnIC0yIC8vIHBvb2xJZDogdWludDY0CglpbnQgMAoJIT0KCWR1cAoJYnogKnNraXBfYW5kMAoJZnJhbWVfZGlnIC0yIC8vIHBvb2xJZDogdWludDY0CglpbnQgMjQKCTw9CgkmJgoKKnNraXBfYW5kMDoKCWFzc2VydAoKCS8vIGNvbnRyYWN0cy92YWxpZGF0b3JSZWdpc3RyeS5hbGdvLnRzOjMxMAoJLy8gcmV0dXJuIHRoaXMudmFsaWRhdG9yTGlzdCh2YWxpZGF0b3JJZCkudmFsdWUucG9vbHNbcG9vbElkIC0gMV0ucG9vbEFwcElkOwoJaW50IDIzNCAvLyBoZWFkT2Zmc2V0CglmcmFtZV9kaWcgLTIgLy8gcG9vbElkOiB1aW50NjQKCWludCAxCgktCglpbnQgMTgKCSogLy8gYWNjICogdHlwZUxlbmd0aAoJKwoJaW50IDAKCSsKCWludCA4CglieXRlIDB4NzYgLy8gInYiCglmcmFtZV9kaWcgLTEgLy8gdmFsaWRhdG9ySWQ6IHVpbnQ2NAoJaXRvYgoJY29uY2F0Cgljb3ZlciAyCglib3hfZXh0cmFjdAoJYnRvaQoJcmV0c3ViCgovLyBnZXRQb29sSW5mbygodWludDY0LHVpbnQ2NCx1aW50NjQpKSh1aW50NjQsdWludDE2LHVpbnQ2NCkKKmFiaV9yb3V0ZV9nZXRQb29sSW5mbzoKCS8vIFRoZSBBQkkgcmV0dXJuIHByZWZpeAoJYnl0ZSAweDE1MWY3Yzc1CgoJLy8gcG9vbEtleTogKHVpbnQ2NCx1aW50NjQsdWludDY0KQoJdHhuYSBBcHBsaWNhdGlvbkFyZ3MgMQoJZHVwCglsZW4KCWludCAyNAoJPT0KCWFzc2VydAoKCS8vIGV4ZWN1dGUgZ2V0UG9vbEluZm8oKHVpbnQ2NCx1aW50NjQsdWludDY0KSkodWludDY0LHVpbnQxNix1aW50NjQpCgljYWxsc3ViIGdldFBvb2xJbmZvCgljb25jYXQKCWxvZwoJaW50IDEKCXJldHVybgoKLy8gZ2V0UG9vbEluZm8ocG9vbEtleTogVmFsaWRhdG9yUG9vbEtleSk6IFBvb2xJbmZvCmdldFBvb2xJbmZvOgoJcHJvdG8gMSAxCgoJLy8gY29udHJhY3RzL3ZhbGlkYXRvclJlZ2lzdHJ5LmFsZ28udHM6MzE1CgkvLyByZXR1cm4gdGhpcy52YWxpZGF0b3JMaXN0KHBvb2xLZXkuaWQpLnZhbHVlLnBvb2xzW3Bvb2xLZXkucG9vbElkIC0gMV07CglpbnQgMjM0IC8vIGhlYWRPZmZzZXQKCWZyYW1lX2RpZyAtMSAvLyBwb29sS2V5OiBWYWxpZGF0b3JQb29sS2V5CglleHRyYWN0IDggOAoJYnRvaQoJaW50IDEKCS0KCWludCAxOAoJKiAvLyBhY2MgKiB0eXBlTGVuZ3RoCgkrCglpbnQgMTgKCWJ5dGUgMHg3NiAvLyAidiIKCWZyYW1lX2RpZyAtMSAvLyBwb29sS2V5OiBWYWxpZGF0b3JQb29sS2V5CglleHRyYWN0IDAgOAoJYnRvaQoJaXRvYgoJY29uY2F0Cgljb3ZlciAyCglib3hfZXh0cmFjdAoJcmV0c3ViCgovLyBnZXRDdXJNYXhTdGFrZVBlclBvb2wodWludDY0KXVpbnQ2NAoqYWJpX3JvdXRlX2dldEN1ck1heFN0YWtlUGVyUG9vbDoKCS8vIFRoZSBBQkkgcmV0dXJuIHByZWZpeAoJYnl0ZSAweDE1MWY3Yzc1CgoJLy8gdmFsaWRhdG9ySWQ6IHVpbnQ2NAoJdHhuYSBBcHBsaWNhdGlvbkFyZ3MgMQoJYnRvaQoKCS8vIGV4ZWN1dGUgZ2V0Q3VyTWF4U3Rha2VQZXJQb29sKHVpbnQ2NCl1aW50NjQKCWNhbGxzdWIgZ2V0Q3VyTWF4U3Rha2VQZXJQb29sCglpdG9iCgljb25jYXQKCWxvZwoJaW50IDEKCXJldHVybgoKLy8gZ2V0Q3VyTWF4U3Rha2VQZXJQb29sKHZhbGlkYXRvcklkOiBWYWxpZGF0b3JJZFR5cGUpOiB1aW50NjQKLy8KLy8gQ2FsY3VsYXRlIHRoZSBtYXhpbXVtIHN0YWtlIHBlciBwb29sIGZvciBhIGdpdmVuIHZhbGlkYXRvci4KLy8gTm9ybWFsbHkgdGhpcyB3b3VsZCBiZSBtYXhBbGdvUGVyUG9vbCwgYnV0IGl0IHNob3VsZCBhbHNvIG5ldmVyIGdvIGFib3ZlIE1heEFsbG93ZWRTdGFrZSAvIG51bVBvb2xzIHNvCi8vIGFzIHBvb2xzIGFyZSBhZGRlZCB0aGUgbWF4IGFsbG93ZWQgcGVyIHBvb2wgY2FuIHJlZHVjZS4KLy8KLy8gQHBhcmFtIHtWYWxpZGF0b3JJZFR5cGV9IHZhbGlkYXRvcklkIC0gVGhlIGlkIG9mIHRoZSB2YWxpZGF0b3IuCmdldEN1ck1heFN0YWtlUGVyUG9vbDoKCXByb3RvIDEgMQoKCS8vIFB1c2ggZW1wdHkgYnl0ZXMgYWZ0ZXIgdGhlIGZyYW1lIHBvaW50ZXIgdG8gcmVzZXJ2ZSBzcGFjZSBmb3IgbG9jYWwgdmFyaWFibGVzCglieXRlIDB4CglkdXBuIDIKCgkvLyBjb250cmFjdHMvdmFsaWRhdG9yUmVnaXN0cnkuYWxnby50czozMjYKCS8vIG51bVBvb2xzID0gdGhpcy52YWxpZGF0b3JMaXN0KHZhbGlkYXRvcklkKS52YWx1ZS5zdGF0ZS5udW1Qb29scyBhcyB1aW50NjQKCWludCAyMDgKCWludCAyCglieXRlIDB4NzYgLy8gInYiCglmcmFtZV9kaWcgLTEgLy8gdmFsaWRhdG9ySWQ6IFZhbGlkYXRvcklkVHlwZQoJaXRvYgoJY29uY2F0Cgljb3ZlciAyCglib3hfZXh0cmFjdAoJYnRvaQoJZnJhbWVfYnVyeSAwIC8vIG51bVBvb2xzOiB1aW50NjQKCgkvLyBjb250cmFjdHMvdmFsaWRhdG9yUmVnaXN0cnkuYWxnby50czozMjcKCS8vIGhhcmRNYXhEaXZpZGVkQmV0d2VlblBvb2xzID0gdGhpcy5tYXhBbGxvd2VkU3Rha2UoKSAvIG51bVBvb2xzCgljYWxsc3ViIG1heEFsbG93ZWRTdGFrZQoJZnJhbWVfZGlnIDAgLy8gbnVtUG9vbHM6IHVpbnQ2NAoJLwoJZnJhbWVfYnVyeSAxIC8vIGhhcmRNYXhEaXZpZGVkQmV0d2VlblBvb2xzOiB1aW50NjQKCgkvLyBjb250cmFjdHMvdmFsaWRhdG9yUmVnaXN0cnkuYWxnby50czozMjgKCS8vIG1heFBlclBvb2w6IHVpbnQ2NCA9IHRoaXMudmFsaWRhdG9yTGlzdCh2YWxpZGF0b3JJZCkudmFsdWUuY29uZmlnLm1heEFsZ29QZXJQb29sCglpbnQgMTgzCglpbnQgOAoJYnl0ZSAweDc2IC8vICJ2IgoJZnJhbWVfZGlnIC0xIC8vIHZhbGlkYXRvcklkOiBWYWxpZGF0b3JJZFR5cGUKCWl0b2IKCWNvbmNhdAoJY292ZXIgMgoJYm94X2V4dHJhY3QKCWJ0b2kKCWZyYW1lX2J1cnkgMiAvLyBtYXhQZXJQb29sOiB1aW50NjQKCgkvLyAqaWYxX2NvbmRpdGlvbgoJLy8gY29udHJhY3RzL3ZhbGlkYXRvclJlZ2lzdHJ5LmFsZ28udHM6MzI5CgkvLyBtYXhQZXJQb29sID09PSAwCglmcmFtZV9kaWcgMiAvLyBtYXhQZXJQb29sOiB1aW50NjQKCWludCAwCgk9PQoJYnogKmlmMV9lbmQKCgkvLyAqaWYxX2NvbnNlcXVlbnQKCS8vIGNvbnRyYWN0cy92YWxpZGF0b3JSZWdpc3RyeS5hbGdvLnRzOjMzMAoJLy8gbWF4UGVyUG9vbCA9IHRoaXMubWF4QWxnb0FsbG93ZWRQZXJQb29sKCkKCWNhbGxzdWIgbWF4QWxnb0FsbG93ZWRQZXJQb29sCglmcmFtZV9idXJ5IDIgLy8gbWF4UGVyUG9vbDogdWludDY0CgoqaWYxX2VuZDoKCS8vICppZjJfY29uZGl0aW9uCgkvLyBjb250cmFjdHMvdmFsaWRhdG9yUmVnaXN0cnkuYWxnby50czozMzIKCS8vIGhhcmRNYXhEaXZpZGVkQmV0d2VlblBvb2xzIDwgbWF4UGVyUG9vbAoJZnJhbWVfZGlnIDEgLy8gaGFyZE1heERpdmlkZWRCZXR3ZWVuUG9vbHM6IHVpbnQ2NAoJZnJhbWVfZGlnIDIgLy8gbWF4UGVyUG9vbDogdWludDY0Cgk8CglieiAqaWYyX2VuZAoKCS8vICppZjJfY29uc2VxdWVudAoJLy8gY29udHJhY3RzL3ZhbGlkYXRvclJlZ2lzdHJ5LmFsZ28udHM6MzMzCgkvLyBtYXhQZXJQb29sID0gaGFyZE1heERpdmlkZWRCZXR3ZWVuUG9vbHMKCWZyYW1lX2RpZyAxIC8vIGhhcmRNYXhEaXZpZGVkQmV0d2VlblBvb2xzOiB1aW50NjQKCWZyYW1lX2J1cnkgMiAvLyBtYXhQZXJQb29sOiB1aW50NjQKCippZjJfZW5kOgoJLy8gY29udHJhY3RzL3ZhbGlkYXRvclJlZ2lzdHJ5LmFsZ28udHM6MzM1CgkvLyByZXR1cm4gbWF4UGVyUG9vbDsKCWZyYW1lX2RpZyAyIC8vIG1heFBlclBvb2w6IHVpbnQ2NAoKCS8vIHNldCB0aGUgc3Vicm91dGluZSByZXR1cm4gdmFsdWUKCWZyYW1lX2J1cnkgMAoKCS8vIHBvcCBhbGwgbG9jYWwgdmFyaWFibGVzIGZyb20gdGhlIHN0YWNrCglwb3BuIDIKCXJldHN1YgoKLy8gZG9lc1N0YWtlck5lZWRUb1BheU1CUihhZGRyZXNzKWJvb2wKKmFiaV9yb3V0ZV9kb2VzU3Rha2VyTmVlZFRvUGF5TUJSOgoJLy8gVGhlIEFCSSByZXR1cm4gcHJlZml4CglieXRlIDB4MTUxZjdjNzUKCgkvLyBzdGFrZXI6IGFkZHJlc3MKCXR4bmEgQXBwbGljYXRpb25BcmdzIDEKCWR1cAoJbGVuCglpbnQgMzIKCT09Cglhc3NlcnQKCgkvLyBleGVjdXRlIGRvZXNTdGFrZXJOZWVkVG9QYXlNQlIoYWRkcmVzcylib29sCgljYWxsc3ViIGRvZXNTdGFrZXJOZWVkVG9QYXlNQlIKCWJ5dGUgMHgwMAoJaW50IDAKCXVuY292ZXIgMgoJc2V0Yml0Cgljb25jYXQKCWxvZwoJaW50IDEKCXJldHVybgoKLy8gZG9lc1N0YWtlck5lZWRUb1BheU1CUihzdGFrZXI6IEFkZHJlc3MpOiBib29sZWFuCi8vCi8vIEhlbHBlciBjYWxsZXJzIGNhbiBjYWxsIHcvIHNpbXVsYXRlIHRvIGRldGVybWluZSBpZiAnQWRkU3Rha2VyJyBNQlIgc2hvdWxkIGJlIGluY2x1ZGVkIHcvIHN0YWtpbmcgYW1vdW50Ci8vIEBwYXJhbSBzdGFrZXIKZG9lc1N0YWtlck5lZWRUb1BheU1CUjoKCXByb3RvIDEgMQoKCS8vIGNvbnRyYWN0cy92YWxpZGF0b3JSZWdpc3RyeS5hbGdvLnRzOjM0NAoJLy8gcmV0dXJuICF0aGlzLnN0YWtlclBvb2xTZXQoc3Rha2VyKS5leGlzdHM7CglieXRlIDB4NzM3MDczIC8vICJzcHMiCglmcmFtZV9kaWcgLTEgLy8gc3Rha2VyOiBBZGRyZXNzCgljb25jYXQKCWJveF9sZW4KCXN3YXAKCXBvcAoJIQoJcmV0c3ViCgovLyBnZXRTdGFrZWRQb29sc0ZvckFjY291bnQoYWRkcmVzcykodWludDY0LHVpbnQ2NCx1aW50NjQpW10KKmFiaV9yb3V0ZV9nZXRTdGFrZWRQb29sc0ZvckFjY291bnQ6CgkvLyBUaGUgQUJJIHJldHVybiBwcmVmaXgKCWJ5dGUgMHgxNTFmN2M3NQoKCS8vIHN0YWtlcjogYWRkcmVzcwoJdHhuYSBBcHBsaWNhdGlvbkFyZ3MgMQoJZHVwCglsZW4KCWludCAzMgoJPT0KCWFzc2VydAoKCS8vIGV4ZWN1dGUgZ2V0U3Rha2VkUG9vbHNGb3JBY2NvdW50KGFkZHJlc3MpKHVpbnQ2NCx1aW50NjQsdWludDY0KVtdCgljYWxsc3ViIGdldFN0YWtlZFBvb2xzRm9yQWNjb3VudAoJZHVwCglsZW4KCWludCAyNAoJLwoJaXRvYgoJZXh0cmFjdCA2IDIKCXN3YXAKCWNvbmNhdAoJY29uY2F0Cglsb2cKCWludCAxCglyZXR1cm4KCi8vIGdldFN0YWtlZFBvb2xzRm9yQWNjb3VudChzdGFrZXI6IEFkZHJlc3MpOiBWYWxpZGF0b3JQb29sS2V5W10KLy8KLy8gUmV0cmlldmVzIHRoZSBzdGFrZWQgcG9vbHMgZm9yIGFuIGFjY291bnQuCi8vCi8vIEBwYXJhbSB7QWRkcmVzc30gc3Rha2VyIC0gVGhlIGFjY291bnQgdG8gcmV0cmlldmUgc3Rha2VkIHBvb2xzIGZvci4KLy8gQHJldHVybiB7VmFsaWRhdG9yUG9vbEtleVtdfSAtIFRoZSBhcnJheSBvZiBzdGFrZWQgcG9vbHMgZm9yIHRoZSBhY2NvdW50LgpnZXRTdGFrZWRQb29sc0ZvckFjY291bnQ6Cglwcm90byAxIDEKCgkvLyBQdXNoIGVtcHR5IGJ5dGVzIGFmdGVyIHRoZSBmcmFtZSBwb2ludGVyIHRvIHJlc2VydmUgc3BhY2UgZm9yIGxvY2FsIHZhcmlhYmxlcwoJYnl0ZSAweAoJZHVwbiAyCgoJLy8gKmlmM19jb25kaXRpb24KCS8vIGNvbnRyYWN0cy92YWxpZGF0b3JSZWdpc3RyeS5hbGdvLnRzOjM1NAoJLy8gIXRoaXMuc3Rha2VyUG9vbFNldChzdGFrZXIpLmV4aXN0cwoJYnl0ZSAweDczNzA3MyAvLyAic3BzIgoJZnJhbWVfZGlnIC0xIC8vIHN0YWtlcjogQWRkcmVzcwoJY29uY2F0Cglib3hfbGVuCglzd2FwCglwb3AKCSEKCWJ6ICppZjNfZW5kCgoJLy8gKmlmM19jb25zZXF1ZW50CgkvLyBjb250cmFjdHMvdmFsaWRhdG9yUmVnaXN0cnkuYWxnby50czozNTUKCS8vIHJldHVybiBbXTsKCWJ5dGUgMHgKCXJldHN1YgoKKmlmM19lbmQ6CgkvLyBjb250cmFjdHMvdmFsaWRhdG9yUmVnaXN0cnkuYWxnby50czozNTcKCS8vIHJldERhdGE6IFZhbGlkYXRvclBvb2xLZXlbXSA9IFtdCglieXRlIDB4CglmcmFtZV9idXJ5IDAgLy8gcmV0RGF0YTogVmFsaWRhdG9yUG9vbEtleVtdCgoJLy8gY29udHJhY3RzL3ZhbGlkYXRvclJlZ2lzdHJ5LmFsZ28udHM6MzU4CgkvLyBwb29sU2V0ID0gY2xvbmUodGhpcy5zdGFrZXJQb29sU2V0KHN0YWtlcikudmFsdWUpCglieXRlIDB4NzM3MDczIC8vICJzcHMiCglmcmFtZV9kaWcgLTEgLy8gc3Rha2VyOiBBZGRyZXNzCgljb25jYXQKCWJveF9nZXQKCWFzc2VydAoJZnJhbWVfYnVyeSAxIC8vIHBvb2xTZXQ6ICh1aW50NjQsdWludDY0LHVpbnQ2NClbNl0KCgkvLyBjb250cmFjdHMvdmFsaWRhdG9yUmVnaXN0cnkuYWxnby50czozNTkKCS8vIGZvciAobGV0IGkgPSAwOyBpIDwgcG9vbFNldC5sZW5ndGg7IGkgKz0gMSkKCWludCAwCglmcmFtZV9idXJ5IDIgLy8gaTogdWludDY0CgoqZm9yXzE6CgkvLyBjb250cmFjdHMvdmFsaWRhdG9yUmVnaXN0cnkuYWxnby50czozNTkKCS8vIGkgPCBwb29sU2V0Lmxlbmd0aAoJZnJhbWVfZGlnIDIgLy8gaTogdWludDY0CglpbnQgNgoJPAoJYnogKmZvcl8xX2VuZAoKCS8vICppZjRfY29uZGl0aW9uCgkvLyBjb250cmFjdHMvdmFsaWRhdG9yUmVnaXN0cnkuYWxnby50czozNjAKCS8vIHBvb2xTZXRbaV0uaWQgIT09IDAKCWZyYW1lX2RpZyAxIC8vIHBvb2xTZXQ6ICh1aW50NjQsdWludDY0LHVpbnQ2NClbNl0KCWZyYW1lX2RpZyAyIC8vIGk6IHVpbnQ2NAoJaW50IDI0CgkqIC8vIGFjYyAqIHR5cGVMZW5ndGgKCWludCAwCgkrCglpbnQgOAoJZXh0cmFjdDMKCWJ0b2kKCWludCAwCgkhPQoJYnogKmlmNF9lbmQKCgkvLyAqaWY0X2NvbnNlcXVlbnQKCS8vIGNvbnRyYWN0cy92YWxpZGF0b3JSZWdpc3RyeS5hbGdvLnRzOjM2MQoJLy8gcmV0RGF0YS5wdXNoKHBvb2xTZXRbaV0pCglmcmFtZV9kaWcgMCAvLyByZXREYXRhOiBWYWxpZGF0b3JQb29sS2V5W10KCWZyYW1lX2RpZyAxIC8vIHBvb2xTZXQ6ICh1aW50NjQsdWludDY0LHVpbnQ2NClbNl0KCWZyYW1lX2RpZyAyIC8vIGk6IHVpbnQ2NAoJaW50IDI0CgkqIC8vIGFjYyAqIHR5cGVMZW5ndGgKCWludCAyNAoJZXh0cmFjdDMKCWNvbmNhdAoJZnJhbWVfYnVyeSAwIC8vIHJldERhdGE6IFZhbGlkYXRvclBvb2xLZXlbXQoKKmlmNF9lbmQ6CgoqZm9yXzFfY29udGludWU6CgkvLyBjb250cmFjdHMvdmFsaWRhdG9yUmVnaXN0cnkuYWxnby50czozNTkKCS8vIGkgKz0gMQoJZnJhbWVfZGlnIDIgLy8gaTogdWludDY0CglpbnQgMQoJKwoJZnJhbWVfYnVyeSAyIC8vIGk6IHVpbnQ2NAoJYiAqZm9yXzEKCipmb3JfMV9lbmQ6CgkvLyBjb250cmFjdHMvdmFsaWRhdG9yUmVnaXN0cnkuYWxnby50czozNjQKCS8vIHJldHVybiByZXREYXRhOwoJZnJhbWVfZGlnIDAgLy8gcmV0RGF0YTogVmFsaWRhdG9yUG9vbEtleVtdCgoJLy8gc2V0IHRoZSBzdWJyb3V0aW5lIHJldHVybiB2YWx1ZQoJZnJhbWVfYnVyeSAwCgoJLy8gcG9wIGFsbCBsb2NhbCB2YXJpYWJsZXMgZnJvbSB0aGUgc3RhY2sKCXBvcG4gMgoJcmV0c3ViCgovLyBnZXRUb2tlblBheW91dFJhdGlvKHVpbnQ2NCkodWludDY0WzI0XSx1aW50NjQpCiphYmlfcm91dGVfZ2V0VG9rZW5QYXlvdXRSYXRpbzoKCS8vIFRoZSBBQkkgcmV0dXJuIHByZWZpeAoJYnl0ZSAweDE1MWY3Yzc1CgoJLy8gdmFsaWRhdG9ySWQ6IHVpbnQ2NAoJdHhuYSBBcHBsaWNhdGlvbkFyZ3MgMQoJYnRvaQoKCS8vIGV4ZWN1dGUgZ2V0VG9rZW5QYXlvdXRSYXRpbyh1aW50NjQpKHVpbnQ2NFsyNF0sdWludDY0KQoJY2FsbHN1YiBnZXRUb2tlblBheW91dFJhdGlvCgljb25jYXQKCWxvZwoJaW50IDEKCXJldHVybgoKLy8gZ2V0VG9rZW5QYXlvdXRSYXRpbyh2YWxpZGF0b3JJZDogVmFsaWRhdG9ySWRUeXBlKTogUG9vbFRva2VuUGF5b3V0UmF0aW8KLy8KLy8gUmV0cmlldmVzIHRoZSB0b2tlbiBwYXlvdXQgcmF0aW8gZm9yIGEgZ2l2ZW4gdmFsaWRhdG9yIC0gcmV0dXJuaW5nIHRoZSBwb29sIHJhdGlvcyBvZiB3aG9sZSBzbyB0aGF0IHRva2VuCi8vIHBheW91dHMgYWNyb3NzIHBvb2xzIGNhbiBiZSBiYXNlZCBvbiBhIHN0YWJsZSBzbmFwaG9zdCBvZiBzdGFrZS4KLy8KLy8gQHBhcmFtIHtWYWxpZGF0b3JJZFR5cGV9IHZhbGlkYXRvcklkIC0gVGhlIGlkIG9mIHRoZSB2YWxpZGF0b3IuCi8vIEByZXR1cm4ge1Bvb2xUb2tlblBheW91dFJhdGlvfSAtIFRoZSB0b2tlbiBwYXlvdXQgcmF0aW8gZm9yIHRoZSB2YWxpZGF0b3IuCmdldFRva2VuUGF5b3V0UmF0aW86Cglwcm90byAxIDEKCgkvLyBjb250cmFjdHMvdmFsaWRhdG9yUmVnaXN0cnkuYWxnby50czozNzYKCS8vIHJldHVybiB0aGlzLnZhbGlkYXRvckxpc3QodmFsaWRhdG9ySWQpLnZhbHVlLnRva2VuUGF5b3V0UmF0aW87CglpbnQgNjY2IC8vIGhlYWRPZmZzZXQKCWludCAyMDAKCWJ5dGUgMHg3NiAvLyAidiIKCWZyYW1lX2RpZyAtMSAvLyB2YWxpZGF0b3JJZDogVmFsaWRhdG9ySWRUeXBlCglpdG9iCgljb25jYXQKCWNvdmVyIDIKCWJveF9leHRyYWN0CglyZXRzdWIKCi8vIGdldE5vZGVQb29sQXNzaWdubWVudHModWludDY0KSgodWludDY0WzNdKVs4XSkKKmFiaV9yb3V0ZV9nZXROb2RlUG9vbEFzc2lnbm1lbnRzOgoJLy8gVGhlIEFCSSByZXR1cm4gcHJlZml4CglieXRlIDB4MTUxZjdjNzUKCgkvLyB2YWxpZGF0b3JJZDogdWludDY0Cgl0eG5hIEFwcGxpY2F0aW9uQXJncyAxCglidG9pCgoJLy8gZXhlY3V0ZSBnZXROb2RlUG9vbEFzc2lnbm1lbnRzKHVpbnQ2NCkoKHVpbnQ2NFszXSlbOF0pCgljYWxsc3ViIGdldE5vZGVQb29sQXNzaWdubWVudHMKCWNvbmNhdAoJbG9nCglpbnQgMQoJcmV0dXJuCgovLyBnZXROb2RlUG9vbEFzc2lnbm1lbnRzKHZhbGlkYXRvcklkOiB1aW50NjQpOiBOb2RlUG9vbEFzc2lnbm1lbnRDb25maWcKZ2V0Tm9kZVBvb2xBc3NpZ25tZW50czoKCXByb3RvIDEgMQoKCS8vIGNvbnRyYWN0cy92YWxpZGF0b3JSZWdpc3RyeS5hbGdvLnRzOjM4MQoJLy8gYXNzZXJ0KHRoaXMudmFsaWRhdG9yTGlzdCh2YWxpZGF0b3JJZCkuZXhpc3RzKQoJYnl0ZSAweDc2IC8vICJ2IgoJZnJhbWVfZGlnIC0xIC8vIHZhbGlkYXRvcklkOiB1aW50NjQKCWl0b2IKCWNvbmNhdAoJYm94X2xlbgoJc3dhcAoJcG9wCglhc3NlcnQKCgkvLyBjb250cmFjdHMvdmFsaWRhdG9yUmVnaXN0cnkuYWxnby50czozODMKCS8vIHJldHVybiB0aGlzLnZhbGlkYXRvckxpc3QodmFsaWRhdG9ySWQpLnZhbHVlLm5vZGVQb29sQXNzaWdubWVudHM7CglpbnQgODY2IC8vIGhlYWRPZmZzZXQKCWludCAxOTIKCWJ5dGUgMHg3NiAvLyAidiIKCWZyYW1lX2RpZyAtMSAvLyB2YWxpZGF0b3JJZDogdWludDY0CglpdG9iCgljb25jYXQKCWNvdmVyIDIKCWJveF9leHRyYWN0CglyZXRzdWIKCi8vIGdldE5GRFJlZ2lzdHJ5SUQoKXVpbnQ2NAoqYWJpX3JvdXRlX2dldE5GRFJlZ2lzdHJ5SUQ6CgkvLyBUaGUgQUJJIHJldHVybiBwcmVmaXgKCWJ5dGUgMHgxNTFmN2M3NQoKCS8vIGV4ZWN1dGUgZ2V0TkZEUmVnaXN0cnlJRCgpdWludDY0CgljYWxsc3ViIGdldE5GRFJlZ2lzdHJ5SUQKCWl0b2IKCWNvbmNhdAoJbG9nCglpbnQgMQoJcmV0dXJuCgovLyBnZXRORkRSZWdpc3RyeUlEKCk6IHVpbnQ2NApnZXRORkRSZWdpc3RyeUlEOgoJcHJvdG8gMCAxCgoJLy8gY29udHJhY3RzL3ZhbGlkYXRvclJlZ2lzdHJ5LmFsZ28udHM6Mzg3CgkvLyByZXR1cm4gdGhpcy5uZmRSZWdpc3RyeUFwcElkOwoJcHVzaGludCBUTVBMX25mZFJlZ2lzdHJ5QXBwSWQKCXJldHN1YgoKLy8gYWRkVmFsaWRhdG9yKHBheSxzdHJpbmcsKHVpbnQ2NCxhZGRyZXNzLGFkZHJlc3MsdWludDY0LHVpbnQ4LGJ5dGVbMzJdLHVpbnQ2NCx1aW50NjQsdWludDY0LHVpbnQxNix1aW50MzIsYWRkcmVzcyx1aW50NjQsdWludDY0LHVpbnQ4LHVpbnQ2NCx1aW50NjQpKXVpbnQ2NAoqYWJpX3JvdXRlX2FkZFZhbGlkYXRvcjoKCS8vIFRoZSBBQkkgcmV0dXJuIHByZWZpeAoJYnl0ZSAweDE1MWY3Yzc1CgoJLy8gY29uZmlnOiAodWludDY0LGFkZHJlc3MsYWRkcmVzcyx1aW50NjQsdWludDgsYnl0ZVszMl0sdWludDY0LHVpbnQ2NCx1aW50NjQsdWludDE2LHVpbnQzMixhZGRyZXNzLHVpbnQ2NCx1aW50NjQsdWludDgsdWludDY0LHVpbnQ2NCkKCXR4bmEgQXBwbGljYXRpb25BcmdzIDIKCWR1cAoJbGVuCglpbnQgMjA4Cgk9PQoJYXNzZXJ0CgoJLy8gbmZkTmFtZTogc3RyaW5nCgl0eG5hIEFwcGxpY2F0aW9uQXJncyAxCglleHRyYWN0IDIgMAoKCS8vIG1iclBheW1lbnQ6IHBheQoJdHhuIEdyb3VwSW5kZXgKCWludCAxCgktCglkdXAKCWd0eG5zIFR5cGVFbnVtCglpbnQgcGF5Cgk9PQoJYXNzZXJ0CgoJLy8gZXhlY3V0ZSBhZGRWYWxpZGF0b3IocGF5LHN0cmluZywodWludDY0LGFkZHJlc3MsYWRkcmVzcyx1aW50NjQsdWludDgsYnl0ZVszMl0sdWludDY0LHVpbnQ2NCx1aW50NjQsdWludDE2LHVpbnQzMixhZGRyZXNzLHVpbnQ2NCx1aW50NjQsdWludDgsdWludDY0LHVpbnQ2NCkpdWludDY0CgljYWxsc3ViIGFkZFZhbGlkYXRvcgoJaXRvYgoJY29uY2F0Cglsb2cKCWludCAxCglyZXR1cm4KCi8vIGFkZFZhbGlkYXRvcihtYnJQYXltZW50OiBQYXlUeG4sIG5mZE5hbWU6IHN0cmluZywgY29uZmlnOiBWYWxpZGF0b3JDb25maWcpOiB1aW50NjQKLy8KLy8gQWRkcyBhIG5ldyB2YWxpZGF0b3IKLy8gQHBhcmFtIG1iclBheW1lbnQgcGF5bWVudCBmcm9tIGNhbGxlciB3aGljaCBjb3ZlcnMgbWJyIGluY3JlYXNlIG9mIG5ldyB2YWxpZGF0b3Igc3RvcmFnZQovLyBAcGFyYW0gbmZkTmFtZSAoT3B0aW9uYWwpIE5hbWUgb2YgbmZkICh1c2VkIGFzIGRvdWJsZS1jaGVjayBhZ2FpbnN0IGlkIHNwZWNpZmllZCBpbiBjb25maWcpCi8vIEBwYXJhbSBjb25maWcgVmFsaWRhdG9yQ29uZmlnIHN0cnVjdAovLyBAcmV0dXJucyB2YWxpZGF0b3IgaWQKYWRkVmFsaWRhdG9yOgoJcHJvdG8gMyAxCgoJLy8gUHVzaCBlbXB0eSBieXRlcyBhZnRlciB0aGUgZnJhbWUgcG9pbnRlciB0byByZXNlcnZlIHNwYWNlIGZvciBsb2NhbCB2YXJpYWJsZXMKCWJ5dGUgMHgKCWR1cAoKCS8vIGNvbnRyYWN0cy92YWxpZGF0b3JSZWdpc3RyeS5hbGdvLnRzOjM5NwoJLy8gdGhpcy52YWxpZGF0ZUNvbmZpZyhjb25maWcpCglmcmFtZV9kaWcgLTMgLy8gY29uZmlnOiBWYWxpZGF0b3JDb25maWcKCWNhbGxzdWIgdmFsaWRhdGVDb25maWcKCgkvLyBjb250cmFjdHMvdmFsaWRhdG9yUmVnaXN0cnkuYWxnby50czozOTgKCS8vIGFzc2VydChjb25maWcub3duZXIgIT09IEFkZHJlc3MuemVyb0FkZHJlc3MpCglmcmFtZV9kaWcgLTMgLy8gY29uZmlnOiBWYWxpZGF0b3JDb25maWcKCWV4dHJhY3QgOCAzMgoJZ2xvYmFsIFplcm9BZGRyZXNzCgkhPQoJYXNzZXJ0CgoJLy8gY29udHJhY3RzL3ZhbGlkYXRvclJlZ2lzdHJ5LmFsZ28udHM6Mzk5CgkvLyBhc3NlcnQoY29uZmlnLm1hbmFnZXIgIT09IEFkZHJlc3MuemVyb0FkZHJlc3MpCglmcmFtZV9kaWcgLTMgLy8gY29uZmlnOiBWYWxpZGF0b3JDb25maWcKCWV4dHJhY3QgNDAgMzIKCWdsb2JhbCBaZXJvQWRkcmVzcwoJIT0KCWFzc2VydAoKCS8vIGNvbnRyYWN0cy92YWxpZGF0b3JSZWdpc3RyeS5hbGdvLnRzOjQwMAoJLy8gYXNzZXJ0KHRoaXMudHhuLnNlbmRlciA9PT0gY29uZmlnLm93bmVyLCAnc2VuZGVyIG11c3QgYmUgb3duZXIgdG8gYWRkIG5ldyB2YWxpZGF0b3InKQoJdHhuIFNlbmRlcgoJZnJhbWVfZGlnIC0zIC8vIGNvbmZpZzogVmFsaWRhdG9yQ29uZmlnCglleHRyYWN0IDggMzIKCT09CgoJLy8gc2VuZGVyIG11c3QgYmUgb3duZXIgdG8gYWRkIG5ldyB2YWxpZGF0b3IKCWFzc2VydAoKCS8vIGNvbnRyYWN0cy92YWxpZGF0b3JSZWdpc3RyeS5hbGdvLnRzOjQwMgoJLy8gdmVyaWZ5UGF5VHhuKG1iclBheW1lbnQsIHsgYW1vdW50OiB0aGlzLmdldE1ickFtb3VudHMoKS5hZGRWYWxpZGF0b3JNYnIgfSkKCS8vIHZlcmlmeSBhbW91bnQKCWZyYW1lX2RpZyAtMSAvLyBtYnJQYXltZW50OiBQYXlUeG4KCWd0eG5zIEFtb3VudAoJY2FsbHN1YiBnZXRNYnJBbW91bnRzCglleHRyYWN0IDAgOAoJYnRvaQoJPT0KCWFzc2VydAoKCS8vIGNvbnRyYWN0cy92YWxpZGF0b3JSZWdpc3RyeS5hbGdvLnRzOjQwNQoJLy8gdmFsaWRhdG9ySWQgPSB0aGlzLm51bVZhbGlkYXRvcnMudmFsdWUgKyAxCglieXRlIDB4NmU3NTZkNTYgLy8gIm51bVYiCglhcHBfZ2xvYmFsX2dldAoJaW50IDEKCSsKCWZyYW1lX2J1cnkgMCAvLyB2YWxpZGF0b3JJZDogdWludDY0CgoJLy8gY29udHJhY3RzL3ZhbGlkYXRvclJlZ2lzdHJ5LmFsZ28udHM6NDA2CgkvLyB0aGlzLm51bVZhbGlkYXRvcnMudmFsdWUgPSB2YWxpZGF0b3JJZAoJYnl0ZSAweDZlNzU2ZDU2IC8vICJudW1WIgoJZnJhbWVfZGlnIDAgLy8gdmFsaWRhdG9ySWQ6IHVpbnQ2NAoJYXBwX2dsb2JhbF9wdXQKCgkvLyBjb250cmFjdHMvdmFsaWRhdG9yUmVnaXN0cnkuYWxnby50czo0MDgKCS8vIHRoaXMudmFsaWRhdG9yTGlzdCh2YWxpZGF0b3JJZCkuY3JlYXRlKCkKCWJ5dGUgMHg3NiAvLyAidiIKCWZyYW1lX2RpZyAwIC8vIHZhbGlkYXRvcklkOiB1aW50NjQKCWl0b2IKCWNvbmNhdAoJaW50IDEwNTgKCWJveF9jcmVhdGUKCXBvcAoKCS8vIGNvbnRyYWN0cy92YWxpZGF0b3JSZWdpc3RyeS5hbGdvLnRzOjQwOQoJLy8gdGhpcy52YWxpZGF0b3JMaXN0KHZhbGlkYXRvcklkKS52YWx1ZS5jb25maWcgPSBjb25maWcKCWludCAwCglmcmFtZV9kaWcgLTMgLy8gY29uZmlnOiBWYWxpZGF0b3JDb25maWcKCWJ5dGUgMHg3NiAvLyAidiIKCWZyYW1lX2RpZyAwIC8vIHZhbGlkYXRvcklkOiB1aW50NjQKCWl0b2IKCWNvbmNhdAoJY292ZXIgMgoJYm94X3JlcGxhY2UKCgkvLyBjb250cmFjdHMvdmFsaWRhdG9yUmVnaXN0cnkuYWxnby50czo0MTAKCS8vIHRoaXMudmFsaWRhdG9yTGlzdCh2YWxpZGF0b3JJZCkudmFsdWUuY29uZmlnLmlkID0gdmFsaWRhdG9ySWQKCWludCAwCglmcmFtZV9kaWcgMCAvLyB2YWxpZGF0b3JJZDogdWludDY0CglpdG9iCglieXRlIDB4NzYgLy8gInYiCglmcmFtZV9kaWcgMCAvLyB2YWxpZGF0b3JJZDogdWludDY0CglpdG9iCgljb25jYXQKCWNvdmVyIDIKCWJveF9yZXBsYWNlCgoJLy8gKmlmNV9jb25kaXRpb24KCS8vIGNvbnRyYWN0cy92YWxpZGF0b3JSZWdpc3RyeS5hbGdvLnRzOjQxMwoJLy8gY29uZmlnLm5mZEZvckluZm8gIT09IDAKCWZyYW1lX2RpZyAtMyAvLyBjb25maWc6IFZhbGlkYXRvckNvbmZpZwoJZXh0cmFjdCA3MiA4CglidG9pCglpbnQgMAoJIT0KCWJ6ICppZjVfZW5kCgoJLy8gKmlmNV9jb25zZXF1ZW50CgkvLyBjb250cmFjdHMvdmFsaWRhdG9yUmVnaXN0cnkuYWxnby50czo0MTUKCS8vIHNlbmRBcHBDYWxsKHsKCS8vICAgICAgICAgICAgICAgICBhcHBsaWNhdGlvbklEOiBBcHBJRC5mcm9tVWludDY0KHRoaXMubmZkUmVnaXN0cnlBcHBJZCksCgkvLyAgICAgICAgICAgICAgICAgYXBwbGljYXRpb25BcmdzOiBbJ2lzX3ZhbGlkX25mZF9hcHBpZCcsIG5mZE5hbWUsIGl0b2IoY29uZmlnLm5mZEZvckluZm8pXSwKCS8vICAgICAgICAgICAgICAgICBhcHBsaWNhdGlvbnM6IFtBcHBJRC5mcm9tVWludDY0KGNvbmZpZy5uZmRGb3JJbmZvKV0sCgkvLyAgICAgICAgICAgICB9KQoJaXR4bl9iZWdpbgoJaW50IGFwcGwKCWl0eG5fZmllbGQgVHlwZUVudW0KCgkvLyBjb250cmFjdHMvdmFsaWRhdG9yUmVnaXN0cnkuYWxnby50czo0MTYKCS8vIGFwcGxpY2F0aW9uSUQ6IEFwcElELmZyb21VaW50NjQodGhpcy5uZmRSZWdpc3RyeUFwcElkKQoJcHVzaGludCBUTVBMX25mZFJlZ2lzdHJ5QXBwSWQKCWl0eG5fZmllbGQgQXBwbGljYXRpb25JRAoKCS8vIGNvbnRyYWN0cy92YWxpZGF0b3JSZWdpc3RyeS5hbGdvLnRzOjQxNwoJLy8gYXBwbGljYXRpb25BcmdzOiBbJ2lzX3ZhbGlkX25mZF9hcHBpZCcsIG5mZE5hbWUsIGl0b2IoY29uZmlnLm5mZEZvckluZm8pXQoJYnl0ZSAweDY5NzM1Zjc2NjE2YzY5NjQ1ZjZlNjY2NDVmNjE3MDcwNjk2NCAvLyAiaXNfdmFsaWRfbmZkX2FwcGlkIgoJaXR4bl9maWVsZCBBcHBsaWNhdGlvbkFyZ3MKCWZyYW1lX2RpZyAtMiAvLyBuZmROYW1lOiBzdHJpbmcKCWl0eG5fZmllbGQgQXBwbGljYXRpb25BcmdzCglmcmFtZV9kaWcgLTMgLy8gY29uZmlnOiBWYWxpZGF0b3JDb25maWcKCWV4dHJhY3QgNzIgOAoJYnRvaQoJaXRvYgoJaXR4bl9maWVsZCBBcHBsaWNhdGlvbkFyZ3MKCgkvLyBjb250cmFjdHMvdmFsaWRhdG9yUmVnaXN0cnkuYWxnby50czo0MTgKCS8vIGFwcGxpY2F0aW9uczogW0FwcElELmZyb21VaW50NjQoY29uZmlnLm5mZEZvckluZm8pXQoJZnJhbWVfZGlnIC0zIC8vIGNvbmZpZzogVmFsaWRhdG9yQ29uZmlnCglleHRyYWN0IDcyIDgKCWJ0b2kKCWl0eG5fZmllbGQgQXBwbGljYXRpb25zCgoJLy8gRmVlIGZpZWxkIG5vdCBzZXQsIGRlZmF1bHRpbmcgdG8gMAoJaW50IDAKCWl0eG5fZmllbGQgRmVlCgoJLy8gU3VibWl0IGlubmVyIHRyYW5zYWN0aW9uCglpdHhuX3N1Ym1pdAoKCS8vIGNvbnRyYWN0cy92YWxpZGF0b3JSZWdpc3RyeS5hbGdvLnRzOjQyMAoJLy8gYXNzZXJ0KGJ0b2kodGhpcy5pdHhuLmxhc3RMb2cpID09PSAxLCAicHJvdmlkZWQgTkZEIGlzbid0IHZhbGlkIikKCWl0eG4gTGFzdExvZwoJYnRvaQoJaW50IDEKCT09CgoJLy8gcHJvdmlkZWQgTkZEIGlzbid0IHZhbGlkCglhc3NlcnQKCgkvLyBjb250cmFjdHMvdmFsaWRhdG9yUmVnaXN0cnkuYWxnby50czo0MjIKCS8vIGFzc2VydCgKCS8vICAgICAgICAgICAgICAgICB0aGlzLnR4bi5zZW5kZXIgPT09IChBcHBJRC5mcm9tVWludDY0KGNvbmZpZy5uZmRGb3JJbmZvKS5nbG9iYWxTdGF0ZSgnaS5vd25lci5hJykgYXMgQWRkcmVzcyksCgkvLyAgICAgICAgICAgICAgICAgJ0lmIHNwZWNpZnlpbmcgTkZELCBhY2NvdW50IGFkZGluZyB2YWxpZGF0b3IgbXVzdCBiZSBvd25lcicKCS8vICAgICAgICAgICAgICkKCXR4biBTZW5kZXIKCWZyYW1lX2RpZyAtMyAvLyBjb25maWc6IFZhbGlkYXRvckNvbmZpZwoJZXh0cmFjdCA3MiA4CglidG9pCglieXRlIDB4NjkyZTZmNzc2ZTY1NzIyZTYxIC8vICJpLm93bmVyLmEiCglhcHBfZ2xvYmFsX2dldF9leAoJYXNzZXJ0Cgk9PQoKCS8vIElmIHNwZWNpZnlpbmcgTkZELCBhY2NvdW50IGFkZGluZyB2YWxpZGF0b3IgbXVzdCBiZSBvd25lcgoJYXNzZXJ0CgoqaWY1X2VuZDoKCS8vICppZjZfY29uZGl0aW9uCgkvLyBjb250cmFjdHMvdmFsaWRhdG9yUmVnaXN0cnkuYWxnby50czo0MjcKCS8vIGNvbmZpZy5lbnRyeUdhdGluZ1R5cGUgPT09IEdBVElOR19UWVBFX0NSRUFURURfQllfTkZEX0FERFJFU1NFUwoJZnJhbWVfZGlnIC0zIC8vIGNvbmZpZzogVmFsaWRhdG9yQ29uZmlnCglleHRyYWN0IDgwIDEKCWJ0b2kKCWludCAzCgk9PQoJYnogKmlmNl9lbmQKCgkvLyAqaWY2X2NvbnNlcXVlbnQKCS8vIGNvbnRyYWN0cy92YWxpZGF0b3JSZWdpc3RyeS5hbGdvLnRzOjQyOQoJLy8gYXNzZXJ0KGNvbmZpZy5uZmRGb3JJbmZvICE9PSAwLCAnYW4gTkZEIG11c3QgYmUgc3BlY2lmaWVkIGZvciB0aGUgdmFsaWRhdG9yIHdoZW4gZ2F0aW5nIGJ5IE5GRCBhZGRyZXNzZXMnKQoJZnJhbWVfZGlnIC0zIC8vIGNvbmZpZzogVmFsaWRhdG9yQ29uZmlnCglleHRyYWN0IDcyIDgKCWJ0b2kKCWludCAwCgkhPQoKCS8vIGFuIE5GRCBtdXN0IGJlIHNwZWNpZmllZCBmb3IgdGhlIHZhbGlkYXRvciB3aGVuIGdhdGluZyBieSBORkQgYWRkcmVzc2VzCglhc3NlcnQKCippZjZfZW5kOgoJLy8gKmlmN19jb25kaXRpb24KCS8vIGNvbnRyYWN0cy92YWxpZGF0b3JSZWdpc3RyeS5hbGdvLnRzOjQzMQoJLy8gY29uZmlnLmVudHJ5R2F0aW5nVHlwZSA9PT0gR0FUSU5HX1RZUEVfU0VHTUVOVF9PRl9ORkQKCWZyYW1lX2RpZyAtMyAvLyBjb25maWc6IFZhbGlkYXRvckNvbmZpZwoJZXh0cmFjdCA4MCAxCglidG9pCglpbnQgNAoJPT0KCWJ6ICppZjdfZW5kCgoJLy8gKmlmN19jb25zZXF1ZW50CgkvLyBjb250cmFjdHMvdmFsaWRhdG9yUmVnaXN0cnkuYWxnby50czo0MzMKCS8vIG5mZFJvb3RBcHBJRCA9IGV4dHJhY3RVaW50NjQoY29uZmlnLmVudHJ5R2F0aW5nVmFsdWUsIDApCglmcmFtZV9kaWcgLTMgLy8gY29uZmlnOiBWYWxpZGF0b3JDb25maWcKCWV4dHJhY3QgODEgMzIKCWludCAwCglleHRyYWN0X3VpbnQ2NAoJZnJhbWVfYnVyeSAxIC8vIG5mZFJvb3RBcHBJRDogdWludDY0CgoJLy8gY29udHJhY3RzL3ZhbGlkYXRvclJlZ2lzdHJ5LmFsZ28udHM6NDM0CgkvLyBhc3NlcnQodGhpcy5pc05GREFwcElEVmFsaWQobmZkUm9vdEFwcElEKSwgJ3Byb3ZpZGVkIE5GRCBBcHAgaWQgZm9yIGdhdGluZyBtdXN0IGJlIHZhbGlkIE5GRCcpCglmcmFtZV9kaWcgMSAvLyBuZmRSb290QXBwSUQ6IHVpbnQ2NAoJY2FsbHN1YiBpc05GREFwcElEVmFsaWQKCgkvLyBwcm92aWRlZCBORkQgQXBwIGlkIGZvciBnYXRpbmcgbXVzdCBiZSB2YWxpZCBORkQKCWFzc2VydAoKKmlmN19lbmQ6CgkvLyBjb250cmFjdHMvdmFsaWRhdG9yUmVnaXN0cnkuYWxnby50czo0MzcKCS8vIHJldHVybiB2YWxpZGF0b3JJZDsKCWZyYW1lX2RpZyAwIC8vIHZhbGlkYXRvcklkOiB1aW50NjQKCgkvLyBzZXQgdGhlIHN1YnJvdXRpbmUgcmV0dXJuIHZhbHVlCglmcmFtZV9idXJ5IDAKCgkvLyBwb3AgYWxsIGxvY2FsIHZhcmlhYmxlcyBmcm9tIHRoZSBzdGFjawoJcG9wbiAxCglyZXRzdWIKCi8vIGNoYW5nZVZhbGlkYXRvck1hbmFnZXIodWludDY0LGFkZHJlc3Mpdm9pZAoqYWJpX3JvdXRlX2NoYW5nZVZhbGlkYXRvck1hbmFnZXI6CgkvLyBtYW5hZ2VyOiBhZGRyZXNzCgl0eG5hIEFwcGxpY2F0aW9uQXJncyAyCglkdXAKCWxlbgoJaW50IDMyCgk9PQoJYXNzZXJ0CgoJLy8gdmFsaWRhdG9ySWQ6IHVpbnQ2NAoJdHhuYSBBcHBsaWNhdGlvbkFyZ3MgMQoJYnRvaQoKCS8vIGV4ZWN1dGUgY2hhbmdlVmFsaWRhdG9yTWFuYWdlcih1aW50NjQsYWRkcmVzcyl2b2lkCgljYWxsc3ViIGNoYW5nZVZhbGlkYXRvck1hbmFnZXIKCWludCAxCglyZXR1cm4KCi8vIGNoYW5nZVZhbGlkYXRvck1hbmFnZXIodmFsaWRhdG9ySWQ6IFZhbGlkYXRvcklkVHlwZSwgbWFuYWdlcjogQWRkcmVzcyk6IHZvaWQKLy8KLy8gQ2hhbmdlcyB0aGUgVmFsaWRhdG9yIG1hbmFnZXIgZm9yIGEgc3BlY2lmaWMgVmFsaWRhdG9yIGlkLgovLyBbIE9OTFkgT1dORVIgQ0FOIENIQU5HRSBdCi8vCi8vIEBwYXJhbSB7VmFsaWRhdG9ySWRUeXBlfSB2YWxpZGF0b3JJZCAtIFRoZSBpZCBvZiB0aGUgdmFsaWRhdG9yIHRvIGNoYW5nZSB0aGUgbWFuYWdlciBmb3IuCi8vIEBwYXJhbSB7QWRkcmVzc30gbWFuYWdlciAtIFRoZSBuZXcgbWFuYWdlciBhZGRyZXNzLgpjaGFuZ2VWYWxpZGF0b3JNYW5hZ2VyOgoJcHJvdG8gMiAwCgoJLy8gY29udHJhY3RzL3ZhbGlkYXRvclJlZ2lzdHJ5LmFsZ28udHM6NDQ4CgkvLyBhc3NlcnQodGhpcy50eG4uc2VuZGVyID09PSB0aGlzLnZhbGlkYXRvckxpc3QodmFsaWRhdG9ySWQpLnZhbHVlLmNvbmZpZy5vd25lcikKCXR4biBTZW5kZXIKCWludCA4CglpbnQgMzIKCWJ5dGUgMHg3NiAvLyAidiIKCWZyYW1lX2RpZyAtMSAvLyB2YWxpZGF0b3JJZDogVmFsaWRhdG9ySWRUeXBlCglpdG9iCgljb25jYXQKCWNvdmVyIDIKCWJveF9leHRyYWN0Cgk9PQoJYXNzZXJ0CgoJLy8gY29udHJhY3RzL3ZhbGlkYXRvclJlZ2lzdHJ5LmFsZ28udHM6NDQ5CgkvLyB0aGlzLnZhbGlkYXRvckxpc3QodmFsaWRhdG9ySWQpLnZhbHVlLmNvbmZpZy5tYW5hZ2VyID0gbWFuYWdlcgoJaW50IDQwCglmcmFtZV9kaWcgLTIgLy8gbWFuYWdlcjogQWRkcmVzcwoJYnl0ZSAweDc2IC8vICJ2IgoJZnJhbWVfZGlnIC0xIC8vIHZhbGlkYXRvcklkOiBWYWxpZGF0b3JJZFR5cGUKCWl0b2IKCWNvbmNhdAoJY292ZXIgMgoJYm94X3JlcGxhY2UKCXJldHN1YgoKLy8gY2hhbmdlVmFsaWRhdG9yU3Vuc2V0SW5mbyh1aW50NjQsdWludDY0LHVpbnQ2NCl2b2lkCiphYmlfcm91dGVfY2hhbmdlVmFsaWRhdG9yU3Vuc2V0SW5mbzoKCS8vIHN1bnNldHRpbmdUbzogdWludDY0Cgl0eG5hIEFwcGxpY2F0aW9uQXJncyAzCglidG9pCgoJLy8gc3Vuc2V0dGluZ09uOiB1aW50NjQKCXR4bmEgQXBwbGljYXRpb25BcmdzIDIKCWJ0b2kKCgkvLyB2YWxpZGF0b3JJZDogdWludDY0Cgl0eG5hIEFwcGxpY2F0aW9uQXJncyAxCglidG9pCgoJLy8gZXhlY3V0ZSBjaGFuZ2VWYWxpZGF0b3JTdW5zZXRJbmZvKHVpbnQ2NCx1aW50NjQsdWludDY0KXZvaWQKCWNhbGxzdWIgY2hhbmdlVmFsaWRhdG9yU3Vuc2V0SW5mbwoJaW50IDEKCXJldHVybgoKLy8gY2hhbmdlVmFsaWRhdG9yU3Vuc2V0SW5mbyh2YWxpZGF0b3JJZDogVmFsaWRhdG9ySWRUeXBlLCBzdW5zZXR0aW5nT246IHVpbnQ2NCwgc3Vuc2V0dGluZ1RvOiBWYWxpZGF0b3JJZFR5cGUpOiB2b2lkCi8vCi8vIFVwZGF0ZXMgdGhlIHN1bnNldCBpbmZvcm1hdGlvbiBmb3IgYSBnaXZlbiB2YWxpZGF0b3IuCi8vIFsgT05MWSBPV05FUiBDQU4gQ0hBTkdFIF0KLy8KLy8gQHBhcmFtIHtWYWxpZGF0b3JJZFR5cGV9IHZhbGlkYXRvcklkIC0gVGhlIGlkIG9mIHRoZSB2YWxpZGF0b3IgdG8gdXBkYXRlLgovLyBAcGFyYW0ge3VpbnQ2NH0gc3Vuc2V0dGluZ09uIC0gVGhlIG5ldyBzdW5zZXQgdGltZXN0YW1wLgovLyBAcGFyYW0ge3VpbnQ2NH0gc3Vuc2V0dGluZ1RvIC0gVGhlIG5ldyBzdW5zZXQgdG8gdmFsaWRhdG9yIGlkLgpjaGFuZ2VWYWxpZGF0b3JTdW5zZXRJbmZvOgoJcHJvdG8gMyAwCgoJLy8gY29udHJhY3RzL3ZhbGlkYXRvclJlZ2lzdHJ5LmFsZ28udHM6NDYxCgkvLyBhc3NlcnQodGhpcy50eG4uc2VuZGVyID09PSB0aGlzLnZhbGlkYXRvckxpc3QodmFsaWRhdG9ySWQpLnZhbHVlLmNvbmZpZy5vd25lcikKCXR4biBTZW5kZXIKCWludCA4CglpbnQgMzIKCWJ5dGUgMHg3NiAvLyAidiIKCWZyYW1lX2RpZyAtMSAvLyB2YWxpZGF0b3JJZDogVmFsaWRhdG9ySWRUeXBlCglpdG9iCgljb25jYXQKCWNvdmVyIDIKCWJveF9leHRyYWN0Cgk9PQoJYXNzZXJ0CgoJLy8gY29udHJhY3RzL3ZhbGlkYXRvclJlZ2lzdHJ5LmFsZ28udHM6NDYyCgkvLyB0aGlzLnZhbGlkYXRvckxpc3QodmFsaWRhdG9ySWQpLnZhbHVlLmNvbmZpZy5zdW5zZXR0aW5nT24gPSBzdW5zZXR0aW5nT24KCWludCAxOTIKCWZyYW1lX2RpZyAtMiAvLyBzdW5zZXR0aW5nT246IHVpbnQ2NAoJaXRvYgoJYnl0ZSAweDc2IC8vICJ2IgoJZnJhbWVfZGlnIC0xIC8vIHZhbGlkYXRvcklkOiBWYWxpZGF0b3JJZFR5cGUKCWl0b2IKCWNvbmNhdAoJY292ZXIgMgoJYm94X3JlcGxhY2UKCgkvLyBjb250cmFjdHMvdmFsaWRhdG9yUmVnaXN0cnkuYWxnby50czo0NjMKCS8vIHRoaXMudmFsaWRhdG9yTGlzdCh2YWxpZGF0b3JJZCkudmFsdWUuY29uZmlnLnN1bnNldHRpbmdUbyA9IHN1bnNldHRpbmdUbwoJaW50IDIwMAoJZnJhbWVfZGlnIC0zIC8vIHN1bnNldHRpbmdUbzogVmFsaWRhdG9ySWRUeXBlCglpdG9iCglieXRlIDB4NzYgLy8gInYiCglmcmFtZV9kaWcgLTEgLy8gdmFsaWRhdG9ySWQ6IFZhbGlkYXRvcklkVHlwZQoJaXRvYgoJY29uY2F0Cgljb3ZlciAyCglib3hfcmVwbGFjZQoJcmV0c3ViCgovLyBjaGFuZ2VWYWxpZGF0b3JORkQodWludDY0LHVpbnQ2NCxzdHJpbmcpdm9pZAoqYWJpX3JvdXRlX2NoYW5nZVZhbGlkYXRvck5GRDoKCS8vIG5mZE5hbWU6IHN0cmluZwoJdHhuYSBBcHBsaWNhdGlvbkFyZ3MgMwoJZXh0cmFjdCAyIDAKCgkvLyBuZmRBcHBJRDogdWludDY0Cgl0eG5hIEFwcGxpY2F0aW9uQXJncyAyCglidG9pCgoJLy8gdmFsaWRhdG9ySWQ6IHVpbnQ2NAoJdHhuYSBBcHBsaWNhdGlvbkFyZ3MgMQoJYnRvaQoKCS8vIGV4ZWN1dGUgY2hhbmdlVmFsaWRhdG9yTkZEKHVpbnQ2NCx1aW50NjQsc3RyaW5nKXZvaWQKCWNhbGxzdWIgY2hhbmdlVmFsaWRhdG9yTkZECglpbnQgMQoJcmV0dXJuCgovLyBjaGFuZ2VWYWxpZGF0b3JORkQodmFsaWRhdG9ySWQ6IFZhbGlkYXRvcklkVHlwZSwgbmZkQXBwSUQ6IHVpbnQ2NCwgbmZkTmFtZTogc3RyaW5nKTogdm9pZAovLwovLyBDaGFuZ2VzIHRoZSBORkQgZm9yIGEgdmFsaWRhdG9yIGluIHRoZSB2YWxpZGF0b3JMaXN0IGNvbnRyYWN0LgovLyBbIE9OTFkgT1dORVIgT1IgTUFOQUdFUiBDQU4gQ0hBTkdFIF0KLy8KLy8gQHBhcmFtIHtWYWxpZGF0b3JJZFR5cGV9IHZhbGlkYXRvcklkIC0gVGhlIGlkIG9mIHRoZSB2YWxpZGF0b3IgdG8gdXBkYXRlLgovLyBAcGFyYW0ge3VpbnQ2NH0gbmZkQXBwSUQgLSBUaGUgYXBwbGljYXRpb24gaWQgb2YgdGhlIE5GRCB0byBhc3NpZ24gdG8gdGhlIHZhbGlkYXRvci4KLy8gQHBhcmFtIHtzdHJpbmd9IG5mZE5hbWUgLSBUaGUgbmFtZSBvZiB0aGUgTkZEICh3aGljaCBtdXN0IG1hdGNoKQpjaGFuZ2VWYWxpZGF0b3JORkQ6Cglwcm90byAzIDAKCgkvLyBjb250cmFjdHMvdmFsaWRhdG9yUmVnaXN0cnkuYWxnby50czo0NzYKCS8vIGFzc2VydCgKCS8vICAgICAgICAgICAgIHRoaXMudHhuLnNlbmRlciA9PT0gdGhpcy52YWxpZGF0b3JMaXN0KHZhbGlkYXRvcklkKS52YWx1ZS5jb25maWcub3duZXIgfHwKCS8vICAgICAgICAgICAgICAgICB0aGlzLnR4bi5zZW5kZXIgPT09IHRoaXMudmFsaWRhdG9yTGlzdCh2YWxpZGF0b3JJZCkudmFsdWUuY29uZmlnLm1hbmFnZXIKCS8vICAgICAgICAgKQoJdHhuIFNlbmRlcgoJaW50IDgKCWludCAzMgoJYnl0ZSAweDc2IC8vICJ2IgoJZnJhbWVfZGlnIC0xIC8vIHZhbGlkYXRvcklkOiBWYWxpZGF0b3JJZFR5cGUKCWl0b2IKCWNvbmNhdAoJY292ZXIgMgoJYm94X2V4dHJhY3QKCT09CglkdXAKCWJueiAqc2tpcF9vcjAKCXR4biBTZW5kZXIKCWludCA0MAoJaW50IDMyCglieXRlIDB4NzYgLy8gInYiCglmcmFtZV9kaWcgLTEgLy8gdmFsaWRhdG9ySWQ6IFZhbGlkYXRvcklkVHlwZQoJaXRvYgoJY29uY2F0Cgljb3ZlciAyCglib3hfZXh0cmFjdAoJPT0KCXx8Cgoqc2tpcF9vcjA6Cglhc3NlcnQKCgkvLyBjb250cmFjdHMvdmFsaWRhdG9yUmVnaXN0cnkuYWxnby50czo0ODEKCS8vIHNlbmRBcHBDYWxsKHsKCS8vICAgICAgICAgICAgIGFwcGxpY2F0aW9uSUQ6IEFwcElELmZyb21VaW50NjQodGhpcy5uZmRSZWdpc3RyeUFwcElkKSwKCS8vICAgICAgICAgICAgIGFwcGxpY2F0aW9uQXJnczogWydpc192YWxpZF9uZmRfYXBwaWQnLCBuZmROYW1lLCBpdG9iKG5mZEFwcElEKV0sCgkvLyAgICAgICAgICAgICBhcHBsaWNhdGlvbnM6IFtBcHBJRC5mcm9tVWludDY0KG5mZEFwcElEKV0sCgkvLyAgICAgICAgIH0pCglpdHhuX2JlZ2luCglpbnQgYXBwbAoJaXR4bl9maWVsZCBUeXBlRW51bQoKCS8vIGNvbnRyYWN0cy92YWxpZGF0b3JSZWdpc3RyeS5hbGdvLnRzOjQ4MgoJLy8gYXBwbGljYXRpb25JRDogQXBwSUQuZnJvbVVpbnQ2NCh0aGlzLm5mZFJlZ2lzdHJ5QXBwSWQpCglwdXNoaW50IFRNUExfbmZkUmVnaXN0cnlBcHBJZAoJaXR4bl9maWVsZCBBcHBsaWNhdGlvbklECgoJLy8gY29udHJhY3RzL3ZhbGlkYXRvclJlZ2lzdHJ5LmFsZ28udHM6NDgzCgkvLyBhcHBsaWNhdGlvbkFyZ3M6IFsnaXNfdmFsaWRfbmZkX2FwcGlkJywgbmZkTmFtZSwgaXRvYihuZmRBcHBJRCldCglieXRlIDB4Njk3MzVmNzY2MTZjNjk2NDVmNmU2NjY0NWY2MTcwNzA2OTY0IC8vICJpc192YWxpZF9uZmRfYXBwaWQiCglpdHhuX2ZpZWxkIEFwcGxpY2F0aW9uQXJncwoJZnJhbWVfZGlnIC0zIC8vIG5mZE5hbWU6IHN0cmluZwoJaXR4bl9maWVsZCBBcHBsaWNhdGlvbkFyZ3MKCWZyYW1lX2RpZyAtMiAvLyBuZmRBcHBJRDogdWludDY0CglpdG9iCglpdHhuX2ZpZWxkIEFwcGxpY2F0aW9uQXJncwoKCS8vIGNvbnRyYWN0cy92YWxpZGF0b3JSZWdpc3RyeS5hbGdvLnRzOjQ4NAoJLy8gYXBwbGljYXRpb25zOiBbQXBwSUQuZnJvbVVpbnQ2NChuZmRBcHBJRCldCglmcmFtZV9kaWcgLTIgLy8gbmZkQXBwSUQ6IHVpbnQ2NAoJaXR4bl9maWVsZCBBcHBsaWNhdGlvbnMKCgkvLyBGZWUgZmllbGQgbm90IHNldCwgZGVmYXVsdGluZyB0byAwCglpbnQgMAoJaXR4bl9maWVsZCBGZWUKCgkvLyBTdWJtaXQgaW5uZXIgdHJhbnNhY3Rpb24KCWl0eG5fc3VibWl0CgoJLy8gY29udHJhY3RzL3ZhbGlkYXRvclJlZ2lzdHJ5LmFsZ28udHM6NDg3CgkvLyBhc3NlcnQoCgkvLyAgICAgICAgICAgICB0aGlzLnR4bi5zZW5kZXIgPT09IChBcHBJRC5mcm9tVWludDY0KG5mZEFwcElEKS5nbG9iYWxTdGF0ZSgnaS5vd25lci5hJykgYXMgQWRkcmVzcyksCgkvLyAgICAgICAgICAgICAnSWYgc3BlY2lmeWluZyBORkQsIGFjY291bnQgYWRkaW5nIHZhbGlkYXRvciBtdXN0IGJlIG93bmVyJwoJLy8gICAgICAgICApCgl0eG4gU2VuZGVyCglmcmFtZV9kaWcgLTIgLy8gbmZkQXBwSUQ6IHVpbnQ2NAoJYnl0ZSAweDY5MmU2Zjc3NmU2NTcyMmU2MSAvLyAiaS5vd25lci5hIgoJYXBwX2dsb2JhbF9nZXRfZXgKCWFzc2VydAoJPT0KCgkvLyBJZiBzcGVjaWZ5aW5nIE5GRCwgYWNjb3VudCBhZGRpbmcgdmFsaWRhdG9yIG11c3QgYmUgb3duZXIKCWFzc2VydAoKCS8vIGNvbnRyYWN0cy92YWxpZGF0b3JSZWdpc3RyeS5hbGdvLnRzOjQ5MQoJLy8gdGhpcy52YWxpZGF0b3JMaXN0KHZhbGlkYXRvcklkKS52YWx1ZS5jb25maWcubmZkRm9ySW5mbyA9IG5mZEFwcElECglpbnQgNzIKCWZyYW1lX2RpZyAtMiAvLyBuZmRBcHBJRDogdWludDY0CglpdG9iCglieXRlIDB4NzYgLy8gInYiCglmcmFtZV9kaWcgLTEgLy8gdmFsaWRhdG9ySWQ6IFZhbGlkYXRvcklkVHlwZQoJaXRvYgoJY29uY2F0Cgljb3ZlciAyCglib3hfcmVwbGFjZQoJcmV0c3ViCgovLyBjaGFuZ2VWYWxpZGF0b3JDb21taXNzaW9uQWRkcmVzcyh1aW50NjQsYWRkcmVzcyl2b2lkCiphYmlfcm91dGVfY2hhbmdlVmFsaWRhdG9yQ29tbWlzc2lvbkFkZHJlc3M6CgkvLyBjb21taXNzaW9uQWRkcmVzczogYWRkcmVzcwoJdHhuYSBBcHBsaWNhdGlvbkFyZ3MgMgoJZHVwCglsZW4KCWludCAzMgoJPT0KCWFzc2VydAoKCS8vIHZhbGlkYXRvcklkOiB1aW50NjQKCXR4bmEgQXBwbGljYXRpb25BcmdzIDEKCWJ0b2kKCgkvLyBleGVjdXRlIGNoYW5nZVZhbGlkYXRvckNvbW1pc3Npb25BZGRyZXNzKHVpbnQ2NCxhZGRyZXNzKXZvaWQKCWNhbGxzdWIgY2hhbmdlVmFsaWRhdG9yQ29tbWlzc2lvbkFkZHJlc3MKCWludCAxCglyZXR1cm4KCi8vIGNoYW5nZVZhbGlkYXRvckNvbW1pc3Npb25BZGRyZXNzKHZhbGlkYXRvcklkOiBWYWxpZGF0b3JJZFR5cGUsIGNvbW1pc3Npb25BZGRyZXNzOiBBZGRyZXNzKTogdm9pZAovLwovLyBDaGFuZ2UgdGhlIGNvbW1pc3Npb24gYWRkcmVzcyB0aGF0IHZhbGlkYXRvciByZXdhcmRzIGFyZSBzZW50IHRvLgovLyBbIE9OTFkgT1dORVIgQ0FOIENIQU5HRSBdCmNoYW5nZVZhbGlkYXRvckNvbW1pc3Npb25BZGRyZXNzOgoJcHJvdG8gMiAwCgoJLy8gY29udHJhY3RzL3ZhbGlkYXRvclJlZ2lzdHJ5LmFsZ28udHM6NDk5CgkvLyBhc3NlcnQodGhpcy50eG4uc2VuZGVyID09PSB0aGlzLnZhbGlkYXRvckxpc3QodmFsaWRhdG9ySWQpLnZhbHVlLmNvbmZpZy5vd25lcikKCXR4biBTZW5kZXIKCWludCA4CglpbnQgMzIKCWJ5dGUgMHg3NiAvLyAidiIKCWZyYW1lX2RpZyAtMSAvLyB2YWxpZGF0b3JJZDogVmFsaWRhdG9ySWRUeXBlCglpdG9iCgljb25jYXQKCWNvdmVyIDIKCWJveF9leHRyYWN0Cgk9PQoJYXNzZXJ0CgoJLy8gY29udHJhY3RzL3ZhbGlkYXRvclJlZ2lzdHJ5LmFsZ28udHM6NTAwCgkvLyBhc3NlcnQoY29tbWlzc2lvbkFkZHJlc3MgIT09IEFkZHJlc3MuemVyb0FkZHJlc3MpCglmcmFtZV9kaWcgLTIgLy8gY29tbWlzc2lvbkFkZHJlc3M6IEFkZHJlc3MKCWdsb2JhbCBaZXJvQWRkcmVzcwoJIT0KCWFzc2VydAoKCS8vIGNvbnRyYWN0cy92YWxpZGF0b3JSZWdpc3RyeS5hbGdvLnRzOjUwMQoJLy8gdGhpcy52YWxpZGF0b3JMaXN0KHZhbGlkYXRvcklkKS52YWx1ZS5jb25maWcudmFsaWRhdG9yQ29tbWlzc2lvbkFkZHJlc3MgPSBjb21taXNzaW9uQWRkcmVzcwoJaW50IDE0MwoJZnJhbWVfZGlnIC0yIC8vIGNvbW1pc3Npb25BZGRyZXNzOiBBZGRyZXNzCglieXRlIDB4NzYgLy8gInYiCglmcmFtZV9kaWcgLTEgLy8gdmFsaWRhdG9ySWQ6IFZhbGlkYXRvcklkVHlwZQoJaXRvYgoJY29uY2F0Cgljb3ZlciAyCglib3hfcmVwbGFjZQoJcmV0c3ViCgovLyBjaGFuZ2VWYWxpZGF0b3JSZXdhcmRJbmZvKHVpbnQ2NCx1aW50OCxieXRlWzMyXSx1aW50NjQsdWludDY0KXZvaWQKKmFiaV9yb3V0ZV9jaGFuZ2VWYWxpZGF0b3JSZXdhcmRJbmZvOgoJLy8gUmV3YXJkUGVyUGF5b3V0OiB1aW50NjQKCXR4bmEgQXBwbGljYXRpb25BcmdzIDUKCWJ0b2kKCgkvLyBHYXRpbmdBc3NldE1pbkJhbGFuY2U6IHVpbnQ2NAoJdHhuYSBBcHBsaWNhdGlvbkFyZ3MgNAoJYnRvaQoKCS8vIEVudHJ5R2F0aW5nVmFsdWU6IGJ5dGVbMzJdCgl0eG5hIEFwcGxpY2F0aW9uQXJncyAzCglkdXAKCWxlbgoJaW50IDMyCgk9PQoJYXNzZXJ0CgoJLy8gRW50cnlHYXRpbmdUeXBlOiB1aW50OAoJdHhuYSBBcHBsaWNhdGlvbkFyZ3MgMgoJZHVwCglsZW4KCWludCAxCgk9PQoJYXNzZXJ0CglidG9pCgoJLy8gdmFsaWRhdG9ySWQ6IHVpbnQ2NAoJdHhuYSBBcHBsaWNhdGlvbkFyZ3MgMQoJYnRvaQoKCS8vIGV4ZWN1dGUgY2hhbmdlVmFsaWRhdG9yUmV3YXJkSW5mbyh1aW50NjQsdWludDgsYnl0ZVszMl0sdWludDY0LHVpbnQ2NCl2b2lkCgljYWxsc3ViIGNoYW5nZVZhbGlkYXRvclJld2FyZEluZm8KCWludCAxCglyZXR1cm4KCi8vIGNoYW5nZVZhbGlkYXRvclJld2FyZEluZm8odmFsaWRhdG9ySWQ6IFZhbGlkYXRvcklkVHlwZSwgRW50cnlHYXRpbmdUeXBlOiB1aW50OCwgRW50cnlHYXRpbmdWYWx1ZTogYnl0ZXMzMiwgR2F0aW5nQXNzZXRNaW5CYWxhbmNlOiB1aW50NjQsIFJld2FyZFBlclBheW91dDogdWludDY0KTogdm9pZAovLwovLyBBbGxvdyB0aGUgYWRkaXRpb25hbCByZXdhcmRzIChnYXRpbmcgZW50cnksIGFkZGl0aW9uYWwgdG9rZW4gcmV3YXJkcykgaW5mb3JtYXRpb24gYmUgY2hhbmdlZCBhdCB3aWxsLgovLyBbIE9OTFkgT1dORVIgQ0FOIENIQU5HRSBdCmNoYW5nZVZhbGlkYXRvclJld2FyZEluZm86Cglwcm90byA1IDAKCgkvLyBjb250cmFjdHMvdmFsaWRhdG9yUmVnaXN0cnkuYWxnby50czo1MTUKCS8vIGFzc2VydCh0aGlzLnR4bi5zZW5kZXIgPT09IHRoaXMudmFsaWRhdG9yTGlzdCh2YWxpZGF0b3JJZCkudmFsdWUuY29uZmlnLm93bmVyKQoJdHhuIFNlbmRlcgoJaW50IDgKCWludCAzMgoJYnl0ZSAweDc2IC8vICJ2IgoJZnJhbWVfZGlnIC0xIC8vIHZhbGlkYXRvcklkOiBWYWxpZGF0b3JJZFR5cGUKCWl0b2IKCWNvbmNhdAoJY292ZXIgMgoJYm94X2V4dHJhY3QKCT09Cglhc3NlcnQKCgkvLyBjb250cmFjdHMvdmFsaWRhdG9yUmVnaXN0cnkuYWxnby50czo1MTcKCS8vIHRoaXMudmFsaWRhdG9yTGlzdCh2YWxpZGF0b3JJZCkudmFsdWUuY29uZmlnLmVudHJ5R2F0aW5nVHlwZSA9IEVudHJ5R2F0aW5nVHlwZQoJaW50IDgwCglmcmFtZV9kaWcgLTIgLy8gRW50cnlHYXRpbmdUeXBlOiB1aW50OAoJaXRvYgoJZXh0cmFjdCA3IDEKCWJ5dGUgMHg3NiAvLyAidiIKCWZyYW1lX2RpZyAtMSAvLyB2YWxpZGF0b3JJZDogVmFsaWRhdG9ySWRUeXBlCglpdG9iCgljb25jYXQKCWNvdmVyIDIKCWJveF9yZXBsYWNlCgoJLy8gY29udHJhY3RzL3ZhbGlkYXRvclJlZ2lzdHJ5LmFsZ28udHM6NTE4CgkvLyB0aGlzLnZhbGlkYXRvckxpc3QodmFsaWRhdG9ySWQpLnZhbHVlLmNvbmZpZy5lbnRyeUdhdGluZ1ZhbHVlID0gRW50cnlHYXRpbmdWYWx1ZQoJaW50IDgxCglmcmFtZV9kaWcgLTMgLy8gRW50cnlHYXRpbmdWYWx1ZTogYnl0ZXMzMgoJYnl0ZSAweDc2IC8vICJ2IgoJZnJhbWVfZGlnIC0xIC8vIHZhbGlkYXRvcklkOiBWYWxpZGF0b3JJZFR5cGUKCWl0b2IKCWNvbmNhdAoJY292ZXIgMgoJYm94X3JlcGxhY2UKCgkvLyBjb250cmFjdHMvdmFsaWRhdG9yUmVnaXN0cnkuYWxnby50czo1MTkKCS8vIHRoaXMudmFsaWRhdG9yTGlzdCh2YWxpZGF0b3JJZCkudmFsdWUuY29uZmlnLmdhdGluZ0Fzc2V0TWluQmFsYW5jZSA9IEdhdGluZ0Fzc2V0TWluQmFsYW5jZQoJaW50IDExMwoJZnJhbWVfZGlnIC00IC8vIEdhdGluZ0Fzc2V0TWluQmFsYW5jZTogdWludDY0CglpdG9iCglieXRlIDB4NzYgLy8gInYiCglmcmFtZV9kaWcgLTEgLy8gdmFsaWRhdG9ySWQ6IFZhbGlkYXRvcklkVHlwZQoJaXRvYgoJY29uY2F0Cgljb3ZlciAyCglib3hfcmVwbGFjZQoKCS8vIGNvbnRyYWN0cy92YWxpZGF0b3JSZWdpc3RyeS5hbGdvLnRzOjUyMAoJLy8gdGhpcy52YWxpZGF0b3JMaXN0KHZhbGlkYXRvcklkKS52YWx1ZS5jb25maWcucmV3YXJkUGVyUGF5b3V0ID0gUmV3YXJkUGVyUGF5b3V0CglpbnQgMTI5CglmcmFtZV9kaWcgLTUgLy8gUmV3YXJkUGVyUGF5b3V0OiB1aW50NjQKCWl0b2IKCWJ5dGUgMHg3NiAvLyAidiIKCWZyYW1lX2RpZyAtMSAvLyB2YWxpZGF0b3JJZDogVmFsaWRhdG9ySWRUeXBlCglpdG9iCgljb25jYXQKCWNvdmVyIDIKCWJveF9yZXBsYWNlCglyZXRzdWIKCi8vIGFkZFBvb2wocGF5LHVpbnQ2NCx1aW50NjQpKHVpbnQ2NCx1aW50NjQsdWludDY0KQoqYWJpX3JvdXRlX2FkZFBvb2w6CgkvLyBUaGUgQUJJIHJldHVybiBwcmVmaXgKCWJ5dGUgMHgxNTFmN2M3NQoKCS8vIG5vZGVOdW06IHVpbnQ2NAoJdHhuYSBBcHBsaWNhdGlvbkFyZ3MgMgoJYnRvaQoKCS8vIHZhbGlkYXRvcklkOiB1aW50NjQKCXR4bmEgQXBwbGljYXRpb25BcmdzIDEKCWJ0b2kKCgkvLyBtYnJQYXltZW50OiBwYXkKCXR4biBHcm91cEluZGV4CglpbnQgMQoJLQoJZHVwCglndHhucyBUeXBlRW51bQoJaW50IHBheQoJPT0KCWFzc2VydAoKCS8vIGV4ZWN1dGUgYWRkUG9vbChwYXksdWludDY0LHVpbnQ2NCkodWludDY0LHVpbnQ2NCx1aW50NjQpCgljYWxsc3ViIGFkZFBvb2wKCWNvbmNhdAoJbG9nCglpbnQgMQoJcmV0dXJuCgovLyBhZGRQb29sKG1iclBheW1lbnQ6IFBheVR4biwgdmFsaWRhdG9ySWQ6IFZhbGlkYXRvcklkVHlwZSwgbm9kZU51bTogdWludDY0KTogVmFsaWRhdG9yUG9vbEtleQovLwovLyBBZGRzIGEgbmV3IHBvb2wgdG8gYSB2YWxpZGF0b3IncyBwb29sIHNldCwgcmV0dXJuaW5nIHRoZSAna2V5JyB0byByZWZlcmVuY2UgdGhlIHBvb2wgaW4gdGhlIGZ1dHVyZSBmb3Igc3Rha2luZywgZXRjLgovLyBUaGUgY2FsbGVyIG11c3QgcGF5IHRoZSBjb3N0IG9mIHRoZSB2YWxpZGF0b3JzIE1CUiBpbmNyZWFzZSBhcyB3ZWxsIGFzIHRoZSBNQlIgdGhhdCB3aWxsIGJlIG5lZWRlZCBmb3IgdGhlIHBvb2wgaXRzZWxmLgovLwovLyBbIE9OTFkgT1dORVIgT1IgTUFOQUdFUiBDQU4gY2FsbCBdCi8vIEBwYXJhbSB7UGF5VHhufSBtYnJQYXltZW50IHBheW1lbnQgZnJvbSBjYWxsZXIgd2hpY2ggY292ZXJzIG1iciBpbmNyZWFzZSBvZiBhZGRpbmcgYSBuZXcgcG9vbAovLyBAcGFyYW0ge3VpbnQ2NH0gdmFsaWRhdG9ySWQgaXMgaWQgb2YgdmFsaWRhdG9yIHRvIHBvb2wgdG8gKG11c3QgYmUgb3duZXIgb3IgbWFuYWdlcikKLy8gQHBhcmFtIHt1aW50NjR9IG5vZGVOdW0gaXMgbm9kZSBudW1iZXIgdG8gYWRkIHRvCi8vIEByZXR1cm5zIHtWYWxpZGF0b3JQb29sS2V5fSBwb29sIGtleSB0byBjcmVhdGVkIHBvb2wKYWRkUG9vbDoKCXByb3RvIDMgMQoKCS8vIFB1c2ggZW1wdHkgYnl0ZXMgYWZ0ZXIgdGhlIGZyYW1lIHBvaW50ZXIgdG8gcmVzZXJ2ZSBzcGFjZSBmb3IgbG9jYWwgdmFyaWFibGVzCglieXRlIDB4CglkdXAKCgkvLyBjb250cmFjdHMvdmFsaWRhdG9yUmVnaXN0cnkuYWxnby50czo1MzYKCS8vIGFzc2VydCgKCS8vICAgICAgICAgICAgIHRoaXMudHhuLnNlbmRlciA9PT0gdGhpcy52YWxpZGF0b3JMaXN0KHZhbGlkYXRvcklkKS52YWx1ZS5jb25maWcub3duZXIgfHwKCS8vICAgICAgICAgICAgICAgICB0aGlzLnR4bi5zZW5kZXIgPT09IHRoaXMudmFsaWRhdG9yTGlzdCh2YWxpZGF0b3JJZCkudmFsdWUuY29uZmlnLm1hbmFnZXIKCS8vICAgICAgICAgKQoJdHhuIFNlbmRlcgoJaW50IDgKCWludCAzMgoJYnl0ZSAweDc2IC8vICJ2IgoJZnJhbWVfZGlnIC0yIC8vIHZhbGlkYXRvcklkOiBWYWxpZGF0b3JJZFR5cGUKCWl0b2IKCWNvbmNhdAoJY292ZXIgMgoJYm94X2V4dHJhY3QKCT09CglkdXAKCWJueiAqc2tpcF9vcjEKCXR4biBTZW5kZXIKCWludCA0MAoJaW50IDMyCglieXRlIDB4NzYgLy8gInYiCglmcmFtZV9kaWcgLTIgLy8gdmFsaWRhdG9ySWQ6IFZhbGlkYXRvcklkVHlwZQoJaXRvYgoJY29uY2F0Cgljb3ZlciAyCglib3hfZXh0cmFjdAoJPT0KCXx8Cgoqc2tpcF9vcjE6Cglhc3NlcnQKCgkvLyBjb250cmFjdHMvdmFsaWRhdG9yUmVnaXN0cnkuYWxnby50czo1NDIKCS8vIHZlcmlmeVBheVR4bihtYnJQYXltZW50LCB7IGFtb3VudDogdGhpcy5nZXRNYnJBbW91bnRzKCkuYWRkUG9vbE1iciwgcmVjZWl2ZXI6IHRoaXMuYXBwLmFkZHJlc3MgfSkKCS8vIHZlcmlmeSBhbW91bnQKCWZyYW1lX2RpZyAtMSAvLyBtYnJQYXltZW50OiBQYXlUeG4KCWd0eG5zIEFtb3VudAoJY2FsbHN1YiBnZXRNYnJBbW91bnRzCglleHRyYWN0IDggOAoJYnRvaQoJPT0KCWFzc2VydAoKCS8vIHZlcmlmeSByZWNlaXZlcgoJZnJhbWVfZGlnIC0xIC8vIG1iclBheW1lbnQ6IFBheVR4bgoJZ3R4bnMgUmVjZWl2ZXIKCWdsb2JhbCBDdXJyZW50QXBwbGljYXRpb25BZGRyZXNzCgk9PQoJYXNzZXJ0CgoJLy8gY29udHJhY3RzL3ZhbGlkYXRvclJlZ2lzdHJ5LmFsZ28udHM6NTQ0CgkvLyBhc3NlcnQodGhpcy52YWxpZGF0b3JMaXN0KHZhbGlkYXRvcklkKS5leGlzdHMpCglieXRlIDB4NzYgLy8gInYiCglmcmFtZV9kaWcgLTIgLy8gdmFsaWRhdG9ySWQ6IFZhbGlkYXRvcklkVHlwZQoJaXRvYgoJY29uY2F0Cglib3hfbGVuCglzd2FwCglwb3AKCWFzc2VydAoKCS8vIGNvbnRyYWN0cy92YWxpZGF0b3JSZWdpc3RyeS5hbGdvLnRzOjU0NgoJLy8gbnVtUG9vbHM6IHVpbnQ2NCA9IHRoaXMudmFsaWRhdG9yTGlzdCh2YWxpZGF0b3JJZCkudmFsdWUuc3RhdGUubnVtUG9vbHMgYXMgdWludDY0CglpbnQgMjA4CglpbnQgMgoJYnl0ZSAweDc2IC8vICJ2IgoJZnJhbWVfZGlnIC0yIC8vIHZhbGlkYXRvcklkOiBWYWxpZGF0b3JJZFR5cGUKCWl0b2IKCWNvbmNhdAoJY292ZXIgMgoJYm94X2V4dHJhY3QKCWJ0b2kKCWZyYW1lX2J1cnkgMCAvLyBudW1Qb29sczogdWludDY0CgoJLy8gKmlmOF9jb25kaXRpb24KCS8vIGNvbnRyYWN0cy92YWxpZGF0b3JSZWdpc3RyeS5hbGdvLnRzOjU0NwoJLy8gKG51bVBvb2xzIGFzIHVpbnQ2NCkgPj0gTUFYX1BPT0xTCglmcmFtZV9kaWcgMCAvLyBudW1Qb29sczogdWludDY0CglpbnQgMjQKCT49CglieiAqaWY4X2VuZAoKCS8vICppZjhfY29uc2VxdWVudAoJZXJyIC8vICdhbHJlYWR5IGF0IG1heCBwb29sIHNpemUnCgoqaWY4X2VuZDoKCS8vIGNvbnRyYWN0cy92YWxpZGF0b3JSZWdpc3RyeS5hbGdvLnRzOjU1MAoJLy8gbnVtUG9vbHMgKz0gMQoJZnJhbWVfZGlnIDAgLy8gbnVtUG9vbHM6IHVpbnQ2NAoJaW50IDEKCSsKCWZyYW1lX2J1cnkgMCAvLyBudW1Qb29sczogdWludDY0CgoJLy8gY29udHJhY3RzL3ZhbGlkYXRvclJlZ2lzdHJ5LmFsZ28udHM6NTUzCgkvLyBzZW5kQXBwQ2FsbCh7CgkvLyAgICAgICAgICAgICBvbkNvbXBsZXRpb246IE9uQ29tcGxldGlvbi5Ob09wLAoJLy8gICAgICAgICAgICAgYXBwcm92YWxQcm9ncmFtOiBBcHBJRC5mcm9tVWludDY0KHRoaXMuc3Rha2luZ1Bvb2xUZW1wbGF0ZUFwcElkLnZhbHVlKS5hcHByb3ZhbFByb2dyYW0sCgkvLyAgICAgICAgICAgICBjbGVhclN0YXRlUHJvZ3JhbTogQXBwSUQuZnJvbVVpbnQ2NCh0aGlzLnN0YWtpbmdQb29sVGVtcGxhdGVBcHBJZC52YWx1ZSkuY2xlYXJTdGF0ZVByb2dyYW0sCgkvLyAgICAgICAgICAgICBnbG9iYWxOdW1VaW50OiBBcHBJRC5mcm9tVWludDY0KHRoaXMuc3Rha2luZ1Bvb2xUZW1wbGF0ZUFwcElkLnZhbHVlKS5nbG9iYWxOdW1VaW50LAoJLy8gICAgICAgICAgICAgZ2xvYmFsTnVtQnl0ZVNsaWNlOiBBcHBJRC5mcm9tVWludDY0KHRoaXMuc3Rha2luZ1Bvb2xUZW1wbGF0ZUFwcElkLnZhbHVlKS5nbG9iYWxOdW1CeXRlU2xpY2UsCgkvLyAgICAgICAgICAgICBleHRyYVByb2dyYW1QYWdlczogQXBwSUQuZnJvbVVpbnQ2NCh0aGlzLnN0YWtpbmdQb29sVGVtcGxhdGVBcHBJZC52YWx1ZSkuZXh0cmFQcm9ncmFtUGFnZXMsCgkvLyAgICAgICAgICAgICBhcHBsaWNhdGlvbkFyZ3M6IFsKCS8vICAgICAgICAgICAgICAgICAvLyBjcmVhdGluZ0NvbnRyYWN0SUQsIHZhbGlkYXRvcklkLCBwb29sSWQsIG1pbkVudHJ5U3Rha2UKCS8vICAgICAgICAgICAgICAgICBtZXRob2QoJ2NyZWF0ZUFwcGxpY2F0aW9uKHVpbnQ2NCx1aW50NjQsdWludDY0LHVpbnQ2NCl2b2lkJyksCgkvLyAgICAgICAgICAgICAgICAgaXRvYih0aGlzLmFwcC5pZCksCgkvLyAgICAgICAgICAgICAgICAgaXRvYih2YWxpZGF0b3JJZCksCgkvLyAgICAgICAgICAgICAgICAgaXRvYihudW1Qb29scyBhcyB1aW50NjQpLAoJLy8gICAgICAgICAgICAgICAgIGl0b2IodGhpcy52YWxpZGF0b3JMaXN0KHZhbGlkYXRvcklkKS52YWx1ZS5jb25maWcubWluRW50cnlTdGFrZSksCgkvLyAgICAgICAgICAgICBdLAoJLy8gICAgICAgICB9KQoJaXR4bl9iZWdpbgoJaW50IGFwcGwKCWl0eG5fZmllbGQgVHlwZUVudW0KCgkvLyBjb250cmFjdHMvdmFsaWRhdG9yUmVnaXN0cnkuYWxnby50czo1NTQKCS8vIG9uQ29tcGxldGlvbjogT25Db21wbGV0aW9uLk5vT3AKCWludCAwIC8vIE5vT3AKCWl0eG5fZmllbGQgT25Db21wbGV0aW9uCgoJLy8gY29udHJhY3RzL3ZhbGlkYXRvclJlZ2lzdHJ5LmFsZ28udHM6NTU1CgkvLyBhcHByb3ZhbFByb2dyYW06IEFwcElELmZyb21VaW50NjQodGhpcy5zdGFraW5nUG9vbFRlbXBsYXRlQXBwSWQudmFsdWUpLmFwcHJvdmFsUHJvZ3JhbQoJYnl0ZSAweDcwNmY2ZjZjNTQ2NTZkNzA2YzYxNzQ2NTQxNzA3MDQ5NjQgLy8gInBvb2xUZW1wbGF0ZUFwcElkIgoJYXBwX2dsb2JhbF9nZXQKCWFwcF9wYXJhbXNfZ2V0IEFwcEFwcHJvdmFsUHJvZ3JhbQoJcG9wCglpdHhuX2ZpZWxkIEFwcHJvdmFsUHJvZ3JhbQoKCS8vIGNvbnRyYWN0cy92YWxpZGF0b3JSZWdpc3RyeS5hbGdvLnRzOjU1NgoJLy8gY2xlYXJTdGF0ZVByb2dyYW06IEFwcElELmZyb21VaW50NjQodGhpcy5zdGFraW5nUG9vbFRlbXBsYXRlQXBwSWQudmFsdWUpLmNsZWFyU3RhdGVQcm9ncmFtCglieXRlIDB4NzA2ZjZmNmM1NDY1NmQ3MDZjNjE3NDY1NDE3MDcwNDk2NCAvLyAicG9vbFRlbXBsYXRlQXBwSWQiCglhcHBfZ2xvYmFsX2dldAoJYXBwX3BhcmFtc19nZXQgQXBwQ2xlYXJTdGF0ZVByb2dyYW0KCXBvcAoJaXR4bl9maWVsZCBDbGVhclN0YXRlUHJvZ3JhbQoKCS8vIGNvbnRyYWN0cy92YWxpZGF0b3JSZWdpc3RyeS5hbGdvLnRzOjU1NwoJLy8gZ2xvYmFsTnVtVWludDogQXBwSUQuZnJvbVVpbnQ2NCh0aGlzLnN0YWtpbmdQb29sVGVtcGxhdGVBcHBJZC52YWx1ZSkuZ2xvYmFsTnVtVWludAoJYnl0ZSAweDcwNmY2ZjZjNTQ2NTZkNzA2YzYxNzQ2NTQxNzA3MDQ5NjQgLy8gInBvb2xUZW1wbGF0ZUFwcElkIgoJYXBwX2dsb2JhbF9nZXQKCWFwcF9wYXJhbXNfZ2V0IEFwcEdsb2JhbE51bVVpbnQKCXBvcAoJaXR4bl9maWVsZCBHbG9iYWxOdW1VaW50CgoJLy8gY29udHJhY3RzL3ZhbGlkYXRvclJlZ2lzdHJ5LmFsZ28udHM6NTU4CgkvLyBnbG9iYWxOdW1CeXRlU2xpY2U6IEFwcElELmZyb21VaW50NjQodGhpcy5zdGFraW5nUG9vbFRlbXBsYXRlQXBwSWQudmFsdWUpLmdsb2JhbE51bUJ5dGVTbGljZQoJYnl0ZSAweDcwNmY2ZjZjNTQ2NTZkNzA2YzYxNzQ2NTQxNzA3MDQ5NjQgLy8gInBvb2xUZW1wbGF0ZUFwcElkIgoJYXBwX2dsb2JhbF9nZXQKCWFwcF9wYXJhbXNfZ2V0IEFwcEdsb2JhbE51bUJ5dGVTbGljZQoJcG9wCglpdHhuX2ZpZWxkIEdsb2JhbE51bUJ5dGVTbGljZQoKCS8vIGNvbnRyYWN0cy92YWxpZGF0b3JSZWdpc3RyeS5hbGdvLnRzOjU1OQoJLy8gZXh0cmFQcm9ncmFtUGFnZXM6IEFwcElELmZyb21VaW50NjQodGhpcy5zdGFraW5nUG9vbFRlbXBsYXRlQXBwSWQudmFsdWUpLmV4dHJhUHJvZ3JhbVBhZ2VzCglieXRlIDB4NzA2ZjZmNmM1NDY1NmQ3MDZjNjE3NDY1NDE3MDcwNDk2NCAvLyAicG9vbFRlbXBsYXRlQXBwSWQiCglhcHBfZ2xvYmFsX2dldAoJYXBwX3BhcmFtc19nZXQgQXBwRXh0cmFQcm9ncmFtUGFnZXMKCXBvcAoJaXR4bl9maWVsZCBFeHRyYVByb2dyYW1QYWdlcwoKCS8vIGNvbnRyYWN0cy92YWxpZGF0b3JSZWdpc3RyeS5hbGdvLnRzOjU2MAoJLy8gYXBwbGljYXRpb25BcmdzOiBbCgkvLyAgICAgICAgICAgICAgICAgLy8gY3JlYXRpbmdDb250cmFjdElELCB2YWxpZGF0b3JJZCwgcG9vbElkLCBtaW5FbnRyeVN0YWtlCgkvLyAgICAgICAgICAgICAgICAgbWV0aG9kKCdjcmVhdGVBcHBsaWNhdGlvbih1aW50NjQsdWludDY0LHVpbnQ2NCx1aW50NjQpdm9pZCcpLAoJLy8gICAgICAgICAgICAgICAgIGl0b2IodGhpcy5hcHAuaWQpLAoJLy8gICAgICAgICAgICAgICAgIGl0b2IodmFsaWRhdG9ySWQpLAoJLy8gICAgICAgICAgICAgICAgIGl0b2IobnVtUG9vbHMgYXMgdWludDY0KSwKCS8vICAgICAgICAgICAgICAgICBpdG9iKHRoaXMudmFsaWRhdG9yTGlzdCh2YWxpZGF0b3JJZCkudmFsdWUuY29uZmlnLm1pbkVudHJ5U3Rha2UpLAoJLy8gICAgICAgICAgICAgXQoJbWV0aG9kICJjcmVhdGVBcHBsaWNhdGlvbih1aW50NjQsdWludDY0LHVpbnQ2NCx1aW50NjQpdm9pZCIKCWl0eG5fZmllbGQgQXBwbGljYXRpb25BcmdzCgl0eG5hIEFwcGxpY2F0aW9ucyAwCglpdG9iCglpdHhuX2ZpZWxkIEFwcGxpY2F0aW9uQXJncwoJZnJhbWVfZGlnIC0yIC8vIHZhbGlkYXRvcklkOiBWYWxpZGF0b3JJZFR5cGUKCWl0b2IKCWl0eG5fZmllbGQgQXBwbGljYXRpb25BcmdzCglmcmFtZV9kaWcgMCAvLyBudW1Qb29sczogdWludDY0CglpdG9iCglpdHhuX2ZpZWxkIEFwcGxpY2F0aW9uQXJncwoJaW50IDE3NQoJaW50IDgKCWJ5dGUgMHg3NiAvLyAidiIKCWZyYW1lX2RpZyAtMiAvLyB2YWxpZGF0b3JJZDogVmFsaWRhdG9ySWRUeXBlCglpdG9iCgljb25jYXQKCWNvdmVyIDIKCWJveF9leHRyYWN0CglidG9pCglpdG9iCglpdHhuX2ZpZWxkIEFwcGxpY2F0aW9uQXJncwoKCS8vIEZlZSBmaWVsZCBub3Qgc2V0LCBkZWZhdWx0aW5nIHRvIDAKCWludCAwCglpdHhuX2ZpZWxkIEZlZQoKCS8vIFN1Ym1pdCBpbm5lciB0cmFuc2FjdGlvbgoJaXR4bl9zdWJtaXQKCgkvLyBjb250cmFjdHMvdmFsaWRhdG9yUmVnaXN0cnkuYWxnby50czo1NzAKCS8vIHRoaXMudmFsaWRhdG9yTGlzdCh2YWxpZGF0b3JJZCkudmFsdWUuc3RhdGUubnVtUG9vbHMgPSBudW1Qb29scyBhcyB1aW50MTYKCWludCAyMDgKCWZyYW1lX2RpZyAwIC8vIG51bVBvb2xzOiB1aW50NjQKCWl0b2IKCWV4dHJhY3QgNiAyCglieXRlIDB4NzYgLy8gInYiCglmcmFtZV9kaWcgLTIgLy8gdmFsaWRhdG9ySWQ6IFZhbGlkYXRvcklkVHlwZQoJaXRvYgoJY29uY2F0Cgljb3ZlciAyCglib3hfcmVwbGFjZQoKCS8vIGNvbnRyYWN0cy92YWxpZGF0b3JSZWdpc3RyeS5hbGdvLnRzOjU3MwoJLy8gcG9vbEFwcElkID0gdGhpcy5pdHhuLmNyZWF0ZWRBcHBsaWNhdGlvbklELmlkCglpdHhuIENyZWF0ZWRBcHBsaWNhdGlvbklECglmcmFtZV9idXJ5IDEgLy8gcG9vbEFwcElkOiB1aW50NjQKCgkvLyBjb250cmFjdHMvdmFsaWRhdG9yUmVnaXN0cnkuYWxnby50czo1NzQKCS8vIHRoaXMudmFsaWRhdG9yTGlzdCh2YWxpZGF0b3JJZCkudmFsdWUucG9vbHNbbnVtUG9vbHMgLSAxXS5wb29sQXBwSWQgPSBwb29sQXBwSWQKCWludCAyMzQgLy8gaGVhZE9mZnNldAoJZnJhbWVfZGlnIDAgLy8gbnVtUG9vbHM6IHVpbnQ2NAoJaW50IDEKCS0KCWludCAxOAoJKiAvLyBhY2MgKiB0eXBlTGVuZ3RoCgkrCglpbnQgMAoJKwoJZnJhbWVfZGlnIDEgLy8gcG9vbEFwcElkOiB1aW50NjQKCWl0b2IKCWJ5dGUgMHg3NiAvLyAidiIKCWZyYW1lX2RpZyAtMiAvLyB2YWxpZGF0b3JJZDogVmFsaWRhdG9ySWRUeXBlCglpdG9iCgljb25jYXQKCWNvdmVyIDIKCWJveF9yZXBsYWNlCgoJLy8gY29udHJhY3RzL3ZhbGlkYXRvclJlZ2lzdHJ5LmFsZ28udHM6NTc1CgkvLyB0aGlzLmFkZFBvb2xUb05vZGUodmFsaWRhdG9ySWQsIHBvb2xBcHBJZCwgbm9kZU51bSkKCWZyYW1lX2RpZyAtMyAvLyBub2RlTnVtOiB1aW50NjQKCWZyYW1lX2RpZyAxIC8vIHBvb2xBcHBJZDogdWludDY0CglmcmFtZV9kaWcgLTIgLy8gdmFsaWRhdG9ySWQ6IFZhbGlkYXRvcklkVHlwZQoJY2FsbHN1YiBhZGRQb29sVG9Ob2RlCgoJLy8gY29udHJhY3RzL3ZhbGlkYXRvclJlZ2lzdHJ5LmFsZ28udHM6NTgzCgkvLyByZXR1cm4geyBpZDogdmFsaWRhdG9ySWQsIHBvb2xJZDogbnVtUG9vbHMgYXMgdWludDY0LCBwb29sQXBwSWQ6IHRoaXMuaXR4biEuY3JlYXRlZEFwcGxpY2F0aW9uSUQuaWQgfTsKCWZyYW1lX2RpZyAtMiAvLyB2YWxpZGF0b3JJZDogVmFsaWRhdG9ySWRUeXBlCglpdG9iCglmcmFtZV9kaWcgMCAvLyBudW1Qb29sczogdWludDY0CglpdG9iCgljb25jYXQKCWl0eG4gQ3JlYXRlZEFwcGxpY2F0aW9uSUQKCWl0b2IKCWNvbmNhdAoKCS8vIHNldCB0aGUgc3Vicm91dGluZSByZXR1cm4gdmFsdWUKCWZyYW1lX2J1cnkgMAoKCS8vIHBvcCBhbGwgbG9jYWwgdmFyaWFibGVzIGZyb20gdGhlIHN0YWNrCglwb3BuIDEKCXJldHN1YgoKLy8gYWRkU3Rha2UocGF5LHVpbnQ2NCx1aW50NjQpKHVpbnQ2NCx1aW50NjQsdWludDY0KQoqYWJpX3JvdXRlX2FkZFN0YWtlOgoJLy8gVGhlIEFCSSByZXR1cm4gcHJlZml4CglieXRlIDB4MTUxZjdjNzUKCgkvLyB2YWx1ZVRvVmVyaWZ5OiB1aW50NjQKCXR4bmEgQXBwbGljYXRpb25BcmdzIDIKCWJ0b2kKCgkvLyB2YWxpZGF0b3JJZDogdWludDY0Cgl0eG5hIEFwcGxpY2F0aW9uQXJncyAxCglidG9pCgoJLy8gc3Rha2VkQW1vdW50UGF5bWVudDogcGF5Cgl0eG4gR3JvdXBJbmRleAoJaW50IDEKCS0KCWR1cAoJZ3R4bnMgVHlwZUVudW0KCWludCBwYXkKCT09Cglhc3NlcnQKCgkvLyBleGVjdXRlIGFkZFN0YWtlKHBheSx1aW50NjQsdWludDY0KSh1aW50NjQsdWludDY0LHVpbnQ2NCkKCWNhbGxzdWIgYWRkU3Rha2UKCWNvbmNhdAoJbG9nCglpbnQgMQoJcmV0dXJuCgovLyBhZGRTdGFrZShzdGFrZWRBbW91bnRQYXltZW50OiBQYXlUeG4sIHZhbGlkYXRvcklkOiBWYWxpZGF0b3JJZFR5cGUsIHZhbHVlVG9WZXJpZnk6IHVpbnQ2NCk6IFZhbGlkYXRvclBvb2xLZXkKLy8KLy8gQWRkcyBzdGFrZSB0byBhIHZhbGlkYXRvciBwb29sLgovLwovLyBAcGFyYW0ge1BheVR4bn0gc3Rha2VkQW1vdW50UGF5bWVudCAtIHBheW1lbnQgY29taW5nIGZyb20gc3Rha2VyIHRvIHBsYWNlIGludG8gYSBwb29sCi8vIEBwYXJhbSB7VmFsaWRhdG9ySWRUeXBlfSB2YWxpZGF0b3JJZCAtIFRoZSBpZCBvZiB0aGUgdmFsaWRhdG9yLgovLyBAcGFyYW0ge3VpbnQ2NH0gdmFsdWVUb1ZlcmlmeSAtIG9ubHkgaWYgdmFsaWRhdG9yIGhhcyBnYXRpbmcgdG8gZW50ZXIgLSB0aGlzIGlzIGFzc2V0IGlkIG9yIG5mZCBpZCB0aGF0IGNvcnJlc3BvbmRzIHRvIGdhdGluZy4KLy8gVHhuIHNlbmRlciBpcyBmYWN0b3JlZCBpbiBhcyB3ZWxsIGlmIHRoYXQgaXMgcGFydCBvZiBnYXRpbmcuCi8vICogQHJldHVybnMge1ZhbGlkYXRvclBvb2xLZXl9IC0gVGhlIGtleSBvZiB0aGUgdmFsaWRhdG9yIHBvb2wuCmFkZFN0YWtlOgoJcHJvdG8gMyAxCgoJLy8gUHVzaCBlbXB0eSBieXRlcyBhZnRlciB0aGUgZnJhbWUgcG9pbnRlciB0byByZXNlcnZlIHNwYWNlIGZvciBsb2NhbCB2YXJpYWJsZXMKCWJ5dGUgMHgKCWR1cG4gNQoKCS8vIGNvbnRyYWN0cy92YWxpZGF0b3JSZWdpc3RyeS5hbGdvLnRzOjU5NgoJLy8gYXNzZXJ0KHRoaXMudmFsaWRhdG9yTGlzdCh2YWxpZGF0b3JJZCkuZXhpc3RzKQoJYnl0ZSAweDc2IC8vICJ2IgoJZnJhbWVfZGlnIC0yIC8vIHZhbGlkYXRvcklkOiBWYWxpZGF0b3JJZFR5cGUKCWl0b2IKCWNvbmNhdAoJYm94X2xlbgoJc3dhcAoJcG9wCglhc3NlcnQKCgkvLyBjb250cmFjdHMvdmFsaWRhdG9yUmVnaXN0cnkuYWxnby50czo1OTgKCS8vIHN0YWtlciA9IHRoaXMudHhuLnNlbmRlcgoJdHhuIFNlbmRlcgoJZnJhbWVfYnVyeSAwIC8vIHN0YWtlcjogYWRkcmVzcwoKCS8vIGNvbnRyYWN0cy92YWxpZGF0b3JSZWdpc3RyeS5hbGdvLnRzOjYwMgoJLy8gdmVyaWZ5UGF5VHhuKHN0YWtlZEFtb3VudFBheW1lbnQsIHsKCS8vICAgICAgICAgICAgIHNlbmRlcjogc3Rha2VyLAoJLy8gICAgICAgICAgICAgcmVjZWl2ZXI6IHRoaXMuYXBwLmFkZHJlc3MsCgkvLyAgICAgICAgIH0pCgkvLyB2ZXJpZnkgc2VuZGVyCglmcmFtZV9kaWcgLTEgLy8gc3Rha2VkQW1vdW50UGF5bWVudDogUGF5VHhuCglndHhucyBTZW5kZXIKCWZyYW1lX2RpZyAwIC8vIHN0YWtlcjogYWRkcmVzcwoJPT0KCWFzc2VydAoKCS8vIHZlcmlmeSByZWNlaXZlcgoJZnJhbWVfZGlnIC0xIC8vIHN0YWtlZEFtb3VudFBheW1lbnQ6IFBheVR4bgoJZ3R4bnMgUmVjZWl2ZXIKCWdsb2JhbCBDdXJyZW50QXBwbGljYXRpb25BZGRyZXNzCgk9PQoJYXNzZXJ0CgoJLy8gY29udHJhY3RzL3ZhbGlkYXRvclJlZ2lzdHJ5LmFsZ28udHM6NjA5CgkvLyBhc3NlcnQoCgkvLyAgICAgICAgICAgICB0aGlzLnZhbGlkYXRvckxpc3QodmFsaWRhdG9ySWQpLnZhbHVlLnN0YXRlLnRvdGFsQWxnb1N0YWtlZCA8IHRoaXMubWF4QWxsb3dlZFN0YWtlKCksCgkvLyAgICAgICAgICAgICAndG90YWwgc3Rha2VkIGZvciBhbGwgb2YgYSB2YWxpZGF0b3JzIHBvb2xzIG1heSBub3QgZXhjZWVkIGhhcmQgY2FwJwoJLy8gICAgICAgICApCglpbnQgMjE4CglpbnQgOAoJYnl0ZSAweDc2IC8vICJ2IgoJZnJhbWVfZGlnIC0yIC8vIHZhbGlkYXRvcklkOiBWYWxpZGF0b3JJZFR5cGUKCWl0b2IKCWNvbmNhdAoJY292ZXIgMgoJYm94X2V4dHJhY3QKCWJ0b2kKCWNhbGxzdWIgbWF4QWxsb3dlZFN0YWtlCgk8CgoJLy8gdG90YWwgc3Rha2VkIGZvciBhbGwgb2YgYSB2YWxpZGF0b3JzIHBvb2xzIG1heSBub3QgZXhjZWVkIGhhcmQgY2FwCglhc3NlcnQKCgkvLyBjb250cmFjdHMvdmFsaWRhdG9yUmVnaXN0cnkuYWxnby50czo2MTYKCS8vIHRoaXMuZG9lc1N0YWtlck1lZXRHYXRpbmcodmFsaWRhdG9ySWQsIHZhbHVlVG9WZXJpZnkpCglmcmFtZV9kaWcgLTMgLy8gdmFsdWVUb1ZlcmlmeTogdWludDY0CglmcmFtZV9kaWcgLTIgLy8gdmFsaWRhdG9ySWQ6IFZhbGlkYXRvcklkVHlwZQoJY2FsbHN1YiBkb2VzU3Rha2VyTWVldEdhdGluZwoKCS8vIGNvbnRyYWN0cy92YWxpZGF0b3JSZWdpc3RyeS5hbGdvLnRzOjYxOAoJLy8gcmVhbEFtb3VudCA9IHN0YWtlZEFtb3VudFBheW1lbnQuYW1vdW50CglmcmFtZV9kaWcgLTEgLy8gc3Rha2VkQW1vdW50UGF5bWVudDogUGF5VHhuCglndHhucyBBbW91bnQKCWZyYW1lX2J1cnkgMSAvLyByZWFsQW1vdW50OiB1aW50NjQKCgkvLyBjb250cmFjdHMvdmFsaWRhdG9yUmVnaXN0cnkuYWxnby50czo2MTkKCS8vIG1ickFtdExlZnRCZWhpbmQ6IHVpbnQ2NCA9IDAKCWludCAwCglmcmFtZV9idXJ5IDIgLy8gbWJyQW10TGVmdEJlaGluZDogdWludDY0CgoJLy8gKmlmOV9jb25kaXRpb24KCS8vIGNvbnRyYWN0cy92YWxpZGF0b3JSZWdpc3RyeS5hbGdvLnRzOjYyMQoJLy8gIXRoaXMuc3Rha2VyUG9vbFNldChzdGFrZXIpLmV4aXN0cwoJYnl0ZSAweDczNzA3MyAvLyAic3BzIgoJZnJhbWVfZGlnIDAgLy8gc3Rha2VyOiBhZGRyZXNzCgljb25jYXQKCWJveF9sZW4KCXN3YXAKCXBvcAoJIQoJYnogKmlmOV9lbmQKCgkvLyAqaWY5X2NvbnNlcXVlbnQKCS8vIGNvbnRyYWN0cy92YWxpZGF0b3JSZWdpc3RyeS5hbGdvLnRzOjYyNAoJLy8gbWJyQW10TGVmdEJlaGluZCA9IHRoaXMuZ2V0TWJyQW1vdW50cygpLmFkZFN0YWtlck1icgoJY2FsbHN1YiBnZXRNYnJBbW91bnRzCglleHRyYWN0IDI0IDgKCWJ0b2kKCWZyYW1lX2J1cnkgMiAvLyBtYnJBbXRMZWZ0QmVoaW5kOiB1aW50NjQKCgkvLyBjb250cmFjdHMvdmFsaWRhdG9yUmVnaXN0cnkuYWxnby50czo2MjUKCS8vIHJlYWxBbW91bnQgLT0gbWJyQW10TGVmdEJlaGluZAoJZnJhbWVfZGlnIDEgLy8gcmVhbEFtb3VudDogdWludDY0CglmcmFtZV9kaWcgMiAvLyBtYnJBbXRMZWZ0QmVoaW5kOiB1aW50NjQKCS0KCWZyYW1lX2J1cnkgMSAvLyByZWFsQW1vdW50OiB1aW50NjQKCgkvLyBjb250cmFjdHMvdmFsaWRhdG9yUmVnaXN0cnkuYWxnby50czo2MjYKCS8vIHRoaXMuc3Rha2VyUG9vbFNldChzdGFrZXIpLmNyZWF0ZSgpCglieXRlIDB4NzM3MDczIC8vICJzcHMiCglmcmFtZV9kaWcgMCAvLyBzdGFrZXI6IGFkZHJlc3MKCWNvbmNhdAoJaW50IDE0NAoJYm94X2NyZWF0ZQoJcG9wCgoqaWY5X2VuZDoKCS8vIGNvbnRyYWN0cy92YWxpZGF0b3JSZWdpc3RyeS5hbGdvLnRzOjYzMAoJLy8gZmluZFJldCA9IHRoaXMuZmluZFBvb2xGb3JTdGFrZXIodmFsaWRhdG9ySWQsIHN0YWtlciwgcmVhbEFtb3VudCkKCWZyYW1lX2RpZyAxIC8vIHJlYWxBbW91bnQ6IHVpbnQ2NAoJZnJhbWVfZGlnIDAgLy8gc3Rha2VyOiBhZGRyZXNzCglmcmFtZV9kaWcgLTIgLy8gdmFsaWRhdG9ySWQ6IFZhbGlkYXRvcklkVHlwZQoJY2FsbHN1YiBmaW5kUG9vbEZvclN0YWtlcgoJZnJhbWVfYnVyeSAzIC8vIGZpbmRSZXQ6ICgodWludDY0LHVpbnQ2NCx1aW50NjQpLGJvb2wsYm9vbCkKCgkvLyBjb250cmFjdHMvdmFsaWRhdG9yUmVnaXN0cnkuYWxnby50czo2MzEKCS8vIHBvb2xLZXkgPSBmaW5kUmV0WzBdCgkvLyBjb250cmFjdHMvdmFsaWRhdG9yUmVnaXN0cnkuYWxnby50czo2MzIKCS8vIGlzTmV3U3Rha2VyVG9WYWxpZGF0b3IgPSBmaW5kUmV0WzFdCglmcmFtZV9kaWcgMyAvLyBmaW5kUmV0OiAoKHVpbnQ2NCx1aW50NjQsdWludDY0KSxib29sLGJvb2wpCglzdG9yZSAyNTUgLy8gZnVsbCBhcnJheQoJbG9hZCAyNTUgLy8gZnVsbCBhcnJheQoJaW50IDE5MgoJZ2V0Yml0CglmcmFtZV9idXJ5IDQgLy8gaXNOZXdTdGFrZXJUb1ZhbGlkYXRvcjogYm9vbAoKCS8vIGNvbnRyYWN0cy92YWxpZGF0b3JSZWdpc3RyeS5hbGdvLnRzOjYzMwoJLy8gaXNOZXdTdGFrZXJUb1Byb3RvY29sID0gZmluZFJldFsyXQoJZnJhbWVfZGlnIDMgLy8gZmluZFJldDogKCh1aW50NjQsdWludDY0LHVpbnQ2NCksYm9vbCxib29sKQoJc3RvcmUgMjU1IC8vIGZ1bGwgYXJyYXkKCWxvYWQgMjU1IC8vIGZ1bGwgYXJyYXkKCWludCAxOTMKCWdldGJpdAoJZnJhbWVfYnVyeSA1IC8vIGlzTmV3U3Rha2VyVG9Qcm90b2NvbDogYm9vbAoKCS8vICppZjEwX2NvbmRpdGlvbgoJLy8gY29udHJhY3RzL3ZhbGlkYXRvclJlZ2lzdHJ5LmFsZ28udHM6NjM0CgkvLyBwb29sS2V5LnBvb2xJZCA9PT0gMAoJZnJhbWVfZGlnIDMgLy8gZmluZFJldDogKCh1aW50NjQsdWludDY0LHVpbnQ2NCksYm9vbCxib29sKQoJc3RvcmUgMjU1IC8vIGZ1bGwgYXJyYXkKCWxvYWQgMjU1IC8vIGZ1bGwgYXJyYXkKCWV4dHJhY3QgOCA4CglidG9pCglpbnQgMAoJPT0KCWJ6ICppZjEwX2VuZAoKCS8vICppZjEwX2NvbnNlcXVlbnQKCWVyciAvLyAnTm8gcG9vbCBhdmFpbGFibGUgd2l0aCBmcmVlIHN0YWtlLiAgVmFsaWRhdG9yIG5lZWRzIHRvIGFkZCBhbm90aGVyIHBvb2wnCgoqaWYxMF9lbmQ6CgkvLyBjb250cmFjdHMvdmFsaWRhdG9yUmVnaXN0cnkuYWxnby50czo2MzkKCS8vIHRoaXMudXBkYXRlU3Rha2VyUG9vbFNldChzdGFrZXIsIHBvb2xLZXkpCglmcmFtZV9kaWcgMyAvLyBmaW5kUmV0OiAoKHVpbnQ2NCx1aW50NjQsdWludDY0KSxib29sLGJvb2wpCglzdG9yZSAyNTUgLy8gZnVsbCBhcnJheQoJbG9hZCAyNTUgLy8gZnVsbCBhcnJheQoJZXh0cmFjdCAwIDI0CglmcmFtZV9kaWcgMCAvLyBzdGFrZXI6IGFkZHJlc3MKCWNhbGxzdWIgdXBkYXRlU3Rha2VyUG9vbFNldAoKCS8vIGNvbnRyYWN0cy92YWxpZGF0b3JSZWdpc3RyeS5hbGdvLnRzOjY0MgoJLy8gdGhpcy5jYWxsUG9vbEFkZFN0YWtlKAoJLy8gICAgICAgICAgICAgc3Rha2VkQW1vdW50UGF5bWVudCwKCS8vICAgICAgICAgICAgIHBvb2xLZXksCgkvLyAgICAgICAgICAgICBtYnJBbXRMZWZ0QmVoaW5kLAoJLy8gICAgICAgICAgICAgaXNOZXdTdGFrZXJUb1ZhbGlkYXRvciwKCS8vICAgICAgICAgICAgIGlzTmV3U3Rha2VyVG9Qcm90b2NvbAoJLy8gICAgICAgICApCglmcmFtZV9kaWcgNSAvLyBpc05ld1N0YWtlclRvUHJvdG9jb2w6IGJvb2wKCWZyYW1lX2RpZyA0IC8vIGlzTmV3U3Rha2VyVG9WYWxpZGF0b3I6IGJvb2wKCWZyYW1lX2RpZyAyIC8vIG1ickFtdExlZnRCZWhpbmQ6IHVpbnQ2NAoJZnJhbWVfZGlnIDMgLy8gZmluZFJldDogKCh1aW50NjQsdWludDY0LHVpbnQ2NCksYm9vbCxib29sKQoJc3RvcmUgMjU1IC8vIGZ1bGwgYXJyYXkKCWxvYWQgMjU1IC8vIGZ1bGwgYXJyYXkKCWV4dHJhY3QgMCAyNAoJZnJhbWVfZGlnIC0xIC8vIHN0YWtlZEFtb3VudFBheW1lbnQ6IFBheVR4bgoJY2FsbHN1YiBjYWxsUG9vbEFkZFN0YWtlCgoJLy8gY29udHJhY3RzL3ZhbGlkYXRvclJlZ2lzdHJ5LmFsZ28udHM6NjU3CgkvLyByZXR1cm4gcG9vbEtleTsKCWZyYW1lX2RpZyAzIC8vIGZpbmRSZXQ6ICgodWludDY0LHVpbnQ2NCx1aW50NjQpLGJvb2wsYm9vbCkKCXN0b3JlIDI1NSAvLyBmdWxsIGFycmF5Cglsb2FkIDI1NSAvLyBmdWxsIGFycmF5CglleHRyYWN0IDAgMjQKCgkvLyBzZXQgdGhlIHN1YnJvdXRpbmUgcmV0dXJuIHZhbHVlCglmcmFtZV9idXJ5IDAKCgkvLyBwb3AgYWxsIGxvY2FsIHZhcmlhYmxlcyBmcm9tIHRoZSBzdGFjawoJcG9wbiA1CglyZXRzdWIKCi8vIHNldFRva2VuUGF5b3V0UmF0aW8odWludDY0KSh1aW50NjRbMjRdLHVpbnQ2NCkKKmFiaV9yb3V0ZV9zZXRUb2tlblBheW91dFJhdGlvOgoJLy8gVGhlIEFCSSByZXR1cm4gcHJlZml4CglieXRlIDB4MTUxZjdjNzUKCgkvLyB2YWxpZGF0b3JJZDogdWludDY0Cgl0eG5hIEFwcGxpY2F0aW9uQXJncyAxCglidG9pCgoJLy8gZXhlY3V0ZSBzZXRUb2tlblBheW91dFJhdGlvKHVpbnQ2NCkodWludDY0WzI0XSx1aW50NjQpCgljYWxsc3ViIHNldFRva2VuUGF5b3V0UmF0aW8KCWNvbmNhdAoJbG9nCglpbnQgMQoJcmV0dXJuCgovLyBzZXRUb2tlblBheW91dFJhdGlvKHZhbGlkYXRvcklkOiBWYWxpZGF0b3JJZFR5cGUpOiBQb29sVG9rZW5QYXlvdXRSYXRpbwovLwovLyBzZXRUb2tlblBheW91dFJhdGlvIGlzIGNhbGxlZCBieSBTdGFraW5nIFBvb2wgIyAxIChPTkxZKSB0byBhc2sgdGhlIHZhbGlkYXRvciAodXMpIHRvIGNhbGN1bGF0ZSB0aGUgcmF0aW9zCi8vIG9mIHN0YWtlIGluIHRoZSBwb29scyBmb3Igc3Vic2VxdWVudCB0b2tlbiBwYXlvdXRzIChpZTogMiBwb29scywgJzEwMCcgYWxnbyB0b3RhbCBzdGFrZWQsIDYwIGluIHBvb2wgMSwgYW5kIDQwCi8vIGluIHBvb2wgMi4gIFRoaXMgaXMgZG9uZSBzbyB3ZSBoYXZlIGEgc3RhYmxlIHNuYXBzaG90IG9mIHN0YWtlIC0gdGFrZW4gb25jZSBwZXIgZXBvY2ggLSBvbmx5IHRyaWdnZXJlZCBieQovLyBwb29sIDEgZG9pbmcgcGF5b3V0LiAgcG9vbHMgb3RoZXIgdGhhbiAxIGRvaW5nIHBheW91dCBjYWxsIHBvb2wgMSB0byBhc2sgaXQgZG8gaXQgZmlyc3QuCi8vIEl0IHdvdWxkIGJlIDYwLzQwJSBpbiB0aGUgcG9vbFBjdE9mV2hvbGUgdmFsdWVzLiAgVGhlIHRva2VuIHJld2FyZCBwYXlvdXRzIHRoZW4gdXNlIHRoZXNlIHZhbHVlcyBpbnN0ZWFkIG9mCi8vIHRoZWlyICdjdXJyZW50JyBzdGFrZSB3aGljaCBjaGFuZ2VzIGFzIHBhcnQgb2YgdGhlIHBheW91dHMgdGhlbXNlbHZlcyAoYW5kIHBlb3BsZSBjb3VsZCBiZSBjaGFuZ2luZyBzdGFrZQovLyBkdXJpbmcgdGhlIGVwb2NoIHVwZGF0ZXMgYWNyb3NzIHBvb2xzKQovLwovLyBNdWx0aXBsZSBwb29scyB3aWxsIGNhbGwgdXMgdmlhIHBvb2wgMSAocG9vbDItPnBvb2wxLT52YWxkaWF0b3IsIGV0Yy4pIHNvIGRvbid0IGFzc2VydCBvbiBwb29sMSBjYWxsaW5nIG11bHRpcGxlCi8vIHRpbWVzIGluIHNhbWUgZXBvY2guICBKdXN0IHJldHVybi4KLy8KLy8gQHBhcmFtIHZhbGlkYXRvcklkIC0gdmFsaWRhdG9yIGlkIChhbmQgdGh1cyBwb29sKSBjYWxsaW5nIHVzLiAgVmVyaWZpZWQgc28gdGhhdCBzZW5kZXIgTVVTVCBiZSBwb29sIDEgb2YgdGhpcyB2YWxpZGF0b3IuCi8vIEByZXR1cm5zIFBvb2xUb2tlblBheW91dFJhdGlvIC0gdGhlIGZpbmlzaGVkIHJhdGlvIGRhdGEKc2V0VG9rZW5QYXlvdXRSYXRpbzoKCXByb3RvIDEgMQoKCS8vIFB1c2ggZW1wdHkgYnl0ZXMgYWZ0ZXIgdGhlIGZyYW1lIHBvaW50ZXIgdG8gcmVzZXJ2ZSBzcGFjZSBmb3IgbG9jYWwgdmFyaWFibGVzCglieXRlIDB4CglkdXBuIDgKCgkvLyBjb250cmFjdHMvdmFsaWRhdG9yUmVnaXN0cnkuYWxnby50czo2NzcKCS8vIHBvb2wxQXBwSUQgPSB0aGlzLnZhbGlkYXRvckxpc3QodmFsaWRhdG9ySWQpLnZhbHVlLnBvb2xzWzBdLnBvb2xBcHBJZAoJaW50IDIzNAoJaW50IDgKCWJ5dGUgMHg3NiAvLyAidiIKCWZyYW1lX2RpZyAtMSAvLyB2YWxpZGF0b3JJZDogVmFsaWRhdG9ySWRUeXBlCglpdG9iCgljb25jYXQKCWNvdmVyIDIKCWJveF9leHRyYWN0CglidG9pCglmcmFtZV9idXJ5IDAgLy8gcG9vbDFBcHBJRDogdWludDY0CgoJLy8gY29udHJhY3RzL3ZhbGlkYXRvclJlZ2lzdHJ5LmFsZ28udHM6Njc4CgkvLyBhc3NlcnQocG9vbDFBcHBJRCAhPT0gMCkKCWZyYW1lX2RpZyAwIC8vIHBvb2wxQXBwSUQ6IHVpbnQ2NAoJaW50IDAKCSE9Cglhc3NlcnQKCgkvLyAqaWYxMV9jb25kaXRpb24KCS8vIGNvbnRyYWN0cy92YWxpZGF0b3JSZWdpc3RyeS5hbGdvLnRzOjY4MAoJLy8gdGhpcy50eG4uc2VuZGVyICE9PSBBcHBJRC5mcm9tVWludDY0KHBvb2wxQXBwSUQpLmFkZHJlc3MKCXR4biBTZW5kZXIKCWZyYW1lX2RpZyAwIC8vIHBvb2wxQXBwSUQ6IHVpbnQ2NAoJYXBwX3BhcmFtc19nZXQgQXBwQWRkcmVzcwoJcG9wCgkhPQoJYnogKmlmMTFfZW5kCgoJLy8gKmlmMTFfY29uc2VxdWVudAoJLy8gY29udHJhY3RzL3ZhbGlkYXRvclJlZ2lzdHJ5LmFsZ28udHM6NjgxCgkvLyByZXR1cm4gdGhpcy52YWxpZGF0b3JMaXN0KHZhbGlkYXRvcklkKS52YWx1ZS50b2tlblBheW91dFJhdGlvOwoJaW50IDY2NiAvLyBoZWFkT2Zmc2V0CglpbnQgMjAwCglieXRlIDB4NzYgLy8gInYiCglmcmFtZV9kaWcgLTEgLy8gdmFsaWRhdG9ySWQ6IFZhbGlkYXRvcklkVHlwZQoJaXRvYgoJY29uY2F0Cgljb3ZlciAyCglib3hfZXh0cmFjdAoKCS8vIHNldCB0aGUgc3Vicm91dGluZSByZXR1cm4gdmFsdWUKCWZyYW1lX2J1cnkgMAoJcmV0c3ViCgoqaWYxMV9lbmQ6CgkvLyBjb250cmFjdHMvdmFsaWRhdG9yUmVnaXN0cnkuYWxnby50czo2ODYKCS8vIGN1clRpbWUgPSBnbG9iYWxzLmxhdGVzdFRpbWVzdGFtcAoJZ2xvYmFsIExhdGVzdFRpbWVzdGFtcAoJZnJhbWVfYnVyeSAxIC8vIGN1clRpbWU6IHVpbnQ2NAoKCS8vIGNvbnRyYWN0cy92YWxpZGF0b3JSZWdpc3RyeS5hbGdvLnRzOjY4NwoJLy8gbGFzdFBheW91dFVwZGF0ZSA9IHRoaXMudmFsaWRhdG9yTGlzdCh2YWxpZGF0b3JJZCkudmFsdWUudG9rZW5QYXlvdXRSYXRpby51cGRhdGVkRm9yUGF5b3V0CglpbnQgODU4CglpbnQgOAoJYnl0ZSAweDc2IC8vICJ2IgoJZnJhbWVfZGlnIC0xIC8vIHZhbGlkYXRvcklkOiBWYWxpZGF0b3JJZFR5cGUKCWl0b2IKCWNvbmNhdAoJY292ZXIgMgoJYm94X2V4dHJhY3QKCWJ0b2kKCWZyYW1lX2J1cnkgMiAvLyBsYXN0UGF5b3V0VXBkYXRlOiB1aW50NjQKCgkvLyAqaWYxMl9jb25kaXRpb24KCS8vIGNvbnRyYWN0cy92YWxpZGF0b3JSZWdpc3RyeS5hbGdvLnRzOjY4OAoJLy8gbGFzdFBheW91dFVwZGF0ZSAhPT0gMAoJZnJhbWVfZGlnIDIgLy8gbGFzdFBheW91dFVwZGF0ZTogdWludDY0CglpbnQgMAoJIT0KCWJ6ICppZjEyX2VuZAoKCS8vICppZjEyX2NvbnNlcXVlbnQKCS8vICppZjEzX2NvbmRpdGlvbgoJLy8gY29udHJhY3RzL3ZhbGlkYXRvclJlZ2lzdHJ5LmFsZ28udHM6NjkwCgkvLyAoQXBwSUQuZnJvbVVpbnQ2NChwb29sMUFwcElEKS5nbG9iYWxTdGF0ZSgnbGFzdFBheW91dCcpIGFzIHVpbnQ2NCkgPT09IGxhc3RQYXlvdXRVcGRhdGUKCWZyYW1lX2RpZyAwIC8vIHBvb2wxQXBwSUQ6IHVpbnQ2NAoJYnl0ZSAweDZjNjE3Mzc0NTA2MTc5NmY3NTc0IC8vICJsYXN0UGF5b3V0IgoJYXBwX2dsb2JhbF9nZXRfZXgKCWFzc2VydAoJZnJhbWVfZGlnIDIgLy8gbGFzdFBheW91dFVwZGF0ZTogdWludDY0Cgk9PQoJYnogKmlmMTNfZW5kCgoJLy8gKmlmMTNfY29uc2VxdWVudAoJLy8gY29udHJhY3RzL3ZhbGlkYXRvclJlZ2lzdHJ5LmFsZ28udHM6NjkxCgkvLyByZXR1cm4gdGhpcy52YWxpZGF0b3JMaXN0KHZhbGlkYXRvcklkKS52YWx1ZS50b2tlblBheW91dFJhdGlvOwoJaW50IDY2NiAvLyBoZWFkT2Zmc2V0CglpbnQgMjAwCglieXRlIDB4NzYgLy8gInYiCglmcmFtZV9kaWcgLTEgLy8gdmFsaWRhdG9ySWQ6IFZhbGlkYXRvcklkVHlwZQoJaXRvYgoJY29uY2F0Cgljb3ZlciAyCglib3hfZXh0cmFjdAoKCS8vIHNldCB0aGUgc3Vicm91dGluZSByZXR1cm4gdmFsdWUKCWZyYW1lX2J1cnkgMAoKCS8vIHBvcCBhbGwgbG9jYWwgdmFyaWFibGVzIGZyb20gdGhlIHN0YWNrCglwb3BuIDIKCXJldHN1YgoKKmlmMTNfZW5kOgoJLy8gY29udHJhY3RzL3ZhbGlkYXRvclJlZ2lzdHJ5LmFsZ28udHM6NjkzCgkvLyBzZWNzU2luY2VMYXN0UGF5b3V0ID0gY3VyVGltZSAtIGxhc3RQYXlvdXRVcGRhdGUKCWZyYW1lX2RpZyAxIC8vIGN1clRpbWU6IHVpbnQ2NAoJZnJhbWVfZGlnIDIgLy8gbGFzdFBheW91dFVwZGF0ZTogdWludDY0CgktCglmcmFtZV9idXJ5IDMgLy8gc2Vjc1NpbmNlTGFzdFBheW91dDogdWludDY0CgoJLy8gY29udHJhY3RzL3ZhbGlkYXRvclJlZ2lzdHJ5LmFsZ28udHM6Njk0CgkvLyBlcG9jaEluU2VjcyA9ICh0aGlzLnZhbGlkYXRvckxpc3QodmFsaWRhdG9ySWQpLnZhbHVlLmNvbmZpZy5wYXlvdXRFdmVyeVhNaW5zIGFzIHVpbnQ2NCkgKiA2MAoJaW50IDEzNwoJaW50IDIKCWJ5dGUgMHg3NiAvLyAidiIKCWZyYW1lX2RpZyAtMSAvLyB2YWxpZGF0b3JJZDogVmFsaWRhdG9ySWRUeXBlCglpdG9iCgljb25jYXQKCWNvdmVyIDIKCWJveF9leHRyYWN0CglidG9pCglpbnQgNjAKCSoKCWZyYW1lX2J1cnkgNCAvLyBlcG9jaEluU2VjczogdWludDY0CgoJLy8gKmlmMTRfY29uZGl0aW9uCgkvLyBjb250cmFjdHMvdmFsaWRhdG9yUmVnaXN0cnkuYWxnby50czo2OTYKCS8vIHNlY3NTaW5jZUxhc3RQYXlvdXQgPCBlcG9jaEluU2VjcwoJZnJhbWVfZGlnIDMgLy8gc2Vjc1NpbmNlTGFzdFBheW91dDogdWludDY0CglmcmFtZV9kaWcgNCAvLyBlcG9jaEluU2VjczogdWludDY0Cgk8CglieiAqaWYxNF9lbmQKCgkvLyAqaWYxNF9jb25zZXF1ZW50CgkvLyBjb250cmFjdHMvdmFsaWRhdG9yUmVnaXN0cnkuYWxnby50czo2OTcKCS8vIHJldHVybiB0aGlzLnZhbGlkYXRvckxpc3QodmFsaWRhdG9ySWQpLnZhbHVlLnRva2VuUGF5b3V0UmF0aW87CglpbnQgNjY2IC8vIGhlYWRPZmZzZXQKCWludCAyMDAKCWJ5dGUgMHg3NiAvLyAidiIKCWZyYW1lX2RpZyAtMSAvLyB2YWxpZGF0b3JJZDogVmFsaWRhdG9ySWRUeXBlCglpdG9iCgljb25jYXQKCWNvdmVyIDIKCWJveF9leHRyYWN0CgoJLy8gc2V0IHRoZSBzdWJyb3V0aW5lIHJldHVybiB2YWx1ZQoJZnJhbWVfYnVyeSAwCgoJLy8gcG9wIGFsbCBsb2NhbCB2YXJpYWJsZXMgZnJvbSB0aGUgc3RhY2sKCXBvcG4gNAoJcmV0c3ViCgoqaWYxNF9lbmQ6CgoqaWYxMl9lbmQ6CgkvLyBjb250cmFjdHMvdmFsaWRhdG9yUmVnaXN0cnkuYWxnby50czo3MDAKCS8vIHRoaXMudmFsaWRhdG9yTGlzdCh2YWxpZGF0b3JJZCkudmFsdWUudG9rZW5QYXlvdXRSYXRpby51cGRhdGVkRm9yUGF5b3V0ID0gY3VyVGltZQoJaW50IDg1OAoJZnJhbWVfZGlnIDEgLy8gY3VyVGltZTogdWludDY0CglpdG9iCglieXRlIDB4NzYgLy8gInYiCglmcmFtZV9kaWcgLTEgLy8gdmFsaWRhdG9ySWQ6IFZhbGlkYXRvcklkVHlwZQoJaXRvYgoJY29uY2F0Cgljb3ZlciAyCglib3hfcmVwbGFjZQoKCS8vIGNvbnRyYWN0cy92YWxpZGF0b3JSZWdpc3RyeS5hbGdvLnRzOjcwMgoJLy8gY3VyTnVtUG9vbHMgPSB0aGlzLnZhbGlkYXRvckxpc3QodmFsaWRhdG9ySWQpLnZhbHVlLnN0YXRlLm51bVBvb2xzIGFzIHVpbnQ2NAoJaW50IDIwOAoJaW50IDIKCWJ5dGUgMHg3NiAvLyAidiIKCWZyYW1lX2RpZyAtMSAvLyB2YWxpZGF0b3JJZDogVmFsaWRhdG9ySWRUeXBlCglpdG9iCgljb25jYXQKCWNvdmVyIDIKCWJveF9leHRyYWN0CglidG9pCglmcmFtZV9idXJ5IDUgLy8gY3VyTnVtUG9vbHM6IHVpbnQ2NAoKCS8vIGNvbnRyYWN0cy92YWxpZGF0b3JSZWdpc3RyeS5hbGdvLnRzOjcwMwoJLy8gdG90YWxTdGFrZUZvclZhbGlkYXRvciA9IHRoaXMudmFsaWRhdG9yTGlzdCh2YWxpZGF0b3JJZCkudmFsdWUuc3RhdGUudG90YWxBbGdvU3Rha2VkCglpbnQgMjE4CglpbnQgOAoJYnl0ZSAweDc2IC8vICJ2IgoJZnJhbWVfZGlnIC0xIC8vIHZhbGlkYXRvcklkOiBWYWxpZGF0b3JJZFR5cGUKCWl0b2IKCWNvbmNhdAoJY292ZXIgMgoJYm94X2V4dHJhY3QKCWJ0b2kKCWZyYW1lX2J1cnkgNiAvLyB0b3RhbFN0YWtlRm9yVmFsaWRhdG9yOiB1aW50NjQKCgkvLyBjb250cmFjdHMvdmFsaWRhdG9yUmVnaXN0cnkuYWxnby50czo3MDQKCS8vIGZvciAobGV0IGkgPSAwOyBpIDwgY3VyTnVtUG9vbHM7IGkgKz0gMSkKCWludCAwCglmcmFtZV9idXJ5IDcgLy8gaTogdWludDY0CgoqZm9yXzI6CgkvLyBjb250cmFjdHMvdmFsaWRhdG9yUmVnaXN0cnkuYWxnby50czo3MDQKCS8vIGkgPCBjdXJOdW1Qb29scwoJZnJhbWVfZGlnIDcgLy8gaTogdWludDY0CglmcmFtZV9kaWcgNSAvLyBjdXJOdW1Qb29sczogdWludDY0Cgk8CglieiAqZm9yXzJfZW5kCgoJLy8gY29udHJhY3RzL3ZhbGlkYXRvclJlZ2lzdHJ5LmFsZ28udHM6NzA5CgkvLyBvdXJQb29sUGN0T2ZXaG9sZSA9IHdpZGVSYXRpbygKCS8vICAgICAgICAgICAgICAgICBbdGhpcy52YWxpZGF0b3JMaXN0KHZhbGlkYXRvcklkKS52YWx1ZS5wb29sc1tpXS50b3RhbEFsZ29TdGFrZWQsIDFfMDAwXzAwMF0sCgkvLyAgICAgICAgICAgICAgICAgW3RvdGFsU3Rha2VGb3JWYWxpZGF0b3JdCgkvLyAgICAgICAgICAgICApCglpbnQgMjM0IC8vIGhlYWRPZmZzZXQKCWZyYW1lX2RpZyA3IC8vIGk6IHVpbnQ2NAoJaW50IDE4CgkqIC8vIGFjYyAqIHR5cGVMZW5ndGgKCSsKCWludCAxMCAvLyBoZWFkT2Zmc2V0CgkrCglpbnQgOAoJYnl0ZSAweDc2IC8vICJ2IgoJZnJhbWVfZGlnIC0xIC8vIHZhbGlkYXRvcklkOiBWYWxpZGF0b3JJZFR5cGUKCWl0b2IKCWNvbmNhdAoJY292ZXIgMgoJYm94X2V4dHJhY3QKCWJ0b2kKCWludCAxXzAwMF8wMDAKCW11bHcKCWludCAwCglmcmFtZV9kaWcgNiAvLyB0b3RhbFN0YWtlRm9yVmFsaWRhdG9yOiB1aW50NjQKCWRpdm1vZHcKCXBvcAoJcG9wCglzd2FwCgkhCglhc3NlcnQKCWZyYW1lX2J1cnkgOCAvLyBvdXJQb29sUGN0T2ZXaG9sZTogdWludDY0CgoJLy8gY29udHJhY3RzL3ZhbGlkYXRvclJlZ2lzdHJ5LmFsZ28udHM6NzEzCgkvLyB0aGlzLnZhbGlkYXRvckxpc3QodmFsaWRhdG9ySWQpLnZhbHVlLnRva2VuUGF5b3V0UmF0aW8ucG9vbFBjdE9mV2hvbGVbaV0gPSBvdXJQb29sUGN0T2ZXaG9sZQoJaW50IDY2NgoJZnJhbWVfZGlnIDcgLy8gaTogdWludDY0CglpbnQgOAoJKiAvLyBhY2MgKiB0eXBlTGVuZ3RoCgkrCglmcmFtZV9kaWcgOCAvLyBvdXJQb29sUGN0T2ZXaG9sZTogdWludDY0CglpdG9iCglieXRlIDB4NzYgLy8gInYiCglmcmFtZV9kaWcgLTEgLy8gdmFsaWRhdG9ySWQ6IFZhbGlkYXRvcklkVHlwZQoJaXRvYgoJY29uY2F0Cgljb3ZlciAyCglib3hfcmVwbGFjZQoKKmZvcl8yX2NvbnRpbnVlOgoJLy8gY29udHJhY3RzL3ZhbGlkYXRvclJlZ2lzdHJ5LmFsZ28udHM6NzA0CgkvLyBpICs9IDEKCWZyYW1lX2RpZyA3IC8vIGk6IHVpbnQ2NAoJaW50IDEKCSsKCWZyYW1lX2J1cnkgNyAvLyBpOiB1aW50NjQKCWIgKmZvcl8yCgoqZm9yXzJfZW5kOgoJLy8gY29udHJhY3RzL3ZhbGlkYXRvclJlZ2lzdHJ5LmFsZ28udHM6NzE1CgkvLyByZXR1cm4gdGhpcy52YWxpZGF0b3JMaXN0KHZhbGlkYXRvcklkKS52YWx1ZS50b2tlblBheW91dFJhdGlvOwoJaW50IDY2NiAvLyBoZWFkT2Zmc2V0CglpbnQgMjAwCglieXRlIDB4NzYgLy8gInYiCglmcmFtZV9kaWcgLTEgLy8gdmFsaWRhdG9ySWQ6IFZhbGlkYXRvcklkVHlwZQoJaXRvYgoJY29uY2F0Cgljb3ZlciAyCglib3hfZXh0cmFjdAoKCS8vIHNldCB0aGUgc3Vicm91dGluZSByZXR1cm4gdmFsdWUKCWZyYW1lX2J1cnkgMAoKCS8vIHBvcCBhbGwgbG9jYWwgdmFyaWFibGVzIGZyb20gdGhlIHN0YWNrCglwb3BuIDgKCXJldHN1YgoKLy8gc3Rha2VVcGRhdGVkVmlhUmV3YXJkcygodWludDY0LHVpbnQ2NCx1aW50NjQpLHVpbnQ2NCx1aW50NjQpdm9pZAoqYWJpX3JvdXRlX3N0YWtlVXBkYXRlZFZpYVJld2FyZHM6CgkvLyByZXdhcmRUb2tlbkFtb3VudFJlc2VydmVkOiB1aW50NjQKCXR4bmEgQXBwbGljYXRpb25BcmdzIDMKCWJ0b2kKCgkvLyBhbGdvVG9BZGQ6IHVpbnQ2NAoJdHhuYSBBcHBsaWNhdGlvbkFyZ3MgMgoJYnRvaQoKCS8vIHBvb2xLZXk6ICh1aW50NjQsdWludDY0LHVpbnQ2NCkKCXR4bmEgQXBwbGljYXRpb25BcmdzIDEKCWR1cAoJbGVuCglpbnQgMjQKCT09Cglhc3NlcnQKCgkvLyBleGVjdXRlIHN0YWtlVXBkYXRlZFZpYVJld2FyZHMoKHVpbnQ2NCx1aW50NjQsdWludDY0KSx1aW50NjQsdWludDY0KXZvaWQKCWNhbGxzdWIgc3Rha2VVcGRhdGVkVmlhUmV3YXJkcwoJaW50IDEKCXJldHVybgoKLy8gc3Rha2VVcGRhdGVkVmlhUmV3YXJkcyhwb29sS2V5OiBWYWxpZGF0b3JQb29sS2V5LCBhbGdvVG9BZGQ6IHVpbnQ2NCwgcmV3YXJkVG9rZW5BbW91bnRSZXNlcnZlZDogdWludDY0KTogdm9pZAovLwovLyBzdGFrZVVwZGF0ZWRWaWFSZXdhcmRzIGlzIGNhbGxlZCBieSBTdGFraW5nIHBvb2xzIHRvIGluZm9ybSB0aGUgdmFsaWRhdG9yICh1cykgdGhhdCBhIHBhcnRpY3VsYXIgYW1vdW50IG9mIHRvdGFsCi8vIHN0YWtlIGhhcyBiZWVuIGFkZGVkIHRvIHRoZSBzcGVjaWZpZWQgcG9vbC4gIFRoaXMgaXMgdXNlZCB0byB1cGRhdGUgdGhlIHN0YXRzIHdlIGhhdmUgaW4gb3VyIFBvb2xJbmZvIHN0b3JhZ2UuCi8vIFRoZSBjYWxsaW5nIEFwcCBpZCBpcyB2YWxpZGF0ZWQgYWdhaW5zdCBvdXIgcG9vbCBsaXN0IGFzIHdlbGwuCi8vIEBwYXJhbSB7VmFsaWRhdG9yUG9vbEtleX0gcG9vbEtleSAtIFZhbGlkYXRvclBvb2xLZXkgdHlwZQovLyBAcGFyYW0ge3VpbnQ2NH0gYWxnb1RvQWRkIC0gYW1vdW50IHRoaXMgdmFsaWRhdG9yJ3MgdG90YWwgc3Rha2UgaW5jcmVhc2VkIHZpYSByZXdhcmRzCi8vIEBwYXJhbSB7dWludDY0fSByZXdhcmRUb2tlbkFtb3VudFJlc2VydmVkIC0gYW1vdW50IHRoaXMgdmFsaWRhdG9yJ3MgdG90YWwgc3Rha2UgaW5jcmVhc2VkIHZpYSByZXdhcmRzICh0aGF0IHNob3VsZCBiZQovLyBzZWVuIGFzICdhY2NvdW50ZWQgZm9yL3BlbmRpbmcgc3BlbnQnKQpzdGFrZVVwZGF0ZWRWaWFSZXdhcmRzOgoJcHJvdG8gMyAwCgoJLy8gY29udHJhY3RzL3ZhbGlkYXRvclJlZ2lzdHJ5LmFsZ28udHM6NzI4CgkvLyB0aGlzLnZlcmlmeVBvb2xLZXlDYWxsZXIocG9vbEtleSkKCWZyYW1lX2RpZyAtMSAvLyBwb29sS2V5OiBWYWxpZGF0b3JQb29sS2V5CgljYWxsc3ViIHZlcmlmeVBvb2xLZXlDYWxsZXIKCgkvLyBjb250cmFjdHMvdmFsaWRhdG9yUmVnaXN0cnkuYWxnby50czo3MzEKCS8vIHRoaXMudmFsaWRhdG9yTGlzdChwb29sS2V5LmlkKS52YWx1ZS5wb29sc1twb29sS2V5LnBvb2xJZCAtIDFdLnRvdGFsQWxnb1N0YWtlZCArPSBhbGdvVG9BZGQKCWludCAyMzQgLy8gaGVhZE9mZnNldAoJZnJhbWVfZGlnIC0xIC8vIHBvb2xLZXk6IFZhbGlkYXRvclBvb2xLZXkKCWV4dHJhY3QgOCA4CglidG9pCglpbnQgMQoJLQoJaW50IDE4CgkqIC8vIGFjYyAqIHR5cGVMZW5ndGgKCSsKCWludCAxMCAvLyBoZWFkT2Zmc2V0CgkrCglpbnQgMjM0IC8vIGhlYWRPZmZzZXQKCWZyYW1lX2RpZyAtMSAvLyBwb29sS2V5OiBWYWxpZGF0b3JQb29sS2V5CglleHRyYWN0IDggOAoJYnRvaQoJaW50IDEKCS0KCWludCAxOAoJKiAvLyBhY2MgKiB0eXBlTGVuZ3RoCgkrCglpbnQgMTAgLy8gaGVhZE9mZnNldAoJKwoJaW50IDgKCWJ5dGUgMHg3NiAvLyAidiIKCWZyYW1lX2RpZyAtMSAvLyBwb29sS2V5OiBWYWxpZGF0b3JQb29sS2V5CglleHRyYWN0IDAgOAoJYnRvaQoJaXRvYgoJY29uY2F0Cgljb3ZlciAyCglib3hfZXh0cmFjdAoJYnRvaQoJZnJhbWVfZGlnIC0yIC8vIGFsZ29Ub0FkZDogdWludDY0CgkrCglpdG9iCglieXRlIDB4NzYgLy8gInYiCglmcmFtZV9kaWcgLTEgLy8gcG9vbEtleTogVmFsaWRhdG9yUG9vbEtleQoJZXh0cmFjdCAwIDgKCWJ0b2kKCWl0b2IKCWNvbmNhdAoJY292ZXIgMgoJYm94X3JlcGxhY2UKCgkvLyBjb250cmFjdHMvdmFsaWRhdG9yUmVnaXN0cnkuYWxnby50czo3MzIKCS8vIHRoaXMudmFsaWRhdG9yTGlzdChwb29sS2V5LmlkKS52YWx1ZS5zdGF0ZS50b3RhbEFsZ29TdGFrZWQgKz0gYWxnb1RvQWRkCglpbnQgMjE4CglkdXAKCWludCA4CglieXRlIDB4NzYgLy8gInYiCglmcmFtZV9kaWcgLTEgLy8gcG9vbEtleTogVmFsaWRhdG9yUG9vbEtleQoJZXh0cmFjdCAwIDgKCWJ0b2kKCWl0b2IKCWNvbmNhdAoJY292ZXIgMgoJYm94X2V4dHJhY3QKCWJ0b2kKCWZyYW1lX2RpZyAtMiAvLyBhbGdvVG9BZGQ6IHVpbnQ2NAoJKwoJaXRvYgoJYnl0ZSAweDc2IC8vICJ2IgoJZnJhbWVfZGlnIC0xIC8vIHBvb2xLZXk6IFZhbGlkYXRvclBvb2xLZXkKCWV4dHJhY3QgMCA4CglidG9pCglpdG9iCgljb25jYXQKCWNvdmVyIDIKCWJveF9yZXBsYWNlCgoJLy8gY29udHJhY3RzL3ZhbGlkYXRvclJlZ2lzdHJ5LmFsZ28udHM6NzMzCgkvLyB0aGlzLnZhbGlkYXRvckxpc3QocG9vbEtleS5pZCkudmFsdWUuc3RhdGUucmV3YXJkVG9rZW5IZWxkQmFjayArPSByZXdhcmRUb2tlbkFtb3VudFJlc2VydmVkCglpbnQgMjI2CglkdXAKCWludCA4CglieXRlIDB4NzYgLy8gInYiCglmcmFtZV9kaWcgLTEgLy8gcG9vbEtleTogVmFsaWRhdG9yUG9vbEtleQoJZXh0cmFjdCAwIDgKCWJ0b2kKCWl0b2IKCWNvbmNhdAoJY292ZXIgMgoJYm94X2V4dHJhY3QKCWJ0b2kKCWZyYW1lX2RpZyAtMyAvLyByZXdhcmRUb2tlbkFtb3VudFJlc2VydmVkOiB1aW50NjQKCSsKCWl0b2IKCWJ5dGUgMHg3NiAvLyAidiIKCWZyYW1lX2RpZyAtMSAvLyBwb29sS2V5OiBWYWxpZGF0b3JQb29sS2V5CglleHRyYWN0IDAgOAoJYnRvaQoJaXRvYgoJY29uY2F0Cgljb3ZlciAyCglib3hfcmVwbGFjZQoKCS8vIGNvbnRyYWN0cy92YWxpZGF0b3JSZWdpc3RyeS5hbGdvLnRzOjczNQoJLy8gdGhpcy50b3RhbEFsZ29TdGFrZWQudmFsdWUgKz0gYWxnb1RvQWRkCglieXRlIDB4NzM3NDYxNmI2NTY0IC8vICJzdGFrZWQiCglhcHBfZ2xvYmFsX2dldAoJZnJhbWVfZGlnIC0yIC8vIGFsZ29Ub0FkZDogdWludDY0CgkrCglieXRlIDB4NzM3NDYxNmI2NTY0IC8vICJzdGFrZWQiCglzd2FwCglhcHBfZ2xvYmFsX3B1dAoKCS8vIGNvbnRyYWN0cy92YWxpZGF0b3JSZWdpc3RyeS5hbGdvLnRzOjczOAoJLy8gdGhpcy5yZXZlcmlmeU5GRE93bmVyc2hpcChwb29sS2V5LmlkKQoJZnJhbWVfZGlnIC0xIC8vIHBvb2xLZXk6IFZhbGlkYXRvclBvb2xLZXkKCWV4dHJhY3QgMCA4CglidG9pCgljYWxsc3ViIHJldmVyaWZ5TkZET3duZXJzaGlwCglyZXRzdWIKCi8vIHN0YWtlUmVtb3ZlZCgodWludDY0LHVpbnQ2NCx1aW50NjQpLGFkZHJlc3MsdWludDY0LHVpbnQ2NCxib29sKXZvaWQKKmFiaV9yb3V0ZV9zdGFrZVJlbW92ZWQ6CgkvLyBzdGFrZXJSZW1vdmVkOiBib29sCgl0eG5hIEFwcGxpY2F0aW9uQXJncyA1CglkdXAKCWxlbgoJaW50IDEKCT09Cglhc3NlcnQKCWludCAwCglnZXRiaXQKCgkvLyByZXdhcmRSZW1vdmVkOiB1aW50NjQKCXR4bmEgQXBwbGljYXRpb25BcmdzIDQKCWJ0b2kKCgkvLyBhbW91bnRSZW1vdmVkOiB1aW50NjQKCXR4bmEgQXBwbGljYXRpb25BcmdzIDMKCWJ0b2kKCgkvLyBzdGFrZXI6IGFkZHJlc3MKCXR4bmEgQXBwbGljYXRpb25BcmdzIDIKCWR1cAoJbGVuCglpbnQgMzIKCT09Cglhc3NlcnQKCgkvLyBwb29sS2V5OiAodWludDY0LHVpbnQ2NCx1aW50NjQpCgl0eG5hIEFwcGxpY2F0aW9uQXJncyAxCglkdXAKCWxlbgoJaW50IDI0Cgk9PQoJYXNzZXJ0CgoJLy8gZXhlY3V0ZSBzdGFrZVJlbW92ZWQoKHVpbnQ2NCx1aW50NjQsdWludDY0KSxhZGRyZXNzLHVpbnQ2NCx1aW50NjQsYm9vbCl2b2lkCgljYWxsc3ViIHN0YWtlUmVtb3ZlZAoJaW50IDEKCXJldHVybgoKLy8gc3Rha2VSZW1vdmVkKHBvb2xLZXk6IFZhbGlkYXRvclBvb2xLZXksIHN0YWtlcjogQWRkcmVzcywgYW1vdW50UmVtb3ZlZDogdWludDY0LCByZXdhcmRSZW1vdmVkOiB1aW50NjQsIHN0YWtlclJlbW92ZWQ6IGJvb2xlYW4pOiB2b2lkCi8vCi8vIHN0YWtlUmVtb3ZlZCBpcyBjYWxsZWQgYnkgU3Rha2luZyBwb29scyB0byBpbmZvcm0gdGhlIHZhbGlkYXRvciAodXMpIHRoYXQgYSBwYXJ0aWN1bGFyIGFtb3VudCBvZiB0b3RhbCBzdGFrZSBoYXMgYmVlbiByZW1vdmVkCi8vIGZyb20gdGhlIHNwZWNpZmllZCBwb29sLiAgVGhpcyBpcyB1c2VkIHRvIHVwZGF0ZSB0aGUgc3RhdHMgd2UgaGF2ZSBpbiBvdXIgUG9vbEluZm8gc3RvcmFnZS4KLy8gSWYgYW55IGFtb3VudCBvZiByZXdhcmRSZW1vdmVkIGlzIHNwZWNpZmllZCwgdGhlbiB0aGF0IGFtb3VudCBvZiByZXdhcmQgaXMgc2VudCB0byB0aGUgdXNlCi8vIFRoZSBjYWxsaW5nIEFwcCBpZCBpcyB2YWxpZGF0ZWQgYWdhaW5zdCBvdXIgcG9vbCBsaXN0IGFzIHdlbGwuCi8vCi8vIEBwYXJhbSB7VmFsaWRhdG9yUG9vbEtleX0gcG9vbEtleSBjYWxsaW5nIHVzIGZyb20gd2hpY2ggc3Rha2Ugd2FzIHJlbW92ZWQKLy8gQHBhcmFtIHtBZGRyZXNzfSBzdGFrZXIKLy8gQHBhcmFtIHt1aW50NjR9IGFtb3VudFJlbW92ZWQgLSBhbGdvIGFtb3VudCByZW1vdmVkCi8vIEBwYXJhbSB7dWludDY0fSByZXdhcmRSZW1vdmVkIC0gaWYgYXBwbGljYWJsZSwgYW1vdW50IG9mIHRva2VuIHJld2FyZCByZW1vdmVkIChieSBwb29sIDEgY2FsbGVyKSBvciBUTyByZW1vdmUgYW5kIHBheSBvdXQgKHZpYSBwb29sIDEgZnJvbSBkaWZmZXJlbnQgcG9vbCBjYWxsZXIpCi8vIEBwYXJhbSB7Ym9vbGVhbn0gc3Rha2VyUmVtb3ZlZApzdGFrZVJlbW92ZWQ6Cglwcm90byA1IDAKCgkvLyBQdXNoIGVtcHR5IGJ5dGVzIGFmdGVyIHRoZSBmcmFtZSBwb2ludGVyIHRvIHJlc2VydmUgc3BhY2UgZm9yIGxvY2FsIHZhcmlhYmxlcwoJYnl0ZSAweAoJZHVwbiAzCgoJLy8gKmlmMTVfY29uZGl0aW9uCgkvLyBjb250cmFjdHMvdmFsaWRhdG9yUmVnaXN0cnkuYWxnby50czo3NjgKCS8vIGdsb2JhbHMub3Bjb2RlQnVkZ2V0IDwgMzAwCglnbG9iYWwgT3Bjb2RlQnVkZ2V0CglpbnQgMzAwCgk8CglieiAqaWYxNV9lbmQKCgkvLyAqaWYxNV9jb25zZXF1ZW50CgkvLyBjb250cmFjdHMvdmFsaWRhdG9yUmVnaXN0cnkuYWxnby50czo3NjkKCS8vIGluY3JlYXNlT3Bjb2RlQnVkZ2V0KCkKCWl0eG5fYmVnaW4KCWludCBhcHBsCglpdHhuX2ZpZWxkIFR5cGVFbnVtCglpbnQgMAoJaXR4bl9maWVsZCBGZWUKCWJ5dGUgYjY0IENvRUIgLy8gI3ByYWdtYSB2ZXJzaW9uIDEwOyBpbnQgMQoJZHVwCglpdHhuX2ZpZWxkIEFwcHJvdmFsUHJvZ3JhbQoJaXR4bl9maWVsZCBDbGVhclN0YXRlUHJvZ3JhbQoJaW50IERlbGV0ZUFwcGxpY2F0aW9uCglpdHhuX2ZpZWxkIE9uQ29tcGxldGlvbgoJaXR4bl9zdWJtaXQKCippZjE1X2VuZDoKCS8vIGNvbnRyYWN0cy92YWxpZGF0b3JSZWdpc3RyeS5hbGdvLnRzOjc3MQoJLy8gdGhpcy52ZXJpZnlQb29sS2V5Q2FsbGVyKHBvb2xLZXkpCglmcmFtZV9kaWcgLTEgLy8gcG9vbEtleTogVmFsaWRhdG9yUG9vbEtleQoJY2FsbHN1YiB2ZXJpZnlQb29sS2V5Q2FsbGVyCgoJLy8gY29udHJhY3RzL3ZhbGlkYXRvclJlZ2lzdHJ5LmFsZ28udHM6Nzc1CgkvLyBhc3NlcnQoYW1vdW50UmVtb3ZlZCA+IDAgfHwgcmV3YXJkUmVtb3ZlZCA+IDApCglmcmFtZV9kaWcgLTMgLy8gYW1vdW50UmVtb3ZlZDogdWludDY0CglpbnQgMAoJPgoJZHVwCglibnogKnNraXBfb3IyCglmcmFtZV9kaWcgLTQgLy8gcmV3YXJkUmVtb3ZlZDogdWludDY0CglpbnQgMAoJPgoJfHwKCipza2lwX29yMjoKCWFzc2VydAoKCS8vIGNvbnRyYWN0cy92YWxpZGF0b3JSZWdpc3RyeS5hbGdvLnRzOjc3OAoJLy8gdGhpcy52YWxpZGF0b3JMaXN0KHBvb2xLZXkuaWQpLnZhbHVlLnBvb2xzW3Bvb2xLZXkucG9vbElkIC0gMV0udG90YWxBbGdvU3Rha2VkIC09IGFtb3VudFJlbW92ZWQKCWludCAyMzQgLy8gaGVhZE9mZnNldAoJZnJhbWVfZGlnIC0xIC8vIHBvb2xLZXk6IFZhbGlkYXRvclBvb2xLZXkKCWV4dHJhY3QgOCA4CglidG9pCglpbnQgMQoJLQoJaW50IDE4CgkqIC8vIGFjYyAqIHR5cGVMZW5ndGgKCSsKCWludCAxMCAvLyBoZWFkT2Zmc2V0CgkrCglpbnQgMjM0IC8vIGhlYWRPZmZzZXQKCWZyYW1lX2RpZyAtMSAvLyBwb29sS2V5OiBWYWxpZGF0b3JQb29sS2V5CglleHRyYWN0IDggOAoJYnRvaQoJaW50IDEKCS0KCWludCAxOAoJKiAvLyBhY2MgKiB0eXBlTGVuZ3RoCgkrCglpbnQgMTAgLy8gaGVhZE9mZnNldAoJKwoJaW50IDgKCWJ5dGUgMHg3NiAvLyAidiIKCWZyYW1lX2RpZyAtMSAvLyBwb29sS2V5OiBWYWxpZGF0b3JQb29sS2V5CglleHRyYWN0IDAgOAoJYnRvaQoJaXRvYgoJY29uY2F0Cgljb3ZlciAyCglib3hfZXh0cmFjdAoJYnRvaQoJZnJhbWVfZGlnIC0zIC8vIGFtb3VudFJlbW92ZWQ6IHVpbnQ2NAoJLQoJaXRvYgoJYnl0ZSAweDc2IC8vICJ2IgoJZnJhbWVfZGlnIC0xIC8vIHBvb2xLZXk6IFZhbGlkYXRvclBvb2xLZXkKCWV4dHJhY3QgMCA4CglidG9pCglpdG9iCgljb25jYXQKCWNvdmVyIDIKCWJveF9yZXBsYWNlCgoJLy8gY29udHJhY3RzL3ZhbGlkYXRvclJlZ2lzdHJ5LmFsZ28udHM6Nzc5CgkvLyB0aGlzLnZhbGlkYXRvckxpc3QocG9vbEtleS5pZCkudmFsdWUuc3RhdGUudG90YWxBbGdvU3Rha2VkIC09IGFtb3VudFJlbW92ZWQKCWludCAyMTgKCWR1cAoJaW50IDgKCWJ5dGUgMHg3NiAvLyAidiIKCWZyYW1lX2RpZyAtMSAvLyBwb29sS2V5OiBWYWxpZGF0b3JQb29sS2V5CglleHRyYWN0IDAgOAoJYnRvaQoJaXRvYgoJY29uY2F0Cgljb3ZlciAyCglib3hfZXh0cmFjdAoJYnRvaQoJZnJhbWVfZGlnIC0zIC8vIGFtb3VudFJlbW92ZWQ6IHVpbnQ2NAoJLQoJaXRvYgoJYnl0ZSAweDc2IC8vICJ2IgoJZnJhbWVfZGlnIC0xIC8vIHBvb2xLZXk6IFZhbGlkYXRvclBvb2xLZXkKCWV4dHJhY3QgMCA4CglidG9pCglpdG9iCgljb25jYXQKCWNvdmVyIDIKCWJveF9yZXBsYWNlCgoJLy8gY29udHJhY3RzL3ZhbGlkYXRvclJlZ2lzdHJ5LmFsZ28udHM6NzgwCgkvLyB0aGlzLnRvdGFsQWxnb1N0YWtlZC52YWx1ZSAtPSBhbW91bnRSZW1vdmVkCglieXRlIDB4NzM3NDYxNmI2NTY0IC8vICJzdGFrZWQiCglhcHBfZ2xvYmFsX2dldAoJZnJhbWVfZGlnIC0zIC8vIGFtb3VudFJlbW92ZWQ6IHVpbnQ2NAoJLQoJYnl0ZSAweDczNzQ2MTZiNjU2NCAvLyAic3Rha2VkIgoJc3dhcAoJYXBwX2dsb2JhbF9wdXQKCgkvLyAqaWYxNl9jb25kaXRpb24KCS8vIGNvbnRyYWN0cy92YWxpZGF0b3JSZWdpc3RyeS5hbGdvLnRzOjc4MgoJLy8gcmV3YXJkUmVtb3ZlZCA+IDAKCWZyYW1lX2RpZyAtNCAvLyByZXdhcmRSZW1vdmVkOiB1aW50NjQKCWludCAwCgk+CglieiAqaWYxNl9lbHNlCgoJLy8gKmlmMTZfY29uc2VxdWVudAoJLy8gY29udHJhY3RzL3ZhbGlkYXRvclJlZ2lzdHJ5LmFsZ28udHM6NzgzCgkvLyByZXdhcmRUb2tlbklEID0gdGhpcy52YWxpZGF0b3JMaXN0KHBvb2xLZXkuaWQpLnZhbHVlLmNvbmZpZy5yZXdhcmRUb2tlbklkCglpbnQgMTIxCglpbnQgOAoJYnl0ZSAweDc2IC8vICJ2IgoJZnJhbWVfZGlnIC0xIC8vIHBvb2xLZXk6IFZhbGlkYXRvclBvb2xLZXkKCWV4dHJhY3QgMCA4CglidG9pCglpdG9iCgljb25jYXQKCWNvdmVyIDIKCWJveF9leHRyYWN0CglidG9pCglmcmFtZV9idXJ5IDAgLy8gcmV3YXJkVG9rZW5JRDogdWludDY0CgoJLy8gY29udHJhY3RzL3ZhbGlkYXRvclJlZ2lzdHJ5LmFsZ28udHM6Nzg0CgkvLyBhc3NlcnQocmV3YXJkVG9rZW5JRCAhPT0gMCwgInJld2FyZFJlbW92ZWQgY2FuJ3QgYmUgc2V0IGlmIHZhbGlkYXRvciBkb2Vzbid0IGhhdmUgcmV3YXJkIHRva2VuISIpCglmcmFtZV9kaWcgMCAvLyByZXdhcmRUb2tlbklEOiB1aW50NjQKCWludCAwCgkhPQoKCS8vIHJld2FyZFJlbW92ZWQgY2FuJ3QgYmUgc2V0IGlmIHZhbGlkYXRvciBkb2Vzbid0IGhhdmUgcmV3YXJkIHRva2VuIQoJYXNzZXJ0CgoJLy8gY29udHJhY3RzL3ZhbGlkYXRvclJlZ2lzdHJ5LmFsZ28udHM6Nzg1CgkvLyBhc3NlcnQoCgkvLyAgICAgICAgICAgICAgICAgdGhpcy52YWxpZGF0b3JMaXN0KHBvb2xLZXkuaWQpLnZhbHVlLnN0YXRlLnJld2FyZFRva2VuSGVsZEJhY2sgPj0gcmV3YXJkUmVtb3ZlZCwKCS8vICAgICAgICAgICAgICAgICAncmV3YXJkIGJlaW5nIHJlbW92ZWQgbXVzdCBiZSBjb3ZlcmVkIGJ5IGhvbGQgYmFjayBhbW91bnQnCgkvLyAgICAgICAgICAgICApCglpbnQgMjI2CglpbnQgOAoJYnl0ZSAweDc2IC8vICJ2IgoJZnJhbWVfZGlnIC0xIC8vIHBvb2xLZXk6IFZhbGlkYXRvclBvb2xLZXkKCWV4dHJhY3QgMCA4CglidG9pCglpdG9iCgljb25jYXQKCWNvdmVyIDIKCWJveF9leHRyYWN0CglidG9pCglmcmFtZV9kaWcgLTQgLy8gcmV3YXJkUmVtb3ZlZDogdWludDY0Cgk+PQoKCS8vIHJld2FyZCBiZWluZyByZW1vdmVkIG11c3QgYmUgY292ZXJlZCBieSBob2xkIGJhY2sgYW1vdW50Cglhc3NlcnQKCgkvLyBjb250cmFjdHMvdmFsaWRhdG9yUmVnaXN0cnkuYWxnby50czo3OTEKCS8vIHRoaXMudmFsaWRhdG9yTGlzdChwb29sS2V5LmlkKS52YWx1ZS5zdGF0ZS5yZXdhcmRUb2tlbkhlbGRCYWNrIC09IHJld2FyZFJlbW92ZWQKCWludCAyMjYKCWR1cAoJaW50IDgKCWJ5dGUgMHg3NiAvLyAidiIKCWZyYW1lX2RpZyAtMSAvLyBwb29sS2V5OiBWYWxpZGF0b3JQb29sS2V5CglleHRyYWN0IDAgOAoJYnRvaQoJaXRvYgoJY29uY2F0Cgljb3ZlciAyCglib3hfZXh0cmFjdAoJYnRvaQoJZnJhbWVfZGlnIC00IC8vIHJld2FyZFJlbW92ZWQ6IHVpbnQ2NAoJLQoJaXRvYgoJYnl0ZSAweDc2IC8vICJ2IgoJZnJhbWVfZGlnIC0xIC8vIHBvb2xLZXk6IFZhbGlkYXRvclBvb2xLZXkKCWV4dHJhY3QgMCA4CglidG9pCglpdG9iCgljb25jYXQKCWNvdmVyIDIKCWJveF9yZXBsYWNlCgoJLy8gKmlmMTdfY29uZGl0aW9uCgkvLyBjb250cmFjdHMvdmFsaWRhdG9yUmVnaXN0cnkuYWxnby50czo3OTYKCS8vIHBvb2xLZXkucG9vbElkICE9PSAxCglmcmFtZV9kaWcgLTEgLy8gcG9vbEtleTogVmFsaWRhdG9yUG9vbEtleQoJZXh0cmFjdCA4IDgKCWJ0b2kKCWludCAxCgkhPQoJYnogKmlmMTdfZW5kCgoJLy8gKmlmMTdfY29uc2VxdWVudAoJLy8gY29udHJhY3RzL3ZhbGlkYXRvclJlZ2lzdHJ5LmFsZ28udHM6Nzk3CgkvLyBzZW5kTWV0aG9kQ2FsbDx0eXBlb2YgU3Rha2luZ1Bvb2wucHJvdG90eXBlLnBheVRva2VuUmV3YXJkPih7CgkvLyAgICAgICAgICAgICAgICAgICAgIGFwcGxpY2F0aW9uSUQ6IEFwcElELmZyb21VaW50NjQodGhpcy52YWxpZGF0b3JMaXN0KHBvb2xLZXkuaWQpLnZhbHVlLnBvb2xzWzBdLnBvb2xBcHBJZCksCgkvLyAgICAgICAgICAgICAgICAgICAgIG1ldGhvZEFyZ3M6IFtzdGFrZXIsIHJld2FyZFRva2VuSUQsIHJld2FyZFJlbW92ZWRdLAoJLy8gICAgICAgICAgICAgICAgIH0pCglpdHhuX2JlZ2luCglpbnQgYXBwbAoJaXR4bl9maWVsZCBUeXBlRW51bQoJbWV0aG9kICJwYXlUb2tlblJld2FyZChhZGRyZXNzLHVpbnQ2NCx1aW50NjQpdm9pZCIKCWl0eG5fZmllbGQgQXBwbGljYXRpb25BcmdzCgoJLy8gY29udHJhY3RzL3ZhbGlkYXRvclJlZ2lzdHJ5LmFsZ28udHM6Nzk4CgkvLyBhcHBsaWNhdGlvbklEOiBBcHBJRC5mcm9tVWludDY0KHRoaXMudmFsaWRhdG9yTGlzdChwb29sS2V5LmlkKS52YWx1ZS5wb29sc1swXS5wb29sQXBwSWQpCglpbnQgMjM0CglpbnQgOAoJYnl0ZSAweDc2IC8vICJ2IgoJZnJhbWVfZGlnIC0xIC8vIHBvb2xLZXk6IFZhbGlkYXRvclBvb2xLZXkKCWV4dHJhY3QgMCA4CglidG9pCglpdG9iCgljb25jYXQKCWNvdmVyIDIKCWJveF9leHRyYWN0CglidG9pCglpdHhuX2ZpZWxkIEFwcGxpY2F0aW9uSUQKCgkvLyBjb250cmFjdHMvdmFsaWRhdG9yUmVnaXN0cnkuYWxnby50czo3OTkKCS8vIG1ldGhvZEFyZ3M6IFtzdGFrZXIsIHJld2FyZFRva2VuSUQsIHJld2FyZFJlbW92ZWRdCglmcmFtZV9kaWcgLTIgLy8gc3Rha2VyOiBBZGRyZXNzCglpdHhuX2ZpZWxkIEFwcGxpY2F0aW9uQXJncwoJZnJhbWVfZGlnIDAgLy8gcmV3YXJkVG9rZW5JRDogdWludDY0CglpdG9iCglpdHhuX2ZpZWxkIEFwcGxpY2F0aW9uQXJncwoJZnJhbWVfZGlnIC00IC8vIHJld2FyZFJlbW92ZWQ6IHVpbnQ2NAoJaXRvYgoJaXR4bl9maWVsZCBBcHBsaWNhdGlvbkFyZ3MKCgkvLyBGZWUgZmllbGQgbm90IHNldCwgZGVmYXVsdGluZyB0byAwCglpbnQgMAoJaXR4bl9maWVsZCBGZWUKCgkvLyBTdWJtaXQgaW5uZXIgdHJhbnNhY3Rpb24KCWl0eG5fc3VibWl0CgoqaWYxN19lbmQ6CgliICppZjE2X2VuZAoKKmlmMTZfZWxzZToKCippZjE2X2VuZDoKCS8vICppZjE4X2NvbmRpdGlvbgoJLy8gY29udHJhY3RzL3ZhbGlkYXRvclJlZ2lzdHJ5LmFsZ28udHM6ODI0CgkvLyBzdGFrZXJSZW1vdmVkCglmcmFtZV9kaWcgLTUgLy8gc3Rha2VyUmVtb3ZlZDogYm9vbGVhbgoJYnogKmlmMThfZW5kCgoJLy8gKmlmMThfY29uc2VxdWVudAoJLy8gY29udHJhY3RzL3ZhbGlkYXRvclJlZ2lzdHJ5LmFsZ28udHM6ODI2CgkvLyB0aGlzLnZhbGlkYXRvckxpc3QocG9vbEtleS5pZCkudmFsdWUucG9vbHNbcG9vbEtleS5wb29sSWQgLSAxXS50b3RhbFN0YWtlcnMgLT0gMQoJaW50IDIzNCAvLyBoZWFkT2Zmc2V0CglmcmFtZV9kaWcgLTEgLy8gcG9vbEtleTogVmFsaWRhdG9yUG9vbEtleQoJZXh0cmFjdCA4IDgKCWJ0b2kKCWludCAxCgktCglpbnQgMTgKCSogLy8gYWNjICogdHlwZUxlbmd0aAoJKwoJaW50IDggLy8gaGVhZE9mZnNldAoJKwoJaW50IDIzNCAvLyBoZWFkT2Zmc2V0CglmcmFtZV9kaWcgLTEgLy8gcG9vbEtleTogVmFsaWRhdG9yUG9vbEtleQoJZXh0cmFjdCA4IDgKCWJ0b2kKCWludCAxCgktCglpbnQgMTgKCSogLy8gYWNjICogdHlwZUxlbmd0aAoJKwoJaW50IDggLy8gaGVhZE9mZnNldAoJKwoJaW50IDIKCWJ5dGUgMHg3NiAvLyAidiIKCWZyYW1lX2RpZyAtMSAvLyBwb29sS2V5OiBWYWxpZGF0b3JQb29sS2V5CglleHRyYWN0IDAgOAoJYnRvaQoJaXRvYgoJY29uY2F0Cgljb3ZlciAyCglib3hfZXh0cmFjdAoJYnRvaQoJaW50IDEKCS0KCWl0b2IKCWV4dHJhY3QgNiAyCglieXRlIDB4NzYgLy8gInYiCglmcmFtZV9kaWcgLTEgLy8gcG9vbEtleTogVmFsaWRhdG9yUG9vbEtleQoJZXh0cmFjdCAwIDgKCWJ0b2kKCWl0b2IKCWNvbmNhdAoJY292ZXIgMgoJYm94X3JlcGxhY2UKCgkvLyBjb250cmFjdHMvdmFsaWRhdG9yUmVnaXN0cnkuYWxnby50czo4MjgKCS8vIHJlbW92ZVJldCA9IHRoaXMucmVtb3ZlRnJvbVN0YWtlclBvb2xTZXQoc3Rha2VyLCA8VmFsaWRhdG9yUG9vbEtleT57CgkvLyAgICAgICAgICAgICAgICAgaWQ6IHBvb2xLZXkuaWQsCgkvLyAgICAgICAgICAgICAgICAgcG9vbElkOiBwb29sS2V5LnBvb2xJZCwKCS8vICAgICAgICAgICAgICAgICBwb29sQXBwSWQ6IHBvb2xLZXkucG9vbEFwcElkLAoJLy8gICAgICAgICAgICAgfSkKCWZyYW1lX2RpZyAtMSAvLyBwb29sS2V5OiBWYWxpZGF0b3JQb29sS2V5CglleHRyYWN0IDAgOAoJYnRvaQoJaXRvYgoJZnJhbWVfZGlnIC0xIC8vIHBvb2xLZXk6IFZhbGlkYXRvclBvb2xLZXkKCWV4dHJhY3QgOCA4CglidG9pCglpdG9iCgljb25jYXQKCWZyYW1lX2RpZyAtMSAvLyBwb29sS2V5OiBWYWxpZGF0b3JQb29sS2V5CglleHRyYWN0IDE2IDgKCWJ0b2kKCWl0b2IKCWNvbmNhdAoJZnJhbWVfZGlnIC0yIC8vIHN0YWtlcjogQWRkcmVzcwoJY2FsbHN1YiByZW1vdmVGcm9tU3Rha2VyUG9vbFNldAoJZnJhbWVfYnVyeSAxIC8vIHJlbW92ZVJldDogKGJvb2wsYm9vbCkKCgkvLyBjb250cmFjdHMvdmFsaWRhdG9yUmVnaXN0cnkuYWxnby50czo4MzMKCS8vIHN0YWtlck91dE9mVGhpc1ZhbGlkYXRvciA9IHJlbW92ZVJldFswXQoJZnJhbWVfZGlnIDEgLy8gcmVtb3ZlUmV0OiAoYm9vbCxib29sKQoJc3RvcmUgMjU1IC8vIGZ1bGwgYXJyYXkKCWxvYWQgMjU1IC8vIGZ1bGwgYXJyYXkKCWludCAwCglnZXRiaXQKCWZyYW1lX2J1cnkgMiAvLyBzdGFrZXJPdXRPZlRoaXNWYWxpZGF0b3I6IGJvb2wKCgkvLyBjb250cmFjdHMvdmFsaWRhdG9yUmVnaXN0cnkuYWxnby50czo4MzQKCS8vIHN0YWtlck91dE9mUHJvdG9jb2wgPSByZW1vdmVSZXRbMV0KCWZyYW1lX2RpZyAxIC8vIHJlbW92ZVJldDogKGJvb2wsYm9vbCkKCXN0b3JlIDI1NSAvLyBmdWxsIGFycmF5Cglsb2FkIDI1NSAvLyBmdWxsIGFycmF5CglpbnQgMQoJZ2V0Yml0CglmcmFtZV9idXJ5IDMgLy8gc3Rha2VyT3V0T2ZQcm90b2NvbDogYm9vbAoKCS8vICppZjE5X2NvbmRpdGlvbgoJLy8gY29udHJhY3RzL3ZhbGlkYXRvclJlZ2lzdHJ5LmFsZ28udHM6ODM2CgkvLyBzdGFrZXJPdXRPZlRoaXNWYWxpZGF0b3IKCWZyYW1lX2RpZyAyIC8vIHN0YWtlck91dE9mVGhpc1ZhbGlkYXRvcjogYm9vbAoJYnogKmlmMTlfZW5kCgoJLy8gKmlmMTlfY29uc2VxdWVudAoJLy8gY29udHJhY3RzL3ZhbGlkYXRvclJlZ2lzdHJ5LmFsZ28udHM6ODM3CgkvLyB0aGlzLnZhbGlkYXRvckxpc3QocG9vbEtleS5pZCkudmFsdWUuc3RhdGUudG90YWxTdGFrZXJzIC09IDEKCWludCAyMTAKCWR1cAoJaW50IDgKCWJ5dGUgMHg3NiAvLyAidiIKCWZyYW1lX2RpZyAtMSAvLyBwb29sS2V5OiBWYWxpZGF0b3JQb29sS2V5CglleHRyYWN0IDAgOAoJYnRvaQoJaXRvYgoJY29uY2F0Cgljb3ZlciAyCglib3hfZXh0cmFjdAoJYnRvaQoJaW50IDEKCS0KCWl0b2IKCWJ5dGUgMHg3NiAvLyAidiIKCWZyYW1lX2RpZyAtMSAvLyBwb29sS2V5OiBWYWxpZGF0b3JQb29sS2V5CglleHRyYWN0IDAgOAoJYnRvaQoJaXRvYgoJY29uY2F0Cgljb3ZlciAyCglib3hfcmVwbGFjZQoKKmlmMTlfZW5kOgoJLy8gKmlmMjBfY29uZGl0aW9uCgkvLyBjb250cmFjdHMvdmFsaWRhdG9yUmVnaXN0cnkuYWxnby50czo4NDAKCS8vIHN0YWtlck91dE9mUHJvdG9jb2wKCWZyYW1lX2RpZyAzIC8vIHN0YWtlck91dE9mUHJvdG9jb2w6IGJvb2wKCWJ6ICppZjIwX2VuZAoKCS8vICppZjIwX2NvbnNlcXVlbnQKCS8vIGNvbnRyYWN0cy92YWxpZGF0b3JSZWdpc3RyeS5hbGdvLnRzOjg0MQoJLy8gdGhpcy5udW1TdGFrZXJzLnZhbHVlIC09IDEKCWJ5dGUgMHg2ZTc1NmQ1Mzc0NjE2YjY1NzI3MyAvLyAibnVtU3Rha2VycyIKCWFwcF9nbG9iYWxfZ2V0CglpbnQgMQoJLQoJYnl0ZSAweDZlNzU2ZDUzNzQ2MTZiNjU3MjczIC8vICJudW1TdGFrZXJzIgoJc3dhcAoJYXBwX2dsb2JhbF9wdXQKCippZjIwX2VuZDoKCippZjE4X2VuZDoKCXJldHN1YgoKLy8gZmluZFBvb2xGb3JTdGFrZXIodWludDY0LGFkZHJlc3MsdWludDY0KSgodWludDY0LHVpbnQ2NCx1aW50NjQpLGJvb2wsYm9vbCkKKmFiaV9yb3V0ZV9maW5kUG9vbEZvclN0YWtlcjoKCS8vIFRoZSBBQkkgcmV0dXJuIHByZWZpeAoJYnl0ZSAweDE1MWY3Yzc1CgoJLy8gYW1vdW50VG9TdGFrZTogdWludDY0Cgl0eG5hIEFwcGxpY2F0aW9uQXJncyAzCglidG9pCgoJLy8gc3Rha2VyOiBhZGRyZXNzCgl0eG5hIEFwcGxpY2F0aW9uQXJncyAyCglkdXAKCWxlbgoJaW50IDMyCgk9PQoJYXNzZXJ0CgoJLy8gdmFsaWRhdG9ySWQ6IHVpbnQ2NAoJdHhuYSBBcHBsaWNhdGlvbkFyZ3MgMQoJYnRvaQoKCS8vIGV4ZWN1dGUgZmluZFBvb2xGb3JTdGFrZXIodWludDY0LGFkZHJlc3MsdWludDY0KSgodWludDY0LHVpbnQ2NCx1aW50NjQpLGJvb2wsYm9vbCkKCWNhbGxzdWIgZmluZFBvb2xGb3JTdGFrZXIKCWNvbmNhdAoJbG9nCglpbnQgMQoJcmV0dXJuCgovLyBmaW5kUG9vbEZvclN0YWtlcih2YWxpZGF0b3JJZDogVmFsaWRhdG9ySWRUeXBlLCBzdGFrZXI6IEFkZHJlc3MsIGFtb3VudFRvU3Rha2U6IHVpbnQ2NCk6IFtWYWxpZGF0b3JQb29sS2V5LCBib29sZWFuLCBib29sZWFuXQovLwovLyBGaW5kcyB0aGUgcG9vbCBmb3IgYSBzdGFrZXIgYmFzZWQgb24gdGhlIHByb3ZpZGVkIHZhbGlkYXRvciBpZCwgc3Rha2VyIGFkZHJlc3MsIGFuZCBhbW91bnQgdG8gc3Rha2UuCi8vIEZpcnN0IGNoZWNrcyB0aGUgc3Rha2VycyAnYWxyZWFkeSBzdGFrZWQgbGlzdCcgZm9yIHRoZSB2YWxpZGF0b3IgcHJlZmVycmluZyB0aG9zZSAoYWRkaW5nIGlmIHBvc3NpYmxlKSB0aGVuIGFkZHMKLy8gdG8gbmV3IHBvb2wgaWYgbmVjZXNzYXJ5LgovLwovLyBAcGFyYW0ge1ZhbGlkYXRvcklkVHlwZX0gdmFsaWRhdG9ySWQgLSBUaGUgaWQgb2YgdGhlIHZhbGlkYXRvci4KLy8gQHBhcmFtIHtBZGRyZXNzfSBzdGFrZXIgLSBUaGUgYWRkcmVzcyBvZiB0aGUgc3Rha2VyLgovLyBAcGFyYW0ge3VpbnQ2NH0gYW1vdW50VG9TdGFrZSAtIFRoZSBhbW91bnQgdG8gc3Rha2UuCi8vIEByZXR1cm5zIHtWYWxpZGF0b3JQb29sS2V5LCBib29sZWFuLCBib29sZWFufSAtIFRoZSBwb29sIGZvciB0aGUgc3Rha2VyLCB0cnVlL2ZhbHNlIG9uIHdoZXRoZXIgdGhlIHN0YWtlciBpcyAnbmV3JwovLyB0byB0aGlzIFZBTElEQVRPUiwgYW5kIHRydWUvZmFsc2UgaWYgc3Rha2VyIGlzIG5ldyB0byB0aGUgcHJvdG9jb2wuCmZpbmRQb29sRm9yU3Rha2VyOgoJcHJvdG8gMyAxCgoJLy8gUHVzaCBlbXB0eSBieXRlcyBhZnRlciB0aGUgZnJhbWUgcG9pbnRlciB0byByZXNlcnZlIHNwYWNlIGZvciBsb2NhbCB2YXJpYWJsZXMKCWJ5dGUgMHgKCWR1cG4gNwoKCS8vIGNvbnRyYWN0cy92YWxpZGF0b3JSZWdpc3RyeS5hbGdvLnRzOjg2MgoJLy8gaXNOZXdTdGFrZXJUb1ZhbGlkYXRvciA9IHRydWUKCWludCAxCglmcmFtZV9idXJ5IDAgLy8gaXNOZXdTdGFrZXJUb1ZhbGlkYXRvcjogYm9vbAoKCS8vIGNvbnRyYWN0cy92YWxpZGF0b3JSZWdpc3RyeS5hbGdvLnRzOjg2MwoJLy8gaXNOZXdTdGFrZXJUb1Byb3RvY29sID0gdHJ1ZQoJaW50IDEKCWZyYW1lX2J1cnkgMSAvLyBpc05ld1N0YWtlclRvUHJvdG9jb2w6IGJvb2wKCgkvLyBjb250cmFjdHMvdmFsaWRhdG9yUmVnaXN0cnkuYWxnby50czo4NzEKCS8vIG1heFBlclBvb2wgPSB0aGlzLmdldEN1ck1heFN0YWtlUGVyUG9vbCh2YWxpZGF0b3JJZCkKCWZyYW1lX2RpZyAtMSAvLyB2YWxpZGF0b3JJZDogVmFsaWRhdG9ySWRUeXBlCgljYWxsc3ViIGdldEN1ck1heFN0YWtlUGVyUG9vbAoJZnJhbWVfYnVyeSAyIC8vIG1heFBlclBvb2w6IHVpbnQ2NAoKCS8vICppZjIxX2NvbmRpdGlvbgoJLy8gY29udHJhY3RzL3ZhbGlkYXRvclJlZ2lzdHJ5LmFsZ28udHM6ODc0CgkvLyB0aGlzLnN0YWtlclBvb2xTZXQoc3Rha2VyKS5leGlzdHMKCWJ5dGUgMHg3MzcwNzMgLy8gInNwcyIKCWZyYW1lX2RpZyAtMiAvLyBzdGFrZXI6IEFkZHJlc3MKCWNvbmNhdAoJYm94X2xlbgoJc3dhcAoJcG9wCglieiAqaWYyMV9lbmQKCgkvLyAqaWYyMV9jb25zZXF1ZW50CgkvLyBjb250cmFjdHMvdmFsaWRhdG9yUmVnaXN0cnkuYWxnby50czo4NzUKCS8vIHBvb2xTZXQgPSBjbG9uZSh0aGlzLnN0YWtlclBvb2xTZXQoc3Rha2VyKS52YWx1ZSkKCWJ5dGUgMHg3MzcwNzMgLy8gInNwcyIKCWZyYW1lX2RpZyAtMiAvLyBzdGFrZXI6IEFkZHJlc3MKCWNvbmNhdAoJYm94X2dldAoJYXNzZXJ0CglmcmFtZV9idXJ5IDMgLy8gcG9vbFNldDogKHVpbnQ2NCx1aW50NjQsdWludDY0KVs2XQoKCS8vIGNvbnRyYWN0cy92YWxpZGF0b3JSZWdpc3RyeS5hbGdvLnRzOjg3NgoJLy8gYXNzZXJ0KHZhbGlkYXRvcklkICE9PSAwKQoJZnJhbWVfZGlnIC0xIC8vIHZhbGlkYXRvcklkOiBWYWxpZGF0b3JJZFR5cGUKCWludCAwCgkhPQoJYXNzZXJ0CgoJLy8gY29udHJhY3RzL3ZhbGlkYXRvclJlZ2lzdHJ5LmFsZ28udHM6ODc3CgkvLyBmb3IgKGxldCBpID0gMDsgaSA8IHBvb2xTZXQubGVuZ3RoOyBpICs9IDEpCglpbnQgMAoJZnJhbWVfYnVyeSA0IC8vIGk6IHVpbnQ2NAoKKmZvcl8zOgoJLy8gY29udHJhY3RzL3ZhbGlkYXRvclJlZ2lzdHJ5LmFsZ28udHM6ODc3CgkvLyBpIDwgcG9vbFNldC5sZW5ndGgKCWZyYW1lX2RpZyA0IC8vIGk6IHVpbnQ2NAoJaW50IDYKCTwKCWJ6ICpmb3JfM19lbmQKCgkvLyAqaWYyMl9jb25kaXRpb24KCS8vIGNvbnRyYWN0cy92YWxpZGF0b3JSZWdpc3RyeS5hbGdvLnRzOjg3OAoJLy8gZ2xvYmFscy5vcGNvZGVCdWRnZXQgPCAzMDAKCWdsb2JhbCBPcGNvZGVCdWRnZXQKCWludCAzMDAKCTwKCWJ6ICppZjIyX2VuZAoKCS8vICppZjIyX2NvbnNlcXVlbnQKCS8vIGNvbnRyYWN0cy92YWxpZGF0b3JSZWdpc3RyeS5hbGdvLnRzOjg3OQoJLy8gaW5jcmVhc2VPcGNvZGVCdWRnZXQoKQoJaXR4bl9iZWdpbgoJaW50IGFwcGwKCWl0eG5fZmllbGQgVHlwZUVudW0KCWludCAwCglpdHhuX2ZpZWxkIEZlZQoJYnl0ZSBiNjQgQ29FQiAvLyAjcHJhZ21hIHZlcnNpb24gMTA7IGludCAxCglkdXAKCWl0eG5fZmllbGQgQXBwcm92YWxQcm9ncmFtCglpdHhuX2ZpZWxkIENsZWFyU3RhdGVQcm9ncmFtCglpbnQgRGVsZXRlQXBwbGljYXRpb24KCWl0eG5fZmllbGQgT25Db21wbGV0aW9uCglpdHhuX3N1Ym1pdAoKKmlmMjJfZW5kOgoJLy8gKmlmMjNfY29uZGl0aW9uCgkvLyBjb250cmFjdHMvdmFsaWRhdG9yUmVnaXN0cnkuYWxnby50czo4ODEKCS8vIHBvb2xTZXRbaV0uaWQgPT09IDAKCWZyYW1lX2RpZyAzIC8vIHBvb2xTZXQ6ICh1aW50NjQsdWludDY0LHVpbnQ2NClbNl0KCWZyYW1lX2RpZyA0IC8vIGk6IHVpbnQ2NAoJaW50IDI0CgkqIC8vIGFjYyAqIHR5cGVMZW5ndGgKCWludCAwCgkrCglpbnQgOAoJZXh0cmFjdDMKCWJ0b2kKCWludCAwCgk9PQoJYnogKmlmMjNfZW5kCgoJLy8gKmlmMjNfY29uc2VxdWVudAoJYiAqZm9yXzNfY29udGludWUKCippZjIzX2VuZDoKCS8vIGNvbnRyYWN0cy92YWxpZGF0b3JSZWdpc3RyeS5hbGdvLnRzOjg4NAoJLy8gaXNOZXdTdGFrZXJUb1Byb3RvY29sID0gZmFsc2UKCWludCAwCglmcmFtZV9idXJ5IDEgLy8gaXNOZXdTdGFrZXJUb1Byb3RvY29sOiBib29sCgoJLy8gKmlmMjRfY29uZGl0aW9uCgkvLyBjb250cmFjdHMvdmFsaWRhdG9yUmVnaXN0cnkuYWxnby50czo4ODUKCS8vIHBvb2xTZXRbaV0uaWQgPT09IHZhbGlkYXRvcklkCglmcmFtZV9kaWcgMyAvLyBwb29sU2V0OiAodWludDY0LHVpbnQ2NCx1aW50NjQpWzZdCglmcmFtZV9kaWcgNCAvLyBpOiB1aW50NjQKCWludCAyNAoJKiAvLyBhY2MgKiB0eXBlTGVuZ3RoCglpbnQgMAoJKwoJaW50IDgKCWV4dHJhY3QzCglidG9pCglmcmFtZV9kaWcgLTEgLy8gdmFsaWRhdG9ySWQ6IFZhbGlkYXRvcklkVHlwZQoJPT0KCWJ6ICppZjI0X2VuZAoKCS8vICppZjI0X2NvbnNlcXVlbnQKCS8vIGNvbnRyYWN0cy92YWxpZGF0b3JSZWdpc3RyeS5hbGdvLnRzOjg4NwoJLy8gaXNOZXdTdGFrZXJUb1ZhbGlkYXRvciA9IGZhbHNlCglpbnQgMAoJZnJhbWVfYnVyeSAwIC8vIGlzTmV3U3Rha2VyVG9WYWxpZGF0b3I6IGJvb2wKCgkvLyAqaWYyNV9jb25kaXRpb24KCS8vIGNvbnRyYWN0cy92YWxpZGF0b3JSZWdpc3RyeS5hbGdvLnRzOjg4OQoJLy8gdGhpcy52YWxpZGF0b3JMaXN0KHZhbGlkYXRvcklkKS52YWx1ZS5wb29sc1twb29sU2V0W2ldLnBvb2xJZCAtIDFdLnRvdGFsQWxnb1N0YWtlZCArCgkvLyAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYW1vdW50VG9TdGFrZSA8PQoJLy8gICAgICAgICAgICAgICAgICAgICAgICAgbWF4UGVyUG9vbAoJaW50IDIzNCAvLyBoZWFkT2Zmc2V0CglmcmFtZV9kaWcgMyAvLyBwb29sU2V0OiAodWludDY0LHVpbnQ2NCx1aW50NjQpWzZdCglmcmFtZV9kaWcgNCAvLyBpOiB1aW50NjQKCWludCAyNAoJKiAvLyBhY2MgKiB0eXBlTGVuZ3RoCglpbnQgOCAvLyBoZWFkT2Zmc2V0CgkrCglpbnQgOAoJZXh0cmFjdDMKCWJ0b2kKCWludCAxCgktCglpbnQgMTgKCSogLy8gYWNjICogdHlwZUxlbmd0aAoJKwoJaW50IDEwIC8vIGhlYWRPZmZzZXQKCSsKCWludCA4CglieXRlIDB4NzYgLy8gInYiCglmcmFtZV9kaWcgLTEgLy8gdmFsaWRhdG9ySWQ6IFZhbGlkYXRvcklkVHlwZQoJaXRvYgoJY29uY2F0Cgljb3ZlciAyCglib3hfZXh0cmFjdAoJYnRvaQoJZnJhbWVfZGlnIC0zIC8vIGFtb3VudFRvU3Rha2U6IHVpbnQ2NAoJKwoJZnJhbWVfZGlnIDIgLy8gbWF4UGVyUG9vbDogdWludDY0Cgk8PQoJYnogKmlmMjVfZW5kCgoJLy8gKmlmMjVfY29uc2VxdWVudAoJLy8gY29udHJhY3RzL3ZhbGlkYXRvclJlZ2lzdHJ5LmFsZ28udHM6ODkzCgkvLyByZXR1cm4gW3Bvb2xTZXRbaV0sIGlzTmV3U3Rha2VyVG9WYWxpZGF0b3IsIGlzTmV3U3Rha2VyVG9Qcm90b2NvbF07CglmcmFtZV9kaWcgMyAvLyBwb29sU2V0OiAodWludDY0LHVpbnQ2NCx1aW50NjQpWzZdCglmcmFtZV9kaWcgNCAvLyBpOiB1aW50NjQKCWludCAyNAoJKiAvLyBhY2MgKiB0eXBlTGVuZ3RoCglpbnQgMjQKCWV4dHJhY3QzCglieXRlIDB4MDAKCWludCAwCglmcmFtZV9kaWcgMCAvLyBpc05ld1N0YWtlclRvVmFsaWRhdG9yOiBib29sCglzZXRiaXQKCWludCAxCglmcmFtZV9kaWcgMSAvLyBpc05ld1N0YWtlclRvUHJvdG9jb2w6IGJvb2wKCXNldGJpdAoJY29uY2F0CgoJLy8gc2V0IHRoZSBzdWJyb3V0aW5lIHJldHVybiB2YWx1ZQoJZnJhbWVfYnVyeSAwCgoJLy8gcG9wIGFsbCBsb2NhbCB2YXJpYWJsZXMgZnJvbSB0aGUgc3RhY2sKCXBvcG4gNAoJcmV0c3ViCgoqaWYyNV9lbmQ6CgoqaWYyNF9lbmQ6CgoqZm9yXzNfY29udGludWU6CgkvLyBjb250cmFjdHMvdmFsaWRhdG9yUmVnaXN0cnkuYWxnby50czo4NzcKCS8vIGkgKz0gMQoJZnJhbWVfZGlnIDQgLy8gaTogdWludDY0CglpbnQgMQoJKwoJZnJhbWVfYnVyeSA0IC8vIGk6IHVpbnQ2NAoJYiAqZm9yXzMKCipmb3JfM19lbmQ6CgoqaWYyMV9lbmQ6CgkvLyBjb250cmFjdHMvdmFsaWRhdG9yUmVnaXN0cnkuYWxnby50czo5MDAKCS8vIGFzc2VydCgKCS8vICAgICAgICAgICAgIGFtb3VudFRvU3Rha2UgPj0gdGhpcy52YWxpZGF0b3JMaXN0KHZhbGlkYXRvcklkKS52YWx1ZS5jb25maWcubWluRW50cnlTdGFrZSwKCS8vICAgICAgICAgICAgICdtdXN0IHN0YWtlIGF0IGxlYXN0IHRoZSBtaW5pbXVtIGZvciB0aGlzIHBvb2wnCgkvLyAgICAgICAgICkKCWZyYW1lX2RpZyAtMyAvLyBhbW91bnRUb1N0YWtlOiB1aW50NjQKCWludCAxNzUKCWludCA4CglieXRlIDB4NzYgLy8gInYiCglmcmFtZV9kaWcgLTEgLy8gdmFsaWRhdG9ySWQ6IFZhbGlkYXRvcklkVHlwZQoJaXRvYgoJY29uY2F0Cgljb3ZlciAyCglib3hfZXh0cmFjdAoJYnRvaQoJPj0KCgkvLyBtdXN0IHN0YWtlIGF0IGxlYXN0IHRoZSBtaW5pbXVtIGZvciB0aGlzIHBvb2wKCWFzc2VydAoKCS8vIGNvbnRyYWN0cy92YWxpZGF0b3JSZWdpc3RyeS5hbGdvLnRzOjkwNgoJLy8gcG9vbHMgPSBjbG9uZSh0aGlzLnZhbGlkYXRvckxpc3QodmFsaWRhdG9ySWQpLnZhbHVlLnBvb2xzKQoJaW50IDIzNCAvLyBoZWFkT2Zmc2V0CglpbnQgNDMyCglieXRlIDB4NzYgLy8gInYiCglmcmFtZV9kaWcgLTEgLy8gdmFsaWRhdG9ySWQ6IFZhbGlkYXRvcklkVHlwZQoJaXRvYgoJY29uY2F0Cgljb3ZlciAyCglib3hfZXh0cmFjdAoJZnJhbWVfYnVyeSA1IC8vIHBvb2xzOiAodWludDY0LHVpbnQxNix1aW50NjQpWzI0XQoKCS8vIGNvbnRyYWN0cy92YWxpZGF0b3JSZWdpc3RyeS5hbGdvLnRzOjkwNwoJLy8gY3VyTnVtUG9vbHMgPSB0aGlzLnZhbGlkYXRvckxpc3QodmFsaWRhdG9ySWQpLnZhbHVlLnN0YXRlLm51bVBvb2xzIGFzIHVpbnQ2NAoJaW50IDIwOAoJaW50IDIKCWJ5dGUgMHg3NiAvLyAidiIKCWZyYW1lX2RpZyAtMSAvLyB2YWxpZGF0b3JJZDogVmFsaWRhdG9ySWRUeXBlCglpdG9iCgljb25jYXQKCWNvdmVyIDIKCWJveF9leHRyYWN0CglidG9pCglmcmFtZV9idXJ5IDYgLy8gY3VyTnVtUG9vbHM6IHVpbnQ2NAoKCS8vIGNvbnRyYWN0cy92YWxpZGF0b3JSZWdpc3RyeS5hbGdvLnRzOjkwOAoJLy8gZm9yIChsZXQgaSA9IDA7IGkgPCBjdXJOdW1Qb29sczsgaSArPSAxKQoJaW50IDAKCWZyYW1lX2J1cnkgNyAvLyBpOiB1aW50NjQKCipmb3JfNDoKCS8vIGNvbnRyYWN0cy92YWxpZGF0b3JSZWdpc3RyeS5hbGdvLnRzOjkwOAoJLy8gaSA8IGN1ck51bVBvb2xzCglmcmFtZV9kaWcgNyAvLyBpOiB1aW50NjQKCWZyYW1lX2RpZyA2IC8vIGN1ck51bVBvb2xzOiB1aW50NjQKCTwKCWJ6ICpmb3JfNF9lbmQKCgkvLyAqaWYyNl9jb25kaXRpb24KCS8vIGNvbnRyYWN0cy92YWxpZGF0b3JSZWdpc3RyeS5hbGdvLnRzOjkwOQoJLy8gcG9vbHNbaV0udG90YWxBbGdvU3Rha2VkICsgYW1vdW50VG9TdGFrZSA8PSBtYXhQZXJQb29sCglmcmFtZV9kaWcgNSAvLyBwb29sczogKHVpbnQ2NCx1aW50MTYsdWludDY0KVsyNF0KCWZyYW1lX2RpZyA3IC8vIGk6IHVpbnQ2NAoJaW50IDE4CgkqIC8vIGFjYyAqIHR5cGVMZW5ndGgKCWludCAxMCAvLyBoZWFkT2Zmc2V0CgkrCglpbnQgOAoJZXh0cmFjdDMKCWJ0b2kKCWZyYW1lX2RpZyAtMyAvLyBhbW91bnRUb1N0YWtlOiB1aW50NjQKCSsKCWZyYW1lX2RpZyAyIC8vIG1heFBlclBvb2w6IHVpbnQ2NAoJPD0KCWJ6ICppZjI2X2VuZAoKCS8vICppZjI2X2NvbnNlcXVlbnQKCS8vIGNvbnRyYWN0cy92YWxpZGF0b3JSZWdpc3RyeS5hbGdvLnRzOjkxMAoJLy8gcmV0dXJuIFsKCS8vICAgICAgICAgICAgICAgICAgICAgeyBpZDogdmFsaWRhdG9ySWQsIHBvb2xJZDogaSArIDEsIHBvb2xBcHBJZDogcG9vbHNbaV0ucG9vbEFwcElkIH0sCgkvLyAgICAgICAgICAgICAgICAgICAgIGlzTmV3U3Rha2VyVG9WYWxpZGF0b3IsCgkvLyAgICAgICAgICAgICAgICAgICAgIGlzTmV3U3Rha2VyVG9Qcm90b2NvbCwKCS8vICAgICAgICAgICAgICAgICBdOwoJZnJhbWVfZGlnIC0xIC8vIHZhbGlkYXRvcklkOiBWYWxpZGF0b3JJZFR5cGUKCWl0b2IKCWZyYW1lX2RpZyA3IC8vIGk6IHVpbnQ2NAoJaW50IDEKCSsKCWl0b2IKCWNvbmNhdAoJZnJhbWVfZGlnIDUgLy8gcG9vbHM6ICh1aW50NjQsdWludDE2LHVpbnQ2NClbMjRdCglmcmFtZV9kaWcgNyAvLyBpOiB1aW50NjQKCWludCAxOAoJKiAvLyBhY2MgKiB0eXBlTGVuZ3RoCglpbnQgMAoJKwoJaW50IDgKCWV4dHJhY3QzCglidG9pCglpdG9iCgljb25jYXQKCWJ5dGUgMHgwMAoJaW50IDAKCWZyYW1lX2RpZyAwIC8vIGlzTmV3U3Rha2VyVG9WYWxpZGF0b3I6IGJvb2wKCXNldGJpdAoJaW50IDEKCWZyYW1lX2RpZyAxIC8vIGlzTmV3U3Rha2VyVG9Qcm90b2NvbDogYm9vbAoJc2V0Yml0Cgljb25jYXQKCgkvLyBzZXQgdGhlIHN1YnJvdXRpbmUgcmV0dXJuIHZhbHVlCglmcmFtZV9idXJ5IDAKCgkvLyBwb3AgYWxsIGxvY2FsIHZhcmlhYmxlcyBmcm9tIHRoZSBzdGFjawoJcG9wbiA3CglyZXRzdWIKCippZjI2X2VuZDoKCipmb3JfNF9jb250aW51ZToKCS8vIGNvbnRyYWN0cy92YWxpZGF0b3JSZWdpc3RyeS5hbGdvLnRzOjkwOAoJLy8gaSArPSAxCglmcmFtZV9kaWcgNyAvLyBpOiB1aW50NjQKCWludCAxCgkrCglmcmFtZV9idXJ5IDcgLy8gaTogdWludDY0CgliICpmb3JfNAoKKmZvcl80X2VuZDoKCS8vIGNvbnRyYWN0cy92YWxpZGF0b3JSZWdpc3RyeS5hbGdvLnRzOjkxOAoJLy8gcmV0dXJuIFt7IGlkOiB2YWxpZGF0b3JJZCwgcG9vbElkOiAwLCBwb29sQXBwSWQ6IDAgfSwgaXNOZXdTdGFrZXJUb1ZhbGlkYXRvciwgaXNOZXdTdGFrZXJUb1Byb3RvY29sXTsKCWZyYW1lX2RpZyAtMSAvLyB2YWxpZGF0b3JJZDogVmFsaWRhdG9ySWRUeXBlCglpdG9iCglieXRlIDB4MDAwMDAwMDAwMDAwMDAwMAoJY29uY2F0CglieXRlIDB4MDAwMDAwMDAwMDAwMDAwMAoJY29uY2F0CglieXRlIDB4MDAKCWludCAwCglmcmFtZV9kaWcgMCAvLyBpc05ld1N0YWtlclRvVmFsaWRhdG9yOiBib29sCglzZXRiaXQKCWludCAxCglmcmFtZV9kaWcgMSAvLyBpc05ld1N0YWtlclRvUHJvdG9jb2w6IGJvb2wKCXNldGJpdAoJY29uY2F0CgoJLy8gc2V0IHRoZSBzdWJyb3V0aW5lIHJldHVybiB2YWx1ZQoJZnJhbWVfYnVyeSAwCgoJLy8gcG9wIGFsbCBsb2NhbCB2YXJpYWJsZXMgZnJvbSB0aGUgc3RhY2sKCXBvcG4gNwoJcmV0c3ViCgovLyBtb3ZlUG9vbFRvTm9kZSh1aW50NjQsdWludDY0LHVpbnQ2NCl2b2lkCiphYmlfcm91dGVfbW92ZVBvb2xUb05vZGU6CgkvLyBub2RlTnVtOiB1aW50NjQKCXR4bmEgQXBwbGljYXRpb25BcmdzIDMKCWJ0b2kKCgkvLyBwb29sQXBwSWQ6IHVpbnQ2NAoJdHhuYSBBcHBsaWNhdGlvbkFyZ3MgMgoJYnRvaQoKCS8vIHZhbGlkYXRvcklkOiB1aW50NjQKCXR4bmEgQXBwbGljYXRpb25BcmdzIDEKCWJ0b2kKCgkvLyBleGVjdXRlIG1vdmVQb29sVG9Ob2RlKHVpbnQ2NCx1aW50NjQsdWludDY0KXZvaWQKCWNhbGxzdWIgbW92ZVBvb2xUb05vZGUKCWludCAxCglyZXR1cm4KCi8vIG1vdmVQb29sVG9Ob2RlKHZhbGlkYXRvcklkOiBWYWxpZGF0b3JJZFR5cGUsIHBvb2xBcHBJZDogdWludDY0LCBub2RlTnVtOiB1aW50NjQpOiB2b2lkCi8vCi8vIEZpbmQgdGhlIHNwZWNpZmllZCBwb29sIChpbiBhbnkgbm9kZSBudW1iZXIpIGFuZCBtb3ZlIGl0IHRvIHRoZSBzcGVjaWZpZWQgbm9kZS4KLy8gVGhlIHBvb2wgYWNjb3VudCBpcyBmb3JjZWQgb2ZmbGluZSBpZiBtb3ZlZCBzbyBwcmlvciBub2RlIHdpbGwgc3RpbGwgcnVuIGZvciAzMjAgcm91bmRzIGJ1dAovLyBuZXcga2V5IGdvZXMgb25saW5lIG9uIG5ldyBub2RlIHNvb24gYWZ0ZXIgKDMyMCByb3VuZHMgYWZ0ZXIgaXQgZ29lcyBvbmxpbmUpCi8vIE5vLW9wIGlmIHN1Y2Nlc3MsIGFzc2VydHMgaWYgbm90IGZvdW5kIG9yIGNhbid0IG1vdmUgIChubyBzcGFjZSBpbiB0YXJnZXQpCi8vIFsgT05MWSBPV05FUiBPUiBNQU5BR0VSIENBTiBDSEFOR0UgXQovLyBPbmx5IGNhbGxhYmxlIGJ5IG93bmVyIG9yIG1hbmFnZXIKbW92ZVBvb2xUb05vZGU6Cglwcm90byAzIDAKCgkvLyBQdXNoIGVtcHR5IGJ5dGVzIGFmdGVyIHRoZSBmcmFtZSBwb2ludGVyIHRvIHJlc2VydmUgc3BhY2UgZm9yIGxvY2FsIHZhcmlhYmxlcwoJYnl0ZSAweAoJZHVwbiAyCgoJLy8gY29udHJhY3RzL3ZhbGlkYXRvclJlZ2lzdHJ5LmFsZ28udHM6OTMxCgkvLyBhc3NlcnQoCgkvLyAgICAgICAgICAgICB0aGlzLnR4bi5zZW5kZXIgPT09IHRoaXMudmFsaWRhdG9yTGlzdCh2YWxpZGF0b3JJZCkudmFsdWUuY29uZmlnLm93bmVyIHx8CgkvLyAgICAgICAgICAgICAgICAgdGhpcy50eG4uc2VuZGVyID09PSB0aGlzLnZhbGlkYXRvckxpc3QodmFsaWRhdG9ySWQpLnZhbHVlLmNvbmZpZy5tYW5hZ2VyCgkvLyAgICAgICAgICkKCXR4biBTZW5kZXIKCWludCA4CglpbnQgMzIKCWJ5dGUgMHg3NiAvLyAidiIKCWZyYW1lX2RpZyAtMSAvLyB2YWxpZGF0b3JJZDogVmFsaWRhdG9ySWRUeXBlCglpdG9iCgljb25jYXQKCWNvdmVyIDIKCWJveF9leHRyYWN0Cgk9PQoJZHVwCglibnogKnNraXBfb3IzCgl0eG4gU2VuZGVyCglpbnQgNDAKCWludCAzMgoJYnl0ZSAweDc2IC8vICJ2IgoJZnJhbWVfZGlnIC0xIC8vIHZhbGlkYXRvcklkOiBWYWxpZGF0b3JJZFR5cGUKCWl0b2IKCWNvbmNhdAoJY292ZXIgMgoJYm94X2V4dHJhY3QKCT09Cgl8fAoKKnNraXBfb3IzOgoJYXNzZXJ0CgoJLy8gY29udHJhY3RzL3ZhbGlkYXRvclJlZ2lzdHJ5LmFsZ28udHM6OTM2CgkvLyBub2RlUG9vbEFzc2lnbm1lbnRzID0gY2xvbmUodGhpcy52YWxpZGF0b3JMaXN0KHZhbGlkYXRvcklkKS52YWx1ZS5ub2RlUG9vbEFzc2lnbm1lbnRzKQoJaW50IDg2NiAvLyBoZWFkT2Zmc2V0CglpbnQgMTkyCglieXRlIDB4NzYgLy8gInYiCglmcmFtZV9kaWcgLTEgLy8gdmFsaWRhdG9ySWQ6IFZhbGlkYXRvcklkVHlwZQoJaXRvYgoJY29uY2F0Cgljb3ZlciAyCglib3hfZXh0cmFjdAoJZnJhbWVfYnVyeSAwIC8vIG5vZGVQb29sQXNzaWdubWVudHM6ICgodWludDY0WzNdKVs4XSkKCgkvLyBjb250cmFjdHMvdmFsaWRhdG9yUmVnaXN0cnkuYWxnby50czo5MzcKCS8vIGFzc2VydChub2RlTnVtID49IDEgJiYgbm9kZU51bSA8PSBNQVhfTk9ERVMpCglmcmFtZV9kaWcgLTMgLy8gbm9kZU51bTogdWludDY0CglpbnQgMQoJPj0KCWR1cAoJYnogKnNraXBfYW5kMQoJZnJhbWVfZGlnIC0zIC8vIG5vZGVOdW06IHVpbnQ2NAoJaW50IDgKCTw9CgkmJgoKKnNraXBfYW5kMToKCWFzc2VydAoKCS8vIGNvbnRyYWN0cy92YWxpZGF0b3JSZWdpc3RyeS5hbGdvLnRzOjkzOQoJLy8gZm9yIChsZXQgc3JjTm9kZUlkeCA9IDA7IHNyY05vZGVJZHggPCBNQVhfTk9ERVM7IHNyY05vZGVJZHggKz0gMSkKCWludCAwCglmcmFtZV9idXJ5IDEgLy8gc3JjTm9kZUlkeDogdWludDY0CgoqZm9yXzU6CgkvLyBjb250cmFjdHMvdmFsaWRhdG9yUmVnaXN0cnkuYWxnby50czo5MzkKCS8vIHNyY05vZGVJZHggPCBNQVhfTk9ERVMKCWZyYW1lX2RpZyAxIC8vIHNyY05vZGVJZHg6IHVpbnQ2NAoJaW50IDgKCTwKCWJ6ICpmb3JfNV9lbmQKCgkvLyBjb250cmFjdHMvdmFsaWRhdG9yUmVnaXN0cnkuYWxnby50czo5NDAKCS8vIGZvciAobGV0IGkgPSAwOyBpIDwgTUFYX1BPT0xTX1BFUl9OT0RFOyBpICs9IDEpCglpbnQgMAoJZnJhbWVfYnVyeSAyIC8vIGk6IHVpbnQ2NAoKKmZvcl82OgoJLy8gY29udHJhY3RzL3ZhbGlkYXRvclJlZ2lzdHJ5LmFsZ28udHM6OTQwCgkvLyBpIDwgTUFYX1BPT0xTX1BFUl9OT0RFCglmcmFtZV9kaWcgMiAvLyBpOiB1aW50NjQKCWludCAzCgk8CglieiAqZm9yXzZfZW5kCgoJLy8gKmlmMjdfY29uZGl0aW9uCgkvLyBjb250cmFjdHMvdmFsaWRhdG9yUmVnaXN0cnkuYWxnby50czo5NDEKCS8vIG5vZGVQb29sQXNzaWdubWVudHMubm9kZXNbc3JjTm9kZUlkeF0ucG9vbEFwcElkc1tpXSA9PT0gcG9vbEFwcElkCglmcmFtZV9kaWcgMCAvLyBub2RlUG9vbEFzc2lnbm1lbnRzOiAoKHVpbnQ2NFszXSlbOF0pCglpbnQgMAoJZnJhbWVfZGlnIDEgLy8gc3JjTm9kZUlkeDogdWludDY0CglpbnQgMjQKCSogLy8gYWNjICogdHlwZUxlbmd0aAoJKwoJaW50IDAKCSsKCWZyYW1lX2RpZyAyIC8vIGk6IHVpbnQ2NAoJaW50IDgKCSogLy8gYWNjICogdHlwZUxlbmd0aAoJKwoJaW50IDgKCWV4dHJhY3QzCglidG9pCglmcmFtZV9kaWcgLTIgLy8gcG9vbEFwcElkOiB1aW50NjQKCT09CglieiAqaWYyN19lbmQKCgkvLyAqaWYyN19jb25zZXF1ZW50CgkvLyBjb250cmFjdHMvdmFsaWRhdG9yUmVnaXN0cnkuYWxnby50czo5NDIKCS8vIGFzc2VydChub2RlTnVtIC0gMSAhPT0gc3JjTm9kZUlkeCwgImNhbid0IG1vdmUgdG8gc2FtZSBub2RlIikKCWZyYW1lX2RpZyAtMyAvLyBub2RlTnVtOiB1aW50NjQKCWludCAxCgktCglmcmFtZV9kaWcgMSAvLyBzcmNOb2RlSWR4OiB1aW50NjQKCSE9CgoJLy8gY2FuJ3QgbW92ZSB0byBzYW1lIG5vZGUKCWFzc2VydAoKCS8vIGNvbnRyYWN0cy92YWxpZGF0b3JSZWdpc3RyeS5hbGdvLnRzOjk0NAoJLy8gdGhpcy52YWxpZGF0b3JMaXN0KHZhbGlkYXRvcklkKS52YWx1ZS5ub2RlUG9vbEFzc2lnbm1lbnRzLm5vZGVzW3NyY05vZGVJZHhdLnBvb2xBcHBJZHNbaV0gPSAwCglpbnQgODY2CglmcmFtZV9kaWcgMSAvLyBzcmNOb2RlSWR4OiB1aW50NjQKCWludCAyNAoJKiAvLyBhY2MgKiB0eXBlTGVuZ3RoCgkrCglpbnQgMAoJKwoJZnJhbWVfZGlnIDIgLy8gaTogdWludDY0CglpbnQgOAoJKiAvLyBhY2MgKiB0eXBlTGVuZ3RoCgkrCglieXRlIDB4MDAwMDAwMDAwMDAwMDAwMAoJYnl0ZSAweDc2IC8vICJ2IgoJZnJhbWVfZGlnIC0xIC8vIHZhbGlkYXRvcklkOiBWYWxpZGF0b3JJZFR5cGUKCWl0b2IKCWNvbmNhdAoJY292ZXIgMgoJYm94X3JlcGxhY2UKCgkvLyBjb250cmFjdHMvdmFsaWRhdG9yUmVnaXN0cnkuYWxnby50czo5NDcKCS8vIHNlbmRNZXRob2RDYWxsPHR5cGVvZiBTdGFraW5nUG9vbC5wcm90b3R5cGUuZ29PZmZsaW5lPih7CgkvLyAgICAgICAgICAgICAgICAgICAgICAgICBhcHBsaWNhdGlvbklEOiBBcHBJRC5mcm9tVWludDY0KHBvb2xBcHBJZCksCgkvLyAgICAgICAgICAgICAgICAgICAgIH0pCglpdHhuX2JlZ2luCglpbnQgYXBwbAoJaXR4bl9maWVsZCBUeXBlRW51bQoJbWV0aG9kICJnb09mZmxpbmUoKXZvaWQiCglpdHhuX2ZpZWxkIEFwcGxpY2F0aW9uQXJncwoKCS8vIGNvbnRyYWN0cy92YWxpZGF0b3JSZWdpc3RyeS5hbGdvLnRzOjk0OAoJLy8gYXBwbGljYXRpb25JRDogQXBwSUQuZnJvbVVpbnQ2NChwb29sQXBwSWQpCglmcmFtZV9kaWcgLTIgLy8gcG9vbEFwcElkOiB1aW50NjQKCWl0eG5fZmllbGQgQXBwbGljYXRpb25JRAoKCS8vIEZlZSBmaWVsZCBub3Qgc2V0LCBkZWZhdWx0aW5nIHRvIDAKCWludCAwCglpdHhuX2ZpZWxkIEZlZQoKCS8vIFN1Ym1pdCBpbm5lciB0cmFuc2FjdGlvbgoJaXR4bl9zdWJtaXQKCgkvLyBjb250cmFjdHMvdmFsaWRhdG9yUmVnaXN0cnkuYWxnby50czo5NTIKCS8vIHRoaXMuYWRkUG9vbFRvTm9kZSh2YWxpZGF0b3JJZCwgcG9vbEFwcElkLCBub2RlTnVtKQoJZnJhbWVfZGlnIC0zIC8vIG5vZGVOdW06IHVpbnQ2NAoJZnJhbWVfZGlnIC0yIC8vIHBvb2xBcHBJZDogdWludDY0CglmcmFtZV9kaWcgLTEgLy8gdmFsaWRhdG9ySWQ6IFZhbGlkYXRvcklkVHlwZQoJY2FsbHN1YiBhZGRQb29sVG9Ob2RlCgoJLy8gY29udHJhY3RzL3ZhbGlkYXRvclJlZ2lzdHJ5LmFsZ28udHM6OTUzCgkvLyByZXR1cm47CglyZXRzdWIKCippZjI3X2VuZDoKCipmb3JfNl9jb250aW51ZToKCS8vIGNvbnRyYWN0cy92YWxpZGF0b3JSZWdpc3RyeS5hbGdvLnRzOjk0MAoJLy8gaSArPSAxCglmcmFtZV9kaWcgMiAvLyBpOiB1aW50NjQKCWludCAxCgkrCglmcmFtZV9idXJ5IDIgLy8gaTogdWludDY0CgliICpmb3JfNgoKKmZvcl82X2VuZDoKCipmb3JfNV9jb250aW51ZToKCS8vIGNvbnRyYWN0cy92YWxpZGF0b3JSZWdpc3RyeS5hbGdvLnRzOjkzOQoJLy8gc3JjTm9kZUlkeCArPSAxCglmcmFtZV9kaWcgMSAvLyBzcmNOb2RlSWR4OiB1aW50NjQKCWludCAxCgkrCglmcmFtZV9idXJ5IDEgLy8gc3JjTm9kZUlkeDogdWludDY0CgliICpmb3JfNQoKKmZvcl81X2VuZDoKCWVyciAvLyAiY291bGRuJ3QgZmluZCBwb29sIGFwcCBpZCBpbiBub2RlcyB0byBtb3ZlIgoKLy8gdmVyaWZ5UG9vbEtleUNhbGxlcihwb29sS2V5OiBWYWxpZGF0b3JQb29sS2V5KTogdm9pZAovLwovLyBMb2dzIHRoZSBhZGRpdGlvbiBvZiBhIG5ldyB2YWxpZGF0b3IgdG8gdGhlIHN5c3RlbSwgaXRzIGluaXRpYWwgb3duZXIgYW5kIG1hbmFnZXIKLy8KLy8KLy8gdmVyaWZ5UG9vbEtleUNhbGxlciB2ZXJpZmllcyB0aGUgcGFzc2VkIGluIGtleSAoZnJvbSBhIHN0YWtpbmcgcG9vbCBjYWxsaW5nIHVzIHRvIHVwZGF0ZSBtZXRyaWNzKSBpcyB2YWxpZAovLyBhbmQgbWF0Y2hlcyB0aGUgaW5mb3JtYXRpb24gd2UgaGF2ZSBpbiBvdXIgc3RhdGUuICAnRmFrZScgcG9vbHMgY291bGQgY2FsbCB1cyB0byB1cGRhdGUgb3VyIGRhdGEsIGJ1dCB0aGV5Ci8vIGNhbid0IGZha2UgdGhlIGlkcyBhbmQgbW9zdCBpbXBvcnRhbnRseSBhcHBsaWNhdGlvbiBpZCghKSBvZiB0aGUgY2FsbGVyIHRoYXQgaGFzIHRvIG1hdGNoLgp2ZXJpZnlQb29sS2V5Q2FsbGVyOgoJcHJvdG8gMSAwCgoJLy8gY29udHJhY3RzL3ZhbGlkYXRvclJlZ2lzdHJ5LmFsZ28udHM6MTA1MQoJLy8gYXNzZXJ0KHRoaXMudmFsaWRhdG9yTGlzdChwb29sS2V5LmlkKS5leGlzdHMpCglieXRlIDB4NzYgLy8gInYiCglmcmFtZV9kaWcgLTEgLy8gcG9vbEtleTogVmFsaWRhdG9yUG9vbEtleQoJZXh0cmFjdCAwIDgKCWJ0b2kKCWl0b2IKCWNvbmNhdAoJYm94X2xlbgoJc3dhcAoJcG9wCglhc3NlcnQKCgkvLyBjb250cmFjdHMvdmFsaWRhdG9yUmVnaXN0cnkuYWxnby50czoxMDUyCgkvLyBhc3NlcnQoKHBvb2xLZXkucG9vbElkIGFzIHVpbnQ2NCkgPCAyICoqIDE2KQoJZnJhbWVfZGlnIC0xIC8vIHBvb2xLZXk6IFZhbGlkYXRvclBvb2xLZXkKCWV4dHJhY3QgOCA4CglidG9pCglpbnQgMgoJaW50IDE2CglleHAKCTwKCWFzc2VydAoKCS8vIGNvbnRyYWN0cy92YWxpZGF0b3JSZWdpc3RyeS5hbGdvLnRzOjEwNTMKCS8vIGFzc2VydChwb29sS2V5LnBvb2xJZCA+IDAgJiYgKHBvb2xLZXkucG9vbElkIGFzIHVpbnQxNikgPD0gdGhpcy52YWxpZGF0b3JMaXN0KHBvb2xLZXkuaWQpLnZhbHVlLnN0YXRlLm51bVBvb2xzKQoJZnJhbWVfZGlnIC0xIC8vIHBvb2xLZXk6IFZhbGlkYXRvclBvb2xLZXkKCWV4dHJhY3QgOCA4CglidG9pCglpbnQgMAoJPgoJZHVwCglieiAqc2tpcF9hbmQyCglmcmFtZV9kaWcgLTEgLy8gcG9vbEtleTogVmFsaWRhdG9yUG9vbEtleQoJZXh0cmFjdCA4IDgKCWJ0b2kKCWludCAyMDgKCWludCAyCglieXRlIDB4NzYgLy8gInYiCglmcmFtZV9kaWcgLTEgLy8gcG9vbEtleTogVmFsaWRhdG9yUG9vbEtleQoJZXh0cmFjdCAwIDgKCWJ0b2kKCWl0b2IKCWNvbmNhdAoJY292ZXIgMgoJYm94X2V4dHJhY3QKCWJ0b2kKCTw9CgkmJgoKKnNraXBfYW5kMjoKCWFzc2VydAoKCS8vIGNvbnRyYWN0cy92YWxpZGF0b3JSZWdpc3RyeS5hbGdvLnRzOjEwNTYKCS8vIGFzc2VydCgKCS8vICAgICAgICAgICAgIHBvb2xLZXkucG9vbEFwcElkID09PSB0aGlzLnZhbGlkYXRvckxpc3QocG9vbEtleS5pZCkudmFsdWUucG9vbHNbcG9vbEtleS5wb29sSWQgLSAxXS5wb29sQXBwSWQsCgkvLyAgICAgICAgICAgICAiVGhlIHBhc3NlZCBpbiBhcHAgaWQgZG9lc24ndCBtYXRjaCB0aGUgcGFzc2VkIGluIGlkcyIKCS8vICAgICAgICAgKQoJZnJhbWVfZGlnIC0xIC8vIHBvb2xLZXk6IFZhbGlkYXRvclBvb2xLZXkKCWV4dHJhY3QgMTYgOAoJYnRvaQoJaW50IDIzNCAvLyBoZWFkT2Zmc2V0CglmcmFtZV9kaWcgLTEgLy8gcG9vbEtleTogVmFsaWRhdG9yUG9vbEtleQoJZXh0cmFjdCA4IDgKCWJ0b2kKCWludCAxCgktCglpbnQgMTgKCSogLy8gYWNjICogdHlwZUxlbmd0aAoJKwoJaW50IDAKCSsKCWludCA4CglieXRlIDB4NzYgLy8gInYiCglmcmFtZV9kaWcgLTEgLy8gcG9vbEtleTogVmFsaWRhdG9yUG9vbEtleQoJZXh0cmFjdCAwIDgKCWJ0b2kKCWl0b2IKCWNvbmNhdAoJY292ZXIgMgoJYm94X2V4dHJhY3QKCWJ0b2kKCT09CgoJLy8gVGhlIHBhc3NlZCBpbiBhcHAgaWQgZG9lc24ndCBtYXRjaCB0aGUgcGFzc2VkIGluIGlkcwoJYXNzZXJ0CgoJLy8gY29udHJhY3RzL3ZhbGlkYXRvclJlZ2lzdHJ5LmFsZ28udHM6MTA2MQoJLy8gYXNzZXJ0KHRoaXMudHhuLnNlbmRlciA9PT0gQXBwSUQuZnJvbVVpbnQ2NChwb29sS2V5LnBvb2xBcHBJZCkuYWRkcmVzcykKCXR4biBTZW5kZXIKCWZyYW1lX2RpZyAtMSAvLyBwb29sS2V5OiBWYWxpZGF0b3JQb29sS2V5CglleHRyYWN0IDE2IDgKCWJ0b2kKCWFwcF9wYXJhbXNfZ2V0IEFwcEFkZHJlc3MKCXBvcAoJPT0KCWFzc2VydAoKCS8vIGNvbnRyYWN0cy92YWxpZGF0b3JSZWdpc3RyeS5hbGdvLnRzOjEwNjMKCS8vIGFzc2VydChwb29sS2V5LmlkID09PSAoQXBwSUQuZnJvbVVpbnQ2NChwb29sS2V5LnBvb2xBcHBJZCkuZ2xvYmFsU3RhdGUoJ3ZhbGlkYXRvcklkJykgYXMgdWludDY0KSkKCWZyYW1lX2RpZyAtMSAvLyBwb29sS2V5OiBWYWxpZGF0b3JQb29sS2V5CglleHRyYWN0IDAgOAoJYnRvaQoJZnJhbWVfZGlnIC0xIC8vIHBvb2xLZXk6IFZhbGlkYXRvclBvb2xLZXkKCWV4dHJhY3QgMTYgOAoJYnRvaQoJYnl0ZSAweDc2NjE2YzY5NjQ2MTc0NmY3MjQ5NjQgLy8gInZhbGlkYXRvcklkIgoJYXBwX2dsb2JhbF9nZXRfZXgKCWFzc2VydAoJPT0KCWFzc2VydAoKCS8vIGNvbnRyYWN0cy92YWxpZGF0b3JSZWdpc3RyeS5hbGdvLnRzOjEwNjQKCS8vIGFzc2VydChwb29sS2V5LnBvb2xJZCA9PT0gKEFwcElELmZyb21VaW50NjQocG9vbEtleS5wb29sQXBwSWQpLmdsb2JhbFN0YXRlKCdwb29sSWQnKSBhcyB1aW50NjQpKQoJZnJhbWVfZGlnIC0xIC8vIHBvb2xLZXk6IFZhbGlkYXRvclBvb2xLZXkKCWV4dHJhY3QgOCA4CglidG9pCglmcmFtZV9kaWcgLTEgLy8gcG9vbEtleTogVmFsaWRhdG9yUG9vbEtleQoJZXh0cmFjdCAxNiA4CglidG9pCglieXRlIDB4NzA2ZjZmNmM0OTY0IC8vICJwb29sSWQiCglhcHBfZ2xvYmFsX2dldF9leAoJYXNzZXJ0Cgk9PQoJYXNzZXJ0CglyZXRzdWIKCi8vIHJldmVyaWZ5TkZET3duZXJzaGlwKHZhbGlkYXRvcklkOiBWYWxpZGF0b3JJZFR5cGUpOiB2b2lkCi8vCi8vIFRoaXMgbWV0aG9kIHZlcmlmaWVzIHRoZSBvd25lcnNoaXAgb2YgTkZEIChOYW1lZCBGdW5jdGlvbiBEYXRhKSBieSBhIHZhbGlkYXRvci4KLy8gSWYgdGhlIG93bmVyc2hpcCBpcyBubyBsb25nZXIgdmFsaWQsIGl0IHJlbW92ZXMgdGhlIE5GRCBmcm9tIHRoZSB2YWxpZGF0b3IncyBjb25maWd1cmF0aW9uLgovLwovLyBAcGFyYW0ge1ZhbGlkYXRvcklkVHlwZX0gdmFsaWRhdG9ySWQgLSBUaGUgaWQgb2YgdGhlIHZhbGlkYXRvciB3aG9zZSBkYXRhIHNob3VsZCBiZSByZS1ldmFsdWF0ZWQuCnJldmVyaWZ5TkZET3duZXJzaGlwOgoJcHJvdG8gMSAwCgoJLy8gUHVzaCBlbXB0eSBieXRlcyBhZnRlciB0aGUgZnJhbWUgcG9pbnRlciB0byByZXNlcnZlIHNwYWNlIGZvciBsb2NhbCB2YXJpYWJsZXMKCWJ5dGUgMHgKCWR1cAoKCS8vIGNvbnRyYWN0cy92YWxpZGF0b3JSZWdpc3RyeS5hbGdvLnRzOjEwNzQKCS8vIHZhbGlkYXRvckNvbmZpZyA9IHRoaXMudmFsaWRhdG9yTGlzdCh2YWxpZGF0b3JJZCkudmFsdWUuY29uZmlnCglieXRlIDB4NzYgLy8gInYiCglmcmFtZV9kaWcgLTEgLy8gdmFsaWRhdG9ySWQ6IFZhbGlkYXRvcklkVHlwZQoJaXRvYgoJY29uY2F0CglmcmFtZV9idXJ5IDAgLy8gc3RvcmFnZSBrZXkvL3ZhbGlkYXRvckNvbmZpZwoKCS8vICppZjI4X2NvbmRpdGlvbgoJLy8gY29udHJhY3RzL3ZhbGlkYXRvclJlZ2lzdHJ5LmFsZ28udHM6MTA3NQoJLy8gdmFsaWRhdG9yQ29uZmlnLm5mZEZvckluZm8gIT09IDAKCWludCA3MgoJaW50IDgKCWJ5dGUgMHg3NiAvLyAidiIKCWZyYW1lX2RpZyAtMSAvLyB2YWxpZGF0b3JJZDogVmFsaWRhdG9ySWRUeXBlCglpdG9iCgljb25jYXQKCWNvdmVyIDIKCWJveF9leHRyYWN0CglidG9pCglpbnQgMAoJIT0KCWJ6ICppZjI4X2VuZAoKCS8vICppZjI4X2NvbnNlcXVlbnQKCS8vIGNvbnRyYWN0cy92YWxpZGF0b3JSZWdpc3RyeS5hbGdvLnRzOjEwNzgKCS8vIG5mZE93bmVyID0gQXBwSUQuZnJvbVVpbnQ2NCh2YWxpZGF0b3JDb25maWcubmZkRm9ySW5mbykuZ2xvYmFsU3RhdGUoJ2kub3duZXIuYScpIGFzIEFkZHJlc3MKCWludCA3MgoJaW50IDgKCWJ5dGUgMHg3NiAvLyAidiIKCWZyYW1lX2RpZyAtMSAvLyB2YWxpZGF0b3JJZDogVmFsaWRhdG9ySWRUeXBlCglpdG9iCgljb25jYXQKCWNvdmVyIDIKCWJveF9leHRyYWN0CglidG9pCglieXRlIDB4NjkyZTZmNzc2ZTY1NzIyZTYxIC8vICJpLm93bmVyLmEiCglhcHBfZ2xvYmFsX2dldF9leAoJYXNzZXJ0CglmcmFtZV9idXJ5IDEgLy8gbmZkT3duZXI6IGFkZHJlc3MKCgkvLyAqaWYyOV9jb25kaXRpb24KCS8vIGNvbnRyYWN0cy92YWxpZGF0b3JSZWdpc3RyeS5hbGdvLnRzOjEwODAKCS8vIHZhbGlkYXRvckNvbmZpZy5vd25lciAhPT0gbmZkT3duZXIgJiYgdmFsaWRhdG9yQ29uZmlnLm1hbmFnZXIgIT09IG5mZE93bmVyCglpbnQgOAoJaW50IDMyCglieXRlIDB4NzYgLy8gInYiCglmcmFtZV9kaWcgLTEgLy8gdmFsaWRhdG9ySWQ6IFZhbGlkYXRvcklkVHlwZQoJaXRvYgoJY29uY2F0Cgljb3ZlciAyCglib3hfZXh0cmFjdAoJZnJhbWVfZGlnIDEgLy8gbmZkT3duZXI6IGFkZHJlc3MKCSE9CglkdXAKCWJ6ICpza2lwX2FuZDMKCWludCA0MAoJaW50IDMyCglieXRlIDB4NzYgLy8gInYiCglmcmFtZV9kaWcgLTEgLy8gdmFsaWRhdG9ySWQ6IFZhbGlkYXRvcklkVHlwZQoJaXRvYgoJY29uY2F0Cgljb3ZlciAyCglib3hfZXh0cmFjdAoJZnJhbWVfZGlnIDEgLy8gbmZkT3duZXI6IGFkZHJlc3MKCSE9CgkmJgoKKnNraXBfYW5kMzoKCWJ6ICppZjI5X2VuZAoKCS8vICppZjI5X2NvbnNlcXVlbnQKCS8vIGNvbnRyYWN0cy92YWxpZGF0b3JSZWdpc3RyeS5hbGdvLnRzOjEwODIKCS8vIHRoaXMudmFsaWRhdG9yTGlzdCh2YWxpZGF0b3JJZCkudmFsdWUuY29uZmlnLm5mZEZvckluZm8gPSAwCglpbnQgNzIKCWJ5dGUgMHgwMDAwMDAwMDAwMDAwMDAwCglieXRlIDB4NzYgLy8gInYiCglmcmFtZV9kaWcgLTEgLy8gdmFsaWRhdG9ySWQ6IFZhbGlkYXRvcklkVHlwZQoJaXRvYgoJY29uY2F0Cgljb3ZlciAyCglib3hfcmVwbGFjZQoKKmlmMjlfZW5kOgoKKmlmMjhfZW5kOgoJcmV0c3ViCgovLyB2YWxpZGF0ZUNvbmZpZyhjb25maWc6IFZhbGlkYXRvckNvbmZpZyk6IHZvaWQKdmFsaWRhdGVDb25maWc6Cglwcm90byAxIDAKCgkvLyBjb250cmFjdHMvdmFsaWRhdG9yUmVnaXN0cnkuYWxnby50czoxMDg5CgkvLyBhc3NlcnQoY29uZmlnLmVudHJ5R2F0aW5nVHlwZSA+PSBHQVRJTkdfVFlQRV9OT05FICYmIGNvbmZpZy5lbnRyeUdhdGluZ1R5cGUgPD0gR0FUSU5HX1RZUEVfQ09OU1RfTUFYKQoJZnJhbWVfZGlnIC0xIC8vIGNvbmZpZzogVmFsaWRhdG9yQ29uZmlnCglleHRyYWN0IDgwIDEKCWJ0b2kKCWludCAwCgk+PQoJZHVwCglieiAqc2tpcF9hbmQ0CglmcmFtZV9kaWcgLTEgLy8gY29uZmlnOiBWYWxpZGF0b3JDb25maWcKCWV4dHJhY3QgODAgMQoJYnRvaQoJaW50IDQKCTw9CgkmJgoKKnNraXBfYW5kNDoKCWFzc2VydAoKCS8vIGNvbnRyYWN0cy92YWxpZGF0b3JSZWdpc3RyeS5hbGdvLnRzOjEwOTAKCS8vIGFzc2VydChjb25maWcucGF5b3V0RXZlcnlYTWlucyA+PSBNSU5fUEFZT1VUX01JTlMgJiYgY29uZmlnLnBheW91dEV2ZXJ5WE1pbnMgPD0gTUFYX1BBWU9VVF9NSU5TKQoJZnJhbWVfZGlnIC0xIC8vIGNvbmZpZzogVmFsaWRhdG9yQ29uZmlnCglleHRyYWN0IDEzNyAyCglidG9pCglpbnQgMQoJPj0KCWR1cAoJYnogKnNraXBfYW5kNQoJZnJhbWVfZGlnIC0xIC8vIGNvbmZpZzogVmFsaWRhdG9yQ29uZmlnCglleHRyYWN0IDEzNyAyCglidG9pCglpbnQgMTAwODAKCTw9CgkmJgoKKnNraXBfYW5kNToKCWFzc2VydAoKCS8vIGNvbnRyYWN0cy92YWxpZGF0b3JSZWdpc3RyeS5hbGdvLnRzOjEwOTEKCS8vIGFzc2VydChjb25maWcucGVyY2VudFRvVmFsaWRhdG9yID49IE1JTl9QQ1RfVE9fVkFMSURBVE9SICYmIGNvbmZpZy5wZXJjZW50VG9WYWxpZGF0b3IgPD0gTUFYX1BDVF9UT19WQUxJREFUT1IpCglmcmFtZV9kaWcgLTEgLy8gY29uZmlnOiBWYWxpZGF0b3JDb25maWcKCWV4dHJhY3QgMTM5IDQKCWJ0b2kKCWludCAwCgk+PQoJZHVwCglieiAqc2tpcF9hbmQ2CglmcmFtZV9kaWcgLTEgLy8gY29uZmlnOiBWYWxpZGF0b3JDb25maWcKCWV4dHJhY3QgMTM5IDQKCWJ0b2kKCWludCAxMDAwMDAwCgk8PQoJJiYKCipza2lwX2FuZDY6Cglhc3NlcnQKCgkvLyAqaWYzMF9jb25kaXRpb24KCS8vIGNvbnRyYWN0cy92YWxpZGF0b3JSZWdpc3RyeS5hbGdvLnRzOjEwOTIKCS8vIGNvbmZpZy5wZXJjZW50VG9WYWxpZGF0b3IgIT09IDAKCWZyYW1lX2RpZyAtMSAvLyBjb25maWc6IFZhbGlkYXRvckNvbmZpZwoJZXh0cmFjdCAxMzkgNAoJYnRvaQoJaW50IDAKCSE9CglieiAqaWYzMF9lbmQKCgkvLyAqaWYzMF9jb25zZXF1ZW50CgkvLyBjb250cmFjdHMvdmFsaWRhdG9yUmVnaXN0cnkuYWxnby50czoxMDkzCgkvLyBhc3NlcnQoCgkvLyAgICAgICAgICAgICAgICAgY29uZmlnLnZhbGlkYXRvckNvbW1pc3Npb25BZGRyZXNzICE9PSBBZGRyZXNzLnplcm9BZGRyZXNzLAoJLy8gICAgICAgICAgICAgICAgICd2YWxpZGF0b3JDb21taXNzaW9uQWRkcmVzcyBtdXN0IGJlIHNldCBpZiBwZXJjZW50IHRvIHZhbGlkYXRvciBpcyBub3QgMCcKCS8vICAgICAgICAgICAgICkKCWZyYW1lX2RpZyAtMSAvLyBjb25maWc6IFZhbGlkYXRvckNvbmZpZwoJZXh0cmFjdCAxNDMgMzIKCWdsb2JhbCBaZXJvQWRkcmVzcwoJIT0KCgkvLyB2YWxpZGF0b3JDb21taXNzaW9uQWRkcmVzcyBtdXN0IGJlIHNldCBpZiBwZXJjZW50IHRvIHZhbGlkYXRvciBpcyBub3QgMAoJYXNzZXJ0CgoqaWYzMF9lbmQ6CgkvLyBjb250cmFjdHMvdmFsaWRhdG9yUmVnaXN0cnkuYWxnby50czoxMDk4CgkvLyBhc3NlcnQoY29uZmlnLm1pbkVudHJ5U3Rha2UgPj0gTUlOX0FMR09fU1RBS0VfUEVSX1BPT0wpCglmcmFtZV9kaWcgLTEgLy8gY29uZmlnOiBWYWxpZGF0b3JDb25maWcKCWV4dHJhY3QgMTc1IDgKCWJ0b2kKCWludCAxMDAwMDAwCgk+PQoJYXNzZXJ0CgoJLy8gY29udHJhY3RzL3ZhbGlkYXRvclJlZ2lzdHJ5LmFsZ28udHM6MTEwMAoJLy8gYXNzZXJ0KGNvbmZpZy5wb29sc1Blck5vZGUgPiAwICYmIGNvbmZpZy5wb29sc1Blck5vZGUgPD0gTUFYX1BPT0xTX1BFUl9OT0RFKQoJZnJhbWVfZGlnIC0xIC8vIGNvbmZpZzogVmFsaWRhdG9yQ29uZmlnCglleHRyYWN0IDE5MSAxCglidG9pCglpbnQgMAoJPgoJZHVwCglieiAqc2tpcF9hbmQ3CglmcmFtZV9kaWcgLTEgLy8gY29uZmlnOiBWYWxpZGF0b3JDb25maWcKCWV4dHJhY3QgMTkxIDEKCWJ0b2kKCWludCAzCgk8PQoJJiYKCipza2lwX2FuZDc6Cglhc3NlcnQKCXJldHN1YgoKLy8gY2FsbFBvb2xBZGRTdGFrZShzdGFrZWRBbW91bnRQYXltZW50OiBQYXlUeG4sIHBvb2xLZXk6IFZhbGlkYXRvclBvb2xLZXksIG1ickFtdFBhaWQ6IHVpbnQ2NCwgaXNOZXdTdGFrZXJUb1ZhbGlkYXRvcjogYm9vbGVhbiwgaXNOZXdTdGFrZXJUb1Byb3RvY29sOiBib29sZWFuKTogdm9pZAovLwovLyBBZGRzIGEgc3Rha2VycyBhbW91bnQgb2YgYWxnbyB0byBhIHZhbGlkYXRvciBwb29sLCB0cmFuc2ZlcnJpbmcgdGhlIGFsZ28gd2UgcmVjZWl2ZWQgZnJvbSB0aGVtIChhbHJlYWR5IHZlcmlmaWVkCi8vIGJ5IG91ciBjYWxsZXIpIHRvIHRoZSBzdGFraW5nIHBvb2wgYWNjb3VudCwgYW5kIHRoZW4gdGVsbGluZyBpdCBhYm91dCB0aGUgYW1vdW50IGJlaW5nIGFkZGVkIGZvciB0aGUgc3BlY2lmaWVkCi8vIHN0YWtlci4KLy8KLy8gQHBhcmFtIHtQYXlUeG59IHN0YWtlZEFtb3VudFBheW1lbnQgLSBwYXltZW50IGNvbWluZyBmcm9tIHN0YWtlciB0byBwbGFjZSBpbnRvIGEgcG9vbAovLyBAcGFyYW0ge1ZhbGlkYXRvclBvb2xLZXl9IHBvb2xLZXkgLSBUaGUga2V5IG9mIHRoZSB2YWxpZGF0b3IgcG9vbC4KLy8gQHBhcmFtIHt1aW50NjR9IG1ickFtdFBhaWQgLSBBbW91bnQgdGhlIHVzZXIgaXMgbGVhdmluZyBiZWhpbmQgaW4gdGhlIHZhbGlkYXRvciB0byBwYXkgZm9yIHRoZWlyIHN0YWtlciBNQlIgY29zdAovLyBAcGFyYW0ge2Jvb2xlYW59IGlzTmV3U3Rha2VyVG9WYWxpZGF0b3IgLSBpZiB0aGlzIGlzIGEgbmV3LCBmaXJzdC10aW1lIHN0YWtlciB0byB0aGUgdmFsaWRhdG9yCi8vIEBwYXJhbSB7Ym9vbGVhbn0gaXNOZXdTdGFrZXJUb1Byb3RvY29sIC0gaWYgdGhpcyBpcyBhIG5ldywgZmlyc3QtdGltZSBzdGFrZXIgdG8gdGhlIHByb3RvY29sCmNhbGxQb29sQWRkU3Rha2U6Cglwcm90byA1IDAKCgkvLyBQdXNoIGVtcHR5IGJ5dGVzIGFmdGVyIHRoZSBmcmFtZSBwb2ludGVyIHRvIHJlc2VydmUgc3BhY2UgZm9yIGxvY2FsIHZhcmlhYmxlcwoJYnl0ZSAweAoJZHVwbiAyCgoJLy8gKmlmMzFfY29uZGl0aW9uCgkvLyBjb250cmFjdHMvdmFsaWRhdG9yUmVnaXN0cnkuYWxnby50czoxMTIxCgkvLyBnbG9iYWxzLm9wY29kZUJ1ZGdldCA8IDUwMAoJZ2xvYmFsIE9wY29kZUJ1ZGdldAoJaW50IDUwMAoJPAoJYnogKmlmMzFfZW5kCgoJLy8gKmlmMzFfY29uc2VxdWVudAoJLy8gY29udHJhY3RzL3ZhbGlkYXRvclJlZ2lzdHJ5LmFsZ28udHM6MTEyMgoJLy8gaW5jcmVhc2VPcGNvZGVCdWRnZXQoKQoJaXR4bl9iZWdpbgoJaW50IGFwcGwKCWl0eG5fZmllbGQgVHlwZUVudW0KCWludCAwCglpdHhuX2ZpZWxkIEZlZQoJYnl0ZSBiNjQgQ29FQiAvLyAjcHJhZ21hIHZlcnNpb24gMTA7IGludCAxCglkdXAKCWl0eG5fZmllbGQgQXBwcm92YWxQcm9ncmFtCglpdHhuX2ZpZWxkIENsZWFyU3RhdGVQcm9ncmFtCglpbnQgRGVsZXRlQXBwbGljYXRpb24KCWl0eG5fZmllbGQgT25Db21wbGV0aW9uCglpdHhuX3N1Ym1pdAoKKmlmMzFfZW5kOgoJLy8gY29udHJhY3RzL3ZhbGlkYXRvclJlZ2lzdHJ5LmFsZ28udHM6MTEyNAoJLy8gcG9vbEFwcElkID0gdGhpcy52YWxpZGF0b3JMaXN0KHBvb2xLZXkuaWQpLnZhbHVlLnBvb2xzW3Bvb2xLZXkucG9vbElkIC0gMV0ucG9vbEFwcElkCglpbnQgMjM0IC8vIGhlYWRPZmZzZXQKCWZyYW1lX2RpZyAtMiAvLyBwb29sS2V5OiBWYWxpZGF0b3JQb29sS2V5CglleHRyYWN0IDggOAoJYnRvaQoJaW50IDEKCS0KCWludCAxOAoJKiAvLyBhY2MgKiB0eXBlTGVuZ3RoCgkrCglpbnQgMAoJKwoJaW50IDgKCWJ5dGUgMHg3NiAvLyAidiIKCWZyYW1lX2RpZyAtMiAvLyBwb29sS2V5OiBWYWxpZGF0b3JQb29sS2V5CglleHRyYWN0IDAgOAoJYnRvaQoJaXRvYgoJY29uY2F0Cgljb3ZlciAyCglib3hfZXh0cmFjdAoJYnRvaQoJZnJhbWVfYnVyeSAwIC8vIHBvb2xBcHBJZDogdWludDY0CgoJLy8gY29udHJhY3RzL3ZhbGlkYXRvclJlZ2lzdHJ5LmFsZ28udHM6MTEyOAoJLy8gc2VuZE1ldGhvZENhbGw8dHlwZW9mIFN0YWtpbmdQb29sLnByb3RvdHlwZS5hZGRTdGFrZT4oewoJLy8gICAgICAgICAgICAgYXBwbGljYXRpb25JRDogQXBwSUQuZnJvbVVpbnQ2NChwb29sQXBwSWQpLAoJLy8gICAgICAgICAgICAgbWV0aG9kQXJnczogWwoJLy8gICAgICAgICAgICAgICAgIC8vID09PT09PT0KCS8vICAgICAgICAgICAgICAgICAvLyBUSElTIElTIEEgU0VORCBvZiB0aGUgYW1vdW50IHJlY2VpdmVkIHJpZ2h0IGJhY2sgb3V0IGFuZCBpbnRvIHRoZSBzdGFraW5nIHBvb2wgY29udHJhY3QgYWNjb3VudC4KCS8vICAgICAgICAgICAgICAgICB7IGFtb3VudDogc3Rha2VkQW1vdW50UGF5bWVudC5hbW91bnQgLSBtYnJBbXRQYWlkLCByZWNlaXZlcjogQXBwSUQuZnJvbVVpbnQ2NChwb29sQXBwSWQpLmFkZHJlc3MgfSwKCS8vICAgICAgICAgICAgICAgICAvLyA9PT09PT09CgkvLyAgICAgICAgICAgICAgICAgc3Rha2VkQW1vdW50UGF5bWVudC5zZW5kZXIsCgkvLyAgICAgICAgICAgICBdLAoJLy8gICAgICAgICB9KQoJaXR4bl9iZWdpbgoJaW50IHBheQoJaXR4bl9maWVsZCBUeXBlRW51bQoKCS8vIGNvbnRyYWN0cy92YWxpZGF0b3JSZWdpc3RyeS5hbGdvLnRzOjExMzMKCS8vIGFtb3VudDogc3Rha2VkQW1vdW50UGF5bWVudC5hbW91bnQgLSBtYnJBbXRQYWlkCglmcmFtZV9kaWcgLTEgLy8gc3Rha2VkQW1vdW50UGF5bWVudDogUGF5VHhuCglndHhucyBBbW91bnQKCWZyYW1lX2RpZyAtMyAvLyBtYnJBbXRQYWlkOiB1aW50NjQKCS0KCWl0eG5fZmllbGQgQW1vdW50CgoJLy8gY29udHJhY3RzL3ZhbGlkYXRvclJlZ2lzdHJ5LmFsZ28udHM6MTEzMwoJLy8gcmVjZWl2ZXI6IEFwcElELmZyb21VaW50NjQocG9vbEFwcElkKS5hZGRyZXNzCglmcmFtZV9kaWcgMCAvLyBwb29sQXBwSWQ6IHVpbnQ2NAoJYXBwX3BhcmFtc19nZXQgQXBwQWRkcmVzcwoJcG9wCglpdHhuX2ZpZWxkIFJlY2VpdmVyCgoJLy8gRmVlIGZpZWxkIG5vdCBzZXQsIGRlZmF1bHRpbmcgdG8gMAoJaW50IDAKCWl0eG5fZmllbGQgRmVlCglpdHhuX25leHQKCWludCBhcHBsCglpdHhuX2ZpZWxkIFR5cGVFbnVtCgltZXRob2QgImFkZFN0YWtlKHBheSxhZGRyZXNzKXVpbnQ2NCIKCWl0eG5fZmllbGQgQXBwbGljYXRpb25BcmdzCgoJLy8gY29udHJhY3RzL3ZhbGlkYXRvclJlZ2lzdHJ5LmFsZ28udHM6MTEyOQoJLy8gYXBwbGljYXRpb25JRDogQXBwSUQuZnJvbVVpbnQ2NChwb29sQXBwSWQpCglmcmFtZV9kaWcgMCAvLyBwb29sQXBwSWQ6IHVpbnQ2NAoJaXR4bl9maWVsZCBBcHBsaWNhdGlvbklECgoJLy8gY29udHJhY3RzL3ZhbGlkYXRvclJlZ2lzdHJ5LmFsZ28udHM6MTEzMAoJLy8gbWV0aG9kQXJnczogWwoJLy8gICAgICAgICAgICAgICAgIC8vID09PT09PT0KCS8vICAgICAgICAgICAgICAgICAvLyBUSElTIElTIEEgU0VORCBvZiB0aGUgYW1vdW50IHJlY2VpdmVkIHJpZ2h0IGJhY2sgb3V0IGFuZCBpbnRvIHRoZSBzdGFraW5nIHBvb2wgY29udHJhY3QgYWNjb3VudC4KCS8vICAgICAgICAgICAgICAgICB7IGFtb3VudDogc3Rha2VkQW1vdW50UGF5bWVudC5hbW91bnQgLSBtYnJBbXRQYWlkLCByZWNlaXZlcjogQXBwSUQuZnJvbVVpbnQ2NChwb29sQXBwSWQpLmFkZHJlc3MgfSwKCS8vICAgICAgICAgICAgICAgICAvLyA9PT09PT09CgkvLyAgICAgICAgICAgICAgICAgc3Rha2VkQW1vdW50UGF5bWVudC5zZW5kZXIsCgkvLyAgICAgICAgICAgICBdCglmcmFtZV9kaWcgLTEgLy8gc3Rha2VkQW1vdW50UGF5bWVudDogUGF5VHhuCglndHhucyBTZW5kZXIKCWl0eG5fZmllbGQgQXBwbGljYXRpb25BcmdzCgoJLy8gRmVlIGZpZWxkIG5vdCBzZXQsIGRlZmF1bHRpbmcgdG8gMAoJaW50IDAKCWl0eG5fZmllbGQgRmVlCgoJLy8gU3VibWl0IGlubmVyIHRyYW5zYWN0aW9uCglpdHhuX3N1Ym1pdAoJaXR4biBOdW1Mb2dzCglpbnQgMQoJLQoJaXR4bmFzIExvZ3MKCWV4dHJhY3QgNCAwCglidG9pCgoJLy8gY29udHJhY3RzL3ZhbGlkYXRvclJlZ2lzdHJ5LmFsZ28udHM6MTE0MAoJLy8gcG9vbE51bVN0YWtlcnMgPSBBcHBJRC5mcm9tVWludDY0KHBvb2xBcHBJZCkuZ2xvYmFsU3RhdGUoJ251bVN0YWtlcnMnKSBhcyB1aW50NjQKCWZyYW1lX2RpZyAwIC8vIHBvb2xBcHBJZDogdWludDY0CglieXRlIDB4NmU3NTZkNTM3NDYxNmI2NTcyNzMgLy8gIm51bVN0YWtlcnMiCglhcHBfZ2xvYmFsX2dldF9leAoJYXNzZXJ0CglmcmFtZV9idXJ5IDEgLy8gcG9vbE51bVN0YWtlcnM6IHVpbnQ2NAoKCS8vIGNvbnRyYWN0cy92YWxpZGF0b3JSZWdpc3RyeS5hbGdvLnRzOjExNDEKCS8vIHBvb2xBbGdvU3Rha2VkID0gQXBwSUQuZnJvbVVpbnQ2NChwb29sQXBwSWQpLmdsb2JhbFN0YXRlKCdzdGFrZWQnKSBhcyB1aW50NjQKCWZyYW1lX2RpZyAwIC8vIHBvb2xBcHBJZDogdWludDY0CglieXRlIDB4NzM3NDYxNmI2NTY0IC8vICJzdGFrZWQiCglhcHBfZ2xvYmFsX2dldF9leAoJYXNzZXJ0CglmcmFtZV9idXJ5IDIgLy8gcG9vbEFsZ29TdGFrZWQ6IHVpbnQ2NAoKCS8vIGNvbnRyYWN0cy92YWxpZGF0b3JSZWdpc3RyeS5hbGdvLnRzOjExNDIKCS8vIHRoaXMudmFsaWRhdG9yTGlzdChwb29sS2V5LmlkKS52YWx1ZS5wb29sc1twb29sS2V5LnBvb2xJZCAtIDFdLnRvdGFsU3Rha2VycyA9IHBvb2xOdW1TdGFrZXJzIGFzIHVpbnQxNgoJaW50IDIzNCAvLyBoZWFkT2Zmc2V0CglmcmFtZV9kaWcgLTIgLy8gcG9vbEtleTogVmFsaWRhdG9yUG9vbEtleQoJZXh0cmFjdCA4IDgKCWJ0b2kKCWludCAxCgktCglpbnQgMTgKCSogLy8gYWNjICogdHlwZUxlbmd0aAoJKwoJaW50IDggLy8gaGVhZE9mZnNldAoJKwoJZnJhbWVfZGlnIDEgLy8gcG9vbE51bVN0YWtlcnM6IHVpbnQ2NAoJaXRvYgoJZXh0cmFjdCA2IDIKCWJ5dGUgMHg3NiAvLyAidiIKCWZyYW1lX2RpZyAtMiAvLyBwb29sS2V5OiBWYWxpZGF0b3JQb29sS2V5CglleHRyYWN0IDAgOAoJYnRvaQoJaXRvYgoJY29uY2F0Cgljb3ZlciAyCglib3hfcmVwbGFjZQoKCS8vIGNvbnRyYWN0cy92YWxpZGF0b3JSZWdpc3RyeS5hbGdvLnRzOjExNDMKCS8vIHRoaXMudmFsaWRhdG9yTGlzdChwb29sS2V5LmlkKS52YWx1ZS5wb29sc1twb29sS2V5LnBvb2xJZCAtIDFdLnRvdGFsQWxnb1N0YWtlZCA9IHBvb2xBbGdvU3Rha2VkCglpbnQgMjM0IC8vIGhlYWRPZmZzZXQKCWZyYW1lX2RpZyAtMiAvLyBwb29sS2V5OiBWYWxpZGF0b3JQb29sS2V5CglleHRyYWN0IDggOAoJYnRvaQoJaW50IDEKCS0KCWludCAxOAoJKiAvLyBhY2MgKiB0eXBlTGVuZ3RoCgkrCglpbnQgMTAgLy8gaGVhZE9mZnNldAoJKwoJZnJhbWVfZGlnIDIgLy8gcG9vbEFsZ29TdGFrZWQ6IHVpbnQ2NAoJaXRvYgoJYnl0ZSAweDc2IC8vICJ2IgoJZnJhbWVfZGlnIC0yIC8vIHBvb2xLZXk6IFZhbGlkYXRvclBvb2xLZXkKCWV4dHJhY3QgMCA4CglidG9pCglpdG9iCgljb25jYXQKCWNvdmVyIDIKCWJveF9yZXBsYWNlCgoJLy8gKmlmMzJfY29uZGl0aW9uCgkvLyBjb250cmFjdHMvdmFsaWRhdG9yUmVnaXN0cnkuYWxnby50czoxMTQ2CgkvLyBpc05ld1N0YWtlclRvVmFsaWRhdG9yCglmcmFtZV9kaWcgLTQgLy8gaXNOZXdTdGFrZXJUb1ZhbGlkYXRvcjogYm9vbGVhbgoJYnogKmlmMzJfZW5kCgoJLy8gKmlmMzJfY29uc2VxdWVudAoJLy8gY29udHJhY3RzL3ZhbGlkYXRvclJlZ2lzdHJ5LmFsZ28udHM6MTE0NwoJLy8gdGhpcy52YWxpZGF0b3JMaXN0KHBvb2xLZXkuaWQpLnZhbHVlLnN0YXRlLnRvdGFsU3Rha2VycyArPSAxCglpbnQgMjEwCglkdXAKCWludCA4CglieXRlIDB4NzYgLy8gInYiCglmcmFtZV9kaWcgLTIgLy8gcG9vbEtleTogVmFsaWRhdG9yUG9vbEtleQoJZXh0cmFjdCAwIDgKCWJ0b2kKCWl0b2IKCWNvbmNhdAoJY292ZXIgMgoJYm94X2V4dHJhY3QKCWJ0b2kKCWludCAxCgkrCglpdG9iCglieXRlIDB4NzYgLy8gInYiCglmcmFtZV9kaWcgLTIgLy8gcG9vbEtleTogVmFsaWRhdG9yUG9vbEtleQoJZXh0cmFjdCAwIDgKCWJ0b2kKCWl0b2IKCWNvbmNhdAoJY292ZXIgMgoJYm94X3JlcGxhY2UKCippZjMyX2VuZDoKCS8vICppZjMzX2NvbmRpdGlvbgoJLy8gY29udHJhY3RzL3ZhbGlkYXRvclJlZ2lzdHJ5LmFsZ28udHM6MTE0OQoJLy8gaXNOZXdTdGFrZXJUb1Byb3RvY29sCglmcmFtZV9kaWcgLTUgLy8gaXNOZXdTdGFrZXJUb1Byb3RvY29sOiBib29sZWFuCglieiAqaWYzM19lbmQKCgkvLyAqaWYzM19jb25zZXF1ZW50CgkvLyBjb250cmFjdHMvdmFsaWRhdG9yUmVnaXN0cnkuYWxnby50czoxMTUwCgkvLyB0aGlzLm51bVN0YWtlcnMudmFsdWUgKz0gMQoJYnl0ZSAweDZlNzU2ZDUzNzQ2MTZiNjU3MjczIC8vICJudW1TdGFrZXJzIgoJYXBwX2dsb2JhbF9nZXQKCWludCAxCgkrCglieXRlIDB4NmU3NTZkNTM3NDYxNmI2NTcyNzMgLy8gIm51bVN0YWtlcnMiCglzd2FwCglhcHBfZ2xvYmFsX3B1dAoKKmlmMzNfZW5kOgoJLy8gY29udHJhY3RzL3ZhbGlkYXRvclJlZ2lzdHJ5LmFsZ28udHM6MTE1MgoJLy8gdGhpcy52YWxpZGF0b3JMaXN0KHBvb2xLZXkuaWQpLnZhbHVlLnN0YXRlLnRvdGFsQWxnb1N0YWtlZCArPSBzdGFrZWRBbW91bnRQYXltZW50LmFtb3VudCAtIG1ickFtdFBhaWQKCWludCAyMTgKCWR1cAoJaW50IDgKCWJ5dGUgMHg3NiAvLyAidiIKCWZyYW1lX2RpZyAtMiAvLyBwb29sS2V5OiBWYWxpZGF0b3JQb29sS2V5CglleHRyYWN0IDAgOAoJYnRvaQoJaXRvYgoJY29uY2F0Cgljb3ZlciAyCglib3hfZXh0cmFjdAoJYnRvaQoJZnJhbWVfZGlnIC0xIC8vIHN0YWtlZEFtb3VudFBheW1lbnQ6IFBheVR4bgoJZ3R4bnMgQW1vdW50CglmcmFtZV9kaWcgLTMgLy8gbWJyQW10UGFpZDogdWludDY0CgktCgkrCglpdG9iCglieXRlIDB4NzYgLy8gInYiCglmcmFtZV9kaWcgLTIgLy8gcG9vbEtleTogVmFsaWRhdG9yUG9vbEtleQoJZXh0cmFjdCAwIDgKCWJ0b2kKCWl0b2IKCWNvbmNhdAoJY292ZXIgMgoJYm94X3JlcGxhY2UKCgkvLyBjb250cmFjdHMvdmFsaWRhdG9yUmVnaXN0cnkuYWxnby50czoxMTUzCgkvLyB0aGlzLnRvdGFsQWxnb1N0YWtlZC52YWx1ZSArPSBzdGFrZWRBbW91bnRQYXltZW50LmFtb3VudCAtIG1ickFtdFBhaWQKCWJ5dGUgMHg3Mzc0NjE2YjY1NjQgLy8gInN0YWtlZCIKCWFwcF9nbG9iYWxfZ2V0CglmcmFtZV9kaWcgLTEgLy8gc3Rha2VkQW1vdW50UGF5bWVudDogUGF5VHhuCglndHhucyBBbW91bnQKCWZyYW1lX2RpZyAtMyAvLyBtYnJBbXRQYWlkOiB1aW50NjQKCS0KCSsKCWJ5dGUgMHg3Mzc0NjE2YjY1NjQgLy8gInN0YWtlZCIKCXN3YXAKCWFwcF9nbG9iYWxfcHV0CglyZXRzdWIKCi8vIHVwZGF0ZVN0YWtlclBvb2xTZXQoc3Rha2VyOiBBZGRyZXNzLCBwb29sS2V5OiBWYWxpZGF0b3JQb29sS2V5KTogdm9pZAp1cGRhdGVTdGFrZXJQb29sU2V0OgoJcHJvdG8gMiAwCgoJLy8gUHVzaCBlbXB0eSBieXRlcyBhZnRlciB0aGUgZnJhbWUgcG9pbnRlciB0byByZXNlcnZlIHNwYWNlIGZvciBsb2NhbCB2YXJpYWJsZXMKCWJ5dGUgMHgKCWR1cAoKCS8vIGNvbnRyYWN0cy92YWxpZGF0b3JSZWdpc3RyeS5hbGdvLnRzOjExNTcKCS8vIGFzc2VydCh0aGlzLnN0YWtlclBvb2xTZXQoc3Rha2VyKS5leGlzdHMpCglieXRlIDB4NzM3MDczIC8vICJzcHMiCglmcmFtZV9kaWcgLTEgLy8gc3Rha2VyOiBBZGRyZXNzCgljb25jYXQKCWJveF9sZW4KCXN3YXAKCXBvcAoJYXNzZXJ0CgoJLy8gY29udHJhY3RzL3ZhbGlkYXRvclJlZ2lzdHJ5LmFsZ28udHM6MTE1OQoJLy8gcG9vbFNldCA9IGNsb25lKHRoaXMuc3Rha2VyUG9vbFNldChzdGFrZXIpLnZhbHVlKQoJYnl0ZSAweDczNzA3MyAvLyAic3BzIgoJZnJhbWVfZGlnIC0xIC8vIHN0YWtlcjogQWRkcmVzcwoJY29uY2F0Cglib3hfZ2V0Cglhc3NlcnQKCWZyYW1lX2J1cnkgMCAvLyBwb29sU2V0OiAodWludDY0LHVpbnQ2NCx1aW50NjQpWzZdCgoJLy8gY29udHJhY3RzL3ZhbGlkYXRvclJlZ2lzdHJ5LmFsZ28udHM6MTE2MAoJLy8gZm9yIChsZXQgaSA9IDA7IGkgPCB0aGlzLnN0YWtlclBvb2xTZXQoc3Rha2VyKS52YWx1ZS5sZW5ndGg7IGkgKz0gMSkKCWludCAwCglmcmFtZV9idXJ5IDEgLy8gaTogdWludDY0CgoqZm9yXzc6CgkvLyBjb250cmFjdHMvdmFsaWRhdG9yUmVnaXN0cnkuYWxnby50czoxMTYwCgkvLyBpIDwgdGhpcy5zdGFrZXJQb29sU2V0KHN0YWtlcikudmFsdWUubGVuZ3RoCglmcmFtZV9kaWcgMSAvLyBpOiB1aW50NjQKCWludCA2Cgk8CglieiAqZm9yXzdfZW5kCgoJLy8gKmlmMzRfY29uZGl0aW9uCgkvLyBjb250cmFjdHMvdmFsaWRhdG9yUmVnaXN0cnkuYWxnby50czoxMTYxCgkvLyBwb29sU2V0W2ldID09PSBwb29sS2V5CglmcmFtZV9kaWcgMCAvLyBwb29sU2V0OiAodWludDY0LHVpbnQ2NCx1aW50NjQpWzZdCglmcmFtZV9kaWcgMSAvLyBpOiB1aW50NjQKCWludCAyNAoJKiAvLyBhY2MgKiB0eXBlTGVuZ3RoCglpbnQgMjQKCWV4dHJhY3QzCglmcmFtZV9kaWcgLTIgLy8gcG9vbEtleTogVmFsaWRhdG9yUG9vbEtleQoJPT0KCWJ6ICppZjM0X2VuZAoKCS8vICppZjM0X2NvbnNlcXVlbnQKCS8vIGNvbnRyYWN0cy92YWxpZGF0b3JSZWdpc3RyeS5hbGdvLnRzOjExNjMKCS8vIHJldHVybjsKCXJldHN1YgoKKmlmMzRfZW5kOgoJLy8gKmlmMzVfY29uZGl0aW9uCgkvLyBjb250cmFjdHMvdmFsaWRhdG9yUmVnaXN0cnkuYWxnby50czoxMTY1CgkvLyBwb29sU2V0W2ldLmlkID09PSAwCglmcmFtZV9kaWcgMCAvLyBwb29sU2V0OiAodWludDY0LHVpbnQ2NCx1aW50NjQpWzZdCglmcmFtZV9kaWcgMSAvLyBpOiB1aW50NjQKCWludCAyNAoJKiAvLyBhY2MgKiB0eXBlTGVuZ3RoCglpbnQgMAoJKwoJaW50IDgKCWV4dHJhY3QzCglidG9pCglpbnQgMAoJPT0KCWJ6ICppZjM1X2VuZAoKCS8vICppZjM1X2NvbnNlcXVlbnQKCS8vIGNvbnRyYWN0cy92YWxpZGF0b3JSZWdpc3RyeS5hbGdvLnRzOjExNjYKCS8vIHRoaXMuc3Rha2VyUG9vbFNldChzdGFrZXIpLnZhbHVlW2ldID0gcG9vbEtleQoJZnJhbWVfZGlnIDEgLy8gaTogdWludDY0CglpbnQgMjQKCSogLy8gYWNjICogdHlwZUxlbmd0aAoJZnJhbWVfZGlnIC0yIC8vIHBvb2xLZXk6IFZhbGlkYXRvclBvb2xLZXkKCWJ5dGUgMHg3MzcwNzMgLy8gInNwcyIKCWZyYW1lX2RpZyAtMSAvLyBzdGFrZXI6IEFkZHJlc3MKCWNvbmNhdAoJY292ZXIgMgoJYm94X3JlcGxhY2UKCgkvLyBjb250cmFjdHMvdmFsaWRhdG9yUmVnaXN0cnkuYWxnby50czoxMTY3CgkvLyByZXR1cm47CglyZXRzdWIKCippZjM1X2VuZDoKCipmb3JfN19jb250aW51ZToKCS8vIGNvbnRyYWN0cy92YWxpZGF0b3JSZWdpc3RyeS5hbGdvLnRzOjExNjAKCS8vIGkgKz0gMQoJZnJhbWVfZGlnIDEgLy8gaTogdWludDY0CglpbnQgMQoJKwoJZnJhbWVfYnVyeSAxIC8vIGk6IHVpbnQ2NAoJYiAqZm9yXzcKCipmb3JfN19lbmQ6CgllcnIgLy8gJ05vIGVtcHR5IHNsb3QgYXZhaWxhYmxlIGluIHRoZSBzdGFrZXIgcG9vbCBzZXQnCgovLyByZW1vdmVGcm9tU3Rha2VyUG9vbFNldChzdGFrZXI6IEFkZHJlc3MsIHBvb2xLZXk6IFZhbGlkYXRvclBvb2xLZXkpOiBbYm9vbGVhbiwgYm9vbGVhbl0KLy8KLy8gUmVtb3ZlcyBhIHBvb2wga2V5IGZyb20gdGhlIHN0YWtlcidzIGFjdGl2ZSBwb29sIHNldCAtIGZhaWxzIGlmIG5vdCBmb3VuZCAoISkKLy8KLy8gQHBhcmFtIHtBZGRyZXNzfSBzdGFrZXIgLSBUaGUgYWRkcmVzcyBvZiB0aGUgc3Rha2VyLgovLyBAcGFyYW0ge1ZhbGlkYXRvclBvb2xLZXl9IHBvb2xLZXkgLSBUaGUgcG9vbCBrZXkgdGhleSBzaG91bGQgYmUgc3RvcmVkIGluCi8vCi8vIEByZXR1cm4gW2Jvb2xlYW4sIGJvb2xlYW5dIFtpcyB0aGUgc3Rha2VyIGdvbmUgZnJvbSBBTEwgcG9vbHMgb2YgdGhlIGdpdmVuIFZBTElEQVRPUiwgYW5kIGlzIHN0YWtlciBnb25lIGZyb20gQUxMIHBvb2xzXQpyZW1vdmVGcm9tU3Rha2VyUG9vbFNldDoKCXByb3RvIDIgMQoKCS8vIFB1c2ggZW1wdHkgYnl0ZXMgYWZ0ZXIgdGhlIGZyYW1lIHBvaW50ZXIgdG8gcmVzZXJ2ZSBzcGFjZSBmb3IgbG9jYWwgdmFyaWFibGVzCglieXRlIDB4CglkdXBuIDQKCgkvLyBjb250cmFjdHMvdmFsaWRhdG9yUmVnaXN0cnkuYWxnby50czoxMTgzCgkvLyBpblNhbWVWYWxpZGF0b3JQb29sQ291bnQgPSAwCglpbnQgMAoJZnJhbWVfYnVyeSAwIC8vIGluU2FtZVZhbGlkYXRvclBvb2xDb3VudDogdWludDY0CgoJLy8gY29udHJhY3RzL3ZhbGlkYXRvclJlZ2lzdHJ5LmFsZ28udHM6MTE4NAoJLy8gaW5BbnlQb29sQ291bnQgPSAwCglpbnQgMAoJZnJhbWVfYnVyeSAxIC8vIGluQW55UG9vbENvdW50OiB1aW50NjQKCgkvLyBjb250cmFjdHMvdmFsaWRhdG9yUmVnaXN0cnkuYWxnby50czoxMTg1CgkvLyBmb3VuZCA9IGZhbHNlCglpbnQgMAoJZnJhbWVfYnVyeSAyIC8vIGZvdW5kOiBib29sCgoJLy8gY29udHJhY3RzL3ZhbGlkYXRvclJlZ2lzdHJ5LmFsZ28udHM6MTE4NwoJLy8gcG9vbFNldCA9IGNsb25lKHRoaXMuc3Rha2VyUG9vbFNldChzdGFrZXIpLnZhbHVlKQoJYnl0ZSAweDczNzA3MyAvLyAic3BzIgoJZnJhbWVfZGlnIC0xIC8vIHN0YWtlcjogQWRkcmVzcwoJY29uY2F0Cglib3hfZ2V0Cglhc3NlcnQKCWZyYW1lX2J1cnkgMyAvLyBwb29sU2V0OiAodWludDY0LHVpbnQ2NCx1aW50NjQpWzZdCgoJLy8gY29udHJhY3RzL3ZhbGlkYXRvclJlZ2lzdHJ5LmFsZ28udHM6MTE4OAoJLy8gZm9yIChsZXQgaSA9IDA7IGkgPCB0aGlzLnN0YWtlclBvb2xTZXQoc3Rha2VyKS52YWx1ZS5sZW5ndGg7IGkgKz0gMSkKCWludCAwCglmcmFtZV9idXJ5IDQgLy8gaTogdWludDY0CgoqZm9yXzg6CgkvLyBjb250cmFjdHMvdmFsaWRhdG9yUmVnaXN0cnkuYWxnby50czoxMTg4CgkvLyBpIDwgdGhpcy5zdGFrZXJQb29sU2V0KHN0YWtlcikudmFsdWUubGVuZ3RoCglmcmFtZV9kaWcgNCAvLyBpOiB1aW50NjQKCWludCA2Cgk8CglieiAqZm9yXzhfZW5kCgoJLy8gKmlmMzZfY29uZGl0aW9uCgkvLyBjb250cmFjdHMvdmFsaWRhdG9yUmVnaXN0cnkuYWxnby50czoxMTg5CgkvLyBwb29sU2V0W2ldLmlkID09PSAwCglmcmFtZV9kaWcgMyAvLyBwb29sU2V0OiAodWludDY0LHVpbnQ2NCx1aW50NjQpWzZdCglmcmFtZV9kaWcgNCAvLyBpOiB1aW50NjQKCWludCAyNAoJKiAvLyBhY2MgKiB0eXBlTGVuZ3RoCglpbnQgMAoJKwoJaW50IDgKCWV4dHJhY3QzCglidG9pCglpbnQgMAoJPT0KCWJ6ICppZjM2X2VuZAoKCS8vICppZjM2X2NvbnNlcXVlbnQKCWIgKmZvcl84X2NvbnRpbnVlCgoqaWYzNl9lbmQ6CgkvLyBjb250cmFjdHMvdmFsaWRhdG9yUmVnaXN0cnkuYWxnby50czoxMTkyCgkvLyBpbkFueVBvb2xDb3VudCArPSAxCglmcmFtZV9kaWcgMSAvLyBpbkFueVBvb2xDb3VudDogdWludDY0CglpbnQgMQoJKwoJZnJhbWVfYnVyeSAxIC8vIGluQW55UG9vbENvdW50OiB1aW50NjQKCgkvLyAqaWYzN19jb25kaXRpb24KCS8vIGNvbnRyYWN0cy92YWxpZGF0b3JSZWdpc3RyeS5hbGdvLnRzOjExOTMKCS8vIHBvb2xTZXRbaV0uaWQgPT09IHBvb2xLZXkuaWQKCWZyYW1lX2RpZyAzIC8vIHBvb2xTZXQ6ICh1aW50NjQsdWludDY0LHVpbnQ2NClbNl0KCWZyYW1lX2RpZyA0IC8vIGk6IHVpbnQ2NAoJaW50IDI0CgkqIC8vIGFjYyAqIHR5cGVMZW5ndGgKCWludCAwCgkrCglpbnQgOAoJZXh0cmFjdDMKCWJ0b2kKCWZyYW1lX2RpZyAtMiAvLyBwb29sS2V5OiBWYWxpZGF0b3JQb29sS2V5CglleHRyYWN0IDAgOAoJYnRvaQoJPT0KCWJ6ICppZjM3X2VuZAoKCS8vICppZjM3X2NvbnNlcXVlbnQKCS8vICppZjM4X2NvbmRpdGlvbgoJLy8gY29udHJhY3RzL3ZhbGlkYXRvclJlZ2lzdHJ5LmFsZ28udHM6MTE5NAoJLy8gcG9vbFNldFtpXSA9PT0gcG9vbEtleQoJZnJhbWVfZGlnIDMgLy8gcG9vbFNldDogKHVpbnQ2NCx1aW50NjQsdWludDY0KVs2XQoJZnJhbWVfZGlnIDQgLy8gaTogdWludDY0CglpbnQgMjQKCSogLy8gYWNjICogdHlwZUxlbmd0aAoJaW50IDI0CglleHRyYWN0MwoJZnJhbWVfZGlnIC0yIC8vIHBvb2xLZXk6IFZhbGlkYXRvclBvb2xLZXkKCT09CglieiAqaWYzOF9lbHNlCgoJLy8gKmlmMzhfY29uc2VxdWVudAoJLy8gY29udHJhY3RzL3ZhbGlkYXRvclJlZ2lzdHJ5LmFsZ28udHM6MTE5NQoJLy8gZm91bmQgPSB0cnVlCglpbnQgMQoJZnJhbWVfYnVyeSAyIC8vIGZvdW5kOiBib29sCgoJLy8gY29udHJhY3RzL3ZhbGlkYXRvclJlZ2lzdHJ5LmFsZ28udHM6MTE5NwoJLy8gdGhpcy5zdGFrZXJQb29sU2V0KHN0YWtlcikudmFsdWVbaV0gPSB7IGlkOiAwLCBwb29sSWQ6IDAsIHBvb2xBcHBJZDogMCB9CglmcmFtZV9kaWcgNCAvLyBpOiB1aW50NjQKCWludCAyNAoJKiAvLyBhY2MgKiB0eXBlTGVuZ3RoCglieXRlIDB4MDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwCglieXRlIDB4NzM3MDczIC8vICJzcHMiCglmcmFtZV9kaWcgLTEgLy8gc3Rha2VyOiBBZGRyZXNzCgljb25jYXQKCWNvdmVyIDIKCWJveF9yZXBsYWNlCgliICppZjM4X2VuZAoKKmlmMzhfZWxzZToKCS8vIGNvbnRyYWN0cy92YWxpZGF0b3JSZWdpc3RyeS5hbGdvLnRzOjExOTkKCS8vIGluU2FtZVZhbGlkYXRvclBvb2xDb3VudCArPSAxCglmcmFtZV9kaWcgMCAvLyBpblNhbWVWYWxpZGF0b3JQb29sQ291bnQ6IHVpbnQ2NAoJaW50IDEKCSsKCWZyYW1lX2J1cnkgMCAvLyBpblNhbWVWYWxpZGF0b3JQb29sQ291bnQ6IHVpbnQ2NAoKKmlmMzhfZW5kOgoKKmlmMzdfZW5kOgoKKmZvcl84X2NvbnRpbnVlOgoJLy8gY29udHJhY3RzL3ZhbGlkYXRvclJlZ2lzdHJ5LmFsZ28udHM6MTE4OAoJLy8gaSArPSAxCglmcmFtZV9kaWcgNCAvLyBpOiB1aW50NjQKCWludCAxCgkrCglmcmFtZV9idXJ5IDQgLy8gaTogdWludDY0CgliICpmb3JfOAoKKmZvcl84X2VuZDoKCS8vICppZjM5X2NvbmRpdGlvbgoJLy8gY29udHJhY3RzL3ZhbGlkYXRvclJlZ2lzdHJ5LmFsZ28udHM6MTIwMwoJLy8gIWZvdW5kCglmcmFtZV9kaWcgMiAvLyBmb3VuZDogYm9vbAoJIQoJYnogKmlmMzlfZW5kCgoJLy8gKmlmMzlfY29uc2VxdWVudAoJZXJyIC8vICdObyBtYXRjaGluZyBzbG90IGZvdW5kIHdoZW4gdG9sZCB0byByZW1vdmUgYSBwb29sIGZyb20gdGhlIHN0YWtlcnMgc2V0JwoKKmlmMzlfZW5kOgoJLy8gY29udHJhY3RzL3ZhbGlkYXRvclJlZ2lzdHJ5LmFsZ28udHM6MTIwNwoJLy8gcmV0dXJuIFtpblNhbWVWYWxpZGF0b3JQb29sQ291bnQgPT09IDAsIGluQW55UG9vbENvdW50ID09PSAwXTsKCWJ5dGUgMHgwMAoJaW50IDAKCWZyYW1lX2RpZyAwIC8vIGluU2FtZVZhbGlkYXRvclBvb2xDb3VudDogdWludDY0CglpbnQgMAoJPT0KCXNldGJpdAoJaW50IDEKCWZyYW1lX2RpZyAxIC8vIGluQW55UG9vbENvdW50OiB1aW50NjQKCWludCAwCgk9PQoJc2V0Yml0CgoJLy8gc2V0IHRoZSBzdWJyb3V0aW5lIHJldHVybiB2YWx1ZQoJZnJhbWVfYnVyeSAwCgoJLy8gcG9wIGFsbCBsb2NhbCB2YXJpYWJsZXMgZnJvbSB0aGUgc3RhY2sKCXBvcG4gNAoJcmV0c3ViCgovLyBhZGRQb29sVG9Ob2RlKHZhbGlkYXRvcklkOiBWYWxpZGF0b3JJZFR5cGUsIHBvb2xBcHBJZDogdWludDY0LCBub2RlTnVtOiB1aW50NjQpOiB2b2lkCmFkZFBvb2xUb05vZGU6Cglwcm90byAzIDAKCgkvLyBQdXNoIGVtcHR5IGJ5dGVzIGFmdGVyIHRoZSBmcmFtZSBwb2ludGVyIHRvIHJlc2VydmUgc3BhY2UgZm9yIGxvY2FsIHZhcmlhYmxlcwoJYnl0ZSAweAoJZHVwbiAyCgoJLy8gY29udHJhY3RzL3ZhbGlkYXRvclJlZ2lzdHJ5LmFsZ28udHM6MTIxMQoJLy8gbm9kZVBvb2xBc3NpZ25tZW50cyA9IGNsb25lKHRoaXMudmFsaWRhdG9yTGlzdCh2YWxpZGF0b3JJZCkudmFsdWUubm9kZVBvb2xBc3NpZ25tZW50cykKCWludCA4NjYgLy8gaGVhZE9mZnNldAoJaW50IDE5MgoJYnl0ZSAweDc2IC8vICJ2IgoJZnJhbWVfZGlnIC0xIC8vIHZhbGlkYXRvcklkOiBWYWxpZGF0b3JJZFR5cGUKCWl0b2IKCWNvbmNhdAoJY292ZXIgMgoJYm94X2V4dHJhY3QKCWZyYW1lX2J1cnkgMCAvLyBub2RlUG9vbEFzc2lnbm1lbnRzOiAoKHVpbnQ2NFszXSlbOF0pCgoJLy8gY29udHJhY3RzL3ZhbGlkYXRvclJlZ2lzdHJ5LmFsZ28udHM6MTIxMgoJLy8gbWF4UG9vbHNQZXJOb2RlRm9yVGhpc1ZhbGlkYXRvciA9IHRoaXMudmFsaWRhdG9yTGlzdCh2YWxpZGF0b3JJZCkudmFsdWUuY29uZmlnLnBvb2xzUGVyTm9kZSBhcyB1aW50NjQKCWludCAxOTEKCWludCAxCglieXRlIDB4NzYgLy8gInYiCglmcmFtZV9kaWcgLTEgLy8gdmFsaWRhdG9ySWQ6IFZhbGlkYXRvcklkVHlwZQoJaXRvYgoJY29uY2F0Cgljb3ZlciAyCglib3hfZXh0cmFjdAoJYnRvaQoJZnJhbWVfYnVyeSAxIC8vIG1heFBvb2xzUGVyTm9kZUZvclRoaXNWYWxpZGF0b3I6IHVpbnQ2NAoKCS8vIGNvbnRyYWN0cy92YWxpZGF0b3JSZWdpc3RyeS5hbGdvLnRzOjEyMTQKCS8vIGFzc2VydChub2RlTnVtID49IDEgJiYgbm9kZU51bSA8PSBNQVhfTk9ERVMpCglmcmFtZV9kaWcgLTMgLy8gbm9kZU51bTogdWludDY0CglpbnQgMQoJPj0KCWR1cAoJYnogKnNraXBfYW5kOAoJZnJhbWVfZGlnIC0zIC8vIG5vZGVOdW06IHVpbnQ2NAoJaW50IDgKCTw9CgkmJgoKKnNraXBfYW5kODoKCWFzc2VydAoKCS8vIGNvbnRyYWN0cy92YWxpZGF0b3JSZWdpc3RyeS5hbGdvLnRzOjEyMTYKCS8vIGZvciAobGV0IGkgPSAwOyBpIDwgbWF4UG9vbHNQZXJOb2RlRm9yVGhpc1ZhbGlkYXRvcjsgaSArPSAxKQoJaW50IDAKCWZyYW1lX2J1cnkgMiAvLyBpOiB1aW50NjQKCipmb3JfOToKCS8vIGNvbnRyYWN0cy92YWxpZGF0b3JSZWdpc3RyeS5hbGdvLnRzOjEyMTYKCS8vIGkgPCBtYXhQb29sc1Blck5vZGVGb3JUaGlzVmFsaWRhdG9yCglmcmFtZV9kaWcgMiAvLyBpOiB1aW50NjQKCWZyYW1lX2RpZyAxIC8vIG1heFBvb2xzUGVyTm9kZUZvclRoaXNWYWxpZGF0b3I6IHVpbnQ2NAoJPAoJYnogKmZvcl85X2VuZAoKCS8vICppZjQwX2NvbmRpdGlvbgoJLy8gY29udHJhY3RzL3ZhbGlkYXRvclJlZ2lzdHJ5LmFsZ28udHM6MTIxNwoJLy8gbm9kZVBvb2xBc3NpZ25tZW50cy5ub2Rlc1tub2RlTnVtIC0gMV0ucG9vbEFwcElkc1tpXSA9PT0gMAoJZnJhbWVfZGlnIDAgLy8gbm9kZVBvb2xBc3NpZ25tZW50czogKCh1aW50NjRbM10pWzhdKQoJaW50IDAKCWZyYW1lX2RpZyAtMyAvLyBub2RlTnVtOiB1aW50NjQKCWludCAxCgktCglpbnQgMjQKCSogLy8gYWNjICogdHlwZUxlbmd0aAoJKwoJaW50IDAKCSsKCWZyYW1lX2RpZyAyIC8vIGk6IHVpbnQ2NAoJaW50IDgKCSogLy8gYWNjICogdHlwZUxlbmd0aAoJKwoJaW50IDgKCWV4dHJhY3QzCglidG9pCglpbnQgMAoJPT0KCWJ6ICppZjQwX2VuZAoKCS8vICppZjQwX2NvbnNlcXVlbnQKCS8vIGNvbnRyYWN0cy92YWxpZGF0b3JSZWdpc3RyeS5hbGdvLnRzOjEyMTkKCS8vIHRoaXMudmFsaWRhdG9yTGlzdCh2YWxpZGF0b3JJZCkudmFsdWUubm9kZVBvb2xBc3NpZ25tZW50cy5ub2Rlc1tub2RlTnVtIC0gMV0ucG9vbEFwcElkc1tpXSA9IHBvb2xBcHBJZAoJaW50IDg2NgoJZnJhbWVfZGlnIC0zIC8vIG5vZGVOdW06IHVpbnQ2NAoJaW50IDEKCS0KCWludCAyNAoJKiAvLyBhY2MgKiB0eXBlTGVuZ3RoCgkrCglpbnQgMAoJKwoJZnJhbWVfZGlnIDIgLy8gaTogdWludDY0CglpbnQgOAoJKiAvLyBhY2MgKiB0eXBlTGVuZ3RoCgkrCglmcmFtZV9kaWcgLTIgLy8gcG9vbEFwcElkOiB1aW50NjQKCWl0b2IKCWJ5dGUgMHg3NiAvLyAidiIKCWZyYW1lX2RpZyAtMSAvLyB2YWxpZGF0b3JJZDogVmFsaWRhdG9ySWRUeXBlCglpdG9iCgljb25jYXQKCWNvdmVyIDIKCWJveF9yZXBsYWNlCgoJLy8gY29udHJhY3RzL3ZhbGlkYXRvclJlZ2lzdHJ5LmFsZ28udHM6MTIyMAoJLy8gcmV0dXJuOwoJcmV0c3ViCgoqaWY0MF9lbmQ6CgoqZm9yXzlfY29udGludWU6CgkvLyBjb250cmFjdHMvdmFsaWRhdG9yUmVnaXN0cnkuYWxnby50czoxMjE2CgkvLyBpICs9IDEKCWZyYW1lX2RpZyAyIC8vIGk6IHVpbnQ2NAoJaW50IDEKCSsKCWZyYW1lX2J1cnkgMiAvLyBpOiB1aW50NjQKCWIgKmZvcl85CgoqZm9yXzlfZW5kOgoJZXJyIC8vICdubyBhdmFpbGFibGUgc3BhY2UgaW4gc3BlY2lmaWVkIG5vZGUgZm9yIHRoaXMgcG9vbCcKCi8vIGRvZXNTdGFrZXJNZWV0R2F0aW5nKHZhbGlkYXRvcklkOiBWYWxpZGF0b3JJZFR5cGUsIHZhbHVlVG9WZXJpZnk6IHVpbnQ2NCk6IHZvaWQKLy8KLy8gQ2hlY2tzIGlmIGEgc3Rha2VyIG1lZXRzIHRoZSBnYXRpbmcgcmVxdWlyZW1lbnRzIHNwZWNpZmllZCBieSB0aGUgdmFsaWRhdG9yLgovLwovLyBAcGFyYW0ge1ZhbGlkYXRvcklkVHlwZX0gdmFsaWRhdG9ySWQgLSBUaGUgaWQgb2YgdGhlIHZhbGlkYXRvci4KLy8gQHBhcmFtIHt1aW50NjR9IHZhbHVlVG9WZXJpZnkgLSBUaGUgdmFsdWUgdG8gdmVyaWZ5IGFnYWluc3QgdGhlIGdhdGluZyByZXF1aXJlbWVudHMuCi8vIEByZXR1cm5zIHt2b2lkfSBvciBhc3NlcnRzIGlmIHJlcXVpcmVtZW50cyBub3QgbWV0Lgpkb2VzU3Rha2VyTWVldEdhdGluZzoKCXByb3RvIDIgMAoKCS8vIFB1c2ggZW1wdHkgYnl0ZXMgYWZ0ZXIgdGhlIGZyYW1lIHBvaW50ZXIgdG8gcmVzZXJ2ZSBzcGFjZSBmb3IgbG9jYWwgdmFyaWFibGVzCglieXRlIDB4CglkdXBuIDcKCgkvLyBjb250cmFjdHMvdmFsaWRhdG9yUmVnaXN0cnkuYWxnby50czoxMjM0CgkvLyB0eXBlID0gdGhpcy52YWxpZGF0b3JMaXN0KHZhbGlkYXRvcklkKS52YWx1ZS5jb25maWcuZW50cnlHYXRpbmdUeXBlCglpbnQgODAKCWludCAxCglieXRlIDB4NzYgLy8gInYiCglmcmFtZV9kaWcgLTEgLy8gdmFsaWRhdG9ySWQ6IFZhbGlkYXRvcklkVHlwZQoJaXRvYgoJY29uY2F0Cgljb3ZlciAyCglib3hfZXh0cmFjdAoJYnRvaQoJZnJhbWVfYnVyeSAwIC8vIHR5cGU6IHVpbnQ4CgoJLy8gKmlmNDFfY29uZGl0aW9uCgkvLyBjb250cmFjdHMvdmFsaWRhdG9yUmVnaXN0cnkuYWxnby50czoxMjM1CgkvLyB0eXBlID09PSBHQVRJTkdfVFlQRV9OT05FCglmcmFtZV9kaWcgMCAvLyB0eXBlOiB1aW50OAoJaW50IDAKCT09CglieiAqaWY0MV9lbmQKCgkvLyAqaWY0MV9jb25zZXF1ZW50CgkvLyBjb250cmFjdHMvdmFsaWRhdG9yUmVnaXN0cnkuYWxnby50czoxMjM2CgkvLyByZXR1cm47CglyZXRzdWIKCippZjQxX2VuZDoKCS8vIGNvbnRyYWN0cy92YWxpZGF0b3JSZWdpc3RyeS5hbGdvLnRzOjEyMzgKCS8vIHN0YWtlciA9IHRoaXMudHhuLnNlbmRlcgoJdHhuIFNlbmRlcgoJZnJhbWVfYnVyeSAxIC8vIHN0YWtlcjogYWRkcmVzcwoKCS8vIGNvbnRyYWN0cy92YWxpZGF0b3JSZWdpc3RyeS5hbGdvLnRzOjEyMzkKCS8vIGdhdGVSZXEgPSBjbG9uZSh0aGlzLnZhbGlkYXRvckxpc3QodmFsaWRhdG9ySWQpLnZhbHVlLmNvbmZpZy5lbnRyeUdhdGluZ1ZhbHVlKQoJaW50IDgxCglpbnQgMzIKCWJ5dGUgMHg3NiAvLyAidiIKCWZyYW1lX2RpZyAtMSAvLyB2YWxpZGF0b3JJZDogVmFsaWRhdG9ySWRUeXBlCglpdG9iCgljb25jYXQKCWNvdmVyIDIKCWJveF9leHRyYWN0CglmcmFtZV9idXJ5IDIgLy8gZ2F0ZVJlcTogYnl0ZVszMl0KCgkvLyAqaWY0Ml9jb25kaXRpb24KCS8vIGNvbnRyYWN0cy92YWxpZGF0b3JSZWdpc3RyeS5hbGdvLnRzOjEyNDMKCS8vIHR5cGUgPT09IEdBVElOR19UWVBFX0FTU0VUU19DUkVBVEVEX0JZIHx8CgkvLyAgICAgICAgICAgICB0eXBlID09PSBHQVRJTkdfVFlQRV9BU1NFVF9JRCB8fAoJLy8gICAgICAgICAgICAgdHlwZSA9PT0gR0FUSU5HX1RZUEVfQ1JFQVRFRF9CWV9ORkRfQUREUkVTU0VTCglmcmFtZV9kaWcgMCAvLyB0eXBlOiB1aW50OAoJaW50IDEKCT09CglkdXAKCWJueiAqc2tpcF9vcjQKCWZyYW1lX2RpZyAwIC8vIHR5cGU6IHVpbnQ4CglpbnQgMgoJPT0KCXx8Cgoqc2tpcF9vcjQ6CglkdXAKCWJueiAqc2tpcF9vcjUKCWZyYW1lX2RpZyAwIC8vIHR5cGU6IHVpbnQ4CglpbnQgMwoJPT0KCXx8Cgoqc2tpcF9vcjU6CglieiAqaWY0Ml9lbmQKCgkvLyAqaWY0Ml9jb25zZXF1ZW50CgkvLyBjb250cmFjdHMvdmFsaWRhdG9yUmVnaXN0cnkuYWxnby50czoxMjQ3CgkvLyBhc3NlcnQodmFsdWVUb1ZlcmlmeSAhPT0gMCkKCWZyYW1lX2RpZyAtMiAvLyB2YWx1ZVRvVmVyaWZ5OiB1aW50NjQKCWludCAwCgkhPQoJYXNzZXJ0CgoJLy8gY29udHJhY3RzL3ZhbGlkYXRvclJlZ2lzdHJ5LmFsZ28udHM6MTI0OAoJLy8gYmFsUmVxdWlyZWQgPSB0aGlzLnZhbGlkYXRvckxpc3QodmFsaWRhdG9ySWQpLnZhbHVlLmNvbmZpZy5nYXRpbmdBc3NldE1pbkJhbGFuY2UKCWludCAxMTMKCWludCA4CglieXRlIDB4NzYgLy8gInYiCglmcmFtZV9kaWcgLTEgLy8gdmFsaWRhdG9ySWQ6IFZhbGlkYXRvcklkVHlwZQoJaXRvYgoJY29uY2F0Cgljb3ZlciAyCglib3hfZXh0cmFjdAoJYnRvaQoJZnJhbWVfYnVyeSAzIC8vIGJhbFJlcXVpcmVkOiB1aW50NjQKCgkvLyAqaWY0M19jb25kaXRpb24KCS8vIGNvbnRyYWN0cy92YWxpZGF0b3JSZWdpc3RyeS5hbGdvLnRzOjEyNDkKCS8vIGJhbFJlcXVpcmVkID09PSAwCglmcmFtZV9kaWcgMyAvLyBiYWxSZXF1aXJlZDogdWludDY0CglpbnQgMAoJPT0KCWJ6ICppZjQzX2VuZAoKCS8vICppZjQzX2NvbnNlcXVlbnQKCS8vIGNvbnRyYWN0cy92YWxpZGF0b3JSZWdpc3RyeS5hbGdvLnRzOjEyNTAKCS8vIGJhbFJlcXVpcmVkID0gMQoJaW50IDEKCWZyYW1lX2J1cnkgMyAvLyBiYWxSZXF1aXJlZDogdWludDY0CgoqaWY0M19lbmQ6CgkvLyBjb250cmFjdHMvdmFsaWRhdG9yUmVnaXN0cnkuYWxnby50czoxMjUyCgkvLyBhc3NlcnQoCgkvLyAgICAgICAgICAgICAgICAgc3Rha2VyLmFzc2V0QmFsYW5jZShBc3NldElELmZyb21VaW50NjQodmFsdWVUb1ZlcmlmeSkpID49IGJhbFJlcXVpcmVkLAoJLy8gICAgICAgICAgICAgICAgICdtdXN0IGhhdmUgcmVxdWlyZWQgbWluaW11bSBiYWxhbmNlIG9mIHZhbGlkYXRvciBkZWZpbmVkIHRva2VuIHRvIGFkZCBzdGFrZScKCS8vICAgICAgICAgICAgICkKCWZyYW1lX2RpZyAxIC8vIHN0YWtlcjogYWRkcmVzcwoJZnJhbWVfZGlnIC0yIC8vIHZhbHVlVG9WZXJpZnk6IHVpbnQ2NAoJYXNzZXRfaG9sZGluZ19nZXQgQXNzZXRCYWxhbmNlCglwb3AKCWZyYW1lX2RpZyAzIC8vIGJhbFJlcXVpcmVkOiB1aW50NjQKCT49CgoJLy8gbXVzdCBoYXZlIHJlcXVpcmVkIG1pbmltdW0gYmFsYW5jZSBvZiB2YWxpZGF0b3IgZGVmaW5lZCB0b2tlbiB0byBhZGQgc3Rha2UKCWFzc2VydAoKKmlmNDJfZW5kOgoJLy8gKmlmNDRfY29uZGl0aW9uCgkvLyBjb250cmFjdHMvdmFsaWRhdG9yUmVnaXN0cnkuYWxnby50czoxMjU3CgkvLyB0eXBlID09PSBHQVRJTkdfVFlQRV9BU1NFVFNfQ1JFQVRFRF9CWQoJZnJhbWVfZGlnIDAgLy8gdHlwZTogdWludDgKCWludCAxCgk9PQoJYnogKmlmNDRfZW5kCgoJLy8gKmlmNDRfY29uc2VxdWVudAoJLy8gY29udHJhY3RzL3ZhbGlkYXRvclJlZ2lzdHJ5LmFsZ28udHM6MTI1OAoJLy8gYXNzZXJ0KAoJLy8gICAgICAgICAgICAgICAgIEFzc2V0SUQuZnJvbVVpbnQ2NCh2YWx1ZVRvVmVyaWZ5KS5jcmVhdG9yID09PSBBZGRyZXNzLmZyb21CeXRlcyhnYXRlUmVxKSwKCS8vICAgICAgICAgICAgICAgICAnc3BlY2lmaWVkIGFzc2V0IG11c3QgYmUgY3JlYXRlZCBieSBjcmVhdG9yIHRoYXQgdGhlIHZhbGlkYXRvciBkZWZpbmVkIGFzIGEgcmVxdWlyZW1lbnQgdG8gc3Rha2UnCgkvLyAgICAgICAgICAgICApCglmcmFtZV9kaWcgLTIgLy8gdmFsdWVUb1ZlcmlmeTogdWludDY0Cglhc3NldF9wYXJhbXNfZ2V0IEFzc2V0Q3JlYXRvcgoJcG9wCglmcmFtZV9kaWcgMiAvLyBnYXRlUmVxOiBieXRlWzMyXQoJPT0KCgkvLyBzcGVjaWZpZWQgYXNzZXQgbXVzdCBiZSBjcmVhdGVkIGJ5IGNyZWF0b3IgdGhhdCB0aGUgdmFsaWRhdG9yIGRlZmluZWQgYXMgYSByZXF1aXJlbWVudCB0byBzdGFrZQoJYXNzZXJ0CgoqaWY0NF9lbmQ6CgkvLyAqaWY0NV9jb25kaXRpb24KCS8vIGNvbnRyYWN0cy92YWxpZGF0b3JSZWdpc3RyeS5hbGdvLnRzOjEyNjMKCS8vIHR5cGUgPT09IEdBVElOR19UWVBFX0FTU0VUX0lECglmcmFtZV9kaWcgMCAvLyB0eXBlOiB1aW50OAoJaW50IDIKCT09CglieiAqaWY0NV9lbmQKCgkvLyAqaWY0NV9jb25zZXF1ZW50CgkvLyBjb250cmFjdHMvdmFsaWRhdG9yUmVnaXN0cnkuYWxnby50czoxMjY0CgkvLyByZXF1aXJlZEFzc2V0ID0gZXh0cmFjdFVpbnQ2NChnYXRlUmVxLCAwKQoJZnJhbWVfZGlnIDIgLy8gZ2F0ZVJlcTogYnl0ZVszMl0KCWludCAwCglleHRyYWN0X3VpbnQ2NAoJZnJhbWVfYnVyeSA0IC8vIHJlcXVpcmVkQXNzZXQ6IHVpbnQ2NAoKCS8vIGNvbnRyYWN0cy92YWxpZGF0b3JSZWdpc3RyeS5hbGdvLnRzOjEyNjUKCS8vIGFzc2VydChyZXF1aXJlZEFzc2V0ICE9PSAwKQoJZnJhbWVfZGlnIDQgLy8gcmVxdWlyZWRBc3NldDogdWludDY0CglpbnQgMAoJIT0KCWFzc2VydAoKCS8vIGNvbnRyYWN0cy92YWxpZGF0b3JSZWdpc3RyeS5hbGdvLnRzOjEyNjYKCS8vIGFzc2VydCgKCS8vICAgICAgICAgICAgICAgICB2YWx1ZVRvVmVyaWZ5ID09PSByZXF1aXJlZEFzc2V0LAoJLy8gICAgICAgICAgICAgICAgICdzcGVjaWZpZWQgYXNzZXQgbXVzdCBiZSBpZGVudGljYWwgdG8gdGhlIGFzc2V0IGlkIGRlZmluZWQgYXMgYSByZXF1aXJlbWVudCB0byBzdGFrZScKCS8vICAgICAgICAgICAgICkKCWZyYW1lX2RpZyAtMiAvLyB2YWx1ZVRvVmVyaWZ5OiB1aW50NjQKCWZyYW1lX2RpZyA0IC8vIHJlcXVpcmVkQXNzZXQ6IHVpbnQ2NAoJPT0KCgkvLyBzcGVjaWZpZWQgYXNzZXQgbXVzdCBiZSBpZGVudGljYWwgdG8gdGhlIGFzc2V0IGlkIGRlZmluZWQgYXMgYSByZXF1aXJlbWVudCB0byBzdGFrZQoJYXNzZXJ0CgoqaWY0NV9lbmQ6CgkvLyAqaWY0Nl9jb25kaXRpb24KCS8vIGNvbnRyYWN0cy92YWxpZGF0b3JSZWdpc3RyeS5hbGdvLnRzOjEyNzEKCS8vIHR5cGUgPT09IEdBVElOR19UWVBFX0NSRUFURURfQllfTkZEX0FERFJFU1NFUwoJZnJhbWVfZGlnIDAgLy8gdHlwZTogdWludDgKCWludCAzCgk9PQoJYnogKmlmNDZfZW5kCgoJLy8gKmlmNDZfY29uc2VxdWVudAoJLy8gY29udHJhY3RzL3ZhbGlkYXRvclJlZ2lzdHJ5LmFsZ28udHM6MTI3MgoJLy8gbmZkRm9ySW5mbyA9IHRoaXMudmFsaWRhdG9yTGlzdCh2YWxpZGF0b3JJZCkudmFsdWUuY29uZmlnLm5mZEZvckluZm8KCWludCA3MgoJaW50IDgKCWJ5dGUgMHg3NiAvLyAidiIKCWZyYW1lX2RpZyAtMSAvLyB2YWxpZGF0b3JJZDogVmFsaWRhdG9ySWRUeXBlCglpdG9iCgljb25jYXQKCWNvdmVyIDIKCWJveF9leHRyYWN0CglidG9pCglmcmFtZV9idXJ5IDUgLy8gbmZkRm9ySW5mbzogdWludDY0CgoJLy8gY29udHJhY3RzL3ZhbGlkYXRvclJlZ2lzdHJ5LmFsZ28udHM6MTI3NQoJLy8gYXNzZXJ0KAoJLy8gICAgICAgICAgICAgICAgIHRoaXMuaXNBZGRyZXNzSW5ORkRDQUFsZ29MaXN0KG5mZEZvckluZm8sIEFzc2V0SUQuZnJvbVVpbnQ2NCh2YWx1ZVRvVmVyaWZ5KS5jcmVhdG9yKSwKCS8vICAgICAgICAgICAgICAgICAnc3BlY2lmaWVkIGFzc2V0IG11c3QgYmUgY3JlYXRlZCBieSBjcmVhdG9yIHRoYXQgaXMgb25lIG9mIHRoZSBsaW5rZWQgYWRkcmVzc2VzIGluIGFuIG5mZCcKCS8vICAgICAgICAgICAgICkKCWZyYW1lX2RpZyAtMiAvLyB2YWx1ZVRvVmVyaWZ5OiB1aW50NjQKCWFzc2V0X3BhcmFtc19nZXQgQXNzZXRDcmVhdG9yCglwb3AKCWZyYW1lX2RpZyA1IC8vIG5mZEZvckluZm86IHVpbnQ2NAoJY2FsbHN1YiBpc0FkZHJlc3NJbk5GRENBQWxnb0xpc3QKCgkvLyBzcGVjaWZpZWQgYXNzZXQgbXVzdCBiZSBjcmVhdGVkIGJ5IGNyZWF0b3IgdGhhdCBpcyBvbmUgb2YgdGhlIGxpbmtlZCBhZGRyZXNzZXMgaW4gYW4gbmZkCglhc3NlcnQKCippZjQ2X2VuZDoKCS8vICppZjQ3X2NvbmRpdGlvbgoJLy8gY29udHJhY3RzL3ZhbGlkYXRvclJlZ2lzdHJ5LmFsZ28udHM6MTI4MAoJLy8gdHlwZSA9PT0gR0FUSU5HX1RZUEVfU0VHTUVOVF9PRl9ORkQKCWZyYW1lX2RpZyAwIC8vIHR5cGU6IHVpbnQ4CglpbnQgNAoJPT0KCWJ6ICppZjQ3X2VuZAoKCS8vICppZjQ3X2NvbnNlcXVlbnQKCS8vIGNvbnRyYWN0cy92YWxpZGF0b3JSZWdpc3RyeS5hbGdvLnRzOjEyODIKCS8vIHVzZXJPZmZlcmVkTkZEQXBwSUQgPSB2YWx1ZVRvVmVyaWZ5CglmcmFtZV9kaWcgLTIgLy8gdmFsdWVUb1ZlcmlmeTogdWludDY0CglmcmFtZV9idXJ5IDYgLy8gdXNlck9mZmVyZWRORkRBcHBJRDogdWludDY0CgoJLy8gY29udHJhY3RzL3ZhbGlkYXRvclJlZ2lzdHJ5LmFsZ28udHM6MTI4MwoJLy8gYXNzZXJ0KHRoaXMuaXNORkRBcHBJRFZhbGlkKHVzZXJPZmZlcmVkTkZEQXBwSUQpLCAncHJvdmlkZWQgTkZEIG11c3QgYmUgdmFsaWQnKQoJZnJhbWVfZGlnIDYgLy8gdXNlck9mZmVyZWRORkRBcHBJRDogdWludDY0CgljYWxsc3ViIGlzTkZEQXBwSURWYWxpZAoKCS8vIHByb3ZpZGVkIE5GRCBtdXN0IGJlIHZhbGlkCglhc3NlcnQKCgkvLyBjb250cmFjdHMvdmFsaWRhdG9yUmVnaXN0cnkuYWxnby50czoxMjg2CgkvLyBhc3NlcnQoCgkvLyAgICAgICAgICAgICAgICAgcmF3Qnl0ZXMoQXBwSUQuZnJvbVVpbnQ2NCh1c2VyT2ZmZXJlZE5GREFwcElEKS5nbG9iYWxTdGF0ZSgnaS5vd25lci5hJykgYXMgQWRkcmVzcykgPT09CgkvLyAgICAgICAgICAgICAgICAgICAgIHJhd0J5dGVzKHN0YWtlcikgfHwgdGhpcy5pc0FkZHJlc3NJbk5GRENBQWxnb0xpc3QodXNlck9mZmVyZWRORkRBcHBJRCwgc3Rha2VyKSwKCS8vICAgICAgICAgICAgICAgICAicHJvdmlkZWQgbmZkIGZvciBlbnRyeSBpc24ndCBvd25lZCBvciBsaW5rZWQgdG8gdGhlIHN0YWtlciIKCS8vICAgICAgICAgICAgICkKCWZyYW1lX2RpZyA2IC8vIHVzZXJPZmZlcmVkTkZEQXBwSUQ6IHVpbnQ2NAoJYnl0ZSAweDY5MmU2Zjc3NmU2NTcyMmU2MSAvLyAiaS5vd25lci5hIgoJYXBwX2dsb2JhbF9nZXRfZXgKCWFzc2VydAoJZnJhbWVfZGlnIDEgLy8gc3Rha2VyOiBhZGRyZXNzCgk9PQoJZHVwCglibnogKnNraXBfb3I2CglmcmFtZV9kaWcgMSAvLyBzdGFrZXI6IGFkZHJlc3MKCWZyYW1lX2RpZyA2IC8vIHVzZXJPZmZlcmVkTkZEQXBwSUQ6IHVpbnQ2NAoJY2FsbHN1YiBpc0FkZHJlc3NJbk5GRENBQWxnb0xpc3QKCXx8Cgoqc2tpcF9vcjY6CgkvLyBwcm92aWRlZCBuZmQgZm9yIGVudHJ5IGlzbid0IG93bmVkIG9yIGxpbmtlZCB0byB0aGUgc3Rha2VyCglhc3NlcnQKCgkvLyBjb250cmFjdHMvdmFsaWRhdG9yUmVnaXN0cnkuYWxnby50czoxMjkzCgkvLyByZXF1aXJlZFBhcmVudEFwcElEID0gZXh0cmFjdFVpbnQ2NChnYXRlUmVxLCAwKQoJZnJhbWVfZGlnIDIgLy8gZ2F0ZVJlcTogYnl0ZVszMl0KCWludCAwCglleHRyYWN0X3VpbnQ2NAoJZnJhbWVfYnVyeSA3IC8vIHJlcXVpcmVkUGFyZW50QXBwSUQ6IHVpbnQ2NAoKCS8vIGNvbnRyYWN0cy92YWxpZGF0b3JSZWdpc3RyeS5hbGdvLnRzOjEyOTUKCS8vIGFzc2VydCgKCS8vICAgICAgICAgICAgICAgICAoQXBwSUQuZnJvbVVpbnQ2NCh1c2VyT2ZmZXJlZE5GREFwcElEKS5nbG9iYWxTdGF0ZSgnaS5wYXJlbnRBcHBJRCcpIGFzIHVpbnQ2NCkgPT09IHJlcXVpcmVkUGFyZW50QXBwSUQsCgkvLyAgICAgICAgICAgICAgICAgJ3NwZWNpZmllZCBuZmQgbXVzdCBiZSBhIHNlZ21lbnQgb2YgdGhlIG5mZCB0aGUgdmFsaWRhdG9yIHNwZWNpZmllZCBhcyBhIHJlcXVpcmVtZW50JwoJLy8gICAgICAgICAgICAgKQoJZnJhbWVfZGlnIDYgLy8gdXNlck9mZmVyZWRORkRBcHBJRDogdWludDY0CglieXRlIDB4NjkyZTcwNjE3MjY1NmU3NDQxNzA3MDQ5NDQgLy8gImkucGFyZW50QXBwSUQiCglhcHBfZ2xvYmFsX2dldF9leAoJYXNzZXJ0CglmcmFtZV9kaWcgNyAvLyByZXF1aXJlZFBhcmVudEFwcElEOiB1aW50NjQKCT09CgoJLy8gc3BlY2lmaWVkIG5mZCBtdXN0IGJlIGEgc2VnbWVudCBvZiB0aGUgbmZkIHRoZSB2YWxpZGF0b3Igc3BlY2lmaWVkIGFzIGEgcmVxdWlyZW1lbnQKCWFzc2VydAoKKmlmNDdfZW5kOgoJcmV0c3ViCgovLyBpc05GREFwcElEVmFsaWQobmZkQXBwSUQ6IHVpbnQ2NCk6IGJvb2xlYW4KLy8KLy8gQ2hlY2tzIGlmIHRoZSBnaXZlbiBORkQgQXBwIGlkIGlzIHZhbGlkLiAgVXNpbmcgb25seSB0aGUgQXBwIGlkIHRoZXJlJ3Mgbm8gdmFsaWRhdGlvbiBhZ2FpbnN0IHRoZSBuYW1lIChpZTogdGhhdCBuZmQgWCBpcyBuYW1lIFkpCi8vIFNvIGl0J3MgYXNzdW1lZCBmb3IgdGhlIGNhbGxlciwgdGhlIGFwcCBpZCBhbG9uZSBpcyBmaW5lLiAgVGhlIG5hbWUgaXMgZmV0Y2hlZCBmcm9tIHRoZSBzcGVjaWZpZWQgYXBwIGlkIGFuZCB0aGUgdHdvCi8vIHRvZ2V0aGVyIGFyZSB1c2VkIGZvciB2YWxpZGl0eSBjaGVjayBjYWxsIHRvIHRoZSBuZmQgcmVnaXN0cnkuCi8vCi8vIEBwYXJhbSB7dWludDY0fSBuZmRBcHBJRCAtIFRoZSBORkQgQXBwIGlkIHRvIHZlcmlmeS4KLy8KLy8gQHJldHVybnMge2Jvb2xlYW59IC0gUmV0dXJucyB0cnVlIGlmIHRoZSBORkQgQXBwIGlkIGlzIHZhbGlkLCBvdGhlcndpc2UgZmFsc2UuCmlzTkZEQXBwSURWYWxpZDoKCXByb3RvIDEgMQoKCS8vIFB1c2ggZW1wdHkgYnl0ZXMgYWZ0ZXIgdGhlIGZyYW1lIHBvaW50ZXIgdG8gcmVzZXJ2ZSBzcGFjZSBmb3IgbG9jYWwgdmFyaWFibGVzCglieXRlIDB4CgoJLy8gY29udHJhY3RzL3ZhbGlkYXRvclJlZ2lzdHJ5LmFsZ28udHM6MTMxMwoJLy8gdXNlck9mZmVyZWRORkROYW1lID0gQXBwSUQuZnJvbVVpbnQ2NChuZmRBcHBJRCkuZ2xvYmFsU3RhdGUoJ2kubmFtZScpIGFzIHN0cmluZwoJZnJhbWVfZGlnIC0xIC8vIG5mZEFwcElEOiB1aW50NjQKCWJ5dGUgMHg2OTJlNmU2MTZkNjUgLy8gImkubmFtZSIKCWFwcF9nbG9iYWxfZ2V0X2V4Cglhc3NlcnQKCWZyYW1lX2J1cnkgMCAvLyB1c2VyT2ZmZXJlZE5GRE5hbWU6IHN0cmluZwoKCS8vIGNvbnRyYWN0cy92YWxpZGF0b3JSZWdpc3RyeS5hbGdvLnRzOjEzMTUKCS8vIHNlbmRBcHBDYWxsKHsKCS8vICAgICAgICAgICAgIGFwcGxpY2F0aW9uSUQ6IEFwcElELmZyb21VaW50NjQodGhpcy5uZmRSZWdpc3RyeUFwcElkKSwKCS8vICAgICAgICAgICAgIGFwcGxpY2F0aW9uQXJnczogWydpc192YWxpZF9uZmRfYXBwaWQnLCB1c2VyT2ZmZXJlZE5GRE5hbWUsIGl0b2IobmZkQXBwSUQpXSwKCS8vICAgICAgICAgICAgIGFwcGxpY2F0aW9uczogW0FwcElELmZyb21VaW50NjQobmZkQXBwSUQpXSwKCS8vICAgICAgICAgfSkKCWl0eG5fYmVnaW4KCWludCBhcHBsCglpdHhuX2ZpZWxkIFR5cGVFbnVtCgoJLy8gY29udHJhY3RzL3ZhbGlkYXRvclJlZ2lzdHJ5LmFsZ28udHM6MTMxNgoJLy8gYXBwbGljYXRpb25JRDogQXBwSUQuZnJvbVVpbnQ2NCh0aGlzLm5mZFJlZ2lzdHJ5QXBwSWQpCglwdXNoaW50IFRNUExfbmZkUmVnaXN0cnlBcHBJZAoJaXR4bl9maWVsZCBBcHBsaWNhdGlvbklECgoJLy8gY29udHJhY3RzL3ZhbGlkYXRvclJlZ2lzdHJ5LmFsZ28udHM6MTMxNwoJLy8gYXBwbGljYXRpb25BcmdzOiBbJ2lzX3ZhbGlkX25mZF9hcHBpZCcsIHVzZXJPZmZlcmVkTkZETmFtZSwgaXRvYihuZmRBcHBJRCldCglieXRlIDB4Njk3MzVmNzY2MTZjNjk2NDVmNmU2NjY0NWY2MTcwNzA2OTY0IC8vICJpc192YWxpZF9uZmRfYXBwaWQiCglpdHhuX2ZpZWxkIEFwcGxpY2F0aW9uQXJncwoJZnJhbWVfZGlnIDAgLy8gdXNlck9mZmVyZWRORkROYW1lOiBzdHJpbmcKCWl0eG5fZmllbGQgQXBwbGljYXRpb25BcmdzCglmcmFtZV9kaWcgLTEgLy8gbmZkQXBwSUQ6IHVpbnQ2NAoJaXRvYgoJaXR4bl9maWVsZCBBcHBsaWNhdGlvbkFyZ3MKCgkvLyBjb250cmFjdHMvdmFsaWRhdG9yUmVnaXN0cnkuYWxnby50czoxMzE4CgkvLyBhcHBsaWNhdGlvbnM6IFtBcHBJRC5mcm9tVWludDY0KG5mZEFwcElEKV0KCWZyYW1lX2RpZyAtMSAvLyBuZmRBcHBJRDogdWludDY0CglpdHhuX2ZpZWxkIEFwcGxpY2F0aW9ucwoKCS8vIEZlZSBmaWVsZCBub3Qgc2V0LCBkZWZhdWx0aW5nIHRvIDAKCWludCAwCglpdHhuX2ZpZWxkIEZlZQoKCS8vIFN1Ym1pdCBpbm5lciB0cmFuc2FjdGlvbgoJaXR4bl9zdWJtaXQKCgkvLyBjb250cmFjdHMvdmFsaWRhdG9yUmVnaXN0cnkuYWxnby50czoxMzIwCgkvLyByZXR1cm4gYnRvaSh0aGlzLml0eG4ubGFzdExvZykgPT09IDE7CglpdHhuIExhc3RMb2cKCWJ0b2kKCWludCAxCgk9PQoKCS8vIHNldCB0aGUgc3Vicm91dGluZSByZXR1cm4gdmFsdWUKCWZyYW1lX2J1cnkgMAoJcmV0c3ViCgovLyBpc0FkZHJlc3NJbk5GRENBQWxnb0xpc3QobmZkQXBwSUQ6IHVpbnQ2NCwgYWRkclRvRmluZDogQWRkcmVzcyk6IGJvb2xlYW4KLy8KLy8gQ2hlY2tzIGlmIHRoZSBzcGVjaWZpZWQgYWRkcmVzcyBpcyBwcmVzZW50IGluIGFuIE5GRHMgbGlzdCBvZiB2ZXJpZmllZCBhZGRyZXNzZXMuCi8vIFRoZSBORkQgaXMgYXNzdW1lZCB0byBoYXZlIGFscmVhZHkgYmVlbiB2YWxpZGF0ZWQgYXMgb2ZmaWNpYWwuCi8vCi8vIEBwYXJhbSB7dWludDY0fSBuZmRBcHBJRCAtIFRoZSBORkQgYXBwbGljYXRpb24gaWQuCi8vIEBwYXJhbSB7QWRkcmVzc30gYWRkclRvRmluZCAtIFRoZSBhZGRyZXNzIHRvIGZpbmQgaW4gdGhlIHYuY2FBbGdvLjAuYXMgcHJvcGVydHkKLy8gQHJldHVybiB7Ym9vbGVhbn0gLSBgdHJ1ZWAgaWYgdGhlIGFkZHJlc3MgaXMgcHJlc2VudCwgYGZhbHNlYCBvdGhlcndpc2UuCmlzQWRkcmVzc0luTkZEQ0FBbGdvTGlzdDoKCXByb3RvIDIgMQoKCS8vIFB1c2ggZW1wdHkgYnl0ZXMgYWZ0ZXIgdGhlIGZyYW1lIHBvaW50ZXIgdG8gcmVzZXJ2ZSBzcGFjZSBmb3IgbG9jYWwgdmFyaWFibGVzCglieXRlIDB4CglkdXBuIDIKCgkvLyBjb250cmFjdHMvdmFsaWRhdG9yUmVnaXN0cnkuYWxnby50czoxMzMyCgkvLyBzZW5kQXBwQ2FsbCh7CgkvLyAgICAgICAgICAgICBhcHBsaWNhdGlvbklEOiBBcHBJRC5mcm9tVWludDY0KG5mZEFwcElEKSwKCS8vICAgICAgICAgICAgIGFwcGxpY2F0aW9uQXJnczogWydyZWFkX3Byb3BlcnR5JywgJ3YuY2FBbGdvLjAuYXMnXSwKCS8vICAgICAgICAgfSkKCWl0eG5fYmVnaW4KCWludCBhcHBsCglpdHhuX2ZpZWxkIFR5cGVFbnVtCgoJLy8gY29udHJhY3RzL3ZhbGlkYXRvclJlZ2lzdHJ5LmFsZ28udHM6MTMzMwoJLy8gYXBwbGljYXRpb25JRDogQXBwSUQuZnJvbVVpbnQ2NChuZmRBcHBJRCkKCWZyYW1lX2RpZyAtMSAvLyBuZmRBcHBJRDogdWludDY0CglpdHhuX2ZpZWxkIEFwcGxpY2F0aW9uSUQKCgkvLyBjb250cmFjdHMvdmFsaWRhdG9yUmVnaXN0cnkuYWxnby50czoxMzM0CgkvLyBhcHBsaWNhdGlvbkFyZ3M6IFsncmVhZF9wcm9wZXJ0eScsICd2LmNhQWxnby4wLmFzJ10KCWJ5dGUgMHg3MjY1NjE2NDVmNzA3MjZmNzA2NTcyNzQ3OSAvLyAicmVhZF9wcm9wZXJ0eSIKCWl0eG5fZmllbGQgQXBwbGljYXRpb25BcmdzCglieXRlIDB4NzYyZTYzNjE0MTZjNjc2ZjJlMzAyZTYxNzMgLy8gInYuY2FBbGdvLjAuYXMiCglpdHhuX2ZpZWxkIEFwcGxpY2F0aW9uQXJncwoKCS8vIEZlZSBmaWVsZCBub3Qgc2V0LCBkZWZhdWx0aW5nIHRvIDAKCWludCAwCglpdHhuX2ZpZWxkIEZlZQoKCS8vIFN1Ym1pdCBpbm5lciB0cmFuc2FjdGlvbgoJaXR4bl9zdWJtaXQKCgkvLyBjb250cmFjdHMvdmFsaWRhdG9yUmVnaXN0cnkuYWxnby50czoxMzM2CgkvLyBjYUFsZ29EYXRhID0gdGhpcy5pdHhuLmxhc3RMb2cKCWl0eG4gTGFzdExvZwoJZnJhbWVfYnVyeSAwIC8vIGNhQWxnb0RhdGE6IGJ5dGVbXQoKCS8vIGNvbnRyYWN0cy92YWxpZGF0b3JSZWdpc3RyeS5hbGdvLnRzOjEzMzcKCS8vIGZvciAobGV0IGkgPSAwOyBpIDwgY2FBbGdvRGF0YS5sZW5ndGg7IGkgKz0gMzIpCglpbnQgMAoJZnJhbWVfYnVyeSAxIC8vIGk6IHVpbnQ2NAoKKmZvcl8xMDoKCS8vIGNvbnRyYWN0cy92YWxpZGF0b3JSZWdpc3RyeS5hbGdvLnRzOjEzMzcKCS8vIGkgPCBjYUFsZ29EYXRhLmxlbmd0aAoJZnJhbWVfZGlnIDEgLy8gaTogdWludDY0CglmcmFtZV9kaWcgMCAvLyBjYUFsZ29EYXRhOiBieXRlW10KCWxlbgoJPAoJYnogKmZvcl8xMF9lbmQKCgkvLyBjb250cmFjdHMvdmFsaWRhdG9yUmVnaXN0cnkuYWxnby50czoxMzM4CgkvLyBhZGRyID0gZXh0cmFjdDMoY2FBbGdvRGF0YSwgaSwgMzIpCglmcmFtZV9kaWcgMCAvLyBjYUFsZ29EYXRhOiBieXRlW10KCWZyYW1lX2RpZyAxIC8vIGk6IHVpbnQ2NAoJaW50IDMyCglleHRyYWN0MwoJZnJhbWVfYnVyeSAyIC8vIGFkZHI6IGJ5dGVbXQoKCS8vICppZjQ4X2NvbmRpdGlvbgoJLy8gY29udHJhY3RzL3ZhbGlkYXRvclJlZ2lzdHJ5LmFsZ28udHM6MTMzOQoJLy8gYWRkciAhPT0gcmF3Qnl0ZXMoZ2xvYmFscy56ZXJvQWRkcmVzcykgJiYgYWRkciA9PT0gcmF3Qnl0ZXMoYWRkclRvRmluZCkKCWZyYW1lX2RpZyAyIC8vIGFkZHI6IGJ5dGVbXQoJZ2xvYmFsIFplcm9BZGRyZXNzCgkhPQoJZHVwCglieiAqc2tpcF9hbmQ5CglmcmFtZV9kaWcgMiAvLyBhZGRyOiBieXRlW10KCWZyYW1lX2RpZyAtMiAvLyBhZGRyVG9GaW5kOiBBZGRyZXNzCgk9PQoJJiYKCipza2lwX2FuZDk6CglieiAqaWY0OF9lbmQKCgkvLyAqaWY0OF9jb25zZXF1ZW50CgkvLyBjb250cmFjdHMvdmFsaWRhdG9yUmVnaXN0cnkuYWxnby50czoxMzQwCgkvLyByZXR1cm4gdHJ1ZTsKCWludCAxCgoJLy8gc2V0IHRoZSBzdWJyb3V0aW5lIHJldHVybiB2YWx1ZQoJZnJhbWVfYnVyeSAwCgoJLy8gcG9wIGFsbCBsb2NhbCB2YXJpYWJsZXMgZnJvbSB0aGUgc3RhY2sKCXBvcG4gMgoJcmV0c3ViCgoqaWY0OF9lbmQ6CgoqZm9yXzEwX2NvbnRpbnVlOgoJLy8gY29udHJhY3RzL3ZhbGlkYXRvclJlZ2lzdHJ5LmFsZ28udHM6MTMzNwoJLy8gaSArPSAzMgoJZnJhbWVfZGlnIDEgLy8gaTogdWludDY0CglpbnQgMzIKCSsKCWZyYW1lX2J1cnkgMSAvLyBpOiB1aW50NjQKCWIgKmZvcl8xMAoKKmZvcl8xMF9lbmQ6CgkvLyBjb250cmFjdHMvdmFsaWRhdG9yUmVnaXN0cnkuYWxnby50czoxMzQzCgkvLyByZXR1cm4gZmFsc2U7CglpbnQgMAoKCS8vIHNldCB0aGUgc3Vicm91dGluZSByZXR1cm4gdmFsdWUKCWZyYW1lX2J1cnkgMAoKCS8vIHBvcCBhbGwgbG9jYWwgdmFyaWFibGVzIGZyb20gdGhlIHN0YWNrCglwb3BuIDIKCXJldHN1YgoKLy8gbWF4QWxnb0FsbG93ZWRQZXJQb29sKCk6IHVpbnQ2NAovLwovLyBSZXR1cm5zIHRoZSBNQVhJTVVNIGFsbG93ZWQgc3Rha2UgcGVyIHBvb2wgYW5kIHN0aWxsIHJlY2VpdmUgaW5jZW50aXZlcyAtIHdlJ2xsIHRyZWF0IHRoaXMgYXMgdGhlICdtYXggcGVyIHBvb2wnCm1heEFsZ29BbGxvd2VkUGVyUG9vbDoKCXByb3RvIDAgMQoKCS8vIGNvbnRyYWN0cy92YWxpZGF0b3JSZWdpc3RyeS5hbGdvLnRzOjEzNTEKCS8vIHJldHVybiA3MF8wMDBfMDAwXzAwMF8wMDA7CglpbnQgNzBfMDAwXzAwMF8wMDBfMDAwCglyZXRzdWIKCi8vIGFsZ29TYXR1cmF0aW9uTGV2ZWwoKTogdWludDY0Ci8vCi8vIFJldHVybnMgdGhlIG1heGltdW0gYWxsb3dlZCBzdGFrZSBwZXIgdmFsaWRhdG9yIGJhc2VkIG9uIGEgcGVyY2VudGFnZSBvZiBhbGwgY3VycmVudCBvbmxpbmUgc3Rha2UgYmVmb3JlCi8vIHRoZSB2YWxpZGF0b3IgaXMgY29uc2lkZXJlZCBzYXR1cmF0ZWQgLSB3aGVyZSByZXdhcmRzIGFyZSBkaW1pbmlzaGVkLgovLyBOT1RFOiB0aGlzIGZ1bmN0aW9uIGlzIGRlZmluZWQgdHdpY2UgLSBoZXJlIGFuZCBpbiBzdGFraW5nIHBvb2wgY29udHJhY3QuICBCb3RoIG11c3QgYmUgaWRlbnRpY2FsLgphbGdvU2F0dXJhdGlvbkxldmVsOgoJcHJvdG8gMCAxCgoJLy8gUHVzaCBlbXB0eSBieXRlcyBhZnRlciB0aGUgZnJhbWUgcG9pbnRlciB0byByZXNlcnZlIHNwYWNlIGZvciBsb2NhbCB2YXJpYWJsZXMKCWJ5dGUgMHgKCgkvLyBjb250cmFjdHMvdmFsaWRhdG9yUmVnaXN0cnkuYWxnby50czoxMzYwCgkvLyBvbmxpbmUgPSB0aGlzLmdldEN1cnJlbnRPbmxpbmVTdGFrZSgpCgljYWxsc3ViIGdldEN1cnJlbnRPbmxpbmVTdGFrZQoJZnJhbWVfYnVyeSAwIC8vIG9ubGluZTogdWludDY0CgoJLy8gY29udHJhY3RzL3ZhbGlkYXRvclJlZ2lzdHJ5LmFsZ28udHM6MTM2MgoJLy8gcmV0dXJuIHdpZGVSYXRpbyhbb25saW5lLCBNQVhfVkFMSURBVE9SX1NPRlRfUENUX09GX09OTElORV8xREVDSU1BTF0sIFsxMDAwXSk7CglmcmFtZV9kaWcgMCAvLyBvbmxpbmU6IHVpbnQ2NAoJaW50IDEwMAoJbXVsdwoJaW50IDAKCWludCAxMDAwCglkaXZtb2R3Cglwb3AKCXBvcAoJc3dhcAoJIQoJYXNzZXJ0CgoJLy8gc2V0IHRoZSBzdWJyb3V0aW5lIHJldHVybiB2YWx1ZQoJZnJhbWVfYnVyeSAwCglyZXRzdWIKCi8vIG1heEFsbG93ZWRTdGFrZSgpOiB1aW50NjQKLy8KLy8gUmV0dXJucyB0aGUgTUFYSU1VTSBhbGxvd2VkIHN0YWtlIHBlciB2YWxpZGF0b3IgYmFzZWQgb24gYSBwZXJjZW50YWdlIG9mIGFsbCBjdXJyZW50IG9ubGluZSBzdGFrZS4KLy8gQWRkaW5nIHN0YWtlIGlzIGNvbXBsZXRlbHkgYmxvY2tlZCBhdCB0aGlzIGFtb3VudC4KbWF4QWxsb3dlZFN0YWtlOgoJcHJvdG8gMCAxCgoJLy8gUHVzaCBlbXB0eSBieXRlcyBhZnRlciB0aGUgZnJhbWUgcG9pbnRlciB0byByZXNlcnZlIHNwYWNlIGZvciBsb2NhbCB2YXJpYWJsZXMKCWJ5dGUgMHgKCgkvLyBjb250cmFjdHMvdmFsaWRhdG9yUmVnaXN0cnkuYWxnby50czoxMzcwCgkvLyBvbmxpbmUgPSB0aGlzLmdldEN1cnJlbnRPbmxpbmVTdGFrZSgpCgljYWxsc3ViIGdldEN1cnJlbnRPbmxpbmVTdGFrZQoJZnJhbWVfYnVyeSAwIC8vIG9ubGluZTogdWludDY0CgoJLy8gY29udHJhY3RzL3ZhbGlkYXRvclJlZ2lzdHJ5LmFsZ28udHM6MTM3MgoJLy8gcmV0dXJuIHdpZGVSYXRpbyhbb25saW5lLCBNQVhfVkFMSURBVE9SX0hBUkRfUENUX09GX09OTElORV8xREVDSU1BTF0sIFsxMDAwXSk7CglmcmFtZV9kaWcgMCAvLyBvbmxpbmU6IHVpbnQ2NAoJaW50IDE1MAoJbXVsdwoJaW50IDAKCWludCAxMDAwCglkaXZtb2R3Cglwb3AKCXBvcAoJc3dhcAoJIQoJYXNzZXJ0CgoJLy8gc2V0IHRoZSBzdWJyb3V0aW5lIHJldHVybiB2YWx1ZQoJZnJhbWVfYnVyeSAwCglyZXRzdWIKCi8vIGdldEN1cnJlbnRPbmxpbmVTdGFrZSgpOiB1aW50NjQKZ2V0Q3VycmVudE9ubGluZVN0YWtlOgoJcHJvdG8gMCAxCgoJLy8gY29udHJhY3RzL3ZhbGlkYXRvclJlZ2lzdHJ5LmFsZ28udHM6MTM3NwoJLy8gcmV0dXJuIDJfMDAwXzAwMF8wMDBfMDAwXzAwMDsKCWludCAyXzAwMF8wMDBfMDAwXzAwMF8wMDAKCXJldHN1YgoKLy8gbWluQmFsYW5jZUZvckFjY291bnQoY29udHJhY3RzOiB1aW50NjQsIGV4dHJhUGFnZXM6IHVpbnQ2NCwgYXNzZXRzOiB1aW50NjQsIGxvY2FsSW50czogdWludDY0LCBsb2NhbEJ5dGVzOiB1aW50NjQsIGdsb2JhbEludHM6IHVpbnQ2NCwgZ2xvYmFsQnl0ZXM6IHVpbnQ2NCk6IHVpbnQ2NAptaW5CYWxhbmNlRm9yQWNjb3VudDoKCXByb3RvIDcgMQoKCS8vIFB1c2ggZW1wdHkgYnl0ZXMgYWZ0ZXIgdGhlIGZyYW1lIHBvaW50ZXIgdG8gcmVzZXJ2ZSBzcGFjZSBmb3IgbG9jYWwgdmFyaWFibGVzCglieXRlIDB4CgoJLy8gY29udHJhY3RzL3ZhbGlkYXRvclJlZ2lzdHJ5LmFsZ28udHM6MTM4OQoJLy8gbWluQmFsID0gQUxHT1JBTkRfQUNDT1VOVF9NSU5fQkFMQU5DRQoJaW50IDEwMDAwMAoJZnJhbWVfYnVyeSAwIC8vIG1pbkJhbDogdWludDY0CgoJLy8gY29udHJhY3RzL3ZhbGlkYXRvclJlZ2lzdHJ5LmFsZ28udHM6MTM5MAoJLy8gbWluQmFsICs9IGNvbnRyYWN0cyAqIEFQUExJQ0FUSU9OX0JBU0VfRkVFCglmcmFtZV9kaWcgMCAvLyBtaW5CYWw6IHVpbnQ2NAoJZnJhbWVfZGlnIC0xIC8vIGNvbnRyYWN0czogdWludDY0CglpbnQgMTAwMDAwCgkqCgkrCglmcmFtZV9idXJ5IDAgLy8gbWluQmFsOiB1aW50NjQKCgkvLyBjb250cmFjdHMvdmFsaWRhdG9yUmVnaXN0cnkuYWxnby50czoxMzkxCgkvLyBtaW5CYWwgKz0gZXh0cmFQYWdlcyAqIEFQUExJQ0FUSU9OX0JBU0VfRkVFCglmcmFtZV9kaWcgMCAvLyBtaW5CYWw6IHVpbnQ2NAoJZnJhbWVfZGlnIC0yIC8vIGV4dHJhUGFnZXM6IHVpbnQ2NAoJaW50IDEwMDAwMAoJKgoJKwoJZnJhbWVfYnVyeSAwIC8vIG1pbkJhbDogdWludDY0CgoJLy8gY29udHJhY3RzL3ZhbGlkYXRvclJlZ2lzdHJ5LmFsZ28udHM6MTM5MgoJLy8gbWluQmFsICs9IGFzc2V0cyAqIEFTU0VUX0hPTERJTkdfRkVFCglmcmFtZV9kaWcgMCAvLyBtaW5CYWw6IHVpbnQ2NAoJZnJhbWVfZGlnIC0zIC8vIGFzc2V0czogdWludDY0CglpbnQgMTAwMDAwCgkqCgkrCglmcmFtZV9idXJ5IDAgLy8gbWluQmFsOiB1aW50NjQKCgkvLyBjb250cmFjdHMvdmFsaWRhdG9yUmVnaXN0cnkuYWxnby50czoxMzkzCgkvLyBtaW5CYWwgKz0gbG9jYWxJbnRzICogU1NDX1ZBTFVFX1VJTlQKCWZyYW1lX2RpZyAwIC8vIG1pbkJhbDogdWludDY0CglmcmFtZV9kaWcgLTQgLy8gbG9jYWxJbnRzOiB1aW50NjQKCWludCAyODUwMAoJKgoJKwoJZnJhbWVfYnVyeSAwIC8vIG1pbkJhbDogdWludDY0CgoJLy8gY29udHJhY3RzL3ZhbGlkYXRvclJlZ2lzdHJ5LmFsZ28udHM6MTM5NAoJLy8gbWluQmFsICs9IGdsb2JhbEludHMgKiBTU0NfVkFMVUVfVUlOVAoJZnJhbWVfZGlnIDAgLy8gbWluQmFsOiB1aW50NjQKCWZyYW1lX2RpZyAtNiAvLyBnbG9iYWxJbnRzOiB1aW50NjQKCWludCAyODUwMAoJKgoJKwoJZnJhbWVfYnVyeSAwIC8vIG1pbkJhbDogdWludDY0CgoJLy8gY29udHJhY3RzL3ZhbGlkYXRvclJlZ2lzdHJ5LmFsZ28udHM6MTM5NQoJLy8gbWluQmFsICs9IGxvY2FsQnl0ZXMgKiBTU0NfVkFMVUVfQllURVMKCWZyYW1lX2RpZyAwIC8vIG1pbkJhbDogdWludDY0CglmcmFtZV9kaWcgLTUgLy8gbG9jYWxCeXRlczogdWludDY0CglpbnQgNTAwMDAKCSoKCSsKCWZyYW1lX2J1cnkgMCAvLyBtaW5CYWw6IHVpbnQ2NAoKCS8vIGNvbnRyYWN0cy92YWxpZGF0b3JSZWdpc3RyeS5hbGdvLnRzOjEzOTYKCS8vIG1pbkJhbCArPSBnbG9iYWxCeXRlcyAqIFNTQ19WQUxVRV9CWVRFUwoJZnJhbWVfZGlnIDAgLy8gbWluQmFsOiB1aW50NjQKCWZyYW1lX2RpZyAtNyAvLyBnbG9iYWxCeXRlczogdWludDY0CglpbnQgNTAwMDAKCSoKCSsKCWZyYW1lX2J1cnkgMCAvLyBtaW5CYWw6IHVpbnQ2NAoKCS8vIGNvbnRyYWN0cy92YWxpZGF0b3JSZWdpc3RyeS5hbGdvLnRzOjEzOTcKCS8vIHJldHVybiBtaW5CYWw7CglmcmFtZV9kaWcgMCAvLyBtaW5CYWw6IHVpbnQ2NAoKCS8vIHNldCB0aGUgc3Vicm91dGluZSByZXR1cm4gdmFsdWUKCWZyYW1lX2J1cnkgMAoJcmV0c3ViCgovLyBjb3N0Rm9yQm94U3RvcmFnZSh0b3RhbE51bUJ5dGVzOiB1aW50NjQpOiB1aW50NjQKY29zdEZvckJveFN0b3JhZ2U6Cglwcm90byAxIDEKCgkvLyBjb250cmFjdHMvdmFsaWRhdG9yUmVnaXN0cnkuYWxnby50czoxNDA0CgkvLyByZXR1cm4gU0NCT1hfUEVSQk9YICsgdG90YWxOdW1CeXRlcyAqIFNDQk9YX1BFUkJZVEU7CglpbnQgMjUwMAoJZnJhbWVfZGlnIC0xIC8vIHRvdGFsTnVtQnl0ZXM6IHVpbnQ2NAoJaW50IDQwMAoJKgoJKwoJcmV0c3ViCgoqY3JlYXRlX05vT3A6CgltZXRob2QgImNyZWF0ZUFwcGxpY2F0aW9uKHVpbnQ2NCl2b2lkIgoJdHhuYSBBcHBsaWNhdGlvbkFyZ3MgMAoJbWF0Y2ggKmFiaV9yb3V0ZV9jcmVhdGVBcHBsaWNhdGlvbgoJZXJyCgoqY2FsbF9Ob09wOgoJbWV0aG9kICJnYXMoKXZvaWQiCgltZXRob2QgImdldE1ickFtb3VudHMoKSh1aW50NjQsdWludDY0LHVpbnQ2NCx1aW50NjQpIgoJbWV0aG9kICJnZXRQcm90b2NvbENvbnN0cmFpbnRzKCkodWludDY0LHVpbnQ2NCx1aW50NjQsdWludDY0LHVpbnQ2NCx1aW50NjQsdWludDY0LHVpbnQ2NCx1aW50NjQsdWludDY0LHVpbnQ2NCkiCgltZXRob2QgImdldE51bVZhbGlkYXRvcnMoKXVpbnQ2NCIKCW1ldGhvZCAiZ2V0VmFsaWRhdG9yQ29uZmlnKHVpbnQ2NCkodWludDY0LGFkZHJlc3MsYWRkcmVzcyx1aW50NjQsdWludDgsYnl0ZVszMl0sdWludDY0LHVpbnQ2NCx1aW50NjQsdWludDE2LHVpbnQzMixhZGRyZXNzLHVpbnQ2NCx1aW50NjQsdWludDgsdWludDY0LHVpbnQ2NCkiCgltZXRob2QgImdldFZhbGlkYXRvclN0YXRlKHVpbnQ2NCkodWludDE2LHVpbnQ2NCx1aW50NjQsdWludDY0KSIKCW1ldGhvZCAiZ2V0VmFsaWRhdG9yT3duZXJBbmRNYW5hZ2VyKHVpbnQ2NCkoYWRkcmVzcyxhZGRyZXNzKSIKCW1ldGhvZCAiZ2V0UG9vbHModWludDY0KSh1aW50NjQsdWludDE2LHVpbnQ2NClbXSIKCW1ldGhvZCAiZ2V0UG9vbEFwcElkKHVpbnQ2NCx1aW50NjQpdWludDY0IgoJbWV0aG9kICJnZXRQb29sSW5mbygodWludDY0LHVpbnQ2NCx1aW50NjQpKSh1aW50NjQsdWludDE2LHVpbnQ2NCkiCgltZXRob2QgImdldEN1ck1heFN0YWtlUGVyUG9vbCh1aW50NjQpdWludDY0IgoJbWV0aG9kICJkb2VzU3Rha2VyTmVlZFRvUGF5TUJSKGFkZHJlc3MpYm9vbCIKCW1ldGhvZCAiZ2V0U3Rha2VkUG9vbHNGb3JBY2NvdW50KGFkZHJlc3MpKHVpbnQ2NCx1aW50NjQsdWludDY0KVtdIgoJbWV0aG9kICJnZXRUb2tlblBheW91dFJhdGlvKHVpbnQ2NCkodWludDY0WzI0XSx1aW50NjQpIgoJbWV0aG9kICJnZXROb2RlUG9vbEFzc2lnbm1lbnRzKHVpbnQ2NCkoKHVpbnQ2NFszXSlbOF0pIgoJbWV0aG9kICJnZXRORkRSZWdpc3RyeUlEKCl1aW50NjQiCgltZXRob2QgImFkZFZhbGlkYXRvcihwYXksc3RyaW5nLCh1aW50NjQsYWRkcmVzcyxhZGRyZXNzLHVpbnQ2NCx1aW50OCxieXRlWzMyXSx1aW50NjQsdWludDY0LHVpbnQ2NCx1aW50MTYsdWludDMyLGFkZHJlc3MsdWludDY0LHVpbnQ2NCx1aW50OCx1aW50NjQsdWludDY0KSl1aW50NjQiCgltZXRob2QgImNoYW5nZVZhbGlkYXRvck1hbmFnZXIodWludDY0LGFkZHJlc3Mpdm9pZCIKCW1ldGhvZCAiY2hhbmdlVmFsaWRhdG9yU3Vuc2V0SW5mbyh1aW50NjQsdWludDY0LHVpbnQ2NCl2b2lkIgoJbWV0aG9kICJjaGFuZ2VWYWxpZGF0b3JORkQodWludDY0LHVpbnQ2NCxzdHJpbmcpdm9pZCIKCW1ldGhvZCAiY2hhbmdlVmFsaWRhdG9yQ29tbWlzc2lvbkFkZHJlc3ModWludDY0LGFkZHJlc3Mpdm9pZCIKCW1ldGhvZCAiY2hhbmdlVmFsaWRhdG9yUmV3YXJkSW5mbyh1aW50NjQsdWludDgsYnl0ZVszMl0sdWludDY0LHVpbnQ2NCl2b2lkIgoJbWV0aG9kICJhZGRQb29sKHBheSx1aW50NjQsdWludDY0KSh1aW50NjQsdWludDY0LHVpbnQ2NCkiCgltZXRob2QgImFkZFN0YWtlKHBheSx1aW50NjQsdWludDY0KSh1aW50NjQsdWludDY0LHVpbnQ2NCkiCgltZXRob2QgInNldFRva2VuUGF5b3V0UmF0aW8odWludDY0KSh1aW50NjRbMjRdLHVpbnQ2NCkiCgltZXRob2QgInN0YWtlVXBkYXRlZFZpYVJld2FyZHMoKHVpbnQ2NCx1aW50NjQsdWludDY0KSx1aW50NjQsdWludDY0KXZvaWQiCgltZXRob2QgInN0YWtlUmVtb3ZlZCgodWludDY0LHVpbnQ2NCx1aW50NjQpLGFkZHJlc3MsdWludDY0LHVpbnQ2NCxib29sKXZvaWQiCgltZXRob2QgImZpbmRQb29sRm9yU3Rha2VyKHVpbnQ2NCxhZGRyZXNzLHVpbnQ2NCkoKHVpbnQ2NCx1aW50NjQsdWludDY0KSxib29sLGJvb2wpIgoJbWV0aG9kICJtb3ZlUG9vbFRvTm9kZSh1aW50NjQsdWludDY0LHVpbnQ2NCl2b2lkIgoJdHhuYSBBcHBsaWNhdGlvbkFyZ3MgMAoJbWF0Y2ggKmFiaV9yb3V0ZV9nYXMgKmFiaV9yb3V0ZV9nZXRNYnJBbW91bnRzICphYmlfcm91dGVfZ2V0UHJvdG9jb2xDb25zdHJhaW50cyAqYWJpX3JvdXRlX2dldE51bVZhbGlkYXRvcnMgKmFiaV9yb3V0ZV9nZXRWYWxpZGF0b3JDb25maWcgKmFiaV9yb3V0ZV9nZXRWYWxpZGF0b3JTdGF0ZSAqYWJpX3JvdXRlX2dldFZhbGlkYXRvck93bmVyQW5kTWFuYWdlciAqYWJpX3JvdXRlX2dldFBvb2xzICphYmlfcm91dGVfZ2V0UG9vbEFwcElkICphYmlfcm91dGVfZ2V0UG9vbEluZm8gKmFiaV9yb3V0ZV9nZXRDdXJNYXhTdGFrZVBlclBvb2wgKmFiaV9yb3V0ZV9kb2VzU3Rha2VyTmVlZFRvUGF5TUJSICphYmlfcm91dGVfZ2V0U3Rha2VkUG9vbHNGb3JBY2NvdW50ICphYmlfcm91dGVfZ2V0VG9rZW5QYXlvdXRSYXRpbyAqYWJpX3JvdXRlX2dldE5vZGVQb29sQXNzaWdubWVudHMgKmFiaV9yb3V0ZV9nZXRORkRSZWdpc3RyeUlEICphYmlfcm91dGVfYWRkVmFsaWRhdG9yICphYmlfcm91dGVfY2hhbmdlVmFsaWRhdG9yTWFuYWdlciAqYWJpX3JvdXRlX2NoYW5nZVZhbGlkYXRvclN1bnNldEluZm8gKmFiaV9yb3V0ZV9jaGFuZ2VWYWxpZGF0b3JORkQgKmFiaV9yb3V0ZV9jaGFuZ2VWYWxpZGF0b3JDb21taXNzaW9uQWRkcmVzcyAqYWJpX3JvdXRlX2NoYW5nZVZhbGlkYXRvclJld2FyZEluZm8gKmFiaV9yb3V0ZV9hZGRQb29sICphYmlfcm91dGVfYWRkU3Rha2UgKmFiaV9yb3V0ZV9zZXRUb2tlblBheW91dFJhdGlvICphYmlfcm91dGVfc3Rha2VVcGRhdGVkVmlhUmV3YXJkcyAqYWJpX3JvdXRlX3N0YWtlUmVtb3ZlZCAqYWJpX3JvdXRlX2ZpbmRQb29sRm9yU3Rha2VyICphYmlfcm91dGVfbW92ZVBvb2xUb05vZGUKCWVycg==", + "clear": "I3ByYWdtYSB2ZXJzaW9uIDEw" + }, + "contract": { + "name": "ValidatorRegistry", + "desc": "", + "methods": [ + { + "name": "createApplication", + "args": [ + { + "name": "poolTemplateAppId", + "type": "uint64" + } + ], + "returns": { + "type": "void" + } + }, + { + "name": "gas", + "desc": "gas is a dummy no-op call that can be used to pool-up resource references and opcode cost", + "args": [], + "returns": { + "type": "void" + } + }, + { + "name": "getMbrAmounts", + "desc": "Returns the MBR amounts needed for various actions:[addValidatorMbr: uint64 - mbr needed to add a new validator - paid to validator contractaddPoolMbr: uint64 - mbr needed to add a new pool - paid to validatorpoolInitMbr: uint64 - mbr needed to initStorage() of pool - paid to pool itselfaddStakerMbr: uint64 - mbr staker needs to add to first staking payment (stays w/ validator)]", + "args": [], + "returns": { + "type": "(uint64,uint64,uint64,uint64)" + } + }, + { + "name": "getProtocolConstraints", + "desc": "Returns the protocol constraints so that UIs can limit what users specify for validator configuration parameters.", + "args": [], + "returns": { + "type": "(uint64,uint64,uint64,uint64,uint64,uint64,uint64,uint64,uint64,uint64,uint64)" + } + }, + { + "name": "getNumValidators", + "desc": "Returns the current number of validators", + "args": [], + "returns": { + "type": "uint64" + } + }, + { + "name": "getValidatorConfig", + "args": [ + { + "name": "validatorId", + "type": "uint64" + } + ], + "returns": { + "type": "(uint64,address,address,uint64,uint8,byte[32],uint64,uint64,uint64,uint16,uint32,address,uint64,uint64,uint8,uint64,uint64)" + } + }, + { + "name": "getValidatorState", + "args": [ + { + "name": "validatorId", + "type": "uint64" + } + ], + "returns": { + "type": "(uint16,uint64,uint64,uint64)" + } + }, + { + "name": "getValidatorOwnerAndManager", + "args": [ + { + "name": "validatorId", + "type": "uint64" + } + ], + "returns": { + "type": "(address,address)" + } + }, + { + "name": "getPools", + "desc": "Return list of all pools for this validator.", + "args": [ + { + "name": "validatorId", + "type": "uint64", + "desc": "@return{PoolInfo[]}- array of poolsNot callable from other contracts because>1K return but can be called w/ simulate which bumps log returns" + } + ], + "returns": { + "type": "(uint64,uint16,uint64)[]" + } + }, + { + "name": "getPoolAppId", + "args": [ + { + "name": "validatorId", + "type": "uint64" + }, + { + "name": "poolId", + "type": "uint64" + } + ], + "returns": { + "type": "uint64" + } + }, + { + "name": "getPoolInfo", + "args": [ + { + "name": "poolKey", + "type": "(uint64,uint64,uint64)" + } + ], + "returns": { + "type": "(uint64,uint16,uint64)" + } + }, + { + "name": "getCurMaxStakePerPool", + "desc": "Calculate the maximum stake per pool for a given validator.Normally this would be maxAlgoPerPool, but it should also never go above MaxAllowedStake / numPools soas pools are added the max allowed per pool can reduce.", + "args": [ + { + "name": "validatorId", + "type": "uint64", + "desc": "The id of the validator." + } + ], + "returns": { + "type": "uint64" + } + }, + { + "name": "doesStakerNeedToPayMBR", + "desc": "Helper callers can call w/ simulate to determine if 'AddStaker' MBR should be included w/ staking amount", + "args": [ + { + "name": "staker", + "type": "address" + } + ], + "returns": { + "type": "bool" + } + }, + { + "name": "getStakedPoolsForAccount", + "desc": "Retrieves the staked pools for an account.", + "args": [ + { + "name": "staker", + "type": "address", + "desc": "The account to retrieve staked pools for.@return{ValidatorPoolKey[]}- The array of staked pools for the account." + } + ], + "returns": { + "type": "(uint64,uint64,uint64)[]" + } + }, + { + "name": "getTokenPayoutRatio", + "desc": "Retrieves the token payout ratio for a given validator - returning the pool ratios of whole so that tokenpayouts across pools can be based on a stable snaphost of stake.", + "args": [ + { + "name": "validatorId", + "type": "uint64", + "desc": "The id of the validator.@return{PoolTokenPayoutRatio}- The token payout ratio for the validator." + } + ], + "returns": { + "type": "(uint64[24],uint64)" + } + }, + { + "name": "getNodePoolAssignments", + "args": [ + { + "name": "validatorId", + "type": "uint64" + } + ], + "returns": { + "type": "((uint64[3])[8])" + } + }, + { + "name": "getNFDRegistryID", + "args": [], + "returns": { + "type": "uint64" + } + }, + { + "name": "addValidator", + "desc": "Adds a new validator", + "args": [ + { + "name": "mbrPayment", + "type": "pay", + "desc": "payment from caller which covers mbr increase of new validator storage" + }, + { + "name": "nfdName", + "type": "string", + "desc": "(Optional) Name of nfd (used as double-check against id specified in config)" + }, + { + "name": "config", + "type": "(uint64,address,address,uint64,uint8,byte[32],uint64,uint64,uint64,uint16,uint32,address,uint64,uint64,uint8,uint64,uint64)", + "desc": "ValidatorConfig struct" + } + ], + "returns": { + "type": "uint64", + "desc": "validator id" + } + }, + { + "name": "changeValidatorManager", + "desc": "Changes the Validator manager for a specific Validator id.[ ONLY OWNER CAN CHANGE ]", + "args": [ + { + "name": "validatorId", + "type": "uint64", + "desc": "The id of the validator to change the manager for." + }, + { + "name": "manager", + "type": "address", + "desc": "The new manager address." + } + ], + "returns": { + "type": "void" + } + }, + { + "name": "changeValidatorSunsetInfo", + "desc": "Updates the sunset information for a given validator.[ ONLY OWNER CAN CHANGE ]", + "args": [ + { + "name": "validatorId", + "type": "uint64", + "desc": "The id of the validator to update." + }, + { + "name": "sunsettingOn", + "type": "uint64", + "desc": "The new sunset timestamp." + }, + { + "name": "sunsettingTo", + "type": "uint64", + "desc": "The new sunset to validator id." + } + ], + "returns": { + "type": "void" + } + }, + { + "name": "changeValidatorNFD", + "desc": "Changes the NFD for a validator in the validatorList contract.[ ONLY OWNER OR MANAGER CAN CHANGE ]", + "args": [ + { + "name": "validatorId", + "type": "uint64", + "desc": "The id of the validator to update." + }, + { + "name": "nfdAppID", + "type": "uint64", + "desc": "The application id of the NFD to assign to the validator." + }, + { + "name": "nfdName", + "type": "string", + "desc": "The name of the NFD (which must match)" + } + ], + "returns": { + "type": "void" + } + }, + { + "name": "changeValidatorCommissionAddress", + "desc": "Change the commission address that validator rewards are sent to.[ ONLY OWNER CAN CHANGE ]", + "args": [ + { + "name": "validatorId", + "type": "uint64" + }, + { + "name": "commissionAddress", + "type": "address" + } + ], + "returns": { + "type": "void" + } + }, + { + "name": "changeValidatorRewardInfo", + "desc": "Allow the additional rewards (gating entry, additional token rewards) information be changed at will.[ ONLY OWNER CAN CHANGE ]", + "args": [ + { + "name": "validatorId", + "type": "uint64" + }, + { + "name": "EntryGatingType", + "type": "uint8" + }, + { + "name": "EntryGatingValue", + "type": "byte[32]" + }, + { + "name": "GatingAssetMinBalance", + "type": "uint64" + }, + { + "name": "RewardPerPayout", + "type": "uint64" + } + ], + "returns": { + "type": "void" + } + }, + { + "name": "addPool", + "desc": "Adds a new pool to a validator's pool set, returning the 'key' to reference the pool in the future for staking, etc.The caller must pay the cost of the validators MBR increase as well as the MBR that will be needed for the pool itself.[ ONLY OWNER OR MANAGER CAN call ]", + "args": [ + { + "name": "mbrPayment", + "type": "pay", + "desc": "payment from caller which covers mbr increase of adding a new pool" + }, + { + "name": "validatorId", + "type": "uint64", + "desc": "is id of validator to pool to (must be owner or manager)" + }, + { + "name": "nodeNum", + "type": "uint64", + "desc": "is node number to add to" + } + ], + "returns": { + "type": "(uint64,uint64,uint64)", + "desc": "{ValidatorPoolKey}pool key to created pool" + } + }, + { + "name": "addStake", + "desc": "Adds stake to a validator pool.", + "args": [ + { + "name": "stakedAmountPayment", + "type": "pay", + "desc": "payment coming from staker to place into a pool" + }, + { + "name": "validatorId", + "type": "uint64", + "desc": "The id of the validator." + }, + { + "name": "valueToVerify", + "type": "uint64", + "desc": "only if validator has gating to enter - this is asset id or nfd id that corresponds to gating.Txn sender is factored in as well if that is part of gating.*" + } + ], + "returns": { + "type": "(uint64,uint64,uint64)", + "desc": "{ValidatorPoolKey}- The key of the validator pool." + } + }, + { + "name": "setTokenPayoutRatio", + "desc": "setTokenPayoutRatio is called by Staking Pool # 1 (ONLY) to ask the validator (us) to calculate the ratiosof stake in the pools for subsequent token payouts (ie: 2 pools, '100' algo total staked, 60 in pool 1, and 40in pool 2. This is done so we have a stable snapshot of stake - taken once per epoch - only triggered bypool 1 doing payout. pools other than 1 doing payout call pool 1 to ask it do it first.It would be 60/40% in the poolPctOfWhole values. The token reward payouts then use these values instead oftheir 'current' stake which changes as part of the payouts themselves (and people could be changing stakeduring the epoch updates across pools)Multiple pools will call us via pool 1 (pool2->pool1->valdiator, etc.) so don't assert on pool1 calling multipletimes in same epoch. Just return.", + "args": [ + { + "name": "validatorId", + "type": "uint64", + "desc": "validator id (and thus pool) calling us. Verified so that sender MUST be pool 1 of this validator." + } + ], + "returns": { + "type": "(uint64[24],uint64)", + "desc": "PoolTokenPayoutRatio - the finished ratio data" + } + }, + { + "name": "stakeUpdatedViaRewards", + "desc": "stakeUpdatedViaRewards is called by Staking pools to inform the validator (us) that a particular amount of totalstake has been added to the specified pool. This is used to update the stats we have in our PoolInfo storage.The calling App id is validated against our pool list as well.", + "args": [ + { + "name": "poolKey", + "type": "(uint64,uint64,uint64)", + "desc": "ValidatorPoolKey type" + }, + { + "name": "algoToAdd", + "type": "uint64", + "desc": "amount this validator's total stake increased via rewards" + }, + { + "name": "rewardTokenAmountReserved", + "type": "uint64", + "desc": "amount this validator's total stake increased via rewards (that should beseen as 'accounted for/pending spent')" + } + ], + "returns": { + "type": "void" + } + }, + { + "name": "stakeRemoved", + "desc": "stakeRemoved is called by Staking pools to inform the validator (us) that a particular amount of total stake has been removedfrom the specified pool. This is used to update the stats we have in our PoolInfo storage.If any amount of rewardRemoved is specified, then that amount of reward is sent to the useThe calling App id is validated against our pool list as well.", + "args": [ + { + "name": "poolKey", + "type": "(uint64,uint64,uint64)", + "desc": "calling us from which stake was removed" + }, + { + "name": "staker", + "type": "address" + }, + { + "name": "amountRemoved", + "type": "uint64", + "desc": "algo amount removed" + }, + { + "name": "rewardRemoved", + "type": "uint64", + "desc": "if applicable, amount of token reward removed (by pool 1 caller) or TO remove and pay out (via pool 1 from different pool caller)" + }, + { + "name": "stakerRemoved", + "type": "bool" + } + ], + "returns": { + "type": "void" + } + }, + { + "name": "findPoolForStaker", + "desc": "Finds the pool for a staker based on the provided validator id, staker address, and amount to stake.First checks the stakers 'already staked list' for the validator preferring those (adding if possible) then addsto new pool if necessary.", + "args": [ + { + "name": "validatorId", + "type": "uint64", + "desc": "The id of the validator." + }, + { + "name": "staker", + "type": "address", + "desc": "The address of the staker." + }, + { + "name": "amountToStake", + "type": "uint64", + "desc": "The amount to stake." + } + ], + "returns": { + "type": "((uint64,uint64,uint64),bool,bool)", + "desc": "{ValidatorPoolKey, boolean, boolean}- The pool for the staker, true/false on whether the staker is 'new'to this VALIDATOR, and true/false if staker is new to the protocol." + } + }, + { + "name": "movePoolToNode", + "desc": "Find the specified pool (in any node number) and move it to the specified node.The pool account is forced offline if moved so prior node will still run for 320 rounds butnew key goes online on new node soon after (320 rounds after it goes online)No-op if success, asserts if not found or can't move (no space in target)[ ONLY OWNER OR MANAGER CAN CHANGE ]Only callable by owner or manager", + "args": [ + { + "name": "validatorId", + "type": "uint64" + }, + { + "name": "poolAppId", + "type": "uint64" + }, + { + "name": "nodeNum", + "type": "uint64" + } + ], + "returns": { + "type": "void" + } + } + ] + } +} \ No newline at end of file diff --git a/nodemgr/internal/lib/reti/consts.go b/nodemgr/internal/lib/reti/consts.go new file mode 100644 index 00000000..ff3894fb --- /dev/null +++ b/nodemgr/internal/lib/reti/consts.go @@ -0,0 +1,51 @@ +package reti + +import ( + "bytes" + "encoding/binary" + + "github.com/algorand/go-algorand-sdk/v2/types" +) + +const ( + // Global state keys in Validator contract + VldtrNumValidators = "numV" + VldtrPoolTmplId = "poolTemplateAppId" + + // Global state keys in Staking pool contract + StakePoolCreatorApp = "creatorApp" + StakePoolValidatorId = "validatorId" + StakePoolPoolId = "poolId" + StakePoolNumStakers = "numStakers" + StakePoolStaked = "staked" + StakePoolMinEntryStake = "minEntryStake" + StakePoolMaxStake = "maxStake" + StakePoolLastPayout = "lastPayout" + StakePoolAlgodVer = "algodVer" + + // Gating types + GatingTypeNone = 0 + GatingTypeAssetsCreatedBy = 1 + GatingTypeAssetId = 2 + GatingTypeCreatedByNFDAddresses = 3 + GatingTypeSegmentOfNFD = 4 +) + +// Algorand address to use as sender for read-only simulate calls (not signed but still has to be valid address) +// Use devnet/betanet/testnet feesink (funded same on mainnet so can also use there) +var DummyAlgoSender, _ = types.DecodeAddress("A7NMWS3NT3IUDMLVO26ULGXGIIOUQ3ND2TXSER6EBGRZNOBOUIQXHIBGDE") + +func GetValidatorListBoxName(id uint64) []byte { + prefix := []byte("v") + ibytes := make([]byte, 8) + binary.BigEndian.PutUint64(ibytes, id) + return bytes.Join([][]byte{prefix, ibytes[:]}, nil) +} + +func GetStakerPoolSetBoxName(stakerAccount types.Address) []byte { + return bytes.Join([][]byte{[]byte("sps"), stakerAccount[:]}, nil) +} + +func GetStakerLedgerBoxName() []byte { + return []byte("stakers") +} diff --git a/nodemgr/internal/lib/reti/errors.go b/nodemgr/internal/lib/reti/errors.go new file mode 100644 index 00000000..c3fe6493 --- /dev/null +++ b/nodemgr/internal/lib/reti/errors.go @@ -0,0 +1,11 @@ +package reti + +import ( + "errors" +) + +var ( + ErrCantFetchValidators = errors.New("couldn't fetch num of validators from global state of validator application") + ErrCantFetchPoolKey = errors.New("couldn't fetch poolkey data") + ErrNotEnoughRewardAvailable = errors.New("reward available not at least least 1 ALGO - skipping payout") +) diff --git a/nodemgr/internal/lib/reti/metrics.go b/nodemgr/internal/lib/reti/metrics.go new file mode 100644 index 00000000..ef60e366 --- /dev/null +++ b/nodemgr/internal/lib/reti/metrics.go @@ -0,0 +1,33 @@ +package reti + +import ( + "github.com/prometheus/client_golang/prometheus" + "github.com/prometheus/client_golang/prometheus/promauto" +) + +var ( + promNumPools = promauto.NewGauge(prometheus.GaugeOpts{ + Subsystem: "reti", + Name: "pool_count", + }) + promNumStakers = promauto.NewGauge(prometheus.GaugeOpts{ + Subsystem: "reti", + Name: "staker_count", + }) + promTotalStaked = promauto.NewGauge(prometheus.GaugeOpts{ + Subsystem: "reti", + Name: "staked_total", + }) + promRewardAvailable = promauto.NewGauge(prometheus.GaugeOpts{ + Subsystem: "reti", + Name: "reward_available", + }) + promAmtConsideredSaturated = promauto.NewGauge(prometheus.GaugeOpts{ + Subsystem: "reti", + Name: "max_stake_before_saturated_total", + }) + promMaxStakeAllowed = promauto.NewGauge(prometheus.GaugeOpts{ + Subsystem: "reti", + Name: "max_stake_allowed_total", + }) +) diff --git a/nodemgr/internal/lib/reti/reti.go b/nodemgr/internal/lib/reti/reti.go new file mode 100644 index 00000000..a1febd12 --- /dev/null +++ b/nodemgr/internal/lib/reti/reti.go @@ -0,0 +1,215 @@ +package reti + +import ( + "context" + "embed" + "encoding/json" + "errors" + "fmt" + "log/slog" + "sync" + + "github.com/algorand/go-algorand-sdk/v2/abi" + "github.com/algorand/go-algorand-sdk/v2/client/v2/algod" + "github.com/algorand/go-algorand-sdk/v2/types" + + "github.com/TxnLab/reti/internal/lib/algo" + "github.com/TxnLab/reti/internal/lib/misc" +) + +type Reti struct { + Logger *slog.Logger + algoClient *algod.Client + signer algo.MultipleWalletSigner + + // RetiAppId is simply the master validator contract id + RetiAppId uint64 + ValidatorId uint64 + NodeNum uint64 + + poolTmplAppId uint64 + + validatorContract *abi.Contract + poolContract *abi.Contract + + // Loaded from on-chain state at start and on-demand via LoadStateFromChain + // Mutex wrap is just lazy way of allowing single shared-state of instance data that's periodically updated + sync.RWMutex + info ValidatorInfo +} + +func (r *Reti) Info() ValidatorInfo { + r.RLock() + defer r.RUnlock() + return r.info +} + +func (r *Reti) SetInfo(Info ValidatorInfo) { + r.Lock() + defer r.Unlock() + r.info = Info +} + +func New( + validatorAppId uint64, + logger *slog.Logger, + algoClient *algod.Client, + signer algo.MultipleWalletSigner, + validatorId uint64, + nodeNum uint64, +) (*Reti, error) { + + retReti := &Reti{ + RetiAppId: validatorAppId, + ValidatorId: validatorId, + NodeNum: nodeNum, + + Logger: logger, + algoClient: algoClient, + signer: signer, + } + validatorContract, err := loadContract("artifacts/contracts/ValidatorRegistry.arc32.json") + if err != nil { + return nil, err + } + poolContract, err := loadContract("artifacts/contracts/StakingPool.arc32.json") + if err != nil { + return nil, err + } + retReti.validatorContract = validatorContract + retReti.poolContract = poolContract + + misc.Infof(logger, "client initialized, Protocol App id:%d, Validator id:%d, Node Number:%d", validatorAppId, validatorId, nodeNum) + + return retReti, nil +} + +func (r *Reti) IsConfigured() bool { + return r.RetiAppId != 0 && r.ValidatorId != 0 && r.NodeNum != 0 +} + +// LoadState loads the state of the Reti instance by retrieving information from +// the chain and setting the local values to the on-chain current state. +// It also verifies that the validator has either owner or manager keys present, and match the +// keys we have available (which will have to sign for either owner or manager depending on call) +// Prometheus metrics are also updated based on loaded state. +func (r *Reti) LoadState(ctx context.Context) error { + if r.RetiAppId == 0 { + return errors.New("reti App id not defined") + } + appInfo, err := r.algoClient.GetApplicationByID(r.RetiAppId).Do(ctx) + if err != nil { + return err + } + r.poolTmplAppId, _ = algo.GetIntFromGlobalState(appInfo.Params.GlobalState, VldtrPoolTmplId) + + // Now load all the data from the chain for our validator, etc. + if r.ValidatorId != 0 { + config, err := r.GetValidatorConfig(r.ValidatorId) + if err != nil { + return fmt.Errorf("unable to GetValidatorConfig: %w", err) + } + // verify this validator is one we have either owner or manager keys for !! + _, err = r.signer.FindFirstSigner([]string{config.Owner, config.Manager}) + if err != nil { + return fmt.Errorf("neither owner or manager address for validator id:%d has local keys present", r.ValidatorId) + } + constraints, err := r.GetProtocolConstraints() + if err != nil { + return fmt.Errorf("unable to GetProtocolConstraints: %w", err) + } + + // We could get total stake etc for all pools at once via the validator state but since there will be multiple instances + // of this daemon we should just report per-validator data and the validator can max / sum, etc. as appropriate + // in their metrics dashboard - taking data from all daemons. + pools, err := r.GetValidatorPools(r.ValidatorId) + if err != nil { + return fmt.Errorf("unable to GetValidatorPools: %w", err) + } + + assignments, err := r.GetValidatorNodePoolAssignments(r.ValidatorId) + if err != nil { + return fmt.Errorf("unable to GetValidatorNodePoolAssignments: %w", err) + } + newInfo := ValidatorInfo{ + Config: *config, + Pools: pools, + NodePoolAssignments: *assignments, + LocalPools: map[uint64]uint64{}, + } + + if r.NodeNum == 0 || int(r.NodeNum) > len(newInfo.NodePoolAssignments.Nodes) { + return fmt.Errorf("configured Node number:%d is invalid for number of on-chain nodes configured: %d", r.NodeNum, len(newInfo.NodePoolAssignments.Nodes)) + } + + r.Logger.Debug("state re-loaded") + + // Just report metrics for OUR node - validators will presumably scrape metrics from all their nodes + var ( + localStakers uint64 + localTotalStaked uint64 + localTotalRewards float64 + ) + for _, poolAppID := range newInfo.NodePoolAssignments.Nodes[r.NodeNum-1].PoolAppIds { + var poolID uint64 + for poolIdx, pool := range pools { + if pool.PoolAppId == poolAppID { + localStakers += uint64(pool.TotalStakers) + localTotalStaked += pool.TotalAlgoStaked + localTotalRewards += float64(r.PoolAvailableRewards(pool.PoolAppId, pool.TotalAlgoStaked)) / 1e6 + + poolID = uint64(poolIdx + 1) + break + } + } + if poolID == 0 { + return fmt.Errorf("couldn't fetch pool id for staking pool app id:%d", poolAppID) + } + newInfo.LocalPools[poolID] = poolAppID + + } + + promNumPools.Set(float64(len(newInfo.LocalPools))) + promNumStakers.Set(float64(localStakers)) + promTotalStaked.Set(float64(localTotalStaked) / 1e6) + + promRewardAvailable.Set(localTotalRewards) + + promAmtConsideredSaturated.Set(float64(constraints.AmtConsideredSaturated) / 1e6) + promMaxStakeAllowed.Set(float64(constraints.MaxAlgoPerValidator) / 1e6) + + r.SetInfo(newInfo) + } + return nil +} + +func (r *Reti) getLocalSignerForSimulateCalls() (types.Address, error) { + return DummyAlgoSender, nil +} + +//go:embed artifacts/contracts/ValidatorRegistry.arc32.json +//go:embed artifacts/contracts/StakingPool.arc32.json +var embeddedF embed.FS + +func loadContract(fname string) (*abi.Contract, error) { + data, err := embeddedF.ReadFile(fname) + if err != nil { + return nil, err + } + return loadContractFromArc32(data) +} + +// ABIContractWrap struct is just so we can unmarshal an arc32 document into the abi.contract type +// we ignore everything else in arc32 +type ABIContractWrap struct { + Contract abi.Contract `json:"contract"` +} + +func loadContractFromArc32(arc32 []byte) (*abi.Contract, error) { + var contractWrap ABIContractWrap + err := json.Unmarshal(arc32, &contractWrap) + if err != nil { + return nil, err + } + return &contractWrap.Contract, nil +} diff --git a/nodemgr/internal/lib/reti/stakingpool.go b/nodemgr/internal/lib/reti/stakingpool.go new file mode 100644 index 00000000..6a2e3928 --- /dev/null +++ b/nodemgr/internal/lib/reti/stakingpool.go @@ -0,0 +1,278 @@ +package reti + +import ( + "context" + "encoding/binary" + "errors" + "fmt" + + "github.com/algorand/go-algorand-sdk/v2/client/v2/common/models" + "github.com/algorand/go-algorand-sdk/v2/crypto" + "github.com/algorand/go-algorand-sdk/v2/transaction" + "github.com/algorand/go-algorand-sdk/v2/types" + + "github.com/TxnLab/reti/internal/lib/algo" + "github.com/TxnLab/reti/internal/lib/misc" +) + +type StakedInfo struct { + Account types.Address + Balance uint64 + TotalRewarded uint64 + RewardTokenBalance uint64 + EntryTime uint64 +} + +func (r *Reti) GetLedgerforPool(poolAppID uint64) ([]StakedInfo, error) { + var retLedger []StakedInfo + boxData, err := r.algoClient.GetApplicationBoxByName(poolAppID, GetStakerLedgerBoxName()).Do(context.Background()) + if err != nil { + return nil, err + } + // Iterate through the boxData.Value []byte, taking the fixed-size struct data stored in it (StakedInfo encoded struct) + // and appending to retLedger as it goes + const stakedInfoSize = 64 + for i := 0; i < len(boxData.Value); i += stakedInfoSize { + ledgerData := boxData.Value[i : i+stakedInfoSize] + var stakedInfo StakedInfo + stakedInfo.Account = types.Address{} + copy(stakedInfo.Account[:], ledgerData[0:32]) + stakedInfo.Balance = binary.BigEndian.Uint64(ledgerData[32:40]) + stakedInfo.TotalRewarded = binary.BigEndian.Uint64(ledgerData[40:48]) + stakedInfo.RewardTokenBalance = binary.BigEndian.Uint64(ledgerData[48:56]) + stakedInfo.EntryTime = binary.BigEndian.Uint64(ledgerData[56:64]) + retLedger = append(retLedger, stakedInfo) + } + + return retLedger, nil +} + +func (r *Reti) GetPoolID(poolAppID uint64) (uint64, error) { + appInfo, err := r.algoClient.GetApplicationByID(poolAppID).Do(context.Background()) + if err != nil { + return 0, err + } + return algo.GetIntFromGlobalState(appInfo.Params.GlobalState, StakePoolPoolId) +} + +func (r *Reti) GetLastPayout(poolAppID uint64) (uint64, error) { + appInfo, err := r.algoClient.GetApplicationByID(poolAppID).Do(context.Background()) + if err != nil { + return 0, err + } + return algo.GetIntFromGlobalState(appInfo.Params.GlobalState, StakePoolLastPayout) +} + +func (r *Reti) GetAlgodVer(poolAppID uint64) (string, error) { + appInfo, err := r.algoClient.GetApplicationByID(poolAppID).Do(context.Background()) + if err != nil { + return "", err + } + return algo.GetStringFromGlobalState(appInfo.Params.GlobalState, StakePoolAlgodVer) +} + +func (r *Reti) UpdateAlgodVer(poolAppID uint64, algodVer string, caller types.Address) error { + var err error + + params, err := r.algoClient.SuggestedParams().Do(context.Background()) + if err != nil { + return err + } + + atc := transaction.AtomicTransactionComposer{} + updateAlgodVerMethod, _ := r.poolContract.GetMethodByName("updateAlgodVer") + + params.FlatFee = true + params.Fee = transaction.MinTxnFee * 2 + + err = atc.AddMethodCall(transaction.AddMethodCallParams{ + AppID: poolAppID, + Method: updateAlgodVerMethod, + MethodArgs: []any{algodVer}, + ForeignApps: []uint64{r.RetiAppId}, + BoxReferences: []types.AppBoxReference{ + {AppID: r.RetiAppId, Name: GetValidatorListBoxName(r.ValidatorId)}, + {AppID: 0, Name: nil}, // extra i/o + }, + SuggestedParams: params, + OnComplete: types.NoOpOC, + Sender: caller, + Signer: algo.SignWithAccountForATC(r.signer, caller.String()), + }) + if err != nil { + return err + } + + _, err = atc.Execute(r.algoClient, context.Background(), 4) + if err != nil { + return err + } + return nil +} + +func (r *Reti) EpochBalanceUpdate(poolID int, poolAppID uint64, caller types.Address) error { + var ( + err error + info = r.Info() + ) + + // make sure we even have enough rewards to do the payout + pools, err := r.GetValidatorPools(r.ValidatorId) + if err != nil { + return fmt.Errorf("failed to get validator pools: %w", err) + } + rewardAvail := r.PoolAvailableRewards(poolAppID, pools[poolID-1].TotalAlgoStaked) + if rewardAvail < 1e6 { + misc.Infof(r.Logger, "Pool:%d epoch update - reward too small:%s", poolID, algo.FormattedAlgoAmount(rewardAvail)) + return ErrNotEnoughRewardAvailable + } + misc.Infof(r.Logger, "Pool:%d epoch update for app id:%d", poolID, poolAppID) + + params, err := r.algoClient.SuggestedParams().Do(context.Background()) + if err != nil { + return err + } + + getAtc := func(feesToUse uint64) (transaction.AtomicTransactionComposer, error) { + atc := transaction.AtomicTransactionComposer{} + gasMethod, _ := r.poolContract.GetMethodByName("gas") + epochUpdateMethod, _ := r.poolContract.GetMethodByName("epochBalanceUpdate") + + newParams := params + + newParams.FlatFee = true + newParams.Fee = 0 + + // we need to stack up references in this gas method for resource pooling + err = atc.AddMethodCall(transaction.AddMethodCallParams{ + AppID: poolAppID, + Method: gasMethod, + ForeignApps: []uint64{r.RetiAppId}, + BoxReferences: []types.AppBoxReference{ + {AppID: r.RetiAppId, Name: GetValidatorListBoxName(r.ValidatorId)}, + {AppID: 0, Name: GetStakerLedgerBoxName()}, + {AppID: 0, Name: nil}, // extra i/o + {AppID: 0, Name: nil}, // extra i/o + {AppID: 0, Name: nil}, // extra i/o + {AppID: 0, Name: nil}, // extra i/o + {AppID: 0, Name: nil}, // extra i/o + }, + SuggestedParams: newParams, + OnComplete: types.NoOpOC, + Sender: caller, + Signer: algo.SignWithAccountForATC(r.signer, caller.String()), + }) + if err != nil { + return atc, err + } + if feesToUse == 0 { + // we're simulating so go with super high budget + feesToUse = 240 * transaction.MinTxnFee + } + newParams.Fee = types.MicroAlgos(feesToUse) + err = atc.AddMethodCall(transaction.AddMethodCallParams{ + AppID: poolAppID, + Method: epochUpdateMethod, + ForeignAccounts: []string{info.Config.ValidatorCommissionAddress}, + BoxReferences: []types.AppBoxReference{ + {AppID: 0, Name: nil}, // extra i/o + {AppID: 0, Name: nil}, // extra i/o + {AppID: 0, Name: nil}, // extra i/o + {AppID: 0, Name: nil}, // extra i/o + {AppID: 0, Name: nil}, // extra i/o + {AppID: 0, Name: nil}, // extra i/o + {AppID: 0, Name: nil}, // extra i/o + }, + SuggestedParams: newParams, + OnComplete: types.NoOpOC, + Sender: caller, + Signer: algo.SignWithAccountForATC(r.signer, caller.String()), + }) + if err != nil { + return atc, err + } + return atc, err + } + + // simulate first + atc, err := getAtc(0) + if err != nil { + return err + } + simResult, err := atc.Simulate(context.Background(), r.algoClient, models.SimulateRequest{ + AllowUnnamedResources: true, + }) + if err != nil { + return err + } + if simResult.SimulateResponse.TxnGroups[0].FailureMessage != "" { + return errors.New(simResult.SimulateResponse.TxnGroups[0].FailureMessage) + } + // Figure out how much app budget was added so we can know the real fees to use when we execute + atc, err = getAtc(transaction.MinTxnFee * (simResult.SimulateResponse.TxnGroups[0].AppBudgetAdded / 700)) + if err != nil { + return err + } + + _, err = atc.Execute(r.algoClient, context.Background(), 4) + if err != nil { + return err + } + return nil +} + +func (r *Reti) GoOnline(poolAppID uint64, caller types.Address, votePK []byte, selectionPK []byte, stateProofPK []byte, voteFirst uint64, voteLast uint64, voteKeyDilution uint64) error { + var err error + + params, err := r.algoClient.SuggestedParams().Do(context.Background()) + if err != nil { + return err + } + + atc := transaction.AtomicTransactionComposer{} + goOnlineMethod, _ := r.poolContract.GetMethodByName("goOnline") + + params.FlatFee = true + params.Fee = transaction.MinTxnFee * 3 + + err = atc.AddMethodCall(transaction.AddMethodCallParams{ + AppID: poolAppID, + Method: goOnlineMethod, + MethodArgs: []any{ + votePK, + selectionPK, + stateProofPK, + voteFirst, + voteLast, + voteKeyDilution, + }, + ForeignApps: []uint64{r.RetiAppId}, + BoxReferences: []types.AppBoxReference{ + {AppID: r.RetiAppId, Name: GetValidatorListBoxName(r.ValidatorId)}, + {AppID: 0, Name: nil}, // extra i/o + }, + SuggestedParams: params, + OnComplete: types.NoOpOC, + Sender: caller, + Signer: algo.SignWithAccountForATC(r.signer, caller.String()), + }) + if err != nil { + return err + } + + _, err = atc.Execute(r.algoClient, context.Background(), 4) + if err != nil { + return err + } + return nil +} + +// PoolBalance just returns the currently available (minus MBR) balance for basic 'is this usable' check. +func (r *Reti) PoolBalance(poolAppID uint64) uint64 { + return r.PoolAvailableRewards(poolAppID, 0) +} + +func (r *Reti) PoolAvailableRewards(poolAppID uint64, totalAlgoStaked uint64) uint64 { + acctInfo, _ := algo.GetBareAccount(context.Background(), r.algoClient, crypto.GetApplicationAddress(poolAppID).String()) + return acctInfo.Amount - totalAlgoStaked - acctInfo.MinBalance +} diff --git a/nodemgr/internal/lib/reti/validator.go b/nodemgr/internal/lib/reti/validator.go new file mode 100644 index 00000000..ac58b8ff --- /dev/null +++ b/nodemgr/internal/lib/reti/validator.go @@ -0,0 +1,1338 @@ +package reti + +import ( + "context" + "encoding/binary" + "errors" + "fmt" + "log/slog" + "strings" + "time" + + "github.com/algorand/go-algorand-sdk/v2/client/v2/common/models" + "github.com/algorand/go-algorand-sdk/v2/crypto" + "github.com/algorand/go-algorand-sdk/v2/transaction" + "github.com/algorand/go-algorand-sdk/v2/types" + + "github.com/TxnLab/reti/internal/lib/algo" + "github.com/TxnLab/reti/internal/lib/misc" +) + +// ValidatorInfo is loaded at startup but also on-demand via Reti.LoadState +type ValidatorInfo struct { + Config ValidatorConfig + Pools []PoolInfo + NodePoolAssignments NodePoolAssignmentConfig + + // A generated map of pool id's and the App id assigned to it - for 'our' node + // determined via Pools and NodePoolAssignments + LocalPools map[uint64]uint64 +} + +type NodeConfig struct { + PoolAppIds []uint64 +} + +type NodePoolAssignmentConfig struct { + Nodes []NodeConfig +} + +type ValidatorConfig struct { + // ID of this validator (sequentially assigned) + ID uint64 + // account that controls config - presumably cold-wallet + Owner string + // account that triggers/pays for payouts and keyreg transactions - needs to be hotwallet as node has to sign for the transactions + Manager string + // Optional NFD AppID which the validator uses to describe their validator pool + NFDForInfo uint64 + + // EntryGatingType / EntryGatingValue specifies an optional gating mechanism - whose criteria + // the staker must meet. + EntryGatingType uint8 + EntryGatingValue []byte + + // GatingAssetMinBalance specifies a minimum token base units amount needed of an asset owned by the specified + // creator (if defined). If 0, then they need to hold at lest 1 unit, but its assumed this is for tokens, ie: hold + // 10000[.000000] of token + GatingAssetMinBalance uint64 + + // Reward token ASA ID and reward rate (Optional): A validator can define a token that users are awarded in addition to + // the ALGO they receive for being in the pool. This will allow projects to allow rewarding members their own + // token. Hold at least 5000 VEST to enter a Vestige staking pool, they have 1 day epochs and all + // stakers get X amount of VEST as daily rewards (added to stakers ‘available’ balance) for removal at any time. + RewardTokenId uint64 + RewardPerPayout uint64 + + // Payout frequency in minutes (can be no shorter than this) + PayoutEveryXMins int + // Payout percentage expressed w/ four decimals - ie: 50000 = 5% -> .0005 - + PercentToValidator int + // account that receives the validation commission each epoch payout (can be ZeroAddress) + ValidatorCommissionAddress string + // minimum stake required to enter pool - but must withdraw all if want to go below this amount as well(!) + MinEntryStake uint64 + // maximum stake allowed per pool (to keep under incentive limits) + MaxAlgoPerPool uint64 + // Number of pools to allow per node (max of 3 is recommended) + PoolsPerNode int + + SunsettingOn uint64 // timestamp when validator will sunset (if != 0) + SunsettingTo uint64 // validator ID that validator is 'moving' to (if known) + +} + +func ValidatorConfigFromABIReturn(returnVal any) (*ValidatorConfig, error) { + if arrReturn, ok := returnVal.([]any); ok { + if len(arrReturn) != 17 { + return nil, fmt.Errorf("should be 17 elements returned in ValidatorConfig response") + } + pkAsString := func(pk []uint8) string { + addr, _ := types.EncodeAddress(pk) + return addr + } + byte32AsSlice := func(byte32 []any) []byte { + ret := make([]byte, len(byte32)) + for i, b := range byte32 { + ret[i] = b.(byte) + } + return ret + } + config := &ValidatorConfig{} + config.ID = arrReturn[0].(uint64) + config.Owner = pkAsString(arrReturn[1].([]uint8)) + config.Manager = pkAsString(arrReturn[2].([]uint8)) + config.NFDForInfo = arrReturn[3].(uint64) + config.EntryGatingType = arrReturn[4].(uint8) + config.EntryGatingValue = byte32AsSlice(arrReturn[5].([]any)) + config.GatingAssetMinBalance = arrReturn[6].(uint64) + config.RewardTokenId = arrReturn[7].(uint64) + config.RewardPerPayout = arrReturn[8].(uint64) + config.PayoutEveryXMins = int(arrReturn[9].(uint16)) + config.PercentToValidator = int(arrReturn[10].(uint32)) + config.ValidatorCommissionAddress = pkAsString(arrReturn[11].([]uint8)) + config.MinEntryStake = arrReturn[12].(uint64) + config.MaxAlgoPerPool = arrReturn[13].(uint64) + config.PoolsPerNode = int(arrReturn[14].(uint8)) + config.SunsettingOn = arrReturn[15].(uint64) + config.SunsettingTo = arrReturn[16].(uint64) + return config, nil + } + return nil, fmt.Errorf("unknown value returned from abi, type:%T", returnVal) +} + +type ProtocolConstraints struct { + EpochPayoutMinsMin uint64 + EpochPayoutMinsMax uint64 + MinPctToValidatorWFourDecimals uint64 + MaxPctToValidatorWFourDecimals uint64 + MinEntryStake uint64 // in microAlgo + MaxAlgoPerPool uint64 // in microAlgo + MaxAlgoPerValidator uint64 // in microAlgo + AmtConsideredSaturated uint64 // soft stake - when saturation starts - in microAlgo + MaxNodes uint64 + MaxPoolsPerNode uint64 + MaxStakersPerPool uint64 +} + +func ProtocolConstraintsFromABIReturn(returnVal any) (*ProtocolConstraints, error) { + if arrReturn, ok := returnVal.([]any); ok { + if len(arrReturn) != 11 { + return nil, fmt.Errorf("should be 10 elements returned in ProtocolConstraints response") + } + constraints := &ProtocolConstraints{} + constraints.EpochPayoutMinsMin = arrReturn[0].(uint64) + constraints.EpochPayoutMinsMax = arrReturn[1].(uint64) + constraints.MinPctToValidatorWFourDecimals = arrReturn[2].(uint64) + constraints.MaxPctToValidatorWFourDecimals = arrReturn[3].(uint64) + constraints.MinEntryStake = arrReturn[4].(uint64) + constraints.MaxAlgoPerPool = arrReturn[5].(uint64) + constraints.MaxAlgoPerValidator = arrReturn[6].(uint64) + constraints.AmtConsideredSaturated = arrReturn[7].(uint64) + constraints.MaxNodes = arrReturn[8].(uint64) + constraints.MaxPoolsPerNode = arrReturn[9].(uint64) + constraints.MaxStakersPerPool = arrReturn[10].(uint64) + return constraints, nil + } + return nil, fmt.Errorf("unknown value returned from abi, type:%T", returnVal) +} + +func formattedMinutes(mins int) string { + // return a string expression of minutes in various forms (if applicable) + // minutes, hours, days + var out strings.Builder + if mins < 60 { + out.WriteString(fmt.Sprintf("%d minutes", mins)) + } else if mins < 1440 { + hours := mins / 60 + minutes := mins % 60 + out.WriteString(fmt.Sprintf("%d hours, %d minutes", hours, minutes)) + } else { + days := mins / 1440 + hours := (mins % 1440) / 60 + minutes := (mins % 1440) % 60 + out.WriteString(fmt.Sprintf("%d days, %d hours, %d minutes", days, hours, minutes)) + } + return out.String() +} + +func (v *ValidatorConfig) String() string { + var out strings.Builder + + out.WriteString(fmt.Sprintf("id: %d\n", v.ID)) + out.WriteString(fmt.Sprintf("owner: %s\n", v.Owner)) + out.WriteString(fmt.Sprintf("manager: %s\n", v.Manager)) + out.WriteString(fmt.Sprintf("Validator Commission Address: %s\n", v.ValidatorCommissionAddress)) + out.WriteString(fmt.Sprintf("%% to Validator: %.04f\n", float64(v.PercentToValidator)/10_000.0)) + if v.NFDForInfo != 0 { + out.WriteString(fmt.Sprintf("NFD id: %d\n", v.NFDForInfo)) + } + switch v.EntryGatingType { + case GatingTypeNone: + case GatingTypeAssetsCreatedBy: + addr, err := types.EncodeAddress(v.EntryGatingValue) + if err != nil { + out.WriteString(fmt.Sprintf("Reward Token Creator Reqd: {err:%v}\n", err)) + } else { + out.WriteString(fmt.Sprintf("Reward Token Creator Reqd: %s\n", addr)) + } + out.WriteString(fmt.Sprintf("Reward Token Min Bal: %d\n", v.GatingAssetMinBalance)) + case GatingTypeAssetId: + out.WriteString(fmt.Sprintf("Reward Token Requires ASA:%d\n", binary.BigEndian.Uint64(v.EntryGatingValue))) + out.WriteString(fmt.Sprintf("Reward Token Min Bal: %d\n", v.GatingAssetMinBalance)) + case GatingTypeCreatedByNFDAddresses: + out.WriteString(fmt.Sprintf("Reward Token NFD Creator Addresses, NFD id:%d\n", binary.BigEndian.Uint64(v.EntryGatingValue))) + out.WriteString(fmt.Sprintf("Reward Token Min Bal: %d\n", v.GatingAssetMinBalance)) + case GatingTypeSegmentOfNFD: + out.WriteString(fmt.Sprintf("Reward Token NFD Segments of Root NFD id:%d\n", binary.BigEndian.Uint64(v.EntryGatingValue))) + } + if v.EntryGatingType != GatingTypeNone { + out.WriteString(fmt.Sprintf("Reward Token id: %d\n", v.RewardTokenId)) + out.WriteString(fmt.Sprintf("Reward Per Payout: %d\n", v.RewardPerPayout)) + } + + out.WriteString(fmt.Sprintf("Payout Every %s\n", formattedMinutes(v.PayoutEveryXMins))) + out.WriteString(fmt.Sprintf("Min Entry Stake: %s\n", algo.FormattedAlgoAmount(v.MinEntryStake))) + out.WriteString(fmt.Sprintf("Max Algo Per Pool: %s\n", algo.FormattedAlgoAmount(v.MaxAlgoPerPool))) + out.WriteString(fmt.Sprintf("Max pools per Node: %d\n", v.PoolsPerNode)) + if v.SunsettingOn != 0 { + out.WriteString(fmt.Sprintf("Sunsetting On: %s\n", time.Unix(int64(v.SunsettingOn), 0).Format(time.RFC3339))) + if v.SunsettingTo != 0 { + out.WriteString(fmt.Sprintf("Sunsetting To: %d\n", v.SunsettingTo)) + } + } + + return out.String() +} + +type ValidatorCurState struct { + NumPools int // current number of pools this validator has - capped at MaxPools + TotalStakers uint64 // total number of stakers across all pools + TotalAlgoStaked uint64 // total amount staked to this validator across ALL of its pools + RewardTokenHeldBack uint64 // amount of reward tokens held back +} + +func (v *ValidatorCurState) String() string { + return fmt.Sprintf("numPools: %d, totalStakers: %d, totalAlgoStaked: %d", v.NumPools, v.TotalStakers, v.TotalAlgoStaked) +} + +func ValidatorCurStateFromABIReturn(returnVal any) (*ValidatorCurState, error) { + if arrReturn, ok := returnVal.([]any); ok { + if len(arrReturn) != 4 { + return nil, fmt.Errorf("should be 4 elements returned in ValidatorCurState response") + } + state := &ValidatorCurState{} + state.NumPools = int(arrReturn[0].(uint16)) + state.TotalStakers = arrReturn[1].(uint64) + state.TotalAlgoStaked = arrReturn[2].(uint64) + state.RewardTokenHeldBack = arrReturn[3].(uint64) + + return state, nil + } + return nil, fmt.Errorf("unknown value returned from abi, type:%T", returnVal) +} + +type ValidatorPoolKey struct { + ID uint64 // 0 is invalid - should start at 1 (but is direct key in box) + PoolId uint64 // 0 means INVALID ! - so 1 is index, technically of [0] + PoolAppId uint64 +} + +func (v *ValidatorPoolKey) String() string { + return fmt.Sprintf("ValidatorPoolKey{id: %d, poolId: %d, poolAppId: %d}", v.ID, v.PoolId, v.PoolAppId) +} + +func ValidatorPoolKeyFromABIReturn(returnVal any) (*ValidatorPoolKey, error) { + if arrReturn, ok := returnVal.([]any); ok { + if len(arrReturn) != 3 { + return nil, fmt.Errorf("should be 3 elements returned in ValidatorPoolKey response") + } + key := &ValidatorPoolKey{} + key.ID = arrReturn[0].(uint64) + key.PoolId = arrReturn[1].(uint64) + key.PoolAppId = arrReturn[2].(uint64) + + return key, nil + } + return nil, ErrCantFetchPoolKey +} + +type PoolInfo struct { + PoolAppId uint64 // The App id of this staking pool contract instance + TotalStakers int + TotalAlgoStaked uint64 +} + +func ValidatorPoolsFromABIReturn(returnVal any) ([]PoolInfo, error) { + var retPools []PoolInfo + if arrReturn, ok := returnVal.([]any); ok { + for _, poolInfoAny := range arrReturn { + if poolInfo, ok := poolInfoAny.([]any); ok { + if len(poolInfo) != 3 { + return nil, fmt.Errorf("should be 3 elements returned in PoolInfo response") + } + retPools = append(retPools, PoolInfo{ + PoolAppId: poolInfo[0].(uint64), + TotalStakers: int(poolInfo[1].(uint16)), + TotalAlgoStaked: poolInfo[2].(uint64), + }) + } + } + return retPools, nil + } + return retPools, ErrCantFetchPoolKey +} + +func ValidatorPoolInfoFromABIReturn(returnVal any) (*PoolInfo, error) { + if arrReturn, ok := returnVal.([]any); ok { + if len(arrReturn) != 3 { + return nil, fmt.Errorf("should be 3 elements returned in PoolInfo response") + } + key := &PoolInfo{} + key.PoolAppId = arrReturn[0].(uint64) + key.TotalStakers = int(arrReturn[1].(uint16)) + key.PoolAppId = arrReturn[2].(uint64) + + return key, nil + } + return nil, ErrCantFetchPoolKey +} + +func (r *Reti) AddValidator(info *ValidatorInfo, nfdName string) (uint64, error) { + var err error + + params, err := r.algoClient.SuggestedParams().Do(context.Background()) + if err != nil { + return 0, err + } + + ownerAddr, _ := types.DecodeAddress(info.Config.Owner) + managerAddr, _ := types.DecodeAddress(info.Config.Manager) + commissionAddr, _ := types.DecodeAddress(info.Config.ValidatorCommissionAddress) + //mustHoldCreatorAddr, _ := types.DecodeAddress(info.config.MustHoldCreatorNFT) + + // first determine how much we have to add in MBR to the validator + mbrs, err := r.getMbrAmounts(ownerAddr) + if err != nil { + return 0, err + } + + // Now try to actually create the validator !! + atc := transaction.AtomicTransactionComposer{} + + addValidatorMethod, err := r.validatorContract.GetMethodByName("addValidator") + if err != nil { + return 0, err + } + // We need to set all the box references ourselves still in go, so we need the id of the 'next' validator + // We'll do the next two just to be safe (for race condition of someone else adding validator before us) + curValidatorId, err := r.getNumValidators() + if err != nil { + return 0, err + } + slog.Debug("mbrs", "validatormbr", mbrs.AddValidatorMbr) + + // Pay the mbr to add a validator then wrap for use in ATC. + paymentTxn, err := transaction.MakePaymentTxn(ownerAddr.String(), crypto.GetApplicationAddress(r.RetiAppId).String(), mbrs.AddValidatorMbr, nil, "", params) + payTxWithSigner := transaction.TransactionWithSigner{ + Txn: paymentTxn, + Signer: algo.SignWithAccountForATC(r.signer, ownerAddr.String()), + } + + err = atc.AddMethodCall(transaction.AddMethodCallParams{ + AppID: r.RetiAppId, + Method: addValidatorMethod, + MethodArgs: []any{ + // MBR payment + payTxWithSigner, + // -- + nfdName, + []any{ + 0, // id is ignored and assigned by contract + ownerAddr, + managerAddr, + info.Config.NFDForInfo, + 0, // gating type none + [32]byte{}, + info.Config.GatingAssetMinBalance, + info.Config.RewardTokenId, + info.Config.RewardPerPayout, + uint16(info.Config.PayoutEveryXMins), + uint16(info.Config.PercentToValidator), + commissionAddr, + info.Config.MinEntryStake, + info.Config.MaxAlgoPerPool, + uint8(info.Config.PoolsPerNode), + info.Config.SunsettingOn, + info.Config.SunsettingTo, + }, + }, + BoxReferences: []types.AppBoxReference{ + {AppID: 0, Name: GetValidatorListBoxName(curValidatorId + 1)}, + {AppID: 0, Name: GetValidatorListBoxName(curValidatorId + 2)}, + {AppID: 0, Name: nil}, // extra i/o + }, + SuggestedParams: params, + OnComplete: types.NoOpOC, + Sender: ownerAddr, + Signer: algo.SignWithAccountForATC(r.signer, ownerAddr.String()), + }) + if err != nil { + return 0, fmt.Errorf("error in atc compose: %w", err) + } + + result, err := atc.Execute(r.algoClient, context.Background(), 4) + if err != nil { + return 0, err + } + if validatorId, ok := result.MethodResults[0].ReturnValue.(uint64); ok { + return validatorId, nil + } + return 0, nil +} + +func (r *Reti) GetProtocolConstraints() (*ProtocolConstraints, error) { + var err error + + params, err := r.algoClient.SuggestedParams().Do(context.Background()) + if err != nil { + return nil, err + } + + dummyAddr, err := r.getLocalSignerForSimulateCalls() + if err != nil { + return nil, err + } + // Now try to actually create the validator !! + atc := transaction.AtomicTransactionComposer{} + + method, _ := r.validatorContract.GetMethodByName("getProtocolConstraints") + atc.AddMethodCall(transaction.AddMethodCallParams{ + AppID: r.RetiAppId, + Method: method, + MethodArgs: []any{}, + SuggestedParams: params, + OnComplete: types.NoOpOC, + Sender: dummyAddr, + Signer: transaction.EmptyTransactionSigner{}, + }) + + result, err := atc.Simulate(context.Background(), r.algoClient, models.SimulateRequest{ + AllowEmptySignatures: true, + AllowUnnamedResources: true, + }) + if err != nil { + return nil, err + } + if result.SimulateResponse.TxnGroups[0].FailureMessage != "" { + return nil, fmt.Errorf("error retrieving protocol constraints: %s", result.SimulateResponse.TxnGroups[0].FailureMessage) + } + return ProtocolConstraintsFromABIReturn(result.MethodResults[0].ReturnValue) +} + +func (r *Reti) GetValidatorConfig(id uint64) (*ValidatorConfig, error) { + var err error + + params, err := r.algoClient.SuggestedParams().Do(context.Background()) + if err != nil { + return nil, err + } + + dummyAddr, err := r.getLocalSignerForSimulateCalls() + if err != nil { + return nil, err + } + // Now try to actually create the validator !! + atc := transaction.AtomicTransactionComposer{} + + method, err := r.validatorContract.GetMethodByName("getValidatorConfig") + if err != nil { + return nil, err + } + atc.AddMethodCall(transaction.AddMethodCallParams{ + AppID: r.RetiAppId, + Method: method, + MethodArgs: []any{id}, + BoxReferences: []types.AppBoxReference{ + {AppID: 0, Name: GetValidatorListBoxName(id)}, + {AppID: 0, Name: nil}, // extra i/o + }, + SuggestedParams: params, + OnComplete: types.NoOpOC, + Sender: dummyAddr, + Signer: transaction.EmptyTransactionSigner{}, + }) + + result, err := atc.Simulate(context.Background(), r.algoClient, models.SimulateRequest{ + AllowEmptySignatures: true, + AllowUnnamedResources: true, + }) + if err != nil { + return nil, err + } + if result.SimulateResponse.TxnGroups[0].FailureMessage != "" { + return nil, fmt.Errorf("error retrieving validator config: %s", result.SimulateResponse.TxnGroups[0].FailureMessage) + } + return ValidatorConfigFromABIReturn(result.MethodResults[0].ReturnValue) +} + +func (r *Reti) GetValidatorState(id uint64) (*ValidatorCurState, error) { + var err error + + params, err := r.algoClient.SuggestedParams().Do(context.Background()) + if err != nil { + return nil, err + } + + dummyAddr, err := r.getLocalSignerForSimulateCalls() + if err != nil { + return nil, err + } + + // Now try to actually create the validator !! + atc := transaction.AtomicTransactionComposer{} + + method, err := r.validatorContract.GetMethodByName("getValidatorState") + if err != nil { + return nil, err + } + atc.AddMethodCall(transaction.AddMethodCallParams{ + AppID: r.RetiAppId, + Method: method, + MethodArgs: []any{id}, + BoxReferences: []types.AppBoxReference{ + {AppID: 0, Name: GetValidatorListBoxName(id)}, + {AppID: 0, Name: nil}, // extra i/o + }, + SuggestedParams: params, + OnComplete: types.NoOpOC, + Sender: dummyAddr, + Signer: transaction.EmptyTransactionSigner{}, + }) + + result, err := atc.Simulate(context.Background(), r.algoClient, models.SimulateRequest{ + AllowEmptySignatures: true, + AllowUnnamedResources: true, + }) + if err != nil { + return nil, err + } + return ValidatorCurStateFromABIReturn(result.MethodResults[0].ReturnValue) +} + +func (r *Reti) GetValidatorPools(id uint64) ([]PoolInfo, error) { + var err error + + params, err := r.algoClient.SuggestedParams().Do(context.Background()) + if err != nil { + return nil, err + } + + dummyAddr, err := r.getLocalSignerForSimulateCalls() + if err != nil { + return nil, err + } + + // Now try to actually create the validator !! + atc := transaction.AtomicTransactionComposer{} + + getPoolInfoMethod, err := r.validatorContract.GetMethodByName("getPools") + if err != nil { + return nil, err + } + atc.AddMethodCall(transaction.AddMethodCallParams{ + AppID: r.RetiAppId, + Method: getPoolInfoMethod, + MethodArgs: []any{id}, + BoxReferences: []types.AppBoxReference{ + {AppID: 0, Name: GetValidatorListBoxName(id)}, + {AppID: 0, Name: nil}, // extra i/o + }, + SuggestedParams: params, + OnComplete: types.NoOpOC, + Sender: dummyAddr, + Signer: transaction.EmptyTransactionSigner{}, + }) + + result, err := atc.Simulate(context.Background(), r.algoClient, models.SimulateRequest{ + AllowEmptySignatures: true, + AllowMoreLogging: true, + AllowUnnamedResources: true, + }) + if err != nil { + return nil, err + } + return ValidatorPoolsFromABIReturn(result.MethodResults[0].ReturnValue) +} + +func (r *Reti) GetValidatorPoolInfo(poolKey ValidatorPoolKey) (*PoolInfo, error) { + var err error + + params, err := r.algoClient.SuggestedParams().Do(context.Background()) + if err != nil { + return nil, err + } + + dummyAddr, err := r.getLocalSignerForSimulateCalls() + if err != nil { + return nil, err + } + + // Now try to actually create the validator !! + atc := transaction.AtomicTransactionComposer{} + + getPoolInfoMethod, _ := r.validatorContract.GetMethodByName("getPoolInfo") + _ = atc.AddMethodCall(transaction.AddMethodCallParams{ + AppID: r.RetiAppId, + Method: getPoolInfoMethod, + MethodArgs: []any{poolKey.ID, poolKey.PoolId, poolKey.PoolAppId}, + ForeignApps: []uint64{poolKey.PoolAppId}, + BoxReferences: []types.AppBoxReference{ + {AppID: 0, Name: GetValidatorListBoxName(poolKey.PoolAppId)}, + {AppID: 0, Name: nil}, // extra i/o + }, + SuggestedParams: params, + OnComplete: types.NoOpOC, + Sender: dummyAddr, + Signer: transaction.EmptyTransactionSigner{}, + }) + + result, err := atc.Simulate(context.Background(), r.algoClient, models.SimulateRequest{ + AllowEmptySignatures: true, + AllowUnnamedResources: true, + }) + if err != nil { + return nil, err + } + return ValidatorPoolInfoFromABIReturn(result.MethodResults[0].ReturnValue) +} + +func (r *Reti) GetStakedPoolsForAccount(staker types.Address) ([]*ValidatorPoolKey, error) { + params, err := r.algoClient.SuggestedParams().Do(context.Background()) + if err != nil { + return nil, err + } + + method, err := r.validatorContract.GetMethodByName("getStakedPoolsForAccount") + if err != nil { + return nil, err + } + atc := transaction.AtomicTransactionComposer{} + atc.AddMethodCall(transaction.AddMethodCallParams{ + AppID: r.RetiAppId, + Method: method, + MethodArgs: []any{staker}, + SuggestedParams: params, + OnComplete: types.NoOpOC, + Sender: staker, + Signer: transaction.EmptyTransactionSigner{}, + }) + result, err := atc.Simulate(context.Background(), r.algoClient, models.SimulateRequest{ + AllowEmptySignatures: true, + AllowUnnamedResources: true, + }) + if err != nil { + return nil, err + } + if result.SimulateResponse.TxnGroups[0].FailureMessage != "" { + return nil, errors.New(result.SimulateResponse.TxnGroups[0].FailureMessage) + } + var retPools []*ValidatorPoolKey + if arrReturn, ok := result.MethodResults[0].ReturnValue.([]any); ok { + for _, poolInfoAny := range arrReturn { + poolKey, err := ValidatorPoolKeyFromABIReturn(poolInfoAny) + if err != nil { + return nil, err + } + retPools = append(retPools, poolKey) + } + return retPools, nil + } + + return nil, fmt.Errorf("unknown result type:%#v", result.MethodResults) +} + +func (r *Reti) GetValidatorNodePoolAssignments(id uint64) (*NodePoolAssignmentConfig, error) { + var err error + + params, err := r.algoClient.SuggestedParams().Do(context.Background()) + if err != nil { + return nil, err + } + + dummyAddr, err := r.getLocalSignerForSimulateCalls() + if err != nil { + return nil, err + } + + // Now try to actually create the validator !! + atc := transaction.AtomicTransactionComposer{} + + getNodePoolAssignmentsMethod, err := r.validatorContract.GetMethodByName("getNodePoolAssignments") + if err != nil { + return nil, err + } + atc.AddMethodCall(transaction.AddMethodCallParams{ + AppID: r.RetiAppId, + Method: getNodePoolAssignmentsMethod, + MethodArgs: []any{id}, + BoxReferences: []types.AppBoxReference{ + {AppID: 0, Name: GetValidatorListBoxName(id)}, + {AppID: 0, Name: nil}, // extra i/o + }, + SuggestedParams: params, + OnComplete: types.NoOpOC, + Sender: dummyAddr, + Signer: transaction.EmptyTransactionSigner{}, + }) + + result, err := atc.Simulate(context.Background(), r.algoClient, models.SimulateRequest{ + AllowEmptySignatures: true, + AllowMoreLogging: true, + AllowUnnamedResources: true, + }) + if err != nil { + return nil, err + } + return NodePoolAssignmentFromABIReturn(result.MethodResults[0].ReturnValue) +} + +func NodePoolAssignmentFromABIReturn(returnVal any) (*NodePoolAssignmentConfig, error) { + var retPAC = &NodePoolAssignmentConfig{} + if arrReturn, ok := returnVal.([]any); ok { + for _, nodeConfigAny := range arrReturn { + if nodes, ok := nodeConfigAny.([]any); ok { + for _, pools := range nodes { + if poolIDs, ok := pools.([]any); ok { + var ids []uint64 + for _, id := range poolIDs[0].([]any) { + convertedID := id.(uint64) + if convertedID == 0 { + continue + } + ids = append(ids, convertedID) + } + retPAC.Nodes = append(retPAC.Nodes, NodeConfig{PoolAppIds: ids}) + } + } + } + } + return retPAC, nil + } + return nil, ErrCantFetchPoolKey +} + +func (r *Reti) FindPoolForStaker(id uint64, staker types.Address, amount uint64) (*ValidatorPoolKey, error) { + params, err := r.algoClient.SuggestedParams().Do(context.Background()) + if err != nil { + return nil, err + } + + findPoolMethod, _ := r.validatorContract.GetMethodByName("findPoolForStaker") + atc := transaction.AtomicTransactionComposer{} + atc.AddMethodCall(transaction.AddMethodCallParams{ + AppID: r.RetiAppId, + Method: findPoolMethod, + MethodArgs: []any{id, staker, amount}, + SuggestedParams: params, + OnComplete: types.NoOpOC, + Sender: staker, + Signer: transaction.EmptyTransactionSigner{}, + }) + result, err := atc.Simulate(context.Background(), r.algoClient, models.SimulateRequest{ + AllowEmptySignatures: true, + AllowUnnamedResources: true, + }) + if err != nil { + return nil, err + } + if result.SimulateResponse.TxnGroups[0].FailureMessage != "" { + return nil, errors.New(result.SimulateResponse.TxnGroups[0].FailureMessage) + } + // findPoolForStaker returns [ValidatorPoolKey, boolean] + return ValidatorPoolKeyFromABIReturn(result.MethodResults[0].ReturnValue.([]any)[0]) +} + +func (r *Reti) ChangeValidatorCommissionAddress(id uint64, sender types.Address, commissionAddress types.Address) error { + var err error + + params, err := r.algoClient.SuggestedParams().Do(context.Background()) + if err != nil { + return err + } + + atc := transaction.AtomicTransactionComposer{} + + changeAddressMethod, _ := r.validatorContract.GetMethodByName("changeValidatorCommissionAddress") + // We have to pay MBR into the Validator contract itself for adding a pool + atc.AddMethodCall(transaction.AddMethodCallParams{ + AppID: r.RetiAppId, + Method: changeAddressMethod, + MethodArgs: []any{ + id, + commissionAddress, + }, + ForeignApps: []uint64{r.poolTemplateAppId()}, + BoxReferences: []types.AppBoxReference{ + {AppID: 0, Name: GetValidatorListBoxName(id)}, + {AppID: 0, Name: nil}, // extra i/o + }, + SuggestedParams: params, + OnComplete: types.NoOpOC, + Sender: sender, + Signer: algo.SignWithAccountForATC(r.signer, sender.String()), + }) + _, err = atc.Execute(r.algoClient, context.Background(), 4) + if err != nil { + return err + } + + return nil + +} + +func (r *Reti) AddStakingPool(nodeNum uint64) (*ValidatorPoolKey, error) { + var ( + info = r.Info() + err error + ) + + params, err := r.algoClient.SuggestedParams().Do(context.Background()) + if err != nil { + return nil, err + } + + managerAddr, _ := types.DecodeAddress(info.Config.Manager) + + // first determine how much we have to add in MBR to the validator for adding a staking pool + mbrs, err := r.getMbrAmounts(managerAddr) + if err != nil { + return nil, err + } + + // Now try to actually create the pool !! + atc := transaction.AtomicTransactionComposer{} + + misc.Infof(r.Logger, "adding staking pool to node:%d", nodeNum) + addPoolMethod, _ := r.validatorContract.GetMethodByName("addPool") + // We have to pay MBR into the Validator contract itself for adding a pool + paymentTxn, err := transaction.MakePaymentTxn(managerAddr.String(), crypto.GetApplicationAddress(r.RetiAppId).String(), mbrs.AddPoolMbr, nil, "", params) + payTxWithSigner := transaction.TransactionWithSigner{ + Txn: paymentTxn, + Signer: algo.SignWithAccountForATC(r.signer, managerAddr.String()), + } + + params.FlatFee = true + params.Fee = types.MicroAlgos(max(uint64(params.MinFee), 1000) + params.MinFee) + + atc.AddMethodCall(transaction.AddMethodCallParams{ + AppID: r.RetiAppId, + Method: addPoolMethod, + MethodArgs: []any{ + // MBR payment + payTxWithSigner, + // -- + info.Config.ID, + nodeNum, + }, + ForeignApps: []uint64{r.poolTemplateAppId()}, + BoxReferences: []types.AppBoxReference{ + {AppID: 0, Name: GetValidatorListBoxName(info.Config.ID)}, + {AppID: 0, Name: nil}, // extra i/o + }, + SuggestedParams: params, + OnComplete: types.NoOpOC, + Sender: managerAddr, + Signer: algo.SignWithAccountForATC(r.signer, managerAddr.String()), + }) + result, err := atc.Execute(r.algoClient, context.Background(), 4) + if err != nil { + return nil, err + } + + poolKey, err := ValidatorPoolKeyFromABIReturn(result.MethodResults[0].ReturnValue) + if err != nil { + return nil, err + } + + err = r.CheckAndInitStakingPoolStorage(poolKey) + if err != nil { + return nil, err + } + + return poolKey, err +} + +func (r *Reti) MovePoolToNode(poolAppId uint64, nodeNum uint64) error { + var ( + info = r.Info() + err error + ) + + params, err := r.algoClient.SuggestedParams().Do(context.Background()) + if err != nil { + return err + } + + managerAddr, _ := types.DecodeAddress(info.Config.Manager) + + atc := transaction.AtomicTransactionComposer{} + misc.Infof(r.Logger, "trying to move pool app id:%d to node number:%d", poolAppId, nodeNum) + movePoolMethod, _ := r.validatorContract.GetMethodByName("movePoolToNode") + + // pay for go offline call as well + params.FlatFee = true + params.Fee = types.MicroAlgos(max(uint64(params.MinFee), 1000) + (2 * params.MinFee)) + + atc.AddMethodCall(transaction.AddMethodCallParams{ + AppID: r.RetiAppId, + Method: movePoolMethod, + MethodArgs: []any{ + info.Config.ID, + poolAppId, + nodeNum, + }, + ForeignApps: []uint64{ + r.poolTemplateAppId(), + poolAppId, + }, + BoxReferences: []types.AppBoxReference{ + {AppID: 0, Name: GetValidatorListBoxName(info.Config.ID)}, + {AppID: 0, Name: nil}, // extra i/o + }, + SuggestedParams: params, + OnComplete: types.NoOpOC, + Sender: managerAddr, + Signer: algo.SignWithAccountForATC(r.signer, managerAddr.String()), + }) + _, err = atc.Execute(r.algoClient, context.Background(), 4) + if err != nil { + return err + } + return nil +} + +func (r *Reti) CheckAndInitStakingPoolStorage(poolKey *ValidatorPoolKey) error { + // First determine if we NEED to initialize this pool ! + if val, err := r.algoClient.GetApplicationBoxByName(poolKey.PoolAppId, GetStakerLedgerBoxName()).Do(context.Background()); err == nil { + if len(val.Value) > 0 { + // we have value already - we're already initialized. + return nil + } + } + + params, err := r.algoClient.SuggestedParams().Do(context.Background()) + if err != nil { + return err + } + + managerAddr, _ := types.DecodeAddress(r.Info().Config.Manager) + + mbrs, err := r.getMbrAmounts(managerAddr) + if err != nil { + return err + } + + // Now we have to pay MBR into the staking pool itself (!) and tell it to initialize itself + gasMethod, _ := r.poolContract.GetMethodByName("gas") + initStorageMethod, _ := r.poolContract.GetMethodByName("initStorage") + + misc.Infof(r.Logger, "initializing staking pool storage, mbr payment to pool:%s", algo.FormattedAlgoAmount(mbrs.PoolInitMbr)) + atc := transaction.AtomicTransactionComposer{} + paymentTxn, err := transaction.MakePaymentTxn(managerAddr.String(), crypto.GetApplicationAddress(poolKey.PoolAppId).String(), mbrs.PoolInitMbr, nil, "", params) + payTxWithSigner := transaction.TransactionWithSigner{ + Txn: paymentTxn, + Signer: algo.SignWithAccountForATC(r.signer, managerAddr.String()), + } + // we need to stack up references in this gas method for resource pooling + atc.AddMethodCall(transaction.AddMethodCallParams{ + AppID: poolKey.PoolAppId, + Method: gasMethod, + BoxReferences: []types.AppBoxReference{ + {AppID: r.RetiAppId, Name: GetValidatorListBoxName(poolKey.ID)}, + {AppID: 0, Name: GetStakerLedgerBoxName()}, + {AppID: 0, Name: nil}, // extra i/o + {AppID: 0, Name: nil}, // extra i/o + {AppID: 0, Name: nil}, // extra i/o + {AppID: 0, Name: nil}, // extra i/o + }, + ForeignApps: []uint64{r.RetiAppId}, + SuggestedParams: params, + OnComplete: types.NoOpOC, + Sender: managerAddr, + Signer: algo.SignWithAccountForATC(r.signer, managerAddr.String()), + }) + params.FlatFee = true + params.Fee = 3 * transaction.MinTxnFee + atc.AddMethodCall(transaction.AddMethodCallParams{ + AppID: poolKey.PoolAppId, + Method: initStorageMethod, + MethodArgs: []any{ + // MBR payment + payTxWithSigner, + }, + BoxReferences: []types.AppBoxReference{ + {AppID: 0, Name: nil}, // extra i/o + {AppID: 0, Name: nil}, // extra i/o + {AppID: 0, Name: nil}, // extra i/o + {AppID: 0, Name: nil}, // extra i/o + {AppID: 0, Name: nil}, // extra i/o + {AppID: 0, Name: nil}, // extra i/o + {AppID: 0, Name: nil}, // extra i/o + {AppID: 0, Name: nil}, // extra i/o + }, + SuggestedParams: params, + OnComplete: types.NoOpOC, + Sender: managerAddr, + Signer: algo.SignWithAccountForATC(r.signer, managerAddr.String()), + }) + _, err = atc.Execute(r.algoClient, context.Background(), 4) + if err != nil { + return err + } + return nil +} + +func (r *Reti) AddStake(validatorId uint64, staker types.Address, amount uint64, assetIDToCheck uint64) (*ValidatorPoolKey, error) { + var ( + err error + amountToStake = uint64(amount) + ) + + params, err := r.algoClient.SuggestedParams().Do(context.Background()) + if err != nil { + return nil, err + } + + // first determine how much we might have to add in MBR if this is a first-time staker + mbrs, err := r.getMbrAmounts(staker) + if err != nil { + return nil, err + } + + mbrPaymentNeeded, err := r.doesStakerNeedToPayMBR(staker) + if err != nil { + return nil, err + } + if mbrPaymentNeeded { + misc.Infof(r.Logger, "Adding %s ALGO to stake to cover first-time MBR", algo.FormattedAlgoAmount(mbrs.AddStakerMbr)) + amountToStake += mbrs.AddStakerMbr + } + + // Because we can't do easy simulate->execute in Go we have to figure out the references ourselves which means we need to know in advance + // what staking pool we'll go to. So we can just ask validator to find the pool for us and then use that (some small race conditions obviously) + futurePoolKey, err := r.FindPoolForStaker(validatorId, staker, amount) + if err != nil { + return nil, err + } + + getAtc := func(feesToUse uint64) (transaction.AtomicTransactionComposer, error) { + atc := transaction.AtomicTransactionComposer{} + gasMethod, _ := r.validatorContract.GetMethodByName("gas") + stakeMethod, _ := r.validatorContract.GetMethodByName("addStake") + + params.FlatFee = true + params.Fee = transaction.MinTxnFee + + paymentTxn, err := transaction.MakePaymentTxn(staker.String(), crypto.GetApplicationAddress(r.RetiAppId).String(), amountToStake, nil, "", params) + payTxWithSigner := transaction.TransactionWithSigner{ + Txn: paymentTxn, + Signer: algo.SignWithAccountForATC(r.signer, staker.String()), + } + + // we need to stack up references in this gas method for resource pooling + err = atc.AddMethodCall(transaction.AddMethodCallParams{ + AppID: r.RetiAppId, + Method: gasMethod, + BoxReferences: []types.AppBoxReference{ + {AppID: 0, Name: GetValidatorListBoxName(validatorId)}, + {AppID: 0, Name: nil}, // extra i/o + {AppID: 0, Name: nil}, // extra i/o + {AppID: 0, Name: nil}, // extra i/o + {AppID: 0, Name: nil}, // extra i/o + {AppID: 0, Name: nil}, // extra i/o + {AppID: 0, Name: GetStakerPoolSetBoxName(staker)}, + }, + SuggestedParams: params, + OnComplete: types.NoOpOC, + Sender: staker, + Signer: algo.SignWithAccountForATC(r.signer, staker.String()), + }) + if err != nil { + return atc, err + } + if feesToUse == 0 { + // we're simulating so go with super high budget + feesToUse = 240 * transaction.MinTxnFee + } + params.FlatFee = true + params.Fee = types.MicroAlgos(feesToUse) + err = atc.AddMethodCall(transaction.AddMethodCallParams{ + AppID: r.RetiAppId, + Method: stakeMethod, + MethodArgs: []any{ + // MBR payment + payTxWithSigner, + // -- + validatorId, + assetIDToCheck, + }, + ForeignApps: []uint64{futurePoolKey.PoolAppId}, + BoxReferences: []types.AppBoxReference{ + {AppID: futurePoolKey.PoolAppId, Name: GetStakerLedgerBoxName()}, + {AppID: 0, Name: nil}, // extra i/o + {AppID: 0, Name: nil}, // extra i/o + {AppID: 0, Name: nil}, // extra i/o + {AppID: 0, Name: nil}, // extra i/o + {AppID: 0, Name: nil}, // extra i/o + {AppID: 0, Name: nil}, // extra i/o + }, + SuggestedParams: params, + OnComplete: types.NoOpOC, + Sender: staker, + Signer: algo.SignWithAccountForATC(r.signer, staker.String()), + }) + if err != nil { + return atc, err + } + return atc, err + } + + // simulate first + atc, err := getAtc(0) + if err != nil { + return nil, err + } + simResult, err := atc.Simulate(context.Background(), r.algoClient, models.SimulateRequest{ + AllowEmptySignatures: true, + AllowUnnamedResources: true, + }) + if err != nil { + return nil, err + } + if simResult.SimulateResponse.TxnGroups[0].FailureMessage != "" { + return nil, errors.New(simResult.SimulateResponse.TxnGroups[0].FailureMessage) + } + // Figure out how much app budget was added so we can know the real fees to use when we execute + atc, err = getAtc(2*transaction.MinTxnFee + transaction.MinTxnFee*(simResult.SimulateResponse.TxnGroups[0].AppBudgetAdded/700)) + if err != nil { + return nil, err + } + + result, err := atc.Execute(r.algoClient, context.Background(), 4) + if err != nil { + return nil, err + } + return ValidatorPoolKeyFromABIReturn(result.MethodResults[1].ReturnValue) +} + +func (r *Reti) RemoveStake(poolKey ValidatorPoolKey, staker types.Address, amount uint64) error { + var err error + + params, err := r.algoClient.SuggestedParams().Do(context.Background()) + if err != nil { + return err + } + + getAtc := func(feesToUse uint64) (transaction.AtomicTransactionComposer, error) { + atc := transaction.AtomicTransactionComposer{} + gasMethod, _ := r.validatorContract.GetMethodByName("gas") + unstakeMethod, _ := r.poolContract.GetMethodByName("removeStake") + + params.FlatFee = true + params.Fee = transaction.MinTxnFee + + // we need to stack up references in this gas method for resource pooling + err = atc.AddMethodCall(transaction.AddMethodCallParams{ + AppID: r.RetiAppId, + Method: gasMethod, + BoxReferences: []types.AppBoxReference{ + {AppID: r.RetiAppId, Name: GetValidatorListBoxName(poolKey.ID)}, + {AppID: r.RetiAppId, Name: nil}, // extra i/o + {AppID: r.RetiAppId, Name: GetStakerPoolSetBoxName(staker)}, + }, + SuggestedParams: params, + OnComplete: types.NoOpOC, + Sender: staker, + Signer: algo.SignWithAccountForATC(r.signer, staker.String()), + }) + if err != nil { + return atc, err + } + if feesToUse == 0 { + // we're simulating so go with super high budget + feesToUse = 240 * transaction.MinTxnFee + } + params.FlatFee = true + params.Fee = types.MicroAlgos(feesToUse) + err = atc.AddMethodCall(transaction.AddMethodCallParams{ + AppID: poolKey.PoolAppId, + Method: unstakeMethod, + MethodArgs: []any{ + amount, + }, + ForeignApps: []uint64{poolKey.PoolAppId}, + BoxReferences: []types.AppBoxReference{ + {AppID: 0, Name: GetStakerLedgerBoxName()}, + {AppID: 0, Name: nil}, // extra i/o + {AppID: 0, Name: nil}, // extra i/o + {AppID: 0, Name: nil}, // extra i/o + {AppID: 0, Name: nil}, // extra i/o + {AppID: 0, Name: nil}, // extra i/o + {AppID: 0, Name: nil}, // extra i/o + }, + SuggestedParams: params, + OnComplete: types.NoOpOC, + Sender: staker, + Signer: algo.SignWithAccountForATC(r.signer, staker.String()), + }) + if err != nil { + return atc, err + } + return atc, err + } + + // simulate first + atc, err := getAtc(0) + if err != nil { + return err + } + simResult, err := atc.Simulate(context.Background(), r.algoClient, models.SimulateRequest{ + AllowEmptySignatures: true, + AllowUnnamedResources: true, + }) + if err != nil { + return err + } + if simResult.SimulateResponse.TxnGroups[0].FailureMessage != "" { + return errors.New(simResult.SimulateResponse.TxnGroups[0].FailureMessage) + } + // Figure out how much app budget was added so we can know the real fees to use when we execute + atc, err = getAtc(2*transaction.MinTxnFee + transaction.MinTxnFee*(simResult.SimulateResponse.TxnGroups[0].AppBudgetAdded/700)) + if err != nil { + return err + } + + _, err = atc.Execute(r.algoClient, context.Background(), 4) + if err != nil { + return err + } + return nil +} + +type MbrAmounts struct { + AddValidatorMbr uint64 + AddPoolMbr uint64 + PoolInitMbr uint64 + AddStakerMbr uint64 +} + +func (r *Reti) getMbrAmounts(caller types.Address) (MbrAmounts, error) { + params, err := r.algoClient.SuggestedParams().Do(context.Background()) + if err != nil { + return MbrAmounts{}, err + } + + method, err := r.validatorContract.GetMethodByName("getMbrAmounts") + if err != nil { + return MbrAmounts{}, err + } + atc := transaction.AtomicTransactionComposer{} + atc.AddMethodCall(transaction.AddMethodCallParams{ + AppID: r.RetiAppId, + Method: method, + SuggestedParams: params, + OnComplete: types.NoOpOC, + Sender: caller, + Signer: transaction.EmptyTransactionSigner{}, + }) + result, err := atc.Simulate(context.Background(), r.algoClient, models.SimulateRequest{ + AllowEmptySignatures: true, + AllowUnnamedResources: true, + }) + if err != nil { + return MbrAmounts{}, err + } + if result.SimulateResponse.TxnGroups[0].FailureMessage != "" { + return MbrAmounts{}, errors.New(result.SimulateResponse.TxnGroups[0].FailureMessage) + } + + if results, ok := result.MethodResults[0].ReturnValue.([]any); ok { + if len(results) != 4 { + return MbrAmounts{}, errors.New("invalid number of results") + } + var mbrs MbrAmounts + mbrs.AddValidatorMbr = results[0].(uint64) + mbrs.AddPoolMbr = results[1].(uint64) + mbrs.PoolInitMbr = results[2].(uint64) + mbrs.AddStakerMbr = results[3].(uint64) + return mbrs, nil + } + return MbrAmounts{}, fmt.Errorf("unknown result type:%#v", result.MethodResults) +} + +func (r *Reti) doesStakerNeedToPayMBR(staker types.Address) (bool, error) { + params, err := r.algoClient.SuggestedParams().Do(context.Background()) + if err != nil { + return false, err + } + + method, err := r.validatorContract.GetMethodByName("doesStakerNeedToPayMBR") + if err != nil { + return false, err + } + atc := transaction.AtomicTransactionComposer{} + atc.AddMethodCall(transaction.AddMethodCallParams{ + AppID: r.RetiAppId, + Method: method, + MethodArgs: []any{staker}, + SuggestedParams: params, + OnComplete: types.NoOpOC, + Sender: staker, + Signer: transaction.EmptyTransactionSigner{}, + }) + result, err := atc.Simulate(context.Background(), r.algoClient, models.SimulateRequest{ + AllowEmptySignatures: true, + AllowUnnamedResources: true, + }) + if err != nil { + return false, err + } + val := result.MethodResults[0].ReturnValue + if boolReturn, ok := val.(bool); ok { + return boolReturn, nil + } + return false, errors.New("unknown return value from doesStakerNeedToPayMBR") +} + +func (r *Reti) getNumValidators() (uint64, error) { + appInfo, err := r.algoClient.GetApplicationByID(r.RetiAppId).Do(context.Background()) + if err != nil { + return 0, err + } + return algo.GetIntFromGlobalState(appInfo.Params.GlobalState, VldtrNumValidators) +} + +func (r *Reti) poolTemplateAppId() uint64 { + return r.poolTmplAppId +} diff --git a/nodemgr/keycmds.go b/nodemgr/keycmds.go new file mode 100644 index 00000000..8b0eb593 --- /dev/null +++ b/nodemgr/keycmds.go @@ -0,0 +1,71 @@ +package main + +import ( + "context" + "encoding/base64" + "fmt" + + "github.com/algorand/go-algorand-sdk/v2/crypto" + "github.com/algorand/go-algorand-sdk/v2/types" + "github.com/urfave/cli/v3" + + "github.com/TxnLab/reti/internal/lib/algo" +) + +func GetKeyCmdOpts() *cli.Command { + return &cli.Command{ + Name: "key", + Aliases: []string{"k"}, + Usage: "Participation key related commands", + Before: checkConfigured, + Commands: []*cli.Command{ + { + Name: "list", + Aliases: []string{"l"}, + Usage: "List part keys on this node", + Action: KeysList, + Flags: []cli.Flag{ + &cli.BoolFlag{ + Name: "all", + Usage: "Show ALL pools for this validator not just for this node", + Value: false, + }, + }, + }, + }, + } +} + +func KeysList(ctx context.Context, command *cli.Command) error { + partKeys, err := algo.GetParticipationKeys(ctx, App.algoClient) + if err != nil { + return err + } + for _, poolAppID := range App.retiClient.Info().LocalPools { + addr := crypto.GetApplicationAddress(poolAppID) + for account, keys := range partKeys { + if !command.Bool("all") && addr.String() != account { + continue + } + for _, key := range keys { + selkey, _ := types.EncodeAddress(key.Key.SelectionParticipationKey) + stproofKey := base64.StdEncoding.EncodeToString(key.Key.StateProofKey) + votekey, _ := types.EncodeAddress(key.Key.VoteParticipationKey) + fmt.Println("id:", key.Id) + fmt.Println("Address:", key.Address) + fmt.Println("Vote First Valid:", key.Key.VoteFirstValid) + fmt.Println("Vote Last Valid:", key.Key.VoteLastValid) + fmt.Println("Effective First Valid:", key.EffectiveFirstValid) + fmt.Println("Effective Last Valid:", key.EffectiveLastValid) + fmt.Println("Vote Key Dilution:", key.Key.VoteKeyDilution) + fmt.Println("Selection Participation Key:", selkey) + fmt.Println("state Proof Key:", stproofKey) + fmt.Println("Vote Participation Key:", votekey) + fmt.Println("Last Vote:", key.LastVote) + fmt.Println("Last Block Proposal:", key.LastBlockProposal) + fmt.Println() + } + } + } + return nil +} diff --git a/nodemgr/main.go b/nodemgr/main.go new file mode 100644 index 00000000..461201a0 --- /dev/null +++ b/nodemgr/main.go @@ -0,0 +1,22 @@ +package main + +import ( + "context" + "log/slog" + "os" + + "github.com/TxnLab/reti/internal/lib/misc" +) + +var App *RetiApp + +func main() { + App = initApp() + + misc.LoadEnvSettings() + err := App.cliCmd.Run(context.Background(), os.Args) + if err != nil { + slog.Error("Error in execution:", "msg", err) + os.Exit(1) + } +} diff --git a/nodemgr/poolcmds.go b/nodemgr/poolcmds.go new file mode 100644 index 00000000..9c22581f --- /dev/null +++ b/nodemgr/poolcmds.go @@ -0,0 +1,449 @@ +package main + +import ( + "bytes" + "context" + "fmt" + "log/slog" + "strconv" + "strings" + "text/tabwriter" + "time" + + "github.com/algorand/go-algorand-sdk/v2/crypto" + "github.com/algorand/go-algorand-sdk/v2/types" + "github.com/urfave/cli/v3" + + "github.com/TxnLab/reti/internal/lib/algo" + "github.com/TxnLab/reti/internal/lib/misc" + "github.com/TxnLab/reti/internal/lib/reti" +) + +func GetPoolCmdOpts() *cli.Command { + return &cli.Command{ + Name: "pool", + Aliases: []string{"p"}, + Usage: "Add/Configure staking pools for this node", + Before: checkConfigured, + Commands: []*cli.Command{ + { + Name: "list", + Aliases: []string{"l"}, + Usage: "List pools on this node", + Action: PoolsList, + Flags: []cli.Flag{ + &cli.BoolFlag{ + Name: "all", + Usage: "Show ALL pools for this validator not just for this node", + Value: false, + }, + &cli.BoolFlag{ + Name: "offline", + Aliases: []string{"o"}, + Usage: "Don't try to connect to the algod nodes to determine status", + Value: false, + }, + }, + }, + { + Name: "ledger", + Aliases: []string{"l"}, + Usage: "List detailed ledger for a specific pool", + Action: PoolLedger, + Flags: []cli.Flag{ + &cli.UintFlag{ + Name: "pool", + Usage: "Pool id (the number in 'pool list')", + Value: 1, + Required: true, + }, + }, + }, + { + Name: "add", + Aliases: []string{"a"}, + Usage: "Add a new staking pool to this node", + Category: "pool", + Action: PoolAdd, + Flags: []cli.Flag{ + &cli.UintFlag{ + Name: "node", + Usage: "The node number (1+) to add this pool to - defaults to current node", + Value: 0, + }, + }, + }, + { + Name: "claim", + Usage: "Claim an existing pool for this node, using manager address as verified. Signing keys must be present for this address to load", + Flags: []cli.Flag{ + &cli.UintFlag{ + Name: "pool", + Usage: "Pool id (the number in 'pool list' to claim for this node. Do NOT use the same pool on multiple nodes !!", + Required: true, + }, + }, + Action: ClaimPool, + }, + { + Name: "payout", + Usage: "Try to force a manual epoch update (payout). Normally happens automatically as part of daemon operations", + Flags: []cli.Flag{ + &cli.UintFlag{ + Name: "pool", + Usage: "Pool id (the number in 'pool list')", + Value: 1, + Required: true, + }, + }, + Action: PayoutPool, + }, + { + Name: "stake", + Usage: "Mostly for testing - but allows adding stake w/ a locally available account Add a new staking pool to this node", + Category: "pool", + Action: StakeAdd, + Flags: []cli.Flag{ + &cli.StringFlag{ + Name: "account", + Usage: "The account to send stake 'from' - the staker account.", + Required: true, + }, + &cli.UintFlag{ + Name: "amount", + Usage: "The amount of whole algo to stake", + Required: true, + }, + &cli.UintFlag{ + Name: "validator", + Aliases: []string{"v"}, + Usage: "The validator id to stake to", + Required: true, + }, + }, + }, + { + Name: "unstake", + Usage: "Mostly for testing - but allows adding stake w/ a locally available account Add a new staking pool to this node", + Category: "pool", + Action: StakeRemove, + Flags: []cli.Flag{ + &cli.StringFlag{ + Name: "account", + Usage: "The staker account wanting to remove stake", + Required: true, + }, + &cli.UintFlag{ + Name: "amount", + Usage: "The amount of whole algo to unstake", + Required: true, + }, + &cli.UintFlag{ + Name: "validator", + Aliases: []string{"v"}, + Usage: "The validator id stake is with", + Required: true, + }, + &cli.UintFlag{ + Name: "pool", + Aliases: []string{"p"}, + Usage: "The pool id to remove the stake from", + Required: true, + }, + }, + }, + }, + } +} + +func PoolsList(ctx context.Context, command *cli.Command) error { + // Display user-friendly version of pool list inside info using the TabWriter class, displaying + // final output using fmt.Print type statements + var ( + totalRewards uint64 + showAll = command.Bool("all") + offlineAlgod = command.Bool("offline") + info = App.retiClient.Info() + partKeys = algo.PartKeysByAddress{} + ) + + state, err := App.retiClient.GetValidatorState(App.retiClient.Info().Config.ID) + if err != nil { + return fmt.Errorf("failed to get validator state: %w", err) + } + + // we just want the latest round so we can show last vote/proposal relative to current round + status, err := App.algoClient.Status().Do(ctx) + + if !offlineAlgod { + partKeys, err = algo.GetParticipationKeys(ctx, App.algoClient) + if err != nil { + return err + } + } + getParticipationData := func(account string, selectionPartKey []byte) (uint64, uint64) { + if keys, found := partKeys[account]; found { + for _, key := range keys { + if bytes.Compare(key.Key.SelectionParticipationKey, selectionPartKey) == 0 { + return key.LastVote, key.LastBlockProposal + } + } + } + return 0, 0 + } + + out := new(strings.Builder) + tw := tabwriter.NewWriter(out, 0, 0, 2, ' ', tabwriter.AlignRight) + fmt.Fprintln(tw, "Viewing pools for our Node:", App.retiClient.NodeNum) + if !showAll { + fmt.Fprintln(tw, "Pool (O=Online)\tPool App id\t# stakers\tAmt Staked\tRwd Avail\tVote\tProp.\t") + } else { + fmt.Fprintln(tw, "Pool (O=Online)\tNode\tPool App id\t# stakers\tAmt Staked\tRwd Avail\tVote\tProp.\t") + + } + for i, pool := range info.Pools { + var ( + onlineStr = " " + nodeStr string + ) + // find the pool in the node assignments (so we can show node num if necessary) + nodeNum := 0 + for nodeIdx, nodeConfigs := range info.NodePoolAssignments.Nodes { + for _, appId := range nodeConfigs.PoolAppIds { + if appId == pool.PoolAppId { + nodeNum = nodeIdx + 1 + break + } + } + } + if nodeNum == 0 { + return fmt.Errorf("unable to determine node number for pool appid:%d", pool.PoolAppId) + } + if uint64(nodeNum) == App.retiClient.NodeNum { + nodeStr = "*" + } else if !showAll { + continue + } else { + nodeStr = strconv.Itoa(nodeNum) + } + acctInfo, err := algo.GetBareAccount(context.Background(), App.algoClient, crypto.GetApplicationAddress(pool.PoolAppId).String()) + if err != nil { + return fmt.Errorf("account fetch error, account:%s, err:%w", crypto.GetApplicationAddress(pool.PoolAppId).String(), err) + } + if acctInfo.Status == OnlineStatus { + onlineStr = "O" + } + + rewardAvail := App.retiClient.PoolAvailableRewards(pool.PoolAppId, pool.TotalAlgoStaked) + totalRewards += rewardAvail + + lastVote, lastProposal := getParticipationData(crypto.GetApplicationAddress(pool.PoolAppId).String(), acctInfo.Participation.SelectionParticipationKey) + var ( + voteData string + partData string + ) + if lastVote != 0 { + // round might get behind last vote/proposal so handle that as well. + if status.LastRound <= lastVote { + voteData = "latest" + } else { + voteData = fmt.Sprintf("-%d", status.LastRound-lastVote) + } + } + if lastProposal != 0 { + if status.LastRound <= lastProposal { + partData = "latest" + } else { + partData = fmt.Sprintf("-%d", status.LastRound-lastProposal) + } + } + if !showAll { + fmt.Fprintf(tw, "%d %s\t%d\t%d\t%s\t%s\t%s\t%s\t\n", i+1, onlineStr, pool.PoolAppId, pool.TotalStakers, + algo.FormattedAlgoAmount(pool.TotalAlgoStaked), algo.FormattedAlgoAmount(rewardAvail), + voteData, partData) + } else { + fmt.Fprintf(tw, "%d %s\t%s\t%d\t%d\t%s\t%s\t%s\t%s\t\n", i+1, onlineStr, nodeStr, pool.PoolAppId, pool.TotalStakers, + algo.FormattedAlgoAmount(pool.TotalAlgoStaked), algo.FormattedAlgoAmount(rewardAvail), + voteData, partData) + + } + } + fmt.Fprintf(tw, "TOTAL\t\t%d\t%s\t%s\t\n", state.TotalStakers, algo.FormattedAlgoAmount(state.TotalAlgoStaked), + algo.FormattedAlgoAmount(totalRewards)) + + tw.Flush() + fmt.Print(out.String()) + return err +} + +func PoolLedger(ctx context.Context, command *cli.Command) error { + var ( + nextPayTime time.Time + info = App.retiClient.Info() + epochDuration = time.Duration(info.Config.PayoutEveryXMins) * time.Minute + ) + poolId := int(command.Uint("pool")) + if poolId == 0 { + return fmt.Errorf("pool numbers must start at 1. See the pool list -all output for list") + } + if poolId > len(info.Pools) { + return fmt.Errorf("pool with id %d does not exist. See the pool list -all output for list", poolId) + } + + lastPayout, err := App.retiClient.GetLastPayout(info.Pools[poolId-1].PoolAppId) + if err == nil { + nextPayTime = time.Unix(int64(lastPayout), 0).Add(time.Duration(info.Config.PayoutEveryXMins) * time.Minute) + } else { + nextPayTime = time.Now() + } + if nextPayTime.Before(time.Now()) { + nextPayTime = time.Now() + } + pctTimeInEpoch := func(stakerEntryTime uint64) int { + entryTime := time.Unix(int64(stakerEntryTime), 0) + timeInEpoch := nextPayTime.Sub(entryTime).Seconds() / epochDuration.Seconds() * 100 + if timeInEpoch < 0 { + // they're past the epoch because of entry time + 320 rounds (~16mins) + timeInEpoch = 0 + } + if timeInEpoch > 100 { + timeInEpoch = 100 + } + return int(timeInEpoch) + } + + ledger, err := App.retiClient.GetLedgerforPool(info.Pools[poolId-1].PoolAppId) + if err != nil { + return fmt.Errorf("unable to GetLedgerforPool: %w", err) + } + + rewardAvail := App.retiClient.PoolAvailableRewards(info.Pools[poolId-1].PoolAppId, info.Pools[poolId-1].TotalAlgoStaked) + + out := new(strings.Builder) + tw := tabwriter.NewWriter(out, 0, 0, 2, ' ', tabwriter.AlignRight) + fmt.Fprintln(tw, "account\tStaked\tTotal Rewarded\tRwd Tokens\tPct\tEntry Time\t") + for _, stakerData := range ledger { + if stakerData.Account == types.ZeroAddress { + continue + } + fmt.Fprintf(tw, "%s\t%s\t%s\t%d\t%d\t%s\t\n", stakerData.Account.String(), algo.FormattedAlgoAmount(stakerData.Balance), algo.FormattedAlgoAmount(stakerData.TotalRewarded), + stakerData.RewardTokenBalance, pctTimeInEpoch(stakerData.EntryTime), time.Unix(int64(stakerData.EntryTime), 0).UTC().Format(time.RFC3339)) + } + fmt.Fprintf(tw, "Pool Reward Avail: %s\t\n", algo.FormattedAlgoAmount(rewardAvail)) + tw.Flush() + slog.Info(out.String()) + //fmt.Print(out.String()) + return nil +} + +func PoolAdd(ctx context.Context, command *cli.Command) error { + nodeNum := command.Uint("node") + if nodeNum == 0 { + // just add to our current node if not specified + nodeNum = App.retiClient.NodeNum + } + if len(App.retiClient.Info().LocalPools) >= App.retiClient.Info().Config.PoolsPerNode { + return fmt.Errorf("maximum number of pools have been reached on this node. No more can be added") + } + + poolKey, err := App.retiClient.AddStakingPool(nodeNum) + if err != nil { + return err + } + slog.Info("added new pool", "key", poolKey.String()) + return App.retiClient.LoadState(ctx) +} + +func ClaimPool(ctx context.Context, command *cli.Command) error { + var info = App.retiClient.Info() + if len(info.LocalPools) >= info.Config.PoolsPerNode { + return fmt.Errorf("maximum number of pools have been reached on this node. No more can be added") + } + + _, err := App.signer.FindFirstSigner([]string{info.Config.Owner, info.Config.Manager}) + if err != nil { + return fmt.Errorf("neither owner or manager address for your validator has local keys present") + } + + poolId := command.Uint("pool") + if poolId == 0 { + return fmt.Errorf("pool numbers must start at 1. See the pool list -all output for list") + } + if _, found := info.LocalPools[poolId]; found { + return fmt.Errorf("pool with id %d has already been claimed by this validator", poolId) + } + if poolId > uint64(len(info.Pools)) { + return fmt.Errorf("pool with id %d does not exist. See the pool list -all output for list", poolId) + } + err = App.retiClient.MovePoolToNode(info.Pools[poolId-1].PoolAppId, App.retiClient.NodeNum) + if err != nil { + return fmt.Errorf("error in call to MovePoolToNode, err:%w", err) + } + + misc.Infof(App.logger, "You have successfully moved the pool") + if err != nil { + return err + } + return nil +} + +func StakeAdd(ctx context.Context, command *cli.Command) error { + // account, amount, validator + stakerAddr, err := types.DecodeAddress(command.String("account")) + if err != nil { + return err + } + poolKey, err := App.retiClient.AddStake( + command.Uint("validator"), + stakerAddr, + command.Uint("amount")*1e6, + 0, // TODO do we bother handle token gating in CLI ? best left to the UI + ) + if err != nil { + return err + } + misc.Infof(App.logger, "stake added into pool:%d", poolKey.PoolId) + return nil +} + +func StakeRemove(ctx context.Context, command *cli.Command) error { + // account, amount, validator, pool + stakerAddr, err := types.DecodeAddress(command.String("account")) + if err != nil { + return err + } + validatorId := command.Uint("validator") + var poolKey *reti.ValidatorPoolKey + // This staker must have staked something! + poolKeys, err := App.retiClient.GetStakedPoolsForAccount(stakerAddr) + if err != nil { + return err + } + for _, key := range poolKeys { + if key.ID == validatorId && key.PoolId == command.Uint("pool") { + poolKey = key + break + } + } + if poolKey == nil { + return fmt.Errorf("staker has not staked in the specified pool") + } + + err = App.retiClient.RemoveStake(*poolKey, stakerAddr, command.Uint("amount")*1e6) + if err != nil { + return err + } + misc.Infof(App.logger, "stake removed from pool:%d", poolKey.PoolId) + return nil +} + +func PayoutPool(ctx context.Context, command *cli.Command) error { + var info = App.retiClient.Info() + poolID := command.Uint("pool") + if _, found := info.LocalPools[poolID]; !found { + return fmt.Errorf("pool num:%d not on this node", poolID) + } + signerAddr, _ := types.DecodeAddress(info.Config.Manager) + + return App.retiClient.EpochBalanceUpdate(int(poolID), info.LocalPools[poolID], signerAddr) +} diff --git a/nodemgr/svc.go b/nodemgr/svc.go new file mode 100644 index 00000000..88213a6b --- /dev/null +++ b/nodemgr/svc.go @@ -0,0 +1,64 @@ +package main + +import ( + "context" + "fmt" + "os" + "os/signal" + "sync" + "syscall" + + "github.com/urfave/cli/v3" + + "github.com/TxnLab/reti/internal/lib/misc" +) + +func GetDaemonCmdOpts() *cli.Command { + return &cli.Command{ + Name: "daemon", + Aliases: []string{"d"}, + Usage: "Run the application as a daemon", + Before: checkConfigured, // make sure validator is already configured + Action: runAsDaemon, + Flags: []cli.Flag{ + &cli.IntFlag{ + Name: "port", + Usage: "port to expose prometheus /metrics and /ready endpoint", + Value: 6260, + Required: false, + }, + }, + } +} + +func runAsDaemon(ctx context.Context, cmd *cli.Command) error { + var wg sync.WaitGroup + + if err := App.retiClient.LoadState(ctx); err != nil { + return err + } + + // Create channel used by both the signal handler and server goroutines + // to notify the main goroutine when to stop the server. + errc := make(chan error) + + // Setup interrupt handler so that ctrl-c or sigterm gracefully stops the process + go func() { + c := make(chan os.Signal, 1) + signal.Notify(c, syscall.SIGINT, syscall.SIGTERM) + errc <- fmt.Errorf("%s", <-c) + }() + ctx, cancel := context.WithCancel(context.Background()) + + newDaemon().start(ctx, &wg, int(cmd.Int("port"))) + + misc.Infof(App.logger, "exiting (%v)", <-errc) // wait for termination signal + + // Send cancellation signal to the goroutines. + cancel() + misc.Infof(App.logger, "waiting on backround tasks..") + wg.Wait() + + misc.Infof(App.logger, "exited") + return nil +} diff --git a/nodemgr/validatorcmds.go b/nodemgr/validatorcmds.go new file mode 100644 index 00000000..53b36638 --- /dev/null +++ b/nodemgr/validatorcmds.go @@ -0,0 +1,292 @@ +package main + +import ( + "context" + "errors" + "fmt" + "log/slog" + "regexp" + "strconv" + + "github.com/algorand/go-algorand-sdk/v2/types" + "github.com/manifoldco/promptui" + "github.com/urfave/cli/v3" + + "github.com/TxnLab/reti/internal/lib/algo" + "github.com/TxnLab/reti/internal/lib/reti" +) + +func GetValidatorCmdOpts() *cli.Command { + return &cli.Command{ + Name: "validator", + Aliases: []string{"v"}, + Usage: "Configure validator options", + Commands: []*cli.Command{ + { + Name: "init", + Usage: "Initialize self as validator - creating or resetting configuration - should only be done ONCE, EVER !", + Action: InitValidator, + }, + { + Name: "info", + Usage: "Display info about the validator from the chain", + Action: DisplayValidatorInfo, + }, + { + Name: "state", + Usage: "Display info about the validator's current state from the chain", + Action: DisplayValidatorState, + }, + { + Name: "change", + Usage: "Change configuration parameters of validator", + Commands: []*cli.Command{ + { + Name: "commission", + Usage: "Change the commission address", + Flags: []cli.Flag{ + &cli.StringFlag{ + Name: "address", + Usage: "The algorand address to send commissions to.", + Required: true, + }, + }, + Action: ChangeCommission, + }, + }, + }, + }, + } +} + +func InitValidator(ctx context.Context, cmd *cli.Command) error { + if App.retiClient.IsConfigured() { + result, _ := yesNo("A validator configuration already appears to exist, do you REALLY want to add an entirely new validator configuration") + if result != "y" { + return nil + } + return DefineValidator() + } + result, _ := yesNo("Validator not configured. Create brand new validator") + if result != "y" { + return nil + } + return DefineValidator() +} + +func DisplayValidatorInfo(ctx context.Context, command *cli.Command) error { + if !App.retiClient.IsConfigured() { + return fmt.Errorf("validator not configured") + } + var config = App.retiClient.Info().Config + fmt.Println(config.String()) + constraints, err := App.retiClient.GetProtocolConstraints() + if err != nil { + return err + } + fmt.Printf("Amt when saturated: %s\n", algo.FormattedAlgoAmount(constraints.AmtConsideredSaturated)) + fmt.Printf("Max Algo per Validator: %s\n", algo.FormattedAlgoAmount(constraints.MaxAlgoPerValidator)) + return nil +} + +func DisplayValidatorState(ctx context.Context, command *cli.Command) error { + if !App.retiClient.IsConfigured() { + return fmt.Errorf("validator not configured") + } + // Get information from the chain about the current state + state, err := App.retiClient.GetValidatorState(App.retiClient.Info().Config.ID) + if err != nil { + return err + } + slog.Info(state.String()) + return nil +} + +func ChangeCommission(ctx context.Context, command *cli.Command) error { + if !App.retiClient.IsConfigured() { + return fmt.Errorf("validator not configured") + } + var info = App.retiClient.Info() + + signer, err := App.signer.FindFirstSigner([]string{info.Config.Owner, info.Config.Manager}) + if err != nil { + return fmt.Errorf("neither owner or manager address for your validator has local keys present") + } + signerAddr, _ := types.DecodeAddress(signer) + + commissionAddress, err := types.DecodeAddress(command.String("address")) + if err != nil { + return err + } + + err = App.retiClient.ChangeValidatorCommissionAddress(info.Config.ID, signerAddr, commissionAddress) + if err != nil { + return err + } + return App.retiClient.LoadState(ctx) +} + +func DefineValidator() error { + var ( + err error + nfdAppId uint64 + nfdName string + ) + + // Build up a new validator config + config := reti.ValidatorConfig{} + + owner, err := getAlgoAccount("Enter account address for the 'owner' of the validator", "") + if err != nil { + return err + } + if !App.signer.HasAccount(owner) { + return fmt.Errorf("The mnemonics aren't available for this account. Aborting") + } + config.Owner = owner + + manager, err := getAlgoAccount("Enter account address for the 'manager' of the validator", owner) + if err != nil { + return err + } + if !App.signer.HasAccount(manager) { + return fmt.Errorf("The mnemonics aren't available for this account. Aborting") + } + config.Manager = manager + if y, _ := yesNo("Do you want to associate an NFD with this"); y == "y" { + nfdAppId, nfdName, err = getNFDAppId("Enter the NFD Name for this validator", config.Owner) + if err != nil { + return err + } + config.NFDForInfo = nfdAppId + } + // Use the promptui library to ask questions for each of the configuration items in ValidatorConfig + config.PayoutEveryXMins, err = getInt("Enter the payout frequency (in minutes - 1, 60 (1 hr), max 7 days)", 1, 1, 60*24*7) + if err != nil { + return err + } + + config.PercentToValidator, err = getInt("Enter the payout percentage to the validator (in four decimals, ie: 5% = 50000)", 50000, 0, 1000000) + if err != nil { + return err + } + + config.ValidatorCommissionAddress, err = getAlgoAccount("Enter the address that receives the validation commission each epoch payout", config.Owner) + if err != nil { + return err + } + + minStake, err := getInt("Enter the minimum algo stake required to enter the pool", 1000, 1, 1_000_000_000) + if err != nil { + return err + } + config.MinEntryStake = uint64(minStake) * 1e6 + + maxPerPool, err := getInt("Enter the maximum algo stake allowed per pool", 0, 0, 100_000_000) + if err != nil { + return err + } + config.MaxAlgoPerPool = uint64(maxPerPool) * 1e6 + + config.PoolsPerNode, err = getInt("Enter the number of pools to allow per node [max 3 recommended]", 3, 3, 6) + if err != nil { + return err + } + + info := &reti.ValidatorInfo{Config: config} + + validatorId, err := App.retiClient.AddValidator(info, nfdName) + if err != nil { + return err + } + info.Config.ID = validatorId + slog.Info("New Validator added, your Validator id is:", "id", info.Config.ID) + return App.retiClient.LoadState(context.Background()) +} + +func getInt(prompt string, defVal int, minVal int, maxVal int) (int, error) { + validate := func(input string) error { + value, err := strconv.Atoi(input) + if err != nil { + return err + } + if value < minVal || value > maxVal { + return fmt.Errorf("value must be between %d and %d", minVal, maxVal) + } + return nil + } + result, err := (&promptui.Prompt{ + Label: prompt, + Default: strconv.Itoa(defVal), + Validate: validate, + }).Run() + if err != nil { + return 0, err + } + value, _ := strconv.Atoi(result) + return value, nil +} + +func getNFDAppId(prompt string, owner string) (uint64, string, error) { + var ( + nfdId uint64 + nfdName string + ) + _, err := (&promptui.Prompt{ + Label: prompt, + Validate: func(name string) error { + if IsNFDNameValid(name) != nil { + return invalidNFD + } + nfd, _, err := App.nfdApi.NfdApi.NfdGetNFD(context.Background(), name, nil) + if err != nil { + return err + } + if nfd.Owner != owner { + return fmt.Errorf("nfd owner:%s is not same as owner you specified:%s", nfd.Owner, owner) + } + nfdId = uint64(nfd.AppID) + nfdName = nfd.Name + return nil + }, + }).Run() + if err != nil { + return 0, "", err + } + return nfdId, nfdName, nil +} + +func getAlgoAccount(prompt string, defVal string) (string, error) { + return (&promptui.Prompt{ + Label: prompt, + Default: defVal, + Validate: func(s string) error { + _, err := types.DecodeAddress(s) + return err + }, + }).Run() +} + +func yesNo(prompt string) (string, error) { + return (&promptui.Prompt{ + Label: prompt, + IsConfirm: true, + }).Run() +} + +var validNFDNameWSuffixRegex = regexp.MustCompile(`^([a-z0-9]{1,27}\.){0,1}(?P[a-z0-9]{1,27})\.algo$`) + +var invalidNFD = errors.New("invalid nfd name") + +// IsNFDNameValid is simple validity check if an NFD name is valid based on allowing/disallowing emojis, and whether +// the .algo suffix is required to be there. +func IsNFDNameValid(name string) error { + var match bool + + match = validNFDNameWSuffixRegex.MatchString(name) + + if match { + return nil + } + return fmt.Errorf("invalid name:%s", name) +} diff --git a/ui/.algokit.toml b/ui/.algokit.toml new file mode 100644 index 00000000..917a0bbf --- /dev/null +++ b/ui/.algokit.toml @@ -0,0 +1,10 @@ +[algokit] +min_version = "v1.3.0b1" + +[generate.import_contract] +description = "Import a typed client from your smart contracts project" +path = ".algokit/generators/import_contract" + +[project] +type = "frontend" +name = "reti-ui" diff --git a/ui/.copier-answers.yml b/ui/.copier-answers.yml new file mode 100644 index 00000000..abfe1859 --- /dev/null +++ b/ui/.copier-answers.yml @@ -0,0 +1,15 @@ +# Changes here will be overwritten by Copier; NEVER EDIT MANUALLY +_commit: 0.10.1 +_src_path: gh:algorandfoundation/algokit-react-frontend-template +author_email: drichar@gmail.com +author_name: Doug Richar +ide_jetbrains: false +ide_vscode: true +preset_name: custom +project_name: reti-ui +use_daisy_ui: false +use_eslint_prettier: true +use_github_actions: false +use_jest: true +use_playwright: true +use_tailwind: true diff --git a/ui/.editorconfig b/ui/.editorconfig new file mode 100644 index 00000000..a83b72cd --- /dev/null +++ b/ui/.editorconfig @@ -0,0 +1,9 @@ +[*] +charset = utf-8 +insert_final_newline = true +end_of_line = lf +indent_style = space +indent_size = 2 +tab_width = 2 +max_line_length = 140 +trim_trailing_whitespace = true diff --git a/ui/.env.template b/ui/.env.template new file mode 100644 index 00000000..68416058 --- /dev/null +++ b/ui/.env.template @@ -0,0 +1,88 @@ +# ========================== +# LocalNet configuration +# copy to ./ui/.env.localnet +# ========================== + +VITE_ENVIRONMENT=local + +# Algod +VITE_ALGOD_TOKEN=aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +VITE_ALGOD_SERVER=http://localhost +VITE_ALGOD_PORT=4001 +VITE_ALGOD_NETWORK="" + +# Indexer +VITE_INDEXER_TOKEN=aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +VITE_INDEXER_SERVER=http://localhost +VITE_INDEXER_PORT=8980 + +# KMD +# Please note: +# 1. This is only needed for LocalNet since +# by default KMD provider is ignored on other networks. +# 2. AlgoKit LocalNet starts with a single wallet called 'unencrypted-default-wallet', +# with heaps of tokens available for testing. +VITE_KMD_TOKEN=aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +VITE_KMD_SERVER=http://localhost +VITE_KMD_PORT=4002 +VITE_KMD_WALLET="unencrypted-default-wallet" +VITE_KMD_PASSWORD="" + +# NFDomains +VITE_NFD_API_URL=http://localhost:80 +VITE_NFD_APP_URL=http://localhost:3000 + +# Reti +# After bootstrap, set this to the master validator application id +VITE_RETI_APP_ID=0 + +# ========================= +# TestNet configuration: +# copy to ./ui/.env.testnet +# ========================= + +VITE_ENVIRONMENT=local + +# Algod +VITE_ALGOD_TOKEN="" +VITE_ALGOD_SERVER="https://testnet-api.algonode.cloud" +VITE_ALGOD_PORT="" +VITE_ALGOD_NETWORK="testnet" + +# Indexer +VITE_INDEXER_TOKEN="" +VITE_INDEXER_SERVER="https://testnet-idx.algonode.cloud" +VITE_INDEXER_PORT="" + +# NFDomains +VITE_NFD_API_URL=https://api.testnet.nf.domains +VITE_NFD_APP_URL=https://app.testnet.nf.domains + +# Reti +VITE_RETI_APP_ID=0 + + +# ========================= +# MainNet configuration: +# copy to ./ui/.env.mainnet +# ========================= + +VITE_ENVIRONMENT=production + +# Algod +VITE_ALGOD_TOKEN="" +VITE_ALGOD_SERVER="https://mainnet-api.algonode.cloud" +VITE_ALGOD_PORT="" +VITE_ALGOD_NETWORK="mainnet" + +# Indexer +VITE_INDEXER_TOKEN="" +VITE_INDEXER_SERVER="https://mainnet-idx.algonode.cloud" +VITE_INDEXER_PORT="" + +# NFDomains +VITE_NFD_API_URL=https://api.nf.domains +VITE_NFD_APP_URL=https://app.nf.domains + +# Reti +VITE_RETI_APP_ID=0 diff --git a/ui/.eslintrc b/ui/.eslintrc new file mode 100644 index 00000000..fba9c53a --- /dev/null +++ b/ui/.eslintrc @@ -0,0 +1,32 @@ +{ + "root": true, + "env": { + "node": true + }, + "parser": "@typescript-eslint/parser", + "plugins": ["@typescript-eslint", "prettier"], + "extends": [ + "eslint:recommended", + "plugin:@typescript-eslint/eslint-recommended", + "plugin:@typescript-eslint/recommended", + "plugin:prettier/recommended" + ], + "rules": { + "prettier/prettier": "warn", + "no-console": [ + "warn", + { + "allow": ["warn", "error"] + } + ], + "@typescript-eslint/no-unused-vars": [ + "warn", + { + "ignoreRestSiblings": true, + "argsIgnorePattern": "^_", + "destructuredArrayIgnorePattern": "^_" + } + ], + "prefer-template": "error" + } +} diff --git a/ui/.gitattributes b/ui/.gitattributes new file mode 100644 index 00000000..6313b56c --- /dev/null +++ b/ui/.gitattributes @@ -0,0 +1 @@ +* text=auto eol=lf diff --git a/ui/.gitignore b/ui/.gitignore new file mode 100644 index 00000000..6323fba8 --- /dev/null +++ b/ui/.gitignore @@ -0,0 +1,38 @@ +# See https://help.github.com/articles/ignoring-files/ for more about ignoring files. + +# dependencies +/node_modules +/.pnp +.pnp.js + +# testing +/coverage + +# production +/build + + +# dotenv environment variable files +.env +.env.localnet +.env.testnet +.env.mainnet +env/ + +# misc +/dist +.DS_Store + + +npm-debug.log* +yarn-debug.log* +yarn-error.log* +/test-results/ +/playwright-report/ +/playwright/.cache/ + +# PyCharm +.idea +!.idea/ +.idea/* +!.idea/runConfigurations/ diff --git a/ui/.prettierignore b/ui/.prettierignore new file mode 100644 index 00000000..dbda6ae9 --- /dev/null +++ b/ui/.prettierignore @@ -0,0 +1,12 @@ +# don't ever format node_modules +node_modules +# don't lint format output (make sure it's set to your correct build folder name) +dist +build +# don't format nyc coverage output +coverage +# don't format generated types +**/generated/types.d.ts +**/generated/types.ts +# don't format ide files +.idea diff --git a/ui/.prettierrc.cjs b/ui/.prettierrc.cjs new file mode 100644 index 00000000..b0533335 --- /dev/null +++ b/ui/.prettierrc.cjs @@ -0,0 +1,10 @@ +module.exports = { + singleQuote: true, + jsxSingleQuote: false, + semi: false, + tabWidth: 2, + trailingComma: 'all', + printWidth: 100, + endOfLine: 'lf', + arrowParens: 'always', +} diff --git a/ui/.vscode/extensions.json b/ui/.vscode/extensions.json new file mode 100644 index 00000000..69c7b499 --- /dev/null +++ b/ui/.vscode/extensions.json @@ -0,0 +1,13 @@ +{ + "recommendations": [ + "EditorConfig.EditorConfig", + "dotenv.dotenv-vscode", + "esbenp.prettier-vscode", + "dbaeumer.vscode-eslint", + "krysenlo.vite-plugin-eslint-problemmatcher", + "ms-playwright.playwright", + "Orta.vscode-jest", + "bradlc.vscode-tailwindcss", + "csstools.postcss" + ] +} diff --git a/ui/.vscode/launch.json b/ui/.vscode/launch.json new file mode 100644 index 00000000..7edaf04e --- /dev/null +++ b/ui/.vscode/launch.json @@ -0,0 +1,68 @@ +{ + "configurations": [ + { + "type": "msedge", + "request": "launch", + "name": "Run (Edge)", + "url": "http://localhost:5173", + "webRoot": "${workspaceFolder}", + "presentation": { + "hidden": false, + "group": "2. Web" + } + }, + { + "type": "chrome", + "request": "launch", + "name": "Run (Chrome)", + "url": "http://localhost:5173", + "webRoot": "${workspaceFolder}", + "presentation": { + "hidden": false, + "group": "2. Web" + } + }, + { + "type": "firefox", + "request": "launch", + "name": "Run (Firefox)", + "url": "http://localhost:5173", + "webRoot": "${workspaceFolder}", + "presentation": { + "hidden": false, + "group": "2. Web" + } + }, + { + "name": "Run dApp", + "type": "node", + "request": "launch", + "runtimeExecutable": "npm", + "runtimeArgs": ["run", "dev"], + "cwd": "${workspaceRoot}", + "console": "integratedTerminal", + "skipFiles": ["/**", "node_modules/**"], + "presentation": { + "hidden": false, + "group": "1. Run Project", + "order": 1 + } + }, + { + "name": "Run dApp (+ LocalNet)", + "type": "node", + "request": "launch", + "runtimeExecutable": "npm", + "runtimeArgs": ["run", "dev"], + "cwd": "${workspaceRoot}", + "console": "integratedTerminal", + "skipFiles": ["/**", "node_modules/**"], + "preLaunchTask": "Start AlgoKit LocalNet", + "presentation": { + "hidden": false, + "group": "1. Run Project", + "order": 1 + } + } + ] +} diff --git a/ui/.vscode/settings.json b/ui/.vscode/settings.json new file mode 100644 index 00000000..eeb66d33 --- /dev/null +++ b/ui/.vscode/settings.json @@ -0,0 +1,16 @@ +{ + "editor.tabSize": 2, + "editor.insertSpaces": true, + "editor.detectIndentation": false, + "editor.formatOnSave": true, + "editor.defaultFormatter": "esbenp.prettier-vscode", + "editor.codeActionsOnSave": { + "source.fixAll.eslint": "explicit", + "source.organizeImports": "explicit" + }, + "dotenv.enableAutocloaking": false, + "jest.autoRun": { + "watch": false, + "onSave": "test-file" + } +} diff --git a/ui/.vscode/tasks.json b/ui/.vscode/tasks.json new file mode 100644 index 00000000..5ef4b719 --- /dev/null +++ b/ui/.vscode/tasks.json @@ -0,0 +1,15 @@ +{ + "version": "2.0.0", + "tasks": [ + { + "label": "Start AlgoKit LocalNet", + "command": "algokit", + "args": ["localnet", "start"], + "type": "shell", + "options": { + "cwd": "${workspaceFolder}" + }, + "problemMatcher": [] + } + ] +} diff --git a/ui/LICENSE b/ui/LICENSE new file mode 100644 index 00000000..e19fbfa1 --- /dev/null +++ b/ui/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2024 Algorand Foundation + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/ui/README.md b/ui/README.md new file mode 100644 index 00000000..d020af00 --- /dev/null +++ b/ui/README.md @@ -0,0 +1,65 @@ +# reti-ui + +This starter React project has been generated using AlgoKit. See below for default getting started instructions. + +# Setup + +### Initial setup + +1. Clone this repository locally +2. Install pre-requisites: + - Make sure to have [Docker](https://www.docker.com/) installed and running on your machine. + - Install `AlgoKit` - [Link](https://github.com/algorandfoundation/algokit-cli#install): The minimum required version is `1.1`. Ensure you can execute `algokit --version` and get `1.1` or later. + - Bootstrap your local environment; run `algokit bootstrap all` within this folder, which will run `npm install` to install NPM packages and dependencies for your frontend component/webapp. + - Run `algokit localnet start` to start a local Algorand network in Docker. If you are using VS Code launch configurations provided by the template, this will be done automatically for you. +3. Open the project and start debugging / developing via: + - VS Code + 1. Open the repository root in VS Code + 2. Install recommended extensions + 3. Hit F5 (or whatever you have debug mapped to) and it should start running with breakpoint debugging. + - JetBrains WebStorm + 1. Open the repository root in WebStorm + 2. Hit Shift+F10|Ctrl+R (or whatever you have debug mapped to). Then Shift+CMD|Ctrl+Click on the link in the console to open the browser with debugger attached. + - Other + 1. Open the repository root in your text editor of choice + 2. In a terminal run `npm run dev` + +### Subsequently + +1. If you update to the latest source code and there are new dependencies you will need to run `algokit bootstrap all` again +2. Follow step 3 above + +> Please note, by default frontend is pre configured to run against Algorand LocalNet. If you want to run against TestNet or MainNet, comment out the current environment variable and uncomment the relevant one in [`.env`](.env) file that is created after running bootstrap command and based on [`.env.template`](.env.template). + +# Algorand Wallet integrations + +The template comes with [`use-wallet`](https://github.com/txnlab/use-wallet) integration, which provides a React hook for connecting to an Algorand wallet providers. The following wallet providers are included by default: + +- LocalNet: +- - [KMD/Local Wallet](https://github.com/TxnLab/use-wallet#kmd-algorand-key-management-daemon) - Algorand's Key Management Daemon (KMD) is a service that manages Algorand private keys and signs transactions. Works best with AlgoKit LocalNet and allows you to easily test and interact with your dApps locally. +- TestNet and others: +- - [Pera Wallet](https://perawallet.app). +- - [Defly Wallet](https://defly.app). +- - [Exodus Wallet](https://www.exodus.com). +- - [Daffi Wallet](https://www.daffi.me). + +Refer to official [`use-wallet`](https://github.com/txnlab/use-wallet) documentation for detailed guidelines on how to integrate with other wallet providers (such as WalletConnect v2). Too see implementation details on the use wallet hook and initialization of extra wallet providers refer to [`App.tsx`](./src/App.tsx). + +# Tools + +This project makes use of React and Tailwind to provider a base project configuration to develop frontends for your Algorand dApps and interactions with smart contracts. The following tools are in use: + +- [AlgoKit Utils](https://github.com/algorandfoundation/algokit-utils-ts) - Various TypeScript utilities to simplify interactions with Algorand and AlgoKit. +- [React](https://reactjs.org/) - A JavaScript library for building user interfaces. +- [Tailwind CSS](https://tailwindcss.com/) - A utility-first CSS framework for rapidly building custom designs. +- [use-wallet](https://github.com/txnlab/use-wallet) - A React hook for connecting to an Algorand wallet providers. +- [npm](https://www.npmjs.com/): Node.js package manager +- [jest](https://jestjs.io/): JavaScript testing framework +- [playwright](https://playwright.dev/): Browser automation library +- [Prettier](https://prettier.io/): Opinionated code formatter +- [ESLint](https://eslint.org/): Tool for identifying and reporting on patterns in JavaScript + It has also been configured to have a productive dev experience out of the box in [VS Code](https://code.visualstudio.com/), see the [.vscode](./.vscode) folder. + +# Integrating with smart contracts and application clients + +Refer to the detailed guidance on [integrating with smart contracts and application clients](./src/contracts/README.md). In essence, for any smart contract codebase generated with AlgoKit or other tools that produce compile contracts into ARC34 compliant app specifications, you can use the `algokit generate` command to generate TypeScript or Python typed client. Once generated simply drag and drop the generated client into `./src/contracts` and import it into your React components as you see fit. diff --git a/ui/components.json b/ui/components.json new file mode 100644 index 00000000..85f5714c --- /dev/null +++ b/ui/components.json @@ -0,0 +1,17 @@ +{ + "$schema": "https://ui.shadcn.com/schema.json", + "style": "new-york", + "rsc": false, + "tsx": true, + "tailwind": { + "config": "tailwind.config.js", + "css": "src/styles/main.css", + "baseColor": "stone", + "cssVariables": true, + "prefix": "" + }, + "aliases": { + "components": "@/components", + "utils": "@/utils/ui" + } +} diff --git a/ui/index.html b/ui/index.html new file mode 100644 index 00000000..276c3b60 --- /dev/null +++ b/ui/index.html @@ -0,0 +1,16 @@ + + + + + + Réti Pooling + + + +
+ + + + diff --git a/ui/jest.config.ts b/ui/jest.config.ts new file mode 100644 index 00000000..eab1ba7f --- /dev/null +++ b/ui/jest.config.ts @@ -0,0 +1,20 @@ +import type { Config } from '@jest/types' + +const config: Config.InitialOptions = { + preset: 'ts-jest', + testEnvironment: 'node', + testMatch: ['**/*.spec.ts', '**/*.spec.tsx'], + moduleDirectories: ['node_modules', 'src'], + transform: { + '': [ + 'ts-jest', + { + tsconfig: 'tsconfig.test.json', + }, + ], + }, + coveragePathIgnorePatterns: ['tests'], + testPathIgnorePatterns: ['/tests/'], +} + +export default config diff --git a/ui/package.json b/ui/package.json new file mode 100644 index 00000000..c5a10c5d --- /dev/null +++ b/ui/package.json @@ -0,0 +1,115 @@ +{ + "name": "reti-ui", + "version": "0.1.0", + "author": { + "name": "Doug Richar", + "email": "drichar@gmail.com" + }, + "private": true, + "type": "module", + "engines": { + "node": ">=18.0" + }, + "devDependencies": { + "@playwright/test": "^1.35.0", + "@tanstack/router-vite-plugin": "^1.18.1", + "@types/big.js": "^6.2.2", + "@types/jest": "29.5.2", + "@types/node": "^18.19.20", + "@types/react": "^18.2.11", + "@types/react-dom": "^18.2.4", + "@typescript-eslint/eslint-plugin": "^6.5.0", + "@typescript-eslint/parser": "^6.5.0", + "@vitejs/plugin-react": "^4.2.1", + "autoprefixer": "^10.4.14", + "eslint": "^8.42.0", + "eslint-config-prettier": "^8.8.0", + "eslint-plugin-prettier": "^5.0.0", + "playwright": "^1.35.0", + "postcss": "^8.4.24", + "tailwindcss": "3.3.2", + "ts-jest": "^29.1.1", + "ts-node": "^10.9.1", + "typescript": "^5.4.2", + "vite": "^5.0.0" + }, + "dependencies": { + "@algorandfoundation/algokit-utils": "^5.0.0", + "@blockshake/defly-connect": "^1.1.6", + "@daffiwallet/connect": "^1.0.3", + "@hookform/resolvers": "^3.3.4", + "@perawallet/connect": "^1.3.1", + "@radix-ui/react-avatar": "^1.0.4", + "@radix-ui/react-checkbox": "^1.0.4", + "@radix-ui/react-dialog": "^1.0.5", + "@radix-ui/react-dropdown-menu": "^2.0.6", + "@radix-ui/react-icons": "^1.3.0", + "@radix-ui/react-label": "^2.0.2", + "@radix-ui/react-navigation-menu": "^1.1.4", + "@radix-ui/react-select": "^2.0.0", + "@radix-ui/react-slot": "^1.0.2", + "@radix-ui/react-tooltip": "^1.0.7", + "@tanstack/react-query": "^5.24.1", + "@tanstack/react-query-devtools": "^5.27.3", + "@tanstack/react-router": "^1.22.0", + "@tanstack/react-table": "^8.13.2", + "@tanstack/router-devtools": "^1.18.4", + "@txnlab/use-wallet-react": "3.0.0-beta.2", + "@walletconnect/modal-sign-html": "^2.6.1", + "algosdk": "^2.7.0", + "axios": "^1", + "axios-cache-interceptor": "^1", + "big.js": "^6.2.1", + "class-variance-authority": "^0.7.0", + "clsx": "^2.1.0", + "copy-to-clipboard": "^3.3.3", + "dayjs": "^1.11.10", + "lucide-react": "^0.363.0", + "next-themes": "^0.2.1", + "notistack": "^3.0.1", + "react": "^18.2.0", + "react-dom": "^18.2.0", + "react-helmet-async": "^2.0.4", + "react-hook-form": "^7.51.0", + "recharts": "^2.12.2", + "sonner": "^1.4.3", + "tailwind-merge": "^2.2.1", + "tailwindcss-animate": "^1.0.7", + "tslib": "^2.6.2", + "use-debounce": "^10.0.0", + "zod": "^3.22.4" + }, + "scripts": { + "dev": "vite", + "dev:localnet": "vite --mode localnet --port 5173", + "dev:testnet": "vite --mode testnet --port 5183", + "dev:mainnet": "vite --mode mainnet --port 5193", + "build": "tsc && vite build", + "test": "jest --coverage --passWithNoTests", + "playwright:test": "playwright test", + "lint": "eslint src --ext ts,tsx --report-unused-disable-directives --max-warnings 0", + "lint:fix": "eslint src --ext ts,tsx --report-unused-disable-directives --max-warnings 0 --fix", + "prettier": "npx prettier --check .", + "prettier:fix": "npx prettier --write .", + "typecheck": "tsc --noEmit", + "preview": "vite preview" + }, + "eslintConfig": { + "extends": [ + "react-app/jest", + "react-app" + ] + }, + "browserslist": { + "production": [ + ">0.2%", + "not dead", + "not op_mini all" + ], + "development": [ + "last 1 chrome version", + "last 1 firefox version", + "last 1 safari version" + ] + } +} diff --git a/ui/playwright.config.ts b/ui/playwright.config.ts new file mode 100644 index 00000000..d7cbca6f --- /dev/null +++ b/ui/playwright.config.ts @@ -0,0 +1,73 @@ +import { defineConfig, devices } from '@playwright/test' + +/** + * Read environment variables from file. + * https://github.com/motdotla/dotenv + */ +// require('dotenv').config(); + +/** + * See https://playwright.dev/docs/test-configuration. + */ +export default defineConfig({ + testDir: './tests', + /* Run tests in files in parallel */ + fullyParallel: true, + /* Fail the build on CI if you accidentally left test.only in the source code. */ + forbidOnly: !!process.env.CI, + /* Retry on CI only */ + retries: process.env.CI ? 2 : 0, + /* Opt out of parallel tests on CI. */ + workers: process.env.CI ? 1 : undefined, + /* Reporter to use. See https://playwright.dev/docs/test-reporters */ + reporter: 'html', + /* Shared settings for all the projects below. See https://playwright.dev/docs/api/class-testoptions. */ + use: { + /* Base URL to use in actions like `await page.goto('/')`. */ + // baseURL: 'http://127.0.0.1:3000', + + /* Collect trace when retrying the failed test. See https://playwright.dev/docs/trace-viewer */ + trace: 'on-first-retry', + testIdAttribute: 'data-test-id', + }, + + /* Configure projects for major browsers */ + projects: [ + { + name: 'chromium', + use: { ...devices['Desktop Chrome'] }, + }, + + { + name: 'firefox', + use: { ...devices['Desktop Firefox'] }, + }, + + /* Test against mobile viewports. */ + // { + // name: 'Mobile Chrome', + // use: { ...devices['Pixel 5'] }, + // }, + // { + // name: 'Mobile Safari', + // use: { ...devices['iPhone 12'] }, + // }, + + /* Test against branded browsers. */ + // { + // name: 'Microsoft Edge', + // use: { ...devices['Desktop Edge'], channel: 'msedge' }, + // }, + // { + // name: 'Google Chrome', + // use: { ..devices['Desktop Chrome'], channel: 'chrome' }, + // }, + ], + + /* Run your local dev server before starting the tests */ + webServer: { + command: 'npm run dev', + url: 'http://localhost:5173', + reuseExistingServer: !process.env.CI, + }, +}) diff --git a/ui/pnpm-lock.yaml b/ui/pnpm-lock.yaml new file mode 100644 index 00000000..22e69d90 --- /dev/null +++ b/ui/pnpm-lock.yaml @@ -0,0 +1,7664 @@ +lockfileVersion: '6.0' + +settings: + autoInstallPeers: true + excludeLinksFromLockfile: false + +dependencies: + '@algorandfoundation/algokit-utils': + specifier: ^5.0.0 + version: 5.6.1(algosdk@2.7.0) + '@blockshake/defly-connect': + specifier: ^1.1.6 + version: 1.1.6(algosdk@2.7.0) + '@daffiwallet/connect': + specifier: ^1.0.3 + version: 1.0.3(algosdk@2.7.0) + '@hookform/resolvers': + specifier: ^3.3.4 + version: 3.3.4(react-hook-form@7.51.1) + '@perawallet/connect': + specifier: ^1.3.1 + version: 1.3.4(algosdk@2.7.0) + '@radix-ui/react-avatar': + specifier: ^1.0.4 + version: 1.0.4(@types/react-dom@18.2.22)(@types/react@18.2.67)(react-dom@18.2.0)(react@18.2.0) + '@radix-ui/react-checkbox': + specifier: ^1.0.4 + version: 1.0.4(@types/react-dom@18.2.22)(@types/react@18.2.67)(react-dom@18.2.0)(react@18.2.0) + '@radix-ui/react-dialog': + specifier: ^1.0.5 + version: 1.0.5(@types/react-dom@18.2.22)(@types/react@18.2.67)(react-dom@18.2.0)(react@18.2.0) + '@radix-ui/react-dropdown-menu': + specifier: ^2.0.6 + version: 2.0.6(@types/react-dom@18.2.22)(@types/react@18.2.67)(react-dom@18.2.0)(react@18.2.0) + '@radix-ui/react-icons': + specifier: ^1.3.0 + version: 1.3.0(react@18.2.0) + '@radix-ui/react-label': + specifier: ^2.0.2 + version: 2.0.2(@types/react-dom@18.2.22)(@types/react@18.2.67)(react-dom@18.2.0)(react@18.2.0) + '@radix-ui/react-navigation-menu': + specifier: ^1.1.4 + version: 1.1.4(@types/react-dom@18.2.22)(@types/react@18.2.67)(react-dom@18.2.0)(react@18.2.0) + '@radix-ui/react-select': + specifier: ^2.0.0 + version: 2.0.0(@types/react-dom@18.2.22)(@types/react@18.2.67)(react-dom@18.2.0)(react@18.2.0) + '@radix-ui/react-slot': + specifier: ^1.0.2 + version: 1.0.2(@types/react@18.2.67)(react@18.2.0) + '@radix-ui/react-tooltip': + specifier: ^1.0.7 + version: 1.0.7(@types/react-dom@18.2.22)(@types/react@18.2.67)(react-dom@18.2.0)(react@18.2.0) + '@tanstack/react-query': + specifier: ^5.24.1 + version: 5.28.4(react@18.2.0) + '@tanstack/react-query-devtools': + specifier: ^5.27.3 + version: 5.28.4(@tanstack/react-query@5.28.4)(react@18.2.0) + '@tanstack/react-router': + specifier: ^1.22.0 + version: 1.22.0(react-dom@18.2.0)(react@18.2.0) + '@tanstack/react-table': + specifier: ^8.13.2 + version: 8.14.0(react-dom@18.2.0)(react@18.2.0) + '@tanstack/router-devtools': + specifier: ^1.18.4 + version: 1.20.4(csstype@3.1.3)(react-dom@18.2.0)(react@18.2.0) + '@txnlab/use-wallet-react': + specifier: 3.0.0-beta.2 + version: 3.0.0-beta.2(@blockshake/defly-connect@1.1.6)(@perawallet/connect@1.3.4)(algosdk@2.7.0)(react-dom@18.2.0)(react@18.2.0) + '@walletconnect/modal-sign-html': + specifier: ^2.6.1 + version: 2.6.2(@types/react@18.2.67)(react@18.2.0) + algosdk: + specifier: ^2.7.0 + version: 2.7.0 + axios: + specifier: ^1 + version: 1.6.8 + axios-cache-interceptor: + specifier: ^1 + version: 1.5.1(axios@1.6.8) + big.js: + specifier: ^6.2.1 + version: 6.2.1 + class-variance-authority: + specifier: ^0.7.0 + version: 0.7.0 + clsx: + specifier: ^2.1.0 + version: 2.1.0 + copy-to-clipboard: + specifier: ^3.3.3 + version: 3.3.3 + dayjs: + specifier: ^1.11.10 + version: 1.11.10 + lucide-react: + specifier: ^0.363.0 + version: 0.363.0(react@18.2.0) + next-themes: + specifier: ^0.2.1 + version: 0.2.1(next@14.1.4)(react-dom@18.2.0)(react@18.2.0) + notistack: + specifier: ^3.0.1 + version: 3.0.1(csstype@3.1.3)(react-dom@18.2.0)(react@18.2.0) + react: + specifier: ^18.2.0 + version: 18.2.0 + react-dom: + specifier: ^18.2.0 + version: 18.2.0(react@18.2.0) + react-helmet-async: + specifier: ^2.0.4 + version: 2.0.4(react-dom@18.2.0)(react@18.2.0) + react-hook-form: + specifier: ^7.51.0 + version: 7.51.1(react@18.2.0) + recharts: + specifier: ^2.12.2 + version: 2.12.3(react-dom@18.2.0)(react@18.2.0) + sonner: + specifier: ^1.4.3 + version: 1.4.3(react-dom@18.2.0)(react@18.2.0) + tailwind-merge: + specifier: ^2.2.1 + version: 2.2.2 + tailwindcss-animate: + specifier: ^1.0.7 + version: 1.0.7(tailwindcss@3.3.2) + tslib: + specifier: ^2.6.2 + version: 2.6.2 + use-debounce: + specifier: ^10.0.0 + version: 10.0.0(react@18.2.0) + zod: + specifier: ^3.22.4 + version: 3.22.4 + +devDependencies: + '@playwright/test': + specifier: ^1.35.0 + version: 1.42.1 + '@tanstack/router-vite-plugin': + specifier: ^1.18.1 + version: 1.20.2 + '@types/big.js': + specifier: ^6.2.2 + version: 6.2.2 + '@types/jest': + specifier: 29.5.2 + version: 29.5.2 + '@types/node': + specifier: ^18.19.20 + version: 18.19.26 + '@types/react': + specifier: ^18.2.11 + version: 18.2.67 + '@types/react-dom': + specifier: ^18.2.4 + version: 18.2.22 + '@typescript-eslint/eslint-plugin': + specifier: ^6.5.0 + version: 6.21.0(@typescript-eslint/parser@6.21.0)(eslint@8.57.0)(typescript@5.4.2) + '@typescript-eslint/parser': + specifier: ^6.5.0 + version: 6.21.0(eslint@8.57.0)(typescript@5.4.2) + '@vitejs/plugin-react': + specifier: ^4.2.1 + version: 4.2.1(vite@5.1.6) + autoprefixer: + specifier: ^10.4.14 + version: 10.4.18(postcss@8.4.37) + eslint: + specifier: ^8.42.0 + version: 8.57.0 + eslint-config-prettier: + specifier: ^8.8.0 + version: 8.10.0(eslint@8.57.0) + eslint-plugin-prettier: + specifier: ^5.0.0 + version: 5.1.3(eslint-config-prettier@8.10.0)(eslint@8.57.0)(prettier@3.2.5) + playwright: + specifier: ^1.35.0 + version: 1.42.1 + postcss: + specifier: ^8.4.24 + version: 8.4.37 + tailwindcss: + specifier: 3.3.2 + version: 3.3.2(ts-node@10.9.2) + ts-jest: + specifier: ^29.1.1 + version: 29.1.2(@babel/core@7.24.1)(jest@29.7.0)(typescript@5.4.2) + ts-node: + specifier: ^10.9.1 + version: 10.9.2(@types/node@18.19.26)(typescript@5.4.2) + typescript: + specifier: ^5.4.2 + version: 5.4.2 + vite: + specifier: ^5.0.0 + version: 5.1.6(@types/node@18.19.26) + +packages: + + /@aashutoshrathi/word-wrap@1.2.6: + resolution: {integrity: sha512-1Yjs2SvM8TflER/OD3cOjhWWOZb58A2t7wpE2S9XfBYTiIl+XFhQG2bjy4Pu1I+EAlCNUzRDYDdFwFYUKvXcIA==} + engines: {node: '>=0.10.0'} + dev: true + + /@algorandfoundation/algokit-utils@5.6.1(algosdk@2.7.0): + resolution: {integrity: sha512-lC27i9I0knu88yykFcBcLhpoCaZQByxZp1/vrGlEUeMcVe4fPhvzYpipnIzPySkuRJjwn0XVKKuawAkg1gZ/OQ==} + engines: {node: '>=18.0'} + peerDependencies: + algosdk: ^2.7.0 + dependencies: + algosdk: 2.7.0 + buffer: 6.0.3 + dev: false + + /@alloc/quick-lru@5.2.0: + resolution: {integrity: sha512-UrcABB+4bUrFABwbluTIBErXwvbsU/V7TZWfmbgJfbkwiBuziS9gxdODUyuiecfdGQ85jglMW6juS3+z5TsKLw==} + engines: {node: '>=10'} + + /@ampproject/remapping@2.3.0: + resolution: {integrity: sha512-30iZtAPgz+LTIYoeivqYo853f02jBYSd5uGnGpkFV0M3xOt9aN73erkgYAmZU43x4VfqcnLxW9Kpg3R5LC4YYw==} + engines: {node: '>=6.0.0'} + dependencies: + '@jridgewell/gen-mapping': 0.3.5 + '@jridgewell/trace-mapping': 0.3.25 + + /@babel/code-frame@7.24.2: + resolution: {integrity: sha512-y5+tLQyV8pg3fsiln67BVLD1P13Eg4lh5RW9mF0zUuvLrv9uIQ4MCL+CRT+FTsBlBjcIan6PGsLcBN0m3ClUyQ==} + engines: {node: '>=6.9.0'} + dependencies: + '@babel/highlight': 7.24.2 + picocolors: 1.0.0 + + /@babel/compat-data@7.24.1: + resolution: {integrity: sha512-Pc65opHDliVpRHuKfzI+gSA4zcgr65O4cl64fFJIWEEh8JoHIHh0Oez1Eo8Arz8zq/JhgKodQaxEwUPRtZylVA==} + engines: {node: '>=6.9.0'} + + /@babel/core@7.24.1: + resolution: {integrity: sha512-F82udohVyIgGAY2VVj/g34TpFUG606rumIHjTfVbssPg2zTR7PuuEpZcX8JA6sgBfIYmJrFtWgPvHQuJamVqZQ==} + engines: {node: '>=6.9.0'} + dependencies: + '@ampproject/remapping': 2.3.0 + '@babel/code-frame': 7.24.2 + '@babel/generator': 7.24.1 + '@babel/helper-compilation-targets': 7.23.6 + '@babel/helper-module-transforms': 7.23.3(@babel/core@7.24.1) + '@babel/helpers': 7.24.1 + '@babel/parser': 7.24.1 + '@babel/template': 7.24.0 + '@babel/traverse': 7.24.1 + '@babel/types': 7.24.0 + convert-source-map: 2.0.0 + debug: 4.3.4 + gensync: 1.0.0-beta.2 + json5: 2.2.3 + semver: 6.3.1 + transitivePeerDependencies: + - supports-color + + /@babel/core@7.24.3: + resolution: {integrity: sha512-5FcvN1JHw2sHJChotgx8Ek0lyuh4kCKelgMTTqhYJJtloNvUfpAFMeNQUtdlIaktwrSV9LtCdqwk48wL2wBacQ==} + engines: {node: '>=6.9.0'} + dependencies: + '@ampproject/remapping': 2.3.0 + '@babel/code-frame': 7.24.2 + '@babel/generator': 7.24.1 + '@babel/helper-compilation-targets': 7.23.6 + '@babel/helper-module-transforms': 7.23.3(@babel/core@7.24.3) + '@babel/helpers': 7.24.1 + '@babel/parser': 7.24.1 + '@babel/template': 7.24.0 + '@babel/traverse': 7.24.1 + '@babel/types': 7.24.0 + convert-source-map: 2.0.0 + debug: 4.3.4 + gensync: 1.0.0-beta.2 + json5: 2.2.3 + semver: 6.3.1 + transitivePeerDependencies: + - supports-color + dev: true + + /@babel/generator@7.24.1: + resolution: {integrity: sha512-DfCRfZsBcrPEHUfuBMgbJ1Ut01Y/itOs+hY2nFLgqsqXd52/iSiVq5TITtUasIUgm+IIKdY2/1I7auiQOEeC9A==} + engines: {node: '>=6.9.0'} + dependencies: + '@babel/types': 7.24.0 + '@jridgewell/gen-mapping': 0.3.5 + '@jridgewell/trace-mapping': 0.3.25 + jsesc: 2.5.2 + + /@babel/helper-compilation-targets@7.23.6: + resolution: {integrity: sha512-9JB548GZoQVmzrFgp8o7KxdgkTGm6xs9DW0o/Pim72UDjzr5ObUQ6ZzYPqA+g9OTS2bBQoctLJrky0RDCAWRgQ==} + engines: {node: '>=6.9.0'} + dependencies: + '@babel/compat-data': 7.24.1 + '@babel/helper-validator-option': 7.23.5 + browserslist: 4.23.0 + lru-cache: 5.1.1 + semver: 6.3.1 + + /@babel/helper-environment-visitor@7.22.20: + resolution: {integrity: sha512-zfedSIzFhat/gFhWfHtgWvlec0nqB9YEIVrpuwjruLlXfUSnA8cJB0miHKwqDnQ7d32aKo2xt88/xZptwxbfhA==} + engines: {node: '>=6.9.0'} + + /@babel/helper-function-name@7.23.0: + resolution: {integrity: sha512-OErEqsrxjZTJciZ4Oo+eoZqeW9UIiOcuYKRJA4ZAgV9myA+pOXhhmpfNCKjEH/auVfEYVFJ6y1Tc4r0eIApqiw==} + engines: {node: '>=6.9.0'} + dependencies: + '@babel/template': 7.24.0 + '@babel/types': 7.24.0 + + /@babel/helper-hoist-variables@7.22.5: + resolution: {integrity: sha512-wGjk9QZVzvknA6yKIUURb8zY3grXCcOZt+/7Wcy8O2uctxhplmUPkOdlgoNhmdVee2c92JXbf1xpMtVNbfoxRw==} + engines: {node: '>=6.9.0'} + dependencies: + '@babel/types': 7.24.0 + + /@babel/helper-module-imports@7.24.1: + resolution: {integrity: sha512-HfEWzysMyOa7xI5uQHc/OcZf67/jc+xe/RZlznWQHhbb8Pg1SkRdbK4yEi61aY8wxQA7PkSfoojtLQP/Kpe3og==} + engines: {node: '>=6.9.0'} + dependencies: + '@babel/types': 7.24.0 + + /@babel/helper-module-transforms@7.23.3(@babel/core@7.24.1): + resolution: {integrity: sha512-7bBs4ED9OmswdfDzpz4MpWgSrV7FXlc3zIagvLFjS5H+Mk7Snr21vQ6QwrsoCGMfNC4e4LQPdoULEt4ykz0SRQ==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0 + dependencies: + '@babel/core': 7.24.1 + '@babel/helper-environment-visitor': 7.22.20 + '@babel/helper-module-imports': 7.24.1 + '@babel/helper-simple-access': 7.22.5 + '@babel/helper-split-export-declaration': 7.22.6 + '@babel/helper-validator-identifier': 7.22.20 + + /@babel/helper-module-transforms@7.23.3(@babel/core@7.24.3): + resolution: {integrity: sha512-7bBs4ED9OmswdfDzpz4MpWgSrV7FXlc3zIagvLFjS5H+Mk7Snr21vQ6QwrsoCGMfNC4e4LQPdoULEt4ykz0SRQ==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0 + dependencies: + '@babel/core': 7.24.3 + '@babel/helper-environment-visitor': 7.22.20 + '@babel/helper-module-imports': 7.24.1 + '@babel/helper-simple-access': 7.22.5 + '@babel/helper-split-export-declaration': 7.22.6 + '@babel/helper-validator-identifier': 7.22.20 + dev: true + + /@babel/helper-plugin-utils@7.24.0: + resolution: {integrity: sha512-9cUznXMG0+FxRuJfvL82QlTqIzhVW9sL0KjMPHhAOOvpQGL8QtdxnBKILjBqxlHyliz0yCa1G903ZXI/FuHy2w==} + engines: {node: '>=6.9.0'} + dev: true + + /@babel/helper-simple-access@7.22.5: + resolution: {integrity: sha512-n0H99E/K+Bika3++WNL17POvo4rKWZ7lZEp1Q+fStVbUi8nxPQEBOlTmCOxW/0JsS56SKKQ+ojAe2pHKJHN35w==} + engines: {node: '>=6.9.0'} + dependencies: + '@babel/types': 7.24.0 + + /@babel/helper-split-export-declaration@7.22.6: + resolution: {integrity: sha512-AsUnxuLhRYsisFiaJwvp1QF+I3KjD5FOxut14q/GzovUe6orHLesW2C7d754kRm53h5gqrz6sFl6sxc4BVtE/g==} + engines: {node: '>=6.9.0'} + dependencies: + '@babel/types': 7.24.0 + + /@babel/helper-string-parser@7.24.1: + resolution: {integrity: sha512-2ofRCjnnA9y+wk8b9IAREroeUP02KHp431N2mhKniy2yKIDKpbrHv9eXwm8cBeWQYcJmzv5qKCu65P47eCF7CQ==} + engines: {node: '>=6.9.0'} + + /@babel/helper-validator-identifier@7.22.20: + resolution: {integrity: sha512-Y4OZ+ytlatR8AI+8KZfKuL5urKp7qey08ha31L8b3BwewJAoJamTzyvxPR/5D+KkdJCGPq/+8TukHBlY10FX9A==} + engines: {node: '>=6.9.0'} + + /@babel/helper-validator-option@7.23.5: + resolution: {integrity: sha512-85ttAOMLsr53VgXkTbkx8oA6YTfT4q7/HzXSLEYmjcSTJPMPQtvq1BD79Byep5xMUYbGRzEpDsjUf3dyp54IKw==} + engines: {node: '>=6.9.0'} + + /@babel/helpers@7.24.1: + resolution: {integrity: sha512-BpU09QqEe6ZCHuIHFphEFgvNSrubve1FtyMton26ekZ85gRGi6LrTF7zArARp2YvyFxloeiRmtSCq5sjh1WqIg==} + engines: {node: '>=6.9.0'} + dependencies: + '@babel/template': 7.24.0 + '@babel/traverse': 7.24.1 + '@babel/types': 7.24.0 + transitivePeerDependencies: + - supports-color + + /@babel/highlight@7.24.2: + resolution: {integrity: sha512-Yac1ao4flkTxTteCDZLEvdxg2fZfz1v8M4QpaGypq/WPDqg3ijHYbDfs+LG5hvzSoqaSZ9/Z9lKSP3CjZjv+pA==} + engines: {node: '>=6.9.0'} + dependencies: + '@babel/helper-validator-identifier': 7.22.20 + chalk: 2.4.2 + js-tokens: 4.0.0 + picocolors: 1.0.0 + + /@babel/parser@7.24.1: + resolution: {integrity: sha512-Zo9c7N3xdOIQrNip7Lc9wvRPzlRtovHVE4lkz8WEDr7uYh/GMQhSiIgFxGIArRHYdJE5kxtZjAf8rT0xhdLCzg==} + engines: {node: '>=6.0.0'} + hasBin: true + dependencies: + '@babel/types': 7.24.0 + + /@babel/plugin-syntax-async-generators@7.8.4(@babel/core@7.24.3): + resolution: {integrity: sha512-tycmZxkGfZaxhMRbXlPXuVFpdWlXpir2W4AMhSJgRKzk/eDlIXOhb2LHWoLpDF7TEHylV5zNhykX6KAgHJmTNw==} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.24.3 + '@babel/helper-plugin-utils': 7.24.0 + dev: true + + /@babel/plugin-syntax-bigint@7.8.3(@babel/core@7.24.3): + resolution: {integrity: sha512-wnTnFlG+YxQm3vDxpGE57Pj0srRU4sHE/mDkt1qv2YJJSeUAec2ma4WLUnUPeKjyrfntVwe/N6dCXpU+zL3Npg==} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.24.3 + '@babel/helper-plugin-utils': 7.24.0 + dev: true + + /@babel/plugin-syntax-class-properties@7.12.13(@babel/core@7.24.3): + resolution: {integrity: sha512-fm4idjKla0YahUNgFNLCB0qySdsoPiZP3iQE3rky0mBUtMZ23yDJ9SJdg6dXTSDnulOVqiF3Hgr9nbXvXTQZYA==} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.24.3 + '@babel/helper-plugin-utils': 7.24.0 + dev: true + + /@babel/plugin-syntax-import-meta@7.10.4(@babel/core@7.24.3): + resolution: {integrity: sha512-Yqfm+XDx0+Prh3VSeEQCPU81yC+JWZ2pDPFSS4ZdpfZhp4MkFMaDC1UqseovEKwSUpnIL7+vK+Clp7bfh0iD7g==} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.24.3 + '@babel/helper-plugin-utils': 7.24.0 + dev: true + + /@babel/plugin-syntax-json-strings@7.8.3(@babel/core@7.24.3): + resolution: {integrity: sha512-lY6kdGpWHvjoe2vk4WrAapEuBR69EMxZl+RoGRhrFGNYVK8mOPAW8VfbT/ZgrFbXlDNiiaxQnAtgVCZ6jv30EA==} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.24.3 + '@babel/helper-plugin-utils': 7.24.0 + dev: true + + /@babel/plugin-syntax-jsx@7.24.1(@babel/core@7.24.3): + resolution: {integrity: sha512-2eCtxZXf+kbkMIsXS4poTvT4Yu5rXiRa+9xGVT56raghjmBTKMpFNc9R4IDiB4emao9eO22Ox7CxuJG7BgExqA==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.24.3 + '@babel/helper-plugin-utils': 7.24.0 + dev: true + + /@babel/plugin-syntax-logical-assignment-operators@7.10.4(@babel/core@7.24.3): + resolution: {integrity: sha512-d8waShlpFDinQ5MtvGU9xDAOzKH47+FFoney2baFIoMr952hKOLp1HR7VszoZvOsV/4+RRszNY7D17ba0te0ig==} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.24.3 + '@babel/helper-plugin-utils': 7.24.0 + dev: true + + /@babel/plugin-syntax-nullish-coalescing-operator@7.8.3(@babel/core@7.24.3): + resolution: {integrity: sha512-aSff4zPII1u2QD7y+F8oDsz19ew4IGEJg9SVW+bqwpwtfFleiQDMdzA/R+UlWDzfnHFCxxleFT0PMIrR36XLNQ==} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.24.3 + '@babel/helper-plugin-utils': 7.24.0 + dev: true + + /@babel/plugin-syntax-numeric-separator@7.10.4(@babel/core@7.24.3): + resolution: {integrity: sha512-9H6YdfkcK/uOnY/K7/aA2xpzaAgkQn37yzWUMRK7OaPOqOpGS1+n0H5hxT9AUw9EsSjPW8SVyMJwYRtWs3X3ug==} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.24.3 + '@babel/helper-plugin-utils': 7.24.0 + dev: true + + /@babel/plugin-syntax-object-rest-spread@7.8.3(@babel/core@7.24.3): + resolution: {integrity: sha512-XoqMijGZb9y3y2XskN+P1wUGiVwWZ5JmoDRwx5+3GmEplNyVM2s2Dg8ILFQm8rWM48orGy5YpI5Bl8U1y7ydlA==} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.24.3 + '@babel/helper-plugin-utils': 7.24.0 + dev: true + + /@babel/plugin-syntax-optional-catch-binding@7.8.3(@babel/core@7.24.3): + resolution: {integrity: sha512-6VPD0Pc1lpTqw0aKoeRTMiB+kWhAoT24PA+ksWSBrFtl5SIRVpZlwN3NNPQjehA2E/91FV3RjLWoVTglWcSV3Q==} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.24.3 + '@babel/helper-plugin-utils': 7.24.0 + dev: true + + /@babel/plugin-syntax-optional-chaining@7.8.3(@babel/core@7.24.3): + resolution: {integrity: sha512-KoK9ErH1MBlCPxV0VANkXW2/dw4vlbGDrFgz8bmUsBGYkFRcbRwMh6cIJubdPrkxRwuGdtCk0v/wPTKbQgBjkg==} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.24.3 + '@babel/helper-plugin-utils': 7.24.0 + dev: true + + /@babel/plugin-syntax-top-level-await@7.14.5(@babel/core@7.24.3): + resolution: {integrity: sha512-hx++upLv5U1rgYfwe1xBQUhRmU41NEvpUvrp8jkrSCdvGSnM5/qdRMtylJ6PG5OFkBaHkbTAKTnd3/YyESRHFw==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.24.3 + '@babel/helper-plugin-utils': 7.24.0 + dev: true + + /@babel/plugin-syntax-typescript@7.24.1(@babel/core@7.24.3): + resolution: {integrity: sha512-Yhnmvy5HZEnHUty6i++gcfH1/l68AHnItFHnaCv6hn9dNh0hQvvQJsxpi4BMBFN5DLeHBuucT/0DgzXif/OyRw==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.24.3 + '@babel/helper-plugin-utils': 7.24.0 + dev: true + + /@babel/plugin-transform-react-jsx-self@7.24.1(@babel/core@7.24.1): + resolution: {integrity: sha512-kDJgnPujTmAZ/9q2CN4m2/lRsUUPDvsG3+tSHWUJIzMGTt5U/b/fwWd3RO3n+5mjLrsBrVa5eKFRVSQbi3dF1w==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.24.1 + '@babel/helper-plugin-utils': 7.24.0 + dev: true + + /@babel/plugin-transform-react-jsx-source@7.24.1(@babel/core@7.24.1): + resolution: {integrity: sha512-1v202n7aUq4uXAieRTKcwPzNyphlCuqHHDcdSNc+vdhoTEZcFMh+L5yZuCmGaIO7bs1nJUNfHB89TZyoL48xNA==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.24.1 + '@babel/helper-plugin-utils': 7.24.0 + dev: true + + /@babel/runtime@7.24.1: + resolution: {integrity: sha512-+BIznRzyqBf+2wCTxcKE3wDjfGeCoVE61KSHGpkzqrLi8qxqFwBeUFyId2cxkTmm55fzDGnm0+yCxaxygrLUnQ==} + engines: {node: '>=6.9.0'} + dependencies: + regenerator-runtime: 0.14.1 + dev: false + + /@babel/template@7.24.0: + resolution: {integrity: sha512-Bkf2q8lMB0AFpX0NFEqSbx1OkTHf0f+0j82mkw+ZpzBnkk7e9Ql0891vlfgi+kHwOk8tQjiQHpqh4LaSa0fKEA==} + engines: {node: '>=6.9.0'} + dependencies: + '@babel/code-frame': 7.24.2 + '@babel/parser': 7.24.1 + '@babel/types': 7.24.0 + + /@babel/traverse@7.24.1: + resolution: {integrity: sha512-xuU6o9m68KeqZbQuDt2TcKSxUw/mrsvavlEqQ1leZ/B+C9tk6E4sRWy97WaXgvq5E+nU3cXMxv3WKOCanVMCmQ==} + engines: {node: '>=6.9.0'} + dependencies: + '@babel/code-frame': 7.24.2 + '@babel/generator': 7.24.1 + '@babel/helper-environment-visitor': 7.22.20 + '@babel/helper-function-name': 7.23.0 + '@babel/helper-hoist-variables': 7.22.5 + '@babel/helper-split-export-declaration': 7.22.6 + '@babel/parser': 7.24.1 + '@babel/types': 7.24.0 + debug: 4.3.4 + globals: 11.12.0 + transitivePeerDependencies: + - supports-color + + /@babel/types@7.24.0: + resolution: {integrity: sha512-+j7a5c253RfKh8iABBhywc8NSfP5LURe7Uh4qpsh6jc+aLJguvmIUBdjSdEMQv2bENrCR5MfRdjGo7vzS/ob7w==} + engines: {node: '>=6.9.0'} + dependencies: + '@babel/helper-string-parser': 7.24.1 + '@babel/helper-validator-identifier': 7.22.20 + to-fast-properties: 2.0.0 + + /@bcoe/v8-coverage@0.2.3: + resolution: {integrity: sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==} + dev: true + + /@blockshake/defly-connect@1.1.6(algosdk@2.7.0): + resolution: {integrity: sha512-pgibHfWjTkfyjQhRVKR2mnnG7Vv/oBJGowphrIwdF62TkElRspsCrv/GcasZ2ipw+Wrqp3cdsE1W7GU0ZjgPwg==} + peerDependencies: + algosdk: ^2.1.0 + dependencies: + '@walletconnect/client': 1.8.0 + '@walletconnect/types': 1.8.0 + algosdk: 2.7.0 + bowser: 2.11.0 + buffer: 6.0.3 + lottie-web: 5.12.2 + qr-code-styling: 1.6.0-rc.1 + transitivePeerDependencies: + - bufferutil + - utf-8-validate + dev: false + + /@cspotcode/source-map-support@0.8.1: + resolution: {integrity: sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==} + engines: {node: '>=12'} + dependencies: + '@jridgewell/trace-mapping': 0.3.9 + + /@daffiwallet/connect@1.0.3(algosdk@2.7.0): + resolution: {integrity: sha512-H2YaVfvsAW57s23JpJD9cP97hJsO527YtoT/Iga/fBlUUe6akXGi5Uvz3q6KAI8jD7GJ4N3qQTpK4nFbTHmDyQ==} + peerDependencies: + algosdk: ^2.1.0 + dependencies: + '@evanhahn/lottie-web-light': 5.8.1 + '@walletconnect/client': 1.8.0 + '@walletconnect/types': 1.8.0 + algosdk: 2.7.0 + bowser: 2.11.0 + buffer: 6.0.3 + qr-code-styling: 1.5.0 + transitivePeerDependencies: + - bufferutil + - utf-8-validate + dev: false + + /@esbuild/aix-ppc64@0.19.12: + resolution: {integrity: sha512-bmoCYyWdEL3wDQIVbcyzRyeKLgk2WtWLTWz1ZIAZF/EGbNOwSA6ew3PftJ1PqMiOOGu0OyFMzG53L0zqIpPeNA==} + engines: {node: '>=12'} + cpu: [ppc64] + os: [aix] + requiresBuild: true + dev: true + optional: true + + /@esbuild/android-arm64@0.19.12: + resolution: {integrity: sha512-P0UVNGIienjZv3f5zq0DP3Nt2IE/3plFzuaS96vihvD0Hd6H/q4WXUGpCxD/E8YrSXfNyRPbpTq+T8ZQioSuPA==} + engines: {node: '>=12'} + cpu: [arm64] + os: [android] + requiresBuild: true + dev: true + optional: true + + /@esbuild/android-arm@0.19.12: + resolution: {integrity: sha512-qg/Lj1mu3CdQlDEEiWrlC4eaPZ1KztwGJ9B6J+/6G+/4ewxJg7gqj8eVYWvao1bXrqGiW2rsBZFSX3q2lcW05w==} + engines: {node: '>=12'} + cpu: [arm] + os: [android] + requiresBuild: true + dev: true + optional: true + + /@esbuild/android-x64@0.19.12: + resolution: {integrity: sha512-3k7ZoUW6Q6YqhdhIaq/WZ7HwBpnFBlW905Fa4s4qWJyiNOgT1dOqDiVAQFwBH7gBRZr17gLrlFCRzF6jFh7Kew==} + engines: {node: '>=12'} + cpu: [x64] + os: [android] + requiresBuild: true + dev: true + optional: true + + /@esbuild/darwin-arm64@0.19.12: + resolution: {integrity: sha512-B6IeSgZgtEzGC42jsI+YYu9Z3HKRxp8ZT3cqhvliEHovq8HSX2YX8lNocDn79gCKJXOSaEot9MVYky7AKjCs8g==} + engines: {node: '>=12'} + cpu: [arm64] + os: [darwin] + requiresBuild: true + dev: true + optional: true + + /@esbuild/darwin-x64@0.19.12: + resolution: {integrity: sha512-hKoVkKzFiToTgn+41qGhsUJXFlIjxI/jSYeZf3ugemDYZldIXIxhvwN6erJGlX4t5h417iFuheZ7l+YVn05N3A==} + engines: {node: '>=12'} + cpu: [x64] + os: [darwin] + requiresBuild: true + dev: true + optional: true + + /@esbuild/freebsd-arm64@0.19.12: + resolution: {integrity: sha512-4aRvFIXmwAcDBw9AueDQ2YnGmz5L6obe5kmPT8Vd+/+x/JMVKCgdcRwH6APrbpNXsPz+K653Qg8HB/oXvXVukA==} + engines: {node: '>=12'} + cpu: [arm64] + os: [freebsd] + requiresBuild: true + dev: true + optional: true + + /@esbuild/freebsd-x64@0.19.12: + resolution: {integrity: sha512-EYoXZ4d8xtBoVN7CEwWY2IN4ho76xjYXqSXMNccFSx2lgqOG/1TBPW0yPx1bJZk94qu3tX0fycJeeQsKovA8gg==} + engines: {node: '>=12'} + cpu: [x64] + os: [freebsd] + requiresBuild: true + dev: true + optional: true + + /@esbuild/linux-arm64@0.19.12: + resolution: {integrity: sha512-EoTjyYyLuVPfdPLsGVVVC8a0p1BFFvtpQDB/YLEhaXyf/5bczaGeN15QkR+O4S5LeJ92Tqotve7i1jn35qwvdA==} + engines: {node: '>=12'} + cpu: [arm64] + os: [linux] + requiresBuild: true + dev: true + optional: true + + /@esbuild/linux-arm@0.19.12: + resolution: {integrity: sha512-J5jPms//KhSNv+LO1S1TX1UWp1ucM6N6XuL6ITdKWElCu8wXP72l9MM0zDTzzeikVyqFE6U8YAV9/tFyj0ti+w==} + engines: {node: '>=12'} + cpu: [arm] + os: [linux] + requiresBuild: true + dev: true + optional: true + + /@esbuild/linux-ia32@0.19.12: + resolution: {integrity: sha512-Thsa42rrP1+UIGaWz47uydHSBOgTUnwBwNq59khgIwktK6x60Hivfbux9iNR0eHCHzOLjLMLfUMLCypBkZXMHA==} + engines: {node: '>=12'} + cpu: [ia32] + os: [linux] + requiresBuild: true + dev: true + optional: true + + /@esbuild/linux-loong64@0.19.12: + resolution: {integrity: sha512-LiXdXA0s3IqRRjm6rV6XaWATScKAXjI4R4LoDlvO7+yQqFdlr1Bax62sRwkVvRIrwXxvtYEHHI4dm50jAXkuAA==} + engines: {node: '>=12'} + cpu: [loong64] + os: [linux] + requiresBuild: true + dev: true + optional: true + + /@esbuild/linux-mips64el@0.19.12: + resolution: {integrity: sha512-fEnAuj5VGTanfJ07ff0gOA6IPsvrVHLVb6Lyd1g2/ed67oU1eFzL0r9WL7ZzscD+/N6i3dWumGE1Un4f7Amf+w==} + engines: {node: '>=12'} + cpu: [mips64el] + os: [linux] + requiresBuild: true + dev: true + optional: true + + /@esbuild/linux-ppc64@0.19.12: + resolution: {integrity: sha512-nYJA2/QPimDQOh1rKWedNOe3Gfc8PabU7HT3iXWtNUbRzXS9+vgB0Fjaqr//XNbd82mCxHzik2qotuI89cfixg==} + engines: {node: '>=12'} + cpu: [ppc64] + os: [linux] + requiresBuild: true + dev: true + optional: true + + /@esbuild/linux-riscv64@0.19.12: + resolution: {integrity: sha512-2MueBrlPQCw5dVJJpQdUYgeqIzDQgw3QtiAHUC4RBz9FXPrskyyU3VI1hw7C0BSKB9OduwSJ79FTCqtGMWqJHg==} + engines: {node: '>=12'} + cpu: [riscv64] + os: [linux] + requiresBuild: true + dev: true + optional: true + + /@esbuild/linux-s390x@0.19.12: + resolution: {integrity: sha512-+Pil1Nv3Umes4m3AZKqA2anfhJiVmNCYkPchwFJNEJN5QxmTs1uzyy4TvmDrCRNT2ApwSari7ZIgrPeUx4UZDg==} + engines: {node: '>=12'} + cpu: [s390x] + os: [linux] + requiresBuild: true + dev: true + optional: true + + /@esbuild/linux-x64@0.19.12: + resolution: {integrity: sha512-B71g1QpxfwBvNrfyJdVDexenDIt1CiDN1TIXLbhOw0KhJzE78KIFGX6OJ9MrtC0oOqMWf+0xop4qEU8JrJTwCg==} + engines: {node: '>=12'} + cpu: [x64] + os: [linux] + requiresBuild: true + dev: true + optional: true + + /@esbuild/netbsd-x64@0.19.12: + resolution: {integrity: sha512-3ltjQ7n1owJgFbuC61Oj++XhtzmymoCihNFgT84UAmJnxJfm4sYCiSLTXZtE00VWYpPMYc+ZQmB6xbSdVh0JWA==} + engines: {node: '>=12'} + cpu: [x64] + os: [netbsd] + requiresBuild: true + dev: true + optional: true + + /@esbuild/openbsd-x64@0.19.12: + resolution: {integrity: sha512-RbrfTB9SWsr0kWmb9srfF+L933uMDdu9BIzdA7os2t0TXhCRjrQyCeOt6wVxr79CKD4c+p+YhCj31HBkYcXebw==} + engines: {node: '>=12'} + cpu: [x64] + os: [openbsd] + requiresBuild: true + dev: true + optional: true + + /@esbuild/sunos-x64@0.19.12: + resolution: {integrity: sha512-HKjJwRrW8uWtCQnQOz9qcU3mUZhTUQvi56Q8DPTLLB+DawoiQdjsYq+j+D3s9I8VFtDr+F9CjgXKKC4ss89IeA==} + engines: {node: '>=12'} + cpu: [x64] + os: [sunos] + requiresBuild: true + dev: true + optional: true + + /@esbuild/win32-arm64@0.19.12: + resolution: {integrity: sha512-URgtR1dJnmGvX864pn1B2YUYNzjmXkuJOIqG2HdU62MVS4EHpU2946OZoTMnRUHklGtJdJZ33QfzdjGACXhn1A==} + engines: {node: '>=12'} + cpu: [arm64] + os: [win32] + requiresBuild: true + dev: true + optional: true + + /@esbuild/win32-ia32@0.19.12: + resolution: {integrity: sha512-+ZOE6pUkMOJfmxmBZElNOx72NKpIa/HFOMGzu8fqzQJ5kgf6aTGrcJaFsNiVMH4JKpMipyK+7k0n2UXN7a8YKQ==} + engines: {node: '>=12'} + cpu: [ia32] + os: [win32] + requiresBuild: true + dev: true + optional: true + + /@esbuild/win32-x64@0.19.12: + resolution: {integrity: sha512-T1QyPSDCyMXaO3pzBkF96E8xMkiRYbUEZADd29SyPGabqxMViNoii+NcK7eWJAEoU6RZyEm5lVSIjTmcdoB9HA==} + engines: {node: '>=12'} + cpu: [x64] + os: [win32] + requiresBuild: true + dev: true + optional: true + + /@eslint-community/eslint-utils@4.4.0(eslint@8.57.0): + resolution: {integrity: sha512-1/sA4dwrzBAyeUoQ6oxahHKmrZvsnLCg4RfxW3ZFGGmQkSNQPFNLV9CUEFQP1x9EYXHTo5p6xdhZM1Ne9p/AfA==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + peerDependencies: + eslint: ^6.0.0 || ^7.0.0 || >=8.0.0 + dependencies: + eslint: 8.57.0 + eslint-visitor-keys: 3.4.3 + dev: true + + /@eslint-community/regexpp@4.10.0: + resolution: {integrity: sha512-Cu96Sd2By9mCNTx2iyKOmq10v22jUVQv0lQnlGNy16oE9589yE+QADPbrMGCkA51cKZSg3Pu/aTJVTGfL/qjUA==} + engines: {node: ^12.0.0 || ^14.0.0 || >=16.0.0} + dev: true + + /@eslint/eslintrc@2.1.4: + resolution: {integrity: sha512-269Z39MS6wVJtsoUl10L60WdkhJVdPG24Q4eZTH3nnF6lpvSShEK3wQjDX9JRWAUPvPh7COouPpU9IrqaZFvtQ==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + dependencies: + ajv: 6.12.6 + debug: 4.3.4 + espree: 9.6.1 + globals: 13.24.0 + ignore: 5.3.1 + import-fresh: 3.3.0 + js-yaml: 4.1.0 + minimatch: 3.1.2 + strip-json-comments: 3.1.1 + transitivePeerDependencies: + - supports-color + dev: true + + /@eslint/js@8.57.0: + resolution: {integrity: sha512-Ys+3g2TaW7gADOJzPt83SJtCDhMjndcDMFVQ/Tj9iA1BfJzFKD9mAUXT3OenpuPHbI6P/myECxRJrofUsDx/5g==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + dev: true + + /@evanhahn/lottie-web-light@5.8.1: + resolution: {integrity: sha512-U0G1tt3/UEYnyCNNslWPi1dB7X1xQ9aoSip+B3GTKO/Bns8yz/p39vBkRSN9d25nkbHuCsbjky2coQftj5YVKw==} + dev: false + + /@floating-ui/core@1.6.0: + resolution: {integrity: sha512-PcF++MykgmTj3CIyOQbKA/hDzOAiqI3mhuoN44WRCopIs1sgoDoU4oty4Jtqaj/y3oDU6fnVSm4QG0a3t5i0+g==} + dependencies: + '@floating-ui/utils': 0.2.1 + dev: false + + /@floating-ui/dom@1.6.3: + resolution: {integrity: sha512-RnDthu3mzPlQ31Ss/BTwQ1zjzIhr3lk1gZB1OC56h/1vEtaXkESrOqL5fQVMfXpwGtRwX+YsZBdyHtJMQnkArw==} + dependencies: + '@floating-ui/core': 1.6.0 + '@floating-ui/utils': 0.2.1 + dev: false + + /@floating-ui/react-dom@2.0.8(react-dom@18.2.0)(react@18.2.0): + resolution: {integrity: sha512-HOdqOt3R3OGeTKidaLvJKcgg75S6tibQ3Tif4eyd91QnIJWr0NLvoXFpJA/j8HqkFSL68GDca9AuyWEHlhyClw==} + peerDependencies: + react: '>=16.8.0' + react-dom: '>=16.8.0' + dependencies: + '@floating-ui/dom': 1.6.3 + react: 18.2.0 + react-dom: 18.2.0(react@18.2.0) + dev: false + + /@floating-ui/utils@0.2.1: + resolution: {integrity: sha512-9TANp6GPoMtYzQdt54kfAyMmz1+osLlXdg2ENroU7zzrtflTLrrC/lgrIfaSe+Wu0b89GKccT7vxXA0MoAIO+Q==} + dev: false + + /@hookform/resolvers@3.3.4(react-hook-form@7.51.1): + resolution: {integrity: sha512-o5cgpGOuJYrd+iMKvkttOclgwRW86EsWJZZRC23prf0uU2i48Htq4PuT73AVb9ionFyZrwYEITuOFGF+BydEtQ==} + peerDependencies: + react-hook-form: ^7.0.0 + dependencies: + react-hook-form: 7.51.1(react@18.2.0) + dev: false + + /@humanwhocodes/config-array@0.11.14: + resolution: {integrity: sha512-3T8LkOmg45BV5FICb15QQMsyUSWrQ8AygVfC7ZG32zOalnqrilm018ZVCw0eapXux8FtA33q8PSRSstjee3jSg==} + engines: {node: '>=10.10.0'} + dependencies: + '@humanwhocodes/object-schema': 2.0.2 + debug: 4.3.4 + minimatch: 3.1.2 + transitivePeerDependencies: + - supports-color + dev: true + + /@humanwhocodes/module-importer@1.0.1: + resolution: {integrity: sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==} + engines: {node: '>=12.22'} + dev: true + + /@humanwhocodes/object-schema@2.0.2: + resolution: {integrity: sha512-6EwiSjwWYP7pTckG6I5eyFANjPhmPjUX9JRLUSfNPC7FX7zK9gyZAfUEaECL6ALTpGX5AjnBq3C9XmVWPitNpw==} + dev: true + + /@isaacs/cliui@8.0.2: + resolution: {integrity: sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==} + engines: {node: '>=12'} + dependencies: + string-width: 5.1.2 + string-width-cjs: /string-width@4.2.3 + strip-ansi: 7.1.0 + strip-ansi-cjs: /strip-ansi@6.0.1 + wrap-ansi: 8.1.0 + wrap-ansi-cjs: /wrap-ansi@7.0.0 + + /@istanbuljs/load-nyc-config@1.1.0: + resolution: {integrity: sha512-VjeHSlIzpv/NyD3N0YuHfXOPDIixcA1q2ZV98wsMqcYlPmv2n3Yb2lYP9XMElnaFVXg5A7YLTeLu6V84uQDjmQ==} + engines: {node: '>=8'} + dependencies: + camelcase: 5.3.1 + find-up: 4.1.0 + get-package-type: 0.1.0 + js-yaml: 3.14.1 + resolve-from: 5.0.0 + dev: true + + /@istanbuljs/schema@0.1.3: + resolution: {integrity: sha512-ZXRY4jNvVgSVQ8DL3LTcakaAtXwTVUxE81hslsyD2AtoXW/wVob10HkOJ1X/pAlcI7D+2YoZKg5do8G/w6RYgA==} + engines: {node: '>=8'} + dev: true + + /@jest/console@29.7.0: + resolution: {integrity: sha512-5Ni4CU7XHQi32IJ398EEP4RrB8eV09sXP2ROqD4bksHrnTree52PsxvX8tpL8LvTZ3pFzXyPbNQReSN41CAhOg==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + dependencies: + '@jest/types': 29.6.3 + '@types/node': 18.19.28 + chalk: 4.1.2 + jest-message-util: 29.7.0 + jest-util: 29.7.0 + slash: 3.0.0 + dev: true + + /@jest/core@29.7.0(ts-node@10.9.2): + resolution: {integrity: sha512-n7aeXWKMnGtDA48y8TLWJPJmLmmZ642Ceo78cYWEpiD7FzDgmNDV/GCVRorPABdXLJZ/9wzzgZAlHjXjxDHGsg==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + peerDependencies: + node-notifier: ^8.0.1 || ^9.0.0 || ^10.0.0 + peerDependenciesMeta: + node-notifier: + optional: true + dependencies: + '@jest/console': 29.7.0 + '@jest/reporters': 29.7.0 + '@jest/test-result': 29.7.0 + '@jest/transform': 29.7.0 + '@jest/types': 29.6.3 + '@types/node': 18.19.28 + ansi-escapes: 4.3.2 + chalk: 4.1.2 + ci-info: 3.9.0 + exit: 0.1.2 + graceful-fs: 4.2.11 + jest-changed-files: 29.7.0 + jest-config: 29.7.0(@types/node@18.19.28)(ts-node@10.9.2) + jest-haste-map: 29.7.0 + jest-message-util: 29.7.0 + jest-regex-util: 29.6.3 + jest-resolve: 29.7.0 + jest-resolve-dependencies: 29.7.0 + jest-runner: 29.7.0 + jest-runtime: 29.7.0 + jest-snapshot: 29.7.0 + jest-util: 29.7.0 + jest-validate: 29.7.0 + jest-watcher: 29.7.0 + micromatch: 4.0.5 + pretty-format: 29.7.0 + slash: 3.0.0 + strip-ansi: 6.0.1 + transitivePeerDependencies: + - babel-plugin-macros + - supports-color + - ts-node + dev: true + + /@jest/environment@29.7.0: + resolution: {integrity: sha512-aQIfHDq33ExsN4jP1NWGXhxgQ/wixs60gDiKO+XVMd8Mn0NWPWgc34ZQDTb2jKaUWQ7MuwoitXAsN2XVXNMpAw==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + dependencies: + '@jest/fake-timers': 29.7.0 + '@jest/types': 29.6.3 + '@types/node': 18.19.28 + jest-mock: 29.7.0 + dev: true + + /@jest/expect-utils@29.7.0: + resolution: {integrity: sha512-GlsNBWiFQFCVi9QVSx7f5AgMeLxe9YCCs5PuP2O2LdjDAA8Jh9eX7lA1Jq/xdXw3Wb3hyvlFNfZIfcRetSzYcA==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + dependencies: + jest-get-type: 29.6.3 + dev: true + + /@jest/expect@29.7.0: + resolution: {integrity: sha512-8uMeAMycttpva3P1lBHB8VciS9V0XAr3GymPpipdyQXbBcuhkLQOSe8E/p92RyAdToS6ZD1tFkX+CkhoECE0dQ==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + dependencies: + expect: 29.7.0 + jest-snapshot: 29.7.0 + transitivePeerDependencies: + - supports-color + dev: true + + /@jest/fake-timers@29.7.0: + resolution: {integrity: sha512-q4DH1Ha4TTFPdxLsqDXK1d3+ioSL7yL5oCMJZgDYm6i+6CygW5E5xVr/D1HdsGxjt1ZWSfUAs9OxSB/BNelWrQ==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + dependencies: + '@jest/types': 29.6.3 + '@sinonjs/fake-timers': 10.3.0 + '@types/node': 18.19.28 + jest-message-util: 29.7.0 + jest-mock: 29.7.0 + jest-util: 29.7.0 + dev: true + + /@jest/globals@29.7.0: + resolution: {integrity: sha512-mpiz3dutLbkW2MNFubUGUEVLkTGiqW6yLVTA+JbP6fI6J5iL9Y0Nlg8k95pcF8ctKwCS7WVxteBs29hhfAotzQ==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + dependencies: + '@jest/environment': 29.7.0 + '@jest/expect': 29.7.0 + '@jest/types': 29.6.3 + jest-mock: 29.7.0 + transitivePeerDependencies: + - supports-color + dev: true + + /@jest/reporters@29.7.0: + resolution: {integrity: sha512-DApq0KJbJOEzAFYjHADNNxAE3KbhxQB1y5Kplb5Waqw6zVbuWatSnMjE5gs8FUgEPmNsnZA3NCWl9NG0ia04Pg==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + peerDependencies: + node-notifier: ^8.0.1 || ^9.0.0 || ^10.0.0 + peerDependenciesMeta: + node-notifier: + optional: true + dependencies: + '@bcoe/v8-coverage': 0.2.3 + '@jest/console': 29.7.0 + '@jest/test-result': 29.7.0 + '@jest/transform': 29.7.0 + '@jest/types': 29.6.3 + '@jridgewell/trace-mapping': 0.3.25 + '@types/node': 18.19.28 + chalk: 4.1.2 + collect-v8-coverage: 1.0.2 + exit: 0.1.2 + glob: 7.2.3 + graceful-fs: 4.2.11 + istanbul-lib-coverage: 3.2.2 + istanbul-lib-instrument: 6.0.2 + istanbul-lib-report: 3.0.1 + istanbul-lib-source-maps: 4.0.1 + istanbul-reports: 3.1.7 + jest-message-util: 29.7.0 + jest-util: 29.7.0 + jest-worker: 29.7.0 + slash: 3.0.0 + string-length: 4.0.2 + strip-ansi: 6.0.1 + v8-to-istanbul: 9.2.0 + transitivePeerDependencies: + - supports-color + dev: true + + /@jest/schemas@29.6.3: + resolution: {integrity: sha512-mo5j5X+jIZmJQveBKeS/clAueipV7KgiX1vMgCxam1RNYiqE1w62n0/tJJnHtjW8ZHcQco5gY85jA3mi0L+nSA==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + dependencies: + '@sinclair/typebox': 0.27.8 + dev: true + + /@jest/source-map@29.6.3: + resolution: {integrity: sha512-MHjT95QuipcPrpLM+8JMSzFx6eHp5Bm+4XeFDJlwsvVBjmKNiIAvasGK2fxz2WbGRlnvqehFbh07MMa7n3YJnw==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + dependencies: + '@jridgewell/trace-mapping': 0.3.25 + callsites: 3.1.0 + graceful-fs: 4.2.11 + dev: true + + /@jest/test-result@29.7.0: + resolution: {integrity: sha512-Fdx+tv6x1zlkJPcWXmMDAG2HBnaR9XPSd5aDWQVsfrZmLVT3lU1cwyxLgRmXR9yrq4NBoEm9BMsfgFzTQAbJYA==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + dependencies: + '@jest/console': 29.7.0 + '@jest/types': 29.6.3 + '@types/istanbul-lib-coverage': 2.0.6 + collect-v8-coverage: 1.0.2 + dev: true + + /@jest/test-sequencer@29.7.0: + resolution: {integrity: sha512-GQwJ5WZVrKnOJuiYiAF52UNUJXgTZx1NHjFSEB0qEMmSZKAkdMoIzw/Cj6x6NF4AvV23AUqDpFzQkN/eYCYTxw==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + dependencies: + '@jest/test-result': 29.7.0 + graceful-fs: 4.2.11 + jest-haste-map: 29.7.0 + slash: 3.0.0 + dev: true + + /@jest/transform@29.7.0: + resolution: {integrity: sha512-ok/BTPFzFKVMwO5eOHRrvnBVHdRy9IrsrW1GpMaQ9MCnilNLXQKmAX8s1YXDFaai9xJpac2ySzV0YeRRECr2Vw==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + dependencies: + '@babel/core': 7.24.3 + '@jest/types': 29.6.3 + '@jridgewell/trace-mapping': 0.3.25 + babel-plugin-istanbul: 6.1.1 + chalk: 4.1.2 + convert-source-map: 2.0.0 + fast-json-stable-stringify: 2.1.0 + graceful-fs: 4.2.11 + jest-haste-map: 29.7.0 + jest-regex-util: 29.6.3 + jest-util: 29.7.0 + micromatch: 4.0.5 + pirates: 4.0.6 + slash: 3.0.0 + write-file-atomic: 4.0.2 + transitivePeerDependencies: + - supports-color + dev: true + + /@jest/types@29.6.3: + resolution: {integrity: sha512-u3UPsIilWKOM3F9CXtrG8LEJmNxwoCQC/XVj4IKYXvvpx7QIi/Kg1LI5uDmDpKlac62NUtX7eLjRh+jVZcLOzw==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + dependencies: + '@jest/schemas': 29.6.3 + '@types/istanbul-lib-coverage': 2.0.6 + '@types/istanbul-reports': 3.0.4 + '@types/node': 18.19.26 + '@types/yargs': 17.0.32 + chalk: 4.1.2 + dev: true + + /@jridgewell/gen-mapping@0.3.5: + resolution: {integrity: sha512-IzL8ZoEDIBRWEzlCcRhOaCupYyN5gdIK+Q6fbFdPDg6HqX6jpkItn7DFIpW9LQzXG6Df9sA7+OKnq0qlz/GaQg==} + engines: {node: '>=6.0.0'} + dependencies: + '@jridgewell/set-array': 1.2.1 + '@jridgewell/sourcemap-codec': 1.4.15 + '@jridgewell/trace-mapping': 0.3.25 + + /@jridgewell/resolve-uri@3.1.2: + resolution: {integrity: sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==} + engines: {node: '>=6.0.0'} + + /@jridgewell/set-array@1.2.1: + resolution: {integrity: sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A==} + engines: {node: '>=6.0.0'} + + /@jridgewell/sourcemap-codec@1.4.15: + resolution: {integrity: sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==} + + /@jridgewell/trace-mapping@0.3.25: + resolution: {integrity: sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==} + dependencies: + '@jridgewell/resolve-uri': 3.1.2 + '@jridgewell/sourcemap-codec': 1.4.15 + + /@jridgewell/trace-mapping@0.3.9: + resolution: {integrity: sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==} + dependencies: + '@jridgewell/resolve-uri': 3.1.2 + '@jridgewell/sourcemap-codec': 1.4.15 + + /@lit-labs/ssr-dom-shim@1.2.0: + resolution: {integrity: sha512-yWJKmpGE6lUURKAaIltoPIE/wrbY3TEkqQt+X0m+7fQNnAv0keydnYvbiJFP1PnMhizmIWRWOG5KLhYyc/xl+g==} + dev: false + + /@lit/reactive-element@1.6.3: + resolution: {integrity: sha512-QuTgnG52Poic7uM1AN5yJ09QMe0O28e10XzSvWDz02TJiiKee4stsiownEIadWm8nYzyDAyT+gKzUoZmiWQtsQ==} + dependencies: + '@lit-labs/ssr-dom-shim': 1.2.0 + dev: false + + /@motionone/animation@10.17.0: + resolution: {integrity: sha512-ANfIN9+iq1kGgsZxs+Nz96uiNcPLGTXwfNo2Xz/fcJXniPYpaz/Uyrfa+7I5BPLxCP82sh7quVDudf1GABqHbg==} + dependencies: + '@motionone/easing': 10.17.0 + '@motionone/types': 10.17.0 + '@motionone/utils': 10.17.0 + tslib: 2.6.2 + dev: false + + /@motionone/dom@10.17.0: + resolution: {integrity: sha512-cMm33swRlCX/qOPHWGbIlCl0K9Uwi6X5RiL8Ma6OrlJ/TP7Q+Np5GE4xcZkFptysFjMTi4zcZzpnNQGQ5D6M0Q==} + dependencies: + '@motionone/animation': 10.17.0 + '@motionone/generators': 10.17.0 + '@motionone/types': 10.17.0 + '@motionone/utils': 10.17.0 + hey-listen: 1.0.8 + tslib: 2.6.2 + dev: false + + /@motionone/easing@10.17.0: + resolution: {integrity: sha512-Bxe2wSuLu/qxqW4rBFS5m9tMLOw+QBh8v5A7Z5k4Ul4sTj5jAOfZG5R0bn5ywmk+Fs92Ij1feZ5pmC4TeXA8Tg==} + dependencies: + '@motionone/utils': 10.17.0 + tslib: 2.6.2 + dev: false + + /@motionone/generators@10.17.0: + resolution: {integrity: sha512-T6Uo5bDHrZWhIfxG/2Aut7qyWQyJIWehk6OB4qNvr/jwA/SRmixwbd7SOrxZi1z5rH3LIeFFBKK1xHnSbGPZSQ==} + dependencies: + '@motionone/types': 10.17.0 + '@motionone/utils': 10.17.0 + tslib: 2.6.2 + dev: false + + /@motionone/svelte@10.16.4: + resolution: {integrity: sha512-zRVqk20lD1xqe+yEDZhMYgftsuHc25+9JSo+r0a0OWUJFocjSV9D/+UGhX4xgJsuwB9acPzXLr20w40VnY2PQA==} + dependencies: + '@motionone/dom': 10.17.0 + tslib: 2.6.2 + dev: false + + /@motionone/types@10.17.0: + resolution: {integrity: sha512-EgeeqOZVdRUTEHq95Z3t8Rsirc7chN5xFAPMYFobx8TPubkEfRSm5xihmMUkbaR2ErKJTUw3347QDPTHIW12IA==} + dev: false + + /@motionone/utils@10.17.0: + resolution: {integrity: sha512-bGwrki4896apMWIj9yp5rAS2m0xyhxblg6gTB/leWDPt+pb410W8lYWsxyurX+DH+gO1zsQsfx2su/c1/LtTpg==} + dependencies: + '@motionone/types': 10.17.0 + hey-listen: 1.0.8 + tslib: 2.6.2 + dev: false + + /@motionone/vue@10.16.4: + resolution: {integrity: sha512-z10PF9JV6SbjFq+/rYabM+8CVlMokgl8RFGvieSGNTmrkQanfHn+15XBrhG3BgUfvmTeSeyShfOHpG0i9zEdcg==} + deprecated: Motion One for Vue is deprecated. Use Oku Motion instead https://oku-ui.com/motion + dependencies: + '@motionone/dom': 10.17.0 + tslib: 2.6.2 + dev: false + + /@next/env@14.1.4: + resolution: {integrity: sha512-e7X7bbn3Z6DWnDi75UWn+REgAbLEqxI8Tq2pkFOFAMpWAWApz/YCUhtWMWn410h8Q2fYiYL7Yg5OlxMOCfFjJQ==} + dev: false + + /@next/swc-darwin-arm64@14.1.4: + resolution: {integrity: sha512-ubmUkbmW65nIAOmoxT1IROZdmmJMmdYvXIe8211send9ZYJu+SqxSnJM4TrPj9wmL6g9Atvj0S/2cFmMSS99jg==} + engines: {node: '>= 10'} + cpu: [arm64] + os: [darwin] + requiresBuild: true + dev: false + optional: true + + /@next/swc-darwin-x64@14.1.4: + resolution: {integrity: sha512-b0Xo1ELj3u7IkZWAKcJPJEhBop117U78l70nfoQGo4xUSvv0PJSTaV4U9xQBLvZlnjsYkc8RwQN1HoH/oQmLlQ==} + engines: {node: '>= 10'} + cpu: [x64] + os: [darwin] + requiresBuild: true + dev: false + optional: true + + /@next/swc-linux-arm64-gnu@14.1.4: + resolution: {integrity: sha512-457G0hcLrdYA/u1O2XkRMsDKId5VKe3uKPvrKVOyuARa6nXrdhJOOYU9hkKKyQTMru1B8qEP78IAhf/1XnVqKA==} + engines: {node: '>= 10'} + cpu: [arm64] + os: [linux] + requiresBuild: true + dev: false + optional: true + + /@next/swc-linux-arm64-musl@14.1.4: + resolution: {integrity: sha512-l/kMG+z6MB+fKA9KdtyprkTQ1ihlJcBh66cf0HvqGP+rXBbOXX0dpJatjZbHeunvEHoBBS69GYQG5ry78JMy3g==} + engines: {node: '>= 10'} + cpu: [arm64] + os: [linux] + requiresBuild: true + dev: false + optional: true + + /@next/swc-linux-x64-gnu@14.1.4: + resolution: {integrity: sha512-BapIFZ3ZRnvQ1uWbmqEGJuPT9cgLwvKtxhK/L2t4QYO7l+/DxXuIGjvp1x8rvfa/x1FFSsipERZK70pewbtJtw==} + engines: {node: '>= 10'} + cpu: [x64] + os: [linux] + requiresBuild: true + dev: false + optional: true + + /@next/swc-linux-x64-musl@14.1.4: + resolution: {integrity: sha512-mqVxTwk4XuBl49qn2A5UmzFImoL1iLm0KQQwtdRJRKl21ylQwwGCxJtIYo2rbfkZHoSKlh/YgztY0qH3wG1xIg==} + engines: {node: '>= 10'} + cpu: [x64] + os: [linux] + requiresBuild: true + dev: false + optional: true + + /@next/swc-win32-arm64-msvc@14.1.4: + resolution: {integrity: sha512-xzxF4ErcumXjO2Pvg/wVGrtr9QQJLk3IyQX1ddAC/fi6/5jZCZ9xpuL9Tzc4KPWMFq8GGWFVDMshZOdHGdkvag==} + engines: {node: '>= 10'} + cpu: [arm64] + os: [win32] + requiresBuild: true + dev: false + optional: true + + /@next/swc-win32-ia32-msvc@14.1.4: + resolution: {integrity: sha512-WZiz8OdbkpRw6/IU/lredZWKKZopUMhcI2F+XiMAcPja0uZYdMTZQRoQ0WZcvinn9xZAidimE7tN9W5v9Yyfyw==} + engines: {node: '>= 10'} + cpu: [ia32] + os: [win32] + requiresBuild: true + dev: false + optional: true + + /@next/swc-win32-x64-msvc@14.1.4: + resolution: {integrity: sha512-4Rto21sPfw555sZ/XNLqfxDUNeLhNYGO2dlPqsnuCg8N8a2a9u1ltqBOPQ4vj1Gf7eJC0W2hHG2eYUHuiXgY2w==} + engines: {node: '>= 10'} + cpu: [x64] + os: [win32] + requiresBuild: true + dev: false + optional: true + + /@nodelib/fs.scandir@2.1.5: + resolution: {integrity: sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==} + engines: {node: '>= 8'} + dependencies: + '@nodelib/fs.stat': 2.0.5 + run-parallel: 1.2.0 + + /@nodelib/fs.stat@2.0.5: + resolution: {integrity: sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==} + engines: {node: '>= 8'} + + /@nodelib/fs.walk@1.2.8: + resolution: {integrity: sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==} + engines: {node: '>= 8'} + dependencies: + '@nodelib/fs.scandir': 2.1.5 + fastq: 1.17.1 + + /@parcel/watcher-android-arm64@2.4.1: + resolution: {integrity: sha512-LOi/WTbbh3aTn2RYddrO8pnapixAziFl6SMxHM69r3tvdSm94JtCenaKgk1GRg5FJ5wpMCpHeW+7yqPlvZv7kg==} + engines: {node: '>= 10.0.0'} + cpu: [arm64] + os: [android] + requiresBuild: true + dev: false + optional: true + + /@parcel/watcher-darwin-arm64@2.4.1: + resolution: {integrity: sha512-ln41eihm5YXIY043vBrrHfn94SIBlqOWmoROhsMVTSXGh0QahKGy77tfEywQ7v3NywyxBBkGIfrWRHm0hsKtzA==} + engines: {node: '>= 10.0.0'} + cpu: [arm64] + os: [darwin] + requiresBuild: true + dev: false + optional: true + + /@parcel/watcher-darwin-x64@2.4.1: + resolution: {integrity: sha512-yrw81BRLjjtHyDu7J61oPuSoeYWR3lDElcPGJyOvIXmor6DEo7/G2u1o7I38cwlcoBHQFULqF6nesIX3tsEXMg==} + engines: {node: '>= 10.0.0'} + cpu: [x64] + os: [darwin] + requiresBuild: true + dev: false + optional: true + + /@parcel/watcher-freebsd-x64@2.4.1: + resolution: {integrity: sha512-TJa3Pex/gX3CWIx/Co8k+ykNdDCLx+TuZj3f3h7eOjgpdKM+Mnix37RYsYU4LHhiYJz3DK5nFCCra81p6g050w==} + engines: {node: '>= 10.0.0'} + cpu: [x64] + os: [freebsd] + requiresBuild: true + dev: false + optional: true + + /@parcel/watcher-linux-arm-glibc@2.4.1: + resolution: {integrity: sha512-4rVYDlsMEYfa537BRXxJ5UF4ddNwnr2/1O4MHM5PjI9cvV2qymvhwZSFgXqbS8YoTk5i/JR0L0JDs69BUn45YA==} + engines: {node: '>= 10.0.0'} + cpu: [arm] + os: [linux] + requiresBuild: true + dev: false + optional: true + + /@parcel/watcher-linux-arm64-glibc@2.4.1: + resolution: {integrity: sha512-BJ7mH985OADVLpbrzCLgrJ3TOpiZggE9FMblfO65PlOCdG++xJpKUJ0Aol74ZUIYfb8WsRlUdgrZxKkz3zXWYA==} + engines: {node: '>= 10.0.0'} + cpu: [arm64] + os: [linux] + requiresBuild: true + dev: false + optional: true + + /@parcel/watcher-linux-arm64-musl@2.4.1: + resolution: {integrity: sha512-p4Xb7JGq3MLgAfYhslU2SjoV9G0kI0Xry0kuxeG/41UfpjHGOhv7UoUDAz/jb1u2elbhazy4rRBL8PegPJFBhA==} + engines: {node: '>= 10.0.0'} + cpu: [arm64] + os: [linux] + requiresBuild: true + dev: false + optional: true + + /@parcel/watcher-linux-x64-glibc@2.4.1: + resolution: {integrity: sha512-s9O3fByZ/2pyYDPoLM6zt92yu6P4E39a03zvO0qCHOTjxmt3GHRMLuRZEWhWLASTMSrrnVNWdVI/+pUElJBBBg==} + engines: {node: '>= 10.0.0'} + cpu: [x64] + os: [linux] + requiresBuild: true + dev: false + optional: true + + /@parcel/watcher-linux-x64-musl@2.4.1: + resolution: {integrity: sha512-L2nZTYR1myLNST0O632g0Dx9LyMNHrn6TOt76sYxWLdff3cB22/GZX2UPtJnaqQPdCRoszoY5rcOj4oMTtp5fQ==} + engines: {node: '>= 10.0.0'} + cpu: [x64] + os: [linux] + requiresBuild: true + dev: false + optional: true + + /@parcel/watcher-wasm@2.4.1: + resolution: {integrity: sha512-/ZR0RxqxU/xxDGzbzosMjh4W6NdYFMqq2nvo2b8SLi7rsl/4jkL8S5stIikorNkdR50oVDvqb/3JT05WM+CRRA==} + engines: {node: '>= 10.0.0'} + dependencies: + is-glob: 4.0.3 + micromatch: 4.0.5 + dev: false + bundledDependencies: + - napi-wasm + + /@parcel/watcher-win32-arm64@2.4.1: + resolution: {integrity: sha512-Uq2BPp5GWhrq/lcuItCHoqxjULU1QYEcyjSO5jqqOK8RNFDBQnenMMx4gAl3v8GiWa59E9+uDM7yZ6LxwUIfRg==} + engines: {node: '>= 10.0.0'} + cpu: [arm64] + os: [win32] + requiresBuild: true + dev: false + optional: true + + /@parcel/watcher-win32-ia32@2.4.1: + resolution: {integrity: sha512-maNRit5QQV2kgHFSYwftmPBxiuK5u4DXjbXx7q6eKjq5dsLXZ4FJiVvlcw35QXzk0KrUecJmuVFbj4uV9oYrcw==} + engines: {node: '>= 10.0.0'} + cpu: [ia32] + os: [win32] + requiresBuild: true + dev: false + optional: true + + /@parcel/watcher-win32-x64@2.4.1: + resolution: {integrity: sha512-+DvS92F9ezicfswqrvIRM2njcYJbd5mb9CUgtrHCHmvn7pPPa+nMDRu1o1bYYz/l5IB2NVGNJWiH7h1E58IF2A==} + engines: {node: '>= 10.0.0'} + cpu: [x64] + os: [win32] + requiresBuild: true + dev: false + optional: true + + /@parcel/watcher@2.4.1: + resolution: {integrity: sha512-HNjmfLQEVRZmHRET336f20H/8kOozUGwk7yajvsonjNxbj2wBTK1WsQuHkD5yYh9RxFGL2EyDHryOihOwUoKDA==} + engines: {node: '>= 10.0.0'} + dependencies: + detect-libc: 1.0.3 + is-glob: 4.0.3 + micromatch: 4.0.5 + node-addon-api: 7.1.0 + optionalDependencies: + '@parcel/watcher-android-arm64': 2.4.1 + '@parcel/watcher-darwin-arm64': 2.4.1 + '@parcel/watcher-darwin-x64': 2.4.1 + '@parcel/watcher-freebsd-x64': 2.4.1 + '@parcel/watcher-linux-arm-glibc': 2.4.1 + '@parcel/watcher-linux-arm64-glibc': 2.4.1 + '@parcel/watcher-linux-arm64-musl': 2.4.1 + '@parcel/watcher-linux-x64-glibc': 2.4.1 + '@parcel/watcher-linux-x64-musl': 2.4.1 + '@parcel/watcher-win32-arm64': 2.4.1 + '@parcel/watcher-win32-ia32': 2.4.1 + '@parcel/watcher-win32-x64': 2.4.1 + dev: false + + /@perawallet/connect@1.3.4(algosdk@2.7.0): + resolution: {integrity: sha512-PRnD1YEXXoWjTlfWmZCGGHQWn7Zquxh44bXmEtluklq/kTkBOk5CToZWng1J/Ae9g0xMR85B1Y/xwnriFufcpA==} + peerDependencies: + algosdk: ^2.1.0 + dependencies: + '@evanhahn/lottie-web-light': 5.8.1 + '@walletconnect/client': 1.8.0 + '@walletconnect/types': 1.8.0 + algosdk: 2.7.0 + bowser: 2.11.0 + buffer: 6.0.3 + qr-code-styling: 1.6.0-rc.1 + transitivePeerDependencies: + - bufferutil + - utf-8-validate + dev: false + + /@pkgjs/parseargs@0.11.0: + resolution: {integrity: sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==} + engines: {node: '>=14'} + requiresBuild: true + optional: true + + /@pkgr/core@0.1.1: + resolution: {integrity: sha512-cq8o4cWH0ibXh9VGi5P20Tu9XF/0fFXl9EUinr9QfTM7a7p0oTA4iJRCQWppXR1Pg8dSM0UCItCkPwsk9qWWYA==} + engines: {node: ^12.20.0 || ^14.18.0 || >=16.0.0} + dev: true + + /@playwright/test@1.42.1: + resolution: {integrity: sha512-Gq9rmS54mjBL/7/MvBaNOBwbfnh7beHvS6oS4srqXFcQHpQCV1+c8JXWE8VLPyRDhgS3H8x8A7hztqI9VnwrAQ==} + engines: {node: '>=16'} + hasBin: true + dependencies: + playwright: 1.42.1 + dev: true + + /@radix-ui/number@1.0.1: + resolution: {integrity: sha512-T5gIdVO2mmPW3NNhjNgEP3cqMXjXL9UbO0BzWcXfvdBs+BohbQxvd/K5hSVKmn9/lbTdsQVKbUcP5WLCwvUbBg==} + dependencies: + '@babel/runtime': 7.24.1 + dev: false + + /@radix-ui/primitive@1.0.1: + resolution: {integrity: sha512-yQ8oGX2GVsEYMWGxcovu1uGWPCxV5BFfeeYxqPmuAzUyLT9qmaMXSAhXpb0WrspIeqYzdJpkh2vHModJPgRIaw==} + dependencies: + '@babel/runtime': 7.24.1 + dev: false + + /@radix-ui/react-arrow@1.0.3(@types/react-dom@18.2.22)(@types/react@18.2.67)(react-dom@18.2.0)(react@18.2.0): + resolution: {integrity: sha512-wSP+pHsB/jQRaL6voubsQ/ZlrGBHHrOjmBnr19hxYgtS0WvAFwZhK2WP/YY5yF9uKECCEEDGxuLxq1NBK51wFA==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 + react-dom: ^16.8 || ^17.0 || ^18.0 + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + dependencies: + '@babel/runtime': 7.24.1 + '@radix-ui/react-primitive': 1.0.3(@types/react-dom@18.2.22)(@types/react@18.2.67)(react-dom@18.2.0)(react@18.2.0) + '@types/react': 18.2.67 + '@types/react-dom': 18.2.22 + react: 18.2.0 + react-dom: 18.2.0(react@18.2.0) + dev: false + + /@radix-ui/react-avatar@1.0.4(@types/react-dom@18.2.22)(@types/react@18.2.67)(react-dom@18.2.0)(react@18.2.0): + resolution: {integrity: sha512-kVK2K7ZD3wwj3qhle0ElXhOjbezIgyl2hVvgwfIdexL3rN6zJmy5AqqIf+D31lxVppdzV8CjAfZ6PklkmInZLw==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 + react-dom: ^16.8 || ^17.0 || ^18.0 + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + dependencies: + '@babel/runtime': 7.24.1 + '@radix-ui/react-context': 1.0.1(@types/react@18.2.67)(react@18.2.0) + '@radix-ui/react-primitive': 1.0.3(@types/react-dom@18.2.22)(@types/react@18.2.67)(react-dom@18.2.0)(react@18.2.0) + '@radix-ui/react-use-callback-ref': 1.0.1(@types/react@18.2.67)(react@18.2.0) + '@radix-ui/react-use-layout-effect': 1.0.1(@types/react@18.2.67)(react@18.2.0) + '@types/react': 18.2.67 + '@types/react-dom': 18.2.22 + react: 18.2.0 + react-dom: 18.2.0(react@18.2.0) + dev: false + + /@radix-ui/react-checkbox@1.0.4(@types/react-dom@18.2.22)(@types/react@18.2.67)(react-dom@18.2.0)(react@18.2.0): + resolution: {integrity: sha512-CBuGQa52aAYnADZVt/KBQzXrwx6TqnlwtcIPGtVt5JkkzQwMOLJjPukimhfKEr4GQNd43C+djUh5Ikopj8pSLg==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 + react-dom: ^16.8 || ^17.0 || ^18.0 + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + dependencies: + '@babel/runtime': 7.24.1 + '@radix-ui/primitive': 1.0.1 + '@radix-ui/react-compose-refs': 1.0.1(@types/react@18.2.67)(react@18.2.0) + '@radix-ui/react-context': 1.0.1(@types/react@18.2.67)(react@18.2.0) + '@radix-ui/react-presence': 1.0.1(@types/react-dom@18.2.22)(@types/react@18.2.67)(react-dom@18.2.0)(react@18.2.0) + '@radix-ui/react-primitive': 1.0.3(@types/react-dom@18.2.22)(@types/react@18.2.67)(react-dom@18.2.0)(react@18.2.0) + '@radix-ui/react-use-controllable-state': 1.0.1(@types/react@18.2.67)(react@18.2.0) + '@radix-ui/react-use-previous': 1.0.1(@types/react@18.2.67)(react@18.2.0) + '@radix-ui/react-use-size': 1.0.1(@types/react@18.2.67)(react@18.2.0) + '@types/react': 18.2.67 + '@types/react-dom': 18.2.22 + react: 18.2.0 + react-dom: 18.2.0(react@18.2.0) + dev: false + + /@radix-ui/react-collection@1.0.3(@types/react-dom@18.2.22)(@types/react@18.2.67)(react-dom@18.2.0)(react@18.2.0): + resolution: {integrity: sha512-3SzW+0PW7yBBoQlT8wNcGtaxaD0XSu0uLUFgrtHY08Acx05TaHaOmVLR73c0j/cqpDy53KBMO7s0dx2wmOIDIA==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 + react-dom: ^16.8 || ^17.0 || ^18.0 + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + dependencies: + '@babel/runtime': 7.24.1 + '@radix-ui/react-compose-refs': 1.0.1(@types/react@18.2.67)(react@18.2.0) + '@radix-ui/react-context': 1.0.1(@types/react@18.2.67)(react@18.2.0) + '@radix-ui/react-primitive': 1.0.3(@types/react-dom@18.2.22)(@types/react@18.2.67)(react-dom@18.2.0)(react@18.2.0) + '@radix-ui/react-slot': 1.0.2(@types/react@18.2.67)(react@18.2.0) + '@types/react': 18.2.67 + '@types/react-dom': 18.2.22 + react: 18.2.0 + react-dom: 18.2.0(react@18.2.0) + dev: false + + /@radix-ui/react-compose-refs@1.0.1(@types/react@18.2.67)(react@18.2.0): + resolution: {integrity: sha512-fDSBgd44FKHa1FRMU59qBMPFcl2PZE+2nmqunj+BWFyYYjnhIDWL2ItDs3rrbJDQOtzt5nIebLCQc4QRfz6LJw==} + peerDependencies: + '@types/react': '*' + react: ^16.8 || ^17.0 || ^18.0 + peerDependenciesMeta: + '@types/react': + optional: true + dependencies: + '@babel/runtime': 7.24.1 + '@types/react': 18.2.67 + react: 18.2.0 + dev: false + + /@radix-ui/react-context@1.0.1(@types/react@18.2.67)(react@18.2.0): + resolution: {integrity: sha512-ebbrdFoYTcuZ0v4wG5tedGnp9tzcV8awzsxYph7gXUyvnNLuTIcCk1q17JEbnVhXAKG9oX3KtchwiMIAYp9NLg==} + peerDependencies: + '@types/react': '*' + react: ^16.8 || ^17.0 || ^18.0 + peerDependenciesMeta: + '@types/react': + optional: true + dependencies: + '@babel/runtime': 7.24.1 + '@types/react': 18.2.67 + react: 18.2.0 + dev: false + + /@radix-ui/react-dialog@1.0.5(@types/react-dom@18.2.22)(@types/react@18.2.67)(react-dom@18.2.0)(react@18.2.0): + resolution: {integrity: sha512-GjWJX/AUpB703eEBanuBnIWdIXg6NvJFCXcNlSZk4xdszCdhrJgBoUd1cGk67vFO+WdA2pfI/plOpqz/5GUP6Q==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 + react-dom: ^16.8 || ^17.0 || ^18.0 + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + dependencies: + '@babel/runtime': 7.24.1 + '@radix-ui/primitive': 1.0.1 + '@radix-ui/react-compose-refs': 1.0.1(@types/react@18.2.67)(react@18.2.0) + '@radix-ui/react-context': 1.0.1(@types/react@18.2.67)(react@18.2.0) + '@radix-ui/react-dismissable-layer': 1.0.5(@types/react-dom@18.2.22)(@types/react@18.2.67)(react-dom@18.2.0)(react@18.2.0) + '@radix-ui/react-focus-guards': 1.0.1(@types/react@18.2.67)(react@18.2.0) + '@radix-ui/react-focus-scope': 1.0.4(@types/react-dom@18.2.22)(@types/react@18.2.67)(react-dom@18.2.0)(react@18.2.0) + '@radix-ui/react-id': 1.0.1(@types/react@18.2.67)(react@18.2.0) + '@radix-ui/react-portal': 1.0.4(@types/react-dom@18.2.22)(@types/react@18.2.67)(react-dom@18.2.0)(react@18.2.0) + '@radix-ui/react-presence': 1.0.1(@types/react-dom@18.2.22)(@types/react@18.2.67)(react-dom@18.2.0)(react@18.2.0) + '@radix-ui/react-primitive': 1.0.3(@types/react-dom@18.2.22)(@types/react@18.2.67)(react-dom@18.2.0)(react@18.2.0) + '@radix-ui/react-slot': 1.0.2(@types/react@18.2.67)(react@18.2.0) + '@radix-ui/react-use-controllable-state': 1.0.1(@types/react@18.2.67)(react@18.2.0) + '@types/react': 18.2.67 + '@types/react-dom': 18.2.22 + aria-hidden: 1.2.3 + react: 18.2.0 + react-dom: 18.2.0(react@18.2.0) + react-remove-scroll: 2.5.5(@types/react@18.2.67)(react@18.2.0) + dev: false + + /@radix-ui/react-direction@1.0.1(@types/react@18.2.67)(react@18.2.0): + resolution: {integrity: sha512-RXcvnXgyvYvBEOhCBuddKecVkoMiI10Jcm5cTI7abJRAHYfFxeu+FBQs/DvdxSYucxR5mna0dNsL6QFlds5TMA==} + peerDependencies: + '@types/react': '*' + react: ^16.8 || ^17.0 || ^18.0 + peerDependenciesMeta: + '@types/react': + optional: true + dependencies: + '@babel/runtime': 7.24.1 + '@types/react': 18.2.67 + react: 18.2.0 + dev: false + + /@radix-ui/react-dismissable-layer@1.0.5(@types/react-dom@18.2.22)(@types/react@18.2.67)(react-dom@18.2.0)(react@18.2.0): + resolution: {integrity: sha512-aJeDjQhywg9LBu2t/At58hCvr7pEm0o2Ke1x33B+MhjNmmZ17sy4KImo0KPLgsnc/zN7GPdce8Cnn0SWvwZO7g==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 + react-dom: ^16.8 || ^17.0 || ^18.0 + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + dependencies: + '@babel/runtime': 7.24.1 + '@radix-ui/primitive': 1.0.1 + '@radix-ui/react-compose-refs': 1.0.1(@types/react@18.2.67)(react@18.2.0) + '@radix-ui/react-primitive': 1.0.3(@types/react-dom@18.2.22)(@types/react@18.2.67)(react-dom@18.2.0)(react@18.2.0) + '@radix-ui/react-use-callback-ref': 1.0.1(@types/react@18.2.67)(react@18.2.0) + '@radix-ui/react-use-escape-keydown': 1.0.3(@types/react@18.2.67)(react@18.2.0) + '@types/react': 18.2.67 + '@types/react-dom': 18.2.22 + react: 18.2.0 + react-dom: 18.2.0(react@18.2.0) + dev: false + + /@radix-ui/react-dropdown-menu@2.0.6(@types/react-dom@18.2.22)(@types/react@18.2.67)(react-dom@18.2.0)(react@18.2.0): + resolution: {integrity: sha512-i6TuFOoWmLWq+M/eCLGd/bQ2HfAX1RJgvrBQ6AQLmzfvsLdefxbWu8G9zczcPFfcSPehz9GcpF6K9QYreFV8hA==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 + react-dom: ^16.8 || ^17.0 || ^18.0 + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + dependencies: + '@babel/runtime': 7.24.1 + '@radix-ui/primitive': 1.0.1 + '@radix-ui/react-compose-refs': 1.0.1(@types/react@18.2.67)(react@18.2.0) + '@radix-ui/react-context': 1.0.1(@types/react@18.2.67)(react@18.2.0) + '@radix-ui/react-id': 1.0.1(@types/react@18.2.67)(react@18.2.0) + '@radix-ui/react-menu': 2.0.6(@types/react-dom@18.2.22)(@types/react@18.2.67)(react-dom@18.2.0)(react@18.2.0) + '@radix-ui/react-primitive': 1.0.3(@types/react-dom@18.2.22)(@types/react@18.2.67)(react-dom@18.2.0)(react@18.2.0) + '@radix-ui/react-use-controllable-state': 1.0.1(@types/react@18.2.67)(react@18.2.0) + '@types/react': 18.2.67 + '@types/react-dom': 18.2.22 + react: 18.2.0 + react-dom: 18.2.0(react@18.2.0) + dev: false + + /@radix-ui/react-focus-guards@1.0.1(@types/react@18.2.67)(react@18.2.0): + resolution: {integrity: sha512-Rect2dWbQ8waGzhMavsIbmSVCgYxkXLxxR3ZvCX79JOglzdEy4JXMb98lq4hPxUbLr77nP0UOGf4rcMU+s1pUA==} + peerDependencies: + '@types/react': '*' + react: ^16.8 || ^17.0 || ^18.0 + peerDependenciesMeta: + '@types/react': + optional: true + dependencies: + '@babel/runtime': 7.24.1 + '@types/react': 18.2.67 + react: 18.2.0 + dev: false + + /@radix-ui/react-focus-scope@1.0.4(@types/react-dom@18.2.22)(@types/react@18.2.67)(react-dom@18.2.0)(react@18.2.0): + resolution: {integrity: sha512-sL04Mgvf+FmyvZeYfNu1EPAaaxD+aw7cYeIB9L9Fvq8+urhltTRaEo5ysKOpHuKPclsZcSUMKlN05x4u+CINpA==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 + react-dom: ^16.8 || ^17.0 || ^18.0 + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + dependencies: + '@babel/runtime': 7.24.1 + '@radix-ui/react-compose-refs': 1.0.1(@types/react@18.2.67)(react@18.2.0) + '@radix-ui/react-primitive': 1.0.3(@types/react-dom@18.2.22)(@types/react@18.2.67)(react-dom@18.2.0)(react@18.2.0) + '@radix-ui/react-use-callback-ref': 1.0.1(@types/react@18.2.67)(react@18.2.0) + '@types/react': 18.2.67 + '@types/react-dom': 18.2.22 + react: 18.2.0 + react-dom: 18.2.0(react@18.2.0) + dev: false + + /@radix-ui/react-icons@1.3.0(react@18.2.0): + resolution: {integrity: sha512-jQxj/0LKgp+j9BiTXz3O3sgs26RNet2iLWmsPyRz2SIcR4q/4SbazXfnYwbAr+vLYKSfc7qxzyGQA1HLlYiuNw==} + peerDependencies: + react: ^16.x || ^17.x || ^18.x + dependencies: + react: 18.2.0 + dev: false + + /@radix-ui/react-id@1.0.1(@types/react@18.2.67)(react@18.2.0): + resolution: {integrity: sha512-tI7sT/kqYp8p96yGWY1OAnLHrqDgzHefRBKQ2YAkBS5ja7QLcZ9Z/uY7bEjPUatf8RomoXM8/1sMj1IJaE5UzQ==} + peerDependencies: + '@types/react': '*' + react: ^16.8 || ^17.0 || ^18.0 + peerDependenciesMeta: + '@types/react': + optional: true + dependencies: + '@babel/runtime': 7.24.1 + '@radix-ui/react-use-layout-effect': 1.0.1(@types/react@18.2.67)(react@18.2.0) + '@types/react': 18.2.67 + react: 18.2.0 + dev: false + + /@radix-ui/react-label@2.0.2(@types/react-dom@18.2.22)(@types/react@18.2.67)(react-dom@18.2.0)(react@18.2.0): + resolution: {integrity: sha512-N5ehvlM7qoTLx7nWPodsPYPgMzA5WM8zZChQg8nyFJKnDO5WHdba1vv5/H6IO5LtJMfD2Q3wh1qHFGNtK0w3bQ==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 + react-dom: ^16.8 || ^17.0 || ^18.0 + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + dependencies: + '@babel/runtime': 7.24.1 + '@radix-ui/react-primitive': 1.0.3(@types/react-dom@18.2.22)(@types/react@18.2.67)(react-dom@18.2.0)(react@18.2.0) + '@types/react': 18.2.67 + '@types/react-dom': 18.2.22 + react: 18.2.0 + react-dom: 18.2.0(react@18.2.0) + dev: false + + /@radix-ui/react-menu@2.0.6(@types/react-dom@18.2.22)(@types/react@18.2.67)(react-dom@18.2.0)(react@18.2.0): + resolution: {integrity: sha512-BVkFLS+bUC8HcImkRKPSiVumA1VPOOEC5WBMiT+QAVsPzW1FJzI9KnqgGxVDPBcql5xXrHkD3JOVoXWEXD8SYA==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 + react-dom: ^16.8 || ^17.0 || ^18.0 + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + dependencies: + '@babel/runtime': 7.24.1 + '@radix-ui/primitive': 1.0.1 + '@radix-ui/react-collection': 1.0.3(@types/react-dom@18.2.22)(@types/react@18.2.67)(react-dom@18.2.0)(react@18.2.0) + '@radix-ui/react-compose-refs': 1.0.1(@types/react@18.2.67)(react@18.2.0) + '@radix-ui/react-context': 1.0.1(@types/react@18.2.67)(react@18.2.0) + '@radix-ui/react-direction': 1.0.1(@types/react@18.2.67)(react@18.2.0) + '@radix-ui/react-dismissable-layer': 1.0.5(@types/react-dom@18.2.22)(@types/react@18.2.67)(react-dom@18.2.0)(react@18.2.0) + '@radix-ui/react-focus-guards': 1.0.1(@types/react@18.2.67)(react@18.2.0) + '@radix-ui/react-focus-scope': 1.0.4(@types/react-dom@18.2.22)(@types/react@18.2.67)(react-dom@18.2.0)(react@18.2.0) + '@radix-ui/react-id': 1.0.1(@types/react@18.2.67)(react@18.2.0) + '@radix-ui/react-popper': 1.1.3(@types/react-dom@18.2.22)(@types/react@18.2.67)(react-dom@18.2.0)(react@18.2.0) + '@radix-ui/react-portal': 1.0.4(@types/react-dom@18.2.22)(@types/react@18.2.67)(react-dom@18.2.0)(react@18.2.0) + '@radix-ui/react-presence': 1.0.1(@types/react-dom@18.2.22)(@types/react@18.2.67)(react-dom@18.2.0)(react@18.2.0) + '@radix-ui/react-primitive': 1.0.3(@types/react-dom@18.2.22)(@types/react@18.2.67)(react-dom@18.2.0)(react@18.2.0) + '@radix-ui/react-roving-focus': 1.0.4(@types/react-dom@18.2.22)(@types/react@18.2.67)(react-dom@18.2.0)(react@18.2.0) + '@radix-ui/react-slot': 1.0.2(@types/react@18.2.67)(react@18.2.0) + '@radix-ui/react-use-callback-ref': 1.0.1(@types/react@18.2.67)(react@18.2.0) + '@types/react': 18.2.67 + '@types/react-dom': 18.2.22 + aria-hidden: 1.2.3 + react: 18.2.0 + react-dom: 18.2.0(react@18.2.0) + react-remove-scroll: 2.5.5(@types/react@18.2.67)(react@18.2.0) + dev: false + + /@radix-ui/react-navigation-menu@1.1.4(@types/react-dom@18.2.22)(@types/react@18.2.67)(react-dom@18.2.0)(react@18.2.0): + resolution: {integrity: sha512-Cc+seCS3PmWmjI51ufGG7zp1cAAIRqHVw7C9LOA2TZ+R4hG6rDvHcTqIsEEFLmZO3zNVH72jOOE7kKNy8W+RtA==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 + react-dom: ^16.8 || ^17.0 || ^18.0 + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + dependencies: + '@babel/runtime': 7.24.1 + '@radix-ui/primitive': 1.0.1 + '@radix-ui/react-collection': 1.0.3(@types/react-dom@18.2.22)(@types/react@18.2.67)(react-dom@18.2.0)(react@18.2.0) + '@radix-ui/react-compose-refs': 1.0.1(@types/react@18.2.67)(react@18.2.0) + '@radix-ui/react-context': 1.0.1(@types/react@18.2.67)(react@18.2.0) + '@radix-ui/react-direction': 1.0.1(@types/react@18.2.67)(react@18.2.0) + '@radix-ui/react-dismissable-layer': 1.0.5(@types/react-dom@18.2.22)(@types/react@18.2.67)(react-dom@18.2.0)(react@18.2.0) + '@radix-ui/react-id': 1.0.1(@types/react@18.2.67)(react@18.2.0) + '@radix-ui/react-presence': 1.0.1(@types/react-dom@18.2.22)(@types/react@18.2.67)(react-dom@18.2.0)(react@18.2.0) + '@radix-ui/react-primitive': 1.0.3(@types/react-dom@18.2.22)(@types/react@18.2.67)(react-dom@18.2.0)(react@18.2.0) + '@radix-ui/react-use-callback-ref': 1.0.1(@types/react@18.2.67)(react@18.2.0) + '@radix-ui/react-use-controllable-state': 1.0.1(@types/react@18.2.67)(react@18.2.0) + '@radix-ui/react-use-layout-effect': 1.0.1(@types/react@18.2.67)(react@18.2.0) + '@radix-ui/react-use-previous': 1.0.1(@types/react@18.2.67)(react@18.2.0) + '@radix-ui/react-visually-hidden': 1.0.3(@types/react-dom@18.2.22)(@types/react@18.2.67)(react-dom@18.2.0)(react@18.2.0) + '@types/react': 18.2.67 + '@types/react-dom': 18.2.22 + react: 18.2.0 + react-dom: 18.2.0(react@18.2.0) + dev: false + + /@radix-ui/react-popper@1.1.3(@types/react-dom@18.2.22)(@types/react@18.2.67)(react-dom@18.2.0)(react@18.2.0): + resolution: {integrity: sha512-cKpopj/5RHZWjrbF2846jBNacjQVwkP068DfmgrNJXpvVWrOvlAmE9xSiy5OqeE+Gi8D9fP+oDhUnPqNMY8/5w==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 + react-dom: ^16.8 || ^17.0 || ^18.0 + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + dependencies: + '@babel/runtime': 7.24.1 + '@floating-ui/react-dom': 2.0.8(react-dom@18.2.0)(react@18.2.0) + '@radix-ui/react-arrow': 1.0.3(@types/react-dom@18.2.22)(@types/react@18.2.67)(react-dom@18.2.0)(react@18.2.0) + '@radix-ui/react-compose-refs': 1.0.1(@types/react@18.2.67)(react@18.2.0) + '@radix-ui/react-context': 1.0.1(@types/react@18.2.67)(react@18.2.0) + '@radix-ui/react-primitive': 1.0.3(@types/react-dom@18.2.22)(@types/react@18.2.67)(react-dom@18.2.0)(react@18.2.0) + '@radix-ui/react-use-callback-ref': 1.0.1(@types/react@18.2.67)(react@18.2.0) + '@radix-ui/react-use-layout-effect': 1.0.1(@types/react@18.2.67)(react@18.2.0) + '@radix-ui/react-use-rect': 1.0.1(@types/react@18.2.67)(react@18.2.0) + '@radix-ui/react-use-size': 1.0.1(@types/react@18.2.67)(react@18.2.0) + '@radix-ui/rect': 1.0.1 + '@types/react': 18.2.67 + '@types/react-dom': 18.2.22 + react: 18.2.0 + react-dom: 18.2.0(react@18.2.0) + dev: false + + /@radix-ui/react-portal@1.0.4(@types/react-dom@18.2.22)(@types/react@18.2.67)(react-dom@18.2.0)(react@18.2.0): + resolution: {integrity: sha512-Qki+C/EuGUVCQTOTD5vzJzJuMUlewbzuKyUy+/iHM2uwGiru9gZeBJtHAPKAEkB5KWGi9mP/CHKcY0wt1aW45Q==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 + react-dom: ^16.8 || ^17.0 || ^18.0 + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + dependencies: + '@babel/runtime': 7.24.1 + '@radix-ui/react-primitive': 1.0.3(@types/react-dom@18.2.22)(@types/react@18.2.67)(react-dom@18.2.0)(react@18.2.0) + '@types/react': 18.2.67 + '@types/react-dom': 18.2.22 + react: 18.2.0 + react-dom: 18.2.0(react@18.2.0) + dev: false + + /@radix-ui/react-presence@1.0.1(@types/react-dom@18.2.22)(@types/react@18.2.67)(react-dom@18.2.0)(react@18.2.0): + resolution: {integrity: sha512-UXLW4UAbIY5ZjcvzjfRFo5gxva8QirC9hF7wRE4U5gz+TP0DbRk+//qyuAQ1McDxBt1xNMBTaciFGvEmJvAZCg==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 + react-dom: ^16.8 || ^17.0 || ^18.0 + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + dependencies: + '@babel/runtime': 7.24.1 + '@radix-ui/react-compose-refs': 1.0.1(@types/react@18.2.67)(react@18.2.0) + '@radix-ui/react-use-layout-effect': 1.0.1(@types/react@18.2.67)(react@18.2.0) + '@types/react': 18.2.67 + '@types/react-dom': 18.2.22 + react: 18.2.0 + react-dom: 18.2.0(react@18.2.0) + dev: false + + /@radix-ui/react-primitive@1.0.3(@types/react-dom@18.2.22)(@types/react@18.2.67)(react-dom@18.2.0)(react@18.2.0): + resolution: {integrity: sha512-yi58uVyoAcK/Nq1inRY56ZSjKypBNKTa/1mcL8qdl6oJeEaDbOldlzrGn7P6Q3Id5d+SYNGc5AJgc4vGhjs5+g==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 + react-dom: ^16.8 || ^17.0 || ^18.0 + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + dependencies: + '@babel/runtime': 7.24.1 + '@radix-ui/react-slot': 1.0.2(@types/react@18.2.67)(react@18.2.0) + '@types/react': 18.2.67 + '@types/react-dom': 18.2.22 + react: 18.2.0 + react-dom: 18.2.0(react@18.2.0) + dev: false + + /@radix-ui/react-roving-focus@1.0.4(@types/react-dom@18.2.22)(@types/react@18.2.67)(react-dom@18.2.0)(react@18.2.0): + resolution: {integrity: sha512-2mUg5Mgcu001VkGy+FfzZyzbmuUWzgWkj3rvv4yu+mLw03+mTzbxZHvfcGyFp2b8EkQeMkpRQ5FiA2Vr2O6TeQ==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 + react-dom: ^16.8 || ^17.0 || ^18.0 + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + dependencies: + '@babel/runtime': 7.24.1 + '@radix-ui/primitive': 1.0.1 + '@radix-ui/react-collection': 1.0.3(@types/react-dom@18.2.22)(@types/react@18.2.67)(react-dom@18.2.0)(react@18.2.0) + '@radix-ui/react-compose-refs': 1.0.1(@types/react@18.2.67)(react@18.2.0) + '@radix-ui/react-context': 1.0.1(@types/react@18.2.67)(react@18.2.0) + '@radix-ui/react-direction': 1.0.1(@types/react@18.2.67)(react@18.2.0) + '@radix-ui/react-id': 1.0.1(@types/react@18.2.67)(react@18.2.0) + '@radix-ui/react-primitive': 1.0.3(@types/react-dom@18.2.22)(@types/react@18.2.67)(react-dom@18.2.0)(react@18.2.0) + '@radix-ui/react-use-callback-ref': 1.0.1(@types/react@18.2.67)(react@18.2.0) + '@radix-ui/react-use-controllable-state': 1.0.1(@types/react@18.2.67)(react@18.2.0) + '@types/react': 18.2.67 + '@types/react-dom': 18.2.22 + react: 18.2.0 + react-dom: 18.2.0(react@18.2.0) + dev: false + + /@radix-ui/react-select@2.0.0(@types/react-dom@18.2.22)(@types/react@18.2.67)(react-dom@18.2.0)(react@18.2.0): + resolution: {integrity: sha512-RH5b7af4oHtkcHS7pG6Sgv5rk5Wxa7XI8W5gvB1N/yiuDGZxko1ynvOiVhFM7Cis2A8zxF9bTOUVbRDzPepe6w==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 + react-dom: ^16.8 || ^17.0 || ^18.0 + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + dependencies: + '@babel/runtime': 7.24.1 + '@radix-ui/number': 1.0.1 + '@radix-ui/primitive': 1.0.1 + '@radix-ui/react-collection': 1.0.3(@types/react-dom@18.2.22)(@types/react@18.2.67)(react-dom@18.2.0)(react@18.2.0) + '@radix-ui/react-compose-refs': 1.0.1(@types/react@18.2.67)(react@18.2.0) + '@radix-ui/react-context': 1.0.1(@types/react@18.2.67)(react@18.2.0) + '@radix-ui/react-direction': 1.0.1(@types/react@18.2.67)(react@18.2.0) + '@radix-ui/react-dismissable-layer': 1.0.5(@types/react-dom@18.2.22)(@types/react@18.2.67)(react-dom@18.2.0)(react@18.2.0) + '@radix-ui/react-focus-guards': 1.0.1(@types/react@18.2.67)(react@18.2.0) + '@radix-ui/react-focus-scope': 1.0.4(@types/react-dom@18.2.22)(@types/react@18.2.67)(react-dom@18.2.0)(react@18.2.0) + '@radix-ui/react-id': 1.0.1(@types/react@18.2.67)(react@18.2.0) + '@radix-ui/react-popper': 1.1.3(@types/react-dom@18.2.22)(@types/react@18.2.67)(react-dom@18.2.0)(react@18.2.0) + '@radix-ui/react-portal': 1.0.4(@types/react-dom@18.2.22)(@types/react@18.2.67)(react-dom@18.2.0)(react@18.2.0) + '@radix-ui/react-primitive': 1.0.3(@types/react-dom@18.2.22)(@types/react@18.2.67)(react-dom@18.2.0)(react@18.2.0) + '@radix-ui/react-slot': 1.0.2(@types/react@18.2.67)(react@18.2.0) + '@radix-ui/react-use-callback-ref': 1.0.1(@types/react@18.2.67)(react@18.2.0) + '@radix-ui/react-use-controllable-state': 1.0.1(@types/react@18.2.67)(react@18.2.0) + '@radix-ui/react-use-layout-effect': 1.0.1(@types/react@18.2.67)(react@18.2.0) + '@radix-ui/react-use-previous': 1.0.1(@types/react@18.2.67)(react@18.2.0) + '@radix-ui/react-visually-hidden': 1.0.3(@types/react-dom@18.2.22)(@types/react@18.2.67)(react-dom@18.2.0)(react@18.2.0) + '@types/react': 18.2.67 + '@types/react-dom': 18.2.22 + aria-hidden: 1.2.3 + react: 18.2.0 + react-dom: 18.2.0(react@18.2.0) + react-remove-scroll: 2.5.5(@types/react@18.2.67)(react@18.2.0) + dev: false + + /@radix-ui/react-slot@1.0.2(@types/react@18.2.67)(react@18.2.0): + resolution: {integrity: sha512-YeTpuq4deV+6DusvVUW4ivBgnkHwECUu0BiN43L5UCDFgdhsRUWAghhTF5MbvNTPzmiFOx90asDSUjWuCNapwg==} + peerDependencies: + '@types/react': '*' + react: ^16.8 || ^17.0 || ^18.0 + peerDependenciesMeta: + '@types/react': + optional: true + dependencies: + '@babel/runtime': 7.24.1 + '@radix-ui/react-compose-refs': 1.0.1(@types/react@18.2.67)(react@18.2.0) + '@types/react': 18.2.67 + react: 18.2.0 + dev: false + + /@radix-ui/react-tooltip@1.0.7(@types/react-dom@18.2.22)(@types/react@18.2.67)(react-dom@18.2.0)(react@18.2.0): + resolution: {integrity: sha512-lPh5iKNFVQ/jav/j6ZrWq3blfDJ0OH9R6FlNUHPMqdLuQ9vwDgFsRxvl8b7Asuy5c8xmoojHUxKHQSOAvMHxyw==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 + react-dom: ^16.8 || ^17.0 || ^18.0 + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + dependencies: + '@babel/runtime': 7.24.1 + '@radix-ui/primitive': 1.0.1 + '@radix-ui/react-compose-refs': 1.0.1(@types/react@18.2.67)(react@18.2.0) + '@radix-ui/react-context': 1.0.1(@types/react@18.2.67)(react@18.2.0) + '@radix-ui/react-dismissable-layer': 1.0.5(@types/react-dom@18.2.22)(@types/react@18.2.67)(react-dom@18.2.0)(react@18.2.0) + '@radix-ui/react-id': 1.0.1(@types/react@18.2.67)(react@18.2.0) + '@radix-ui/react-popper': 1.1.3(@types/react-dom@18.2.22)(@types/react@18.2.67)(react-dom@18.2.0)(react@18.2.0) + '@radix-ui/react-portal': 1.0.4(@types/react-dom@18.2.22)(@types/react@18.2.67)(react-dom@18.2.0)(react@18.2.0) + '@radix-ui/react-presence': 1.0.1(@types/react-dom@18.2.22)(@types/react@18.2.67)(react-dom@18.2.0)(react@18.2.0) + '@radix-ui/react-primitive': 1.0.3(@types/react-dom@18.2.22)(@types/react@18.2.67)(react-dom@18.2.0)(react@18.2.0) + '@radix-ui/react-slot': 1.0.2(@types/react@18.2.67)(react@18.2.0) + '@radix-ui/react-use-controllable-state': 1.0.1(@types/react@18.2.67)(react@18.2.0) + '@radix-ui/react-visually-hidden': 1.0.3(@types/react-dom@18.2.22)(@types/react@18.2.67)(react-dom@18.2.0)(react@18.2.0) + '@types/react': 18.2.67 + '@types/react-dom': 18.2.22 + react: 18.2.0 + react-dom: 18.2.0(react@18.2.0) + dev: false + + /@radix-ui/react-use-callback-ref@1.0.1(@types/react@18.2.67)(react@18.2.0): + resolution: {integrity: sha512-D94LjX4Sp0xJFVaoQOd3OO9k7tpBYNOXdVhkltUbGv2Qb9OXdrg/CpsjlZv7ia14Sylv398LswWBVVu5nqKzAQ==} + peerDependencies: + '@types/react': '*' + react: ^16.8 || ^17.0 || ^18.0 + peerDependenciesMeta: + '@types/react': + optional: true + dependencies: + '@babel/runtime': 7.24.1 + '@types/react': 18.2.67 + react: 18.2.0 + dev: false + + /@radix-ui/react-use-controllable-state@1.0.1(@types/react@18.2.67)(react@18.2.0): + resolution: {integrity: sha512-Svl5GY5FQeN758fWKrjM6Qb7asvXeiZltlT4U2gVfl8Gx5UAv2sMR0LWo8yhsIZh2oQ0eFdZ59aoOOMV7b47VA==} + peerDependencies: + '@types/react': '*' + react: ^16.8 || ^17.0 || ^18.0 + peerDependenciesMeta: + '@types/react': + optional: true + dependencies: + '@babel/runtime': 7.24.1 + '@radix-ui/react-use-callback-ref': 1.0.1(@types/react@18.2.67)(react@18.2.0) + '@types/react': 18.2.67 + react: 18.2.0 + dev: false + + /@radix-ui/react-use-escape-keydown@1.0.3(@types/react@18.2.67)(react@18.2.0): + resolution: {integrity: sha512-vyL82j40hcFicA+M4Ex7hVkB9vHgSse1ZWomAqV2Je3RleKGO5iM8KMOEtfoSB0PnIelMd2lATjTGMYqN5ylTg==} + peerDependencies: + '@types/react': '*' + react: ^16.8 || ^17.0 || ^18.0 + peerDependenciesMeta: + '@types/react': + optional: true + dependencies: + '@babel/runtime': 7.24.1 + '@radix-ui/react-use-callback-ref': 1.0.1(@types/react@18.2.67)(react@18.2.0) + '@types/react': 18.2.67 + react: 18.2.0 + dev: false + + /@radix-ui/react-use-layout-effect@1.0.1(@types/react@18.2.67)(react@18.2.0): + resolution: {integrity: sha512-v/5RegiJWYdoCvMnITBkNNx6bCj20fiaJnWtRkU18yITptraXjffz5Qbn05uOiQnOvi+dbkznkoaMltz1GnszQ==} + peerDependencies: + '@types/react': '*' + react: ^16.8 || ^17.0 || ^18.0 + peerDependenciesMeta: + '@types/react': + optional: true + dependencies: + '@babel/runtime': 7.24.1 + '@types/react': 18.2.67 + react: 18.2.0 + dev: false + + /@radix-ui/react-use-previous@1.0.1(@types/react@18.2.67)(react@18.2.0): + resolution: {integrity: sha512-cV5La9DPwiQ7S0gf/0qiD6YgNqM5Fk97Kdrlc5yBcrF3jyEZQwm7vYFqMo4IfeHgJXsRaMvLABFtd0OVEmZhDw==} + peerDependencies: + '@types/react': '*' + react: ^16.8 || ^17.0 || ^18.0 + peerDependenciesMeta: + '@types/react': + optional: true + dependencies: + '@babel/runtime': 7.24.1 + '@types/react': 18.2.67 + react: 18.2.0 + dev: false + + /@radix-ui/react-use-rect@1.0.1(@types/react@18.2.67)(react@18.2.0): + resolution: {integrity: sha512-Cq5DLuSiuYVKNU8orzJMbl15TXilTnJKUCltMVQg53BQOF1/C5toAaGrowkgksdBQ9H+SRL23g0HDmg9tvmxXw==} + peerDependencies: + '@types/react': '*' + react: ^16.8 || ^17.0 || ^18.0 + peerDependenciesMeta: + '@types/react': + optional: true + dependencies: + '@babel/runtime': 7.24.1 + '@radix-ui/rect': 1.0.1 + '@types/react': 18.2.67 + react: 18.2.0 + dev: false + + /@radix-ui/react-use-size@1.0.1(@types/react@18.2.67)(react@18.2.0): + resolution: {integrity: sha512-ibay+VqrgcaI6veAojjofPATwledXiSmX+C0KrBk/xgpX9rBzPV3OsfwlhQdUOFbh+LKQorLYT+xTXW9V8yd0g==} + peerDependencies: + '@types/react': '*' + react: ^16.8 || ^17.0 || ^18.0 + peerDependenciesMeta: + '@types/react': + optional: true + dependencies: + '@babel/runtime': 7.24.1 + '@radix-ui/react-use-layout-effect': 1.0.1(@types/react@18.2.67)(react@18.2.0) + '@types/react': 18.2.67 + react: 18.2.0 + dev: false + + /@radix-ui/react-visually-hidden@1.0.3(@types/react-dom@18.2.22)(@types/react@18.2.67)(react-dom@18.2.0)(react@18.2.0): + resolution: {integrity: sha512-D4w41yN5YRKtu464TLnByKzMDG/JlMPHtfZgQAu9v6mNakUqGUI9vUrfQKz8NK41VMm/xbZbh76NUTVtIYqOMA==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 + react-dom: ^16.8 || ^17.0 || ^18.0 + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + dependencies: + '@babel/runtime': 7.24.1 + '@radix-ui/react-primitive': 1.0.3(@types/react-dom@18.2.22)(@types/react@18.2.67)(react-dom@18.2.0)(react@18.2.0) + '@types/react': 18.2.67 + '@types/react-dom': 18.2.22 + react: 18.2.0 + react-dom: 18.2.0(react@18.2.0) + dev: false + + /@radix-ui/rect@1.0.1: + resolution: {integrity: sha512-fyrgCaedtvMg9NK3en0pnOYJdtfwxUcNolezkNPUsoX57X8oQk+NkqcvzHXD2uKNij6GXmWU9NDru2IWjrO4BQ==} + dependencies: + '@babel/runtime': 7.24.1 + dev: false + + /@rollup/rollup-android-arm-eabi@4.13.0: + resolution: {integrity: sha512-5ZYPOuaAqEH/W3gYsRkxQATBW3Ii1MfaT4EQstTnLKViLi2gLSQmlmtTpGucNP3sXEpOiI5tdGhjdE111ekyEg==} + cpu: [arm] + os: [android] + requiresBuild: true + dev: true + optional: true + + /@rollup/rollup-android-arm64@4.13.0: + resolution: {integrity: sha512-BSbaCmn8ZadK3UAQdlauSvtaJjhlDEjS5hEVVIN3A4bbl3X+otyf/kOJV08bYiRxfejP3DXFzO2jz3G20107+Q==} + cpu: [arm64] + os: [android] + requiresBuild: true + dev: true + optional: true + + /@rollup/rollup-darwin-arm64@4.13.0: + resolution: {integrity: sha512-Ovf2evVaP6sW5Ut0GHyUSOqA6tVKfrTHddtmxGQc1CTQa1Cw3/KMCDEEICZBbyppcwnhMwcDce9ZRxdWRpVd6g==} + cpu: [arm64] + os: [darwin] + requiresBuild: true + dev: true + optional: true + + /@rollup/rollup-darwin-x64@4.13.0: + resolution: {integrity: sha512-U+Jcxm89UTK592vZ2J9st9ajRv/hrwHdnvyuJpa5A2ngGSVHypigidkQJP+YiGL6JODiUeMzkqQzbCG3At81Gg==} + cpu: [x64] + os: [darwin] + requiresBuild: true + dev: true + optional: true + + /@rollup/rollup-linux-arm-gnueabihf@4.13.0: + resolution: {integrity: sha512-8wZidaUJUTIR5T4vRS22VkSMOVooG0F4N+JSwQXWSRiC6yfEsFMLTYRFHvby5mFFuExHa/yAp9juSphQQJAijQ==} + cpu: [arm] + os: [linux] + requiresBuild: true + dev: true + optional: true + + /@rollup/rollup-linux-arm64-gnu@4.13.0: + resolution: {integrity: sha512-Iu0Kno1vrD7zHQDxOmvweqLkAzjxEVqNhUIXBsZ8hu8Oak7/5VTPrxOEZXYC1nmrBVJp0ZcL2E7lSuuOVaE3+w==} + cpu: [arm64] + os: [linux] + requiresBuild: true + dev: true + optional: true + + /@rollup/rollup-linux-arm64-musl@4.13.0: + resolution: {integrity: sha512-C31QrW47llgVyrRjIwiOwsHFcaIwmkKi3PCroQY5aVq4H0A5v/vVVAtFsI1nfBngtoRpeREvZOkIhmRwUKkAdw==} + cpu: [arm64] + os: [linux] + requiresBuild: true + dev: true + optional: true + + /@rollup/rollup-linux-riscv64-gnu@4.13.0: + resolution: {integrity: sha512-Oq90dtMHvthFOPMl7pt7KmxzX7E71AfyIhh+cPhLY9oko97Zf2C9tt/XJD4RgxhaGeAraAXDtqxvKE1y/j35lA==} + cpu: [riscv64] + os: [linux] + requiresBuild: true + dev: true + optional: true + + /@rollup/rollup-linux-x64-gnu@4.13.0: + resolution: {integrity: sha512-yUD/8wMffnTKuiIsl6xU+4IA8UNhQ/f1sAnQebmE/lyQ8abjsVyDkyRkWop0kdMhKMprpNIhPmYlCxgHrPoXoA==} + cpu: [x64] + os: [linux] + requiresBuild: true + dev: true + optional: true + + /@rollup/rollup-linux-x64-musl@4.13.0: + resolution: {integrity: sha512-9RyNqoFNdF0vu/qqX63fKotBh43fJQeYC98hCaf89DYQpv+xu0D8QFSOS0biA7cGuqJFOc1bJ+m2rhhsKcw1hw==} + cpu: [x64] + os: [linux] + requiresBuild: true + dev: true + optional: true + + /@rollup/rollup-win32-arm64-msvc@4.13.0: + resolution: {integrity: sha512-46ue8ymtm/5PUU6pCvjlic0z82qWkxv54GTJZgHrQUuZnVH+tvvSP0LsozIDsCBFO4VjJ13N68wqrKSeScUKdA==} + cpu: [arm64] + os: [win32] + requiresBuild: true + dev: true + optional: true + + /@rollup/rollup-win32-ia32-msvc@4.13.0: + resolution: {integrity: sha512-P5/MqLdLSlqxbeuJ3YDeX37srC8mCflSyTrUsgbU1c/U9j6l2g2GiIdYaGD9QjdMQPMSgYm7hgg0551wHyIluw==} + cpu: [ia32] + os: [win32] + requiresBuild: true + dev: true + optional: true + + /@rollup/rollup-win32-x64-msvc@4.13.0: + resolution: {integrity: sha512-UKXUQNbO3DOhzLRwHSpa0HnhhCgNODvfoPWv2FCXme8N/ANFfhIPMGuOT+QuKd16+B5yxZ0HdpNlqPvTMS1qfw==} + cpu: [x64] + os: [win32] + requiresBuild: true + dev: true + optional: true + + /@sinclair/typebox@0.27.8: + resolution: {integrity: sha512-+Fj43pSMwJs4KRrH/938Uf+uAELIgVBmQzg/q1YG10djyfA3TnrU8N8XzqCh/okZdszqBQTZf96idMfE5lnwTA==} + dev: true + + /@sinonjs/commons@3.0.1: + resolution: {integrity: sha512-K3mCHKQ9sVh8o1C9cxkwxaOmXoAMlDxC1mYyHrjqOWEcBjYr76t96zL2zlj5dUGZ3HSw240X1qgH3Mjf1yJWpQ==} + dependencies: + type-detect: 4.0.8 + dev: true + + /@sinonjs/fake-timers@10.3.0: + resolution: {integrity: sha512-V4BG07kuYSUkTCSBHG8G8TNhM+F19jXFWnQtzj+we8DrkpSBCee9Z3Ms8yiGer/dlmhe35/Xdgyo3/0rQKg7YA==} + dependencies: + '@sinonjs/commons': 3.0.1 + dev: true + + /@stablelib/aead@1.0.1: + resolution: {integrity: sha512-q39ik6sxGHewqtO0nP4BuSe3db5G1fEJE8ukvngS2gLkBXyy6E7pLubhbYgnkDFv6V8cWaxcE4Xn0t6LWcJkyg==} + dev: false + + /@stablelib/binary@1.0.1: + resolution: {integrity: sha512-ClJWvmL6UBM/wjkvv/7m5VP3GMr9t0osr4yVgLZsLCOz4hGN9gIAFEqnJ0TsSMAN+n840nf2cHZnA5/KFqHC7Q==} + dependencies: + '@stablelib/int': 1.0.1 + dev: false + + /@stablelib/bytes@1.0.1: + resolution: {integrity: sha512-Kre4Y4kdwuqL8BR2E9hV/R5sOrUj6NanZaZis0V6lX5yzqC3hBuVSDXUIBqQv/sCpmuWRiHLwqiT1pqqjuBXoQ==} + dev: false + + /@stablelib/chacha20poly1305@1.0.1: + resolution: {integrity: sha512-MmViqnqHd1ymwjOQfghRKw2R/jMIGT3wySN7cthjXCBdO+qErNPUBnRzqNpnvIwg7JBCg3LdeCZZO4de/yEhVA==} + dependencies: + '@stablelib/aead': 1.0.1 + '@stablelib/binary': 1.0.1 + '@stablelib/chacha': 1.0.1 + '@stablelib/constant-time': 1.0.1 + '@stablelib/poly1305': 1.0.1 + '@stablelib/wipe': 1.0.1 + dev: false + + /@stablelib/chacha@1.0.1: + resolution: {integrity: sha512-Pmlrswzr0pBzDofdFuVe1q7KdsHKhhU24e8gkEwnTGOmlC7PADzLVxGdn2PoNVBBabdg0l/IfLKg6sHAbTQugg==} + dependencies: + '@stablelib/binary': 1.0.1 + '@stablelib/wipe': 1.0.1 + dev: false + + /@stablelib/constant-time@1.0.1: + resolution: {integrity: sha512-tNOs3uD0vSJcK6z1fvef4Y+buN7DXhzHDPqRLSXUel1UfqMB1PWNsnnAezrKfEwTLpN0cGH2p9NNjs6IqeD0eg==} + dev: false + + /@stablelib/ed25519@1.0.3: + resolution: {integrity: sha512-puIMWaX9QlRsbhxfDc5i+mNPMY+0TmQEskunY1rZEBPi1acBCVQAhnsk/1Hk50DGPtVsZtAWQg4NHGlVaO9Hqg==} + dependencies: + '@stablelib/random': 1.0.2 + '@stablelib/sha512': 1.0.1 + '@stablelib/wipe': 1.0.1 + dev: false + + /@stablelib/hash@1.0.1: + resolution: {integrity: sha512-eTPJc/stDkdtOcrNMZ6mcMK1e6yBbqRBaNW55XA1jU8w/7QdnCF0CmMmOD1m7VSkBR44PWrMHU2l6r8YEQHMgg==} + dev: false + + /@stablelib/hkdf@1.0.1: + resolution: {integrity: sha512-SBEHYE16ZXlHuaW5RcGk533YlBj4grMeg5TooN80W3NpcHRtLZLLXvKyX0qcRFxf+BGDobJLnwkvgEwHIDBR6g==} + dependencies: + '@stablelib/hash': 1.0.1 + '@stablelib/hmac': 1.0.1 + '@stablelib/wipe': 1.0.1 + dev: false + + /@stablelib/hmac@1.0.1: + resolution: {integrity: sha512-V2APD9NSnhVpV/QMYgCVMIYKiYG6LSqw1S65wxVoirhU/51ACio6D4yDVSwMzuTJXWZoVHbDdINioBwKy5kVmA==} + dependencies: + '@stablelib/constant-time': 1.0.1 + '@stablelib/hash': 1.0.1 + '@stablelib/wipe': 1.0.1 + dev: false + + /@stablelib/int@1.0.1: + resolution: {integrity: sha512-byr69X/sDtDiIjIV6m4roLVWnNNlRGzsvxw+agj8CIEazqWGOQp2dTYgQhtyVXV9wpO6WyXRQUzLV/JRNumT2w==} + dev: false + + /@stablelib/keyagreement@1.0.1: + resolution: {integrity: sha512-VKL6xBwgJnI6l1jKrBAfn265cspaWBPAPEc62VBQrWHLqVgNRE09gQ/AnOEyKUWrrqfD+xSQ3u42gJjLDdMDQg==} + dependencies: + '@stablelib/bytes': 1.0.1 + dev: false + + /@stablelib/poly1305@1.0.1: + resolution: {integrity: sha512-1HlG3oTSuQDOhSnLwJRKeTRSAdFNVB/1djy2ZbS35rBSJ/PFqx9cf9qatinWghC2UbfOYD8AcrtbUQl8WoxabA==} + dependencies: + '@stablelib/constant-time': 1.0.1 + '@stablelib/wipe': 1.0.1 + dev: false + + /@stablelib/random@1.0.2: + resolution: {integrity: sha512-rIsE83Xpb7clHPVRlBj8qNe5L8ISQOzjghYQm/dZ7VaM2KHYwMW5adjQjrzTZCchFnNCNhkwtnOBa9HTMJCI8w==} + dependencies: + '@stablelib/binary': 1.0.1 + '@stablelib/wipe': 1.0.1 + dev: false + + /@stablelib/sha256@1.0.1: + resolution: {integrity: sha512-GIIH3e6KH+91FqGV42Kcj71Uefd/QEe7Dy42sBTeqppXV95ggCcxLTk39bEr+lZfJmp+ghsR07J++ORkRELsBQ==} + dependencies: + '@stablelib/binary': 1.0.1 + '@stablelib/hash': 1.0.1 + '@stablelib/wipe': 1.0.1 + dev: false + + /@stablelib/sha512@1.0.1: + resolution: {integrity: sha512-13gl/iawHV9zvDKciLo1fQ8Bgn2Pvf7OV6amaRVKiq3pjQ3UmEpXxWiAfV8tYjUpeZroBxtyrwtdooQT/i3hzw==} + dependencies: + '@stablelib/binary': 1.0.1 + '@stablelib/hash': 1.0.1 + '@stablelib/wipe': 1.0.1 + dev: false + + /@stablelib/wipe@1.0.1: + resolution: {integrity: sha512-WfqfX/eXGiAd3RJe4VU2snh/ZPwtSjLG4ynQ/vYzvghTh7dHFcI1wl+nrkWG6lGhukOxOsUHfv8dUXr58D0ayg==} + dev: false + + /@stablelib/x25519@1.0.3: + resolution: {integrity: sha512-KnTbKmUhPhHavzobclVJQG5kuivH+qDLpe84iRqX3CLrKp881cF160JvXJ+hjn1aMyCwYOKeIZefIH/P5cJoRw==} + dependencies: + '@stablelib/keyagreement': 1.0.1 + '@stablelib/random': 1.0.2 + '@stablelib/wipe': 1.0.1 + dev: false + + /@swc/helpers@0.5.2: + resolution: {integrity: sha512-E4KcWTpoLHqwPHLxidpOqQbcrZVgi0rsmmZXUle1jXmJfuIf/UWpczUJ7MZZ5tlxytgJXyp0w4PGkkeLiuIdZw==} + dependencies: + tslib: 2.6.2 + dev: false + + /@tanstack/history@1.15.13: + resolution: {integrity: sha512-ToaeMtK5S4YaxCywAlYexc7KPFN0esjyTZ4vXzJhXEWAkro9iHgh7m/4ozPJb7oTo65WkHWX0W9GjcZbInSD8w==} + engines: {node: '>=12'} + dev: false + + /@tanstack/query-core@5.28.4: + resolution: {integrity: sha512-uQZqOFqLWUvXNIQZ63XdKzg22NtHzgCBUfDmjDHi3BoF+nUYeBNvMi/xFPtFrMhqRzG2Ir4mYaGsWZzmiEjXpA==} + dev: false + + /@tanstack/query-devtools@5.28.3: + resolution: {integrity: sha512-Kxch05PVnxLUAyRiz2gXYQhXATHfXbQQwvz858YPjYYQyi7yk8SyS9Z5hyw90bRb0pd3rjelXyGFCsNMWvEghw==} + dev: false + + /@tanstack/react-query-devtools@5.28.4(@tanstack/react-query@5.28.4)(react@18.2.0): + resolution: {integrity: sha512-oS+3INjCIX4Nkh0IAV6LH2mgLqJjkcd/DDxp8dwdWCGloLrz6IBj+bOuuI2wD0zb8r7l45wIAYIhl4Z6XyTupQ==} + peerDependencies: + '@tanstack/react-query': ^5.28.4 + react: ^18.0.0 + dependencies: + '@tanstack/query-devtools': 5.28.3 + '@tanstack/react-query': 5.28.4(react@18.2.0) + react: 18.2.0 + dev: false + + /@tanstack/react-query@5.28.4(react@18.2.0): + resolution: {integrity: sha512-BErcoB/QQG6YwLSUKnaGxF+lSc270RH2w3kMBpG0i4YzDCsFs2pdxPX1WVknQvFk9bNgukMb158hc2Zb4SdwSA==} + peerDependencies: + react: ^18.0.0 + dependencies: + '@tanstack/query-core': 5.28.4 + react: 18.2.0 + dev: false + + /@tanstack/react-router@1.20.4(react-dom@18.2.0)(react@18.2.0): + resolution: {integrity: sha512-sZ50qlSheTTa69jZMSzqrf1hvpbXi37jeCHLuj1+5WwJYmZaJynk9U7bB7vXTm4bkpQKC/L4eTx/DdIQ9yfIgQ==} + engines: {node: '>=12'} + peerDependencies: + react: '>=16' + react-dom: '>=16' + dependencies: + '@tanstack/history': 1.15.13 + '@tanstack/react-store': 0.2.1(react-dom@18.2.0)(react@18.2.0) + react: 18.2.0 + react-dom: 18.2.0(react@18.2.0) + tiny-invariant: 1.3.3 + tiny-warning: 1.0.3 + dev: false + + /@tanstack/react-router@1.22.0(react-dom@18.2.0)(react@18.2.0): + resolution: {integrity: sha512-D7OZHs3iicTGwg8f0J/qCwcKOPN9UWLRqKvaz3lISu28wkMLQhX+wspI+9/xYZg+tMlbUzUzxVhLD8yHI9rfNg==} + engines: {node: '>=12'} + peerDependencies: + react: '>=16' + react-dom: '>=16' + dependencies: + '@tanstack/history': 1.15.13 + '@tanstack/react-store': 0.2.1(react-dom@18.2.0)(react@18.2.0) + react: 18.2.0 + react-dom: 18.2.0(react@18.2.0) + tiny-invariant: 1.3.3 + tiny-warning: 1.0.3 + dev: false + + /@tanstack/react-store@0.2.1(react-dom@18.2.0)(react@18.2.0): + resolution: {integrity: sha512-tEbMCQjbeVw9KOP/202LfqZMSNAVi6zYkkp1kBom8nFuMx/965Hzes3+6G6b/comCwVxoJU8Gg9IrcF8yRPthw==} + peerDependencies: + react: '>=16' + react-dom: '>=16' + dependencies: + '@tanstack/store': 0.1.3 + react: 18.2.0 + react-dom: 18.2.0(react@18.2.0) + use-sync-external-store: 1.2.0(react@18.2.0) + dev: false + + /@tanstack/react-store@0.3.1(react-dom@18.2.0)(react@18.2.0): + resolution: {integrity: sha512-PfV271d345It6FdcX4c9gd+llKGddtvau8iJnybTAWmYVyDeFWfIIkiAJ5iNITJmI02AzqgtcV3QLNBBlpBUjA==} + peerDependencies: + react: ^17.0.0 || ^18.0.0 + react-dom: ^17.0.0 || ^18.0.0 + dependencies: + '@tanstack/store': 0.3.1 + react: 18.2.0 + react-dom: 18.2.0(react@18.2.0) + use-sync-external-store: 1.2.0(react@18.2.0) + dev: false + + /@tanstack/react-table@8.14.0(react-dom@18.2.0)(react@18.2.0): + resolution: {integrity: sha512-l9iwO99oz/azy5RT5VkVRsHHuy7o//fiXgLxzl3fad8qf7Bj+9ihsfmE6Q+BNjH4wHbxZkahwxtb3ngGq9FQxA==} + engines: {node: '>=12'} + peerDependencies: + react: '>=16' + react-dom: '>=16' + dependencies: + '@tanstack/table-core': 8.14.0 + react: 18.2.0 + react-dom: 18.2.0(react@18.2.0) + dev: false + + /@tanstack/router-devtools@1.20.4(csstype@3.1.3)(react-dom@18.2.0)(react@18.2.0): + resolution: {integrity: sha512-K2GFvAnr/4pM0s37Wds2/MP6bM8Fr1YY2cK2xMZdxgXhjIdKGNfi1fbddIhIriBUaeFHqr2DuqM8+vTtbJt/dw==} + engines: {node: '>=12'} + peerDependencies: + react: '>=16' + react-dom: '>=16' + dependencies: + '@tanstack/react-router': 1.20.4(react-dom@18.2.0)(react@18.2.0) + clsx: 2.1.0 + date-fns: 2.30.0 + goober: 2.1.14(csstype@3.1.3) + react: 18.2.0 + react-dom: 18.2.0(react@18.2.0) + transitivePeerDependencies: + - csstype + dev: false + + /@tanstack/router-generator@1.20.0: + resolution: {integrity: sha512-YkxVMi6q3K3V99Xo13dbP4fQDHxGUZi8Z5B7t4XZvwouAj7RDF8Tm8UcJVix8VLWaH4pt1idSXy185GWLTAiTw==} + engines: {node: '>=12'} + dependencies: + prettier: 3.2.5 + zod: 3.22.4 + dev: true + + /@tanstack/router-vite-plugin@1.20.2: + resolution: {integrity: sha512-lZ6fBwXszmzS0n9fbQUDdi0u4f6ZimDXIQhMjZEzqn9yB/IPloqN0ja0Bac78/5C7gJhsZ8YcgH8qRqqXYWGeg==} + engines: {node: '>=12'} + dependencies: + '@tanstack/router-generator': 1.20.0 + dev: true + + /@tanstack/store@0.1.3: + resolution: {integrity: sha512-GnolmC8Fr4mvsHE1fGQmR3Nm0eBO3KnZjDU0a+P3TeQNM/dDscFGxtA7p31NplQNW3KwBw4t1RVFmz0VeKLxcw==} + dev: false + + /@tanstack/store@0.3.1: + resolution: {integrity: sha512-A49KN8SpLMWaNmZGPa9K982RQ81W+m7W6iStcQVeKeVS70JZRqkF0fDwKByREPq6qz9/kS0aQFOPQ0W6wIeU5g==} + dev: false + + /@tanstack/table-core@8.14.0: + resolution: {integrity: sha512-wDhpKJahGHWhmRt4RxtV3pES63CoeadljGWS/xeS9OJr1HBl2NB+OO44ht3sxDH5j5TRDAbQzC0NvSlsUfn7lQ==} + engines: {node: '>=12'} + dev: false + + /@tsconfig/node10@1.0.9: + resolution: {integrity: sha512-jNsYVVxU8v5g43Erja32laIDHXeoNvFEpX33OK4d6hljo3jDhCBDhx5dhCCTMWUojscpAagGiRkBKxpdl9fxqA==} + + /@tsconfig/node12@1.0.11: + resolution: {integrity: sha512-cqefuRsh12pWyGsIoBKJA9luFu3mRxCA+ORZvA4ktLSzIuCUtWVxGIuXigEwO5/ywWFMZ2QEGKWvkZG1zDMTag==} + + /@tsconfig/node14@1.0.3: + resolution: {integrity: sha512-ysT8mhdixWK6Hw3i1V2AeRqZ5WfXg1G43mqoYlM2nc6388Fq5jcXyr5mRsqViLx/GJYdoL0bfXD8nmF+Zn/Iow==} + + /@tsconfig/node16@1.0.4: + resolution: {integrity: sha512-vxhUy4J8lyeyinH7Azl1pdd43GJhZH/tP2weN8TntQblOY+A0XbT8DJk1/oCPuOOyg/Ja757rG0CgHcWC8OfMA==} + + /@txnlab/use-wallet-react@3.0.0-beta.2(@blockshake/defly-connect@1.1.6)(@perawallet/connect@1.3.4)(algosdk@2.7.0)(react-dom@18.2.0)(react@18.2.0): + resolution: {integrity: sha512-Kw6z9nodXfc2dB92Ge6gL1GXhqnxZi/NQWJNuq9d2qTVKLvcXOMXsJmGxPosFkERtXyBMwniMikZPGVK+KWBqw==} + peerDependencies: + '@blockshake/defly-connect': ^1.1.6 + '@perawallet/connect': ^1.3.3 + '@walletconnect/modal': ^2.6.2 + '@walletconnect/sign-client': ^2.10.2 + algosdk: ^2.6.0 + lute-connect: ^1.1.3 + react: ^17.0.0 || ^18.0.0 + react-dom: ^17.0.0 || ^18.0.0 + peerDependenciesMeta: + '@blockshake/defly-connect': + optional: true + '@perawallet/connect': + optional: true + '@walletconnect/modal': + optional: true + '@walletconnect/sign-client': + optional: true + lute-connect: + optional: true + dependencies: + '@blockshake/defly-connect': 1.1.6(algosdk@2.7.0) + '@perawallet/connect': 1.3.4(algosdk@2.7.0) + '@tanstack/react-store': 0.3.1(react-dom@18.2.0)(react@18.2.0) + '@txnlab/use-wallet': 3.0.0-beta.2(@blockshake/defly-connect@1.1.6)(@perawallet/connect@1.3.4) + algosdk: 2.7.0 + react: 18.2.0 + react-dom: 18.2.0(react@18.2.0) + transitivePeerDependencies: + - '@azure/app-configuration' + - '@azure/cosmos' + - '@azure/data-tables' + - '@azure/identity' + - '@azure/keyvault-secrets' + - '@azure/storage-blob' + - '@capacitor/preferences' + - '@netlify/blobs' + - '@planetscale/database' + - '@react-native-async-storage/async-storage' + - '@upstash/redis' + - '@vercel/kv' + - ioredis + - uWebSockets.js + dev: false + + /@txnlab/use-wallet@3.0.0-beta.2(@blockshake/defly-connect@1.1.6)(@perawallet/connect@1.3.4): + resolution: {integrity: sha512-vYGBZXHWWE4oz1YWz1dOEpog/U9nvKIEnPfrVZVEeOJT4RhuJpY70axHpFyxCP9Y1ngxuVYqpy7JK3wM1HMFmg==} + peerDependencies: + '@blockshake/defly-connect': ^1.1.6 + '@perawallet/connect': ^1.3.3 + '@walletconnect/modal': ^2.6.2 + '@walletconnect/sign-client': ^2.10.2 + lute-connect: ^1.1.3 + peerDependenciesMeta: + '@blockshake/defly-connect': + optional: true + '@perawallet/connect': + optional: true + '@walletconnect/modal': + optional: true + '@walletconnect/sign-client': + optional: true + lute-connect: + optional: true + dependencies: + '@blockshake/defly-connect': 1.1.6(algosdk@2.7.0) + '@perawallet/connect': 1.3.4(algosdk@2.7.0) + '@tanstack/store': 0.3.1 + '@walletconnect/utils': 2.11.3 + algosdk: 2.7.0 + buffer: 6.0.3 + transitivePeerDependencies: + - '@azure/app-configuration' + - '@azure/cosmos' + - '@azure/data-tables' + - '@azure/identity' + - '@azure/keyvault-secrets' + - '@azure/storage-blob' + - '@capacitor/preferences' + - '@netlify/blobs' + - '@planetscale/database' + - '@react-native-async-storage/async-storage' + - '@upstash/redis' + - '@vercel/kv' + - ioredis + - uWebSockets.js + dev: false + + /@types/babel__core@7.20.5: + resolution: {integrity: sha512-qoQprZvz5wQFJwMDqeseRXWv3rqMvhgpbXFfVyWhbx9X47POIA6i/+dXefEmZKoAgOaTdaIgNSMqMIU61yRyzA==} + dependencies: + '@babel/parser': 7.24.1 + '@babel/types': 7.24.0 + '@types/babel__generator': 7.6.8 + '@types/babel__template': 7.4.4 + '@types/babel__traverse': 7.20.5 + dev: true + + /@types/babel__generator@7.6.8: + resolution: {integrity: sha512-ASsj+tpEDsEiFr1arWrlN6V3mdfjRMZt6LtK/Vp/kreFLnr5QH5+DhvD5nINYZXzwJvXeGq+05iUXcAzVrqWtw==} + dependencies: + '@babel/types': 7.24.0 + dev: true + + /@types/babel__template@7.4.4: + resolution: {integrity: sha512-h/NUaSyG5EyxBIp8YRxo4RMe2/qQgvyowRwVMzhYhBCONbW8PUsg4lkFMrhgZhUe5z3L3MiLDuvyJ/CaPa2A8A==} + dependencies: + '@babel/parser': 7.24.1 + '@babel/types': 7.24.0 + dev: true + + /@types/babel__traverse@7.20.5: + resolution: {integrity: sha512-WXCyOcRtH37HAUkpXhUduaxdm82b4GSlyTqajXviN4EfiuPgNYR109xMCKvpl6zPIpua0DGlMEDCq+g8EdoheQ==} + dependencies: + '@babel/types': 7.24.0 + dev: true + + /@types/big.js@6.2.2: + resolution: {integrity: sha512-e2cOW9YlVzFY2iScnGBBkplKsrn2CsObHQ2Hiw4V1sSyiGbgWL8IyqE3zFi1Pt5o1pdAtYkDAIsF3KKUPjdzaA==} + dev: true + + /@types/d3-array@3.2.1: + resolution: {integrity: sha512-Y2Jn2idRrLzUfAKV2LyRImR+y4oa2AntrgID95SHJxuMUrkNXmanDSed71sRNZysveJVt1hLLemQZIady0FpEg==} + dev: false + + /@types/d3-color@3.1.3: + resolution: {integrity: sha512-iO90scth9WAbmgv7ogoq57O9YpKmFBbmoEoCHDB2xMBY0+/KVrqAaCDyCE16dUspeOvIxFFRI+0sEtqDqy2b4A==} + dev: false + + /@types/d3-ease@3.0.2: + resolution: {integrity: sha512-NcV1JjO5oDzoK26oMzbILE6HW7uVXOHLQvHshBUW4UMdZGfiY6v5BeQwh9a9tCzv+CeefZQHJt5SRgK154RtiA==} + dev: false + + /@types/d3-interpolate@3.0.4: + resolution: {integrity: sha512-mgLPETlrpVV1YRJIglr4Ez47g7Yxjl1lj7YKsiMCb27VJH9W8NVM6Bb9d8kkpG/uAQS5AmbA48q2IAolKKo1MA==} + dependencies: + '@types/d3-color': 3.1.3 + dev: false + + /@types/d3-path@3.1.0: + resolution: {integrity: sha512-P2dlU/q51fkOc/Gfl3Ul9kicV7l+ra934qBFXCFhrZMOL6du1TM0pm1ThYvENukyOn5h9v+yMJ9Fn5JK4QozrQ==} + dev: false + + /@types/d3-scale@4.0.8: + resolution: {integrity: sha512-gkK1VVTr5iNiYJ7vWDI+yUFFlszhNMtVeneJ6lUTKPjprsvLLI9/tgEGiXJOnlINJA8FyA88gfnQsHbybVZrYQ==} + dependencies: + '@types/d3-time': 3.0.3 + dev: false + + /@types/d3-shape@3.1.6: + resolution: {integrity: sha512-5KKk5aKGu2I+O6SONMYSNflgiP0WfZIQvVUMan50wHsLG1G94JlxEVnCpQARfTtzytuY0p/9PXXZb3I7giofIA==} + dependencies: + '@types/d3-path': 3.1.0 + dev: false + + /@types/d3-time@3.0.3: + resolution: {integrity: sha512-2p6olUZ4w3s+07q3Tm2dbiMZy5pCDfYwtLXXHUnVzXgQlZ/OyPtUz6OL382BkOuGlLXqfT+wqv8Fw2v8/0geBw==} + dev: false + + /@types/d3-timer@3.0.2: + resolution: {integrity: sha512-Ps3T8E8dZDam6fUyNiMkekK3XUsaUEik+idO9/YjPtfj2qruF8tFBXS7XhtE4iIXBLxhmLjP3SXpLhVf21I9Lw==} + dev: false + + /@types/estree@1.0.5: + resolution: {integrity: sha512-/kYRxGDLWzHOB7q+wtSUQlFrtcdUccpfy+X+9iMBpHK8QLLhx2wIPYuS5DYtR9Wa/YlZAbIovy7qVdB1Aq6Lyw==} + dev: true + + /@types/graceful-fs@4.1.9: + resolution: {integrity: sha512-olP3sd1qOEe5dXTSaFvQG+02VdRXcdytWLAZsAq1PecU8uqQAhkrnbli7DagjtXKW/Bl7YJbUsa8MPcuc8LHEQ==} + dependencies: + '@types/node': 18.19.28 + dev: true + + /@types/istanbul-lib-coverage@2.0.6: + resolution: {integrity: sha512-2QF/t/auWm0lsy8XtKVPG19v3sSOQlJe/YHZgfjb/KBBHOGSV+J2q/S671rcq9uTBrLAXmZpqJiaQbMT+zNU1w==} + dev: true + + /@types/istanbul-lib-report@3.0.3: + resolution: {integrity: sha512-NQn7AHQnk/RSLOxrBbGyJM/aVQ+pjj5HCgasFxc0K/KhoATfQ/47AyUl15I2yBUpihjmas+a+VJBOqecrFH+uA==} + dependencies: + '@types/istanbul-lib-coverage': 2.0.6 + dev: true + + /@types/istanbul-reports@3.0.4: + resolution: {integrity: sha512-pk2B1NWalF9toCRu6gjBzR69syFjP4Od8WRAX+0mmf9lAjCRicLOWc+ZrxZHx/0XRjotgkF9t6iaMJ+aXcOdZQ==} + dependencies: + '@types/istanbul-lib-report': 3.0.3 + dev: true + + /@types/jest@29.5.2: + resolution: {integrity: sha512-mSoZVJF5YzGVCk+FsDxzDuH7s+SCkzrgKZzf0Z0T2WudhBUPoF6ktoTPC4R0ZoCPCV5xUvuU6ias5NvxcBcMMg==} + dependencies: + expect: 29.7.0 + pretty-format: 29.7.0 + dev: true + + /@types/json-schema@7.0.15: + resolution: {integrity: sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==} + dev: true + + /@types/node@18.19.26: + resolution: {integrity: sha512-+wiMJsIwLOYCvUqSdKTrfkS8mpTp+MPINe6+Np4TAGFWWRWiBQ5kSq9nZGCSPkzx9mvT+uEukzpX4MOSCydcvw==} + dependencies: + undici-types: 5.26.5 + + /@types/node@18.19.28: + resolution: {integrity: sha512-J5cOGD9n4x3YGgVuaND6khm5x07MMdAKkRyXnjVR6KFhLMNh2yONGiP7Z+4+tBOt5mK+GvDTiacTOVGGpqiecw==} + dependencies: + undici-types: 5.26.5 + dev: true + + /@types/prop-types@15.7.11: + resolution: {integrity: sha512-ga8y9v9uyeiLdpKddhxYQkxNDrfvuPrlFb0N1qnZZByvcElJaXthF1UhvCh9TLWJBEHeNtdnbysW7Y6Uq8CVng==} + + /@types/react-dom@18.2.22: + resolution: {integrity: sha512-fHkBXPeNtfvri6gdsMYyW+dW7RXFo6Ad09nLFK0VQWR7yGLai/Cyvyj696gbwYvBnhGtevUG9cET0pmUbMtoPQ==} + dependencies: + '@types/react': 18.2.67 + + /@types/react@18.2.67: + resolution: {integrity: sha512-vkIE2vTIMHQ/xL0rgmuoECBCkZFZeHr49HeWSc24AptMbNRo7pwSBvj73rlJJs9fGKj0koS+V7kQB1jHS0uCgw==} + dependencies: + '@types/prop-types': 15.7.11 + '@types/scheduler': 0.16.8 + csstype: 3.1.3 + + /@types/scheduler@0.16.8: + resolution: {integrity: sha512-WZLiwShhwLRmeV6zH+GkbOFT6Z6VklCItrDioxUnv+u4Ll+8vKeFySoFyK/0ctcRpOmwAicELfmys1sDc/Rw+A==} + + /@types/semver@7.5.8: + resolution: {integrity: sha512-I8EUhyrgfLrcTkzV3TSsGyl1tSuPrEDzr0yd5m90UgNxQkyDXULk3b6MlQqTCpZpNtWe1K0hzclnZkTcLBe2UQ==} + dev: true + + /@types/stack-utils@2.0.3: + resolution: {integrity: sha512-9aEbYZ3TbYMznPdcdr3SmIrLXwC/AKZXQeCf9Pgao5CKb8CyHuEX5jzWPTkvregvhRJHcpRO6BFoGW9ycaOkYw==} + dev: true + + /@types/trusted-types@2.0.7: + resolution: {integrity: sha512-ScaPdn1dQczgbl0QFTeTOmVHFULt394XJgOQNoyVhZ6r2vLnMLJfBPd53SB52T/3G36VI1/g2MZaX0cwDuXsfw==} + dev: false + + /@types/yargs-parser@21.0.3: + resolution: {integrity: sha512-I4q9QU9MQv4oEOz4tAHJtNz1cwuLxn2F3xcc2iV5WdqLPpUnj30aUuxt1mAxYTG+oe8CZMV/+6rU4S4gRDzqtQ==} + dev: true + + /@types/yargs@17.0.32: + resolution: {integrity: sha512-xQ67Yc/laOG5uMfX/093MRlGGCIBzZMarVa+gfNKJxWAIgykYpVGkBdbqEzGDDfCrVUj6Hiff4mTZ5BA6TmAog==} + dependencies: + '@types/yargs-parser': 21.0.3 + dev: true + + /@typescript-eslint/eslint-plugin@6.21.0(@typescript-eslint/parser@6.21.0)(eslint@8.57.0)(typescript@5.4.2): + resolution: {integrity: sha512-oy9+hTPCUFpngkEZUSzbf9MxI65wbKFoQYsgPdILTfbUldp5ovUuphZVe4i30emU9M/kP+T64Di0mxl7dSw3MA==} + engines: {node: ^16.0.0 || >=18.0.0} + peerDependencies: + '@typescript-eslint/parser': ^6.0.0 || ^6.0.0-alpha + eslint: ^7.0.0 || ^8.0.0 + typescript: '*' + peerDependenciesMeta: + typescript: + optional: true + dependencies: + '@eslint-community/regexpp': 4.10.0 + '@typescript-eslint/parser': 6.21.0(eslint@8.57.0)(typescript@5.4.2) + '@typescript-eslint/scope-manager': 6.21.0 + '@typescript-eslint/type-utils': 6.21.0(eslint@8.57.0)(typescript@5.4.2) + '@typescript-eslint/utils': 6.21.0(eslint@8.57.0)(typescript@5.4.2) + '@typescript-eslint/visitor-keys': 6.21.0 + debug: 4.3.4 + eslint: 8.57.0 + graphemer: 1.4.0 + ignore: 5.3.1 + natural-compare: 1.4.0 + semver: 7.6.0 + ts-api-utils: 1.3.0(typescript@5.4.2) + typescript: 5.4.2 + transitivePeerDependencies: + - supports-color + dev: true + + /@typescript-eslint/parser@6.21.0(eslint@8.57.0)(typescript@5.4.2): + resolution: {integrity: sha512-tbsV1jPne5CkFQCgPBcDOt30ItF7aJoZL997JSF7MhGQqOeT3svWRYxiqlfA5RUdlHN6Fi+EI9bxqbdyAUZjYQ==} + engines: {node: ^16.0.0 || >=18.0.0} + peerDependencies: + eslint: ^7.0.0 || ^8.0.0 + typescript: '*' + peerDependenciesMeta: + typescript: + optional: true + dependencies: + '@typescript-eslint/scope-manager': 6.21.0 + '@typescript-eslint/types': 6.21.0 + '@typescript-eslint/typescript-estree': 6.21.0(typescript@5.4.2) + '@typescript-eslint/visitor-keys': 6.21.0 + debug: 4.3.4 + eslint: 8.57.0 + typescript: 5.4.2 + transitivePeerDependencies: + - supports-color + dev: true + + /@typescript-eslint/scope-manager@6.21.0: + resolution: {integrity: sha512-OwLUIWZJry80O99zvqXVEioyniJMa+d2GrqpUTqi5/v5D5rOrppJVBPa0yKCblcigC0/aYAzxxqQ1B+DS2RYsg==} + engines: {node: ^16.0.0 || >=18.0.0} + dependencies: + '@typescript-eslint/types': 6.21.0 + '@typescript-eslint/visitor-keys': 6.21.0 + dev: true + + /@typescript-eslint/type-utils@6.21.0(eslint@8.57.0)(typescript@5.4.2): + resolution: {integrity: sha512-rZQI7wHfao8qMX3Rd3xqeYSMCL3SoiSQLBATSiVKARdFGCYSRvmViieZjqc58jKgs8Y8i9YvVVhRbHSTA4VBag==} + engines: {node: ^16.0.0 || >=18.0.0} + peerDependencies: + eslint: ^7.0.0 || ^8.0.0 + typescript: '*' + peerDependenciesMeta: + typescript: + optional: true + dependencies: + '@typescript-eslint/typescript-estree': 6.21.0(typescript@5.4.2) + '@typescript-eslint/utils': 6.21.0(eslint@8.57.0)(typescript@5.4.2) + debug: 4.3.4 + eslint: 8.57.0 + ts-api-utils: 1.3.0(typescript@5.4.2) + typescript: 5.4.2 + transitivePeerDependencies: + - supports-color + dev: true + + /@typescript-eslint/types@6.21.0: + resolution: {integrity: sha512-1kFmZ1rOm5epu9NZEZm1kckCDGj5UJEf7P1kliH4LKu/RkwpsfqqGmY2OOcUs18lSlQBKLDYBOGxRVtrMN5lpg==} + engines: {node: ^16.0.0 || >=18.0.0} + dev: true + + /@typescript-eslint/typescript-estree@6.21.0(typescript@5.4.2): + resolution: {integrity: sha512-6npJTkZcO+y2/kr+z0hc4HwNfrrP4kNYh57ek7yCNlrBjWQ1Y0OS7jiZTkgumrvkX5HkEKXFZkkdFNkaW2wmUQ==} + engines: {node: ^16.0.0 || >=18.0.0} + peerDependencies: + typescript: '*' + peerDependenciesMeta: + typescript: + optional: true + dependencies: + '@typescript-eslint/types': 6.21.0 + '@typescript-eslint/visitor-keys': 6.21.0 + debug: 4.3.4 + globby: 11.1.0 + is-glob: 4.0.3 + minimatch: 9.0.3 + semver: 7.6.0 + ts-api-utils: 1.3.0(typescript@5.4.2) + typescript: 5.4.2 + transitivePeerDependencies: + - supports-color + dev: true + + /@typescript-eslint/utils@6.21.0(eslint@8.57.0)(typescript@5.4.2): + resolution: {integrity: sha512-NfWVaC8HP9T8cbKQxHcsJBY5YE1O33+jpMwN45qzWWaPDZgLIbo12toGMWnmhvCpd3sIxkpDw3Wv1B3dYrbDQQ==} + engines: {node: ^16.0.0 || >=18.0.0} + peerDependencies: + eslint: ^7.0.0 || ^8.0.0 + dependencies: + '@eslint-community/eslint-utils': 4.4.0(eslint@8.57.0) + '@types/json-schema': 7.0.15 + '@types/semver': 7.5.8 + '@typescript-eslint/scope-manager': 6.21.0 + '@typescript-eslint/types': 6.21.0 + '@typescript-eslint/typescript-estree': 6.21.0(typescript@5.4.2) + eslint: 8.57.0 + semver: 7.6.0 + transitivePeerDependencies: + - supports-color + - typescript + dev: true + + /@typescript-eslint/visitor-keys@6.21.0: + resolution: {integrity: sha512-JJtkDduxLi9bivAB+cYOVMtbkqdPOhZ+ZI5LC47MIRrDV4Yn2o+ZnW10Nkmr28xRpSpdJ6Sm42Hjf2+REYXm0A==} + engines: {node: ^16.0.0 || >=18.0.0} + dependencies: + '@typescript-eslint/types': 6.21.0 + eslint-visitor-keys: 3.4.3 + dev: true + + /@ungap/structured-clone@1.2.0: + resolution: {integrity: sha512-zuVdFrMJiuCDQUMCzQaD6KL28MjnqqN8XnAqiEq9PNm/hCPTSGfrXCOfwj1ow4LFb/tNymJPwsNbVePc1xFqrQ==} + dev: true + + /@vitejs/plugin-react@4.2.1(vite@5.1.6): + resolution: {integrity: sha512-oojO9IDc4nCUUi8qIR11KoQm0XFFLIwsRBwHRR4d/88IWghn1y6ckz/bJ8GHDCsYEJee8mDzqtJxh15/cisJNQ==} + engines: {node: ^14.18.0 || >=16.0.0} + peerDependencies: + vite: ^4.2.0 || ^5.0.0 + dependencies: + '@babel/core': 7.24.1 + '@babel/plugin-transform-react-jsx-self': 7.24.1(@babel/core@7.24.1) + '@babel/plugin-transform-react-jsx-source': 7.24.1(@babel/core@7.24.1) + '@types/babel__core': 7.20.5 + react-refresh: 0.14.0 + vite: 5.1.6(@types/node@18.19.26) + transitivePeerDependencies: + - supports-color + dev: true + + /@walletconnect/browser-utils@1.8.0: + resolution: {integrity: sha512-Wcqqx+wjxIo9fv6eBUFHPsW1y/bGWWRboni5dfD8PtOmrihrEpOCmvRJe4rfl7xgJW8Ea9UqKEaq0bIRLHlK4A==} + dependencies: + '@walletconnect/safe-json': 1.0.0 + '@walletconnect/types': 1.8.0 + '@walletconnect/window-getters': 1.0.0 + '@walletconnect/window-metadata': 1.0.0 + detect-browser: 5.2.0 + dev: false + + /@walletconnect/client@1.8.0: + resolution: {integrity: sha512-svyBQ14NHx6Cs2j4TpkQaBI/2AF4+LXz64FojTjMtV4VMMhl81jSO1vNeg+yYhQzvjcGH/GpSwixjyCW0xFBOQ==} + deprecated: 'WalletConnect''s v1 SDKs are now deprecated. Please upgrade to a v2 SDK. For details see: https://docs.walletconnect.com/' + dependencies: + '@walletconnect/core': 1.8.0 + '@walletconnect/iso-crypto': 1.8.0 + '@walletconnect/types': 1.8.0 + '@walletconnect/utils': 1.8.0 + transitivePeerDependencies: + - bufferutil + - utf-8-validate + dev: false + + /@walletconnect/core@1.8.0: + resolution: {integrity: sha512-aFTHvEEbXcZ8XdWBw6rpQDte41Rxwnuk3SgTD8/iKGSRTni50gI9S3YEzMj05jozSiOBxQci4pJDMVhIUMtarw==} + dependencies: + '@walletconnect/socket-transport': 1.8.0 + '@walletconnect/types': 1.8.0 + '@walletconnect/utils': 1.8.0 + transitivePeerDependencies: + - bufferutil + - utf-8-validate + dev: false + + /@walletconnect/core@2.10.0: + resolution: {integrity: sha512-Z8pdorfIMueuiBXLdnf7yloiO9JIiobuxN3j0OTal+MYc4q5/2O7d+jdD1DAXbLi1taJx3x60UXT/FPVkjIqIQ==} + dependencies: + '@walletconnect/heartbeat': 1.2.1 + '@walletconnect/jsonrpc-provider': 1.0.13 + '@walletconnect/jsonrpc-types': 1.0.3 + '@walletconnect/jsonrpc-utils': 1.0.8 + '@walletconnect/jsonrpc-ws-connection': 1.0.13 + '@walletconnect/keyvaluestorage': 1.1.1 + '@walletconnect/logger': 2.0.1 + '@walletconnect/relay-api': 1.0.9 + '@walletconnect/relay-auth': 1.0.4 + '@walletconnect/safe-json': 1.0.2 + '@walletconnect/time': 1.0.2 + '@walletconnect/types': 2.10.0 + '@walletconnect/utils': 2.10.0 + events: 3.3.0 + lodash.isequal: 4.5.0 + uint8arrays: 3.1.1 + transitivePeerDependencies: + - '@azure/app-configuration' + - '@azure/cosmos' + - '@azure/data-tables' + - '@azure/identity' + - '@azure/keyvault-secrets' + - '@azure/storage-blob' + - '@capacitor/preferences' + - '@netlify/blobs' + - '@planetscale/database' + - '@react-native-async-storage/async-storage' + - '@upstash/redis' + - '@vercel/kv' + - bufferutil + - ioredis + - uWebSockets.js + - utf-8-validate + dev: false + + /@walletconnect/crypto@1.0.3: + resolution: {integrity: sha512-+2jdORD7XQs76I2Odgr3wwrtyuLUXD/kprNVsjWRhhhdO9Mt6WqVzOPu0/t7OHSmgal8k7SoBQzUc5hu/8zL/g==} + dependencies: + '@walletconnect/encoding': 1.0.2 + '@walletconnect/environment': 1.0.1 + '@walletconnect/randombytes': 1.0.3 + aes-js: 3.1.2 + hash.js: 1.1.7 + tslib: 1.14.1 + dev: false + + /@walletconnect/encoding@1.0.2: + resolution: {integrity: sha512-CrwSBrjqJ7rpGQcTL3kU+Ief+Bcuu9PH6JLOb+wM6NITX1GTxR/MfNwnQfhLKK6xpRAyj2/nM04OOH6wS8Imag==} + dependencies: + is-typedarray: 1.0.0 + tslib: 1.14.1 + typedarray-to-buffer: 3.1.5 + dev: false + + /@walletconnect/environment@1.0.1: + resolution: {integrity: sha512-T426LLZtHj8e8rYnKfzsw1aG6+M0BT1ZxayMdv/p8yM0MU+eJDISqNY3/bccxRr4LrF9csq02Rhqt08Ibl0VRg==} + dependencies: + tslib: 1.14.1 + dev: false + + /@walletconnect/events@1.0.1: + resolution: {integrity: sha512-NPTqaoi0oPBVNuLv7qPaJazmGHs5JGyO8eEAk5VGKmJzDR7AHzD4k6ilox5kxk1iwiOnFopBOOMLs86Oa76HpQ==} + dependencies: + keyvaluestorage-interface: 1.0.0 + tslib: 1.14.1 + dev: false + + /@walletconnect/heartbeat@1.2.1: + resolution: {integrity: sha512-yVzws616xsDLJxuG/28FqtZ5rzrTA4gUjdEMTbWB5Y8V1XHRmqq4efAxCw5ie7WjbXFSUyBHaWlMR+2/CpQC5Q==} + dependencies: + '@walletconnect/events': 1.0.1 + '@walletconnect/time': 1.0.2 + tslib: 1.14.1 + dev: false + + /@walletconnect/iso-crypto@1.8.0: + resolution: {integrity: sha512-pWy19KCyitpfXb70hA73r9FcvklS+FvO9QUIttp3c2mfW8frxgYeRXfxLRCIQTkaYueRKvdqPjbyhPLam508XQ==} + dependencies: + '@walletconnect/crypto': 1.0.3 + '@walletconnect/types': 1.8.0 + '@walletconnect/utils': 1.8.0 + dev: false + + /@walletconnect/jsonrpc-provider@1.0.13: + resolution: {integrity: sha512-K73EpThqHnSR26gOyNEL+acEex3P7VWZe6KE12ZwKzAt2H4e5gldZHbjsu2QR9cLeJ8AXuO7kEMOIcRv1QEc7g==} + dependencies: + '@walletconnect/jsonrpc-utils': 1.0.8 + '@walletconnect/safe-json': 1.0.2 + tslib: 1.14.1 + dev: false + + /@walletconnect/jsonrpc-types@1.0.3: + resolution: {integrity: sha512-iIQ8hboBl3o5ufmJ8cuduGad0CQm3ZlsHtujv9Eu16xq89q+BG7Nh5VLxxUgmtpnrePgFkTwXirCTkwJH1v+Yw==} + dependencies: + keyvaluestorage-interface: 1.0.0 + tslib: 1.14.1 + dev: false + + /@walletconnect/jsonrpc-utils@1.0.8: + resolution: {integrity: sha512-vdeb03bD8VzJUL6ZtzRYsFMq1eZQcM3EAzT0a3st59dyLfJ0wq+tKMpmGH7HlB7waD858UWgfIcudbPFsbzVdw==} + dependencies: + '@walletconnect/environment': 1.0.1 + '@walletconnect/jsonrpc-types': 1.0.3 + tslib: 1.14.1 + dev: false + + /@walletconnect/jsonrpc-ws-connection@1.0.13: + resolution: {integrity: sha512-mfOM7uFH4lGtQxG+XklYuFBj6dwVvseTt5/ahOkkmpcAEgz2umuzu7fTR+h5EmjQBdrmYyEBOWADbeaFNxdySg==} + dependencies: + '@walletconnect/jsonrpc-utils': 1.0.8 + '@walletconnect/safe-json': 1.0.2 + events: 3.3.0 + tslib: 1.14.1 + ws: 7.5.9 + transitivePeerDependencies: + - bufferutil + - utf-8-validate + dev: false + + /@walletconnect/keyvaluestorage@1.1.1: + resolution: {integrity: sha512-V7ZQq2+mSxAq7MrRqDxanTzu2RcElfK1PfNYiaVnJgJ7Q7G7hTVwF8voIBx92qsRyGHZihrwNPHuZd1aKkd0rA==} + peerDependencies: + '@react-native-async-storage/async-storage': 1.x + peerDependenciesMeta: + '@react-native-async-storage/async-storage': + optional: true + dependencies: + '@walletconnect/safe-json': 1.0.2 + idb-keyval: 6.2.1 + unstorage: 1.10.2(idb-keyval@6.2.1) + transitivePeerDependencies: + - '@azure/app-configuration' + - '@azure/cosmos' + - '@azure/data-tables' + - '@azure/identity' + - '@azure/keyvault-secrets' + - '@azure/storage-blob' + - '@capacitor/preferences' + - '@netlify/blobs' + - '@planetscale/database' + - '@upstash/redis' + - '@vercel/kv' + - ioredis + - uWebSockets.js + dev: false + + /@walletconnect/logger@2.0.1: + resolution: {integrity: sha512-SsTKdsgWm+oDTBeNE/zHxxr5eJfZmE9/5yp/Ku+zJtcTAjELb3DXueWkDXmE9h8uHIbJzIb5wj5lPdzyrjT6hQ==} + dependencies: + pino: 7.11.0 + tslib: 1.14.1 + dev: false + + /@walletconnect/modal-core@2.6.2(@types/react@18.2.67)(react@18.2.0): + resolution: {integrity: sha512-cv8ibvdOJQv2B+nyxP9IIFdxvQznMz8OOr/oR/AaUZym4hjXNL/l1a2UlSQBXrVjo3xxbouMxLb3kBsHoYP2CA==} + dependencies: + valtio: 1.11.2(@types/react@18.2.67)(react@18.2.0) + transitivePeerDependencies: + - '@types/react' + - react + dev: false + + /@walletconnect/modal-sign-html@2.6.2(@types/react@18.2.67)(react@18.2.0): + resolution: {integrity: sha512-p9VhWTikRfUIdUUrOsHj0vRFx0FmI6qraE6kVqxOeLwO9OoLQ6xpIRYpYwPrmASMaXRKFbLul1R3F1MKpBPvcA==} + dependencies: + '@walletconnect/modal': 2.6.2(@types/react@18.2.67)(react@18.2.0) + '@walletconnect/sign-client': 2.10.0 + transitivePeerDependencies: + - '@azure/app-configuration' + - '@azure/cosmos' + - '@azure/data-tables' + - '@azure/identity' + - '@azure/keyvault-secrets' + - '@azure/storage-blob' + - '@capacitor/preferences' + - '@netlify/blobs' + - '@planetscale/database' + - '@react-native-async-storage/async-storage' + - '@types/react' + - '@upstash/redis' + - '@vercel/kv' + - bufferutil + - ioredis + - react + - uWebSockets.js + - utf-8-validate + dev: false + + /@walletconnect/modal-ui@2.6.2(@types/react@18.2.67)(react@18.2.0): + resolution: {integrity: sha512-rbdstM1HPGvr7jprQkyPggX7rP4XiCG85ZA+zWBEX0dVQg8PpAgRUqpeub4xQKDgY7pY/xLRXSiCVdWGqvG2HA==} + dependencies: + '@walletconnect/modal-core': 2.6.2(@types/react@18.2.67)(react@18.2.0) + lit: 2.8.0 + motion: 10.16.2 + qrcode: 1.5.3 + transitivePeerDependencies: + - '@types/react' + - react + dev: false + + /@walletconnect/modal@2.6.2(@types/react@18.2.67)(react@18.2.0): + resolution: {integrity: sha512-eFopgKi8AjKf/0U4SemvcYw9zlLpx9njVN8sf6DAkowC2Md0gPU/UNEbH1Wwj407pEKnEds98pKWib1NN1ACoA==} + dependencies: + '@walletconnect/modal-core': 2.6.2(@types/react@18.2.67)(react@18.2.0) + '@walletconnect/modal-ui': 2.6.2(@types/react@18.2.67)(react@18.2.0) + transitivePeerDependencies: + - '@types/react' + - react + dev: false + + /@walletconnect/randombytes@1.0.3: + resolution: {integrity: sha512-35lpzxcHFbTN3ABefC9W+uBpNZl1GC4Wpx0ed30gibfO/y9oLdy1NznbV96HARQKSBV9J9M/rrtIvf6a23jfYw==} + dependencies: + '@walletconnect/encoding': 1.0.2 + '@walletconnect/environment': 1.0.1 + randombytes: 2.1.0 + tslib: 1.14.1 + dev: false + + /@walletconnect/relay-api@1.0.9: + resolution: {integrity: sha512-Q3+rylJOqRkO1D9Su0DPE3mmznbAalYapJ9qmzDgK28mYF9alcP3UwG/og5V7l7CFOqzCLi7B8BvcBUrpDj0Rg==} + dependencies: + '@walletconnect/jsonrpc-types': 1.0.3 + tslib: 1.14.1 + dev: false + + /@walletconnect/relay-auth@1.0.4: + resolution: {integrity: sha512-kKJcS6+WxYq5kshpPaxGHdwf5y98ZwbfuS4EE/NkQzqrDFm5Cj+dP8LofzWvjrrLkZq7Afy7WrQMXdLy8Sx7HQ==} + dependencies: + '@stablelib/ed25519': 1.0.3 + '@stablelib/random': 1.0.2 + '@walletconnect/safe-json': 1.0.2 + '@walletconnect/time': 1.0.2 + tslib: 1.14.1 + uint8arrays: 3.1.1 + dev: false + + /@walletconnect/safe-json@1.0.0: + resolution: {integrity: sha512-QJzp/S/86sUAgWY6eh5MKYmSfZaRpIlmCJdi5uG4DJlKkZrHEF7ye7gA+VtbVzvTtpM/gRwO2plQuiooIeXjfg==} + dev: false + + /@walletconnect/safe-json@1.0.2: + resolution: {integrity: sha512-Ogb7I27kZ3LPC3ibn8ldyUr5544t3/STow9+lzz7Sfo808YD7SBWk7SAsdBFlYgP2zDRy2hS3sKRcuSRM0OTmA==} + dependencies: + tslib: 1.14.1 + dev: false + + /@walletconnect/sign-client@2.10.0: + resolution: {integrity: sha512-hbDljDS53kR/It3oXD91UkcOsT6diNnW5+Zzksm0YEfwww5dop/YfNlcdnc8+jKUhWOL/YDPNQCjzsCSNlVzbw==} + dependencies: + '@walletconnect/core': 2.10.0 + '@walletconnect/events': 1.0.1 + '@walletconnect/heartbeat': 1.2.1 + '@walletconnect/jsonrpc-utils': 1.0.8 + '@walletconnect/logger': 2.0.1 + '@walletconnect/time': 1.0.2 + '@walletconnect/types': 2.10.0 + '@walletconnect/utils': 2.10.0 + events: 3.3.0 + transitivePeerDependencies: + - '@azure/app-configuration' + - '@azure/cosmos' + - '@azure/data-tables' + - '@azure/identity' + - '@azure/keyvault-secrets' + - '@azure/storage-blob' + - '@capacitor/preferences' + - '@netlify/blobs' + - '@planetscale/database' + - '@react-native-async-storage/async-storage' + - '@upstash/redis' + - '@vercel/kv' + - bufferutil + - ioredis + - uWebSockets.js + - utf-8-validate + dev: false + + /@walletconnect/socket-transport@1.8.0: + resolution: {integrity: sha512-5DyIyWrzHXTcVp0Vd93zJ5XMW61iDM6bcWT4p8DTRfFsOtW46JquruMhxOLeCOieM4D73kcr3U7WtyR4JUsGuQ==} + dependencies: + '@walletconnect/types': 1.8.0 + '@walletconnect/utils': 1.8.0 + ws: 7.5.3 + transitivePeerDependencies: + - bufferutil + - utf-8-validate + dev: false + + /@walletconnect/time@1.0.2: + resolution: {integrity: sha512-uzdd9woDcJ1AaBZRhqy5rNC9laqWGErfc4dxA9a87mPdKOgWMD85mcFo9dIYIts/Jwocfwn07EC6EzclKubk/g==} + dependencies: + tslib: 1.14.1 + dev: false + + /@walletconnect/types@1.8.0: + resolution: {integrity: sha512-Cn+3I0V0vT9ghMuzh1KzZvCkiAxTq+1TR2eSqw5E5AVWfmCtECFkVZBP6uUJZ8YjwLqXheI+rnjqPy7sVM4Fyg==} + deprecated: 'WalletConnect''s v1 SDKs are now deprecated. Please upgrade to a v2 SDK. For details see: https://docs.walletconnect.com/' + dev: false + + /@walletconnect/types@2.10.0: + resolution: {integrity: sha512-kSTA/WZnbKdEbvbXSW16Ty6dOSzOZCHnGg6JH7q1MuraalD2HuNg00lVVu7QAZ/Rj1Gn9DAkrgP5Wd5a8Xq//Q==} + dependencies: + '@walletconnect/events': 1.0.1 + '@walletconnect/heartbeat': 1.2.1 + '@walletconnect/jsonrpc-types': 1.0.3 + '@walletconnect/keyvaluestorage': 1.1.1 + '@walletconnect/logger': 2.0.1 + events: 3.3.0 + transitivePeerDependencies: + - '@azure/app-configuration' + - '@azure/cosmos' + - '@azure/data-tables' + - '@azure/identity' + - '@azure/keyvault-secrets' + - '@azure/storage-blob' + - '@capacitor/preferences' + - '@netlify/blobs' + - '@planetscale/database' + - '@react-native-async-storage/async-storage' + - '@upstash/redis' + - '@vercel/kv' + - ioredis + - uWebSockets.js + dev: false + + /@walletconnect/types@2.11.3: + resolution: {integrity: sha512-JY4wA9MVosDW9dcJMTpnwliste0aJGJ1X6Q4ulLsQsgWRSEBRkLila0oUT01TDBW9Yq8uUp7uFOUTaKx6KWVAg==} + dependencies: + '@walletconnect/events': 1.0.1 + '@walletconnect/heartbeat': 1.2.1 + '@walletconnect/jsonrpc-types': 1.0.3 + '@walletconnect/keyvaluestorage': 1.1.1 + '@walletconnect/logger': 2.0.1 + events: 3.3.0 + transitivePeerDependencies: + - '@azure/app-configuration' + - '@azure/cosmos' + - '@azure/data-tables' + - '@azure/identity' + - '@azure/keyvault-secrets' + - '@azure/storage-blob' + - '@capacitor/preferences' + - '@netlify/blobs' + - '@planetscale/database' + - '@react-native-async-storage/async-storage' + - '@upstash/redis' + - '@vercel/kv' + - ioredis + - uWebSockets.js + dev: false + + /@walletconnect/utils@1.8.0: + resolution: {integrity: sha512-zExzp8Mj1YiAIBfKNm5u622oNw44WOESzo6hj+Q3apSMIb0Jph9X3GDIdbZmvVZsNPxWDL7uodKgZcCInZv2vA==} + dependencies: + '@walletconnect/browser-utils': 1.8.0 + '@walletconnect/encoding': 1.0.2 + '@walletconnect/jsonrpc-utils': 1.0.8 + '@walletconnect/types': 1.8.0 + bn.js: 4.11.8 + js-sha3: 0.8.0 + query-string: 6.13.5 + dev: false + + /@walletconnect/utils@2.10.0: + resolution: {integrity: sha512-9GRyEz/7CJW+G04RvrjPET5k7hOEsB9b3fF9cWDk/iDCxSWpbkU/hv/urRB36C+gvQMAZgIZYX3dHfzJWkY/2g==} + dependencies: + '@stablelib/chacha20poly1305': 1.0.1 + '@stablelib/hkdf': 1.0.1 + '@stablelib/random': 1.0.2 + '@stablelib/sha256': 1.0.1 + '@stablelib/x25519': 1.0.3 + '@walletconnect/relay-api': 1.0.9 + '@walletconnect/safe-json': 1.0.2 + '@walletconnect/time': 1.0.2 + '@walletconnect/types': 2.10.0 + '@walletconnect/window-getters': 1.0.1 + '@walletconnect/window-metadata': 1.0.1 + detect-browser: 5.3.0 + query-string: 7.1.3 + uint8arrays: 3.1.1 + transitivePeerDependencies: + - '@azure/app-configuration' + - '@azure/cosmos' + - '@azure/data-tables' + - '@azure/identity' + - '@azure/keyvault-secrets' + - '@azure/storage-blob' + - '@capacitor/preferences' + - '@netlify/blobs' + - '@planetscale/database' + - '@react-native-async-storage/async-storage' + - '@upstash/redis' + - '@vercel/kv' + - ioredis + - uWebSockets.js + dev: false + + /@walletconnect/utils@2.11.3: + resolution: {integrity: sha512-jsdNkrl/IcTkzWFn0S2d0urzBXg6RxVJtUYRsUx3qI3wzOGiABP9ui3yiZ3SgZOv9aRe62PaNp1qpbYZ+zPb8Q==} + dependencies: + '@stablelib/chacha20poly1305': 1.0.1 + '@stablelib/hkdf': 1.0.1 + '@stablelib/random': 1.0.2 + '@stablelib/sha256': 1.0.1 + '@stablelib/x25519': 1.0.3 + '@walletconnect/relay-api': 1.0.9 + '@walletconnect/safe-json': 1.0.2 + '@walletconnect/time': 1.0.2 + '@walletconnect/types': 2.11.3 + '@walletconnect/window-getters': 1.0.1 + '@walletconnect/window-metadata': 1.0.1 + detect-browser: 5.3.0 + query-string: 7.1.3 + uint8arrays: 3.1.1 + transitivePeerDependencies: + - '@azure/app-configuration' + - '@azure/cosmos' + - '@azure/data-tables' + - '@azure/identity' + - '@azure/keyvault-secrets' + - '@azure/storage-blob' + - '@capacitor/preferences' + - '@netlify/blobs' + - '@planetscale/database' + - '@react-native-async-storage/async-storage' + - '@upstash/redis' + - '@vercel/kv' + - ioredis + - uWebSockets.js + dev: false + + /@walletconnect/window-getters@1.0.0: + resolution: {integrity: sha512-xB0SQsLaleIYIkSsl43vm8EwETpBzJ2gnzk7e0wMF3ktqiTGS6TFHxcprMl5R44KKh4tCcHCJwolMCaDSwtAaA==} + dev: false + + /@walletconnect/window-getters@1.0.1: + resolution: {integrity: sha512-vHp+HqzGxORPAN8gY03qnbTMnhqIwjeRJNOMOAzePRg4xVEEE2WvYsI9G2NMjOknA8hnuYbU3/hwLcKbjhc8+Q==} + dependencies: + tslib: 1.14.1 + dev: false + + /@walletconnect/window-metadata@1.0.0: + resolution: {integrity: sha512-9eFvmJxIKCC3YWOL97SgRkKhlyGXkrHwamfechmqszbypFspaSk+t2jQXAEU7YClHF6Qjw5eYOmy1//zFi9/GA==} + dependencies: + '@walletconnect/window-getters': 1.0.0 + dev: false + + /@walletconnect/window-metadata@1.0.1: + resolution: {integrity: sha512-9koTqyGrM2cqFRW517BPY/iEtUDx2r1+Pwwu5m7sJ7ka79wi3EyqhqcICk/yDmv6jAS1rjKgTKXlEhanYjijcA==} + dependencies: + '@walletconnect/window-getters': 1.0.1 + tslib: 1.14.1 + dev: false + + /acorn-jsx@5.3.2(acorn@8.11.3): + resolution: {integrity: sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==} + peerDependencies: + acorn: ^6.0.0 || ^7.0.0 || ^8.0.0 + dependencies: + acorn: 8.11.3 + dev: true + + /acorn-walk@8.3.2: + resolution: {integrity: sha512-cjkyv4OtNCIeqhHrfS81QWXoCBPExR/J62oyEqepVw8WaQeSqpW2uhuLPh1m9eWhDuOo/jUXVTlifvesOWp/4A==} + engines: {node: '>=0.4.0'} + + /acorn@8.11.3: + resolution: {integrity: sha512-Y9rRfJG5jcKOE0CLisYbojUjIrIEE7AGMzA/Sm4BslANhbS+cDMpgBdcPT91oJ7OuJ9hYJBx59RjbhxVnrF8Xg==} + engines: {node: '>=0.4.0'} + hasBin: true + + /aes-js@3.1.2: + resolution: {integrity: sha512-e5pEa2kBnBOgR4Y/p20pskXI74UEz7de8ZGVo58asOtvSVG5YAbJeELPZxOmt+Bnz3rX753YKhfIn4X4l1PPRQ==} + dev: false + + /ajv@6.12.6: + resolution: {integrity: sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==} + dependencies: + fast-deep-equal: 3.1.3 + fast-json-stable-stringify: 2.1.0 + json-schema-traverse: 0.4.1 + uri-js: 4.4.1 + dev: true + + /algo-msgpack-with-bigint@2.1.1: + resolution: {integrity: sha512-F1tGh056XczEaEAqu7s+hlZUDWwOBT70Eq0lfMpBP2YguSQVyxRbprLq5rELXKQOyOaixTWYhMeMQMzP0U5FoQ==} + engines: {node: '>= 10'} + dev: false + + /algosdk@2.7.0: + resolution: {integrity: sha512-sBE9lpV7bup3rZ+q2j3JQaFAE9JwZvjWKX00vPlG8e9txctXbgLL56jZhSWZndqhDI9oI+0P4NldkuQIWdrUyg==} + engines: {node: '>=18.0.0'} + dependencies: + algo-msgpack-with-bigint: 2.1.1 + buffer: 6.0.3 + hi-base32: 0.5.1 + js-sha256: 0.9.0 + js-sha3: 0.8.0 + js-sha512: 0.8.0 + json-bigint: 1.0.0 + tweetnacl: 1.0.3 + vlq: 2.0.4 + dev: false + + /ansi-escapes@4.3.2: + resolution: {integrity: sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ==} + engines: {node: '>=8'} + dependencies: + type-fest: 0.21.3 + dev: true + + /ansi-regex@5.0.1: + resolution: {integrity: sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==} + engines: {node: '>=8'} + + /ansi-regex@6.0.1: + resolution: {integrity: sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA==} + engines: {node: '>=12'} + + /ansi-styles@3.2.1: + resolution: {integrity: sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==} + engines: {node: '>=4'} + dependencies: + color-convert: 1.9.3 + + /ansi-styles@4.3.0: + resolution: {integrity: sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==} + engines: {node: '>=8'} + dependencies: + color-convert: 2.0.1 + + /ansi-styles@5.2.0: + resolution: {integrity: sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==} + engines: {node: '>=10'} + dev: true + + /ansi-styles@6.2.1: + resolution: {integrity: sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==} + engines: {node: '>=12'} + + /any-promise@1.3.0: + resolution: {integrity: sha512-7UvmKalWRt1wgjL1RrGxoSJW/0QZFIegpeGvZG9kjp8vrRu55XTHbwnqq2GpXm9uLbcuhxm3IqX9OB4MZR1b2A==} + + /anymatch@3.1.3: + resolution: {integrity: sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==} + engines: {node: '>= 8'} + dependencies: + normalize-path: 3.0.0 + picomatch: 2.3.1 + + /arg@4.1.3: + resolution: {integrity: sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==} + + /arg@5.0.2: + resolution: {integrity: sha512-PYjyFOLKQ9y57JvQ6QLo8dAgNqswh8M1RMJYdQduT6xbWSgK36P/Z/v+p888pM69jMMfS8Xd8F6I1kQ/I9HUGg==} + + /argparse@1.0.10: + resolution: {integrity: sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==} + dependencies: + sprintf-js: 1.0.3 + dev: true + + /argparse@2.0.1: + resolution: {integrity: sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==} + dev: true + + /aria-hidden@1.2.3: + resolution: {integrity: sha512-xcLxITLe2HYa1cnYnwCjkOO1PqUHQpozB8x9AR0OgWN2woOBi5kSDVxKfd0b7sb1hw5qFeJhXm9H1nu3xSfLeQ==} + engines: {node: '>=10'} + dependencies: + tslib: 2.6.2 + dev: false + + /array-union@2.1.0: + resolution: {integrity: sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==} + engines: {node: '>=8'} + dev: true + + /asynckit@0.4.0: + resolution: {integrity: sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==} + dev: false + + /atomic-sleep@1.0.0: + resolution: {integrity: sha512-kNOjDqAh7px0XWNI+4QbzoiR/nTkHAWNud2uvnJquD1/x5a7EQZMJT0AczqK0Qn67oY/TTQ1LbUKajZpp3I9tQ==} + engines: {node: '>=8.0.0'} + dev: false + + /autoprefixer@10.4.18(postcss@8.4.37): + resolution: {integrity: sha512-1DKbDfsr6KUElM6wg+0zRNkB/Q7WcKYAaK+pzXn+Xqmszm/5Xa9coeNdtP88Vi+dPzZnMjhge8GIV49ZQkDa+g==} + engines: {node: ^10 || ^12 || >=14} + hasBin: true + peerDependencies: + postcss: ^8.1.0 + dependencies: + browserslist: 4.23.0 + caniuse-lite: 1.0.30001599 + fraction.js: 4.3.7 + normalize-range: 0.1.2 + picocolors: 1.0.0 + postcss: 8.4.37 + postcss-value-parser: 4.2.0 + dev: true + + /axios-cache-interceptor@1.5.1(axios@1.6.8): + resolution: {integrity: sha512-1p/rTi7DSqUghJ5Ck8GKNt47X6f3IB8XnJ+TM4PwIdhimmCgh0jEQiwI8mBvf2kIMIl4Kz5idwbf/ouK75nEHA==} + engines: {node: '>=12'} + peerDependencies: + axios: ^1 + dependencies: + axios: 1.6.8 + cache-parser: 1.2.4 + fast-defer: 1.1.8 + object-code: 1.3.2 + dev: false + + /axios@1.6.8: + resolution: {integrity: sha512-v/ZHtJDU39mDpyBoFVkETcd/uNdxrWRrg3bKpOKzXFA6Bvqopts6ALSMU3y6ijYxbw2B+wPrIv46egTzJXCLGQ==} + dependencies: + follow-redirects: 1.15.6 + form-data: 4.0.0 + proxy-from-env: 1.1.0 + transitivePeerDependencies: + - debug + dev: false + + /babel-jest@29.7.0(@babel/core@7.24.3): + resolution: {integrity: sha512-BrvGY3xZSwEcCzKvKsCi2GgHqDqsYkOP4/by5xCgIwGXQxIEh+8ew3gmrE1y7XRR6LHZIj6yLYnUi/mm2KXKBg==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + peerDependencies: + '@babel/core': ^7.8.0 + dependencies: + '@babel/core': 7.24.3 + '@jest/transform': 29.7.0 + '@types/babel__core': 7.20.5 + babel-plugin-istanbul: 6.1.1 + babel-preset-jest: 29.6.3(@babel/core@7.24.3) + chalk: 4.1.2 + graceful-fs: 4.2.11 + slash: 3.0.0 + transitivePeerDependencies: + - supports-color + dev: true + + /babel-plugin-istanbul@6.1.1: + resolution: {integrity: sha512-Y1IQok9821cC9onCx5otgFfRm7Lm+I+wwxOx738M/WLPZ9Q42m4IG5W0FNX8WLL2gYMZo3JkuXIH2DOpWM+qwA==} + engines: {node: '>=8'} + dependencies: + '@babel/helper-plugin-utils': 7.24.0 + '@istanbuljs/load-nyc-config': 1.1.0 + '@istanbuljs/schema': 0.1.3 + istanbul-lib-instrument: 5.2.1 + test-exclude: 6.0.0 + transitivePeerDependencies: + - supports-color + dev: true + + /babel-plugin-jest-hoist@29.6.3: + resolution: {integrity: sha512-ESAc/RJvGTFEzRwOTT4+lNDk/GNHMkKbNzsvT0qKRfDyyYTskxB5rnU2njIDYVxXCBHHEI1c0YwHob3WaYujOg==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + dependencies: + '@babel/template': 7.24.0 + '@babel/types': 7.24.0 + '@types/babel__core': 7.20.5 + '@types/babel__traverse': 7.20.5 + dev: true + + /babel-preset-current-node-syntax@1.0.1(@babel/core@7.24.3): + resolution: {integrity: sha512-M7LQ0bxarkxQoN+vz5aJPsLBn77n8QgTFmo8WK0/44auK2xlCXrYcUxHFxgU7qW5Yzw/CjmLRK2uJzaCd7LvqQ==} + peerDependencies: + '@babel/core': ^7.0.0 + dependencies: + '@babel/core': 7.24.3 + '@babel/plugin-syntax-async-generators': 7.8.4(@babel/core@7.24.3) + '@babel/plugin-syntax-bigint': 7.8.3(@babel/core@7.24.3) + '@babel/plugin-syntax-class-properties': 7.12.13(@babel/core@7.24.3) + '@babel/plugin-syntax-import-meta': 7.10.4(@babel/core@7.24.3) + '@babel/plugin-syntax-json-strings': 7.8.3(@babel/core@7.24.3) + '@babel/plugin-syntax-logical-assignment-operators': 7.10.4(@babel/core@7.24.3) + '@babel/plugin-syntax-nullish-coalescing-operator': 7.8.3(@babel/core@7.24.3) + '@babel/plugin-syntax-numeric-separator': 7.10.4(@babel/core@7.24.3) + '@babel/plugin-syntax-object-rest-spread': 7.8.3(@babel/core@7.24.3) + '@babel/plugin-syntax-optional-catch-binding': 7.8.3(@babel/core@7.24.3) + '@babel/plugin-syntax-optional-chaining': 7.8.3(@babel/core@7.24.3) + '@babel/plugin-syntax-top-level-await': 7.14.5(@babel/core@7.24.3) + dev: true + + /babel-preset-jest@29.6.3(@babel/core@7.24.3): + resolution: {integrity: sha512-0B3bhxR6snWXJZtR/RliHTDPRgn1sNHOR0yVtq/IiQFyuOVjFS+wuio/R4gSNkyYmKmJB4wGZv2NZanmKmTnNA==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + peerDependencies: + '@babel/core': ^7.0.0 + dependencies: + '@babel/core': 7.24.3 + babel-plugin-jest-hoist: 29.6.3 + babel-preset-current-node-syntax: 1.0.1(@babel/core@7.24.3) + dev: true + + /balanced-match@1.0.2: + resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==} + + /base64-js@1.5.1: + resolution: {integrity: sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==} + dev: false + + /big.js@6.2.1: + resolution: {integrity: sha512-bCtHMwL9LeDIozFn+oNhhFoq+yQ3BNdnsLSASUxLciOb1vgvpHsIO1dsENiGMgbb4SkP5TrzWzRiLddn8ahVOQ==} + dev: false + + /bignumber.js@9.1.2: + resolution: {integrity: sha512-2/mKyZH9K85bzOEfhXDBFZTGd1CTs+5IHpeFQo9luiBG7hghdC851Pj2WAhb6E3R6b9tZj/XKhbg4fum+Kepug==} + dev: false + + /binary-extensions@2.3.0: + resolution: {integrity: sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==} + engines: {node: '>=8'} + + /bn.js@4.11.8: + resolution: {integrity: sha512-ItfYfPLkWHUjckQCk8xC+LwxgK8NYcXywGigJgSwOP8Y2iyWT4f2vsZnoOXTTbo+o5yXmIUJ4gn5538SO5S3gA==} + dev: false + + /bowser@2.11.0: + resolution: {integrity: sha512-AlcaJBi/pqqJBIQ8U9Mcpc9i8Aqxn88Skv5d+xBX006BY5u8N3mGLHa5Lgppa7L/HfwgwLgZ6NYs+Ag6uUmJRA==} + dev: false + + /brace-expansion@1.1.11: + resolution: {integrity: sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==} + dependencies: + balanced-match: 1.0.2 + concat-map: 0.0.1 + dev: true + + /brace-expansion@2.0.1: + resolution: {integrity: sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==} + dependencies: + balanced-match: 1.0.2 + + /braces@3.0.2: + resolution: {integrity: sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==} + engines: {node: '>=8'} + dependencies: + fill-range: 7.0.1 + + /browserslist@4.23.0: + resolution: {integrity: sha512-QW8HiM1shhT2GuzkvklfjcKDiWFXHOeFCIA/huJPwHsslwcydgk7X+z2zXpEijP98UCY7HbubZt5J2Zgvf0CaQ==} + engines: {node: ^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7} + hasBin: true + dependencies: + caniuse-lite: 1.0.30001599 + electron-to-chromium: 1.4.711 + node-releases: 2.0.14 + update-browserslist-db: 1.0.13(browserslist@4.23.0) + + /bs-logger@0.2.6: + resolution: {integrity: sha512-pd8DCoxmbgc7hyPKOvxtqNcjYoOsABPQdcCUjGp3d42VR2CX1ORhk2A87oqqu5R1kk+76nsxZupkmyd+MVtCog==} + engines: {node: '>= 6'} + dependencies: + fast-json-stable-stringify: 2.1.0 + dev: true + + /bser@2.1.1: + resolution: {integrity: sha512-gQxTNE/GAfIIrmHLUE3oJyp5FO6HRBfhjnw4/wMmA63ZGDJnWBmgY/lyQBpnDUkGmAhbSe39tx2d/iTOAfglwQ==} + dependencies: + node-int64: 0.4.0 + dev: true + + /buffer-from@1.1.2: + resolution: {integrity: sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==} + dev: true + + /buffer@6.0.3: + resolution: {integrity: sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==} + dependencies: + base64-js: 1.5.1 + ieee754: 1.2.1 + dev: false + + /busboy@1.6.0: + resolution: {integrity: sha512-8SFQbg/0hQ9xy3UNTB0YEnsNBbWfhf7RtnzpL7TkBiTBRfrQ9Fxcnz7VJsleJpyp6rVLvXiuORqjlHi5q+PYuA==} + engines: {node: '>=10.16.0'} + dependencies: + streamsearch: 1.1.0 + dev: false + + /cache-parser@1.2.4: + resolution: {integrity: sha512-O0KwuHuJnbHUrghHi2kGp0SxnWSIBXTYt7M8WVhW0kbPRUNUKoE/Of6e1rRD6AAxmfxFunKnt90yEK09D+sc5g==} + dev: false + + /callsites@3.1.0: + resolution: {integrity: sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==} + engines: {node: '>=6'} + dev: true + + /camelcase-css@2.0.1: + resolution: {integrity: sha512-QOSvevhslijgYwRx6Rv7zKdMF8lbRmx+uQGx2+vDc+KI/eBnsy9kit5aj23AgGu3pa4t9AgwbnXWqS+iOY+2aA==} + engines: {node: '>= 6'} + + /camelcase@5.3.1: + resolution: {integrity: sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==} + engines: {node: '>=6'} + + /camelcase@6.3.0: + resolution: {integrity: sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==} + engines: {node: '>=10'} + dev: true + + /caniuse-lite@1.0.30001599: + resolution: {integrity: sha512-LRAQHZ4yT1+f9LemSMeqdMpMxZcc4RMWdj4tiFe3G8tNkWK+E58g+/tzotb5cU6TbcVJLr4fySiAW7XmxQvZQA==} + + /caniuse-lite@1.0.30001605: + resolution: {integrity: sha512-nXwGlFWo34uliI9z3n6Qc0wZaf7zaZWA1CPZ169La5mV3I/gem7bst0vr5XQH5TJXZIMfDeZyOrZnSlVzKxxHQ==} + dev: false + + /chalk@2.4.2: + resolution: {integrity: sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==} + engines: {node: '>=4'} + dependencies: + ansi-styles: 3.2.1 + escape-string-regexp: 1.0.5 + supports-color: 5.5.0 + + /chalk@4.1.2: + resolution: {integrity: sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==} + engines: {node: '>=10'} + dependencies: + ansi-styles: 4.3.0 + supports-color: 7.2.0 + dev: true + + /char-regex@1.0.2: + resolution: {integrity: sha512-kWWXztvZ5SBQV+eRgKFeh8q5sLuZY2+8WUIzlxWVTg+oGwY14qylx1KbKzHd8P6ZYkAg0xyIDU9JMHhyJMZ1jw==} + engines: {node: '>=10'} + dev: true + + /chokidar@3.6.0: + resolution: {integrity: sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==} + engines: {node: '>= 8.10.0'} + dependencies: + anymatch: 3.1.3 + braces: 3.0.2 + glob-parent: 5.1.2 + is-binary-path: 2.1.0 + is-glob: 4.0.3 + normalize-path: 3.0.0 + readdirp: 3.6.0 + optionalDependencies: + fsevents: 2.3.3 + + /ci-info@3.9.0: + resolution: {integrity: sha512-NIxF55hv4nSqQswkAeiOi1r83xy8JldOFDTWiug55KBu9Jnblncd2U6ViHmYgHf01TPZS77NJBhBMKdWj9HQMQ==} + engines: {node: '>=8'} + dev: true + + /citty@0.1.6: + resolution: {integrity: sha512-tskPPKEs8D2KPafUypv2gxwJP8h/OaJmC82QQGGDQcHvXX43xF2VDACcJVmZ0EuSxkpO9Kc4MlrA3q0+FG58AQ==} + dependencies: + consola: 3.2.3 + dev: false + + /cjs-module-lexer@1.2.3: + resolution: {integrity: sha512-0TNiGstbQmCFwt4akjjBg5pLRTSyj/PkWQ1ZoO2zntmg9yLqSRxwEa4iCfQLGjqhiqBfOJa7W/E8wfGrTDmlZQ==} + dev: true + + /class-variance-authority@0.7.0: + resolution: {integrity: sha512-jFI8IQw4hczaL4ALINxqLEXQbWcNjoSkloa4IaufXCJr6QawJyw7tuRysRsrE8w2p/4gGaxKIt/hX3qz/IbD1A==} + dependencies: + clsx: 2.0.0 + dev: false + + /client-only@0.0.1: + resolution: {integrity: sha512-IV3Ou0jSMzZrd3pZ48nLkT9DA7Ag1pnPzaiQhpW7c3RbcqqzvzzVu+L8gfqMp/8IM2MQtSiqaCxrrcfu8I8rMA==} + dev: false + + /clipboardy@4.0.0: + resolution: {integrity: sha512-5mOlNS0mhX0707P2I0aZ2V/cmHUEO/fL7VFLqszkhUsxt7RwnmrInf/eEQKlf5GzvYeHIjT+Ov1HRfNmymlG0w==} + engines: {node: '>=18'} + dependencies: + execa: 8.0.1 + is-wsl: 3.1.0 + is64bit: 2.0.0 + dev: false + + /cliui@6.0.0: + resolution: {integrity: sha512-t6wbgtoCXvAzst7QgXxJYqPt0usEfbgQdftEPbLL/cvv6HPE5VgvqCuAIDR0NgU52ds6rFwqrgakNLrHEjCbrQ==} + dependencies: + string-width: 4.2.3 + strip-ansi: 6.0.1 + wrap-ansi: 6.2.0 + dev: false + + /cliui@8.0.1: + resolution: {integrity: sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==} + engines: {node: '>=12'} + dependencies: + string-width: 4.2.3 + strip-ansi: 6.0.1 + wrap-ansi: 7.0.0 + dev: true + + /clsx@1.2.1: + resolution: {integrity: sha512-EcR6r5a8bj6pu3ycsa/E/cKVGuTgZJZdsyUYHOksG/UHIiKfjxzRxYJpyVBwYaQeOvghal9fcc4PidlgzugAQg==} + engines: {node: '>=6'} + dev: false + + /clsx@2.0.0: + resolution: {integrity: sha512-rQ1+kcj+ttHG0MKVGBUXwayCCF1oh39BF5COIpRzuCEv8Mwjv0XucrI2ExNTOn9IlLifGClWQcU9BrZORvtw6Q==} + engines: {node: '>=6'} + dev: false + + /clsx@2.1.0: + resolution: {integrity: sha512-m3iNNWpd9rl3jvvcBnu70ylMdrXt8Vlq4HYadnU5fwcOtvkSQWPmj7amUcDT2qYI7risszBjI5AUIUox9D16pg==} + engines: {node: '>=6'} + dev: false + + /co@4.6.0: + resolution: {integrity: sha512-QVb0dM5HvG+uaxitm8wONl7jltx8dqhfU33DcqtOZcLSVIKSDDLDi7+0LbAKiyI8hD9u42m2YxXSkMGWThaecQ==} + engines: {iojs: '>= 1.0.0', node: '>= 0.12.0'} + dev: true + + /collect-v8-coverage@1.0.2: + resolution: {integrity: sha512-lHl4d5/ONEbLlJvaJNtsF/Lz+WvB07u2ycqTYbdrq7UypDXailES4valYb2eWiJFxZlVmpGekfqoxQhzyFdT4Q==} + dev: true + + /color-convert@1.9.3: + resolution: {integrity: sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==} + dependencies: + color-name: 1.1.3 + + /color-convert@2.0.1: + resolution: {integrity: sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==} + engines: {node: '>=7.0.0'} + dependencies: + color-name: 1.1.4 + + /color-name@1.1.3: + resolution: {integrity: sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==} + + /color-name@1.1.4: + resolution: {integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==} + + /combined-stream@1.0.8: + resolution: {integrity: sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==} + engines: {node: '>= 0.8'} + dependencies: + delayed-stream: 1.0.0 + dev: false + + /commander@4.1.1: + resolution: {integrity: sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA==} + engines: {node: '>= 6'} + + /concat-map@0.0.1: + resolution: {integrity: sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==} + dev: true + + /consola@3.2.3: + resolution: {integrity: sha512-I5qxpzLv+sJhTVEoLYNcTW+bThDCPsit0vLNKShZx6rLtpilNpmmeTPaeqJb9ZE9dV3DGaeby6Vuhrw38WjeyQ==} + engines: {node: ^14.18.0 || >=16.10.0} + dev: false + + /convert-source-map@2.0.0: + resolution: {integrity: sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==} + + /cookie-es@1.0.0: + resolution: {integrity: sha512-mWYvfOLrfEc996hlKcdABeIiPHUPC6DM2QYZdGGOvhOTbA3tjm2eBwqlJpoFdjC89NI4Qt6h0Pu06Mp+1Pj5OQ==} + dev: false + + /copy-to-clipboard@3.3.3: + resolution: {integrity: sha512-2KV8NhB5JqC3ky0r9PMCAZKbUHSwtEo4CwCs0KXgruG43gX5PMqDEBbVU4OUzw2MuAWUfsuFmWvEKG5QRfSnJA==} + dependencies: + toggle-selection: 1.0.6 + dev: false + + /create-jest@29.7.0(@types/node@18.19.26)(ts-node@10.9.2): + resolution: {integrity: sha512-Adz2bdH0Vq3F53KEMJOoftQFutWCukm6J24wbPWRO4k1kMY7gS7ds/uoJkNuV8wDCtWWnuwGcJwpWcih+zEW1Q==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + hasBin: true + dependencies: + '@jest/types': 29.6.3 + chalk: 4.1.2 + exit: 0.1.2 + graceful-fs: 4.2.11 + jest-config: 29.7.0(@types/node@18.19.26)(ts-node@10.9.2) + jest-util: 29.7.0 + prompts: 2.4.2 + transitivePeerDependencies: + - '@types/node' + - babel-plugin-macros + - supports-color + - ts-node + dev: true + + /create-require@1.1.1: + resolution: {integrity: sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==} + + /cross-spawn@7.0.3: + resolution: {integrity: sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==} + engines: {node: '>= 8'} + dependencies: + path-key: 3.1.1 + shebang-command: 2.0.0 + which: 2.0.2 + + /crossws@0.2.4: + resolution: {integrity: sha512-DAxroI2uSOgUKLz00NX6A8U/8EE3SZHmIND+10jkVSaypvyt57J5JEOxAQOL6lQxyzi/wZbTIwssU1uy69h5Vg==} + peerDependencies: + uWebSockets.js: '*' + peerDependenciesMeta: + uWebSockets.js: + optional: true + dev: false + + /cssesc@3.0.0: + resolution: {integrity: sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==} + engines: {node: '>=4'} + hasBin: true + + /csstype@3.1.3: + resolution: {integrity: sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==} + + /d3-array@3.2.4: + resolution: {integrity: sha512-tdQAmyA18i4J7wprpYq8ClcxZy3SC31QMeByyCFyRt7BVHdREQZ5lpzoe5mFEYZUWe+oq8HBvk9JjpibyEV4Jg==} + engines: {node: '>=12'} + dependencies: + internmap: 2.0.3 + dev: false + + /d3-color@3.1.0: + resolution: {integrity: sha512-zg/chbXyeBtMQ1LbD/WSoW2DpC3I0mpmPdW+ynRTj/x2DAWYrIY7qeZIHidozwV24m4iavr15lNwIwLxRmOxhA==} + engines: {node: '>=12'} + dev: false + + /d3-ease@3.0.1: + resolution: {integrity: sha512-wR/XK3D3XcLIZwpbvQwQ5fK+8Ykds1ip7A2Txe0yxncXSdq1L9skcG7blcedkOX+ZcgxGAmLX1FrRGbADwzi0w==} + engines: {node: '>=12'} + dev: false + + /d3-format@3.1.0: + resolution: {integrity: sha512-YyUI6AEuY/Wpt8KWLgZHsIU86atmikuoOmCfommt0LYHiQSPjvX2AcFc38PX0CBpr2RCyZhjex+NS/LPOv6YqA==} + engines: {node: '>=12'} + dev: false + + /d3-interpolate@3.0.1: + resolution: {integrity: sha512-3bYs1rOD33uo8aqJfKP3JWPAibgw8Zm2+L9vBKEHJ2Rg+viTR7o5Mmv5mZcieN+FRYaAOWX5SJATX6k1PWz72g==} + engines: {node: '>=12'} + dependencies: + d3-color: 3.1.0 + dev: false + + /d3-path@3.1.0: + resolution: {integrity: sha512-p3KP5HCf/bvjBSSKuXid6Zqijx7wIfNW+J/maPs+iwR35at5JCbLUT0LzF1cnjbCHWhqzQTIN2Jpe8pRebIEFQ==} + engines: {node: '>=12'} + dev: false + + /d3-scale@4.0.2: + resolution: {integrity: sha512-GZW464g1SH7ag3Y7hXjf8RoUuAFIqklOAq3MRl4OaWabTFJY9PN/E1YklhXLh+OQ3fM9yS2nOkCoS+WLZ6kvxQ==} + engines: {node: '>=12'} + dependencies: + d3-array: 3.2.4 + d3-format: 3.1.0 + d3-interpolate: 3.0.1 + d3-time: 3.1.0 + d3-time-format: 4.1.0 + dev: false + + /d3-shape@3.2.0: + resolution: {integrity: sha512-SaLBuwGm3MOViRq2ABk3eLoxwZELpH6zhl3FbAoJ7Vm1gofKx6El1Ib5z23NUEhF9AsGl7y+dzLe5Cw2AArGTA==} + engines: {node: '>=12'} + dependencies: + d3-path: 3.1.0 + dev: false + + /d3-time-format@4.1.0: + resolution: {integrity: sha512-dJxPBlzC7NugB2PDLwo9Q8JiTR3M3e4/XANkreKSUxF8vvXKqm1Yfq4Q5dl8budlunRVlUUaDUgFt7eA8D6NLg==} + engines: {node: '>=12'} + dependencies: + d3-time: 3.1.0 + dev: false + + /d3-time@3.1.0: + resolution: {integrity: sha512-VqKjzBLejbSMT4IgbmVgDjpkYrNWUYJnbCGo874u7MMKIWsILRX+OpX/gTk8MqjpT1A/c6HY2dCA77ZN0lkQ2Q==} + engines: {node: '>=12'} + dependencies: + d3-array: 3.2.4 + dev: false + + /d3-timer@3.0.1: + resolution: {integrity: sha512-ndfJ/JxxMd3nw31uyKoY2naivF+r29V+Lc0svZxe1JvvIRmi8hUsrMvdOwgS1o6uBHmiz91geQ0ylPP0aj1VUA==} + engines: {node: '>=12'} + dev: false + + /date-fns@2.30.0: + resolution: {integrity: sha512-fnULvOpxnC5/Vg3NCiWelDsLiUc9bRwAPs/+LfTLNvetFCtCTN+yQz15C/fs4AwX1R9K5GLtLfn8QW+dWisaAw==} + engines: {node: '>=0.11'} + dependencies: + '@babel/runtime': 7.24.1 + dev: false + + /dayjs@1.11.10: + resolution: {integrity: sha512-vjAczensTgRcqDERK0SR2XMwsF/tSvnvlv6VcF2GIhg6Sx4yOIt/irsr1RDJsKiIyBzJDpCoXiWWq28MqH2cnQ==} + dev: false + + /debug@4.3.4: + resolution: {integrity: sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==} + engines: {node: '>=6.0'} + peerDependencies: + supports-color: '*' + peerDependenciesMeta: + supports-color: + optional: true + dependencies: + ms: 2.1.2 + + /decamelize@1.2.0: + resolution: {integrity: sha512-z2S+W9X73hAUUki+N+9Za2lBlun89zigOyGrsax+KUQ6wKW4ZoWpEYBkGhQjwAjjDCkWxhY0VKEhk8wzY7F5cA==} + engines: {node: '>=0.10.0'} + dev: false + + /decimal.js-light@2.5.1: + resolution: {integrity: sha512-qIMFpTMZmny+MMIitAB6D7iVPEorVw6YQRWkvarTkT4tBeSLLiHzcwj6q0MmYSFCiVpiqPJTJEYIrpcPzVEIvg==} + dev: false + + /decode-uri-component@0.2.2: + resolution: {integrity: sha512-FqUYQ+8o158GyGTrMFJms9qh3CqTKvAqgqsTnkLI8sKu0028orqBhxNMFkFen0zGyg6epACD32pjVk58ngIErQ==} + engines: {node: '>=0.10'} + dev: false + + /dedent@1.5.1: + resolution: {integrity: sha512-+LxW+KLWxu3HW3M2w2ympwtqPrqYRzU8fqi6Fhd18fBALe15blJPI/I4+UHveMVG6lJqB4JNd4UG0S5cnVHwIg==} + peerDependencies: + babel-plugin-macros: ^3.1.0 + peerDependenciesMeta: + babel-plugin-macros: + optional: true + dev: true + + /deep-is@0.1.4: + resolution: {integrity: sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==} + dev: true + + /deepmerge@4.3.1: + resolution: {integrity: sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==} + engines: {node: '>=0.10.0'} + dev: true + + /defu@6.1.4: + resolution: {integrity: sha512-mEQCMmwJu317oSz8CwdIOdwf3xMif1ttiM8LTufzc3g6kR+9Pe236twL8j3IYT1F7GfRgGcW6MWxzZjLIkuHIg==} + dev: false + + /delayed-stream@1.0.0: + resolution: {integrity: sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==} + engines: {node: '>=0.4.0'} + dev: false + + /destr@2.0.3: + resolution: {integrity: sha512-2N3BOUU4gYMpTP24s5rF5iP7BDr7uNTCs4ozw3kf/eKfvWSIu93GEBi5m427YoyJoeOzQ5smuu4nNAPGb8idSQ==} + dev: false + + /detect-browser@5.2.0: + resolution: {integrity: sha512-tr7XntDAu50BVENgQfajMLzacmSe34D+qZc4zjnniz0ZVuw/TZcLcyxHQjYpJTM36sGEkZZlYLnIM1hH7alTMA==} + dev: false + + /detect-browser@5.3.0: + resolution: {integrity: sha512-53rsFbGdwMwlF7qvCt0ypLM5V5/Mbl0szB7GPN8y9NCcbknYOeVVXdrXEq+90IwAfrrzt6Hd+u2E2ntakICU8w==} + dev: false + + /detect-libc@1.0.3: + resolution: {integrity: sha512-pGjwhsmsp4kL2RTz08wcOlGN83otlqHeD/Z5T8GXZB+/YcpQ/dgo+lbU8ZsGxV0HIvqqxo9l7mqYwyYMD9bKDg==} + engines: {node: '>=0.10'} + hasBin: true + dev: false + + /detect-newline@3.1.0: + resolution: {integrity: sha512-TLz+x/vEXm/Y7P7wn1EJFNLxYpUD4TgMosxY6fAVJUnJMbupHBOncxyWUG9OpTaH9EBD7uFI5LfEgmMOc54DsA==} + engines: {node: '>=8'} + dev: true + + /detect-node-es@1.1.0: + resolution: {integrity: sha512-ypdmJU/TbBby2Dxibuv7ZLW3Bs1QEmM7nHjEANfohJLvE0XVujisn1qPJcZxg+qDucsr+bP6fLD1rPS3AhJ7EQ==} + dev: false + + /didyoumean@1.2.2: + resolution: {integrity: sha512-gxtyfqMg7GKyhQmb056K7M3xszy/myH8w+B4RT+QXBQsvAOdc3XymqDDPHx1BgPgsdAA5SIifona89YtRATDzw==} + + /diff-sequences@29.6.3: + resolution: {integrity: sha512-EjePK1srD3P08o2j4f0ExnylqRs5B9tJjcp9t1krH2qRi8CCdsYfwe9JgSLurFBWwq4uOlipzfk5fHNvwFKr8Q==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + dev: true + + /diff@4.0.2: + resolution: {integrity: sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==} + engines: {node: '>=0.3.1'} + + /dijkstrajs@1.0.3: + resolution: {integrity: sha512-qiSlmBq9+BCdCA/L46dw8Uy93mloxsPSbwnm5yrKn2vMPiy8KyAskTF6zuV/j5BMsmOGZDPs7KjU+mjb670kfA==} + dev: false + + /dir-glob@3.0.1: + resolution: {integrity: sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==} + engines: {node: '>=8'} + dependencies: + path-type: 4.0.0 + dev: true + + /dlv@1.1.3: + resolution: {integrity: sha512-+HlytyjlPKnIG8XuRG8WvmBP8xs8P71y+SKKS6ZXWoEgLuePxtDoUEiH7WkdePWrQ5JBpE6aoVqfZfJUQkjXwA==} + + /doctrine@3.0.0: + resolution: {integrity: sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==} + engines: {node: '>=6.0.0'} + dependencies: + esutils: 2.0.3 + dev: true + + /dom-helpers@5.2.1: + resolution: {integrity: sha512-nRCa7CK3VTrM2NmGkIy4cbK7IZlgBE/PYMn55rrXefr5xXDP0LdtfPnblFDoVdcAfslJ7or6iqAUnx0CCGIWQA==} + dependencies: + '@babel/runtime': 7.24.1 + csstype: 3.1.3 + dev: false + + /duplexify@4.1.3: + resolution: {integrity: sha512-M3BmBhwJRZsSx38lZyhE53Csddgzl5R7xGJNk7CVddZD6CcmwMCH8J+7AprIrQKH7TonKxaCjcv27Qmf+sQ+oA==} + dependencies: + end-of-stream: 1.4.4 + inherits: 2.0.4 + readable-stream: 3.6.2 + stream-shift: 1.0.3 + dev: false + + /eastasianwidth@0.2.0: + resolution: {integrity: sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==} + + /electron-to-chromium@1.4.711: + resolution: {integrity: sha512-hRg81qzvUEibX2lDxnFlVCHACa+LtrCPIsWAxo161LDYIB3jauf57RGsMZV9mvGwE98yGH06icj3zBEoOkxd/w==} + + /emittery@0.13.1: + resolution: {integrity: sha512-DeWwawk6r5yR9jFgnDKYt4sLS0LmHJJi3ZOnb5/JdbYwj3nW+FxQnHIjhBKz8YLC7oRNPVM9NQ47I3CVx34eqQ==} + engines: {node: '>=12'} + dev: true + + /emoji-regex@8.0.0: + resolution: {integrity: sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==} + + /emoji-regex@9.2.2: + resolution: {integrity: sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==} + + /encode-utf8@1.0.3: + resolution: {integrity: sha512-ucAnuBEhUK4boH2HjVYG5Q2mQyPorvv0u/ocS+zhdw0S8AlHYY+GOFhP1Gio5z4icpP2ivFSvhtFjQi8+T9ppw==} + dev: false + + /end-of-stream@1.4.4: + resolution: {integrity: sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==} + dependencies: + once: 1.4.0 + dev: false + + /error-ex@1.3.2: + resolution: {integrity: sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==} + dependencies: + is-arrayish: 0.2.1 + dev: true + + /esbuild@0.19.12: + resolution: {integrity: sha512-aARqgq8roFBj054KvQr5f1sFu0D65G+miZRCuJyJ0G13Zwx7vRar5Zhn2tkQNzIXcBrNVsv/8stehpj+GAjgbg==} + engines: {node: '>=12'} + hasBin: true + requiresBuild: true + optionalDependencies: + '@esbuild/aix-ppc64': 0.19.12 + '@esbuild/android-arm': 0.19.12 + '@esbuild/android-arm64': 0.19.12 + '@esbuild/android-x64': 0.19.12 + '@esbuild/darwin-arm64': 0.19.12 + '@esbuild/darwin-x64': 0.19.12 + '@esbuild/freebsd-arm64': 0.19.12 + '@esbuild/freebsd-x64': 0.19.12 + '@esbuild/linux-arm': 0.19.12 + '@esbuild/linux-arm64': 0.19.12 + '@esbuild/linux-ia32': 0.19.12 + '@esbuild/linux-loong64': 0.19.12 + '@esbuild/linux-mips64el': 0.19.12 + '@esbuild/linux-ppc64': 0.19.12 + '@esbuild/linux-riscv64': 0.19.12 + '@esbuild/linux-s390x': 0.19.12 + '@esbuild/linux-x64': 0.19.12 + '@esbuild/netbsd-x64': 0.19.12 + '@esbuild/openbsd-x64': 0.19.12 + '@esbuild/sunos-x64': 0.19.12 + '@esbuild/win32-arm64': 0.19.12 + '@esbuild/win32-ia32': 0.19.12 + '@esbuild/win32-x64': 0.19.12 + dev: true + + /escalade@3.1.2: + resolution: {integrity: sha512-ErCHMCae19vR8vQGe50xIsVomy19rg6gFu3+r3jkEO46suLMWBksvVyoGgQV+jOfl84ZSOSlmv6Gxa89PmTGmA==} + engines: {node: '>=6'} + + /escape-string-regexp@1.0.5: + resolution: {integrity: sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==} + engines: {node: '>=0.8.0'} + + /escape-string-regexp@2.0.0: + resolution: {integrity: sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w==} + engines: {node: '>=8'} + dev: true + + /escape-string-regexp@4.0.0: + resolution: {integrity: sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==} + engines: {node: '>=10'} + dev: true + + /eslint-config-prettier@8.10.0(eslint@8.57.0): + resolution: {integrity: sha512-SM8AMJdeQqRYT9O9zguiruQZaN7+z+E4eAP9oiLNGKMtomwaB1E9dcgUD6ZAn/eQAb52USbvezbiljfZUhbJcg==} + hasBin: true + peerDependencies: + eslint: '>=7.0.0' + dependencies: + eslint: 8.57.0 + dev: true + + /eslint-plugin-prettier@5.1.3(eslint-config-prettier@8.10.0)(eslint@8.57.0)(prettier@3.2.5): + resolution: {integrity: sha512-C9GCVAs4Eq7ZC/XFQHITLiHJxQngdtraXaM+LoUFoFp/lHNl2Zn8f3WQbe9HvTBBQ9YnKFB0/2Ajdqwo5D1EAw==} + engines: {node: ^14.18.0 || >=16.0.0} + peerDependencies: + '@types/eslint': '>=8.0.0' + eslint: '>=8.0.0' + eslint-config-prettier: '*' + prettier: '>=3.0.0' + peerDependenciesMeta: + '@types/eslint': + optional: true + eslint-config-prettier: + optional: true + dependencies: + eslint: 8.57.0 + eslint-config-prettier: 8.10.0(eslint@8.57.0) + prettier: 3.2.5 + prettier-linter-helpers: 1.0.0 + synckit: 0.8.8 + dev: true + + /eslint-scope@7.2.2: + resolution: {integrity: sha512-dOt21O7lTMhDM+X9mB4GX+DZrZtCUJPL/wlcTqxyrx5IvO0IYtILdtrQGQp+8n5S0gwSVmOf9NQrjMOgfQZlIg==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + dependencies: + esrecurse: 4.3.0 + estraverse: 5.3.0 + dev: true + + /eslint-visitor-keys@3.4.3: + resolution: {integrity: sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + dev: true + + /eslint@8.57.0: + resolution: {integrity: sha512-dZ6+mexnaTIbSBZWgou51U6OmzIhYM2VcNdtiTtI7qPNZm35Akpr0f6vtw3w1Kmn5PYo+tZVfh13WrhpS6oLqQ==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + hasBin: true + dependencies: + '@eslint-community/eslint-utils': 4.4.0(eslint@8.57.0) + '@eslint-community/regexpp': 4.10.0 + '@eslint/eslintrc': 2.1.4 + '@eslint/js': 8.57.0 + '@humanwhocodes/config-array': 0.11.14 + '@humanwhocodes/module-importer': 1.0.1 + '@nodelib/fs.walk': 1.2.8 + '@ungap/structured-clone': 1.2.0 + ajv: 6.12.6 + chalk: 4.1.2 + cross-spawn: 7.0.3 + debug: 4.3.4 + doctrine: 3.0.0 + escape-string-regexp: 4.0.0 + eslint-scope: 7.2.2 + eslint-visitor-keys: 3.4.3 + espree: 9.6.1 + esquery: 1.5.0 + esutils: 2.0.3 + fast-deep-equal: 3.1.3 + file-entry-cache: 6.0.1 + find-up: 5.0.0 + glob-parent: 6.0.2 + globals: 13.24.0 + graphemer: 1.4.0 + ignore: 5.3.1 + imurmurhash: 0.1.4 + is-glob: 4.0.3 + is-path-inside: 3.0.3 + js-yaml: 4.1.0 + json-stable-stringify-without-jsonify: 1.0.1 + levn: 0.4.1 + lodash.merge: 4.6.2 + minimatch: 3.1.2 + natural-compare: 1.4.0 + optionator: 0.9.3 + strip-ansi: 6.0.1 + text-table: 0.2.0 + transitivePeerDependencies: + - supports-color + dev: true + + /espree@9.6.1: + resolution: {integrity: sha512-oruZaFkjorTpF32kDSI5/75ViwGeZginGGy2NoOSg3Q9bnwlnmDm4HLnkl0RE3n+njDXR037aY1+x58Z/zFdwQ==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + dependencies: + acorn: 8.11.3 + acorn-jsx: 5.3.2(acorn@8.11.3) + eslint-visitor-keys: 3.4.3 + dev: true + + /esprima@4.0.1: + resolution: {integrity: sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==} + engines: {node: '>=4'} + hasBin: true + dev: true + + /esquery@1.5.0: + resolution: {integrity: sha512-YQLXUplAwJgCydQ78IMJywZCceoqk1oH01OERdSAJc/7U2AylwjhSCLDEtqwg811idIS/9fIU5GjG73IgjKMVg==} + engines: {node: '>=0.10'} + dependencies: + estraverse: 5.3.0 + dev: true + + /esrecurse@4.3.0: + resolution: {integrity: sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==} + engines: {node: '>=4.0'} + dependencies: + estraverse: 5.3.0 + dev: true + + /estraverse@5.3.0: + resolution: {integrity: sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==} + engines: {node: '>=4.0'} + dev: true + + /esutils@2.0.3: + resolution: {integrity: sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==} + engines: {node: '>=0.10.0'} + dev: true + + /eventemitter3@4.0.7: + resolution: {integrity: sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw==} + dev: false + + /events@3.3.0: + resolution: {integrity: sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==} + engines: {node: '>=0.8.x'} + dev: false + + /execa@5.1.1: + resolution: {integrity: sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==} + engines: {node: '>=10'} + dependencies: + cross-spawn: 7.0.3 + get-stream: 6.0.1 + human-signals: 2.1.0 + is-stream: 2.0.1 + merge-stream: 2.0.0 + npm-run-path: 4.0.1 + onetime: 5.1.2 + signal-exit: 3.0.7 + strip-final-newline: 2.0.0 + dev: true + + /execa@8.0.1: + resolution: {integrity: sha512-VyhnebXciFV2DESc+p6B+y0LjSm0krU4OgJN44qFAhBY0TJ+1V61tYD2+wHusZ6F9n5K+vl8k0sTy7PEfV4qpg==} + engines: {node: '>=16.17'} + dependencies: + cross-spawn: 7.0.3 + get-stream: 8.0.1 + human-signals: 5.0.0 + is-stream: 3.0.0 + merge-stream: 2.0.0 + npm-run-path: 5.3.0 + onetime: 6.0.0 + signal-exit: 4.1.0 + strip-final-newline: 3.0.0 + dev: false + + /exit@0.1.2: + resolution: {integrity: sha512-Zk/eNKV2zbjpKzrsQ+n1G6poVbErQxJ0LBOJXaKZ1EViLzH+hrLu9cdXI4zw9dBQJslwBEpbQ2P1oS7nDxs6jQ==} + engines: {node: '>= 0.8.0'} + dev: true + + /expect@29.7.0: + resolution: {integrity: sha512-2Zks0hf1VLFYI1kbh0I5jP3KHHyCHpkfyHBzsSXRFgl/Bg9mWYfMW8oD+PdMPlEwy5HNsR9JutYy6pMeOh61nw==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + dependencies: + '@jest/expect-utils': 29.7.0 + jest-get-type: 29.6.3 + jest-matcher-utils: 29.7.0 + jest-message-util: 29.7.0 + jest-util: 29.7.0 + dev: true + + /fast-deep-equal@3.1.3: + resolution: {integrity: sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==} + dev: true + + /fast-defer@1.1.8: + resolution: {integrity: sha512-lEJeOH5VL5R09j6AA0D4Uvq7AgsHw0dAImQQ+F3iSyHZuAxyQfWobsagGpTcOPvJr3urmKRHrs+Gs9hV+/Qm/Q==} + dev: false + + /fast-diff@1.3.0: + resolution: {integrity: sha512-VxPP4NqbUjj6MaAOafWeUn2cXWLcCtljklUtZf0Ind4XQ+QPtmA0b18zZy0jIQx+ExRVCR/ZQpBmik5lXshNsw==} + dev: true + + /fast-equals@5.0.1: + resolution: {integrity: sha512-WF1Wi8PwwSY7/6Kx0vKXtw8RwuSGoM1bvDaJbu7MxDlR1vovZjIAKrnzyrThgAjm6JDTu0fVgWXDlMGspodfoQ==} + engines: {node: '>=6.0.0'} + dev: false + + /fast-glob@3.3.2: + resolution: {integrity: sha512-oX2ruAFQwf/Orj8m737Y5adxDQO0LAB7/S5MnxCdTNDd4p6BsyIVsv9JQsATbTSq8KHRpLwIHbVlUNatxd+1Ow==} + engines: {node: '>=8.6.0'} + dependencies: + '@nodelib/fs.stat': 2.0.5 + '@nodelib/fs.walk': 1.2.8 + glob-parent: 5.1.2 + merge2: 1.4.1 + micromatch: 4.0.5 + + /fast-json-stable-stringify@2.1.0: + resolution: {integrity: sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==} + dev: true + + /fast-levenshtein@2.0.6: + resolution: {integrity: sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==} + dev: true + + /fast-redact@3.5.0: + resolution: {integrity: sha512-dwsoQlS7h9hMeYUq1W++23NDcBLV4KqONnITDV9DjfS3q1SgDGVrBdvvTLUotWtPSD7asWDV9/CmsZPy8Hf70A==} + engines: {node: '>=6'} + dev: false + + /fastq@1.17.1: + resolution: {integrity: sha512-sRVD3lWVIXWg6By68ZN7vho9a1pQcN/WBFaAAsDDFzlJjvoGx0P8z7V1t72grFJfJhu3YPZBuu25f7Kaw2jN1w==} + dependencies: + reusify: 1.0.4 + + /fb-watchman@2.0.2: + resolution: {integrity: sha512-p5161BqbuCaSnB8jIbzQHOlpgsPmK5rJVDfDKO91Axs5NC1uu3HRQm6wt9cd9/+GtQQIO53JdGXXoyDpTAsgYA==} + dependencies: + bser: 2.1.1 + dev: true + + /file-entry-cache@6.0.1: + resolution: {integrity: sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==} + engines: {node: ^10.12.0 || >=12.0.0} + dependencies: + flat-cache: 3.2.0 + dev: true + + /fill-range@7.0.1: + resolution: {integrity: sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==} + engines: {node: '>=8'} + dependencies: + to-regex-range: 5.0.1 + + /filter-obj@1.1.0: + resolution: {integrity: sha512-8rXg1ZnX7xzy2NGDVkBVaAy+lSlPNwad13BtgSlLuxfIslyt5Vg64U7tFcCt4WS1R0hvtnQybT/IyCkGZ3DpXQ==} + engines: {node: '>=0.10.0'} + dev: false + + /find-up@4.1.0: + resolution: {integrity: sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==} + engines: {node: '>=8'} + dependencies: + locate-path: 5.0.0 + path-exists: 4.0.0 + + /find-up@5.0.0: + resolution: {integrity: sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==} + engines: {node: '>=10'} + dependencies: + locate-path: 6.0.0 + path-exists: 4.0.0 + dev: true + + /flat-cache@3.2.0: + resolution: {integrity: sha512-CYcENa+FtcUKLmhhqyctpclsq7QF38pKjZHsGNiSQF5r4FtoKDWabFDl3hzaEQMvT1LHEysw5twgLvpYYb4vbw==} + engines: {node: ^10.12.0 || >=12.0.0} + dependencies: + flatted: 3.3.1 + keyv: 4.5.4 + rimraf: 3.0.2 + dev: true + + /flatted@3.3.1: + resolution: {integrity: sha512-X8cqMLLie7KsNUDSdzeN8FYK9rEt4Dt67OsG/DNGnYTSDBG4uFAJFBnUeiV+zCVAvwFy56IjM9sH51jVaEhNxw==} + dev: true + + /follow-redirects@1.15.6: + resolution: {integrity: sha512-wWN62YITEaOpSK584EZXJafH1AGpO8RVgElfkuXbTOrPX4fIfOyEpW/CsiNd8JdYrAoOvafRTOEnvsO++qCqFA==} + engines: {node: '>=4.0'} + peerDependencies: + debug: '*' + peerDependenciesMeta: + debug: + optional: true + dev: false + + /foreground-child@3.1.1: + resolution: {integrity: sha512-TMKDUnIte6bfb5nWv7V/caI169OHgvwjb7V4WkeUvbQQdjr5rWKqHFiKWb/fcOwB+CzBT+qbWjvj+DVwRskpIg==} + engines: {node: '>=14'} + dependencies: + cross-spawn: 7.0.3 + signal-exit: 4.1.0 + + /form-data@4.0.0: + resolution: {integrity: sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==} + engines: {node: '>= 6'} + dependencies: + asynckit: 0.4.0 + combined-stream: 1.0.8 + mime-types: 2.1.35 + dev: false + + /fraction.js@4.3.7: + resolution: {integrity: sha512-ZsDfxO51wGAXREY55a7la9LScWpwv9RxIrYABrlvOFBlH/ShPnrtsXeuUIfXKKOVicNxQ+o8JTbJvjS4M89yew==} + dev: true + + /fs.realpath@1.0.0: + resolution: {integrity: sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==} + dev: true + + /fsevents@2.3.2: + resolution: {integrity: sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==} + engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0} + os: [darwin] + requiresBuild: true + dev: true + optional: true + + /fsevents@2.3.3: + resolution: {integrity: sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==} + engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0} + os: [darwin] + requiresBuild: true + optional: true + + /function-bind@1.1.2: + resolution: {integrity: sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==} + + /gensync@1.0.0-beta.2: + resolution: {integrity: sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==} + engines: {node: '>=6.9.0'} + + /get-caller-file@2.0.5: + resolution: {integrity: sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==} + engines: {node: 6.* || 8.* || >= 10.*} + + /get-nonce@1.0.1: + resolution: {integrity: sha512-FJhYRoDaiatfEkUK8HKlicmu/3SGFD51q3itKDGoSTysQJBnfOcxU5GxnhE1E6soB76MbT0MBtnKJuXyAx+96Q==} + engines: {node: '>=6'} + dev: false + + /get-package-type@0.1.0: + resolution: {integrity: sha512-pjzuKtY64GYfWizNAJ0fr9VqttZkNiK2iS430LtIHzjBEr6bX8Am2zm4sW4Ro5wjWW5cAlRL1qAMTcXbjNAO2Q==} + engines: {node: '>=8.0.0'} + dev: true + + /get-port-please@3.1.2: + resolution: {integrity: sha512-Gxc29eLs1fbn6LQ4jSU4vXjlwyZhF5HsGuMAa7gqBP4Rw4yxxltyDUuF5MBclFzDTXO+ACchGQoeela4DSfzdQ==} + dev: false + + /get-stream@6.0.1: + resolution: {integrity: sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==} + engines: {node: '>=10'} + dev: true + + /get-stream@8.0.1: + resolution: {integrity: sha512-VaUJspBffn/LMCJVoMvSAdmscJyS1auj5Zulnn5UoYcY531UWmdwhRWkcGKnGU93m5HSXP9LP2usOryrBtQowA==} + engines: {node: '>=16'} + dev: false + + /glob-parent@5.1.2: + resolution: {integrity: sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==} + engines: {node: '>= 6'} + dependencies: + is-glob: 4.0.3 + + /glob-parent@6.0.2: + resolution: {integrity: sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==} + engines: {node: '>=10.13.0'} + dependencies: + is-glob: 4.0.3 + + /glob@10.3.10: + resolution: {integrity: sha512-fa46+tv1Ak0UPK1TOy/pZrIybNNt4HCv7SDzwyfiOZkvZLEbjsZkJBPtDHVshZjbecAoAGSC20MjLDG/qr679g==} + engines: {node: '>=16 || 14 >=14.17'} + hasBin: true + dependencies: + foreground-child: 3.1.1 + jackspeak: 2.3.6 + minimatch: 9.0.3 + minipass: 7.0.4 + path-scurry: 1.10.1 + + /glob@7.2.3: + resolution: {integrity: sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==} + dependencies: + fs.realpath: 1.0.0 + inflight: 1.0.6 + inherits: 2.0.4 + minimatch: 3.1.2 + once: 1.4.0 + path-is-absolute: 1.0.1 + dev: true + + /globals@11.12.0: + resolution: {integrity: sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==} + engines: {node: '>=4'} + + /globals@13.24.0: + resolution: {integrity: sha512-AhO5QUcj8llrbG09iWhPU2B204J1xnPeL8kQmVorSsy+Sjj1sk8gIyh6cUocGmH4L0UuhAJy+hJMRA4mgA4mFQ==} + engines: {node: '>=8'} + dependencies: + type-fest: 0.20.2 + dev: true + + /globby@11.1.0: + resolution: {integrity: sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==} + engines: {node: '>=10'} + dependencies: + array-union: 2.1.0 + dir-glob: 3.0.1 + fast-glob: 3.3.2 + ignore: 5.3.1 + merge2: 1.4.1 + slash: 3.0.0 + dev: true + + /goober@2.1.14(csstype@3.1.3): + resolution: {integrity: sha512-4UpC0NdGyAFqLNPnhCT2iHpza2q+RAY3GV85a/mRPdzyPQMsj0KmMMuetdIkzWRbJ+Hgau1EZztq8ImmiMGhsg==} + peerDependencies: + csstype: ^3.0.10 + dependencies: + csstype: 3.1.3 + dev: false + + /graceful-fs@4.2.11: + resolution: {integrity: sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==} + + /graphemer@1.4.0: + resolution: {integrity: sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==} + dev: true + + /h3@1.11.1: + resolution: {integrity: sha512-AbaH6IDnZN6nmbnJOH72y3c5Wwh9P97soSVdGSBbcDACRdkC0FEWf25pzx4f/NuOCK6quHmW18yF2Wx+G4Zi1A==} + dependencies: + cookie-es: 1.0.0 + crossws: 0.2.4 + defu: 6.1.4 + destr: 2.0.3 + iron-webcrypto: 1.1.0 + ohash: 1.1.3 + radix3: 1.1.1 + ufo: 1.5.2 + uncrypto: 0.1.3 + unenv: 1.9.0 + transitivePeerDependencies: + - uWebSockets.js + dev: false + + /has-flag@3.0.0: + resolution: {integrity: sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==} + engines: {node: '>=4'} + + /has-flag@4.0.0: + resolution: {integrity: sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==} + engines: {node: '>=8'} + dev: true + + /hash.js@1.1.7: + resolution: {integrity: sha512-taOaskGt4z4SOANNseOviYDvjEJinIkRgmp7LbKP2YTTmVxWBl87s/uzK9r+44BclBSp2X7K1hqeNfz9JbBeXA==} + dependencies: + inherits: 2.0.4 + minimalistic-assert: 1.0.1 + dev: false + + /hasown@2.0.2: + resolution: {integrity: sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==} + engines: {node: '>= 0.4'} + dependencies: + function-bind: 1.1.2 + + /hey-listen@1.0.8: + resolution: {integrity: sha512-COpmrF2NOg4TBWUJ5UVyaCU2A88wEMkUPK4hNqyCkqHbxT92BbvfjoSozkAIIm6XhicGlJHhFdullInrdhwU8Q==} + dev: false + + /hi-base32@0.5.1: + resolution: {integrity: sha512-EmBBpvdYh/4XxsnUybsPag6VikPYnN30td+vQk+GI3qpahVEG9+gTkG0aXVxTjBqQ5T6ijbWIu77O+C5WFWsnA==} + dev: false + + /html-escaper@2.0.2: + resolution: {integrity: sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==} + dev: true + + /http-shutdown@1.2.2: + resolution: {integrity: sha512-S9wWkJ/VSY9/k4qcjG318bqJNruzE4HySUhFYknwmu6LBP97KLLfwNf+n4V1BHurvFNkSKLFnK/RsuUnRTf9Vw==} + engines: {iojs: '>= 1.0.0', node: '>= 0.12.0'} + dev: false + + /human-signals@2.1.0: + resolution: {integrity: sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==} + engines: {node: '>=10.17.0'} + dev: true + + /human-signals@5.0.0: + resolution: {integrity: sha512-AXcZb6vzzrFAUE61HnN4mpLqd/cSIwNQjtNWR0euPm6y0iqx3G4gOXaIDdtdDwZmhwe82LA6+zinmW4UBWVePQ==} + engines: {node: '>=16.17.0'} + dev: false + + /idb-keyval@6.2.1: + resolution: {integrity: sha512-8Sb3veuYCyrZL+VBt9LJfZjLUPWVvqn8tG28VqYNFCo43KHcKuq+b4EiXGeuaLAQWL2YmyDgMp2aSpH9JHsEQg==} + dev: false + + /ieee754@1.2.1: + resolution: {integrity: sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==} + dev: false + + /ignore@5.3.1: + resolution: {integrity: sha512-5Fytz/IraMjqpwfd34ke28PTVMjZjJG2MPn5t7OE4eUCUNf8BAa7b5WUS9/Qvr6mwOQS7Mk6vdsMno5he+T8Xw==} + engines: {node: '>= 4'} + dev: true + + /import-fresh@3.3.0: + resolution: {integrity: sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==} + engines: {node: '>=6'} + dependencies: + parent-module: 1.0.1 + resolve-from: 4.0.0 + dev: true + + /import-local@3.1.0: + resolution: {integrity: sha512-ASB07uLtnDs1o6EHjKpX34BKYDSqnFerfTOJL2HvMqF70LnxpjkzDB8J44oT9pu4AMPkQwf8jl6szgvNd2tRIg==} + engines: {node: '>=8'} + hasBin: true + dependencies: + pkg-dir: 4.2.0 + resolve-cwd: 3.0.0 + dev: true + + /imurmurhash@0.1.4: + resolution: {integrity: sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==} + engines: {node: '>=0.8.19'} + dev: true + + /inflight@1.0.6: + resolution: {integrity: sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==} + dependencies: + once: 1.4.0 + wrappy: 1.0.2 + dev: true + + /inherits@2.0.4: + resolution: {integrity: sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==} + + /internmap@2.0.3: + resolution: {integrity: sha512-5Hh7Y1wQbvY5ooGgPbDaL5iYLAPzMTUrjMulskHLH6wnv/A+1q5rgEaiuqEjB+oxGXIVZs1FF+R/KPN3ZSQYYg==} + engines: {node: '>=12'} + dev: false + + /invariant@2.2.4: + resolution: {integrity: sha512-phJfQVBuaJM5raOpJjSfkiD6BpbCE4Ns//LaXl6wGYtUBY83nWS6Rf9tXm2e8VaK60JEjYldbPif/A2B1C2gNA==} + dependencies: + loose-envify: 1.4.0 + dev: false + + /iron-webcrypto@1.1.0: + resolution: {integrity: sha512-5vgYsCakNlaQub1orZK5QmNYhwYtcllTkZBp5sfIaCqY93Cf6l+v2rtE+E4TMbcfjxDMCdrO8wmp7+ZvhDECLA==} + dev: false + + /is-arrayish@0.2.1: + resolution: {integrity: sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==} + dev: true + + /is-binary-path@2.1.0: + resolution: {integrity: sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==} + engines: {node: '>=8'} + dependencies: + binary-extensions: 2.3.0 + + /is-core-module@2.13.1: + resolution: {integrity: sha512-hHrIjvZsftOsvKSn2TRYl63zvxsgE0K+0mYMoH6gD4omR5IWB2KynivBQczo3+wF1cCkjzvptnI9Q0sPU66ilw==} + dependencies: + hasown: 2.0.2 + + /is-docker@3.0.0: + resolution: {integrity: sha512-eljcgEDlEns/7AXFosB5K/2nCM4P7FQPkGc/DWLy5rmFEWvZayGrik1d9/QIY5nJ4f9YsVvBkA6kJpHn9rISdQ==} + engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + hasBin: true + dev: false + + /is-extglob@2.1.1: + resolution: {integrity: sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==} + engines: {node: '>=0.10.0'} + + /is-fullwidth-code-point@3.0.0: + resolution: {integrity: sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==} + engines: {node: '>=8'} + + /is-generator-fn@2.1.0: + resolution: {integrity: sha512-cTIB4yPYL/Grw0EaSzASzg6bBy9gqCofvWN8okThAYIxKJZC+udlRAmGbM0XLeniEJSs8uEgHPGuHSe1XsOLSQ==} + engines: {node: '>=6'} + dev: true + + /is-glob@4.0.3: + resolution: {integrity: sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==} + engines: {node: '>=0.10.0'} + dependencies: + is-extglob: 2.1.1 + + /is-inside-container@1.0.0: + resolution: {integrity: sha512-KIYLCCJghfHZxqjYBE7rEy0OBuTd5xCHS7tHVgvCLkx7StIoaxwNW3hCALgEUjFfeRk+MG/Qxmp/vtETEF3tRA==} + engines: {node: '>=14.16'} + hasBin: true + dependencies: + is-docker: 3.0.0 + dev: false + + /is-number@7.0.0: + resolution: {integrity: sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==} + engines: {node: '>=0.12.0'} + + /is-path-inside@3.0.3: + resolution: {integrity: sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==} + engines: {node: '>=8'} + dev: true + + /is-stream@2.0.1: + resolution: {integrity: sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==} + engines: {node: '>=8'} + dev: true + + /is-stream@3.0.0: + resolution: {integrity: sha512-LnQR4bZ9IADDRSkvpqMGvt/tEJWclzklNgSw48V5EAaAeDd6qGvN8ei6k5p0tvxSR171VmGyHuTiAOfxAbr8kA==} + engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + dev: false + + /is-typedarray@1.0.0: + resolution: {integrity: sha512-cyA56iCMHAh5CdzjJIa4aohJyeO1YbwLi3Jc35MmRU6poroFjIGZzUzupGiRPOjgHg9TLu43xbpwXk523fMxKA==} + dev: false + + /is-wsl@3.1.0: + resolution: {integrity: sha512-UcVfVfaK4Sc4m7X3dUSoHoozQGBEFeDC+zVo06t98xe8CzHSZZBekNXH+tu0NalHolcJ/QAGqS46Hef7QXBIMw==} + engines: {node: '>=16'} + dependencies: + is-inside-container: 1.0.0 + dev: false + + /is64bit@2.0.0: + resolution: {integrity: sha512-jv+8jaWCl0g2lSBkNSVXdzfBA0npK1HGC2KtWM9FumFRoGS94g3NbCCLVnCYHLjp4GrW2KZeeSTMo5ddtznmGw==} + engines: {node: '>=18'} + dependencies: + system-architecture: 0.1.0 + dev: false + + /isexe@2.0.0: + resolution: {integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==} + + /istanbul-lib-coverage@3.2.2: + resolution: {integrity: sha512-O8dpsF+r0WV/8MNRKfnmrtCWhuKjxrq2w+jpzBL5UZKTi2LeVWnWOmWRxFlesJONmc+wLAGvKQZEOanko0LFTg==} + engines: {node: '>=8'} + dev: true + + /istanbul-lib-instrument@5.2.1: + resolution: {integrity: sha512-pzqtp31nLv/XFOzXGuvhCb8qhjmTVo5vjVk19XE4CRlSWz0KoeJ3bw9XsA7nOp9YBf4qHjwBxkDzKcME/J29Yg==} + engines: {node: '>=8'} + dependencies: + '@babel/core': 7.24.3 + '@babel/parser': 7.24.1 + '@istanbuljs/schema': 0.1.3 + istanbul-lib-coverage: 3.2.2 + semver: 6.3.1 + transitivePeerDependencies: + - supports-color + dev: true + + /istanbul-lib-instrument@6.0.2: + resolution: {integrity: sha512-1WUsZ9R1lA0HtBSohTkm39WTPlNKSJ5iFk7UwqXkBLoHQT+hfqPsfsTDVuZdKGaBwn7din9bS7SsnoAr943hvw==} + engines: {node: '>=10'} + dependencies: + '@babel/core': 7.24.3 + '@babel/parser': 7.24.1 + '@istanbuljs/schema': 0.1.3 + istanbul-lib-coverage: 3.2.2 + semver: 7.6.0 + transitivePeerDependencies: + - supports-color + dev: true + + /istanbul-lib-report@3.0.1: + resolution: {integrity: sha512-GCfE1mtsHGOELCU8e/Z7YWzpmybrx/+dSTfLrvY8qRmaY6zXTKWn6WQIjaAFw069icm6GVMNkgu0NzI4iPZUNw==} + engines: {node: '>=10'} + dependencies: + istanbul-lib-coverage: 3.2.2 + make-dir: 4.0.0 + supports-color: 7.2.0 + dev: true + + /istanbul-lib-source-maps@4.0.1: + resolution: {integrity: sha512-n3s8EwkdFIJCG3BPKBYvskgXGoy88ARzvegkitk60NxRdwltLOTaH7CUiMRXvwYorl0Q712iEjcWB+fK/MrWVw==} + engines: {node: '>=10'} + dependencies: + debug: 4.3.4 + istanbul-lib-coverage: 3.2.2 + source-map: 0.6.1 + transitivePeerDependencies: + - supports-color + dev: true + + /istanbul-reports@3.1.7: + resolution: {integrity: sha512-BewmUXImeuRk2YY0PVbxgKAysvhRPUQE0h5QRM++nVWyubKGV0l8qQ5op8+B2DOmwSe63Jivj0BjkPQVf8fP5g==} + engines: {node: '>=8'} + dependencies: + html-escaper: 2.0.2 + istanbul-lib-report: 3.0.1 + dev: true + + /jackspeak@2.3.6: + resolution: {integrity: sha512-N3yCS/NegsOBokc8GAdM8UcmfsKiSS8cipheD/nivzr700H+nsMOxJjQnvwOcRYVuFkdH0wGUvW2WbXGmrZGbQ==} + engines: {node: '>=14'} + dependencies: + '@isaacs/cliui': 8.0.2 + optionalDependencies: + '@pkgjs/parseargs': 0.11.0 + + /jest-changed-files@29.7.0: + resolution: {integrity: sha512-fEArFiwf1BpQ+4bXSprcDc3/x4HSzL4al2tozwVpDFpsxALjLYdyiIK4e5Vz66GQJIbXJ82+35PtysofptNX2w==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + dependencies: + execa: 5.1.1 + jest-util: 29.7.0 + p-limit: 3.1.0 + dev: true + + /jest-circus@29.7.0: + resolution: {integrity: sha512-3E1nCMgipcTkCocFwM90XXQab9bS+GMsjdpmPrlelaxwD93Ad8iVEjX/vvHPdLPnFf+L40u+5+iutRdA1N9myw==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + dependencies: + '@jest/environment': 29.7.0 + '@jest/expect': 29.7.0 + '@jest/test-result': 29.7.0 + '@jest/types': 29.6.3 + '@types/node': 18.19.28 + chalk: 4.1.2 + co: 4.6.0 + dedent: 1.5.1 + is-generator-fn: 2.1.0 + jest-each: 29.7.0 + jest-matcher-utils: 29.7.0 + jest-message-util: 29.7.0 + jest-runtime: 29.7.0 + jest-snapshot: 29.7.0 + jest-util: 29.7.0 + p-limit: 3.1.0 + pretty-format: 29.7.0 + pure-rand: 6.1.0 + slash: 3.0.0 + stack-utils: 2.0.6 + transitivePeerDependencies: + - babel-plugin-macros + - supports-color + dev: true + + /jest-cli@29.7.0(@types/node@18.19.26)(ts-node@10.9.2): + resolution: {integrity: sha512-OVVobw2IubN/GSYsxETi+gOe7Ka59EFMR/twOU3Jb2GnKKeMGJB5SGUUrEz3SFVmJASUdZUzy83sLNNQ2gZslg==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + hasBin: true + peerDependencies: + node-notifier: ^8.0.1 || ^9.0.0 || ^10.0.0 + peerDependenciesMeta: + node-notifier: + optional: true + dependencies: + '@jest/core': 29.7.0(ts-node@10.9.2) + '@jest/test-result': 29.7.0 + '@jest/types': 29.6.3 + chalk: 4.1.2 + create-jest: 29.7.0(@types/node@18.19.26)(ts-node@10.9.2) + exit: 0.1.2 + import-local: 3.1.0 + jest-config: 29.7.0(@types/node@18.19.26)(ts-node@10.9.2) + jest-util: 29.7.0 + jest-validate: 29.7.0 + yargs: 17.7.2 + transitivePeerDependencies: + - '@types/node' + - babel-plugin-macros + - supports-color + - ts-node + dev: true + + /jest-config@29.7.0(@types/node@18.19.26)(ts-node@10.9.2): + resolution: {integrity: sha512-uXbpfeQ7R6TZBqI3/TxCU4q4ttk3u0PJeC+E0zbfSoSjq6bJ7buBPxzQPL0ifrkY4DNu4JUdk0ImlBUYi840eQ==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + peerDependencies: + '@types/node': '*' + ts-node: '>=9.0.0' + peerDependenciesMeta: + '@types/node': + optional: true + ts-node: + optional: true + dependencies: + '@babel/core': 7.24.3 + '@jest/test-sequencer': 29.7.0 + '@jest/types': 29.6.3 + '@types/node': 18.19.26 + babel-jest: 29.7.0(@babel/core@7.24.3) + chalk: 4.1.2 + ci-info: 3.9.0 + deepmerge: 4.3.1 + glob: 7.2.3 + graceful-fs: 4.2.11 + jest-circus: 29.7.0 + jest-environment-node: 29.7.0 + jest-get-type: 29.6.3 + jest-regex-util: 29.6.3 + jest-resolve: 29.7.0 + jest-runner: 29.7.0 + jest-util: 29.7.0 + jest-validate: 29.7.0 + micromatch: 4.0.5 + parse-json: 5.2.0 + pretty-format: 29.7.0 + slash: 3.0.0 + strip-json-comments: 3.1.1 + ts-node: 10.9.2(@types/node@18.19.26)(typescript@5.4.2) + transitivePeerDependencies: + - babel-plugin-macros + - supports-color + dev: true + + /jest-config@29.7.0(@types/node@18.19.28)(ts-node@10.9.2): + resolution: {integrity: sha512-uXbpfeQ7R6TZBqI3/TxCU4q4ttk3u0PJeC+E0zbfSoSjq6bJ7buBPxzQPL0ifrkY4DNu4JUdk0ImlBUYi840eQ==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + peerDependencies: + '@types/node': '*' + ts-node: '>=9.0.0' + peerDependenciesMeta: + '@types/node': + optional: true + ts-node: + optional: true + dependencies: + '@babel/core': 7.24.3 + '@jest/test-sequencer': 29.7.0 + '@jest/types': 29.6.3 + '@types/node': 18.19.28 + babel-jest: 29.7.0(@babel/core@7.24.3) + chalk: 4.1.2 + ci-info: 3.9.0 + deepmerge: 4.3.1 + glob: 7.2.3 + graceful-fs: 4.2.11 + jest-circus: 29.7.0 + jest-environment-node: 29.7.0 + jest-get-type: 29.6.3 + jest-regex-util: 29.6.3 + jest-resolve: 29.7.0 + jest-runner: 29.7.0 + jest-util: 29.7.0 + jest-validate: 29.7.0 + micromatch: 4.0.5 + parse-json: 5.2.0 + pretty-format: 29.7.0 + slash: 3.0.0 + strip-json-comments: 3.1.1 + ts-node: 10.9.2(@types/node@18.19.26)(typescript@5.4.2) + transitivePeerDependencies: + - babel-plugin-macros + - supports-color + dev: true + + /jest-diff@29.7.0: + resolution: {integrity: sha512-LMIgiIrhigmPrs03JHpxUh2yISK3vLFPkAodPeo0+BuF7wA2FoQbkEg1u8gBYBThncu7e1oEDUfIXVuTqLRUjw==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + dependencies: + chalk: 4.1.2 + diff-sequences: 29.6.3 + jest-get-type: 29.6.3 + pretty-format: 29.7.0 + dev: true + + /jest-docblock@29.7.0: + resolution: {integrity: sha512-q617Auw3A612guyaFgsbFeYpNP5t2aoUNLwBUbc/0kD1R4t9ixDbyFTHd1nok4epoVFpr7PmeWHrhvuV3XaJ4g==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + dependencies: + detect-newline: 3.1.0 + dev: true + + /jest-each@29.7.0: + resolution: {integrity: sha512-gns+Er14+ZrEoC5fhOfYCY1LOHHr0TI+rQUHZS8Ttw2l7gl+80eHc/gFf2Ktkw0+SIACDTeWvpFcv3B04VembQ==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + dependencies: + '@jest/types': 29.6.3 + chalk: 4.1.2 + jest-get-type: 29.6.3 + jest-util: 29.7.0 + pretty-format: 29.7.0 + dev: true + + /jest-environment-node@29.7.0: + resolution: {integrity: sha512-DOSwCRqXirTOyheM+4d5YZOrWcdu0LNZ87ewUoywbcb2XR4wKgqiG8vNeYwhjFMbEkfju7wx2GYH0P2gevGvFw==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + dependencies: + '@jest/environment': 29.7.0 + '@jest/fake-timers': 29.7.0 + '@jest/types': 29.6.3 + '@types/node': 18.19.28 + jest-mock: 29.7.0 + jest-util: 29.7.0 + dev: true + + /jest-get-type@29.6.3: + resolution: {integrity: sha512-zrteXnqYxfQh7l5FHyL38jL39di8H8rHoecLH3JNxH3BwOrBsNeabdap5e0I23lD4HHI8W5VFBZqG4Eaq5LNcw==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + dev: true + + /jest-haste-map@29.7.0: + resolution: {integrity: sha512-fP8u2pyfqx0K1rGn1R9pyE0/KTn+G7PxktWidOBTqFPLYX0b9ksaMFkhK5vrS3DVun09pckLdlx90QthlW7AmA==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + dependencies: + '@jest/types': 29.6.3 + '@types/graceful-fs': 4.1.9 + '@types/node': 18.19.28 + anymatch: 3.1.3 + fb-watchman: 2.0.2 + graceful-fs: 4.2.11 + jest-regex-util: 29.6.3 + jest-util: 29.7.0 + jest-worker: 29.7.0 + micromatch: 4.0.5 + walker: 1.0.8 + optionalDependencies: + fsevents: 2.3.3 + dev: true + + /jest-leak-detector@29.7.0: + resolution: {integrity: sha512-kYA8IJcSYtST2BY9I+SMC32nDpBT3J2NvWJx8+JCuCdl/CR1I4EKUJROiP8XtCcxqgTTBGJNdbB1A8XRKbTetw==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + dependencies: + jest-get-type: 29.6.3 + pretty-format: 29.7.0 + dev: true + + /jest-matcher-utils@29.7.0: + resolution: {integrity: sha512-sBkD+Xi9DtcChsI3L3u0+N0opgPYnCRPtGcQYrgXmR+hmt/fYfWAL0xRXYU8eWOdfuLgBe0YCW3AFtnRLagq/g==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + dependencies: + chalk: 4.1.2 + jest-diff: 29.7.0 + jest-get-type: 29.6.3 + pretty-format: 29.7.0 + dev: true + + /jest-message-util@29.7.0: + resolution: {integrity: sha512-GBEV4GRADeP+qtB2+6u61stea8mGcOT4mCtrYISZwfu9/ISHFJ/5zOMXYbpBE9RsS5+Gb63DW4FgmnKJ79Kf6w==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + dependencies: + '@babel/code-frame': 7.24.2 + '@jest/types': 29.6.3 + '@types/stack-utils': 2.0.3 + chalk: 4.1.2 + graceful-fs: 4.2.11 + micromatch: 4.0.5 + pretty-format: 29.7.0 + slash: 3.0.0 + stack-utils: 2.0.6 + dev: true + + /jest-mock@29.7.0: + resolution: {integrity: sha512-ITOMZn+UkYS4ZFh83xYAOzWStloNzJFO2s8DWrE4lhtGD+AorgnbkiKERe4wQVBydIGPx059g6riW5Btp6Llnw==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + dependencies: + '@jest/types': 29.6.3 + '@types/node': 18.19.28 + jest-util: 29.7.0 + dev: true + + /jest-pnp-resolver@1.2.3(jest-resolve@29.7.0): + resolution: {integrity: sha512-+3NpwQEnRoIBtx4fyhblQDPgJI0H1IEIkX7ShLUjPGA7TtUTvI1oiKi3SR4oBR0hQhQR80l4WAe5RrXBwWMA8w==} + engines: {node: '>=6'} + peerDependencies: + jest-resolve: '*' + peerDependenciesMeta: + jest-resolve: + optional: true + dependencies: + jest-resolve: 29.7.0 + dev: true + + /jest-regex-util@29.6.3: + resolution: {integrity: sha512-KJJBsRCyyLNWCNBOvZyRDnAIfUiRJ8v+hOBQYGn8gDyF3UegwiP4gwRR3/SDa42g1YbVycTidUF3rKjyLFDWbg==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + dev: true + + /jest-resolve-dependencies@29.7.0: + resolution: {integrity: sha512-un0zD/6qxJ+S0et7WxeI3H5XSe9lTBBR7bOHCHXkKR6luG5mwDDlIzVQ0V5cZCuoTgEdcdwzTghYkTWfubi+nA==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + dependencies: + jest-regex-util: 29.6.3 + jest-snapshot: 29.7.0 + transitivePeerDependencies: + - supports-color + dev: true + + /jest-resolve@29.7.0: + resolution: {integrity: sha512-IOVhZSrg+UvVAshDSDtHyFCCBUl/Q3AAJv8iZ6ZjnZ74xzvwuzLXid9IIIPgTnY62SJjfuupMKZsZQRsCvxEgA==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + dependencies: + chalk: 4.1.2 + graceful-fs: 4.2.11 + jest-haste-map: 29.7.0 + jest-pnp-resolver: 1.2.3(jest-resolve@29.7.0) + jest-util: 29.7.0 + jest-validate: 29.7.0 + resolve: 1.22.8 + resolve.exports: 2.0.2 + slash: 3.0.0 + dev: true + + /jest-runner@29.7.0: + resolution: {integrity: sha512-fsc4N6cPCAahybGBfTRcq5wFR6fpLznMg47sY5aDpsoejOcVYFb07AHuSnR0liMcPTgBsA3ZJL6kFOjPdoNipQ==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + dependencies: + '@jest/console': 29.7.0 + '@jest/environment': 29.7.0 + '@jest/test-result': 29.7.0 + '@jest/transform': 29.7.0 + '@jest/types': 29.6.3 + '@types/node': 18.19.28 + chalk: 4.1.2 + emittery: 0.13.1 + graceful-fs: 4.2.11 + jest-docblock: 29.7.0 + jest-environment-node: 29.7.0 + jest-haste-map: 29.7.0 + jest-leak-detector: 29.7.0 + jest-message-util: 29.7.0 + jest-resolve: 29.7.0 + jest-runtime: 29.7.0 + jest-util: 29.7.0 + jest-watcher: 29.7.0 + jest-worker: 29.7.0 + p-limit: 3.1.0 + source-map-support: 0.5.13 + transitivePeerDependencies: + - supports-color + dev: true + + /jest-runtime@29.7.0: + resolution: {integrity: sha512-gUnLjgwdGqW7B4LvOIkbKs9WGbn+QLqRQQ9juC6HndeDiezIwhDP+mhMwHWCEcfQ5RUXa6OPnFF8BJh5xegwwQ==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + dependencies: + '@jest/environment': 29.7.0 + '@jest/fake-timers': 29.7.0 + '@jest/globals': 29.7.0 + '@jest/source-map': 29.6.3 + '@jest/test-result': 29.7.0 + '@jest/transform': 29.7.0 + '@jest/types': 29.6.3 + '@types/node': 18.19.28 + chalk: 4.1.2 + cjs-module-lexer: 1.2.3 + collect-v8-coverage: 1.0.2 + glob: 7.2.3 + graceful-fs: 4.2.11 + jest-haste-map: 29.7.0 + jest-message-util: 29.7.0 + jest-mock: 29.7.0 + jest-regex-util: 29.6.3 + jest-resolve: 29.7.0 + jest-snapshot: 29.7.0 + jest-util: 29.7.0 + slash: 3.0.0 + strip-bom: 4.0.0 + transitivePeerDependencies: + - supports-color + dev: true + + /jest-snapshot@29.7.0: + resolution: {integrity: sha512-Rm0BMWtxBcioHr1/OX5YCP8Uov4riHvKPknOGs804Zg9JGZgmIBkbtlxJC/7Z4msKYVbIJtfU+tKb8xlYNfdkw==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + dependencies: + '@babel/core': 7.24.3 + '@babel/generator': 7.24.1 + '@babel/plugin-syntax-jsx': 7.24.1(@babel/core@7.24.3) + '@babel/plugin-syntax-typescript': 7.24.1(@babel/core@7.24.3) + '@babel/types': 7.24.0 + '@jest/expect-utils': 29.7.0 + '@jest/transform': 29.7.0 + '@jest/types': 29.6.3 + babel-preset-current-node-syntax: 1.0.1(@babel/core@7.24.3) + chalk: 4.1.2 + expect: 29.7.0 + graceful-fs: 4.2.11 + jest-diff: 29.7.0 + jest-get-type: 29.6.3 + jest-matcher-utils: 29.7.0 + jest-message-util: 29.7.0 + jest-util: 29.7.0 + natural-compare: 1.4.0 + pretty-format: 29.7.0 + semver: 7.6.0 + transitivePeerDependencies: + - supports-color + dev: true + + /jest-util@29.7.0: + resolution: {integrity: sha512-z6EbKajIpqGKU56y5KBUgy1dt1ihhQJgWzUlZHArA/+X2ad7Cb5iF+AK1EWVL/Bo7Rz9uurpqw6SiBCefUbCGA==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + dependencies: + '@jest/types': 29.6.3 + '@types/node': 18.19.26 + chalk: 4.1.2 + ci-info: 3.9.0 + graceful-fs: 4.2.11 + picomatch: 2.3.1 + dev: true + + /jest-validate@29.7.0: + resolution: {integrity: sha512-ZB7wHqaRGVw/9hST/OuFUReG7M8vKeq0/J2egIGLdvjHCmYqGARhzXmtgi+gVeZ5uXFF219aOc3Ls2yLg27tkw==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + dependencies: + '@jest/types': 29.6.3 + camelcase: 6.3.0 + chalk: 4.1.2 + jest-get-type: 29.6.3 + leven: 3.1.0 + pretty-format: 29.7.0 + dev: true + + /jest-watcher@29.7.0: + resolution: {integrity: sha512-49Fg7WXkU3Vl2h6LbLtMQ/HyB6rXSIX7SqvBLQmssRBGN9I0PNvPmAmCWSOY6SOvrjhI/F7/bGAv9RtnsPA03g==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + dependencies: + '@jest/test-result': 29.7.0 + '@jest/types': 29.6.3 + '@types/node': 18.19.28 + ansi-escapes: 4.3.2 + chalk: 4.1.2 + emittery: 0.13.1 + jest-util: 29.7.0 + string-length: 4.0.2 + dev: true + + /jest-worker@29.7.0: + resolution: {integrity: sha512-eIz2msL/EzL9UFTFFx7jBTkeZfku0yUAyZZZmJ93H2TYEiroIx2PQjEXcwYtYl8zXCxb+PAmA2hLIt/6ZEkPHw==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + dependencies: + '@types/node': 18.19.28 + jest-util: 29.7.0 + merge-stream: 2.0.0 + supports-color: 8.1.1 + dev: true + + /jest@29.7.0(@types/node@18.19.26)(ts-node@10.9.2): + resolution: {integrity: sha512-NIy3oAFp9shda19hy4HK0HRTWKtPJmGdnvywu01nOqNC2vZg+Z+fvJDxpMQA88eb2I9EcafcdjYgsDthnYTvGw==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + hasBin: true + peerDependencies: + node-notifier: ^8.0.1 || ^9.0.0 || ^10.0.0 + peerDependenciesMeta: + node-notifier: + optional: true + dependencies: + '@jest/core': 29.7.0(ts-node@10.9.2) + '@jest/types': 29.6.3 + import-local: 3.1.0 + jest-cli: 29.7.0(@types/node@18.19.26)(ts-node@10.9.2) + transitivePeerDependencies: + - '@types/node' + - babel-plugin-macros + - supports-color + - ts-node + dev: true + + /jiti@1.21.0: + resolution: {integrity: sha512-gFqAIbuKyyso/3G2qhiO2OM6shY6EPP/R0+mkDbyspxKazh8BXDC5FiFsUjlczgdNz/vfra0da2y+aHrusLG/Q==} + hasBin: true + + /js-sha256@0.9.0: + resolution: {integrity: sha512-sga3MHh9sgQN2+pJ9VYZ+1LPwXOxuBJBA5nrR5/ofPfuiJBE2hnjsaN8se8JznOmGLN2p49Pe5U/ttafcs/apA==} + dev: false + + /js-sha3@0.8.0: + resolution: {integrity: sha512-gF1cRrHhIzNfToc802P800N8PpXS+evLLXfsVpowqmAFR9uwbi89WvXg2QspOmXL8QL86J4T1EpFu+yUkwJY3Q==} + dev: false + + /js-sha512@0.8.0: + resolution: {integrity: sha512-PWsmefG6Jkodqt+ePTvBZCSMFgN7Clckjd0O7su3I0+BW2QWUTJNzjktHsztGLhncP2h8mcF9V9Y2Ha59pAViQ==} + dev: false + + /js-tokens@4.0.0: + resolution: {integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==} + + /js-yaml@3.14.1: + resolution: {integrity: sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==} + hasBin: true + dependencies: + argparse: 1.0.10 + esprima: 4.0.1 + dev: true + + /js-yaml@4.1.0: + resolution: {integrity: sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==} + hasBin: true + dependencies: + argparse: 2.0.1 + dev: true + + /jsesc@2.5.2: + resolution: {integrity: sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==} + engines: {node: '>=4'} + hasBin: true + + /json-bigint@1.0.0: + resolution: {integrity: sha512-SiPv/8VpZuWbvLSMtTDU8hEfrZWg/mH/nV/b4o0CYbSxu1UIQPLdwKOCIyLQX+VIPO5vrLX3i8qtqFyhdPSUSQ==} + dependencies: + bignumber.js: 9.1.2 + dev: false + + /json-buffer@3.0.1: + resolution: {integrity: sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==} + dev: true + + /json-parse-even-better-errors@2.3.1: + resolution: {integrity: sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==} + dev: true + + /json-schema-traverse@0.4.1: + resolution: {integrity: sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==} + dev: true + + /json-stable-stringify-without-jsonify@1.0.1: + resolution: {integrity: sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==} + dev: true + + /json5@2.2.3: + resolution: {integrity: sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==} + engines: {node: '>=6'} + hasBin: true + + /jsonc-parser@3.2.1: + resolution: {integrity: sha512-AilxAyFOAcK5wA1+LeaySVBrHsGQvUFCDWXKpZjzaL0PqW+xfBOttn8GNtWKFWqneyMZj41MWF9Kl6iPWLwgOA==} + dev: false + + /keyv@4.5.4: + resolution: {integrity: sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==} + dependencies: + json-buffer: 3.0.1 + dev: true + + /keyvaluestorage-interface@1.0.0: + resolution: {integrity: sha512-8t6Q3TclQ4uZynJY9IGr2+SsIGwK9JHcO6ootkHCGA0CrQCRy+VkouYNO2xicET6b9al7QKzpebNow+gkpCL8g==} + dev: false + + /kleur@3.0.3: + resolution: {integrity: sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w==} + engines: {node: '>=6'} + dev: true + + /leven@3.1.0: + resolution: {integrity: sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A==} + engines: {node: '>=6'} + dev: true + + /levn@0.4.1: + resolution: {integrity: sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==} + engines: {node: '>= 0.8.0'} + dependencies: + prelude-ls: 1.2.1 + type-check: 0.4.0 + dev: true + + /lilconfig@2.1.0: + resolution: {integrity: sha512-utWOt/GHzuUxnLKxB6dk81RoOeoNeHgbrXiuGk4yyF5qlRz+iIVWu56E2fqGHFrXz0QNUhLB/8nKqvRH66JKGQ==} + engines: {node: '>=10'} + + /lilconfig@3.1.1: + resolution: {integrity: sha512-O18pf7nyvHTckunPWCV1XUNXU1piu01y2b7ATJ0ppkUkk8ocqVWBrYjJBCwHDjD/ZWcfyrA0P4gKhzWGi5EINQ==} + engines: {node: '>=14'} + + /lines-and-columns@1.2.4: + resolution: {integrity: sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==} + + /listhen@1.7.2: + resolution: {integrity: sha512-7/HamOm5YD9Wb7CFgAZkKgVPA96WwhcTQoqtm2VTZGVbVVn3IWKRBTgrU7cchA3Q8k9iCsG8Osoi9GX4JsGM9g==} + hasBin: true + dependencies: + '@parcel/watcher': 2.4.1 + '@parcel/watcher-wasm': 2.4.1 + citty: 0.1.6 + clipboardy: 4.0.0 + consola: 3.2.3 + crossws: 0.2.4 + defu: 6.1.4 + get-port-please: 3.1.2 + h3: 1.11.1 + http-shutdown: 1.2.2 + jiti: 1.21.0 + mlly: 1.6.1 + node-forge: 1.3.1 + pathe: 1.1.2 + std-env: 3.7.0 + ufo: 1.5.2 + untun: 0.1.3 + uqr: 0.1.2 + transitivePeerDependencies: + - uWebSockets.js + dev: false + + /lit-element@3.3.3: + resolution: {integrity: sha512-XbeRxmTHubXENkV4h8RIPyr8lXc+Ff28rkcQzw3G6up2xg5E8Zu1IgOWIwBLEQsu3cOVFqdYwiVi0hv0SlpqUA==} + dependencies: + '@lit-labs/ssr-dom-shim': 1.2.0 + '@lit/reactive-element': 1.6.3 + lit-html: 2.8.0 + dev: false + + /lit-html@2.8.0: + resolution: {integrity: sha512-o9t+MQM3P4y7M7yNzqAyjp7z+mQGa4NS4CxiyLqFPyFWyc4O+nodLrkrxSaCTrla6M5YOLaT3RpbbqjszB5g3Q==} + dependencies: + '@types/trusted-types': 2.0.7 + dev: false + + /lit@2.8.0: + resolution: {integrity: sha512-4Sc3OFX9QHOJaHbmTMk28SYgVxLN3ePDjg7hofEft2zWlehFL3LiAuapWc4U/kYwMYJSh2hTCPZ6/LIC7ii0MA==} + dependencies: + '@lit/reactive-element': 1.6.3 + lit-element: 3.3.3 + lit-html: 2.8.0 + dev: false + + /locate-path@5.0.0: + resolution: {integrity: sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==} + engines: {node: '>=8'} + dependencies: + p-locate: 4.1.0 + + /locate-path@6.0.0: + resolution: {integrity: sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==} + engines: {node: '>=10'} + dependencies: + p-locate: 5.0.0 + dev: true + + /lodash.isequal@4.5.0: + resolution: {integrity: sha512-pDo3lu8Jhfjqls6GkMgpahsF9kCyayhgykjyLMNFTKWrpVdAQtYyB4muAMWozBB4ig/dtWAmsMxLEI8wuz+DYQ==} + dev: false + + /lodash.memoize@4.1.2: + resolution: {integrity: sha512-t7j+NzmgnQzTAYXcsHYLgimltOV1MXHtlOWf6GjL9Kj8GK5FInw5JotxvbOs+IvV1/Dzo04/fCGfLVs7aXb4Ag==} + dev: true + + /lodash.merge@4.6.2: + resolution: {integrity: sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==} + dev: true + + /lodash@4.17.21: + resolution: {integrity: sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==} + dev: false + + /loose-envify@1.4.0: + resolution: {integrity: sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==} + hasBin: true + dependencies: + js-tokens: 4.0.0 + dev: false + + /lottie-web@5.12.2: + resolution: {integrity: sha512-uvhvYPC8kGPjXT3MyKMrL3JitEAmDMp30lVkuq/590Mw9ok6pWcFCwXJveo0t5uqYw1UREQHofD+jVpdjBv8wg==} + dev: false + + /lru-cache@10.2.0: + resolution: {integrity: sha512-2bIM8x+VAf6JT4bKAljS1qUWgMsqZRPGJS6FSahIMPVvctcNhyVp7AJu7quxOW9jwkryBReKZY5tY5JYv2n/7Q==} + engines: {node: 14 || >=16.14} + + /lru-cache@5.1.1: + resolution: {integrity: sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==} + dependencies: + yallist: 3.1.1 + + /lru-cache@6.0.0: + resolution: {integrity: sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==} + engines: {node: '>=10'} + dependencies: + yallist: 4.0.0 + dev: true + + /lucide-react@0.363.0(react@18.2.0): + resolution: {integrity: sha512-AlsfPCsXQyQx7wwsIgzcKOL9LwC498LIMAo+c0Es5PkHJa33xwmYAkkSoKoJWWWSYQEStqu58/jT4tL2gi32uQ==} + peerDependencies: + react: ^16.5.1 || ^17.0.0 || ^18.0.0 + dependencies: + react: 18.2.0 + dev: false + + /make-dir@4.0.0: + resolution: {integrity: sha512-hXdUTZYIVOt1Ex//jAQi+wTZZpUpwBj/0QsOzqegb3rGMMeJiSEu5xLHnYfBrRV4RH2+OCSOO95Is/7x1WJ4bw==} + engines: {node: '>=10'} + dependencies: + semver: 7.6.0 + dev: true + + /make-error@1.3.6: + resolution: {integrity: sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==} + + /makeerror@1.0.12: + resolution: {integrity: sha512-JmqCvUhmt43madlpFzG4BQzG2Z3m6tvQDNKdClZnO3VbIudJYmxsT0FNJMeiB2+JTSlTQTSbU8QdesVmwJcmLg==} + dependencies: + tmpl: 1.0.5 + dev: true + + /merge-stream@2.0.0: + resolution: {integrity: sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==} + + /merge2@1.4.1: + resolution: {integrity: sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==} + engines: {node: '>= 8'} + + /micromatch@4.0.5: + resolution: {integrity: sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==} + engines: {node: '>=8.6'} + dependencies: + braces: 3.0.2 + picomatch: 2.3.1 + + /mime-db@1.52.0: + resolution: {integrity: sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==} + engines: {node: '>= 0.6'} + dev: false + + /mime-types@2.1.35: + resolution: {integrity: sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==} + engines: {node: '>= 0.6'} + dependencies: + mime-db: 1.52.0 + dev: false + + /mime@3.0.0: + resolution: {integrity: sha512-jSCU7/VB1loIWBZe14aEYHU/+1UMEHoaO7qxCOVJOw9GgH72VAWppxNcjU+x9a2k3GSIBXNKxXQFqRvvZ7vr3A==} + engines: {node: '>=10.0.0'} + hasBin: true + dev: false + + /mimic-fn@2.1.0: + resolution: {integrity: sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==} + engines: {node: '>=6'} + dev: true + + /mimic-fn@4.0.0: + resolution: {integrity: sha512-vqiC06CuhBTUdZH+RYl8sFrL096vA45Ok5ISO6sE/Mr1jRbGH4Csnhi8f3wKVl7x8mO4Au7Ir9D3Oyv1VYMFJw==} + engines: {node: '>=12'} + dev: false + + /minimalistic-assert@1.0.1: + resolution: {integrity: sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A==} + dev: false + + /minimatch@3.1.2: + resolution: {integrity: sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==} + dependencies: + brace-expansion: 1.1.11 + dev: true + + /minimatch@9.0.3: + resolution: {integrity: sha512-RHiac9mvaRw0x3AYRgDC1CxAP7HTcNrrECeA8YYJeWnpo+2Q5CegtZjaotWTWxDG3UeGA1coE05iH1mPjT/2mg==} + engines: {node: '>=16 || 14 >=14.17'} + dependencies: + brace-expansion: 2.0.1 + + /minipass@7.0.4: + resolution: {integrity: sha512-jYofLM5Dam9279rdkWzqHozUo4ybjdZmCsDHePy5V/PbBcVMiSZR97gmAy45aqi8CK1lG2ECd356FU86avfwUQ==} + engines: {node: '>=16 || 14 >=14.17'} + + /mlly@1.6.1: + resolution: {integrity: sha512-vLgaHvaeunuOXHSmEbZ9izxPx3USsk8KCQ8iC+aTlp5sKRSoZvwhHh5L9VbKSaVC6sJDqbyohIS76E2VmHIPAA==} + dependencies: + acorn: 8.11.3 + pathe: 1.1.2 + pkg-types: 1.0.3 + ufo: 1.5.2 + dev: false + + /motion@10.16.2: + resolution: {integrity: sha512-p+PurYqfUdcJZvtnmAqu5fJgV2kR0uLFQuBKtLeFVTrYEVllI99tiOTSefVNYuip9ELTEkepIIDftNdze76NAQ==} + dependencies: + '@motionone/animation': 10.17.0 + '@motionone/dom': 10.17.0 + '@motionone/svelte': 10.16.4 + '@motionone/types': 10.17.0 + '@motionone/utils': 10.17.0 + '@motionone/vue': 10.16.4 + dev: false + + /mri@1.2.0: + resolution: {integrity: sha512-tzzskb3bG8LvYGFF/mDTpq3jpI6Q9wc3LEmBaghu+DdCssd1FakN7Bc0hVNmEyGq1bq3RgfkCb3cmQLpNPOroA==} + engines: {node: '>=4'} + dev: false + + /ms@2.1.2: + resolution: {integrity: sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==} + + /multiformats@9.9.0: + resolution: {integrity: sha512-HoMUjhH9T8DDBNT+6xzkrd9ga/XiBI4xLr58LJACwK6G3HTOPeMz4nB4KJs33L2BelrIJa7P0VuNaVF3hMYfjg==} + dev: false + + /mz@2.7.0: + resolution: {integrity: sha512-z81GNO7nnYMEhrGh9LeymoE4+Yr0Wn5McHIZMK5cfQCl+NDX08sCZgUc9/6MHni9IWuFLm1Z3HTCXu2z9fN62Q==} + dependencies: + any-promise: 1.3.0 + object-assign: 4.1.1 + thenify-all: 1.6.0 + + /nanoid@3.3.7: + resolution: {integrity: sha512-eSRppjcPIatRIMC1U6UngP8XFcz8MQWGQdt1MTBQ7NaAmvXDfvNxbvWV3x2y6CdEUciCSsDHDQZbhYaB8QEo2g==} + engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1} + hasBin: true + + /natural-compare@1.4.0: + resolution: {integrity: sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==} + dev: true + + /next-themes@0.2.1(next@14.1.4)(react-dom@18.2.0)(react@18.2.0): + resolution: {integrity: sha512-B+AKNfYNIzh0vqQQKqQItTS8evEouKD7H5Hj3kmuPERwddR2TxvDSFZuTj6T7Jfn1oyeUyJMydPl1Bkxkh0W7A==} + peerDependencies: + next: '*' + react: '*' + react-dom: '*' + dependencies: + next: 14.1.4(@babel/core@7.24.1)(react-dom@18.2.0)(react@18.2.0) + react: 18.2.0 + react-dom: 18.2.0(react@18.2.0) + dev: false + + /next@14.1.4(@babel/core@7.24.1)(react-dom@18.2.0)(react@18.2.0): + resolution: {integrity: sha512-1WTaXeSrUwlz/XcnhGTY7+8eiaFvdet5z9u3V2jb+Ek1vFo0VhHKSAIJvDWfQpttWjnyw14kBeq28TPq7bTeEQ==} + engines: {node: '>=18.17.0'} + hasBin: true + peerDependencies: + '@opentelemetry/api': ^1.1.0 + react: ^18.2.0 + react-dom: ^18.2.0 + sass: ^1.3.0 + peerDependenciesMeta: + '@opentelemetry/api': + optional: true + sass: + optional: true + dependencies: + '@next/env': 14.1.4 + '@swc/helpers': 0.5.2 + busboy: 1.6.0 + caniuse-lite: 1.0.30001605 + graceful-fs: 4.2.11 + postcss: 8.4.31 + react: 18.2.0 + react-dom: 18.2.0(react@18.2.0) + styled-jsx: 5.1.1(@babel/core@7.24.1)(react@18.2.0) + optionalDependencies: + '@next/swc-darwin-arm64': 14.1.4 + '@next/swc-darwin-x64': 14.1.4 + '@next/swc-linux-arm64-gnu': 14.1.4 + '@next/swc-linux-arm64-musl': 14.1.4 + '@next/swc-linux-x64-gnu': 14.1.4 + '@next/swc-linux-x64-musl': 14.1.4 + '@next/swc-win32-arm64-msvc': 14.1.4 + '@next/swc-win32-ia32-msvc': 14.1.4 + '@next/swc-win32-x64-msvc': 14.1.4 + transitivePeerDependencies: + - '@babel/core' + - babel-plugin-macros + dev: false + + /node-addon-api@7.1.0: + resolution: {integrity: sha512-mNcltoe1R8o7STTegSOHdnJNN7s5EUvhoS7ShnTHDyOSd+8H+UdWODq6qSv67PjC8Zc5JRT8+oLAMCr0SIXw7g==} + engines: {node: ^16 || ^18 || >= 20} + dev: false + + /node-fetch-native@1.6.2: + resolution: {integrity: sha512-69mtXOFZ6hSkYiXAVB5SqaRvrbITC/NPyqv7yuu/qw0nmgPyYbIMYYNIDhNtwPrzk0ptrimrLz/hhjvm4w5Z+w==} + dev: false + + /node-forge@1.3.1: + resolution: {integrity: sha512-dPEtOeMvF9VMcYV/1Wb8CPoVAXtp6MKMlcbAt4ddqmGqUJ6fQZFXkNZNkNlfevtNkGtaSoXf/vNNNSvgrdXwtA==} + engines: {node: '>= 6.13.0'} + dev: false + + /node-int64@0.4.0: + resolution: {integrity: sha512-O5lz91xSOeoXP6DulyHfllpq+Eg00MWitZIbtPfoSEvqIHdl5gfcY6hYzDWnj0qD5tz52PI08u9qUvSVeUBeHw==} + dev: true + + /node-releases@2.0.14: + resolution: {integrity: sha512-y10wOWt8yZpqXmOgRo77WaHEmhYQYGNA6y421PKsKYWEK8aW+cqAphborZDhqfyKrbZEN92CN1X2KbafY2s7Yw==} + + /normalize-path@3.0.0: + resolution: {integrity: sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==} + engines: {node: '>=0.10.0'} + + /normalize-range@0.1.2: + resolution: {integrity: sha512-bdok/XvKII3nUpklnV6P2hxtMNrCboOjAcyBuQnWEhO665FwrSNRxU+AqpsyvO6LgGYPspN+lu5CLtw4jPRKNA==} + engines: {node: '>=0.10.0'} + dev: true + + /notistack@3.0.1(csstype@3.1.3)(react-dom@18.2.0)(react@18.2.0): + resolution: {integrity: sha512-ntVZXXgSQH5WYfyU+3HfcXuKaapzAJ8fBLQ/G618rn3yvSzEbnOB8ZSOwhX+dAORy/lw+GC2N061JA0+gYWTVA==} + engines: {node: '>=12.0.0', npm: '>=6.0.0'} + peerDependencies: + react: ^16.8.0 || ^17.0.0 || ^18.0.0 + react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 + dependencies: + clsx: 1.2.1 + goober: 2.1.14(csstype@3.1.3) + react: 18.2.0 + react-dom: 18.2.0(react@18.2.0) + transitivePeerDependencies: + - csstype + dev: false + + /npm-run-path@4.0.1: + resolution: {integrity: sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==} + engines: {node: '>=8'} + dependencies: + path-key: 3.1.1 + dev: true + + /npm-run-path@5.3.0: + resolution: {integrity: sha512-ppwTtiJZq0O/ai0z7yfudtBpWIoxM8yE6nHi1X47eFR2EWORqfbu6CnPlNsjeN683eT0qG6H/Pyf9fCcvjnnnQ==} + engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + dependencies: + path-key: 4.0.0 + dev: false + + /object-assign@4.1.1: + resolution: {integrity: sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==} + engines: {node: '>=0.10.0'} + + /object-code@1.3.2: + resolution: {integrity: sha512-3CVDmQiru7YYVr+4OpCGrqkVE7GogmWinDcgfno1fXlKgIhtW9FhgHTiV98gMPUjQwWuWvijQDCY8sGnqKrhTw==} + dev: false + + /object-hash@3.0.0: + resolution: {integrity: sha512-RSn9F68PjH9HqtltsSnqYC1XXoWe9Bju5+213R98cNGttag9q9yAOTzdbsqvIa7aNm5WffBZFpWYr2aWrklWAw==} + engines: {node: '>= 6'} + + /ofetch@1.3.3: + resolution: {integrity: sha512-s1ZCMmQWXy4b5K/TW9i/DtiN8Ku+xCiHcjQ6/J/nDdssirrQNOoB165Zu8EqLMA2lln1JUth9a0aW9Ap2ctrUg==} + dependencies: + destr: 2.0.3 + node-fetch-native: 1.6.2 + ufo: 1.5.2 + dev: false + + /ohash@1.1.3: + resolution: {integrity: sha512-zuHHiGTYTA1sYJ/wZN+t5HKZaH23i4yI1HMwbuXm24Nid7Dv0KcuRlKoNKS9UNfAVSBlnGLcuQrnOKWOZoEGaw==} + dev: false + + /on-exit-leak-free@0.2.0: + resolution: {integrity: sha512-dqaz3u44QbRXQooZLTUKU41ZrzYrcvLISVgbrzbyCMxpmSLJvZ3ZamIJIZ29P6OhZIkNIQKosdeM6t1LYbA9hg==} + dev: false + + /once@1.4.0: + resolution: {integrity: sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==} + dependencies: + wrappy: 1.0.2 + + /onetime@5.1.2: + resolution: {integrity: sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==} + engines: {node: '>=6'} + dependencies: + mimic-fn: 2.1.0 + dev: true + + /onetime@6.0.0: + resolution: {integrity: sha512-1FlR+gjXK7X+AsAHso35MnyN5KqGwJRi/31ft6x0M194ht7S+rWAvd7PHss9xSKMzE0asv1pyIHaJYq+BbacAQ==} + engines: {node: '>=12'} + dependencies: + mimic-fn: 4.0.0 + dev: false + + /optionator@0.9.3: + resolution: {integrity: sha512-JjCoypp+jKn1ttEFExxhetCKeJt9zhAgAve5FXHixTvFDW/5aEktX9bufBKLRRMdU7bNtpLfcGu94B3cdEJgjg==} + engines: {node: '>= 0.8.0'} + dependencies: + '@aashutoshrathi/word-wrap': 1.2.6 + deep-is: 0.1.4 + fast-levenshtein: 2.0.6 + levn: 0.4.1 + prelude-ls: 1.2.1 + type-check: 0.4.0 + dev: true + + /p-limit@2.3.0: + resolution: {integrity: sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==} + engines: {node: '>=6'} + dependencies: + p-try: 2.2.0 + + /p-limit@3.1.0: + resolution: {integrity: sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==} + engines: {node: '>=10'} + dependencies: + yocto-queue: 0.1.0 + dev: true + + /p-locate@4.1.0: + resolution: {integrity: sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==} + engines: {node: '>=8'} + dependencies: + p-limit: 2.3.0 + + /p-locate@5.0.0: + resolution: {integrity: sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==} + engines: {node: '>=10'} + dependencies: + p-limit: 3.1.0 + dev: true + + /p-try@2.2.0: + resolution: {integrity: sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==} + engines: {node: '>=6'} + + /parent-module@1.0.1: + resolution: {integrity: sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==} + engines: {node: '>=6'} + dependencies: + callsites: 3.1.0 + dev: true + + /parse-json@5.2.0: + resolution: {integrity: sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==} + engines: {node: '>=8'} + dependencies: + '@babel/code-frame': 7.24.2 + error-ex: 1.3.2 + json-parse-even-better-errors: 2.3.1 + lines-and-columns: 1.2.4 + dev: true + + /path-exists@4.0.0: + resolution: {integrity: sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==} + engines: {node: '>=8'} + + /path-is-absolute@1.0.1: + resolution: {integrity: sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==} + engines: {node: '>=0.10.0'} + dev: true + + /path-key@3.1.1: + resolution: {integrity: sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==} + engines: {node: '>=8'} + + /path-key@4.0.0: + resolution: {integrity: sha512-haREypq7xkM7ErfgIyA0z+Bj4AGKlMSdlQE2jvJo6huWD1EdkKYV+G/T4nq0YEF2vgTT8kqMFKo1uHn950r4SQ==} + engines: {node: '>=12'} + dev: false + + /path-parse@1.0.7: + resolution: {integrity: sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==} + + /path-scurry@1.10.1: + resolution: {integrity: sha512-MkhCqzzBEpPvxxQ71Md0b1Kk51W01lrYvlMzSUaIzNsODdd7mqhiimSZlr+VegAz5Z6Vzt9Xg2ttE//XBhH3EQ==} + engines: {node: '>=16 || 14 >=14.17'} + dependencies: + lru-cache: 10.2.0 + minipass: 7.0.4 + + /path-type@4.0.0: + resolution: {integrity: sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==} + engines: {node: '>=8'} + dev: true + + /pathe@1.1.2: + resolution: {integrity: sha512-whLdWMYL2TwI08hn8/ZqAbrVemu0LNaNNJZX73O6qaIdCTfXutsLhMkjdENX0qhsQ9uIimo4/aQOmXkoon2nDQ==} + dev: false + + /picocolors@1.0.0: + resolution: {integrity: sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==} + + /picomatch@2.3.1: + resolution: {integrity: sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==} + engines: {node: '>=8.6'} + + /pify@2.3.0: + resolution: {integrity: sha512-udgsAY+fTnvv7kI7aaxbqwWNb0AHiB0qBO89PZKPkoTmGOgdbrHDKD+0B2X4uTfJ/FT1R09r9gTsjUjNJotuog==} + engines: {node: '>=0.10.0'} + + /pino-abstract-transport@0.5.0: + resolution: {integrity: sha512-+KAgmVeqXYbTtU2FScx1XS3kNyfZ5TrXY07V96QnUSFqo2gAqlvmaxH67Lj7SWazqsMabf+58ctdTcBgnOLUOQ==} + dependencies: + duplexify: 4.1.3 + split2: 4.2.0 + dev: false + + /pino-std-serializers@4.0.0: + resolution: {integrity: sha512-cK0pekc1Kjy5w9V2/n+8MkZwusa6EyyxfeQCB799CQRhRt/CqYKiWs5adeu8Shve2ZNffvfC/7J64A2PJo1W/Q==} + dev: false + + /pino@7.11.0: + resolution: {integrity: sha512-dMACeu63HtRLmCG8VKdy4cShCPKaYDR4youZqoSWLxl5Gu99HUw8bw75thbPv9Nip+H+QYX8o3ZJbTdVZZ2TVg==} + hasBin: true + dependencies: + atomic-sleep: 1.0.0 + fast-redact: 3.5.0 + on-exit-leak-free: 0.2.0 + pino-abstract-transport: 0.5.0 + pino-std-serializers: 4.0.0 + process-warning: 1.0.0 + quick-format-unescaped: 4.0.4 + real-require: 0.1.0 + safe-stable-stringify: 2.4.3 + sonic-boom: 2.8.0 + thread-stream: 0.15.2 + dev: false + + /pirates@4.0.6: + resolution: {integrity: sha512-saLsH7WeYYPiD25LDuLRRY/i+6HaPYr6G1OUlN39otzkSTxKnubR9RTxS3/Kk50s1g2JTgFwWQDQyplC5/SHZg==} + engines: {node: '>= 6'} + + /pkg-dir@4.2.0: + resolution: {integrity: sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==} + engines: {node: '>=8'} + dependencies: + find-up: 4.1.0 + dev: true + + /pkg-types@1.0.3: + resolution: {integrity: sha512-nN7pYi0AQqJnoLPC9eHFQ8AcyaixBUOwvqc5TDnIKCMEE6I0y8P7OKA7fPexsXGCGxQDl/cmrLAp26LhcwxZ4A==} + dependencies: + jsonc-parser: 3.2.1 + mlly: 1.6.1 + pathe: 1.1.2 + dev: false + + /playwright-core@1.42.1: + resolution: {integrity: sha512-mxz6zclokgrke9p1vtdy/COWBH+eOZgYUVVU34C73M+4j4HLlQJHtfcqiqqxpP0o8HhMkflvfbquLX5dg6wlfA==} + engines: {node: '>=16'} + hasBin: true + dev: true + + /playwright@1.42.1: + resolution: {integrity: sha512-PgwB03s2DZBcNRoW+1w9E+VkLBxweib6KTXM0M3tkiT4jVxKSi6PmVJ591J+0u10LUrgxB7dLRbiJqO5s2QPMg==} + engines: {node: '>=16'} + hasBin: true + dependencies: + playwright-core: 1.42.1 + optionalDependencies: + fsevents: 2.3.2 + dev: true + + /pngjs@5.0.0: + resolution: {integrity: sha512-40QW5YalBNfQo5yRYmiw7Yz6TKKVr3h6970B2YE+3fQpsWcrbj1PzJgxeJ19DRQjhMbKPIuMY8rFaXc8moolVw==} + engines: {node: '>=10.13.0'} + dev: false + + /postcss-import@15.1.0(postcss@8.4.37): + resolution: {integrity: sha512-hpr+J05B2FVYUAXHeK1YyI267J/dDDhMU6B6civm8hSY1jYJnBXxzKDKDswzJmtLHryrjhnDjqqp/49t8FALew==} + engines: {node: '>=14.0.0'} + peerDependencies: + postcss: ^8.0.0 + dependencies: + postcss: 8.4.37 + postcss-value-parser: 4.2.0 + read-cache: 1.0.0 + resolve: 1.22.8 + + /postcss-js@4.0.1(postcss@8.4.37): + resolution: {integrity: sha512-dDLF8pEO191hJMtlHFPRa8xsizHaM82MLfNkUHdUtVEV3tgTp5oj+8qbEqYM57SLfc74KSbw//4SeJma2LRVIw==} + engines: {node: ^12 || ^14 || >= 16} + peerDependencies: + postcss: ^8.4.21 + dependencies: + camelcase-css: 2.0.1 + postcss: 8.4.37 + + /postcss-load-config@4.0.2(postcss@8.4.37)(ts-node@10.9.2): + resolution: {integrity: sha512-bSVhyJGL00wMVoPUzAVAnbEoWyqRxkjv64tUl427SKnPrENtq6hJwUojroMz2VB+Q1edmi4IfrAPpami5VVgMQ==} + engines: {node: '>= 14'} + peerDependencies: + postcss: '>=8.0.9' + ts-node: '>=9.0.0' + peerDependenciesMeta: + postcss: + optional: true + ts-node: + optional: true + dependencies: + lilconfig: 3.1.1 + postcss: 8.4.37 + ts-node: 10.9.2(@types/node@18.19.26)(typescript@5.4.2) + yaml: 2.4.1 + + /postcss-nested@6.0.1(postcss@8.4.37): + resolution: {integrity: sha512-mEp4xPMi5bSWiMbsgoPfcP74lsWLHkQbZc3sY+jWYd65CUwXrUaTp0fmNpa01ZcETKlIgUdFN/MpS2xZtqL9dQ==} + engines: {node: '>=12.0'} + peerDependencies: + postcss: ^8.2.14 + dependencies: + postcss: 8.4.37 + postcss-selector-parser: 6.0.16 + + /postcss-selector-parser@6.0.16: + resolution: {integrity: sha512-A0RVJrX+IUkVZbW3ClroRWurercFhieevHB38sr2+l9eUClMqome3LmEmnhlNy+5Mr2EYN6B2Kaw9wYdd+VHiw==} + engines: {node: '>=4'} + dependencies: + cssesc: 3.0.0 + util-deprecate: 1.0.2 + + /postcss-value-parser@4.2.0: + resolution: {integrity: sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==} + + /postcss@8.4.31: + resolution: {integrity: sha512-PS08Iboia9mts/2ygV3eLpY5ghnUcfLV/EXTOW1E2qYxJKGGBUtNjN76FYHnMs36RmARn41bC0AZmn+rR0OVpQ==} + engines: {node: ^10 || ^12 || >=14} + dependencies: + nanoid: 3.3.7 + picocolors: 1.0.0 + source-map-js: 1.2.0 + dev: false + + /postcss@8.4.37: + resolution: {integrity: sha512-7iB/v/r7Woof0glKLH8b1SPHrsX7uhdO+Geb41QpF/+mWZHU3uxxSlN+UXGVit1PawOYDToO+AbZzhBzWRDwbQ==} + engines: {node: ^10 || ^12 || >=14} + dependencies: + nanoid: 3.3.7 + picocolors: 1.0.0 + source-map-js: 1.2.0 + + /prelude-ls@1.2.1: + resolution: {integrity: sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==} + engines: {node: '>= 0.8.0'} + dev: true + + /prettier-linter-helpers@1.0.0: + resolution: {integrity: sha512-GbK2cP9nraSSUF9N2XwUwqfzlAFlMNYYl+ShE/V+H8a9uNl/oUqB1w2EL54Jh0OlyRSd8RfWYJ3coVS4TROP2w==} + engines: {node: '>=6.0.0'} + dependencies: + fast-diff: 1.3.0 + dev: true + + /prettier@3.2.5: + resolution: {integrity: sha512-3/GWa9aOC0YeD7LUfvOG2NiDyhOWRvt1k+rcKhOuYnMY24iiCphgneUfJDyFXd6rZCAnuLBv6UeAULtrhT/F4A==} + engines: {node: '>=14'} + hasBin: true + dev: true + + /pretty-format@29.7.0: + resolution: {integrity: sha512-Pdlw/oPxN+aXdmM9R00JVC9WVFoCLTKJvDVLgmJ+qAffBMxsV85l/Lu7sNx4zSzPyoL2euImuEwHhOXdEgNFZQ==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + dependencies: + '@jest/schemas': 29.6.3 + ansi-styles: 5.2.0 + react-is: 18.2.0 + dev: true + + /process-warning@1.0.0: + resolution: {integrity: sha512-du4wfLyj4yCZq1VupnVSZmRsPJsNuxoDQFdCFHLaYiEbFBD7QE0a+I4D7hOxrVnh78QE/YipFAj9lXHiXocV+Q==} + dev: false + + /prompts@2.4.2: + resolution: {integrity: sha512-NxNv/kLguCA7p3jE8oL2aEBsrJWgAakBpgmgK6lpPWV+WuOmY6r2/zbAVnP+T8bQlA0nzHXSJSJW0Hq7ylaD2Q==} + engines: {node: '>= 6'} + dependencies: + kleur: 3.0.3 + sisteransi: 1.0.5 + dev: true + + /prop-types@15.8.1: + resolution: {integrity: sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==} + dependencies: + loose-envify: 1.4.0 + object-assign: 4.1.1 + react-is: 16.13.1 + dev: false + + /proxy-compare@2.5.1: + resolution: {integrity: sha512-oyfc0Tx87Cpwva5ZXezSp5V9vht1c7dZBhvuV/y3ctkgMVUmiAGDVeeB0dKhGSyT0v1ZTEQYpe/RXlBVBNuCLA==} + dev: false + + /proxy-from-env@1.1.0: + resolution: {integrity: sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==} + dev: false + + /punycode@2.3.1: + resolution: {integrity: sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==} + engines: {node: '>=6'} + dev: true + + /pure-rand@6.1.0: + resolution: {integrity: sha512-bVWawvoZoBYpp6yIoQtQXHZjmz35RSVHnUOTefl8Vcjr8snTPY1wnpSPMWekcFwbxI6gtmT7rSYPFvz71ldiOA==} + dev: true + + /qr-code-styling@1.5.0: + resolution: {integrity: sha512-7C+1cZGsZWH0BIRtv24faKZJwkxdYlynXktP9dDxKNSik2bqaUZck3B3MpQod/wqm9i3l4q7QsPGkRGKvcuqZw==} + dependencies: + qrcode-generator: 1.4.4 + dev: false + + /qr-code-styling@1.6.0-rc.1: + resolution: {integrity: sha512-ModRIiW6oUnsP18QzrRYZSc/CFKFKIdj7pUs57AEVH20ajlglRpN3HukjHk0UbNMTlKGuaYl7Gt6/O5Gg2NU2Q==} + dependencies: + qrcode-generator: 1.4.4 + dev: false + + /qrcode-generator@1.4.4: + resolution: {integrity: sha512-HM7yY8O2ilqhmULxGMpcHSF1EhJJ9yBj8gvDEuZ6M+KGJ0YY2hKpnXvRD+hZPLrDVck3ExIGhmPtSdcjC+guuw==} + dev: false + + /qrcode@1.5.3: + resolution: {integrity: sha512-puyri6ApkEHYiVl4CFzo1tDkAZ+ATcnbJrJ6RiBM1Fhctdn/ix9MTE3hRph33omisEbC/2fcfemsseiKgBPKZg==} + engines: {node: '>=10.13.0'} + hasBin: true + dependencies: + dijkstrajs: 1.0.3 + encode-utf8: 1.0.3 + pngjs: 5.0.0 + yargs: 15.4.1 + dev: false + + /query-string@6.13.5: + resolution: {integrity: sha512-svk3xg9qHR39P3JlHuD7g3nRnyay5mHbrPctEBDUxUkHRifPHXJDhBUycdCC0NBjXoDf44Gb+IsOZL1Uwn8M/Q==} + engines: {node: '>=6'} + dependencies: + decode-uri-component: 0.2.2 + split-on-first: 1.1.0 + strict-uri-encode: 2.0.0 + dev: false + + /query-string@7.1.3: + resolution: {integrity: sha512-hh2WYhq4fi8+b+/2Kg9CEge4fDPvHS534aOOvOZeQ3+Vf2mCFsaFBYj0i+iXcAq6I9Vzp5fjMFBlONvayDC1qg==} + engines: {node: '>=6'} + dependencies: + decode-uri-component: 0.2.2 + filter-obj: 1.1.0 + split-on-first: 1.1.0 + strict-uri-encode: 2.0.0 + dev: false + + /queue-microtask@1.2.3: + resolution: {integrity: sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==} + + /quick-format-unescaped@4.0.4: + resolution: {integrity: sha512-tYC1Q1hgyRuHgloV/YXs2w15unPVh8qfu/qCTfhTYamaw7fyhumKa2yGpdSo87vY32rIclj+4fWYQXUMs9EHvg==} + dev: false + + /radix3@1.1.1: + resolution: {integrity: sha512-yUUd5VTiFtcMEx0qFUxGAv5gbMc1un4RvEO1JZdP7ZUl/RHygZK6PknIKntmQRZxnMY3ZXD2ISaw1ij8GYW1yg==} + dev: false + + /randombytes@2.1.0: + resolution: {integrity: sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==} + dependencies: + safe-buffer: 5.2.1 + dev: false + + /react-dom@18.2.0(react@18.2.0): + resolution: {integrity: sha512-6IMTriUmvsjHUjNtEDudZfuDQUoWXVxKHhlEGSk81n4YFS+r/Kl99wXiwlVXtPBtJenozv2P+hxDsw9eA7Xo6g==} + peerDependencies: + react: ^18.2.0 + dependencies: + loose-envify: 1.4.0 + react: 18.2.0 + scheduler: 0.23.0 + dev: false + + /react-fast-compare@3.2.2: + resolution: {integrity: sha512-nsO+KSNgo1SbJqJEYRE9ERzo7YtYbou/OqjSQKxV7jcKox7+usiUVZOAC+XnDOABXggQTno0Y1CpVnuWEc1boQ==} + dev: false + + /react-helmet-async@2.0.4(react-dom@18.2.0)(react@18.2.0): + resolution: {integrity: sha512-yxjQMWposw+akRfvpl5+8xejl4JtUlHnEBcji6u8/e6oc7ozT+P9PNTWMhCbz2y9tc5zPegw2BvKjQA+NwdEjQ==} + peerDependencies: + react: ^16.6.0 || ^17.0.0 || ^18.0.0 + react-dom: ^16.6.0 || ^17.0.0 || ^18.0.0 + dependencies: + invariant: 2.2.4 + react: 18.2.0 + react-dom: 18.2.0(react@18.2.0) + react-fast-compare: 3.2.2 + shallowequal: 1.1.0 + dev: false + + /react-hook-form@7.51.1(react@18.2.0): + resolution: {integrity: sha512-ifnBjl+kW0ksINHd+8C/Gp6a4eZOdWyvRv0UBaByShwU8JbVx5hTcTWEcd5VdybvmPTATkVVXk9npXArHmo56w==} + engines: {node: '>=12.22.0'} + peerDependencies: + react: ^16.8.0 || ^17 || ^18 + dependencies: + react: 18.2.0 + dev: false + + /react-is@16.13.1: + resolution: {integrity: sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==} + dev: false + + /react-is@18.2.0: + resolution: {integrity: sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w==} + dev: true + + /react-refresh@0.14.0: + resolution: {integrity: sha512-wViHqhAd8OHeLS/IRMJjTSDHF3U9eWi62F/MledQGPdJGDhodXJ9PBLNGr6WWL7qlH12Mt3TyTpbS+hGXMjCzQ==} + engines: {node: '>=0.10.0'} + dev: true + + /react-remove-scroll-bar@2.3.6(@types/react@18.2.67)(react@18.2.0): + resolution: {integrity: sha512-DtSYaao4mBmX+HDo5YWYdBWQwYIQQshUV/dVxFxK+KM26Wjwp1gZ6rv6OC3oujI6Bfu6Xyg3TwK533AQutsn/g==} + engines: {node: '>=10'} + peerDependencies: + '@types/react': ^16.8.0 || ^17.0.0 || ^18.0.0 + react: ^16.8.0 || ^17.0.0 || ^18.0.0 + peerDependenciesMeta: + '@types/react': + optional: true + dependencies: + '@types/react': 18.2.67 + react: 18.2.0 + react-style-singleton: 2.2.1(@types/react@18.2.67)(react@18.2.0) + tslib: 2.6.2 + dev: false + + /react-remove-scroll@2.5.5(@types/react@18.2.67)(react@18.2.0): + resolution: {integrity: sha512-ImKhrzJJsyXJfBZ4bzu8Bwpka14c/fQt0k+cyFp/PBhTfyDnU5hjOtM4AG/0AMyy8oKzOTR0lDgJIM7pYXI0kw==} + engines: {node: '>=10'} + peerDependencies: + '@types/react': ^16.8.0 || ^17.0.0 || ^18.0.0 + react: ^16.8.0 || ^17.0.0 || ^18.0.0 + peerDependenciesMeta: + '@types/react': + optional: true + dependencies: + '@types/react': 18.2.67 + react: 18.2.0 + react-remove-scroll-bar: 2.3.6(@types/react@18.2.67)(react@18.2.0) + react-style-singleton: 2.2.1(@types/react@18.2.67)(react@18.2.0) + tslib: 2.6.2 + use-callback-ref: 1.3.1(@types/react@18.2.67)(react@18.2.0) + use-sidecar: 1.1.2(@types/react@18.2.67)(react@18.2.0) + dev: false + + /react-smooth@4.0.0(react-dom@18.2.0)(react@18.2.0): + resolution: {integrity: sha512-2NMXOBY1uVUQx1jBeENGA497HK20y6CPGYL1ZnJLeoQ8rrc3UfmOM82sRxtzpcoCkUMy4CS0RGylfuVhuFjBgg==} + peerDependencies: + react: ^16.8.0 || ^17.0.0 || ^18.0.0 + react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 + dependencies: + fast-equals: 5.0.1 + prop-types: 15.8.1 + react: 18.2.0 + react-dom: 18.2.0(react@18.2.0) + react-transition-group: 4.4.5(react-dom@18.2.0)(react@18.2.0) + dev: false + + /react-style-singleton@2.2.1(@types/react@18.2.67)(react@18.2.0): + resolution: {integrity: sha512-ZWj0fHEMyWkHzKYUr2Bs/4zU6XLmq9HsgBURm7g5pAVfyn49DgUiNgY2d4lXRlYSiCif9YBGpQleewkcqddc7g==} + engines: {node: '>=10'} + peerDependencies: + '@types/react': ^16.8.0 || ^17.0.0 || ^18.0.0 + react: ^16.8.0 || ^17.0.0 || ^18.0.0 + peerDependenciesMeta: + '@types/react': + optional: true + dependencies: + '@types/react': 18.2.67 + get-nonce: 1.0.1 + invariant: 2.2.4 + react: 18.2.0 + tslib: 2.6.2 + dev: false + + /react-transition-group@4.4.5(react-dom@18.2.0)(react@18.2.0): + resolution: {integrity: sha512-pZcd1MCJoiKiBR2NRxeCRg13uCXbydPnmB4EOeRrY7480qNWO8IIgQG6zlDkm6uRMsURXPuKq0GWtiM59a5Q6g==} + peerDependencies: + react: '>=16.6.0' + react-dom: '>=16.6.0' + dependencies: + '@babel/runtime': 7.24.1 + dom-helpers: 5.2.1 + loose-envify: 1.4.0 + prop-types: 15.8.1 + react: 18.2.0 + react-dom: 18.2.0(react@18.2.0) + dev: false + + /react@18.2.0: + resolution: {integrity: sha512-/3IjMdb2L9QbBdWiW5e3P2/npwMBaU9mHCSCUzNln0ZCYbcfTsGbTJrU/kGemdH2IWmB2ioZ+zkxtmq6g09fGQ==} + engines: {node: '>=0.10.0'} + dependencies: + loose-envify: 1.4.0 + dev: false + + /read-cache@1.0.0: + resolution: {integrity: sha512-Owdv/Ft7IjOgm/i0xvNDZ1LrRANRfew4b2prF3OWMQLxLfu3bS8FVhCsrSCMK4lR56Y9ya+AThoTpDCTxCmpRA==} + dependencies: + pify: 2.3.0 + + /readable-stream@3.6.2: + resolution: {integrity: sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==} + engines: {node: '>= 6'} + dependencies: + inherits: 2.0.4 + string_decoder: 1.3.0 + util-deprecate: 1.0.2 + dev: false + + /readdirp@3.6.0: + resolution: {integrity: sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==} + engines: {node: '>=8.10.0'} + dependencies: + picomatch: 2.3.1 + + /real-require@0.1.0: + resolution: {integrity: sha512-r/H9MzAWtrv8aSVjPCMFpDMl5q66GqtmmRkRjpHTsp4zBAa+snZyiQNlMONiUmEJcsnaw0wCauJ2GWODr/aFkg==} + engines: {node: '>= 12.13.0'} + dev: false + + /recharts-scale@0.4.5: + resolution: {integrity: sha512-kivNFO+0OcUNu7jQquLXAxz1FIwZj8nrj+YkOKc5694NbjCvcT6aSZiIzNzd2Kul4o4rTto8QVR9lMNtxD4G1w==} + dependencies: + decimal.js-light: 2.5.1 + dev: false + + /recharts@2.12.3(react-dom@18.2.0)(react@18.2.0): + resolution: {integrity: sha512-vE/F7wTlokf5mtCqVDJlVKelCjliLSJ+DJxj79XlMREm7gpV7ljwbrwE3CfeaoDlOaLX+6iwHaVRn9587YkwIg==} + engines: {node: '>=14'} + peerDependencies: + react: ^16.0.0 || ^17.0.0 || ^18.0.0 + react-dom: ^16.0.0 || ^17.0.0 || ^18.0.0 + dependencies: + clsx: 2.1.0 + eventemitter3: 4.0.7 + lodash: 4.17.21 + react: 18.2.0 + react-dom: 18.2.0(react@18.2.0) + react-is: 16.13.1 + react-smooth: 4.0.0(react-dom@18.2.0)(react@18.2.0) + recharts-scale: 0.4.5 + tiny-invariant: 1.3.3 + victory-vendor: 36.9.2 + dev: false + + /regenerator-runtime@0.14.1: + resolution: {integrity: sha512-dYnhHh0nJoMfnkZs6GmmhFknAGRrLznOu5nc9ML+EJxGvrx6H7teuevqVqCuPcPK//3eDrrjQhehXVx9cnkGdw==} + dev: false + + /require-directory@2.1.1: + resolution: {integrity: sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==} + engines: {node: '>=0.10.0'} + + /require-main-filename@2.0.0: + resolution: {integrity: sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg==} + dev: false + + /resolve-cwd@3.0.0: + resolution: {integrity: sha512-OrZaX2Mb+rJCpH/6CpSqt9xFVpN++x01XnN2ie9g6P5/3xelLAkXWVADpdz1IHD/KFfEXyE6V0U01OQ3UO2rEg==} + engines: {node: '>=8'} + dependencies: + resolve-from: 5.0.0 + dev: true + + /resolve-from@4.0.0: + resolution: {integrity: sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==} + engines: {node: '>=4'} + dev: true + + /resolve-from@5.0.0: + resolution: {integrity: sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==} + engines: {node: '>=8'} + dev: true + + /resolve.exports@2.0.2: + resolution: {integrity: sha512-X2UW6Nw3n/aMgDVy+0rSqgHlv39WZAlZrXCdnbyEiKm17DSqHX4MmQMaST3FbeWR5FTuRcUwYAziZajji0Y7mg==} + engines: {node: '>=10'} + dev: true + + /resolve@1.22.8: + resolution: {integrity: sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw==} + hasBin: true + dependencies: + is-core-module: 2.13.1 + path-parse: 1.0.7 + supports-preserve-symlinks-flag: 1.0.0 + + /reusify@1.0.4: + resolution: {integrity: sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==} + engines: {iojs: '>=1.0.0', node: '>=0.10.0'} + + /rimraf@3.0.2: + resolution: {integrity: sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==} + hasBin: true + dependencies: + glob: 7.2.3 + dev: true + + /rollup@4.13.0: + resolution: {integrity: sha512-3YegKemjoQnYKmsBlOHfMLVPPA5xLkQ8MHLLSw/fBrFaVkEayL51DilPpNNLq1exr98F2B1TzrV0FUlN3gWRPg==} + engines: {node: '>=18.0.0', npm: '>=8.0.0'} + hasBin: true + dependencies: + '@types/estree': 1.0.5 + optionalDependencies: + '@rollup/rollup-android-arm-eabi': 4.13.0 + '@rollup/rollup-android-arm64': 4.13.0 + '@rollup/rollup-darwin-arm64': 4.13.0 + '@rollup/rollup-darwin-x64': 4.13.0 + '@rollup/rollup-linux-arm-gnueabihf': 4.13.0 + '@rollup/rollup-linux-arm64-gnu': 4.13.0 + '@rollup/rollup-linux-arm64-musl': 4.13.0 + '@rollup/rollup-linux-riscv64-gnu': 4.13.0 + '@rollup/rollup-linux-x64-gnu': 4.13.0 + '@rollup/rollup-linux-x64-musl': 4.13.0 + '@rollup/rollup-win32-arm64-msvc': 4.13.0 + '@rollup/rollup-win32-ia32-msvc': 4.13.0 + '@rollup/rollup-win32-x64-msvc': 4.13.0 + fsevents: 2.3.3 + dev: true + + /run-parallel@1.2.0: + resolution: {integrity: sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==} + dependencies: + queue-microtask: 1.2.3 + + /safe-buffer@5.2.1: + resolution: {integrity: sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==} + dev: false + + /safe-stable-stringify@2.4.3: + resolution: {integrity: sha512-e2bDA2WJT0wxseVd4lsDP4+3ONX6HpMXQa1ZhFQ7SU+GjvORCmShbCMltrtIDfkYhVHrOcPtj+KhmDBdPdZD1g==} + engines: {node: '>=10'} + dev: false + + /scheduler@0.23.0: + resolution: {integrity: sha512-CtuThmgHNg7zIZWAXi3AsyIzA3n4xx7aNyjwC2VJldO2LMVDhFK+63xGqq6CsJH4rTAt6/M+N4GhZiDYPx9eUw==} + dependencies: + loose-envify: 1.4.0 + dev: false + + /semver@6.3.1: + resolution: {integrity: sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==} + hasBin: true + + /semver@7.6.0: + resolution: {integrity: sha512-EnwXhrlwXMk9gKu5/flx5sv/an57AkRplG3hTK68W7FRDN+k+OWBj65M7719OkA82XLBxrcX0KSHj+X5COhOVg==} + engines: {node: '>=10'} + hasBin: true + dependencies: + lru-cache: 6.0.0 + dev: true + + /set-blocking@2.0.0: + resolution: {integrity: sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw==} + dev: false + + /shallowequal@1.1.0: + resolution: {integrity: sha512-y0m1JoUZSlPAjXVtPPW70aZWfIL/dSP7AFkRnniLCrK/8MDKog3TySTBmckD+RObVxH0v4Tox67+F14PdED2oQ==} + dev: false + + /shebang-command@2.0.0: + resolution: {integrity: sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==} + engines: {node: '>=8'} + dependencies: + shebang-regex: 3.0.0 + + /shebang-regex@3.0.0: + resolution: {integrity: sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==} + engines: {node: '>=8'} + + /signal-exit@3.0.7: + resolution: {integrity: sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==} + dev: true + + /signal-exit@4.1.0: + resolution: {integrity: sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==} + engines: {node: '>=14'} + + /sisteransi@1.0.5: + resolution: {integrity: sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg==} + dev: true + + /slash@3.0.0: + resolution: {integrity: sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==} + engines: {node: '>=8'} + dev: true + + /sonic-boom@2.8.0: + resolution: {integrity: sha512-kuonw1YOYYNOve5iHdSahXPOK49GqwA+LZhI6Wz/l0rP57iKyXXIHaRagOBHAPmGwJC6od2Z9zgvZ5loSgMlVg==} + dependencies: + atomic-sleep: 1.0.0 + dev: false + + /sonner@1.4.3(react-dom@18.2.0)(react@18.2.0): + resolution: {integrity: sha512-SArYlHbkjqRuLiR0iGY2ZSr09oOrxw081ZZkQPfXrs8aZQLIBOLOdzTYxGJB5yIZ7qL56UEPmrX1YqbODwG0Lw==} + peerDependencies: + react: ^18.0.0 + react-dom: ^18.0.0 + dependencies: + react: 18.2.0 + react-dom: 18.2.0(react@18.2.0) + dev: false + + /source-map-js@1.2.0: + resolution: {integrity: sha512-itJW8lvSA0TXEphiRoawsCksnlf8SyvmFzIhltqAHluXd88pkCd+cXJVHTDwdCr0IzwptSm035IHQktUu1QUMg==} + engines: {node: '>=0.10.0'} + + /source-map-support@0.5.13: + resolution: {integrity: sha512-SHSKFHadjVA5oR4PPqhtAVdcBWwRYVd6g6cAXnIbRiIwc2EhPrTuKUBdSLvlEKyIP3GCf89fltvcZiP9MMFA1w==} + dependencies: + buffer-from: 1.1.2 + source-map: 0.6.1 + dev: true + + /source-map@0.6.1: + resolution: {integrity: sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==} + engines: {node: '>=0.10.0'} + dev: true + + /split-on-first@1.1.0: + resolution: {integrity: sha512-43ZssAJaMusuKWL8sKUBQXHWOpq8d6CfN/u1p4gUzfJkM05C8rxTmYrkIPTXapZpORA6LkkzcUulJ8FqA7Uudw==} + engines: {node: '>=6'} + dev: false + + /split2@4.2.0: + resolution: {integrity: sha512-UcjcJOWknrNkF6PLX83qcHM6KHgVKNkV62Y8a5uYDVv9ydGQVwAHMKqHdJje1VTWpljG0WYpCDhrCdAOYH4TWg==} + engines: {node: '>= 10.x'} + dev: false + + /sprintf-js@1.0.3: + resolution: {integrity: sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==} + dev: true + + /stack-utils@2.0.6: + resolution: {integrity: sha512-XlkWvfIm6RmsWtNJx+uqtKLS8eqFbxUg0ZzLXqY0caEy9l7hruX8IpiDnjsLavoBgqCCR71TqWO8MaXYheJ3RQ==} + engines: {node: '>=10'} + dependencies: + escape-string-regexp: 2.0.0 + dev: true + + /std-env@3.7.0: + resolution: {integrity: sha512-JPbdCEQLj1w5GilpiHAx3qJvFndqybBysA3qUOnznweH4QbNYUsW/ea8QzSrnh0vNsezMMw5bcVool8lM0gwzg==} + dev: false + + /stream-shift@1.0.3: + resolution: {integrity: sha512-76ORR0DO1o1hlKwTbi/DM3EXWGf3ZJYO8cXX5RJwnul2DEg2oyoZyjLNoQM8WsvZiFKCRfC1O0J7iCvie3RZmQ==} + dev: false + + /streamsearch@1.1.0: + resolution: {integrity: sha512-Mcc5wHehp9aXz1ax6bZUyY5afg9u2rv5cqQI3mRrYkGC8rW2hM02jWuwjtL++LS5qinSyhj2QfLyNsuc+VsExg==} + engines: {node: '>=10.0.0'} + dev: false + + /strict-uri-encode@2.0.0: + resolution: {integrity: sha512-QwiXZgpRcKkhTj2Scnn++4PKtWsH0kpzZ62L2R6c/LUVYv7hVnZqcg2+sMuT6R7Jusu1vviK/MFsu6kNJfWlEQ==} + engines: {node: '>=4'} + dev: false + + /string-length@4.0.2: + resolution: {integrity: sha512-+l6rNN5fYHNhZZy41RXsYptCjA2Igmq4EG7kZAYFQI1E1VTXarr6ZPXBg6eq7Y6eK4FEhY6AJlyuFIb/v/S0VQ==} + engines: {node: '>=10'} + dependencies: + char-regex: 1.0.2 + strip-ansi: 6.0.1 + dev: true + + /string-width@4.2.3: + resolution: {integrity: sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==} + engines: {node: '>=8'} + dependencies: + emoji-regex: 8.0.0 + is-fullwidth-code-point: 3.0.0 + strip-ansi: 6.0.1 + + /string-width@5.1.2: + resolution: {integrity: sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==} + engines: {node: '>=12'} + dependencies: + eastasianwidth: 0.2.0 + emoji-regex: 9.2.2 + strip-ansi: 7.1.0 + + /string_decoder@1.3.0: + resolution: {integrity: sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==} + dependencies: + safe-buffer: 5.2.1 + dev: false + + /strip-ansi@6.0.1: + resolution: {integrity: sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==} + engines: {node: '>=8'} + dependencies: + ansi-regex: 5.0.1 + + /strip-ansi@7.1.0: + resolution: {integrity: sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==} + engines: {node: '>=12'} + dependencies: + ansi-regex: 6.0.1 + + /strip-bom@4.0.0: + resolution: {integrity: sha512-3xurFv5tEgii33Zi8Jtp55wEIILR9eh34FAW00PZf+JnSsTmV/ioewSgQl97JHvgjoRGwPShsWm+IdrxB35d0w==} + engines: {node: '>=8'} + dev: true + + /strip-final-newline@2.0.0: + resolution: {integrity: sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==} + engines: {node: '>=6'} + dev: true + + /strip-final-newline@3.0.0: + resolution: {integrity: sha512-dOESqjYr96iWYylGObzd39EuNTa5VJxyvVAEm5Jnh7KGo75V43Hk1odPQkNDyXNmUR6k+gEiDVXnjB8HJ3crXw==} + engines: {node: '>=12'} + dev: false + + /strip-json-comments@3.1.1: + resolution: {integrity: sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==} + engines: {node: '>=8'} + dev: true + + /styled-jsx@5.1.1(@babel/core@7.24.1)(react@18.2.0): + resolution: {integrity: sha512-pW7uC1l4mBZ8ugbiZrcIsiIvVx1UmTfw7UkC3Um2tmfUq9Bhk8IiyEIPl6F8agHgjzku6j0xQEZbfA5uSgSaCw==} + engines: {node: '>= 12.0.0'} + peerDependencies: + '@babel/core': '*' + babel-plugin-macros: '*' + react: '>= 16.8.0 || 17.x.x || ^18.0.0-0' + peerDependenciesMeta: + '@babel/core': + optional: true + babel-plugin-macros: + optional: true + dependencies: + '@babel/core': 7.24.1 + client-only: 0.0.1 + react: 18.2.0 + dev: false + + /sucrase@3.35.0: + resolution: {integrity: sha512-8EbVDiu9iN/nESwxeSxDKe0dunta1GOlHufmSSXxMD2z2/tMZpDMpvXQGsc+ajGo8y2uYUmixaSRUc/QPoQ0GA==} + engines: {node: '>=16 || 14 >=14.17'} + hasBin: true + dependencies: + '@jridgewell/gen-mapping': 0.3.5 + commander: 4.1.1 + glob: 10.3.10 + lines-and-columns: 1.2.4 + mz: 2.7.0 + pirates: 4.0.6 + ts-interface-checker: 0.1.13 + + /supports-color@5.5.0: + resolution: {integrity: sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==} + engines: {node: '>=4'} + dependencies: + has-flag: 3.0.0 + + /supports-color@7.2.0: + resolution: {integrity: sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==} + engines: {node: '>=8'} + dependencies: + has-flag: 4.0.0 + dev: true + + /supports-color@8.1.1: + resolution: {integrity: sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==} + engines: {node: '>=10'} + dependencies: + has-flag: 4.0.0 + dev: true + + /supports-preserve-symlinks-flag@1.0.0: + resolution: {integrity: sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==} + engines: {node: '>= 0.4'} + + /synckit@0.8.8: + resolution: {integrity: sha512-HwOKAP7Wc5aRGYdKH+dw0PRRpbO841v2DENBtjnR5HFWoiNByAl7vrx3p0G/rCyYXQsrxqtX48TImFtPcIHSpQ==} + engines: {node: ^14.18.0 || >=16.0.0} + dependencies: + '@pkgr/core': 0.1.1 + tslib: 2.6.2 + dev: true + + /system-architecture@0.1.0: + resolution: {integrity: sha512-ulAk51I9UVUyJgxlv9M6lFot2WP3e7t8Kz9+IS6D4rVba1tR9kON+Ey69f+1R4Q8cd45Lod6a4IcJIxnzGc/zA==} + engines: {node: '>=18'} + dev: false + + /tailwind-merge@2.2.2: + resolution: {integrity: sha512-tWANXsnmJzgw6mQ07nE3aCDkCK4QdT3ThPMCzawoYA2Pws7vSTCvz3Vrjg61jVUGfFZPJzxEP+NimbcW+EdaDw==} + dependencies: + '@babel/runtime': 7.24.1 + dev: false + + /tailwindcss-animate@1.0.7(tailwindcss@3.3.2): + resolution: {integrity: sha512-bl6mpH3T7I3UFxuvDEXLxy/VuFxBk5bbzplh7tXI68mwMokNYd1t9qPBHlnyTwfa4JGC4zP516I1hYYtQ/vspA==} + peerDependencies: + tailwindcss: '>=3.0.0 || insiders' + dependencies: + tailwindcss: 3.3.2(ts-node@10.9.2) + dev: false + + /tailwindcss@3.3.2(ts-node@10.9.2): + resolution: {integrity: sha512-9jPkMiIBXvPc2KywkraqsUfbfj+dHDb+JPWtSJa9MLFdrPyazI7q6WX2sUrm7R9eVR7qqv3Pas7EvQFzxKnI6w==} + engines: {node: '>=14.0.0'} + hasBin: true + dependencies: + '@alloc/quick-lru': 5.2.0 + arg: 5.0.2 + chokidar: 3.6.0 + didyoumean: 1.2.2 + dlv: 1.1.3 + fast-glob: 3.3.2 + glob-parent: 6.0.2 + is-glob: 4.0.3 + jiti: 1.21.0 + lilconfig: 2.1.0 + micromatch: 4.0.5 + normalize-path: 3.0.0 + object-hash: 3.0.0 + picocolors: 1.0.0 + postcss: 8.4.37 + postcss-import: 15.1.0(postcss@8.4.37) + postcss-js: 4.0.1(postcss@8.4.37) + postcss-load-config: 4.0.2(postcss@8.4.37)(ts-node@10.9.2) + postcss-nested: 6.0.1(postcss@8.4.37) + postcss-selector-parser: 6.0.16 + postcss-value-parser: 4.2.0 + resolve: 1.22.8 + sucrase: 3.35.0 + transitivePeerDependencies: + - ts-node + + /test-exclude@6.0.0: + resolution: {integrity: sha512-cAGWPIyOHU6zlmg88jwm7VRyXnMN7iV68OGAbYDk/Mh/xC/pzVPlQtY6ngoIH/5/tciuhGfvESU8GrHrcxD56w==} + engines: {node: '>=8'} + dependencies: + '@istanbuljs/schema': 0.1.3 + glob: 7.2.3 + minimatch: 3.1.2 + dev: true + + /text-table@0.2.0: + resolution: {integrity: sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==} + dev: true + + /thenify-all@1.6.0: + resolution: {integrity: sha512-RNxQH/qI8/t3thXJDwcstUO4zeqo64+Uy/+sNVRBx4Xn2OX+OZ9oP+iJnNFqplFra2ZUVeKCSa2oVWi3T4uVmA==} + engines: {node: '>=0.8'} + dependencies: + thenify: 3.3.1 + + /thenify@3.3.1: + resolution: {integrity: sha512-RVZSIV5IG10Hk3enotrhvz0T9em6cyHBLkH/YAZuKqd8hRkKhSfCGIcP2KUY0EPxndzANBmNllzWPwak+bheSw==} + dependencies: + any-promise: 1.3.0 + + /thread-stream@0.15.2: + resolution: {integrity: sha512-UkEhKIg2pD+fjkHQKyJO3yoIvAP3N6RlNFt2dUhcS1FGvCD1cQa1M/PGknCLFIyZdtJOWQjejp7bdNqmN7zwdA==} + dependencies: + real-require: 0.1.0 + dev: false + + /tiny-invariant@1.3.3: + resolution: {integrity: sha512-+FbBPE1o9QAYvviau/qC5SE3caw21q3xkvWKBtja5vgqOWIHHJ3ioaq1VPfn/Szqctz2bU/oYeKd9/z5BL+PVg==} + dev: false + + /tiny-warning@1.0.3: + resolution: {integrity: sha512-lBN9zLN/oAf68o3zNXYrdCt1kP8WsiGW8Oo2ka41b2IM5JL/S1CTyX1rW0mb/zSuJun0ZUrDxx4sqvYS2FWzPA==} + dev: false + + /tmpl@1.0.5: + resolution: {integrity: sha512-3f0uOEAQwIqGuWW2MVzYg8fV/QNnc/IpuJNG837rLuczAaLVHslWHZQj4IGiEl5Hs3kkbhwL9Ab7Hrsmuj+Smw==} + dev: true + + /to-fast-properties@2.0.0: + resolution: {integrity: sha512-/OaKK0xYrs3DmxRYqL/yDc+FxFUVYhDlXMhRmv3z915w2HF1tnN1omB354j8VUGO/hbRzyD6Y3sA7v7GS/ceog==} + engines: {node: '>=4'} + + /to-regex-range@5.0.1: + resolution: {integrity: sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==} + engines: {node: '>=8.0'} + dependencies: + is-number: 7.0.0 + + /toggle-selection@1.0.6: + resolution: {integrity: sha512-BiZS+C1OS8g/q2RRbJmy59xpyghNBqrr6k5L/uKBGRsTfxmu3ffiRnd8mlGPUVayg8pvfi5urfnu8TU7DVOkLQ==} + dev: false + + /ts-api-utils@1.3.0(typescript@5.4.2): + resolution: {integrity: sha512-UQMIo7pb8WRomKR1/+MFVLTroIvDVtMX3K6OUir8ynLyzB8Jeriont2bTAtmNPa1ekAgN7YPDyf6V+ygrdU+eQ==} + engines: {node: '>=16'} + peerDependencies: + typescript: '>=4.2.0' + dependencies: + typescript: 5.4.2 + dev: true + + /ts-interface-checker@0.1.13: + resolution: {integrity: sha512-Y/arvbn+rrz3JCKl9C4kVNfTfSm2/mEp5FSz5EsZSANGPSlQrpRI5M4PKF+mJnE52jOO90PnPSc3Ur3bTQw0gA==} + + /ts-jest@29.1.2(@babel/core@7.24.1)(jest@29.7.0)(typescript@5.4.2): + resolution: {integrity: sha512-br6GJoH/WUX4pu7FbZXuWGKGNDuU7b8Uj77g/Sp7puZV6EXzuByl6JrECvm0MzVzSTkSHWTihsXt+5XYER5b+g==} + engines: {node: ^16.10.0 || ^18.0.0 || >=20.0.0} + hasBin: true + peerDependencies: + '@babel/core': '>=7.0.0-beta.0 <8' + '@jest/types': ^29.0.0 + babel-jest: ^29.0.0 + esbuild: '*' + jest: ^29.0.0 + typescript: '>=4.3 <6' + peerDependenciesMeta: + '@babel/core': + optional: true + '@jest/types': + optional: true + babel-jest: + optional: true + esbuild: + optional: true + dependencies: + '@babel/core': 7.24.1 + bs-logger: 0.2.6 + fast-json-stable-stringify: 2.1.0 + jest: 29.7.0(@types/node@18.19.26)(ts-node@10.9.2) + jest-util: 29.7.0 + json5: 2.2.3 + lodash.memoize: 4.1.2 + make-error: 1.3.6 + semver: 7.6.0 + typescript: 5.4.2 + yargs-parser: 21.1.1 + dev: true + + /ts-node@10.9.2(@types/node@18.19.26)(typescript@5.4.2): + resolution: {integrity: sha512-f0FFpIdcHgn8zcPSbf1dRevwt047YMnaiJM3u2w2RewrB+fob/zePZcrOyQoLMMO7aBIddLcQIEK5dYjkLnGrQ==} + hasBin: true + peerDependencies: + '@swc/core': '>=1.2.50' + '@swc/wasm': '>=1.2.50' + '@types/node': '*' + typescript: '>=2.7' + peerDependenciesMeta: + '@swc/core': + optional: true + '@swc/wasm': + optional: true + dependencies: + '@cspotcode/source-map-support': 0.8.1 + '@tsconfig/node10': 1.0.9 + '@tsconfig/node12': 1.0.11 + '@tsconfig/node14': 1.0.3 + '@tsconfig/node16': 1.0.4 + '@types/node': 18.19.26 + acorn: 8.11.3 + acorn-walk: 8.3.2 + arg: 4.1.3 + create-require: 1.1.1 + diff: 4.0.2 + make-error: 1.3.6 + typescript: 5.4.2 + v8-compile-cache-lib: 3.0.1 + yn: 3.1.1 + + /tslib@1.14.1: + resolution: {integrity: sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==} + dev: false + + /tslib@2.6.2: + resolution: {integrity: sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==} + + /tweetnacl@1.0.3: + resolution: {integrity: sha512-6rt+RN7aOi1nGMyC4Xa5DdYiukl2UWCbcJft7YhxReBGQD7OAM8Pbxw6YMo4r2diNEA8FEmu32YOn9rhaiE5yw==} + dev: false + + /type-check@0.4.0: + resolution: {integrity: sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==} + engines: {node: '>= 0.8.0'} + dependencies: + prelude-ls: 1.2.1 + dev: true + + /type-detect@4.0.8: + resolution: {integrity: sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==} + engines: {node: '>=4'} + dev: true + + /type-fest@0.20.2: + resolution: {integrity: sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==} + engines: {node: '>=10'} + dev: true + + /type-fest@0.21.3: + resolution: {integrity: sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==} + engines: {node: '>=10'} + dev: true + + /typedarray-to-buffer@3.1.5: + resolution: {integrity: sha512-zdu8XMNEDepKKR+XYOXAVPtWui0ly0NtohUscw+UmaHiAWT8hrV1rr//H6V+0DvJ3OQ19S979M0laLfX8rm82Q==} + dependencies: + is-typedarray: 1.0.0 + dev: false + + /typescript@5.4.2: + resolution: {integrity: sha512-+2/g0Fds1ERlP6JsakQQDXjZdZMM+rqpamFZJEKh4kwTIn3iDkgKtby0CeNd5ATNZ4Ry1ax15TMx0W2V+miizQ==} + engines: {node: '>=14.17'} + hasBin: true + + /ufo@1.5.2: + resolution: {integrity: sha512-eiutMaL0J2MKdhcOM1tUy13pIrYnyR87fEd8STJQFrrAwImwvlXkxlZEjaKah8r2viPohld08lt73QfLG1NxMg==} + dev: false + + /uint8arrays@3.1.1: + resolution: {integrity: sha512-+QJa8QRnbdXVpHYjLoTpJIdCTiw9Ir62nocClWuXIq2JIh4Uta0cQsTSpFL678p2CN8B+XSApwcU+pQEqVpKWg==} + dependencies: + multiformats: 9.9.0 + dev: false + + /uncrypto@0.1.3: + resolution: {integrity: sha512-Ql87qFHB3s/De2ClA9e0gsnS6zXG27SkTiSJwjCc9MebbfapQfuPzumMIUMi38ezPZVNFcHI9sUIepeQfw8J8Q==} + dev: false + + /undici-types@5.26.5: + resolution: {integrity: sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==} + + /unenv@1.9.0: + resolution: {integrity: sha512-QKnFNznRxmbOF1hDgzpqrlIf6NC5sbZ2OJ+5Wl3OX8uM+LUJXbj4TXvLJCtwbPTmbMHCLIz6JLKNinNsMShK9g==} + dependencies: + consola: 3.2.3 + defu: 6.1.4 + mime: 3.0.0 + node-fetch-native: 1.6.2 + pathe: 1.1.2 + dev: false + + /unstorage@1.10.2(idb-keyval@6.2.1): + resolution: {integrity: sha512-cULBcwDqrS8UhlIysUJs2Dk0Mmt8h7B0E6mtR+relW9nZvsf/u4SkAYyNliPiPW7XtFNb5u3IUMkxGxFTTRTgQ==} + peerDependencies: + '@azure/app-configuration': ^1.5.0 + '@azure/cosmos': ^4.0.0 + '@azure/data-tables': ^13.2.2 + '@azure/identity': ^4.0.1 + '@azure/keyvault-secrets': ^4.8.0 + '@azure/storage-blob': ^12.17.0 + '@capacitor/preferences': ^5.0.7 + '@netlify/blobs': ^6.5.0 || ^7.0.0 + '@planetscale/database': ^1.16.0 + '@upstash/redis': ^1.28.4 + '@vercel/kv': ^1.0.1 + idb-keyval: ^6.2.1 + ioredis: ^5.3.2 + peerDependenciesMeta: + '@azure/app-configuration': + optional: true + '@azure/cosmos': + optional: true + '@azure/data-tables': + optional: true + '@azure/identity': + optional: true + '@azure/keyvault-secrets': + optional: true + '@azure/storage-blob': + optional: true + '@capacitor/preferences': + optional: true + '@netlify/blobs': + optional: true + '@planetscale/database': + optional: true + '@upstash/redis': + optional: true + '@vercel/kv': + optional: true + idb-keyval: + optional: true + ioredis: + optional: true + dependencies: + anymatch: 3.1.3 + chokidar: 3.6.0 + destr: 2.0.3 + h3: 1.11.1 + idb-keyval: 6.2.1 + listhen: 1.7.2 + lru-cache: 10.2.0 + mri: 1.2.0 + node-fetch-native: 1.6.2 + ofetch: 1.3.3 + ufo: 1.5.2 + transitivePeerDependencies: + - uWebSockets.js + dev: false + + /untun@0.1.3: + resolution: {integrity: sha512-4luGP9LMYszMRZwsvyUd9MrxgEGZdZuZgpVQHEEX0lCYFESasVRvZd0EYpCkOIbJKHMuv0LskpXc/8Un+MJzEQ==} + hasBin: true + dependencies: + citty: 0.1.6 + consola: 3.2.3 + pathe: 1.1.2 + dev: false + + /update-browserslist-db@1.0.13(browserslist@4.23.0): + resolution: {integrity: sha512-xebP81SNcPuNpPP3uzeW1NYXxI3rxyJzF3pD6sH4jE7o/IX+WtSpwnVU+qIsDPyk0d3hmFQ7mjqc6AtV604hbg==} + hasBin: true + peerDependencies: + browserslist: '>= 4.21.0' + dependencies: + browserslist: 4.23.0 + escalade: 3.1.2 + picocolors: 1.0.0 + + /uqr@0.1.2: + resolution: {integrity: sha512-MJu7ypHq6QasgF5YRTjqscSzQp/W11zoUk6kvmlH+fmWEs63Y0Eib13hYFwAzagRJcVY8WVnlV+eBDUGMJ5IbA==} + dev: false + + /uri-js@4.4.1: + resolution: {integrity: sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==} + dependencies: + punycode: 2.3.1 + dev: true + + /use-callback-ref@1.3.1(@types/react@18.2.67)(react@18.2.0): + resolution: {integrity: sha512-Lg4Vx1XZQauB42Hw3kK7JM6yjVjgFmFC5/Ab797s79aARomD2nEErc4mCgM8EZrARLmmbWpi5DGCadmK50DcAQ==} + engines: {node: '>=10'} + peerDependencies: + '@types/react': ^16.8.0 || ^17.0.0 || ^18.0.0 + react: ^16.8.0 || ^17.0.0 || ^18.0.0 + peerDependenciesMeta: + '@types/react': + optional: true + dependencies: + '@types/react': 18.2.67 + react: 18.2.0 + tslib: 2.6.2 + dev: false + + /use-debounce@10.0.0(react@18.2.0): + resolution: {integrity: sha512-XRjvlvCB46bah9IBXVnq/ACP2lxqXyZj0D9hj4K5OzNroMDpTEBg8Anuh1/UfRTRs7pLhQ+RiNxxwZu9+MVl1A==} + engines: {node: '>= 16.0.0'} + peerDependencies: + react: '>=16.8.0' + dependencies: + react: 18.2.0 + dev: false + + /use-sidecar@1.1.2(@types/react@18.2.67)(react@18.2.0): + resolution: {integrity: sha512-epTbsLuzZ7lPClpz2TyryBfztm7m+28DlEv2ZCQ3MDr5ssiwyOwGH/e5F9CkfWjJ1t4clvI58yF822/GUkjjhw==} + engines: {node: '>=10'} + peerDependencies: + '@types/react': ^16.9.0 || ^17.0.0 || ^18.0.0 + react: ^16.8.0 || ^17.0.0 || ^18.0.0 + peerDependenciesMeta: + '@types/react': + optional: true + dependencies: + '@types/react': 18.2.67 + detect-node-es: 1.1.0 + react: 18.2.0 + tslib: 2.6.2 + dev: false + + /use-sync-external-store@1.2.0(react@18.2.0): + resolution: {integrity: sha512-eEgnFxGQ1Ife9bzYs6VLi8/4X6CObHMw9Qr9tPY43iKwsPw8xE8+EFsf/2cFZ5S3esXgpWgtSCtLNS41F+sKPA==} + peerDependencies: + react: ^16.8.0 || ^17.0.0 || ^18.0.0 + dependencies: + react: 18.2.0 + dev: false + + /util-deprecate@1.0.2: + resolution: {integrity: sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==} + + /v8-compile-cache-lib@3.0.1: + resolution: {integrity: sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg==} + + /v8-to-istanbul@9.2.0: + resolution: {integrity: sha512-/EH/sDgxU2eGxajKdwLCDmQ4FWq+kpi3uCmBGpw1xJtnAxEjlD8j8PEiGWpCIMIs3ciNAgH0d3TTJiUkYzyZjA==} + engines: {node: '>=10.12.0'} + dependencies: + '@jridgewell/trace-mapping': 0.3.25 + '@types/istanbul-lib-coverage': 2.0.6 + convert-source-map: 2.0.0 + dev: true + + /valtio@1.11.2(@types/react@18.2.67)(react@18.2.0): + resolution: {integrity: sha512-1XfIxnUXzyswPAPXo1P3Pdx2mq/pIqZICkWN60Hby0d9Iqb+MEIpqgYVlbflvHdrp2YR/q3jyKWRPJJ100yxaw==} + engines: {node: '>=12.20.0'} + peerDependencies: + '@types/react': '>=16.8' + react: '>=16.8' + peerDependenciesMeta: + '@types/react': + optional: true + react: + optional: true + dependencies: + '@types/react': 18.2.67 + proxy-compare: 2.5.1 + react: 18.2.0 + use-sync-external-store: 1.2.0(react@18.2.0) + dev: false + + /victory-vendor@36.9.2: + resolution: {integrity: sha512-PnpQQMuxlwYdocC8fIJqVXvkeViHYzotI+NJrCuav0ZYFoq912ZHBk3mCeuj+5/VpodOjPe1z0Fk2ihgzlXqjQ==} + dependencies: + '@types/d3-array': 3.2.1 + '@types/d3-ease': 3.0.2 + '@types/d3-interpolate': 3.0.4 + '@types/d3-scale': 4.0.8 + '@types/d3-shape': 3.1.6 + '@types/d3-time': 3.0.3 + '@types/d3-timer': 3.0.2 + d3-array: 3.2.4 + d3-ease: 3.0.1 + d3-interpolate: 3.0.1 + d3-scale: 4.0.2 + d3-shape: 3.2.0 + d3-time: 3.1.0 + d3-timer: 3.0.1 + dev: false + + /vite@5.1.6(@types/node@18.19.26): + resolution: {integrity: sha512-yYIAZs9nVfRJ/AiOLCA91zzhjsHUgMjB+EigzFb6W2XTLO8JixBCKCjvhKZaye+NKYHCrkv3Oh50dH9EdLU2RA==} + engines: {node: ^18.0.0 || >=20.0.0} + hasBin: true + peerDependencies: + '@types/node': ^18.0.0 || >=20.0.0 + less: '*' + lightningcss: ^1.21.0 + sass: '*' + stylus: '*' + sugarss: '*' + terser: ^5.4.0 + peerDependenciesMeta: + '@types/node': + optional: true + less: + optional: true + lightningcss: + optional: true + sass: + optional: true + stylus: + optional: true + sugarss: + optional: true + terser: + optional: true + dependencies: + '@types/node': 18.19.26 + esbuild: 0.19.12 + postcss: 8.4.37 + rollup: 4.13.0 + optionalDependencies: + fsevents: 2.3.3 + dev: true + + /vlq@2.0.4: + resolution: {integrity: sha512-aodjPa2wPQFkra1G8CzJBTHXhgk3EVSwxSWXNPr1fgdFLUb8kvLV1iEb6rFgasIsjP82HWI6dsb5Io26DDnasA==} + dev: false + + /walker@1.0.8: + resolution: {integrity: sha512-ts/8E8l5b7kY0vlWLewOkDXMmPdLcVV4GmOQLyxuSswIJsweeFZtAsMF7k1Nszz+TYBQrlYRmzOnr398y1JemQ==} + dependencies: + makeerror: 1.0.12 + dev: true + + /which-module@2.0.1: + resolution: {integrity: sha512-iBdZ57RDvnOR9AGBhML2vFZf7h8vmBjhoaZqODJBFWHVtKkDmKuHai3cx5PgVMrX5YDNp27AofYbAwctSS+vhQ==} + dev: false + + /which@2.0.2: + resolution: {integrity: sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==} + engines: {node: '>= 8'} + hasBin: true + dependencies: + isexe: 2.0.0 + + /wrap-ansi@6.2.0: + resolution: {integrity: sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==} + engines: {node: '>=8'} + dependencies: + ansi-styles: 4.3.0 + string-width: 4.2.3 + strip-ansi: 6.0.1 + dev: false + + /wrap-ansi@7.0.0: + resolution: {integrity: sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==} + engines: {node: '>=10'} + dependencies: + ansi-styles: 4.3.0 + string-width: 4.2.3 + strip-ansi: 6.0.1 + + /wrap-ansi@8.1.0: + resolution: {integrity: sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==} + engines: {node: '>=12'} + dependencies: + ansi-styles: 6.2.1 + string-width: 5.1.2 + strip-ansi: 7.1.0 + + /wrappy@1.0.2: + resolution: {integrity: sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==} + + /write-file-atomic@4.0.2: + resolution: {integrity: sha512-7KxauUdBmSdWnmpaGFg+ppNjKF8uNLry8LyzjauQDOVONfFLNKrKvQOxZ/VuTIcS/gge/YNahf5RIIQWTSarlg==} + engines: {node: ^12.13.0 || ^14.15.0 || >=16.0.0} + dependencies: + imurmurhash: 0.1.4 + signal-exit: 3.0.7 + dev: true + + /ws@7.5.3: + resolution: {integrity: sha512-kQ/dHIzuLrS6Je9+uv81ueZomEwH0qVYstcAQ4/Z93K8zeko9gtAbttJWzoC5ukqXY1PpoouV3+VSOqEAFt5wg==} + engines: {node: '>=8.3.0'} + peerDependencies: + bufferutil: ^4.0.1 + utf-8-validate: ^5.0.2 + peerDependenciesMeta: + bufferutil: + optional: true + utf-8-validate: + optional: true + dev: false + + /ws@7.5.9: + resolution: {integrity: sha512-F+P9Jil7UiSKSkppIiD94dN07AwvFixvLIj1Og1Rl9GGMuNipJnV9JzjD6XuqmAeiswGvUmNLjr5cFuXwNS77Q==} + engines: {node: '>=8.3.0'} + peerDependencies: + bufferutil: ^4.0.1 + utf-8-validate: ^5.0.2 + peerDependenciesMeta: + bufferutil: + optional: true + utf-8-validate: + optional: true + dev: false + + /y18n@4.0.3: + resolution: {integrity: sha512-JKhqTOwSrqNA1NY5lSztJ1GrBiUodLMmIZuLiDaMRJ+itFd+ABVE8XBjOvIWL+rSqNDC74LCSFmlb/U4UZ4hJQ==} + dev: false + + /y18n@5.0.8: + resolution: {integrity: sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==} + engines: {node: '>=10'} + dev: true + + /yallist@3.1.1: + resolution: {integrity: sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==} + + /yallist@4.0.0: + resolution: {integrity: sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==} + dev: true + + /yaml@2.4.1: + resolution: {integrity: sha512-pIXzoImaqmfOrL7teGUBt/T7ZDnyeGBWyXQBvOVhLkWLN37GXv8NMLK406UY6dS51JfcQHsmcW5cJ441bHg6Lg==} + engines: {node: '>= 14'} + hasBin: true + + /yargs-parser@18.1.3: + resolution: {integrity: sha512-o50j0JeToy/4K6OZcaQmW6lyXXKhq7csREXcDwk2omFPJEwUNOVtJKvmDr9EI1fAJZUyZcRF7kxGBWmRXudrCQ==} + engines: {node: '>=6'} + dependencies: + camelcase: 5.3.1 + decamelize: 1.2.0 + dev: false + + /yargs-parser@21.1.1: + resolution: {integrity: sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==} + engines: {node: '>=12'} + dev: true + + /yargs@15.4.1: + resolution: {integrity: sha512-aePbxDmcYW++PaqBsJ+HYUFwCdv4LVvdnhBy78E57PIor8/OVvhMrADFFEDh8DHDFRv/O9i3lPhsENjO7QX0+A==} + engines: {node: '>=8'} + dependencies: + cliui: 6.0.0 + decamelize: 1.2.0 + find-up: 4.1.0 + get-caller-file: 2.0.5 + require-directory: 2.1.1 + require-main-filename: 2.0.0 + set-blocking: 2.0.0 + string-width: 4.2.3 + which-module: 2.0.1 + y18n: 4.0.3 + yargs-parser: 18.1.3 + dev: false + + /yargs@17.7.2: + resolution: {integrity: sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==} + engines: {node: '>=12'} + dependencies: + cliui: 8.0.1 + escalade: 3.1.2 + get-caller-file: 2.0.5 + require-directory: 2.1.1 + string-width: 4.2.3 + y18n: 5.0.8 + yargs-parser: 21.1.1 + dev: true + + /yn@3.1.1: + resolution: {integrity: sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==} + engines: {node: '>=6'} + + /yocto-queue@0.1.0: + resolution: {integrity: sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==} + engines: {node: '>=10'} + dev: true + + /zod@3.22.4: + resolution: {integrity: sha512-iC+8Io04lddc+mVqQ9AZ7OQ2MrUKGN+oIQyq1vemgt46jwCwLfhq7/pwnBnNXXXZb8VTVLKwp9EDkx+ryxIWmg==} diff --git a/ui/postcss.config.cjs b/ui/postcss.config.cjs new file mode 100644 index 00000000..33ad091d --- /dev/null +++ b/ui/postcss.config.cjs @@ -0,0 +1,6 @@ +module.exports = { + plugins: { + tailwindcss: {}, + autoprefixer: {}, + }, +} diff --git a/ui/public/fonts/Algo.ttf b/ui/public/fonts/Algo.ttf new file mode 100644 index 00000000..98989777 Binary files /dev/null and b/ui/public/fonts/Algo.ttf differ diff --git a/ui/public/fonts/Algo.woff b/ui/public/fonts/Algo.woff new file mode 100644 index 00000000..2c9e70be Binary files /dev/null and b/ui/public/fonts/Algo.woff differ diff --git a/ui/public/fonts/Algo.woff2 b/ui/public/fonts/Algo.woff2 new file mode 100644 index 00000000..0b2898cc Binary files /dev/null and b/ui/public/fonts/Algo.woff2 differ diff --git a/ui/public/index.html b/ui/public/index.html new file mode 100644 index 00000000..990372ae --- /dev/null +++ b/ui/public/index.html @@ -0,0 +1,34 @@ + + + + + + + + + + React App + + + +
+ + + diff --git a/ui/public/robots.txt b/ui/public/robots.txt new file mode 100644 index 00000000..e9e57dc4 --- /dev/null +++ b/ui/public/robots.txt @@ -0,0 +1,3 @@ +# https://www.robotstxt.org/robotstxt.html +User-agent: * +Disallow: diff --git a/ui/src/api/algod.ts b/ui/src/api/algod.ts new file mode 100644 index 00000000..c29de1b1 --- /dev/null +++ b/ui/src/api/algod.ts @@ -0,0 +1,45 @@ +import * as algokit from '@algorandfoundation/algokit-utils' +import { AlgoAmount } from '@algorandfoundation/algokit-utils/types/amount' +import { AccountBalance, AccountInformation, Asset, Exclude } from '@/interfaces/algod' +import { getAlgodConfigFromViteEnvironment } from '@/utils/network/getAlgoClientConfigs' + +const algodConfig = getAlgodConfigFromViteEnvironment() +const algodClient = algokit.getAlgoClient({ + server: algodConfig.server, + port: algodConfig.port, + token: algodConfig.token, +}) + +export async function getAccountInformation( + address: string, + exclude: Exclude = 'none', +): Promise { + const accountInfo = await algodClient.accountInformation(address).exclude(exclude).do() + return accountInfo as AccountInformation +} + +export async function getAccountBalance( + address: string, + availableBalance = false, +): Promise { + const accountInfo = await getAccountInformation(address, 'all') + + return availableBalance ? accountInfo.amount - accountInfo['min-balance'] : accountInfo.amount +} + +export async function getAsset(assetId: number): Promise { + const asset = await algodClient.getAssetByID(assetId).do() + return asset as Asset +} + +export async function fetchBalance(address: string | null): Promise { + if (!address) { + throw new Error('No address provided') + } + const accountInfo = await getAccountInformation(address, 'all') + return { + amount: AlgoAmount.MicroAlgos(accountInfo.amount), + available: AlgoAmount.MicroAlgos(accountInfo.amount - accountInfo['min-balance']), + minimum: AlgoAmount.MicroAlgos(accountInfo['min-balance']), + } +} diff --git a/ui/src/api/contracts.ts b/ui/src/api/contracts.ts new file mode 100644 index 00000000..9481b011 --- /dev/null +++ b/ui/src/api/contracts.ts @@ -0,0 +1,947 @@ +import * as algokit from '@algorandfoundation/algokit-utils' +import { TransactionSignerAccount } from '@algorandfoundation/algokit-utils/types/account' +import { AlgoAmount } from '@algorandfoundation/algokit-utils/types/amount' +import algosdk from 'algosdk' +import { StakingPoolClient } from '@/contracts/StakingPoolClient' +import { ValidatorRegistryClient } from '@/contracts/ValidatorRegistryClient' +import { StakedInfo, StakerPoolData, StakerValidatorData } from '@/interfaces/staking' +import { + Constraints, + MbrAmounts, + NodePoolAssignmentConfig, + PoolInfo, + RawConstraints, + RawNodePoolAssignmentConfig, + RawPoolTokenPayoutRatios, + RawPoolsInfo, + RawValidatorConfig, + RawValidatorState, + Validator, + ValidatorPoolKey, +} from '@/interfaces/validator' +import { + transformNodePoolAssignment, + transformValidatorConfig, + transformValidatorData, +} from '@/utils/contracts' +import { getAlgodConfigFromViteEnvironment } from '@/utils/network/getAlgoClientConfigs' +import { getRetiAppIdFromViteEnvironment } from '@/utils/env' +import { getActiveWalletAddress } from '@/utils/wallets' + +const algodConfig = getAlgodConfigFromViteEnvironment() +const algodClient = algokit.getAlgoClient({ + server: algodConfig.server, + port: algodConfig.port, + token: algodConfig.token, +}) + +const RETI_APP_ID = getRetiAppIdFromViteEnvironment() + +export const makeSimulateValidatorClient = (activeAddress: string) => { + return new ValidatorRegistryClient( + { + sender: { addr: activeAddress, signer: algosdk.makeEmptyTransactionSigner() }, + resolveBy: 'id', + id: RETI_APP_ID, + }, + algodClient, + ) +} + +export const makeValidatorClient = (signer: algosdk.TransactionSigner, activeAddress: string) => { + return new ValidatorRegistryClient( + { + sender: { signer, addr: activeAddress } as TransactionSignerAccount, + resolveBy: 'id', + id: RETI_APP_ID, + }, + algodClient, + ) +} + +export const makeSimulateStakingPoolClient = ( + poolAppId: number | bigint, + activeAddress: string, +) => { + return new StakingPoolClient( + { + sender: { addr: activeAddress, signer: algosdk.makeEmptyTransactionSigner() }, + resolveBy: 'id', + id: poolAppId, + }, + algodClient, + ) +} + +export const makeStakingPoolClient = ( + poolAppId: number | bigint, + signer: algosdk.TransactionSigner, + activeAddress: string, +) => { + return new StakingPoolClient( + { + sender: { signer, addr: activeAddress } as TransactionSignerAccount, + resolveBy: 'id', + id: poolAppId, + }, + algodClient, + ) +} + +export function callGetNumValidators(validatorClient: ValidatorRegistryClient) { + return validatorClient + .compose() + .getNumValidators({}) + .simulate({ allowEmptySignatures: true, allowUnnamedResources: true }) +} + +export function callGetValidatorConfig( + validatorId: number | bigint, + validatorClient: ValidatorRegistryClient, +) { + return validatorClient + .compose() + .getValidatorConfig({ validatorId }) + .simulate({ allowEmptySignatures: true, allowUnnamedResources: true }) +} + +export function callGetValidatorState( + validatorId: number | bigint, + validatorClient: ValidatorRegistryClient, +) { + return validatorClient + .compose() + .getValidatorState({ validatorId }) + .simulate({ allowEmptySignatures: true, allowUnnamedResources: true }) +} + +export async function fetchValidator( + validatorId: string | number | bigint, + client?: ValidatorRegistryClient, +) { + try { + const activeAddress = getActiveWalletAddress() + + if (!activeAddress) { + throw new Error('No active wallet found') + } + + const validatorClient = client || makeSimulateValidatorClient(activeAddress) + + const [config, state, validatorPoolData, poolTokenPayoutRatios, nodePoolAssignments] = + await Promise.all([ + callGetValidatorConfig(Number(validatorId), validatorClient), + callGetValidatorState(Number(validatorId), validatorClient), + callGetPools(Number(validatorId), validatorClient), + callGetTokenPayoutRatio(Number(validatorId), validatorClient), + callGetNodePoolAssignments(Number(validatorId), validatorClient), + ]) + + const rawConfig = config.returns?.[0] as RawValidatorConfig + const rawState = state.returns?.[0] as RawValidatorState + const rawPoolsInfo = validatorPoolData.returns?.[0] as RawPoolsInfo + const rawPoolTokenPayoutRatios = poolTokenPayoutRatios.returns?.[0] as RawPoolTokenPayoutRatios + const rawNodePoolAssignment = nodePoolAssignments.returns?.[0] as RawNodePoolAssignmentConfig + + if ( + !rawConfig || + !rawState || + !rawPoolsInfo || + !rawPoolTokenPayoutRatios || + !rawNodePoolAssignment + ) { + throw new ValidatorNotFoundError(`Validator with id "${Number(validatorId)}" not found!`) + } + + // Transform raw data to Validator object + const validator: Validator = transformValidatorData( + rawConfig, + rawState, + rawPoolsInfo, + rawPoolTokenPayoutRatios, + rawNodePoolAssignment, + ) + return validator + } catch (error) { + console.error(error) + throw error + } +} + +export async function fetchValidators(client?: ValidatorRegistryClient) { + try { + const activeAddress = getActiveWalletAddress() + + if (!activeAddress) { + throw new Error('No active wallet found') + } + + const validatorClient = client || makeSimulateValidatorClient(activeAddress) + + // App call to fetch total number of validators + const numValidatorsResponse = await callGetNumValidators(validatorClient) + + const numValidators = numValidatorsResponse.returns![0] + + if (!numValidators) { + return [] + } + + const allValidators: Array = [] + const batchSize = 10 + + for (let i = 0; i < numValidators; i += batchSize) { + const batchPromises = Array.from( + { length: Math.min(batchSize, Number(numValidators) - i) }, + (_, index) => { + const validatorId = i + index + 1 + return fetchValidator(validatorId, validatorClient) + }, + ) + + // Run batch calls in parallel, then filter out any undefined results + const batchResults = (await Promise.all(batchPromises)).filter( + (validator) => validator !== undefined, + ) as Array + + allValidators.push(...batchResults) + } + + return allValidators + } catch (error) { + console.error(error) + throw error + } +} + +export class ValidatorNotFoundError extends Error {} + +export function callGetNodePoolAssignments( + validatorId: number | bigint, + validatorClient: ValidatorRegistryClient, +) { + return validatorClient + .compose() + .getNodePoolAssignments({ validatorId }) + .simulate({ allowEmptySignatures: true, allowUnnamedResources: true }) +} + +export async function fetchNodePoolAssignments( + validatorId: string | number | bigint, +): Promise { + try { + const activeAddress = getActiveWalletAddress() + + if (!activeAddress) { + throw new Error('No active wallet found') + } + + const validatorClient = makeSimulateValidatorClient(activeAddress) + + const nodePoolAssignmentResponse = await callGetNodePoolAssignments( + Number(validatorId), + validatorClient, + ) + + const rawNodePoolAssignmentConfig: RawNodePoolAssignmentConfig | undefined = + nodePoolAssignmentResponse.returns![0] + + if (!rawNodePoolAssignmentConfig) { + throw new Error('No node pool assignment found') + } + + const nodePoolAssignmentConfig = transformNodePoolAssignment(rawNodePoolAssignmentConfig) + return nodePoolAssignmentConfig + } catch (error) { + console.error(error) + throw error + } +} + +export function callGetTokenPayoutRatio( + validatorId: number | bigint, + validatorClient: ValidatorRegistryClient, +) { + return validatorClient + .compose() + .getTokenPayoutRatio({ validatorId }) + .simulate({ allowEmptySignatures: true, allowUnnamedResources: true }) +} + +export async function fetchTokenPayoutRatio(validatorId: string | number | bigint) { + try { + const activeAddress = getActiveWalletAddress() + + if (!activeAddress) { + throw new Error('No active wallet found') + } + + const validatorClient = makeSimulateValidatorClient(activeAddress) + + const result = await callGetTokenPayoutRatio(Number(validatorId), validatorClient) + + return result.returns![0] + } catch (error) { + console.error(error) + throw error + } +} + +export function callGetMbrAmounts(validatorClient: ValidatorRegistryClient) { + return validatorClient + .compose() + .getMbrAmounts({}) + .simulate({ allowEmptySignatures: true, allowUnnamedResources: true }) +} + +export async function fetchMbrAmounts(client?: ValidatorRegistryClient): Promise { + try { + const activeAddress = getActiveWalletAddress() + + if (!activeAddress) { + throw new Error('No active wallet found') + } + + const validatorClient = client || makeSimulateValidatorClient(activeAddress) + + const mbrAmountsResponse = await callGetMbrAmounts(validatorClient) + const [validatorMbr, poolMbr, poolInitMbr, stakerMbr] = mbrAmountsResponse.returns![0] + + return { + validatorMbr: Number(validatorMbr), + poolMbr: Number(poolMbr), + poolInitMbr: Number(poolInitMbr), + stakerMbr: Number(stakerMbr), + } + } catch (error) { + console.error(error) + throw error + } +} + +export async function addStakingPool( + validatorId: number, + nodeNum: number, + poolMbr: number, + signer: algosdk.TransactionSigner, + activeAddress: string, +): Promise { + const validatorClient = makeValidatorClient(signer, activeAddress) + + const validatorAppRef = await validatorClient.appClient.getAppReference() + const suggestedParams = await algodClient.getTransactionParams().do() + + const payValidatorAddPoolMbr = algosdk.makePaymentTxnWithSuggestedParamsFromObject({ + from: activeAddress, + to: validatorAppRef.appAddress, + amount: poolMbr, + suggestedParams, + }) + + const addPoolResponse = await validatorClient + .compose() + .gas({}, { note: '1' }) + .gas({}, { note: '2' }) + .addPool( + { + mbrPayment: { + transaction: payValidatorAddPoolMbr, + signer: { signer, addr: activeAddress } as TransactionSignerAccount, + }, + validatorId, + nodeNum, + }, + { + sendParams: { + fee: AlgoAmount.MicroAlgos(2000), + }, + }, + ) + .execute({ populateAppCallResources: true }) + + const [valId, poolId, poolAppId] = addPoolResponse.returns![2] + + const stakingPool: ValidatorPoolKey = { + poolId: Number(poolId), + poolAppId: Number(poolAppId), + validatorId: Number(valId), + } + + return stakingPool +} + +export async function initStakingPoolStorage( + poolAppId: number, + poolInitMbr: number, + optInRewardToken: boolean, + signer: algosdk.TransactionSigner, + activeAddress: string, +): Promise { + const suggestedParams = await algodClient.getTransactionParams().do() + + const mbrAmount = optInRewardToken ? poolInitMbr + AlgoAmount.Algos(0.1).microAlgos : poolInitMbr + + const payPoolInitStorageMbr = algosdk.makePaymentTxnWithSuggestedParamsFromObject({ + from: activeAddress, + to: algosdk.getApplicationAddress(poolAppId), + amount: mbrAmount, + suggestedParams, + }) + + const stakingPoolClient = makeStakingPoolClient(poolAppId, signer, activeAddress) + + await stakingPoolClient + .compose() + .gas({}, { note: '1' }) + .gas({}, { note: '2' }) + .initStorage( + { + mbrPayment: { + transaction: payPoolInitStorageMbr, + signer: { signer, addr: activeAddress } as TransactionSignerAccount, + }, + }, + { sendParams: { fee: AlgoAmount.MicroAlgos(3000) } }, + ) + .execute({ populateAppCallResources: true }) +} + +export async function doesStakerNeedToPayMbr( + activeAddress: string, + client?: ValidatorRegistryClient, +): Promise { + const validatorClient = client || makeSimulateValidatorClient(activeAddress) + + const result = await validatorClient + .compose() + .doesStakerNeedToPayMbr({ + staker: activeAddress, + }) + .simulate({ allowEmptySignatures: true, allowUnnamedResources: true }) + + return result.returns![0] +} + +export async function addStake( + validatorId: number, + stakeAmount: number, // microalgos + signer: algosdk.TransactionSigner, + activeAddress: string, +): Promise { + const validatorClient = makeValidatorClient(signer, activeAddress) + + const validatorAppRef = await validatorClient.appClient.getAppReference() + const suggestedParams = await algodClient.getTransactionParams().do() + + const stakeTransferPayment = algosdk.makePaymentTxnWithSuggestedParamsFromObject({ + from: activeAddress, + to: validatorAppRef.appAddress, + amount: stakeAmount, + suggestedParams, + }) + + const simulateValidatorClient = makeSimulateValidatorClient(activeAddress) + + const simulateResults = await simulateValidatorClient + .compose() + .gas({}) + .addStake( + { + stakedAmountPayment: { + transaction: stakeTransferPayment, + signer: { addr: activeAddress, signer: algosdk.makeEmptyTransactionSigner() }, + }, + validatorId, + valueToVerify: 0, + }, + { sendParams: { fee: AlgoAmount.MicroAlgos(240_000) } }, + ) + .simulate({ allowEmptySignatures: true, allowUnnamedResources: true }) + + stakeTransferPayment.group = undefined + + // @todo: switch to Joe's new method(s) + const feesAmount = AlgoAmount.MicroAlgos( + 2000 + 1000 * ((simulateResults.simulateResponse.txnGroups[0].appBudgetAdded as number) / 700), + ) + + const results = await validatorClient + .compose() + .gas({}) + .addStake( + { + stakedAmountPayment: { + transaction: stakeTransferPayment, + signer: { signer, addr: activeAddress } as TransactionSignerAccount, + }, + validatorId, + valueToVerify: 0, + }, + { sendParams: { fee: feesAmount } }, + ) + .execute({ populateAppCallResources: true }) + + const [valId, poolId, poolAppId] = results.returns![1] + + return { + poolId: Number(poolId), + poolAppId: Number(poolAppId), + validatorId: Number(valId), + } +} + +export async function callFindPoolForStaker( + validatorId: number | bigint, + staker: string, + amountToStake: number | bigint, + validatorClient: ValidatorRegistryClient, +) { + return validatorClient + .compose() + .findPoolForStaker({ validatorId, staker, amountToStake }) + .simulate({ allowEmptySignatures: true, allowUnnamedResources: true }) +} + +export async function isNewStakerToValidator( + validatorId: number | bigint, + staker: string, + minEntryStake: number | bigint, +) { + const activeAddress = getActiveWalletAddress() + + if (!activeAddress) { + throw new Error('No active wallet found') + } + + const validatorClient = makeSimulateValidatorClient(activeAddress) + const result = await callFindPoolForStaker(validatorId, staker, minEntryStake, validatorClient) + + const [_, isNewStaker] = result.returns![0] + + return isNewStaker +} + +export async function callGetStakedPoolsForAccount( + staker: string, + validatorClient: ValidatorRegistryClient, +) { + return validatorClient + .compose() + .getStakedPoolsForAccount({ staker }) + .simulate({ allowEmptySignatures: true, allowUnnamedResources: true }) +} + +export async function fetchStakedPoolsForAccount(staker: string): Promise { + try { + const activeAddress = getActiveWalletAddress() + + if (!activeAddress) { + throw new Error('No active wallet found') + } + + const validatorClient = makeSimulateValidatorClient(activeAddress) + const result = await callGetStakedPoolsForAccount(staker, validatorClient) + + const stakedPools = result.returns![0] + + return stakedPools.map(([validatorId, poolId, poolAppId]) => ({ + validatorId: Number(validatorId), + poolId: Number(poolId), + poolAppId: Number(poolAppId), + })) + } catch (error) { + console.error(error) + throw error + } +} + +export async function callGetStakerInfo(staker: string, stakingPoolClient: StakingPoolClient) { + return stakingPoolClient + .compose() + .getStakerInfo({ staker }) + .simulate({ allowEmptySignatures: true, allowUnnamedResources: true }) +} + +export async function fetchStakerPoolData( + poolKey: ValidatorPoolKey, + staker: string, +): Promise { + try { + const activeAddress = getActiveWalletAddress() + + if (!activeAddress) { + throw new Error('No active wallet found') + } + + const stakingPoolClient = makeSimulateStakingPoolClient(poolKey.poolAppId, activeAddress) + + const result = await callGetStakerInfo(staker, stakingPoolClient) + + const [account, balance, totalRewarded, rewardTokenBalance, entryTime] = result.returns![0] + + const stakedInfo: StakedInfo = { + account, + balance: Number(balance), + totalRewarded: Number(totalRewarded), + rewardTokenBalance: Number(rewardTokenBalance), + entryTime: Number(entryTime), + } + + const stakerPoolData: StakerPoolData = { + ...stakedInfo, + poolKey, + } + + return stakerPoolData + } catch (error) { + console.error(error) + throw error + } +} + +export async function fetchStakerValidatorData(staker: string): Promise { + try { + const activeAddress = getActiveWalletAddress() + + if (!activeAddress) { + throw new Error('No active wallet found') + } + + const poolKeys = await fetchStakedPoolsForAccount(staker) + + const allPools: Array = [] + const batchSize = 10 + + for (let i = 0; i < poolKeys.length; i += batchSize) { + const batchPromises = Array.from( + { length: Math.min(batchSize, poolKeys.length - i) }, + (_, index) => { + const poolKey = poolKeys[i + index] + return fetchStakerPoolData(poolKey, staker) + }, + ) + + // Run batch calls in parallel + const batchResults = await Promise.all(batchPromises) + + allPools.push(...batchResults) + } + + // Group pool stakes by validatorId and sum up balances + const stakerValidatorData = allPools.reduce((acc, pool) => { + const { validatorId } = pool.poolKey + + // Check if we already have an entry for this validator + const existingData = acc.find((data) => data.validatorId === validatorId) + + if (existingData) { + // staker is in another pool for this validator, update validator totals + existingData.balance += pool.balance + existingData.totalRewarded += pool.totalRewarded + existingData.rewardTokenBalance += pool.rewardTokenBalance + existingData.entryTime = Math.min(existingData.entryTime, pool.entryTime) + existingData.pools.push(pool) // add pool to existing StakerPoolData[] + } else { + // First pool for this validator, add new entry + acc.push({ + validatorId, + balance: pool.balance, + totalRewarded: pool.totalRewarded, + rewardTokenBalance: pool.rewardTokenBalance, + entryTime: pool.entryTime, + pools: [pool], // add pool to new StakerPoolData[] + }) + } + + return acc + }, [] as StakerValidatorData[]) + + return stakerValidatorData + } catch (error) { + console.error(error) + throw error + } +} + +export async function callGetProtocolConstraints(validatorClient: ValidatorRegistryClient) { + return validatorClient + .compose() + .getProtocolConstraints({}) + .simulate({ allowEmptySignatures: true, allowUnnamedResources: true }) +} + +export async function fetchProtocolConstraints( + client?: ValidatorRegistryClient, +): Promise { + try { + const activeAddress = getActiveWalletAddress() + + if (!activeAddress) { + throw new Error('No active wallet found') + } + + const validatorClient = client || makeSimulateValidatorClient(activeAddress) + + const result = await callGetProtocolConstraints(validatorClient) + + const [ + payoutMinsMin, + payoutMinsMax, + commissionPctMin, + commissionPctMax, + minEntryStake, + maxAlgoPerPool, + maxAlgoPerValidator, + saturationThreshold, + maxNodes, + maxPoolsPerNode, + maxStakersPerPool, + ] = result.returns![0] as RawConstraints + + return { + payoutMinsMin: Number(payoutMinsMin), + payoutMinsMax: Number(payoutMinsMax), + commissionPctMin: Number(commissionPctMin), + commissionPctMax: Number(commissionPctMax), + minEntryStake, + maxAlgoPerPool, + maxAlgoPerValidator, + saturationThreshold, + maxNodes: Number(maxNodes), + maxPoolsPerNode: Number(maxPoolsPerNode), + maxStakersPerPool: Number(maxStakersPerPool), + } + } catch (error) { + console.error(error) + throw error + } +} + +export async function removeStake( + poolAppId: number | bigint, + amountToUnstake: number, + signer: algosdk.TransactionSigner, + activeAddress: string, +) { + const stakingPoolSimulateClient = makeSimulateStakingPoolClient(poolAppId, activeAddress) + + const simulateResult = await stakingPoolSimulateClient + .compose() + .gas({}, { note: '1', sendParams: { fee: AlgoAmount.MicroAlgos(0) } }) + .gas({}, { note: '2', sendParams: { fee: AlgoAmount.MicroAlgos(0) } }) + .removeStake( + { + amountToUnstake, + }, + { sendParams: { fee: AlgoAmount.MicroAlgos(240_000) } }, + ) + .simulate({ allowEmptySignatures: true, allowUnnamedResources: true }) + + // @todo: switch to Joe's new method(s) + const feesAmount = AlgoAmount.MicroAlgos( + 1000 * + Math.floor( + ((simulateResult.simulateResponse.txnGroups[0].appBudgetAdded as number) + 699) / 700, + ), + ) + + const stakingPoolClient = makeStakingPoolClient(poolAppId, signer, activeAddress) + + await stakingPoolClient + .compose() + .gas({}, { note: '1', sendParams: { fee: AlgoAmount.MicroAlgos(0) } }) + .gas({}, { note: '2', sendParams: { fee: AlgoAmount.MicroAlgos(0) } }) + .removeStake( + { + amountToUnstake, + }, + { sendParams: { fee: feesAmount } }, + ) + .execute({ populateAppCallResources: true }) +} + +export async function epochBalanceUpdate( + poolAppId: number | bigint, + signer: algosdk.TransactionSigner, + activeAddress: string, +): Promise { + try { + const stakingPoolSimulateClient = makeSimulateStakingPoolClient(poolAppId, activeAddress) + + const simulateResult = await stakingPoolSimulateClient + .compose() + .gas({}, { note: '1' }) + .gas({}, { note: '2' }) + .epochBalanceUpdate({}, { sendParams: { fee: AlgoAmount.MicroAlgos(240_000) } }) + .simulate({ allowEmptySignatures: true, allowUnnamedResources: true }) + + // @todo: switch to Joe's new method(s) + const feesAmount = AlgoAmount.MicroAlgos( + 3000 + 1000 * ((simulateResult.simulateResponse.txnGroups[0].appBudgetAdded as number) / 700), + ) + + const stakingPoolClient = makeStakingPoolClient(poolAppId, signer, activeAddress) + + await stakingPoolClient + .compose() + .gas({}, { note: '1', sendParams: { fee: AlgoAmount.MicroAlgos(0) } }) + .gas({}, { note: '2', sendParams: { fee: AlgoAmount.MicroAlgos(0) } }) + .epochBalanceUpdate({}, { sendParams: { fee: feesAmount } }) + .execute({ populateAppCallResources: true }) + } catch (error) { + console.error(error) + throw error + } +} + +export async function callGetPoolInfo( + poolKey: ValidatorPoolKey, + validatorClient: ValidatorRegistryClient, +) { + return validatorClient + .compose() + .getPoolInfo({ poolKey: [poolKey.validatorId, poolKey.poolId, poolKey.poolAppId] }) + .simulate({ allowEmptySignatures: true, allowUnnamedResources: true }) +} + +export async function fetchPoolInfo( + poolKey: ValidatorPoolKey, + client?: ValidatorRegistryClient, +): Promise { + try { + const activeAddress = getActiveWalletAddress() + + if (!activeAddress) { + throw new Error('No active wallet found') + } + + const validatorClient = client || makeSimulateValidatorClient(activeAddress) + + const result = await callGetPoolInfo(poolKey, validatorClient) + + const [poolAppId, totalStakers, totalAlgoStaked] = result.returns![0] + + return { + poolAppId: Number(poolAppId), + totalStakers: Number(totalStakers), + totalAlgoStaked, + } + } catch (error) { + console.error(error) + throw error + } +} + +export async function callGetPools( + validatorId: number | bigint, + validatorClient: ValidatorRegistryClient, +) { + return validatorClient + .compose() + .getPools({ validatorId }) + .simulate({ allowEmptySignatures: true, allowUnnamedResources: true }) +} + +export async function fetchValidatorPools( + validatorId: string | number, + client?: ValidatorRegistryClient, +): Promise { + try { + const activeAddress = getActiveWalletAddress() + + if (!activeAddress) { + throw new Error('No active wallet found') + } + + const validatorClient = client || makeSimulateValidatorClient(activeAddress) + + const result = await callGetPools(Number(validatorId), validatorClient) + + const poolsInfo = result.returns![0] + + return poolsInfo.map(([poolAppId, totalStakers, totalAlgoStaked]) => ({ + poolAppId: Number(poolAppId), + totalStakers: Number(totalStakers), + totalAlgoStaked, + })) + } catch (error) { + console.error(error) + throw error + } +} + +export async function fetchMaxAvailableToStake(validatorId: string | number): Promise { + try { + const activeAddress = getActiveWalletAddress() + + if (!activeAddress) { + throw new Error('No active wallet found') + } + + const validatorClient = makeSimulateValidatorClient(activeAddress) + + const validatorConfigResult = await callGetValidatorConfig(Number(validatorId), validatorClient) + const rawConfig = validatorConfigResult.returns![0] + + const validatorConfig = transformValidatorConfig(rawConfig) + + const poolsInfo: PoolInfo[] = await fetchValidatorPools(validatorId) + + // For each pool, subtract the totalAlgoStaked from maxAlgoPerPool and return the highest value + const maxAvailableToStake = poolsInfo.reduce((acc, pool) => { + const availableToStake = Number(validatorConfig.maxAlgoPerPool) - Number(pool.totalAlgoStaked) + return availableToStake > acc ? availableToStake : acc + }, 0) + + return maxAvailableToStake + } catch (error) { + console.error(error) + throw error + } +} + +export async function claimTokens( + pools: PoolInfo[], + signer: algosdk.TransactionSigner, + activeAddress: string, +) { + const atc1 = new algosdk.AtomicTransactionComposer() + + for (const pool of pools) { + const client = makeSimulateStakingPoolClient(pool.poolAppId, activeAddress) + await client.gas({}, { note: '1', sendParams: { atc: atc1, fee: AlgoAmount.MicroAlgos(0) } }) + await client.gas({}, { note: '2', sendParams: { atc: atc1, fee: AlgoAmount.MicroAlgos(0) } }) + await client.claimTokens({}, { sendParams: { atc: atc1, fee: AlgoAmount.MicroAlgos(240_000) } }) + } + + const simulateResult = await atc1.simulate( + algodClient, + new algosdk.modelsv2.SimulateRequest({ + txnGroups: [], + allowEmptySignatures: true, + allowUnnamedResources: true, + }), + ) + + // @todo: switch to Joe's new method(s) + const feesAmount = AlgoAmount.MicroAlgos( + 1000 * + Math.floor( + ((simulateResult.simulateResponse.txnGroups[0].appBudgetAdded as number) + 699) / 700, + ), + ) + + const atc2 = new algosdk.AtomicTransactionComposer() + + for (const pool of pools) { + const client = makeStakingPoolClient(pool.poolAppId, signer, activeAddress) + await client.gas({}, { note: '1', sendParams: { atc: atc2, fee: AlgoAmount.MicroAlgos(0) } }) + await client.gas({}, { note: '2', sendParams: { atc: atc2, fee: AlgoAmount.MicroAlgos(0) } }) + await client.claimTokens({}, { sendParams: { atc: atc2, fee: feesAmount } }) + } + + await algokit.sendAtomicTransactionComposer( + { atc: atc2, sendParams: { populateAppCallResources: true } }, + algodClient, + ) +} diff --git a/ui/src/api/nfd.ts b/ui/src/api/nfd.ts new file mode 100644 index 00000000..6d3a1d16 --- /dev/null +++ b/ui/src/api/nfd.ts @@ -0,0 +1,20 @@ +import { AxiosRequestConfig } from 'axios' +import { Nfd, NfdGetNFDParams } from '@/interfaces/nfd' +import axios from '@/lib/axios' + +export async function fetchNfd( + nameOrID: string | number, + params?: NfdGetNFDParams, + options?: AxiosRequestConfig, +): Promise { + const { data: nfd } = await axios.get(`/nfd/${nameOrID}`, { + ...options, + params: { ...params, ...options?.params }, + }) + + if (!nfd || !nfd.appID || !nfd.name) { + throw new Error('NFD not found') + } + + return nfd +} diff --git a/ui/src/api/queries.ts b/ui/src/api/queries.ts new file mode 100644 index 00000000..aebc2ebd --- /dev/null +++ b/ui/src/api/queries.ts @@ -0,0 +1,63 @@ +import { queryOptions } from '@tanstack/react-query' +import { fetchBalance } from '@/api/algod' +import { + fetchMbrAmounts, + fetchNodePoolAssignments, + fetchProtocolConstraints, + fetchValidator, + fetchValidators, +} from '@/api/contracts' +import { fetchNfd } from '@/api/nfd' +import { NfdGetNFDParams } from '@/interfaces/nfd' + +export const validatorsQueryOptions = queryOptions({ + queryKey: ['validators'], + queryFn: () => fetchValidators(), + // staleTime: Infinity, + retry: false, +}) + +export const validatorQueryOptions = (validatorId: number | string) => + queryOptions({ + queryKey: ['validator', String(validatorId)], + queryFn: () => fetchValidator(validatorId), + // staleTime: Infinity, + retry: false, + }) + +export const poolAssignmentQueryOptions = (validatorId: number | string, enabled = true) => + queryOptions({ + queryKey: ['pool-assignments', String(validatorId)], + queryFn: () => fetchNodePoolAssignments(validatorId), + enabled, + }) + +export const mbrQueryOptions = queryOptions({ + queryKey: ['mbr'], + queryFn: () => fetchMbrAmounts(), + staleTime: Infinity, +}) + +export const constraintsQueryOptions = queryOptions({ + queryKey: ['constraints'], + queryFn: () => fetchProtocolConstraints(), + staleTime: Infinity, +}) + +export const balanceQueryOptions = (address: string | null) => + queryOptions({ + queryKey: ['account-balance', address], + queryFn: () => fetchBalance(address), + enabled: !!address, + refetchInterval: 1000 * 30, + }) + +export const nfdQueryOptions = ( + nameOrId: string | number, + params: NfdGetNFDParams = { view: 'brief' }, +) => + queryOptions({ + queryKey: ['nfd', String(nameOrId), params], + queryFn: () => fetchNfd(String(nameOrId), params), + enabled: !!nameOrId, + }) diff --git a/ui/src/assets/logo.svg b/ui/src/assets/logo.svg new file mode 100644 index 00000000..71694760 --- /dev/null +++ b/ui/src/assets/logo.svg @@ -0,0 +1 @@ + diff --git a/ui/src/components/AddPoolModal.tsx b/ui/src/components/AddPoolModal.tsx new file mode 100644 index 00000000..7c36423e --- /dev/null +++ b/ui/src/components/AddPoolModal.tsx @@ -0,0 +1,216 @@ +import { zodResolver } from '@hookform/resolvers/zod' +import { useQuery, useQueryClient } from '@tanstack/react-query' +import { useRouter } from '@tanstack/react-router' +import { useWallet } from '@txnlab/use-wallet-react' +import * as React from 'react' +import { useForm } from 'react-hook-form' +import { toast } from 'sonner' +import { z } from 'zod' +import { addStakingPool, fetchMbrAmounts, initStakingPoolStorage } from '@/api/contracts' +import { poolAssignmentQueryOptions } from '@/api/queries' +import { NodeSelect } from '@/components/NodeSelect' +import { Button } from '@/components/ui/button' +import { + Dialog, + DialogContent, + DialogDescription, + DialogHeader, + DialogTitle, +} from '@/components/ui/dialog' +import { + Form, + FormDescription, + FormField, + FormItem, + FormLabel, + FormMessage, +} from '@/components/ui/form' +import { NodePoolAssignmentConfig, Validator } from '@/interfaces/validator' +import { findFirstAvailableNode } from '@/utils/contracts' +import { cn } from '@/utils/ui' + +const formSchema = z.object({ + nodeNum: z.string(), +}) + +interface AddPoolModalProps { + validator: Validator | null + setValidator: React.Dispatch> + poolAssignment?: NodePoolAssignmentConfig +} + +export function AddPoolModal({ + validator, + setValidator, + poolAssignment: poolAssignmentProp, +}: AddPoolModalProps) { + const [isSigning, setIsSigning] = React.useState(false) + + const queryClient = useQueryClient() + const router = useRouter() + const { transactionSigner, activeAddress } = useWallet() + + const form = useForm>({ + resolver: zodResolver(formSchema), + mode: 'onChange', + defaultValues: { + nodeNum: '1', + }, + }) + + const { isValid } = form.formState + + const assignmentQuery = useQuery(poolAssignmentQueryOptions(validator?.id || '', !!validator)) + const poolAssignment = assignmentQuery.data || poolAssignmentProp + + const defaultNodeNum = React.useMemo(() => { + if (!validator?.config.poolsPerNode || !poolAssignment) { + return '1' + } + const nodeNum = findFirstAvailableNode(poolAssignment, validator.config.poolsPerNode) + return nodeNum?.toString() || '1' + }, [poolAssignment, validator?.config.poolsPerNode]) + + React.useEffect(() => { + form.setValue('nodeNum', defaultNodeNum) + }, [defaultNodeNum, form.setValue]) + + const handleOpenChange = (open: boolean) => { + if (!open) { + setValidator(null) + form.reset({ nodeNum: '1' }) + } + } + + const toastIdRef = React.useRef(`toast-${Date.now()}-${Math.random()}`) + const TOAST_ID = toastIdRef.current + + const onSubmit = async (data: z.infer) => { + const toastId = `${TOAST_ID}-add-pool` + + try { + setIsSigning(true) + + if (!activeAddress) { + throw new Error('No active address') + } + + const { poolMbr, poolInitMbr } = await queryClient.ensureQueryData({ + queryKey: ['mbr'], + queryFn: () => fetchMbrAmounts(), + }) + + toast.loading('Sign transactions to add staking pool...', { id: toastId }) + + const stakingPool = await addStakingPool( + validator!.id, + Number(data.nodeNum), + poolMbr, + transactionSigner, + activeAddress, + ) + + const optInRewardToken = + validator?.config.rewardTokenId !== 0 && validator?.state.numPools === 0 + + await initStakingPoolStorage( + stakingPool.poolAppId, + poolInitMbr, + optInRewardToken, + transactionSigner, + activeAddress, + ) + + toast.success(`Staking pool ${stakingPool.poolId} created!`, { + id: toastId, + duration: 5000, + }) + + queryClient.setQueryData(['validator', String(validator!.id)], (prevData) => { + if (!prevData) { + return prevData + } + + return { + ...prevData, + state: { + ...prevData.state, + numPools: prevData.state.numPools + 1, + }, + } + }) + + queryClient.setQueryData(['validators'], (prevData) => { + if (!prevData) { + return prevData + } + + return prevData.map((validator: Validator) => { + if (validator.id === validator!.id) { + return { + ...validator, + state: { + ...validator.state, + numPools: validator.state.numPools + 1, + }, + } + } + + return validator + }) + }) + + router.invalidate() + queryClient.invalidateQueries({ queryKey: ['pool-assignments', validator!.id] }) + } catch (error) { + toast.error('Failed to create staking pool', { id: toastId }) + console.error(error) + } finally { + setIsSigning(false) + setValidator(null) + } + } + + return ( + + event.preventDefault()}> + + Add a Pool + + Create and fund a new staking pool for Validator {validator?.id} + + +
+
+ + ( + + Select Node + {poolAssignment && !!validator && ( + + )} + + Select a node with an available slot (max: {validator?.config.poolsPerNode}) + + + + )} + /> + + + +
+
+
+ ) +} diff --git a/ui/src/components/AddStakeModal.tsx b/ui/src/components/AddStakeModal.tsx new file mode 100644 index 00000000..c53ac8bf --- /dev/null +++ b/ui/src/components/AddStakeModal.tsx @@ -0,0 +1,392 @@ +import { AlgoAmount } from '@algorandfoundation/algokit-utils/types/amount' +import { zodResolver } from '@hookform/resolvers/zod' +import { useQuery, useQueryClient } from '@tanstack/react-query' +import { useRouter } from '@tanstack/react-router' +import { useWallet } from '@txnlab/use-wallet-react' +import { ArrowUpRight } from 'lucide-react' +import * as React from 'react' +import { useForm } from 'react-hook-form' +import { toast } from 'sonner' +import { z } from 'zod' +import { getAccountBalance } from '@/api/algod' +import { + addStake, + doesStakerNeedToPayMbr, + fetchMaxAvailableToStake, + isNewStakerToValidator, +} from '@/api/contracts' +import { mbrQueryOptions } from '@/api/queries' +import { AlgoDisplayAmount } from '@/components/AlgoDisplayAmount' +import { Button } from '@/components/ui/button' +import { + Dialog, + DialogContent, + DialogDescription, + DialogHeader, + DialogTitle, +} from '@/components/ui/dialog' +import { + Form, + FormControl, + FormDescription, + FormField, + FormItem, + FormLabel, + FormMessage, +} from '@/components/ui/form' +import { Input } from '@/components/ui/input' +import { StakerPoolData, StakerValidatorData } from '@/interfaces/staking' +import { Constraints, Validator } from '@/interfaces/validator' +import { dayjs } from '@/utils/dayjs' +import { formatAlgoAmount } from '@/utils/format' + +interface AddStakeModalProps { + validator: Validator | null + setValidator: React.Dispatch> + constraints?: Constraints +} + +export function AddStakeModal({ validator, setValidator, constraints }: AddStakeModalProps) { + const [isSigning, setIsSigning] = React.useState(false) + + const queryClient = useQueryClient() + const router = useRouter() + const { transactionSigner, activeAddress } = useWallet() + + // @todo: this will be available globally from wallet menu + const availableBalanceQuery = useQuery({ + queryKey: ['available-balance', activeAddress], + queryFn: () => getAccountBalance(activeAddress!, true), + enabled: !!activeAddress, + refetchInterval: 30000, + }) + const availableBalance = availableBalanceQuery.data || 0 + + // @todo: make this a custom hook, call from higher up and pass down as prop + const mbrQuery = useQuery(mbrQueryOptions) + const stakerMbr = mbrQuery.data?.stakerMbr || 0 + + // @todo: make this a custom hook, call from higher up and pass down as prop + const mbrRequiredQuery = useQuery({ + queryKey: ['mbr-required', activeAddress], + queryFn: () => doesStakerNeedToPayMbr(activeAddress!), + enabled: !!activeAddress, + staleTime: Infinity, + }) + const mbrRequired = mbrRequiredQuery.data || false + const mbrAmount = mbrRequired ? stakerMbr : 0 + + const poolMaximumQuery = useQuery({ + queryKey: ['pool-max', validator?.id], + queryFn: () => fetchMaxAvailableToStake(validator!.id), + enabled: !!validator, + }) + const poolMaximumStake = poolMaximumQuery.data || Number(constraints?.maxAlgoPerPool) + + const stakerMaximumStake = React.useMemo(() => { + const estimatedFee = AlgoAmount.MicroAlgos(240_000).microAlgos + return Math.max(0, availableBalance - mbrAmount - estimatedFee) + }, [availableBalance, mbrAmount]) + + const maximumStake = Math.min(stakerMaximumStake, poolMaximumStake || stakerMaximumStake) + + const formSchema = z.object({ + amountToStake: z + .string() + .refine((val) => val !== '', { + message: 'Required field', + }) + .refine((val) => !isNaN(Number(val)) && parseFloat(val) > 0, { + message: 'Invalid amount', + }) + .superRefine((val, ctx) => { + const algoAmount = parseFloat(val) + const amountToStake = AlgoAmount.Algos(algoAmount).microAlgos + + if (validator) { + const minimumStake = Number(validator.config.minEntryStake) + + if (amountToStake < minimumStake) { + ctx.addIssue({ + code: z.ZodIssueCode.too_small, + minimum: minimumStake, + type: 'number', + inclusive: true, + message: `Minimum stake is ${formatAlgoAmount(AlgoAmount.MicroAlgos(minimumStake).algos)} ALGO`, + }) + } + + if (amountToStake > stakerMaximumStake) { + ctx.addIssue({ + code: z.ZodIssueCode.too_big, + maximum: stakerMaximumStake, + type: 'number', + inclusive: true, + message: 'Exceeds available balance', + }) + } + + if (poolMaximumStake !== undefined) { + if (amountToStake > poolMaximumStake) { + ctx.addIssue({ + code: z.ZodIssueCode.too_big, + maximum: poolMaximumStake, + type: 'number', + inclusive: true, + message: `Exceeds limit for validator's pools`, + }) + } + } + } + }), + }) + + const form = useForm>({ + resolver: zodResolver(formSchema), + mode: 'onChange', + defaultValues: { + amountToStake: '', + }, + }) + + const { errors, isValid } = form.formState + + const handleOpenChange = (open: boolean) => { + if (!open) { + setValidator(null) + form.reset() + } + } + + const handleSetMaxAmount = (event: React.MouseEvent) => { + event.preventDefault() + + form.setValue('amountToStake', AlgoAmount.MicroAlgos(maximumStake).algos.toString(), { + shouldValidate: true, + }) + } + + const toastIdRef = React.useRef(`toast-${Date.now()}-${Math.random()}`) + const TOAST_ID = toastIdRef.current + + const onSubmit = async (data: z.infer) => { + const toastId = `${TOAST_ID}-add-stake` + + try { + setIsSigning(true) + + if (!activeAddress) { + throw new Error('No wallet connected') + } + + const amountToStake = AlgoAmount.Algos(Number(data.amountToStake)).microAlgos + const totalAmount = mbrRequired ? amountToStake + stakerMbr : amountToStake + + const isNewStaker = await isNewStakerToValidator( + validator!.id, + activeAddress, + Number(validator!.config.minEntryStake), + ) + + toast.loading('Sign transactions to add stake...', { id: toastId }) + + const poolKey = await addStake(validator!.id, totalAmount, transactionSigner, activeAddress) + + toast.success( +
+ + + Added to + Pool {poolKey.poolId} on Validator {poolKey.validatorId} + +
, + { + id: toastId, + duration: 5000, + }, + ) + + queryClient.setQueryData( + ['stakes', { staker: activeAddress }], + (prevData) => { + if (!prevData) { + return prevData + } + + const poolData: StakerPoolData = { + poolKey, + account: activeAddress, + balance: amountToStake, + totalRewarded: 0, + rewardTokenBalance: 0, + entryTime: dayjs().unix(), + } + + // Check if the staker already has a stake with the validator + const existingValidatorData = prevData.find( + (data) => data.validatorId === poolKey.validatorId, + ) + + if (existingValidatorData) { + // Check if the staker already has a stake in the pool + const existingPool = existingValidatorData.pools.find( + (pool) => pool.poolKey.poolId === poolKey.poolId, + ) + + if (existingPool) { + // Update the existing pool + return prevData.map((data) => { + if (data.validatorId === poolKey.validatorId) { + return { + ...data, + balance: data.balance + amountToStake, + pools: data.pools.map((pool) => { + if (pool.poolKey.poolId === poolKey.poolId) { + return { + ...pool, + balance: pool.balance + amountToStake, + } + } + + return pool + }), + } + } + + return data + }) + } + + // Add the new pool to the existing validator stake data + return prevData.map((data) => { + if (data.validatorId === poolKey.validatorId) { + return { + ...data, + balance: data.balance + amountToStake, + pools: [...data.pools, poolData], + } + } + + return data + }) + } + + // Add a new validator stake entry + return [ + ...prevData, + { + validatorId: poolKey.validatorId, + balance: amountToStake, + totalRewarded: 0, + rewardTokenBalance: 0, + entryTime: dayjs().unix(), + pools: [poolData], + }, + ] + }, + ) + + queryClient.setQueryData(['validator', String(validator!.id)], (prevData) => { + if (!prevData) { + return prevData + } + + return { + ...prevData, + state: { + ...prevData.state, + totalStakers: isNewStaker + ? prevData.state.totalStakers + 1 + : prevData.state.totalStakers, + totalAlgoStaked: prevData.state.totalAlgoStaked + BigInt(amountToStake), + }, + } + }) + + queryClient.setQueryData(['validators'], (prevData) => { + if (!prevData) { + return prevData + } + + return prevData.map((v: Validator) => { + if (v.id === validator!.id) { + return { + ...v, + state: { + ...v.state, + totalStakers: isNewStaker ? v.state.totalStakers + 1 : v.state.totalStakers, + totalAlgoStaked: v.state.totalAlgoStaked + BigInt(amountToStake), + }, + } + } + + return v + }) + }) + + router.invalidate() + } catch (error) { + toast.error('Failed to add stake to pool', { id: toastId }) + console.error(error) + } finally { + setIsSigning(false) + setValidator(null) + } + } + + return ( + + + + Add Stake to Validator {validator?.id} + + This will send your ALGO to the validator and stake it in one of their pools. + + +
+
+ + ( + + Amount to Stake + +
+ + +
+
+ + Enter the amount you wish to stake.{' '} + {mbrRequired && stakerMbr && ( + + NOTE: First time stakers will need to pay{' '} + in fees. + + )} + +
+ {errors.amountToStake?.message} +
+
+ )} + /> + + + +
+
+
+ ) +} diff --git a/ui/src/components/AddValidatorForm.tsx b/ui/src/components/AddValidatorForm.tsx new file mode 100644 index 00000000..ce9f3d67 --- /dev/null +++ b/ui/src/components/AddValidatorForm.tsx @@ -0,0 +1,607 @@ +import * as algokit from '@algorandfoundation/algokit-utils' +import { TransactionSignerAccount } from '@algorandfoundation/algokit-utils/types/account' +import { AlgoAmount } from '@algorandfoundation/algokit-utils/types/amount' +import { zodResolver } from '@hookform/resolvers/zod' +import { useNavigate } from '@tanstack/react-router' +import { useWallet } from '@txnlab/use-wallet-react' +import algosdk from 'algosdk' +import { isAxiosError } from 'axios' +import { Check, MonitorCheck } from 'lucide-react' +import * as React from 'react' +import { useForm } from 'react-hook-form' +import { toast } from 'sonner' +import { useDebouncedCallback } from 'use-debounce' +import { z } from 'zod' +import { makeSimulateValidatorClient, makeValidatorClient } from '@/api/contracts' +import { fetchNfd } from '@/api/nfd' +import { Button } from '@/components/ui/button' +import { + Card, + CardContent, + CardDescription, + CardFooter, + CardHeader, + CardTitle, +} from '@/components/ui/card' +import { + Form, + FormControl, + FormDescription, + FormField, + FormItem, + FormLabel, + FormMessage, +} from '@/components/ui/form' +import { Input } from '@/components/ui/input' +import { Constraints, ValidatorConfig } from '@/interfaces/validator' +import { getAddValidatorFormSchema } from '@/utils/contracts' +import { getAlgodConfigFromViteEnvironment } from '@/utils/network/getAlgoClientConfigs' +import { cn } from '@/utils/ui' + +const algodConfig = getAlgodConfigFromViteEnvironment() +const algodClient = algokit.getAlgoClient({ + server: algodConfig.server, + port: algodConfig.port, + token: algodConfig.token, +}) + +interface AddValidatorFormProps { + constraints: Constraints +} + +export function AddValidatorForm({ constraints }: AddValidatorFormProps) { + const [nfdAppId, setNfdAppId] = React.useState(0) + const [isFetchingAppId, setIsFetchingAppId] = React.useState(false) + const [isSigning, setIsSigning] = React.useState(false) + + const { transactionSigner, activeAddress } = useWallet() + + const navigate = useNavigate({ from: '/add' }) + + const formSchema = getAddValidatorFormSchema(constraints) + + const form = useForm>({ + resolver: zodResolver(formSchema), + mode: 'onBlur', + defaultValues: { + owner: '', + manager: '', + nfdForInfo: '', + entryGatingType: '', + entryGatingValue: '', + gatingAssetMinBalance: '', + rewardTokenId: '', + rewardPerPayout: '', + payoutEveryXMins: '', + percentToValidator: '', + validatorCommissionAddress: '', + minEntryStake: '', + maxAlgoPerPool: '', + poolsPerNode: '', + sunsettingOn: '', + sunsettingTo: '', + }, + }) + + const { errors, isValid } = form.formState + + const fetchNfdForInfo = async (value: string) => { + setIsFetchingAppId(true) + + try { + const nfd = await fetchNfd(value, { view: 'tiny' }) + + // If we have an app id, clear error if it exists + form.clearErrors('nfdForInfo') + setNfdAppId(nfd.appID!) + } catch (error) { + if (isAxiosError(error) && error.response) { + if (error.response.status !== 404) { + console.error(error.message) + } + } else { + // Handle non-HTTP errors + console.error(error) + } + form.setError('nfdForInfo', { type: 'manual', message: 'NFD app id not found' }) + } finally { + setIsFetchingAppId(false) + } + } + + const debouncedCheck = useDebouncedCallback(async (value) => { + const isValid = await form.trigger('nfdForInfo') + if (isValid) { + fetchNfdForInfo(value) + } + }, 500) + + const toastIdRef = React.useRef(`toast-${Date.now()}-${Math.random()}`) + const TOAST_ID = toastIdRef.current + + const onSubmit = async (values: z.infer) => { + const toastId = `${TOAST_ID}-validator` + + try { + setIsSigning(true) + + if (!activeAddress) { + throw new Error('No active address') + } + + const validatorClient = makeValidatorClient(transactionSigner, activeAddress) + + toast.loading('Sign transactions to add validator...', { id: toastId }) + + const validatorAppRef = await validatorClient.appClient.getAppReference() + + const [validatorMbr] = ( + await validatorClient + .compose() + .getMbrAmounts( + {}, + { + sender: { + addr: activeAddress as string, + signer: algosdk.makeEmptyTransactionSigner(), + }, + }, + ) + .simulate({ allowEmptySignatures: true, allowUnnamedResources: true }) + ).returns![0] + + const suggestedParams = await algodClient.getTransactionParams().do() + + const payValidatorMbr = algosdk.makePaymentTxnWithSuggestedParamsFromObject({ + from: activeAddress, + to: validatorAppRef.appAddress, + amount: Number(validatorMbr), + suggestedParams, + }) + + const validatorConfig: ValidatorConfig = { + id: 0, // id not known yet + owner: values.owner, + manager: values.manager, + nfdForInfo: nfdAppId, + entryGatingType: 0, + entryGatingValue: new Uint8Array(32), + gatingAssetMinBalance: BigInt(values.gatingAssetMinBalance || 0), + rewardTokenId: Number(values.rewardTokenId || 0), + rewardPerPayout: BigInt(values.rewardPerPayout || 0), + payoutEveryXMins: Number(values.payoutEveryXMins), + percentToValidator: Number(values.percentToValidator) * 10000, + validatorCommissionAddress: values.validatorCommissionAddress, + minEntryStake: BigInt(AlgoAmount.Algos(Number(values.minEntryStake)).microAlgos), + maxAlgoPerPool: BigInt(AlgoAmount.Algos(Number(values.maxAlgoPerPool)).microAlgos), + poolsPerNode: Number(values.poolsPerNode), + sunsettingOn: Number(values.sunsettingOn || 0), + sunsettingTo: Number(values.sunsettingTo || 0), + } + + const simulateValidatorClient = makeSimulateValidatorClient(activeAddress) + + const simulateResult = await simulateValidatorClient + .compose() + .addValidator( + { + mbrPayment: { + transaction: payValidatorMbr, + signer: { addr: activeAddress, signer: algosdk.makeEmptyTransactionSigner() }, + }, + nfdName: values.nfdForInfo || '', + config: [ + validatorConfig.id, + validatorConfig.owner, + validatorConfig.manager, + validatorConfig.nfdForInfo, + validatorConfig.entryGatingType, + validatorConfig.entryGatingValue, + validatorConfig.gatingAssetMinBalance, + validatorConfig.rewardTokenId, + validatorConfig.rewardPerPayout, + validatorConfig.payoutEveryXMins, + validatorConfig.percentToValidator, + validatorConfig.validatorCommissionAddress, + validatorConfig.minEntryStake, + validatorConfig.maxAlgoPerPool, + validatorConfig.poolsPerNode, + validatorConfig.sunsettingOn, + validatorConfig.sunsettingTo, + ], + }, + { sendParams: { fee: AlgoAmount.MicroAlgos(240_000) } }, + ) + .simulate({ allowEmptySignatures: true, allowUnnamedResources: true }) + + payValidatorMbr.group = undefined + + // @todo: switch to Joe's new method(s) + const feesAmount = AlgoAmount.MicroAlgos( + 1000 * + Math.floor( + ((simulateResult.simulateResponse.txnGroups[0].appBudgetAdded as number) + 699) / 700, + ), + ) + + const result = await validatorClient + .compose() + .addValidator( + { + mbrPayment: { + transaction: payValidatorMbr, + signer: { + signer: transactionSigner, + addr: activeAddress, + } as TransactionSignerAccount, + }, + nfdName: values.nfdForInfo || '', + config: [ + validatorConfig.id, + validatorConfig.owner, + validatorConfig.manager, + validatorConfig.nfdForInfo, + validatorConfig.entryGatingType, + validatorConfig.entryGatingValue, + validatorConfig.gatingAssetMinBalance, + validatorConfig.rewardTokenId, + validatorConfig.rewardPerPayout, + validatorConfig.payoutEveryXMins, + validatorConfig.percentToValidator, + validatorConfig.validatorCommissionAddress, + validatorConfig.minEntryStake, + validatorConfig.maxAlgoPerPool, + validatorConfig.poolsPerNode, + validatorConfig.sunsettingOn, + validatorConfig.sunsettingTo, + ], + }, + { sendParams: { fee: feesAmount } }, + ) + .execute({ populateAppCallResources: true }) + + const validatorId = Number(result.returns![0]) + + toast.success( +
+ + Validator {validatorId} created! +
, + { + id: toastId, + duration: 5000, + }, + ) + + navigate({ to: '/dashboard' }) + } catch (error) { + toast.error('Failed to create validator', { id: toastId }) + console.error(error) + } + } + + return ( +
+ + + + New validator configuration + + Fields marked with * are required + + + +
+ ( + + + Owner address * + + + + + + Account that controls config (cold wallet recommended) + + {errors.owner?.message} + + )} + /> + + ( + + + Manager address * + + + + + + Account that triggers payouts and keyreg transactions (must sign transactions) + + {errors.manager?.message} + + )} + /> + + ( + + Associated NFD +
+ + 0 ? 'pr-10' : '', + )} + placeholder="" + autoComplete="new-password" + spellCheck="false" + {...field} + onChange={(e) => { + field.onChange(e) // Inform react-hook-form of the change + setNfdAppId(0) // Reset NFD app id + debouncedCheck(e.target.value) // Perform debounced validation + }} + /> + +
0 ? 'opacity-100' : 'opacity-0', + 'pointer-events-none absolute inset-y-0 right-0 flex items-center pr-3', + )} + > + {isFetchingAppId ? ( + + ) : nfdAppId ? ( + + ) : null} +
+
+ + + NFD which the validator uses to describe their validator pool (optional) + + {errors.nfdForInfo?.message} +
+ )} + /> + + ( + + Creator NFT Minimum Balance + + + + + Minimum required balance of the asset described above + + {errors.gatingAssetMinBalance?.message} + + )} + /> + + ( + + Reward Token ID + + + + {errors.rewardTokenId?.message} + + )} + /> + + ( + + Reward Token Amount Per Payout + + + + {errors.rewardPerPayout?.message} + + )} + /> + + ( + + + Epoch length * + + + + + Frequency of rewards payouts (in minutes) + {errors.payoutEveryXMins?.message} + + )} + /> + + ( + + + Validator commission percent * + + + + + + Payout percentage w/ up to four decimals (e.g., 5.0001) + + {errors.percentToValidator?.message} + + )} + /> + + ( + + + Commission address * + + + + + + Account that receives validator commission payments + + {errors.validatorCommissionAddress?.message} + + )} + /> + + ( + + + Minimum entry stake * + + + + + Minimum stake required to enter a pool + {errors.minEntryStake?.message} + + )} + /> + + ( + + Maximum total stake + + + + + Maximum stake allowed per pool (to keep under incentive limits) + + {errors.maxAlgoPerPool?.message} + + )} + /> + + ( + + + Pools per node * + + + + + + Number of pools to allow per node (max of 3 is recommended) + + {errors.poolsPerNode?.message} + + )} + /> + + ( + + Sunset Time + + + + Timestamp when validator will sunset + {errors.sunsettingOn?.message} + + )} + /> + + ( + + Sunset To (Validator ID) + + + + + Validator ID that the validator is moving to (if known) + + {errors.sunsettingTo?.message} + + )} + /> +
+
+ + {/* */} + + +
+
+ + ) +} diff --git a/ui/src/components/AlgoDisplayAmount.tsx b/ui/src/components/AlgoDisplayAmount.tsx new file mode 100644 index 00000000..fef8c465 --- /dev/null +++ b/ui/src/components/AlgoDisplayAmount.tsx @@ -0,0 +1,60 @@ +import Big from 'big.js' +import { AlgoSymbol } from '@/components/AlgoSymbol' +import { convertFromBaseUnits, formatWithPrecision } from '@/utils/format' +import { cn } from '@/utils/ui' + +interface AlgoDisplayAmountProps { + amount: number | bigint | string + microalgos?: boolean + trim?: boolean + maxLength?: number + compactPrecision?: number + mutedRemainder?: boolean + className?: string +} + +export function AlgoDisplayAmount({ + amount, + microalgos = false, + trim = true, + maxLength, + compactPrecision = 1, + mutedRemainder = false, + className = '', +}: AlgoDisplayAmountProps) { + const classes = cn('whitespace-nowrap', className) + const numAmount = typeof amount === 'string' ? parseFloat(amount) : Number(amount) + + const formatted = microalgos + ? convertFromBaseUnits(numAmount, 6).toFixed(6) + : new Big(numAmount).toFixed(6) + + const parts = formatted.split('.') + + if (trim && parts.length === 2) { + parts[1] = parts[1].replace(/\.?0+$/, '') + } + + if (maxLength && parts.join('.').length > maxLength) { + return ( + + +  {formatWithPrecision(parseFloat(formatted), compactPrecision)} + + ) + } + + parts[0] = new Intl.NumberFormat().format(parseFloat(parts[0])) + + return ( + + +  {parts[0]} + {`.${parts[1]}`} + + ) +} diff --git a/ui/src/components/AlgoSymbol.tsx b/ui/src/components/AlgoSymbol.tsx new file mode 100644 index 00000000..19d9119b --- /dev/null +++ b/ui/src/components/AlgoSymbol.tsx @@ -0,0 +1,5 @@ +import { cn } from '@/utils/ui' + +export function AlgoSymbol({ className = '' }) { + return A +} diff --git a/ui/src/components/Connect.tsx b/ui/src/components/Connect.tsx new file mode 100644 index 00000000..b62ae070 --- /dev/null +++ b/ui/src/components/Connect.tsx @@ -0,0 +1,46 @@ +import { useWallet } from '@txnlab/use-wallet-react' +import * as React from 'react' +import { Button } from '@/components/ui/button' +import { + Dialog, + DialogContent, + DialogDescription, + DialogHeader, + DialogTitle, + DialogTrigger, +} from '@/components/ui/dialog' + +export function Connect() { + const [isOpen, setIsOpen] = React.useState(false) + const { wallets } = useWallet() + + return ( + + + + + + + Connect + + Connect your wallet to access your account and manage staking. + + +
+ {wallets?.map((wallet) => ( + + ))} +
+
+
+ ) +} diff --git a/ui/src/components/ConnectedMenu.tsx b/ui/src/components/ConnectedMenu.tsx new file mode 100644 index 00000000..6018a65d --- /dev/null +++ b/ui/src/components/ConnectedMenu.tsx @@ -0,0 +1,66 @@ +import { useWallet } from '@txnlab/use-wallet-react' +import { Copy } from 'lucide-react' +import { SelectAccount } from '@/components/SelectAccount' +import { Button } from '@/components/ui/button' +import { + DropdownMenu, + DropdownMenuContent, + DropdownMenuItem, + DropdownMenuSeparator, + DropdownMenuShortcut, + DropdownMenuTrigger, +} from '@/components/ui/dropdown-menu' +import { WalletBalance } from '@/components/WalletBalance' +import { copyToClipboard } from '@/utils/copyToClipboard' +import { ellipseAddress } from '@/utils/ellipseAddress' + +interface ConnectedMenuProps { + activeAddress: string +} + +export function ConnectedMenu({ activeAddress }: ConnectedMenuProps) { + const { activeWallet, activeAccount } = useWallet() + + return ( + + + + + {activeWallet && activeAccount && ( + +
+ {!!activeWallet && activeWallet.accounts.length > 1 ? ( + + ) : ( + {ellipseAddress(activeAddress)} + )} + +
+ +
+ +
+ + activeWallet?.disconnect()}> + Disconnect + ⇧D + +
+ )} +
+ ) +} diff --git a/ui/src/components/DataTableColumnHeader.tsx b/ui/src/components/DataTableColumnHeader.tsx new file mode 100644 index 00000000..14b5b5b9 --- /dev/null +++ b/ui/src/components/DataTableColumnHeader.tsx @@ -0,0 +1,60 @@ +import { ArrowDownIcon, ArrowUpIcon, CaretSortIcon, EyeNoneIcon } from '@radix-ui/react-icons' +import { Column } from '@tanstack/react-table' +import { Button } from '@/components/ui/button' +import { + DropdownMenu, + DropdownMenuContent, + DropdownMenuItem, + DropdownMenuSeparator, + DropdownMenuTrigger, +} from '@/components/ui/dropdown-menu' +import { cn } from '@/utils/ui' + +interface DataTableColumnHeaderProps extends React.HTMLAttributes { + column: Column + title: string +} + +export function DataTableColumnHeader({ + column, + title, + className, +}: DataTableColumnHeaderProps) { + if (!column.getCanSort()) { + return
{title}
+ } + + return ( +
+ + + + + + column.toggleSorting(false)}> + + Asc + + column.toggleSorting(true)}> + + Desc + + + column.toggleVisibility(false)}> + + Hide + + + +
+ ) +} diff --git a/ui/src/components/DataTableViewOptions.tsx b/ui/src/components/DataTableViewOptions.tsx new file mode 100644 index 00000000..97fa6cf9 --- /dev/null +++ b/ui/src/components/DataTableViewOptions.tsx @@ -0,0 +1,51 @@ +import { Table } from '@tanstack/react-table' +import { ChevronDownIcon } from 'lucide-react' +import { Button } from '@/components/ui/button' +import { + DropdownMenu, + DropdownMenuCheckboxItem, + DropdownMenuContent, + DropdownMenuLabel, + DropdownMenuSeparator, + DropdownMenuTrigger, +} from '@/components/ui/dropdown-menu' +import { cn } from '@/utils/ui' + +interface DataTableViewOptionsProps { + table: Table + className?: string +} + +export function DataTableViewOptions({ + table, + className = '', +}: DataTableViewOptionsProps) { + return ( + + + + + + Toggle columns + + {table + .getAllColumns() + .filter((column) => typeof column.accessorFn !== 'undefined' && column.getCanHide()) + .map((column) => { + return ( + column.toggleVisibility(!!value)} + > + {column.id} + + ) + })} + + + ) +} diff --git a/ui/src/components/ErrorBoundary.tsx b/ui/src/components/ErrorBoundary.tsx new file mode 100644 index 00000000..435bf61d --- /dev/null +++ b/ui/src/components/ErrorBoundary.tsx @@ -0,0 +1,46 @@ +import React, { ReactNode } from 'react' + +interface ErrorBoundaryProps { + children: ReactNode +} + +interface ErrorBoundaryState { + hasError: boolean + error: Error | null +} + +class ErrorBoundary extends React.Component { + constructor(props: ErrorBoundaryProps) { + super(props) + this.state = { hasError: false, error: null } + } + + static getDerivedStateFromError(error: Error): ErrorBoundaryState { + // Update state so the next render will show the fallback UI. + return { hasError: true, error: error } + } + + render(): ReactNode { + if (this.state.hasError) { + // You can render any custom fallback UI + return ( +
+
+
+

Error occured

+

+ {this.state.error?.message.includes('Attempt to get default algod configuration') + ? 'Please make sure to set up your environment variables correctly. Create a .env file based on .env.template and fill in the required values. This controls the network and credentials for connections with Algod and Indexer.' + : this.state.error?.message} +

+
+
+
+ ) + } + + return this.props.children + } +} + +export default ErrorBoundary diff --git a/ui/src/components/Layout.tsx b/ui/src/components/Layout.tsx new file mode 100644 index 00000000..55007847 --- /dev/null +++ b/ui/src/components/Layout.tsx @@ -0,0 +1,49 @@ +import { Link } from '@tanstack/react-router' +import { useWallet } from '@txnlab/use-wallet-react' +import { Crown } from 'lucide-react' +import { Connect } from '@/components/Connect' +import { ConnectedMenu } from '@/components/ConnectedMenu' +import { MobileMenu } from '@/components/MobileMenu' +import { ModeToggle } from '@/components/ModeToggle' +import { Navigation } from '@/components/Navigation' + +interface LayoutProps { + title?: string + children: React.ReactNode +} + +export function Layout({ children }: LayoutProps) { + const { activeAddress } = useWallet() + + return ( +
+ + +
{children}
+
+ ) +} diff --git a/ui/src/components/Meta.tsx b/ui/src/components/Meta.tsx new file mode 100644 index 00000000..951556e6 --- /dev/null +++ b/ui/src/components/Meta.tsx @@ -0,0 +1,14 @@ +import { Helmet } from 'react-helmet-async' + +interface MetaProps { + title?: string +} + +export function Meta({ title }: MetaProps) { + return ( + + {title ? `Réti Pooling | ${title}` : 'Réti Pooling'} + + + ) +} diff --git a/ui/src/components/MobileMenu.tsx b/ui/src/components/MobileMenu.tsx new file mode 100644 index 00000000..b83a65ce --- /dev/null +++ b/ui/src/components/MobileMenu.tsx @@ -0,0 +1,44 @@ +import * as React from 'react' +import { Menu } from 'lucide-react' +import { Navigation } from '@/components/Navigation' +import { Button } from '@/components/ui/button' +import { + Sheet, + SheetContent, + // SheetDescription, + SheetHeader, + SheetTitle, + SheetTrigger, +} from '@/components/ui/sheet' + +export function MobileMenu() { + const [isOpen, setIsOpen] = React.useState(false) + + return ( + + + + + + + Reti Staking + {/* + This is a placeholder for the mobile menu. It will contain the main navigation and other + actions. + */} + +
+ +
+
+
+ ) +} diff --git a/ui/src/components/ModeToggle.tsx b/ui/src/components/ModeToggle.tsx new file mode 100644 index 00000000..d20c13ae --- /dev/null +++ b/ui/src/components/ModeToggle.tsx @@ -0,0 +1,30 @@ +import { Moon, Sun } from 'lucide-react' +import { Button } from '@/components/ui/button' +import { + DropdownMenu, + DropdownMenuContent, + DropdownMenuItem, + DropdownMenuTrigger, +} from '@/components/ui/dropdown-menu' +import { useTheme } from '@/providers/ThemeProvider' + +export function ModeToggle() { + const { setTheme } = useTheme() + + return ( + + + + + + setTheme('light')}>Light + setTheme('dark')}>Dark + setTheme('system')}>System + + + ) +} diff --git a/ui/src/components/Navigation.tsx b/ui/src/components/Navigation.tsx new file mode 100644 index 00000000..9774f364 --- /dev/null +++ b/ui/src/components/Navigation.tsx @@ -0,0 +1,52 @@ +import { Link } from '@tanstack/react-router' +import { useWallet } from '@txnlab/use-wallet-react' +import { + NavigationMenu, + NavigationMenuItem, + NavigationMenuLink, + NavigationMenuList, + navigationMenuTriggerStyle, +} from '@/components/ui/navigation-menu' +import { cn } from '@/utils/ui' + +interface NavigationProps { + showHome?: boolean + orientation?: 'horizontal' | 'vertical' +} + +export function Navigation({ showHome = false, orientation = 'horizontal' }: NavigationProps) { + const { activeAddress } = useWallet() + + return ( + + + {showHome && ( + + + + Home + + + + )} + + {!!activeAddress && ( + <> + + + + Add Validator + + + + + )} + + + ) +} diff --git a/ui/src/components/NfdAvatar.tsx b/ui/src/components/NfdAvatar.tsx new file mode 100644 index 00000000..629f717f --- /dev/null +++ b/ui/src/components/NfdAvatar.tsx @@ -0,0 +1,17 @@ +import { Avatar, AvatarFallback, AvatarImage } from '@/components/ui/avatar' +import { Nfd } from '@/interfaces/nfd' +import { getNfdAvatarUrl } from '@/utils/nfd' + +interface NfdAvatarProps { + nfd: Nfd + className?: string +} + +export function NfdAvatar({ nfd, className = '' }: NfdAvatarProps) { + return ( + + + {nfd.name.slice(0, 2).toUpperCase()} + + ) +} diff --git a/ui/src/components/NfdThumbnail.tsx b/ui/src/components/NfdThumbnail.tsx new file mode 100644 index 00000000..9179ce2e --- /dev/null +++ b/ui/src/components/NfdThumbnail.tsx @@ -0,0 +1,32 @@ +import { useQuery } from '@tanstack/react-query' +import { nfdQueryOptions } from '@/api/queries' +import { getNfdProfileUrl } from '@/utils/nfd' +import { NfdAvatar } from '@/components/NfdAvatar' + +export interface NfdThumbnailProps { + nameOrId: string | number +} + +export function NfdThumbnail({ nameOrId }: NfdThumbnailProps) { + const { data: nfd, isLoading, error } = useQuery(nfdQueryOptions(nameOrId)) + + if (isLoading) { + return Loading... + } + + if (error || !nfd) { + return Error fetching balance + } + + return ( + + + {nfd.name} + + ) +} diff --git a/ui/src/components/NodeSelect.tsx b/ui/src/components/NodeSelect.tsx new file mode 100644 index 00000000..38f5fd93 --- /dev/null +++ b/ui/src/components/NodeSelect.tsx @@ -0,0 +1,41 @@ +import { + Select, + SelectContent, + SelectGroup, + SelectItem, + SelectTrigger, + SelectValue, +} from '@/components/ui/select' +import { NodePoolAssignmentConfig } from '@/interfaces/validator' +import { processNodePoolAssignment } from '@/utils/contracts' + +interface NodeSelectProps { + nodes: NodePoolAssignmentConfig + poolsPerNode: number + onValueChange: (value: string) => void + defaultValue: string +} + +export function NodeSelect({ nodes, poolsPerNode, onValueChange, defaultValue }: NodeSelectProps) { + const nodeInfo = processNodePoolAssignment(nodes, poolsPerNode) + + return ( + + ) +} diff --git a/ui/src/components/PageHeader.tsx b/ui/src/components/PageHeader.tsx new file mode 100644 index 00000000..3de8e0fc --- /dev/null +++ b/ui/src/components/PageHeader.tsx @@ -0,0 +1,12 @@ +export function PageHeader({ title }: { title?: string | null }) { + if (!title) return null + return ( +
+
+

+ {title} +

+
+
+ ) +} diff --git a/ui/src/components/PageMain.tsx b/ui/src/components/PageMain.tsx new file mode 100644 index 00000000..4fd4da0c --- /dev/null +++ b/ui/src/components/PageMain.tsx @@ -0,0 +1,9 @@ +import React from 'react' + +export function PageMain({ children }: { children: React.ReactNode }) { + return ( +
+
{children}
+
+ ) +} diff --git a/ui/src/components/SelectAccount.tsx b/ui/src/components/SelectAccount.tsx new file mode 100644 index 00000000..63e42321 --- /dev/null +++ b/ui/src/components/SelectAccount.tsx @@ -0,0 +1,32 @@ +import { WalletAccount } from '@txnlab/use-wallet-react' +import { + Select, + SelectContent, + SelectItem, + SelectTrigger, + SelectValue, +} from '@/components/ui/select' +import { ellipseAddress } from '@/utils/ellipseAddress' + +interface SelectAccountProps { + accounts: WalletAccount[] | undefined + activeAccount: WalletAccount | undefined + onValueChange: (value: string) => void +} + +export function SelectAccount({ accounts, activeAccount, onValueChange }: SelectAccountProps) { + return ( + + ) +} diff --git a/ui/src/components/StakingTable.tsx b/ui/src/components/StakingTable.tsx new file mode 100644 index 00000000..fb6fedd3 --- /dev/null +++ b/ui/src/components/StakingTable.tsx @@ -0,0 +1,302 @@ +import { useQuery, useQueryClient } from '@tanstack/react-query' +import { useRouter } from '@tanstack/react-router' +import { + ColumnDef, + ColumnFiltersState, + SortingState, + VisibilityState, + flexRender, + getCoreRowModel, + getFilteredRowModel, + getSortedRowModel, + useReactTable, +} from '@tanstack/react-table' +import { useWallet } from '@txnlab/use-wallet-react' +import dayjs from 'dayjs' +import { FlaskConical, MoreHorizontal } from 'lucide-react' +import * as React from 'react' +import { constraintsQueryOptions } from '@/api/queries' +import { AddStakeModal } from '@/components/AddStakeModal' +import { AlgoDisplayAmount } from '@/components/AlgoDisplayAmount' +import { DataTableColumnHeader } from '@/components/DataTableColumnHeader' +import { Button } from '@/components/ui/button' +import { + DropdownMenu, + DropdownMenuContent, + DropdownMenuGroup, + DropdownMenuItem, + DropdownMenuSeparator, + DropdownMenuTrigger, +} from '@/components/ui/dropdown-menu' +import { + Table, + TableBody, + TableCell, + TableHead, + TableHeader, + TableRow, +} from '@/components/ui/table' +import { UnstakeModal } from '@/components/UnstakeModal' +import { StakerValidatorData } from '@/interfaces/staking' +import { Validator } from '@/interfaces/validator' +import { canManageValidator, isStakingDisabled, isUnstakingDisabled } from '@/utils/contracts' +import { simulateEpoch } from '@/utils/development' +import { cn } from '@/utils/ui' + +interface StakingTableProps { + validators: Validator[] + stakesByValidator: StakerValidatorData[] + isLoading: boolean +} + +export function StakingTable({ validators, stakesByValidator, isLoading }: StakingTableProps) { + const [sorting, setSorting] = React.useState([]) + const [columnFilters, setColumnFilters] = React.useState([]) + const [columnVisibility, setColumnVisibility] = React.useState({}) + const [rowSelection, setRowSelection] = React.useState({}) + + const [addStakeValidator, setAddStakeValidator] = React.useState(null) + const [unstakeValidator, setUnstakeValidator] = React.useState(null) + + const { transactionSigner, activeAddress } = useWallet() + + const { data: constraints } = useQuery(constraintsQueryOptions) + + const router = useRouter() + const queryClient = useQueryClient() + + const columns: ColumnDef[] = [ + // { + // id: 'select', + // header: ({ table }) => ( + // table.toggleAllPageRowsSelected(!!value)} + // className={cn(isLoading ? 'invisible' : 'mr-2')} + // aria-label="Select all" + // /> + // ), + // cell: ({ row }) => ( + // row.toggleSelected(!!value)} + // aria-label="Select row" + // className="mr-2" + // /> + // ), + // enableSorting: false, + // enableHiding: false, + // }, + { + accessorKey: 'validatorId', + header: ({ column }) => , + cell: ({ row }) => row.original.validatorId, + size: 100, + }, + { + accessorKey: 'balance', + header: ({ column }) => , + cell: ({ row }) => ( + + ), + }, + { + accessorKey: 'totalRewarded', + header: ({ column }) => , + cell: ({ row }) => ( + + ), + }, + { + accessorKey: 'rewardTokenBalance', + header: ({ column }) => ( + + ), + cell: ({ row }) => { + const validator = validators.find((v) => v.id === row.original.validatorId) + const { rewardTokenId } = validator?.config || {} + if (!rewardTokenId || Number(rewardTokenId) === 0) return '--' + return {row.original.rewardTokenBalance || 0} + }, + }, + { + accessorKey: 'entryTime', + header: ({ column }) => , + cell: ({ row }) => ( + + {dayjs.unix(row.original.entryTime).format('lll')} + + ), + }, + { + id: 'actions', + cell: ({ row }) => { + const validatorId = row.original.validatorId + const validator = validators.find((v) => v.id === validatorId) + + if (!validator || !activeAddress) return null + + const stakingDisabled = isStakingDisabled(validator, constraints) + const unstakingDisabled = isUnstakingDisabled(validator, stakesByValidator) + const canManage = canManageValidator(validator, activeAddress) + + const isDevelopment = process.env.NODE_ENV === 'development' + const canSimulateEpoch = isDevelopment && canManage + + return ( +
+ + + + + + + + + + setAddStakeValidator(validator)} + disabled={stakingDisabled} + > + Stake + + setUnstakeValidator(validator)} + disabled={unstakingDisabled} + > + Unstake + + + + {canSimulateEpoch && ( + <> + + + + await simulateEpoch( + validator, + row.original.pools, + 100, + transactionSigner, + activeAddress, + queryClient, + router, + ) + } + disabled={unstakingDisabled} + > + + Simulate Epoch + + + + )} + + +
+ ) + }, + }, + ] + + const table = useReactTable({ + data: stakesByValidator, + columns, + getCoreRowModel: getCoreRowModel(), + onSortingChange: setSorting, + getSortedRowModel: getSortedRowModel(), + onColumnFiltersChange: setColumnFilters, + getFilteredRowModel: getFilteredRowModel(), + onColumnVisibilityChange: setColumnVisibility, + onRowSelectionChange: setRowSelection, + state: { + sorting, + columnFilters, + columnVisibility, + rowSelection, + }, + }) + + return ( + <> +
+
+

My Stakes

+
+
+ + + {table.getHeaderGroups().map((headerGroup) => ( + + {headerGroup.headers.map((header) => { + return ( + + {header.isPlaceholder + ? null + : flexRender(header.column.columnDef.header, header.getContext())} + + ) + })} + + ))} + + + {table.getRowModel().rows?.length ? ( + table.getRowModel().rows.map((row) => ( + + {row.getVisibleCells().map((cell) => ( + + {flexRender(cell.column.columnDef.cell, cell.getContext())} + + ))} + + )) + ) : ( + + + {isLoading ? 'Loading...' : 'No results'} + + + )} + +
+
+ + {/* {table.getFilteredRowModel().rows.length > 0 && ( +
+
+ {table.getFilteredSelectedRowModel().rows.length} of{' '} + {table.getFilteredRowModel().rows.length} row(s) selected. +
+
+ )} */} +
+ + + + + ) +} diff --git a/ui/src/components/UnstakeModal.tsx b/ui/src/components/UnstakeModal.tsx new file mode 100644 index 00000000..291c667e --- /dev/null +++ b/ui/src/components/UnstakeModal.tsx @@ -0,0 +1,400 @@ +import { AlgoAmount } from '@algorandfoundation/algokit-utils/types/amount' +import { zodResolver } from '@hookform/resolvers/zod' +import { useQueryClient } from '@tanstack/react-query' +import { useRouter } from '@tanstack/react-router' +import { useWallet } from '@txnlab/use-wallet-react' +import { ArrowDownLeft } from 'lucide-react' +import * as React from 'react' +import { useForm } from 'react-hook-form' +import { toast } from 'sonner' +import { z } from 'zod' +import { removeStake } from '@/api/contracts' +import { AlgoDisplayAmount } from '@/components/AlgoDisplayAmount' +import { Button } from '@/components/ui/button' +import { + Dialog, + DialogContent, + DialogDescription, + DialogHeader, + DialogTitle, +} from '@/components/ui/dialog' +import { + Form, + FormControl, + FormDescription, + FormField, + FormItem, + FormLabel, + FormMessage, +} from '@/components/ui/form' +import { Input } from '@/components/ui/input' +import { + Select, + SelectContent, + SelectItem, + SelectTrigger, + SelectValue, +} from '@/components/ui/select' +import { StakerPoolData, StakerValidatorData } from '@/interfaces/staking' +import { Validator } from '@/interfaces/validator' +import { formatAlgoAmount } from '@/utils/format' + +interface UnstakeModalProps { + validator: Validator | null + setValidator: React.Dispatch> + stakesByValidator: StakerValidatorData[] +} + +export function UnstakeModal({ validator, setValidator, stakesByValidator }: UnstakeModalProps) { + const [isSigning, setIsSigning] = React.useState(false) + const [selectedPoolId, setSelectedPoolId] = React.useState('') + + const stakerPoolsData = React.useMemo( + () => stakesByValidator.find((data) => data.validatorId === validator?.id)?.pools || [], + [stakesByValidator, validator], + ) + + React.useEffect(() => { + if (stakerPoolsData.length > 0 && selectedPoolId === '') { + setSelectedPoolId(stakerPoolsData[0].poolKey.poolId.toString()) + } + }, [stakerPoolsData]) + + const queryClient = useQueryClient() + const router = useRouter() + const { transactionSigner, activeAddress } = useWallet() + + const formSchema = z.object({ + amountToUnstake: z + .string() + .refine((val) => val !== '', { + message: 'Required field', + }) + .refine((val) => !isNaN(Number(val)) && parseFloat(val) > 0, { + message: 'Invalid amount', + }) + .superRefine((val, ctx) => { + const algoAmount = parseFloat(val) + const amountToUnstake = AlgoAmount.Algos(algoAmount).microAlgos + const stakerPoolData = stakerPoolsData.find( + (p) => p.poolKey.poolId === Number(selectedPoolId), + ) + + if (stakerPoolData && validator) { + const currentBalance = stakerPoolData.balance + const minimumStake = Number(validator.config.minEntryStake) + + if (amountToUnstake > currentBalance) { + ctx.addIssue({ + code: z.ZodIssueCode.too_big, + maximum: currentBalance, + type: 'number', + inclusive: true, + message: 'Cannot exceed current stake', + }) + } + + if (amountToUnstake !== currentBalance) { + // Not removing all stake in pool, must maintain minimum stake + if (currentBalance - amountToUnstake < minimumStake) { + ctx.addIssue({ + code: z.ZodIssueCode.too_big, + maximum: currentBalance - minimumStake, + type: 'number', + inclusive: true, + message: `Minimum stake is ${formatAlgoAmount(AlgoAmount.MicroAlgos(minimumStake).algos)} ALGO`, + }) + } + } + } + }), + }) + + const form = useForm>({ + resolver: zodResolver(formSchema), + mode: 'onChange', + defaultValues: { + amountToUnstake: '', + }, + }) + + const { errors, isValid } = form.formState + + const handleOpenChange = (open: boolean) => { + if (!open) { + setValidator(null) + setSelectedPoolId('') + form.reset() + } + } + + const handleSetSelectedPool = (poolId: string) => { + setSelectedPoolId(poolId) + form.reset() + } + + const handleSetMaxAmount = (event: React.MouseEvent) => { + event.preventDefault() + + const pool = stakerPoolsData.find((p) => p.poolKey.poolId === Number(selectedPoolId)) + + if (!pool) { + return + } + + form.setValue('amountToUnstake', AlgoAmount.MicroAlgos(pool.balance).algos.toString(), { + shouldValidate: true, + }) + } + + const toastIdRef = React.useRef(`toast-${Date.now()}-${Math.random()}`) + const TOAST_ID = toastIdRef.current + + const onSubmit = async (data: z.infer) => { + const toastId = `${TOAST_ID}-unstake` + + try { + setIsSigning(true) + + if (!activeAddress) { + throw new Error('No active address') + } + + const pool = stakerPoolsData.find((p) => p.poolKey.poolId === Number(selectedPoolId)) + + if (!pool) { + throw new Error('Invalid pool') + } + + const amountToUnstake = AlgoAmount.Algos(parseFloat(data.amountToUnstake)).microAlgos + + toast.loading('Sign transactions to remove stake...', { id: toastId }) + + await removeStake(pool.poolKey.poolAppId, amountToUnstake, transactionSigner, activeAddress) + + toast.success( +
+ + + Removed {' '} + from Pool {pool.poolKey.poolId} on Validator {pool.poolKey.validatorId} + +
, + { + id: toastId, + duration: 5000, + }, + ) + + const allStakerData = queryClient.getQueryData([ + 'stakes', + { staker: activeAddress }, + ]) + + const stakerValidatorData = allStakerData?.find( + (data) => data.validatorId === pool.poolKey.validatorId, + ) + + if (stakerValidatorData) { + const updatedPool = stakerValidatorData.pools.find( + (p) => p.poolKey.poolId === pool.poolKey.poolId, + ) + + if (updatedPool) { + const newBalance = updatedPool.balance - amountToUnstake + + const newPools = + newBalance === 0 + ? stakerValidatorData.pools.filter((p) => p.poolKey.poolId !== pool.poolKey.poolId) + : stakerValidatorData.pools.map((p) => { + if (p.poolKey.poolId === pool.poolKey.poolId) { + return { + ...p, + balance: newBalance, + } + } + + return p + }) + + const allStakeRemoved = newPools.length === 0 + + queryClient.setQueryData( + ['stakes', { staker: activeAddress }], + (prevData) => { + if (!prevData) { + return prevData + } + + if (allStakeRemoved) { + return prevData.filter((d) => d.validatorId !== pool.poolKey.validatorId) + } + + return prevData.map((data) => { + if (data.validatorId === pool.poolKey.validatorId) { + return { + ...data, + balance: data.balance - amountToUnstake, + pools: newPools, + } + } + + return data + }) + }, + ) + + queryClient.setQueryData( + ['validator', String(pool.poolKey.validatorId)], + (prevData) => { + if (!prevData) { + return prevData + } + + return { + ...prevData, + state: { + ...prevData.state, + totalStakers: allStakeRemoved + ? prevData.state.totalStakers - 1 + : prevData.state.totalStakers, + totalAlgoStaked: prevData.state.totalAlgoStaked - BigInt(amountToUnstake), + }, + } + }, + ) + + queryClient.setQueryData(['validators'], (prevData) => { + if (!prevData) { + return prevData + } + + return prevData.map((v: Validator) => { + if (v.id === pool.poolKey.validatorId) { + return { + ...v, + state: { + ...v.state, + totalStakers: allStakeRemoved ? v.state.totalStakers - 1 : v.state.totalStakers, + totalAlgoStaked: v.state.totalAlgoStaked - BigInt(amountToUnstake), + }, + } + } + + return v + }) + }) + } + } + + router.invalidate() + } catch (error) { + toast.error('Failed to remove stake from pool', { id: toastId }) + console.error(error) + } finally { + setIsSigning(false) + setValidator(null) + } + } + + return ( + + + + Remove Stake from Validator {validator?.id} + + This will remove your ALGO stake from{' '} + {stakerPoolsData.length === 1 + ? `Pool ${stakerPoolsData[0].poolKey.poolId}` + : 'the selected pool'} + + +
+
+ +
+
+ + {stakerPoolsData.length === 1 ? ( +

+ + + +

+ ) : ( + <> + +

Select a pool

+ + )} +
+
+ ( + + Amount to Unstake + +
+ + +
+
+ Enter the amount to unstake +
+ {errors.amountToUnstake?.message} +
+
+ )} + /> +
+
+ + +
+ +
+
+
+ ) +} diff --git a/ui/src/components/ValidatorDetails.tsx b/ui/src/components/ValidatorDetails.tsx new file mode 100644 index 00000000..3222397e --- /dev/null +++ b/ui/src/components/ValidatorDetails.tsx @@ -0,0 +1,230 @@ +import { useQuery } from '@tanstack/react-query' +import { useWallet } from '@txnlab/use-wallet-react' +import { Coins, Pencil, Percent, Users, Waves } from 'lucide-react' +import * as React from 'react' +import { poolAssignmentQueryOptions } from '@/api/queries' +import { Overview } from '@/components/_Overview' +import { AddPoolModal } from '@/components/AddPoolModal' +import { AlgoDisplayAmount } from '@/components/AlgoDisplayAmount' +import { Button } from '@/components/ui/button' +import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card' +import { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger } from '@/components/ui/tooltip' +import { Validator } from '@/interfaces/validator' +import { validatorHasAvailableSlots } from '@/utils/contracts' +import { formatDuration } from '@/utils/dayjs' +import { ellipseAddress } from '@/utils/ellipseAddress' + +interface ValidatorDetailsProps { + validator: Validator +} + +export function ValidatorDetails({ validator }: ValidatorDetailsProps) { + const [addPoolValidator, setAddPoolValidator] = React.useState(null) + + const { activeAddress } = useWallet() + + const isManager = validator.config.manager === activeAddress + const isOwner = validator.config.owner === activeAddress + const canEdit = isManager || isOwner + + const { data: poolAssignment } = useQuery(poolAssignmentQueryOptions(validator.id, canEdit)) + + const hasSlots = React.useMemo(() => { + return poolAssignment + ? validatorHasAvailableSlots(poolAssignment, validator.config.poolsPerNode) + : false + }, [poolAssignment, validator.config.poolsPerNode]) + + const canAddPool = canEdit && hasSlots + + return ( + <> +
+
+ + + Total Staked + + + +
+ +
+ {/*

+20.1% from last month

*/} +
+
+ + + Stakers + + + +
+ {validator.state.totalStakers} +
+ {/*

+180.1% from last month

*/} +
+
+ + + Pools + + + +
+ {Number(validator.state.numPools)} + {canAddPool && ( + + )} +
+ {/*

+201 since last hour

*/} +
+
+ + + Commission + + + +
+ {`${validator.config.percentToValidator / 10000}%`} +
+ {/*

+19% from last month

*/} +
+
+
+
+ + + Analytics + + + + + + + + Validator Details + {/* You made 265 sales this month. */} + + +
+
+
+
Owner
+
+ {ellipseAddress(validator.config.owner)} +
+
+
+
Manager
+
+ {ellipseAddress(validator.config.manager)} + {canEdit && ( + + + + + + +

Edit manager

+
+
+
+ )} +
+
+
+
+ Commission Account +
+
+ {ellipseAddress(validator.config.validatorCommissionAddress)} + {canEdit && ( + + + + + + +

Edit commission account

+
+
+
+ )} +
+
+
+
+ Payout Frequency +
+
+ + {formatDuration(validator.config.payoutEveryXMins)} + + {canEdit && ( + + + + + + +

Edit payout frequency

+
+
+
+ )} +
+
+
+
+ Minimum Entry Stake +
+
+ +
+
+
+
+ Maximum Stake Per Pool +
+
+ +
+
+
+
+
+
+
+
+ + {poolAssignment && ( + + )} + + ) +} diff --git a/ui/src/components/ValidatorTable.tsx b/ui/src/components/ValidatorTable.tsx new file mode 100644 index 00000000..8629cf61 --- /dev/null +++ b/ui/src/components/ValidatorTable.tsx @@ -0,0 +1,351 @@ +import { AlgoAmount } from '@algorandfoundation/algokit-utils/types/amount' +import { useQuery } from '@tanstack/react-query' +import { Link } from '@tanstack/react-router' +import { + ColumnDef, + ColumnFiltersState, + SortingState, + VisibilityState, + flexRender, + getCoreRowModel, + getFilteredRowModel, + getSortedRowModel, + useReactTable, +} from '@tanstack/react-table' +import { useWallet } from '@txnlab/use-wallet-react' +import { FlaskConical, MoreHorizontal } from 'lucide-react' +import * as React from 'react' +import { constraintsQueryOptions } from '@/api/queries' +import { AddPoolModal } from '@/components/AddPoolModal' +import { AddStakeModal } from '@/components/AddStakeModal' +import { AlgoDisplayAmount } from '@/components/AlgoDisplayAmount' +import { DataTableColumnHeader } from '@/components/DataTableColumnHeader' +import { DataTableViewOptions } from '@/components/DataTableViewOptions' +import { NfdThumbnail } from '@/components/NfdThumbnail' +import { Button } from '@/components/ui/button' +import { + DropdownMenu, + DropdownMenuContent, + DropdownMenuGroup, + DropdownMenuItem, + DropdownMenuSeparator, + DropdownMenuTrigger, +} from '@/components/ui/dropdown-menu' +import { Input } from '@/components/ui/input' +import { + Table, + TableBody, + TableCell, + TableHead, + TableHeader, + TableRow, +} from '@/components/ui/table' +import { UnstakeModal } from '@/components/UnstakeModal' +import { StakerValidatorData } from '@/interfaces/staking' +import { Validator } from '@/interfaces/validator' +import { + calculateMaxStake, + calculateMaxStakers, + canManageValidator, + isAddingPoolDisabled, + isStakingDisabled, + isUnstakingDisabled, +} from '@/utils/contracts' +import { formatDuration } from '@/utils/dayjs' +import { sendRewardTokensToPool } from '@/utils/development' +import { ellipseAddress } from '@/utils/ellipseAddress' +import { cn } from '@/utils/ui' + +interface ValidatorTableProps { + validators: Validator[] + stakesByValidator: StakerValidatorData[] +} + +export function ValidatorTable({ validators, stakesByValidator }: ValidatorTableProps) { + const [sorting, setSorting] = React.useState([]) + const [columnFilters, setColumnFilters] = React.useState([]) + const [columnVisibility, setColumnVisibility] = React.useState({}) + const [rowSelection, setRowSelection] = React.useState({}) + + const [addStakeValidator, setAddStakeValidator] = React.useState(null) + const [unstakeValidator, setUnstakeValidator] = React.useState(null) + const [addPoolValidator, setAddPoolValidator] = React.useState(null) + + const { transactionSigner, activeAddress } = useWallet() + + const { data: constraints } = useQuery(constraintsQueryOptions) + + const columns: ColumnDef[] = [ + { + accessorKey: 'id', + header: ({ column }) => , + size: 70, + }, + { + id: 'validator', + accessorFn: (row) => row.config.owner, + header: ({ column }) => , + cell: ({ row }) => { + const validator = row.original + + const nfdAppId = validator.config.nfdForInfo + if (nfdAppId > 0) { + return + } + return ellipseAddress(validator.config.owner) + }, + }, + { + id: 'minEntry', + accessorFn: (row) => Number(row.config.minEntryStake), + header: ({ column }) => , + cell: ({ row }) => { + const validator = row.original + return + }, + }, + { + id: 'stake', + accessorFn: (row) => Number(row.state.totalAlgoStaked), + header: ({ column }) => , + cell: ({ row }) => { + const validator = row.original + + const currentStake = AlgoAmount.MicroAlgos(Number(validator.state.totalAlgoStaked)).algos + const currentStakeCompact = new Intl.NumberFormat(undefined, { + notation: 'compact', + }).format(currentStake) + + const maxStake = calculateMaxStake(validator, true) + const maxStakeCompact = new Intl.NumberFormat(undefined, { + notation: 'compact', + }).format(maxStake) + + return ( + + {currentStakeCompact} / {maxStakeCompact} + + ) + }, + }, + { + id: 'stakers', + accessorFn: (row) => row.state.totalStakers, + header: ({ column }) => , + cell: ({ row }) => { + const validator = row.original + + if (validator.state.numPools == 0) return '--' + + const totalStakers = validator.state.totalStakers + const maxStakers = calculateMaxStakers(validator) + + return ( + + {totalStakers} / {maxStakers} + + ) + }, + }, + { + id: 'commission', + accessorFn: (row) => row.config.percentToValidator, + header: ({ column }) => , + cell: ({ row }) => { + const validator = row.original + const percent = validator.config.percentToValidator / 10000 + return `${percent}%` + }, + }, + { + id: 'payoutFrequency', + accessorFn: (row) => row.config.payoutEveryXMins, + header: ({ column }) => , + cell: ({ row }) => { + const validator = row.original + const frequencyFormatted = formatDuration(validator.config.payoutEveryXMins) + return {frequencyFormatted} + }, + }, + { + id: 'actions', + cell: ({ row }) => { + const validator = row.original + const stakingDisabled = isStakingDisabled(validator, constraints) + const unstakingDisabled = isUnstakingDisabled(validator, stakesByValidator) + const addingPoolDisabled = isAddingPoolDisabled(validator) + const canManage = canManageValidator(validator, activeAddress!) + + const isDevelopment = process.env.NODE_ENV === 'development' + const hasRewardToken = validator.config.rewardTokenId > 0 + const canSendRewardTokens = isDevelopment && canManage && hasRewardToken + const sendRewardTokensDisabled = validator.state.numPools === 0 + + return ( +
+ + + + + + + + setAddStakeValidator(validator)} + disabled={stakingDisabled} + > + Stake + + setUnstakeValidator(validator)} + disabled={unstakingDisabled} + > + Unstake + + + + + + + {canManage ? 'Manage' : 'View'} + + + {canManage && ( + setAddPoolValidator(validator)} + disabled={addingPoolDisabled} + > + Add Staking Pool + + )} + + {canSendRewardTokens && ( + <> + + + + await sendRewardTokensToPool( + validator, + 5000, + transactionSigner, + activeAddress!, + ) + } + disabled={sendRewardTokensDisabled} + > + + Send Tokens + + + + )} + + + +
+ ) + }, + size: 120, + }, + ] + + const table = useReactTable({ + data: validators, + columns, + getCoreRowModel: getCoreRowModel(), + onSortingChange: setSorting, + getSortedRowModel: getSortedRowModel(), + onColumnFiltersChange: setColumnFilters, + getFilteredRowModel: getFilteredRowModel(), + onColumnVisibilityChange: setColumnVisibility, + onRowSelectionChange: setRowSelection, + state: { + sorting, + columnFilters, + columnVisibility, + rowSelection, + }, + }) + + return ( + <> +
+
+

All Validators

+
+ table.getColumn('validator')?.setFilterValue(event.target.value)} + className="sm:max-w-sm lg:w-64" + /> + +
+
+
+ + + {table.getHeaderGroups().map((headerGroup) => ( + + {headerGroup.headers.map((header) => { + return ( + + {header.isPlaceholder + ? null + : flexRender(header.column.columnDef.header, header.getContext())} + + ) + })} + + ))} + + + {table.getRowModel().rows?.length ? ( + table.getRowModel().rows.map((row) => ( + + {row.getVisibleCells().map((cell) => ( + + {flexRender(cell.column.columnDef.cell, cell.getContext())} + + ))} + + )) + ) : ( + + + No results + + + )} + +
+
+
+ + + + + + ) +} diff --git a/ui/src/components/WalletBalance.tsx b/ui/src/components/WalletBalance.tsx new file mode 100644 index 00000000..bcb79b47 --- /dev/null +++ b/ui/src/components/WalletBalance.tsx @@ -0,0 +1,28 @@ +import { useQuery } from '@tanstack/react-query' +import { balanceQueryOptions } from '@/api/queries' +import { AlgoDisplayAmount } from '@/components/AlgoDisplayAmount' + +interface WalletBalanceProps { + activeAddress: string +} + +export function WalletBalance({ activeAddress }: WalletBalanceProps) { + const { data: balance, isLoading, error } = useQuery(balanceQueryOptions(activeAddress)) + + if (isLoading) { + return Loading... + } + + if (error || !balance) { + return Error fetching balance + } + + return ( +
+

Account Balance

+

+ +

+
+ ) +} diff --git a/ui/src/components/WalletShortcutHandler.tsx b/ui/src/components/WalletShortcutHandler.tsx new file mode 100644 index 00000000..08fc55b9 --- /dev/null +++ b/ui/src/components/WalletShortcutHandler.tsx @@ -0,0 +1,28 @@ +import { useWallet } from '@txnlab/use-wallet-react' +import * as React from 'react' + +export function WalletShortcutHandler() { + const { activeWallet } = useWallet() + + const handleDisconnect = React.useCallback(() => { + if (activeWallet) { + activeWallet.disconnect() + } + }, [activeWallet]) + + React.useEffect(() => { + const handleKeyDown = (event: KeyboardEvent) => { + if (event.shiftKey && event.key === 'D') { + handleDisconnect() + } + } + + window.addEventListener('keydown', handleKeyDown) + + return () => { + window.removeEventListener('keydown', handleKeyDown) + } + }, [handleDisconnect]) + + return null +} diff --git a/ui/src/components/_Overview.tsx b/ui/src/components/_Overview.tsx new file mode 100644 index 00000000..2d73d9de --- /dev/null +++ b/ui/src/components/_Overview.tsx @@ -0,0 +1,70 @@ +import { Bar, BarChart, ResponsiveContainer, XAxis, YAxis } from 'recharts' + +const data = [ + { + name: 'Jan', + total: Math.floor(Math.random() * 5000) + 1000, + }, + { + name: 'Feb', + total: Math.floor(Math.random() * 5000) + 1000, + }, + { + name: 'Mar', + total: Math.floor(Math.random() * 5000) + 1000, + }, + { + name: 'Apr', + total: Math.floor(Math.random() * 5000) + 1000, + }, + { + name: 'May', + total: Math.floor(Math.random() * 5000) + 1000, + }, + { + name: 'Jun', + total: Math.floor(Math.random() * 5000) + 1000, + }, + { + name: 'Jul', + total: Math.floor(Math.random() * 5000) + 1000, + }, + { + name: 'Aug', + total: Math.floor(Math.random() * 5000) + 1000, + }, + { + name: 'Sep', + total: Math.floor(Math.random() * 5000) + 1000, + }, + { + name: 'Oct', + total: Math.floor(Math.random() * 5000) + 1000, + }, + { + name: 'Nov', + total: Math.floor(Math.random() * 5000) + 1000, + }, + { + name: 'Dec', + total: Math.floor(Math.random() * 5000) + 1000, + }, +] + +export function Overview() { + return ( + + + + `${value}`} + /> + + + + ) +} diff --git a/ui/src/components/ui/avatar.tsx b/ui/src/components/ui/avatar.tsx new file mode 100644 index 00000000..33ae3c6e --- /dev/null +++ b/ui/src/components/ui/avatar.tsx @@ -0,0 +1,48 @@ +import * as React from "react" +import * as AvatarPrimitive from "@radix-ui/react-avatar" + +import { cn } from "@/utils/ui" + +const Avatar = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, ...props }, ref) => ( + +)) +Avatar.displayName = AvatarPrimitive.Root.displayName + +const AvatarImage = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, ...props }, ref) => ( + +)) +AvatarImage.displayName = AvatarPrimitive.Image.displayName + +const AvatarFallback = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, ...props }, ref) => ( + +)) +AvatarFallback.displayName = AvatarPrimitive.Fallback.displayName + +export { Avatar, AvatarImage, AvatarFallback } diff --git a/ui/src/components/ui/button.tsx b/ui/src/components/ui/button.tsx new file mode 100644 index 00000000..32f326b7 --- /dev/null +++ b/ui/src/components/ui/button.tsx @@ -0,0 +1,49 @@ +import * as React from 'react' +import { Slot } from '@radix-ui/react-slot' +import { cva, type VariantProps } from 'class-variance-authority' + +import { cn } from '@/utils/ui' + +const buttonVariants = cva( + 'inline-flex items-center justify-center whitespace-nowrap rounded-md text-sm font-medium ring-offset-background transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50', + { + variants: { + variant: { + default: 'bg-primary text-primary-foreground hover:bg-primary/90', + destructive: 'bg-destructive text-destructive-foreground hover:bg-destructive/90', + outline: 'border border-input bg-background hover:bg-accent hover:text-accent-foreground', + secondary: 'bg-secondary text-secondary-foreground hover:bg-secondary/80', + ghost: 'hover:bg-accent hover:text-accent-foreground', + link: 'text-primary underline-offset-4 hover:underline', + }, + size: { + default: 'h-10 px-4 py-2', + sm: 'h-9 rounded-md px-3', + lg: 'h-11 rounded-md px-8', + icon: 'h-10 w-10', + }, + }, + defaultVariants: { + variant: 'default', + size: 'default', + }, + }, +) + +export interface ButtonProps + extends React.ButtonHTMLAttributes, + VariantProps { + asChild?: boolean +} + +const Button = React.forwardRef( + ({ className, variant, size, asChild = false, ...props }, ref) => { + const Comp = asChild ? Slot : 'button' + return ( + + ) + }, +) +Button.displayName = 'Button' + +export { Button, buttonVariants } diff --git a/ui/src/components/ui/card.tsx b/ui/src/components/ui/card.tsx new file mode 100644 index 00000000..d67b9e57 --- /dev/null +++ b/ui/src/components/ui/card.tsx @@ -0,0 +1,76 @@ +import * as React from "react" + +import { cn } from "@/utils/ui" + +const Card = React.forwardRef< + HTMLDivElement, + React.HTMLAttributes +>(({ className, ...props }, ref) => ( +
+)) +Card.displayName = "Card" + +const CardHeader = React.forwardRef< + HTMLDivElement, + React.HTMLAttributes +>(({ className, ...props }, ref) => ( +
+)) +CardHeader.displayName = "CardHeader" + +const CardTitle = React.forwardRef< + HTMLParagraphElement, + React.HTMLAttributes +>(({ className, ...props }, ref) => ( +

+)) +CardTitle.displayName = "CardTitle" + +const CardDescription = React.forwardRef< + HTMLParagraphElement, + React.HTMLAttributes +>(({ className, ...props }, ref) => ( +

+)) +CardDescription.displayName = "CardDescription" + +const CardContent = React.forwardRef< + HTMLDivElement, + React.HTMLAttributes +>(({ className, ...props }, ref) => ( +

+)) +CardContent.displayName = "CardContent" + +const CardFooter = React.forwardRef< + HTMLDivElement, + React.HTMLAttributes +>(({ className, ...props }, ref) => ( +
+)) +CardFooter.displayName = "CardFooter" + +export { Card, CardHeader, CardFooter, CardTitle, CardDescription, CardContent } diff --git a/ui/src/components/ui/checkbox.tsx b/ui/src/components/ui/checkbox.tsx new file mode 100644 index 00000000..5c5c7b43 --- /dev/null +++ b/ui/src/components/ui/checkbox.tsx @@ -0,0 +1,26 @@ +import * as React from 'react' +import * as CheckboxPrimitive from '@radix-ui/react-checkbox' +import { CheckIcon } from '@radix-ui/react-icons' + +import { cn } from '@/utils/ui' + +const Checkbox = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, ...props }, ref) => ( + + + + + +)) +Checkbox.displayName = CheckboxPrimitive.Root.displayName + +export { Checkbox } diff --git a/ui/src/components/ui/dialog.tsx b/ui/src/components/ui/dialog.tsx new file mode 100644 index 00000000..0e9f699a --- /dev/null +++ b/ui/src/components/ui/dialog.tsx @@ -0,0 +1,102 @@ +import * as React from 'react' +import * as DialogPrimitive from '@radix-ui/react-dialog' +import { Cross2Icon } from '@radix-ui/react-icons' + +import { cn } from '@/utils/ui' + +const Dialog = DialogPrimitive.Root + +const DialogTrigger = DialogPrimitive.Trigger + +const DialogPortal = DialogPrimitive.Portal + +const DialogClose = DialogPrimitive.Close + +const DialogOverlay = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, ...props }, ref) => ( + +)) +DialogOverlay.displayName = DialogPrimitive.Overlay.displayName + +const DialogContent = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, children, ...props }, ref) => ( + + + + {children} + + + Close + + + +)) +DialogContent.displayName = DialogPrimitive.Content.displayName + +const DialogHeader = ({ className, ...props }: React.HTMLAttributes) => ( +
+) +DialogHeader.displayName = 'DialogHeader' + +const DialogFooter = ({ className, ...props }: React.HTMLAttributes) => ( +
+) +DialogFooter.displayName = 'DialogFooter' + +const DialogTitle = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, ...props }, ref) => ( + +)) +DialogTitle.displayName = DialogPrimitive.Title.displayName + +const DialogDescription = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, ...props }, ref) => ( + +)) +DialogDescription.displayName = DialogPrimitive.Description.displayName + +export { + Dialog, + DialogPortal, + DialogOverlay, + DialogTrigger, + DialogClose, + DialogContent, + DialogHeader, + DialogFooter, + DialogTitle, + DialogDescription, +} diff --git a/ui/src/components/ui/dropdown-menu.tsx b/ui/src/components/ui/dropdown-menu.tsx new file mode 100644 index 00000000..52329851 --- /dev/null +++ b/ui/src/components/ui/dropdown-menu.tsx @@ -0,0 +1,183 @@ +import * as React from 'react' +import * as DropdownMenuPrimitive from '@radix-ui/react-dropdown-menu' +import { Check, ChevronRight, Circle } from 'lucide-react' + +import { cn } from '@/utils/ui' + +const DropdownMenu = DropdownMenuPrimitive.Root + +const DropdownMenuTrigger = DropdownMenuPrimitive.Trigger + +const DropdownMenuGroup = DropdownMenuPrimitive.Group + +const DropdownMenuPortal = DropdownMenuPrimitive.Portal + +const DropdownMenuSub = DropdownMenuPrimitive.Sub + +const DropdownMenuRadioGroup = DropdownMenuPrimitive.RadioGroup + +const DropdownMenuSubTrigger = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef & { + inset?: boolean + } +>(({ className, inset, children, ...props }, ref) => ( + + {children} + + +)) +DropdownMenuSubTrigger.displayName = DropdownMenuPrimitive.SubTrigger.displayName + +const DropdownMenuSubContent = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, ...props }, ref) => ( + +)) +DropdownMenuSubContent.displayName = DropdownMenuPrimitive.SubContent.displayName + +const DropdownMenuContent = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, sideOffset = 4, ...props }, ref) => ( + + + +)) +DropdownMenuContent.displayName = DropdownMenuPrimitive.Content.displayName + +const DropdownMenuItem = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef & { + inset?: boolean + } +>(({ className, inset, ...props }, ref) => ( + +)) +DropdownMenuItem.displayName = DropdownMenuPrimitive.Item.displayName + +const DropdownMenuCheckboxItem = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, children, checked, ...props }, ref) => ( + + + + + + + {children} + +)) +DropdownMenuCheckboxItem.displayName = DropdownMenuPrimitive.CheckboxItem.displayName + +const DropdownMenuRadioItem = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, children, ...props }, ref) => ( + + + + + + + {children} + +)) +DropdownMenuRadioItem.displayName = DropdownMenuPrimitive.RadioItem.displayName + +const DropdownMenuLabel = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef & { + inset?: boolean + } +>(({ className, inset, ...props }, ref) => ( + +)) +DropdownMenuLabel.displayName = DropdownMenuPrimitive.Label.displayName + +const DropdownMenuSeparator = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, ...props }, ref) => ( + +)) +DropdownMenuSeparator.displayName = DropdownMenuPrimitive.Separator.displayName + +const DropdownMenuShortcut = ({ className, ...props }: React.HTMLAttributes) => { + return +} +DropdownMenuShortcut.displayName = 'DropdownMenuShortcut' + +export { + DropdownMenu, + DropdownMenuTrigger, + DropdownMenuContent, + DropdownMenuItem, + DropdownMenuCheckboxItem, + DropdownMenuRadioItem, + DropdownMenuLabel, + DropdownMenuSeparator, + DropdownMenuShortcut, + DropdownMenuGroup, + DropdownMenuPortal, + DropdownMenuSub, + DropdownMenuSubContent, + DropdownMenuSubTrigger, + DropdownMenuRadioGroup, +} diff --git a/ui/src/components/ui/form.tsx b/ui/src/components/ui/form.tsx new file mode 100644 index 00000000..76125903 --- /dev/null +++ b/ui/src/components/ui/form.tsx @@ -0,0 +1,176 @@ +import * as React from "react" +import * as LabelPrimitive from "@radix-ui/react-label" +import { Slot } from "@radix-ui/react-slot" +import { + Controller, + ControllerProps, + FieldPath, + FieldValues, + FormProvider, + useFormContext, +} from "react-hook-form" + +import { cn } from "@/utils/ui" +import { Label } from "@/components/ui/label" + +const Form = FormProvider + +type FormFieldContextValue< + TFieldValues extends FieldValues = FieldValues, + TName extends FieldPath = FieldPath +> = { + name: TName +} + +const FormFieldContext = React.createContext( + {} as FormFieldContextValue +) + +const FormField = < + TFieldValues extends FieldValues = FieldValues, + TName extends FieldPath = FieldPath +>({ + ...props +}: ControllerProps) => { + return ( + + + + ) +} + +const useFormField = () => { + const fieldContext = React.useContext(FormFieldContext) + const itemContext = React.useContext(FormItemContext) + const { getFieldState, formState } = useFormContext() + + const fieldState = getFieldState(fieldContext.name, formState) + + if (!fieldContext) { + throw new Error("useFormField should be used within ") + } + + const { id } = itemContext + + return { + id, + name: fieldContext.name, + formItemId: `${id}-form-item`, + formDescriptionId: `${id}-form-item-description`, + formMessageId: `${id}-form-item-message`, + ...fieldState, + } +} + +type FormItemContextValue = { + id: string +} + +const FormItemContext = React.createContext( + {} as FormItemContextValue +) + +const FormItem = React.forwardRef< + HTMLDivElement, + React.HTMLAttributes +>(({ className, ...props }, ref) => { + const id = React.useId() + + return ( + +
+ + ) +}) +FormItem.displayName = "FormItem" + +const FormLabel = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, ...props }, ref) => { + const { error, formItemId } = useFormField() + + return ( +