diff --git a/src/controllers/accounts/AccountsStakingPayoutsController.ts b/src/controllers/accounts/AccountsStakingPayoutsController.ts index 59abd2bcc..8df352eee 100644 --- a/src/controllers/accounts/AccountsStakingPayoutsController.ts +++ b/src/controllers/accounts/AccountsStakingPayoutsController.ts @@ -16,13 +16,15 @@ import type { ApiPromise } from '@polkadot/api'; import type { ApiDecoration } from '@polkadot/api/types'; -import { Option } from '@polkadot/types'; +import { Option, u32 } from '@polkadot/types'; import BN from 'bn.js'; import { RequestHandler } from 'express'; import { BadRequest, InternalServerError } from 'http-errors'; import { validateAddress, validateBoolean } from '../../middleware'; import { AccountsStakingPayoutsService } from '../../services'; +import { IEarlyErasBlockInfo } from '../../services/accounts/AccountsStakingPayoutsService'; +import kusamaEarlyErasBlockInfo from '../../services/accounts/kusamaEarlyErasBlockInfo.json'; import { IAddressParam } from '../../types/requests'; import AbstractController from '../AbstractController'; @@ -99,9 +101,24 @@ export default class AccountsStakingPayoutsController extends AbstractController { params: { address }, query: { depth, era, unclaimedOnly, at } }, res, ): Promise => { - const hash = await this.getHashFromAt(at); - const apiAt = await this.api.at(hash); + const earlyErasBlockInfo: IEarlyErasBlockInfo = kusamaEarlyErasBlockInfo; + let hash = await this.getHashFromAt(at); + let apiAt = await this.api.at(hash); const { eraArg, currentEra } = await this.getEraAndHash(apiAt, this.verifyAndCastOr('era', era, undefined)); + if (currentEra <= 519 && depth !== undefined) { + throw new InternalServerError('The `depth` query parameter is disabled for eras less than 518.'); + } else if (currentEra <= 519 && era !== undefined) { + throw new InternalServerError('The `era` query parameter is disabled for eras less than 518.'); + } + let sanitizedDepth: string | undefined; + if (depth) { + sanitizedDepth = Math.min(Number(depth), currentEra - 518).toString(); + } + if (currentEra < 518) { + const eraStartBlock: number = earlyErasBlockInfo[currentEra].start; + hash = await this.getHashFromAt(eraStartBlock.toString()); + apiAt = await this.api.at(hash); + } const unclaimedOnlyArg = unclaimedOnly === 'false' ? false : true; @@ -110,7 +127,7 @@ export default class AccountsStakingPayoutsController extends AbstractController await this.service.fetchAccountStakingPayout( hash, address, - this.verifyAndCastOr('depth', depth, 1) as number, + this.verifyAndCastOr('depth', sanitizedDepth, 1) as number, eraArg, unclaimedOnlyArg, currentEra, @@ -120,17 +137,8 @@ export default class AccountsStakingPayoutsController extends AbstractController }; private async getEraAndHash(apiAt: ApiDecoration<'promise'>, era?: number) { - const [activeEraOption, currentEraMaybeOption] = await Promise.all([ - apiAt.query.staking.activeEra(), - apiAt.query.staking.currentEra(), - ]); - - if (activeEraOption.isNone) { - throw new InternalServerError('ActiveEra is None when Some was expected'); - } - const activeEra = activeEraOption.unwrap().index.toNumber(); - - let currentEra; + let currentEra: number; + const currentEraMaybeOption = (await apiAt.query.staking.currentEra()) as u32 & Option; if (currentEraMaybeOption instanceof Option) { if (currentEraMaybeOption.isNone) { throw new InternalServerError('CurrentEra is None when Some was expected'); @@ -144,6 +152,32 @@ export default class AccountsStakingPayoutsController extends AbstractController throw new InternalServerError('Query for current_era returned a non-processable result.'); } + let activeEra; + if (apiAt.query.staking.activeEra) { + const activeEraOption = await apiAt.query.staking.activeEra(); + if (activeEraOption.isNone) { + const historicActiveEra = await apiAt.query.staking.currentEra(); + if (historicActiveEra.isNone) { + throw new InternalServerError('ActiveEra is None when Some was expected'); + } else { + activeEra = historicActiveEra.unwrap().toNumber(); + } + } else { + activeEra = activeEraOption.unwrap().index.toNumber(); + } + } else { + const sessionIndex = await apiAt.query.session.currentIndex(); + const idx = sessionIndex.toNumber() % 6; + // https://substrate.stackexchange.com/a/2026/1786 + if (currentEra < 518) { + activeEra = currentEra; + } else if (idx > 0) { + activeEra = currentEra; + } else { + activeEra = currentEra - 1; + } + } + if (era !== undefined && era > activeEra - 1) { throw new BadRequest( `The specified era (${era}) is too large. ` + `Largest era payout info is available for is ${activeEra - 1}`, diff --git a/src/services/accounts/AccountsStakingPayoutsService.ts b/src/services/accounts/AccountsStakingPayoutsService.ts index cc3441d34..a69c92560 100644 --- a/src/services/accounts/AccountsStakingPayoutsService.ts +++ b/src/services/accounts/AccountsStakingPayoutsService.ts @@ -21,26 +21,31 @@ import type { DeriveEraNominatorExposure, DeriveEraValidatorExposure, } from '@polkadot/api-derive/staking/types'; -import type { Option, StorageKey, u32 } from '@polkadot/types'; +import { Option, StorageKey, u32, u128 } from '@polkadot/types'; +import { Vec } from '@polkadot/types'; import type { AccountId, BalanceOf, BlockHash, EraIndex, + EraPoints, Perbill, StakingLedger, StakingLedgerTo240, + ValidatorPrefsWithCommission, } from '@polkadot/types/interfaces'; import type { PalletStakingEraRewardPoints, PalletStakingExposure, PalletStakingStakingLedger, + PalletStakingValidatorPrefs, } from '@polkadot/types/lookup'; import { CalcPayout } from '@substrate/calc'; import { BadRequest } from 'http-errors'; import type { IAccountStakingPayouts, IEraPayouts, IPayout } from '../../types/responses'; import { AbstractService } from '../AbstractService'; +import kusamaEarlyErasBlockInfo from './kusamaEarlyErasBlockInfo.json'; /** * Copyright 2024 via polkadot-js/api @@ -52,7 +57,21 @@ type KeysAndExposures = [StorageKey<[EraIndex, AccountId]>, PalletStakingExposur * General information about an era, in tuple form because we initially get it * by destructuring a Promise.all(...) */ -type IErasGeneral = [DeriveEraExposure, PalletStakingEraRewardPoints, Option]; +type IErasGeneral = [IAdjustedDeriveEraExposure, PalletStakingEraRewardPoints | EraPoints, Option]; + +/** + * Index of the validator for eras previous to 518 + */ +interface ValidatorIndex { + [x: string]: number; +} +/** + * Adapted AdjustedDeriveEraExposure interface for compatibility with eras + * previous to 518 + */ +interface IAdjustedDeriveEraExposure extends DeriveEraExposure { + validatorIndex?: ValidatorIndex; +} /** * Commission and staking ledger of a validator @@ -66,8 +85,8 @@ interface ICommissionAndLedger { * All the data we need to calculate payouts for an address at a given era. */ interface IEraData { - deriveEraExposure: DeriveEraExposure; - eraRewardPoints: PalletStakingEraRewardPoints; + deriveEraExposure: IAdjustedDeriveEraExposure; + eraRewardPoints: PalletStakingEraRewardPoints | EraPoints; erasValidatorRewardOption: Option; exposuresWithCommission?: (ICommissionAndLedger & { validatorId: string; @@ -75,6 +94,22 @@ interface IEraData { eraIndex: EraIndex; } +/** + * Block information relevant for compatibility with eras previous + * to 518 + */ +interface IBlockInfo { + height: string; + hash: BlockHash; +} + +export interface IEarlyErasBlockInfo { + [era: string]: { + start: number; + end: number; + }; +} + export class AccountsStakingPayoutsService extends AbstractService { /** * Fetch and derive payouts for `address`. @@ -99,24 +134,28 @@ export class AccountsStakingPayoutsService extends AbstractService { const { api } = this; const { number } = await api.rpc.chain.getHeader(hash); + const sanitizedEra = era < 0 ? 0 : era; + /** * Given https://github.com/polkadot-js/api/issues/5232, * polkadot-js, and substrate treats historyDepth as a consts. In order * to maintain historical integrity we need to make a check to cover both the * storage query and the consts. */ - let historyDepth: u32; + let historyDepth: u32 = api.registry.createType('u32', 84); if (historicApi.consts.staking.historyDepth) { historyDepth = historicApi.consts.staking.historyDepth; - } else { + } else if (historicApi.query.staking.historyDepth) { historyDepth = await historicApi.query.staking.historyDepth(); + } else if (currentEra < 518) { + historyDepth = api.registry.createType('u32', 0); } // Information is kept for eras in `[current_era - history_depth; current_era]` - if (depth > historyDepth.toNumber()) { + if (historyDepth.toNumber() !== 0 && depth > historyDepth.toNumber()) { throw new BadRequest('Must specify a depth less than history_depth'); } - if (era - (depth - 1) < currentEra - historyDepth.toNumber()) { + if (era - (depth - 1) < currentEra - historyDepth.toNumber() && historyDepth.toNumber() !== 0) { // In scenarios where depth is not > historyDepth, but the user specifies an era // and historyDepth combo that would lead to querying eras older than history depth throw new BadRequest( @@ -125,16 +164,16 @@ export class AccountsStakingPayoutsService extends AbstractService { ); } - const at = { + const at: IBlockInfo = { height: number.unwrap().toString(10), hash, }; // User friendly - we don't error if the user specified era & depth combo <= 0, instead just start at 0 - const startEra = Math.max(0, era - (depth - 1)); + const startEra = Math.max(0, sanitizedEra - (depth - 1)); // Fetch general data about the era - const allErasGeneral = await this.fetchAllErasGeneral(historicApi, startEra, era); + const allErasGeneral = await this.fetchAllErasGeneral(historicApi, startEra, sanitizedEra, at); // With the general data, we can now fetch the commission of each validator `address` nominates const allErasCommissions = await this.fetchAllErasCommissions( @@ -182,37 +221,92 @@ export class AccountsStakingPayoutsService extends AbstractService { /** * Fetch general info about eras in the inclusive range `startEra` .. `era`. * - * @param api `ApiPromise` - * @param hash `BlockHash` to make call at + * @param historicApi Historic api for querying past blocks * @param startEra first era to get data for * @param era the last era to get data for + * @param blockNumber block information to ensure compatibility with older eras */ async fetchAllErasGeneral( historicApi: ApiDecoration<'promise'>, startEra: number, era: number, + blockNumber: IBlockInfo, ): Promise { const allDeriveQuerys: Promise[] = []; + let nextEraStartBlock: number = Number(blockNumber.height); + let eraDurationInBlocks: number = 0; + const runtimeInfo = await this.api.rpc.state.getRuntimeVersion(blockNumber.hash); + const earlyErasBlockInfo: IEarlyErasBlockInfo = kusamaEarlyErasBlockInfo; for (let e = startEra; e <= era; e += 1) { const eraIndex = historicApi.registry.createType('EraIndex', e); - const eraGeneralTuple = Promise.all([ - this.deriveEraExposure(historicApi, eraIndex), - historicApi.query.staking.erasRewardPoints(eraIndex), - historicApi.query.staking.erasValidatorReward(eraIndex), - ]); + if (historicApi.query.staking.erasRewardPoints) { + const eraGeneralTuple = Promise.all([ + this.deriveEraExposure(historicApi, eraIndex), + historicApi.query.staking.erasRewardPoints(eraIndex), + historicApi.query.staking.erasValidatorReward(eraIndex), + ]); + allDeriveQuerys.push(eraGeneralTuple); + } else { + // We check if we are in the Kusama chain since currently we have + // the block info for the early eras only for Kusama. + if (runtimeInfo.specName.toString() === 'kusama') { + // Retrieve the first block of the era following the given era in order + // to fetch the `Rewards` event at that block. + nextEraStartBlock = era === 0 ? earlyErasBlockInfo[era + 1].start : earlyErasBlockInfo[era].start; + } else { + const sessionDuration = historicApi.consts.staking.sessionsPerEra.toNumber(); + const epochDuration = historicApi.consts.babe.epochDuration.toNumber(); + eraDurationInBlocks = sessionDuration * epochDuration; + } + const nextEraStartBlockHash: BlockHash = await this.api.rpc.chain.getBlockHash(nextEraStartBlock); + const currentEraEndBlockHash: BlockHash = + era === 0 + ? await this.api.rpc.chain.getBlockHash(earlyErasBlockInfo[0].end) + : await this.api.rpc.chain.getBlockHash(earlyErasBlockInfo[era - 1].end); - allDeriveQuerys.push(eraGeneralTuple); - } + let reward: Option = historicApi.registry.createType('Option'); + + const blockInfo = await this.api.rpc.chain.getBlock(nextEraStartBlockHash); + + const allRecords = await historicApi.query.system.events(); + + blockInfo.block.extrinsics.forEach((index) => { + allRecords + .filter(({ phase }) => phase.isApplyExtrinsic && phase.asApplyExtrinsic.eq(index)) + .forEach(({ event }) => { + if (event.method.toString() === 'Reward') { + const [dispatchInfo] = event.data; + reward = historicApi.registry.createType('Option', dispatchInfo.toString()); + } + }); + }); + const points = this.fetchHistoricRewardPoints(currentEraEndBlockHash); + const rewardPromise: Promise> = new Promise>((resolve) => { + resolve(reward); + }); + if (runtimeInfo.specName.toString() !== 'kusama') { + nextEraStartBlock = nextEraStartBlock - eraDurationInBlocks; + } + + const eraGeneralTuple = Promise.all([this.deriveEraExposure(historicApi, eraIndex), points, rewardPromise]); + + allDeriveQuerys.push(eraGeneralTuple); + } + } return Promise.all(allDeriveQuerys); } + private async fetchHistoricRewardPoints(hash: BlockHash): Promise { + const historicApi = await this.api.at(hash); + return historicApi.query.staking.currentEraPointsEarned() as unknown as EraPoints; + } + /** * Fetch the commission & staking ledger for each `validatorId` in `deriveErasExposures`. * - * @param api `ApiPromise` - * @param hash `BlockHash` to make call at + * @param historicApi Historic api for querying past blocks * @param address address of the _Stash_ account to get the payouts of * @param startEra first era to get data for * @param deriveErasExposures exposures per era for `address` @@ -221,7 +315,7 @@ export class AccountsStakingPayoutsService extends AbstractService { historicApi: ApiDecoration<'promise'>, address: string, startEra: number, - deriveErasExposures: DeriveEraExposure[], + deriveErasExposures: IAdjustedDeriveEraExposure[], ): Promise { // Cache StakingLedger to reduce redundant queries to node const validatorLedgerCache: { [id: string]: PalletStakingStakingLedger } = {}; @@ -262,22 +356,24 @@ export class AccountsStakingPayoutsService extends AbstractService { message: `${address} has no nominations for the era ${eraIndex.toString()}`, }; } - - if (erasValidatorRewardOption.isNone) { + if (erasValidatorRewardOption.isNone && eraIndex.toNumber() !== 0) { + const event = eraIndex.toNumber() > 517 ? 'ErasValidatorReward' : 'Reward'; return { - message: `No ErasValidatorReward for the era ${eraIndex.toString()}`, + message: `No ${event} for the era ${eraIndex.toString()}`, }; } const totalEraRewardPoints = eraRewardPoints.total; - const totalEraPayout = erasValidatorRewardOption.unwrap(); + const totalEraPayout = + eraIndex.toNumber() !== 0 ? erasValidatorRewardOption.unwrap() : this.api.registry.createType('BalanceOf', 0); const calcPayout = CalcPayout.from_params(totalEraRewardPoints.toNumber(), totalEraPayout.toString(10)); // Iterate through validators that this nominator backs and calculate payouts for the era const payouts: IPayout[] = []; for (const { validatorId, commission: validatorCommission, validatorLedger } of exposuresWithCommission) { - const totalValidatorRewardPoints = this.extractTotalValidatorRewardPoints(eraRewardPoints, validatorId); - + const totalValidatorRewardPoints = deriveEraExposure.validatorIndex + ? this.extractTotalValidatorRewardPoints(eraRewardPoints, validatorId, deriveEraExposure.validatorIndex) + : this.extractTotalValidatorRewardPoints(eraRewardPoints, validatorId); if (!totalValidatorRewardPoints || totalValidatorRewardPoints?.toNumber() === 0) { // Nothing to do if there are no reward points for the validator continue; @@ -289,7 +385,6 @@ export class AccountsStakingPayoutsService extends AbstractService { // This should not happen once at this point, but here for safety continue; } - if (!validatorLedger) { continue; } @@ -313,6 +408,8 @@ export class AccountsStakingPayoutsService extends AbstractService { } else { continue; } + } else if (eraIndex.toNumber() < 518) { + indexOfEra = eraIndex.toNumber(); } else { continue; } @@ -351,10 +448,9 @@ export class AccountsStakingPayoutsService extends AbstractService { /** * Fetch the `commission` and `StakingLedger` of `validatorId`. * - * @param api + * @param historicApi Historic api for querying past blocks * @param validatorId accountId of a validator's _Stash_ account * @param era the era to query - * @param hash `BlockHash` to make call at * @param validatorLedgerCache object mapping validatorId => StakingLedger to limit redundant queries */ private async fetchCommissionAndLedger( @@ -363,20 +459,33 @@ export class AccountsStakingPayoutsService extends AbstractService { era: number, validatorLedgerCache: { [id: string]: PalletStakingStakingLedger }, ): Promise { - let commission; + let commission: Perbill; let validatorLedger; + let commissionPromise; + const ancient: boolean = era < 518; if (validatorId in validatorLedgerCache) { validatorLedger = validatorLedgerCache[validatorId]; - const prefs = await historicApi.query.staking.erasValidatorPrefs(era, validatorId); - - commission = prefs.commission.unwrap(); + let prefs: PalletStakingValidatorPrefs | ValidatorPrefsWithCommission; + if (!ancient) { + prefs = await historicApi.query.staking.erasValidatorPrefs(era, validatorId); + commission = prefs.commission.unwrap(); + } else { + prefs = (await historicApi.query.staking.validators(validatorId)) as ValidatorPrefsWithCommission; + commission = (prefs[0] as PalletStakingValidatorPrefs | ValidatorPrefsWithCommission).commission.unwrap(); + } } else { + commissionPromise = ancient + ? historicApi.query.staking.validators(validatorId) + : historicApi.query.staking.erasValidatorPrefs(era, validatorId); + const [prefs, validatorControllerOption] = await Promise.all([ - historicApi.query.staking.erasValidatorPrefs(era, validatorId), + commissionPromise, historicApi.query.staking.bonded(validatorId), ]); - commission = prefs.commission.unwrap(); + commission = ancient + ? (prefs[0] as PalletStakingValidatorPrefs | ValidatorPrefsWithCommission).commission.unwrap() + : prefs.commission.unwrap(); if (validatorControllerOption.isNone) { return { @@ -385,7 +494,6 @@ export class AccountsStakingPayoutsService extends AbstractService { } const validatorLedgerOption = await historicApi.query.staking.ledger(validatorControllerOption.unwrap()); - if (validatorLedgerOption.isNone) { return { commission, @@ -406,14 +514,18 @@ export class AccountsStakingPayoutsService extends AbstractService { * The original version uses the base ApiDerive implementation which does not include the ApiDecoration implementation. * It is required in this version to query older blocks for their historic data. * - * @param historicApi - * @param eraIndex + * @param historicApi Historic api for querying past blocks + * @param eraIndex index of the era to query */ private async deriveEraExposure( historicApi: ApiDecoration<'promise'>, eraIndex: EraIndex, - ): Promise { - function mapStakers(era: EraIndex, stakers: KeysAndExposures): DeriveEraExposure { + ): Promise { + function mapStakers( + era: EraIndex, + stakers: KeysAndExposures, + validatorIndex: ValidatorIndex, + ): IAdjustedDeriveEraExposure { const nominators: DeriveEraNominatorExposure = {}; const validators: DeriveEraValidatorExposure = {}; @@ -429,26 +541,66 @@ export class AccountsStakingPayoutsService extends AbstractService { nominators[nominatorId].push({ validatorId, validatorIndex }); }); }); - - return { era, nominators, validators }; + if (Object.keys(validatorIndex).length > 0) { + return { era, nominators, validators, validatorIndex }; + } else { + return { era, nominators, validators }; + } } + let storageKeys: KeysAndExposures = []; - const eraExposure = await historicApi.query.staking.erasStakersClipped.entries(eraIndex); + const validatorIndex: ValidatorIndex = {}; - return mapStakers(eraIndex, eraExposure); - } + if (historicApi.query.staking.erasStakersClipped) { + storageKeys = await historicApi.query.staking.erasStakersClipped.entries(eraIndex); + } else { + const validators: Vec = (await historicApi.query.staking.currentElected()) as Vec; + + const validatorId: AccountId[] = []; + + validators.map((validator, index) => { + validatorIndex[validator.toString()] = index; + validatorId.push(validator); + }); + + let eraExposure: PalletStakingExposure = {} as PalletStakingExposure; + + for (const validator of validatorId) { + const storageKey = { + args: [eraIndex, validator], + } as unknown as StorageKey<[EraIndex, AccountId]>; + eraExposure = (await historicApi.query.staking.stakers(validator)) as unknown as PalletStakingExposure; + storageKeys.push([storageKey, eraExposure]); + } + } + return mapStakers(eraIndex, storageKeys, validatorIndex); + } /** * Extract the reward points of `validatorId` from `EraRewardPoints`. * * @param eraRewardPoints * @param validatorId accountId of a validator's _Stash_ account + * @param validatorIndex index of the validator in relation to the `EraPoints` + * array * */ - private extractTotalValidatorRewardPoints(eraRewardPoints: PalletStakingEraRewardPoints, validatorId: string) { + private extractTotalValidatorRewardPoints( + eraRewardPoints: PalletStakingEraRewardPoints | EraPoints, + validatorId: string, + validatorIndex?: ValidatorIndex, + ) { // Ideally we would just use the map's `get`, but that does not seem to be working here - for (const [id, points] of eraRewardPoints.individual.entries()) { - if (id.toString() === validatorId) { - return points; + if (validatorIndex === undefined) { + for (const [id, points] of eraRewardPoints.individual.entries()) { + if (id.toString() === validatorId) { + return points; + } + } + } else { + for (const [id, points] of eraRewardPoints.individual.entries()) { + if (id.toString() === validatorIndex[validatorId.toString()].toString()) { + return points; + } } } @@ -461,9 +613,9 @@ export class AccountsStakingPayoutsService extends AbstractService { * * @param address address of the _Stash_ account to get the exposure of behind `validatorId` * @param validatorId accountId of a validator's _Stash_ account - * @param deriveEraExposure + * @param deriveEraExposure result of deriveEraExposure */ - private extractExposure(address: string, validatorId: string, deriveEraExposure: DeriveEraExposure) { + private extractExposure(address: string, validatorId: string, deriveEraExposure: IAdjustedDeriveEraExposure) { // Get total stake behind validator const totalExposure = deriveEraExposure.validators[validatorId].total; @@ -490,7 +642,7 @@ export class AccountsStakingPayoutsService extends AbstractService { */ deriveNominatedExposures( address: string, - deriveEraExposure: DeriveEraExposure, + deriveEraExposure: IAdjustedDeriveEraExposure, ): DeriveEraExposureNominating[] | undefined { let nominatedExposures: DeriveEraExposureNominating[] = deriveEraExposure.nominators[address] ?? []; if (deriveEraExposure.validators[address]) { diff --git a/src/services/accounts/kusamaEarlyErasBlockInfo.json b/src/services/accounts/kusamaEarlyErasBlockInfo.json new file mode 100644 index 000000000..34aaecfa2 --- /dev/null +++ b/src/services/accounts/kusamaEarlyErasBlockInfo.json @@ -0,0 +1,2083 @@ +{ + "0": { + "start": 0, + "end": 27574 + }, + "1": { + "start": 27575, + "end": 28174 + }, + "2": { + "start": 28175, + "end": 28636 + }, + "3": { + "start": 28637, + "end": 29098 + }, + "4": { + "start": 29099, + "end": 29677 + }, + "5": { + "start": 29678, + "end": 30244 + }, + "6": { + "start": 30245, + "end": 30818 + }, + "7": { + "start": 30819, + "end": 31379 + }, + "8": { + "start": 31380, + "end": 31928 + }, + "9": { + "start": 31929, + "end": 32467 + }, + "10": { + "start": 32468, + "end": 33010 + }, + "11": { + "start": 33011, + "end": 33592 + }, + "12": { + "start": 33593, + "end": 34129 + }, + "13": { + "start": 34130, + "end": 34678 + }, + "14": { + "start": 34679, + "end": 35260 + }, + "15": { + "start": 35261, + "end": 35841 + }, + "16": { + "start": 35842, + "end": 36429 + }, + "17": { + "start": 36430, + "end": 37025 + }, + "18": { + "start": 37026, + "end": 37621 + }, + "19": { + "start": 37622, + "end": 38211 + }, + "20": { + "start": 38212, + "end": 38792 + }, + "21": { + "start": 38793, + "end": 39360 + }, + "22": { + "start": 39361, + "end": 39937 + }, + "23": { + "start": 39938, + "end": 40524 + }, + "24": { + "start": 40525, + "end": 41092 + }, + "25": { + "start": 41093, + "end": 41673 + }, + "26": { + "start": 41674, + "end": 42262 + }, + "27": { + "start": 42263, + "end": 42852 + }, + "28": { + "start": 42853, + "end": 43447 + }, + "29": { + "start": 43448, + "end": 44038 + }, + "30": { + "start": 44039, + "end": 44624 + }, + "31": { + "start": 44625, + "end": 45219 + }, + "32": { + "start": 45220, + "end": 45811 + }, + "33": { + "start": 45812, + "end": 46407 + }, + "34": { + "start": 46408, + "end": 47002 + }, + "35": { + "start": 47003, + "end": 47600 + }, + "36": { + "start": 47601, + "end": 48196 + }, + "37": { + "start": 48197, + "end": 48794 + }, + "38": { + "start": 48795, + "end": 49390 + }, + "39": { + "start": 49391, + "end": 49988 + }, + "40": { + "start": 49989, + "end": 50586 + }, + "41": { + "start": 50587, + "end": 51180 + }, + "42": { + "start": 51181, + "end": 51778 + }, + "43": { + "start": 51779, + "end": 52377 + }, + "44": { + "start": 52378, + "end": 52976 + }, + "45": { + "start": 52977, + "end": 53571 + }, + "46": { + "start": 53572, + "end": 54170 + }, + "47": { + "start": 54171, + "end": 54765 + }, + "48": { + "start": 54766, + "end": 55359 + }, + "49": { + "start": 55360, + "end": 55952 + }, + "50": { + "start": 55953, + "end": 56543 + }, + "51": { + "start": 56544, + "end": 57126 + }, + "52": { + "start": 57127, + "end": 57708 + }, + "53": { + "start": 57709, + "end": 58296 + }, + "54": { + "start": 58297, + "end": 58881 + }, + "55": { + "start": 58882, + "end": 59469 + }, + "56": { + "start": 59470, + "end": 60049 + }, + "57": { + "start": 60050, + "end": 60628 + }, + "58": { + "start": 60629, + "end": 61199 + }, + "59": { + "start": 61200, + "end": 61771 + }, + "60": { + "start": 61772, + "end": 62341 + }, + "61": { + "start": 62342, + "end": 62918 + }, + "62": { + "start": 62919, + "end": 63488 + }, + "63": { + "start": 63489, + "end": 64068 + }, + "64": { + "start": 64069, + "end": 64648 + }, + "65": { + "start": 64649, + "end": 65219 + }, + "66": { + "start": 65220, + "end": 65791 + }, + "67": { + "start": 65792, + "end": 66357 + }, + "68": { + "start": 66358, + "end": 66931 + }, + "69": { + "start": 66932, + "end": 67497 + }, + "70": { + "start": 67498, + "end": 68034 + }, + "71": { + "start": 68035, + "end": 68593 + }, + "72": { + "start": 68594, + "end": 69148 + }, + "73": { + "start": 69149, + "end": 69710 + }, + "74": { + "start": 69711, + "end": 70279 + }, + "75": { + "start": 70280, + "end": 70854 + }, + "76": { + "start": 70855, + "end": 71413 + }, + "77": { + "start": 71414, + "end": 71975 + }, + "78": { + "start": 71976, + "end": 72541 + }, + "79": { + "start": 72542, + "end": 73102 + }, + "80": { + "start": 73103, + "end": 73652 + }, + "81": { + "start": 73653, + "end": 74201 + }, + "82": { + "start": 74202, + "end": 74734 + }, + "83": { + "start": 74735, + "end": 75286 + }, + "84": { + "start": 75287, + "end": 75852 + }, + "85": { + "start": 75853, + "end": 76413 + }, + "86": { + "start": 76414, + "end": 76967 + }, + "87": { + "start": 76968, + "end": 77518 + }, + "88": { + "start": 77519, + "end": 78057 + }, + "89": { + "start": 78058, + "end": 78605 + }, + "90": { + "start": 78606, + "end": 79145 + }, + "91": { + "start": 79146, + "end": 79665 + }, + "92": { + "start": 79666, + "end": 80185 + }, + "93": { + "start": 80186, + "end": 80689 + }, + "94": { + "start": 80690, + "end": 81210 + }, + "95": { + "start": 81211, + "end": 81739 + }, + "96": { + "start": 81740, + "end": 82268 + }, + "97": { + "start": 82269, + "end": 82837 + }, + "98": { + "start": 82838, + "end": 83414 + }, + "99": { + "start": 83415, + "end": 83998 + }, + "100": { + "start": 83999, + "end": 84581 + }, + "101": { + "start": 84582, + "end": 85146 + }, + "102": { + "start": 85147, + "end": 85707 + }, + "103": { + "start": 85708, + "end": 89205 + }, + "104": { + "start": 89206, + "end": 92748 + }, + "105": { + "start": 92749, + "end": 96268 + }, + "106": { + "start": 96269, + "end": 99743 + }, + "107": { + "start": 99744, + "end": 103277 + }, + "108": { + "start": 103278, + "end": 106786 + }, + "109": { + "start": 106787, + "end": 110294 + }, + "110": { + "start": 110295, + "end": 113797 + }, + "111": { + "start": 113798, + "end": 117325 + }, + "112": { + "start": 117326, + "end": 120865 + }, + "113": { + "start": 120866, + "end": 124400 + }, + "114": { + "start": 124401, + "end": 127923 + }, + "115": { + "start": 127924, + "end": 131478 + }, + "116": { + "start": 131479, + "end": 135006 + }, + "117": { + "start": 135007, + "end": 138541 + }, + "118": { + "start": 138542, + "end": 142079 + }, + "119": { + "start": 142080, + "end": 145620 + }, + "120": { + "start": 145621, + "end": 149148 + }, + "121": { + "start": 149149, + "end": 152702 + }, + "122": { + "start": 152703, + "end": 156210 + }, + "123": { + "start": 156211, + "end": 159751 + }, + "124": { + "start": 159752, + "end": 163254 + }, + "125": { + "start": 163255, + "end": 166758 + }, + "126": { + "start": 166759, + "end": 170279 + }, + "127": { + "start": 170280, + "end": 173789 + }, + "128": { + "start": 173790, + "end": 177331 + }, + "129": { + "start": 177332, + "end": 180837 + }, + "130": { + "start": 180838, + "end": 184369 + }, + "131": { + "start": 184370, + "end": 187897 + }, + "132": { + "start": 187898, + "end": 191407 + }, + "133": { + "start": 191408, + "end": 194916 + }, + "134": { + "start": 194917, + "end": 198444 + }, + "135": { + "start": 198445, + "end": 201971 + }, + "136": { + "start": 201972, + "end": 205523 + }, + "137": { + "start": 205524, + "end": 209048 + }, + "138": { + "start": 209049, + "end": 212588 + }, + "139": { + "start": 212589, + "end": 216118 + }, + "140": { + "start": 216119, + "end": 219648 + }, + "141": { + "start": 219649, + "end": 223168 + }, + "142": { + "start": 223169, + "end": 226679 + }, + "143": { + "start": 226680, + "end": 230210 + }, + "144": { + "start": 230211, + "end": 233757 + }, + "145": { + "start": 233758, + "end": 237284 + }, + "146": { + "start": 237285, + "end": 240830 + }, + "147": { + "start": 240831, + "end": 244384 + }, + "148": { + "start": 244385, + "end": 247944 + }, + "149": { + "start": 247945, + "end": 251491 + }, + "150": { + "start": 251492, + "end": 255025 + }, + "151": { + "start": 255026, + "end": 258559 + }, + "152": { + "start": 258560, + "end": 262088 + }, + "153": { + "start": 262089, + "end": 265606 + }, + "154": { + "start": 265607, + "end": 269152 + }, + "155": { + "start": 269153, + "end": 272687 + }, + "156": { + "start": 272688, + "end": 276234 + }, + "157": { + "start": 276235, + "end": 279768 + }, + "158": { + "start": 279769, + "end": 283298 + }, + "159": { + "start": 283299, + "end": 286840 + }, + "160": { + "start": 286841, + "end": 290358 + }, + "161": { + "start": 290359, + "end": 293904 + }, + "162": { + "start": 293905, + "end": 297451 + }, + "163": { + "start": 297452, + "end": 301001 + }, + "164": { + "start": 301002, + "end": 304550 + }, + "165": { + "start": 304551, + "end": 308063 + }, + "166": { + "start": 308064, + "end": 311576 + }, + "167": { + "start": 311577, + "end": 315098 + }, + "168": { + "start": 315099, + "end": 318622 + }, + "169": { + "start": 318623, + "end": 322154 + }, + "170": { + "start": 322155, + "end": 325679 + }, + "171": { + "start": 325680, + "end": 329200 + }, + "172": { + "start": 329201, + "end": 332735 + }, + "173": { + "start": 332736, + "end": 336247 + }, + "174": { + "start": 336248, + "end": 339741 + }, + "175": { + "start": 339742, + "end": 343213 + }, + "176": { + "start": 343214, + "end": 346724 + }, + "177": { + "start": 346725, + "end": 350210 + }, + "178": { + "start": 350211, + "end": 353712 + }, + "179": { + "start": 353713, + "end": 357239 + }, + "180": { + "start": 357240, + "end": 360735 + }, + "181": { + "start": 360736, + "end": 364225 + }, + "182": { + "start": 364226, + "end": 367721 + }, + "183": { + "start": 367722, + "end": 371227 + }, + "184": { + "start": 371228, + "end": 374752 + }, + "185": { + "start": 374753, + "end": 378253 + }, + "186": { + "start": 378254, + "end": 381775 + }, + "187": { + "start": 381776, + "end": 385257 + }, + "188": { + "start": 385258, + "end": 388786 + }, + "189": { + "start": 388787, + "end": 392272 + }, + "190": { + "start": 392273, + "end": 395780 + }, + "191": { + "start": 395781, + "end": 399304 + }, + "192": { + "start": 399305, + "end": 402848 + }, + "193": { + "start": 402849, + "end": 406368 + }, + "194": { + "start": 406369, + "end": 409886 + }, + "195": { + "start": 409887, + "end": 413400 + }, + "196": { + "start": 413401, + "end": 416923 + }, + "197": { + "start": 416924, + "end": 420420 + }, + "198": { + "start": 420421, + "end": 423919 + }, + "199": { + "start": 423920, + "end": 427441 + }, + "200": { + "start": 427442, + "end": 430958 + }, + "201": { + "start": 430959, + "end": 434492 + }, + "202": { + "start": 434493, + "end": 437987 + }, + "203": { + "start": 437988, + "end": 441515 + }, + "204": { + "start": 441516, + "end": 445041 + }, + "205": { + "start": 445042, + "end": 448569 + }, + "206": { + "start": 448570, + "end": 452072 + }, + "207": { + "start": 452073, + "end": 455591 + }, + "208": { + "start": 455592, + "end": 459111 + }, + "209": { + "start": 459112, + "end": 462626 + }, + "210": { + "start": 462627, + "end": 466110 + }, + "211": { + "start": 466111, + "end": 469627 + }, + "212": { + "start": 469628, + "end": 473156 + }, + "213": { + "start": 473157, + "end": 476640 + }, + "214": { + "start": 476641, + "end": 480110 + }, + "215": { + "start": 480111, + "end": 483597 + }, + "216": { + "start": 483598, + "end": 487050 + }, + "217": { + "start": 487051, + "end": 490547 + }, + "218": { + "start": 490548, + "end": 494050 + }, + "219": { + "start": 494051, + "end": 497568 + }, + "220": { + "start": 497569, + "end": 501062 + }, + "221": { + "start": 501063, + "end": 504535 + }, + "222": { + "start": 504536, + "end": 508014 + }, + "223": { + "start": 508015, + "end": 511488 + }, + "224": { + "start": 511489, + "end": 514951 + }, + "225": { + "start": 514952, + "end": 516940 + }, + "226": { + "start": 516941, + "end": 517149 + }, + "227": { + "start": 517150, + "end": 519240 + }, + "228": { + "start": 519241, + "end": 519578 + }, + "229": { + "start": 519579, + "end": 521695 + }, + "230": { + "start": 521696, + "end": 523853 + }, + "231": { + "start": 523854, + "end": 526063 + }, + "232": { + "start": 526064, + "end": 528196 + }, + "233": { + "start": 528197, + "end": 530275 + }, + "234": { + "start": 530276, + "end": 532480 + }, + "235": { + "start": 532481, + "end": 532801 + }, + "236": { + "start": 532802, + "end": 534993 + }, + "237": { + "start": 534994, + "end": 537172 + }, + "238": { + "start": 537173, + "end": 539204 + }, + "239": { + "start": 539205, + "end": 539441 + }, + "240": { + "start": 539442, + "end": 539658 + }, + "241": { + "start": 539659, + "end": 539875 + }, + "242": { + "start": 539876, + "end": 540139 + }, + "243": { + "start": 540140, + "end": 541248 + }, + "244": { + "start": 541249, + "end": 541449 + }, + "245": { + "start": 541450, + "end": 541581 + }, + "246": { + "start": 541582, + "end": 541665 + }, + "247": { + "start": 541666, + "end": 541817 + }, + "248": { + "start": 541818, + "end": 542218 + }, + "249": { + "start": 542219, + "end": 542260 + }, + "250": { + "start": 542261, + "end": 542328 + }, + "251": { + "start": 542329, + "end": 542511 + }, + "252": { + "start": 542512, + "end": 543377 + }, + "253": { + "start": 543378, + "end": 543944 + }, + "254": { + "start": 543945, + "end": 544154 + }, + "255": { + "start": 544155, + "end": 544330 + }, + "256": { + "start": 544331, + "end": 544488 + }, + "257": { + "start": 544489, + "end": 544667 + }, + "258": { + "start": 544668, + "end": 544915 + }, + "259": { + "start": 544916, + "end": 545276 + }, + "260": { + "start": 545277, + "end": 545579 + }, + "261": { + "start": 545580, + "end": 545849 + }, + "262": { + "start": 545850, + "end": 546105 + }, + "263": { + "start": 546106, + "end": 546287 + }, + "264": { + "start": 546288, + "end": 546495 + }, + "265": { + "start": 546496, + "end": 546749 + }, + "266": { + "start": 546750, + "end": 546927 + }, + "267": { + "start": 546928, + "end": 547145 + }, + "268": { + "start": 547146, + "end": 547362 + }, + "269": { + "start": 547363, + "end": 547651 + }, + "270": { + "start": 547652, + "end": 547918 + }, + "271": { + "start": 547919, + "end": 548261 + }, + "272": { + "start": 548262, + "end": 548616 + }, + "273": { + "start": 548617, + "end": 551616 + }, + "274": { + "start": 551617, + "end": 554740 + }, + "275": { + "start": 554741, + "end": 558036 + }, + "276": { + "start": 558037, + "end": 561344 + }, + "277": { + "start": 561345, + "end": 564660 + }, + "278": { + "start": 564661, + "end": 568055 + }, + "279": { + "start": 568056, + "end": 571376 + }, + "280": { + "start": 571377, + "end": 574787 + }, + "281": { + "start": 574788, + "end": 578232 + }, + "282": { + "start": 578233, + "end": 581685 + }, + "283": { + "start": 581686, + "end": 585106 + }, + "284": { + "start": 585107, + "end": 588462 + }, + "285": { + "start": 588463, + "end": 591829 + }, + "286": { + "start": 591830, + "end": 595180 + }, + "287": { + "start": 595181, + "end": 598606 + }, + "288": { + "start": 598607, + "end": 601918 + }, + "289": { + "start": 601919, + "end": 605434 + }, + "290": { + "start": 605435, + "end": 608949 + }, + "291": { + "start": 608950, + "end": 612435 + }, + "292": { + "start": 612436, + "end": 615809 + }, + "293": { + "start": 615810, + "end": 619188 + }, + "294": { + "start": 619189, + "end": 622582 + }, + "295": { + "start": 622583, + "end": 625878 + }, + "296": { + "start": 625879, + "end": 629267 + }, + "297": { + "start": 629268, + "end": 632619 + }, + "298": { + "start": 632620, + "end": 635952 + }, + "299": { + "start": 635953, + "end": 639199 + }, + "300": { + "start": 639200, + "end": 642552 + }, + "301": { + "start": 642553, + "end": 645922 + }, + "302": { + "start": 645923, + "end": 649312 + }, + "303": { + "start": 649313, + "end": 652690 + }, + "304": { + "start": 652691, + "end": 656098 + }, + "305": { + "start": 656099, + "end": 659539 + }, + "306": { + "start": 659540, + "end": 662988 + }, + "307": { + "start": 662989, + "end": 666368 + }, + "308": { + "start": 666369, + "end": 669764 + }, + "309": { + "start": 669765, + "end": 673269 + }, + "310": { + "start": 673270, + "end": 676744 + }, + "311": { + "start": 676745, + "end": 680273 + }, + "312": { + "start": 680274, + "end": 683797 + }, + "313": { + "start": 683798, + "end": 687336 + }, + "314": { + "start": 687337, + "end": 690875 + }, + "315": { + "start": 690876, + "end": 694129 + }, + "316": { + "start": 694130, + "end": 694675 + }, + "317": { + "start": 694676, + "end": 698093 + }, + "318": { + "start": 698094, + "end": 701635 + }, + "319": { + "start": 701636, + "end": 705208 + }, + "320": { + "start": 705209, + "end": 708713 + }, + "321": { + "start": 708714, + "end": 712203 + }, + "322": { + "start": 712204, + "end": 715735 + }, + "323": { + "start": 715736, + "end": 719269 + }, + "324": { + "start": 719270, + "end": 722809 + }, + "325": { + "start": 722810, + "end": 726334 + }, + "326": { + "start": 726335, + "end": 729861 + }, + "327": { + "start": 729862, + "end": 733397 + }, + "328": { + "start": 733398, + "end": 736907 + }, + "329": { + "start": 736908, + "end": 740412 + }, + "330": { + "start": 740413, + "end": 743925 + }, + "331": { + "start": 743926, + "end": 747423 + }, + "332": { + "start": 747424, + "end": 750910 + }, + "333": { + "start": 750911, + "end": 754406 + }, + "334": { + "start": 754407, + "end": 757906 + }, + "335": { + "start": 757907, + "end": 761434 + }, + "336": { + "start": 761435, + "end": 764913 + }, + "337": { + "start": 764914, + "end": 768388 + }, + "338": { + "start": 768389, + "end": 771889 + }, + "339": { + "start": 771890, + "end": 775392 + }, + "340": { + "start": 775393, + "end": 778902 + }, + "341": { + "start": 778903, + "end": 782405 + }, + "342": { + "start": 782406, + "end": 785917 + }, + "343": { + "start": 785918, + "end": 789429 + }, + "344": { + "start": 789430, + "end": 792937 + }, + "345": { + "start": 792938, + "end": 796424 + }, + "346": { + "start": 796425, + "end": 799913 + }, + "347": { + "start": 799914, + "end": 803408 + }, + "348": { + "start": 803409, + "end": 806915 + }, + "349": { + "start": 806916, + "end": 810421 + }, + "350": { + "start": 810422, + "end": 813912 + }, + "351": { + "start": 813913, + "end": 817428 + }, + "352": { + "start": 817429, + "end": 820941 + }, + "353": { + "start": 820942, + "end": 824417 + }, + "354": { + "start": 824418, + "end": 827929 + }, + "355": { + "start": 827930, + "end": 831427 + }, + "356": { + "start": 831428, + "end": 834947 + }, + "357": { + "start": 834948, + "end": 838412 + }, + "358": { + "start": 838413, + "end": 841875 + }, + "359": { + "start": 841876, + "end": 845333 + }, + "360": { + "start": 845334, + "end": 848800 + }, + "361": { + "start": 848801, + "end": 852257 + }, + "362": { + "start": 852258, + "end": 855729 + }, + "363": { + "start": 855730, + "end": 859195 + }, + "364": { + "start": 859196, + "end": 862658 + }, + "365": { + "start": 862659, + "end": 866089 + }, + "366": { + "start": 866090, + "end": 869583 + }, + "367": { + "start": 869584, + "end": 873082 + }, + "368": { + "start": 873083, + "end": 876580 + }, + "369": { + "start": 876581, + "end": 880087 + }, + "370": { + "start": 880088, + "end": 883616 + }, + "371": { + "start": 883617, + "end": 887118 + }, + "372": { + "start": 887119, + "end": 890624 + }, + "373": { + "start": 890625, + "end": 894121 + }, + "374": { + "start": 894122, + "end": 897617 + }, + "375": { + "start": 897618, + "end": 901108 + }, + "376": { + "start": 901109, + "end": 901628 + }, + "377": { + "start": 901629, + "end": 901929 + }, + "378": { + "start": 901930, + "end": 904779 + }, + "379": { + "start": 904780, + "end": 907820 + }, + "380": { + "start": 907821, + "end": 911024 + }, + "381": { + "start": 911025, + "end": 914237 + }, + "382": { + "start": 914238, + "end": 917427 + }, + "383": { + "start": 917428, + "end": 920628 + }, + "384": { + "start": 920629, + "end": 923846 + }, + "385": { + "start": 923847, + "end": 927081 + }, + "386": { + "start": 927082, + "end": 930216 + }, + "387": { + "start": 930217, + "end": 933335 + }, + "388": { + "start": 933336, + "end": 936495 + }, + "389": { + "start": 936496, + "end": 939642 + }, + "390": { + "start": 939643, + "end": 942749 + }, + "391": { + "start": 942750, + "end": 945918 + }, + "392": { + "start": 945919, + "end": 949073 + }, + "393": { + "start": 949074, + "end": 952225 + }, + "394": { + "start": 952226, + "end": 955292 + }, + "395": { + "start": 955293, + "end": 958390 + }, + "396": { + "start": 958391, + "end": 961442 + }, + "397": { + "start": 961443, + "end": 964491 + }, + "398": { + "start": 964492, + "end": 967527 + }, + "399": { + "start": 967528, + "end": 970607 + }, + "400": { + "start": 970608, + "end": 973645 + }, + "401": { + "start": 973646, + "end": 976674 + }, + "402": { + "start": 976675, + "end": 979719 + }, + "403": { + "start": 979720, + "end": 982859 + }, + "404": { + "start": 982860, + "end": 985938 + }, + "405": { + "start": 985939, + "end": 989015 + }, + "406": { + "start": 989016, + "end": 992146 + }, + "407": { + "start": 992147, + "end": 995364 + }, + "408": { + "start": 995365, + "end": 998543 + }, + "409": { + "start": 998544, + "end": 1001763 + }, + "410": { + "start": 1001764, + "end": 1004935 + }, + "411": { + "start": 1004936, + "end": 1008152 + }, + "412": { + "start": 1008153, + "end": 1011372 + }, + "413": { + "start": 1011373, + "end": 1014616 + }, + "414": { + "start": 1014617, + "end": 1017848 + }, + "415": { + "start": 1017849, + "end": 1021069 + }, + "416": { + "start": 1021070, + "end": 1024328 + }, + "417": { + "start": 1024329, + "end": 1027604 + }, + "418": { + "start": 1027605, + "end": 1030902 + }, + "419": { + "start": 1030903, + "end": 1034240 + }, + "420": { + "start": 1034241, + "end": 1037534 + }, + "421": { + "start": 1037535, + "end": 1040804 + }, + "422": { + "start": 1040805, + "end": 1044067 + }, + "423": { + "start": 1044068, + "end": 1047367 + }, + "424": { + "start": 1047368, + "end": 1050631 + }, + "425": { + "start": 1050632, + "end": 1053930 + }, + "426": { + "start": 1053931, + "end": 1057266 + }, + "427": { + "start": 1057267, + "end": 1060550 + }, + "428": { + "start": 1060551, + "end": 1063876 + }, + "429": { + "start": 1063877, + "end": 1067169 + }, + "430": { + "start": 1067170, + "end": 1070468 + }, + "431": { + "start": 1070469, + "end": 1073791 + }, + "432": { + "start": 1073792, + "end": 1077124 + }, + "433": { + "start": 1077125, + "end": 1080453 + }, + "434": { + "start": 1080454, + "end": 1083789 + }, + "435": { + "start": 1083790, + "end": 1087290 + }, + "436": { + "start": 1087291, + "end": 1090782 + }, + "437": { + "start": 1090783, + "end": 1094253 + }, + "438": { + "start": 1094254, + "end": 1097747 + }, + "439": { + "start": 1097748, + "end": 1101265 + }, + "440": { + "start": 1101266, + "end": 1104774 + }, + "441": { + "start": 1104775, + "end": 1108298 + }, + "442": { + "start": 1108299, + "end": 1111785 + }, + "443": { + "start": 1111786, + "end": 1115296 + }, + "444": { + "start": 1115297, + "end": 1118812 + }, + "445": { + "start": 1118813, + "end": 1122324 + }, + "446": { + "start": 1122325, + "end": 1125828 + }, + "447": { + "start": 1125829, + "end": 1129318 + }, + "448": { + "start": 1129319, + "end": 1132860 + }, + "449": { + "start": 1132861, + "end": 1136389 + }, + "450": { + "start": 1136390, + "end": 1139934 + }, + "451": { + "start": 1139935, + "end": 1143473 + }, + "452": { + "start": 1143474, + "end": 1147007 + }, + "453": { + "start": 1147008, + "end": 1150551 + }, + "454": { + "start": 1150552, + "end": 1154091 + }, + "455": { + "start": 1154092, + "end": 1157618 + }, + "456": { + "start": 1157619, + "end": 1161141 + }, + "457": { + "start": 1161142, + "end": 1164684 + }, + "458": { + "start": 1164685, + "end": 1168203 + }, + "459": { + "start": 1168204, + "end": 1171738 + }, + "460": { + "start": 1171739, + "end": 1175282 + }, + "461": { + "start": 1175283, + "end": 1178812 + }, + "462": { + "start": 1178813, + "end": 1182348 + }, + "463": { + "start": 1182349, + "end": 1185892 + }, + "464": { + "start": 1185893, + "end": 1189434 + }, + "465": { + "start": 1189435, + "end": 1192973 + }, + "466": { + "start": 1192974, + "end": 1196483 + }, + "467": { + "start": 1196484, + "end": 1200019 + }, + "468": { + "start": 1200020, + "end": 1203568 + }, + "469": { + "start": 1203569, + "end": 1207092 + }, + "470": { + "start": 1207093, + "end": 1210587 + }, + "471": { + "start": 1210588, + "end": 1214084 + }, + "472": { + "start": 1214085, + "end": 1217599 + }, + "473": { + "start": 1217600, + "end": 1221098 + }, + "474": { + "start": 1221099, + "end": 1224602 + }, + "475": { + "start": 1224603, + "end": 1228151 + }, + "476": { + "start": 1228152, + "end": 1231707 + }, + "477": { + "start": 1231708, + "end": 1235240 + }, + "478": { + "start": 1235241, + "end": 1238778 + }, + "479": { + "start": 1238779, + "end": 1242267 + }, + "480": { + "start": 1242268, + "end": 1245768 + }, + "481": { + "start": 1245769, + "end": 1249293 + }, + "482": { + "start": 1249294, + "end": 1252802 + }, + "483": { + "start": 1252803, + "end": 1256354 + }, + "484": { + "start": 1256355, + "end": 1259881 + }, + "485": { + "start": 1259882, + "end": 1263419 + }, + "486": { + "start": 1263420, + "end": 1266963 + }, + "487": { + "start": 1266964, + "end": 1270490 + }, + "488": { + "start": 1270491, + "end": 1274009 + }, + "489": { + "start": 1274010, + "end": 1277527 + }, + "490": { + "start": 1277528, + "end": 1281082 + }, + "491": { + "start": 1281083, + "end": 1284627 + }, + "492": { + "start": 1284628, + "end": 1288155 + }, + "493": { + "start": 1288156, + "end": 1291691 + }, + "494": { + "start": 1291692, + "end": 1295220 + }, + "495": { + "start": 1295221, + "end": 1298689 + }, + "496": { + "start": 1298690, + "end": 1302209 + }, + "497": { + "start": 1302210, + "end": 1305740 + }, + "498": { + "start": 1305741, + "end": 1309285 + }, + "499": { + "start": 1309286, + "end": 1312852 + }, + "500": { + "start": 1312853, + "end": 1316394 + }, + "501": { + "start": 1316395, + "end": 1319940 + }, + "502": { + "start": 1319941, + "end": 1323444 + }, + "503": { + "start": 1323445, + "end": 1326964 + }, + "504": { + "start": 1326965, + "end": 1330482 + }, + "505": { + "start": 1330483, + "end": 1333985 + }, + "506": { + "start": 1333986, + "end": 1337532 + }, + "507": { + "start": 1337533, + "end": 1341082 + }, + "508": { + "start": 1341083, + "end": 1344604 + }, + "509": { + "start": 1344605, + "end": 1348144 + }, + "510": { + "start": 1348145, + "end": 1351694 + }, + "511": { + "start": 1351695, + "end": 1355264 + }, + "512": { + "start": 1355265, + "end": 1358845 + }, + "513": { + "start": 1358846, + "end": 1362290 + }, + "514": { + "start": 1362291, + "end": 1365876 + }, + "515": { + "start": 1365877, + "end": 1369443 + }, + "516": { + "start": 1369444, + "end": 1372996 + }, + "517": { + "start": 1372997, + "end": 1375278 + }, + "518": { + "start": 1375279, + "end": 1378035 + }, + "519": { + "start": 1378036, + "end": 1381549 + + } +} \ No newline at end of file