diff --git a/client/.babelrc b/client/.babelrc new file mode 100644 index 00000000..1c237aed --- /dev/null +++ b/client/.babelrc @@ -0,0 +1,13 @@ +{ + "presets": [ + "@babel/preset-env", + "@babel/preset-react", + [ + "@babel/preset-typescript", + { + "optimizeConstEnums": true + } + ] + ], + "plugins": ["babel-plugin-styled-components"] +} diff --git a/client/.env.example b/client/.env.example index e8879c45..14a67fe0 100644 --- a/client/.env.example +++ b/client/.env.example @@ -1,5 +1,13 @@ NODE_ENV=development # This defaults to localhost in development regardless of the value set in this file -DF_DEFAULT_RPC=https://rpc-df.xdaichain.com/ -# Removing this value will disable all webserver calls in the client -DF_WEBSERVER_URL=http://localhost:3000 +DEFAULT_RPC=https://rpc-df.xdaichain.com/ +# Removing this value will disable all webserver calls in the client. + +# Arena does not have a webserver, so we comment this out. +# DF_WEBSERVER_URL=http://localhost:3000 + +# If you want to use a faucet, put url here +DFDAO_WEBSERVER_URL=http://localhost:3003 + +# If you want to use just the Twitter integration, add this: +DF_TWITTER_URL=https://api.zkga.me \ No newline at end of file diff --git a/client/README.md b/client/README.md index 0493b0e5..6b70495a 100644 --- a/client/README.md +++ b/client/README.md @@ -4,8 +4,8 @@ ### Installing Core Dependencies -- Node (v16.x) -- Npm (v8+) +- Node (v14.x OR v16.x) +- Yarn (Javascript Package Manager) #### Installing The Correct Node Version Using NVM @@ -18,13 +18,15 @@ nvm install After the installation is finished, you can run `node --version` to verify that you are running v14 or v16 -#### Installing Dependencies +#### Installing Yarn -After you have Node & Npm installed, run `npm ci` to install the dependencies: +Refer to [Yarn's official documentation](https://classic.yarnpkg.com/en/docs/install) for the installation guide. + +After you have Yarn installed, run `yarn` to install the dependencies: ### Running the client -To connecting to the mainnet client, simply run `npm start`. When asked you can use your whitelist key or import your mainnet burner secret and home coordinates. +To connecting to the mainnet client, simply run `yarn start:prod`. When asked you can use your whitelist key or import your mainnet burner secret and home coordinates. ### Plugin development diff --git a/client/embedded_plugins/Admin-Controls.ts b/client/embedded_plugins/Admin-Controls.ts index a3d648cf..2b84f055 100644 --- a/client/embedded_plugins/Admin-Controls.ts +++ b/client/embedded_plugins/Admin-Controls.ts @@ -1,5 +1,5 @@ // organize-imports-ignore -import type { EthAddress, LocatablePlanet, LocationId, Planet } from '@dfdao/types'; +import type { EthAddress, LocatablePlanet, LocationId, Planet } from '@darkforest_eth/types'; import { MAX_ARTIFACT_RARITY, MAX_SPACESHIP_TYPE, @@ -9,14 +9,17 @@ import { MIN_BIOME, MAX_BIOME, //@ts-ignore -} from 'https://cdn.skypack.dev/@dfdao/constants'; +} from 'https://cdn.skypack.dev/@darkforest_eth/constants'; + //@ts-ignore +import { modPBigInt } from 'https://cdn.skypack.dev/@darkforest_eth/hashing'; //@ts-ignore -import { getPlanetNameHash } from 'https://cdn.skypack.dev/@dfdao/procedural'; +import { getPlanetNameHash } from 'https://cdn.skypack.dev/@darkforest_eth/procedural'; import { locationIdToDecStr, + artifactIdFromHexStr, locationIdFromDecStr, //@ts-ignore -} from 'https://cdn.skypack.dev/@dfdao/serde'; +} from 'https://cdn.skypack.dev/@darkforest_eth/serde'; import { ArtifactRarityNames, ArtifactType, @@ -27,7 +30,7 @@ import { PlanetTypeNames, WorldCoords, //@ts-ignore -} from 'https://cdn.skypack.dev/@dfdao/types'; +} from 'https://cdn.skypack.dev/@darkforest_eth/types'; import { html, render, @@ -79,6 +82,7 @@ async function createArtifact( methodName: 'adminGiveArtifact', }); tx.confirmedPromise.then(() => { + df.hardRefreshArtifact(artifactIdFromHexStr(tokenId.slice(2))); df.hardRefreshPlanet(planet.locationId); }); @@ -198,42 +202,42 @@ async function addAddressToWhitelist(address: EthAddress) { return tx; } -async function createPlanet(coords: WorldCoords, level: number, type: PlanetType) { - coords.x = Math.round(coords.x); - coords.y = Math.round(coords.y); +async function createPlanet( + coords: WorldCoords, + level: number, + type: PlanetType, + isSpawnPlanet: boolean, + isTargetPlanet: boolean +) { + coords.x = modPBigInt(Math.round(coords.x)).toString(); + coords.y = modPBigInt(Math.round(coords.y)).toString(); const location = df.locationBigIntFromCoords(coords).toString(); const perlinValue = df.biomebasePerlin(coords, true); const args = Promise.resolve([ { + location, x: coords.x, y: coords.y, + perlin: perlinValue, level, planetType: type, requireValidLocationId: false, - location: location, - perlin: perlinValue, + isTargetPlanet, + isSpawnPlanet, + blockedPlanetIds: [], }, ]); const tx = await df.submitTransaction({ args, contract: df.getContract(), - methodName: 'createPlanet', + methodName: 'createAndReveal', }); await tx.confirmedPromise; - const revealArgs = df.getSnarkHelper().getRevealArgs(coords.x, coords.y); - const revealTx = await df.submitTransaction({ - args: revealArgs, - contract: df.getContract(), - methodName: 'revealLocation', - }); - - await revealTx.confirmedPromise; - await df.hardRefreshPlanet(locationIdFromDecStr(location)); } @@ -354,13 +358,15 @@ function PlanetCreator() { const [planetType, setPlanetType] = useState(PlanetType.PLANET); const [choosingLocation, setChoosingLocation] = useState(false); const [planetCoords, setPlanetCoords] = useState(null); + const [isSpawn, setIsSpawn] = useState(false); + const [isTarget, setIsTarget] = useState(false); const placePlanet = useCallback( (coords: WorldCoords) => { - createPlanet(coords, parseInt(level), planetType); + createPlanet(coords, parseInt(level), planetType, isSpawn, isTarget); setChoosingLocation(false); }, - [level, planetType, setChoosingLocation] + [level, planetType, setChoosingLocation, isSpawn, isTarget] ); const updatePlanetCoords = useCallback( @@ -386,7 +392,7 @@ function PlanetCreator() { return html`
-

Create Planet

+ <${Heading} title="Create planet" />
+
+ setIsSpawn(!isSpawn)} + /> + ${' Spawn Planet'} +
+
+ setIsTarget(!isTarget)} + /> + ${' Target Planet'} +
${!choosingLocation && html` [lvl, PlanetLevelNames[lvl]]); + +const PLANET_TYPE = "PLANET_TYPE"; +const ALL_PLANET_TYPES = -1; // PlanetType is an Enum, values 0..4, so adding one more value here +const PLANET_TYPES = Object.values(PlanetType).map( type => [type, PlanetTypeNames[type]]); +PLANET_TYPES.push([ALL_PLANET_TYPES, "All types"]); + +const RANGE_MAX = "RANGE_MAX"; +const MAX_DISTANCE = 10 ** 8; +const RANGES = [ + [1000, "Up to 1000"], + [2000, "Up to 2000"], + [5000, "Up to 5000"], + [10000, "Up to 10,000"], + [20000, "Up to 20,000"], + [50000, "Up to 50,000"], + [100000, "Up to 100,000"], + [200000, "Up to 200,000"], + [500000, "Up to 500,000"], + [999999, "Up to 999,999"] +]; +const DEFAULT_RANGE_MAX = RANGES[DEFAULT_RANGE_INDEX][0]; + +// See Dark Forest Client, file: src/_types/global/GlobalTypes.ts/StatIdx +const StatIdx = { + EnergyCap: 0, + EnergyGro: 1, + Range: 2, + Speed: 3, + Defense: 4, + HalfJunk: 5, +} + +// Miscellaneous constants +const BASE_LINE_WIDTH_PX = 1.0; +const LINE_WIDTH_PLANET_LEVEL_FACTOR = 0.5; +const EXTRA_RADIUS_CANVAS_PX_ADD = 2.0; +const EXTRA_RADIUS_WORLD_PX_LINE_MULTIPLY = 1.15; +const EXTRA_RADIUS_WORLD_PX_PULSE_MULTIPLY = 1.30; +const ELLIPSE_FACTOR = 1.1; +const PULSES_PER_ROTATION = 3; // Number of pulses for full rotation of the circular or elliptical arc +const CIRC_START_RAD = 0; +const CIRC_END_RAD = 2 * Math.PI; +const PULSE_FAST_FACTOR = 2; // In fast mode, how much faster than normal mode +const ALWAYS_PULSE = 'ALWAYS_PULSE'; +const SMALL_TEXT_SIZE = "90%"; +const DEFAULT_ALPHA = 0.75; // If not pulsing alpha, use this constant alpha +const [DESYNC_X, DESYNC_Y] = [101, 103]; // Desynchronises pulsing of separate planets using prime numbers multiplied by canvas coord components +const TOGGLE_OFF = "TOGGLE_OFF"; // Planet arrays are not highlighted if they have this constant as first element (and will be otherwise empty) +const isToggledOn = (arr) => arr[0] !== TOGGLE_OFF; + +// When hovering over / mouseover a button, it is normal brightness +// Otherwise dim it by subtracting this number of RGB points, min=0 +const NON_HOVER_DIMMER = 15; +const getRgb = (arr, hover, invert=false) => { + const [r, g, b] = arr.map(c => hover ? (invert ? 255-c : c) : Math.max(0, (invert ? 255-c : c) - NON_HOVER_DIMMER)); + return `rgb(${r}, ${g}, ${b})` +} + +// Control default button RGB colours, for toggle off and on, and for background, text, and border +const buttonDefaultColours = { + off: { + bg: [50, 50, 50], + text: [200, 200, 200], + bord: [120, 120, 120], + }, + on: { + bg: [80, 80, 80], + text: [230, 230, 230], + bord: [200, 200, 200], + } +}; + +// Set up 7 different highlights + +// Pulsing period - use prime numbers to desynchronise flashing of any two buffs +const periodMsHighlightArtifact = 1201; // want artifact the fastest +const periodMsHighlightRip = 1279; +const periodMsHighlight2xEnergyCap = 1361; +const periodMsHighlight2xEnergyGro = 1451; +const periodMsHighlight2xDefense = 1543; +const periodMsHighlight2xSpeed = 1657; +const periodMsHighlight2xRange = 1753; +const periodMsHighlightHalfJunk = 1831; +const periodMsHighlightInvadeNoCapture = 1787; +const periodMsHighlightSpaceship = 1699; +const periodMsHighlightTarget = 1819; +const periodMsHighlightSpawn = 1947; + +// Set up colours for each of the highlights. Use similar colours to asteroid colour for 2x buffs. +const colsHighlightArtifact = [255, 100, 100]; +const colsHighlightRip = [80, 200, 255]; +const colsHighlight2xEnergyCap = [255, 160, 60]; +const colsHighlight2xEnergyGro = [120, 255, 120]; +const colsHighlight2xDefense = [180, 140, 255]; +const colsHighlight2xSpeed = [255, 100, 255]; +const colsHighlight2xRange = [225, 225, 80]; +const colsHighlightHalfJunk = [180, 150, 130]; +const colsHighlightInvadeNoCapture = [170, 255, 100]; +const colsHighlightSpaceship = [190, 100, 255]; +const colsHighlightTarget = [212, 175, 155]; +const colsHighlightSpawn = [69, 175, 155]; + +// Helper functions for spaceships +const loadAccounts = plugin => { + const knownAddresses = []; + const accounts = []; + const serializedAddresses = localStorage.getItem(ADDRESS_LOCAL_STORAGE_KEY); + if (serializedAddresses !== null) { + const addresses = JSON.parse(serializedAddresses); + for (const addressStr of addresses) { + knownAddresses.push(addressStr); + } + } + for (const addy of knownAddresses) { + accounts.push({ address: addy }); + } + plugin.accounts = accounts; +}; +const loadSpaceships = plugin => { + for (const acc of plugin.accounts) { + const spaceshipsOwnedByAccount = df.entityStore + .getArtifactsOwnedBy(acc.address) + .filter(artifact => isSpaceShip(artifact.artifactType)); + plugin.spaceships = [...plugin.spaceships, ...spaceshipsOwnedByAccount]; + } +}; + +// Helper functions for filters +const prospectExpired = (plugin, planet) => { + if (plugin.dateNow / 1000 > df.contractConstants.TOKEN_MINT_END_SECONDS) return true; // Round has ended + if (!planet.prospectedBlockNumber) return false; + if (planet.hasTriedFindingArtifact) return false; + return planet.prospectedBlockNumber + 255 - df.contractsAPI.ethConnection.blockNumber <= 0; // 256 blocks to prospect an artifact +} +const planetWasAlreadyInvaded = p => p.invader !== emptyAddress; +const planetWasAlreadyCaptured = p => p.capturer !== emptyAddress; +const planetHasRelevantSpaceship = (plugin, planet) => planet.heldArtifactIds.some(id => plugin.spaceships.some(spaceship => id === spaceship.id)); +const distanceToPlanetSquared = planet => planet.location ? (viewport.centerWorldCoords.x - planet.location.coords.x) ** 2 + (viewport.centerWorldCoords.y - planet.location.coords.y) ** 2 : MAX_DISTANCE; +const distanceInRange = (plugin, planet) => distanceToPlanetSquared(planet) <= plugin.getSelectValue(RANGE_MAX) ** 2; +const levelInRange = (plugin, planet) => plugin.getSelectValue(LEVEL_MIN) <= planet.planetLevel && planet.planetLevel <= plugin.getSelectValue(LEVEL_MAX); +const mainChecks = (plugin, planet) => levelInRange(plugin, planet) && distanceInRange(plugin, planet) && !planet.destroyed; +const planetTypeMatches = (plugin, planet) => { + const type = plugin.getSelectValue(PLANET_TYPE); + return type === ALL_PLANET_TYPES || type === planet.planetType; +}; +const filter2xStat = (statIdx, upgradeIdx=-1) => (plugin, planet) => mainChecks(plugin, planet) && planetTypeMatches(plugin, planet) && (planet.bonus && planet.bonus[statIdx] || planet.upgradeState && planet.upgradeState[upgradeIdx]); + +// Filters for each highlight type +const filter2xEnergyCap = filter2xStat(StatIdx.EnergyCap); +const filter2xEnergyGro = filter2xStat(StatIdx.EnergyGro); +const filter2xDefense = filter2xStat(StatIdx.Defense, 0); // defense rank upgrades are on planet.upgradeState[0] +const filter2xSpeed = filter2xStat(StatIdx.Speed, 2); // speed rank upgrades are on planet.upgradeState[2] +const filter2xRange = filter2xStat(StatIdx.Range, 1); // range rank upgrades are on planet.upgradeState[1] +const filterHalfJunk = filter2xStat(StatIdx.HalfJunk); +const filterRip = (plugin, planet) => mainChecks(plugin, planet) && planet.planetType === PlanetType.TRADING_POST; +const filterInvadeNoCapture = (plugin, planet) => mainChecks(plugin, planet) && planetWasAlreadyInvaded(planet) && !planetWasAlreadyCaptured(planet); +const filterSpaceship = (plugin, planet) => mainChecks(plugin, planet) && planetHasRelevantSpaceship(plugin, planet); +const filterTarget = (plugin, planet) => mainChecks(plugin, planet) && planet.isTargetPlanet; +const filterSpawn = (plugin, planet) => mainChecks(plugin, planet) && planet.isSpawnPlanet; +const filterArtifact = (plugin, planet) => { + // Filter out planets of wrong size + if (!mainChecks(plugin, planet)) return false; + + // Include any planet with an artifact circling (and is big enough) + if (planet.heldArtifactIds.length > 0) return true; + + // Otherwise, only keep planet if it's a foundry (RUINS) that hasn't been mined yet, and hasn't expired + return planet.planetType === PlanetType.RUINS + && !(planet.hasTriedFindingArtifact || planet.unconfirmedFindArtifact) + && !prospectExpired(plugin, planet); +}; + +const divCreator = ({width, margin, padding, devCol="#550000"}) => { + const div = document.createElement("div"); + div.style.display = "flex"; + div.style.flexWrap = "wrap"; + if (width) div.style.width = width; + if (margin) div.style.margin = margin; + if (padding) div.style.padding = padding; + if (DEV_MODE) div.style.backgroundColor = devCol; + return div; +} + +const hrCreator = () => { + const hr = document.createElement("hr"); + hr.style.margin = "7px 0px"; + hr.style.borderColor = "rgb(80, 80, 80)"; + return hr; +}; + +const labelCreator = ({text, color, padding, smallText=false, devCol="#111155"}) => { + const label = document.createElement("label"); + label.style.display = "flex"; + label.innerText = text; + if (color) label.style.color = color; + if (padding) label.style.padding = padding; + if (smallText) label.style.fontSize = SMALL_TEXT_SIZE; + if (DEV_MODE) label.style.backgroundColor = devCol; + return label; +}; + +const selectCreator = ({initialValue, valueLabelArr, onchange}) => { + const select = document.createElement("select"); + let mouseOver = false; + select.style.display = "inline"; + select.style.width = WIDTH_PX_HALF; + select.style.border = "1px solid"; + select.style.borderRadius = "6px"; + select.style.padding = "5px 3px"; + valueLabelArr.forEach(([value, label]) => { + const option = document.createElement("option"); + option.value = `${value}`; + option.innerText = label; + select.appendChild(option); + }); + const updateColours = () => { + const colArrs = buttonDefaultColours.off; + select.style.color = getRgb(colArrs.text, mouseOver); + select.style.borderColor = getRgb(colArrs.bord, mouseOver); + select.style.backgroundColor = getRgb(colArrs.bg, mouseOver); + } + updateColours(); + select.onmouseover = () => { + mouseOver = true; + updateColours(); + }; + select.onmouseleave = () => { + mouseOver = false; + updateColours(); + }; + select.onchange = () => { + onchange(); + select.blur(); + } + select.value = `${initialValue}`; + return select; +}; + +const selectData = [ + { + id: LEVEL_MIN, + label: "Min. level:", + initialValue: DEFAULT_LEVEL_MIN, + list: PLANET_LEVELS, + }, + { + id: LEVEL_MAX, + label: "Max. level:", + initialValue: DEFAULT_LEVEL_MAX, + list: PLANET_LEVELS, + }, + { + id: RANGE_MAX, + label: "Max. range:", + initialValue: DEFAULT_RANGE_MAX, + list: RANGES, + }, + { + id: PLANET_TYPE, + label: "Planet type:", + initialValue: ALL_PLANET_TYPES, + list: PLANET_TYPES, + }, +]; +const initialiseSelectWrappers = plugin => { + selectData.forEach(obj => { + obj.value = obj.initialValue; + const wrapper = divCreator({width: WIDTH_PX_HALF, margin: MARGIN_WRAPPER, devCol: "#006633"}); + const label = labelCreator({text: obj.label, color: "#888888", padding: "0px 0px 0px 8px", smallText: true}); + const select = selectCreator({ + initialValue: obj.initialValue, + valueLabelArr: obj.list, + onchange: plugin.recalcAllHighlights + }); + wrapper.appendChild(label); + wrapper.appendChild(select); + obj.element = {}; + obj.element.wrapper = wrapper; + obj.element.label = label; + obj.element.select = select; + plugin.ui.select[obj.id] = obj; + }); +} + +const buttonCreator = ({text, onclick, initialToggleState=false, bgOverrideOn=false, invertTextOn=false, smallText=false}) => { + const button = document.createElement("button"); + let toggledOn = initialToggleState; + let mouseOver = false; + button.innerText = text; + button.style.display = "inline"; + button.style.width = WIDTH_PX_HALF; + button.style.border = "1px solid"; + button.style.borderRadius = "6px"; + button.style.padding = "3px"; + if (smallText) button.style.fontSize = SMALL_TEXT_SIZE; + const setButtonColours = () => { + const colArrs = toggledOn ? buttonDefaultColours.on : buttonDefaultColours.off; + const bgCols = toggledOn && bgOverrideOn ? bgOverrideOn : colArrs.bg; + button.style.color = getRgb(colArrs.text, mouseOver, invertTextOn && toggledOn); + button.style.borderColor = getRgb(colArrs.bord, mouseOver); + button.style.backgroundColor = getRgb(bgCols, mouseOver); + }; + setButtonColours(); + button.onmouseover = () => { + mouseOver = true; + setButtonColours(); + }; + button.onmouseleave = () => { + mouseOver = false; + setButtonColours(); + }; + button.onclick = () => { + toggledOn = !toggledOn; + setButtonColours(); + onclick(); + button.blur(); + }; + return button; +}; + +const drawHighlights = (plugin, planetArr, colRgbArr, periodMs) => { + const ctx = plugin.ctx; + const timeMs = plugin.dateNow; + const drawOptions = plugin.drawOptions; + if (isToggledOn(planetArr)) { + for (let planet of planetArr) { + if (!planet.location) continue; + const { x, y } = planet.location.coords; + // Function to calculate pulse shape, to vary parameter by a triangle wave between 0 and 1 + const getSawWave01 = (item, defaultValue=0.5, slowFactor=1) => { + if (item === ALWAYS_PULSE || drawOptions[item].value) { + const thisTimeMs = drawOptions.sync.value ? (timeMs / slowFactor) : (timeMs / slowFactor) + DESYNC_X * x + DESYNC_Y * y; // Large number of seconds from 1970 (approx) + const thisPeriodMs = drawOptions.pulseFast.value ? periodMs / PULSE_FAST_FACTOR : periodMs; // Cycle Period, in ms + return (thisTimeMs % thisPeriodMs) / thisPeriodMs; // Sawtooth Wave, position in cycle, between 0 and 1 + } else { + return defaultValue; + } + } + const getTriWave01 = (item, defaultValue=0.5) => { + const sawWave01 = getSawWave01(item, defaultValue); + return 2 * Math.min(sawWave01, 1 - sawWave01); // Triangle Wave, between 0 and 1 + } + const colAlpha = getTriWave01("pulseOpacity", DEFAULT_ALPHA); + let radius = ui.getRadiusOfPlanetLevel(planet.planetLevel); + const extraRadiusFactor = 1 + EXTRA_RADIUS_WORLD_PX_PULSE_MULTIPLY * getTriWave01("pulseRadius"); + if (!drawOptions.line.value) { + ctx.fillStyle = `rgba(${"" + colRgbArr[0]}, ${"" + colRgbArr[1]}, ${"" + colRgbArr[2]}, ${"" + colAlpha})`; + } else { + ctx.strokeStyle = `rgba(${"" + colRgbArr[0]}, ${"" + colRgbArr[1]}, ${"" + colRgbArr[2]}, ${"" + colAlpha})`; + radius *= EXTRA_RADIUS_WORLD_PX_LINE_MULTIPLY; + ctx.lineWidth = (BASE_LINE_WIDTH_PX + LINE_WIDTH_PLANET_LEVEL_FACTOR * planet.planetLevel) * (0.5 + getTriWave01("pulseLineWidth")); + if (drawOptions.lineDashed.value) { + ctx.setLineDash([5, 3]); + } else { + ctx.setLineDash([]); + } + } + ctx.beginPath(); + const cX = viewport.worldToCanvasX(x); + const cY = viewport.worldToCanvasY(y); + const cR = extraRadiusFactor * (viewport.worldToCanvasDist(radius) + EXTRA_RADIUS_CANVAS_PX_ADD); + const rotationRad = CIRC_END_RAD * getSawWave01(ALWAYS_PULSE, 0, PULSES_PER_ROTATION); + if (drawOptions.ellipse.value && ctx.ellipse) { + const cR1 = cR / ELLIPSE_FACTOR; + const cR2 = cR * ELLIPSE_FACTOR; + ctx.ellipse(cX, cY, cR1, cR2, rotationRad, CIRC_START_RAD, CIRC_END_RAD); + } else { + ctx.arc(cX, cY, cR, CIRC_START_RAD + rotationRad, CIRC_END_RAD + rotationRad); + } + if (drawOptions.line.value) { + ctx.stroke(); + } else { + ctx.fill(); + } + ctx.closePath(); + } + } +} + +class Plugin { + constructor() { + this.ctx = null; + this.dateNow = Date.now(); + this.ui = {}; + this.ui.select = {}; + initialiseSelectWrappers(this); + this.accounts = []; + this.spaceships = []; + loadAccounts(this); + loadSpaceships(this); + this.drawOptions = { + ellipse: {value: DEFAULT_ELLIPSE, label: "Ellipse"}, + pulseOpacity: {value: DEFAULT_PULSE_OPACITY, label: "Pulse Opacity"}, + line: {value: DEFAULT_LINE, label: "Line"}, + pulseRadius: {value: DEFAULT_PULSE_RADIUS, label: "Pulse Radius"}, + lineDashed: {value: DEFAULT_LINE_DASHED, label: "Line Dashed"}, + pulseLineWidth: {value: DEFAULT_PULSE_LINE_WIDTH, label: "Pulse Line Width"}, + sync: {value: DEFAULT_SYNC_PULSES, label: "Sync Pulses"}, + pulseFast: {value: DEFAULT_PULSE_FAST, label: "Pulse Fast"}, + } + this.drawOptionList = Object.keys(this.drawOptions); + this.highlightData = { + planetsWithArtifact: {label: "Artifacts", filter: filterArtifact, array: [TOGGLE_OFF], periodMs: periodMsHighlightArtifact, cols: colsHighlightArtifact}, + planetsWithRip: {label: "Spacetime Rips", filter: filterRip, array: [TOGGLE_OFF], periodMs: periodMsHighlightRip, cols: colsHighlightRip}, + planetsWith2xDefense: {label: "Defense", filter: filter2xDefense, array: [TOGGLE_OFF], periodMs: periodMsHighlight2xDefense, cols: colsHighlight2xDefense}, + planetsWith2xEnergyCap: {label: "Energy Cap", filter: filter2xEnergyCap, array: [TOGGLE_OFF], periodMs: periodMsHighlight2xEnergyCap, cols: colsHighlight2xEnergyCap}, + planetsWith2xSpeed: {label: "Speed", filter: filter2xSpeed, array: [TOGGLE_OFF], periodMs: periodMsHighlight2xSpeed, cols: colsHighlight2xSpeed}, + planetsWith2xEnergyGro: {label: "Energy Gro", filter: filter2xEnergyGro, array: [TOGGLE_OFF], periodMs: periodMsHighlight2xEnergyGro, cols: colsHighlight2xEnergyGro}, + planetsWith2xRange: {label: "Range", filter: filter2xRange, array: [TOGGLE_OFF], periodMs: periodMsHighlight2xRange, cols: colsHighlight2xRange}, + }; + if (ENABLE_ROUND_5_OPTIONS) { + this.highlightData['planetsWithHalfJunk'] = {label: "Half Junk", filter: filterHalfJunk, array: [TOGGLE_OFF], periodMs: periodMsHighlightHalfJunk, cols: colsHighlightHalfJunk}; + this.highlightData['planetsWithInvadeNoCapture'] = { label: "Need Capture", filter: filterInvadeNoCapture, array: [TOGGLE_OFF], periodMs: periodMsHighlightInvadeNoCapture, cols: colsHighlightInvadeNoCapture }; + this.highlightData['planetsWithSpaceship'] = { label: "Spaceship", filter: filterSpaceship, array: [TOGGLE_OFF], periodMs: periodMsHighlightSpaceship, cols: colsHighlightSpaceship }; + }; + if (ENABLE_TARGET_AND_SPAWN) { + this.highlightData['planetsWithTarget'] = {label: "Target", filter: filterTarget, array: [TOGGLE_OFF], periodMs: periodMsHighlightTarget, cols: colsHighlightTarget}; + this.highlightData['planetsWithSpawn'] = {label: "Spawn", filter: filterSpawn, array: [TOGGLE_OFF], periodMs: periodMsHighlightSpawn, cols: colsHighlightSpawn}; + }; + this.highlightList = Object.keys(this.highlightData); + console.log(`Initialised ${PLUGIN_NAME} plugin:`); + console.dir(this); + + this.refreshHighlightsTimer = setInterval(() => { + setTimeout(this.recalcAllHighlights, 0); + }, REFRESH_INTERVAL_MS); + } + + // Toggle individual draw options on or off + toggleDrawOption = key => { + this.drawOptions[key].value = !this.drawOptions[key].value; + }; + + getSelectValue = id => { + return this.ui.select[id].value; + } + + updateSelectValues = () => { + selectData.forEach(obj => { + const uiEntry = this.ui.select[obj.id]; + uiEntry.value = parseInt(uiEntry.element.select.value, 10); + }) + }; + + logHighlight = (label, count) => { + console.log(`${PLUGIN_NAME} plugin: highlighted ${count} of ${label}`); + } + + // Recalculate all highlights, keep each state + recalcAllHighlights = () => { + this.updateSelectValues(); + this.highlightList.forEach(key => { + const obj = this.highlightData[key]; + const arr = obj.array; + const filterFn = obj.filter; + if (isToggledOn(arr)) { + // Recalc On + arr.length = 0; + for (let planet of df.getAllPlanets()) { + if (filterFn(this, planet)) arr.push(planet); + } + this.logHighlight(obj.label, arr.length); + } else { + // Recalc Off + arr.length = 0; + arr[0] = TOGGLE_OFF; + } + }) + }; + + // Recalculate specific highlight, toggle its state + toggleHighlight = key => { + this.updateSelectValues(); + const obj = this.highlightData[key]; + const arr = obj.array; + const filterFn = obj.filter; + if (isToggledOn(arr)) { + // Toggle to Off + arr.length = 0; // Keep array object, but make it empty + arr[0] = TOGGLE_OFF; + } else { + // Toggle to On + arr.length = 0; + for (let planet of df.getAllPlanets()) { + if (filterFn(this, planet)) arr.push(planet); + } + this.logHighlight(obj.label, arr.length); + } + }; + + render(container) { + container.parentElement.style.minHeight = "unset"; + container.style.minHeight = "unset"; + container.style.width = WIDTH_PX_CONTAINER; + if (DEV_MODE) container.style.backgroundColor = "#663300"; + + container.appendChild(labelCreator({text: "Highlights:", padding: PADDING_SECTION_LABEL})); + const highlightDiv = divCreator({}); + this.highlightList.forEach(key => { + const obj = this.highlightData[key]; + const wrapper = divCreator({width: WIDTH_PX_HALF, margin: MARGIN_WRAPPER, devCol: "#006633"}); + wrapper.appendChild(buttonCreator({ + text: obj.label, + onclick: () => this.toggleHighlight(key), + initialToggleState: isToggledOn(obj.array), + bgOverrideOn: obj.cols, + invertTextOn: true + })); + highlightDiv.appendChild(wrapper); + }) + container.appendChild(highlightDiv); + + container.appendChild(hrCreator()); + + container.appendChild(labelCreator({text: "Filters:", padding: PADDING_SECTION_LABEL})); + const filterDiv = divCreator({}); + filterDiv.appendChild(this.ui.select[LEVEL_MIN].element.wrapper); + filterDiv.appendChild(this.ui.select[LEVEL_MAX].element.wrapper); + filterDiv.appendChild(this.ui.select[RANGE_MAX].element.wrapper); + filterDiv.appendChild(this.ui.select[PLANET_TYPE].element.wrapper); + container.appendChild(filterDiv); + + container.appendChild(hrCreator()); + + container.appendChild(labelCreator({text: "Display options:", padding: PADDING_SECTION_LABEL})); + const displayOptsDiv = divCreator({}); + this.drawOptionList.forEach(key => { + const obj = this.drawOptions[key]; + const wrapper = divCreator({width: WIDTH_PX_HALF, margin: MARGIN_WRAPPER, devCol: "#006633"}); + wrapper.appendChild(buttonCreator({ + text: obj.label, + onclick: () => this.toggleDrawOption(key), + initialToggleState: obj.value, + smallText: true + })); + displayOptsDiv.appendChild(wrapper); + }) + container.appendChild(displayOptsDiv); + } + + draw(ctx) { + ctx.save(); + this.ctx = ctx; + this.dateNow = Date.now(); + this.highlightList.forEach(key => { + const obj = this.highlightData[key]; + drawHighlights(this, obj.array, obj.cols, obj.periodMs); + }) + ctx.restore(); + } + + clearRefreshHighlights() { + if (this.refreshHighlightsTimer) { + clearInterval(this.refreshHighlightsTimer) + } + } + + destroy() { + this.clearRefreshHighlights(); + } +} + +export default Plugin; \ No newline at end of file diff --git a/client/embedded_plugins/Locate-Artifacts.ts b/client/embedded_plugins/Locate-Artifacts.ts deleted file mode 100644 index 0289cff6..00000000 --- a/client/embedded_plugins/Locate-Artifacts.ts +++ /dev/null @@ -1,80 +0,0 @@ -/** - * Remember, you have access these globals: - * 1. df - Just like the df object in your console. - * 2. ui - For interacting with the game's user interface. - * - * Let's log these to the console when you run your plugin! - */ -console.log(df, ui); - -class ArtifactsFinder implements DFPlugin { - private planetList: HTMLDivElement; - - renderPlanets = () => { - this.planetList.innerHTML = ''; - - // keep track of how many we have found - let count = 0; - - const countText = document.createElement('div'); - this.planetList.appendChild(countText); - - for (const planet of df.getAllPlanets()) { - // @ts-ignore - if (planet.location) { - if (df.isPlanetMineable(planet)) { - // is there any other filtering you'd want to do? - // sometimes planets have artifacts deposited on them! - // somtimes a planet's artifact has already been mined. - // see if you can modify this plugin to make it do what - // you want! - const planetEntry = document.createElement('div'); - this.planetList.appendChild(planetEntry); - - // hint: have a hard time finding planets? - // ui.centerCoords might help... - planetEntry.innerText = - '(' + - // @ts-ignore - planet.location.coords.x + - ', ' + - // @ts-ignore - planet.location.coords.y + - ')'; - - count++; - } - } - } - - if (count === 0) { - countText.innerText = 'you have not found any artifacts yet'; - } else { - countText.innerText = 'you have found ' + count + ' artifacts'; - } - }; - - async render(container: HTMLDivElement) { - console.log('rendered 1 artifacts finder'); - const findArtifactsButton = document.createElement('df-button'); - findArtifactsButton.innerText = 'find me some artifacts!'; - container.appendChild(findArtifactsButton); - container.appendChild(document.createElement('br')); - container.appendChild(document.createElement('br')); - findArtifactsButton.addEventListener('click', this.renderPlanets); - this.planetList = document.createElement('div'); - container.appendChild(this.planetList); - - this.planetList.style.maxHeight = '300px'; - this.planetList.style.width = '400px'; - this.planetList.style.overflowX = 'hidden'; - this.planetList.style.overflowY = 'scroll'; - - console.log('rendered artifacts finder'); - } -} - -/** - * And don't forget to export it! - */ -export default ArtifactsFinder; diff --git a/client/embedded_plugins/Map-Export-Filter.js b/client/embedded_plugins/Map-Export-Filter.js new file mode 100644 index 00000000..2dc06876 --- /dev/null +++ b/client/embedded_plugins/Map-Export-Filter.js @@ -0,0 +1,597 @@ +// +// author: https://twitter.com/DfArchon +// +// Map Filter Export +// +// Export filtered planets with or without background. +// +// the speed of export and import is faster :-) +// +// notice 1: If the number of planets is too large, the website may crash, +// so we recommend choose a reasonable planetLevel range, such as [3,9]. +// We don't recommend to choose the planetLevel 0, +// because the planets's amount maybe very large. +// +// notice 2: If you choose to [Download Map With Background], +// plugin will export the map which has a lot of 16x16 pixel blocks, +// the import speed is fast, but you may need to wait the planets to show up for a while. +// Click the button [Show Planets] and Use the middle mouse button to zoom in +// and out may help to make the planets show up more quickly. +// +// notice 3: Your planets can still be attacked by other's small planets which you can't see. +// +// When writing this plugin, we learn a lot from the plugin named map export, +// Thanks to the authors of map export https://github.com/darkforest-eth/plugins/blob/master/content/utilities/map-export/plugin.js! + + +import { PlanetLevel, PlanetType, SpaceType } from + "https://cdn.skypack.dev/@darkforest_eth/types"; + +import { html, render, useState } from + "https://unpkg.com/htm/preact/standalone.module.js"; + +import { getPlayerColor } from + "https://cdn.skypack.dev/@darkforest_eth/procedural"; + +let showPlanets = []; + +export const isPlanet = planet => planet.planetType === PlanetType.PLANET; +export const isAsteroidField = planet => planet.planetType === PlanetType.SILVER_MINE; +export const isFoundry = planet => planet.planetType === PlanetType.RUINS; +export const isSpacetimeRip = planet => planet.planetType === PlanetType.TRADING_POST; +export const isQuasar = planet => planet.planetType === PlanetType.SILVER_BANK; + +export const inBlackSpace = planet => planet.spaceType === SpaceType.DEEP_SPACE; +export const inGreenSpace = planet => planet.spaceType === SpaceType.DEAD_SPACE; +export const inBlueSpace = planet => planet.spaceType === SpaceType.NEBULA; +export const inDarkblueSpace = planet => planet.spaceType === SpaceType.SPACE; +export const destroyedFilter = plt => { + return plt.location !== undefined && plt.destroyed === false; +} + +export const sleep = ms => new Promise(resolve => setTimeout(resolve, ms)); + +function drawRound(ctx, p, color, width = 1) { + if (!p) return '(???,???)'; + const viewport = ui.getViewport(); + ctx.strokeStyle = color; + ctx.lineWidth = width; + const { + x, + y + } = viewport.worldToCanvasCoords(p.location.coords); + const range = p.range * 0.01 * 20; + const trueRange = viewport.worldToCanvasDist(range); + ctx.beginPath(); + // ctx.setLineDash([10,10]); + ctx.arc(x, y, trueRange, 0, 2 * Math.PI); + ctx.stroke(); + return `(${p.location.coords.x},${p.location.coords.y})`; +} + +function zeroFill(i) { + if (i >= 0 && i <= 9) return "0" + i; + else return i; +} + +function getCurrentTime() { + var date = new Date(); + var month = zeroFill(date.getMonth() + 1); + var day = zeroFill(date.getDate()); + var hour = zeroFill(date.getHours()); + var minute = zeroFill(date.getMinutes()); + var second = zeroFill(date.getSeconds()); + + var curTime = date.getFullYear() + "-" + month + "-" + day + + "_" + hour + "-" + minute + "-" + second; + + return curTime; +} + +const PLANET_LEVELS = Object.values(PlanetLevel).map((level) => ({ + value: level, + text: level.toString(), +})); + + +function mapFilterExport() { + + const [leftLevel, setLeftLevel] = useState(3); + const [rightLevel, setRightLevel] = useState(9); + + const [hasPlanet, setHasPlanet] = useState(true); + const [hasAsteroidField, setHasAsteroidField] = useState(true); + const [hasFoundry, setHasFoundry] = useState(true); + const [hasSpacetimeRip, setHasSpacetimeRip] = useState(true); + const [hasQuasar, setHasQuasar] = useState(false); + + const [ohBlackSpace, setOhBlackSpace] = useState(true); + const [ohGreenSpace, setOhGreenSpace] = useState(true); + const [ohBlueSpace, setOhBlueSpace] = useState(true); + const [ohDarkblueSpace, setOhDarkblueSpace] = useState(true); + const [onlyMe, setOnlyMe] = useState(false); + + const [info, setInfo] = useState(''); + const [info2, setInfo2] = useState(''); + + + //functions + function judgeLevel(plt) { + let minLevel = Math.min(leftLevel, rightLevel); + let maxLevel = Math.max(leftLevel, rightLevel); + return minLevel <= plt.planetLevel && plt.planetLevel <= maxLevel; + } + + function judgePlanetType(plt) { + if (hasPlanet && isPlanet(plt)) return true; + if (hasAsteroidField && isAsteroidField(plt)) return true; + if (hasFoundry && isFoundry(plt)) return true; + if (hasSpacetimeRip && isSpacetimeRip(plt)) return true; + if (hasQuasar && isQuasar(plt)) return true; + return false; + } + + function judgeOwner(plt) { + if (onlyMe === false) return true; + if (plt.owner === df.account) return true; + return false; + + } + + function judgeSpaceType(plt) { + if (ohBlackSpace && inBlackSpace(plt)) return true; + if (ohGreenSpace && inGreenSpace(plt)) return true; + if (ohBlueSpace && inBlueSpace(plt)) return true; + if (ohDarkblueSpace && inDarkblueSpace(plt)) return true; + return false; + } + + function generateMapWithoutBackground() { + let chunks = ui.getExploredChunks(); + let chunksAsArray = Array.from(chunks); + + let res = []; + + let planetsCount = 0; + let mapPixelsCnt = 0; + + + for (let i = 0; i < chunksAsArray.length; i++) { + const chunk = chunksAsArray[i]; + + let chunkFootprint = chunk.chunkFootprint; + let bottomLeft = chunkFootprint.bottomLeft; + let sideLength = chunkFootprint.sideLength; + let chunkPerlin = chunkFootprint.perlin; + + let planetLocations = chunk.planetLocations; + + let smallLength = 16; + let number = sideLength / smallLength; + + if (sideLength < smallLength) continue; + + mapPixelsCnt += number * number; + + let planetLocationsWithMark = []; + + planetLocations.forEach(item => { + const coords = item.coords; + let plt = df.getPlanetWithCoords(coords); + + let flag = true; + + if (judgeLevel(plt) === false) flag = false; + if (judgePlanetType(plt) === false) flag = false; + if (judgeSpaceType(plt) === false) flag = false; + if (judgeOwner(plt) === false) flag = false; + if (destroyedFilter(plt) === false) flag = false; + + if (flag) { + let tx = coords.x - bottomLeft.x; + let ty = coords.y - bottomLeft.y; + tx = Math.floor(tx / smallLength); + ty = Math.floor(ty / smallLength); + + let value = tx * number + ty; + let newItem = item; + newItem.mark = value; + planetLocationsWithMark.push(newItem); + planetsCount++; + } + }); + + planetLocationsWithMark = planetLocationsWithMark.sort((a, b) => a.mark - b.mark); + + let stack = []; + + for (let i = 0; i < planetLocationsWithMark.length; i++) { + let item = planetLocationsWithMark[i]; + let mark = item.mark; + let rhs = {}; + rhs.biomebase = item.biomebase; + rhs.coords = item.coords; + rhs.hash = item.hash; + rhs.perlin = item.perlin; + + stack.push(rhs); + + if ((i === planetLocationsWithMark.length - 1) || + (i + 1 < planetLocationsWithMark.length && + planetLocationsWithMark[i].mark != planetLocationsWithMark[i + 1].mark) + ) { + + let newChunk = {}; + newChunk.chunkFootprint = {}; + + let tx = Math.floor(mark / number) * smallLength; + let ty = (mark - number * Math.floor(mark / number)) * smallLength; + tx += bottomLeft.x; + ty += bottomLeft.y; + let coords = { x: tx, y: ty }; + newChunk.chunkFootprint.bottomLeft = coords; + newChunk.chunkFootprint.sideLength = smallLength; + newChunk.perlin = chunkPerlin; + let notCnt = 0; + for (let j = 0; j < stack.length; j++) { + let pltCoords = stack[j].coords; + if (pltCoords.x >= tx && pltCoords.x < tx + smallLength && pltCoords.y >= ty && pltCoords.y < ty + smallLength); + else notCnt++; + } + + //notice: normally notCnt===0 + if (notCnt !== 0) console.error('notCnt:' + notCnt); + + newChunk.planetLocations = stack; + if (stack.length !== 0) { + res.push(newChunk); + stack = []; + } + } + } + } + + let newInfo = html`
+
export ${planetsCount} planets
+
${mapPixelsCnt} 16x16 pixel blocks before
+
${res.length} 16x16 pixel blocks now
+
`; + setInfo(newInfo); + return res; + } + + let onDownloadWithoutBackground = async () => { + let newInfo = html`
Begin To Download Map Without Background
`; + setInfo(newInfo); + let newInfo2 = html`
You may need to wait for a while...
`; + setInfo2(newInfo2); + // notice : sleep is to refresh page + await sleep(100); + + let mapRaw = generateMapWithoutBackground(); + try { + let map = JSON.stringify(mapRaw); + var blob = new Blob([map], { type: 'application/json' }), + anchor = document.createElement('a'); + let currentTime = getCurrentTime(); + anchor.download = df.getContractAddress().substring(0, 6) + '_' + currentTime + '_map.json'; + anchor.href = (window.webkitURL || window.URL).createObjectURL(blob); + anchor.dataset.downloadurl = ['application/json', anchor.download, anchor.href].join(':'); + anchor.click(); + let newInfo = html`
Download Map Successfully :-)
`; + setInfo2(newInfo); + + } catch (err) { + console.error(err); + let newInfo = html`
Download Map Error :-|
`; + setInfo(newInfo); + } + } + + function generateMapWithBackground() { + let chunks = ui.getExploredChunks(); + let chunksAsArray = Array.from(chunks); + + let planetsCount = 0; + + + + let res = []; + + for (let i = 0; i < chunksAsArray.length; i++) { + const chunk = chunksAsArray[i]; + const planetLocations = chunk.planetLocations; + let planetLocationsWithMark = []; + let newChunk = {}; + newChunk.chunkFootprint = {}; + newChunk.chunkFootprint.bottomLeft = chunk.chunkFootprint.bottomLeft; + newChunk.chunkFootprint.sideLength = chunk.chunkFootprint.sideLength; + newChunk.perlin = chunk.perlin; + + + planetLocations.forEach(item=>{ + const coords = item.coords; + let plt = df.getPlanetWithCoords(coords); + let flag = true; + if(judgeLevel(plt)===false) flag = false; + if(judgePlanetType(plt)===false) flag = false; + if(judgeSpaceType(plt)===false) flag = false; + if(judgeOwner(plt)===false) flag = false; + if(destroyedFilter(plt)===false) flag = false; + if(flag){ + planetLocationsWithMark.push(item); + + } + }); + + newChunk.planetLocations = planetLocationsWithMark; + res.push(newChunk); + planetsCount+=planetLocationsWithMark.length; + } + + let newInfo = html`
+
export ${planetsCount} planets
+
`; + setInfo(newInfo); + return res; + } + + let onDownloadWithBackground = async () => { + let newInfo = html`
Begin To Download Map With Background
`; + setInfo(newInfo); + let newInfo2 = html`
You may need to wait for a while...
`; + setInfo2(newInfo2); + // notice : sleep is to refresh page + await sleep(100); + + let mapRaw = generateMapWithBackground(); + try { + let map = JSON.stringify(mapRaw); + var blob = new Blob([map], { type: 'application/json' }), + anchor = document.createElement('a'); + let currentTime = getCurrentTime(); + anchor.download = df.getContractAddress().substring(0, 6) + '_' + currentTime + '_map.json'; + anchor.href = (window.webkitURL || window.URL).createObjectURL(blob); + anchor.dataset.downloadurl = ['application/json', anchor.download, anchor.href].join(':'); + anchor.click(); + let newInfo = html`
Download Map Successfully :-)
`; + setInfo2(newInfo); + + } catch (err) { + console.error(err); + let newInfo = html`
Download Map Error :-|
`; + setInfo(newInfo); + } + } + + + + + async function processMap(input) { + let chunks; + try { + chunks = JSON.parse(input); + + } catch (err) { + console.error(err); + let newInfo = html`
Invalid map data. Check the data in your file.
`; + setInfo(newInfo); + return; + } + + let newInfo = html`
Importing, this will take a while...
`; + setInfo(newInfo); + try { + await df.bulkAddNewChunks(chunks) + let newInfo = html`
Successfully imported map :-)
`; + setInfo(newInfo); + } catch (err) { + console.error(err); + let newInfo = html`
Encountered an unexpected error :-(
`; + setInfo(newInfo); + } + } + + let onUpload = async () => { + let newInfo = html`
Begin To Upload
`; + setInfo(newInfo); + let newInfo2 = html`
You may need to wait For a while...
`; + setInfo2(newInfo2); + + let inputFile = document.createElement('input'); + inputFile.type = 'file'; + inputFile.onchange = () => { + try { + var file = inputFile.files.item(0); + var reader = new FileReader(); + reader.onload = () => { + processMap(reader.result); + }; + reader.readAsText(file); + + newInfo2 = html`
NOTICE: Filter Functions Only Used In Download!
`; + setInfo2(newInfo2); + + } catch (err) { + console.error(err); + let newInfo = html`
Unable to upload map :-(
`; + setInfo(newInfo); + setInfo2(''); + return; + } + } + inputFile.click(); + } + + let updatePlanets = () => { + showPlanets = Array.from(df.getAllPlanets()) + .filter(destroyedFilter) + .filter(judgeLevel) + .filter(judgeOwner) + .filter(judgeSpaceType); + } + + let clearPlanets = () => { + showPlanets = []; + } + + // css style + let divStyle = { + textAlign: 'center', + justifyContent: "space-around", + width: "100%", + marginTop: "10px", + }; + + let buttonStyle = { height: "25px", width: "130px" }; + + let longButtonStyle = { height: "25px", width: "300px" }; + let selectStyle = { + background: "rgb(8,8,8)", + width: "100px", + padding: "3px 5px", + border: "1px solid white", + borderRadius: "3px", + }; + + let planetLevelStyle = { + marginTop: "5px", + marginBottom: "5px" + }; + + // Component + const leftLevelSelect = html` + + `; + const rightLevelSelect = html` + + `; + + let levelComponent = html`
+ ${leftLevelSelect} + ${' '} + ${rightLevelSelect} +
`; + + let thePlanetComponent = html`
+ setHasPlanet(!hasPlanet)}/> + ${' Planet'}
`; + + let theAsteroidFiledComponent = html`
+ setHasAsteroidField(!hasAsteroidField)}/> + ${' AsteroidField'}
`; + + let theFoundryComponent = html`
+ setHasFoundry(!hasFoundry)}/> + ${' Foundry'}
`; + + let theSpacetimeRipComponent = html`
+ setHasSpacetimeRip(!hasSpacetimeRip)}/> + ${' SpacetimeRip'}
`; + + let theQuasarComponent = html`
+ setHasQuasar(!hasQuasar)}/> + ${' Quasar'}
`; + + let planetTypeComponent = html` +
+ ${thePlanetComponent} + ${theAsteroidFiledComponent} + ${theFoundryComponent} + ${theSpacetimeRipComponent} + ${theQuasarComponent} +
+ `; + + let theBlackSpaceComponent = html`
+ setOhBlackSpace(!ohBlackSpace)}/> + ${' Black'}
`; + + let theGreenSpaceComponent = html`
+ setOhGreenSpace(!ohGreenSpace)}/> + ${' Green'}
`; + + let theBlueSpaceComponent = html`
+ setOhBlueSpace(!ohBlackSpace)}/> + ${' Blue'}
`; + let theDarkblueSpaceComponent = html`
+ setOhDarkblueSpace(!ohDarkblueSpace)}/> + ${' Darkblue'}
`; + + let spaceTypeComponent = html` +
+ + ${theBlackSpaceComponent} + ${theGreenSpaceComponent} + ${theBlueSpaceComponent} + ${theDarkblueSpaceComponent} +
`; + + let ownerComponent = html` +
+ setOnlyMe(!onlyMe)}/> + + ${' All '} + setOnlyMe(!onlyMe)}/> + ${' Me '} +
`; + + return html`
+ ${levelComponent} +
+ ${planetTypeComponent} + ${ownerComponent} + ${spaceTypeComponent} + +
+
+ +
+
+ +
+
+ +
+
+ + ${' '} + +
+ + + ${info} + ${info2} +
`; +} + +class Plugin { + constructor() { + this.container = null; + } + + draw(ctx) { + showPlanets.forEach(p => { + let color = getPlayerColor(p.owner); + drawRound(ctx, p, color, 2); + }); + } + + async render(container) { + this.container = container; + container.style.width = "320px"; + container.style.height = "380px"; + render(html`<${mapFilterExport} />`, container); + } + + destroy() { + render(null, this.container); + } +} + +export default Plugin; + diff --git a/client/embedded_plugins/Metrics.ts b/client/embedded_plugins/Metrics.ts new file mode 100644 index 00000000..2a4f32a8 --- /dev/null +++ b/client/embedded_plugins/Metrics.ts @@ -0,0 +1,268 @@ +// organize-imports-ignore +import { BLOCK_EXPLORER_URL } from '@darkforest_eth/constants'; +import { DarkForest } from '@darkforest_eth/contracts/typechain'; +import type { + ContractMethodName, + EthAddress, + LocatablePlanet, + LocationId, + Planet, + Transaction, + TxIntent, +} from '@darkforest_eth/types'; +import { ContractTransaction, logger } from 'ethers'; +import { + MAX_ARTIFACT_RARITY, + MAX_SPACESHIP_TYPE, + MIN_ARTIFACT_RARITY, + MIN_ARTIFACT_TYPE, + MIN_SPACESHIP_TYPE, + //@ts-ignore +} from 'https://cdn.skypack.dev/@darkforest_eth/constants'; +//@ts-ignore +import { getPlanetNameHash } from 'https://cdn.skypack.dev/@darkforest_eth/procedural'; +import { + locationIdToDecStr, + artifactIdFromHexStr, + //@ts-ignore +} from 'https://cdn.skypack.dev/@darkforest_eth/serde'; +import { + ArtifactRarityNames, + ArtifactType, + ArtifactTypeNames, + //@ts-ignore +} from 'https://cdn.skypack.dev/@darkforest_eth/types'; +import { + html, + render, + useEffect, + useState, + //@ts-ignore +} from 'https://unpkg.com/htm/preact/standalone.module.js'; + +type Tx = Transaction<{ + args: Promise; + contract: DarkForest; + methodName: ContractMethodName; +}> + +async function dfWaitWithMetrics(tx: Tx): Promise { + try { + // console.log(`tx`, tx); + const submit = await tx.submittedPromise; + // console.log(`submit`, submit); + var startTime = performance.now() + const receipt = await tx.confirmedPromise; + var endTime = performance.now() + // console.log(`${tx.intent.methodName} confirmed ${endTime - startTime} milliseconds`) + //console.log(`confirmed with ${receipt.confirmations} blocks, ${receipt.gasUsed} gas used and ${submit.gasPrice} price (wei)`); + return endTime - startTime; + } catch (error) { + console.log(`ERROR`, error); + return 0; + } +} + +async function waitWithMetrics(tx: ContractTransaction, name?: string): Promise { + try { + var startTime = performance.now() + const receipt = await tx.wait(); + var endTime = performance.now() + // console.log(`${name} confirmed ${endTime - startTime} milliseconds`) + //console.log(`confirmed with ${receipt.confirmations} blocks, ${receipt.gasUsed} gas used and ${tx.gasPrice} price (wei)`); + return endTime - startTime; + } catch (error) { + console.log(`ERROR`) + return 0; + } +} + + +async function pauseGame() { + const tx = await df.submitTransaction({ + args: Promise.resolve([]), + contract: df.getContract(), + methodName: 'pause' as ContractMethodName, + }); + return await dfWaitWithMetrics(tx); +} + +async function unpauseGame() { + const tx = await df.submitTransaction({ + args: Promise.resolve([]), + contract: df.getContract(), + methodName: 'unpause' as ContractMethodName, + }); + return await dfWaitWithMetrics(tx); +} + +async function rawPauseGame() { + const contract = df.getContract(); + const tx = await contract.pause() + return await waitWithMetrics(tx, 'raw pause'); +} + +async function rawUnpauseGame() { + const contract = df.getContract(); + const tx = await contract.unpause() + return await waitWithMetrics(tx, 'raw unpause'); +} + +async function changeRPC(rpcUrl: string) { + df.getEthConnection() + .setRpcUrl(rpcUrl) + .then(() => { + localStorage.setItem('XDAI_RPC_ENDPOINT_v5', rpcUrl); + }) + .catch(() => { + console.log(`error setting RPC`); + }); +} + +async function testPauseDifference() { + await changeRPC('https://kovan.optimism.io'); + setPollingInterval(); + + await logPauseDifference(2) + + await changeRPC('wss://ws-kovan.optimism.io'); + await logPauseDifference(2); +} + +function setPollingInterval(interval = 8000) { + const interval1 = df.getEthConnection().getProvider().pollingInterval; + console.log(`polling interval is ${interval1}`) + + // Return if wss websocket rpc, which has interval of 0. + if(interval1 == 0) return; + + // @ts-expect-error Need to do this because getEthConnection() creates a fresh provider each time + df.ethConnection.provider.pollingInterval = interval; + const res = df.getEthConnection().getProvider().pollingInterval + console.log(`polling interval is now ${res}`) + +} + +function pollingIntervalSanityCheck() { + console.log(`running pollInterval sanity check`); + for(var i = 0; i < 5; i++) { + setTimeout(() => {setPollingInterval()}, 5000 * i + 1); + } +} + +async function logPauseDifference(iterations = 1) { + console.log(`testing Pause difference with: + polling interval ${df.getEthConnection().getProvider().pollingInterval} + rpc: ${df.getEthConnection().getRpcEndpoint()}`); + + let paused = await df.getContract().paused(); + console.log('pre: paused?', paused); + + if(paused) await unpauseGame(); + paused = await df.getContract().paused(); + console.log('post: paused?', paused); + if(paused) throw new Error('must test on unpaused game'); + + var pauseTime = 0; + var unPauseTime = 0; + var rawPauseTime = 0; + var rawUnPauseTime = 0; + + setPollingInterval(); + + for(var i = 0; i < iterations; i++) { + console.log(`getting metrics for round ${i} of normal pause / unpause`); + + pauseTime += await pauseGame(); + unPauseTime += await unpauseGame(); + + console.log(`getting metrics for round ${i} of raw pause / unpause`); + rawPauseTime += await rawPauseGame(); + rawUnPauseTime += await rawUnpauseGame(); + } + + const normalAvg = (pauseTime + unPauseTime) / iterations; + const rawAvg = (rawPauseTime + rawUnPauseTime) / iterations; + + var results: any = {}; + results['normal_avg_ms'] = normalAvg.toFixed(2); + results['raw_avg_ms'] = rawAvg.toFixed(2); + results['polling_interval'] = df.getEthConnection().getProvider().pollingInterval + results['rpc'] = df.getEthConnection().getRpcEndpoint() + console.log('Test results', results); +} + +function Heading({ title }: { title: string }) { + return html`

${title}

`; +} + + +const wrapperStyle = { + display: 'flex', + flexDirection: 'column', + gap: '8px', +}; + +const rowStyle = { + display: 'flex', + gap: '8px', + alignItems: 'center', +}; + +function App() { + const [selectedPlanet, setSelectedPlanet] = useState(null); + const [selectedShip, setSelectedShip] = useState(MIN_SPACESHIP_TYPE); + const [selectedArtifact, setSelectedArtifact] = useState(MIN_ARTIFACT_TYPE); + const [artifactRarity, setArtifactRarity] = useState('1'); + const [whitelistAddress, setWhitelistAddress] = useState(null); + const [account, setAccount] = useState(null); + const [shipAccount, setShipAccount] = useState(null); + const [planetAccount, setPlanetAccount] = useState(null); + const [artifactAccount, setArtifactAccount] = useState(null); + + useEffect(() => { + const account = df.getAccount(); + setAccount(account); + setShipAccount(account); + setPlanetAccount(account); + setArtifactAccount(account); + }, []); + + useEffect(() => { + const subscription = ui.selectedPlanetId$.subscribe((p: LocationId) => { + setSelectedPlanet(ui.getPlanetWithId(p)); + }); + + return () => subscription.unsubscribe(); + }, [setSelectedPlanet]); + + return html` +
+

Logged in as account: ${account}

+ + <${Heading} title="Game state" /> + +
+ Change game state: + pauseGame()}> Pause + unpauseGame()}> Unpause + rawPauseGame()}> Raw Pause + rawUnpauseGame()}> Raw Unpause + logPauseDifference()}> Log Pause Difference + testPauseDifference()}> Test Pause Difference + pollingIntervalSanityCheck()}> Poll Interval Sanity + +
+
+ `; +} + +class Plugin implements DFPlugin { + async render(container: HTMLDivElement) { + container.style.width = '525px'; + + render(html`<${App} />`, container); + } +} + +export default Plugin; \ No newline at end of file diff --git a/client/embedded_plugins/Performance-Optimiser.js b/client/embedded_plugins/Performance-Optimiser.js new file mode 100644 index 00000000..308e2dff --- /dev/null +++ b/client/embedded_plugins/Performance-Optimiser.js @@ -0,0 +1,153 @@ +// Performance Optimizer +// +// Aims to improve performance under heavy load: +// * Reduce render load by limiting percentage of total compute power to spend on rendering. Implemented by overwriting `window.requestAnimationFrame`. Could be more sophisiticated in the future if render managers get exposed. +// * Clear zk-SNARK proofs cache / Set max. limit of zk-SNARK proofs. Default is 20. Every move between the same two planets after the first one is sped up significantly. + +import $ from 'https://cdn.skypack.dev/pin/jquery@v3.5.1-GJsJJ2VEWnBDZuot9fRf/min/jquery.js'; + +class PerformanceOptimizerState { + constructor() { + this.pluginWindow = null; + + this.rendering = "unlimited"; + this.renderingFps = 10; + this.renderingPercentage = 50; + + this.cacheCount = 0; + this.cacheLimit = 20; // SnarkArgsHelper.DEFAULT_SNARK_CACHE_SIZE = 20 + + this.destroyed = false; + + const requestIDMap = {}; + let nextRequestID = 0; + + window._requestAnimationFrame = window.requestAnimationFrame; + const requestAnimationFrame = callback => { + let currentCallback, requestID; + let lastRenderStart = 0; + let lastRenderDuration = 0; + + const execute = () => { + delete requestIDMap[requestID]; + window.requestAnimationFrame = startLoop; + currentCallback(); + window.requestAnimationFrame = requestAnimationFrame; + }; + + const loop = () => { + if (this.destroyed) return currentCallback(); + + if (this.rendering === "fps") { + const now = Date.now(); + if (this.renderingFps > 0 && now - lastRenderStart >= 1000 / this.renderingFps) { + lastRenderStart = now; + return execute(); + } + } else if (this.rendering === "percent") { + const now = Date.now(); + if (this.renderingPercentage > 0 && now - lastRenderStart >= Math.min(lastRenderDuration * 100 / this.renderingPercentage, 1000)) { + lastRenderStart = now; + execute(); + lastRenderDuration = Date.now() - now; + return; + } + } else if (this.rendering !== "stopped") { + return execute(); + } + requestIDMap[requestID] = window._requestAnimationFrame(loop); + } + const startLoop = callback => { + requestID = nextRequestID++; + currentCallback = callback; + requestIDMap[requestID] = window._requestAnimationFrame(loop); + return requestID; + } + return startLoop(callback); + }; + window.requestAnimationFrame = requestAnimationFrame; + + window._cancelAnimationFrame = window.cancelAnimationFrame; + window.cancelAnimationFrame = requestID => { + window._cancelAnimationFrame(requestIDMap[requestID]); + delete requestIDMap[requestID]; + }; + + // SNARK cache limit size adjustment + df.snarkHelper.setSnarkCacheSize(this.cacheLimit) + + } + + destroy() { + this.destroyed = true; + this.pluginWindow = null; + window.cancelAnimationFrame = window._cancelAnimationFrame; + window.requestAnimationFrame = window._requestAnimationFrame; + df.snarkHelper.setSnarkCacheSize(20) + console.log("original functions restored."); + delete df.performanceOptimizerState; + } +} + +if (df.performanceOptimizerState === undefined) df.performanceOptimizerState = new PerformanceOptimizerState(); +const state = df.performanceOptimizerState; + +class PerformanceOptimizer { + constructor() { + state.pluginWindow = this; + } + + clearSnarkCache() { + df.snarkHelper.moveSnarkCache.clear() + } + + async render(div) { + $(div) + .append($('

Limit Rendering

')) + .append($('
') + .append($('')) + .append($(' unlimited')) + ) + .append($('
') + .append($('')) + .append($(' max FPS: ')) + .append($(``)) + .append($(` ${state.renderingFps} FPS`)) + ) + .append($('
') + .append($('')) + .append($(' max percentage: ')) + .append($(``)) + .append($(` ${state.renderingPercentage}%`)) + ) + .append($('
') + .append($('')) + .append($(' stopped')) + ) + .append($('
')) + .append($('

Cache zk-SNARK Proofs

')) + .append($('
') + .append($(' max. SNARK CACHE SIZE: ')) + .append($(``)) + .append($(` ${state.cacheLimit} `)) + ) + .append($('
') + .append($(`Clear`)) + ); + $(`input:radio[name=rendering][value=${state.rendering}]`).prop("checked", true); + $('#cachingBox').prop("checked", state.caching); + $('input:radio[name=rendering]').change(function () { state.rendering = this.value }); + const [fpsSpan, percentageSpan, cacheLimitSizeSpan] = [$("#fpsSpan"), $("#percentageSpan"), $("#cacheLimitSizeSpan")]; + $('#fpsRange').change(function () { state.renderingFps = parseInt(this.value) }).on("input", function () { fpsSpan.text(` ${this.value} FPS`) }); + $('#percentageRange').change(function () { state.renderingPercentage = parseInt(this.value) }).on("input", function () { percentageSpan.text(` ${this.value}%`) }); + + $('#cacheLimitSize').change(function () { state.cacheLimit = parseInt(this.value) }).on("input", function () { cacheLimitSizeSpan.text(` ${this.value}`) }); + $('#cacheClearBtn').click(() => { this.clearSnarkCache(); }) + } + + destroy() { + state.pluginWindow = null; + } +} + +export default PerformanceOptimizer; \ No newline at end of file diff --git a/client/embedded_plugins/Rage-Cage.ts b/client/embedded_plugins/Rage-Cage.ts deleted file mode 100644 index 07632342..00000000 --- a/client/embedded_plugins/Rage-Cage.ts +++ /dev/null @@ -1,89 +0,0 @@ -class RageCage implements DFPlugin { - private img: HTMLImageElement; - private loaded: boolean; - - /** - * As you saw in the README plugin, you can render - * arbitrary HTML UI into a Dark Forest modal. - */ - async render(div: HTMLDivElement) { - // once this plugin is run, let's load a nice image - // from the internet, in order to draw it on top of - // planets - this.img = document.createElement('img'); - this.loaded = false; - div.appendChild(this.img); - - this.img.addEventListener('load', () => { - // we should only use the image once - // it actually loads. - this.loaded = true; - div.innerText = 'welcome to nicolas cage world'; - }); - - this.img.src = - 'https://upload.wikimedia.org/wikipedia/' + 'commons/c/c0/Nicolas_Cage_Deauville_2013.jpg'; - - // hide the image, it doesn't need to show up - // in the modal, we only need this img element - // to load the image. - this.img.style.display = 'none'; - - div.style.width = '100px'; - div.style.height = '100px'; - div.innerText = 'loading, please wait!'; - // check out the helpful functions that appear - // in the Viewport class! - console.log(ui.getViewport()); - } - - /** - * In addition to rendering HTML UI into a div, plugins - * can draw directly onto the game UI. This function is - * optional, but if it exists, it is called in sync with - * the rest of the game, and allows you to draw onto an - * HTML5 canvas that lays on top of the rest of the game. - * - * In the example below, we render an image on top of every - * planet. - * - * ctx is an instance of CanvasRenderingContext2D. - */ - draw(ctx: CanvasRenderingContext2D) { - // don't draw anything until nic cage loads - if (!this.loaded) return; - - // the viewport class provides helpful functions for - // interacting with the currently-visible area of the - // game - const viewport = ui.getViewport(); - const planets = ui.getPlanetsInViewport(); - - for (const p of planets) { - // use the Viewport class to determine the pixel - // coordinates of the planet on the screen - const pixelCenter = viewport.worldToCanvasCoords( - // @ts-ignore - p.location.coords - ); - - // how many pixels is the radius of the planet? - const trueRadius = viewport.worldToCanvasDist(ui.getRadiusOfPlanetLevel(p.planetLevel)); - - // draw nicolas cage on top of the planet - ctx.drawImage( - this.img, - 50, - 50, - 400, - 400, - pixelCenter.x - trueRadius, - pixelCenter.y - trueRadius, - trueRadius * 2, - trueRadius * 2 - ); - } - } -} - -export default RageCage; diff --git a/client/embedded_plugins/Remote-Explorer.ts b/client/embedded_plugins/Remote-Explorer.ts index d5bd5a68..5a27e70a 100644 --- a/client/embedded_plugins/Remote-Explorer.ts +++ b/client/embedded_plugins/Remote-Explorer.ts @@ -1,7 +1,7 @@ // organize-imports-ignore -import type { Chunk, WorldCoords } from '@dfdao/types'; +import type { Chunk, WorldCoords } from '@darkforest_eth/types'; //@ts-ignore -import { locationIdFromDecStr } from 'https://cdn.skypack.dev/@dfdao/serde'; +import { locationIdFromDecStr } from 'https://cdn.skypack.dev/@darkforest_eth/serde'; import { html, render, @@ -287,6 +287,7 @@ function App({ return html`
+

Warning: mimc has been reduced to 5. \nUpdate your explorer!

${miners.map( (miner: ExtendedMinerManager) => html` <${MinerUI} key=${miner.url} miner=${miner} onRemove=${remove} /> @@ -330,6 +331,7 @@ class RemoteExplorerPlugin implements DFPlugin { pattern, df.getWorldRadius(), df.planetRarity, + df.planetLevelThresholds, df.getHashConfig(), false, () => new RemoteWorker(url) diff --git a/client/embedded_plugins/Renderer-Showcase.ts b/client/embedded_plugins/Renderer-Showcase.ts deleted file mode 100644 index 9c8582d7..00000000 --- a/client/embedded_plugins/Renderer-Showcase.ts +++ /dev/null @@ -1,938 +0,0 @@ -/* eslint-disable */ -/** - * Below is a list of class definitions for renderers. - * These are blank renderers as they have no functionality. - * The result of using these renderers is the same as disabling the renderer. - */ -// organize-imports-ignore -import { - engineConsts, - EngineUtils, - GameGLManager, - GenericRenderer, - glsl, -//@ts-ignore -} from 'https://cdn.skypack.dev/@dfdao/renderer'; -import { - AsteroidRendererType, - AttribType, - BackgroundRendererType, - BeltRendererType, - BlackDomainRendererType, - CaptureZoneRendererType, - CanvasCoords, - Chunk, - CircleRendererType, - GameViewport, - LineRendererType, - LocatablePlanet, - LocationId, - MineBodyRendererType, - MineRendererType, - PerlinRendererType, - Planet, - PlanetRendererType, - PlanetRenderInfo, - PlanetRenderManagerType, - QuasarBodyRendererType, - QuasarRayRendererType, - QuasarRendererType, - RectRendererType, - RenderedArtifact, - RendererType, - RGBAVec, - RGBVec, - RingRendererType, - RuinsRendererType, - SpaceRendererType, - SpacetimeRipRendererType, - SpriteRendererType, - TextAlign, - TextAnchor, - TextRendererType, - UIRendererType, - UniformType, - UnminedRendererType, - VoyageRendererType, - WorldCoords, - WormholeRendererType, -//@ts-ignore -} from 'https://cdn.skypack.dev/@dfdao/types'; -//@ts-ignore -import { html, render } from 'https://unpkg.com/htm/preact/standalone.module.js'; - -// Line 78 - 350: Blank Renderer -// Line 350 - 651: Circle Renderer -// Line 626 - End: Plugin - - - - -// Line 78 - 376 -// "Blank" renderer class definitions -// When passing in these renderers into the Dark Forest API, the result would be the same as disabling that type of renderer. - -class PlanetRenderer implements PlanetRendererType { - rendererType = RendererType.Planet; - queuePlanetBody(planet: Planet, centerW: WorldCoords, radiusW: number): void {} - flush(): void {} -} - -class MineRenderer implements MineRendererType { - rendererType = RendererType.Mine; - queueMine(planet: Planet, centerW: WorldCoords, radiusW: number): void {} - flush(): void {} -} - -class SpacetimeRipRenderer implements SpacetimeRipRendererType { - rendererType = RendererType.SpacetimeRip; - queueRip(planet: Planet, centerW: WorldCoords, radiusW: number): void {} - flush(): void {} -} - -class QuasarRenderer implements QuasarRendererType { - rendererType = RendererType.Quasar; - - queueQuasar(planet: Planet, centerW: WorldCoords, radiusW: number): void {} - flush(): void {} -} - -class RuinsRenderer implements RuinsRendererType { - rendererType = RendererType.Ruins; - queueRuins(planet: Planet, centerW: WorldCoords, radiusW: number): void {} - flush(): void {} -} -class AsteroidRenderer implements AsteroidRendererType { - rendererType = RendererType.Asteroid; - queueAsteroid(planet: Planet, centerW: CanvasCoords, radiusW: number, color?: RGBVec): void {} - flush(): void {} -} - -class RingRenderer implements RingRendererType { - rendererType = RendererType.Ring; - queueRingAtIdx( - planet: Planet, - centerW: WorldCoords, - radiusW: number, - color?: RGBVec, - beltIdx?: number, - angle?: number - ): void {} - flush(): void {} -} - -class SpriteRenderer implements SpriteRendererType { - rendererType = RendererType.Sprite; - //drawing artifacts around world - queueArtifactWorld( - artifact: RenderedArtifact, - posW: CanvasCoords, - widthW: number, - alpha?: number, - atFrame?: number | undefined, - color?: RGBVec | undefined, - theta?: number | undefined, - viewport?: GameViewport - ): void {} - //drawing artifacts when traveling with voyagers - queueArtifact( - artifact: RenderedArtifact, - pos: CanvasCoords, - width?: number, - alpha?: number, - atFrame?: number | undefined, - color?: RGBVec | undefined, - theta?: number | undefined - ): void {} - flush(): void {} -} - -class BlackDomainRenderer implements BlackDomainRendererType { - rendererType = RendererType.BlackDomain; - queueBlackDomain(planet: Planet, centerW: WorldCoords, radiusW: number): void {} - flush(): void {} -} - -class TextRenderer implements TextRendererType { - rendererType = RendererType.Text; - queueTextWorld( - text: string, - coords: WorldCoords, - color?: RGBAVec, - offY?: number, // measured in text units - constant screen-coord offset that it useful for drawing nice things - align?: TextAlign, - anchor?: TextAnchor, - zIdx?: number - ): void {} - flush(): void {} -} - -class VoyageRenderer implements VoyageRendererType { - rendererType = RendererType.Voyager; - queueVoyages(): void {} - flush(): void {} -} - -class WormholeRenderer implements WormholeRendererType { - rendererType = RendererType.Wormhole; - queueWormholes(): void {} - flush(): void {} -} - -class MineBodyRenderer implements MineBodyRendererType { - rendererType = RendererType.MineBody; - queueMineScreen(planet: Planet, center: WorldCoords, radius: number, z: number): void {} - flush(): void {} - setUniforms(): void {} -} - -class BeltRenderer implements BeltRendererType { - rendererType = RendererType.Belt; - queueBeltAtIdx( - planet: Planet, - center: WorldCoords | CanvasCoords, - radius?: number, - color?: RGBVec, - beltIdx?: number, - angle?: number, - screen?: boolean - ): void {} - flush(): void {} - setUniforms(): void {} -} - -class BackgroundRenderer implements BackgroundRendererType { - rendererType = RendererType.Background; - queueChunks( - exploredChunks: Iterable, - highPerfMode: boolean, - drawChunkBorders: boolean, - disableFancySpaceEffect: boolean, - innerNebulaColor?: string, - nebulaColor?: string, - spaceColor?: string, - deepSpaceColor?: string, - deadSpaceColor?: string - ): void {} - flush(): void {} -} - -class SpaceRenderer implements SpaceRendererType { - rendererType = RendererType.Space; - queueChunk(chunk: Chunk): void {} - setColorConfiguration( - innerNebulaColor: string, - nebulaColor: string, - spaceColor: string, - deepSpaceColor: string, - deadSpaceColor: string - ): void {} - flush(): void {} -} - -class UnminedRenderer implements UnminedRendererType { - rendererType = RendererType.Unmined; - queueRect( - { x, y }: CanvasCoords, - width: number, - height: number, - color: RGBVec, - zIdx: number - ): void {} - flush(): void {} -} - -class PerlinRenderer implements PerlinRendererType { - rendererType = RendererType.Perlin; - queueChunk(chunk: Chunk): void {} - flush(): void {} -} - -class LineRenderer implements LineRendererType { - rendererType = RendererType.Line; - queueLineWorld( - start: WorldCoords, - end: WorldCoords, - color?: RGBAVec, - width?: number, - zIdx?: number, - dashed?: boolean - ): void {} - flush(): void {} -} - -class RectRenderer implements RectRendererType { - rendererType = RendererType.Rect; - queueRectCenterWorld( - center: WorldCoords, - width: number, - height: number, - color?: RGBVec, - stroke?: number, - zIdx?: number - ): void {} - flush(): void {} -} - -class CircleRenderer implements CircleRendererType { - rendererType = RendererType.Circle; - queueCircleWorld( - center: CanvasCoords, - radius: number, - color?: RGBAVec, - stroke?: number, - angle?: number, // percent of arc to render - dashed?: boolean - ): void {} - queueCircleWorldCenterOnly( - center: WorldCoords, - radius: number, // canvas coords - color?: RGBAVec - ): void {} - flush(): void {} -} - -class UIRenderer implements UIRendererType { - rendererType = RendererType.UI; - queueBorders(): void {} - queueSelectedRangeRing(): void {} - queueSelectedRect(): void {} - queueHoveringRect(): void {} - queueMousePath(): void {} - drawMiner(): void {} - flush(): void {} -} - -class PlanetRenderManager implements PlanetRenderManagerType { - rendererType = RendererType.PlanetManager; - queueRangeRings(planet: LocatablePlanet): void {} - queuePlanets( - cachedPlanets: Map, - now: number, - highPerfMode: boolean, - disableEmojis: boolean, - disableHats: boolean - ): void {} - flush(): void {} -} - -class QuasarBodyRenderer implements QuasarBodyRendererType { - rendererType = RendererType.QuasarBody; - queueQuasarBody( - planet: Planet, - centerW: WorldCoords, - radiusW: number, - z?: number, - angle?: number - ): void {} - flush(): void {} -} - -class QuasarRayRenderer implements QuasarRayRendererType { - rendererType = RendererType.QuasarRay; - queueQuasarRay( - planet: Planet, - centerW: WorldCoords, - radiusW: number, - z?: number, - top?: boolean, - angle?: number - ): void {} - flush(): void {} -} - -class CaptureZoneRenderer implements CaptureZoneRendererType{ - rendererType = RendererType.CaptureZone; - - queueCaptureZones(): void {} - - flush(): void {} -} - -// line 350 - 351 -// Circle Renderer Definitions using WebGl - - - -// Program Definition -// A program is what we use to organizie the attributes and shaders of WebGl Programs - -const u = { - matrix: 'u_matrix', // matrix to convert from world coords to clipspace -}; - -const a = { - position: 'a_position', // as [posx, posy, rectposx, rectposy] - color: 'a_color', - props: 'a_props', // as [stroke, angle, dash] - eps: 'a_eps', - planetInfo: 'a_planetInfo', //as [planetlevel, radius] - PlanetUpgrades: 'a_planetUpgrades', //as [defense:number , range: number, speed: number] - PlanetResources: 'a_planetResources', //as [energy:number , energy cap: number, silver: number, silver cap: number] -}; - -const GENERIC_PLANET_PROGRAM_DEFINITION = { - uniforms: { - matrix: { name: u.matrix, type: UniformType.Mat4 }, - }, - attribs: { - position: { - dim: 4, - type: AttribType.Float, - normalize: false, - name: a.position, - }, - eps: { - dim: 1, - type: AttribType.Float, - normalize: false, - name: a.eps, - }, - color: { - dim: 4, - type: AttribType.UByte, - normalize: true, - name: a.color, - }, - props: { - dim: 2, - type: AttribType.Float, - normalize: false, - name: a.props, - }, - planetInfo: { - dim: 2, - type: AttribType.UByte, - normalize: false, - name: a.planetInfo, - }, - planetUpgrades: { - dim: 3, - type: AttribType.UByte, - normalize: false, - name: a.PlanetUpgrades, - }, - planetResources: { - dim: 4, - type: AttribType.UByte, - normalize: false, - name: a.PlanetResources, - }, - }, - - vertexShader: glsl` - in vec4 a_position; - in vec4 a_color; - in vec2 a_props; - in float a_eps; - in vec2 a_planetInfo; - in vec4 a_planetResources; - - uniform mat4 u_matrix; - - out float v_planetLevel; - out vec4 v_color; - out vec2 v_rectPos; - out float v_angle; - out float v_dash; - out float v_eps; - out float energy; - out float energy_cap; - - void main() { - gl_Position = u_matrix * vec4(a_position.xy, 0.0, 1.0); - - v_rectPos = a_position.zw; - v_color = a_color; - v_angle = a_props.x; - v_dash = a_props.y; - v_eps = a_eps; - v_planetLevel = a_planetInfo[0]; - energy = a_planetResources[0]; - energy_cap = a_planetResources[1]; - } - `, - - fragmentShader: glsl` - #define PI 3.1415926535 - - precision highp float; - out vec4 outColor; - - in vec4 v_color; - in vec2 v_rectPos; - in float v_angle; - in float v_dash; - in float v_eps; - in float v_planetLevel; - in float energy; - in float energy_cap; - - void main() { - vec4 color = v_color; - float dist = length(v_rectPos); - - if (dist > 1.0) discard; // if it's outside the circle - - // anti-aliasing if barely in the circle - float ratio = (1.0 - dist) / v_eps; - if (ratio < 1.) { - color.a *= ratio; - } - - - /* get angle for both angle + dash checks */ - float angle = atan(v_rectPos.y, v_rectPos.x); - - // add 5pi/2 to translate it to [-PI/2, 3PI / 2] - float check = angle + (5.0 * PI / 2.0); - check -= (check > 2.0 * PI ? 2.0 * PI : 0.0); - float pct = check / (2.0 * PI); - - /* do angle check */ - - if (v_angle != 1.0 && pct > v_angle) discard; - - /* do dash check */ - bool isDash = v_dash > 0.0; - float interval = angle / v_dash; - float modulo = interval - 2.0 * floor(interval / 2.0); - bool isGap = modulo > 1.0; - if (isDash && isGap) discard; - - /* now draw it */ - outColor = vec4(1,1.0/energy_cap*energy,0,1); - } - `, -}; -class CirclePlanetRenderer extends GenericRenderer< - typeof GENERIC_PLANET_PROGRAM_DEFINITION, - GameGLManager -> { - quadBuffer: number[]; - - viewport: GameViewport; - rendererType: number; - - vertexShader: string; - fragmentShader: string; - - manager: GameGLManager; - - constructor(glManager: GameGLManager, n: number) { - super(glManager, GENERIC_PLANET_PROGRAM_DEFINITION); - //@ts-ignore - this.verts = 0; //found in generic renderer - - this.manager = glManager; - const { vertexShader: vert, fragmentShader: frag } = GENERIC_PLANET_PROGRAM_DEFINITION; - this.vertexShader = vert; - this.fragmentShader = frag; - this.rendererType = n; - this.viewport = this.manager.renderer.getViewport(); - this.quadBuffer = EngineUtils.makeEmptyDoubleQuad(); - } - - public queuePlanet( - center: CanvasCoords, - radius: number, - planet: Planet, - angle = 1, // percent of arc to render - dashed = false - ): void { - const color = [255, 255, 255, 255] as RGBAVec; - const { - position: posA, - color: colorA, - props: propsA, - eps: epsA, - planetInfo: planetInfoA, - planetUpgrades: planetUpgradesA, - planetResources: planetResourcesA, - //@ts-ignore - } = this.attribManagers; - const { x, y } = center; - // 1 on either side for antialiasing - const r = radius + 1; - - const { x1, y1 } = { x1: x - r, y1: y - r }; - const { x2, y2 } = { x2: x + r, y2: y + r }; - - // prettier-ignore - EngineUtils.makeDoubleQuadBuffered( - this.quadBuffer, - x1, y1, x2, y2, -1, -1, 1, 1 - ); - //@ts-ignore - posA.setVertex(this.quadBuffer, this.verts); - - // convert pixels to radians - const interval = engineConsts.dashLength; - const pixPerRad = radius; - - const dashRad = interval / pixPerRad; - const dash = dashed ? dashRad : -1; - - const eps = 1 / radius; - const resources = [planet.energy, planet.energyCap, planet.silver, planet.silverCap]; - for (let i = 0; i < 6; i++) { - //@ts-ignore - colorA.setVertex(color, this.verts + i); - //@ts-ignore - propsA.setVertex([angle, dash], this.verts + i); - //@ts-ignore - planetInfoA.setVertex([planet.planetLevel, radius], this.verts + i); - //@ts-ignore - planetUpgradesA.setVertex(planet.upgradeState, this.verts + i); - //@ts-ignore - planetResourcesA.setVertex(resources, this.verts + i); - //@ts-ignore - epsA.setVertex([eps], this.verts + i); - } - //@ts-ignore - this.verts += 6; - } - - public queueGenericPlanet( - planet: Planet, - center: WorldCoords, - radius: number, // world coords - stroke = -1, - angle = 1, - dashed = false - ) { - const centerCanvas = this.viewport.worldToCanvasCoords(center); - const rCanvas = this.viewport.worldToCanvasDist(radius); - this.queuePlanet(centerCanvas, rCanvas, planet, angle, dashed); - } - - public setUniforms() { - //@ts-ignore - this.uniformSetters.matrix(this.manager.projectionMatrix); - } - - public queuePlanetBody(planet: Planet, centerW: WorldCoords, radiusW: number): void { - this.queueGenericPlanet(planet, centerW, radiusW); - } - public queueMine(planet: Planet, centerW: WorldCoords, radiusW: number): void { - this.queueGenericPlanet(planet, centerW, radiusW); - } - public queueRip(planet: Planet, centerW: WorldCoords, radiusW: number): void { - this.queueGenericPlanet(planet, centerW, radiusW); - } - - public queueQuasar(planet: Planet, centerW: WorldCoords, radiusW: number): void { - this.queueGenericPlanet(planet, centerW, radiusW); - } - - public queueRuins(planet: Planet, centerW: WorldCoords, radiusW: number): void { - this.queueGenericPlanet(planet, centerW, radiusW); - } - - public queueAsteroid(planet: Planet, centerW: CanvasCoords, radiusW: number): void { - this.queueGenericPlanet(planet, centerW, radiusW); - } -} - -/** - * 626-END: Plugin - */ - -export default class EmbeddedRendererShowcase implements DFPlugin { - CirclePlanetLibrary: { [key: string]: any }; - circleSelector: string; - circleChecker: { [key: string]: boolean }; - - constructor() { - let glMan = ui.getGlManager(); - this.circleSelector = 'Planet'; - if (glMan) { - this.CirclePlanetLibrary = { - Planet: new CirclePlanetRenderer(glMan, RendererType.Planet), - Mine: new CirclePlanetRenderer(glMan, RendererType.Mine), - SpacetimeRip: new CirclePlanetRenderer(glMan, RendererType.SpacetimeRip), - Quasar: new CirclePlanetRenderer(glMan, RendererType.Quasar), - Ruins: new CirclePlanetRenderer(glMan, RendererType.Ruins), - }; - } - this.circleChecker = {}; - for (let key in this.CirclePlanetLibrary) { - this.circleChecker[key] = false; - } - } - async render(div: HTMLDivElement) { - div.style.width = '500px'; - render( - html` -
Disabling Renderers
-
- Whats actually happening here is that the current renderer is being replaced with a - 'blank' renderer. A blank renderer is a renderer who's flush function has no - functionality. So the behavior is similar to disabling the current renderer. -
-
- - { - disable(); - }} - > - Disable - -
-
-
Circle Planets
-
- This replaces the current planet renderer with a renderer that uses WebGL to create a - circle where the color of the circle changes on the percentage of energy on the planet. -
-
- - - { - const btn = document.getElementById('CirclePlanetBtn'); - if (this.circleChecker[this.circleSelector] === false) { - ui.setCustomRenderer(this.CirclePlanetLibrary[this.circleSelector]); - this.circleChecker[this.circleSelector] = true; - btn!.innerText = 'Disable'; - } else { - ui.disableCustomRenderer(this.CirclePlanetLibrary[this.circleSelector]); - this.circleChecker[this.circleSelector] = false; - btn!.innerText = 'Enable'; - } - }} - > - Enable - -
-
-
Renderer Descriptions
- -
- `, - div - ); - } - - destroy(): void { - currentPlanet = 'Planet'; - for (let key in rendererLibrary) { - ui.disableCustomRenderer(rendererLibrary[key]); - } - for (let key in this.CirclePlanetLibrary) { - ui.disableCustomRenderer(this.CirclePlanetLibrary[key]); - } - } -} - -let selectStyle = { - outline: 'none', - background: '#151515', - color: '#838383', - borderRadius: '4px', - border: '1px solid #777', - width: '100px', - padding: '2px 6px', - cursor: 'pointer', - margin: '10px', -}; - -let inputStyle = { - background: 'rgb(8,8,8)', - width: '400px', - padding: '3px 5px', -}; - -let buttonStyle = { height: '25px', padding: '3px 5px', margin: '10px', 'text-align': 'center' }; - -let rendererLibrary: { [key: string]: any } = { - Planet: new PlanetRenderer(), - Mine: new MineRenderer(), - SpacetimeRip: new SpacetimeRipRenderer(), - Ruins: new RuinsRenderer(), - Quasar: new QuasarRenderer(), - Asteroid: new AsteroidRenderer(), - MineBody: new MineBodyRenderer(), - MineBelt: new BeltRenderer(), - Background: new BackgroundRenderer(), - UnminedBackground: new UnminedRenderer(), - SpaceBackground: new SpaceRenderer(), - Artifact: new SpriteRenderer(), - AllPlanets: new PlanetRenderManager(), - Text: new TextRenderer(), - Voyager: new VoyageRenderer(), - Perlin: new PerlinRenderer(), - Wormhole: new WormholeRenderer(), - BlackDomain: new BlackDomainRenderer(), - Rectangles: new RectRenderer(), - Line: new LineRenderer(), - Circle: new CircleRenderer(), - Ring: new RingRenderer(), - UI: new UIRenderer(), - QuasarBody: new QuasarBodyRenderer(), - QuasarRay: new QuasarRayRenderer(), - CaptureZone: new CaptureZoneRenderer(), -}; - -let disabled: { [key: string]: boolean } = {}; -for (let key in rendererLibrary) { - disabled[key] = false; -} - -let currentPlanet: string = 'Planet'; - -function disable() { - const btn = document.getElementById('RegPlanetBtn'); - if (disabled[currentPlanet] === false) { - ui.setCustomRenderer(rendererLibrary[currentPlanet]); - disabled[currentPlanet] = true; - btn!.innerText = 'Enable'; - } else { - ui.disableCustomRenderer(rendererLibrary[currentPlanet]); - disabled[currentPlanet] = false; - btn!.innerText = 'Disable'; - } -} - -const cellStyle = { - width: '25%', - float: 'left', -}; - -const discriptionStyle = { - TextAlign: 'justify', -}; - -// Used for discription of each type of renderer -let rendererDescription: { [key: string]: any } = { - Blank: '', - Planet: 'basic planets', - Mine: 'asteroid fields', - SpacetimeRip: 'Spacetime Rips', - Ruins: 'foundries', - Quasar: 'quasars', - Asteroid: 'asteroid that hover around different planets', - MineBody: 'the body/asteroids of asteroid fields', - MineBelt: 'the belts/rings around asteroid fields', - Background: 'the background of the game', - UnminedBackground: 'unmined space chunks (part of the background)', - SpaceBackground: 'mined space chunks (part of the background)', - Artifact: 'artifacts', - AllPlanets: 'All planet types', - Text: 'text that are displayed on the game canvas', - Voyager: 'Voyages. The transfer of energy between planets.', - Perlin: - 'the game background. Perlin is the method in which we generate the location of space biomes.', - Wormhole: 'visual effects of wormholes. Wormholes are generated by a special type of artifact.', - BlackDomain: - 'visual effects of black domains. Black Domains are created by a special type of artifact', - Rectangles: 'all rectangles drawn in game: indicators for selection of planet, ', - Line: ' all lines drawn in game: The line that connect planets during voyages and wormholes ', - Circle: - 'all circles drawn in the game: The voyager(circle) in voyages, Circles used to indicate the range a planets has, The boarder of the game world. ', - Ring: 'rings that indicate the level of a planet', - UI: 'in game user interface: game borders, range indicators, selection indicators, mouse path, miner', - QuasarBody: 'the body of the Quasar', - QuasarRay: 'the ray of the Quasar', - CaptureZone: 'the capture zones' -}; -/* eslint-enable */ diff --git a/client/embedded_plugins/Repeat-Attack.js b/client/embedded_plugins/Repeat-Attack.js new file mode 100644 index 00000000..c2c4a709 --- /dev/null +++ b/client/embedded_plugins/Repeat-Attack.js @@ -0,0 +1,592 @@ +// Repeat Attack +// +// Auto-attack when source planet has enough energy! +// +// original author: TBC +// enhancements in 2022: https://twitter.com/davidryan59 + +//@ts-ignore +import { + PlanetType, + SpaceType, + PlanetTypeNames, + //@ts-ignore +} from 'https://cdn.skypack.dev/@darkforest_eth/types'; +//@ts-ignore +import { isUnconfirmedMoveTx } from 'https://cdn.skypack.dev/@darkforest_eth/serde'; +//@ts-ignore +import { + html, + render, + useEffect, + useState, + useLayoutEffect, + //@ts-ignore +} from 'https://unpkg.com/htm/preact/standalone.module.js'; + +import { getPlanetName } from 'https://cdn.skypack.dev/@darkforest_eth/procedural'; + + +// ---------------------------------------- +// User Configurable Options + +// Control how much energy gets sent, and when +let DEFAULT_PERCENTAGE_TRIGGER = 75; // What percentage energy will trigger a send? +let DEFAULT_PERCENTAGE_REMAIN = 25; // How much energy will remain after sending? + +// Stagger all the different attacks by this number of seconds, don't send all at once +let STAGGER_S = 15; // Over what number of seconds will all repeat attacks happen once? + +// UI controls +let MAX_CHARS = 15; // How many letters of planet name to display? +let WIDTH_PX = 440; // What is the width of plugin window? +let MIN_V = 10; // Set minimum values for sliders +let MAX_V = 90; // Set maximum values for sliders +let STEP_V = 5; // Set step size for sliders + +// Keyboard shortcuts +const KEY_SET_SOURCE = 'v'; +const KEY_SET_TARGET = 'b'; +const KEY_START_FIRING = 'n'; +const KEY_TOGGLE_SILVER = 'm'; +const KEY_TOGGLE_OUTGOING_FIRING = ','; +const KEY_TOGGLE_OUTGOING_FIRING_DISPLAY = '<'; // '<' displays better than ',' +const KEY_TOGGLE_INCOMING_FIRING = '.'; +const KEY_TOGGLE_INCOMING_FIRING_DISPLAY = '>'; // '>' displays better than '.' + +// Other controls +let SILVER_SEND_PERCENT = 99; // Sends this proportion of silver from the source planet + +// Note - `let` was sometimes used by original author in this plugin to sidestep any weird execution env problems +// ---------------------------------------- + + +const FIRING_NONE = 0; +const FIRING_ACTIVE = 1; +const FIRING_PAUSED = 2; + +const sendSilverStatuses = [ + 'Do not send', // 0 + 'Upgrade first', // 1 + 'Send all' // 2 +]; +const sendSilverStatusesIcon = ['-', 'U', '$']; +const UPGRADE_FIRST = 1; +const SEND_ALL_SILVER = 2; +const INITIAL_SILVER_STATUS = UPGRADE_FIRST; +const toggleSilverStatus = val => (val + 1) % 3; // 3 way toggle + +const viewport = ui.getViewport(); +const PI_2 = 6.2831853; // 2 * pi, the number of radians in a complete circle +const [DESYNC_X, DESYNC_Y] = [101, 103]; // Desynchronises pulsing of separate planets using prime numbers multiplied by canvas coord components + +const PLANET_UNKNOWN = '?????'; +const getPlanetString = locationId => { + const planet = df.getPlanetWithId(locationId); + if (!planet) return PLANET_UNKNOWN; + let type = 'P'; + if( planet.planetType == PlanetType.SILVER_MINE) type = 'A' + else if (planet.planetType == PlanetType.RUINS) type = 'F' + else if (planet.planetType == PlanetType.TRADING_POST) type = 'STR' + else if (planet.planetType == PlanetType.SILVER_BANK) type = 'Q' + return `L${planet.planetLevel}-${type} ${getPlanetName(planet)}`; +}; +const getPlanetMaxRank = (planet) => { + if (!planet) return 0; + if(planet.planetType != PlanetType.PLANET) return 0; + if (planet.spaceType === SpaceType.NEBULA) return 3; + else if (planet.spaceType === SpaceType.SPACE) return 4; + else return 5; +}; +const isFullRank = (planet) => { + if (!planet) return true; + const maxRank = getPlanetMaxRank(planet); + const rank = planet.upgradeState.reduce( + (a, b) => a + b, + 0 + ); + return rank >= maxRank; +}; +function unconfirmedDepartures(planet) { + return ( + planet.transactions + ?.getTransactions(isUnconfirmedMoveTx) + //@ts-ignore + .reduce((acc, tx) => acc + tx.intent.forces, 0) || 0 + ); +} +function planetCurrentPercentEnergy(planet) { + const departures = unconfirmedDepartures(planet); + const estimatedEnergy = Math.floor(planet.energy - departures); + return Math.floor((estimatedEnergy / planet.energyCap) * 100); +} +class Repeater { + constructor() { + //@ts-ignore + if (typeof window.__CORELOOP__ == 'undefined') { + //setup append only interval id storage + //@ts-ignore + window.__CORELOOP__ = []; + } else { + //clear out old intervald + console.log('KILLING PREVIOUS INTERVALS'); + //@ts-ignore + window.__CORELOOP__.forEach((id) => window.clearInterval(id)); + } + this.currentPlanets = { // store relevant planets + selected: ui.getSelectedPlanet(), + source: null, + target: null + } + this.currentAttack = { // store attack being set up + sourceId: null, + targetId: null, + active: true, + pcTrigger: DEFAULT_PERCENTAGE_TRIGGER, + pcRemain: DEFAULT_PERCENTAGE_REMAIN, + sendSilverStatus: INITIAL_SILVER_STATUS + } + this.attacks = []; // attacks already set up + this.account = df.getAccount(); + this.configHash = df.contractConstants.CONFIG_HASH; + this.contractAddress = df.getContractAddress(); + this.loadAttacks(); + this.intervalId = window.setInterval(this.coreLoop.bind(this), 1000); + //@ts-ignore + window.__CORELOOP__.push(this.intervalId); + } + saveAttacks() { + localStorage.setItem(`repeatAttacks-${this.account}-${this.configHash}`, JSON.stringify(this.attacks)); + } + loadAttacks() { + const attacksJSON = localStorage.getItem(`repeatAttacks-${this.account}-${this.configHash}`); + // @ts-ignore + if (attacksJSON) this.attacks = JSON.parse(attacksJSON); + } + addAttack() { + const attack = { ...this.currentAttack }; + // Make sure source and target set + if (!attack.sourceId || !attack.targetId) return; + // Make sure remaining energy is less than trigger energy + attack.pcRemain = (attack.pcTrigger <= attack.pcRemain) ? parseInt(attack.pcTrigger / 2) : attack.pcRemain; + // Filter out existing attacks from this source, then add new attack at top + let newAttacks = this.attacks.filter(a => a.sourceId !== attack.sourceId); + newAttacks = [attack, ...newAttacks]; + this.attacks = newAttacks; + this.saveAttacks(); + } + toggleActive(position) { + this.attacks[position].active = !this.attacks[position].active; + this.saveAttacks(); + } + toggleSilver(position) { + this.attacks[position].sendSilverStatus = toggleSilverStatus(this.attacks[position].sendSilverStatus); + this.saveAttacks(); + } + removeAttack(position) { + this.attacks.splice(position, 1); + this.saveAttacks(); + } + removeAllAttacks() { + this.attacks = []; + this.saveAttacks(); + } + getFiringStatus(item) { + const planetId = this.currentPlanets.selected?.locationId; + if (!planetId) return FIRING_NONE; + const attacks = this.attacks.filter(a => a[item] === planetId); + if (!attacks.length) return FIRING_NONE; + const pausedAttacks = attacks.filter(a => !a.active); + return (pausedAttacks.length < attacks.length) ? FIRING_ACTIVE : FIRING_PAUSED; + } + outgoingStatus() { return this.getFiringStatus('sourceId'); } + incomingStatus() { return this.getFiringStatus('targetId'); } + toggleOutgoingFiring() { + const planetId = this.currentPlanets.selected?.locationId; + if (!planetId) return; + const newActive = !(this.outgoingStatus() === FIRING_ACTIVE); + this.attacks = this.attacks.map(a => { + if (a.sourceId === planetId) a.active = newActive; + return a + }) + this.saveAttacks(); + } + toggleIncomingFiring() { + const planetId = this.currentPlanets.selected?.locationId; + if (!planetId) return; + const newActive = !(this.incomingStatus() === FIRING_ACTIVE); + this.attacks = this.attacks.map(a => { + if (a.targetId === planetId) a.active = newActive; + return a + }) + this.saveAttacks(); + } + coreLoop() { + if(!this || !this.attacks) return; + this.attacks.forEach( (attack, idx) => { + if(idx % STAGGER_S == Math.floor(Date.now() / 1000) % STAGGER_S) ExecuteAttack(attack); + }); + } +} +const ExecuteAttack = ({sourceId, targetId, active, pcTrigger, pcRemain, sendSilverStatus}) => { + let srcPlanet = df.getPlanetWithId(sourceId); + if (!srcPlanet) return; + if (!active) return; + // Needs updated check getUnconfirmedDepartingForces + const departingForces = unconfirmedDepartures(srcPlanet); + const TRIGGER_AMOUNT = Math.floor((srcPlanet.energyCap * pcTrigger) / 100); + const FUZZY_ENERGY = Math.floor(srcPlanet.energy - departingForces); //Best estimate of how much energy is ready to send + if (FUZZY_ENERGY > TRIGGER_AMOUNT) { + const overflow_send = + planetCurrentPercentEnergy(srcPlanet) - pcRemain; + const FORCES = Math.floor((srcPlanet.energyCap * overflow_send) / 100); + let silver = 0; + if ( sendSilverStatus === SEND_ALL_SILVER || (sendSilverStatus === UPGRADE_FIRST && isFullRank(srcPlanet))) { + silver = Math.round(srcPlanet.silver * (SILVER_SEND_PERCENT / 100)); + } + df.move(sourceId, targetId, FORCES, silver); + } +}; +let Keyboard_Shortcut = { + fontSize: '85%', + color: 'rgba(220, 180, 128, 1)' +}; +let Margin_3L_3R = { + marginLeft: '3px', + marginRight: '3px', +}; +let Margin_12L_12R = { + marginLeft: '12px', + marginRight: '12px', +}; +let Margin_12B = { + marginBottom: '12px', +}; +let Margin_6B = { + marginBottom: '6px', +}; +let Clickable = { + cursor: 'pointer', + textDecoration: 'underline', +}; +let ActionEntry = { + marginBottom: '5px', + display: 'flex', + justifyContent: 'space-between', + color: '', +}; +function centerPlanet(id) { + ui.centerLocationId(id); +} +function Attack({ attack, onToggleActive, onToggleSilver, onDelete }) { + const srcString = getPlanetString(attack.sourceId); + const targetString = getPlanetString(attack.targetId); + const finalSrc = srcString.length > MAX_CHARS ? srcString.slice(0, MAX_CHARS - 3).concat('...') : srcString; + const finalTarget = targetString.length > MAX_CHARS ? targetString.slice(0, MAX_CHARS - 3).concat('...') : targetString; + return html` +
+ + + + centerPlanet(attack.sourceId)}>${finalSrc} + -> + centerPlanet(attack.targetId)}>${finalTarget} + + + ${`${attack.pcTrigger}%`} + -> + ${`${attack.pcRemain}%`} + + + + + + +
+ `; +} +function AddAttack({ repeater, startFiring, toggleOutgoingFiring, toggleIncomingFiring }) { + + const [currentPlanets, setCurrentPlanetsUS] = useState(repeater.currentPlanets); + const getCurrentPlanet = option => { + currentPlanets; // call UI state, but use repeater state + return repeater.currentPlanets[option]; + } + const setCurrentPlanet = (option, value) => { + repeater.currentPlanets[option] = value; + setCurrentPlanetsUS(repeater.currentPlanets); + } + + const [currentAttack, setCurrentAttackUS] = useState(repeater.currentAttack); + const getCurrentAttack = option => { + currentAttack; // call UI state, but use repeater state + return repeater.currentAttack[option]; + } + const setCurrentAttack = (option, value) => { + repeater.currentAttack[option] = value; + setCurrentAttackUS(repeater.currentAttack); + } + + const setSource = () => { + const planet = getCurrentPlanet('selected'); + setCurrentPlanet('source', planet); + setCurrentAttack('sourceId', planet?.locationId) + } + + const setTarget = () => { + const planet = getCurrentPlanet('selected'); + setCurrentPlanet('target', planet); + setCurrentAttack('targetId', planet?.locationId) + } + + const toggleSendSilver = () => setCurrentAttack( + 'sendSilverStatus', + toggleSilverStatus(getCurrentAttack('sendSilverStatus')) + ); + + useLayoutEffect(() => { + let onClick = () => setCurrentPlanet('selected', ui.getSelectedPlanet()); + window.addEventListener('click', onClick); + return () => { + window.removeEventListener('click', onClick); + }; + }, []); + useLayoutEffect(() => { + let onKeyUp = e => { + switch (e.key) { + case KEY_SET_SOURCE: + setSource(); + break; + case KEY_SET_TARGET: + setTarget(); + break; + case KEY_TOGGLE_SILVER: + toggleSendSilver(); + break; + case KEY_START_FIRING: + startFiring(); + break; + case KEY_TOGGLE_OUTGOING_FIRING: + case KEY_TOGGLE_OUTGOING_FIRING_DISPLAY: + toggleOutgoingFiring(); + break; + case KEY_TOGGLE_INCOMING_FIRING: + case KEY_TOGGLE_INCOMING_FIRING_DISPLAY: + toggleIncomingFiring(); + break; + } + }; + window.addEventListener('keyup', onKeyUp); + return () => { + window.removeEventListener('keyup', onKeyUp); + }; + }, []); + return html` +
+
+ + centerPlanet(getCurrentAttack('sourceId')) : () => {}} + > + ${getPlanetString(getCurrentAttack('sourceId'))} + +
+
+ + centerPlanet(getCurrentAttack('targetId')) : () => {}} + > + ${getPlanetString(getCurrentAttack('targetId'))} + +
+
+ Trigger firing at this energy: setCurrentAttack('pcTrigger', parseInt(e.target.value))}/> ${getCurrentAttack('pcTrigger')}% +
+
+ Remaining energy after firing: setCurrentAttack('pcRemain', parseInt(e.target.value))}/> ${getCurrentAttack('pcRemain')}% +
+
+ Choose when to send silver: +
+
+ +
+
+
+
+ Selected: + centerPlanet(getCurrentPlanet('selected').locationId) : () => {}} + > + ${getPlanetString(getCurrentPlanet('selected')?.locationId)} + +
+
+ ${repeater.outgoingStatus() === FIRING_NONE ? '' : html` + + `} + ${repeater.incomingStatus() === FIRING_NONE ? '' : html` + + `} +
+
+
+
+ `; +} +function AttackList({ repeater }) { + const [attacks, setAttacks] = useState([...repeater.attacks]); + useEffect(() => { + const id = setInterval(() => { + setAttacks([...repeater.attacks]); + }, 1000); + setAttacks([...repeater.attacks]); + return () => clearInterval(id); + }, [attacks.length]); + let actionList = { + backgroundColor: '#252525', + maxHeight: '240px', + overflowX: 'hidden', + overflowY: 'scroll', + padding: '5px', + borderRadius: '5px', + }; + //@ts-ignore + let actionsChildren = attacks.map((action, index) => { + return html` + <${Attack} + attack=${action} + onToggleActive=${() => repeater.toggleActive(index)} + onToggleSilver=${() => repeater.toggleSilver(index)} + onDelete=${() => repeater.removeAttack(index)} + /> + `; + }); + return html` + + Auto-attack when source planet has enough energy! + + <${AddAttack} + repeater=${repeater} + startFiring=${() => repeater.addAttack()} + toggleOutgoingFiring=${() => repeater.toggleOutgoingFiring()} + toggleIncomingFiring=${() => repeater.toggleIncomingFiring()} + /> +

+ Active (${attacks.reduce((acc, atk) => acc + (atk.active ? 1 : 0), 0)} / ${attacks.length}) + + +

+
${actionsChildren.length ? actionsChildren : 'No Actions.'}
+ `; +} +function App({ repeater }) { + return html`<${AttackList} repeater=${repeater} />`; +} + +const drawHighlights = plugin => { + const ctx = plugin.ctx; + const timeMs = plugin.dateNow; + const planet = plugin.repeater.currentPlanets.selected; + if (!planet || !planet.location) return; + const selectedPlanetId = planet.locationId; + const attacks = plugin.repeater.attacks; + const attacksSelectedIsSource = attacks.filter(a => a.sourceId === selectedPlanetId); + const attacksSelectedIsTarget = attacks.filter(a => a.targetId === selectedPlanetId); + if (!attacksSelectedIsSource.length && !attacksSelectedIsTarget.length) return; + const getSawWave01 = (periodMs, planet) => { + const coords = planet.location.coords; + const adjustedTimeMs = timeMs + DESYNC_X * coords.x + DESYNC_Y * coords.y; // Large number of seconds from 1970 (approx) + return (adjustedTimeMs % periodMs) / periodMs; // Sawtooth Wave, position in cycle, between 0 and 1 + } + const getTriWave01 = (periodMs, planet) => { + const sawWave01 = getSawWave01(periodMs, planet); + return 2 * Math.min(sawWave01, 1 - sawWave01); // Triangle Wave, between 0 and 1 + } + const drawHighlight = (planetId, rgba, periodMs, lineWidth, arcFraction) => { + const thePlanet = ui.getPlanetWithId(planetId); + const theCoords = thePlanet.location.coords; + ctx.strokeStyle = rgba; + ctx.setLineDash([12, 8]); + ctx.lineWidth = lineWidth; + ctx.beginPath(); + const cX = viewport.worldToCanvasX(theCoords.x); + const cY = viewport.worldToCanvasY(theCoords.y); + const cR = 10 + viewport.worldToCanvasDist(1.4 * ui.getRadiusOfPlanetLevel(thePlanet.planetLevel)); + const START_RADIANS = PI_2 * getSawWave01(periodMs, thePlanet); + ctx.arc(cX, cY, cR, START_RADIANS, START_RADIANS + PI_2 * arcFraction); + ctx.stroke(); + ctx.closePath(); + } + attacksSelectedIsSource.forEach(a => a.active + ? drawHighlight(a.targetId, `rgba(255, 80, 80, 0.6)`, 23000, 8, 0.55) + : drawHighlight(a.targetId, `rgba(180, 140, 40, 0.6)`, 23000, 6, 0.3) + ); + drawHighlight(selectedPlanetId, `rgba(80, 80, 255, 0.7)`, -12000, 6, 0.7); + attacksSelectedIsTarget.forEach(a => a.active + ? drawHighlight(a.sourceId, `rgba(80, 255, 80, 0.5)`, 7000, 4, 0.8) + : drawHighlight(a.sourceId, `rgba(140, 180, 40, 0.5)`, 7000, 3, 0.4) + ); +} + +class Plugin { + constructor() { + this.repeater = new Repeater(); + this.ctx = null; + this.dateNow = Date.now(); + this.root = undefined; + } + stop() { + //@ts-ignore + window.__CORELOOP__.forEach((id) => window.clearInterval(id)); + } + /** + * Called when plugin is launched with the "run" button. + */ + async render(container) { + this.container = container; + container.style.width = `${WIDTH_PX}px`; + this.root = render(html`<${App} repeater=${this.repeater} />`, container); + } + /** + * Used to highlight source, selected, and target planets. + */ + draw(ctx) { + ctx.save(); + this.ctx = ctx; + this.dateNow = Date.now(); + drawHighlights(this); + ctx.restore(); + } + /** + * Called when plugin modal is closed. + */ + destroy() { + //@ts-ignore + window.__CORELOOP__.forEach((id) => window.clearInterval(id)); + if (this.container) render(html`
`, this.container); + } +} +/** + * And don't forget to export it! + */ +export default Plugin; diff --git a/client/embedded_plugins/Upgrade-Manager.js b/client/embedded_plugins/Upgrade-Manager.js new file mode 100644 index 00000000..a63b5fd9 --- /dev/null +++ b/client/embedded_plugins/Upgrade-Manager.js @@ -0,0 +1,103 @@ +// Upgrade Manager +// +// upgrades all the planets in your empire every minute according to a pattern (d = defense, r = range, s = speed) +// for example, if the pattern is "rrrsd" a rank 3 planet that can upgrade will choose to upgrade the speed branch + +import { + SpaceType, + PlanetType, + } from "https://cdn.skypack.dev/@darkforest_eth/types"; + + // if planet is not at max rank and has enough silver + const planetCanUpgrade = (planet) => { + const totalRank = planet.upgradeState.reduce((a, b) => a + b); + if (planet.spaceType === SpaceType.NEBULA && totalRank >= 3) return false; + if (planet.spaceType === SpaceType.SPACE && totalRank >= 4) return false; + if (planet.spaceType === SpaceType.DEEP_SPACE && totalRank >= 5) return false; + if (planet.spaceType === SpaceType.DEAD_SPACE && totalRank >= 5) return false; + return ( + planet.planetLevel !== 0 && + planet.planetType === PlanetType.PLANET && + planet.silver >= silverNeededForUpgrade(planet) + ); + }; + + const silverNeededForUpgrade = (planet) => { + const totalLevel = planet.upgradeState.reduce((a, b) => a + b); + return (totalLevel + 1) * 0.2 * planet.silverCap; + }; + + const upgradablePlanets = () => { + return df.getMyPlanets().filter(planetCanUpgrade); + }; + + // upgrades planet, using a pattern + // just a rudimentary implementation that takes the branch that should be upgraded from the nth letter of the pattern, where n is the current rank + const upgradePlanet = (planet, pattern) => { + const rank = planet.upgradeState.reduce((a, b) => a + b, 0); + if (pattern.length <= rank) return; + const upgradeBranch = ["d", "r", "s"].indexOf(pattern[rank]); + df.upgrade(planet.locationId, upgradeBranch); + }; + + const upgradeAllPlanets = (pattern) => { + upgradablePlanets().forEach((p) => upgradePlanet(p, pattern)); + }; + + class UpgradeManager { + async render(container) { + // brief explanation on the syntax + const tutorial = document.createElement("div"); + tutorial.innerText = "d = defense, r = range, s = speed"; + tutorial.style.fontSize = "11px"; + tutorial.style.marginBottom = "10px"; + + const patternLabel = document.createElement("label"); + patternLabel.innerText = "Upgrade pattern:"; + patternLabel.htmlFor = "pattern"; + patternLabel.style.display = "block"; + + const patternInput = document.createElement("input"); + patternInput.value = "rrrrs"; + patternInput.id = "pattern"; + patternInput.style.display = "block"; + + const upgradePlanetsButton = document.createElement("button"); + upgradePlanetsButton.innerText = "Start Upgrading!"; + upgradePlanetsButton.style.marginTop = "1em"; + upgradePlanetsButton.style.display = "block"; + + // determines to either start or cancel upgrading when the button above is clicked + let upgradingToggle = true; + + // upgrade all planets once per minute + upgradePlanetsButton.onclick = () => { + if (upgradingToggle) { + upgradeAllPlanets([...patternInput.value]); + this.upgradePlanetsInterval = window.setInterval( + () => upgradeAllPlanets([...patternInput.value]), + 1e3 * 30 + ); + } else { + window.clearInterval(this.upgradePlanetsInterval); + } + upgradingToggle = !upgradingToggle; + upgradePlanetsButton.innerText = upgradingToggle + ? "Start Upgrading!" + : "Stop Upgrading"; + }; + + container.append( + tutorial, + patternLabel, + patternInput, + upgradePlanetsButton + ); + patternInput.focus(); + } + + destroy() { + window.clearInterval(this.upgradePlanetsInterval); + } + } + export default UpgradeManager; \ No newline at end of file diff --git a/client/embedded_plugins/Voyage-Time.js b/client/embedded_plugins/Voyage-Time.js new file mode 100644 index 00000000..c620a450 --- /dev/null +++ b/client/embedded_plugins/Voyage-Time.js @@ -0,0 +1,129 @@ +// Voyage Time +// +// View estimated time for a voyage. + +let oneMinute = 60; +let oneHour = 60 * oneMinute; + + +class VoyageTime { + constructor() { + this.energyPercent = 55; + this.estimatedTime = document.createElement('div'); + this.estimatedTime.innerText = '?????'; + this.estimatedTime.style.textAlign = 'center'; + this.estimatedTimeSeconds = document.createElement('div'); + this.estimatedTimeSeconds.innerText = ''; + this.estimatedTimeSeconds.style.textAlign = 'center'; + this.estimatedEnergy = document.createElement('div'); + this.estimatedEnergy.innerText = '?????'; + this.estimatedEnergy.style.textAlign = 'center'; + } + + calcVoyageTime = () => { + let fromPlanet = ui.getSelectedPlanet(); + if (fromPlanet) { + let toPlanet = ui.getHoveringOverPlanet(); + + if (toPlanet && fromPlanet !== toPlanet) { + // In seconds + let time = Math.ceil( + df.getTimeForMove(fromPlanet.locationId, toPlanet.locationId) + ); + let hours = Math.floor(time / oneHour); + let minutes = Math.floor(time % oneHour / 60); + let seconds = Math.ceil(time % oneHour % oneMinute); + if (hours >= 1) { + this.estimatedTime.innerText = `${hours} hrs, ${minutes} mins, ${seconds} secs`; + } else if (minutes >= 1) { + this.estimatedTime.innerText = `${minutes} mins, ${seconds} secs`; + } else { + this.estimatedTime.innerText = `${seconds} secs`; + } + // this.estimatedTimeSeconds.innerText = `${time} secs`; + // Energy + let sendEnergy = (fromPlanet.energyCap * this.energyPercent / 100); + let arriveEnergy = df.getEnergyArrivingForMove(fromPlanet.locationId, toPlanet.locationId, undefined, sendEnergy); + if (toPlanet.owner !== df.getAccount()) { + arriveEnergy = arriveEnergy * 100 / toPlanet.defense + } + sendEnergy = Math.ceil(sendEnergy); + arriveEnergy = Math.ceil(arriveEnergy); + if (sendEnergy > 1000000) { + sendEnergy = (sendEnergy / 1000000).toFixed(1) + 'M'; + } else if (sendEnergy > 1000) { + sendEnergy = (sendEnergy / 1000).toFixed(1) + 'K'; + } + if (arriveEnergy > 1000000) { + arriveEnergy = (arriveEnergy / 1000000).toFixed(1) + 'M'; + } else if (arriveEnergy > 1000) { + arriveEnergy = (arriveEnergy / 1000).toFixed(1) + 'K'; + } + this.estimatedEnergy.innerText = `Sending ${sendEnergy}, will receive ${arriveEnergy}`; + } else { + this.estimatedTime.innerText = '?????'; + this.estimatedTimeSeconds.innerText = ``; + this.estimatedEnergy.innerText = '?????'; + } + } else { + this.estimatedTime.innerText = '?????'; + this.estimatedTimeSeconds.innerText = ``; + this.estimatedEnergy.innerText = '?????'; + } + } + + render(container) { + container.parentElement.style.minHeight = 'unset'; + container.style.width = '250px'; + container.style.minHeight = 'unset'; + window.addEventListener('mousemove', this.calcVoyageTime); + + let label = document.createElement('div'); + label.innerText = 'Voyage Time:' + label.style.textAlign = 'center'; + + container.appendChild(label); + container.appendChild(this.estimatedTime); + container.appendChild(this.estimatedTimeSeconds); + + let stepperLabel = document.createElement('label'); + stepperLabel.innerText = 'Energy sent:'; + stepperLabel.style.textAlign = 'center'; + stepperLabel.style.display = 'block'; + + let stepper = document.createElement('input'); + stepper.type = 'range'; + stepper.min = '0'; + stepper.max = '100'; + stepper.step = '5'; + stepper.value = `${this.energyPercent}`; + stepper.style.width = '80%'; + stepper.style.height = '24px'; + + let percent = document.createElement('span'); + percent.innerText = `${stepper.value}%`; + percent.style.float = 'right'; + + stepper.onchange = (evt) => { + percent.innerText = `${evt.target.value}%`; + try { + this.energyPercent = parseInt(evt.target.value, 10); + } catch (e) { + console.error('could not parse energy percent', e); + } + } + + container.appendChild(stepperLabel); + container.appendChild(stepper); + container.appendChild(percent); + container.appendChild(this.estimatedEnergy); + } + + destroy() { + window.removeEventListener('mousemove', this.calcVoyageTime); + delete this.estimatedTime + delete this.estimatedTimeSeconds + } +} + +export default VoyageTime; \ No newline at end of file diff --git a/client/index.html b/client/index.html index 7c089e0f..12c274d6 100644 --- a/client/index.html +++ b/client/index.html @@ -11,7 +11,7 @@ - + - + - - - - - - - - - - + + + + + + + + + + - - - - + + + + - + - - + Dark Forest
- diff --git a/client/last_updated.txt b/client/last_updated.txt new file mode 100644 index 00000000..a9ecdd54 --- /dev/null +++ b/client/last_updated.txt @@ -0,0 +1 @@ +last updated: Mon Apr 11 18:20:58 UTC 2022 diff --git a/client/netlify.toml b/client/netlify.toml index 6fb83ba0..f8fd0910 100644 --- a/client/netlify.toml +++ b/client/netlify.toml @@ -1,5 +1,5 @@ [build] - command = "npm run build" + command = "yarn build" functions = "functions" publish = "dist" @@ -8,10 +8,15 @@ to = "/index.html" status = 200 +[[redirects]] + from = "/archive/8d8a7d2a/*" + to = "https://6247dc3ca1de3b6ce0c8e184--df-prod.netlify.app/:splat" + status = 200 + ## (optional) Settings for Netlify Dev ## https://github.com/netlify/cli/blob/master/docs/netlify-dev.md#project-detection #[dev] -# command = "npm start" # Command to start your dev server +# command = "yarn start" # Command to start your dev server # port = 3000 # Port that the dev server will be listening on # publish = "dist" # Folder with the static content for _redirect file diff --git a/client/package.json b/client/package.json index 99519934..1bec29a6 100644 --- a/client/package.json +++ b/client/package.json @@ -1,26 +1,28 @@ { "name": "client", - "version": "100.0.0-dev.0", + "version": "6.7.29", "private": true, "license": "GPL-3.0", "author": "0xPARC ", "dependencies": { - "@dfdao/constants": "100.0.0-dev.0", - "@dfdao/contracts": "100.0.0-dev.0", - "@dfdao/events": "100.0.0-dev.0", - "@dfdao/hashing": "100.0.0-dev.0", - "@dfdao/hexgen": "100.0.0-dev.0", - "@dfdao/network": "100.0.0-dev.0", - "@dfdao/procedural": "100.0.0-dev.0", - "@dfdao/renderer": "100.0.0-dev.0", - "@dfdao/serde": "100.0.0-dev.0", - "@dfdao/settings": "100.0.0-dev.0", - "@dfdao/snarks": "100.0.0-dev.0", - "@dfdao/types": "100.0.0-dev.0", - "@dfdao/gamelogic": "100.0.0-dev.0", - "@dfdao/ui": "100.0.0-dev.0", - "@dfdao/whitelist": "100.0.0-dev.0", + "@darkforest_eth/constants": "6.7.29", + "@darkforest_eth/contracts": "6.7.29", + "@darkforest_eth/events": "6.7.29", + "@darkforest_eth/gamelogic": "6.7.29", + "@darkforest_eth/hashing": "6.7.29", + "@darkforest_eth/hexgen": "6.7.29", + "@darkforest_eth/network": "6.7.29", + "@darkforest_eth/procedural": "6.7.29", + "@darkforest_eth/renderer": "6.7.29", + "@darkforest_eth/serde": "6.7.29", + "@darkforest_eth/settings": "6.7.29", + "@darkforest_eth/snarks": "6.7.29", + "@darkforest_eth/types": "6.7.29", + "@darkforest_eth/ui": "6.7.29", + "@darkforest_eth/whitelist": "6.7.29", + "@dfdao/dynasty": "1.1.0", "@lit-labs/react": "^1.0.0", + "@radix-ui/react-toast": "^0.1.1", "animejs": "^3.2.1", "auto-bind": "^4.0.0", "bad-words": "^3.0.4", @@ -30,7 +32,7 @@ "delay": "^5.0.0", "email-validator": "^2.0.4", "emoji-picker-react": "^3.4.8", - "ethers": "^5.7.1", + "ethers": "^5.5.1", "events": "^3.0.0", "fastq": "^1.10.0", "file-saver": "^2.0.5", @@ -49,29 +51,29 @@ "react": "^17.0.2", "react-dom": "^17.0.2", "react-loader-spinner": "^4.0.0", + "react-markdown": "^8.0.3", "react-router-dom": "^5.3.0", + "react-select": "^5.3.2", "react-simple-code-editor": "^0.11.0", "react-sortablejs": "^6.0.0", "react-timeago": "^6.2.1", "sortablejs": "^1.10.2", "styled-components": "^5.3.3", + "swr": "^1.3.0", "ts-dedent": "^2.0.0", - "uuid": "^8.3.2", - "yjs": "^13.5.41", - "y-indexeddb": "^9.0.9" + "uuid": "^8.3.2" }, "scripts": { "declarations": "tsc -p tsconfig.decs.json", + "test": "exit 0", "lint": "eslint .", "format": "prettier --write .", - "start": "vite", - "build": "vite build", + "start": "webpack-dev-server --mode development --hot", + "build": "webpack --mode production", "clean": "del-cli dist node_modules declarations public/contracts tsconfig.ref.tsbuildinfo", - "docs": "typedoc && npm run format", + "docs": "typedoc && yarn format", "deploy": "netlify build && netlify deploy", - "deploy:prod": "netlify build && netlify deploy --prod", - "test": "vitest run", - "coverage": "vitest run --coverage" + "deploy:prod": "netlify build && netlify deploy --prod" }, "browserslist": { "production": [ @@ -87,10 +89,10 @@ "node": ">=16" }, "devDependencies": { - "@projectsophon/workspace": "^2.0.0", - "@rollup/plugin-commonjs": "^22.0.2", - "@rollup/plugin-node-resolve": "14.1.0", - "@types/react-timeago": "^4.1.3", + "@babel/core": "^7.17.5", + "@babel/preset-env": "^7.16.11", + "@babel/preset-react": "^7.16.7", + "@babel/preset-typescript": "^7.16.7", "@types/animejs": "^3.1.3", "@types/color": "^3.0.2", "@types/gl-matrix": "^3.2.0", @@ -100,20 +102,32 @@ "@types/react": "^17.0.34", "@types/react-dom": "^17.0.11", "@types/react-router-dom": "^5.3.2", + "@types/react-timeago": "^4.1.3", "@types/sortablejs": "^1.10.6", "@types/styled-components": "^5.1.15", "@types/uuid": "^8.3.0", - "@vitejs/plugin-react": "^2.1.0", + "@types/webpack-env": "^1.16.3", + "babel-loader": "^8.2.3", + "babel-plugin-styled-components": "^2.0.5", + "copy-webpack-plugin": "^9.0.1", + "css-loader": "^6.5.1", "del-cli": "^4.0.1", - "esbuild": "0.15.8", - "eslint": "^8.23.1", - "jsdom": "^20.0.0", + "dotenv": "^10.0.0", + "eslint": "^7.30.0", + "fork-ts-checker-webpack-plugin": "^7.2.1", + "html-webpack-plugin": "^5.5.0", "netlify-cli": "^3.8.5", - "prettier": "^2.7.1", - "typedoc": "^0.23.15", - "typedoc-plugin-markdown": "3.13.x", - "typescript": "4.7.x", - "vite": "^3.1.3", - "vitest": "^0.23.4" + "prettier": "^2.3.0", + "raw-loader": "^4.0.2", + "resolve-package-path": "^4.0.3", + "source-map-loader": "^3.0.0", + "style-loader": "^3.3.1", + "typedoc": "^0.22.8", + "typedoc-plugin-markdown": "3.11.x", + "typescript": "4.5.x", + "webpack": "^5.62.1", + "webpack-bundle-analyzer": "^4.5.0", + "webpack-cli": "^4.9.1", + "webpack-dev-server": "^4.4.0" } } diff --git a/client/plugins/RendererPlugin.md b/client/plugins/RendererPlugin.md index 0904a52b..9cf39773 100644 --- a/client/plugins/RendererPlugin.md +++ b/client/plugins/RendererPlugin.md @@ -20,7 +20,7 @@ Renderers have two main methods: - Flush: Flush is called every frame in the game. When called, the entities in the queue should be rendered onto the game canvas and the queue cleared. -For the game to recognize if the class is a renderer, it has to follow one of the renderer interfaces that can be found in `@dfdao/types` +For the game to recognize if the class is a renderer, it has to follow one of the renderer interfaces that can be found in `@darkforest_eth/types` For instance `MineRendererType` is an interface for mine renderers. Mine renderers are used to draw Asteroid Fields which is a type of planet (not to be confused with Asteroids). @@ -70,10 +70,10 @@ When you replace a renderer in the game, the renderer is then put on our renderi We will run through the creation of a renderer that will replace the renderer for Asteroid Fields. -To create a renderer it has to follow one of the renderer interfaces that can be found in ​​`@dfdao/types`. For the Asteroid Fields, we will be using the `MineRendererType`. +To create a renderer it has to follow one of the renderer interfaces that can be found in ​​`@darkforest_eth/types`. For the Asteroid Fields, we will be using the `MineRendererType`. ```javascript -import { RendererType } from 'https://cdn.skypack.dev/@dfdao/types'; +import { RendererType } from 'https://cdn.skypack.dev/@darkforest_eth/types'; class GenericMineRenderer { constructor() { @@ -99,7 +99,7 @@ After: If you noticed in the queue function, the coordinate of the planet and the size of planet is relative to the game world. However when drawn on the canvas, the size and location of planet change based on the position of the players camera. We provide developers a way to easily transform between coordinate systems via the viewport class. You can get the viewport from the global ui class. `ui.getViewport()`. An example of the use of the viewport can be seen in the code of the `queueMine` function below. ```javascript -import { RendererType } from 'https://cdn.skypack.dev/@dfdao/types'; +import { RendererType } from 'https://cdn.skypack.dev/@darkforest_eth/types'; class GenericMineRenderer { constructor() { @@ -123,7 +123,7 @@ These are the 2 functions used above. - `worldToCanvasCoords` will translate from game world coordinates to canvas coordinates. In the code above we are translating the location of the Asteroid Field to its location relative to the canvas. - `worldToCanvasDist` will translate a distance relative to the game world to the pixel distance on the canvas. -After implementing the above code you should be ready to start implementing code that will draw on the game canvas. +After implementing the above code you should be ready to start implementing code that will draw on the game canvas. To do this you will need to be able to access the `WebGLRenderingContext`. ## WebGL Code @@ -155,8 +155,12 @@ The code below contains all of the objects that we will explore to demonstrate W ## Fragment and Vertex Shaders ```javascript -import { glsl } from 'https://cdn.skypack.dev/@dfdao/renderer'; -import { RendererProgram, AttribeType, UniformType } from 'https://cdn.skypack.dev/@dfdao/types'; +import { glsl } from 'https://cdn.skypack.dev/@darkforest_eth/renderer'; +import { + RendererProgram, + AttribeType, + UniformType, +} from 'https://cdn.skypack.dev/@darkforest_eth/types'; const program = { uniforms: { matrix: { name: 'u_matrix', type: UniformType.Mat4 }, @@ -185,7 +189,7 @@ const program = { out float v_energy_cap; void main() { // converting from canvas coordinates too clip space - gl_Position = u_matrix * vec4(a_position.xy, 0.0, 1.0); + gl_Position = u_matrix * vec4(a_position.xy, 0.0, 1.0); //setting the varrying variables for use in the fragment shader v_energy = a_energy.x; v_energy_cap = a_energy.y; @@ -206,9 +210,9 @@ const program = { float dist = length(v_rectPos); // if it's outside the circle - if (dist > 1.0) discard; + if (dist > 1.0) discard; - //determine the color of the pixel using rgb values + //determine the color of the pixel using rgb values //[red,green,blue,opacity] the range of the numbers is from 0 to 1 outColor = vec4(1,1.0/v_energy_cap*v_energy,0,1); } @@ -240,9 +244,9 @@ The fragment shader is called for every pixel in the square. The `outColor` is t ## Renderer Code ```javascript -import { EngineUtils, GenericRenderer, glsl } from 'https://cdn.skypack.dev/@dfdao/renderer'; +import { EngineUtils, GenericRenderer, glsl } from 'https://cdn.skypack.dev/@darkforest_eth/renderer'; import { AttribType, RendererType, UniformType, -} from 'https://cdn.skypack.dev/@dfdao/types'; +} from 'https://cdn.skypack.dev/@darkforest_eth/types'; class GenericMineRenderer extends GenericRenderer { constructor(gl, vp) { super(gl, program); @@ -347,8 +351,16 @@ For each vertex we are importing the information about the planet's energy to th The final code for the renderer looks like this: ```javascript -import { EngineUtils, GenericRenderer, glsl } from 'https://cdn.skypack.dev/@dfdao/renderer'; -import { AttribType, RendererType, UniformType } from 'https://cdn.skypack.dev/@dfdao/types'; +import { + EngineUtils, + GenericRenderer, + glsl, +} from 'https://cdn.skypack.dev/@darkforest_eth/renderer'; +import { + AttribType, + RendererType, + UniformType, +} from 'https://cdn.skypack.dev/@darkforest_eth/types'; class GenericMineRenderer extends GenericRenderer { constructor(gl, vp) { @@ -415,7 +427,7 @@ const program = { out float v_energy_cap; void main() { // converting from canvas coordinates too clip space - gl_Position = u_matrix * vec4(a_position.xy, 0.0, 1.0); + gl_Position = u_matrix * vec4(a_position.xy, 0.0, 1.0); //setting the varrying variables for use in the fragment shader v_energy = a_energy.x; v_energy_cap = a_energy.y; @@ -436,9 +448,9 @@ const program = { float dist = length(v_rectPos); // if it's outside the circle - if (dist > 1.0) discard; + if (dist > 1.0) discard; - //determine the color of the pixel using rgb values + //determine the color of the pixel using rgb values //[red,green,blue,opacity] the range of the numbers is from 0 to 1 outColor = vec4(1,1.0/v_energy_cap*v_energy,0,1); } diff --git a/client/public/icons/alerts/combat/planetsupported.svg b/client/public/icons/alerts/combat/planetsupported.svg new file mode 100644 index 00000000..b5ec2a0f --- /dev/null +++ b/client/public/icons/alerts/combat/planetsupported.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/client/public/icons/gclogo.svg b/client/public/icons/gclogo.svg new file mode 100644 index 00000000..d7bbdd86 --- /dev/null +++ b/client/public/icons/gclogo.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/client/public/icons/twitter.svg b/client/public/icons/twitter.svg index 14b2b610..b25ac935 100644 --- a/client/public/icons/twitter.svg +++ b/client/public/icons/twitter.svg @@ -1,7 +1,16 @@ - - - - + + + diff --git a/client/public/img/LandingPageGrid.svg b/client/public/img/LandingPageGrid.svg new file mode 100644 index 00000000..0deda619 --- /dev/null +++ b/client/public/img/LandingPageGrid.svg @@ -0,0 +1,38 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/client/public/img/epicbattle.jpg b/client/public/img/epicbattle.jpg new file mode 100644 index 00000000..04c8d372 Binary files /dev/null and b/client/public/img/epicbattle.jpg differ diff --git a/client/public/img/screenshots/bluespace.png b/client/public/img/screenshots/bluespace.png new file mode 100644 index 00000000..c8bf8f22 Binary files /dev/null and b/client/public/img/screenshots/bluespace.png differ diff --git a/client/public/img/screenshots/deathstar.png b/client/public/img/screenshots/deathstar.png new file mode 100644 index 00000000..9d916b49 Binary files /dev/null and b/client/public/img/screenshots/deathstar.png differ diff --git a/client/public/img/screenshots/pickles.png b/client/public/img/screenshots/pickles.png new file mode 100644 index 00000000..c4407300 Binary files /dev/null and b/client/public/img/screenshots/pickles.png differ diff --git a/client/public/img/screenshots/purple.png b/client/public/img/screenshots/purple.png new file mode 100644 index 00000000..2ce4261d Binary files /dev/null and b/client/public/img/screenshots/purple.png differ diff --git a/client/public/img/screenshots/stock.png b/client/public/img/screenshots/stock.png new file mode 100644 index 00000000..b2abc6e0 Binary files /dev/null and b/client/public/img/screenshots/stock.png differ diff --git a/client/public/img/screenshots/tutorial-banner.png b/client/public/img/screenshots/tutorial-banner.png new file mode 100644 index 00000000..798bc37a Binary files /dev/null and b/client/public/img/screenshots/tutorial-banner.png differ diff --git a/client/public/img/screenshots/wholeworld.png b/client/public/img/screenshots/wholeworld.png new file mode 100644 index 00000000..4f352e58 Binary files /dev/null and b/client/public/img/screenshots/wholeworld.png differ diff --git a/client/public/ready-alert.mp3 b/client/public/ready-alert.mp3 new file mode 100644 index 00000000..3d8a5f62 Binary files /dev/null and b/client/public/ready-alert.mp3 differ diff --git a/client/public/round_art/arena.jpg b/client/public/round_art/arena.jpg new file mode 100644 index 00000000..82961734 Binary files /dev/null and b/client/public/round_art/arena.jpg differ diff --git a/client/public/round_art/galacticleague.jpg b/client/public/round_art/galacticleague.jpg new file mode 100644 index 00000000..1eb48020 Binary files /dev/null and b/client/public/round_art/galacticleague.jpg differ diff --git a/client/public/round_art/grandprix.png b/client/public/round_art/grandprix.png new file mode 100644 index 00000000..cf2eebc8 Binary files /dev/null and b/client/public/round_art/grandprix.png differ diff --git a/client/public/snarkjs.min.js b/client/public/snarkjs.min.js index 7f02dedb..7f839ad4 100644 --- a/client/public/snarkjs.min.js +++ b/client/public/snarkjs.min.js @@ -1,10 +1 @@ -var snarkjs=function(t){"use strict";const e=[0,1,2,2,3,3,3,3,4,4,4,4,4,4,4,4];function a(t,e){return e&&10!=e?16==e?"0x"==t.slice(0,2)?BigInt(t):BigInt("0x"+t):void 0:BigInt(t)}const i=a;function o(t,e){return BigInt(t)<>BigInt(e)}const r=o,l=n;var c=Object.freeze({__proto__:null,fromString:a,e:i,fromArray:function(t,e){let a=BigInt(0);e=BigInt(e);for(let i=0;i>=BigInt(1)}return a},bits:function(t){let e=BigInt(t);const a=[];for(;e;)e&BigInt(1)?a.push(1):a.push(0),e>>=BigInt(1);return a},toNumber:function(t){if(t>BigInt(Number.MAX_SAFE_INTEGER))throw new Error("Number too big");return Number(t)},toArray:function(t,e){const a=[];let i=BigInt(t);for(e=BigInt(e);i;)a.unshift(Number(i%e)),i/=e;return a},add:function(t,e){return BigInt(t)+BigInt(e)},sub:function(t,e){return BigInt(t)-BigInt(e)},neg:function(t){return-BigInt(t)},mul:function(t,e){return BigInt(t)*BigInt(e)},square:function(t){return BigInt(t)*BigInt(t)},pow:function(t,e){return BigInt(t)**BigInt(e)},exp:function(t,e){return BigInt(t)**BigInt(e)},abs:function(t){return BigInt(t)>=0?BigInt(t):-BigInt(t)},div:function(t,e){return BigInt(t)/BigInt(e)},mod:function(t,e){return BigInt(t)%BigInt(e)},eq:function(t,e){return BigInt(t)==BigInt(e)},neq:function(t,e){return BigInt(t)!=BigInt(e)},lt:function(t,e){return BigInt(t)BigInt(e)},leq:function(t,e){return BigInt(t)<=BigInt(e)},geq:function(t,e){return BigInt(t)>=BigInt(e)},band:function(t,e){return BigInt(t)&BigInt(e)},bor:function(t,e){return BigInt(t)|BigInt(e)},bxor:function(t,e){return BigInt(t)^BigInt(e)},land:function(t,e){return BigInt(t)&&BigInt(e)},lor:function(t,e){return BigInt(t)||BigInt(e)},lnot:function(t){return!BigInt(t)}}),s="undefined"!=typeof globalThis?globalThis:"undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof self?self:{};function d(t){var e={exports:{}};return t(e,e.exports),e.exports}var u=d((function(t){var e=function(t){var a=1e7,i=9007199254740992,o=g(i),n="0123456789abcdefghijklmnopqrstuvwxyz",r="function"==typeof BigInt;function l(t,e,a,i){return void 0===t?l[0]:void 0!==e&&(10!=+e||a)?K(t,e,a,i):Z(t)}function c(t,e){this.value=t,this.sign=e,this.isSmall=!1}function s(t){this.value=t,this.sign=t<0,this.isSmall=!0}function d(t){this.value=t}function u(t){return-i0?Math.floor(t):Math.ceil(t)}function m(t,e){var i,o,n=t.length,r=e.length,l=new Array(n),c=0,s=a;for(o=0;o=s?1:0,l[o]=i-c*s;for(;o0&&l.push(c),l}function L(t,e){return t.length>=e.length?m(t,e):m(e,t)}function w(t,e){var i,o,n=t.length,r=new Array(n),l=a;for(o=0;o0;)r[o++]=e%l,e=Math.floor(e/l);return r}function A(t,e){var i,o,n=t.length,r=e.length,l=new Array(n),c=0,s=a;for(i=0;i0;)r[o++]=c%l,c=Math.floor(c/l);return r}function C(t,e){for(var a=[];e-- >0;)a.push(0);return a.concat(t)}function F(t,e){var a=Math.max(t.length,e.length);if(a<=30)return y(t,e);a=Math.ceil(a/2);var i=t.slice(a),o=t.slice(0,a),n=e.slice(a),r=e.slice(0,a),l=F(o,r),c=F(i,n),s=F(L(o,i),L(r,n)),d=L(L(l,C(A(A(s,l),c),a)),C(c,2*a));return _(d),d}function x(t,e,i){return new c(t=0;--a)o=(n=1e7*o+t[a])-(i=h(n/e))*e,l[a]=0|i;return[l,0|o]}function B(t,e){var i,o=Z(e);if(r)return[new d(t.value/o.value),new d(t.value%o.value)];var n,u=t.value,m=o.value;if(0===m)throw new Error("Cannot divide by zero");if(t.isSmall)return o.isSmall?[new s(h(u/m)),new s(u%m)]:[l[0],t];if(o.isSmall){if(1===m)return[t,l[0]];if(-1==m)return[t.negate(),l[0]];var L=Math.abs(m);if(L=0;o--){for(i=g-1,L[o+u]!==h&&(i=Math.floor((L[o+u]*g+L[o+u-1])/h)),n=0,r=0,c=w.length,l=0;ls&&(n=(n+1)*g),i=Math.ceil(n/r);do{if(S(l=I(e,i),u)<=0)break;i--}while(i);d.push(i),u=A(u,l)}return d.reverse(),[f(d),f(u)]}(u,m),n=i[0];var y=t.sign!==o.sign,C=i[1],F=t.sign;return"number"==typeof n?(y&&(n=-n),n=new s(n)):n=new c(n,y),"number"==typeof C?(F&&(C=-C),C=new s(C)):C=new c(C,F),[n,C]}function S(t,e){if(t.length!==e.length)return t.length>e.length?1:-1;for(var a=t.length-1;a>=0;a--)if(t[a]!==e[a])return t[a]>e[a]?1:-1;return 0}function G(t){var e=t.abs();return!e.isUnit()&&(!!(e.equals(2)||e.equals(3)||e.equals(5))||!(e.isEven()||e.isDivisibleBy(3)||e.isDivisibleBy(5))&&(!!e.lesser(49)||void 0))}function P(t,a){for(var i,o,n,r=t.prev(),l=r,c=0;l.isEven();)l=l.divide(2),c++;t:for(o=0;o=0?i=A(t,e):(i=A(e,t),a=!a),"number"==typeof(i=f(i))?(a&&(i=-i),new s(i)):new c(i,a)}(a,i,this.sign)},c.prototype.minus=c.prototype.subtract,s.prototype.subtract=function(t){var e=Z(t),a=this.value;if(a<0!==e.sign)return this.add(e.negate());var i=e.value;return e.isSmall?new s(a-i):b(i,Math.abs(a),a>=0)},s.prototype.minus=s.prototype.subtract,d.prototype.subtract=function(t){return new d(this.value-Z(t).value)},d.prototype.minus=d.prototype.subtract,c.prototype.negate=function(){return new c(this.value,!this.sign)},s.prototype.negate=function(){var t=this.sign,e=new s(-this.value);return e.sign=!t,e},d.prototype.negate=function(){return new d(-this.value)},c.prototype.abs=function(){return new c(this.value,!1)},s.prototype.abs=function(){return new s(Math.abs(this.value))},d.prototype.abs=function(){return new d(this.value>=0?this.value:-this.value)},c.prototype.multiply=function(t){var e,i,o,n=Z(t),r=this.value,s=n.value,d=this.sign!==n.sign;if(n.isSmall){if(0===s)return l[0];if(1===s)return this;if(-1===s)return this.negate();if((e=Math.abs(s))0?F(r,s):y(r,s),d)},c.prototype.times=c.prototype.multiply,s.prototype._multiplyBySmall=function(t){return u(t.value*this.value)?new s(t.value*this.value):x(Math.abs(t.value),g(Math.abs(this.value)),this.sign!==t.sign)},c.prototype._multiplyBySmall=function(t){return 0===t.value?l[0]:1===t.value?this:-1===t.value?this.negate():x(Math.abs(t.value),this.value,this.sign!==t.sign)},s.prototype.multiply=function(t){return Z(t)._multiplyBySmall(this)},s.prototype.times=s.prototype.multiply,d.prototype.multiply=function(t){return new d(this.value*Z(t).value)},d.prototype.times=d.prototype.multiply,c.prototype.square=function(){return new c(v(this.value),!1)},s.prototype.square=function(){var t=this.value*this.value;return u(t)?new s(t):new c(v(g(Math.abs(this.value))),!1)},d.prototype.square=function(t){return new d(this.value*this.value)},c.prototype.divmod=function(t){var e=B(this,t);return{quotient:e[0],remainder:e[1]}},d.prototype.divmod=s.prototype.divmod=c.prototype.divmod,c.prototype.divide=function(t){return B(this,t)[0]},d.prototype.over=d.prototype.divide=function(t){return new d(this.value/Z(t).value)},s.prototype.over=s.prototype.divide=c.prototype.over=c.prototype.divide,c.prototype.mod=function(t){return B(this,t)[1]},d.prototype.mod=d.prototype.remainder=function(t){return new d(this.value%Z(t).value)},s.prototype.remainder=s.prototype.mod=c.prototype.remainder=c.prototype.mod,c.prototype.pow=function(t){var e,a,i,o=Z(t),n=this.value,r=o.value;if(0===r)return l[1];if(0===n)return l[0];if(1===n)return l[1];if(-1===n)return o.isEven()?l[1]:l[-1];if(o.sign)return l[0];if(!o.isSmall)throw new Error("The exponent "+o.toString()+" is too large.");if(this.isSmall&&u(e=Math.pow(n,r)))return new s(h(e));for(a=this,i=l[1];!0&r&&(i=i.times(a),--r),0!==r;)r/=2,a=a.square();return i},s.prototype.pow=c.prototype.pow,d.prototype.pow=function(t){var e=Z(t),a=this.value,i=e.value,o=BigInt(0),n=BigInt(1),r=BigInt(2);if(i===o)return l[1];if(a===o)return l[0];if(a===n)return l[1];if(a===BigInt(-1))return e.isEven()?l[1]:l[-1];if(e.isNegative())return new d(o);for(var c=this,s=l[1];(i&n)===n&&(s=s.times(c),--i),i!==o;)i/=r,c=c.square();return s},c.prototype.modPow=function(t,e){if(t=Z(t),(e=Z(e)).isZero())throw new Error("Cannot take modPow with modulus 0");var a=l[1],i=this.mod(e);for(t.isNegative()&&(t=t.multiply(l[-1]),i=i.modInv(e));t.isPositive();){if(i.isZero())return l[0];t.isOdd()&&(a=a.multiply(i).mod(e)),t=t.divide(2),i=i.square().mod(e)}return a},d.prototype.modPow=s.prototype.modPow=c.prototype.modPow,c.prototype.compareAbs=function(t){var e=Z(t),a=this.value,i=e.value;return e.isSmall?1:S(a,i)},s.prototype.compareAbs=function(t){var e=Z(t),a=Math.abs(this.value),i=e.value;return e.isSmall?a===(i=Math.abs(i))?0:a>i?1:-1:-1},d.prototype.compareAbs=function(t){var e=this.value,a=Z(t).value;return(e=e>=0?e:-e)===(a=a>=0?a:-a)?0:e>a?1:-1},c.prototype.compare=function(t){if(t===1/0)return-1;if(t===-1/0)return 1;var e=Z(t),a=this.value,i=e.value;return this.sign!==e.sign?e.sign?1:-1:e.isSmall?this.sign?-1:1:S(a,i)*(this.sign?-1:1)},c.prototype.compareTo=c.prototype.compare,s.prototype.compare=function(t){if(t===1/0)return-1;if(t===-1/0)return 1;var e=Z(t),a=this.value,i=e.value;return e.isSmall?a==i?0:a>i?1:-1:a<0!==e.sign?a<0?-1:1:a<0?1:-1},s.prototype.compareTo=s.prototype.compare,d.prototype.compare=function(t){if(t===1/0)return-1;if(t===-1/0)return 1;var e=this.value,a=Z(t).value;return e===a?0:e>a?1:-1},d.prototype.compareTo=d.prototype.compare,c.prototype.equals=function(t){return 0===this.compare(t)},d.prototype.eq=d.prototype.equals=s.prototype.eq=s.prototype.equals=c.prototype.eq=c.prototype.equals,c.prototype.notEquals=function(t){return 0!==this.compare(t)},d.prototype.neq=d.prototype.notEquals=s.prototype.neq=s.prototype.notEquals=c.prototype.neq=c.prototype.notEquals,c.prototype.greater=function(t){return this.compare(t)>0},d.prototype.gt=d.prototype.greater=s.prototype.gt=s.prototype.greater=c.prototype.gt=c.prototype.greater,c.prototype.lesser=function(t){return this.compare(t)<0},d.prototype.lt=d.prototype.lesser=s.prototype.lt=s.prototype.lesser=c.prototype.lt=c.prototype.lesser,c.prototype.greaterOrEquals=function(t){return this.compare(t)>=0},d.prototype.geq=d.prototype.greaterOrEquals=s.prototype.geq=s.prototype.greaterOrEquals=c.prototype.geq=c.prototype.greaterOrEquals,c.prototype.lesserOrEquals=function(t){return this.compare(t)<=0},d.prototype.leq=d.prototype.lesserOrEquals=s.prototype.leq=s.prototype.lesserOrEquals=c.prototype.leq=c.prototype.lesserOrEquals,c.prototype.isEven=function(){return 0==(1&this.value[0])},s.prototype.isEven=function(){return 0==(1&this.value)},d.prototype.isEven=function(){return(this.value&BigInt(1))===BigInt(0)},c.prototype.isOdd=function(){return 1==(1&this.value[0])},s.prototype.isOdd=function(){return 1==(1&this.value)},d.prototype.isOdd=function(){return(this.value&BigInt(1))===BigInt(1)},c.prototype.isPositive=function(){return!this.sign},s.prototype.isPositive=function(){return this.value>0},d.prototype.isPositive=s.prototype.isPositive,c.prototype.isNegative=function(){return this.sign},s.prototype.isNegative=function(){return this.value<0},d.prototype.isNegative=s.prototype.isNegative,c.prototype.isUnit=function(){return!1},s.prototype.isUnit=function(){return 1===Math.abs(this.value)},d.prototype.isUnit=function(){return this.abs().value===BigInt(1)},c.prototype.isZero=function(){return!1},s.prototype.isZero=function(){return 0===this.value},d.prototype.isZero=function(){return this.value===BigInt(0)},c.prototype.isDivisibleBy=function(t){var e=Z(t);return!e.isZero()&&(!!e.isUnit()||(0===e.compareAbs(2)?this.isEven():this.mod(e).isZero()))},d.prototype.isDivisibleBy=s.prototype.isDivisibleBy=c.prototype.isDivisibleBy,c.prototype.isPrime=function(a){var i=G(this);if(i!==t)return i;var o=this.abs(),n=o.bitLength();if(n<=64)return P(o,[2,3,5,7,11,13,17,19,23,29,31,37]);for(var r=Math.log(2)*n.toJSNumber(),l=Math.ceil(!0===a?2*Math.pow(r,2):r),c=[],s=0;s-i?new s(t-1):new c(o,!0)},d.prototype.prev=function(){return new d(this.value-BigInt(1))};for(var O=[1];2*O[O.length-1]<=a;)O.push(2*O[O.length-1]);var U=O.length,z=O[U-1];function q(t){return Math.abs(t)<=a}function Q(t,a,i){a=Z(a);for(var o=t.isNegative(),n=a.isNegative(),r=o?t.not():t,l=n?a.not():a,c=0,s=0,d=null,u=null,g=[];!r.isZero()||!l.isZero();)c=(d=B(r,z))[1].toJSNumber(),o&&(c=z-1-c),s=(u=B(l,z))[1].toJSNumber(),n&&(s=z-1-s),r=d[0],l=u[0],g.push(i(c,s));for(var f=0!==i(o?1:0,n?1:0)?e(-1):e(0),_=g.length-1;_>=0;_-=1)f=f.multiply(z).add(e(g[_]));return f}c.prototype.shiftLeft=function(t){var e=Z(t).toJSNumber();if(!q(e))throw new Error(String(e)+" is too large for shifting.");if(e<0)return this.shiftRight(-e);var a=this;if(a.isZero())return a;for(;e>=U;)a=a.multiply(z),e-=U-1;return a.multiply(O[e])},d.prototype.shiftLeft=s.prototype.shiftLeft=c.prototype.shiftLeft,c.prototype.shiftRight=function(t){var e,a=Z(t).toJSNumber();if(!q(a))throw new Error(String(a)+" is too large for shifting.");if(a<0)return this.shiftLeft(-a);for(var i=this;a>=U;){if(i.isZero()||i.isNegative()&&i.isUnit())return i;i=(e=B(i,z))[1].isNegative()?e[0].prev():e[0],a-=U-1}return(e=B(i,O[a]))[1].isNegative()?e[0].prev():e[0]},d.prototype.shiftRight=s.prototype.shiftRight=c.prototype.shiftRight,c.prototype.not=function(){return this.negate().prev()},d.prototype.not=s.prototype.not=c.prototype.not,c.prototype.and=function(t){return Q(this,t,(function(t,e){return t&e}))},d.prototype.and=s.prototype.and=c.prototype.and,c.prototype.or=function(t){return Q(this,t,(function(t,e){return t|e}))},d.prototype.or=s.prototype.or=c.prototype.or,c.prototype.xor=function(t){return Q(this,t,(function(t,e){return t^e}))},d.prototype.xor=s.prototype.xor=c.prototype.xor;var M=1<<30;function k(t){var e=t.value,i="number"==typeof e?e|M:"bigint"==typeof e?e|BigInt(M):e[0]+e[1]*a|1073758208;return i&-i}function T(t,a){if(a.compareTo(t)<=0){var i=T(t,a.square(a)),o=i.p,n=i.e,r=o.multiply(a);return r.compareTo(t)<=0?{p:r,e:2*n+1}:{p:o,e:2*n}}return{p:e(1),e:0}}function R(t,e){return t=Z(t),e=Z(e),t.greater(e)?t:e}function N(t,e){return t=Z(t),e=Z(e),t.lesser(e)?t:e}function D(t,e){if(t=Z(t).abs(),e=Z(e).abs(),t.equals(e))return t;if(t.isZero())return e;if(e.isZero())return t;for(var a,i,o=l[1];t.isEven()&&e.isEven();)a=N(k(t),k(e)),t=t.divide(a),e=e.divide(a),o=o.multiply(a);for(;t.isEven();)t=t.divide(k(t));do{for(;e.isEven();)e=e.divide(k(e));t.greater(e)&&(i=e,e=t,t=i),e=e.subtract(t)}while(!e.isZero());return o.isUnit()?t:t.multiply(o)}c.prototype.bitLength=function(){var t=this;return t.compareTo(e(0))<0&&(t=t.negate().subtract(e(1))),0===t.compareTo(e(0))?e(0):e(T(t,e(2)).e).add(e(1))},d.prototype.bitLength=s.prototype.bitLength=c.prototype.bitLength;var K=function(t,e,a,i){a=a||n,t=String(t),i||(t=t.toLowerCase(),a=a.toLowerCase());var o,r=t.length,l=Math.abs(e),c={};for(o=0;o=l)){if("1"===u&&1===l)continue;throw new Error(u+" is not a valid digit in base "+e+".")}}e=Z(e);var s=[],d="-"===t[0];for(o=d?1:0;o"!==t[o]&&o=0;i--)o=o.add(t[i].times(n)),n=n.times(e);return a?o.negate():o}function j(t,a){if((a=e(a)).isZero()){if(t.isZero())return{value:[0],isNegative:!1};throw new Error("Cannot convert nonzero numbers to base 0.")}if(a.equals(-1)){if(t.isZero())return{value:[0],isNegative:!1};if(t.isNegative())return{value:[].concat.apply([],Array.apply(null,Array(-t.toJSNumber())).map(Array.prototype.valueOf,[1,0])),isNegative:!1};var i=Array.apply(null,Array(t.toJSNumber()-1)).map(Array.prototype.valueOf,[0,1]);return i.unshift([1]),{value:[].concat.apply([],i),isNegative:!1}}var o=!1;if(t.isNegative()&&a.isPositive()&&(o=!0,t=t.abs()),a.isUnit())return t.isZero()?{value:[0],isNegative:!1}:{value:Array.apply(null,Array(t.toJSNumber())).map(Number.prototype.valueOf,1),isNegative:o};for(var n,r=[],l=t;l.isNegative()||l.compareAbs(a)>=0;){n=l.divmod(a),l=n.quotient;var c=n.remainder;c.isNegative()&&(c=a.minus(c).abs(),l=l.next()),r.push(c.toJSNumber())}return r.push(l.toJSNumber()),{value:r.reverse(),isNegative:o}}function H(t,e,a){var i=j(t,e);return(i.isNegative?"-":"")+i.value.map((function(t){return function(t,e){return t<(e=e||n).length?e[t]:"<"+t+">"}(t,a)})).join("")}function $(t){if(u(+t)){var e=+t;if(e===h(e))return r?new d(BigInt(e)):new s(e);throw new Error("Invalid integer: "+t)}var a="-"===t[0];a&&(t=t.slice(1));var i=t.split(/e/i);if(i.length>2)throw new Error("Invalid integer: "+i.join("e"));if(2===i.length){var o=i[1];if("+"===o[0]&&(o=o.slice(1)),(o=+o)!==h(o)||!u(o))throw new Error("Invalid integer: "+o+" is not a valid exponent.");var n=i[0],l=n.indexOf(".");if(l>=0&&(o-=n.length-l-1,n=n.slice(0,l)+n.slice(l+1)),o<0)throw new Error("Cannot include negative exponent part for integers");t=n+=new Array(o+1).join("0")}if(!/^([0-9][0-9]*)$/.test(t))throw new Error("Invalid integer: "+t);if(r)return new d(BigInt(a?"-"+t:t));for(var g=[],f=t.length,p=f-7;f>0;)g.push(+t.slice(p,f)),(p-=7)<0&&(p=0),f-=7;return _(g),new c(g,a)}function Z(t){return"number"==typeof t?function(t){if(r)return new d(BigInt(t));if(u(t)){if(t!==h(t))throw new Error(t+" is not an integer.");return new s(t)}return $(t.toString())}(t):"string"==typeof t?$(t):"bigint"==typeof t?new d(t):t}c.prototype.toArray=function(t){return j(this,t)},s.prototype.toArray=function(t){return j(this,t)},d.prototype.toArray=function(t){return j(this,t)},c.prototype.toString=function(e,a){if(e===t&&(e=10),10!==e)return H(this,e,a);for(var i,o=this.value,n=o.length,r=String(o[--n]);--n>=0;)i=String(o[n]),r+="0000000".slice(i.length)+i;return(this.sign?"-":"")+r},s.prototype.toString=function(e,a){return e===t&&(e=10),10!=e?H(this,e,a):String(this.value)},d.prototype.toString=s.prototype.toString,d.prototype.toJSON=c.prototype.toJSON=s.prototype.toJSON=function(){return this.toString()},c.prototype.valueOf=function(){return parseInt(this.toString(),10)},c.prototype.toJSNumber=c.prototype.valueOf,s.prototype.valueOf=function(){return this.value},s.prototype.toJSNumber=s.prototype.valueOf,d.prototype.valueOf=d.prototype.toJSNumber=function(){return parseInt(this.toString(),10)};for(var Y=0;Y<1e3;Y++)l[Y]=Z(Y),Y>0&&(l[-Y]=Z(-Y));return l.one=l[1],l.zero=l[0],l.minusOne=l[-1],l.max=R,l.min=N,l.gcd=D,l.lcm=function(t,e){return t=Z(t).abs(),e=Z(e).abs(),t.divide(D(t,e)).multiply(e)},l.isInstance=function(t){return t instanceof c||t instanceof s||t instanceof d},l.randBetween=function(t,e,i){t=Z(t),e=Z(e);var o=i||Math.random,n=N(t,e),r=R(t,e).subtract(n).add(1);if(r.isSmall)return n.add(Math.floor(o()*r));for(var c=j(r,a).value,s=[],d=!0,u=0;u>5);for(let t=0;t>5);for(let t=0;to[o.length-e-1]=t.toString(16).padStart(8,"0"))),A.fromString(o.join(""),16)},A.fromRprBE=function(t,e,a){a=a||t.byteLength,e=e||0;const i=new DataView(t.buffer,t.byteOffset+e,a),o=new Array(a/4);for(let t=0;t>=1;return a}function pt(t,e,a){if(U(a))return t.one;const i=R(a);if(0==i.legth)return t.one;let o=e;for(let a=i.length-2;a>=0;a--)o=t.square(o),i[a]&&(o=t.mul(o,e));return o}function ht(t){if(t.m%2==1)if(tt(X(t.p,4),1))if(tt(X(t.p,8),1))if(tt(X(t.p,16),1))!function(t){t.sqrt_q=Z(t.p,t.m),t.sqrt_s=0,t.sqrt_t=V(t.sqrt_q,1);for(;!k(t.sqrt_t);)t.sqrt_s=t.sqrt_s+1,t.sqrt_t=W(t.sqrt_t,2);let e=t.one;for(;t.eq(e,t.one);){const a=t.random();t.sqrt_z=t.pow(a,t.sqrt_t),e=t.pow(t.sqrt_z,2**(t.sqrt_s-1))}t.sqrt_tm1d2=W(V(t.sqrt_t,1),2),t.sqrt=function(t){const e=this;if(e.isZero(t))return e.zero;let a=e.pow(t,e.sqrt_tm1d2);const i=e.pow(e.mul(e.square(a),t),2**(e.sqrt_s-1));if(e.eq(i,e.negone))return null;let o=e.sqrt_s,n=e.mul(t,a),r=e.mul(n,a),l=e.sqrt_z;for(;!e.eq(r,e.one);){let t=e.square(r),i=1;for(;!e.eq(t,e.one);)t=e.square(t),i++;a=l;for(let t=0;t>>0,t[o]=(t[o]^t[e])>>>0,t[o]=(t[o]<<16|t[o]>>>16&65535)>>>0,t[i]=t[i]+t[o]>>>0,t[a]=(t[a]^t[i])>>>0,t[a]=(t[a]<<12|t[a]>>>20&4095)>>>0,t[e]=t[e]+t[a]>>>0,t[o]=(t[o]^t[e])>>>0,t[o]=(t[o]<<8|t[o]>>>24&255)>>>0,t[i]=t[i]+t[o]>>>0,t[a]=(t[a]^t[i])>>>0,t[a]=(t[a]<<7|t[a]>>>25&127)>>>0}class Lt{constructor(t){t=t||[0,0,0,0,0,0,0,0],this.state=[1634760805,857760878,2036477234,1797285236,t[0],t[1],t[2],t[3],t[4],t[5],t[6],t[7],0,0,0,0],this.idx=16,this.buff=new Array(16)}nextU32(){return 16==this.idx&&this.update(),this.buff[this.idx++]}nextU64(){return K(H(this.nextU32(),4294967296),this.nextU32())}nextBool(){return 1==(1&this.nextU32())}update(){for(let t=0;t<16;t++)this.buff[t]=this.state[t];for(let e=0;e<10;e++)mt(t=this.buff,0,4,8,12),mt(t,1,5,9,13),mt(t,2,6,10,14),mt(t,3,7,11,15),mt(t,0,5,10,15),mt(t,1,6,11,12),mt(t,2,7,8,13),mt(t,3,4,9,14);var t;for(let t=0;t<16;t++)this.buff[t]=this.buff[t]+this.state[t]>>>0;this.idx=0,this.state[12]=this.state[12]+1>>>0,0==this.state[12]&&(this.state[13]=this.state[13]+1>>>0,0==this.state[13]&&(this.state[14]=this.state[14]+1>>>0,0==this.state[14]&&(this.state[15]=this.state[15]+1>>>0)))}}var wt={};function At(t){let e=new Uint8Array(t);if(void 0!==globalThis.crypto)globalThis.crypto.getRandomValues(e);else for(let a=0;a>>0;return e}let bt=null;function yt(){return bt||(bt=new Lt(function(){const t=At(32),e=new Uint32Array(t.buffer),a=[];for(let t=0;t<8;t++)a.push(e[t]);return a}()),bt)}class It{constructor(t){this.type="F1",this.one=BigInt(1),this.zero=BigInt(0),this.p=BigInt(t),this.m=1,this.negone=this.p-this.one,this.two=BigInt(2),this.half=this.p>>this.one,this.bitLength=P(this.p),this.mask=(this.one<>this.one;this.nqr=this.two;let a=this.pow(this.nqr,e);for(;!this.eq(a,this.negone);)this.nqr=this.nqr+this.one,a=this.pow(this.nqr,e);for(this.s=0,this.t=this.negone;(this.t&this.one)==this.zero;)this.s=this.s+1,this.t=this.t>>this.one;this.nqr_to_t=this.pow(this.nqr,this.t),ht(this)}e(t,e){let a;if(e?16==e&&(a=BigInt("0x"+t)):a=BigInt(t),a<0){let t=-a;return t>=this.p&&(t%=this.p),this.p-t}return a>=this.p?a%this.p:a}add(t,e){const a=t+e;return a>=this.p?a-this.p:a}sub(t,e){return t>=e?t-e:this.p-e+t}neg(t){return t?this.p-t:t}mul(t,e){return t*e%this.p}mulScalar(t,e){return t*this.e(e)%this.p}square(t){return t*t%this.p}eq(t,e){return t==e}neq(t,e){return t!=e}lt(t,e){return(t>this.half?t-this.p:t)<(e>this.half?e-this.p:e)}gt(t,e){return(t>this.half?t-this.p:t)>(e>this.half?e-this.p:e)}leq(t,e){return(t>this.half?t-this.p:t)<=(e>this.half?e-this.p:e)}geq(t,e){return(t>this.half?t-this.p:t)>=(e>this.half?e-this.p:e)}div(t,e){return this.mul(t,this.inv(e))}idiv(t,e){if(!e)throw new Error("Division by zero");return t/e}inv(t){if(!t)throw new Error("Division by zero");let e=this.zero,a=this.p,i=this.one,o=t%this.p;for(;o;){let t=a/o;[e,i]=[i,e-t*i],[a,o]=[o,a-t*o]}return e=this.p?a-this.p:a}bor(t,e){const a=(t|e)&this.mask;return a>=this.p?a-this.p:a}bxor(t,e){const a=(t^e)&this.mask;return a>=this.p?a-this.p:a}bnot(t){const e=t^this.mask;return e>=this.p?e-this.p:e}shl(t,e){if(Number(e)=this.p?a-this.p:a}{const a=this.p-e;return Number(a)>a:this.zero}}shr(t,e){if(Number(e)>e;{const a=this.p-e;if(Number(a)=this.p?e-this.p:e}return 0}}land(t,e){return t&&e?this.one:this.zero}lor(t,e){return t||e?this.one:this.zero}lnot(t){return t?this.zero:this.one}sqrt_old(t){if(t==this.zero)return this.zero;if(this.pow(t,this.negone>>this.one)!=this.one)return null;let e=this.s,a=this.nqr_to_t,i=this.pow(t,this.t),o=this.pow(t,this.add(this.t,this.one)>>this.one);for(;i!=this.one;){let t=this.square(i),n=1;for(;t!=this.one;)n++,t=this.square(t);let r=a;for(let t=0;tthis.p>>this.one&&(o=this.neg(o)),o}normalize(t,e){if((t=BigInt(t,e))<0){let e=-t;return e>=this.p&&(e%=this.p),this.p-e}return t>=this.p?t%this.p:t}random(){const t=2*this.bitLength/8;let e=this.zero;for(let a=0;athis.half){a="-"+(this.p-t).toString(e)}else a=t.toString(e);return a}isZero(t){return t==this.zero}fromRng(t){let e;do{e=this.zero;for(let a=0;a=this.p);return e=e*this.Ri%this.p,e}}class Ct{constructor(t){this.type="F1",this.one=u.one,this.zero=u.zero,this.p=u(t),this.m=1,this.negone=this.p.minus(u.one),this.two=u(2),this.half=this.p.shiftRight(1),this.bitLength=this.p.bitLength(),this.mask=u.one.shiftLeft(this.bitLength).minus(u.one),this.n64=Math.floor((this.bitLength-1)/64)+1,this.n32=2*this.n64,this.n8=8*this.n64,this.R=u.one.shiftLeft(64*this.n64),this.Ri=this.inv(this.R);const e=this.negone.shiftRight(this.one);this.nqr=this.two;let a=this.pow(this.nqr,e);for(;!a.equals(this.negone);)this.nqr=this.nqr.add(this.one),a=this.pow(this.nqr,e);for(this.s=this.zero,this.t=this.negone;!this.t.isOdd();)this.s=this.s.add(this.one),this.t=this.t.shiftRight(this.one);this.nqr_to_t=this.pow(this.nqr,this.t),ht(this)}e(t,e){const a=u(t,e);return this.normalize(a)}add(t,e){let a=t.add(e);return a.geq(this.p)&&(a=a.minus(this.p)),a}sub(t,e){return t.geq(e)?t.minus(e):this.p.minus(e.minus(t))}neg(t){return t.isZero()?t:this.p.minus(t)}mul(t,e){return t.times(e).mod(this.p)}mulScalar(t,e){return t.times(u(e)).mod(this.p)}square(t){return t.square().mod(this.p)}eq(t,e){return t.eq(e)}neq(t,e){return t.neq(e)}lt(t,e){const a=t.gt(this.half)?t.minus(this.p):t,i=e.gt(this.half)?e.minus(this.p):e;return a.lt(i)}gt(t,e){const a=t.gt(this.half)?t.minus(this.p):t,i=e.gt(this.half)?e.minus(this.p):e;return a.gt(i)}leq(t,e){const a=t.gt(this.half)?t.minus(this.p):t,i=e.gt(this.half)?e.minus(this.p):e;return a.leq(i)}geq(t,e){const a=t.gt(this.half)?t.minus(this.p):t,i=e.gt(this.half)?e.minus(this.p):e;return a.geq(i)}div(t,e){if(e.isZero())throw new Error("Division by zero");return t.times(e.modInv(this.p)).mod(this.p)}idiv(t,e){if(e.isZero())throw new Error("Division by zero");return t.divide(e)}inv(t){if(t.isZero())throw new Error("Division by zero");return t.modInv(this.p)}mod(t,e){return t.mod(e)}pow(t,e){return t.modPow(e,this.p)}exp(t,e){return t.modPow(e,this.p)}band(t,e){return t.and(e).and(this.mask).mod(this.p)}bor(t,e){return t.or(e).and(this.mask).mod(this.p)}bxor(t,e){return t.xor(e).and(this.mask).mod(this.p)}bnot(t){return t.xor(this.mask).mod(this.p)}shl(t,e){if(e.lt(this.bitLength))return t.shiftLeft(e).and(this.mask).mod(this.p);{const a=this.p.minus(e);return a.lt(this.bitLength)?this.shr(t,a):u.zero}}shr(t,e){if(e.lt(this.bitLength))return t.shiftRight(e);{const a=this.p.minus(e);return a.lt(this.bitLength)?this.shl(t,a):u.zero}}land(t,e){return t.isZero()||e.isZero()?u.zero:u.one}lor(t,e){return t.isZero()&&e.isZero()?u.zero:u.one}lnot(t){return t.isZero()?u.one:u.zero}sqrt_old(t){if(t.equals(this.zero))return this.zero;if(!this.pow(t,this.negone.shiftRight(this.one)).equals(this.one))return null;let e=parseInt(this.s),a=this.nqr_to_t,i=this.pow(t,this.t),o=this.pow(t,this.add(this.t,this.one).shiftRight(this.one));for(;!i.equals(this.one);){let t=this.square(i),n=1;for(;!t.equals(this.one);)n++,t=this.square(t);let r=a;for(let t=0;t>1&&i>1,t>>1)))),e.addCode(a.setLocal(c,a.i64_add(a.getLocal(c),a.i64_shr_u(a.getLocal(l),a.i64_const(32)))))),t>0&&(e.addCode(a.setLocal(l,a.i64_add(a.i64_and(a.getLocal(l),a.i64_const(4294967295)),a.i64_and(a.getLocal(s),a.i64_const(4294967295))))),e.addCode(a.setLocal(c,a.i64_add(a.i64_add(a.getLocal(c),a.i64_shr_u(a.getLocal(l),a.i64_const(32))),a.getLocal(d))))),e.addCode(a.i64_store32(a.getLocal("r"),4*t,a.getLocal(l))),e.addCode(a.setLocal(s,a.getLocal(c)),a.setLocal(d,a.i64_shr_u(a.getLocal(s),a.i64_const(32))))}e.addCode(a.i64_store32(a.getLocal("r"),4*o*2-4,a.getLocal(s)))}(),function(){const e=t.addFunction(i+"_squareOld");e.addParam("x","i32"),e.addParam("r","i32");const a=e.getCodeBuilder();e.addCode(a.call(i+"_mul",a.getLocal("x"),a.getLocal("x"),a.getLocal("r")))}(),function(){!function(){const e=t.addFunction(i+"__mul1");e.addParam("px","i32"),e.addParam("y","i64"),e.addParam("pr","i32"),e.addLocal("c","i64");const a=e.getCodeBuilder();e.addCode(a.setLocal("c",a.i64_mul(a.i64_load32_u(a.getLocal("px"),0,0),a.getLocal("y")))),e.addCode(a.i64_store32(a.getLocal("pr"),0,0,a.getLocal("c")));for(let t=1;t>e)),[...c.setLocal("b",c.i32_sub(c.getLocal("b"),c.i32_const(128>>e))),...c.call(i,c.getLocal("r"),s,c.getLocal("r"))]));return t}(),c.br_if(1,c.i32_eqz(c.getLocal("i"))),c.br(0))))},Gt=function(t,e){const a=8*t.modules[e].n64,i=t.addFunction(e+"_batchInverse");i.addParam("pIn","i32"),i.addParam("inStep","i32"),i.addParam("n","i32"),i.addParam("pOut","i32"),i.addParam("outStep","i32"),i.addLocal("itAux","i32"),i.addLocal("itIn","i32"),i.addLocal("itOut","i32"),i.addLocal("i","i32");const o=i.getCodeBuilder(),n=o.i32_const(t.alloc(a));i.addCode(o.setLocal("itAux",o.i32_load(o.i32_const(0))),o.i32_store(o.i32_const(0),o.i32_add(o.getLocal("itAux"),o.i32_mul(o.i32_add(o.getLocal("n"),o.i32_const(1)),o.i32_const(a))))),i.addCode(o.call(e+"_one",o.getLocal("itAux")),o.setLocal("itIn",o.getLocal("pIn")),o.setLocal("itAux",o.i32_add(o.getLocal("itAux"),o.i32_const(a))),o.setLocal("i",o.i32_const(0)),o.block(o.loop(o.br_if(1,o.i32_eq(o.getLocal("i"),o.getLocal("n"))),o.if(o.call(e+"_isZero",o.getLocal("itIn")),o.call(e+"_copy",o.i32_sub(o.getLocal("itAux"),o.i32_const(a)),o.getLocal("itAux")),o.call(e+"_mul",o.getLocal("itIn"),o.i32_sub(o.getLocal("itAux"),o.i32_const(a)),o.getLocal("itAux"))),o.setLocal("itIn",o.i32_add(o.getLocal("itIn"),o.getLocal("inStep"))),o.setLocal("itAux",o.i32_add(o.getLocal("itAux"),o.i32_const(a))),o.setLocal("i",o.i32_add(o.getLocal("i"),o.i32_const(1))),o.br(0))),o.setLocal("itIn",o.i32_sub(o.getLocal("itIn"),o.getLocal("inStep"))),o.setLocal("itAux",o.i32_sub(o.getLocal("itAux"),o.i32_const(a))),o.setLocal("itOut",o.i32_add(o.getLocal("pOut"),o.i32_mul(o.i32_sub(o.getLocal("n"),o.i32_const(1)),o.getLocal("outStep")))),o.call(e+"_inverse",o.getLocal("itAux"),o.getLocal("itAux")),o.block(o.loop(o.br_if(1,o.i32_eqz(o.getLocal("i"))),o.if(o.call(e+"_isZero",o.getLocal("itIn")),[...o.call(e+"_copy",o.getLocal("itAux"),o.i32_sub(o.getLocal("itAux"),o.i32_const(a))),...o.call(e+"_zero",o.getLocal("itOut"))],[...o.call(e+"_copy",o.i32_sub(o.getLocal("itAux"),o.i32_const(a)),n),...o.call(e+"_mul",o.getLocal("itAux"),o.getLocal("itIn"),o.i32_sub(o.getLocal("itAux"),o.i32_const(a))),...o.call(e+"_mul",o.getLocal("itAux"),n,o.getLocal("itOut"))]),o.setLocal("itIn",o.i32_sub(o.getLocal("itIn"),o.getLocal("inStep"))),o.setLocal("itOut",o.i32_sub(o.getLocal("itOut"),o.getLocal("outStep"))),o.setLocal("itAux",o.i32_sub(o.getLocal("itAux"),o.i32_const(a))),o.setLocal("i",o.i32_sub(o.getLocal("i"),o.i32_const(1))),o.br(0)))),i.addCode(o.i32_store(o.i32_const(0),o.getLocal("itAux")))};var Pt=function(t,e,a,i,o,n){void 0===n&&(n=i=r&&e.addCode(a.i64_store32(a.getLocal("r"),4*(t-r),a.getLocal(p))),[p,h]=[h,p],e.addCode(a.setLocal(h,a.i64_shr_u(a.getLocal(p),a.i64_const(32))))}e.addCode(a.i64_store32(a.getLocal("r"),4*r-4,a.getLocal(p))),e.addCode(a.if(a.i32_wrap_i64(a.getLocal(h)),a.drop(a.call(s+"_sub",a.getLocal("r"),a.i32_const(d),a.getLocal("r"))),a.if(a.call(s+"_gte",a.getLocal("r"),a.i32_const(d)),a.drop(a.call(s+"_sub",a.getLocal("r"),a.i32_const(d),a.getLocal("r"))))))}(),function(){const e=t.addFunction(c+"_square");e.addParam("x","i32"),e.addParam("r","i32"),e.addLocal("c0","i64"),e.addLocal("c1","i64"),e.addLocal("c0_old","i64"),e.addLocal("c1_old","i64"),e.addLocal("np32","i64");for(let t=0;t>1&&i>1,t>>1)))),e.addCode(a.setLocal(p,a.i64_add(a.getLocal(p),a.i64_shr_u(a.getLocal(_),a.i64_const(32)))))),t>0&&(e.addCode(a.setLocal(_,a.i64_add(a.i64_and(a.getLocal(_),a.i64_const(4294967295)),a.i64_and(a.getLocal(h),a.i64_const(4294967295))))),e.addCode(a.setLocal(p,a.i64_add(a.i64_add(a.getLocal(p),a.i64_shr_u(a.getLocal(_),a.i64_const(32))),a.getLocal(m)))));for(let i=Math.max(1,t-r+1);i<=t&&i=r&&e.addCode(a.i64_store32(a.getLocal("r"),4*(t-r),a.getLocal(_))),e.addCode(a.setLocal(h,a.getLocal(p)),a.setLocal(m,a.i64_shr_u(a.getLocal(h),a.i64_const(32))))}e.addCode(a.i64_store32(a.getLocal("r"),4*r-4,a.getLocal(h))),e.addCode(a.if(a.i32_wrap_i64(a.getLocal(m)),a.drop(a.call(s+"_sub",a.getLocal("r"),a.i32_const(d),a.getLocal("r"))),a.if(a.call(s+"_gte",a.getLocal("r"),a.i32_const(d)),a.drop(a.call(s+"_sub",a.getLocal("r"),a.i32_const(d),a.getLocal("r"))))))}(),function(){const e=t.addFunction(c+"_squareOld");e.addParam("x","i32"),e.addParam("r","i32");const a=e.getCodeBuilder();e.addCode(a.call(c+"_mul",a.getLocal("x"),a.getLocal("x"),a.getLocal("r")))}(),function(){const e=t.addFunction(c+"_toMontgomery");e.addParam("x","i32"),e.addParam("r","i32");const a=e.getCodeBuilder();e.addCode(a.call(c+"_mul",a.getLocal("x"),a.i32_const(g),a.getLocal("r")))}(),function(){const e=t.alloc(2*l),a=t.addFunction(c+"_fromMontgomery");a.addParam("x","i32"),a.addParam("r","i32");const i=a.getCodeBuilder();a.addCode(i.call(s+"_copy",i.getLocal("x"),i.i32_const(e))),a.addCode(i.call(s+"_zero",i.i32_const(e+l))),a.addCode(i.call(c+"_mReduct",i.i32_const(e),i.getLocal("r")))}(),function(){const e=t.addFunction(c+"_isNegative");e.addParam("x","i32"),e.setReturnType("i32");const a=e.getCodeBuilder(),i=a.i32_const(t.alloc(l));e.addCode(a.call(c+"_fromMontgomery",a.getLocal("x"),i),a.call(s+"_gte",i,a.i32_const(w)))}(),function(){const e=t.addFunction(c+"_sign");e.addParam("x","i32"),e.setReturnType("i32");const a=e.getCodeBuilder(),i=a.i32_const(t.alloc(l));e.addCode(a.if(a.call(s+"_isZero",a.getLocal("x")),a.ret(a.i32_const(0))),a.call(c+"_fromMontgomery",a.getLocal("x"),i),a.if(a.call(s+"_gte",i,a.i32_const(w)),a.ret(a.i32_const(-1))),a.ret(a.i32_const(1)))}(),function(){const e=t.addFunction(c+"_inverse");e.addParam("x","i32"),e.addParam("r","i32");const a=e.getCodeBuilder();e.addCode(a.call(c+"_fromMontgomery",a.getLocal("x"),a.getLocal("r"))),e.addCode(a.call(s+"_inverseMod",a.getLocal("r"),a.i32_const(d),a.getLocal("r"))),e.addCode(a.call(c+"_toMontgomery",a.getLocal("r"),a.getLocal("r")))}(),function(){const e=t.addFunction(c+"_one");e.addParam("pr","i32");const a=e.getCodeBuilder();e.addCode(a.call(s+"_copy",a.i32_const(f),a.getLocal("pr")))}(),function(){const e=t.addFunction(c+"_load");e.addParam("scalar","i32"),e.addParam("scalarLen","i32"),e.addParam("r","i32"),e.addLocal("p","i32"),e.addLocal("l","i32"),e.addLocal("i","i32"),e.addLocal("j","i32");const a=e.getCodeBuilder(),i=a.i32_const(t.alloc(l)),o=t.alloc(l),n=a.i32_const(o);e.addCode(a.call(s+"_zero",a.getLocal("r")),a.setLocal("i",a.i32_const(l)),a.setLocal("p",a.getLocal("scalar")),a.block(a.loop(a.br_if(1,a.i32_gt_u(a.getLocal("i"),a.getLocal("scalarLen"))),a.if(a.i32_eq(a.getLocal("i"),a.i32_const(l)),a.call(c+"_one",i),a.call(c+"_mul",i,a.i32_const(g),i)),a.call(c+"_mul",a.getLocal("p"),i,n),a.call(c+"_add",a.getLocal("r"),n,a.getLocal("r")),a.setLocal("p",a.i32_add(a.getLocal("p"),a.i32_const(l))),a.setLocal("i",a.i32_add(a.getLocal("i"),a.i32_const(l))),a.br(0))),a.setLocal("l",a.i32_rem_u(a.getLocal("scalarLen"),a.i32_const(l))),a.if(a.i32_eqz(a.getLocal("l")),a.ret([])),a.call(s+"_zero",n),a.setLocal("j",a.i32_const(0)),a.block(a.loop(a.br_if(1,a.i32_eq(a.getLocal("j"),a.getLocal("l"))),a.i32_store8(a.getLocal("j"),o,a.i32_load8_u(a.getLocal("p"))),a.setLocal("p",a.i32_add(a.getLocal("p"),a.i32_const(1))),a.setLocal("j",a.i32_add(a.getLocal("j"),a.i32_const(1))),a.br(0))),a.if(a.i32_eq(a.getLocal("i"),a.i32_const(l)),a.call(c+"_one",i),a.call(c+"_mul",i,a.i32_const(g),i)),a.call(c+"_mul",n,i,n),a.call(c+"_add",a.getLocal("r"),n,a.getLocal("r")))}(),function(){const e=t.addFunction(c+"_timesScalar");e.addParam("x","i32"),e.addParam("scalar","i32"),e.addParam("scalarLen","i32"),e.addParam("r","i32");const a=e.getCodeBuilder(),i=a.i32_const(t.alloc(l));e.addCode(a.call(c+"_load",a.getLocal("scalar"),a.getLocal("scalarLen"),i),a.call(c+"_toMontgomery",i,i),a.call(c+"_mul",a.getLocal("x"),i,a.getLocal("r")))}(),Gt(t,c),Pt(t,c+"_batchToMontgomery",c+"_toMontgomery",l,l),Pt(t,c+"_batchFromMontgomery",c+"_fromMontgomery",l,l),Pt(t,c+"_batchNeg",c+"_neg",l,l),Ot(t,c+"_batchAdd",c+"_add",l,l),Ot(t,c+"_batchSub",c+"_sub",l,l),Ot(t,c+"_batchMul",c+"_mul",l,l),t.exportFunction(c+"_add"),t.exportFunction(c+"_sub"),t.exportFunction(c+"_neg"),t.exportFunction(c+"_isNegative"),t.exportFunction(c+"_isOne"),t.exportFunction(c+"_sign"),t.exportFunction(c+"_mReduct"),t.exportFunction(c+"_mul"),t.exportFunction(c+"_square"),t.exportFunction(c+"_squareOld"),t.exportFunction(c+"_fromMontgomery"),t.exportFunction(c+"_toMontgomery"),t.exportFunction(c+"_inverse"),t.exportFunction(c+"_one"),t.exportFunction(c+"_load"),t.exportFunction(c+"_timesScalar"),St(t,c+"_exp",l,c+"_mul",c+"_square",s+"_copy",c+"_one"),t.exportFunction(c+"_exp"),t.exportFunction(c+"_batchInverse"),o.isPrime()&&(!function(){const e=t.addFunction(c+"_sqrt");e.addParam("n","i32"),e.addParam("r","i32"),e.addLocal("m","i32"),e.addLocal("i","i32"),e.addLocal("j","i32");const a=e.getCodeBuilder(),i=a.i32_const(f),o=a.i32_const(t.alloc(l)),n=a.i32_const(t.alloc(l)),r=a.i32_const(t.alloc(l)),s=a.i32_const(t.alloc(l)),d=a.i32_const(t.alloc(l));e.addCode(a.if(a.call(c+"_isZero",a.getLocal("n")),a.ret(a.call(c+"_zero",a.getLocal("r")))),a.setLocal("m",a.i32_const(b)),a.call(c+"_copy",a.i32_const(F),o),a.call(c+"_exp",a.getLocal("n"),a.i32_const(I),a.i32_const(l),n),a.call(c+"_exp",a.getLocal("n"),a.i32_const(v),a.i32_const(l),r),a.block(a.loop(a.br_if(1,a.call(c+"_eq",n,i)),a.call(c+"_square",n,s),a.setLocal("i",a.i32_const(1)),a.block(a.loop(a.br_if(1,a.call(c+"_eq",s,i)),a.call(c+"_square",s,s),a.setLocal("i",a.i32_add(a.getLocal("i"),a.i32_const(1))),a.br(0))),a.call(c+"_copy",o,d),a.setLocal("j",a.i32_sub(a.i32_sub(a.getLocal("m"),a.getLocal("i")),a.i32_const(1))),a.block(a.loop(a.br_if(1,a.i32_eqz(a.getLocal("j"))),a.call(c+"_square",d,d),a.setLocal("j",a.i32_sub(a.getLocal("j"),a.i32_const(1))),a.br(0))),a.setLocal("m",a.getLocal("i")),a.call(c+"_square",d,o),a.call(c+"_mul",n,o,n),a.call(c+"_mul",r,d,r),a.br(0))),a.if(a.call(c+"_isNegative",r),a.call(c+"_neg",r,a.getLocal("r")),a.call(c+"_copy",r,a.getLocal("r"))))}(),function(){const e=t.addFunction(c+"_isSquare");e.addParam("n","i32"),e.setReturnType("i32");const a=e.getCodeBuilder(),i=a.i32_const(f),o=a.i32_const(t.alloc(l));e.addCode(a.if(a.call(c+"_isZero",a.getLocal("n")),a.ret(a.i32_const(1))),a.call(c+"_exp",a.getLocal("n"),a.i32_const(m),a.i32_const(l),o),a.call(c+"_eq",o,i))}(),t.exportFunction(c+"_sqrt"),t.exportFunction(c+"_isSquare")),t.exportFunction(c+"_batchToMontgomery"),t.exportFunction(c+"_batchFromMontgomery"),c},zt=function(t,e,a,i,o){const n=u(e),r=Math.floor((n.minus(1).bitLength()-1)/64)+1,l=8*r,c=a||"f1";if(t.modules[c])return c;t.modules[c]={n64:r};const s=o||"int",d=Ut(t,n,i,s),g=t.modules[d].pR2,f=t.modules[d].pq,_=t.modules[d].pePlusOne;return function(){const e=t.alloc(l),a=t.addFunction(c+"_mul");a.addParam("x","i32"),a.addParam("y","i32"),a.addParam("r","i32");const i=a.getCodeBuilder();a.addCode(i.call(d+"_mul",i.getLocal("x"),i.getLocal("y"),i.i32_const(e))),a.addCode(i.call(d+"_mul",i.i32_const(e),i.i32_const(g),i.getLocal("r")))}(),function(){const e=t.addFunction(c+"_square");e.addParam("x","i32"),e.addParam("r","i32");const a=e.getCodeBuilder();e.addCode(a.call(c+"_mul",a.getLocal("x"),a.getLocal("x"),a.getLocal("r")))}(),function(){const e=t.addFunction(c+"_inverse");e.addParam("x","i32"),e.addParam("r","i32");const a=e.getCodeBuilder();e.addCode(a.call(s+"_inverseMod",a.getLocal("x"),a.i32_const(f),a.getLocal("r")))}(),function(){const e=t.addFunction(c+"_isNegative");e.addParam("x","i32"),e.setReturnType("i32");const a=e.getCodeBuilder();e.addCode(a.call(s+"_gte",a.getLocal("x"),a.i32_const(_)))}(),t.exportFunction(d+"_add",c+"_add"),t.exportFunction(d+"_sub",c+"_sub"),t.exportFunction(d+"_neg",c+"_neg"),t.exportFunction(c+"_mul"),t.exportFunction(c+"_square"),t.exportFunction(c+"_inverse"),t.exportFunction(c+"_isNegative"),t.exportFunction(d+"_copy",c+"_copy"),t.exportFunction(d+"_zero",c+"_zero"),t.exportFunction(d+"_one",c+"_one"),t.exportFunction(d+"_isZero",c+"_isZero"),t.exportFunction(d+"_eq",c+"_eq"),c},qt=function(t,e,a,i){if(t.modules[a])return a;const o=8*t.modules[i].n64,n=t.modules[i].q;return t.modules[a]={n64:2*t.modules[i].n64},function(){const e=t.addFunction(a+"_isZero");e.addParam("x","i32"),e.setReturnType("i32");const n=e.getCodeBuilder(),r=n.getLocal("x"),l=n.i32_add(n.getLocal("x"),n.i32_const(o));e.addCode(n.i32_and(n.call(i+"_isZero",r),n.call(i+"_isZero",l)))}(),function(){const e=t.addFunction(a+"_isOne");e.addParam("x","i32"),e.setReturnType("i32");const n=e.getCodeBuilder(),r=n.getLocal("x"),l=n.i32_add(n.getLocal("x"),n.i32_const(o));e.addCode(n.ret(n.i32_and(n.call(i+"_isOne",r),n.call(i+"_isZero",l))))}(),function(){const e=t.addFunction(a+"_zero");e.addParam("x","i32");const n=e.getCodeBuilder(),r=n.getLocal("x"),l=n.i32_add(n.getLocal("x"),n.i32_const(o));e.addCode(n.call(i+"_zero",r),n.call(i+"_zero",l))}(),function(){const e=t.addFunction(a+"_one");e.addParam("x","i32");const n=e.getCodeBuilder(),r=n.getLocal("x"),l=n.i32_add(n.getLocal("x"),n.i32_const(o));e.addCode(n.call(i+"_one",r),n.call(i+"_zero",l))}(),function(){const e=t.addFunction(a+"_copy");e.addParam("x","i32"),e.addParam("r","i32");const n=e.getCodeBuilder(),r=n.getLocal("x"),l=n.i32_add(n.getLocal("x"),n.i32_const(o)),c=n.getLocal("r"),s=n.i32_add(n.getLocal("r"),n.i32_const(o));e.addCode(n.call(i+"_copy",r,c),n.call(i+"_copy",l,s))}(),function(){const n=t.addFunction(a+"_mul");n.addParam("x","i32"),n.addParam("y","i32"),n.addParam("r","i32");const r=n.getCodeBuilder(),l=r.getLocal("x"),c=r.i32_add(r.getLocal("x"),r.i32_const(o)),s=r.getLocal("y"),d=r.i32_add(r.getLocal("y"),r.i32_const(o)),u=r.getLocal("r"),g=r.i32_add(r.getLocal("r"),r.i32_const(o)),f=r.i32_const(t.alloc(o)),_=r.i32_const(t.alloc(o)),p=r.i32_const(t.alloc(o)),h=r.i32_const(t.alloc(o));n.addCode(r.call(i+"_mul",l,s,f),r.call(i+"_mul",c,d,_),r.call(i+"_add",l,c,p),r.call(i+"_add",s,d,h),r.call(i+"_mul",p,h,p),r.call(e,_,u),r.call(i+"_add",f,u,u),r.call(i+"_add",f,_,g),r.call(i+"_sub",p,g,g))}(),function(){const e=t.addFunction(a+"_mul1");e.addParam("x","i32"),e.addParam("y","i32"),e.addParam("r","i32");const n=e.getCodeBuilder(),r=n.getLocal("x"),l=n.i32_add(n.getLocal("x"),n.i32_const(o)),c=n.getLocal("y"),s=n.getLocal("r"),d=n.i32_add(n.getLocal("r"),n.i32_const(o));e.addCode(n.call(i+"_mul",r,c,s),n.call(i+"_mul",l,c,d))}(),function(){const n=t.addFunction(a+"_square");n.addParam("x","i32"),n.addParam("r","i32");const r=n.getCodeBuilder(),l=r.getLocal("x"),c=r.i32_add(r.getLocal("x"),r.i32_const(o)),s=r.getLocal("r"),d=r.i32_add(r.getLocal("r"),r.i32_const(o)),u=r.i32_const(t.alloc(o)),g=r.i32_const(t.alloc(o)),f=r.i32_const(t.alloc(o)),_=r.i32_const(t.alloc(o));n.addCode(r.call(i+"_mul",l,c,u),r.call(i+"_add",l,c,g),r.call(e,c,f),r.call(i+"_add",l,f,f),r.call(e,u,_),r.call(i+"_add",_,u,_),r.call(i+"_mul",g,f,s),r.call(i+"_sub",s,_,s),r.call(i+"_add",u,u,d))}(),function(){const e=t.addFunction(a+"_add");e.addParam("x","i32"),e.addParam("y","i32"),e.addParam("r","i32");const n=e.getCodeBuilder(),r=n.getLocal("x"),l=n.i32_add(n.getLocal("x"),n.i32_const(o)),c=n.getLocal("y"),s=n.i32_add(n.getLocal("y"),n.i32_const(o)),d=n.getLocal("r"),u=n.i32_add(n.getLocal("r"),n.i32_const(o));e.addCode(n.call(i+"_add",r,c,d),n.call(i+"_add",l,s,u))}(),function(){const e=t.addFunction(a+"_sub");e.addParam("x","i32"),e.addParam("y","i32"),e.addParam("r","i32");const n=e.getCodeBuilder(),r=n.getLocal("x"),l=n.i32_add(n.getLocal("x"),n.i32_const(o)),c=n.getLocal("y"),s=n.i32_add(n.getLocal("y"),n.i32_const(o)),d=n.getLocal("r"),u=n.i32_add(n.getLocal("r"),n.i32_const(o));e.addCode(n.call(i+"_sub",r,c,d),n.call(i+"_sub",l,s,u))}(),function(){const e=t.addFunction(a+"_neg");e.addParam("x","i32"),e.addParam("r","i32");const n=e.getCodeBuilder(),r=n.getLocal("x"),l=n.i32_add(n.getLocal("x"),n.i32_const(o)),c=n.getLocal("r"),s=n.i32_add(n.getLocal("r"),n.i32_const(o));e.addCode(n.call(i+"_neg",r,c),n.call(i+"_neg",l,s))}(),function(){const e=t.addFunction(a+"_conjugate");e.addParam("x","i32"),e.addParam("r","i32");const n=e.getCodeBuilder(),r=n.getLocal("x"),l=n.i32_add(n.getLocal("x"),n.i32_const(o)),c=n.getLocal("r"),s=n.i32_add(n.getLocal("r"),n.i32_const(o));e.addCode(n.call(i+"_copy",r,c),n.call(i+"_neg",l,s))}(),function(){const e=t.addFunction(a+"_toMontgomery");e.addParam("x","i32"),e.addParam("r","i32");const n=e.getCodeBuilder(),r=n.getLocal("x"),l=n.i32_add(n.getLocal("x"),n.i32_const(o)),c=n.getLocal("r"),s=n.i32_add(n.getLocal("r"),n.i32_const(o));e.addCode(n.call(i+"_toMontgomery",r,c),n.call(i+"_toMontgomery",l,s))}(),function(){const e=t.addFunction(a+"_fromMontgomery");e.addParam("x","i32"),e.addParam("r","i32");const n=e.getCodeBuilder(),r=n.getLocal("x"),l=n.i32_add(n.getLocal("x"),n.i32_const(o)),c=n.getLocal("r"),s=n.i32_add(n.getLocal("r"),n.i32_const(o));e.addCode(n.call(i+"_fromMontgomery",r,c),n.call(i+"_fromMontgomery",l,s))}(),function(){const e=t.addFunction(a+"_eq");e.addParam("x","i32"),e.addParam("y","i32"),e.setReturnType("i32");const n=e.getCodeBuilder(),r=n.getLocal("x"),l=n.i32_add(n.getLocal("x"),n.i32_const(o)),c=n.getLocal("y"),s=n.i32_add(n.getLocal("y"),n.i32_const(o));e.addCode(n.i32_and(n.call(i+"_eq",r,c),n.call(i+"_eq",l,s)))}(),function(){const n=t.addFunction(a+"_inverse");n.addParam("x","i32"),n.addParam("r","i32");const r=n.getCodeBuilder(),l=r.getLocal("x"),c=r.i32_add(r.getLocal("x"),r.i32_const(o)),s=r.getLocal("r"),d=r.i32_add(r.getLocal("r"),r.i32_const(o)),u=r.i32_const(t.alloc(o)),g=r.i32_const(t.alloc(o)),f=r.i32_const(t.alloc(o)),_=r.i32_const(t.alloc(o));n.addCode(r.call(i+"_square",l,u),r.call(i+"_square",c,g),r.call(e,g,f),r.call(i+"_sub",u,f,f),r.call(i+"_inverse",f,_),r.call(i+"_mul",l,_,s),r.call(i+"_mul",c,_,d),r.call(i+"_neg",d,d))}(),function(){const e=t.addFunction(a+"_timesScalar");e.addParam("x","i32"),e.addParam("scalar","i32"),e.addParam("scalarLen","i32"),e.addParam("r","i32");const n=e.getCodeBuilder(),r=n.getLocal("x"),l=n.i32_add(n.getLocal("x"),n.i32_const(o)),c=n.getLocal("r"),s=n.i32_add(n.getLocal("r"),n.i32_const(o));e.addCode(n.call(i+"_timesScalar",r,n.getLocal("scalar"),n.getLocal("scalarLen"),c),n.call(i+"_timesScalar",l,n.getLocal("scalar"),n.getLocal("scalarLen"),s))}(),function(){const e=t.addFunction(a+"_sign");e.addParam("x","i32"),e.addLocal("s","i32"),e.setReturnType("i32");const n=e.getCodeBuilder(),r=n.getLocal("x"),l=n.i32_add(n.getLocal("x"),n.i32_const(o));e.addCode(n.setLocal("s",n.call(i+"_sign",l)),n.if(n.getLocal("s"),n.ret(n.getLocal("s"))),n.ret(n.call(i+"_sign",r)))}(),function(){const e=t.addFunction(a+"_isNegative");e.addParam("x","i32"),e.setReturnType("i32");const n=e.getCodeBuilder(),r=n.getLocal("x"),l=n.i32_add(n.getLocal("x"),n.i32_const(o));e.addCode(n.if(n.call(i+"_isZero",l),n.ret(n.call(i+"_isNegative",r))),n.ret(n.call(i+"_isNegative",l)))}(),t.exportFunction(a+"_isZero"),t.exportFunction(a+"_isOne"),t.exportFunction(a+"_zero"),t.exportFunction(a+"_one"),t.exportFunction(a+"_copy"),t.exportFunction(a+"_mul"),t.exportFunction(a+"_mul1"),t.exportFunction(a+"_square"),t.exportFunction(a+"_add"),t.exportFunction(a+"_sub"),t.exportFunction(a+"_neg"),t.exportFunction(a+"_sign"),t.exportFunction(a+"_conjugate"),t.exportFunction(a+"_fromMontgomery"),t.exportFunction(a+"_toMontgomery"),t.exportFunction(a+"_eq"),t.exportFunction(a+"_inverse"),Gt(t,a),St(t,a+"_exp",2*o,a+"_mul",a+"_square",a+"_copy",a+"_one"),function(){const e=t.addFunction(a+"_sqrt");e.addParam("a","i32"),e.addParam("pr","i32");const r=e.getCodeBuilder(),l=r.i32_const(t.alloc(Et(u(n).minus(u(3)).divide(4),o))),c=r.i32_const(t.alloc(Et(u(n).minus(u(1)).divide(2),o))),s=r.getLocal("a"),d=r.i32_const(t.alloc(2*o)),g=r.i32_const(t.alloc(2*o)),f=r.i32_const(t.alloc(2*o)),_=t.alloc(2*o),p=r.i32_const(_),h=r.i32_const(_),m=r.i32_const(_+o),L=r.i32_const(t.alloc(2*o)),w=r.i32_const(t.alloc(2*o));e.addCode(r.call(a+"_one",p),r.call(a+"_neg",p,p),r.call(a+"_exp",s,l,r.i32_const(o),d),r.call(a+"_square",d,g),r.call(a+"_mul",s,g,g),r.call(a+"_conjugate",g,f),r.call(a+"_mul",f,g,f),r.if(r.call(a+"_eq",f,p),r.unreachable()),r.call(a+"_mul",d,s,L),r.if(r.call(a+"_eq",g,p),[...r.call(i+"_zero",h),...r.call(i+"_one",m),...r.call(a+"_mul",p,L,r.getLocal("pr"))],[...r.call(a+"_one",w),...r.call(a+"_add",w,g,w),...r.call(a+"_exp",w,c,r.i32_const(o),w),...r.call(a+"_mul",w,L,r.getLocal("pr"))]))}(),function(){const e=t.addFunction(a+"_isSquare");e.addParam("a","i32"),e.setReturnType("i32");const i=e.getCodeBuilder(),r=i.i32_const(t.alloc(Et(u(n).minus(u(3)).divide(4),o))),l=i.getLocal("a"),c=i.i32_const(t.alloc(2*o)),s=i.i32_const(t.alloc(2*o)),d=i.i32_const(t.alloc(2*o)),g=t.alloc(2*o),f=i.i32_const(g);e.addCode(i.call(a+"_one",f),i.call(a+"_neg",f,f),i.call(a+"_exp",l,r,i.i32_const(o),c),i.call(a+"_square",c,s),i.call(a+"_mul",l,s,s),i.call(a+"_conjugate",s,d),i.call(a+"_mul",d,s,d),i.if(i.call(a+"_eq",d,f),i.ret(i.i32_const(0))),i.ret(i.i32_const(1)))}(),t.exportFunction(a+"_exp"),t.exportFunction(a+"_timesScalar"),t.exportFunction(a+"_batchInverse"),t.exportFunction(a+"_sqrt"),t.exportFunction(a+"_isSquare"),t.exportFunction(a+"_isNegative"),a},Qt=function(t,e,a,i){if(t.modules[a])return a;const o=8*t.modules[i].n64;return t.modules[a]={n64:3*t.modules[i].n64},function(){const e=t.addFunction(a+"_isZero");e.addParam("x","i32"),e.setReturnType("i32");const n=e.getCodeBuilder(),r=n.getLocal("x"),l=n.i32_add(n.getLocal("x"),n.i32_const(o)),c=n.i32_add(n.getLocal("x"),n.i32_const(2*o));e.addCode(n.i32_and(n.i32_and(n.call(i+"_isZero",r),n.call(i+"_isZero",l)),n.call(i+"_isZero",c)))}(),function(){const e=t.addFunction(a+"_isOne");e.addParam("x","i32"),e.setReturnType("i32");const n=e.getCodeBuilder(),r=n.getLocal("x"),l=n.i32_add(n.getLocal("x"),n.i32_const(o)),c=n.i32_add(n.getLocal("x"),n.i32_const(2*o));e.addCode(n.ret(n.i32_and(n.i32_and(n.call(i+"_isOne",r),n.call(i+"_isZero",l)),n.call(i+"_isZero",c))))}(),function(){const e=t.addFunction(a+"_zero");e.addParam("x","i32");const n=e.getCodeBuilder(),r=n.getLocal("x"),l=n.i32_add(n.getLocal("x"),n.i32_const(o)),c=n.i32_add(n.getLocal("x"),n.i32_const(2*o));e.addCode(n.call(i+"_zero",r),n.call(i+"_zero",l),n.call(i+"_zero",c))}(),function(){const e=t.addFunction(a+"_one");e.addParam("x","i32");const n=e.getCodeBuilder(),r=n.getLocal("x"),l=n.i32_add(n.getLocal("x"),n.i32_const(o)),c=n.i32_add(n.getLocal("x"),n.i32_const(2*o));e.addCode(n.call(i+"_one",r),n.call(i+"_zero",l),n.call(i+"_zero",c))}(),function(){const e=t.addFunction(a+"_copy");e.addParam("x","i32"),e.addParam("r","i32");const n=e.getCodeBuilder(),r=n.getLocal("x"),l=n.i32_add(n.getLocal("x"),n.i32_const(o)),c=n.i32_add(n.getLocal("x"),n.i32_const(2*o)),s=n.getLocal("r"),d=n.i32_add(n.getLocal("r"),n.i32_const(o)),u=n.i32_add(n.getLocal("r"),n.i32_const(2*o));e.addCode(n.call(i+"_copy",r,s),n.call(i+"_copy",l,d),n.call(i+"_copy",c,u))}(),function(){const n=t.addFunction(a+"_mul");n.addParam("x","i32"),n.addParam("y","i32"),n.addParam("r","i32");const r=n.getCodeBuilder(),l=r.getLocal("x"),c=r.i32_add(r.getLocal("x"),r.i32_const(o)),s=r.i32_add(r.getLocal("x"),r.i32_const(2*o)),d=r.getLocal("y"),u=r.i32_add(r.getLocal("y"),r.i32_const(o)),g=r.i32_add(r.getLocal("y"),r.i32_const(2*o)),f=r.getLocal("r"),_=r.i32_add(r.getLocal("r"),r.i32_const(o)),p=r.i32_add(r.getLocal("r"),r.i32_const(2*o)),h=r.i32_const(t.alloc(o)),m=r.i32_const(t.alloc(o)),L=r.i32_const(t.alloc(o)),w=r.i32_const(t.alloc(o)),A=r.i32_const(t.alloc(o)),b=r.i32_const(t.alloc(o)),y=r.i32_const(t.alloc(o)),I=r.i32_const(t.alloc(o)),C=r.i32_const(t.alloc(o)),F=r.i32_const(t.alloc(o)),x=r.i32_const(t.alloc(o)),v=r.i32_const(t.alloc(o)),E=r.i32_const(t.alloc(o));n.addCode(r.call(i+"_mul",l,d,h),r.call(i+"_mul",c,u,m),r.call(i+"_mul",s,g,L),r.call(i+"_add",l,c,w),r.call(i+"_add",d,u,A),r.call(i+"_add",l,s,b),r.call(i+"_add",d,g,y),r.call(i+"_add",c,s,I),r.call(i+"_add",u,g,C),r.call(i+"_add",h,m,F),r.call(i+"_add",h,L,x),r.call(i+"_add",m,L,v),r.call(i+"_mul",I,C,f),r.call(i+"_sub",f,v,f),r.call(e,f,f),r.call(i+"_add",h,f,f),r.call(i+"_mul",w,A,_),r.call(i+"_sub",_,F,_),r.call(e,L,E),r.call(i+"_add",_,E,_),r.call(i+"_mul",b,y,p),r.call(i+"_sub",p,x,p),r.call(i+"_add",p,m,p))}(),function(){const n=t.addFunction(a+"_square");n.addParam("x","i32"),n.addParam("r","i32");const r=n.getCodeBuilder(),l=r.getLocal("x"),c=r.i32_add(r.getLocal("x"),r.i32_const(o)),s=r.i32_add(r.getLocal("x"),r.i32_const(2*o)),d=r.getLocal("r"),u=r.i32_add(r.getLocal("r"),r.i32_const(o)),g=r.i32_add(r.getLocal("r"),r.i32_const(2*o)),f=r.i32_const(t.alloc(o)),_=r.i32_const(t.alloc(o)),p=r.i32_const(t.alloc(o)),h=r.i32_const(t.alloc(o)),m=r.i32_const(t.alloc(o)),L=r.i32_const(t.alloc(o)),w=r.i32_const(t.alloc(o));n.addCode(r.call(i+"_square",l,f),r.call(i+"_mul",l,c,_),r.call(i+"_add",_,_,p),r.call(i+"_sub",l,c,h),r.call(i+"_add",h,s,h),r.call(i+"_square",h,h),r.call(i+"_mul",c,s,m),r.call(i+"_add",m,m,L),r.call(i+"_square",s,w),r.call(e,L,d),r.call(i+"_add",f,d,d),r.call(e,w,u),r.call(i+"_add",p,u,u),r.call(i+"_add",f,w,g),r.call(i+"_sub",L,g,g),r.call(i+"_add",h,g,g),r.call(i+"_add",p,g,g))}(),function(){const e=t.addFunction(a+"_add");e.addParam("x","i32"),e.addParam("y","i32"),e.addParam("r","i32");const n=e.getCodeBuilder(),r=n.getLocal("x"),l=n.i32_add(n.getLocal("x"),n.i32_const(o)),c=n.i32_add(n.getLocal("x"),n.i32_const(2*o)),s=n.getLocal("y"),d=n.i32_add(n.getLocal("y"),n.i32_const(o)),u=n.i32_add(n.getLocal("y"),n.i32_const(2*o)),g=n.getLocal("r"),f=n.i32_add(n.getLocal("r"),n.i32_const(o)),_=n.i32_add(n.getLocal("r"),n.i32_const(2*o));e.addCode(n.call(i+"_add",r,s,g),n.call(i+"_add",l,d,f),n.call(i+"_add",c,u,_))}(),function(){const e=t.addFunction(a+"_sub");e.addParam("x","i32"),e.addParam("y","i32"),e.addParam("r","i32");const n=e.getCodeBuilder(),r=n.getLocal("x"),l=n.i32_add(n.getLocal("x"),n.i32_const(o)),c=n.i32_add(n.getLocal("x"),n.i32_const(2*o)),s=n.getLocal("y"),d=n.i32_add(n.getLocal("y"),n.i32_const(o)),u=n.i32_add(n.getLocal("y"),n.i32_const(2*o)),g=n.getLocal("r"),f=n.i32_add(n.getLocal("r"),n.i32_const(o)),_=n.i32_add(n.getLocal("r"),n.i32_const(2*o));e.addCode(n.call(i+"_sub",r,s,g),n.call(i+"_sub",l,d,f),n.call(i+"_sub",c,u,_))}(),function(){const e=t.addFunction(a+"_neg");e.addParam("x","i32"),e.addParam("r","i32");const n=e.getCodeBuilder(),r=n.getLocal("x"),l=n.i32_add(n.getLocal("x"),n.i32_const(o)),c=n.i32_add(n.getLocal("x"),n.i32_const(2*o)),s=n.getLocal("r"),d=n.i32_add(n.getLocal("r"),n.i32_const(o)),u=n.i32_add(n.getLocal("r"),n.i32_const(2*o));e.addCode(n.call(i+"_neg",r,s),n.call(i+"_neg",l,d),n.call(i+"_neg",c,u))}(),function(){const e=t.addFunction(a+"_sign");e.addParam("x","i32"),e.addLocal("s","i32"),e.setReturnType("i32");const n=e.getCodeBuilder(),r=n.getLocal("x"),l=n.i32_add(n.getLocal("x"),n.i32_const(o)),c=n.i32_add(n.getLocal("x"),n.i32_const(2*o));e.addCode(n.setLocal("s",n.call(i+"_sign",c)),n.if(n.getLocal("s"),n.ret(n.getLocal("s"))),n.setLocal("s",n.call(i+"_sign",l)),n.if(n.getLocal("s"),n.ret(n.getLocal("s"))),n.ret(n.call(i+"_sign",r)))}(),function(){const e=t.addFunction(a+"_toMontgomery");e.addParam("x","i32"),e.addParam("r","i32");const n=e.getCodeBuilder(),r=n.getLocal("x"),l=n.i32_add(n.getLocal("x"),n.i32_const(o)),c=n.i32_add(n.getLocal("x"),n.i32_const(2*o)),s=n.getLocal("r"),d=n.i32_add(n.getLocal("r"),n.i32_const(o)),u=n.i32_add(n.getLocal("r"),n.i32_const(2*o));e.addCode(n.call(i+"_toMontgomery",r,s),n.call(i+"_toMontgomery",l,d),n.call(i+"_toMontgomery",c,u))}(),function(){const e=t.addFunction(a+"_fromMontgomery");e.addParam("x","i32"),e.addParam("r","i32");const n=e.getCodeBuilder(),r=n.getLocal("x"),l=n.i32_add(n.getLocal("x"),n.i32_const(o)),c=n.i32_add(n.getLocal("x"),n.i32_const(2*o)),s=n.getLocal("r"),d=n.i32_add(n.getLocal("r"),n.i32_const(o)),u=n.i32_add(n.getLocal("r"),n.i32_const(2*o));e.addCode(n.call(i+"_fromMontgomery",r,s),n.call(i+"_fromMontgomery",l,d),n.call(i+"_fromMontgomery",c,u))}(),function(){const e=t.addFunction(a+"_eq");e.addParam("x","i32"),e.addParam("y","i32"),e.setReturnType("i32");const n=e.getCodeBuilder(),r=n.getLocal("x"),l=n.i32_add(n.getLocal("x"),n.i32_const(o)),c=n.i32_add(n.getLocal("x"),n.i32_const(2*o)),s=n.getLocal("y"),d=n.i32_add(n.getLocal("y"),n.i32_const(o)),u=n.i32_add(n.getLocal("y"),n.i32_const(2*o));e.addCode(n.i32_and(n.i32_and(n.call(i+"_eq",r,s),n.call(i+"_eq",l,d)),n.call(i+"_eq",c,u)))}(),function(){const n=t.addFunction(a+"_inverse");n.addParam("x","i32"),n.addParam("r","i32");const r=n.getCodeBuilder(),l=r.getLocal("x"),c=r.i32_add(r.getLocal("x"),r.i32_const(o)),s=r.i32_add(r.getLocal("x"),r.i32_const(2*o)),d=r.getLocal("r"),u=r.i32_add(r.getLocal("r"),r.i32_const(o)),g=r.i32_add(r.getLocal("r"),r.i32_const(2*o)),f=r.i32_const(t.alloc(o)),_=r.i32_const(t.alloc(o)),p=r.i32_const(t.alloc(o)),h=r.i32_const(t.alloc(o)),m=r.i32_const(t.alloc(o)),L=r.i32_const(t.alloc(o)),w=r.i32_const(t.alloc(o)),A=r.i32_const(t.alloc(o)),b=r.i32_const(t.alloc(o)),y=r.i32_const(t.alloc(o)),I=r.i32_const(t.alloc(o));n.addCode(r.call(i+"_square",l,f),r.call(i+"_square",c,_),r.call(i+"_square",s,p),r.call(i+"_mul",l,c,h),r.call(i+"_mul",l,s,m),r.call(i+"_mul",c,s,L),r.call(e,L,w),r.call(i+"_sub",f,w,w),r.call(e,p,A),r.call(i+"_sub",A,h,A),r.call(i+"_sub",_,m,b),r.call(i+"_mul",s,A,y),r.call(i+"_mul",c,b,I),r.call(i+"_add",y,I,y),r.call(e,y,y),r.call(i+"_mul",l,w,I),r.call(i+"_add",I,y,y),r.call(i+"_inverse",y,y),r.call(i+"_mul",y,w,d),r.call(i+"_mul",y,A,u),r.call(i+"_mul",y,b,g))}(),function(){const e=t.addFunction(a+"_timesScalar");e.addParam("x","i32"),e.addParam("scalar","i32"),e.addParam("scalarLen","i32"),e.addParam("r","i32");const n=e.getCodeBuilder(),r=n.getLocal("x"),l=n.i32_add(n.getLocal("x"),n.i32_const(o)),c=n.i32_add(n.getLocal("x"),n.i32_const(2*o)),s=n.getLocal("r"),d=n.i32_add(n.getLocal("r"),n.i32_const(o)),u=n.i32_add(n.getLocal("r"),n.i32_const(2*o));e.addCode(n.call(i+"_timesScalar",r,n.getLocal("scalar"),n.getLocal("scalarLen"),s),n.call(i+"_timesScalar",l,n.getLocal("scalar"),n.getLocal("scalarLen"),d),n.call(i+"_timesScalar",c,n.getLocal("scalar"),n.getLocal("scalarLen"),u))}(),function(){const e=t.addFunction(a+"_isNegative");e.addParam("x","i32"),e.setReturnType("i32");const n=e.getCodeBuilder(),r=n.getLocal("x"),l=n.i32_add(n.getLocal("x"),n.i32_const(o)),c=n.i32_add(n.getLocal("x"),n.i32_const(2*o));e.addCode(n.if(n.call(i+"_isZero",c),n.if(n.call(i+"_isZero",l),n.ret(n.call(i+"_isNegative",r)),n.ret(n.call(i+"_isNegative",l)))),n.ret(n.call(i+"_isNegative",c)))}(),t.exportFunction(a+"_isZero"),t.exportFunction(a+"_isOne"),t.exportFunction(a+"_zero"),t.exportFunction(a+"_one"),t.exportFunction(a+"_copy"),t.exportFunction(a+"_mul"),t.exportFunction(a+"_square"),t.exportFunction(a+"_add"),t.exportFunction(a+"_sub"),t.exportFunction(a+"_neg"),t.exportFunction(a+"_sign"),t.exportFunction(a+"_fromMontgomery"),t.exportFunction(a+"_toMontgomery"),t.exportFunction(a+"_eq"),t.exportFunction(a+"_inverse"),Gt(t,a),St(t,a+"_exp",3*o,a+"_mul",a+"_square",a+"_copy",a+"_one"),t.exportFunction(a+"_exp"),t.exportFunction(a+"_timesScalar"),t.exportFunction(a+"_batchInverse"),t.exportFunction(a+"_isNegative"),a},Mt=function(t,e,a,i,o,n,r,l){const c=t.addFunction(e);c.addParam("base","i32"),c.addParam("scalar","i32"),c.addParam("scalarLength","i32"),c.addParam("r","i32"),c.addLocal("old0","i32"),c.addLocal("nbits","i32"),c.addLocal("i","i32"),c.addLocal("last","i32"),c.addLocal("cur","i32"),c.addLocal("carry","i32"),c.addLocal("p","i32");const s=c.getCodeBuilder(),d=s.i32_const(t.alloc(a));function u(t){return s.i32_and(s.i32_shr_u(s.i32_load(s.i32_add(s.getLocal("scalar"),s.i32_and(s.i32_shr_u(t,s.i32_const(3)),s.i32_const(4294967292)))),s.i32_and(t,s.i32_const(31))),s.i32_const(1))}function g(t){return[...s.i32_store8(s.getLocal("p"),s.i32_const(t)),...s.setLocal("p",s.i32_add(s.getLocal("p"),s.i32_const(1)))]}c.addCode(s.if(s.i32_eqz(s.getLocal("scalarLength")),[...s.call(l,s.getLocal("r")),...s.ret([])]),s.setLocal("nbits",s.i32_shl(s.getLocal("scalarLength"),s.i32_const(3))),s.setLocal("old0",s.i32_load(s.i32_const(0))),s.setLocal("p",s.getLocal("old0")),s.i32_store(s.i32_const(0),s.i32_and(s.i32_add(s.i32_add(s.getLocal("old0"),s.i32_const(32)),s.getLocal("nbits")),s.i32_const(4294967288))),s.setLocal("i",s.i32_const(1)),s.setLocal("last",u(s.i32_const(0))),s.setLocal("carry",s.i32_const(0)),s.block(s.loop(s.br_if(1,s.i32_eq(s.getLocal("i"),s.getLocal("nbits"))),s.setLocal("cur",u(s.getLocal("i"))),s.if(s.getLocal("last"),s.if(s.getLocal("cur"),s.if(s.getLocal("carry"),[...s.setLocal("last",s.i32_const(0)),...s.setLocal("carry",s.i32_const(1)),...g(1)],[...s.setLocal("last",s.i32_const(0)),...s.setLocal("carry",s.i32_const(1)),...g(255)]),s.if(s.getLocal("carry"),[...s.setLocal("last",s.i32_const(0)),...s.setLocal("carry",s.i32_const(1)),...g(255)],[...s.setLocal("last",s.i32_const(0)),...s.setLocal("carry",s.i32_const(0)),...g(1)])),s.if(s.getLocal("cur"),s.if(s.getLocal("carry"),[...s.setLocal("last",s.i32_const(0)),...s.setLocal("carry",s.i32_const(1)),...g(0)],[...s.setLocal("last",s.i32_const(1)),...s.setLocal("carry",s.i32_const(0)),...g(0)]),s.if(s.getLocal("carry"),[...s.setLocal("last",s.i32_const(1)),...s.setLocal("carry",s.i32_const(0)),...g(0)],[...s.setLocal("last",s.i32_const(0)),...s.setLocal("carry",s.i32_const(0)),...g(0)]))),s.setLocal("i",s.i32_add(s.getLocal("i"),s.i32_const(1))),s.br(0))),s.if(s.getLocal("last"),s.if(s.getLocal("carry"),[...g(255),...g(0),...g(1)],[...g(1)]),s.if(s.getLocal("carry"),[...g(0),...g(1)])),s.setLocal("p",s.i32_sub(s.getLocal("p"),s.i32_const(1))),s.call(r,s.getLocal("base"),d),s.call(l,s.getLocal("r")),s.block(s.loop(s.call(o,s.getLocal("r"),s.getLocal("r")),s.setLocal("cur",s.i32_load8_u(s.getLocal("p"))),s.if(s.getLocal("cur"),s.if(s.i32_eq(s.getLocal("cur"),s.i32_const(1)),s.call(i,s.getLocal("r"),d,s.getLocal("r")),s.call(n,s.getLocal("r"),d,s.getLocal("r")))),s.br_if(1,s.i32_eq(s.getLocal("old0"),s.getLocal("p"))),s.setLocal("p",s.i32_sub(s.getLocal("p"),s.i32_const(1))),s.br(0))),s.i32_store(s.i32_const(0),s.getLocal("old0")))},kt=function(t,e,a,i,o){const n=8*t.modules[e].n64;function r(){const i=t.addFunction(a);i.addParam("pBases","i32"),i.addParam("pScalars","i32"),i.addParam("scalarSize","i32"),i.addParam("n","i32"),i.addParam("pr","i32"),i.addLocal("chunkSize","i32"),i.addLocal("nChunks","i32"),i.addLocal("itScalar","i32"),i.addLocal("endScalar","i32"),i.addLocal("itBase","i32"),i.addLocal("itBit","i32"),i.addLocal("i","i32"),i.addLocal("j","i32"),i.addLocal("nTable","i32"),i.addLocal("pTable","i32"),i.addLocal("idx","i32"),i.addLocal("pIdxTable","i32");const o=i.getCodeBuilder(),r=o.i32_const(t.alloc(n)),l=t.alloc([17,17,17,17,17,17,17,17,17,17,16,16,15,14,13,13,12,11,10,9,8,7,7,6,5,4,3,2,1,1,1,1]);i.addCode(o.call(e+"_zero",o.getLocal("pr")),o.if(o.i32_eqz(o.getLocal("n")),o.ret([])),o.setLocal("chunkSize",o.i32_load8_u(o.i32_clz(o.getLocal("n")),l)),o.setLocal("nChunks",o.i32_add(o.i32_div_u(o.i32_sub(o.i32_shl(o.getLocal("scalarSize"),o.i32_const(3)),o.i32_const(1)),o.getLocal("chunkSize")),o.i32_const(1))),o.setLocal("itBit",o.i32_mul(o.i32_sub(o.getLocal("nChunks"),o.i32_const(1)),o.getLocal("chunkSize"))),o.block(o.loop(o.br_if(1,o.i32_lt_s(o.getLocal("itBit"),o.i32_const(0))),o.if(o.i32_eqz(o.call(e+"_isZero",o.getLocal("pr"))),[...o.setLocal("j",o.i32_const(0)),...o.block(o.loop(o.br_if(1,o.i32_eq(o.getLocal("j"),o.getLocal("chunkSize"))),o.call(e+"_double",o.getLocal("pr"),o.getLocal("pr")),o.setLocal("j",o.i32_add(o.getLocal("j"),o.i32_const(1))),o.br(0)))]),o.call(a+"_chunk",o.getLocal("pBases"),o.getLocal("pScalars"),o.getLocal("scalarSize"),o.getLocal("n"),o.getLocal("itBit"),o.getLocal("chunkSize"),r),o.call(e+"_add",o.getLocal("pr"),r,o.getLocal("pr")),o.setLocal("itBit",o.i32_sub(o.getLocal("itBit"),o.getLocal("chunkSize"))),o.br(0))))}!function(){const e=t.addFunction(a+"_getChunk");e.addParam("pScalar","i32"),e.addParam("scalarSize","i32"),e.addParam("startBit","i32"),e.addParam("chunkSize","i32"),e.addLocal("bitsToEnd","i32"),e.addLocal("mask","i32"),e.setReturnType("i32");const i=e.getCodeBuilder();e.addCode(i.setLocal("bitsToEnd",i.i32_sub(i.i32_mul(i.getLocal("scalarSize"),i.i32_const(8)),i.getLocal("startBit"))),i.if(i.i32_gt_s(i.getLocal("chunkSize"),i.getLocal("bitsToEnd")),i.setLocal("mask",i.i32_sub(i.i32_shl(i.i32_const(1),i.getLocal("bitsToEnd")),i.i32_const(1))),i.setLocal("mask",i.i32_sub(i.i32_shl(i.i32_const(1),i.getLocal("chunkSize")),i.i32_const(1)))),i.i32_and(i.i32_shr_u(i.i32_load(i.i32_add(i.getLocal("pScalar"),i.i32_shr_u(i.getLocal("startBit"),i.i32_const(3))),0,0),i.i32_and(i.getLocal("startBit"),i.i32_const(7))),i.getLocal("mask")))}(),function(){const i=t.addFunction(a+"_reduceTable");i.addParam("pTable","i32"),i.addParam("p","i32"),i.addLocal("half","i32"),i.addLocal("it1","i32"),i.addLocal("it2","i32"),i.addLocal("pAcc","i32");const o=i.getCodeBuilder();i.addCode(o.if(o.i32_eq(o.getLocal("p"),o.i32_const(1)),o.ret([])),o.setLocal("half",o.i32_shl(o.i32_const(1),o.i32_sub(o.getLocal("p"),o.i32_const(1)))),o.setLocal("it1",o.getLocal("pTable")),o.setLocal("it2",o.i32_add(o.getLocal("pTable"),o.i32_mul(o.getLocal("half"),o.i32_const(n)))),o.setLocal("pAcc",o.i32_sub(o.getLocal("it2"),o.i32_const(n))),o.block(o.loop(o.br_if(1,o.i32_eq(o.getLocal("it1"),o.getLocal("pAcc"))),o.call(e+"_add",o.getLocal("it1"),o.getLocal("it2"),o.getLocal("it1")),o.call(e+"_add",o.getLocal("pAcc"),o.getLocal("it2"),o.getLocal("pAcc")),o.setLocal("it1",o.i32_add(o.getLocal("it1"),o.i32_const(n))),o.setLocal("it2",o.i32_add(o.getLocal("it2"),o.i32_const(n))),o.br(0))),o.call(a+"_reduceTable",o.getLocal("pTable"),o.i32_sub(o.getLocal("p"),o.i32_const(1))),o.setLocal("p",o.i32_sub(o.getLocal("p"),o.i32_const(1))),o.block(o.loop(o.br_if(1,o.i32_eqz(o.getLocal("p"))),o.call(e+"_double",o.getLocal("pAcc"),o.getLocal("pAcc")),o.setLocal("p",o.i32_sub(o.getLocal("p"),o.i32_const(1))),o.br(0))),o.call(e+"_add",o.getLocal("pTable"),o.getLocal("pAcc"),o.getLocal("pTable")))}(),function(){const r=t.addFunction(a+"_chunk");r.addParam("pBases","i32"),r.addParam("pScalars","i32"),r.addParam("scalarSize","i32"),r.addParam("n","i32"),r.addParam("startBit","i32"),r.addParam("chunkSize","i32"),r.addParam("pr","i32"),r.addLocal("nChunks","i32"),r.addLocal("itScalar","i32"),r.addLocal("endScalar","i32"),r.addLocal("itBase","i32"),r.addLocal("i","i32"),r.addLocal("j","i32"),r.addLocal("nTable","i32"),r.addLocal("pTable","i32"),r.addLocal("idx","i32"),r.addLocal("pIdxTable","i32");const l=r.getCodeBuilder();r.addCode(l.if(l.i32_eqz(l.getLocal("n")),[...l.call(e+"_zero",l.getLocal("pr")),...l.ret([])]),l.setLocal("nTable",l.i32_shl(l.i32_const(1),l.getLocal("chunkSize"))),l.setLocal("pTable",l.i32_load(l.i32_const(0))),l.i32_store(l.i32_const(0),l.i32_add(l.getLocal("pTable"),l.i32_mul(l.getLocal("nTable"),l.i32_const(n)))),l.setLocal("j",l.i32_const(0)),l.block(l.loop(l.br_if(1,l.i32_eq(l.getLocal("j"),l.getLocal("nTable"))),l.call(e+"_zero",l.i32_add(l.getLocal("pTable"),l.i32_mul(l.getLocal("j"),l.i32_const(n)))),l.setLocal("j",l.i32_add(l.getLocal("j"),l.i32_const(1))),l.br(0))),l.setLocal("itBase",l.getLocal("pBases")),l.setLocal("itScalar",l.getLocal("pScalars")),l.setLocal("endScalar",l.i32_add(l.getLocal("pScalars"),l.i32_mul(l.getLocal("n"),l.getLocal("scalarSize")))),l.block(l.loop(l.br_if(1,l.i32_eq(l.getLocal("itScalar"),l.getLocal("endScalar"))),l.setLocal("idx",l.call(a+"_getChunk",l.getLocal("itScalar"),l.getLocal("scalarSize"),l.getLocal("startBit"),l.getLocal("chunkSize"))),l.if(l.getLocal("idx"),[...l.setLocal("pIdxTable",l.i32_add(l.getLocal("pTable"),l.i32_mul(l.i32_sub(l.getLocal("idx"),l.i32_const(1)),l.i32_const(n)))),...l.call(i,l.getLocal("pIdxTable"),l.getLocal("itBase"),l.getLocal("pIdxTable"))]),l.setLocal("itScalar",l.i32_add(l.getLocal("itScalar"),l.getLocal("scalarSize"))),l.setLocal("itBase",l.i32_add(l.getLocal("itBase"),l.i32_const(o))),l.br(0))),l.call(a+"_reduceTable",l.getLocal("pTable"),l.getLocal("chunkSize")),l.call(e+"_copy",l.getLocal("pTable"),l.getLocal("pr")),l.i32_store(l.i32_const(0),l.getLocal("pTable")))}(),r(),t.exportFunction(a),t.exportFunction(a+"_chunk")},Tt=function(t,e,a,i){const o=t.modules[a].n64,n=8*o;if(t.modules[e])return e;return t.modules[e]={n64:3*o},function(){const i=t.addFunction(e+"_isZeroAffine");i.addParam("p1","i32"),i.setReturnType("i32");const o=i.getCodeBuilder();i.addCode(o.i32_and(o.call(a+"_isZero",o.getLocal("p1")),o.call(a+"_isZero",o.i32_add(o.getLocal("p1"),o.i32_const(n)))))}(),function(){const i=t.addFunction(e+"_isZero");i.addParam("p1","i32"),i.setReturnType("i32");const o=i.getCodeBuilder();i.addCode(o.call(a+"_isZero",o.i32_add(o.getLocal("p1"),o.i32_const(2*n))))}(),function(){const i=t.addFunction(e+"_zeroAffine");i.addParam("pr","i32");const o=i.getCodeBuilder();i.addCode(o.call(a+"_zero",o.getLocal("pr"))),i.addCode(o.call(a+"_zero",o.i32_add(o.getLocal("pr"),o.i32_const(n))))}(),function(){const i=t.addFunction(e+"_zero");i.addParam("pr","i32");const o=i.getCodeBuilder();i.addCode(o.call(a+"_zero",o.getLocal("pr"))),i.addCode(o.call(a+"_one",o.i32_add(o.getLocal("pr"),o.i32_const(n)))),i.addCode(o.call(a+"_zero",o.i32_add(o.getLocal("pr"),o.i32_const(2*n))))}(),function(){const a=t.addFunction(e+"_copyAffine");a.addParam("ps","i32"),a.addParam("pd","i32");const i=a.getCodeBuilder();for(let t=0;t<2*o;t++)a.addCode(i.i64_store(i.getLocal("pd"),8*t,i.i64_load(i.getLocal("ps"),8*t)))}(),function(){const a=t.addFunction(e+"_copy");a.addParam("ps","i32"),a.addParam("pd","i32");const i=a.getCodeBuilder();for(let t=0;t<3*o;t++)a.addCode(i.i64_store(i.getLocal("pd"),8*t,i.i64_load(i.getLocal("ps"),8*t)))}(),function(){const i=t.addFunction(e+"_toJacobian");i.addParam("p1","i32"),i.addParam("pr","i32");const o=i.getCodeBuilder(),r=o.getLocal("p1"),l=o.i32_add(o.getLocal("p1"),o.i32_const(n)),c=o.getLocal("pr"),s=o.i32_add(o.getLocal("pr"),o.i32_const(n)),d=o.i32_add(o.getLocal("pr"),o.i32_const(2*n));i.addCode(o.if(o.call(e+"_isZeroAffine",o.getLocal("p1")),o.call(e+"_zero",o.getLocal("pr")),[...o.call(a+"_one",d),...o.call(a+"_copy",l,s),...o.call(a+"_copy",r,c)]))}(),function(){const i=t.addFunction(e+"_eqAffine");i.addParam("p1","i32"),i.addParam("p2","i32"),i.setReturnType("i32"),i.addLocal("z1","i32");const o=i.getCodeBuilder();i.addCode(o.ret(o.i32_and(o.call(a+"_eq",o.getLocal("p1"),o.getLocal("p2")),o.call(a+"_eq",o.i32_add(o.getLocal("p1"),o.i32_const(n)),o.i32_add(o.getLocal("p2"),o.i32_const(n))))))}(),function(){const i=t.addFunction(e+"_eqMixed");i.addParam("p1","i32"),i.addParam("p2","i32"),i.setReturnType("i32"),i.addLocal("z1","i32");const o=i.getCodeBuilder(),r=o.getLocal("p1"),l=o.i32_add(o.getLocal("p1"),o.i32_const(n));i.addCode(o.setLocal("z1",o.i32_add(o.getLocal("p1"),o.i32_const(2*n))));const c=o.getLocal("z1"),s=o.getLocal("p2"),d=o.i32_add(o.getLocal("p2"),o.i32_const(n)),u=o.i32_const(t.alloc(n)),g=o.i32_const(t.alloc(n)),f=o.i32_const(t.alloc(n)),_=o.i32_const(t.alloc(n));i.addCode(o.if(o.call(e+"_isZero",o.getLocal("p1")),o.ret(o.call(e+"_isZeroAffine",o.getLocal("p2")))),o.if(o.call(e+"_isZeroAffine",o.getLocal("p2")),o.ret(o.i32_const(0))),o.if(o.call(a+"_isOne",c),o.ret(o.call(e+"_eqAffine",o.getLocal("p1"),o.getLocal("p2")))),o.call(a+"_square",c,u),o.call(a+"_mul",s,u,g),o.call(a+"_mul",c,u,f),o.call(a+"_mul",d,f,_),o.if(o.call(a+"_eq",r,g),o.if(o.call(a+"_eq",l,_),o.ret(o.i32_const(1)))),o.ret(o.i32_const(0)))}(),function(){const i=t.addFunction(e+"_eq");i.addParam("p1","i32"),i.addParam("p2","i32"),i.setReturnType("i32"),i.addLocal("z1","i32"),i.addLocal("z2","i32");const o=i.getCodeBuilder(),r=o.getLocal("p1"),l=o.i32_add(o.getLocal("p1"),o.i32_const(n));i.addCode(o.setLocal("z1",o.i32_add(o.getLocal("p1"),o.i32_const(2*n))));const c=o.getLocal("z1"),s=o.getLocal("p2"),d=o.i32_add(o.getLocal("p2"),o.i32_const(n));i.addCode(o.setLocal("z2",o.i32_add(o.getLocal("p2"),o.i32_const(2*n))));const u=o.getLocal("z2"),g=o.i32_const(t.alloc(n)),f=o.i32_const(t.alloc(n)),_=o.i32_const(t.alloc(n)),p=o.i32_const(t.alloc(n)),h=o.i32_const(t.alloc(n)),m=o.i32_const(t.alloc(n)),L=o.i32_const(t.alloc(n)),w=o.i32_const(t.alloc(n));i.addCode(o.if(o.call(e+"_isZero",o.getLocal("p1")),o.ret(o.call(e+"_isZero",o.getLocal("p2")))),o.if(o.call(e+"_isZero",o.getLocal("p2")),o.ret(o.i32_const(0))),o.if(o.call(a+"_isOne",c),o.ret(o.call(e+"_eqMixed",o.getLocal("p2"),o.getLocal("p1")))),o.if(o.call(a+"_isOne",u),o.ret(o.call(e+"_eqMixed",o.getLocal("p1"),o.getLocal("p2")))),o.call(a+"_square",c,g),o.call(a+"_square",u,f),o.call(a+"_mul",r,f,_),o.call(a+"_mul",s,g,p),o.call(a+"_mul",c,g,h),o.call(a+"_mul",u,f,m),o.call(a+"_mul",l,m,L),o.call(a+"_mul",d,h,w),o.if(o.call(a+"_eq",_,p),o.if(o.call(a+"_eq",L,w),o.ret(o.i32_const(1)))),o.ret(o.i32_const(0)))}(),function(){const i=t.addFunction(e+"_doubleAffine");i.addParam("p1","i32"),i.addParam("pr","i32");const o=i.getCodeBuilder(),r=o.getLocal("p1"),l=o.i32_add(o.getLocal("p1"),o.i32_const(n)),c=o.getLocal("pr"),s=o.i32_add(o.getLocal("pr"),o.i32_const(n)),d=o.i32_add(o.getLocal("pr"),o.i32_const(2*n)),u=o.i32_const(t.alloc(n)),g=o.i32_const(t.alloc(n)),f=o.i32_const(t.alloc(n)),_=o.i32_const(t.alloc(n)),p=o.i32_const(t.alloc(n)),h=o.i32_const(t.alloc(n));i.addCode(o.if(o.call(e+"_isZeroAffine",o.getLocal("p1")),[...o.call(e+"_toJacobian",o.getLocal("p1"),o.getLocal("pr")),...o.ret([])]),o.call(a+"_square",r,u),o.call(a+"_square",l,g),o.call(a+"_square",g,f),o.call(a+"_add",r,g,_),o.call(a+"_square",_,_),o.call(a+"_sub",_,u,_),o.call(a+"_sub",_,f,_),o.call(a+"_add",_,_,_),o.call(a+"_add",u,u,p),o.call(a+"_add",p,u,p),o.call(a+"_add",l,l,d),o.call(a+"_square",p,c),o.call(a+"_sub",c,_,c),o.call(a+"_sub",c,_,c),o.call(a+"_add",f,f,h),o.call(a+"_add",h,h,h),o.call(a+"_add",h,h,h),o.call(a+"_sub",_,c,s),o.call(a+"_mul",s,p,s),o.call(a+"_sub",s,h,s))}(),function(){const i=t.addFunction(e+"_double");i.addParam("p1","i32"),i.addParam("pr","i32");const o=i.getCodeBuilder(),r=o.getLocal("p1"),l=o.i32_add(o.getLocal("p1"),o.i32_const(n)),c=o.i32_add(o.getLocal("p1"),o.i32_const(2*n)),s=o.getLocal("pr"),d=o.i32_add(o.getLocal("pr"),o.i32_const(n)),u=o.i32_add(o.getLocal("pr"),o.i32_const(2*n)),g=o.i32_const(t.alloc(n)),f=o.i32_const(t.alloc(n)),_=o.i32_const(t.alloc(n)),p=o.i32_const(t.alloc(n)),h=o.i32_const(t.alloc(n)),m=o.i32_const(t.alloc(n)),L=o.i32_const(t.alloc(n)),w=o.i32_const(t.alloc(n));i.addCode(o.if(o.call(e+"_isZero",o.getLocal("p1")),[...o.call(e+"_copy",o.getLocal("p1"),o.getLocal("pr")),...o.ret([])]),o.if(o.call(a+"_isOne",c),[...o.ret(o.call(e+"_doubleAffine",o.getLocal("p1"),o.getLocal("pr"))),...o.ret([])]),o.call(a+"_square",r,g),o.call(a+"_square",l,f),o.call(a+"_square",f,_),o.call(a+"_add",r,f,p),o.call(a+"_square",p,p),o.call(a+"_sub",p,g,p),o.call(a+"_sub",p,_,p),o.call(a+"_add",p,p,p),o.call(a+"_add",g,g,h),o.call(a+"_add",h,g,h),o.call(a+"_square",h,m),o.call(a+"_mul",l,c,L),o.call(a+"_add",p,p,s),o.call(a+"_sub",m,s,s),o.call(a+"_add",_,_,w),o.call(a+"_add",w,w,w),o.call(a+"_add",w,w,w),o.call(a+"_sub",p,s,d),o.call(a+"_mul",d,h,d),o.call(a+"_sub",d,w,d),o.call(a+"_add",L,L,u))}(),function(){const i=t.addFunction(e+"_addAffine");i.addParam("p1","i32"),i.addParam("p2","i32"),i.addParam("pr","i32"),i.addLocal("z1","i32");const o=i.getCodeBuilder(),r=o.getLocal("p1"),l=o.i32_add(o.getLocal("p1"),o.i32_const(n));i.addCode(o.setLocal("z1",o.i32_add(o.getLocal("p1"),o.i32_const(2*n))));const c=o.getLocal("p2"),s=o.i32_add(o.getLocal("p2"),o.i32_const(n)),d=o.getLocal("pr"),u=o.i32_add(o.getLocal("pr"),o.i32_const(n)),g=o.i32_add(o.getLocal("pr"),o.i32_const(2*n)),f=o.i32_const(t.alloc(n)),_=o.i32_const(t.alloc(n)),p=o.i32_const(t.alloc(n)),h=o.i32_const(t.alloc(n)),m=o.i32_const(t.alloc(n)),L=o.i32_const(t.alloc(n)),w=o.i32_const(t.alloc(n)),A=o.i32_const(t.alloc(n)),b=o.i32_const(t.alloc(n)),y=o.i32_const(t.alloc(n));i.addCode(o.if(o.call(e+"_isZeroAffine",o.getLocal("p1")),[...o.call(e+"_copyAffine",o.getLocal("p2"),o.getLocal("pr")),...o.call(a+"_one",o.i32_add(o.getLocal("pr"),o.i32_const(2*n))),...o.ret([])]),o.if(o.call(e+"_isZeroAffine",o.getLocal("p2")),[...o.call(e+"_copyAffine",o.getLocal("p1"),o.getLocal("pr")),...o.call(a+"_one",o.i32_add(o.getLocal("pr"),o.i32_const(2*n))),...o.ret([])]),o.if(o.call(a+"_eq",r,c),o.if(o.call(a+"_eq",l,s),[...o.call(e+"_doubleAffine",o.getLocal("p2"),o.getLocal("pr")),...o.ret([])])),o.call(a+"_sub",c,r,f),o.call(a+"_sub",s,l,p),o.call(a+"_square",f,_),o.call(a+"_add",_,_,h),o.call(a+"_add",h,h,h),o.call(a+"_mul",f,h,m),o.call(a+"_add",p,p,L),o.call(a+"_mul",r,h,A),o.call(a+"_square",L,w),o.call(a+"_add",A,A,b),o.call(a+"_sub",w,m,d),o.call(a+"_sub",d,b,d),o.call(a+"_mul",l,m,y),o.call(a+"_add",y,y,y),o.call(a+"_sub",A,d,u),o.call(a+"_mul",u,L,u),o.call(a+"_sub",u,y,u),o.call(a+"_add",f,f,g))}(),function(){const i=t.addFunction(e+"_addMixed");i.addParam("p1","i32"),i.addParam("p2","i32"),i.addParam("pr","i32"),i.addLocal("z1","i32");const o=i.getCodeBuilder(),r=o.getLocal("p1"),l=o.i32_add(o.getLocal("p1"),o.i32_const(n));i.addCode(o.setLocal("z1",o.i32_add(o.getLocal("p1"),o.i32_const(2*n))));const c=o.getLocal("z1"),s=o.getLocal("p2"),d=o.i32_add(o.getLocal("p2"),o.i32_const(n)),u=o.getLocal("pr"),g=o.i32_add(o.getLocal("pr"),o.i32_const(n)),f=o.i32_add(o.getLocal("pr"),o.i32_const(2*n)),_=o.i32_const(t.alloc(n)),p=o.i32_const(t.alloc(n)),h=o.i32_const(t.alloc(n)),m=o.i32_const(t.alloc(n)),L=o.i32_const(t.alloc(n)),w=o.i32_const(t.alloc(n)),A=o.i32_const(t.alloc(n)),b=o.i32_const(t.alloc(n)),y=o.i32_const(t.alloc(n)),I=o.i32_const(t.alloc(n)),C=o.i32_const(t.alloc(n)),F=o.i32_const(t.alloc(n)),x=o.i32_const(t.alloc(n)),v=o.i32_const(t.alloc(n));i.addCode(o.if(o.call(e+"_isZero",o.getLocal("p1")),[...o.call(e+"_copyAffine",o.getLocal("p2"),o.getLocal("pr")),...o.call(a+"_one",o.i32_add(o.getLocal("pr"),o.i32_const(2*n))),...o.ret([])]),o.if(o.call(e+"_isZeroAffine",o.getLocal("p2")),[...o.call(e+"_copy",o.getLocal("p1"),o.getLocal("pr")),...o.ret([])]),o.if(o.call(a+"_isOne",c),[...o.call(e+"_addAffine",r,s,u),...o.ret([])]),o.call(a+"_square",c,_),o.call(a+"_mul",s,_,p),o.call(a+"_mul",c,_,h),o.call(a+"_mul",d,h,m),o.if(o.call(a+"_eq",r,p),o.if(o.call(a+"_eq",l,m),[...o.call(e+"_doubleAffine",o.getLocal("p2"),o.getLocal("pr")),...o.ret([])])),o.call(a+"_sub",p,r,L),o.call(a+"_sub",m,l,A),o.call(a+"_square",L,w),o.call(a+"_add",w,w,b),o.call(a+"_add",b,b,b),o.call(a+"_mul",L,b,y),o.call(a+"_add",A,A,I),o.call(a+"_mul",r,b,F),o.call(a+"_square",I,C),o.call(a+"_add",F,F,x),o.call(a+"_sub",C,y,u),o.call(a+"_sub",u,x,u),o.call(a+"_mul",l,y,v),o.call(a+"_add",v,v,v),o.call(a+"_sub",F,u,g),o.call(a+"_mul",g,I,g),o.call(a+"_sub",g,v,g),o.call(a+"_add",c,L,f),o.call(a+"_square",f,f),o.call(a+"_sub",f,_,f),o.call(a+"_sub",f,w,f))}(),function(){const i=t.addFunction(e+"_add");i.addParam("p1","i32"),i.addParam("p2","i32"),i.addParam("pr","i32"),i.addLocal("z1","i32"),i.addLocal("z2","i32");const o=i.getCodeBuilder(),r=o.getLocal("p1"),l=o.i32_add(o.getLocal("p1"),o.i32_const(n));i.addCode(o.setLocal("z1",o.i32_add(o.getLocal("p1"),o.i32_const(2*n))));const c=o.getLocal("z1"),s=o.getLocal("p2"),d=o.i32_add(o.getLocal("p2"),o.i32_const(n));i.addCode(o.setLocal("z2",o.i32_add(o.getLocal("p2"),o.i32_const(2*n))));const u=o.getLocal("z2"),g=o.getLocal("pr"),f=o.i32_add(o.getLocal("pr"),o.i32_const(n)),_=o.i32_add(o.getLocal("pr"),o.i32_const(2*n)),p=o.i32_const(t.alloc(n)),h=o.i32_const(t.alloc(n)),m=o.i32_const(t.alloc(n)),L=o.i32_const(t.alloc(n)),w=o.i32_const(t.alloc(n)),A=o.i32_const(t.alloc(n)),b=o.i32_const(t.alloc(n)),y=o.i32_const(t.alloc(n)),I=o.i32_const(t.alloc(n)),C=o.i32_const(t.alloc(n)),F=o.i32_const(t.alloc(n)),x=o.i32_const(t.alloc(n)),v=o.i32_const(t.alloc(n)),E=o.i32_const(t.alloc(n)),B=o.i32_const(t.alloc(n)),S=o.i32_const(t.alloc(n)),G=o.i32_const(t.alloc(n));i.addCode(o.if(o.call(e+"_isZero",o.getLocal("p1")),[...o.call(e+"_copy",o.getLocal("p2"),o.getLocal("pr")),...o.ret([])]),o.if(o.call(e+"_isZero",o.getLocal("p2")),[...o.call(e+"_copy",o.getLocal("p1"),o.getLocal("pr")),...o.ret([])]),o.if(o.call(a+"_isOne",c),[...o.call(e+"_addMixed",s,r,g),...o.ret([])]),o.if(o.call(a+"_isOne",u),[...o.call(e+"_addMixed",r,s,g),...o.ret([])]),o.call(a+"_square",c,p),o.call(a+"_square",u,h),o.call(a+"_mul",r,h,m),o.call(a+"_mul",s,p,L),o.call(a+"_mul",c,p,w),o.call(a+"_mul",u,h,A),o.call(a+"_mul",l,A,b),o.call(a+"_mul",d,w,y),o.if(o.call(a+"_eq",m,L),o.if(o.call(a+"_eq",b,y),[...o.call(e+"_double",o.getLocal("p1"),o.getLocal("pr")),...o.ret([])])),o.call(a+"_sub",L,m,I),o.call(a+"_sub",y,b,C),o.call(a+"_add",I,I,F),o.call(a+"_square",F,F),o.call(a+"_mul",I,F,x),o.call(a+"_add",C,C,v),o.call(a+"_mul",m,F,B),o.call(a+"_square",v,E),o.call(a+"_add",B,B,S),o.call(a+"_sub",E,x,g),o.call(a+"_sub",g,S,g),o.call(a+"_mul",b,x,G),o.call(a+"_add",G,G,G),o.call(a+"_sub",B,g,f),o.call(a+"_mul",f,v,f),o.call(a+"_sub",f,G,f),o.call(a+"_add",c,u,_),o.call(a+"_square",_,_),o.call(a+"_sub",_,p,_),o.call(a+"_sub",_,h,_),o.call(a+"_mul",_,I,_))}(),function(){const i=t.addFunction(e+"_negAffine");i.addParam("p1","i32"),i.addParam("pr","i32");const o=i.getCodeBuilder(),r=o.getLocal("p1"),l=o.i32_add(o.getLocal("p1"),o.i32_const(n)),c=o.getLocal("pr"),s=o.i32_add(o.getLocal("pr"),o.i32_const(n));i.addCode(o.call(a+"_copy",r,c),o.call(a+"_neg",l,s))}(),function(){const i=t.addFunction(e+"_neg");i.addParam("p1","i32"),i.addParam("pr","i32");const o=i.getCodeBuilder(),r=o.getLocal("p1"),l=o.i32_add(o.getLocal("p1"),o.i32_const(n)),c=o.i32_add(o.getLocal("p1"),o.i32_const(2*n)),s=o.getLocal("pr"),d=o.i32_add(o.getLocal("pr"),o.i32_const(n)),u=o.i32_add(o.getLocal("pr"),o.i32_const(2*n));i.addCode(o.call(a+"_copy",r,s),o.call(a+"_neg",l,d),o.call(a+"_copy",c,u))}(),function(){const a=t.addFunction(e+"_subAffine");a.addParam("p1","i32"),a.addParam("p2","i32"),a.addParam("pr","i32");const i=a.getCodeBuilder(),o=i.i32_const(t.alloc(3*n));a.addCode(i.call(e+"_negAffine",i.getLocal("p2"),o),i.call(e+"_addAffine",i.getLocal("p1"),o,i.getLocal("pr")))}(),function(){const a=t.addFunction(e+"_subMixed");a.addParam("p1","i32"),a.addParam("p2","i32"),a.addParam("pr","i32");const i=a.getCodeBuilder(),o=i.i32_const(t.alloc(3*n));a.addCode(i.call(e+"_negAffine",i.getLocal("p2"),o),i.call(e+"_addMixed",i.getLocal("p1"),o,i.getLocal("pr")))}(),function(){const a=t.addFunction(e+"_sub");a.addParam("p1","i32"),a.addParam("p2","i32"),a.addParam("pr","i32");const i=a.getCodeBuilder(),o=i.i32_const(t.alloc(3*n));a.addCode(i.call(e+"_neg",i.getLocal("p2"),o),i.call(e+"_add",i.getLocal("p1"),o,i.getLocal("pr")))}(),function(){const i=t.addFunction(e+"_fromMontgomeryAffine");i.addParam("p1","i32"),i.addParam("pr","i32");const o=i.getCodeBuilder();i.addCode(o.call(a+"_fromMontgomery",o.getLocal("p1"),o.getLocal("pr")));for(let t=1;t<2;t++)i.addCode(o.call(a+"_fromMontgomery",o.i32_add(o.getLocal("p1"),o.i32_const(t*n)),o.i32_add(o.getLocal("pr"),o.i32_const(t*n))))}(),function(){const i=t.addFunction(e+"_fromMontgomery");i.addParam("p1","i32"),i.addParam("pr","i32");const o=i.getCodeBuilder();i.addCode(o.call(a+"_fromMontgomery",o.getLocal("p1"),o.getLocal("pr")));for(let t=1;t<3;t++)i.addCode(o.call(a+"_fromMontgomery",o.i32_add(o.getLocal("p1"),o.i32_const(t*n)),o.i32_add(o.getLocal("pr"),o.i32_const(t*n))))}(),function(){const i=t.addFunction(e+"_toMontgomeryAffine");i.addParam("p1","i32"),i.addParam("pr","i32");const o=i.getCodeBuilder();i.addCode(o.call(a+"_toMontgomery",o.getLocal("p1"),o.getLocal("pr")));for(let t=1;t<2;t++)i.addCode(o.call(a+"_toMontgomery",o.i32_add(o.getLocal("p1"),o.i32_const(t*n)),o.i32_add(o.getLocal("pr"),o.i32_const(t*n))))}(),function(){const i=t.addFunction(e+"_toMontgomery");i.addParam("p1","i32"),i.addParam("pr","i32");const o=i.getCodeBuilder();i.addCode(o.call(a+"_toMontgomery",o.getLocal("p1"),o.getLocal("pr")));for(let t=1;t<3;t++)i.addCode(o.call(a+"_toMontgomery",o.i32_add(o.getLocal("p1"),o.i32_const(t*n)),o.i32_add(o.getLocal("pr"),o.i32_const(t*n))))}(),function(){const i=t.addFunction(e+"_toAffine");i.addParam("p1","i32"),i.addParam("pr","i32");const o=i.getCodeBuilder(),r=o.getLocal("p1"),l=o.i32_add(o.getLocal("p1"),o.i32_const(n)),c=o.i32_add(o.getLocal("p1"),o.i32_const(2*n)),s=o.getLocal("pr"),d=o.i32_add(o.getLocal("pr"),o.i32_const(n)),u=o.i32_const(t.alloc(n)),g=o.i32_const(t.alloc(n)),f=o.i32_const(t.alloc(n));i.addCode(o.if(o.call(e+"_isZero",o.getLocal("p1")),[...o.call(a+"_zero",s),...o.call(a+"_zero",d)],[...o.call(a+"_inverse",c,u),...o.call(a+"_square",u,g),...o.call(a+"_mul",u,g,f),...o.call(a+"_mul",r,g,s),...o.call(a+"_mul",l,f,d)]))}(),function(){const o=t.addFunction(e+"_inCurveAffine");o.addParam("pIn","i32"),o.setReturnType("i32");const r=o.getCodeBuilder(),l=r.getLocal("pIn"),c=r.i32_add(r.getLocal("pIn"),r.i32_const(n)),s=r.i32_const(t.alloc(n)),d=r.i32_const(t.alloc(n));o.addCode(r.call(a+"_square",c,s),r.call(a+"_square",l,d),r.call(a+"_mul",l,d,d),r.call(a+"_add",d,r.i32_const(i),d),r.ret(r.call(a+"_eq",s,d)))}(),function(){const a=t.addFunction(e+"_inCurve");a.addParam("pIn","i32"),a.setReturnType("i32");const i=a.getCodeBuilder(),o=i.i32_const(t.alloc(2*n));a.addCode(i.call(e+"_toAffine",i.getLocal("pIn"),o),i.ret(i.call(e+"_inCurveAffine",o)))}(),function(){const i=t.addFunction(e+"_batchToAffine");i.addParam("pIn","i32"),i.addParam("n","i32"),i.addParam("pOut","i32"),i.addLocal("pAux","i32"),i.addLocal("itIn","i32"),i.addLocal("itAux","i32"),i.addLocal("itOut","i32"),i.addLocal("i","i32");const o=i.getCodeBuilder(),r=o.i32_const(t.alloc(n));i.addCode(o.setLocal("pAux",o.i32_load(o.i32_const(0))),o.i32_store(o.i32_const(0),o.i32_add(o.getLocal("pAux"),o.i32_mul(o.getLocal("n"),o.i32_const(n)))),o.call(a+"_batchInverse",o.i32_add(o.getLocal("pIn"),o.i32_const(2*n)),o.i32_const(3*n),o.getLocal("n"),o.getLocal("pAux"),o.i32_const(n)),o.setLocal("itIn",o.getLocal("pIn")),o.setLocal("itAux",o.getLocal("pAux")),o.setLocal("itOut",o.getLocal("pOut")),o.setLocal("i",o.i32_const(0)),o.block(o.loop(o.br_if(1,o.i32_eq(o.getLocal("i"),o.getLocal("n"))),o.if(o.call(a+"_isZero",o.getLocal("itAux")),[...o.call(a+"_zero",o.getLocal("itOut")),...o.call(a+"_zero",o.i32_add(o.getLocal("itOut"),o.i32_const(n)))],[...o.call(a+"_mul",o.getLocal("itAux"),o.i32_add(o.getLocal("itIn"),o.i32_const(n)),r),...o.call(a+"_square",o.getLocal("itAux"),o.getLocal("itAux")),...o.call(a+"_mul",o.getLocal("itAux"),o.getLocal("itIn"),o.getLocal("itOut")),...o.call(a+"_mul",o.getLocal("itAux"),r,o.i32_add(o.getLocal("itOut"),o.i32_const(n)))]),o.setLocal("itIn",o.i32_add(o.getLocal("itIn"),o.i32_const(3*n))),o.setLocal("itOut",o.i32_add(o.getLocal("itOut"),o.i32_const(2*n))),o.setLocal("itAux",o.i32_add(o.getLocal("itAux"),o.i32_const(n))),o.setLocal("i",o.i32_add(o.getLocal("i"),o.i32_const(1))),o.br(0))),o.i32_store(o.i32_const(0),o.getLocal("pAux")))}(),function(){const i=t.addFunction(e+"_normalize");i.addParam("p1","i32"),i.addParam("pr","i32");const o=i.getCodeBuilder(),r=o.getLocal("p1"),l=o.i32_add(o.getLocal("p1"),o.i32_const(n)),c=o.i32_add(o.getLocal("p1"),o.i32_const(2*n)),s=o.getLocal("pr"),d=o.i32_add(o.getLocal("pr"),o.i32_const(n)),u=o.i32_add(o.getLocal("pr"),o.i32_const(2*n)),g=o.i32_const(t.alloc(n)),f=o.i32_const(t.alloc(n)),_=o.i32_const(t.alloc(n));i.addCode(o.if(o.call(e+"_isZero",o.getLocal("p1")),o.call(e+"_zero",o.getLocal("pr")),[...o.call(a+"_inverse",c,g),...o.call(a+"_square",g,f),...o.call(a+"_mul",g,f,_),...o.call(a+"_mul",r,f,s),...o.call(a+"_mul",l,_,d),...o.call(a+"_one",u)]))}(),function(){const a=t.addFunction(e+"__reverseBytes");a.addParam("pIn","i32"),a.addParam("n","i32"),a.addParam("pOut","i32"),a.addLocal("itOut","i32"),a.addLocal("itIn","i32");const i=a.getCodeBuilder();a.addCode(i.setLocal("itOut",i.i32_sub(i.i32_add(i.getLocal("pOut"),i.getLocal("n")),i.i32_const(1))),i.setLocal("itIn",i.getLocal("pIn")),i.block(i.loop(i.br_if(1,i.i32_lt_s(i.getLocal("itOut"),i.getLocal("pOut"))),i.i32_store8(i.getLocal("itOut"),i.i32_load8_u(i.getLocal("itIn"))),i.setLocal("itOut",i.i32_sub(i.getLocal("itOut"),i.i32_const(1))),i.setLocal("itIn",i.i32_add(i.getLocal("itIn"),i.i32_const(1))),i.br(0))))}(),function(){const a=t.addFunction(e+"_LEMtoU");a.addParam("pIn","i32"),a.addParam("pOut","i32");const i=a.getCodeBuilder(),o=t.alloc(2*n),r=i.i32_const(o),l=i.i32_const(o),c=i.i32_const(o+n);a.addCode(i.if(i.call(e+"_isZeroAffine",i.getLocal("pIn")),[...i.call(e+"_zeroAffine",i.getLocal("pOut")),...i.i32_store8(i.getLocal("pOut"),i.i32_const(64)),...i.ret([])]),i.call(e+"_fromMontgomeryAffine",i.getLocal("pIn"),r),i.call(e+"__reverseBytes",l,i.i32_const(n),i.getLocal("pOut")),i.call(e+"__reverseBytes",c,i.i32_const(n),i.i32_add(i.getLocal("pOut"),i.i32_const(n))))}(),function(){const i=t.addFunction(e+"_LEMtoC");i.addParam("pIn","i32"),i.addParam("pOut","i32");const o=i.getCodeBuilder(),r=o.i32_const(t.alloc(n));i.addCode(o.if(o.call(e+"_isZero",o.getLocal("pIn")),[...o.call(a+"_zero",o.getLocal("pOut")),...o.i32_store8(o.getLocal("pOut"),o.i32_const(64)),...o.ret([])]),o.call(a+"_fromMontgomery",o.getLocal("pIn"),r),o.call(e+"__reverseBytes",r,o.i32_const(n),o.getLocal("pOut")),o.if(o.i32_eq(o.call(a+"_sign",o.i32_add(o.getLocal("pIn"),o.i32_const(n))),o.i32_const(-1)),o.i32_store8(o.getLocal("pOut"),o.i32_or(o.i32_load8_u(o.getLocal("pOut")),o.i32_const(128)))))}(),function(){const a=t.addFunction(e+"_UtoLEM");a.addParam("pIn","i32"),a.addParam("pOut","i32");const i=a.getCodeBuilder(),o=t.alloc(2*n),r=i.i32_const(o),l=i.i32_const(o),c=i.i32_const(o+n);a.addCode(i.if(i.i32_and(i.i32_load8_u(i.getLocal("pIn")),i.i32_const(64)),[...i.call(e+"_zeroAffine",i.getLocal("pOut")),...i.ret([])]),i.call(e+"__reverseBytes",i.getLocal("pIn"),i.i32_const(n),l),i.call(e+"__reverseBytes",i.i32_add(i.getLocal("pIn"),i.i32_const(n)),i.i32_const(n),c),i.call(e+"_toMontgomeryAffine",r,i.getLocal("pOut")))}(),function(){const o=t.addFunction(e+"_CtoLEM");o.addParam("pIn","i32"),o.addParam("pOut","i32"),o.addLocal("firstByte","i32"),o.addLocal("greatest","i32");const r=o.getCodeBuilder(),l=t.alloc(2*n),c=r.i32_const(l),s=r.i32_const(l+n);o.addCode(r.setLocal("firstByte",r.i32_load8_u(r.getLocal("pIn"))),r.if(r.i32_and(r.getLocal("firstByte"),r.i32_const(64)),[...r.call(e+"_zeroAffine",r.getLocal("pOut")),...r.ret([])]),r.setLocal("greatest",r.i32_and(r.getLocal("firstByte"),r.i32_const(128))),r.call(a+"_copy",r.getLocal("pIn"),s),r.i32_store8(s,r.i32_and(r.getLocal("firstByte"),r.i32_const(63))),r.call(e+"__reverseBytes",s,r.i32_const(n),c),r.call(a+"_toMontgomery",c,r.getLocal("pOut")),r.call(a+"_square",r.getLocal("pOut"),s),r.call(a+"_mul",r.getLocal("pOut"),s,s),r.call(a+"_add",s,r.i32_const(i),s),r.call(a+"_sqrt",s,s),r.call(a+"_neg",s,c),r.if(r.i32_eq(r.call(a+"_sign",s),r.i32_const(-1)),r.if(r.getLocal("greatest"),r.call(a+"_copy",s,r.i32_add(r.getLocal("pOut"),r.i32_const(n))),r.call(a+"_neg",s,r.i32_add(r.getLocal("pOut"),r.i32_const(n)))),r.if(r.getLocal("greatest"),r.call(a+"_neg",s,r.i32_add(r.getLocal("pOut"),r.i32_const(n))),r.call(a+"_copy",s,r.i32_add(r.getLocal("pOut"),r.i32_const(n))))))}(),Pt(t,e+"_batchLEMtoU",e+"_LEMtoU",2*n,2*n),Pt(t,e+"_batchLEMtoC",e+"_LEMtoC",2*n,n),Pt(t,e+"_batchUtoLEM",e+"_UtoLEM",2*n,2*n),Pt(t,e+"_batchCtoLEM",e+"_CtoLEM",n,2*n,!0),Pt(t,e+"_batchToJacobian",e+"_toJacobian",2*n,3*n,!0),kt(t,e,e+"_multiexp",e+"_add",3*n),kt(t,e,e+"_multiexpAffine",e+"_addMixed",2*n),Mt(t,e+"_timesScalar",3*n,e+"_add",e+"_double",e+"_sub",e+"_copy",e+"_zero"),Mt(t,e+"_timesScalarAffine",2*n,e+"_addMixed",e+"_double",e+"_subMixed",e+"_copyAffine",e+"_zero"),t.exportFunction(e+"_isZero"),t.exportFunction(e+"_isZeroAffine"),t.exportFunction(e+"_eq"),t.exportFunction(e+"_eqMixed"),t.exportFunction(e+"_eqAffine"),t.exportFunction(e+"_copy"),t.exportFunction(e+"_copyAffine"),t.exportFunction(e+"_zero"),t.exportFunction(e+"_zeroAffine"),t.exportFunction(e+"_double"),t.exportFunction(e+"_doubleAffine"),t.exportFunction(e+"_add"),t.exportFunction(e+"_addMixed"),t.exportFunction(e+"_addAffine"),t.exportFunction(e+"_neg"),t.exportFunction(e+"_negAffine"),t.exportFunction(e+"_sub"),t.exportFunction(e+"_subMixed"),t.exportFunction(e+"_subAffine"),t.exportFunction(e+"_fromMontgomery"),t.exportFunction(e+"_fromMontgomeryAffine"),t.exportFunction(e+"_toMontgomery"),t.exportFunction(e+"_toMontgomeryAffine"),t.exportFunction(e+"_timesScalar"),t.exportFunction(e+"_timesScalarAffine"),t.exportFunction(e+"_normalize"),t.exportFunction(e+"_LEMtoU"),t.exportFunction(e+"_LEMtoC"),t.exportFunction(e+"_UtoLEM"),t.exportFunction(e+"_CtoLEM"),t.exportFunction(e+"_batchLEMtoU"),t.exportFunction(e+"_batchLEMtoC"),t.exportFunction(e+"_batchUtoLEM"),t.exportFunction(e+"_batchCtoLEM"),t.exportFunction(e+"_toAffine"),t.exportFunction(e+"_toJacobian"),t.exportFunction(e+"_batchToAffine"),t.exportFunction(e+"_batchToJacobian"),t.exportFunction(e+"_inCurve"),t.exportFunction(e+"_inCurveAffine"),e},Rt=function(t,e,a,i,o){const n=8*t.modules[i].n64,r=8*t.modules[a].n64,l=t.modules[i].q;let c=l.minus(u(1)),s=0;for(;!c.isOdd();)s++,c=c.shiftRight(1);let d=u(2);for(;d.modPow(l.shiftRight(1),l).equals(1);)d=d.add(1);const g=new Array(s+1);g[s]=d.modPow(c,l);let f=s-1;for(;f>=0;)g[f]=g[f+1].modPow(2,l),f--;const _=[],p=u(1).shiftLeft(8*n).mod(l);for(let t=0;t>a);return e}const x=Array(256);for(let t=0;t<256;t++)x[t]=F(t);const v=t.alloc(x);function E(){const a=t.addFunction(e+"_fft");a.addParam("px","i32"),a.addParam("n","i32"),a.addLocal("bits","i32");const o=a.getCodeBuilder(),r=o.i32_const(t.alloc(n));a.addCode(o.setLocal("bits",o.call(e+"__log2",o.getLocal("n"))),o.call(i+"_one",r),o.call(e+"_rawfft",o.getLocal("px"),o.getLocal("bits"),o.i32_const(0),r))}!function(){const a=t.addFunction(e+"__rev");a.addParam("x","i32"),a.addParam("bits","i32"),a.setReturnType("i32");const i=a.getCodeBuilder();a.addCode(i.i32_rotl(i.i32_add(i.i32_add(i.i32_shl(i.i32_load8_u(i.i32_and(i.getLocal("x"),i.i32_const(255)),v,0),i.i32_const(24)),i.i32_shl(i.i32_load8_u(i.i32_and(i.i32_shr_u(i.getLocal("x"),i.i32_const(8)),i.i32_const(255)),v,0),i.i32_const(16))),i.i32_add(i.i32_shl(i.i32_load8_u(i.i32_and(i.i32_shr_u(i.getLocal("x"),i.i32_const(16)),i.i32_const(255)),v,0),i.i32_const(8)),i.i32_load8_u(i.i32_and(i.i32_shr_u(i.getLocal("x"),i.i32_const(24)),i.i32_const(255)),v,0))),i.getLocal("bits")))}(),function(){const i=t.addFunction(e+"__reversePermutation");i.addParam("px","i32"),i.addParam("bits","i32"),i.addLocal("n","i32"),i.addLocal("i","i32"),i.addLocal("ri","i32"),i.addLocal("idx1","i32"),i.addLocal("idx2","i32");const o=i.getCodeBuilder(),n=o.i32_const(t.alloc(r));i.addCode(o.setLocal("n",o.i32_shl(o.i32_const(1),o.getLocal("bits"))),o.setLocal("i",o.i32_const(0)),o.block(o.loop(o.br_if(1,o.i32_eq(o.getLocal("i"),o.getLocal("n"))),o.setLocal("idx1",o.i32_add(o.getLocal("px"),o.i32_mul(o.getLocal("i"),o.i32_const(r)))),o.setLocal("ri",o.call(e+"__rev",o.getLocal("i"),o.getLocal("bits"))),o.setLocal("idx2",o.i32_add(o.getLocal("px"),o.i32_mul(o.getLocal("ri"),o.i32_const(r)))),o.if(o.i32_lt_u(o.getLocal("i"),o.getLocal("ri")),[...o.call(a+"_copy",o.getLocal("idx1"),n),...o.call(a+"_copy",o.getLocal("idx2"),o.getLocal("idx1")),...o.call(a+"_copy",n,o.getLocal("idx2"))]),o.setLocal("i",o.i32_add(o.getLocal("i"),o.i32_const(1))),o.br(0))))}(),function(){const n=t.addFunction(e+"__fftFinal");n.addParam("px","i32"),n.addParam("bits","i32"),n.addParam("reverse","i32"),n.addParam("mulFactor","i32"),n.addLocal("n","i32"),n.addLocal("ndiv2","i32"),n.addLocal("pInv2","i32"),n.addLocal("i","i32"),n.addLocal("mask","i32"),n.addLocal("idx1","i32"),n.addLocal("idx2","i32");const l=n.getCodeBuilder(),c=l.i32_const(t.alloc(r));n.addCode(l.if(l.i32_and(l.i32_eqz(l.getLocal("reverse")),l.call(i+"_isOne",l.getLocal("mulFactor"))),l.ret([])),l.setLocal("n",l.i32_shl(l.i32_const(1),l.getLocal("bits"))),l.setLocal("mask",l.i32_sub(l.getLocal("n"),l.i32_const(1))),l.setLocal("i",l.i32_const(1)),l.setLocal("ndiv2",l.i32_shr_u(l.getLocal("n"),l.i32_const(1))),l.block(l.loop(l.br_if(1,l.i32_ge_u(l.getLocal("i"),l.getLocal("ndiv2"))),l.setLocal("idx1",l.i32_add(l.getLocal("px"),l.i32_mul(l.getLocal("i"),l.i32_const(r)))),l.setLocal("idx2",l.i32_add(l.getLocal("px"),l.i32_mul(l.i32_sub(l.getLocal("n"),l.getLocal("i")),l.i32_const(r)))),l.if(l.getLocal("reverse"),l.if(l.call(i+"_isOne",l.getLocal("mulFactor")),[...l.call(a+"_copy",l.getLocal("idx1"),c),...l.call(a+"_copy",l.getLocal("idx2"),l.getLocal("idx1")),...l.call(a+"_copy",c,l.getLocal("idx2"))],[...l.call(a+"_copy",l.getLocal("idx1"),c),...l.call(o,l.getLocal("idx2"),l.getLocal("mulFactor"),l.getLocal("idx1")),...l.call(o,c,l.getLocal("mulFactor"),l.getLocal("idx2"))]),l.if(l.call(i+"_isOne",l.getLocal("mulFactor")),[],[...l.call(o,l.getLocal("idx1"),l.getLocal("mulFactor"),l.getLocal("idx1")),...l.call(o,l.getLocal("idx2"),l.getLocal("mulFactor"),l.getLocal("idx2"))])),l.setLocal("i",l.i32_add(l.getLocal("i"),l.i32_const(1))),l.br(0))),l.if(l.call(i+"_isOne",l.getLocal("mulFactor")),[],[...l.call(o,l.getLocal("px"),l.getLocal("mulFactor"),l.getLocal("px")),...l.setLocal("idx2",l.i32_add(l.getLocal("px"),l.i32_mul(l.getLocal("ndiv2"),l.i32_const(r)))),...l.call(o,l.getLocal("idx2"),l.getLocal("mulFactor"),l.getLocal("idx2"))]))}(),function(){const l=t.addFunction(e+"_rawfft");l.addParam("px","i32"),l.addParam("bits","i32"),l.addParam("reverse","i32"),l.addParam("mulFactor","i32"),l.addLocal("s","i32"),l.addLocal("k","i32"),l.addLocal("j","i32"),l.addLocal("m","i32"),l.addLocal("mdiv2","i32"),l.addLocal("n","i32"),l.addLocal("pwm","i32"),l.addLocal("idx1","i32"),l.addLocal("idx2","i32");const c=l.getCodeBuilder(),s=c.i32_const(t.alloc(n)),d=c.i32_const(t.alloc(r)),u=c.i32_const(t.alloc(r));l.addCode(c.call(e+"__reversePermutation",c.getLocal("px"),c.getLocal("bits")),c.setLocal("n",c.i32_shl(c.i32_const(1),c.getLocal("bits"))),c.setLocal("s",c.i32_const(1)),c.block(c.loop(c.br_if(1,c.i32_gt_u(c.getLocal("s"),c.getLocal("bits"))),c.setLocal("m",c.i32_shl(c.i32_const(1),c.getLocal("s"))),c.setLocal("pwm",c.i32_add(c.i32_const(h),c.i32_mul(c.getLocal("s"),c.i32_const(n)))),c.setLocal("k",c.i32_const(0)),c.block(c.loop(c.br_if(1,c.i32_ge_u(c.getLocal("k"),c.getLocal("n"))),c.call(i+"_one",s),c.setLocal("mdiv2",c.i32_shr_u(c.getLocal("m"),c.i32_const(1))),c.setLocal("j",c.i32_const(0)),c.block(c.loop(c.br_if(1,c.i32_ge_u(c.getLocal("j"),c.getLocal("mdiv2"))),c.setLocal("idx1",c.i32_add(c.getLocal("px"),c.i32_mul(c.i32_add(c.getLocal("k"),c.getLocal("j")),c.i32_const(r)))),c.setLocal("idx2",c.i32_add(c.getLocal("idx1"),c.i32_mul(c.getLocal("mdiv2"),c.i32_const(r)))),c.call(o,c.getLocal("idx2"),s,d),c.call(a+"_copy",c.getLocal("idx1"),u),c.call(a+"_add",u,d,c.getLocal("idx1")),c.call(a+"_sub",u,d,c.getLocal("idx2")),c.call(i+"_mul",s,c.getLocal("pwm"),s),c.setLocal("j",c.i32_add(c.getLocal("j"),c.i32_const(1))),c.br(0))),c.setLocal("k",c.i32_add(c.getLocal("k"),c.getLocal("m"))),c.br(0))),c.setLocal("s",c.i32_add(c.getLocal("s"),c.i32_const(1))),c.br(0))),c.call(e+"__fftFinal",c.getLocal("px"),c.getLocal("bits"),c.getLocal("reverse"),c.getLocal("mulFactor")))}(),function(){const a=t.addFunction(e+"__log2");a.addParam("n","i32"),a.setReturnType("i32"),a.addLocal("bits","i32"),a.addLocal("aux","i32");const i=a.getCodeBuilder();a.addCode(i.setLocal("aux",i.i32_shr_u(i.getLocal("n"),i.i32_const(1)))),a.addCode(i.setLocal("bits",i.i32_const(0))),a.addCode(i.block(i.loop(i.br_if(1,i.i32_eqz(i.getLocal("aux"))),i.setLocal("aux",i.i32_shr_u(i.getLocal("aux"),i.i32_const(1))),i.setLocal("bits",i.i32_add(i.getLocal("bits"),i.i32_const(1))),i.br(0)))),a.addCode(i.if(i.i32_ne(i.getLocal("n"),i.i32_shl(i.i32_const(1),i.getLocal("bits"))),i.unreachable())),a.addCode(i.if(i.i32_gt_u(i.getLocal("bits"),i.i32_const(s)),i.unreachable())),a.addCode(i.getLocal("bits"))}(),E(),function(){const a=t.addFunction(e+"_ifft");a.addParam("px","i32"),a.addParam("n","i32"),a.addLocal("bits","i32"),a.addLocal("pInv2","i32");const i=a.getCodeBuilder();a.addCode(i.setLocal("bits",i.call(e+"__log2",i.getLocal("n"))),i.setLocal("pInv2",i.i32_add(i.i32_const(w),i.i32_mul(i.getLocal("bits"),i.i32_const(n)))),i.call(e+"_rawfft",i.getLocal("px"),i.getLocal("bits"),i.i32_const(1),i.getLocal("pInv2")))}(),function(){const l=t.addFunction(e+"_fftJoin");l.addParam("pBuff1","i32"),l.addParam("pBuff2","i32"),l.addParam("n","i32"),l.addParam("first","i32"),l.addParam("inc","i32"),l.addLocal("idx1","i32"),l.addLocal("idx2","i32"),l.addLocal("i","i32");const c=l.getCodeBuilder(),s=c.i32_const(t.alloc(n)),d=c.i32_const(t.alloc(r)),u=c.i32_const(t.alloc(r));l.addCode(c.call(i+"_copy",c.getLocal("first"),s),c.setLocal("i",c.i32_const(0)),c.block(c.loop(c.br_if(1,c.i32_eq(c.getLocal("i"),c.getLocal("n"))),c.setLocal("idx1",c.i32_add(c.getLocal("pBuff1"),c.i32_mul(c.getLocal("i"),c.i32_const(r)))),c.setLocal("idx2",c.i32_add(c.getLocal("pBuff2"),c.i32_mul(c.getLocal("i"),c.i32_const(r)))),c.call(o,c.getLocal("idx2"),s,d),c.call(a+"_copy",c.getLocal("idx1"),u),c.call(a+"_add",u,d,c.getLocal("idx1")),c.call(a+"_sub",u,d,c.getLocal("idx2")),c.call(i+"_mul",s,c.getLocal("inc"),s),c.setLocal("i",c.i32_add(c.getLocal("i"),c.i32_const(1))),c.br(0))))}(),function(){const l=t.addFunction(e+"_fftJoinExt");l.addParam("pBuff1","i32"),l.addParam("pBuff2","i32"),l.addParam("n","i32"),l.addParam("first","i32"),l.addParam("inc","i32"),l.addParam("totalBits","i32"),l.addLocal("idx1","i32"),l.addLocal("idx2","i32"),l.addLocal("i","i32"),l.addLocal("pShiftToM","i32");const c=l.getCodeBuilder(),s=c.i32_const(t.alloc(n)),d=c.i32_const(t.alloc(r));l.addCode(c.setLocal("pShiftToM",c.i32_add(c.i32_const(I),c.i32_mul(c.getLocal("totalBits"),c.i32_const(n)))),c.call(i+"_copy",c.getLocal("first"),s),c.setLocal("i",c.i32_const(0)),c.block(c.loop(c.br_if(1,c.i32_eq(c.getLocal("i"),c.getLocal("n"))),c.setLocal("idx1",c.i32_add(c.getLocal("pBuff1"),c.i32_mul(c.getLocal("i"),c.i32_const(r)))),c.setLocal("idx2",c.i32_add(c.getLocal("pBuff2"),c.i32_mul(c.getLocal("i"),c.i32_const(r)))),c.call(a+"_add",c.getLocal("idx1"),c.getLocal("idx2"),d),c.call(o,c.getLocal("idx2"),c.getLocal("pShiftToM"),c.getLocal("idx2")),c.call(a+"_add",c.getLocal("idx1"),c.getLocal("idx2"),c.getLocal("idx2")),c.call(o,c.getLocal("idx2"),s,c.getLocal("idx2")),c.call(a+"_copy",d,c.getLocal("idx1")),c.call(i+"_mul",s,c.getLocal("inc"),s),c.setLocal("i",c.i32_add(c.getLocal("i"),c.i32_const(1))),c.br(0))))}(),function(){const l=t.addFunction(e+"_fftJoinExtInv");l.addParam("pBuff1","i32"),l.addParam("pBuff2","i32"),l.addParam("n","i32"),l.addParam("first","i32"),l.addParam("inc","i32"),l.addParam("totalBits","i32"),l.addLocal("idx1","i32"),l.addLocal("idx2","i32"),l.addLocal("i","i32"),l.addLocal("pShiftToM","i32"),l.addLocal("pSConst","i32");const c=l.getCodeBuilder(),s=c.i32_const(t.alloc(n)),d=c.i32_const(t.alloc(r));l.addCode(c.setLocal("pShiftToM",c.i32_add(c.i32_const(I),c.i32_mul(c.getLocal("totalBits"),c.i32_const(n)))),c.setLocal("pSConst",c.i32_add(c.i32_const(C),c.i32_mul(c.getLocal("totalBits"),c.i32_const(n)))),c.call(i+"_copy",c.getLocal("first"),s),c.setLocal("i",c.i32_const(0)),c.block(c.loop(c.br_if(1,c.i32_eq(c.getLocal("i"),c.getLocal("n"))),c.setLocal("idx1",c.i32_add(c.getLocal("pBuff1"),c.i32_mul(c.getLocal("i"),c.i32_const(r)))),c.setLocal("idx2",c.i32_add(c.getLocal("pBuff2"),c.i32_mul(c.getLocal("i"),c.i32_const(r)))),c.call(o,c.getLocal("idx2"),s,d),c.call(a+"_sub",c.getLocal("idx1"),d,c.getLocal("idx2")),c.call(o,c.getLocal("idx2"),c.getLocal("pSConst"),c.getLocal("idx2")),c.call(o,c.getLocal("idx1"),c.getLocal("pShiftToM"),c.getLocal("idx1")),c.call(a+"_sub",d,c.getLocal("idx1"),c.getLocal("idx1")),c.call(o,c.getLocal("idx1"),c.getLocal("pSConst"),c.getLocal("idx1")),c.call(i+"_mul",s,c.getLocal("inc"),s),c.setLocal("i",c.i32_add(c.getLocal("i"),c.i32_const(1))),c.br(0))))}(),function(){const l=t.addFunction(e+"_fftMix");l.addParam("pBuff","i32"),l.addParam("n","i32"),l.addParam("exp","i32"),l.addLocal("nGroups","i32"),l.addLocal("nPerGroup","i32"),l.addLocal("nPerGroupDiv2","i32"),l.addLocal("pairOffset","i32"),l.addLocal("idx1","i32"),l.addLocal("idx2","i32"),l.addLocal("i","i32"),l.addLocal("j","i32"),l.addLocal("pwm","i32");const c=l.getCodeBuilder(),s=c.i32_const(t.alloc(n)),d=c.i32_const(t.alloc(r)),u=c.i32_const(t.alloc(r));l.addCode(c.setLocal("nPerGroup",c.i32_shl(c.i32_const(1),c.getLocal("exp"))),c.setLocal("nPerGroupDiv2",c.i32_shr_u(c.getLocal("nPerGroup"),c.i32_const(1))),c.setLocal("nGroups",c.i32_shr_u(c.getLocal("n"),c.getLocal("exp"))),c.setLocal("pairOffset",c.i32_mul(c.getLocal("nPerGroupDiv2"),c.i32_const(r))),c.setLocal("pwm",c.i32_add(c.i32_const(h),c.i32_mul(c.getLocal("exp"),c.i32_const(n)))),c.setLocal("i",c.i32_const(0)),c.block(c.loop(c.br_if(1,c.i32_eq(c.getLocal("i"),c.getLocal("nGroups"))),c.call(i+"_one",s),c.setLocal("j",c.i32_const(0)),c.block(c.loop(c.br_if(1,c.i32_eq(c.getLocal("j"),c.getLocal("nPerGroupDiv2"))),c.setLocal("idx1",c.i32_add(c.getLocal("pBuff"),c.i32_mul(c.i32_add(c.i32_mul(c.getLocal("i"),c.getLocal("nPerGroup")),c.getLocal("j")),c.i32_const(r)))),c.setLocal("idx2",c.i32_add(c.getLocal("idx1"),c.getLocal("pairOffset"))),c.call(o,c.getLocal("idx2"),s,d),c.call(a+"_copy",c.getLocal("idx1"),u),c.call(a+"_add",u,d,c.getLocal("idx1")),c.call(a+"_sub",u,d,c.getLocal("idx2")),c.call(i+"_mul",s,c.getLocal("pwm"),s),c.setLocal("j",c.i32_add(c.getLocal("j"),c.i32_const(1))),c.br(0))),c.setLocal("i",c.i32_add(c.getLocal("i"),c.i32_const(1))),c.br(0))))}(),function(){const i=t.addFunction(e+"_fftFinal");i.addParam("pBuff","i32"),i.addParam("n","i32"),i.addParam("factor","i32"),i.addLocal("idx1","i32"),i.addLocal("idx2","i32"),i.addLocal("i","i32"),i.addLocal("ndiv2","i32");const n=i.getCodeBuilder(),l=n.i32_const(t.alloc(r));i.addCode(n.setLocal("ndiv2",n.i32_shr_u(n.getLocal("n"),n.i32_const(1))),n.if(n.i32_and(n.getLocal("n"),n.i32_const(1)),n.call(o,n.i32_add(n.getLocal("pBuff"),n.i32_mul(n.getLocal("ndiv2"),n.i32_const(r))),n.getLocal("factor"),n.i32_add(n.getLocal("pBuff"),n.i32_mul(n.getLocal("ndiv2"),n.i32_const(r))))),n.setLocal("i",n.i32_const(0)),n.block(n.loop(n.br_if(1,n.i32_ge_u(n.getLocal("i"),n.getLocal("ndiv2"))),n.setLocal("idx1",n.i32_add(n.getLocal("pBuff"),n.i32_mul(n.getLocal("i"),n.i32_const(r)))),n.setLocal("idx2",n.i32_add(n.getLocal("pBuff"),n.i32_mul(n.i32_sub(n.i32_sub(n.getLocal("n"),n.i32_const(1)),n.getLocal("i")),n.i32_const(r)))),n.call(o,n.getLocal("idx2"),n.getLocal("factor"),l),n.call(o,n.getLocal("idx1"),n.getLocal("factor"),n.getLocal("idx2")),n.call(a+"_copy",l,n.getLocal("idx1")),n.setLocal("i",n.i32_add(n.getLocal("i"),n.i32_const(1))),n.br(0))))}(),function(){const l=t.addFunction(e+"_prepareLagrangeEvaluation");l.addParam("pBuff1","i32"),l.addParam("pBuff2","i32"),l.addParam("n","i32"),l.addParam("first","i32"),l.addParam("inc","i32"),l.addParam("totalBits","i32"),l.addLocal("idx1","i32"),l.addLocal("idx2","i32"),l.addLocal("i","i32"),l.addLocal("pShiftToM","i32"),l.addLocal("pSConst","i32");const c=l.getCodeBuilder(),s=c.i32_const(t.alloc(n)),d=c.i32_const(t.alloc(r));l.addCode(c.setLocal("pShiftToM",c.i32_add(c.i32_const(I),c.i32_mul(c.getLocal("totalBits"),c.i32_const(n)))),c.setLocal("pSConst",c.i32_add(c.i32_const(C),c.i32_mul(c.getLocal("totalBits"),c.i32_const(n)))),c.call(i+"_copy",c.getLocal("first"),s),c.setLocal("i",c.i32_const(0)),c.block(c.loop(c.br_if(1,c.i32_eq(c.getLocal("i"),c.getLocal("n"))),c.setLocal("idx1",c.i32_add(c.getLocal("pBuff1"),c.i32_mul(c.getLocal("i"),c.i32_const(r)))),c.setLocal("idx2",c.i32_add(c.getLocal("pBuff2"),c.i32_mul(c.getLocal("i"),c.i32_const(r)))),c.call(o,c.getLocal("idx1"),c.getLocal("pShiftToM"),d),c.call(a+"_sub",c.getLocal("idx2"),d,d),c.call(a+"_sub",c.getLocal("idx1"),c.getLocal("idx2"),c.getLocal("idx2")),c.call(o,d,c.getLocal("pSConst"),c.getLocal("idx1")),c.call(o,c.getLocal("idx2"),s,c.getLocal("idx2")),c.call(i+"_mul",s,c.getLocal("inc"),s),c.setLocal("i",c.i32_add(c.getLocal("i"),c.i32_const(1))),c.br(0))))}(),t.exportFunction(e+"_fft"),t.exportFunction(e+"_ifft"),t.exportFunction(e+"_rawfft"),t.exportFunction(e+"_fftJoin"),t.exportFunction(e+"_fftJoinExt"),t.exportFunction(e+"_fftJoinExtInv"),t.exportFunction(e+"_fftMix"),t.exportFunction(e+"_fftFinal"),t.exportFunction(e+"_prepareLagrangeEvaluation")},Nt=function(t,e,a){const i=8*t.modules[a].n64;return function(){const o=t.addFunction(e+"_zero");o.addParam("px","i32"),o.addParam("n","i32"),o.addLocal("lastp","i32"),o.addLocal("p","i32");const n=o.getCodeBuilder();o.addCode(n.setLocal("p",n.getLocal("px")),n.setLocal("lastp",n.i32_add(n.getLocal("px"),n.i32_mul(n.getLocal("n"),n.i32_const(i)))),n.block(n.loop(n.br_if(1,n.i32_eq(n.getLocal("p"),n.getLocal("lastp"))),n.call(a+"_zero",n.getLocal("p")),n.setLocal("p",n.i32_add(n.getLocal("p"),n.i32_const(i))),n.br(0))))}(),function(){const o=t.addFunction(e+"_constructLC");o.addParam("ppolynomials","i32"),o.addParam("psignals","i32"),o.addParam("nSignals","i32"),o.addParam("pres","i32"),o.addLocal("i","i32"),o.addLocal("j","i32"),o.addLocal("pp","i32"),o.addLocal("ps","i32"),o.addLocal("pd","i32"),o.addLocal("ncoefs","i32");const n=o.getCodeBuilder(),r=n.i32_const(t.alloc(i));o.addCode(n.setLocal("i",n.i32_const(0)),n.setLocal("pp",n.getLocal("ppolynomials")),n.setLocal("ps",n.getLocal("psignals")),n.block(n.loop(n.br_if(1,n.i32_eq(n.getLocal("i"),n.getLocal("nSignals"))),n.setLocal("ncoefs",n.i32_load(n.getLocal("pp"))),n.setLocal("pp",n.i32_add(n.getLocal("pp"),n.i32_const(4))),n.setLocal("j",n.i32_const(0)),n.block(n.loop(n.br_if(1,n.i32_eq(n.getLocal("j"),n.getLocal("ncoefs"))),n.setLocal("pd",n.i32_add(n.getLocal("pres"),n.i32_mul(n.i32_load(n.getLocal("pp")),n.i32_const(i)))),n.setLocal("pp",n.i32_add(n.getLocal("pp"),n.i32_const(4))),n.call(a+"_mul",n.getLocal("ps"),n.getLocal("pp"),r),n.call(a+"_add",r,n.getLocal("pd"),n.getLocal("pd")),n.setLocal("pp",n.i32_add(n.getLocal("pp"),n.i32_const(i))),n.setLocal("j",n.i32_add(n.getLocal("j"),n.i32_const(1))),n.br(0))),n.setLocal("ps",n.i32_add(n.getLocal("ps"),n.i32_const(i))),n.setLocal("i",n.i32_add(n.getLocal("i"),n.i32_const(1))),n.br(0))))}(),t.exportFunction(e+"_zero"),t.exportFunction(e+"_constructLC"),e},Dt=function(t,e,a){const i=8*t.modules[a].n64;return function(){const o=t.addFunction(e+"_buildABC");o.addParam("pCoefs","i32"),o.addParam("nCoefs","i32"),o.addParam("pWitness","i32"),o.addParam("pA","i32"),o.addParam("pB","i32"),o.addParam("pC","i32"),o.addParam("offsetOut","i32"),o.addParam("nOut","i32"),o.addParam("offsetWitness","i32"),o.addParam("nWitness","i32"),o.addLocal("it","i32"),o.addLocal("ita","i32"),o.addLocal("itb","i32"),o.addLocal("last","i32"),o.addLocal("m","i32"),o.addLocal("c","i32"),o.addLocal("s","i32"),o.addLocal("pOut","i32");const n=o.getCodeBuilder(),r=n.i32_const(t.alloc(i));o.addCode(n.setLocal("ita",n.getLocal("pA")),n.setLocal("itb",n.getLocal("pB")),n.setLocal("last",n.i32_add(n.getLocal("pA"),n.i32_mul(n.getLocal("nOut"),n.i32_const(i)))),n.block(n.loop(n.br_if(1,n.i32_eq(n.getLocal("ita"),n.getLocal("last"))),n.call(a+"_zero",n.getLocal("ita")),n.call(a+"_zero",n.getLocal("itb")),n.setLocal("ita",n.i32_add(n.getLocal("ita"),n.i32_const(i))),n.setLocal("itb",n.i32_add(n.getLocal("itb"),n.i32_const(i))),n.br(0))),n.setLocal("it",n.getLocal("pCoefs")),n.setLocal("last",n.i32_add(n.getLocal("pCoefs"),n.i32_mul(n.getLocal("nCoefs"),n.i32_const(i+12)))),n.block(n.loop(n.br_if(1,n.i32_eq(n.getLocal("it"),n.getLocal("last"))),n.setLocal("s",n.i32_load(n.getLocal("it"),8)),n.if(n.i32_or(n.i32_lt_u(n.getLocal("s"),n.getLocal("offsetWitness")),n.i32_ge_u(n.getLocal("s"),n.i32_add(n.getLocal("offsetWitness"),n.getLocal("nWitness")))),[...n.setLocal("it",n.i32_add(n.getLocal("it"),n.i32_const(i+12))),...n.br(1)]),n.setLocal("m",n.i32_load(n.getLocal("it"))),n.if(n.i32_eq(n.getLocal("m"),n.i32_const(0)),n.setLocal("pOut",n.getLocal("pA")),n.if(n.i32_eq(n.getLocal("m"),n.i32_const(1)),n.setLocal("pOut",n.getLocal("pB")),[...n.setLocal("it",n.i32_add(n.getLocal("it"),n.i32_const(i+12))),...n.br(1)])),n.setLocal("c",n.i32_load(n.getLocal("it"),4)),n.if(n.i32_or(n.i32_lt_u(n.getLocal("c"),n.getLocal("offsetOut")),n.i32_ge_u(n.getLocal("c"),n.i32_add(n.getLocal("offsetOut"),n.getLocal("nOut")))),[...n.setLocal("it",n.i32_add(n.getLocal("it"),n.i32_const(i+12))),...n.br(1)]),n.setLocal("pOut",n.i32_add(n.getLocal("pOut"),n.i32_mul(n.i32_sub(n.getLocal("c"),n.getLocal("offsetOut")),n.i32_const(i)))),n.call(a+"_mul",n.i32_add(n.getLocal("pWitness"),n.i32_mul(n.i32_sub(n.getLocal("s"),n.getLocal("offsetWitness")),n.i32_const(i))),n.i32_add(n.getLocal("it"),n.i32_const(12)),r),n.call(a+"_add",n.getLocal("pOut"),r,n.getLocal("pOut")),n.setLocal("it",n.i32_add(n.getLocal("it"),n.i32_const(i+12))),n.br(0))),n.setLocal("ita",n.getLocal("pA")),n.setLocal("itb",n.getLocal("pB")),n.setLocal("it",n.getLocal("pC")),n.setLocal("last",n.i32_add(n.getLocal("pA"),n.i32_mul(n.getLocal("nOut"),n.i32_const(i)))),n.block(n.loop(n.br_if(1,n.i32_eq(n.getLocal("ita"),n.getLocal("last"))),n.call(a+"_mul",n.getLocal("ita"),n.getLocal("itb"),n.getLocal("it")),n.setLocal("ita",n.i32_add(n.getLocal("ita"),n.i32_const(i))),n.setLocal("itb",n.i32_add(n.getLocal("itb"),n.i32_const(i))),n.setLocal("it",n.i32_add(n.getLocal("it"),n.i32_const(i))),n.br(0))))}(),function(){const o=t.addFunction(e+"_joinABC");o.addParam("pA","i32"),o.addParam("pB","i32"),o.addParam("pC","i32"),o.addParam("n","i32"),o.addParam("pP","i32"),o.addLocal("ita","i32"),o.addLocal("itb","i32"),o.addLocal("itc","i32"),o.addLocal("itp","i32"),o.addLocal("last","i32");const n=o.getCodeBuilder(),r=n.i32_const(t.alloc(i));o.addCode(n.setLocal("ita",n.getLocal("pA")),n.setLocal("itb",n.getLocal("pB")),n.setLocal("itc",n.getLocal("pC")),n.setLocal("itp",n.getLocal("pP")),n.setLocal("last",n.i32_add(n.getLocal("pA"),n.i32_mul(n.getLocal("n"),n.i32_const(i)))),n.block(n.loop(n.br_if(1,n.i32_eq(n.getLocal("ita"),n.getLocal("last"))),n.call(a+"_mul",n.getLocal("ita"),n.getLocal("itb"),r),n.call(a+"_sub",r,n.getLocal("itc"),n.getLocal("itp")),n.setLocal("ita",n.i32_add(n.getLocal("ita"),n.i32_const(i))),n.setLocal("itb",n.i32_add(n.getLocal("itb"),n.i32_const(i))),n.setLocal("itc",n.i32_add(n.getLocal("itc"),n.i32_const(i))),n.setLocal("itp",n.i32_add(n.getLocal("itp"),n.i32_const(i))),n.br(0))))}(),function(){const o=t.addFunction(e+"_batchAdd");o.addParam("pa","i32"),o.addParam("pb","i32"),o.addParam("n","i32"),o.addParam("pr","i32"),o.addLocal("ita","i32"),o.addLocal("itb","i32"),o.addLocal("itr","i32"),o.addLocal("last","i32");const n=o.getCodeBuilder();o.addCode(n.setLocal("ita",n.getLocal("pa")),n.setLocal("itb",n.getLocal("pb")),n.setLocal("itr",n.getLocal("pr")),n.setLocal("last",n.i32_add(n.getLocal("pa"),n.i32_mul(n.getLocal("n"),n.i32_const(i)))),n.block(n.loop(n.br_if(1,n.i32_eq(n.getLocal("ita"),n.getLocal("last"))),n.call(a+"_add",n.getLocal("ita"),n.getLocal("itb"),n.getLocal("itr")),n.setLocal("ita",n.i32_add(n.getLocal("ita"),n.i32_const(i))),n.setLocal("itb",n.i32_add(n.getLocal("itb"),n.i32_const(i))),n.setLocal("itr",n.i32_add(n.getLocal("itr"),n.i32_const(i))),n.br(0))))}(),t.exportFunction(e+"_buildABC"),t.exportFunction(e+"_joinABC"),t.exportFunction(e+"_batchAdd"),e},Kt=function(t,e,a,i,o,n,r,l){const c=t.addFunction(e);c.addParam("pIn","i32"),c.addParam("n","i32"),c.addParam("pFirst","i32"),c.addParam("pInc","i32"),c.addParam("pOut","i32"),c.addLocal("pOldFree","i32"),c.addLocal("i","i32"),c.addLocal("pFrom","i32"),c.addLocal("pTo","i32");const s=c.getCodeBuilder(),d=s.i32_const(t.alloc(r));c.addCode(s.setLocal("pFrom",s.getLocal("pIn")),s.setLocal("pTo",s.getLocal("pOut"))),c.addCode(s.call(i+"_copy",s.getLocal("pFirst"),d)),c.addCode(s.setLocal("i",s.i32_const(0)),s.block(s.loop(s.br_if(1,s.i32_eq(s.getLocal("i"),s.getLocal("n"))),s.call(l,s.getLocal("pFrom"),d,s.getLocal("pTo")),s.setLocal("pFrom",s.i32_add(s.getLocal("pFrom"),s.i32_const(o))),s.setLocal("pTo",s.i32_add(s.getLocal("pTo"),s.i32_const(n))),s.call(i+"_mul",d,s.getLocal("pInc"),d),s.setLocal("i",s.i32_add(s.getLocal("i"),s.i32_const(1))),s.br(0)))),t.exportFunction(e)},Vt=function(t,e){const a=e||"bn128";if(t.modules[a])return a;const i=u("21888242871839275222246405745257275088696311157297823662689037894645226208583"),o=u("21888242871839275222246405745257275088548364400416034343698204186575808495617"),n=Math.floor((i.minus(1).bitLength()-1)/64)+1,r=8*n,l=r,c=r,s=2*c,d=12*c,g=t.alloc(Et(o,l)),f=Ut(t,i,"f1m");zt(t,o,"fr","frm");const _=t.alloc(Et(A(u(3)),c)),p=Tt(t,"g1m","f1m",_);Rt(t,"frm","frm","frm","frm_mul"),Nt(t,"pol","frm"),Dt(t,"qap","frm");const h=qt(t,"f1m_neg","f2m","f1m"),m=t.alloc([...Et(A(u("19485874751759354771024239261021720505790618469301721065564631296452457478373")),c),...Et(A(u("266929791119991161246907387137283842545076965332900288569378510910307636690")),c)]),L=Tt(t,"g2m","f2m",m);function w(e,a){const i=t.addFunction(e);i.addParam("pG","i32"),i.addParam("pFr","i32"),i.addParam("pr","i32");const o=i.getCodeBuilder(),n=o.i32_const(t.alloc(r));i.addCode(o.call("frm_fromMontgomery",o.getLocal("pFr"),n),o.call(a,o.getLocal("pG"),n,o.i32_const(r),o.getLocal("pr"))),t.exportFunction(e)}function A(t){return u(t).times(u.one.shiftLeft(8*c)).mod(i)}w("g1m_timesFr","g1m_timesScalar"),Rt(t,"g1m","g1m","frm","g1m_timesFr"),w("g2m_timesFr","g2m_timesScalar"),Rt(t,"g2m","g2m","frm","g2m_timesFr"),w("g1m_timesFrAffine","g1m_timesScalarAffine"),w("g2m_timesFrAffine","g2m_timesScalarAffine"),Kt(t,"frm_batchApplyKey",0,"frm",r,r,r,"frm_mul"),Kt(t,"g1m_batchApplyKey",0,"frm",3*r,3*r,r,"g1m_timesFr"),Kt(t,"g1m_batchApplyKeyMixed",0,"frm",2*r,3*r,r,"g1m_timesFrAffine"),Kt(t,"g2m_batchApplyKey",0,"frm",2*r*3,3*r*2,r,"g2m_timesFr"),Kt(t,"g2m_batchApplyKeyMixed",0,"frm",2*r*2,3*r*2,r,"g2m_timesFrAffine");const b=[u("1"),u("2"),u.one],y=t.alloc([...Et(A(b[0]),c),...Et(A(b[1]),c),...Et(A(b[2]),c)]),I=[u.zero,u.one,u.zero],C=t.alloc([...Et(A(I[0]),c),...Et(A(I[1]),c),...Et(A(I[2]),c)]),F=[[u("10857046999023057135944570762232829481370756359578518086990519993285655852781"),u("11559732032986387107991004021392285783925812861821192530917403151452391805634")],[u("8495653923123431417604973247489272438418190587263600148770280649306958101930"),u("4082367875863433681332203403145435568316851327593401208105741076214120093531")],[u.one,u.zero]],x=t.alloc([...Et(A(F[0][0]),c),...Et(A(F[0][1]),c),...Et(A(F[1][0]),c),...Et(A(F[1][1]),c),...Et(A(F[2][0]),c),...Et(A(F[2][1]),c)]),v=[[u.zero,u.zero],[u.one,u.zero],[u.zero,u.zero]],E=t.alloc([...Et(A(v[0][0]),c),...Et(A(v[0][1]),c),...Et(A(v[1][0]),c),...Et(A(v[1][1]),c),...Et(A(v[2][0]),c),...Et(A(v[2][1]),c)]),B=t.alloc([...Et(A(1),c),...Et(A(0),c),...Et(A(0),c),...Et(A(0),c),...Et(A(0),c),...Et(A(0),c),...Et(A(0),c),...Et(A(0),c),...Et(A(0),c),...Et(A(0),c),...Et(A(0),c),...Et(A(0),c)]),S=t.alloc([...Et(A(9),c),...Et(A(1),c)]),G=t.alloc([...Et(A(u(2).modInv(i)),c),...Et(u(0),c)]),P=S,O=t.alloc([...Et(A("19485874751759354771024239261021720505790618469301721065564631296452457478373"),c),...Et(A("266929791119991161246907387137283842545076965332900288569378510910307636690"),c)]);!function(){const e=t.addFunction(a+"_mulNR6");e.addParam("x","i32"),e.addParam("pr","i32");const i=e.getCodeBuilder();e.addCode(i.call(h+"_mul",i.i32_const(S),i.getLocal("x"),i.getLocal("pr")))}();const U=Qt(t,a+"_mulNR6","f6m","f2m");!function(){const e=t.addFunction(a+"_mulNR12");e.addParam("x","i32"),e.addParam("pr","i32");const i=e.getCodeBuilder();e.addCode(i.call(h+"_mul",i.i32_const(S),i.i32_add(i.getLocal("x"),i.i32_const(4*r)),i.getLocal("pr")),i.call(h+"_copy",i.getLocal("x"),i.i32_add(i.getLocal("pr"),i.i32_const(2*r))),i.call(h+"_copy",i.i32_add(i.getLocal("x"),i.i32_const(2*r)),i.i32_add(i.getLocal("pr"),i.i32_const(4*r))))}();const z=qt(t,a+"_mulNR12","ftm",U),q=function(t){let e=t;const a=[];for(;e.gt(u.zero);)e.isOdd()?a.push(1):a.push(0),e=e.shiftRight(1);return a}(u("29793968203157093288")),Q=t.alloc(q),M=3*s,k=q.length-1,T=q.reduce(((t,e)=>t+(0!=e?1:0)),0),R=6*r,N=3*r*2+(T+k+1)*M;t.modules[a]={n64:n,pG1gen:y,pG1zero:C,pG1b:_,pG2gen:x,pG2zero:E,pG2b:m,pq:t.modules.f1m.pq,pr:g,pOneT:B,prePSize:R,preQSize:N,r:o.toString(),q:i.toString()};const D=u("4965661367192848881");function K(e){const o=[[[u("1"),u("0")],[u("1"),u("0")],[u("1"),u("0")],[u("1"),u("0")],[u("1"),u("0")],[u("1"),u("0")],[u("1"),u("0")],[u("1"),u("0")],[u("1"),u("0")],[u("1"),u("0")],[u("1"),u("0")],[u("1"),u("0")]],[[u("1"),u("0")],[u("8376118865763821496583973867626364092589906065868298776909617916018768340080"),u("16469823323077808223889137241176536799009286646108169935659301613961712198316")],[u("21888242871839275220042445260109153167277707414472061641714758635765020556617"),u("0")],[u("11697423496358154304825782922584725312912383441159505038794027105778954184319"),u("303847389135065887422783454877609941456349188919719272345083954437860409601")],[u("21888242871839275220042445260109153167277707414472061641714758635765020556616"),u("0")],[u("3321304630594332808241809054958361220322477375291206261884409189760185844239"),u("5722266937896532885780051958958348231143373700109372999374820235121374419868")],[u("21888242871839275222246405745257275088696311157297823662689037894645226208582"),u("0")],[u("13512124006075453725662431877630910996106405091429524885779419978626457868503"),u("5418419548761466998357268504080738289687024511189653727029736280683514010267")],[u("2203960485148121921418603742825762020974279258880205651966"),u("0")],[u("10190819375481120917420622822672549775783927716138318623895010788866272024264"),u("21584395482704209334823622290379665147239961968378104390343953940207365798982")],[u("2203960485148121921418603742825762020974279258880205651967"),u("0")],[u("18566938241244942414004596690298913868373833782006617400804628704885040364344"),u("16165975933942742336466353786298926857552937457188450663314217659523851788715")]]],n=[[[u("1"),u("0")],[u("1"),u("0")],[u("1"),u("0")],[u("1"),u("0")],[u("1"),u("0")],[u("1"),u("0")]],[[u("1"),u("0")],[u("21575463638280843010398324269430826099269044274347216827212613867836435027261"),u("10307601595873709700152284273816112264069230130616436755625194854815875713954")],[u("21888242871839275220042445260109153167277707414472061641714758635765020556616"),u("0")],[u("3772000881919853776433695186713858239009073593817195771773381919316419345261"),u("2236595495967245188281701248203181795121068902605861227855261137820944008926")],[u("2203960485148121921418603742825762020974279258880205651966"),u("0")],[u("18429021223477853657660792034369865839114504446431234726392080002137598044644"),u("9344045779998320333812420223237981029506012124075525679208581902008406485703")]],[[u("1"),u("0")],[u("2581911344467009335267311115468803099551665605076196740867805258568234346338"),u("19937756971775647987995932169929341994314640652964949448313374472400716661030")],[u("2203960485148121921418603742825762020974279258880205651966"),u("0")],[u("5324479202449903542726783395506214481928257762400643279780343368557297135718"),u("16208900380737693084919495127334387981393726419856888799917914180988844123039")],[u("21888242871839275220042445260109153167277707414472061641714758635765020556616"),u("0")],[u("13981852324922362344252311234282257507216387789820983642040889267519694726527"),u("7629828391165209371577384193250820201684255241773809077146787135900891633097")]]],r=t.addFunction(a+"__frobeniusMap"+e);r.addParam("x","i32"),r.addParam("r","i32");const l=r.getCodeBuilder();for(let a=0;a<6;a++){const i=0==a?l.getLocal("x"):l.i32_add(l.getLocal("x"),l.i32_const(a*s)),u=i,g=l.i32_add(l.getLocal("x"),l.i32_const(a*s+c)),_=0==a?l.getLocal("r"):l.i32_add(l.getLocal("r"),l.i32_const(a*s)),p=_,m=l.i32_add(l.getLocal("r"),l.i32_const(a*s+c)),L=d(o[Math.floor(a/3)][e%12],n[a%3][e%6]),w=t.alloc([...Et(A(L[0]),32),...Et(A(L[1]),32)]);e%2==1?r.addCode(l.call(f+"_copy",u,p),l.call(f+"_neg",g,m),l.call(h+"_mul",_,l.i32_const(w),_)):r.addCode(l.call(h+"_mul",i,l.i32_const(w),_))}function d(t,e){const a=u(t[0]),o=u(t[1]),n=u(e[0]),r=u(e[1]),l=[a.times(n).minus(o.times(r)).mod(i),a.times(r).add(o.times(n)).mod(i)];return l[0].isNegative()&&(l[0]=l[0].add(i)),l}}function V(e,i){const o=function(t){let e=t;const a=[];for(;e.gt(u.zero);){if(e.isOdd()){const t=2-e.mod(4).toJSNumber();a.push(t),e=e.minus(t)}else a.push(0);e=e.shiftRight(1)}return a}(e).map((t=>-1==t?255:t)),n=t.alloc(o);t.alloc(Et(e,32));const r=t.addFunction(a+"__cyclotomicExp_"+i);r.addParam("x","i32"),r.addParam("r","i32"),r.addLocal("bit","i32"),r.addLocal("i","i32");const l=r.getCodeBuilder(),c=l.getLocal("x"),s=l.getLocal("r"),g=l.i32_const(t.alloc(d));r.addCode(l.call(z+"_conjugate",c,g),l.call(z+"_one",s),l.if(l.teeLocal("bit",l.i32_load8_s(l.i32_const(o.length-1),n)),l.if(l.i32_eq(l.getLocal("bit"),l.i32_const(1)),l.call(z+"_mul",s,c,s),l.call(z+"_mul",s,g,s))),l.setLocal("i",l.i32_const(o.length-2)),l.block(l.loop(l.call(a+"__cyclotomicSquare",s,s),l.if(l.teeLocal("bit",l.i32_load8_s(l.getLocal("i"),n)),l.if(l.i32_eq(l.getLocal("bit"),l.i32_const(1)),l.call(z+"_mul",s,c,s),l.call(z+"_mul",s,g,s))),l.br_if(1,l.i32_eqz(l.getLocal("i"))),l.setLocal("i",l.i32_sub(l.getLocal("i"),l.i32_const(1))),l.br(0))))}function j(){!function(){const e=t.addFunction(a+"__cyclotomicSquare");e.addParam("x","i32"),e.addParam("r","i32");const i=e.getCodeBuilder(),o=i.getLocal("x"),n=i.i32_add(i.getLocal("x"),i.i32_const(s)),r=i.i32_add(i.getLocal("x"),i.i32_const(2*s)),l=i.i32_add(i.getLocal("x"),i.i32_const(3*s)),c=i.i32_add(i.getLocal("x"),i.i32_const(4*s)),d=i.i32_add(i.getLocal("x"),i.i32_const(5*s)),u=i.getLocal("r"),g=i.i32_add(i.getLocal("r"),i.i32_const(s)),f=i.i32_add(i.getLocal("r"),i.i32_const(2*s)),_=i.i32_add(i.getLocal("r"),i.i32_const(3*s)),p=i.i32_add(i.getLocal("r"),i.i32_const(4*s)),m=i.i32_add(i.getLocal("r"),i.i32_const(5*s)),L=i.i32_const(t.alloc(s)),w=i.i32_const(t.alloc(s)),A=i.i32_const(t.alloc(s)),b=i.i32_const(t.alloc(s)),y=i.i32_const(t.alloc(s)),I=i.i32_const(t.alloc(s)),C=i.i32_const(t.alloc(s)),F=i.i32_const(t.alloc(s));e.addCode(i.call(h+"_mul",o,c,C),i.call(h+"_mul",c,i.i32_const(S),L),i.call(h+"_add",o,L,L),i.call(h+"_add",o,c,F),i.call(h+"_mul",F,L,L),i.call(h+"_mul",i.i32_const(S),C,F),i.call(h+"_add",C,F,F),i.call(h+"_sub",L,F,L),i.call(h+"_add",C,C,w),i.call(h+"_mul",l,r,C),i.call(h+"_mul",r,i.i32_const(S),A),i.call(h+"_add",l,A,A),i.call(h+"_add",l,r,F),i.call(h+"_mul",F,A,A),i.call(h+"_mul",i.i32_const(S),C,F),i.call(h+"_add",C,F,F),i.call(h+"_sub",A,F,A),i.call(h+"_add",C,C,b),i.call(h+"_mul",n,d,C),i.call(h+"_mul",d,i.i32_const(S),y),i.call(h+"_add",n,y,y),i.call(h+"_add",n,d,F),i.call(h+"_mul",F,y,y),i.call(h+"_mul",i.i32_const(S),C,F),i.call(h+"_add",C,F,F),i.call(h+"_sub",y,F,y),i.call(h+"_add",C,C,I),i.call(h+"_sub",L,o,u),i.call(h+"_add",u,u,u),i.call(h+"_add",L,u,u),i.call(h+"_add",w,c,p),i.call(h+"_add",p,p,p),i.call(h+"_add",w,p,p),i.call(h+"_mul",I,i.i32_const(P),F),i.call(h+"_add",F,l,_),i.call(h+"_add",_,_,_),i.call(h+"_add",F,_,_),i.call(h+"_sub",y,r,f),i.call(h+"_add",f,f,f),i.call(h+"_add",y,f,f),i.call(h+"_sub",A,n,g),i.call(h+"_add",g,g,g),i.call(h+"_add",A,g,g),i.call(h+"_add",b,d,m),i.call(h+"_add",m,m,m),i.call(h+"_add",b,m,m))}(),V(D,"w0");const e=t.addFunction(a+"__finalExponentiationLastChunk");e.addParam("x","i32"),e.addParam("r","i32");const i=e.getCodeBuilder(),o=i.getLocal("x"),n=i.getLocal("r"),r=i.i32_const(t.alloc(d)),l=i.i32_const(t.alloc(d)),c=i.i32_const(t.alloc(d)),u=i.i32_const(t.alloc(d)),g=i.i32_const(t.alloc(d)),f=i.i32_const(t.alloc(d)),_=i.i32_const(t.alloc(d)),p=i.i32_const(t.alloc(d)),m=i.i32_const(t.alloc(d)),L=i.i32_const(t.alloc(d)),w=i.i32_const(t.alloc(d)),A=i.i32_const(t.alloc(d)),b=i.i32_const(t.alloc(d)),y=i.i32_const(t.alloc(d)),I=i.i32_const(t.alloc(d)),C=i.i32_const(t.alloc(d)),F=i.i32_const(t.alloc(d)),x=i.i32_const(t.alloc(d)),v=i.i32_const(t.alloc(d)),E=i.i32_const(t.alloc(d)),B=i.i32_const(t.alloc(d));e.addCode(i.call(a+"__cyclotomicExp_w0",o,r),i.call(z+"_conjugate",r,r),i.call(a+"__cyclotomicSquare",r,l),i.call(a+"__cyclotomicSquare",l,c),i.call(z+"_mul",c,l,u),i.call(a+"__cyclotomicExp_w0",u,g),i.call(z+"_conjugate",g,g),i.call(a+"__cyclotomicSquare",g,f),i.call(a+"__cyclotomicExp_w0",f,_),i.call(z+"_conjugate",_,_),i.call(z+"_conjugate",u,p),i.call(z+"_conjugate",_,m),i.call(z+"_mul",m,g,L),i.call(z+"_mul",L,p,w),i.call(z+"_mul",w,l,A),i.call(z+"_mul",w,g,b),i.call(z+"_mul",b,o,y),i.call(a+"__frobeniusMap1",A,I),i.call(z+"_mul",I,y,C),i.call(a+"__frobeniusMap2",w,F),i.call(z+"_mul",F,C,x),i.call(z+"_conjugate",o,v),i.call(z+"_mul",v,A,E),i.call(a+"__frobeniusMap3",E,B),i.call(z+"_mul",B,x,n))}const H=t.alloc(R),$=t.alloc(N);function Z(e){const i=t.addFunction(a+"_pairingEq"+e);for(let t=0;tt+(0!=e?1:0)),0),T=6*r,R=3*r*2+(k+M+1)*Q,N=u("15132376222941642752");function D(e){const a=[[[u("1"),u("0")],[u("1"),u("0")],[u("1"),u("0")],[u("1"),u("0")],[u("1"),u("0")],[u("1"),u("0")],[u("1"),u("0")],[u("1"),u("0")],[u("1"),u("0")],[u("1"),u("0")],[u("1"),u("0")],[u("1"),u("0")]],[[u("1"),u("0")],[u("3850754370037169011952147076051364057158807420970682438676050522613628423219637725072182697113062777891589506424760"),u("151655185184498381465642749684540099398075398968325446656007613510403227271200139370504932015952886146304766135027")],[u("793479390729215512621379701633421447060886740281060493010456487427281649075476305620758731620351"),u("0")],[u("2973677408986561043442465346520108879172042883009249989176415018091420807192182638567116318576472649347015917690530"),u("1028732146235106349975324479215795277384839936929757896155643118032610843298655225875571310552543014690878354869257")],[u("793479390729215512621379701633421447060886740281060493010456487427281649075476305620758731620350"),u("0")],[u("3125332594171059424908108096204648978570118281977575435832422631601824034463382777937621250592425535493320683825557"),u("877076961050607968509681729531255177986764537961432449499635504522207616027455086505066378536590128544573588734230")],[u("4002409555221667393417789825735904156556882819939007885332058136124031650490837864442687629129015664037894272559786"),u("0")],[u("151655185184498381465642749684540099398075398968325446656007613510403227271200139370504932015952886146304766135027"),u("3850754370037169011952147076051364057158807420970682438676050522613628423219637725072182697113062777891589506424760")],[u("4002409555221667392624310435006688643935503118305586438271171395842971157480381377015405980053539358417135540939436"),u("0")],[u("1028732146235106349975324479215795277384839936929757896155643118032610843298655225875571310552543014690878354869257"),u("2973677408986561043442465346520108879172042883009249989176415018091420807192182638567116318576472649347015917690530")],[u("4002409555221667392624310435006688643935503118305586438271171395842971157480381377015405980053539358417135540939437"),u("0")],[u("877076961050607968509681729531255177986764537961432449499635504522207616027455086505066378536590128544573588734230"),u("3125332594171059424908108096204648978570118281977575435832422631601824034463382777937621250592425535493320683825557")]]],o=[[[u("1"),u("0")],[u("1"),u("0")],[u("1"),u("0")],[u("1"),u("0")],[u("1"),u("0")],[u("1"),u("0")]],[[u("1"),u("0")],[u("0"),u("4002409555221667392624310435006688643935503118305586438271171395842971157480381377015405980053539358417135540939436")],[u("793479390729215512621379701633421447060886740281060493010456487427281649075476305620758731620350"),u("0")],[u("0"),u("1")],[u("4002409555221667392624310435006688643935503118305586438271171395842971157480381377015405980053539358417135540939436"),u("0")],[u("0"),u("793479390729215512621379701633421447060886740281060493010456487427281649075476305620758731620350")]],[[u("1"),u("0")],[u("4002409555221667392624310435006688643935503118305586438271171395842971157480381377015405980053539358417135540939437"),u("0")],[u("4002409555221667392624310435006688643935503118305586438271171395842971157480381377015405980053539358417135540939436"),u("0")],[u("4002409555221667393417789825735904156556882819939007885332058136124031650490837864442687629129015664037894272559786"),u("0")],[u("793479390729215512621379701633421447060886740281060493010456487427281649075476305620758731620350"),u("0")],[u("793479390729215512621379701633421447060886740281060493010456487427281649075476305620758731620351"),u("0")]]],n=t.addFunction(U+"_frobeniusMap"+e);n.addParam("x","i32"),n.addParam("r","i32");const s=n.getCodeBuilder();for(let i=0;i<6;i++){const u=0==i?s.getLocal("x"):s.i32_add(s.getLocal("x"),s.i32_const(i*c)),g=u,f=s.i32_add(s.getLocal("x"),s.i32_const(i*c+l)),_=0==i?s.getLocal("r"):s.i32_add(s.getLocal("r"),s.i32_const(i*c)),h=_,m=s.i32_add(s.getLocal("r"),s.i32_const(i*c+l)),w=d(a[Math.floor(i/3)][e%12],o[i%3][e%6]),A=t.alloc([...Et(y(w[0]),r),...Et(y(w[1]),r)]);e%2==1?n.addCode(s.call(p+"_copy",g,h),s.call(p+"_neg",f,m),s.call(L+"_mul",_,s.i32_const(A),_)):n.addCode(s.call(L+"_mul",u,s.i32_const(A),_))}function d(t,e){const a=u(t[0]),o=u(t[1]),n=u(e[0]),r=u(e[1]),l=[a.times(n).minus(o.times(r)).mod(i),a.times(r).add(o.times(n)).mod(i)];return l[0].isNegative()&&(l[0]=l[0].add(i)),l}}function K(e,i,o){const n=function(t){let e=t;const a=[];for(;e.gt(u.zero);){if(e.isOdd()){const t=2-e.mod(4).toJSNumber();a.push(t),e=e.minus(t)}else a.push(0);e=e.shiftRight(1)}return a}(e).map((t=>-1==t?255:t)),r=t.alloc(n),l=t.addFunction(a+"__cyclotomicExp_"+o);l.addParam("x","i32"),l.addParam("r","i32"),l.addLocal("bit","i32"),l.addLocal("i","i32");const c=l.getCodeBuilder(),d=c.getLocal("x"),g=c.getLocal("r"),f=c.i32_const(t.alloc(s));l.addCode(c.call(U+"_conjugate",d,f),c.call(U+"_one",g),c.if(c.teeLocal("bit",c.i32_load8_s(c.i32_const(n.length-1),r)),c.if(c.i32_eq(c.getLocal("bit"),c.i32_const(1)),c.call(U+"_mul",g,d,g),c.call(U+"_mul",g,f,g))),c.setLocal("i",c.i32_const(n.length-2)),c.block(c.loop(c.call(a+"__cyclotomicSquare",g,g),c.if(c.teeLocal("bit",c.i32_load8_s(c.getLocal("i"),r)),c.if(c.i32_eq(c.getLocal("bit"),c.i32_const(1)),c.call(U+"_mul",g,d,g),c.call(U+"_mul",g,f,g))),c.br_if(1,c.i32_eqz(c.getLocal("i"))),c.setLocal("i",c.i32_sub(c.getLocal("i"),c.i32_const(1))),c.br(0)))),i&&l.addCode(c.call(U+"_conjugate",g,g))}t.modules[a]={n64q:n,n64r:d,n8q:r,n8r:g,pG1gen:C,pG1zero:x,pG1b:h,pG2gen:E,pG2zero:S,pG2b:w,pq:t.modules.f1m.pq,pr:_,pOneT:G,r:o,q:i,prePSize:T,preQSize:R},function(){const e=t.addFunction(O+"_mul1");e.addParam("pA","i32"),e.addParam("pC1","i32"),e.addParam("pR","i32");const a=e.getCodeBuilder(),i=a.getLocal("pA"),o=a.i32_add(a.getLocal("pA"),a.i32_const(2*l)),n=a.i32_add(a.getLocal("pA"),a.i32_const(4*l)),r=a.getLocal("pC1"),c=a.getLocal("pR"),s=a.i32_add(a.getLocal("pR"),a.i32_const(2*l)),d=a.i32_add(a.getLocal("pR"),a.i32_const(4*l)),u=a.i32_const(t.alloc(2*l)),g=a.i32_const(t.alloc(2*l));e.addCode(a.call(L+"_add",i,o,u),a.call(L+"_add",o,n,g),a.call(L+"_mul",o,r,d),a.call(L+"_mul",g,r,c),a.call(L+"_sub",c,d,c),a.call(L+"_mulNR",c,c),a.call(L+"_mul",u,r,s),a.call(L+"_sub",s,d,s))}(),function(){const e=t.addFunction(O+"_mul01");e.addParam("pA","i32"),e.addParam("pC0","i32"),e.addParam("pC1","i32"),e.addParam("pR","i32");const a=e.getCodeBuilder(),i=a.getLocal("pA"),o=a.i32_add(a.getLocal("pA"),a.i32_const(2*l)),n=a.i32_add(a.getLocal("pA"),a.i32_const(4*l)),r=a.getLocal("pC0"),c=a.getLocal("pC1"),s=a.getLocal("pR"),d=a.i32_add(a.getLocal("pR"),a.i32_const(2*l)),u=a.i32_add(a.getLocal("pR"),a.i32_const(4*l)),g=a.i32_const(t.alloc(2*l)),f=a.i32_const(t.alloc(2*l)),_=a.i32_const(t.alloc(2*l)),p=a.i32_const(t.alloc(2*l));e.addCode(a.call(L+"_mul",i,r,g),a.call(L+"_mul",o,c,f),a.call(L+"_add",i,o,_),a.call(L+"_add",i,n,p),a.call(L+"_add",o,n,s),a.call(L+"_mul",s,c,s),a.call(L+"_sub",s,f,s),a.call(L+"_mulNR",s,s),a.call(L+"_add",s,g,s),a.call(L+"_add",r,c,d),a.call(L+"_mul",d,_,d),a.call(L+"_sub",d,g,d),a.call(L+"_sub",d,f,d),a.call(L+"_mul",p,r,u),a.call(L+"_sub",u,g,u),a.call(L+"_add",u,f,u))}(),function(){const e=t.addFunction(U+"_mul014");e.addParam("pA","i32"),e.addParam("pC0","i32"),e.addParam("pC1","i32"),e.addParam("pC4","i32"),e.addParam("pR","i32");const a=e.getCodeBuilder(),i=a.getLocal("pA"),o=a.i32_add(a.getLocal("pA"),a.i32_const(6*l)),n=a.getLocal("pC0"),r=a.getLocal("pC1"),c=a.getLocal("pC4"),s=a.i32_const(t.alloc(6*l)),d=a.i32_const(t.alloc(6*l)),u=a.i32_const(t.alloc(2*l)),g=a.getLocal("pR"),f=a.i32_add(a.getLocal("pR"),a.i32_const(6*l));e.addCode(a.call(O+"_mul01",i,n,r,s),a.call(O+"_mul1",o,c,d),a.call(L+"_add",r,c,u),a.call(O+"_add",o,i,f),a.call(O+"_mul01",f,n,u,f),a.call(O+"_sub",f,s,f),a.call(O+"_sub",f,d,f),a.call(O+"_copy",d,g),a.call(O+"_mulNR",g,g),a.call(O+"_add",g,s,g))}(),function(){const e=t.addFunction(a+"_ell");e.addParam("pP","i32"),e.addParam("pCoefs","i32"),e.addParam("pF","i32");const i=e.getCodeBuilder(),o=i.getLocal("pP"),n=i.i32_add(i.getLocal("pP"),i.i32_const(r)),c=i.getLocal("pF"),s=i.getLocal("pCoefs"),d=i.i32_add(i.getLocal("pCoefs"),i.i32_const(l)),u=i.i32_add(i.getLocal("pCoefs"),i.i32_const(2*l)),g=i.i32_add(i.getLocal("pCoefs"),i.i32_const(3*l)),f=i.i32_add(i.getLocal("pCoefs"),i.i32_const(4*l)),_=t.alloc(2*l),h=i.i32_const(_),m=i.i32_const(_),L=i.i32_const(_+l),w=t.alloc(2*l),A=i.i32_const(w),b=i.i32_const(w),y=i.i32_const(w+l);e.addCode(i.call(p+"_mul",s,n,m),i.call(p+"_mul",d,n,L),i.call(p+"_mul",u,o,b),i.call(p+"_mul",g,o,y),i.call(U+"_mul014",c,f,A,h,c))}();const V=t.alloc(T),j=t.alloc(R);function H(e){const i=t.addFunction(a+"_pairingEq"+e);for(let t=0;t{a[i]=t(e[i])})),a}return e},unstringifyBigInts:function t(e){if("string"==typeof e&&/^[0-9]+$/.test(e))return BigInt(e);if("string"==typeof e&&/^0x[0-9a-fA-F]+$/.test(e))return BigInt(e);if(Array.isArray(e))return e.map(t);if("object"==typeof e){if(null===e)return null;const a={};return Object.keys(e).forEach((i=>{a[i]=t(e[i])})),a}return e},beBuff2int:function(t){let e=BigInt(0),a=t.length,i=0;const o=new DataView(t.buffer,t.byteOffset,t.byteLength);for(;a>0;)a>=4?(a-=4,e+=BigInt(o.getUint32(a))<=2?(a-=2,e+=BigInt(o.getUint16(a))<0;)n-4>=0?(n-=4,o.setUint32(n,Number(a&BigInt(4294967295))),a>>=BigInt(32)):n-2>=0?(n-=2,o.setUint16(n,Number(a&BigInt(65535))),a>>=BigInt(16)):(n-=1,o.setUint8(n,Number(a&BigInt(255))),a>>=BigInt(8));if(a)throw new Error("Number does not fit in this length");return i},leBuff2int:function(t){let e=BigInt(0),a=0;const i=new DataView(t.buffer,t.byteOffset,t.byteLength);for(;a>=BigInt(32)):n+2<=e?(o.setUint16(Number(n,a&BigInt(65535)),!0),n+=2,a>>=BigInt(16)):(o.setUint8(Number(n,a&BigInt(255)),!0),n+=1,a>>=BigInt(8));if(a)throw new Error("Number does not fit in this length");return i},stringifyFElements:function t(e,a){if("bigint"==typeof a||void 0!==a.eq)return a.toString(10);if(a instanceof Uint8Array)return e.toString(e.e(a));if(Array.isArray(a))return a.map(t.bind(this,e));if("object"==typeof a){const i={};return Object.keys(a).forEach((o=>{i[o]=t(e,a[o])})),i}return a},unstringifyFElements:function t(e,a){if("string"==typeof a&&/^[0-9]+$/.test(a))return e.e(a);if("string"==typeof a&&/^0x[0-9a-fA-F]+$/.test(a))return e.e(a);if(Array.isArray(a))return a.map(t.bind(this,e));if("object"==typeof a){if(null===a)return null;const i={};return Object.keys(a).forEach((o=>{i[o]=t(e,a[o])})),i}return a}});var $t=Object.freeze({__proto__:null,stringifyBigInts:function t(e){if("bigint"==typeof e||void 0!==e.eq)return e.toString(10);if(Array.isArray(e))return e.map(t);if("object"==typeof e){const a={};return Object.keys(e).forEach((i=>{a[i]=t(e[i])})),a}return e},unstringifyBigInts:function t(e){if("string"==typeof e&&/^[0-9]+$/.test(e))return u(e);if("string"==typeof e&&/^0x[0-9a-fA-F]+$/.test(e))return u(e);if(Array.isArray(e))return e.map(t);if("object"==typeof e){const a={};return Object.keys(e).forEach((i=>{a[i]=t(e[i])})),a}return e},beBuff2int:function(t){let e=u.zero;for(let a=0;a=0;){let t=Number(a.and(u("255")));o[i]=t,i--,a=a.shiftRight(8)}if(!a.eq(u.zero))throw new Error("Number does not fit in this length");return o},leBuff2int:function(t){let e=u.zero;for(let a=0;a>=1;return a}Zt.bitReverse=function(t,e){return(Yt[t>>>24]|Yt[t>>>16&255]<<8|Yt[t>>>8&255]<<16|Yt[255&t]<<24)>>>32-e},Zt.log2=function(t){return(0!=(4294901760&t)?(t&=4294901760,16):0)|(0!=(4278255360&t)?(t&=4278255360,8):0)|(0!=(4042322160&t)?(t&=4042322160,4):0)|(0!=(3435973836&t)?(t&=3435973836,2):0)|0!=(2863311530&t)},Zt.buffReverseBits=function(t,e){const a=t.byteLength/e,i=Zt.log2(a);if(a!=1<a){const i=t.slice(o*e,(o+1)*e);t.set(t.slice(a*e,(a+1)*e),o*e),t.set(i,a*e)}}},Zt.array2buffer=function(t,e){const a=new Uint8Array(e*t.length);for(let i=0;i0;){const t=r+l>ge?ge-r:l,e=new Uint8Array(this.buffers[n].buffer,this.buffers[n].byteOffset+r,t);if(t==a)return e.slice();o||(o=a<=ge?new Uint8Array(a):new fe(a)),o.set(e,a-l),l-=t,n++,r=0}return o}set(t,e){void 0===e&&(e=0);const a=t.byteLength;if(0==a)return;const i=Math.floor(e/ge);if(i==Math.floor((e+a-1)/ge))return t instanceof fe&&1==t.buffers.length?this.buffers[i].set(t.buffers[0],e%ge):this.buffers[i].set(t,e%ge);let o=i,n=e%ge,r=a;for(;r>0;){const e=n+r>ge?ge-n:r,i=t.slice(a-r,a-r+e);new Uint8Array(this.buffers[o].buffer,this.buffers[o].byteOffset+n,e).set(i),r-=e,o++,n=0}}}function _e(t,e,a,i){return async function(o){const n=Math.floor(o.byteLength/a);if(n*a!==o.byteLength)throw new Error("Invalid buffer size");const r=Math.floor(n/t.concurrency),l=[];for(let c=0;c=0;t--)this.w[t]=this.square(this.w[t+1]);if(!this.eq(this.w[0],this.one))throw new Error("Error calculating roots of unity");this.batchToMontgomery=_e(t,e+"_batchToMontgomery",this.n8,this.n8),this.batchFromMontgomery=_e(t,e+"_batchFromMontgomery",this.n8,this.n8)}op2(t,e,a){return this.tm.setBuff(this.pOp1,e),this.tm.setBuff(this.pOp2,a),this.tm.instance.exports[this.prefix+t](this.pOp1,this.pOp2,this.pOp3),this.tm.getBuff(this.pOp3,this.n8)}op2Bool(t,e,a){return this.tm.setBuff(this.pOp1,e),this.tm.setBuff(this.pOp2,a),!!this.tm.instance.exports[this.prefix+t](this.pOp1,this.pOp2)}op1(t,e){return this.tm.setBuff(this.pOp1,e),this.tm.instance.exports[this.prefix+t](this.pOp1,this.pOp3),this.tm.getBuff(this.pOp3,this.n8)}op1Bool(t,e){return this.tm.setBuff(this.pOp1,e),!!this.tm.instance.exports[this.prefix+t](this.pOp1,this.pOp3)}add(t,e){return this.op2("_add",t,e)}eq(t,e){return this.op2Bool("_eq",t,e)}isZero(t){return this.op1Bool("_isZero",t)}sub(t,e){return this.op2("_sub",t,e)}neg(t){return this.op1("_neg",t)}inv(t){return this.op1("_inverse",t)}toMontgomery(t){return this.op1("_toMontgomery",t)}fromMontgomery(t){return this.op1("_fromMontgomery",t)}mul(t,e){return this.op2("_mul",t,e)}div(t,e){return this.tm.setBuff(this.pOp1,t),this.tm.setBuff(this.pOp2,e),this.tm.instance.exports[this.prefix+"_inverse"](this.pOp2,this.pOp2),this.tm.instance.exports[this.prefix+"_mul"](this.pOp1,this.pOp2,this.pOp3),this.tm.getBuff(this.pOp3,this.n8)}square(t){return this.op1("_square",t)}isSquare(t){return this.op1Bool("_isSquare",t)}sqrt(t){return this.op1("_sqrt",t)}exp(t,e){return e instanceof Uint8Array||(e=x(S(e))),this.tm.setBuff(this.pOp1,t),this.tm.setBuff(this.pOp2,e),this.tm.instance.exports[this.prefix+"_exp"](this.pOp1,this.pOp2,e.byteLength,this.pOp3),this.tm.getBuff(this.pOp3,this.n8)}isNegative(t){return this.op1Bool("_isNegative",t)}e(t,e){if(t instanceof Uint8Array)return t;let a=S(t,e);O(a)?(a=j(a),it(a,this.p)&&(a=X(a,this.p)),a=V(this.p,a)):it(a,this.p)&&(a=X(a,this.p));const i=re(a,this.n8);return this.toMontgomery(i)}toString(t,e){const a=this.fromMontgomery(t),i=I(a,0);return F(i,e)}fromRng(t){let e;const a=new Uint8Array(this.n8);do{e=v;for(let a=0;ai.buffer.byteLength){const o=i.buffer.byteLength/65536;let n=Math.floor((a[0]+t)/65536)+1;n>e&&(n=e),i.grow(n-o)}return o}function r(t){const e=n(t.byteLength);return c(e,t),e}function l(t,e){const a=new Uint8Array(i.buffer);return new Uint8Array(a.buffer,a.byteOffset+t,e)}function c(t,e){new Uint8Array(i.buffer).set(new Uint8Array(e),t)}function s(t){if("INIT"==t[0].cmd)return o(t[0]);const e={vars:[],out:[]},s=new Uint32Array(i.buffer,0,1)[0];for(let i=0;i{this.reject=e,this.resolve=t}))}}var Ie;const Ce="data:application/javascript;base64,"+(Ie="("+we.toString()+")(self)",globalThis.btoa(Ie));class Fe{constructor(){this.actionQueue=[],this.oldPFree=0}startSyncOp(){if(0!=this.oldPFree)throw new Error("Sync operation in progress");this.oldPFree=this.u32[0]}endSyncOp(){if(0==this.oldPFree)throw new Error("No sync operation in progress");this.u32[0]=this.oldPFree,this.oldPFree=0}postAction(t,e,a,i){if(this.working[t])throw new Error("Posting a job t a working worker");return this.working[t]=!0,this.pendingDeferreds[t]=i||new ye,this.workers[t].postMessage(e,a),this.pendingDeferreds[t].promise}processWorks(){for(let t=0;t0;t++)if(0==this.working[t]){const e=this.actionQueue.shift();this.postAction(t,e.data,e.transfers,e.deferred)}}queueAction(t,e){const a=new ye;if(this.singleThread){const e=this.taskManager(t);a.resolve(e)}else this.actionQueue.push({data:t,transfers:e,deferred:a}),this.processWorks();return a.promise}resetMemory(){this.u32[0]=this.initalPFree}allocBuff(t){const e=this.alloc(t.byteLength);return this.setBuff(e,t),e}getBuff(t,e){return this.u8.slice(t,t+e)}setBuff(t,e){this.u8.set(new Uint8Array(e),t)}alloc(t){for(;3&this.u32[0];)this.u32[0]++;const e=this.u32[0];return this.u32[0]+=t,e}async terminate(){for(let t=0;tsetTimeout(e,t))))}}function xe(t,e){const a=t[e],i=t.Fr,o=t.tm;t[e].batchApplyKey=async function(t,n,r,l,c){let s,d,u,g,f;if(l=l||"affine",c=c||"affine","G1"==e)"jacobian"==l?(u=3*a.F.n8,s="g1m_batchApplyKey"):(u=2*a.F.n8,s="g1m_batchApplyKeyMixed"),g=3*a.F.n8,"jacobian"==c?f=3*a.F.n8:(d="g1m_batchToAffine",f=2*a.F.n8);else if("G2"==e)"jacobian"==l?(u=3*a.F.n8,s="g2m_batchApplyKey"):(u=2*a.F.n8,s="g2m_batchApplyKeyMixed"),g=3*a.F.n8,"jacobian"==c?f=3*a.F.n8:(d="g2m_batchToAffine",f=2*a.F.n8);else{if("Fr"!=e)throw new Error("Invalid group: "+e);s="frm_batchApplyKey",u=a.n8,g=a.n8,f=a.n8}const _=Math.floor(t.byteLength/u),p=Math.floor(_/o.concurrency),h=[];r=i.e(r);let m=i.e(n);for(let e=0;e=0;t--){if(!a.isZero(p))for(let t=0;ts&&(p=s),p<1024&&(p=1024);const h=[];for(let e=0;e(l&&l.debug(`Multiexp end: ${c}: ${e}/${u}`),t))))}const m=await Promise.all(h);let L=a.zero;for(let t=m.length-1;t>=0;t--)L=a.add(L,m[t]);return L}a.multiExp=async function(t,e,a,i){return await n(t,e,"jacobian",a,i)},a.multiExpAffine=async function(t,e,a,i){return await n(t,e,"affine",a,i)}}function Be(t,e){const a=t[e],i=t.Fr,o=a.tm;async function n(t,l,c,s,d,u){c=c||"affine",s=s||"affine";let g,f,_,p,h,m,L,w;"G1"==e?("affine"==c?(g=2*a.F.n8,p="g1m_batchToJacobian"):g=3*a.F.n8,f=3*a.F.n8,l&&(w="g1m_fftFinal"),L="g1m_fftJoin",m="g1m_fftMix","affine"==s?(_=2*a.F.n8,h="g1m_batchToAffine"):_=3*a.F.n8):"G2"==e?("affine"==c?(g=2*a.F.n8,p="g2m_batchToJacobian"):g=3*a.F.n8,f=3*a.F.n8,l&&(w="g2m_fftFinal"),L="g2m_fftJoin",m="g2m_fftMix","affine"==s?(_=2*a.F.n8,h="g2m_batchToAffine"):_=3*a.F.n8):"Fr"==e&&(g=a.n8,f=a.n8,_=a.n8,l&&(w="frm_fftFinal"),m="frm_fftMix",L="frm_fftJoin");let A=!1;Array.isArray(t)?(t=le(t,g),A=!0):t=t.slice(0,t.byteLength);const b=t.byteLength/g,y=Xt(b);if(1<1<<28?new fe(2*u[0].byteLength):new Uint8Array(2*u[0].byteLength);return g.set(u[0]),g.set(u[1],u[0].byteLength),g}(t,c,s,d,u):await async function(t,e,a,o,l){let c,s;c=t.slice(0,t.byteLength/2),s=t.slice(t.byteLength/2,t.byteLength);const d=[];[c,s]=await r(c,s,"fftJoinExt",i.one,i.shift,e,"jacobian",o,l),d.push(n(c,!1,"jacobian",a,o,l)),d.push(n(s,!1,"jacobian",a,o,l));const u=await Promise.all(d);let g;g=u[0].byteLength>1<<28?new fe(2*u[0].byteLength):new Uint8Array(2*u[0].byteLength);return g.set(u[0]),g.set(u[1],u[0].byteLength),g}(t,c,s,d,u),A?ce(e,_):e}let I,C,F;l&&(I=i.inv(i.e(b))),te(t,g);let x=Math.min(16384,b),v=b/x;for(;v=16;)v*=2,x/=2;const E=Xt(x),B=[];for(let e=0;e(d&&d.debug(`${u}: fft ${y} mix end: ${e}/${v}`),t))))}F=await Promise.all(B);for(let t=0;t(d&&d.debug(`${u}: fft ${y} join ${t}/${y} ${r+1}/${e} ${l}/${a/2}`),i))))}const r=await Promise.all(n);for(let t=0;t0;e--)C.set(F[e],t),t+=x*_,delete F[e];C.set(F[0].slice(0,(x-1)*_),t),delete F[0]}else for(let t=0;t65536&&(A=65536);const b=[];for(let e=0;e(u&&u.debug(`${g}: fftJoinExt End: ${e}/${w}`),t))))}const y=await Promise.all(b);let I,C;w*h>1<<28?(I=new fe(w*h),C=new fe(w*h)):(I=new Uint8Array(w*h),C=new Uint8Array(w*h));let F=0;for(let t=0;ti.s+1)throw c&&c.error("lagrangeEvaluations input too big"),new Error("lagrangeEvaluations input too big");let f=t.slice(0,t.byteLength/2),_=t.slice(t.byteLength/2,t.byteLength);const p=i.exp(i.shift,u/2),h=i.inv(i.sub(i.one,p));[f,_]=await r(f,_,"prepareLagrangeEvaluation",h,i.shiftInv,o,"jacobian",c,s+" prep");const m=[];let L;return m.push(n(f,!0,"jacobian",l,c,s+" t0")),m.push(n(_,!0,"jacobian",l,c,s+" t1")),[f,_]=await Promise.all(m),L=f.byteLength>1<<28?new fe(2*f.byteLength):new Uint8Array(2*f.byteLength),L.set(f),L.set(_,f.byteLength),L},a.fftMix=async function(t){const n=3*a.F.n8;let r,l;if("G1"==e)r="g1m_fftMix",l="g1m_fftJoin";else if("G2"==e)r="g2m_fftMix",l="g2m_fftJoin";else{if("Fr"!=e)throw new Error("Invalid group");r="frm_fftMix",l="frm_fftJoin"}const c=Math.floor(t.byteLength/n),s=Xt(c);let d=1<=0;t--)f.set(g[t][0],_),_+=g[t][0].byteLength;return f}}async function Se(t){const e=await async function(t,e){const a=new Fe;a.memory=new WebAssembly.Memory({initial:25}),a.u8=new Uint8Array(a.memory.buffer),a.u32=new Uint32Array(a.memory.buffer);const i=await WebAssembly.compile(t.code);if(a.instance=await WebAssembly.instantiate(i,{env:{memory:a.memory}}),a.singleThread=e,a.initalPFree=a.u32[0],a.pq=t.pq,a.pr=t.pr,a.pG1gen=t.pG1gen,a.pG1zero=t.pG1zero,a.pG2gen=t.pG2gen,a.pG2zero=t.pG2zero,a.pOneT=t.pOneT,e)a.code=t.code,a.taskManager=we(),await a.taskManager([{cmd:"INIT",init:25,code:a.code.slice()}]),a.concurrency=1;else{let e;a.workers=[],a.pendingDeferreds=[],a.working=[],e="object"==typeof navigator&&navigator.hardwareConcurrency?navigator.hardwareConcurrency:Ae.cpus().length,0==e&&(e=2),e>64&&(e=64),a.concurrency=e;for(let t=0;t>6,128|63&i):i<55296||i>=57344?e.push(224|i>>12,128|i>>6&63,128|63&i):(a++,i=65536+((1023&i)<<10|1023&t.charCodeAt(a)),e.push(240|i>>18,128|i>>12&63,128|i>>6&63,128|63&i))}return e}(t);return[...Ue(e.length),...e]},qe=function t(e){if("string"==typeof e){let t=e.split("\n");for(let e=0;eke[t.type]))],...this.returnType?[1,ke[this.returnType]]:[0]]}getBody(){const t=this.locals.map((t=>[...Qe.varuint32(t.length),ke[t.type]])),e=[...Qe.varuint32(this.locals.length),...[].concat(...t),...this.code,11];return[...Qe.varuint32(e.length),...e]}addCode(...t){this.code.push(...[].concat(...t))}getCodeBuilder(){return new Me(this)}};var Re=class{constructor(){this.functions=[],this.functionIdxByName={},this.nImportFunctions=0,this.nInternalFunctions=0,this.memory={pagesSize:1,moduleName:"env",fieldName:"memory"},this.free=8,this.datas=[],this.modules={},this.exports=[],this.functionsTable=[]}build(){return this._setSignatures(),new Uint8Array([...Qe.u32(1836278016),...Qe.u32(1),...this._buildType(),...this._buildImport(),...this._buildFunctionDeclarations(),...this._buildFunctionsTable(),...this._buildExports(),...this._buildElements(),...this._buildCode(),...this._buildData()])}addFunction(t){if(void 0!==this.functionIdxByName[t])throw new Error(`Function already defined: ${t}`);const e=this.functions.length;return this.functionIdxByName[t]=e,this.functions.push(new Te(this,t,"internal")),this.nInternalFunctions++,this.functions[e]}addIimportFunction(t,e,a){if(void 0!==this.functionIdxByName[t])throw new Error(`Function already defined: ${t}`);if(this.functions.length>0&&"internal"==this.functions[this.functions.length-1].type)throw new Error(`Import functions must be declared before internal: ${t}`);let i=a||t;const o=this.functions.length;return this.functionIdxByName[t]=o,this.functions.push(new Te(this,t,"import",e,i)),this.nImportFunctions++,this.functions[o]}setMemory(t,e,a){this.memory={pagesSize:t,moduleName:e||"env",fieldName:a||"memory"}}exportFunction(t,e){const a=e||t;if(void 0===this.functionIdxByName[t])throw new Error(`Function not defined: ${t}`);const i=this.functionIdxByName[t];a!=t&&(this.functionIdxByName[a]=i),this.exports.push({exportName:a,idx:i})}addFunctionToTable(t){const e=this.functionIdxByName[t];this.functionsTable.push(e)}addData(t,e){this.datas.push({offset:t,bytes:e})}alloc(t,e){let a,i;(Array.isArray(t)||ArrayBuffer.isView(t))&&void 0===e?(a=t.length,i=t):(a=t,i=e),a=1+(a-1>>3)<<3;const o=this.free;return this.free+=a,i&&this.addData(o,i),o}allocString(t){const e=(new globalThis.TextEncoder).encode(t);return this.alloc([...e,0])}_setSignatures(){this.signatures=[];const t={};if(this.functionsTable.length>0){const e=this.functions[this.functionsTable[0]].getSignature();t["s_"+Qe.toHexString(e)]=0,this.signatures.push(e)}for(let e=0;e{e.pendingLoads.push({page:t,resolve:a,reject:i})}));return e.__statusPage("After Load request: ",t),a}__statusPage(t,e){const a=[],i=this;if(!i.logHistory)return;a.push("=="+t+" "+e);let o="";for(let t=0;t "+e.history[t][a][i])}_triggerLoad(){const t=this;if(t.reading)return;if(0==t.pendingLoads.length)return;const e=Object.keys(t.pages),a=[];for(let i=0;i0&&(void 0!==t.pages[t.pendingLoads[0].page]||i>0||a.length>0);){const e=t.pendingLoads.shift();if(void 0!==t.pages[e.page]){t.pages[e.page].pendingOps++;const i=a.indexOf(e.page);i>=0&&a.splice(i,1),t.pages[e.page].loading?t.pages[e.page].loading.push(e):e.resolve(),t.__statusPage("After Load (cached): ",e.page)}else{if(i)i--;else{const e=a.shift();t.__statusPage("Before Unload: ",e),t.avBuffs.unshift(t.pages[e]),delete t.pages[e],t.__statusPage("After Unload: ",e)}e.page>=t.totalPages?(t.pages[e.page]=n(),e.resolve(),t.__statusPage("After Load (new): ",e.page)):(t.reading=!0,t.pages[e.page]=n(),t.pages[e.page].loading=[e],o.push(t.fd.read(t.pages[e.page].buff,0,t.pageSize,e.page*t.pageSize).then((a=>{t.pages[e.page].size=a.bytesRead;const i=t.pages[e.page].loading;delete t.pages[e.page].loading;for(let t=0;t{e.reject(t)}))),t.__statusPage("After Load (loading): ",e.page))}}function n(){if(t.avBuffs.length>0){const e=t.avBuffs.shift();return e.dirty=!1,e.pendingOps=1,e.size=0,e}return{dirty:!1,buff:new Uint8Array(t.pageSize),pendingOps:1,size:0}}Promise.all(o).then((()=>{t.reading=!1,t.pendingLoads.length>0&&setImmediate(t._triggerLoad.bind(t)),t._tryClose()}))}_triggerWrite(){const t=this;if(t.writing)return;const e=Object.keys(t.pages),a=[];for(let i=0;i{o.writing=!1}),(e=>{console.log("ERROR Writing: "+e),t.error=e,t._tryClose()}))))}t.writing&&Promise.all(a).then((()=>{t.writing=!1,setImmediate(t._triggerWrite.bind(t)),t._tryClose(),t.pendingLoads.length>0&&setImmediate(t._triggerLoad.bind(t))}))}_getDirtyPage(){for(let t in this.pages)if(this.pages[t].dirty)return t;return-1}async write(t,e){if(0==t.byteLength)return;const a=this;if(void 0===e&&(e=a.pos),a.pos=e+t.byteLength,a.totalSize0;){await n[r-i];const e=l+c>a.pageSize?a.pageSize-l:c,o=t.slice(t.byteLength-c,t.byteLength-c+e);new Uint8Array(a.pages[r].buff.buffer,l,e).set(o),a.pages[r].dirty=!0,a.pages[r].pendingOps--,a.pages[r].size=Math.max(l+e,a.pages[r].size),r>=a.totalPages&&(a.totalPages=r+1),c-=e,r++,l=0,a.writing||setImmediate(a._triggerWrite.bind(a))}}async read(t,e){let a=new Uint8Array(t);return await this.readToBuffer(a,0,t,e),a}async readToBuffer(t,e,a,i){if(0==a)return;const o=this;if(a>o.pageSize*o.maxPagesLoaded*.8){const t=Math.floor(1.1*a);this.maxPagesLoaded=Math.floor(t/o.pageSize)+1}if(void 0===i&&(i=o.pos),o.pos=i+a,o.pendingClose)throw new Error("Reading a closing file");const n=Math.floor(i/o.pageSize),r=Math.floor((i+a-1)/o.pageSize),l=[];for(let t=n;t<=r;t++)l.push(o._loadPage(t));o._triggerLoad();let c=n,s=i%o.pageSize,d=i+a>o.totalSize?a-(i+a-o.totalSize):a;for(;d>0;){await l[c-n],o.__statusPage("After Await (read): ",c);const i=s+d>o.pageSize?o.pageSize-s:d,r=new Uint8Array(o.pages[c].buff.buffer,o.pages[c].buff.byteOffset+s,i);t.set(r,e+a-d),o.pages[c].pendingOps--,o.__statusPage("After Op done: ",c),d-=i,c++,s=0,o.pendingLoads.length>0&&setImmediate(o._triggerLoad.bind(o))}this.pos=i+a}_tryClose(){const t=this;if(!t.pendingClose)return;t.error&&t.pendingCloseReject(t.error);t._getDirtyPage()>=0||t.writing||t.reading||t.pendingLoads.length>0||t.pendingClose()}close(){const t=this;if(t.pendingClose)throw new Error("Closing the file twice");return new Promise(((e,a)=>{t.pendingClose=e,t.pendingCloseReject=a,t._tryClose()})).then((()=>{t.fd.close()}),(e=>{throw t.fd.close(),e}))}async discard(){await this.close(),await Ze.promises.unlink(this.fileName)}async writeULE32(t,e){const a=new Uint8Array(4);new DataView(a.buffer).setUint32(0,t,!0),await this.write(a,e)}async writeUBE32(t,e){const a=new Uint8Array(4);new DataView(a.buffer).setUint32(0,t,!1),await this.write(a,e)}async writeULE64(t,e){const a=new Uint8Array(8),i=new DataView(a.buffer);i.setUint32(0,4294967295&t,!0),i.setUint32(4,Math.floor(t/4294967296),!0),await this.write(a,e)}async readULE32(t){const e=await this.read(4,t);return new Uint32Array(e.buffer)[0]}async readUBE32(t){const e=await this.read(4,t);return new DataView(e.buffer).getUint32(0,!1)}async readULE64(t){const e=await this.read(8,t),a=new Uint32Array(e.buffer);return 4294967296*a[1]+a[0]}}const We=new Uint8Array(4),Xe=new DataView(We.buffer),ta=new Uint8Array(8),ea=new DataView(ta.buffer);class aa{constructor(){this.pageSize=16384}_resizeIfNeeded(t){if(t>this.allocSize){const e=Math.max(this.allocSize+(1<<20),Math.floor(1.1*this.allocSize),t),a=new Uint8Array(e);a.set(this.o.data),this.o.data=a,this.allocSize=e}}async write(t,e){if(void 0===e&&(e=this.pos),this.readOnly)throw new Error("Writing a read only file");this._resizeIfNeeded(e+t.byteLength),this.o.data.set(t.slice(),e),e+t.byteLength>this.totalSize&&(this.totalSize=e+t.byteLength),this.pos=e+t.byteLength}async readToBuffer(t,e,a,i){if(void 0===i&&(i=this.pos),this.readOnly&&i+a>this.totalSize)throw new Error("Reading out of bounds");this._resizeIfNeeded(i+a);const o=new Uint8Array(this.o.data.buffer,this.o.data.byteOffset+i,a);t.set(o,e),this.pos=i+a}async read(t,e){const a=new Uint8Array(t);return await this.readToBuffer(a,0,t,e),a}close(){this.o.data.byteLength!=this.totalSize&&(this.o.data=this.o.data.slice(0,this.totalSize))}async discard(){}async writeULE32(t,e){Xe.setUint32(0,t,!0),await this.write(We,e)}async writeUBE32(t,e){Xe.setUint32(0,t,!1),await this.write(We,e)}async writeULE64(t,e){ea.setUint32(0,4294967295&t,!0),ea.setUint32(4,Math.floor(t/4294967296),!0),await this.write(ta,e)}async readULE32(t){const e=await this.read(4,t);return new Uint32Array(e.buffer)[0]}async readUBE32(t){const e=await this.read(4,t);return new DataView(e.buffer).getUint32(0,!1)}async readULE64(t){const e=await this.read(8,t),a=new Uint32Array(e.buffer);return 4294967296*a[1]+a[0]}}const ia=1<<22;const oa=new Uint8Array(4),na=new DataView(oa.buffer),ra=new Uint8Array(8),la=new DataView(ra.buffer);class ca{constructor(){this.pageSize=16384}_resizeIfNeeded(t){if(t<=this.totalSize)return;if(this.readOnly)throw new Error("Reading out of file bounds");const e=Math.floor((t-1)/ia)+1;for(let a=Math.max(this.o.data.length-1,0);a0;){const e=o+n>ia?ia-o:n,r=t.slice(t.byteLength-n,t.byteLength-n+e);new Uint8Array(a.o.data[i].buffer,o,e).set(r),n-=e,i++,o=0}this.pos=e+t.byteLength}async readToBuffer(t,e,a,i){const o=this;if(void 0===i&&(i=o.pos),this.readOnly&&i+a>this.totalSize)throw new Error("Reading out of bounds");this._resizeIfNeeded(i+a);let n=Math.floor(i/ia),r=i%ia,l=a;for(;l>0;){const i=r+l>ia?ia-r:l,c=new Uint8Array(o.o.data[n].buffer,r,i);t.set(c,e+a-l),l-=i,n++,r=0}this.pos=i+a}async read(t,e){const a=new Uint8Array(t);return await this.readToBuffer(a,0,t,e),a}close(){}async discard(){}async writeULE32(t,e){na.setUint32(0,t,!0),await this.write(oa,e)}async writeUBE32(t,e){na.setUint32(0,t,!1),await this.write(oa,e)}async writeULE64(t,e){la.setUint32(0,4294967295&t,!0),la.setUint32(4,Math.floor(t/4294967296),!0),await this.write(ra,e)}async readULE32(t){const e=await this.read(4,t);return new Uint32Array(e.buffer)[0]}async readUBE32(t){const e=await this.read(4,t);return new DataView(e.buffer).getUint32(0,!1)}async readULE64(t){const e=await this.read(8,t),a=new Uint32Array(e.buffer);return 4294967296*a[1]+a[0]}}async function sa(t,e,a){if("string"==typeof t&&(t={type:"file",fileName:t,cacheSize:e||65536,pageSize:a||8192}),"file"==t.type)return await Ye(t.fileName,"w+",t.cacheSize,t.pageSize);if("mem"==t.type)return function(t){const e=t.initialSize||1<<20,a=new aa;return a.o=t,a.o.data=new Uint8Array(e),a.allocSize=e,a.totalSize=0,a.readOnly=!1,a.pos=0,a}(t);if("bigMem"==t.type)return function(t){const e=t.initialSize||0,a=new ca;a.o=t;const i=e?Math.floor((e-1)/ia)+1:0;a.o.data=[];for(let t=0;ta)throw new Error("Version not supported");const c=await n.readULE32();let s=[];for(let t=0;t1)throw new Error(t.fileName+": Section Duplicated "+a);t.pos=e[a][0].p,t.readingSection=e[a][0]}async function ha(t,e){if(void 0===t.readingSection)throw new Error("Not reading a section");if(!e&&t.pos-t.readingSection.p!=t.readingSection.size)throw new Error("Invalid section size reading");delete t.readingSection}async function ma(t,e,a,i){const o=new Uint8Array(a);He.toRprLE(o,0,e,a),await t.write(o,i)}async function La(t,e,a){const i=await t.read(e,a);return He.fromRprLE(i,0,e)}async function wa(t,e,a,i,o){void 0===o&&(o=e[i][0].size);const n=t.pageSize;await pa(t,e,i),await fa(a,i);for(let e=0;ee[a][0].size)throw new Error("Reading out of the range of the section");let n;return n=o<1<<30?new Uint8Array(o):new fe(o),await t.readToBuffer(n,0,o,e[a][0].p+i),n}async function ba(t,e,a,i,o){const n=16*t.pageSize;if(await pa(t,e,o),await pa(a,i,o),e[o][0].size!=i[o][0].size)return!1;const r=e[o][0].size;for(let e=0;e=0)e=await De();else{if(!(["BLS12381"].indexOf(a)>=0))throw new Error(`Curve not supported: ${t}`);e=await Ke()}return e}var xa=function t(e,a){if(!e){var i=new va(a);throw Error.captureStackTrace&&Error.captureStackTrace(i,t),i}};class va extends Error{}function Ea(t){return t.length}va.prototype.name="AssertionError";var Ba={byteLength:Ea,toString:function(t){const e=t.byteLength;let a="";for(let i=0;i1&&61===t.charCodeAt(e-1)&&e--,3*e>>>2}Ga[45]=62,Ga[95]=63;var Oa={byteLength:Pa,toString:function(t){const e=t.byteLength;let a="";for(let i=0;i>2]+Sa[(3&t[i])<<4|t[i+1]>>4]+Sa[(15&t[i+1])<<2|t[i+2]>>6]+Sa[63&t[i+2]];return e%3==2?a=a.substring(0,a.length-1)+"=":e%3==1&&(a=a.substring(0,a.length-2)+"=="),a},write:function(t,e,a=0,i=Pa(e)){const o=Math.min(i,t.byteLength-a);for(let a=0,i=0;a>4,t[i++]=(15&n)<<4|r>>2,t[i++]=(3&r)<<6|63&l}return o}};function Ua(t){return t.length>>>1}var za={byteLength:Ua,toString:function(t){const e=t.byteLength;t=new DataView(t.buffer,t.byteOffset,e);let a="",i=0;for(let o=e-e%4;i=48&&t<=57?t-48:t>=65&&t<=70?t-65+10:t>=97&&t<=102?t-97+10:void 0}function Qa(t){let e=0;for(let a=0,i=t.length;a=55296&&o<=56319&&a+1=56320&&i<=57343){e+=4,a++;continue}}e+=o<=127?1:o<=2047?2:3}return e}let Ma,ka;if("undefined"!=typeof TextDecoder){const t=new TextDecoder;Ma=function(e){return t.decode(e)}}else Ma=function(t){const e=t.byteLength;let a="",i=0;for(;i0){let e=0;for(;e>i,i-=6;i>=0;)t[r++]=128|a>>i&63,i-=6;n+=a>=65536?2:1}return o};var Ta={byteLength:Qa,toString:Ma,write:ka};function Ra(t){return 2*t.length}var Na={byteLength:Ra,toString:function(t){const e=t.byteLength;let a="";for(let i=0;i>8,r=o%256;t[a+2*i]=r,t[a+2*i+1]=n}return o}};function Da(t){switch(t){case"ascii":return Ba;case"base64":return Oa;case"hex":return za;case"utf8":case"utf-8":case void 0:return Ta;case"ucs2":case"ucs-2":case"utf16le":case"utf-16le":return Na;default:throw new Error(`Unknown encoding: ${t}`)}}function Ka(t){return t instanceof Uint8Array}function Va(t,e,a){return"string"==typeof t?function(t,e){const a=Da(e),i=new Uint8Array(a.byteLength(t));return a.write(i,t,0,i.byteLength),i}(t,e):Array.isArray(t)?function(t){const e=new Uint8Array(t.length);return e.set(t),e}(t):ArrayBuffer.isView(t)?function(t){const e=new Uint8Array(t.byteLength);return e.set(t),e}(t):function(t,e,a){return new Uint8Array(t,e,a)}(t,e,a)}function ja(t,e,a){const i=t[e];t[e]=t[a],t[a]=i}var Ha={isBuffer:Ka,alloc:function(t,e,a){const i=new Uint8Array(t);return void 0!==e&&e(i,e,0,i.byteLength,a),i},allocUnsafe:function(t){return new Uint8Array(t)},allocUnsafeSlow:function(t){return new Uint8Array(t)},byteLength:function(t,e){return Da(e).byteLength(t)},compare:function(t,e){if(t===e)return 0;const a=Math.min(t.byteLength,e.byteLength);t=new DataView(t.buffer,t.byteOffset,t.byteLength),e=new DataView(e.buffer,e.byteOffset,e.byteLength);let i=0;for(let o=a-a%4;io)return 1}for(;io)return 1}return t.byteLength>e.byteLength?1:t.byteLengtht+e.byteLength),0));const a=new Uint8Array(e);return t.reduce(((t,e)=>(a.set(e,t),t+e.byteLength)),0),a},copy:function(t,e,a=0,i=0,o=t.byteLength){if(o>0&&o=t.byteLength)throw new RangeError("sourceStart is out of range");if(o<0)throw new RangeError("sourceEnd is out of range");a>=e.byteLength&&(a=e.byteLength),o>t.byteLength&&(o=t.byteLength),e.byteLength-a=o||i<=a?"":(a<0&&(a=0),i>o&&(i=o),(0!==a||i{for(var t=new Uint8Array(128),e=0;e<64;e++)t[e<26?e+65:e<52?e+71:e<62?e-4:4*e-205]=e;return e=>{for(var a=e.length,i=new Uint8Array(3*(a-("="==e[a-1])-("="==e[a-2]))/4|0),o=0,n=0;o>4,i[n++]=l<<4|c>>2,i[n++]=c<<6|s}return i}})(),Za=((t,e)=>function(){return e||(0,t[Object.keys(t)[0]])((e={exports:{}}).exports,e),e.exports})({"wasm-binary:./blake2b.wat"(t,e){e.exports=$a("AGFzbQEAAAABEANgAn9/AGADf39/AGABfwADBQQAAQICBQUBAQroBwdNBQZtZW1vcnkCAAxibGFrZTJiX2luaXQAAA5ibGFrZTJiX3VwZGF0ZQABDWJsYWtlMmJfZmluYWwAAhBibGFrZTJiX2NvbXByZXNzAAMKvz8EwAIAIABCADcDACAAQgA3AwggAEIANwMQIABCADcDGCAAQgA3AyAgAEIANwMoIABCADcDMCAAQgA3AzggAEIANwNAIABCADcDSCAAQgA3A1AgAEIANwNYIABCADcDYCAAQgA3A2ggAEIANwNwIABCADcDeCAAQoiS853/zPmE6gBBACkDAIU3A4ABIABCu86qptjQ67O7f0EIKQMAhTcDiAEgAEKr8NP0r+68tzxBECkDAIU3A5ABIABC8e30+KWn/aelf0EYKQMAhTcDmAEgAELRhZrv+s+Uh9EAQSApAwCFNwOgASAAQp/Y+dnCkdqCm39BKCkDAIU3A6gBIABC6/qG2r+19sEfQTApAwCFNwOwASAAQvnC+JuRo7Pw2wBBOCkDAIU3A7gBIABCADcDwAEgAEIANwPIASAAQgA3A9ABC20BA38gAEHAAWohAyAAQcgBaiEEIAQpAwCnIQUCQANAIAEgAkYNASAFQYABRgRAIAMgAykDACAFrXw3AwBBACEFIAAQAwsgACAFaiABLQAAOgAAIAVBAWohBSABQQFqIQEMAAsLIAQgBa03AwALYQEDfyAAQcABaiEBIABByAFqIQIgASABKQMAIAIpAwB8NwMAIABCfzcD0AEgAikDAKchAwJAA0AgA0GAAUYNASAAIANqQQA6AAAgA0EBaiEDDAALCyACIAOtNwMAIAAQAwuqOwIgfgl/IABBgAFqISEgAEGIAWohIiAAQZABaiEjIABBmAFqISQgAEGgAWohJSAAQagBaiEmIABBsAFqIScgAEG4AWohKCAhKQMAIQEgIikDACECICMpAwAhAyAkKQMAIQQgJSkDACEFICYpAwAhBiAnKQMAIQcgKCkDACEIQoiS853/zPmE6gAhCUK7zqqm2NDrs7t/IQpCq/DT9K/uvLc8IQtC8e30+KWn/aelfyEMQtGFmu/6z5SH0QAhDUKf2PnZwpHagpt/IQ5C6/qG2r+19sEfIQ9C+cL4m5Gjs/DbACEQIAApAwAhESAAKQMIIRIgACkDECETIAApAxghFCAAKQMgIRUgACkDKCEWIAApAzAhFyAAKQM4IRggACkDQCEZIAApA0ghGiAAKQNQIRsgACkDWCEcIAApA2AhHSAAKQNoIR4gACkDcCEfIAApA3ghICANIAApA8ABhSENIA8gACkD0AGFIQ8gASAFIBF8fCEBIA0gAYVCIIohDSAJIA18IQkgBSAJhUIYiiEFIAEgBSASfHwhASANIAGFQhCKIQ0gCSANfCEJIAUgCYVCP4ohBSACIAYgE3x8IQIgDiAChUIgiiEOIAogDnwhCiAGIAqFQhiKIQYgAiAGIBR8fCECIA4gAoVCEIohDiAKIA58IQogBiAKhUI/iiEGIAMgByAVfHwhAyAPIAOFQiCKIQ8gCyAPfCELIAcgC4VCGIohByADIAcgFnx8IQMgDyADhUIQiiEPIAsgD3whCyAHIAuFQj+KIQcgBCAIIBd8fCEEIBAgBIVCIIohECAMIBB8IQwgCCAMhUIYiiEIIAQgCCAYfHwhBCAQIASFQhCKIRAgDCAQfCEMIAggDIVCP4ohCCABIAYgGXx8IQEgECABhUIgiiEQIAsgEHwhCyAGIAuFQhiKIQYgASAGIBp8fCEBIBAgAYVCEIohECALIBB8IQsgBiALhUI/iiEGIAIgByAbfHwhAiANIAKFQiCKIQ0gDCANfCEMIAcgDIVCGIohByACIAcgHHx8IQIgDSAChUIQiiENIAwgDXwhDCAHIAyFQj+KIQcgAyAIIB18fCEDIA4gA4VCIIohDiAJIA58IQkgCCAJhUIYiiEIIAMgCCAefHwhAyAOIAOFQhCKIQ4gCSAOfCEJIAggCYVCP4ohCCAEIAUgH3x8IQQgDyAEhUIgiiEPIAogD3whCiAFIAqFQhiKIQUgBCAFICB8fCEEIA8gBIVCEIohDyAKIA98IQogBSAKhUI/iiEFIAEgBSAffHwhASANIAGFQiCKIQ0gCSANfCEJIAUgCYVCGIohBSABIAUgG3x8IQEgDSABhUIQiiENIAkgDXwhCSAFIAmFQj+KIQUgAiAGIBV8fCECIA4gAoVCIIohDiAKIA58IQogBiAKhUIYiiEGIAIgBiAZfHwhAiAOIAKFQhCKIQ4gCiAOfCEKIAYgCoVCP4ohBiADIAcgGnx8IQMgDyADhUIgiiEPIAsgD3whCyAHIAuFQhiKIQcgAyAHICB8fCEDIA8gA4VCEIohDyALIA98IQsgByALhUI/iiEHIAQgCCAefHwhBCAQIASFQiCKIRAgDCAQfCEMIAggDIVCGIohCCAEIAggF3x8IQQgECAEhUIQiiEQIAwgEHwhDCAIIAyFQj+KIQggASAGIBJ8fCEBIBAgAYVCIIohECALIBB8IQsgBiALhUIYiiEGIAEgBiAdfHwhASAQIAGFQhCKIRAgCyAQfCELIAYgC4VCP4ohBiACIAcgEXx8IQIgDSAChUIgiiENIAwgDXwhDCAHIAyFQhiKIQcgAiAHIBN8fCECIA0gAoVCEIohDSAMIA18IQwgByAMhUI/iiEHIAMgCCAcfHwhAyAOIAOFQiCKIQ4gCSAOfCEJIAggCYVCGIohCCADIAggGHx8IQMgDiADhUIQiiEOIAkgDnwhCSAIIAmFQj+KIQggBCAFIBZ8fCEEIA8gBIVCIIohDyAKIA98IQogBSAKhUIYiiEFIAQgBSAUfHwhBCAPIASFQhCKIQ8gCiAPfCEKIAUgCoVCP4ohBSABIAUgHHx8IQEgDSABhUIgiiENIAkgDXwhCSAFIAmFQhiKIQUgASAFIBl8fCEBIA0gAYVCEIohDSAJIA18IQkgBSAJhUI/iiEFIAIgBiAdfHwhAiAOIAKFQiCKIQ4gCiAOfCEKIAYgCoVCGIohBiACIAYgEXx8IQIgDiAChUIQiiEOIAogDnwhCiAGIAqFQj+KIQYgAyAHIBZ8fCEDIA8gA4VCIIohDyALIA98IQsgByALhUIYiiEHIAMgByATfHwhAyAPIAOFQhCKIQ8gCyAPfCELIAcgC4VCP4ohByAEIAggIHx8IQQgECAEhUIgiiEQIAwgEHwhDCAIIAyFQhiKIQggBCAIIB58fCEEIBAgBIVCEIohECAMIBB8IQwgCCAMhUI/iiEIIAEgBiAbfHwhASAQIAGFQiCKIRAgCyAQfCELIAYgC4VCGIohBiABIAYgH3x8IQEgECABhUIQiiEQIAsgEHwhCyAGIAuFQj+KIQYgAiAHIBR8fCECIA0gAoVCIIohDSAMIA18IQwgByAMhUIYiiEHIAIgByAXfHwhAiANIAKFQhCKIQ0gDCANfCEMIAcgDIVCP4ohByADIAggGHx8IQMgDiADhUIgiiEOIAkgDnwhCSAIIAmFQhiKIQggAyAIIBJ8fCEDIA4gA4VCEIohDiAJIA58IQkgCCAJhUI/iiEIIAQgBSAafHwhBCAPIASFQiCKIQ8gCiAPfCEKIAUgCoVCGIohBSAEIAUgFXx8IQQgDyAEhUIQiiEPIAogD3whCiAFIAqFQj+KIQUgASAFIBh8fCEBIA0gAYVCIIohDSAJIA18IQkgBSAJhUIYiiEFIAEgBSAafHwhASANIAGFQhCKIQ0gCSANfCEJIAUgCYVCP4ohBSACIAYgFHx8IQIgDiAChUIgiiEOIAogDnwhCiAGIAqFQhiKIQYgAiAGIBJ8fCECIA4gAoVCEIohDiAKIA58IQogBiAKhUI/iiEGIAMgByAefHwhAyAPIAOFQiCKIQ8gCyAPfCELIAcgC4VCGIohByADIAcgHXx8IQMgDyADhUIQiiEPIAsgD3whCyAHIAuFQj+KIQcgBCAIIBx8fCEEIBAgBIVCIIohECAMIBB8IQwgCCAMhUIYiiEIIAQgCCAffHwhBCAQIASFQhCKIRAgDCAQfCEMIAggDIVCP4ohCCABIAYgE3x8IQEgECABhUIgiiEQIAsgEHwhCyAGIAuFQhiKIQYgASAGIBd8fCEBIBAgAYVCEIohECALIBB8IQsgBiALhUI/iiEGIAIgByAWfHwhAiANIAKFQiCKIQ0gDCANfCEMIAcgDIVCGIohByACIAcgG3x8IQIgDSAChUIQiiENIAwgDXwhDCAHIAyFQj+KIQcgAyAIIBV8fCEDIA4gA4VCIIohDiAJIA58IQkgCCAJhUIYiiEIIAMgCCARfHwhAyAOIAOFQhCKIQ4gCSAOfCEJIAggCYVCP4ohCCAEIAUgIHx8IQQgDyAEhUIgiiEPIAogD3whCiAFIAqFQhiKIQUgBCAFIBl8fCEEIA8gBIVCEIohDyAKIA98IQogBSAKhUI/iiEFIAEgBSAafHwhASANIAGFQiCKIQ0gCSANfCEJIAUgCYVCGIohBSABIAUgEXx8IQEgDSABhUIQiiENIAkgDXwhCSAFIAmFQj+KIQUgAiAGIBZ8fCECIA4gAoVCIIohDiAKIA58IQogBiAKhUIYiiEGIAIgBiAYfHwhAiAOIAKFQhCKIQ4gCiAOfCEKIAYgCoVCP4ohBiADIAcgE3x8IQMgDyADhUIgiiEPIAsgD3whCyAHIAuFQhiKIQcgAyAHIBV8fCEDIA8gA4VCEIohDyALIA98IQsgByALhUI/iiEHIAQgCCAbfHwhBCAQIASFQiCKIRAgDCAQfCEMIAggDIVCGIohCCAEIAggIHx8IQQgECAEhUIQiiEQIAwgEHwhDCAIIAyFQj+KIQggASAGIB98fCEBIBAgAYVCIIohECALIBB8IQsgBiALhUIYiiEGIAEgBiASfHwhASAQIAGFQhCKIRAgCyAQfCELIAYgC4VCP4ohBiACIAcgHHx8IQIgDSAChUIgiiENIAwgDXwhDCAHIAyFQhiKIQcgAiAHIB18fCECIA0gAoVCEIohDSAMIA18IQwgByAMhUI/iiEHIAMgCCAXfHwhAyAOIAOFQiCKIQ4gCSAOfCEJIAggCYVCGIohCCADIAggGXx8IQMgDiADhUIQiiEOIAkgDnwhCSAIIAmFQj+KIQggBCAFIBR8fCEEIA8gBIVCIIohDyAKIA98IQogBSAKhUIYiiEFIAQgBSAefHwhBCAPIASFQhCKIQ8gCiAPfCEKIAUgCoVCP4ohBSABIAUgE3x8IQEgDSABhUIgiiENIAkgDXwhCSAFIAmFQhiKIQUgASAFIB18fCEBIA0gAYVCEIohDSAJIA18IQkgBSAJhUI/iiEFIAIgBiAXfHwhAiAOIAKFQiCKIQ4gCiAOfCEKIAYgCoVCGIohBiACIAYgG3x8IQIgDiAChUIQiiEOIAogDnwhCiAGIAqFQj+KIQYgAyAHIBF8fCEDIA8gA4VCIIohDyALIA98IQsgByALhUIYiiEHIAMgByAcfHwhAyAPIAOFQhCKIQ8gCyAPfCELIAcgC4VCP4ohByAEIAggGXx8IQQgECAEhUIgiiEQIAwgEHwhDCAIIAyFQhiKIQggBCAIIBR8fCEEIBAgBIVCEIohECAMIBB8IQwgCCAMhUI/iiEIIAEgBiAVfHwhASAQIAGFQiCKIRAgCyAQfCELIAYgC4VCGIohBiABIAYgHnx8IQEgECABhUIQiiEQIAsgEHwhCyAGIAuFQj+KIQYgAiAHIBh8fCECIA0gAoVCIIohDSAMIA18IQwgByAMhUIYiiEHIAIgByAWfHwhAiANIAKFQhCKIQ0gDCANfCEMIAcgDIVCP4ohByADIAggIHx8IQMgDiADhUIgiiEOIAkgDnwhCSAIIAmFQhiKIQggAyAIIB98fCEDIA4gA4VCEIohDiAJIA58IQkgCCAJhUI/iiEIIAQgBSASfHwhBCAPIASFQiCKIQ8gCiAPfCEKIAUgCoVCGIohBSAEIAUgGnx8IQQgDyAEhUIQiiEPIAogD3whCiAFIAqFQj+KIQUgASAFIB18fCEBIA0gAYVCIIohDSAJIA18IQkgBSAJhUIYiiEFIAEgBSAWfHwhASANIAGFQhCKIQ0gCSANfCEJIAUgCYVCP4ohBSACIAYgEnx8IQIgDiAChUIgiiEOIAogDnwhCiAGIAqFQhiKIQYgAiAGICB8fCECIA4gAoVCEIohDiAKIA58IQogBiAKhUI/iiEGIAMgByAffHwhAyAPIAOFQiCKIQ8gCyAPfCELIAcgC4VCGIohByADIAcgHnx8IQMgDyADhUIQiiEPIAsgD3whCyAHIAuFQj+KIQcgBCAIIBV8fCEEIBAgBIVCIIohECAMIBB8IQwgCCAMhUIYiiEIIAQgCCAbfHwhBCAQIASFQhCKIRAgDCAQfCEMIAggDIVCP4ohCCABIAYgEXx8IQEgECABhUIgiiEQIAsgEHwhCyAGIAuFQhiKIQYgASAGIBh8fCEBIBAgAYVCEIohECALIBB8IQsgBiALhUI/iiEGIAIgByAXfHwhAiANIAKFQiCKIQ0gDCANfCEMIAcgDIVCGIohByACIAcgFHx8IQIgDSAChUIQiiENIAwgDXwhDCAHIAyFQj+KIQcgAyAIIBp8fCEDIA4gA4VCIIohDiAJIA58IQkgCCAJhUIYiiEIIAMgCCATfHwhAyAOIAOFQhCKIQ4gCSAOfCEJIAggCYVCP4ohCCAEIAUgGXx8IQQgDyAEhUIgiiEPIAogD3whCiAFIAqFQhiKIQUgBCAFIBx8fCEEIA8gBIVCEIohDyAKIA98IQogBSAKhUI/iiEFIAEgBSAefHwhASANIAGFQiCKIQ0gCSANfCEJIAUgCYVCGIohBSABIAUgHHx8IQEgDSABhUIQiiENIAkgDXwhCSAFIAmFQj+KIQUgAiAGIBh8fCECIA4gAoVCIIohDiAKIA58IQogBiAKhUIYiiEGIAIgBiAffHwhAiAOIAKFQhCKIQ4gCiAOfCEKIAYgCoVCP4ohBiADIAcgHXx8IQMgDyADhUIgiiEPIAsgD3whCyAHIAuFQhiKIQcgAyAHIBJ8fCEDIA8gA4VCEIohDyALIA98IQsgByALhUI/iiEHIAQgCCAUfHwhBCAQIASFQiCKIRAgDCAQfCEMIAggDIVCGIohCCAEIAggGnx8IQQgECAEhUIQiiEQIAwgEHwhDCAIIAyFQj+KIQggASAGIBZ8fCEBIBAgAYVCIIohECALIBB8IQsgBiALhUIYiiEGIAEgBiARfHwhASAQIAGFQhCKIRAgCyAQfCELIAYgC4VCP4ohBiACIAcgIHx8IQIgDSAChUIgiiENIAwgDXwhDCAHIAyFQhiKIQcgAiAHIBV8fCECIA0gAoVCEIohDSAMIA18IQwgByAMhUI/iiEHIAMgCCAZfHwhAyAOIAOFQiCKIQ4gCSAOfCEJIAggCYVCGIohCCADIAggF3x8IQMgDiADhUIQiiEOIAkgDnwhCSAIIAmFQj+KIQggBCAFIBN8fCEEIA8gBIVCIIohDyAKIA98IQogBSAKhUIYiiEFIAQgBSAbfHwhBCAPIASFQhCKIQ8gCiAPfCEKIAUgCoVCP4ohBSABIAUgF3x8IQEgDSABhUIgiiENIAkgDXwhCSAFIAmFQhiKIQUgASAFICB8fCEBIA0gAYVCEIohDSAJIA18IQkgBSAJhUI/iiEFIAIgBiAffHwhAiAOIAKFQiCKIQ4gCiAOfCEKIAYgCoVCGIohBiACIAYgGnx8IQIgDiAChUIQiiEOIAogDnwhCiAGIAqFQj+KIQYgAyAHIBx8fCEDIA8gA4VCIIohDyALIA98IQsgByALhUIYiiEHIAMgByAUfHwhAyAPIAOFQhCKIQ8gCyAPfCELIAcgC4VCP4ohByAEIAggEXx8IQQgECAEhUIgiiEQIAwgEHwhDCAIIAyFQhiKIQggBCAIIBl8fCEEIBAgBIVCEIohECAMIBB8IQwgCCAMhUI/iiEIIAEgBiAdfHwhASAQIAGFQiCKIRAgCyAQfCELIAYgC4VCGIohBiABIAYgE3x8IQEgECABhUIQiiEQIAsgEHwhCyAGIAuFQj+KIQYgAiAHIB58fCECIA0gAoVCIIohDSAMIA18IQwgByAMhUIYiiEHIAIgByAYfHwhAiANIAKFQhCKIQ0gDCANfCEMIAcgDIVCP4ohByADIAggEnx8IQMgDiADhUIgiiEOIAkgDnwhCSAIIAmFQhiKIQggAyAIIBV8fCEDIA4gA4VCEIohDiAJIA58IQkgCCAJhUI/iiEIIAQgBSAbfHwhBCAPIASFQiCKIQ8gCiAPfCEKIAUgCoVCGIohBSAEIAUgFnx8IQQgDyAEhUIQiiEPIAogD3whCiAFIAqFQj+KIQUgASAFIBt8fCEBIA0gAYVCIIohDSAJIA18IQkgBSAJhUIYiiEFIAEgBSATfHwhASANIAGFQhCKIQ0gCSANfCEJIAUgCYVCP4ohBSACIAYgGXx8IQIgDiAChUIgiiEOIAogDnwhCiAGIAqFQhiKIQYgAiAGIBV8fCECIA4gAoVCEIohDiAKIA58IQogBiAKhUI/iiEGIAMgByAYfHwhAyAPIAOFQiCKIQ8gCyAPfCELIAcgC4VCGIohByADIAcgF3x8IQMgDyADhUIQiiEPIAsgD3whCyAHIAuFQj+KIQcgBCAIIBJ8fCEEIBAgBIVCIIohECAMIBB8IQwgCCAMhUIYiiEIIAQgCCAWfHwhBCAQIASFQhCKIRAgDCAQfCEMIAggDIVCP4ohCCABIAYgIHx8IQEgECABhUIgiiEQIAsgEHwhCyAGIAuFQhiKIQYgASAGIBx8fCEBIBAgAYVCEIohECALIBB8IQsgBiALhUI/iiEGIAIgByAafHwhAiANIAKFQiCKIQ0gDCANfCEMIAcgDIVCGIohByACIAcgH3x8IQIgDSAChUIQiiENIAwgDXwhDCAHIAyFQj+KIQcgAyAIIBR8fCEDIA4gA4VCIIohDiAJIA58IQkgCCAJhUIYiiEIIAMgCCAdfHwhAyAOIAOFQhCKIQ4gCSAOfCEJIAggCYVCP4ohCCAEIAUgHnx8IQQgDyAEhUIgiiEPIAogD3whCiAFIAqFQhiKIQUgBCAFIBF8fCEEIA8gBIVCEIohDyAKIA98IQogBSAKhUI/iiEFIAEgBSARfHwhASANIAGFQiCKIQ0gCSANfCEJIAUgCYVCGIohBSABIAUgEnx8IQEgDSABhUIQiiENIAkgDXwhCSAFIAmFQj+KIQUgAiAGIBN8fCECIA4gAoVCIIohDiAKIA58IQogBiAKhUIYiiEGIAIgBiAUfHwhAiAOIAKFQhCKIQ4gCiAOfCEKIAYgCoVCP4ohBiADIAcgFXx8IQMgDyADhUIgiiEPIAsgD3whCyAHIAuFQhiKIQcgAyAHIBZ8fCEDIA8gA4VCEIohDyALIA98IQsgByALhUI/iiEHIAQgCCAXfHwhBCAQIASFQiCKIRAgDCAQfCEMIAggDIVCGIohCCAEIAggGHx8IQQgECAEhUIQiiEQIAwgEHwhDCAIIAyFQj+KIQggASAGIBl8fCEBIBAgAYVCIIohECALIBB8IQsgBiALhUIYiiEGIAEgBiAafHwhASAQIAGFQhCKIRAgCyAQfCELIAYgC4VCP4ohBiACIAcgG3x8IQIgDSAChUIgiiENIAwgDXwhDCAHIAyFQhiKIQcgAiAHIBx8fCECIA0gAoVCEIohDSAMIA18IQwgByAMhUI/iiEHIAMgCCAdfHwhAyAOIAOFQiCKIQ4gCSAOfCEJIAggCYVCGIohCCADIAggHnx8IQMgDiADhUIQiiEOIAkgDnwhCSAIIAmFQj+KIQggBCAFIB98fCEEIA8gBIVCIIohDyAKIA98IQogBSAKhUIYiiEFIAQgBSAgfHwhBCAPIASFQhCKIQ8gCiAPfCEKIAUgCoVCP4ohBSABIAUgH3x8IQEgDSABhUIgiiENIAkgDXwhCSAFIAmFQhiKIQUgASAFIBt8fCEBIA0gAYVCEIohDSAJIA18IQkgBSAJhUI/iiEFIAIgBiAVfHwhAiAOIAKFQiCKIQ4gCiAOfCEKIAYgCoVCGIohBiACIAYgGXx8IQIgDiAChUIQiiEOIAogDnwhCiAGIAqFQj+KIQYgAyAHIBp8fCEDIA8gA4VCIIohDyALIA98IQsgByALhUIYiiEHIAMgByAgfHwhAyAPIAOFQhCKIQ8gCyAPfCELIAcgC4VCP4ohByAEIAggHnx8IQQgECAEhUIgiiEQIAwgEHwhDCAIIAyFQhiKIQggBCAIIBd8fCEEIBAgBIVCEIohECAMIBB8IQwgCCAMhUI/iiEIIAEgBiASfHwhASAQIAGFQiCKIRAgCyAQfCELIAYgC4VCGIohBiABIAYgHXx8IQEgECABhUIQiiEQIAsgEHwhCyAGIAuFQj+KIQYgAiAHIBF8fCECIA0gAoVCIIohDSAMIA18IQwgByAMhUIYiiEHIAIgByATfHwhAiANIAKFQhCKIQ0gDCANfCEMIAcgDIVCP4ohByADIAggHHx8IQMgDiADhUIgiiEOIAkgDnwhCSAIIAmFQhiKIQggAyAIIBh8fCEDIA4gA4VCEIohDiAJIA58IQkgCCAJhUI/iiEIIAQgBSAWfHwhBCAPIASFQiCKIQ8gCiAPfCEKIAUgCoVCGIohBSAEIAUgFHx8IQQgDyAEhUIQiiEPIAogD3whCiAFIAqFQj+KIQUgISAhKQMAIAEgCYWFNwMAICIgIikDACACIAqFhTcDACAjICMpAwAgAyALhYU3AwAgJCAkKQMAIAQgDIWFNwMAICUgJSkDACAFIA2FhTcDACAmICYpAwAgBiAOhYU3AwAgJyAnKQMAIAcgD4WFNwMAICggKCkDACAIIBCFhTcDAAs=")}}),Ya=Za(),Ja=WebAssembly.compile(Ya),Wa=d((function(t){var e=null,a="undefined"!=typeof WebAssembly&&(async t=>(await WebAssembly.instantiate(await Ja,t)).exports)().then((t=>{e=t})),i=64,o=[];t.exports=u;var n=t.exports.BYTES_MIN=16,r=t.exports.BYTES_MAX=64;t.exports.BYTES=32;var l=t.exports.KEYBYTES_MIN=16,c=t.exports.KEYBYTES_MAX=64;t.exports.KEYBYTES=32;var s=t.exports.SALTBYTES=16,d=t.exports.PERSONALBYTES=16;function u(t,a,g,f,_){if(!(this instanceof u))return new u(t,a,g,f,_);if(!e)throw new Error("WASM not loaded. Wait for Blake2b.ready(cb)");t||(t=32),!0!==_&&(xa(t>=n,"digestLength must be at least "+n+", was given "+t),xa(t<=r,"digestLength must be at most "+r+", was given "+t),null!=a&&(xa(a instanceof Uint8Array,"key must be Uint8Array or Buffer"),xa(a.length>=l,"key must be at least "+l+", was given "+a.length),xa(a.length<=c,"key must be at least "+c+", was given "+a.length)),null!=g&&(xa(g instanceof Uint8Array,"salt must be Uint8Array or Buffer"),xa(g.length===s,"salt must be exactly "+s+", was given "+g.length)),null!=f&&(xa(f instanceof Uint8Array,"personal must be Uint8Array or Buffer"),xa(f.length===d,"personal must be exactly "+d+", was given "+f.length))),o.length||(o.push(i),i+=216),this.digestLength=t,this.finalized=!1,this.pointer=o.pop(),this._memory=new Uint8Array(e.memory.buffer),this._memory.fill(0,0,64),this._memory[0]=this.digestLength,this._memory[1]=a?a.length:0,this._memory[2]=1,this._memory[3]=1,g&&this._memory.set(g,32),f&&this._memory.set(f,48),this.pointer+216>this._memory.length&&this._realloc(this.pointer+216),e.blake2b_init(this.pointer,this.digestLength),a&&(this.update(a),this._memory.fill(0,i,i+a.length),this._memory[this.pointer+200]=128)}function g(){}u.prototype._realloc=function(t){e.memory.grow(Math.max(0,Math.ceil(Math.abs(t-this._memory.length)/65536))),this._memory=new Uint8Array(e.memory.buffer)},u.prototype.update=function(t){return xa(!1===this.finalized,"Hash instance finalized"),xa(t instanceof Uint8Array,"input must be Uint8Array or Buffer"),i+t.length>this._memory.length&&this._realloc(i+t.length),this._memory.set(t,i),e.blake2b_update(this.pointer,i,i+t.length),this},u.prototype.digest=function(t){if(xa(!1===this.finalized,"Hash instance finalized"),this.finalized=!0,o.push(this.pointer),e.blake2b_final(this.pointer),!t||"binary"===t)return this._memory.slice(this.pointer+128,this.pointer+128+this.digestLength);if("string"==typeof t)return Ha.toString(this._memory,t,this.pointer+128,this.pointer+128+this.digestLength);xa(t instanceof Uint8Array&&t.length>=this.digestLength,"input must be Uint8Array or Buffer");for(var a=0;at()),t):t(new Error("WebAssembly not supported"))},u.prototype.ready=u.ready,u.prototype.getPartialHash=function(){return this._memory.slice(this.pointer,this.pointer+216)},u.prototype.setPartialHash=function(t){this._memory.set(t,this.pointer)}}));const Xa=[];for(let t=0;t<256;t++)Xa[t]=ti(t,8);function ti(t,e){let a=0,i=t;for(let t=0;t>=1;return a}function ei(t){return(0!=(4294901760&t)?(t&=4294901760,16):0)|(0!=(4278255360&t)?(t&=4278255360,8):0)|(0!=(4042322160&t)?(t&=4042322160,4):0)|(0!=(3435973836&t)?(t&=3435973836,2):0)|0!=(2863311530&t)}function ai(t,e){const a=new DataView(t.buffer,t.byteOffset,t.byteLength);let i="";for(let t=0;t<4;t++){t>0&&(i+="\n"),i+="\t\t";for(let e=0;e<4;e++)e>0&&(i+=" "),i+=a.getUint32(16*t+4*e).toString(16).padStart(8,"0")}return e&&(i=e+"\n"+i),i}function ii(t,e){if(t.byteLength!=e.byteLength)return!1;for(var a=new Int8Array(t),i=new Int8Array(e),o=0;o!=t.byteLength;o++)if(a[o]!=i[o])return!1;return!0}function oi(t){const e=t.getPartialHash(),a=Wa(64);return a.setPartialHash(e),a}async function ni(t,e,a,i,o){if(t.G1.isZero(e))return!1;if(t.G1.isZero(a))return!1;if(t.G2.isZero(i))return!1;if(t.G2.isZero(o))return!1;return await t.pairingEq(e,o,t.G1.neg(a),i)}async function ri(t){for(;!t;)t=await window.prompt("Enter a random text. (Entropy): ","");const e=Wa(64);e.update(wt.randomBytes(64));const a=new TextEncoder;e.update(a.encode(t));const i=Buffer.from(e.digest()),o=[];for(let t=0;t<8;t++)o[t]=i.readUInt32BE(4*t);return new Lt(o)}function li(t,e){let a,i;e<32?(a=1<>>0,i=1):(a=4294967296,i=1<>>0);let o=t;for(let t=0;t0){const e=new Uint8Array(i);await t.writeULE32(e.byteLength),await t.write(e)}else await t.writeULE32(0)}async function wi(t,e,a){await fa(t,10),await t.write(a.csHash),await t.writeULE32(a.contributions.length);for(let i=0;i0;)a.unshift(0),n--;return a}async function Ei(t,e){e=e||{};let a,i=32767,o=!1;for(;!o;)try{a=new WebAssembly.Memory({initial:i}),o=!0}catch(t){if(1===i)throw t;console.warn("Could not allocate "+1024*i*64+" bytes. This may cause severe instability. Trying with "+1024*i*64/2+" bytes"),i=Math.floor(i/2)}const n=await WebAssembly.compile(t);let r;const l=await WebAssembly.instantiate(n,{env:{memory:a},runtime:{exceptionHandler:function(t){let e;throw e=1==t?"Signal not found. ":2==t?"Too many signals set. ":3==t?"Signal already set. ":4==t?"Assert Failed. ":5==t?"Not enough memory. ":"Unknown error.",console.log("ERROR: ",t,e),new Error(e)},showSharedRWMemory:function(){const t=l.exports.getFieldNumLen32(),e=new Uint32Array(t);for(let a=0;a0;a++)i.push(e[t+a]);return String.fromCharCode.apply(null,i)}}class Bi{constructor(t,e,a){this.memory=t,this.i32=new Uint32Array(t.buffer),this.instance=e,this.n32=(this.instance.exports.getFrLen()>>2)-2;const i=this.instance.exports.getPRawPrime(),o=new Array(this.n32);for(let t=0;t>2)+t];this.prime=He.fromArray(o,4294967296),this.Fr=new vt(this.prime),this.mask32=He.fromString("FFFFFFFF",16),this.NVars=this.instance.exports.getNVars(),this.n64=Math.floor((this.Fr.bitLength-1)/64)+1,this.R=this.Fr.e(He.shiftLeft(1,64*this.n64)),this.RInv=this.Fr.inv(this.R),this.sanityCheck=a}circom_version(){return 1}async _doCalculateWitness(t,e){this.instance.exports.init(this.sanityCheck||e?1:0);const a=this.allocInt(),i=this.allocFr();Object.keys(t).forEach((e=>{const o=xi(e),n=parseInt(o.slice(0,8),16),r=parseInt(o.slice(8,16),16);try{this.instance.exports.getSignalOffset32(a,0,n,r)}catch(t){throw new Error(`Signal ${e} is not an input of the circuit.`)}const l=this.getInt(a),c=Fi(t[e]);for(let t=0;t>2]}setInt(t,e){this.i32[t>>2]=e}getFr(t){const e=this,a=t>>2;if(2147483648&e.i32[a+1]){const t=new Array(e.n32);for(let i=0;i>2]=o,void(a.i32[1+(t>>2)]=0)}a.i32[t>>2]=0,a.i32[1+(t>>2)]=2147483648;const n=He.toArray(e,4294967296);for(let e=0;e>2)+e]=i>=0?n[i]:0}}}class Si{constructor(t,e){this.instance=t,this.version=this.instance.exports.getVersion(),this.n32=this.instance.exports.getFieldNumLen32(),this.instance.exports.getRawPrime();const a=new Array(this.n32);for(let t=0;t{const a=xi(e),o=parseInt(a.slice(0,8),16),n=parseInt(a.slice(8,16),16),r=Fi(t[e]);for(let t=0;t1)throw new Error(t.fileName+": File has more than one header");t.pos=e[1][0].p;const a=await t.readULE32(),i=await t.read(a),o=He.fromRprLE(i),n=await Ca(o);if(8*n.F1.n64!=a)throw new Error(t.fileName+": Invalid size");const r=await t.readULE32(),l=await t.readULE32();if(t.pos-e[1][0].p!=e[1][0].size)throw new Error("Invalid PTau header size");return{curve:n,power:r,ceremonyPower:l}}function Ri(t,e,a,i){const o={tau:{},alpha:{},beta:{}};return o.tau.g1_s=n(),o.tau.g1_sx=n(),o.alpha.g1_s=n(),o.alpha.g1_sx=n(),o.beta.g1_s=n(),o.beta.g1_sx=n(),o.tau.g2_spx=r(),o.alpha.g2_spx=r(),o.beta.g2_spx=r(),o;function n(){let o;return o=i?a.G1.fromRprLEM(t,e):a.G1.fromRprUncompressed(t,e),e+=2*a.G1.F.n8,o}function r(){let o;return o=i?a.G2.fromRprLEM(t,e):a.G2.fromRprUncompressed(t,e),e+=2*a.G2.F.n8,o}}function Ni(t,e,a,i,o){async function n(i){o?a.G1.toRprLEM(t,e,i):a.G1.toRprUncompressed(t,e,i),e+=2*a.F1.n8}async function r(i){o?a.G2.toRprLEM(t,e,i):a.G2.toRprUncompressed(t,e,i),e+=2*a.F2.n8}return n(i.tau.g1_s),n(i.tau.g1_sx),n(i.alpha.g1_s),n(i.alpha.g1_sx),n(i.beta.g1_s),n(i.beta.g1_sx),r(i.tau.g2_spx),r(i.alpha.g2_spx),r(i.beta.g2_spx),t}async function Di(t,e){const a={};a.tauG1=await c(),a.tauG2=await s(),a.alphaG1=await c(),a.betaG1=await c(),a.betaG2=await s(),a.key=await async function(t,e,a){return Ri(await t.read(2*e.F1.n8*6+2*e.F2.n8*3),0,e,a)}(t,e,!0),a.partialHash=await t.read(216),a.nextChallenge=await t.read(64),a.type=await t.readULE32();const i=new Uint8Array(2*e.G1.F.n8*6+2*e.G2.F.n8*3);Ni(i,0,e,a.key,!1);const o=Wa(64);o.setPartialHash(a.partialHash),o.update(i),a.responseHash=o.digest();const n=await t.readULE32(),r=t.pos;let l=0;for(;t.pos-r1)throw new Error(t.fileName+": File has more than one contributions section");t.pos=a[7][0].p;const i=await t.readULE32(),o=[];for(let a=0;a0){const e=new Uint8Array(n);await t.writeULE32(e.byteLength),await t.write(e)}else await t.writeULE32(0);async function r(a){e.G1.toRprLEM(i,0,a),await t.write(i)}async function l(a){e.G2.toRprLEM(o,0,a),await t.write(o)}}async function ji(t,e,a){await t.writeULE32(7);const i=t.pos;await t.writeULE64(0),await t.writeULE32(a.length);for(let i=0;i0?u[u.length-1].nextChallenge:Hi(s,d,n);const w=await ga(a,"ptau",1,o?7:2);await ki(w,s,d);const A=await m.read(64);if(ii(r,L)&&(L=A,u[u.length-1].nextChallenge=L),!ii(A,L))throw new Error("Wrong contribution. this contribution is not based on the previus hash");const b=new Wa(64);b.update(A);const y=[];let I;I=await x(m,w,"G1",2,2**d*2-1,[1],"tauG1"),g.tauG1=I[0],I=await x(m,w,"G2",3,2**d,[1],"tauG2"),g.tauG2=I[0],I=await x(m,w,"G1",4,2**d,[0],"alphaG1"),g.alphaG1=I[0],I=await x(m,w,"G1",5,2**d,[0],"betaG1"),g.betaG1=I[0],I=await x(m,w,"G2",6,1,[0],"betaG2"),g.betaG2=I[0],g.partialHash=b.getPartialHash();const C=await m.read(2*s.F1.n8*6+2*s.F2.n8*3);g.key=Ri(C,0,s,!1),b.update(new Uint8Array(C));const F=b.digest();if(n&&n.info(ai(F,"Contribution Response Hash imported: ")),o){const t=new Wa(64);t.update(F),await v(t,w,"G1",2,2**d*2-1,"tauG1",n),await v(t,w,"G2",3,2**d,"tauG2",n),await v(t,w,"G1",4,2**d,"alphaTauG1",n),await v(t,w,"G1",5,2**d,"betaTauG1",n),await v(t,w,"G2",6,1,"betaG2",n),g.nextChallenge=t.digest(),n&&n.info(ai(g.nextChallenge,"Next Challenge Hash: "))}else g.nextChallenge=r;return u.push(g),await ji(w,s,u),await m.close(),await w.close(),await l.close(),g.nextChallenge;async function x(t,e,a,i,r,l,c){return o?await async function(t,e,a,i,o,r,l){const c=s[a],d=c.F.n8,u=2*c.F.n8,g=[];await fa(e,i);const f=Math.floor((1<<24)/u);y[i]=e.pos;for(let a=0;a=a&&e=e&&o1?c[c.length-2]:s;const u=c[c.length-1];if(e&&e.debug("Validating contribution #"+c[c.length-1].id),!await Yi(n,u,d,e))return!1;const g=Wa(64);g.update(u.responseHash),e&&e.debug("Verifying powers in tau*G1 section");const f=await A(2,"G1","tauG1",2**r*2-1,[0,1],e);if(a=await Zi(n,f.R1,f.R2,n.G2.g,u.tauG2),!0!==a)return e&&e.error("tauG1 section. Powers do not match"),!1;if(!n.G1.eq(n.G1.g,f.singularPoints[0]))return e&&e.error("First element of tau*G1 section must be the generator"),!1;if(!n.G1.eq(u.tauG1,f.singularPoints[1]))return e&&e.error("Second element of tau*G1 section does not match the one in the contribution section"),!1;e&&e.debug("Verifying powers in tau*G2 section");const _=await A(3,"G2","tauG2",2**r,[0,1],e);if(a=await Zi(n,n.G1.g,u.tauG1,_.R1,_.R2),!0!==a)return e&&e.error("tauG2 section. Powers do not match"),!1;if(!n.G2.eq(n.G2.g,_.singularPoints[0]))return e&&e.error("First element of tau*G2 section must be the generator"),!1;if(!n.G2.eq(u.tauG2,_.singularPoints[1]))return e&&e.error("Second element of tau*G2 section does not match the one in the contribution section"),!1;e&&e.debug("Verifying powers in alpha*tau*G1 section");const p=await A(4,"G1","alphatauG1",2**r,[0],e);if(a=await Zi(n,p.R1,p.R2,n.G2.g,u.tauG2),!0!==a)return e&&e.error("alphaTauG1 section. Powers do not match"),!1;if(!n.G1.eq(u.alphaG1,p.singularPoints[0]))return e&&e.error("First element of alpha*tau*G1 section (alpha*G1) does not match the one in the contribution section"),!1;e&&e.debug("Verifying powers in beta*tau*G1 section");const h=await A(5,"G1","betatauG1",2**r,[0],e);if(a=await Zi(n,h.R1,h.R2,n.G2.g,u.tauG2),!0!==a)return e&&e.error("betaTauG1 section. Powers do not match"),!1;if(!n.G1.eq(u.betaG1,h.singularPoints[0]))return e&&e.error("First element of beta*tau*G1 section (beta*G1) does not match the one in the contribution section"),!1;const m=await async function(t){const e=n.G2,a=2*e.F.n8,r=new Uint8Array(a);if(!o[6])throw t.error("File has no BetaG2 section"),new Error("File has no BetaG2 section");if(o[6].length>1)throw t.error("File has no BetaG2 section"),new Error("File has more than one GetaG2 section");i.pos=o[6][0].p;const l=await i.read(a),c=e.fromRprLEM(l);return e.toRprUncompressed(r,0,c),g.update(r),c}(e);if(!n.G2.eq(u.betaG2,m))return e&&e.error("betaG2 element in betaG2 section does not match the one in the contribution section"),!1;const L=g.digest();if(r==l&&!ii(L,u.nextChallenge))return e&&e.error("Hash of the values does not match the next challenge of the last contributor in the contributions section"),!1;e&&e.info(ai(L,"Next challenge hash: ")),w(u,d);for(let t=c.length-2;t>=0;t--){const a=c[t],i=t>0?c[t-1]:s;if(!await Yi(n,a,i,e))return!1;w(a,i)}if(e&&e.info("-----------------------------------------------------"),o[12]&&o[13]&&o[14]&&o[15]){let t;if(t=await b("G1",2,12,"tauG1",e),!t)return!1;if(t=await b("G2",3,13,"tauG2",e),!t)return!1;if(t=await b("G1",4,14,"alphaTauG1",e),!t)return!1;if(t=await b("G1",5,15,"betaTauG1",e),!t)return!1}else e&&e.warn('this file does not contain phase2 precalculated values. Please run: \n snarkjs "powersoftau preparephase2" to prepare this file to be used in the phase2 ceremony.');return await i.close(),e&&e.info("Powers of Tau Ok!"),!0;function w(t,a){if(!e)return;e.info("-----------------------------------------------------"),e.info(`Contribution #${t.id}: ${t.name||""}`),e.info(ai(t.nextChallenge,"Next Challenge: "));const i=new Uint8Array(2*n.G1.F.n8*6+2*n.G2.F.n8*3);Ni(i,0,n,t.key,!1);const o=Wa(64);o.setPartialHash(t.partialHash),o.update(i);const r=o.digest();e.info(ai(r,"Response Hash:")),e.info(ai(a.nextChallenge,"Response Hash:")),1==t.type&&(e.info(`Beacon generator: ${si(t.beaconHash)}`),e.info(`Beacon iterations Exp: ${t.numIterationsExp}`))}async function A(t,e,a,r,l,c){const s=n[e],d=2*s.F.n8;await pa(i,o,t);const u=[];let f=s.zero,_=s.zero,p=s.zero;for(let t=0;t0){const t=s.fromRprLEM(o,0),e=wt.randomBytes(4).readUInt32BE(0,!0);f=s.add(f,s.timesScalar(p,e)),_=s.add(_,s.timesScalar(t,e))}const m=await s.multiExpAffine(o.slice(0,(e-1)*d),h),L=await s.multiExpAffine(o.slice(d),h);f=s.add(f,m),_=s.add(_,L),p=s.fromRprLEM(o,(e-1)*d);for(let a=0;a=t&&i1;)s/=2,d+=1;if(2**d!=c)throw new Error("Invalid file size");o&&o.debug("Power to tau size: "+d);const u=await ri(i),g=await sa(a),f=Wa(64);for(let t=0;t{o.debug(e+".g1_s: "+t.G1.toString(h[e].g1_s,16)),o.debug(e+".g1_sx: "+t.G1.toString(h[e].g1_sx,16)),o.debug(e+".g2_sp: "+t.G2.toString(h[e].g2_sp,16)),o.debug(e+".g2_spx: "+t.G2.toString(h[e].g2_spx,16)),o.debug("")}));const m=Wa(64);await g.write(p),m.update(p),await Wi(n,g,m,t,"G1",2**d*2-1,t.Fr.one,h.tau.prvKey,"COMPRESSED","tauG1",o),await Wi(n,g,m,t,"G2",2**d,t.Fr.one,h.tau.prvKey,"COMPRESSED","tauG2",o),await Wi(n,g,m,t,"G1",2**d,h.alpha.prvKey,h.tau.prvKey,"COMPRESSED","alphaTauG1",o),await Wi(n,g,m,t,"G1",2**d,h.beta.prvKey,h.tau.prvKey,"COMPRESSED","betaTauG1",o),await Wi(n,g,m,t,"G2",1,h.beta.prvKey,h.tau.prvKey,"COMPRESSED","betaTauG2",o);const L=new Uint8Array(2*t.F1.n8*6+2*t.F2.n8*3);Ni(L,0,t,h,!1),await g.write(L),m.update(L);const w=m.digest();o&&o.info(ai(w,"Contribution Response Hash: ")),await g.close(),await n.close()},beacon:async function(t,e,a,i,o,n){const r=ci(i);if(0==r.byteLength||2*r.byteLength!=i.length)return n&&n.error("Invalid Beacon Hash. (It must be a valid hexadecimal sequence)"),!1;if(r.length>=256)return n&&n.error("Maximum lenght of beacon hash is 255 bytes"),!1;if((o=parseInt(o))<10||o>63)return n&&n.error("Invalid numIterationsExp. (Must be between 10 and 63)"),!1;await Wa.ready();const{fd:l,sections:c}=await ua(t,"ptau",1),{curve:s,power:d,ceremonyPower:u}=await Ti(l,c);if(d!=u)return n&&n.error("This file has been reduced. You cannot contribute into a reduced file."),!1;c[12]&&n&&n.warn("Contributing into a file that has phase2 calculated. You will have to prepare phase2 again.");const g=await Ki(l,s,c),f={name:a,type:1,numIterationsExp:o,beaconHash:r};let _;_=g.length>0?g[g.length-1].nextChallenge:Hi(s,d,n),f.key=$i(s,_,r,o);const p=new Wa(64);p.update(_);const h=await ga(e,"ptau",1,7);await ki(h,s,d);const m=[];let L;L=await y(2,"G1",2**d*2-1,s.Fr.e(1),f.key.tau.prvKey,"tauG1",n),f.tauG1=L[1],L=await y(3,"G2",2**d,s.Fr.e(1),f.key.tau.prvKey,"tauG2",n),f.tauG2=L[1],L=await y(4,"G1",2**d,f.key.alpha.prvKey,f.key.tau.prvKey,"alphaTauG1",n),f.alphaG1=L[0],L=await y(5,"G1",2**d,f.key.beta.prvKey,f.key.tau.prvKey,"betaTauG1",n),f.betaG1=L[0],L=await y(6,"G2",1,f.key.beta.prvKey,f.key.tau.prvKey,"betaTauG2",n),f.betaG2=L[0],f.partialHash=p.getPartialHash();const w=new Uint8Array(2*s.F1.n8*6+2*s.F2.n8*3);Ni(w,0,s,f.key,!1),p.update(new Uint8Array(w));const A=p.digest();n&&n.info(ai(A,"Contribution Response Hash imported: "));const b=new Wa(64);return b.update(A),await I(h,"G1",2,2**d*2-1,"tauG1",n),await I(h,"G2",3,2**d,"tauG2",n),await I(h,"G1",4,2**d,"alphaTauG1",n),await I(h,"G1",5,2**d,"betaTauG1",n),await I(h,"G2",6,1,"betaG2",n),f.nextChallenge=b.digest(),n&&n.info(ai(f.nextChallenge,"Next Challenge Hash: ")),g.push(f),await ji(h,s,g),await l.close(),await h.close(),A;async function y(t,e,a,i,o,n,r){const d=[];l.pos=c[t][0].p,await fa(h,t),m[t]=h.pos;const u=s[e],g=2*u.F.n8,f=Math.floor((1<<20)/g);let _=i;for(let t=0;t0?d[d.length-1].nextChallenge:Hi(l,c,o),u.key=Mi(l,g,f);const _=new Wa(64);_.update(g);const p=await ga(e,"ptau",1,7);await ki(p,l,c);const h=[];let m;m=await b(2,"G1",2**c*2-1,l.Fr.e(1),u.key.tau.prvKey,"tauG1"),u.tauG1=m[1],m=await b(3,"G2",2**c,l.Fr.e(1),u.key.tau.prvKey,"tauG2"),u.tauG2=m[1],m=await b(4,"G1",2**c,u.key.alpha.prvKey,u.key.tau.prvKey,"alphaTauG1"),u.alphaG1=m[0],m=await b(5,"G1",2**c,u.key.beta.prvKey,u.key.tau.prvKey,"betaTauG1"),u.betaG1=m[0],m=await b(6,"G2",1,u.key.beta.prvKey,u.key.tau.prvKey,"betaTauG2"),u.betaG2=m[0],u.partialHash=_.getPartialHash();const L=new Uint8Array(2*l.F1.n8*6+2*l.F2.n8*3);Ni(L,0,l,u.key,!1),_.update(new Uint8Array(L));const w=_.digest();o&&o.info(ai(w,"Contribution Response Hash imported: "));const A=new Wa(64);return A.update(w),await y(p,"G1",2,2**c*2-1,"tauG1"),await y(p,"G2",3,2**c,"tauG2"),await y(p,"G1",4,2**c,"alphaTauG1"),await y(p,"G1",5,2**c,"betaTauG1"),await y(p,"G2",6,1,"betaG2"),u.nextChallenge=A.digest(),o&&o.info(ai(u.nextChallenge,"Next Challenge Hash: ")),d.push(u),await ji(p,l,d),await n.close(),await p.close(),w;async function b(t,e,a,i,c,s){const d=[];n.pos=r[t][0].p,await fa(p,t),h[t]=p.pos;const u=l[e],g=2*u.F.n8,f=Math.floor((1<<20)/g);let m=i;for(let t=0;t=this.length&&(this.length=t+1),!0}getKeys(){const t=new io;for(let e=0;e1<<20?new io:[];for(let t=0;t1<<20?new io:[];for(let t=0;t{a[i]=co(t,e[i])})),a}return"bigint"==typeof e||void 0!==e.eq?e.toString(10):e}var so=Object.freeze({__proto__:null,print:function(t,e,a){for(let e=0;e{let i="";return Object.keys(a).forEach((o=>{let n=e.varIdx2Name[o];"one"==n&&(n="");let r=t.curve.Fr.toString(a[o]);"1"==r&&(r=""),"-1"==r&&(r="-"),""!=i&&"-"!=r[0]&&(r="+"+r),""!=i&&(r=" "+r),i=i+r+n})),i},n=`[ ${o(i[0])} ] * [ ${o(i[1])} ] - [ ${o(i[2])} ] = 0`;a&&a.info(n)}},info:async function(t,e){const a=await no(t);return He.eq(a.prime,lo)?e&&e.info("Curve: bn-128"):He.eq(a.prime,ro)?e&&e.info("Curve: bls12-381"):e&&e.info(`Unknown Curve. Prime: ${He.toString(a.prime)}`),e&&e.info(`# of Wires: ${a.nVars}`),e&&e.info(`# of Constraints: ${a.nConstraints}`),e&&e.info(`# of Private Inputs: ${a.nPrvInputs}`),e&&e.info(`# of Public Inputs: ${a.nPubInputs}`),e&&e.info(`# of Labels: ${a.nLabels}`),e&&e.info(`# of Outputs: ${a.nOutputs}`),a},exportJson:async function(t,e){const a=await no(t,!0,!0,!0,e),i=a.curve.Fr;return delete a.curve,co(i,a)}});async function uo(t){const e={labelIdx2Name:["one"],varIdx2Name:["one"],componentIdx2Name:[]},a=await da(t),i=await a.read(a.totalSize),o=new TextDecoder("utf-8").decode(i).split("\n");for(let t=0;t=this.length&&(this.length=t+1),!0}getKeys(){const t=new ho;for(let e=0;ec)return i&&i.error(`circuit too big for this power of tau ceremony. ${u.nConstraints}*2 > 2**${c}`),-1;if(!r[12])return i&&i.error("Powers of tau is not prepared."),-1;const h=u.nOutputs+u.nPubInputs,m=2**p;await fa(g,1),await g.writeULE32(1),await _a(g),await fa(g,2);const L=l.q,w=8*(Math.floor((He.bitLength(L)-1)/64)+1),A=l.r,b=8*(Math.floor((He.bitLength(A)-1)/64)+1),y=He.mod(He.shl(1,8*b),A),I=l.Fr.e(He.mod(He.mul(y,y),A));let C,F,x;await g.writeULE32(w),await ma(g,L,w),await g.writeULE32(b),await ma(g,A,b),await g.writeULE32(u.nVars),await g.writeULE32(h),await g.writeULE32(m),C=await n.read(f,r[4][0].p),await g.write(C),C=await l.G1.batchLEMtoU(C),o.update(C),F=await n.read(f,r[5][0].p),await g.write(F),F=await l.G1.batchLEMtoU(F),o.update(F),x=await n.read(_,r[6][0].p),await g.write(x),x=await l.G2.batchLEMtoU(x),o.update(x);const v=new Uint8Array(f);l.G1.toRprLEM(v,0,l.G1.g);const E=new Uint8Array(_);l.G2.toRprLEM(E,0,l.G2.g);const B=new Uint8Array(f);l.G1.toRprUncompressed(B,0,l.G1.g);const S=new Uint8Array(_);l.G2.toRprUncompressed(S,0,l.G2.g),await g.write(E),await g.write(v),await g.write(E),o.update(S),o.update(B),o.update(S),await _a(g),i&&i.info("Reading r1cs");let G=await Aa(s,d,2);const P=new ho(u.nVars),O=new ho(u.nVars),U=new ho(u.nVars),z=new ho(u.nVars-h-1),q=new Array(h+1);i&&i.info("Reading tauG1");let Q=await Aa(n,r,12,(m-1)*f,m*f);i&&i.info("Reading tauG2");let M=await Aa(n,r,13,(m-1)*_,m*_);i&&i.info("Reading alphatauG1");let k=await Aa(n,r,14,(m-1)*f,m*f);i&&i.info("Reading betatauG1");let T=await Aa(n,r,15,(m-1)*f,m*f);await async function(){const t=new Uint8Array(12+l.Fr.n8),e=new DataView(t.buffer),a=new Uint8Array(l.Fr.n8);l.Fr.toRprLE(a,0,l.Fr.e(1));let o=0;function n(){const t=G.slice(o,o+4);o+=4;return new DataView(t.buffer).getUint32(0,!0)}const r=new ho;for(let t=0;t=0?l.Fr.fromRprLE(G.slice(i[3],i[3]+l.Fr.n8),0):l.Fr.fromRprLE(a,0);const n=l.Fr.mul(o,I);l.Fr.toRprLE(t,12,n),c.set(t,d),d+=t.length}await g.write(c),await _a(g)}(),await N(3,"G1",q,"IC"),await async function(){await fa(g,9);const t=new fe(m*f);if(p(i&&i.debug(`Writing points end ${n}: ${d}/${a.length}`),t)))),s+=o,t++}const d=await Promise.all(c);for(let t=0;t32768?(f=new fe(p*n),_=new fe(p*l.Fr.n8)):(f=new Uint8Array(p*n),_=new Uint8Array(p*l.Fr.n8));let h=0,m=0;const L=[Q,M,k,T],w=new Uint8Array(l.Fr.n8);l.Fr.toRprLE(w,0,l.Fr.e(1));let A=0;for(let t=0;t=0?_.set(G.slice(e[t][o][2],e[t][o][2]+l.Fr.n8),A*l.Fr.n8):_.set(w,A*l.Fr.n8),A++;if(e.length>1){const t=[];t.push({cmd:"ALLOCSET",var:0,buff:f}),t.push({cmd:"ALLOCSET",var:1,buff:_}),t.push({cmd:"ALLOC",var:2,len:e.length*r}),h=0,m=0;let a=0;for(let i=0;i=0;t--){const e=d.contributions[t];i&&i.info("-------------------------"),i&&i.info(ai(e.contributionHash,`contribution #${t+1} ${e.name?e.name:""}:`)),1==e.type&&(i&&i.info(`Beacon generator: ${si(e.beaconHash)}`),i&&i.info(`Beacon iterations Exp: ${e.numIterationsExp}`))}return i&&i.info("-------------------------"),i&&i.info("ZKey Ok!"),!0;async function L(t,e){const a=2*c.G1.F.n8,i=t.byteLength/a,o=c.tm.concurrency,n=Math.floor(i/o),r=[];for(let a=0;ag.contributions.length)return o&&o.error("The impoerted file does not include new contributions"),!1;for(let t=0;t=256)return n&&n.error("Maximum lenght of beacon hash is 255 bytes"),!1;if((o=parseInt(o))<10||o>63)return n&&n.error("Invalid numIterationsExp. (Must be between 10 and 63)"),!1;const{fd:l,sections:c}=await ua(t,"zkey",2),s=await pi(l,c);if("groth16"!=s.protocol)throw new Error("zkey file is not groth16");const d=await Ca(s.q),u=await mi(l,d,c),g=await ga(e,"zkey",1,10),f=await li(r,o),_=Wa(64);_.update(u.csHash);for(let t=0;t>5,this.byteCount=this.blockCount<<2,this.outputBlocks=a>>5,this.extraBytes=(31&a)>>3;for(var i=0;i<50;++i)this.s[i]=0}function P(t,e,a){G.call(this,t,e,a)}G.prototype.update=function(t){if(this.finalized)throw new Error("finalize already called");var a,i=typeof t;if("string"!==i){if("object"!==i)throw new Error(e);if(null===t)throw new Error(e);if(r&&t.constructor===ArrayBuffer)t=new Uint8Array(t);else if(!(Array.isArray(t)||r&&ArrayBuffer.isView(t)))throw new Error(e);a=!0}for(var o,n,l=this.blocks,c=this.byteCount,s=t.length,u=this.blockCount,g=0,f=this.s;g>2]|=t[g]<>2]|=n<>2]|=(192|n>>6)<>2]|=(128|63&n)<=57344?(l[o>>2]|=(224|n>>12)<>2]|=(128|n>>6&63)<>2]|=(128|63&n)<>2]|=(240|n>>18)<>2]|=(128|n>>12&63)<>2]|=(128|n>>6&63)<>2]|=(128|63&n)<=c){for(this.start=o-c,this.block=l[u],o=0;o>=8);a>0;)o.unshift(a),a=255&(t>>=8),++i;return e?o.push(i):o.unshift(i),this.update(o),o.length},G.prototype.encodeString=function(t){var a,i=typeof t;if("string"!==i){if("object"!==i)throw new Error(e);if(null===t)throw new Error(e);if(r&&t.constructor===ArrayBuffer)t=new Uint8Array(t);else if(!(Array.isArray(t)||r&&ArrayBuffer.isView(t)))throw new Error(e);a=!0}var o=0,n=t.length;if(a)o=n;else for(var l=0;l=57344?o+=3:(c=65536+((1023&c)<<10|1023&t.charCodeAt(++l)),o+=4)}return o+=this.encode(8*o),this.update(t),o},G.prototype.bytepad=function(t,e){for(var a=this.encode(e),i=0;i>2]|=this.padding[3&e],this.lastByteIndex===this.byteCount)for(t[0]=t[a],e=1;e>4&15]+l[15&t]+l[t>>12&15]+l[t>>8&15]+l[t>>20&15]+l[t>>16&15]+l[t>>28&15]+l[t>>24&15];r%e==0&&(O(a),n=0)}return o&&(t=a[n],c+=l[t>>4&15]+l[15&t],o>1&&(c+=l[t>>12&15]+l[t>>8&15]),o>2&&(c+=l[t>>20&15]+l[t>>16&15])),c},G.prototype.arrayBuffer=function(){this.finalize();var t,e=this.blockCount,a=this.s,i=this.outputBlocks,o=this.extraBytes,n=0,r=0,l=this.outputBits>>3;t=o?new ArrayBuffer(i+1<<2):new ArrayBuffer(l);for(var c=new Uint32Array(t);r>8&255,c[t+2]=e>>16&255,c[t+3]=e>>24&255;l%a==0&&O(i)}return n&&(t=l<<2,e=i[r],c[t]=255&e,n>1&&(c[t+1]=e>>8&255),n>2&&(c[t+2]=e>>16&255)),c},P.prototype=new G,P.prototype.finalize=function(){return this.encode(this.outputBits,!0),G.prototype.finalize.call(this)};var O=function(t){var e,a,i,o,n,r,l,c,s,d,g,f,_,p,h,m,L,w,A,b,y,I,C,F,x,v,E,B,S,G,P,O,U,z,q,Q,M,k,T,R,N,D,K,V,j,H,$,Z,Y,J,W,X,tt,et,at,it,ot,nt,rt,lt,ct,st,dt;for(i=0;i<48;i+=2)o=t[0]^t[10]^t[20]^t[30]^t[40],n=t[1]^t[11]^t[21]^t[31]^t[41],r=t[2]^t[12]^t[22]^t[32]^t[42],l=t[3]^t[13]^t[23]^t[33]^t[43],c=t[4]^t[14]^t[24]^t[34]^t[44],s=t[5]^t[15]^t[25]^t[35]^t[45],d=t[6]^t[16]^t[26]^t[36]^t[46],g=t[7]^t[17]^t[27]^t[37]^t[47],e=(f=t[8]^t[18]^t[28]^t[38]^t[48])^(r<<1|l>>>31),a=(_=t[9]^t[19]^t[29]^t[39]^t[49])^(l<<1|r>>>31),t[0]^=e,t[1]^=a,t[10]^=e,t[11]^=a,t[20]^=e,t[21]^=a,t[30]^=e,t[31]^=a,t[40]^=e,t[41]^=a,e=o^(c<<1|s>>>31),a=n^(s<<1|c>>>31),t[2]^=e,t[3]^=a,t[12]^=e,t[13]^=a,t[22]^=e,t[23]^=a,t[32]^=e,t[33]^=a,t[42]^=e,t[43]^=a,e=r^(d<<1|g>>>31),a=l^(g<<1|d>>>31),t[4]^=e,t[5]^=a,t[14]^=e,t[15]^=a,t[24]^=e,t[25]^=a,t[34]^=e,t[35]^=a,t[44]^=e,t[45]^=a,e=c^(f<<1|_>>>31),a=s^(_<<1|f>>>31),t[6]^=e,t[7]^=a,t[16]^=e,t[17]^=a,t[26]^=e,t[27]^=a,t[36]^=e,t[37]^=a,t[46]^=e,t[47]^=a,e=d^(o<<1|n>>>31),a=g^(n<<1|o>>>31),t[8]^=e,t[9]^=a,t[18]^=e,t[19]^=a,t[28]^=e,t[29]^=a,t[38]^=e,t[39]^=a,t[48]^=e,t[49]^=a,p=t[0],h=t[1],H=t[11]<<4|t[10]>>>28,$=t[10]<<4|t[11]>>>28,B=t[20]<<3|t[21]>>>29,S=t[21]<<3|t[20]>>>29,lt=t[31]<<9|t[30]>>>23,ct=t[30]<<9|t[31]>>>23,D=t[40]<<18|t[41]>>>14,K=t[41]<<18|t[40]>>>14,z=t[2]<<1|t[3]>>>31,q=t[3]<<1|t[2]>>>31,m=t[13]<<12|t[12]>>>20,L=t[12]<<12|t[13]>>>20,Z=t[22]<<10|t[23]>>>22,Y=t[23]<<10|t[22]>>>22,G=t[33]<<13|t[32]>>>19,P=t[32]<<13|t[33]>>>19,st=t[42]<<2|t[43]>>>30,dt=t[43]<<2|t[42]>>>30,et=t[5]<<30|t[4]>>>2,at=t[4]<<30|t[5]>>>2,Q=t[14]<<6|t[15]>>>26,M=t[15]<<6|t[14]>>>26,w=t[25]<<11|t[24]>>>21,A=t[24]<<11|t[25]>>>21,J=t[34]<<15|t[35]>>>17,W=t[35]<<15|t[34]>>>17,O=t[45]<<29|t[44]>>>3,U=t[44]<<29|t[45]>>>3,F=t[6]<<28|t[7]>>>4,x=t[7]<<28|t[6]>>>4,it=t[17]<<23|t[16]>>>9,ot=t[16]<<23|t[17]>>>9,k=t[26]<<25|t[27]>>>7,T=t[27]<<25|t[26]>>>7,b=t[36]<<21|t[37]>>>11,y=t[37]<<21|t[36]>>>11,X=t[47]<<24|t[46]>>>8,tt=t[46]<<24|t[47]>>>8,V=t[8]<<27|t[9]>>>5,j=t[9]<<27|t[8]>>>5,v=t[18]<<20|t[19]>>>12,E=t[19]<<20|t[18]>>>12,nt=t[29]<<7|t[28]>>>25,rt=t[28]<<7|t[29]>>>25,R=t[38]<<8|t[39]>>>24,N=t[39]<<8|t[38]>>>24,I=t[48]<<14|t[49]>>>18,C=t[49]<<14|t[48]>>>18,t[0]=p^~m&w,t[1]=h^~L&A,t[10]=F^~v&B,t[11]=x^~E&S,t[20]=z^~Q&k,t[21]=q^~M&T,t[30]=V^~H&Z,t[31]=j^~$&Y,t[40]=et^~it&nt,t[41]=at^~ot&rt,t[2]=m^~w&b,t[3]=L^~A&y,t[12]=v^~B&G,t[13]=E^~S&P,t[22]=Q^~k&R,t[23]=M^~T&N,t[32]=H^~Z&J,t[33]=$^~Y&W,t[42]=it^~nt<,t[43]=ot^~rt&ct,t[4]=w^~b&I,t[5]=A^~y&C,t[14]=B^~G&O,t[15]=S^~P&U,t[24]=k^~R&D,t[25]=T^~N&K,t[34]=Z^~J&X,t[35]=Y^~W&tt,t[44]=nt^~lt&st,t[45]=rt^~ct&dt,t[6]=b^~I&p,t[7]=y^~C&h,t[16]=G^~O&F,t[17]=P^~U&x,t[26]=R^~D&z,t[27]=N^~K&q,t[36]=J^~X&V,t[37]=W^~tt&j,t[46]=lt^~st&et,t[47]=ct^~dt&at,t[8]=I^~p&m,t[9]=C^~h&L,t[18]=O^~F&v,t[19]=U^~x&E,t[28]=D^~z&Q,t[29]=K^~q&M,t[38]=X^~V&H,t[39]=tt^~j&$,t[48]=st^~et&it,t[49]=dt^~at&ot,t[0]^=u[i],t[1]^=u[i+1]};if(n)t.exports=I;else for(F=0;F3*c.domainSize-4&&!d.isZero(e))throw new Error("T Polynomial is not divisible")}a&&a.debug("ifft Tz");const x=await d.ifft(I);for(let t=0;t<4*c.domainSize;t++){const e=x.slice(t*g,(t+1)*g);if(t>3*c.domainSize+5){if(!d.isZero(e))throw new Error("Tz Polynomial is not well calculated")}else F.set(d.add(F.slice(t*g,(t+1)*g),e),t*g)}function E(t,e,a,i,o){let n,r;const l=d.mul(t,e),c=d.mul(t,i),s=d.mul(a,e);n=l;let u=d.mul(a,i);return r=d.add(c,s),o&&(r=d.add(r,d.mul(_[o],u))),[n,r]}function G(t,e,a,i,o,n,r,l,c){let s,u;const g=d.mul(t,e),f=d.mul(t,n),p=d.mul(o,e),L=d.mul(o,n),w=d.mul(a,i),A=d.mul(a,l),b=d.mul(r,i),y=d.mul(r,l);s=d.mul(g,w);let I=d.mul(p,w);I=d.add(I,d.mul(f,w)),I=d.add(I,d.mul(g,b)),I=d.add(I,d.mul(g,A));let C=d.mul(L,w);C=d.add(C,d.mul(p,b)),C=d.add(C,d.mul(p,A)),C=d.add(C,d.mul(f,b)),C=d.add(C,d.mul(f,A)),C=d.add(C,d.mul(g,y));let F=d.mul(f,y);F=d.add(F,d.mul(p,y)),F=d.add(F,d.mul(L,A)),F=d.add(F,d.mul(L,b));let x=d.mul(L,y);return u=I,c&&(u=d.add(u,d.mul(_[c],C)),u=d.add(u,d.mul(h[c],F)),u=d.add(u,d.mul(m[c],x))),[s,u]}v=F.slice(0,(3*c.domainSize+6)*g),B.T1=await N(F.slice(0,c.domainSize*g),"multiexp T1"),B.T2=await N(F.slice(c.domainSize*g,2*c.domainSize*g),"multiexp T2"),B.T3=await N(F.slice(2*c.domainSize*g,(3*c.domainSize+6)*g),"multiexp T3")}(),await async function(){const t=new fe(c.domainSize*g);await r.readToBuffer(t,0,c.domainSize*g,l[7][0].p);const e=new fe(c.domainSize*g);await r.readToBuffer(e,0,c.domainSize*g,l[8][0].p);const i=new fe(c.domainSize*g);await r.readToBuffer(i,0,c.domainSize*g,l[9][0].p);const o=new fe(c.domainSize*g);await r.readToBuffer(o,0,c.domainSize*g,l[10][0].p);const n=new fe(c.domainSize*g);await r.readToBuffer(n,0,c.domainSize*g,l[11][0].p);const s=new fe(c.domainSize*g);await r.readToBuffer(s,0,c.domainSize*g,l[12][0].p+10*c.domainSize*g);const f=new Uint8Array(2*u.F.n8*3);u.toRprUncompressed(f,0,B.T1),u.toRprUncompressed(f,2*u.F.n8,B.T2),u.toRprUncompressed(f,4*u.F.n8,B.T3),z.xi=k(f),a&&a.debug("xi: "+d.toString(z.xi));B.eval_a=T(I,z.xi),B.eval_b=T(C,z.xi),B.eval_c=T(F,z.xi),B.eval_s1=T(P,z.xi),B.eval_s2=T(O,z.xi),B.eval_t=T(v,z.xi),B.eval_zw=T(x,d.mul(z.xi,d.w[c.power]));const _=d.mul(B.eval_a,B.eval_b);let p=B.eval_a;const h=d.mul(z.beta,z.xi);p=d.add(p,h),p=d.add(p,z.gamma);let m=B.eval_b;m=d.add(m,d.mul(h,c.k1)),m=d.add(m,z.gamma);let L=B.eval_c;L=d.add(L,d.mul(h,c.k2)),L=d.add(L,z.gamma);const w=d.mul(d.mul(d.mul(p,m),L),z.alpha);let A=B.eval_a;A=d.add(A,d.mul(z.beta,B.eval_s1)),A=d.add(A,z.gamma);let b=B.eval_b;b=d.add(b,d.mul(z.beta,B.eval_s2)),b=d.add(b,z.gamma);let y=d.mul(A,b);y=d.mul(y,z.beta),y=d.mul(y,B.eval_zw),y=d.mul(y,z.alpha),z.xim=z.xi;for(let t=0;t=0;o--)i=d.add(d.mul(i,e),t.slice(o*g,(o+1)*g));return i}function R(t,e){const a=t.byteLength/g,i=new fe(a*g);i.set(d.zero,(a-1)*g),i.set(t.slice((a-1)*g,a*g),(a-2)*g);for(let o=a-3;o>=0;o--)i.set(d.add(t.slice((o+1)*g,(o+2)*g),d.mul(e,i.slice((o+1)*g,(o+2)*g))),o*g);if(!d.eq(t.slice(0,g),d.mul(d.neg(e),i.slice(0,g))))throw new Error("Polinomial does not divide");return i}async function N(t,e){const i=t.byteLength/g,o=U.slice(0,i*s.G1.F.n8*2),n=await s.Fr.batchFromMontgomery(t);let r=await s.G1.multiExpAffine(o,n,a,e);return r=s.G1.toAffine(r),r}async function D(t,e){e=e||[];let a=await d.ifft(t);const i=new fe(g*c.domainSize*4);i.set(a,0);const o=new fe(g*(c.domainSize+e.length));o.set(a,0);for(let t=0;t>1),a=t.slice(t.length>>1),i=n(e),o=n(a),l=i[0],c=o[0],s=w++,d=r.Fr.zero,u=_.neg(i[1]),g=_.neg(o[1]),f=r.Fr.one,p=r.Fr.zero;return m.push([l,c,s,d,u,g,f,p]),L.push([l,c,i[1],o[1]]),[s,r.Fr.one]}for(let t=1;t<=A;t++){const e=t,a=0,i=0,o=r.Fr.zero,n=r.Fr.one,l=r.Fr.zero,c=r.Fr.zero,s=r.Fr.zero;m.push([e,a,i,o,n,l,c,s])}for(let t=0;tl)return i&&i.error(`circuit too big for this power of tau ceremony. ${m.length} > 2**${l}`),-1;if(!n[12])return i&&i.error("Powers of tau is not prepared."),-1;const C=new fe(I*u),F=n[12][0].p+(2**y-1)*u;await o.readToBuffer(C,0,I*u,F);const[x,v]=function(){let t=_.two;for(;a(t,[],y);)_.add(t,_.one);let e=_.add(t,_.one);for(;a(e,[t],y);)_.add(e,_.one);return[t,e];function a(t,e,a){const i=2**a;let o=_.one;for(let n=0;n>BigInt(I)}const t=Q,i=B;var E=Object.freeze({__proto__:null,fromString:g,e:C,fromArray:function(A,I){let g=0n;I=BigInt(I);for(let C=0;C>=1n}return g},bits:function(A){let I=BigInt(A);const g=[];for(;I;)1n&I?g.push(1):g.push(0),I>>=1n;return g},toNumber:function(A){if(A>BigInt(Number.MAX_SAFE_INTEGER))throw new Error("Number too big");return Number(A)},toArray:function(A,I){const g=[];let C=BigInt(A);for(I=BigInt(I);C;)g.unshift(Number(C%I)),C/=I;return g},add:function(A,I){return BigInt(A)+BigInt(I)},sub:function(A,I){return BigInt(A)-BigInt(I)},neg:function(A){return-BigInt(A)},mul:function(A,I){return BigInt(A)*BigInt(I)},square:function(A){return BigInt(A)*BigInt(A)},pow:function(A,I){return BigInt(A)**BigInt(I)},exp:function(A,I){return BigInt(A)**BigInt(I)},abs:function(A){return BigInt(A)>=0?BigInt(A):-BigInt(A)},div:function(A,I){return BigInt(A)/BigInt(I)},mod:function(A,I){return BigInt(A)%BigInt(I)},eq:function(A,I){return BigInt(A)==BigInt(I)},neq:function(A,I){return BigInt(A)!=BigInt(I)},lt:function(A,I){return BigInt(A)BigInt(I)},leq:function(A,I){return BigInt(A)<=BigInt(I)},geq:function(A,I){return BigInt(A)>=BigInt(I)},band:function(A,I){return BigInt(A)&BigInt(I)},bor:function(A,I){return BigInt(A)|BigInt(I)},bxor:function(A,I){return BigInt(A)^BigInt(I)},land:function(A,I){return BigInt(A)&&BigInt(I)},lor:function(A,I){return BigInt(A)||BigInt(I)},lnot:function(A){return!BigInt(A)}});function e(A){var I={exports:{}};return A(I,I.exports),I.exports}var n=e((function(A){var I=function(A){var g=1e7,C=9007199254740992,Q=o(C),B="0123456789abcdefghijklmnopqrstuvwxyz",t="function"==typeof BigInt;function i(A,I,g,C){return void 0===A?i[0]:void 0!==I&&(10!=+I||g)?Z(A,I,g,C):j(A)}function E(A,I){this.value=A,this.sign=I,this.isSmall=!1}function e(A){this.value=A,this.sign=A<0,this.isSmall=!0}function n(A){this.value=A}function a(A){return-C0?Math.floor(A):Math.ceil(A)}function f(A,I){var C,Q,B=A.length,t=I.length,i=new Array(B),E=0,e=g;for(Q=0;Q=e?1:0,i[Q]=C-E*e;for(;Q0&&i.push(E),i}function D(A,I){return A.length>=I.length?f(A,I):f(I,A)}function c(A,I){var C,Q,B=A.length,t=new Array(B),i=g;for(Q=0;Q0;)t[Q++]=I%i,I=Math.floor(I/i);return t}function y(A,I){var C,Q,B=A.length,t=I.length,i=new Array(B),E=0,e=g;for(C=0;C0;)t[Q++]=E%i,E=Math.floor(E/i);return t}function p(A,I){for(var g=[];I-- >0;)g.push(0);return g.concat(A)}function l(A,I){var g=Math.max(A.length,I.length);if(g<=30)return M(A,I);g=Math.ceil(g/2);var C=A.slice(g),Q=A.slice(0,g),B=I.slice(g),t=I.slice(0,g),i=l(Q,t),E=l(C,B),e=l(D(Q,C),D(t,B)),n=D(D(i,p(y(y(e,i),E),g)),p(E,2*g));return r(n),n}function H(A,I,C){return new E(A=0;--g)Q=(B=1e7*Q+A[g])-(C=s(B/I))*I,i[g]=0|C;return[i,0|Q]}function d(A,I){var C,Q=j(I);if(t)return[new n(A.value/Q.value),new n(A.value%Q.value)];var B,a=A.value,f=Q.value;if(0===f)throw new Error("Cannot divide by zero");if(A.isSmall)return Q.isSmall?[new e(s(a/f)),new e(a%f)]:[i[0],A];if(Q.isSmall){if(1===f)return[A,i[0]];if(-1==f)return[A.negate(),i[0]];var D=Math.abs(f);if(D=0;Q--){for(C=o-1,D[Q+a]!==s&&(C=Math.floor((D[Q+a]*o+D[Q+a-1])/s)),B=0,t=0,E=c.length,i=0;ie&&(B=(B+1)*o),C=Math.ceil(B/t);do{if(m(i=u(I,C),a)<=0)break;C--}while(C);n.push(C),a=y(a,i)}return n.reverse(),[h(n),h(a)]}(a,f))[0];var M=A.sign!==Q.sign,p=C[1],l=A.sign;return"number"==typeof B?(M&&(B=-B),B=new e(B)):B=new E(B,M),"number"==typeof p?(l&&(p=-p),p=new e(p)):p=new E(p,l),[B,p]}function m(A,I){if(A.length!==I.length)return A.length>I.length?1:-1;for(var g=A.length-1;g>=0;g--)if(A[g]!==I[g])return A[g]>I[g]?1:-1;return 0}function L(A){var I=A.abs();return!I.isUnit()&&(!!(I.equals(2)||I.equals(3)||I.equals(5))||!(I.isEven()||I.isDivisibleBy(3)||I.isDivisibleBy(5))&&(!!I.lesser(49)||void 0))}function J(A,g){for(var C,Q,B,t=A.prev(),i=t,E=0;i.isEven();)i=i.divide(2),E++;A:for(Q=0;Q=0?C=y(A,I):(C=y(I,A),g=!g),"number"==typeof(C=h(C))?(g&&(C=-C),new e(C)):new E(C,g)}(g,C,this.sign)},E.prototype.minus=E.prototype.subtract,e.prototype.subtract=function(A){var I=j(A),g=this.value;if(g<0!==I.sign)return this.add(I.negate());var C=I.value;return I.isSmall?new e(g-C):F(C,Math.abs(g),g>=0)},e.prototype.minus=e.prototype.subtract,n.prototype.subtract=function(A){return new n(this.value-j(A).value)},n.prototype.minus=n.prototype.subtract,E.prototype.negate=function(){return new E(this.value,!this.sign)},e.prototype.negate=function(){var A=this.sign,I=new e(-this.value);return I.sign=!A,I},n.prototype.negate=function(){return new n(-this.value)},E.prototype.abs=function(){return new E(this.value,!1)},e.prototype.abs=function(){return new e(Math.abs(this.value))},n.prototype.abs=function(){return new n(this.value>=0?this.value:-this.value)},E.prototype.multiply=function(A){var I,C,Q,B=j(A),t=this.value,e=B.value,n=this.sign!==B.sign;if(B.isSmall){if(0===e)return i[0];if(1===e)return this;if(-1===e)return this.negate();if((I=Math.abs(e))0?l(t,e):M(t,e),n)},E.prototype.times=E.prototype.multiply,e.prototype._multiplyBySmall=function(A){return a(A.value*this.value)?new e(A.value*this.value):H(Math.abs(A.value),o(Math.abs(this.value)),this.sign!==A.sign)},E.prototype._multiplyBySmall=function(A){return 0===A.value?i[0]:1===A.value?this:-1===A.value?this.negate():H(Math.abs(A.value),this.value,this.sign!==A.sign)},e.prototype.multiply=function(A){return j(A)._multiplyBySmall(this)},e.prototype.times=e.prototype.multiply,n.prototype.multiply=function(A){return new n(this.value*j(A).value)},n.prototype.times=n.prototype.multiply,E.prototype.square=function(){return new E(G(this.value),!1)},e.prototype.square=function(){var A=this.value*this.value;return a(A)?new e(A):new E(G(o(Math.abs(this.value))),!1)},n.prototype.square=function(A){return new n(this.value*this.value)},E.prototype.divmod=function(A){var I=d(this,A);return{quotient:I[0],remainder:I[1]}},n.prototype.divmod=e.prototype.divmod=E.prototype.divmod,E.prototype.divide=function(A){return d(this,A)[0]},n.prototype.over=n.prototype.divide=function(A){return new n(this.value/j(A).value)},e.prototype.over=e.prototype.divide=E.prototype.over=E.prototype.divide,E.prototype.mod=function(A){return d(this,A)[1]},n.prototype.mod=n.prototype.remainder=function(A){return new n(this.value%j(A).value)},e.prototype.remainder=e.prototype.mod=E.prototype.remainder=E.prototype.mod,E.prototype.pow=function(A){var I,g,C,Q=j(A),B=this.value,t=Q.value;if(0===t)return i[1];if(0===B)return i[0];if(1===B)return i[1];if(-1===B)return Q.isEven()?i[1]:i[-1];if(Q.sign)return i[0];if(!Q.isSmall)throw new Error("The exponent "+Q.toString()+" is too large.");if(this.isSmall&&a(I=Math.pow(B,t)))return new e(s(I));for(g=this,C=i[1];!0&t&&(C=C.times(g),--t),0!==t;)t/=2,g=g.square();return C},e.prototype.pow=E.prototype.pow,n.prototype.pow=function(A){var I=j(A),g=this.value,C=I.value,Q=BigInt(0),B=BigInt(1),t=BigInt(2);if(C===Q)return i[1];if(g===Q)return i[0];if(g===B)return i[1];if(g===BigInt(-1))return I.isEven()?i[1]:i[-1];if(I.isNegative())return new n(Q);for(var E=this,e=i[1];(C&B)===B&&(e=e.times(E),--C),C!==Q;)C/=t,E=E.square();return e},E.prototype.modPow=function(A,I){if(A=j(A),(I=j(I)).isZero())throw new Error("Cannot take modPow with modulus 0");var g=i[1],C=this.mod(I);for(A.isNegative()&&(A=A.multiply(i[-1]),C=C.modInv(I));A.isPositive();){if(C.isZero())return i[0];A.isOdd()&&(g=g.multiply(C).mod(I)),A=A.divide(2),C=C.square().mod(I)}return g},n.prototype.modPow=e.prototype.modPow=E.prototype.modPow,E.prototype.compareAbs=function(A){var I=j(A),g=this.value,C=I.value;return I.isSmall?1:m(g,C)},e.prototype.compareAbs=function(A){var I=j(A),g=Math.abs(this.value),C=I.value;return I.isSmall?g===(C=Math.abs(C))?0:g>C?1:-1:-1},n.prototype.compareAbs=function(A){var I=this.value,g=j(A).value;return(I=I>=0?I:-I)===(g=g>=0?g:-g)?0:I>g?1:-1},E.prototype.compare=function(A){if(A===1/0)return-1;if(A===-1/0)return 1;var I=j(A),g=this.value,C=I.value;return this.sign!==I.sign?I.sign?1:-1:I.isSmall?this.sign?-1:1:m(g,C)*(this.sign?-1:1)},E.prototype.compareTo=E.prototype.compare,e.prototype.compare=function(A){if(A===1/0)return-1;if(A===-1/0)return 1;var I=j(A),g=this.value,C=I.value;return I.isSmall?g==C?0:g>C?1:-1:g<0!==I.sign?g<0?-1:1:g<0?1:-1},e.prototype.compareTo=e.prototype.compare,n.prototype.compare=function(A){if(A===1/0)return-1;if(A===-1/0)return 1;var I=this.value,g=j(A).value;return I===g?0:I>g?1:-1},n.prototype.compareTo=n.prototype.compare,E.prototype.equals=function(A){return 0===this.compare(A)},n.prototype.eq=n.prototype.equals=e.prototype.eq=e.prototype.equals=E.prototype.eq=E.prototype.equals,E.prototype.notEquals=function(A){return 0!==this.compare(A)},n.prototype.neq=n.prototype.notEquals=e.prototype.neq=e.prototype.notEquals=E.prototype.neq=E.prototype.notEquals,E.prototype.greater=function(A){return this.compare(A)>0},n.prototype.gt=n.prototype.greater=e.prototype.gt=e.prototype.greater=E.prototype.gt=E.prototype.greater,E.prototype.lesser=function(A){return this.compare(A)<0},n.prototype.lt=n.prototype.lesser=e.prototype.lt=e.prototype.lesser=E.prototype.lt=E.prototype.lesser,E.prototype.greaterOrEquals=function(A){return this.compare(A)>=0},n.prototype.geq=n.prototype.greaterOrEquals=e.prototype.geq=e.prototype.greaterOrEquals=E.prototype.geq=E.prototype.greaterOrEquals,E.prototype.lesserOrEquals=function(A){return this.compare(A)<=0},n.prototype.leq=n.prototype.lesserOrEquals=e.prototype.leq=e.prototype.lesserOrEquals=E.prototype.leq=E.prototype.lesserOrEquals,E.prototype.isEven=function(){return 0==(1&this.value[0])},e.prototype.isEven=function(){return 0==(1&this.value)},n.prototype.isEven=function(){return(this.value&BigInt(1))===BigInt(0)},E.prototype.isOdd=function(){return 1==(1&this.value[0])},e.prototype.isOdd=function(){return 1==(1&this.value)},n.prototype.isOdd=function(){return(this.value&BigInt(1))===BigInt(1)},E.prototype.isPositive=function(){return!this.sign},e.prototype.isPositive=function(){return this.value>0},n.prototype.isPositive=e.prototype.isPositive,E.prototype.isNegative=function(){return this.sign},e.prototype.isNegative=function(){return this.value<0},n.prototype.isNegative=e.prototype.isNegative,E.prototype.isUnit=function(){return!1},e.prototype.isUnit=function(){return 1===Math.abs(this.value)},n.prototype.isUnit=function(){return this.abs().value===BigInt(1)},E.prototype.isZero=function(){return!1},e.prototype.isZero=function(){return 0===this.value},n.prototype.isZero=function(){return this.value===BigInt(0)},E.prototype.isDivisibleBy=function(A){var I=j(A);return!I.isZero()&&(!!I.isUnit()||(0===I.compareAbs(2)?this.isEven():this.mod(I).isZero()))},n.prototype.isDivisibleBy=e.prototype.isDivisibleBy=E.prototype.isDivisibleBy,E.prototype.isPrime=function(g){var C=L(this);if(C!==A)return C;var Q=this.abs(),B=Q.bitLength();if(B<=64)return J(Q,[2,3,5,7,11,13,17,19,23,29,31,37]);for(var t=Math.log(2)*B.toJSNumber(),i=Math.ceil(!0===g?2*Math.pow(t,2):t),E=[],e=0;e-C?new e(A-1):new E(Q,!0)},n.prototype.prev=function(){return new n(this.value-BigInt(1))};for(var k=[1];2*k[k.length-1]<=g;)k.push(2*k[k.length-1]);var N=k.length,b=k[N-1];function R(A){return Math.abs(A)<=g}function S(A,g,C){g=j(g);for(var Q=A.isNegative(),B=g.isNegative(),t=Q?A.not():A,i=B?g.not():g,E=0,e=0,n=null,a=null,o=[];!t.isZero()||!i.isZero();)E=(n=d(t,b))[1].toJSNumber(),Q&&(E=b-1-E),e=(a=d(i,b))[1].toJSNumber(),B&&(e=b-1-e),t=n[0],i=a[0],o.push(C(E,e));for(var h=0!==C(Q?1:0,B?1:0)?I(-1):I(0),r=o.length-1;r>=0;r-=1)h=h.multiply(b).add(I(o[r]));return h}E.prototype.shiftLeft=function(A){var I=j(A).toJSNumber();if(!R(I))throw new Error(String(I)+" is too large for shifting.");if(I<0)return this.shiftRight(-I);var g=this;if(g.isZero())return g;for(;I>=N;)g=g.multiply(b),I-=N-1;return g.multiply(k[I])},n.prototype.shiftLeft=e.prototype.shiftLeft=E.prototype.shiftLeft,E.prototype.shiftRight=function(A){var I,g=j(A).toJSNumber();if(!R(g))throw new Error(String(g)+" is too large for shifting.");if(g<0)return this.shiftLeft(-g);for(var C=this;g>=N;){if(C.isZero()||C.isNegative()&&C.isUnit())return C;C=(I=d(C,b))[1].isNegative()?I[0].prev():I[0],g-=N-1}return(I=d(C,k[g]))[1].isNegative()?I[0].prev():I[0]},n.prototype.shiftRight=e.prototype.shiftRight=E.prototype.shiftRight,E.prototype.not=function(){return this.negate().prev()},n.prototype.not=e.prototype.not=E.prototype.not,E.prototype.and=function(A){return S(this,A,(function(A,I){return A&I}))},n.prototype.and=e.prototype.and=E.prototype.and,E.prototype.or=function(A){return S(this,A,(function(A,I){return A|I}))},n.prototype.or=e.prototype.or=E.prototype.or,E.prototype.xor=function(A){return S(this,A,(function(A,I){return A^I}))},n.prototype.xor=e.prototype.xor=E.prototype.xor;var v=1<<30;function Y(A){var I=A.value,C="number"==typeof I?I|v:"bigint"==typeof I?I|BigInt(v):I[0]+I[1]*g|1073758208;return C&-C}function P(A,g){if(g.compareTo(A)<=0){var C=P(A,g.square(g)),Q=C.p,B=C.e,t=Q.multiply(g);return t.compareTo(A)<=0?{p:t,e:2*B+1}:{p:Q,e:2*B}}return{p:I(1),e:0}}function q(A,I){return A=j(A),I=j(I),A.greater(I)?A:I}function x(A,I){return A=j(A),I=j(I),A.lesser(I)?A:I}function X(A,I){if(A=j(A).abs(),I=j(I).abs(),A.equals(I))return A;if(A.isZero())return I;if(I.isZero())return A;for(var g,C,Q=i[1];A.isEven()&&I.isEven();)g=x(Y(A),Y(I)),A=A.divide(g),I=I.divide(g),Q=Q.multiply(g);for(;A.isEven();)A=A.divide(Y(A));do{for(;I.isEven();)I=I.divide(Y(I));A.greater(I)&&(C=I,I=A,A=C),I=I.subtract(A)}while(!I.isZero());return Q.isUnit()?A:A.multiply(Q)}E.prototype.bitLength=function(){var A=this;return A.compareTo(I(0))<0&&(A=A.negate().subtract(I(1))),0===A.compareTo(I(0))?I(0):I(P(A,I(2)).e).add(I(1))},n.prototype.bitLength=e.prototype.bitLength=E.prototype.bitLength;var Z=function(A,I,g,C){g=g||B,A=String(A),C||(A=A.toLowerCase(),g=g.toLowerCase());var Q,t=A.length,i=Math.abs(I),E={};for(Q=0;Q=i)){if("1"===a&&1===i)continue;throw new Error(a+" is not a valid digit in base "+I+".")}}I=j(I);var e=[],n="-"===A[0];for(Q=n?1:0;Q"!==A[Q]&&Q=0;C--)Q=Q.add(A[C].times(B)),B=B.times(I);return g?Q.negate():Q}function K(A,g){if((g=I(g)).isZero()){if(A.isZero())return{value:[0],isNegative:!1};throw new Error("Cannot convert nonzero numbers to base 0.")}if(g.equals(-1)){if(A.isZero())return{value:[0],isNegative:!1};if(A.isNegative())return{value:[].concat.apply([],Array.apply(null,Array(-A.toJSNumber())).map(Array.prototype.valueOf,[1,0])),isNegative:!1};var C=Array.apply(null,Array(A.toJSNumber()-1)).map(Array.prototype.valueOf,[0,1]);return C.unshift([1]),{value:[].concat.apply([],C),isNegative:!1}}var Q=!1;if(A.isNegative()&&g.isPositive()&&(Q=!0,A=A.abs()),g.isUnit())return A.isZero()?{value:[0],isNegative:!1}:{value:Array.apply(null,Array(A.toJSNumber())).map(Number.prototype.valueOf,1),isNegative:Q};for(var B,t=[],i=A;i.isNegative()||i.compareAbs(g)>=0;){B=i.divmod(g),i=B.quotient;var E=B.remainder;E.isNegative()&&(E=g.minus(E).abs(),i=i.next()),t.push(E.toJSNumber())}return t.push(i.toJSNumber()),{value:t.reverse(),isNegative:Q}}function W(A,I,g){var C=K(A,I);return(C.isNegative?"-":"")+C.value.map((function(A){return function(A,I){return A<(I=I||B).length?I[A]:"<"+A+">"}(A,g)})).join("")}function O(A){if(a(+A)){var I=+A;if(I===s(I))return t?new n(BigInt(I)):new e(I);throw new Error("Invalid integer: "+A)}var g="-"===A[0];g&&(A=A.slice(1));var C=A.split(/e/i);if(C.length>2)throw new Error("Invalid integer: "+C.join("e"));if(2===C.length){var Q=C[1];if("+"===Q[0]&&(Q=Q.slice(1)),(Q=+Q)!==s(Q)||!a(Q))throw new Error("Invalid integer: "+Q+" is not a valid exponent.");var B=C[0],i=B.indexOf(".");if(i>=0&&(Q-=B.length-i-1,B=B.slice(0,i)+B.slice(i+1)),Q<0)throw new Error("Cannot include negative exponent part for integers");A=B+=new Array(Q+1).join("0")}if(!/^([0-9][0-9]*)$/.test(A))throw new Error("Invalid integer: "+A);if(t)return new n(BigInt(g?"-"+A:A));for(var o=[],h=A.length,w=h-7;h>0;)o.push(+A.slice(w,h)),(w-=7)<0&&(w=0),h-=7;return r(o),new E(o,g)}function j(A){return"number"==typeof A?function(A){if(t)return new n(BigInt(A));if(a(A)){if(A!==s(A))throw new Error(A+" is not an integer.");return new e(A)}return O(A.toString())}(A):"string"==typeof A?O(A):"bigint"==typeof A?new n(A):A}E.prototype.toArray=function(A){return K(this,A)},e.prototype.toArray=function(A){return K(this,A)},n.prototype.toArray=function(A){return K(this,A)},E.prototype.toString=function(I,g){if(I===A&&(I=10),10!==I)return W(this,I,g);for(var C,Q=this.value,B=Q.length,t=String(Q[--B]);--B>=0;)C=String(Q[B]),t+="0000000".slice(C.length)+C;return(this.sign?"-":"")+t},e.prototype.toString=function(I,g){return I===A&&(I=10),10!=I?W(this,I,g):String(this.value)},n.prototype.toString=e.prototype.toString,n.prototype.toJSON=E.prototype.toJSON=e.prototype.toJSON=function(){return this.toString()},E.prototype.valueOf=function(){return parseInt(this.toString(),10)},E.prototype.toJSNumber=E.prototype.valueOf,e.prototype.valueOf=function(){return this.value},e.prototype.toJSNumber=e.prototype.valueOf,n.prototype.valueOf=n.prototype.toJSNumber=function(){return parseInt(this.toString(),10)};for(var z=0;z<1e3;z++)i[z]=j(z),z>0&&(i[-z]=j(-z));return i.one=i[1],i.zero=i[0],i.minusOne=i[-1],i.max=q,i.min=x,i.gcd=X,i.lcm=function(A,I){return A=j(A).abs(),I=j(I).abs(),A.divide(X(A,I)).multiply(I)},i.isInstance=function(A){return A instanceof E||A instanceof e||A instanceof n},i.randBetween=function(A,I,C){A=j(A),I=j(I);var Q=C||Math.random,B=x(A,I),t=q(A,I).subtract(B).add(1);if(t.isSmall)return B.add(Math.floor(Q()*t));for(var E=K(t,g).value,e=[],n=!0,a=0;a>5);for(let A=0;A>5);for(let A=0;AQ[Q.length-I-1]=A.toString(16).padStart(8,"0"))),c.fromString(Q.join(""),16)},c.fromRprBE=function(A,I,g){g=g||A.byteLength;const C=new DataView(A.buffer,A.byteOffset+I,g),Q=new Array(g/4);for(let A=0;A>=1;return g}function rA(A,I,g){if(k(g))return A.one;const C=P(g);if(0==C.legth)return A.one;let Q=I;for(let g=C.length-2;g>=0;g--)Q=A.square(Q),C[g]&&(Q=A.mul(Q,I));return Q}function wA(A){if(A.m%2==1)if($(_(A.p,4),1))if($(_(A.p,8),1))if($(_(A.p,16),1))!function(A){A.sqrt_q=O(A.p,A.m),A.sqrt_s=0,A.sqrt_t=Z(A.sqrt_q,1);for(;!v(A.sqrt_t);)A.sqrt_s=A.sqrt_s+1,A.sqrt_t=T(A.sqrt_t,2);let I=A.one;for(;A.eq(I,A.one);){const g=A.random();A.sqrt_z=A.pow(g,A.sqrt_t),I=A.pow(A.sqrt_z,2**(A.sqrt_s-1))}A.sqrt_tm1d2=T(Z(A.sqrt_t,1),2),A.sqrt=function(A){const I=this;if(I.isZero(A))return I.zero;let g=I.pow(A,I.sqrt_tm1d2);const C=I.pow(I.mul(I.square(g),A),2**(I.sqrt_s-1));if(I.eq(C,I.negone))return null;let Q=I.sqrt_s,B=I.mul(A,g),t=I.mul(B,g),i=I.sqrt_z;for(;!I.eq(t,I.one);){let A=I.square(t),C=1;for(;!I.eq(A,I.one);)A=I.square(A),C++;g=i;for(let A=0;A>>0,A[Q]=(A[Q]^A[I])>>>0,A[Q]=(A[Q]<<16|A[Q]>>>16&65535)>>>0,A[C]=A[C]+A[Q]>>>0,A[g]=(A[g]^A[C])>>>0,A[g]=(A[g]<<12|A[g]>>>20&4095)>>>0,A[I]=A[I]+A[g]>>>0,A[Q]=(A[Q]^A[I])>>>0,A[Q]=(A[Q]<<8|A[Q]>>>24&255)>>>0,A[C]=A[C]+A[Q]>>>0,A[g]=(A[g]^A[C])>>>0,A[g]=(A[g]<<7|A[g]>>>25&127)>>>0}class fA{constructor(A){A=A||[0,0,0,0,0,0,0,0],this.state=[1634760805,857760878,2036477234,1797285236,A[0],A[1],A[2],A[3],A[4],A[5],A[6],A[7],0,0,0,0],this.idx=16,this.buff=new Array(16)}nextU32(){return 16==this.idx&&this.update(),this.buff[this.idx++]}nextU64(){return X(K(this.nextU32(),4294967296),this.nextU32())}nextBool(){return 1==(1&this.nextU32())}update(){for(let A=0;A<16;A++)this.buff[A]=this.state[A];for(let I=0;I<10;I++)sA(A=this.buff,0,4,8,12),sA(A,1,5,9,13),sA(A,2,6,10,14),sA(A,3,7,11,15),sA(A,0,5,10,15),sA(A,1,6,11,12),sA(A,2,7,8,13),sA(A,3,4,9,14);var A;for(let A=0;A<16;A++)this.buff[A]=this.buff[A]+this.state[A]>>>0;this.idx=0,this.state[12]=this.state[12]+1>>>0,0==this.state[12]&&(this.state[13]=this.state[13]+1>>>0,0==this.state[13]&&(this.state[14]=this.state[14]+1>>>0,0==this.state[14]&&(this.state[15]=this.state[15]+1>>>0)))}}var DA={};function cA(A){let I=new Uint8Array(A);if("undefined"!=typeof window)if(void 0!==window.crypto)window.crypto.getRandomValues(I);else for(let g=0;g>>0;else DA.randomFillSync(I);return I}let yA=null;function FA(){return yA||(yA=new fA(function(){const A=cA(32),I=new Uint32Array(A.buffer),g=[];for(let A=0;A<8;A++)g.push(I[A]);return g}()),yA)}class MA{constructor(A){this.type="F1",this.one=1n,this.zero=0n,this.p=BigInt(A),this.m=1,this.negone=this.p-1n,this.two=2n,this.half=this.p>>1n,this.bitLength=L(this.p),this.mask=(1n<>1n;this.nqr=this.two;let g=this.pow(this.nqr,I);for(;!this.eq(g,this.negone);)this.nqr=this.nqr+1n,g=this.pow(this.nqr,I);for(this.s=0,this.t=this.negone;0n==(1n&this.t);)this.s=this.s+1,this.t=this.t>>1n;this.nqr_to_t=this.pow(this.nqr,this.t),wA(this)}e(A,I){let g;if(I?16==I&&(g=BigInt("0x"+A)):g=BigInt(A),g<0){let A=-g;return A>=this.p&&(A%=this.p),this.p-A}return g>=this.p?g%this.p:g}add(A,I){const g=A+I;return g>=this.p?g-this.p:g}sub(A,I){return A>=I?A-I:this.p-I+A}neg(A){return A?this.p-A:A}mul(A,I){return A*I%this.p}mulScalar(A,I){return A*this.e(I)%this.p}square(A){return A*A%this.p}eq(A,I){return A==I}neq(A,I){return A!=I}lt(A,I){return(A>this.half?A-this.p:A)<(I>this.half?I-this.p:I)}gt(A,I){return(A>this.half?A-this.p:A)>(I>this.half?I-this.p:I)}leq(A,I){return(A>this.half?A-this.p:A)<=(I>this.half?I-this.p:I)}geq(A,I){return(A>this.half?A-this.p:A)>=(I>this.half?I-this.p:I)}div(A,I){return this.mul(A,this.inv(I))}idiv(A,I){if(!I)throw new Error("Division by zero");return A/I}inv(A){if(!A)throw new Error("Division by zero");let I=0n,g=this.p,C=1n,Q=A%this.p;for(;Q;){let A=g/Q;[I,C]=[C,I-A*C],[g,Q]=[Q,g-A*Q]}return I<0n&&(I+=this.p),I}mod(A,I){return A%I}pow(A,I){return rA(this,A,I)}exp(A,I){return rA(this,A,I)}band(A,I){const g=A&I&this.mask;return g>=this.p?g-this.p:g}bor(A,I){const g=(A|I)&this.mask;return g>=this.p?g-this.p:g}bxor(A,I){const g=(A^I)&this.mask;return g>=this.p?g-this.p:g}bnot(A){const I=A^this.mask;return I>=this.p?I-this.p:I}shl(A,I){if(Number(I)=this.p?g-this.p:g}{const g=this.p-I;return Number(g)>g:0n}}shr(A,I){if(Number(I)>I;{const g=this.p-I;if(Number(g)=this.p?I-this.p:I}return 0}}land(A,I){return A&&I?1n:0n}lor(A,I){return A||I?1n:0n}lnot(A){return A?0n:1n}sqrt_old(A){if(0n==A)return this.zero;if(1n!=this.pow(A,this.negone>>this.one))return null;let I=this.s,g=this.nqr_to_t,C=this.pow(A,this.t),Q=this.pow(A,this.add(this.t,this.one)>>1n);for(;1n!=C;){let A=this.square(C),B=1;for(;1n!=A;)B++,A=this.square(A);let t=g;for(let A=0;Athis.p>>1n&&(Q=this.neg(Q)),Q}normalize(A,I){if((A=BigInt(A,I))<0){let I=-A;return I>=this.p&&(I%=this.p),this.p-I}return A>=this.p?A%this.p:A}random(){const A=2*this.bitLength/8;let I=0n;for(let g=0;gthis.half){g="-"+(this.p-A).toString(I)}else g=A.toString(I);return g}isZero(A){return 0n==A}fromRng(A){let I;do{I=0n;for(let g=0;g=this.p);return I=I*this.Ri%this.p,I}}class uA{constructor(A){this.type="F1",this.one=n.one,this.zero=n.zero,this.p=n(A),this.m=1,this.negone=this.p.minus(n.one),this.two=n(2),this.half=this.p.shiftRight(1),this.bitLength=this.p.bitLength(),this.mask=n.one.shiftLeft(this.bitLength).minus(n.one),this.n64=Math.floor((this.bitLength-1)/64)+1,this.n32=2*this.n64,this.n8=8*this.n64,this.R=n.one.shiftLeft(64*this.n64),this.Ri=this.inv(this.R);const I=this.negone.shiftRight(this.one);this.nqr=this.two;let g=this.pow(this.nqr,I);for(;!g.equals(this.negone);)this.nqr=this.nqr.add(this.one),g=this.pow(this.nqr,I);for(this.s=this.zero,this.t=this.negone;!this.t.isOdd();)this.s=this.s.add(this.one),this.t=this.t.shiftRight(this.one);this.nqr_to_t=this.pow(this.nqr,this.t),wA(this)}e(A,I){const g=n(A,I);return this.normalize(g)}add(A,I){let g=A.add(I);return g.geq(this.p)&&(g=g.minus(this.p)),g}sub(A,I){return A.geq(I)?A.minus(I):this.p.minus(I.minus(A))}neg(A){return A.isZero()?A:this.p.minus(A)}mul(A,I){return A.times(I).mod(this.p)}mulScalar(A,I){return A.times(n(I)).mod(this.p)}square(A){return A.square().mod(this.p)}eq(A,I){return A.eq(I)}neq(A,I){return A.neq(I)}lt(A,I){const g=A.gt(this.half)?A.minus(this.p):A,C=I.gt(this.half)?I.minus(this.p):I;return g.lt(C)}gt(A,I){const g=A.gt(this.half)?A.minus(this.p):A,C=I.gt(this.half)?I.minus(this.p):I;return g.gt(C)}leq(A,I){const g=A.gt(this.half)?A.minus(this.p):A,C=I.gt(this.half)?I.minus(this.p):I;return g.leq(C)}geq(A,I){const g=A.gt(this.half)?A.minus(this.p):A,C=I.gt(this.half)?I.minus(this.p):I;return g.geq(C)}div(A,I){if(I.isZero())throw new Error("Division by zero");return A.times(I.modInv(this.p)).mod(this.p)}idiv(A,I){if(I.isZero())throw new Error("Division by zero");return A.divide(I)}inv(A){if(A.isZero())throw new Error("Division by zero");return A.modInv(this.p)}mod(A,I){return A.mod(I)}pow(A,I){return A.modPow(I,this.p)}exp(A,I){return A.modPow(I,this.p)}band(A,I){return A.and(I).and(this.mask).mod(this.p)}bor(A,I){return A.or(I).and(this.mask).mod(this.p)}bxor(A,I){return A.xor(I).and(this.mask).mod(this.p)}bnot(A){return A.xor(this.mask).mod(this.p)}shl(A,I){if(I.lt(this.bitLength))return A.shiftLeft(I).and(this.mask).mod(this.p);{const g=this.p.minus(I);return g.lt(this.bitLength)?this.shr(A,g):n.zero}}shr(A,I){if(I.lt(this.bitLength))return A.shiftRight(I);{const g=this.p.minus(I);return g.lt(this.bitLength)?this.shl(A,g):n.zero}}land(A,I){return A.isZero()||I.isZero()?n.zero:n.one}lor(A,I){return A.isZero()&&I.isZero()?n.zero:n.one}lnot(A){return A.isZero()?n.one:n.zero}sqrt_old(A){if(A.equals(this.zero))return this.zero;if(!this.pow(A,this.negone.shiftRight(this.one)).equals(this.one))return null;let I=parseInt(this.s),g=this.nqr_to_t,C=this.pow(A,this.t),Q=this.pow(A,this.add(this.t,this.one).shiftRight(this.one));for(;!C.equals(this.one);){let A=this.square(C),B=1;for(;!A.equals(this.one);)B++,A=this.square(A);let t=g;for(let A=0;A{g[C]=A(I[C])})),g}return I},unstringifyBigInts:function A(I){if("string"==typeof I&&/^[0-9]+$/.test(I))return BigInt(I);if(Array.isArray(I))return I.map(A);if("object"==typeof I){if(null===I)return null;const g={};return Object.keys(I).forEach((C=>{g[C]=A(I[C])})),g}return I},beBuff2int:function(A){let I=0n,g=A.length,C=0;const Q=new DataView(A.buffer,A.byteOffset,A.byteLength);for(;g>0;)g>=4?(g-=4,I+=BigInt(Q.getUint32(g))<=2?(g-=2,I+=BigInt(Q.getUint16(g))<0;)B-4>=0?(B-=4,Q.setUint32(B,Number(0xFFFFFFFFn&g)),g>>=32n):B-2>=0?(B-=2,Q.setUint16(B,Number(0xFFFFn&g)),g>>=16n):(B-=1,Q.setUint8(B,Number(0xFFn&g)),g>>=8n);if(g)throw new Error("Number does not fit in this length");return C},leBuff2int:function(A){let I=0n,g=0;const C=new DataView(A.buffer,A.byteOffset,A.byteLength);for(;g>=32n):B+2<=I?(Q.setUint16(Number(B,0xFFFFn&g),!0),B+=2,g>>=16n):(Q.setUint8(Number(B,0xFFn&g),!0),B+=1,g>>=8n);if(g)throw new Error("Number does not fit in this length");return C}});var mA=Object.freeze({__proto__:null,stringifyBigInts:function A(I){if("bigint"==typeof I||void 0!==I.eq)return I.toString(10);if(Array.isArray(I))return I.map(A);if("object"==typeof I){const g={};return Object.keys(I).forEach((C=>{g[C]=A(I[C])})),g}return I},unstringifyBigInts:function A(I){if("string"==typeof I&&/^[0-9]+$/.test(I))return n(I);if(Array.isArray(I))return I.map(A);if("object"==typeof I){const g={};return Object.keys(I).forEach((C=>{g[C]=A(I[C])})),g}return I},beBuff2int:function(A){let I=n.zero;for(let g=0;g=0;){let A=Number(g.and(n("255")));Q[C]=A,C--,g=g.shiftRight(8)}if(!g.eq(n.zero))throw new Error("Number does not fit in this length");return Q},leBuff2int:function(A){let I=n.zero;for(let g=0;g>=1;return g}LA.bitReverse=function(A,I){return(JA[A>>>24]|JA[A>>>16&255]<<8|JA[A>>>8&255]<<16|JA[255&A]<<24)>>>32-I},LA.log2=function(A){return(0!=(4294901760&A)?(A&=4294901760,16):0)|(0!=(4278255360&A)?(A&=4278255360,8):0)|(0!=(4042322160&A)?(A&=4042322160,4):0)|(0!=(3435973836&A)?(A&=3435973836,2):0)|0!=(2863311530&A)},LA.buffReverseBits=function(A,I){const g=A.byteLength/I,C=LA.log2(g);if(g!=1<g){const C=A.slice(Q*I,(Q+1)*I);A.set(A.slice(g*I,(g+1)*I),Q*I),A.set(C,g*I)}}};let{bitReverse:NA,log2:bA,buffReverseBits:RA,stringifyBigInts:SA,unstringifyBigInts:vA,beBuff2int:YA,beInt2Buff:PA,leBuff2int:qA,leInt2Buff:xA}=LA;var XA=Object.freeze({__proto__:null,bitReverse:NA,log2:bA,buffReverseBits:RA,stringifyBigInts:SA,unstringifyBigInts:vA,beBuff2int:YA,beInt2Buff:PA,leBuff2int:qA,leInt2Buff:xA});const ZA=1<<30;class VA{constructor(A){this.buffers=[],this.byteLength=A;for(let I=0;I0;){const A=t+i>ZA?ZA-t:i,I=new Uint8Array(this.buffers[B].buffer,this.buffers[B].byteOffset+t,A);if(A==g)return I.slice();Q||(Q=g<=ZA?new Uint8Array(g):new VA(g)),Q.set(I,g-i),i-=A,B++,t=0}return Q}set(A,I){void 0===I&&(I=0);const g=A.byteLength;if(0==g)return;const C=Math.floor(I/ZA);if(C==Math.floor((I+g-1)/ZA))return this.buffers[C].set(A,I%ZA);let Q=C,B=I%ZA,t=g;for(;t>0;){const I=B+t>ZA?ZA-B:t,C=A.slice(g-t,g-t+I);new Uint8Array(this.buffers[Q].buffer,this.buffers[Q].byteOffset+B,I).set(C),t-=I,Q++,B=0}}}function KA(A,I,g,C){return async function(Q){const B=Math.floor(Q.byteLength/g);if(B*g!==Q.byteLength)throw new Error("Invalid buffer size");const t=Math.floor(B/A.concurrency),i=[];for(let E=0;E=0;A--)this.w[A]=this.square(this.w[A+1]);if(!this.eq(this.w[0],this.one))throw new Error("Error calculating roots of unity");this.batchToMontgomery=KA(A,I+"_batchToMontgomery",this.n8,this.n8),this.batchFromMontgomery=KA(A,I+"_batchFromMontgomery",this.n8,this.n8)}op2(A,I,g){return this.tm.setBuff(this.pOp1,I),this.tm.setBuff(this.pOp2,g),this.tm.instance.exports[this.prefix+A](this.pOp1,this.pOp2,this.pOp3),this.tm.getBuff(this.pOp3,this.n8)}op2Bool(A,I,g){return this.tm.setBuff(this.pOp1,I),this.tm.setBuff(this.pOp2,g),!!this.tm.instance.exports[this.prefix+A](this.pOp1,this.pOp2)}op1(A,I){return this.tm.setBuff(this.pOp1,I),this.tm.instance.exports[this.prefix+A](this.pOp1,this.pOp3),this.tm.getBuff(this.pOp3,this.n8)}op1Bool(A,I){return this.tm.setBuff(this.pOp1,I),!!this.tm.instance.exports[this.prefix+A](this.pOp1,this.pOp3)}add(A,I){return this.op2("_add",A,I)}eq(A,I){return this.op2Bool("_eq",A,I)}isZero(A){return this.op1Bool("_isZero",A)}sub(A,I){return this.op2("_sub",A,I)}neg(A){return this.op1("_neg",A)}inv(A){return this.op1("_inverse",A)}toMontgomery(A){return this.op1("_toMontgomery",A)}fromMontgomery(A){return this.op1("_fromMontgomery",A)}mul(A,I){return this.op2("_mul",A,I)}div(A,I){return this.tm.setBuff(this.pOp1,A),this.tm.setBuff(this.pOp2,I),this.tm.instance.exports[this.prefix+"_inverse"](this.pOp2,this.pOp2),this.tm.instance.exports[this.prefix+"_mul"](this.pOp1,this.pOp2,this.pOp3),this.tm.getBuff(this.pOp3,this.n8)}square(A){return this.op1("_square",A)}isSquare(A){return this.op1Bool("_isSquare",A)}sqrt(A){return this.op1("_sqrt",A)}exp(A,I){return I instanceof Uint8Array||(I=l(d(I))),this.tm.setBuff(this.pOp1,A),this.tm.setBuff(this.pOp2,I),this.tm.instance.exports[this.prefix+"_exp"](this.pOp1,this.pOp2,I.byteLength,this.pOp3),this.tm.getBuff(this.pOp3,this.n8)}isNegative(A){return this.op1Bool("_isNegative",A)}e(A,I){if(A instanceof Uint8Array)return A;let g=d(A,I);J(g)?(g=V(g),gA(g,this.p)&&(g=_(g,this.p)),g=Z(this.p,g)):gA(g,this.p)&&(g=_(g,this.p));const C=xA(g,this.n8);return this.toMontgomery(C)}toString(A,I){const g=this.fromMontgomery(A),C=M(g,0);return p(C,I)}fromRng(A){let I;const g=new Uint8Array(this.n8);do{I=H;for(let g=0;gC.buffer.byteLength){const Q=C.buffer.byteLength/65536;let B=Math.floor((g[0]+A)/65536)+1;B>I&&(B=I),C.grow(B-Q)}return Q}function t(A){const I=B(A.byteLength);return E(I,A),I}function i(A,I){const g=new Uint8Array(C.buffer);return new Uint8Array(g.buffer,g.byteOffset+A,I)}function E(A,I){new Uint8Array(C.buffer).set(new Uint8Array(I),A)}function e(A){if("INIT"==A[0].cmd)return Q(A[0]);const I={vars:[],out:[]},e=new Uint32Array(C.buffer,0,1)[0];for(let C=0;C{this.reject=I,this.resolve=A}))}}function II(A){for(var I=window.atob(A),g=I.length,C=new Uint8Array(g),Q=0;Q0;A++)if(0==this.working[A]){const I=this.actionQueue.shift();this.postAction(A,I.data,I.transfers,I.deferred)}}queueAction(A,I){const g=new AI;if(this.singleThread){const I=this.taskManager(A);g.resolve(I)}else this.actionQueue.push({data:A,transfers:I,deferred:g}),this.processWorks();return g.promise}resetMemory(){this.u32[0]=this.initalPFree}allocBuff(A){const I=this.alloc(A.byteLength);return this.setBuff(I,A),I}getBuff(A,I){return this.u8.slice(A,A+I)}setBuff(A,I){this.u8.set(new Uint8Array(I),A)}alloc(A){for(;3&this.u32[0];)this.u32[0]++;const I=this.u32[0];return this.u32[0]+=A,I}async terminate(){for(let A=0;AsetTimeout(I,A))))}}function BI(A,I){const g=A[I],C=A.Fr,Q=A.tm;A[I].batchApplyKey=async function(A,B,t,i,E){let e,n,a,o,h;if(i=i||"affine",E=E||"affine","G1"==I)"jacobian"==i?(a=3*g.F.n8,e="g1m_batchApplyKey"):(a=2*g.F.n8,e="g1m_batchApplyKeyMixed"),o=3*g.F.n8,"jacobian"==E?h=3*g.F.n8:(n="g1m_batchToAffine",h=2*g.F.n8);else if("G2"==I)"jacobian"==i?(a=3*g.F.n8,e="g2m_batchApplyKey"):(a=2*g.F.n8,e="g2m_batchApplyKeyMixed"),o=3*g.F.n8,"jacobian"==E?h=3*g.F.n8:(n="g2m_batchToAffine",h=2*g.F.n8);else{if("Fr"!=I)throw new Error("Invalid group: "+I);e="frm_batchApplyKey",a=g.n8,o=g.n8,h=g.n8}const r=Math.floor(A.byteLength/a),w=Math.floor(r/Q.concurrency),s=[];t=C.e(t);let f=C.e(B);for(let I=0;I=0;A--){if(!g.isZero(w))for(let A=0;Ae&&(w=e),w<1024&&(w=1024);const s=[];for(let I=0;I(i&&i.debug(`Multiexp end: ${E}: ${I}/${a}`),A))))}const f=await Promise.all(s);let D=g.zero;for(let A=f.length-1;A>=0;A--)D=g.add(D,f[A]);return D}g.multiExp=async function(A,I,g,C){return await B(A,I,"jacobian",g,C)},g.multiExpAffine=async function(A,I,g,C){return await B(A,I,"affine",g,C)}}function EI(A,I){const g=A[I],C=A.Fr,Q=g.tm;async function B(i,E,e,n,a,o){e=e||"affine",n=n||"affine";let h,r,w,s,f,D,c,y;"G1"==I?("affine"==e?(h=2*g.F.n8,s="g1m_batchToJacobian"):h=3*g.F.n8,r=3*g.F.n8,E&&(y="g1m_fftFinal"),c="g1m_fftJoin",D="g1m_fftMix","affine"==n?(w=2*g.F.n8,f="g1m_batchToAffine"):w=3*g.F.n8):"G2"==I?("affine"==e?(h=2*g.F.n8,s="g2m_batchToJacobian"):h=3*g.F.n8,r=3*g.F.n8,E&&(y="g2m_fftFinal"),c="g2m_fftJoin",D="g2m_fftMix","affine"==n?(w=2*g.F.n8,f="g2m_batchToAffine"):w=3*g.F.n8):"Fr"==I&&(h=g.n8,r=g.n8,w=g.n8,E&&(y="frm_fftFinal"),D="frm_fftMix",c="frm_fftJoin");let F=!1;Array.isArray(i)&&(i=A.array2buffer(i,h),F=!0);const M=i.byteLength/h,u=bA(M);if(1<1<<28?new VA(2*a[0].byteLength):new Uint8Array(2*a[0].byteLength);return o.set(a[0]),o.set(a[1],a[0].byteLength),o}(i,e,n,a,o):await async function(A,I,g,Q,i){let E,e;E=A.slice(0,A.byteLength/2),e=A.slice(A.byteLength/2,A.byteLength);const n=[];[E,e]=await t(E,e,"fftJoinExt",C.one,C.shift,I,"jacobian",Q,i),n.push(B(E,!1,"jacobian",g,Q,i)),n.push(B(e,!1,"jacobian",g,Q,i));const a=await Promise.all(n);let o;o=a[0].byteLength>1<<28?new VA(2*a[0].byteLength):new Uint8Array(2*a[0].byteLength);return o.set(a[0]),o.set(a[1],a[0].byteLength),o}(i,e,n,a,o),F?A.buffer2array(I,w):I}let p,l,H;E&&(p=C.inv(C.e(M))),RA(i,h);let G=Math.min(16384,M),U=M/G;for(;U=16;)U*=2,G/=2;const d=bA(G),m=[];for(let A=0;A(a&&a.debug(`${o}: fft ${u} mix end: ${A}/${U}`),I))))}H=await Promise.all(m);for(let A=0;A(a&&a.debug(`${o}: fft ${u} join ${A}/${u} ${t+1}/${I} ${i}/${g/2}`),C))))}const t=await Promise.all(B);for(let A=0;A0;I--)l.set(H[I],A),A+=G*w,delete H[I];l.set(H[0].slice(0,(G-1)*w),A),delete H[0]}else for(let A=0;A65536&&(y=65536);const F=[];for(let I=0;I(a&&a.debug(`${o}: fftJoinExt End: ${I}/${c}`),A))))}const M=await Promise.all(F);let u,p;c*s>1<<28?(u=new VA(c*s),p=new VA(c*s)):(u=new Uint8Array(c*s),p=new Uint8Array(c*s));let l=0;for(let A=0;AC.s+1)throw E&&E.error("lagrangeEvaluations input too big"),new Error("lagrangeEvaluations input too big");let h=A.slice(0,A.byteLength/2),r=A.slice(A.byteLength/2,A.byteLength);const w=C.exp(C.shift,a/2),s=C.inv(C.sub(C.one,w));[h,r]=await t(h,r,"prepareLagrangeEvaluation",s,C.shiftInv,Q,"jacobian",E,e+" prep");const f=[];let D;return f.push(B(h,!0,"jacobian",i,E,e+" t0")),f.push(B(r,!0,"jacobian",i,E,e+" t1")),[h,r]=await Promise.all(f),D=h.byteLength>1<<28?new VA(2*h.byteLength):new Uint8Array(2*h.byteLength),D.set(h),D.set(r,h.byteLength),D},g.fftMix=async function(A){const B=3*g.F.n8;let t,i;if("G1"==I)t="g1m_fftMix",i="g1m_fftJoin";else if("G2"==I)t="g2m_fftMix",i="g2m_fftJoin";else{if("Fr"!=I)throw new Error("Invalid group");t="frm_fftMix",i="frm_fftJoin"}const E=Math.floor(A.byteLength/B),e=bA(E);let n=1<=0;A--)h.set(o[A][0],r),r+=o[A][0].byteLength;return h}}async function eI(A){const I=await async function(A,I){const g=new QI;g.memory=new WebAssembly.Memory({initial:25}),g.u8=new Uint8Array(g.memory.buffer),g.u32=new Uint32Array(g.memory.buffer);const C=await WebAssembly.compile(II(A.code));if(g.instance=await WebAssembly.instantiate(C,{env:{memory:g.memory}}),g.singleThread=I,g.initalPFree=g.u32[0],g.pq=A.pq,g.pr=A.pr,g.pG1gen=A.pG1gen,g.pG1zero=A.pG1zero,g.pG2gen=A.pG2gen,g.pG2zero=A.pG2zero,g.pOneT=A.pOneT,I)g.code=II(A.code),g.taskManager=TA(),await g.taskManager([{cmd:"INIT",init:25,code:g.code.slice()}]),g.concurrency=1;else{let I;g.workers=[],g.pendingDeferreds=[],g.working=[],I="object"==typeof navigator&&navigator.hardwareConcurrency?navigator.hardwareConcurrency:_A.cpus().length,I>64&&(I=64),g.concurrency=I;for(let A=0;A{I.pendingLoads.push({page:A,resolve:g,reject:C})}));return I.__statusPage("After Load request: ",A),g}__statusPage(A,I){const g=[],C=this;if(!C.logHistory)return;g.push("=="+A+" "+I);let Q="";for(let A=0;A "+I.history[A][g][C])}_triggerLoad(){const A=this;if(A.reading)return;if(0==A.pendingLoads.length)return;const I=Object.keys(A.pages),g=[];for(let C=0;C0&&(void 0!==A.pages[A.pendingLoads[0].page]||C>0||g.length>0);){const I=A.pendingLoads.shift();if(void 0!==A.pages[I.page]){A.pages[I.page].pendingOps++;const C=g.indexOf(I.page);C>=0&&g.splice(C,1),A.pages[I.page].loading?A.pages[I.page].loading.push(I):I.resolve(),A.__statusPage("After Load (cached): ",I.page)}else{if(C)C--;else{const I=g.shift();A.__statusPage("Before Unload: ",I),A.avBuffs.unshift(A.pages[I]),delete A.pages[I],A.__statusPage("After Unload: ",I)}I.page>=A.totalPages?(A.pages[I.page]=B(),I.resolve(),A.__statusPage("After Load (new): ",I.page)):(A.reading=!0,A.pages[I.page]=B(),A.pages[I.page].loading=[I],Q.push(A.fd.read(A.pages[I.page].buff,0,A.pageSize,I.page*A.pageSize).then((g=>{A.pages[I.page].size=g.bytesRead;const C=A.pages[I.page].loading;delete A.pages[I.page].loading;for(let A=0;A{I.reject(A)}))),A.__statusPage("After Load (loading): ",I.page))}}function B(){if(A.avBuffs.length>0){const I=A.avBuffs.shift();return I.dirty=!1,I.pendingOps=1,I.size=0,I}return{dirty:!1,buff:new Uint8Array(A.pageSize),pendingOps:1,size:0}}Promise.all(Q).then((()=>{A.reading=!1,A.pendingLoads.length>0&&setImmediate(A._triggerLoad.bind(A)),A._tryClose()}))}_triggerWrite(){const A=this;if(A.writing)return;const I=Object.keys(A.pages),g=[];for(let C=0;C{Q.writing=!1}),(I=>{console.log("ERROR Writing: "+I),A.error=I,A._tryClose()}))))}A.writing&&Promise.all(g).then((()=>{A.writing=!1,setImmediate(A._triggerWrite.bind(A)),A._tryClose(),A.pendingLoads.length>0&&setImmediate(A._triggerLoad.bind(A))}))}_getDirtyPage(){for(let A in this.pages)if(this.pages[A].dirty)return A;return-1}async write(A,I){if(0==A.byteLength)return;const g=this;if(void 0===I&&(I=g.pos),g.pos=I+A.byteLength,g.totalSize0;){await B[t-C];const I=i+E>g.pageSize?g.pageSize-i:E,Q=A.slice(A.byteLength-E,A.byteLength-E+I);new Uint8Array(g.pages[t].buff.buffer,i,I).set(Q),g.pages[t].dirty=!0,g.pages[t].pendingOps--,g.pages[t].size=Math.max(i+I,g.pages[t].size),t>=g.totalPages&&(g.totalPages=t+1),E-=I,t++,i=0,g.writing||setImmediate(g._triggerWrite.bind(g))}}async read(A,I){let g=new Uint8Array(A);return await this.readToBuffer(g,0,A,I),g}async readToBuffer(A,I,g,C){if(0==g)return;const Q=this;if(g>Q.pageSize*Q.maxPagesLoaded*.8){const A=Math.floor(1.1*g);this.maxPagesLoaded=Math.floor(A/Q.pageSize)+1}if(void 0===C&&(C=Q.pos),Q.pos=C+g,Q.pendingClose)throw new Error("Reading a closing file");const B=Math.floor(C/Q.pageSize),t=Math.floor((C+g-1)/Q.pageSize),i=[];for(let A=B;A<=t;A++)i.push(Q._loadPage(A));Q._triggerLoad();let E=B,e=C%Q.pageSize,n=C+g>Q.totalSize?g-(C+g-Q.totalSize):g;for(;n>0;){await i[E-B],Q.__statusPage("After Await (read): ",E);const C=e+n>Q.pageSize?Q.pageSize-e:n,t=new Uint8Array(Q.pages[E].buff.buffer,Q.pages[E].buff.byteOffset+e,C);A.set(t,I+g-n),Q.pages[E].pendingOps--,Q.__statusPage("After Op done: ",E),n-=C,E++,e=0,Q.pendingLoads.length>0&&setImmediate(Q._triggerLoad.bind(Q))}this.pos=C+g}_tryClose(){const A=this;if(!A.pendingClose)return;A.error&&A.pendingCloseReject(A.error);A._getDirtyPage()>=0||A.writing||A.reading||A.pendingLoads.length>0||A.pendingClose()}close(){const A=this;if(A.pendingClose)throw new Error("Closing the file twice");return new Promise(((I,g)=>{A.pendingClose=I,A.pendingCloseReject=g,A._tryClose()})).then((()=>{A.fd.close()}),(I=>{throw A.fd.close(),I}))}async discard(){await this.close(),await sI.promises.unlink(this.fileName)}async writeULE32(A,I){const g=new Uint8Array(4);new DataView(g.buffer).setUint32(0,A,!0),await this.write(g,I)}async writeUBE32(A,I){const g=new Uint8Array(4);new DataView(g.buffer).setUint32(0,A,!1),await this.write(g,I)}async writeULE64(A,I){const g=new Uint8Array(8),C=new DataView(g.buffer);C.setUint32(0,4294967295&A,!0),C.setUint32(4,Math.floor(A/4294967296),!0),await this.write(g,I)}async readULE32(A){const I=await this.read(4,A);return new Uint32Array(I.buffer)[0]}async readUBE32(A){const I=await this.read(4,A);return new DataView(I.buffer).getUint32(0,!1)}async readULE64(A){const I=await this.read(8,A),g=new Uint32Array(I.buffer);return 4294967296*g[1]+g[0]}}const cI=new Uint8Array(4),yI=new DataView(cI.buffer),FI=new Uint8Array(8),MI=new DataView(FI.buffer);class uI{constructor(){this.pageSize=16384}_resizeIfNeeded(A){if(A>this.allocSize){const I=Math.max(this.allocSize+(1<<20),Math.floor(1.1*this.allocSize),A),g=new Uint8Array(I);g.set(this.o.data),this.o.data=g,this.allocSize=I}}async write(A,I){if(void 0===I&&(I=this.pos),this.readOnly)throw new Error("Writing a read only file");this._resizeIfNeeded(I+A.byteLength),this.o.data.set(A.slice(),I),I+A.byteLength>this.totalSize&&(this.totalSize=I+A.byteLength),this.pos=I+A.byteLength}async readToBuffer(A,I,g,C){if(void 0===C&&(C=this.pos),this.readOnly&&C+g>this.totalSize)throw new Error("Reading out of bounds");this._resizeIfNeeded(C+g);const Q=new Uint8Array(this.o.data.buffer,this.o.data.byteOffset+C,g);A.set(Q,I),this.pos=C+g}async read(A,I){const g=new Uint8Array(A);return await this.readToBuffer(g,0,A,I),g}close(){this.o.data.byteLength!=this.totalSize&&(this.o.data=this.o.data.slice(0,this.totalSize))}async discard(){}async writeULE32(A,I){yI.setUint32(0,A,!0),await this.write(cI,I)}async writeUBE32(A,I){yI.setUint32(0,A,!1),await this.write(cI,I)}async writeULE64(A,I){MI.setUint32(0,4294967295&A,!0),MI.setUint32(4,Math.floor(A/4294967296),!0),await this.write(FI,I)}async readULE32(A){const I=await this.read(4,A);return new Uint32Array(I.buffer)[0]}async readUBE32(A){const I=await this.read(4,A);return new DataView(I.buffer).getUint32(0,!1)}async readULE64(A){const I=await this.read(8,A),g=new Uint32Array(I.buffer);return 4294967296*g[1]+g[0]}}const pI=1<<22;const lI=new Uint8Array(4),HI=new DataView(lI.buffer),GI=new Uint8Array(8),UI=new DataView(GI.buffer);class dI{constructor(){this.pageSize=16384}_resizeIfNeeded(A){if(A<=this.totalSize)return;if(this.readOnly)throw new Error("Reading out of file bounds");const I=Math.floor((A-1)/pI)+1;for(let g=Math.max(this.o.data.length-1,0);g0;){const I=Q+B>pI?pI-Q:B,t=A.slice(A.byteLength-B,A.byteLength-B+I);new Uint8Array(g.o.data[C].buffer,Q,I).set(t),B-=I,C++,Q=0}this.pos=I+A.byteLength}async readToBuffer(A,I,g,C){const Q=this;if(void 0===C&&(C=Q.pos),this.readOnly&&C+g>this.totalSize)throw new Error("Reading out of bounds");this._resizeIfNeeded(C+g);let B=Math.floor(C/pI),t=C%pI,i=g;for(;i>0;){const C=t+i>pI?pI-t:i,E=new Uint8Array(Q.o.data[B].buffer,t,C);A.set(E,I+g-i),i-=C,B++,t=0}this.pos=C+g}async read(A,I){const g=new Uint8Array(A);return await this.readToBuffer(g,0,A,I),g}close(){}async discard(){}async writeULE32(A,I){HI.setUint32(0,A,!0),await this.write(lI,I)}async writeUBE32(A,I){HI.setUint32(0,A,!1),await this.write(lI,I)}async writeULE64(A,I){UI.setUint32(0,4294967295&A,!0),UI.setUint32(4,Math.floor(A/4294967296),!0),await this.write(GI,I)}async readULE32(A){const I=await this.read(4,A);return new Uint32Array(I.buffer)[0]}async readUBE32(A){const I=await this.read(4,A);return new DataView(I.buffer).getUint32(0,!1)}async readULE64(A){const I=await this.read(8,A),g=new Uint32Array(I.buffer);return 4294967296*g[1]+g[0]}}async function mI(A,I,g){if("string"==typeof A&&(A={type:"file",fileName:A,cacheSize:I||65536,pageSize:g||8192}),"file"==A.type)return await fI(A.fileName,"w+",A.cacheSize,A.pageSize);if("mem"==A.type)return function(A){const I=A.initialSize||1<<20,g=new uI;return g.o=A,g.o.data=new Uint8Array(I),g.allocSize=I,g.totalSize=0,g.readOnly=!1,g.pos=0,g}(A);if("bigMem"==A.type)return function(A){const I=A.initialSize||0,g=new dI;g.o=A;const C=I?Math.floor((I-1)/pI)+1:0;g.o.data=[];for(let A=0;Ag)throw new Error("Version not supported");const E=await B.readULE32();let e=[];for(let A=0;A1)throw new Error(A.fileName+": Section Duplicated "+g);A.pos=I[g][0].p,A.readingSection=I[g][0]}async function SI(A,I){if(void 0===A.readingSection)throw new Error("Not reading a section");if(!I&&A.pos-A.readingSection.p!=A.readingSection.size)throw new Error("Invalid section size reading");delete A.readingSection}async function vI(A,I,g,C){const Q=new Uint8Array(g);rI.toRprLE(Q,0,I,g),await A.write(Q,C)}async function YI(A,I,g){const C=await A.read(I,g);return rI.fromRprLE(C,0,I)}async function PI(A,I,g,C,Q){void 0===Q&&(Q=I[C][0].size);const B=A.pageSize;await RI(A,I,C),await NI(g,C);for(let I=0;II[g][0].size)throw new Error("Reading out of the range of the section");let B;return B=Q<1<<30?new Uint8Array(Q):new VA(Q),await A.readToBuffer(B,0,Q,I[g][0].p+C),B}async function xI(A,I,g,C,Q){const B=16*A.pageSize;if(await RI(A,I,Q),await RI(g,C,Q),I[Q][0].size!=C[Q][0].size)return!1;const t=I[Q][0].size;for(let I=0;I=Q,"digestLength must be at least "+Q+", was given "+A),KI(A<=B,"digestLength must be at most "+B+", was given "+A),null!=a&&(KI(a instanceof Uint8Array,"key must be Uint8Array or Buffer"),KI(a.length>=t,"key must be at least "+t+", was given "+a.length),KI(a.length<=i,"key must be at least "+i+", was given "+a.length)),null!=o&&(KI(o instanceof Uint8Array,"salt must be Uint8Array or Buffer"),KI(o.length===E,"salt must be exactly "+E+", was given "+o.length)),null!=h&&(KI(h instanceof Uint8Array,"personal must be Uint8Array or Buffer"),KI(h.length===e,"personal must be exactly "+e+", was given "+h.length))),C.length||(C.push(g),g+=216),this.digestLength=A,this.finalized=!1,this.pointer=C.pop(),I.memory.fill(0,0,64),I.memory[0]=this.digestLength,I.memory[1]=a?a.length:0,I.memory[2]=1,I.memory[3]=1,o&&I.memory.set(o,32),h&&I.memory.set(h,48),this.pointer+216>I.memory.length&&I.realloc(this.pointer+216),I.exports.blake2b_init(this.pointer,this.digestLength),a&&(this.update(a),I.memory.fill(0,g,g+a.length),I.memory[this.pointer+200]=128)}function a(){}function o(A){return A<16?"0"+A.toString(16):A.toString(16)}n.prototype.update=function(A){return KI(!1===this.finalized,"Hash instance finalized"),KI(A instanceof Uint8Array,"input must be Uint8Array or Buffer"),g+A.length>I.memory.length&&I.realloc(g+A.length),I.memory.set(A,g),I.exports.blake2b_update(this.pointer,g,g+A.length),this},n.prototype.getPartialHash=function(){return I.memory.slice(this.pointer,this.pointer+216)},n.prototype.setPartialHash=function(A){I.memory.set(A,this.pointer)},n.prototype.digest=function(A){if(KI(!1===this.finalized,"Hash instance finalized"),this.finalized=!0,C.push(this.pointer),I.exports.blake2b_final(this.pointer),!A||"binary"===A)return I.memory.slice(this.pointer+128,this.pointer+128+this.digestLength);if("hex"===A)return function(A,I,g){for(var C="",Q=0;Q=this.digestLength,"input must be Uint8Array or Buffer");for(var g=0;g>=1;return g}function Ag(A){return(0!=(4294901760&A)?(A&=4294901760,16):0)|(0!=(4278255360&A)?(A&=4278255360,8):0)|(0!=(4042322160&A)?(A&=4042322160,4):0)|(0!=(3435973836&A)?(A&=3435973836,2):0)|0!=(2863311530&A)}function Ig(A,I){const g=new DataView(A.buffer,A.byteOffset,A.byteLength);let C="";for(let A=0;A<4;A++){A>0&&(C+="\n"),C+="\t\t";for(let I=0;I<4;I++)I>0&&(C+=" "),C+=g.getUint32(16*A+4*I).toString(16).padStart(8,"0")}return I&&(C=I+"\n"+C),C}function gg(A,I){if(A.byteLength!=I.byteLength)return!1;for(var g=new Int8Array(A),C=new Int8Array(I),Q=0;Q!=A.byteLength;Q++)if(g[Q]!=C[Q])return!1;return!0}function Cg(A){const I=A.getPartialHash(),g=TI(64);return g.setPartialHash(I),g}async function Qg(A,I,g,C,Q){if(A.G1.isZero(I))return!1;if(A.G1.isZero(g))return!1;if(A.G2.isZero(C))return!1;if(A.G2.isZero(Q))return!1;return await A.pairingEq(I,Q,A.G1.neg(g),C)}async function Bg(A){for(;!A;)A=await window.prompt("Enter a random text. (Entropy): ","");const I=TI(64);I.update(DA.randomBytes(64));const g=new TextEncoder;I.update(g.encode(A));const C=Buffer.from(I.digest()),Q=[];for(let A=0;A<8;A++)Q[A]=C.readUInt32BE(4*A);return new fA(Q)}function tg(A,I){let g,C;I<32?(g=1<>>0,C=1):(g=4294967296,C=1<>>0);let Q=A;for(let A=0;A0){const I=new Uint8Array(C);await A.writeULE32(I.byteLength),await A.write(I)}else await A.writeULE32(0)}async function Dg(A,I,g){await NI(A,10),await A.write(g.csHash),await A.writeULE32(g.contributions.length);for(let C=0;C /\\../\\",h=52,r={32:{offset:0},64:{offset:[0,0,0,0]},128:{offset:[0,0,0,0,0,0,0,0]},256:{offset:[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0]},512:{offset:[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0]},1024:{offset:[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0]}};for(A=0;A<256;A++)E[A]=(A>>4&15).toString(16)+(15&A).toString(16);function w(A,I){var g,C,Q,B=[0],t="";for(C=0;C0;)B.push(g%I),g=g/I|0}for(C=B.length-1;C>=0;--C)t+="0123456789abcdefghijklmnopqrstuvwxyz"[B[C]];return t}function s(A,I){return{bits:I,value:A,dec:function(){return w(A,10)},hex:function(){return A},str:function(){return w(A,36)}}}function f(A,I){return{bits:I,value:A,dec:function(){return A.toString()},hex:function(){return E[A>>>24]+E[A>>>16&255]+E[A>>>8&255]+E[255&A]},str:function(){return A.toString(36)}}}function D(A,I){return{bits:I,value:A,dec:function(){return A.toString()},hex:function(){return("0000000000000000"+A.toString(16)).substr(-13)},str:function(){return A.toString(36)}}}function c(A,E){var e="object"==typeof A?JSON.stringify(A):A;switch(E||h){case 32:return I(e);case 64:return C(e);case 128:return Q(e);case 256:return B(e);case 512:return t(e);case 1024:return i(e);default:return g(e)}}function y(A){if("1a"===A)n=A,I=a?l:u,g=a?d:G,C=a?k:L,Q=a?S:b,B=a?q:Y,t=a?V:X,i=a?j:W;else{if("1"!==A)throw new Error("Supported FNV versions: 1, 1a");n=A,I=a?H:p,g=a?m:U,C=a?N:J,Q=a?v:R,B=a?x:P,t=a?K:Z,i=a?z:O}}function F(A){A?(a=!0,I="1a"==n?l:H,g="1a"==n?d:m,C="1a"==n?k:N,Q="1a"==n?S:v,B="1a"==n?q:x,t="1a"==n?V:K,i="1a"==n?j:z):(a=!1,I="1a"==n?u:p,g="1a"==n?G:U,C="1a"==n?L:J,Q="1a"==n?b:R,B="1a"==n?Y:P,t="1a"==n?X:Z,i="1a"==n?W:O)}function M(A){var I,g,C=n;for(var Q in(A=A||0===A?A:o)===o&&y("1"),r){for(r[Q].offset=[],g=0;g>>16)&65535),t+=(B^=A.charCodeAt(I++))<<8,B=65535&(Q=403*B),t=403*(i=t+(Q>>>16)&65535),t+=(B^=A.charCodeAt(I++))<<8,B=65535&(Q=403*B),t=403*(i=t+(Q>>>16)&65535),i=(t+=(B^=A.charCodeAt(I++))<<8)+((Q=403*B)>>>16)&65535,B=65535&Q;for(;I>>16)&65535,B=65535&Q;return f((i<<16>>>0)+B,32)}function p(A){var I,g=A.length-3,C=r[32].offset,Q=0,B=0|C[1],t=0,i=0|C[0];for(I=0;I>>16)&65535),t+=(B^=A.charCodeAt(I++))<<8,B=65535&(Q=403*B),t=403*(i=t+(Q>>>16)&65535),t+=(B^=A.charCodeAt(I++))<<8,B=65535&(Q=403*B),t=403*(i=t+(Q>>>16)&65535),i=(t+=(B^=A.charCodeAt(I++))<<8)+((Q=403*B)>>>16)&65535,B=65535&Q,B^=A.charCodeAt(I++);for(;I>>16)&65535,B=65535&Q,B^=A.charCodeAt(I++);return f((i<<16>>>0)+B,32)}function l(A){var I,g,C=A.length,Q=r[32].offset,B=0,t=0|Q[1],i=0,E=0|Q[0];for(g=0;g>6|192)<<8)+((B=403*t)>>>16)&65535,t=65535&B,t^=63&I|128):55296==(64512&I)&&g+1>18|240)<<8,t=65535&(B=403*t),i=403*(E=i+(B>>>16)&65535),i+=(t^=I>>12&63|128)<<8,t=65535&(B=403*t),i=403*(E=i+(B>>>16)&65535),E=(i+=(t^=I>>6&63|128)<<8)+((B=403*t)>>>16)&65535,t=65535&B,t^=63&I|128):(i=403*E,i+=(t^=I>>12|224)<<8,t=65535&(B=403*t),i=403*(E=i+(B>>>16)&65535),E=(i+=(t^=I>>6&63|128)<<8)+((B=403*t)>>>16)&65535,t=65535&B,t^=63&I|128),i=403*E,E=(i+=t<<8)+((B=403*t)>>>16)&65535,t=65535&B;return f((E<<16>>>0)+t,32)}function H(A){var I,g,C=A.length,Q=r[32].offset,B=0,t=0|Q[1],i=0,E=0|Q[0];for(g=0;g>>16)&65535,t=65535&B,(I=A.charCodeAt(g))<128?t^=I:I<2048?(i=403*E,E=(i+=(t^=I>>6|192)<<8)+((B=403*t)>>>16)&65535,t=65535&B,t^=63&I|128):55296==(64512&I)&&g+1>18|240)<<8,t=65535&(B=403*t),i=403*(E=i+(B>>>16)&65535),i+=(t^=I>>12&63|128)<<8,t=65535&(B=403*t),i=403*(E=i+(B>>>16)&65535),E=(i+=(t^=I>>6&63|128)<<8)+((B=403*t)>>>16)&65535,t=65535&B,t^=63&I|128):(i=403*E,i+=(t^=I>>12|224)<<8,t=65535&(B=403*t),i=403*(E=i+(B>>>16)&65535),E=(i+=(t^=I>>6&63|128)<<8)+((B=403*t)>>>16)&65535,t=65535&B,t^=63&I|128);return f((E<<16>>>0)+t,32)}function G(A){var I,g=A.length-3,C=r[64].offset,Q=0,B=0|C[3],t=0,i=0|C[2],E=0,e=0|C[1],n=0,a=0|C[0];for(I=0;I>>16)>>>16)>>>16)&65535,t=435*(i=65535&t),E=435*(e=65535&E),n=435*a,E+=(B^=A.charCodeAt(I++))<<8,B=65535&(Q=435*B),a=(n+=i<<8)+((E+=(t+=Q>>>16)>>>16)>>>16)&65535,t=435*(i=65535&t),E=435*(e=65535&E),n=435*a,E+=(B^=A.charCodeAt(I++))<<8,B=65535&(Q=435*B),a=(n+=i<<8)+((E+=(t+=Q>>>16)>>>16)>>>16)&65535,t=435*(i=65535&t),E=435*(e=65535&E),n=435*a,E+=(B^=A.charCodeAt(I++))<<8,n+=i<<8,B=65535&(Q=435*B),i=65535&(t+=Q>>>16),a=n+((E+=t>>>16)>>>16)&65535,e=65535&E;for(;I>>16),a=n+((E+=t>>>16)>>>16)&65535,e=65535&E;return D(281474976710656*(15&a)+4294967296*e+65536*i+(B^a>>4),52)}function U(A){var I,g=A.length-3,C=r[64].offset,Q=0,B=0|C[3],t=0,i=0|C[2],E=0,e=0|C[1],n=0,a=0|C[0];for(I=0;I>>16)>>>16)>>>16)&65535,t=435*(i=65535&t),E=435*(e=65535&E),n=435*a,E+=(B^=A.charCodeAt(I++))<<8,B=65535&(Q=435*B),a=(n+=i<<8)+((E+=(t+=Q>>>16)>>>16)>>>16)&65535,t=435*(i=65535&t),E=435*(e=65535&E),n=435*a,E+=(B^=A.charCodeAt(I++))<<8,B=65535&(Q=435*B),a=(n+=i<<8)+((E+=(t+=Q>>>16)>>>16)>>>16)&65535,t=435*(i=65535&t),E=435*(e=65535&E),n=435*a,E+=(B^=A.charCodeAt(I++))<<8,n+=i<<8,B=65535&(Q=435*B),i=65535&(t+=Q>>>16),a=n+((E+=t>>>16)>>>16)&65535,e=65535&E,B^=A.charCodeAt(I++);for(;I>>16),a=n+((E+=t>>>16)>>>16)&65535,e=65535&E,B^=A.charCodeAt(I++);return D(281474976710656*(15&a)+4294967296*e+65536*i+(B^a>>4),52)}function d(A){var I,g,C=A.length,Q=r[64].offset,B=0,t=0|Q[3],i=0,E=0|Q[2],e=0,n=0|Q[1],a=0,o=0|Q[0];for(g=0;g>6|192)<<8,a+=E<<8,t=65535&(B=435*t),E=65535&(i+=B>>>16),o=a+((e+=i>>>16)>>>16)&65535,n=65535&e,t^=63&I|128):55296==(64512&I)&&g+1>18|240)<<8,t=65535&(B=435*t),o=(a+=E<<8)+((e+=(i+=B>>>16)>>>16)>>>16)&65535,i=435*(E=65535&i),e=435*(n=65535&e),a=435*o,e+=(t^=I>>12&63|128)<<8,t=65535&(B=435*t),o=(a+=E<<8)+((e+=(i+=B>>>16)>>>16)>>>16)&65535,i=435*(E=65535&i),e=435*(n=65535&e),a=435*o,e+=(t^=I>>6&63|128)<<8,a+=E<<8,t=65535&(B=435*t),E=65535&(i+=B>>>16),o=a+((e+=i>>>16)>>>16)&65535,n=65535&e,t^=63&I|128):(i=435*E,e=435*n,a=435*o,e+=(t^=I>>12|224)<<8,t=65535&(B=435*t),o=(a+=E<<8)+((e+=(i+=B>>>16)>>>16)>>>16)&65535,i=435*(E=65535&i),e=435*(n=65535&e),a=435*o,e+=(t^=I>>6&63|128)<<8,a+=E<<8,t=65535&(B=435*t),E=65535&(i+=B>>>16),o=a+((e+=i>>>16)>>>16)&65535,n=65535&e,t^=63&I|128),i=435*E,e=435*n,a=435*o,e+=t<<8,a+=E<<8,t=65535&(B=435*t),E=65535&(i+=B>>>16),o=a+((e+=i>>>16)>>>16)&65535,n=65535&e;return D(281474976710656*(15&o)+4294967296*n+65536*E+(t^o>>4),52)}function m(A){var I,g,C=A.length,Q=r[64].offset,B=0,t=0|Q[3],i=0,E=0|Q[2],e=0,n=0|Q[1],a=0,o=0|Q[0];for(g=0;g>>16),o=a+((e+=i>>>16)>>>16)&65535,n=65535&e,(I=A.charCodeAt(g))<128?t^=I:I<2048?(i=435*E,e=435*n,a=435*o,e+=(t^=I>>6|192)<<8,a+=E<<8,t=65535&(B=435*t),E=65535&(i+=B>>>16),o=a+((e+=i>>>16)>>>16)&65535,n=65535&e,t^=63&I|128):55296==(64512&I)&&g+1>18|240)<<8,t=65535&(B=435*t),o=(a+=E<<8)+((e+=(i+=B>>>16)>>>16)>>>16)&65535,i=435*(E=65535&i),e=435*(n=65535&e),a=435*o,e+=(t^=I>>12&63|128)<<8,t=65535&(B=435*t),o=(a+=E<<8)+((e+=(i+=B>>>16)>>>16)>>>16)&65535,i=435*(E=65535&i),e=435*(n=65535&e),a=435*o,e+=(t^=I>>6&63|128)<<8,a+=E<<8,t=65535&(B=435*t),E=65535&(i+=B>>>16),o=a+((e+=i>>>16)>>>16)&65535,n=65535&e,t^=63&I|128):(i=435*E,e=435*n,a=435*o,e+=(t^=I>>12|224)<<8,t=65535&(B=435*t),o=(a+=E<<8)+((e+=(i+=B>>>16)>>>16)>>>16)&65535,i=435*(E=65535&i),e=435*(n=65535&e),a=435*o,e+=(t^=I>>6&63|128)<<8,a+=E<<8,t=65535&(B=435*t),E=65535&(i+=B>>>16),o=a+((e+=i>>>16)>>>16)&65535,n=65535&e,t^=63&I|128);return D(281474976710656*(15&o)+4294967296*n+65536*E+(t^o>>4),52)}function L(A){var I,g=A.length-3,C=r[64].offset,Q=0,B=0|C[3],t=0,i=0|C[2],e=0,n=0|C[1],a=0,o=0|C[0];for(I=0;I>>16)>>>16)>>>16)&65535,t=435*(i=65535&t),e=435*(n=65535&e),a=435*o,e+=(B^=A.charCodeAt(I++))<<8,B=65535&(Q=435*B),o=(a+=i<<8)+((e+=(t+=Q>>>16)>>>16)>>>16)&65535,t=435*(i=65535&t),e=435*(n=65535&e),a=435*o,e+=(B^=A.charCodeAt(I++))<<8,B=65535&(Q=435*B),o=(a+=i<<8)+((e+=(t+=Q>>>16)>>>16)>>>16)&65535,t=435*(i=65535&t),e=435*(n=65535&e),a=435*o,e+=(B^=A.charCodeAt(I++))<<8,a+=i<<8,B=65535&(Q=435*B),i=65535&(t+=Q>>>16),o=a+((e+=t>>>16)>>>16)&65535,n=65535&e;for(;I>>16),o=a+((e+=t>>>16)>>>16)&65535,n=65535&e;return s(E[o>>8]+E[255&o]+E[n>>8]+E[255&n]+E[i>>8]+E[255&i]+E[B>>8]+E[255&B],64)}function J(A){var I,g=A.length-3,C=r[64].offset,Q=0,B=0|C[3],t=0,i=0|C[2],e=0,n=0|C[1],a=0,o=0|C[0];for(I=0;I>>16)>>>16)>>>16)&65535,t=435*(i=65535&t),e=435*(n=65535&e),a=435*o,e+=(B^=A.charCodeAt(I++))<<8,B=65535&(Q=435*B),o=(a+=i<<8)+((e+=(t+=Q>>>16)>>>16)>>>16)&65535,t=435*(i=65535&t),e=435*(n=65535&e),a=435*o,e+=(B^=A.charCodeAt(I++))<<8,B=65535&(Q=435*B),o=(a+=i<<8)+((e+=(t+=Q>>>16)>>>16)>>>16)&65535,t=435*(i=65535&t),e=435*(n=65535&e),a=435*o,e+=(B^=A.charCodeAt(I++))<<8,a+=i<<8,B=65535&(Q=435*B),i=65535&(t+=Q>>>16),o=a+((e+=t>>>16)>>>16)&65535,n=65535&e,B^=A.charCodeAt(I++);for(;I>>16),o=a+((e+=t>>>16)>>>16)&65535,n=65535&e,B^=A.charCodeAt(I++);return s(E[o>>8]+E[255&o]+E[n>>8]+E[255&n]+E[i>>8]+E[255&i]+E[B>>8]+E[255&B],64)}function k(A){var I,g,C=A.length,Q=r[64].offset,B=0,t=0|Q[3],i=0,e=0|Q[2],n=0,a=0|Q[1],o=0,h=0|Q[0];for(g=0;g>6|192)<<8,o+=e<<8,t=65535&(B=435*t),e=65535&(i+=B>>>16),h=o+((n+=i>>>16)>>>16)&65535,a=65535&n,t^=63&I|128):55296==(64512&I)&&g+1>18|240)<<8,t=65535&(B=435*t),h=(o+=e<<8)+((n+=(i+=B>>>16)>>>16)>>>16)&65535,i=435*(e=65535&i),n=435*(a=65535&n),o=435*h,n+=(t^=I>>12&63|128)<<8,t=65535&(B=435*t),h=(o+=e<<8)+((n+=(i+=B>>>16)>>>16)>>>16)&65535,i=435*(e=65535&i),n=435*(a=65535&n),o=435*h,n+=(t^=I>>6&63|128)<<8,o+=e<<8,t=65535&(B=435*t),e=65535&(i+=B>>>16),h=o+((n+=i>>>16)>>>16)&65535,a=65535&n,t^=63&I|128):(i=435*e,n=435*a,o=435*h,n+=(t^=I>>12|224)<<8,t=65535&(B=435*t),h=(o+=e<<8)+((n+=(i+=B>>>16)>>>16)>>>16)&65535,i=435*(e=65535&i),n=435*(a=65535&n),o=435*h,n+=(t^=I>>6&63|128)<<8,o+=e<<8,t=65535&(B=435*t),e=65535&(i+=B>>>16),h=o+((n+=i>>>16)>>>16)&65535,a=65535&n,t^=63&I|128),i=435*e,n=435*a,o=435*h,n+=t<<8,o+=e<<8,t=65535&(B=435*t),e=65535&(i+=B>>>16),h=o+((n+=i>>>16)>>>16)&65535,a=65535&n;return s(E[h>>8]+E[255&h]+E[a>>8]+E[255&a]+E[e>>8]+E[255&e]+E[t>>8]+E[255&t],64)}function N(A){var I,g,C=A.length,Q=r[64].offset,B=0,t=0|Q[3],i=0,e=0|Q[2],n=0,a=0|Q[1],o=0,h=0|Q[0];for(g=0;g>>16),h=o+((n+=i>>>16)>>>16)&65535,a=65535&n,(I=A.charCodeAt(g))<128?t^=I:I<2048?(i=435*e,n=435*a,o=435*h,n+=(t^=I>>6|192)<<8,o+=e<<8,t=65535&(B=435*t),e=65535&(i+=B>>>16),h=o+((n+=i>>>16)>>>16)&65535,a=65535&n,t^=63&I|128):55296==(64512&I)&&g+1>18|240)<<8,t=65535&(B=435*t),h=(o+=e<<8)+((n+=(i+=B>>>16)>>>16)>>>16)&65535,i=435*(e=65535&i),n=435*(a=65535&n),o=435*h,n+=(t^=I>>12&63|128)<<8,t=65535&(B=435*t),h=(o+=e<<8)+((n+=(i+=B>>>16)>>>16)>>>16)&65535,i=435*(e=65535&i),n=435*(a=65535&n),o=435*h,n+=(t^=I>>6&63|128)<<8,o+=e<<8,t=65535&(B=435*t),e=65535&(i+=B>>>16),h=o+((n+=i>>>16)>>>16)&65535,a=65535&n,t^=63&I|128):(i=435*e,n=435*a,o=435*h,n+=(t^=I>>12|224)<<8,t=65535&(B=435*t),h=(o+=e<<8)+((n+=(i+=B>>>16)>>>16)>>>16)&65535,i=435*(e=65535&i),n=435*(a=65535&n),o=435*h,n+=(t^=I>>6&63|128)<<8,o+=e<<8,t=65535&(B=435*t),e=65535&(i+=B>>>16),h=o+((n+=i>>>16)>>>16)&65535,a=65535&n,t^=63&I|128);return s(E[h>>8]+E[255&h]+E[a>>8]+E[255&a]+E[e>>8]+E[255&e]+E[t>>8]+E[255&t],64)}function b(A){var I,g=A.length-3,C=r[128].offset,Q=0,B=0|C[7],t=0,i=0|C[6],e=0,n=0|C[5],a=0,o=0|C[4],h=0,w=0|C[3],f=0,D=0|C[2],c=0,y=0|C[1],F=0,M=0|C[0];for(I=0;I>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)&65535,t=315*(i=65535&t),e=315*(n=65535&e),a=315*(o=65535&a),h=315*(w=65535&h),f=315*(D=65535&f),c=315*(y=65535&c),F=315*M,f+=(B^=A.charCodeAt(I++))<<8,c+=i<<8,B=65535&(Q=315*B),M=(F+=n<<8)+((c+=(f+=(h+=(a+=(e+=(t+=Q>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)&65535,t=315*(i=65535&t),e=315*(n=65535&e),a=315*(o=65535&a),h=315*(w=65535&h),f=315*(D=65535&f),c=315*(y=65535&c),F=315*M,f+=(B^=A.charCodeAt(I++))<<8,c+=i<<8,B=65535&(Q=315*B),M=(F+=n<<8)+((c+=(f+=(h+=(a+=(e+=(t+=Q>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)&65535,t=315*(i=65535&t),e=315*(n=65535&e),a=315*(o=65535&a),h=315*(w=65535&h),f=315*(D=65535&f),c=315*(y=65535&c),F=315*M,f+=(B^=A.charCodeAt(I++))<<8,c+=i<<8,F+=n<<8,B=65535&(Q=315*B),i=65535&(t+=Q>>>16),n=65535&(e+=t>>>16),o=65535&(a+=e>>>16),w=65535&(h+=a>>>16),D=65535&(f+=h>>>16),M=F+((c+=f>>>16)>>>16)&65535,y=65535&c;for(;I>>16),n=65535&(e+=t>>>16),o=65535&(a+=e>>>16),w=65535&(h+=a>>>16),D=65535&(f+=h>>>16),M=F+((c+=f>>>16)>>>16)&65535,y=65535&c;return s(E[M>>8]+E[255&M]+E[y>>8]+E[255&y]+E[D>>8]+E[255&D]+E[w>>8]+E[255&w]+E[o>>8]+E[255&o]+E[n>>8]+E[255&n]+E[i>>8]+E[255&i]+E[B>>8]+E[255&B],128)}function R(A){var I,g=A.length-3,C=r[128].offset,Q=0,B=0|C[7],t=0,i=0|C[6],e=0,n=0|C[5],a=0,o=0|C[4],h=0,w=0|C[3],f=0,D=0|C[2],c=0,y=0|C[1],F=0,M=0|C[0];for(I=0;I>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)&65535,t=315*(i=65535&t),e=315*(n=65535&e),a=315*(o=65535&a),h=315*(w=65535&h),f=315*(D=65535&f),c=315*(y=65535&c),F=315*M,f+=(B^=A.charCodeAt(I++))<<8,c+=i<<8,B=65535&(Q=315*B),M=(F+=n<<8)+((c+=(f+=(h+=(a+=(e+=(t+=Q>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)&65535,t=315*(i=65535&t),e=315*(n=65535&e),a=315*(o=65535&a),h=315*(w=65535&h),f=315*(D=65535&f),c=315*(y=65535&c),F=315*M,f+=(B^=A.charCodeAt(I++))<<8,c+=i<<8,B=65535&(Q=315*B),M=(F+=n<<8)+((c+=(f+=(h+=(a+=(e+=(t+=Q>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)&65535,t=315*(i=65535&t),e=315*(n=65535&e),a=315*(o=65535&a),h=315*(w=65535&h),f=315*(D=65535&f),c=315*(y=65535&c),F=315*M,f+=(B^=A.charCodeAt(I++))<<8,c+=i<<8,F+=n<<8,B=65535&(Q=315*B),i=65535&(t+=Q>>>16),n=65535&(e+=t>>>16),o=65535&(a+=e>>>16),w=65535&(h+=a>>>16),D=65535&(f+=h>>>16),M=F+((c+=f>>>16)>>>16)&65535,y=65535&c,B^=A.charCodeAt(I++);for(;I>>16),n=65535&(e+=t>>>16),o=65535&(a+=e>>>16),w=65535&(h+=a>>>16),D=65535&(f+=h>>>16),M=F+((c+=f>>>16)>>>16)&65535,y=65535&c,B^=A.charCodeAt(I++);return s(E[M>>8]+E[255&M]+E[y>>8]+E[255&y]+E[D>>8]+E[255&D]+E[w>>8]+E[255&w]+E[o>>8]+E[255&o]+E[n>>8]+E[255&n]+E[i>>8]+E[255&i]+E[B>>8]+E[255&B],128)}function S(A){var I,g,C=A.length,Q=r[128].offset,B=0,t=0|Q[7],i=0,e=0|Q[6],n=0,a=0|Q[5],o=0,h=0|Q[4],w=0,f=0|Q[3],D=0,c=0|Q[2],y=0,F=0|Q[1],M=0,u=0|Q[0];for(g=0;g>6|192)<<8,y+=e<<8,M+=a<<8,t=65535&(B=315*t),e=65535&(i+=B>>>16),a=65535&(n+=i>>>16),h=65535&(o+=n>>>16),f=65535&(w+=o>>>16),c=65535&(D+=w>>>16),u=M+((y+=D>>>16)>>>16)&65535,F=65535&y,t^=63&I|128):55296==(64512&I)&&g+1>18|240)<<8,y+=e<<8,t=65535&(B=315*t),u=(M+=a<<8)+((y+=(D+=(w+=(o+=(n+=(i+=B>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)&65535,i=315*(e=65535&i),n=315*(a=65535&n),o=315*(h=65535&o),w=315*(f=65535&w),D=315*(c=65535&D),y=315*(F=65535&y),M=315*u,D+=(t^=I>>12&63|128)<<8,y+=e<<8,t=65535&(B=315*t),u=(M+=a<<8)+((y+=(D+=(w+=(o+=(n+=(i+=B>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)&65535,i=315*(e=65535&i),n=315*(a=65535&n),o=315*(h=65535&o),w=315*(f=65535&w),D=315*(c=65535&D),y=315*(F=65535&y),M=315*u,D+=(t^=I>>6&63|128)<<8,y+=e<<8,M+=a<<8,t=65535&(B=315*t),e=65535&(i+=B>>>16),a=65535&(n+=i>>>16),h=65535&(o+=n>>>16),f=65535&(w+=o>>>16),c=65535&(D+=w>>>16),u=M+((y+=D>>>16)>>>16)&65535,F=65535&y,t^=63&I|128):(i=315*e,n=315*a,o=315*h,w=315*f,D=315*c,y=315*F,M=315*u,D+=(t^=I>>12|224)<<8,y+=e<<8,t=65535&(B=315*t),u=(M+=a<<8)+((y+=(D+=(w+=(o+=(n+=(i+=B>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)&65535,i=315*(e=65535&i),n=315*(a=65535&n),o=315*(h=65535&o),w=315*(f=65535&w),D=315*(c=65535&D),y=315*(F=65535&y),M=315*u,D+=(t^=I>>6&63|128)<<8,y+=e<<8,M+=a<<8,t=65535&(B=315*t),e=65535&(i+=B>>>16),a=65535&(n+=i>>>16),h=65535&(o+=n>>>16),f=65535&(w+=o>>>16),c=65535&(D+=w>>>16),u=M+((y+=D>>>16)>>>16)&65535,F=65535&y,t^=63&I|128),i=315*e,n=315*a,o=315*h,w=315*f,D=315*c,y=315*F,M=315*u,D+=t<<8,y+=e<<8,M+=a<<8,t=65535&(B=315*t),e=65535&(i+=B>>>16),a=65535&(n+=i>>>16),h=65535&(o+=n>>>16),f=65535&(w+=o>>>16),c=65535&(D+=w>>>16),u=M+((y+=D>>>16)>>>16)&65535,F=65535&y;return s(E[u>>8]+E[255&u]+E[F>>8]+E[255&F]+E[c>>8]+E[255&c]+E[f>>8]+E[255&f]+E[h>>8]+E[255&h]+E[a>>8]+E[255&a]+E[e>>8]+E[255&e]+E[t>>8]+E[255&t],128)}function v(A){var I,g,C=A.length,Q=r[128].offset,B=0,t=0|Q[7],i=0,e=0|Q[6],n=0,a=0|Q[5],o=0,h=0|Q[4],w=0,f=0|Q[3],D=0,c=0|Q[2],y=0,F=0|Q[1],M=0,u=0|Q[0];for(g=0;g>>16),a=65535&(n+=i>>>16),h=65535&(o+=n>>>16),f=65535&(w+=o>>>16),c=65535&(D+=w>>>16),u=M+((y+=D>>>16)>>>16)&65535,F=65535&y,(I=A.charCodeAt(g))<128?t^=I:I<2048?(i=315*e,n=315*a,o=315*h,w=315*f,D=315*c,y=315*F,M=315*u,D+=(t^=I>>6|192)<<8,y+=e<<8,M+=a<<8,t=65535&(B=315*t),e=65535&(i+=B>>>16),a=65535&(n+=i>>>16),h=65535&(o+=n>>>16),f=65535&(w+=o>>>16),c=65535&(D+=w>>>16),u=M+((y+=D>>>16)>>>16)&65535,F=65535&y,t^=63&I|128):55296==(64512&I)&&g+1>18|240)<<8,y+=e<<8,t=65535&(B=315*t),u=(M+=a<<8)+((y+=(D+=(w+=(o+=(n+=(i+=B>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)&65535,i=315*(e=65535&i),n=315*(a=65535&n),o=315*(h=65535&o),w=315*(f=65535&w),D=315*(c=65535&D),y=315*(F=65535&y),M=315*u,D+=(t^=I>>12&63|128)<<8,y+=e<<8,t=65535&(B=315*t),u=(M+=a<<8)+((y+=(D+=(w+=(o+=(n+=(i+=B>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)&65535,i=315*(e=65535&i),n=315*(a=65535&n),o=315*(h=65535&o),w=315*(f=65535&w),D=315*(c=65535&D),y=315*(F=65535&y),M=315*u,D+=(t^=I>>6&63|128)<<8,y+=e<<8,M+=a<<8,t=65535&(B=315*t),e=65535&(i+=B>>>16),a=65535&(n+=i>>>16),h=65535&(o+=n>>>16),f=65535&(w+=o>>>16),c=65535&(D+=w>>>16),u=M+((y+=D>>>16)>>>16)&65535,F=65535&y,t^=63&I|128):(i=315*e,n=315*a,o=315*h,w=315*f,D=315*c,y=315*F,M=315*u,D+=(t^=I>>12|224)<<8,y+=e<<8,t=65535&(B=315*t),u=(M+=a<<8)+((y+=(D+=(w+=(o+=(n+=(i+=B>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)&65535,i=315*(e=65535&i),n=315*(a=65535&n),o=315*(h=65535&o),w=315*(f=65535&w),D=315*(c=65535&D),y=315*(F=65535&y),M=315*u,D+=(t^=I>>6&63|128)<<8,y+=e<<8,M+=a<<8,t=65535&(B=315*t),e=65535&(i+=B>>>16),a=65535&(n+=i>>>16),h=65535&(o+=n>>>16),f=65535&(w+=o>>>16),c=65535&(D+=w>>>16),u=M+((y+=D>>>16)>>>16)&65535,F=65535&y,t^=63&I|128);return s(E[u>>8]+E[255&u]+E[F>>8]+E[255&F]+E[c>>8]+E[255&c]+E[f>>8]+E[255&f]+E[h>>8]+E[255&h]+E[a>>8]+E[255&a]+E[e>>8]+E[255&e]+E[t>>8]+E[255&t],128)}function Y(A){var I,g=A.length-3,C=r[256].offset,Q=0,B=0|C[15],t=0,i=0|C[14],e=0,n=0|C[13],a=0,o=0|C[12],h=0,w=0|C[11],f=0,D=0|C[10],c=0,y=0|C[9],F=0,M=0|C[8],u=0,p=0|C[7],l=0,H=0|C[6],G=0,U=0|C[5],d=0,m=0|C[4],L=0,J=0|C[3],k=0,N=0|C[2],b=0,R=0|C[1],S=0,v=0|C[0];for(I=0;I>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)&65535,t=355*(i=65535&t),e=355*(n=65535&e),a=355*(o=65535&a),h=355*(w=65535&h),f=355*(D=65535&f),c=355*(y=65535&c),F=355*(M=65535&F),u=355*(p=65535&u),l=355*(H=65535&l),G=355*(U=65535&G),d=355*(m=65535&d),L=355*(J=65535&L),k=355*(N=65535&k),b=355*(R=65535&b),S=355*v,G+=(B^=A.charCodeAt(I++))<<8,d+=i<<8,L+=n<<8,k+=o<<8,b+=w<<8,B=65535&(Q=355*B),v=(S+=D<<8)+((b+=(k+=(L+=(d+=(G+=(l+=(u+=(F+=(c+=(f+=(h+=(a+=(e+=(t+=Q>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)&65535,t=355*(i=65535&t),e=355*(n=65535&e),a=355*(o=65535&a),h=355*(w=65535&h),f=355*(D=65535&f),c=355*(y=65535&c),F=355*(M=65535&F),u=355*(p=65535&u),l=355*(H=65535&l),G=355*(U=65535&G),d=355*(m=65535&d),L=355*(J=65535&L),k=355*(N=65535&k),b=355*(R=65535&b),S=355*v,G+=(B^=A.charCodeAt(I++))<<8,d+=i<<8,L+=n<<8,k+=o<<8,b+=w<<8,B=65535&(Q=355*B),v=(S+=D<<8)+((b+=(k+=(L+=(d+=(G+=(l+=(u+=(F+=(c+=(f+=(h+=(a+=(e+=(t+=Q>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)&65535,t=355*(i=65535&t),e=355*(n=65535&e),a=355*(o=65535&a),h=355*(w=65535&h),f=355*(D=65535&f),c=355*(y=65535&c),F=355*(M=65535&F),u=355*(p=65535&u),l=355*(H=65535&l),G=355*(U=65535&G),d=355*(m=65535&d),L=355*(J=65535&L),k=355*(N=65535&k),b=355*(R=65535&b),S=355*v,G+=(B^=A.charCodeAt(I++))<<8,d+=i<<8,L+=n<<8,k+=o<<8,b+=w<<8,S+=D<<8,B=65535&(Q=355*B),i=65535&(t+=Q>>>16),n=65535&(e+=t>>>16),o=65535&(a+=e>>>16),w=65535&(h+=a>>>16),D=65535&(f+=h>>>16),y=65535&(c+=f>>>16),M=65535&(F+=c>>>16),p=65535&(u+=F>>>16),H=65535&(l+=u>>>16),U=65535&(G+=l>>>16),m=65535&(d+=G>>>16),J=65535&(L+=d>>>16),N=65535&(k+=L>>>16),v=S+((b+=k>>>16)>>>16)&65535,R=65535&b;for(;I>>16),n=65535&(e+=t>>>16),o=65535&(a+=e>>>16),w=65535&(h+=a>>>16),D=65535&(f+=h>>>16),y=65535&(c+=f>>>16),M=65535&(F+=c>>>16),p=65535&(u+=F>>>16),H=65535&(l+=u>>>16),U=65535&(G+=l>>>16),m=65535&(d+=G>>>16),J=65535&(L+=d>>>16),N=65535&(k+=L>>>16),v=S+((b+=k>>>16)>>>16)&65535,R=65535&b;return s(E[v>>8]+E[255&v]+E[R>>8]+E[255&R]+E[N>>8]+E[255&N]+E[J>>8]+E[255&J]+E[m>>8]+E[255&m]+E[U>>8]+E[255&U]+E[H>>8]+E[255&H]+E[p>>8]+E[255&p]+E[M>>8]+E[255&M]+E[y>>8]+E[255&y]+E[D>>8]+E[255&D]+E[w>>8]+E[255&w]+E[o>>8]+E[255&o]+E[n>>8]+E[255&n]+E[i>>8]+E[255&i]+E[B>>8]+E[255&B],256)}function P(A){var I,g=A.length-3,C=r[256].offset,Q=0,B=0|C[15],t=0,i=0|C[14],e=0,n=0|C[13],a=0,o=0|C[12],h=0,w=0|C[11],f=0,D=0|C[10],c=0,y=0|C[9],F=0,M=0|C[8],u=0,p=0|C[7],l=0,H=0|C[6],G=0,U=0|C[5],d=0,m=0|C[4],L=0,J=0|C[3],k=0,N=0|C[2],b=0,R=0|C[1],S=0,v=0|C[0];for(I=0;I>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)&65535,t=355*(i=65535&t),e=355*(n=65535&e),a=355*(o=65535&a),h=355*(w=65535&h),f=355*(D=65535&f),c=355*(y=65535&c),F=355*(M=65535&F),u=355*(p=65535&u),l=355*(H=65535&l),G=355*(U=65535&G),d=355*(m=65535&d),L=355*(J=65535&L),k=355*(N=65535&k),b=355*(R=65535&b),S=355*v,G+=(B^=A.charCodeAt(I++))<<8,d+=i<<8,L+=n<<8,k+=o<<8,b+=w<<8,B=65535&(Q=355*B),v=(S+=D<<8)+((b+=(k+=(L+=(d+=(G+=(l+=(u+=(F+=(c+=(f+=(h+=(a+=(e+=(t+=Q>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)&65535,t=355*(i=65535&t),e=355*(n=65535&e),a=355*(o=65535&a),h=355*(w=65535&h),f=355*(D=65535&f),c=355*(y=65535&c),F=355*(M=65535&F),u=355*(p=65535&u),l=355*(H=65535&l),G=355*(U=65535&G),d=355*(m=65535&d),L=355*(J=65535&L),k=355*(N=65535&k),b=355*(R=65535&b),S=355*v,G+=(B^=A.charCodeAt(I++))<<8,d+=i<<8,L+=n<<8,k+=o<<8,b+=w<<8,B=65535&(Q=355*B),v=(S+=D<<8)+((b+=(k+=(L+=(d+=(G+=(l+=(u+=(F+=(c+=(f+=(h+=(a+=(e+=(t+=Q>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)&65535,t=355*(i=65535&t),e=355*(n=65535&e),a=355*(o=65535&a),h=355*(w=65535&h),f=355*(D=65535&f),c=355*(y=65535&c),F=355*(M=65535&F),u=355*(p=65535&u),l=355*(H=65535&l),G=355*(U=65535&G),d=355*(m=65535&d),L=355*(J=65535&L),k=355*(N=65535&k),b=355*(R=65535&b),S=355*v,G+=(B^=A.charCodeAt(I++))<<8,d+=i<<8,L+=n<<8,k+=o<<8,b+=w<<8,S+=D<<8,B=65535&(Q=355*B),i=65535&(t+=Q>>>16),n=65535&(e+=t>>>16),o=65535&(a+=e>>>16),w=65535&(h+=a>>>16),D=65535&(f+=h>>>16),y=65535&(c+=f>>>16),M=65535&(F+=c>>>16),p=65535&(u+=F>>>16),H=65535&(l+=u>>>16),U=65535&(G+=l>>>16),m=65535&(d+=G>>>16),J=65535&(L+=d>>>16),N=65535&(k+=L>>>16),v=S+((b+=k>>>16)>>>16)&65535,R=65535&b,B^=A.charCodeAt(I++);for(;I>>16),n=65535&(e+=t>>>16),o=65535&(a+=e>>>16),w=65535&(h+=a>>>16),D=65535&(f+=h>>>16),y=65535&(c+=f>>>16),M=65535&(F+=c>>>16),p=65535&(u+=F>>>16),H=65535&(l+=u>>>16),U=65535&(G+=l>>>16),m=65535&(d+=G>>>16),J=65535&(L+=d>>>16),N=65535&(k+=L>>>16),v=S+((b+=k>>>16)>>>16)&65535,R=65535&b,B^=A.charCodeAt(I++);return s(E[v>>8]+E[255&v]+E[R>>8]+E[255&R]+E[N>>8]+E[255&N]+E[J>>8]+E[255&J]+E[m>>8]+E[255&m]+E[U>>8]+E[255&U]+E[H>>8]+E[255&H]+E[p>>8]+E[255&p]+E[M>>8]+E[255&M]+E[y>>8]+E[255&y]+E[D>>8]+E[255&D]+E[w>>8]+E[255&w]+E[o>>8]+E[255&o]+E[n>>8]+E[255&n]+E[i>>8]+E[255&i]+E[B>>8]+E[255&B],256)}function q(A){var I,g,C=A.length,Q=r[256].offset,B=0,t=0|Q[15],i=0,e=0|Q[14],n=0,a=0|Q[13],o=0,h=0|Q[12],w=0,f=0|Q[11],D=0,c=0|Q[10],y=0,F=0|Q[9],M=0,u=0|Q[8],p=0,l=0|Q[7],H=0,G=0|Q[6],U=0,d=0|Q[5],m=0,L=0|Q[4],J=0,k=0|Q[3],N=0,b=0|Q[2],R=0,S=0|Q[1],v=0,Y=0|Q[0];for(g=0;g>6|192)<<8,m+=e<<8,J+=a<<8,N+=h<<8,R+=f<<8,v+=c<<8,t=65535&(B=355*t),e=65535&(i+=B>>>16),a=65535&(n+=i>>>16),h=65535&(o+=n>>>16),f=65535&(w+=o>>>16),c=65535&(D+=w>>>16),F=65535&(y+=D>>>16),u=65535&(M+=y>>>16),l=65535&(p+=M>>>16),G=65535&(H+=p>>>16),d=65535&(U+=H>>>16),L=65535&(m+=U>>>16),k=65535&(J+=m>>>16),b=65535&(N+=J>>>16),Y=v+((R+=N>>>16)>>>16)&65535,S=65535&R,t^=63&I|128):55296==(64512&I)&&g+1>18|240)<<8,m+=e<<8,J+=a<<8,N+=h<<8,R+=f<<8,t=65535&(B=355*t),Y=(v+=c<<8)+((R+=(N+=(J+=(m+=(U+=(H+=(p+=(M+=(y+=(D+=(w+=(o+=(n+=(i+=B>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)&65535,i=355*(e=65535&i),n=355*(a=65535&n),o=355*(h=65535&o),w=355*(f=65535&w),D=355*(c=65535&D),y=355*(F=65535&y),M=355*(u=65535&M),p=355*(l=65535&p),H=355*(G=65535&H),U=355*(d=65535&U),m=355*(L=65535&m),J=355*(k=65535&J),N=355*(b=65535&N),R=355*(S=65535&R),v=355*Y,U+=(t^=I>>12&63|128)<<8,m+=e<<8,J+=a<<8,N+=h<<8,R+=f<<8,t=65535&(B=355*t),Y=(v+=c<<8)+((R+=(N+=(J+=(m+=(U+=(H+=(p+=(M+=(y+=(D+=(w+=(o+=(n+=(i+=B>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)&65535,i=355*(e=65535&i),n=355*(a=65535&n),o=355*(h=65535&o),w=355*(f=65535&w),D=355*(c=65535&D),y=355*(F=65535&y),M=355*(u=65535&M),p=355*(l=65535&p),H=355*(G=65535&H),U=355*(d=65535&U),m=355*(L=65535&m),J=355*(k=65535&J),N=355*(b=65535&N),R=355*(S=65535&R),v=355*Y,U+=(t^=I>>6&63|128)<<8,m+=e<<8,J+=a<<8,N+=h<<8,R+=f<<8,v+=c<<8,t=65535&(B=355*t),e=65535&(i+=B>>>16),a=65535&(n+=i>>>16),h=65535&(o+=n>>>16),f=65535&(w+=o>>>16),c=65535&(D+=w>>>16),F=65535&(y+=D>>>16),u=65535&(M+=y>>>16),l=65535&(p+=M>>>16),G=65535&(H+=p>>>16),d=65535&(U+=H>>>16),L=65535&(m+=U>>>16),k=65535&(J+=m>>>16),b=65535&(N+=J>>>16),Y=v+((R+=N>>>16)>>>16)&65535,S=65535&R,t^=63&I|128):(i=355*e,n=355*a,o=355*h,w=355*f,D=355*c,y=355*F,M=355*u,p=355*l,H=355*G,U=355*d,m=355*L,J=355*k,N=355*b,R=355*S,v=355*Y,U+=(t^=I>>12|224)<<8,m+=e<<8,J+=a<<8,N+=h<<8,R+=f<<8,t=65535&(B=355*t),Y=(v+=c<<8)+((R+=(N+=(J+=(m+=(U+=(H+=(p+=(M+=(y+=(D+=(w+=(o+=(n+=(i+=B>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)&65535,i=355*(e=65535&i),n=355*(a=65535&n),o=355*(h=65535&o),w=355*(f=65535&w),D=355*(c=65535&D),y=355*(F=65535&y),M=355*(u=65535&M),p=355*(l=65535&p),H=355*(G=65535&H),U=355*(d=65535&U),m=355*(L=65535&m),J=355*(k=65535&J),N=355*(b=65535&N),R=355*(S=65535&R),v=355*Y,U+=(t^=I>>6&63|128)<<8,m+=e<<8,J+=a<<8,N+=h<<8,R+=f<<8,v+=c<<8,t=65535&(B=355*t),e=65535&(i+=B>>>16),a=65535&(n+=i>>>16),h=65535&(o+=n>>>16),f=65535&(w+=o>>>16),c=65535&(D+=w>>>16),F=65535&(y+=D>>>16),u=65535&(M+=y>>>16),l=65535&(p+=M>>>16),G=65535&(H+=p>>>16),d=65535&(U+=H>>>16),L=65535&(m+=U>>>16),k=65535&(J+=m>>>16),b=65535&(N+=J>>>16),Y=v+((R+=N>>>16)>>>16)&65535,S=65535&R,t^=63&I|128),i=355*e,n=355*a,o=355*h,w=355*f,D=355*c,y=355*F,M=355*u,p=355*l,H=355*G,U=355*d,m=355*L,J=355*k,N=355*b,R=355*S,v=355*Y,U+=t<<8,m+=e<<8,J+=a<<8,N+=h<<8,R+=f<<8,v+=c<<8,t=65535&(B=355*t),e=65535&(i+=B>>>16),a=65535&(n+=i>>>16),h=65535&(o+=n>>>16),f=65535&(w+=o>>>16),c=65535&(D+=w>>>16),F=65535&(y+=D>>>16),u=65535&(M+=y>>>16),l=65535&(p+=M>>>16),G=65535&(H+=p>>>16),d=65535&(U+=H>>>16),L=65535&(m+=U>>>16),k=65535&(J+=m>>>16),b=65535&(N+=J>>>16),Y=v+((R+=N>>>16)>>>16)&65535,S=65535&R;return s(E[Y>>8]+E[255&Y]+E[S>>8]+E[255&S]+E[b>>8]+E[255&b]+E[k>>8]+E[255&k]+E[L>>8]+E[255&L]+E[d>>8]+E[255&d]+E[G>>8]+E[255&G]+E[l>>8]+E[255&l]+E[u>>8]+E[255&u]+E[F>>8]+E[255&F]+E[c>>8]+E[255&c]+E[f>>8]+E[255&f]+E[h>>8]+E[255&h]+E[a>>8]+E[255&a]+E[e>>8]+E[255&e]+E[t>>8]+E[255&t],256)}function x(A){var I,g,C=A.length,Q=r[256].offset,B=0,t=0|Q[15],i=0,e=0|Q[14],n=0,a=0|Q[13],o=0,h=0|Q[12],w=0,f=0|Q[11],D=0,c=0|Q[10],y=0,F=0|Q[9],M=0,u=0|Q[8],p=0,l=0|Q[7],H=0,G=0|Q[6],U=0,d=0|Q[5],m=0,L=0|Q[4],J=0,k=0|Q[3],N=0,b=0|Q[2],R=0,S=0|Q[1],v=0,Y=0|Q[0];for(g=0;g>>16),a=65535&(n+=i>>>16),h=65535&(o+=n>>>16),f=65535&(w+=o>>>16),c=65535&(D+=w>>>16),F=65535&(y+=D>>>16),u=65535&(M+=y>>>16),l=65535&(p+=M>>>16),G=65535&(H+=p>>>16),d=65535&(U+=H>>>16),L=65535&(m+=U>>>16),k=65535&(J+=m>>>16),b=65535&(N+=J>>>16),Y=v+((R+=N>>>16)>>>16)&65535,S=65535&R,(I=A.charCodeAt(g))<128?t^=I:I<2048?(i=355*e,n=355*a,o=355*h,w=355*f,D=355*c,y=355*F,M=355*u,p=355*l,H=355*G,U=355*d,m=355*L,J=355*k,N=355*b,R=355*S,v=355*Y,U+=(t^=I>>6|192)<<8,m+=e<<8,J+=a<<8,N+=h<<8,R+=f<<8,v+=c<<8,t=65535&(B=355*t),e=65535&(i+=B>>>16),a=65535&(n+=i>>>16),h=65535&(o+=n>>>16),f=65535&(w+=o>>>16),c=65535&(D+=w>>>16),F=65535&(y+=D>>>16),u=65535&(M+=y>>>16),l=65535&(p+=M>>>16),G=65535&(H+=p>>>16),d=65535&(U+=H>>>16),L=65535&(m+=U>>>16),k=65535&(J+=m>>>16),b=65535&(N+=J>>>16),Y=v+((R+=N>>>16)>>>16)&65535,S=65535&R,t^=63&I|128):55296==(64512&I)&&g+1>18|240)<<8,m+=e<<8,J+=a<<8,N+=h<<8,R+=f<<8,t=65535&(B=355*t),Y=(v+=c<<8)+((R+=(N+=(J+=(m+=(U+=(H+=(p+=(M+=(y+=(D+=(w+=(o+=(n+=(i+=B>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)&65535,i=355*(e=65535&i),n=355*(a=65535&n),o=355*(h=65535&o),w=355*(f=65535&w),D=355*(c=65535&D),y=355*(F=65535&y),M=355*(u=65535&M),p=355*(l=65535&p),H=355*(G=65535&H),U=355*(d=65535&U),m=355*(L=65535&m),J=355*(k=65535&J),N=355*(b=65535&N),R=355*(S=65535&R),v=355*Y,U+=(t^=I>>12&63|128)<<8,m+=e<<8,J+=a<<8,N+=h<<8,R+=f<<8,t=65535&(B=355*t),Y=(v+=c<<8)+((R+=(N+=(J+=(m+=(U+=(H+=(p+=(M+=(y+=(D+=(w+=(o+=(n+=(i+=B>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)&65535,i=355*(e=65535&i),n=355*(a=65535&n),o=355*(h=65535&o),w=355*(f=65535&w),D=355*(c=65535&D),y=355*(F=65535&y),M=355*(u=65535&M),p=355*(l=65535&p),H=355*(G=65535&H),U=355*(d=65535&U),m=355*(L=65535&m),J=355*(k=65535&J),N=355*(b=65535&N),R=355*(S=65535&R),v=355*Y,U+=(t^=I>>6&63|128)<<8,m+=e<<8,J+=a<<8,N+=h<<8,R+=f<<8,v+=c<<8,t=65535&(B=355*t),e=65535&(i+=B>>>16),a=65535&(n+=i>>>16),h=65535&(o+=n>>>16),f=65535&(w+=o>>>16),c=65535&(D+=w>>>16),F=65535&(y+=D>>>16),u=65535&(M+=y>>>16),l=65535&(p+=M>>>16),G=65535&(H+=p>>>16),d=65535&(U+=H>>>16),L=65535&(m+=U>>>16),k=65535&(J+=m>>>16),b=65535&(N+=J>>>16),Y=v+((R+=N>>>16)>>>16)&65535,S=65535&R,t^=63&I|128):(i=355*e,n=355*a,o=355*h,w=355*f,D=355*c,y=355*F,M=355*u,p=355*l,H=355*G,U=355*d,m=355*L,J=355*k,N=355*b,R=355*S,v=355*Y,U+=(t^=I>>12|224)<<8,m+=e<<8,J+=a<<8,N+=h<<8,R+=f<<8,t=65535&(B=355*t),Y=(v+=c<<8)+((R+=(N+=(J+=(m+=(U+=(H+=(p+=(M+=(y+=(D+=(w+=(o+=(n+=(i+=B>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)&65535,i=355*(e=65535&i),n=355*(a=65535&n),o=355*(h=65535&o),w=355*(f=65535&w),D=355*(c=65535&D),y=355*(F=65535&y),M=355*(u=65535&M),p=355*(l=65535&p),H=355*(G=65535&H),U=355*(d=65535&U),m=355*(L=65535&m),J=355*(k=65535&J),N=355*(b=65535&N),R=355*(S=65535&R),v=355*Y,U+=(t^=I>>6&63|128)<<8,m+=e<<8,J+=a<<8,N+=h<<8,R+=f<<8,v+=c<<8,t=65535&(B=355*t),e=65535&(i+=B>>>16),a=65535&(n+=i>>>16),h=65535&(o+=n>>>16),f=65535&(w+=o>>>16),c=65535&(D+=w>>>16),F=65535&(y+=D>>>16),u=65535&(M+=y>>>16),l=65535&(p+=M>>>16),G=65535&(H+=p>>>16),d=65535&(U+=H>>>16),L=65535&(m+=U>>>16),k=65535&(J+=m>>>16),b=65535&(N+=J>>>16),Y=v+((R+=N>>>16)>>>16)&65535,S=65535&R,t^=63&I|128);return s(E[Y>>8]+E[255&Y]+E[S>>8]+E[255&S]+E[b>>8]+E[255&b]+E[k>>8]+E[255&k]+E[L>>8]+E[255&L]+E[d>>8]+E[255&d]+E[G>>8]+E[255&G]+E[l>>8]+E[255&l]+E[u>>8]+E[255&u]+E[F>>8]+E[255&F]+E[c>>8]+E[255&c]+E[f>>8]+E[255&f]+E[h>>8]+E[255&h]+E[a>>8]+E[255&a]+E[e>>8]+E[255&e]+E[t>>8]+E[255&t],256)}function X(A){var I,g=A.length-3,C=r[512].offset,Q=0,B=0|C[31],t=0,i=0|C[30],e=0,n=0|C[29],a=0,o=0|C[28],h=0,w=0|C[27],f=0,D=0|C[26],c=0,y=0|C[25],F=0,M=0|C[24],u=0,p=0|C[23],l=0,H=0|C[22],G=0,U=0|C[21],d=0,m=0|C[20],L=0,J=0|C[19],k=0,N=0|C[18],b=0,R=0|C[17],S=0,v=0|C[16],Y=0,P=0|C[15],q=0,x=0|C[14],X=0,Z=0|C[13],V=0,K=0|C[12],W=0,O=0|C[11],j=0,z=0|C[10],T=0,_=0|C[9],$=0,AA=0|C[8],IA=0,gA=0|C[7],CA=0,QA=0|C[6],BA=0,tA=0|C[5],iA=0,EA=0|C[4],eA=0,nA=0|C[3],aA=0,oA=0|C[2],hA=0,rA=0|C[1],wA=0,sA=0|C[0];for(I=0;I>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)&65535,t=343*(i=65535&t),e=343*(n=65535&e),a=343*(o=65535&a),h=343*(w=65535&h),f=343*(D=65535&f),c=343*(y=65535&c),F=343*(M=65535&F),u=343*(p=65535&u),l=343*(H=65535&l),G=343*(U=65535&G),d=343*(m=65535&d),L=343*(J=65535&L),k=343*(N=65535&k),b=343*(R=65535&b),S=343*(v=65535&S),Y=343*(P=65535&Y),q=343*(x=65535&q),X=343*(Z=65535&X),V=343*(K=65535&V),W=343*(O=65535&W),j=343*(z=65535&j),T=343*(_=65535&T),$=343*(AA=65535&$),IA=343*(gA=65535&IA),CA=343*(QA=65535&CA),BA=343*(tA=65535&BA),iA=343*(EA=65535&iA),eA=343*(nA=65535&eA),aA=343*(oA=65535&aA),hA=343*(rA=65535&hA),wA=343*sA,j+=(B^=A.charCodeAt(I++))<<8,T+=i<<8,$+=n<<8,IA+=o<<8,CA+=w<<8,BA+=D<<8,iA+=y<<8,eA+=M<<8,aA+=p<<8,hA+=H<<8,B=65535&(Q=343*B),sA=(wA+=U<<8)+((hA+=(aA+=(eA+=(iA+=(BA+=(CA+=(IA+=($+=(T+=(j+=(W+=(V+=(X+=(q+=(Y+=(S+=(b+=(k+=(L+=(d+=(G+=(l+=(u+=(F+=(c+=(f+=(h+=(a+=(e+=(t+=Q>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)&65535,t=343*(i=65535&t),e=343*(n=65535&e),a=343*(o=65535&a),h=343*(w=65535&h),f=343*(D=65535&f),c=343*(y=65535&c),F=343*(M=65535&F),u=343*(p=65535&u),l=343*(H=65535&l),G=343*(U=65535&G),d=343*(m=65535&d),L=343*(J=65535&L),k=343*(N=65535&k),b=343*(R=65535&b),S=343*(v=65535&S),Y=343*(P=65535&Y),q=343*(x=65535&q),X=343*(Z=65535&X),V=343*(K=65535&V),W=343*(O=65535&W),j=343*(z=65535&j),T=343*(_=65535&T),$=343*(AA=65535&$),IA=343*(gA=65535&IA),CA=343*(QA=65535&CA),BA=343*(tA=65535&BA),iA=343*(EA=65535&iA),eA=343*(nA=65535&eA),aA=343*(oA=65535&aA),hA=343*(rA=65535&hA),wA=343*sA,j+=(B^=A.charCodeAt(I++))<<8,T+=i<<8,$+=n<<8,IA+=o<<8,CA+=w<<8,BA+=D<<8,iA+=y<<8,eA+=M<<8,aA+=p<<8,hA+=H<<8,B=65535&(Q=343*B),sA=(wA+=U<<8)+((hA+=(aA+=(eA+=(iA+=(BA+=(CA+=(IA+=($+=(T+=(j+=(W+=(V+=(X+=(q+=(Y+=(S+=(b+=(k+=(L+=(d+=(G+=(l+=(u+=(F+=(c+=(f+=(h+=(a+=(e+=(t+=Q>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)&65535,t=343*(i=65535&t),e=343*(n=65535&e),a=343*(o=65535&a),h=343*(w=65535&h),f=343*(D=65535&f),c=343*(y=65535&c),F=343*(M=65535&F),u=343*(p=65535&u),l=343*(H=65535&l),G=343*(U=65535&G),d=343*(m=65535&d),L=343*(J=65535&L),k=343*(N=65535&k),b=343*(R=65535&b),S=343*(v=65535&S),Y=343*(P=65535&Y),q=343*(x=65535&q),X=343*(Z=65535&X),V=343*(K=65535&V),W=343*(O=65535&W),j=343*(z=65535&j),T=343*(_=65535&T),$=343*(AA=65535&$),IA=343*(gA=65535&IA),CA=343*(QA=65535&CA),BA=343*(tA=65535&BA),iA=343*(EA=65535&iA),eA=343*(nA=65535&eA),aA=343*(oA=65535&aA),hA=343*(rA=65535&hA),wA=343*sA,j+=(B^=A.charCodeAt(I++))<<8,T+=i<<8,$+=n<<8,IA+=o<<8,CA+=w<<8,BA+=D<<8,iA+=y<<8,eA+=M<<8,aA+=p<<8,hA+=H<<8,wA+=U<<8,B=65535&(Q=343*B),i=65535&(t+=Q>>>16),n=65535&(e+=t>>>16),o=65535&(a+=e>>>16),w=65535&(h+=a>>>16),D=65535&(f+=h>>>16),y=65535&(c+=f>>>16),M=65535&(F+=c>>>16),p=65535&(u+=F>>>16),H=65535&(l+=u>>>16),U=65535&(G+=l>>>16),m=65535&(d+=G>>>16),J=65535&(L+=d>>>16),N=65535&(k+=L>>>16),R=65535&(b+=k>>>16),v=65535&(S+=b>>>16),P=65535&(Y+=S>>>16),x=65535&(q+=Y>>>16),Z=65535&(X+=q>>>16),K=65535&(V+=X>>>16),O=65535&(W+=V>>>16),z=65535&(j+=W>>>16),_=65535&(T+=j>>>16),AA=65535&($+=T>>>16),gA=65535&(IA+=$>>>16),QA=65535&(CA+=IA>>>16),tA=65535&(BA+=CA>>>16),EA=65535&(iA+=BA>>>16),nA=65535&(eA+=iA>>>16),oA=65535&(aA+=eA>>>16),sA=wA+((hA+=aA>>>16)>>>16)&65535,rA=65535&hA;for(;I>>16),n=65535&(e+=t>>>16),o=65535&(a+=e>>>16),w=65535&(h+=a>>>16),D=65535&(f+=h>>>16),y=65535&(c+=f>>>16),M=65535&(F+=c>>>16),p=65535&(u+=F>>>16),H=65535&(l+=u>>>16),U=65535&(G+=l>>>16),m=65535&(d+=G>>>16),J=65535&(L+=d>>>16),N=65535&(k+=L>>>16),R=65535&(b+=k>>>16),v=65535&(S+=b>>>16),P=65535&(Y+=S>>>16),x=65535&(q+=Y>>>16),Z=65535&(X+=q>>>16),K=65535&(V+=X>>>16),O=65535&(W+=V>>>16),z=65535&(j+=W>>>16),_=65535&(T+=j>>>16),AA=65535&($+=T>>>16),gA=65535&(IA+=$>>>16),QA=65535&(CA+=IA>>>16),tA=65535&(BA+=CA>>>16),EA=65535&(iA+=BA>>>16),nA=65535&(eA+=iA>>>16),oA=65535&(aA+=eA>>>16),sA=wA+((hA+=aA>>>16)>>>16)&65535,rA=65535&hA;return s(E[sA>>8]+E[255&sA]+E[rA>>8]+E[255&rA]+E[oA>>8]+E[255&oA]+E[nA>>8]+E[255&nA]+E[EA>>8]+E[255&EA]+E[tA>>8]+E[255&tA]+E[QA>>8]+E[255&QA]+E[gA>>8]+E[255&gA]+E[AA>>8]+E[255&AA]+E[_>>8]+E[255&_]+E[z>>8]+E[255&z]+E[O>>8]+E[255&O]+E[K>>8]+E[255&K]+E[Z>>8]+E[255&Z]+E[x>>8]+E[255&x]+E[P>>8]+E[255&P]+E[v>>8]+E[255&v]+E[R>>8]+E[255&R]+E[N>>8]+E[255&N]+E[J>>8]+E[255&J]+E[m>>8]+E[255&m]+E[U>>8]+E[255&U]+E[H>>8]+E[255&H]+E[p>>8]+E[255&p]+E[M>>8]+E[255&M]+E[y>>8]+E[255&y]+E[D>>8]+E[255&D]+E[w>>8]+E[255&w]+E[o>>8]+E[255&o]+E[n>>8]+E[255&n]+E[i>>8]+E[255&i]+E[B>>8]+E[255&B],512)}function Z(A){var I,g=A.length-3,C=r[512].offset,Q=0,B=0|C[31],t=0,i=0|C[30],e=0,n=0|C[29],a=0,o=0|C[28],h=0,w=0|C[27],f=0,D=0|C[26],c=0,y=0|C[25],F=0,M=0|C[24],u=0,p=0|C[23],l=0,H=0|C[22],G=0,U=0|C[21],d=0,m=0|C[20],L=0,J=0|C[19],k=0,N=0|C[18],b=0,R=0|C[17],S=0,v=0|C[16],Y=0,P=0|C[15],q=0,x=0|C[14],X=0,Z=0|C[13],V=0,K=0|C[12],W=0,O=0|C[11],j=0,z=0|C[10],T=0,_=0|C[9],$=0,AA=0|C[8],IA=0,gA=0|C[7],CA=0,QA=0|C[6],BA=0,tA=0|C[5],iA=0,EA=0|C[4],eA=0,nA=0|C[3],aA=0,oA=0|C[2],hA=0,rA=0|C[1],wA=0,sA=0|C[0];for(I=0;I>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)&65535,t=343*(i=65535&t),e=343*(n=65535&e),a=343*(o=65535&a),h=343*(w=65535&h),f=343*(D=65535&f),c=343*(y=65535&c),F=343*(M=65535&F),u=343*(p=65535&u),l=343*(H=65535&l),G=343*(U=65535&G),d=343*(m=65535&d),L=343*(J=65535&L),k=343*(N=65535&k),b=343*(R=65535&b),S=343*(v=65535&S),Y=343*(P=65535&Y),q=343*(x=65535&q),X=343*(Z=65535&X),V=343*(K=65535&V),W=343*(O=65535&W),j=343*(z=65535&j),T=343*(_=65535&T),$=343*(AA=65535&$),IA=343*(gA=65535&IA),CA=343*(QA=65535&CA),BA=343*(tA=65535&BA),iA=343*(EA=65535&iA),eA=343*(nA=65535&eA),aA=343*(oA=65535&aA),hA=343*(rA=65535&hA),wA=343*sA,j+=(B^=A.charCodeAt(I++))<<8,T+=i<<8,$+=n<<8,IA+=o<<8,CA+=w<<8,BA+=D<<8,iA+=y<<8,eA+=M<<8,aA+=p<<8,hA+=H<<8,B=65535&(Q=343*B),sA=(wA+=U<<8)+((hA+=(aA+=(eA+=(iA+=(BA+=(CA+=(IA+=($+=(T+=(j+=(W+=(V+=(X+=(q+=(Y+=(S+=(b+=(k+=(L+=(d+=(G+=(l+=(u+=(F+=(c+=(f+=(h+=(a+=(e+=(t+=Q>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)&65535,t=343*(i=65535&t),e=343*(n=65535&e),a=343*(o=65535&a),h=343*(w=65535&h),f=343*(D=65535&f),c=343*(y=65535&c),F=343*(M=65535&F),u=343*(p=65535&u),l=343*(H=65535&l),G=343*(U=65535&G),d=343*(m=65535&d),L=343*(J=65535&L),k=343*(N=65535&k),b=343*(R=65535&b),S=343*(v=65535&S),Y=343*(P=65535&Y),q=343*(x=65535&q),X=343*(Z=65535&X),V=343*(K=65535&V),W=343*(O=65535&W),j=343*(z=65535&j),T=343*(_=65535&T),$=343*(AA=65535&$),IA=343*(gA=65535&IA),CA=343*(QA=65535&CA),BA=343*(tA=65535&BA),iA=343*(EA=65535&iA),eA=343*(nA=65535&eA),aA=343*(oA=65535&aA),hA=343*(rA=65535&hA),wA=343*sA,j+=(B^=A.charCodeAt(I++))<<8,T+=i<<8,$+=n<<8,IA+=o<<8,CA+=w<<8,BA+=D<<8,iA+=y<<8,eA+=M<<8,aA+=p<<8,hA+=H<<8,B=65535&(Q=343*B),sA=(wA+=U<<8)+((hA+=(aA+=(eA+=(iA+=(BA+=(CA+=(IA+=($+=(T+=(j+=(W+=(V+=(X+=(q+=(Y+=(S+=(b+=(k+=(L+=(d+=(G+=(l+=(u+=(F+=(c+=(f+=(h+=(a+=(e+=(t+=Q>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)&65535,t=343*(i=65535&t),e=343*(n=65535&e),a=343*(o=65535&a),h=343*(w=65535&h),f=343*(D=65535&f),c=343*(y=65535&c),F=343*(M=65535&F),u=343*(p=65535&u),l=343*(H=65535&l),G=343*(U=65535&G),d=343*(m=65535&d),L=343*(J=65535&L),k=343*(N=65535&k),b=343*(R=65535&b),S=343*(v=65535&S),Y=343*(P=65535&Y),q=343*(x=65535&q),X=343*(Z=65535&X),V=343*(K=65535&V),W=343*(O=65535&W),j=343*(z=65535&j),T=343*(_=65535&T),$=343*(AA=65535&$),IA=343*(gA=65535&IA),CA=343*(QA=65535&CA),BA=343*(tA=65535&BA),iA=343*(EA=65535&iA),eA=343*(nA=65535&eA),aA=343*(oA=65535&aA),hA=343*(rA=65535&hA),wA=343*sA,j+=(B^=A.charCodeAt(I++))<<8,T+=i<<8,$+=n<<8,IA+=o<<8,CA+=w<<8,BA+=D<<8,iA+=y<<8,eA+=M<<8,aA+=p<<8,hA+=H<<8,wA+=U<<8,B=65535&(Q=343*B),i=65535&(t+=Q>>>16),n=65535&(e+=t>>>16),o=65535&(a+=e>>>16),w=65535&(h+=a>>>16),D=65535&(f+=h>>>16),y=65535&(c+=f>>>16),M=65535&(F+=c>>>16),p=65535&(u+=F>>>16),H=65535&(l+=u>>>16),U=65535&(G+=l>>>16),m=65535&(d+=G>>>16),J=65535&(L+=d>>>16),N=65535&(k+=L>>>16),R=65535&(b+=k>>>16),v=65535&(S+=b>>>16),P=65535&(Y+=S>>>16),x=65535&(q+=Y>>>16),Z=65535&(X+=q>>>16),K=65535&(V+=X>>>16),O=65535&(W+=V>>>16),z=65535&(j+=W>>>16),_=65535&(T+=j>>>16),AA=65535&($+=T>>>16),gA=65535&(IA+=$>>>16),QA=65535&(CA+=IA>>>16),tA=65535&(BA+=CA>>>16),EA=65535&(iA+=BA>>>16),nA=65535&(eA+=iA>>>16),oA=65535&(aA+=eA>>>16),sA=wA+((hA+=aA>>>16)>>>16)&65535,rA=65535&hA,B^=A.charCodeAt(I++);for(;I>>16),n=65535&(e+=t>>>16),o=65535&(a+=e>>>16),w=65535&(h+=a>>>16),D=65535&(f+=h>>>16),y=65535&(c+=f>>>16),M=65535&(F+=c>>>16),p=65535&(u+=F>>>16),H=65535&(l+=u>>>16),U=65535&(G+=l>>>16),m=65535&(d+=G>>>16),J=65535&(L+=d>>>16),N=65535&(k+=L>>>16),R=65535&(b+=k>>>16),v=65535&(S+=b>>>16),P=65535&(Y+=S>>>16),x=65535&(q+=Y>>>16),Z=65535&(X+=q>>>16),K=65535&(V+=X>>>16),O=65535&(W+=V>>>16),z=65535&(j+=W>>>16),_=65535&(T+=j>>>16),AA=65535&($+=T>>>16),gA=65535&(IA+=$>>>16),QA=65535&(CA+=IA>>>16),tA=65535&(BA+=CA>>>16),EA=65535&(iA+=BA>>>16),nA=65535&(eA+=iA>>>16),oA=65535&(aA+=eA>>>16),sA=wA+((hA+=aA>>>16)>>>16)&65535,rA=65535&hA,B^=A.charCodeAt(I++);return s(E[sA>>8]+E[255&sA]+E[rA>>8]+E[255&rA]+E[oA>>8]+E[255&oA]+E[nA>>8]+E[255&nA]+E[EA>>8]+E[255&EA]+E[tA>>8]+E[255&tA]+E[QA>>8]+E[255&QA]+E[gA>>8]+E[255&gA]+E[AA>>8]+E[255&AA]+E[_>>8]+E[255&_]+E[z>>8]+E[255&z]+E[O>>8]+E[255&O]+E[K>>8]+E[255&K]+E[Z>>8]+E[255&Z]+E[x>>8]+E[255&x]+E[P>>8]+E[255&P]+E[v>>8]+E[255&v]+E[R>>8]+E[255&R]+E[N>>8]+E[255&N]+E[J>>8]+E[255&J]+E[m>>8]+E[255&m]+E[U>>8]+E[255&U]+E[H>>8]+E[255&H]+E[p>>8]+E[255&p]+E[M>>8]+E[255&M]+E[y>>8]+E[255&y]+E[D>>8]+E[255&D]+E[w>>8]+E[255&w]+E[o>>8]+E[255&o]+E[n>>8]+E[255&n]+E[i>>8]+E[255&i]+E[B>>8]+E[255&B],512)}function V(A){var I,g,C=A.length,Q=r[512].offset,B=0,t=0|Q[31],i=0,e=0|Q[30],n=0,a=0|Q[29],o=0,h=0|Q[28],w=0,f=0|Q[27],D=0,c=0|Q[26],y=0,F=0|Q[25],M=0,u=0|Q[24],p=0,l=0|Q[23],H=0,G=0|Q[22],U=0,d=0|Q[21],m=0,L=0|Q[20],J=0,k=0|Q[19],N=0,b=0|Q[18],R=0,S=0|Q[17],v=0,Y=0|Q[16],P=0,q=0|Q[15],x=0,X=0|Q[14],Z=0,V=0|Q[13],K=0,W=0|Q[12],O=0,j=0|Q[11],z=0,T=0|Q[10],_=0,$=0|Q[9],AA=0,IA=0|Q[8],gA=0,CA=0|Q[7],QA=0,BA=0|Q[6],tA=0,iA=0|Q[5],EA=0,eA=0|Q[4],nA=0,aA=0|Q[3],oA=0,hA=0|Q[2],rA=0,wA=0|Q[1],sA=0,fA=0|Q[0];for(g=0;g>6|192)<<8,_+=e<<8,AA+=a<<8,gA+=h<<8,QA+=f<<8,tA+=c<<8,EA+=F<<8,nA+=u<<8,oA+=l<<8,rA+=G<<8,sA+=d<<8,t=65535&(B=343*t),e=65535&(i+=B>>>16),a=65535&(n+=i>>>16),h=65535&(o+=n>>>16),f=65535&(w+=o>>>16),c=65535&(D+=w>>>16),F=65535&(y+=D>>>16),u=65535&(M+=y>>>16),l=65535&(p+=M>>>16),G=65535&(H+=p>>>16),d=65535&(U+=H>>>16),L=65535&(m+=U>>>16),k=65535&(J+=m>>>16),b=65535&(N+=J>>>16),S=65535&(R+=N>>>16),Y=65535&(v+=R>>>16),q=65535&(P+=v>>>16),X=65535&(x+=P>>>16),V=65535&(Z+=x>>>16),W=65535&(K+=Z>>>16),j=65535&(O+=K>>>16),T=65535&(z+=O>>>16),$=65535&(_+=z>>>16),IA=65535&(AA+=_>>>16),CA=65535&(gA+=AA>>>16),BA=65535&(QA+=gA>>>16),iA=65535&(tA+=QA>>>16),eA=65535&(EA+=tA>>>16),aA=65535&(nA+=EA>>>16),hA=65535&(oA+=nA>>>16),fA=sA+((rA+=oA>>>16)>>>16)&65535,wA=65535&rA,t^=63&I|128):55296==(64512&I)&&g+1>18|240)<<8,_+=e<<8,AA+=a<<8,gA+=h<<8,QA+=f<<8,tA+=c<<8,EA+=F<<8,nA+=u<<8,oA+=l<<8,rA+=G<<8,t=65535&(B=343*t),fA=(sA+=d<<8)+((rA+=(oA+=(nA+=(EA+=(tA+=(QA+=(gA+=(AA+=(_+=(z+=(O+=(K+=(Z+=(x+=(P+=(v+=(R+=(N+=(J+=(m+=(U+=(H+=(p+=(M+=(y+=(D+=(w+=(o+=(n+=(i+=B>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)&65535,i=343*(e=65535&i),n=343*(a=65535&n),o=343*(h=65535&o),w=343*(f=65535&w),D=343*(c=65535&D),y=343*(F=65535&y),M=343*(u=65535&M),p=343*(l=65535&p),H=343*(G=65535&H),U=343*(d=65535&U),m=343*(L=65535&m),J=343*(k=65535&J),N=343*(b=65535&N),R=343*(S=65535&R),v=343*(Y=65535&v),P=343*(q=65535&P),x=343*(X=65535&x),Z=343*(V=65535&Z),K=343*(W=65535&K),O=343*(j=65535&O),z=343*(T=65535&z),_=343*($=65535&_),AA=343*(IA=65535&AA),gA=343*(CA=65535&gA),QA=343*(BA=65535&QA),tA=343*(iA=65535&tA),EA=343*(eA=65535&EA),nA=343*(aA=65535&nA),oA=343*(hA=65535&oA),rA=343*(wA=65535&rA),sA=343*fA,z+=(t^=I>>12&63|128)<<8,_+=e<<8,AA+=a<<8,gA+=h<<8,QA+=f<<8,tA+=c<<8,EA+=F<<8,nA+=u<<8,oA+=l<<8,rA+=G<<8,t=65535&(B=343*t),fA=(sA+=d<<8)+((rA+=(oA+=(nA+=(EA+=(tA+=(QA+=(gA+=(AA+=(_+=(z+=(O+=(K+=(Z+=(x+=(P+=(v+=(R+=(N+=(J+=(m+=(U+=(H+=(p+=(M+=(y+=(D+=(w+=(o+=(n+=(i+=B>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)&65535,i=343*(e=65535&i),n=343*(a=65535&n),o=343*(h=65535&o),w=343*(f=65535&w),D=343*(c=65535&D),y=343*(F=65535&y),M=343*(u=65535&M),p=343*(l=65535&p),H=343*(G=65535&H),U=343*(d=65535&U),m=343*(L=65535&m),J=343*(k=65535&J),N=343*(b=65535&N),R=343*(S=65535&R),v=343*(Y=65535&v),P=343*(q=65535&P),x=343*(X=65535&x),Z=343*(V=65535&Z),K=343*(W=65535&K),O=343*(j=65535&O),z=343*(T=65535&z),_=343*($=65535&_),AA=343*(IA=65535&AA),gA=343*(CA=65535&gA),QA=343*(BA=65535&QA),tA=343*(iA=65535&tA),EA=343*(eA=65535&EA),nA=343*(aA=65535&nA),oA=343*(hA=65535&oA),rA=343*(wA=65535&rA),sA=343*fA,z+=(t^=I>>6&63|128)<<8,_+=e<<8,AA+=a<<8,gA+=h<<8,QA+=f<<8,tA+=c<<8,EA+=F<<8,nA+=u<<8,oA+=l<<8,rA+=G<<8,sA+=d<<8,t=65535&(B=343*t),e=65535&(i+=B>>>16),a=65535&(n+=i>>>16),h=65535&(o+=n>>>16),f=65535&(w+=o>>>16),c=65535&(D+=w>>>16),F=65535&(y+=D>>>16),u=65535&(M+=y>>>16),l=65535&(p+=M>>>16),G=65535&(H+=p>>>16),d=65535&(U+=H>>>16),L=65535&(m+=U>>>16),k=65535&(J+=m>>>16),b=65535&(N+=J>>>16),S=65535&(R+=N>>>16),Y=65535&(v+=R>>>16),q=65535&(P+=v>>>16),X=65535&(x+=P>>>16),V=65535&(Z+=x>>>16),W=65535&(K+=Z>>>16),j=65535&(O+=K>>>16),T=65535&(z+=O>>>16),$=65535&(_+=z>>>16),IA=65535&(AA+=_>>>16),CA=65535&(gA+=AA>>>16),BA=65535&(QA+=gA>>>16),iA=65535&(tA+=QA>>>16),eA=65535&(EA+=tA>>>16),aA=65535&(nA+=EA>>>16),hA=65535&(oA+=nA>>>16),fA=sA+((rA+=oA>>>16)>>>16)&65535,wA=65535&rA,t^=63&I|128):(i=343*e,n=343*a,o=343*h,w=343*f,D=343*c,y=343*F,M=343*u,p=343*l,H=343*G,U=343*d,m=343*L,J=343*k,N=343*b,R=343*S,v=343*Y,P=343*q,x=343*X,Z=343*V,K=343*W,O=343*j,z=343*T,_=343*$,AA=343*IA,gA=343*CA,QA=343*BA,tA=343*iA,EA=343*eA,nA=343*aA,oA=343*hA,rA=343*wA,sA=343*fA,z+=(t^=I>>12|224)<<8,_+=e<<8,AA+=a<<8,gA+=h<<8,QA+=f<<8,tA+=c<<8,EA+=F<<8,nA+=u<<8,oA+=l<<8,rA+=G<<8,t=65535&(B=343*t),fA=(sA+=d<<8)+((rA+=(oA+=(nA+=(EA+=(tA+=(QA+=(gA+=(AA+=(_+=(z+=(O+=(K+=(Z+=(x+=(P+=(v+=(R+=(N+=(J+=(m+=(U+=(H+=(p+=(M+=(y+=(D+=(w+=(o+=(n+=(i+=B>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)&65535,i=343*(e=65535&i),n=343*(a=65535&n),o=343*(h=65535&o),w=343*(f=65535&w),D=343*(c=65535&D),y=343*(F=65535&y),M=343*(u=65535&M),p=343*(l=65535&p),H=343*(G=65535&H),U=343*(d=65535&U),m=343*(L=65535&m),J=343*(k=65535&J),N=343*(b=65535&N),R=343*(S=65535&R),v=343*(Y=65535&v),P=343*(q=65535&P),x=343*(X=65535&x),Z=343*(V=65535&Z),K=343*(W=65535&K),O=343*(j=65535&O),z=343*(T=65535&z),_=343*($=65535&_),AA=343*(IA=65535&AA),gA=343*(CA=65535&gA),QA=343*(BA=65535&QA),tA=343*(iA=65535&tA),EA=343*(eA=65535&EA),nA=343*(aA=65535&nA),oA=343*(hA=65535&oA),rA=343*(wA=65535&rA),sA=343*fA,z+=(t^=I>>6&63|128)<<8,_+=e<<8,AA+=a<<8,gA+=h<<8,QA+=f<<8,tA+=c<<8,EA+=F<<8,nA+=u<<8,oA+=l<<8,rA+=G<<8,sA+=d<<8,t=65535&(B=343*t),e=65535&(i+=B>>>16),a=65535&(n+=i>>>16),h=65535&(o+=n>>>16),f=65535&(w+=o>>>16),c=65535&(D+=w>>>16),F=65535&(y+=D>>>16),u=65535&(M+=y>>>16),l=65535&(p+=M>>>16),G=65535&(H+=p>>>16),d=65535&(U+=H>>>16),L=65535&(m+=U>>>16),k=65535&(J+=m>>>16),b=65535&(N+=J>>>16),S=65535&(R+=N>>>16),Y=65535&(v+=R>>>16),q=65535&(P+=v>>>16),X=65535&(x+=P>>>16),V=65535&(Z+=x>>>16),W=65535&(K+=Z>>>16),j=65535&(O+=K>>>16),T=65535&(z+=O>>>16),$=65535&(_+=z>>>16),IA=65535&(AA+=_>>>16),CA=65535&(gA+=AA>>>16),BA=65535&(QA+=gA>>>16),iA=65535&(tA+=QA>>>16),eA=65535&(EA+=tA>>>16),aA=65535&(nA+=EA>>>16),hA=65535&(oA+=nA>>>16),fA=sA+((rA+=oA>>>16)>>>16)&65535,wA=65535&rA,t^=63&I|128),i=343*e,n=343*a,o=343*h,w=343*f,D=343*c,y=343*F,M=343*u,p=343*l,H=343*G,U=343*d,m=343*L,J=343*k,N=343*b,R=343*S,v=343*Y,P=343*q,x=343*X,Z=343*V,K=343*W,O=343*j,z=343*T,_=343*$,AA=343*IA,gA=343*CA,QA=343*BA,tA=343*iA,EA=343*eA,nA=343*aA,oA=343*hA,rA=343*wA,sA=343*fA,z+=t<<8,_+=e<<8,AA+=a<<8,gA+=h<<8,QA+=f<<8,tA+=c<<8,EA+=F<<8,nA+=u<<8,oA+=l<<8,rA+=G<<8,sA+=d<<8,t=65535&(B=343*t),e=65535&(i+=B>>>16),a=65535&(n+=i>>>16),h=65535&(o+=n>>>16),f=65535&(w+=o>>>16),c=65535&(D+=w>>>16),F=65535&(y+=D>>>16),u=65535&(M+=y>>>16),l=65535&(p+=M>>>16),G=65535&(H+=p>>>16),d=65535&(U+=H>>>16),L=65535&(m+=U>>>16),k=65535&(J+=m>>>16),b=65535&(N+=J>>>16),S=65535&(R+=N>>>16),Y=65535&(v+=R>>>16),q=65535&(P+=v>>>16),X=65535&(x+=P>>>16),V=65535&(Z+=x>>>16),W=65535&(K+=Z>>>16),j=65535&(O+=K>>>16),T=65535&(z+=O>>>16),$=65535&(_+=z>>>16),IA=65535&(AA+=_>>>16),CA=65535&(gA+=AA>>>16),BA=65535&(QA+=gA>>>16),iA=65535&(tA+=QA>>>16),eA=65535&(EA+=tA>>>16),aA=65535&(nA+=EA>>>16),hA=65535&(oA+=nA>>>16),fA=sA+((rA+=oA>>>16)>>>16)&65535,wA=65535&rA;return s(E[fA>>8]+E[255&fA]+E[wA>>8]+E[255&wA]+E[hA>>8]+E[255&hA]+E[aA>>8]+E[255&aA]+E[eA>>8]+E[255&eA]+E[iA>>8]+E[255&iA]+E[BA>>8]+E[255&BA]+E[CA>>8]+E[255&CA]+E[IA>>8]+E[255&IA]+E[$>>8]+E[255&$]+E[T>>8]+E[255&T]+E[j>>8]+E[255&j]+E[W>>8]+E[255&W]+E[V>>8]+E[255&V]+E[X>>8]+E[255&X]+E[q>>8]+E[255&q]+E[Y>>8]+E[255&Y]+E[S>>8]+E[255&S]+E[b>>8]+E[255&b]+E[k>>8]+E[255&k]+E[L>>8]+E[255&L]+E[d>>8]+E[255&d]+E[G>>8]+E[255&G]+E[l>>8]+E[255&l]+E[u>>8]+E[255&u]+E[F>>8]+E[255&F]+E[c>>8]+E[255&c]+E[f>>8]+E[255&f]+E[h>>8]+E[255&h]+E[a>>8]+E[255&a]+E[e>>8]+E[255&e]+E[t>>8]+E[255&t],512)}function K(A){var I,g,C=A.length,Q=r[512].offset,B=0,t=0|Q[31],i=0,e=0|Q[30],n=0,a=0|Q[29],o=0,h=0|Q[28],w=0,f=0|Q[27],D=0,c=0|Q[26],y=0,F=0|Q[25],M=0,u=0|Q[24],p=0,l=0|Q[23],H=0,G=0|Q[22],U=0,d=0|Q[21],m=0,L=0|Q[20],J=0,k=0|Q[19],N=0,b=0|Q[18],R=0,S=0|Q[17],v=0,Y=0|Q[16],P=0,q=0|Q[15],x=0,X=0|Q[14],Z=0,V=0|Q[13],K=0,W=0|Q[12],O=0,j=0|Q[11],z=0,T=0|Q[10],_=0,$=0|Q[9],AA=0,IA=0|Q[8],gA=0,CA=0|Q[7],QA=0,BA=0|Q[6],tA=0,iA=0|Q[5],EA=0,eA=0|Q[4],nA=0,aA=0|Q[3],oA=0,hA=0|Q[2],rA=0,wA=0|Q[1],sA=0,fA=0|Q[0];for(g=0;g>>16),a=65535&(n+=i>>>16),h=65535&(o+=n>>>16),f=65535&(w+=o>>>16),c=65535&(D+=w>>>16),F=65535&(y+=D>>>16),u=65535&(M+=y>>>16),l=65535&(p+=M>>>16),G=65535&(H+=p>>>16),d=65535&(U+=H>>>16),L=65535&(m+=U>>>16),k=65535&(J+=m>>>16),b=65535&(N+=J>>>16),S=65535&(R+=N>>>16),Y=65535&(v+=R>>>16),q=65535&(P+=v>>>16),X=65535&(x+=P>>>16),V=65535&(Z+=x>>>16),W=65535&(K+=Z>>>16),j=65535&(O+=K>>>16),T=65535&(z+=O>>>16),$=65535&(_+=z>>>16),IA=65535&(AA+=_>>>16),CA=65535&(gA+=AA>>>16),BA=65535&(QA+=gA>>>16),iA=65535&(tA+=QA>>>16),eA=65535&(EA+=tA>>>16),aA=65535&(nA+=EA>>>16),hA=65535&(oA+=nA>>>16),fA=sA+((rA+=oA>>>16)>>>16)&65535,wA=65535&rA,(I=A.charCodeAt(g))<128?t^=I:I<2048?(i=343*e,n=343*a,o=343*h,w=343*f,D=343*c,y=343*F,M=343*u,p=343*l,H=343*G,U=343*d,m=343*L,J=343*k,N=343*b,R=343*S,v=343*Y,P=343*q,x=343*X,Z=343*V,K=343*W,O=343*j,z=343*T,_=343*$,AA=343*IA,gA=343*CA,QA=343*BA,tA=343*iA,EA=343*eA,nA=343*aA,oA=343*hA,rA=343*wA,sA=343*fA,z+=(t^=I>>6|192)<<8,_+=e<<8,AA+=a<<8,gA+=h<<8,QA+=f<<8,tA+=c<<8,EA+=F<<8,nA+=u<<8,oA+=l<<8,rA+=G<<8,sA+=d<<8,t=65535&(B=343*t),e=65535&(i+=B>>>16),a=65535&(n+=i>>>16),h=65535&(o+=n>>>16),f=65535&(w+=o>>>16),c=65535&(D+=w>>>16),F=65535&(y+=D>>>16),u=65535&(M+=y>>>16),l=65535&(p+=M>>>16),G=65535&(H+=p>>>16),d=65535&(U+=H>>>16),L=65535&(m+=U>>>16),k=65535&(J+=m>>>16),b=65535&(N+=J>>>16),S=65535&(R+=N>>>16),Y=65535&(v+=R>>>16),q=65535&(P+=v>>>16),X=65535&(x+=P>>>16),V=65535&(Z+=x>>>16),W=65535&(K+=Z>>>16),j=65535&(O+=K>>>16),T=65535&(z+=O>>>16),$=65535&(_+=z>>>16),IA=65535&(AA+=_>>>16),CA=65535&(gA+=AA>>>16),BA=65535&(QA+=gA>>>16),iA=65535&(tA+=QA>>>16),eA=65535&(EA+=tA>>>16),aA=65535&(nA+=EA>>>16),hA=65535&(oA+=nA>>>16),fA=sA+((rA+=oA>>>16)>>>16)&65535,wA=65535&rA,t^=63&I|128):55296==(64512&I)&&g+1>18|240)<<8,_+=e<<8,AA+=a<<8,gA+=h<<8,QA+=f<<8,tA+=c<<8,EA+=F<<8,nA+=u<<8,oA+=l<<8,rA+=G<<8,t=65535&(B=343*t),fA=(sA+=d<<8)+((rA+=(oA+=(nA+=(EA+=(tA+=(QA+=(gA+=(AA+=(_+=(z+=(O+=(K+=(Z+=(x+=(P+=(v+=(R+=(N+=(J+=(m+=(U+=(H+=(p+=(M+=(y+=(D+=(w+=(o+=(n+=(i+=B>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)&65535,i=343*(e=65535&i),n=343*(a=65535&n),o=343*(h=65535&o),w=343*(f=65535&w),D=343*(c=65535&D),y=343*(F=65535&y),M=343*(u=65535&M),p=343*(l=65535&p),H=343*(G=65535&H),U=343*(d=65535&U),m=343*(L=65535&m),J=343*(k=65535&J),N=343*(b=65535&N),R=343*(S=65535&R),v=343*(Y=65535&v),P=343*(q=65535&P),x=343*(X=65535&x),Z=343*(V=65535&Z),K=343*(W=65535&K),O=343*(j=65535&O),z=343*(T=65535&z),_=343*($=65535&_),AA=343*(IA=65535&AA),gA=343*(CA=65535&gA),QA=343*(BA=65535&QA),tA=343*(iA=65535&tA),EA=343*(eA=65535&EA),nA=343*(aA=65535&nA),oA=343*(hA=65535&oA),rA=343*(wA=65535&rA),sA=343*fA,z+=(t^=I>>12&63|128)<<8,_+=e<<8,AA+=a<<8,gA+=h<<8,QA+=f<<8,tA+=c<<8,EA+=F<<8,nA+=u<<8,oA+=l<<8,rA+=G<<8,t=65535&(B=343*t),fA=(sA+=d<<8)+((rA+=(oA+=(nA+=(EA+=(tA+=(QA+=(gA+=(AA+=(_+=(z+=(O+=(K+=(Z+=(x+=(P+=(v+=(R+=(N+=(J+=(m+=(U+=(H+=(p+=(M+=(y+=(D+=(w+=(o+=(n+=(i+=B>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)&65535,i=343*(e=65535&i),n=343*(a=65535&n),o=343*(h=65535&o),w=343*(f=65535&w),D=343*(c=65535&D),y=343*(F=65535&y),M=343*(u=65535&M),p=343*(l=65535&p),H=343*(G=65535&H),U=343*(d=65535&U),m=343*(L=65535&m),J=343*(k=65535&J),N=343*(b=65535&N),R=343*(S=65535&R),v=343*(Y=65535&v),P=343*(q=65535&P),x=343*(X=65535&x),Z=343*(V=65535&Z),K=343*(W=65535&K),O=343*(j=65535&O),z=343*(T=65535&z),_=343*($=65535&_),AA=343*(IA=65535&AA),gA=343*(CA=65535&gA),QA=343*(BA=65535&QA),tA=343*(iA=65535&tA),EA=343*(eA=65535&EA),nA=343*(aA=65535&nA),oA=343*(hA=65535&oA),rA=343*(wA=65535&rA),sA=343*fA,z+=(t^=I>>6&63|128)<<8,_+=e<<8,AA+=a<<8,gA+=h<<8,QA+=f<<8,tA+=c<<8,EA+=F<<8,nA+=u<<8,oA+=l<<8,rA+=G<<8,sA+=d<<8,t=65535&(B=343*t),e=65535&(i+=B>>>16),a=65535&(n+=i>>>16),h=65535&(o+=n>>>16),f=65535&(w+=o>>>16),c=65535&(D+=w>>>16),F=65535&(y+=D>>>16),u=65535&(M+=y>>>16),l=65535&(p+=M>>>16),G=65535&(H+=p>>>16),d=65535&(U+=H>>>16),L=65535&(m+=U>>>16),k=65535&(J+=m>>>16),b=65535&(N+=J>>>16),S=65535&(R+=N>>>16),Y=65535&(v+=R>>>16),q=65535&(P+=v>>>16),X=65535&(x+=P>>>16),V=65535&(Z+=x>>>16),W=65535&(K+=Z>>>16),j=65535&(O+=K>>>16),T=65535&(z+=O>>>16),$=65535&(_+=z>>>16),IA=65535&(AA+=_>>>16),CA=65535&(gA+=AA>>>16),BA=65535&(QA+=gA>>>16),iA=65535&(tA+=QA>>>16),eA=65535&(EA+=tA>>>16),aA=65535&(nA+=EA>>>16),hA=65535&(oA+=nA>>>16),fA=sA+((rA+=oA>>>16)>>>16)&65535,wA=65535&rA,t^=63&I|128):(i=343*e,n=343*a,o=343*h,w=343*f,D=343*c,y=343*F,M=343*u,p=343*l,H=343*G,U=343*d,m=343*L,J=343*k,N=343*b,R=343*S,v=343*Y,P=343*q,x=343*X,Z=343*V,K=343*W,O=343*j,z=343*T,_=343*$,AA=343*IA,gA=343*CA,QA=343*BA,tA=343*iA,EA=343*eA,nA=343*aA,oA=343*hA,rA=343*wA,sA=343*fA,z+=(t^=I>>12|224)<<8,_+=e<<8,AA+=a<<8,gA+=h<<8,QA+=f<<8,tA+=c<<8,EA+=F<<8,nA+=u<<8,oA+=l<<8,rA+=G<<8,t=65535&(B=343*t),fA=(sA+=d<<8)+((rA+=(oA+=(nA+=(EA+=(tA+=(QA+=(gA+=(AA+=(_+=(z+=(O+=(K+=(Z+=(x+=(P+=(v+=(R+=(N+=(J+=(m+=(U+=(H+=(p+=(M+=(y+=(D+=(w+=(o+=(n+=(i+=B>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)&65535,i=343*(e=65535&i),n=343*(a=65535&n),o=343*(h=65535&o),w=343*(f=65535&w),D=343*(c=65535&D),y=343*(F=65535&y),M=343*(u=65535&M),p=343*(l=65535&p),H=343*(G=65535&H),U=343*(d=65535&U),m=343*(L=65535&m),J=343*(k=65535&J),N=343*(b=65535&N),R=343*(S=65535&R),v=343*(Y=65535&v),P=343*(q=65535&P),x=343*(X=65535&x),Z=343*(V=65535&Z),K=343*(W=65535&K),O=343*(j=65535&O),z=343*(T=65535&z),_=343*($=65535&_),AA=343*(IA=65535&AA),gA=343*(CA=65535&gA),QA=343*(BA=65535&QA),tA=343*(iA=65535&tA),EA=343*(eA=65535&EA),nA=343*(aA=65535&nA),oA=343*(hA=65535&oA),rA=343*(wA=65535&rA),sA=343*fA,z+=(t^=I>>6&63|128)<<8,_+=e<<8,AA+=a<<8,gA+=h<<8,QA+=f<<8,tA+=c<<8,EA+=F<<8,nA+=u<<8,oA+=l<<8,rA+=G<<8,sA+=d<<8,t=65535&(B=343*t),e=65535&(i+=B>>>16),a=65535&(n+=i>>>16),h=65535&(o+=n>>>16),f=65535&(w+=o>>>16),c=65535&(D+=w>>>16),F=65535&(y+=D>>>16),u=65535&(M+=y>>>16),l=65535&(p+=M>>>16),G=65535&(H+=p>>>16),d=65535&(U+=H>>>16),L=65535&(m+=U>>>16),k=65535&(J+=m>>>16),b=65535&(N+=J>>>16),S=65535&(R+=N>>>16),Y=65535&(v+=R>>>16),q=65535&(P+=v>>>16),X=65535&(x+=P>>>16),V=65535&(Z+=x>>>16),W=65535&(K+=Z>>>16),j=65535&(O+=K>>>16),T=65535&(z+=O>>>16),$=65535&(_+=z>>>16),IA=65535&(AA+=_>>>16),CA=65535&(gA+=AA>>>16),BA=65535&(QA+=gA>>>16),iA=65535&(tA+=QA>>>16),eA=65535&(EA+=tA>>>16),aA=65535&(nA+=EA>>>16),hA=65535&(oA+=nA>>>16),fA=sA+((rA+=oA>>>16)>>>16)&65535,wA=65535&rA,t^=63&I|128);return s(E[fA>>8]+E[255&fA]+E[wA>>8]+E[255&wA]+E[hA>>8]+E[255&hA]+E[aA>>8]+E[255&aA]+E[eA>>8]+E[255&eA]+E[iA>>8]+E[255&iA]+E[BA>>8]+E[255&BA]+E[CA>>8]+E[255&CA]+E[IA>>8]+E[255&IA]+E[$>>8]+E[255&$]+E[T>>8]+E[255&T]+E[j>>8]+E[255&j]+E[W>>8]+E[255&W]+E[V>>8]+E[255&V]+E[X>>8]+E[255&X]+E[q>>8]+E[255&q]+E[Y>>8]+E[255&Y]+E[S>>8]+E[255&S]+E[b>>8]+E[255&b]+E[k>>8]+E[255&k]+E[L>>8]+E[255&L]+E[d>>8]+E[255&d]+E[G>>8]+E[255&G]+E[l>>8]+E[255&l]+E[u>>8]+E[255&u]+E[F>>8]+E[255&F]+E[c>>8]+E[255&c]+E[f>>8]+E[255&f]+E[h>>8]+E[255&h]+E[a>>8]+E[255&a]+E[e>>8]+E[255&e]+E[t>>8]+E[255&t],512)}function W(A){var I,g=A.length-3,C=r[1024].offset,Q=0,B=0|C[63],t=0,i=0|C[62],e=0,n=0|C[61],a=0,o=0|C[60],h=0,w=0|C[59],f=0,D=0|C[58],c=0,y=0|C[57],F=0,M=0|C[56],u=0,p=0|C[55],l=0,H=0|C[54],G=0,U=0|C[53],d=0,m=0|C[52],L=0,J=0|C[51],k=0,N=0|C[50],b=0,R=0|C[49],S=0,v=0|C[48],Y=0,P=0|C[47],q=0,x=0|C[46],X=0,Z=0|C[45],V=0,K=0|C[44],W=0,O=0|C[43],j=0,z=0|C[42],T=0,_=0|C[41],$=0,AA=0|C[40],IA=0,gA=0|C[39],CA=0,QA=0|C[38],BA=0,tA=0|C[37],iA=0,EA=0|C[36],eA=0,nA=0|C[35],aA=0,oA=0|C[34],hA=0,rA=0|C[33],wA=0,sA=0|C[32],fA=0,DA=0|C[31],cA=0,yA=0|C[30],FA=0,MA=0|C[29],uA=0,pA=0|C[28],lA=0,HA=0|C[27],GA=0,UA=0|C[26],dA=0,mA=0|C[25],LA=0,JA=0|C[24],kA=0,NA=0|C[23],bA=0,RA=0|C[22],SA=0,vA=0|C[21],YA=0,PA=0|C[20],qA=0,xA=0|C[19],XA=0,ZA=0|C[18],VA=0,KA=0|C[17],WA=0,OA=0|C[16],jA=0,zA=0|C[15],TA=0,_A=0|C[14],$A=0,AI=0|C[13],II=0,gI=0|C[12],CI=0,QI=0|C[11],BI=0,tI=0|C[10],iI=0,EI=0|C[9],eI=0,nI=0|C[8],aI=0,oI=0|C[7],hI=0,rI=0|C[6],wI=0,sI=0|C[5],fI=0,DI=0|C[4],cI=0,yI=0|C[3],FI=0,MI=0|C[2],uI=0,pI=0|C[1],lI=0,HI=0|C[0];for(I=0;I>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)&65535,t=397*(i=65535&t),e=397*(n=65535&e),a=397*(o=65535&a),h=397*(w=65535&h),f=397*(D=65535&f),c=397*(y=65535&c),F=397*(M=65535&F),u=397*(p=65535&u),l=397*(H=65535&l),G=397*(U=65535&G),d=397*(m=65535&d),L=397*(J=65535&L),k=397*(N=65535&k),b=397*(R=65535&b),S=397*(v=65535&S),Y=397*(P=65535&Y),q=397*(x=65535&q),X=397*(Z=65535&X),V=397*(K=65535&V),W=397*(O=65535&W),j=397*(z=65535&j),T=397*(_=65535&T),$=397*(AA=65535&$),IA=397*(gA=65535&IA),CA=397*(QA=65535&CA),BA=397*(tA=65535&BA),iA=397*(EA=65535&iA),eA=397*(nA=65535&eA),aA=397*(oA=65535&aA),hA=397*(rA=65535&hA),wA=397*(sA=65535&wA),fA=397*(DA=65535&fA),cA=397*(yA=65535&cA),FA=397*(MA=65535&FA),uA=397*(pA=65535&uA),lA=397*(HA=65535&lA),GA=397*(UA=65535&GA),dA=397*(mA=65535&dA),LA=397*(JA=65535&LA),kA=397*(NA=65535&kA),bA=397*(RA=65535&bA),SA=397*(vA=65535&SA),YA=397*(PA=65535&YA),qA=397*(xA=65535&qA),XA=397*(ZA=65535&XA),VA=397*(KA=65535&VA),WA=397*(OA=65535&WA),jA=397*(zA=65535&jA),TA=397*(_A=65535&TA),$A=397*(AI=65535&$A),II=397*(gI=65535&II),CI=397*(QI=65535&CI),BI=397*(tI=65535&BI),iI=397*(EI=65535&iI),eI=397*(nI=65535&eI),aI=397*(oI=65535&aI),hI=397*(rI=65535&hI),wI=397*(sI=65535&wI),fI=397*(DI=65535&fI),cI=397*(yI=65535&cI),FI=397*(MI=65535&FI),uI=397*(pI=65535&uI),lI=397*HI,SA+=(B^=A.charCodeAt(I++))<<8,YA+=i<<8,qA+=n<<8,XA+=o<<8,VA+=w<<8,WA+=D<<8,jA+=y<<8,TA+=M<<8,$A+=p<<8,II+=H<<8,CI+=U<<8,BI+=m<<8,iI+=J<<8,eI+=N<<8,aI+=R<<8,hI+=v<<8,wI+=P<<8,fI+=x<<8,cI+=Z<<8,FI+=K<<8,uI+=O<<8,B=65535&(Q=397*B),HI=(lI+=z<<8)+((uI+=(FI+=(cI+=(fI+=(wI+=(hI+=(aI+=(eI+=(iI+=(BI+=(CI+=(II+=($A+=(TA+=(jA+=(WA+=(VA+=(XA+=(qA+=(YA+=(SA+=(bA+=(kA+=(LA+=(dA+=(GA+=(lA+=(uA+=(FA+=(cA+=(fA+=(wA+=(hA+=(aA+=(eA+=(iA+=(BA+=(CA+=(IA+=($+=(T+=(j+=(W+=(V+=(X+=(q+=(Y+=(S+=(b+=(k+=(L+=(d+=(G+=(l+=(u+=(F+=(c+=(f+=(h+=(a+=(e+=(t+=Q>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)&65535,t=397*(i=65535&t),e=397*(n=65535&e),a=397*(o=65535&a),h=397*(w=65535&h),f=397*(D=65535&f),c=397*(y=65535&c),F=397*(M=65535&F),u=397*(p=65535&u),l=397*(H=65535&l),G=397*(U=65535&G),d=397*(m=65535&d),L=397*(J=65535&L),k=397*(N=65535&k),b=397*(R=65535&b),S=397*(v=65535&S),Y=397*(P=65535&Y),q=397*(x=65535&q),X=397*(Z=65535&X),V=397*(K=65535&V),W=397*(O=65535&W),j=397*(z=65535&j),T=397*(_=65535&T),$=397*(AA=65535&$),IA=397*(gA=65535&IA),CA=397*(QA=65535&CA),BA=397*(tA=65535&BA),iA=397*(EA=65535&iA),eA=397*(nA=65535&eA),aA=397*(oA=65535&aA),hA=397*(rA=65535&hA),wA=397*(sA=65535&wA),fA=397*(DA=65535&fA),cA=397*(yA=65535&cA),FA=397*(MA=65535&FA),uA=397*(pA=65535&uA),lA=397*(HA=65535&lA),GA=397*(UA=65535&GA),dA=397*(mA=65535&dA),LA=397*(JA=65535&LA),kA=397*(NA=65535&kA),bA=397*(RA=65535&bA),SA=397*(vA=65535&SA),YA=397*(PA=65535&YA),qA=397*(xA=65535&qA),XA=397*(ZA=65535&XA),VA=397*(KA=65535&VA),WA=397*(OA=65535&WA),jA=397*(zA=65535&jA),TA=397*(_A=65535&TA),$A=397*(AI=65535&$A),II=397*(gI=65535&II),CI=397*(QI=65535&CI),BI=397*(tI=65535&BI),iI=397*(EI=65535&iI),eI=397*(nI=65535&eI),aI=397*(oI=65535&aI),hI=397*(rI=65535&hI),wI=397*(sI=65535&wI),fI=397*(DI=65535&fI),cI=397*(yI=65535&cI),FI=397*(MI=65535&FI),uI=397*(pI=65535&uI),lI=397*HI,SA+=(B^=A.charCodeAt(I++))<<8,YA+=i<<8,qA+=n<<8,XA+=o<<8,VA+=w<<8,WA+=D<<8,jA+=y<<8,TA+=M<<8,$A+=p<<8,II+=H<<8,CI+=U<<8,BI+=m<<8,iI+=J<<8,eI+=N<<8,aI+=R<<8,hI+=v<<8,wI+=P<<8,fI+=x<<8,cI+=Z<<8,FI+=K<<8,uI+=O<<8,B=65535&(Q=397*B),HI=(lI+=z<<8)+((uI+=(FI+=(cI+=(fI+=(wI+=(hI+=(aI+=(eI+=(iI+=(BI+=(CI+=(II+=($A+=(TA+=(jA+=(WA+=(VA+=(XA+=(qA+=(YA+=(SA+=(bA+=(kA+=(LA+=(dA+=(GA+=(lA+=(uA+=(FA+=(cA+=(fA+=(wA+=(hA+=(aA+=(eA+=(iA+=(BA+=(CA+=(IA+=($+=(T+=(j+=(W+=(V+=(X+=(q+=(Y+=(S+=(b+=(k+=(L+=(d+=(G+=(l+=(u+=(F+=(c+=(f+=(h+=(a+=(e+=(t+=Q>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)&65535,t=397*(i=65535&t),e=397*(n=65535&e),a=397*(o=65535&a),h=397*(w=65535&h),f=397*(D=65535&f),c=397*(y=65535&c),F=397*(M=65535&F),u=397*(p=65535&u),l=397*(H=65535&l),G=397*(U=65535&G),d=397*(m=65535&d),L=397*(J=65535&L),k=397*(N=65535&k),b=397*(R=65535&b),S=397*(v=65535&S),Y=397*(P=65535&Y),q=397*(x=65535&q),X=397*(Z=65535&X),V=397*(K=65535&V),W=397*(O=65535&W),j=397*(z=65535&j),T=397*(_=65535&T),$=397*(AA=65535&$),IA=397*(gA=65535&IA),CA=397*(QA=65535&CA),BA=397*(tA=65535&BA),iA=397*(EA=65535&iA),eA=397*(nA=65535&eA),aA=397*(oA=65535&aA),hA=397*(rA=65535&hA),wA=397*(sA=65535&wA),fA=397*(DA=65535&fA),cA=397*(yA=65535&cA),FA=397*(MA=65535&FA),uA=397*(pA=65535&uA),lA=397*(HA=65535&lA),GA=397*(UA=65535&GA),dA=397*(mA=65535&dA),LA=397*(JA=65535&LA),kA=397*(NA=65535&kA),bA=397*(RA=65535&bA),SA=397*(vA=65535&SA),YA=397*(PA=65535&YA),qA=397*(xA=65535&qA),XA=397*(ZA=65535&XA),VA=397*(KA=65535&VA),WA=397*(OA=65535&WA),jA=397*(zA=65535&jA),TA=397*(_A=65535&TA),$A=397*(AI=65535&$A),II=397*(gI=65535&II),CI=397*(QI=65535&CI),BI=397*(tI=65535&BI),iI=397*(EI=65535&iI),eI=397*(nI=65535&eI),aI=397*(oI=65535&aI),hI=397*(rI=65535&hI),wI=397*(sI=65535&wI),fI=397*(DI=65535&fI),cI=397*(yI=65535&cI),FI=397*(MI=65535&FI),uI=397*(pI=65535&uI),lI=397*HI,SA+=(B^=A.charCodeAt(I++))<<8,YA+=i<<8,qA+=n<<8,XA+=o<<8,VA+=w<<8,WA+=D<<8,jA+=y<<8,TA+=M<<8,$A+=p<<8,II+=H<<8,CI+=U<<8,BI+=m<<8,iI+=J<<8,eI+=N<<8,aI+=R<<8,hI+=v<<8,wI+=P<<8,fI+=x<<8,cI+=Z<<8,FI+=K<<8,uI+=O<<8,lI+=z<<8,B=65535&(Q=397*B),i=65535&(t+=Q>>>16),n=65535&(e+=t>>>16),o=65535&(a+=e>>>16),w=65535&(h+=a>>>16),D=65535&(f+=h>>>16),y=65535&(c+=f>>>16),M=65535&(F+=c>>>16),p=65535&(u+=F>>>16),H=65535&(l+=u>>>16),U=65535&(G+=l>>>16),m=65535&(d+=G>>>16),J=65535&(L+=d>>>16),N=65535&(k+=L>>>16),R=65535&(b+=k>>>16),v=65535&(S+=b>>>16),P=65535&(Y+=S>>>16),x=65535&(q+=Y>>>16),Z=65535&(X+=q>>>16),K=65535&(V+=X>>>16),O=65535&(W+=V>>>16),z=65535&(j+=W>>>16),_=65535&(T+=j>>>16),AA=65535&($+=T>>>16),gA=65535&(IA+=$>>>16),QA=65535&(CA+=IA>>>16),tA=65535&(BA+=CA>>>16),EA=65535&(iA+=BA>>>16),nA=65535&(eA+=iA>>>16),oA=65535&(aA+=eA>>>16),rA=65535&(hA+=aA>>>16),sA=65535&(wA+=hA>>>16),DA=65535&(fA+=wA>>>16),yA=65535&(cA+=fA>>>16),MA=65535&(FA+=cA>>>16),pA=65535&(uA+=FA>>>16),HA=65535&(lA+=uA>>>16),UA=65535&(GA+=lA>>>16),mA=65535&(dA+=GA>>>16),JA=65535&(LA+=dA>>>16),NA=65535&(kA+=LA>>>16),RA=65535&(bA+=kA>>>16),vA=65535&(SA+=bA>>>16),PA=65535&(YA+=SA>>>16),xA=65535&(qA+=YA>>>16),ZA=65535&(XA+=qA>>>16),KA=65535&(VA+=XA>>>16),OA=65535&(WA+=VA>>>16),zA=65535&(jA+=WA>>>16),_A=65535&(TA+=jA>>>16),AI=65535&($A+=TA>>>16),gI=65535&(II+=$A>>>16),QI=65535&(CI+=II>>>16),tI=65535&(BI+=CI>>>16),EI=65535&(iI+=BI>>>16),nI=65535&(eI+=iI>>>16),oI=65535&(aI+=eI>>>16),rI=65535&(hI+=aI>>>16),sI=65535&(wI+=hI>>>16),DI=65535&(fI+=wI>>>16),yI=65535&(cI+=fI>>>16),MI=65535&(FI+=cI>>>16),HI=lI+((uI+=FI>>>16)>>>16)&65535,pI=65535&uI;for(;I>>16),n=65535&(e+=t>>>16),o=65535&(a+=e>>>16),w=65535&(h+=a>>>16),D=65535&(f+=h>>>16),y=65535&(c+=f>>>16),M=65535&(F+=c>>>16),p=65535&(u+=F>>>16),H=65535&(l+=u>>>16),U=65535&(G+=l>>>16),m=65535&(d+=G>>>16),J=65535&(L+=d>>>16),N=65535&(k+=L>>>16),R=65535&(b+=k>>>16),v=65535&(S+=b>>>16),P=65535&(Y+=S>>>16),x=65535&(q+=Y>>>16),Z=65535&(X+=q>>>16),K=65535&(V+=X>>>16),O=65535&(W+=V>>>16),z=65535&(j+=W>>>16),_=65535&(T+=j>>>16),AA=65535&($+=T>>>16),gA=65535&(IA+=$>>>16),QA=65535&(CA+=IA>>>16),tA=65535&(BA+=CA>>>16),EA=65535&(iA+=BA>>>16),nA=65535&(eA+=iA>>>16),oA=65535&(aA+=eA>>>16),rA=65535&(hA+=aA>>>16),sA=65535&(wA+=hA>>>16),DA=65535&(fA+=wA>>>16),yA=65535&(cA+=fA>>>16),MA=65535&(FA+=cA>>>16),pA=65535&(uA+=FA>>>16),HA=65535&(lA+=uA>>>16),UA=65535&(GA+=lA>>>16),mA=65535&(dA+=GA>>>16),JA=65535&(LA+=dA>>>16),NA=65535&(kA+=LA>>>16),RA=65535&(bA+=kA>>>16),vA=65535&(SA+=bA>>>16),PA=65535&(YA+=SA>>>16),xA=65535&(qA+=YA>>>16),ZA=65535&(XA+=qA>>>16),KA=65535&(VA+=XA>>>16),OA=65535&(WA+=VA>>>16),zA=65535&(jA+=WA>>>16),_A=65535&(TA+=jA>>>16),AI=65535&($A+=TA>>>16),gI=65535&(II+=$A>>>16),QI=65535&(CI+=II>>>16),tI=65535&(BI+=CI>>>16),EI=65535&(iI+=BI>>>16),nI=65535&(eI+=iI>>>16),oI=65535&(aI+=eI>>>16),rI=65535&(hI+=aI>>>16),sI=65535&(wI+=hI>>>16),DI=65535&(fI+=wI>>>16),yI=65535&(cI+=fI>>>16),MI=65535&(FI+=cI>>>16),HI=lI+((uI+=FI>>>16)>>>16)&65535,pI=65535&uI;return s(E[HI>>8]+E[255&HI]+E[pI>>8]+E[255&pI]+E[MI>>8]+E[255&MI]+E[yI>>8]+E[255&yI]+E[DI>>8]+E[255&DI]+E[sI>>8]+E[255&sI]+E[rI>>8]+E[255&rI]+E[oI>>8]+E[255&oI]+E[nI>>8]+E[255&nI]+E[EI>>8]+E[255&EI]+E[tI>>8]+E[255&tI]+E[QI>>8]+E[255&QI]+E[gI>>8]+E[255&gI]+E[AI>>8]+E[255&AI]+E[_A>>8]+E[255&_A]+E[zA>>8]+E[255&zA]+E[OA>>8]+E[255&OA]+E[KA>>8]+E[255&KA]+E[ZA>>8]+E[255&ZA]+E[xA>>8]+E[255&xA]+E[PA>>8]+E[255&PA]+E[vA>>8]+E[255&vA]+E[RA>>8]+E[255&RA]+E[NA>>8]+E[255&NA]+E[JA>>8]+E[255&JA]+E[mA>>8]+E[255&mA]+E[UA>>8]+E[255&UA]+E[HA>>8]+E[255&HA]+E[pA>>8]+E[255&pA]+E[MA>>8]+E[255&MA]+E[yA>>8]+E[255&yA]+E[DA>>8]+E[255&DA]+E[sA>>8]+E[255&sA]+E[rA>>8]+E[255&rA]+E[oA>>8]+E[255&oA]+E[nA>>8]+E[255&nA]+E[EA>>8]+E[255&EA]+E[tA>>8]+E[255&tA]+E[QA>>8]+E[255&QA]+E[gA>>8]+E[255&gA]+E[AA>>8]+E[255&AA]+E[_>>8]+E[255&_]+E[z>>8]+E[255&z]+E[O>>8]+E[255&O]+E[K>>8]+E[255&K]+E[Z>>8]+E[255&Z]+E[x>>8]+E[255&x]+E[P>>8]+E[255&P]+E[v>>8]+E[255&v]+E[R>>8]+E[255&R]+E[N>>8]+E[255&N]+E[J>>8]+E[255&J]+E[m>>8]+E[255&m]+E[U>>8]+E[255&U]+E[H>>8]+E[255&H]+E[p>>8]+E[255&p]+E[M>>8]+E[255&M]+E[y>>8]+E[255&y]+E[D>>8]+E[255&D]+E[w>>8]+E[255&w]+E[o>>8]+E[255&o]+E[n>>8]+E[255&n]+E[i>>8]+E[255&i]+E[B>>8]+E[255&B],1024)}function O(A){var I,g=A.length-3,C=r[1024].offset,Q=0,B=0|C[63],t=0,i=0|C[62],e=0,n=0|C[61],a=0,o=0|C[60],h=0,w=0|C[59],f=0,D=0|C[58],c=0,y=0|C[57],F=0,M=0|C[56],u=0,p=0|C[55],l=0,H=0|C[54],G=0,U=0|C[53],d=0,m=0|C[52],L=0,J=0|C[51],k=0,N=0|C[50],b=0,R=0|C[49],S=0,v=0|C[48],Y=0,P=0|C[47],q=0,x=0|C[46],X=0,Z=0|C[45],V=0,K=0|C[44],W=0,O=0|C[43],j=0,z=0|C[42],T=0,_=0|C[41],$=0,AA=0|C[40],IA=0,gA=0|C[39],CA=0,QA=0|C[38],BA=0,tA=0|C[37],iA=0,EA=0|C[36],eA=0,nA=0|C[35],aA=0,oA=0|C[34],hA=0,rA=0|C[33],wA=0,sA=0|C[32],fA=0,DA=0|C[31],cA=0,yA=0|C[30],FA=0,MA=0|C[29],uA=0,pA=0|C[28],lA=0,HA=0|C[27],GA=0,UA=0|C[26],dA=0,mA=0|C[25],LA=0,JA=0|C[24],kA=0,NA=0|C[23],bA=0,RA=0|C[22],SA=0,vA=0|C[21],YA=0,PA=0|C[20],qA=0,xA=0|C[19],XA=0,ZA=0|C[18],VA=0,KA=0|C[17],WA=0,OA=0|C[16],jA=0,zA=0|C[15],TA=0,_A=0|C[14],$A=0,AI=0|C[13],II=0,gI=0|C[12],CI=0,QI=0|C[11],BI=0,tI=0|C[10],iI=0,EI=0|C[9],eI=0,nI=0|C[8],aI=0,oI=0|C[7],hI=0,rI=0|C[6],wI=0,sI=0|C[5],fI=0,DI=0|C[4],cI=0,yI=0|C[3],FI=0,MI=0|C[2],uI=0,pI=0|C[1],lI=0,HI=0|C[0];for(I=0;I>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)&65535,t=397*(i=65535&t),e=397*(n=65535&e),a=397*(o=65535&a),h=397*(w=65535&h),f=397*(D=65535&f),c=397*(y=65535&c),F=397*(M=65535&F),u=397*(p=65535&u),l=397*(H=65535&l),G=397*(U=65535&G),d=397*(m=65535&d),L=397*(J=65535&L),k=397*(N=65535&k),b=397*(R=65535&b),S=397*(v=65535&S),Y=397*(P=65535&Y),q=397*(x=65535&q),X=397*(Z=65535&X),V=397*(K=65535&V),W=397*(O=65535&W),j=397*(z=65535&j),T=397*(_=65535&T),$=397*(AA=65535&$),IA=397*(gA=65535&IA),CA=397*(QA=65535&CA),BA=397*(tA=65535&BA),iA=397*(EA=65535&iA),eA=397*(nA=65535&eA),aA=397*(oA=65535&aA),hA=397*(rA=65535&hA),wA=397*(sA=65535&wA),fA=397*(DA=65535&fA),cA=397*(yA=65535&cA),FA=397*(MA=65535&FA),uA=397*(pA=65535&uA),lA=397*(HA=65535&lA),GA=397*(UA=65535&GA),dA=397*(mA=65535&dA),LA=397*(JA=65535&LA),kA=397*(NA=65535&kA),bA=397*(RA=65535&bA),SA=397*(vA=65535&SA),YA=397*(PA=65535&YA),qA=397*(xA=65535&qA),XA=397*(ZA=65535&XA),VA=397*(KA=65535&VA),WA=397*(OA=65535&WA),jA=397*(zA=65535&jA),TA=397*(_A=65535&TA),$A=397*(AI=65535&$A),II=397*(gI=65535&II),CI=397*(QI=65535&CI),BI=397*(tI=65535&BI),iI=397*(EI=65535&iI),eI=397*(nI=65535&eI),aI=397*(oI=65535&aI),hI=397*(rI=65535&hI),wI=397*(sI=65535&wI),fI=397*(DI=65535&fI),cI=397*(yI=65535&cI),FI=397*(MI=65535&FI),uI=397*(pI=65535&uI),lI=397*HI,SA+=(B^=A.charCodeAt(I++))<<8,YA+=i<<8,qA+=n<<8,XA+=o<<8,VA+=w<<8,WA+=D<<8,jA+=y<<8,TA+=M<<8,$A+=p<<8,II+=H<<8,CI+=U<<8,BI+=m<<8,iI+=J<<8,eI+=N<<8,aI+=R<<8,hI+=v<<8,wI+=P<<8,fI+=x<<8,cI+=Z<<8,FI+=K<<8,uI+=O<<8,B=65535&(Q=397*B),HI=(lI+=z<<8)+((uI+=(FI+=(cI+=(fI+=(wI+=(hI+=(aI+=(eI+=(iI+=(BI+=(CI+=(II+=($A+=(TA+=(jA+=(WA+=(VA+=(XA+=(qA+=(YA+=(SA+=(bA+=(kA+=(LA+=(dA+=(GA+=(lA+=(uA+=(FA+=(cA+=(fA+=(wA+=(hA+=(aA+=(eA+=(iA+=(BA+=(CA+=(IA+=($+=(T+=(j+=(W+=(V+=(X+=(q+=(Y+=(S+=(b+=(k+=(L+=(d+=(G+=(l+=(u+=(F+=(c+=(f+=(h+=(a+=(e+=(t+=Q>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)&65535,t=397*(i=65535&t),e=397*(n=65535&e),a=397*(o=65535&a),h=397*(w=65535&h),f=397*(D=65535&f),c=397*(y=65535&c),F=397*(M=65535&F),u=397*(p=65535&u),l=397*(H=65535&l),G=397*(U=65535&G),d=397*(m=65535&d),L=397*(J=65535&L),k=397*(N=65535&k),b=397*(R=65535&b),S=397*(v=65535&S),Y=397*(P=65535&Y),q=397*(x=65535&q),X=397*(Z=65535&X),V=397*(K=65535&V),W=397*(O=65535&W),j=397*(z=65535&j),T=397*(_=65535&T),$=397*(AA=65535&$),IA=397*(gA=65535&IA),CA=397*(QA=65535&CA),BA=397*(tA=65535&BA),iA=397*(EA=65535&iA),eA=397*(nA=65535&eA),aA=397*(oA=65535&aA),hA=397*(rA=65535&hA),wA=397*(sA=65535&wA),fA=397*(DA=65535&fA),cA=397*(yA=65535&cA),FA=397*(MA=65535&FA),uA=397*(pA=65535&uA),lA=397*(HA=65535&lA),GA=397*(UA=65535&GA),dA=397*(mA=65535&dA),LA=397*(JA=65535&LA),kA=397*(NA=65535&kA),bA=397*(RA=65535&bA),SA=397*(vA=65535&SA),YA=397*(PA=65535&YA),qA=397*(xA=65535&qA),XA=397*(ZA=65535&XA),VA=397*(KA=65535&VA),WA=397*(OA=65535&WA),jA=397*(zA=65535&jA),TA=397*(_A=65535&TA),$A=397*(AI=65535&$A),II=397*(gI=65535&II),CI=397*(QI=65535&CI),BI=397*(tI=65535&BI),iI=397*(EI=65535&iI),eI=397*(nI=65535&eI),aI=397*(oI=65535&aI),hI=397*(rI=65535&hI),wI=397*(sI=65535&wI),fI=397*(DI=65535&fI),cI=397*(yI=65535&cI),FI=397*(MI=65535&FI),uI=397*(pI=65535&uI),lI=397*HI,SA+=(B^=A.charCodeAt(I++))<<8,YA+=i<<8,qA+=n<<8,XA+=o<<8,VA+=w<<8,WA+=D<<8,jA+=y<<8,TA+=M<<8,$A+=p<<8,II+=H<<8,CI+=U<<8,BI+=m<<8,iI+=J<<8,eI+=N<<8,aI+=R<<8,hI+=v<<8,wI+=P<<8,fI+=x<<8,cI+=Z<<8,FI+=K<<8,uI+=O<<8,B=65535&(Q=397*B),HI=(lI+=z<<8)+((uI+=(FI+=(cI+=(fI+=(wI+=(hI+=(aI+=(eI+=(iI+=(BI+=(CI+=(II+=($A+=(TA+=(jA+=(WA+=(VA+=(XA+=(qA+=(YA+=(SA+=(bA+=(kA+=(LA+=(dA+=(GA+=(lA+=(uA+=(FA+=(cA+=(fA+=(wA+=(hA+=(aA+=(eA+=(iA+=(BA+=(CA+=(IA+=($+=(T+=(j+=(W+=(V+=(X+=(q+=(Y+=(S+=(b+=(k+=(L+=(d+=(G+=(l+=(u+=(F+=(c+=(f+=(h+=(a+=(e+=(t+=Q>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)&65535,t=397*(i=65535&t),e=397*(n=65535&e),a=397*(o=65535&a),h=397*(w=65535&h),f=397*(D=65535&f),c=397*(y=65535&c),F=397*(M=65535&F),u=397*(p=65535&u),l=397*(H=65535&l),G=397*(U=65535&G),d=397*(m=65535&d),L=397*(J=65535&L),k=397*(N=65535&k),b=397*(R=65535&b),S=397*(v=65535&S),Y=397*(P=65535&Y),q=397*(x=65535&q),X=397*(Z=65535&X),V=397*(K=65535&V),W=397*(O=65535&W),j=397*(z=65535&j),T=397*(_=65535&T),$=397*(AA=65535&$),IA=397*(gA=65535&IA),CA=397*(QA=65535&CA),BA=397*(tA=65535&BA),iA=397*(EA=65535&iA),eA=397*(nA=65535&eA),aA=397*(oA=65535&aA),hA=397*(rA=65535&hA),wA=397*(sA=65535&wA),fA=397*(DA=65535&fA),cA=397*(yA=65535&cA),FA=397*(MA=65535&FA),uA=397*(pA=65535&uA),lA=397*(HA=65535&lA),GA=397*(UA=65535&GA),dA=397*(mA=65535&dA),LA=397*(JA=65535&LA),kA=397*(NA=65535&kA),bA=397*(RA=65535&bA),SA=397*(vA=65535&SA),YA=397*(PA=65535&YA),qA=397*(xA=65535&qA),XA=397*(ZA=65535&XA),VA=397*(KA=65535&VA),WA=397*(OA=65535&WA),jA=397*(zA=65535&jA),TA=397*(_A=65535&TA),$A=397*(AI=65535&$A),II=397*(gI=65535&II),CI=397*(QI=65535&CI),BI=397*(tI=65535&BI),iI=397*(EI=65535&iI),eI=397*(nI=65535&eI),aI=397*(oI=65535&aI),hI=397*(rI=65535&hI),wI=397*(sI=65535&wI),fI=397*(DI=65535&fI),cI=397*(yI=65535&cI),FI=397*(MI=65535&FI),uI=397*(pI=65535&uI),lI=397*HI,SA+=(B^=A.charCodeAt(I++))<<8,YA+=i<<8,qA+=n<<8,XA+=o<<8,VA+=w<<8,WA+=D<<8,jA+=y<<8,TA+=M<<8,$A+=p<<8,II+=H<<8,CI+=U<<8,BI+=m<<8,iI+=J<<8,eI+=N<<8,aI+=R<<8,hI+=v<<8,wI+=P<<8,fI+=x<<8,cI+=Z<<8,FI+=K<<8,uI+=O<<8,lI+=z<<8,B=65535&(Q=397*B),i=65535&(t+=Q>>>16),n=65535&(e+=t>>>16),o=65535&(a+=e>>>16),w=65535&(h+=a>>>16),D=65535&(f+=h>>>16),y=65535&(c+=f>>>16),M=65535&(F+=c>>>16),p=65535&(u+=F>>>16),H=65535&(l+=u>>>16),U=65535&(G+=l>>>16),m=65535&(d+=G>>>16),J=65535&(L+=d>>>16),N=65535&(k+=L>>>16),R=65535&(b+=k>>>16),v=65535&(S+=b>>>16),P=65535&(Y+=S>>>16),x=65535&(q+=Y>>>16),Z=65535&(X+=q>>>16),K=65535&(V+=X>>>16),O=65535&(W+=V>>>16),z=65535&(j+=W>>>16),_=65535&(T+=j>>>16),AA=65535&($+=T>>>16),gA=65535&(IA+=$>>>16),QA=65535&(CA+=IA>>>16),tA=65535&(BA+=CA>>>16),EA=65535&(iA+=BA>>>16),nA=65535&(eA+=iA>>>16),oA=65535&(aA+=eA>>>16),rA=65535&(hA+=aA>>>16),sA=65535&(wA+=hA>>>16),DA=65535&(fA+=wA>>>16),yA=65535&(cA+=fA>>>16),MA=65535&(FA+=cA>>>16),pA=65535&(uA+=FA>>>16),HA=65535&(lA+=uA>>>16),UA=65535&(GA+=lA>>>16),mA=65535&(dA+=GA>>>16),JA=65535&(LA+=dA>>>16),NA=65535&(kA+=LA>>>16),RA=65535&(bA+=kA>>>16),vA=65535&(SA+=bA>>>16),PA=65535&(YA+=SA>>>16),xA=65535&(qA+=YA>>>16),ZA=65535&(XA+=qA>>>16),KA=65535&(VA+=XA>>>16),OA=65535&(WA+=VA>>>16),zA=65535&(jA+=WA>>>16),_A=65535&(TA+=jA>>>16),AI=65535&($A+=TA>>>16),gI=65535&(II+=$A>>>16),QI=65535&(CI+=II>>>16),tI=65535&(BI+=CI>>>16),EI=65535&(iI+=BI>>>16),nI=65535&(eI+=iI>>>16),oI=65535&(aI+=eI>>>16),rI=65535&(hI+=aI>>>16),sI=65535&(wI+=hI>>>16),DI=65535&(fI+=wI>>>16),yI=65535&(cI+=fI>>>16),MI=65535&(FI+=cI>>>16),HI=lI+((uI+=FI>>>16)>>>16)&65535,pI=65535&uI,B^=A.charCodeAt(I++);for(;I>>16),n=65535&(e+=t>>>16),o=65535&(a+=e>>>16),w=65535&(h+=a>>>16),D=65535&(f+=h>>>16),y=65535&(c+=f>>>16),M=65535&(F+=c>>>16),p=65535&(u+=F>>>16),H=65535&(l+=u>>>16),U=65535&(G+=l>>>16),m=65535&(d+=G>>>16),J=65535&(L+=d>>>16),N=65535&(k+=L>>>16),R=65535&(b+=k>>>16),v=65535&(S+=b>>>16),P=65535&(Y+=S>>>16),x=65535&(q+=Y>>>16),Z=65535&(X+=q>>>16),K=65535&(V+=X>>>16),O=65535&(W+=V>>>16),z=65535&(j+=W>>>16),_=65535&(T+=j>>>16),AA=65535&($+=T>>>16),gA=65535&(IA+=$>>>16),QA=65535&(CA+=IA>>>16),tA=65535&(BA+=CA>>>16),EA=65535&(iA+=BA>>>16),nA=65535&(eA+=iA>>>16),oA=65535&(aA+=eA>>>16),rA=65535&(hA+=aA>>>16),sA=65535&(wA+=hA>>>16),DA=65535&(fA+=wA>>>16),yA=65535&(cA+=fA>>>16),MA=65535&(FA+=cA>>>16),pA=65535&(uA+=FA>>>16),HA=65535&(lA+=uA>>>16),UA=65535&(GA+=lA>>>16),mA=65535&(dA+=GA>>>16),JA=65535&(LA+=dA>>>16),NA=65535&(kA+=LA>>>16),RA=65535&(bA+=kA>>>16),vA=65535&(SA+=bA>>>16),PA=65535&(YA+=SA>>>16),xA=65535&(qA+=YA>>>16),ZA=65535&(XA+=qA>>>16),KA=65535&(VA+=XA>>>16),OA=65535&(WA+=VA>>>16),zA=65535&(jA+=WA>>>16),_A=65535&(TA+=jA>>>16),AI=65535&($A+=TA>>>16),gI=65535&(II+=$A>>>16),QI=65535&(CI+=II>>>16),tI=65535&(BI+=CI>>>16),EI=65535&(iI+=BI>>>16),nI=65535&(eI+=iI>>>16),oI=65535&(aI+=eI>>>16),rI=65535&(hI+=aI>>>16),sI=65535&(wI+=hI>>>16),DI=65535&(fI+=wI>>>16),yI=65535&(cI+=fI>>>16),MI=65535&(FI+=cI>>>16),HI=lI+((uI+=FI>>>16)>>>16)&65535,pI=65535&uI,B^=A.charCodeAt(I++);return s(E[HI>>8]+E[255&HI]+E[pI>>8]+E[255&pI]+E[MI>>8]+E[255&MI]+E[yI>>8]+E[255&yI]+E[DI>>8]+E[255&DI]+E[sI>>8]+E[255&sI]+E[rI>>8]+E[255&rI]+E[oI>>8]+E[255&oI]+E[nI>>8]+E[255&nI]+E[EI>>8]+E[255&EI]+E[tI>>8]+E[255&tI]+E[QI>>8]+E[255&QI]+E[gI>>8]+E[255&gI]+E[AI>>8]+E[255&AI]+E[_A>>8]+E[255&_A]+E[zA>>8]+E[255&zA]+E[OA>>8]+E[255&OA]+E[KA>>8]+E[255&KA]+E[ZA>>8]+E[255&ZA]+E[xA>>8]+E[255&xA]+E[PA>>8]+E[255&PA]+E[vA>>8]+E[255&vA]+E[RA>>8]+E[255&RA]+E[NA>>8]+E[255&NA]+E[JA>>8]+E[255&JA]+E[mA>>8]+E[255&mA]+E[UA>>8]+E[255&UA]+E[HA>>8]+E[255&HA]+E[pA>>8]+E[255&pA]+E[MA>>8]+E[255&MA]+E[yA>>8]+E[255&yA]+E[DA>>8]+E[255&DA]+E[sA>>8]+E[255&sA]+E[rA>>8]+E[255&rA]+E[oA>>8]+E[255&oA]+E[nA>>8]+E[255&nA]+E[EA>>8]+E[255&EA]+E[tA>>8]+E[255&tA]+E[QA>>8]+E[255&QA]+E[gA>>8]+E[255&gA]+E[AA>>8]+E[255&AA]+E[_>>8]+E[255&_]+E[z>>8]+E[255&z]+E[O>>8]+E[255&O]+E[K>>8]+E[255&K]+E[Z>>8]+E[255&Z]+E[x>>8]+E[255&x]+E[P>>8]+E[255&P]+E[v>>8]+E[255&v]+E[R>>8]+E[255&R]+E[N>>8]+E[255&N]+E[J>>8]+E[255&J]+E[m>>8]+E[255&m]+E[U>>8]+E[255&U]+E[H>>8]+E[255&H]+E[p>>8]+E[255&p]+E[M>>8]+E[255&M]+E[y>>8]+E[255&y]+E[D>>8]+E[255&D]+E[w>>8]+E[255&w]+E[o>>8]+E[255&o]+E[n>>8]+E[255&n]+E[i>>8]+E[255&i]+E[B>>8]+E[255&B],1024)}function j(A){var I,g,C=A.length,Q=r[1024].offset,B=0,t=0|Q[63],i=0,e=0|Q[62],n=0,a=0|Q[61],o=0,h=0|Q[60],w=0,f=0|Q[59],D=0,c=0|Q[58],y=0,F=0|Q[57],M=0,u=0|Q[56],p=0,l=0|Q[55],H=0,G=0|Q[54],U=0,d=0|Q[53],m=0,L=0|Q[52],J=0,k=0|Q[51],N=0,b=0|Q[50],R=0,S=0|Q[49],v=0,Y=0|Q[48],P=0,q=0|Q[47],x=0,X=0|Q[46],Z=0,V=0|Q[45],K=0,W=0|Q[44],O=0,j=0|Q[43],z=0,T=0|Q[42],_=0,$=0|Q[41],AA=0,IA=0|Q[40],gA=0,CA=0|Q[39],QA=0,BA=0|Q[38],tA=0,iA=0|Q[37],EA=0,eA=0|Q[36],nA=0,aA=0|Q[35],oA=0,hA=0|Q[34],rA=0,wA=0|Q[33],sA=0,fA=0|Q[32],DA=0,cA=0|Q[31],yA=0,FA=0|Q[30],MA=0,uA=0|Q[29],pA=0,lA=0|Q[28],HA=0,GA=0|Q[27],UA=0,dA=0|Q[26],mA=0,LA=0|Q[25],JA=0,kA=0|Q[24],NA=0,bA=0|Q[23],RA=0,SA=0|Q[22],vA=0,YA=0|Q[21],PA=0,qA=0|Q[20],xA=0,XA=0|Q[19],ZA=0,VA=0|Q[18],KA=0,WA=0|Q[17],OA=0,jA=0|Q[16],zA=0,TA=0|Q[15],_A=0,$A=0|Q[14],AI=0,II=0|Q[13],gI=0,CI=0|Q[12],QI=0,BI=0|Q[11],tI=0,iI=0|Q[10],EI=0,eI=0|Q[9],nI=0,aI=0|Q[8],oI=0,hI=0|Q[7],rI=0,wI=0|Q[6],sI=0,fI=0|Q[5],DI=0,cI=0|Q[4],yI=0,FI=0|Q[3],MI=0,uI=0|Q[2],pI=0,lI=0|Q[1],HI=0,GI=0|Q[0];for(g=0;g>6|192)<<8,PA+=e<<8,xA+=a<<8,ZA+=h<<8,KA+=f<<8,OA+=c<<8,zA+=F<<8,_A+=u<<8,AI+=l<<8,gI+=G<<8,QI+=d<<8,tI+=L<<8,EI+=k<<8,nI+=b<<8,oI+=S<<8,rI+=Y<<8,sI+=q<<8,DI+=X<<8,yI+=V<<8,MI+=W<<8,pI+=j<<8,HI+=T<<8,t=65535&(B=397*t),e=65535&(i+=B>>>16),a=65535&(n+=i>>>16),h=65535&(o+=n>>>16),f=65535&(w+=o>>>16),c=65535&(D+=w>>>16),F=65535&(y+=D>>>16),u=65535&(M+=y>>>16),l=65535&(p+=M>>>16),G=65535&(H+=p>>>16),d=65535&(U+=H>>>16),L=65535&(m+=U>>>16),k=65535&(J+=m>>>16),b=65535&(N+=J>>>16),S=65535&(R+=N>>>16),Y=65535&(v+=R>>>16),q=65535&(P+=v>>>16),X=65535&(x+=P>>>16),V=65535&(Z+=x>>>16),W=65535&(K+=Z>>>16),j=65535&(O+=K>>>16),T=65535&(z+=O>>>16),$=65535&(_+=z>>>16),IA=65535&(AA+=_>>>16),CA=65535&(gA+=AA>>>16),BA=65535&(QA+=gA>>>16),iA=65535&(tA+=QA>>>16),eA=65535&(EA+=tA>>>16),aA=65535&(nA+=EA>>>16),hA=65535&(oA+=nA>>>16),wA=65535&(rA+=oA>>>16),fA=65535&(sA+=rA>>>16),cA=65535&(DA+=sA>>>16),FA=65535&(yA+=DA>>>16),uA=65535&(MA+=yA>>>16),lA=65535&(pA+=MA>>>16),GA=65535&(HA+=pA>>>16),dA=65535&(UA+=HA>>>16),LA=65535&(mA+=UA>>>16),kA=65535&(JA+=mA>>>16),bA=65535&(NA+=JA>>>16),SA=65535&(RA+=NA>>>16),YA=65535&(vA+=RA>>>16),qA=65535&(PA+=vA>>>16),XA=65535&(xA+=PA>>>16),VA=65535&(ZA+=xA>>>16),WA=65535&(KA+=ZA>>>16),jA=65535&(OA+=KA>>>16),TA=65535&(zA+=OA>>>16),$A=65535&(_A+=zA>>>16),II=65535&(AI+=_A>>>16),CI=65535&(gI+=AI>>>16),BI=65535&(QI+=gI>>>16),iI=65535&(tI+=QI>>>16),eI=65535&(EI+=tI>>>16),aI=65535&(nI+=EI>>>16),hI=65535&(oI+=nI>>>16),wI=65535&(rI+=oI>>>16),fI=65535&(sI+=rI>>>16),cI=65535&(DI+=sI>>>16),FI=65535&(yI+=DI>>>16),uI=65535&(MI+=yI>>>16),GI=HI+((pI+=MI>>>16)>>>16)&65535,lI=65535&pI,t^=63&I|128):55296==(64512&I)&&g+1>18|240)<<8,PA+=e<<8,xA+=a<<8,ZA+=h<<8,KA+=f<<8,OA+=c<<8,zA+=F<<8,_A+=u<<8,AI+=l<<8,gI+=G<<8,QI+=d<<8,tI+=L<<8,EI+=k<<8,nI+=b<<8,oI+=S<<8,rI+=Y<<8,sI+=q<<8,DI+=X<<8,yI+=V<<8,MI+=W<<8,pI+=j<<8,t=65535&(B=397*t),GI=(HI+=T<<8)+((pI+=(MI+=(yI+=(DI+=(sI+=(rI+=(oI+=(nI+=(EI+=(tI+=(QI+=(gI+=(AI+=(_A+=(zA+=(OA+=(KA+=(ZA+=(xA+=(PA+=(vA+=(RA+=(NA+=(JA+=(mA+=(UA+=(HA+=(pA+=(MA+=(yA+=(DA+=(sA+=(rA+=(oA+=(nA+=(EA+=(tA+=(QA+=(gA+=(AA+=(_+=(z+=(O+=(K+=(Z+=(x+=(P+=(v+=(R+=(N+=(J+=(m+=(U+=(H+=(p+=(M+=(y+=(D+=(w+=(o+=(n+=(i+=B>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)&65535,i=397*(e=65535&i),n=397*(a=65535&n),o=397*(h=65535&o),w=397*(f=65535&w),D=397*(c=65535&D),y=397*(F=65535&y),M=397*(u=65535&M),p=397*(l=65535&p),H=397*(G=65535&H),U=397*(d=65535&U),m=397*(L=65535&m),J=397*(k=65535&J),N=397*(b=65535&N),R=397*(S=65535&R),v=397*(Y=65535&v),P=397*(q=65535&P),x=397*(X=65535&x),Z=397*(V=65535&Z),K=397*(W=65535&K),O=397*(j=65535&O),z=397*(T=65535&z),_=397*($=65535&_),AA=397*(IA=65535&AA),gA=397*(CA=65535&gA),QA=397*(BA=65535&QA),tA=397*(iA=65535&tA),EA=397*(eA=65535&EA),nA=397*(aA=65535&nA),oA=397*(hA=65535&oA),rA=397*(wA=65535&rA),sA=397*(fA=65535&sA),DA=397*(cA=65535&DA),yA=397*(FA=65535&yA),MA=397*(uA=65535&MA),pA=397*(lA=65535&pA),HA=397*(GA=65535&HA),UA=397*(dA=65535&UA),mA=397*(LA=65535&mA),JA=397*(kA=65535&JA),NA=397*(bA=65535&NA),RA=397*(SA=65535&RA),vA=397*(YA=65535&vA),PA=397*(qA=65535&PA),xA=397*(XA=65535&xA),ZA=397*(VA=65535&ZA),KA=397*(WA=65535&KA),OA=397*(jA=65535&OA),zA=397*(TA=65535&zA),_A=397*($A=65535&_A),AI=397*(II=65535&AI),gI=397*(CI=65535&gI),QI=397*(BI=65535&QI),tI=397*(iI=65535&tI),EI=397*(eI=65535&EI),nI=397*(aI=65535&nI),oI=397*(hI=65535&oI),rI=397*(wI=65535&rI),sI=397*(fI=65535&sI),DI=397*(cI=65535&DI),yI=397*(FI=65535&yI),MI=397*(uI=65535&MI),pI=397*(lI=65535&pI),HI=397*GI,vA+=(t^=I>>12&63|128)<<8,PA+=e<<8,xA+=a<<8,ZA+=h<<8,KA+=f<<8,OA+=c<<8,zA+=F<<8,_A+=u<<8,AI+=l<<8,gI+=G<<8,QI+=d<<8,tI+=L<<8,EI+=k<<8,nI+=b<<8,oI+=S<<8,rI+=Y<<8,sI+=q<<8,DI+=X<<8,yI+=V<<8,MI+=W<<8,pI+=j<<8,t=65535&(B=397*t),GI=(HI+=T<<8)+((pI+=(MI+=(yI+=(DI+=(sI+=(rI+=(oI+=(nI+=(EI+=(tI+=(QI+=(gI+=(AI+=(_A+=(zA+=(OA+=(KA+=(ZA+=(xA+=(PA+=(vA+=(RA+=(NA+=(JA+=(mA+=(UA+=(HA+=(pA+=(MA+=(yA+=(DA+=(sA+=(rA+=(oA+=(nA+=(EA+=(tA+=(QA+=(gA+=(AA+=(_+=(z+=(O+=(K+=(Z+=(x+=(P+=(v+=(R+=(N+=(J+=(m+=(U+=(H+=(p+=(M+=(y+=(D+=(w+=(o+=(n+=(i+=B>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)&65535,i=397*(e=65535&i),n=397*(a=65535&n),o=397*(h=65535&o),w=397*(f=65535&w),D=397*(c=65535&D),y=397*(F=65535&y),M=397*(u=65535&M),p=397*(l=65535&p),H=397*(G=65535&H),U=397*(d=65535&U),m=397*(L=65535&m),J=397*(k=65535&J),N=397*(b=65535&N),R=397*(S=65535&R),v=397*(Y=65535&v),P=397*(q=65535&P),x=397*(X=65535&x),Z=397*(V=65535&Z),K=397*(W=65535&K),O=397*(j=65535&O),z=397*(T=65535&z),_=397*($=65535&_),AA=397*(IA=65535&AA),gA=397*(CA=65535&gA),QA=397*(BA=65535&QA),tA=397*(iA=65535&tA),EA=397*(eA=65535&EA),nA=397*(aA=65535&nA),oA=397*(hA=65535&oA),rA=397*(wA=65535&rA),sA=397*(fA=65535&sA),DA=397*(cA=65535&DA),yA=397*(FA=65535&yA),MA=397*(uA=65535&MA),pA=397*(lA=65535&pA),HA=397*(GA=65535&HA),UA=397*(dA=65535&UA),mA=397*(LA=65535&mA),JA=397*(kA=65535&JA),NA=397*(bA=65535&NA),RA=397*(SA=65535&RA),vA=397*(YA=65535&vA),PA=397*(qA=65535&PA),xA=397*(XA=65535&xA),ZA=397*(VA=65535&ZA),KA=397*(WA=65535&KA),OA=397*(jA=65535&OA),zA=397*(TA=65535&zA),_A=397*($A=65535&_A),AI=397*(II=65535&AI),gI=397*(CI=65535&gI),QI=397*(BI=65535&QI),tI=397*(iI=65535&tI),EI=397*(eI=65535&EI),nI=397*(aI=65535&nI),oI=397*(hI=65535&oI),rI=397*(wI=65535&rI),sI=397*(fI=65535&sI),DI=397*(cI=65535&DI),yI=397*(FI=65535&yI),MI=397*(uI=65535&MI),pI=397*(lI=65535&pI),HI=397*GI,vA+=(t^=I>>6&63|128)<<8,PA+=e<<8,xA+=a<<8,ZA+=h<<8,KA+=f<<8,OA+=c<<8,zA+=F<<8,_A+=u<<8,AI+=l<<8,gI+=G<<8,QI+=d<<8,tI+=L<<8,EI+=k<<8,nI+=b<<8,oI+=S<<8,rI+=Y<<8,sI+=q<<8,DI+=X<<8,yI+=V<<8,MI+=W<<8,pI+=j<<8,HI+=T<<8,t=65535&(B=397*t),e=65535&(i+=B>>>16),a=65535&(n+=i>>>16),h=65535&(o+=n>>>16),f=65535&(w+=o>>>16),c=65535&(D+=w>>>16),F=65535&(y+=D>>>16),u=65535&(M+=y>>>16),l=65535&(p+=M>>>16),G=65535&(H+=p>>>16),d=65535&(U+=H>>>16),L=65535&(m+=U>>>16),k=65535&(J+=m>>>16),b=65535&(N+=J>>>16),S=65535&(R+=N>>>16),Y=65535&(v+=R>>>16),q=65535&(P+=v>>>16),X=65535&(x+=P>>>16),V=65535&(Z+=x>>>16),W=65535&(K+=Z>>>16),j=65535&(O+=K>>>16),T=65535&(z+=O>>>16),$=65535&(_+=z>>>16),IA=65535&(AA+=_>>>16),CA=65535&(gA+=AA>>>16),BA=65535&(QA+=gA>>>16),iA=65535&(tA+=QA>>>16),eA=65535&(EA+=tA>>>16),aA=65535&(nA+=EA>>>16),hA=65535&(oA+=nA>>>16),wA=65535&(rA+=oA>>>16),fA=65535&(sA+=rA>>>16),cA=65535&(DA+=sA>>>16),FA=65535&(yA+=DA>>>16),uA=65535&(MA+=yA>>>16),lA=65535&(pA+=MA>>>16),GA=65535&(HA+=pA>>>16),dA=65535&(UA+=HA>>>16),LA=65535&(mA+=UA>>>16),kA=65535&(JA+=mA>>>16),bA=65535&(NA+=JA>>>16),SA=65535&(RA+=NA>>>16),YA=65535&(vA+=RA>>>16),qA=65535&(PA+=vA>>>16),XA=65535&(xA+=PA>>>16),VA=65535&(ZA+=xA>>>16),WA=65535&(KA+=ZA>>>16),jA=65535&(OA+=KA>>>16),TA=65535&(zA+=OA>>>16),$A=65535&(_A+=zA>>>16),II=65535&(AI+=_A>>>16),CI=65535&(gI+=AI>>>16),BI=65535&(QI+=gI>>>16),iI=65535&(tI+=QI>>>16),eI=65535&(EI+=tI>>>16),aI=65535&(nI+=EI>>>16),hI=65535&(oI+=nI>>>16),wI=65535&(rI+=oI>>>16),fI=65535&(sI+=rI>>>16),cI=65535&(DI+=sI>>>16),FI=65535&(yI+=DI>>>16),uI=65535&(MI+=yI>>>16),GI=HI+((pI+=MI>>>16)>>>16)&65535,lI=65535&pI,t^=63&I|128):(i=397*e,n=397*a,o=397*h,w=397*f,D=397*c,y=397*F,M=397*u,p=397*l,H=397*G,U=397*d,m=397*L,J=397*k,N=397*b,R=397*S,v=397*Y,P=397*q,x=397*X,Z=397*V,K=397*W,O=397*j,z=397*T,_=397*$,AA=397*IA,gA=397*CA,QA=397*BA,tA=397*iA,EA=397*eA,nA=397*aA,oA=397*hA,rA=397*wA,sA=397*fA,DA=397*cA,yA=397*FA,MA=397*uA,pA=397*lA,HA=397*GA,UA=397*dA,mA=397*LA,JA=397*kA,NA=397*bA,RA=397*SA,vA=397*YA,PA=397*qA,xA=397*XA,ZA=397*VA,KA=397*WA,OA=397*jA,zA=397*TA,_A=397*$A,AI=397*II,gI=397*CI,QI=397*BI,tI=397*iI,EI=397*eI,nI=397*aI,oI=397*hI,rI=397*wI,sI=397*fI,DI=397*cI,yI=397*FI,MI=397*uI,pI=397*lI,HI=397*GI,vA+=(t^=I>>12|224)<<8,PA+=e<<8,xA+=a<<8,ZA+=h<<8,KA+=f<<8,OA+=c<<8,zA+=F<<8,_A+=u<<8,AI+=l<<8,gI+=G<<8,QI+=d<<8,tI+=L<<8,EI+=k<<8,nI+=b<<8,oI+=S<<8,rI+=Y<<8,sI+=q<<8,DI+=X<<8,yI+=V<<8,MI+=W<<8,pI+=j<<8,t=65535&(B=397*t),GI=(HI+=T<<8)+((pI+=(MI+=(yI+=(DI+=(sI+=(rI+=(oI+=(nI+=(EI+=(tI+=(QI+=(gI+=(AI+=(_A+=(zA+=(OA+=(KA+=(ZA+=(xA+=(PA+=(vA+=(RA+=(NA+=(JA+=(mA+=(UA+=(HA+=(pA+=(MA+=(yA+=(DA+=(sA+=(rA+=(oA+=(nA+=(EA+=(tA+=(QA+=(gA+=(AA+=(_+=(z+=(O+=(K+=(Z+=(x+=(P+=(v+=(R+=(N+=(J+=(m+=(U+=(H+=(p+=(M+=(y+=(D+=(w+=(o+=(n+=(i+=B>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)&65535,i=397*(e=65535&i),n=397*(a=65535&n),o=397*(h=65535&o),w=397*(f=65535&w),D=397*(c=65535&D),y=397*(F=65535&y),M=397*(u=65535&M),p=397*(l=65535&p),H=397*(G=65535&H),U=397*(d=65535&U),m=397*(L=65535&m),J=397*(k=65535&J),N=397*(b=65535&N),R=397*(S=65535&R),v=397*(Y=65535&v),P=397*(q=65535&P),x=397*(X=65535&x),Z=397*(V=65535&Z),K=397*(W=65535&K),O=397*(j=65535&O),z=397*(T=65535&z),_=397*($=65535&_),AA=397*(IA=65535&AA),gA=397*(CA=65535&gA),QA=397*(BA=65535&QA),tA=397*(iA=65535&tA),EA=397*(eA=65535&EA),nA=397*(aA=65535&nA),oA=397*(hA=65535&oA),rA=397*(wA=65535&rA),sA=397*(fA=65535&sA),DA=397*(cA=65535&DA),yA=397*(FA=65535&yA),MA=397*(uA=65535&MA),pA=397*(lA=65535&pA),HA=397*(GA=65535&HA),UA=397*(dA=65535&UA),mA=397*(LA=65535&mA),JA=397*(kA=65535&JA),NA=397*(bA=65535&NA),RA=397*(SA=65535&RA),vA=397*(YA=65535&vA),PA=397*(qA=65535&PA),xA=397*(XA=65535&xA),ZA=397*(VA=65535&ZA),KA=397*(WA=65535&KA),OA=397*(jA=65535&OA),zA=397*(TA=65535&zA),_A=397*($A=65535&_A),AI=397*(II=65535&AI),gI=397*(CI=65535&gI),QI=397*(BI=65535&QI),tI=397*(iI=65535&tI),EI=397*(eI=65535&EI),nI=397*(aI=65535&nI),oI=397*(hI=65535&oI),rI=397*(wI=65535&rI),sI=397*(fI=65535&sI),DI=397*(cI=65535&DI),yI=397*(FI=65535&yI),MI=397*(uI=65535&MI),pI=397*(lI=65535&pI),HI=397*GI,vA+=(t^=I>>6&63|128)<<8,PA+=e<<8,xA+=a<<8,ZA+=h<<8,KA+=f<<8,OA+=c<<8,zA+=F<<8,_A+=u<<8,AI+=l<<8,gI+=G<<8,QI+=d<<8,tI+=L<<8,EI+=k<<8,nI+=b<<8,oI+=S<<8,rI+=Y<<8,sI+=q<<8,DI+=X<<8,yI+=V<<8,MI+=W<<8,pI+=j<<8,HI+=T<<8,t=65535&(B=397*t),e=65535&(i+=B>>>16),a=65535&(n+=i>>>16),h=65535&(o+=n>>>16),f=65535&(w+=o>>>16),c=65535&(D+=w>>>16),F=65535&(y+=D>>>16),u=65535&(M+=y>>>16),l=65535&(p+=M>>>16),G=65535&(H+=p>>>16),d=65535&(U+=H>>>16),L=65535&(m+=U>>>16),k=65535&(J+=m>>>16),b=65535&(N+=J>>>16),S=65535&(R+=N>>>16),Y=65535&(v+=R>>>16),q=65535&(P+=v>>>16),X=65535&(x+=P>>>16),V=65535&(Z+=x>>>16),W=65535&(K+=Z>>>16),j=65535&(O+=K>>>16),T=65535&(z+=O>>>16),$=65535&(_+=z>>>16),IA=65535&(AA+=_>>>16),CA=65535&(gA+=AA>>>16),BA=65535&(QA+=gA>>>16),iA=65535&(tA+=QA>>>16),eA=65535&(EA+=tA>>>16),aA=65535&(nA+=EA>>>16),hA=65535&(oA+=nA>>>16),wA=65535&(rA+=oA>>>16),fA=65535&(sA+=rA>>>16),cA=65535&(DA+=sA>>>16),FA=65535&(yA+=DA>>>16),uA=65535&(MA+=yA>>>16),lA=65535&(pA+=MA>>>16),GA=65535&(HA+=pA>>>16),dA=65535&(UA+=HA>>>16),LA=65535&(mA+=UA>>>16),kA=65535&(JA+=mA>>>16),bA=65535&(NA+=JA>>>16),SA=65535&(RA+=NA>>>16),YA=65535&(vA+=RA>>>16),qA=65535&(PA+=vA>>>16),XA=65535&(xA+=PA>>>16),VA=65535&(ZA+=xA>>>16),WA=65535&(KA+=ZA>>>16),jA=65535&(OA+=KA>>>16),TA=65535&(zA+=OA>>>16),$A=65535&(_A+=zA>>>16),II=65535&(AI+=_A>>>16),CI=65535&(gI+=AI>>>16),BI=65535&(QI+=gI>>>16),iI=65535&(tI+=QI>>>16),eI=65535&(EI+=tI>>>16),aI=65535&(nI+=EI>>>16),hI=65535&(oI+=nI>>>16),wI=65535&(rI+=oI>>>16),fI=65535&(sI+=rI>>>16),cI=65535&(DI+=sI>>>16),FI=65535&(yI+=DI>>>16),uI=65535&(MI+=yI>>>16),GI=HI+((pI+=MI>>>16)>>>16)&65535,lI=65535&pI,t^=63&I|128),i=397*e,n=397*a,o=397*h,w=397*f,D=397*c,y=397*F,M=397*u,p=397*l,H=397*G,U=397*d,m=397*L,J=397*k,N=397*b,R=397*S,v=397*Y,P=397*q,x=397*X,Z=397*V,K=397*W,O=397*j,z=397*T,_=397*$,AA=397*IA,gA=397*CA,QA=397*BA,tA=397*iA,EA=397*eA,nA=397*aA,oA=397*hA,rA=397*wA,sA=397*fA,DA=397*cA,yA=397*FA,MA=397*uA,pA=397*lA,HA=397*GA,UA=397*dA,mA=397*LA,JA=397*kA,NA=397*bA,RA=397*SA,vA=397*YA,PA=397*qA,xA=397*XA,ZA=397*VA,KA=397*WA,OA=397*jA,zA=397*TA,_A=397*$A,AI=397*II,gI=397*CI,QI=397*BI,tI=397*iI,EI=397*eI,nI=397*aI,oI=397*hI,rI=397*wI,sI=397*fI,DI=397*cI,yI=397*FI,MI=397*uI,pI=397*lI,HI=397*GI,vA+=t<<8,PA+=e<<8,xA+=a<<8,ZA+=h<<8,KA+=f<<8,OA+=c<<8,zA+=F<<8,_A+=u<<8,AI+=l<<8,gI+=G<<8,QI+=d<<8,tI+=L<<8,EI+=k<<8,nI+=b<<8,oI+=S<<8,rI+=Y<<8,sI+=q<<8,DI+=X<<8,yI+=V<<8,MI+=W<<8,pI+=j<<8,HI+=T<<8,t=65535&(B=397*t),e=65535&(i+=B>>>16),a=65535&(n+=i>>>16),h=65535&(o+=n>>>16),f=65535&(w+=o>>>16),c=65535&(D+=w>>>16),F=65535&(y+=D>>>16),u=65535&(M+=y>>>16),l=65535&(p+=M>>>16),G=65535&(H+=p>>>16),d=65535&(U+=H>>>16),L=65535&(m+=U>>>16),k=65535&(J+=m>>>16),b=65535&(N+=J>>>16),S=65535&(R+=N>>>16),Y=65535&(v+=R>>>16),q=65535&(P+=v>>>16),X=65535&(x+=P>>>16),V=65535&(Z+=x>>>16),W=65535&(K+=Z>>>16),j=65535&(O+=K>>>16),T=65535&(z+=O>>>16),$=65535&(_+=z>>>16),IA=65535&(AA+=_>>>16),CA=65535&(gA+=AA>>>16),BA=65535&(QA+=gA>>>16),iA=65535&(tA+=QA>>>16),eA=65535&(EA+=tA>>>16),aA=65535&(nA+=EA>>>16),hA=65535&(oA+=nA>>>16),wA=65535&(rA+=oA>>>16),fA=65535&(sA+=rA>>>16),cA=65535&(DA+=sA>>>16),FA=65535&(yA+=DA>>>16),uA=65535&(MA+=yA>>>16),lA=65535&(pA+=MA>>>16),GA=65535&(HA+=pA>>>16),dA=65535&(UA+=HA>>>16),LA=65535&(mA+=UA>>>16),kA=65535&(JA+=mA>>>16),bA=65535&(NA+=JA>>>16),SA=65535&(RA+=NA>>>16),YA=65535&(vA+=RA>>>16),qA=65535&(PA+=vA>>>16),XA=65535&(xA+=PA>>>16),VA=65535&(ZA+=xA>>>16),WA=65535&(KA+=ZA>>>16),jA=65535&(OA+=KA>>>16),TA=65535&(zA+=OA>>>16),$A=65535&(_A+=zA>>>16),II=65535&(AI+=_A>>>16),CI=65535&(gI+=AI>>>16),BI=65535&(QI+=gI>>>16),iI=65535&(tI+=QI>>>16),eI=65535&(EI+=tI>>>16),aI=65535&(nI+=EI>>>16),hI=65535&(oI+=nI>>>16),wI=65535&(rI+=oI>>>16),fI=65535&(sI+=rI>>>16),cI=65535&(DI+=sI>>>16),FI=65535&(yI+=DI>>>16),uI=65535&(MI+=yI>>>16),GI=HI+((pI+=MI>>>16)>>>16)&65535,lI=65535&pI;return s(E[GI>>8]+E[255&GI]+E[lI>>8]+E[255&lI]+E[uI>>8]+E[255&uI]+E[FI>>8]+E[255&FI]+E[cI>>8]+E[255&cI]+E[fI>>8]+E[255&fI]+E[wI>>8]+E[255&wI]+E[hI>>8]+E[255&hI]+E[aI>>8]+E[255&aI]+E[eI>>8]+E[255&eI]+E[iI>>8]+E[255&iI]+E[BI>>8]+E[255&BI]+E[CI>>8]+E[255&CI]+E[II>>8]+E[255&II]+E[$A>>8]+E[255&$A]+E[TA>>8]+E[255&TA]+E[jA>>8]+E[255&jA]+E[WA>>8]+E[255&WA]+E[VA>>8]+E[255&VA]+E[XA>>8]+E[255&XA]+E[qA>>8]+E[255&qA]+E[YA>>8]+E[255&YA]+E[SA>>8]+E[255&SA]+E[bA>>8]+E[255&bA]+E[kA>>8]+E[255&kA]+E[LA>>8]+E[255&LA]+E[dA>>8]+E[255&dA]+E[GA>>8]+E[255&GA]+E[lA>>8]+E[255&lA]+E[uA>>8]+E[255&uA]+E[FA>>8]+E[255&FA]+E[cA>>8]+E[255&cA]+E[fA>>8]+E[255&fA]+E[wA>>8]+E[255&wA]+E[hA>>8]+E[255&hA]+E[aA>>8]+E[255&aA]+E[eA>>8]+E[255&eA]+E[iA>>8]+E[255&iA]+E[BA>>8]+E[255&BA]+E[CA>>8]+E[255&CA]+E[IA>>8]+E[255&IA]+E[$>>8]+E[255&$]+E[T>>8]+E[255&T]+E[j>>8]+E[255&j]+E[W>>8]+E[255&W]+E[V>>8]+E[255&V]+E[X>>8]+E[255&X]+E[q>>8]+E[255&q]+E[Y>>8]+E[255&Y]+E[S>>8]+E[255&S]+E[b>>8]+E[255&b]+E[k>>8]+E[255&k]+E[L>>8]+E[255&L]+E[d>>8]+E[255&d]+E[G>>8]+E[255&G]+E[l>>8]+E[255&l]+E[u>>8]+E[255&u]+E[F>>8]+E[255&F]+E[c>>8]+E[255&c]+E[f>>8]+E[255&f]+E[h>>8]+E[255&h]+E[a>>8]+E[255&a]+E[e>>8]+E[255&e]+E[t>>8]+E[255&t],1024)}function z(A){var I,g,C=A.length,Q=r[1024].offset,B=0,t=0|Q[63],i=0,e=0|Q[62],n=0,a=0|Q[61],o=0,h=0|Q[60],w=0,f=0|Q[59],D=0,c=0|Q[58],y=0,F=0|Q[57],M=0,u=0|Q[56],p=0,l=0|Q[55],H=0,G=0|Q[54],U=0,d=0|Q[53],m=0,L=0|Q[52],J=0,k=0|Q[51],N=0,b=0|Q[50],R=0,S=0|Q[49],v=0,Y=0|Q[48],P=0,q=0|Q[47],x=0,X=0|Q[46],Z=0,V=0|Q[45],K=0,W=0|Q[44],O=0,j=0|Q[43],z=0,T=0|Q[42],_=0,$=0|Q[41],AA=0,IA=0|Q[40],gA=0,CA=0|Q[39],QA=0,BA=0|Q[38],tA=0,iA=0|Q[37],EA=0,eA=0|Q[36],nA=0,aA=0|Q[35],oA=0,hA=0|Q[34],rA=0,wA=0|Q[33],sA=0,fA=0|Q[32],DA=0,cA=0|Q[31],yA=0,FA=0|Q[30],MA=0,uA=0|Q[29],pA=0,lA=0|Q[28],HA=0,GA=0|Q[27],UA=0,dA=0|Q[26],mA=0,LA=0|Q[25],JA=0,kA=0|Q[24],NA=0,bA=0|Q[23],RA=0,SA=0|Q[22],vA=0,YA=0|Q[21],PA=0,qA=0|Q[20],xA=0,XA=0|Q[19],ZA=0,VA=0|Q[18],KA=0,WA=0|Q[17],OA=0,jA=0|Q[16],zA=0,TA=0|Q[15],_A=0,$A=0|Q[14],AI=0,II=0|Q[13],gI=0,CI=0|Q[12],QI=0,BI=0|Q[11],tI=0,iI=0|Q[10],EI=0,eI=0|Q[9],nI=0,aI=0|Q[8],oI=0,hI=0|Q[7],rI=0,wI=0|Q[6],sI=0,fI=0|Q[5],DI=0,cI=0|Q[4],yI=0,FI=0|Q[3],MI=0,uI=0|Q[2],pI=0,lI=0|Q[1],HI=0,GI=0|Q[0];for(g=0;g>>16),a=65535&(n+=i>>>16),h=65535&(o+=n>>>16),f=65535&(w+=o>>>16),c=65535&(D+=w>>>16),F=65535&(y+=D>>>16),u=65535&(M+=y>>>16),l=65535&(p+=M>>>16),G=65535&(H+=p>>>16),d=65535&(U+=H>>>16),L=65535&(m+=U>>>16),k=65535&(J+=m>>>16),b=65535&(N+=J>>>16),S=65535&(R+=N>>>16),Y=65535&(v+=R>>>16),q=65535&(P+=v>>>16),X=65535&(x+=P>>>16),V=65535&(Z+=x>>>16),W=65535&(K+=Z>>>16),j=65535&(O+=K>>>16),T=65535&(z+=O>>>16),$=65535&(_+=z>>>16),IA=65535&(AA+=_>>>16),CA=65535&(gA+=AA>>>16),BA=65535&(QA+=gA>>>16),iA=65535&(tA+=QA>>>16),eA=65535&(EA+=tA>>>16),aA=65535&(nA+=EA>>>16),hA=65535&(oA+=nA>>>16),wA=65535&(rA+=oA>>>16),fA=65535&(sA+=rA>>>16),cA=65535&(DA+=sA>>>16),FA=65535&(yA+=DA>>>16),uA=65535&(MA+=yA>>>16),lA=65535&(pA+=MA>>>16),GA=65535&(HA+=pA>>>16),dA=65535&(UA+=HA>>>16),LA=65535&(mA+=UA>>>16),kA=65535&(JA+=mA>>>16),bA=65535&(NA+=JA>>>16),SA=65535&(RA+=NA>>>16),YA=65535&(vA+=RA>>>16),qA=65535&(PA+=vA>>>16),XA=65535&(xA+=PA>>>16),VA=65535&(ZA+=xA>>>16),WA=65535&(KA+=ZA>>>16),jA=65535&(OA+=KA>>>16),TA=65535&(zA+=OA>>>16),$A=65535&(_A+=zA>>>16),II=65535&(AI+=_A>>>16),CI=65535&(gI+=AI>>>16),BI=65535&(QI+=gI>>>16),iI=65535&(tI+=QI>>>16),eI=65535&(EI+=tI>>>16),aI=65535&(nI+=EI>>>16),hI=65535&(oI+=nI>>>16),wI=65535&(rI+=oI>>>16),fI=65535&(sI+=rI>>>16),cI=65535&(DI+=sI>>>16),FI=65535&(yI+=DI>>>16),uI=65535&(MI+=yI>>>16),GI=HI+((pI+=MI>>>16)>>>16)&65535,lI=65535&pI,(I=A.charCodeAt(g))<128?t^=I:I<2048?(i=397*e,n=397*a,o=397*h,w=397*f,D=397*c,y=397*F,M=397*u,p=397*l,H=397*G,U=397*d,m=397*L,J=397*k,N=397*b,R=397*S,v=397*Y,P=397*q,x=397*X,Z=397*V,K=397*W,O=397*j,z=397*T,_=397*$,AA=397*IA,gA=397*CA,QA=397*BA,tA=397*iA,EA=397*eA,nA=397*aA,oA=397*hA,rA=397*wA,sA=397*fA,DA=397*cA,yA=397*FA,MA=397*uA,pA=397*lA,HA=397*GA,UA=397*dA,mA=397*LA,JA=397*kA,NA=397*bA,RA=397*SA,vA=397*YA,PA=397*qA,xA=397*XA,ZA=397*VA,KA=397*WA,OA=397*jA,zA=397*TA,_A=397*$A,AI=397*II,gI=397*CI,QI=397*BI,tI=397*iI,EI=397*eI,nI=397*aI,oI=397*hI,rI=397*wI,sI=397*fI,DI=397*cI,yI=397*FI,MI=397*uI,pI=397*lI,HI=397*GI,vA+=(t^=I>>6|192)<<8,PA+=e<<8,xA+=a<<8,ZA+=h<<8,KA+=f<<8,OA+=c<<8,zA+=F<<8,_A+=u<<8,AI+=l<<8,gI+=G<<8,QI+=d<<8,tI+=L<<8,EI+=k<<8,nI+=b<<8,oI+=S<<8,rI+=Y<<8,sI+=q<<8,DI+=X<<8,yI+=V<<8,MI+=W<<8,pI+=j<<8,HI+=T<<8,t=65535&(B=397*t),e=65535&(i+=B>>>16),a=65535&(n+=i>>>16),h=65535&(o+=n>>>16),f=65535&(w+=o>>>16),c=65535&(D+=w>>>16),F=65535&(y+=D>>>16),u=65535&(M+=y>>>16),l=65535&(p+=M>>>16),G=65535&(H+=p>>>16),d=65535&(U+=H>>>16),L=65535&(m+=U>>>16),k=65535&(J+=m>>>16),b=65535&(N+=J>>>16),S=65535&(R+=N>>>16),Y=65535&(v+=R>>>16),q=65535&(P+=v>>>16),X=65535&(x+=P>>>16),V=65535&(Z+=x>>>16),W=65535&(K+=Z>>>16),j=65535&(O+=K>>>16),T=65535&(z+=O>>>16),$=65535&(_+=z>>>16),IA=65535&(AA+=_>>>16),CA=65535&(gA+=AA>>>16),BA=65535&(QA+=gA>>>16),iA=65535&(tA+=QA>>>16),eA=65535&(EA+=tA>>>16),aA=65535&(nA+=EA>>>16),hA=65535&(oA+=nA>>>16),wA=65535&(rA+=oA>>>16),fA=65535&(sA+=rA>>>16),cA=65535&(DA+=sA>>>16),FA=65535&(yA+=DA>>>16),uA=65535&(MA+=yA>>>16),lA=65535&(pA+=MA>>>16),GA=65535&(HA+=pA>>>16),dA=65535&(UA+=HA>>>16),LA=65535&(mA+=UA>>>16),kA=65535&(JA+=mA>>>16),bA=65535&(NA+=JA>>>16),SA=65535&(RA+=NA>>>16),YA=65535&(vA+=RA>>>16),qA=65535&(PA+=vA>>>16),XA=65535&(xA+=PA>>>16),VA=65535&(ZA+=xA>>>16),WA=65535&(KA+=ZA>>>16),jA=65535&(OA+=KA>>>16),TA=65535&(zA+=OA>>>16),$A=65535&(_A+=zA>>>16),II=65535&(AI+=_A>>>16),CI=65535&(gI+=AI>>>16),BI=65535&(QI+=gI>>>16),iI=65535&(tI+=QI>>>16),eI=65535&(EI+=tI>>>16),aI=65535&(nI+=EI>>>16),hI=65535&(oI+=nI>>>16),wI=65535&(rI+=oI>>>16),fI=65535&(sI+=rI>>>16),cI=65535&(DI+=sI>>>16),FI=65535&(yI+=DI>>>16),uI=65535&(MI+=yI>>>16),GI=HI+((pI+=MI>>>16)>>>16)&65535,lI=65535&pI,t^=63&I|128):55296==(64512&I)&&g+1>18|240)<<8,PA+=e<<8,xA+=a<<8,ZA+=h<<8,KA+=f<<8,OA+=c<<8,zA+=F<<8,_A+=u<<8,AI+=l<<8,gI+=G<<8,QI+=d<<8,tI+=L<<8,EI+=k<<8,nI+=b<<8,oI+=S<<8,rI+=Y<<8,sI+=q<<8,DI+=X<<8,yI+=V<<8,MI+=W<<8,pI+=j<<8,t=65535&(B=397*t),GI=(HI+=T<<8)+((pI+=(MI+=(yI+=(DI+=(sI+=(rI+=(oI+=(nI+=(EI+=(tI+=(QI+=(gI+=(AI+=(_A+=(zA+=(OA+=(KA+=(ZA+=(xA+=(PA+=(vA+=(RA+=(NA+=(JA+=(mA+=(UA+=(HA+=(pA+=(MA+=(yA+=(DA+=(sA+=(rA+=(oA+=(nA+=(EA+=(tA+=(QA+=(gA+=(AA+=(_+=(z+=(O+=(K+=(Z+=(x+=(P+=(v+=(R+=(N+=(J+=(m+=(U+=(H+=(p+=(M+=(y+=(D+=(w+=(o+=(n+=(i+=B>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)&65535,i=397*(e=65535&i),n=397*(a=65535&n),o=397*(h=65535&o),w=397*(f=65535&w),D=397*(c=65535&D),y=397*(F=65535&y),M=397*(u=65535&M),p=397*(l=65535&p),H=397*(G=65535&H),U=397*(d=65535&U),m=397*(L=65535&m),J=397*(k=65535&J),N=397*(b=65535&N),R=397*(S=65535&R),v=397*(Y=65535&v),P=397*(q=65535&P),x=397*(X=65535&x),Z=397*(V=65535&Z),K=397*(W=65535&K),O=397*(j=65535&O),z=397*(T=65535&z),_=397*($=65535&_),AA=397*(IA=65535&AA),gA=397*(CA=65535&gA),QA=397*(BA=65535&QA),tA=397*(iA=65535&tA),EA=397*(eA=65535&EA),nA=397*(aA=65535&nA),oA=397*(hA=65535&oA),rA=397*(wA=65535&rA),sA=397*(fA=65535&sA),DA=397*(cA=65535&DA),yA=397*(FA=65535&yA),MA=397*(uA=65535&MA),pA=397*(lA=65535&pA),HA=397*(GA=65535&HA),UA=397*(dA=65535&UA),mA=397*(LA=65535&mA),JA=397*(kA=65535&JA),NA=397*(bA=65535&NA),RA=397*(SA=65535&RA),vA=397*(YA=65535&vA),PA=397*(qA=65535&PA),xA=397*(XA=65535&xA),ZA=397*(VA=65535&ZA),KA=397*(WA=65535&KA),OA=397*(jA=65535&OA),zA=397*(TA=65535&zA),_A=397*($A=65535&_A),AI=397*(II=65535&AI),gI=397*(CI=65535&gI),QI=397*(BI=65535&QI),tI=397*(iI=65535&tI),EI=397*(eI=65535&EI),nI=397*(aI=65535&nI),oI=397*(hI=65535&oI),rI=397*(wI=65535&rI),sI=397*(fI=65535&sI),DI=397*(cI=65535&DI),yI=397*(FI=65535&yI),MI=397*(uI=65535&MI),pI=397*(lI=65535&pI),HI=397*GI,vA+=(t^=I>>12&63|128)<<8,PA+=e<<8,xA+=a<<8,ZA+=h<<8,KA+=f<<8,OA+=c<<8,zA+=F<<8,_A+=u<<8,AI+=l<<8,gI+=G<<8,QI+=d<<8,tI+=L<<8,EI+=k<<8,nI+=b<<8,oI+=S<<8,rI+=Y<<8,sI+=q<<8,DI+=X<<8,yI+=V<<8,MI+=W<<8,pI+=j<<8,t=65535&(B=397*t),GI=(HI+=T<<8)+((pI+=(MI+=(yI+=(DI+=(sI+=(rI+=(oI+=(nI+=(EI+=(tI+=(QI+=(gI+=(AI+=(_A+=(zA+=(OA+=(KA+=(ZA+=(xA+=(PA+=(vA+=(RA+=(NA+=(JA+=(mA+=(UA+=(HA+=(pA+=(MA+=(yA+=(DA+=(sA+=(rA+=(oA+=(nA+=(EA+=(tA+=(QA+=(gA+=(AA+=(_+=(z+=(O+=(K+=(Z+=(x+=(P+=(v+=(R+=(N+=(J+=(m+=(U+=(H+=(p+=(M+=(y+=(D+=(w+=(o+=(n+=(i+=B>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)&65535,i=397*(e=65535&i),n=397*(a=65535&n),o=397*(h=65535&o),w=397*(f=65535&w),D=397*(c=65535&D),y=397*(F=65535&y),M=397*(u=65535&M),p=397*(l=65535&p),H=397*(G=65535&H),U=397*(d=65535&U),m=397*(L=65535&m),J=397*(k=65535&J),N=397*(b=65535&N),R=397*(S=65535&R),v=397*(Y=65535&v),P=397*(q=65535&P),x=397*(X=65535&x),Z=397*(V=65535&Z),K=397*(W=65535&K),O=397*(j=65535&O),z=397*(T=65535&z),_=397*($=65535&_),AA=397*(IA=65535&AA),gA=397*(CA=65535&gA),QA=397*(BA=65535&QA),tA=397*(iA=65535&tA),EA=397*(eA=65535&EA),nA=397*(aA=65535&nA),oA=397*(hA=65535&oA),rA=397*(wA=65535&rA),sA=397*(fA=65535&sA),DA=397*(cA=65535&DA),yA=397*(FA=65535&yA),MA=397*(uA=65535&MA),pA=397*(lA=65535&pA),HA=397*(GA=65535&HA),UA=397*(dA=65535&UA),mA=397*(LA=65535&mA),JA=397*(kA=65535&JA),NA=397*(bA=65535&NA),RA=397*(SA=65535&RA),vA=397*(YA=65535&vA),PA=397*(qA=65535&PA),xA=397*(XA=65535&xA),ZA=397*(VA=65535&ZA),KA=397*(WA=65535&KA),OA=397*(jA=65535&OA),zA=397*(TA=65535&zA),_A=397*($A=65535&_A),AI=397*(II=65535&AI),gI=397*(CI=65535&gI),QI=397*(BI=65535&QI),tI=397*(iI=65535&tI),EI=397*(eI=65535&EI),nI=397*(aI=65535&nI),oI=397*(hI=65535&oI),rI=397*(wI=65535&rI),sI=397*(fI=65535&sI),DI=397*(cI=65535&DI),yI=397*(FI=65535&yI),MI=397*(uI=65535&MI),pI=397*(lI=65535&pI),HI=397*GI,vA+=(t^=I>>6&63|128)<<8,PA+=e<<8,xA+=a<<8,ZA+=h<<8,KA+=f<<8,OA+=c<<8,zA+=F<<8,_A+=u<<8,AI+=l<<8,gI+=G<<8,QI+=d<<8,tI+=L<<8,EI+=k<<8,nI+=b<<8,oI+=S<<8,rI+=Y<<8,sI+=q<<8,DI+=X<<8,yI+=V<<8,MI+=W<<8,pI+=j<<8,HI+=T<<8,t=65535&(B=397*t),e=65535&(i+=B>>>16),a=65535&(n+=i>>>16),h=65535&(o+=n>>>16),f=65535&(w+=o>>>16),c=65535&(D+=w>>>16),F=65535&(y+=D>>>16),u=65535&(M+=y>>>16),l=65535&(p+=M>>>16),G=65535&(H+=p>>>16),d=65535&(U+=H>>>16),L=65535&(m+=U>>>16),k=65535&(J+=m>>>16),b=65535&(N+=J>>>16),S=65535&(R+=N>>>16),Y=65535&(v+=R>>>16),q=65535&(P+=v>>>16),X=65535&(x+=P>>>16),V=65535&(Z+=x>>>16),W=65535&(K+=Z>>>16),j=65535&(O+=K>>>16),T=65535&(z+=O>>>16),$=65535&(_+=z>>>16),IA=65535&(AA+=_>>>16),CA=65535&(gA+=AA>>>16),BA=65535&(QA+=gA>>>16),iA=65535&(tA+=QA>>>16),eA=65535&(EA+=tA>>>16),aA=65535&(nA+=EA>>>16),hA=65535&(oA+=nA>>>16),wA=65535&(rA+=oA>>>16),fA=65535&(sA+=rA>>>16),cA=65535&(DA+=sA>>>16),FA=65535&(yA+=DA>>>16),uA=65535&(MA+=yA>>>16),lA=65535&(pA+=MA>>>16),GA=65535&(HA+=pA>>>16),dA=65535&(UA+=HA>>>16),LA=65535&(mA+=UA>>>16),kA=65535&(JA+=mA>>>16),bA=65535&(NA+=JA>>>16),SA=65535&(RA+=NA>>>16),YA=65535&(vA+=RA>>>16),qA=65535&(PA+=vA>>>16),XA=65535&(xA+=PA>>>16),VA=65535&(ZA+=xA>>>16),WA=65535&(KA+=ZA>>>16),jA=65535&(OA+=KA>>>16),TA=65535&(zA+=OA>>>16),$A=65535&(_A+=zA>>>16),II=65535&(AI+=_A>>>16),CI=65535&(gI+=AI>>>16),BI=65535&(QI+=gI>>>16),iI=65535&(tI+=QI>>>16),eI=65535&(EI+=tI>>>16),aI=65535&(nI+=EI>>>16),hI=65535&(oI+=nI>>>16),wI=65535&(rI+=oI>>>16),fI=65535&(sI+=rI>>>16),cI=65535&(DI+=sI>>>16),FI=65535&(yI+=DI>>>16),uI=65535&(MI+=yI>>>16),GI=HI+((pI+=MI>>>16)>>>16)&65535,lI=65535&pI,t^=63&I|128):(i=397*e,n=397*a,o=397*h,w=397*f,D=397*c,y=397*F,M=397*u,p=397*l,H=397*G,U=397*d,m=397*L,J=397*k,N=397*b,R=397*S,v=397*Y,P=397*q,x=397*X,Z=397*V,K=397*W,O=397*j,z=397*T,_=397*$,AA=397*IA,gA=397*CA,QA=397*BA,tA=397*iA,EA=397*eA,nA=397*aA,oA=397*hA,rA=397*wA,sA=397*fA,DA=397*cA,yA=397*FA,MA=397*uA,pA=397*lA,HA=397*GA,UA=397*dA,mA=397*LA,JA=397*kA,NA=397*bA,RA=397*SA,vA=397*YA,PA=397*qA,xA=397*XA,ZA=397*VA,KA=397*WA,OA=397*jA,zA=397*TA,_A=397*$A,AI=397*II,gI=397*CI,QI=397*BI,tI=397*iI,EI=397*eI,nI=397*aI,oI=397*hI,rI=397*wI,sI=397*fI,DI=397*cI,yI=397*FI,MI=397*uI,pI=397*lI,HI=397*GI,vA+=(t^=I>>12|224)<<8,PA+=e<<8,xA+=a<<8,ZA+=h<<8,KA+=f<<8,OA+=c<<8,zA+=F<<8,_A+=u<<8,AI+=l<<8,gI+=G<<8,QI+=d<<8,tI+=L<<8,EI+=k<<8,nI+=b<<8,oI+=S<<8,rI+=Y<<8,sI+=q<<8,DI+=X<<8,yI+=V<<8,MI+=W<<8,pI+=j<<8,t=65535&(B=397*t),GI=(HI+=T<<8)+((pI+=(MI+=(yI+=(DI+=(sI+=(rI+=(oI+=(nI+=(EI+=(tI+=(QI+=(gI+=(AI+=(_A+=(zA+=(OA+=(KA+=(ZA+=(xA+=(PA+=(vA+=(RA+=(NA+=(JA+=(mA+=(UA+=(HA+=(pA+=(MA+=(yA+=(DA+=(sA+=(rA+=(oA+=(nA+=(EA+=(tA+=(QA+=(gA+=(AA+=(_+=(z+=(O+=(K+=(Z+=(x+=(P+=(v+=(R+=(N+=(J+=(m+=(U+=(H+=(p+=(M+=(y+=(D+=(w+=(o+=(n+=(i+=B>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)>>>16)&65535,i=397*(e=65535&i),n=397*(a=65535&n),o=397*(h=65535&o),w=397*(f=65535&w),D=397*(c=65535&D),y=397*(F=65535&y),M=397*(u=65535&M),p=397*(l=65535&p),H=397*(G=65535&H),U=397*(d=65535&U),m=397*(L=65535&m),J=397*(k=65535&J),N=397*(b=65535&N),R=397*(S=65535&R),v=397*(Y=65535&v),P=397*(q=65535&P),x=397*(X=65535&x),Z=397*(V=65535&Z),K=397*(W=65535&K),O=397*(j=65535&O),z=397*(T=65535&z),_=397*($=65535&_),AA=397*(IA=65535&AA),gA=397*(CA=65535&gA),QA=397*(BA=65535&QA),tA=397*(iA=65535&tA),EA=397*(eA=65535&EA),nA=397*(aA=65535&nA),oA=397*(hA=65535&oA),rA=397*(wA=65535&rA),sA=397*(fA=65535&sA),DA=397*(cA=65535&DA),yA=397*(FA=65535&yA),MA=397*(uA=65535&MA),pA=397*(lA=65535&pA),HA=397*(GA=65535&HA),UA=397*(dA=65535&UA),mA=397*(LA=65535&mA),JA=397*(kA=65535&JA),NA=397*(bA=65535&NA),RA=397*(SA=65535&RA),vA=397*(YA=65535&vA),PA=397*(qA=65535&PA),xA=397*(XA=65535&xA),ZA=397*(VA=65535&ZA),KA=397*(WA=65535&KA),OA=397*(jA=65535&OA),zA=397*(TA=65535&zA),_A=397*($A=65535&_A),AI=397*(II=65535&AI),gI=397*(CI=65535&gI),QI=397*(BI=65535&QI),tI=397*(iI=65535&tI),EI=397*(eI=65535&EI),nI=397*(aI=65535&nI),oI=397*(hI=65535&oI),rI=397*(wI=65535&rI),sI=397*(fI=65535&sI),DI=397*(cI=65535&DI),yI=397*(FI=65535&yI),MI=397*(uI=65535&MI),pI=397*(lI=65535&pI),HI=397*GI,vA+=(t^=I>>6&63|128)<<8,PA+=e<<8,xA+=a<<8,ZA+=h<<8,KA+=f<<8,OA+=c<<8,zA+=F<<8,_A+=u<<8,AI+=l<<8,gI+=G<<8,QI+=d<<8,tI+=L<<8,EI+=k<<8,nI+=b<<8,oI+=S<<8,rI+=Y<<8,sI+=q<<8,DI+=X<<8,yI+=V<<8,MI+=W<<8,pI+=j<<8,HI+=T<<8,t=65535&(B=397*t),e=65535&(i+=B>>>16),a=65535&(n+=i>>>16),h=65535&(o+=n>>>16),f=65535&(w+=o>>>16),c=65535&(D+=w>>>16),F=65535&(y+=D>>>16),u=65535&(M+=y>>>16),l=65535&(p+=M>>>16),G=65535&(H+=p>>>16),d=65535&(U+=H>>>16),L=65535&(m+=U>>>16),k=65535&(J+=m>>>16),b=65535&(N+=J>>>16),S=65535&(R+=N>>>16),Y=65535&(v+=R>>>16),q=65535&(P+=v>>>16),X=65535&(x+=P>>>16),V=65535&(Z+=x>>>16),W=65535&(K+=Z>>>16),j=65535&(O+=K>>>16),T=65535&(z+=O>>>16),$=65535&(_+=z>>>16),IA=65535&(AA+=_>>>16),CA=65535&(gA+=AA>>>16),BA=65535&(QA+=gA>>>16),iA=65535&(tA+=QA>>>16),eA=65535&(EA+=tA>>>16),aA=65535&(nA+=EA>>>16),hA=65535&(oA+=nA>>>16),wA=65535&(rA+=oA>>>16),fA=65535&(sA+=rA>>>16),cA=65535&(DA+=sA>>>16),FA=65535&(yA+=DA>>>16),uA=65535&(MA+=yA>>>16),lA=65535&(pA+=MA>>>16),GA=65535&(HA+=pA>>>16),dA=65535&(UA+=HA>>>16),LA=65535&(mA+=UA>>>16),kA=65535&(JA+=mA>>>16),bA=65535&(NA+=JA>>>16),SA=65535&(RA+=NA>>>16),YA=65535&(vA+=RA>>>16),qA=65535&(PA+=vA>>>16),XA=65535&(xA+=PA>>>16),VA=65535&(ZA+=xA>>>16),WA=65535&(KA+=ZA>>>16),jA=65535&(OA+=KA>>>16),TA=65535&(zA+=OA>>>16),$A=65535&(_A+=zA>>>16),II=65535&(AI+=_A>>>16),CI=65535&(gI+=AI>>>16),BI=65535&(QI+=gI>>>16),iI=65535&(tI+=QI>>>16),eI=65535&(EI+=tI>>>16),aI=65535&(nI+=EI>>>16),hI=65535&(oI+=nI>>>16),wI=65535&(rI+=oI>>>16),fI=65535&(sI+=rI>>>16),cI=65535&(DI+=sI>>>16),FI=65535&(yI+=DI>>>16),uI=65535&(MI+=yI>>>16),GI=HI+((pI+=MI>>>16)>>>16)&65535,lI=65535&pI,t^=63&I|128);return s(E[GI>>8]+E[255&GI]+E[lI>>8]+E[255&lI]+E[uI>>8]+E[255&uI]+E[FI>>8]+E[255&FI]+E[cI>>8]+E[255&cI]+E[fI>>8]+E[255&fI]+E[wI>>8]+E[255&wI]+E[hI>>8]+E[255&hI]+E[aI>>8]+E[255&aI]+E[eI>>8]+E[255&eI]+E[iI>>8]+E[255&iI]+E[BI>>8]+E[255&BI]+E[CI>>8]+E[255&CI]+E[II>>8]+E[255&II]+E[$A>>8]+E[255&$A]+E[TA>>8]+E[255&TA]+E[jA>>8]+E[255&jA]+E[WA>>8]+E[255&WA]+E[VA>>8]+E[255&VA]+E[XA>>8]+E[255&XA]+E[qA>>8]+E[255&qA]+E[YA>>8]+E[255&YA]+E[SA>>8]+E[255&SA]+E[bA>>8]+E[255&bA]+E[kA>>8]+E[255&kA]+E[LA>>8]+E[255&LA]+E[dA>>8]+E[255&dA]+E[GA>>8]+E[255&GA]+E[lA>>8]+E[255&lA]+E[uA>>8]+E[255&uA]+E[FA>>8]+E[255&FA]+E[cA>>8]+E[255&cA]+E[fA>>8]+E[255&fA]+E[wA>>8]+E[255&wA]+E[hA>>8]+E[255&hA]+E[aA>>8]+E[255&aA]+E[eA>>8]+E[255&eA]+E[iA>>8]+E[255&iA]+E[BA>>8]+E[255&BA]+E[CA>>8]+E[255&CA]+E[IA>>8]+E[255&IA]+E[$>>8]+E[255&$]+E[T>>8]+E[255&T]+E[j>>8]+E[255&j]+E[W>>8]+E[255&W]+E[V>>8]+E[255&V]+E[X>>8]+E[255&X]+E[q>>8]+E[255&q]+E[Y>>8]+E[255&Y]+E[S>>8]+E[255&S]+E[b>>8]+E[255&b]+E[k>>8]+E[255&k]+E[L>>8]+E[255&L]+E[d>>8]+E[255&d]+E[G>>8]+E[255&G]+E[l>>8]+E[255&l]+E[u>>8]+E[255&u]+E[F>>8]+E[255&F]+E[c>>8]+E[255&c]+E[f>>8]+E[255&f]+E[h>>8]+E[255&h]+E[a>>8]+E[255&a]+E[e>>8]+E[255&e]+E[t>>8]+E[255&t],1024)}return I=u,g=G,C=L,Q=b,B=Y,t=X,i=W,y("1a"),F(!1),M(),{hash:c,setKeyspace:function(A){if(52!==A&&!r[A])throw new Error("Supported FNV keyspacs: 32, 52, 64, 128, 256, 512, and 1024 bit");h=A},version:y,useUTF8:F,seed:M,fast1a32:function(A){var I,g=A.length-3,C=0,Q=40389,B=0,t=33052;for(I=0;I>>16)&65535),B+=(Q^=A.charCodeAt(I++))<<8,Q=65535&(C=403*Q),B=403*(t=B+(C>>>16)&65535),B+=(Q^=A.charCodeAt(I++))<<8,Q=65535&(C=403*Q),B=403*(t=B+(C>>>16)&65535),t=(B+=(Q^=A.charCodeAt(I++))<<8)+((C=403*Q)>>>16)&65535,Q=65535&C;for(;I>>16)&65535,Q=65535&C;return(t<<16>>>0)+Q},fast1a32hex:function(A){var I,g=A.length-3,C=0,Q=40389,B=0,t=33052;for(I=0;I>>16)&65535),B+=(Q^=A.charCodeAt(I++))<<8,Q=65535&(C=403*Q),B=403*(t=B+(C>>>16)&65535),B+=(Q^=A.charCodeAt(I++))<<8,Q=65535&(C=403*Q),B=403*(t=B+(C>>>16)&65535),t=(B+=(Q^=A.charCodeAt(I++))<<8)+((C=403*Q)>>>16)&65535,Q=65535&C;for(;I>>16)&65535,Q=65535&C;return E[t>>>8&255]+E[255&t]+E[Q>>>8&255]+E[255&Q]},fast1a52:function(A){var I,g=A.length-3,C=0,Q=8997,B=0,t=33826,i=0,E=40164,e=0,n=52210;for(I=0;I>>16)>>>16)>>>16)&65535,B=435*(t=65535&B),i=435*(E=65535&i),e=435*n,i+=(Q^=A.charCodeAt(I++))<<8,Q=65535&(C=435*Q),n=(e+=t<<8)+((i+=(B+=C>>>16)>>>16)>>>16)&65535,B=435*(t=65535&B),i=435*(E=65535&i),e=435*n,i+=(Q^=A.charCodeAt(I++))<<8,Q=65535&(C=435*Q),n=(e+=t<<8)+((i+=(B+=C>>>16)>>>16)>>>16)&65535,B=435*(t=65535&B),i=435*(E=65535&i),e=435*n,i+=(Q^=A.charCodeAt(I++))<<8,e+=t<<8,Q=65535&(C=435*Q),t=65535&(B+=C>>>16),n=e+((i+=B>>>16)>>>16)&65535,E=65535&i;for(;I>>16),n=e+((i+=B>>>16)>>>16)&65535,E=65535&i;return 281474976710656*(15&n)+4294967296*E+65536*t+(Q^n>>4)},fast1a52hex:function(A){var I,g=A.length-3,C=0,Q=8997,B=0,t=33826,i=0,n=40164,a=0,o=52210;for(I=0;I>>16)>>>16)>>>16)&65535,B=435*(t=65535&B),i=435*(n=65535&i),a=435*o,i+=(Q^=A.charCodeAt(I++))<<8,Q=65535&(C=435*Q),o=(a+=t<<8)+((i+=(B+=C>>>16)>>>16)>>>16)&65535,B=435*(t=65535&B),i=435*(n=65535&i),a=435*o,i+=(Q^=A.charCodeAt(I++))<<8,Q=65535&(C=435*Q),o=(a+=t<<8)+((i+=(B+=C>>>16)>>>16)>>>16)&65535,B=435*(t=65535&B),i=435*(n=65535&i),a=435*o,i+=(Q^=A.charCodeAt(I++))<<8,a+=t<<8,Q=65535&(C=435*Q),t=65535&(B+=C>>>16),o=a+((i+=B>>>16)>>>16)&65535,n=65535&i;for(;I>>16),o=a+((i+=B>>>16)>>>16)&65535,n=65535&i;return e[15&o]+E[n>>8]+E[255&n]+E[t>>8]+E[255&t]+E[Q>>8^o>>12]+E[255&(Q^o>>4)]},fast1a64:function(A){var I,g=A.length-3,C=0,Q=8997,B=0,t=33826,i=0,e=40164,n=0,a=52210;for(I=0;I>>16)>>>16)>>>16)&65535,B=435*(t=65535&B),i=435*(e=65535&i),n=435*a,i+=(Q^=A.charCodeAt(I++))<<8,Q=65535&(C=435*Q),a=(n+=t<<8)+((i+=(B+=C>>>16)>>>16)>>>16)&65535,B=435*(t=65535&B),i=435*(e=65535&i),n=435*a,i+=(Q^=A.charCodeAt(I++))<<8,Q=65535&(C=435*Q),a=(n+=t<<8)+((i+=(B+=C>>>16)>>>16)>>>16)&65535,B=435*(t=65535&B),i=435*(e=65535&i),n=435*a,i+=(Q^=A.charCodeAt(I++))<<8,n+=t<<8,Q=65535&(C=435*Q),t=65535&(B+=C>>>16),a=n+((i+=B>>>16)>>>16)&65535,e=65535&i;for(;I>>16),a=n+((i+=B>>>16)>>>16)&65535,e=65535&i;return E[a>>8]+E[255&a]+E[e>>8]+E[255&e]+E[t>>8]+E[255&t]+E[Q>>8]+E[255&Q]},fast1a32utf:function(A){var I,g,C=A.length,Q=0,B=40389,t=0,i=33052;for(g=0;g>6|192)<<8)+((Q=403*B)>>>16)&65535,B=65535&Q,B^=63&I|128):55296==(64512&I)&&g+1>18|240)<<8,B=65535&(Q=403*B),t=403*(i=t+(Q>>>16)&65535),t+=(B^=I>>12&63|128)<<8,B=65535&(Q=403*B),t=403*(i=t+(Q>>>16)&65535),i=(t+=(B^=I>>6&63|128)<<8)+((Q=403*B)>>>16)&65535,B=65535&Q,B^=63&I|128):(t=403*i,t+=(B^=I>>12|224)<<8,B=65535&(Q=403*B),t=403*(i=t+(Q>>>16)&65535),i=(t+=(B^=I>>6&63|128)<<8)+((Q=403*B)>>>16)&65535,B=65535&Q,B^=63&I|128),t=403*i,i=(t+=B<<8)+((Q=403*B)>>>16)&65535,B=65535&Q;return(i<<16>>>0)+B},fast1a32hexutf:function(A){var I,g,C=A.length,Q=0,B=40389,t=0,i=33052;for(g=0;g>6|192)<<8)+((Q=403*B)>>>16)&65535,B=65535&Q,B^=63&I|128):55296==(64512&I)&&g+1>18|240)<<8,B=65535&(Q=403*B),t=403*(i=t+(Q>>>16)&65535),t+=(B^=I>>12&63|128)<<8,B=65535&(Q=403*B),t=403*(i=t+(Q>>>16)&65535),i=(t+=(B^=I>>6&63|128)<<8)+((Q=403*B)>>>16)&65535,B=65535&Q,B^=63&I|128):(t=403*i,t+=(B^=I>>12|224)<<8,B=65535&(Q=403*B),t=403*(i=t+(Q>>>16)&65535),i=(t+=(B^=I>>6&63|128)<<8)+((Q=403*B)>>>16)&65535,B=65535&Q,B^=63&I|128),t=403*i,i=(t+=B<<8)+((Q=403*B)>>>16)&65535,B=65535&Q;return E[i>>>8&255]+E[255&i]+E[B>>>8&255]+E[255&B]},fast1a52utf:function(A){var I,g,C=A.length,Q=0,B=8997,t=0,i=33826,E=0,e=40164,n=0,a=52210;for(g=0;g>6|192)<<8,n+=i<<8,B=65535&(Q=435*B),i=65535&(t+=Q>>>16),a=n+((E+=t>>>16)>>>16)&65535,e=65535&E,B^=63&I|128):55296==(64512&I)&&g+1>18|240)<<8,B=65535&(Q=435*B),a=(n+=i<<8)+((E+=(t+=Q>>>16)>>>16)>>>16)&65535,t=435*(i=65535&t),E=435*(e=65535&E),n=435*a,E+=(B^=I>>12&63|128)<<8,B=65535&(Q=435*B),a=(n+=i<<8)+((E+=(t+=Q>>>16)>>>16)>>>16)&65535,t=435*(i=65535&t),E=435*(e=65535&E),n=435*a,E+=(B^=I>>6&63|128)<<8,n+=i<<8,B=65535&(Q=435*B),i=65535&(t+=Q>>>16),a=n+((E+=t>>>16)>>>16)&65535,e=65535&E,B^=63&I|128):(t=435*i,E=435*e,n=435*a,E+=(B^=I>>12|224)<<8,B=65535&(Q=435*B),a=(n+=i<<8)+((E+=(t+=Q>>>16)>>>16)>>>16)&65535,t=435*(i=65535&t),E=435*(e=65535&E),n=435*a,E+=(B^=I>>6&63|128)<<8,n+=i<<8,B=65535&(Q=435*B),i=65535&(t+=Q>>>16),a=n+((E+=t>>>16)>>>16)&65535,e=65535&E,B^=63&I|128),t=435*i,E=435*e,n=435*a,E+=B<<8,n+=i<<8,B=65535&(Q=435*B),i=65535&(t+=Q>>>16),a=n+((E+=t>>>16)>>>16)&65535,e=65535&E;return 281474976710656*(15&a)+4294967296*e+65536*i+(B^a>>4)},fast1a52hexutf:function(A){var I,g,C=A.length,Q=0,B=8997,t=0,i=33826,n=0,a=40164,o=0,h=52210;for(g=0;g>6|192)<<8,o+=i<<8,B=65535&(Q=435*B),i=65535&(t+=Q>>>16),h=o+((n+=t>>>16)>>>16)&65535,a=65535&n,B^=63&I|128):55296==(64512&I)&&g+1>18|240)<<8,B=65535&(Q=435*B),h=(o+=i<<8)+((n+=(t+=Q>>>16)>>>16)>>>16)&65535,t=435*(i=65535&t),n=435*(a=65535&n),o=435*h,n+=(B^=I>>12&63|128)<<8,B=65535&(Q=435*B),h=(o+=i<<8)+((n+=(t+=Q>>>16)>>>16)>>>16)&65535,t=435*(i=65535&t),n=435*(a=65535&n),o=435*h,n+=(B^=I>>6&63|128)<<8,o+=i<<8,B=65535&(Q=435*B),i=65535&(t+=Q>>>16),h=o+((n+=t>>>16)>>>16)&65535,a=65535&n,B^=63&I|128):(t=435*i,n=435*a,o=435*h,n+=(B^=I>>12|224)<<8,B=65535&(Q=435*B),h=(o+=i<<8)+((n+=(t+=Q>>>16)>>>16)>>>16)&65535,t=435*(i=65535&t),n=435*(a=65535&n),o=435*h,n+=(B^=I>>6&63|128)<<8,o+=i<<8,B=65535&(Q=435*B),i=65535&(t+=Q>>>16),h=o+((n+=t>>>16)>>>16)&65535,a=65535&n,B^=63&I|128),t=435*i,n=435*a,o=435*h,n+=B<<8,o+=i<<8,B=65535&(Q=435*B),i=65535&(t+=Q>>>16),h=o+((n+=t>>>16)>>>16)&65535,a=65535&n;return e[15&h]+E[a>>8]+E[255&a]+E[i>>8]+E[255&i]+E[B>>8^h>>12]+E[255&(B^h>>4)]},fast1a64utf:function(A){var I,g,C=A.length,Q=0,B=8997,t=0,i=33826,e=0,n=40164,a=0,o=52210;for(g=0;g>6|192)<<8,a+=i<<8,B=65535&(Q=435*B),i=65535&(t+=Q>>>16),o=a+((e+=t>>>16)>>>16)&65535,n=65535&e,B^=63&I|128):55296==(64512&I)&&g+1>18|240)<<8,B=65535&(Q=435*B),o=(a+=i<<8)+((e+=(t+=Q>>>16)>>>16)>>>16)&65535,t=435*(i=65535&t),e=435*(n=65535&e),a=435*o,e+=(B^=I>>12&63|128)<<8,B=65535&(Q=435*B),o=(a+=i<<8)+((e+=(t+=Q>>>16)>>>16)>>>16)&65535,t=435*(i=65535&t),e=435*(n=65535&e),a=435*o,e+=(B^=I>>6&63|128)<<8,a+=i<<8,B=65535&(Q=435*B),i=65535&(t+=Q>>>16),o=a+((e+=t>>>16)>>>16)&65535,n=65535&e,B^=63&I|128):(t=435*i,e=435*n,a=435*o,e+=(B^=I>>12|224)<<8,B=65535&(Q=435*B),o=(a+=i<<8)+((e+=(t+=Q>>>16)>>>16)>>>16)&65535,t=435*(i=65535&t),e=435*(n=65535&e),a=435*o,e+=(B^=I>>6&63|128)<<8,a+=i<<8,B=65535&(Q=435*B),i=65535&(t+=Q>>>16),o=a+((e+=t>>>16)>>>16)&65535,n=65535&e,B^=63&I|128),t=435*i,e=435*n,a=435*o,e+=B<<8,a+=i<<8,B=65535&(Q=435*B),i=65535&(t+=Q>>>16),o=a+((e+=t>>>16)>>>16)&65535,n=65535&e;return E[o>>8]+E[255&o]+E[n>>8]+E[255&n]+E[i>>8]+E[255&i]+E[B>>8]+E[255&B]}}}();A.exports=I}));async function lg(A,I){I=I||{};let g,C=32767,Q=!1;for(;!Q;)try{g=new WebAssembly.Memory({initial:C}),Q=!0}catch(A){if(1===C)throw A;console.warn("Could not allocate "+1024*C*64+" bytes. This may cause severe instability. Trying with "+1024*C*64/2+" bytes"),C=Math.floor(C/2)}const B=await WebAssembly.compile(A);let t;const i=await WebAssembly.instantiate(B,{env:{memory:g},runtime:{error:function(A,g,C,Q,B,i){let E;throw E=7==A?e(g)+" "+t.getFr(Q).toString()+" != "+t.getFr(B).toString()+" "+e(i):9==A?e(g)+" "+t.getFr(Q).toString()+" "+e(B):5==A&&I.sym?e(g)+" "+I.sym.labelIdx2Name[B]:e(g)+" "+C+" "+Q+" "+B+" "+i,console.log("ERROR: ",A,E),new Error(E)},log:function(A){console.log(t.getFr(A).toString())},logGetSignal:function(A,g){I.logGetSignal&&I.logGetSignal(A,t.getFr(g))},logSetSignal:function(A,g){I.logSetSignal&&I.logSetSignal(A,t.getFr(g))},logStartComponent:function(A){I.logStartComponent&&I.logStartComponent(A)},logFinishComponent:function(A){I.logFinishComponent&&I.logFinishComponent(A)}}}),E=I&&(I.sanityCheck||I.logGetSignal||I.logSetSignal||I.logStartComponent||I.logFinishComponent);return t=new Hg(g,i,E),t;function e(A){const I=new Uint8Array(g.buffer),C=[];for(let g=0;I[A+g]>0;g++)C.push(I[A+g]);return String.fromCharCode.apply(null,C)}}class Hg{constructor(A,I,g){this.memory=A,this.i32=new Uint32Array(A.buffer),this.instance=I,this.n32=(this.instance.exports.getFrLen()>>2)-2;const C=this.instance.exports.getPRawPrime(),Q=new Array(this.n32);for(let A=0;A>2)+A];this.prime=rI.fromArray(Q,4294967296),this.Fr=new HA(this.prime),this.mask32=rI.fromString("FFFFFFFF",16),this.NVars=this.instance.exports.getNVars(),this.n64=Math.floor((this.Fr.bitLength-1)/64)+1,this.R=this.Fr.e(rI.shiftLeft(1,64*this.n64)),this.RInv=this.Fr.inv(this.R),this.sanityCheck=g}async _doCalculateWitness(A,I){this.instance.exports.init(this.sanityCheck||I?1:0);const g=this.allocInt(),C=this.allocFr();Object.keys(A).forEach((I=>{const Q=function(A){return pg.hash(A,64).hex()}(I),B=parseInt(Q.slice(0,8),16),t=parseInt(Q.slice(8,16),16);try{this.instance.exports.getSignalOffset32(g,0,B,t)}catch(A){throw new Error(`Signal ${I} is not an input of the circuit.`)}const i=this.getInt(g),E=(e=A[I],function A(I,g){if(Array.isArray(g))for(let C=0;C>2]}setInt(A,I){this.i32[A>>2]=I}getFr(A){const I=this,g=A>>2;if(2147483648&I.i32[g+1]){const A=new Array(I.n32);for(let C=0;C>2]=Q,void(g.i32[1+(A>>2)]=0)}g.i32[A>>2]=0,g.i32[1+(A>>2)]=2147483648;const B=rI.toArray(I,4294967296);for(let I=0;I>2)+I]=C>=0?B[C]:0}}}async function Gg(A,I,g,C){const Q=await LI(I),B=await Q.read(Q.totalSize);await Q.close();const t=await lg(B),i=await t.calculateBinWitness(A),E=await kI(g,"wtns",2,2);await async function(A,I,g){await NI(A,1);const C=8*(Math.floor((rI.bitLength(g)-1)/64)+1);if(await A.writeULE32(C),await vI(A,g,C),I.byteLength%C!=0)throw new Error("Invalid witness length");await A.writeULE32(I.byteLength/C),await bI(A),await NI(A,2),await A.write(I),await bI(A)}(E,i,t.prime),await E.close()}const{unstringifyBigInts:Ug}=wI;var dg=Object.freeze({__proto__:null,fullProve:async function(A,I,g,C){const Q={type:"mem"};return await Gg(A,I,Q),await ug(g,Q,C)},prove:ug,verify:async function(A,I,g,C){A=Ug(A),g=Ug(g),I=Ug(I);const Q=await async function(A){let I;const g=A.toUpperCase().match(/[A-Za-z0-9]+/g).join("");if(["BN128","BN254","ALTBN128"].indexOf(g)>=0)I=await nI();else{if(!(["BLS12381"].indexOf(g)>=0))throw new Error(`Curve not supported: ${A}`);I=await aI()}return I}(A.curve),B=Q.G1.fromObject(A.IC[0]),t=new Uint8Array(2*Q.G1.F.n8*I.length),i=new Uint8Array(Q.Fr.n8*I.length);for(let g=0;g1)throw new Error(A.fileName+": File has more than one header");A.pos=I[1][0].p;const g=await A.readULE32(),C=await A.read(g),Q=rI.fromRprLE(C),B=await VI(Q);if(8*B.F1.n64!=g)throw new Error(A.fileName+": Invalid size");const t=await A.readULE32(),i=await A.readULE32();if(A.pos-I[1][0].p!=I[1][0].size)throw new Error("Invalid PTau header size");return{curve:B,power:t,ceremonyPower:i}}function Rg(A,I,g,C){const Q={tau:{},alpha:{},beta:{}};return Q.tau.g1_s=B(),Q.tau.g1_sx=B(),Q.alpha.g1_s=B(),Q.alpha.g1_sx=B(),Q.beta.g1_s=B(),Q.beta.g1_sx=B(),Q.tau.g2_spx=t(),Q.alpha.g2_spx=t(),Q.beta.g2_spx=t(),Q;function B(){let Q;return Q=C?g.G1.fromRprLEM(A,I):g.G1.fromRprUncompressed(A,I),I+=2*g.G1.F.n8,Q}function t(){let Q;return Q=C?g.G2.fromRprLEM(A,I):g.G2.fromRprUncompressed(A,I),I+=2*g.G2.F.n8,Q}}function Sg(A,I,g,C,Q){async function B(C){Q?g.G1.toRprLEM(A,I,C):g.G1.toRprUncompressed(A,I,C),I+=2*g.F1.n8}async function t(C){Q?g.G2.toRprLEM(A,I,C):g.G2.toRprUncompressed(A,I,C),I+=2*g.F2.n8}return B(C.tau.g1_s),B(C.tau.g1_sx),B(C.alpha.g1_s),B(C.alpha.g1_sx),B(C.beta.g1_s),B(C.beta.g1_sx),t(C.tau.g2_spx),t(C.alpha.g2_spx),t(C.beta.g2_spx),A}async function vg(A,I){const g={};g.tauG1=await E(),g.tauG2=await e(),g.alphaG1=await E(),g.betaG1=await E(),g.betaG2=await e(),g.key=await async function(A,I,g){return Rg(await A.read(2*I.F1.n8*6+2*I.F2.n8*3),0,I,g)}(A,I,!0),g.partialHash=await A.read(216),g.nextChallenge=await A.read(64),g.type=await A.readULE32();const C=new Uint8Array(2*I.G1.F.n8*6+2*I.G2.F.n8*3);Sg(C,0,I,g.key,!1);const Q=TI(64);Q.setPartialHash(g.partialHash),Q.update(C),g.responseHash=Q.digest();const B=await A.readULE32(),t=A.pos;let i=0;for(;A.pos-t1)throw new Error(A.fileName+": File has more than one contributions section");A.pos=g[7][0].p;const C=await A.readULE32(),Q=[];for(let g=0;g0){const I=new Uint8Array(B);await A.writeULE32(I.byteLength),await A.write(I)}else await A.writeULE32(0);async function t(g){I.G1.toRprLEM(C,0,g),await A.write(C)}async function i(g){I.G2.toRprLEM(Q,0,g),await A.write(Q)}}async function qg(A,I,g){await A.writeULE32(7);const C=A.pos;await A.writeULE64(0),await A.writeULE32(g.length);for(let C=0;C0?a[a.length-1].nextChallenge:xg(e,n,B);const c=await kI(g,"ptau",1,Q?7:2);await Ng(c,e,n);const y=await f.read(64);if(gg(t,D)&&(D=y,a[a.length-1].nextChallenge=D),!gg(y,D))throw new Error("Wrong contribution. this contribution is not based on the previus hash");const F=new TI(64);F.update(y);const M=[];let u;u=await H(f,c,"G1",2,2**n*2-1,[1],"tauG1"),o.tauG1=u[0],u=await H(f,c,"G2",3,2**n,[1],"tauG2"),o.tauG2=u[0],u=await H(f,c,"G1",4,2**n,[0],"alphaG1"),o.alphaG1=u[0],u=await H(f,c,"G1",5,2**n,[0],"betaG1"),o.betaG1=u[0],u=await H(f,c,"G2",6,1,[0],"betaG2"),o.betaG2=u[0],o.partialHash=F.getPartialHash();const p=await f.read(2*e.F1.n8*6+2*e.F2.n8*3);o.key=Rg(p,0,e,!1),F.update(new Uint8Array(p));const l=F.digest();if(B&&B.info(Ig(l,"Contribution Response Hash imported: ")),Q){const A=new TI(64);A.update(l),await G(A,c,"G1",2,2**n*2-1,"tauG1",B),await G(A,c,"G2",3,2**n,"tauG2",B),await G(A,c,"G1",4,2**n,"alphaTauG1",B),await G(A,c,"G1",5,2**n,"betaTauG1",B),await G(A,c,"G2",6,1,"betaG2",B),o.nextChallenge=A.digest(),B&&B.info(Ig(o.nextChallenge,"Next Challenge Hash: "))}else o.nextChallenge=t;return a.push(o),await qg(c,e,a),await f.close(),await c.close(),await i.close(),o.nextChallenge;async function H(A,I,g,C,t,i,E){return Q?await async function(A,I,g,C,Q,t,i){const E=e[g],n=E.F.n8,a=2*E.F.n8,o=[];await NI(I,C);const h=Math.floor((1<<24)/a);M[C]=I.pos;for(let g=0;g=g&&I=I&&Q1?E[E.length-2]:e;const a=E[E.length-1];if(I&&I.debug("Validating contribution #"+E[E.length-1].id),!await Vg(B,a,n,I))return!1;const o=TI(64);o.update(a.responseHash),I&&I.debug("Verifying powers in tau*G1 section");const h=await y(2,"G1","tauG1",2**t*2-1,[0,1],I);if(g=await Zg(B,h.R1,h.R2,B.G2.g,a.tauG2),!0!==g)return I&&I.error("tauG1 section. Powers do not match"),!1;if(!B.G1.eq(B.G1.g,h.singularPoints[0]))return I&&I.error("First element of tau*G1 section must be the generator"),!1;if(!B.G1.eq(a.tauG1,h.singularPoints[1]))return I&&I.error("Second element of tau*G1 section does not match the one in the contribution section"),!1;I&&I.debug("Verifying powers in tau*G2 section");const r=await y(3,"G2","tauG2",2**t,[0,1],I);if(g=await Zg(B,B.G1.g,a.tauG1,r.R1,r.R2),!0!==g)return I&&I.error("tauG2 section. Powers do not match"),!1;if(!B.G2.eq(B.G2.g,r.singularPoints[0]))return I&&I.error("First element of tau*G2 section must be the generator"),!1;if(!B.G2.eq(a.tauG2,r.singularPoints[1]))return I&&I.error("Second element of tau*G2 section does not match the one in the contribution section"),!1;I&&I.debug("Verifying powers in alpha*tau*G1 section");const w=await y(4,"G1","alphatauG1",2**t,[0],I);if(g=await Zg(B,w.R1,w.R2,B.G2.g,a.tauG2),!0!==g)return I&&I.error("alphaTauG1 section. Powers do not match"),!1;if(!B.G1.eq(a.alphaG1,w.singularPoints[0]))return I&&I.error("First element of alpha*tau*G1 section (alpha*G1) does not match the one in the contribution section"),!1;I&&I.debug("Verifying powers in beta*tau*G1 section");const s=await y(5,"G1","betatauG1",2**t,[0],I);if(g=await Zg(B,s.R1,s.R2,B.G2.g,a.tauG2),!0!==g)return I&&I.error("betaTauG1 section. Powers do not match"),!1;if(!B.G1.eq(a.betaG1,s.singularPoints[0]))return I&&I.error("First element of beta*tau*G1 section (beta*G1) does not match the one in the contribution section"),!1;const f=await async function(A){const I=B.G2,g=2*I.F.n8,t=new Uint8Array(g);if(!Q[6])throw A.error("File has no BetaG2 section"),new Error("File has no BetaG2 section");if(Q[6].length>1)throw A.error("File has no BetaG2 section"),new Error("File has more than one GetaG2 section");C.pos=Q[6][0].p;const i=await C.read(g),E=I.fromRprLEM(i);return I.toRprUncompressed(t,0,E),o.update(t),E}(I);if(!B.G2.eq(a.betaG2,f))return I&&I.error("betaG2 element in betaG2 section does not match the one in the contribution section"),!1;const D=o.digest();if(t==i&&!gg(D,a.nextChallenge))return I&&I.error("Hash of the values does not match the next challenge of the last contributor in the contributions section"),!1;I&&I.info(Ig(D,"Next challenge hash: ")),c(a,n);for(let A=E.length-2;A>=0;A--){const g=E[A],C=A>0?E[A-1]:e;if(!await Vg(B,g,C,I))return!1;c(g,C)}if(I&&I.info("-----------------------------------------------------"),Q[12]&&Q[13]&&Q[14]&&Q[15]){let A;if(A=await F("G1",2,12,"tauG1",I),!A)return!1;if(A=await F("G2",3,13,"tauG2",I),!A)return!1;if(A=await F("G1",4,14,"alphaTauG1",I),!A)return!1;if(A=await F("G1",5,15,"betaTauG1",I),!A)return!1}else I&&I.warn('this file does not contain phase2 precalculated values. Please run: \n snarkjs "powersoftau preparephase2" to prepare this file to be used in the phase2 ceremony.');return await C.close(),I&&I.info("Powers of Tau Ok!"),!0;function c(A,g){if(!I)return;I.info("-----------------------------------------------------"),I.info(`Contribution #${A.id}: ${A.name||""}`),I.info(Ig(A.nextChallenge,"Next Challenge: "));const C=new Uint8Array(2*B.G1.F.n8*6+2*B.G2.F.n8*3);Sg(C,0,B,A.key,!1);const Q=TI(64);Q.setPartialHash(A.partialHash),Q.update(C);const t=Q.digest();I.info(Ig(t,"Response Hash:")),I.info(Ig(g.nextChallenge,"Response Hash:")),1==A.type&&(I.info(`Beacon generator: ${Eg(A.beaconHash)}`),I.info(`Beacon iterations Exp: ${A.numIterationsExp}`))}async function y(A,I,g,t,i,E){const e=B[I],n=2*e.F.n8;await RI(C,Q,A);const a=[];let h=e.zero,r=e.zero,w=e.zero;for(let A=0;A0){const A=e.fromRprLEM(Q,0),I=DA.randomBytes(4).readUInt32BE(0,!0);h=e.add(h,e.timesScalar(w,I)),r=e.add(r,e.timesScalar(A,I))}const f=await e.multiExpAffine(Q.slice(0,(I-1)*n),s),D=await e.multiExpAffine(Q.slice(n),s);h=e.add(h,f),r=e.add(r,D),w=e.fromRprLEM(Q,(I-1)*n);for(let g=0;g=A&&C1;)e/=2,n+=1;if(2**n!=E)throw new Error("Invalid file size");Q&&Q.debug("Power to tau size: "+n);const a=await Bg(C),o=await mI(g),h=TI(64);for(let A=0;A{Q.debug(I+".g1_s: "+A.G1.toString(s[I].g1_s,16)),Q.debug(I+".g1_sx: "+A.G1.toString(s[I].g1_sx,16)),Q.debug(I+".g2_sp: "+A.G2.toString(s[I].g2_sp,16)),Q.debug(I+".g2_spx: "+A.G2.toString(s[I].g2_spx,16)),Q.debug("")}));const f=TI(64);await o.write(w),f.update(w),await Wg(B,o,f,A,"G1",2**n*2-1,A.Fr.one,s.tau.prvKey,"COMPRESSED","tauG1",Q),await Wg(B,o,f,A,"G2",2**n,A.Fr.one,s.tau.prvKey,"COMPRESSED","tauG2",Q),await Wg(B,o,f,A,"G1",2**n,s.alpha.prvKey,s.tau.prvKey,"COMPRESSED","alphaTauG1",Q),await Wg(B,o,f,A,"G1",2**n,s.beta.prvKey,s.tau.prvKey,"COMPRESSED","betaTauG1",Q),await Wg(B,o,f,A,"G2",1,s.beta.prvKey,s.tau.prvKey,"COMPRESSED","betaTauG2",Q);const D=new Uint8Array(2*A.F1.n8*6+2*A.F2.n8*3);Sg(D,0,A,s,!1),await o.write(D),f.update(D);const c=f.digest();Q&&Q.info(Ig(c,"Contribution Response Hash: ")),await o.close(),await B.close()},beacon:async function(A,I,g,C,Q,B){const t=ig(C);if(0==t.byteLength||2*t.byteLength!=C.length)return B&&B.error("Invalid Beacon Hash. (It must be a valid hexadecimal sequence)"),!1;if(t.length>=256)return B&&B.error("Maximum lenght of beacon hash is 255 bytes"),!1;if((Q=parseInt(Q))<10||Q>63)return B&&B.error("Invalid numIterationsExp. (Must be between 10 and 63)"),!1;await TI.ready();const{fd:i,sections:E}=await JI(A,"ptau",1),{curve:e,power:n,ceremonyPower:a}=await bg(i,E);if(n!=a)return B&&B.error("This file has been reduced. You cannot contribute into a reduced file."),!1;E[12]&&B&&B.warn("Contributing into a file that has phase2 calculated. You will have to prepare phase2 again.");const o=await Yg(i,e,E),h={name:g,type:1,numIterationsExp:Q,beaconHash:t};let r;r=o.length>0?o[o.length-1].nextChallenge:xg(e,n,B),h.key=Xg(e,r,t,Q);const w=new TI(64);w.update(r);const s=await kI(I,"ptau",1,7);await Ng(s,e,n);const f=[];let D;D=await M(2,"G1",2**n*2-1,e.Fr.e(1),h.key.tau.prvKey,"tauG1",B),h.tauG1=D[1],D=await M(3,"G2",2**n,e.Fr.e(1),h.key.tau.prvKey,"tauG2",B),h.tauG2=D[1],D=await M(4,"G1",2**n,h.key.alpha.prvKey,h.key.tau.prvKey,"alphaTauG1",B),h.alphaG1=D[0],D=await M(5,"G1",2**n,h.key.beta.prvKey,h.key.tau.prvKey,"betaTauG1",B),h.betaG1=D[0],D=await M(6,"G2",1,h.key.beta.prvKey,h.key.tau.prvKey,"betaTauG2",B),h.betaG2=D[0],h.partialHash=w.getPartialHash();const c=new Uint8Array(2*e.F1.n8*6+2*e.F2.n8*3);Sg(c,0,e,h.key,!1),w.update(new Uint8Array(c));const y=w.digest();B&&B.info(Ig(y,"Contribution Response Hash imported: "));const F=new TI(64);return F.update(y),await u(s,"G1",2,2**n*2-1,"tauG1",B),await u(s,"G2",3,2**n,"tauG2",B),await u(s,"G1",4,2**n,"alphaTauG1",B),await u(s,"G1",5,2**n,"betaTauG1",B),await u(s,"G2",6,1,"betaG2",B),h.nextChallenge=F.digest(),B&&B.info(Ig(h.nextChallenge,"Next Challenge Hash: ")),o.push(h),await qg(s,e,o),await i.close(),await s.close(),y;async function M(A,I,g,C,Q,B,t){const n=[];i.pos=E[A][0].p,await NI(s,A),f[A]=s.pos;const a=e[I],o=2*a.F.n8,h=Math.floor((1<<20)/o);let r=C;for(let A=0;A0?n[n.length-1].nextChallenge:xg(i,E,Q),a.key=kg(i,o,h);const r=new TI(64);r.update(o);const w=await kI(I,"ptau",1,7);await Ng(w,i,E);const s=[];let f;f=await F(2,"G1",2**E*2-1,i.Fr.e(1),a.key.tau.prvKey,"tauG1"),a.tauG1=f[1],f=await F(3,"G2",2**E,i.Fr.e(1),a.key.tau.prvKey,"tauG2"),a.tauG2=f[1],f=await F(4,"G1",2**E,a.key.alpha.prvKey,a.key.tau.prvKey,"alphaTauG1"),a.alphaG1=f[0],f=await F(5,"G1",2**E,a.key.beta.prvKey,a.key.tau.prvKey,"betaTauG1"),a.betaG1=f[0],f=await F(6,"G2",1,a.key.beta.prvKey,a.key.tau.prvKey,"betaTauG2"),a.betaG2=f[0],a.partialHash=r.getPartialHash();const D=new Uint8Array(2*i.F1.n8*6+2*i.F2.n8*3);Sg(D,0,i,a.key,!1),r.update(new Uint8Array(D));const c=r.digest();Q&&Q.info(Ig(c,"Contribution Response Hash imported: "));const y=new TI(64);return y.update(c),await M(w,"G1",2,2**E*2-1,"tauG1"),await M(w,"G2",3,2**E,"tauG2"),await M(w,"G1",4,2**E,"alphaTauG1"),await M(w,"G1",5,2**E,"betaTauG1"),await M(w,"G2",6,1,"betaG2"),a.nextChallenge=y.digest(),Q&&Q.info(Ig(a.nextChallenge,"Next Challenge Hash: ")),n.push(a),await qg(w,i,n),await B.close(),await w.close(),c;async function F(A,I,g,C,E,e){const n=[];B.pos=t[A][0].p,await NI(w,A),s[A]=w.pos;const a=i[I],o=2*a.F.n8,h=Math.floor((1<<20)/o);let f=C;for(let A=0;A=this.length&&(this.length=A+1),!0}getKeys(){const A=new _g;for(let I=0;I1<<20?new _g:[];for(let A=0;A1<<20?new _g:[];for(let A=0;A{g[C]=CC(A,I[C])})),g}return"bigint"==typeof I||void 0!==I.eq?I.toString(10):I}var QC=Object.freeze({__proto__:null,print:function(A,I,g){for(let I=0;I{let C="";return Object.keys(g).forEach((Q=>{let B=I.varIdx2Name[Q];"one"==B&&(B="");let t=A.curve.Fr.toString(g[Q]);"1"==t&&(t=""),"-1"==t&&(t="-"),""!=C&&"-"!=t[0]&&(t="+"+t),""!=C&&(t=" "+t),C=C+t+B})),C},B=`[ ${Q(C[0])} ] * [ ${Q(C[1])} ] - [ ${Q(C[2])} ] = 0`;g&&g.info(B)}},info:async function(A,I){const g=await AC(A);return rI.eq(g.prime,gC)?I&&I.info("Curve: bn-128"):rI.eq(g.prime,IC)?I&&I.info("Curve: bls12-381"):I&&I.info(`Unknown Curve. Prime: ${rI.toString(g.prime)}`),I&&I.info(`# of Wires: ${g.nVars}`),I&&I.info(`# of Constraints: ${g.nConstraints}`),I&&I.info(`# of Private Inputs: ${g.nPrvInputs}`),I&&I.info(`# of Public Inputs: ${g.nPubInputs}`),I&&I.info(`# of Labels: ${g.nLabels}`),I&&I.info(`# of Outputs: ${g.nOutputs}`),g},exportJson:async function(A,I){const g=await AC(A,!0,!0,!0,I),C=g.curve.Fr;return delete g.curve,CC(C,g)}});async function BC(A){const I={labelIdx2Name:["one"],varIdx2Name:["one"],componentIdx2Name:[]},g=await LI(A),C=await g.read(g.totalSize),Q=new TextDecoder("utf-8").decode(C).split("\n");for(let A=0;A=this.length&&(this.length=A+1),!0}getKeys(){const A=new nC;for(let I=0;IE)return C&&C.error(`circuit too big for this power of tau ceremony. ${a.nConstraints}*2 > 2**${E}`),-1;if(!t[12])return C&&C.error("Powers of tau is not prepared."),-1;const s=a.nOutputs+a.nPubInputs,f=2**w;await NI(o,1),await o.writeULE32(1),await bI(o),await NI(o,2);const D=i.q,c=8*(Math.floor((rI.bitLength(D)-1)/64)+1),y=i.r,F=8*(Math.floor((rI.bitLength(y)-1)/64)+1),M=rI.mod(rI.shl(1,8*F),y),u=i.Fr.e(rI.mod(rI.mul(M,M),y));let p,l,H;await o.writeULE32(c),await vI(o,D,c),await o.writeULE32(F),await vI(o,y,F),await o.writeULE32(a.nVars),await o.writeULE32(s),await o.writeULE32(f),p=await B.read(h,t[4][0].p),await o.write(p),p=await i.G1.batchLEMtoU(p),Q.update(p),l=await B.read(h,t[5][0].p),await o.write(l),l=await i.G1.batchLEMtoU(l),Q.update(l),H=await B.read(r,t[6][0].p),await o.write(H),H=await i.G2.batchLEMtoU(H),Q.update(H);const G=new Uint8Array(h);i.G1.toRprLEM(G,0,i.G1.g);const U=new Uint8Array(r);i.G2.toRprLEM(U,0,i.G2.g);const d=new Uint8Array(h);i.G1.toRprUncompressed(d,0,i.G1.g);const m=new Uint8Array(r);i.G2.toRprUncompressed(m,0,i.G2.g),await o.write(U),await o.write(G),await o.write(U),Q.update(m),Q.update(d),Q.update(m),await bI(o),C&&C.info("Reading r1cs");let L=await qI(e,n,2);const J=new nC(a.nVars),k=new nC(a.nVars),N=new nC(a.nVars),b=new nC(a.nVars-s-1),R=new Array(s+1);C&&C.info("Reading tauG1");let S=await qI(B,t,12,(f-1)*h,f*h);C&&C.info("Reading tauG2");let v=await qI(B,t,13,(f-1)*r,f*r);C&&C.info("Reading alphatauG1");let Y=await qI(B,t,14,(f-1)*h,f*h);C&&C.info("Reading betatauG1");let P=await qI(B,t,15,(f-1)*h,f*h);await async function(){const A=new Uint8Array(12+i.Fr.n8),I=new DataView(A.buffer),g=new Uint8Array(i.Fr.n8);i.Fr.toRprLE(g,0,i.Fr.e(1));let Q=0;function B(){const A=L.slice(Q,Q+4);Q+=4;return new DataView(A.buffer).getUint32(0,!0)}const t=new nC;for(let A=0;A=0?i.Fr.fromRprLE(L.slice(C[3],C[3]+i.Fr.n8),0):i.Fr.fromRprLE(g,0);const B=i.Fr.mul(Q,u);i.Fr.toRprLE(A,12,B),E.set(A,n),n+=A.length}await o.write(E),await bI(o)}(),await x(3,"G1",R,"IC"),await async function(){await NI(o,9);const A=new VA(f*h);if(w(C&&C.debug(`Writing points end ${B}: ${n}/${g.length}`),A)))),e+=Q,A++}const n=await Promise.all(E);for(let A=0;A32768?(h=new VA(w*B),r=new VA(w*i.Fr.n8)):(h=new Uint8Array(w*B),r=new Uint8Array(w*i.Fr.n8));let s=0,f=0;const D=[S,v,Y,P],c=new Uint8Array(i.Fr.n8);i.Fr.toRprLE(c,0,i.Fr.e(1));let y=0;for(let A=0;A=0?r.set(L.slice(I[A][Q][2],I[A][Q][2]+i.Fr.n8),y*i.Fr.n8):r.set(c,y*i.Fr.n8),y++;if(I.length>1){const A=[];A.push({cmd:"ALLOCSET",var:0,buff:h}),A.push({cmd:"ALLOCSET",var:1,buff:r}),A.push({cmd:"ALLOC",var:2,len:I.length*t}),s=0,f=0;let g=0;for(let C=0;C=0;A--){const I=n.contributions[A];C&&C.info("-------------------------"),C&&C.info(Ig(I.contributionHash,`contribution #${A+1} ${I.name?I.name:""}:`)),1==I.type&&(C&&C.info(`Beacon generator: ${Eg(I.beaconHash)}`),C&&C.info(`Beacon iterations Exp: ${I.numIterationsExp}`))}return C&&C.info("-------------------------"),C&&C.info("ZKey Ok!"),!0;async function D(A,I){const g=2*E.G1.F.n8,C=A.byteLength/g,Q=E.tm.concurrency,B=Math.floor(C/Q),t=[];for(let g=0;go.contributions.length)return Q&&Q.error("The impoerted file does not include new contributions"),!1;for(let A=0;A=256)return B&&B.error("Maximum lenght of beacon hash is 255 bytes"),!1;if((Q=parseInt(Q))<10||Q>63)return B&&B.error("Invalid numIterationsExp. (Must be between 10 and 63)"),!1;const{fd:i,sections:E}=await JI(A,"zkey",2),e=await rg(i,E,"groth16"),n=await VI(e.q),a=await sg(i,n,E),o=await kI(I,"zkey",1,10),h=await tg(t,Q),r=TI(64);r.update(a.csHash);for(let A=0;A",i);const E=`[${C.vk_beta_2[0][1].toString()},${C.vk_beta_2[0][0].toString()}], [${C.vk_beta_2[1][1].toString()},${C.vk_beta_2[1][0].toString()}]`;t=t.replace("<%vk_beta2%>",E);const e=`[${C.vk_gamma_2[0][1].toString()},${C.vk_gamma_2[0][0].toString()}], [${C.vk_gamma_2[1][1].toString()},${C.vk_gamma_2[1][0].toString()}]`;t=t.replace("<%vk_gamma2%>",e);const n=`[${C.vk_delta_2[0][1].toString()},${C.vk_delta_2[0][0].toString()}], [${C.vk_delta_2[1][1].toString()},${C.vk_delta_2[1][0].toString()}]`;t=t.replace("<%vk_delta2%>",n),t=t.replace("<%vk_input_length%>",(C.IC.length-1).toString()),t=t.replace("<%vk_ic_length%>",C.IC.length.toString());let a="";for(let A=0;A",a),t}});return A.groth16=dg,A.powersOfTau=Og,A.r1cs=QC,A.wtns=tC,A.zKey=sC,Object.defineProperty(A,"__esModule",{value:!0}),A}({}); diff --git a/client/src/Backend/GameLogic/ArenaCreationManager.ts b/client/src/Backend/GameLogic/ArenaCreationManager.ts new file mode 100644 index 00000000..c63f06c8 --- /dev/null +++ b/client/src/Backend/GameLogic/ArenaCreationManager.ts @@ -0,0 +1,474 @@ +import { EMPTY_ADDRESS } from '@darkforest_eth/constants'; +import { INIT_ADDRESS } from '@darkforest_eth/contracts'; +import { DarkForest, DFArenaInitialize } from '@darkforest_eth/contracts/typechain'; +import { fakeHash, mimcHash, modPBigInt, perlin } from '@darkforest_eth/hashing'; +import { EthConnection } from '@darkforest_eth/network'; +import { address } from '@darkforest_eth/serde'; +import { + buildContractCallArgs, + fakeProof, + RevealSnarkContractCallArgs, + RevealSnarkInput, + SnarkJSProofAndSignals, +} from '@darkforest_eth/snarks'; +import revealCircuitPath from '@darkforest_eth/snarks/reveal.wasm'; +import revealZkeyPath from '@darkforest_eth/snarks/reveal.zkey'; +import { + ContractMethodName, + EthAddress, + LocationId, + UnconfirmedCreateArenaPlanet, + UnconfirmedCreateLobby, + UnconfirmedReveal, + UnconfirmedStartLobby, + WorldCoords, + WorldLocation, +} from '@darkforest_eth/types'; +import { TransactionReceipt } from '@ethersproject/providers'; +import { keccak256, toUtf8Bytes } from 'ethers/lib/utils'; +import _ from 'lodash'; +import { InitPlanet, LobbyPlanet } from '../../Frontend/Panes/Lobby/LobbiesUtils'; +import { LobbyInitializers } from '../../Frontend/Panes/Lobby/Reducer'; +import { OPTIMISM_GAS_LIMIT } from '../../Frontend/Utils/constants'; +import { loadDiamondContract, loadInitContract } from '../Network/Blockchain'; +import { ContractsAPI, makeContractsAPI } from './ContractsAPI'; + +export type CreatePlanetData = { + location: string; + planetCoords: { + x: number; + y: number; + }; + perlinValue: number; + biomeBase: number; +}; + +export type CreatedPlanet = LobbyPlanet & { + createTx: string | undefined; + revealTx: string | undefined; +}; + +export class ArenaCreationManager { + private readonly parentAddress: EthAddress; + private readonly contract: ContractsAPI; + private readonly connection: EthConnection; + private arenaAddress: EthAddress | undefined; + private configHash: string | undefined; + private whitelistedAddresses: EthAddress[]; + private createdPlanets: CreatedPlanet[]; + private created: boolean = false; + + private constructor( + parentAddress: EthAddress, + contract: ContractsAPI, + connection: EthConnection + ) { + this.parentAddress = parentAddress; + this.contract = contract; + this.connection = connection; + this.whitelistedAddresses = []; + this.createdPlanets = []; + } + + public async createAndInitArena(config: LobbyInitializers) { + if (config.ADMIN_PLANETS) { + config.INIT_PLANETS = this.lobbyPlanetsToInitPlanets(config, config.ADMIN_PLANETS); + } + + /* Don't want to submit ADMIN_PLANET as initdata because not used */ + + // @ts-expect-error The Operand of a delete must be optional + delete config.ADMIN_PLANETS; + + try { + const initContract = await this.connection.loadContract( + INIT_ADDRESS, + loadInitContract + ); + + const artifactBaseURI = ''; + const initInterface = initContract.interface; + const initAddress = INIT_ADDRESS; + const initFunctionCall = initInterface.encodeFunctionData('init', [ + config, + { + allowListEnabled: config.WHITELIST_ENABLED, + artifactBaseURI, + allowedAddresses: config.WHITELIST, + }, + ]); + console.log('creating lobby at', this.contract.getContractAddress()); + const createTxIntent: UnconfirmedCreateLobby = { + methodName: 'createLobby', + contract: this.contract.contract, + args: Promise.resolve([initAddress, initFunctionCall]), + }; + + const tx = await this.contract.submitTransaction(createTxIntent, { + // The createLobby function costs somewhere around 12mil gas + gasLimit: OPTIMISM_GAS_LIMIT, + }); + + const lobbyReceipt = await tx.confirmedPromise; + console.log(`created arena with ${lobbyReceipt.gasUsed} gas`); + + const { owner, lobby } = this.getLobbyCreatedEvent(lobbyReceipt, this.contract.contract); + + const diamond = await this.connection.loadContract(lobby, loadDiamondContract); + + const startTxIntent: UnconfirmedStartLobby = { + methodName: 'start', + contract: diamond, // Calling this on new diamond + args: Promise.resolve([]), + }; + + const startTx = await this.contract.submitTransaction(startTxIntent, { + // The createLobby function costs somewhere around 12mil gas + gasLimit: OPTIMISM_GAS_LIMIT, + }); + + const startRct = await startTx.confirmedPromise; + console.log(`initialized arena with ${startRct.gasUsed} gas`); + this.created = true; + this.arenaAddress = lobby; + this.configHash = (await diamond.getArenaConstants()).CONFIG_HASH; + + return { owner, lobby, startTx }; + } catch (e) { + console.log(e); + throw new Error('lobby creation transaction failed.'); + } + } + + public async createPlanet(planet: LobbyPlanet, initializers: LobbyInitializers) { + const args = Promise.resolve([this.lobbyPlanetToInitPlanet(planet, initializers)]); + + const txIntent: UnconfirmedCreateArenaPlanet = { + methodName: 'createArenaPlanet', + contract: this.contract.contract, + args: args, + }; + + const tx = await this.contract.submitTransaction(txIntent, { + gasLimit: '15000000', + }); + + await tx.confirmedPromise; + this.createdPlanets.push({ ...planet, createTx: tx?.hash, revealTx: undefined }); + } + + public async revealPlanet(planet: LobbyPlanet, initializers: LobbyInitializers) { + const planetData = this.generatePlanetData(planet, initializers); + const getArgs = async () => { + const revealArgs = await this.makeRevealProof( + planet.x, + planet.y, + initializers.PLANETHASH_KEY, + initializers.SPACETYPE_KEY, + initializers.PERLIN_LENGTH_SCALE, + initializers.PERLIN_MIRROR_X, + initializers.PERLIN_MIRROR_Y, + initializers.DISABLE_ZK_CHECKS, + initializers.PLANET_RARITY + ); + return revealArgs; + }; + + const worldLocation = { + coords: planetData.planetCoords as WorldCoords, + hash: location.toString() as LocationId, + perlin: planetData.perlinValue, + biomebase: planetData.biomeBase, + } as WorldLocation; + + const txIntent: UnconfirmedReveal = { + methodName: 'revealLocation', + contract: this.contract.contract, + locationId: location.toString() as LocationId, + location: worldLocation, + args: getArgs(), + }; + + // Always await the submitTransaction so we can catch rejections + const tx = await this.contract.submitTransaction(txIntent); + console.log(`reveal tx submitted`); + + await tx.confirmedPromise; + console.log(`reveal tx accepted`); + const createdPlanet = this.createdPlanets.find((p) => p.x == planet.x && p.y == planet.y); + if (!createdPlanet) throw new Error('created planet not found'); + createdPlanet.revealTx = tx?.hash; + } + + // to do: simplify planet creation so either only create lobby planets + // or only create init planets + public async bulkCreateLobbyPlanets({ + config, + planets, + }: { + config: LobbyInitializers; + planets?: LobbyPlanet[]; + }) { + // make create Planet args + const planetsToCreate = planets || config.ADMIN_PLANETS; + const initPlanets = this.lobbyPlanetsToInitPlanets(config, planetsToCreate); + + const args = Promise.resolve([initPlanets]); + const txIntent = { + methodName: 'bulkCreateAndReveal' as ContractMethodName, + contract: this.lobbyContract(), + args: args, + }; + + const tx = await this.contract.submitTransaction(txIntent, { + gasLimit: '15000000', + }); + + const createRct = await tx.confirmedPromise; + console.log(`created ${planets?.length} planets with ${createRct.gasUsed} gas`); + await tx.confirmedPromise; + planetsToCreate.map((p) => + this.createdPlanets.push({ ...p, createTx: tx?.hash, revealTx: tx?.hash }) + ); + } + + public async bulkCreateInitPlanets({ + config, + planets, + CHUNK_SIZE = 24, + }: { + config: LobbyInitializers; + planets?: InitPlanet[]; + CHUNK_SIZE?: number; + }) { + const planetsToCreate = planets || config.INIT_PLANETS; + const createPlanetTxs = _.chunk(planetsToCreate, CHUNK_SIZE).map(async (chunk) => { + const args = Promise.resolve([chunk]); + const txIntent = { + methodName: 'bulkCreateAndReveal' as ContractMethodName, + contract: this.lobbyContract(), + args: args, + }; + const tx = await this.contract.submitTransaction(txIntent, { + gasLimit: OPTIMISM_GAS_LIMIT + }); + return tx.confirmedPromise; + }); + + const res = await Promise.all(createPlanetTxs); + console.log( + `successfully created planets`, + createPlanetTxs.map((i) => i) + ); + } + + public async whitelistPlayer(address: EthAddress) { + const args = Promise.resolve([address]); + const txIntent = { + methodName: 'addToWhitelist' as ContractMethodName, + contract: this.contract.contract, + args: args, + }; + + const tx = await this.contract.submitTransaction(txIntent, { + gasLimit: '15000000', + }); + + await tx.confirmedPromise; + this.whitelistedAddresses.push(address); + } + + public lobbyPlanetToInitPlanet(planet: LobbyPlanet, initializers: LobbyInitializers) { + const locationFunc = initializers.DISABLE_ZK_CHECKS + ? fakeHash(initializers.PLANET_RARITY) + : mimcHash(initializers.PLANETHASH_KEY); + + const location = locationFunc(planet.x, planet.y).toString(); + + const planetCoords = { + x: planet.x, + y: planet.y, + }; + const perlinValue = perlin(planetCoords, { + key: initializers.SPACETYPE_KEY, + scale: initializers.PERLIN_LENGTH_SCALE, + mirrorX: initializers.PERLIN_MIRROR_X, + mirrorY: initializers.PERLIN_MIRROR_Y, + floor: true, + }); + + return { + location: location, + x: modPBigInt(planet.x).toString(), + y: modPBigInt(planet.y).toString(), + perlin: perlinValue, + level: planet.level, + planetType: planet.planetType, + requireValidLocationId: false, + isTargetPlanet: planet.isTargetPlanet, + isSpawnPlanet: planet.isSpawnPlanet, + blockedPlanetIds: planet.blockedPlanetLocs.map((p) => locationFunc(p.x, p.y).toString()), + }; + } + + public lobbyPlanetsToInitPlanets( + initializers: LobbyInitializers, + planets: LobbyPlanet[] + ): InitPlanet[] { + const initPlanets: InitPlanet[] = []; + planets.forEach((p) => initPlanets.push(this.lobbyPlanetToInitPlanet(p, initializers))); + // SORT INIT PLANETS SO THEY HAVE SAME ORDER ON-CHAIN. THIS CAN BREAK CONFIG HASH OTHERWISE. + initPlanets.sort((a, b) => (a.location > b.location ? 1 : -1)); + return initPlanets; + } + + public getLobbyCreatedEvent( + lobbyReceipt: TransactionReceipt, + contract: DarkForest + ): { owner: EthAddress; lobby: EthAddress } { + const lobbyCreatedHash = keccak256(toUtf8Bytes('LobbyCreated(address,address)')); + const log = lobbyReceipt.logs.find((log) => log.topics[0] === lobbyCreatedHash); + if (log) { + return { + owner: address(contract.interface.parseLog(log).args.creatorAddress), + lobby: address(contract.interface.parseLog(log).args.lobbyAddress), + }; + } else { + throw new Error('Lobby Created event not found'); + } + } + + private generatePlanetData(planet: LobbyPlanet, initializers: LobbyInitializers) { + const location = initializers.DISABLE_ZK_CHECKS + ? fakeHash(initializers.PLANET_RARITY)(planet.x, planet.y).toString() + : mimcHash(initializers.PLANETHASH_KEY)(planet.x, planet.y).toString(); + + const planetCoords = { + x: planet.x, + y: planet.y, + }; + + const perlinValue = perlin(planetCoords, { + key: initializers.SPACETYPE_KEY, + scale: initializers.PERLIN_LENGTH_SCALE, + mirrorX: initializers.PERLIN_MIRROR_X, + mirrorY: initializers.PERLIN_MIRROR_Y, + floor: true, + }); + + const biomeBase = perlin(planetCoords, { + key: initializers.BIOMEBASE_KEY, + scale: initializers.PERLIN_LENGTH_SCALE, + mirrorX: initializers.PERLIN_MIRROR_X, + mirrorY: initializers.PERLIN_MIRROR_Y, + floor: true, + }); + + return { + location: location, + planetCoords: planetCoords, + perlinValue: perlinValue, + biomeBase: biomeBase, + }; + } + + private async makeRevealProof( + x: number, + y: number, + planetHashKey: number, + spaceTypeKey: number, + scale: number, + mirrorX: boolean, + mirrorY: boolean, + zkChecksDisabled: boolean, + planetRarity: number + ): Promise { + if (zkChecksDisabled) { + const location = fakeHash(planetRarity)(x, y).toString(); + const perlinValue = perlin( + { x, y }, + { + key: spaceTypeKey, + scale, + mirrorX, + mirrorY, + floor: true, + } + ); + const { proof, publicSignals } = fakeProof([ + location, + perlinValue.toString(), + modPBigInt(x).toString(), + modPBigInt(y).toString(), + planetHashKey.toString(), + spaceTypeKey.toString(), + scale.toString(), + mirrorX ? '1' : '0', + mirrorY ? '1' : '0', + ]); + return buildContractCallArgs(proof, publicSignals) as RevealSnarkContractCallArgs; + } else { + const input: RevealSnarkInput = { + x: modPBigInt(x).toString(), + y: modPBigInt(y).toString(), + PLANETHASH_KEY: planetHashKey.toString(), + SPACETYPE_KEY: spaceTypeKey.toString(), + SCALE: scale.toString(), + xMirror: mirrorX ? '1' : '0', + yMirror: mirrorY ? '1' : '0', + }; + + const { proof, publicSignals }: SnarkJSProofAndSignals = + await window.snarkjs.groth16.fullProve(input, revealCircuitPath, revealZkeyPath); + + return buildContractCallArgs(proof, publicSignals) as RevealSnarkContractCallArgs; + } + } + + private lobbyContract() { + if (!this.arenaAddress) throw new Error('no lobby created'); + return this.connection.getContract(this.arenaAddress); + } + + get planets() { + return this.createdPlanets; + } + + get allAddresses() { + return this.whitelistedAddresses; + } + + get account(): EthAddress { + const address = this.connection.getAddress(); + return address || EMPTY_ADDRESS; + } + + getParentAddress() { + return this.parentAddress; + } + + getArenaAddress() { + return this.arenaAddress; + } + + getArenaConfigHash() { + return this.configHash; + } + + get arenaCreated() { + return this.created; + } + + static async create( + connection: EthConnection, + contractAddress: EthAddress + ): Promise { + try { + const contract = await makeContractsAPI({ connection, contractAddress }); + const manager = new ArenaCreationManager(contractAddress, contract, connection); + return manager; + } catch (e) { + throw new Error("couldn't connect to blockchain."); + } + } +} diff --git a/client/src/Backend/GameLogic/ArrivalUtils.ts b/client/src/Backend/GameLogic/ArrivalUtils.ts index ca78893b..c97eef1a 100644 --- a/client/src/Backend/GameLogic/ArrivalUtils.ts +++ b/client/src/Backend/GameLogic/ArrivalUtils.ts @@ -1,16 +1,17 @@ -import { CONTRACT_PRECISION } from '@dfdao/constants'; -import { hasOwner, isEmojiFlagMessage } from '@dfdao/gamelogic'; +import { CONTRACT_PRECISION } from '@darkforest_eth/constants'; +import { hasOwner, isActivated, isEmojiFlagMessage } from '@darkforest_eth/gamelogic'; import { ArrivalType, + Artifact, ArtifactType, EmojiFlagBody, Planet, PlanetMessage, PlanetType, + Player, QueuedArrival, - SpaceshipType, Upgrade, -} from '@dfdao/types'; +} from '@darkforest_eth/types'; import _ from 'lodash'; import { ContractConstants } from '../../_types/darkforest/api/ContractsAPITypes'; @@ -82,6 +83,7 @@ const getEnergyAtTime = (planet: Planet, atTimeMillis: number): number => { export const updatePlanetToTime = ( planet: Planet, + planetArtifacts: Artifact[], atTimeMillis: number, contractConstants: ContractConstants, setPlanet: (p: Planet) => void = () => {} @@ -98,25 +100,16 @@ export const updatePlanetToTime = ( planet.lastUpdated = atTimeMillis / 1000; const photoidActivationTime = contractConstants.PHOTOID_ACTIVATION_DELAY * 1000; - if (planet.activeArtifact) { - const activePhotoid = - planet.activeArtifact.artifactType === ArtifactType.PhotoidCannon && - atTimeMillis - planet.artifactActivationTime * 1000 >= photoidActivationTime; - - if (activePhotoid && !planet.localPhotoidUpgrade) { - // TODO: pre-load from contract? - const range = [100, 200, 200, 200, 200, 200]; - const speedBoosts = [100, 500, 1000, 1500, 2000, 2500]; - const timeDelayedUpgrade: Upgrade = { - energyCapMultiplier: 100, - energyGroMultiplier: 100, - rangeMultiplier: range[planet.activeArtifact.rarity], - speedMultiplier: speedBoosts[planet.activeArtifact.rarity], - defMultiplier: 100, - }; - planet.localPhotoidUpgrade = timeDelayedUpgrade; - applyUpgrade(planet, timeDelayedUpgrade); - } + const activePhotoid = planetArtifacts.find( + (a) => + a.artifactType === ArtifactType.PhotoidCannon && + isActivated(a) && + atTimeMillis - a.lastActivated * 1000 >= photoidActivationTime + ); + + if (activePhotoid && !planet.localPhotoidUpgrade) { + planet.localPhotoidUpgrade = activePhotoid.timeDelayedUpgrade; + applyUpgrade(planet, activePhotoid.timeDelayedUpgrade); } setPlanet(planet); @@ -151,8 +144,12 @@ export interface PlanetDiff { export const arrive = ( toPlanet: Planet, + artifactsOnPlanet: Artifact[], arrival: QueuedArrival, - contractConstants: ContractConstants + arrivingArtifact: Artifact | undefined, + contractConstants: ContractConstants, + arrivalPlayer: Player | undefined, + toOwner: Player | undefined ): PlanetDiff => { // this function optimistically simulates an arrival if (toPlanet.locationId !== arrival.toPlanet) { @@ -160,7 +157,7 @@ export const arrive = ( } // update toPlanet energy and silver right before arrival - updatePlanetToTime(toPlanet, arrival.arrivalTime * 1000, contractConstants); + updatePlanetToTime(toPlanet, artifactsOnPlanet, arrival.arrivalTime * 1000, contractConstants); const prevPlanet = _.cloneDeep(toPlanet); if (toPlanet.destroyed) { @@ -170,7 +167,8 @@ export const arrive = ( // apply energy const { energyArriving } = arrival; - if (arrival.player !== toPlanet.owner) { + const onSameTeam = toOwner && arrivalPlayer?.team == toOwner?.team; + if (arrival.player !== toPlanet.owner && (!contractConstants.TEAMS_ENABLED || !onSameTeam) ) { if (arrival.arrivalType === ArrivalType.Wormhole) { // if this is a wormhole arrival to a planet that isn't owned by the initiator of // the move, then don't move any energy @@ -212,25 +210,19 @@ export const arrive = ( } // transfer artifact if necessary - if (arrival.artifact) { - toPlanet.artifacts.push(arrival.artifact); - } - - if (arrival.spaceship) { - toPlanet.spaceships.push(arrival.spaceship); - if (arrival.spaceship.spaceshipType === SpaceshipType.ShipMothership) { - if (toPlanet.energyGroDoublers === 0) { - toPlanet.energyGrowth *= 2; - } - toPlanet.energyGroDoublers++; - } else if (arrival.spaceship.spaceshipType === SpaceshipType.ShipWhale) { - if (toPlanet.silverGroDoublers === 0) { - toPlanet.silverGrowth *= 2; - } - toPlanet.silverGroDoublers++; - } else if (arrival.spaceship.spaceshipType === SpaceshipType.ShipTitan) { + if (arrival.artifactId) { + toPlanet.heldArtifactIds.push(arrival.artifactId); + } + + if (arrivingArtifact) { + if (arrivingArtifact.artifactType === ArtifactType.ShipMothership) { + toPlanet.energyGrowth *= 2; + } else if (arrivingArtifact.artifactType === ArtifactType.ShipWhale) { + toPlanet.silverGrowth *= 2; + } else if (arrivingArtifact.artifactType === ArtifactType.ShipTitan) { toPlanet.pausers++; } + arrivingArtifact.onPlanetId = toPlanet.locationId; } return { arrival, current: toPlanet, previous: prevPlanet }; diff --git a/client/src/Backend/GameLogic/CaptureZoneGenerator.ts b/client/src/Backend/GameLogic/CaptureZoneGenerator.ts index d8f56565..bec19fa9 100644 --- a/client/src/Backend/GameLogic/CaptureZoneGenerator.ts +++ b/client/src/Backend/GameLogic/CaptureZoneGenerator.ts @@ -1,5 +1,5 @@ -import { monomitter, Monomitter } from '@dfdao/events'; -import { CaptureZone, Chunk, LocationId } from '@dfdao/types'; +import { monomitter, Monomitter } from '@darkforest_eth/events'; +import { CaptureZone, Chunk, LocationId } from '@darkforest_eth/types'; import bigInt from 'big-integer'; import { utils } from 'ethers'; import GameManager, { GameManagerEvent } from './GameManager'; diff --git a/client/src/Backend/GameLogic/ContractsAPI.ts b/client/src/Backend/GameLogic/ContractsAPI.ts index 033b1553..f24e0386 100644 --- a/client/src/Backend/GameLogic/ContractsAPI.ts +++ b/client/src/Backend/GameLogic/ContractsAPI.ts @@ -1,5 +1,5 @@ -import { EMPTY_LOCATION_ID } from '@dfdao/constants'; -import { DarkForest } from '@dfdao/contracts/typechain'; +import { EMPTY_LOCATION_ID, GNOSIS_CHAIN_ID, GNOSIS_OPTIMISM_CHAIN_ID, KOVAN_OPTIMISM_CHAIN_ID } from '@darkforest_eth/constants'; +import { DarkForest } from '@darkforest_eth/contracts/typechain'; import { aggregateBulkGetter, ContractCaller, @@ -7,31 +7,28 @@ import { ethToWei, TxCollection, TxExecutor, -} from '@dfdao/network'; +} from '@darkforest_eth/network'; import { address, + artifactIdFromEthersBN, artifactIdToDecStr, decodeArrival, decodeArtifact, decodeArtifactPointValues, decodePlanet, decodePlanetDefaults, - decodePlanetTypeWeights, decodePlayer, decodeRevealedCoords, - decodeSpaceship, - decodeUpgrade, decodeUpgradeBranches, - isArtifact, - isSpaceship, locationIdFromEthersBN, locationIdToDecStr, -} from '@dfdao/serde'; +} from '@darkforest_eth/serde'; import { Artifact, ArtifactId, ArtifactType, AutoGasSetting, + BlocklistMap, DiagnosticUpdater, EthAddress, LocationId, @@ -40,14 +37,12 @@ import { QueuedArrival, RevealedCoords, Setting, - Spaceship, Transaction, TransactionId, TxIntent, - Upgrade, VoyageId, -} from '@dfdao/types'; -import { BigNumber as EthersBN, ContractFunction, Event, providers } from 'ethers'; +} from '@darkforest_eth/types'; +import { BigNumber, BigNumber as EthersBN, ContractFunction, Event, providers } from 'ethers'; import { EventEmitter } from 'events'; import _ from 'lodash'; import NotificationManager from '../../Frontend/Game/NotificationManager'; @@ -57,6 +52,7 @@ import { ContractConstants, ContractEvent, ContractsAPIEvent, + PlanetTypeWeightsBySpaceType, } from '../../_types/darkforest/api/ContractsAPITypes'; import { loadDiamondContract } from '../Network/Blockchain'; import { eventLogger, EventType } from '../Network/EventLogger'; @@ -74,9 +70,9 @@ interface ContractsApiConfig { */ export class ContractsAPI extends EventEmitter { /** - * Don't allow users to submit txs if balance falls below this amount/ + * Don't allow users to submit txs if balance falls below this amount (in wei) */ - private static readonly MIN_BALANCE = ethToWei(0.002); + private static readonly MIN_BALANCE = 100; /** * Instrumented {@link ThrottledConcurrentQueue} for blockchain reads. @@ -126,7 +122,7 @@ export class ContractsAPI extends EventEmitter { */ private getGasFeeForTransaction(tx: Transaction): AutoGasSetting | string { if ( - (tx.intent.methodName === 'initializePlayer' || tx.intent.methodName === 'getSpaceShips') && + (tx.intent.methodName === 'arenaInitializePlayer' || tx.intent.methodName === 'getSpaceShips') && tx.intent.contract.address === this.contract.address ) { return '50'; @@ -163,7 +159,13 @@ export class ContractsAPI extends EventEmitter { throw new Error('xDAI balance too low!'); } - const gasFeeGwei = EthersBN.from(overrides?.gasPrice || '1000000000'); + const chainId = (await this.ethConnection.getProvider().getNetwork()).chainId; + + let defaultGas = '1000000000'; // GNOSIS_CHAIN_ID gas + if (chainId === GNOSIS_OPTIMISM_CHAIN_ID) defaultGas = '1'; + if (chainId === KOVAN_OPTIMISM_CHAIN_ID) defaultGas = '100000'; + + const gasFeeGwei = EthersBN.from(overrides?.gasPrice || defaultGas); await openConfirmationWindowForTransaction({ contractAddress: this.contractAddress, @@ -185,10 +187,7 @@ export class ContractsAPI extends EventEmitter { this.emit(ContractsAPIEvent.TxProcessing, tx); } - private async afterTransaction( - _txRequest: Transaction, - txDiagnosticInfo: Record - ) { + private async afterTransaction(_txRequest: Transaction, txDiagnosticInfo: unknown) { eventLogger.logEvent(EventType.Transaction, txDiagnosticInfo); } @@ -225,13 +224,17 @@ export class ContractsAPI extends EventEmitter { contract.filters.AdminGiveSpaceship(null, null).topics, contract.filters.PauseStateChanged(null).topics, contract.filters.LobbyCreated(null, null).topics, - contract.filters.SpaceshipFound(null, null, null).topics, + contract.filters.Gameover(null).topics, + contract.filters.GameStarted(null,null).topics, + contract.filters.PlayerReady(null,null).topics, + contract.filters.PlayerNotReady(null,null).topics, ].map((topicsOrUndefined) => (topicsOrUndefined || [])[0]), ] as Array>, }; const eventHandlers = { [ContractEvent.PauseStateChanged]: (paused: boolean) => { + // console.log(`paused ${paused}`); this.emit(ContractsAPIEvent.PauseStateChanged, paused); }, [ContractEvent.AdminOwnershipChanged]: (location: EthersBN, _newOwner: string) => { @@ -249,42 +252,26 @@ export class ContractsAPI extends EventEmitter { rawArtifactId: EthersBN, loc: EthersBN ) => { - this.emit(ContractsAPIEvent.PlanetUpdate, locationIdFromEthersBN(loc)); - }, - [ContractEvent.SpaceshipFound]: ( - playerAddr: string, - rawSpaceshipId: EthersBN, - loc: EthersBN - ) => { - this.emit( - ContractsAPIEvent.SpaceshipFound, - address(playerAddr), - decodeSpaceship(rawSpaceshipId) - ); + const artifactId = artifactIdFromEthersBN(rawArtifactId); + this.emit(ContractsAPIEvent.ArtifactUpdate, artifactId); this.emit(ContractsAPIEvent.PlanetUpdate, locationIdFromEthersBN(loc)); }, [ContractEvent.ArtifactDeposited]: ( - playerAddr: string, + _playerAddr: string, rawArtifactId: EthersBN, loc: EthersBN ) => { - this.emit( - ContractsAPIEvent.ArtifactDeposited, - address(playerAddr), - decodeArtifact(rawArtifactId) - ); + const artifactId = artifactIdFromEthersBN(rawArtifactId); + this.emit(ContractsAPIEvent.ArtifactUpdate, artifactId); this.emit(ContractsAPIEvent.PlanetUpdate, locationIdFromEthersBN(loc)); }, [ContractEvent.ArtifactWithdrawn]: ( - playerAddr: string, + _playerAddr: string, rawArtifactId: EthersBN, loc: EthersBN ) => { - this.emit( - ContractsAPIEvent.ArtifactWithdrawn, - address(playerAddr), - decodeArtifact(rawArtifactId) - ); + const artifactId = artifactIdFromEthersBN(rawArtifactId); + this.emit(ContractsAPIEvent.ArtifactUpdate, artifactId); this.emit(ContractsAPIEvent.PlanetUpdate, locationIdFromEthersBN(loc)); }, [ContractEvent.ArtifactActivated]: ( @@ -292,6 +279,8 @@ export class ContractsAPI extends EventEmitter { rawArtifactId: EthersBN, loc: EthersBN ) => { + const artifactId = artifactIdFromEthersBN(rawArtifactId); + this.emit(ContractsAPIEvent.ArtifactUpdate, artifactId); this.emit(ContractsAPIEvent.PlanetUpdate, locationIdFromEthersBN(loc)); }, [ContractEvent.ArtifactDeactivated]: ( @@ -299,6 +288,8 @@ export class ContractsAPI extends EventEmitter { rawArtifactId: EthersBN, loc: EthersBN ) => { + const artifactId = artifactIdFromEthersBN(rawArtifactId); + this.emit(ContractsAPIEvent.ArtifactUpdate, artifactId); this.emit(ContractsAPIEvent.PlanetUpdate, locationIdFromEthersBN(loc)); }, [ContractEvent.PlayerInitialized]: async (player: string, locRaw: EthersBN, _: Event) => { @@ -382,6 +373,22 @@ export class ContractsAPI extends EventEmitter { [ContractEvent.LobbyCreated]: (ownerAddr: string, lobbyAddr: string) => { this.emit(ContractsAPIEvent.LobbyCreated, address(ownerAddr), address(lobbyAddr)); }, + [ContractEvent.Gameover]: (player: string) => { + this.emit(ContractsAPIEvent.PlayerUpdate, address(player)); + this.emit(ContractsAPIEvent.Gameover); + }, + [ContractEvent.GameStarted]: (player: string, startTime: EthersBN) => { + // console.log('GAme started', player); + this.emit(ContractsAPIEvent.GameStarted, address(player), startTime.toNumber()); + }, + [ContractEvent.PlayerReady]: (player: string, time: EthersBN) => { + // console.log('CONTRACT PLAYER READY', player); + this.emit(ContractsAPIEvent.PlayerUpdate, address(player)); + }, + [ContractEvent.PlayerNotReady]: (player: string, time: EthersBN) => { + // console.log('CONTRACT PLAYER NOT READY', player); + this.emit(ContractsAPIEvent.PlayerUpdate, address(player)); + }, }; this.ethConnection.subscribeToContractEvents(contract, eventHandlers, filter); @@ -404,6 +411,14 @@ export class ContractsAPI extends EventEmitter { contract.removeAllListeners(ContractEvent.PlanetSilverWithdrawn); contract.removeAllListeners(ContractEvent.PlanetInvaded); contract.removeAllListeners(ContractEvent.PlanetCaptured); + contract.removeAllListeners(ContractEvent.Gameover); + contract.removeAllListeners(ContractEvent.PauseStateChanged); + contract.removeAllListeners(ContractEvent.PlayerReady); + contract.removeAllListeners(ContractEvent.PlayerNotReady); + contract.removeAllListeners(ContractEvent.GameStarted); + contract.removeAllListeners(ContractEvent.PlayerReady); + contract.removeAllListeners(ContractEvent.PlayerNotReady); + } public getContractAddress(): EthAddress { @@ -435,7 +450,8 @@ export class ContractsAPI extends EventEmitter { BIOME_THRESHOLD_1, BIOME_THRESHOLD_2, SILVER_SCORE_VALUE, - PLANET_LEVEL_THRESHOLDS, + // TODO: Actually put this in game constants + // PLANET_LEVEL_THRESHOLDS, PLANET_RARITY, PLANET_TRANSFER_ENABLED, PHOTOID_ACTIVATION_DELAY, @@ -448,16 +464,35 @@ export class ContractsAPI extends EventEmitter { // Capture Zones GAME_START_BLOCK, CAPTURE_ZONES_ENABLED, + CAPTURE_ZONE_COUNT, CAPTURE_ZONE_CHANGE_BLOCK_INTERVAL, CAPTURE_ZONE_RADIUS, CAPTURE_ZONE_PLANET_LEVEL_SCORE, CAPTURE_ZONE_HOLD_BLOCKS_REQUIRED, CAPTURE_ZONES_PER_5000_WORLD_RADIUS, - SPACESHIPS, - ROUND_END_REWARDS_BY_RANK, } = await this.makeCall(this.contract.getGameConstants); - const TOKEN_MINT_END_SECONDS = ( + const { + MANUAL_SPAWN, + TARGET_PLANETS, + CLAIM_VICTORY_ENERGY_PERCENT, + MODIFIERS, + SPACESHIPS, + RANDOM_ARTIFACTS, + NO_ADMIN, + CONFIG_HASH, + INIT_PLANET_HASHES, + CONFIRM_START, + BLOCK_CAPTURE, + BLOCK_MOVES, + TARGETS_REQUIRED_FOR_VICTORY, + TEAMS_ENABLED, + NUM_TEAMS, + RANKED, + START_PAUSED + } = await this.makeCall(this.contract.getArenaConstants); + + const TOKEN_MINT_END_TIMESTAMP = ( await this.makeCall(this.contract.TOKEN_MINT_END_TIMESTAMP) ).toNumber(); @@ -465,15 +500,18 @@ export class ContractsAPI extends EventEmitter { const upgrades = decodeUpgradeBranches(await this.makeCall(this.contract.getUpgrades)); - const PLANET_TYPE_WEIGHTS = decodePlanetTypeWeights( - await this.makeCall(this.contract.getTypeWeights) - ); + const PLANET_TYPE_WEIGHTS: PlanetTypeWeightsBySpaceType = + await this.makeCall(this.contract.getTypeWeights); const rawPointValues = await this.makeCall(this.contract.getArtifactPointValues); const ARTIFACT_POINT_VALUES = decodeArtifactPointValues(rawPointValues); const planetDefaults = decodePlanetDefaults(await this.makeCall(this.contract.getDefaultStats)); + const planetLevelThresholds = ( + await this.makeCall(this.contract.getPlanetLevelThresholds) + ).map((x: EthersBN) => x.toNumber()); + const planetCumulativeRarities = ( await this.makeCall(this.contract.getCumulativeRarities) ).map((x: EthersBN) => x.toNumber()); @@ -491,7 +529,8 @@ export class ContractsAPI extends EventEmitter { PERLIN_LENGTH_SCALE: PERLIN_LENGTH_SCALE.toNumber(), PERLIN_MIRROR_X, PERLIN_MIRROR_Y, - TOKEN_MINT_END_SECONDS, + CLAIM_PLANET_COOLDOWN: 0, + TOKEN_MINT_END_TIMESTAMP, MAX_NATURAL_PLANET_LEVEL: MAX_NATURAL_PLANET_LEVEL.toNumber(), TIME_FACTOR_HUNDREDTHS: TIME_FACTOR_HUNDREDTHS.toNumber(), PERLIN_THRESHOLD_1: PERLIN_THRESHOLD_1.toNumber(), @@ -503,22 +542,21 @@ export class ContractsAPI extends EventEmitter { BIOME_THRESHOLD_2: BIOME_THRESHOLD_2.toNumber(), SILVER_SCORE_VALUE: SILVER_SCORE_VALUE.toNumber(), PLANET_LEVEL_THRESHOLDS: [ - PLANET_LEVEL_THRESHOLDS[0].toNumber(), - PLANET_LEVEL_THRESHOLDS[1].toNumber(), - PLANET_LEVEL_THRESHOLDS[2].toNumber(), - PLANET_LEVEL_THRESHOLDS[3].toNumber(), - PLANET_LEVEL_THRESHOLDS[4].toNumber(), - PLANET_LEVEL_THRESHOLDS[5].toNumber(), - PLANET_LEVEL_THRESHOLDS[6].toNumber(), - PLANET_LEVEL_THRESHOLDS[7].toNumber(), - PLANET_LEVEL_THRESHOLDS[8].toNumber(), - PLANET_LEVEL_THRESHOLDS[9].toNumber(), + planetLevelThresholds[0], + planetLevelThresholds[1], + planetLevelThresholds[2], + planetLevelThresholds[3], + planetLevelThresholds[4], + planetLevelThresholds[5], + planetLevelThresholds[6], + planetLevelThresholds[7], + planetLevelThresholds[8], + planetLevelThresholds[9], ], PLANET_RARITY: PLANET_RARITY.toNumber(), PLANET_TRANSFER_ENABLED, PLANET_TYPE_WEIGHTS, ARTIFACT_POINT_VALUES, - SPACE_JUNK_ENABLED, SPACE_JUNK_LIMIT: SPACE_JUNK_LIMIT.toNumber(), PLANET_LEVEL_JUNK: [ @@ -548,6 +586,7 @@ export class ContractsAPI extends EventEmitter { defaultSilverGrowth: planetDefaults.silverGrowth, defaultSilverCap: planetDefaults.silverCap, defaultBarbarianPercentage: planetDefaults.barbarianPercentage, + planetLevelThresholds, planetCumulativeRarities, upgrades, @@ -555,6 +594,7 @@ export class ContractsAPI extends EventEmitter { // Capture Zones GAME_START_BLOCK: GAME_START_BLOCK.toNumber(), CAPTURE_ZONES_ENABLED, + CAPTURE_ZONE_COUNT: CAPTURE_ZONE_COUNT.toNumber(), CAPTURE_ZONE_CHANGE_BLOCK_INTERVAL: CAPTURE_ZONE_CHANGE_BLOCK_INTERVAL.toNumber(), CAPTURE_ZONE_RADIUS: CAPTURE_ZONE_RADIUS.toNumber(), CAPTURE_ZONE_PLANET_LEVEL_SCORE: [ @@ -571,76 +611,36 @@ export class ContractsAPI extends EventEmitter { ], CAPTURE_ZONE_HOLD_BLOCKS_REQUIRED: CAPTURE_ZONE_HOLD_BLOCKS_REQUIRED.toNumber(), CAPTURE_ZONES_PER_5000_WORLD_RADIUS: CAPTURE_ZONES_PER_5000_WORLD_RADIUS.toNumber(), - SPACESHIPS: SPACESHIPS, - ROUND_END_REWARDS_BY_RANK: [ - ROUND_END_REWARDS_BY_RANK[0].toNumber(), - ROUND_END_REWARDS_BY_RANK[1].toNumber(), - ROUND_END_REWARDS_BY_RANK[2].toNumber(), - ROUND_END_REWARDS_BY_RANK[3].toNumber(), - ROUND_END_REWARDS_BY_RANK[4].toNumber(), - ROUND_END_REWARDS_BY_RANK[5].toNumber(), - ROUND_END_REWARDS_BY_RANK[6].toNumber(), - ROUND_END_REWARDS_BY_RANK[7].toNumber(), - ROUND_END_REWARDS_BY_RANK[8].toNumber(), - ROUND_END_REWARDS_BY_RANK[9].toNumber(), - ROUND_END_REWARDS_BY_RANK[10].toNumber(), - ROUND_END_REWARDS_BY_RANK[11].toNumber(), - ROUND_END_REWARDS_BY_RANK[12].toNumber(), - ROUND_END_REWARDS_BY_RANK[13].toNumber(), - ROUND_END_REWARDS_BY_RANK[14].toNumber(), - ROUND_END_REWARDS_BY_RANK[15].toNumber(), - ROUND_END_REWARDS_BY_RANK[16].toNumber(), - ROUND_END_REWARDS_BY_RANK[17].toNumber(), - ROUND_END_REWARDS_BY_RANK[18].toNumber(), - ROUND_END_REWARDS_BY_RANK[19].toNumber(), - ROUND_END_REWARDS_BY_RANK[20].toNumber(), - ROUND_END_REWARDS_BY_RANK[21].toNumber(), - ROUND_END_REWARDS_BY_RANK[22].toNumber(), - ROUND_END_REWARDS_BY_RANK[23].toNumber(), - ROUND_END_REWARDS_BY_RANK[24].toNumber(), - ROUND_END_REWARDS_BY_RANK[25].toNumber(), - ROUND_END_REWARDS_BY_RANK[26].toNumber(), - ROUND_END_REWARDS_BY_RANK[27].toNumber(), - ROUND_END_REWARDS_BY_RANK[28].toNumber(), - ROUND_END_REWARDS_BY_RANK[29].toNumber(), - ROUND_END_REWARDS_BY_RANK[30].toNumber(), - ROUND_END_REWARDS_BY_RANK[31].toNumber(), - ROUND_END_REWARDS_BY_RANK[32].toNumber(), - ROUND_END_REWARDS_BY_RANK[33].toNumber(), - ROUND_END_REWARDS_BY_RANK[34].toNumber(), - ROUND_END_REWARDS_BY_RANK[35].toNumber(), - ROUND_END_REWARDS_BY_RANK[36].toNumber(), - ROUND_END_REWARDS_BY_RANK[37].toNumber(), - ROUND_END_REWARDS_BY_RANK[38].toNumber(), - ROUND_END_REWARDS_BY_RANK[39].toNumber(), - ROUND_END_REWARDS_BY_RANK[40].toNumber(), - ROUND_END_REWARDS_BY_RANK[41].toNumber(), - ROUND_END_REWARDS_BY_RANK[42].toNumber(), - ROUND_END_REWARDS_BY_RANK[43].toNumber(), - ROUND_END_REWARDS_BY_RANK[44].toNumber(), - ROUND_END_REWARDS_BY_RANK[45].toNumber(), - ROUND_END_REWARDS_BY_RANK[46].toNumber(), - ROUND_END_REWARDS_BY_RANK[47].toNumber(), - ROUND_END_REWARDS_BY_RANK[48].toNumber(), - ROUND_END_REWARDS_BY_RANK[49].toNumber(), - ROUND_END_REWARDS_BY_RANK[50].toNumber(), - ROUND_END_REWARDS_BY_RANK[51].toNumber(), - ROUND_END_REWARDS_BY_RANK[52].toNumber(), - ROUND_END_REWARDS_BY_RANK[53].toNumber(), - ROUND_END_REWARDS_BY_RANK[54].toNumber(), - ROUND_END_REWARDS_BY_RANK[55].toNumber(), - ROUND_END_REWARDS_BY_RANK[56].toNumber(), - ROUND_END_REWARDS_BY_RANK[57].toNumber(), - ROUND_END_REWARDS_BY_RANK[58].toNumber(), - ROUND_END_REWARDS_BY_RANK[59].toNumber(), - ROUND_END_REWARDS_BY_RANK[60].toNumber(), - ROUND_END_REWARDS_BY_RANK[61].toNumber(), - ROUND_END_REWARDS_BY_RANK[62].toNumber(), - ROUND_END_REWARDS_BY_RANK[63].toNumber(), + + MANUAL_SPAWN: MANUAL_SPAWN, + TARGET_PLANETS: TARGET_PLANETS, + CLAIM_VICTORY_ENERGY_PERCENT: CLAIM_VICTORY_ENERGY_PERCENT.toNumber(), + MODIFIERS: [ + MODIFIERS[0].toNumber(), + MODIFIERS[1].toNumber(), + MODIFIERS[2].toNumber(), + MODIFIERS[3].toNumber(), + MODIFIERS[4].toNumber(), + MODIFIERS[5].toNumber(), + MODIFIERS[6].toNumber(), + MODIFIERS[7].toNumber(), ], + SPACESHIPS: [SPACESHIPS[0], SPACESHIPS[1], SPACESHIPS[2], SPACESHIPS[3], SPACESHIPS[4]], + RANDOM_ARTIFACTS, + NO_ADMIN, + INIT_PLANET_HASHES, + CONFIG_HASH, + CONFIRM_START, + START_PAUSED, + BLOCK_CAPTURE, + BLOCK_MOVES, + TARGETS_REQUIRED_FOR_VICTORY: TARGETS_REQUIRED_FOR_VICTORY.toNumber(), + TEAMS_ENABLED, + NUM_TEAMS: NUM_TEAMS.toNumber(), + RANKED }; - return constants; + return constants; } public async getPlayers( @@ -648,16 +648,23 @@ export class ContractsAPI extends EventEmitter { ): Promise> { const nPlayers: number = (await this.makeCall(this.contract.getNPlayers)).toNumber(); - const players = await aggregateBulkGetter( + const players = await aggregateBulkGetter( nPlayers, 200, - async (start, end) => - (await this.makeCall(this.contract.bulkGetPlayers, [start, end])).map(decodePlayer), + async (start, end) => await this.makeCall(this.contract.bulkGetPlayers, [start, end]), + onProgress + ); + + const arenaPlayers = await aggregateBulkGetter( + nPlayers, + 200, + async (start, end) => await this.makeCall(this.contract.bulkGetArenaPlayers, [start, end]), onProgress ); const playerMap: Map = new Map(); - for (const player of players) { + for (let i = 0; i < nPlayers; i ++) { + const player = decodePlayer(players[i], arenaPlayers[i]); playerMap.set(player.address, player); } return playerMap; @@ -665,8 +672,10 @@ export class ContractsAPI extends EventEmitter { public async getPlayerById(playerId: EthAddress): Promise { const rawPlayer = await this.makeCall(this.contract.players, [playerId]); + const rawArenaPlayer = await this.makeCall(this.contract.arenaPlayers, [playerId]); + if (!rawPlayer.isInitialized) return undefined; - const player = decodePlayer(rawPlayer); + const player = decodePlayer(rawPlayer, rawArenaPlayer); return player; } @@ -733,6 +742,48 @@ export class ContractsAPI extends EventEmitter { return planetIds.map(locationIdFromEthersBN); } + public async getTargetPlanetIds( + startingAt: number, + onProgress?: (fractionCompleted: number) => void + ): Promise { + const nPlanets: number = ( + await this.makeCall(this.contract.getNTargetPlanets) + ).toNumber(); + + const planetIds = await aggregateBulkGetter( + nPlanets - startingAt, + 1000, + async (start, end) => + await this.makeCall(this.contract.bulkGetTargetPlanetIds, [ + start + startingAt, + end + startingAt, + ]), + onProgress + ); + return planetIds.map(locationIdFromEthersBN); + } + + public async getSpawnPlanetIds( + startingAt: number, + onProgress?: (fractionCompleted: number) => void + ): Promise { + const nPlanets: number = ( + await this.makeCall(this.contract.getNSpawnPlanets) + ).toNumber(); + + const planetIds = await aggregateBulkGetter( + nPlanets - startingAt, + 1000, + async (start, end) => + await this.makeCall(this.contract.bulkGetSpawnPlanetIds, [ + start + startingAt, + end + startingAt, + ]), + onProgress + ); + return planetIds.map(locationIdFromEthersBN); + } + public async getRevealedCoordsByIdIfExists( planetId: LocationId ): Promise { @@ -749,6 +800,25 @@ export class ContractsAPI extends EventEmitter { return this.makeCall(this.contract.paused); } + public async getGameover(): Promise { + return this.makeCall(this.contract.getGameover); + } + + public async getWinners(): Promise { + const winnerString = await this.makeCall(this.contract.getWinners); + return winnerString.map(w => address(w)); + } + + public async getStartTime(): Promise { + const startTime = (await this.makeCall(this.contract.getStartTime)).toNumber(); + return startTime == 0 ? undefined : startTime ; + } + + public async getEndTime(): Promise { + const endTime = (await this.makeCall(this.contract.getEndTime)).toNumber(); + return endTime == 0 ? undefined : endTime ; + } + public async getRevealedPlanetsCoords( startingAt: number, onProgressIds?: (fractionCompleted: number) => void, @@ -784,7 +854,8 @@ export class ContractsAPI extends EventEmitter { public async bulkGetPlanets( toLoadPlanets: LocationId[], - onProgressPlanet?: (fractionCompleted: number) => void + onProgressPlanet?: (fractionCompleted: number) => void, + onProgressMetadata?: (fractionCompleted: number) => void ): Promise> { const rawPlanets = await aggregateBulkGetter( toLoadPlanets.length, @@ -796,11 +867,53 @@ export class ContractsAPI extends EventEmitter { onProgressPlanet ); + const rawPlanetsExtendedInfo = await aggregateBulkGetter( + toLoadPlanets.length, + 200, + async (start, end) => + await this.makeCall(this.contract.bulkGetPlanetsExtendedInfoByIds, [ + toLoadPlanets.slice(start, end).map(locationIdToDecStr), + ]), + (fractionCompleted) => { + if (!onProgressMetadata) return; + onProgressMetadata(fractionCompleted / 2); + } + ); + + const rawPlanetsExtendedInfo2 = await aggregateBulkGetter( + toLoadPlanets.length, + 200, + async (start, end) => + await this.makeCall(this.contract.bulkGetPlanetsExtendedInfo2ByIds, [ + toLoadPlanets.slice(start, end).map(locationIdToDecStr), + ]), + (fractionCompleted) => { + if (!onProgressMetadata) return; + onProgressMetadata(0.5 + fractionCompleted / 2); + } + ); + + const rawPlanetsArenaInfo = await aggregateBulkGetter( + toLoadPlanets.length, + 200, + async (start, end) => + await this.makeCall(this.contract.bulkGetPlanetsArenaInfoByIds, [ + toLoadPlanets.slice(start, end).map(locationIdToDecStr), + ]), + onProgressMetadata + ); + const planets: Map = new Map(); for (let i = 0; i < toLoadPlanets.length; i += 1) { - if (!!rawPlanets[i]) { - const planet = decodePlanet(locationIdToDecStr(toLoadPlanets[i]), rawPlanets[i]); + if (!!rawPlanets[i] && !!rawPlanetsExtendedInfo[i]) { + const planet = decodePlanet( + locationIdToDecStr(toLoadPlanets[i]), + rawPlanets[i], + rawPlanetsExtendedInfo[i], + rawPlanetsExtendedInfo2[i], + rawPlanetsArenaInfo[i] + ); planet.transactions = new TxCollection(); planets.set(planet.locationId, planet); } @@ -810,50 +923,79 @@ export class ContractsAPI extends EventEmitter { public async getPlanetById(planetId: LocationId): Promise { const decStrId = locationIdToDecStr(planetId); + const rawExtendedInfo = await this.makeCall(this.contract.planetsExtendedInfo, [decStrId]); + const rawExtendedInfo2 = await this.makeCall(this.contract.planetsExtendedInfo2, [decStrId]); + const rawArenaInfo = await this.makeCall(this.contract.planetsArenaInfo, [decStrId]); + + if (!rawExtendedInfo[0]) return undefined; // planetExtendedInfo.isInitialized is false + if (!rawExtendedInfo2[0]) return undefined; // planetExtendedInfo.isInitialized is false const rawPlanet = await this.makeCall(this.contract.planets, [decStrId]); - return decodePlanet(decStrId, rawPlanet); + return decodePlanet(decStrId, rawPlanet, rawExtendedInfo, rawExtendedInfo2, rawArenaInfo); } - public async getPlayerArtifacts( - playerId?: EthAddress, - onProgress?: (percent: number) => void + public async getArtifactById(artifactId: ArtifactId): Promise { + const exists = await this.makeCall(this.contract.doesArtifactExist, [ + artifactIdToDecStr(artifactId), + ]); + if (!exists) return undefined; + const rawArtifact = await this.makeCall(this.contract.getArtifactById, [ + artifactIdToDecStr(artifactId), + ]); + + const artifact = decodeArtifact(rawArtifact); + artifact.transactions = new TxCollection(); + return artifact; + } + + public async bulkGetArtifactsOnPlanets( + locationIds: LocationId[], + onProgress?: (fractionCompleted: number) => void + ): Promise { + const rawArtifacts = await aggregateBulkGetter( + locationIds.length, + 200, + async (start, end) => + await this.makeCall(this.contract.bulkGetPlanetArtifacts, [ + locationIds.slice(start, end).map(locationIdToDecStr), + ]), + onProgress + ); + + return rawArtifacts.map((rawArtifactArray) => { + return rawArtifactArray.map(decodeArtifact); + }); + } + + public async bulkGetArtifacts( + artifactIds: ArtifactId[], + onProgress?: (fractionCompleted: number) => void ): Promise { - if (playerId === undefined) return []; + const rawArtifacts = await aggregateBulkGetter( + artifactIds.length, + 200, + async (start, end) => + await this.makeCall(this.contract.bulkGetArtifactsByIds, [ + artifactIds.slice(start, end).map(artifactIdToDecStr), + ]), + onProgress + ); - const tokenIds = await this.makeCall(this.contract.tokensByAccount, [playerId]); - if (onProgress) { - onProgress(0.95); - } - const artifacts = tokenIds.filter(isArtifact).map(decodeArtifact); - if (onProgress) { - onProgress(1); - } - return artifacts; + const ret: Artifact[] = rawArtifacts.map(decodeArtifact); + ret.forEach((a) => (a.transactions = new TxCollection())); + + return ret; } - public async getPlayerSpaceships( + public async getPlayerArtifacts( playerId?: EthAddress, onProgress?: (percent: number) => void - ): Promise { + ): Promise { if (playerId === undefined) return []; - const tokenIds = await this.makeCall(this.contract.tokensByAccount, [playerId]); - if (onProgress) { - onProgress(0.95); - } - const spaceships = tokenIds.filter(isSpaceship).map(decodeSpaceship); - if (onProgress) { - onProgress(1); - } - return spaceships; - } - - public async getUpgradeForArtifact(artifactId: ArtifactId): Promise { - const rawUpgrade = await this.makeCall(this.contract.getUpgradeForArtifact, [ - artifactIdToDecStr(artifactId), - ]); - - return decodeUpgrade(rawUpgrade); + const myArtifactIds = (await this.makeCall(this.contract.getPlayerArtifactIds, [playerId])).map( + artifactIdFromEthersBN + ); + return this.bulkGetArtifacts(myArtifactIds, onProgress); } public setDiagnosticUpdater(diagnosticUpdater?: DiagnosticUpdater) { @@ -866,6 +1008,14 @@ export class ContractsAPI extends EventEmitter { txIntent: T, overrides?: providers.TransactionRequest ): Promise> { + + /* Find a way to speed this up */ + const chainId = (await this.ethConnection.getProvider().getNetwork()).chainId; + overrides = overrides ?? {}; + + if (chainId === GNOSIS_OPTIMISM_CHAIN_ID) overrides.gasPrice = '1'; + if (chainId === KOVAN_OPTIMISM_CHAIN_ID) overrides.gasPrice = '100000'; + const queuedTx = await this.txExecutor.queueTransaction(txIntent, overrides); this.emit(ContractsAPIEvent.TxQueued, queuedTx); @@ -926,4 +1076,4 @@ export async function makeContractsAPI({ await connection.loadContract(contractAddress, loadDiamondContract); return new ContractsAPI({ connection, contractAddress }); -} +} \ No newline at end of file diff --git a/client/src/Backend/GameLogic/GameManager.ts b/client/src/Backend/GameLogic/GameManager.ts index fe7be87e..739d428f 100644 --- a/client/src/Backend/GameLogic/GameManager.ts +++ b/client/src/Backend/GameLogic/GameManager.ts @@ -3,26 +3,31 @@ import { CONTRACT_PRECISION, EMPTY_ADDRESS, MIN_PLANET_LEVEL, -} from '@dfdao/constants'; -import type { DarkForest } from '@dfdao/contracts/typechain'; -import { monomitter, Monomitter, Subscription } from '@dfdao/events'; -import { getRange, isLocatable, timeUntilNextBroadcastAvailable } from '@dfdao/gamelogic'; -import { fakeHash, mimcHash, perlin } from '@dfdao/hashing'; +} from '@darkforest_eth/constants'; +import type { DarkForest } from '@darkforest_eth/contracts/typechain'; +import { monomitter, Monomitter, Subscription } from '@darkforest_eth/events'; +import { + getRange, + isActivated, + isLocatable, + isSpaceShip, + timeUntilNextBroadcastAvailable, +} from '@darkforest_eth/gamelogic'; +import { fakeHash, mimcHash, perlin } from '@darkforest_eth/hashing'; import { createContract, EthConnection, ThrottledConcurrentQueue, verifySignature, weiToEth, -} from '@dfdao/network'; -import { getPlanetName } from '@dfdao/procedural'; +} from '@darkforest_eth/network'; +import { getPlanetName } from '@darkforest_eth/procedural'; import { artifactIdToDecStr, - artifactIdToEthersBN, - decodeArtifact, isUnconfirmedActivateArtifactTx, isUnconfirmedBuyHatTx, isUnconfirmedCapturePlanetTx, + isUnconfirmedClaimVictoryTx, isUnconfirmedDeactivateArtifactTx, isUnconfirmedDepositArtifactTx, isUnconfirmedFindArtifactTx, @@ -36,8 +41,7 @@ import { isUnconfirmedWithdrawSilverTx, locationIdFromBigInt, locationIdToDecStr, - spaceshipIdToDecStr, -} from '@dfdao/serde'; +} from '@darkforest_eth/serde'; import { Artifact, ArtifactId, @@ -56,6 +60,7 @@ import { PlanetLevel, PlanetMessageType, PlanetType, + PlanetTypeNames, Player, QueuedArrival, Radii, @@ -64,23 +69,23 @@ import { RevealedLocation, Setting, SignedMessage, - Spaceship, - SpaceshipId, SpaceType, Transaction, TxIntent, UnconfirmedActivateArtifact, UnconfirmedBuyHat, UnconfirmedCapturePlanet, - UnconfirmedClaimReward, + UnconfirmedClaimVictory, UnconfirmedDeactivateArtifact, UnconfirmedDepositArtifact, UnconfirmedFindArtifact, UnconfirmedInit, UnconfirmedInvadePlanet, UnconfirmedMove, + UnconfirmedNotReady, UnconfirmedPlanetTransfer, UnconfirmedProspectPlanet, + UnconfirmedReady, UnconfirmedReveal, UnconfirmedUpgrade, UnconfirmedWithdrawArtifact, @@ -89,13 +94,14 @@ import { VoyageId, WorldCoords, WorldLocation, -} from '@dfdao/types'; + Wormhole, +} from '@darkforest_eth/types'; import bigInt, { BigInteger } from 'big-integer'; import delay from 'delay'; -import { BigNumber, Contract, ContractInterface, providers } from 'ethers'; +import { BigNumber, Contract, ContractInterface, constants, providers } from 'ethers'; import { EventEmitter } from 'events'; import NotificationManager from '../../Frontend/Game/NotificationManager'; -import { MIN_CHUNK_SIZE } from '../../Frontend/Utils/constants'; +import { competitiveConfig, MIN_CHUNK_SIZE } from '../../Frontend/Utils/constants'; import { Diff, generateDiffEmitter, getDisposableEmitter } from '../../Frontend/Utils/EmitterUtils'; import { getBooleanSetting, @@ -111,6 +117,7 @@ import { TerminalHandle } from '../../Frontend/Views/Terminal'; import { ContractConstants, ContractsAPIEvent, + MoveArgIdxs, MoveArgs, ZKArgIdx, } from '../../_types/darkforest/api/ContractsAPITypes'; @@ -125,7 +132,7 @@ import { TowardsCenterPatternV2, } from '../Miner/MiningPatterns'; import { eventLogger, EventType } from '../Network/EventLogger'; -import { loadLeaderboard } from '../Network/LeaderboardApi'; +import { loadLeaderboard } from '../Network/GraphApi/LeaderboardApi'; import { addMessage, deleteMessages, getMessagesOnPlanets } from '../Network/MessageAPI'; import { loadNetworkHealth } from '../Network/NetworkHealthApi'; import { @@ -134,11 +141,10 @@ import { verifyTwitterHandle, } from '../Network/UtilityServerAPI'; import { SerializedPlugin } from '../Plugins/SerializedPlugin'; -import OtherStore from '../Storage/OtherStore'; import PersistentChunkStore from '../Storage/PersistentChunkStore'; import { easeInAnimation, emojiEaseOutAnimation } from '../Utils/Animation'; import SnarkArgsHelper from '../Utils/SnarkArgsHelper'; -import { hexifyBigIntNestedArray } from '../Utils/Utils'; +import { getDeterministicArtifact, hexifyBigIntNestedArray } from '../Utils/Utils'; import { getEmojiMessage } from './ArrivalUtils'; import { CaptureZoneGenerator, CaptureZonesGeneratedEvent } from './CaptureZoneGenerator'; import { ContractsAPI, makeContractsAPI } from './ContractsAPI'; @@ -150,7 +156,10 @@ export enum GameManagerEvent { DiscoveredNewChunk = 'DiscoveredNewChunk', InitializedPlayer = 'InitializedPlayer', InitializedPlayerError = 'InitializedPlayerError', + ArtifactUpdate = 'ArtifactUpdate', Moved = 'Moved', + TargetPlanetInvaded = 'TargetPlanetInvaded', + Gameover = 'Gameover', } class GameManager extends EventEmitter { @@ -205,8 +214,14 @@ class GameManager extends EventEmitter { * or something like that. */ private readonly persistentChunkStore: PersistentChunkStore; - // Literally other storage stuff that people dumped into the chunk store - private readonly otherStore: OtherStore; + + /** + * An object that syncs any newly added or deleted chunks to the player's IndexedDB. + * + * @todo it also persists other game data to IndexedDB. This class needs to be renamed `GameSaver` + * or something like that. + */ + private readonly configHashPersistentChunkStore: PersistentChunkStore; /** * Responsible for generating snark proofs. @@ -235,7 +250,12 @@ class GameManager extends EventEmitter { /** * @todo change this to the correct timestamp each round. */ - private readonly endTimeSeconds: number = 1948939200; // new Date("2031-10-05T04:00:00.000Z").getTime() / 1000 + private startTime: number | undefined; + + /** + * @todo change this to the correct timestamp each round. + */ + private endTimeSeconds: number | undefined; /** * An interface to the blockchain that is a little bit lower-level than {@link ContractsAPI}. It @@ -328,6 +348,8 @@ class GameManager extends EventEmitter { public paused$: Monomitter; + public gameStarted$: Monomitter; + /** * Diagnostic information about the game. */ @@ -349,6 +371,17 @@ class GameManager extends EventEmitter { return this.contractConstants.PLANET_RARITY; } + public get planetLevelThresholds(): number[] { + return this.contractConstants.PLANET_LEVEL_THRESHOLDS; + } + + private gameover: boolean; + + public gameover$: Monomitter; + + private winners: EthAddress[]; + + private spectator: boolean; /** * Generates capture zones. */ @@ -368,14 +401,18 @@ class GameManager extends EventEmitter { contractsAPI: ContractsAPI, contractConstants: ContractConstants, persistentChunkStore: PersistentChunkStore, - otherStore: OtherStore, snarkHelper: SnarkArgsHelper, homeLocation: WorldLocation | undefined, useMockHash: boolean, + artifacts: Map, ethConnection: EthConnection, paused: boolean, - myArtifacts: Map, - mySpaceships: Map + gameover: boolean, + winners: EthAddress[], + spectator: boolean, + startTime: number | undefined, + endTime: number | undefined, + configHashPersistentChunkStore: PersistentChunkStore ) { super(); @@ -400,7 +437,11 @@ class GameManager extends EventEmitter { this.worldRadius = worldRadius; this.networkHealth$ = monomitter(true); this.paused$ = monomitter(true); + this.gameStarted$ = monomitter(this.getGameStarted()); this.playersUpdated$ = monomitter(); + this.gameover = gameover; + this.winners = winners; + this.gameover$ = monomitter(true); if (contractConstants.CAPTURE_ZONES_ENABLED) { this.captureZoneGenerator = new CaptureZoneGenerator( @@ -418,6 +459,7 @@ class GameManager extends EventEmitter { perlinMirrorX: contractConstants.PERLIN_MIRROR_X, perlinMirrorY: contractConstants.PERLIN_MIRROR_Y, planetRarity: contractConstants.PLANET_RARITY, + planetLevelThresholds: contractConstants.PLANET_LEVEL_THRESHOLDS, }; this.planetHashMimc = useMockHash ? fakeHash(this.hashConfig.planetRarity) @@ -460,29 +502,30 @@ class GameManager extends EventEmitter { } } - // TODO: Untangle this mess this.entityStore = new GameObjects( account, touchedPlanets, allTouchedPlanetIds, revealedLocations, claimedLocations, + artifacts, persistentChunkStore.allChunks(), unprocessedArrivals, unprocessedPlanetArrivalIds, + this, contractConstants, - worldRadius, - myArtifacts, - mySpaceships + worldRadius ); this.contractsAPI = contractsAPI; this.persistentChunkStore = persistentChunkStore; - this.otherStore = otherStore; + this.configHashPersistentChunkStore = configHashPersistentChunkStore; this.snarkHelper = snarkHelper; this.useMockHash = useMockHash; this.paused = paused; - + this.startTime = startTime; + this.endTimeSeconds = endTime; + this.spectator = spectator; this.ethConnection = ethConnection; this.diagnosticsInterval = setInterval(this.uploadDiagnostics.bind(this), 10_000); @@ -512,7 +555,8 @@ class GameManager extends EventEmitter { this.refreshScoreboard(); this.refreshNetworkHealth(); - this.getSpaceships(); + + // if (!spectator) this.getSpaceships(); this.safeMode = false; } @@ -573,10 +617,14 @@ class GameManager extends EventEmitter { connection, terminal, contractAddress, + spectator, + configHash, }: { connection: EthConnection; terminal: React.MutableRefObject; contractAddress: EthAddress; + spectator: boolean; + configHash?: string; }): Promise { if (!terminal.current) { throw new Error('you must pass in a handle to a terminal'); @@ -593,45 +641,61 @@ class GameManager extends EventEmitter { terminal.current?.println('Loading game data from disk...'); - const persistentChunkStore = new PersistentChunkStore({ account, contractAddress }); - const otherStore = await OtherStore.create({ account, contractAddress }); + const persistentChunkStore = await PersistentChunkStore.create({ account, contractAddress }); + const configHashPersistentChunkStore = await PersistentChunkStore.create({ + account, + contractAddress, + configHash, + }); terminal.current?.println('Downloading data from Ethereum blockchain...'); terminal.current?.println('(the contract is very big. this may take a while)'); terminal.current?.newline(); - const initialState = await gameStateDownloader.download( - contractsAPI, - persistentChunkStore, - otherStore - ); - const possibleHomes = await otherStore.getHomeLocations(); + const initialState = await gameStateDownloader.download(contractsAPI, persistentChunkStore); + + let possibleHomes = undefined; + if (!spectator) possibleHomes = await persistentChunkStore.getHomeLocations(); terminal.current?.println(''); terminal.current?.println('Building Index...'); - await otherStore.saveTouchedPlanetIds(initialState.allTouchedPlanetIds); - await otherStore.saveRevealedCoords(initialState.allRevealedCoords); + await persistentChunkStore.saveTouchedPlanetIds(initialState.allTouchedPlanetIds); + await persistentChunkStore.saveRevealedCoords(initialState.allRevealedCoords); - const myArtifacts: Map = new Map(); + const knownArtifacts: Map = new Map(); - for (const myArtifact of initialState.myArtifacts) { - myArtifacts.set(myArtifact.id, myArtifact); + for (let i = 0; i < initialState.loadedPlanets.length; i++) { + const planet = initialState.touchedAndLocatedPlanets.get(initialState.loadedPlanets[i]); + + if (!planet) { + continue; + } + + planet.heldArtifactIds = initialState.heldArtifacts[i].map((a) => a.id); + + for (const heldArtifact of initialState.heldArtifacts[i]) { + knownArtifacts.set(heldArtifact.id, heldArtifact); + } } - const mySpaceships: Map = new Map(); + for (const myArtifact of initialState.myArtifacts) { + knownArtifacts.set(myArtifact.id, myArtifact); + } - for (const mySpaceship of initialState.mySpaceships) { - mySpaceships.set(mySpaceship.id, mySpaceship); + for (const artifact of initialState.artifactsOnVoyages) { + knownArtifacts.set(artifact.id, artifact); } // figure out what's my home planet let homeLocation: WorldLocation | undefined = undefined; - for (const loc of possibleHomes) { - if (initialState.allTouchedPlanetIds.includes(loc.hash)) { - homeLocation = loc; - await otherStore.confirmHomeLocation(loc); - break; + if (possibleHomes) { + for (const loc of possibleHomes) { + if (initialState.allTouchedPlanetIds.includes(loc.hash)) { + homeLocation = loc; + await persistentChunkStore.confirmHomeLocation(loc); + break; + } } } @@ -643,6 +707,7 @@ class GameManager extends EventEmitter { perlinMirrorX: initialState.contractConstants.PERLIN_MIRROR_X, perlinMirrorY: initialState.contractConstants.PERLIN_MIRROR_Y, planetRarity: initialState.contractConstants.PLANET_RARITY, + planetLevelThresholds: initialState.contractConstants.PLANET_LEVEL_THRESHOLDS, }; const useMockHash = initialState.contractConstants.DISABLE_ZK_CHECKS; @@ -664,14 +729,18 @@ class GameManager extends EventEmitter { contractsAPI, initialState.contractConstants, persistentChunkStore, - otherStore, snarkHelper, homeLocation, useMockHash, + knownArtifacts, connection, initialState.paused, - myArtifacts, - mySpaceships + initialState.gameover, + initialState.winners, + spectator, + initialState.startTime, + initialState.endTime, + configHashPersistentChunkStore ); gameManager.setPlayerTwitters(initialState.twitters); @@ -697,20 +766,9 @@ class GameManager extends EventEmitter { // set up listeners: whenever ContractsAPI reports some game state update, do some logic gameManager.contractsAPI - .on(ContractsAPIEvent.ArtifactWithdrawn, (owner: EthAddress, artifact: Artifact) => { - if (owner === account) { - gameManager.entityStore.addMyArtifact(artifact); - } - }) - .on(ContractsAPIEvent.ArtifactDeposited, (owner: EthAddress, artifact: Artifact) => { - if (owner === account) { - gameManager.entityStore.removeMyArtifact(artifact); - } - }) - .on(ContractsAPIEvent.SpaceshipFound, (owner: EthAddress, spaceship: Spaceship) => { - if (owner === account) { - gameManager.entityStore.addMySpaceship(spaceship); - } + .on(ContractsAPIEvent.ArtifactUpdate, async (artifactId: ArtifactId) => { + await gameManager.hardRefreshArtifact(artifactId); + gameManager.emit(GameManagerEvent.ArtifactUpdate, artifactId); }) .on( ContractsAPIEvent.PlanetTransferred, @@ -762,12 +820,12 @@ class GameManager extends EventEmitter { gameManager.entityStore.onTxIntent(tx); }) .on(ContractsAPIEvent.TxSubmitted, (tx: Transaction) => { - gameManager.otherStore.onEthTxSubmit(tx); + gameManager.persistentChunkStore.onEthTxSubmit(tx); gameManager.onTxSubmit(tx); }) .on(ContractsAPIEvent.TxConfirmed, async (tx: Transaction) => { if (!tx.hash) return; // this should never happen - gameManager.otherStore.onEthTxComplete(tx.hash); + gameManager.persistentChunkStore.onEthTxComplete(tx.hash); if (isUnconfirmedRevealTx(tx)) { await gameManager.hardRefreshPlanet(tx.intent.locationId); @@ -788,7 +846,14 @@ class GameManager extends EventEmitter { // mining manager should be initialized already via joinGame, but just in case... gameManager.initMiningManager(tx.intent.location.coords, 4); } else if (isUnconfirmedMoveTx(tx)) { - await Promise.all([gameManager.bulkHardRefreshPlanets([tx.intent.from, tx.intent.to])]); + if (!gameManager.startTime) { + gameManager.startTime = Date.now() / 1000; + } + const promises = [gameManager.bulkHardRefreshPlanets([tx.intent.from, tx.intent.to])]; + if (tx.intent.artifact) { + promises.push(gameManager.hardRefreshArtifact(tx.intent.artifact)); + } + await Promise.all(promises); } else if (isUnconfirmedUpgradeTx(tx)) { await gameManager.hardRefreshPlanet(tx.intent.locationId); } else if (isUnconfirmedBuyHatTx(tx)) { @@ -798,15 +863,27 @@ class GameManager extends EventEmitter { } else if (isUnconfirmedFindArtifactTx(tx)) { await gameManager.hardRefreshPlanet(tx.intent.planetId); } else if (isUnconfirmedDepositArtifactTx(tx)) { - await Promise.all([gameManager.hardRefreshPlanet(tx.intent.locationId)]); + await Promise.all([ + gameManager.hardRefreshPlanet(tx.intent.locationId), + gameManager.hardRefreshArtifact(tx.intent.artifactId), + ]); } else if (isUnconfirmedWithdrawArtifactTx(tx)) { - await Promise.all([await gameManager.hardRefreshPlanet(tx.intent.locationId)]); + await Promise.all([ + await gameManager.hardRefreshPlanet(tx.intent.locationId), + await gameManager.hardRefreshArtifact(tx.intent.artifactId), + ]); } else if (isUnconfirmedProspectPlanetTx(tx)) { await gameManager.softRefreshPlanet(tx.intent.planetId); } else if (isUnconfirmedActivateArtifactTx(tx)) { - await Promise.all([gameManager.hardRefreshPlanet(tx.intent.locationId)]); + await Promise.all([ + gameManager.hardRefreshPlanet(tx.intent.locationId), + gameManager.hardRefreshArtifact(tx.intent.artifactId), + ]); } else if (isUnconfirmedDeactivateArtifactTx(tx)) { - await Promise.all([gameManager.hardRefreshPlanet(tx.intent.locationId)]); + await Promise.all([ + gameManager.hardRefreshPlanet(tx.intent.locationId), + gameManager.hardRefreshArtifact(tx.intent.artifactId), + ]); } else if (isUnconfirmedWithdrawSilverTx(tx)) { await gameManager.softRefreshPlanet(tx.intent.locationId); } else if (isUnconfirmedCapturePlanetTx(tx)) { @@ -819,6 +896,8 @@ class GameManager extends EventEmitter { gameManager.hardRefreshPlayer(gameManager.getAccount()), gameManager.hardRefreshPlanet(tx.intent.locationId), ]); + } else if (isUnconfirmedClaimVictoryTx(tx)) { + await Promise.all([gameManager.hardRefreshPlayer(gameManager.getAccount())]); } gameManager.entityStore.clearUnconfirmedTxIntent(tx); @@ -827,7 +906,7 @@ class GameManager extends EventEmitter { .on(ContractsAPIEvent.TxErrored, async (tx: Transaction) => { gameManager.entityStore.clearUnconfirmedTxIntent(tx); if (tx.hash) { - gameManager.otherStore.onEthTxComplete(tx.hash); + gameManager.persistentChunkStore.onEthTxComplete(tx.hash); } gameManager.onTxReverted(tx); }) @@ -837,9 +916,17 @@ class GameManager extends EventEmitter { .on(ContractsAPIEvent.RadiusUpdated, async () => { const newRadius = await gameManager.contractsAPI.getWorldRadius(); gameManager.setRadius(newRadius); + }) + .on(ContractsAPIEvent.Gameover, async () => { + gameManager.setGameover(true); + gameManager.gameover$.publish(true); + }) + .on(ContractsAPIEvent.GameStarted, async (player: EthAddress, startTime: number) => { + gameManager.startTime = startTime; + gameManager.gameStarted$.publish(true); }); - const unconfirmedTxs = await otherStore.getUnconfirmedSubmittedEthTxs(); + const unconfirmedTxs = await persistentChunkStore.getUnconfirmedSubmittedEthTxs(); const confirmationQueue = new ThrottledConcurrentQueue({ invocationIntervalMs: 1000, maxInvocationsPerIntervalMs: 10, @@ -856,7 +943,9 @@ class GameManager extends EventEmitter { // we only want to initialize the mining manager if the player has already joined the game // if they haven't, we'll do this once the player has joined the game - if (!!homeLocation && initialState.players.has(account as string)) { + if (spectator) { + gameManager.initMiningManager({ x: 0, y: 0 }); + } else if (!!homeLocation && initialState.players.has(account as string)) { gameManager.initMiningManager(homeLocation.coords); } @@ -889,6 +978,8 @@ class GameManager extends EventEmitter { const planet = await this.contractsAPI.getPlanetById(planetId); if (!planet) return; const arrivals = await this.contractsAPI.getArrivalsForPlanet(planetId); + const artifactsOnPlanets = await this.contractsAPI.bulkGetArtifactsOnPlanets([planetId]); + const artifactsOnPlanet = artifactsOnPlanets[0]; const revealedCoords = await this.contractsAPI.getRevealedCoordsByIdIfExists(planetId); let revealedLocation: RevealedLocation | undefined; @@ -904,9 +995,16 @@ class GameManager extends EventEmitter { this.entityStore.replacePlanetFromContractData( planet, arrivals, + artifactsOnPlanet.map((a) => a.id), revealedLocation, claimedCoords?.revealer ); + + // it's important that we reload the artifacts that are on the planet after the move + // completes because this move could have been a photoid canon move. one of the side + // effects of this type of move is that the active photoid canon deactivates upon a move + // meaning we need to reload its data from the blockchain. + artifactsOnPlanet.forEach((a) => this.entityStore.replaceArtifactFromContractData(a)); } private async bulkHardRefreshPlanets(planetIds: LocationId[]): Promise { @@ -914,6 +1012,7 @@ class GameManager extends EventEmitter { const allVoyages = await this.contractsAPI.getAllArrivals(planetIds); const planetsToUpdateMap = await this.contractsAPI.bulkGetPlanets(planetIds); + const artifactsOnPlanets = await this.contractsAPI.bulkGetArtifactsOnPlanets(planetIds); planetsToUpdateMap.forEach((planet, locId) => { if (planetsToUpdateMap.has(locId)) { planetVoyageMap.set(locId, []); @@ -939,9 +1038,23 @@ class GameManager extends EventEmitter { const voyagesForPlanet = planetVoyageMap.get(planet.locationId); if (voyagesForPlanet) { - this.entityStore.replacePlanetFromContractData(planet, voyagesForPlanet); + this.entityStore.replacePlanetFromContractData( + planet, + voyagesForPlanet, + artifactsOnPlanets[i].map((a) => a.id) + ); } } + + for (const artifacts of artifactsOnPlanets) { + this.entityStore.replaceArtifactsFromContractData(artifacts); + } + } + + public async hardRefreshArtifact(artifactId: ArtifactId): Promise { + const artifact = await this.contractsAPI.getArtifactById(artifactId); + if (!artifact) return; + this.entityStore.replaceArtifactFromContractData(artifact); } private onTxSubmit(tx: Transaction): void { @@ -1036,7 +1149,7 @@ class GameManager extends EventEmitter { * The game ends at a particular time in the future - get this time measured * in seconds from the epoch. */ - public getEndTimeSeconds(): number { + public getEndTimeSeconds(): number | undefined { return this.endTimeSeconds; } @@ -1044,7 +1157,7 @@ class GameManager extends EventEmitter { * Dark Forest tokens can only be minted up to a certain time - get this time measured in seconds from epoch. */ public getTokenMintEndTimeSeconds(): number { - return this.contractConstants.TOKEN_MINT_END_SECONDS; + return this.contractConstants.TOKEN_MINT_END_TIMESTAMP; } /** @@ -1137,7 +1250,7 @@ class GameManager extends EventEmitter { * Returns whether or not the current round has ended. */ public isRoundOver(): boolean { - return Date.now() / 1000 > this.getTokenMintEndTimeSeconds(); + return this.gameover; } /** @@ -1214,6 +1327,7 @@ class GameManager extends EventEmitter { myPattern, this.worldRadius, this.planetRarity, + this.planetLevelThresholds, this.hashConfig, this.useMockHash ); @@ -1316,20 +1430,18 @@ class GameManager extends EventEmitter { } /** - * Gets the artifacts in the players wallet + * gets both deposited artifacts that are on planets i own as well as artifacts i own */ getMyArtifacts(): Artifact[] { if (!this.account) return []; + const ownedByMe = this.entityStore.getArtifactsOwnedBy(this.account); + const onPlanetsOwnedByMe = this.entityStore + .getArtifactsOnPlanetsOwnedBy(this.account) + // filter out space ships because they always show up + // in the `ownedByMe` array. + .filter((a) => !isSpaceShip(a.artifactType)); - return Array.from(this.entityStore.getMyArtifactMap().values()); - } - /** - * Gets the spaceships in the players wallet - */ - getMySpaceships(): Spaceship[] { - if (!this.account) return []; - - return Array.from(this.entityStore.getMySpaceshipMap().values()); + return [...ownedByMe, ...onPlanetsOwnedByMe]; } /** @@ -1373,6 +1485,21 @@ class GameManager extends EventEmitter { return player?.score; } + /** + * Gets the artifact with the given id. Null if no artifact with id exists. + */ + getArtifactWithId(artifactId?: ArtifactId): Artifact | undefined { + return this.entityStore.getArtifactById(artifactId); + } + + /** + * Gets the artifacts with the given ids, including ones we know exist but haven't been loaded, + * represented by `undefined`. + */ + getArtifactsWithIds(artifactIds: ArtifactId[] = []): Array { + return artifactIds.map((id) => this.getArtifactWithId(id)); + } + /** * Gets the level of the given planet. Returns undefined if the planet does not exist. Does * NOT update the planet if the planet is stale, which means this function is fast. @@ -1455,7 +1582,7 @@ class GameManager extends EventEmitter { * to link a twitter to their account. */ async getSignedTwitter(twitter: string): Promise { - return this.ethConnection.signMessage(twitter); + return this.ethConnection.signMessage(JSON.stringify({ twitter })); } /** @@ -1548,9 +1675,6 @@ class GameManager extends EventEmitter { getChunkStore(): PersistentChunkStore { return this.persistentChunkStore; } - getOtherStore(): OtherStore { - return this.otherStore; - } /** * The perlin value at each coordinate determines the space type. There are four space @@ -1603,6 +1727,13 @@ class GameManager extends EventEmitter { } } + private async setGameover(gameover: boolean) { + this.gameover = gameover; + this.winners = await this.contractsAPI.getWinners(); + this.startTime = await this.contractsAPI.getStartTime(); + this.endTimeSeconds = await this.contractsAPI.getEndTime(); + } + private async refreshTwitters(): Promise { const addressTwitters = await getAllTwitters(); this.setPlayerTwitters(addressTwitters); @@ -1630,8 +1761,8 @@ class GameManager extends EventEmitter { } private checkGameHasEnded(): boolean { - if (Date.now() / 1000 > this.endTimeSeconds) { - this.terminal.current?.println('[ERROR] Game has ended.'); + if (this.gameover) { + this.terminal.current?.println('[ERROR] Game has ended.', TerminalTextStyle.Red); return true; } return false; @@ -1660,6 +1791,26 @@ class GameManager extends EventEmitter { ); } + /** + * Gets the timestamp (ms) of the next time that we can claim a planet. + */ + public getNextClaimAvailableTimestamp() { + if (!this.account) { + throw new Error('no account set'); + } + const myLastClaimTimestamp = this.players.get(this.account)?.lastClaimTimestamp; + + if (!myLastClaimTimestamp) { + return Date.now(); + } + if (!this.contractConstants.CLAIM_PLANET_COOLDOWN) { + return 0; + } + + // both the variables in the next line are denominated in seconds + return (myLastClaimTimestamp + this.contractConstants.CLAIM_PLANET_COOLDOWN) * 1000; + } + public getCaptureZones(): Set { return this.captureZoneGenerator?.getZones() || new Set(); } @@ -1855,16 +2006,140 @@ class GameManager extends EventEmitter { } } + public isTargetHeld(planet: Planet): boolean { + const constants = this.getContractConstants(); + if (!this.account) return false; + if (!planet.isTargetPlanet) return false; + if (constants.TEAMS_ENABLED) { + const owner = this.getPlayer(planet.owner); + const me = this.getPlayer(); + if (!owner || !me || owner.team !== me.team) return false; + } else if (planet.owner != this.account) return false; + if ((planet.energy * 100) / planet.energyCap < constants.CLAIM_VICTORY_ENERGY_PERCENT) + return false; + if (this.playerCaptureBlocked(this.account, planet.locationId)) return false; + return true; + } + + public checkVictoryCondition(): boolean { + const targetPlanets = this.getPlayerTargetPlanets(); + + let captured: number = 0; + + const constants = this.getContractConstants(); + for (const planet of targetPlanets) { + if (!this.isTargetHeld(planet)) continue; + + captured++; + if (captured >= this.targetsRequired) return true; + } + return false; + } + + public async claimVictory() { + try { + if (this.gameover) { + throw new Error('game is over'); + } + + if (this.paused) { + throw new Error('game is paused'); + } + + if (!this.checkVictoryCondition()) { + throw new Error('victory condition not met'); + } + + const txIntent: UnconfirmedClaimVictory = { + methodName: 'claimVictory', + contract: this.contractsAPI.contract, + args: Promise.resolve([]), + }; + + const tx = await this.contractsAPI.submitTransaction(txIntent); + return tx; + } catch (e) { + this.getNotificationsManager().txInitError('claimVictory', e.message); + throw e; + } + } + /** * Attempts to join the game. Should not be called once you've already joined. */ - public async joinGame(beforeRetry: (e: Error) => Promise): Promise { + public async joinGame(beforeRetry: (e: Error) => Promise, team: number): Promise { try { if (this.checkGameHasEnded()) { throw new Error('game has ended'); } - const planet = await this.findRandomHomePlanet(); + let planet: LocatablePlanet; + if (this.contractConstants.MANUAL_SPAWN) { + this.terminal.current?.println(``); + this.terminal.current?.println(`Retrieving available manual planets`); + this.terminal.current?.println(``); + + const spawnPlanets = await this.contractsAPI.getSpawnPlanetIds(0); + // console.log(`all manually created spawn planets: ${spawnPlanets}`); + const potentialHomeIds = spawnPlanets.filter((planetId) => { + const planet = this.getGameObjects().getPlanetWithId(planetId); + if (!planet) { + // console.log('not a planet'); + return false; + } + // console.log(`planet's owner: ${planet.owner}`); + if (planet.owner !== constants.AddressZero) { + return false; + } + if (!isLocatable(planet)) { + // console.log('planet not locatable'); + return false; + } + return true; + }); + + if (potentialHomeIds.length == 0) { + throw new Error('no spawn locations available'); + } + const potentialHomePlanets = potentialHomeIds.map((planetId) => { + return this.getGameObjects().getPlanetWithId(planetId) as LocatablePlanet; + }); + let selected = false; + let selection; + + // If only one spawn planet, don't let player choose. + if (potentialHomePlanets.length == 1) { + planet = potentialHomePlanets[0]; + } else { + do { + for (let i = 0; i < potentialHomePlanets.length; i++) { + const x = potentialHomePlanets[i].location.coords.x; + const y = potentialHomePlanets[i].location.coords.y; + const type = potentialHomePlanets[i].planetType; + + const level = potentialHomePlanets[i].planetLevel; + this.terminal.current?.print(`(${i + 1}): `, TerminalTextStyle.Sub); + this.terminal.current?.println( + `Level ${level} ${PlanetTypeNames[type]} at (${x},${y})` + ); + } + + this.terminal.current?.println(''); + this.terminal.current?.println(`Choose a spawn planet:`, TerminalTextStyle.White); + selection = +((await this.terminal.current?.getInput()) || ''); + if (isNaN(selection) || selection > potentialHomePlanets.length) { + this.terminal.current?.println('Unrecognized input. Please try again.'); + this.terminal.current?.println(''); + } else { + selected = true; + } + } while (!selected); + planet = potentialHomePlanets[selection - 1]; + } + } else { + planet = await this.findRandomHomePlanet(); + } + this.homeLocation = planet.location; this.terminal.current?.println(''); this.terminal.current?.println(`Found Suitable Home Planet: ${getPlanetName(planet)} `); @@ -1873,8 +2148,7 @@ class GameManager extends EventEmitter { ); this.terminal.current?.println(''); - await this.otherStore.addHomeLocation(planet.location); - + await this.persistentChunkStore.addHomeLocation(planet.location); const getArgs = async () => { const args = await this.snarkHelper.getInitArgs( planet.location.coords.x, @@ -1887,7 +2161,7 @@ class GameManager extends EventEmitter { TerminalTextStyle.Sub ); this.terminal.current?.newline(); - return args; + return [...args, team]; }; const txIntent: UnconfirmedInit = { @@ -1930,14 +2204,11 @@ class GameManager extends EventEmitter { this.getNotificationsManager().txInitError('initializePlayer', e.message); throw e; } + this.refreshTwitters(); } private async getSpaceships() { if (!this.account || !this.homeLocation?.hash) return; - if (!Object.values(this.contractConstants.SPACESHIPS).some((a) => a === true)) { - console.log('all spaceships disabled, not calling the tx'); - return; - } const player = await this.contractsAPI.getPlayerById(this.account); if (player?.claimedShips) return; @@ -1973,7 +2244,7 @@ class GameManager extends EventEmitter { */ async addAccount(coords: WorldCoords): Promise { const loc: WorldLocation = this.locationFromCoords(coords); - await this.otherStore.addHomeLocation(loc); + await this.persistentChunkStore.addHomeLocation(loc); this.initMiningManager(coords); this.homeLocation = loc; return true; @@ -2043,6 +2314,7 @@ class GameManager extends EventEmitter { pattern, this.worldRadius, this.planetRarity, + this.planetLevelThresholds, this.hashConfig, this.useMockHash ); @@ -2233,7 +2505,20 @@ class GameManager extends EventEmitter { const tx = await this.contractsAPI.submitTransaction(txIntent); - // TODO: Found notification (through events?) + tx.confirmedPromise + .then(() => { + return this.waitForPlanet(planet.locationId, ({ current }: Diff) => { + return current.heldArtifactIds + .map(this.getArtifactWithId.bind(this)) + .find((a: Artifact) => a?.planetDiscoveredOn === planet.locationId) as Artifact; + }).then((foundArtifact) => { + if (!foundArtifact) throw new Error('Artifact not found?'); + const notifManager = NotificationManager.getInstance(); + + notifManager.artifactFound(planet as LocatablePlanet, foundArtifact); + }); + }) + .catch(console.log); return tx; } catch (e) { @@ -2274,12 +2559,9 @@ class GameManager extends EventEmitter { const tx = await this.contractsAPI.submitTransaction(txIntent); - tx.confirmedPromise.then(() => { - this.getGameObjects().updatePlanet(locationId, (planet) => { - const artifact = decodeArtifact(artifactIdToEthersBN(artifactId)); - planet.artifacts.push(artifact); - }); - }); + tx.confirmedPromise.then(() => + this.getGameObjects().updateArtifact(artifactId, (a) => (a.onPlanetId = locationId)) + ); return tx; } catch (e) { @@ -2331,9 +2613,7 @@ class GameManager extends EventEmitter { const tx = await this.contractsAPI.submitTransaction(txIntent); tx.confirmedPromise.then(() => - this.getGameObjects().updatePlanet(locationId, (planet) => { - planet.artifacts = planet.artifacts.filter(({ id }) => id !== artifactId); - }) + this.getGameObjects().updateArtifact(artifactId, (a) => (a.onPlanetId = undefined)) ); return tx; @@ -2633,6 +2913,40 @@ class GameManager extends EventEmitter { return verifySignature(preSigned, message.signature as string, message.sender); } + public async ready() { + try { + const txIntent: UnconfirmedReady = { + methodName: 'ready', + contract: this.contractsAPI.contract, + args: Promise.resolve([]), + }; + // Always await the submitTransaction so we can catch rejections + const tx = await this.contractsAPI.submitTransaction(txIntent); + + return tx; + } catch (e) { + this.getNotificationsManager().txInitError('upgradePlanet', e.message); + throw e; + } + } + + public async notReady() { + try { + const txIntent: UnconfirmedNotReady = { + methodName: 'notReady', + contract: this.contractsAPI.contract, + args: Promise.resolve([]), + }; + // Always await the submitTransaction so we can catch rejections + const tx = await this.contractsAPI.submitTransaction(txIntent); + + return tx; + } catch (e) { + this.getNotificationsManager().txInitError('upgradePlanet', e.message); + throw e; + } + } + /** * Submits a transaction to the blockchain to move the given amount of resources from * the given planet to the given planet. @@ -2643,7 +2957,6 @@ class GameManager extends EventEmitter { forces: number, silver: number, artifactMoved?: ArtifactId, - spaceshipMoved?: SpaceshipId, abandoning = false, bypassChecks = false ): Promise> { @@ -2655,6 +2968,14 @@ class GameManager extends EventEmitter { throw new Error('game has ended'); } + if (this.paused) { + throw new Error('game is paused'); + } + + if (this.account && this.playerMoveBlocked(this.account, to)) { + throw new Error('Cannot move to a blocked planet'); + } + const arrivalsToOriginPlanet = this.entityStore.getArrivalIdsForLocation(from); const hasIncomingVoyage = arrivalsToOriginPlanet && arrivalsToOriginPlanet.length > 0; if (abandoning && hasIncomingVoyage) { @@ -2691,26 +3012,27 @@ class GameManager extends EventEmitter { if ( ((!bypassChecks && !this.account) || !oldPlanet || oldPlanet.owner !== this.account) && - !spaceshipMoved + !isSpaceShip(this.getArtifactWithId(artifactMoved)?.artifactType) ) { throw new Error('attempted to move from a planet not owned by player'); } - if (artifactMoved) { - if (!bypassChecks) { - if (oldPlanet?.activeArtifact?.id === artifactMoved) { - throw new Error("can't move an activated artifact"); - } - if (!oldPlanet?.artifacts?.find(({ id }) => id === artifactMoved)) { - throw new Error("that artifact isn't on this planet!"); - } + if (this.contractConstants.SPACE_JUNK_ENABLED && this.account) { + const toPlanetJunk = this.entityStore.getPlanetWithLocation(newLocation)?.spaceJunk; + const playerJunk = this.getPlayerSpaceJunk(this.account); + const junkLimit = this.getPlayerSpaceJunkLimit(this.account); + const fromPlanet = this.getPlanetWithId(from); + let energyAbandoning: number = 0; + if (abandoning && fromPlanet) { + energyAbandoning = this.getDefaultSpaceJunkForPlanetLevel(fromPlanet?.planetLevel) || 0; } - } - if (spaceshipMoved) { - if (!bypassChecks) { - if (!oldPlanet?.spaceships?.find(({ id }) => id === spaceshipMoved)) { - throw new Error("that spaceship isn't on this planet!"); - } + if ( + toPlanetJunk && + playerJunk && + junkLimit && + playerJunk + toPlanetJunk - energyAbandoning > junkLimit + ) { + throw new Error('player reached junk limit'); } } @@ -2728,11 +3050,13 @@ class GameManager extends EventEmitter { snarkArgs[ZKArgIdx.PROOF_A], snarkArgs[ZKArgIdx.PROOF_B], snarkArgs[ZKArgIdx.PROOF_C], - snarkArgs[ZKArgIdx.DATA], - (shipsMoved * CONTRACT_PRECISION).toString(), - (silverMoved * CONTRACT_PRECISION).toString(), - '0', - abandoning ? '1' : '0', + [ + ...snarkArgs[ZKArgIdx.DATA], + (shipsMoved * CONTRACT_PRECISION).toString(), + (silverMoved * CONTRACT_PRECISION).toString(), + '0', + abandoning ? '1' : '0', + ], ] as MoveArgs; this.terminal.current?.println('MOVE: calculated SNARK with args:', TerminalTextStyle.Sub); @@ -2743,10 +3067,7 @@ class GameManager extends EventEmitter { this.terminal.current?.newline(); if (artifactMoved) { - args[6] = artifactIdToDecStr(artifactMoved); - } - if (spaceshipMoved) { - args[6] = spaceshipIdToDecStr(spaceshipMoved); + args[ZKArgIdx.DATA][MoveArgIdxs.ARTIFACT_SENT] = artifactIdToDecStr(artifactMoved); } return args; @@ -2760,11 +3081,26 @@ class GameManager extends EventEmitter { to: newLocation.hash, forces: shipsMoved, silver: silverMoved, - // TODO: Make this less shit - artifact: artifactMoved || spaceshipMoved, + artifact: artifactMoved, abandoning, }; + if (artifactMoved) { + const artifact = this.entityStore.getArtifactById(artifactMoved); + + if (!bypassChecks) { + if (!artifact) { + throw new Error("couldn't find this artifact"); + } + if (isActivated(artifact)) { + throw new Error("can't move an activated artifact"); + } + if (!oldPlanet?.heldArtifactIds?.includes(artifactMoved)) { + throw new Error("that artifact isn't on this planet!"); + } + } + } + // Always await the submitTransaction so we can catch rejections const tx = await this.contractsAPI.submitTransaction(txIntent); @@ -2903,47 +3239,13 @@ class GameManager extends EventEmitter { } } - /** - * Receive XDAI for the claiming player based on their score rank at the end of the round. - */ - async claimRoundEndReward(bypassChecks = false): Promise> { - try { - if (!bypassChecks) { - if (!this.checkGameHasEnded()) { - throw new Error('game has not ended'); - } - } - - const allPlayers = await this.contractsAPI.getPlayers(); - const sortedPlayers = Array.from(allPlayers.values()).sort((a, b) => b.score - a.score); - const sortedPlayerAddresses = sortedPlayers.map((p) => p.address); - const sortedScores = sortedPlayers.map((p) => p.score); - - const txIntent: UnconfirmedClaimReward = { - methodName: 'claimReward', - contract: this.contractsAPI.contract, - args: Promise.resolve([sortedPlayerAddresses, sortedScores]), - sortedPlayerAddresses, - sortedScores, - }; - - // Always await the submitTransaction so we can catch rejections - const tx = await this.contractsAPI.submitTransaction(txIntent); - - return tx; - } catch (e) { - this.getNotificationsManager().txInitError('claimReward', e.message); - throw e; - } - } - /** * Makes this game manager aware of a new chunk - which includes its location, size, * as well as all of the planets contained in that chunk. Causes the client to load * all of the information about those planets from the blockchain. */ addNewChunk(chunk: Chunk): GameManager { - this.persistentChunkStore.addChunk(chunk); + this.persistentChunkStore.addChunk(chunk, true); for (const planetLocation of chunk.planetLocations) { this.entityStore.addPlanetLocation(planetLocation); @@ -2972,7 +3274,7 @@ class GameManager extends EventEmitter { ); const planetIdsToUpdate: LocationId[] = []; for (const chunk of chunks) { - this.persistentChunkStore.addChunk(chunk); + this.persistentChunkStore.addChunk(chunk, true); for (const planetLocation of chunk.planetLocations) { this.entityStore.addPlanetLocation(planetLocation); @@ -3116,6 +3418,16 @@ class GameManager extends EventEmitter { return ret; } + /** + * Gets the active artifact on this planet, if one exists. + */ + getActiveArtifact(planet: Planet): Artifact | undefined { + const artifacts = this.getArtifactsWithIds(planet.heldArtifactIds); + const active = artifacts.find((a) => a && isActivated(a)); + + return active; + } + /** * If there's an active artifact on either of these planets which happens to be a wormhole which * is active and targetting the other planet, return the wormhole boost which is greater. Values @@ -3125,21 +3437,21 @@ class GameManager extends EventEmitter { fromPlanet: Planet, toPlanet: Planet ): { distanceFactor: number; speedFactor: number } | undefined { - const fromActiveArtifact = fromPlanet.activeArtifact; - const toActiveArtifact = toPlanet.activeArtifact; + const fromActiveArtifact = this.getActiveArtifact(fromPlanet); + const toActiveArtifact = this.getActiveArtifact(toPlanet); let greaterRarity: ArtifactRarity | undefined; if ( fromActiveArtifact?.artifactType === ArtifactType.Wormhole && - fromPlanet.wormholeTo === toPlanet.locationId + fromActiveArtifact.wormholeTo === toPlanet.locationId ) { greaterRarity = fromActiveArtifact.rarity; } if ( toActiveArtifact?.artifactType === ArtifactType.Wormhole && - toPlanet.wormholeTo === fromPlanet.locationId + toActiveArtifact.wormholeTo === fromPlanet.locationId ) { if (greaterRarity === undefined) { greaterRarity = toActiveArtifact.rarity; @@ -3186,14 +3498,16 @@ class GameManager extends EventEmitter { * Load the serialized versions of all the plugins that this player has. */ public async loadPlugins(): Promise { - return this.otherStore.loadPlugins(); + console.log('loading Plugins from storage'); + return this.configHashPersistentChunkStore.loadPlugins(); } /** * Overwrites all the saved plugins to equal the given array of plugins. */ public async savePlugins(savedPlugins: SerializedPlugin[]): Promise { - await this.otherStore.savePlugins(savedPlugins); + await this.persistentChunkStore.savePlugins(savedPlugins); + await this.configHashPersistentChunkStore.savePlugins(savedPlugins); } /** @@ -3270,7 +3584,7 @@ class GameManager extends EventEmitter { return NotificationManager.getInstance(); } - getWormholes(): Iterable<[LocationId, LocationId]> { + getWormholes(): Iterable { return this.entityStore.getWormholes(); } @@ -3279,6 +3593,68 @@ class GameManager extends EventEmitter { return this.entityStore.getPlanetMap(); } + public getSpawnPlanets(): Planet[] { + const spawns = [...this.getPlanetMap()].filter(([, planet]) => planet.isSpawnPlanet); + return spawns.map((p) => p[1]); + } + + public getAllTargetPlanets(): Planet[] { + return [...this.getPlanetMap()].reduce( + (total, [location, planet]) => (planet.isTargetPlanet ? [...total, planet] : total), + [] + ); + } + + public getPlayerTargetPlanets(account?: EthAddress): Planet[] { + const player = this.getPlayer(account); + if (!player) return []; + return [...this.getPlanetMap()].reduce( + (total, [location, planet]) => + planet.isTargetPlanet && !this.isMoveBlocked(location, player.homePlanetId) + ? [...total, planet] + : total, + [] + ); + } + + public getAllBlocks(): { [dest: LocationId]: LocationId[] } { + const blocks: { [dest: LocationId]: LocationId[] } = {}; + + [...this.getPlanetMap()].forEach(([location, planet]) => { + if (planet.blockedPlanetIds.length > 0) blocks[location] = planet.blockedPlanetIds; + }); + return blocks; + } + + public getPlayerBlockedPlanets(account?: EthAddress): Planet[] { + const player = this.getPlayer(account); + if (!player) return []; + return [...this.getPlanetMap()].reduce( + (total, [location, planet]) => + !planet.isTargetPlanet && this.isMoveBlocked(location, player.homePlanetId) + ? [...total, planet] + : total, + [] + ); + } + + public getPlayerDefensePlanets(account?: EthAddress): Planet[] { + const player = this.getPlayer(account); + if (!player) return []; + return [...this.getPlanetMap()].reduce( + (total, [location, planet]) => + planet.isTargetPlanet && this.isMoveBlocked(location, player.homePlanetId) + ? [...total, planet] + : total, + [] + ); + } + + /** Return a reference to the artifact map */ + public getArtifactMap(): Map { + return this.entityStore.getArtifactMap(); + } + /** Return a reference to the map of my planets */ public getMyPlanetMap(): Map { return this.entityStore.getMyPlanetMap(); @@ -3293,16 +3669,17 @@ class GameManager extends EventEmitter { return this.entityStore.planetUpdated$; } + public getArtifactUpdated$(): Monomitter { + return this.entityStore.artifactUpdated$; + } + public getMyPlanetsUpdated$(): Monomitter> { return this.entityStore.myPlanetsUpdated$; } - public getMyArtifactsUpdated$(): Monomitter<[ArtifactId, Artifact | undefined]> { + public getMyArtifactsUpdated$(): Monomitter> { return this.entityStore.myArtifactsUpdated$; } - public getMySpaceshipsUpdated$(): Monomitter<[SpaceshipId, Spaceship | undefined]> { - return this.entityStore.mySpaceshipsUpdated$; - } /** * Returns an instance of a `Contract` from the ethersjs library. This is the library we use to @@ -3392,6 +3769,9 @@ class GameManager extends EventEmitter { }); }); } + public getIsSpectator() { + return this.spectator; + } public getSafeMode() { return this.safeMode; @@ -3409,6 +3789,68 @@ class GameManager extends EventEmitter { return this.getAddress() === this.contractConstants.adminAddress; } + public gameDuration() { + if (!this.startTime) { + return 0; + } + if (this.endTimeSeconds) { + return this.endTimeSeconds - this.startTime; + } + return Date.now() / 1000 - this.startTime; + } + + public getStartTime() { + return this.startTime; + } + + public claimVictoryPercentage() { + return this.contractConstants.CLAIM_VICTORY_ENERGY_PERCENT; + } + + // Return true if move is blocked in blocklist. + public isMoveBlocked(destId: LocationId, srcId: LocationId): boolean { + return ( + this.contractConstants.BLOCK_MOVES && + !!this.getPlanetWithId(destId)?.blockedPlanetIds.find((id) => id == srcId) + ); + } + + public isCaptureBlocked(destId: LocationId, srcId: LocationId): boolean { + return ( + this.contractConstants.BLOCK_CAPTURE && + !!this.getPlanetWithId(destId)?.blockedPlanetIds.find((id) => id == srcId) + ); + } + + public blockMoves(): boolean { + return this.contractConstants.BLOCK_MOVES; + } + + public blockCapture(): boolean { + return this.contractConstants.BLOCK_CAPTURE; + } + + public playerMoveBlocked(account: EthAddress, targetLocation: LocationId): boolean { + const player = this.getPlayer(account); + if (!player) return false; + return this.isMoveBlocked(targetLocation, player.homePlanetId); + } + + public playerCaptureBlocked(account: EthAddress, targetLocation: LocationId): boolean { + const player = this.getPlayer(account); + if (!player) return false; + return this.isCaptureBlocked(targetLocation, player.homePlanetId); + } + + public getTargetsHeld(address?: EthAddress): Planet[] { + address = address || this.account; + return this.getPlayerTargetPlanets().filter((planet) => this.isTargetHeld(planet)); + } + + get targetsRequired(): number { + return this.getContractConstants().TARGETS_REQUIRED_FOR_VICTORY; + } + /** * Right now the only buffs supported in this way are * speed/range buffs from Abandoning a planet. @@ -3457,8 +3899,44 @@ class GameManager extends EventEmitter { return this.paused$; } - public getUpgradeForArtifact(artifactId: ArtifactId) { - return this.contractsAPI.getUpgradeForArtifact(artifactId); + public getGameStarted(): boolean { + if (this.getStartTime() !== undefined) return true; + return false; + } + + public getGameStarted$(): Monomitter { + return this.gameStarted$; + } + + public getGameover(): boolean { + return this.gameover; + } + + public getGameover$(): Monomitter { + return this.gameover$; + } + + public getWinners(): EthAddress[] { + return this.winners; + } + + public isCompetitive(): boolean { + return this.contractConstants.CONFIG_HASH == competitiveConfig; + } + public getTeamsEnabled() { + return this.contractConstants.TEAMS_ENABLED; + } + + public getPlayerMoves(addr: EthAddress) { + const player = this.getPlayer(addr); + if (!player) throw new Error('Player not found'); + return player.moves; + } + + public getDeterministicArtifact(locationId: LocationId) { + const planet = this.getPlanetWithId(locationId) as LocatablePlanet; + if (!planet?.location) return null; + return getDeterministicArtifact(planet); } } diff --git a/client/src/Backend/GameLogic/GameObjects.ts b/client/src/Backend/GameLogic/GameObjects.ts index 5a48c613..73221f59 100644 --- a/client/src/Backend/GameLogic/GameObjects.ts +++ b/client/src/Backend/GameLogic/GameObjects.ts @@ -1,14 +1,15 @@ -import { EMPTY_ADDRESS, MAX_PLANET_LEVEL, MIN_PLANET_LEVEL } from '@dfdao/constants'; -import { Monomitter, monomitter } from '@dfdao/events'; -import { hasOwner, isLocatable } from '@dfdao/gamelogic'; -import { bonusFromHex, getBytesFromHex } from '@dfdao/hexgen'; -import { TxCollection } from '@dfdao/network'; +import { EMPTY_ADDRESS, MAX_PLANET_LEVEL, MIN_PLANET_LEVEL } from '@darkforest_eth/constants'; +import { Monomitter, monomitter } from '@darkforest_eth/events'; +import { hasOwner, isActivated, isLocatable } from '@darkforest_eth/gamelogic'; +import { bonusFromHex, getBytesFromHex } from '@darkforest_eth/hexgen'; +import { TxCollection } from '@darkforest_eth/network'; import { isUnconfirmedActivateArtifact, isUnconfirmedActivateArtifactTx, isUnconfirmedBuyHat, isUnconfirmedBuyHatTx, isUnconfirmedCapturePlanetTx, + isUnconfirmedClaimVictoryTx, isUnconfirmedDeactivateArtifact, isUnconfirmedDeactivateArtifactTx, isUnconfirmedDepositArtifact, @@ -31,12 +32,13 @@ import { isUnconfirmedWithdrawArtifactTx, isUnconfirmedWithdrawSilver, isUnconfirmedWithdrawSilverTx, -} from '@dfdao/serde'; +} from '@darkforest_eth/serde'; import { Abstract, ArrivalWithTimer, Artifact, ArtifactId, + ArtifactType, Biome, Chunk, ClaimedLocation, @@ -49,23 +51,29 @@ import { QueuedArrival, Radii, RevealedLocation, - Spaceship, - SpaceshipId, SpaceType, Transaction, TransactionCollection, VoyageId, WorldCoords, WorldLocation, -} from '@dfdao/types'; + Wormhole, +} from '@darkforest_eth/types'; import autoBind from 'auto-bind'; import bigInt from 'big-integer'; import { ethers } from 'ethers'; import _ from 'lodash'; import NotificationManager from '../../Frontend/Game/NotificationManager'; -import { getPlanetId, getPlanetOwner, setObjectSyncState } from '../../Frontend/Utils/EmitterUtils'; +import { + getArtifactId, + getArtifactOwner, + getPlanetId, + getPlanetOwner, + setObjectSyncState, +} from '../../Frontend/Utils/EmitterUtils'; import { ContractConstants } from '../../_types/darkforest/api/ContractsAPITypes'; import { arrive, PlanetDiff, updatePlanetToTime } from './ArrivalUtils'; +import GameManager from './GameManager'; import { LayeredMap } from './LayeredMap'; type CoordsString = Abstract; @@ -104,7 +112,7 @@ export class GameObjects { * * @todo extract the pattern we're using for the field tuples * - {planets, myPlanets, myPlanetsUpdated, planetUpdated$} - * - {artifacts, myArtifacts, myArtifactsUpdated} + * - {artifacts, myArtifacts, myArtifactsUpdated, artifactUpdated$} * * into some sort of class. */ @@ -118,22 +126,23 @@ export class GameObjects { private readonly myPlanets: Map; /** - * Cached index of artifacts in a players wallet. + * Cached index of all known artifact data. * * @see The same warning applys as the one on {@link GameObjects.planets} */ - private readonly myArtifacts: Map; + private readonly artifacts: Map; + /** - * Cached index of spaceships in a players wallet. + * Cached index of artifacts owned by the player. * * @see The same warning applys as the one on {@link GameObjects.planets} */ - private readonly mySpaceships: Map; + private readonly myArtifacts: Map; /** * Map from artifact ids to wormholes. */ - private readonly wormholes: Map; + private readonly wormholes: Map; /** * Set of all planet ids that we know have been interacted-with on-chain. @@ -181,6 +190,7 @@ export class GameObjects { */ private readonly contractConstants: ContractConstants; + private readonly gameManager: GameManager; /** * Map from a stringified representation of an x-y coordinate to an object that contains some more * information about the world at that location. @@ -197,6 +207,11 @@ export class GameObjects { */ public readonly planetUpdated$: Monomitter; + /** + * Event emitter which publishes whenever an artifact has been updated. + */ + public readonly artifactUpdated$: Monomitter; + /** * Whenever a planet is updated, we publish to this event with a reference to a map from location * id to planet. We need to rethink this event emitter because it currently publishes every time @@ -207,15 +222,10 @@ export class GameObjects { public readonly myPlanetsUpdated$: Monomitter>; /** - * Whenever an artifact changes in a player's wallet, this event emitter publishes. See + * Whenever one of the player's artifacts are updated, this event emitter publishes. See * {@link GameObjects.myPlanetsUpdated$} for more info. */ - public readonly myArtifactsUpdated$: Monomitter<[ArtifactId, Artifact | undefined]>; - /** - * Whenever a spaceship changes in a player's wallet, this event emitter publishes. See - * {@link GameObjects.myPlanetsUpdated$} for more info. - */ - public readonly mySpaceshipsUpdated$: Monomitter<[SpaceshipId, Spaceship | undefined]>; + public readonly myArtifactsUpdated$: Monomitter>; constructor( address: EthAddress | undefined, @@ -223,13 +233,13 @@ export class GameObjects { allTouchedPlanetIds: Set, revealedLocations: Map, claimedLocations: Map, + artifacts: Map, allChunks: Iterable, unprocessedArrivals: Map, unprocessedPlanetArrivalIds: Map, + gameManager: GameManager, contractConstants: ContractConstants, - worldRadius: number, - myArtifacts: Map, - mySpaceships: Map + worldRadius: number ) { autoBind(this); @@ -239,9 +249,10 @@ export class GameObjects { this.touchedPlanetIds = allTouchedPlanetIds; this.revealedLocations = revealedLocations; this.claimedLocations = claimedLocations; - this.myArtifacts = myArtifacts; - this.mySpaceships = mySpaceships; + this.artifacts = artifacts; + this.myArtifacts = new Map(); this.contractConstants = contractConstants; + this.gameManager = gameManager; this.coordsToLocation = new Map(); this.planetLocationMap = new Map(); const planetArrivalIds = new Map(); @@ -251,8 +262,8 @@ export class GameObjects { this.layeredMap = new LayeredMap(worldRadius); this.planetUpdated$ = monomitter(); + this.artifactUpdated$ = monomitter(); this.myArtifactsUpdated$ = monomitter(); - this.mySpaceshipsUpdated$ = monomitter(); this.myPlanetsUpdated$ = monomitter(); for (const chunk of allChunks) { @@ -265,6 +276,8 @@ export class GameObjects { this.addPlanetLocation(location); } + this.replaceArtifactsFromContractData(artifacts.values()); + touchedPlanets.forEach((planet, planetId) => { const arrivalIds = unprocessedPlanetArrivalIds.get(planetId); @@ -317,18 +330,52 @@ export class GameObjects { setInterval(() => { this.planets.forEach((planet) => { if (planet && hasOwner(planet)) { - updatePlanetToTime(planet, Date.now(), this.contractConstants); + updatePlanetToTime( + planet, + this.getPlanetArtifacts(planet.locationId), + Date.now(), + this.contractConstants + ); } }); }, 120 * 1000); } - public getWormholes(): Iterable<[LocationId, LocationId]> { - return this.wormholes.entries(); + public getWormholes(): Iterable { + return this.wormholes.values(); + } + + public getArtifactById(artifactId?: ArtifactId): Artifact | undefined { + return artifactId ? this.artifacts.get(artifactId) : undefined; + } + + public getArtifactsOwnedBy(addr: EthAddress): Artifact[] { + const ret: Artifact[] = []; + this.artifacts.forEach((artifact) => { + if (artifact.currentOwner === addr || artifact.controller === addr) { + ret.push(artifact); + } + }); + return ret; } public getPlanetArtifacts(planetId: LocationId): Artifact[] { - return this.planets.get(planetId)?.artifacts || []; + return (this.planets.get(planetId)?.heldArtifactIds || []) + .map((id) => this.artifacts.get(id)) + .filter((a) => !!a) as Artifact[]; + } + + public getArtifactsOnPlanetsOwnedBy(addr: EthAddress): Artifact[] { + const ret: Artifact[] = []; + this.artifacts.forEach((artifact) => { + if (artifact.onPlanetId) { + const planet = this.getPlanetWithId(artifact.onPlanetId, false); + if (planet && planet.owner === addr) { + ret.push(artifact); + } + } + }); + return ret; } // get planet by ID - must be in contract or known chunks @@ -370,6 +417,25 @@ export class GameObjects { } } + /** + * received some artifact data from the contract. update our stores + */ + public replaceArtifactFromContractData(artifact: Artifact): void { + const localArtifact = this.artifacts.get(artifact.id); + if (localArtifact) { + artifact.transactions = localArtifact.transactions; + artifact.onPlanetId = localArtifact.onPlanetId; + } + + this.setArtifact(artifact); + } + + public replaceArtifactsFromContractData(artifacts: Iterable) { + for (const artifact of artifacts) { + this.replaceArtifactFromContractData(artifact); + } + } + /** * Given a planet id, update the state of the given planet by calling the given update function. * If the planet was updated, then also publish the appropriate event. @@ -383,12 +449,26 @@ export class GameObjects { } } + /** + * Given a planet id, update the state of the given planet by calling the given update function. + * If the planet was updated, then also publish the appropriate event. + */ + public updateArtifact(id: ArtifactId | undefined, updateFn: (p: Artifact) => void) { + const artifact = this.getArtifactById(id); + + if (artifact !== undefined) { + updateFn(artifact); + this.setArtifact(artifact); + } + } + /** * received some planet data from the contract. update our stores */ public replacePlanetFromContractData( planet: Planet, updatedArrivals?: QueuedArrival[], + updatedArtifactsOnPlanet?: ArtifactId[], revealedLocation?: RevealedLocation, claimerEthAddress?: EthAddress // TODO: Remove this ): void { @@ -415,10 +495,16 @@ export class GameObjects { planet.emojiZoopAnimation = emojiZoopAnimation; planet.emojiZoopOutAnimation = emojiZoopOutAnimation; planet.messages = messages; + + // Possibly non updated props + planet.heldArtifactIds = localPlanet.heldArtifactIds; } else { this.planets.set(planet.locationId, planet); } + if (updatedArtifactsOnPlanet) { + planet.heldArtifactIds = updatedArtifactsOnPlanet; + } // make planet Locatable if we know its location const loc = this.planetLocationMap.get(planet.locationId) || revealedLocation; if (loc) { @@ -611,6 +697,13 @@ export class GameObjects { planet.transactions?.addTransaction(tx); this.setPlanet(planet); } + if (tx.intent.artifact) { + const artifact = this.getArtifactById(tx.intent.artifact); + if (artifact) { + artifact.transactions?.addTransaction(tx); + this.setArtifact(artifact); + } + } } else if (isUnconfirmedUpgradeTx(tx)) { const planet = this.getPlanetWithId(tx.intent.locationId); if (planet) { @@ -643,28 +736,48 @@ export class GameObjects { } } else if (isUnconfirmedDepositArtifactTx(tx)) { const planet = this.getPlanetWithId(tx.intent.locationId); + const artifact = this.getArtifactById(tx.intent.artifactId); if (planet) { planet.transactions?.addTransaction(tx); this.setPlanet(planet); } + if (artifact) { + artifact.transactions?.addTransaction(tx); + this.setArtifact(artifact); + } } else if (isUnconfirmedWithdrawArtifactTx(tx)) { const planet = this.getPlanetWithId(tx.intent.locationId); + const artifact = this.getArtifactById(tx.intent.artifactId); if (planet) { planet.transactions?.addTransaction(tx); this.setPlanet(planet); } + if (artifact) { + artifact.transactions?.addTransaction(tx); + this.setArtifact(artifact); + } } else if (isUnconfirmedActivateArtifactTx(tx)) { const planet = this.getPlanetWithId(tx.intent.locationId); + const artifact = this.getArtifactById(tx.intent.artifactId); if (planet) { planet.transactions?.addTransaction(tx); this.setPlanet(planet); } + if (artifact) { + artifact.transactions?.addTransaction(tx); + this.setArtifact(artifact); + } } else if (isUnconfirmedDeactivateArtifactTx(tx)) { const planet = this.getPlanetWithId(tx.intent.locationId); + const artifact = this.getArtifactById(tx.intent.artifactId); if (planet) { planet.transactions?.addTransaction(tx); this.setPlanet(planet); } + if (artifact) { + artifact.transactions?.addTransaction(tx); + this.setArtifact(artifact); + } } else if (isUnconfirmedWithdrawSilverTx(tx)) { const planet = this.getPlanetWithId(tx.intent.locationId); if (planet) { @@ -712,6 +825,13 @@ export class GameObjects { planet.transactions?.removeTransaction(tx); this.setPlanet(planet); } + if (tx.intent.artifact) { + const artifact = this.getArtifactById(tx.intent.artifact); + if (artifact) { + artifact.transactions?.removeTransaction(tx); + this.setArtifact(artifact); + } + } } else if (isUnconfirmedUpgrade(tx.intent)) { const planet = this.getPlanetWithId(tx.intent.locationId); if (planet) { @@ -733,18 +853,28 @@ export class GameObjects { } } else if (isUnconfirmedDepositArtifact(tx.intent)) { const planet = this.getPlanetWithId(tx.intent.locationId); + const artifact = this.getArtifactById(tx.intent.artifactId); if (planet) { planet.transactions?.removeTransaction(tx); this.setPlanet(planet); } + if (artifact) { + artifact.transactions?.removeTransaction(tx); + this.setArtifact(artifact); + } } else if (isUnconfirmedWithdrawArtifact(tx.intent)) { const planet = this.getPlanetWithId(tx.intent.locationId); + const artifact = this.getArtifactById(tx.intent.artifactId); if (planet) { planet.transactions?.removeTransaction(tx); this.setPlanet(planet); } + if (artifact) { + artifact.transactions?.removeTransaction(tx); + this.setArtifact(artifact); + } } else if (isUnconfirmedTransfer(tx.intent)) { const planet = this.getPlanetWithId(tx.intent.planetId); if (planet) { @@ -759,16 +889,26 @@ export class GameObjects { } } else if (isUnconfirmedActivateArtifact(tx.intent)) { const planet = this.getPlanetWithId(tx.intent.locationId); + const artifact = this.getArtifactById(tx.intent.artifactId); if (planet) { planet.transactions?.removeTransaction(tx); this.setPlanet(planet); } + if (artifact) { + artifact.transactions?.removeTransaction(tx); + this.setArtifact(artifact); + } } else if (isUnconfirmedDeactivateArtifact(tx.intent)) { const planet = this.getPlanetWithId(tx.intent.locationId); + const artifact = this.getArtifactById(tx.intent.artifactId); if (planet) { planet.transactions?.removeTransaction(tx); this.setPlanet(planet); } + if (artifact) { + artifact.transactions?.removeTransaction(tx); + this.setArtifact(artifact); + } } else if (isUnconfirmedWithdrawSilver(tx.intent)) { const planet = this.getPlanetWithId(tx.intent.locationId); if (planet) { @@ -794,6 +934,10 @@ export class GameObjects { return this.planets; } + public getArtifactMap(): Map { + return this.artifacts; + } + public getMyPlanetMap(): Map { return this.myPlanets; } @@ -801,28 +945,6 @@ export class GameObjects { public getMyArtifactMap(): Map { return this.myArtifacts; } - // TODO: This needs to track the AMOUNT of a given artifact in my wallet - public addMyArtifact(artifact: Artifact) { - this.myArtifacts.set(artifact.id, artifact); - this.myArtifactsUpdated$.publish([artifact.id, artifact]); - } - // TODO: This needs to track the AMOUNT of a given artifact in my wallet - public removeMyArtifact(artifact: Artifact) { - this.myArtifacts.delete(artifact.id); - this.myArtifactsUpdated$.publish([artifact.id, undefined]); - } - - public getMySpaceshipMap(): Map { - return this.mySpaceships; - } - public addMySpaceship(spaceship: Spaceship) { - this.mySpaceships.set(spaceship.id, spaceship); - this.mySpaceshipsUpdated$.publish([spaceship.id, spaceship]); - } - public removeMySpaceship(spaceship: Spaceship) { - this.mySpaceships.delete(spaceship.id); - this.mySpaceshipsUpdated$.publish([spaceship.id, undefined]); - } public getRevealedLocations(): Map { return this.revealedLocations; @@ -897,12 +1019,6 @@ export class GameObjects { this.layeredMap.insertPlanet(planet.location, planet.planetLevel); } - if (planet.wormholeTo) { - this.wormholes.set(planet.locationId, planet.wormholeTo); - } else { - this.wormholes.delete(planet.locationId); - } - setObjectSyncState( this.planets, this.myPlanets, @@ -915,6 +1031,35 @@ export class GameObjects { ); } + /** + * Set an artifact into our cached store. Should ALWAYS call this when setting an artifact. + * `this.artifacts` and `this.myArtifacts` should NEVER be accessed directly! + * This function also handles managing artifact update messages and indexing the map of owned artifacts. + * @param artifact the artifact to set + */ + private setArtifact(artifact: Artifact) { + if (artifact.artifactType === ArtifactType.Wormhole && artifact.onPlanetId) { + if (artifact.wormholeTo && isActivated(artifact)) { + this.wormholes.set(artifact.id, { + from: artifact.onPlanetId, + to: artifact.wormholeTo, + }); + } else { + this.wormholes.delete(artifact.id); + } + } + + setObjectSyncState( + this.artifacts, + this.myArtifacts, + this.address, + this.artifactUpdated$, + this.myArtifactsUpdated$, + getArtifactId, + getArtifactOwner, + artifact + ); + } /** * Emit notifications based on a planet's state change */ @@ -937,12 +1082,17 @@ export class GameObjects { if (previous.owner === this.address && current.owner !== this.address) { notifManager.planetLost(current as LocatablePlanet); } + const teamsEnabled = this.gameManager.getTeamsEnabled(); + const arrivalPlayer = this.gameManager.getPlayer(arrival.player); + const currentOwner = this.gameManager.getPlayer(current.owner); if ( arrival.player !== this.address && current.owner === this.address && arrival.energyArriving !== 0 ) { - notifManager.planetAttacked(current as LocatablePlanet); + if (teamsEnabled && arrivalPlayer?.team == currentOwner?.team) + notifManager.planetSupported(current as LocatablePlanet); + else notifManager.planetAttacked(current as LocatablePlanet); } } @@ -968,10 +1118,20 @@ export class GameObjects { arrivals.sort((a, b) => a.arrivalTime - b.arrivalTime); const nowInSeconds = Date.now() / 1000; for (const arrival of arrivals) { + const arrivalPlayer = this.gameManager.getPlayer(arrival.player); try { if (nowInSeconds - arrival.arrivalTime > 0) { + const toOwner = this.gameManager.getPlayer(planet.owner); // if arrival happened in the past, run this arrival - const update = arrive(planet, arrival, this.contractConstants); + const update = arrive( + planet, + this.getPlanetArtifacts(planet.locationId), + arrival, + this.getArtifactById(arrival.artifactId), + this.contractConstants, + arrivalPlayer, + toOwner + ); this.removeArrival(planetId, update.arrival.eventId); this.emitArrivalNotifications(update); @@ -979,7 +1139,17 @@ export class GameObjects { // otherwise, set a timer to do this arrival in the future // and append it to arrivalsWithTimers const applyFutureArrival = setTimeout(() => { - const update = arrive(planet, arrival, this.contractConstants); + const toOwner = this.gameManager.getPlayer(planet.owner); + + const update = arrive( + planet, + this.getPlanetArtifacts(planet.locationId), + arrival, + this.getArtifactById(arrival.artifactId), + this.contractConstants, + arrivalPlayer, + toOwner + ); this.emitArrivalNotifications(update); this.removeArrival(planetId, update.arrival.eventId); }, arrival.arrivalTime * 1000 - Date.now()); @@ -1024,7 +1194,7 @@ export class GameObjects { let ret = MIN_PLANET_LEVEL; for (let type = MAX_PLANET_LEVEL; type >= MIN_PLANET_LEVEL; type--) { - if (levelBigInt < bigInt(this.contractConstants.PLANET_LEVEL_THRESHOLDS[type])) { + if (levelBigInt < bigInt(this.contractConstants.planetLevelThresholds[type])) { ret = type; break; } @@ -1204,6 +1374,9 @@ export class GameObjects { const biome = this.getBiome(location); + const isTargetPlanet = false; + const isSpawnPlanet = false; + return { locationId: hex, perlin, @@ -1242,12 +1415,7 @@ export class GameObjects { silverSpent: 0, prospectedBlockNumber: undefined, - artifacts: [], - spaceships: [], - activeArtifact: undefined, - artifactActivationTime: 0, - wormholeTo: undefined, - + heldArtifactIds: [], destroyed: false, isInContract: this.touchedPlanetIds.has(hex), syncedWithContract: false, @@ -1258,18 +1426,26 @@ export class GameObjects { hasTriedFindingArtifact: false, messages: undefined, pausers: 0, - energyGroDoublers: 0, - silverGroDoublers: 0, invader: EMPTY_ADDRESS, capturer: EMPTY_ADDRESS, + + isTargetPlanet, + isSpawnPlanet, + blockedPlanetIds: [] }; } private updatePlanetIfStale(planet: Planet): void { const now = Date.now(); if (now / 1000 - planet.lastUpdated > 1) { - updatePlanetToTime(planet, now, this.contractConstants, this.setPlanet); + updatePlanetToTime( + planet, + this.getPlanetArtifacts(planet.locationId), + now, + this.contractConstants, + this.setPlanet + ); } } @@ -1308,6 +1484,32 @@ export class GameObjects { return planet.lastUpdated + timeToTarget; } + /** + * Returns the EthAddress of the player who can control the owner: + * if the artifact is on a planet, this is the owner of the planet + * if the artifact is on a voyage, this is the initiator of the voyage + * if the artifact is not on either, then it is the owner of the artifact NFT + */ + public getArtifactController(artifactId: ArtifactId): EthAddress | undefined { + const artifact = this.getArtifactById(artifactId); + if (!artifact) { + return undefined; + } + + if (artifact.onPlanetId) { + const planet = this.getPlanetWithId(artifact.onPlanetId); + if (!planet) { + return undefined; + } + return planet.owner === EMPTY_ADDRESS ? undefined : planet.owner; + } else if (artifact.onVoyageId) { + const arrival = this.arrivals.get(artifact.onVoyageId); + return arrival?.arrivalData.player || undefined; + } else { + return artifact.currentOwner === EMPTY_ADDRESS ? undefined : artifact.currentOwner; + } + } + /** * Get all of the incoming voyages for a given location. */ diff --git a/client/src/Backend/GameLogic/GameUIManager.ts b/client/src/Backend/GameLogic/GameUIManager.ts index d9a50e28..b75177e5 100644 --- a/client/src/Backend/GameLogic/GameUIManager.ts +++ b/client/src/Backend/GameLogic/GameUIManager.ts @@ -1,13 +1,14 @@ -import { EMPTY_ADDRESS } from '@dfdao/constants'; -import { Monomitter, monomitter } from '@dfdao/events'; -import { biomeName, isLocatable } from '@dfdao/gamelogic'; -import { planetHasBonus } from '@dfdao/hexgen'; -import { EthConnection } from '@dfdao/network'; -import { GameGLManager, Renderer } from '@dfdao/renderer'; -import { isUnconfirmedMoveTx } from '@dfdao/serde'; +import { EMPTY_ADDRESS } from '@darkforest_eth/constants'; +import { Monomitter, monomitter } from '@darkforest_eth/events'; +import { biomeName, isLocatable, isSpaceShip } from '@darkforest_eth/gamelogic'; +import { planetHasBonus } from '@darkforest_eth/hexgen'; +import { EthConnection } from '@darkforest_eth/network'; +import { GameGLManager, Renderer } from '@darkforest_eth/renderer'; +import { isUnconfirmedMoveTx } from '@darkforest_eth/serde'; import { Artifact, ArtifactId, + ArtifactType, BaseRenderer, Biome, Chunk, @@ -24,8 +25,6 @@ import { QueuedArrival, Rectangle, Setting, - Spaceship, - SpaceshipId, SpaceType, Transaction, UnconfirmedActivateArtifact, @@ -35,7 +34,8 @@ import { UpgradeBranchName, WorldCoords, WorldLocation, -} from '@dfdao/types'; + Wormhole, +} from '@darkforest_eth/types'; import autoBind from 'auto-bind'; import { BigNumber } from 'ethers'; import EventEmitter from 'events'; @@ -108,7 +108,6 @@ class GameUIManager extends EventEmitter { private silverSending: { [key: string]: number } = {}; // this is a percentage private artifactSending: { [key: string]: Artifact | undefined } = {}; - private spaceshipSending: { [key: string]: Spaceship | undefined } = {}; private plugins: PluginManager; @@ -116,7 +115,8 @@ class GameUIManager extends EventEmitter { public readonly hoverPlanetId$: Monomitter; public readonly hoverPlanet$: Monomitter; public readonly hoverArtifactId$: Monomitter; - public readonly hoverSpaceshipId$: Monomitter; + public readonly hoverArtifact$: Monomitter; + public readonly myArtifacts$: Monomitter>; public readonly isSending$: Monomitter; public readonly isAbandoning$: Monomitter; @@ -164,7 +164,12 @@ class GameUIManager extends EventEmitter { ); this.hoverArtifactId$ = monomitter(); - this.hoverSpaceshipId$ = monomitter(); + this.hoverArtifact$ = getObjectWithIdFromMap( + this.getArtifactMap(), + this.hoverArtifactId$, + this.gameManager.getArtifactUpdated$() + ); + this.myArtifacts$ = this.gameManager.getMyArtifactsUpdated$(); this.viewportEntities = new ViewportEntities(this.gameManager, this); this.isSending$ = monomitter(true); @@ -197,7 +202,7 @@ class GameUIManager extends EventEmitter { const uiEmitter = UIEmitter.getInstance(); const uiManager = new GameUIManager(gameManager, terminalHandle); - const modalManager = await ModalManager.create(gameManager.getOtherStore()); + const modalManager = await ModalManager.create(gameManager.getChunkStore()); uiManager.setModalManager(modalManager); @@ -310,8 +315,8 @@ class GameUIManager extends EventEmitter { } } - public joinGame(beforeRetry: (e: Error) => Promise): Promise { - return this.gameManager.joinGame(beforeRetry); + public joinGame(beforeRetry: (e: Error) => Promise, team : number): Promise { + return this.gameManager.joinGame(beforeRetry, team); } public addAccount(coords: WorldCoords): Promise { @@ -517,7 +522,7 @@ class GameUIManager extends EventEmitter { // make it so you leave one force behind if (this.isSendingShip(mouseDownPlanet.locationId)) { - tutorialManager.acceptInput(TutorialState.Spaceship); + tutorialManager.acceptInput(TutorialState.MoveSpaceship); forces = 0; } else if (forces >= from.energy) { forces = from.energy - 1; @@ -554,7 +559,6 @@ class GameUIManager extends EventEmitter { `df.move('${from.locationId}', '${to.locationId}', ${forces}, ${silver})` ); const artifact = this.getArtifactSending(from.locationId); - const spaceship = this.getSpaceshipSending(from.locationId); this.gameManager.move( from.locationId, @@ -562,9 +566,8 @@ class GameUIManager extends EventEmitter { forces, silver, artifact?.id, - spaceship?.id, abandoning - ); + ) tutorialManager.acceptInput(TutorialState.SendFleet); } @@ -599,7 +602,6 @@ class GameUIManager extends EventEmitter { public toggleExplore() { if (this.isMining()) { this?.stopExplore(); - TutorialManager.getInstance(this).acceptInput(TutorialState.MinerPause); } else { this?.startExplore(); } @@ -647,13 +649,10 @@ class GameUIManager extends EventEmitter { public setArtifactSending(planetId: LocationId, artifact?: Artifact) { this.artifactSending[planetId] = artifact; - this.gameManager.getGameObjects().forceTick(planetId); - } - - public setSpaceshipSending(planetId: LocationId, spaceship?: Spaceship) { - this.spaceshipSending[planetId] = spaceship; - this.abandoning = false; - this.isAbandoning$.publish(false); + if (this.isSendingShip(planetId)) { + this.abandoning = false; + this.isAbandoning$.publish(false); + } this.gameManager.getGameObjects().forceTick(planetId); } @@ -696,14 +695,30 @@ class GameUIManager extends EventEmitter { return this.gameManager.getTwitter(address); } - public getEndTimeSeconds(): number { + public getEndTimeSeconds(): number | undefined { return this.gameManager.getEndTimeSeconds(); } + public getTeamsEnabled(): boolean { + return this.gameManager.getTeamsEnabled(); + } + + public checkVictoryCondition() : boolean { + return this.gameManager.checkVictoryCondition(); + } + public isRoundOver(): boolean { return this.gameManager.isRoundOver(); } + public getTargetsHeld(address?: EthAddress) : Planet[] { + return this.gameManager.getTargetsHeld(address); + } + + public getTargetsRequired() : number { + return this.gameManager.targetsRequired; + } + public getUpgrade(branch: UpgradeBranchName, level: number): Upgrade { return this.gameManager.getUpgrade(branch, level); } @@ -760,11 +775,6 @@ class GameUIManager extends EventEmitter { public setSelectedPlanet(planet: LocatablePlanet | undefined): void { this.previousSelectedPlanetId = this.selectedPlanetId; - if (!planet) { - const tutorialManager = TutorialManager.getInstance(this); - tutorialManager.acceptInput(TutorialState.Deselect); - } - const uiEmitter = UIEmitter.getInstance(); this.selectedPlanetId = planet?.locationId; if (!planet) { @@ -778,7 +788,7 @@ class GameUIManager extends EventEmitter { if (coordsEqual(loc.coords, this.getHomeCoords())) { const tutorialManager = TutorialManager.getInstance(this); - tutorialManager.acceptInput(TutorialState.HomePlanet); + tutorialManager.acceptInput(TutorialState.Welcome); } } } @@ -809,7 +819,6 @@ class GameUIManager extends EventEmitter { // Set to undefined after SendComplete so it can send another one this.artifactSending[locationId] = undefined; - this.spaceshipSending[locationId] = undefined; this.sendingPlanet = undefined; // Done at the end so they clear the artifact @@ -998,9 +1007,7 @@ class GameUIManager extends EventEmitter { public setHoveringOverArtifact(artifactId?: ArtifactId) { this.hoverArtifactId$.publish(artifactId); - } - public setHoveringOverSpaceship(spaceshipId?: SpaceshipId) { - this.hoverSpaceshipId$.publish(spaceshipId); + this.hoverArtifact$.publish(artifactId ? this.getArtifactWithId(artifactId) : undefined); } public getHoveringOverPlanet(): Planet | undefined { @@ -1050,10 +1057,6 @@ class GameUIManager extends EventEmitter { if (!planetId) return undefined; return this.artifactSending[planetId]; } - public getSpaceshipSending(planetId?: LocationId): Spaceship | undefined { - if (!planetId) return undefined; - return this.spaceshipSending[planetId]; - } public getAbandonSpeedChangePercent(): number { const { SPACE_JUNK_ENABLED, ABANDON_SPEED_CHANGE_PERCENT } = this.contractConstants; @@ -1075,7 +1078,7 @@ class GameUIManager extends EventEmitter { public isSendingShip(planetId?: LocationId): boolean { if (!planetId) return false; - return this.spaceshipSending[planetId] !== undefined; + return isSpaceShip(this.artifactSending[planetId]?.artifactType); } public isOverOwnPlanet(coords: WorldCoords): Planet | undefined { @@ -1090,8 +1093,24 @@ class GameUIManager extends EventEmitter { public getMyArtifacts(): Artifact[] { return this.gameManager.getMyArtifacts(); } - public getMySpaceships(): Spaceship[] { - return this.gameManager.getMySpaceships(); + + public getMyArtifactsNotOnPlanet(): Artifact[] { + return this.getMyArtifacts().filter((a) => !a.onPlanetId); + } + + public getMySpaceships(): Artifact[] { + const ships = this.gameManager + .getMyArtifacts() + .filter( + (a) => + a.artifactType == ArtifactType.Spaceship || + a.artifactType == ArtifactType.ShipMothership || + a.artifactType == ArtifactType.ShipCrescent || + a.artifactType == ArtifactType.ShipWhale || + a.artifactType == ArtifactType.ShipGear || + a.artifactType == ArtifactType.ShipTitan + ); + return ships; } public getPlanetWithId(planetId: LocationId | undefined): Planet | undefined { @@ -1106,10 +1125,23 @@ class GameUIManager extends EventEmitter { return this.gameManager.getPlayer(address); } + public getArtifactWithId(artifactId: ArtifactId | undefined): Artifact | undefined { + return this.gameManager.getArtifactWithId(artifactId); + } + public getPlanetWithCoords(coords: WorldCoords | undefined): Planet | undefined { return coords && this.gameManager.getPlanetWithCoords(coords); } + public getArtifactsWithIds(artifactIds?: ArtifactId[]): Array { + return this.gameManager.getArtifactsWithIds(artifactIds); + } + + public getArtifactPlanet(artifact: Artifact): Planet | undefined { + if (!artifact.onPlanetId) return undefined; + return this.getPlanetWithId(artifact.onPlanetId); + } + public getPlanetLevel(planetId: LocationId): PlanetLevel | undefined { return this.gameManager.getPlanetLevel(planetId); } @@ -1152,7 +1184,7 @@ class GameUIManager extends EventEmitter { return this.gameManager.getUnconfirmedWormholeActivations(); } - public getWormholes(): Iterable<[LocationId, LocationId]> { + public getWormholes(): Iterable { return this.gameManager.getWormholes(); } @@ -1279,6 +1311,10 @@ class GameUIManager extends EventEmitter { return this.gameManager.getPlanetMap(); } + public getArtifactMap(): Map { + return this.gameManager.getArtifactMap(); + } + public getMyPlanetMap(): Map { return this.gameManager.getMyPlanetMap(); } @@ -1303,6 +1339,50 @@ class GameUIManager extends EventEmitter { return this.contractConstants.CAPTURE_ZONES_ENABLED; } + public get manualSpawnEnabled(): boolean { + return this.contractConstants.MANUAL_SPAWN; + } + + public get targetPlanetsEnabled(): boolean { + return this.contractConstants.TARGET_PLANETS; + } + + public getSpawnPlanets(): Planet[] { + return this.gameManager.getSpawnPlanets(); + } + + public getPlayerTargetPlanets(account? : EthAddress): Planet[] { + return this.gameManager.getPlayerTargetPlanets(account); + } + + public isTargetHeld(planet: Planet) : boolean { + return this.gameManager.isTargetHeld(planet); + } + + public blockMovesEnabled() :boolean { + return this.gameManager.blockMoves(); + } + + public playerMoveBlocked(player: EthAddress, planet: LocationId) : boolean { + return this.gameManager.playerMoveBlocked(player, planet); + } + + public getAllTargetPlanets() : Planet[] { + return this.gameManager.getAllTargetPlanets(); + } + + public playerCaptureBlocked(player: EthAddress, planet: LocationId) : boolean { + return this.gameManager.playerCaptureBlocked(player, planet); + } + + public getPlayerBlockedPlanets(account?: EthAddress) : Planet[] { + return this.gameManager.getPlayerBlockedPlanets(account); + } + + public getPlayerDefensePlanets(account?: EthAddress) : Planet[] { + return this.gameManager.getPlayerDefensePlanets(account); + } + public potentialCaptureScore(planetLevel: number): number { return this.contractConstants.CAPTURE_ZONE_PLANET_LEVEL_SCORE[planetLevel]; } @@ -1403,6 +1483,10 @@ class GameUIManager extends EventEmitter { return Renderer.instance; } + public isCompetitive() : boolean { + return this.gameManager.isCompetitive(); + } + getPaused(): boolean { return this.gameManager.getPaused(); } @@ -1411,6 +1495,37 @@ class GameUIManager extends EventEmitter { return this.gameManager.getPaused$(); } + get gameStarted(): boolean { + return this.gameManager.getGameStarted(); + } + + getGameStarted$(): Monomitter { + return this.gameManager.getGameStarted$(); + } + + getGameover(): boolean { + return this.gameManager.getGameover(); + } + + getGameover$(): Monomitter { + return this.gameManager.getGameover$(); + } + + getPlayerMoves(addr : EthAddress) { + return this.gameManager.getPlayerMoves(addr); + } + + public getWinners(): EthAddress[] { + return this.gameManager.getWinners(); + } + + public getGameDuration(): number { + return this.gameManager.gameDuration(); + } + public getClaimVictoryPercentage(): number { + return this.gameManager.claimVictoryPercentage(); + } + public getSilverScoreValue(): number { return this.contractConstants.SILVER_SCORE_VALUE; } @@ -1423,6 +1538,10 @@ class GameUIManager extends EventEmitter { return this.contractConstants.CAPTURE_ZONE_PLANET_LEVEL_SCORE; } + public getArtifactUpdated$() { + return this.gameManager.getArtifactUpdated$(); + } + public getUIEmitter() { return UIEmitter.getInstance(); } @@ -1465,17 +1584,6 @@ class GameUIManager extends EventEmitter { const renderer = this.getRenderer(); if (renderer) renderer.removeCustomRenderer(customRenderer); } - - public getUpgradeForArtifact(artifactId: ArtifactId) { - return this.gameManager.getUpgradeForArtifact(artifactId); - } - - public getMyArtifactsUpdated$() { - return this.gameManager.getMyArtifactsUpdated$(); - } - public getMySpaceshipsUpdated$() { - return this.gameManager.getMySpaceshipsUpdated$(); - } } export default GameUIManager; diff --git a/client/src/Backend/GameLogic/InitialGameStateDownloader.tsx b/client/src/Backend/GameLogic/InitialGameStateDownloader.tsx index 662e03ed..9e866d5a 100644 --- a/client/src/Backend/GameLogic/InitialGameStateDownloader.tsx +++ b/client/src/Backend/GameLogic/InitialGameStateDownloader.tsx @@ -1,14 +1,16 @@ import { Artifact, + ArtifactId, + BlocklistMap, ClaimedCoords, + EthAddress, LocationId, Planet, Player, QueuedArrival, RevealedCoords, - Spaceship, VoyageId, -} from '@dfdao/types'; +} from '@darkforest_eth/types'; import _ from 'lodash'; import React from 'react'; import { Link } from '../../Frontend/Components/CoreUI'; @@ -18,7 +20,6 @@ import { TerminalHandle } from '../../Frontend/Views/Terminal'; import { ContractConstants } from '../../_types/darkforest/api/ContractsAPITypes'; import { AddressTwitterMap } from '../../_types/darkforest/api/UtilityServerAPITypes'; import { tryGetAllTwitters } from '../Network/UtilityServerAPI'; -import OtherStore from '../Storage/OtherStore'; import PersistentChunkStore from '../Storage/PersistentChunkStore'; import { ContractsAPI } from './ContractsAPI'; @@ -31,8 +32,9 @@ export interface InitialGameState { allClaimedCoords?: ClaimedCoords[]; pendingMoves: QueuedArrival[]; touchedAndLocatedPlanets: Map; + artifactsOnVoyages: Artifact[]; myArtifacts: Artifact[]; - mySpaceships: Spaceship[]; + heldArtifacts: Artifact[][]; loadedPlanets: LocationId[]; revealedCoordsMap: Map; claimedCoordsMap?: Map; @@ -40,6 +42,10 @@ export interface InitialGameState { arrivals: Map; twitters: AddressTwitterMap; paused: boolean; + startTime: number | undefined; + endTime: number | undefined; + gameover: boolean; + winners: EthAddress[]; } export class InitialGameStateDownloader { @@ -61,19 +67,18 @@ export class InitialGameStateDownloader { async download( contractsAPI: ContractsAPI, - persistentChunkStore: PersistentChunkStore, - otherStore: OtherStore + persistentChunkStore: PersistentChunkStore ): Promise { + const isDev = process.env.NODE_ENV !== 'production'; + /** * In development we use the same contract address every time we deploy, * so storage is polluted with the IDs of old universes. */ - const storedTouchedPlanetIds = import.meta.env.DEV - ? [] - : await otherStore.getSavedTouchedPlanetIds(); - const storedRevealedCoords = import.meta.env.DEV + const storedTouchedPlanetIds = isDev ? [] - : await otherStore.getSavedRevealedCoords(); + : await persistentChunkStore.getSavedTouchedPlanetIds(); + const storedRevealedCoords = isDev ? [] : await persistentChunkStore.getSavedRevealedCoords(); this.terminal.printElement(); this.terminal.newline(); @@ -87,8 +92,10 @@ export class InitialGameStateDownloader { const pendingMovesLoadingBar = this.makeProgressListener('Pending Moves'); const planetsLoadingBar = this.makeProgressListener('Planets'); + const planetsMetadataLoadingBar = this.makeProgressListener('Planet Metadatas'); + const artifactsOnPlanetsLoadingBar = this.makeProgressListener('Artifacts On Planets'); + const artifactsInFlightLoadingBar = this.makeProgressListener('Artifacts On Moves'); const yourArtifactsLoadingBar = this.makeProgressListener('Your Artifacts'); - const yourSpaceshipsLoadingBar = this.makeProgressListener('Your Spaceships'); const contractConstants = contractsAPI.getConstants(); const worldRadius = contractsAPI.getWorldRadius(); @@ -98,9 +105,7 @@ export class InitialGameStateDownloader { const arrivals: Map = new Map(); const planetVoyageIdMap: Map = new Map(); - // Ensure that all chunks have been loaded from indexeddb - await persistentChunkStore.chunksLoaded(); - const minedChunks = Array.from(persistentChunkStore.allChunks()); + const minedChunks = Array.from(await persistentChunkStore.allChunks()); const minedPlanetIds = new Set( _.flatMap(minedChunks, (c) => c.planetLocations).map((l) => l.hash) ); @@ -139,7 +144,8 @@ export class InitialGameStateDownloader { const touchedAndLocatedPlanets = await contractsAPI.bulkGetPlanets( planetsToLoad, - planetsLoadingBar + planetsLoadingBar, + planetsMetadataLoadingBar ); touchedAndLocatedPlanets.forEach((_planet, locId) => { @@ -157,17 +163,33 @@ export class InitialGameStateDownloader { arrivals.set(arrival.eventId, arrival); } + const artifactIdsOnVoyages: ArtifactId[] = []; + for (const arrival of pendingMoves) { + if (arrival.artifactId) { + artifactIdsOnVoyages.push(arrival.artifactId); + } + } + + const artifactsOnVoyages = await contractsAPI.bulkGetArtifacts( + artifactIdsOnVoyages, + artifactsInFlightLoadingBar + ); + + const heldArtifacts = contractsAPI.bulkGetArtifactsOnPlanets( + planetsToLoad, + artifactsOnPlanetsLoadingBar + ); const myArtifacts = contractsAPI.getPlayerArtifacts( contractsAPI.getAddress(), yourArtifactsLoadingBar ); - const mySpaceships = contractsAPI.getPlayerSpaceships( - contractsAPI.getAddress(), - yourSpaceshipsLoadingBar - ); const twitters = await tryGetAllTwitters(); const paused = contractsAPI.getIsPaused(); + const gameover = contractsAPI.getGameover(); + const winners = contractsAPI.getWinners(); + const startTime = contractsAPI.getStartTime(); + const endTime = contractsAPI.getEndTime(); const initialState: InitialGameState = { contractConstants: await contractConstants, @@ -177,8 +199,9 @@ export class InitialGameStateDownloader { allRevealedCoords, pendingMoves, touchedAndLocatedPlanets, + artifactsOnVoyages, myArtifacts: await myArtifacts, - mySpaceships: await mySpaceships, + heldArtifacts: await heldArtifacts, loadedPlanets: planetsToLoad, revealedCoordsMap, claimedCoordsMap, @@ -186,6 +209,10 @@ export class InitialGameStateDownloader { arrivals, twitters, paused: await paused, + gameover: await gameover, + winners: await winners, + startTime: await startTime, + endTime: await endTime, }; return initialState; diff --git a/client/src/Backend/GameLogic/LayeredMap.ts b/client/src/Backend/GameLogic/LayeredMap.ts index 53c57edb..d318f056 100644 --- a/client/src/Backend/GameLogic/LayeredMap.ts +++ b/client/src/Backend/GameLogic/LayeredMap.ts @@ -1,5 +1,5 @@ -import { MAX_PLANET_LEVEL, MIN_PLANET_LEVEL } from '@dfdao/constants'; -import { LocationId, Radii, WorldCoords, WorldLocation } from '@dfdao/types'; +import { MAX_PLANET_LEVEL, MIN_PLANET_LEVEL } from '@darkforest_eth/constants'; +import { LocationId, Radii, WorldCoords, WorldLocation } from '@darkforest_eth/types'; import { Box, Circle, Point, QuadTree } from 'js-quadtree'; /** diff --git a/client/src/Backend/GameLogic/PluginManager.tsx b/client/src/Backend/GameLogic/PluginManager.tsx index 5f1e74b5..95217d54 100644 --- a/client/src/Backend/GameLogic/PluginManager.tsx +++ b/client/src/Backend/GameLogic/PluginManager.tsx @@ -1,5 +1,5 @@ -import { Monomitter, monomitter } from '@dfdao/events'; -import { PluginId } from '@dfdao/types'; +import { Monomitter, monomitter } from '@darkforest_eth/events'; +import { PluginId } from '@darkforest_eth/types'; import { EmbeddedPlugin, getEmbeddedPlugins } from '../Plugins/EmbeddedPluginLoader'; import { PluginProcess } from '../Plugins/PluginProcess'; import { SerializedPlugin } from '../Plugins/SerializedPlugin'; @@ -202,7 +202,10 @@ export class PluginManager { }); const moduleUrl = URL.createObjectURL(moduleFile); try { - const { default: Plugin } = await import(/* @vite-ignore */ moduleUrl); + // The `webpackIgnore` "magic comment" is almost undocumented, but it makes + // webpack skip over this dynamic `import` call so it won't be transformed into + // a weird _webpack_require_dynamic_ call + const { default: Plugin } = await import(/* webpackIgnore: true */ moduleUrl); if (this.pluginProcesses[id] === undefined) { // instantiate the plugin and attach it to the process list this.pluginProcesses[id] = new Plugin(); diff --git a/client/src/Backend/GameLogic/TutorialManager.ts b/client/src/Backend/GameLogic/TutorialManager.ts index ce88dbb2..20685538 100644 --- a/client/src/Backend/GameLogic/TutorialManager.ts +++ b/client/src/Backend/GameLogic/TutorialManager.ts @@ -1,36 +1,36 @@ -import { Setting } from '@dfdao/types'; +import { Setting } from '@darkforest_eth/types'; import { EventEmitter } from 'events'; import NotificationManager from '../../Frontend/Game/NotificationManager'; import { setBooleanSetting } from '../../Frontend/Utils/SettingsHooks'; import GameUIManager from './GameUIManager'; - +import { tutorialAsteroidLocation, tutorialFoundryLocation } from '../../Frontend/Utils/constants'; export const enum TutorialManagerEvent { StateChanged = 'StateChanged', } export const enum TutorialState { None, - - HomePlanet, + Welcome, + SpawnPlanet, + ZoomOut, SendFleet, + PlanetTypes, + Upgrade, + UpgradeComplete, SpaceJunk, Spaceship, - Deselect, - ZoomOut, + MoveSpaceship, + Foundry, + Artifact, MinerMove, - MinerPause, - Terminal, HowToGetScore, - ScoringDetails, - Valhalla, - AlmostCompleted, Completed, } class TutorialManager extends EventEmitter { static instance: TutorialManager; - private tutorialState: TutorialState = TutorialState.None; + private tutorialState: TutorialState = TutorialState.Welcome; private uiManager: GameUIManager; @@ -54,18 +54,40 @@ class TutorialManager extends EventEmitter { if (newState === TutorialState.Completed) { const notifManager = NotificationManager.getInstance(); notifManager.welcomePlayer(); + } else if (newState === TutorialState.HowToGetScore) { + const targetLocation = this.uiManager.getPlayerTargetPlanets(); + if (targetLocation.length > 0) { + this.uiManager.centerLocationId(targetLocation[0].locationId); + } + } else if (newState === TutorialState.SendFleet) { + const asteroid = this.uiManager.getPlanetWithCoords(tutorialAsteroidLocation); + asteroid && this.uiManager.centerLocationId(asteroid.locationId); + } else if (newState === TutorialState.MoveSpaceship) { + const foundry = this.uiManager.getPlanetWithCoords(tutorialFoundryLocation); + foundry && this.uiManager.centerLocationId(foundry.locationId); + } else if (newState === TutorialState.ZoomOut) { + const homeLocation = this.uiManager.getHomeHash(); + if (homeLocation) this.uiManager.centerLocationId(homeLocation); } } private advance() { let newState = Math.min(this.tutorialState + 1, TutorialState.Completed); - if (this.shouldSkipState(newState)) newState++; + while (this.shouldSkipState(newState)) newState++; this.setTutorialState(newState); } private shouldSkipState(state: TutorialState) { - return !this.uiManager.getSpaceJunkEnabled() && state === TutorialState.SpaceJunk; + if (!this.uiManager.getSpaceJunkEnabled() && state === TutorialState.SpaceJunk) return true; + if (this.uiManager.getMySpaceships().length == 0 && state === TutorialState.Spaceship) + return true; + if ( + this.uiManager.getPlayerTargetPlanets().length == 0 && + state === TutorialState.HowToGetScore + ) + return true; + return false; } reset() { @@ -73,7 +95,7 @@ class TutorialManager extends EventEmitter { contractAddress: this.uiManager.getContractAddress(), account: this.uiManager.getAccount(), }; - setBooleanSetting(config, Setting.TutorialOpen, true); + setBooleanSetting(config, Setting.ShowTutorial, true); this.setTutorialState(TutorialState.None); } diff --git a/client/src/Backend/GameLogic/ViewportEntities.ts b/client/src/Backend/GameLogic/ViewportEntities.ts index d6944099..1b6281b5 100644 --- a/client/src/Backend/GameLogic/ViewportEntities.ts +++ b/client/src/Backend/GameLogic/ViewportEntities.ts @@ -1,5 +1,5 @@ -import { MAX_PLANET_LEVEL, MIN_PLANET_LEVEL } from '@dfdao/constants'; -import { isLocatable } from '@dfdao/gamelogic'; +import { MAX_PLANET_LEVEL, MIN_PLANET_LEVEL } from '@darkforest_eth/constants'; +import { isLocatable } from '@darkforest_eth/gamelogic'; import { Chunk, LocatablePlanet, @@ -8,7 +8,7 @@ import { PlanetRenderInfo, Radii, WorldCoords, -} from '@dfdao/types'; +} from '@darkforest_eth/types'; import Viewport from '../../Frontend/Game/Viewport'; import { planetLevelToAnimationSpeed, sinusoidalAnimation } from '../Utils/Animation'; import GameManager from './GameManager'; @@ -120,13 +120,15 @@ export class ViewportEntities { private replacePlanets(newPlanetsInViewport: LocatablePlanet[]) { const radii = this.getPlanetRadii(Viewport.getInstance()); const planetsToRemove = new Set(Array.from(this.cachedPlanets.keys())); - + const player = this.uiManager.getAccount(); + if(!player) return; newPlanetsInViewport.forEach((planet: LocatablePlanet) => { planetsToRemove.delete(planet.locationId); const newPlanetInfo: PlanetRenderInfo = { planet: planet, radii: radii.get(planet.planetLevel) as Radii, + blocked: this.gameManager.playerMoveBlocked(player, planet.locationId) }; if (!planet.emojiBobAnimation) { diff --git a/client/src/Backend/Miner/ChunkUtils.ts b/client/src/Backend/Miner/ChunkUtils.ts index 982b27cd..174b31fd 100644 --- a/client/src/Backend/Miner/ChunkUtils.ts +++ b/client/src/Backend/Miner/ChunkUtils.ts @@ -1,20 +1,5 @@ -import type { Abstract } from '@dfdao/types'; -import { Chunk, Rectangle, WorldCoords, WorldLocation } from '@dfdao/types'; -import { Map } from 'yjs'; - -/** - * one of "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ" - */ -type BucketId = Abstract; -type ChunkId = Abstract; - -/** - * Abstract interface shared between different types of chunk stores. Currently we have one that - * writes to IndexedDB, and one that simply throws away the data. - */ -export interface ChunkStore { - hasMinedChunk: (chunkFootprint: Rectangle) => boolean; -} +import { Chunk, Rectangle, WorldCoords, WorldLocation } from '@darkforest_eth/types'; +import { BucketId, ChunkId, PersistedChunk } from '../../_types/darkforest/api/ChunkStoreTypes'; /** * Deterministically assigns a bucket ID to a rectangle, based on its position and size in the @@ -42,6 +27,48 @@ export function getChunkKey(chunkLoc: Rectangle): ChunkId { `${chunkLoc.bottomLeft.y}`) as ChunkId; } +/** + * Converts from the in-game representation of a chunk to its persisted representation. + */ +export function toPersistedChunk(chunk: Chunk): PersistedChunk { + const planetLocations = chunk.planetLocations.map((location) => ({ + x: location.coords.x, + y: location.coords.y, + h: location.hash, + p: location.perlin, + b: location.biomebase, + })); + + return { + x: chunk.chunkFootprint.bottomLeft.x, + y: chunk.chunkFootprint.bottomLeft.y, + s: chunk.chunkFootprint.sideLength, + l: planetLocations, + p: chunk.perlin, + }; +} + +/** + * Converts from the persisted representation of a chunk to the in-game representation of a chunk. + */ +export const toExploredChunk = (chunk: PersistedChunk): Chunk => { + const planetLocations = chunk.l.map((location) => ({ + coords: { x: location.x, y: location.y }, + hash: location.h, + perlin: location.p, + biomebase: location.b, + })); + + return { + chunkFootprint: { + bottomLeft: { x: chunk.x, y: chunk.y }, + sideLength: chunk.s, + }, + planetLocations, + perlin: chunk.p, + }; +}; + /** * An aligned chunk is one whose corner's coordinates are multiples of its side length, and its side * length is a power of two between {@link MIN_CHUNK_SIZE} and {@link MAX_CHUNK_SIZE} inclusive. @@ -58,7 +85,7 @@ export function getChunkKey(chunkLoc: Rectangle): ChunkId { * that the four chunks, if merged, would result in an "aligned" chunk whose side length is double * the given chunk. */ -function getSiblingLocations(chunkLoc: Rectangle): [Rectangle, Rectangle, Rectangle] { +export const getSiblingLocations = (chunkLoc: Rectangle): [Rectangle, Rectangle, Rectangle] => { const doubleSideLen = 2 * chunkLoc.sideLength; const newBottomLeftX = Math.floor(chunkLoc.bottomLeft.x / doubleSideLen) * doubleSideLen; const newBottomLeftY = Math.floor(chunkLoc.bottomLeft.y / doubleSideLen) * doubleSideLen; @@ -82,7 +109,7 @@ function getSiblingLocations(chunkLoc: Rectangle): [Rectangle, Rectangle, Rectan } } return [siblingLocs[0], siblingLocs[1], siblingLocs[2]]; -} +}; /** * Returns the unique aligned chunk (for definition of "aligned" see comment on @@ -107,7 +134,7 @@ export function getChunkOfSideLengthContainingPoint( * At a high level, call this function to update an efficient quadtree-like store containing all of * the chunks that a player has either mined or imported in their client. * - * More specifically, adds the given new chunk to the given map of chunks. If the map of chunks + * More speecifically, adds the given new chunk to the given map of chunks. If the map of chunks * contains all of the "sibling" chunks to this new chunk, then instead of adding it, we merge the 4 * sibling chunks, and add the merged chunk to the map and remove the existing sibling chunks. This * function is recursive, which means that if the newly created merged chunk can also be merged with @@ -122,44 +149,21 @@ export function getChunkOfSideLengthContainingPoint( * `existingChunks` map. `onAdd` will be called exactly once, whereas `onRemove` only ever be called * for sibling chunks that existed prior to this function being called. */ -export function processChunkInMap( - existingChunks: Map, - chunk: Chunk, - onAdd: (arg: Chunk) => void, - onRemove: (arg: Chunk) => void, +export function addToChunkMap( + existingChunks: Map, + newChunk: Chunk, + onAdd?: (arg: Chunk) => void, + onRemove?: (arg: Chunk) => void, maxChunkSize?: number ) { - for ( - let clearingSideLen = 16; - clearingSideLen < chunk.chunkFootprint.sideLength; - clearingSideLen *= 2 - ) { - for (let x = 0; x < chunk.chunkFootprint.sideLength; x += clearingSideLen) { - for (let y = 0; y < chunk.chunkFootprint.sideLength; y += clearingSideLen) { - const queryChunk: Rectangle = { - bottomLeft: { - x: chunk.chunkFootprint.bottomLeft.x + x, - y: chunk.chunkFootprint.bottomLeft.y + y, - }, - sideLength: clearingSideLen, - }; - const queryChunkKey = getChunkKey(queryChunk); - const exploredChunk = existingChunks.get(queryChunkKey); - if (exploredChunk) { - onRemove(exploredChunk); - } - } - } - } - - let sideLength = chunk.chunkFootprint.sideLength; + let sideLength = newChunk.chunkFootprint.sideLength; let chunkToAdd: Chunk = { chunkFootprint: { - bottomLeft: chunk.chunkFootprint.bottomLeft, + bottomLeft: newChunk.chunkFootprint.bottomLeft, sideLength, }, - planetLocations: [...chunk.planetLocations], - perlin: chunk.perlin, + planetLocations: [...newChunk.planetLocations], + perlin: newChunk.perlin, }; while (!maxChunkSize || sideLength < maxChunkSize) { const siblingLocs = getSiblingLocations(chunkToAdd.chunkFootprint); @@ -177,8 +181,12 @@ export function processChunkInMap( for (const siblingLoc of siblingLocs) { const siblingKey = getChunkKey(siblingLoc); const sibling = existingChunks.get(siblingKey); - if (sibling) { + if (onRemove !== undefined && sibling) { onRemove(sibling); + } else { + existingChunks.delete(siblingKey); + } + if (sibling) { planetLocations = planetLocations.concat(sibling.planetLocations); newPerlin += sibling.perlin / 4; } @@ -193,5 +201,9 @@ export function processChunkInMap( perlin: Math.floor(newPerlin * 1000) / 1000, }; } - onAdd(chunkToAdd); + if (onAdd !== undefined) { + onAdd(chunkToAdd); + } else { + existingChunks.set(getChunkKey(chunkToAdd.chunkFootprint), chunkToAdd); + } } diff --git a/client/src/Backend/Miner/MinerManager.ts b/client/src/Backend/Miner/MinerManager.ts index 533e6c9d..f49698fb 100644 --- a/client/src/Backend/Miner/MinerManager.ts +++ b/client/src/Backend/Miner/MinerManager.ts @@ -1,10 +1,10 @@ -import { perlin } from '@dfdao/hashing'; -import { Chunk, PerlinConfig, Rectangle } from '@dfdao/types'; +import { perlin } from '@darkforest_eth/hashing'; +import { Chunk, PerlinConfig, Rectangle } from '@darkforest_eth/types'; import { EventEmitter } from 'events'; import _ from 'lodash'; +import { ChunkStore } from '../../_types/darkforest/api/ChunkStoreTypes'; import { HashConfig, MinerWorkerMessage } from '../../_types/global/GlobalTypes'; -import { ChunkStore, getChunkKey } from './ChunkUtils'; -import DefaultWorker from './miner.worker.ts?worker'; +import { getChunkKey } from './ChunkUtils'; import { MiningPattern } from './MiningPatterns'; export const enum MinerManagerEvent { @@ -14,7 +14,7 @@ export const enum MinerManagerEvent { export type workerFactory = () => Worker; function defaultWorker() { - return new DefaultWorker(); + return new Worker(new URL('./miner.worker.ts', import.meta.url)); } export class HomePlanetMinerChunkStore implements ChunkStore { @@ -56,6 +56,7 @@ export class HomePlanetMinerChunkStore implements ChunkStore { class MinerManager extends EventEmitter { private readonly minedChunksStore: ChunkStore; private readonly planetRarity: number; + private readonly planetLevelThresholds: number[]; private isExploring = false; private miningPattern: MiningPattern; @@ -78,6 +79,7 @@ class MinerManager extends EventEmitter { miningPattern: MiningPattern, worldRadius: number, planetRarity: number, + planetLevelThresholds: number[], hashConfig: HashConfig, useMockHash: boolean, workerFactory: workerFactory @@ -87,6 +89,7 @@ class MinerManager extends EventEmitter { this.miningPattern = miningPattern; this.worldRadius = worldRadius; this.planetRarity = planetRarity; + this.planetLevelThresholds = planetLevelThresholds; this.workers = []; this.hashConfig = hashConfig; this.perlinOptions = { @@ -122,6 +125,7 @@ class MinerManager extends EventEmitter { miningPattern: MiningPattern, worldRadius: number, planetRarity: number, + planetLevelThresholds: number[], hashConfig: HashConfig, useMockHash = false, workerFactory: workerFactory = defaultWorker @@ -131,6 +135,7 @@ class MinerManager extends EventEmitter { miningPattern, worldRadius, planetRarity, + planetLevelThresholds, hashConfig, useMockHash, workerFactory diff --git a/client/src/Backend/Miner/MiningPatterns.ts b/client/src/Backend/Miner/MiningPatterns.ts index 2d2ef8d0..47cc43eb 100644 --- a/client/src/Backend/Miner/MiningPatterns.ts +++ b/client/src/Backend/Miner/MiningPatterns.ts @@ -1,4 +1,4 @@ -import { Rectangle, WorldCoords } from '@dfdao/types'; +import { Rectangle, WorldCoords } from '@darkforest_eth/types'; export const enum MiningPatternType { Home, diff --git a/client/src/Backend/Miner/PlanetUtils.ts b/client/src/Backend/Miner/PlanetUtils.ts new file mode 100644 index 00000000..fcd6fc37 --- /dev/null +++ b/client/src/Backend/Miner/PlanetUtils.ts @@ -0,0 +1,10 @@ +import { getBytesFromHex } from "@darkforest_eth/hexgen"; +import { LocationId } from "@darkforest_eth/types"; +import * as bigInt from 'big-integer'; + +export function planetLevelBelowLevel0Threshold(hex: LocationId, thresholds: number[]): boolean { + const levelBigInt = getBytesFromHex(hex, 4, 7); + + // Threshold [0] is the largest number. + return levelBigInt < bigInt(thresholds[0]); +} diff --git a/client/src/Backend/Miner/miner.worker.ts b/client/src/Backend/Miner/miner.worker.ts index 89c349b1..148331e1 100644 --- a/client/src/Backend/Miner/miner.worker.ts +++ b/client/src/Backend/Miner/miner.worker.ts @@ -1,11 +1,12 @@ -import { mimcHash, perlin } from '@dfdao/hashing'; -import { locationIdFromBigInt } from '@dfdao/serde'; -import { Chunk, PerlinConfig, Rectangle, WorldLocation } from '@dfdao/types'; +import { mimcHash, perlin } from '@darkforest_eth/hashing'; +import { locationIdFromBigInt } from '@darkforest_eth/serde'; +import { Chunk, PerlinConfig, Rectangle, WorldLocation } from '@darkforest_eth/types'; import * as bigInt from 'big-integer'; import { BigInteger } from 'big-integer'; import { LOCATION_ID_UB } from '../../Frontend/Utils/constants'; import { MinerWorkerMessage } from '../../_types/global/GlobalTypes'; import { getPlanetLocations } from './permutation'; +import { planetLevelBelowLevel0Threshold } from './PlanetUtils'; /* eslint-disable @typescript-eslint/no-explicit-any */ const ctx: Worker = self as any; @@ -16,6 +17,7 @@ const exploreChunk = ( workerIndex: number, totalWorkers: number, planetRarity: number, + planetLevelThresholds: number[], jobId: number, useFakeHash: boolean, planetHashKey: number, @@ -52,7 +54,7 @@ const exploreChunk = ( perlinLengthScale, perlinMirrorY, perlinMirrorY - )(chunkFootprint, planetRarity); + )(chunkFootprint, planetRarity, planetLevelThresholds); } else { const planetRarityBI: BigInteger = bigInt(planetRarity); let count = 0; @@ -63,6 +65,10 @@ const exploreChunk = ( if (count % totalWorkers === workerIndex) { const hash: BigInteger = planetHashFn(x, y); if (hash.lesser(LOCATION_ID_UB.divide(planetRarityBI))) { + // if planet bytes 4-6 are too high for planet threshold, don't render on client. + if (!planetLevelBelowLevel0Threshold(locationIdFromBigInt(hash), planetLevelThresholds)) + continue; + planetLocations.push({ coords: { x, y }, hash: locationIdFromBigInt(hash), @@ -95,6 +101,7 @@ ctx.addEventListener('message', (e: MessageEvent) => { exploreMessage.workerIndex, exploreMessage.totalWorkers, exploreMessage.planetRarity, + exploreMessage.planetLevelThresholds, exploreMessage.jobId, exploreMessage.useMockHash, exploreMessage.planetHashKey, diff --git a/client/src/Backend/Miner/permutation.ts b/client/src/Backend/Miner/permutation.ts index bbb2d342..f4d58ce3 100644 --- a/client/src/Backend/Miner/permutation.ts +++ b/client/src/Backend/Miner/permutation.ts @@ -1,6 +1,7 @@ -import { fakeHash, perlin, seededRandom } from '@dfdao/hashing'; -import { locationIdFromBigInt } from '@dfdao/serde'; -import { Rectangle, WorldCoords, WorldLocation } from '@dfdao/types'; +import { fakeHash, perlin, seededRandom } from '@darkforest_eth/hashing'; +import { locationIdFromBigInt } from '@darkforest_eth/serde'; +import { Rectangle, WorldCoords, WorldLocation } from '@darkforest_eth/types'; +import { planetLevelBelowLevel0Threshold } from './PlanetUtils'; type IdxWithRand = { idx: number; @@ -66,9 +67,9 @@ export const getPlanetLocations = biomebaseKey: number, perlinLengthScale: number, perlinMirrorX: boolean, - perlinMirrorY: boolean + perlinMirrorY: boolean, ) => - (chunkFootprint: Rectangle, planetRarity: number) => { + (chunkFootprint: Rectangle, planetRarity: number, planetLevelThresholds: number[]) => { // assume that the chunkFootprint is entirely contained within a 256x256 grid square const { bottomLeft, sideLength } = chunkFootprint; const { x, y } = bottomLeft; @@ -113,7 +114,10 @@ export const getPlanetLocations = mirrorY: perlinMirrorY, floor: true, }), - })); + })) + .filter( + (planetData) => planetLevelBelowLevel0Threshold(planetData.hash, planetLevelThresholds) + ); return locs; }; diff --git a/client/src/Backend/Network/AccountManager.ts b/client/src/Backend/Network/AccountManager.ts index 2c9046d5..51b3e558 100644 --- a/client/src/Backend/Network/AccountManager.ts +++ b/client/src/Backend/Network/AccountManager.ts @@ -1,5 +1,5 @@ -import { address } from '@dfdao/serde'; -import { EthAddress } from '@dfdao/types'; +import { address } from '@darkforest_eth/serde'; +import { EthAddress } from '@darkforest_eth/types'; import { utils } from 'ethers'; import stringify from 'json-stable-stringify'; @@ -11,12 +11,14 @@ export interface Account { privateKey: string; } +const ACTIVE_TIME = 1000 * 60 * 60 * 24 * 7; /** * This is the key in local storage in which we keep an array of all the public addresses of the * accounts that have been imported/generated into this client. */ const ADDRESS_LOCAL_STORAGE_KEY = 'KNOWN_ADDRESSES'; - +const ACTIVE_LOCAL_STORAGE_KEY = 'ACTIVE_ADDRESS'; +const ACTIVE_SET_TIME_STORAGE_KEY = 'ACTIVE_SET'; /** * In-memory representation of all the accounts in this client. */ @@ -36,6 +38,43 @@ function save() { } } +export function setActive(account: Account) { + localStorage.setItem(ACTIVE_LOCAL_STORAGE_KEY, account.address); + localStorage.setItem(`skey-${account.address}`, account.privateKey); + + localStorage.setItem(ACTIVE_SET_TIME_STORAGE_KEY, Date.now().toString()); +} + +/** + * Store all of the accounts in local storage. + */ + +export function resetActive(): void { + localStorage.removeItem(ACTIVE_LOCAL_STORAGE_KEY); + + localStorage.removeItem(ACTIVE_SET_TIME_STORAGE_KEY); +} + +function loadActive(): Account | undefined { + const timeSetStr = localStorage.getItem(ACTIVE_SET_TIME_STORAGE_KEY); + const timeSet = Number(timeSetStr); + const activeAccount = localStorage.getItem(ACTIVE_LOCAL_STORAGE_KEY); + + if ( + timeSetStr == null || + timeSet == NaN || + activeAccount == null || + timeSetStr == '' || + activeAccount == '' || + Date.now() - ACTIVE_TIME > timeSet + ) { + resetActive(); + return undefined; + } + + return accounts.find((account) => account.address == address(activeAccount)); +} + /** * Load all of the accounts from local storage. */ @@ -45,7 +84,7 @@ function load(): Account[] { // first we load the public addresses const serializedAddresses = localStorage.getItem(ADDRESS_LOCAL_STORAGE_KEY); - if (serializedAddresses !== null) { + if (serializedAddresses && serializedAddresses.length > 0) { const addresses = JSON.parse(serializedAddresses) as string[]; for (const addressStr of addresses) { knownAddresses.push(address(addressStr)); @@ -74,6 +113,10 @@ export function getAccounts(): Account[] { return [...accounts]; } +export function getActive(): Account | undefined { + return loadActive(); +} + /** * Adds the given account, and saves it to localstorage. */ @@ -85,3 +128,8 @@ export function addAccount(privateKey: string) { save(); } + +export function logOut() { + resetActive(); + window.location.reload(); +} \ No newline at end of file diff --git a/client/src/Backend/Network/Blockchain.ts b/client/src/Backend/Network/Blockchain.ts index 16facdc0..1b1dd262 100644 --- a/client/src/Backend/Network/Blockchain.ts +++ b/client/src/Backend/Network/Blockchain.ts @@ -1,5 +1,9 @@ -import diamondContractAbiUrl from '@dfdao/contracts/abis/DarkForest.json?url'; -import { createContract, createEthConnection, EthConnection } from '@dfdao/network'; +// These are loaded as URL paths by a webpack loader +import { NETWORK } from '@darkforest_eth/contracts'; +import diamondContractAbiUrl from '@darkforest_eth/contracts/abis/DarkForest.json'; +import faucetContractAbiUrl from '@darkforest_eth/contracts/abis/DFArenaFaucet.json'; +import initContractAbiUrl from '@darkforest_eth/contracts/abis/DFArenaInitialize.json'; +import { createContract, createEthConnection, EthConnection } from '@darkforest_eth/network'; import type { Contract, providers, Wallet } from 'ethers'; /** @@ -15,12 +19,38 @@ export async function loadDiamondContract( return createContract(address, abi, provider, signer); } +/** + * Loads the faucet contract, which is responsible for dripping funds to players + */ +export async function loadFaucetContract( + address: string, + provider: providers.JsonRpcProvider, + signer?: Wallet +): Promise { + const abi = await fetch(faucetContractAbiUrl).then((r) => r.json()); + + return createContract(address, abi, provider, signer); +} + +/** + * Loads the init contract, which is responsible for initializing lobbies + */ +export async function loadInitContract( + address: string, + provider: providers.JsonRpcProvider, + signer?: Wallet +): Promise { + const abi = await fetch(initContractAbiUrl).then((r) => r.json()); + + return createContract(address, abi, provider, signer); +} + export function getEthConnection(): Promise { - const defaultUrl = import.meta.env.DF_DEFAULT_RPC as string; + const isProdNetwork = NETWORK.toString() !== 'localhost' && NETWORK.toString() !== 'hardhat'; + const defaultUrl = process.env.DEFAULT_RPC as string; let url: string; - - if (import.meta.env.PROD) { + if (isProdNetwork) { url = localStorage.getItem('XDAI_RPC_ENDPOINT_v5') || defaultUrl; } else { url = 'http://localhost:8545'; @@ -28,8 +58,12 @@ export function getEthConnection(): Promise { console.log(`GAME METADATA:`); console.log(`rpc url: ${url}`); - console.log(`is production: ${import.meta.env.PROD}`); - console.log(`webserver url: ${import.meta.env.DF_WEBSERVER_URL}`); + console.log(`is production network: ${isProdNetwork}`); + console.log(`client build: ${process.env.NODE_ENV}`); + console.log(`webserver url: ${process.env.DF_WEBSERVER_URL}`); + console.log(`faucet url: ${process.env.FAUCET_URL}`); + console.log(`dfdao url: ${process.env.DFDAO_WEBSERVER_URL} `); + console.log(`graph url: ${process.env.GRAPH_URL}`); return createEthConnection(url); } diff --git a/client/src/Backend/Network/EventLogger.ts b/client/src/Backend/Network/EventLogger.ts index b350570f..f2f60347 100644 --- a/client/src/Backend/Network/EventLogger.ts +++ b/client/src/Backend/Network/EventLogger.ts @@ -4,16 +4,16 @@ export const enum EventType { } export class EventLogger { - private static augmentEvent(event: Record, eventType: EventType) { + private static augmentEvent(event: unknown, eventType: EventType) { return Object.assign(event, { df_event_type: eventType }); } - logEvent(eventType: EventType, event: Record) { - if (!import.meta.env.DF_WEBSERVER_URL) { + logEvent(eventType: EventType, event: unknown) { + if (!process.env.DF_WEBSERVER_URL) { return; } - fetch(`${import.meta.env.DF_WEBSERVER_URL}/event`, { + fetch(`${process.env.DF_WEBSERVER_URL}/event`, { method: 'POST', body: JSON.stringify(EventLogger.augmentEvent(event, eventType)), headers: { diff --git a/client/src/Backend/Network/GraphApi.ts b/client/src/Backend/Network/GraphApi.ts new file mode 100644 index 00000000..6fee3ec4 --- /dev/null +++ b/client/src/Backend/Network/GraphApi.ts @@ -0,0 +1,13 @@ +export const getGraphQLData = async (query: string, graphApiUrl: string) => { + const response = await fetch(graphApiUrl, { + method: 'POST', + body: JSON.stringify({ query, operationName: null, variables: null }), + headers: { + 'Content-Type': 'application/json', + Accept: 'application/json', + }, + }); + + const json = await response.json(); + return json; +}; diff --git a/client/src/Backend/Network/GraphApi/AccountApi.ts b/client/src/Backend/Network/GraphApi/AccountApi.ts new file mode 100644 index 00000000..b7cf8d5e --- /dev/null +++ b/client/src/Backend/Network/GraphApi/AccountApi.ts @@ -0,0 +1,24 @@ +import { EthAddress, RawAccount } from '@darkforest_eth/types'; +import { CONFIG_CONSTANTS } from '../../../Frontend/Utils/constants'; +import { getGraphQLData } from '../GraphApi'; + +export async function loadAccountData(address: EthAddress): Promise { + const query = ` +query { + player(id:"${address}") { + wins + matches + arenaPlayers { + arena{ + lobbyAddress, + configHash, + gameOver, + startTime, + ${CONFIG_CONSTANTS} + } + } + } +} +`; + return (await getGraphQLData(query, process.env.GRAPH_URL || 'localhost:8000')).data.player; +} diff --git a/client/src/Backend/Network/GraphApi/BadgeApi.ts b/client/src/Backend/Network/GraphApi/BadgeApi.ts new file mode 100644 index 00000000..a93e1c4f --- /dev/null +++ b/client/src/Backend/Network/GraphApi/BadgeApi.ts @@ -0,0 +1,31 @@ +import { + BadgeSet, + BadgeType, + ConfigBadge, +} from '@darkforest_eth/types'; + +// Given a season, get all badges won by all Players +export function graphBadgeToGrandPrixBadge( + graphBadge: BadgeSet | undefined, + configHash: string +): ConfigBadge[] { + if(!graphBadge) return []; + const badges: BadgeType[] = []; + + if (graphBadge.startYourEngine) badges.push(BadgeType.StartYourEngine); + if (graphBadge.nice) badges.push(BadgeType.Nice); + if (graphBadge.ouch) badges.push(BadgeType.Sleepy); + if (graphBadge.based) badges.push(BadgeType.Tree); + if (graphBadge.wallBreaker) badges.push(BadgeType.Wallbreaker); + + return badges.map((badge) => { + return { + type: badge, + configHash, + }; + }); +} + +export function getBadges(configHash: string, configBadges: BadgeSet[]): ConfigBadge[] { + return configBadges.map((configBadge) => graphBadgeToGrandPrixBadge(configBadge,configHash)).flat(); +} diff --git a/client/src/Backend/Network/GraphApi/ConfigApi.ts b/client/src/Backend/Network/GraphApi/ConfigApi.ts new file mode 100644 index 00000000..3d4e0377 --- /dev/null +++ b/client/src/Backend/Network/GraphApi/ConfigApi.ts @@ -0,0 +1,192 @@ +import { EthAddress, GraphArena, GraphPlanet, WorldCoords } from '@darkforest_eth/types'; +import { BigNumber } from 'ethers'; +import _ from 'lodash'; +import { LobbyPlanet } from '../../../Frontend/Panes/Lobby/LobbiesUtils'; +import { LobbyInitializers } from '../../../Frontend/Panes/Lobby/Reducer'; +import { CONFIG_CONSTANTS } from '../../../Frontend/Utils/constants'; +import { getGraphQLData } from '../GraphApi'; + +function toNum(num: BigNumber): number { + return BigNumber.from(num).toNumber(); +} + +export async function loadConfigFromHash(config: string): Promise< + | { + config: LobbyInitializers; + address: string; + } + | undefined +> { + const query = ` +query { + arenas(first:5, where: {configHash: "${config}"}) { + lobbyAddress, + configHash, + gameOver, + startTime, + ${CONFIG_CONSTANTS} + } +} +`; + const rawData = await getGraphQLData(query, process.env.GRAPH_URL || 'localhost:8000'); + // @ts-expect-error + const hasPlanets = rawData.data.arenas.filter((a) => a.planets.length > 0); + if(hasPlanets.length == 0) return undefined; + const res = convertGraphConfig(hasPlanets[0]); + if (res) return res; +} + +export async function loadConfigFromAddress(address: EthAddress): Promise<{ + config: LobbyInitializers; + address: string; +}> { + const query = ` + query { + arena(id: "${address}") { + lobbyAddress, + configHash, + gameOver, + startTime, + ${CONFIG_CONSTANTS} + } + } +`; + try { + const rawData: GraphArena = ( + await getGraphQLData(query, process.env.GRAPH_URL || 'localhost:8000') + ).data.arena; + if (!rawData) throw new Error('arena has no data'); + const configData = convertGraphConfig(rawData); + return configData; + } catch (e) { + console.log(e); + throw new Error('could not fetch config data from the graph'); + } +} + +const GraphPlanetType = ['PLANET', 'ASTEROID', 'FOUNDRY', 'SPACETIME_RIP', 'QUASAR']; + +export function convertGraphConfig(arena: GraphArena): { + config: LobbyInitializers; + address: string; +} { + if (!arena.config) throw new Error("Can't load arena config"); + const cf = arena.config; + // const thresholds: number[] = arena.config.PLANET_LEVEL_THRESHOLDS; + return { + config: { + ...arena.config, + ABANDON_RANGE_CHANGE_PERCENT: toNum(cf.ABANDON_RANGE_CHANGE_PERCENT), + ABANDON_SPEED_CHANGE_PERCENT: toNum(cf.ABANDON_SPEED_CHANGE_PERCENT), + ARTIFACT_POINT_VALUES: [ + toNum(cf.ARTIFACT_POINT_VALUES[0]), + toNum(cf.ARTIFACT_POINT_VALUES[1]), + toNum(cf.ARTIFACT_POINT_VALUES[2]), + toNum(cf.ARTIFACT_POINT_VALUES[3]), + toNum(cf.ARTIFACT_POINT_VALUES[4]), + toNum(cf.ARTIFACT_POINT_VALUES[5]), + ], + BIOME_THRESHOLD_1: toNum(cf.BIOME_THRESHOLD_1), + BIOME_THRESHOLD_2: toNum(cf.BIOME_THRESHOLD_2), + BIOMEBASE_KEY: toNum(cf.BIOMEBASE_KEY), + CAPTURE_ZONE_CHANGE_BLOCK_INTERVAL: toNum(cf.CAPTURE_ZONE_CHANGE_BLOCK_INTERVAL), + CAPTURE_ZONE_COUNT: toNum(cf.CAPTURE_ZONE_COUNT), + CAPTURE_ZONE_HOLD_BLOCKS_REQUIRED: toNum(cf.CAPTURE_ZONE_HOLD_BLOCKS_REQUIRED), + CAPTURE_ZONE_PLANET_LEVEL_SCORE: [ + toNum(cf.CAPTURE_ZONE_PLANET_LEVEL_SCORE[0]), + toNum(cf.CAPTURE_ZONE_PLANET_LEVEL_SCORE[1]), + toNum(cf.CAPTURE_ZONE_PLANET_LEVEL_SCORE[2]), + toNum(cf.CAPTURE_ZONE_PLANET_LEVEL_SCORE[3]), + toNum(cf.CAPTURE_ZONE_PLANET_LEVEL_SCORE[4]), + toNum(cf.CAPTURE_ZONE_PLANET_LEVEL_SCORE[5]), + toNum(cf.CAPTURE_ZONE_PLANET_LEVEL_SCORE[6]), + toNum(cf.CAPTURE_ZONE_PLANET_LEVEL_SCORE[7]), + toNum(cf.CAPTURE_ZONE_PLANET_LEVEL_SCORE[8]), + toNum(cf.CAPTURE_ZONE_PLANET_LEVEL_SCORE[9]), + ], + CAPTURE_ZONE_RADIUS: toNum(cf.CAPTURE_ZONE_RADIUS), + CAPTURE_ZONES_PER_5000_WORLD_RADIUS: toNum(cf.CAPTURE_ZONES_PER_5000_WORLD_RADIUS), + CLAIM_VICTORY_ENERGY_PERCENT: toNum(cf.CLAIM_VICTORY_ENERGY_PERCENT), + INIT_PERLIN_MAX: toNum(cf.INIT_PERLIN_MAX), + INIT_PERLIN_MIN: toNum(cf.INIT_PERLIN_MIN), + LOCATION_REVEAL_COOLDOWN: toNum(cf.LOCATION_REVEAL_COOLDOWN), + MAX_NATURAL_PLANET_LEVEL: toNum(cf.MAX_NATURAL_PLANET_LEVEL), + MODIFIERS: [ + toNum(cf.MODIFIERS[0]), + toNum(cf.MODIFIERS[1]), + toNum(cf.MODIFIERS[2]), + toNum(cf.MODIFIERS[3]), + toNum(cf.MODIFIERS[4]), + toNum(cf.MODIFIERS[5]), + toNum(cf.MODIFIERS[6]), + toNum(cf.MODIFIERS[7]), + ], + NUM_TEAMS: toNum(cf.NUM_TEAMS), + PERLIN_LENGTH_SCALE: toNum(cf.PERLIN_LENGTH_SCALE), + PERLIN_THRESHOLD_1: toNum(cf.PERLIN_THRESHOLD_1), + PERLIN_THRESHOLD_2: toNum(cf.PERLIN_THRESHOLD_2), + PERLIN_THRESHOLD_3: toNum(cf.PERLIN_THRESHOLD_3), + PHOTOID_ACTIVATION_DELAY: toNum(cf.PHOTOID_ACTIVATION_DELAY), + PLANET_LEVEL_JUNK: [ + toNum(cf.PLANET_LEVEL_JUNK[0]), + toNum(cf.PLANET_LEVEL_JUNK[1]), + toNum(cf.PLANET_LEVEL_JUNK[2]), + toNum(cf.PLANET_LEVEL_JUNK[3]), + toNum(cf.PLANET_LEVEL_JUNK[4]), + toNum(cf.PLANET_LEVEL_JUNK[5]), + toNum(cf.PLANET_LEVEL_JUNK[6]), + toNum(cf.PLANET_LEVEL_JUNK[7]), + toNum(cf.PLANET_LEVEL_JUNK[8]), + toNum(cf.PLANET_LEVEL_JUNK[9]), + ], + PLANET_LEVEL_THRESHOLDS: [ + toNum(cf.PLANET_LEVEL_THRESHOLDS[0]), + toNum(cf.PLANET_LEVEL_THRESHOLDS[1]), + toNum(cf.PLANET_LEVEL_THRESHOLDS[2]), + toNum(cf.PLANET_LEVEL_THRESHOLDS[3]), + toNum(cf.PLANET_LEVEL_THRESHOLDS[4]), + toNum(cf.PLANET_LEVEL_THRESHOLDS[5]), + toNum(cf.PLANET_LEVEL_THRESHOLDS[6]), + toNum(cf.PLANET_LEVEL_THRESHOLDS[7]), + toNum(cf.PLANET_LEVEL_THRESHOLDS[8]), + toNum(cf.PLANET_LEVEL_THRESHOLDS[9]), + ], + PLANET_RARITY: toNum(cf.PLANET_RARITY), + PLANETHASH_KEY: toNum(cf.PLANETHASH_KEY), + SILVER_SCORE_VALUE: toNum(cf.SILVER_SCORE_VALUE), + SPACE_JUNK_LIMIT: toNum(cf.SPACE_JUNK_LIMIT), + SPACETYPE_KEY: toNum(cf.SPACETYPE_KEY), + SPAWN_RIM_AREA: toNum(cf.SPAWN_RIM_AREA), + TARGETS_REQUIRED_FOR_VICTORY: toNum(cf.TARGETS_REQUIRED_FOR_VICTORY), + TIME_FACTOR_HUNDREDTHS: toNum(cf.TIME_FACTOR_HUNDREDTHS), + TOKEN_MINT_END_TIMESTAMP: toNum(cf.TOKEN_MINT_END_TIMESTAMP), + WORLD_RADIUS_MIN: toNum(cf.WORLD_RADIUS_MIN), + // CLAIM_PLANET_COOLDOWN: 0, + PLANET_TYPE_WEIGHTS: _.chunk(arena.config.PLANET_TYPE_WEIGHTS, 50).map((block) => + _.chunk(block, 5) + ) as any, + WHITELIST: [], + ADMIN_PLANETS: arena.planets.map((planet: GraphPlanet) => { + return { + ...planet, + planetType: GraphPlanetType.indexOf(planet.planetType), + x: Number(planet.x), + y: Number(planet.y), + perlin: toNum(planet.perlin), + level: toNum(planet.level), + location: planet.locationDec, + isTargetPlanet: planet.targetPlanet, + isSpawnPlanet: planet.spawnPlanet, + blockedPlanetLocs: planet.blockedPlanetIds.map((i) => { + return { + x: i.x, + y: i.y, + } as WorldCoords; + }), + } as LobbyPlanet; + }), + INIT_PLANETS: [], + }, + address: arena.lobbyAddress, + }; +} diff --git a/client/src/Backend/Network/GraphApi/EloLeaderboardApi.ts b/client/src/Backend/Network/GraphApi/EloLeaderboardApi.ts new file mode 100644 index 00000000..58b576cc --- /dev/null +++ b/client/src/Backend/Network/GraphApi/EloLeaderboardApi.ts @@ -0,0 +1,46 @@ +import { EthAddress, GraphConfigPlayer } from '@darkforest_eth/types'; +import { competitiveConfig } from '../../../Frontend/Utils/constants'; +import { getGraphQLData } from '../GraphApi'; + +export async function loadPlayerElo( + config: string, + address: EthAddress +): Promise { + const QUERY = ` + query { + configPlayer(id: "${address}"}) { + elo, + wins, + losses, + configHash + } +} +`; + const rawData = await getGraphQLData(QUERY, process.env.GRAPH_URL || 'localhost:8000'); + return rawData; +} + +export async function loadEloLeaderboard( + config: string = competitiveConfig, + isCompetitive: boolean = false +): Promise { + const QUERY = ` + query { + configPlayers(first:1000, where: {configHash: "${config}", gamesFinished_gte:1}) { + address, + elo, + wins, + losses + + } + } + `; + + const rawData = await getGraphQLData(QUERY, process.env.GRAPH_URL || 'localhost:8000'); + + if (rawData.error) { + throw new Error(rawData.error); + } + + return rawData.data.configPlayers; +} diff --git a/client/src/Backend/Network/GraphApi/GrandPrixApi.ts b/client/src/Backend/Network/GraphApi/GrandPrixApi.ts new file mode 100644 index 00000000..da34fcc6 --- /dev/null +++ b/client/src/Backend/Network/GraphApi/GrandPrixApi.ts @@ -0,0 +1,140 @@ +import { createContract, EthConnection } from '@darkforest_eth/network'; +import { address } from '@darkforest_eth/serde'; +import { + EthAddress, + GrandPrixMetadata, + GraphArena, + Leaderboard, + LeaderboardEntry, + RegistryResponse, +} from '@darkforest_eth/types'; +import { + roundEndTimestamp, + roundStartTimestamp, + competitiveConfig, + DUMMY, + SEASON_GRAND_PRIXS, +} from '../../../Frontend/Utils/constants'; +import { getGraphQLData } from '../GraphApi'; +import { getAllTwitters } from '../UtilityServerAPI'; +import RegistryAbi from "@dfdao/dynasty/abi/Registry.json"; +// Contract addresses +import deploymentUrl from "@dfdao/dynasty/deployment.json"; +import { Contract, ethers, providers, Wallet } from 'ethers'; +import { Registry } from '@dfdao/dynasty/types' + +/** + * Purpose: + * Fetch necessary data for Grand Prixs + */ + +export async function loadArenaLeaderboard( + config: string = competitiveConfig, + isCompetitive: boolean +): Promise { + const QUERY = ` +query { + arenas( + first:1000, + where: {configHash: "${config}", duration_not: null} + orderBy: duration + orderDirection: asc + ) + { + id + startTime + winners(first :1) { + address + moves + } + gameOver + endTime + duration + } +} +`; + const rawData = await getGraphQLData(QUERY, process.env.GRAPH_URL || 'localhost:8000'); + if (rawData.error) { + throw new Error(rawData.error); + } + const ret = await convertData(rawData.data.arenas, config == competitiveConfig); + return ret; +} + +async function convertData(arenas: GraphArena[], isCompetitive: boolean): Promise { + let entries: LeaderboardEntry[] = []; + const twitters = await getAllTwitters(); + + const roundStart = new Date(roundStartTimestamp).getTime() / 1000; + + const roundEnd = new Date(roundEndTimestamp).getTime() / 1000; + for (const arena of arenas) { + if ( + !arena.gameOver || + !arena.endTime || + !arena.duration || + // arena.startTime == 0 || + // arena.winners.length == 0 || + // !arena.winners[0].address || + (isCompetitive && (roundEnd <= arena.endTime || roundStart >= arena.startTime)) + ) + continue; + + const winnerAddress = address(arena.winners[0].address); + const entry = entries.find((p) => winnerAddress == p.ethAddress); + + if (!entry) { + entries.push({ + ethAddress: winnerAddress, + score: undefined, + twitter: twitters[winnerAddress], + moves: arena.winners[0].moves, + startTime: arena.startTime, + endTime: arena.endTime, + time: arena.duration, + gamesFinished: 0, + gamesStarted: 0 + }); + } else if (entry.time && entry.time > arena.duration) { + entry.time = arena.duration; + } + } + + return { entries, length: arenas.length }; +} + + +export async function loadRegistryContract( + address: string, + provider: providers.JsonRpcProvider, + signer?: Wallet +): Promise { + const abi = await fetch(RegistryAbi).then((r) => r.json()); + return createContract(address, abi.abi, provider, signer); +} + +export async function loadRegistry( + ethConnection: EthConnection, +): Promise { + if(DUMMY) { + return SEASON_GRAND_PRIXS; + } + + const deployment = await fetch(deploymentUrl).then((r) => r.json()); + + const registry = await ethConnection.loadContract(deployment.registry, loadRegistryContract); + const allGrandPrix = await registry.getAllGrandPrix(); + const metadata: GrandPrixMetadata[] = []; + allGrandPrix.map(gp => { + if(gp.parentAddress != ethers.constants.AddressZero) { + metadata.push({ + configHash: gp.configHash, + seasonId: gp.seasonId.toNumber(), + startTime: Math.floor(gp.startTime.toNumber() / 1000), + endTime: Math.floor(gp.endTime.toNumber() / 1000), + parentAddress: address(gp.parentAddress) + }) + } + }) + return metadata; +} diff --git a/client/src/Backend/Network/LeaderboardApi.ts b/client/src/Backend/Network/GraphApi/LeaderboardApi.ts similarity index 54% rename from client/src/Backend/Network/LeaderboardApi.ts rename to client/src/Backend/Network/GraphApi/LeaderboardApi.ts index 486e5bdc..a810018b 100644 --- a/client/src/Backend/Network/LeaderboardApi.ts +++ b/client/src/Backend/Network/GraphApi/LeaderboardApi.ts @@ -1,11 +1,11 @@ -import { Leaderboard } from '@dfdao/types'; +import { Leaderboard } from '@darkforest_eth/types'; export async function loadLeaderboard(): Promise { - if (!import.meta.env.DF_WEBSERVER_URL) { - return { entries: [] }; + if (!process.env.DF_WEBSERVER_URL) { + return { entries: [], length: 0}; } - const address = `${import.meta.env.DF_WEBSERVER_URL}/leaderboard`; + const address = `${process.env.DF_WEBSERVER_URL}/leaderboard`; const res = await fetch(address, { method: 'GET', }); diff --git a/client/src/Backend/Network/GraphApi/MapsApi.ts b/client/src/Backend/Network/GraphApi/MapsApi.ts new file mode 100644 index 00000000..df1003c3 --- /dev/null +++ b/client/src/Backend/Network/GraphApi/MapsApi.ts @@ -0,0 +1,27 @@ +import { EthAddress, MapInfo } from '@darkforest_eth/types'; +import { getGraphQLData } from '../GraphApi'; + +export async function loadRecentMaps( + nMaps?: number, + configHash?: string, + creator?: string +): Promise { + const where = configHash ? `configHash: "${configHash}"` : creator ? `creator: "${creator}"` : ''; + const query = ` + query { + arenas(${ + nMaps ? `first:${nMaps}` : `` + }, orderBy:creationTime, orderDirection:desc, where:{${where}} ) { + configHash + creator + lobbyAddress + startTime + planets { + id + } + } + } + `; + + return (await getGraphQLData(query, process.env.GRAPH_URL || 'localhost:8000')).data?.arenas; +} diff --git a/client/src/Backend/Network/GraphApi/SeasonLeaderboardApi.ts b/client/src/Backend/Network/GraphApi/SeasonLeaderboardApi.ts new file mode 100644 index 00000000..e1027534 --- /dev/null +++ b/client/src/Backend/Network/GraphApi/SeasonLeaderboardApi.ts @@ -0,0 +1,644 @@ +import { address } from '@darkforest_eth/serde'; +import { + BadgeSet, + BadgeType, + CleanConfigPlayer, + ConfigBadge, + ConfigPlayer, + EthAddress, + GrandPrixHistory, + GrandPrixMetadata, + GrandPrixPlayers, + Leaderboard, + LeaderboardEntry, + SeasonHistory, + SeasonPlayers, + SeasonScore, + Wallbreaker, + WallbreakerArena, +} from '@darkforest_eth/types'; +import { UniquePlayerBadges } from '@darkforest_eth/types/src/grand_prix'; +import { + // SEASON_GRAND_PRIXS, + HOUR_IN_SECONDS, + EGP, + DUMMY, + BADGE_BONUSES, + SECOND_CONFIG_HASH_GP1, + FIRST_CONFIG_HASH_GP1, + FIRST_CONFIG_FINAL_VALID_START, + NERONZZ_WEEK_1, +} from '../../../Frontend/Utils/constants'; +import { + createDummySeasonData, + isPastOrCurrentRound, +} from '../../../Frontend/Views/Portal/PortalUtils'; +import { AddressTwitterMap } from '../../../_types/darkforest/api/UtilityServerAPITypes'; +import { getGraphQLData } from '../GraphApi'; +import { graphBadgeToGrandPrixBadge } from './BadgeApi'; + +export async function loadWallbreakers( + SEASON_GRAND_PRIXS: GrandPrixMetadata[] +): Promise { + const wallbreakerQuery = SEASON_GRAND_PRIXS.map((grandPrix) => { + const QUERY = ` + query + { + arenas( + where: { + configHash: "${grandPrix.configHash}" + duration_not:null, + startTime_gte: ${grandPrix.startTime} + endTime_lte: ${grandPrix.endTime} + } + orderBy: duration + orderDirection: asc + first: 1 + ) { + configHash + lobbyAddress + winners { + address + } + duration + } + } + `; + return getGraphQLData(QUERY, process.env.GRAPH_URL || 'localhost:8000'); + }); + const res = await Promise.all(wallbreakerQuery); + if (res && res.length == 0) return []; + const wallBreakersRaw = res.filter(x => x.data.arenas.length > 0).map((x) => { + if (x.error) { + throw new Error(x.error); + } else { + const fastestRun: WallbreakerArena = x.data.arenas[0]; + const configHash = fastestRun.configHash; + // Manual logic to account for wrong map. + if(configHash == SECOND_CONFIG_HASH_GP1 && fastestRun.duration > NERONZZ_WEEK_1.time) { + fastestRun.winners[0] = {address: NERONZZ_WEEK_1.address}; + fastestRun.duration = NERONZZ_WEEK_1.time; + return fastestRun + } + else { + return fastestRun + } + } + }); + + // Filter undefined because graph returns [undefined] if query isn't found + const wallBreakers = wallBreakersRaw + .filter((wbr) => wbr !== undefined) + .map((wbr) => { + return { + configHash: wbr.configHash, + player: wbr.winners[0].address, + duration: wbr.duration, + arenaAddress: wbr.lobbyAddress, + } as Wallbreaker; + }); + return wallBreakers; +} + +// Returns all the ConfigPlayers for each Grand Prix, including the Wallbreaker. +// It calls loadWallbreakers() internally. +export async function loadAllPlayerData( + SEASON_GRAND_PRIXS: GrandPrixMetadata[] +): Promise { + if (DUMMY) return createDummySeasonData(200); + if (!EGP) return []; + // Query size is number of unique players on each Grand Prix in a season. (6 GPs * 100 players = 100 results). + // If > 1000, graph won't return. + const QUERY = ` +query + { + configPlayers( + first: 1000 + ) { + id + address + gamesStarted + gamesFinished + bestTime { + winners(first:1) { + moves + } + duration + startTime + endTime + gameOver + } + configHash + badge { + based + ouch + startYourEngine + nice + } + } + } +`; + const rawData = await getGraphQLData(QUERY, process.env.GRAPH_URL || 'localhost:8000'); + if (rawData.error) { + throw new Error(rawData.error); + } + + if (!rawData.data) { + throw new Error(`rawData.data undefined. Make sure query is correct`); + } + if (!rawData.data.configPlayers) + throw new Error(`config players undefined. Make sure query is correct`); + + const configPlayersFinal = await buildCleanConfigPlayer( + rawData.data.configPlayers, + SEASON_GRAND_PRIXS + ); + + return configPlayersFinal; +} + +// Grand Prixs for each player in the given season, grouped by player. +export function loadSeasonPlayers( + configPlayers: CleanConfigPlayer[], + seasonId: number, + SEASON_GRAND_PRIXS: GrandPrixMetadata[] +): SeasonPlayers { + const seasonConfigHashes = SEASON_GRAND_PRIXS.filter((s) => s.seasonId == seasonId).map((s) => + s.configHash.toLowerCase() + ); + const seasonConfigPlayers = configPlayers.filter( + (cp) => + seasonConfigHashes.includes(cp.configHash.toLowerCase()) && + isPastOrCurrentRound(cp.configHash, SEASON_GRAND_PRIXS) && + cp.gamesFinished > 0 + ); + const seasonPlayers = groupByPlayers(seasonConfigPlayers); + return seasonPlayers; +} + +export interface SeasonLeaderboardEntry { + address: string; + games: CleanConfigPlayer[]; + score: number; + totalDuration: number; + badges: number; +} + +export interface SeasonLeaderboardProps { + seasonId: number; + entries: SeasonLeaderboardEntry[]; +} + +// Called after seasonPlayers are filtered for the given season. +export function loadSeasonLeaderboard( + configPlayers: CleanConfigPlayer[], + seasonId: number, + SEASON_GRAND_PRIXS: GrandPrixMetadata[] +): SeasonLeaderboardProps { + const seasonPlayers = loadSeasonPlayers(configPlayers, seasonId, SEASON_GRAND_PRIXS); + const leaderboardProps: SeasonLeaderboardProps = { + seasonId, + entries: [], + }; + + for (const [player, cleanConfigPlayers] of Object.entries(seasonPlayers)) { + const allBadges = cleanConfigPlayers + .map((ccp) => ccp.badges.map((badge) => badge.type).flat()) + .flat(); + const badgeScore = calcBadgeTypeScore(allBadges); + const { score, badges, totalDuration } = cleanConfigPlayers + .map((ccp) => { + return { score: ccp.score, badges: ccp.badges.length, totalDuration: ccp.duration }; + }) + .reduce((a, b) => { + return { + score: a.score + b.score, + badges: a.badges + b.badges, + totalDuration: a.totalDuration + b.totalDuration, + }; + }); + const entry: SeasonLeaderboardEntry = { + address: player, + games: cleanConfigPlayers, + score: score + badgeScore, + totalDuration: totalDuration - badgeScore, + badges, + }; + leaderboardProps.entries.push(entry); + } + return leaderboardProps; +} + +// Filter to get all Config Players for a single Grand Prix +// Can be used for badges +export function loadGrandPrixPlayers(configPlayers: CleanConfigPlayer[], configHash: string) { + const grandPrixScores = configPlayers + .filter((cp) => cp.configHash == configHash) + .sort((a, b) => a.duration - b.duration); + return grandPrixScores; +} + +// Assumes configPlayers have same configHash +export function configPlayersToLeaderboard( + configPlayers: CleanConfigPlayer[], + twitters?: AddressTwitterMap +) { + let entries: LeaderboardEntry[] = []; + + // Just show wallBreaker badge in client. + let numMatches = 0; + configPlayers + .filter((cp) => cp.score > 0) + .map((cp) => { + numMatches += cp.gamesStarted; + const leaderBoardEntry: LeaderboardEntry = { + ethAddress: address(cp.address), + score: calcCleanGrandPrixScore(cp), + twitter: twitters?.[cp.address], + moves: cp.moves, + startTime: cp.startTime, + endTime: cp.endTime, + time: cp.duration, + gamesFinished: cp.gamesFinished, + gamesStarted: cp.gamesStarted, + wallBreaker: cp.badges.some((cp) => cp.type == BadgeType.Wallbreaker), + }; + entries.push(leaderBoardEntry); + }); + + return { entries, length: numMatches } as Leaderboard; +} + +// Get a single player's Season data. Best Grand Prix results and badges. +export function loadSeasonPlayer(playerId: string, configPlayers: ConfigPlayer[]): ConfigPlayer[] { + return configPlayers.filter((cp) => cp.address === playerId); +} + +export function loadGrandPrixLeaderboard( + configPlayers: CleanConfigPlayer[], + configHash: string, + twitters?: AddressTwitterMap +) { + const players = loadGrandPrixPlayers(configPlayers, configHash); + const leaderboard = configPlayersToLeaderboard(players, twitters); + return leaderboard; +} + +export interface BestTime { + duration: number; + winners: { + moves: number; + }[]; + startTime: number; + endTime: number; + gameOver: boolean; +} +// Return list of config players with configHashPrev merged into configHashCurr. +function mergeGrandPrix( + configPlayers: ConfigPlayer[], + configHashPrev: string, + configHashCurr: string +) { + const notInGP = configPlayers.filter( + (cp) => cp.configHash != configHashPrev && cp.configHash != configHashCurr + ); + const playedInGP = configPlayers.filter( + (cp) => cp.configHash == configHashPrev || cp.configHash == configHashCurr + ); + const seasonPlayers = groupByConfigPlayers(playedInGP); + const mergedPlayers: ConfigPlayer[] = []; + for (const [player, configPlayers] of Object.entries(seasonPlayers)) { + // concat player + if (configPlayers.length > 2 || configPlayers.length == 0) + throw new Error('invalid amount of configPlayers'); + + const playedInPrev = configPlayers.find((cp) => cp.configHash == configHashPrev); + const playedInCurr = configPlayers.find((cp) => cp.configHash == configHashCurr); + + if (!playedInPrev && !playedInCurr) throw new Error('prev and curr cannot both be undefined'); + const prevBestTime = playedInPrev?.bestTime; + const currBestTime = playedInCurr?.bestTime; + + let bestTime: BestTime | undefined; + if (prevBestTime && !currBestTime) { + bestTime = prevBestTime; + } else if (!prevBestTime && currBestTime) { + bestTime = currBestTime; + } else if (prevBestTime && currBestTime) { + bestTime = prevBestTime.duration < currBestTime.duration ? prevBestTime : currBestTime; + } else { + bestTime = undefined; + } + + function mergeBadges(player1Badges: BadgeSet | undefined, player2Badges: BadgeSet | undefined) { + let newBadgeSet: BadgeSet = { + startYourEngine: + Boolean(player1Badges?.startYourEngine) || Boolean(player2Badges?.startYourEngine), + nice: Boolean(player1Badges?.nice) || Boolean(player2Badges?.nice), + ouch: Boolean(player1Badges?.ouch) || Boolean(player2Badges?.ouch), + based: Boolean(player1Badges?.based) || Boolean(player2Badges?.based), + wallBreaker: false, + }; + + return newBadgeSet; + } + + const newConfigPlayer: ConfigPlayer = { + id: `${configPlayers[0].address}-${configHashCurr}`, + configHash: configHashCurr, + address: configPlayers[0].address, + bestTime, + gamesStarted: + (playedInPrev ? playedInPrev.gamesStarted : 0) + + (playedInCurr ? playedInCurr.gamesStarted : 0), + gamesFinished: + (playedInPrev ? playedInPrev.gamesFinished : 0) + + (playedInCurr ? playedInCurr.gamesFinished : 0), + badge: mergeBadges(playedInPrev?.badge, playedInCurr?.badge), + }; + // push + mergedPlayers.push(newConfigPlayer); + } + + return notInGP.concat(mergedPlayers); +} + +// Returns true if a given match has occurred after the Grand Prix start time. +// OR true if match is not a grand Prix match. +export function validGrandPrixMatch( + configHash: string, + startTime: number | undefined, + SEASON_GRAND_PRIXS: GrandPrixMetadata[] +) { + const grandPrixs = SEASON_GRAND_PRIXS.filter((gp) => gp.configHash == configHash); + if (grandPrixs.length == 0) return true; // Match is valid if not an official Grand Prix. + if (!startTime) return false; + const grandPrix = grandPrixs[0]; + return startTime >= grandPrix.startTime; +} + +// Add wallbreaker badge to ConfigPlayers +async function buildCleanConfigPlayer( + configPlayers: ConfigPlayer[], + SEASON_GRAND_PRIXS: GrandPrixMetadata[] +): Promise { + const wallBreakers = await loadWallbreakers(SEASON_GRAND_PRIXS); + const configPlayersStage1 = configPlayers.filter( + (cp) => + validGrandPrixMatch(cp.configHash, cp.bestTime?.startTime, SEASON_GRAND_PRIXS) && + cp.gamesFinished > 0 && + // Filter just for Grand Prix Week 1 + (cp.configHash == FIRST_CONFIG_HASH_GP1 + ? cp.bestTime!.startTime < FIRST_CONFIG_FINAL_VALID_START + : true) + ); + + // Merge just for Grand Prix Week 1 + const configPlayersStage2 = mergeGrandPrix( + configPlayersStage1, + FIRST_CONFIG_HASH_GP1, + SECOND_CONFIG_HASH_GP1 + ); + + return configPlayersStage2.map((cfp) => { + const isWallBreaker = + wallBreakers.length > 0 && + wallBreakers.filter((e) => e.player === cfp.address && e.configHash === cfp.configHash) + .length > 0; + if (isWallBreaker && cfp.badge) { + cfp.badge.wallBreaker = true; + } + const duration = cfp.bestTime ? cfp.bestTime.duration : HOUR_IN_SECONDS; + const cleanConfig: CleanConfigPlayer = { + id: cfp.id, + address: cfp.address, + duration, + moves: cfp.bestTime ? cfp.bestTime.winners[0].moves : 0, + startTime: cfp.bestTime ? cfp.bestTime.startTime : Math.floor(Date.now() / 1000), + endTime: cfp.bestTime ? cfp.bestTime.endTime : Math.floor(Date.now() / 1000), + badges: graphBadgeToGrandPrixBadge(cfp.badge, cfp.configHash), + configHash: cfp.configHash, + gamesStarted: cfp.gamesStarted, + gamesFinished: cfp.gamesFinished, + score: calcGrandPrixScore(duration), // Doesn't include badges!! + }; + return cleanConfig; + }); +} + +// Group ConfigPlayers by address to calculate Season Score +export function groupByPlayers(configPlayers: CleanConfigPlayer[]): SeasonPlayers { + const seasonPlayers: SeasonPlayers = {}; + configPlayers.map((cp) => { + if (!seasonPlayers[cp.address]) seasonPlayers[cp.address] = []; + seasonPlayers[cp.address].push(cp); + }); + return seasonPlayers; +} + +export interface SeasonConfigPlayers { + [address: string]: ConfigPlayer[]; +} +export function groupByConfigPlayers(configPlayers: ConfigPlayer[]): SeasonConfigPlayers { + const seasonPlayers: SeasonConfigPlayers = {}; + configPlayers.map((cp) => { + if (!seasonPlayers[cp.address]) seasonPlayers[cp.address] = []; + seasonPlayers[cp.address].push(cp); + }); + return seasonPlayers; +} + +// Sum player dictionary to create list of {player, score} +export function getSeasonScore( + seasonPlayers: SeasonPlayers, + SEASON_GRAND_PRIXS: GrandPrixMetadata[] +): SeasonScore[] { + const seasonScores: SeasonScore[] = []; + for (const [player, cleanConfigPlayers] of Object.entries(seasonPlayers)) { + const badges: ConfigBadge[][] = []; + const seasonScore: SeasonScore = { + player, + score: cleanConfigPlayers + .filter((ccp) => isPastOrCurrentRound(ccp.configHash, SEASON_GRAND_PRIXS)) + .map((result) => { + badges.push(result.badges); + return calcCleanGrandPrixScore(result); + }) + .reduce((prev, curr) => prev + curr), + grandPrixsFinished: cleanConfigPlayers.length, + }; + seasonScore.score -= calcBadgeTypeScore(badges.flat().map((b) => b.type)); + seasonScores.push(seasonScore); + } + return seasonScores; +} +function groupByGrandPrix(configPlayers: CleanConfigPlayer[] | undefined): GrandPrixPlayers { + if (!configPlayers) return {}; + + const seasonPlayers: GrandPrixPlayers = {}; + configPlayers.map((cp) => { + if (!seasonPlayers[cp.configHash]) seasonPlayers[cp.configHash] = []; + seasonPlayers[cp.configHash].push(cp); + }); + return seasonPlayers; +} + +export interface Seasons { + [id: number]: GrandPrixMetadata[]; +} + +function groupBySeason(grandPrixs: GrandPrixMetadata[]): Seasons { + const seasons: Seasons = {}; + grandPrixs.map((gp) => { + if (!seasons[gp.seasonId]) seasons[gp.seasonId] = []; + seasons[gp.seasonId].push(gp); + }); + return seasons; +} + +/** + * Utils to calculate scores + */ +export function calcBadgeTypeScore(badges: BadgeType[]): number { + let badgeScore = 0; + for (let item of Object.values(BadgeType)) { + if (badges.includes(item as BadgeType)) badgeScore += BADGE_BONUSES[item as BadgeType].bonus; + } + return badgeScore; +} + +// Doesn't include badges. Badges just add season points. +export function calcCleanGrandPrixScore(cleanConfigPlayer: CleanConfigPlayer): number { + // return HOUR_IN_SECONDS - cleanConfigPlayer.duration; + return cleanConfigPlayer.duration; +} + +export function calcGrandPrixScore(duration: number): number { + return duration; +} + +/** + * Big daddy score calculation + */ + +// Returns empty values if player not found +export function loadPlayerSeasonHistoryView( + player: EthAddress, + configPlayers: CleanConfigPlayer[], + SEASON_GRAND_PRIXS: GrandPrixMetadata[] +): SeasonHistory[] { + const seasonHistories: SeasonHistory[] = []; + + // Get Season Rank and Score. + // Need to handle multiple seasons. + + // Loops over all official Grand Prixs + const seasons = groupBySeason(SEASON_GRAND_PRIXS); + + // For each Season, get required data. + for (const [key, value] of Object.entries(seasons)) { + const grandPrixs = value as GrandPrixMetadata[]; + + // Calculate Player's Season Aggregate Statistics + const seasonId = parseInt(key); + const seasonScores = getSeasonScore( + loadSeasonPlayers(configPlayers, seasonId, SEASON_GRAND_PRIXS), + SEASON_GRAND_PRIXS + ); + + let rank = seasonScores.length; + let score = 0; + seasonScores + .sort((a, b) => { + if (a.grandPrixsFinished > b.grandPrixsFinished) return -1; + else if (b.grandPrixsFinished > a.grandPrixsFinished) return 1; + else { + return a.score - b.score; + } + }) + .map((s, index) => { + if (s.player == player) { + rank = index + 1; + score = s.score; + } + }); + + const seasonHistory: SeasonHistory = { + seasonId, + rank, + score, + players: seasonScores.length, + grandPrixs: [], + }; + + const grandPrixHistories: GrandPrixHistory[] = []; + + // Calculate Grand prix aggregate statistics + grandPrixs.map((gp) => { + // When no players have started a game, no config players exist. + const allGrandPrixs = groupByGrandPrix(configPlayers)[gp.configHash]; + let rank = allGrandPrixs ? allGrandPrixs.length : 0; + let score = 0; + if (allGrandPrixs && allGrandPrixs.length > 0) { + allGrandPrixs + .sort((a, b) => a.score - b.score) + .map((s, index) => { + if (s.address == player) { + rank = index + 1; + score = s.score; + } + }); + + // Get grand prixs player has participated in for badges + const seasonPlayers = groupByPlayers(configPlayers)[player] as + | CleanConfigPlayer[] + | undefined; + const playerGrandPrixs = seasonPlayers?.filter((cp) => cp.configHash == gp.configHash)[0]; + + const grandPrixHistory: GrandPrixHistory = { + configHash: gp.configHash, + rank, + score, + players: allGrandPrixs.length, + badges: playerGrandPrixs ? playerGrandPrixs.badges : [], + }; + + grandPrixHistories.push(grandPrixHistory); + } + }); + + seasonHistory.grandPrixs = grandPrixHistories; + seasonHistories.push(seasonHistory); + } + return seasonHistories; +} + +export function getBadges(configBadges: BadgeType[][]): BadgeType[] { + return configBadges.map((configBadge) => configBadge).flat(); +} + +// Output: object of player address => unique season badges +export function loadUniquePlayerBadges( + configPlayers: CleanConfigPlayer[], + seasonId: number, + SEASON_GRAND_PRIXS: GrandPrixMetadata[] +) { + const seasonPlayers = loadSeasonPlayers(configPlayers, seasonId, SEASON_GRAND_PRIXS); + const res: { [player: string]: ConfigBadge[] } = {}; + for (const [player, playerGrandPrixs] of Object.entries(seasonPlayers)) { + const allBadges = playerGrandPrixs.map((pgp) => pgp.badges).flat(); + const uniqueBadgeSet: UniquePlayerBadges = {}; + const wallBreakers: ConfigBadge[] = []; + allBadges.forEach((cb) => { + if (cb.type != BadgeType.Wallbreaker) { + uniqueBadgeSet[cb.type] = cb; + } else { + wallBreakers.push(cb); + } + }); + + const uniques = Object.values(uniqueBadgeSet) as ConfigBadge[]; + res[player] = uniques.concat(wallBreakers); + } + return res; +} diff --git a/client/src/Backend/Network/GraphApi/SpyApi.ts b/client/src/Backend/Network/GraphApi/SpyApi.ts new file mode 100644 index 00000000..0359653a --- /dev/null +++ b/client/src/Backend/Network/GraphApi/SpyApi.ts @@ -0,0 +1,75 @@ +import { CleanMatchEntry, ExtendedMatchEntry, GrandPrixMetadata, LiveMatch } from '@darkforest_eth/types'; +import { getGraphQLData } from '../GraphApi'; +import { validGrandPrixMatch } from './SeasonLeaderboardApi'; + +export const loadLiveMatches = async ( + seasonData: GrandPrixMetadata[], + configHash?: string +): Promise => { + // Get last week of data. + const startTime = Math.round((Date.now() - 1000 * 60 * 60 * 24 * 7) / 1000); + + const hash = configHash ? `configHash: "${configHash}",` : ''; + const query = ` + query { + arenas(first: 1000, orderBy: startTime, orderDirection: desc, where: {startTime_gt: ${startTime}, ${hash}}) { + lobbyAddress + firstMover { + address + }, + players { + address + moves + } + creator, + id + startTime, + endTime, + configHash + planets { + spawnPlanet + } + gameOver + duration + } + }`; + + const response = await getGraphQLData(query, process.env.GRAPH_URL || 'localhost:8000'); + if ('errors' in response) { + throw new Error(`error when fetching data, ${JSON.stringify(response)}`); + } + + const { arenas } = response.data; + if (arenas === null) { + throw new Error(`error when fetching data, ${JSON.stringify(response)}`); + } + + return { entries: cleanLiveMatches(arenas as ExtendedMatchEntry[], seasonData) }; +}; + +function calcMoves(match: ExtendedMatchEntry) { + const players = match.players; + if (!players || players.length == 0) return 0; + else { + return players.map((lm) => lm.moves).reduce((a, b) => a + b); + } +} +export function cleanLiveMatches(liveMatches: ExtendedMatchEntry[], seasonData: GrandPrixMetadata[]) { + return liveMatches + .filter(lm => validGrandPrixMatch(lm.configHash,lm.startTime,seasonData)) + .map((lm) => { + const clean: CleanMatchEntry = { + creator: lm.creator, + lobbyAddress: lm.lobbyAddress, + moves: calcMoves(lm), + configHash: lm.configHash, + numSpawn: lm.planets.length, + gameOver: lm.gameOver, + duration: lm.duration, + startTime: lm.startTime, + endTime: lm.endTime, + players: lm.players ? lm.players.map((p) => p.address) : [], + }; + return clean; + }); +} diff --git a/client/src/Backend/Network/MessageAPI.ts b/client/src/Backend/Network/MessageAPI.ts index 5155aa27..5d6c0f3c 100644 --- a/client/src/Backend/Network/MessageAPI.ts +++ b/client/src/Backend/Network/MessageAPI.ts @@ -4,17 +4,17 @@ import { PlanetMessageResponse, PostMessageRequest, SignedMessage, -} from '@dfdao/types'; +} from '@darkforest_eth/types'; export async function getMessagesOnPlanets( request: PlanetMessageRequest ): Promise { - if (request.planets.length === 0 || !import.meta.env.DF_WEBSERVER_URL) { + if (request.planets.length === 0 || !process.env.DF_WEBSERVER_URL) { return {}; } try { - const response = await fetch(`${import.meta.env.DF_WEBSERVER_URL}/messages`, { + const response = await fetch(`${process.env.DF_WEBSERVER_URL}/messages`, { headers: { 'Content-Type': 'application/json', }, @@ -34,12 +34,12 @@ export async function getMessagesOnPlanets( export async function addMessage( request: SignedMessage> ): Promise { - if (!import.meta.env.DF_WEBSERVER_URL) { + if (!process.env.DF_WEBSERVER_URL) { return; } try { - const res = await fetch(`${import.meta.env.DF_WEBSERVER_URL}/add-message`, { + const res = await fetch(`${process.env.DF_WEBSERVER_URL}/add-message`, { headers: { 'Content-Type': 'application/json', }, @@ -57,12 +57,12 @@ export async function addMessage( } export async function deleteMessages(request: SignedMessage): Promise { - if (!import.meta.env.DF_WEBSERVER_URL) { + if (!process.env.DF_WEBSERVER_URL) { return; } try { - const res = await fetch(`${import.meta.env.DF_WEBSERVER_URL}/delete-messages`, { + const res = await fetch(`${process.env.DF_WEBSERVER_URL}/delete-messages`, { headers: { 'Content-Type': 'application/json', }, diff --git a/client/src/Backend/Network/NetworkHealthApi.ts b/client/src/Backend/Network/NetworkHealthApi.ts index 94b5785e..98e2b082 100644 --- a/client/src/Backend/Network/NetworkHealthApi.ts +++ b/client/src/Backend/Network/NetworkHealthApi.ts @@ -1,15 +1,15 @@ -import { NetworkHealthSummary } from '@dfdao/types'; +import { NetworkHealthSummary } from '@darkforest_eth/types'; /** * The Dark Forest webserver keeps track of network health, this function loads that information * from the webserver. */ export async function loadNetworkHealth(): Promise { - if (!import.meta.env.DF_WEBSERVER_URL) { + if (!process.env.DF_WEBSERVER_URL) { return []; } - const result = await fetch(`${import.meta.env.DF_WEBSERVER_URL}/network-health`, { + const result = await fetch(`${process.env.DF_WEBSERVER_URL}/network-health`, { method: 'POST', headers: { 'Content-Type': 'application/json', diff --git a/client/src/Backend/Network/UtilityServerAPI.ts b/client/src/Backend/Network/UtilityServerAPI.ts index 2a673cc4..b62ecb76 100644 --- a/client/src/Backend/Network/UtilityServerAPI.ts +++ b/client/src/Backend/Network/UtilityServerAPI.ts @@ -1,8 +1,17 @@ -import { EthAddress, RegisterResponse, SignedMessage, WhitelistStatusResponse } from '@dfdao/types'; +import { FAUCET_ADDRESS } from '@darkforest_eth/contracts'; +import { DFArenaFaucet } from '@darkforest_eth/contracts/typechain'; +import { EthConnection, weiToEth } from '@darkforest_eth/network'; +import { + EthAddress, + RegisterResponse, + SignedMessage, + WhitelistStatusResponse, +} from '@darkforest_eth/types'; import * as EmailValidator from 'email-validator'; import timeout from 'p-timeout'; import { TerminalHandle } from '../../Frontend/Views/Terminal'; import { AddressTwitterMap } from '../../_types/darkforest/api/UtilityServerAPITypes'; +import { loadFaucetContract } from './Blockchain'; export const enum EmailResponse { Success, @@ -11,14 +20,14 @@ export const enum EmailResponse { } export const submitInterestedEmail = async (email: string): Promise => { - if (!import.meta.env.DF_WEBSERVER_URL) { + if (!process.env.DF_WEBSERVER_URL) { return EmailResponse.ServerError; } if (!EmailValidator.validate(email)) { return EmailResponse.Invalid; } - const { success } = await fetch(`${import.meta.env.DF_WEBSERVER_URL}/email/interested`, { + const { success } = await fetch(`${process.env.DF_WEBSERVER_URL}/email/interested`, { method: 'POST', body: JSON.stringify({ email }), headers: { @@ -30,14 +39,14 @@ export const submitInterestedEmail = async (email: string): Promise => { - if (!import.meta.env.DF_WEBSERVER_URL) { + if (!process.env.DF_WEBSERVER_URL) { return EmailResponse.ServerError; } if (!EmailValidator.validate(email)) { return EmailResponse.Invalid; } - const { success } = await fetch(`${import.meta.env.DF_WEBSERVER_URL}/email/unsubscribe`, { + const { success } = await fetch(`${process.env.DF_WEBSERVER_URL}/email/unsubscribe`, { method: 'POST', body: JSON.stringify({ email }), headers: { @@ -51,7 +60,7 @@ export const submitUnsubscribeEmail = async (email: string): Promise ): Promise => { - if (!import.meta.env.DF_WEBSERVER_URL) { + if (!process.env.DF_WEBSERVER_URL) { return EmailResponse.ServerError; } @@ -59,7 +68,7 @@ export const submitPlayerEmail = async ( return EmailResponse.Invalid; } - const { success } = await fetch(`${import.meta.env.DF_WEBSERVER_URL}/email/playing`, { + const { success } = await fetch(`${process.env.DF_WEBSERVER_URL}/email/playing`, { method: 'POST', body: JSON.stringify(request), headers: { @@ -105,7 +114,7 @@ export async function callRegisterAndWaitForConfirmation( address: EthAddress, terminal: React.MutableRefObject ): Promise { - if (!import.meta.env.DF_WEBSERVER_URL) { + if (!process.env.DF_WEBSERVER_URL) { return { errorMessage: 'Cannot connect to server.', canRetry: false }; } @@ -141,19 +150,16 @@ export async function callRegisterAndWaitForConfirmation( export const whitelistStatus = async ( address: EthAddress ): Promise => { - if (!import.meta.env.DF_WEBSERVER_URL) { + if (!process.env.DF_WEBSERVER_URL) { return null; } - return await fetch( - `${import.meta.env.DF_WEBSERVER_URL}/whitelist/address/${address}/isWhitelisted`, - { - method: 'GET', - headers: { - 'Content-Type': 'application/json', - }, - } - ).then((x) => x.json()); + return await fetch(`${process.env.DF_WEBSERVER_URL}/whitelist/address/${address}/isWhitelisted`, { + method: 'GET', + headers: { + 'Content-Type': 'application/json', + }, + }).then((x) => x.json()); }; /** @@ -164,12 +170,12 @@ export const submitWhitelistKey = async ( key: string, address: EthAddress ): Promise => { - if (!import.meta.env.DF_WEBSERVER_URL) { + if (!process.env.DF_WEBSERVER_URL) { return null; } try { - return await fetch(`${import.meta.env.DF_WEBSERVER_URL}/whitelist/register`, { + return await fetch(`${process.env.DF_WEBSERVER_URL}/whitelist/register`, { method: 'POST', body: JSON.stringify({ key, @@ -185,18 +191,64 @@ export const submitWhitelistKey = async ( } }; +export async function sendDrip(connection: EthConnection, address: EthAddress) { + // If drip fails + try { + const currBalance = weiToEth(await connection.loadBalance(address)); + const faucet = await connection.loadContract(FAUCET_ADDRESS, loadFaucetContract); + const nextAccessTimeSeconds = (await faucet.getNextAccessTime(address)).toNumber(); + const nowSeconds = Date.now() / 999; + + if (currBalance > 0.005 || nowSeconds < nextAccessTimeSeconds) { + return; + } + const success = await requestFaucet(address); + + if (!success) { + throw new Error('An error occurred in faucet. Try again with an account that has XDAI'); + } + } catch (e) { + throw new Error(e); + } +} + +export const requestFaucet = async (address: EthAddress): Promise => { + if (!process.env.FAUCET_URL) { + return false; + } + + console.log(`sending faucet request for`, address); + // TODO: Provide own env variable for this feature + // if (process.env.NODE_ENV === 'production') { + // return false; + // } + + try { + const res = await fetch(`${process.env.FAUCET_URL}/drip/${address}`, {}); + if (!res.ok) { + const json = await res.json(); + console.log(json); + return false; + } + return true; + } catch (e) { + console.error(`error when requesting drip: ${e}`); + return false; + } +}; + export const requestDevFaucet = async (address: EthAddress): Promise => { - if (!import.meta.env.DF_WEBSERVER_URL) { + if (!process.env.DF_WEBSERVER_URL) { return false; } // TODO: Provide own env variable for this feature - if (import.meta.env.PROD) { + if (process.env.NODE_ENV === 'production') { return false; } try { - const { success } = await fetch(`${import.meta.env.DF_WEBSERVER_URL}/whitelist/faucet`, { + const { success } = await fetch(`${process.env.DF_WEBSERVER_URL}/whitelist/faucet`, { method: 'POST', body: JSON.stringify({ address, @@ -227,7 +279,7 @@ export const tryGetAllTwitters = async (): Promise => { export const getAllTwitters = async (): Promise => { try { const twitterMap: AddressTwitterMap = await fetch( - `${import.meta.env.DF_WEBSERVER_URL}/twitter/all-twitters` + `${process.env.DF_TWITTER_URL}/twitter/all-twitters` ).then((x) => x.json()); return twitterMap; } catch (e) { @@ -239,7 +291,7 @@ export const verifyTwitterHandle = async ( verifyMessage: SignedMessage<{ twitter: string }> ): Promise => { try { - const res = await fetch(`${import.meta.env.DF_WEBSERVER_URL}/twitter/verify-twitter`, { + const res = await fetch(`${process.env.DF_TWITTER_URL}/twitter/verify-twitter`, { method: 'POST', body: JSON.stringify({ verifyMessage, @@ -248,7 +300,6 @@ export const verifyTwitterHandle = async ( 'Content-Type': 'application/json', }, }).then((x) => x.json()); - return res.success; } catch (e) { console.error(`error when verifying twitter handle: ${e}`); @@ -260,7 +311,7 @@ export const disconnectTwitter = async ( disconnectMessage: SignedMessage<{ twitter: string }> ): Promise => { try { - const res = await fetch(`${import.meta.env.DF_WEBSERVER_URL}/twitter/disconnect`, { + const res = await fetch(`${process.env.DF_TWITTER_URL}/twitter/disconnect`, { method: 'POST', body: JSON.stringify({ disconnectMessage, @@ -276,3 +327,11 @@ export const disconnectTwitter = async ( return false; } }; + +export const fetcher = (...args: any) => + fetch(args).then((res) => { + if (!res.ok) { + return undefined; + } + return res.json(); + }); diff --git a/client/src/Backend/Plugins/EmbeddedPluginLoader.ts b/client/src/Backend/Plugins/EmbeddedPluginLoader.ts index c08856ab..725e7209 100644 --- a/client/src/Backend/Plugins/EmbeddedPluginLoader.ts +++ b/client/src/Backend/Plugins/EmbeddedPluginLoader.ts @@ -1,4 +1,4 @@ -import { PluginId } from '@dfdao/types'; +import { PluginId } from '@darkforest_eth/types'; /** * This interface represents an embedded plugin, which is stored in `embedded_plugins/`. @@ -13,44 +13,30 @@ export interface EmbeddedPlugin { * Load all of the embedded plugins in the dist directory of the `embedded_plugins/` project * as Plain Text files. This means that `embedded_plugins/` can't use `import` for relative paths. */ -const pluginsContext: Record = import.meta.glob( - [ - '../../../embedded_plugins/**/*.ts', - '../../../embedded_plugins/**/*.tsx', - '../../../embedded_plugins/**/*.js', - '../../../embedded_plugins/**/*.jsx', - ], - { - eager: true, - } -); - -function flattenPath(filename: string) { - // TODO: Remove the `./` when possible, only added for parity with the old webpack code - return filename.replace('../../../embedded_plugins/', './'); -} +const pluginsContext = require.context('../../../embedded_plugins/', false, /\.[jt]sx?$/); function cleanFilename(filename: string) { - return flattenPath(filename) + return filename .replace(/^\.\//, '') .replace(/[_-]/g, ' ') .replace(/\.[jt]sx?$/, ''); } export function getEmbeddedPlugins(isAdmin: boolean) { - return Object.keys(pluginsContext) + return pluginsContext + .keys() .filter((filename) => { if (isAdmin) { return true; } else { - return !filename.includes('./Admin-Controls'); + return !filename.startsWith('./Admin-Controls') && !filename.startsWith('./Metrics'); } }) .map((filename) => { return { - id: flattenPath(filename) as PluginId, + id: filename as PluginId, name: cleanFilename(filename), - code: pluginsContext[filename].default, + code: pluginsContext<{ default: string }>(filename).default, }; }); } diff --git a/client/src/Backend/Plugins/SerializedPlugin.ts b/client/src/Backend/Plugins/SerializedPlugin.ts index 26160f45..999c8e3c 100644 --- a/client/src/Backend/Plugins/SerializedPlugin.ts +++ b/client/src/Backend/Plugins/SerializedPlugin.ts @@ -1,4 +1,4 @@ -import { PluginId } from '@dfdao/types'; +import { PluginId } from '@darkforest_eth/types'; /** * Represents a plugin that the user has added to their game. Used diff --git a/client/src/Backend/Storage/OtherStore.ts b/client/src/Backend/Storage/OtherStore.ts deleted file mode 100644 index 238dda12..00000000 --- a/client/src/Backend/Storage/OtherStore.ts +++ /dev/null @@ -1,244 +0,0 @@ -import { - ClaimedCoords, - EthAddress, - LocationId, - ModalId, - ModalPosition, - PersistedTransaction, - RevealedCoords, - Transaction, - WorldLocation, -} from '@dfdao/types'; -import { IDBPDatabase, openDB } from 'idb'; -import stringify from 'json-stable-stringify'; -import { SerializedPlugin } from '../Plugins/SerializedPlugin'; - -const enum ObjectStore { - DEFAULT = 'default', - UNCONFIRMED_ETH_TXS = 'unminedEthTxs', - PLUGINS = 'plugins', - /** - * Store modal positions so that we can keep modal panes open across sessions. - */ - MODAL_POS = 'modalPositions', -} - -interface OtherStoreConfig { - db: IDBPDatabase; - contractAddress: EthAddress; - account: EthAddress; -} - -export const MODAL_POSITIONS_KEY = 'modal_positions'; - -class OtherStore { - private db: IDBPDatabase; - private confirmedTxHashes: Set; - private account: EthAddress; - private contractAddress: EthAddress; - - constructor({ db, account, contractAddress }: OtherStoreConfig) { - this.db = db; - this.confirmedTxHashes = new Set(); - this.account = account; - this.contractAddress = contractAddress; - } - - destroy(): void { - // no-op; we don't actually destroy the instance, we leave the db connection open in case we need it in the future - } - - /** - * NOTE! if you're creating a new object store, it will not be *added* to existing dark forest - * accounts. This creation code runs once per account. Therefore, if you're adding a new object - * store, and need to test it out, you must either clear the indexed db databse for this account, - * or create a brand new account. - */ - static async create({ - account, - contractAddress, - }: Omit): Promise { - const db = await openDB(`darkforest-${contractAddress}-${account}`, 1, { - upgrade(db) { - db.createObjectStore(ObjectStore.DEFAULT); - db.createObjectStore(ObjectStore.UNCONFIRMED_ETH_TXS); - db.createObjectStore(ObjectStore.PLUGINS); - db.createObjectStore(ObjectStore.MODAL_POS); - }, - }); - - const localStorageManager = new OtherStore({ db, account, contractAddress }); - - return localStorageManager; - } - - /** - * Important! This sets the key in indexed db per account and per contract. This means the same - * client can connect to multiple different dark forest contracts, with multiple different - * accounts, and the persistent storage will not overwrite data that is not relevant for the - * current configuration of the client. - */ - private async getKey( - key: string, - objStore: ObjectStore = ObjectStore.DEFAULT - ): Promise { - return await this.db.get(objStore, `${this.contractAddress}-${this.account}-${key}`); - } - - /** - * Important! This sets the key in indexed db per account and per contract. This means the same - * client can connect to multiple different dark forest contracts, with multiple different - * accounts, and the persistent storage will not overwrite data that is not relevant for the - * current configuration of the client. - */ - private async setKey( - key: string, - value: string, - objStore: ObjectStore = ObjectStore.DEFAULT - ): Promise { - await this.db.put(objStore, value, `${this.contractAddress}-${this.account}-${key}`); - } - - private async removeKey(key: string, objStore: ObjectStore = ObjectStore.DEFAULT): Promise { - await this.db.delete(objStore, `${this.contractAddress}-${this.account}-${key}`); - } - - /** - * we keep a list rather than a single location, since client/contract can - * often go out of sync on initialization - if client thinks that init - * failed but is wrong, it will prompt user to initialize with new home coords, - * which bricks the user's account. - */ - public async getHomeLocations(): Promise { - const homeLocations = await this.getKey('homeLocations'); - let parsed: WorldLocation[] = []; - if (homeLocations) { - parsed = JSON.parse(homeLocations) as WorldLocation[]; - } - - return parsed; - } - - public async addHomeLocation(location: WorldLocation): Promise { - let locationList = await this.getHomeLocations(); - if (locationList) { - locationList.push(location); - } else { - locationList = [location]; - } - locationList = Array.from(new Set(locationList)); - await this.setKey('homeLocations', stringify(locationList)); - } - - public async confirmHomeLocation(location: WorldLocation): Promise { - await this.setKey('homeLocations', stringify([location])); - } - - public async getSavedTouchedPlanetIds(): Promise { - const touchedPlanetIds = await this.getKey('touchedPlanetIds'); - - if (touchedPlanetIds) { - const parsed = JSON.parse(touchedPlanetIds) as LocationId[]; - return parsed; - } - - return []; - } - - public async getSavedRevealedCoords(): Promise { - const revealedPlanetIds = await this.getKey('revealedPlanetIds'); - - if (revealedPlanetIds) { - const parsed = JSON.parse(revealedPlanetIds); - // changed the type on 6/1/21 to include revealer field - // eslint-disable-next-line @typescript-eslint/no-explicit-any - if (parsed.length === 0 || !(parsed[0] as any).revealer) { - return []; - } - return parsed as RevealedCoords[]; - } - - return []; - } - public async getSavedClaimedCoords(): Promise { - const claimedPlanetIds = await this.getKey('claimedPlanetIds'); - - if (claimedPlanetIds) { - const parsed = JSON.parse(claimedPlanetIds); - // changed the type on 6/1/21 to include revealer field - // eslint-disable-next-line @typescript-eslint/no-explicit-any - if (parsed.length === 0 || !(parsed[0] as any).revealer) { - return []; - } - return parsed as ClaimedCoords[]; - } - - return []; - } - - public async saveTouchedPlanetIds(ids: LocationId[]) { - await this.setKey('touchedPlanetIds', stringify(ids)); - } - - public async saveRevealedCoords(revealedCoordTups: RevealedCoords[]) { - await this.setKey('revealedPlanetIds', stringify(revealedCoordTups)); - } - - public async saveClaimedCoords(claimedCoordTupps: ClaimedCoords[]) { - await this.setKey('claimedPlanetIds', stringify(claimedCoordTupps)); - } - - /** - * Whenever a transaction is submitted, it is persisted. When the transaction either fails or - * succeeds, it is un-persisted. The reason we persist submitted transactions is to be able to - * wait for them upon a fresh start of the game if you close the game before a transaction - * confirms. - */ - public async onEthTxSubmit(tx: Transaction): Promise { - // in case the tx was mined and saved already - if (!tx.hash || this.confirmedTxHashes.has(tx.hash)) return; - const ser: PersistedTransaction = { hash: tx.hash, intent: tx.intent }; - await this.db.put(ObjectStore.UNCONFIRMED_ETH_TXS, JSON.parse(JSON.stringify(ser)), tx.hash); - } - - /** - * Partner function to {@link OtherStore#onEthTxSubmit} - */ - public async onEthTxComplete(txHash: string): Promise { - this.confirmedTxHashes.add(txHash); - await this.db.delete(ObjectStore.UNCONFIRMED_ETH_TXS, txHash); - } - - public async getUnconfirmedSubmittedEthTxs(): Promise { - const ret: PersistedTransaction[] = await this.db.getAll(ObjectStore.UNCONFIRMED_ETH_TXS); - return ret; - } - - public async loadPlugins(): Promise { - const savedPlugins = await this.getKey('plugins', ObjectStore.PLUGINS); - - if (!savedPlugins) { - return []; - } - - return JSON.parse(savedPlugins) as SerializedPlugin[]; - } - - public async savePlugins(plugins: SerializedPlugin[]): Promise { - await this.setKey('plugins', JSON.stringify(plugins), ObjectStore.PLUGINS); - } - - public async saveModalPositions(modalPositions: Map): Promise { - if (!this.db.objectStoreNames.contains(ObjectStore.MODAL_POS)) return; - const serialized = JSON.stringify(Array.from(modalPositions.entries())); - await this.setKey(MODAL_POSITIONS_KEY, serialized, ObjectStore.MODAL_POS); - } - - public async loadModalPositions(): Promise> { - if (!this.db.objectStoreNames.contains(ObjectStore.MODAL_POS)) return new Map(); - const winPos = await this.getKey(MODAL_POSITIONS_KEY, ObjectStore.MODAL_POS); - return new Map(winPos ? JSON.parse(winPos) : null); - } -} - -export default OtherStore; diff --git a/client/src/Backend/Storage/PersistentChunkStore.ts b/client/src/Backend/Storage/PersistentChunkStore.ts index ae386c9f..b49d6ba5 100644 --- a/client/src/Backend/Storage/PersistentChunkStore.ts +++ b/client/src/Backend/Storage/PersistentChunkStore.ts @@ -1,32 +1,127 @@ -import { Chunk, DiagnosticUpdater, EthAddress, Rectangle } from '@dfdao/types'; -import { IndexeddbPersistence } from 'y-indexeddb'; -import { Doc, Map } from 'yjs'; +import { + Chunk, + ClaimedCoords, + DiagnosticUpdater, + EthAddress, + LocationId, + ModalId, + ModalPosition, + PersistedTransaction, + Rectangle, + RevealedCoords, + Transaction, + WorldLocation, +} from '@darkforest_eth/types'; +import { IDBPDatabase, openDB } from 'idb'; +import stringify from 'json-stable-stringify'; +import _ from 'lodash'; import { MAX_CHUNK_SIZE } from '../../Frontend/Utils/constants'; +import { ChunkId, ChunkStore, PersistedChunk } from '../../_types/darkforest/api/ChunkStoreTypes'; import { - ChunkStore, + addToChunkMap, getChunkKey, getChunkOfSideLengthContainingPoint, - processChunkInMap, + toExploredChunk, + toPersistedChunk, } from '../Miner/ChunkUtils'; +import { SerializedPlugin } from '../Plugins/SerializedPlugin'; + +const enum ObjectStore { + DEFAULT = 'default', + BOARD = 'knownBoard', + UNCONFIRMED_ETH_TXS = 'unminedEthTxs', + PLUGINS = 'plugins', + /** + * Store modal positions so that we can keep modal panes open across sessions. + */ + MODAL_POS = 'modalPositions', +} + +const enum DBActionType { + UPDATE, + DELETE, +} + +interface DBAction { + type: DBActionType; + dbKey: T; + dbValue?: Chunk; +} + +type DBTx = DBAction[]; + +interface DebouncedFunc void> { + (...args: Parameters): ReturnType | undefined; + cancel(): void; +} + +interface PersistentChunkStoreConfig { + db: IDBPDatabase; + contractAddress: EthAddress; + account: EthAddress; + configHash?: string +} + +export const MODAL_POSITIONS_KEY = 'modal_positions'; class PersistentChunkStore implements ChunkStore { private diagnosticUpdater?: DiagnosticUpdater; - private doc: Doc; - private chunkMap: Map; - private db: IndexeddbPersistence; - - constructor(config: { account: EthAddress; contractAddress: string }) { - this.doc = new Doc(); - this.chunkMap = this.doc.getMap('chunks'); + private db: IDBPDatabase; + private queuedChunkWrites: DBTx[]; + private throttledSaveChunkCacheToDisk: DebouncedFunc<() => Promise>; + private nUpdatesLastTwoMins = 0; // we save every 5s, unless this goes above 50 + private chunkMap: Map; + private confirmedTxHashes: Set; + private account: EthAddress; + private contractAddress: EthAddress; + private configHash?: string; - this.db = new IndexeddbPersistence( - `darkforest-${config.contractAddress}-${config.account}-chunks`, - this.doc + constructor({ db, account, contractAddress, configHash }: PersistentChunkStoreConfig) { + this.db = db; + this.queuedChunkWrites = []; + this.confirmedTxHashes = new Set(); + this.throttledSaveChunkCacheToDisk = _.throttle( + this.persistQueuedChunks, + 2000 // TODO ); + this.chunkMap = new Map(); + this.account = account; + this.contractAddress = contractAddress; + this.configHash = configHash; } destroy(): void { - this.doc.destroy(); + // no-op; we don't actually destroy the instance, we leave the db connection open in case we need it in the future + } + + /** + * NOTE! if you're creating a new object store, it will not be *added* to existing dark forest + * accounts. This creation code runs once per account. Therefore, if you're adding a new object + * store, and need to test it out, you must either clear the indexed db databse for this account, + * or create a brand new account. + */ + static async create({ + account, + contractAddress, + configHash + }: Omit): Promise { + console.log('chunk config hash', configHash); + const dbString = configHash ? `darkforest-${configHash}-${account}` : `darkforest-${contractAddress}-${account}`; + const db = await openDB(dbString, 1, { + upgrade(db) { + db.createObjectStore(ObjectStore.DEFAULT); + db.createObjectStore(ObjectStore.BOARD); + db.createObjectStore(ObjectStore.UNCONFIRMED_ETH_TXS); + db.createObjectStore(ObjectStore.PLUGINS); + db.createObjectStore(ObjectStore.MODAL_POS); + }, + }); + + const localStorageManager = new PersistentChunkStore({ db, account, contractAddress, configHash }); + + await localStorageManager.loadChunks(); + + return localStorageManager; } public setDiagnosticUpdater(diagnosticUpdater?: DiagnosticUpdater) { @@ -34,10 +129,182 @@ class PersistentChunkStore implements ChunkStore { } /** - * A function to await if you need to be sure all chunks have been loaded from indexeddb + * Important! This sets the key in indexed db per account and per contract. This means the same + * client can connect to multiple different dark forest contracts, with multiple different + * accounts, and the persistent storage will not overwrite data that is not relevant for the + * current configuration of the client. */ - async chunksLoaded(): Promise { - await this.db.whenSynced; + private async getKey( + key: string, + objStore: ObjectStore = ObjectStore.DEFAULT + ): Promise { + const dbStr = this.configHash ? `${this.configHash}-${this.account}-${key}` : `${this.contractAddress}-${this.account}-${key}` + return await this.db.get(objStore, dbStr); + } + + /** + * Important! This sets the key in indexed db per account and per contract. This means the same + * client can connect to multiple different dark forest contracts, with multiple different + * accounts, and the persistent storage will not overwrite data that is not relevant for the + * current configuration of the client. + */ + private async setKey( + key: string, + value: string, + objStore: ObjectStore = ObjectStore.DEFAULT, + ): Promise { + const dbStr = this.configHash ? `${this.configHash}-${this.account}-${key}` : `${this.contractAddress}-${this.account}-${key}` + await this.db.put(objStore, value, dbStr); + } + + private async removeKey(key: string, objStore: ObjectStore = ObjectStore.DEFAULT): Promise { + const dbStr = this.configHash ? `${this.configHash}-${this.account}-${key}` : `${this.contractAddress}-${this.account}-${key}` + await this.db.delete(objStore, dbStr); + } + + private async bulkSetKeyInCollection( + updateChunkTxs: DBTx[], + collection: ObjectStore + ): Promise { + const tx = this.db.transaction(collection, 'readwrite'); + updateChunkTxs.forEach((updateChunkTx) => { + updateChunkTx.forEach(({ type, dbKey: key, dbValue: value }) => { + if (type === DBActionType.UPDATE) { + tx.store.put(toPersistedChunk(value as Chunk), key); + } else if (type === DBActionType.DELETE) { + tx.store.delete(key); + } + }); + }); + await tx.done; + } + + /** + * This function loads all chunks persisted in the user's storage into the game. + */ + private async loadChunks(): Promise { + // we can't bulk get all chunks, since idb will crash/hang + // we also can't assign random non-primary keys and query on ranges + // so we append a random alphanumeric character to the front of keys + // and then bulk query for keys starting with 0, then 1, then 2, etc. + // see the `getBucket` function in `ChunkUtils.ts` for more information. + const borders = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ~'; + let chunkCount = 0; + + for (let idx = 0; idx < borders.length - 1; idx += 1) { + const bucketOfChunks = await this.db.getAll( + ObjectStore.BOARD, + IDBKeyRange.bound(borders[idx], borders[idx + 1], false, true) + ); + + bucketOfChunks.forEach((chunk: PersistedChunk) => { + this.addChunk(toExploredChunk(chunk), false); + }); + + chunkCount += bucketOfChunks.length; + } + + console.log(`loaded ${chunkCount} chunks from local storage`); + } + + /** + * Rather than saving a chunk immediately after it's mined, we queue up new chunks, and + * periodically save them. This function gets all of the queued new chunks, and persists them to + * indexed db. + */ + private async persistQueuedChunks() { + const toSave = [...this.queuedChunkWrites]; // make a copy + this.queuedChunkWrites = []; + this.diagnosticUpdater && + this.diagnosticUpdater.updateDiagnostics((d) => { + d.chunkUpdates = 0; + }); + await this.bulkSetKeyInCollection(toSave, ObjectStore.BOARD); + } + + /** + * we keep a list rather than a single location, since client/contract can + * often go out of sync on initialization - if client thinks that init + * failed but is wrong, it will prompt user to initialize with new home coords, + * which bricks the user's account. + */ + public async getHomeLocations(): Promise { + const homeLocations = await this.getKey('homeLocations'); + let parsed: WorldLocation[] = []; + if (homeLocations) { + parsed = JSON.parse(homeLocations) as WorldLocation[]; + } + + return parsed; + } + + public async addHomeLocation(location: WorldLocation): Promise { + let locationList = await this.getHomeLocations(); + if (locationList) { + locationList.push(location); + } else { + locationList = [location]; + } + locationList = Array.from(new Set(locationList)); + await this.setKey('homeLocations', stringify(locationList)); + } + + public async confirmHomeLocation(location: WorldLocation): Promise { + await this.setKey('homeLocations', stringify([location])); + } + + public async getSavedTouchedPlanetIds(): Promise { + const touchedPlanetIds = await this.getKey('touchedPlanetIds'); + + if (touchedPlanetIds) { + const parsed = JSON.parse(touchedPlanetIds) as LocationId[]; + return parsed; + } + + return []; + } + + public async getSavedRevealedCoords(): Promise { + const revealedPlanetIds = await this.getKey('revealedPlanetIds'); + + if (revealedPlanetIds) { + const parsed = JSON.parse(revealedPlanetIds); + // changed the type on 6/1/21 to include revealer field + // eslint-disable-next-line @typescript-eslint/no-explicit-any + if (parsed.length === 0 || !(parsed[0] as any).revealer) { + return []; + } + return parsed as RevealedCoords[]; + } + + return []; + } + public async getSavedClaimedCoords(): Promise { + const claimedPlanetIds = await this.getKey('claimedPlanetIds'); + + if (claimedPlanetIds) { + const parsed = JSON.parse(claimedPlanetIds); + // changed the type on 6/1/21 to include revealer field + // eslint-disable-next-line @typescript-eslint/no-explicit-any + if (parsed.length === 0 || !(parsed[0] as any).revealer) { + return []; + } + return parsed as ClaimedCoords[]; + } + + return []; + } + + public async saveTouchedPlanetIds(ids: LocationId[]) { + await this.setKey('touchedPlanetIds', stringify(ids)); + } + + public async saveRevealedCoords(revealedCoordTups: RevealedCoords[]) { + await this.setKey('revealedPlanetIds', stringify(revealedCoordTups)); + } + + public async saveClaimedCoords(claimedCoordTupps: ClaimedCoords[]) { + await this.setKey('claimedPlanetIds', stringify(claimedCoordTupps)); } /** @@ -51,7 +318,7 @@ class PersistentChunkStore implements ChunkStore { while (sideLength <= MAX_CHUNK_SIZE) { const testChunkLoc = getChunkOfSideLengthContainingPoint(chunkLoc.bottomLeft, sideLength); - const chunk = this.chunkMap.get(getChunkKey(testChunkLoc)); + const chunk = this.getChunkById(getChunkKey(testChunkLoc)); if (chunk) { return chunk; } @@ -65,6 +332,10 @@ class PersistentChunkStore implements ChunkStore { return !!this.getChunkByFootprint(chunkLoc); } + private getChunkById(chunkId: ChunkId): Chunk | undefined { + return this.chunkMap.get(chunkId); + } + /** * When a chunk is mined, or a chunk is imported via map import, or a chunk is loaded from * persistent storage for the first time, we need to add this chunk to the game. This function @@ -72,31 +343,175 @@ class PersistentChunkStore implements ChunkStore { * might not want to persist the chunk is if you are sure that you got it from persistent storage. * i.e. it already exists in persistent storage. */ - public addChunk(chunk: Chunk): void { + public addChunk(chunk: Chunk, persistChunk = true): void { if (this.hasMinedChunk(chunk.chunkFootprint)) { return; } - this.doc.transact(() => { - processChunkInMap(this.chunkMap, chunk, this.onAdd, this.onRemove, MAX_CHUNK_SIZE); - }); + const tx: DBAction[] = []; + + if (persistChunk) { + const minedSubChunks = this.getMinedSubChunks(chunk); + for (const subChunk of minedSubChunks) { + tx.push({ + type: DBActionType.DELETE, + dbKey: getChunkKey(subChunk.chunkFootprint), + }); + } + } + + addToChunkMap( + this.chunkMap, + chunk, + (chunk) => { + tx.push({ + type: DBActionType.UPDATE, + dbKey: getChunkKey(chunk.chunkFootprint), + dbValue: chunk, + }); + }, + (chunk) => { + tx.push({ + type: DBActionType.DELETE, + dbKey: getChunkKey(chunk.chunkFootprint), + }); + }, + MAX_CHUNK_SIZE + ); + + // modify in-memory store + for (const action of tx) { + if (action.type === DBActionType.UPDATE && action.dbValue) { + this.chunkMap.set(action.dbKey, action.dbValue); + } else if (action.type === DBActionType.DELETE) { + this.chunkMap.delete(action.dbKey); + } + } this.diagnosticUpdater?.updateDiagnostics((d) => { d.totalChunks = this.chunkMap.size; }); + + // can stop here, if we're just loading into in-memory store from storage + if (!persistChunk) { + return; + } + + this.queuedChunkWrites.push(tx); + + this.diagnosticUpdater && + this.diagnosticUpdater.updateDiagnostics((d) => { + d.chunkUpdates = this.queuedChunkWrites.length; + }); + + // save chunks every 5s if we're just starting up, or 30s once we're moving + this.recomputeSaveThrottleAfterUpdate(); + this.throttledSaveChunkCacheToDisk(); } - private onAdd = (chunk: Chunk) => { - this.chunkMap.set(getChunkKey(chunk.chunkFootprint), chunk); - }; + /** + * Returns all the mined chunks with smaller sidelength strictly contained in the chunk. + * + * TODO: move this into ChunkUtils, and also make use of it, the way that it is currently used, in + * the function named `addToChunkMap`. + */ + private getMinedSubChunks(chunk: Chunk): Chunk[] { + const ret: Chunk[] = []; + for ( + let clearingSideLen = 16; + clearingSideLen < chunk.chunkFootprint.sideLength; + clearingSideLen *= 2 + ) { + for (let x = 0; x < chunk.chunkFootprint.sideLength; x += clearingSideLen) { + for (let y = 0; y < chunk.chunkFootprint.sideLength; y += clearingSideLen) { + const queryChunk: Rectangle = { + bottomLeft: { + x: chunk.chunkFootprint.bottomLeft.x + x, + y: chunk.chunkFootprint.bottomLeft.y + y, + }, + sideLength: clearingSideLen, + }; + const queryChunkKey = getChunkKey(queryChunk); + const exploredChunk = this.getChunkById(queryChunkKey); + if (exploredChunk) { + ret.push(exploredChunk); + } + } + } + } + return ret; + } - private onRemove = (chunk: Chunk) => { - this.chunkMap.delete(getChunkKey(chunk.chunkFootprint)); - }; + private recomputeSaveThrottleAfterUpdate() { + this.nUpdatesLastTwoMins += 1; + if (this.nUpdatesLastTwoMins === 50) { + this.throttledSaveChunkCacheToDisk.cancel(); + this.throttledSaveChunkCacheToDisk = _.throttle(this.persistQueuedChunks, 30000); + } + setTimeout(() => { + this.nUpdatesLastTwoMins -= 1; + if (this.nUpdatesLastTwoMins === 49) { + this.throttledSaveChunkCacheToDisk.cancel(); + this.throttledSaveChunkCacheToDisk = _.throttle(this.persistQueuedChunks, 5000); + } + }, 120000); + } public allChunks(): Iterable { return this.chunkMap.values(); } + + /** + * Whenever a transaction is submitted, it is persisted. When the transaction either fails or + * succeeds, it is un-persisted. The reason we persist submitted transactions is to be able to + * wait for them upon a fresh start of the game if you close the game before a transaction + * confirms. + */ + public async onEthTxSubmit(tx: Transaction): Promise { + // in case the tx was mined and saved already + if (!tx.hash || this.confirmedTxHashes.has(tx.hash)) return; + const ser: PersistedTransaction = { hash: tx.hash, intent: tx.intent }; + await this.db.put(ObjectStore.UNCONFIRMED_ETH_TXS, JSON.parse(JSON.stringify(ser)), tx.hash); + } + + /** + * Partner function to {@link PersistentChunkStore#onEthTxSubmit} + */ + public async onEthTxComplete(txHash: string): Promise { + this.confirmedTxHashes.add(txHash); + await this.db.delete(ObjectStore.UNCONFIRMED_ETH_TXS, txHash); + } + + public async getUnconfirmedSubmittedEthTxs(): Promise { + const ret: PersistedTransaction[] = await this.db.getAll(ObjectStore.UNCONFIRMED_ETH_TXS); + return ret; + } + + public async loadPlugins(): Promise { + const savedPlugins = await this.getKey('plugins', ObjectStore.PLUGINS); + + if (!savedPlugins) { + return []; + } + + return JSON.parse(savedPlugins) as SerializedPlugin[]; + } + + public async savePlugins(plugins: SerializedPlugin[]): Promise { + await this.setKey('plugins', JSON.stringify(plugins), ObjectStore.PLUGINS); + } + + public async saveModalPositions(modalPositions: Map): Promise { + if (!this.db.objectStoreNames.contains(ObjectStore.MODAL_POS)) return; + const serialized = JSON.stringify(Array.from(modalPositions.entries())); + await this.setKey(MODAL_POSITIONS_KEY, serialized, ObjectStore.MODAL_POS); + } + + public async loadModalPositions(): Promise> { + if (!this.db.objectStoreNames.contains(ObjectStore.MODAL_POS)) return new Map(); + const winPos = await this.getKey(MODAL_POSITIONS_KEY, ObjectStore.MODAL_POS); + return new Map(winPos ? JSON.parse(winPos) : null); + } } export default PersistentChunkStore; diff --git a/client/src/Backend/Storage/ReaderDataStore.ts b/client/src/Backend/Storage/ReaderDataStore.ts index ef7690f0..c4339af9 100644 --- a/client/src/Backend/Storage/ReaderDataStore.ts +++ b/client/src/Backend/Storage/ReaderDataStore.ts @@ -1,6 +1,7 @@ -import { isLocatable } from '@dfdao/gamelogic'; -import { EthConnection } from '@dfdao/network'; +import { isLocatable } from '@darkforest_eth/gamelogic'; +import { EthConnection } from '@darkforest_eth/network'; import { + ArtifactId, Biome, EthAddress, LocatablePlanet, @@ -8,7 +9,7 @@ import { Planet, SpaceType, WorldLocation, -} from '@dfdao/types'; +} from '@darkforest_eth/types'; import { ContractConstants } from '../../_types/darkforest/api/ContractsAPITypes'; import { AddressTwitterMap } from '../../_types/darkforest/api/UtilityServerAPITypes'; import { arrive, updatePlanetToTime } from '../GameLogic/ArrivalUtils'; @@ -74,7 +75,7 @@ class ReaderDataStore { const addressTwitterMap = await getAllTwitters(); const contractConstants = await contractsAPI.getConstants(); const persistentChunkStore = - viewer && new PersistentChunkStore({ account: viewer, contractAddress }); + viewer && (await PersistentChunkStore.create({ account: viewer, contractAddress })); const singlePlanetStore = new ReaderDataStore({ contractAddress, @@ -98,7 +99,7 @@ class ReaderDataStore { } } - private async setPlanetLocationIfKnown(planet: Planet): Promise { + private setPlanetLocationIfKnown(planet: Planet): void { let planetLocation = undefined; if (planet && isLocatable(planet)) { @@ -110,7 +111,6 @@ class ReaderDataStore { } if (this.persistentChunkStore) { - await this.persistentChunkStore.chunksLoaded(); for (const chunk of this.persistentChunkStore.allChunks()) { for (const loc of chunk.planetLocations) { if (loc.hash === planet.locationId) { @@ -143,15 +143,25 @@ class ReaderDataStore { for (const arrival of arrivals) { if (nowInSeconds < arrival.arrivalTime) break; - arrive(planet, arrival, contractConstants); + arrive(planet, [], arrival, undefined, contractConstants, undefined, undefined); } - updatePlanetToTime(planet, Date.now(), contractConstants); - await this.setPlanetLocationIfKnown(planet); + updatePlanetToTime(planet, [], Date.now(), contractConstants); + this.setPlanetLocationIfKnown(planet); return planet; } + public async loadArtifactFromContract(artifactId: ArtifactId) { + const artifact = await this.contractsAPI.getArtifactById(artifactId); + + if (!artifact) { + throw new Error(`unable to load artifact with id ${artifactId}`); + } + + return artifact; + } + // copied from GameEntityMemoryStore. needed to determine biome if we know planet location private spaceTypeFromPerlin(perlin: number): SpaceType { if (perlin < this.contractConstants.PERLIN_THRESHOLD_1) { diff --git a/client/src/Backend/Utils/Animation.ts b/client/src/Backend/Utils/Animation.ts index 2562450a..72d1e98e 100644 --- a/client/src/Backend/Utils/Animation.ts +++ b/client/src/Backend/Utils/Animation.ts @@ -1,4 +1,4 @@ -import { DFAnimation, DFStatefulAnimation, PlanetLevel } from '@dfdao/types'; +import { DFAnimation, DFStatefulAnimation, PlanetLevel } from '@darkforest_eth/types'; import anime from 'animejs'; export function sinusoidalAnimation(rps: number): DFAnimation { diff --git a/client/src/Backend/Utils/Coordinates.ts b/client/src/Backend/Utils/Coordinates.ts index 2d1e5d99..c726e06c 100644 --- a/client/src/Backend/Utils/Coordinates.ts +++ b/client/src/Backend/Utils/Coordinates.ts @@ -1,4 +1,4 @@ -import { CanvasCoords, WorldCoords } from '@dfdao/types'; +import { CanvasCoords, WorldCoords } from '@darkforest_eth/types'; export const coordsEqual = (a: WorldCoords, b: WorldCoords): boolean => a.x === b.x && a.y === b.y; diff --git a/client/src/Backend/Utils/Populate.ts b/client/src/Backend/Utils/Populate.ts new file mode 100644 index 00000000..c242bf17 --- /dev/null +++ b/client/src/Backend/Utils/Populate.ts @@ -0,0 +1,89 @@ +// + +import { ArenaCreationManager } from '../GameLogic/ArenaCreationManager'; +import { stockConfig } from '../../Frontend/Utils/StockConfigs'; +import { EthConnection } from '@darkforest_eth/network'; +import { EthAddress, UnconfirmedInit } from '@darkforest_eth/types'; +import { HashConfig } from '../../_types/global/GlobalTypes'; +import SnarkArgsHelper from './SnarkArgsHelper'; +import { TerminalHandle } from '../../Frontend/Views/Terminal'; +import { useRef } from 'react'; +import { DarkForest } from '@darkforest_eth/contracts/typechain'; +import { loadDiamondContract } from '../Network/Blockchain'; +import { LobbyInitializers } from '../../Frontend/Panes/Lobby/Reducer'; + +export async function populateBulk( + ethConnection: EthConnection, + contractAddress: EthAddress, + numTimes = 1 +): Promise { + const arr = new Array(numTimes) + for (let a of arr) { + await populate(ethConnection, contractAddress); + } +} +export async function populate( + ethConnection: EthConnection, + contractAddress: EthAddress, +): Promise { + + const initConfig = (Math.random() > 0.5 ) ? stockConfig.devOnePlayerRace : stockConfig.devOnePlayerRaceB; + const config = JSON.parse(JSON.stringify(initConfig)) as LobbyInitializers; + + // 1. Create new arena Creation manager + const newCreationManager = await ArenaCreationManager.create(ethConnection, contractAddress); + + // 2. Fetch home planet. + console.log(`ADMIN Planets`, config.ADMIN_PLANETS); + const homePlanet = config.ADMIN_PLANETS.filter((p) => p.isSpawnPlanet)[0]; + const initHomePlanet = newCreationManager.lobbyPlanetToInitPlanet(homePlanet, config); + + // 3. Create and Init Arena + const { owner, lobby } = await newCreationManager.createAndInitArena(config); + + console.log('Created lobby at', lobby); + + const contract = await ethConnection.loadContract(lobby, loadDiamondContract); + + // 4. Add Admin Planets + await newCreationManager.bulkCreateInitPlanets({ config }); + + // 5. Make init Snark Args + const hashConfig: HashConfig = { + planetHashKey: config.PLANETHASH_KEY, + spaceTypeKey: config.SPACETYPE_KEY, + biomebaseKey: config.BIOMEBASE_KEY, + perlinLengthScale: config.PERLIN_LENGTH_SCALE, + perlinMirrorX: config.PERLIN_MIRROR_X, + perlinMirrorY: config.PERLIN_MIRROR_Y, + planetRarity: config.PLANET_RARITY, + planetLevelThresholds: config.PLANET_LEVEL_THRESHOLDS, + }; + + const useMockHash = config.DISABLE_ZK_CHECKS; + + // @ts-expect-error + const snarkHelper = SnarkArgsHelper.create(hashConfig, undefined, useMockHash); + const getArgs = async () => { + const args = await snarkHelper.getInitArgs( + homePlanet.x, + homePlanet.y, + Math.floor(Math.sqrt(homePlanet.x ** 2 + homePlanet.y ** 2)) + 1 // floor(sqrt(x^2 + y^2)) + 1 + ); + return args; + }; + + const args = await getArgs(); + + const configHash = newCreationManager.getArenaConfigHash(); + console.log('Config hash:', configHash); + + const initTx = await contract.initializePlayer(...args, 0); + const initRct = await initTx.wait(); + console.log(`initialized player`); + + const claimTx = await contract.claimVictory(); + const claimRct = await claimTx.wait(); + + console.log(`gameOver?`, await contract.getGameover()); +} diff --git a/client/src/Backend/Utils/Rank.ts b/client/src/Backend/Utils/Rank.ts new file mode 100644 index 00000000..563cb606 --- /dev/null +++ b/client/src/Backend/Utils/Rank.ts @@ -0,0 +1,16 @@ +import { goldTime, silverTime, bronzeTime } from '../../Frontend/Utils/constants'; + + +export enum Rank { + GOLD, + SILVER, + BRONZE, + NONE, +} + +export function getRank(time: number): Rank { + if (time <= goldTime) return Rank.GOLD; + else if (time <= silverTime) return Rank.SILVER; + else if (time <= bronzeTime) return Rank.BRONZE; + else return Rank.NONE; +} diff --git a/client/src/Backend/Utils/SnarkArgsHelper.ts b/client/src/Backend/Utils/SnarkArgsHelper.ts index 0382a58c..b83a135d 100644 --- a/client/src/Backend/Utils/SnarkArgsHelper.ts +++ b/client/src/Backend/Utils/SnarkArgsHelper.ts @@ -1,4 +1,4 @@ -import { fakeHash, mimcHash, modPBigInt, modPBigIntNative, perlin } from '@dfdao/hashing'; +import { fakeHash, mimcHash, modPBigInt, modPBigIntNative, perlin } from '@darkforest_eth/hashing'; import { BiomebaseSnarkContractCallArgs, BiomebaseSnarkInput, @@ -11,16 +11,16 @@ import { RevealSnarkContractCallArgs, RevealSnarkInput, SnarkJSProofAndSignals, -} from '@dfdao/snarks'; -import biomebaseCircuitPath from '@dfdao/snarks/biomebase.wasm?url'; -import biomebaseZkeyPath from '@dfdao/snarks/biomebase.zkey?url'; -import initCircuitPath from '@dfdao/snarks/init.wasm?url'; -import initZkeyPath from '@dfdao/snarks/init.zkey?url'; -import moveCircuitPath from '@dfdao/snarks/move.wasm?url'; -import moveZkeyPath from '@dfdao/snarks/move.zkey?url'; -import revealCircuitPath from '@dfdao/snarks/reveal.wasm?url'; -import revealZkeyPath from '@dfdao/snarks/reveal.zkey?url'; -import { PerlinConfig } from '@dfdao/types'; +} from '@darkforest_eth/snarks'; +import biomebaseCircuitPath from '@darkforest_eth/snarks/biomebase.wasm'; +import biomebaseZkeyPath from '@darkforest_eth/snarks/biomebase.zkey'; +import initCircuitPath from '@darkforest_eth/snarks/init.wasm'; +import initZkeyPath from '@darkforest_eth/snarks/init.zkey'; +import moveCircuitPath from '@darkforest_eth/snarks/move.wasm'; +import moveZkeyPath from '@darkforest_eth/snarks/move.zkey'; +import revealCircuitPath from '@darkforest_eth/snarks/reveal.wasm'; +import revealZkeyPath from '@darkforest_eth/snarks/reveal.zkey'; +import { PerlinConfig } from '@darkforest_eth/types'; import * as bigInt from 'big-integer'; import { BigInteger } from 'big-integer'; import FastQueue from 'fastq'; @@ -197,7 +197,7 @@ class SnarkArgsHelper { async getInitArgs(x: number, y: number, r: number): Promise { try { const start = Date.now(); - this.terminal.current?.println('INIT: calculating witness and proof', TerminalTextStyle.Sub); + this.terminal?.current?.println('INIT: calculating witness and proof', TerminalTextStyle.Sub); const input: InitSnarkInput = { x: modPBigInt(x).toString(), y: modPBigInt(y).toString(), @@ -214,7 +214,7 @@ class SnarkArgsHelper { : await this.snarkProverQueue.doProof(input, initCircuitPath, initZkeyPath); const ret = buildContractCallArgs(proof, publicSignals) as InitSnarkContractCallArgs; const end = Date.now(); - this.terminal.current?.println( + this.terminal?.current?.println( `INIT: calculated witness and proof in ${end - start}ms`, TerminalTextStyle.Sub ); diff --git a/client/src/Backend/Utils/Utils.ts b/client/src/Backend/Utils/Utils.ts index 7d9d5d93..dc3995a6 100644 --- a/client/src/Backend/Utils/Utils.ts +++ b/client/src/Backend/Utils/Utils.ts @@ -1,7 +1,22 @@ -import { formatNumber } from '@dfdao/gamelogic'; -import { EthAddress, Planet, SpaceType, Upgrade, UpgradeBranchName } from '@dfdao/types'; +import { formatNumber } from '@darkforest_eth/gamelogic'; +import { locationIdToDecStr } from '@darkforest_eth/serde'; +import { Initializers } from '@darkforest_eth/settings'; +import { + ArtifactRarity, + ArtifactType, + Biome, + EthAddress, + LocatablePlanet, + LocationId, + Planet, + SpaceType, + Upgrade, + UpgradeBranchName, +} from '@darkforest_eth/types'; import * as bigInt from 'big-integer'; import { BigInteger } from 'big-integer'; +import { BigNumber, ethers, utils } from 'ethers'; +import { roundEndTimestamp, roundStartTimestamp } from '../../Frontend/Utils/constants'; import { StatIdx } from '../../_types/global/GlobalTypes'; export const ONE_DAY = 24 * 60 * 60 * 1000; @@ -50,13 +65,13 @@ function hashToHue(hash: string): number { return baseHue; } -export const getPlayerColor: (player: EthAddress) => string = (player) => { - return hslStr(hashToHue(player.slice(2)), 100, 70); // remove 0x -}; +// export const getPlayerColor: (player: EthAddress) => string = (player) => { +// return hslStr(hashToHue(player.slice(2)), 100, 70); // remove 0x +// }; -export const getOwnerColor: (planet: Planet) => string = (planet) => { - return planet.owner ? getPlayerColor(planet.owner) : 'hsl(0,1%,50%)'; -}; +// export const getOwnerColor: (planet: Planet) => string = (planet) => { +// return planet.owner ? getPlayerColor(planet.owner) : 'hsl(0,1%,50%)'; +// }; export const getRandomActionId = () => { const hex = '0123456789abcdef'; @@ -119,3 +134,90 @@ export const titleCase = (title: string): string => return `${word.substring(0, 1).toUpperCase()}${word.substring(1)}`; }) .join(' '); + +export const isRoundOngoing = (): boolean => { + const roundStart = new Date(roundStartTimestamp).getTime(); + + const roundEnd = new Date(roundEndTimestamp).getTime(); + const now = Date.now(); + return now > roundStart && now < roundEnd; +}; + +function artifactRarityFromPlanetLevel(planetLevel: number): ArtifactRarity { + if (planetLevel <= 1) return ArtifactRarity.Common; + else if (planetLevel <= 3) return ArtifactRarity.Rare; + else if (planetLevel <= 5) return ArtifactRarity.Epic; + else if (planetLevel <= 7) return ArtifactRarity.Legendary; + else return ArtifactRarity.Mythic; +} + + +export function getDeterministicArtifact(planet: LocatablePlanet) { + + const abiCoder = ethers.utils.defaultAbiCoder; + + const artifactSeed = ethers.utils.keccak256( + abiCoder.encode(['uint'], [BigInt('0x'+planet.locationId)]) + ); + + const seedHash = ethers.utils.keccak256(abiCoder.encode(['uint'], [BigInt(artifactSeed)])); + + const seed = BigNumber.from(artifactSeed); + const lastByteOfSeed = seed.mod(BigNumber.from('0xff')).toNumber(); + const bigLastByte = BigNumber.from(lastByteOfSeed); + + const secondLastByteOfSeed = ((seed.sub(bigLastByte)).div(BigNumber.from(256))).mod(BigNumber.from('0xff')).toNumber(); + + const perlin = planet.perlin; + const biome = planet.biome; + + let artifactType: ArtifactType = ArtifactType.Pyramid; + + if (lastByteOfSeed < 39) { + artifactType = ArtifactType.Monolith; + } else if (lastByteOfSeed < 78) { + artifactType = ArtifactType.Colossus; + } + // else if (lastByteOfSeed < 117) { + // artifactType = ArtifactType.Spaceship; + // } + else if (lastByteOfSeed < 156) { + artifactType = ArtifactType.Pyramid; + } else if (lastByteOfSeed < 171) { + artifactType = ArtifactType.Wormhole; + } else if (lastByteOfSeed < 186) { + artifactType = ArtifactType.PlanetaryShield; + } else if (lastByteOfSeed < 201) { + artifactType = ArtifactType.PhotoidCannon; + } else if (lastByteOfSeed < 216) { + artifactType = ArtifactType.BloomFilter; + } else if (lastByteOfSeed < 231) { + artifactType = ArtifactType.BlackDomain; + } else { + if (biome === Biome.ICE) { + artifactType = ArtifactType.PlanetaryShield; + } else if (biome === Biome.LAVA) { + artifactType = ArtifactType.PhotoidCannon; + } else if (biome === Biome.WASTELAND) { + artifactType = ArtifactType.BloomFilter; + } else if (biome === Biome.CORRUPTED) { + artifactType = ArtifactType.BlackDomain; + } else { + artifactType = ArtifactType.Wormhole; + } + artifactType = ArtifactType.PhotoidCannon; + } + + let bonus = 0; + if (secondLastByteOfSeed < 4) { + bonus = 2; + } else if (secondLastByteOfSeed < 16) { + bonus = 1; + } + + const rarity = artifactRarityFromPlanetLevel(planet.planetLevel + bonus); + + // console.log('artifactType', artifactType, 'rarity', rarity); + + return { type: artifactType, rarity }; +} \ No newline at end of file diff --git a/client/src/Backend/Utils/WhitelistSnarkArgsHelper.ts b/client/src/Backend/Utils/WhitelistSnarkArgsHelper.ts index 42a45db8..01148e1e 100644 --- a/client/src/Backend/Utils/WhitelistSnarkArgsHelper.ts +++ b/client/src/Backend/Utils/WhitelistSnarkArgsHelper.ts @@ -3,10 +3,10 @@ import { SnarkJSProofAndSignals, WhitelistSnarkContractCallArgs, WhitelistSnarkInput, -} from '@dfdao/snarks'; -import whitelistCircuitPath from '@dfdao/snarks/whitelist.wasm?url'; -import whitelistZkeyPath from '@dfdao/snarks/whitelist.zkey?url'; -import { EthAddress } from '@dfdao/types'; +} from '@darkforest_eth/snarks'; +import whitelistCircuitPath from '@darkforest_eth/snarks/whitelist.wasm'; +import whitelistZkeyPath from '@darkforest_eth/snarks/whitelist.zkey'; +import { EthAddress } from '@darkforest_eth/types'; import bigInt, { BigInteger } from 'big-integer'; import { TerminalTextStyle } from '../../Frontend/Utils/TerminalTypes'; import { TerminalHandle } from '../../Frontend/Views/Terminal'; diff --git a/client/src/Frontend/Panes/Lobbies/minimap.worker.ts b/client/src/Backend/Utils/minimap.worker.ts similarity index 55% rename from client/src/Frontend/Panes/Lobbies/minimap.worker.ts rename to client/src/Backend/Utils/minimap.worker.ts index 5ed4b2b4..04457162 100644 --- a/client/src/Frontend/Panes/Lobbies/minimap.worker.ts +++ b/client/src/Backend/Utils/minimap.worker.ts @@ -1,6 +1,6 @@ -import { perlin } from '@dfdao/hashing'; -import { SpaceType, WorldCoords } from '@dfdao/types'; -import { DrawMessage, MinimapConfig } from './MinimapUtils'; +import { perlin } from "@darkforest_eth/hashing"; +import { SpaceType, WorldCoords } from "@darkforest_eth/types"; +import { DrawMessage, MinimapConfig, PlanetType } from "../../Frontend/Panes/Lobby/MinimapUtils"; const ctx = self as unknown as Worker; @@ -24,7 +24,7 @@ function spaceTypeFromPerlin(perlin: number, config: MinimapConfig): SpaceType { // https://github.com/darkforest-eth/plugins/blob/358a386356b9145005f17045d9f4ce22661d99a1/content/utilities/mini-map/plugin.js function generate(config: MinimapConfig): DrawMessage { const data = []; - const step = config.worldRadius / 25; + const step = config.worldRadius * config.dot / 100; const radius = config.worldRadius; @@ -38,23 +38,39 @@ function generate(config: MinimapConfig): DrawMessage { return false; }; + const checkStagedPlanet = (x: number, y: number) : PlanetType => { + let s = Math.round(step / 2); + const stagedPlanet = config.stagedPlanets.find( + (planet) => x - s <= planet.x && planet.x < x + s && y - s <= planet.y && planet.y < y + s + ); + const createdPlanet = config.createdPlanets.find( + (planet) => x - s <= planet.x && planet.x < x + s && y - s <= planet.y && planet.y < y + s + ); + if (createdPlanet) return 'created' as PlanetType; + if (stagedPlanet?.isSpawnPlanet) return 'spawn' as PlanetType; + if (stagedPlanet?.isTargetPlanet) return 'target' as PlanetType; + if (stagedPlanet) return 'staged' as PlanetType; + return undefined; + }; // generate x coordinates for (let i = radius * -1; i < radius; i += step) { // generate y coordinates for (let j = radius * -1; j < radius; j += step) { // filter points within map circle - if (checkBounds(0, 0, i, j, radius)) { - // store coordinate and space type - data.push({ - x: i, - y: j, - type: spaceTypeFromPerlin(spaceTypePerlin({ x: i, y: j }, config), config), - }); + if (!checkBounds(0, 0, i, j, radius)) { + continue; } + // store coordinate and space type + data.push({ + x: i, + y: j, + type: spaceTypeFromPerlin(spaceTypePerlin({ x: i, y: j }, config), config), + planet: checkStagedPlanet(i, j) + }); } } - return { radius, data }; + return { radius, data, dot: config.dot }; } ctx.addEventListener('message', (e: MessageEvent) => { diff --git a/client/src/Frontend/Components/ArtifactImage.tsx b/client/src/Frontend/Components/ArtifactImage.tsx index 26b3be7f..d5cd9dc7 100644 --- a/client/src/Frontend/Components/ArtifactImage.tsx +++ b/client/src/Frontend/Components/ArtifactImage.tsx @@ -1,10 +1,11 @@ -import { ArtifactFileColor, artifactFileName } from '@dfdao/gamelogic'; -import { Artifact } from '@dfdao/types'; +import { ArtifactFileColor, artifactFileName, isSpaceShip } from '@darkforest_eth/gamelogic'; +import { Artifact } from '@darkforest_eth/types'; import React from 'react'; import styled, { css } from 'styled-components'; import dfstyles from '../Styles/dfstyles'; export const ARTIFACT_URL = 'https://d2wspbczt15cqu.cloudfront.net/v0.6.0-artifacts/'; +// const ARTIFACT_URL = '/public/img/artifacts/videos/'; function getArtifactUrl(thumb: boolean, artifact: Artifact, color: ArtifactFileColor): string { const fileName = artifactFileName(true, thumb, artifact, color); @@ -23,12 +24,17 @@ export function ArtifactImage({ bgColor?: ArtifactFileColor; }) { const url = getArtifactUrl(thumb || false, artifact, bgColor || ArtifactFileColor.BLUE); + const image = isSpaceShip(artifact.artifactType) ? ( + + ) : ( + + ); return ( - + {image} ); } diff --git a/client/src/Frontend/Components/Badges.tsx b/client/src/Frontend/Components/Badges.tsx new file mode 100644 index 00000000..96b82619 --- /dev/null +++ b/client/src/Frontend/Components/Badges.tsx @@ -0,0 +1,89 @@ +// should be able to be treated as a text element +import { BadgeType } from '@darkforest_eth/types'; +import { DarkForestBadge, getBadgeElement } from '@darkforest_eth/ui'; +import { createComponent } from '@lit-labs/react'; +import React from 'react'; +import styled from 'styled-components'; +import { theme } from '../Views/Portal/styleUtils'; + +// TODO: Decide if this is the best place to register the custom elements +customElements.define(DarkForestBadge.tagName, DarkForestBadge); + +// This wraps the customElement in a React wrapper to make it behave exactly like a React component +export const Badge = createComponent(React, DarkForestBadge.tagName, DarkForestBadge, { + // If we had any, we would map DOM events to React handlers passed in as props. For example: + // onClick: 'click' +}); + +export function BadgeDetailsRow({ type, count = 1 }: { type: BadgeType; count: number }) { + const badgeElement = getBadgeElement(type); + if (!badgeElement) return <>; + + return ( + + + + + {badgeElement.name} {count > 1 ? `(x${count})` : ''} + + {badgeElement.description} + + + ); +} + +export function BadgeDetailsCol({ type, count = 1 }: { type: BadgeType; count: number }) { + const badgeElement = getBadgeElement(type); + if (!badgeElement) return <>; + + return ( + + + + + {badgeElement.name} {count > 1 ? `(x${count})` : ''} + + {badgeElement.description} + + + ); +} + +export function SpacedBadges({ badges }: { badges: BadgeType[] }) { + return ( +
+ {badges.map((badge, idx) => ( + + ))} +
+ ); +} + +export function StackedBadges({}: {}) {} + +const BadgeDetailsContainer = styled.div<{ col?: boolean }>` + display: flex; + flex-direction: ${(props) => (props.col ? 'column' : 'row')}; + gap: 4px; + align-items: center; + background: ${theme.colors.bg1}; + border-radius: ${theme.borderRadius}; + padding: ${theme.spacing.md}; +`; + +const BadgeContent = styled.div` + display: flex; + flex-direction: column; + gap: ${theme.spacing.sm}; +`; + +const BadgeTitle = styled.span` + font-family: ${theme.fonts.mono}; + color: ${theme.colors.fgPrimary}; + text-transform: uppercase; + letter-spacing: 0.06em; +`; + +const BadgeDescription = styled.span` + color: ${theme.colors.fgMuted2}; +`; diff --git a/client/src/Frontend/Components/Btn.tsx b/client/src/Frontend/Components/Btn.tsx index 3de1a7ca..89a639f4 100644 --- a/client/src/Frontend/Components/Btn.tsx +++ b/client/src/Frontend/Components/Btn.tsx @@ -1,4 +1,8 @@ -import { DarkForestButton, DarkForestShortcutButton, ShortcutPressedEvent } from '@dfdao/ui'; +import { + DarkForestButton, + DarkForestShortcutButton, + ShortcutPressedEvent, +} from '@darkforest_eth/ui'; import { createComponent } from '@lit-labs/react'; import React from 'react'; diff --git a/client/src/Frontend/Components/CapturePlanetButton.tsx b/client/src/Frontend/Components/CapturePlanetButton.tsx index a3ca1535..4f42c0b2 100644 --- a/client/src/Frontend/Components/CapturePlanetButton.tsx +++ b/client/src/Frontend/Components/CapturePlanetButton.tsx @@ -1,11 +1,11 @@ -import { EMPTY_ADDRESS } from '@dfdao/constants'; -import { isUnconfirmedCapturePlanetTx, isUnconfirmedInvadePlanetTx } from '@dfdao/serde'; -import { Planet, TooltipName } from '@dfdao/types'; +import { EMPTY_ADDRESS } from '@darkforest_eth/constants'; +import { isUnconfirmedCapturePlanetTx, isUnconfirmedInvadePlanetTx } from '@darkforest_eth/serde'; +import { Planet, TooltipName } from '@darkforest_eth/types'; import React, { useCallback, useMemo } from 'react'; import styled from 'styled-components'; import { Wrapper } from '../../Backend/Utils/Wrapper'; import { TooltipTrigger } from '../Panes/Tooltip'; -import { useAccount, useUIManager } from '../Utils/AppHooks'; +import { useAddress, useUIManager } from '../Utils/AppHooks'; import { useEmitterValue } from '../Utils/EmitterHooks'; import { INVADE } from '../Utils/ShortcutConstants'; import { ShortcutBtn } from './Btn'; @@ -27,7 +27,7 @@ export function CapturePlanetButton({ planetWrapper: Wrapper; }) { const uiManager = useUIManager(); - const account = useAccount(uiManager); + const account = useAddress(uiManager); const gameManager = uiManager.getGameManager(); const currentBlockNumber = useEmitterValue(uiManager.getEthConnection().blockNumber$, undefined); const owned = planetWrapper.value?.owner === account; diff --git a/client/src/Frontend/Components/Copyable.tsx b/client/src/Frontend/Components/Copyable.tsx new file mode 100644 index 00000000..22affae5 --- /dev/null +++ b/client/src/Frontend/Components/Copyable.tsx @@ -0,0 +1,90 @@ +import React, { useState } from 'react'; +import styled from 'styled-components'; +import { theme } from '../Views/Portal/styleUtils'; + +const onCopy = ( + textToCopy: string, + onCopySuccess: () => void, + onCopyError: (msg: string) => void +) => { + if (!navigator.clipboard) { + onCopyError('Clipboard API not supported'); + return; + } + navigator.clipboard.writeText(textToCopy).then( + () => { + console.log('Async: Copying to clipboard was successful!'); + onCopySuccess(); + }, + (err) => { + console.error('Async: Could not copy text: ', err); + onCopyError("Couldn't copy to clipboard"); + } + ); +}; + +export const Copyable: React.FC<{ + textToCopy: string; + displayValue?: string; + onCopyError: (msg: string) => void; + children: React.ReactNode; +}> = ({ textToCopy, onCopyError, children }) => { + const [copied, setCopied] = useState(false); + const handleCopySuccess = () => { + setCopied(true); + }; + return ( + + {children} + onCopy(textToCopy, handleCopySuccess, onCopyError)}> + {copied ? : } + + + ); +}; + +const Container = styled.div` + display: flex; + align-items: center; + width: 100%; + gap: 8px; + cursor: pointer; +`; + +const CopyButton = styled.button` + display: flex; + align-items: center; + justify-content: center; + height: 24px; + width: 24px; + background: ${theme.colors.bg2}; + border-radius 4px; + color: ${theme.colors.fgMuted}; + transition: all .2s ease-in-out; + &:hover { + background: ${theme.colors.bg3}; + color: ${theme.colors.fgPrimary}; + } +`; + +const CopyIcon = () => ( + + + +); + +const CheckIcon = () => ( + + + +); diff --git a/client/src/Frontend/Components/CopyableInput.tsx b/client/src/Frontend/Components/CopyableInput.tsx new file mode 100644 index 00000000..c8a6aa6e --- /dev/null +++ b/client/src/Frontend/Components/CopyableInput.tsx @@ -0,0 +1,91 @@ +import React, { useState } from 'react'; +import styled from 'styled-components'; + +const onCopy = ( + textToCopy: string, + onCopySuccess: () => void, + onCopyError: (msg: string) => void +) => { + if (!navigator.clipboard) { + onCopyError('Clipboard API not supported'); + return; + } + navigator.clipboard.writeText(textToCopy).then( + () => { + console.log('Async: Copying to clipboard was successful!'); + onCopySuccess(); + }, + (err) => { + console.error('Async: Could not copy text: ', err); + onCopyError("Couldn't copy to clipboard"); + } + ); +}; + +export const CopyableInput: React.FC<{ + copyText: string; + displayValue?: string; + label?: string; + onCopyError: (msg: string) => void; +}> = ({ copyText, displayValue, label, onCopyError }) => { + const [copied, setCopied] = useState(false); + const handleCopySuccess = () => { + setCopied(true); + }; + return ( + + {label && {label}} + + {}}/> + onCopy(copyText, handleCopySuccess, onCopyError)}> + {copied ? '✓ Copied' : 'Copy'} + + + + ); +}; + +const Container = styled.div` + display: flex; + flex-direction: column; + width: 100%; + gap: 8px; +`; + +const InputContainer = styled.div` + position: relative; + display: flex; + width: 100%; + align-items: center; +`; + +const CopyButton = styled.button` + display: flex; + align-items: center; + justify-content; + position: absolute; + right: 8px; + height: calc(49px - 16px); + border-radius 4px; + background: #252525; + border: 1px solid #5F5F5F; + color: #bbb; + padding: 0 8px; + transition: .2s ease-in-out; + &:hover { + background: #3D3D3D; + } +`; + +const LabelText = styled.span` + color: rgba(255, 255, 255, 0.6); +`; + +const Input = styled.input` + flex: 1; + border: 1px solid #bbb; + padding: 16px 8px; + border-radius: 4px; + color: rgba(255, 255, 255, 1); + background: transparent; +`; diff --git a/client/src/Frontend/Components/CoreUI.tsx b/client/src/Frontend/Components/CoreUI.tsx index dd226f50..1baff038 100644 --- a/client/src/Frontend/Components/CoreUI.tsx +++ b/client/src/Frontend/Components/CoreUI.tsx @@ -89,6 +89,7 @@ export const HeaderText = styled.div` export const SectionHeader = styled(HeaderText)` margin-bottom: 16px; display: block; + text-decoration: none; `; export const Section = styled.div` @@ -147,6 +148,7 @@ export const AlignCenterHorizontally = styled.div` flex-direction: row; justify-content: center; align-items: center; + // margin-top: 7px; `; export const AlignCenterVertically = styled.div` @@ -321,6 +323,7 @@ export function SelectFrom({ labels, style, wide, + portal, }: { values: string[]; value: string; @@ -328,6 +331,7 @@ export function SelectFrom({ labels: string[]; style?: React.CSSProperties; wide?: boolean; + portal?: boolean; }) { const onChange = useCallback( (e: ChangeEvent) => { @@ -344,8 +348,10 @@ export function SelectFrom({ copyOfValues.push(value); } + const portalStyle = portal ? { background: dfstyles.colors.textLight, color: dfstyles.colors.backgrounddark} : {}; + return ( - {copyOfValues.map((value, i) => { return (