Changes to simoji.scroll.pub

Breck Yunits
Breck Yunits
9 months ago
Create CNAME
CNAME
Changed around line 1
+ simoji.treenotation.org
Breck Yunits
Breck Yunits
9 months ago
Update subdomain
cheatSheet.html
Changed around line 2
-
+
Changed around line 395: experiment
-

Simoji the language is a Tree Language. There are no visible syntax characters. Indentation is used for parent/child relationships. Here is the grammar.

+

Simoji the language is a Tree Language. There are no visible syntax characters. Indentation is used for parent/child relationships. Here is the grammar.

Changed around line 437: experiment
-

You can load any simulation from a publicly accessible URL by prefixing it with: https://simoji.pub/#url . For example: https://simoji.pub/#url%20https://simoji.pub/examples/eatTheBacon.simoji

+

You can load any simulation from a publicly accessible URL by prefixing it with: https://simoji.treenotation.org/#url . For example: https://simoji.treenotation.org/#url%20https://simoji.treenotation.org/examples/eatTheBacon.simoji

Changed around line 450: experiment
- getLinks()[1].click()
+ ].click()
cheatSheet.scroll
Changed around line 95: code
- https://jtree.treenotation.org/designer#url%20https%3A%2F%2Fsimoji.pub%2Fdist%2Fsimoji.grammar grammar
+ https://jtree.treenotation.org/designer#url%20https%3A%2F%2Fsimoji.treenotation.org%2Fdist%2Fsimoji.grammar grammar
Changed around line 115: pipeTable
- * You can load any simulation from a publicly accessible URL by prefixing it with: `https://simoji.pub/#url `. For example: https://simoji.pub/#url%20https://simoji.pub/examples/eatTheBacon.simoji
+ * You can load any simulation from a publicly accessible URL by prefixing it with: `https://simoji.treenotation.org/#url `. For example: https://simoji.treenotation.org/#url%20https://simoji.treenotation.org/examples/eatTheBacon.simoji
header.scroll
Changed around line 4: gazetteCss
- baseUrl https://simoji.pub/
+ baseUrl https://simoji.treenotation.org/
index.html
Changed around line 11
-
+
readme.html
Changed around line 2
-
+
Changed around line 365: h4.scrollQuestion {
- getLinks()[1].click()
+ ].click()
releaseNotes.html
Changed around line 2
-
+
Changed around line 327: h4.scrollQuestion {
- getLinks()[1].click()
+ ].click()
Breck Yunits
Breck Yunits
10 months ago
Delete CNAME
CNAME
Changed around line 0
- simoji.pub
Breck Yunits
Breck Yunits
1 year ago
Version 3 - new coordinate system (#8) * checkpoint * checkpoint * checkpoint * Code cleanup * checkpoint * Test cleanup * checkpoint * checkpoint * checkpoint * checkpoint * checkpoint * checkpoint * checkpoint * checkpoint * checkpoint * checkpoint * checkpoint * checkpoint * checkpoint * checkpoint * checkpoint * checkpoint * Turn off auto-snapshot * Drop agents in the center of click * update examples * Fill update * checkpoint * Collission fixes * Quad tree fixes * Fix draw * checkpoint * Switch to unit vectors * checkpoint * checkpoint * checkpoint * Remove game of life for now * Version 3 --------- Co-authored-by: Breck Yunits
.gitignore
Changed around line 3: node_modules
- .DS_Store
+ .DS_Store
+ package-lock.json
BrowserGlue.js
Changed around line 3: const { TreeNode } = require("jtree/products/TreeNode.js")
- const { Keywords, LocalStorageKeys, UrlKeys } = require("./components/Types.js")
+ const { LocalStorageKeys, UrlKeys } = require("./components/Types.js")
Changed around line 43: class BrowserGlue extends AbstractTreeComponentParser {
- const grammar = await fetch("simoji.grammar")
+ const grammar = await fetch("dist/simoji.grammar")
build.js
Changed around line 1
+ const path = require("path")
+ const { Server } = require("./server.js")
+
+ const distFolder = path.join(__dirname, "dist")
Changed around line 25: node_modules/jtree/products/stump.browser.js
- const libCode = libPaths.map(path => Disk.read(__dirname + "/" + path)).join("\n\n")
+ const libCode = libPaths.map(libPath => Disk.read(path.join(__dirname, libPath))).join("\n\n")
- Disk.write(__dirname + "/dist/libs.js", libCode)
+ Disk.write(path.join(distFolder, "simoji.grammar"), new Server().grammar)
+ Disk.write(path.join(distFolder, "libs.js"), libCode)
- const ourPaths = Disk.getFiles(__dirname + "/components").filter(path => !path.includes(".test"))
- ourPaths.unshift(__dirname + "/yodash.js")
- ourPaths.push(__dirname + "/BrowserGlue.js")
+ const ourPaths = Disk.getFiles(path.join(__dirname, "components")).filter(path => !path.includes(".test"))
+ ourPaths.unshift(path.join(__dirname, "yodash.js"))
+ ourPaths.push(path.join(__dirname, "BrowserGlue.js"))
Changed around line 46: const simCode = ourPaths
- Disk.write(__dirname + "/dist/simoji.js", simCode)
+ Disk.write(path.join(distFolder, "simoji.js"), simCode)
- grammar: Disk.read(__dirname + "/simoji.grammar"),
+ grammar: Disk.read(path.join(distFolder, "simoji.grammar")),
- Disk.write(__dirname + "/dist/constants.js", `const SimConstants = ` + JSON.stringify(SimConstants))
+ Disk.write(path.join(distFolder, "constants.js"), `const SimConstants = ` + JSON.stringify(SimConstants))
cheatSheet.scroll
Changed around line 45: code
- onTick
- onHit
- - onTouch
- onDeath
Changed around line 95: code
- https://jtree.treenotation.org/designer#url%20https%3A%2F%2Fsimoji.pub%2Fsimoji.grammar grammar
+ https://jtree.treenotation.org/designer#url%20https%3A%2F%2Fsimoji.pub%2Fdist%2Fsimoji.grammar grammar
components/Agent.js
Changed around line 1
- const { AbstractTreeComponentParser } = require("jtree/products/TreeComponentFramework.node.js")
- const { Keywords, Directions } = require("./Types.js")
+ const { Keywords } = require("./Types.js")
+ const classCache = {}
+ const getClassCache = (program, words) => {
+ const key = words.join(" ")
+ if (!classCache[key]) classCache[key] = yodash.flatten(yodash.pick(program, words))
+ return classCache[key]
+ }
+
- angle = Directions.South
+ _direction = { x: 0, y: 1 }
+
+ get direction() {
+ if (this.angle) {
+ const vectors = {
+ North: [0, -1],
+ East: [1, 0],
+ South: [0, 1],
+ West: [-1, 0],
+ Northeast: [Math.cos(Math.PI / 4), Math.sin((Math.PI * 3) / 4)],
+ Southeast: [Math.cos((Math.PI * 3) / 4), Math.sin(Math.PI / 4)],
+ Southwest: [-Math.cos((Math.PI * 3) / 4), Math.sin(Math.PI * (5 / 8))],
+ Northwest: [-Math.cos(Math.PI * (5 / 8)), Math.sin((Math.PI * -3) / 4)]
+ }
+ this._direction = vectors[this.angle]
+ this.angle = ""
+ }
+ return this._direction
+ }
+
+ set direction(newDirection) {
+ this._direction = newDirection
+ }
- return this.definitionWithBehaviors.findNodes(eventName)
+ return this.definitionWithClasses.findNodes(eventName)
- get definitionWithBehaviors() {
- if (!this.behaviors.length) return this.board.simojiProgram.getNode(this.firstWord)
- const behaviors = yodash.flatten(yodash.pick(this.board.simojiProgram, [this.firstWord, ...this.behaviors]))
- return behaviors
+ get definitionWithClasses() {
+ if (!this.classes.length) return this.board.simojiProgram.getNode(this.firstWord)
+ return getClassCache(this.board.simojiProgram, [this.firstWord, ...this.classes])
Changed around line 58: class Agent extends TreeNode {
- handleNeighbors() {
- if (!this.stillExists) return
- this.getCommandBlocks(Keywords.onNeighbors).forEach(neighborConditions => {
- if (this.skip(neighborConditions.getWord(1))) return
-
- const { neighorCount } = this
-
- neighborConditions.forEach(conditionAndCommandsBlock => {
- const [emoji, operator, count] = conditionAndCommandsBlock.words
- const actual = neighorCount[emoji]
- if (!yodash.compare(actual ?? 0, operator, count)) return
- conditionAndCommandsBlock.forEach(command => this._executeCommand(this, command))
-
- if (this.getIndex() === -1) return {}
- })
- })
- }
-
- handleTouches(agentPositionMap) {
- if (!this.stillExists) return
- this.getCommandBlocks(Keywords.onTouch).forEach(touchMap => {
- if (this.skip(touchMap.getWord(1))) return
-
- for (let pos of yodash.positionsAdjacentTo(this.position)) {
- const hits = agentPositionMap.get(yodash.makePositionHash(pos)) ?? []
- for (let target of hits) {
- const targetId = target.firstWord
- const commandBlock = touchMap.getNode(targetId)
- if (commandBlock) {
- commandBlock.forEach(command => this._executeCommand(target, command))
- if (this.getIndex() === -1) return
- }
- }
- }
- })
- }
-
- handleOverlaps(targets) {
- if (!this.stillExists) return
- this.getCommandBlocks(Keywords.onHit).forEach(hitMap => {
- if (this.skip(hitMap.getWord(1))) return
- targets.forEach(target => {
- const targetId = target.firstWord
- const commandBlock = hitMap.getNode(targetId)
- if (commandBlock) commandBlock.forEach(command => this._executeCommand(target, command))
- })
- })
- }
-
- get overlappingAgents() {
- return (this.board.agentPositionMap.get(this.positionHash) ?? []).filter(node => node !== this)
- }
-
Changed around line 85: class Agent extends TreeNode {
- get neighorCount() {
- const { agentPositionMap } = this.board
- const neighborCounts = {}
- yodash.positionsAdjacentTo(this.position).forEach(pos => {
- const agents = agentPositionMap.get(yodash.makePositionHash(pos)) ?? []
- agents.forEach(agent => {
- if (!neighborCounts[agent.name]) neighborCounts[agent.name] = 0
- neighborCounts[agent.name]++
- })
- })
- return neighborCounts
- }
-
Changed around line 94: class Agent extends TreeNode {
- this.parent.appendLine(`${newObject} ${this.positionHash}`)
-
+ this.parent.insertInbounds(newObject, this.x, this.y)
- const { angle } = this
- if (angle.includes(Directions.North)) this.moveNorth()
- else if (angle.includes(Directions.South)) this.moveSouth()
- if (angle.includes(Directions.East)) this.moveEast()
- else if (angle.includes(Directions.West)) this.moveWest()
+ const { direction, speed } = this
+
+ this.top = Math.max(this.top + direction.y * speed, 0)
+ this.left = Math.max(this.left + direction.x * speed, 0)
- node.position = { right: this.left, down: this.top }
+ node.setPosition({ x: this.x, y: this.y })
- moveSouth() {
- this.top++
+ speed = 1
+
+ get x() {
+ return this.left
- moveNorth() {
- this.top--
+ get y() {
+ return this.top
- moveWest() {
- this.left--
+ get w() {
+ return this.width
- moveEast() {
- this.left++
+ get h() {
+ return this.height
+ width = 10
+ height = 10
+
- return this.position.down
+ return this._y ?? this.position.y
- this.position = {
- down: value,
- right: this.left
- }
- }
-
- set position(value) {
- if (this.board.isSolidAgent(value)) return this.bouncy ? this.bounce() : this
- const newLine = this.getLine()
- .split(" ")
- .map(part => (part.includes("⬇️") ? value.down + "⬇️" : part.includes("➡️") ? value.right + "➡️" : part))
- .join(" ")
- return this.setLine(newLine)
+ this.setPosition({
+ y: value,
+ x: this.left
+ })
+ setPosition(newPosition) {
+ if (!this.board.canGoHere(newPosition.x, newPosition.y, this.width, this.height))
+ return this.bouncy ? this.bounce() : this
+
+ this._x = newPosition.x
+ this._y = newPosition.y
+ // Todo: do we need to update the string?
+ return this.setLine([this.firstWord, newPosition.x, newPosition.y].join(" "))
+ }
+
+ handleCollisions(targetAgents) {
+ if (!this.stillExists) return
+ this.getCommandBlocks(Keywords.onHit).forEach(hitMap => {
+ if (this.skip(hitMap.getWord(1))) return
+ targetAgents.forEach(targetAgent => {
+ const targetId = targetAgent.firstWord
+ const commandBlock = hitMap.getNode(targetId)
+ if (commandBlock) commandBlock.forEach(command => this._executeCommand(targetAgent, command))
+ })
+ })
+ }
+
+ get symbol() {
+ return this.firstWord
+ }
+
+ get collidingAgents() {
+ return this.board.objectsCollidingWith(this.x, this.y, this.width, this.height).filter(node => node !== this)
+ }
+
+ get neighorCount() {
+ return this.board.getNeighborCount(this)
+ }
+
- return this.board.cols
+ return this.board.width - this.width - 1
- return this.board.rows
+ return this.board.height - this.height - 1
- this.position = {
- down: this.top,
- right: value
- }
+ this.setPosition({
+ y: this.top,
+ x: value
+ })
- return this.position.right
+ return this._x ?? this.position.x
- get position() {
- return yodash.parsePosition(this.words)
+ get bounds() {
+ return {
+ x: this.x,
+ y: this.y,
+ w: this.width,
+ h: this.height
+ }
- get positionHash() {
- return yodash.makePositionHash(this.position)
+ get position() {
+ return {
+ x: parseInt(this.words[1]),
+ y: parseInt(this.words[2])
+ }
- return this.parent.gridSize
+ return 1
+ }
+
+ get agentSize() {
+ return this.size ?? this.gridSize
Changed around line 252: class Agent extends TreeNode {
- this.element.remove()
+ if (this.element) this.element.remove()
- return document.getElementById(`agent${this._getUid()}`)
+ return document.getElementById(this.id)
Changed around line 267: class Agent extends TreeNode {
- const { gridSize, health } = this
+ const { health, width, height } = this
- return `top:${this.top * gridSize}px;left:${
- this.left * gridSize
- }px;font-size:${gridSize}px;line-height: ${gridSize}px;${opacity};${this.style ?? ""}`
+ return `top:${this.top}px;left:${this.left}px;font-size:${height}px;line-height:${height}px;${opacity};${
+ this.style ?? ""
+ }`
+ }
+
+ get id() {
+ return `agent${this.agentNumber}`
+ }
+
+ get agentNumber() {
+ return this._getUid()
- elem.setAttribute("id", `agent${this._getUid()}`)
+ elem.setAttribute("id", this.id)
Changed around line 292: class Agent extends TreeNode {
- toStumpCode() {
- return `div ${this.html ?? this.icon}
- id agent${this._getUid()}
- class Agent ${this.selected ? SelectedClass : ""}
- style ${this.inlineStyle}`
+ toggleSelectCommand() {
+ const { root } = this
+ root.selection.includes(this) ? this.unselectCommand() : this.selectCommand()
+
+ root.ensureRender()
+ return this
+ }
+
+ unselectCommand() {
+ this.unselect()
+ this.root.selection = this.root.selection.filter(node => node !== this)
+ }
+
+ selectCommand() {
+ this.root.selection.push(this)
+ this.select()
Changed around line 325: class Agent extends TreeNode {
- target.angle = this.angle
+ target.direction = this.direction
Changed around line 370: class Agent extends TreeNode {
- this.angle = yodash.flipAngle(this.angle)
+ const { x, y } = this.direction
+ this.direction = { x: -x, y: -y }
Changed around line 387: class Agent extends TreeNode {
- this.angle = yodash.getRandomAngle(this.board.randomNumberGenerator)
+ const rng = this.board.randomNumberGenerator
+ this.direction = { x: 2 * rng() - 1, y: 2 * rng() - 1 }
Changed around line 396: class Agent extends TreeNode {
- if (targets) this.angle = yodash.getBestAngle(targets, this.position)
+ if (!targets) return this
+ this.target = yodash.getClosest(targets, this)
+ this.direction = yodash.unitVector(this, this.target)
Changed around line 406: class Agent extends TreeNode {
- if (targets) this.angle = yodash.flipAngle(yodash.getBestAngle(targets, this.position))
+ if (!targets) return this
+ this.target = yodash.getClosest(targets, this)
+ const bestUnitVector = yodash.unitVector(this, this.target)
+ this.direction = { x: -bestUnitVector.x, y: -bestUnitVector.y }
Changed around line 418: class Agent extends TreeNode {
- const position = command.getWordsFrom(2).length ? command.getWordsFrom(2).join(" ") : subject.positionHash
+ const position = command.getWordsFrom(2).length ? command.getWordsFrom(2).join(" ") : `${subject.x} ${subject.y}`
+ get midpoint() {
+ return { x: this.x + this.width / 2, y: this.y + this.height / 2 }
+ }
+
+ emit(subject, command) {
+ const { midpoint } = this
+ const position = command.getWordsFrom(2).length ? command.getWordsFrom(2).join(" ") : `${midpoint.x} ${midpoint.y}`
+ const agent = this.board.appendLine(`${command.getWord(1)} ${position}`)
+ agent.direction = this.direction
+ }
+
- while (this.overlappingAgents.length) {
+ while (this.collidingAgents.length) {
+ grow() {
+ this.width++
+ this.height++
+ this.markDirty()
+ }
+
+ shrink() {
+ if (!this.width || !this.height) return
+ this.width--
+ this.height--
+ this.markDirty()
+ }
+
+ _lastPulse
+ pulse() {
+ if (this._lastPulse) this.shrink()
+ else this.grow()
+ this._lastPulse = !this._lastPulse
+ }
+
- this.behaviors.push(command.getWord(1))
+ this.classes.push(command.getWord(1))
- const behaviorName = command.getWord(1)
- this.behaviors = this.behaviors.filter(name => name !== behaviorName)
+ const className = command.getWord(1)
+ this.classes = this.classes.filter(name => name !== className)
components/Board.js
Changed around line 2: const { TreeNode } = require("jtree/products/TreeNode.js")
+ const { CollisionDetector } = require("./CollisionDetector.js")
Changed around line 61: class BoardComponent extends AbstractTreeComponentParser {
- return parseInt(this.getWord(1))
+ return 1
- get rows() {
- return parseInt(this.getWord(2))
+ get width() {
+ if (this._width === undefined) this._width = parseInt(this.getWord(2))
+ return this._width
- get cols() {
- return parseInt(this.getWord(3))
+ get height() {
+ if (this._height === undefined) this._height = parseInt(this.getWord(3))
+ return this._height
Changed around line 110: class BoardComponent extends AbstractTreeComponentParser {
- insertAgentAtCommand(right, down) {
+ insertAgentAtCommand(xCenter, yCenter) {
- const board = this
- const positionHash = down + " " + right
- board.resetAgentPositionMap()
- const { agentPositionMap } = board
- const existingObjects = agentPositionMap.get(positionHash) ?? []
- if (existingObjects.length) return root.toggleSelectCommand(existingObjects)
-
+ this.clearCollisionDetector()
- //if (parent.findNodes(agentToInsert).length > MAX_ITEMS) return true
+ const { agentWidth, agentHeight } = this.getAgentHeightAndWidth(agentToInsert)
+
+ const x = xCenter - Math.floor(agentWidth / 2)
+ const y = yCenter - Math.floor(agentHeight / 2)
- board.prependLine(`${agentToInsert} ${positionHash}`)
- board.renderAndGetRenderReport()
- board.resetAgentPositionMap()
+ //if (parent.findNodes(agentToInsert).length > MAX_ITEMS) return true
- if (!root.isSnapshotOn) root.snapShotCommand()
+ this.prependLine(`${agentToInsert} ${x} ${y}`)
+ this.renderAndGetRenderReport()
+ this.clearCollisionDetector()
- targetNode.appendLine(`insertAt ${agentToInsert} ${down} ${right}`)
+ targetNode.appendLine(`insertAt ${agentToInsert} ${x} ${y}`)
Changed around line 150: class BoardComponent extends AbstractTreeComponentParser {
-
- this.resetAgentPositionMap()
- this.handleOverlaps()
- this.handleTouches()
- this.handleNeighbors()
-
+ this.clearCollisionDetector()
+ this.handleCollisions()
Changed around line 176: class BoardComponent extends AbstractTreeComponentParser {
+ treeComponentDidMount() {
+ const that = this
+ if (this.isNodeJs()) return
+ jQuery(this.getStumpNode().getShadow().element).on("click", ".Agent", function (evt) {
+ const agent = evt.target
+ const id = parseInt(jQuery(agent).attr("id").replace("agent", ""))
+ that.getAgent(id).toggleSelectCommand()
+ })
+ }
+
+ getAgent(uid) {
+ return this.agents.find(agent => agent._getUid() === uid)
+ }
+
Changed around line 218: class BoardComponent extends AbstractTreeComponentParser {
- occupiedSpots = new Set()
-
+ getAgentHeightAndWidth(agentSymbol) {
+ const item = new this.agentMap[agentSymbol]()
+ return { agentWidth: item.width, agentHeight: item.height }
+ }
+
+ insertInbounds(agentSymbol, x, y) {
+ const { agentWidth, agentHeight } = this.getAgentHeightAndWidth(agentSymbol)
+ const xOver = x + agentWidth - this.width
+ const yOver = y + agentHeight - this.height
+ if (xOver > 0) x = x - xOver - 10
+ if (yOver > 0) y = y - yOver - 10
+ if (x < 0) x = 0
+ if (y < 0) y = 0
+ this.appendLine(`${agentSymbol} ${x} ${y}`)
+ }
+
+ // todo: origin
+ insertClusteredRandomAgents(amount, agentSymbol, x = 0, y = 0) {
+ const { agentWidth, agentHeight } = this.getAgentHeightAndWidth(agentSymbol)
+ const spots = this.collisionDetector.findClusteredNonOverlappingSquares(
+ agentWidth,
+ agentHeight,
+ amount,
+ x,
+ y,
+ (amount * agentWidth) / 4
+ )
+ return spots.map(spot => `${agentSymbol} ${spot.x} ${spot.y}`).join("\n")
+ }
+
- yodash.insertClusteredRandomAgents(
- this.randomNumberGenerator,
+ this.insertClusteredRandomAgents(
- this.rows,
- this.cols,
- this.occupiedSpots,
+ this.clearCollisionDetector()
- this.appendLine(`${commandNode.getWord(1)} ${commandNode.getWord(3)} ${commandNode.getWord(2)}`)
- // TODO: update occupied spots cache?
+ this.appendLine(`${commandNode.getWord(1)} ${commandNode.getWord(2)} ${commandNode.getWord(3)}`)
+ this.clearCollisionDetector()
- const newLines = yodash.makeRectangle(...yodash.parseInts(commandNode.words.slice(1), 1))
+ // todo: need a typed words method in jtree
+ // rectangle 🙂 width height x y 🙂
+ const [command, agentSymbol, width, height, x, y, fillSymbol, spacing] = commandNode.words
+
+ const { agentWidth, agentHeight } = this.getAgentHeightAndWidth(agentSymbol)
+
+ const options = {
+ agentSymbol,
+ width: parseInt(width),
+ height: parseInt(height),
+ x: x ? parseInt(x) : 0,
+ y: y ? parseInt(y) : 0,
+ fillSymbol,
+ spacing: spacing || 0,
+ agentHeight,
+ agentWidth
+ }
+
+ const newLines = this.makeRectangle(options)
- // TODO: update occupied spots cache?
+ this.clearCollisionDetector()
- yodash.updateOccupiedSpots(newSpots, this.occupiedSpots)
+ this.clearCollisionDetector()
- this.concat(yodash.fill(this.rows, this.cols, this.occupiedSpots, commandNode.getWord(1)))
+ this.concat(this.fill(commandNode.getWord(1)))
+ this.clearCollisionDetector()
- const { occupiedSpots } = this
- const spots = yodash.draw(commandNode.childrenToString())
- yodash.updateOccupiedSpots(spots, occupiedSpots)
- this.concat(spots)
+ this.concat(this.draw(commandNode.childrenToString()))
+ this.clearCollisionDetector()
Changed around line 321: class BoardComponent extends AbstractTreeComponentParser {
- const { rows, cols, occupiedSpots } = this
- const emoji = commandNode.getWord(2)
+ const { width, height } = this
+ const agentSymbol = commandNode.getWord(2)
+ const { agentWidth, agentHeight } = this.getAgentHeightAndWidth(agentSymbol)
+ const maxCells = (width * height) / (agentWidth * agentHeight)
+ amount = amount.includes("%") ? yodash.parsePercent(amount) * maxCells : parseInt(amount)
+
+ const spots = this.collisionDetector.findNonOverlappingSquares(agentWidth, agentHeight, amount)
+
+ const newAgents = spots.map(spot => `${agentSymbol} ${spot.x + " " + spot.y}`).join("\n")
- const availableSpots = yodash.getAllAvailableSpots(rows, cols, occupiedSpots)
- amount = amount.includes("%") ? yodash.parsePercent(amount) * (rows * cols) : parseInt(amount)
- const newAgents = yodash
- .sampleFrom(availableSpots, amount, this.randomNumberGenerator)
- .map(spot => {
- const { hash } = spot
- occupiedSpots.add(hash)
- return `${emoji} ${hash}`
- })
- .join("\n")
+ this.clearCollisionDetector()
Changed around line 356: class BoardComponent extends AbstractTreeComponentParser {
- isSolidAgent(position) {
- if (!this._solidsSet) this.resetAgentPositionMap()
- const hash = yodash.makePositionHash(position)
- if (this._solidsSet.has(hash)) return true
-
- return false
- }
-
- get agentPositionMap() {
- if (!this._agentPositionMap) this.resetAgentPositionMap()
- return this._agentPositionMap
- }
-
- resetAgentPositionMap() {
- const map = new Map()
- const solidsSet = new Set()
- this.agents.forEach(agent => {
- const { positionHash } = agent
- if (agent.solid) solidsSet.add(positionHash)
- if (!map.has(positionHash)) map.set(positionHash, [])
- map.get(positionHash).push(agent)
- })
- this._solidsSet = solidsSet
- this._agentPositionMap = map
- this.occupiedSpots = new Set(map.keys())
- }
-
Changed around line 370: class BoardComponent extends AbstractTreeComponentParser {
- handleOverlaps() {
- this.agentPositionMap.forEach(nodes => {
- if (nodes.length > 1) nodes.forEach(node => node.handleOverlaps(nodes))
- })
+ clearCollisionDetector() {
+ delete this._collisionDetector
+ delete this._solidCollisionDetector
- handleTouches() {
- const agentPositionMap = this.agentPositionMap
- this.agents.forEach(node => node.handleTouches(agentPositionMap))
+ _collisionDetector
+ get collisionDetector() {
+ if (!this._collisionDetector) this._collisionDetector = new CollisionDetector(this.agents, this.width, this.height)
+ return this._collisionDetector
- handleNeighbors() {
- this.agents.forEach(node => node.handleNeighbors())
+ handleCollisions() {
+ const collisions = this.collisionDetector.detectCollisions()
+ collisions.forEach(collision => {
+ const [agentA, agentB] = collision
+ agentA.handleCollisions([agentB])
+ agentB.handleCollisions([agentA])
+ })
Changed around line 471: class BoardComponent extends AbstractTreeComponentParser {
- this.appendLine(
- `${command.getWord(1)} ${yodash.getRandomLocationHash(
- this.rows,
- this.cols,
- undefined,
- this.randomNumberGenerator
- )}`
- )
+ this.appendLine(`${command.getWord(1)} ${this.getRandomLocationHash()}`)
Changed around line 495: class BoardComponent extends AbstractTreeComponentParser {
+
+ isRectOccupied(x, y, width, height) {
+ return !this.collisionDetector.isSpotAvailable(x, y, width, height)
+ }
+
+ objectsCollidingWith(x, y, width, height) {
+ return this.collisionDetector.getCollidingAgents(x, y, width, height)
+ }
+
+ _solidCollisionDetector
+ get solidCollisionDetector() {
+ if (!this._solidCollisionDetector)
+ this._solidCollisionDetector = new CollisionDetector(
+ this.agents.filter(agent => agent.solid),
+ this.width,
+ this.height
+ )
+ return this._solidCollisionDetector
+ }
+
+ canGoHere(x, y, width, height) {
+ const blockersHere = this.solidCollisionDetector.getCollidingAgents(x, y, width, height)
+ if (blockersHere.length) return false
+
+ return true
+ }
+
+ get collidingAgents() {
+ const agents = this.agents
+ const collidingAgents = []
+ for (let agent of agents) {
+ const { position, agentSize } = agent
+ const agentsHere = this.objectsCollidingWith(position.x, position.y, agentSize).filter(a => a !== agent)
+ if (agentsHere.length) collidingAgents.push(...agentsHere)
+ }
+ return collidingAgents
+ }
+
+ makePositionHash(positionType) {
+ return `${positionType.x + " " + positionType.y}`
+ }
+
+ getRandomLocationHash(size = 1) {
+ const { x, y } = this.getRandomLocation()
+ if (this.isRectOccupied(x, y, size, size)) return this.getRandomLocationHash()
+ return this.makePositionHash({ x, y })
+ }
+
+ getRandomLocation() {
+ const { randomNumberGenerator, height, width } = this
+ const maxRight = width
+ const maxBottom = height
+ const x = Math.round(randomNumberGenerator() * maxRight)
+ const y = Math.round(randomNumberGenerator() * maxBottom)
+ return { x, y }
+ }
+
+ draw(str) {
+ const lines = str.split("\n")
+ const output = []
+ let agentWidth
+ let agentHeight
+ for (let index = 0; index < lines.length; index++) {
+ const words = lines[index].split(" ")
+ for (let wordIndex = 0; wordIndex < words.length; wordIndex++) {
+ const agentSymbol = words[wordIndex]
+ if (agentSymbol && !agentWidth) {
+ // Draw assumes everything being drawn is a square with sides N.
+ agentWidth = this.getAgentHeightAndWidth(agentSymbol).agentWidth
+ agentHeight = agentWidth
+ }
+
+ if (agentSymbol !== "")
+ output.push(`${agentSymbol} ${this.makePositionHash({ y: index * agentHeight, x: wordIndex * agentHeight })}`)
+ }
+ }
+ return output.join("\n")
+ }
+
+ makeRectangle(options) {
+ const { width, height, agentSymbol, x, y, fillSymbol, spacing, agentHeight, agentWidth } = options
+
+ if (width < 1 || height < 1) return ""
+
+ if (isNaN(x)) x = 20
+ if (isNaN(y)) y = 20
+
+ const cells = []
+ let row = 0
+ while (row < height) {
+ let col = 0
+ while (col < width) {
+ const isPerimeter = row === 0 || row === height - 1 || col === 0 || col === width - 1
+ if (!fillSymbol && !isPerimeter) {
+ col++
+ continue
+ }
+
+ cells.push(
+ `${isPerimeter ? agentSymbol : fillSymbol} ${x + col * (agentWidth + spacing)} ${
+ y + row * (agentHeight + spacing)
+ }`
+ )
+ col++
+ }
+ row++
+ }
+ return cells.join("\n")
+ }
+
+ fill(agentSymbol) {
+ let { width, height } = this
+ const { agentWidth, agentHeight } = this.getAgentHeightAndWidth(agentSymbol)
+ const board = []
+ let y = 0
+ while (y < height - agentHeight) {
+ let x = 0
+ while (x < width - agentWidth) {
+ if (this.isRectOccupied(x, y, agentWidth, agentHeight)) {
+ x += agentWidth
+ continue
+ }
+ board.push(`${agentSymbol} ${x} ${y}`)
+ x += agentWidth
+ }
+ y += agentHeight
+ }
+ return board.join("\n")
+ }
+
+ getNeighborCount(rect) {
+ const { position, agentSize } = rect
+ const neighborCounts = {}
+ this.positionsAdjacentToRect(position.right, position.down, agentSize).forEach(pos => {
+ const agents = this.objectsCollidingWith(pos.right, pos.down, agentSize)
+ agents.forEach(agent => {
+ if (!neighborCounts[agent.name]) neighborCounts[agent.name] = 0
+ neighborCounts[agent.name]++
+ })
+ })
+ return neighborCounts
+ }
+
+ positionsAdjacentToRect(x, y, size) {
+ const positions = []
+ for (let row = y - size; row <= y + size; row++) {
+ for (let col = x - size; col <= x + size; col++) {
+ if (row === y && col === x) continue
+ positions.push({ right: col, down: row })
+ }
+ }
+ return positions
+ }
components/Board.test.node.js
Changed around line 1
+ #!/usr/bin/env node
+
+ const { BoardComponent } = require("./Board.js")
+ const { TestRacer } = require("jtree/products/TestRacer.js")
+
+ const testTree = {}
+
+ testTree.makeRectangle = areEqual => {
+ const expected = `😀 0 0
+ 😀 1 0
+ 😀 0 1
+ 😀 1 1`
+
+ const options = {
+ agentSymbol: "😀",
+ width: 2,
+ height: 2,
+ x: 0,
+ y: 0,
+ fillSymbol: false,
+ spacing: 0,
+ agentHeight: 1,
+ agentWidth: 1
+ }
+
+ const board = new BoardComponent()
+ areEqual(board.makeRectangle(options), expected)
+
+ options.agentSymbol = "🚪"
+ options.height = 1
+ options.x = 1
+ options.y = 1
+ areEqual(
+ board.makeRectangle(options),
+ `🚪 1 1
+ 🚪 2 1`
+ )
+ }
+
+ if (!module.parent) TestRacer.testSingleFile(__filename, testTree)
+ module.exports = { testTree }
components/CollisionDetector.js
Changed around line 1
+ class Bounds {
+ constructor(x, y, w, h) {
+ this.x = x
+ this.y = y
+ this.w = w
+ this.h = h
+ }
+
+ intersects(range) {
+ return !(
+ range.x >= this.x + this.w ||
+ range.y >= this.y + this.h ||
+ range.x + range.w <= this.x ||
+ range.y + range.h <= this.y
+ )
+ }
+ }
+
+ class Quadtree {
+ constructor(bounds, capacity, maxDepth = 10) {
+ this.bounds = new Bounds(bounds.x, bounds.y, bounds.w, bounds.h)
+ this.capacity = capacity
+ this.maxDepth = maxDepth
+ this.agents = []
+ }
+
+ get agentCount() {
+ let count = 0
+
+ if (this.isLeaf()) {
+ count += this.agents.length
+ } else {
+ for (const child of this.children) {
+ count += child.agentCount
+ }
+ }
+
+ return count
+ }
+
+ insert(agent, depth = 0) {
+ if (!this.bounds.intersects(agent)) return false
+
+ if (!this.divided && (this.agents.length < this.capacity || depth >= this.maxDepth)) {
+ this.agents.push(agent)
+ return true
+ } else {
+ if (!this.divided) this.divide()
+ for (const child of this.children) {
+ if (child.insert(agent, depth + 1)) return true
+ }
+ }
+ return false
+ }
+
+ isLeaf() {
+ return !this.divided
+ }
+
+ get northWest() {
+ return this.children[0]
+ }
+
+ get northEast() {
+ return this.children[1]
+ }
+
+ get southWest() {
+ return this.children[2]
+ }
+
+ get southEast() {
+ return this.children[3]
+ }
+
+ prettyPrint(depth = 0) {
+ let output = ""
+
+ if (this.isLeaf()) {
+ output += "-".repeat(depth - 1)
+ output += `[${this.bounds.x}, ${this.bounds.y}, ${this.bounds.w}, ${this.bounds.h}]: `
+ output += this.agents.map(agent => agent.id).join(", ")
+ output += "\n"
+ } else {
+ output += this.northWest.prettyPrint(depth + 1)
+ output += this.northEast.prettyPrint(depth + 1)
+ output += this.southWest.prettyPrint(depth + 1)
+ output += this.southEast.prettyPrint(depth + 1)
+ }
+
+ return output
+ }
+
+ get divided() {
+ return !!this.children
+ }
+
+ divide() {
+ const { x, y } = this.bounds
+ const { bounds, capacity } = this
+ const w = bounds.w / 2
+ const h = bounds.h / 2
+
+ this.children = [
+ new Quadtree({ x, y, w, h }, capacity),
+ new Quadtree({ x: x + w, y, w, h }, capacity),
+ new Quadtree({ x, y: y + h, w, h }, capacity),
+ new Quadtree({ x: x + w, y: y + h, w, h }, capacity)
+ ]
+
+ for (const agent of this.agents) this.insert(agent)
+ delete this.agents
+ }
+
+ query(range, found = []) {
+ if (!this.bounds.intersects(range)) return found
+
+ if (!this.divided) {
+ for (const agent of this.agents) if (range.intersects(agent)) found.push(agent)
+ } else {
+ for (const child of this.children) child.query(range, found)
+ }
+
+ return found
+ }
+ }
+
+ class CollisionDetector {
+ constructor(agents, worldWidth, worldHeight) {
+ this.agents = agents
+ this.width = worldWidth
+ this.height = worldHeight
+ this.quadtree = new Quadtree({ x: 0, y: 0, w: worldWidth, h: worldHeight }, 4)
+ for (const agent of this.agents) this.addAgent(agent)
+ }
+
+ addAgent(agent) {
+ this.quadtree.insert(agent)
+ return this
+ }
+
+ isSpotAvailable(x, y, width, height) {
+ const searchBounds = new Bounds(x, y, width, height)
+
+ const nearbyAgents = this.quadtree.query(searchBounds)
+
+ for (const agent of nearbyAgents) {
+ if (x < agent.x + agent.width && x + width > agent.x && y < agent.y + agent.height && y + height > agent.y) {
+ return false
+ }
+ }
+ return true
+ }
+
+ findNonOverlappingSquares(width, height, N) {
+ const nonOverlappingSquares = []
+ const availableCells = []
+
+ // Divide the world into cells
+ for (let x = 0; x < this.width - width; x += width) {
+ for (let y = 0; y < this.height - height; y += height) {
+ if (this.isSpotAvailable(x, y, width, height)) availableCells.push({ x, y })
+ }
+ }
+
+ // Randomly select non-overlapping cells
+ while (nonOverlappingSquares.length < N && availableCells.length) {
+ const randomIndex = Math.floor(Math.random() * availableCells.length)
+ nonOverlappingSquares.push(availableCells[randomIndex])
+ availableCells.splice(randomIndex, 1)
+ }
+ return nonOverlappingSquares
+ }
+
+ findClusteredNonOverlappingSquares(width, height, N, centerX, centerY, clusterRadius) {
+ const nonOverlappingSquares = []
+ const availableCells = []
+
+ // Divide the world into cells and filter by clusterRadius
+ for (let x = 0; x < this.width - width; x += width) {
+ for (let y = 0; y < this.height - height; y += height) {
+ const dx = x - centerX
+ const dy = y - centerY
+ const distance = Math.sqrt(dx * dx + dy * dy)
+
+ if (distance <= clusterRadius && this.isSpotAvailable(x, y, width, height)) {
+ availableCells.push({ x: x, y: y })
+ }
+ }
+ }
+
+ // Randomly select non-overlapping cells
+ while (nonOverlappingSquares.length < N && availableCells.length > 0) {
+ const randomIndex = Math.floor(Math.random() * availableCells.length)
+ nonOverlappingSquares.push(availableCells[randomIndex])
+ availableCells.splice(randomIndex, 1)
+ }
+
+ return nonOverlappingSquares
+ }
+
+ getCollidingAgents(x, y, width, height) {
+ const collidingAgents = []
+ const queryBounds = new Bounds(x, y, width, height)
+ const nearbyAgents = this.quadtree.query(queryBounds)
+
+ for (const agent of nearbyAgents) {
+ if (queryBounds.intersects(agent)) collidingAgents.push(agent)
+ }
+
+ return collidingAgents
+ }
+
+ detectCollisions() {
+ let collissions = []
+
+ for (const agentA of this.agents) {
+ const searchBounds = new Bounds(
+ agentA.x - agentA.width,
+ agentA.y - agentA.height,
+ agentA.width * 2,
+ agentA.height * 2
+ )
+ const nearbyAgents = this.quadtree.query(searchBounds)
+ for (const agentB of nearbyAgents) {
+ if (agentA !== agentB && this.checkCollision(agentA, agentB)) collissions.push([agentA, agentB])
+ }
+ }
+ return collissions
+ }
+
+ checkCollision(a, b) {
+ return a.x < b.x + b.width && a.x + a.width > b.x && a.y < b.y + b.height && a.y + a.height > b.y
+ }
+ }
+
+ module.exports = { CollisionDetector }
components/CollisionDetector.test.node.js
Changed around line 1
+ #!/usr/bin/env node
+
+ const { CollisionDetector } = require("./CollisionDetector.js")
+ const { TestRacer } = require("jtree/products/TestRacer.js")
+
+ const testTree = {}
+
+ class MockWorld {
+ constructor(width, height) {
+ this.width = width
+ this.height = height
+ }
+ }
+
+ class MockAgent {
+ constructor(id, position) {
+ this.id = id
+ this.x = position.x
+ this.y = position.y
+ this.width = position.width
+ this.height = position.height
+ }
+
+ get w() {
+ return this.width
+ }
+
+ get h() {
+ return this.height
+ }
+ }
+
+ testTree.empty = areEqual => {
+ const world = new MockWorld(500, 500)
+ const agents = []
+ const collisionDetector = new CollisionDetector(agents, world.width, world.height)
+ areEqual(collisionDetector.detectCollisions().length, 0) // Should not detect any collisions
+ }
+
+ testTree.miss = areEqual => {
+ const world = new MockWorld(500, 500)
+ const agents = [
+ new MockAgent(1, { x: 50, y: 50, width: 10, height: 10 }),
+ new MockAgent(2, { x: 200, y: 200, width: 10, height: 10 })
+ ]
+ const collisionDetector = new CollisionDetector(agents, world.width, world.height)
+ areEqual(collisionDetector.detectCollisions().length, 0) // Should not detect any collisions
+ }
+
+ testTree.hit = areEqual => {
+ const world = new MockWorld(500, 500)
+ const agents = [
+ new MockAgent(1, { x: 50, y: 50, width: 10, height: 10 }),
+ new MockAgent(2, { x: 55, y: 55, width: 10, height: 10 })
+ ]
+ const collisionDetector = new CollisionDetector(agents, world.width, world.height)
+ areEqual(collisionDetector.detectCollisions().length, 2, "one hit") // Should detect a collision between agents 1 and 2
+ }
+
+ testTree.multiple = areEqual => {
+ const world = new MockWorld(500, 500)
+ const agents = [
+ new MockAgent(1, { x: 50, y: 50, width: 10, height: 10 }),
+ new MockAgent(2, { x: 55, y: 55, width: 10, height: 10 }),
+ new MockAgent(3, { x: 200, y: 200, width: 10, height: 10 }),
+ new MockAgent(4, { x: 205, y: 200, width: 10, height: 10 }),
+ new MockAgent(5, { x: 400, y: 400, width: 10, height: 10 })
+ ]
+ const collisionDetector = new CollisionDetector(agents, world.width, world.height)
+ areEqual(collisionDetector.detectCollisions().length, 4, "2 hits") // Should detect collisions between agents 1 and 2, and agents 3 and 4
+ }
+
+ testTree.get = areEqual => {
+ const world = new MockWorld(500, 500)
+ const agents = [
+ new MockAgent(1, { x: 50, y: 50, width: 10, height: 10 }),
+ new MockAgent(2, { x: 55, y: 55, width: 10, height: 10 }),
+ new MockAgent(3, { x: 200, y: 200, width: 10, height: 10 })
+ ]
+ const collisionDetector = new CollisionDetector(agents, world.width, world.height)
+ const collidingAgents = collisionDetector.getCollidingAgents(45, 45, 20, 20)
+ areEqual(collidingAgents.length, 2, "query works") // Should return an array containing the agents 1 and 2, as they collide with the specified rectangle
+ }
+
+ testTree.big = areEqual => {
+ const world = new MockWorld(500, 500)
+ const agents = [
+ new MockAgent(1, { x: 50, y: 50, width: 10, height: 10 }),
+ new MockAgent(2, { x: 55, y: 55, width: 10, height: 10 }),
+ new MockAgent(3, { x: 200, y: 200, width: 10, height: 10 }),
+ new MockAgent(4, { x: 250, y: 250, width: 10, height: 10 }),
+ new MockAgent(5, { x: 300, y: 300, width: 10, height: 10 }),
+ new MockAgent(6, { x: 30, y: 30, width: 10, height: 10 }),
+ new MockAgent(7, { x: 15, y: 15, width: 10, height: 10 }),
+ new MockAgent(8, { x: 100, y: 100, width: 10, height: 10 }),
+ new MockAgent(9, { x: 75, y: 75, width: 10, height: 10 }),
+ new MockAgent(10, { x: 350, y: 350, width: 10, height: 10 }),
+ new MockAgent(11, { x: 400, y: 400, width: 10, height: 10 }),
+ new MockAgent(12, { x: 450, y: 450, width: 10, height: 10 })
+ ]
+ const collisionDetector = new CollisionDetector(agents, world.width, world.height)
+ const collidingAgents = collisionDetector.getCollidingAgents(45, 45, 30, 30)
+ areEqual(collidingAgents.length, 2) // Should return an array containing the agents 1 and 2, as they collide with the specified rectangle
+ }
+
+ if (!module.parent) TestRacer.testSingleFile(__filename, testTree)
+ module.exports = { testTree }
components/Examples.js
Changed around line 17: const Categories = new TreeNode(`🦠 Epidemiology
- 👾 Game of Life
- gameOfLife
- gospersGliderGun
- gameOfLifeAdvanced
components/Grid.js
Changed around line 1
- const { yodash } = require("../yodash.js")
- gridClickCommand(down, right) {
- return this.parent.insertAgentAtCommand(right, down)
+ gridClickCommand(x, y) {
+ return this.parent.insertAgentAtCommand(x, y)
- makeBlock(down, right, gridSize) {
- return `\n div
- class block
- style width:${gridSize}px;height:${gridSize}px;top:${down * gridSize}px;left:${right * gridSize}px;
- clickCommand gridClickCommand ${yodash.makePositionHash({ right, down })}`
+ treeComponentDidMount() {
+ const that = this
+ if (this.isNodeJs()) return super.treeComponentDidMount()
+
+ jQuery(`.${GridComponent.name}`).on("click", function (evt) {
+ const { offsetX, offsetY } = evt
+ const x = offsetX
+ const y = offsetY
+ that.gridClickCommand(x, y)
+ })
- const { cols, rows, gridSize } = this.parent
- let blocks = ""
- let rs = rows
- while (rs >= 0) {
- let cs = cols
- while (cs >= 0) {
- blocks = this.makeBlock(rs, cs, gridSize) + blocks
- cs--
- }
- rs--
- }
- return (
- `div
- class ${GridComponent.name}` + blocks
- )
+ return `div
+ class ${GridComponent.name}`
components/SimEditor.js
Changed around line 2: const { TreeNode } = require("jtree/products/TreeNode.js")
- /*NODE_JS_ONLY*/ const simojiParser = require("jtree/products/GrammarCompiler.js").GrammarCompiler.compileGrammarFileAtPathAndReturnRootParser( __dirname + "/../simoji.grammar")
+ /*NODE_JS_ONLY*/ const simojiParser = require("jtree/products/GrammarCompiler.js").GrammarCompiler.compileGrammarFileAtPathAndReturnRootParser( __dirname + "/../dist/simoji.grammar")
components/SimojiApp.js
Changed around line 20: const { BottomBarComponent } = require("./BottomBar.js")
- const { Keywords, LocalStorageKeys, UrlKeys, Directions, ParserTypes } = require("./Types.js")
-
- const MIN_GRID_SIZE = 10
- const MAX_GRID_SIZE = 200
- const DEFAULT_GRID_SIZE = 20
- const MIN_GRID_COLUMNS = 10
- const MIN_GRID_ROWS = 10
+ const { Keywords, LocalStorageKeys, UrlKeys, ParserTypes } = require("./Types.js")
- /*NODE_JS_ONLY*/ const simojiParser = require("jtree/products/GrammarCompiler.js").GrammarCompiler.compileGrammarFileAtPathAndReturnRootParser( __dirname + "/../simoji.grammar")
+ /*NODE_JS_ONLY*/ const simojiParser = require("jtree/products/GrammarCompiler.js").GrammarCompiler.compileGrammarFileAtPathAndReturnRootParser( __dirname + "/../dist/simoji.grammar")
Changed around line 81: class SimojiApp extends AbstractTreeComponentParser {
- const setSize = simojiProgram.get(Keywords.size)
- const gridSize = Math.min(Math.max(setSize ? parseInt(setSize) : DEFAULT_GRID_SIZE, MIN_GRID_SIZE), MAX_GRID_SIZE)
-
- const maxAvailableCols = Math.floor((windowWidth - chromeWidth) / gridSize) - 1
- const maxAvailableRows = Math.floor((windowHeight - SIZES.CHROME_HEIGHT - SIZES.TITLE_HEIGHT) / gridSize) - 1
+ const width = windowWidth - chromeWidth - 1
+ const height = windowHeight - SIZES.CHROME_HEIGHT - SIZES.TITLE_HEIGHT - 1
- const setCols = simojiProgram.get(Keywords.columns)
- const cols = Math.max(1, setCols ? parseInt(setCols) : Math.max(MIN_GRID_COLUMNS, maxAvailableCols))
+ const setWidth = simojiProgram.get(Keywords.width)
+ const setHeight = simojiProgram.get(Keywords.height)
+ // todo: use the set values if present
- const setRows = simojiProgram.get(Keywords.rows)
- const rows = Math.max(1, setRows ? parseInt(setRows) : Math.max(MIN_GRID_ROWS, maxAvailableRows))
-
- return { gridSize, cols, rows }
+ return { width, height }
Changed around line 129: class SimojiApp extends AbstractTreeComponentParser {
- const { gridSize, cols, rows } = this.makeGrid(program, windowWidth, windowHeight)
+ const { width, height } = this.makeGrid(program, windowWidth, windowHeight)
- `${BoardComponent.name} ${gridSize} ${rows} ${cols} ${index}`,
+ `${BoardComponent.name} 1 ${width} ${height} ${index}`,
Changed around line 240: ${styleNode ? styleNode.toString().replace("style", BoardStyleComponent.name) :
- if (!this.isSnapshotOn) this.snapShotCommand()
Changed around line 319: ${styleNode ? styleNode.toString().replace("style", BoardStyleComponent.name) :
- toggleSelectCommand(objects) {
- objects.forEach(object => {
- this.selection.includes(object) ? this.unselectCommand(object) : this.selectCommand(object)
- })
-
- this.ensureRender()
- return this
- }
-
- unselectCommand(object) {
- object.unselect()
- this.selection = this.selection.filter(node => node !== object)
- }
-
- selectCommand(object) {
- this.selection.push(object)
- object.select()
- }
-
Changed around line 396: ${styleNode ? styleNode.toString().replace("style", BoardStyleComponent.name) :
- moveSelection(direction) {
+ moveSelection(x, y) {
- node.angle = direction
+ node.direction = { x, y }
- this.boards.forEach(board => board.resetAgentPositionMap())
-
- this.boards.forEach(board => board.resetAgentPositionMap())
+ // todo: update any state?
- // technically also needs rows and column settings
+ // technically also needs width and height settings
Changed around line 426: ${styleNode ? styleNode.toString().replace("style", BoardStyleComponent.name) :
- newCode.set(Keywords.rows, board.rows.toString())
- newCode.set(Keywords.columns, board.cols.toString())
+ newCode.set(Keywords.height, board.height.toString())
+ newCode.set(Keywords.width, board.width.toString())
- experiment.set(Keywords.rows, board.rows.toString())
- experiment.set(Keywords.columns, board.cols.toString())
+ experiment.set(Keywords.height, board.height.toString())
+ experiment.set(Keywords.width, board.width.toString())
Changed around line 468: ${styleNode ? styleNode.toString().replace("style", BoardStyleComponent.name) :
- up: () => this.moveSelection(Directions.North),
- down: () => this.moveSelection(Directions.South),
- right: () => this.moveSelection(Directions.East),
- left: () => this.moveSelection(Directions.West),
+ up: () => this.moveSelection(0, -1),
+ down: () => this.moveSelection(0, 1),
+ right: () => this.moveSelection(1, 0),
+ left: () => this.moveSelection(-1, 0),
components/SimojiApp.test.node.js
Changed around line 1
+ const { TestRacer } = require("jtree/products/TestRacer.js")
- const grammarPath = __dirname + "/../simoji.grammar"
+ const grammarPath = __dirname + "/../dist/simoji.grammar"
Changed around line 68: insert 10 😃
+ if (!module.parent) TestRacer.testSingleFile(__filename, testTree)
- const runTree = testTree => {
- const tap = require("tap")
- Object.keys(testTree).forEach(key => {
- testTree[key](tap.equal)
- })
- }
- if (module && !module.parent) runTree(testTree)
components/Types.js
Changed around line 2: const Keywords = {}
- Keywords.size = "size"
- Keywords.rows = "rows"
- Keywords.columns = "columns"
+ Keywords.height = "height"
+ Keywords.width = "width"
- Keywords.onNeighbors = "onNeighbors"
- Keywords.onTouch = "onTouch"
Changed around line 26: UrlKeys.simoji = "simoji"
- const Directions = {}
-
- Directions.North = "North"
- Directions.East = "East"
- Directions.South = "South"
- Directions.West = "West"
-
Changed around line 33: ParserTypes.experimentParser = "experimentParser"
- module.exports = { Keywords, LocalStorageKeys, UrlKeys, Directions, ParserTypes }
+ module.exports = { Keywords, LocalStorageKeys, UrlKeys, ParserTypes }
dev.html
Changed around line 28
+
dist/constants.js
Changed around line 1
- const SimConstants = {"grammar":"anyCell\nbooleanCell\nstringCell\n highlightScope string\nsettingValueCell\n highlightScope constant.numeric\ncssCell\n highlightScope string\njavascriptCell\n highlightScope string\nhtmlCell\n highlightScope string\nemojiCell\n highlightScope string\nohayoCell\n highlightScope string\nblankCell\ncodeCell\n highlightScope comment\ncommentCell\n highlightScope comment\nkeywordCell\n highlightScope keyword\ntextCell\n highlightScope string\nintegerCell\n highlightScope constant.numeric\nbehaviorNameCell\n highlightScope keyword\nconditionalOperatorCell\n highlightScope keyword\n enum < > = <= >=\npositionCell\n highlightScope constant.numeric\nneighborCountCell\n extends integerCell\n min 0\n max 8\nintegerOrPercentCell\n highlightScope constant.numeric\nprobabilityCell\n description A number between 0 and 1\n highlightScope constant.numeric\npropertyNameCell\n highlightScope keyword\nangleCell\n enum North South East West NorthWest NorthEast SouthWest SouthEast\n highlightScope constant.numeric\nerrorParser\n baseParser errorParser\nsimojiParser\n extensions simoji\n description A Tree Language that compiles to a TreeComponentFramework app.\n root\n inScope abstractIgnoreParser abstractSetupParser abstractInjectCommandParser onTickParser onExtinctParser behaviorDefinitionParser experimentParser settingDefinitionParser\n catchAllParser agentDefinitionParser\n compilesTo javascript\n example\n 🦋\n onTick .1\n turnRandomly\n move\n onTick .2\n turnToward 💡\n move\n 💡\n \n insert 10 🦋\n insert 2 💡\n javascript\n get agentTypes() {\n return this.filter(node => node.parserId === \"agentDefinitionParser\")\n }\nexperimentParser\n cruxFromId\n cells keywordCell\n inScope abstractIgnoreParser abstractSetupParser abstractInjectCommandParser onTickParser onExtinctParser settingDefinitionParser\n catchAllCellType stringCell\nabstractSetupParser\natTimeParser\n cruxFromId\n description Run commands at a certain tick.\n cells keywordCell integerCell\n extends abstractSetupParser\n inScope abstractInjectCommandParser\nabstractSetupNumberParser\n cells keywordCell integerCell\n extends abstractSetupParser\n javascript\n compile() {\n return \"\"\n }\nsizeParser\n description Size of a grid cell in pixels. Min is 10. Max is 200.\n extends abstractSetupNumberParser\n cruxFromId\nrowsParser\n description Number of rows in the grid. Default is based on screen size.\n extends abstractSetupNumberParser\n cruxFromId\ncolumnsParser\n description Number of columns in the grid. Default is based on screen size.\n extends abstractSetupNumberParser\n cruxFromId\nseedParser\n description If you'd like reproducible runs set a seed for the random number generator.\n extends abstractSetupNumberParser\n cruxFromId\nticksPerSecondParser\n description Time in milliseconds of one step.\n extends abstractSetupNumberParser\n cruxFromId\nreportParser\n cruxFromId\n description Define a custom report template.\n catchAllParser ohayoLineParser\n extends abstractSetupParser\n cells keywordCell\n javascript\n compile() {\n return \"\"\n }\nstyleParser\n description Optional CSS to load in BoardStyleComponent\n extends abstractSetupParser\n cells keywordCell\n cruxFromId\n catchAllParser styleLineParser\n javascript\n compile() {\n return \"\"\n }\nquestionParser\n cruxFromId\n description What are you trying to figure out?\n cells keywordCell\n catchAllCellType stringCell\n extends abstractSetupParser\nabstractInjectCommandParser\nfillParser\n description Fill all blank cells with this agent.\n extends abstractInjectCommandParser\n cells keywordCell emojiCell\n cruxFromId\ndrawParser\n extends abstractInjectCommandParser\n cells keywordCell\n cruxFromId\n catchAllParser drawLineParser\ninsertParser\n extends abstractInjectCommandParser\n cells keywordCell integerOrPercentCell emojiCell\n cruxFromId\ninsertAtParser\n extends insertParser\n description Insert at X Y\n cells keywordCell emojiCell positionCell positionCell\n cruxFromId\ninsertClusterParser\n extends insertParser\n cruxFromId\n catchAllCellType integerCell\nrectangleDrawParser\n extends abstractInjectCommandParser\n cells keywordCell emojiCell integerCell integerCell\n catchAllCellType integerCell\n crux rectangle\npasteDrawParser\n extends abstractInjectCommandParser\n cells keywordCell\n crux paste\n catchAllParser pasteLineParser\ndrawLineParser\n catchAllCellType emojiCell\npasteLineParser\n catchAllCellType anyCell\n catchAllParser pasteLineParser\nagentDefinitionParser\n inScope abstractIgnoreParser abstractEventParser abstractAgentAttributeParser behaviorAttributeParser\n cells keywordCell\n catchAllParser errorParser\n compiler\n stringTemplate \n javascript\n compile() {\n const root = this.root\n const name = root.agentKeywordMap[this.firstWord]\n const normal = super.compile()\n const behaviors = this.filter(node => node.parserId === \"behaviorAttributeParser\")\n .map(behavior => `\"${behavior.getLine()}\"`)\n .join(\",\")\n return `class ${name} extends Agent {\n icon = \"${this.firstWord}\"\n behaviors = [${behaviors}]\n ${normal}\n }`\n }\nabstractCommandParser\n cells keywordCell\nabstractSubjectObjectCommandParser\n extends abstractCommandParser\nreplaceWithCommandParser\n extends abstractSubjectObjectCommandParser\n crux replaceWith\n cells keywordCell emojiCell\nkickItCommandParser\n extends abstractSubjectObjectCommandParser\n crux kickIt\nshootCommandParser\n extends abstractSubjectObjectCommandParser\n crux shoot\npickItUpCommandParser\n extends abstractSubjectObjectCommandParser\n crux pickItUp\nspawnCommandParser\n crux spawn\n extends abstractCommandParser\n cells keywordCell emojiCell\n catchAllCellType positionCell\nmoveToEmptySpotCommandParser\n crux moveToEmptySpot\n extends abstractCommandParser\n cells keywordCell\nremoveCommandParser\n description Remove this agent from the board.\n crux remove\n extends abstractCommandParser\n cells keywordCell\njavascriptCommandParser\n description An escape hatch so you can write custom javascript in a pinch.\n extends abstractCommandParser\n crux javascript\n catchAllParser javascriptLineParser\n cells keywordCell\nalertCommandParser\n extends abstractCommandParser\n crux alert\n catchAllCellType stringCell\nlogCommandParser\n extends abstractCommandParser\n crux log\n catchAllCellType stringCell\nnarrateCommandParser\n extends abstractCommandParser\n crux narrate\n catchAllCellType stringCell\npauseCommandParser\n extends abstractCommandParser\n crux pause\ndecreaseCommandParser\n extends abstractCommandParser\n description Decrease a property by 1.\n crux decrease\n cells keywordCell propertyNameCell\nincreaseCommandParser\n extends abstractCommandParser\n description Increase a property by 1.\n crux increase\n cells keywordCell propertyNameCell\nmoveCommandParser\n extends abstractCommandParser\n crux move\nturnRandomlyCommandParser\n extends abstractCommandParser\n crux turnRandomly\njitterCommandParser\n extends abstractCommandParser\n crux jitter\nturnTowardCommandParser\n description Turn to the closest agent of a certain type.\n extends abstractCommandParser\n crux turnToward\n cells keywordCell emojiCell\nturnFromCommandParser\n description Turn away from the closest agent of a certain type.\n extends abstractCommandParser\n crux turnFrom\n cells keywordCell emojiCell\nlearnCommandParser\n crux learn\n extends abstractCommandParser\n cells keywordCell behaviorNameCell\nunlearnCommandParser\n crux unlearn\n extends abstractCommandParser\n cells keywordCell behaviorNameCell\nabstractAgentAttributeParser\n cells keywordCell\nstringAttributeParser\n extends abstractAgentAttributeParser\n pattern ^\\w+ .+$\n catchAllCellType stringCell\n javascript\n compile() {\n return `${this.firstWord} = \"${this.getWord(1)}\"`\n }\nangleParser\n extends stringAttributeParser\n cells keywordCell angleCell\n cruxFromId\nagentStyleParser\n description Provide custom CSS for an agent type.\n extends stringAttributeParser\n cells keywordCell cssCell\n crux style\nagentHtmlParser\n description Provide custom HTML for each rendered agent.\n extends stringAttributeParser\n cells keywordCell htmlCell\n crux html\nabstractBooleanAttributeParser\n description A boolean attribute.\n extends abstractAgentAttributeParser\n javascript\n compile() {\n return `${this.firstWord} = true`\n }\nnoPaletteParser\n extends abstractBooleanAttributeParser\n cruxFromId\n description Don't show this agent in the palette.\nsolidTraitParser\n description If set other agents won't pass through these.\n extends abstractBooleanAttributeParser\n crux solid\nbouncyTraitParser\n description If set other agents will bounce off this after a collision.\n extends abstractBooleanAttributeParser\n crux bouncy\nabstractIntegerAttributeParser\n extends abstractAgentAttributeParser\n description An integer attribute.\n cells keywordCell integerCell\n javascript\n compile() {\n return `${this.firstWord} = ${this.getWord(1)}`\n }\ncustomIntegerAttributeParser\n pattern ^\\w+ \\d+$\n extends abstractIntegerAttributeParser\nhealthParser\n extends abstractIntegerAttributeParser\n cruxFromId\nsettingDefinitionParser\n description Define a configurable input.\n cells keywordCell settingValueCell\n pattern ^\\w+Setting .+$\nohayoLineParser\n description Data visualization code written for Ohayo.\n catchAllCellType ohayoCell\nstyleLineParser\n catchAllCellType cssCell\n catchAllParser styleLineParser\ntargetEmojiParser\n inScope abstractCommandParser\n cells emojiCell\nabstractEventParser\n cells keywordCell\n catchAllCellType probabilityCell\n javascript\n compile() {\n return ``\n }\nabstractInteractionEventParser\n extends abstractEventParser\n catchAllParser targetEmojiParser\nonHitParser\n extends abstractInteractionEventParser\n cruxFromId\n description Define what happens when this agent collides with other agents.\nonTouchParser\n extends abstractInteractionEventParser\n cruxFromId\n description Define what happens when this agent is adjacent to other agents.\nonNeighborsParser\n description Define what happens when a certain amount of neighbors are nearby.\n extends abstractInteractionEventParser\n inScope emojiAndNeighborConditionParser\n cruxFromId\nonDeathParser\n extends abstractEventParser\n cruxFromId\n inScope abstractCommandParser\n description Define what happens when this agent runs out of health.\nonTickParser\n extends abstractEventParser\n cruxFromId\n inScope abstractCommandParser\n description Define what happens each tick.\nemojiAndNeighborConditionParser\n inScope abstractCommandParser\n pattern ^.+ (<|>|=|<=|>=)+ .+$\n cells emojiCell conditionalOperatorCell neighborCountCell\nonExtinctParser\n cruxFromId\n inScope abstractCommandParser\n cells keywordCell emojiCell\n description Define what happens when a type of agent goes extinct from the board.\n javascript\n compile() {\n return \"\"\n }\nabstractIgnoreParser\n tags doNotSynthesize\n javascript\n compile () {\n return \"\"\n }\ncommentParser\n extends abstractIgnoreParser\n catchAllCellType commentCell\n cruxFromId\n catchAllParser commentLineParser\ncommentAliasParser\n description Alternate alias for a comment.\n crux #\n extends commentParser\nblankLineParser\n extends abstractIgnoreParser\n description Blank lines compile do nothing.\n cells blankCell\n pattern ^$\ncommentLineParser\n catchAllCellType commentCell\njavascriptLineParser\n catchAllCellType javascriptCell\nbehaviorAttributeParser\n cells behaviorNameCell\n pattern ^.*Behavior$\n javascript\n compile() {\n return \"\"\n }\nbehaviorDefinitionParser\n inScope abstractIgnoreParser abstractEventParser\n cells behaviorNameCell\n pattern ^.*Behavior$\n catchAllParser errorParser\n javascript\n compile() {\n return \"\"\n }","examples":"ants\n comment\n https://ccl.northwestern.edu/netlogo/models/Ants\n \n ⛰\n onTick 0.05\n spawn 🐜\n 🐜\n onTick\n jitter\n onHit\n 🥖\n pickItUp\n 🥖\n \n insert 3 🥖\n insert 1 ⛰\nbasketball\n question Is it better to shoot wildly or to bring it close to the basket?\n \n experiment Shoot rarely\n shotProbabilitySetting .02\n \n experiment\n shotProbabilitySetting .2\n \n experiment\n shotProbabilitySetting .4\n \n experiment Shoot right away\n shotProbabilitySetting .8\n \n 🏀\n onHit\n 🥅⛹️‍♂️\n narrate Blue scores!\n spawn 🏀 9⬇️ 15➡️\n spawn 🔵 18⬇️ 1➡️\n remove\n 🥅⛹️‍♀️\n narrate Red scores!\n spawn 🏀 9⬇️ 15➡️\n spawn 🔴 17⬇️ 1➡️\n remove\n \n \n moveEastToBlankSpotBehavior\n onTick\n moveToEmptySpot\n unlearn moveEastToBlankSpotBehavior\n \n \n 🔵\n angle East\n moveEastToBlankSpotBehavior\n 🔴\n angle East\n moveEastToBlankSpotBehavior\n \n \n ticksPerSecond 30\n \n hasBallBehavior\n comment Sprint toward net\n onTick .5\n turnToward net\n move\n narrate breaks toward the net.\n comment Shoot\n onTick shotProbabilitySetting\n turnToward net\n shoot\n narrate shoots!\n learn noBallBehavior\n unlearn hasBallBehavior\n comment Pass\n onTick .02\n turnToward team\n shoot\n narrate passes the ball!\n learn noBallBehavior\n unlearn hasBallBehavior\n \n noBallBehavior\n onTick .3\n turnToward 🏀\n move\n onHit\n 🏀\n pickItUp\n narrate has the ball\n learn hasBallBehavior\n unlearn noBallBehavior\n onTick .05\n turnFrom opponent\n move\n onTick .1\n turnFrom opponent\n jitter\n \n # Blue Team\n ⛹️‍♂️\n net 🥅⛹️‍♂️\n team ⛹️‍♂️\n opponent ⛹️‍♀️\n noBallBehavior\n \n # Red Team\n ⛹️‍♀️\n net 🥅⛹️‍♀️\n team ⛹️‍♀️\n opponent ⛹️‍♂️\n noBallBehavior\n \n # Baskets\n 🥅⛹️‍♂️\n html 🥅\n 🥅⛹️‍♀️\n html 🥅\n paste\n 🥅⛹️‍♂️ 8⬇️ 2➡️\n 🥅⛹️‍♀️ 8⬇️ 29➡️\n 🏀 9⬇️ 15➡️\n \n # Court\n 🪵\n solid\n rectangle 🪵 30 15 1 1\n \n size 30\n \n # Red Team\n paste\n ⛹️‍♀️ 9⬇️ 6➡️\n ⛹️‍♀️ 5⬇️ 6➡️\n ⛹️‍♀️ 11⬇️ 11➡️\n ⛹️‍♀️ 8⬇️ 11➡️\n ⛹️‍♀️ 5⬇️ 11➡️\n \n # Blue Team\n paste\n ⛹️‍♂️ 8⬇️ 25➡️\n ⛹️‍♂️ 6⬇️ 25➡️\n ⛹️‍♂️ 11⬇️ 20➡️\n ⛹️‍♂️ 7⬇️ 20➡️\n ⛹️‍♂️ 4⬇️ 20➡️\n \ncity\n ⛪️\n comment church\n 🏟\n comment stadium\n 🏥\n comment hospital\n 🏭\n comment factory\n 🏦\n comment bank\n 🏛\n comment courthouse\n 🏫\n comment school\n 🏡\n comment house\n 🏘\n comment houses\n 🎡\n comment park\n 🏪\n comment store\n 🚗\n onTick\n move\n move\n angle West\n 🚓\n onTick\n move\n move\n angle West\n 🚋\n comment subway\n onTick\n move\n move\n move\n angle West\n ⬜️\n comment road\n 🟩\n ⛳️\n size 20\n \n rectangle ⬜️ 10 20 0 0\n rectangle ⬜️ 10 1 0 10\n paste\n 🏛 9⬇️ 8➡️\n 🏭 1⬇️ 4➡️\n 🏭 1⬇️ 3➡️\n 🏭 1⬇️ 2➡️\n 🏭 1⬇️ 1➡️\n 🏡 18⬇️ 5➡️\n 🏡 18⬇️ 6➡️\n 🏡 18⬇️ 7➡️\n 🏡 18⬇️ 8➡️\ncops\n 🚗\n onTick .5\n jitter\n move\n 🚓\n onHit\n 🚗\n alert Got em!\n pause\n onTick .1\n turnToward 🚗\n move\n onTick .1\n move\n \n size 20\n ticksPerSecond 30\n \n paste\n 🚓 1⬇️ 1➡️\n 🚗 15⬇️ 5➡️\ncovid19\n 🦠\n \n question How long will the pandemic last?\n \n # Given someone has never been infected, what are the odds they get infected?\n succeptibilitySetting .95\n # What are odds of reinfection?\n reinfectionRateSetting .002\n \n # 1 is no lockdowns. 0 is total lockdown.\n freedomOfMovementSetting 1\n \n # What is starting population size?\n urbanPopulationSetting 150\n # What is starting rural population?\n ruralPopulationSetting 30\n # What is starting infected size?\n startingInfectedSetting 3\n \n # How many places can one get the vaccine?\n vaccineCentersSetting 5\n # How likely are people to seek the vaccine?\n vaccinationDesirabilitySetting .3\n # Given someone was vaxed, what are the odds they get infected?\n vaxSucceptibilitySetting .5\n \n experiment High Vaccination Rate, High Vaccine Efficacy\n vaccinationDesirabilitySetting .8\n vaxSucceptibilitySetting .05\n \n \n experiment High Vaccination Rate, Low Vaccine Efficacy\n vaccinationDesirabilitySetting .8\n vaxSucceptibilitySetting .75\n \n experiment Lockdown\n freedomOfMovementSetting .3\n \n experiment High Reinfection Rate\n reinfectionRateSetting .2\n \n \n insert startingInfectedSetting 🧟\n insert vaccineCentersSetting 💉\n \n insertCluster urbanPopulationSetting 🙍\n insert ruralPopulationSetting 🙍\n \n \n 🧟\n health 100\n onTick .03\n log recovered\n replaceWith 🦸‍♂️\n onTick\n decrease health\n jitter\n onDeath\n replaceWith 🪦\n \n 🦸‍♂️\n comment Recovered\n onTick\n jitter\n onTouch reinfectionRateSetting\n 🧟\n replaceWith 🧟\n \n lifeBehavior\n onTick freedomOfMovementSetting\n jitter\n \n seekVaccineBehavior\n onTick vaccinationDesirabilitySetting\n turnToward 💉\n move\n \n \n 🙍\n lifeBehavior\n seekVaccineBehavior\n onTouch innateImmunitySetting\n 🧟\n replaceWith 🧟\n 💉\n replaceWith 🧑🏽‍🚒\n \n \n 💉\n \n \n 🧑🏽‍🚒\n lifeBehavior\n onTouch vaxSucceptibilitySetting\n 🧟\n replaceWith 🧟\n \n \n \n \n onExtinct 🧟\n log No more cases.\n pause\n \n \n 🪦\n \n size 15\n ticksPerSecond 10\n \n report\n roughjs.line\n columns.keep 🧟\n roughjs.line Active Cases\n columns.keep 🪦\n roughjs.line Cumulative Deaths\n \n \n comment\n See Also\n - http://covidsim.eu/\n - http://modelingcommons.org/browse/one_model/6282#model_tabs_browse_info\n - https://github.com/maplerainresearch/covid19-sim-mesa/blob/master/model.py\n - https://www.frontiersin.org/articles/10.3389/fpubh.2020.563247/full\n - https://ncase.me/covid-19/\n - https://en.wikipedia.org/wiki/List_of_COVID-19_simulation_models\n \n \ncovid19simple\n question What is the effect of population density on pandemic duration?\n \n experiment\n insertCluster 100 🙍\n insertCluster 100 🙍\n insertCluster 100 🙍\n insertCluster 30 🙍\n insertCluster 30 🙍\n insertCluster 10 🙍\n \n experiment\n insert 200 🙍\n \n experiment\n insertCluster 200 🙍\n \n experiment\n insertCluster 200 🙍\n insert 200 🙍\n \n \n 🦠\n health 10\n onTick\n decrease health\n onDeath\n remove\n \n 🧟\n health 100\n onTick .03\n log recovered\n replaceWith 🦸‍♂️\n onTick\n decrease health\n jitter\n onDeath\n replaceWith 🪦\n \n 🦸‍♂️\n comment immune\n onTick\n jitter\n \n 🙍\n onTick\n jitter\n onTouch\n 🦠\n replaceWith 🧟\n 🧟\n replaceWith 🧟\n \n insert 1 🦠\n \n onExtinct 🧟\n log No more cases.\n pause\n \n \n 🪦\n \n size 15\n ticksPerSecond 10\n \n report\n roughjs.line\n columns.keep 🧟\n roughjs.line Active Cases\n columns.keep 🪦\n roughjs.line Cumulative Deaths\n \n \n comment\n See Also\n - http://covidsim.eu/\n - http://modelingcommons.org/browse/one_model/6282#model_tabs_browse_info\n - https://github.com/maplerainresearch/covid19-sim-mesa/blob/master/model.py\n - https://www.frontiersin.org/articles/10.3389/fpubh.2020.563247/full\n - https://ncase.me/covid-19/\n - https://en.wikipedia.org/wiki/List_of_COVID-19_simulation_models\n \neatTheBacon\n 🐕\n onTick .2\n turnToward 🥓\n move\n onTick .2\n jitter\n 🥓\n onTouch\n 🐕\n remove\n 🥦\n \n \n insert 1 🐕\n insert 3 🥓\n insert 10 🥦\n \nelevators\n 🛗\n onTick\n move\n move\n angle South\n bouncy\n onHit\n 🚶🏻\n pickItUp\n 🚶🏻\n angle West\n onTick\n move\n bouncy\n 🌾\n 🚪\n onTick .001\n spawn 🚶🏻\n 🪵\n solid\n 🚗\n \n \n size 15\n \n rectangle 🪵 20➡️ 47⬇️ 5 1\n rectangle 🌾 40➡️ 1⬇️ 0 48\n rectangle 🚪 1➡️ 45⬇️ 15 2\n paste\n 🛗 6⬇️ 19➡️\n 🛗 4⬇️ 22➡️\n 🛗 3⬇️ 20➡️\n 🛗 10⬇️ 13➡️\n 🛗 4⬇️ 9➡️\n 🛗 3⬇️ 11➡️\n 🚗 47⬇️ 30➡️\n 🚗 47⬇️ 28➡️\nfire\n question How fast do fires spread?\n \n 🌲\n onHit\n ⚡️\n replaceWith 🔥\n onTouch\n 🔥\n replaceWith 🔥\n \n ⚡️\n health 10\n onTick\n decrease health\n onDeath\n remove\n \n 🔥\n health 50\n onTick\n decrease health\n onDeath\n replaceWith ⬛️\n \n \n ⬛️\n comment Burnt forest\n html 🌲\n style filter:grayscale(100%);\n \n \n insert 50% 🌲\n onTick .3\n spawn ⚡️\nfireAdvanced\n question What is the effect of forest density on fire risk?\n \n experiment\n treeDensitySetting 10%\n \n experiment\n treeDensitySetting 20%\n \n experiment\n treeDensitySetting 40%\n \n experiment\n treeDensitySetting 80%\n \n catchFireSetting .3\n fireSpreadSetting .7\n fireLifetimeSetting 10\n lightningFrequencySetting .1\n \n 🌲\n onHit catchFireSetting\n ⚡️\n replaceWith 🔥\n onTouch fireSpreadSetting\n 🔥\n replaceWith 🔥\n \n ⚡️\n health 10\n onTick\n decrease health\n onDeath\n remove\n \n 🔥\n health fireLifetimeSetting\n onTick\n decrease health\n onDeath\n replaceWith ⬛️\n \n \n ⬛️\n comment Burnt forest\n html 🌲\n style filter:grayscale(100%);\n \n \n insert treeDensitySetting 🌲\n onTick lightningFrequencySetting\n spawn ⚡️\n \ngameOfLife\n question Can simple rules produce complex effects?\n \n ⬛️\n onNeighbors\n ⬛️ < 2\n replaceWith ◻️\n ⬛️ > 3\n replaceWith ◻️\n \n ◻️\n onNeighbors\n ⬛️ = 3\n replaceWith ⬛️\n \n insert 10% ⬛️\n fill ◻️\n size 15\ngameOfLifeAdvanced\n # Conway's Game of Life\n \n experiment\n neighborSetting 2\n \n experiment\n neighborSetting 3\n \n experiment\n neighborSetting 4\n \n experiment\n neighborSetting 5\n \n ⬛️\n onNeighbors\n ⬛️ < 2\n replaceWith ◻️\n ⬛️ > neighborSetting\n replaceWith ◻️\n \n ◻️\n onNeighbors\n ⬛️ = 3\n replaceWith ⬛️\n \n insert 10% ⬛️\n fill ◻️\n size 15\ngospersGliderGun\n ⬛️\n onNeighbors\n ⬛️ < 2\n replaceWith ◻️\n ⬛️ > 3\n replaceWith ◻️\n \n ◻️\n onNeighbors\n ⬛️ = 3\n replaceWith ⬛️\n \n # Gosper's Glider Gun\n \n draw\n ⬛️ \n ⬛️ ⬛️ \n ⬛️ ⬛️ ⬛️ ⬛️ \n ⬛️ ⬛️ ⬛️ ⬛️ ⬛️ ⬛️\n ⬛️ ⬛️ ⬛️ ⬛️ ⬛️ ⬛️\n ⬛️ ⬛️ ⬛️ ⬛️ ⬛️ ⬛️ ⬛️ ⬛️ \n ⬛️ ⬛️ ⬛️ ⬛️ ⬛️ \n ⬛️ ⬛️ \n ⬛️ ⬛️ \n \n \n fill ◻️\n \nmoths\n question Can you move the moths from one light to the other?\n \n 🦋\n onTick .1\n jitter\n move\n onTick .2\n turnToward 💡\n move\n move\n 💡\n \n ticksPerSecond 10\n size 20\n style\n .BoardComponent {background:black;}\n \n insert 10 🦋\n insert 2 💡\n \n comment\n http://www.netlogoweb.org/launch#http://www.netlogoweb.org/assets/modelslib/Sample%20Models/Biology/Moths.nlogo\nninjas\n 🤺\n health 100\n onTick\n decrease health\n jitter\n \n 🥷\n health 100\n onTick\n decrease health\n jitter\n \n insert 50 🤺\n insert 50 🥷\npong\n \n \n 🏐\n bouncy\n onTick\n move\n angle West\n 🏓\n angle East\n onHit\n 🏐\n kickIt\n 🏸\n angle West\n onHit\n 🏐\n kickIt\n 🪵\n solid\n \n size 20\n ticksPerSecond 10\n \n rectangle 🪵 30 15 5 5\n paste\n 🏓 13⬇️ 6➡️\n 🏸 13⬇️ 33➡️\n 🏐 13⬇️ 19➡️\n \n \npoolTable\n comment\n Needs balls to collide. Acceleration.\n \n 🎱\n bouncy\n onHit\n 🎱\n kickIt\n 🏐\n kickIt\n \n 🪵\n solid\n \n 🏐\n bouncy\n onTick .1\n turnRandomly\n kickIt\n onTick .5\n kickIt\n onHit\n 🎱\n kickIt\n angle West\n \n rectangle 🪵 40 20 0 7\n paste\n 🏐 17⬇️ 32➡️\n 🎱 12⬇️ 7➡️\n 🎱 14⬇️ 7➡️\n 🎱 16⬇️ 7➡️\n 🎱 18⬇️ 7➡️\n 🎱 20⬇️ 7➡️\n 🎱 22⬇️ 7➡️\n 🎱 21⬇️ 8➡️\n 🎱 19⬇️ 8➡️\n 🎱 17⬇️ 8➡️\n 🎱 15⬇️ 8➡️\n 🎱 13⬇️ 8➡️\n 🎱 20⬇️ 9➡️\n 🎱 18⬇️ 9➡️\n 🎱 16⬇️ 9➡️\n 🎱 14⬇️ 9➡️\n 🎱 15⬇️ 10➡️\n 🎱 17⬇️ 10➡️\n 🎱 19⬇️ 10➡️\n 🎱 18⬇️ 11➡️\n 🎱 16⬇️ 11➡️\n 🎱 17⬇️ 12➡️\nsoccer\n \n \n ⚽️\n onHit\n 🥅\n pause\n alert GOAAAAAAAAALLLL!\n bouncy\n \n ⛹️‍♂️\n onTick\n jitter\n onHit\n ⚽️\n kickIt\n \n ⛹️‍♀️\n onTick\n jitter\n onHit\n ⚽️\n kickIt\n 🥅\n 🪵\n solid\n \n size 20\n ticksPerSecond 10\n \n rectangle 🪵 30 15 5 5\n \n paste\n 🥅 13⬇️ 6➡️\n 🥅 13⬇️ 33➡️\n ⚽️ 13⬇️ 19➡️\n \n paste\n ⛹️‍♀️ 17⬇️ 14➡️\n ⛹️‍♀️ 17⬇️ 17➡️\n ⛹️‍♀️ 13⬇️ 17➡️\n ⛹️‍♀️ 13⬇️ 14➡️\n ⛹️‍♀️ 8⬇️ 14➡️\n ⛹️‍♀️ 8⬇️ 17➡️\n ⛹️‍♀️ 10⬇️ 14➡️\n ⛹️‍♀️ 9⬇️ 10➡️\n ⛹️‍♀️ 13⬇️ 8➡️\n ⛹️‍♀️ 13⬇️ 10➡️\n ⛹️‍♀️ 17⬇️ 10➡️\n \n paste\n ⛹️‍♂️ 13⬇️ 31➡️\n ⛹️‍♂️ 17⬇️ 28➡️\n ⛹️‍♂️ 13⬇️ 28➡️\n ⛹️‍♂️ 8⬇️ 29➡️\n ⛹️‍♂️ 8⬇️ 25➡️\n ⛹️‍♂️ 10⬇️ 25➡️\n ⛹️‍♂️ 13⬇️ 25➡️\n ⛹️‍♂️ 17⬇️ 25➡️\n ⛹️‍♂️ 17⬇️ 21➡️\n ⛹️‍♂️ 8⬇️ 21➡️\n ⛹️‍♂️ 13⬇️ 21➡️\n \nstartupIdeas\n question What is the effect of ideas vs ideas with revenue?\n \n 👨‍💼🔖\n comment person with an idea\n onTick\n jitter\n \n 👨‍💼💰\n comment peron with an idea\n that is making money\n onTick\n jitter\n \n 👨‍\n onTick .1\n jitter\n onTick .1\n turnToward 👨‍💼💰\n move\n \n \n size 10\n insert 200 👨‍\n insert 30 👨‍💼🔖\n insert 3 👨‍💼💰\n \n \nstore\n 🚶🏻\n onTick\n move\n angle North\n 🛒\n 🚪\n onTick .1\n spawn 🚶🏻\n 🪵\n solid\n \n size 25\n \n rectangle 🪵 30 15 3 3\n paste\n 🚪 16⬇️ 17➡️\n \nvirus\n question What might the spread of a simple virus look like?\n \n 🧟\n health 100\n onTick .9\n decrease health\n jitter\n onTick .01\n log recovered\n replaceWith 🦸‍♂️\n onDeath\n replaceWith 🪦\n \n 🙍\n onTick\n jitter\n onTouch\n 🧟\n replaceWith 🧟\n \n 🦸‍♂️\n onTick\n jitter\n \n insert 10% 🙍\n insert 1 🧟\n \n 🪦\n \n onExtinct 🧟\n log No more cases.\n pause\nwaves\n 🌊\n onTick\n move\n angle South\n \n size 25\n ticksPerSecond 5\n \n rectangle 🌊 100 1 0\n rectangle 🌊 100 1 0 6\n rectangle 🌊 100 1 0 11\nzombies\n question Can you protect the family from the zombies?\n \n 🧟‍♂️\n noPalette\n onTick\n jitter\n onHit\n 🪃\n replaceWith 🪦\n 💣\n replaceWith 🪦\n 👨‍👩‍👧‍👦\n pause\n alert TheyGotYou!\n \n 🧱\n solid\n \n 🔫\n onTick .1\n spawn 🪃\n \n 🪃\n noPalette\n angle West\n onTick\n move\n \n 💣\n \n 🪦\n noPalette\n comment Dead zombie\n \n 👨‍👩‍👧‍👦\n noPalette\n \n size 30\n ticksPerSecond 10\n \n insertCluster 30 🧟‍♂️ 1 1\n paste\n 👨‍👩‍👧‍👦 12⬇️ 11➡️"}
+ const SimConstants = {"grammar":"\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\nanyCell\nbooleanCell\nstringCell\n highlightScope string\nsettingValueCell\n highlightScope constant.numeric\ncssCell\n highlightScope string\njavascriptCell\n highlightScope string\nhtmlCell\n highlightScope string\nemojiCell\n highlightScope string\nohayoCell\n highlightScope string\nblankCell\ncodeCell\n highlightScope comment\ncommentCell\n highlightScope comment\nkeywordCell\n highlightScope keyword\ntextCell\n highlightScope string\nintegerCell\n highlightScope constant.numeric\nclassNameCell\n highlightScope keyword\nconditionalOperatorCell\n highlightScope keyword\n enum < > = <= >=\npositionCell\n highlightScope constant.numeric\nneighborCountCell\n extends integerCell\n min 0\n max 8\nintegerOrPercentCell\n highlightScope constant.numeric\nprobabilityCell\n description A number between 0 and 1\n highlightScope constant.numeric\npropertyNameCell\n highlightScope keyword\nangleCell\n enum North South East West NorthWest NorthEast SouthWest SouthEast\n highlightScope constant.numeric\njavascriptLineParser\n catchAllCellType javascriptCell\nabstractCommandParser\n cells keywordCell\nabstractSubjectObjectCommandParser\n extends abstractCommandParser\nreplaceWithCommandParser\n extends abstractSubjectObjectCommandParser\n crux replaceWith\n cells keywordCell emojiCell\nkickItCommandParser\n extends abstractSubjectObjectCommandParser\n crux kickIt\nshootCommandParser\n extends abstractSubjectObjectCommandParser\n crux shoot\npickItUpCommandParser\n extends abstractSubjectObjectCommandParser\n crux pickItUp\nspawnCommandParser\n crux spawn\n extends abstractCommandParser\n cells keywordCell emojiCell\n catchAllCellType positionCell\nemitCommandParser\n crux emit\n extends abstractCommandParser\n cells keywordCell emojiCell\nremoveCommandParser\n description Remove this agent from the board.\n crux remove\n extends abstractCommandParser\n cells keywordCell\njavascriptCommandParser\n description An escape hatch so you can write custom javascript in a pinch.\n extends abstractCommandParser\n crux javascript\n catchAllParser javascriptLineParser\n cells keywordCell\nalertCommandParser\n extends abstractCommandParser\n crux alert\n catchAllCellType stringCell\nlogCommandParser\n extends abstractCommandParser\n crux log\n catchAllCellType stringCell\nnarrateCommandParser\n extends abstractCommandParser\n crux narrate\n catchAllCellType stringCell\npauseCommandParser\n extends abstractCommandParser\n crux pause\ndecreaseCommandParser\n extends abstractCommandParser\n description Decrease a property by 1.\n crux decrease\n cells keywordCell propertyNameCell\nincreaseCommandParser\n extends abstractCommandParser\n description Increase a property by 1.\n crux increase\n cells keywordCell propertyNameCell\ngrowCommandParser\n extends abstractCommandParser\n crux grow\nshrinkCommandParser\n extends abstractCommandParser\n crux shrink\npulseCommandParser\n extends abstractCommandParser\n crux pulse\nlearnCommandParser\n crux learn\n extends abstractCommandParser\n cells keywordCell classNameCell\nunlearnCommandParser\n crux unlearn\n extends abstractCommandParser\n cells keywordCell classNameCell\nmoveCommandParser\n extends abstractCommandParser\n crux move\nmoveToEmptySpotCommandParser\n crux moveToEmptySpot\n extends abstractCommandParser\n cells keywordCell\nturnRandomlyCommandParser\n extends abstractCommandParser\n crux turnRandomly\njitterCommandParser\n extends abstractCommandParser\n crux jitter\nturnTowardCommandParser\n description Turn to the closest agent of a certain type.\n extends abstractCommandParser\n crux turnToward\n cells keywordCell emojiCell\nturnFromCommandParser\n description Turn away from the closest agent of a certain type.\n extends abstractCommandParser\n crux turnFrom\n cells keywordCell emojiCell\nagentDefinitionParser\n inScope abstractIgnoreParser abstractEventParser abstractAgentAttributeParser belongsToClassParser\n cells keywordCell\n catchAllParser errorParser\n compiler\n stringTemplate \n javascript\n compile() {\n const root = this.root\n const name = root.agentKeywordMap[this.firstWord]\n const normal = super.compile()\n const classIds = this.filter(node => node.parserId === \"belongsToClassParser\").map(node => node.getLine())\n const props = classIds.map(id => this.root.getNode(id).properties).join(\"\\n\\n\")\n return `class ${name} extends Agent {\n icon = \"${this.firstWord}\"\n classes = [${classIds.map(id => `\"${id}\"`).join(\",\")}]\n ${props}\n ${normal}\n }`\n }\nabstractAgentAttributeParser\n cells keywordCell\nstringAttributeParser\n extends abstractAgentAttributeParser\n pattern ^\\w+ .+$\n catchAllCellType stringCell\n javascript\n compile() {\n return `${this.firstWord} = \"${this.content}\"`\n }\nangleParser\n extends stringAttributeParser\n cells keywordCell angleCell\n cruxFromId\nagentStyleParser\n description Provide custom CSS for an agent type.\n extends stringAttributeParser\n cells keywordCell cssCell\n crux style\nagentHtmlParser\n description Provide custom HTML for each rendered agent.\n extends stringAttributeParser\n cells keywordCell htmlCell\n crux html\nabstractBooleanAttributeParser\n description A boolean attribute.\n extends abstractAgentAttributeParser\n javascript\n compile() {\n return `${this.firstWord} = true`\n }\nnoPaletteParser\n extends abstractBooleanAttributeParser\n cruxFromId\n description Don't show this agent in the palette.\nsolidTraitParser\n description If set other agents won't pass through these.\n extends abstractBooleanAttributeParser\n crux solid\nbouncyTraitParser\n description If set other agents will bounce off this after a collision.\n extends abstractBooleanAttributeParser\n crux bouncy\nabstractIntegerAttributeParser\n extends abstractAgentAttributeParser\n description An integer attribute.\n cells keywordCell integerCell\n javascript\n compile() {\n return `${this.firstWord} = ${this.getWord(1)}`\n }\ncustomIntegerAttributeParser\n pattern ^\\w+ \\d+$\n extends abstractIntegerAttributeParser\nhealthParser\n extends abstractIntegerAttributeParser\n cruxFromId\nagentWidthParser\n extends abstractIntegerAttributeParser\n description Width of the agent.\n crux width\nagentHeightParser\n extends abstractIntegerAttributeParser\n description Height of the agent.\n crux height\nspeedParser\n extends abstractIntegerAttributeParser\n description Movement speed. Default is 1\n crux speed\nsettingDefinitionParser\n description Define a configurable input.\n cells keywordCell settingValueCell\n pattern ^\\w+Setting .+$\nstyleLineParser\n catchAllCellType cssCell\n catchAllParser styleLineParser\nabstractSetupParser\nstyleParser\n description Optional CSS to load in BoardStyleComponent\n extends abstractSetupParser\n cells keywordCell\n cruxFromId\n catchAllParser styleLineParser\n javascript\n compile() {\n return \"\"\n }\nquestionParser\n cruxFromId\n description What are you trying to figure out?\n cells keywordCell\n catchAllCellType stringCell\n extends abstractSetupParser\natTimeParser\n cruxFromId\n description Run commands at a certain tick.\n cells keywordCell integerCell\n extends abstractSetupParser\n inScope abstractInjectCommandParser\nabstractSetupNumberParser\n cells keywordCell integerCell\n extends abstractSetupParser\n javascript\n compile() {\n return \"\"\n }\nheightParser\n description Height of the grid. Default is based on screen size.\n extends abstractSetupNumberParser\n crux height\nwidthParser\n description Width of the grid. Default is based on screen size.\n extends abstractSetupNumberParser\n crux width\nseedParser\n description If you'd like reproducible runs set a seed for the random number generator.\n extends abstractSetupNumberParser\n cruxFromId\nticksPerSecondParser\n description Time in milliseconds of one step.\n extends abstractSetupNumberParser\n cruxFromId\nreportParser\n cruxFromId\n description Define a custom report template.\n catchAllParser ohayoLineParser\n extends abstractSetupParser\n cells keywordCell\n javascript\n compile() {\n return \"\"\n }\nbelongsToClassParser\n cells classNameCell\n pattern ^.*Class$\n javascript\n compile() {\n return \"\"\n }\nclassDefinitionParser\n inScope abstractIgnoreParser abstractEventParser abstractAgentAttributeParser\n cells classNameCell\n pattern ^.*Class$\n catchAllParser errorParser\n javascript\n compile() {\n return \"\"\n }\n get properties() {\n return this.filter(node => node.doesExtend(\"abstractAgentAttributeParser\")).map(node => node.compile()).join(\"\\n\")\n }\ncommentLineParser\n catchAllCellType commentCell\nabstractIgnoreParser\n tags doNotSynthesize\n javascript\n compile () {\n return \"\"\n }\ncommentParser\n extends abstractIgnoreParser\n catchAllCellType commentCell\n cruxFromId\n catchAllParser commentLineParser\ncommentAliasParser\n description Alternate alias for a comment.\n crux #\n extends commentParser\nblankLineParser\n extends abstractIgnoreParser\n description Blank lines compile do nothing.\n cells blankCell\n pattern ^$\nabstractInjectCommandParser\ninsertParser\n extends abstractInjectCommandParser\n cells keywordCell integerOrPercentCell emojiCell\n cruxFromId\ninsertAtParser\n extends insertParser\n description Insert at X Y\n cells keywordCell emojiCell positionCell positionCell\n cruxFromId\ninsertClusterParser\n extends insertParser\n cruxFromId\n catchAllCellType integerCell\nfillParser\n description Fill all blank cells with this agent.\n extends abstractInjectCommandParser\n cells keywordCell emojiCell\n cruxFromId\ndrawParser\n extends abstractInjectCommandParser\n cells keywordCell\n cruxFromId\n catchAllParser drawLineParser\nrectangleDrawParser\n extends abstractInjectCommandParser\n example\n rectangle 🙂 width height x y 🙂\n cells keywordCell emojiCell integerCell integerCell\n catchAllCellType integerCell\n crux rectangle\npasteDrawParser\n extends abstractInjectCommandParser\n cells keywordCell\n crux paste\n catchAllParser pasteLineParser\ndrawLineParser\n catchAllCellType emojiCell\npasteLineParser\n catchAllCellType anyCell\n catchAllParser pasteLineParser\ntargetEmojiParser\n inScope abstractCommandParser\n cells emojiCell\nabstractEventParser\n cells keywordCell\n catchAllCellType probabilityCell\n javascript\n compile() {\n return ``\n }\nabstractInteractionEventParser\n extends abstractEventParser\n catchAllParser targetEmojiParser\nonHitParser\n extends abstractInteractionEventParser\n cruxFromId\n description Define what happens when this agent collides with other agents.\nonDeathParser\n extends abstractEventParser\n cruxFromId\n inScope abstractCommandParser\n description Define what happens when this agent runs out of health.\nonTickParser\n extends abstractEventParser\n cruxFromId\n inScope abstractCommandParser\n description Define what happens each tick.\nemojiAndNeighborConditionParser\n inScope abstractCommandParser\n pattern ^.+ (<|>|=|<=|>=)+ .+$\n cells emojiCell conditionalOperatorCell neighborCountCell\nonExtinctParser\n cruxFromId\n inScope abstractCommandParser\n cells keywordCell emojiCell\n description Define what happens when a type of agent goes extinct from the board.\n javascript\n compile() {\n return \"\"\n }\nexperimentParser\n cruxFromId\n cells keywordCell\n inScope abstractIgnoreParser abstractSetupParser abstractInjectCommandParser onTickParser onExtinctParser settingDefinitionParser\n catchAllCellType stringCell\nohayoLineParser\n description Data visualization code written for Ohayo.\n catchAllCellType ohayoCell\nerrorParser\n baseParser errorParser\nsimojiParser\n extensions simoji\n description A Tree Language that compiles to a TreeComponentFramework app.\n root\n inScope abstractIgnoreParser abstractSetupParser abstractInjectCommandParser onTickParser onExtinctParser classDefinitionParser experimentParser settingDefinitionParser\n catchAllParser agentDefinitionParser\n compilesTo javascript\n example\n 🦋\n onTick .1\n turnRandomly\n move\n onTick .2\n turnToward 💡\n move\n 💡\n \n insert 10 🦋\n insert 2 💡\n javascript\n get agentTypes() {\n return this.filter(node => node.parserId === \"agentDefinitionParser\")\n }","examples":"ants\n comment\n https://ccl.northwestern.edu/netlogo/models/Ants\n \n ⛰\n onTick 0.05\n spawn 🐜\n 🐜\n onTick\n jitter\n onHit\n 🥖\n pickItUp\n 🥖\n \n insert 3 🥖\n insert 1 ⛰\nbasketball\n question Is it better to shoot wildly or to bring it close to the basket?\n \n experiment Shoot rarely\n shotProbabilitySetting .02\n \n experiment\n shotProbabilitySetting .2\n \n experiment\n shotProbabilitySetting .4\n \n experiment Shoot right away\n shotProbabilitySetting .8\n \n thingClass\n width 30\n height 30\n \n personClass\n width 40\n height 40\n speed 20\n \n 🏀\n width 20\n height 20\n speed 30\n onHit\n 🥅⛹️‍♂️\n narrate Blue scores!\n spawn 🏀 15 9\n spawn 🔵 1 18\n remove\n 🥅⛹️‍♀️\n narrate Red scores!\n spawn 🏀 15 9\n spawn 🔴 1 17\n remove\n \n \n moveEastToBlankSpotClass\n onTick\n moveToEmptySpot\n unlearn moveEastToBlankSpotClass\n \n \n 🔵\n angle East\n moveEastToBlankSpotClass\n 🔴\n angle East\n moveEastToBlankSpotClass\n \n \n ticksPerSecond 30\n \n hasBallClass\n comment Sprint toward net\n onTick .5\n turnToward net\n move\n narrate breaks toward the net.\n comment Shoot\n onTick shotProbabilitySetting\n turnToward net\n shoot\n narrate shoots!\n learn noBallClass\n unlearn hasBallClass\n comment Pass\n onTick .02\n turnToward team\n shoot\n narrate passes the ball!\n learn noBallClass\n unlearn hasBallClass\n \n noBallClass\n onTick .3\n turnToward 🏀\n move\n onHit\n 🏀\n pickItUp\n narrate has the ball\n learn hasBallClass\n unlearn noBallClass\n onTick .05\n turnFrom opponent\n move\n onTick .1\n turnFrom opponent\n jitter\n \n # Blue Team\n ⛹️‍♂️\n personClass\n net 🥅⛹️‍♂️\n team ⛹️‍♂️\n opponent ⛹️‍♀️\n noBallClass\n \n # Red Team\n ⛹️‍♀️\n personClass\n net 🥅⛹️‍♀️\n team ⛹️‍♀️\n opponent ⛹️‍♂️\n noBallClass\n \n # Baskets\n 🥅⛹️‍♂️\n thingClass\n html 🥅\n 🥅⛹️‍♀️\n thingClass\n html 🥅\n \n paste\n 🥅⛹️‍♂️ 50 180\n 🥅⛹️‍♀️ 800 180\n 🏀 425 180\n \n # Court\n 🪵\n thingClass\n solid\n rectangle 🪵 30 15 1 1\n \n \n insertAt ⛹️‍♂️ 719 140\n insertAt ⛹️‍♂️ 733 242\n insertAt ⛹️‍♂️ 727 341\n insertAt ⛹️‍♂️ 645 172\n insertAt ⛹️‍♂️ 626 271\n insertAt ⛹️‍♀️ 167 142\n insertAt ⛹️‍♀️ 154 286\n insertAt ⛹️‍♀️ 307 139\n insertAt ⛹️‍♀️ 309 227\n insertAt ⛹️‍♀️ 320 341\ncity\n ⛪️\n comment church\n 🏟\n comment stadium\n 🏥\n comment hospital\n 🏭\n comment factory\n 🏦\n comment bank\n 🏛\n comment courthouse\n 🏫\n comment school\n 🏡\n comment house\n 🏘\n comment houses\n 🎡\n comment park\n 🏪\n comment store\n 🚗\n onTick\n move\n move\n angle West\n 🚓\n onTick\n move\n move\n angle West\n 🚋\n comment subway\n onTick\n move\n move\n move\n angle West\n ⬜️\n comment road\n 🟩\n ⛳️\n \n rectangle ⬜️ 10 20 0 0\n rectangle ⬜️ 10 1 0 10\n paste\n 🏛 8 9\n 🏭 4 1\n 🏭 3 1\n 🏭 2 1\n 🏭 1 1\n 🏡 5 18\n 🏡 6 18\n 🏡 7 18\n 🏡 8 18\ncops\n 🚗\n onTick .5\n jitter\n move\n 🚓\n onHit\n 🚗\n alert Got em!\n pause\n onTick .1\n turnToward 🚗\n move\n onTick .1\n move\n \n ticksPerSecond 30\n \n paste\n 🚓 1 1\n 🚗 5 15\ncovid19\n 🦠\n thingClass\n \n question How long will the pandemic last?\n \n # Given someone has never been infected, what are the odds they get infected?\n succeptibilitySetting .95\n # What are odds of reinfection?\n reinfectionRateSetting .002\n \n # 1 is no lockdowns. 0 is total lockdown.\n freedomOfMovementSetting 1\n \n # What is starting population size?\n urbanPopulationSetting 150\n # What is starting rural population?\n ruralPopulationSetting 30\n # What is starting infected size?\n startingInfectedSetting 3\n \n # How many places can one get the vaccine?\n vaccineCentersSetting 5\n # How likely are people to seek the vaccine?\n vaccinationDesirabilitySetting .3\n # Given someone was vaxed, what are the odds they get infected?\n vaxSucceptibilitySetting .5\n \n experiment High Vaccination Rate, High Vaccine Efficacy\n vaccinationDesirabilitySetting .8\n vaxSucceptibilitySetting .05\n \n \n experiment High Vaccination Rate, Low Vaccine Efficacy\n vaccinationDesirabilitySetting .8\n vaxSucceptibilitySetting .75\n \n experiment Lockdown\n freedomOfMovementSetting .1\n \n experiment High Reinfection Rate\n reinfectionRateSetting .3\n \n \n insert startingInfectedSetting 🧟\n insert vaccineCentersSetting 💉\n \n insertCluster urbanPopulationSetting 🙍\n insert ruralPopulationSetting 🙍\n \n thingClass\n width 20\n height 20\n speed 5\n \n 🧟\n thingClass\n health 100\n onTick .03\n log recovered\n replaceWith 🦸‍♂️\n onTick\n decrease health\n jitter\n onDeath\n replaceWith 🪦\n \n 🦸‍♂️\n thingClass\n comment Recovered\n onTick\n jitter\n onHit reinfectionRateSetting\n 🧟\n replaceWith 🧟\n \n aliveClass\n onTick freedomOfMovementSetting\n jitter\n \n vaccineSeekerClass\n onTick vaccinationDesirabilitySetting\n turnToward 💉\n move\n \n \n 🙍\n thingClass\n aliveClass\n vaccineSeekerClass\n onHit innateImmunitySetting\n 🧟\n replaceWith 🧟\n 💉\n replaceWith 🧑🏽‍🚒\n \n \n 💉\n thingClass\n \n \n 🧑🏽‍🚒\n thingClass\n aliveClass\n onHit vaxSucceptibilitySetting\n 🧟\n replaceWith 🧟\n \n \n \n \n onExtinct 🧟\n log No more cases.\n pause\n \n \n 🪦\n thingClass\n \n \n ticksPerSecond 10\n \n report\n roughjs.line\n columns.keep 🧟\n roughjs.line Active Cases\n columns.keep 🪦\n roughjs.line Cumulative Deaths\n \n \n comment\n See Also\n - http://covidsim.eu/\n - http://modelingcommons.org/browse/one_model/6282#model_tabs_browse_info\n - https://github.com/maplerainresearch/covid19-sim-mesa/blob/master/model.py\n - https://www.frontiersin.org/articles/10.3389/fpubh.2020.563247/full\n - https://ncase.me/covid-19/\n - https://en.wikipedia.org/wiki/List_of_COVID-19_simulation_models\n \n \ncovid19simple\n question What is the effect of population density on pandemic duration?\n \n experiment\n insertCluster 100 🙍\n insertCluster 100 🙍\n insertCluster 100 🙍\n insertCluster 30 🙍\n insertCluster 30 🙍\n insertCluster 10 🙍\n \n experiment\n insert 200 🙍\n \n experiment\n insertCluster 200 🙍\n \n experiment\n insertCluster 200 🙍\n insert 200 🙍\n \n \n 🦠\n health 10\n onTick\n decrease health\n onDeath\n remove\n \n 🧟\n health 100\n onTick .03\n log recovered\n replaceWith 🦸‍♂️\n onTick\n decrease health\n jitter\n onDeath\n replaceWith 🪦\n \n 🦸‍♂️\n comment immune\n onTick\n jitter\n \n 🙍\n onTick\n jitter\n onHit\n 🦠\n replaceWith 🧟\n 🧟\n replaceWith 🧟\n \n insert 1 🦠\n \n onExtinct 🧟\n log No more cases.\n pause\n \n \n 🪦\n \n ticksPerSecond 10\n \n report\n roughjs.line\n columns.keep 🧟\n roughjs.line Active Cases\n columns.keep 🪦\n roughjs.line Cumulative Deaths\n \n \n comment\n See Also\n - http://covidsim.eu/\n - http://modelingcommons.org/browse/one_model/6282#model_tabs_browse_info\n - https://github.com/maplerainresearch/covid19-sim-mesa/blob/master/model.py\n - https://www.frontiersin.org/articles/10.3389/fpubh.2020.563247/full\n - https://ncase.me/covid-19/\n - https://en.wikipedia.org/wiki/List_of_COVID-19_simulation_models\n \neatTheBacon\n 🐕\n onTick .2\n turnToward 🥓\n move\n onTick .2\n jitter\n 🥓\n onHit\n 🐕\n remove\n 🥦\n \n \n insert 1 🐕\n insert 3 🥓\n insert 10 🥦\n \nelevators\n 🛗\n onTick\n move\n move\n angle South\n bouncy\n onHit\n 🚶🏻\n pickItUp\n 🚶🏻\n angle West\n onTick\n move\n bouncy\n 🌾\n 🚪\n onTick .001\n spawn 🚶🏻\n 🪵\n solid\n 🚗\n \n \n rectangle 🪵 20 47 5 1\n rectangle 🌾 40 1 0 48\n rectangle 🚪 1 45 15 2\n paste\n 🛗 19 6\n 🛗 22 4\n 🛗 20 3\n 🛗 13 10\n 🛗 9 4\n 🛗 11 3\n 🚗 30 47\n 🚗 28 47\nfire\n question How fast do fires spread?\n \n 🌲\n width 20\n height 20\n onHit\n ⚡️\n replaceWith ⬛️\n replaceWith 🔥\n onHit\n 🔥\n replaceWith ⬛️\n replaceWith 🔥\n \n ⚡️\n health 10\n onTick\n decrease health\n onDeath\n remove\n \n 🔥\n width 40\n height 40\n health 50\n onTick\n jitter\n decrease health\n shrink\n \n ⬛️\n comment Burnt forest\n html 🌲\n style filter:grayscale(100%);\n \n \n insert 50% 🌲\n onTick .3\n spawn ⚡️\nfireAdvanced\n question What is the effect of forest density on fire risk?\n \n experiment\n treeDensitySetting 10%\n \n experiment\n treeDensitySetting 20%\n \n experiment\n treeDensitySetting 40%\n \n experiment\n treeDensitySetting 80%\n \n catchFireSetting .3\n fireSpreadSetting .7\n fireLifetimeSetting 10\n lightningFrequencySetting .1\n \n 🌲\n width 20\n height 20\n onHit catchFireSetting\n ⚡️\n replaceWith 🔥\n onHit fireSpreadSetting\n 🔥\n replaceWith 🔥\n \n ⚡️\n health 10\n onTick\n decrease health\n onDeath\n remove\n \n 🔥\n width 40\n height 40\n health fireLifetimeSetting\n onTick\n decrease health\n jitter\n shrink\n onDeath\n replaceWith ⬛️\n \n \n ⬛️\n comment Burnt forest\n html 🌲\n style filter:grayscale(100%);\n \n \n insert treeDensitySetting 🌲\n onTick lightningFrequencySetting\n spawn ⚡️\n \nmoths\n question Can you move the moths from one light to the other?\n \n 🦋\n speed 10\n height 30\n width 30\n onTick .5\n jitter\n move\n onTick .2\n turnToward 💡\n move\n move\n 💡\n height 100\n width 100\n \n ticksPerSecond 10\n style\n .BoardComponent {background:black;}\n \n insert 10 🦋\n insert 2 💡\n \n comment\n http://www.netlogoweb.org/launch#http://www.netlogoweb.org/assets/modelslib/Sample%20Models/Biology/Moths.nlogo\nninjas\n 🤺\n health 100\n onTick\n decrease health\n jitter\n \n 🥷\n health 100\n onTick\n decrease health\n jitter\n \n insert 50 🤺\n insert 50 🥷\npong\n \n 🏐\n bouncy\n speed 20\n onTick\n move\n angle West\n 🏓\n width 30\n height 30\n angle East\n onHit\n 🏐\n kickIt\n \n 🏸\n width 30\n height 30\n angle West\n onHit\n 🏐\n kickIt\n 🪵\n solid\n \n ticksPerSecond 10\n \n rectangle 🪵 50 15 50 50\n \n \n insertAt 🏐 273 125\n insertAt 🏓 90 120\n insertAt 🏸 510 121\npoolTable\n comment\n Needs balls to collide. Acceleration.\n \n 🎱\n bouncy\n onHit\n 🎱\n kickIt\n turnRandomly\n 🏐\n kickIt\n \n 🪵\n solid\n \n 🏐\n bouncy\n speed 10\n onTick .1\n kickIt\n onTick .5\n kickIt\n onHit\n 🎱\n turnRandomly\n kickIt\n move\n turnRandomly\n angle West\n \n rectangle 🪵 40 20 10 70\n paste\n 🏐 320 170\n 🎱 70 120\n 🎱 70 140\n 🎱 70 160\n 🎱 70 180\n 🎱 70 200\n 🎱 70 220\n 🎱 80 210\n 🎱 80 190\n 🎱 80 170\n 🎱 80 150\n 🎱 80 130\n 🎱 90 200\n 🎱 90 180\n 🎱 90 160\n 🎱 90 140\n 🎱 100 150\n 🎱 100 170\n 🎱 100 190\n 🎱 110 180\n 🎱 110 160\n 🎱 120 170\nsoccer\n thingClass\n width 40\n height 40\n speed 20\n \n ⚽️\n width 20\n height 20\n speed 30\n onHit\n 🥅\n pause\n alert GOAAAAAAAAALLLL!\n bouncy\n \n ⛹️‍♂️\n thingClass\n onTick\n jitter\n onHit\n ⚽️\n kickIt\n \n ⛹️‍♀️\n thingClass\n onTick\n jitter\n onHit\n ⚽️\n kickIt\n \n 🥅\n thingClass\n 🪵\n thingClass\n solid\n \n ticksPerSecond 10\n \n rectangle 🪵 30 15 5 5\n \n \n seed 1681189626875\n height 862\n width 1354\n insertAt 🥅 1095 293\n insertAt 🥅 98 294\n insertAt ⛹️‍♂️ 993 303\n insertAt ⛹️‍♂️ 923 114\n insertAt ⛹️‍♂️ 923 244\n insertAt ⛹️‍♂️ 954 449\n insertAt ⛹️‍♂️ 844 129\n insertAt ⛹️‍♂️ 842 246\n insertAt ⛹️‍♂️ 849 337\n insertAt ⛹️‍♂️ 866 454\n insertAt ⛹️‍♂️ 722 148\n insertAt ⛹️‍♂️ 705 273\n insertAt ⛹️‍♂️ 722 423\n insertAt ⛹️‍♀️ 443 168\n insertAt ⛹️‍♀️ 496 285\n insertAt ⛹️‍♀️ 481 441\n insertAt ⛹️‍♀️ 317 137\n insertAt ⛹️‍♀️ 321 253\n insertAt ⛹️‍♀️ 342 334\n insertAt ⛹️‍♀️ 333 471\n insertAt ⛹️‍♀️ 196 505\n insertAt ⛹️‍♀️ 182 395\n insertAt ⛹️‍♀️ 212 192\n insertAt ⛹️‍♀️ 161 318\n insertAt ⚽️ 618 322\nstartupIdeas\n question What is the effect of ideas vs ideas with revenue?\n \n personClass\n width 25\n height 25\n speed 10\n \n 👨‍💼🔖\n comment person with an idea\n personClass\n onTick\n jitter\n \n 👨‍💼💰\n width 50\n height 50\n comment peron with an idea\n that is making money\n personClass\n onTick\n jitter\n \n 👨‍\n personClass\n onTick .1\n jitter\n onTick .1\n turnToward 👨‍💼💰\n move\n \n \n insert 200 👨‍\n insert 30 👨‍💼🔖\n insert 3 👨‍💼💰\n \n \nstore\n bigClass\n width 20\n height 20\n \n 🚶🏻\n bigClass\n speed 10\n onTick\n move\n onTick .4\n turnRandomly\n move\n onTick .5\n turnToward 🛒\n onHit\n 🛒\n pickItUp\n angle South\n 🛒\n bigClass\n 🚪\n bigClass\n onTick .1\n spawn 🚶🏻\n 🪵\n bigClass\n solid\n \n rectangle 🪵 30 15 30 30\n paste\n 🚪 170 120\n \n \n \n insertAt 🛒 432 95\n insertAt 🛒 435 212\ntalking\n 🙂\n width 30\n height 30\n onTick .1\n turnToward 🙂\n emit 💬\n \n \n 💬\n health 5\n speed 10\n onHit\n 🙂\n decrease health\n decrease health\n decrease health\n decrease health\n decrease health\n decrease health\n onTick\n move\n decrease health\n onDeath\n remove\n \n \n rectangle 🙂 5 5 100 100 🙂 20\n \n textClass\n width 20\n height 20\n \n 1\n html Imagine a world with 25 people\n textClass\n \n insertAt 1 70 60\nvirus\n question What might the spread of a simple virus look like?\n \n thingClass\n width 20\n height 20\n speed 20\n \n 🧟\n thingClass\n health 100\n onTick .9\n decrease health\n jitter\n onTick .01\n log recovered\n replaceWith 🦸‍♂️\n onDeath\n replaceWith 🪦\n \n 🙍\n thingClass\n onTick\n jitter\n onHit\n 🧟\n replaceWith 🧟\n \n 🦸‍♂️\n # Recovered\n thingClass\n onTick\n jitter\n \n insert 10% 🙍\n insert 1 🧟\n \n 🪦\n thingClass\n \n onExtinct 🧟\n log No more cases.\n pause\nwaves\n 🌊\n onTick\n move\n angle South\n \n ticksPerSecond 5\n \n rectangle 🌊 100 1 0\n rectangle 🌊 100 1 0 6\n rectangle 🌊 100 1 0 11\nzombies\n question Can you protect the family from the zombies?\n \n bigClass\n width 40\n height 40\n \n 🧟‍♂️\n bigClass\n speed 10\n noPalette\n onTick\n jitter\n onHit\n 🪃\n replaceWith 🪦\n 💣\n replaceWith 🪦\n 👨‍👩‍👧‍👦\n pause\n alert TheyGotYou!\n \n 🧱\n bigClass\n solid\n \n 🔫\n bigClass\n onTick .1\n spawn 🪃\n \n 🪃\n speed 50\n bigClass\n width 50\n height 50\n noPalette\n angle West\n onTick\n move\n \n 💣\n bigClass\n \n 🪦\n bigClass\n noPalette\n comment Dead zombie\n \n 👨‍👩‍👧‍👦\n bigClass\n noPalette\n \n ticksPerSecond 10\n \n insertCluster 30 🧟‍♂️ 1 1\n paste\n 👨‍👩‍👧‍👦 400 400"}
dist/simoji.grammar
Changed around line 1
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
Changed around line 53: textCell
- behaviorNameCell
+ classNameCell
Changed around line 74: propertyNameCell
- errorParser
- baseParser errorParser
- simojiParser
- extensions simoji
- description A Tree Language that compiles to a TreeComponentFramework app.
- root
- inScope abstractIgnoreParser abstractSetupParser abstractInjectCommandParser onTickParser onExtinctParser behaviorDefinitionParser experimentParser settingDefinitionParser
- catchAllParser agentDefinitionParser
- compilesTo javascript
- example
- 🦋
- onTick .1
- turnRandomly
- move
- onTick .2
- turnToward 💡
- move
- 💡
-
- insert 10 🦋
- insert 2 💡
- javascript
- get agentTypes() {
- return this.filter(node => node.parserId === "agentDefinitionParser")
- }
- experimentParser
- cruxFromId
- cells keywordCell
- inScope abstractIgnoreParser abstractSetupParser abstractInjectCommandParser onTickParser onExtinctParser settingDefinitionParser
- catchAllCellType stringCell
- abstractSetupParser
- atTimeParser
- cruxFromId
- description Run commands at a certain tick.
- cells keywordCell integerCell
- extends abstractSetupParser
- inScope abstractInjectCommandParser
- abstractSetupNumberParser
- cells keywordCell integerCell
- extends abstractSetupParser
- javascript
- compile() {
- return ""
- }
- sizeParser
- description Size of a grid cell in pixels. Min is 10. Max is 200.
- extends abstractSetupNumberParser
- cruxFromId
- rowsParser
- description Number of rows in the grid. Default is based on screen size.
- extends abstractSetupNumberParser
- cruxFromId
- columnsParser
- description Number of columns in the grid. Default is based on screen size.
- extends abstractSetupNumberParser
- cruxFromId
- seedParser
- description If you'd like reproducible runs set a seed for the random number generator.
- extends abstractSetupNumberParser
- cruxFromId
- ticksPerSecondParser
- description Time in milliseconds of one step.
- extends abstractSetupNumberParser
- cruxFromId
- reportParser
- cruxFromId
- description Define a custom report template.
- catchAllParser ohayoLineParser
- extends abstractSetupParser
- cells keywordCell
- javascript
- compile() {
- return ""
- }
- styleParser
- description Optional CSS to load in BoardStyleComponent
- extends abstractSetupParser
- cells keywordCell
- cruxFromId
- catchAllParser styleLineParser
- javascript
- compile() {
- return ""
- }
- questionParser
- cruxFromId
- description What are you trying to figure out?
- cells keywordCell
- catchAllCellType stringCell
- extends abstractSetupParser
- abstractInjectCommandParser
- fillParser
- description Fill all blank cells with this agent.
- extends abstractInjectCommandParser
- cells keywordCell emojiCell
- cruxFromId
- drawParser
- extends abstractInjectCommandParser
- cells keywordCell
- cruxFromId
- catchAllParser drawLineParser
- insertParser
- extends abstractInjectCommandParser
- cells keywordCell integerOrPercentCell emojiCell
- cruxFromId
- insertAtParser
- extends insertParser
- description Insert at X Y
- cells keywordCell emojiCell positionCell positionCell
- cruxFromId
- insertClusterParser
- extends insertParser
- cruxFromId
- catchAllCellType integerCell
- rectangleDrawParser
- extends abstractInjectCommandParser
- cells keywordCell emojiCell integerCell integerCell
- catchAllCellType integerCell
- crux rectangle
- pasteDrawParser
- extends abstractInjectCommandParser
- cells keywordCell
- crux paste
- catchAllParser pasteLineParser
- drawLineParser
- catchAllCellType emojiCell
- pasteLineParser
- catchAllCellType anyCell
- catchAllParser pasteLineParser
- agentDefinitionParser
- inScope abstractIgnoreParser abstractEventParser abstractAgentAttributeParser behaviorAttributeParser
- cells keywordCell
- catchAllParser errorParser
- compiler
- stringTemplate
- javascript
- compile() {
- const root = this.root
- const name = root.agentKeywordMap[this.firstWord]
- const normal = super.compile()
- const behaviors = this.filter(node => node.parserId === "behaviorAttributeParser")
- .map(behavior => `"${behavior.getLine()}"`)
- .join(",")
- return `class ${name} extends Agent {
- icon = "${this.firstWord}"
- behaviors = [${behaviors}]
- ${normal}
- }`
- }
+ javascriptLineParser
+ catchAllCellType javascriptCell
Changed around line 98: spawnCommandParser
- moveToEmptySpotCommandParser
- crux moveToEmptySpot
+ emitCommandParser
+ crux emit
- cells keywordCell
+ cells keywordCell emojiCell
Changed around line 138: increaseCommandParser
+ growCommandParser
+ extends abstractCommandParser
+ crux grow
+ shrinkCommandParser
+ extends abstractCommandParser
+ crux shrink
+ pulseCommandParser
+ extends abstractCommandParser
+ crux pulse
+ learnCommandParser
+ crux learn
+ extends abstractCommandParser
+ cells keywordCell classNameCell
+ unlearnCommandParser
+ crux unlearn
+ extends abstractCommandParser
+ cells keywordCell classNameCell
+ moveToEmptySpotCommandParser
+ crux moveToEmptySpot
+ extends abstractCommandParser
+ cells keywordCell
Changed around line 178: turnFromCommandParser
- learnCommandParser
- crux learn
- extends abstractCommandParser
- cells keywordCell behaviorNameCell
- unlearnCommandParser
- crux unlearn
- extends abstractCommandParser
- cells keywordCell behaviorNameCell
+ agentDefinitionParser
+ inScope abstractIgnoreParser abstractEventParser abstractAgentAttributeParser belongsToClassParser
+ cells keywordCell
+ catchAllParser errorParser
+ compiler
+ stringTemplate
+ javascript
+ compile() {
+ const root = this.root
+ const name = root.agentKeywordMap[this.firstWord]
+ const normal = super.compile()
+ const classIds = this.filter(node => node.parserId === "belongsToClassParser").map(node => node.getLine())
+ const props = classIds.map(id => this.root.getNode(id).properties).join("\n\n")
+ return `class ${name} extends Agent {
+ icon = "${this.firstWord}"
+ classes = [${classIds.map(id => `"${id}"`).join(",")}]
+ ${props}
+ ${normal}
+ }`
+ }
Changed around line 206: stringAttributeParser
- return `${this.firstWord} = "${this.getWord(1)}"`
+ return `${this.firstWord} = "${this.content}"`
Changed around line 255: customIntegerAttributeParser
+ agentWidthParser
+ extends abstractIntegerAttributeParser
+ description Width of the agent.
+ crux width
+ agentHeightParser
+ extends abstractIntegerAttributeParser
+ description Height of the agent.
+ crux height
+ speedParser
+ extends abstractIntegerAttributeParser
+ description Movement speed. Default is 1
+ crux speed
- ohayoLineParser
- description Data visualization code written for Ohayo.
- catchAllCellType ohayoCell
+ abstractSetupParser
+ styleParser
+ description Optional CSS to load in BoardStyleComponent
+ extends abstractSetupParser
+ cells keywordCell
+ cruxFromId
+ catchAllParser styleLineParser
+ javascript
+ compile() {
+ return ""
+ }
+ questionParser
+ cruxFromId
+ description What are you trying to figure out?
+ cells keywordCell
+ catchAllCellType stringCell
+ extends abstractSetupParser
+ atTimeParser
+ cruxFromId
+ description Run commands at a certain tick.
+ cells keywordCell integerCell
+ extends abstractSetupParser
+ inScope abstractInjectCommandParser
+ abstractSetupNumberParser
+ cells keywordCell integerCell
+ extends abstractSetupParser
+ javascript
+ compile() {
+ return ""
+ }
+ heightParser
+ description Height of the grid. Default is based on screen size.
+ extends abstractSetupNumberParser
+ crux height
+ widthParser
+ description Width of the grid. Default is based on screen size.
+ extends abstractSetupNumberParser
+ crux width
+ seedParser
+ description If you'd like reproducible runs set a seed for the random number generator.
+ extends abstractSetupNumberParser
+ cruxFromId
+ ticksPerSecondParser
+ description Time in milliseconds of one step.
+ extends abstractSetupNumberParser
+ cruxFromId
+ reportParser
+ cruxFromId
+ description Define a custom report template.
+ catchAllParser ohayoLineParser
+ extends abstractSetupParser
+ cells keywordCell
+ javascript
+ compile() {
+ return ""
+ }
+ belongsToClassParser
+ cells classNameCell
+ pattern ^.*Class$
+ javascript
+ compile() {
+ return ""
+ }
+ classDefinitionParser
+ inScope abstractIgnoreParser abstractEventParser abstractAgentAttributeParser
+ cells classNameCell
+ pattern ^.*Class$
+ catchAllParser errorParser
+ javascript
+ compile() {
+ return ""
+ }
+ get properties() {
+ return this.filter(node => node.doesExtend("abstractAgentAttributeParser")).map(node => node.compile()).join("\n")
+ }
+ commentLineParser
+ catchAllCellType commentCell
+ abstractIgnoreParser
+ tags doNotSynthesize
+ javascript
+ compile () {
+ return ""
+ }
+ commentParser
+ extends abstractIgnoreParser
+ catchAllCellType commentCell
+ cruxFromId
+ catchAllParser commentLineParser
+ commentAliasParser
+ description Alternate alias for a comment.
+ crux #
+ extends commentParser
+ blankLineParser
+ extends abstractIgnoreParser
+ description Blank lines compile do nothing.
+ cells blankCell
+ pattern ^$
+ abstractInjectCommandParser
+ insertParser
+ extends abstractInjectCommandParser
+ cells keywordCell integerOrPercentCell emojiCell
+ cruxFromId
+ insertAtParser
+ extends insertParser
+ description Insert at X Y
+ cells keywordCell emojiCell positionCell positionCell
+ cruxFromId
+ insertClusterParser
+ extends insertParser
+ cruxFromId
+ catchAllCellType integerCell
+ fillParser
+ description Fill all blank cells with this agent.
+ extends abstractInjectCommandParser
+ cells keywordCell emojiCell
+ cruxFromId
+ drawParser
+ extends abstractInjectCommandParser
+ cells keywordCell
+ cruxFromId
+ catchAllParser drawLineParser
+ rectangleDrawParser
+ extends abstractInjectCommandParser
+ example
+ rectangle 🙂 width height x y 🙂
+ cells keywordCell emojiCell integerCell integerCell
+ catchAllCellType integerCell
+ crux rectangle
+ pasteDrawParser
+ extends abstractInjectCommandParser
+ cells keywordCell
+ crux paste
+ catchAllParser pasteLineParser
+ drawLineParser
+ catchAllCellType emojiCell
+ pasteLineParser
+ catchAllCellType anyCell
+ catchAllParser pasteLineParser
Changed around line 429: onHitParser
- onTouchParser
- extends abstractInteractionEventParser
- cruxFromId
- description Define what happens when this agent is adjacent to other agents.
- onNeighborsParser
- description Define what happens when a certain amount of neighbors are nearby.
- extends abstractInteractionEventParser
- inScope emojiAndNeighborConditionParser
- cruxFromId
Changed around line 452: onExtinctParser
- abstractIgnoreParser
- tags doNotSynthesize
- javascript
- compile () {
- return ""
- }
- commentParser
- extends abstractIgnoreParser
- catchAllCellType commentCell
+ experimentParser
- catchAllParser commentLineParser
- commentAliasParser
- description Alternate alias for a comment.
- crux #
- extends commentParser
- blankLineParser
- extends abstractIgnoreParser
- description Blank lines compile do nothing.
- cells blankCell
- pattern ^$
- commentLineParser
- catchAllCellType commentCell
- javascriptLineParser
- catchAllCellType javascriptCell
- behaviorAttributeParser
- cells behaviorNameCell
- pattern ^.*Behavior$
- javascript
- compile() {
- return ""
- }
- behaviorDefinitionParser
- inScope abstractIgnoreParser abstractEventParser
- cells behaviorNameCell
- pattern ^.*Behavior$
- catchAllParser errorParser
+ cells keywordCell
+ inScope abstractIgnoreParser abstractSetupParser abstractInjectCommandParser onTickParser onExtinctParser settingDefinitionParser
+ catchAllCellType stringCell
+ ohayoLineParser
+ description Data visualization code written for Ohayo.
+ catchAllCellType ohayoCell
+ errorParser
+ baseParser errorParser
+ simojiParser
+ extensions simoji
+ description A Tree Language that compiles to a TreeComponentFramework app.
+ root
+ inScope abstractIgnoreParser abstractSetupParser abstractInjectCommandParser onTickParser onExtinctParser classDefinitionParser experimentParser settingDefinitionParser
+ catchAllParser agentDefinitionParser
+ compilesTo javascript
+ example
+ 🦋
+ onTick .1
+ turnRandomly
+ move
+ onTick .2
+ turnToward 💡
+ move
+ 💡
+
+ insert 10 🦋
+ insert 2 💡
- compile() {
- return ""
+ get agentTypes() {
+ return this.filter(node => node.parserId === "agentDefinitionParser")
dist/simoji.js
Changed around line 3: const yodash = {}
-
- yodash.parseInts = (arr, start) => arr.map((item, index) => (index >= start ? parseInt(item) : item))
-
- yodash.getRandomAngle = randomNumberGenerator => {
- const r1 = randomNumberGenerator()
- const r2 = randomNumberGenerator()
- if (r1 > 0.5) return r2 > 0.5 ? Directions.North : Directions.South
- return r2 > 0.5 ? Directions.West : Directions.East
- }
-
- yodash.flipAngle = angle => {
- let newAngle = ""
- if (angle.includes(Directions.North)) newAngle += Directions.South
- else if (angle.includes(Directions.South)) newAngle += Directions.North
- if (angle.includes(Directions.East)) newAngle += Directions.West
- else if (angle.includes(Directions.West)) newAngle += Directions.East
- return newAngle
- }
-
Changed around line 13: yodash.compare = (left, operator, right) => {
+ // Todo: why do we do this? Very confusing. Caught me by surprise.
+ // Is it because sometimes the class name is not valid JS?
- const clone = program.clone()
- clone.filter(node => node.parserId !== ParserTypes.agentDefinitionParser).forEach(node => node.destroy())
- clone.agentKeywordMap = {}
- clone.agentTypes.forEach((node, index) => (clone.agentKeywordMap[node.firstWord] = `simAgent${index}`))
- const compiled = clone.compile()
- const agentMap = Object.keys(clone.agentKeywordMap)
- .map(key => `"${key}":${clone.agentKeywordMap[key]}`)
+ const agentKeywordMap = {}
+ program.agentKeywordMap = agentKeywordMap // confusing
+ const agentDefs = program.filter(node => node.parserId === ParserTypes.agentDefinitionParser)
+ agentDefs.forEach((node, index) => (agentKeywordMap[node.firstWord] = `simAgent${index}`))
+ const compiled = agentDefs.map(node => node.compile()).join("\n")
+ const agentMap = Object.keys(agentKeywordMap)
+ .map(key => `"${key}":${agentKeywordMap[key]}`)
Changed around line 51: yodash.patchExperimentAndReplaceSymbols = (program, experiment) => {
- yodash.getBestAngle = (targets, position) => {
+ yodash.getClosest = (targets, subject) => {
- targets.forEach(candidate => {
- const pos = candidate.position
- const distance = math.distance([pos.down, pos.right], [position.down, position.right])
+ targets.forEach(agent => {
+ if (agent === subject) return
+ const distance = math.distance([agent.y, agent.x], [subject.y, subject.x])
- target = candidate
+ target = agent
- const heading = target.position
- return yodash.angle(position.down, position.right, heading.down, heading.right)
- }
-
- yodash.angle = (cx, cy, ex, ey) => {
- const dy = ey - cy
- const dx = ex - cx
- let theta = Math.atan2(dy, dx) // range (-PI, PI]
- theta *= 180 / Math.PI // rads to degs, range (-180, 180]
- //if (theta < 0) theta = 360 + theta; // range [0, 360)
- let angle = ""
-
- if (Math.abs(theta) > 90) angle += Directions.North
- else angle += Directions.South
- if (theta < 0) angle += Directions.West
- else angle += Directions.East
- return angle
- }
-
- yodash.getRandomLocation = (rows, cols, randomNumberGenerator) => {
- const maxRight = cols
- const maxBottom = rows
- const right = Math.round(randomNumberGenerator() * maxRight)
- const down = Math.round(randomNumberGenerator() * maxBottom)
- return { right, down }
+ return target
- yodash.getRandomLocationHash = (rows, cols, occupiedSpots, randomNumberGenerator) => {
- const { right, down } = yodash.getRandomLocation(rows, cols, randomNumberGenerator)
- const hash = yodash.makePositionHash({ right, down })
- if (occupiedSpots && occupiedSpots.has(hash))
- return yodash.getRandomLocationHash(rows, cols, occupiedSpots, randomNumberGenerator)
- return hash
- }
-
- yodash.fill = (rows, cols, occupiedSpots, emoji) => {
- const board = []
- while (rows >= 0) {
- let col = cols
- while (col >= 0) {
- const hash = yodash.makePositionHash({ right: col, down: rows })
- col--
- if (occupiedSpots.has(hash)) continue
- board.push(`${emoji} ${hash}`)
- }
- rows--
+ yodash.unitVector = (objA, objB) => {
+ // calculate direction vector (delta)
+ const delta = {
+ x: objB.x - objA.x,
+ y: objB.y - objA.y
- return board.join("\n")
- }
-
- yodash.positionsAdjacentTo = position => {
- let { right, down } = position
- const positions = []
- down--
- positions.push({ down, right })
- right--
- positions.push({ down, right })
- right++
- right++
- positions.push({ down, right })
- down++
- positions.push({ down, right })
- right--
- right--
- positions.push({ down, right })
- down++
- positions.push({ down, right })
- right++
- positions.push({ down, right })
- right++
- positions.push({ down, right })
- return positions
- }
- yodash.makePositionHash = position => `${position.down + "⬇️ " + position.right + "➡️"}`
-
- yodash.makeRectangle = (character = "🧱", width = 20, height = 20, startRight = 0, startDown = 0) => {
- if (width < 1 || height < 1) {
- return ""
- }
- const cells = []
- let row = 0
- while (row < height) {
- let col = 0
- while (col < width) {
- const isPerimeter = row === 0 || row === height - 1 || col === 0 || col === width - 1
- if (isPerimeter)
- cells.push(
- `${character} ${yodash.makePositionHash({
- down: startDown + row,
- right: startRight + col
- })}`
- )
- col++
- }
- row++
- }
- return cells.join("\n")
- }
+ // calculate magnitude of delta (distance between two points)
+ const magDelta = Math.sqrt(delta.x * delta.x + delta.y * delta.y)
- yodash.parsePosition = words => {
+ // calculate unit vector (normalize direction vector by dividing by magnitude)
- down: parseInt(words.find(word => word.includes("⬇️")).slice(0, -1)),
- right: parseInt(words.find(word => word.includes("➡️")).slice(0, -1))
- }
- }
-
- yodash.draw = str => {
- const lines = str.split("\n")
- const output = []
- for (let index = 0; index < lines.length; index++) {
- const words = lines[index].split(" ")
- for (let wordIndex = 0; wordIndex < words.length; wordIndex++) {
- const word = words[wordIndex]
- if (word !== "") output.push(`${word} ${yodash.makePositionHash({ down: index, right: wordIndex })}`)
- }
- }
- return output.join("\n")
- }
-
- yodash.updateOccupiedSpots = (board, occupiedSpots) => {
- new TreeNode(board).forEach(line => {
- occupiedSpots.add(yodash.makePositionHash(yodash.parsePosition(line.words)))
- })
- }
-
- yodash.getAllAvailableSpots = (rows, cols, occupiedSpots, rowStart = 0, colStart = 0) => {
- const availablePositions = []
- let down = rows
- while (down >= rowStart) {
- let right = cols
- while (right >= colStart) {
- const hash = yodash.makePositionHash({ right, down })
- if (!occupiedSpots.has(hash)) availablePositions.push({ right, down, hash })
- right--
- }
- down--
+ x: delta.x / magDelta,
+ y: delta.y / magDelta
- return availablePositions
- yodash.insertClusteredRandomAgents = (
- randomNumberGenerator,
- amount,
- char,
- rows,
- cols,
- occupiedSpots,
- originRow,
- originColumn
- ) => {
- const availableSpots = yodash.getAllAvailableSpots(rows, cols, occupiedSpots)
- const spots = yodash.sampleFrom(availableSpots, amount * 10, randomNumberGenerator)
- const origin = originColumn
- ? { down: parseInt(originRow), right: parseInt(originColumn) }
- : yodash.getRandomLocation(rows, cols, randomNumberGenerator)
- const sortedByDistance = lodash.sortBy(spots, spot =>
- math.distance([origin.down, origin.right], [spot.down, spot.right])
- )
-
- return sortedByDistance
- .slice(0, amount)
- .map(spot => {
- const { hash } = spot
- occupiedSpots.add(hash)
- return `${char} ${hash}`
- })
- .join("\n")
- }
-
Changed around line 209: window.AbstractContextMenuComponent = AbstractContextMenuComponent
-
+ const classCache = {}
+ const getClassCache = (program, words) => {
+ const key = words.join(" ")
+ if (!classCache[key]) classCache[key] = yodash.flatten(yodash.pick(program, words))
+ return classCache[key]
+ }
+
- angle = Directions.South
+ _direction = { x: 0, y: 1 }
+
+ get direction() {
+ if (this.angle) {
+ const vectors = {
+ North: [0, -1],
+ East: [1, 0],
+ South: [0, 1],
+ West: [-1, 0],
+ Northeast: [Math.cos(Math.PI / 4), Math.sin((Math.PI * 3) / 4)],
+ Southeast: [Math.cos((Math.PI * 3) / 4), Math.sin(Math.PI / 4)],
+ Southwest: [-Math.cos((Math.PI * 3) / 4), Math.sin(Math.PI * (5 / 8))],
+ Northwest: [-Math.cos(Math.PI * (5 / 8)), Math.sin((Math.PI * -3) / 4)]
+ }
+ this._direction = vectors[this.angle]
+ this.angle = ""
+ }
+ return this._direction
+ }
+
+ set direction(newDirection) {
+ this._direction = newDirection
+ }
- return this.definitionWithBehaviors.findNodes(eventName)
+ return this.definitionWithClasses.findNodes(eventName)
- get definitionWithBehaviors() {
- if (!this.behaviors.length) return this.board.simojiProgram.getNode(this.firstWord)
- const behaviors = yodash.flatten(yodash.pick(this.board.simojiProgram, [this.firstWord, ...this.behaviors]))
- return behaviors
+ get definitionWithClasses() {
+ if (!this.classes.length) return this.board.simojiProgram.getNode(this.firstWord)
+ return getClassCache(this.board.simojiProgram, [this.firstWord, ...this.classes])
Changed around line 265: class Agent extends TreeNode {
- handleNeighbors() {
- if (!this.stillExists) return
- this.getCommandBlocks(Keywords.onNeighbors).forEach(neighborConditions => {
- if (this.skip(neighborConditions.getWord(1))) return
-
- const { neighorCount } = this
-
- neighborConditions.forEach(conditionAndCommandsBlock => {
- const [emoji, operator, count] = conditionAndCommandsBlock.words
- const actual = neighorCount[emoji]
- if (!yodash.compare(actual ?? 0, operator, count)) return
- conditionAndCommandsBlock.forEach(command => this._executeCommand(this, command))
-
- if (this.getIndex() === -1) return {}
- })
- })
- }
-
- handleTouches(agentPositionMap) {
- if (!this.stillExists) return
- this.getCommandBlocks(Keywords.onTouch).forEach(touchMap => {
- if (this.skip(touchMap.getWord(1))) return
-
- for (let pos of yodash.positionsAdjacentTo(this.position)) {
- const hits = agentPositionMap.get(yodash.makePositionHash(pos)) ?? []
- for (let target of hits) {
- const targetId = target.firstWord
- const commandBlock = touchMap.getNode(targetId)
- if (commandBlock) {
- commandBlock.forEach(command => this._executeCommand(target, command))
- if (this.getIndex() === -1) return
- }
- }
- }
- })
- }
-
- handleOverlaps(targets) {
- if (!this.stillExists) return
- this.getCommandBlocks(Keywords.onHit).forEach(hitMap => {
- if (this.skip(hitMap.getWord(1))) return
- targets.forEach(target => {
- const targetId = target.firstWord
- const commandBlock = hitMap.getNode(targetId)
- if (commandBlock) commandBlock.forEach(command => this._executeCommand(target, command))
- })
- })
- }
-
- get overlappingAgents() {
- return (this.board.agentPositionMap.get(this.positionHash) ?? []).filter(node => node !== this)
- }
-
Changed around line 292: class Agent extends TreeNode {
- get neighorCount() {
- const { agentPositionMap } = this.board
- const neighborCounts = {}
- yodash.positionsAdjacentTo(this.position).forEach(pos => {
- const agents = agentPositionMap.get(yodash.makePositionHash(pos)) ?? []
- agents.forEach(agent => {
- if (!neighborCounts[agent.name]) neighborCounts[agent.name] = 0
- neighborCounts[agent.name]++
- })
- })
- return neighborCounts
- }
-
Changed around line 301: class Agent extends TreeNode {
- this.parent.appendLine(`${newObject} ${this.positionHash}`)
-
+ this.parent.insertInbounds(newObject, this.x, this.y)
- const { angle } = this
- if (angle.includes(Directions.North)) this.moveNorth()
- else if (angle.includes(Directions.South)) this.moveSouth()
- if (angle.includes(Directions.East)) this.moveEast()
- else if (angle.includes(Directions.West)) this.moveWest()
+ const { direction, speed } = this
+
+ this.top = Math.max(this.top + direction.y * speed, 0)
+ this.left = Math.max(this.left + direction.x * speed, 0)
- node.position = { right: this.left, down: this.top }
+ node.setPosition({ x: this.x, y: this.y })
- moveSouth() {
- this.top++
+ speed = 1
+
+ get x() {
+ return this.left
- moveNorth() {
- this.top--
+ get y() {
+ return this.top
- moveWest() {
- this.left--
+ get w() {
+ return this.width
- moveEast() {
- this.left++
+ get h() {
+ return this.height
+ width = 10
+ height = 10
+
- return this.position.down
+ return this._y ?? this.position.y
- this.position = {
- down: value,
- right: this.left
- }
- }
-
- set position(value) {
- if (this.board.isSolidAgent(value)) return this.bouncy ? this.bounce() : this
- const newLine = this.getLine()
- .split(" ")
- .map(part => (part.includes("⬇️") ? value.down + "⬇️" : part.includes("➡️") ? value.right + "➡️" : part))
- .join(" ")
- return this.setLine(newLine)
+ this.setPosition({
+ y: value,
+ x: this.left
+ })
+ setPosition(newPosition) {
+ if (!this.board.canGoHere(newPosition.x, newPosition.y, this.width, this.height))
+ return this.bouncy ? this.bounce() : this
+
+ this._x = newPosition.x
+ this._y = newPosition.y
+ // Todo: do we need to update the string?
+ return this.setLine([this.firstWord, newPosition.x, newPosition.y].join(" "))
+ }
+
+ handleCollisions(targetAgents) {
+ if (!this.stillExists) return
+ this.getCommandBlocks(Keywords.onHit).forEach(hitMap => {
+ if (this.skip(hitMap.getWord(1))) return
+ targetAgents.forEach(targetAgent => {
+ const targetId = targetAgent.firstWord
+ const commandBlock = hitMap.getNode(targetId)
+ if (commandBlock) commandBlock.forEach(command => this._executeCommand(targetAgent, command))
+ })
+ })
+ }
+
+ get symbol() {
+ return this.firstWord
+ }
+
+ get collidingAgents() {
+ return this.board.objectsCollidingWith(this.x, this.y, this.width, this.height).filter(node => node !== this)
+ }
+
+ get neighorCount() {
+ return this.board.getNeighborCount(this)
+ }
+
- return this.board.cols
+ return this.board.width - this.width - 1
- return this.board.rows
+ return this.board.height - this.height - 1
- this.position = {
- down: this.top,
- right: value
- }
+ this.setPosition({
+ y: this.top,
+ x: value
+ })
- return this.position.right
+ return this._x ?? this.position.x
- get position() {
- return yodash.parsePosition(this.words)
+ get bounds() {
+ return {
+ x: this.x,
+ y: this.y,
+ w: this.width,
+ h: this.height
+ }
- get positionHash() {
- return yodash.makePositionHash(this.position)
+ get position() {
+ return {
+ x: parseInt(this.words[1]),
+ y: parseInt(this.words[2])
+ }
- return this.parent.gridSize
+ return 1
+ }
+
+ get agentSize() {
+ return this.size ?? this.gridSize
Changed around line 459: class Agent extends TreeNode {
- this.element.remove()
+ if (this.element) this.element.remove()
- return document.getElementById(`agent${this._getUid()}`)
+ return document.getElementById(this.id)
Changed around line 474: class Agent extends TreeNode {
- const { gridSize, health } = this
+ const { health, width, height } = this
- return `top:${this.top * gridSize}px;left:${
- this.left * gridSize
- }px;font-size:${gridSize}px;line-height: ${gridSize}px;${opacity};${this.style ?? ""}`
+ return `top:${this.top}px;left:${this.left}px;font-size:${height}px;line-height:${height}px;${opacity};${
+ this.style ?? ""
+ }`
+ }
+
+ get id() {
+ return `agent${this.agentNumber}`
+ }
+
+ get agentNumber() {
+ return this._getUid()
- elem.setAttribute("id", `agent${this._getUid()}`)
+ elem.setAttribute("id", this.id)
Changed around line 499: class Agent extends TreeNode {
- toStumpCode() {
- return `div ${this.html ?? this.icon}
- id agent${this._getUid()}
- class Agent ${this.selected ? SelectedClass : ""}
- style ${this.inlineStyle}`
+ toggleSelectCommand() {
+ const { root } = this
+ root.selection.includes(this) ? this.unselectCommand() : this.selectCommand()
+
+ root.ensureRender()
+ return this
+ }
+
+ unselectCommand() {
+ this.unselect()
+ this.root.selection = this.root.selection.filter(node => node !== this)
+ }
+
+ selectCommand() {
+ this.root.selection.push(this)
+ this.select()
Changed around line 532: class Agent extends TreeNode {
- target.angle = this.angle
+ target.direction = this.direction
Changed around line 577: class Agent extends TreeNode {
- this.angle = yodash.flipAngle(this.angle)
+ const { x, y } = this.direction
+ this.direction = { x: -x, y: -y }
Changed around line 594: class Agent extends TreeNode {
- this.angle = yodash.getRandomAngle(this.board.randomNumberGenerator)
+ const rng = this.board.randomNumberGenerator
+ this.direction = { x: 2 * rng() - 1, y: 2 * rng() - 1 }
Changed around line 603: class Agent extends TreeNode {
- if (targets) this.angle = yodash.getBestAngle(targets, this.position)
+ if (!targets) return this
+ this.target = yodash.getClosest(targets, this)
+ this.direction = yodash.unitVector(this, this.target)
Changed around line 613: class Agent extends TreeNode {
- if (targets) this.angle = yodash.flipAngle(yodash.getBestAngle(targets, this.position))
+ if (!targets) return this
+ this.target = yodash.getClosest(targets, this)
+ const bestUnitVector = yodash.unitVector(this, this.target)
+ this.direction = { x: -bestUnitVector.x, y: -bestUnitVector.y }
Changed around line 625: class Agent extends TreeNode {
- const position = command.getWordsFrom(2).length ? command.getWordsFrom(2).join(" ") : subject.positionHash
+ const position = command.getWordsFrom(2).length ? command.getWordsFrom(2).join(" ") : `${subject.x} ${subject.y}`
+ get midpoint() {
+ return { x: this.x + this.width / 2, y: this.y + this.height / 2 }
+ }
+
+ emit(subject, command) {
+ const { midpoint } = this
+ const position = command.getWordsFrom(2).length ? command.getWordsFrom(2).join(" ") : `${midpoint.x} ${midpoint.y}`
+ const agent = this.board.appendLine(`${command.getWord(1)} ${position}`)
+ agent.direction = this.direction
+ }
+
- while (this.overlappingAgents.length) {
+ while (this.collidingAgents.length) {
+ grow() {
+ this.width++
+ this.height++
+ this.markDirty()
+ }
+
+ shrink() {
+ if (!this.width || !this.height) return
+ this.width--
+ this.height--
+ this.markDirty()
+ }
+
+ _lastPulse
+ pulse() {
+ if (this._lastPulse) this.shrink()
+ else this.grow()
+ this._lastPulse = !this._lastPulse
+ }
+
- this.behaviors.push(command.getWord(1))
+ this.classes.push(command.getWord(1))
- const behaviorName = command.getWord(1)
- this.behaviors = this.behaviors.filter(name => name !== behaviorName)
+ const className = command.getWord(1)
+ this.classes = this.classes.filter(name => name !== className)
Changed around line 732: window.AgentPaletteComponent = AgentPaletteComponent
+
Changed around line 787: class BoardComponent extends AbstractTreeComponentParser {
- return parseInt(this.getWord(1))
+ return 1
- get rows() {
- return parseInt(this.getWord(2))
+ get width() {
+ if (this._width === undefined) this._width = parseInt(this.getWord(2))
+ return this._width
- get cols() {
- return parseInt(this.getWord(3))
+ get height() {
+ if (this._height === undefined) this._height = parseInt(this.getWord(3))
+ return this._height
Changed around line 836: class BoardComponent extends AbstractTreeComponentParser {
- insertAgentAtCommand(right, down) {
+ insertAgentAtCommand(xCenter, yCenter) {
- const board = this
- const positionHash = down + " " + right
- board.resetAgentPositionMap()
- const { agentPositionMap } = board
- const existingObjects = agentPositionMap.get(positionHash) ?? []
- if (existingObjects.length) return root.toggleSelectCommand(existingObjects)
-
+ this.clearCollisionDetector()
- //if (parent.findNodes(agentToInsert).length > MAX_ITEMS) return true
+ const { agentWidth, agentHeight } = this.getAgentHeightAndWidth(agentToInsert)
+
+ const x = xCenter - Math.floor(agentWidth / 2)
+ const y = yCenter - Math.floor(agentHeight / 2)
- board.prependLine(`${agentToInsert} ${positionHash}`)
- board.renderAndGetRenderReport()
- board.resetAgentPositionMap()
+ //if (parent.findNodes(agentToInsert).length > MAX_ITEMS) return true
- if (!root.isSnapshotOn) root.snapShotCommand()
+ this.prependLine(`${agentToInsert} ${x} ${y}`)
+ this.renderAndGetRenderReport()
+ this.clearCollisionDetector()
- targetNode.appendLine(`insertAt ${agentToInsert} ${down} ${right}`)
+ targetNode.appendLine(`insertAt ${agentToInsert} ${x} ${y}`)
Changed around line 876: class BoardComponent extends AbstractTreeComponentParser {
-
- this.resetAgentPositionMap()
- this.handleOverlaps()
- this.handleTouches()
- this.handleNeighbors()
-
+ this.clearCollisionDetector()
+ this.handleCollisions()
Changed around line 902: class BoardComponent extends AbstractTreeComponentParser {
+ treeComponentDidMount() {
+ const that = this
+ if (this.isNodeJs()) return
+ jQuery(this.getStumpNode().getShadow().element).on("click", ".Agent", function (evt) {
+ const agent = evt.target
+ const id = parseInt(jQuery(agent).attr("id").replace("agent", ""))
+ that.getAgent(id).toggleSelectCommand()
+ })
+ }
+
+ getAgent(uid) {
+ return this.agents.find(agent => agent._getUid() === uid)
+ }
+
Changed around line 944: class BoardComponent extends AbstractTreeComponentParser {
- occupiedSpots = new Set()
-
+ getAgentHeightAndWidth(agentSymbol) {
+ const item = new this.agentMap[agentSymbol]()
+ return { agentWidth: item.width, agentHeight: item.height }
+ }
+
+ insertInbounds(agentSymbol, x, y) {
+ const { agentWidth, agentHeight } = this.getAgentHeightAndWidth(agentSymbol)
+ const xOver = x + agentWidth - this.width
+ const yOver = y + agentHeight - this.height
+ if (xOver > 0) x = x - xOver - 10
+ if (yOver > 0) y = y - yOver - 10
+ if (x < 0) x = 0
+ if (y < 0) y = 0
+ this.appendLine(`${agentSymbol} ${x} ${y}`)
+ }
+
+ // todo: origin
+ insertClusteredRandomAgents(amount, agentSymbol, x = 0, y = 0) {
+ const { agentWidth, agentHeight } = this.getAgentHeightAndWidth(agentSymbol)
+ const spots = this.collisionDetector.findClusteredNonOverlappingSquares(
+ agentWidth,
+ agentHeight,
+ amount,
+ x,
+ y,
+ (amount * agentWidth) / 4
+ )
+ return spots.map(spot => `${agentSymbol} ${spot.x} ${spot.y}`).join("\n")
+ }
+
- yodash.insertClusteredRandomAgents(
- this.randomNumberGenerator,
+ this.insertClusteredRandomAgents(
- this.rows,
- this.cols,
- this.occupiedSpots,
+ this.clearCollisionDetector()
- this.appendLine(`${commandNode.getWord(1)} ${commandNode.getWord(3)} ${commandNode.getWord(2)}`)
- // TODO: update occupied spots cache?
+ this.appendLine(`${commandNode.getWord(1)} ${commandNode.getWord(2)} ${commandNode.getWord(3)}`)
+ this.clearCollisionDetector()
- const newLines = yodash.makeRectangle(...yodash.parseInts(commandNode.words.slice(1), 1))
+ // todo: need a typed words method in jtree
+ // rectangle 🙂 width height x y 🙂
+ const [command, agentSymbol, width, height, x, y, fillSymbol, spacing] = commandNode.words
+
+ const { agentWidth, agentHeight } = this.getAgentHeightAndWidth(agentSymbol)
+
+ const options = {
+ agentSymbol,
+ width: parseInt(width),
+ height: parseInt(height),
+ x: x ? parseInt(x) : 0,
+ y: y ? parseInt(y) : 0,
+ fillSymbol,
+ spacing: spacing || 0,
+ agentHeight,
+ agentWidth
+ }
+
+ const newLines = this.makeRectangle(options)
- // TODO: update occupied spots cache?
+ this.clearCollisionDetector()
- yodash.updateOccupiedSpots(newSpots, this.occupiedSpots)
+ this.clearCollisionDetector()
- this.concat(yodash.fill(this.rows, this.cols, this.occupiedSpots, commandNode.getWord(1)))
+ this.concat(this.fill(commandNode.getWord(1)))
+ this.clearCollisionDetector()
- const { occupiedSpots } = this
- const spots = yodash.draw(commandNode.childrenToString())
- yodash.updateOccupiedSpots(spots, occupiedSpots)
- this.concat(spots)
+ this.concat(this.draw(commandNode.childrenToString()))
+ this.clearCollisionDetector()
Changed around line 1047: class BoardComponent extends AbstractTreeComponentParser {
- const { rows, cols, occupiedSpots } = this
- const emoji = commandNode.getWord(2)
+ const { width, height } = this
+ const agentSymbol = commandNode.getWord(2)
+ const { agentWidth, agentHeight } = this.getAgentHeightAndWidth(agentSymbol)
+ const maxCells = (width * height) / (agentWidth * agentHeight)
+ amount = amount.includes("%") ? yodash.parsePercent(amount) * maxCells : parseInt(amount)
+
+ const spots = this.collisionDetector.findNonOverlappingSquares(agentWidth, agentHeight, amount)
+
+ const newAgents = spots.map(spot => `${agentSymbol} ${spot.x + " " + spot.y}`).join("\n")
- const availableSpots = yodash.getAllAvailableSpots(rows, cols, occupiedSpots)
- amount = amount.includes("%") ? yodash.parsePercent(amount) * (rows * cols) : parseInt(amount)
- const newAgents = yodash
- .sampleFrom(availableSpots, amount, this.randomNumberGenerator)
- .map(spot => {
- const { hash } = spot
- occupiedSpots.add(hash)
- return `${emoji} ${hash}`
- })
- .join("\n")
+ this.clearCollisionDetector()
Changed around line 1082: class BoardComponent extends AbstractTreeComponentParser {
- isSolidAgent(position) {
- if (!this._solidsSet) this.resetAgentPositionMap()
- const hash = yodash.makePositionHash(position)
- if (this._solidsSet.has(hash)) return true
-
- return false
- }
-
- get agentPositionMap() {
- if (!this._agentPositionMap) this.resetAgentPositionMap()
- return this._agentPositionMap
- }
-
- resetAgentPositionMap() {
- const map = new Map()
- const solidsSet = new Set()
- this.agents.forEach(agent => {
- const { positionHash } = agent
- if (agent.solid) solidsSet.add(positionHash)
- if (!map.has(positionHash)) map.set(positionHash, [])
- map.get(positionHash).push(agent)
- })
- this._solidsSet = solidsSet
- this._agentPositionMap = map
- this.occupiedSpots = new Set(map.keys())
- }
-
Changed around line 1096: class BoardComponent extends AbstractTreeComponentParser {
- handleOverlaps() {
- this.agentPositionMap.forEach(nodes => {
- if (nodes.length > 1) nodes.forEach(node => node.handleOverlaps(nodes))
- })
+ clearCollisionDetector() {
+ delete this._collisionDetector
+ delete this._solidCollisionDetector
- handleTouches() {
- const agentPositionMap = this.agentPositionMap
- this.agents.forEach(node => node.handleTouches(agentPositionMap))
+ _collisionDetector
+ get collisionDetector() {
+ if (!this._collisionDetector) this._collisionDetector = new CollisionDetector(this.agents, this.width, this.height)
+ return this._collisionDetector
- handleNeighbors() {
- this.agents.forEach(node => node.handleNeighbors())
+ handleCollisions() {
+ const collisions = this.collisionDetector.detectCollisions()
+ collisions.forEach(collision => {
+ const [agentA, agentB] = collision
+ agentA.handleCollisions([agentB])
+ agentB.handleCollisions([agentA])
+ })
Changed around line 1197: class BoardComponent extends AbstractTreeComponentParser {
- this.appendLine(
- `${command.getWord(1)} ${yodash.getRandomLocationHash(
- this.rows,
- this.cols,
- undefined,
- this.randomNumberGenerator
- )}`
- )
+ this.appendLine(`${command.getWord(1)} ${this.getRandomLocationHash()}`)
Changed around line 1221: class BoardComponent extends AbstractTreeComponentParser {
+
+ isRectOccupied(x, y, width, height) {
+ return !this.collisionDetector.isSpotAvailable(x, y, width, height)
+ }
+
+ objectsCollidingWith(x, y, width, height) {
+ return this.collisionDetector.getCollidingAgents(x, y, width, height)
+ }
+
+ _solidCollisionDetector
+ get solidCollisionDetector() {
+ if (!this._solidCollisionDetector)
+ this._solidCollisionDetector = new CollisionDetector(
+ this.agents.filter(agent => agent.solid),
+ this.width,
+ this.height
+ )
+ return this._solidCollisionDetector
+ }
+
+ canGoHere(x, y, width, height) {
+ const blockersHere = this.solidCollisionDetector.getCollidingAgents(x, y, width, height)
+ if (blockersHere.length) return false
+
+ return true
+ }
+
+ get collidingAgents() {
+ const agents = this.agents
+ const collidingAgents = []
+ for (let agent of agents) {
+ const { position, agentSize } = agent
+ const agentsHere = this.objectsCollidingWith(position.x, position.y, agentSize).filter(a => a !== agent)
+ if (agentsHere.length) collidingAgents.push(...agentsHere)
+ }
+ return collidingAgents
+ }
+
+ makePositionHash(positionType) {
+ return `${positionType.x + " " + positionType.y}`
+ }
+
+ getRandomLocationHash(size = 1) {
+ const { x, y } = this.getRandomLocation()
+ if (this.isRectOccupied(x, y, size, size)) return this.getRandomLocationHash()
+ return this.makePositionHash({ x, y })
+ }
+
+ getRandomLocation() {
+ const { randomNumberGenerator, height, width } = this
+ const maxRight = width
+ const maxBottom = height
+ const x = Math.round(randomNumberGenerator() * maxRight)
+ const y = Math.round(randomNumberGenerator() * maxBottom)
+ return { x, y }
+ }
+
+ draw(str) {
+ const lines = str.split("\n")
+ const output = []
+ let agentWidth
+ let agentHeight
+ for (let index = 0; index < lines.length; index++) {
+ const words = lines[index].split(" ")
+ for (let wordIndex = 0; wordIndex < words.length; wordIndex++) {
+ const agentSymbol = words[wordIndex]
+ if (agentSymbol && !agentWidth) {
+ // Draw assumes everything being drawn is a square with sides N.
+ agentWidth = this.getAgentHeightAndWidth(agentSymbol).agentWidth
+ agentHeight = agentWidth
+ }
+
+ if (agentSymbol !== "")
+ output.push(`${agentSymbol} ${this.makePositionHash({ y: index * agentHeight, x: wordIndex * agentHeight })}`)
+ }
+ }
+ return output.join("\n")
+ }
+
+ makeRectangle(options) {
+ const { width, height, agentSymbol, x, y, fillSymbol, spacing, agentHeight, agentWidth } = options
+
+ if (width < 1 || height < 1) return ""
+
+ if (isNaN(x)) x = 20
+ if (isNaN(y)) y = 20
+
+ const cells = []
+ let row = 0
+ while (row < height) {
+ let col = 0
+ while (col < width) {
+ const isPerimeter = row === 0 || row === height - 1 || col === 0 || col === width - 1
+ if (!fillSymbol && !isPerimeter) {
+ col++
+ continue
+ }
+
+ cells.push(
+ `${isPerimeter ? agentSymbol : fillSymbol} ${x + col * (agentWidth + spacing)} ${
+ y + row * (agentHeight + spacing)
+ }`
+ )
+ col++
+ }
+ row++
+ }
+ return cells.join("\n")
+ }
+
+ fill(agentSymbol) {
+ let { width, height } = this
+ const { agentWidth, agentHeight } = this.getAgentHeightAndWidth(agentSymbol)
+ const board = []
+ let y = 0
+ while (y < height - agentHeight) {
+ let x = 0
+ while (x < width - agentWidth) {
+ if (this.isRectOccupied(x, y, agentWidth, agentHeight)) {
+ x += agentWidth
+ continue
+ }
+ board.push(`${agentSymbol} ${x} ${y}`)
+ x += agentWidth
+ }
+ y += agentHeight
+ }
+ return board.join("\n")
+ }
+
+ getNeighborCount(rect) {
+ const { position, agentSize } = rect
+ const neighborCounts = {}
+ this.positionsAdjacentToRect(position.right, position.down, agentSize).forEach(pos => {
+ const agents = this.objectsCollidingWith(pos.right, pos.down, agentSize)
+ agents.forEach(agent => {
+ if (!neighborCounts[agent.name]) neighborCounts[agent.name] = 0
+ neighborCounts[agent.name]++
+ })
+ })
+ return neighborCounts
+ }
+
+ positionsAdjacentToRect(x, y, size) {
+ const positions = []
+ for (let row = y - size; row <= y + size; row++) {
+ for (let col = x - size; col <= x + size; col++) {
+ if (row === y && col === x) continue
+ positions.push({ right: col, down: row })
+ }
+ }
+ return positions
+ }
Changed around line 1416: class BottomBarComponent extends AbstractTreeComponentParser {
+ class Bounds {
+ constructor(x, y, w, h) {
+ this.x = x
+ this.y = y
+ this.w = w
+ this.h = h
+ }
+
+ intersects(range) {
+ return !(
+ range.x >= this.x + this.w ||
+ range.y >= this.y + this.h ||
+ range.x + range.w <= this.x ||
+ range.y + range.h <= this.y
+ )
+ }
+ }
+
+ class Quadtree {
+ constructor(bounds, capacity, maxDepth = 10) {
+ this.bounds = new Bounds(bounds.x, bounds.y, bounds.w, bounds.h)
+ this.capacity = capacity
+ this.maxDepth = maxDepth
+ this.agents = []
+ }
+
+ get agentCount() {
+ let count = 0
+
+ if (this.isLeaf()) {
+ count += this.agents.length
+ } else {
+ for (const child of this.children) {
+ count += child.agentCount
+ }
+ }
+
+ return count
+ }
+
+ insert(agent, depth = 0) {
+ if (!this.bounds.intersects(agent)) return false
+
+ if (!this.divided && (this.agents.length < this.capacity || depth >= this.maxDepth)) {
+ this.agents.push(agent)
+ return true
+ } else {
+ if (!this.divided) this.divide()
+ for (const child of this.children) {
+ if (child.insert(agent, depth + 1)) return true
+ }
+ }
+ return false
+ }
+
+ isLeaf() {
+ return !this.divided
+ }
+
+ get northWest() {
+ return this.children[0]
+ }
+
+ get northEast() {
+ return this.children[1]
+ }
+
+ get southWest() {
+ return this.children[2]
+ }
+
+ get southEast() {
+ return this.children[3]
+ }
+
+ prettyPrint(depth = 0) {
+ let output = ""
+
+ if (this.isLeaf()) {
+ output += "-".repeat(depth - 1)
+ output += `[${this.bounds.x}, ${this.bounds.y}, ${this.bounds.w}, ${this.bounds.h}]: `
+ output += this.agents.map(agent => agent.id).join(", ")
+ output += "\n"
+ } else {
+ output += this.northWest.prettyPrint(depth + 1)
+ output += this.northEast.prettyPrint(depth + 1)
+ output += this.southWest.prettyPrint(depth + 1)
+ output += this.southEast.prettyPrint(depth + 1)
+ }
+
+ return output
+ }
+
+ get divided() {
+ return !!this.children
+ }
+
+ divide() {
+ const { x, y } = this.bounds
+ const { bounds, capacity } = this
+ const w = bounds.w / 2
+ const h = bounds.h / 2
+
+ this.children = [
+ new Quadtree({ x, y, w, h }, capacity),
+ new Quadtree({ x: x + w, y, w, h }, capacity),
+ new Quadtree({ x, y: y + h, w, h }, capacity),
+ new Quadtree({ x: x + w, y: y + h, w, h }, capacity)
+ ]
+
+ for (const agent of this.agents) this.insert(agent)
+ delete this.agents
+ }
+
+ query(range, found = []) {
+ if (!this.bounds.intersects(range)) return found
+
+ if (!this.divided) {
+ for (const agent of this.agents) if (range.intersects(agent)) found.push(agent)
+ } else {
+ for (const child of this.children) child.query(range, found)
+ }
+
+ return found
+ }
+ }
+
+ class CollisionDetector {
+ constructor(agents, worldWidth, worldHeight) {
+ this.agents = agents
+ this.width = worldWidth
+ this.height = worldHeight
+ this.quadtree = new Quadtree({ x: 0, y: 0, w: worldWidth, h: worldHeight }, 4)
+ for (const agent of this.agents) this.addAgent(agent)
+ }
+
+ addAgent(agent) {
+ this.quadtree.insert(agent)
+ return this
+ }
+
+ isSpotAvailable(x, y, width, height) {
+ const searchBounds = new Bounds(x, y, width, height)
+
+ const nearbyAgents = this.quadtree.query(searchBounds)
+
+ for (const agent of nearbyAgents) {
+ if (x < agent.x + agent.width && x + width > agent.x && y < agent.y + agent.height && y + height > agent.y) {
+ return false
+ }
+ }
+ return true
+ }
+
+ findNonOverlappingSquares(width, height, N) {
+ const nonOverlappingSquares = []
+ const availableCells = []
+
+ // Divide the world into cells
+ for (let x = 0; x < this.width - width; x += width) {
+ for (let y = 0; y < this.height - height; y += height) {
+ if (this.isSpotAvailable(x, y, width, height)) availableCells.push({ x, y })
+ }
+ }
+
+ // Randomly select non-overlapping cells
+ while (nonOverlappingSquares.length < N && availableCells.length) {
+ const randomIndex = Math.floor(Math.random() * availableCells.length)
+ nonOverlappingSquares.push(availableCells[randomIndex])
+ availableCells.splice(randomIndex, 1)
+ }
+ return nonOverlappingSquares
+ }
+
+ findClusteredNonOverlappingSquares(width, height, N, centerX, centerY, clusterRadius) {
+ const nonOverlappingSquares = []
+ const availableCells = []
+
+ // Divide the world into cells and filter by clusterRadius
+ for (let x = 0; x < this.width - width; x += width) {
+ for (let y = 0; y < this.height - height; y += height) {
+ const dx = x - centerX
+ const dy = y - centerY
+ const distance = Math.sqrt(dx * dx + dy * dy)
+
+ if (distance <= clusterRadius && this.isSpotAvailable(x, y, width, height)) {
+ availableCells.push({ x: x, y: y })
+ }
+ }
+ }
+
+ // Randomly select non-overlapping cells
+ while (nonOverlappingSquares.length < N && availableCells.length > 0) {
+ const randomIndex = Math.floor(Math.random() * availableCells.length)
+ nonOverlappingSquares.push(availableCells[randomIndex])
+ availableCells.splice(randomIndex, 1)
+ }
+
+ return nonOverlappingSquares
+ }
+
+ getCollidingAgents(x, y, width, height) {
+ const collidingAgents = []
+ const queryBounds = new Bounds(x, y, width, height)
+ const nearbyAgents = this.quadtree.query(queryBounds)
+
+ for (const agent of nearbyAgents) {
+ if (queryBounds.intersects(agent)) collidingAgents.push(agent)
+ }
+
+ return collidingAgents
+ }
+
+ detectCollisions() {
+ let collissions = []
+
+ for (const agentA of this.agents) {
+ const searchBounds = new Bounds(
+ agentA.x - agentA.width,
+ agentA.y - agentA.height,
+ agentA.width * 2,
+ agentA.height * 2
+ )
+ const nearbyAgents = this.quadtree.query(searchBounds)
+ for (const agentB of nearbyAgents) {
+ if (agentA !== agentB && this.checkCollision(agentA, agentB)) collissions.push([agentA, agentB])
+ }
+ }
+ return collissions
+ }
+
+ checkCollision(a, b) {
+ return a.x < b.x + b.width && a.x + a.width > b.x && a.y < b.y + b.height && a.y + a.height > b.y
+ }
+ }
+
+ window.CollisionDetector = CollisionDetector
+
+
Changed around line 1729: const Categories = new TreeNode(`🦠 Epidemiology
- 👾 Game of Life
- gameOfLife
- gospersGliderGun
- gameOfLifeAdvanced
Changed around line 1791: window.ExampleMenuComponent = ExampleMenuComponent
-
- gridClickCommand(down, right) {
- return this.parent.insertAgentAtCommand(right, down)
+ gridClickCommand(x, y) {
+ return this.parent.insertAgentAtCommand(x, y)
- makeBlock(down, right, gridSize) {
- return `\n div
- class block
- style width:${gridSize}px;height:${gridSize}px;top:${down * gridSize}px;left:${right * gridSize}px;
- clickCommand gridClickCommand ${yodash.makePositionHash({ right, down })}`
+ treeComponentDidMount() {
+ const that = this
+ if (this.isNodeJs()) return super.treeComponentDidMount()
+
+ jQuery(`.${GridComponent.name}`).on("click", function (evt) {
+ const { offsetX, offsetY } = evt
+ const x = offsetX
+ const y = offsetY
+ that.gridClickCommand(x, y)
+ })
- const { cols, rows, gridSize } = this.parent
- let blocks = ""
- let rs = rows
- while (rs >= 0) {
- let cs = cols
- while (cs >= 0) {
- blocks = this.makeBlock(rs, cs, gridSize) + blocks
- cs--
- }
- rs--
- }
- return (
- `div
- class ${GridComponent.name}` + blocks
- )
+ return `div
+ class ${GridComponent.name}`
Changed around line 2144: window.SimEditorComponent = SimEditorComponent
-
- const MIN_GRID_SIZE = 10
- const MAX_GRID_SIZE = 200
- const DEFAULT_GRID_SIZE = 20
- const MIN_GRID_COLUMNS = 10
- const MIN_GRID_ROWS = 10
Changed around line 2203: class SimojiApp extends AbstractTreeComponentParser {
- const setSize = simojiProgram.get(Keywords.size)
- const gridSize = Math.min(Math.max(setSize ? parseInt(setSize) : DEFAULT_GRID_SIZE, MIN_GRID_SIZE), MAX_GRID_SIZE)
-
- const maxAvailableCols = Math.floor((windowWidth - chromeWidth) / gridSize) - 1
- const maxAvailableRows = Math.floor((windowHeight - SIZES.CHROME_HEIGHT - SIZES.TITLE_HEIGHT) / gridSize) - 1
+ const width = windowWidth - chromeWidth - 1
+ const height = windowHeight - SIZES.CHROME_HEIGHT - SIZES.TITLE_HEIGHT - 1
- const setCols = simojiProgram.get(Keywords.columns)
- const cols = Math.max(1, setCols ? parseInt(setCols) : Math.max(MIN_GRID_COLUMNS, maxAvailableCols))
+ const setWidth = simojiProgram.get(Keywords.width)
+ const setHeight = simojiProgram.get(Keywords.height)
+ // todo: use the set values if present
- const setRows = simojiProgram.get(Keywords.rows)
- const rows = Math.max(1, setRows ? parseInt(setRows) : Math.max(MIN_GRID_ROWS, maxAvailableRows))
-
- return { gridSize, cols, rows }
+ return { width, height }
Changed around line 2251: class SimojiApp extends AbstractTreeComponentParser {
- const { gridSize, cols, rows } = this.makeGrid(program, windowWidth, windowHeight)
+ const { width, height } = this.makeGrid(program, windowWidth, windowHeight)
- `${BoardComponent.name} ${gridSize} ${rows} ${cols} ${index}`,
+ `${BoardComponent.name} 1 ${width} ${height} ${index}`,
Changed around line 2362: ${styleNode ? styleNode.toString().replace("style", BoardStyleComponent.name) :
- if (!this.isSnapshotOn) this.snapShotCommand()
Changed around line 2441: ${styleNode ? styleNode.toString().replace("style", BoardStyleComponent.name) :
- toggleSelectCommand(objects) {
- objects.forEach(object => {
- this.selection.includes(object) ? this.unselectCommand(object) : this.selectCommand(object)
- })
-
- this.ensureRender()
- return this
- }
-
- unselectCommand(object) {
- object.unselect()
- this.selection = this.selection.filter(node => node !== object)
- }
-
- selectCommand(object) {
- this.selection.push(object)
- object.select()
- }
-
Changed around line 2518: ${styleNode ? styleNode.toString().replace("style", BoardStyleComponent.name) :
- moveSelection(direction) {
+ moveSelection(x, y) {
- node.angle = direction
+ node.direction = { x, y }
- this.boards.forEach(board => board.resetAgentPositionMap())
-
- this.boards.forEach(board => board.resetAgentPositionMap())
+ // todo: update any state?
- // technically also needs rows and column settings
+ // technically also needs width and height settings
Changed around line 2548: ${styleNode ? styleNode.toString().replace("style", BoardStyleComponent.name) :
- newCode.set(Keywords.rows, board.rows.toString())
- newCode.set(Keywords.columns, board.cols.toString())
+ newCode.set(Keywords.height, board.height.toString())
+ newCode.set(Keywords.width, board.width.toString())
- experiment.set(Keywords.rows, board.rows.toString())
- experiment.set(Keywords.columns, board.cols.toString())
+ experiment.set(Keywords.height, board.height.toString())
+ experiment.set(Keywords.width, board.width.toString())
Changed around line 2590: ${styleNode ? styleNode.toString().replace("style", BoardStyleComponent.name) :
- up: () => this.moveSelection(Directions.North),
- down: () => this.moveSelection(Directions.South),
- right: () => this.moveSelection(Directions.East),
- left: () => this.moveSelection(Directions.West),
+ up: () => this.moveSelection(0, -1),
+ down: () => this.moveSelection(0, 1),
+ right: () => this.moveSelection(1, 0),
+ left: () => this.moveSelection(-1, 0),
Changed around line 2720: const Keywords = {}
- Keywords.size = "size"
- Keywords.rows = "rows"
- Keywords.columns = "columns"
+ Keywords.height = "height"
+ Keywords.width = "width"
- Keywords.onNeighbors = "onNeighbors"
- Keywords.onTouch = "onTouch"
Changed around line 2744: UrlKeys.simoji = "simoji"
- const Directions = {}
-
- Directions.North = "North"
- Directions.East = "East"
- Directions.South = "South"
- Directions.West = "West"
-
Changed around line 2757: window.LocalStorageKeys = LocalStorageKeys
- window.Directions = Directions
-
Changed around line 2805: class BrowserGlue extends AbstractTreeComponentParser {
- const grammar = await fetch("simoji.grammar")
+ const grammar = await fetch("dist/simoji.grammar")
examples.js
Changed around line 1
- const stamp = require("jtree/products/stamp.nodejs.js")
examples/basketball.simoji
Changed around line 12: experiment
+ thingClass
+ width 30
+ height 30
+
+ personClass
+ width 40
+ height 40
+ speed 20
+
+ width 20
+ height 20
+ speed 30
- spawn 🏀 9⬇️ 15➡️
- spawn 🔵 18⬇️ 1➡️
+ spawn 🏀 15 9
+ spawn 🔵 1 18
- spawn 🏀 9⬇️ 15➡️
- spawn 🔴 17⬇️ 1➡️
+ spawn 🏀 15 9
+ spawn 🔴 1 17
- moveEastToBlankSpotBehavior
+ moveEastToBlankSpotClass
- unlearn moveEastToBlankSpotBehavior
+ unlearn moveEastToBlankSpotClass
- moveEastToBlankSpotBehavior
+ moveEastToBlankSpotClass
- moveEastToBlankSpotBehavior
+ moveEastToBlankSpotClass
- hasBallBehavior
+ hasBallClass
Changed around line 65: hasBallBehavior
- learn noBallBehavior
- unlearn hasBallBehavior
+ learn noBallClass
+ unlearn hasBallClass
- learn noBallBehavior
- unlearn hasBallBehavior
+ learn noBallClass
+ unlearn hasBallClass
- noBallBehavior
+ noBallClass
Changed around line 83: noBallBehavior
- learn hasBallBehavior
- unlearn noBallBehavior
+ learn hasBallClass
+ unlearn noBallClass
Changed around line 94: noBallBehavior
+ personClass
- noBallBehavior
+ noBallClass
+ personClass
- noBallBehavior
+ noBallClass
+ thingClass
+ thingClass
+
- 🥅⛹️‍♂️ 8⬇️ 2➡️
- 🥅⛹️‍♀️ 8⬇️ 29➡️
- 🏀 9⬇️ 15➡️
+ 🥅⛹️‍♂️ 50 180
+ 🥅⛹️‍♀️ 800 180
+ 🏀 425 180
+ thingClass
- size 30
-
- # Red Team
- paste
- ⛹️‍♀️ 9⬇️ 6➡️
- ⛹️‍♀️ 5⬇️ 6➡️
- ⛹️‍♀️ 11⬇️ 11➡️
- ⛹️‍♀️ 8⬇️ 11➡️
- ⛹️‍♀️ 5⬇️ 11➡️
- # Blue Team
- paste
- ⛹️‍♂️ 8⬇️ 25➡️
- ⛹️‍♂️ 6⬇️ 25➡️
- ⛹️‍♂️ 11⬇️ 20➡️
- ⛹️‍♂️ 7⬇️ 20➡️
- ⛹️‍♂️ 4⬇️ 20➡️
+ insertAt ⛹️‍♂️ 719 140
+ insertAt ⛹️‍♂️ 733 242
+ insertAt ⛹️‍♂️ 727 341
+ insertAt ⛹️‍♂️ 645 172
+ insertAt ⛹️‍♂️ 626 271
+ insertAt ⛹️‍♀️ 167 142
+ insertAt ⛹️‍♀️ 154 286
+ insertAt ⛹️‍♀️ 307 139
+ insertAt ⛹️‍♀️ 309 227
+ insertAt ⛹️‍♀️ 320 341
examples/city.simoji
Changed around line 41
- size 20
- 🏛 9⬇️ 8➡️
- 🏭 1⬇️ 4➡️
- 🏭 1⬇️ 3➡️
- 🏭 1⬇️ 2➡️
- 🏭 1⬇️ 1➡️
- 🏡 18⬇️ 5➡️
- 🏡 18⬇️ 6➡️
- 🏡 18⬇️ 7➡️
- 🏡 18⬇️ 8➡️
+ 🏛 8 9
+ 🏭 4 1
+ 🏭 3 1
+ 🏭 2 1
+ 🏭 1 1
+ 🏡 5 18
+ 🏡 6 18
+ 🏡 7 18
+ 🏡 8 18
examples/cops.simoji
Changed around line 13
- size 20
- 🚓 1⬇️ 1➡️
- 🚗 15⬇️ 5➡️
+ 🚓 1 1
+ 🚗 5 15
examples/covid19.simoji
Changed around line 1
+ thingClass
Changed around line 35: experiment High Vaccination Rate, Low Vaccine Efficacy
- freedomOfMovementSetting .3
+ freedomOfMovementSetting .1
- reinfectionRateSetting .2
+ reinfectionRateSetting .3
Changed around line 47: insert vaccineCentersSetting 💉
+ thingClass
+ width 20
+ height 20
+ speed 5
+ thingClass
Changed around line 65: insert ruralPopulationSetting 🙍
+ thingClass
- onTouch reinfectionRateSetting
+ onHit reinfectionRateSetting
- lifeBehavior
+ aliveClass
- seekVaccineBehavior
+ vaccineSeekerClass
- lifeBehavior
- seekVaccineBehavior
- onTouch innateImmunitySetting
+ thingClass
+ aliveClass
+ vaccineSeekerClass
+ onHit innateImmunitySetting
Changed around line 95: seekVaccineBehavior
+ thingClass
- lifeBehavior
- onTouch vaxSucceptibilitySetting
+ thingClass
+ aliveClass
+ onHit vaxSucceptibilitySetting
Changed around line 114: onExtinct 🧟
+ thingClass
+
- size 15
examples/covid19simple.simoji
Changed around line 45: experiment
- onTouch
+ onHit
Changed around line 60: onExtinct 🧟
- size 15
examples/eatTheBacon.simoji
Changed around line 5
- onTouch
+ onHit
examples/elevators.simoji
Changed around line 21
- size 15
-
- rectangle 🪵 20➡️ 47⬇️ 5 1
- rectangle 🌾 40➡️ 1⬇️ 0 48
- rectangle 🚪 1➡️ 45⬇️ 15 2
+ rectangle 🪵 20 47 5 1
+ rectangle 🌾 40 1 0 48
+ rectangle 🚪 1 45 15 2
- 🛗 6⬇️ 19➡️
- 🛗 4⬇️ 22➡️
- 🛗 3⬇️ 20➡️
- 🛗 10⬇️ 13➡️
- 🛗 4⬇️ 9➡️
- 🛗 3⬇️ 11➡️
- 🚗 47⬇️ 30➡️
- 🚗 47⬇️ 28➡️
+ 🛗 19 6
+ 🛗 22 4
+ 🛗 20 3
+ 🛗 13 10
+ 🛗 9 4
+ 🛗 11 3
+ 🚗 30 47
+ 🚗 28 47
examples/fire.simoji
Changed around line 1
+ width 20
+ height 20
+ replaceWith ⬛️
- onTouch
+ onHit
+ replaceWith ⬛️
Changed around line 20: question How fast do fires spread?
+ width 40
+ height 40
+ jitter
- onDeath
- replaceWith ⬛️
-
+ shrink
examples/fireAdvanced.simoji
Changed around line 18: fireLifetimeSetting 10
+ width 20
+ height 20
- onTouch fireSpreadSetting
+ onHit fireSpreadSetting
Changed around line 35: lightningFrequencySetting .1
+ width 40
+ height 40
+ jitter
+ shrink
examples/gameOfLife.simoji
Changed around line 0
- question Can simple rules produce complex effects?
-
- ⬛️
- onNeighbors
- ⬛️ < 2
- replaceWith ◻️
- ⬛️ > 3
- replaceWith ◻️
-
- ◻️
- onNeighbors
- ⬛️ = 3
- replaceWith ⬛️
-
- insert 10% ⬛️
- fill ◻️
- size 15
examples/gameOfLifeAdvanced.simoji
Changed around line 0
- # Conway's Game of Life
-
- experiment
- neighborSetting 2
-
- experiment
- neighborSetting 3
-
- experiment
- neighborSetting 4
-
- experiment
- neighborSetting 5
-
- ⬛️
- onNeighbors
- ⬛️ < 2
- replaceWith ◻️
- ⬛️ > neighborSetting
- replaceWith ◻️
-
- ◻️
- onNeighbors
- ⬛️ = 3
- replaceWith ⬛️
-
- insert 10% ⬛️
- fill ◻️
- size 15
examples/gospersGliderGun.simoji
Changed around line 0
- ⬛️
- onNeighbors
- ⬛️ < 2
- replaceWith ◻️
- ⬛️ > 3
- replaceWith ◻️
-
- ◻️
- onNeighbors
- ⬛️ = 3
- replaceWith ⬛️
-
- # Gosper's Glider Gun
-
- draw
- ⬛️
- ⬛️ ⬛️
- ⬛️ ⬛️ ⬛️ ⬛️
- ⬛️ ⬛️ ⬛️ ⬛️ ⬛️ ⬛️
- ⬛️ ⬛️ ⬛️ ⬛️ ⬛️ ⬛️
- ⬛️ ⬛️ ⬛️ ⬛️ ⬛️ ⬛️ ⬛️ ⬛️
- ⬛️ ⬛️ ⬛️ ⬛️ ⬛️
- ⬛️ ⬛️
- ⬛️ ⬛️
-
-
- fill ◻️
examples/moths.simoji
Changed around line 1
- onTick .1
+ speed 10
+ height 30
+ width 30
+ onTick .5
Changed around line 12: question Can you move the moths from one light to the other?
+ height 100
+ width 100
- size 20
examples/pong.simoji
Changed around line 1
-
+ speed 20
+ width 30
+ height 30
+
+ width 30
+ height 30
Changed around line 23
- size 20
- rectangle 🪵 30 15 5 5
- paste
- 🏓 13⬇️ 6➡️
- 🏸 13⬇️ 33➡️
- 🏐 13⬇️ 19➡️
+ rectangle 🪵 50 15 50 50
+
+ insertAt 🏐 273 125
+ insertAt 🏓 90 120
+ insertAt 🏸 510 121
examples/poolTable.simoji
Changed around line 6: comment
+ turnRandomly
Changed around line 15: comment
+ speed 10
- turnRandomly
+ turnRandomly
+ move
+ turnRandomly
- rectangle 🪵 40 20 0 7
+ rectangle 🪵 40 20 10 70
- 🏐 17⬇️ 32➡️
- 🎱 12⬇️ 7➡️
- 🎱 14⬇️ 7➡️
- 🎱 16⬇️ 7➡️
- 🎱 18⬇️ 7➡️
- 🎱 20⬇️ 7➡️
- 🎱 22⬇️ 7➡️
- 🎱 21⬇️ 8➡️
- 🎱 19⬇️ 8➡️
- 🎱 17⬇️ 8➡️
- 🎱 15⬇️ 8➡️
- 🎱 13⬇️ 8➡️
- 🎱 20⬇️ 9➡️
- 🎱 18⬇️ 9➡️
- 🎱 16⬇️ 9➡️
- 🎱 14⬇️ 9➡️
- 🎱 15⬇️ 10➡️
- 🎱 17⬇️ 10➡️
- 🎱 19⬇️ 10➡️
- 🎱 18⬇️ 11➡️
- 🎱 16⬇️ 11➡️
- 🎱 17⬇️ 12➡️
+ 🏐 320 170
+ 🎱 70 120
+ 🎱 70 140
+ 🎱 70 160
+ 🎱 70 180
+ 🎱 70 200
+ 🎱 70 220
+ 🎱 80 210
+ 🎱 80 190
+ 🎱 80 170
+ 🎱 80 150
+ 🎱 80 130
+ 🎱 90 200
+ 🎱 90 180
+ 🎱 90 160
+ 🎱 90 140
+ 🎱 100 150
+ 🎱 100 170
+ 🎱 100 190
+ 🎱 110 180
+ 🎱 110 160
+ 🎱 120 170
examples/soccer.simoji
Changed around line 1
-
+ thingClass
+ width 40
+ height 40
+ speed 20
+ width 20
+ height 20
+ speed 30
Changed around line 14
+ thingClass
Changed around line 22
+ thingClass
+
+ thingClass
+ thingClass
- size 20
- paste
- 🥅 13⬇️ 6➡️
- 🥅 13⬇️ 33➡️
- ⚽️ 13⬇️ 19➡️
-
- paste
- ⛹️‍♀️ 17⬇️ 14➡️
- ⛹️‍♀️ 17⬇️ 17➡️
- ⛹️‍♀️ 13⬇️ 17➡️
- ⛹️‍♀️ 13⬇️ 14➡️
- ⛹️‍♀️ 8⬇️ 14➡️
- ⛹️‍♀️ 8⬇️ 17➡️
- ⛹️‍♀️ 10⬇️ 14➡️
- ⛹️‍♀️ 9⬇️ 10➡️
- ⛹️‍♀️ 13⬇️ 8➡️
- ⛹️‍♀️ 13⬇️ 10➡️
- ⛹️‍♀️ 17⬇️ 10➡️
-
- paste
- ⛹️‍♂️ 13⬇️ 31➡️
- ⛹️‍♂️ 17⬇️ 28➡️
- ⛹️‍♂️ 13⬇️ 28➡️
- ⛹️‍♂️ 8⬇️ 29➡️
- ⛹️‍♂️ 8⬇️ 25➡️
- ⛹️‍♂️ 10⬇️ 25➡️
- ⛹️‍♂️ 13⬇️ 25➡️
- ⛹️‍♂️ 17⬇️ 25➡️
- ⛹️‍♂️ 17⬇️ 21➡️
- ⛹️‍♂️ 8⬇️ 21➡️
- ⛹️‍♂️ 13⬇️ 21➡️
+
+ seed 1681189626875
+ height 862
+ width 1354
+ insertAt 🥅 1095 293
+ insertAt 🥅 98 294
+ insertAt ⛹️‍♂️ 993 303
+ insertAt ⛹️‍♂️ 923 114
+ insertAt ⛹️‍♂️ 923 244
+ insertAt ⛹️‍♂️ 954 449
+ insertAt ⛹️‍♂️ 844 129
+ insertAt ⛹️‍♂️ 842 246
+ insertAt ⛹️‍♂️ 849 337
+ insertAt ⛹️‍♂️ 866 454
+ insertAt ⛹️‍♂️ 722 148
+ insertAt ⛹️‍♂️ 705 273
+ insertAt ⛹️‍♂️ 722 423
+ insertAt ⛹️‍♀️ 443 168
+ insertAt ⛹️‍♀️ 496 285
+ insertAt ⛹️‍♀️ 481 441
+ insertAt ⛹️‍♀️ 317 137
+ insertAt ⛹️‍♀️ 321 253
+ insertAt ⛹️‍♀️ 342 334
+ insertAt ⛹️‍♀️ 333 471
+ insertAt ⛹️‍♀️ 196 505
+ insertAt ⛹️‍♀️ 182 395
+ insertAt ⛹️‍♀️ 212 192
+ insertAt ⛹️‍♀️ 161 318
+ insertAt ⚽️ 618 322
examples/startupIdeas.simoji
Changed around line 1
+ personClass
+ width 25
+ height 25
+ speed 10
+
+ personClass
+ width 50
+ height 50
+ personClass
+ personClass
Changed around line 29: question What is the effect of ideas vs ideas with revenue?
- size 10
examples/store.simoji
Changed around line 1
+ bigClass
+ width 20
+ height 20
+
+ bigClass
+ speed 10
- angle North
+ onTick .4
+ turnRandomly
+ move
+ onTick .5
+ turnToward 🛒
+ onHit
+ 🛒
+ pickItUp
+ angle South
+ bigClass
+ bigClass
+ bigClass
- size 25
-
- rectangle 🪵 30 15 3 3
+ rectangle 🪵 30 15 30 30
- 🚪 16⬇️ 17➡️
+ 🚪 170 120
+
+
+
+ insertAt 🛒 432 95
+ insertAt 🛒 435 212
examples/talking.simoji
Changed around line 1
+ 🙂
+ width 30
+ height 30
+ onTick .1
+ turnToward 🙂
+ emit 💬
+
+
+ 💬
+ health 5
+ speed 10
+ onHit
+ 🙂
+ decrease health
+ decrease health
+ decrease health
+ decrease health
+ decrease health
+ decrease health
+ onTick
+ move
+ decrease health
+ onDeath
+ remove
+
+
+ rectangle 🙂 5 5 100 100 🙂 20
+
+ textClass
+ width 20
+ height 20
+
+ 1
+ html Imagine a world with 25 people
+ textClass
+
+ insertAt 1 70 60
examples/virus.simoji
Changed around line 1
+ thingClass
+ width 20
+ height 20
+ speed 20
+
+ thingClass
Changed around line 18: question What might the spread of a simple virus look like?
+ thingClass
- onTouch
+ onHit
+ # Recovered
+ thingClass
Changed around line 35: insert 10% 🙍
+ thingClass
examples/waves.simoji
Changed around line 3
- size 25
examples/zombies.simoji
Changed around line 1
+ bigClass
+ width 40
+ height 40
+
+ bigClass
+ speed 10
Changed around line 20: question Can you protect the family from the zombies?
+ bigClass
+ bigClass
+ speed 50
+ bigClass
+ width 50
+ height 50
+ bigClass
+ bigClass
+ bigClass
- size 30
- 👨‍👩‍👧‍👦 12⬇️ 11➡️
+ 👨‍👩‍👧‍👦 400 400
grammar/actions.grammar
Changed around line 1
+ javascriptLineParser
+ catchAllCellType javascriptCell
+ abstractCommandParser
+ cells keywordCell
+
+ abstractSubjectObjectCommandParser
+ extends abstractCommandParser
+ replaceWithCommandParser
+ extends abstractSubjectObjectCommandParser
+ crux replaceWith
+ cells keywordCell emojiCell
+ kickItCommandParser
+ extends abstractSubjectObjectCommandParser
+ crux kickIt
+ shootCommandParser
+ extends abstractSubjectObjectCommandParser
+ crux shoot
+ pickItUpCommandParser
+ extends abstractSubjectObjectCommandParser
+ crux pickItUp
+
+ spawnCommandParser
+ crux spawn
+ extends abstractCommandParser
+ cells keywordCell emojiCell
+ catchAllCellType positionCell
+ emitCommandParser
+ crux emit
+ extends abstractCommandParser
+ cells keywordCell emojiCell
+ removeCommandParser
+ description Remove this agent from the board.
+ crux remove
+ extends abstractCommandParser
+ cells keywordCell
+ javascriptCommandParser
+ description An escape hatch so you can write custom javascript in a pinch.
+ extends abstractCommandParser
+ crux javascript
+ catchAllParser javascriptLineParser
+ cells keywordCell
+
+ alertCommandParser
+ extends abstractCommandParser
+ crux alert
+ catchAllCellType stringCell
+ logCommandParser
+ extends abstractCommandParser
+ crux log
+ catchAllCellType stringCell
+ narrateCommandParser
+ extends abstractCommandParser
+ crux narrate
+ catchAllCellType stringCell
+ pauseCommandParser
+ extends abstractCommandParser
+ crux pause
+
+ decreaseCommandParser
+ extends abstractCommandParser
+ description Decrease a property by 1.
+ crux decrease
+ cells keywordCell propertyNameCell
+ increaseCommandParser
+ extends abstractCommandParser
+ description Increase a property by 1.
+ crux increase
+ cells keywordCell propertyNameCell
+
+ growCommandParser
+ extends abstractCommandParser
+ crux grow
+ shrinkCommandParser
+ extends abstractCommandParser
+ crux shrink
+ pulseCommandParser
+ extends abstractCommandParser
+ crux pulse
+
+ learnCommandParser
+ crux learn
+ extends abstractCommandParser
+ cells keywordCell classNameCell
+ unlearnCommandParser
+ crux unlearn
+ extends abstractCommandParser
+ cells keywordCell classNameCell
grammar/agents.grammar
Changed around line 1
+ agentDefinitionParser
+ inScope abstractIgnoreParser abstractEventParser abstractAgentAttributeParser belongsToClassParser
+ cells keywordCell
+ catchAllParser errorParser
+ compiler
+ stringTemplate
+ javascript
+ compile() {
+ const root = this.root
+ const name = root.agentKeywordMap[this.firstWord]
+ const normal = super.compile()
+ const classIds = this.filter(node => node.parserId === "belongsToClassParser").map(node => node.getLine())
+ const props = classIds.map(id => this.root.getNode(id).properties).join("\n\n")
+ return `class ${name} extends Agent {
+ icon = "${this.firstWord}"
+ classes = [${classIds.map(id => `"${id}"`).join(",")}]
+ ${props}
+ ${normal}
+ }`
+ }
grammar/attributes.grammar
Changed around line 1
+ abstractAgentAttributeParser
+ cells keywordCell
+ stringAttributeParser
+ extends abstractAgentAttributeParser
+ pattern ^\w+ .+$
+ catchAllCellType stringCell
+ javascript
+ compile() {
+ return `${this.firstWord} = "${this.content}"`
+ }
+ angleParser
+ extends stringAttributeParser
+ cells keywordCell angleCell
+ cruxFromId
+ agentStyleParser
+ description Provide custom CSS for an agent type.
+ extends stringAttributeParser
+ cells keywordCell cssCell
+ crux style
+ agentHtmlParser
+ description Provide custom HTML for each rendered agent.
+ extends stringAttributeParser
+ cells keywordCell htmlCell
+ crux html
+ abstractBooleanAttributeParser
+ description A boolean attribute.
+ extends abstractAgentAttributeParser
+ javascript
+ compile() {
+ return `${this.firstWord} = true`
+ }
+ noPaletteParser
+ extends abstractBooleanAttributeParser
+ cruxFromId
+ description Don't show this agent in the palette.
+ solidTraitParser
+ description If set other agents won't pass through these.
+ extends abstractBooleanAttributeParser
+ crux solid
+ bouncyTraitParser
+ description If set other agents will bounce off this after a collision.
+ extends abstractBooleanAttributeParser
+ crux bouncy
+ abstractIntegerAttributeParser
+ extends abstractAgentAttributeParser
+ description An integer attribute.
+ cells keywordCell integerCell
+ javascript
+ compile() {
+ return `${this.firstWord} = ${this.getWord(1)}`
+ }
+ customIntegerAttributeParser
+ pattern ^\w+ \d+$
+ extends abstractIntegerAttributeParser
+ healthParser
+ extends abstractIntegerAttributeParser
+ cruxFromId
+ agentWidthParser
+ extends abstractIntegerAttributeParser
+ description Width of the agent.
+ crux width
+ agentHeightParser
+ extends abstractIntegerAttributeParser
+ description Height of the agent.
+ crux height
+ speedParser
+ extends abstractIntegerAttributeParser
+ description Movement speed. Default is 1
+ crux speed
+ settingDefinitionParser
+ description Define a configurable input.
+ cells keywordCell settingValueCell
+ pattern ^\w+Setting .+$
grammar/board.grammar
Changed around line 1
+ styleLineParser
+ catchAllCellType cssCell
+ catchAllParser styleLineParser
+ styleParser
+ description Optional CSS to load in BoardStyleComponent
+ extends abstractSetupParser
+ cells keywordCell
+ cruxFromId
+ catchAllParser styleLineParser
+ javascript
+ compile() {
+ return ""
+ }
+ questionParser
+ cruxFromId
+ description What are you trying to figure out?
+ cells keywordCell
+ catchAllCellType stringCell
+ extends abstractSetupParser
grammar/cells.grammar
Changed around line 1
+ anyCell
+ booleanCell
+ stringCell
+ highlightScope string
+ settingValueCell
+ highlightScope constant.numeric
+ cssCell
+ highlightScope string
+ javascriptCell
+ highlightScope string
+ htmlCell
+ highlightScope string
+ emojiCell
+ highlightScope string
+ ohayoCell
+ highlightScope string
+ blankCell
+ codeCell
+ highlightScope comment
+ commentCell
+ highlightScope comment
+ keywordCell
+ highlightScope keyword
+ textCell
+ highlightScope string
+ integerCell
+ highlightScope constant.numeric
+
+ classNameCell
+ highlightScope keyword
+ conditionalOperatorCell
+ highlightScope keyword
+ enum < > = <= >=
+ positionCell
+ highlightScope constant.numeric
+ neighborCountCell
+ extends integerCell
+ min 0
+ max 8
+ integerOrPercentCell
+ highlightScope constant.numeric
+ probabilityCell
+ description A number between 0 and 1
+ highlightScope constant.numeric
+ propertyNameCell
+ highlightScope keyword
+ angleCell
+ enum North South East West NorthWest NorthEast SouthWest SouthEast
+ highlightScope constant.numeric
grammar/classes.grammar
Changed around line 1
+ belongsToClassParser
+ cells classNameCell
+ pattern ^.*Class$
+ javascript
+ compile() {
+ return ""
+ }
+ classDefinitionParser
+ inScope abstractIgnoreParser abstractEventParser abstractAgentAttributeParser
+ cells classNameCell
+ pattern ^.*Class$
+ catchAllParser errorParser
+ javascript
+ compile() {
+ return ""
+ }
+ get properties() {
+ return this.filter(node => node.doesExtend("abstractAgentAttributeParser")).map(node => node.compile()).join("\n")
+ }
grammar/comments.grammar
Changed around line 1
+ commentLineParser
+ catchAllCellType commentCell
+ commentParser
+ extends abstractIgnoreParser
+ catchAllCellType commentCell
+ cruxFromId
+ catchAllParser commentLineParser
+ commentAliasParser
+ description Alternate alias for a comment.
+ crux #
+ extends commentParser
grammar/draw.grammar
Changed around line 1
+ atTimeParser
+ cruxFromId
+ description Run commands at a certain tick.
+ cells keywordCell integerCell
+ extends abstractSetupParser
+ inScope abstractInjectCommandParser
+ abstractInjectCommandParser
+
+ insertParser
+ extends abstractInjectCommandParser
+ cells keywordCell integerOrPercentCell emojiCell
+ cruxFromId
+ insertAtParser
+ extends insertParser
+ description Insert at X Y
+ cells keywordCell emojiCell positionCell positionCell
+ cruxFromId
+ insertClusterParser
+ extends insertParser
+ cruxFromId
+ catchAllCellType integerCell
+
+ fillParser
+ description Fill all blank cells with this agent.
+ extends abstractInjectCommandParser
+ cells keywordCell emojiCell
+ cruxFromId
+
+ drawLineParser
+ catchAllCellType emojiCell
+ drawParser
+ extends abstractInjectCommandParser
+ cells keywordCell
+ cruxFromId
+ catchAllParser drawLineParser
+
+ rectangleDrawParser
+ extends abstractInjectCommandParser
+ example
+ rectangle 🙂 width height x y 🙂
+ cells keywordCell emojiCell integerCell integerCell
+ catchAllCellType integerCell
+ crux rectangle
+
+ pasteLineParser
+ catchAllCellType anyCell
+ catchAllParser pasteLineParser
+ pasteDrawParser
+ extends abstractInjectCommandParser
+ cells keywordCell
+ crux paste
+ catchAllParser pasteLineParser
grammar/events.grammar
Changed around line 1
+ targetEmojiParser
+ inScope abstractCommandParser
+ cells emojiCell
+ abstractEventParser
+ cells keywordCell
+ catchAllCellType probabilityCell
+ javascript
+ compile() {
+ return ``
+ }
+ abstractInteractionEventParser
+ extends abstractEventParser
+ catchAllParser targetEmojiParser
+ onHitParser
+ extends abstractInteractionEventParser
+ cruxFromId
+ description Define what happens when this agent collides with other agents.
+ onDeathParser
+ extends abstractEventParser
+ cruxFromId
+ inScope abstractCommandParser
+ description Define what happens when this agent runs out of health.
+ onTickParser
+ extends abstractEventParser
+ cruxFromId
+ inScope abstractCommandParser
+ description Define what happens each tick.
+ emojiAndNeighborConditionParser
+ inScope abstractCommandParser
+ pattern ^.+ (<|>|=|<=|>=)+ .+$
+ cells emojiCell conditionalOperatorCell neighborCountCell
+ onExtinctParser
+ cruxFromId
+ inScope abstractCommandParser
+ cells keywordCell emojiCell
+ description Define what happens when a type of agent goes extinct from the board.
+ javascript
+ compile() {
+ return ""
+ }
grammar/experiment.grammar
Changed around line 1
+ experimentParser
+ cruxFromId
+ cells keywordCell
+ inScope abstractIgnoreParser abstractSetupParser abstractInjectCommandParser onTickParser onExtinctParser settingDefinitionParser
+ catchAllCellType stringCell
+ abstractSetupNumberParser
+ cells keywordCell integerCell
+ extends abstractSetupParser
+ javascript
+ compile() {
+ return ""
+ }
+ heightParser
+ description Height of the grid. Default is based on screen size.
+ extends abstractSetupNumberParser
+ crux height
+ widthParser
+ description Width of the grid. Default is based on screen size.
+ extends abstractSetupNumberParser
+ crux width
+ seedParser
+ description If you'd like reproducible runs set a seed for the random number generator.
+ extends abstractSetupNumberParser
+ cruxFromId
+ ticksPerSecondParser
+ description Time in milliseconds of one step.
+ extends abstractSetupNumberParser
+ cruxFromId
grammar/movement.grammar
Changed around line 1
+ moveCommandParser
+ extends abstractCommandParser
+ crux move
+ moveToEmptySpotCommandParser
+ crux moveToEmptySpot
+ extends abstractCommandParser
+ cells keywordCell
+ turnRandomlyCommandParser
+ extends abstractCommandParser
+ crux turnRandomly
+ jitterCommandParser
+ extends abstractCommandParser
+ crux jitter
+ turnTowardCommandParser
+ description Turn to the closest agent of a certain type.
+ extends abstractCommandParser
+ crux turnToward
+ cells keywordCell emojiCell
+ turnFromCommandParser
+ description Turn away from the closest agent of a certain type.
+ extends abstractCommandParser
+ crux turnFrom
+ cells keywordCell emojiCell
grammar/report.grammar
Changed around line 1
+ ohayoLineParser
+ description Data visualization code written for Ohayo.
+ catchAllCellType ohayoCell
+ reportParser
+ cruxFromId
+ description Define a custom report template.
+ catchAllParser ohayoLineParser
+ extends abstractSetupParser
+ cells keywordCell
+ javascript
+ compile() {
+ return ""
+ }
grammar/root.grammar
Changed around line 1
+ errorParser
+ baseParser errorParser
+ abstractSetupParser
+ abstractIgnoreParser
+ tags doNotSynthesize
+ javascript
+ compile () {
+ return ""
+ }
+ simojiParser
+ extensions simoji
+ description A Tree Language that compiles to a TreeComponentFramework app.
+ root
+ inScope abstractIgnoreParser abstractSetupParser abstractInjectCommandParser onTickParser onExtinctParser classDefinitionParser experimentParser settingDefinitionParser
+ catchAllParser agentDefinitionParser
+ compilesTo javascript
+ example
+ 🦋
+ onTick .1
+ turnRandomly
+ move
+ onTick .2
+ turnToward 💡
+ move
+ 💡
+
+ insert 10 🦋
+ insert 2 💡
+ javascript
+ get agentTypes() {
+ return this.filter(node => node.parserId === "agentDefinitionParser")
+ }
+ blankLineParser
+ extends abstractIgnoreParser
+ description Blank lines compile do nothing.
+ cells blankCell
+ pattern ^$
package-lock.json
Changed around line 0
- {
- "name": "simoji",
- "version": "2.0.0",
- "lockfileVersion": 2,
- "requires": true,
- "packages": {
- "": {
- "name": "simoji",
- "version": "2.0.0",
- "dependencies": {
- "jquery": "^3.6.0",
- "jtree": "^74.0.0",
- "lodash": "^4.17.21",
- "mathjs": "^9.4.4",
- "minimist": "^1.2.5"
- },
- "bin": {
- "simoji": "cli.js"
- },
- "devDependencies": {
- "tap": "^15.0.9"
- },
- "engines": {
- "node": ">=16.0.0"
- }
- },
- "node_modules/@babel/code-frame": {
- "version": "7.14.5",
- "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.14.5.tgz",
- "integrity": "sha512-9pzDqyc6OLDaqe+zbACgFkb6fKMNG6CObKpnYXChRsvYGyEdc7CA2BaqeOM+vOtCS5ndmJicPJhKAwYRI6UfFw==",
- "dev": true,
- "dependencies": {
- "@babel/highlight": "^7.14.5"
- },
- "engines": {
- "node": ">=6.9.0"
- }
- },
- "node_modules/@babel/compat-data": {
- "version": "7.14.7",
- "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.14.7.tgz",
- "integrity": "sha512-nS6dZaISCXJ3+518CWiBfEr//gHyMO02uDxBkXTKZDN5POruCnOZ1N4YBRZDCabwF8nZMWBpRxIicmXtBs+fvw==",
- "dev": true,
- "engines": {
- "node": ">=6.9.0"
- }
- },
- "node_modules/@babel/core": {
- "version": "7.14.8",
- "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.14.8.tgz",
- "integrity": "sha512-/AtaeEhT6ErpDhInbXmjHcUQXH0L0TEgscfcxk1qbOvLuKCa5aZT0SOOtDKFY96/CLROwbLSKyFor6idgNaU4Q==",
- "dev": true,
- "dependencies": {
- "@babel/code-frame": "^7.14.5",
- "@babel/generator": "^7.14.8",
- "@babel/helper-compilation-targets": "^7.14.5",
- "@babel/helper-module-transforms": "^7.14.8",
- "@babel/helpers": "^7.14.8",
- "@babel/parser": "^7.14.8",
- "@babel/template": "^7.14.5",
- "@babel/traverse": "^7.14.8",
- "@babel/types": "^7.14.8",
- "convert-source-map": "^1.7.0",
- "debug": "^4.1.0",
- "gensync": "^1.0.0-beta.2",
- "json5": "^2.1.2",
- "semver": "^6.3.0",
- "source-map": "^0.5.0"
- },
- "engines": {
- "node": ">=6.9.0"
- }
- },
- "node_modules/@babel/core/node_modules/debug": {
- "version": "4.3.2",
- "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.2.tgz",
- "integrity": "sha512-mOp8wKcvj7XxC78zLgw/ZA+6TSgkoE2C/ienthhRD298T7UNwAg9diBpLRxC0mOezLl4B0xV7M0cCO6P/O0Xhw==",
- "dev": true,
- "dependencies": {
- "ms": "2.1.2"
- },
- "engines": {
- "node": ">=6.0"
- }
- },
- "node_modules/@babel/core/node_modules/ms": {
- "version": "2.1.2",
- "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
- "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==",
- "dev": true
- },
- "node_modules/@babel/generator": {
- "version": "7.14.8",
- "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.14.8.tgz",
- "integrity": "sha512-cYDUpvIzhBVnMzRoY1fkSEhK/HmwEVwlyULYgn/tMQYd6Obag3ylCjONle3gdErfXBW61SVTlR9QR7uWlgeIkg==",
- "dev": true,
- "dependencies": {
- "@babel/types": "^7.14.8",
- "jsesc": "^2.5.1",
- "source-map": "^0.5.0"
- },
- "engines": {
- "node": ">=6.9.0"
- }
- },
- "node_modules/@babel/helper-compilation-targets": {
- "version": "7.14.5",
- "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.14.5.tgz",
- "integrity": "sha512-v+QtZqXEiOnpO6EYvlImB6zCD2Lel06RzOPzmkz/D/XgQiUu3C/Jb1LOqSt/AIA34TYi/Q+KlT8vTQrgdxkbLw==",
- "dev": true,
- "dependencies": {
- "@babel/compat-data": "^7.14.5",
- "@babel/helper-validator-option": "^7.14.5",
- "browserslist": "^4.16.6",
- "semver": "^6.3.0"
- },
- "engines": {
- "node": ">=6.9.0"
- }
- },
- "node_modules/@babel/helper-function-name": {
- "version": "7.14.5",
- "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.14.5.tgz",
- "integrity": "sha512-Gjna0AsXWfFvrAuX+VKcN/aNNWonizBj39yGwUzVDVTlMYJMK2Wp6xdpy72mfArFq5uK+NOuexfzZlzI1z9+AQ==",
- "dev": true,
- "dependencies": {
- "@babel/helper-get-function-arity": "^7.14.5",
- "@babel/template": "^7.14.5",
- "@babel/types": "^7.14.5"
- },
- "engines": {
- "node": ">=6.9.0"
- }
- },
- "node_modules/@babel/helper-get-function-arity": {
- "version": "7.14.5",
- "resolved": "https://registry.npmjs.org/@babel/helper-get-function-arity/-/helper-get-function-arity-7.14.5.tgz",
- "integrity": "sha512-I1Db4Shst5lewOM4V+ZKJzQ0JGGaZ6VY1jYvMghRjqs6DWgxLCIyFt30GlnKkfUeFLpJt2vzbMVEXVSXlIFYUg==",
- "dev": true,
- "dependencies": {
- "@babel/types": "^7.14.5"
- },
- "engines": {
- "node": ">=6.9.0"
- }
- },
- "node_modules/@babel/helper-hoist-variables": {
- "version": "7.14.5",
- "resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.14.5.tgz",
- "integrity": "sha512-R1PXiz31Uc0Vxy4OEOm07x0oSjKAdPPCh3tPivn/Eo8cvz6gveAeuyUUPB21Hoiif0uoPQSSdhIPS3352nvdyQ==",
- "dev": true,
- "dependencies": {
- "@babel/types": "^7.14.5"
- },
- "engines": {
- "node": ">=6.9.0"
- }
- },
- "node_modules/@babel/helper-member-expression-to-functions": {
- "version": "7.14.7",
- "resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.14.7.tgz",
- "integrity": "sha512-TMUt4xKxJn6ccjcOW7c4hlwyJArizskAhoSTOCkA0uZ+KghIaci0Qg9R043kUMWI9mtQfgny+NQ5QATnZ+paaA==",
- "dev": true,
- "dependencies": {
- "@babel/types": "^7.14.5"
- },
- "engines": {
- "node": ">=6.9.0"
- }
- },
- "node_modules/@babel/helper-module-imports": {
- "version": "7.14.5",
- "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.14.5.tgz",
- "integrity": "sha512-SwrNHu5QWS84XlHwGYPDtCxcA0hrSlL2yhWYLgeOc0w7ccOl2qv4s/nARI0aYZW+bSwAL5CukeXA47B/1NKcnQ==",
- "dev": true,
- "dependencies": {
- "@babel/types": "^7.14.5"
- },
- "engines": {
- "node": ">=6.9.0"
- }
- },
- "node_modules/@babel/helper-module-transforms": {
- "version": "7.14.8",
- "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.14.8.tgz",
- "integrity": "sha512-RyE+NFOjXn5A9YU1dkpeBaduagTlZ0+fccnIcAGbv1KGUlReBj7utF7oEth8IdIBQPcux0DDgW5MFBH2xu9KcA==",
- "dev": true,
- "dependencies": {
- "@babel/helper-module-imports": "^7.14.5",
- "@babel/helper-replace-supers": "^7.14.5",
- "@babel/helper-simple-access": "^7.14.8",
- "@babel/helper-split-export-declaration": "^7.14.5",
- "@babel/helper-validator-identifier": "^7.14.8",
- "@babel/template": "^7.14.5",
- "@babel/traverse": "^7.14.8",
- "@babel/types": "^7.14.8"
- },
- "engines": {
- "node": ">=6.9.0"
- }
- },
- "node_modules/@babel/helper-optimise-call-expression": {
- "version": "7.14.5",
- "resolved": "https://registry.npmjs.org/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.14.5.tgz",
- "integrity": "sha512-IqiLIrODUOdnPU9/F8ib1Fx2ohlgDhxnIDU7OEVi+kAbEZcyiF7BLU8W6PfvPi9LzztjS7kcbzbmL7oG8kD6VA==",
- "dev": true,
- "dependencies": {
- "@babel/types": "^7.14.5"
- },
- "engines": {
- "node": ">=6.9.0"
- }
- },
- "node_modules/@babel/helper-replace-supers": {
- "version": "7.14.5",
- "resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.14.5.tgz",
- "integrity": "sha512-3i1Qe9/8x/hCHINujn+iuHy+mMRLoc77b2nI9TB0zjH1hvn9qGlXjWlggdwUcju36PkPCy/lpM7LLUdcTyH4Ow==",
- "dev": true,
- "dependencies": {
- "@babel/helper-member-expression-to-functions": "^7.14.5",
- "@babel/helper-optimise-call-expression": "^7.14.5",
- "@babel/traverse": "^7.14.5",
- "@babel/types": "^7.14.5"
- },
- "engines": {
- "node": ">=6.9.0"
- }
- },
- "node_modules/@babel/helper-simple-access": {
- "version": "7.14.8",
- "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.14.8.tgz",
- "integrity": "sha512-TrFN4RHh9gnWEU+s7JloIho2T76GPwRHhdzOWLqTrMnlas8T9O7ec+oEDNsRXndOmru9ymH9DFrEOxpzPoSbdg==",
- "dev": true,
- "dependencies": {
- "@babel/types": "^7.14.8"
- },
- "engines": {
- "node": ">=6.9.0"
- }
- },
- "node_modules/@babel/helper-split-export-declaration": {
- "version": "7.14.5",
- "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.14.5.tgz",
- "integrity": "sha512-hprxVPu6e5Kdp2puZUmvOGjaLv9TCe58E/Fl6hRq4YiVQxIcNvuq6uTM2r1mT/oPskuS9CgR+I94sqAYv0NGKA==",
- "dev": true,
- "dependencies": {
- "@babel/types": "^7.14.5"
- },
- "engines": {
- "node": ">=6.9.0"
- }
- },
- "node_modules/@babel/helper-validator-identifier": {
- "version": "7.14.8",
- "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.14.8.tgz",
- "integrity": "sha512-ZGy6/XQjllhYQrNw/3zfWRwZCTVSiBLZ9DHVZxn9n2gip/7ab8mv2TWlKPIBk26RwedCBoWdjLmn+t9na2Gcow==",
- "dev": true,
- "engines": {
- "node": ">=6.9.0"
- }
- },
- "node_modules/@babel/helper-validator-option": {
- "version": "7.14.5",
- "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.14.5.tgz",
- "integrity": "sha512-OX8D5eeX4XwcroVW45NMvoYaIuFI+GQpA2a8Gi+X/U/cDUIRsV37qQfF905F0htTRCREQIB4KqPeaveRJUl3Ow==",
- "dev": true,
- "engines": {
- "node": ">=6.9.0"
- }
- },
- "node_modules/@babel/helpers": {
- "version": "7.14.8",
- "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.14.8.tgz",
- "integrity": "sha512-ZRDmI56pnV+p1dH6d+UN6GINGz7Krps3+270qqI9UJ4wxYThfAIcI5i7j5vXC4FJ3Wap+S9qcebxeYiqn87DZw==",
- "dev": true,
- "dependencies": {
- "@babel/template": "^7.14.5",
- "@babel/traverse": "^7.14.8",
- "@babel/types": "^7.14.8"
- },
- "engines": {
- "node": ">=6.9.0"
- }
- },
- "node_modules/@babel/highlight": {
- "version": "7.14.5",
- "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.14.5.tgz",
- "integrity": "sha512-qf9u2WFWVV0MppaL877j2dBtQIDgmidgjGk5VIMw3OadXvYaXn66U1BFlH2t4+t3i+8PhedppRv+i40ABzd+gg==",
- "dev": true,
- "dependencies": {
- "@babel/helper-validator-identifier": "^7.14.5",
- "chalk": "^2.0.0",
- "js-tokens": "^4.0.0"
- },
- "engines": {
- "node": ">=6.9.0"
- }
- },
- "node_modules/@babel/parser": {
- "version": "7.14.8",
- "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.14.8.tgz",
- "integrity": "sha512-syoCQFOoo/fzkWDeM0dLEZi5xqurb5vuyzwIMNZRNun+N/9A4cUZeQaE7dTrB8jGaKuJRBtEOajtnmw0I5hvvA==",
- "dev": true,
- "bin": {
- "parser": "bin/babel-parser.js"
- },
- "engines": {
- "node": ">=6.0.0"
- }
- },
- "node_modules/@babel/runtime": {
- "version": "7.14.8",
- "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.14.8.tgz",
- "integrity": "sha512-twj3L8Og5SaCRCErB4x4ajbvBIVV77CGeFglHpeg5WC5FF8TZzBWXtTJ4MqaD9QszLYTtr+IsaAL2rEUevb+eg==",
- "dependencies": {
- "regenerator-runtime": "^0.13.4"
- },
- "engines": {
- "node": ">=6.9.0"
- }
- },
- "node_modules/@babel/template": {
- "version": "7.14.5",
- "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.14.5.tgz",
- "integrity": "sha512-6Z3Po85sfxRGachLULUhOmvAaOo7xCvqGQtxINai2mEGPFm6pQ4z5QInFnUrRpfoSV60BnjyF5F3c+15fxFV1g==",
- "dev": true,
- "dependencies": {
- "@babel/code-frame": "^7.14.5",
- "@babel/parser": "^7.14.5",
- "@babel/types": "^7.14.5"
- },
- "engines": {
- "node": ">=6.9.0"
- }
- },
- "node_modules/@babel/traverse": {
- "version": "7.14.8",
- "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.14.8.tgz",
- "integrity": "sha512-kexHhzCljJcFNn1KYAQ6A5wxMRzq9ebYpEDV4+WdNyr3i7O44tanbDOR/xjiG2F3sllan+LgwK+7OMk0EmydHg==",
- "dev": true,
- "dependencies": {
- "@babel/code-frame": "^7.14.5",
- "@babel/generator": "^7.14.8",
- "@babel/helper-function-name": "^7.14.5",
- "@babel/helper-hoist-variables": "^7.14.5",
- "@babel/helper-split-export-declaration": "^7.14.5",
- "@babel/parser": "^7.14.8",
- "@babel/types": "^7.14.8",
- "debug": "^4.1.0",
- "globals": "^11.1.0"
- },
- "engines": {
- "node": ">=6.9.0"
- }
- },
- "node_modules/@babel/traverse/node_modules/debug": {
- "version": "4.3.2",
- "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.2.tgz",
- "integrity": "sha512-mOp8wKcvj7XxC78zLgw/ZA+6TSgkoE2C/ienthhRD298T7UNwAg9diBpLRxC0mOezLl4B0xV7M0cCO6P/O0Xhw==",
- "dev": true,
- "dependencies": {
- "ms": "2.1.2"
- },
- "engines": {
- "node": ">=6.0"
- }
- },
- "node_modules/@babel/traverse/node_modules/ms": {
- "version": "2.1.2",
- "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
- "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==",
- "dev": true
- },
- "node_modules/@babel/types": {
- "version": "7.14.8",
- "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.14.8.tgz",
- "integrity": "sha512-iob4soQa7dZw8nodR/KlOQkPh9S4I8RwCxwRIFuiMRYjOzH/KJzdUfDgz6cGi5dDaclXF4P2PAhCdrBJNIg68Q==",
- "dev": true,
- "dependencies": {
- "@babel/helper-validator-identifier": "^7.14.8",
- "to-fast-properties": "^2.0.0"
- },
- "engines": {
- "node": ">=6.9.0"
- }
- },
- "node_modules/@istanbuljs/load-nyc-config": {
- "version": "1.1.0",
- "resolved": "https://registry.npmjs.org/@istanbuljs/load-nyc-config/-/load-nyc-config-1.1.0.tgz",
- "integrity": "sha512-VjeHSlIzpv/NyD3N0YuHfXOPDIixcA1q2ZV98wsMqcYlPmv2n3Yb2lYP9XMElnaFVXg5A7YLTeLu6V84uQDjmQ==",
- "dev": true,
- "dependencies": {
- "camelcase": "^5.3.1",
- "find-up": "^4.1.0",
- "get-package-type": "^0.1.0",
- "js-yaml": "^3.13.1",
- "resolve-from": "^5.0.0"
- },
- "engines": {
- "node": ">=8"
- }
- },
- "node_modules/@istanbuljs/schema": {
- "version": "0.1.3",
- "resolved": "https://registry.npmjs.org/@istanbuljs/schema/-/schema-0.1.3.tgz",
- "integrity": "sha512-ZXRY4jNvVgSVQ8DL3LTcakaAtXwTVUxE81hslsyD2AtoXW/wVob10HkOJ1X/pAlcI7D+2YoZKg5do8G/w6RYgA==",
- "dev": true,
- "engines": {
- "node": ">=8"
- }
- },
- "node_modules/accepts": {
- "version": "1.3.8",
- "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz",
- "integrity": "sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==",
- "dependencies": {
- "mime-types": "~2.1.34",
- "negotiator": "0.6.3"
- },
- "engines": {
- "node": ">= 0.6"
- }
- },
- "node_modules/aggregate-error": {
- "version": "3.1.0",
- "resolved": "https://registry.npmjs.org/aggregate-error/-/aggregate-error-3.1.0.tgz",
- "integrity": "sha512-4I7Td01quW/RpocfNayFdFVk1qSuoh0E7JrbRJ16nH01HhKFQ88INq9Sd+nd72zqRySlr9BmDA8xlEJ6vJMrYA==",
- "dev": true,
- "dependencies": {
- "clean-stack": "^2.0.0",
- "indent-string": "^4.0.0"
- },
- "engines": {
- "node": ">=8"
- }
- },
- "node_modules/ajv": {
- "version": "6.12.6",
- "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz",
- "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==",
- "dev": true,
- "dependencies": {
- "fast-deep-equal": "^3.1.1",
- "fast-json-stable-stringify": "^2.0.0",
- "json-schema-traverse": "^0.4.1",
- "uri-js": "^4.2.2"
- }
- },
- "node_modules/ansi-regex": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz",
- "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=",
- "dev": true,
- "engines": {
- "node": ">=4"
- }
- },
- "node_modules/ansi-styles": {
- "version": "3.2.1",
- "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz",
- "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==",
- "dev": true,
- "dependencies": {
- "color-convert": "^1.9.0"
- },
- "engines": {
- "node": ">=4"
- }
- },
- "node_modules/anymatch": {
- "version": "3.1.2",
- "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.2.tgz",
- "integrity": "sha512-P43ePfOAIupkguHUycrc4qJ9kz8ZiuOUijaETwX7THt0Y/GNK7v0aa8rY816xWjZ7rJdA5XdMcpVFTKMq+RvWg==",
- "dev": true,
- "dependencies": {
- "normalize-path": "^3.0.0",
- "picomatch": "^2.0.4"
- },
- "engines": {
- "node": ">= 8"
- }
- },
- "node_modules/append-transform": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/append-transform/-/append-transform-2.0.0.tgz",
- "integrity": "sha512-7yeyCEurROLQJFv5Xj4lEGTy0borxepjFv1g22oAdqFu//SrAlDl1O1Nxx15SH1RoliUml6p8dwJW9jvZughhg==",
- "dev": true,
- "dependencies": {
- "default-require-extensions": "^3.0.0"
- },
- "engines": {
- "node": ">=8"
- }
- },
- "node_modules/archy": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/archy/-/archy-1.0.0.tgz",
- "integrity": "sha1-+cjBN1fMHde8N5rHeyxipcKGjEA=",
- "dev": true
- },
- "node_modules/argparse": {
- "version": "1.0.10",
- "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz",
- "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==",
- "dev": true,
- "dependencies": {
- "sprintf-js": "~1.0.2"
- }
- },
- "node_modules/array-flatten": {
- "version": "1.1.1",
- "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz",
- "integrity": "sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg=="
- },
- "node_modules/asap": {
- "version": "2.0.6",
- "resolved": "https://registry.npmjs.org/asap/-/asap-2.0.6.tgz",
- "integrity": "sha512-BSHWgDSAiKs50o2Re8ppvp3seVHXSRM44cdSsT9FfNEUUZLOGWVCsiWaRPWM1Znn+mqZ1OfVZ3z3DWEzSp7hRA=="
- },
- "node_modules/asn1": {
- "version": "0.2.4",
- "resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.4.tgz",
- "integrity": "sha512-jxwzQpLQjSmWXgwaCZE9Nz+glAG01yF1QnWgbhGwHI5A6FRIEY6IVqtHhIepHqI7/kyEyQEagBC5mBEFlIYvdg==",
- "dev": true,
- "dependencies": {
- "safer-buffer": "~2.1.0"
- }
- },
- "node_modules/assert-plus": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz",
- "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=",
- "dev": true,
- "engines": {
- "node": ">=0.8"
- }
- },
- "node_modules/async-hook-domain": {
- "version": "2.0.3",
- "resolved": "https://registry.npmjs.org/async-hook-domain/-/async-hook-domain-2.0.3.tgz",
- "integrity": "sha512-MadiLLDEZRZzZwcm0dgS+K99qXZ4H2saAUwUgwzFulbAkXrKi3AX5FvWS3FFTQtLMwrqcGqAJe6o12KrObejQA==",
- "dev": true,
- "engines": {
- "node": ">=10"
- }
- },
- "node_modules/asynckit": {
- "version": "0.4.0",
- "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz",
- "integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k="
- },
- "node_modules/aws-sign2": {
- "version": "0.7.0",
- "resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.7.0.tgz",
- "integrity": "sha1-tG6JCTSpWR8tL2+G1+ap8bP+dqg=",
- "dev": true,
- "engines": {
- "node": "*"
- }
- },
- "node_modules/aws4": {
- "version": "1.11.0",
- "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.11.0.tgz",
- "integrity": "sha512-xh1Rl34h6Fi1DC2WWKfxUTVqRsNnr6LsKz2+hfwDxQJWmrx8+c7ylaqBMcHfl1U1r2dsifOvKX3LQuLNZ+XSvA==",
- "dev": true
- },
- "node_modules/balanced-match": {
- "version": "1.0.2",
- "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz",
- "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw=="
- },
- "node_modules/bcrypt-pbkdf": {
- "version": "1.0.2",
- "resolved": "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz",
- "integrity": "sha1-pDAdOJtqQ/m2f/PKEaP2Y342Dp4=",
- "dev": true,
- "dependencies": {
- "tweetnacl": "^0.14.3"
- }
- },
- "node_modules/binary-extensions": {
- "version": "2.2.0",
- "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz",
- "integrity": "sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==",
- "dev": true,
- "engines": {
- "node": ">=8"
- }
- },
- "node_modules/bind-obj-methods": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/bind-obj-methods/-/bind-obj-methods-3.0.0.tgz",
- "integrity": "sha512-nLEaaz3/sEzNSyPWRsN9HNsqwk1AUyECtGj+XwGdIi3xABnEqecvXtIJ0wehQXuuER5uZ/5fTs2usONgYjG+iw==",
- "dev": true,
- "engines": {
- "node": ">=10"
- }
- },
- "node_modules/body-parser": {
- "version": "1.20.1",
- "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.1.tgz",
- "integrity": "sha512-jWi7abTbYwajOytWCQc37VulmWiRae5RyTpaCyDcS5/lMdtwSz5lOpDE67srw/HYe35f1z3fDQw+3txg7gNtWw==",
- "dependencies": {
- "bytes": "3.1.2",
- "content-type": "~1.0.4",
- "debug": "2.6.9",
- "depd": "2.0.0",
- "destroy": "1.2.0",
- "http-errors": "2.0.0",
- "iconv-lite": "0.4.24",
- "on-finished": "2.4.1",
- "qs": "6.11.0",
- "raw-body": "2.5.1",
- "type-is": "~1.6.18",
- "unpipe": "1.0.0"
- },
- "engines": {
- "node": ">= 0.8",
- "npm": "1.2.8000 || >= 1.4.16"
- }
- },
- "node_modules/brace-expansion": {
- "version": "1.1.11",
- "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz",
- "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==",
- "dev": true,
- "dependencies": {
- "balanced-match": "^1.0.0",
- "concat-map": "0.0.1"
- }
- },
- "node_modules/braces": {
- "version": "3.0.2",
- "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz",
- "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==",
- "dev": true,
- "dependencies": {
- "fill-range": "^7.0.1"
- },
- "engines": {
- "node": ">=8"
- }
- },
- "node_modules/browserslist": {
- "version": "4.16.6",
- "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.16.6.tgz",
- "integrity": "sha512-Wspk/PqO+4W9qp5iUTJsa1B/QrYn1keNCcEP5OvP7WBwT4KaDly0uONYmC6Xa3Z5IqnUgS0KcgLYu1l74x0ZXQ==",
- "dev": true,
- "dependencies": {
- "caniuse-lite": "^1.0.30001219",
- "colorette": "^1.2.2",
- "electron-to-chromium": "^1.3.723",
- "escalade": "^3.1.1",
- "node-releases": "^1.1.71"
- },
- "bin": {
- "browserslist": "cli.js"
- },
- "engines": {
- "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7"
- }
- },
- "node_modules/buffer-from": {
- "version": "1.1.1",
- "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.1.tgz",
- "integrity": "sha512-MQcXEUbCKtEo7bhqEs6560Hyd4XaovZlO/k9V3hjVUF/zwW7KBVdSK4gIt/bzwS9MbR5qob+F5jusZsb0YQK2A==",
- "dev": true
- },
- "node_modules/bytes": {
- "version": "3.1.2",
- "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz",
- "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==",
- "engines": {
- "node": ">= 0.8"
- }
- },
- "node_modules/caching-transform": {
- "version": "4.0.0",
- "resolved": "https://registry.npmjs.org/caching-transform/-/caching-transform-4.0.0.tgz",
- "integrity": "sha512-kpqOvwXnjjN44D89K5ccQC+RUrsy7jB/XLlRrx0D7/2HNcTPqzsb6XgYoErwko6QsV184CA2YgS1fxDiiDZMWA==",
- "dev": true,
- "dependencies": {
- "hasha": "^5.0.0",
- "make-dir": "^3.0.0",
- "package-hash": "^4.0.0",
- "write-file-atomic": "^3.0.0"
- },
- "engines": {
- "node": ">=8"
- }
- },
- "node_modules/call-bind": {
- "version": "1.0.2",
- "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.2.tgz",
- "integrity": "sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==",
- "dependencies": {
- "function-bind": "^1.1.1",
- "get-intrinsic": "^1.0.2"
- },
- "funding": {
- "url": "https://github.com/sponsors/ljharb"
- }
- },
- "node_modules/camelcase": {
- "version": "5.3.1",
- "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz",
- "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==",
- "dev": true,
- "engines": {
- "node": ">=6"
- }
- },
- "node_modules/caniuse-lite": {
- "version": "1.0.30001245",
- "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001245.tgz",
- "integrity": "sha512-768fM9j1PKXpOCKws6eTo3RHmvTUsG9UrpT4WoREFeZgJBTi4/X9g565azS/rVUGtqb8nt7FjLeF5u4kukERnA==",
- "dev": true
- },
- "node_modules/caseless": {
- "version": "0.12.0",
- "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz",
- "integrity": "sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw=",
- "dev": true
- },
- "node_modules/chalk": {
- "version": "2.4.2",
- "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz",
- "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==",
- "dev": true,
- "dependencies": {
- "ansi-styles": "^3.2.1",
- "escape-string-regexp": "^1.0.5",
- "supports-color": "^5.3.0"
- },
- "engines": {
- "node": ">=4"
- }
- },
- "node_modules/chalk/node_modules/escape-string-regexp": {
- "version": "1.0.5",
- "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz",
- "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=",
- "dev": true,
- "engines": {
- "node": ">=0.8.0"
- }
- },
- "node_modules/chokidar": {
- "version": "3.5.2",
- "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.2.tgz",
- "integrity": "sha512-ekGhOnNVPgT77r4K/U3GDhu+FQ2S8TnK/s2KbIGXi0SZWuwkZ2QNyfWdZW+TVfn84DpEP7rLeCt2UI6bJ8GwbQ==",
- "dev": true,
- "dependencies": {
- "anymatch": "~3.1.2",
- "braces": "~3.0.2",
- "glob-parent": "~5.1.2",
- "is-binary-path": "~2.1.0",
- "is-glob": "~4.0.1",
- "normalize-path": "~3.0.0",
- "readdirp": "~3.6.0"
- },
- "engines": {
- "node": ">= 8.10.0"
- },
- "optionalDependencies": {
- "fsevents": "~2.3.2"
- }
- },
- "node_modules/clean-stack": {
- "version": "2.2.0",
- "resolved": "https://registry.npmjs.org/clean-stack/-/clean-stack-2.2.0.tgz",
- "integrity": "sha512-4diC9HaTE+KRAMWhDhrGOECgWZxoevMc5TlkObMqNSsVU62PYzXZ/SMTjzyGAFF1YusgxGcSWTEXBhp0CPwQ1A==",
- "dev": true,
- "engines": {
- "node": ">=6"
- }
- },
- "node_modules/cliui": {
- "version": "4.1.0",
- "resolved": "https://registry.npmjs.org/cliui/-/cliui-4.1.0.tgz",
- "integrity": "sha512-4FG+RSG9DL7uEwRUZXZn3SS34DiDPfzP0VOiEwtUWlE+AR2EIg+hSyvrIgUUfhdgR/UkAeW2QHgeP+hWrXs7jQ==",
- "dev": true,
- "dependencies": {
- "string-width": "^2.1.1",
- "strip-ansi": "^4.0.0",
- "wrap-ansi": "^2.0.0"
- }
- },
- "node_modules/code-point-at": {
- "version": "1.1.0",
- "resolved": "https://registry.npmjs.org/code-point-at/-/code-point-at-1.1.0.tgz",
- "integrity": "sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c=",
- "dev": true,
- "engines": {
- "node": ">=0.10.0"
- }
- },
- "node_modules/color-convert": {
- "version": "1.9.3",
- "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz",
- "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==",
- "dev": true,
- "dependencies": {
- "color-name": "1.1.3"
- }
- },
- "node_modules/color-name": {
- "version": "1.1.3",
- "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz",
- "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=",
- "dev": true
- },
- "node_modules/color-support": {
- "version": "1.1.3",
- "resolved": "https://registry.npmjs.org/color-support/-/color-support-1.1.3.tgz",
- "integrity": "sha512-qiBjkpbMLO/HL68y+lh4q0/O1MZFj2RX6X/KmMa3+gJD3z+WwI1ZzDHysvqHGS3mP6mznPckpXmw1nI9cJjyRg==",
- "dev": true,
- "bin": {
- "color-support": "bin.js"
- }
- },
- "node_modules/colorette": {
- "version": "1.2.2",
- "resolved": "https://registry.npmjs.org/colorette/-/colorette-1.2.2.tgz",
- "integrity": "sha512-MKGMzyfeuutC/ZJ1cba9NqcNpfeqMUcYmyF1ZFY6/Cn7CNSAKx6a+s48sqLqyAiZuaP2TcqMhoo+dlwFnVxT9w==",
- "dev": true
- },
- "node_modules/combined-stream": {
- "version": "1.0.8",
- "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz",
- "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==",
- "dependencies": {
- "delayed-stream": "~1.0.0"
- },
- "engines": {
- "node": ">= 0.8"
- }
- },
- "node_modules/commondir": {
- "version": "1.0.1",
- "resolved": "https://registry.npmjs.org/commondir/-/commondir-1.0.1.tgz",
- "integrity": "sha1-3dgA2gxmEnOTzKWVDqloo6rxJTs=",
- "dev": true
- },
- "node_modules/complex.js": {
- "version": "2.0.15",
- "resolved": "https://registry.npmjs.org/complex.js/-/complex.js-2.0.15.tgz",
- "integrity": "sha512-gDBvQU8IG139ZBQTSo2qvDFP+lANMGluM779csXOr6ny1NUtA3wkUnCFjlDNH/moAVfXtvClYt6G0zarFbtz5w==",
- "engines": {
- "node": "*"
- }
- },
- "node_modules/component-emitter": {
- "version": "1.3.0",
- "resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.3.0.tgz",
- "integrity": "sha512-Rd3se6QB+sO1TwqZjscQrurpEPIfO0/yYnSin6Q/rD3mOutHvUrCAhJub3r90uNb+SESBuE0QYoB90YdfatsRg=="
- },
- "node_modules/concat-map": {
- "version": "0.0.1",
- "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
- "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=",
- "dev": true
- },
- "node_modules/content-disposition": {
- "version": "0.5.4",
- "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.4.tgz",
- "integrity": "sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ==",
- "dependencies": {
- "safe-buffer": "5.2.1"
- },
- "engines": {
- "node": ">= 0.6"
- }
- },
- "node_modules/content-disposition/node_modules/safe-buffer": {
- "version": "5.2.1",
- "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz",
- "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==",
- "funding": [
- {
- "type": "github",
- "url": "https://github.com/sponsors/feross"
- },
- {
- "type": "patreon",
- "url": "https://www.patreon.com/feross"
- },
- {
- "type": "consulting",
- "url": "https://feross.org/support"
- }
- ]
- },
- "node_modules/content-type": {
- "version": "1.0.5",
- "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.5.tgz",
- "integrity": "sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==",
- "engines": {
- "node": ">= 0.6"
- }
- },
- "node_modules/convert-source-map": {
- "version": "1.8.0",
- "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.8.0.tgz",
- "integrity": "sha512-+OQdjP49zViI/6i7nIJpA8rAl4sV/JdPfU9nZs3VqOwGIgizICvuN2ru6fMd+4llL0tar18UYJXfZ/TWtmhUjA==",
- "dev": true,
- "dependencies": {
- "safe-buffer": "~5.1.1"
- }
- },
- "node_modules/cookie": {
- "version": "0.5.0",
- "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.5.0.tgz",
- "integrity": "sha512-YZ3GUyn/o8gfKJlnlX7g7xq4gyO6OSuhGPKaaGssGB2qgDUS0gPgtTvoyZLTt9Ab6dC4hfc9dV5arkvc/OCmrw==",
- "engines": {
- "node": ">= 0.6"
- }
- },
- "node_modules/cookie-signature": {
- "version": "1.0.6",
- "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz",
- "integrity": "sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ=="
- },
- "node_modules/cookiejar": {
- "version": "2.1.4",
- "resolved": "https://registry.npmjs.org/cookiejar/-/cookiejar-2.1.4.tgz",
- "integrity": "sha512-LDx6oHrK+PhzLKJU9j5S7/Y3jM/mUHvD/DeI1WQmJn652iPC5Y4TBzC9l+5OMOXlyTTA+SmVUPm0HQUwpD5Jqw=="
- },
- "node_modules/core-util-is": {
- "version": "1.0.2",
- "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz",
- "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=",
- "dev": true
- },
- "node_modules/coveralls": {
- "version": "3.1.1",
- "resolved": "https://registry.npmjs.org/coveralls/-/coveralls-3.1.1.tgz",
- "integrity": "sha512-+dxnG2NHncSD1NrqbSM3dn/lE57O6Qf/koe9+I7c+wzkqRmEvcp0kgJdxKInzYzkICKkFMZsX3Vct3++tsF9ww==",
- "dev": true,
- "dependencies": {
- "js-yaml": "^3.13.1",
- "lcov-parse": "^1.0.0",
- "log-driver": "^1.2.7",
- "minimist": "^1.2.5",
- "request": "^2.88.2"
- },
- "bin": {
- "coveralls": "bin/coveralls.js"
- },
- "engines": {
- "node": ">=6"
- }
- },
- "node_modules/cross-spawn": {
- "version": "7.0.3",
- "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz",
- "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==",
- "dev": true,
- "dependencies": {
- "path-key": "^3.1.0",
- "shebang-command": "^2.0.0",
- "which": "^2.0.1"
- },
- "engines": {
- "node": ">= 8"
- }
- },
- "node_modules/dashdash": {
- "version": "1.14.1",
- "resolved": "https://registry.npmjs.org/dashdash/-/dashdash-1.14.1.tgz",
- "integrity": "sha1-hTz6D3y+L+1d4gMmuN1YEDX24vA=",
- "dev": true,
- "dependencies": {
- "assert-plus": "^1.0.0"
- },
- "engines": {
- "node": ">=0.10"
- }
- },
- "node_modules/debug": {
- "version": "2.6.9",
- "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
- "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
- "dependencies": {
- "ms": "2.0.0"
- }
- },
- "node_modules/decamelize": {
- "version": "1.2.0",
- "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz",
- "integrity": "sha1-9lNNFRSCabIDUue+4m9QH5oZEpA=",
- "dev": true,
- "engines": {
- "node": ">=0.10.0"
- }
- },
- "node_modules/decimal.js": {
- "version": "10.3.1",
- "resolved": "https://registry.npmjs.org/decimal.js/-/decimal.js-10.3.1.tgz",
- "integrity": "sha512-V0pfhfr8suzyPGOx3nmq4aHqabehUZn6Ch9kyFpV79TGDTWFmHqUqXdabR7QHqxzrYolF4+tVmJhUG4OURg5dQ=="
- },
- "node_modules/default-require-extensions": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/default-require-extensions/-/default-require-extensions-3.0.0.tgz",
- "integrity": "sha512-ek6DpXq/SCpvjhpFsLFRVtIxJCRw6fUR42lYMVZuUMK7n8eMz4Uh5clckdBjEpLhn/gEBZo7hDJnJcwdKLKQjg==",
- "dev": true,
- "dependencies": {
- "strip-bom": "^4.0.0"
- },
- "engines": {
- "node": ">=8"
- }
- },
- "node_modules/delayed-stream": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz",
- "integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk=",
- "engines": {
- "node": ">=0.4.0"
- }
- },
- "node_modules/depd": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz",
- "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==",
- "engines": {
- "node": ">= 0.8"
- }
- },
- "node_modules/destroy": {
- "version": "1.2.0",
- "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.2.0.tgz",
- "integrity": "sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg==",
- "engines": {
- "node": ">= 0.8",
- "npm": "1.2.8000 || >= 1.4.16"
- }
- },
- "node_modules/dezalgo": {
- "version": "1.0.4",
- "resolved": "https://registry.npmjs.org/dezalgo/-/dezalgo-1.0.4.tgz",
- "integrity": "sha512-rXSP0bf+5n0Qonsb+SVVfNfIsimO4HEtmnIpPHY8Q1UCzKlQrDMfdobr8nJOOsRgWCyMRqeSBQzmWUMq7zvVig==",
- "dependencies": {
- "asap": "^2.0.0",
- "wrappy": "1"
- }
- },
- "node_modules/diff": {
- "version": "4.0.2",
- "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz",
- "integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==",
- "dev": true,
- "engines": {
- "node": ">=0.3.1"
- }
- },
- "node_modules/ecc-jsbn": {
- "version": "0.1.2",
- "resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz",
- "integrity": "sha1-OoOpBOVDUyh4dMVkt1SThoSamMk=",
- "dev": true,
- "dependencies": {
- "jsbn": "~0.1.0",
- "safer-buffer": "^2.1.0"
- }
- },
- "node_modules/ee-first": {
- "version": "1.1.1",
- "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz",
- "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow=="
- },
- "node_modules/electron-to-chromium": {
- "version": "1.3.780",
- "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.780.tgz",
- "integrity": "sha512-2KQ9OYm9WMUNpAPA/4aerURl3hwRc9tNlpsiEj3Y8Gf7LVf26NzyLIX2v0hSagQwrS9+cWab+28A2GPKDoVNRA==",
- "dev": true
- },
- "node_modules/emoji-regex": {
- "version": "8.0.0",
- "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz",
- "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==",
- "dev": true
- },
- "node_modules/encodeurl": {
- "version": "1.0.2",
- "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz",
- "integrity": "sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==",
- "engines": {
- "node": ">= 0.8"
- }
- },
- "node_modules/es6-error": {
- "version": "4.1.1",
- "resolved": "https://registry.npmjs.org/es6-error/-/es6-error-4.1.1.tgz",
- "integrity": "sha512-Um/+FxMr9CISWh0bi5Zv0iOD+4cFh5qLeks1qhAopKVAJw3drgKbKySikp7wGhDL0HPeaja0P5ULZrxLkniUVg==",
- "dev": true
- },
- "node_modules/escalade": {
- "version": "3.1.1",
- "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz",
- "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==",
- "dev": true,
- "engines": {
- "node": ">=6"
- }
- },
- "node_modules/escape-html": {
- "version": "1.0.3",
- "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz",
- "integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow=="
- },
- "node_modules/escape-latex": {
- "version": "1.2.0",
- "resolved": "https://registry.npmjs.org/escape-latex/-/escape-latex-1.2.0.tgz",
- "integrity": "sha512-nV5aVWW1K0wEiUIEdZ4erkGGH8mDxGyxSeqPzRNtWP7ataw+/olFObw7hujFWlVjNsaDFw5VZ5NzVSIqRgfTiw=="
- },
- "node_modules/escape-string-regexp": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-2.0.0.tgz",
- "integrity": "sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w==",
- "dev": true,
- "engines": {
- "node": ">=8"
- }
- },
- "node_modules/esprima": {
- "version": "4.0.1",
- "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz",
- "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==",
- "dev": true,
- "bin": {
- "esparse": "bin/esparse.js",
- "esvalidate": "bin/esvalidate.js"
- },
- "engines": {
- "node": ">=4"
- }
- },
- "node_modules/etag": {
- "version": "1.8.1",
- "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz",
- "integrity": "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==",
- "engines": {
- "node": ">= 0.6"
- }
- },
- "node_modules/events-to-array": {
- "version": "1.1.2",
- "resolved": "https://registry.npmjs.org/events-to-array/-/events-to-array-1.1.2.tgz",
- "integrity": "sha1-LUH1Y+H+QA7Uli/hpNXGp1Od9/Y=",
- "dev": true
- },
- "node_modules/express": {
- "version": "4.18.2",
- "resolved": "https://registry.npmjs.org/express/-/express-4.18.2.tgz",
- "integrity": "sha512-5/PsL6iGPdfQ/lKM1UuielYgv3BUoJfz1aUwU9vHZ+J7gyvwdQXFEBIEIaxeGf0GIcreATNyBExtalisDbuMqQ==",
- "dependencies": {
- "accepts": "~1.3.8",
- "array-flatten": "1.1.1",
- "body-parser": "1.20.1",
- "content-disposition": "0.5.4",
- "content-type": "~1.0.4",
- "cookie": "0.5.0",
- "cookie-signature": "1.0.6",
- "debug": "2.6.9",
- "depd": "2.0.0",
- "encodeurl": "~1.0.2",
- "escape-html": "~1.0.3",
- "etag": "~1.8.1",
- "finalhandler": "1.2.0",
- "fresh": "0.5.2",
- "http-errors": "2.0.0",
- "merge-descriptors": "1.0.1",
- "methods": "~1.1.2",
- "on-finished": "2.4.1",
- "parseurl": "~1.3.3",
- "path-to-regexp": "0.1.7",
- "proxy-addr": "~2.0.7",
- "qs": "6.11.0",
- "range-parser": "~1.2.1",
- "safe-buffer": "5.2.1",
- "send": "0.18.0",
- "serve-static": "1.15.0",
- "setprototypeof": "1.2.0",
- "statuses": "2.0.1",
- "type-is": "~1.6.18",
- "utils-merge": "1.0.1",
- "vary": "~1.1.2"
- },
- "engines": {
- "node": ">= 0.10.0"
- }
- },
- "node_modules/express/node_modules/safe-buffer": {
- "version": "5.2.1",
- "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz",
- "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==",
- "funding": [
- {
- "type": "github",
- "url": "https://github.com/sponsors/feross"
- },
- {
- "type": "patreon",
- "url": "https://www.patreon.com/feross"
- },
- {
- "type": "consulting",
- "url": "https://feross.org/support"
- }
- ]
- },
- "node_modules/extend": {
- "version": "3.0.2",
- "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz",
- "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==",
- "dev": true
- },
- "node_modules/extsprintf": {
- "version": "1.3.0",
- "resolved": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.3.0.tgz",
- "integrity": "sha1-lpGEQOMEGnpBT4xS48V06zw+HgU=",
- "dev": true,
- "engines": [
- "node >=0.6.0"
- ]
- },
- "node_modules/fast-deep-equal": {
- "version": "3.1.3",
- "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz",
- "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==",
- "dev": true
- },
- "node_modules/fast-json-stable-stringify": {
- "version": "2.1.0",
- "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz",
- "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==",
- "dev": true
- },
- "node_modules/fast-safe-stringify": {
- "version": "2.1.1",
- "resolved": "https://registry.npmjs.org/fast-safe-stringify/-/fast-safe-stringify-2.1.1.tgz",
- "integrity": "sha512-W+KJc2dmILlPplD/H4K9l9LcAHAfPtP6BY84uVLXQ6Evcz9Lcg33Y2z1IVblT6xdY54PXYVHEv+0Wpq8Io6zkA=="
- },
- "node_modules/fill-range": {
- "version": "7.0.1",
- "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz",
- "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==",
- "dev": true,
- "dependencies": {
- "to-regex-range": "^5.0.1"
- },
- "engines": {
- "node": ">=8"
- }
- },
- "node_modules/finalhandler": {
- "version": "1.2.0",
- "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.2.0.tgz",
- "integrity": "sha512-5uXcUVftlQMFnWC9qu/svkWv3GTd2PfUhK/3PLkYNAe7FbqJMt3515HaxE6eRL74GdsriiwujiawdaB1BpEISg==",
- "dependencies": {
- "debug": "2.6.9",
- "encodeurl": "~1.0.2",
- "escape-html": "~1.0.3",
- "on-finished": "2.4.1",
- "parseurl": "~1.3.3",
- "statuses": "2.0.1",
- "unpipe": "~1.0.0"
- },
- "engines": {
- "node": ">= 0.8"
- }
- },
- "node_modules/find-cache-dir": {
- "version": "3.3.1",
- "resolved": "https://registry.npmjs.org/find-cache-dir/-/find-cache-dir-3.3.1.tgz",
- "integrity": "sha512-t2GDMt3oGC/v+BMwzmllWDuJF/xcDtE5j/fCGbqDD7OLuJkj0cfh1YSA5VKPvwMeLFLNDBkwOKZ2X85jGLVftQ==",
- "dev": true,
- "dependencies": {
- "commondir": "^1.0.1",
- "make-dir": "^3.0.2",
- "pkg-dir": "^4.1.0"
- },
- "engines": {
- "node": ">=8"
- }
- },
- "node_modules/find-up": {
- "version": "4.1.0",
- "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz",
- "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==",
- "dev": true,
- "dependencies": {
- "locate-path": "^5.0.0",
- "path-exists": "^4.0.0"
- },
- "engines": {
- "node": ">=8"
- }
- },
- "node_modules/findit": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/findit/-/findit-2.0.0.tgz",
- "integrity": "sha1-ZQnwEmr0wXhVHPqZOU4DLhOk1W4=",
- "dev": true
- },
- "node_modules/foreground-child": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-2.0.0.tgz",
- "integrity": "sha512-dCIq9FpEcyQyXKCkyzmlPTFNgrCzPudOe+mhvJU5zAtlBnGVy2yKxtfsxK2tQBThwq225jcvBjpw1Gr40uzZCA==",
- "dev": true,
- "dependencies": {
- "cross-spawn": "^7.0.0",
- "signal-exit": "^3.0.2"
- },
- "engines": {
- "node": ">=8.0.0"
- }
- },
- "node_modules/forever-agent": {
- "version": "0.6.1",
- "resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz",
- "integrity": "sha1-+8cfDEGt6zf5bFd60e1C2P2sypE=",
- "dev": true,
- "engines": {
- "node": "*"
- }
- },
- "node_modules/form-data": {
- "version": "4.0.0",
- "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz",
- "integrity": "sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==",
- "dependencies": {
- "asynckit": "^0.4.0",
- "combined-stream": "^1.0.8",
- "mime-types": "^2.1.12"
- },
- "engines": {
- "node": ">= 6"
- }
- },
- "node_modules/formidable": {
- "version": "2.1.2",
- "resolved": "https://registry.npmjs.org/formidable/-/formidable-2.1.2.tgz",
- "integrity": "sha512-CM3GuJ57US06mlpQ47YcunuUZ9jpm8Vx+P2CGt2j7HpgkKZO/DJYQ0Bobim8G6PFQmK5lOqOOdUXboU+h73A4g==",
- "dependencies": {
- "dezalgo": "^1.0.4",
- "hexoid": "^1.0.0",
- "once": "^1.4.0",
- "qs": "^6.11.0"
- },
- "funding": {
- "url": "https://ko-fi.com/tunnckoCore/commissions"
- }
- },
- "node_modules/forwarded": {
- "version": "0.2.0",
- "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz",
- "integrity": "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==",
- "engines": {
- "node": ">= 0.6"
- }
- },
- "node_modules/fraction.js": {
- "version": "4.1.1",
- "resolved": "https://registry.npmjs.org/fraction.js/-/fraction.js-4.1.1.tgz",
- "integrity": "sha512-MHOhvvxHTfRFpF1geTK9czMIZ6xclsEor2wkIGYYq+PxcQqT7vStJqjhe6S1TenZrMZzo+wlqOufBDVepUEgPg==",
- "engines": {
- "node": "*"
- }
- },
- "node_modules/fresh": {
- "version": "0.5.2",
- "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz",
- "integrity": "sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q==",
- "engines": {
- "node": ">= 0.6"
- }
- },
- "node_modules/fromentries": {
- "version": "1.3.2",
- "resolved": "https://registry.npmjs.org/fromentries/-/fromentries-1.3.2.tgz",
- "integrity": "sha512-cHEpEQHUg0f8XdtZCc2ZAhrHzKzT0MrFUTcvx+hfxYu7rGMDc5SKoXFh+n4YigxsHXRzc6OrCshdR1bWH6HHyg==",
- "dev": true
- },
- "node_modules/fs-exists-cached": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/fs-exists-cached/-/fs-exists-cached-1.0.0.tgz",
- "integrity": "sha1-zyVVTKBQ3EmuZla0HeQiWJidy84=",
- "dev": true
- },
- "node_modules/fs.realpath": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz",
- "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8="
- },
- "node_modules/fsevents": {
- "version": "2.3.2",
- "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz",
- "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==",
- "dev": true,
- "optional": true,
- "os": [
- "darwin"
- ],
- "engines": {
- "node": "^8.16.0 || ^10.6.0 || >=11.0.0"
- }
- },
- "node_modules/function-bind": {
- "version": "1.1.1",
- "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz",
- "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A=="
- },
- "node_modules/function-loop": {
- "version": "2.0.1",
- "resolved": "https://registry.npmjs.org/function-loop/-/function-loop-2.0.1.tgz",
- "integrity": "sha512-ktIR+O6i/4h+j/ZhZJNdzeI4i9lEPeEK6UPR2EVyTVBqOwcU3Za9xYKLH64ZR9HmcROyRrOkizNyjjtWJzDDkQ==",
- "dev": true
- },
- "node_modules/gensync": {
- "version": "1.0.0-beta.2",
- "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz",
- "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==",
- "dev": true,
- "engines": {
- "node": ">=6.9.0"
- }
- },
- "node_modules/get-caller-file": {
- "version": "2.0.5",
- "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz",
- "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==",
- "dev": true,
- "engines": {
- "node": "6.* || 8.* || >= 10.*"
- }
- },
- "node_modules/get-intrinsic": {
- "version": "1.2.0",
- "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.0.tgz",
- "integrity": "sha512-L049y6nFOuom5wGyRc3/gdTLO94dySVKRACj1RmJZBQXlbTMhtNIgkWkUHq+jYmZvKf14EW1EoJnnjbmoHij0Q==",
- "dependencies": {
- "function-bind": "^1.1.1",
- "has": "^1.0.3",
- "has-symbols": "^1.0.3"
- },
- "funding": {
- "url": "https://github.com/sponsors/ljharb"
- }
- },
- "node_modules/get-package-type": {
- "version": "0.1.0",
- "resolved": "https://registry.npmjs.org/get-package-type/-/get-package-type-0.1.0.tgz",
- "integrity": "sha512-pjzuKtY64GYfWizNAJ0fr9VqttZkNiK2iS430LtIHzjBEr6bX8Am2zm4sW4Ro5wjWW5cAlRL1qAMTcXbjNAO2Q==",
- "dev": true,
- "engines": {
- "node": ">=8.0.0"
- }
- },
- "node_modules/getpass": {
- "version": "0.1.7",
- "resolved": "https://registry.npmjs.org/getpass/-/getpass-0.1.7.tgz",
- "integrity": "sha1-Xv+OPmhNVprkyysSgmBOi6YhSfo=",
- "dev": true,
- "dependencies": {
- "assert-plus": "^1.0.0"
- }
- },
- "node_modules/glob": {
- "version": "7.1.7",
- "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.7.tgz",
- "integrity": "sha512-OvD9ENzPLbegENnYP5UUfJIirTg4+XwMWGaQfQTY0JenxNvvIKP3U3/tAQSPIu/lHxXYSZmpXlUHeqAIdKzBLQ==",
- "dev": true,
- "dependencies": {
- "fs.realpath": "^1.0.0",
- "inflight": "^1.0.4",
- "inherits": "2",
- "minimatch": "^3.0.4",
- "once": "^1.3.0",
- "path-is-absolute": "^1.0.0"
- },
- "engines": {
- "node": "*"
- }
- },
- "node_modules/glob-parent": {
- "version": "5.1.2",
- "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz",
- "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==",
- "dev": true,
- "dependencies": {
- "is-glob": "^4.0.1"
- },
- "engines": {
- "node": ">= 6"
- }
- },
- "node_modules/globals": {
- "version": "11.12.0",
- "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz",
- "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==",
- "dev": true,
- "engines": {
- "node": ">=4"
- }
- },
- "node_modules/graceful-fs": {
- "version": "4.2.6",
- "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.6.tgz",
- "integrity": "sha512-nTnJ528pbqxYanhpDYsi4Rd8MAeaBA67+RZ10CM1m3bTAVFEDcd5AuA4a6W5YkGZ1iNXHzZz8T6TBKLeBuNriQ==",
- "dev": true
- },
- "node_modules/har-schema": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/har-schema/-/har-schema-2.0.0.tgz",
- "integrity": "sha1-qUwiJOvKwEeCoNkDVSHyRzW37JI=",
- "dev": true,
- "engines": {
- "node": ">=4"
- }
- },
- "node_modules/har-validator": {
- "version": "5.1.5",
- "resolved": "https://registry.npmjs.org/har-validator/-/har-validator-5.1.5.tgz",
- "integrity": "sha512-nmT2T0lljbxdQZfspsno9hgrG3Uir6Ks5afism62poxqBM6sDnMEuPmzTq8XN0OEwqKLLdh1jQI3qyE66Nzb3w==",
- "dev": true,
- "dependencies": {
- "ajv": "^6.12.3",
- "har-schema": "^2.0.0"
- },
- "engines": {
- "node": ">=6"
- }
- },
- "node_modules/has": {
- "version": "1.0.3",
- "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz",
- "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==",
- "dependencies": {
- "function-bind": "^1.1.1"
- },
- "engines": {
- "node": ">= 0.4.0"
- }
- },
- "node_modules/has-flag": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz",
- "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=",
- "dev": true,
- "engines": {
- "node": ">=4"
- }
- },
- "node_modules/has-symbols": {
- "version": "1.0.3",
- "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz",
- "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==",
- "engines": {
- "node": ">= 0.4"
- },
- "funding": {
- "url": "https://github.com/sponsors/ljharb"
- }
- },
- "node_modules/hasha": {
- "version": "5.2.2",
- "resolved": "https://registry.npmjs.org/hasha/-/hasha-5.2.2.tgz",
- "integrity": "sha512-Hrp5vIK/xr5SkeN2onO32H0MgNZ0f17HRNH39WfL0SYUNOTZ5Lz1TJ8Pajo/87dYGEFlLMm7mIc/k/s6Bvz9HQ==",
- "dev": true,
- "dependencies": {
- "is-stream": "^2.0.0",
- "type-fest": "^0.8.0"
- },
- "engines": {
- "node": ">=8"
- }
- },
- "node_modules/hexoid": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/hexoid/-/hexoid-1.0.0.tgz",
- "integrity": "sha512-QFLV0taWQOZtvIRIAdBChesmogZrtuXvVWsFHZTk2SU+anspqZ2vMnoLg7IE1+Uk16N19APic1BuF8bC8c2m5g==",
- "engines": {
- "node": ">=8"
- }
- },
- "node_modules/html-escaper": {
- "version": "2.0.2",
- "resolved": "https://registry.npmjs.org/html-escaper/-/html-escaper-2.0.2.tgz",
- "integrity": "sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==",
- "dev": true
- },
- "node_modules/http-errors": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz",
- "integrity": "sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==",
- "dependencies": {
- "depd": "2.0.0",
- "inherits": "2.0.4",
- "setprototypeof": "1.2.0",
- "statuses": "2.0.1",
- "toidentifier": "1.0.1"
- },
- "engines": {
- "node": ">= 0.8"
- }
- },
- "node_modules/http-signature": {
- "version": "1.2.0",
- "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.2.0.tgz",
- "integrity": "sha1-muzZJRFHcvPZW2WmCruPfBj7rOE=",
- "dev": true,
- "dependencies": {
- "assert-plus": "^1.0.0",
- "jsprim": "^1.2.2",
- "sshpk": "^1.7.0"
- },
- "engines": {
- "node": ">=0.8",
- "npm": ">=1.3.7"
- }
- },
- "node_modules/iconv-lite": {
- "version": "0.4.24",
- "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz",
- "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==",
- "dependencies": {
- "safer-buffer": ">= 2.1.2 < 3"
- },
- "engines": {
- "node": ">=0.10.0"
- }
- },
- "node_modules/imurmurhash": {
- "version": "0.1.4",
- "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz",
- "integrity": "sha1-khi5srkoojixPcT7a21XbyMUU+o=",
- "dev": true,
- "engines": {
- "node": ">=0.8.19"
- }
- },
- "node_modules/indent-string": {
- "version": "4.0.0",
- "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-4.0.0.tgz",
- "integrity": "sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==",
- "dev": true,
- "engines": {
- "node": ">=8"
- }
- },
- "node_modules/inflight": {
- "version": "1.0.6",
- "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz",
- "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=",
- "dev": true,
- "dependencies": {
- "once": "^1.3.0",
- "wrappy": "1"
- }
- },
- "node_modules/inherits": {
- "version": "2.0.4",
- "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz",
- "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ=="
- },
- "node_modules/ipaddr.js": {
- "version": "1.9.1",
- "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz",
- "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==",
- "engines": {
- "node": ">= 0.10"
- }
- },
- "node_modules/is-binary-path": {
- "version": "2.1.0",
- "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz",
- "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==",
- "dev": true,
- "dependencies": {
- "binary-extensions": "^2.0.0"
- },
- "engines": {
- "node": ">=8"
- }
- },
- "node_modules/is-extglob": {
- "version": "2.1.1",
- "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz",
- "integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=",
- "dev": true,
- "engines": {
- "node": ">=0.10.0"
- }
- },
- "node_modules/is-fullwidth-code-point": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz",
- "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=",
- "dev": true,
- "engines": {
- "node": ">=4"
- }
- },
- "node_modules/is-glob": {
- "version": "4.0.1",
- "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.1.tgz",
- "integrity": "sha512-5G0tKtBTFImOqDnLB2hG6Bp2qcKEFduo4tZu9MT/H6NQv/ghhy30o55ufafxJ/LdH79LLs2Kfrn85TLKyA7BUg==",
- "dev": true,
- "dependencies": {
- "is-extglob": "^2.1.1"
- },
- "engines": {
- "node": ">=0.10.0"
- }
- },
- "node_modules/is-number": {
- "version": "7.0.0",
- "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz",
- "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==",
- "dev": true,
- "engines": {
- "node": ">=0.12.0"
- }
- },
- "node_modules/is-stream": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.0.tgz",
- "integrity": "sha512-XCoy+WlUr7d1+Z8GgSuXmpuUFC9fOhRXglJMx+dwLKTkL44Cjd4W1Z5P+BQZpr+cR93aGP4S/s7Ftw6Nd/kiEw==",
- "dev": true,
- "engines": {
- "node": ">=8"
- }
- },
- "node_modules/is-typedarray": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz",
- "integrity": "sha1-5HnICFjfDBsR3dppQPlgEfzaSpo=",
- "dev": true
- },
- "node_modules/is-windows": {
- "version": "1.0.2",
- "resolved": "https://registry.npmjs.org/is-windows/-/is-windows-1.0.2.tgz",
- "integrity": "sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA==",
- "dev": true,
- "engines": {
- "node": ">=0.10.0"
- }
- },
- "node_modules/isexe": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz",
- "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=",
- "dev": true
- },
- "node_modules/isstream": {
- "version": "0.1.2",
- "resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz",
- "integrity": "sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo=",
- "dev": true
- },
- "node_modules/istanbul-lib-coverage": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-3.0.0.tgz",
- "integrity": "sha512-UiUIqxMgRDET6eR+o5HbfRYP1l0hqkWOs7vNxC/mggutCMUIhWMm8gAHb8tHlyfD3/l6rlgNA5cKdDzEAf6hEg==",
- "dev": true,
- "engines": {
- "node": ">=8"
- }
- },
- "node_modules/istanbul-lib-hook": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/istanbul-lib-hook/-/istanbul-lib-hook-3.0.0.tgz",
- "integrity": "sha512-Pt/uge1Q9s+5VAZ+pCo16TYMWPBIl+oaNIjgLQxcX0itS6ueeaA+pEfThZpH8WxhFgCiEb8sAJY6MdUKgiIWaQ==",
- "dev": true,
- "dependencies": {
- "append-transform": "^2.0.0"
- },
- "engines": {
- "node": ">=8"
- }
- },
- "node_modules/istanbul-lib-instrument": {
- "version": "4.0.3",
- "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-4.0.3.tgz",
- "integrity": "sha512-BXgQl9kf4WTCPCCpmFGoJkz/+uhvm7h7PFKUYxh7qarQd3ER33vHG//qaE8eN25l07YqZPpHXU9I09l/RD5aGQ==",
- "dev": true,
- "dependencies": {
- "@babel/core": "^7.7.5",
- "@istanbuljs/schema": "^0.1.2",
- "istanbul-lib-coverage": "^3.0.0",
- "semver": "^6.3.0"
- },
- "engines": {
- "node": ">=8"
- }
- },
- "node_modules/istanbul-lib-processinfo": {
- "version": "2.0.2",
- "resolved": "https://registry.npmjs.org/istanbul-lib-processinfo/-/istanbul-lib-processinfo-2.0.2.tgz",
- "integrity": "sha512-kOwpa7z9hme+IBPZMzQ5vdQj8srYgAtaRqeI48NGmAQ+/5yKiHLV0QbYqQpxsdEF0+w14SoB8YbnHKcXE2KnYw==",
- "dev": true,
- "dependencies": {
- "archy": "^1.0.0",
- "cross-spawn": "^7.0.0",
- "istanbul-lib-coverage": "^3.0.0-alpha.1",
- "make-dir": "^3.0.0",
- "p-map": "^3.0.0",
- "rimraf": "^3.0.0",
- "uuid": "^3.3.3"
- },
- "engines": {
- "node": ">=8"
- }
- },
- "node_modules/istanbul-lib-report": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/istanbul-lib-report/-/istanbul-lib-report-3.0.0.tgz",
- "integrity": "sha512-wcdi+uAKzfiGT2abPpKZ0hSU1rGQjUQnLvtY5MpQ7QCTahD3VODhcu4wcfY1YtkGaDD5yuydOLINXsfbus9ROw==",
- "dev": true,
- "dependencies": {
- "istanbul-lib-coverage": "^3.0.0",
- "make-dir": "^3.0.0",
- "supports-color": "^7.1.0"
- },
- "engines": {
- "node": ">=8"
- }
- },
- "node_modules/istanbul-lib-report/node_modules/has-flag": {
- "version": "4.0.0",
- "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
- "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
- "dev": true,
- "engines": {
- "node": ">=8"
- }
- },
- "node_modules/istanbul-lib-report/node_modules/supports-color": {
- "version": "7.2.0",
- "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
- "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==",
- "dev": true,
- "dependencies": {
- "has-flag": "^4.0.0"
- },
- "engines": {
- "node": ">=8"
- }
- },
- "node_modules/istanbul-lib-source-maps": {
- "version": "4.0.0",
- "resolved": "https://registry.npmjs.org/istanbul-lib-source-maps/-/istanbul-lib-source-maps-4.0.0.tgz",
- "integrity": "sha512-c16LpFRkR8vQXyHZ5nLpY35JZtzj1PQY1iZmesUbf1FZHbIupcWfjgOXBY9YHkLEQ6puz1u4Dgj6qmU/DisrZg==",
- "dev": true,
- "dependencies": {
- "debug": "^4.1.1",
- "istanbul-lib-coverage": "^3.0.0",
- "source-map": "^0.6.1"
- },
- "engines": {
- "node": ">=8"
- }
- },
- "node_modules/istanbul-lib-source-maps/node_modules/debug": {
- "version": "4.3.2",
- "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.2.tgz",
- "integrity": "sha512-mOp8wKcvj7XxC78zLgw/ZA+6TSgkoE2C/ienthhRD298T7UNwAg9diBpLRxC0mOezLl4B0xV7M0cCO6P/O0Xhw==",
- "dev": true,
- "dependencies": {
- "ms": "2.1.2"
- },
- "engines": {
- "node": ">=6.0"
- }
- },
- "node_modules/istanbul-lib-source-maps/node_modules/ms": {
- "version": "2.1.2",
- "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
- "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==",
- "dev": true
- },
- "node_modules/istanbul-lib-source-maps/node_modules/source-map": {
- "version": "0.6.1",
- "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
- "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==",
- "dev": true,
- "engines": {
- "node": ">=0.10.0"
- }
- },
- "node_modules/istanbul-reports": {
- "version": "3.0.2",
- "resolved": "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-3.0.2.tgz",
- "integrity": "sha512-9tZvz7AiR3PEDNGiV9vIouQ/EAcqMXFmkcA1CDFTwOB98OZVDL0PH9glHotf5Ugp6GCOTypfzGWI/OqjWNCRUw==",
- "dev": true,
- "dependencies": {
- "html-escaper": "^2.0.0",
- "istanbul-lib-report": "^3.0.0"
- },
- "engines": {
- "node": ">=8"
- }
- },
- "node_modules/jackspeak": {
- "version": "1.4.0",
- "resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-1.4.0.tgz",
- "integrity": "sha512-VDcSunT+wcccoG46FtzuBAyQKlzhHjli4q31e1fIHGOsRspqNUFjVzGb+7eIFDlTvqLygxapDHPHS0ouT2o/tw==",
- "dev": true,
- "dependencies": {
- "cliui": "^4.1.0"
- },
- "engines": {
- "node": ">=8"
- }
- },
- "node_modules/javascript-natural-sort": {
- "version": "0.7.1",
- "resolved": "https://registry.npmjs.org/javascript-natural-sort/-/javascript-natural-sort-0.7.1.tgz",
- "integrity": "sha1-+eIwPUUH9tdDVac2ZNFED7Wg71k="
- },
- "node_modules/jquery": {
- "version": "3.6.0",
- "resolved": "https://registry.npmjs.org/jquery/-/jquery-3.6.0.tgz",
- "integrity": "sha512-JVzAR/AjBvVt2BmYhxRCSYysDsPcssdmTFnzyLEts9qNwmjmu4JTAMYubEfwVOSwpQ1I1sKKFcxhZCI2buerfw=="
- },
- "node_modules/js-tokens": {
- "version": "4.0.0",
- "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz",
- "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==",
- "dev": true
- },
- "node_modules/js-yaml": {
- "version": "3.14.1",
- "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz",
- "integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==",
- "dev": true,
- "dependencies": {
- "argparse": "^1.0.7",
- "esprima": "^4.0.0"
- },
- "bin": {
- "js-yaml": "bin/js-yaml.js"
- }
- },
- "node_modules/jsbn": {
- "version": "0.1.1",
- "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-0.1.1.tgz",
- "integrity": "sha1-peZUwuWi3rXyAdls77yoDA7y9RM=",
- "dev": true
- },
- "node_modules/jsesc": {
- "version": "2.5.2",
- "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz",
- "integrity": "sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==",
- "dev": true,
- "bin": {
- "jsesc": "bin/jsesc"
- },
- "engines": {
- "node": ">=4"
- }
- },
- "node_modules/json-schema": {
- "version": "0.2.3",
- "resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.2.3.tgz",
- "integrity": "sha1-tIDIkuWaLwWVTOcnvT8qTogvnhM=",
- "dev": true
- },
- "node_modules/json-schema-traverse": {
- "version": "0.4.1",
- "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz",
- "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==",
- "dev": true
- },
- "node_modules/json-stringify-safe": {
- "version": "5.0.1",
- "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz",
- "integrity": "sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus=",
- "dev": true
- },
- "node_modules/json5": {
- "version": "2.2.0",
- "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.0.tgz",
- "integrity": "sha512-f+8cldu7X/y7RAJurMEJmdoKXGB/X550w2Nr3tTbezL6RwEE/iMcm+tZnXeoZtKuOq6ft8+CqzEkrIgx1fPoQA==",
- "dev": true,
- "dependencies": {
- "minimist": "^1.2.5"
- },
- "bin": {
- "json5": "lib/cli.js"
- },
- "engines": {
- "node": ">=6"
- }
- },
- "node_modules/jsprim": {
- "version": "1.4.1",
- "resolved": "https://registry.npmjs.org/jsprim/-/jsprim-1.4.1.tgz",
- "integrity": "sha1-MT5mvB5cwG5Di8G3SZwuXFastqI=",
- "dev": true,
- "engines": [
- "node >=0.6.0"
- ],
- "dependencies": {
- "assert-plus": "1.0.0",
- "extsprintf": "1.3.0",
- "json-schema": "0.2.3",
- "verror": "1.10.0"
- }
- },
- "node_modules/jtree": {
- "version": "74.0.0",
- "resolved": "https://registry.npmjs.org/jtree/-/jtree-74.0.0.tgz",
- "integrity": "sha512-jKyvI60geVzmtfqahfG4kszQp2zg50N7JvtLTxaRamZpqi3J+a+3UduSEZvzBN8k7qSvcR7rA0TBbXSBinCOPw==",
- "dependencies": {
- "express": "^4.18.2",
- "glob": "^9.3.4",
- "mkdirp": "^2.1.6",
- "prettier": "^2.8.7",
- "recursive-readdir-sync": "^1.0.6",
- "superagent": "^8.0.9"
- },
- "engines": {
- "node": ">=16.0"
- }
- },
- "node_modules/jtree/node_modules/brace-expansion": {
- "version": "2.0.1",
- "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz",
- "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==",
- "dependencies": {
- "balanced-match": "^1.0.0"
- }
- },
- "node_modules/jtree/node_modules/glob": {
- "version": "9.3.4",
- "resolved": "https://registry.npmjs.org/glob/-/glob-9.3.4.tgz",
- "integrity": "sha512-qaSc49hojMOv1EPM4EuyITjDSgSKI0rthoHnvE81tcOi1SCVndHko7auqxdQ14eiQG2NDBJBE86+2xIrbIvrbA==",
- "dependencies": {
- "fs.realpath": "^1.0.0",
- "minimatch": "^8.0.2",
- "minipass": "^4.2.4",
- "path-scurry": "^1.6.1"
- },
- "engines": {
- "node": ">=16 || 14 >=14.17"
- },
- "funding": {
- "url": "https://github.com/sponsors/isaacs"
- }
- },
- "node_modules/jtree/node_modules/minimatch": {
- "version": "8.0.3",
- "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-8.0.3.tgz",
- "integrity": "sha512-tEEvU9TkZgnFDCtpnrEYnPsjT7iUx42aXfs4bzmQ5sMA09/6hZY0jeZcGkXyDagiBOvkUjNo8Viom+Me6+2x7g==",
- "dependencies": {
- "brace-expansion": "^2.0.1"
- },
- "engines": {
- "node": ">=16 || 14 >=14.17"
- },
- "funding": {
- "url": "https://github.com/sponsors/isaacs"
- }
- },
- "node_modules/jtree/node_modules/minipass": {
- "version": "4.2.5",
- "resolved": "https://registry.npmjs.org/minipass/-/minipass-4.2.5.tgz",
- "integrity": "sha512-+yQl7SX3bIT83Lhb4BVorMAHVuqsskxRdlmO9kTpyukp8vsm2Sn/fUOV9xlnG8/a5JsypJzap21lz/y3FBMJ8Q==",
- "engines": {
- "node": ">=8"
- }
- },
- "node_modules/lcov-parse": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/lcov-parse/-/lcov-parse-1.0.0.tgz",
- "integrity": "sha1-6w1GtUER68VhrLTECO+TY73I9+A=",
- "dev": true,
- "bin": {
- "lcov-parse": "bin/cli.js"
- }
- },
- "node_modules/libtap": {
- "version": "1.1.1",
- "resolved": "https://registry.npmjs.org/libtap/-/libtap-1.1.1.tgz",
- "integrity": "sha512-Fye8fh1+G7E8qqmjQaY+pXGxy7HM0S6bqCCJFLa16+g2jODBByxbJFDpjbDNF69wfRVyvJ+foLZc1WTIv7dx+g==",
- "dev": true,
- "dependencies": {
- "async-hook-domain": "^2.0.1",
- "bind-obj-methods": "^3.0.0",
- "diff": "^4.0.2",
- "function-loop": "^2.0.1",
- "minipass": "^3.1.1",
- "own-or": "^1.0.0",
- "own-or-env": "^1.0.1",
- "signal-exit": "^3.0.2",
- "stack-utils": "^2.0.1",
- "tap-parser": "^10.0.1",
- "tap-yaml": "^1.0.0",
- "tcompare": "^5.0.1",
- "trivial-deferred": "^1.0.1",
- "yapool": "^1.0.0"
- },
- "engines": {
- "node": ">=10"
- }
- },
- "node_modules/locate-path": {
- "version": "5.0.0",
- "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz",
- "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==",
- "dev": true,
- "dependencies": {
- "p-locate": "^4.1.0"
- },
- "engines": {
- "node": ">=8"
- }
- },
- "node_modules/lodash": {
- "version": "4.17.21",
- "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz",
- "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg=="
- },
- "node_modules/lodash.flattendeep": {
- "version": "4.4.0",
- "resolved": "https://registry.npmjs.org/lodash.flattendeep/-/lodash.flattendeep-4.4.0.tgz",
- "integrity": "sha1-+wMJF/hqMTTlvJvsDWngAT3f7bI=",
- "dev": true
- },
- "node_modules/log-driver": {
- "version": "1.2.7",
- "resolved": "https://registry.npmjs.org/log-driver/-/log-driver-1.2.7.tgz",
- "integrity": "sha512-U7KCmLdqsGHBLeWqYlFA0V0Sl6P08EE1ZrmA9cxjUE0WVqT9qnyVDPz1kzpFEP0jdJuFnasWIfSd7fsaNXkpbg==",
- "dev": true,
- "engines": {
- "node": ">=0.8.6"
- }
- },
- "node_modules/loose-envify": {
- "version": "1.4.0",
- "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz",
- "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==",
- "dev": true,
- "dependencies": {
- "js-tokens": "^3.0.0 || ^4.0.0"
- },
- "bin": {
- "loose-envify": "cli.js"
- }
- },
- "node_modules/lru-cache": {
- "version": "7.18.3",
- "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-7.18.3.tgz",
- "integrity": "sha512-jumlc0BIUrS3qJGgIkWZsyfAM7NCWiBcCDhnd+3NNM5KbBmLTgHVfWBcg6W+rLUsIpzpERPsvwUP7CckAQSOoA==",
- "engines": {
- "node": ">=12"
- }
- },
- "node_modules/make-dir": {
- "version": "3.1.0",
- "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz",
- "integrity": "sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==",
- "dev": true,
- "dependencies": {
- "semver": "^6.0.0"
- },
- "engines": {
- "node": ">=8"
- }
- },
- "node_modules/mathjs": {
- "version": "9.4.4",
- "resolved": "https://registry.npmjs.org/mathjs/-/mathjs-9.4.4.tgz",
- "integrity": "sha512-5EEJXnWOzLDgMHSFyw623nH+MTBZxquWwXtrzTsingOouJJ6UZG2VNO1lwH31IMt9aMno1axO6TYleIP4YSDaQ==",
- "dependencies": {
- "@babel/runtime": "^7.14.6",
- "complex.js": "^2.0.15",
- "decimal.js": "^10.3.1",
- "escape-latex": "^1.2.0",
- "fraction.js": "^4.1.1",
- "javascript-natural-sort": "^0.7.1",
- "seedrandom": "^3.0.5",
- "tiny-emitter": "^2.1.0",
- "typed-function": "^2.0.0"
- },
- "bin": {
- "mathjs": "bin/cli.js"
- },
- "engines": {
- "node": ">= 12"
- }
- },
- "node_modules/media-typer": {
- "version": "0.3.0",
- "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz",
- "integrity": "sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ==",
- "engines": {
- "node": ">= 0.6"
- }
- },
- "node_modules/merge-descriptors": {
- "version": "1.0.1",
- "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz",
- "integrity": "sha512-cCi6g3/Zr1iqQi6ySbseM1Xvooa98N0w31jzUYrXPX2xqObmFGHJ0tQ5u74H3mVh7wLouTseZyYIq39g8cNp1w=="
- },
- "node_modules/methods": {
- "version": "1.1.2",
- "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz",
- "integrity": "sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w==",
- "engines": {
- "node": ">= 0.6"
- }
- },
- "node_modules/mime": {
- "version": "1.6.0",
- "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz",
- "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==",
- "bin": {
- "mime": "cli.js"
- },
- "engines": {
- "node": ">=4"
- }
- },
- "node_modules/mime-db": {
- "version": "1.52.0",
- "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz",
- "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==",
- "engines": {
- "node": ">= 0.6"
- }
- },
- "node_modules/mime-types": {
- "version": "2.1.35",
- "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz",
- "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==",
- "dependencies": {
- "mime-db": "1.52.0"
- },
- "engines": {
- "node": ">= 0.6"
- }
- },
- "node_modules/minimatch": {
- "version": "3.0.4",
- "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz",
- "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==",
- "dev": true,
- "dependencies": {
- "brace-expansion": "^1.1.7"
- },
- "engines": {
- "node": "*"
- }
- },
- "node_modules/minimist": {
- "version": "1.2.6",
- "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.6.tgz",
- "integrity": "sha512-Jsjnk4bw3YJqYzbdyBiNsPWHPfO++UGG749Cxs6peCu5Xg4nrena6OVxOYxrQTqww0Jmwt+Ref8rggumkTLz9Q=="
- },
- "node_modules/minipass": {
- "version": "3.1.3",
- "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.1.3.tgz",
- "integrity": "sha512-Mgd2GdMVzY+x3IJ+oHnVM+KG3lA5c8tnabyJKmHSaG2kAGpudxuOf8ToDkhumF7UzME7DecbQE9uOZhNm7PuJg==",
- "dev": true,
- "dependencies": {
- "yallist": "^4.0.0"
- },
- "engines": {
- "node": ">=8"
- }
- },
- "node_modules/mkdirp": {
- "version": "2.1.6",
- "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-2.1.6.tgz",
- "integrity": "sha512-+hEnITedc8LAtIP9u3HJDFIdcLV2vXP33sqLLIzkv1Db1zO/1OxbvYf0Y1OC/S/Qo5dxHXepofhmxL02PsKe+A==",
- "bin": {
- "mkdirp": "dist/cjs/src/bin.js"
- },
- "engines": {
- "node": ">=10"
- },
- "funding": {
- "url": "https://github.com/sponsors/isaacs"
- }
- },
- "node_modules/ms": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
- "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A=="
- },
- "node_modules/negotiator": {
- "version": "0.6.3",
- "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz",
- "integrity": "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==",
- "engines": {
- "node": ">= 0.6"
- }
- },
- "node_modules/node-preload": {
- "version": "0.2.1",
- "resolved": "https://registry.npmjs.org/node-preload/-/node-preload-0.2.1.tgz",
- "integrity": "sha512-RM5oyBy45cLEoHqCeh+MNuFAxO0vTFBLskvQbOKnEE7YTTSN4tbN8QWDIPQ6L+WvKsB/qLEGpYe2ZZ9d4W9OIQ==",
- "dev": true,
- "dependencies": {
- "process-on-spawn": "^1.0.0"
- },
- "engines": {
- "node": ">=8"
- }
- },
- "node_modules/node-releases": {
- "version": "1.1.73",
- "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-1.1.73.tgz",
- "integrity": "sha512-uW7fodD6pyW2FZNZnp/Z3hvWKeEW1Y8R1+1CnErE8cXFXzl5blBOoVB41CvMer6P6Q0S5FXDwcHgFd1Wj0U9zg==",
- "dev": true
- },
- "node_modules/normalize-path": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz",
- "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==",
- "dev": true,
- "engines": {
- "node": ">=0.10.0"
- }
- },
- "node_modules/number-is-nan": {
- "version": "1.0.1",
- "resolved": "https://registry.npmjs.org/number-is-nan/-/number-is-nan-1.0.1.tgz",
- "integrity": "sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0=",
- "dev": true,
- "engines": {
- "node": ">=0.10.0"
- }
- },
- "node_modules/nyc": {
- "version": "15.1.0",
- "resolved": "https://registry.npmjs.org/nyc/-/nyc-15.1.0.tgz",
- "integrity": "sha512-jMW04n9SxKdKi1ZMGhvUTHBN0EICCRkHemEoE5jm6mTYcqcdas0ATzgUgejlQUHMvpnOZqGB5Xxsv9KxJW1j8A==",
- "dev": true,
- "dependencies": {
- "@istanbuljs/load-nyc-config": "^1.0.0",
- "@istanbuljs/schema": "^0.1.2",
- "caching-transform": "^4.0.0",
- "convert-source-map": "^1.7.0",
- "decamelize": "^1.2.0",
- "find-cache-dir": "^3.2.0",
- "find-up": "^4.1.0",
- "foreground-child": "^2.0.0",
- "get-package-type": "^0.1.0",
- "glob": "^7.1.6",
- "istanbul-lib-coverage": "^3.0.0",
- "istanbul-lib-hook": "^3.0.0",
- "istanbul-lib-instrument": "^4.0.0",
- "istanbul-lib-processinfo": "^2.0.2",
- "istanbul-lib-report": "^3.0.0",
- "istanbul-lib-source-maps": "^4.0.0",
- "istanbul-reports": "^3.0.2",
- "make-dir": "^3.0.0",
- "node-preload": "^0.2.1",
- "p-map": "^3.0.0",
- "process-on-spawn": "^1.0.0",
- "resolve-from": "^5.0.0",
- "rimraf": "^3.0.0",
- "signal-exit": "^3.0.2",
- "spawn-wrap": "^2.0.0",
- "test-exclude": "^6.0.0",
- "yargs": "^15.0.2"
- },
- "bin": {
- "nyc": "bin/nyc.js"
- },
- "engines": {
- "node": ">=8.9"
- }
- },
- "node_modules/oauth-sign": {
- "version": "0.9.0",
- "resolved": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.9.0.tgz",
- "integrity": "sha512-fexhUFFPTGV8ybAtSIGbV6gOkSv8UtRbDBnAyLQw4QPKkgNlsH2ByPGtMUqdWkos6YCRmAqViwgZrJc/mRDzZQ==",
- "dev": true,
- "engines": {
- "node": "*"
- }
- },
- "node_modules/object-assign": {
- "version": "4.1.1",
- "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz",
- "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=",
- "dev": true,
- "engines": {
- "node": ">=0.10.0"
- }
- },
- "node_modules/object-inspect": {
- "version": "1.12.3",
- "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.12.3.tgz",
- "integrity": "sha512-geUvdk7c+eizMNUDkRpW1wJwgfOiOeHbxBR/hLXK1aT6zmVSO0jsQcs7fj6MGw89jC/cjGfLcNOrtMYtGqm81g==",
- "funding": {
- "url": "https://github.com/sponsors/ljharb"
- }
- },
- "node_modules/on-finished": {
- "version": "2.4.1",
- "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz",
- "integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==",
- "dependencies": {
- "ee-first": "1.1.1"
- },
- "engines": {
- "node": ">= 0.8"
- }
- },
- "node_modules/once": {
- "version": "1.4.0",
- "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz",
- "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=",
- "dependencies": {
- "wrappy": "1"
- }
- },
- "node_modules/opener": {
- "version": "1.5.2",
- "resolved": "https://registry.npmjs.org/opener/-/opener-1.5.2.tgz",
- "integrity": "sha512-ur5UIdyw5Y7yEj9wLzhqXiy6GZ3Mwx0yGI+5sMn2r0N0v3cKJvUmFH5yPP+WXh9e0xfyzyJX95D8l088DNFj7A==",
- "dev": true,
- "bin": {
- "opener": "bin/opener-bin.js"
- }
- },
- "node_modules/own-or": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/own-or/-/own-or-1.0.0.tgz",
- "integrity": "sha1-Tod/vtqaLsgAD7wLyuOWRe6L+Nw=",
- "dev": true
- },
- "node_modules/own-or-env": {
- "version": "1.0.1",
- "resolved": "https://registry.npmjs.org/own-or-env/-/own-or-env-1.0.1.tgz",
- "integrity": "sha512-y8qULRbRAlL6x2+M0vIe7jJbJx/kmUTzYonRAa2ayesR2qWLswninkVyeJe4x3IEXhdgoNodzjQRKAoEs6Fmrw==",
- "dev": true,
- "dependencies": {
- "own-or": "^1.0.0"
- }
- },
- "node_modules/p-limit": {
- "version": "2.3.0",
- "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz",
- "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==",
- "dev": true,
- "dependencies": {
- "p-try": "^2.0.0"
- },
- "engines": {
- "node": ">=6"
- }
- },
- "node_modules/p-locate": {
- "version": "4.1.0",
- "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz",
- "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==",
- "dev": true,
- "dependencies": {
- "p-limit": "^2.2.0"
- },
- "engines": {
- "node": ">=8"
- }
- },
- "node_modules/p-map": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/p-map/-/p-map-3.0.0.tgz",
- "integrity": "sha512-d3qXVTF/s+W+CdJ5A29wywV2n8CQQYahlgz2bFiA+4eVNJbHJodPZ+/gXwPGh0bOqA+j8S+6+ckmvLGPk1QpxQ==",
- "dev": true,
- "dependencies": {
- "aggregate-error": "^3.0.0"
- },
- "engines": {
- "node": ">=8"
- }
- },
- "node_modules/p-try": {
- "version": "2.2.0",
- "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz",
- "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==",
- "dev": true,
- "engines": {
- "node": ">=6"
- }
- },
- "node_modules/package-hash": {
- "version": "4.0.0",
- "resolved": "https://registry.npmjs.org/package-hash/-/package-hash-4.0.0.tgz",
- "integrity": "sha512-whdkPIooSu/bASggZ96BWVvZTRMOFxnyUG5PnTSGKoJE2gd5mbVNmR2Nj20QFzxYYgAXpoqC+AiXzl+UMRh7zQ==",
- "dev": true,
- "dependencies": {
- "graceful-fs": "^4.1.15",
- "hasha": "^5.0.0",
- "lodash.flattendeep": "^4.4.0",
- "release-zalgo": "^1.0.0"
- },
- "engines": {
- "node": ">=8"
- }
- },
- "node_modules/parseurl": {
- "version": "1.3.3",
- "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz",
- "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==",
- "engines": {
- "node": ">= 0.8"
- }
- },
- "node_modules/path-exists": {
- "version": "4.0.0",
- "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz",
- "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==",
- "dev": true,
- "engines": {
- "node": ">=8"
- }
- },
- "node_modules/path-is-absolute": {
- "version": "1.0.1",
- "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz",
- "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=",
- "dev": true,
- "engines": {
- "node": ">=0.10.0"
- }
- },
- "node_modules/path-key": {
- "version": "3.1.1",
- "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz",
- "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==",
- "dev": true,
- "engines": {
- "node": ">=8"
- }
- },
- "node_modules/path-scurry": {
- "version": "1.6.3",
- "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-1.6.3.tgz",
- "integrity": "sha512-RAmB+n30SlN+HnNx6EbcpoDy9nwdpcGPnEKrJnu6GZoDWBdIjo1UQMVtW2ybtC7LC2oKLcMq8y5g8WnKLiod9g==",
- "dependencies": {
- "lru-cache": "^7.14.1",
- "minipass": "^4.0.2"
- },
- "engines": {
- "node": ">=16 || 14 >=14.17"
- },
- "funding": {
- "url": "https://github.com/sponsors/isaacs"
- }
- },
- "node_modules/path-scurry/node_modules/minipass": {
- "version": "4.2.5",
- "resolved": "https://registry.npmjs.org/minipass/-/minipass-4.2.5.tgz",
- "integrity": "sha512-+yQl7SX3bIT83Lhb4BVorMAHVuqsskxRdlmO9kTpyukp8vsm2Sn/fUOV9xlnG8/a5JsypJzap21lz/y3FBMJ8Q==",
- "engines": {
- "node": ">=8"
- }
- },
- "node_modules/path-to-regexp": {
- "version": "0.1.7",
- "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz",
- "integrity": "sha512-5DFkuoqlv1uYQKxy8omFBeJPQcdoE07Kv2sferDCrAq1ohOU+MSDswDIbnx3YAM60qIOnYa53wBhXW0EbMonrQ=="
- },
- "node_modules/performance-now": {
- "version": "2.1.0",
- "resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz",
- "integrity": "sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns=",
- "dev": true
- },
- "node_modules/picomatch": {
- "version": "2.3.0",
- "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.0.tgz",
- "integrity": "sha512-lY1Q/PiJGC2zOv/z391WOTD+Z02bCgsFfvxoXXf6h7kv9o+WmsmzYqrAwY63sNgOxE4xEdq0WyUnXfKeBrSvYw==",
- "dev": true,
- "engines": {
- "node": ">=8.6"
- }
- },
- "node_modules/pkg-dir": {
- "version": "4.2.0",
- "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-4.2.0.tgz",
- "integrity": "sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==",
- "dev": true,
- "dependencies": {
- "find-up": "^4.0.0"
- },
- "engines": {
- "node": ">=8"
- }
- },
- "node_modules/prettier": {
- "version": "2.8.7",
- "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.8.7.tgz",
- "integrity": "sha512-yPngTo3aXUUmyuTjeTUT75txrf+aMh9FiD7q9ZE/i6r0bPb22g4FsE6Y338PQX1bmfy08i9QQCB7/rcUAVntfw==",
- "bin": {
- "prettier": "bin-prettier.js"
- },
- "engines": {
- "node": ">=10.13.0"
- },
- "funding": {
- "url": "https://github.com/prettier/prettier?sponsor=1"
- }
- },
- "node_modules/process-on-spawn": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/process-on-spawn/-/process-on-spawn-1.0.0.tgz",
- "integrity": "sha512-1WsPDsUSMmZH5LeMLegqkPDrsGgsWwk1Exipy2hvB0o/F0ASzbpIctSCcZIK1ykJvtTJULEH+20WOFjMvGnCTg==",
- "dev": true,
- "dependencies": {
- "fromentries": "^1.2.0"
- },
- "engines": {
- "node": ">=8"
- }
- },
- "node_modules/prop-types": {
- "version": "15.7.2",
- "resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.7.2.tgz",
- "integrity": "sha512-8QQikdH7//R2vurIJSutZ1smHYTcLpRWEOlHnzcWHmBYrOGUysKwSsrC89BCiFj3CbrfJ/nXFdJepOVrY1GCHQ==",
- "dev": true,
- "dependencies": {
- "loose-envify": "^1.4.0",
- "object-assign": "^4.1.1",
- "react-is": "^16.8.1"
- }
- },
- "node_modules/proxy-addr": {
- "version": "2.0.7",
- "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz",
- "integrity": "sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==",
- "dependencies": {
- "forwarded": "0.2.0",
- "ipaddr.js": "1.9.1"
- },
- "engines": {
- "node": ">= 0.10"
- }
- },
- "node_modules/psl": {
- "version": "1.8.0",
- "resolved": "https://registry.npmjs.org/psl/-/psl-1.8.0.tgz",
- "integrity": "sha512-RIdOzyoavK+hA18OGGWDqUTsCLhtA7IcZ/6NCs4fFJaHBDab+pDDmDIByWFRQJq2Cd7r1OoQxBGKOaztq+hjIQ==",
- "dev": true
- },
- "node_modules/punycode": {
- "version": "2.1.1",
- "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz",
- "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==",
- "dev": true,
- "engines": {
- "node": ">=6"
- }
- },
- "node_modules/qs": {
- "version": "6.11.0",
- "resolved": "https://registry.npmjs.org/qs/-/qs-6.11.0.tgz",
- "integrity": "sha512-MvjoMCJwEarSbUYk5O+nmoSzSutSsTwF85zcHPQ9OrlFoZOYIjaqBAJIqIXjptyD5vThxGq52Xu/MaJzRkIk4Q==",
- "dependencies": {
- "side-channel": "^1.0.4"
- },
- "engines": {
- "node": ">=0.6"
- },
- "funding": {
- "url": "https://github.com/sponsors/ljharb"
- }
- },
- "node_modules/range-parser": {
- "version": "1.2.1",
- "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz",
- "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==",
- "engines": {
- "node": ">= 0.6"
- }
- },
- "node_modules/raw-body": {
- "version": "2.5.1",
- "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.1.tgz",
- "integrity": "sha512-qqJBtEyVgS0ZmPGdCFPWJ3FreoqvG4MVQln/kCgF7Olq95IbOp0/BWyMwbdtn4VTvkM8Y7khCQ2Xgk/tcrCXig==",
- "dependencies": {
- "bytes": "3.1.2",
- "http-errors": "2.0.0",
- "iconv-lite": "0.4.24",
- "unpipe": "1.0.0"
- },
- "engines": {
- "node": ">= 0.8"
- }
- },
- "node_modules/react": {
- "version": "16.14.0",
- "resolved": "https://registry.npmjs.org/react/-/react-16.14.0.tgz",
- "integrity": "sha512-0X2CImDkJGApiAlcf0ODKIneSwBPhqJawOa5wCtKbu7ZECrmS26NvtSILynQ66cgkT/RJ4LidJOc3bUESwmU8g==",
- "dev": true,
- "dependencies": {
- "loose-envify": "^1.1.0",
- "object-assign": "^4.1.1",
- "prop-types": "^15.6.2"
- },
- "engines": {
- "node": ">=0.10.0"
- }
- },
- "node_modules/react-is": {
- "version": "16.13.1",
- "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz",
- "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==",
- "dev": true
- },
- "node_modules/readdirp": {
- "version": "3.6.0",
- "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz",
- "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==",
- "dev": true,
- "dependencies": {
- "picomatch": "^2.2.1"
- },
- "engines": {
- "node": ">=8.10.0"
- }
- },
- "node_modules/recursive-readdir-sync": {
- "version": "1.0.6",
- "resolved": "https://registry.npmjs.org/recursive-readdir-sync/-/recursive-readdir-sync-1.0.6.tgz",
- "integrity": "sha1-Hb9tMvPFu4083pemxYjVR6nhPVY="
- },
- "node_modules/regenerator-runtime": {
- "version": "0.13.9",
- "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.9.tgz",
- "integrity": "sha512-p3VT+cOEgxFsRRA9X4lkI1E+k2/CtnKtU4gcxyaCUreilL/vqI6CdZ3wxVUx3UOUg+gnUOQQcRI7BmSI656MYA=="
- },
- "node_modules/release-zalgo": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/release-zalgo/-/release-zalgo-1.0.0.tgz",
- "integrity": "sha1-CXALflB0Mpc5Mw5TXFqQ+2eFFzA=",
- "dev": true,
- "dependencies": {
- "es6-error": "^4.0.1"
- },
- "engines": {
- "node": ">=4"
- }
- },
- "node_modules/request": {
- "version": "2.88.2",
- "resolved": "https://registry.npmjs.org/request/-/request-2.88.2.tgz",
- "integrity": "sha512-MsvtOrfG9ZcrOwAW+Qi+F6HbD0CWXEh9ou77uOb7FM2WPhwT7smM833PzanhJLsgXjN89Ir6V2PczXNnMpwKhw==",
- "dev": true,
- "dependencies": {
- "aws-sign2": "~0.7.0",
- "aws4": "^1.8.0",
- "caseless": "~0.12.0",
- "combined-stream": "~1.0.6",
- "extend": "~3.0.2",
- "forever-agent": "~0.6.1",
- "form-data": "~2.3.2",
- "har-validator": "~5.1.3",
- "http-signature": "~1.2.0",
- "is-typedarray": "~1.0.0",
- "isstream": "~0.1.2",
- "json-stringify-safe": "~5.0.1",
- "mime-types": "~2.1.19",
- "oauth-sign": "~0.9.0",
- "performance-now": "^2.1.0",
- "qs": "~6.5.2",
- "safe-buffer": "^5.1.2",
- "tough-cookie": "~2.5.0",
- "tunnel-agent": "^0.6.0",
- "uuid": "^3.3.2"
- },
- "engines": {
- "node": ">= 6"
- }
- },
- "node_modules/request/node_modules/form-data": {
- "version": "2.3.3",
- "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.3.3.tgz",
- "integrity": "sha512-1lLKB2Mu3aGP1Q/2eCOx0fNbRMe7XdwktwOruhfqqd0rIJWwN4Dh+E3hrPSlDCXnSR7UtZ1N38rVXm+6+MEhJQ==",
- "dev": true,
- "dependencies": {
- "asynckit": "^0.4.0",
- "combined-stream": "^1.0.6",
- "mime-types": "^2.1.12"
- },
- "engines": {
- "node": ">= 0.12"
- }
- },
- "node_modules/request/node_modules/qs": {
- "version": "6.5.2",
- "resolved": "https://registry.npmjs.org/qs/-/qs-6.5.2.tgz",
- "integrity": "sha512-N5ZAX4/LxJmF+7wN74pUD6qAh9/wnvdQcjq9TZjevvXzSUo7bfmw91saqMjzGS2xq91/odN2dW/WOl7qQHNDGA==",
- "dev": true,
- "engines": {
- "node": ">=0.6"
- }
- },
- "node_modules/require-directory": {
- "version": "2.1.1",
- "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz",
- "integrity": "sha1-jGStX9MNqxyXbiNE/+f3kqam30I=",
- "dev": true,
- "engines": {
- "node": ">=0.10.0"
- }
- },
- "node_modules/require-main-filename": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-2.0.0.tgz",
- "integrity": "sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg==",
- "dev": true
- },
- "node_modules/resolve-from": {
- "version": "5.0.0",
- "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz",
- "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==",
- "dev": true,
- "engines": {
- "node": ">=8"
- }
- },
- "node_modules/rimraf": {
- "version": "3.0.2",
- "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz",
- "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==",
- "dev": true,
- "dependencies": {
- "glob": "^7.1.3"
- },
- "bin": {
- "rimraf": "bin.js"
- }
- },
- "node_modules/safe-buffer": {
- "version": "5.1.2",
- "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz",
- "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==",
- "dev": true
- },
- "node_modules/safer-buffer": {
- "version": "2.1.2",
- "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz",
- "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg=="
- },
- "node_modules/seedrandom": {
- "version": "3.0.5",
- "resolved": "https://registry.npmjs.org/seedrandom/-/seedrandom-3.0.5.tgz",
- "integrity": "sha512-8OwmbklUNzwezjGInmZ+2clQmExQPvomqjL7LFqOYqtmuxRgQYqOD3mHaU+MvZn5FLUeVxVfQjwLZW/n/JFuqg=="
- },
- "node_modules/semver": {
- "version": "6.3.0",
- "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz",
- "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==",
- "dev": true,
- "bin": {
- "semver": "bin/semver.js"
- }
- },
- "node_modules/send": {
- "version": "0.18.0",
- "resolved": "https://registry.npmjs.org/send/-/send-0.18.0.tgz",
- "integrity": "sha512-qqWzuOjSFOuqPjFe4NOsMLafToQQwBSOEpS+FwEt3A2V3vKubTquT3vmLTQpFgMXp8AlFWFuP1qKaJZOtPpVXg==",
- "dependencies": {
- "debug": "2.6.9",
- "depd": "2.0.0",
- "destroy": "1.2.0",
- "encodeurl": "~1.0.2",
- "escape-html": "~1.0.3",
- "etag": "~1.8.1",
- "fresh": "0.5.2",
- "http-errors": "2.0.0",
- "mime": "1.6.0",
- "ms": "2.1.3",
- "on-finished": "2.4.1",
- "range-parser": "~1.2.1",
- "statuses": "2.0.1"
- },
- "engines": {
- "node": ">= 0.8.0"
- }
- },
- "node_modules/send/node_modules/ms": {
- "version": "2.1.3",
- "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
- "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA=="
- },
- "node_modules/serve-static": {
- "version": "1.15.0",
- "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.15.0.tgz",
- "integrity": "sha512-XGuRDNjXUijsUL0vl6nSD7cwURuzEgglbOaFuZM9g3kwDXOWVTck0jLzjPzGD+TazWbboZYu52/9/XPdUgne9g==",
- "dependencies": {
- "encodeurl": "~1.0.2",
- "escape-html": "~1.0.3",
- "parseurl": "~1.3.3",
- "send": "0.18.0"
- },
- "engines": {
- "node": ">= 0.8.0"
- }
- },
- "node_modules/set-blocking": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz",
- "integrity": "sha1-BF+XgtARrppoA93TgrJDkrPYkPc=",
- "dev": true
- },
- "node_modules/setprototypeof": {
- "version": "1.2.0",
- "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz",
- "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw=="
- },
- "node_modules/shebang-command": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz",
- "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==",
- "dev": true,
- "dependencies": {
- "shebang-regex": "^3.0.0"
- },
- "engines": {
- "node": ">=8"
- }
- },
- "node_modules/shebang-regex": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz",
- "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==",
- "dev": true,
- "engines": {
- "node": ">=8"
- }
- },
- "node_modules/side-channel": {
- "version": "1.0.4",
- "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.4.tgz",
- "integrity": "sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==",
- "dependencies": {
- "call-bind": "^1.0.0",
- "get-intrinsic": "^1.0.2",
- "object-inspect": "^1.9.0"
- },
- "funding": {
- "url": "https://github.com/sponsors/ljharb"
- }
- },
- "node_modules/signal-exit": {
- "version": "3.0.3",
- "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.3.tgz",
- "integrity": "sha512-VUJ49FC8U1OxwZLxIbTTrDvLnf/6TDgxZcK8wxR8zs13xpx7xbG60ndBlhNrFi2EMuFRoeDoJO7wthSLq42EjA==",
- "dev": true
- },
- "node_modules/source-map": {
- "version": "0.5.7",
- "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz",
- "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=",
- "dev": true,
- "engines": {
- "node": ">=0.10.0"
- }
- },
- "node_modules/source-map-support": {
- "version": "0.5.19",
- "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.19.tgz",
- "integrity": "sha512-Wonm7zOCIJzBGQdB+thsPar0kYuCIzYvxZwlBa87yi/Mdjv7Tip2cyVbLj5o0cFPN4EVkuTwb3GDDyUx2DGnGw==",
- "dev": true,
- "dependencies": {
- "buffer-from": "^1.0.0",
- "source-map": "^0.6.0"
- }
- },
- "node_modules/source-map-support/node_modules/source-map": {
- "version": "0.6.1",
- "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
- "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==",
- "dev": true,
- "engines": {
- "node": ">=0.10.0"
- }
- },
- "node_modules/spawn-wrap": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/spawn-wrap/-/spawn-wrap-2.0.0.tgz",
- "integrity": "sha512-EeajNjfN9zMnULLwhZZQU3GWBoFNkbngTUPfaawT4RkMiviTxcX0qfhVbGey39mfctfDHkWtuecgQ8NJcyQWHg==",
- "dev": true,
- "dependencies": {
- "foreground-child": "^2.0.0",
- "is-windows": "^1.0.2",
- "make-dir": "^3.0.0",
- "rimraf": "^3.0.0",
- "signal-exit": "^3.0.2",
- "which": "^2.0.1"
- },
- "engines": {
- "node": ">=8"
- }
- },
- "node_modules/sprintf-js": {
- "version": "1.0.3",
- "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz",
- "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=",
- "dev": true
- },
- "node_modules/sshpk": {
- "version": "1.16.1",
- "resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.16.1.tgz",
- "integrity": "sha512-HXXqVUq7+pcKeLqqZj6mHFUMvXtOJt1uoUx09pFW6011inTMxqI8BA8PM95myrIyyKwdnzjdFjLiE6KBPVtJIg==",
- "dev": true,
- "dependencies": {
- "asn1": "~0.2.3",
- "assert-plus": "^1.0.0",
- "bcrypt-pbkdf": "^1.0.0",
- "dashdash": "^1.12.0",
- "ecc-jsbn": "~0.1.1",
- "getpass": "^0.1.1",
- "jsbn": "~0.1.0",
- "safer-buffer": "^2.0.2",
- "tweetnacl": "~0.14.0"
- },
- "engines": {
- "node": ">=0.10.0"
- }
- },
- "node_modules/stack-utils": {
- "version": "2.0.3",
- "resolved": "https://registry.npmjs.org/stack-utils/-/stack-utils-2.0.3.tgz",
- "integrity": "sha512-gL//fkxfWUsIlFL2Tl42Cl6+HFALEaB1FU76I/Fy+oZjRreP7OPMXFlGbxM7NQsI0ZpUfw76sHnv0WNYuTb7Iw==",
- "dev": true,
- "dependencies": {
- "escape-string-regexp": "^2.0.0"
- },
- "engines": {
- "node": ">=10"
- }
- },
- "node_modules/statuses": {
- "version": "2.0.1",
- "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz",
- "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==",
- "engines": {
- "node": ">= 0.8"
- }
- },
- "node_modules/string-width": {
- "version": "2.1.1",
- "resolved": "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz",
- "integrity": "sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==",
- "dev": true,
- "dependencies": {
- "is-fullwidth-code-point": "^2.0.0",
- "strip-ansi": "^4.0.0"
- },
- "engines": {
- "node": ">=4"
- }
- },
- "node_modules/strip-ansi": {
- "version": "4.0.0",
- "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz",
- "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=",
- "dev": true,
- "dependencies": {
- "ansi-regex": "^3.0.0"
- },
- "engines": {
- "node": ">=4"
- }
- },
- "node_modules/strip-bom": {
- "version": "4.0.0",
- "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-4.0.0.tgz",
- "integrity": "sha512-3xurFv5tEgii33Zi8Jtp55wEIILR9eh34FAW00PZf+JnSsTmV/ioewSgQl97JHvgjoRGwPShsWm+IdrxB35d0w==",
- "dev": true,
- "engines": {
- "node": ">=8"
- }
- },
- "node_modules/superagent": {
- "version": "8.0.9",
- "resolved": "https://registry.npmjs.org/superagent/-/superagent-8.0.9.tgz",
- "integrity": "sha512-4C7Bh5pyHTvU33KpZgwrNKh/VQnvgtCSqPRfJAUdmrtSYePVzVg4E4OzsrbkhJj9O7SO6Bnv75K/F8XVZT8YHA==",
- "dependencies": {
- "component-emitter": "^1.3.0",
- "cookiejar": "^2.1.4",
- "debug": "^4.3.4",
- "fast-safe-stringify": "^2.1.1",
- "form-data": "^4.0.0",
- "formidable": "^2.1.2",
- "methods": "^1.1.2",
- "mime": "2.6.0",
- "qs": "^6.11.0",
- "semver": "^7.3.8"
- },
- "engines": {
- "node": ">=6.4.0 <13 || >=14"
- }
- },
- "node_modules/superagent/node_modules/debug": {
- "version": "4.3.4",
- "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz",
- "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==",
- "dependencies": {
- "ms": "2.1.2"
- },
- "engines": {
- "node": ">=6.0"
- },
- "peerDependenciesMeta": {
- "supports-color": {
- "optional": true
- }
- }
- },
- "node_modules/superagent/node_modules/lru-cache": {
- "version": "6.0.0",
- "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz",
- "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==",
- "dependencies": {
- "yallist": "^4.0.0"
- },
- "engines": {
- "node": ">=10"
- }
- },
- "node_modules/superagent/node_modules/mime": {
- "version": "2.6.0",
- "resolved": "https://registry.npmjs.org/mime/-/mime-2.6.0.tgz",
- "integrity": "sha512-USPkMeET31rOMiarsBNIHZKLGgvKc/LrjofAnBlOttf5ajRvqiRA8QsenbcooctK6d6Ts6aqZXBA+XbkKthiQg==",
- "bin": {
- "mime": "cli.js"
- },
- "engines": {
- "node": ">=4.0.0"
- }
- },
- "node_modules/superagent/node_modules/ms": {
- "version": "2.1.2",
- "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
- "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w=="
- },
- "node_modules/superagent/node_modules/semver": {
- "version": "7.3.8",
- "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.8.tgz",
- "integrity": "sha512-NB1ctGL5rlHrPJtFDVIVzTyQylMLu9N9VICA6HSFJo8MCGVTMW6gfpicwKmmK/dAjTOrqu5l63JJOpDSrAis3A==",
- "dependencies": {
- "lru-cache": "^6.0.0"
- },
- "bin": {
- "semver": "bin/semver.js"
- },
- "engines": {
- "node": ">=10"
- }
- },
- "node_modules/supports-color": {
- "version": "5.5.0",
- "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz",
- "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==",
- "dev": true,
- "dependencies": {
- "has-flag": "^3.0.0"
- },
- "engines": {
- "node": ">=4"
- }
- },
- "node_modules/tap": {
- "version": "15.0.9",
- "resolved": "https://registry.npmjs.org/tap/-/tap-15.0.9.tgz",
- "integrity": "sha512-bqY5SxEqYKRd37PIUfKBf9HMs/hklyl/fGXkuStr9rYTIGa0/icpSLsm6IVOmx2qT0/TliPNJ6OvS5kddJYHdg==",
- "bundleDependencies": [
- "@types/react",
- "glob",
- "import-jsx",
- "ink",
- "minipass",
- "rimraf",
- "signal-exit",
- "tap-parser",
- "tap-yaml",
- "treport"
- ],
- "dev": true,
- "dependencies": {
- "@types/react": "^16.9.23",
- "chokidar": "^3.3.0",
- "coveralls": "^3.0.11",
- "findit": "^2.0.0",
- "foreground-child": "^2.0.0",
- "fs-exists-cached": "^1.0.0",
- "glob": "^7.1.6",
- "import-jsx": "^4.0.0",
- "ink": "^2.7.1",
- "isexe": "^2.0.0",
- "istanbul-lib-processinfo": "^2.0.2",
- "jackspeak": "^1.4.0",
- "libtap": "^1.1.1",
- "minipass": "^3.1.1",
- "mkdirp": "^1.0.4",
- "nyc": "^15.1.0",
- "opener": "^1.5.1",
- "react": "^16.12.0",
- "rimraf": "^3.0.0",
- "signal-exit": "^3.0.0",
- "source-map-support": "^0.5.16",
- "tap-mocha-reporter": "^5.0.0",
- "tap-parser": "^10.0.1",
- "tap-yaml": "^1.0.0",
- "tcompare": "^5.0.6",
- "treport": "^2.0.2",
- "which": "^2.0.2"
- },
- "bin": {
- "tap": "bin/run.js"
- },
- "engines": {
- "node": ">=10"
- }
- },
- "node_modules/tap-mocha-reporter": {
- "version": "5.0.1",
- "resolved": "https://registry.npmjs.org/tap-mocha-reporter/-/tap-mocha-reporter-5.0.1.tgz",
- "integrity": "sha512-1knFWOwd4khx/7uSEnUeaP9IPW3w+sqTgJMhrwah6t46nZ8P25atOKAjSvVDsT67lOPu0nfdOqUwoyKn+3E5pA==",
- "dev": true,
- "dependencies": {
- "color-support": "^1.1.0",
- "debug": "^4.1.1",
- "diff": "^4.0.1",
- "escape-string-regexp": "^2.0.0",
- "glob": "^7.0.5",
- "tap-parser": "^10.0.0",
- "tap-yaml": "^1.0.0",
- "unicode-length": "^2.0.2"
- },
- "bin": {
- "tap-mocha-reporter": "index.js"
- },
- "engines": {
- "node": ">= 8"
- }
- },
- "node_modules/tap-mocha-reporter/node_modules/debug": {
- "version": "4.3.2",
- "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.2.tgz",
- "integrity": "sha512-mOp8wKcvj7XxC78zLgw/ZA+6TSgkoE2C/ienthhRD298T7UNwAg9diBpLRxC0mOezLl4B0xV7M0cCO6P/O0Xhw==",
- "dev": true,
- "dependencies": {
- "ms": "2.1.2"
- },
- "engines": {
- "node": ">=6.0"
- }
- },
- "node_modules/tap-mocha-reporter/node_modules/ms": {
- "version": "2.1.2",
- "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
- "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==",
- "dev": true
- },
- "node_modules/tap-parser": {
- "version": "10.1.0",
- "resolved": "https://registry.npmjs.org/tap-parser/-/tap-parser-10.1.0.tgz",
- "integrity": "sha512-FujQeciDaOiOvaIVGS1Rpb0v4R6XkOjvWCWowlz5oKuhPkEJ8U6pxgqt38xuzYhPt8dWEnfHn2jqpZdJEkW7pA==",
- "dev": true,
- "dependencies": {
- "events-to-array": "^1.0.1",
- "minipass": "^3.0.0",
- "tap-yaml": "^1.0.0"
- },
- "bin": {
- "tap-parser": "bin/cmd.js"
- },
- "engines": {
- "node": ">= 8"
- }
- },
- "node_modules/tap-yaml": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/tap-yaml/-/tap-yaml-1.0.0.tgz",
- "integrity": "sha512-Rxbx4EnrWkYk0/ztcm5u3/VznbyFJpyXO12dDBHKWiDVxy7O2Qw6MRrwO5H6Ww0U5YhRY/4C/VzWmFPhBQc4qQ==",
- "dev": true,
- "dependencies": {
- "yaml": "^1.5.0"
- }
- },
- "node_modules/tap/node_modules/@babel/code-frame": {
- "version": "7.12.13",
- "dev": true,
- "inBundle": true,
- "license": "MIT",
- "dependencies": {
- "@babel/highlight": "^7.12.13"
- }
- },
- "node_modules/tap/node_modules/@babel/compat-data": {
- "version": "7.14.0",
- "dev": true,
- "inBundle": true,
- "license": "MIT"
- },
- "node_modules/tap/node_modules/@babel/core": {
- "version": "7.14.0",
- "dev": true,
- "inBundle": true,
- "license": "MIT",
- "dependencies": {
- "@babel/code-frame": "^7.12.13",
- "@babel/generator": "^7.14.0",
- "@babel/helper-compilation-targets": "^7.13.16",
- "@babel/helper-module-transforms": "^7.14.0",
- "@babel/helpers": "^7.14.0",
- "@babel/parser": "^7.14.0",
- "@babel/template": "^7.12.13",
- "@babel/traverse": "^7.14.0",
- "@babel/types": "^7.14.0",
- "convert-source-map": "^1.7.0",
- "debug": "^4.1.0",
- "gensync": "^1.0.0-beta.2",
- "json5": "^2.1.2",
- "semver": "^6.3.0",
- "source-map": "^0.5.0"
- },
- "engines": {
- "node": ">=6.9.0"
- },
- "funding": {
- "type": "opencollective",
- "url": "https://opencollective.com/babel"
- }
- },
- "node_modules/tap/node_modules/@babel/generator": {
- "version": "7.14.1",
- "dev": true,
- "inBundle": true,
- "license": "MIT",
- "dependencies": {
- "@babel/types": "^7.14.1",
- "jsesc": "^2.5.1",
- "source-map": "^0.5.0"
- }
- },
- "node_modules/tap/node_modules/@babel/helper-annotate-as-pure": {
- "version": "7.12.13",
- "dev": true,
- "inBundle": true,
- "license": "MIT",
- "dependencies": {
- "@babel/types": "^7.12.13"
- }
- },
- "node_modules/tap/node_modules/@babel/helper-compilation-targets": {
- "version": "7.13.16",
- "dev": true,
- "inBundle": true,
- "license": "MIT",
- "dependencies": {
- "@babel/compat-data": "^7.13.15",
- "@babel/helper-validator-option": "^7.12.17",
- "browserslist": "^4.14.5",
- "semver": "^6.3.0"
- },
- "peerDependencies": {
- "@babel/core": "^7.0.0"
- }
- },
- "node_modules/tap/node_modules/@babel/helper-function-name": {
- "version": "7.12.13",
- "dev": true,
- "inBundle": true,
- "license": "MIT",
- "dependencies": {
- "@babel/helper-get-function-arity": "^7.12.13",
- "@babel/template": "^7.12.13",
- "@babel/types": "^7.12.13"
- }
- },
- "node_modules/tap/node_modules/@babel/helper-get-function-arity": {
- "version": "7.12.13",
- "dev": true,
- "inBundle": true,
- "license": "MIT",
- "dependencies": {
- "@babel/types": "^7.12.13"
- }
- },
- "node_modules/tap/node_modules/@babel/helper-member-expression-to-functions": {
- "version": "7.13.12",
- "dev": true,
- "inBundle": true,
- "license": "MIT",
- "dependencies": {
- "@babel/types": "^7.13.12"
- }
- },
- "node_modules/tap/node_modules/@babel/helper-module-imports": {
- "version": "7.13.12",
- "dev": true,
- "inBundle": true,
- "license": "MIT",
- "dependencies": {
- "@babel/types": "^7.13.12"
- }
- },
- "node_modules/tap/node_modules/@babel/helper-module-transforms": {
- "version": "7.14.0",
- "dev": true,
- "inBundle": true,
- "license": "MIT",
- "dependencies": {
- "@babel/helper-module-imports": "^7.13.12",
- "@babel/helper-replace-supers": "^7.13.12",
- "@babel/helper-simple-access": "^7.13.12",
- "@babel/helper-split-export-declaration": "^7.12.13",
- "@babel/helper-validator-identifier": "^7.14.0",
- "@babel/template": "^7.12.13",
- "@babel/traverse": "^7.14.0",
- "@babel/types": "^7.14.0"
- }
- },
- "node_modules/tap/node_modules/@babel/helper-optimise-call-expression": {
- "version": "7.12.13",
- "dev": true,
- "inBundle": true,
- "license": "MIT",
- "dependencies": {
- "@babel/types": "^7.12.13"
- }
- },
- "node_modules/tap/node_modules/@babel/helper-plugin-utils": {
- "version": "7.13.0",
- "dev": true,
- "inBundle": true,
- "license": "MIT"
- },
- "node_modules/tap/node_modules/@babel/helper-replace-supers": {
- "version": "7.13.12",
- "dev": true,
- "inBundle": true,
- "license": "MIT",
- "dependencies": {
- "@babel/helper-member-expression-to-functions": "^7.13.12",
- "@babel/helper-optimise-call-expression": "^7.12.13",
- "@babel/traverse": "^7.13.0",
- "@babel/types": "^7.13.12"
- }
- },
- "node_modules/tap/node_modules/@babel/helper-simple-access": {
- "version": "7.13.12",
- "dev": true,
- "inBundle": true,
- "license": "MIT",
- "dependencies": {
- "@babel/types": "^7.13.12"
- }
- },
- "node_modules/tap/node_modules/@babel/helper-split-export-declaration": {
- "version": "7.12.13",
- "dev": true,
- "inBundle": true,
- "license": "MIT",
- "dependencies": {
- "@babel/types": "^7.12.13"
- }
- },
- "node_modules/tap/node_modules/@babel/helper-validator-identifier": {
- "version": "7.14.0",
- "dev": true,
- "inBundle": true,
- "license": "MIT"
- },
- "node_modules/tap/node_modules/@babel/helper-validator-option": {
- "version": "7.12.17",
- "dev": true,
- "inBundle": true,
- "license": "MIT"
- },
- "node_modules/tap/node_modules/@babel/helpers": {
- "version": "7.14.0",
- "dev": true,
- "inBundle": true,
- "license": "MIT",
- "dependencies": {
- "@babel/template": "^7.12.13",
- "@babel/traverse": "^7.14.0",
- "@babel/types": "^7.14.0"
- }
- },
- "node_modules/tap/node_modules/@babel/highlight": {
- "version": "7.14.0",
- "dev": true,
- "inBundle": true,
- "license": "MIT",
- "dependencies": {
- "@babel/helper-validator-identifier": "^7.14.0",
- "chalk": "^2.0.0",
- "js-tokens": "^4.0.0"
- }
- },
- "node_modules/tap/node_modules/@babel/parser": {
- "version": "7.14.1",
- "dev": true,
- "inBundle": true,
- "license": "MIT",
- "bin": {
- "parser": "bin/babel-parser.js"
- },
- "engines": {
- "node": ">=6.0.0"
- }
- },
- "node_modules/tap/node_modules/@babel/plugin-proposal-object-rest-spread": {
- "version": "7.13.8",
- "dev": true,
- "inBundle": true,
- "license": "MIT",
- "dependencies": {
- "@babel/compat-data": "^7.13.8",
- "@babel/helper-compilation-targets": "^7.13.8",
- "@babel/helper-plugin-utils": "^7.13.0",
- "@babel/plugin-syntax-object-rest-spread": "^7.8.3",
- "@babel/plugin-transform-parameters": "^7.13.0"
- },
- "peerDependencies": {
- "@babel/core": "^7.0.0-0"
- }
- },
- "node_modules/tap/node_modules/@babel/plugin-syntax-jsx": {
- "version": "7.12.13",
- "dev": true,
- "inBundle": true,
- "license": "MIT",
- "dependencies": {
- "@babel/helper-plugin-utils": "^7.12.13"
- },
- "peerDependencies": {
- "@babel/core": "^7.0.0-0"
- }
- },
- "node_modules/tap/node_modules/@babel/plugin-syntax-object-rest-spread": {
- "version": "7.8.3",
- "dev": true,
- "inBundle": true,
- "license": "MIT",
- "dependencies": {
- "@babel/helper-plugin-utils": "^7.8.0"
- },
- "peerDependencies": {
- "@babel/core": "^7.0.0-0"
- }
- },
- "node_modules/tap/node_modules/@babel/plugin-transform-destructuring": {
- "version": "7.13.17",
- "dev": true,
- "inBundle": true,
- "license": "MIT",
- "dependencies": {
- "@babel/helper-plugin-utils": "^7.13.0"
- },
- "peerDependencies": {
- "@babel/core": "^7.0.0-0"
- }
- },
- "node_modules/tap/node_modules/@babel/plugin-transform-parameters": {
- "version": "7.13.0",
- "dev": true,
- "inBundle": true,
- "license": "MIT",
- "dependencies": {
- "@babel/helper-plugin-utils": "^7.13.0"
- },
- "peerDependencies": {
- "@babel/core": "^7.0.0-0"
- }
- },
- "node_modules/tap/node_modules/@babel/plugin-transform-react-jsx": {
- "version": "7.13.12",
- "dev": true,
- "inBundle": true,
- "license": "MIT",
- "dependencies": {
- "@babel/helper-annotate-as-pure": "^7.12.13",
- "@babel/helper-module-imports": "^7.13.12",
- "@babel/helper-plugin-utils": "^7.13.0",
- "@babel/plugin-syntax-jsx": "^7.12.13",
- "@babel/types": "^7.13.12"
- },
- "peerDependencies": {
- "@babel/core": "^7.0.0-0"
- }
- },
- "node_modules/tap/node_modules/@babel/template": {
- "version": "7.12.13",
- "dev": true,
- "inBundle": true,
- "license": "MIT",
- "dependencies": {
- "@babel/code-frame": "^7.12.13",
- "@babel/parser": "^7.12.13",
- "@babel/types": "^7.12.13"
- }
- },
- "node_modules/tap/node_modules/@babel/traverse": {
- "version": "7.14.0",
- "dev": true,
- "inBundle": true,
- "license": "MIT",
- "dependencies": {
- "@babel/code-frame": "^7.12.13",
- "@babel/generator": "^7.14.0",
- "@babel/helper-function-name": "^7.12.13",
- "@babel/helper-split-export-declaration": "^7.12.13",
- "@babel/parser": "^7.14.0",
- "@babel/types": "^7.14.0",
- "debug": "^4.1.0",
- "globals": "^11.1.0"
- }
- },
- "node_modules/tap/node_modules/@babel/types": {
- "version": "7.14.1",
- "dev": true,
- "inBundle": true,
- "license": "MIT",
- "dependencies": {
- "@babel/helper-validator-identifier": "^7.14.0",
- "to-fast-properties": "^2.0.0"
- }
- },
- "node_modules/tap/node_modules/@types/prop-types": {
- "version": "15.7.3",
- "dev": true,
- "inBundle": true,
- "license": "MIT"
- },
- "node_modules/tap/node_modules/@types/react": {
- "version": "16.14.6",
- "dev": true,
- "inBundle": true,
- "license": "MIT",
- "dependencies": {
- "@types/prop-types": "*",
- "@types/scheduler": "*",
- "csstype": "^3.0.2"
- }
- },
- "node_modules/tap/node_modules/@types/scheduler": {
- "version": "0.16.1",
- "dev": true,
- "inBundle": true,
- "license": "MIT"
- },
- "node_modules/tap/node_modules/@types/yoga-layout": {
- "version": "1.9.2",
- "dev": true,
- "inBundle": true,
- "license": "MIT"
- },
- "node_modules/tap/node_modules/ansi-escapes": {
- "version": "4.3.2",
- "dev": true,
- "inBundle": true,
- "license": "MIT",
- "dependencies": {
- "type-fest": "^0.21.3"
- },
- "engines": {
- "node": ">=8"
- },
- "funding": {
- "url": "https://github.com/sponsors/sindresorhus"
- }
- },
- "node_modules/tap/node_modules/ansi-styles": {
- "version": "3.2.1",
- "dev": true,
- "inBundle": true,
- "license": "MIT",
- "dependencies": {
- "color-convert": "^1.9.0"
- },
- "engines": {
- "node": ">=4"
- }
- },
- "node_modules/tap/node_modules/ansicolors": {
- "version": "0.3.2",
- "dev": true,
- "inBundle": true,
- "license": "MIT"
- },
- "node_modules/tap/node_modules/arrify": {
- "version": "2.0.1",
- "dev": true,
- "inBundle": true,
- "license": "MIT",
- "engines": {
- "node": ">=8"
- }
- },
- "node_modules/tap/node_modules/astral-regex": {
- "version": "2.0.0",
- "dev": true,
- "inBundle": true,
- "license": "MIT",
- "engines": {
- "node": ">=8"
- }
- },
- "node_modules/tap/node_modules/auto-bind": {
- "version": "4.0.0",
- "dev": true,
- "inBundle": true,
- "license": "MIT",
- "engines": {
- "node": ">=8"
- },
- "funding": {
- "url": "https://github.com/sponsors/sindresorhus"
- }
- },
- "node_modules/tap/node_modules/balanced-match": {
- "version": "1.0.2",
- "dev": true,
- "inBundle": true,
- "license": "MIT"
- },
- "node_modules/tap/node_modules/brace-expansion": {
- "version": "1.1.11",
- "dev": true,
- "inBundle": true,
- "license": "MIT",
- "dependencies": {
- "balanced-match": "^1.0.0",
- "concat-map": "0.0.1"
- }
- },
- "node_modules/tap/node_modules/browserslist": {
- "version": "4.16.6",
- "dev": true,
- "inBundle": true,
- "license": "MIT",
- "dependencies": {
- "caniuse-lite": "^1.0.30001219",
- "colorette": "^1.2.2",
- "electron-to-chromium": "^1.3.723",
- "escalade": "^3.1.1",
- "node-releases": "^1.1.71"
- },
- "bin": {
- "browserslist": "cli.js"
- },
- "engines": {
- "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7"
- },
- "funding": {
- "type": "opencollective",
- "url": "https://opencollective.com/browserslist"
- }
- },
- "node_modules/tap/node_modules/caller-callsite": {
- "version": "2.0.0",
- "dev": true,
- "inBundle": true,
- "license": "MIT",
- "dependencies": {
- "callsites": "^2.0.0"
- },
- "engines": {
- "node": ">=4"
- }
- },
- "node_modules/tap/node_modules/caller-path": {
- "version": "2.0.0",
- "dev": true,
- "inBundle": true,
- "license": "MIT",
- "dependencies": {
- "caller-callsite": "^2.0.0"
- },
- "engines": {
- "node": ">=4"
- }
- },
- "node_modules/tap/node_modules/callsites": {
- "version": "2.0.0",
- "dev": true,
- "inBundle": true,
- "license": "MIT",
- "engines": {
- "node": ">=4"
- }
- },
- "node_modules/tap/node_modules/caniuse-lite": {
- "version": "1.0.30001223",
- "dev": true,
- "inBundle": true,
- "license": "CC-BY-4.0"
- },
- "node_modules/tap/node_modules/cardinal": {
- "version": "2.1.1",
- "dev": true,
- "inBundle": true,
- "license": "MIT",
- "dependencies": {
- "ansicolors": "~0.3.2",
- "redeyed": "~2.1.0"
- },
- "bin": {
- "cdl": "bin/cdl.js"
- }
- },
- "node_modules/tap/node_modules/chalk": {
- "version": "2.4.2",
- "dev": true,
- "inBundle": true,
- "license": "MIT",
- "dependencies": {
- "ansi-styles": "^3.2.1",
- "escape-string-regexp": "^1.0.5",
- "supports-color": "^5.3.0"
- },
- "engines": {
- "node": ">=4"
- }
- },
- "node_modules/tap/node_modules/ci-info": {
- "version": "2.0.0",
- "dev": true,
- "inBundle": true,
- "license": "MIT"
- },
- "node_modules/tap/node_modules/cli-cursor": {
- "version": "3.1.0",
- "dev": true,
- "inBundle": true,
- "license": "MIT",
- "dependencies": {
- "restore-cursor": "^3.1.0"
- },
- "engines": {
- "node": ">=8"
- }
- },
- "node_modules/tap/node_modules/cli-truncate": {
- "version": "2.1.0",
- "dev": true,
- "inBundle": true,
- "license": "MIT",
- "dependencies": {
- "slice-ansi": "^3.0.0",
- "string-width": "^4.2.0"
- },
- "engines": {
- "node": ">=8"
- },
- "funding": {
- "url": "https://github.com/sponsors/sindresorhus"
- }
- },
- "node_modules/tap/node_modules/color-convert": {
- "version": "1.9.3",
- "dev": true,
- "inBundle": true,
- "license": "MIT",
- "dependencies": {
- "color-name": "1.1.3"
- }
- },
- "node_modules/tap/node_modules/color-name": {
- "version": "1.1.3",
- "dev": true,
- "inBundle": true,
- "license": "MIT"
- },
- "node_modules/tap/node_modules/colorette": {
- "version": "1.2.2",
- "dev": true,
- "inBundle": true,
- "license": "MIT"
- },
- "node_modules/tap/node_modules/commondir": {
- "version": "1.0.1",
- "dev": true,
- "inBundle": true,
- "license": "MIT"
- },
- "node_modules/tap/node_modules/concat-map": {
- "version": "0.0.1",
- "dev": true,
- "inBundle": true,
- "license": "MIT"
- },
- "node_modules/tap/node_modules/convert-source-map": {
- "version": "1.7.0",
- "dev": true,
- "inBundle": true,
- "license": "MIT",
- "dependencies": {
- "safe-buffer": "~5.1.1"
- }
- },
- "node_modules/tap/node_modules/csstype": {
- "version": "3.0.8",
- "dev": true,
- "inBundle": true,
- "license": "MIT"
- },
- "node_modules/tap/node_modules/debug": {
- "version": "4.3.1",
- "dev": true,
- "inBundle": true,
- "license": "MIT",
- "dependencies": {
- "ms": "2.1.2"
- },
- "engines": {
- "node": ">=6.0"
- },
- "peerDependenciesMeta": {
- "supports-color": {
- "optional": true
- }
- }
- },
- "node_modules/tap/node_modules/electron-to-chromium": {
- "version": "1.3.727",
- "dev": true,
- "inBundle": true,
- "license": "ISC"
- },
- "node_modules/tap/node_modules/emoji-regex": {
- "version": "8.0.0",
- "dev": true,
- "inBundle": true,
- "license": "MIT"
- },
- "node_modules/tap/node_modules/escalade": {
- "version": "3.1.1",
- "dev": true,
- "inBundle": true,
- "license": "MIT",
- "engines": {
- "node": ">=6"
- }
- },
- "node_modules/tap/node_modules/escape-string-regexp": {
- "version": "1.0.5",
- "dev": true,
- "inBundle": true,
- "license": "MIT",
- "engines": {
- "node": ">=0.8.0"
- }
- },
- "node_modules/tap/node_modules/esprima": {
- "version": "4.0.1",
- "dev": true,
- "inBundle": true,
- "license": "BSD-2-Clause",
- "bin": {
- "esparse": "bin/esparse.js",
- "esvalidate": "bin/esvalidate.js"
- },
- "engines": {
- "node": ">=4"
- }
- },
- "node_modules/tap/node_modules/events-to-array": {
- "version": "1.1.2",
- "dev": true,
- "inBundle": true,
- "license": "ISC"
- },
- "node_modules/tap/node_modules/find-cache-dir": {
- "version": "3.3.1",
- "dev": true,
- "inBundle": true,
- "license": "MIT",
- "dependencies": {
- "commondir": "^1.0.1",
- "make-dir": "^3.0.2",
- "pkg-dir": "^4.1.0"
- },
- "engines": {
- "node": ">=8"
- },
- "funding": {
- "url": "https://github.com/avajs/find-cache-dir?sponsor=1"
- }
- },
- "node_modules/tap/node_modules/find-up": {
- "version": "4.1.0",
- "dev": true,
- "inBundle": true,
- "license": "MIT",
- "dependencies": {
- "locate-path": "^5.0.0",
- "path-exists": "^4.0.0"
- },
- "engines": {
- "node": ">=8"
- }
- },
- "node_modules/tap/node_modules/fs.realpath": {
- "version": "1.0.0",
- "dev": true,
- "inBundle": true,
- "license": "ISC"
- },
- "node_modules/tap/node_modules/gensync": {
- "version": "1.0.0-beta.2",
- "dev": true,
- "inBundle": true,
- "license": "MIT",
- "engines": {
- "node": ">=6.9.0"
- }
- },
- "node_modules/tap/node_modules/glob": {
- "version": "7.1.7",
- "dev": true,
- "inBundle": true,
- "license": "ISC",
- "dependencies": {
- "fs.realpath": "^1.0.0",
- "inflight": "^1.0.4",
- "inherits": "2",
- "minimatch": "^3.0.4",
- "once": "^1.3.0",
- "path-is-absolute": "^1.0.0"
- },
- "engines": {
- "node": "*"
- },
- "funding": {
- "url": "https://github.com/sponsors/isaacs"
- }
- },
- "node_modules/tap/node_modules/globals": {
- "version": "11.12.0",
- "dev": true,
- "inBundle": true,
- "license": "MIT",
- "engines": {
- "node": ">=4"
- }
- },
- "node_modules/tap/node_modules/has-flag": {
- "version": "3.0.0",
- "dev": true,
- "inBundle": true,
- "license": "MIT",
- "engines": {
- "node": ">=4"
- }
- },
- "node_modules/tap/node_modules/import-jsx": {
- "version": "4.0.0",
- "dev": true,
- "inBundle": true,
- "license": "MIT",
- "dependencies": {
- "@babel/core": "^7.5.5",
- "@babel/plugin-proposal-object-rest-spread": "^7.5.5",
- "@babel/plugin-transform-destructuring": "^7.5.0",
- "@babel/plugin-transform-react-jsx": "^7.3.0",
- "caller-path": "^2.0.0",
- "find-cache-dir": "^3.2.0",
- "make-dir": "^3.0.2",
- "resolve-from": "^3.0.0",
- "rimraf": "^3.0.0"
- },
- "engines": {
- "node": ">=10"
- }
- },
- "node_modules/tap/node_modules/inflight": {
- "version": "1.0.6",
- "dev": true,
- "inBundle": true,
- "license": "ISC",
- "dependencies": {
- "once": "^1.3.0",
- "wrappy": "1"
- }
- },
- "node_modules/tap/node_modules/inherits": {
- "version": "2.0.4",
- "dev": true,
- "inBundle": true,
- "license": "ISC"
- },
- "node_modules/tap/node_modules/ink": {
- "version": "2.7.1",
- "dev": true,
- "inBundle": true,
- "license": "MIT",
- "dependencies": {
- "ansi-escapes": "^4.2.1",
- "arrify": "^2.0.1",
- "auto-bind": "^4.0.0",
- "chalk": "^3.0.0",
- "cli-cursor": "^3.1.0",
- "cli-truncate": "^2.1.0",
- "is-ci": "^2.0.0",
- "lodash.throttle": "^4.1.1",
- "log-update": "^3.0.0",
- "prop-types": "^15.6.2",
- "react-reconciler": "^0.24.0",
- "scheduler": "^0.18.0",
- "signal-exit": "^3.0.2",
- "slice-ansi": "^3.0.0",
- "string-length": "^3.1.0",
- "widest-line": "^3.1.0",
- "wrap-ansi": "^6.2.0",
- "yoga-layout-prebuilt": "^1.9.3"
- },
- "engines": {
- "node": ">=8"
- },
- "peerDependencies": {
- "@types/react": ">=16.8.0",
- "react": ">=16.8.0"
- },
- "peerDependenciesMeta": {
- "@types/react": {
- "optional": true
- }
- }
- },
- "node_modules/tap/node_modules/ink/node_modules/ansi-styles": {
- "version": "4.3.0",
- "dev": true,
- "inBundle": true,
- "license": "MIT",
- "dependencies": {
- "color-convert": "^2.0.1"
- },
- "engines": {
- "node": ">=8"
- },
- "funding": {
- "url": "https://github.com/chalk/ansi-styles?sponsor=1"
- }
- },
- "node_modules/tap/node_modules/ink/node_modules/chalk": {
- "version": "3.0.0",
- "dev": true,
- "inBundle": true,
- "license": "MIT",
- "dependencies": {
- "ansi-styles": "^4.1.0",
- "supports-color": "^7.1.0"
- },
- "engines": {
- "node": ">=8"
- }
- },
- "node_modules/tap/node_modules/ink/node_modules/color-convert": {
- "version": "2.0.1",
- "dev": true,
- "inBundle": true,
- "license": "MIT",
- "dependencies": {
- "color-name": "~1.1.4"
- },
- "engines": {
- "node": ">=7.0.0"
- }
- },
- "node_modules/tap/node_modules/ink/node_modules/color-name": {
- "version": "1.1.4",
- "dev": true,
- "inBundle": true,
- "license": "MIT"
- },
- "node_modules/tap/node_modules/ink/node_modules/has-flag": {
- "version": "4.0.0",
- "dev": true,
- "inBundle": true,
- "license": "MIT",
- "engines": {
- "node": ">=8"
- }
- },
- "node_modules/tap/node_modules/ink/node_modules/supports-color": {
- "version": "7.2.0",
- "dev": true,
- "inBundle": true,
- "license": "MIT",
- "dependencies": {
- "has-flag": "^4.0.0"
- },
- "engines": {
- "node": ">=8"
- }
- },
- "node_modules/tap/node_modules/is-ci": {
- "version": "2.0.0",
- "dev": true,
- "inBundle": true,
- "license": "MIT",
- "dependencies": {
- "ci-info": "^2.0.0"
- },
- "bin": {
- "is-ci": "bin.js"
- }
- },
- "node_modules/tap/node_modules/is-fullwidth-code-point": {
- "version": "3.0.0",
- "dev": true,
- "inBundle": true,
- "license": "MIT",
- "engines": {
- "node": ">=8"
- }
- },
- "node_modules/tap/node_modules/js-tokens": {
- "version": "4.0.0",
- "dev": true,
- "inBundle": true,
- "license": "MIT"
- },
- "node_modules/tap/node_modules/jsesc": {
- "version": "2.5.2",
- "dev": true,
- "inBundle": true,
- "license": "MIT",
- "bin": {
- "jsesc": "bin/jsesc"
- },
- "engines": {
- "node": ">=4"
- }
- },
- "node_modules/tap/node_modules/json5": {
- "version": "2.2.0",
- "dev": true,
- "inBundle": true,
- "license": "MIT",
- "dependencies": {
- "minimist": "^1.2.5"
- },
- "bin": {
- "json5": "lib/cli.js"
- },
- "engines": {
- "node": ">=6"
- }
- },
- "node_modules/tap/node_modules/locate-path": {
- "version": "5.0.0",
- "dev": true,
- "inBundle": true,
- "license": "MIT",
- "dependencies": {
- "p-locate": "^4.1.0"
- },
- "engines": {
- "node": ">=8"
- }
- },
- "node_modules/tap/node_modules/lodash.throttle": {
- "version": "4.1.1",
- "dev": true,
- "inBundle": true,
- "license": "MIT"
- },
- "node_modules/tap/node_modules/log-update": {
- "version": "3.4.0",
- "dev": true,
- "inBundle": true,
- "license": "MIT",
- "dependencies": {
- "ansi-escapes": "^3.2.0",
- "cli-cursor": "^2.1.0",
- "wrap-ansi": "^5.0.0"
- },
- "engines": {
- "node": ">=6"
- },
- "funding": {
- "url": "https://github.com/sponsors/sindresorhus"
- }
- },
- "node_modules/tap/node_modules/log-update/node_modules/ansi-escapes": {
- "version": "3.2.0",
- "dev": true,
- "inBundle": true,
- "license": "MIT",
- "engines": {
- "node": ">=4"
- }
- },
- "node_modules/tap/node_modules/log-update/node_modules/ansi-regex": {
- "version": "4.1.0",
- "dev": true,
- "inBundle": true,
- "license": "MIT",
- "engines": {
- "node": ">=6"
- }
- },
- "node_modules/tap/node_modules/log-update/node_modules/cli-cursor": {
- "version": "2.1.0",
- "dev": true,
- "inBundle": true,
- "license": "MIT",
- "dependencies": {
- "restore-cursor": "^2.0.0"
- },
- "engines": {
- "node": ">=4"
- }
- },
- "node_modules/tap/node_modules/log-update/node_modules/emoji-regex": {
- "version": "7.0.3",
- "dev": true,
- "inBundle": true,
- "license": "MIT"
- },
- "node_modules/tap/node_modules/log-update/node_modules/is-fullwidth-code-point": {
- "version": "2.0.0",
- "dev": true,
- "inBundle": true,
- "license": "MIT",
- "engines": {
- "node": ">=4"
- }
- },
- "node_modules/tap/node_modules/log-update/node_modules/mimic-fn": {
- "version": "1.2.0",
- "dev": true,
- "inBundle": true,
- "license": "MIT",
- "engines": {
- "node": ">=4"
- }
- },
- "node_modules/tap/node_modules/log-update/node_modules/onetime": {
- "version": "2.0.1",
- "dev": true,
- "inBundle": true,
- "license": "MIT",
- "dependencies": {
- "mimic-fn": "^1.0.0"
- },
- "engines": {
- "node": ">=4"
- }
- },
- "node_modules/tap/node_modules/log-update/node_modules/restore-cursor": {
- "version": "2.0.0",
- "dev": true,
- "inBundle": true,
- "license": "MIT",
- "dependencies": {
- "onetime": "^2.0.0",
- "signal-exit": "^3.0.2"
- },
- "engines": {
- "node": ">=4"
- }
- },
- "node_modules/tap/node_modules/log-update/node_modules/string-width": {
- "version": "3.1.0",
- "dev": true,
- "inBundle": true,
- "license": "MIT",
- "dependencies": {
- "emoji-regex": "^7.0.1",
- "is-fullwidth-code-point": "^2.0.0",
- "strip-ansi": "^5.1.0"
- },
- "engines": {
- "node": ">=6"
- }
- },
- "node_modules/tap/node_modules/log-update/node_modules/strip-ansi": {
- "version": "5.2.0",
- "dev": true,
- "inBundle": true,
- "license": "MIT",
- "dependencies": {
- "ansi-regex": "^4.1.0"
- },
- "engines": {
- "node": ">=6"
- }
- },
- "node_modules/tap/node_modules/log-update/node_modules/wrap-ansi": {
- "version": "5.1.0",
- "dev": true,
- "inBundle": true,
- "license": "MIT",
- "dependencies": {
- "ansi-styles": "^3.2.0",
- "string-width": "^3.0.0",
- "strip-ansi": "^5.0.0"
- },
- "engines": {
- "node": ">=6"
- }
- },
- "node_modules/tap/node_modules/loose-envify": {
- "version": "1.4.0",
- "dev": true,
- "inBundle": true,
- "license": "MIT",
- "dependencies": {
- "js-tokens": "^3.0.0 || ^4.0.0"
- },
- "bin": {
- "loose-envify": "cli.js"
- }
- },
- "node_modules/tap/node_modules/make-dir": {
- "version": "3.1.0",
- "dev": true,
- "inBundle": true,
- "license": "MIT",
- "dependencies": {
- "semver": "^6.0.0"
- },
- "engines": {
- "node": ">=8"
- },
- "funding": {
- "url": "https://github.com/sponsors/sindresorhus"
- }
- },
- "node_modules/tap/node_modules/mimic-fn": {
- "version": "2.1.0",
- "dev": true,
- "inBundle": true,
- "license": "MIT",
- "engines": {
- "node": ">=6"
- }
- },
- "node_modules/tap/node_modules/minimatch": {
- "version": "3.0.4",
- "dev": true,
- "inBundle": true,
- "license": "ISC",
- "dependencies": {
- "brace-expansion": "^1.1.7"
- },
- "engines": {
- "node": "*"
- }
- },
- "node_modules/tap/node_modules/minimist": {
- "version": "1.2.5",
- "dev": true,
- "inBundle": true,
- "license": "MIT"
- },
- "node_modules/tap/node_modules/minipass": {
- "version": "3.1.3",
- "dev": true,
- "inBundle": true,
- "license": "ISC",
- "dependencies": {
- "yallist": "^4.0.0"
- },
- "engines": {
- "node": ">=8"
- }
- },
- "node_modules/tap/node_modules/mkdirp": {
- "version": "1.0.4",
- "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz",
- "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==",
- "dev": true,
- "bin": {
- "mkdirp": "bin/cmd.js"
- },
- "engines": {
- "node": ">=10"
- }
- },
- "node_modules/tap/node_modules/ms": {
- "version": "2.1.2",
- "dev": true,
- "inBundle": true,
- "license": "MIT"
- },
- "node_modules/tap/node_modules/node-releases": {
- "version": "1.1.71",
- "dev": true,
- "inBundle": true,
- "license": "MIT"
- },
- "node_modules/tap/node_modules/object-assign": {
- "version": "4.1.1",
- "dev": true,
- "inBundle": true,
- "license": "MIT",
- "engines": {
- "node": ">=0.10.0"
- }
- },
- "node_modules/tap/node_modules/once": {
- "version": "1.4.0",
- "dev": true,
- "inBundle": true,
- "license": "ISC",
- "dependencies": {
- "wrappy": "1"
- }
- },
- "node_modules/tap/node_modules/onetime": {
- "version": "5.1.2",
- "dev": true,
- "inBundle": true,
- "license": "MIT",
- "dependencies": {
- "mimic-fn": "^2.1.0"
- },
- "engines": {
- "node": ">=6"
- },
- "funding": {
- "url": "https://github.com/sponsors/sindresorhus"
- }
- },
- "node_modules/tap/node_modules/p-limit": {
- "version": "2.3.0",
- "dev": true,
- "inBundle": true,
- "license": "MIT",
- "dependencies": {
- "p-try": "^2.0.0"
- },
- "engines": {
- "node": ">=6"
- },
- "funding": {
- "url": "https://github.com/sponsors/sindresorhus"
- }
- },
- "node_modules/tap/node_modules/p-locate": {
- "version": "4.1.0",
- "dev": true,
- "inBundle": true,
- "license": "MIT",
- "dependencies": {
- "p-limit": "^2.2.0"
- },
- "engines": {
- "node": ">=8"
- }
- },
- "node_modules/tap/node_modules/p-try": {
- "version": "2.2.0",
- "dev": true,
- "inBundle": true,
- "license": "MIT",
- "engines": {
- "node": ">=6"
- }
- },
- "node_modules/tap/node_modules/path-exists": {
- "version": "4.0.0",
- "dev": true,
- "inBundle": true,
- "license": "MIT",
- "engines": {
- "node": ">=8"
- }
- },
- "node_modules/tap/node_modules/path-is-absolute": {
- "version": "1.0.1",
- "dev": true,
- "inBundle": true,
- "license": "MIT",
- "engines": {
- "node": ">=0.10.0"
- }
- },
- "node_modules/tap/node_modules/pkg-dir": {
- "version": "4.2.0",
- "dev": true,
- "inBundle": true,
- "license": "MIT",
- "dependencies": {
- "find-up": "^4.0.0"
- },
- "engines": {
- "node": ">=8"
- }
- },
- "node_modules/tap/node_modules/prop-types": {
- "version": "15.7.2",
- "dev": true,
- "inBundle": true,
- "license": "MIT",
- "dependencies": {
- "loose-envify": "^1.4.0",
- "object-assign": "^4.1.1",
- "react-is": "^16.8.1"
- }
- },
- "node_modules/tap/node_modules/punycode": {
- "version": "2.1.1",
- "dev": true,
- "inBundle": true,
- "license": "MIT",
- "engines": {
- "node": ">=6"
- }
- },
- "node_modules/tap/node_modules/react-is": {
- "version": "16.13.1",
- "dev": true,
- "inBundle": true,
- "license": "MIT"
- },
- "node_modules/tap/node_modules/react-reconciler": {
- "version": "0.24.0",
- "dev": true,
- "inBundle": true,
- "license": "MIT",
- "dependencies": {
- "loose-envify": "^1.1.0",
- "object-assign": "^4.1.1",
- "prop-types": "^15.6.2",
- "scheduler": "^0.18.0"
- },
- "engines": {
- "node": ">=0.10.0"
- },
- "peerDependencies": {
- "react": "^16.0.0"
- }
- },
- "node_modules/tap/node_modules/redeyed": {
- "version": "2.1.1",
- "dev": true,
- "inBundle": true,
- "license": "MIT",
- "dependencies": {
- "esprima": "~4.0.0"
- }
- },
- "node_modules/tap/node_modules/resolve-from": {
- "version": "3.0.0",
- "dev": true,
- "inBundle": true,
- "license": "MIT",
- "engines": {
- "node": ">=4"
- }
- },
- "node_modules/tap/node_modules/restore-cursor": {
- "version": "3.1.0",
- "dev": true,
- "inBundle": true,
- "license": "MIT",
- "dependencies": {
- "onetime": "^5.1.0",
- "signal-exit": "^3.0.2"
- },
- "engines": {
- "node": ">=8"
- }
- },
- "node_modules/tap/node_modules/rimraf": {
- "version": "3.0.2",
- "dev": true,
- "inBundle": true,
- "license": "ISC",
- "dependencies": {
- "glob": "^7.1.3"
- },
- "bin": {
- "rimraf": "bin.js"
- },
- "funding": {
- "url": "https://github.com/sponsors/isaacs"
- }
- },
- "node_modules/tap/node_modules/safe-buffer": {
- "version": "5.1.2",
- "dev": true,
- "inBundle": true,
- "license": "MIT"
- },
- "node_modules/tap/node_modules/scheduler": {
- "version": "0.18.0",
- "dev": true,
- "inBundle": true,
- "license": "MIT",
- "dependencies": {
- "loose-envify": "^1.1.0",
- "object-assign": "^4.1.1"
- }
- },
- "node_modules/tap/node_modules/semver": {
- "version": "6.3.0",
- "dev": true,
- "inBundle": true,
- "license": "ISC",
- "bin": {
- "semver": "bin/semver.js"
- }
- },
- "node_modules/tap/node_modules/signal-exit": {
- "version": "3.0.3",
- "dev": true,
- "inBundle": true,
- "license": "ISC"
- },
- "node_modules/tap/node_modules/slice-ansi": {
- "version": "3.0.0",
- "dev": true,
- "inBundle": true,
- "license": "MIT",
- "dependencies": {
- "ansi-styles": "^4.0.0",
- "astral-regex": "^2.0.0",
- "is-fullwidth-code-point": "^3.0.0"
- },
- "engines": {
- "node": ">=8"
- }
- },
- "node_modules/tap/node_modules/slice-ansi/node_modules/ansi-styles": {
- "version": "4.3.0",
- "dev": true,
- "inBundle": true,
- "license": "MIT",
- "dependencies": {
- "color-convert": "^2.0.1"
- },
- "engines": {
- "node": ">=8"
- },
- "funding": {
- "url": "https://github.com/chalk/ansi-styles?sponsor=1"
- }
- },
- "node_modules/tap/node_modules/slice-ansi/node_modules/color-convert": {
- "version": "2.0.1",
- "dev": true,
- "inBundle": true,
- "license": "MIT",
- "dependencies": {
- "color-name": "~1.1.4"
- },
- "engines": {
- "node": ">=7.0.0"
- }
- },
- "node_modules/tap/node_modules/slice-ansi/node_modules/color-name": {
- "version": "1.1.4",
- "dev": true,
- "inBundle": true,
- "license": "MIT"
- },
- "node_modules/tap/node_modules/source-map": {
- "version": "0.5.7",
- "dev": true,
- "inBundle": true,
- "license": "BSD-3-Clause",
- "engines": {
- "node": ">=0.10.0"
- }
- },
- "node_modules/tap/node_modules/string-length": {
- "version": "3.1.0",
- "dev": true,
- "inBundle": true,
- "license": "MIT",
- "dependencies": {
- "astral-regex": "^1.0.0",
- "strip-ansi": "^5.2.0"
- },
- "engines": {
- "node": ">=8"
- }
- },
- "node_modules/tap/node_modules/string-length/node_modules/ansi-regex": {
- "version": "4.1.0",
- "dev": true,
- "inBundle": true,
- "license": "MIT",
- "engines": {
- "node": ">=6"
- }
- },
- "node_modules/tap/node_modules/string-length/node_modules/astral-regex": {
- "version": "1.0.0",
- "dev": true,
- "inBundle": true,
- "license": "MIT",
- "engines": {
- "node": ">=4"
- }
- },
- "node_modules/tap/node_modules/string-length/node_modules/strip-ansi": {
- "version": "5.2.0",
- "dev": true,
- "inBundle": true,
- "license": "MIT",
- "dependencies": {
- "ansi-regex": "^4.1.0"
- },
- "engines": {
- "node": ">=6"
- }
- },
- "node_modules/tap/node_modules/string-width": {
- "version": "4.2.2",
- "dev": true,
- "inBundle": true,
- "license": "MIT",
- "dependencies": {
- "emoji-regex": "^8.0.0",
- "is-fullwidth-code-point": "^3.0.0",
- "strip-ansi": "^6.0.0"
- },
- "engines": {
- "node": ">=8"
- }
- },
- "node_modules/tap/node_modules/string-width/node_modules/ansi-regex": {
- "version": "5.0.0",
- "dev": true,
- "inBundle": true,
- "license": "MIT",
- "engines": {
- "node": ">=8"
- }
- },
- "node_modules/tap/node_modules/string-width/node_modules/strip-ansi": {
- "version": "6.0.0",
- "dev": true,
- "inBundle": true,
- "license": "MIT",
- "dependencies": {
- "ansi-regex": "^5.0.0"
- },
- "engines": {
- "node": ">=8"
- }
- },
- "node_modules/tap/node_modules/supports-color": {
- "version": "5.5.0",
- "dev": true,
- "inBundle": true,
- "license": "MIT",
- "dependencies": {
- "has-flag": "^3.0.0"
- },
- "engines": {
- "node": ">=4"
- }
- },
- "node_modules/tap/node_modules/tap-parser": {
- "version": "10.1.0",
- "dev": true,
- "inBundle": true,
- "license": "MIT",
- "dependencies": {
- "events-to-array": "^1.0.1",
- "minipass": "^3.0.0",
- "tap-yaml": "^1.0.0"
- },
- "bin": {
- "tap-parser": "bin/cmd.js"
- },
- "engines": {
- "node": ">= 8"
- }
- },
- "node_modules/tap/node_modules/tap-yaml": {
- "version": "1.0.0",
- "dev": true,
- "inBundle": true,
- "license": "ISC",
- "dependencies": {
- "yaml": "^1.5.0"
- }
- },
- "node_modules/tap/node_modules/to-fast-properties": {
- "version": "2.0.0",
- "dev": true,
- "inBundle": true,
- "license": "MIT",
- "engines": {
- "node": ">=4"
- }
- },
- "node_modules/tap/node_modules/treport": {
- "version": "2.0.2",
- "dev": true,
- "inBundle": true,
- "license": "ISC",
- "dependencies": {
- "cardinal": "^2.1.1",
- "chalk": "^3.0.0",
- "import-jsx": "^4.0.0",
- "ink": "^2.6.0",
- "ms": "^2.1.2",
- "string-length": "^3.1.0",
- "tap-parser": "^10.0.1",
- "unicode-length": "^2.0.2"
- },
- "peerDependencies": {
- "react": "^16.8.6"
- }
- },
- "node_modules/tap/node_modules/treport/node_modules/ansi-styles": {
- "version": "4.3.0",
- "dev": true,
- "inBundle": true,
- "license": "MIT",
- "dependencies": {
- "color-convert": "^2.0.1"
- },
- "engines": {
- "node": ">=8"
- },
- "funding": {
- "url": "https://github.com/chalk/ansi-styles?sponsor=1"
- }
- },
- "node_modules/tap/node_modules/treport/node_modules/chalk": {
- "version": "3.0.0",
- "dev": true,
- "inBundle": true,
- "license": "MIT",
- "dependencies": {
- "ansi-styles": "^4.1.0",
- "supports-color": "^7.1.0"
- },
- "engines": {
- "node": ">=8"
- }
- },
- "node_modules/tap/node_modules/treport/node_modules/color-convert": {
- "version": "2.0.1",
- "dev": true,
- "inBundle": true,
- "license": "MIT",
- "dependencies": {
- "color-name": "~1.1.4"
- },
- "engines": {
- "node": ">=7.0.0"
- }
- },
- "node_modules/tap/node_modules/treport/node_modules/color-name": {
- "version": "1.1.4",
- "dev": true,
- "inBundle": true,
- "license": "MIT"
- },
- "node_modules/tap/node_modules/treport/node_modules/has-flag": {
- "version": "4.0.0",
- "dev": true,
- "inBundle": true,
- "license": "MIT",
- "engines": {
- "node": ">=8"
- }
- },
- "node_modules/tap/node_modules/treport/node_modules/supports-color": {
- "version": "7.2.0",
- "dev": true,
- "inBundle": true,
- "license": "MIT",
- "dependencies": {
- "has-flag": "^4.0.0"
- },
- "engines": {
- "node": ">=8"
- }
- },
- "node_modules/tap/node_modules/type-fest": {
- "version": "0.21.3",
- "dev": true,
- "inBundle": true,
- "license": "(MIT OR CC0-1.0)",
- "engines": {
- "node": ">=10"
- },
- "funding": {
- "url": "https://github.com/sponsors/sindresorhus"
- }
- },
- "node_modules/tap/node_modules/unicode-length": {
- "version": "2.0.2",
- "dev": true,
- "inBundle": true,
- "license": "MIT",
- "dependencies": {
- "punycode": "^2.0.0",
- "strip-ansi": "^3.0.1"
- }
- },
- "node_modules/tap/node_modules/unicode-length/node_modules/ansi-regex": {
- "version": "2.1.1",
- "dev": true,
- "inBundle": true,
- "license": "MIT",
- "engines": {
- "node": ">=0.10.0"
- }
- },
- "node_modules/tap/node_modules/unicode-length/node_modules/strip-ansi": {
- "version": "3.0.1",
- "dev": true,
- "inBundle": true,
- "license": "MIT",
- "dependencies": {
- "ansi-regex": "^2.0.0"
- },
- "engines": {
- "node": ">=0.10.0"
- }
- },
- "node_modules/tap/node_modules/widest-line": {
- "version": "3.1.0",
- "dev": true,
- "inBundle": true,
- "license": "MIT",
- "dependencies": {
- "string-width": "^4.0.0"
- },
- "engines": {
- "node": ">=8"
- }
- },
- "node_modules/tap/node_modules/wrap-ansi": {
- "version": "6.2.0",
- "dev": true,
- "inBundle": true,
- "license": "MIT",
- "dependencies": {
- "ansi-styles": "^4.0.0",
- "string-width": "^4.1.0",
- "strip-ansi": "^6.0.0"
- },
- "engines": {
- "node": ">=8"
- }
- },
- "node_modules/tap/node_modules/wrap-ansi/node_modules/ansi-regex": {
- "version": "5.0.0",
- "dev": true,
- "inBundle": true,
- "license": "MIT",
- "engines": {
- "node": ">=8"
- }
- },
- "node_modules/tap/node_modules/wrap-ansi/node_modules/ansi-styles": {
- "version": "4.3.0",
- "dev": true,
- "inBundle": true,
- "license": "MIT",
- "dependencies": {
- "color-convert": "^2.0.1"
- },
- "engines": {
- "node": ">=8"
- },
- "funding": {
- "url": "https://github.com/chalk/ansi-styles?sponsor=1"
- }
- },
- "node_modules/tap/node_modules/wrap-ansi/node_modules/color-convert": {
- "version": "2.0.1",
- "dev": true,
- "inBundle": true,
- "license": "MIT",
- "dependencies": {
- "color-name": "~1.1.4"
- },
- "engines": {
- "node": ">=7.0.0"
- }
- },
- "node_modules/tap/node_modules/wrap-ansi/node_modules/color-name": {
- "version": "1.1.4",
- "dev": true,
- "inBundle": true,
- "license": "MIT"
- },
- "node_modules/tap/node_modules/wrap-ansi/node_modules/strip-ansi": {
- "version": "6.0.0",
- "dev": true,
- "inBundle": true,
- "license": "MIT",
- "dependencies": {
- "ansi-regex": "^5.0.0"
- },
- "engines": {
- "node": ">=8"
- }
- },
- "node_modules/tap/node_modules/wrappy": {
- "version": "1.0.2",
- "dev": true,
- "inBundle": true,
- "license": "ISC"
- },
- "node_modules/tap/node_modules/yallist": {
- "version": "4.0.0",
- "dev": true,
- "inBundle": true,
- "license": "ISC"
- },
- "node_modules/tap/node_modules/yaml": {
- "version": "1.10.2",
- "dev": true,
- "inBundle": true,
- "license": "ISC",
- "engines": {
- "node": ">= 6"
- }
- },
- "node_modules/tap/node_modules/yoga-layout-prebuilt": {
- "version": "1.10.0",
- "dev": true,
- "inBundle": true,
- "license": "MIT",
- "dependencies": {
- "@types/yoga-layout": "1.9.2"
- },
- "engines": {
- "node": ">=8"
- }
- },
- "node_modules/tcompare": {
- "version": "5.0.6",
- "resolved": "https://registry.npmjs.org/tcompare/-/tcompare-5.0.6.tgz",
- "integrity": "sha512-OvO7omN/wkdsKzmOqr3sQFfLbghs/2X5mwSkcfgRiXZshfPnTsAs3IRf1RixR/Pff26qG/r9ogcZMpV0YdeGXg==",
- "dev": true,
- "dependencies": {
- "diff": "^4.0.2"
- },
- "engines": {
- "node": ">=10"
- }
- },
- "node_modules/test-exclude": {
- "version": "6.0.0",
- "resolved": "https://registry.npmjs.org/test-exclude/-/test-exclude-6.0.0.tgz",
- "integrity": "sha512-cAGWPIyOHU6zlmg88jwm7VRyXnMN7iV68OGAbYDk/Mh/xC/pzVPlQtY6ngoIH/5/tciuhGfvESU8GrHrcxD56w==",
- "dev": true,
- "dependencies": {
- "@istanbuljs/schema": "^0.1.2",
- "glob": "^7.1.4",
- "minimatch": "^3.0.4"
- },
- "engines": {
- "node": ">=8"
- }
- },
- "node_modules/tiny-emitter": {
- "version": "2.1.0",
- "resolved": "https://registry.npmjs.org/tiny-emitter/-/tiny-emitter-2.1.0.tgz",
- "integrity": "sha512-NB6Dk1A9xgQPMoGqC5CVXn123gWyte215ONT5Pp5a0yt4nlEoO1ZWeCwpncaekPHXO60i47ihFnZPiRPjRMq4Q=="
- },
- "node_modules/to-fast-properties": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz",
- "integrity": "sha1-3F5pjL0HkmW8c+A3doGk5Og/YW4=",
- "dev": true,
- "engines": {
- "node": ">=4"
- }
- },
- "node_modules/to-regex-range": {
- "version": "5.0.1",
- "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz",
- "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==",
- "dev": true,
- "dependencies": {
- "is-number": "^7.0.0"
- },
- "engines": {
- "node": ">=8.0"
- }
- },
- "node_modules/toidentifier": {
- "version": "1.0.1",
- "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz",
- "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==",
- "engines": {
- "node": ">=0.6"
- }
- },
- "node_modules/tough-cookie": {
- "version": "2.5.0",
- "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.5.0.tgz",
- "integrity": "sha512-nlLsUzgm1kfLXSXfRZMc1KLAugd4hqJHDTvc2hDIwS3mZAfMEuMbc03SujMF+GEcpaX/qboeycw6iO8JwVv2+g==",
- "dev": true,
- "dependencies": {
- "psl": "^1.1.28",
- "punycode": "^2.1.1"
- },
- "engines": {
- "node": ">=0.8"
- }
- },
- "node_modules/trivial-deferred": {
- "version": "1.0.1",
- "resolved": "https://registry.npmjs.org/trivial-deferred/-/trivial-deferred-1.0.1.tgz",
- "integrity": "sha1-N21NKdlR1jaKb3oK6FwvTV4GWPM=",
- "dev": true
- },
- "node_modules/tunnel-agent": {
- "version": "0.6.0",
- "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz",
- "integrity": "sha1-J6XeoGs2sEoKmWZ3SykIaPD8QP0=",
- "dev": true,
- "dependencies": {
- "safe-buffer": "^5.0.1"
- },
- "engines": {
- "node": "*"
- }
- },
- "node_modules/tweetnacl": {
- "version": "0.14.5",
- "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.5.tgz",
- "integrity": "sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q=",
- "dev": true
- },
- "node_modules/type-fest": {
- "version": "0.8.1",
- "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.8.1.tgz",
- "integrity": "sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA==",
- "dev": true,
- "engines": {
- "node": ">=8"
- }
- },
- "node_modules/type-is": {
- "version": "1.6.18",
- "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz",
- "integrity": "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==",
- "dependencies": {
- "media-typer": "0.3.0",
- "mime-types": "~2.1.24"
- },
- "engines": {
- "node": ">= 0.6"
- }
- },
- "node_modules/typed-function": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/typed-function/-/typed-function-2.0.0.tgz",
- "integrity": "sha512-Hhy1Iwo/e4AtLZNK10ewVVcP2UEs408DS35ubP825w/YgSBK1KVLwALvvIG4yX75QJrxjCpcWkzkVRB0BwwYlA==",
- "engines": {
- "node": ">= 8"
- }
- },
- "node_modules/typedarray-to-buffer": {
- "version": "3.1.5",
- "resolved": "https://registry.npmjs.org/typedarray-to-buffer/-/typedarray-to-buffer-3.1.5.tgz",
- "integrity": "sha512-zdu8XMNEDepKKR+XYOXAVPtWui0ly0NtohUscw+UmaHiAWT8hrV1rr//H6V+0DvJ3OQ19S979M0laLfX8rm82Q==",
- "dev": true,
- "dependencies": {
- "is-typedarray": "^1.0.0"
- }
- },
- "node_modules/unicode-length": {
- "version": "2.0.2",
- "resolved": "https://registry.npmjs.org/unicode-length/-/unicode-length-2.0.2.tgz",
- "integrity": "sha512-Ph/j1VbS3/r77nhoY2WU0GWGjVYOHL3xpKp0y/Eq2e5r0mT/6b649vm7KFO6RdAdrZkYLdxphYVgvODxPB+Ebg==",
- "dev": true,
- "dependencies": {
- "punycode": "^2.0.0",
- "strip-ansi": "^3.0.1"
- }
- },
- "node_modules/unicode-length/node_modules/ansi-regex": {
- "version": "2.1.1",
- "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz",
- "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=",
- "dev": true,
- "engines": {
- "node": ">=0.10.0"
- }
- },
- "node_modules/unicode-length/node_modules/strip-ansi": {
- "version": "3.0.1",
- "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz",
- "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=",
- "dev": true,
- "dependencies": {
- "ansi-regex": "^2.0.0"
- },
- "engines": {
- "node": ">=0.10.0"
- }
- },
- "node_modules/unpipe": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz",
- "integrity": "sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==",
- "engines": {
- "node": ">= 0.8"
- }
- },
- "node_modules/uri-js": {
- "version": "4.4.1",
- "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz",
- "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==",
- "dev": true,
- "dependencies": {
- "punycode": "^2.1.0"
- }
- },
- "node_modules/utils-merge": {
- "version": "1.0.1",
- "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz",
- "integrity": "sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA==",
- "engines": {
- "node": ">= 0.4.0"
- }
- },
- "node_modules/uuid": {
- "version": "3.4.0",
- "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.4.0.tgz",
- "integrity": "sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==",
- "dev": true,
- "bin": {
- "uuid": "bin/uuid"
- }
- },
- "node_modules/vary": {
- "version": "1.1.2",
- "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz",
- "integrity": "sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==",
- "engines": {
- "node": ">= 0.8"
- }
- },
- "node_modules/verror": {
- "version": "1.10.0",
- "resolved": "https://registry.npmjs.org/verror/-/verror-1.10.0.tgz",
- "integrity": "sha1-OhBcoXBTr1XW4nDB+CiGguGNpAA=",
- "dev": true,
- "engines": [
- "node >=0.6.0"
- ],
- "dependencies": {
- "assert-plus": "^1.0.0",
- "core-util-is": "1.0.2",
- "extsprintf": "^1.2.0"
- }
- },
- "node_modules/which": {
- "version": "2.0.2",
- "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz",
- "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==",
- "dev": true,
- "dependencies": {
- "isexe": "^2.0.0"
- },
- "bin": {
- "node-which": "bin/node-which"
- },
- "engines": {
- "node": ">= 8"
- }
- },
- "node_modules/which-module": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/which-module/-/which-module-2.0.0.tgz",
- "integrity": "sha1-2e8H3Od7mQK4o6j6SzHD4/fm6Ho=",
- "dev": true
- },
- "node_modules/wrap-ansi": {
- "version": "2.1.0",
- "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-2.1.0.tgz",
- "integrity": "sha1-2Pw9KE3QV5T+hJc8rs3Rz4JP3YU=",
- "dev": true,
- "dependencies": {
- "string-width": "^1.0.1",
- "strip-ansi": "^3.0.1"
- },
- "engines": {
- "node": ">=0.10.0"
- }
- },
- "node_modules/wrap-ansi/node_modules/ansi-regex": {
- "version": "2.1.1",
- "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz",
- "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=",
- "dev": true,
- "engines": {
- "node": ">=0.10.0"
- }
- },
- "node_modules/wrap-ansi/node_modules/is-fullwidth-code-point": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz",
- "integrity": "sha1-754xOG8DGn8NZDr4L95QxFfvAMs=",
- "dev": true,
- "dependencies": {
- "number-is-nan": "^1.0.0"
- },
- "engines": {
- "node": ">=0.10.0"
- }
- },
- "node_modules/wrap-ansi/node_modules/string-width": {
- "version": "1.0.2",
- "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz",
- "integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=",
- "dev": true,
- "dependencies": {
- "code-point-at": "^1.0.0",
- "is-fullwidth-code-point": "^1.0.0",
- "strip-ansi": "^3.0.0"
- },
- "engines": {
- "node": ">=0.10.0"
- }
- },
- "node_modules/wrap-ansi/node_modules/strip-ansi": {
- "version": "3.0.1",
- "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz",
- "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=",
- "dev": true,
- "dependencies": {
- "ansi-regex": "^2.0.0"
- },
- "engines": {
- "node": ">=0.10.0"
- }
- },
- "node_modules/wrappy": {
- "version": "1.0.2",
- "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz",
- "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8="
- },
- "node_modules/write-file-atomic": {
- "version": "3.0.3",
- "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-3.0.3.tgz",
- "integrity": "sha512-AvHcyZ5JnSfq3ioSyjrBkH9yW4m7Ayk8/9My/DD9onKeu/94fwrMocemO2QAJFAlnnDN+ZDS+ZjAR5ua1/PV/Q==",
- "dev": true,
- "dependencies": {
- "imurmurhash": "^0.1.4",
- "is-typedarray": "^1.0.0",
- "signal-exit": "^3.0.2",
- "typedarray-to-buffer": "^3.1.5"
- }
- },
- "node_modules/y18n": {
- "version": "4.0.3",
- "resolved": "https://registry.npmjs.org/y18n/-/y18n-4.0.3.tgz",
- "integrity": "sha512-JKhqTOwSrqNA1NY5lSztJ1GrBiUodLMmIZuLiDaMRJ+itFd+ABVE8XBjOvIWL+rSqNDC74LCSFmlb/U4UZ4hJQ==",
- "dev": true
- },
- "node_modules/yallist": {
- "version": "4.0.0",
- "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz",
- "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A=="
- },
- "node_modules/yaml": {
- "version": "1.10.2",
- "resolved": "https://registry.npmjs.org/yaml/-/yaml-1.10.2.tgz",
- "integrity": "sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg==",
- "dev": true,
- "engines": {
- "node": ">= 6"
- }
- },
- "node_modules/yapool": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/yapool/-/yapool-1.0.0.tgz",
- "integrity": "sha1-9pPymjFbUNmp2iZGp6ZkXJaYW2o=",
- "dev": true
- },
- "node_modules/yargs": {
- "version": "15.4.1",
- "resolved": "https://registry.npmjs.org/yargs/-/yargs-15.4.1.tgz",
- "integrity": "sha512-aePbxDmcYW++PaqBsJ+HYUFwCdv4LVvdnhBy78E57PIor8/OVvhMrADFFEDh8DHDFRv/O9i3lPhsENjO7QX0+A==",
- "dev": true,
- "dependencies": {
- "cliui": "^6.0.0",
- "decamelize": "^1.2.0",
- "find-up": "^4.1.0",
- "get-caller-file": "^2.0.1",
- "require-directory": "^2.1.1",
- "require-main-filename": "^2.0.0",
- "set-blocking": "^2.0.0",
- "string-width": "^4.2.0",
- "which-module": "^2.0.0",
- "y18n": "^4.0.0",
- "yargs-parser": "^18.1.2"
- },
- "engines": {
- "node": ">=8"
- }
- },
- "node_modules/yargs-parser": {
- "version": "18.1.3",
- "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-18.1.3.tgz",
- "integrity": "sha512-o50j0JeToy/4K6OZcaQmW6lyXXKhq7csREXcDwk2omFPJEwUNOVtJKvmDr9EI1fAJZUyZcRF7kxGBWmRXudrCQ==",
- "dev": true,
- "dependencies": {
- "camelcase": "^5.0.0",
- "decamelize": "^1.2.0"
- },
- "engines": {
- "node": ">=6"
- }
- },
- "node_modules/yargs/node_modules/ansi-regex": {
- "version": "5.0.0",
- "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.0.tgz",
- "integrity": "sha512-bY6fj56OUQ0hU1KjFNDQuJFezqKdrAyFdIevADiqrWHwSlbmBNMHp5ak2f40Pm8JTFyM2mqxkG6ngkHO11f/lg==",
- "dev": true,
- "engines": {
- "node": ">=8"
- }
- },
- "node_modules/yargs/node_modules/ansi-styles": {
- "version": "4.3.0",
- "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
- "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
- "dev": true,
- "dependencies": {
- "color-convert": "^2.0.1"
- },
- "engines": {
- "node": ">=8"
- }
- },
- "node_modules/yargs/node_modules/cliui": {
- "version": "6.0.0",
- "resolved": "https://registry.npmjs.org/cliui/-/cliui-6.0.0.tgz",
- "integrity": "sha512-t6wbgtoCXvAzst7QgXxJYqPt0usEfbgQdftEPbLL/cvv6HPE5VgvqCuAIDR0NgU52ds6rFwqrgakNLrHEjCbrQ==",
- "dev": true,
- "dependencies": {
- "string-width": "^4.2.0",
- "strip-ansi": "^6.0.0",
- "wrap-ansi": "^6.2.0"
- }
- },
- "node_modules/yargs/node_modules/color-convert": {
- "version": "2.0.1",
- "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
- "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
- "dev": true,
- "dependencies": {
- "color-name": "~1.1.4"
- },
- "engines": {
- "node": ">=7.0.0"
- }
- },
- "node_modules/yargs/node_modules/color-name": {
- "version": "1.1.4",
- "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
- "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
- "dev": true
- },
- "node_modules/yargs/node_modules/is-fullwidth-code-point": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz",
- "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==",
- "dev": true,
- "engines": {
- "node": ">=8"
- }
- },
- "node_modules/yargs/node_modules/string-width": {
- "version": "4.2.2",
- "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.2.tgz",
- "integrity": "sha512-XBJbT3N4JhVumXE0eoLU9DCjcaF92KLNqTmFCnG1pf8duUxFGwtP6AD6nkjw9a3IdiRtL3E2w3JDiE/xi3vOeA==",
- "dev": true,
- "dependencies": {
- "emoji-regex": "^8.0.0",
- "is-fullwidth-code-point": "^3.0.0",
- "strip-ansi": "^6.0.0"
- },
- "engines": {
- "node": ">=8"
- }
- },
- "node_modules/yargs/node_modules/strip-ansi": {
- "version": "6.0.0",
- "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.0.tgz",
- "integrity": "sha512-AuvKTrTfQNYNIctbR1K/YGTR1756GycPsg7b9bdV9Duqur4gv6aKqHXah67Z8ImS7WEz5QVcOtlfW2rZEugt6w==",
- "dev": true,
- "dependencies": {
- "ansi-regex": "^5.0.0"
- },
- "engines": {
- "node": ">=8"
- }
- },
- "node_modules/yargs/node_modules/wrap-ansi": {
- "version": "6.2.0",
- "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-6.2.0.tgz",
- "integrity": "sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==",
- "dev": true,
- "dependencies": {
- "ansi-styles": "^4.0.0",
- "string-width": "^4.1.0",
- "strip-ansi": "^6.0.0"
- },
- "engines": {
- "node": ">=8"
- }
- }
- },
- "dependencies": {
- "@babel/code-frame": {
- "version": "7.14.5",
- "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.14.5.tgz",
- "integrity": "sha512-9pzDqyc6OLDaqe+zbACgFkb6fKMNG6CObKpnYXChRsvYGyEdc7CA2BaqeOM+vOtCS5ndmJicPJhKAwYRI6UfFw==",
- "dev": true,
- "requires": {
- "@babel/highlight": "^7.14.5"
- }
- },
- "@babel/compat-data": {
- "version": "7.14.7",
- "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.14.7.tgz",
- "integrity": "sha512-nS6dZaISCXJ3+518CWiBfEr//gHyMO02uDxBkXTKZDN5POruCnOZ1N4YBRZDCabwF8nZMWBpRxIicmXtBs+fvw==",
- "dev": true
- },
- "@babel/core": {
- "version": "7.14.8",
- "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.14.8.tgz",
- "integrity": "sha512-/AtaeEhT6ErpDhInbXmjHcUQXH0L0TEgscfcxk1qbOvLuKCa5aZT0SOOtDKFY96/CLROwbLSKyFor6idgNaU4Q==",
- "dev": true,
- "requires": {
- "@babel/code-frame": "^7.14.5",
- "@babel/generator": "^7.14.8",
- "@babel/helper-compilation-targets": "^7.14.5",
- "@babel/helper-module-transforms": "^7.14.8",
- "@babel/helpers": "^7.14.8",
- "@babel/parser": "^7.14.8",
- "@babel/template": "^7.14.5",
- "@babel/traverse": "^7.14.8",
- "@babel/types": "^7.14.8",
- "convert-source-map": "^1.7.0",
- "debug": "^4.1.0",
- "gensync": "^1.0.0-beta.2",
- "json5": "^2.1.2",
- "semver": "^6.3.0",
- "source-map": "^0.5.0"
- },
- "dependencies": {
- "debug": {
- "version": "4.3.2",
- "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.2.tgz",
- "integrity": "sha512-mOp8wKcvj7XxC78zLgw/ZA+6TSgkoE2C/ienthhRD298T7UNwAg9diBpLRxC0mOezLl4B0xV7M0cCO6P/O0Xhw==",
- "dev": true,
- "requires": {
- "ms": "2.1.2"
- }
- },
- "ms": {
- "version": "2.1.2",
- "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
- "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==",
- "dev": true
- }
- }
- },
- "@babel/generator": {
- "version": "7.14.8",
- "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.14.8.tgz",
- "integrity": "sha512-cYDUpvIzhBVnMzRoY1fkSEhK/HmwEVwlyULYgn/tMQYd6Obag3ylCjONle3gdErfXBW61SVTlR9QR7uWlgeIkg==",
- "dev": true,
- "requires": {
- "@babel/types": "^7.14.8",
- "jsesc": "^2.5.1",
- "source-map": "^0.5.0"
- }
- },
- "@babel/helper-compilation-targets": {
- "version": "7.14.5",
- "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.14.5.tgz",
- "integrity": "sha512-v+QtZqXEiOnpO6EYvlImB6zCD2Lel06RzOPzmkz/D/XgQiUu3C/Jb1LOqSt/AIA34TYi/Q+KlT8vTQrgdxkbLw==",
- "dev": true,
- "requires": {
- "@babel/compat-data": "^7.14.5",
- "@babel/helper-validator-option": "^7.14.5",
- "browserslist": "^4.16.6",
- "semver": "^6.3.0"
- }
- },
- "@babel/helper-function-name": {
- "version": "7.14.5",
- "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.14.5.tgz",
- "integrity": "sha512-Gjna0AsXWfFvrAuX+VKcN/aNNWonizBj39yGwUzVDVTlMYJMK2Wp6xdpy72mfArFq5uK+NOuexfzZlzI1z9+AQ==",
- "dev": true,
- "requires": {
- "@babel/helper-get-function-arity": "^7.14.5",
- "@babel/template": "^7.14.5",
- "@babel/types": "^7.14.5"
- }
- },
- "@babel/helper-get-function-arity": {
- "version": "7.14.5",
- "resolved": "https://registry.npmjs.org/@babel/helper-get-function-arity/-/helper-get-function-arity-7.14.5.tgz",
- "integrity": "sha512-I1Db4Shst5lewOM4V+ZKJzQ0JGGaZ6VY1jYvMghRjqs6DWgxLCIyFt30GlnKkfUeFLpJt2vzbMVEXVSXlIFYUg==",
- "dev": true,
- "requires": {
- "@babel/types": "^7.14.5"
- }
- },
- "@babel/helper-hoist-variables": {
- "version": "7.14.5",
- "resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.14.5.tgz",
- "integrity": "sha512-R1PXiz31Uc0Vxy4OEOm07x0oSjKAdPPCh3tPivn/Eo8cvz6gveAeuyUUPB21Hoiif0uoPQSSdhIPS3352nvdyQ==",
- "dev": true,
- "requires": {
- "@babel/types": "^7.14.5"
- }
- },
- "@babel/helper-member-expression-to-functions": {
- "version": "7.14.7",
- "resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.14.7.tgz",
- "integrity": "sha512-TMUt4xKxJn6ccjcOW7c4hlwyJArizskAhoSTOCkA0uZ+KghIaci0Qg9R043kUMWI9mtQfgny+NQ5QATnZ+paaA==",
- "dev": true,
- "requires": {
- "@babel/types": "^7.14.5"
- }
- },
- "@babel/helper-module-imports": {
- "version": "7.14.5",
- "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.14.5.tgz",
- "integrity": "sha512-SwrNHu5QWS84XlHwGYPDtCxcA0hrSlL2yhWYLgeOc0w7ccOl2qv4s/nARI0aYZW+bSwAL5CukeXA47B/1NKcnQ==",
- "dev": true,
- "requires": {
- "@babel/types": "^7.14.5"
- }
- },
- "@babel/helper-module-transforms": {
- "version": "7.14.8",
- "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.14.8.tgz",
- "integrity": "sha512-RyE+NFOjXn5A9YU1dkpeBaduagTlZ0+fccnIcAGbv1KGUlReBj7utF7oEth8IdIBQPcux0DDgW5MFBH2xu9KcA==",
- "dev": true,
- "requires": {
- "@babel/helper-module-imports": "^7.14.5",
- "@babel/helper-replace-supers": "^7.14.5",
- "@babel/helper-simple-access": "^7.14.8",
- "@babel/helper-split-export-declaration": "^7.14.5",
- "@babel/helper-validator-identifier": "^7.14.8",
- "@babel/template": "^7.14.5",
- "@babel/traverse": "^7.14.8",
- "@babel/types": "^7.14.8"
- }
- },
- "@babel/helper-optimise-call-expression": {
- "version": "7.14.5",
- "resolved": "https://registry.npmjs.org/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.14.5.tgz",
- "integrity": "sha512-IqiLIrODUOdnPU9/F8ib1Fx2ohlgDhxnIDU7OEVi+kAbEZcyiF7BLU8W6PfvPi9LzztjS7kcbzbmL7oG8kD6VA==",
- "dev": true,
- "requires": {
- "@babel/types": "^7.14.5"
- }
- },
- "@babel/helper-replace-supers": {
- "version": "7.14.5",
- "resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.14.5.tgz",
- "integrity": "sha512-3i1Qe9/8x/hCHINujn+iuHy+mMRLoc77b2nI9TB0zjH1hvn9qGlXjWlggdwUcju36PkPCy/lpM7LLUdcTyH4Ow==",
- "dev": true,
- "requires": {
- "@babel/helper-member-expression-to-functions": "^7.14.5",
- "@babel/helper-optimise-call-expression": "^7.14.5",
- "@babel/traverse": "^7.14.5",
- "@babel/types": "^7.14.5"
- }
- },
- "@babel/helper-simple-access": {
- "version": "7.14.8",
- "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.14.8.tgz",
- "integrity": "sha512-TrFN4RHh9gnWEU+s7JloIho2T76GPwRHhdzOWLqTrMnlas8T9O7ec+oEDNsRXndOmru9ymH9DFrEOxpzPoSbdg==",
- "dev": true,
- "requires": {
- "@babel/types": "^7.14.8"
- }
- },
- "@babel/helper-split-export-declaration": {
- "version": "7.14.5",
- "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.14.5.tgz",
- "integrity": "sha512-hprxVPu6e5Kdp2puZUmvOGjaLv9TCe58E/Fl6hRq4YiVQxIcNvuq6uTM2r1mT/oPskuS9CgR+I94sqAYv0NGKA==",
- "dev": true,
- "requires": {
- "@babel/types": "^7.14.5"
- }
- },
- "@babel/helper-validator-identifier": {
- "version": "7.14.8",
- "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.14.8.tgz",
- "integrity": "sha512-ZGy6/XQjllhYQrNw/3zfWRwZCTVSiBLZ9DHVZxn9n2gip/7ab8mv2TWlKPIBk26RwedCBoWdjLmn+t9na2Gcow==",
- "dev": true
- },
- "@babel/helper-validator-option": {
- "version": "7.14.5",
- "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.14.5.tgz",
- "integrity": "sha512-OX8D5eeX4XwcroVW45NMvoYaIuFI+GQpA2a8Gi+X/U/cDUIRsV37qQfF905F0htTRCREQIB4KqPeaveRJUl3Ow==",
- "dev": true
- },
- "@babel/helpers": {
- "version": "7.14.8",
- "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.14.8.tgz",
- "integrity": "sha512-ZRDmI56pnV+p1dH6d+UN6GINGz7Krps3+270qqI9UJ4wxYThfAIcI5i7j5vXC4FJ3Wap+S9qcebxeYiqn87DZw==",
- "dev": true,
- "requires": {
- "@babel/template": "^7.14.5",
- "@babel/traverse": "^7.14.8",
- "@babel/types": "^7.14.8"
- }
- },
- "@babel/highlight": {
- "version": "7.14.5",
- "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.14.5.tgz",
- "integrity": "sha512-qf9u2WFWVV0MppaL877j2dBtQIDgmidgjGk5VIMw3OadXvYaXn66U1BFlH2t4+t3i+8PhedppRv+i40ABzd+gg==",
- "dev": true,
- "requires": {
- "@babel/helper-validator-identifier": "^7.14.5",
- "chalk": "^2.0.0",
- "js-tokens": "^4.0.0"
- }
- },
- "@babel/parser": {
- "version": "7.14.8",
- "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.14.8.tgz",
- "integrity": "sha512-syoCQFOoo/fzkWDeM0dLEZi5xqurb5vuyzwIMNZRNun+N/9A4cUZeQaE7dTrB8jGaKuJRBtEOajtnmw0I5hvvA==",
- "dev": true
- },
- "@babel/runtime": {
- "version": "7.14.8",
- "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.14.8.tgz",
- "integrity": "sha512-twj3L8Og5SaCRCErB4x4ajbvBIVV77CGeFglHpeg5WC5FF8TZzBWXtTJ4MqaD9QszLYTtr+IsaAL2rEUevb+eg==",
- "requires": {
- "regenerator-runtime": "^0.13.4"
- }
- },
- "@babel/template": {
- "version": "7.14.5",
- "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.14.5.tgz",
- "integrity": "sha512-6Z3Po85sfxRGachLULUhOmvAaOo7xCvqGQtxINai2mEGPFm6pQ4z5QInFnUrRpfoSV60BnjyF5F3c+15fxFV1g==",
- "dev": true,
- "requires": {
- "@babel/code-frame": "^7.14.5",
- "@babel/parser": "^7.14.5",
- "@babel/types": "^7.14.5"
- }
- },
- "@babel/traverse": {
- "version": "7.14.8",
- "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.14.8.tgz",
- "integrity": "sha512-kexHhzCljJcFNn1KYAQ6A5wxMRzq9ebYpEDV4+WdNyr3i7O44tanbDOR/xjiG2F3sllan+LgwK+7OMk0EmydHg==",
- "dev": true,
- "requires": {
- "@babel/code-frame": "^7.14.5",
- "@babel/generator": "^7.14.8",
- "@babel/helper-function-name": "^7.14.5",
- "@babel/helper-hoist-variables": "^7.14.5",
- "@babel/helper-split-export-declaration": "^7.14.5",
- "@babel/parser": "^7.14.8",
- "@babel/types": "^7.14.8",
- "debug": "^4.1.0",
- "globals": "^11.1.0"
- },
- "dependencies": {
- "debug": {
- "version": "4.3.2",
- "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.2.tgz",
- "integrity": "sha512-mOp8wKcvj7XxC78zLgw/ZA+6TSgkoE2C/ienthhRD298T7UNwAg9diBpLRxC0mOezLl4B0xV7M0cCO6P/O0Xhw==",
- "dev": true,
- "requires": {
- "ms": "2.1.2"
- }
- },
- "ms": {
- "version": "2.1.2",
- "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
- "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==",
- "dev": true
- }
- }
- },
- "@babel/types": {
- "version": "7.14.8",
- "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.14.8.tgz",
- "integrity": "sha512-iob4soQa7dZw8nodR/KlOQkPh9S4I8RwCxwRIFuiMRYjOzH/KJzdUfDgz6cGi5dDaclXF4P2PAhCdrBJNIg68Q==",
- "dev": true,
- "requires": {
- "@babel/helper-validator-identifier": "^7.14.8",
- "to-fast-properties": "^2.0.0"
- }
- },
- "@istanbuljs/load-nyc-config": {
- "version": "1.1.0",
- "resolved": "https://registry.npmjs.org/@istanbuljs/load-nyc-config/-/load-nyc-config-1.1.0.tgz",
- "integrity": "sha512-VjeHSlIzpv/NyD3N0YuHfXOPDIixcA1q2ZV98wsMqcYlPmv2n3Yb2lYP9XMElnaFVXg5A7YLTeLu6V84uQDjmQ==",
- "dev": true,
- "requires": {
- "camelcase": "^5.3.1",
- "find-up": "^4.1.0",
- "get-package-type": "^0.1.0",
- "js-yaml": "^3.13.1",
- "resolve-from": "^5.0.0"
- }
- },
- "@istanbuljs/schema": {
- "version": "0.1.3",
- "resolved": "https://registry.npmjs.org/@istanbuljs/schema/-/schema-0.1.3.tgz",
- "integrity": "sha512-ZXRY4jNvVgSVQ8DL3LTcakaAtXwTVUxE81hslsyD2AtoXW/wVob10HkOJ1X/pAlcI7D+2YoZKg5do8G/w6RYgA==",
- "dev": true
- },
- "accepts": {
- "version": "1.3.8",
- "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz",
- "integrity": "sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==",
- "requires": {
- "mime-types": "~2.1.34",
- "negotiator": "0.6.3"
- }
- },
- "aggregate-error": {
- "version": "3.1.0",
- "resolved": "https://registry.npmjs.org/aggregate-error/-/aggregate-error-3.1.0.tgz",
- "integrity": "sha512-4I7Td01quW/RpocfNayFdFVk1qSuoh0E7JrbRJ16nH01HhKFQ88INq9Sd+nd72zqRySlr9BmDA8xlEJ6vJMrYA==",
- "dev": true,
- "requires": {
- "clean-stack": "^2.0.0",
- "indent-string": "^4.0.0"
- }
- },
- "ajv": {
- "version": "6.12.6",
- "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz",
- "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==",
- "dev": true,
- "requires": {
- "fast-deep-equal": "^3.1.1",
- "fast-json-stable-stringify": "^2.0.0",
- "json-schema-traverse": "^0.4.1",
- "uri-js": "^4.2.2"
- }
- },
- "ansi-regex": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz",
- "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=",
- "dev": true
- },
- "ansi-styles": {
- "version": "3.2.1",
- "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz",
- "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==",
- "dev": true,
- "requires": {
- "color-convert": "^1.9.0"
- }
- },
- "anymatch": {
- "version": "3.1.2",
- "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.2.tgz",
- "integrity": "sha512-P43ePfOAIupkguHUycrc4qJ9kz8ZiuOUijaETwX7THt0Y/GNK7v0aa8rY816xWjZ7rJdA5XdMcpVFTKMq+RvWg==",
- "dev": true,
- "requires": {
- "normalize-path": "^3.0.0",
- "picomatch": "^2.0.4"
- }
- },
- "append-transform": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/append-transform/-/append-transform-2.0.0.tgz",
- "integrity": "sha512-7yeyCEurROLQJFv5Xj4lEGTy0borxepjFv1g22oAdqFu//SrAlDl1O1Nxx15SH1RoliUml6p8dwJW9jvZughhg==",
- "dev": true,
- "requires": {
- "default-require-extensions": "^3.0.0"
- }
- },
- "archy": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/archy/-/archy-1.0.0.tgz",
- "integrity": "sha1-+cjBN1fMHde8N5rHeyxipcKGjEA=",
- "dev": true
- },
- "argparse": {
- "version": "1.0.10",
- "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz",
- "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==",
- "dev": true,
- "requires": {
- "sprintf-js": "~1.0.2"
- }
- },
- "array-flatten": {
- "version": "1.1.1",
- "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz",
- "integrity": "sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg=="
- },
- "asap": {
- "version": "2.0.6",
- "resolved": "https://registry.npmjs.org/asap/-/asap-2.0.6.tgz",
- "integrity": "sha512-BSHWgDSAiKs50o2Re8ppvp3seVHXSRM44cdSsT9FfNEUUZLOGWVCsiWaRPWM1Znn+mqZ1OfVZ3z3DWEzSp7hRA=="
- },
- "asn1": {
- "version": "0.2.4",
- "resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.4.tgz",
- "integrity": "sha512-jxwzQpLQjSmWXgwaCZE9Nz+glAG01yF1QnWgbhGwHI5A6FRIEY6IVqtHhIepHqI7/kyEyQEagBC5mBEFlIYvdg==",
- "dev": true,
- "requires": {
- "safer-buffer": "~2.1.0"
- }
- },
- "assert-plus": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz",
- "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=",
- "dev": true
- },
- "async-hook-domain": {
- "version": "2.0.3",
- "resolved": "https://registry.npmjs.org/async-hook-domain/-/async-hook-domain-2.0.3.tgz",
- "integrity": "sha512-MadiLLDEZRZzZwcm0dgS+K99qXZ4H2saAUwUgwzFulbAkXrKi3AX5FvWS3FFTQtLMwrqcGqAJe6o12KrObejQA==",
- "dev": true
- },
- "asynckit": {
- "version": "0.4.0",
- "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz",
- "integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k="
- },
- "aws-sign2": {
- "version": "0.7.0",
- "resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.7.0.tgz",
- "integrity": "sha1-tG6JCTSpWR8tL2+G1+ap8bP+dqg=",
- "dev": true
- },
- "aws4": {
- "version": "1.11.0",
- "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.11.0.tgz",
- "integrity": "sha512-xh1Rl34h6Fi1DC2WWKfxUTVqRsNnr6LsKz2+hfwDxQJWmrx8+c7ylaqBMcHfl1U1r2dsifOvKX3LQuLNZ+XSvA==",
- "dev": true
- },
- "balanced-match": {
- "version": "1.0.2",
- "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz",
- "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw=="
- },
- "bcrypt-pbkdf": {
- "version": "1.0.2",
- "resolved": "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz",
- "integrity": "sha1-pDAdOJtqQ/m2f/PKEaP2Y342Dp4=",
- "dev": true,
- "requires": {
- "tweetnacl": "^0.14.3"
- }
- },
- "binary-extensions": {
- "version": "2.2.0",
- "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz",
- "integrity": "sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==",
- "dev": true
- },
- "bind-obj-methods": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/bind-obj-methods/-/bind-obj-methods-3.0.0.tgz",
- "integrity": "sha512-nLEaaz3/sEzNSyPWRsN9HNsqwk1AUyECtGj+XwGdIi3xABnEqecvXtIJ0wehQXuuER5uZ/5fTs2usONgYjG+iw==",
- "dev": true
- },
- "body-parser": {
- "version": "1.20.1",
- "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.1.tgz",
- "integrity": "sha512-jWi7abTbYwajOytWCQc37VulmWiRae5RyTpaCyDcS5/lMdtwSz5lOpDE67srw/HYe35f1z3fDQw+3txg7gNtWw==",
- "requires": {
- "bytes": "3.1.2",
- "content-type": "~1.0.4",
- "debug": "2.6.9",
- "depd": "2.0.0",
- "destroy": "1.2.0",
- "http-errors": "2.0.0",
- "iconv-lite": "0.4.24",
- "on-finished": "2.4.1",
- "qs": "6.11.0",
- "raw-body": "2.5.1",
- "type-is": "~1.6.18",
- "unpipe": "1.0.0"
- }
- },
- "brace-expansion": {
- "version": "1.1.11",
- "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz",
- "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==",
- "dev": true,
- "requires": {
- "balanced-match": "^1.0.0",
- "concat-map": "0.0.1"
- }
- },
- "braces": {
- "version": "3.0.2",
- "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz",
- "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==",
- "dev": true,
- "requires": {
- "fill-range": "^7.0.1"
- }
- },
- "browserslist": {
- "version": "4.16.6",
- "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.16.6.tgz",
- "integrity": "sha512-Wspk/PqO+4W9qp5iUTJsa1B/QrYn1keNCcEP5OvP7WBwT4KaDly0uONYmC6Xa3Z5IqnUgS0KcgLYu1l74x0ZXQ==",
- "dev": true,
- "requires": {
- "caniuse-lite": "^1.0.30001219",
- "colorette": "^1.2.2",
- "electron-to-chromium": "^1.3.723",
- "escalade": "^3.1.1",
- "node-releases": "^1.1.71"
- }
- },
- "buffer-from": {
- "version": "1.1.1",
- "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.1.tgz",
- "integrity": "sha512-MQcXEUbCKtEo7bhqEs6560Hyd4XaovZlO/k9V3hjVUF/zwW7KBVdSK4gIt/bzwS9MbR5qob+F5jusZsb0YQK2A==",
- "dev": true
- },
- "bytes": {
- "version": "3.1.2",
- "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz",
- "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg=="
- },
- "caching-transform": {
- "version": "4.0.0",
- "resolved": "https://registry.npmjs.org/caching-transform/-/caching-transform-4.0.0.tgz",
- "integrity": "sha512-kpqOvwXnjjN44D89K5ccQC+RUrsy7jB/XLlRrx0D7/2HNcTPqzsb6XgYoErwko6QsV184CA2YgS1fxDiiDZMWA==",
- "dev": true,
- "requires": {
- "hasha": "^5.0.0",
- "make-dir": "^3.0.0",
- "package-hash": "^4.0.0",
- "write-file-atomic": "^3.0.0"
- }
- },
- "call-bind": {
- "version": "1.0.2",
- "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.2.tgz",
- "integrity": "sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==",
- "requires": {
- "function-bind": "^1.1.1",
- "get-intrinsic": "^1.0.2"
- }
- },
- "camelcase": {
- "version": "5.3.1",
- "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz",
- "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==",
- "dev": true
- },
- "caniuse-lite": {
- "version": "1.0.30001245",
- "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001245.tgz",
- "integrity": "sha512-768fM9j1PKXpOCKws6eTo3RHmvTUsG9UrpT4WoREFeZgJBTi4/X9g565azS/rVUGtqb8nt7FjLeF5u4kukERnA==",
- "dev": true
- },
- "caseless": {
- "version": "0.12.0",
- "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz",
- "integrity": "sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw=",
- "dev": true
- },
- "chalk": {
- "version": "2.4.2",
- "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz",
- "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==",
- "dev": true,
- "requires": {
- "ansi-styles": "^3.2.1",
- "escape-string-regexp": "^1.0.5",
- "supports-color": "^5.3.0"
- },
- "dependencies": {
- "escape-string-regexp": {
- "version": "1.0.5",
- "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz",
- "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=",
- "dev": true
- }
- }
- },
- "chokidar": {
- "version": "3.5.2",
- "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.2.tgz",
- "integrity": "sha512-ekGhOnNVPgT77r4K/U3GDhu+FQ2S8TnK/s2KbIGXi0SZWuwkZ2QNyfWdZW+TVfn84DpEP7rLeCt2UI6bJ8GwbQ==",
- "dev": true,
- "requires": {
- "anymatch": "~3.1.2",
- "braces": "~3.0.2",
- "fsevents": "~2.3.2",
- "glob-parent": "~5.1.2",
- "is-binary-path": "~2.1.0",
- "is-glob": "~4.0.1",
- "normalize-path": "~3.0.0",
- "readdirp": "~3.6.0"
- }
- },
- "clean-stack": {
- "version": "2.2.0",
- "resolved": "https://registry.npmjs.org/clean-stack/-/clean-stack-2.2.0.tgz",
- "integrity": "sha512-4diC9HaTE+KRAMWhDhrGOECgWZxoevMc5TlkObMqNSsVU62PYzXZ/SMTjzyGAFF1YusgxGcSWTEXBhp0CPwQ1A==",
- "dev": true
- },
- "cliui": {
- "version": "4.1.0",
- "resolved": "https://registry.npmjs.org/cliui/-/cliui-4.1.0.tgz",
- "integrity": "sha512-4FG+RSG9DL7uEwRUZXZn3SS34DiDPfzP0VOiEwtUWlE+AR2EIg+hSyvrIgUUfhdgR/UkAeW2QHgeP+hWrXs7jQ==",
- "dev": true,
- "requires": {
- "string-width": "^2.1.1",
- "strip-ansi": "^4.0.0",
- "wrap-ansi": "^2.0.0"
- }
- },
- "code-point-at": {
- "version": "1.1.0",
- "resolved": "https://registry.npmjs.org/code-point-at/-/code-point-at-1.1.0.tgz",
- "integrity": "sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c=",
- "dev": true
- },
- "color-convert": {
- "version": "1.9.3",
- "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz",
- "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==",
- "dev": true,
- "requires": {
- "color-name": "1.1.3"
- }
- },
- "color-name": {
- "version": "1.1.3",
- "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz",
- "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=",
- "dev": true
- },
- "color-support": {
- "version": "1.1.3",
- "resolved": "https://registry.npmjs.org/color-support/-/color-support-1.1.3.tgz",
- "integrity": "sha512-qiBjkpbMLO/HL68y+lh4q0/O1MZFj2RX6X/KmMa3+gJD3z+WwI1ZzDHysvqHGS3mP6mznPckpXmw1nI9cJjyRg==",
- "dev": true
- },
- "colorette": {
- "version": "1.2.2",
- "resolved": "https://registry.npmjs.org/colorette/-/colorette-1.2.2.tgz",
- "integrity": "sha512-MKGMzyfeuutC/ZJ1cba9NqcNpfeqMUcYmyF1ZFY6/Cn7CNSAKx6a+s48sqLqyAiZuaP2TcqMhoo+dlwFnVxT9w==",
- "dev": true
- },
- "combined-stream": {
- "version": "1.0.8",
- "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz",
- "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==",
- "requires": {
- "delayed-stream": "~1.0.0"
- }
- },
- "commondir": {
- "version": "1.0.1",
- "resolved": "https://registry.npmjs.org/commondir/-/commondir-1.0.1.tgz",
- "integrity": "sha1-3dgA2gxmEnOTzKWVDqloo6rxJTs=",
- "dev": true
- },
- "complex.js": {
- "version": "2.0.15",
- "resolved": "https://registry.npmjs.org/complex.js/-/complex.js-2.0.15.tgz",
- "integrity": "sha512-gDBvQU8IG139ZBQTSo2qvDFP+lANMGluM779csXOr6ny1NUtA3wkUnCFjlDNH/moAVfXtvClYt6G0zarFbtz5w=="
- },
- "component-emitter": {
- "version": "1.3.0",
- "resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.3.0.tgz",
- "integrity": "sha512-Rd3se6QB+sO1TwqZjscQrurpEPIfO0/yYnSin6Q/rD3mOutHvUrCAhJub3r90uNb+SESBuE0QYoB90YdfatsRg=="
- },
- "concat-map": {
- "version": "0.0.1",
- "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
- "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=",
- "dev": true
- },
- "content-disposition": {
- "version": "0.5.4",
- "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.4.tgz",
- "integrity": "sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ==",
- "requires": {
- "safe-buffer": "5.2.1"
- },
- "dependencies": {
- "safe-buffer": {
- "version": "5.2.1",
- "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz",
- "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ=="
- }
- }
- },
- "content-type": {
- "version": "1.0.5",
- "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.5.tgz",
- "integrity": "sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA=="
- },
- "convert-source-map": {
- "version": "1.8.0",
- "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.8.0.tgz",
- "integrity": "sha512-+OQdjP49zViI/6i7nIJpA8rAl4sV/JdPfU9nZs3VqOwGIgizICvuN2ru6fMd+4llL0tar18UYJXfZ/TWtmhUjA==",
- "dev": true,
- "requires": {
- "safe-buffer": "~5.1.1"
- }
- },
- "cookie": {
- "version": "0.5.0",
- "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.5.0.tgz",
- "integrity": "sha512-YZ3GUyn/o8gfKJlnlX7g7xq4gyO6OSuhGPKaaGssGB2qgDUS0gPgtTvoyZLTt9Ab6dC4hfc9dV5arkvc/OCmrw=="
- },
- "cookie-signature": {
- "version": "1.0.6",
- "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz",
- "integrity": "sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ=="
- },
- "cookiejar": {
- "version": "2.1.4",
- "resolved": "https://registry.npmjs.org/cookiejar/-/cookiejar-2.1.4.tgz",
- "integrity": "sha512-LDx6oHrK+PhzLKJU9j5S7/Y3jM/mUHvD/DeI1WQmJn652iPC5Y4TBzC9l+5OMOXlyTTA+SmVUPm0HQUwpD5Jqw=="
- },
- "core-util-is": {
- "version": "1.0.2",
- "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz",
- "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=",
- "dev": true
- },
- "coveralls": {
- "version": "3.1.1",
- "resolved": "https://registry.npmjs.org/coveralls/-/coveralls-3.1.1.tgz",
- "integrity": "sha512-+dxnG2NHncSD1NrqbSM3dn/lE57O6Qf/koe9+I7c+wzkqRmEvcp0kgJdxKInzYzkICKkFMZsX3Vct3++tsF9ww==",
- "dev": true,
- "requires": {
- "js-yaml": "^3.13.1",
- "lcov-parse": "^1.0.0",
- "log-driver": "^1.2.7",
- "minimist": "^1.2.5",
- "request": "^2.88.2"
- }
- },
- "cross-spawn": {
- "version": "7.0.3",
- "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz",
- "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==",
- "dev": true,
- "requires": {
- "path-key": "^3.1.0",
- "shebang-command": "^2.0.0",
- "which": "^2.0.1"
- }
- },
- "dashdash": {
- "version": "1.14.1",
- "resolved": "https://registry.npmjs.org/dashdash/-/dashdash-1.14.1.tgz",
- "integrity": "sha1-hTz6D3y+L+1d4gMmuN1YEDX24vA=",
- "dev": true,
- "requires": {
- "assert-plus": "^1.0.0"
- }
- },
- "debug": {
- "version": "2.6.9",
- "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
- "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
- "requires": {
- "ms": "2.0.0"
- }
- },
- "decamelize": {
- "version": "1.2.0",
- "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz",
- "integrity": "sha1-9lNNFRSCabIDUue+4m9QH5oZEpA=",
- "dev": true
- },
- "decimal.js": {
- "version": "10.3.1",
- "resolved": "https://registry.npmjs.org/decimal.js/-/decimal.js-10.3.1.tgz",
- "integrity": "sha512-V0pfhfr8suzyPGOx3nmq4aHqabehUZn6Ch9kyFpV79TGDTWFmHqUqXdabR7QHqxzrYolF4+tVmJhUG4OURg5dQ=="
- },
- "default-require-extensions": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/default-require-extensions/-/default-require-extensions-3.0.0.tgz",
- "integrity": "sha512-ek6DpXq/SCpvjhpFsLFRVtIxJCRw6fUR42lYMVZuUMK7n8eMz4Uh5clckdBjEpLhn/gEBZo7hDJnJcwdKLKQjg==",
- "dev": true,
- "requires": {
- "strip-bom": "^4.0.0"
- }
- },
- "delayed-stream": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz",
- "integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk="
- },
- "depd": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz",
- "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw=="
- },
- "destroy": {
- "version": "1.2.0",
- "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.2.0.tgz",
- "integrity": "sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg=="
- },
- "dezalgo": {
- "version": "1.0.4",
- "resolved": "https://registry.npmjs.org/dezalgo/-/dezalgo-1.0.4.tgz",
- "integrity": "sha512-rXSP0bf+5n0Qonsb+SVVfNfIsimO4HEtmnIpPHY8Q1UCzKlQrDMfdobr8nJOOsRgWCyMRqeSBQzmWUMq7zvVig==",
- "requires": {
- "asap": "^2.0.0",
- "wrappy": "1"
- }
- },
- "diff": {
- "version": "4.0.2",
- "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz",
- "integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==",
- "dev": true
- },
- "ecc-jsbn": {
- "version": "0.1.2",
- "resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz",
- "integrity": "sha1-OoOpBOVDUyh4dMVkt1SThoSamMk=",
- "dev": true,
- "requires": {
- "jsbn": "~0.1.0",
- "safer-buffer": "^2.1.0"
- }
- },
- "ee-first": {
- "version": "1.1.1",
- "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz",
- "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow=="
- },
- "electron-to-chromium": {
- "version": "1.3.780",
- "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.780.tgz",
- "integrity": "sha512-2KQ9OYm9WMUNpAPA/4aerURl3hwRc9tNlpsiEj3Y8Gf7LVf26NzyLIX2v0hSagQwrS9+cWab+28A2GPKDoVNRA==",
- "dev": true
- },
- "emoji-regex": {
- "version": "8.0.0",
- "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz",
- "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==",
- "dev": true
- },
- "encodeurl": {
- "version": "1.0.2",
- "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz",
- "integrity": "sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w=="
- },
- "es6-error": {
- "version": "4.1.1",
- "resolved": "https://registry.npmjs.org/es6-error/-/es6-error-4.1.1.tgz",
- "integrity": "sha512-Um/+FxMr9CISWh0bi5Zv0iOD+4cFh5qLeks1qhAopKVAJw3drgKbKySikp7wGhDL0HPeaja0P5ULZrxLkniUVg==",
- "dev": true
- },
- "escalade": {
- "version": "3.1.1",
- "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz",
- "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==",
- "dev": true
- },
- "escape-html": {
- "version": "1.0.3",
- "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz",
- "integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow=="
- },
- "escape-latex": {
- "version": "1.2.0",
- "resolved": "https://registry.npmjs.org/escape-latex/-/escape-latex-1.2.0.tgz",
- "integrity": "sha512-nV5aVWW1K0wEiUIEdZ4erkGGH8mDxGyxSeqPzRNtWP7ataw+/olFObw7hujFWlVjNsaDFw5VZ5NzVSIqRgfTiw=="
- },
- "escape-string-regexp": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-2.0.0.tgz",
- "integrity": "sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w==",
- "dev": true
- },
- "esprima": {
- "version": "4.0.1",
- "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz",
- "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==",
- "dev": true
- },
- "etag": {
- "version": "1.8.1",
- "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz",
- "integrity": "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg=="
- },
- "events-to-array": {
- "version": "1.1.2",
- "resolved": "https://registry.npmjs.org/events-to-array/-/events-to-array-1.1.2.tgz",
- "integrity": "sha1-LUH1Y+H+QA7Uli/hpNXGp1Od9/Y=",
- "dev": true
- },
- "express": {
- "version": "4.18.2",
- "resolved": "https://registry.npmjs.org/express/-/express-4.18.2.tgz",
- "integrity": "sha512-5/PsL6iGPdfQ/lKM1UuielYgv3BUoJfz1aUwU9vHZ+J7gyvwdQXFEBIEIaxeGf0GIcreATNyBExtalisDbuMqQ==",
- "requires": {
- "accepts": "~1.3.8",
- "array-flatten": "1.1.1",
- "body-parser": "1.20.1",
- "content-disposition": "0.5.4",
- "content-type": "~1.0.4",
- "cookie": "0.5.0",
- "cookie-signature": "1.0.6",
- "debug": "2.6.9",
- "depd": "2.0.0",
- "encodeurl": "~1.0.2",
- "escape-html": "~1.0.3",
- "etag": "~1.8.1",
- "finalhandler": "1.2.0",
- "fresh": "0.5.2",
- "http-errors": "2.0.0",
- "merge-descriptors": "1.0.1",
- "methods": "~1.1.2",
- "on-finished": "2.4.1",
- "parseurl": "~1.3.3",
- "path-to-regexp": "0.1.7",
- "proxy-addr": "~2.0.7",
- "qs": "6.11.0",
- "range-parser": "~1.2.1",
- "safe-buffer": "5.2.1",
- "send": "0.18.0",
- "serve-static": "1.15.0",
- "setprototypeof": "1.2.0",
- "statuses": "2.0.1",
- "type-is": "~1.6.18",
- "utils-merge": "1.0.1",
- "vary": "~1.1.2"
- },
- "dependencies": {
- "safe-buffer": {
- "version": "5.2.1",
- "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz",
- "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ=="
- }
- }
- },
- "extend": {
- "version": "3.0.2",
- "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz",
- "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==",
- "dev": true
- },
- "extsprintf": {
- "version": "1.3.0",
- "resolved": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.3.0.tgz",
- "integrity": "sha1-lpGEQOMEGnpBT4xS48V06zw+HgU=",
- "dev": true
- },
- "fast-deep-equal": {
- "version": "3.1.3",
- "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz",
- "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==",
- "dev": true
- },
- "fast-json-stable-stringify": {
- "version": "2.1.0",
- "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz",
- "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==",
- "dev": true
- },
- "fast-safe-stringify": {
- "version": "2.1.1",
- "resolved": "https://registry.npmjs.org/fast-safe-stringify/-/fast-safe-stringify-2.1.1.tgz",
- "integrity": "sha512-W+KJc2dmILlPplD/H4K9l9LcAHAfPtP6BY84uVLXQ6Evcz9Lcg33Y2z1IVblT6xdY54PXYVHEv+0Wpq8Io6zkA=="
- },
- "fill-range": {
- "version": "7.0.1",
- "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz",
- "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==",
- "dev": true,
- "requires": {
- "to-regex-range": "^5.0.1"
- }
- },
- "finalhandler": {
- "version": "1.2.0",
- "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.2.0.tgz",
- "integrity": "sha512-5uXcUVftlQMFnWC9qu/svkWv3GTd2PfUhK/3PLkYNAe7FbqJMt3515HaxE6eRL74GdsriiwujiawdaB1BpEISg==",
- "requires": {
- "debug": "2.6.9",
- "encodeurl": "~1.0.2",
- "escape-html": "~1.0.3",
- "on-finished": "2.4.1",
- "parseurl": "~1.3.3",
- "statuses": "2.0.1",
- "unpipe": "~1.0.0"
- }
- },
- "find-cache-dir": {
- "version": "3.3.1",
- "resolved": "https://registry.npmjs.org/find-cache-dir/-/find-cache-dir-3.3.1.tgz",
- "integrity": "sha512-t2GDMt3oGC/v+BMwzmllWDuJF/xcDtE5j/fCGbqDD7OLuJkj0cfh1YSA5VKPvwMeLFLNDBkwOKZ2X85jGLVftQ==",
- "dev": true,
- "requires": {
- "commondir": "^1.0.1",
- "make-dir": "^3.0.2",
- "pkg-dir": "^4.1.0"
- }
- },
- "find-up": {
- "version": "4.1.0",
- "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz",
- "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==",
- "dev": true,
- "requires": {
- "locate-path": "^5.0.0",
- "path-exists": "^4.0.0"
- }
- },
- "findit": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/findit/-/findit-2.0.0.tgz",
- "integrity": "sha1-ZQnwEmr0wXhVHPqZOU4DLhOk1W4=",
- "dev": true
- },
- "foreground-child": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-2.0.0.tgz",
- "integrity": "sha512-dCIq9FpEcyQyXKCkyzmlPTFNgrCzPudOe+mhvJU5zAtlBnGVy2yKxtfsxK2tQBThwq225jcvBjpw1Gr40uzZCA==",
- "dev": true,
- "requires": {
- "cross-spawn": "^7.0.0",
- "signal-exit": "^3.0.2"
- }
- },
- "forever-agent": {
- "version": "0.6.1",
- "resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz",
- "integrity": "sha1-+8cfDEGt6zf5bFd60e1C2P2sypE=",
- "dev": true
- },
- "form-data": {
- "version": "4.0.0",
- "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz",
- "integrity": "sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==",
- "requires": {
- "asynckit": "^0.4.0",
- "combined-stream": "^1.0.8",
- "mime-types": "^2.1.12"
- }
- },
- "formidable": {
- "version": "2.1.2",
- "resolved": "https://registry.npmjs.org/formidable/-/formidable-2.1.2.tgz",
- "integrity": "sha512-CM3GuJ57US06mlpQ47YcunuUZ9jpm8Vx+P2CGt2j7HpgkKZO/DJYQ0Bobim8G6PFQmK5lOqOOdUXboU+h73A4g==",
- "requires": {
- "dezalgo": "^1.0.4",
- "hexoid": "^1.0.0",
- "once": "^1.4.0",
- "qs": "^6.11.0"
- }
- },
- "forwarded": {
- "version": "0.2.0",
- "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz",
- "integrity": "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow=="
- },
- "fraction.js": {
- "version": "4.1.1",
- "resolved": "https://registry.npmjs.org/fraction.js/-/fraction.js-4.1.1.tgz",
- "integrity": "sha512-MHOhvvxHTfRFpF1geTK9czMIZ6xclsEor2wkIGYYq+PxcQqT7vStJqjhe6S1TenZrMZzo+wlqOufBDVepUEgPg=="
- },
- "fresh": {
- "version": "0.5.2",
- "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz",
- "integrity": "sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q=="
- },
- "fromentries": {
- "version": "1.3.2",
- "resolved": "https://registry.npmjs.org/fromentries/-/fromentries-1.3.2.tgz",
- "integrity": "sha512-cHEpEQHUg0f8XdtZCc2ZAhrHzKzT0MrFUTcvx+hfxYu7rGMDc5SKoXFh+n4YigxsHXRzc6OrCshdR1bWH6HHyg==",
- "dev": true
- },
- "fs-exists-cached": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/fs-exists-cached/-/fs-exists-cached-1.0.0.tgz",
- "integrity": "sha1-zyVVTKBQ3EmuZla0HeQiWJidy84=",
- "dev": true
- },
- "fs.realpath": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz",
- "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8="
- },
- "fsevents": {
- "version": "2.3.2",
- "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz",
- "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==",
- "dev": true,
- "optional": true
- },
- "function-bind": {
- "version": "1.1.1",
- "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz",
- "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A=="
- },
- "function-loop": {
- "version": "2.0.1",
- "resolved": "https://registry.npmjs.org/function-loop/-/function-loop-2.0.1.tgz",
- "integrity": "sha512-ktIR+O6i/4h+j/ZhZJNdzeI4i9lEPeEK6UPR2EVyTVBqOwcU3Za9xYKLH64ZR9HmcROyRrOkizNyjjtWJzDDkQ==",
- "dev": true
- },
- "gensync": {
- "version": "1.0.0-beta.2",
- "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz",
- "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==",
- "dev": true
- },
- "get-caller-file": {
- "version": "2.0.5",
- "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz",
- "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==",
- "dev": true
- },
- "get-intrinsic": {
- "version": "1.2.0",
- "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.0.tgz",
- "integrity": "sha512-L049y6nFOuom5wGyRc3/gdTLO94dySVKRACj1RmJZBQXlbTMhtNIgkWkUHq+jYmZvKf14EW1EoJnnjbmoHij0Q==",
- "requires": {
- "function-bind": "^1.1.1",
- "has": "^1.0.3",
- "has-symbols": "^1.0.3"
- }
- },
- "get-package-type": {
- "version": "0.1.0",
- "resolved": "https://registry.npmjs.org/get-package-type/-/get-package-type-0.1.0.tgz",
- "integrity": "sha512-pjzuKtY64GYfWizNAJ0fr9VqttZkNiK2iS430LtIHzjBEr6bX8Am2zm4sW4Ro5wjWW5cAlRL1qAMTcXbjNAO2Q==",
- "dev": true
- },
- "getpass": {
- "version": "0.1.7",
- "resolved": "https://registry.npmjs.org/getpass/-/getpass-0.1.7.tgz",
- "integrity": "sha1-Xv+OPmhNVprkyysSgmBOi6YhSfo=",
- "dev": true,
- "requires": {
- "assert-plus": "^1.0.0"
- }
- },
- "glob": {
- "version": "7.1.7",
- "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.7.tgz",
- "integrity": "sha512-OvD9ENzPLbegENnYP5UUfJIirTg4+XwMWGaQfQTY0JenxNvvIKP3U3/tAQSPIu/lHxXYSZmpXlUHeqAIdKzBLQ==",
- "dev": true,
- "requires": {
- "fs.realpath": "^1.0.0",
- "inflight": "^1.0.4",
- "inherits": "2",
- "minimatch": "^3.0.4",
- "once": "^1.3.0",
- "path-is-absolute": "^1.0.0"
- }
- },
- "glob-parent": {
- "version": "5.1.2",
- "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz",
- "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==",
- "dev": true,
- "requires": {
- "is-glob": "^4.0.1"
- }
- },
- "globals": {
- "version": "11.12.0",
- "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz",
- "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==",
- "dev": true
- },
- "graceful-fs": {
- "version": "4.2.6",
- "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.6.tgz",
- "integrity": "sha512-nTnJ528pbqxYanhpDYsi4Rd8MAeaBA67+RZ10CM1m3bTAVFEDcd5AuA4a6W5YkGZ1iNXHzZz8T6TBKLeBuNriQ==",
- "dev": true
- },
- "har-schema": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/har-schema/-/har-schema-2.0.0.tgz",
- "integrity": "sha1-qUwiJOvKwEeCoNkDVSHyRzW37JI=",
- "dev": true
- },
- "har-validator": {
- "version": "5.1.5",
- "resolved": "https://registry.npmjs.org/har-validator/-/har-validator-5.1.5.tgz",
- "integrity": "sha512-nmT2T0lljbxdQZfspsno9hgrG3Uir6Ks5afism62poxqBM6sDnMEuPmzTq8XN0OEwqKLLdh1jQI3qyE66Nzb3w==",
- "dev": true,
- "requires": {
- "ajv": "^6.12.3",
- "har-schema": "^2.0.0"
- }
- },
- "has": {
- "version": "1.0.3",
- "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz",
- "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==",
- "requires": {
- "function-bind": "^1.1.1"
- }
- },
- "has-flag": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz",
- "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=",
- "dev": true
- },
- "has-symbols": {
- "version": "1.0.3",
- "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz",
- "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A=="
- },
- "hasha": {
- "version": "5.2.2",
- "resolved": "https://registry.npmjs.org/hasha/-/hasha-5.2.2.tgz",
- "integrity": "sha512-Hrp5vIK/xr5SkeN2onO32H0MgNZ0f17HRNH39WfL0SYUNOTZ5Lz1TJ8Pajo/87dYGEFlLMm7mIc/k/s6Bvz9HQ==",
- "dev": true,
- "requires": {
- "is-stream": "^2.0.0",
- "type-fest": "^0.8.0"
- }
- },
- "hexoid": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/hexoid/-/hexoid-1.0.0.tgz",
- "integrity": "sha512-QFLV0taWQOZtvIRIAdBChesmogZrtuXvVWsFHZTk2SU+anspqZ2vMnoLg7IE1+Uk16N19APic1BuF8bC8c2m5g=="
- },
- "html-escaper": {
- "version": "2.0.2",
- "resolved": "https://registry.npmjs.org/html-escaper/-/html-escaper-2.0.2.tgz",
- "integrity": "sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==",
- "dev": true
- },
- "http-errors": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz",
- "integrity": "sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==",
- "requires": {
- "depd": "2.0.0",
- "inherits": "2.0.4",
- "setprototypeof": "1.2.0",
- "statuses": "2.0.1",
- "toidentifier": "1.0.1"
- }
- },
- "http-signature": {
- "version": "1.2.0",
- "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.2.0.tgz",
- "integrity": "sha1-muzZJRFHcvPZW2WmCruPfBj7rOE=",
- "dev": true,
- "requires": {
- "assert-plus": "^1.0.0",
- "jsprim": "^1.2.2",
- "sshpk": "^1.7.0"
- }
- },
- "iconv-lite": {
- "version": "0.4.24",
- "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz",
- "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==",
- "requires": {
- "safer-buffer": ">= 2.1.2 < 3"
- }
- },
- "imurmurhash": {
- "version": "0.1.4",
- "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz",
- "integrity": "sha1-khi5srkoojixPcT7a21XbyMUU+o=",
- "dev": true
- },
- "indent-string": {
- "version": "4.0.0",
- "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-4.0.0.tgz",
- "integrity": "sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==",
- "dev": true
- },
- "inflight": {
- "version": "1.0.6",
- "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz",
- "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=",
- "dev": true,
- "requires": {
- "once": "^1.3.0",
- "wrappy": "1"
- }
- },
- "inherits": {
- "version": "2.0.4",
- "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz",
- "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ=="
- },
- "ipaddr.js": {
- "version": "1.9.1",
- "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz",
- "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g=="
- },
- "is-binary-path": {
- "version": "2.1.0",
- "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz",
- "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==",
- "dev": true,
- "requires": {
- "binary-extensions": "^2.0.0"
- }
- },
- "is-extglob": {
- "version": "2.1.1",
- "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz",
- "integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=",
- "dev": true
- },
- "is-fullwidth-code-point": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz",
- "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=",
- "dev": true
- },
- "is-glob": {
- "version": "4.0.1",
- "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.1.tgz",
- "integrity": "sha512-5G0tKtBTFImOqDnLB2hG6Bp2qcKEFduo4tZu9MT/H6NQv/ghhy30o55ufafxJ/LdH79LLs2Kfrn85TLKyA7BUg==",
- "dev": true,
- "requires": {
- "is-extglob": "^2.1.1"
- }
- },
- "is-number": {
- "version": "7.0.0",
- "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz",
- "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==",
- "dev": true
- },
- "is-stream": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.0.tgz",
- "integrity": "sha512-XCoy+WlUr7d1+Z8GgSuXmpuUFC9fOhRXglJMx+dwLKTkL44Cjd4W1Z5P+BQZpr+cR93aGP4S/s7Ftw6Nd/kiEw==",
- "dev": true
- },
- "is-typedarray": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz",
- "integrity": "sha1-5HnICFjfDBsR3dppQPlgEfzaSpo=",
- "dev": true
- },
- "is-windows": {
- "version": "1.0.2",
- "resolved": "https://registry.npmjs.org/is-windows/-/is-windows-1.0.2.tgz",
- "integrity": "sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA==",
- "dev": true
- },
- "isexe": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz",
- "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=",
- "dev": true
- },
- "isstream": {
- "version": "0.1.2",
- "resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz",
- "integrity": "sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo=",
- "dev": true
- },
- "istanbul-lib-coverage": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-3.0.0.tgz",
- "integrity": "sha512-UiUIqxMgRDET6eR+o5HbfRYP1l0hqkWOs7vNxC/mggutCMUIhWMm8gAHb8tHlyfD3/l6rlgNA5cKdDzEAf6hEg==",
- "dev": true
- },
- "istanbul-lib-hook": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/istanbul-lib-hook/-/istanbul-lib-hook-3.0.0.tgz",
- "integrity": "sha512-Pt/uge1Q9s+5VAZ+pCo16TYMWPBIl+oaNIjgLQxcX0itS6ueeaA+pEfThZpH8WxhFgCiEb8sAJY6MdUKgiIWaQ==",
- "dev": true,
- "requires": {
- "append-transform": "^2.0.0"
- }
- },
- "istanbul-lib-instrument": {
- "version": "4.0.3",
- "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-4.0.3.tgz",
- "integrity": "sha512-BXgQl9kf4WTCPCCpmFGoJkz/+uhvm7h7PFKUYxh7qarQd3ER33vHG//qaE8eN25l07YqZPpHXU9I09l/RD5aGQ==",
- "dev": true,
- "requires": {
- "@babel/core": "^7.7.5",
- "@istanbuljs/schema": "^0.1.2",
- "istanbul-lib-coverage": "^3.0.0",
- "semver": "^6.3.0"
- }
- },
- "istanbul-lib-processinfo": {
- "version": "2.0.2",
- "resolved": "https://registry.npmjs.org/istanbul-lib-processinfo/-/istanbul-lib-processinfo-2.0.2.tgz",
- "integrity": "sha512-kOwpa7z9hme+IBPZMzQ5vdQj8srYgAtaRqeI48NGmAQ+/5yKiHLV0QbYqQpxsdEF0+w14SoB8YbnHKcXE2KnYw==",
- "dev": true,
- "requires": {
- "archy": "^1.0.0",
- "cross-spawn": "^7.0.0",
- "istanbul-lib-coverage": "^3.0.0-alpha.1",
- "make-dir": "^3.0.0",
- "p-map": "^3.0.0",
- "rimraf": "^3.0.0",
- "uuid": "^3.3.3"
- }
- },
- "istanbul-lib-report": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/istanbul-lib-report/-/istanbul-lib-report-3.0.0.tgz",
- "integrity": "sha512-wcdi+uAKzfiGT2abPpKZ0hSU1rGQjUQnLvtY5MpQ7QCTahD3VODhcu4wcfY1YtkGaDD5yuydOLINXsfbus9ROw==",
- "dev": true,
- "requires": {
- "istanbul-lib-coverage": "^3.0.0",
- "make-dir": "^3.0.0",
- "supports-color": "^7.1.0"
- },
- "dependencies": {
- "has-flag": {
- "version": "4.0.0",
- "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
- "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
- "dev": true
- },
- "supports-color": {
- "version": "7.2.0",
- "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
- "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==",
- "dev": true,
- "requires": {
- "has-flag": "^4.0.0"
- }
- }
- }
- },
- "istanbul-lib-source-maps": {
- "version": "4.0.0",
- "resolved": "https://registry.npmjs.org/istanbul-lib-source-maps/-/istanbul-lib-source-maps-4.0.0.tgz",
- "integrity": "sha512-c16LpFRkR8vQXyHZ5nLpY35JZtzj1PQY1iZmesUbf1FZHbIupcWfjgOXBY9YHkLEQ6puz1u4Dgj6qmU/DisrZg==",
- "dev": true,
- "requires": {
- "debug": "^4.1.1",
- "istanbul-lib-coverage": "^3.0.0",
- "source-map": "^0.6.1"
- },
- "dependencies": {
- "debug": {
- "version": "4.3.2",
- "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.2.tgz",
- "integrity": "sha512-mOp8wKcvj7XxC78zLgw/ZA+6TSgkoE2C/ienthhRD298T7UNwAg9diBpLRxC0mOezLl4B0xV7M0cCO6P/O0Xhw==",
- "dev": true,
- "requires": {
- "ms": "2.1.2"
- }
- },
- "ms": {
- "version": "2.1.2",
- "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
- "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==",
- "dev": true
- },
- "source-map": {
- "version": "0.6.1",
- "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
- "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==",
- "dev": true
- }
- }
- },
- "istanbul-reports": {
- "version": "3.0.2",
- "resolved": "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-3.0.2.tgz",
- "integrity": "sha512-9tZvz7AiR3PEDNGiV9vIouQ/EAcqMXFmkcA1CDFTwOB98OZVDL0PH9glHotf5Ugp6GCOTypfzGWI/OqjWNCRUw==",
- "dev": true,
- "requires": {
- "html-escaper": "^2.0.0",
- "istanbul-lib-report": "^3.0.0"
- }
- },
- "jackspeak": {
- "version": "1.4.0",
- "resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-1.4.0.tgz",
- "integrity": "sha512-VDcSunT+wcccoG46FtzuBAyQKlzhHjli4q31e1fIHGOsRspqNUFjVzGb+7eIFDlTvqLygxapDHPHS0ouT2o/tw==",
- "dev": true,
- "requires": {
- "cliui": "^4.1.0"
- }
- },
- "javascript-natural-sort": {
- "version": "0.7.1",
- "resolved": "https://registry.npmjs.org/javascript-natural-sort/-/javascript-natural-sort-0.7.1.tgz",
- "integrity": "sha1-+eIwPUUH9tdDVac2ZNFED7Wg71k="
- },
- "jquery": {
- "version": "3.6.0",
- "resolved": "https://registry.npmjs.org/jquery/-/jquery-3.6.0.tgz",
- "integrity": "sha512-JVzAR/AjBvVt2BmYhxRCSYysDsPcssdmTFnzyLEts9qNwmjmu4JTAMYubEfwVOSwpQ1I1sKKFcxhZCI2buerfw=="
- },
- "js-tokens": {
- "version": "4.0.0",
- "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz",
- "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==",
- "dev": true
- },
- "js-yaml": {
- "version": "3.14.1",
- "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz",
- "integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==",
- "dev": true,
- "requires": {
- "argparse": "^1.0.7",
- "esprima": "^4.0.0"
- }
- },
- "jsbn": {
- "version": "0.1.1",
- "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-0.1.1.tgz",
- "integrity": "sha1-peZUwuWi3rXyAdls77yoDA7y9RM=",
- "dev": true
- },
- "jsesc": {
- "version": "2.5.2",
- "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz",
- "integrity": "sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==",
- "dev": true
- },
- "json-schema": {
- "version": "0.2.3",
- "resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.2.3.tgz",
- "integrity": "sha1-tIDIkuWaLwWVTOcnvT8qTogvnhM=",
- "dev": true
- },
- "json-schema-traverse": {
- "version": "0.4.1",
- "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz",
- "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==",
- "dev": true
- },
- "json-stringify-safe": {
- "version": "5.0.1",
- "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz",
- "integrity": "sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus=",
- "dev": true
- },
- "json5": {
- "version": "2.2.0",
- "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.0.tgz",
- "integrity": "sha512-f+8cldu7X/y7RAJurMEJmdoKXGB/X550w2Nr3tTbezL6RwEE/iMcm+tZnXeoZtKuOq6ft8+CqzEkrIgx1fPoQA==",
- "dev": true,
- "requires": {
- "minimist": "^1.2.5"
- }
- },
- "jsprim": {
- "version": "1.4.1",
- "resolved": "https://registry.npmjs.org/jsprim/-/jsprim-1.4.1.tgz",
- "integrity": "sha1-MT5mvB5cwG5Di8G3SZwuXFastqI=",
- "dev": true,
- "requires": {
- "assert-plus": "1.0.0",
- "extsprintf": "1.3.0",
- "json-schema": "0.2.3",
- "verror": "1.10.0"
- }
- },
- "jtree": {
- "version": "74.0.0",
- "resolved": "https://registry.npmjs.org/jtree/-/jtree-74.0.0.tgz",
- "integrity": "sha512-jKyvI60geVzmtfqahfG4kszQp2zg50N7JvtLTxaRamZpqi3J+a+3UduSEZvzBN8k7qSvcR7rA0TBbXSBinCOPw==",
- "requires": {
- "express": "^4.18.2",
- "glob": "^9.3.4",
- "mkdirp": "^2.1.6",
- "prettier": "^2.8.7",
- "recursive-readdir-sync": "^1.0.6",
- "superagent": "^8.0.9"
- },
- "dependencies": {
- "brace-expansion": {
- "version": "2.0.1",
- "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz",
- "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==",
- "requires": {
- "balanced-match": "^1.0.0"
- }
- },
- "glob": {
- "version": "9.3.4",
- "resolved": "https://registry.npmjs.org/glob/-/glob-9.3.4.tgz",
- "integrity": "sha512-qaSc49hojMOv1EPM4EuyITjDSgSKI0rthoHnvE81tcOi1SCVndHko7auqxdQ14eiQG2NDBJBE86+2xIrbIvrbA==",
- "requires": {
- "fs.realpath": "^1.0.0",
- "minimatch": "^8.0.2",
- "minipass": "^4.2.4",
- "path-scurry": "^1.6.1"
- }
- },
- "minimatch": {
- "version": "8.0.3",
- "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-8.0.3.tgz",
- "integrity": "sha512-tEEvU9TkZgnFDCtpnrEYnPsjT7iUx42aXfs4bzmQ5sMA09/6hZY0jeZcGkXyDagiBOvkUjNo8Viom+Me6+2x7g==",
- "requires": {
- "brace-expansion": "^2.0.1"
- }
- },
- "minipass": {
- "version": "4.2.5",
- "resolved": "https://registry.npmjs.org/minipass/-/minipass-4.2.5.tgz",
- "integrity": "sha512-+yQl7SX3bIT83Lhb4BVorMAHVuqsskxRdlmO9kTpyukp8vsm2Sn/fUOV9xlnG8/a5JsypJzap21lz/y3FBMJ8Q=="
- }
- }
- },
- "lcov-parse": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/lcov-parse/-/lcov-parse-1.0.0.tgz",
- "integrity": "sha1-6w1GtUER68VhrLTECO+TY73I9+A=",
- "dev": true
- },
- "libtap": {
- "version": "1.1.1",
- "resolved": "https://registry.npmjs.org/libtap/-/libtap-1.1.1.tgz",
- "integrity": "sha512-Fye8fh1+G7E8qqmjQaY+pXGxy7HM0S6bqCCJFLa16+g2jODBByxbJFDpjbDNF69wfRVyvJ+foLZc1WTIv7dx+g==",
- "dev": true,
- "requires": {
- "async-hook-domain": "^2.0.1",
- "bind-obj-methods": "^3.0.0",
- "diff": "^4.0.2",
- "function-loop": "^2.0.1",
- "minipass": "^3.1.1",
- "own-or": "^1.0.0",
- "own-or-env": "^1.0.1",
- "signal-exit": "^3.0.2",
- "stack-utils": "^2.0.1",
- "tap-parser": "^10.0.1",
- "tap-yaml": "^1.0.0",
- "tcompare": "^5.0.1",
- "trivial-deferred": "^1.0.1",
- "yapool": "^1.0.0"
- }
- },
- "locate-path": {
- "version": "5.0.0",
- "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz",
- "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==",
- "dev": true,
- "requires": {
- "p-locate": "^4.1.0"
- }
- },
- "lodash": {
- "version": "4.17.21",
- "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz",
- "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg=="
- },
- "lodash.flattendeep": {
- "version": "4.4.0",
- "resolved": "https://registry.npmjs.org/lodash.flattendeep/-/lodash.flattendeep-4.4.0.tgz",
- "integrity": "sha1-+wMJF/hqMTTlvJvsDWngAT3f7bI=",
- "dev": true
- },
- "log-driver": {
- "version": "1.2.7",
- "resolved": "https://registry.npmjs.org/log-driver/-/log-driver-1.2.7.tgz",
- "integrity": "sha512-U7KCmLdqsGHBLeWqYlFA0V0Sl6P08EE1ZrmA9cxjUE0WVqT9qnyVDPz1kzpFEP0jdJuFnasWIfSd7fsaNXkpbg==",
- "dev": true
- },
- "loose-envify": {
- "version": "1.4.0",
- "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz",
- "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==",
- "dev": true,
- "requires": {
- "js-tokens": "^3.0.0 || ^4.0.0"
- }
- },
- "lru-cache": {
- "version": "7.18.3",
- "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-7.18.3.tgz",
- "integrity": "sha512-jumlc0BIUrS3qJGgIkWZsyfAM7NCWiBcCDhnd+3NNM5KbBmLTgHVfWBcg6W+rLUsIpzpERPsvwUP7CckAQSOoA=="
- },
- "make-dir": {
- "version": "3.1.0",
- "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz",
- "integrity": "sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==",
- "dev": true,
- "requires": {
- "semver": "^6.0.0"
- }
- },
- "mathjs": {
- "version": "9.4.4",
- "resolved": "https://registry.npmjs.org/mathjs/-/mathjs-9.4.4.tgz",
- "integrity": "sha512-5EEJXnWOzLDgMHSFyw623nH+MTBZxquWwXtrzTsingOouJJ6UZG2VNO1lwH31IMt9aMno1axO6TYleIP4YSDaQ==",
- "requires": {
- "@babel/runtime": "^7.14.6",
- "complex.js": "^2.0.15",
- "decimal.js": "^10.3.1",
- "escape-latex": "^1.2.0",
- "fraction.js": "^4.1.1",
- "javascript-natural-sort": "^0.7.1",
- "seedrandom": "^3.0.5",
- "tiny-emitter": "^2.1.0",
- "typed-function": "^2.0.0"
- }
- },
- "media-typer": {
- "version": "0.3.0",
- "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz",
- "integrity": "sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ=="
- },
- "merge-descriptors": {
- "version": "1.0.1",
- "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz",
- "integrity": "sha512-cCi6g3/Zr1iqQi6ySbseM1Xvooa98N0w31jzUYrXPX2xqObmFGHJ0tQ5u74H3mVh7wLouTseZyYIq39g8cNp1w=="
- },
- "methods": {
- "version": "1.1.2",
- "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz",
- "integrity": "sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w=="
- },
- "mime": {
- "version": "1.6.0",
- "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz",
- "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg=="
- },
- "mime-db": {
- "version": "1.52.0",
- "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz",
- "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg=="
- },
- "mime-types": {
- "version": "2.1.35",
- "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz",
- "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==",
- "requires": {
- "mime-db": "1.52.0"
- }
- },
- "minimatch": {
- "version": "3.0.4",
- "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz",
- "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==",
- "dev": true,
- "requires": {
- "brace-expansion": "^1.1.7"
- }
- },
- "minimist": {
- "version": "1.2.6",
- "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.6.tgz",
- "integrity": "sha512-Jsjnk4bw3YJqYzbdyBiNsPWHPfO++UGG749Cxs6peCu5Xg4nrena6OVxOYxrQTqww0Jmwt+Ref8rggumkTLz9Q=="
- },
- "minipass": {
- "version": "3.1.3",
- "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.1.3.tgz",
- "integrity": "sha512-Mgd2GdMVzY+x3IJ+oHnVM+KG3lA5c8tnabyJKmHSaG2kAGpudxuOf8ToDkhumF7UzME7DecbQE9uOZhNm7PuJg==",
- "dev": true,
- "requires": {
- "yallist": "^4.0.0"
- }
- },
- "mkdirp": {
- "version": "2.1.6",
- "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-2.1.6.tgz",
- "integrity": "sha512-+hEnITedc8LAtIP9u3HJDFIdcLV2vXP33sqLLIzkv1Db1zO/1OxbvYf0Y1OC/S/Qo5dxHXepofhmxL02PsKe+A=="
- },
- "ms": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
- "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A=="
- },
- "negotiator": {
- "version": "0.6.3",
- "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz",
- "integrity": "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg=="
- },
- "node-preload": {
- "version": "0.2.1",
- "resolved": "https://registry.npmjs.org/node-preload/-/node-preload-0.2.1.tgz",
- "integrity": "sha512-RM5oyBy45cLEoHqCeh+MNuFAxO0vTFBLskvQbOKnEE7YTTSN4tbN8QWDIPQ6L+WvKsB/qLEGpYe2ZZ9d4W9OIQ==",
- "dev": true,
- "requires": {
- "process-on-spawn": "^1.0.0"
- }
- },
- "node-releases": {
- "version": "1.1.73",
- "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-1.1.73.tgz",
- "integrity": "sha512-uW7fodD6pyW2FZNZnp/Z3hvWKeEW1Y8R1+1CnErE8cXFXzl5blBOoVB41CvMer6P6Q0S5FXDwcHgFd1Wj0U9zg==",
- "dev": true
- },
- "normalize-path": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz",
- "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==",
- "dev": true
- },
- "number-is-nan": {
- "version": "1.0.1",
- "resolved": "https://registry.npmjs.org/number-is-nan/-/number-is-nan-1.0.1.tgz",
- "integrity": "sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0=",
- "dev": true
- },
- "nyc": {
- "version": "15.1.0",
- "resolved": "https://registry.npmjs.org/nyc/-/nyc-15.1.0.tgz",
- "integrity": "sha512-jMW04n9SxKdKi1ZMGhvUTHBN0EICCRkHemEoE5jm6mTYcqcdas0ATzgUgejlQUHMvpnOZqGB5Xxsv9KxJW1j8A==",
- "dev": true,
- "requires": {
- "@istanbuljs/load-nyc-config": "^1.0.0",
- "@istanbuljs/schema": "^0.1.2",
- "caching-transform": "^4.0.0",
- "convert-source-map": "^1.7.0",
- "decamelize": "^1.2.0",
- "find-cache-dir": "^3.2.0",
- "find-up": "^4.1.0",
- "foreground-child": "^2.0.0",
- "get-package-type": "^0.1.0",
- "glob": "^7.1.6",
- "istanbul-lib-coverage": "^3.0.0",
- "istanbul-lib-hook": "^3.0.0",
- "istanbul-lib-instrument": "^4.0.0",
- "istanbul-lib-processinfo": "^2.0.2",
- "istanbul-lib-report": "^3.0.0",
- "istanbul-lib-source-maps": "^4.0.0",
- "istanbul-reports": "^3.0.2",
- "make-dir": "^3.0.0",
- "node-preload": "^0.2.1",
- "p-map": "^3.0.0",
- "process-on-spawn": "^1.0.0",
- "resolve-from": "^5.0.0",
- "rimraf": "^3.0.0",
- "signal-exit": "^3.0.2",
- "spawn-wrap": "^2.0.0",
- "test-exclude": "^6.0.0",
- "yargs": "^15.0.2"
- }
- },
- "oauth-sign": {
- "version": "0.9.0",
- "resolved": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.9.0.tgz",
- "integrity": "sha512-fexhUFFPTGV8ybAtSIGbV6gOkSv8UtRbDBnAyLQw4QPKkgNlsH2ByPGtMUqdWkos6YCRmAqViwgZrJc/mRDzZQ==",
- "dev": true
- },
- "object-assign": {
- "version": "4.1.1",
- "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz",
- "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=",
- "dev": true
- },
- "object-inspect": {
- "version": "1.12.3",
- "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.12.3.tgz",
- "integrity": "sha512-geUvdk7c+eizMNUDkRpW1wJwgfOiOeHbxBR/hLXK1aT6zmVSO0jsQcs7fj6MGw89jC/cjGfLcNOrtMYtGqm81g=="
- },
- "on-finished": {
- "version": "2.4.1",
- "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz",
- "integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==",
- "requires": {
- "ee-first": "1.1.1"
- }
- },
- "once": {
- "version": "1.4.0",
- "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz",
- "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=",
- "requires": {
- "wrappy": "1"
- }
- },
- "opener": {
- "version": "1.5.2",
- "resolved": "https://registry.npmjs.org/opener/-/opener-1.5.2.tgz",
- "integrity": "sha512-ur5UIdyw5Y7yEj9wLzhqXiy6GZ3Mwx0yGI+5sMn2r0N0v3cKJvUmFH5yPP+WXh9e0xfyzyJX95D8l088DNFj7A==",
- "dev": true
- },
- "own-or": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/own-or/-/own-or-1.0.0.tgz",
- "integrity": "sha1-Tod/vtqaLsgAD7wLyuOWRe6L+Nw=",
- "dev": true
- },
- "own-or-env": {
- "version": "1.0.1",
- "resolved": "https://registry.npmjs.org/own-or-env/-/own-or-env-1.0.1.tgz",
- "integrity": "sha512-y8qULRbRAlL6x2+M0vIe7jJbJx/kmUTzYonRAa2ayesR2qWLswninkVyeJe4x3IEXhdgoNodzjQRKAoEs6Fmrw==",
- "dev": true,
- "requires": {
- "own-or": "^1.0.0"
- }
- },
- "p-limit": {
- "version": "2.3.0",
- "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz",
- "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==",
- "dev": true,
- "requires": {
- "p-try": "^2.0.0"
- }
- },
- "p-locate": {
- "version": "4.1.0",
- "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz",
- "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==",
- "dev": true,
- "requires": {
- "p-limit": "^2.2.0"
- }
- },
- "p-map": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/p-map/-/p-map-3.0.0.tgz",
- "integrity": "sha512-d3qXVTF/s+W+CdJ5A29wywV2n8CQQYahlgz2bFiA+4eVNJbHJodPZ+/gXwPGh0bOqA+j8S+6+ckmvLGPk1QpxQ==",
- "dev": true,
- "requires": {
- "aggregate-error": "^3.0.0"
- }
- },
- "p-try": {
- "version": "2.2.0",
- "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz",
- "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==",
- "dev": true
- },
- "package-hash": {
- "version": "4.0.0",
- "resolved": "https://registry.npmjs.org/package-hash/-/package-hash-4.0.0.tgz",
- "integrity": "sha512-whdkPIooSu/bASggZ96BWVvZTRMOFxnyUG5PnTSGKoJE2gd5mbVNmR2Nj20QFzxYYgAXpoqC+AiXzl+UMRh7zQ==",
- "dev": true,
- "requires": {
- "graceful-fs": "^4.1.15",
- "hasha": "^5.0.0",
- "lodash.flattendeep": "^4.4.0",
- "release-zalgo": "^1.0.0"
- }
- },
- "parseurl": {
- "version": "1.3.3",
- "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz",
- "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ=="
- },
- "path-exists": {
- "version": "4.0.0",
- "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz",
- "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==",
- "dev": true
- },
- "path-is-absolute": {
- "version": "1.0.1",
- "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz",
- "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=",
- "dev": true
- },
- "path-key": {
- "version": "3.1.1",
- "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz",
- "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==",
- "dev": true
- },
- "path-scurry": {
- "version": "1.6.3",
- "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-1.6.3.tgz",
- "integrity": "sha512-RAmB+n30SlN+HnNx6EbcpoDy9nwdpcGPnEKrJnu6GZoDWBdIjo1UQMVtW2ybtC7LC2oKLcMq8y5g8WnKLiod9g==",
- "requires": {
- "lru-cache": "^7.14.1",
- "minipass": "^4.0.2"
- },
- "dependencies": {
- "minipass": {
- "version": "4.2.5",
- "resolved": "https://registry.npmjs.org/minipass/-/minipass-4.2.5.tgz",
- "integrity": "sha512-+yQl7SX3bIT83Lhb4BVorMAHVuqsskxRdlmO9kTpyukp8vsm2Sn/fUOV9xlnG8/a5JsypJzap21lz/y3FBMJ8Q=="
- }
- }
- },
- "path-to-regexp": {
- "version": "0.1.7",
- "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz",
- "integrity": "sha512-5DFkuoqlv1uYQKxy8omFBeJPQcdoE07Kv2sferDCrAq1ohOU+MSDswDIbnx3YAM60qIOnYa53wBhXW0EbMonrQ=="
- },
- "performance-now": {
- "version": "2.1.0",
- "resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz",
- "integrity": "sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns=",
- "dev": true
- },
- "picomatch": {
- "version": "2.3.0",
- "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.0.tgz",
- "integrity": "sha512-lY1Q/PiJGC2zOv/z391WOTD+Z02bCgsFfvxoXXf6h7kv9o+WmsmzYqrAwY63sNgOxE4xEdq0WyUnXfKeBrSvYw==",
- "dev": true
- },
- "pkg-dir": {
- "version": "4.2.0",
- "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-4.2.0.tgz",
- "integrity": "sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==",
- "dev": true,
- "requires": {
- "find-up": "^4.0.0"
- }
- },
- "prettier": {
- "version": "2.8.7",
- "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.8.7.tgz",
- "integrity": "sha512-yPngTo3aXUUmyuTjeTUT75txrf+aMh9FiD7q9ZE/i6r0bPb22g4FsE6Y338PQX1bmfy08i9QQCB7/rcUAVntfw=="
- },
- "process-on-spawn": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/process-on-spawn/-/process-on-spawn-1.0.0.tgz",
- "integrity": "sha512-1WsPDsUSMmZH5LeMLegqkPDrsGgsWwk1Exipy2hvB0o/F0ASzbpIctSCcZIK1ykJvtTJULEH+20WOFjMvGnCTg==",
- "dev": true,
- "requires": {
- "fromentries": "^1.2.0"
- }
- },
- "prop-types": {
- "version": "15.7.2",
- "resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.7.2.tgz",
- "integrity": "sha512-8QQikdH7//R2vurIJSutZ1smHYTcLpRWEOlHnzcWHmBYrOGUysKwSsrC89BCiFj3CbrfJ/nXFdJepOVrY1GCHQ==",
- "dev": true,
- "requires": {
- "loose-envify": "^1.4.0",
- "object-assign": "^4.1.1",
- "react-is": "^16.8.1"
- }
- },
- "proxy-addr": {
- "version": "2.0.7",
- "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz",
- "integrity": "sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==",
- "requires": {
- "forwarded": "0.2.0",
- "ipaddr.js": "1.9.1"
- }
- },
- "psl": {
- "version": "1.8.0",
- "resolved": "https://registry.npmjs.org/psl/-/psl-1.8.0.tgz",
- "integrity": "sha512-RIdOzyoavK+hA18OGGWDqUTsCLhtA7IcZ/6NCs4fFJaHBDab+pDDmDIByWFRQJq2Cd7r1OoQxBGKOaztq+hjIQ==",
- "dev": true
- },
- "punycode": {
- "version": "2.1.1",
- "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz",
- "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==",
- "dev": true
- },
- "qs": {
- "version": "6.11.0",
- "resolved": "https://registry.npmjs.org/qs/-/qs-6.11.0.tgz",
- "integrity": "sha512-MvjoMCJwEarSbUYk5O+nmoSzSutSsTwF85zcHPQ9OrlFoZOYIjaqBAJIqIXjptyD5vThxGq52Xu/MaJzRkIk4Q==",
- "requires": {
- "side-channel": "^1.0.4"
- }
- },
- "range-parser": {
- "version": "1.2.1",
- "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz",
- "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg=="
- },
- "raw-body": {
- "version": "2.5.1",
- "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.1.tgz",
- "integrity": "sha512-qqJBtEyVgS0ZmPGdCFPWJ3FreoqvG4MVQln/kCgF7Olq95IbOp0/BWyMwbdtn4VTvkM8Y7khCQ2Xgk/tcrCXig==",
- "requires": {
- "bytes": "3.1.2",
- "http-errors": "2.0.0",
- "iconv-lite": "0.4.24",
- "unpipe": "1.0.0"
- }
- },
- "react": {
- "version": "16.14.0",
- "resolved": "https://registry.npmjs.org/react/-/react-16.14.0.tgz",
- "integrity": "sha512-0X2CImDkJGApiAlcf0ODKIneSwBPhqJawOa5wCtKbu7ZECrmS26NvtSILynQ66cgkT/RJ4LidJOc3bUESwmU8g==",
- "dev": true,
- "requires": {
- "loose-envify": "^1.1.0",
- "object-assign": "^4.1.1",
- "prop-types": "^15.6.2"
- }
- },
- "react-is": {
- "version": "16.13.1",
- "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz",
- "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==",
- "dev": true
- },
- "readdirp": {
- "version": "3.6.0",
- "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz",
- "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==",
- "dev": true,
- "requires": {
- "picomatch": "^2.2.1"
- }
- },
- "recursive-readdir-sync": {
- "version": "1.0.6",
- "resolved": "https://registry.npmjs.org/recursive-readdir-sync/-/recursive-readdir-sync-1.0.6.tgz",
- "integrity": "sha1-Hb9tMvPFu4083pemxYjVR6nhPVY="
- },
- "regenerator-runtime": {
- "version": "0.13.9",
- "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.9.tgz",
- "integrity": "sha512-p3VT+cOEgxFsRRA9X4lkI1E+k2/CtnKtU4gcxyaCUreilL/vqI6CdZ3wxVUx3UOUg+gnUOQQcRI7BmSI656MYA=="
- },
- "release-zalgo": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/release-zalgo/-/release-zalgo-1.0.0.tgz",
- "integrity": "sha1-CXALflB0Mpc5Mw5TXFqQ+2eFFzA=",
- "dev": true,
- "requires": {
- "es6-error": "^4.0.1"
- }
- },
- "request": {
- "version": "2.88.2",
- "resolved": "https://registry.npmjs.org/request/-/request-2.88.2.tgz",
- "integrity": "sha512-MsvtOrfG9ZcrOwAW+Qi+F6HbD0CWXEh9ou77uOb7FM2WPhwT7smM833PzanhJLsgXjN89Ir6V2PczXNnMpwKhw==",
- "dev": true,
- "requires": {
- "aws-sign2": "~0.7.0",
- "aws4": "^1.8.0",
- "caseless": "~0.12.0",
- "combined-stream": "~1.0.6",
- "extend": "~3.0.2",
- "forever-agent": "~0.6.1",
- "form-data": "~2.3.2",
- "har-validator": "~5.1.3",
- "http-signature": "~1.2.0",
- "is-typedarray": "~1.0.0",
- "isstream": "~0.1.2",
- "json-stringify-safe": "~5.0.1",
- "mime-types": "~2.1.19",
- "oauth-sign": "~0.9.0",
- "performance-now": "^2.1.0",
- "qs": "~6.5.2",
- "safe-buffer": "^5.1.2",
- "tough-cookie": "~2.5.0",
- "tunnel-agent": "^0.6.0",
- "uuid": "^3.3.2"
- },
- "dependencies": {
- "form-data": {
- "version": "2.3.3",
- "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.3.3.tgz",
- "integrity": "sha512-1lLKB2Mu3aGP1Q/2eCOx0fNbRMe7XdwktwOruhfqqd0rIJWwN4Dh+E3hrPSlDCXnSR7UtZ1N38rVXm+6+MEhJQ==",
- "dev": true,
- "requires": {
- "asynckit": "^0.4.0",
- "combined-stream": "^1.0.6",
- "mime-types": "^2.1.12"
- }
- },
- "qs": {
- "version": "6.5.2",
- "resolved": "https://registry.npmjs.org/qs/-/qs-6.5.2.tgz",
- "integrity": "sha512-N5ZAX4/LxJmF+7wN74pUD6qAh9/wnvdQcjq9TZjevvXzSUo7bfmw91saqMjzGS2xq91/odN2dW/WOl7qQHNDGA==",
- "dev": true
- }
- }
- },
- "require-directory": {
- "version": "2.1.1",
- "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz",
- "integrity": "sha1-jGStX9MNqxyXbiNE/+f3kqam30I=",
- "dev": true
- },
- "require-main-filename": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-2.0.0.tgz",
- "integrity": "sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg==",
- "dev": true
- },
- "resolve-from": {
- "version": "5.0.0",
- "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz",
- "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==",
- "dev": true
- },
- "rimraf": {
- "version": "3.0.2",
- "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz",
- "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==",
- "dev": true,
- "requires": {
- "glob": "^7.1.3"
- }
- },
- "safe-buffer": {
- "version": "5.1.2",
- "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz",
- "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==",
- "dev": true
- },
- "safer-buffer": {
- "version": "2.1.2",
- "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz",
- "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg=="
- },
- "seedrandom": {
- "version": "3.0.5",
- "resolved": "https://registry.npmjs.org/seedrandom/-/seedrandom-3.0.5.tgz",
- "integrity": "sha512-8OwmbklUNzwezjGInmZ+2clQmExQPvomqjL7LFqOYqtmuxRgQYqOD3mHaU+MvZn5FLUeVxVfQjwLZW/n/JFuqg=="
- },
- "semver": {
- "version": "6.3.0",
- "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz",
- "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==",
- "dev": true
- },
- "send": {
- "version": "0.18.0",
- "resolved": "https://registry.npmjs.org/send/-/send-0.18.0.tgz",
- "integrity": "sha512-qqWzuOjSFOuqPjFe4NOsMLafToQQwBSOEpS+FwEt3A2V3vKubTquT3vmLTQpFgMXp8AlFWFuP1qKaJZOtPpVXg==",
- "requires": {
- "debug": "2.6.9",
- "depd": "2.0.0",
- "destroy": "1.2.0",
- "encodeurl": "~1.0.2",
- "escape-html": "~1.0.3",
- "etag": "~1.8.1",
- "fresh": "0.5.2",
- "http-errors": "2.0.0",
- "mime": "1.6.0",
- "ms": "2.1.3",
- "on-finished": "2.4.1",
- "range-parser": "~1.2.1",
- "statuses": "2.0.1"
- },
- "dependencies": {
- "ms": {
- "version": "2.1.3",
- "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
- "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA=="
- }
- }
- },
- "serve-static": {
- "version": "1.15.0",
- "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.15.0.tgz",
- "integrity": "sha512-XGuRDNjXUijsUL0vl6nSD7cwURuzEgglbOaFuZM9g3kwDXOWVTck0jLzjPzGD+TazWbboZYu52/9/XPdUgne9g==",
- "requires": {
- "encodeurl": "~1.0.2",
- "escape-html": "~1.0.3",
- "parseurl": "~1.3.3",
- "send": "0.18.0"
- }
- },
- "set-blocking": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz",
- "integrity": "sha1-BF+XgtARrppoA93TgrJDkrPYkPc=",
- "dev": true
- },
- "setprototypeof": {
- "version": "1.2.0",
- "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz",
- "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw=="
- },
- "shebang-command": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz",
- "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==",
- "dev": true,
- "requires": {
- "shebang-regex": "^3.0.0"
- }
- },
- "shebang-regex": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz",
- "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==",
- "dev": true
- },
- "side-channel": {
- "version": "1.0.4",
- "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.4.tgz",
- "integrity": "sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==",
- "requires": {
- "call-bind": "^1.0.0",
- "get-intrinsic": "^1.0.2",
- "object-inspect": "^1.9.0"
- }
- },
- "signal-exit": {
- "version": "3.0.3",
- "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.3.tgz",
- "integrity": "sha512-VUJ49FC8U1OxwZLxIbTTrDvLnf/6TDgxZcK8wxR8zs13xpx7xbG60ndBlhNrFi2EMuFRoeDoJO7wthSLq42EjA==",
- "dev": true
- },
- "source-map": {
- "version": "0.5.7",
- "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz",
- "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=",
- "dev": true
- },
- "source-map-support": {
- "version": "0.5.19",
- "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.19.tgz",
- "integrity": "sha512-Wonm7zOCIJzBGQdB+thsPar0kYuCIzYvxZwlBa87yi/Mdjv7Tip2cyVbLj5o0cFPN4EVkuTwb3GDDyUx2DGnGw==",
- "dev": true,
- "requires": {
- "buffer-from": "^1.0.0",
- "source-map": "^0.6.0"
- },
- "dependencies": {
- "source-map": {
- "version": "0.6.1",
- "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
- "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==",
- "dev": true
- }
- }
- },
- "spawn-wrap": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/spawn-wrap/-/spawn-wrap-2.0.0.tgz",
- "integrity": "sha512-EeajNjfN9zMnULLwhZZQU3GWBoFNkbngTUPfaawT4RkMiviTxcX0qfhVbGey39mfctfDHkWtuecgQ8NJcyQWHg==",
- "dev": true,
- "requires": {
- "foreground-child": "^2.0.0",
- "is-windows": "^1.0.2",
- "make-dir": "^3.0.0",
- "rimraf": "^3.0.0",
- "signal-exit": "^3.0.2",
- "which": "^2.0.1"
- }
- },
- "sprintf-js": {
- "version": "1.0.3",
- "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz",
- "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=",
- "dev": true
- },
- "sshpk": {
- "version": "1.16.1",
- "resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.16.1.tgz",
- "integrity": "sha512-HXXqVUq7+pcKeLqqZj6mHFUMvXtOJt1uoUx09pFW6011inTMxqI8BA8PM95myrIyyKwdnzjdFjLiE6KBPVtJIg==",
- "dev": true,
- "requires": {
- "asn1": "~0.2.3",
- "assert-plus": "^1.0.0",
- "bcrypt-pbkdf": "^1.0.0",
- "dashdash": "^1.12.0",
- "ecc-jsbn": "~0.1.1",
- "getpass": "^0.1.1",
- "jsbn": "~0.1.0",
- "safer-buffer": "^2.0.2",
- "tweetnacl": "~0.14.0"
- }
- },
- "stack-utils": {
- "version": "2.0.3",
- "resolved": "https://registry.npmjs.org/stack-utils/-/stack-utils-2.0.3.tgz",
- "integrity": "sha512-gL//fkxfWUsIlFL2Tl42Cl6+HFALEaB1FU76I/Fy+oZjRreP7OPMXFlGbxM7NQsI0ZpUfw76sHnv0WNYuTb7Iw==",
- "dev": true,
- "requires": {
- "escape-string-regexp": "^2.0.0"
- }
- },
- "statuses": {
- "version": "2.0.1",
- "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz",
- "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ=="
- },
- "string-width": {
- "version": "2.1.1",
- "resolved": "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz",
- "integrity": "sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==",
- "dev": true,
- "requires": {
- "is-fullwidth-code-point": "^2.0.0",
- "strip-ansi": "^4.0.0"
- }
- },
- "strip-ansi": {
- "version": "4.0.0",
- "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz",
- "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=",
- "dev": true,
- "requires": {
- "ansi-regex": "^3.0.0"
- }
- },
- "strip-bom": {
- "version": "4.0.0",
- "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-4.0.0.tgz",
- "integrity": "sha512-3xurFv5tEgii33Zi8Jtp55wEIILR9eh34FAW00PZf+JnSsTmV/ioewSgQl97JHvgjoRGwPShsWm+IdrxB35d0w==",
- "dev": true
- },
- "superagent": {
- "version": "8.0.9",
- "resolved": "https://registry.npmjs.org/superagent/-/superagent-8.0.9.tgz",
- "integrity": "sha512-4C7Bh5pyHTvU33KpZgwrNKh/VQnvgtCSqPRfJAUdmrtSYePVzVg4E4OzsrbkhJj9O7SO6Bnv75K/F8XVZT8YHA==",
- "requires": {
- "component-emitter": "^1.3.0",
- "cookiejar": "^2.1.4",
- "debug": "^4.3.4",
- "fast-safe-stringify": "^2.1.1",
- "form-data": "^4.0.0",
- "formidable": "^2.1.2",
- "methods": "^1.1.2",
- "mime": "2.6.0",
- "qs": "^6.11.0",
- "semver": "^7.3.8"
- },
- "dependencies": {
- "debug": {
- "version": "4.3.4",
- "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz",
- "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==",
- "requires": {
- "ms": "2.1.2"
- }
- },
- "lru-cache": {
- "version": "6.0.0",
- "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz",
- "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==",
- "requires": {
- "yallist": "^4.0.0"
- }
- },
- "mime": {
- "version": "2.6.0",
- "resolved": "https://registry.npmjs.org/mime/-/mime-2.6.0.tgz",
- "integrity": "sha512-USPkMeET31rOMiarsBNIHZKLGgvKc/LrjofAnBlOttf5ajRvqiRA8QsenbcooctK6d6Ts6aqZXBA+XbkKthiQg=="
- },
- "ms": {
- "version": "2.1.2",
- "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
- "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w=="
- },
- "semver": {
- "version": "7.3.8",
- "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.8.tgz",
- "integrity": "sha512-NB1ctGL5rlHrPJtFDVIVzTyQylMLu9N9VICA6HSFJo8MCGVTMW6gfpicwKmmK/dAjTOrqu5l63JJOpDSrAis3A==",
- "requires": {
- "lru-cache": "^6.0.0"
- }
- }
- }
- },
- "supports-color": {
- "version": "5.5.0",
- "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz",
- "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==",
- "dev": true,
- "requires": {
- "has-flag": "^3.0.0"
- }
- },
- "tap": {
- "version": "15.0.9",
- "resolved": "https://registry.npmjs.org/tap/-/tap-15.0.9.tgz",
- "integrity": "sha512-bqY5SxEqYKRd37PIUfKBf9HMs/hklyl/fGXkuStr9rYTIGa0/icpSLsm6IVOmx2qT0/TliPNJ6OvS5kddJYHdg==",
- "dev": true,
- "requires": {
- "@types/react": "^16.9.23",
- "chokidar": "^3.3.0",
- "coveralls": "^3.0.11",
- "findit": "^2.0.0",
- "foreground-child": "^2.0.0",
- "fs-exists-cached": "^1.0.0",
- "glob": "^7.1.6",
- "import-jsx": "^4.0.0",
- "ink": "^2.7.1",
- "isexe": "^2.0.0",
- "istanbul-lib-processinfo": "^2.0.2",
- "jackspeak": "^1.4.0",
- "libtap": "^1.1.1",
- "minipass": "^3.1.1",
- "mkdirp": "^1.0.4",
- "nyc": "^15.1.0",
- "opener": "^1.5.1",
- "react": "^16.12.0",
- "rimraf": "^3.0.0",
- "signal-exit": "^3.0.0",
- "source-map-support": "^0.5.16",
- "tap-mocha-reporter": "^5.0.0",
- "tap-parser": "^10.0.1",
- "tap-yaml": "^1.0.0",
- "tcompare": "^5.0.6",
- "treport": "^2.0.2",
- "which": "^2.0.2"
- },
- "dependencies": {
- "@babel/code-frame": {
- "version": "7.12.13",
- "bundled": true,
- "dev": true,
- "requires": {
- "@babel/highlight": "^7.12.13"
- }
- },
- "@babel/compat-data": {
- "version": "7.14.0",
- "bundled": true,
- "dev": true
- },
- "@babel/core": {
- "version": "7.14.0",
- "bundled": true,
- "dev": true,
- "requires": {
- "@babel/code-frame": "^7.12.13",
- "@babel/generator": "^7.14.0",
- "@babel/helper-compilation-targets": "^7.13.16",
- "@babel/helper-module-transforms": "^7.14.0",
- "@babel/helpers": "^7.14.0",
- "@babel/parser": "^7.14.0",
- "@babel/template": "^7.12.13",
- "@babel/traverse": "^7.14.0",
- "@babel/types": "^7.14.0",
- "convert-source-map": "^1.7.0",
- "debug": "^4.1.0",
- "gensync": "^1.0.0-beta.2",
- "json5": "^2.1.2",
- "semver": "^6.3.0",
- "source-map": "^0.5.0"
- }
- },
- "@babel/generator": {
- "version": "7.14.1",
- "bundled": true,
- "dev": true,
- "requires": {
- "@babel/types": "^7.14.1",
- "jsesc": "^2.5.1",
- "source-map": "^0.5.0"
- }
- },
- "@babel/helper-annotate-as-pure": {
- "version": "7.12.13",
- "bundled": true,
- "dev": true,
- "requires": {
- "@babel/types": "^7.12.13"
- }
- },
- "@babel/helper-compilation-targets": {
- "version": "7.13.16",
- "bundled": true,
- "dev": true,
- "requires": {
- "@babel/compat-data": "^7.13.15",
- "@babel/helper-validator-option": "^7.12.17",
- "browserslist": "^4.14.5",
- "semver": "^6.3.0"
- }
- },
- "@babel/helper-function-name": {
- "version": "7.12.13",
- "bundled": true,
- "dev": true,
- "requires": {
- "@babel/helper-get-function-arity": "^7.12.13",
- "@babel/template": "^7.12.13",
- "@babel/types": "^7.12.13"
- }
- },
- "@babel/helper-get-function-arity": {
- "version": "7.12.13",
- "bundled": true,
- "dev": true,
- "requires": {
- "@babel/types": "^7.12.13"
- }
- },
- "@babel/helper-member-expression-to-functions": {
- "version": "7.13.12",
- "bundled": true,
- "dev": true,
- "requires": {
- "@babel/types": "^7.13.12"
- }
- },
- "@babel/helper-module-imports": {
- "version": "7.13.12",
- "bundled": true,
- "dev": true,
- "requires": {
- "@babel/types": "^7.13.12"
- }
- },
- "@babel/helper-module-transforms": {
- "version": "7.14.0",
- "bundled": true,
- "dev": true,
- "requires": {
- "@babel/helper-module-imports": "^7.13.12",
- "@babel/helper-replace-supers": "^7.13.12",
- "@babel/helper-simple-access": "^7.13.12",
- "@babel/helper-split-export-declaration": "^7.12.13",
- "@babel/helper-validator-identifier": "^7.14.0",
- "@babel/template": "^7.12.13",
- "@babel/traverse": "^7.14.0",
- "@babel/types": "^7.14.0"
- }
- },
- "@babel/helper-optimise-call-expression": {
- "version": "7.12.13",
- "bundled": true,
- "dev": true,
- "requires": {
- "@babel/types": "^7.12.13"
- }
- },
- "@babel/helper-plugin-utils": {
- "version": "7.13.0",
- "bundled": true,
- "dev": true
- },
- "@babel/helper-replace-supers": {
- "version": "7.13.12",
- "bundled": true,
- "dev": true,
- "requires": {
- "@babel/helper-member-expression-to-functions": "^7.13.12",
- "@babel/helper-optimise-call-expression": "^7.12.13",
- "@babel/traverse": "^7.13.0",
- "@babel/types": "^7.13.12"
- }
- },
- "@babel/helper-simple-access": {
- "version": "7.13.12",
- "bundled": true,
- "dev": true,
- "requires": {
- "@babel/types": "^7.13.12"
- }
- },
- "@babel/helper-split-export-declaration": {
- "version": "7.12.13",
- "bundled": true,
- "dev": true,
- "requires": {
- "@babel/types": "^7.12.13"
- }
- },
- "@babel/helper-validator-identifier": {
- "version": "7.14.0",
- "bundled": true,
- "dev": true
- },
- "@babel/helper-validator-option": {
- "version": "7.12.17",
- "bundled": true,
- "dev": true
- },
- "@babel/helpers": {
- "version": "7.14.0",
- "bundled": true,
- "dev": true,
- "requires": {
- "@babel/template": "^7.12.13",
- "@babel/traverse": "^7.14.0",
- "@babel/types": "^7.14.0"
- }
- },
- "@babel/highlight": {
- "version": "7.14.0",
- "bundled": true,
- "dev": true,
- "requires": {
- "@babel/helper-validator-identifier": "^7.14.0",
- "chalk": "^2.0.0",
- "js-tokens": "^4.0.0"
- }
- },
- "@babel/parser": {
- "version": "7.14.1",
- "bundled": true,
- "dev": true
- },
- "@babel/plugin-proposal-object-rest-spread": {
- "version": "7.13.8",
- "bundled": true,
- "dev": true,
- "requires": {
- "@babel/compat-data": "^7.13.8",
- "@babel/helper-compilation-targets": "^7.13.8",
- "@babel/helper-plugin-utils": "^7.13.0",
- "@babel/plugin-syntax-object-rest-spread": "^7.8.3",
- "@babel/plugin-transform-parameters": "^7.13.0"
- }
- },
- "@babel/plugin-syntax-jsx": {
- "version": "7.12.13",
- "bundled": true,
- "dev": true,
- "requires": {
- "@babel/helper-plugin-utils": "^7.12.13"
- }
- },
- "@babel/plugin-syntax-object-rest-spread": {
- "version": "7.8.3",
- "bundled": true,
- "dev": true,
- "requires": {
- "@babel/helper-plugin-utils": "^7.8.0"
- }
- },
- "@babel/plugin-transform-destructuring": {
- "version": "7.13.17",
- "bundled": true,
- "dev": true,
- "requires": {
- "@babel/helper-plugin-utils": "^7.13.0"
- }
- },
- "@babel/plugin-transform-parameters": {
- "version": "7.13.0",
- "bundled": true,
- "dev": true,
- "requires": {
- "@babel/helper-plugin-utils": "^7.13.0"
- }
- },
- "@babel/plugin-transform-react-jsx": {
- "version": "7.13.12",
- "bundled": true,
- "dev": true,
- "requires": {
- "@babel/helper-annotate-as-pure": "^7.12.13",
- "@babel/helper-module-imports": "^7.13.12",
- "@babel/helper-plugin-utils": "^7.13.0",
- "@babel/plugin-syntax-jsx": "^7.12.13",
- "@babel/types": "^7.13.12"
- }
- },
- "@babel/template": {
- "version": "7.12.13",
- "bundled": true,
- "dev": true,
- "requires": {
- "@babel/code-frame": "^7.12.13",
- "@babel/parser": "^7.12.13",
- "@babel/types": "^7.12.13"
- }
- },
- "@babel/traverse": {
- "version": "7.14.0",
- "bundled": true,
- "dev": true,
- "requires": {
- "@babel/code-frame": "^7.12.13",
- "@babel/generator": "^7.14.0",
- "@babel/helper-function-name": "^7.12.13",
- "@babel/helper-split-export-declaration": "^7.12.13",
- "@babel/parser": "^7.14.0",
- "@babel/types": "^7.14.0",
- "debug": "^4.1.0",
- "globals": "^11.1.0"
- }
- },
- "@babel/types": {
- "version": "7.14.1",
- "bundled": true,
- "dev": true,
- "requires": {
- "@babel/helper-validator-identifier": "^7.14.0",
- "to-fast-properties": "^2.0.0"
- }
- },
- "@types/prop-types": {
- "version": "15.7.3",
- "bundled": true,
- "dev": true
- },
- "@types/react": {
- "version": "16.14.6",
- "bundled": true,
- "dev": true,
- "requires": {
- "@types/prop-types": "*",
- "@types/scheduler": "*",
- "csstype": "^3.0.2"
- }
- },
- "@types/scheduler": {
- "version": "0.16.1",
- "bundled": true,
- "dev": true
- },
- "@types/yoga-layout": {
- "version": "1.9.2",
- "bundled": true,
- "dev": true
- },
- "ansi-escapes": {
- "version": "4.3.2",
- "bundled": true,
- "dev": true,
- "requires": {
- "type-fest": "^0.21.3"
- }
- },
- "ansi-styles": {
- "version": "3.2.1",
- "bundled": true,
- "dev": true,
- "requires": {
- "color-convert": "^1.9.0"
- }
- },
- "ansicolors": {
- "version": "0.3.2",
- "bundled": true,
- "dev": true
- },
- "arrify": {
- "version": "2.0.1",
- "bundled": true,
- "dev": true
- },
- "astral-regex": {
- "version": "2.0.0",
- "bundled": true,
- "dev": true
- },
- "auto-bind": {
- "version": "4.0.0",
- "bundled": true,
- "dev": true
- },
- "balanced-match": {
- "version": "1.0.2",
- "bundled": true,
- "dev": true
- },
- "brace-expansion": {
- "version": "1.1.11",
- "bundled": true,
- "dev": true,
- "requires": {
- "balanced-match": "^1.0.0",
- "concat-map": "0.0.1"
- }
- },
- "browserslist": {
- "version": "4.16.6",
- "bundled": true,
- "dev": true,
- "requires": {
- "caniuse-lite": "^1.0.30001219",
- "colorette": "^1.2.2",
- "electron-to-chromium": "^1.3.723",
- "escalade": "^3.1.1",
- "node-releases": "^1.1.71"
- }
- },
- "caller-callsite": {
- "version": "2.0.0",
- "bundled": true,
- "dev": true,
- "requires": {
- "callsites": "^2.0.0"
- }
- },
- "caller-path": {
- "version": "2.0.0",
- "bundled": true,
- "dev": true,
- "requires": {
- "caller-callsite": "^2.0.0"
- }
- },
- "callsites": {
- "version": "2.0.0",
- "bundled": true,
- "dev": true
- },
- "caniuse-lite": {
- "version": "1.0.30001223",
- "bundled": true,
- "dev": true
- },
- "cardinal": {
- "version": "2.1.1",
- "bundled": true,
- "dev": true,
- "requires": {
- "ansicolors": "~0.3.2",
- "redeyed": "~2.1.0"
- }
- },
- "chalk": {
- "version": "2.4.2",
- "bundled": true,
- "dev": true,
- "requires": {
- "ansi-styles": "^3.2.1",
- "escape-string-regexp": "^1.0.5",
- "supports-color": "^5.3.0"
- }
- },
- "ci-info": {
- "version": "2.0.0",
- "bundled": true,
- "dev": true
- },
- "cli-cursor": {
- "version": "3.1.0",
- "bundled": true,
- "dev": true,
- "requires": {
- "restore-cursor": "^3.1.0"
- }
- },
- "cli-truncate": {
- "version": "2.1.0",
- "bundled": true,
- "dev": true,
- "requires": {
- "slice-ansi": "^3.0.0",
- "string-width": "^4.2.0"
- }
- },
- "color-convert": {
- "version": "1.9.3",
- "bundled": true,
- "dev": true,
- "requires": {
- "color-name": "1.1.3"
- }
- },
- "color-name": {
- "version": "1.1.3",
- "bundled": true,
- "dev": true
- },
- "colorette": {
- "version": "1.2.2",
- "bundled": true,
- "dev": true
- },
- "commondir": {
- "version": "1.0.1",
- "bundled": true,
- "dev": true
- },
- "concat-map": {
- "version": "0.0.1",
- "bundled": true,
- "dev": true
- },
- "convert-source-map": {
- "version": "1.7.0",
- "bundled": true,
- "dev": true,
- "requires": {
- "safe-buffer": "~5.1.1"
- }
- },
- "csstype": {
- "version": "3.0.8",
- "bundled": true,
- "dev": true
- },
- "debug": {
- "version": "4.3.1",
- "bundled": true,
- "dev": true,
- "requires": {
- "ms": "2.1.2"
- }
- },
- "electron-to-chromium": {
- "version": "1.3.727",
- "bundled": true,
- "dev": true
- },
- "emoji-regex": {
- "version": "8.0.0",
- "bundled": true,
- "dev": true
- },
- "escalade": {
- "version": "3.1.1",
- "bundled": true,
- "dev": true
- },
- "escape-string-regexp": {
- "version": "1.0.5",
- "bundled": true,
- "dev": true
- },
- "esprima": {
- "version": "4.0.1",
- "bundled": true,
- "dev": true
- },
- "events-to-array": {
- "version": "1.1.2",
- "bundled": true,
- "dev": true
- },
- "find-cache-dir": {
- "version": "3.3.1",
- "bundled": true,
- "dev": true,
- "requires": {
- "commondir": "^1.0.1",
- "make-dir": "^3.0.2",
- "pkg-dir": "^4.1.0"
- }
- },
- "find-up": {
- "version": "4.1.0",
- "bundled": true,
- "dev": true,
- "requires": {
- "locate-path": "^5.0.0",
- "path-exists": "^4.0.0"
- }
- },
- "fs.realpath": {
- "version": "1.0.0",
- "bundled": true,
- "dev": true
- },
- "gensync": {
- "version": "1.0.0-beta.2",
- "bundled": true,
- "dev": true
- },
- "glob": {
- "version": "7.1.7",
- "bundled": true,
- "dev": true,
- "requires": {
- "fs.realpath": "^1.0.0",
- "inflight": "^1.0.4",
- "inherits": "2",
- "minimatch": "^3.0.4",
- "once": "^1.3.0",
- "path-is-absolute": "^1.0.0"
- }
- },
- "globals": {
- "version": "11.12.0",
- "bundled": true,
- "dev": true
- },
- "has-flag": {
- "version": "3.0.0",
- "bundled": true,
- "dev": true
- },
- "import-jsx": {
- "version": "4.0.0",
- "bundled": true,
- "dev": true,
- "requires": {
- "@babel/core": "^7.5.5",
- "@babel/plugin-proposal-object-rest-spread": "^7.5.5",
- "@babel/plugin-transform-destructuring": "^7.5.0",
- "@babel/plugin-transform-react-jsx": "^7.3.0",
- "caller-path": "^2.0.0",
- "find-cache-dir": "^3.2.0",
- "make-dir": "^3.0.2",
- "resolve-from": "^3.0.0",
- "rimraf": "^3.0.0"
- }
- },
- "inflight": {
- "version": "1.0.6",
- "bundled": true,
- "dev": true,
- "requires": {
- "once": "^1.3.0",
- "wrappy": "1"
- }
- },
- "inherits": {
- "version": "2.0.4",
- "bundled": true,
- "dev": true
- },
- "ink": {
- "version": "2.7.1",
- "bundled": true,
- "dev": true,
- "requires": {
- "ansi-escapes": "^4.2.1",
- "arrify": "^2.0.1",
- "auto-bind": "^4.0.0",
- "chalk": "^3.0.0",
- "cli-cursor": "^3.1.0",
- "cli-truncate": "^2.1.0",
- "is-ci": "^2.0.0",
- "lodash.throttle": "^4.1.1",
- "log-update": "^3.0.0",
- "prop-types": "^15.6.2",
- "react-reconciler": "^0.24.0",
- "scheduler": "^0.18.0",
- "signal-exit": "^3.0.2",
- "slice-ansi": "^3.0.0",
- "string-length": "^3.1.0",
- "widest-line": "^3.1.0",
- "wrap-ansi": "^6.2.0",
- "yoga-layout-prebuilt": "^1.9.3"
- },
- "dependencies": {
- "ansi-styles": {
- "version": "4.3.0",
- "bundled": true,
- "dev": true,
- "requires": {
- "color-convert": "^2.0.1"
- }
- },
- "chalk": {
- "version": "3.0.0",
- "bundled": true,
- "dev": true,
- "requires": {
- "ansi-styles": "^4.1.0",
- "supports-color": "^7.1.0"
- }
- },
- "color-convert": {
- "version": "2.0.1",
- "bundled": true,
- "dev": true,
- "requires": {
- "color-name": "~1.1.4"
- }
- },
- "color-name": {
- "version": "1.1.4",
- "bundled": true,
- "dev": true
- },
- "has-flag": {
- "version": "4.0.0",
- "bundled": true,
- "dev": true
- },
- "supports-color": {
- "version": "7.2.0",
- "bundled": true,
- "dev": true,
- "requires": {
- "has-flag": "^4.0.0"
- }
- }
- }
- },
- "is-ci": {
- "version": "2.0.0",
- "bundled": true,
- "dev": true,
- "requires": {
- "ci-info": "^2.0.0"
- }
- },
- "is-fullwidth-code-point": {
- "version": "3.0.0",
- "bundled": true,
- "dev": true
- },
- "js-tokens": {
- "version": "4.0.0",
- "bundled": true,
- "dev": true
- },
- "jsesc": {
- "version": "2.5.2",
- "bundled": true,
- "dev": true
- },
- "json5": {
- "version": "2.2.0",
- "bundled": true,
- "dev": true,
- "requires": {
- "minimist": "^1.2.5"
- }
- },
- "locate-path": {
- "version": "5.0.0",
- "bundled": true,
- "dev": true,
- "requires": {
- "p-locate": "^4.1.0"
- }
- },
- "lodash.throttle": {
- "version": "4.1.1",
- "bundled": true,
- "dev": true
- },
- "log-update": {
- "version": "3.4.0",
- "bundled": true,
- "dev": true,
- "requires": {
- "ansi-escapes": "^3.2.0",
- "cli-cursor": "^2.1.0",
- "wrap-ansi": "^5.0.0"
- },
- "dependencies": {
- "ansi-escapes": {
- "version": "3.2.0",
- "bundled": true,
- "dev": true
- },
- "ansi-regex": {
- "version": "4.1.0",
- "bundled": true,
- "dev": true
- },
- "cli-cursor": {
- "version": "2.1.0",
- "bundled": true,
- "dev": true,
- "requires": {
- "restore-cursor": "^2.0.0"
- }
- },
- "emoji-regex": {
- "version": "7.0.3",
- "bundled": true,
- "dev": true
- },
- "is-fullwidth-code-point": {
- "version": "2.0.0",
- "bundled": true,
- "dev": true
- },
- "mimic-fn": {
- "version": "1.2.0",
- "bundled": true,
- "dev": true
- },
- "onetime": {
- "version": "2.0.1",
- "bundled": true,
- "dev": true,
- "requires": {
- "mimic-fn": "^1.0.0"
- }
- },
- "restore-cursor": {
- "version": "2.0.0",
- "bundled": true,
- "dev": true,
- "requires": {
- "onetime": "^2.0.0",
- "signal-exit": "^3.0.2"
- }
- },
- "string-width": {
- "version": "3.1.0",
- "bundled": true,
- "dev": true,
- "requires": {
- "emoji-regex": "^7.0.1",
- "is-fullwidth-code-point": "^2.0.0",
- "strip-ansi": "^5.1.0"
- }
- },
- "strip-ansi": {
- "version": "5.2.0",
- "bundled": true,
- "dev": true,
- "requires": {
- "ansi-regex": "^4.1.0"
- }
- },
- "wrap-ansi": {
- "version": "5.1.0",
- "bundled": true,
- "dev": true,
- "requires": {
- "ansi-styles": "^3.2.0",
- "string-width": "^3.0.0",
- "strip-ansi": "^5.0.0"
- }
- }
- }
- },
- "loose-envify": {
- "version": "1.4.0",
- "bundled": true,
- "dev": true,
- "requires": {
- "js-tokens": "^3.0.0 || ^4.0.0"
- }
- },
- "make-dir": {
- "version": "3.1.0",
- "bundled": true,
- "dev": true,
- "requires": {
- "semver": "^6.0.0"
- }
- },
- "mimic-fn": {
- "version": "2.1.0",
- "bundled": true,
- "dev": true
- },
- "minimatch": {
- "version": "3.0.4",
- "bundled": true,
- "dev": true,
- "requires": {
- "brace-expansion": "^1.1.7"
- }
- },
- "minimist": {
- "version": "1.2.5",
- "bundled": true,
- "dev": true
- },
- "minipass": {
- "version": "3.1.3",
- "bundled": true,
- "dev": true,
- "requires": {
- "yallist": "^4.0.0"
- }
- },
- "mkdirp": {
- "version": "1.0.4",
- "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz",
- "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==",
- "dev": true
- },
- "ms": {
- "version": "2.1.2",
- "bundled": true,
- "dev": true
- },
- "node-releases": {
- "version": "1.1.71",
- "bundled": true,
- "dev": true
- },
- "object-assign": {
- "version": "4.1.1",
- "bundled": true,
- "dev": true
- },
- "once": {
- "version": "1.4.0",
- "bundled": true,
- "dev": true,
- "requires": {
- "wrappy": "1"
- }
- },
- "onetime": {
- "version": "5.1.2",
- "bundled": true,
- "dev": true,
- "requires": {
- "mimic-fn": "^2.1.0"
- }
- },
- "p-limit": {
- "version": "2.3.0",
- "bundled": true,
- "dev": true,
- "requires": {
- "p-try": "^2.0.0"
- }
- },
- "p-locate": {
- "version": "4.1.0",
- "bundled": true,
- "dev": true,
- "requires": {
- "p-limit": "^2.2.0"
- }
- },
- "p-try": {
- "version": "2.2.0",
- "bundled": true,
- "dev": true
- },
- "path-exists": {
- "version": "4.0.0",
- "bundled": true,
- "dev": true
- },
- "path-is-absolute": {
- "version": "1.0.1",
- "bundled": true,
- "dev": true
- },
- "pkg-dir": {
- "version": "4.2.0",
- "bundled": true,
- "dev": true,
- "requires": {
- "find-up": "^4.0.0"
- }
- },
- "prop-types": {
- "version": "15.7.2",
- "bundled": true,
- "dev": true,
- "requires": {
- "loose-envify": "^1.4.0",
- "object-assign": "^4.1.1",
- "react-is": "^16.8.1"
- }
- },
- "punycode": {
- "version": "2.1.1",
- "bundled": true,
- "dev": true
- },
- "react-is": {
- "version": "16.13.1",
- "bundled": true,
- "dev": true
- },
- "react-reconciler": {
- "version": "0.24.0",
- "bundled": true,
- "dev": true,
- "requires": {
- "loose-envify": "^1.1.0",
- "object-assign": "^4.1.1",
- "prop-types": "^15.6.2",
- "scheduler": "^0.18.0"
- }
- },
- "redeyed": {
- "version": "2.1.1",
- "bundled": true,
- "dev": true,
- "requires": {
- "esprima": "~4.0.0"
- }
- },
- "resolve-from": {
- "version": "3.0.0",
- "bundled": true,
- "dev": true
- },
- "restore-cursor": {
- "version": "3.1.0",
- "bundled": true,
- "dev": true,
- "requires": {
- "onetime": "^5.1.0",
- "signal-exit": "^3.0.2"
- }
- },
- "rimraf": {
- "version": "3.0.2",
- "bundled": true,
- "dev": true,
- "requires": {
- "glob": "^7.1.3"
- }
- },
- "safe-buffer": {
- "version": "5.1.2",
- "bundled": true,
- "dev": true
- },
- "scheduler": {
- "version": "0.18.0",
- "bundled": true,
- "dev": true,
- "requires": {
- "loose-envify": "^1.1.0",
- "object-assign": "^4.1.1"
- }
- },
- "semver": {
- "version": "6.3.0",
- "bundled": true,
- "dev": true
- },
- "signal-exit": {
- "version": "3.0.3",
- "bundled": true,
- "dev": true
- },
- "slice-ansi": {
- "version": "3.0.0",
- "bundled": true,
- "dev": true,
- "requires": {
- "ansi-styles": "^4.0.0",
- "astral-regex": "^2.0.0",
- "is-fullwidth-code-point": "^3.0.0"
- },
- "dependencies": {
- "ansi-styles": {
- "version": "4.3.0",
- "bundled": true,
- "dev": true,
- "requires": {
- "color-convert": "^2.0.1"
- }
- },
- "color-convert": {
- "version": "2.0.1",
- "bundled": true,
- "dev": true,
- "requires": {
- "color-name": "~1.1.4"
- }
- },
- "color-name": {
- "version": "1.1.4",
- "bundled": true,
- "dev": true
- }
- }
- },
- "source-map": {
- "version": "0.5.7",
- "bundled": true,
- "dev": true
- },
- "string-length": {
- "version": "3.1.0",
- "bundled": true,
- "dev": true,
- "requires": {
- "astral-regex": "^1.0.0",
- "strip-ansi": "^5.2.0"
- },
- "dependencies": {
- "ansi-regex": {
- "version": "4.1.0",
- "bundled": true,
- "dev": true
- },
- "astral-regex": {
- "version": "1.0.0",
- "bundled": true,
- "dev": true
- },
- "strip-ansi": {
- "version": "5.2.0",
- "bundled": true,
- "dev": true,
- "requires": {
- "ansi-regex": "^4.1.0"
- }
- }
- }
- },
- "string-width": {
- "version": "4.2.2",
- "bundled": true,
- "dev": true,
- "requires": {
- "emoji-regex": "^8.0.0",
- "is-fullwidth-code-point": "^3.0.0",
- "strip-ansi": "^6.0.0"
- },
- "dependencies": {
- "ansi-regex": {
- "version": "5.0.0",
- "bundled": true,
- "dev": true
- },
- "strip-ansi": {
- "version": "6.0.0",
- "bundled": true,
- "dev": true,
- "requires": {
- "ansi-regex": "^5.0.0"
- }
- }
- }
- },
- "supports-color": {
- "version": "5.5.0",
- "bundled": true,
- "dev": true,
- "requires": {
- "has-flag": "^3.0.0"
- }
- },
- "tap-parser": {
- "version": "10.1.0",
- "bundled": true,
- "dev": true,
- "requires": {
- "events-to-array": "^1.0.1",
- "minipass": "^3.0.0",
- "tap-yaml": "^1.0.0"
- }
- },
- "tap-yaml": {
- "version": "1.0.0",
- "bundled": true,
- "dev": true,
- "requires": {
- "yaml": "^1.5.0"
- }
- },
- "to-fast-properties": {
- "version": "2.0.0",
- "bundled": true,
- "dev": true
- },
- "treport": {
- "version": "2.0.2",
- "bundled": true,
- "dev": true,
- "requires": {
- "cardinal": "^2.1.1",
- "chalk": "^3.0.0",
- "import-jsx": "^4.0.0",
- "ink": "^2.6.0",
- "ms": "^2.1.2",
- "string-length": "^3.1.0",
- "tap-parser": "^10.0.1",
- "unicode-length": "^2.0.2"
- },
- "dependencies": {
- "ansi-styles": {
- "version": "4.3.0",
- "bundled": true,
- "dev": true,
- "requires": {
- "color-convert": "^2.0.1"
- }
- },
- "chalk": {
- "version": "3.0.0",
- "bundled": true,
- "dev": true,
- "requires": {
- "ansi-styles": "^4.1.0",
- "supports-color": "^7.1.0"
- }
- },
- "color-convert": {
- "version": "2.0.1",
- "bundled": true,
- "dev": true,
- "requires": {
- "color-name": "~1.1.4"
- }
- },
- "color-name": {
- "version": "1.1.4",
- "bundled": true,
- "dev": true
- },
- "has-flag": {
- "version": "4.0.0",
- "bundled": true,
- "dev": true
- },
- "supports-color": {
- "version": "7.2.0",
- "bundled": true,
- "dev": true,
- "requires": {
- "has-flag": "^4.0.0"
- }
- }
- }
- },
- "type-fest": {
- "version": "0.21.3",
- "bundled": true,
- "dev": true
- },
- "unicode-length": {
- "version": "2.0.2",
- "bundled": true,
- "dev": true,
- "requires": {
- "punycode": "^2.0.0",
- "strip-ansi": "^3.0.1"
- },
- "dependencies": {
- "ansi-regex": {
- "version": "2.1.1",
- "bundled": true,
- "dev": true
- },
- "strip-ansi": {
- "version": "3.0.1",
- "bundled": true,
- "dev": true,
- "requires": {
- "ansi-regex": "^2.0.0"
- }
- }
- }
- },
- "widest-line": {
- "version": "3.1.0",
- "bundled": true,
- "dev": true,
- "requires": {
- "string-width": "^4.0.0"
- }
- },
- "wrap-ansi": {
- "version": "6.2.0",
- "bundled": true,
- "dev": true,
- "requires": {
- "ansi-styles": "^4.0.0",
- "string-width": "^4.1.0",
- "strip-ansi": "^6.0.0"
- },
- "dependencies": {
- "ansi-regex": {
- "version": "5.0.0",
- "bundled": true,
- "dev": true
- },
- "ansi-styles": {
- "version": "4.3.0",
- "bundled": true,
- "dev": true,
- "requires": {
- "color-convert": "^2.0.1"
- }
- },
- "color-convert": {
- "version": "2.0.1",
- "bundled": true,
- "dev": true,
- "requires": {
- "color-name": "~1.1.4"
- }
- },
- "color-name": {
- "version": "1.1.4",
- "bundled": true,
- "dev": true
- },
- "strip-ansi": {
- "version": "6.0.0",
- "bundled": true,
- "dev": true,
- "requires": {
- "ansi-regex": "^5.0.0"
- }
- }
- }
- },
- "wrappy": {
- "version": "1.0.2",
- "bundled": true,
- "dev": true
- },
- "yallist": {
- "version": "4.0.0",
- "bundled": true,
- "dev": true
- },
- "yaml": {
- "version": "1.10.2",
- "bundled": true,
- "dev": true
- },
- "yoga-layout-prebuilt": {
- "version": "1.10.0",
- "bundled": true,
- "dev": true,
- "requires": {
- "@types/yoga-layout": "1.9.2"
- }
- }
- }
- },
- "tap-mocha-reporter": {
- "version": "5.0.1",
- "resolved": "https://registry.npmjs.org/tap-mocha-reporter/-/tap-mocha-reporter-5.0.1.tgz",
- "integrity": "sha512-1knFWOwd4khx/7uSEnUeaP9IPW3w+sqTgJMhrwah6t46nZ8P25atOKAjSvVDsT67lOPu0nfdOqUwoyKn+3E5pA==",
- "dev": true,
- "requires": {
- "color-support": "^1.1.0",
- "debug": "^4.1.1",
- "diff": "^4.0.1",
- "escape-string-regexp": "^2.0.0",
- "glob": "^7.0.5",
- "tap-parser": "^10.0.0",
- "tap-yaml": "^1.0.0",
- "unicode-length": "^2.0.2"
- },
- "dependencies": {
- "debug": {
- "version": "4.3.2",
- "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.2.tgz",
- "integrity": "sha512-mOp8wKcvj7XxC78zLgw/ZA+6TSgkoE2C/ienthhRD298T7UNwAg9diBpLRxC0mOezLl4B0xV7M0cCO6P/O0Xhw==",
- "dev": true,
- "requires": {
- "ms": "2.1.2"
- }
- },
- "ms": {
- "version": "2.1.2",
- "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
- "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==",
- "dev": true
- }
- }
- },
- "tap-parser": {
- "version": "10.1.0",
- "resolved": "https://registry.npmjs.org/tap-parser/-/tap-parser-10.1.0.tgz",
- "integrity": "sha512-FujQeciDaOiOvaIVGS1Rpb0v4R6XkOjvWCWowlz5oKuhPkEJ8U6pxgqt38xuzYhPt8dWEnfHn2jqpZdJEkW7pA==",
- "dev": true,
- "requires": {
- "events-to-array": "^1.0.1",
- "minipass": "^3.0.0",
- "tap-yaml": "^1.0.0"
- }
- },
- "tap-yaml": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/tap-yaml/-/tap-yaml-1.0.0.tgz",
- "integrity": "sha512-Rxbx4EnrWkYk0/ztcm5u3/VznbyFJpyXO12dDBHKWiDVxy7O2Qw6MRrwO5H6Ww0U5YhRY/4C/VzWmFPhBQc4qQ==",
- "dev": true,
- "requires": {
- "yaml": "^1.5.0"
- }
- },
- "tcompare": {
- "version": "5.0.6",
- "resolved": "https://registry.npmjs.org/tcompare/-/tcompare-5.0.6.tgz",
- "integrity": "sha512-OvO7omN/wkdsKzmOqr3sQFfLbghs/2X5mwSkcfgRiXZshfPnTsAs3IRf1RixR/Pff26qG/r9ogcZMpV0YdeGXg==",
- "dev": true,
- "requires": {
- "diff": "^4.0.2"
- }
- },
- "test-exclude": {
- "version": "6.0.0",
- "resolved": "https://registry.npmjs.org/test-exclude/-/test-exclude-6.0.0.tgz",
- "integrity": "sha512-cAGWPIyOHU6zlmg88jwm7VRyXnMN7iV68OGAbYDk/Mh/xC/pzVPlQtY6ngoIH/5/tciuhGfvESU8GrHrcxD56w==",
- "dev": true,
- "requires": {
- "@istanbuljs/schema": "^0.1.2",
- "glob": "^7.1.4",
- "minimatch": "^3.0.4"
- }
- },
- "tiny-emitter": {
- "version": "2.1.0",
- "resolved": "https://registry.npmjs.org/tiny-emitter/-/tiny-emitter-2.1.0.tgz",
- "integrity": "sha512-NB6Dk1A9xgQPMoGqC5CVXn123gWyte215ONT5Pp5a0yt4nlEoO1ZWeCwpncaekPHXO60i47ihFnZPiRPjRMq4Q=="
- },
- "to-fast-properties": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz",
- "integrity": "sha1-3F5pjL0HkmW8c+A3doGk5Og/YW4=",
- "dev": true
- },
- "to-regex-range": {
- "version": "5.0.1",
- "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz",
- "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==",
- "dev": true,
- "requires": {
- "is-number": "^7.0.0"
- }
- },
- "toidentifier": {
- "version": "1.0.1",
- "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz",
- "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA=="
- },
- "tough-cookie": {
- "version": "2.5.0",
- "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.5.0.tgz",
- "integrity": "sha512-nlLsUzgm1kfLXSXfRZMc1KLAugd4hqJHDTvc2hDIwS3mZAfMEuMbc03SujMF+GEcpaX/qboeycw6iO8JwVv2+g==",
- "dev": true,
- "requires": {
- "psl": "^1.1.28",
- "punycode": "^2.1.1"
- }
- },
- "trivial-deferred": {
- "version": "1.0.1",
- "resolved": "https://registry.npmjs.org/trivial-deferred/-/trivial-deferred-1.0.1.tgz",
- "integrity": "sha1-N21NKdlR1jaKb3oK6FwvTV4GWPM=",
- "dev": true
- },
- "tunnel-agent": {
- "version": "0.6.0",
- "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz",
- "integrity": "sha1-J6XeoGs2sEoKmWZ3SykIaPD8QP0=",
- "dev": true,
- "requires": {
- "safe-buffer": "^5.0.1"
- }
- },
- "tweetnacl": {
- "version": "0.14.5",
- "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.5.tgz",
- "integrity": "sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q=",
- "dev": true
- },
- "type-fest": {
- "version": "0.8.1",
- "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.8.1.tgz",
- "integrity": "sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA==",
- "dev": true
- },
- "type-is": {
- "version": "1.6.18",
- "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz",
- "integrity": "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==",
- "requires": {
- "media-typer": "0.3.0",
- "mime-types": "~2.1.24"
- }
- },
- "typed-function": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/typed-function/-/typed-function-2.0.0.tgz",
- "integrity": "sha512-Hhy1Iwo/e4AtLZNK10ewVVcP2UEs408DS35ubP825w/YgSBK1KVLwALvvIG4yX75QJrxjCpcWkzkVRB0BwwYlA=="
- },
- "typedarray-to-buffer": {
- "version": "3.1.5",
- "resolved": "https://registry.npmjs.org/typedarray-to-buffer/-/typedarray-to-buffer-3.1.5.tgz",
- "integrity": "sha512-zdu8XMNEDepKKR+XYOXAVPtWui0ly0NtohUscw+UmaHiAWT8hrV1rr//H6V+0DvJ3OQ19S979M0laLfX8rm82Q==",
- "dev": true,
- "requires": {
- "is-typedarray": "^1.0.0"
- }
- },
- "unicode-length": {
- "version": "2.0.2",
- "resolved": "https://registry.npmjs.org/unicode-length/-/unicode-length-2.0.2.tgz",
- "integrity": "sha512-Ph/j1VbS3/r77nhoY2WU0GWGjVYOHL3xpKp0y/Eq2e5r0mT/6b649vm7KFO6RdAdrZkYLdxphYVgvODxPB+Ebg==",
- "dev": true,
- "requires": {
- "punycode": "^2.0.0",
- "strip-ansi": "^3.0.1"
- },
- "dependencies": {
- "ansi-regex": {
- "version": "2.1.1",
- "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz",
- "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=",
- "dev": true
- },
- "strip-ansi": {
- "version": "3.0.1",
- "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz",
- "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=",
- "dev": true,
- "requires": {
- "ansi-regex": "^2.0.0"
- }
- }
- }
- },
- "unpipe": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz",
- "integrity": "sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ=="
- },
- "uri-js": {
- "version": "4.4.1",
- "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz",
- "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==",
- "dev": true,
- "requires": {
- "punycode": "^2.1.0"
- }
- },
- "utils-merge": {
- "version": "1.0.1",
- "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz",
- "integrity": "sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA=="
- },
- "uuid": {
- "version": "3.4.0",
- "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.4.0.tgz",
- "integrity": "sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==",
- "dev": true
- },
- "vary": {
- "version": "1.1.2",
- "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz",
- "integrity": "sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg=="
- },
- "verror": {
- "version": "1.10.0",
- "resolved": "https://registry.npmjs.org/verror/-/verror-1.10.0.tgz",
- "integrity": "sha1-OhBcoXBTr1XW4nDB+CiGguGNpAA=",
- "dev": true,
- "requires": {
- "assert-plus": "^1.0.0",
- "core-util-is": "1.0.2",
- "extsprintf": "^1.2.0"
- }
- },
- "which": {
- "version": "2.0.2",
- "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz",
- "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==",
- "dev": true,
- "requires": {
- "isexe": "^2.0.0"
- }
- },
- "which-module": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/which-module/-/which-module-2.0.0.tgz",
- "integrity": "sha1-2e8H3Od7mQK4o6j6SzHD4/fm6Ho=",
- "dev": true
- },
- "wrap-ansi": {
- "version": "2.1.0",
- "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-2.1.0.tgz",
- "integrity": "sha1-2Pw9KE3QV5T+hJc8rs3Rz4JP3YU=",
- "dev": true,
- "requires": {
- "string-width": "^1.0.1",
- "strip-ansi": "^3.0.1"
- },
- "dependencies": {
- "ansi-regex": {
- "version": "2.1.1",
- "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz",
- "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=",
- "dev": true
- },
- "is-fullwidth-code-point": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz",
- "integrity": "sha1-754xOG8DGn8NZDr4L95QxFfvAMs=",
- "dev": true,
- "requires": {
- "number-is-nan": "^1.0.0"
- }
- },
- "string-width": {
- "version": "1.0.2",
- "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz",
- "integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=",
- "dev": true,
- "requires": {
- "code-point-at": "^1.0.0",
- "is-fullwidth-code-point": "^1.0.0",
- "strip-ansi": "^3.0.0"
- }
- },
- "strip-ansi": {
- "version": "3.0.1",
- "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz",
- "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=",
- "dev": true,
- "requires": {
- "ansi-regex": "^2.0.0"
- }
- }
- }
- },
- "wrappy": {
- "version": "1.0.2",
- "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz",
- "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8="
- },
- "write-file-atomic": {
- "version": "3.0.3",
- "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-3.0.3.tgz",
- "integrity": "sha512-AvHcyZ5JnSfq3ioSyjrBkH9yW4m7Ayk8/9My/DD9onKeu/94fwrMocemO2QAJFAlnnDN+ZDS+ZjAR5ua1/PV/Q==",
- "dev": true,
- "requires": {
- "imurmurhash": "^0.1.4",
- "is-typedarray": "^1.0.0",
- "signal-exit": "^3.0.2",
- "typedarray-to-buffer": "^3.1.5"
- }
- },
- "y18n": {
- "version": "4.0.3",
- "resolved": "https://registry.npmjs.org/y18n/-/y18n-4.0.3.tgz",
- "integrity": "sha512-JKhqTOwSrqNA1NY5lSztJ1GrBiUodLMmIZuLiDaMRJ+itFd+ABVE8XBjOvIWL+rSqNDC74LCSFmlb/U4UZ4hJQ==",
- "dev": true
- },
- "yallist": {
- "version": "4.0.0",
- "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz",
- "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A=="
- },
- "yaml": {
- "version": "1.10.2",
- "resolved": "https://registry.npmjs.org/yaml/-/yaml-1.10.2.tgz",
- "integrity": "sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg==",
- "dev": true
- },
- "yapool": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/yapool/-/yapool-1.0.0.tgz",
- "integrity": "sha1-9pPymjFbUNmp2iZGp6ZkXJaYW2o=",
- "dev": true
- },
- "yargs": {
- "version": "15.4.1",
- "resolved": "https://registry.npmjs.org/yargs/-/yargs-15.4.1.tgz",
- "integrity": "sha512-aePbxDmcYW++PaqBsJ+HYUFwCdv4LVvdnhBy78E57PIor8/OVvhMrADFFEDh8DHDFRv/O9i3lPhsENjO7QX0+A==",
- "dev": true,
- "requires": {
- "cliui": "^6.0.0",
- "decamelize": "^1.2.0",
- "find-up": "^4.1.0",
- "get-caller-file": "^2.0.1",
- "require-directory": "^2.1.1",
- "require-main-filename": "^2.0.0",
- "set-blocking": "^2.0.0",
- "string-width": "^4.2.0",
- "which-module": "^2.0.0",
- "y18n": "^4.0.0",
- "yargs-parser": "^18.1.2"
- },
- "dependencies": {
- "ansi-regex": {
- "version": "5.0.0",
- "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.0.tgz",
- "integrity": "sha512-bY6fj56OUQ0hU1KjFNDQuJFezqKdrAyFdIevADiqrWHwSlbmBNMHp5ak2f40Pm8JTFyM2mqxkG6ngkHO11f/lg==",
- "dev": true
- },
- "ansi-styles": {
- "version": "4.3.0",
- "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
- "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
- "dev": true,
- "requires": {
- "color-convert": "^2.0.1"
- }
- },
- "cliui": {
- "version": "6.0.0",
- "resolved": "https://registry.npmjs.org/cliui/-/cliui-6.0.0.tgz",
- "integrity": "sha512-t6wbgtoCXvAzst7QgXxJYqPt0usEfbgQdftEPbLL/cvv6HPE5VgvqCuAIDR0NgU52ds6rFwqrgakNLrHEjCbrQ==",
- "dev": true,
- "requires": {
- "string-width": "^4.2.0",
- "strip-ansi": "^6.0.0",
- "wrap-ansi": "^6.2.0"
- }
- },
- "color-convert": {
- "version": "2.0.1",
- "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
- "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
- "dev": true,
- "requires": {
- "color-name": "~1.1.4"
- }
- },
- "color-name": {
- "version": "1.1.4",
- "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
- "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
- "dev": true
- },
- "is-fullwidth-code-point": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz",
- "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==",
- "dev": true
- },
- "string-width": {
- "version": "4.2.2",
- "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.2.tgz",
- "integrity": "sha512-XBJbT3N4JhVumXE0eoLU9DCjcaF92KLNqTmFCnG1pf8duUxFGwtP6AD6nkjw9a3IdiRtL3E2w3JDiE/xi3vOeA==",
- "dev": true,
- "requires": {
- "emoji-regex": "^8.0.0",
- "is-fullwidth-code-point": "^3.0.0",
- "strip-ansi": "^6.0.0"
- }
- },
- "strip-ansi": {
- "version": "6.0.0",
- "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.0.tgz",
- "integrity": "sha512-AuvKTrTfQNYNIctbR1K/YGTR1756GycPsg7b9bdV9Duqur4gv6aKqHXah67Z8ImS7WEz5QVcOtlfW2rZEugt6w==",
- "dev": true,
- "requires": {
- "ansi-regex": "^5.0.0"
- }
- },
- "wrap-ansi": {
- "version": "6.2.0",
- "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-6.2.0.tgz",
- "integrity": "sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==",
- "dev": true,
- "requires": {
- "ansi-styles": "^4.0.0",
- "string-width": "^4.1.0",
- "strip-ansi": "^6.0.0"
- }
- }
- }
- },
- "yargs-parser": {
- "version": "18.1.3",
- "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-18.1.3.tgz",
- "integrity": "sha512-o50j0JeToy/4K6OZcaQmW6lyXXKhq7csREXcDwk2omFPJEwUNOVtJKvmDr9EI1fAJZUyZcRF7kxGBWmRXudrCQ==",
- "dev": true,
- "requires": {
- "camelcase": "^5.0.0",
- "decamelize": "^1.2.0"
- }
- }
- }
- }
package.json
Changed around line 1
- "version": "2.0.0",
+ "version": "3.0.0",
Changed around line 26
- "minimist": "^1.2.5"
- },
- "devDependencies": {
- "tap": "^15.0.9"
+ "minimist": "^1.2.5",
+ "tap": "^16.3.4"
releaseNotes.scroll
Changed around line 4: startColumns
+ # 3.0.0 4-12-2023
+ * A big rewrite to a new grid system.
+ - 🎉 new collision engine and coordinate system. agents can change size and move in any direction (unit vectors over cardinality).
+ - ⚠️ breaking: "neighbors" concept is gone. game of life demos removed. use old version to use those.
+
- 🎉 fill command
- 🎉 kickIt behaves a little smarter
server.js
Changed around line 1
+ const path = require("path")
+ const { Disk } = require("jtree/products/Disk.node.js")
- const stamp = require("jtree/products/stamp.nodejs.js")
- const { TreeNode } = require("jtree/products/TreeNode.js")
+ const grammarParser = require("jtree/products/grammar.nodejs.js")
Changed around line 30: class Server {
+ app.get("/examples", (req, res) => {
+ res.send(getExamples())
+ })
+
+ app.get("/dist/simoji.grammar", (req, res) => {
+ res.send(this.grammar)
+ })
+
+
+ get grammar() {
+ const asOneFile = Disk.getFiles(path.join(__dirname, "grammar"))
+ .filter(file => file.endsWith(".grammar"))
+ .map(filePath => Disk.read(filePath))
+ .join("\n\n")
+ .trim()
+ return new grammarParser(asOneFile)._sortNodesByInScopeOrder()._sortWithParentParsersUpTop().asString
+ }
- const server = new Server()
- server.start()
+ if (!module.parent) new Server().start()
+ module.exports = { Server }
simoji.css
Changed around line 207: body {
+ z-index: 1;
+ user-select: none;
+ cursor: pointer;
+ }
+
+ .Agent:hover {
+ background-color: rgba(0, 0, 0, 0.2);
+ border-radius: 3px;
testAll.js
Changed around line 1
- const runTree = testTree => {
- const tap = require("tap")
- Object.keys(testTree).forEach(key => {
- testTree[key](tap.equal)
- })
- }
+ #! /usr/bin/env node
+
+ const { TestRacer } = require("jtree/products/TestRacer.js")
- runTree({ ...require("./yodash.test.node.js").testTree, ...require("./components/SimojiApp.test.node.js").testTree })
+ const testAll = async () => {
+ const fileTree = {}
+ let folders = `./yodash.test.node.js
+ ./components/SimojiApp.test.node.js
+ ./components/Board.test.node.js
+ ./components/CollisionDetector.test.node.js`
+ .split("\n")
+ .forEach(file => (fileTree[file] = require(file).testTree))
+ const runner = new TestRacer(fileTree)
+ await runner.execute()
+ runner.finish()
+ }
+ testAll()
yodash.js
Changed around line 1
- const lodash = require("lodash")
- const { Directions, ParserTypes } = require("./components/Types.js")
-
- yodash.parseInts = (arr, start) => arr.map((item, index) => (index >= start ? parseInt(item) : item))
-
- yodash.getRandomAngle = randomNumberGenerator => {
- const r1 = randomNumberGenerator()
- const r2 = randomNumberGenerator()
- if (r1 > 0.5) return r2 > 0.5 ? Directions.North : Directions.South
- return r2 > 0.5 ? Directions.West : Directions.East
- }
-
- yodash.flipAngle = angle => {
- let newAngle = ""
- if (angle.includes(Directions.North)) newAngle += Directions.South
- else if (angle.includes(Directions.South)) newAngle += Directions.North
- if (angle.includes(Directions.East)) newAngle += Directions.West
- else if (angle.includes(Directions.West)) newAngle += Directions.East
- return newAngle
- }
+ const { ParserTypes } = require("./components/Types.js")
Changed around line 13: yodash.compare = (left, operator, right) => {
+ // Todo: why do we do this? Very confusing. Caught me by surprise.
+ // Is it because sometimes the class name is not valid JS?
- const clone = program.clone()
- clone.filter(node => node.parserId !== ParserTypes.agentDefinitionParser).forEach(node => node.destroy())
- clone.agentKeywordMap = {}
- clone.agentTypes.forEach((node, index) => (clone.agentKeywordMap[node.firstWord] = `simAgent${index}`))
- const compiled = clone.compile()
- const agentMap = Object.keys(clone.agentKeywordMap)
- .map(key => `"${key}":${clone.agentKeywordMap[key]}`)
+ const agentKeywordMap = {}
+ program.agentKeywordMap = agentKeywordMap // confusing
+ const agentDefs = program.filter(node => node.parserId === ParserTypes.agentDefinitionParser)
+ agentDefs.forEach((node, index) => (agentKeywordMap[node.firstWord] = `simAgent${index}`))
+ const compiled = agentDefs.map(node => node.compile()).join("\n")
+ const agentMap = Object.keys(agentKeywordMap)
+ .map(key => `"${key}":${agentKeywordMap[key]}`)
Changed around line 51: yodash.patchExperimentAndReplaceSymbols = (program, experiment) => {
- yodash.getBestAngle = (targets, position) => {
+ yodash.getClosest = (targets, subject) => {
- targets.forEach(candidate => {
- const pos = candidate.position
- const distance = math.distance([pos.down, pos.right], [position.down, position.right])
+ targets.forEach(agent => {
+ if (agent === subject) return
+ const distance = math.distance([agent.y, agent.x], [subject.y, subject.x])
- target = candidate
+ target = agent
- const heading = target.position
- return yodash.angle(position.down, position.right, heading.down, heading.right)
+ return target
- yodash.angle = (cx, cy, ex, ey) => {
- const dy = ey - cy
- const dx = ex - cx
- let theta = Math.atan2(dy, dx) // range (-PI, PI]
- theta *= 180 / Math.PI // rads to degs, range (-180, 180]
- //if (theta < 0) theta = 360 + theta; // range [0, 360)
- let angle = ""
-
- if (Math.abs(theta) > 90) angle += Directions.North
- else angle += Directions.South
- if (theta < 0) angle += Directions.West
- else angle += Directions.East
- return angle
- }
-
- yodash.getRandomLocation = (rows, cols, randomNumberGenerator) => {
- const maxRight = cols
- const maxBottom = rows
- const right = Math.round(randomNumberGenerator() * maxRight)
- const down = Math.round(randomNumberGenerator() * maxBottom)
- return { right, down }
- }
-
- yodash.getRandomLocationHash = (rows, cols, occupiedSpots, randomNumberGenerator) => {
- const { right, down } = yodash.getRandomLocation(rows, cols, randomNumberGenerator)
- const hash = yodash.makePositionHash({ right, down })
- if (occupiedSpots && occupiedSpots.has(hash))
- return yodash.getRandomLocationHash(rows, cols, occupiedSpots, randomNumberGenerator)
- return hash
- }
-
- yodash.fill = (rows, cols, occupiedSpots, emoji) => {
- const board = []
- while (rows >= 0) {
- let col = cols
- while (col >= 0) {
- const hash = yodash.makePositionHash({ right: col, down: rows })
- col--
- if (occupiedSpots.has(hash)) continue
- board.push(`${emoji} ${hash}`)
- }
- rows--
+ yodash.unitVector = (objA, objB) => {
+ // calculate direction vector (delta)
+ const delta = {
+ x: objB.x - objA.x,
+ y: objB.y - objA.y
- return board.join("\n")
- }
- yodash.positionsAdjacentTo = position => {
- let { right, down } = position
- const positions = []
- down--
- positions.push({ down, right })
- right--
- positions.push({ down, right })
- right++
- right++
- positions.push({ down, right })
- down++
- positions.push({ down, right })
- right--
- right--
- positions.push({ down, right })
- down++
- positions.push({ down, right })
- right++
- positions.push({ down, right })
- right++
- positions.push({ down, right })
- return positions
- }
-
- yodash.makePositionHash = position => `${position.down + "⬇️ " + position.right + "➡️"}`
+ // calculate magnitude of delta (distance between two points)
+ const magDelta = Math.sqrt(delta.x * delta.x + delta.y * delta.y)
- yodash.makeRectangle = (character = "🧱", width = 20, height = 20, startRight = 0, startDown = 0) => {
- if (width < 1 || height < 1) {
- return ""
- }
- const cells = []
- let row = 0
- while (row < height) {
- let col = 0
- while (col < width) {
- const isPerimeter = row === 0 || row === height - 1 || col === 0 || col === width - 1
- if (isPerimeter)
- cells.push(
- `${character} ${yodash.makePositionHash({
- down: startDown + row,
- right: startRight + col
- })}`
- )
- col++
- }
- row++
- }
- return cells.join("\n")
- }
-
- yodash.parsePosition = words => {
+ // calculate unit vector (normalize direction vector by dividing by magnitude)
- down: parseInt(words.find(word => word.includes("⬇️")).slice(0, -1)),
- right: parseInt(words.find(word => word.includes("➡️")).slice(0, -1))
- }
- }
-
- yodash.draw = str => {
- const lines = str.split("\n")
- const output = []
- for (let index = 0; index < lines.length; index++) {
- const words = lines[index].split(" ")
- for (let wordIndex = 0; wordIndex < words.length; wordIndex++) {
- const word = words[wordIndex]
- if (word !== "") output.push(`${word} ${yodash.makePositionHash({ down: index, right: wordIndex })}`)
- }
- }
- return output.join("\n")
- }
-
- yodash.updateOccupiedSpots = (board, occupiedSpots) => {
- new TreeNode(board).forEach(line => {
- occupiedSpots.add(yodash.makePositionHash(yodash.parsePosition(line.words)))
- })
- }
-
- yodash.getAllAvailableSpots = (rows, cols, occupiedSpots, rowStart = 0, colStart = 0) => {
- const availablePositions = []
- let down = rows
- while (down >= rowStart) {
- let right = cols
- while (right >= colStart) {
- const hash = yodash.makePositionHash({ right, down })
- if (!occupiedSpots.has(hash)) availablePositions.push({ right, down, hash })
- right--
- }
- down--
+ x: delta.x / magDelta,
+ y: delta.y / magDelta
- return availablePositions
- yodash.insertClusteredRandomAgents = (
- randomNumberGenerator,
- amount,
- char,
- rows,
- cols,
- occupiedSpots,
- originRow,
- originColumn
- ) => {
- const availableSpots = yodash.getAllAvailableSpots(rows, cols, occupiedSpots)
- const spots = yodash.sampleFrom(availableSpots, amount * 10, randomNumberGenerator)
- const origin = originColumn
- ? { down: parseInt(originRow), right: parseInt(originColumn) }
- : yodash.getRandomLocation(rows, cols, randomNumberGenerator)
- const sortedByDistance = lodash.sortBy(spots, spot =>
- math.distance([origin.down, origin.right], [spot.down, spot.right])
- )
-
- return sortedByDistance
- .slice(0, amount)
- .map(spot => {
- const { hash } = spot
- occupiedSpots.add(hash)
- return `${char} ${hash}`
- })
- .join("\n")
- }
-
yodash.test.node.js
Changed around line 1
+ const { TestRacer } = require("jtree/products/TestRacer.js")
- testTree.getRandomAngle = areEqual => {
- areEqual(yodash.getRandomAngle(Math.random).match(/(East|West|North|South)/).length, 2)
- }
-
- testTree.makeRectangle = areEqual => {
- const expected = `😀 0⬇️ 0➡️
- 😀 0⬇️ 1➡️
- 😀 1⬇️ 0➡️
- 😀 1⬇️ 1➡️`
-
- areEqual(yodash.makeRectangle("😀", 2, 2), expected)
- areEqual(
- yodash.makeRectangle("🚪", 2, 1, 1, 1),
- `🚪 1⬇️ 1➡️
- 🚪 1⬇️ 2➡️`
- )
- }
-
+ if (!module.parent) TestRacer.testSingleFile(__filename, testTree)
- const runTree = testTree => {
- const tap = require("tap")
- Object.keys(testTree).forEach(key => {
- testTree[key](tap.equal)
- })
- }
- if (module && !module.parent) runTree(testTree)
Breck Yunits
Breck Yunits
1 year ago
Add readme and release notes
readme.html
Changed around line 1
+
+ Simoji - Write simulations with Emojis
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ <
+
+
+ >
+
+
+

A work in progress.

+
+
+

Documentation

+
+

Related Work

+
  • NetLogo - 2D/3D, Web/Desktop, Open
  • +
  • GAML Language - Desktop, OpenSource
  • +
  • EmojiSimulator - After shipping I learned Nicky had a similar idea 5+ years before me and executed very well!
  • +
  • AnyLogic - 2D/3D
  • +
  • Framsticks - 3D, Desktop
  • +
    +

    Development

    +

    What is the dev loop like?

    +
    +
    1. Start the dev server with node server.js.
    +
  • Open localhost/dev.html
  • +
  • Edit files
  • +
  • Refresh
  • +
  • Run tests with npm test
  • +
  • Build distribution with ./build.js
  • +

    Roadmap

    +
    • Run sims with 8x as many agents
    +
  • Run 8x more sims at once
  • +
  • Write 8x more kinds of sims with the same number of words
  • +
  • Write models that are 8x less wrong
  • +
  • Generate 8x better distributables
  • +
    +

    ❤️ Public Domain ❤️

    +
    +
    +
    +

    +

    releaseNotes.html
    Changed around line 1
    +
    + Simoji Release Notes
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    + <
    +
    +
    + >
    +
    +
    +
    +
    +

    Here's a list of the notable changes in Simoji.

    +

    2.0.0 07-30-2021

    +
    • 🎉 fill command
    +
  • 🎉 kickIt behaves a little smarter
  • +
  • 🧹 kickIt now uses a tick command stack internally
  • +
  • ⚠️ speed is gone. you now need to explcitly move agents in their onTick.
  • +
  • ⚠️ mass, diameter, force removed
  • +
    +
    +
    +

    +

    Breck Yunits
    Breck Yunits
    1 year ago
    Update to Jtree 74
    BrowserGlue.js
    Changed around line 1
    - const { jtree } = require("jtree")
    + const { TreeNode } = require("jtree/products/TreeNode.js")
    + const { HandGrammarProgram } = require("jtree/products/GrammarLanguage.js")
    - const { AbstractTreeComponent } = require("jtree/products/TreeComponentFramework.node.js")
    + const { AbstractTreeComponentParser } = require("jtree/products/TreeComponentFramework.node.js")
    - class BrowserGlue extends AbstractTreeComponent {
    + class BrowserGlue extends AbstractTreeComponentParser {
    Changed around line 23: class BrowserGlue extends AbstractTreeComponent {
    - const deepLink = new jtree.TreeNode(decodeURIComponent(hash))
    + const deepLink = new TreeNode(decodeURIComponent(hash))
    Changed around line 51: class BrowserGlue extends AbstractTreeComponent {
    - window.simojiCompiler = new jtree.HandGrammarProgram(grammarCode).compileAndReturnRootConstructor()
    + window.simojiParser = new HandGrammarProgram(grammarCode).compileAndReturnRootParser()
    build.js
    Changed around line 13: lib/jquery-ui.min.js
    - node_modules/jtree/products/jtree.browser.js
    + node_modules/jtree/products/Utils.browser.js
    + node_modules/jtree/products/TreeNode.browser.js
    + node_modules/jtree/products/GrammarLanguage.browser.js
    + node_modules/jtree/products/GrammarCodeMirrorMode.browser.js
    components/AbstractContextMenu.js
    Changed around line 1
    - const { jtree } = require("jtree")
    - const { AbstractTreeComponent } = require("jtree/products/TreeComponentFramework.node.js")
    + const { TreeNode } = require("jtree/products/TreeNode.js")
    + const { AbstractTreeComponentParser } = require("jtree/products/TreeComponentFramework.node.js")
    - class AbstractContextMenuComponent extends AbstractTreeComponent {
    + class AbstractContextMenuComponent extends AbstractTreeComponentParser {
    Changed around line 26: class AbstractContextMenuComponent extends AbstractTreeComponent {
    - return new jtree.TreeNode(`div
    + return new TreeNode(`div
    - const app = this.getRootNode()
    + const app = this.root
    Changed around line 55: class AbstractContextMenuComponent extends AbstractTreeComponent {
    - return this.getRootNode().getMouseEvent().clientX
    + return this.root.getMouseEvent().clientX
    components/Agent.js
    Changed around line 1
    - const { AbstractTreeComponent } = require("jtree/products/TreeComponentFramework.node.js")
    + const { AbstractTreeComponentParser } = require("jtree/products/TreeComponentFramework.node.js")
    - const { jtree } = require("jtree")
    + const { TreeNode } = require("jtree/products/TreeNode.js")
    - class Agent extends jtree.TreeNode {
    + class Agent extends TreeNode {
    Changed around line 17: class Agent extends jtree.TreeNode {
    - if (!this.behaviors.length) return this.board.simojiProgram.getNode(this.getWord(0))
    - const behaviors = yodash.flatten(yodash.pick(this.board.simojiProgram, [this.getWord(0), ...this.behaviors]))
    + if (!this.behaviors.length) return this.board.simojiProgram.getNode(this.firstWord)
    + const behaviors = yodash.flatten(yodash.pick(this.board.simojiProgram, [this.firstWord, ...this.behaviors]))
    Changed around line 39: class Agent extends jtree.TreeNode {
    - const [emoji, operator, count] = conditionAndCommandsBlock.getWords()
    + const [emoji, operator, count] = conditionAndCommandsBlock.words
    Changed around line 57: class Agent extends jtree.TreeNode {
    - const targetId = target.getWord(0)
    + const targetId = target.firstWord
    Changed around line 73: class Agent extends jtree.TreeNode {
    - const targetId = target.getWord(0)
    + const targetId = target.firstWord
    Changed around line 85: class Agent extends jtree.TreeNode {
    - const commandName = instruction.getWord(0)
    + const commandName = instruction.firstWord
    Changed around line 133: class Agent extends jtree.TreeNode {
    - this.getParent().appendLine(`${newObject} ${this.positionHash}`)
    + this.parent.appendLine(`${newObject} ${this.positionHash}`)
    Changed around line 183: class Agent extends jtree.TreeNode {
    - get root() {
    - return this.getRootNode()
    - }
    -
    Changed around line 193: class Agent extends jtree.TreeNode {
    - return this.getParent()
    + return this.parent
    Changed around line 219: class Agent extends jtree.TreeNode {
    - return yodash.parsePosition(this.getWords())
    + return yodash.parsePosition(this.words)
    Changed around line 227: class Agent extends jtree.TreeNode {
    - return this.getParent().gridSize
    + return this.parent.gridSize
    Changed around line 268: class Agent extends jtree.TreeNode {
    - return `top:${this.top * gridSize}px;left:${this.left *
    - gridSize}px;font-size:${gridSize}px;line-height: ${gridSize}px;${opacity};${this.style ?? ""}`
    + return `top:${this.top * gridSize}px;left:${
    + this.left * gridSize
    + }px;font-size:${gridSize}px;line-height: ${gridSize}px;${opacity};${this.style ?? ""}`
    Changed around line 306: class Agent extends jtree.TreeNode {
    - target.tickStack = new jtree.TreeNode(`1
    + target.tickStack = new TreeNode(`1
    Changed around line 339: class Agent extends jtree.TreeNode {
    - this.root.log(`${this.getWord(0)} ${command.getContent()}`)
    + this.root.log(`${this.firstWord} ${command.content}`)
    components/AgentPalette.js
    Changed around line 1
    - const { AbstractTreeComponent } = require("jtree/products/TreeComponentFramework.node.js")
    + const { AbstractTreeComponentParser } = require("jtree/products/TreeComponentFramework.node.js")
    - class AgentPaletteComponent extends AbstractTreeComponent {
    + class AgentPaletteComponent extends AbstractTreeComponentParser {
    - const root = this.getRootNode()
    + const root = this.root
    - .map(item => item.getWord(0))
    + .map(item => item.firstWord)
    Changed around line 18: ${items}`
    - return this.getRootNode().allAgentTypes.filter(item => !item.has("noPalette"))
    + return this.root.allAgentTypes.filter(item => !item.has("noPalette"))
    - this.getRootNode().changeAgentBrushCommand(x)
    + this.root.changeAgentBrushCommand(x)
    - return [this.getRootNode().board]
    + return [this.root.board]
    components/Board.js
    Changed around line 1
    - const { jtree } = require("jtree")
    + const { TreeNode } = require("jtree/products/TreeNode.js")
    - const { AbstractTreeComponent } = require("jtree/products/TreeComponentFramework.node.js")
    + const { AbstractTreeComponentParser } = require("jtree/products/TreeComponentFramework.node.js")
    - const { Keywords, NodeTypes } = require("./Types.js")
    + const { Keywords, ParserTypes } = require("./Types.js")
    - class BoardErrorNode extends AbstractTreeComponent {
    - _isErrorNodeType() {
    + class BoardErrorParser extends AbstractTreeComponentParser {
    + _isErrorParser() {
    Changed around line 21: class BoardErrorNode extends AbstractTreeComponent {
    - class leftStartPosition extends jtree.TreeNode {
    + class leftStartPosition extends TreeNode {
    - class BoardComponent extends AbstractTreeComponent {
    + class BoardComponent extends AbstractTreeComponentParser {
    - this._parser = new jtree.TreeNode.Parser(BoardErrorNode, {
    + this._parser = new TreeNode.ParserCombinator(BoardErrorParser, {
    Changed around line 72: class BoardComponent extends AbstractTreeComponent {
    - const csv = new TreeNode(this._populationCounts).toCsv()
    + const csv = new TreeNode(this._populationCounts).asCsv
    Changed around line 102: class BoardComponent extends AbstractTreeComponent {
    - .filter(node => node.doesExtend(NodeTypes.abstractInjectCommandNode))
    + .filter(node => node.doesExtend(ParserTypes.abstractInjectCommandParser))
    Changed around line 168: class BoardComponent extends AbstractTreeComponent {
    - this.getRootNode().resetAllCommand()
    + this.root.resetAllCommand()
    Changed around line 200: class BoardComponent extends AbstractTreeComponent {
    - return this.getParent()
    + return this.parent
    Changed around line 211: class BoardComponent extends AbstractTreeComponent {
    - this[command.getNodeTypeId()](command)
    + this[command.parserId](command)
    - insertClusterNode(commandNode) {
    + insertClusterParser(commandNode) {
    Changed around line 229: class BoardComponent extends AbstractTreeComponent {
    - insertAtNode(commandNode) {
    + insertAtParser(commandNode) {
    - rectangleDrawNode(commandNode) {
    - const newLines = yodash.makeRectangle(...yodash.parseInts(commandNode.getWords().slice(1), 1))
    + rectangleDrawParser(commandNode) {
    + const newLines = yodash.makeRectangle(...yodash.parseInts(commandNode.words.slice(1), 1))
    - pasteDrawNode(commandNode) {
    + pasteDrawParser(commandNode) {
    - fillNode(commandNode) {
    + fillParser(commandNode) {
    - drawNode(commandNode) {
    + drawParser(commandNode) {
    Changed around line 268: class BoardComponent extends AbstractTreeComponent {
    - insertNode(commandNode) {
    + insertParser(commandNode) {
    Changed around line 291: class BoardComponent extends AbstractTreeComponent {
    - this[instruction.getWord(0)](instruction)
    + this[instruction.firstWord](instruction)
    Changed around line 301: class BoardComponent extends AbstractTreeComponent {
    - this[instruction.getWord(0)](instruction)
    + this[instruction.firstWord](instruction)
    Changed around line 315: class BoardComponent extends AbstractTreeComponent {
    - return this.getTopDownArray().filter(node => node instanceof Agent)
    + return this.topDownArray.filter(node => node instanceof Agent)
    Changed around line 407: class BoardComponent extends AbstractTreeComponent {
    - return this.root.mainExperiment.findNodes(Keywords.experiment)[this.boardIndex].getContent() ?? ""
    + return this.root.mainExperiment.findNodes(Keywords.experiment)[this.boardIndex].content ?? ""
    Changed around line 454: class BoardComponent extends AbstractTreeComponent {
    - const message = command.getContent()
    + const message = command.content
    Changed around line 472: class BoardComponent extends AbstractTreeComponent {
    - this.root.log(command.getContent())
    + this.root.log(command.content)
    - class BoardStyleComponent extends AbstractTreeComponent {
    - createParser() {
    - return new jtree.TreeNode.Parser(TreeNode)
    + class BoardStyleComponent extends AbstractTreeComponentParser {
    + createParserCombinator() {
    + return new TreeNode.ParserCombinator(TreeNode)
    components/BottomBar.js
    Changed around line 1
    - const { AbstractTreeComponent } = require("jtree/products/TreeComponentFramework.node.js")
    + const { AbstractTreeComponentParser } = require("jtree/products/TreeComponentFramework.node.js")
    - const { jtree } = require("jtree")
    + const { TreeNode } = require("jtree/products/TreeNode.js")
    - class BottomBarComponent extends AbstractTreeComponent {
    - createParser() {
    - return new jtree.TreeNode.Parser(undefined, {
    + class BottomBarComponent extends AbstractTreeComponentParser {
    + createParserCombinator() {
    + return new TreeNode.ParserCombinator(undefined, {
    components/EditorHandle.js
    Changed around line 1
    - const { AbstractTreeComponent } = require("jtree/products/TreeComponentFramework.node.js")
    + const { AbstractTreeComponentParser } = require("jtree/products/TreeComponentFramework.node.js")
    - class EditorHandleComponent extends AbstractTreeComponent {
    + class EditorHandleComponent extends AbstractTreeComponentParser {
    - return this.getRootNode().editor.width
    + return this.root.editor.width
    - const root = this.getRootNode()
    + const root = this.root
    Changed around line 37: class EditorHandleComponent extends AbstractTreeComponent {
    - return [this.getRootNode().editor]
    + return [this.root.editor]
    components/ExampleSims.js
    Changed around line 1
    - const { jtree } = require("jtree")
    + const { TreeNode } = require("jtree/products/TreeNode.js")
    - const ExampleSims = new jtree.TreeNode()
    + const ExampleSims = new TreeNode()
    components/Examples.js
    Changed around line 1
    - const { jtree } = require("jtree")
    + const { TreeNode } = require("jtree/products/TreeNode.js")
    + const { Utils } = require("jtree/products/Utils.js")
    - const { AbstractTreeComponent } = require("jtree/products/TreeComponentFramework.node.js")
    + const { AbstractTreeComponentParser } = require("jtree/products/TreeComponentFramework.node.js")
    - const Categories = new jtree.TreeNode(`🦠 Epidemiology
    + const Categories = new TreeNode(`🦠 Epidemiology
    Changed around line 33: class ExampleMenuComponent extends AbstractContextMenuComponent {
    - const name = node.getFirstWord()
    + const name = node.firstWord
    - const properName = jtree.Utils.ucfirst(name)
    + const properName = Utils.ucfirst(name)
    Changed around line 47: class ExampleMenuComponent extends AbstractContextMenuComponent {
    - const evt = this.getRootNode().getMouseEvent()
    + const evt = this.root.getMouseEvent()
    - class ExamplesComponent extends AbstractTreeComponent {
    + class ExamplesComponent extends AbstractTreeComponentParser {
    - const icon = category.getFirstWord()
    - const name = category.getContent()
    - const firstFile = category.nodeAt(0).getFirstWord()
    + const icon = category.firstWord
    + const name = category.content
    + const firstFile = category.nodeAt(0).firstWord
    Changed around line 69: ${categories}`
    - const root = this.getRootNode()
    + const root = this.root
    - const firstFile = category.nodeAt(0).getFirstWord()
    - this.getRootNode().toggleAndRender(`${ExampleMenuComponent.name} ${icon}`)
    + const firstFile = category.nodeAt(0).firstWord
    + this.root.toggleAndRender(`${ExampleMenuComponent.name} ${icon}`)
    components/Grid.js
    Changed around line 1
    - const { AbstractTreeComponent } = require("jtree/products/TreeComponentFramework.node.js")
    + const { AbstractTreeComponentParser } = require("jtree/products/TreeComponentFramework.node.js")
    - class GridComponent extends AbstractTreeComponent {
    + class GridComponent extends AbstractTreeComponentParser {
    - return this.getParent().insertAgentAtCommand(right, down)
    + return this.parent.insertAgentAtCommand(right, down)
    Changed around line 14: class GridComponent extends AbstractTreeComponent {
    - const { cols, rows, gridSize } = this.getParent()
    + const { cols, rows, gridSize } = this.parent
    components/HelpModal.js
    Changed around line 1
    - const { jtree } = require("jtree")
    - const { AbstractTreeComponent } = require("jtree/products/TreeComponentFramework.node.js")
    + const { TreeNode } = require("jtree/products/TreeNode.js")
    + const { AbstractTreeComponentParser } = require("jtree/products/TreeComponentFramework.node.js")
    - class AbstractModalTreeComponent extends AbstractTreeComponent {
    + class AbstractModalTreeComponent extends AbstractTreeComponentParser {
    Changed around line 39: class AbstractModalTreeComponent extends AbstractTreeComponent {
    - return new jtree.TreeNode(`section
    + return new TreeNode(`section
    components/PlayButton.js
    Changed around line 1
    - const { AbstractTreeComponent } = require("jtree/products/TreeComponentFramework.node.js")
    + const { AbstractTreeComponentParser } = require("jtree/products/TreeComponentFramework.node.js")
    - class PlayButtonComponent extends AbstractTreeComponent {
    + class PlayButtonComponent extends AbstractTreeComponentParser {
    - return this.getRootNode().isRunning
    + return this.root.isRunning
    components/ReportButton.js
    Changed around line 1
    - const { AbstractTreeComponent } = require("jtree/products/TreeComponentFramework.node.js")
    + const { AbstractTreeComponentParser } = require("jtree/products/TreeComponentFramework.node.js")
    - class ReportButtonComponent extends AbstractTreeComponent {
    + class ReportButtonComponent extends AbstractTreeComponentParser {
    components/ResetButton.js
    Changed around line 1
    - const { AbstractTreeComponent } = require("jtree/products/TreeComponentFramework.node.js")
    + const { AbstractTreeComponentParser } = require("jtree/products/TreeComponentFramework.node.js")
    - class ResetButtonComponent extends AbstractTreeComponent {
    + class ResetButtonComponent extends AbstractTreeComponentParser {
    Changed around line 9: class ResetButtonComponent extends AbstractTreeComponent {
    - this.getRootNode().pauseAllCommand()
    - this.getRootNode().resetAllCommand()
    + this.root.pauseAllCommand()
    + this.root.resetAllCommand()
    components/RightBar.js
    Changed around line 1
    - const { AbstractTreeComponent } = require("jtree/products/TreeComponentFramework.node.js")
    - const { jtree } = require("jtree")
    + const { AbstractTreeComponentParser } = require("jtree/products/TreeComponentFramework.node.js")
    + const { TreeNode } = require("jtree/products/TreeNode.js")
    - class RightBarComponent extends AbstractTreeComponent {
    - createParser() {
    - return new jtree.TreeNode.Parser(undefined, {
    + class RightBarComponent extends AbstractTreeComponentParser {
    + createParserCombinator() {
    + return new TreeNode.ParserCombinator(undefined, {
    components/Share.js
    Changed around line 1
    - const { AbstractTreeComponent } = require("jtree/products/TreeComponentFramework.node.js")
    + const { AbstractTreeComponentParser } = require("jtree/products/TreeComponentFramework.node.js")
    - class ShareComponent extends AbstractTreeComponent {
    + class ShareComponent extends AbstractTreeComponentParser {
    Changed around line 11: class ShareComponent extends AbstractTreeComponent {
    - return [this.getRootNode().firstProgram]
    + return [this.root.firstProgram]
    - return url.toString() + this.getRootNode().urlHash
    + return url.toString() + this.root.urlHash
    components/SimEditor.js
    Changed around line 1
    - const { jtree } = require("jtree")
    - const { AbstractTreeComponent } = require("jtree/products/TreeComponentFramework.node.js")
    + const { TreeNode } = require("jtree/products/TreeNode.js")
    + const { AbstractTreeComponentParser } = require("jtree/products/TreeComponentFramework.node.js")
    - /*NODE_JS_ONLY*/ const simojiCompiler = jtree.compileGrammarFileAtPathAndReturnRootConstructor( __dirname + "/../simoji.grammar")
    + /*NODE_JS_ONLY*/ const simojiParser = require("jtree/products/GrammarCompiler.js").GrammarCompiler.compileGrammarFileAtPathAndReturnRootParser( __dirname + "/../simoji.grammar")
    Changed around line 14: class CodeMirrorShim {
    - class SimEditorComponent extends AbstractTreeComponent {
    + class SimEditorComponent extends AbstractTreeComponentParser {
    Changed around line 26: class SimEditorComponent extends AbstractTreeComponent {
    - createParser() {
    - return new jtree.TreeNode.Parser(undefined, {
    - value: jtree.TreeNode
    + createParserCombinator() {
    + return new TreeNode.ParserCombinator(undefined, {
    + value: TreeNode
    Changed around line 43: class SimEditorComponent extends AbstractTreeComponent {
    - const root = this.getRootNode()
    + const root = this.root
    - this.program = new simojiCompiler(code)
    + this.program = new simojiParser(code)
    Changed around line 70: class SimEditorComponent extends AbstractTreeComponent {
    - this.codeMirrorInstance.addLineWidget(err.getLineNumber() - 1, el, { coverGutter: false, noHScroll: false })
    + this.codeMirrorInstance.addLineWidget(err.lineNumber - 1, el, { coverGutter: false, noHScroll: false })
    Changed around line 85: class SimEditorComponent extends AbstractTreeComponent {
    - this.getRootNode().loadNewSim(this._code)
    + this.root.loadNewSim(this._code)
    Changed around line 116: class SimEditorComponent extends AbstractTreeComponent {
    - this.codeMirrorInstance = new jtree.TreeNotationCodeMirrorMode(
    - "custom",
    - () => simojiCompiler,
    - undefined,
    - CodeMirror
    - )
    + this.codeMirrorInstance = new GrammarCodeMirrorMode("custom", () => simojiParser, undefined, CodeMirror)
    components/SimojiApp.js
    Changed around line 1
    - /*NODE_JS_ONLY*/ const { AbstractTreeComponent, TreeComponentFrameworkDebuggerComponent } = require("jtree/products/TreeComponentFramework.node.js")
    + /*NODE_JS_ONLY*/ const { AbstractTreeComponentParser, TreeComponentFrameworkDebuggerComponent } = require("jtree/products/TreeComponentFramework.node.js")
    - const { jtree } = require("jtree")
    + const { TreeNode } = require("jtree/products/TreeNode.js")
    Changed around line 20: const { BottomBarComponent } = require("./BottomBar.js")
    - const { Keywords, LocalStorageKeys, UrlKeys, Directions, NodeTypes } = require("./Types.js")
    + const { Keywords, LocalStorageKeys, UrlKeys, Directions, ParserTypes } = require("./Types.js")
    Changed around line 29: const MIN_GRID_COLUMNS = 10
    - /*NODE_JS_ONLY*/ const simojiCompiler = jtree.compileGrammarFileAtPathAndReturnRootConstructor( __dirname + "/../simoji.grammar")
    + /*NODE_JS_ONLY*/ const simojiParser = require("jtree/products/GrammarCompiler.js").GrammarCompiler.compileGrammarFileAtPathAndReturnRootParser( __dirname + "/../simoji.grammar")
    - class githubTriangleComponent extends AbstractTreeComponent {
    + class githubTriangleComponent extends AbstractTreeComponentParser {
    Changed around line 52: class githubTriangleComponent extends AbstractTreeComponent {
    - class ErrorNode extends AbstractTreeComponent {
    - _isErrorNodeType() {
    + class ErrorParser extends AbstractTreeComponentParser {
    + _isErrorParser() {
    Changed around line 63: class ErrorNode extends AbstractTreeComponent {
    - class SimojiApp extends AbstractTreeComponent {
    - createParser() {
    - return new jtree.TreeNode.Parser(ErrorNode, {
    + class SimojiApp extends AbstractTreeComponentParser {
    + createParserCombinator() {
    + return new TreeNode.ParserCombinator(ErrorParser, {
    Changed around line 122: class SimojiApp extends AbstractTreeComponent {
    - .filter(node => node.doesExtend(NodeTypes.abstractInjectCommandNode))
    + .filter(node => node.doesExtend(ParserTypes.abstractInjectCommandParser))
    Changed around line 203: ${styleNode ? styleNode.toString().replace("style", BoardStyleComponent.name) :
    - const errs = new simojiCompiler(this.simCode).getAllErrors()
    - console.log(new jtree.TreeNode(errs.map(err => err.toObject())).toFormattedTable(200))
    + const errs = new simojiParser(this.simCode).getAllErrors()
    + console.log(new TreeNode(errs.map(err => err.toObject())).toFormattedTable(200))
    Changed around line 216: ${styleNode ? styleNode.toString().replace("style", BoardStyleComponent.name) :
    - return new simojiCompiler(this.simCode)
    + return new simojiParser(this.simCode)
    Changed around line 229: ${styleNode ? styleNode.toString().replace("style", BoardStyleComponent.name) :
    - this._simojiPrograms = this._simojiPrograms.map(program => new simojiCompiler(program.toString()))
    + this._simojiPrograms = this._simojiPrograms.map(program => new simojiParser(program.toString()))
    Changed around line 273: ${styleNode ? styleNode.toString().replace("style", BoardStyleComponent.name) :
    - willowBrowser.getMousetrap().bind(key, function(evt) {
    + willowBrowser.getMousetrap().bind(key, function (evt) {
    Changed around line 310: ${styleNode ? styleNode.toString().replace("style", BoardStyleComponent.name) :
    - const str = this.selection
    - .map(agent =>
    - agent
    - .getWords()
    - .slice(0, 3)
    - .join(" ")
    - )
    - .join("\n")
    + const str = this.selection.map(agent => agent.words.slice(0, 3).join(" ")).join("\n")
    Changed around line 369: ${styleNode ? styleNode.toString().replace("style", BoardStyleComponent.name) :
    - const tree = new jtree.TreeNode()
    + const tree = new TreeNode()
    Changed around line 448: ${styleNode ? styleNode.toString().replace("style", BoardStyleComponent.name) :
    - return new jtree.TreeNode(this.simCode).has(Keywords.seed)
    + return new TreeNode(this.simCode).has(Keywords.seed)
    - const newCode = new jtree.TreeNode(this.simCode)
    + const newCode = new TreeNode(this.simCode)
    Changed around line 539: SimojiApp.setupApp = (simojiCode, windowWidth = 1000, windowHeight = 1000) => {
    - const startState = new jtree.TreeNode(`${githubTriangleComponent.name}
    + const startState = new TreeNode(`${githubTriangleComponent.name}
    components/SimojiApp.test.node.js
    Changed around line 1
    - const { jtree } = require("jtree")
    + const { TreeNode } = require("jtree/products/TreeNode.js")
    + const { GrammarCompiler } = require("jtree/products/GrammarCompiler.js")
    - const simojiCompiler = jtree.compileGrammarFileAtPathAndReturnRootConstructor(grammarPath)
    + const simojiParser = GrammarCompiler.compileGrammarFileAtPathAndReturnRootParser(grammarPath)
    - if (errs.length) console.log(new jtree.TreeNode(errs).toFormattedTable(60))
    + if (errs.length) console.log(new TreeNode(errs).toFormattedTable(60))
    Changed around line 21: testTree.simGrammarErrors = areEqual => {
    - const program = new simojiCompiler(code)
    + const program = new simojiParser(code)
    Changed around line 29: testTree.simGrammarErrors = areEqual => {
    - if (errs.length) console.log(new jtree.TreeNode(errs).toFormattedTable(60))
    + if (errs.length) console.log(new TreeNode(errs).toFormattedTable(60))
    components/Title.js
    Changed around line 1
    - const { AbstractTreeComponent } = require("jtree/products/TreeComponentFramework.node.js")
    + const { AbstractTreeComponentParser } = require("jtree/products/TreeComponentFramework.node.js")
    - class TitleComponent extends AbstractTreeComponent {
    + class TitleComponent extends AbstractTreeComponentParser {
    - return this.getRootNode()
    + return this.root
    components/TopBar.js
    Changed around line 1
    - const { AbstractTreeComponent } = require("jtree/products/TreeComponentFramework.node.js")
    + const { AbstractTreeComponentParser } = require("jtree/products/TreeComponentFramework.node.js")
    - const { jtree } = require("jtree")
    + const { TreeNode } = require("jtree/products/TreeNode.js")
    - class TopBarComponent extends AbstractTreeComponent {
    - createParser() {
    - return new jtree.TreeNode.Parser(undefined, {
    + class TopBarComponent extends AbstractTreeComponentParser {
    + createParserCombinator() {
    + return new TreeNode.ParserCombinator(undefined, {
    Changed around line 13: class TopBarComponent extends AbstractTreeComponent {
    - class LogoComponent extends AbstractTreeComponent {
    + class LogoComponent extends AbstractTreeComponentParser {
    Changed around line 22: class LogoComponent extends AbstractTreeComponent {
    - this.getRootNode().toggleHelpCommand()
    + this.root.toggleHelpCommand()
    components/Types.js
    Changed around line 36: Directions.East = "East"
    - const NodeTypes = {}
    + const ParserTypes = {}
    - NodeTypes.agentDefinitionNode = "agentDefinitionNode"
    - NodeTypes.experimentNode = "experimentNode"
    - NodeTypes.settingDefinitionNode = "settingDefinitionNode"
    - NodeTypes.abstractInjectCommandNode = "abstractInjectCommandNode"
    + ParserTypes.agentDefinitionParser = "agentDefinitionParser"
    + ParserTypes.experimentParser = "experimentParser"
    + ParserTypes.settingDefinitionParser = "settingDefinitionParser"
    + ParserTypes.abstractInjectCommandParser = "abstractInjectCommandParser"
    - module.exports = { Keywords, LocalStorageKeys, UrlKeys, Directions, NodeTypes }
    + module.exports = { Keywords, LocalStorageKeys, UrlKeys, Directions, ParserTypes }
    dev.html
    Changed around line 12
    -
    +
    +
    +
    +
    dist/constants.js
    Changed around line 1
    - const SimConstants = {"grammar":"anyCell\nbooleanCell\nstringCell\n highlightScope string\nsettingValueCell\n highlightScope constant.numeric\ncssCell\n highlightScope string\njavascriptCell\n highlightScope string\nhtmlCell\n highlightScope string\nemojiCell\n highlightScope string\nohayoCell\n highlightScope string\nblankCell\ncodeCell\n highlightScope comment\ncommentCell\n highlightScope comment\nkeywordCell\n highlightScope keyword\ntextCell\n highlightScope string\nintegerCell\n highlightScope constant.numeric\nbehaviorNameCell\n highlightScope keyword\nconditionalOperatorCell\n highlightScope keyword\n enum < > = <= >=\npositionCell\n highlightScope constant.numeric\nneighborCountCell\n extends integerCell\n min 0\n max 8\nintegerOrPercentCell\n highlightScope constant.numeric\nprobabilityCell\n description A number between 0 and 1\n highlightScope constant.numeric\npropertyNameCell\n highlightScope keyword\nangleCell\n enum North South East West NorthWest NorthEast SouthWest SouthEast\n highlightScope constant.numeric\nerrorNode\n baseNodeType errorNode\nsimojiNode\n extensions simoji\n description A Tree Language that compiles to a TreeComponentFramework app.\n root\n inScope abstractIgnoreNode abstractSetupNode abstractInjectCommandNode onTickNode onExtinctNode behaviorDefinitionNode experimentNode settingDefinitionNode\n catchAllNodeType agentDefinitionNode\n compilesTo javascript\n example\n 🦋\n onTick .1\n turnRandomly\n move\n onTick .2\n turnToward 💡\n move\n 💡\n \n insert 10 🦋\n insert 2 💡\n javascript\n get agentTypes() {\n return this.filter(node => node.getNodeTypeId() === \"agentDefinitionNode\")\n }\nexperimentNode\n crux experiment\n cells keywordCell\n inScope abstractIgnoreNode abstractSetupNode abstractInjectCommandNode onTickNode onExtinctNode settingDefinitionNode\n catchAllCellType stringCell\nabstractSetupNode\natTimeNode\n crux atTime\n description Run commands at a certain tick.\n cells keywordCell integerCell\n extends abstractSetupNode\n inScope abstractInjectCommandNode\nabstractSetupNumberNode\n cells keywordCell integerCell\n extends abstractSetupNode\n javascript\n compile() {\n return \"\"\n }\nsizeNode\n description Size of a grid cell in pixels. Min is 10. Max is 200.\n extends abstractSetupNumberNode\n crux size\nrowsNode\n description Number of rows in the grid. Default is based on screen size.\n extends abstractSetupNumberNode\n crux rows\ncolumnsNode\n description Number of columns in the grid. Default is based on screen size.\n extends abstractSetupNumberNode\n crux columns\nseedNode\n description If you'd like reproducible runs set a seed for the random number generator.\n extends abstractSetupNumberNode\n crux seed\nticksPerSecondNode\n description Time in milliseconds of one step.\n extends abstractSetupNumberNode\n crux ticksPerSecond\nreportNode\n crux report\n description Define a custom report template.\n catchAllNodeType ohayoLineNode\n extends abstractSetupNode\n cells keywordCell\n javascript\n compile() {\n return \"\"\n }\nstyleNode\n description Optional CSS to load in BoardStyleComponent\n extends abstractSetupNode\n cells keywordCell\n crux style\n catchAllNodeType styleLineNode\n javascript\n compile() {\n return \"\"\n }\nquestionNode\n crux question\n description What are you trying to figure out?\n cells keywordCell\n catchAllCellType stringCell\n extends abstractSetupNode\nabstractInjectCommandNode\nfillNode\n description Fill all blank cells with this agent.\n extends abstractInjectCommandNode\n cells keywordCell emojiCell\n crux fill\ndrawNode\n extends abstractInjectCommandNode\n cells keywordCell\n crux draw\n catchAllNodeType drawLineNode\ninsertNode\n extends abstractInjectCommandNode\n cells keywordCell integerOrPercentCell emojiCell\n crux insert\ninsertAtNode\n extends insertNode\n description Insert at X Y\n cells keywordCell emojiCell positionCell positionCell\n crux insertAt\ninsertClusterNode\n extends insertNode\n crux insertCluster\n catchAllCellType integerCell\nrectangleDrawNode\n extends abstractInjectCommandNode\n cells keywordCell emojiCell integerCell integerCell\n catchAllCellType integerCell\n crux rectangle\npasteDrawNode\n extends abstractInjectCommandNode\n cells keywordCell\n crux paste\n catchAllNodeType pasteLineNode\ndrawLineNode\n catchAllCellType emojiCell\npasteLineNode\n catchAllCellType anyCell\n catchAllNodeType pasteLineNode\nagentDefinitionNode\n inScope abstractIgnoreNode abstractEventNode abstractAgentAttributeNode abstractBehaviorAttributeNode\n cells keywordCell\n catchAllNodeType errorNode\n compiler\n stringTemplate \n javascript\n compile() {\n const root = this.getRootNode()\n const name = root.agentKeywordMap[this.getWord(0)]\n const normal = super.compile()\n const behaviors = this.filter(node => node.getNodeTypeId() === \"abstractBehaviorAttributeNode\")\n .map(behavior => `\"${behavior.getLine()}\"`)\n .join(\",\")\n return `class ${name} extends Agent {\n icon = \"${this.getWord(0)}\"\n behaviors = [${behaviors}]\n ${normal}\n }`\n }\nabstractCommandNode\n cells keywordCell\nabstractSubjectObjectCommandNode\n extends abstractCommandNode\nreplaceWithCommandNode\n extends abstractSubjectObjectCommandNode\n crux replaceWith\n cells keywordCell emojiCell\nkickItCommandNode\n extends abstractSubjectObjectCommandNode\n crux kickIt\nshootCommandNode\n extends abstractSubjectObjectCommandNode\n crux shoot\npickItUpCommandNode\n extends abstractSubjectObjectCommandNode\n crux pickItUp\nspawnCommandNode\n crux spawn\n extends abstractCommandNode\n cells keywordCell emojiCell\n catchAllCellType positionCell\nmoveToEmptySpotCommandNode\n crux moveToEmptySpot\n extends abstractCommandNode\n cells keywordCell\nremoveCommandNode\n description Remove this agent from the board.\n crux remove\n extends abstractCommandNode\n cells keywordCell\njavascriptCommandNode\n description An escape hatch so you can write custom javascript in a pinch.\n extends abstractCommandNode\n crux javascript\n catchAllNodeType javascriptLineNode\n cells keywordCell\nalertCommandNode\n extends abstractCommandNode\n crux alert\n catchAllCellType stringCell\nlogCommandNode\n extends abstractCommandNode\n crux log\n catchAllCellType stringCell\nnarrateCommandNode\n extends abstractCommandNode\n crux narrate\n catchAllCellType stringCell\npauseCommandNode\n extends abstractCommandNode\n crux pause\ndecreaseCommandNode\n extends abstractCommandNode\n description Decrease a property by 1.\n crux decrease\n cells keywordCell propertyNameCell\nincreaseCommandNode\n extends abstractCommandNode\n description Increase a property by 1.\n crux increase\n cells keywordCell propertyNameCell\nmoveCommandNode\n extends abstractCommandNode\n crux move\nturnRandomlyCommandNode\n extends abstractCommandNode\n crux turnRandomly\njitterCommandNode\n extends abstractCommandNode\n crux jitter\nturnTowardCommandNode\n description Turn to the closest agent of a certain type.\n extends abstractCommandNode\n crux turnToward\n cells keywordCell emojiCell\nturnFromCommandNode\n description Turn away from the closest agent of a certain type.\n extends abstractCommandNode\n crux turnFrom\n cells keywordCell emojiCell\nlearnCommandNode\n crux learn\n extends abstractCommandNode\n cells keywordCell behaviorNameCell\nunlearnCommandNode\n crux unlearn\n extends abstractCommandNode\n cells keywordCell behaviorNameCell\nabstractAgentAttributeNode\n cells keywordCell\nabstractStringAttributeNode\n extends abstractAgentAttributeNode\n pattern ^\\w+ .+$\n catchAllCellType stringCell\n javascript\n compile() {\n return `${this.getWord(0)} = \"${this.getWord(1)}\"`\n }\nangleNode\n extends abstractStringAttributeNode\n cells keywordCell angleCell\n crux angle\nagentStyleNode\n description Provide custom CSS for an agent type.\n extends abstractStringAttributeNode\n cells keywordCell cssCell\n crux style\nagentHtmlNode\n description Provide custom HTML for each rendered agent.\n extends abstractStringAttributeNode\n cells keywordCell htmlCell\n crux html\nabstractBooleanAttributeNode\n description A boolean attribute.\n extends abstractAgentAttributeNode\n javascript\n compile() {\n return `${this.getWord(0)} = true`\n }\nnoPaletteNode\n extends abstractBooleanAttributeNode\n cruxFromId\n description Don't show this agent in the palette.\nsolidTraitNode\n description If set other agents won't pass through these.\n extends abstractBooleanAttributeNode\n crux solid\nbouncyTraitNode\n description If set other agents will bounce off this after a collision.\n extends abstractBooleanAttributeNode\n crux bouncy\nabstractIntegerAttributeNode\n extends abstractAgentAttributeNode\n description An integer attribute.\n cells keywordCell integerCell\n javascript\n compile() {\n return `${this.getWord(0)} = ${this.getWord(1)}`\n }\ncustomIntegerAttributeNode\n pattern ^\\w+ \\d+$\n extends abstractIntegerAttributeNode\nhealthNode\n extends abstractIntegerAttributeNode\n crux health\nsettingDefinitionNode\n description Define a configurable input.\n cells keywordCell settingValueCell\n pattern ^\\w+Setting .+$\nohayoLineNode\n description Data visualization code written for Ohayo.\n catchAllCellType ohayoCell\nstyleLineNode\n catchAllCellType cssCell\n catchAllNodeType styleLineNode\ntargetEmojiNode\n inScope abstractCommandNode\n cells emojiCell\nabstractEventNode\n cells keywordCell\n catchAllCellType probabilityCell\n javascript\n compile() {\n return ``\n }\nabstractInteractionEventNode\n extends abstractEventNode\n catchAllNodeType targetEmojiNode\nonHitNode\n extends abstractInteractionEventNode\n crux onHit\n description Define what happens when this agent collides with other agents.\nonTouchNode\n extends abstractInteractionEventNode\n crux onTouch\n description Define what happens when this agent is adjacent to other agents.\nonNeighborsNode\n description Define what happens when a certain amount of neighbors are nearby.\n extends abstractInteractionEventNode\n inScope emojiAndNeighborConditionNode\n crux onNeighbors\nonDeathNode\n extends abstractEventNode\n crux onDeath\n inScope abstractCommandNode\n description Define what happens when this agent runs out of health.\nonTickNode\n extends abstractEventNode\n crux onTick\n inScope abstractCommandNode\n description Define what happens each tick.\nemojiAndNeighborConditionNode\n inScope abstractCommandNode\n pattern ^.+ (<|>|=|<=|>=)+ .+$\n cells emojiCell conditionalOperatorCell neighborCountCell\nonExtinctNode\n crux onExtinct\n inScope abstractCommandNode\n cells keywordCell emojiCell\n description Define what happens when a type of agent goes extinct from the board.\n javascript\n compile() {\n return \"\"\n }\nabstractIgnoreNode\n tags doNotSynthesize\n javascript\n compile () {\n return \"\"\n }\ncommentNode\n extends abstractIgnoreNode\n catchAllCellType commentCell\n crux comment\n catchAllNodeType commentLineNode\ncommentAliasNode\n description Alternate alias for a comment.\n crux #\n extends commentNode\nblankLineNode\n extends abstractIgnoreNode\n description Blank lines compile do nothing.\n cells blankCell\n pattern ^$\ncommentLineNode\n catchAllCellType commentCell\njavascriptLineNode\n catchAllCellType javascriptCell\nabstractBehaviorAttributeNode\n cells behaviorNameCell\n pattern ^.*Behavior$\n javascript\n compile() {\n return \"\"\n }\nbehaviorDefinitionNode\n inScope abstractIgnoreNode abstractEventNode\n cells behaviorNameCell\n pattern ^.*Behavior$\n catchAllNodeType errorNode\n javascript\n compile() {\n return \"\"\n }","examples":"ants\n comment\n https://ccl.northwestern.edu/netlogo/models/Ants\n \n ⛰\n onTick 0.05\n spawn 🐜\n 🐜\n onTick\n jitter\n onHit\n 🥖\n pickItUp\n 🥖\n \n insert 3 🥖\n insert 1 ⛰\nbasketball\n question Is it better to shoot wildly or to bring it close to the basket?\n \n experiment Shoot rarely\n shotProbabilitySetting .02\n \n experiment\n shotProbabilitySetting .2\n \n experiment\n shotProbabilitySetting .4\n \n experiment Shoot right away\n shotProbabilitySetting .8\n \n 🏀\n onHit\n 🥅⛹️‍♂️\n narrate Blue scores!\n spawn 🏀 9⬇️ 15➡️\n spawn 🔵 18⬇️ 1➡️\n remove\n 🥅⛹️‍♀️\n narrate Red scores!\n spawn 🏀 9⬇️ 15➡️\n spawn 🔴 17⬇️ 1➡️\n remove\n \n \n moveEastToBlankSpotBehavior\n onTick\n moveToEmptySpot\n unlearn moveEastToBlankSpotBehavior\n \n \n 🔵\n angle East\n moveEastToBlankSpotBehavior\n 🔴\n angle East\n moveEastToBlankSpotBehavior\n \n \n ticksPerSecond 30\n \n hasBallBehavior\n comment Sprint toward net\n onTick .5\n turnToward net\n move\n narrate breaks toward the net.\n comment Shoot\n onTick shotProbabilitySetting\n turnToward net\n shoot\n narrate shoots!\n learn noBallBehavior\n unlearn hasBallBehavior\n comment Pass\n onTick .02\n turnToward team\n shoot\n narrate passes the ball!\n learn noBallBehavior\n unlearn hasBallBehavior\n \n noBallBehavior\n onTick .3\n turnToward 🏀\n move\n onHit\n 🏀\n pickItUp\n narrate has the ball\n learn hasBallBehavior\n unlearn noBallBehavior\n onTick .05\n turnFrom opponent\n move\n onTick .1\n turnFrom opponent\n jitter\n \n # Blue Team\n ⛹️‍♂️\n net 🥅⛹️‍♂️\n team ⛹️‍♂️\n opponent ⛹️‍♀️\n noBallBehavior\n \n # Red Team\n ⛹️‍♀️\n net 🥅⛹️‍♀️\n team ⛹️‍♀️\n opponent ⛹️‍♂️\n noBallBehavior\n \n # Baskets\n 🥅⛹️‍♂️\n html 🥅\n 🥅⛹️‍♀️\n html 🥅\n paste\n 🥅⛹️‍♂️ 8⬇️ 2➡️\n 🥅⛹️‍♀️ 8⬇️ 29➡️\n 🏀 9⬇️ 15➡️\n \n # Court\n 🪵\n solid\n rectangle 🪵 30 15 1 1\n \n size 30\n \n # Red Team\n paste\n ⛹️‍♀️ 9⬇️ 6➡️\n ⛹️‍♀️ 5⬇️ 6➡️\n ⛹️‍♀️ 11⬇️ 11➡️\n ⛹️‍♀️ 8⬇️ 11➡️\n ⛹️‍♀️ 5⬇️ 11➡️\n \n # Blue Team\n paste\n ⛹️‍♂️ 8⬇️ 25➡️\n ⛹️‍♂️ 6⬇️ 25➡️\n ⛹️‍♂️ 11⬇️ 20➡️\n ⛹️‍♂️ 7⬇️ 20➡️\n ⛹️‍♂️ 4⬇️ 20➡️\n \ncity\n ⛪️\n comment church\n 🏟\n comment stadium\n 🏥\n comment hospital\n 🏭\n comment factory\n 🏦\n comment bank\n 🏛\n comment courthouse\n 🏫\n comment school\n 🏡\n comment house\n 🏘\n comment houses\n 🎡\n comment park\n 🏪\n comment store\n 🚗\n onTick\n move\n move\n angle West\n 🚓\n onTick\n move\n move\n angle West\n 🚋\n comment subway\n onTick\n move\n move\n move\n angle West\n ⬜️\n comment road\n 🟩\n ⛳️\n size 20\n \n rectangle ⬜️ 10 20 0 0\n rectangle ⬜️ 10 1 0 10\n paste\n 🏛 9⬇️ 8➡️\n 🏭 1⬇️ 4➡️\n 🏭 1⬇️ 3➡️\n 🏭 1⬇️ 2➡️\n 🏭 1⬇️ 1➡️\n 🏡 18⬇️ 5➡️\n 🏡 18⬇️ 6➡️\n 🏡 18⬇️ 7➡️\n 🏡 18⬇️ 8➡️\ncops\n 🚗\n onTick .5\n jitter\n move\n 🚓\n onHit\n 🚗\n alert Got em!\n pause\n onTick .1\n turnToward 🚗\n move\n onTick .1\n move\n \n size 20\n ticksPerSecond 30\n \n paste\n 🚓 1⬇️ 1➡️\n 🚗 15⬇️ 5➡️\ncovid19\n 🦠\n \n question How long will the pandemic last?\n \n # Given someone has never been infected, what are the odds they get infected?\n succeptibilitySetting .95\n # What are odds of reinfection?\n reinfectionRateSetting .002\n \n # 1 is no lockdowns. 0 is total lockdown.\n freedomOfMovementSetting 1\n \n # What is starting population size?\n urbanPopulationSetting 150\n # What is starting rural population?\n ruralPopulationSetting 30\n # What is starting infected size?\n startingInfectedSetting 3\n \n # How many places can one get the vaccine?\n vaccineCentersSetting 5\n # How likely are people to seek the vaccine?\n vaccinationDesirabilitySetting .3\n # Given someone was vaxed, what are the odds they get infected?\n vaxSucceptibilitySetting .5\n \n experiment High Vaccination Rate, High Vaccine Efficacy\n vaccinationDesirabilitySetting .8\n vaxSucceptibilitySetting .05\n \n \n experiment High Vaccination Rate, Low Vaccine Efficacy\n vaccinationDesirabilitySetting .8\n vaxSucceptibilitySetting .75\n \n experiment Lockdown\n freedomOfMovementSetting .3\n \n experiment High Reinfection Rate\n reinfectionRateSetting .2\n \n \n insert startingInfectedSetting 🧟\n insert vaccineCentersSetting 💉\n \n insertCluster urbanPopulationSetting 🙍\n insert ruralPopulationSetting 🙍\n \n \n 🧟\n health 100\n onTick .03\n log recovered\n replaceWith 🦸‍♂️\n onTick\n decrease health\n jitter\n onDeath\n replaceWith 🪦\n \n 🦸‍♂️\n comment Recovered\n onTick\n jitter\n onTouch reinfectionRateSetting\n 🧟\n replaceWith 🧟\n \n lifeBehavior\n onTick freedomOfMovementSetting\n jitter\n \n seekVaccineBehavior\n onTick vaccinationDesirabilitySetting\n turnToward 💉\n move\n \n \n 🙍\n lifeBehavior\n seekVaccineBehavior\n onTouch innateImmunitySetting\n 🧟\n replaceWith 🧟\n 💉\n replaceWith 🧑🏽‍🚒\n \n \n 💉\n \n \n 🧑🏽‍🚒\n lifeBehavior\n onTouch vaxSucceptibilitySetting\n 🧟\n replaceWith 🧟\n \n \n \n \n onExtinct 🧟\n log No more cases.\n pause\n \n \n 🪦\n \n size 15\n ticksPerSecond 10\n \n report\n roughjs.line\n columns.keep 🧟\n roughjs.line Active Cases\n columns.keep 🪦\n roughjs.line Cumulative Deaths\n \n \n comment\n See Also\n - http://covidsim.eu/\n - http://modelingcommons.org/browse/one_model/6282#model_tabs_browse_info\n - https://github.com/maplerainresearch/covid19-sim-mesa/blob/master/model.py\n - https://www.frontiersin.org/articles/10.3389/fpubh.2020.563247/full\n - https://ncase.me/covid-19/\n - https://en.wikipedia.org/wiki/List_of_COVID-19_simulation_models\n \n \ncovid19simple\n question What is the effect of population density on pandemic duration?\n \n experiment\n insertCluster 100 🙍\n insertCluster 100 🙍\n insertCluster 100 🙍\n insertCluster 30 🙍\n insertCluster 30 🙍\n insertCluster 10 🙍\n \n experiment\n insert 200 🙍\n \n experiment\n insertCluster 200 🙍\n \n experiment\n insertCluster 200 🙍\n insert 200 🙍\n \n \n 🦠\n health 10\n onTick\n decrease health\n onDeath\n remove\n \n 🧟\n health 100\n onTick .03\n log recovered\n replaceWith 🦸‍♂️\n onTick\n decrease health\n jitter\n onDeath\n replaceWith 🪦\n \n 🦸‍♂️\n comment immune\n onTick\n jitter\n \n 🙍\n onTick\n jitter\n onTouch\n 🦠\n replaceWith 🧟\n 🧟\n replaceWith 🧟\n \n insert 1 🦠\n \n onExtinct 🧟\n log No more cases.\n pause\n \n \n 🪦\n \n size 15\n ticksPerSecond 10\n \n report\n roughjs.line\n columns.keep 🧟\n roughjs.line Active Cases\n columns.keep 🪦\n roughjs.line Cumulative Deaths\n \n \n comment\n See Also\n - http://covidsim.eu/\n - http://modelingcommons.org/browse/one_model/6282#model_tabs_browse_info\n - https://github.com/maplerainresearch/covid19-sim-mesa/blob/master/model.py\n - https://www.frontiersin.org/articles/10.3389/fpubh.2020.563247/full\n - https://ncase.me/covid-19/\n - https://en.wikipedia.org/wiki/List_of_COVID-19_simulation_models\n \neatTheBacon\n 🐕\n onTick .2\n turnToward 🥓\n move\n onTick .2\n jitter\n 🥓\n onTouch\n 🐕\n remove\n 🥦\n \n \n insert 1 🐕\n insert 3 🥓\n insert 10 🥦\n \nelevators\n 🛗\n onTick\n move\n move\n angle South\n bouncy\n onHit\n 🚶🏻\n pickItUp\n 🚶🏻\n angle West\n onTick\n move\n bouncy\n 🌾\n 🚪\n onTick .001\n spawn 🚶🏻\n 🪵\n solid\n 🚗\n \n \n size 15\n \n rectangle 🪵 20➡️ 47⬇️ 5 1\n rectangle 🌾 40➡️ 1⬇️ 0 48\n rectangle 🚪 1➡️ 45⬇️ 15 2\n paste\n 🛗 6⬇️ 19➡️\n 🛗 4⬇️ 22➡️\n 🛗 3⬇️ 20➡️\n 🛗 10⬇️ 13➡️\n 🛗 4⬇️ 9➡️\n 🛗 3⬇️ 11➡️\n 🚗 47⬇️ 30➡️\n 🚗 47⬇️ 28➡️\nfire\n question How fast do fires spread?\n \n 🌲\n onHit\n ⚡️\n replaceWith 🔥\n onTouch\n 🔥\n replaceWith 🔥\n \n ⚡️\n health 10\n onTick\n decrease health\n onDeath\n remove\n \n 🔥\n health 50\n onTick\n decrease health\n onDeath\n replaceWith ⬛️\n \n \n ⬛️\n comment Burnt forest\n html 🌲\n style filter:grayscale(100%);\n \n \n insert 50% 🌲\n onTick .3\n spawn ⚡️\nfireAdvanced\n question What is the effect of forest density on fire risk?\n \n experiment\n treeDensitySetting 10%\n \n experiment\n treeDensitySetting 20%\n \n experiment\n treeDensitySetting 40%\n \n experiment\n treeDensitySetting 80%\n \n catchFireSetting .3\n fireSpreadSetting .7\n fireLifetimeSetting 10\n lightningFrequencySetting .1\n \n 🌲\n onHit catchFireSetting\n ⚡️\n replaceWith 🔥\n onTouch fireSpreadSetting\n 🔥\n replaceWith 🔥\n \n ⚡️\n health 10\n onTick\n decrease health\n onDeath\n remove\n \n 🔥\n health fireLifetimeSetting\n onTick\n decrease health\n onDeath\n replaceWith ⬛️\n \n \n ⬛️\n comment Burnt forest\n html 🌲\n style filter:grayscale(100%);\n \n \n insert treeDensitySetting 🌲\n onTick lightningFrequencySetting\n spawn ⚡️\n \ngameOfLife\n question Can simple rules produce complex effects?\n \n ⬛️\n onNeighbors\n ⬛️ < 2\n replaceWith ◻️\n ⬛️ > 3\n replaceWith ◻️\n \n ◻️\n onNeighbors\n ⬛️ = 3\n replaceWith ⬛️\n \n insert 10% ⬛️\n fill ◻️\n size 15\ngameOfLifeAdvanced\n # Conway's Game of Life\n \n experiment\n neighborSetting 2\n \n experiment\n neighborSetting 3\n \n experiment\n neighborSetting 4\n \n experiment\n neighborSetting 5\n \n ⬛️\n onNeighbors\n ⬛️ < 2\n replaceWith ◻️\n ⬛️ > neighborSetting\n replaceWith ◻️\n \n ◻️\n onNeighbors\n ⬛️ = 3\n replaceWith ⬛️\n \n insert 10% ⬛️\n fill ◻️\n size 15\ngospersGliderGun\n ⬛️\n onNeighbors\n ⬛️ < 2\n replaceWith ◻️\n ⬛️ > 3\n replaceWith ◻️\n \n ◻️\n onNeighbors\n ⬛️ = 3\n replaceWith ⬛️\n \n # Gosper's Glider Gun\n \n draw\n ⬛️ \n ⬛️ ⬛️ \n ⬛️ ⬛️ ⬛️ ⬛️ \n ⬛️ ⬛️ ⬛️ ⬛️ ⬛️ ⬛️\n ⬛️ ⬛️ ⬛️ ⬛️ ⬛️ ⬛️\n ⬛️ ⬛️ ⬛️ ⬛️ ⬛️ ⬛️ ⬛️ ⬛️ \n ⬛️ ⬛️ ⬛️ ⬛️ ⬛️ \n ⬛️ ⬛️ \n ⬛️ ⬛️ \n \n \n fill ◻️\n \nmoths\n question Can you move the moths from one light to the other?\n \n 🦋\n onTick .1\n jitter\n move\n onTick .2\n turnToward 💡\n move\n move\n 💡\n \n ticksPerSecond 10\n size 20\n style\n .BoardComponent {background:black;}\n \n insert 10 🦋\n insert 2 💡\n \n comment\n http://www.netlogoweb.org/launch#http://www.netlogoweb.org/assets/modelslib/Sample%20Models/Biology/Moths.nlogo\nninjas\n 🤺\n health 100\n onTick\n decrease health\n jitter\n \n 🥷\n health 100\n onTick\n decrease health\n jitter\n \n insert 50 🤺\n insert 50 🥷\npong\n \n \n 🏐\n bouncy\n onTick\n move\n angle West\n 🏓\n angle East\n onHit\n 🏐\n kickIt\n 🏸\n angle West\n onHit\n 🏐\n kickIt\n 🪵\n solid\n \n size 20\n ticksPerSecond 10\n \n rectangle 🪵 30 15 5 5\n paste\n 🏓 13⬇️ 6➡️\n 🏸 13⬇️ 33➡️\n 🏐 13⬇️ 19➡️\n \n \npoolTable\n comment\n Needs balls to collide. Acceleration.\n \n 🎱\n bouncy\n onHit\n 🎱\n kickIt\n 🏐\n kickIt\n \n 🪵\n solid\n \n 🏐\n bouncy\n onTick .1\n turnRandomly\n kickIt\n onTick .5\n kickIt\n onHit\n 🎱\n kickIt\n angle West\n \n rectangle 🪵 40 20 0 7\n paste\n 🏐 17⬇️ 32➡️\n 🎱 12⬇️ 7➡️\n 🎱 14⬇️ 7➡️\n 🎱 16⬇️ 7➡️\n 🎱 18⬇️ 7➡️\n 🎱 20⬇️ 7➡️\n 🎱 22⬇️ 7➡️\n 🎱 21⬇️ 8➡️\n 🎱 19⬇️ 8➡️\n 🎱 17⬇️ 8➡️\n 🎱 15⬇️ 8➡️\n 🎱 13⬇️ 8➡️\n 🎱 20⬇️ 9➡️\n 🎱 18⬇️ 9➡️\n 🎱 16⬇️ 9➡️\n 🎱 14⬇️ 9➡️\n 🎱 15⬇️ 10➡️\n 🎱 17⬇️ 10➡️\n 🎱 19⬇️ 10➡️\n 🎱 18⬇️ 11➡️\n 🎱 16⬇️ 11➡️\n 🎱 17⬇️ 12➡️\nsoccer\n \n \n ⚽️\n onHit\n 🥅\n pause\n alert GOAAAAAAAAALLLL!\n bouncy\n \n ⛹️‍♂️\n onTick\n jitter\n onHit\n ⚽️\n kickIt\n \n ⛹️‍♀️\n onTick\n jitter\n onHit\n ⚽️\n kickIt\n 🥅\n 🪵\n solid\n \n size 20\n ticksPerSecond 10\n \n rectangle 🪵 30 15 5 5\n \n paste\n 🥅 13⬇️ 6➡️\n 🥅 13⬇️ 33➡️\n ⚽️ 13⬇️ 19➡️\n \n paste\n ⛹️‍♀️ 17⬇️ 14➡️\n ⛹️‍♀️ 17⬇️ 17➡️\n ⛹️‍♀️ 13⬇️ 17➡️\n ⛹️‍♀️ 13⬇️ 14➡️\n ⛹️‍♀️ 8⬇️ 14➡️\n ⛹️‍♀️ 8⬇️ 17➡️\n ⛹️‍♀️ 10⬇️ 14➡️\n ⛹️‍♀️ 9⬇️ 10➡️\n ⛹️‍♀️ 13⬇️ 8➡️\n ⛹️‍♀️ 13⬇️ 10➡️\n ⛹️‍♀️ 17⬇️ 10➡️\n \n paste\n ⛹️‍♂️ 13⬇️ 31➡️\n ⛹️‍♂️ 17⬇️ 28➡️\n ⛹️‍♂️ 13⬇️ 28➡️\n ⛹️‍♂️ 8⬇️ 29➡️\n ⛹️‍♂️ 8⬇️ 25➡️\n ⛹️‍♂️ 10⬇️ 25➡️\n ⛹️‍♂️ 13⬇️ 25➡️\n ⛹️‍♂️ 17⬇️ 25➡️\n ⛹️‍♂️ 17⬇️ 21➡️\n ⛹️‍♂️ 8⬇️ 21➡️\n ⛹️‍♂️ 13⬇️ 21➡️\n \nstartupIdeas\n question What is the effect of ideas vs ideas with revenue?\n \n 👨‍💼🔖\n comment person with an idea\n onTick\n jitter\n \n 👨‍💼💰\n comment peron with an idea\n that is making money\n onTick\n jitter\n \n 👨‍\n onTick .1\n jitter\n onTick .1\n turnToward 👨‍💼💰\n move\n \n \n size 10\n insert 200 👨‍\n insert 30 👨‍💼🔖\n insert 3 👨‍💼💰\n \n \nstore\n 🚶🏻\n onTick\n move\n angle North\n 🛒\n 🚪\n onTick .1\n spawn 🚶🏻\n 🪵\n solid\n \n size 25\n \n rectangle 🪵 30 15 3 3\n paste\n 🚪 16⬇️ 17➡️\n \nvirus\n question What might the spread of a simple virus look like?\n \n 🧟\n health 100\n onTick .9\n decrease health\n jitter\n onTick .01\n log recovered\n replaceWith 🦸‍♂️\n onDeath\n replaceWith 🪦\n \n 🙍\n onTick\n jitter\n onTouch\n 🧟\n replaceWith 🧟\n \n 🦸‍♂️\n onTick\n jitter\n \n insert 10% 🙍\n insert 1 🧟\n \n 🪦\n \n onExtinct 🧟\n log No more cases.\n pause\nwaves\n 🌊\n onTick\n move\n angle South\n \n size 25\n ticksPerSecond 5\n \n rectangle 🌊 100 1 0\n rectangle 🌊 100 1 0 6\n rectangle 🌊 100 1 0 11\nzombies\n question Can you protect the family from the zombies?\n \n 🧟‍♂️\n noPalette\n onTick\n jitter\n onHit\n 🪃\n replaceWith 🪦\n 💣\n replaceWith 🪦\n 👨‍👩‍👧‍👦\n pause\n alert TheyGotYou!\n \n 🧱\n solid\n \n 🔫\n onTick .1\n spawn 🪃\n \n 🪃\n noPalette\n angle West\n onTick\n move\n \n 💣\n \n 🪦\n noPalette\n comment Dead zombie\n \n 👨‍👩‍👧‍👦\n noPalette\n \n size 30\n ticksPerSecond 10\n \n insertCluster 30 🧟‍♂️ 1 1\n paste\n 👨‍👩‍👧‍👦 12⬇️ 11➡️"}
    + const SimConstants = {"grammar":"anyCell\nbooleanCell\nstringCell\n highlightScope string\nsettingValueCell\n highlightScope constant.numeric\ncssCell\n highlightScope string\njavascriptCell\n highlightScope string\nhtmlCell\n highlightScope string\nemojiCell\n highlightScope string\nohayoCell\n highlightScope string\nblankCell\ncodeCell\n highlightScope comment\ncommentCell\n highlightScope comment\nkeywordCell\n highlightScope keyword\ntextCell\n highlightScope string\nintegerCell\n highlightScope constant.numeric\nbehaviorNameCell\n highlightScope keyword\nconditionalOperatorCell\n highlightScope keyword\n enum < > = <= >=\npositionCell\n highlightScope constant.numeric\nneighborCountCell\n extends integerCell\n min 0\n max 8\nintegerOrPercentCell\n highlightScope constant.numeric\nprobabilityCell\n description A number between 0 and 1\n highlightScope constant.numeric\npropertyNameCell\n highlightScope keyword\nangleCell\n enum North South East West NorthWest NorthEast SouthWest SouthEast\n highlightScope constant.numeric\nerrorParser\n baseParser errorParser\nsimojiParser\n extensions simoji\n description A Tree Language that compiles to a TreeComponentFramework app.\n root\n inScope abstractIgnoreParser abstractSetupParser abstractInjectCommandParser onTickParser onExtinctParser behaviorDefinitionParser experimentParser settingDefinitionParser\n catchAllParser agentDefinitionParser\n compilesTo javascript\n example\n 🦋\n onTick .1\n turnRandomly\n move\n onTick .2\n turnToward 💡\n move\n 💡\n \n insert 10 🦋\n insert 2 💡\n javascript\n get agentTypes() {\n return this.filter(node => node.parserId === \"agentDefinitionParser\")\n }\nexperimentParser\n cruxFromId\n cells keywordCell\n inScope abstractIgnoreParser abstractSetupParser abstractInjectCommandParser onTickParser onExtinctParser settingDefinitionParser\n catchAllCellType stringCell\nabstractSetupParser\natTimeParser\n cruxFromId\n description Run commands at a certain tick.\n cells keywordCell integerCell\n extends abstractSetupParser\n inScope abstractInjectCommandParser\nabstractSetupNumberParser\n cells keywordCell integerCell\n extends abstractSetupParser\n javascript\n compile() {\n return \"\"\n }\nsizeParser\n description Size of a grid cell in pixels. Min is 10. Max is 200.\n extends abstractSetupNumberParser\n cruxFromId\nrowsParser\n description Number of rows in the grid. Default is based on screen size.\n extends abstractSetupNumberParser\n cruxFromId\ncolumnsParser\n description Number of columns in the grid. Default is based on screen size.\n extends abstractSetupNumberParser\n cruxFromId\nseedParser\n description If you'd like reproducible runs set a seed for the random number generator.\n extends abstractSetupNumberParser\n cruxFromId\nticksPerSecondParser\n description Time in milliseconds of one step.\n extends abstractSetupNumberParser\n cruxFromId\nreportParser\n cruxFromId\n description Define a custom report template.\n catchAllParser ohayoLineParser\n extends abstractSetupParser\n cells keywordCell\n javascript\n compile() {\n return \"\"\n }\nstyleParser\n description Optional CSS to load in BoardStyleComponent\n extends abstractSetupParser\n cells keywordCell\n cruxFromId\n catchAllParser styleLineParser\n javascript\n compile() {\n return \"\"\n }\nquestionParser\n cruxFromId\n description What are you trying to figure out?\n cells keywordCell\n catchAllCellType stringCell\n extends abstractSetupParser\nabstractInjectCommandParser\nfillParser\n description Fill all blank cells with this agent.\n extends abstractInjectCommandParser\n cells keywordCell emojiCell\n cruxFromId\ndrawParser\n extends abstractInjectCommandParser\n cells keywordCell\n cruxFromId\n catchAllParser drawLineParser\ninsertParser\n extends abstractInjectCommandParser\n cells keywordCell integerOrPercentCell emojiCell\n cruxFromId\ninsertAtParser\n extends insertParser\n description Insert at X Y\n cells keywordCell emojiCell positionCell positionCell\n cruxFromId\ninsertClusterParser\n extends insertParser\n cruxFromId\n catchAllCellType integerCell\nrectangleDrawParser\n extends abstractInjectCommandParser\n cells keywordCell emojiCell integerCell integerCell\n catchAllCellType integerCell\n crux rectangle\npasteDrawParser\n extends abstractInjectCommandParser\n cells keywordCell\n crux paste\n catchAllParser pasteLineParser\ndrawLineParser\n catchAllCellType emojiCell\npasteLineParser\n catchAllCellType anyCell\n catchAllParser pasteLineParser\nagentDefinitionParser\n inScope abstractIgnoreParser abstractEventParser abstractAgentAttributeParser behaviorAttributeParser\n cells keywordCell\n catchAllParser errorParser\n compiler\n stringTemplate \n javascript\n compile() {\n const root = this.root\n const name = root.agentKeywordMap[this.firstWord]\n const normal = super.compile()\n const behaviors = this.filter(node => node.parserId === \"behaviorAttributeParser\")\n .map(behavior => `\"${behavior.getLine()}\"`)\n .join(\",\")\n return `class ${name} extends Agent {\n icon = \"${this.firstWord}\"\n behaviors = [${behaviors}]\n ${normal}\n }`\n }\nabstractCommandParser\n cells keywordCell\nabstractSubjectObjectCommandParser\n extends abstractCommandParser\nreplaceWithCommandParser\n extends abstractSubjectObjectCommandParser\n crux replaceWith\n cells keywordCell emojiCell\nkickItCommandParser\n extends abstractSubjectObjectCommandParser\n crux kickIt\nshootCommandParser\n extends abstractSubjectObjectCommandParser\n crux shoot\npickItUpCommandParser\n extends abstractSubjectObjectCommandParser\n crux pickItUp\nspawnCommandParser\n crux spawn\n extends abstractCommandParser\n cells keywordCell emojiCell\n catchAllCellType positionCell\nmoveToEmptySpotCommandParser\n crux moveToEmptySpot\n extends abstractCommandParser\n cells keywordCell\nremoveCommandParser\n description Remove this agent from the board.\n crux remove\n extends abstractCommandParser\n cells keywordCell\njavascriptCommandParser\n description An escape hatch so you can write custom javascript in a pinch.\n extends abstractCommandParser\n crux javascript\n catchAllParser javascriptLineParser\n cells keywordCell\nalertCommandParser\n extends abstractCommandParser\n crux alert\n catchAllCellType stringCell\nlogCommandParser\n extends abstractCommandParser\n crux log\n catchAllCellType stringCell\nnarrateCommandParser\n extends abstractCommandParser\n crux narrate\n catchAllCellType stringCell\npauseCommandParser\n extends abstractCommandParser\n crux pause\ndecreaseCommandParser\n extends abstractCommandParser\n description Decrease a property by 1.\n crux decrease\n cells keywordCell propertyNameCell\nincreaseCommandParser\n extends abstractCommandParser\n description Increase a property by 1.\n crux increase\n cells keywordCell propertyNameCell\nmoveCommandParser\n extends abstractCommandParser\n crux move\nturnRandomlyCommandParser\n extends abstractCommandParser\n crux turnRandomly\njitterCommandParser\n extends abstractCommandParser\n crux jitter\nturnTowardCommandParser\n description Turn to the closest agent of a certain type.\n extends abstractCommandParser\n crux turnToward\n cells keywordCell emojiCell\nturnFromCommandParser\n description Turn away from the closest agent of a certain type.\n extends abstractCommandParser\n crux turnFrom\n cells keywordCell emojiCell\nlearnCommandParser\n crux learn\n extends abstractCommandParser\n cells keywordCell behaviorNameCell\nunlearnCommandParser\n crux unlearn\n extends abstractCommandParser\n cells keywordCell behaviorNameCell\nabstractAgentAttributeParser\n cells keywordCell\nstringAttributeParser\n extends abstractAgentAttributeParser\n pattern ^\\w+ .+$\n catchAllCellType stringCell\n javascript\n compile() {\n return `${this.firstWord} = \"${this.getWord(1)}\"`\n }\nangleParser\n extends stringAttributeParser\n cells keywordCell angleCell\n cruxFromId\nagentStyleParser\n description Provide custom CSS for an agent type.\n extends stringAttributeParser\n cells keywordCell cssCell\n crux style\nagentHtmlParser\n description Provide custom HTML for each rendered agent.\n extends stringAttributeParser\n cells keywordCell htmlCell\n crux html\nabstractBooleanAttributeParser\n description A boolean attribute.\n extends abstractAgentAttributeParser\n javascript\n compile() {\n return `${this.firstWord} = true`\n }\nnoPaletteParser\n extends abstractBooleanAttributeParser\n cruxFromId\n description Don't show this agent in the palette.\nsolidTraitParser\n description If set other agents won't pass through these.\n extends abstractBooleanAttributeParser\n crux solid\nbouncyTraitParser\n description If set other agents will bounce off this after a collision.\n extends abstractBooleanAttributeParser\n crux bouncy\nabstractIntegerAttributeParser\n extends abstractAgentAttributeParser\n description An integer attribute.\n cells keywordCell integerCell\n javascript\n compile() {\n return `${this.firstWord} = ${this.getWord(1)}`\n }\ncustomIntegerAttributeParser\n pattern ^\\w+ \\d+$\n extends abstractIntegerAttributeParser\nhealthParser\n extends abstractIntegerAttributeParser\n cruxFromId\nsettingDefinitionParser\n description Define a configurable input.\n cells keywordCell settingValueCell\n pattern ^\\w+Setting .+$\nohayoLineParser\n description Data visualization code written for Ohayo.\n catchAllCellType ohayoCell\nstyleLineParser\n catchAllCellType cssCell\n catchAllParser styleLineParser\ntargetEmojiParser\n inScope abstractCommandParser\n cells emojiCell\nabstractEventParser\n cells keywordCell\n catchAllCellType probabilityCell\n javascript\n compile() {\n return ``\n }\nabstractInteractionEventParser\n extends abstractEventParser\n catchAllParser targetEmojiParser\nonHitParser\n extends abstractInteractionEventParser\n cruxFromId\n description Define what happens when this agent collides with other agents.\nonTouchParser\n extends abstractInteractionEventParser\n cruxFromId\n description Define what happens when this agent is adjacent to other agents.\nonNeighborsParser\n description Define what happens when a certain amount of neighbors are nearby.\n extends abstractInteractionEventParser\n inScope emojiAndNeighborConditionParser\n cruxFromId\nonDeathParser\n extends abstractEventParser\n cruxFromId\n inScope abstractCommandParser\n description Define what happens when this agent runs out of health.\nonTickParser\n extends abstractEventParser\n cruxFromId\n inScope abstractCommandParser\n description Define what happens each tick.\nemojiAndNeighborConditionParser\n inScope abstractCommandParser\n pattern ^.+ (<|>|=|<=|>=)+ .+$\n cells emojiCell conditionalOperatorCell neighborCountCell\nonExtinctParser\n cruxFromId\n inScope abstractCommandParser\n cells keywordCell emojiCell\n description Define what happens when a type of agent goes extinct from the board.\n javascript\n compile() {\n return \"\"\n }\nabstractIgnoreParser\n tags doNotSynthesize\n javascript\n compile () {\n return \"\"\n }\ncommentParser\n extends abstractIgnoreParser\n catchAllCellType commentCell\n cruxFromId\n catchAllParser commentLineParser\ncommentAliasParser\n description Alternate alias for a comment.\n crux #\n extends commentParser\nblankLineParser\n extends abstractIgnoreParser\n description Blank lines compile do nothing.\n cells blankCell\n pattern ^$\ncommentLineParser\n catchAllCellType commentCell\njavascriptLineParser\n catchAllCellType javascriptCell\nbehaviorAttributeParser\n cells behaviorNameCell\n pattern ^.*Behavior$\n javascript\n compile() {\n return \"\"\n }\nbehaviorDefinitionParser\n inScope abstractIgnoreParser abstractEventParser\n cells behaviorNameCell\n pattern ^.*Behavior$\n catchAllParser errorParser\n javascript\n compile() {\n return \"\"\n }","examples":"ants\n comment\n https://ccl.northwestern.edu/netlogo/models/Ants\n \n ⛰\n onTick 0.05\n spawn 🐜\n 🐜\n onTick\n jitter\n onHit\n 🥖\n pickItUp\n 🥖\n \n insert 3 🥖\n insert 1 ⛰\nbasketball\n question Is it better to shoot wildly or to bring it close to the basket?\n \n experiment Shoot rarely\n shotProbabilitySetting .02\n \n experiment\n shotProbabilitySetting .2\n \n experiment\n shotProbabilitySetting .4\n \n experiment Shoot right away\n shotProbabilitySetting .8\n \n 🏀\n onHit\n 🥅⛹️‍♂️\n narrate Blue scores!\n spawn 🏀 9⬇️ 15➡️\n spawn 🔵 18⬇️ 1➡️\n remove\n 🥅⛹️‍♀️\n narrate Red scores!\n spawn 🏀 9⬇️ 15➡️\n spawn 🔴 17⬇️ 1➡️\n remove\n \n \n moveEastToBlankSpotBehavior\n onTick\n moveToEmptySpot\n unlearn moveEastToBlankSpotBehavior\n \n \n 🔵\n angle East\n moveEastToBlankSpotBehavior\n 🔴\n angle East\n moveEastToBlankSpotBehavior\n \n \n ticksPerSecond 30\n \n hasBallBehavior\n comment Sprint toward net\n onTick .5\n turnToward net\n move\n narrate breaks toward the net.\n comment Shoot\n onTick shotProbabilitySetting\n turnToward net\n shoot\n narrate shoots!\n learn noBallBehavior\n unlearn hasBallBehavior\n comment Pass\n onTick .02\n turnToward team\n shoot\n narrate passes the ball!\n learn noBallBehavior\n unlearn hasBallBehavior\n \n noBallBehavior\n onTick .3\n turnToward 🏀\n move\n onHit\n 🏀\n pickItUp\n narrate has the ball\n learn hasBallBehavior\n unlearn noBallBehavior\n onTick .05\n turnFrom opponent\n move\n onTick .1\n turnFrom opponent\n jitter\n \n # Blue Team\n ⛹️‍♂️\n net 🥅⛹️‍♂️\n team ⛹️‍♂️\n opponent ⛹️‍♀️\n noBallBehavior\n \n # Red Team\n ⛹️‍♀️\n net 🥅⛹️‍♀️\n team ⛹️‍♀️\n opponent ⛹️‍♂️\n noBallBehavior\n \n # Baskets\n 🥅⛹️‍♂️\n html 🥅\n 🥅⛹️‍♀️\n html 🥅\n paste\n 🥅⛹️‍♂️ 8⬇️ 2➡️\n 🥅⛹️‍♀️ 8⬇️ 29➡️\n 🏀 9⬇️ 15➡️\n \n # Court\n 🪵\n solid\n rectangle 🪵 30 15 1 1\n \n size 30\n \n # Red Team\n paste\n ⛹️‍♀️ 9⬇️ 6➡️\n ⛹️‍♀️ 5⬇️ 6➡️\n ⛹️‍♀️ 11⬇️ 11➡️\n ⛹️‍♀️ 8⬇️ 11➡️\n ⛹️‍♀️ 5⬇️ 11➡️\n \n # Blue Team\n paste\n ⛹️‍♂️ 8⬇️ 25➡️\n ⛹️‍♂️ 6⬇️ 25➡️\n ⛹️‍♂️ 11⬇️ 20➡️\n ⛹️‍♂️ 7⬇️ 20➡️\n ⛹️‍♂️ 4⬇️ 20➡️\n \ncity\n ⛪️\n comment church\n 🏟\n comment stadium\n 🏥\n comment hospital\n 🏭\n comment factory\n 🏦\n comment bank\n 🏛\n comment courthouse\n 🏫\n comment school\n 🏡\n comment house\n 🏘\n comment houses\n 🎡\n comment park\n 🏪\n comment store\n 🚗\n onTick\n move\n move\n angle West\n 🚓\n onTick\n move\n move\n angle West\n 🚋\n comment subway\n onTick\n move\n move\n move\n angle West\n ⬜️\n comment road\n 🟩\n ⛳️\n size 20\n \n rectangle ⬜️ 10 20 0 0\n rectangle ⬜️ 10 1 0 10\n paste\n 🏛 9⬇️ 8➡️\n 🏭 1⬇️ 4➡️\n 🏭 1⬇️ 3➡️\n 🏭 1⬇️ 2➡️\n 🏭 1⬇️ 1➡️\n 🏡 18⬇️ 5➡️\n 🏡 18⬇️ 6➡️\n 🏡 18⬇️ 7➡️\n 🏡 18⬇️ 8➡️\ncops\n 🚗\n onTick .5\n jitter\n move\n 🚓\n onHit\n 🚗\n alert Got em!\n pause\n onTick .1\n turnToward 🚗\n move\n onTick .1\n move\n \n size 20\n ticksPerSecond 30\n \n paste\n 🚓 1⬇️ 1➡️\n 🚗 15⬇️ 5➡️\ncovid19\n 🦠\n \n question How long will the pandemic last?\n \n # Given someone has never been infected, what are the odds they get infected?\n succeptibilitySetting .95\n # What are odds of reinfection?\n reinfectionRateSetting .002\n \n # 1 is no lockdowns. 0 is total lockdown.\n freedomOfMovementSetting 1\n \n # What is starting population size?\n urbanPopulationSetting 150\n # What is starting rural population?\n ruralPopulationSetting 30\n # What is starting infected size?\n startingInfectedSetting 3\n \n # How many places can one get the vaccine?\n vaccineCentersSetting 5\n # How likely are people to seek the vaccine?\n vaccinationDesirabilitySetting .3\n # Given someone was vaxed, what are the odds they get infected?\n vaxSucceptibilitySetting .5\n \n experiment High Vaccination Rate, High Vaccine Efficacy\n vaccinationDesirabilitySetting .8\n vaxSucceptibilitySetting .05\n \n \n experiment High Vaccination Rate, Low Vaccine Efficacy\n vaccinationDesirabilitySetting .8\n vaxSucceptibilitySetting .75\n \n experiment Lockdown\n freedomOfMovementSetting .3\n \n experiment High Reinfection Rate\n reinfectionRateSetting .2\n \n \n insert startingInfectedSetting 🧟\n insert vaccineCentersSetting 💉\n \n insertCluster urbanPopulationSetting 🙍\n insert ruralPopulationSetting 🙍\n \n \n 🧟\n health 100\n onTick .03\n log recovered\n replaceWith 🦸‍♂️\n onTick\n decrease health\n jitter\n onDeath\n replaceWith 🪦\n \n 🦸‍♂️\n comment Recovered\n onTick\n jitter\n onTouch reinfectionRateSetting\n 🧟\n replaceWith 🧟\n \n lifeBehavior\n onTick freedomOfMovementSetting\n jitter\n \n seekVaccineBehavior\n onTick vaccinationDesirabilitySetting\n turnToward 💉\n move\n \n \n 🙍\n lifeBehavior\n seekVaccineBehavior\n onTouch innateImmunitySetting\n 🧟\n replaceWith 🧟\n 💉\n replaceWith 🧑🏽‍🚒\n \n \n 💉\n \n \n 🧑🏽‍🚒\n lifeBehavior\n onTouch vaxSucceptibilitySetting\n 🧟\n replaceWith 🧟\n \n \n \n \n onExtinct 🧟\n log No more cases.\n pause\n \n \n 🪦\n \n size 15\n ticksPerSecond 10\n \n report\n roughjs.line\n columns.keep 🧟\n roughjs.line Active Cases\n columns.keep 🪦\n roughjs.line Cumulative Deaths\n \n \n comment\n See Also\n - http://covidsim.eu/\n - http://modelingcommons.org/browse/one_model/6282#model_tabs_browse_info\n - https://github.com/maplerainresearch/covid19-sim-mesa/blob/master/model.py\n - https://www.frontiersin.org/articles/10.3389/fpubh.2020.563247/full\n - https://ncase.me/covid-19/\n - https://en.wikipedia.org/wiki/List_of_COVID-19_simulation_models\n \n \ncovid19simple\n question What is the effect of population density on pandemic duration?\n \n experiment\n insertCluster 100 🙍\n insertCluster 100 🙍\n insertCluster 100 🙍\n insertCluster 30 🙍\n insertCluster 30 🙍\n insertCluster 10 🙍\n \n experiment\n insert 200 🙍\n \n experiment\n insertCluster 200 🙍\n \n experiment\n insertCluster 200 🙍\n insert 200 🙍\n \n \n 🦠\n health 10\n onTick\n decrease health\n onDeath\n remove\n \n 🧟\n health 100\n onTick .03\n log recovered\n replaceWith 🦸‍♂️\n onTick\n decrease health\n jitter\n onDeath\n replaceWith 🪦\n \n 🦸‍♂️\n comment immune\n onTick\n jitter\n \n 🙍\n onTick\n jitter\n onTouch\n 🦠\n replaceWith 🧟\n 🧟\n replaceWith 🧟\n \n insert 1 🦠\n \n onExtinct 🧟\n log No more cases.\n pause\n \n \n 🪦\n \n size 15\n ticksPerSecond 10\n \n report\n roughjs.line\n columns.keep 🧟\n roughjs.line Active Cases\n columns.keep 🪦\n roughjs.line Cumulative Deaths\n \n \n comment\n See Also\n - http://covidsim.eu/\n - http://modelingcommons.org/browse/one_model/6282#model_tabs_browse_info\n - https://github.com/maplerainresearch/covid19-sim-mesa/blob/master/model.py\n - https://www.frontiersin.org/articles/10.3389/fpubh.2020.563247/full\n - https://ncase.me/covid-19/\n - https://en.wikipedia.org/wiki/List_of_COVID-19_simulation_models\n \neatTheBacon\n 🐕\n onTick .2\n turnToward 🥓\n move\n onTick .2\n jitter\n 🥓\n onTouch\n 🐕\n remove\n 🥦\n \n \n insert 1 🐕\n insert 3 🥓\n insert 10 🥦\n \nelevators\n 🛗\n onTick\n move\n move\n angle South\n bouncy\n onHit\n 🚶🏻\n pickItUp\n 🚶🏻\n angle West\n onTick\n move\n bouncy\n 🌾\n 🚪\n onTick .001\n spawn 🚶🏻\n 🪵\n solid\n 🚗\n \n \n size 15\n \n rectangle 🪵 20➡️ 47⬇️ 5 1\n rectangle 🌾 40➡️ 1⬇️ 0 48\n rectangle 🚪 1➡️ 45⬇️ 15 2\n paste\n 🛗 6⬇️ 19➡️\n 🛗 4⬇️ 22➡️\n 🛗 3⬇️ 20➡️\n 🛗 10⬇️ 13➡️\n 🛗 4⬇️ 9➡️\n 🛗 3⬇️ 11➡️\n 🚗 47⬇️ 30➡️\n 🚗 47⬇️ 28➡️\nfire\n question How fast do fires spread?\n \n 🌲\n onHit\n ⚡️\n replaceWith 🔥\n onTouch\n 🔥\n replaceWith 🔥\n \n ⚡️\n health 10\n onTick\n decrease health\n onDeath\n remove\n \n 🔥\n health 50\n onTick\n decrease health\n onDeath\n replaceWith ⬛️\n \n \n ⬛️\n comment Burnt forest\n html 🌲\n style filter:grayscale(100%);\n \n \n insert 50% 🌲\n onTick .3\n spawn ⚡️\nfireAdvanced\n question What is the effect of forest density on fire risk?\n \n experiment\n treeDensitySetting 10%\n \n experiment\n treeDensitySetting 20%\n \n experiment\n treeDensitySetting 40%\n \n experiment\n treeDensitySetting 80%\n \n catchFireSetting .3\n fireSpreadSetting .7\n fireLifetimeSetting 10\n lightningFrequencySetting .1\n \n 🌲\n onHit catchFireSetting\n ⚡️\n replaceWith 🔥\n onTouch fireSpreadSetting\n 🔥\n replaceWith 🔥\n \n ⚡️\n health 10\n onTick\n decrease health\n onDeath\n remove\n \n 🔥\n health fireLifetimeSetting\n onTick\n decrease health\n onDeath\n replaceWith ⬛️\n \n \n ⬛️\n comment Burnt forest\n html 🌲\n style filter:grayscale(100%);\n \n \n insert treeDensitySetting 🌲\n onTick lightningFrequencySetting\n spawn ⚡️\n \ngameOfLife\n question Can simple rules produce complex effects?\n \n ⬛️\n onNeighbors\n ⬛️ < 2\n replaceWith ◻️\n ⬛️ > 3\n replaceWith ◻️\n \n ◻️\n onNeighbors\n ⬛️ = 3\n replaceWith ⬛️\n \n insert 10% ⬛️\n fill ◻️\n size 15\ngameOfLifeAdvanced\n # Conway's Game of Life\n \n experiment\n neighborSetting 2\n \n experiment\n neighborSetting 3\n \n experiment\n neighborSetting 4\n \n experiment\n neighborSetting 5\n \n ⬛️\n onNeighbors\n ⬛️ < 2\n replaceWith ◻️\n ⬛️ > neighborSetting\n replaceWith ◻️\n \n ◻️\n onNeighbors\n ⬛️ = 3\n replaceWith ⬛️\n \n insert 10% ⬛️\n fill ◻️\n size 15\ngospersGliderGun\n ⬛️\n onNeighbors\n ⬛️ < 2\n replaceWith ◻️\n ⬛️ > 3\n replaceWith ◻️\n \n ◻️\n onNeighbors\n ⬛️ = 3\n replaceWith ⬛️\n \n # Gosper's Glider Gun\n \n draw\n ⬛️ \n ⬛️ ⬛️ \n ⬛️ ⬛️ ⬛️ ⬛️ \n ⬛️ ⬛️ ⬛️ ⬛️ ⬛️ ⬛️\n ⬛️ ⬛️ ⬛️ ⬛️ ⬛️ ⬛️\n ⬛️ ⬛️ ⬛️ ⬛️ ⬛️ ⬛️ ⬛️ ⬛️ \n ⬛️ ⬛️ ⬛️ ⬛️ ⬛️ \n ⬛️ ⬛️ \n ⬛️ ⬛️ \n \n \n fill ◻️\n \nmoths\n question Can you move the moths from one light to the other?\n \n 🦋\n onTick .1\n jitter\n move\n onTick .2\n turnToward 💡\n move\n move\n 💡\n \n ticksPerSecond 10\n size 20\n style\n .BoardComponent {background:black;}\n \n insert 10 🦋\n insert 2 💡\n \n comment\n http://www.netlogoweb.org/launch#http://www.netlogoweb.org/assets/modelslib/Sample%20Models/Biology/Moths.nlogo\nninjas\n 🤺\n health 100\n onTick\n decrease health\n jitter\n \n 🥷\n health 100\n onTick\n decrease health\n jitter\n \n insert 50 🤺\n insert 50 🥷\npong\n \n \n 🏐\n bouncy\n onTick\n move\n angle West\n 🏓\n angle East\n onHit\n 🏐\n kickIt\n 🏸\n angle West\n onHit\n 🏐\n kickIt\n 🪵\n solid\n \n size 20\n ticksPerSecond 10\n \n rectangle 🪵 30 15 5 5\n paste\n 🏓 13⬇️ 6➡️\n 🏸 13⬇️ 33➡️\n 🏐 13⬇️ 19➡️\n \n \npoolTable\n comment\n Needs balls to collide. Acceleration.\n \n 🎱\n bouncy\n onHit\n 🎱\n kickIt\n 🏐\n kickIt\n \n 🪵\n solid\n \n 🏐\n bouncy\n onTick .1\n turnRandomly\n kickIt\n onTick .5\n kickIt\n onHit\n 🎱\n kickIt\n angle West\n \n rectangle 🪵 40 20 0 7\n paste\n 🏐 17⬇️ 32➡️\n 🎱 12⬇️ 7➡️\n 🎱 14⬇️ 7➡️\n 🎱 16⬇️ 7➡️\n 🎱 18⬇️ 7➡️\n 🎱 20⬇️ 7➡️\n 🎱 22⬇️ 7➡️\n 🎱 21⬇️ 8➡️\n 🎱 19⬇️ 8➡️\n 🎱 17⬇️ 8➡️\n 🎱 15⬇️ 8➡️\n 🎱 13⬇️ 8➡️\n 🎱 20⬇️ 9➡️\n 🎱 18⬇️ 9➡️\n 🎱 16⬇️ 9➡️\n 🎱 14⬇️ 9➡️\n 🎱 15⬇️ 10➡️\n 🎱 17⬇️ 10➡️\n 🎱 19⬇️ 10➡️\n 🎱 18⬇️ 11➡️\n 🎱 16⬇️ 11➡️\n 🎱 17⬇️ 12➡️\nsoccer\n \n \n ⚽️\n onHit\n 🥅\n pause\n alert GOAAAAAAAAALLLL!\n bouncy\n \n ⛹️‍♂️\n onTick\n jitter\n onHit\n ⚽️\n kickIt\n \n ⛹️‍♀️\n onTick\n jitter\n onHit\n ⚽️\n kickIt\n 🥅\n 🪵\n solid\n \n size 20\n ticksPerSecond 10\n \n rectangle 🪵 30 15 5 5\n \n paste\n 🥅 13⬇️ 6➡️\n 🥅 13⬇️ 33➡️\n ⚽️ 13⬇️ 19➡️\n \n paste\n ⛹️‍♀️ 17⬇️ 14➡️\n ⛹️‍♀️ 17⬇️ 17➡️\n ⛹️‍♀️ 13⬇️ 17➡️\n ⛹️‍♀️ 13⬇️ 14➡️\n ⛹️‍♀️ 8⬇️ 14➡️\n ⛹️‍♀️ 8⬇️ 17➡️\n ⛹️‍♀️ 10⬇️ 14➡️\n ⛹️‍♀️ 9⬇️ 10➡️\n ⛹️‍♀️ 13⬇️ 8➡️\n ⛹️‍♀️ 13⬇️ 10➡️\n ⛹️‍♀️ 17⬇️ 10➡️\n \n paste\n ⛹️‍♂️ 13⬇️ 31➡️\n ⛹️‍♂️ 17⬇️ 28➡️\n ⛹️‍♂️ 13⬇️ 28➡️\n ⛹️‍♂️ 8⬇️ 29➡️\n ⛹️‍♂️ 8⬇️ 25➡️\n ⛹️‍♂️ 10⬇️ 25➡️\n ⛹️‍♂️ 13⬇️ 25➡️\n ⛹️‍♂️ 17⬇️ 25➡️\n ⛹️‍♂️ 17⬇️ 21➡️\n ⛹️‍♂️ 8⬇️ 21➡️\n ⛹️‍♂️ 13⬇️ 21➡️\n \nstartupIdeas\n question What is the effect of ideas vs ideas with revenue?\n \n 👨‍💼🔖\n comment person with an idea\n onTick\n jitter\n \n 👨‍💼💰\n comment peron with an idea\n that is making money\n onTick\n jitter\n \n 👨‍\n onTick .1\n jitter\n onTick .1\n turnToward 👨‍💼💰\n move\n \n \n size 10\n insert 200 👨‍\n insert 30 👨‍💼🔖\n insert 3 👨‍💼💰\n \n \nstore\n 🚶🏻\n onTick\n move\n angle North\n 🛒\n 🚪\n onTick .1\n spawn 🚶🏻\n 🪵\n solid\n \n size 25\n \n rectangle 🪵 30 15 3 3\n paste\n 🚪 16⬇️ 17➡️\n \nvirus\n question What might the spread of a simple virus look like?\n \n 🧟\n health 100\n onTick .9\n decrease health\n jitter\n onTick .01\n log recovered\n replaceWith 🦸‍♂️\n onDeath\n replaceWith 🪦\n \n 🙍\n onTick\n jitter\n onTouch\n 🧟\n replaceWith 🧟\n \n 🦸‍♂️\n onTick\n jitter\n \n insert 10% 🙍\n insert 1 🧟\n \n 🪦\n \n onExtinct 🧟\n log No more cases.\n pause\nwaves\n 🌊\n onTick\n move\n angle South\n \n size 25\n ticksPerSecond 5\n \n rectangle 🌊 100 1 0\n rectangle 🌊 100 1 0 6\n rectangle 🌊 100 1 0 11\nzombies\n question Can you protect the family from the zombies?\n \n 🧟‍♂️\n noPalette\n onTick\n jitter\n onHit\n 🪃\n replaceWith 🪦\n 💣\n replaceWith 🪦\n 👨‍👩‍👧‍👦\n pause\n alert TheyGotYou!\n \n 🧱\n solid\n \n 🔫\n onTick .1\n spawn 🪃\n \n 🪃\n noPalette\n angle West\n onTick\n move\n \n 💣\n \n 🪦\n noPalette\n comment Dead zombie\n \n 👨‍👩‍👧‍👦\n noPalette\n \n size 30\n ticksPerSecond 10\n \n insertCluster 30 🧟‍♂️ 1 1\n paste\n 👨‍👩‍👧‍👦 12⬇️ 11➡️"}
    dist/libs.js
    Changed around line 10484: Z.prototype.chain=tf,Z.prototype.commit=rf,Z.prototype.next=ef,Z.prototype.plant
    - "use strict"
    - this._tickTime = Date.now() - (TreeUtils.isNodeJs() ? 1000 * process.uptime() : 0)
    + this._tickTime = Date.now() - (Utils.isNodeJs() ? 1000 * process.uptime() : 0)
    Changed around line 10499: class Timer {
    - class TreeUtils {
    + class Utils {
    + static runCommand(instance, command = "", param = undefined) {
    + const run = name => {
    + console.log(`Running ${name}:`)
    + instance[name](param)
    + }
    + if (instance[command + "Command"]) return run(command + "Command")
    + // Get commands from both the child and parent classes
    + const classes = [Object.getPrototypeOf(instance), Object.getPrototypeOf(Object.getPrototypeOf(instance))]
    + const allCommands = classes.map(classInstance => Object.getOwnPropertyNames(classInstance).filter(word => word.endsWith("Command"))).flat()
    + allCommands.sort()
    + const commandAsNumber = parseInt(command) - 1
    + if (command.match(/^\d+$/) && allCommands[commandAsNumber]) return run(allCommands[commandAsNumber])
    + console.log(`\n❌ No command provided. Available commands:\n\n` + allCommands.map((name, index) => `${index + 1}. ${name.replace("Command", "")}`).join("\n") + "\n")
    + }
    + static removeReturnChars(str = "") {
    + return str.replace(/\r/g, "")
    + }
    + static isAbsoluteUrl(url) {
    + return url.startsWith("https://") || url.startsWith("http://")
    + }
    + static removeEmptyLines(str = "") {
    + return str.replace(/\n\n+/g, "\n")
    + }
    + static shiftRight(str = "", numSpaces = 1) {
    + let spaces = " ".repeat(numSpaces)
    + return str.replace(/\n/g, `\n${spaces}`)
    + }
    + static getLinks(str = "") {
    + const _re = new RegExp("(^|[ \t\r\n])((ftp|http|https):(([A-Za-z0-9$_.+!*(),;/?:@&~=-])|%[A-Fa-f0-9]{2}){2,}(#([a-zA-Z0-9][a-zA-Z0-9$_.+!*(),;/?:@&~=%-]*))?([A-Za-z0-9$_+!*();/?:~-]))", "g")
    + return str.match(_re) || []
    + }
    + // Only allow text content and inline styling. Don't allow HTML tags or any nested scroll tags or escape characters.
    + static escapeScrollAndHtml(content = "") {
    + return content.replace(/
    + }
    + static ensureDelimiterNotFound(strings, delimiter) {
    + const hit = strings.find(word => word.includes(delimiter))
    + if (hit) throw `Delimiter "${delimiter}" found in hit`
    + }
    + // https://github.com/rigoneri/indefinite-article.js/blob/master/indefinite-article.js
    + static getIndefiniteArticle(phrase) {
    + // Getting the first word
    + const match = /\w+/.exec(phrase)
    + let word
    + if (match) word = match[0]
    + else return "an"
    + var l_word = word.toLowerCase()
    + // Specific start of words that should be preceded by 'an'
    + var alt_cases = ["honest", "hour", "hono"]
    + for (var i in alt_cases) {
    + if (l_word.indexOf(alt_cases[i]) == 0) return "an"
    + }
    + // Single letter word which should be preceded by 'an'
    + if (l_word.length == 1) {
    + if ("aedhilmnorsx".indexOf(l_word) >= 0) return "an"
    + else return "a"
    + }
    + // Capital words which should likely be preceded by 'an'
    + if (word.match(/(?!FJO|[HLMNS]Y.|RY[EO]|SQU|(F[LR]?|[HL]|MN?|N|RH?|S[CHKLMNPTVW]?|X(YL)?)[AEIOU])[FHLMNRSX][A-Z]/)) {
    + return "an"
    + }
    + // Special cases where a word that begins with a vowel should be preceded by 'a'
    + const regexes = [/^e[uw]/, /^onc?e\b/, /^uni([^nmd]|mo)/, /^u[bcfhjkqrst][aeiou]/]
    + for (var i in regexes) {
    + if (l_word.match(regexes[i])) return "a"
    + }
    + // Special capital words (UK, UN)
    + if (word.match(/^U[NK][AIEO]/)) {
    + return "a"
    + } else if (word == word.toUpperCase()) {
    + if ("aedhilmnorsx".indexOf(l_word[0]) >= 0) return "an"
    + else return "a"
    + }
    + // Basic method of words that begin with a vowel being preceded by 'an'
    + if ("aeiou".indexOf(l_word[0]) >= 0) return "an"
    + // Instances where y follwed by specific letters is preceded by 'an'
    + if (l_word.match(/^y(b[lor]|cl[ea]|fere|gg|p[ios]|rou|tt)/)) return "an"
    + return "a"
    + }
    + static htmlEscaped(content = "") {
    + return content.replace(/
    + }
    + static isValidEmail(email = "") {
    + return email.toLowerCase().match(/^(([^<>()[\]\\.,;:\s@"]+(\.[^<>()[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/)
    + }
    + static capitalizeFirstLetter(str) {
    + return str.charAt(0).toUpperCase() + str.slice(1)
    + }
    + // generate a random alpha numeric hash:
    + static getRandomCharacters(length) {
    + const characters = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"
    + let result = ""
    + for (let i = 0; i < length; i++) {
    + result += characters.charAt(Math.floor(Math.random() * characters.length))
    + }
    + return result
    + }
    Changed around line 10621: class TreeUtils {
    + static titleToPermalink(str) {
    + return str
    + .replace(/[\/\_\:\\\[\]]/g, "-")
    + .replace(/π/g, "pi")
    + .replace(/`/g, "tick")
    + .replace(/\$/g, "dollar-sign")
    + .replace(/\*$/g, "-star")
    + .replace(/^\*/g, "star-")
    + .replace(/\*/g, "-star-")
    + .replace(/\'+$/g, "q")
    + .replace(/^@/g, "at-")
    + .replace(/@$/g, "-at")
    + .replace(/@/g, "-at-")
    + .replace(/[\'\"\,\ū]/g, "")
    + .replace(/^\#/g, "sharp-")
    + .replace(/\#$/g, "-sharp")
    + .replace(/\#/g, "-sharp-")
    + .replace(/[\(\)]/g, "")
    + .replace(/\+\+$/g, "pp")
    + .replace(/\+$/g, "p")
    + .replace(/^\!/g, "bang-")
    + .replace(/\!$/g, "-bang")
    + .replace(/\!/g, "-bang-")
    + .replace(/\&/g, "-n-")
    + .replace(/[\+ ]/g, "-")
    + .replace(/[^a-zA-Z0-9\-\.]/g, "")
    + .toLowerCase()
    + }
    Changed around line 10661: class TreeUtils {
    - matrix.push(TreeUtils.makeVector(cols, fill))
    + matrix.push(Utils.makeVector(cols, fill))
    Changed around line 10702: class TreeUtils {
    - const randFn = TreeUtils._getPseudoRandom0to1FloatGenerator(seed)
    + const randFn = Utils._getPseudoRandom0to1FloatGenerator(seed)
    Changed around line 10711: class TreeUtils {
    - return str.length
    - ? str
    - .toLowerCase()
    - .replace(reg, "")
    - .replace(/ /g, "-")
    - : ""
    + return str.length ? str.toLowerCase().replace(reg, "").replace(/ /g, "-") : ""
    Changed around line 10809: class TreeUtils {
    - const editDistance = TreeUtils._getEditDistance(str, caseSensitive ? candidate : candidate.toLowerCase(), maximumEditDistanceToBeBestMatch)
    + const editDistance = Utils._getEditDistance(str, caseSensitive ? candidate : candidate.toLowerCase(), maximumEditDistanceToBeBestMatch)
    Changed around line 10820: class TreeUtils {
    - maxInt = maxInt || maxInt === 0 ? maxInt : TreeUtils.MAX_INT
    + maxInt = maxInt || maxInt === 0 ? maxInt : Utils.MAX_INT
    Changed around line 10843: class TreeUtils {
    - colMin = TreeUtils.MAX_INT
    + colMin = Utils.MAX_INT
    Changed around line 10928: class TreeUtils {
    - const randFn = TreeUtils._getPseudoRandom0to1FloatGenerator(seed)
    + const randFn = Utils._getPseudoRandom0to1FloatGenerator(seed)
    Changed around line 10939: class TreeUtils {
    - const randFn = TreeUtils._getPseudoRandom0to1FloatGenerator(seed)
    + const randFn = Utils._getPseudoRandom0to1FloatGenerator(seed)
    Changed around line 10957: class TreeUtils {
    - return function() {
    + return function () {
    Changed around line 11085: class TreeUtils {
    - TreeUtils.Timer = Timer
    + Utils.Timer = Timer
    - TreeUtils.linkify = text => {
    + Utils.linkify = (text, target = "_blank") => {
    - replacePattern1 = /(\b(https?|ftp):\/\/[-A-Z0-9+&@#\/%?=~_|!:,.;]*[-A-Z0-9+&@#\/%=~_|])/gim
    - replacedText = text.replace(replacePattern1, '$1')
    + replacePattern1 = /(\b(https?|ftp):\/\/[-A-Z\(\)0-9+&@#\/%?=~_|!:,.;]*[-A-Z0-9+\(\)&@#\/%=~_|])/gim
    + replacedText = text.replace(replacePattern1, `$1`)
    - replacedText = replacedText.replace(replacePattern2, '$1$2')
    + replacedText = replacedText.replace(replacePattern2, `$1$2`)
    - TreeUtils.makeSemiRandomFn = (seed = Date.now()) => {
    + Utils.makeSemiRandomFn = (seed = Date.now()) => {
    - TreeUtils.randomUniformInt = (min, max, seed = Date.now()) => {
    - return Math.floor(TreeUtils.randomUniformFloat(min, max, seed))
    + Utils.randomUniformInt = (min, max, seed = Date.now()) => {
    + return Math.floor(Utils.randomUniformFloat(min, max, seed))
    - TreeUtils.randomUniformFloat = (min, max, seed = Date.now()) => {
    - const randFn = TreeUtils.makeSemiRandomFn(seed)
    + Utils.randomUniformFloat = (min, max, seed = Date.now()) => {
    + const randFn = Utils.makeSemiRandomFn(seed)
    - TreeUtils.getRange = (startIndex, endIndexExclusive, increment = 1) => {
    + Utils.getRange = (startIndex, endIndexExclusive, increment = 1) => {
    - TreeUtils.MAX_INT = Math.pow(2, 32) - 1
    - window.TreeUtils = TreeUtils
    - class TestRacerTestBlock {
    - constructor(testFile, testName, fn) {
    - this._parentFile = testFile
    - this._testName = testName
    - this._testFn = fn
    - }
    - _emitMessage(message) {
    - this._parentFile.getRunner()._emitMessage(message)
    - return message
    - }
    - async execute() {
    - let passes = []
    - let failures = []
    - const assertEqual = (actual, expected, message = "") => {
    - if (expected === actual) {
    - passes.push(message)
    - } else {
    - failures.push([actual, expected, message])
    - }
    - }
    - try {
    - await this._testFn(assertEqual)
    - } catch (err) {
    - failures.push([
    - "1",
    - "0",
    - `Should not have uncaught errors but in ${this._testName} got error:
    - toString:
    - ${new TreeNode(err.toString()).toString(2)}
    - stack:
    - ${new TreeNode(err.stack).toString(2)}`
    - ])
    - }
    - failures.length ? this._emitBlockFailedMessage(failures) : this._emitBlockPassedMessage(passes)
    - return {
    - passes,
    - failures
    - }
    - }
    - _emitBlockPassedMessage(passes) {
    - this._emitMessage(`ok block ${this._testName} - ${passes.length} passed`)
    - }
    - _emitBlockFailedMessage(failures) {
    - // todo: should replace not replace last newline?
    - // todo: do side by side.
    - // todo: add diff.
    - this._emitMessage(`failed block ${this._testName}`)
    - this._emitMessage(
    - failures
    - .map(failure => {
    - const actualVal = failure[0] === undefined ? "undefined" : failure[0].toString()
    - const expectedVal = failure[1] === undefined ? "undefined" : failure[1].toString()
    - const actual = new jtree.TreeNode(`actual\n${new jtree.TreeNode(actualVal).toString(1)}`)
    - const expected = new jtree.TreeNode(`expected\n${new jtree.TreeNode(expectedVal.toString()).toString(1)}`)
    - const comparison = actual.toComparison(expected)
    - return new jtree.TreeNode(` assertion ${failure[2]}\n${comparison.toSideBySide([actual, expected]).toString(2)}`)
    - })
    - .join("\n")
    - )
    - }
    - }
    - class TestRacerFile {
    - constructor(runner, testTree, fileName) {
    - this._runner = runner
    - this._testTree = {}
    - this._fileName = fileName
    - Object.keys(testTree).forEach(key => {
    - this._testTree[key] = new TestRacerTestBlock(this, key, testTree[key])
    - })
    - }
    - getRunner() {
    - return this._runner
    - }
    - getFileName() {
    - return this._fileName
    - }
    - get length() {
    - return Object.values(this._testTree).length
    - }
    - get skippedTestBlockNames() {
    - const testsToRun = this._filterSkippedTestBlocks()
    - return Object.keys(this._testTree).filter(blockName => !testsToRun.includes(blockName))
    - }
    - _emitMessage(message) {
    - this.getRunner()._emitMessage(message)
    - }
    - _filterSkippedTestBlocks() {
    - // _ prefix = run on these tests block
    - // $ prefix = skip this test
    - const runOnlyTheseTestBlocks = Object.keys(this._testTree).filter(key => key.startsWith("_"))
    - if (runOnlyTheseTestBlocks.length) return runOnlyTheseTestBlocks
    - return Object.keys(this._testTree).filter(key => !key.startsWith("$"))
    - }
    - async execute() {
    - const testBlockNames = this._filterSkippedTestBlocks()
    - this._emitStartFileMessage(testBlockNames.length)
    - const fileTimer = new TreeUtils.Timer()
    - const blockResults = {}
    - const blockPromises = testBlockNames.map(async testName => {
    - const results = await this._testTree[testName].execute()
    - blockResults[testName] = results
    - })
    - await Promise.all(blockPromises)
    - const fileStats = this._aggregateBlockResultsIntoFileResults(blockResults)
    - const fileTimeElapsed = fileTimer.tick()
    - fileStats.blocksFailed ? this._emitFileFailedMessage(fileStats, fileTimeElapsed, testBlockNames.length) : this._emitFilePassedMessage(fileStats, fileTimeElapsed, testBlockNames.length)
    - return fileStats
    - }
    - _aggregateBlockResultsIntoFileResults(fileBlockResults) {
    - const fileStats = {
    - assertionsPassed: 0,
    - assertionsFailed: 0,
    - blocksPassed: 0,
    - blocksFailed: 0,
    - failedBlocks: []
    - }
    - Object.keys(fileBlockResults).forEach(blockName => {
    - const results = fileBlockResults[blockName]
    - fileStats.assertionsPassed += results.passes.length
    - fileStats.assertionsFailed += results.failures.length
    - if (results.failures.length) {
    - fileStats.blocksFailed++
    - fileStats.failedBlocks.push(blockName)
    - } else fileStats.blocksPassed++
    - })
    - return fileStats
    - }
    - _emitStartFileMessage(blockCount) {
    - this._emitMessage(`start file ${blockCount} test blocks in file ${this._fileName}`)
    - }
    - _emitFilePassedMessage(fileStats, fileTimeElapsed, blockCount) {
    - this._emitMessage(`ok file ${this._fileName} in ${fileTimeElapsed}ms. ${blockCount} blocks and ${fileStats.assertionsPassed} assertions passed.`)
    - }
    - _emitFileFailedMessage(fileStats, fileTimeElapsed, blockCount) {
    - this._emitMessage(
    - `failed file ${this._fileName} over ${fileTimeElapsed}ms. ${fileStats.blocksFailed} blocks and ${fileStats.assertionsFailed} failed. ${blockCount - fileStats.blocksFailed} blocks and ${fileStats.assertionsPassed} assertions passed`
    - )
    - }
    - }
    - class TestRacer {
    - constructor(fileTestTree) {
    - this._logFunction = console.log
    - this._timer = new TreeUtils.Timer()
    - this._sessionFilesPassed = 0
    - this._sessionFilesFailed = {}
    - this._sessionBlocksFailed = 0
    - this._sessionBlocksPassed = 0
    - this._sessionAssertionsFailed = 0
    - this._sessionAssertionsPassed = 0
    - this._fileTestTree = {}
    - Object.keys(fileTestTree).forEach(fileName => {
    - this._fileTestTree[fileName] = new TestRacerFile(this, fileTestTree[fileName], fileName)
    - })
    - }
    - setLogFunction(logFunction) {
    - this._logFunction = logFunction
    - return this
    - }
    - _addFileResultsToSessionResults(fileStats, fileName) {
    - this._sessionAssertionsPassed += fileStats.assertionsPassed
    - this._sessionAssertionsFailed += fileStats.assertionsFailed
    - this._sessionBlocksPassed += fileStats.blocksPassed
    - this._sessionBlocksFailed += fileStats.blocksFailed
    - if (!fileStats.blocksFailed) this._sessionFilesPassed++
    - else {
    - this._sessionFilesFailed[fileName] = fileStats.failedBlocks
    - }
    - }
    - async execute() {
    - this._emitSessionPlanMessage()
    - const proms = Object.values(this._fileTestTree).map(async testFile => {
    - const results = await testFile.execute()
    - this._addFileResultsToSessionResults(results, testFile.getFileName())
    - })
    - await Promise.all(proms)
    - return this
    - }
    - finish() {
    - return this._emitSessionFinishMessage()
    - }
    - _emitMessage(message) {
    - this._logFunction(message)
    - return message
    - }
    - get length() {
    - return Object.values(this._fileTestTree).length
    - }
    - _emitSessionPlanMessage() {
    - let blocks = 0
    - Object.values(this._fileTestTree).forEach(value => (blocks += value.length))
    - this._emitMessage(`${this.length} files and ${blocks} blocks to run. ${this._getSkippedBlockNames().length} skipped blocks.`)
    - }
    - _getSkippedBlockNames() {
    - const skippedBlocks = []
    - Object.values(this._fileTestTree).forEach(file => {
    - file.skippedTestBlockNames.forEach(blockName => {
    - skippedBlocks.push(blockName)
    - })
    - })
    - return skippedBlocks
    - }
    - _getFailures() {
    - if (!Object.keys(this._sessionFilesFailed).length) return ""
    - return `
    - failures
    - ${new TreeNode(this._sessionFilesFailed).forEach(row => row.forEach(line => line.deleteWordAt(0))).toString(2)}`
    - }
    - _emitSessionFinishMessage() {
    - const skipped = this._getSkippedBlockNames()
    - return this._emitMessage(`finished in ${this._timer.getTotalElapsedTime()}ms
    - skipped
    - ${skipped.length} blocks${skipped ? " " + skipped.join(" ") : ""}
    - passed
    - ${this._sessionFilesPassed} files
    - ${this._sessionBlocksPassed} blocks
    - ${this._sessionAssertionsPassed} assertions
    - failed
    - ${Object.keys(this._sessionFilesFailed).length} files
    - ${this._sessionBlocksFailed} blocks
    - ${this._sessionAssertionsFailed} assertions${this._getFailures()}`)
    - }
    - static async testSingleFile(fileName, testTree) {
    - const obj = {}
    - obj[fileName] = testTree
    - const session = new TestRacer(obj)
    - await session.execute()
    - session.finish()
    - }
    - }
    - window.TestRacer = TestRacer
    + Utils.MAX_INT = Math.pow(2, 32) - 1
    + window.Utils = Utils
    +
    +
    Changed around line 11146: class AbstractNode {
    - ;(function(FileFormat) {
    + ;(function (FileFormat) {
    Changed around line 11174: class TreeWord {
    - ;(function(WhereOperators) {
    + ;(function (WhereOperators) {
    Changed around line 11189: var WhereOperators
    - ;(function(TreeNotationConstants) {
    + ;(function (TreeNotationConstants) {
    - class Parser {
    - constructor(catchAllNodeConstructor, firstWordMap = {}, regexTests = undefined) {
    - this._catchAllNodeConstructor = catchAllNodeConstructor
    + class ParserCombinator {
    + constructor(catchAllParser, firstWordMap = {}, regexTests = undefined) {
    + this._catchAllParser = catchAllParser
    Changed around line 11214: class Parser {
    - _getNodeConstructor(line, contextNode, wordBreakSymbol = " ") {
    - return this._getFirstWordMap().get(this._getFirstWord(line, wordBreakSymbol)) || this._getConstructorFromRegexTests(line) || this._getCatchAllNodeConstructor(contextNode)
    + _getParser(line, contextNode, wordBreakSymbol = " ") {
    + return this._getFirstWordMap().get(this._getFirstWord(line, wordBreakSymbol)) || this._getParserFromRegexTests(line) || this._getCatchAllParser(contextNode)
    - _getCatchAllNodeConstructor(contextNode) {
    - if (this._catchAllNodeConstructor) return this._catchAllNodeConstructor
    - const parent = contextNode.getParent()
    - if (parent) return parent._getParser()._getCatchAllNodeConstructor(parent)
    + _getCatchAllParser(contextNode) {
    + if (this._catchAllParser) return this._catchAllParser
    + const parent = contextNode.parent
    + if (parent) return parent._getParser()._getCatchAllParser(parent)
    - _getConstructorFromRegexTests(line) {
    + _getParserFromRegexTests(line) {
    - if (hit) return hit.nodeConstructor
    + if (hit) return hit.parser
    Changed around line 11251: class TreeNode extends AbstractNode {
    - getLineCellTypes() {
    + get lineCellTypes() {
    - return "undefinedCellType ".repeat(this.getWords().length).trim()
    + return "undefinedCellType ".repeat(this.words.length).trim()
    Changed around line 11263: class TreeNode extends AbstractNode {
    - return this.getParent().slice(0, this.getIndex())
    + return this.parent.slice(0, this.getIndex())
    Changed around line 11271: class TreeNode extends AbstractNode {
    - return this.getParent().slice(this.getIndex() + 1)
    + return this.parent.slice(this.getIndex() + 1)
    - return this.getParent().filter(node => node !== this)
    + return this.parent.filter(node => node !== this)
    - getParent() {
    + get parent() {
    - getIndentation(relativeTo) {
    - const indentLevel = this._getIndentLevel(relativeTo) - 1
    + get indentation() {
    + const indentLevel = this._getIndentLevel() - 1
    - return this.getEdgeSymbol().repeat(indentLevel)
    + return this.edgeSymbol.repeat(indentLevel)
    Changed around line 11299: class TreeNode extends AbstractNode {
    - getTopDownArray() {
    + get topDownArray() {
    Changed around line 11317: class TreeNode extends AbstractNode {
    - getNumberOfLines() {
    + get numberOfLines() {
    Changed around line 11327: class TreeNode extends AbstractNode {
    - const count = node.getWords().length + node.getIndentLevel()
    + const count = node.words.length + node.getIndentLevel()
    - getNumberOfWords() {
    + get numberOfWords() {
    - wordCount += node.getWords().length
    + wordCount += node.words.length
    - getLineNumber() {
    + get lineNumber() {
    - for (let node of this.getRootNode().getTopDownArrayIterator()) {
    + for (let node of this.root.getTopDownArrayIterator()) {
    Changed around line 11358: class TreeNode extends AbstractNode {
    - return !this.length && !this.getContent()
    + return !this.length && !this.content
    - const start = relativeTo || this.getRootNode()
    + const start = relativeTo || this.root
    - return relativeTo === this || !this.getParent()
    + return relativeTo === this || !this.parent
    - getRootNode() {
    + get root() {
    - return this.getParent()._getRootNode(relativeTo)
    + return this.parent._getRootNode(relativeTo)
    - return language.getEdgeSymbol().repeat(indentCount) + this.getLine(language) + (this.length ? language.getNodeBreakSymbol() + this._childrenToString(indentCount + 1, language) : "")
    + return language.edgeSymbol.repeat(indentCount) + this.getLine(language) + (this.length ? language.nodeBreakSymbol + this._childrenToString(indentCount + 1, language) : "")
    + }
    + get asString() {
    + return this.toString()
    Changed around line 11405: class TreeNode extends AbstractNode {
    + get list() {
    + return this.getWordsFrom(1)
    + }
    Changed around line 11416: class TreeNode extends AbstractNode {
    - const edge = this.getEdgeSymbol().repeat(indentCount)
    + const edge = this.edgeSymbol.repeat(indentCount)
    - const childrenHtml = this.length ? `${this.getNodeBreakSymbol()}` + `${this._childrenToHtml(indentCount + 1)}` : ""
    + const childrenHtml = this.length ? `${this.nodeBreakSymbol}` + `${this._childrenToHtml(indentCount + 1)}` : ""
    - if (!this._words) this._words = this._getLine().split(this.getWordBreakSymbol())
    + if (!this._words) this._words = this._getLine().split(this.wordBreakSymbol)
    - getWords() {
    + get words() {
    - doesExtend(nodeTypeId) {
    + doesExtend(parserId) {
    Changed around line 11441: class TreeNode extends AbstractNode {
    - const parent = this.getParent()
    + const parent = this.parent
    Changed around line 11468: class TreeNode extends AbstractNode {
    - return this.isRoot() ? "" : this.getRootNode()._getProjectRootDir()
    + return this.isRoot() ? "" : this.root._getProjectRootDir()
    + }
    + // Concat 2 trees amd return a new true, but replace any nodes
    + // in this tree that start with the same node from the first tree with
    + // that patched version. Does not recurse.
    + patch(two) {
    + const copy = this.clone()
    + two.forEach(node => {
    + const hit = copy.getNode(node.getWord(0))
    + if (hit) hit.destroy()
    + })
    + copy.concat(two)
    + return copy
    Changed around line 11515: class TreeNode extends AbstractNode {
    - const xiLength = this.getEdgeSymbol().length
    - const numIndents = this._getIndentLevel(undefined) - 1
    + const xiLength = this.edgeSymbol.length
    + const numIndents = this._getIndentLevel() - 1
    - return (
    - indentPosition +
    - this.getWords()
    - .slice(0, wordIndex)
    - .join(this.getWordBreakSymbol()).length +
    - this.getWordBreakSymbol().length
    - )
    + return indentPosition + this.words.slice(0, wordIndex).join(this.wordBreakSymbol).length + this.wordBreakSymbol.length
    Changed around line 11527: class TreeNode extends AbstractNode {
    - node = node.getParent()
    + node = node.parent
    Changed around line 11542: class TreeNode extends AbstractNode {
    - this.getTopDownArray().forEach(line => {
    - line.getWords().forEach((word, index) => {
    - line.setWord(index, fill)
    - })
    + this.topDownArray.forEach(line => {
    + line.words.forEach((word, index) => line.setWord(index, fill))
    Changed around line 11564: class TreeNode extends AbstractNode {
    - const wordBreakSymbolLength = this.getWordBreakSymbol().length
    + const wordBreakSymbolLength = this.wordBreakSymbol.length
    - return this.getWords().map((word, wordIndex) => {
    + return this.words.map((word, wordIndex) => {
    Changed around line 11581: class TreeNode extends AbstractNode {
    - this.getWords().forEach((word, wordIndex) => {
    + this.words.forEach((word, wordIndex) => {
    Changed around line 11592: class TreeNode extends AbstractNode {
    - for (let node of this.getTopDownArray()) {
    + for (let node of this.topDownArray) {
    Changed around line 11611: class TreeNode extends AbstractNode {
    - getFirstWord() {
    - return this.getWords()[0]
    + get firstWord() {
    + return this.words[0]
    - getContent() {
    + get content() {
    - return words.length ? words.join(this.getWordBreakSymbol()) : undefined
    + return words.length ? words.join(this.wordBreakSymbol) : undefined
    - getContentWithChildren() {
    + get contentWithChildren() {
    - const content = this.getContent()
    - return (content ? content : "") + (this.length ? this.getNodeBreakSymbol() + this._childrenToString() : "")
    + const content = this.content
    + return (content ? content : "") + (this.length ? this.nodeBreakSymbol + this._childrenToString() : "")
    Changed around line 11631: class TreeNode extends AbstractNode {
    - const parent = this.getParent()
    + const parent = this.parent
    - .map((node, index) => this.getEdgeSymbol().repeat(index) + node.getLine())
    - .join(this.getNodeBreakSymbol())
    + .map((node, index) => this.edgeSymbol.repeat(index) + node.getLine())
    + .join(this.nodeBreakSymbol)
    - return this.getWords().join((language || this).getWordBreakSymbol())
    + return this.words.join((language || this).wordBreakSymbol)
    Changed around line 11662: class TreeNode extends AbstractNode {
    - else if (this.getParent().isRoot(relativeTo)) return this.getFirstWord()
    - return this.getParent()._getFirstWordPath(relativeTo) + this.getEdgeSymbol() + this.getFirstWord()
    + else if (this.parent.isRoot(relativeTo)) return this.firstWord
    + return this.parent._getFirstWordPath(relativeTo) + this.edgeSymbol + this.firstWord
    Changed around line 11679: class TreeNode extends AbstractNode {
    - const path = this.getParent()._getPathVector(relativeTo)
    + const path = this.parent._getPathVector(relativeTo)
    - return this.getParent()._indexOfNode(this)
    + return this.parent._indexOfNode(this)
    - return this.getWords()
    - .map((word, index) => `${TreeUtils.stripHtml(word)}`)
    - .join(`${this.getWordBreakSymbol()}`)
    + return this.words.map((word, index) => `${Utils.stripHtml(word)}`).join(`${this.wordBreakSymbol}`)
    - if (this.getContent() !== undefined) return this.getContentWithChildren()
    + if (this.content !== undefined) return this.contentWithChildren
    - const tag = this.getFirstWord()
    + const tag = this.firstWord
    - const content = this.getContent()
    + const content = this.content
    - const tupleValue = hasChildrenNoContent ? this.toObject() : hasContentAndHasChildren ? this.getContentWithChildren() : content
    - return [this.getFirstWord(), tupleValue]
    + const tupleValue = hasChildrenNoContent ? this.toObject() : hasContentAndHasChildren ? this.contentWithChildren : content
    + return [this.firstWord, tupleValue]
    Changed around line 11739: class TreeNode extends AbstractNode {
    - this.getTopDownArray().forEach(node => node._rightPad(newWidth, padCharacter))
    + this.topDownArray.forEach(node => node._rightPad(newWidth, padCharacter))
    - let linesToAdd = numberOfLines - this.getNumberOfLines()
    + let linesToAdd = numberOfLines - this.numberOfLines
    Changed around line 11756: class TreeNode extends AbstractNode {
    - clone.lengthen(next.getNumberOfLines())
    + clone.lengthen(next.numberOfLines)
    Changed around line 11780: class TreeNode extends AbstractNode {
    - const nodeDelimiter = this.getNodeBreakSymbol()
    + const nodeDelimiter = this.nodeBreakSymbol
    - TreeUtils.interweave(treesOrStrings.map(tree => tree.toString().split(nodeDelimiter)))
    + Utils.interweave(treesOrStrings.map(tree => tree.toString().split(nodeDelimiter)))
    Changed around line 11795: class TreeNode extends AbstractNode {
    - const words = this.getWords()
    + const words = this.words
    - return this.getTopDownArray().find(node => node._hasColumns(columns))
    + return this.topDownArray.find(node => node._hasColumns(columns))
    Changed around line 11829: class TreeNode extends AbstractNode {
    - return this.getTopDownArray().filter(node => node.isSelected())
    + return this.topDownArray.filter(node => node.isSelected())
    Changed around line 11915: class TreeNode extends AbstractNode {
    - this.getTopDownArray().forEach(node => {
    + this.topDownArray.forEach(node => {
    Changed around line 11947: class TreeNode extends AbstractNode {
    + // Flatten a tree node into an object like {twitter:"pldb", "twitter.followers":123}.
    + // Assumes you have a nested key/value list with no multiline strings.
    + toFlatObject(delimiter = ".") {
    + let newObject = {}
    + const { edgeSymbolRegex } = this
    + this.forEach((child, index) => {
    + newObject[child.getWord(0)] = child.content
    + child.topDownArray.forEach(node => {
    + const newColumnName = node.getFirstWordPathRelativeTo(this).replace(edgeSymbolRegex, delimiter)
    + const value = node.content
    + newObject[newColumnName] = value
    + })
    + })
    + return newObject
    + }
    Changed around line 11970: class TreeNode extends AbstractNode {
    - toHtml() {
    + get asHtml() {
    - this.getWords().forEach((word, index) => (word ? cells.push(getLine(index + indents, word)) : ""))
    + this.words.forEach((word, index) => (word ? cells.push(getLine(index + indents, word)) : ""))
    - toHtmlCube() {
    - return this.map((plane, planeIndex) =>
    - plane
    - .getTopDownArray()
    - .map((line, lineIndex) => line._toHtmlCubeLine(line.getIndentLevel() - 2, lineIndex, planeIndex))
    - .join("")
    - ).join("")
    + get asHtmlCube() {
    + return this.map((plane, planeIndex) => plane.topDownArray.map((line, lineIndex) => line._toHtmlCubeLine(line.getIndentLevel() - 2, lineIndex, planeIndex)).join("")).join("")
    - return `${this.getNodeBreakSymbol()}`
    + return `${this.nodeBreakSymbol}`
    - return this.map(node => node.toString(indentCount, language)).join(language.getNodeBreakSymbol())
    + return this.map(node => node.toString(indentCount, language)).join(language.nodeBreakSymbol)
    Changed around line 12007: class TreeNode extends AbstractNode {
    - toXml() {
    + get asXml() {
    Changed around line 12015: class TreeNode extends AbstractNode {
    - csv: tree => tree.toCsv(),
    - tsv: tree => tree.toTsv()
    + csv: tree => tree.asCsv,
    + tsv: tree => tree.asTsv
    Changed around line 12024: class TreeNode extends AbstractNode {
    - return prefix + `${this.getFirstWord()}:` + (this.getContent() ? " " + this.getContent() : "")
    + return prefix + `${this.firstWord}:` + (this.content ? " " + this.content : "")
    - toYaml() {
    + get asYaml() {
    Changed around line 12063: class TreeNode extends AbstractNode {
    - toJsonSubset() {
    + get asJsonSubset() {
    - cells: this.getWords(),
    + cells: this.words,
    - cells: this.getWords()
    + cells: this.words
    - toJson() {
    + get asJson() {
    - toGrid() {
    - const WordBreakSymbol = this.getWordBreakSymbol()
    + get asGrid() {
    + const WordBreakSymbol = this.wordBreakSymbol
    - .split(this.getNodeBreakSymbol())
    + .split(this.nodeBreakSymbol)
    - toGridJson() {
    - return JSON.stringify(this.toGrid(), null, 2)
    + get asGridJson() {
    + return JSON.stringify(this.asGrid, null, 2)
    - return this.getTopDownArray().filter(node => {
    + return this.topDownArray.filter(node => {
    Changed around line 12122: class TreeNode extends AbstractNode {
    - if (hit) return hit.getLine().substr((prefix + this.getWordBreakSymbol()).length)
    + if (hit) return hit.getLine().substr((prefix + this.wordBreakSymbol).length)
    - return node === undefined ? undefined : node.getContent()
    + return node === undefined ? undefined : node.content
    Changed around line 12138: class TreeNode extends AbstractNode {
    - const map = TreeUtils.arrayToMap(fields)
    + const map = Utils.arrayToMap(fields)
    Changed around line 12148: class TreeNode extends AbstractNode {
    - const edgeSymbol = this.getEdgeSymbol()
    + const edgeSymbol = this.edgeSymbol
    - return this.filter(node => node.getFirstWord() === globPath)
    + return this.filter(node => node.firstWord === globPath)
    - const matchingNodes = current === "*" ? this.getChildren() : this.filter(child => child.getFirstWord() === current)
    - return [].concat.apply([], matchingNodes.map(node => node._getNodesByGlobPath(rest)))
    + const matchingNodes = current === "*" ? this.getChildren() : this.filter(child => child.firstWord === current)
    + return [].concat.apply(
    + [],
    + matchingNodes.map(node => node._getNodesByGlobPath(rest))
    + )
    - const edgeSymbol = this.getEdgeSymbol()
    + const edgeSymbol = this.edgeSymbol
    Changed around line 12173: class TreeNode extends AbstractNode {
    - getNext() {
    + get next() {
    - const parent = this.getParent()
    + const parent = this.parent
    - getPrevious() {
    + get previous() {
    - const parent = this.getParent()
    + const parent = this.parent
    Changed around line 12195: class TreeNode extends AbstractNode {
    - obj[node.getFirstWord()] = 1
    + obj[node.firstWord] = 1
    - const ancestorNodes = this._getAncestorNodes((node, id) => node._getNodesByColumn(0, id), node => node.get(key), this)
    + const ancestorNodes = this._getAncestorNodes(
    + (node, id) => node._getNodesByColumn(0, id),
    + node => node.get(key),
    + this
    + )
    - const ancestorNodes = this._getAncestorNodes((node, id) => node._getNodesByColumn(thisColumnNumber, id), node => node.getWord(extendsColumnNumber), this)
    + const ancestorNodes = this._getAncestorNodes(
    + (node, id) => node._getNodesByColumn(thisColumnNumber, id),
    + node => node.getWord(extendsColumnNumber),
    + this
    + )
    - const potentialParentNodes = getPotentialParentNodesByIdFn(this.getParent(), parentId)
    + const potentialParentNodes = getPotentialParentNodesByIdFn(this.parent, parentId)
    Changed around line 12238: class TreeNode extends AbstractNode {
    - names.push(node.nodeAt(path[0]).getFirstWord())
    + names.push(node.nodeAt(path[0]).firstWord)
    Changed around line 12249: class TreeNode extends AbstractNode {
    - toCsv() {
    + get asCsv() {
    Changed around line 12298: class TreeNode extends AbstractNode {
    - _toArrays(header, cellFn) {
    + _toArrays(columnNames, cellFn) {
    - const headerArray = header.map((columnName, index) => cellFn(columnName, 0, index))
    + const header = columnNames.map((columnName, index) => cellFn(columnName, 0, index))
    - header.map((columnName, columnIndex) => {
    + columnNames.map((columnName, columnIndex) => {
    - const content = childNode ? childNode.getContentWithChildren() : ""
    + const content = childNode ? childNode.contentWithChildren : ""
    - rows: rows,
    - header: headerArray
    + rows,
    + header
    - toTable() {
    + get asTable() {
    Changed around line 12349: class TreeNode extends AbstractNode {
    - toSsv() {
    + get asSsv() {
    - toOutline() {
    + get asOutline() {
    Changed around line 12395: class TreeNode extends AbstractNode {
    - const NodeBreakSymbol = this.getNodeBreakSymbol()
    - const WordBreakSymbol = this.getWordBreakSymbol()
    + const NodeBreakSymbol = this.nodeBreakSymbol
    + const WordBreakSymbol = this.wordBreakSymbol
    - toMarkdownTable() {
    + get asMarkdownTable() {
    Changed around line 12416: class TreeNode extends AbstractNode {
    - toTsv() {
    + get asTsv() {
    - getNodeBreakSymbol() {
    + get nodeBreakSymbol() {
    - getWordBreakSymbol() {
    + get wordBreakSymbol() {
    - getNodeBreakSymbolRegex() {
    - return new RegExp(this.getNodeBreakSymbol(), "g")
    + get edgeSymbolRegex() {
    + return new RegExp(this.edgeSymbol, "g")
    - getEdgeSymbol() {
    + get nodeBreakSymbolRegex() {
    + return new RegExp(this.nodeBreakSymbol, "g")
    + }
    + get edgeSymbol() {
    - const lines = text.split(this.getNodeBreakSymbolRegex())
    + const lines = text.split(this.nodeBreakSymbolRegex)
    - .map(line => (line.substr(0, 1) === this.getEdgeSymbol() ? line : this.getEdgeSymbol() + line))
    + .map(line => (line.substr(0, 1) === this.edgeSymbol ? line : this.edgeSymbol + line))
    - .join(this.getNodeBreakSymbol())
    + .join(this.nodeBreakSymbol)
    Changed around line 12454: class TreeNode extends AbstractNode {
    - this._deleteByIndexes(TreeUtils.getRange(0, this.length))
    + this._deleteByIndexes(Utils.getRange(0, this.length))
    Changed around line 12512: class TreeNode extends AbstractNode {
    - const nodeConstructor = this._getParser()._getNodeConstructor(line, this)
    - const newNode = new nodeConstructor(children, line, this)
    + const parser = this._getParser()._getParser(line, this)
    + const newNode = new parser(children, line, this)
    + this.clearQuickCache()
    - const lines = str.split(this.getNodeBreakSymbolRegex())
    + const lines = str.split(this.nodeBreakSymbolRegex)
    Changed around line 12539: class TreeNode extends AbstractNode {
    - const nodeConstructor = parent._getParser()._getNodeConstructor(lineContent, parent)
    - lastNode = new nodeConstructor(undefined, lineContent, parent)
    + const parser = parent._getParser()._getParser(lineContent, parent)
    + lastNode = new parser(undefined, lineContent, parent)
    Changed around line 12551: class TreeNode extends AbstractNode {
    - return this.map(node => node.getContent())
    + return this.map(node => node.content)
    - // todo: rename to getChildrenByConstructor(?)
    - getChildrenByNodeConstructor(constructor) {
    - return this.filter(child => child instanceof constructor)
    + getChildrenByParser(parser) {
    + return this.filter(child => child instanceof parser)
    - getAncestorByNodeConstructor(constructor) {
    - if (this instanceof constructor) return this
    + getAncestorByParser(parser) {
    + if (this instanceof parser) return this
    - const parent = this.getParent()
    - return parent instanceof constructor ? parent : parent.getAncestorByNodeConstructor(constructor)
    + const parent = this.parent
    + return parent instanceof parser ? parent : parent.getAncestorByParser(parser)
    - // todo: rename to getNodeByConstructor(?)
    - getNodeByType(constructor) {
    - return this.find(child => child instanceof constructor)
    + getNodeByParser(parser) {
    + return this.find(child => child instanceof parser)
    Changed around line 12575: class TreeNode extends AbstractNode {
    - if (nodes[index].getFirstWord() === firstWord) return index
    + if (nodes[index].firstWord === firstWord) return index
    Changed around line 12583: class TreeNode extends AbstractNode {
    - return this.map(node => node.getFirstWord())
    + return this.map(node => node.firstWord)
    Changed around line 12591: class TreeNode extends AbstractNode {
    - newIndex[nodes[index].getFirstWord()] = index
    + newIndex[nodes[index].firstWord] = index
    Changed around line 12600: class TreeNode extends AbstractNode {
    - const edgeChar = this.getEdgeSymbol()
    + const edgeChar = this.edgeSymbol
    - clone() {
    - return new this.constructor(this.childrenToString(), this.getLine())
    + clone(children = this.childrenToString(), line = this.getLine()) {
    + return new this.constructor(children, line)
    - // todo: rename to hasFirstWord
    - has(firstWord) {
    + hasFirstWord(firstWord) {
    + has(firstWordPath) {
    + const edgeSymbol = this.edgeSymbol
    + if (!firstWordPath.includes(edgeSymbol)) return this.hasFirstWord(firstWordPath)
    + const parts = firstWordPath.split(edgeSymbol)
    + const next = this.getNode(parts.shift())
    + if (!next) return false
    + return next.has(parts.join(edgeSymbol))
    + }
    Changed around line 12637: class TreeNode extends AbstractNode {
    - return this.getChildren()
    - .reverse()
    - .find(fn)
    + return this.getChildren().reverse().find(fn)
    Changed around line 12657: class TreeNode extends AbstractNode {
    + get quickCache() {
    + if (!this._quickCache) this._quickCache = {}
    + return this._quickCache
    + }
    + getCustomIndex(key) {
    + if (!this.quickCache.customIndexes) this.quickCache.customIndexes = {}
    + const customIndexes = this.quickCache.customIndexes
    + if (customIndexes[key]) return customIndexes[key]
    + const customIndex = {}
    + customIndexes[key] = customIndex
    + this.filter(file => file.has(key)).forEach(file => {
    + const value = file.get(key)
    + if (!customIndex[value]) customIndex[value] = []
    + customIndex[value].push(file)
    + })
    + return customIndex
    + }
    + clearQuickCache() {
    + delete this._quickCache
    + }
    + this.clearQuickCache()
    Changed around line 12699: class TreeNode extends AbstractNode {
    - return this.isRoot() || this.getParent().isRoot() ? undefined : this.getParent().getParent()
    + return this.isRoot() || this.parent.isRoot() ? undefined : this.parent.parent
    - if (!TreeNode._parsers.has(this.constructor)) TreeNode._parsers.set(this.constructor, this.createParser())
    - return TreeNode._parsers.get(this.constructor)
    + if (!TreeNode._parserCombinators.has(this.constructor)) TreeNode._parserCombinators.set(this.constructor, this.createParserCombinator())
    + return TreeNode._parserCombinators.get(this.constructor)
    - createParser() {
    - return new Parser(this.constructor)
    + createParserCombinator() {
    + return new ParserCombinator(this.constructor)
    Changed around line 12728: class TreeNode extends AbstractNode {
    - return Math.max(this.getLineModifiedTime(), this.getChildArrayModifiedTime(), Math.max.apply(null, this.map(child => child.getLineOrChildrenModifiedTime())))
    + return Math.max(
    + this.getLineModifiedTime(),
    + this.getChildArrayModifiedTime(),
    + Math.max.apply(
    + null,
    + this.map(child => child.getLineOrChildrenModifiedTime())
    + )
    + )
    Changed around line 12791: class TreeNode extends AbstractNode {
    - const firstWord = sourceNode.getFirstWord()
    + const firstWord = sourceNode.firstWord
    Changed around line 12801: class TreeNode extends AbstractNode {
    - targetNode = this.touchNode(firstWord).setContent(sourceNode.getContent())
    + targetNode = this.touchNode(firstWord).setContent(sourceNode.content)
    Changed around line 12816: class TreeNode extends AbstractNode {
    - lastNode.getTopDownArray().forEach(node => {
    + lastNode.topDownArray.forEach(node => {
    Changed around line 12827: class TreeNode extends AbstractNode {
    - const wordBreakSymbol = clone.getWordBreakSymbol()
    + const wordBreakSymbol = clone.wordBreakSymbol
    Changed around line 12854: class TreeNode extends AbstractNode {
    - const wi = this.getWordBreakSymbol()
    + const wi = this.wordBreakSymbol
    Changed around line 12862: class TreeNode extends AbstractNode {
    - this.getTopDownArray().forEach(node => {
    + this.topDownArray.forEach(node => {
    Changed around line 12870: class TreeNode extends AbstractNode {
    - const wi = this.getWordBreakSymbol()
    + const wi = this.wordBreakSymbol
    Changed around line 12880: class TreeNode extends AbstractNode {
    - if (content === this.getContent()) return this
    - const newArray = [this.getFirstWord()]
    + if (content === this.content) return this
    + const newArray = [this.firstWord]
    - if (content.match(this.getNodeBreakSymbol())) return this.setContentWithChildren(content)
    + if (content.match(this.nodeBreakSymbol)) return this.setContentWithChildren(content)
    - this._setLine(newArray.join(this.getWordBreakSymbol()))
    + this._setLine(newArray.join(this.wordBreakSymbol))
    - return this.getParent().insertLineAndChildren(line, children, this.getIndex())
    + return this.parent.insertLineAndChildren(line, children, this.getIndex())
    - return this.getParent().insertLineAndChildren(line, children, this.getIndex() + 1)
    + return this.parent.insertLineAndChildren(line, children, this.getIndex() + 1)
    - if (!text.includes(this.getNodeBreakSymbol())) {
    + if (!text.includes(this.nodeBreakSymbol)) {
    - const lines = text.split(this.getNodeBreakSymbolRegex())
    + const lines = text.split(this.nodeBreakSymbolRegex)
    - const remainingString = lines.join(this.getNodeBreakSymbol())
    + const remainingString = lines.join(this.nodeBreakSymbol)
    Changed around line 12919: class TreeNode extends AbstractNode {
    - this.getParent()._clearIndex()
    + this.parent._clearIndex()
    - return this.getParent()._insertLineAndChildren(this.getLine(), this.childrenToString(), this.getIndex() + 1)
    + return this.parent._insertLineAndChildren(this.getLine(), this.childrenToString(), this.getIndex() + 1)
    Changed around line 12933: class TreeNode extends AbstractNode {
    - this.getParent()._deleteNode(this)
    + this.parent._deleteNode(this)
    Changed around line 12964: class TreeNode extends AbstractNode {
    + appendUniqueLine(line) {
    + if (!this.hasLine(line)) return this.appendLine(line)
    + return this.findLine(line)
    + }
    Changed around line 12980: class TreeNode extends AbstractNode {
    - this._getNodesByLineRegex(matches, columns.map(str => new RegExp("^" + str)))
    + this._getNodesByLineRegex(
    + matches,
    + columns.map(str => new RegExp("^" + str))
    + )
    Changed around line 13028: class TreeNode extends AbstractNode {
    - this.forEach(node => node.getWords().reverse())
    + this.forEach(node => node.words.reverse())
    Changed around line 13042: class TreeNode extends AbstractNode {
    - const firstWord = node.getFirstWord()
    + const firstWord = node.firstWord
    Changed around line 13060: class TreeNode extends AbstractNode {
    - if (node.getFirstWord() === firstWord) indexesToDelete.push(index)
    + if (node.firstWord === firstWord) indexesToDelete.push(index)
    - const edgeSymbol = this.getEdgeSymbol()
    + const edgeSymbol = this.edgeSymbol
    Changed around line 13077: class TreeNode extends AbstractNode {
    - const results = this.getTopDownArray().filter(node => node.hasDuplicateFirstWords())
    + const results = this.topDownArray.filter(node => node.hasDuplicateFirstWords())
    - const parent = this.getParent()
    + const parent = this.parent
    Changed around line 13107: class TreeNode extends AbstractNode {
    - const line = index.toString() + (content === undefined ? "" : this.getWordBreakSymbol() + content)
    + const line = index.toString() + (content === undefined ? "" : this.wordBreakSymbol + content)
    Changed around line 13121: class TreeNode extends AbstractNode {
    - const words = this.getWords()
    + const words = this.words
    Changed around line 13138: class TreeNode extends AbstractNode {
    - const parent = this.getParent()
    + const parent = this.parent
    Changed around line 13161: class TreeNode extends AbstractNode {
    - return this.setLine(words.join(this.getWordBreakSymbol()))
    + return this.setLine(words.join(this.wordBreakSymbol))
    - this.setWords(
    - this.getWords()
    - .slice(0, index)
    - .concat(words)
    - )
    + this.setWords(this.words.slice(0, index).concat(words))
    - const words = this.getWords()
    + const words = this.words
    Changed around line 13180: class TreeNode extends AbstractNode {
    - const valA = map[nodeA.getFirstWord()]
    - const valB = map[nodeB.getFirstWord()]
    + const valA = map[nodeA.firstWord]
    + const valB = map[nodeB.firstWord]
    Changed around line 13196: class TreeNode extends AbstractNode {
    - str = str.replace(this.getNodeBreakSymbolRegex(), "") // todo: do we want to do this sanitization?
    - return this._touchNode(str.split(this.getWordBreakSymbol()))
    + str = str.replace(this.nodeBreakSymbolRegex, "") // todo: do we want to do this sanitization?
    + return this._touchNode(str.split(this.wordBreakSymbol))
    Changed around line 13208: class TreeNode extends AbstractNode {
    + findLine(line) {
    + return this.getChildren().find(node => node.getLine() === line)
    + }
    Changed around line 13227: class TreeNode extends AbstractNode {
    - const wordsA = nodeA.getWords()
    - const wordsB = nodeB.getWords()
    + const wordsA = nodeA.words
    + const wordsB = nodeB.words
    Changed around line 13250: class TreeNode extends AbstractNode {
    - addObjectsAsDelimited(arrayOfObjects, delimiter = TreeUtils._chooseDelimiter(new TreeNode(arrayOfObjects).toString())) {
    + addObjectsAsDelimited(arrayOfObjects, delimiter = Utils._chooseDelimiter(new TreeNode(arrayOfObjects).toString())) {
    Changed around line 13261: class TreeNode extends AbstractNode {
    - setChildrenAsDelimited(tree, delimiter = TreeUtils._chooseDelimiter(tree.toString())) {
    + setChildrenAsDelimited(tree, delimiter = Utils._chooseDelimiter(tree.toString())) {
    - convertChildrenToDelimited(delimiter = TreeUtils._chooseDelimiter(this.childrenToString())) {
    + convertChildrenToDelimited(delimiter = Utils._chooseDelimiter(this.childrenToString())) {
    Changed around line 13280: class TreeNode extends AbstractNode {
    - const parentIndex = this.getParent().getIndex()
    + const parentIndex = this.parent.getIndex()
    - const parent = this.getParent()
    + const parent = this.parent
    Changed around line 13307: class TreeNode extends AbstractNode {
    - tree.getTopDownArray().forEach(node => {
    + tree.topDownArray.forEach(node => {
    Changed around line 13423: class TreeNode extends AbstractNode {
    - const cellDelimiter = language.getWordBreakSymbol()
    - const nodeDelimiter = language.getNodeBreakSymbol()
    + const cellDelimiter = language.wordBreakSymbol
    + const nodeDelimiter = language.nodeBreakSymbol
    Changed around line 13439: class TreeNode extends AbstractNode {
    - const cellDelimiter = language.getWordBreakSymbol()
    - const nodeDelimiter = language.getNodeBreakSymbol()
    + const cellDelimiter = language.wordBreakSymbol
    + const nodeDelimiter = language.nodeBreakSymbol
    Changed around line 13657: class TreeNode extends AbstractNode {
    + static fromFolder(folderPath, filepathPredicate = filepath => filepath !== ".DS_Store") {
    + const path = require("path")
    + const fs = require("fs")
    + const tree = new TreeNode()
    + const files = fs
    + .readdirSync(folderPath)
    + .map(filename => path.join(folderPath, filename))
    + .filter(filepath => !fs.statSync(filepath).isDirectory() && filepathPredicate(filepath))
    + .forEach(filePath => tree.appendLineAndChildren(filePath, fs.readFileSync(filePath, "utf8")))
    + return tree
    + }
    - TreeNode._parsers = new Map()
    - TreeNode.Parser = Parser
    + TreeNode._parserCombinators = new Map()
    + TreeNode.ParserCombinator = ParserCombinator
    Changed around line 13682: TreeNode.iris = `sepal_length,sepal_width,petal_length,petal_width,species
    - TreeNode.getVersion = () => "53.8.0"
    + TreeNode.getVersion = () => "74.0.0"
    Changed around line 13691: class AbstractExtendibleTreeNode extends TreeNode {
    - const path = node._getAncestorsArray().map(node => node._getId())
    + const path = node._getAncestorsArray().map(node => node.id)
    - _getChildrenByNodeConstructorInExtended(constructor) {
    - return TreeUtils.flatten(this._getAncestorsArray().map(node => node.getChildrenByNodeConstructor(constructor)))
    + _getChildrenByParserInExtended(parser) {
    + return Utils.flatten(this._getAncestorsArray().map(node => node.getChildrenByParser(parser)))
    Changed around line 13717: class AbstractExtendibleTreeNode extends TreeNode {
    - _doesExtend(nodeTypeId) {
    - return this._getAncestorSet().has(nodeTypeId)
    + _doesExtend(parserId) {
    + return this._getAncestorSet().has(parserId)
    - if (!this._cache_ancestorSet) this._cache_ancestorSet = new Set(this._getAncestorsArray().map(def => def._getId()))
    + if (!this._cache_ancestorSet) this._cache_ancestorSet = new Set(this._getAncestorsArray().map(def => def.id))
    Changed around line 13729: class AbstractExtendibleTreeNode extends TreeNode {
    - _getIdThatThisExtends() {
    + get idThatThisExtends() {
    Changed around line 13737: class AbstractExtendibleTreeNode extends TreeNode {
    - const extendedId = this._getIdThatThisExtends()
    + const extendedId = this.idThatThisExtends
    - const parentNode = this._getIdToNodeMap()[extendedId]
    + const parentNode = this.idToNodeMap[extendedId]
    Changed around line 13747: class AbstractExtendibleTreeNode extends TreeNode {
    - _getIdToNodeMap() {
    - if (!this.isRoot()) return this.getRootNode()._getIdToNodeMap()
    + get idToNodeMap() {
    + if (!this.isRoot()) return this.root.idToNodeMap
    - this._nodeMapCache[child._getId()] = child
    + this._nodeMapCache[child.id] = child
    - _getId() {
    + get id() {
    Changed around line 13766: window.ExtendibleTreeNode = ExtendibleTreeNode
    +
    +
    + // Compiled language parsers will include these files:
    + const GlobalNamespaceAdditions = {
    + Utils: "Utils.js",
    + TreeNode: "TreeNode.js",
    + HandGrammarProgram: "GrammarLanguage.js",
    + GrammarBackedNode: "GrammarLanguage.js"
    + }
    - ;(function(GrammarConstantsCompiler) {
    + ;(function (GrammarConstantsCompiler) {
    Changed around line 13784: var GrammarConstantsCompiler
    - var SQLiteTypes
    - ;(function(SQLiteTypes) {
    - SQLiteTypes["integer"] = "INTEGER"
    - SQLiteTypes["float"] = "FLOAT"
    - SQLiteTypes["text"] = "TEXT"
    - })(SQLiteTypes || (SQLiteTypes = {}))
    - ;(function(GrammarConstantsMisc) {
    + ;(function (GrammarConstantsMisc) {
    - GrammarConstantsMisc["tableName"] = "tableName"
    - ;(function(PreludeCellTypeIds) {
    + ;(function (PreludeCellTypeIds) {
    Changed around line 13800: var PreludeCellTypeIds
    - ;(function(GrammarConstantsConstantTypes) {
    + ;(function (GrammarConstantsConstantTypes) {
    - ;(function(GrammarBundleFiles) {
    + ;(function (GrammarBundleFiles) {
    Changed around line 13815: var GrammarBundleFiles
    - ;(function(GrammarCellParser) {
    + ;(function (GrammarCellParser) {
    - ;(function(GrammarConstants) {
    + ;(function (GrammarConstants) {
    - GrammarConstants["toolingDirective"] = "tooling"
    - GrammarConstants["todoComment"] = "todo"
    + GrammarConstants["comment"] = "//"
    - GrammarConstants["nodeType"] = "nodeType"
    + GrammarConstants["parser"] = "parser"
    - GrammarConstants["nodeTypeSuffix"] = "Node"
    + GrammarConstants["abstractParserPrefix"] = "abstract"
    + GrammarConstants["parserSuffix"] = "Parser"
    Changed around line 13840: var GrammarConstants
    - // baseNodeTypes
    - GrammarConstants["baseNodeType"] = "baseNodeType"
    - GrammarConstants["blobNode"] = "blobNode"
    - GrammarConstants["errorNode"] = "errorNode"
    + // baseParsers
    + GrammarConstants["baseParser"] = "baseParser"
    + GrammarConstants["blobParser"] = "blobParser"
    + GrammarConstants["errorParser"] = "errorParser"
    - GrammarConstants["abstract"] = "abstract"
    + GrammarConstants["listDelimiter"] = "listDelimiter"
    + GrammarConstants["contentKey"] = "contentKey"
    + GrammarConstants["childrenKey"] = "childrenKey"
    + GrammarConstants["uniqueFirstWord"] = "uniqueFirstWord"
    - GrammarConstants["catchAllNodeType"] = "catchAllNodeType"
    + GrammarConstants["catchAllParser"] = "catchAllParser"
    + GrammarConstants["uniqueLine"] = "uniqueLine"
    - // default catchAll nodeType
    - GrammarConstants["BlobNode"] = "BlobNode"
    - GrammarConstants["defaultRootNode"] = "defaultRootNode"
    + // default catchAll parser
    + GrammarConstants["BlobParser"] = "BlobParser"
    + GrammarConstants["DefaultRootParser"] = "DefaultRootParser"
    - GrammarConstants["compilerNodeType"] = "compiler"
    + GrammarConstants["compilerParser"] = "compiler"
    + GrammarConstants["sortTemplate"] = "sortTemplate"
    Changed around line 13895: class TypedWord extends TreeWord {
    - getDefinition() {
    - const handGrammarProgram = this.getHandGrammarProgram()
    - return this.isRoot() ? handGrammarProgram : handGrammarProgram.getNodeTypeDefinitionByNodeTypeId(this.constructor.name)
    - }
    - toSQLiteInsertStatement(primaryKeyFunction = node => node.getWord(0)) {
    - const def = this.getDefinition()
    - const tableName = def.getTableNameIfAny() || def._getId()
    - const columns = def.getSQLiteTableColumns()
    - const hits = columns.filter(colDef => this.has(colDef.columnName))
    - const values = hits.map(colDef => {
    - const node = this.getNode(colDef.columnName)
    - const content = node.getContent()
    - return colDef.type === SQLiteTypes.text ? `"${content}"` : content
    - })
    - hits.unshift({ columnName: "id", type: SQLiteTypes.text })
    - values.unshift(`"${primaryKeyFunction(this)}"`)
    - return `INSERT INTO ${tableName} (${hits.map(col => col.columnName).join(",")}) VALUES (${values.join(",")});`
    + get definition() {
    + if (this._definition) return this._definition
    + this._definition = this.isRoot() ? this.handGrammarProgram : this.parent.definition.getParserDefinitionByParserId(this.constructor.name)
    + return this._definition
    + }
    + get rootGrammarTree() {
    + return this.definition.root
    - getChildInstancesOfNodeTypeId(nodeTypeId) {
    - return this.filter(node => node.doesExtend(nodeTypeId))
    + get nodeIndex() {
    + // StringMap {firstWord: index}
    + // When there are multiple tails with the same firstWord, _index stores the last content.
    + // todo: change the above behavior: when a collision occurs, create an array.
    + return this._nodeIndex || this._makeNodeIndex()
    - doesExtend(nodeTypeId) {
    - return this.getDefinition()._doesExtend(nodeTypeId)
    + _clearIndex() {
    + delete this._nodeIndex
    + return super._clearIndex()
    - _getErrorNodeErrors() {
    - return [this.getFirstWord() ? new UnknownNodeTypeError(this) : new BlankLineError(this)]
    + _makeIndex(startAt = 0) {
    + if (this._nodeIndex) this._makeNodeIndex(startAt)
    + return super._makeIndex(startAt)
    - _getBlobNodeCatchAllNodeType() {
    - return BlobNode
    + _makeNodeIndex(startAt = 0) {
    + if (!this._nodeIndex || !startAt) this._nodeIndex = {}
    + const nodes = this._getChildrenArray()
    + const newIndex = this._nodeIndex
    + const length = nodes.length
    + for (let index = startAt; index < length; index++) {
    + const node = nodes[index]
    + const ancestors = Array.from(node.definition._getAncestorSet()).forEach(id => {
    + if (!newIndex[id]) newIndex[id] = []
    + newIndex[id].push(node)
    + })
    + }
    + return newIndex
    + }
    + getChildInstancesOfParserId(parserId) {
    + return this.nodeIndex[parserId] || []
    + }
    + doesExtend(parserId) {
    + return this.definition._doesExtend(parserId)
    + }
    + _getErrorParserErrors() {
    + return [this.firstWord ? new UnknownParserError(this) : new BlankLineError(this)]
    + }
    + _getBlobParserCatchAllParser() {
    + return BlobParser
    - const keywordMap = this.getDefinition().getFirstWordMapWithDefinitions()
    + const keywordMap = this.definition.firstWordMapWithDefinitions
    - return keywords.map(keyword => {
    - const def = keywordMap[keyword]
    - const description = def.getDescription()
    - return {
    - text: keyword,
    - displayText: keyword + (description ? " " + description : "")
    - }
    - })
    + return keywords
    + .map(keyword => {
    + const def = keywordMap[keyword]
    + if (def.suggestInAutocomplete === false) return false
    + const description = def.description
    + return {
    + text: keyword,
    + displayText: keyword + (description ? " " + description : "")
    + }
    + })
    + .filter(i => i)
    - const cell = this._getParsedCells()[cellIndex]
    + const cell = this.parsedCells[cellIndex]
    - getHandGrammarProgram() {
    + get handGrammarProgram() {
    - return this.getRootNode().getHandGrammarProgram()
    + return this.root.handGrammarProgram
    - const nodeTypeOrder = this.getDefinition()._getMyInScopeNodeTypeIds()
    - if (!nodeTypeOrder.length) return this
    + const parserOrder = this.definition._getMyInScopeParserIds()
    + if (!parserOrder.length) return this
    - nodeTypeOrder.forEach((word, index) => {
    - orderMap[word] = index
    - })
    - this.sort(
    - TreeUtils.makeSortByFn(runtimeNode => {
    - return orderMap[runtimeNode.getDefinition().getNodeTypeIdFromDefinition()]
    - })
    - )
    + parserOrder.forEach((word, index) => (orderMap[word] = index))
    + this.sort(Utils.makeSortByFn(runtimeNode => orderMap[runtimeNode.definition.parserIdFromDefinition]))
    - Object.values(this.getDefinition().getFirstWordMapWithDefinitions()).forEach(def => {
    - if (def.isRequired()) if (!this.getChildren().some(node => node.getDefinition() === def)) errors.push(new MissingRequiredNodeTypeError(this, def.getNodeTypeIdFromDefinition()))
    + Object.values(this.definition.firstWordMapWithDefinitions).forEach(def => {
    + if (def.isRequired() && !this.nodeIndex[def.id]) errors.push(new MissingRequiredParserError(this, def.id))
    - getProgramAsCells() {
    + get programAsCells() {
    - return this.getTopDownArray().map(node => {
    - const cells = node._getParsedCells()
    + return this.topDownArray.map(node => {
    + const cells = node.parsedCells
    Changed around line 14003: class GrammarBackedNode extends TreeNode {
    - getProgramWidth() {
    - return Math.max(...this.getProgramAsCells().map(line => line.length))
    + get programWidth() {
    + return Math.max(...this.programAsCells.map(line => line.length))
    - getAllTypedWords() {
    + get allTypedWords() {
    - this.getTopDownArray().forEach(node => {
    - node.getWordTypes().forEach((cell, index) => {
    - words.push(new TypedWord(node, index, cell.getCellTypeId()))
    - })
    - })
    + this.topDownArray.forEach(node => node.wordTypes.forEach((cell, index) => words.push(new TypedWord(node, index, cell.cellTypeId))))
    - return this.getAllTypedWords().filter(typedWord => typedWord.type === cellTypeId)
    + return this.allTypedWords.filter(typedWord => typedWord.type === cellTypeId)
    - findAllNodesWithNodeType(nodeTypeId) {
    - return this.getTopDownArray().filter(node => node.getDefinition().getNodeTypeIdFromDefinition() === nodeTypeId)
    + findAllNodesWithParser(parserId) {
    + return this.topDownArray.filter(node => node.definition.parserIdFromDefinition === parserId)
    - return this.getTopDownArray()
    - .map(child => child.getIndentation() + child.getLineCellTypes())
    - .join("\n")
    + return this.topDownArray.map(child => child.indentation + child.lineCellTypes).join("\n")
    - tree.getTopDownArray().map((node, lineNumber) => {
    + tree.topDownArray.map((node, lineNumber) => {
    - source: sourceNode.getIndentation() + sourceNode.getLine(),
    - nodeType: sourceNode.constructor.name,
    - cellTypes: node.getContent(),
    + source: sourceNode.indentation + sourceNode.getLine(),
    + parser: sourceNode.constructor.name,
    + cellTypes: node.content,
    - if (errorCount) obj.errorMessages = errs.map(err => err.getMessage()).join(";")
    + if (errorCount) obj.errorMessages = errs.map(err => err.message).join(";")
    - // Helper method for selecting potential nodeTypes needed to update grammar file.
    - getInvalidNodeTypes() {
    + // Helper method for selecting potential parsers needed to update grammar file.
    + get invalidParsers() {
    - .filter(err => err instanceof UnknownNodeTypeError)
    - .map(err => err.getNode().getFirstWord())
    + .filter(err => err instanceof UnknownParserError)
    + .map(err => err.getNode().firstWord)
    Changed around line 14078: class GrammarBackedNode extends TreeNode {
    - ).toTable()
    + ).asTable
    Changed around line 14095: class GrammarBackedNode extends TreeNode {
    - _sortWithParentNodeTypesUpTop() {
    - const familyTree = new HandGrammarProgram(this.toString()).getNodeTypeFamilyTree()
    + _sortWithParentParsersUpTop() {
    + const familyTree = new HandGrammarProgram(this.toString()).parserFamilyTree
    - familyTree.getTopDownArray().forEach((node, index) => {
    + familyTree.topDownArray.forEach((node, index) => {
    Changed around line 14114: class GrammarBackedNode extends TreeNode {
    - this._sortWithParentNodeTypesUpTop()
    + this._sortWithParentParsersUpTop()
    - this.getTopDownArray().forEach(child => {
    + this.topDownArray.forEach(child => {
    - getNodeTypeUsage(filepath = "") {
    - // returns a report on what nodeTypes from its language the program uses
    + sortFromSortTemplate() {
    + if (!this.length) return this
    + // Recurse
    + this.forEach(node => node.sortFromSortTemplate())
    + const def = this.isRoot() ? this.definition.rootParserDefinition : this.definition
    + const { sortIndices, sortSections } = def.sortSpec
    + // Sort and insert section breaks
    + if (sortIndices.size) {
    + // Sort keywords
    + this.sort((nodeA, nodeB) => {
    + var _a, _b
    + const aIndex = (_a = sortIndices.get(nodeA.firstWord)) !== null && _a !== void 0 ? _a : sortIndices.get(nodeA.sortKey)
    + const bIndex = (_b = sortIndices.get(nodeB.firstWord)) !== null && _b !== void 0 ? _b : sortIndices.get(nodeB.sortKey)
    + if (aIndex === undefined) console.error(`sortTemplate is missing "${nodeA.firstWord}"`)
    + const a = aIndex !== null && aIndex !== void 0 ? aIndex : 1000
    + const b = bIndex !== null && bIndex !== void 0 ? bIndex : 1000
    + return a > b ? 1 : a < b ? -1 : nodeA.getLine() > nodeB.getLine()
    + })
    + // pad sections
    + let currentSection = 0
    + this.forEach(node => {
    + var _a
    + const nodeSection = (_a = sortSections.get(node.firstWord)) !== null && _a !== void 0 ? _a : sortSections.get(node.sortKey)
    + const sectionHasAdvanced = nodeSection > currentSection
    + if (sectionHasAdvanced) {
    + currentSection = nodeSection
    + node.prependSibling("") // Put a blank line before this section
    + }
    + })
    + }
    + return this
    + }
    + getParserUsage(filepath = "") {
    + // returns a report on what parsers from its language the program uses
    - const handGrammarProgram = this.getHandGrammarProgram()
    - handGrammarProgram.getValidConcreteAndAbstractNodeTypeDefinitions().forEach(def => {
    - const requiredCellTypeIds = def.getCellParser().getRequiredCellTypeIds()
    - usage.appendLine([def.getNodeTypeIdFromDefinition(), "line-id", "nodeType", requiredCellTypeIds.join(" ")].join(" "))
    + const handGrammarProgram = this.handGrammarProgram
    + handGrammarProgram.validConcreteAndAbstractParserDefinitions.forEach(def => {
    + const requiredCellTypeIds = def.cellParser.getRequiredCellTypeIds()
    + usage.appendLine([def.parserIdFromDefinition, "line-id", "parser", requiredCellTypeIds.join(" ")].join(" "))
    - this.getTopDownArray().forEach((node, lineNumber) => {
    - const stats = usage.getNode(node.getNodeTypeId())
    - stats.appendLine([filepath + "-" + lineNumber, node.getWords().join(" ")].join(" "))
    + this.topDownArray.forEach((node, lineNumber) => {
    + const stats = usage.getNode(node.parserId)
    + stats.appendLine([filepath + "-" + lineNumber, node.words.join(" ")].join(" "))
    - return this.getTopDownArray()
    - .map(child => child.getIndentation() + child.getLineHighlightScopes())
    - .join("\n")
    + return this.topDownArray.map(child => child.indentation + child.getLineHighlightScopes()).join("\n")
    - return this.getTopDownArray()
    - .map(child => child.getDefinition().getLineNumber() + " " + child.getIndentation() + child.getCellDefinitionLineNumbers().join(" "))
    - .join("\n")
    + return this.topDownArray.map(child => child.definition.lineNumber + " " + child.indentation + child.cellDefinitionLineNumbers.join(" ")).join("\n")
    - toCellTypeTreeWithNodeConstructorNames() {
    - return this.getTopDownArray()
    - .map(child => child.constructor.name + this.getWordBreakSymbol() + child.getIndentation() + child.getLineCellTypes())
    - .join("\n")
    + get asCellTypeTreeWithParserIds() {
    + return this.topDownArray.map(child => child.constructor.name + this.wordBreakSymbol + child.indentation + child.lineCellTypes).join("\n")
    - toPreludeCellTypeTreeWithNodeConstructorNames() {
    - return this.getTopDownArray()
    - .map(child => child.constructor.name + this.getWordBreakSymbol() + child.getIndentation() + child.getLineCellPreludeTypes())
    - .join("\n")
    + toPreludeCellTypeTreeWithParserIds() {
    + return this.topDownArray.map(child => child.constructor.name + this.wordBreakSymbol + child.indentation + child.getLineCellPreludeTypes()).join("\n")
    - getTreeWithNodeTypes() {
    - return this.getTopDownArray()
    - .map(child => child.constructor.name + this.getWordBreakSymbol() + child.getIndentation() + child.getLine())
    - .join("\n")
    + get asTreeWithParsers() {
    + return this.topDownArray.map(child => child.constructor.name + this.wordBreakSymbol + child.indentation + child.getLine()).join("\n")
    - const typeNode = this._cache_highlightScopeTree.getTopDownArray()[lineIndex - 1]
    + const typeNode = this._cache_highlightScopeTree.topDownArray[lineIndex - 1]
    Changed around line 14197: class GrammarBackedNode extends TreeNode {
    - createParser() {
    - return this.isRoot()
    - ? new TreeNode.Parser(BlobNode)
    - : new TreeNode.Parser(
    - this.getParent()
    - ._getParser()
    - ._getCatchAllNodeConstructor(this.getParent()),
    - {}
    - )
    + createParserCombinator() {
    + return this.isRoot() ? new TreeNode.ParserCombinator(BlobParser) : new TreeNode.ParserCombinator(this.parent._getParser()._getCatchAllParser(this.parent), {})
    - getNodeTypeId() {
    - return this.getDefinition().getNodeTypeIdFromDefinition()
    + get parserId() {
    + return this.definition.parserIdFromDefinition
    - getWordTypes() {
    - return this._getParsedCells().filter(cell => cell.getWord() !== undefined)
    + get wordTypes() {
    + return this.parsedCells.filter(cell => cell.getWord() !== undefined)
    - return this._getParsedCells()
    - .map(check => check.getErrorIfAny())
    - .filter(identity => identity)
    + return this.parsedCells.map(check => check.getErrorIfAny()).filter(identity => identity)
    - get singleNodeUsedTwiceErrors() {
    + get singleParserUsedTwiceErrors() {
    - const parent = this.getParent()
    - const hits = parent.getChildInstancesOfNodeTypeId(this.getDefinition().id)
    + const parent = this.parent
    + const hits = parent.getChildInstancesOfParserId(this.definition.id)
    - if (node === this) errors.push(new NodeTypeUsedMultipleTimesError(node))
    + if (node === this) errors.push(new ParserUsedMultipleTimesError(node))
    + get uniqueLineAppearsTwiceErrors() {
    + const errors = []
    + const parent = this.parent
    + const hits = parent.getChildInstancesOfParserId(this.definition.id)
    + if (hits.length > 1) {
    + const set = new Set()
    + hits.forEach((node, index) => {
    + const line = node.getLine()
    + if (set.has(line)) errors.push(new ParserUsedMultipleTimesError(node))
    + set.add(line)
    + })
    + }
    + return errors
    + }
    - if (this.getDefinition().isSingle) errors = errors.concat(this.singleNodeUsedTwiceErrors)
    + const def = this.definition
    + if (def.isSingle) errors = errors.concat(this.singleParserUsedTwiceErrors)
    + if (def.isUniqueLine) errors = errors.concat(this.uniqueLineAppearsTwiceErrors)
    Changed around line 14245: class GrammarBackedNode extends TreeNode {
    - _getParsedCells() {
    - return this.getDefinition()
    - .getCellParser()
    - .getCellArray(this)
    + get parsedCells() {
    + return this.definition.cellParser.getCellArray(this)
    - getLineCellTypes() {
    - return this._getParsedCells()
    - .map(slot => slot.getCellTypeId())
    - .join(" ")
    + get lineCellTypes() {
    + return this.parsedCells.map(slot => slot.cellTypeId).join(" ")
    - return this._getParsedCells()
    + return this.parsedCells
    - const def = slot._getCellTypeDefinition()
    + const def = slot.cellTypeDefinition
    - return def ? def._getPreludeKindId() : PreludeCellTypeIds.anyCell
    + return def ? def.preludeKindId : PreludeCellTypeIds.anyCell
    - return this._getParsedCells()
    - .map(slot => slot.getHighlightScope() || defaultScope)
    - .join(" ")
    + return this.parsedCells.map(slot => slot.highlightScope || defaultScope).join(" ")
    - getCellDefinitionLineNumbers() {
    - return this._getParsedCells().map(cell => cell.getDefinitionLineNumber())
    + get cellDefinitionLineNumbers() {
    + return this.parsedCells.map(cell => cell.definitionLineNumber)
    - const indentCharacter = this.getDefinition()._getCompilerObject()[GrammarConstantsCompiler.indentCharacter]
    - const indent = this.getIndentation()
    + const indentCharacter = this.definition._getCompilerObject()[GrammarConstantsCompiler.indentCharacter]
    + const indent = this.indentation
    - const def = node.getDefinition()
    - if (def.isRequired() || def.isSingle) fields[node.getWord(0)] = node.getContent()
    + const def = node.definition
    + if (def.isRequired() || def.isSingle) fields[node.getWord(0)] = node.content
    - const compiler = this.getDefinition()._getCompilerObject()
    + const compiler = this.definition._getCompilerObject()
    - return str !== undefined ? TreeUtils.formatStr(str, catchAllCellDelimiter, Object.assign(this._getFields(), this.cells)) : this.getLine()
    + return str !== undefined ? Utils.formatStr(str, catchAllCellDelimiter, Object.assign(this._getFields(), this.cells)) : this.getLine()
    + }
    + get listDelimiter() {
    + return this.definition._getFromExtended(GrammarConstants.listDelimiter)
    + }
    + get contentKey() {
    + return this.definition._getFromExtended(GrammarConstants.contentKey)
    + }
    + get childrenKey() {
    + return this.definition._getFromExtended(GrammarConstants.childrenKey)
    + }
    + get childrenAreTextBlob() {
    + return this.definition._isBlobParser()
    + }
    + get isArrayElement() {
    + return this.definition._hasFromExtended(GrammarConstants.uniqueFirstWord) ? false : !this.definition.isSingle
    + }
    + get list() {
    + return this.listDelimiter ? this.content.split(this.listDelimiter) : super.list
    + }
    + get typedContent() {
    + // todo: probably a better way to do this, perhaps by defining a cellDelimiter at the node level
    + // todo: this currently parse anything other than string types
    + if (this.listDelimiter) return this.content.split(this.listDelimiter)
    + const cells = this.parsedCells
    + if (cells.length === 2) return cells[1].parsed
    + return this.content
    + }
    + get typedTuple() {
    + const key = this.firstWord
    + if (this.childrenAreTextBlob) return [key, this.childrenToString()]
    + const { typedContent, contentKey, childrenKey } = this
    + if (contentKey || childrenKey) {
    + let obj = {}
    + if (childrenKey) obj[childrenKey] = this.childrenToString()
    + else obj = this.typedMap
    + if (contentKey) {
    + obj[contentKey] = typedContent
    + }
    + return [key, obj]
    + }
    + const hasChildren = this.length > 0
    + const hasChildrenNoContent = typedContent === undefined && hasChildren
    + const shouldReturnValueAsObject = hasChildrenNoContent
    + if (shouldReturnValueAsObject) return [key, this.typedMap]
    + const hasChildrenAndContent = typedContent !== undefined && hasChildren
    + const shouldReturnValueAsContentPlusChildren = hasChildrenAndContent
    + // If the node has a content and a subtree return it as a string, as
    + // Javascript object values can't be both a leaf and a tree.
    + if (shouldReturnValueAsContentPlusChildren) return [key, this.contentWithChildren]
    + return [key, typedContent]
    + }
    + get _shouldSerialize() {
    + const should = this.shouldSerialize
    + return should === undefined ? true : should
    + get typedMap() {
    + const obj = {}
    + this.forEach(node => {
    + if (!node._shouldSerialize) return true
    + const tuple = node.typedTuple
    + if (!node.isArrayElement) obj[tuple[0]] = tuple[1]
    + else {
    + if (!obj[tuple[0]]) obj[tuple[0]] = []
    + obj[tuple[0]].push(tuple[1])
    + }
    + })
    + return obj
    + }
    + fromTypedMap() {}
    - const def = this.getDefinition()
    + const def = this.definition
    - if (def.isTerminalNodeType()) return indent + compiledLine
    + if (def.isTerminalParser()) return indent + compiledLine
    Changed around line 14373: ${indent}${closeChildrenString}`
    - this._getParsedCells().forEach(cell => {
    - const cellTypeId = cell.getCellTypeId()
    - if (!cell.isCatchAll()) cells[cellTypeId] = cell.getParsed()
    + this.parsedCells.forEach(cell => {
    + const cellTypeId = cell.cellTypeId
    + if (!cell.isCatchAll()) cells[cellTypeId] = cell.parsed
    - cells[cellTypeId].push(cell.getParsed())
    + cells[cellTypeId].push(cell.parsed)
    - class BlobNode extends GrammarBackedNode {
    - createParser() {
    - return new TreeNode.Parser(BlobNode, {})
    + class BlobParser extends GrammarBackedNode {
    + createParserCombinator() {
    + return new TreeNode.ParserCombinator(BlobParser, {})
    - class UnknownNodeTypeNode extends GrammarBackedNode {
    - createParser() {
    - return new TreeNode.Parser(UnknownNodeTypeNode, {})
    + class UnknownParserNode extends GrammarBackedNode {
    + createParserCombinator() {
    + return new TreeNode.ParserCombinator(UnknownParserNode, {})
    - return [new UnknownNodeTypeError(this)]
    + return [new UnknownParserError(this)]
    - constructor(node, index, typeDef, cellTypeId, isCatchAll, nodeTypeDef) {
    + constructor(node, index, typeDef, cellTypeId, isCatchAll, parserDefinitionParser) {
    - this._nodeTypeDefinition = nodeTypeDef
    + this._parserDefinitionParser = parserDefinitionParser
    - getDefinitionLineNumber() {
    - return this._typeDef.getLineNumber()
    - }
    - getSQLiteType() {
    - return SQLiteTypes.text
    + get definitionLineNumber() {
    + return this._typeDef.lineNumber
    - getCellTypeId() {
    + get cellTypeId() {
    - getCellIndex() {
    + get cellIndex() {
    - return this._getCellTypeDefinition().get(GrammarConstants.min) || "0"
    + return this.cellTypeDefinition.get(GrammarConstants.min) || "0"
    - return this._getCellTypeDefinition().get(GrammarConstants.max) || "100"
    + return this.cellTypeDefinition.get(GrammarConstants.max) || "100"
    - return this._getCellTypeDefinition().get(GrammarConstants.examples) || ""
    + return this.cellTypeDefinition.get(GrammarConstants.examples) || ""
    - getHighlightScope() {
    - const definition = this._getCellTypeDefinition()
    - if (definition) return definition.getHighlightScope() // todo: why the undefined?
    + get highlightScope() {
    + const definition = this.cellTypeDefinition
    + if (definition) return definition.highlightScope // todo: why the undefined?
    - const cellDef = this._getCellTypeDefinition()
    - let words = cellDef ? cellDef._getAutocompleteWordOptions(this.getNode().getRootNode()) : []
    + const cellDef = this.cellTypeDefinition
    + let words = cellDef ? cellDef._getAutocompleteWordOptions(this.getNode().root) : []
    Changed around line 14459: class AbstractGrammarBackedCell {
    - const cellDef = this._getCellTypeDefinition()
    + const cellDef = this.cellTypeDefinition
    - if (enumOptions) return TreeUtils.getRandomString(1, enumOptions.split(" "))
    + if (enumOptions) return Utils.getRandomString(1, enumOptions.split(" "))
    - const cellDef = this._getCellTypeDefinition()
    + const cellDef = this.cellTypeDefinition
    Changed around line 14487: ${options.toString(1)}`
    - _getCellTypeDefinition() {
    + get cellTypeDefinition() {
    - _getFullLine() {
    - return this.getNode().getLine()
    - }
    - return this._getFullLine().split(" ")[0] // todo: WordBreakSymbol
    + return this.getNode().getLine().split(" ")[0] // todo: WordBreakSymbol
    - return this._getCellTypeDefinition().isValid(word, this.getNode().getRootNode()) && this._isValid()
    + return this.cellTypeDefinition.isValid(word, this.getNode().root) && this._isValid()
    Changed around line 14513: class GrammarBitCell extends AbstractGrammarBackedCell {
    - return TreeUtils.getRandomString(1, "01".split(""))
    + return Utils.getRandomString(1, "01".split(""))
    - getRegexString() {
    + get regexString() {
    - getParsed() {
    + get parsed() {
    Changed around line 14542: class GrammarIntCell extends GrammarNumericCell {
    - return TreeUtils.randomUniformInt(parseInt(this.min), parseInt(this.max), seed).toString()
    + return Utils.randomUniformInt(parseInt(this.min), parseInt(this.max), seed).toString()
    - getRegexString() {
    + get regexString() {
    - getSQLiteType() {
    - return SQLiteTypes.integer
    - }
    - getParsed() {
    + get parsed() {
    Changed around line 14560: class GrammarFloatCell extends GrammarNumericCell {
    - getSQLiteType() {
    - return SQLiteTypes.float
    - }
    - return TreeUtils.randomUniformFloat(parseFloat(this.min), parseFloat(this.max), seed).toString()
    + return Utils.randomUniformFloat(parseFloat(this.min), parseFloat(this.max), seed).toString()
    - getRegexString() {
    + get regexString() {
    - getParsed() {
    + get parsed() {
    Changed around line 14586: class GrammarBoolCell extends AbstractGrammarBackedCell {
    - return TreeUtils.getRandomString(1, ["1", "true", "t", "yes", "0", "false", "f", "no"])
    + return Utils.getRandomString(1, ["1", "true", "t", "yes", "0", "false", "f", "no"])
    - getRegexString() {
    + get regexString() {
    - getParsed() {
    + get parsed() {
    Changed around line 14605: class GrammarAnyCell extends AbstractGrammarBackedCell {
    - const examples = this._getCellTypeDefinition()._getFromExtended(GrammarConstants.examples)
    - if (examples) return TreeUtils.getRandomString(1, examples.split(" "))
    - return this._nodeTypeDefinition.getNodeTypeIdFromDefinition() + "-" + this.constructor.name
    + const examples = this.cellTypeDefinition._getFromExtended(GrammarConstants.examples)
    + if (examples) return Utils.getRandomString(1, examples.split(" "))
    + return this._parserDefinitionParser.parserIdFromDefinition + "-" + this.constructor.name
    - getRegexString() {
    + get regexString() {
    - getParsed() {
    + get parsed() {
    - return this._nodeTypeDefinition._getCruxIfAny()
    + return this._parserDefinitionParser.cruxIfAny
    Changed around line 14633: class GrammarExtraWordCellTypeCell extends AbstractGrammarBackedCell {
    - getParsed() {
    + get parsed() {
    Changed around line 14651: class GrammarUnknownCellTypeCell extends AbstractGrammarBackedCell {
    - getParsed() {
    + get parsed() {
    Changed around line 14663: class AbstractTreeError {
    - return this.getLineNumber() - 1
    + return this.lineNumber - 1
    - getLineNumber() {
    + get lineNumber() {
    - return this.getCellIndex() === this.getNode().getWordIndexAtCharacterIndex(characterIndex)
    + return this.cellIndex === this.getNode().getWordIndexAtCharacterIndex(characterIndex)
    Changed around line 14683: class AbstractTreeError {
    - return this.getNode().getIndentation()
    + return this.getNode().indentation
    - const suggestion = this.getSuggestionMessage()
    + const suggestion = this.suggestionMessage
    - getNodeTypeId() {
    - return this.getNode()
    - .getDefinition()
    - .getNodeTypeIdFromDefinition()
    + get parserId() {
    + return this.getNode().definition.parserIdFromDefinition
    - el.appendChild(
    - document.createTextNode(
    - this.getIndent() +
    - this.getNode()
    - .getDefinition()
    - .getLineHints()
    - )
    - )
    + el.appendChild(document.createTextNode(this.getIndent() + this.getNode().definition.lineHints))
    - el.appendChild(document.createTextNode(this.getIndent() + this.getMessage()))
    + el.appendChild(document.createTextNode(this.getIndent() + this.message))
    - el.appendChild(document.createTextNode(this.getIndent() + `${this.getErrorTypeName()}. Suggestion: ${suggestion}`))
    + el.appendChild(document.createTextNode(this.getIndent() + `${this.errorTypeName}. Suggestion: ${suggestion}`))
    Changed around line 14720: class AbstractTreeError {
    - return this.getNode()
    - .getHandGrammarProgram()
    - .getExtensionName()
    + return this.getNode().handGrammarProgram.extensionName
    - getErrorTypeName() {
    + get errorTypeName() {
    - getCellIndex() {
    + get cellIndex() {
    - type: this.getErrorTypeName(),
    - line: this.getLineNumber(),
    - cell: this.getCellIndex(),
    - suggestion: this.getSuggestionMessage(),
    + type: this.errorTypeName,
    + line: this.lineNumber,
    + cell: this.cellIndex,
    + suggestion: this.suggestionMessage,
    - message: this.getMessage()
    + message: this.message
    - return this.getSuggestionMessage() !== ""
    + return this.suggestionMessage !== ""
    - getSuggestionMessage() {
    + get suggestionMessage() {
    - return this.getMessage()
    + return this.message
    - getMessage() {
    - return `${this.getErrorTypeName()} at line ${this.getLineNumber()} cell ${this.getCellIndex()}.`
    + get message() {
    + return `${this.errorTypeName} at line ${this.lineNumber} cell ${this.cellIndex}.`
    Changed around line 14760: class AbstractCellError extends AbstractTreeError {
    - getCell() {
    + get cell() {
    - getCellIndex() {
    - return this._cell.getCellIndex()
    + get cellIndex() {
    + return this._cell.cellIndex
    - _getWordSuggestion() {
    - return TreeUtils.didYouMean(
    - this.getCell().getWord(),
    - this.getCell()
    - .getAutoCompleteWords()
    - .map(option => option.text)
    + get wordSuggestion() {
    + return Utils.didYouMean(
    + this.cell.getWord(),
    + this.cell.getAutoCompleteWords().map(option => option.text)
    - class UnknownNodeTypeError extends AbstractTreeError {
    - getMessage() {
    + class UnknownParserError extends AbstractTreeError {
    + get message() {
    - const parentNode = node.getParent()
    + const parentNode = node.parent
    - return super.getMessage() + ` Invalid nodeType "${node.getFirstWord()}". Valid nodeTypes are: ${TreeUtils._listToEnglishText(options, 7)}.`
    + return super.message + ` Invalid parser "${node.firstWord}". Valid parsers are: ${Utils._listToEnglishText(options, 7)}.`
    - _getWordSuggestion() {
    + get wordSuggestion() {
    - const parentNode = node.getParent()
    - return TreeUtils.didYouMean(node.getFirstWord(), parentNode.getAutocompleteResults("", 0).map(option => option.text))
    + const parentNode = node.parent
    + return Utils.didYouMean(
    + node.firstWord,
    + parentNode.getAutocompleteResults("", 0).map(option => option.text)
    + )
    - getSuggestionMessage() {
    - const suggestion = this._getWordSuggestion()
    + get suggestionMessage() {
    + const suggestion = this.wordSuggestion
    - if (suggestion) return `Change "${node.getFirstWord()}" to "${suggestion}"`
    + if (suggestion) return `Change "${node.firstWord}" to "${suggestion}"`
    - const suggestion = this._getWordSuggestion()
    - if (suggestion) this.getNode().setWord(this.getCellIndex(), suggestion)
    + const suggestion = this.wordSuggestion
    + if (suggestion) this.getNode().setWord(this.cellIndex, suggestion)
    - class BlankLineError extends UnknownNodeTypeError {
    - getMessage() {
    - return super.getMessage() + ` Line: "${this.getNode().getLine()}". Blank lines are errors.`
    + class BlankLineError extends UnknownParserError {
    + get message() {
    + return super.message + ` Line: "${this.getNode().getLine()}". Blank lines are errors.`
    - getSuggestionMessage() {
    - return `Delete line ${this.getLineNumber()}`
    + get suggestionMessage() {
    + return `Delete line ${this.lineNumber}`
    - class MissingRequiredNodeTypeError extends AbstractTreeError {
    - constructor(node, missingNodeTypeId) {
    + class MissingRequiredParserError extends AbstractTreeError {
    + constructor(node, missingParserId) {
    - this._missingNodeTypeId = missingNodeTypeId
    + this._missingParserId = missingParserId
    + }
    + get message() {
    + return super.message + ` A "${this._missingParserId}" is required.`
    - getMessage() {
    - return super.getMessage() + ` A "${this._missingNodeTypeId}" is required.`
    + }
    + class ParserUsedMultipleTimesError extends AbstractTreeError {
    + get message() {
    + return super.message + ` Multiple "${this.getNode().firstWord}" found.`
    + }
    + get suggestionMessage() {
    + return `Delete line ${this.lineNumber}`
    + }
    + applySuggestion() {
    + return this.getNode().destroy()
    - class NodeTypeUsedMultipleTimesError extends AbstractTreeError {
    - getMessage() {
    - return super.getMessage() + ` Multiple "${this.getNode().getFirstWord()}" found.`
    + class LineAppearsMultipleTimesError extends AbstractTreeError {
    + get message() {
    + return super.message + ` "${this.getNode().getLine()}" appears multiple times.`
    - getSuggestionMessage() {
    - return `Delete line ${this.getLineNumber()}`
    + get suggestionMessage() {
    + return `Delete line ${this.lineNumber}`
    - getMessage() {
    - return super.getMessage() + ` No cellType "${this.getCell().getCellTypeId()}" found. Language grammar for "${this.getExtension()}" may need to be fixed.`
    + get message() {
    + return super.message + ` No cellType "${this.cell.cellTypeId}" found. Language grammar for "${this.getExtension()}" may need to be fixed.`
    - getMessage() {
    - return super.getMessage() + ` "${this.getCell().getWord()}" does not fit in cellType "${this.getCell().getCellTypeId()}".`
    + get message() {
    + return super.message + ` "${this.cell.getWord()}" does not fit in cellType "${this.cell.cellTypeId}".`
    - getSuggestionMessage() {
    - const suggestion = this._getWordSuggestion()
    - if (suggestion) return `Change "${this.getCell().getWord()}" to "${suggestion}"`
    + get suggestionMessage() {
    + const suggestion = this.wordSuggestion
    + if (suggestion) return `Change "${this.cell.getWord()}" to "${suggestion}"`
    - const suggestion = this._getWordSuggestion()
    - if (suggestion) this.getNode().setWord(this.getCellIndex(), suggestion)
    + const suggestion = this.wordSuggestion
    + if (suggestion) this.getNode().setWord(this.cellIndex, suggestion)
    - getMessage() {
    - return super.getMessage() + ` Extra word "${this.getCell().getWord()}" in ${this.getNodeTypeId()}.`
    + get message() {
    + return super.message + ` Extra word "${this.cell.getWord()}" in ${this.parserId}.`
    - getSuggestionMessage() {
    - return `Delete word "${this.getCell().getWord()}" at cell ${this.getCellIndex()}`
    + get suggestionMessage() {
    + return `Delete word "${this.cell.getWord()}" at cell ${this.cellIndex}`
    - return this.getNode().deleteWordAt(this.getCellIndex())
    + return this.getNode().deleteWordAt(this.cellIndex)
    - getMessage() {
    - return super.getMessage() + ` Missing word for cell "${this.getCell().getCellTypeId()}".`
    + get message() {
    + return super.message + ` Missing word for cell "${this.cell.cellTypeId}".`
    - class AbstractGrammarWordTestNode extends TreeNode {}
    - class GrammarRegexTestNode extends AbstractGrammarWordTestNode {
    + class AbstractGrammarWordTestParser extends TreeNode {}
    + class GrammarRegexTestParser extends AbstractGrammarWordTestParser {
    - if (!this._regex) this._regex = new RegExp("^" + this.getContent() + "$")
    + if (!this._regex) this._regex = new RegExp("^" + this.content + "$")
    - class GrammarReservedWordsTestNode extends AbstractGrammarWordTestNode {
    + class GrammarReservedWordsTestParser extends AbstractGrammarWordTestParser {
    - if (!this._set) this._set = new Set(this.getContent().split(" "))
    + if (!this._set) this._set = new Set(this.content.split(" "))
    - class EnumFromCellTypesTestNode extends AbstractGrammarWordTestNode {
    + class EnumFromCellTypesTestParser extends AbstractGrammarWordTestParser {
    Changed around line 14913: class EnumFromCellTypesTestNode extends AbstractGrammarWordTestNode {
    - programRootNode
    - .getAllTypedWords()
    + programRootNode.allTypedWords
    Changed around line 14926: class EnumFromCellTypesTestNode extends AbstractGrammarWordTestNode {
    - class GrammarEnumTestNode extends AbstractGrammarWordTestNode {
    + class GrammarEnumTestNode extends AbstractGrammarWordTestParser {
    - if (!this._map) this._map = TreeUtils.arrayToMap(this.getWordsFrom(1))
    + if (!this._map) this._map = Utils.arrayToMap(this.getWordsFrom(1))
    - class cellTypeDefinitionNode extends AbstractExtendibleTreeNode {
    - createParser() {
    + class cellTypeDefinitionParser extends AbstractExtendibleTreeNode {
    + createParserCombinator() {
    - types[GrammarConstants.regex] = GrammarRegexTestNode
    - types[GrammarConstants.reservedWords] = GrammarReservedWordsTestNode
    - types[GrammarConstants.enumFromCellTypes] = EnumFromCellTypesTestNode
    + types[GrammarConstants.regex] = GrammarRegexTestParser
    + types[GrammarConstants.reservedWords] = GrammarReservedWordsTestParser
    + types[GrammarConstants.enumFromCellTypes] = EnumFromCellTypesTestParser
    - types[GrammarConstants.todoComment] = TreeNode
    + types[GrammarConstants.comment] = TreeNode
    - return new TreeNode.Parser(undefined, types)
    + return new TreeNode.ParserCombinator(undefined, types)
    - _getId() {
    + get id() {
    - _getIdToNodeMap() {
    - return this.getParent().getCellTypeDefinitions()
    + get idToNodeMap() {
    + return this.parent.cellTypeDefinitions
    - return `get ${this.getCellTypeId()}() {
    + return `get ${this.cellTypeId}() {
    - return `get ${this.getCellTypeId()}() {
    + return `get ${this.cellTypeId}() {
    - return this._getPreludeKind() || GrammarAnyCell
    + return this.preludeKind || GrammarAnyCell
    - _getPreludeKind() {
    + get preludeKind() {
    - _getPreludeKindId() {
    + get preludeKindId() {
    - return arr[arr.length - 1]._getId()
    + return arr[arr.length - 1].id
    - getHighlightScope() {
    + get highlightScope() {
    - const preludeKind = this._getPreludeKind()
    + const preludeKind = this.preludeKind
    Changed around line 15008: class cellTypeDefinitionNode extends AbstractExtendibleTreeNode {
    - getRegexString() {
    + get regexString() {
    + _getAllTests() {
    + return this._getChildrenByParserInExtended(AbstractGrammarWordTestParser)
    + }
    - return this._getChildrenByNodeConstructorInExtended(AbstractGrammarWordTestNode).every(node => node.isValid(str, programRootNode))
    + return this._getAllTests().every(node => node.isValid(str, programRootNode))
    - getCellTypeId() {
    + get cellTypeId() {
    Changed around line 15027: class AbstractCellParser {
    - getCatchAllCellTypeId() {
    + get catchAllCellTypeId() {
    - getLineHints() {
    - const catchAllCellTypeId = this.getCatchAllCellTypeId()
    - const nodeTypeId = this._definition._getCruxIfAny() || this._definition._getId() // todo: cleanup
    - return `${nodeTypeId}: ${this.getRequiredCellTypeIds().join(" ")}${catchAllCellTypeId ? ` ${catchAllCellTypeId}...` : ""}`
    + get lineHints() {
    + const catchAllCellTypeId = this.catchAllCellTypeId
    + const parserId = this._definition.cruxIfAny || this._definition.id // todo: cleanup
    + return `${parserId}: ${this.getRequiredCellTypeIds().join(" ")}${catchAllCellTypeId ? ` ${catchAllCellTypeId}...` : ""}`
    - const parameters = this._definition._getFromExtended(GrammarConstants.cells)
    - return parameters ? parameters.split(" ") : []
    + if (!this._requiredCellTypeIds) {
    + const parameters = this._definition._getFromExtended(GrammarConstants.cells)
    + this._requiredCellTypeIds = parameters ? parameters.split(" ") : []
    + }
    + return this._requiredCellTypeIds
    Changed around line 15050: class AbstractCellParser {
    - const wordCount = node ? node.getWords().length : 0
    + const wordCount = node ? node.words.length : 0
    - const grammarProgram = def.getLanguageDefinitionProgram()
    + const grammarProgram = def.languageDefinitionProgram
    Changed around line 15060: class AbstractCellParser {
    - let cellTypeId = isCatchAll ? this.getCatchAllCellTypeId() : this._getCellTypeId(cellIndex, requiredCellTypeIds, wordCount)
    + let cellTypeId = isCatchAll ? this.catchAllCellTypeId : this._getCellTypeId(cellIndex, requiredCellTypeIds, wordCount)
    Changed around line 15070: class AbstractCellParser {
    - cells[cellIndex] = new cellConstructor(node, cellIndex, cellTypeDefinition, cellTypeId, isCatchAll, def)
    + const anyCellConstructor = cellConstructor
    + cells[cellIndex] = new anyCellConstructor(node, cellIndex, cellTypeDefinition, cellTypeId, isCatchAll, def)
    Changed around line 15090: class OmnifixCellParser extends AbstractCellParser {
    - const program = node ? node.getRootNode() : undefined
    - const grammarProgram = def.getLanguageDefinitionProgram()
    - const words = node ? node.getWords() : []
    + const program = node ? node.root : undefined
    + const grammarProgram = def.languageDefinitionProgram
    + const words = node ? node.words : []
    - const catchAllCellTypeId = this.getCatchAllCellTypeId()
    + const catchAllCellTypeId = this.catchAllCellTypeId
    Changed around line 15103: class OmnifixCellParser extends AbstractCellParser {
    - cells.push(new cellConstructor(node, wordIndex, cellTypeDefinition, cellTypeDefinition._getId(), false, def))
    + cells.push(new cellConstructor(node, wordIndex, cellTypeDefinition, cellTypeDefinition.id, false, def))
    Changed around line 15118: class OmnifixCellParser extends AbstractCellParser {
    - cells.push(new cellConstructor(node, wordCount + index, cellTypeDef, cellTypeDef._getId(), false, def))
    + cells.push(new cellConstructor(node, wordCount + index, cellTypeDef, cellTypeDef.id, false, def))
    - class GrammarExampleNode extends TreeNode {}
    - class GrammarCompilerNode extends TreeNode {
    - createParser() {
    + class GrammarExampleParser extends TreeNode {}
    + class GrammarCompilerParser extends TreeNode {
    + createParserCombinator() {
    Changed around line 15138: class GrammarCompilerNode extends TreeNode {
    - return new TreeNode.Parser(undefined, map)
    + return new TreeNode.ParserCombinator(undefined, map)
    - class GrammarNodeTypeConstant extends TreeNode {
    + class AbstractParserConstantParser extends TreeNode {
    + constructor(children, line, parent) {
    + super(children, line, parent)
    + parent[this.identifier] = this.constantValue
    + }
    - return `get ${this.getIdentifier()}() { return ${this.getConstantValueAsJsText()} }`
    + return `get ${this.identifier}() { return ${this.constantValueAsJsText} }`
    - getIdentifier() {
    + get identifier() {
    - getConstantValueAsJsText() {
    + get constantValueAsJsText() {
    - getConstantValue() {
    - return JSON.parse(this.getConstantValueAsJsText())
    + get constantValue() {
    + return JSON.parse(this.constantValueAsJsText)
    - class GrammarNodeTypeConstantInt extends GrammarNodeTypeConstant {}
    - class GrammarNodeTypeConstantString extends GrammarNodeTypeConstant {
    - getConstantValueAsJsText() {
    - return "`" + TreeUtils.escapeBackTicks(this.getConstantValue()) + "`"
    + class GrammarParserConstantInt extends AbstractParserConstantParser {}
    + class GrammarParserConstantString extends AbstractParserConstantParser {
    + get constantValueAsJsText() {
    + return "`" + Utils.escapeBackTicks(this.constantValue) + "`"
    - getConstantValue() {
    + get constantValue() {
    - class GrammarNodeTypeConstantFloat extends GrammarNodeTypeConstant {}
    - class GrammarNodeTypeConstantBoolean extends GrammarNodeTypeConstant {}
    - class AbstractGrammarDefinitionNode extends AbstractExtendibleTreeNode {
    - createParser() {
    + class GrammarParserConstantFloat extends AbstractParserConstantParser {}
    + class GrammarParserConstantBoolean extends AbstractParserConstantParser {}
    + class AbstractParserDefinitionParser extends AbstractExtendibleTreeNode {
    + createParserCombinator() {
    Changed around line 15180: class AbstractGrammarDefinitionNode extends AbstractExtendibleTreeNode {
    - GrammarConstants.catchAllNodeType,
    + GrammarConstants.catchAllParser,
    + GrammarConstants.sortTemplate,
    + GrammarConstants.listDelimiter,
    + GrammarConstants.contentKey,
    + GrammarConstants.childrenKey,
    + GrammarConstants.uniqueFirstWord,
    + GrammarConstants.uniqueLine,
    - GrammarConstants.baseNodeType,
    + GrammarConstants.baseParser,
    - GrammarConstants.abstract,
    - GrammarConstants.todoComment
    + GrammarConstants.comment
    - map[GrammarConstantsConstantTypes.boolean] = GrammarNodeTypeConstantBoolean
    - map[GrammarConstantsConstantTypes.int] = GrammarNodeTypeConstantInt
    - map[GrammarConstantsConstantTypes.string] = GrammarNodeTypeConstantString
    - map[GrammarConstantsConstantTypes.float] = GrammarNodeTypeConstantFloat
    - map[GrammarConstants.compilerNodeType] = GrammarCompilerNode
    - map[GrammarConstants.example] = GrammarExampleNode
    - return new TreeNode.Parser(undefined, map)
    + map[GrammarConstantsConstantTypes.boolean] = GrammarParserConstantBoolean
    + map[GrammarConstantsConstantTypes.int] = GrammarParserConstantInt
    + map[GrammarConstantsConstantTypes.string] = GrammarParserConstantString
    + map[GrammarConstantsConstantTypes.float] = GrammarParserConstantFloat
    + map[GrammarConstants.compilerParser] = GrammarCompilerParser
    + map[GrammarConstants.example] = GrammarExampleParser
    + return new TreeNode.ParserCombinator(undefined, map, [{ regex: HandGrammarProgram.parserFullRegex, parser: parserDefinitionParser }])
    + }
    + get sortSpec() {
    + const sortSections = new Map()
    + const sortIndices = new Map()
    + const sortTemplate = this.get(GrammarConstants.sortTemplate)
    + if (!sortTemplate) return { sortSections, sortIndices }
    + sortTemplate.split(" ").forEach((section, sectionIndex) => section.split(" ").forEach(word => sortSections.set(word, sectionIndex)))
    + sortTemplate.split(" ").forEach((word, index) => sortIndices.set(word, index))
    + return { sortSections, sortIndices }
    - const inScope = this.getFirstWordMapWithDefinitions()
    - const thisId = this._getId()
    + const inScope = this.firstWordMapWithDefinitions
    + const thisId = this.id
    - const map = def.getFirstWordMapWithDefinitions()
    - const id = def._getId()
    + const map = def.firstWordMapWithDefinitions
    + const id = def.id
    - const description = def.getDescription()
    + const description = def.description
    - const description = this.getDescription()
    + const description = this.description
    Changed around line 15254: interface ${thisId} {
    - getTableNameIfAny() {
    - return this.getFrom(`${GrammarConstantsConstantTypes.string} ${GrammarConstantsMisc.tableName}`)
    - }
    - getSQLiteTableColumns() {
    - return this._getConcreteNonErrorInScopeNodeDefinitions(this._getInScopeNodeTypeIds()).map(node => {
    - const firstNonKeywordCellType = node.getCellParser().getCellArray()[1]
    - const type = firstNonKeywordCellType ? firstNonKeywordCellType.getSQLiteType() : SQLiteTypes.text
    - return {
    - columnName: node._getIdWithoutSuffix(),
    - type
    - }
    - })
    - }
    - toSQLiteTableSchema() {
    - const columns = this.getSQLiteTableColumns().map(columnDef => `${columnDef.columnName} ${columnDef.type}`)
    - return `create table ${this.getTableNameIfAny() || this._getId()} (
    - id TEXT NOT NULL PRIMARY KEY,
    - ${columns.join(",\n ")}
    - );`
    - }
    - _getId() {
    - return this.getWord(0)
    - }
    - return this._getId()
    + return this.getWord(0)
    - _getIdWithoutSuffix() {
    - return this._getId().replace(HandGrammarProgram.nodeTypeSuffixRegex, "")
    + get idWithoutSuffix() {
    + return this.id.replace(HandGrammarProgram.parserSuffixRegex, "")
    - getConstantsObject() {
    + get constantsObject() {
    - Object.keys(obj).forEach(key => {
    - obj[key] = obj[key].getConstantValue()
    - })
    + Object.keys(obj).forEach(key => (obj[key] = obj[key].constantValue))
    - const items = extended ? this._getChildrenByNodeConstructorInExtended(GrammarNodeTypeConstant) : this.getChildrenByNodeConstructor(GrammarNodeTypeConstant)
    + const items = extended ? this._getChildrenByParserInExtended(AbstractParserConstantParser) : this.getChildrenByParser(AbstractParserConstantParser)
    - items.forEach(node => {
    - obj[node.getIdentifier()] = node
    - })
    + items.forEach(node => (obj[node.identifier] = node))
    - getExamples() {
    - return this._getChildrenByNodeConstructorInExtended(GrammarExampleNode)
    + get examples() {
    + return this._getChildrenByParserInExtended(GrammarExampleParser)
    - getNodeTypeIdFromDefinition() {
    + get parserIdFromDefinition() {
    - // todo: remove? just reused nodeTypeId
    - _getGeneratedClassName() {
    - return this.getNodeTypeIdFromDefinition()
    + // todo: remove? just reused parserId
    + get generatedClassName() {
    + return this.parserIdFromDefinition
    - _hasValidNodeTypeId() {
    - return !!this._getGeneratedClassName()
    + _hasValidParserId() {
    + return !!this.generatedClassName
    - return this.has(GrammarConstants.abstract)
    - }
    - _getConcreteDescendantDefinitions() {
    - const defs = this._getProgramNodeTypeDefinitionCache()
    - const id = this._getId()
    - return Object.values(defs).filter(def => {
    - return def._doesExtend(id) && !def._isAbstract()
    - })
    + return this.id.startsWith(GrammarConstants.abstractParserPrefix)
    - _getCruxIfAny() {
    - return this.get(GrammarConstants.crux) || (this._hasFromExtended(GrammarConstants.cruxFromId) ? this._getIdWithoutSuffix() : undefined)
    + get cruxIfAny() {
    + return this.get(GrammarConstants.crux) || (this._hasFromExtended(GrammarConstants.cruxFromId) ? this.idWithoutSuffix : undefined)
    - _getRegexMatch() {
    + get regexMatch() {
    - _getFirstCellEnumOptions() {
    + get firstCellEnumOptions() {
    - getLanguageDefinitionProgram() {
    - return this.getParent()
    + get languageDefinitionProgram() {
    + return this.root
    - _getCustomJavascriptMethods() {
    + get customJavascriptMethods() {
    - getFirstWordMapWithDefinitions() {
    - if (!this._cache_firstWordToNodeDefMap) this._cache_firstWordToNodeDefMap = this._createParserInfo(this._getInScopeNodeTypeIds()).firstWordMap
    + get firstWordMapWithDefinitions() {
    + if (!this._cache_firstWordToNodeDefMap) this._cache_firstWordToNodeDefMap = this._createParserInfo(this._getInScopeParserIds()).firstWordMap
    - getRunTimeFirstWordsInScope() {
    + get runTimeFirstWordsInScope() {
    - const grammarProgram = this.getLanguageDefinitionProgram()
    + const grammarProgram = this.languageDefinitionProgram
    Changed around line 15324: ${properties.join("\n")}
    - _getCellGettersAndNodeTypeConstants() {
    + get cellGettersAndParserConstants() {
    - const grammarProgram = this.getLanguageDefinitionProgram()
    + const grammarProgram = this.languageDefinitionProgram
    - Object.values(this._getUniqueConstantNodes(false)).forEach(node => {
    - getters.push(node.getGetter())
    - })
    + Object.values(this._getUniqueConstantNodes(false)).forEach(node => getters.push(node.getGetter()))
    - _createParserInfo(nodeTypeIdsInScope) {
    + _createParserInfo(parserIdsInScope) {
    - if (!nodeTypeIdsInScope.length) return result
    - const allProgramNodeTypeDefinitionsMap = this._getProgramNodeTypeDefinitionCache()
    - Object.keys(allProgramNodeTypeDefinitionsMap)
    - .filter(nodeTypeId => allProgramNodeTypeDefinitionsMap[nodeTypeId].isOrExtendsANodeTypeInScope(nodeTypeIdsInScope))
    - .filter(nodeTypeId => !allProgramNodeTypeDefinitionsMap[nodeTypeId]._isAbstract())
    - .forEach(nodeTypeId => {
    - const def = allProgramNodeTypeDefinitionsMap[nodeTypeId]
    - const regex = def._getRegexMatch()
    - const crux = def._getCruxIfAny()
    - const enumOptions = def._getFirstCellEnumOptions()
    - if (regex) result.regexTests.push({ regex: regex, nodeConstructor: def.getNodeTypeIdFromDefinition() })
    + if (!parserIdsInScope.length) return result
    + const allProgramParserDefinitionsMap = this.programParserDefinitionCache
    + Object.keys(allProgramParserDefinitionsMap)
    + .filter(parserId => {
    + const def = allProgramParserDefinitionsMap[parserId]
    + return def.isOrExtendsAParserInScope(parserIdsInScope) && !def._isAbstract()
    + })
    + .forEach(parserId => {
    + const def = allProgramParserDefinitionsMap[parserId]
    + const regex = def.regexMatch
    + const crux = def.cruxIfAny
    + const enumOptions = def.firstCellEnumOptions
    + if (regex) result.regexTests.push({ regex: regex, parser: def.parserIdFromDefinition })
    - enumOptions.forEach(option => {
    - result.firstWordMap[option] = def
    - })
    + enumOptions.forEach(option => (result.firstWordMap[option] = def))
    - getTopNodeTypeDefinitions() {
    - const arr = Object.values(this.getFirstWordMapWithDefinitions())
    - arr.sort(TreeUtils.makeSortByFn(definition => definition.getFrequency()))
    + get topParserDefinitions() {
    + const arr = Object.values(this.firstWordMapWithDefinitions)
    + arr.sort(Utils.makeSortByFn(definition => definition.frequency))
    - _getMyInScopeNodeTypeIds() {
    - const nodeTypesNode = this.getNode(GrammarConstants.inScope)
    - return nodeTypesNode ? nodeTypesNode.getWordsFrom(1) : []
    + _getMyInScopeParserIds(target = this) {
    + const parsersNode = target.getNode(GrammarConstants.inScope)
    + const scopedDefinitionIds = target.myScopedParserDefinitions.map(def => def.id)
    + return parsersNode ? parsersNode.getWordsFrom(1).concat(scopedDefinitionIds) : scopedDefinitionIds
    - _getInScopeNodeTypeIds() {
    + _getInScopeParserIds() {
    - const ids = this._getMyInScopeNodeTypeIds()
    + const ids = this._getMyInScopeParserIds()
    - return parentDef ? ids.concat(parentDef._getInScopeNodeTypeIds()) : ids
    + return parentDef ? ids.concat(parentDef._getInScopeParserIds()) : ids
    - // Should only one of these node types be present in the parent node?
    - return this._hasFromExtended(GrammarConstants.single)
    + const hit = this._getNodeFromExtended(GrammarConstants.single)
    + return hit && hit.get(GrammarConstants.single) !== "false"
    + }
    + get isUniqueLine() {
    + const hit = this._getNodeFromExtended(GrammarConstants.uniqueLine)
    + return hit && hit.get(GrammarConstants.uniqueLine) !== "false"
    - getNodeTypeDefinitionByNodeTypeId(nodeTypeId) {
    + getParserDefinitionByParserId(parserId) {
    - const def = this._getProgramNodeTypeDefinitionCache()[nodeTypeId]
    + const def = this.programParserDefinitionCache[parserId]
    - // todo: cleanup
    - this.getLanguageDefinitionProgram()._addDefaultCatchAllBlobNode()
    - return this._getProgramNodeTypeDefinitionCache()[nodeTypeId]
    + this.languageDefinitionProgram._addDefaultCatchAllBlobParser() // todo: cleanup. Why did I do this? Needs to be removed or documented.
    + const nodeDef = this.languageDefinitionProgram.programParserDefinitionCache[parserId]
    + if (!nodeDef) throw new Error(`No definition found for parser id "${parserId}". Node: \n---\n${this.asString}\n---`)
    + return nodeDef
    - isDefined(nodeTypeId) {
    - return !!this._getProgramNodeTypeDefinitionCache()[nodeTypeId]
    + isDefined(parserId) {
    + return !!this.programParserDefinitionCache[parserId]
    - _getIdToNodeMap() {
    - return this._getProgramNodeTypeDefinitionCache()
    + get idToNodeMap() {
    + return this.programParserDefinitionCache
    - if (this._cache_isRoot === undefined) this._cache_isRoot = this._getLanguageRootNode() === this
    + if (this._cache_isRoot === undefined) this._cache_isRoot = this._languageRootNode === this
    - _getLanguageRootNode() {
    - return this.getParent().getRootNodeTypeDefinitionNode()
    + get _languageRootNode() {
    + return this.root.rootParserDefinition
    - _isErrorNodeType() {
    - return this.get(GrammarConstants.baseNodeType) === GrammarConstants.errorNode
    + _isErrorParser() {
    + return this.get(GrammarConstants.baseParser) === GrammarConstants.errorParser
    - _isBlobNodeType() {
    + _isBlobParser() {
    - return this.get(GrammarConstants.baseNodeType) === GrammarConstants.blobNode
    + return this._getFromExtended(GrammarConstants.baseParser) === GrammarConstants.blobParser
    - _getErrorMethodToJavascript() {
    - if (this._isBlobNodeType()) return "getErrors() { return [] }" // Skips parsing child nodes for perf gains.
    - if (this._isErrorNodeType()) return "getErrors() { return this._getErrorNodeErrors() }"
    + get errorMethodToJavascript() {
    + if (this._isBlobParser()) return "getErrors() { return [] }" // Skips parsing child nodes for perf gains.
    + if (this._isErrorParser()) return "getErrors() { return this._getErrorParserErrors() }"
    - _getParserToJavascript() {
    - if (this._isBlobNodeType())
    + get parserAsJavascript() {
    + if (this._isBlobParser())
    - return "createParser() { return new jtree.TreeNode.Parser(this._getBlobNodeCatchAllNodeType())}"
    - const parserInfo = this._createParserInfo(this._getMyInScopeNodeTypeIds())
    + return "createParserCombinator() { return new TreeNode.ParserCombinator(this._getBlobParserCatchAllParser())}"
    + const parserInfo = this._createParserInfo(this._getMyInScopeParserIds())
    - const catchAllConstructor = this._getCatchAllNodeConstructorToJavascript()
    - if (!hasFirstWords && !catchAllConstructor && !regexRules.length) return ""
    + const catchAllParser = this.catchAllParserToJavascript
    + if (!hasFirstWords && !catchAllParser && !regexRules.length) return ""
    - ? `Object.assign(Object.assign({}, super.createParser()._getFirstWordMapAsObject()), {` + firstWords.map(firstWord => `"${firstWord}" : ${myFirstWordMap[firstWord].getNodeTypeIdFromDefinition()}`).join(",\n") + "})"
    + ? `Object.assign(Object.assign({}, super.createParserCombinator()._getFirstWordMapAsObject()), {` + firstWords.map(firstWord => `"${firstWord}" : ${myFirstWordMap[firstWord].parserIdFromDefinition}`).join(",\n") + "})"
    - return `{regex: /${rule.regex}/, nodeConstructor: ${rule.nodeConstructor}}`
    + return `{regex: /${rule.regex}/, parser: ${rule.parser}}`
    - const catchAllStr = catchAllConstructor ? catchAllConstructor : this._amIRoot() ? `this._getBlobNodeCatchAllNodeType()` : "undefined"
    - return `createParser() {
    - return new jtree.TreeNode.Parser(${catchAllStr}, ${firstWordsStr}, ${regexStr})
    + const catchAllStr = catchAllParser ? catchAllParser : this._amIRoot() ? `this._getBlobParserCatchAllParser()` : "undefined"
    + const scopedParserJavascript = this.myScopedParserDefinitions.map(def => def.asJavascriptClass).join("\n\n")
    + return `createParserCombinator() {${scopedParserJavascript}
    + return new TreeNode.ParserCombinator(${catchAllStr}, ${firstWordsStr}, ${regexStr})
    - _getCatchAllNodeConstructorToJavascript() {
    - if (this._isBlobNodeType()) return "this._getBlobNodeCatchAllNodeType()"
    - const nodeTypeId = this.get(GrammarConstants.catchAllNodeType)
    - if (!nodeTypeId) return ""
    - const nodeDef = this.getNodeTypeDefinitionByNodeTypeId(nodeTypeId)
    - if (!nodeDef) throw new Error(`No definition found for nodeType id "${nodeTypeId}"`)
    - return nodeDef._getGeneratedClassName()
    + get myScopedParserDefinitions() {
    + return this.getChildrenByParser(parserDefinitionParser)
    + }
    + get catchAllParserToJavascript() {
    + if (this._isBlobParser()) return "this._getBlobParserCatchAllParser()"
    + const parserId = this.get(GrammarConstants.catchAllParser)
    + if (!parserId) return ""
    + const nodeDef = this.getParserDefinitionByParserId(parserId)
    + return nodeDef.generatedClassName
    - _nodeDefToJavascriptClass() {
    - const components = [this._getParserToJavascript(), this._getErrorMethodToJavascript(), this._getCellGettersAndNodeTypeConstants(), this._getCustomJavascriptMethods()].filter(identity => identity)
    + get asJavascriptClass() {
    + const components = [this.parserAsJavascript, this.errorMethodToJavascript, this.cellGettersAndParserConstants, this.customJavascriptMethods].filter(identity => identity)
    + const thisClassName = this.generatedClassName
    - components.push(`static cachedHandGrammarProgramRoot = new jtree.HandGrammarProgram(\`${TreeUtils.escapeBackTicks(
    - this.getParent()
    - .toString()
    - .replace(/\\/g, "\\\\")
    - )}\`)
    - getHandGrammarProgram() {
    + components.push(`static cachedHandGrammarProgramRoot = new HandGrammarProgram(\`${Utils.escapeBackTicks(this.parent.toString().replace(/\\/g, "\\\\"))}\`)
    + get handGrammarProgram() {
    - const nodeTypeMap = this.getLanguageDefinitionProgram()
    - .getValidConcreteAndAbstractNodeTypeDefinitions()
    - .map(def => {
    - const id = def.getNodeTypeIdFromDefinition()
    - return `"${id}": ${id}`
    - })
    - .join(",\n")
    - components.push(`static getNodeTypeMap() { return {${nodeTypeMap} }}`)
    + components.push(`static rootParser = ${thisClassName}`)
    - return `class ${this._getGeneratedClassName()} extends ${this._getExtendsClassName()} {
    + return `class ${thisClassName} extends ${this._getExtendsClassName()} {
    Changed around line 15479: ${properties.join("\n")}
    - return extendedDef ? extendedDef._getGeneratedClassName() : "jtree.GrammarBackedNode"
    + return extendedDef ? extendedDef.generatedClassName : "GrammarBackedNode"
    - const items = this._getChildrenByNodeConstructorInExtended(GrammarCompilerNode)
    + const items = this._getChildrenByParserInExtended(GrammarCompilerParser)
    Changed around line 15491: ${properties.join("\n")}
    - getLineHints() {
    - return this.getCellParser().getLineHints()
    + get lineHints() {
    + return this.cellParser.lineHints
    - isOrExtendsANodeTypeInScope(firstWordsInScope) {
    - const chain = this._getNodeTypeInheritanceSet()
    + isOrExtendsAParserInScope(firstWordsInScope) {
    + const chain = this._getParserInheritanceSet()
    - isTerminalNodeType() {
    - return !this._getFromExtended(GrammarConstants.inScope) && !this._getFromExtended(GrammarConstants.catchAllNodeType)
    + isTerminalParser() {
    + return !this._getFromExtended(GrammarConstants.inScope) && !this._getFromExtended(GrammarConstants.catchAllParser)
    - _getSublimeMatchLine() {
    - const regexMatch = this._getRegexMatch()
    + get sublimeMatchLine() {
    + const regexMatch = this.regexMatch
    - const cruxMatch = this._getCruxIfAny()
    - if (cruxMatch) return `'^ *${TreeUtils.escapeRegExp(cruxMatch)}(?: |$)'`
    - const enumOptions = this._getFirstCellEnumOptions()
    - if (enumOptions) return `'^ *(${TreeUtils.escapeRegExp(enumOptions.join("|"))})(?: |$)'`
    + const cruxMatch = this.cruxIfAny
    + if (cruxMatch) return `'^ *${Utils.escapeRegExp(cruxMatch)}(?: |$)'`
    + const enumOptions = this.firstCellEnumOptions
    + if (enumOptions) return `'^ *(${Utils.escapeRegExp(enumOptions.join("|"))})(?: |$)'`
    - const program = this.getLanguageDefinitionProgram()
    - const cellParser = this.getCellParser()
    + const program = this.languageDefinitionProgram
    + const cellParser = this.cellParser
    - const catchAllCellTypeId = cellParser.getCatchAllCellTypeId()
    + const catchAllCellTypeId = cellParser.catchAllCellTypeId
    - const firstWordHighlightScope = (firstCellTypeDef ? firstCellTypeDef.getHighlightScope() : defaultHighlightScope) + "." + this.getNodeTypeIdFromDefinition()
    - const topHalf = ` '${this.getNodeTypeIdFromDefinition()}':
    - - match: ${this._getSublimeMatchLine()}
    + const firstWordHighlightScope = (firstCellTypeDef ? firstCellTypeDef.highlightScope : defaultHighlightScope) + "." + this.parserIdFromDefinition
    + const topHalf = ` '${this.parserIdFromDefinition}':
    + - match: ${this.sublimeMatchLine}
    Changed around line 15527: ${properties.join("\n")}
    - return ` ${index + 1}: ${(cellTypeDefinition.getHighlightScope() || defaultHighlightScope) + "." + cellTypeDefinition.getCellTypeId()}`
    + return ` ${index + 1}: ${(cellTypeDefinition.highlightScope || defaultHighlightScope) + "." + cellTypeDefinition.cellTypeId}`
    Changed around line 15539: ${captures}
    - match: $
    - _getNodeTypeInheritanceSet() {
    - if (!this._cache_nodeTypeInheritanceSet) this._cache_nodeTypeInheritanceSet = new Set(this.getAncestorNodeTypeIdsArray())
    - return this._cache_nodeTypeInheritanceSet
    + _getParserInheritanceSet() {
    + if (!this._cache_parserInheritanceSet) this._cache_parserInheritanceSet = new Set(this.ancestorParserIdsArray)
    + return this._cache_parserInheritanceSet
    - getAncestorNodeTypeIdsArray() {
    - if (!this._cache_ancestorNodeTypeIdsArray) {
    - this._cache_ancestorNodeTypeIdsArray = this._getAncestorsArray().map(def => def.getNodeTypeIdFromDefinition())
    - this._cache_ancestorNodeTypeIdsArray.reverse()
    + get ancestorParserIdsArray() {
    + if (!this._cache_ancestorParserIdsArray) {
    + this._cache_ancestorParserIdsArray = this._getAncestorsArray().map(def => def.parserIdFromDefinition)
    + this._cache_ancestorParserIdsArray.reverse()
    - return this._cache_ancestorNodeTypeIdsArray
    + return this._cache_ancestorParserIdsArray
    + }
    + get programParserDefinitionCache() {
    + if (!this._cache_parserDefinitionParsers) this._cache_parserDefinitionParsers = this.isRoot || this.hasParserDefinitions ? this.makeProgramParserDefinitionCache() : this.parent.programParserDefinitionCache
    + return this._cache_parserDefinitionParsers
    - _getProgramNodeTypeDefinitionCache() {
    - return this.getLanguageDefinitionProgram()._getProgramNodeTypeDefinitionCache()
    + get hasParserDefinitions() {
    + return !!this.getChildrenByParser(parserDefinitionParser).length
    - getDescription() {
    + makeProgramParserDefinitionCache() {
    + const scopedParsers = this.getChildrenByParser(parserDefinitionParser)
    + const cache = Object.assign({}, this.parent.programParserDefinitionCache) // todo. We don't really need this. we should just lookup the parent if no local hits.
    + scopedParsers.forEach(parserDefinitionParser => (cache[parserDefinitionParser.parserIdFromDefinition] = parserDefinitionParser))
    + return cache
    + }
    + get description() {
    - getFrequency() {
    + get frequency() {
    - _getExtendedNodeTypeId() {
    - const ancestorIds = this.getAncestorNodeTypeIdsArray()
    + _getExtendedParserId() {
    + const ancestorIds = this.ancestorParserIdsArray
    - const crux = this._getCruxIfAny()
    - const cellArray = this.getCellParser()
    - .getCellArray()
    - .filter((item, index) => index) // for now this only works for keyword langs
    + const crux = this.cruxIfAny
    + const cellArray = this.cellParser.getCellArray().filter((item, index) => index) // for now this only works for keyword langs
    Changed around line 15587: ${cells.toString(1)}`
    - return this._getConcreteNonErrorInScopeNodeDefinitions(this._getInScopeNodeTypeIds())
    + return this._getConcreteNonErrorInScopeNodeDefinitions(this._getInScopeParserIds())
    - const crux = this._getCruxIfAny()
    - return this.getCellParser()
    + const crux = this.cruxIfAny
    + return this.cellParser
    - _shouldSynthesize(def, nodeTypeChain) {
    - if (def._isErrorNodeType() || def._isAbstract()) return false
    - if (nodeTypeChain.includes(def._getId())) return false
    + _shouldSynthesize(def, parserChain) {
    + if (def._isErrorParser() || def._isAbstract()) return false
    + if (parserChain.includes(def.id)) return false
    - _getConcreteNonErrorInScopeNodeDefinitions(nodeTypeIds) {
    - const results = []
    - nodeTypeIds.forEach(nodeTypeId => {
    - const def = this.getNodeTypeDefinitionByNodeTypeId(nodeTypeId)
    - if (def._isErrorNodeType()) return true
    - else if (def._isAbstract()) {
    - def._getConcreteDescendantDefinitions().forEach(def => results.push(def))
    - } else {
    - results.push(def)
    - }
    + // Get all definitions in this current scope down, even ones that are scoped inside other definitions.
    + get inScopeAndDescendantDefinitions() {
    + return this.languageDefinitionProgram._collectAllDefinitions(Object.values(this.programParserDefinitionCache), [])
    + }
    + _collectAllDefinitions(defs, collection = []) {
    + defs.forEach(def => {
    + collection.push(def)
    + def._collectAllDefinitions(def.getChildrenByParser(parserDefinitionParser), collection)
    - return results
    + return collection
    + }
    + get cruxPath() {
    + const parentPath = this.parent.cruxPath
    + return (parentPath ? parentPath + " " : "") + this.cruxIfAny
    + }
    + get cruxPathAsColumnName() {
    + return this.cruxPath.replace(/ /g, "_")
    + }
    + // Get every definition that extends from this one, even ones that are scoped inside other definitions.
    + get concreteDescendantDefinitions() {
    + const { inScopeAndDescendantDefinitions, id } = this
    + return Object.values(inScopeAndDescendantDefinitions).filter(def => def._doesExtend(id) && !def._isAbstract())
    + }
    + get concreteInScopeDescendantDefinitions() {
    + // Note: non-recursive.
    + const defs = this.programParserDefinitionCache
    + const id = this.id
    + return Object.values(defs).filter(def => def._doesExtend(id) && !def._isAbstract())
    + }
    + _getConcreteNonErrorInScopeNodeDefinitions(parserIds) {
    + const defs = []
    + parserIds.forEach(parserId => {
    + const def = this.getParserDefinitionByParserId(parserId)
    + if (def._isErrorParser()) return
    + else if (def._isAbstract()) def.concreteInScopeDescendantDefinitions.forEach(def => defs.push(def))
    + else defs.push(def)
    + })
    + return defs
    - synthesizeNode(nodeCount = 1, indentCount = -1, nodeTypesAlreadySynthesized = [], seed = Date.now()) {
    - let inScopeNodeTypeIds = this._getInScopeNodeTypeIds()
    - const catchAllNodeTypeId = this._getFromExtended(GrammarConstants.catchAllNodeType)
    - if (catchAllNodeTypeId) inScopeNodeTypeIds.push(catchAllNodeTypeId)
    - const thisId = this._getId()
    - if (!nodeTypesAlreadySynthesized.includes(thisId)) nodeTypesAlreadySynthesized.push(thisId)
    + synthesizeNode(nodeCount = 1, indentCount = -1, parsersAlreadySynthesized = [], seed = Date.now()) {
    + let inScopeParserIds = this._getInScopeParserIds()
    + const catchAllParserId = this._getFromExtended(GrammarConstants.catchAllParser)
    + if (catchAllParserId) inScopeParserIds.push(catchAllParserId)
    + const thisId = this.id
    + if (!parsersAlreadySynthesized.includes(thisId)) parsersAlreadySynthesized.push(thisId)
    - this._getConcreteNonErrorInScopeNodeDefinitions(inScopeNodeTypeIds.filter(nodeTypeId => !nodeTypesAlreadySynthesized.includes(nodeTypeId)))
    - .filter(def => this._shouldSynthesize(def, nodeTypesAlreadySynthesized))
    + this._getConcreteNonErrorInScopeNodeDefinitions(inScopeParserIds.filter(parserId => !parsersAlreadySynthesized.includes(parserId)))
    + .filter(def => this._shouldSynthesize(def, parsersAlreadySynthesized))
    - const chain = nodeTypesAlreadySynthesized // .slice(0)
    - chain.push(def._getId())
    - def.synthesizeNode(1, indentCount + 1, chain, seed).forEach(line => {
    - lines.push(line)
    - })
    + const chain = parsersAlreadySynthesized // .slice(0)
    + chain.push(def.id)
    + def.synthesizeNode(1, indentCount + 1, chain, seed).forEach(line => lines.push(line))
    - getCellParser() {
    + get cellParser() {
    Changed around line 15679: ${cells.toString(1)}`
    - class nodeTypeDefinitionNode extends AbstractGrammarDefinitionNode {}
    + class parserDefinitionParser extends AbstractParserDefinitionParser {}
    - class HandGrammarProgram extends AbstractGrammarDefinitionNode {
    - createParser() {
    + class HandGrammarProgram extends AbstractParserDefinitionParser {
    + createParserCombinator() {
    - map[GrammarConstants.toolingDirective] = TreeNode
    - map[GrammarConstants.todoComment] = TreeNode
    - return new TreeNode.Parser(UnknownNodeTypeNode, map, [{ regex: HandGrammarProgram.nodeTypeFullRegex, nodeConstructor: nodeTypeDefinitionNode }, { regex: HandGrammarProgram.cellTypeFullRegex, nodeConstructor: cellTypeDefinitionNode }])
    - }
    + map[GrammarConstants.comment] = TreeNode
    + return new TreeNode.ParserCombinator(UnknownParserNode, map, [
    + { regex: HandGrammarProgram.blankLineRegex, parser: TreeNode },
    + { regex: HandGrammarProgram.parserFullRegex, parser: parserDefinitionParser },
    + { regex: HandGrammarProgram.cellTypeFullRegex, parser: cellTypeDefinitionParser }
    + ])
    + }
    + // rootParser
    - _compileAndEvalGrammar() {
    - if (!this.isNodeJs()) this._cache_compiledLoadedNodeTypes = TreeUtils.appendCodeAndReturnValueOnWindow(this.toBrowserJavascript(), this.getRootNodeTypeId()).getNodeTypeMap()
    - else {
    - const path = require("path")
    - const code = this.toNodeJsJavascript(path.join(__dirname, "..", "index.js"))
    - try {
    - const rootNode = this._requireInVmNodeJsRootNodeTypeConstructor(code)
    - this._cache_compiledLoadedNodeTypes = rootNode.getNodeTypeMap()
    - if (!this._cache_compiledLoadedNodeTypes) throw new Error(`Failed to getNodeTypeMap`)
    - } catch (err) {
    - // todo: figure out best error pattern here for debugging
    - console.log(err)
    - // console.log(`Error in code: `)
    - // console.log(new TreeNode(code).toStringWithLineNumbers())
    - }
    + _compileAndReturnRootParser() {
    + if (this._cache_rootParser) return this._cache_rootParser
    + if (!this.isNodeJs()) {
    + this._cache_rootParser = Utils.appendCodeAndReturnValueOnWindow(this.toBrowserJavascript(), this.rootParserId).rootParser
    + return this._cache_rootParser
    + }
    + const path = require("path")
    + const code = this.toNodeJsJavascript(__dirname)
    + try {
    + const rootNode = this._requireInVmNodeJsRootParser(code)
    + this._cache_rootParser = rootNode.rootParser
    + if (!this._cache_rootParser) throw new Error(`Failed to rootParser`)
    + } catch (err) {
    + // todo: figure out best error pattern here for debugging
    + console.log(err)
    + // console.log(`Error in code: `)
    + // console.log(new TreeNode(code).toStringWithLineNumbers())
    + return this._cache_rootParser
    - trainModel(programs, programConstructor = this.compileAndReturnRootConstructor()) {
    - const nodeDefs = this.getValidConcreteAndAbstractNodeTypeDefinitions()
    + get cruxPath() {
    + return ""
    + }
    + trainModel(programs, rootParser = this.compileAndReturnRootParser()) {
    + const nodeDefs = this.validConcreteAndAbstractParserDefinitions
    - const matrix = TreeUtils.makeMatrix(nodeDefCountIncludingRoot, nodeDefCountIncludingRoot, 0)
    + const matrix = Utils.makeMatrix(nodeDefCountIncludingRoot, nodeDefCountIncludingRoot, 0)
    - const id = def._getId()
    + const id = def.id
    - const exampleProgram = new programConstructor(code)
    - exampleProgram.getTopDownArray().forEach(node => {
    - const nodeIndex = idToIndex[node.getDefinition()._getId()]
    - const parentNode = node.getParent()
    + const exampleProgram = new rootParser(code)
    + exampleProgram.topDownArray.forEach(node => {
    + const nodeIndex = idToIndex[node.definition.id]
    + const parentNode = node.parent
    - const parentIndex = idToIndex[parentNode.getDefinition()._getId()]
    + const parentIndex = idToIndex[parentNode.definition.id]
    Changed around line 15749: class HandGrammarProgram extends AbstractGrammarDefinitionNode {
    - const total = TreeUtils.sum(predictionsVector)
    + const total = Utils.sum(predictionsVector)
    - id: id,
    - def: this.getNodeTypeDefinitionByNodeTypeId(id),
    + id,
    + def: this.getParserDefinitionByParserId(id),
    - predictions.sort(TreeUtils.makeSortByFn(prediction => prediction.count)).reverse()
    + predictions.sort(Utils.makeSortByFn(prediction => prediction.count)).reverse()
    Changed around line 15769: class HandGrammarProgram extends AbstractGrammarDefinitionNode {
    - return model.matrix[node.isRoot() ? 0 : model.idToIndex[node.getDefinition()._getId()]]
    + return model.matrix[node.isRoot() ? 0 : model.idToIndex[node.definition.id]]
    - const nodeIndex = model.idToIndex[node.getDefinition()._getId()]
    + const nodeIndex = model.idToIndex[node.definition.id]
    - _compileAndReturnNodeTypeMap() {
    - if (!this._cache_compiledLoadedNodeTypes) this._compileAndEvalGrammar()
    - return this._cache_compiledLoadedNodeTypes
    - }
    - _requireInVmNodeJsRootNodeTypeConstructor(code) {
    + _requireInVmNodeJsRootParser(code) {
    - const jtreePath = path.join(__dirname, "..", "index.js")
    - global.jtree = require(jtreePath)
    + Object.keys(GlobalNamespaceAdditions).forEach(key => {
    + global[key] = require("./" + GlobalNamespaceAdditions[key])
    + })
    - console.log(`Error in compiled grammar code for language "${this.getGrammarName()}"`)
    + console.log(`Error in compiled grammar code for language "${this.grammarName}"`)
    - console.log(`jtreePath: "${jtreePath}"`)
    - examplesToTestBlocks(programConstructor = this.compileAndReturnRootConstructor(), expectedErrorMessage = "") {
    + examplesToTestBlocks(rootParser = this.compileAndReturnRootParser(), expectedErrorMessage = "") {
    - this.getValidConcreteAndAbstractNodeTypeDefinitions().forEach(def =>
    - def.getExamples().forEach(example => {
    - const id = def._getId() + example.getContent()
    + this.validConcreteAndAbstractParserDefinitions.forEach(def =>
    + def.examples.forEach(example => {
    + const id = def.id + example.content
    - const exampleProgram = new programConstructor(example.childrenToString())
    + const exampleProgram = new rootParser(example.childrenToString())
    Changed around line 15815: class HandGrammarProgram extends AbstractGrammarDefinitionNode {
    - const languageName = this.getExtensionName()
    - const rootNodeDef = this.getRootNodeTypeDefinitionNode()
    - const cellTypes = this.getCellTypeDefinitions()
    - const nodeTypeFamilyTree = this.getNodeTypeFamilyTree()
    - const exampleNode = rootNodeDef.getExamples()[0]
    + const languageName = this.extensionName
    + const rootNodeDef = this.rootParserDefinition
    + const cellTypes = this.cellTypeDefinitions
    + const parserFamilyTree = this.parserFamilyTree
    + const exampleNode = rootNodeDef.examples[0]
    - paragraph ${rootNodeDef.getDescription()}
    + paragraph ${rootNodeDef.description}
    Changed around line 15832: ${exampleNode ? exampleNode.childrenToString(1) : ""}
    - - ${languageName} has ${nodeTypeFamilyTree.getTopDownArray().length} node types.
    + - ${languageName} has ${parserFamilyTree.topDownArray.length} node types.
    - ${languageName} has ${Object.keys(cellTypes).length} cell types
    - - The source code for ${languageName} is ${this.getTopDownArray().length} lines long.
    + - The source code for ${languageName} is ${this.topDownArray.length} lines long.
    Changed around line 15849: code
    - ${nodeTypeFamilyTree.toString(1)}
    + ${parserFamilyTree.toString(1)}
    Changed around line 15861: subtitle Road Map
    - ${this.getTopDownArray()
    + ${this.topDownArray
    Changed around line 15871: paragraph This readme was auto-generated using the
    - const rootNodeDef = this.getRootNodeTypeDefinitionNode()
    - const languageName = this.getExtensionName()
    - const example = rootNodeDef.getExamples()[0]
    + const rootNodeDef = this.rootParserDefinition
    + const languageName = this.extensionName
    + const example = rootNodeDef.examples[0]
    Changed around line 15891: paragraph This readme was auto-generated using the
    - console.log(errors.map(error => error.getMessage()))`
    + console.log(errors.map(error => error.message))`
    - files[GrammarBundleFiles.indexHtml] = `
    + files[GrammarBundleFiles.indexHtml] = `
    +
    +
    - const samplePath = "sample." + this.getExtensionName()
    + const samplePath = "sample." + this.extensionName
    - getTargetExtension() {
    - return this.getRootNodeTypeDefinitionNode().get(GrammarConstants.compilesTo)
    + get targetExtension() {
    + return this.rootParserDefinition.get(GrammarConstants.compilesTo)
    - getCellTypeDefinitions() {
    - if (!this._cache_cellTypes) this._cache_cellTypes = this._getCellTypeDefinitions()
    - return this._cache_cellTypes
    + get cellTypeDefinitions() {
    + if (this._cache_cellTypes) return this._cache_cellTypes
    + const types = {}
    + // todo: add built in word types?
    + this.getChildrenByParser(cellTypeDefinitionParser).forEach(type => (types[type.cellTypeId] = type))
    + this._cache_cellTypes = types
    + return types
    - return this.getCellTypeDefinitions()[cellTypeId]
    + return this.cellTypeDefinitions[cellTypeId]
    - getNodeTypeFamilyTree() {
    + get parserFamilyTree() {
    - Object.values(this.getValidConcreteAndAbstractNodeTypeDefinitions()).forEach(node => {
    - const path = node.getAncestorNodeTypeIdsArray().join(" ")
    - tree.touchNode(path)
    - })
    + Object.values(this.validConcreteAndAbstractParserDefinitions).forEach(node => tree.touchNode(node.ancestorParserIdsArray.join(" ")))
    - _getCellTypeDefinitions() {
    - const types = {}
    - // todo: add built in word types?
    - this.getChildrenByNodeConstructor(cellTypeDefinitionNode).forEach(type => (types[type.getCellTypeId()] = type))
    - return types
    - }
    - getLanguageDefinitionProgram() {
    + get languageDefinitionProgram() {
    - getValidConcreteAndAbstractNodeTypeDefinitions() {
    - return this.getChildrenByNodeConstructor(nodeTypeDefinitionNode).filter(node => node._hasValidNodeTypeId())
    + get validConcreteAndAbstractParserDefinitions() {
    + return this.getChildrenByParser(parserDefinitionParser).filter(node => node._hasValidParserId())
    - _getLastRootNodeTypeDefinitionNode() {
    - return this.findLast(def => def instanceof AbstractGrammarDefinitionNode && def.has(GrammarConstants.root) && def._hasValidNodeTypeId())
    + get lastRootParserDefinitionNode() {
    + return this.findLast(def => def instanceof AbstractParserDefinitionParser && def.has(GrammarConstants.root) && def._hasValidParserId())
    - _initRootNodeTypeDefinitionNode() {
    - if (this._cache_rootNodeTypeNode) return
    - if (!this._cache_rootNodeTypeNode) this._cache_rootNodeTypeNode = this._getLastRootNodeTypeDefinitionNode()
    + _initRootParserDefinitionNode() {
    + if (this._cache_rootParserNode) return
    + if (!this._cache_rootParserNode) this._cache_rootParserNode = this.lastRootParserDefinitionNode
    - if (!this._cache_rootNodeTypeNode) {
    - this._cache_rootNodeTypeNode = this.concat(`${GrammarConstants.defaultRootNode}
    + if (!this._cache_rootParserNode) {
    + this._cache_rootParserNode = this.concat(`${GrammarConstants.DefaultRootParser}
    - ${GrammarConstants.catchAllNodeType} ${GrammarConstants.BlobNode}`)[0]
    - this._addDefaultCatchAllBlobNode()
    + ${GrammarConstants.catchAllParser} ${GrammarConstants.BlobParser}`)[0]
    + this._addDefaultCatchAllBlobParser()
    - getRootNodeTypeDefinitionNode() {
    - this._initRootNodeTypeDefinitionNode()
    - return this._cache_rootNodeTypeNode
    + get rootParserDefinition() {
    + this._initRootParserDefinitionNode()
    + return this._cache_rootParserNode
    - // todo: whats the best design pattern to use for this sort of thing?
    - _addDefaultCatchAllBlobNode() {
    - delete this._cache_nodeTypeDefinitions
    - this.concat(`${GrammarConstants.BlobNode}
    - ${GrammarConstants.baseNodeType} ${GrammarConstants.blobNode}`)
    + _addDefaultCatchAllBlobParser() {
    + if (this._addedCatchAll) return
    + this._addedCatchAll = true
    + delete this._cache_parserDefinitionParsers
    + this.concat(`${GrammarConstants.BlobParser}
    + ${GrammarConstants.baseParser} ${GrammarConstants.blobParser}`)
    - getExtensionName() {
    - return this.getGrammarName()
    + get extensionName() {
    + return this.grammarName
    - _getId() {
    - return this.getRootNodeTypeId()
    - }
    - getRootNodeTypeId() {
    - return this.getRootNodeTypeDefinitionNode().getNodeTypeIdFromDefinition()
    + get id() {
    + return this.rootParserId
    - getGrammarName() {
    - return this.getRootNodeTypeId().replace(HandGrammarProgram.nodeTypeSuffixRegex, "")
    + get rootParserId() {
    + return this.rootParserDefinition.parserIdFromDefinition
    - _getMyInScopeNodeTypeIds() {
    - const nodeTypesNode = this.getRootNodeTypeDefinitionNode().getNode(GrammarConstants.inScope)
    - return nodeTypesNode ? nodeTypesNode.getWordsFrom(1) : []
    + get grammarName() {
    + return this.rootParserId.replace(HandGrammarProgram.parserSuffixRegex, "")
    - _getInScopeNodeTypeIds() {
    - const nodeTypesNode = this.getRootNodeTypeDefinitionNode().getNode(GrammarConstants.inScope)
    - return nodeTypesNode ? nodeTypesNode.getWordsFrom(1) : []
    + _getMyInScopeParserIds() {
    + return super._getMyInScopeParserIds(this.rootParserDefinition)
    - _initProgramNodeTypeDefinitionCache() {
    - if (this._cache_nodeTypeDefinitions) return undefined
    - this._cache_nodeTypeDefinitions = {}
    - this.getChildrenByNodeConstructor(nodeTypeDefinitionNode).forEach(nodeTypeDefinitionNode => {
    - this._cache_nodeTypeDefinitions[nodeTypeDefinitionNode.getNodeTypeIdFromDefinition()] = nodeTypeDefinitionNode
    - })
    + _getInScopeParserIds() {
    + const parsersNode = this.rootParserDefinition.getNode(GrammarConstants.inScope)
    + return parsersNode ? parsersNode.getWordsFrom(1) : []
    - _getProgramNodeTypeDefinitionCache() {
    - this._initProgramNodeTypeDefinitionCache()
    - return this._cache_nodeTypeDefinitions
    + makeProgramParserDefinitionCache() {
    + const cache = {}
    + this.getChildrenByParser(parserDefinitionParser).forEach(parserDefinitionParser => (cache[parserDefinitionParser.parserIdFromDefinition] = parserDefinitionParser))
    + return cache
    - compileAndReturnRootConstructor() {
    - if (!this._cache_rootConstructorClass) {
    - const def = this.getRootNodeTypeDefinitionNode()
    - const rootNodeTypeId = def.getNodeTypeIdFromDefinition()
    - this._cache_rootConstructorClass = def.getLanguageDefinitionProgram()._compileAndReturnNodeTypeMap()[rootNodeTypeId]
    + compileAndReturnRootParser() {
    + if (!this._cached_rootParser) {
    + const rootDef = this.rootParserDefinition
    + this._cached_rootParser = rootDef.languageDefinitionProgram._compileAndReturnRootParser()
    - return this._cache_rootConstructorClass
    + return this._cached_rootParser
    - _getFileExtensions() {
    - return this.getRootNodeTypeDefinitionNode().get(GrammarConstants.extensions)
    - ? this.getRootNodeTypeDefinitionNode()
    - .get(GrammarConstants.extensions)
    - .split(" ")
    - .join(",")
    - : this.getExtensionName()
    + get fileExtensions() {
    + return this.rootParserDefinition.get(GrammarConstants.extensions) ? this.rootParserDefinition.get(GrammarConstants.extensions).split(" ").join(",") : this.extensionName
    - toNodeJsJavascript(normalizedJtreePath = "jtree") {
    - return this._rootNodeDefToJavascriptClass(normalizedJtreePath, true).trim()
    + toNodeJsJavascript(jtreeProductsPath = "jtree/products") {
    + return this._rootNodeDefToJavascriptClass(jtreeProductsPath, true).trim()
    - _getProperName() {
    - return TreeUtils.ucfirst(this.getExtensionName())
    - }
    - _rootNodeDefToJavascriptClass(normalizedJtreePath, forNodeJs = true) {
    - const defs = this.getValidConcreteAndAbstractNodeTypeDefinitions()
    + _rootNodeDefToJavascriptClass(jtreeProductsPath, forNodeJs = true) {
    + const defs = this.validConcreteAndAbstractParserDefinitions
    - const nodeTypeClasses = defs.map(def => def._nodeDefToJavascriptClass()).join("\n\n")
    - const rootDef = this.getRootNodeTypeDefinitionNode()
    + const parserClasses = defs.map(def => def.asJavascriptClass).join("\n\n")
    + const rootDef = this.rootParserDefinition
    - const rootName = rootDef._getGeneratedClassName()
    + const rootName = rootDef.generatedClassName
    - if (forNodeJs) {
    + if (forNodeJs)
    - } else {
    - exportScript = `window.${rootName} = ${rootName}`
    - }
    + else exportScript = `window.${rootName} = ${rootName}`
    + let nodeJsImports = ``
    + if (forNodeJs)
    + nodeJsImports = Object.keys(GlobalNamespaceAdditions)
    + .map(key => `const { ${key} } = require("${jtreeProductsPath}/${GlobalNamespaceAdditions[key]}")`)
    + .join("\n")
    - ${forNodeJs ? `const {jtree} = require("${normalizedJtreePath.replace(/\\/g, "\\\\")}")` : ""}
    + ${nodeJsImports}
    - ${nodeTypeClasses}
    + ${parserClasses}
    - const cellTypeDefs = this.getCellTypeDefinitions()
    + const cellTypeDefs = this.cellTypeDefinitions
    - .map(name => ` ${name}: '${cellTypeDefs[name].getRegexString()}'`)
    + .map(name => ` ${name}: '${cellTypeDefs[name].regexString}'`)
    - const defs = this.getValidConcreteAndAbstractNodeTypeDefinitions().filter(kw => !kw._isAbstract())
    - const nodeTypeContexts = defs.map(def => def._toSublimeMatchBlock()).join("\n\n")
    - const includes = defs.map(nodeTypeDef => ` - include: '${nodeTypeDef.getNodeTypeIdFromDefinition()}'`).join("\n")
    + const defs = this.validConcreteAndAbstractParserDefinitions.filter(kw => !kw._isAbstract())
    + const parserContexts = defs.map(def => def._toSublimeMatchBlock()).join("\n\n")
    + const includes = defs.map(parserDef => ` - include: '${parserDef.parserIdFromDefinition}'`).join("\n")
    - name: ${this.getExtensionName()}
    - file_extensions: [${this._getFileExtensions()}]
    - scope: source.${this.getExtensionName()}
    + name: ${this.extensionName}
    + file_extensions: [${this.fileExtensions}]
    + scope: source.${this.extensionName}
    Changed around line 16053: contexts:
    - ${nodeTypeContexts}`
    + ${parserContexts}`
    - HandGrammarProgram.makeNodeTypeId = str => TreeUtils._replaceNonAlphaNumericCharactersWithCharCodes(str).replace(HandGrammarProgram.nodeTypeSuffixRegex, "") + GrammarConstants.nodeTypeSuffix
    - HandGrammarProgram.makeCellTypeId = str => TreeUtils._replaceNonAlphaNumericCharactersWithCharCodes(str).replace(HandGrammarProgram.cellTypeSuffixRegex, "") + GrammarConstants.cellTypeSuffix
    - HandGrammarProgram.nodeTypeSuffixRegex = new RegExp(GrammarConstants.nodeTypeSuffix + "$")
    - HandGrammarProgram.nodeTypeFullRegex = new RegExp("^[a-zA-Z0-9_]+" + GrammarConstants.nodeTypeSuffix + "$")
    + HandGrammarProgram.makeParserId = str => Utils._replaceNonAlphaNumericCharactersWithCharCodes(str).replace(HandGrammarProgram.parserSuffixRegex, "") + GrammarConstants.parserSuffix
    + HandGrammarProgram.makeCellTypeId = str => Utils._replaceNonAlphaNumericCharactersWithCharCodes(str).replace(HandGrammarProgram.cellTypeSuffixRegex, "") + GrammarConstants.cellTypeSuffix
    + HandGrammarProgram.parserSuffixRegex = new RegExp(GrammarConstants.parserSuffix + "$")
    + HandGrammarProgram.parserFullRegex = new RegExp("^[a-zA-Z0-9_]+" + GrammarConstants.parserSuffix + "$")
    + HandGrammarProgram.blankLineRegex = new RegExp("^$")
    - HandGrammarProgram._nodeTypes = {}
    + HandGrammarProgram._parsers = {}
    Changed around line 16073: PreludeKinds[PreludeCellTypeIds.numberCell] = GrammarFloatCell
    - window.GrammarConstants = GrammarConstants
    - window.PreludeCellTypeIds = PreludeCellTypeIds
    - window.HandGrammarProgram = HandGrammarProgram
    - window.GrammarBackedNode = GrammarBackedNode
    - window.UnknownNodeTypeError = UnknownNodeTypeError
    - class Upgrader extends TreeNode {
    - upgradeManyInPlace(globPatterns, fromVersion, toVersion) {
    - this._upgradeMany(globPatterns, fromVersion, toVersion).forEach(file => file.tree.toDisk(file.path))
    - return this
    - }
    - upgradeManyPreview(globPatterns, fromVersion, toVersion) {
    - return this._upgradeMany(globPatterns, fromVersion, toVersion)
    - }
    - _upgradeMany(globPatterns, fromVersion, toVersion) {
    - const glob = this.require("glob")
    - const files = TreeUtils.flatten(globPatterns.map(pattern => glob.sync(pattern)))
    - console.log(`${files.length} files to upgrade`)
    - return files.map(path => {
    - console.log("Upgrading " + path)
    - return {
    - tree: this.upgrade(TreeNode.fromDisk(path), fromVersion, toVersion),
    - path: path
    - }
    - })
    - }
    - upgrade(code, fromVersion, toVersion) {
    - const updateFromMap = this.getUpgradeFromMap()
    - const semver = this.require("semver")
    - let fromMap
    - while ((fromMap = updateFromMap[fromVersion])) {
    - const toNextVersion = Object.keys(fromMap)[0] // todo: currently we just assume 1 step at a time
    - if (semver.lt(toVersion, toNextVersion)) break
    - const fn = Object.values(fromMap)[0]
    - code = fn(code)
    - fromVersion = toNextVersion
    - }
    - return code
    - }
    - }
    - window.Upgrader = Upgrader
    - grammarName = HandGrammarProgram.makeNodeTypeId(grammarName)
    + grammarName = HandGrammarProgram.makeParserId(grammarName)
    - // note: right now we assume 1 global cellTypeMap and nodeTypeMap per grammar. But we may have scopes in the future?
    + // note: right now we assume 1 global cellTypeMap and parserMap per grammar. But we may have scopes in the future?
    - .map(word => HandGrammarProgram.makeNodeTypeId(word))
    + .map(word => HandGrammarProgram.makeParserId(word))
    Changed around line 16091: class UnknownGrammarProgram extends TreeNode {
    - const firstWordIsAnInteger = !!node.getFirstWord().match(/^\d+$/)
    - const parentFirstWord = node.getParent().getFirstWord()
    - if (firstWordIsAnInteger && parentFirstWord) node.setFirstWord(HandGrammarProgram.makeNodeTypeId(parentFirstWord + UnknownGrammarProgram._childSuffix))
    + const firstWordIsAnInteger = !!node.firstWord.match(/^\d+$/)
    + const parentFirstWord = node.parent.firstWord
    + if (firstWordIsAnInteger && parentFirstWord) node.setFirstWord(HandGrammarProgram.makeParserId(parentFirstWord + UnknownGrammarProgram._childSuffix))
    - const firstWord = node.getFirstWord()
    + const firstWord = node.firstWord
    - node.forEach(child => {
    - keywordsToChildKeywords[firstWord][child.getFirstWord()] = true
    - })
    + node.forEach(child => (keywordsToChildKeywords[firstWord][child.firstWord] = true))
    - _inferNodeTypeDef(firstWord, globalCellTypeMap, childFirstWords, instances) {
    - const edgeSymbol = this.getEdgeSymbol()
    - const nodeTypeId = HandGrammarProgram.makeNodeTypeId(firstWord)
    - const nodeDefNode = new TreeNode(nodeTypeId).nodeAt(0)
    - const childNodeTypeIds = childFirstWords.map(word => HandGrammarProgram.makeNodeTypeId(word))
    - if (childNodeTypeIds.length) nodeDefNode.touchNode(GrammarConstants.inScope).setWordsFrom(1, childNodeTypeIds)
    + _inferParserDef(firstWord, globalCellTypeMap, childFirstWords, instances) {
    + const edgeSymbol = this.edgeSymbol
    + const parserId = HandGrammarProgram.makeParserId(firstWord)
    + const nodeDefNode = new TreeNode(parserId).nodeAt(0)
    + const childParserIds = childFirstWords.map(word => HandGrammarProgram.makeParserId(word))
    + if (childParserIds.length) nodeDefNode.touchNode(GrammarConstants.inScope).setWordsFrom(1, childParserIds)
    - .map(line => line.getContent())
    + .map(line => line.content)
    Changed around line 16124: class UnknownGrammarProgram extends TreeNode {
    - const cellType = this._getBestCellType(firstWord, instances.length, maxCellsOnLine, cellsForAllInstances.map(cells => cells[cellIndex]))
    + const cellType = this._getBestCellType(
    + firstWord,
    + instances.length,
    + maxCellsOnLine,
    + cellsForAllInstances.map(cells => cells[cellIndex])
    + )
    Changed around line 16140: class UnknownGrammarProgram extends TreeNode {
    - const needsCruxProperty = !firstWord.endsWith(UnknownGrammarProgram._childSuffix + "Node") // todo: cleanup
    + const needsCruxProperty = !firstWord.endsWith(UnknownGrammarProgram._childSuffix + GrammarConstants.parserSuffix) // todo: cleanup
    Changed around line 16148: class UnknownGrammarProgram extends TreeNode {
    - return nodeDefNode.getParent().toString()
    + return nodeDefNode.parent.toString()
    - // grammarName = HandGrammarProgram.makeNodeTypeId(grammarName)
    + // grammarName = HandGrammarProgram.makeParserId(grammarName)
    - // // note: right now we assume 1 global cellTypeMap and nodeTypeMap per grammar. But we may have scopes in the future?
    - // const rootNodeNames = this.getFirstWords().map(word => HandGrammarProgram.makeNodeTypeId(word))
    + // // note: right now we assume 1 global cellTypeMap and parserMap per grammar. But we may have scopes in the future?
    + // const rootNodeNames = this.getFirstWords().map(word => HandGrammarProgram.makeParserId(word))
    Changed around line 16168: class UnknownGrammarProgram extends TreeNode {
    - const nodeTypeDefs = Object.keys(keywordsToChildKeywords)
    + const parserDefs = Object.keys(keywordsToChildKeywords)
    - .map(firstWord => this._inferNodeTypeDef(firstWord, globalCellTypeMap, Object.keys(keywordsToChildKeywords[firstWord]), keywordsToNodeInstances[firstWord]))
    + .map(firstWord => this._inferParserDef(firstWord, globalCellTypeMap, Object.keys(keywordsToChildKeywords[firstWord]), keywordsToNodeInstances[firstWord]))
    - const nodeBreakSymbol = this.getNodeBreakSymbol()
    - return this._formatCode([this._inferRootNodeForAPrefixLanguage(grammarName).toString(), cellTypeDefs.join(nodeBreakSymbol), nodeTypeDefs.join(nodeBreakSymbol)].filter(identity => identity).join("\n"))
    + const nodeBreakSymbol = this.nodeBreakSymbol
    + return this._formatCode([this._inferRootNodeForAPrefixLanguage(grammarName).toString(), cellTypeDefs.join(nodeBreakSymbol), parserDefs.join(nodeBreakSymbol)].filter(identity => identity).join("\n"))
    - const programConstructor = grammarProgram.compileAndReturnRootConstructor()
    - const program = new programConstructor(code)
    + const rootParser = grammarProgram.compileAndReturnRootParser()
    + const program = new rootParser(code)
    - const edgeSymbol = this.getEdgeSymbol()
    + const edgeSymbol = this.edgeSymbol
    Changed around line 16219: class UnknownGrammarProgram extends TreeNode {
    + window.GrammarConstants = GrammarConstants
    + window.PreludeCellTypeIds = PreludeCellTypeIds
    + window.HandGrammarProgram = HandGrammarProgram
    + window.GrammarBackedNode = GrammarBackedNode
    + window.UnknownParserError = UnknownParserError
    +
    +
    + "use strict"
    - ;(function(CmToken) {
    + ;(function (CmToken) {
    Changed around line 16408: const textMateScopeToCodeMirrorStyle = (scopeSegments, styleTree = tmToCm) => {
    - class TreeNotationCodeMirrorMode {
    - constructor(name, getProgramConstructorFn, getProgramCodeFn, codeMirrorLib = undefined) {
    + class GrammarCodeMirrorMode {
    + constructor(name, getRootParserFn, getProgramCodeFn, codeMirrorLib = undefined) {
    - this._getProgramConstructorFn = getProgramConstructorFn
    + this._getRootParserFn = getRootParserFn
    Changed around line 16419: class TreeNotationCodeMirrorMode {
    - this._cachedProgram = new (this._getProgramConstructorFn())(source)
    + this._cachedProgram = new (this._getRootParserFn())(source)
    - "8": "backspace",
    - "9": "tab",
    - "13": "enter",
    - "16": "shift",
    - "17": "ctrl",
    - "18": "alt",
    - "19": "pause",
    - "20": "capslock",
    - "27": "escape",
    - "33": "pageup",
    - "34": "pagedown",
    - "35": "end",
    - "36": "home",
    - "37": "left",
    - "38": "up",
    - "39": "right",
    - "40": "down",
    - "45": "insert",
    - "46": "delete",
    - "91": "left window key",
    - "92": "right window key",
    - "93": "select",
    - "112": "f1",
    - "113": "f2",
    - "114": "f3",
    - "115": "f4",
    - "116": "f5",
    - "117": "f6",
    - "118": "f7",
    - "119": "f8",
    - "120": "f9",
    - "121": "f10",
    - "122": "f11",
    - "123": "f12",
    - "144": "numlock",
    - "145": "scrolllock"
    + 8: "backspace",
    + 9: "tab",
    + 13: "enter",
    + 16: "shift",
    + 17: "ctrl",
    + 18: "alt",
    + 19: "pause",
    + 20: "capslock",
    + 27: "escape",
    + 33: "pageup",
    + 34: "pagedown",
    + 35: "end",
    + 36: "home",
    + 37: "left",
    + 38: "up",
    + 39: "right",
    + 40: "down",
    + 45: "insert",
    + 46: "delete",
    + 91: "left window key",
    + 92: "right window key",
    + 93: "select",
    + 112: "f1",
    + 113: "f2",
    + 114: "f3",
    + 115: "f4",
    + 116: "f5",
    + 117: "f6",
    + 118: "f7",
    + 119: "f8",
    + 120: "f9",
    + 121: "f10",
    + 122: "f11",
    + 123: "f12",
    + 144: "numlock",
    + 145: "scrolllock"
    Changed around line 16563: class TreeNotationCodeMirrorMode {
    - window.TreeNotationCodeMirrorMode = TreeNotationCodeMirrorMode
    - class jtree {}
    - jtree.GrammarBackedNode = GrammarBackedNode
    - jtree.GrammarConstants = GrammarConstants
    - jtree.Utils = TreeUtils
    - jtree.UnknownNodeTypeError = UnknownNodeTypeError
    - jtree.TestRacer = TestRacer
    - jtree.TreeEvents = TreeEvents
    - jtree.TreeNode = TreeNode
    - jtree.ExtendibleTreeNode = ExtendibleTreeNode
    - jtree.HandGrammarProgram = HandGrammarProgram
    - jtree.UnknownGrammarProgram = UnknownGrammarProgram
    - jtree.TreeNotationCodeMirrorMode = TreeNotationCodeMirrorMode
    - jtree.getVersion = () => TreeNode.getVersion()
    - window.jtree = jtree
    + window.GrammarCodeMirrorMode = GrammarCodeMirrorMode
    - class stumpNode extends jtree.GrammarBackedNode {
    - createParser() {
    - return new jtree.TreeNode.Parser(
    - errorNode,
    - Object.assign(Object.assign({}, super.createParser()._getFirstWordMapAsObject()), {
    - blockquote: htmlTagNode,
    - colgroup: htmlTagNode,
    - datalist: htmlTagNode,
    - fieldset: htmlTagNode,
    - menuitem: htmlTagNode,
    - noscript: htmlTagNode,
    - optgroup: htmlTagNode,
    - progress: htmlTagNode,
    - styleTag: htmlTagNode,
    - template: htmlTagNode,
    - textarea: htmlTagNode,
    - titleTag: htmlTagNode,
    - address: htmlTagNode,
    - article: htmlTagNode,
    - caption: htmlTagNode,
    - details: htmlTagNode,
    - section: htmlTagNode,
    - summary: htmlTagNode,
    - button: htmlTagNode,
    - canvas: htmlTagNode,
    - dialog: htmlTagNode,
    - figure: htmlTagNode,
    - footer: htmlTagNode,
    - header: htmlTagNode,
    - hgroup: htmlTagNode,
    - iframe: htmlTagNode,
    - keygen: htmlTagNode,
    - legend: htmlTagNode,
    - object: htmlTagNode,
    - option: htmlTagNode,
    - output: htmlTagNode,
    - script: htmlTagNode,
    - select: htmlTagNode,
    - source: htmlTagNode,
    - strong: htmlTagNode,
    - aside: htmlTagNode,
    - embed: htmlTagNode,
    - input: htmlTagNode,
    - label: htmlTagNode,
    - meter: htmlTagNode,
    - param: htmlTagNode,
    - small: htmlTagNode,
    - table: htmlTagNode,
    - tbody: htmlTagNode,
    - tfoot: htmlTagNode,
    - thead: htmlTagNode,
    - track: htmlTagNode,
    - video: htmlTagNode,
    - abbr: htmlTagNode,
    - area: htmlTagNode,
    - base: htmlTagNode,
    - body: htmlTagNode,
    - code: htmlTagNode,
    - form: htmlTagNode,
    - head: htmlTagNode,
    - html: htmlTagNode,
    - link: htmlTagNode,
    - main: htmlTagNode,
    - mark: htmlTagNode,
    - menu: htmlTagNode,
    - meta: htmlTagNode,
    - ruby: htmlTagNode,
    - samp: htmlTagNode,
    - span: htmlTagNode,
    - time: htmlTagNode,
    - bdi: htmlTagNode,
    - bdo: htmlTagNode,
    - col: htmlTagNode,
    - del: htmlTagNode,
    - dfn: htmlTagNode,
    - div: htmlTagNode,
    - img: htmlTagNode,
    - ins: htmlTagNode,
    - kbd: htmlTagNode,
    - map: htmlTagNode,
    - nav: htmlTagNode,
    - pre: htmlTagNode,
    - rtc: htmlTagNode,
    - sub: htmlTagNode,
    - sup: htmlTagNode,
    - var: htmlTagNode,
    - wbr: htmlTagNode,
    - br: htmlTagNode,
    - dd: htmlTagNode,
    - dl: htmlTagNode,
    - dt: htmlTagNode,
    - em: htmlTagNode,
    - h1: htmlTagNode,
    - h2: htmlTagNode,
    - h3: htmlTagNode,
    - h4: htmlTagNode,
    - h5: htmlTagNode,
    - h6: htmlTagNode,
    - hr: htmlTagNode,
    - li: htmlTagNode,
    - ol: htmlTagNode,
    - rb: htmlTagNode,
    - rp: htmlTagNode,
    - rt: htmlTagNode,
    - td: htmlTagNode,
    - th: htmlTagNode,
    - tr: htmlTagNode,
    - ul: htmlTagNode,
    - a: htmlTagNode,
    - b: htmlTagNode,
    - i: htmlTagNode,
    - p: htmlTagNode,
    - q: htmlTagNode,
    - s: htmlTagNode,
    - u: htmlTagNode
    + class stumpParser extends GrammarBackedNode {
    + createParserCombinator() {
    + return new TreeNode.ParserCombinator(
    + errorParser,
    + Object.assign(Object.assign({}, super.createParserCombinator()._getFirstWordMapAsObject()), {
    + blockquote: htmlTagParser,
    + colgroup: htmlTagParser,
    + datalist: htmlTagParser,
    + fieldset: htmlTagParser,
    + menuitem: htmlTagParser,
    + noscript: htmlTagParser,
    + optgroup: htmlTagParser,
    + progress: htmlTagParser,
    + styleTag: htmlTagParser,
    + template: htmlTagParser,
    + textarea: htmlTagParser,
    + titleTag: htmlTagParser,
    + address: htmlTagParser,
    + article: htmlTagParser,
    + caption: htmlTagParser,
    + details: htmlTagParser,
    + section: htmlTagParser,
    + summary: htmlTagParser,
    + button: htmlTagParser,
    + canvas: htmlTagParser,
    + dialog: htmlTagParser,
    + figure: htmlTagParser,
    + footer: htmlTagParser,
    + header: htmlTagParser,
    + hgroup: htmlTagParser,
    + iframe: htmlTagParser,
    + keygen: htmlTagParser,
    + legend: htmlTagParser,
    + object: htmlTagParser,
    + option: htmlTagParser,
    + output: htmlTagParser,
    + script: htmlTagParser,
    + select: htmlTagParser,
    + source: htmlTagParser,
    + strong: htmlTagParser,
    + aside: htmlTagParser,
    + embed: htmlTagParser,
    + input: htmlTagParser,
    + label: htmlTagParser,
    + meter: htmlTagParser,
    + param: htmlTagParser,
    + small: htmlTagParser,
    + table: htmlTagParser,
    + tbody: htmlTagParser,
    + tfoot: htmlTagParser,
    + thead: htmlTagParser,
    + track: htmlTagParser,
    + video: htmlTagParser,
    + abbr: htmlTagParser,
    + area: htmlTagParser,
    + base: htmlTagParser,
    + body: htmlTagParser,
    + code: htmlTagParser,
    + form: htmlTagParser,
    + head: htmlTagParser,
    + html: htmlTagParser,
    + link: htmlTagParser,
    + main: htmlTagParser,
    + mark: htmlTagParser,
    + menu: htmlTagParser,
    + meta: htmlTagParser,
    + ruby: htmlTagParser,
    + samp: htmlTagParser,
    + span: htmlTagParser,
    + time: htmlTagParser,
    + bdi: htmlTagParser,
    + bdo: htmlTagParser,
    + col: htmlTagParser,
    + del: htmlTagParser,
    + dfn: htmlTagParser,
    + div: htmlTagParser,
    + img: htmlTagParser,
    + ins: htmlTagParser,
    + kbd: htmlTagParser,
    + map: htmlTagParser,
    + nav: htmlTagParser,
    + pre: htmlTagParser,
    + rtc: htmlTagParser,
    + sub: htmlTagParser,
    + sup: htmlTagParser,
    + var: htmlTagParser,
    + wbr: htmlTagParser,
    + br: htmlTagParser,
    + dd: htmlTagParser,
    + dl: htmlTagParser,
    + dt: htmlTagParser,
    + em: htmlTagParser,
    + h1: htmlTagParser,
    + h2: htmlTagParser,
    + h3: htmlTagParser,
    + h4: htmlTagParser,
    + h5: htmlTagParser,
    + h6: htmlTagParser,
    + hr: htmlTagParser,
    + li: htmlTagParser,
    + ol: htmlTagParser,
    + rb: htmlTagParser,
    + rp: htmlTagParser,
    + rt: htmlTagParser,
    + td: htmlTagParser,
    + th: htmlTagParser,
    + tr: htmlTagParser,
    + ul: htmlTagParser,
    + a: htmlTagParser,
    + b: htmlTagParser,
    + i: htmlTagParser,
    + p: htmlTagParser,
    + q: htmlTagParser,
    + s: htmlTagParser,
    + u: htmlTagParser,
    - [{ regex: /^$/, nodeConstructor: blankLineNode }, { regex: /^[a-zA-Z0-9_]+Component/, nodeConstructor: componentDefinitionNode }]
    + [
    + { regex: /^$/, parser: blankLineParser },
    + { regex: /^[a-zA-Z0-9_]+Component/, parser: componentDefinitionParser },
    + ]
    - return this.toHtml()
    + return this.asHtml
    - static cachedHandGrammarProgramRoot = new jtree.HandGrammarProgram(`tooling onsave jtree build produceLang stump
    + static cachedHandGrammarProgramRoot = new HandGrammarProgram(`// Cell parsers
    Changed around line 16719: htmlAttributeNameCell
    - stumpNode
    +
    + // Line parsers
    + stumpParser
    - catchAllNodeType errorNode
    - inScope htmlTagNode blankLineNode
    + catchAllParser errorParser
    + inScope htmlTagParser blankLineParser
    - return this.toHtml()
    + return this.asHtml
    - blankLineNode
    + blankLineParser
    Changed around line 16746: blankLineNode
    - htmlTagNode
    - inScope bernNode htmlTagNode htmlAttributeNode blankLineNode
    + htmlTagParser
    + inScope bernParser htmlTagParser htmlAttributeParser blankLineParser
    - isHtmlTagNode = true
    + isHtmlTagParser = true
    - const firstWord = this.getFirstWord()
    + const firstWord = this.firstWord
    Changed around line 16764: htmlTagNode
    - toHtmlWithSuids() {
    + asHtmlWithSuids() {
    Changed around line 16780: htmlTagNode
    - this.filter(node => node.isAttributeNode)
    - .forEach(child => elem.setAttribute(child.getFirstWord(), child.getContent()))
    + this.filter(node => node.isAttributeParser)
    + .forEach(child => elem.setAttribute(child.firstWord, child.content))
    - this.filter(node => node.isHtmlTagNode)
    + this.filter(node => node.isHtmlTagParser)
    - const attributesStr = this.filter(node => node.isAttributeNode)
    + const attributesStr = this.filter(node => node.isAttributeParser)
    - const indentForChildNodes = !collapse && this.getChildInstancesOfNodeTypeId("htmlTagNode").length > 0
    + const indentForChildParsers = !collapse && this.getChildInstancesOfParserId("htmlTagParser").length > 0
    - return \`\${!collapse ? indent : ""}<\${tag}\${attributesStr}\${suid}>\${oneLiner}\${indentForChildNodes ? "\\n" : ""}\${children}\${collapse ? "" : "\\n"}\`
    + return \`\${!collapse ? indent : ""}<\${tag}\${attributesStr}\${suid}>\${oneLiner}\${indentForChildParsers ? "\\n" : ""}\${children}\${collapse ? "" : "\\n"}\`
    Changed around line 16808: htmlTagNode
    - return this.getTopDownArray().find(node => node._getUid() === guid)
    + return this.topDownArray.find(node => node._getUid() === guid)
    - const classNode = this.touchNode("class")
    - const words = classNode.getWordsFrom(1)
    + const classParser = this.touchNode("class")
    + const words = classParser.getWordsFrom(1)
    - classNode.setContent(words.join(this.getWordBreakSymbol()))
    + classParser.setContent(words.join(this.wordBreakSymbol))
    - const classNode = this.getNode("class")
    - if (!classNode) return this
    - const newClasses = classNode.getWords().filter(word => word !== className)
    - if (!newClasses.length) classNode.destroy()
    - else classNode.setContent(newClasses.join(" "))
    + const classParser = this.getNode("class")
    + if (!classParser) return this
    + const newClasses = classParser.words.filter(word => word !== className)
    + if (!newClasses.length) classParser.destroy()
    + else classParser.setContent(newClasses.join(" "))
    - const classNode = this.getNode("class")
    - return classNode && classNode.getWords().includes(className) ? true : false
    + const classParser = this.getNode("class")
    + return classParser && classParser.words.includes(className) ? true : false
    Changed around line 16848: htmlTagNode
    - const singleNode = new jtree.TreeNode(text).getChildren()[0]
    + const singleNode = new TreeNode(text).getChildren()[0]
    - const stumpNodeIndex = this.filter(node => node.isHtmlTagNode).indexOf(newNode)
    - this.getShadow().insertHtmlNode(newNode, stumpNodeIndex)
    + const stumpParserIndex = this.filter(node => node.isHtmlTagParser).indexOf(newNode)
    + this.getShadow().insertHtmlNode(newNode, stumpParserIndex)
    Changed around line 16861: htmlTagNode
    - return this.getTopDownArray().find(node =>
    + return this.topDownArray.find(node =>
    Changed around line 16872: htmlTagNode
    - return this.getTopDownArray().filter(node => node.doesExtend("htmlTagNode") && node.getFirstWord() === firstWord)
    + return this.topDownArray.filter(node => node.doesExtend("htmlTagParser") && node.firstWord === firstWord)
    - return this.getTopDownArray().filter(node => node.doesExtend("htmlTagNode") && node.hasLine(line))
    + return this.topDownArray.filter(node => node.doesExtend("htmlTagParser") && node.hasLine(line))
    - return this.getTopDownArray().filter(
    + return this.topDownArray.filter(
    - node.doesExtend("htmlTagNode") &&
    + node.doesExtend("htmlTagParser") &&
    - .getWords()
    + .words
    - return this.getParent().getShadowClass()
    + return this.parent.getShadowClass()
    - return this._treeComponent || this.getParent().getStumpNodeTreeComponent()
    + return this._treeComponent || this.parent.getStumpNodeTreeComponent()
    Changed around line 16913: htmlTagNode
    - toHtml() {
    + get asHtml() {
    - errorNode
    - baseNodeType errorNode
    - componentDefinitionNode
    - extends htmlTagNode
    + errorParser
    + baseParser errorParser
    + componentDefinitionParser
    + extends htmlTagParser
    - htmlAttributeNode
    + htmlAttributeParser
    - return \` \${this.getFirstWord()}="\${this.getContent()}"\`
    + return \` \${this.firstWord}="\${this.content}"\`
    - boolean isAttributeNode true
    + boolean isAttributeParser true
    - catchAllNodeType errorNode
    + catchAllParser errorParser
    - stumpExtendedAttributeNode
    - description Node types not present in HTML but included in stump.
    - extends htmlAttributeNode
    + stumpExtendedAttributeParser
    + description Parser types not present in HTML but included in stump.
    + extends htmlAttributeParser
    - lineOfHtmlContentNode
    + lineOfHtmlContentParser
    - catchAllNodeType lineOfHtmlContentNode
    + catchAllParser lineOfHtmlContentParser
    - bernNode
    + bernParser
    - todo Rename this node type
    + // todo Rename this node type
    - catchAllNodeType lineOfHtmlContentNode
    + catchAllParser lineOfHtmlContentParser
    - getHandGrammarProgram() {
    + get handGrammarProgram() {
    - static getNodeTypeMap() {
    - return {
    - stumpNode: stumpNode,
    - blankLineNode: blankLineNode,
    - htmlTagNode: htmlTagNode,
    - errorNode: errorNode,
    - componentDefinitionNode: componentDefinitionNode,
    - htmlAttributeNode: htmlAttributeNode,
    - stumpExtendedAttributeNode: stumpExtendedAttributeNode,
    - lineOfHtmlContentNode: lineOfHtmlContentNode,
    - bernNode: bernNode
    - }
    - }
    + static rootParser = stumpParser
    - class blankLineNode extends jtree.GrammarBackedNode {
    + class blankLineParser extends GrammarBackedNode {
    Changed around line 16982: bernNode
    - class htmlTagNode extends jtree.GrammarBackedNode {
    - createParser() {
    - return new jtree.TreeNode.Parser(
    + class htmlTagParser extends GrammarBackedNode {
    + createParserCombinator() {
    + return new TreeNode.ParserCombinator(
    - Object.assign(Object.assign({}, super.createParser()._getFirstWordMapAsObject()), {
    - blockquote: htmlTagNode,
    - colgroup: htmlTagNode,
    - datalist: htmlTagNode,
    - fieldset: htmlTagNode,
    - menuitem: htmlTagNode,
    - noscript: htmlTagNode,
    - optgroup: htmlTagNode,
    - progress: htmlTagNode,
    - styleTag: htmlTagNode,
    - template: htmlTagNode,
    - textarea: htmlTagNode,
    - titleTag: htmlTagNode,
    - address: htmlTagNode,
    - article: htmlTagNode,
    - caption: htmlTagNode,
    - details: htmlTagNode,
    - section: htmlTagNode,
    - summary: htmlTagNode,
    - button: htmlTagNode,
    - canvas: htmlTagNode,
    - dialog: htmlTagNode,
    - figure: htmlTagNode,
    - footer: htmlTagNode,
    - header: htmlTagNode,
    - hgroup: htmlTagNode,
    - iframe: htmlTagNode,
    - keygen: htmlTagNode,
    - legend: htmlTagNode,
    - object: htmlTagNode,
    - option: htmlTagNode,
    - output: htmlTagNode,
    - script: htmlTagNode,
    - select: htmlTagNode,
    - source: htmlTagNode,
    - strong: htmlTagNode,
    - aside: htmlTagNode,
    - embed: htmlTagNode,
    - input: htmlTagNode,
    - label: htmlTagNode,
    - meter: htmlTagNode,
    - param: htmlTagNode,
    - small: htmlTagNode,
    - table: htmlTagNode,
    - tbody: htmlTagNode,
    - tfoot: htmlTagNode,
    - thead: htmlTagNode,
    - track: htmlTagNode,
    - video: htmlTagNode,
    - abbr: htmlTagNode,
    - area: htmlTagNode,
    - base: htmlTagNode,
    - body: htmlTagNode,
    - code: htmlTagNode,
    - form: htmlTagNode,
    - head: htmlTagNode,
    - html: htmlTagNode,
    - link: htmlTagNode,
    - main: htmlTagNode,
    - mark: htmlTagNode,
    - menu: htmlTagNode,
    - meta: htmlTagNode,
    - ruby: htmlTagNode,
    - samp: htmlTagNode,
    - span: htmlTagNode,
    - time: htmlTagNode,
    - bdi: htmlTagNode,
    - bdo: htmlTagNode,
    - col: htmlTagNode,
    - del: htmlTagNode,
    - dfn: htmlTagNode,
    - div: htmlTagNode,
    - img: htmlTagNode,
    - ins: htmlTagNode,
    - kbd: htmlTagNode,
    - map: htmlTagNode,
    - nav: htmlTagNode,
    - pre: htmlTagNode,
    - rtc: htmlTagNode,
    - sub: htmlTagNode,
    - sup: htmlTagNode,
    - var: htmlTagNode,
    - wbr: htmlTagNode,
    - br: htmlTagNode,
    - dd: htmlTagNode,
    - dl: htmlTagNode,
    - dt: htmlTagNode,
    - em: htmlTagNode,
    - h1: htmlTagNode,
    - h2: htmlTagNode,
    - h3: htmlTagNode,
    - h4: htmlTagNode,
    - h5: htmlTagNode,
    - h6: htmlTagNode,
    - hr: htmlTagNode,
    - li: htmlTagNode,
    - ol: htmlTagNode,
    - rb: htmlTagNode,
    - rp: htmlTagNode,
    - rt: htmlTagNode,
    - td: htmlTagNode,
    - th: htmlTagNode,
    - tr: htmlTagNode,
    - ul: htmlTagNode,
    - a: htmlTagNode,
    - b: htmlTagNode,
    - i: htmlTagNode,
    - p: htmlTagNode,
    - q: htmlTagNode,
    - s: htmlTagNode,
    - u: htmlTagNode,
    - oncanplaythrough: htmlAttributeNode,
    - ondurationchange: htmlAttributeNode,
    - onloadedmetadata: htmlAttributeNode,
    - contenteditable: htmlAttributeNode,
    - "accept-charset": htmlAttributeNode,
    - onbeforeunload: htmlAttributeNode,
    - onvolumechange: htmlAttributeNode,
    - onbeforeprint: htmlAttributeNode,
    - oncontextmenu: htmlAttributeNode,
    - autocomplete: htmlAttributeNode,
    - onafterprint: htmlAttributeNode,
    - onhashchange: htmlAttributeNode,
    - onloadeddata: htmlAttributeNode,
    - onmousewheel: htmlAttributeNode,
    - onratechange: htmlAttributeNode,
    - ontimeupdate: htmlAttributeNode,
    - oncuechange: htmlAttributeNode,
    - ondragenter: htmlAttributeNode,
    - ondragleave: htmlAttributeNode,
    - ondragstart: htmlAttributeNode,
    - onloadstart: htmlAttributeNode,
    - onmousedown: htmlAttributeNode,
    - onmousemove: htmlAttributeNode,
    - onmouseover: htmlAttributeNode,
    - placeholder: htmlAttributeNode,
    - formaction: htmlAttributeNode,
    - "http-equiv": htmlAttributeNode,
    - novalidate: htmlAttributeNode,
    - ondblclick: htmlAttributeNode,
    - ondragover: htmlAttributeNode,
    - onkeypress: htmlAttributeNode,
    - onmouseout: htmlAttributeNode,
    - onpagehide: htmlAttributeNode,
    - onpageshow: htmlAttributeNode,
    - onpopstate: htmlAttributeNode,
    - onprogress: htmlAttributeNode,
    - spellcheck: htmlAttributeNode,
    - accesskey: htmlAttributeNode,
    - autofocus: htmlAttributeNode,
    - draggable: htmlAttributeNode,
    - maxlength: htmlAttributeNode,
    - oncanplay: htmlAttributeNode,
    - ondragend: htmlAttributeNode,
    - onemptied: htmlAttributeNode,
    - oninvalid: htmlAttributeNode,
    - onkeydown: htmlAttributeNode,
    - onmouseup: htmlAttributeNode,
    - onoffline: htmlAttributeNode,
    - onplaying: htmlAttributeNode,
    - onseeking: htmlAttributeNode,
    - onstalled: htmlAttributeNode,
    - onstorage: htmlAttributeNode,
    - onsuspend: htmlAttributeNode,
    - onwaiting: htmlAttributeNode,
    - translate: htmlAttributeNode,
    - autoplay: htmlAttributeNode,
    - controls: htmlAttributeNode,
    - datetime: htmlAttributeNode,
    - disabled: htmlAttributeNode,
    - download: htmlAttributeNode,
    - dropzone: htmlAttributeNode,
    - hreflang: htmlAttributeNode,
    - multiple: htmlAttributeNode,
    - onchange: htmlAttributeNode,
    - ononline: htmlAttributeNode,
    - onresize: htmlAttributeNode,
    - onscroll: htmlAttributeNode,
    - onsearch: htmlAttributeNode,
    - onseeked: htmlAttributeNode,
    - onselect: htmlAttributeNode,
    - onsubmit: htmlAttributeNode,
    - ontoggle: htmlAttributeNode,
    - onunload: htmlAttributeNode,
    - property: htmlAttributeNode,
    - readonly: htmlAttributeNode,
    - required: htmlAttributeNode,
    - reversed: htmlAttributeNode,
    - selected: htmlAttributeNode,
    - tabindex: htmlAttributeNode,
    - bgcolor: htmlAttributeNode,
    - charset: htmlAttributeNode,
    - checked: htmlAttributeNode,
    - colspan: htmlAttributeNode,
    - content: htmlAttributeNode,
    - default: htmlAttributeNode,
    - dirname: htmlAttributeNode,
    - enctype: htmlAttributeNode,
    - headers: htmlAttributeNode,
    - onabort: htmlAttributeNode,
    - onclick: htmlAttributeNode,
    - onended: htmlAttributeNode,
    - onerror: htmlAttributeNode,
    - onfocus: htmlAttributeNode,
    - oninput: htmlAttributeNode,
    - onkeyup: htmlAttributeNode,
    - onpaste: htmlAttributeNode,
    - onpause: htmlAttributeNode,
    - onreset: htmlAttributeNode,
    - onwheel: htmlAttributeNode,
    - optimum: htmlAttributeNode,
    - pattern: htmlAttributeNode,
    - preload: htmlAttributeNode,
    - rowspan: htmlAttributeNode,
    - sandbox: htmlAttributeNode,
    - srclang: htmlAttributeNode,
    - accept: htmlAttributeNode,
    - action: htmlAttributeNode,
    - border: htmlAttributeNode,
    - coords: htmlAttributeNode,
    - height: htmlAttributeNode,
    - hidden: htmlAttributeNode,
    - method: htmlAttributeNode,
    - onblur: htmlAttributeNode,
    - oncopy: htmlAttributeNode,
    - ondrag: htmlAttributeNode,
    - ondrop: htmlAttributeNode,
    - onload: htmlAttributeNode,
    - onplay: htmlAttributeNode,
    - poster: htmlAttributeNode,
    - srcdoc: htmlAttributeNode,
    - srcset: htmlAttributeNode,
    - target: htmlAttributeNode,
    - usemap: htmlAttributeNode,
    - align: htmlAttributeNode,
    - async: htmlAttributeNode,
    - class: htmlAttributeNode,
    - color: htmlAttributeNode,
    - defer: htmlAttributeNode,
    - ismap: htmlAttributeNode,
    - media: htmlAttributeNode,
    - muted: htmlAttributeNode,
    - oncut: htmlAttributeNode,
    - scope: htmlAttributeNode,
    - shape: htmlAttributeNode,
    - sizes: htmlAttributeNode,
    - start: htmlAttributeNode,
    - style: htmlAttributeNode,
    - title: htmlAttributeNode,
    - value: htmlAttributeNode,
    - width: htmlAttributeNode,
    - cols: htmlAttributeNode,
    - high: htmlAttributeNode,
    - href: htmlAttributeNode,
    - kind: htmlAttributeNode,
    - lang: htmlAttributeNode,
    - list: htmlAttributeNode,
    - loop: htmlAttributeNode,
    - name: htmlAttributeNode,
    - open: htmlAttributeNode,
    - rows: htmlAttributeNode,
    - size: htmlAttributeNode,
    - step: htmlAttributeNode,
    - type: htmlAttributeNode,
    - wrap: htmlAttributeNode,
    - alt: htmlAttributeNode,
    - dir: htmlAttributeNode,
    - for: htmlAttributeNode,
    - low: htmlAttributeNode,
    - max: htmlAttributeNode,
    - min: htmlAttributeNode,
    - rel: htmlAttributeNode,
    - src: htmlAttributeNode,
    - id: htmlAttributeNode,
    - lineShiftClickCommand: stumpExtendedAttributeNode,
    - contextMenuCommand: stumpExtendedAttributeNode,
    - doubleClickCommand: stumpExtendedAttributeNode,
    - shiftClickCommand: stumpExtendedAttributeNode,
    - lineClickCommand: stumpExtendedAttributeNode,
    - changeCommand: stumpExtendedAttributeNode,
    - clickCommand: stumpExtendedAttributeNode,
    - keyUpCommand: stumpExtendedAttributeNode,
    - blurCommand: stumpExtendedAttributeNode,
    - collapse: stumpExtendedAttributeNode,
    - bern: bernNode
    + Object.assign(Object.assign({}, super.createParserCombinator()._getFirstWordMapAsObject()), {
    + blockquote: htmlTagParser,
    + colgroup: htmlTagParser,
    + datalist: htmlTagParser,
    + fieldset: htmlTagParser,
    + menuitem: htmlTagParser,
    + noscript: htmlTagParser,
    + optgroup: htmlTagParser,
    + progress: htmlTagParser,
    + styleTag: htmlTagParser,
    + template: htmlTagParser,
    + textarea: htmlTagParser,
    + titleTag: htmlTagParser,
    + address: htmlTagParser,
    + article: htmlTagParser,
    + caption: htmlTagParser,
    + details: htmlTagParser,
    + section: htmlTagParser,
    + summary: htmlTagParser,
    + button: htmlTagParser,
    + canvas: htmlTagParser,
    + dialog: htmlTagParser,
    + figure: htmlTagParser,
    + footer: htmlTagParser,
    + header: htmlTagParser,
    + hgroup: htmlTagParser,
    + iframe: htmlTagParser,
    + keygen: htmlTagParser,
    + legend: htmlTagParser,
    + object: htmlTagParser,
    + option: htmlTagParser,
    + output: htmlTagParser,
    + script: htmlTagParser,
    + select: htmlTagParser,
    + source: htmlTagParser,
    + strong: htmlTagParser,
    + aside: htmlTagParser,
    + embed: htmlTagParser,
    + input: htmlTagParser,
    + label: htmlTagParser,
    + meter: htmlTagParser,
    + param: htmlTagParser,
    + small: htmlTagParser,
    + table: htmlTagParser,
    + tbody: htmlTagParser,
    + tfoot: htmlTagParser,
    + thead: htmlTagParser,
    + track: htmlTagParser,
    + video: htmlTagParser,
    + abbr: htmlTagParser,
    + area: htmlTagParser,
    + base: htmlTagParser,
    + body: htmlTagParser,
    + code: htmlTagParser,
    + form: htmlTagParser,
    + head: htmlTagParser,
    + html: htmlTagParser,
    + link: htmlTagParser,
    + main: htmlTagParser,
    + mark: htmlTagParser,
    + menu: htmlTagParser,
    + meta: htmlTagParser,
    + ruby: htmlTagParser,
    + samp: htmlTagParser,
    + span: htmlTagParser,
    + time: htmlTagParser,
    + bdi: htmlTagParser,
    + bdo: htmlTagParser,
    + col: htmlTagParser,
    + del: htmlTagParser,
    + dfn: htmlTagParser,
    + div: htmlTagParser,
    + img: htmlTagParser,
    + ins: htmlTagParser,
    + kbd: htmlTagParser,
    + map: htmlTagParser,
    + nav: htmlTagParser,
    + pre: htmlTagParser,
    + rtc: htmlTagParser,
    + sub: htmlTagParser,
    + sup: htmlTagParser,
    + var: htmlTagParser,
    + wbr: htmlTagParser,
    + br: htmlTagParser,
    + dd: htmlTagParser,
    + dl: htmlTagParser,
    + dt: htmlTagParser,
    + em: htmlTagParser,
    + h1: htmlTagParser,
    + h2: htmlTagParser,
    + h3: htmlTagParser,
    + h4: htmlTagParser,
    + h5: htmlTagParser,
    + h6: htmlTagParser,
    + hr: htmlTagParser,
    + li: htmlTagParser,
    + ol: htmlTagParser,
    + rb: htmlTagParser,
    + rp: htmlTagParser,
    + rt: htmlTagParser,
    + td: htmlTagParser,
    + th: htmlTagParser,
    + tr: htmlTagParser,
    + ul: htmlTagParser,
    + a: htmlTagParser,
    + b: htmlTagParser,
    + i: htmlTagParser,
    + p: htmlTagParser,
    + q: htmlTagParser,
    + s: htmlTagParser,
    + u: htmlTagParser,
    + oncanplaythrough: htmlAttributeParser,
    + ondurationchange: htmlAttributeParser,
    + onloadedmetadata: htmlAttributeParser,
    + contenteditable: htmlAttributeParser,
    + "accept-charset": htmlAttributeParser,
    + onbeforeunload: htmlAttributeParser,
    + onvolumechange: htmlAttributeParser,
    + onbeforeprint: htmlAttributeParser,
    + oncontextmenu: htmlAttributeParser,
    + autocomplete: htmlAttributeParser,
    + onafterprint: htmlAttributeParser,
    + onhashchange: htmlAttributeParser,
    + onloadeddata: htmlAttributeParser,
    + onmousewheel: htmlAttributeParser,
    + onratechange: htmlAttributeParser,
    + ontimeupdate: htmlAttributeParser,
    + oncuechange: htmlAttributeParser,
    + ondragenter: htmlAttributeParser,
    + ondragleave: htmlAttributeParser,
    + ondragstart: htmlAttributeParser,
    + onloadstart: htmlAttributeParser,
    + onmousedown: htmlAttributeParser,
    + onmousemove: htmlAttributeParser,
    + onmouseover: htmlAttributeParser,
    + placeholder: htmlAttributeParser,
    + formaction: htmlAttributeParser,
    + "http-equiv": htmlAttributeParser,
    + novalidate: htmlAttributeParser,
    + ondblclick: htmlAttributeParser,
    + ondragover: htmlAttributeParser,
    + onkeypress: htmlAttributeParser,
    + onmouseout: htmlAttributeParser,
    + onpagehide: htmlAttributeParser,
    + onpageshow: htmlAttributeParser,
    + onpopstate: htmlAttributeParser,
    + onprogress: htmlAttributeParser,
    + spellcheck: htmlAttributeParser,
    + accesskey: htmlAttributeParser,
    + autofocus: htmlAttributeParser,
    + draggable: htmlAttributeParser,
    + maxlength: htmlAttributeParser,
    + oncanplay: htmlAttributeParser,
    + ondragend: htmlAttributeParser,
    + onemptied: htmlAttributeParser,
    + oninvalid: htmlAttributeParser,
    + onkeydown: htmlAttributeParser,
    + onmouseup: htmlAttributeParser,
    + onoffline: htmlAttributeParser,
    + onplaying: htmlAttributeParser,
    + onseeking: htmlAttributeParser,
    + onstalled: htmlAttributeParser,
    + onstorage: htmlAttributeParser,
    + onsuspend: htmlAttributeParser,
    + onwaiting: htmlAttributeParser,
    + translate: htmlAttributeParser,
    + autoplay: htmlAttributeParser,
    + controls: htmlAttributeParser,
    + datetime: htmlAttributeParser,
    + disabled: htmlAttributeParser,
    + download: htmlAttributeParser,
    + dropzone: htmlAttributeParser,
    + hreflang: htmlAttributeParser,
    + multiple: htmlAttributeParser,
    + onchange: htmlAttributeParser,
    + ononline: htmlAttributeParser,
    + onresize: htmlAttributeParser,
    + onscroll: htmlAttributeParser,
    + onsearch: htmlAttributeParser,
    + onseeked: htmlAttributeParser,
    + onselect: htmlAttributeParser,
    + onsubmit: htmlAttributeParser,
    + ontoggle: htmlAttributeParser,
    + onunload: htmlAttributeParser,
    + property: htmlAttributeParser,
    + readonly: htmlAttributeParser,
    + required: htmlAttributeParser,
    + reversed: htmlAttributeParser,
    + selected: htmlAttributeParser,
    + tabindex: htmlAttributeParser,
    + bgcolor: htmlAttributeParser,
    + charset: htmlAttributeParser,
    + checked: htmlAttributeParser,
    + colspan: htmlAttributeParser,
    + content: htmlAttributeParser,
    + default: htmlAttributeParser,
    + dirname: htmlAttributeParser,
    + enctype: htmlAttributeParser,
    + headers: htmlAttributeParser,
    + onabort: htmlAttributeParser,
    + onclick: htmlAttributeParser,
    + onended: htmlAttributeParser,
    + onerror: htmlAttributeParser,
    + onfocus: htmlAttributeParser,
    + oninput: htmlAttributeParser,
    + onkeyup: htmlAttributeParser,
    + onpaste: htmlAttributeParser,
    + onpause: htmlAttributeParser,
    + onreset: htmlAttributeParser,
    + onwheel: htmlAttributeParser,
    + optimum: htmlAttributeParser,
    + pattern: htmlAttributeParser,
    + preload: htmlAttributeParser,
    + rowspan: htmlAttributeParser,
    + sandbox: htmlAttributeParser,
    + srclang: htmlAttributeParser,
    + accept: htmlAttributeParser,
    + action: htmlAttributeParser,
    + border: htmlAttributeParser,
    + coords: htmlAttributeParser,
    + height: htmlAttributeParser,
    + hidden: htmlAttributeParser,
    + method: htmlAttributeParser,
    + onblur: htmlAttributeParser,
    + oncopy: htmlAttributeParser,
    + ondrag: htmlAttributeParser,
    + ondrop: htmlAttributeParser,
    + onload: htmlAttributeParser,
    + onplay: htmlAttributeParser,
    + poster: htmlAttributeParser,
    + srcdoc: htmlAttributeParser,
    + srcset: htmlAttributeParser,
    + target: htmlAttributeParser,
    + usemap: htmlAttributeParser,
    + align: htmlAttributeParser,
    + async: htmlAttributeParser,
    + class: htmlAttributeParser,
    + color: htmlAttributeParser,
    + defer: htmlAttributeParser,
    + ismap: htmlAttributeParser,
    + media: htmlAttributeParser,
    + muted: htmlAttributeParser,
    + oncut: htmlAttributeParser,
    + scope: htmlAttributeParser,
    + shape: htmlAttributeParser,
    + sizes: htmlAttributeParser,
    + start: htmlAttributeParser,
    + style: htmlAttributeParser,
    + title: htmlAttributeParser,
    + value: htmlAttributeParser,
    + width: htmlAttributeParser,
    + cols: htmlAttributeParser,
    + high: htmlAttributeParser,
    + href: htmlAttributeParser,
    + kind: htmlAttributeParser,
    + lang: htmlAttributeParser,
    + list: htmlAttributeParser,
    + loop: htmlAttributeParser,
    + name: htmlAttributeParser,
    + open: htmlAttributeParser,
    + rows: htmlAttributeParser,
    + size: htmlAttributeParser,
    + step: htmlAttributeParser,
    + type: htmlAttributeParser,
    + wrap: htmlAttributeParser,
    + alt: htmlAttributeParser,
    + dir: htmlAttributeParser,
    + for: htmlAttributeParser,
    + low: htmlAttributeParser,
    + max: htmlAttributeParser,
    + min: htmlAttributeParser,
    + rel: htmlAttributeParser,
    + src: htmlAttributeParser,
    + id: htmlAttributeParser,
    + lineShiftClickCommand: stumpExtendedAttributeParser,
    + contextMenuCommand: stumpExtendedAttributeParser,
    + doubleClickCommand: stumpExtendedAttributeParser,
    + shiftClickCommand: stumpExtendedAttributeParser,
    + lineClickCommand: stumpExtendedAttributeParser,
    + changeCommand: stumpExtendedAttributeParser,
    + clickCommand: stumpExtendedAttributeParser,
    + keyUpCommand: stumpExtendedAttributeParser,
    + blurCommand: stumpExtendedAttributeParser,
    + collapse: stumpExtendedAttributeParser,
    + bern: bernParser,
    - [{ regex: /^$/, nodeConstructor: blankLineNode }, { regex: /^[a-zA-Z0-9_]+Component/, nodeConstructor: componentDefinitionNode }]
    + [
    + { regex: /^$/, parser: blankLineParser },
    + { regex: /^[a-zA-Z0-9_]+Component/, parser: componentDefinitionParser },
    + ]
    Changed around line 17284: bernNode
    - isHtmlTagNode = true
    + isHtmlTagParser = true
    - const firstWord = this.getFirstWord()
    + const firstWord = this.firstWord
    - styleTag: "style"
    + styleTag: "style",
    - toHtmlWithSuids() {
    + asHtmlWithSuids() {
    Changed around line 17313: bernNode
    - this.filter(node => node.isAttributeNode).forEach(child => elem.setAttribute(child.getFirstWord(), child.getContent()))
    + this.filter((node) => node.isAttributeParser).forEach((child) => elem.setAttribute(child.firstWord, child.content))
    - this.filter(node => node.isHtmlTagNode).forEach(child => elem.appendChild(child.domElement))
    + this.filter((node) => node.isHtmlTagParser).forEach((child) => elem.appendChild(child.domElement))
    - const children = this.map(child => child._toHtml(indentCount + 1, withSuid)).join("")
    - const attributesStr = this.filter(node => node.isAttributeNode)
    - .map(child => child.getAttribute())
    + const children = this.map((child) => child._toHtml(indentCount + 1, withSuid)).join("")
    + const attributesStr = this.filter((node) => node.isAttributeParser)
    + .map((child) => child.getAttribute())
    - const indentForChildNodes = !collapse && this.getChildInstancesOfNodeTypeId("htmlTagNode").length > 0
    + const indentForChildParsers = !collapse && this.getChildInstancesOfParserId("htmlTagParser").length > 0
    - return `${!collapse ? indent : ""}<${tag}${attributesStr}${suid}>${oneLiner}${indentForChildNodes ? "\n" : ""}${children}${collapse ? "" : "\n"}`
    + return `${!collapse ? indent : ""}<${tag}${attributesStr}${suid}>${oneLiner}${indentForChildParsers ? "\n" : ""}${children}${
    + collapse ? "" : "\n"
    + }`
    Changed around line 17341: bernNode
    - return this.getTopDownArray().find(node => node._getUid() === guid)
    + return this.topDownArray.find((node) => node._getUid() === guid)
    - const classNode = this.touchNode("class")
    - const words = classNode.getWordsFrom(1)
    + const classParser = this.touchNode("class")
    + const words = classParser.getWordsFrom(1)
    - classNode.setContent(words.join(this.getWordBreakSymbol()))
    + classParser.setContent(words.join(this.wordBreakSymbol))
    - const classNode = this.getNode("class")
    - if (!classNode) return this
    - const newClasses = classNode.getWords().filter(word => word !== className)
    - if (!newClasses.length) classNode.destroy()
    - else classNode.setContent(newClasses.join(" "))
    + const classParser = this.getNode("class")
    + if (!classParser) return this
    + const newClasses = classParser.words.filter((word) => word !== className)
    + if (!newClasses.length) classParser.destroy()
    + else classParser.setContent(newClasses.join(" "))
    - const classNode = this.getNode("class")
    - return classNode && classNode.getWords().includes(className) ? true : false
    + const classParser = this.getNode("class")
    + return classParser && classParser.words.includes(className) ? true : false
    Changed around line 17381: bernNode
    - const singleNode = new jtree.TreeNode(text).getChildren()[0]
    + const singleNode = new TreeNode(text).getChildren()[0]
    - const stumpNodeIndex = this.filter(node => node.isHtmlTagNode).indexOf(newNode)
    - this.getShadow().insertHtmlNode(newNode, stumpNodeIndex)
    + const stumpParserIndex = this.filter((node) => node.isHtmlTagParser).indexOf(newNode)
    + this.getShadow().insertHtmlNode(newNode, stumpParserIndex)
    Changed around line 17394: bernNode
    - return this.getTopDownArray().find(node =>
    + return this.topDownArray.find((node) =>
    - .map(child => child.getLine())
    + .map((child) => child.getLine())
    Changed around line 17405: bernNode
    - return this.getTopDownArray().filter(node => node.doesExtend("htmlTagNode") && node.getFirstWord() === firstWord)
    + return this.topDownArray.filter((node) => node.doesExtend("htmlTagParser") && node.firstWord === firstWord)
    - return this.getChildren().some(node => node.getLine() === line)
    + return this.getChildren().some((node) => node.getLine() === line)
    - return this.getTopDownArray().filter(node => node.doesExtend("htmlTagNode") && node.hasLine(line))
    + return this.topDownArray.filter((node) => node.doesExtend("htmlTagParser") && node.hasLine(line))
    - return this.getTopDownArray().filter(
    - node =>
    - node.doesExtend("htmlTagNode") &&
    - node.has("class") &&
    - node
    - .getNode("class")
    - .getWords()
    - .includes(className)
    - )
    + return this.topDownArray.filter((node) => node.doesExtend("htmlTagParser") && node.has("class") && node.getNode("class").words.includes(className))
    - return this.getParent().getShadowClass()
    + return this.parent.getShadowClass()
    - return this._treeComponent || this.getParent().getStumpNodeTreeComponent()
    + return this._treeComponent || this.parent.getStumpNodeTreeComponent()
    Changed around line 17438: bernNode
    - toHtml() {
    + get asHtml() {
    - class errorNode extends jtree.GrammarBackedNode {
    + class errorParser extends GrammarBackedNode {
    - return this._getErrorNodeErrors()
    + return this._getErrorParserErrors()
    - class componentDefinitionNode extends htmlTagNode {
    + class componentDefinitionParser extends htmlTagParser {
    Changed around line 17458: bernNode
    - class htmlAttributeNode extends jtree.GrammarBackedNode {
    - createParser() {
    - return new jtree.TreeNode.Parser(errorNode, undefined, undefined)
    + class htmlAttributeParser extends GrammarBackedNode {
    + createParserCombinator() {
    + return new TreeNode.ParserCombinator(errorParser, undefined, undefined)
    Changed around line 17471: bernNode
    - get isAttributeNode() {
    + get isAttributeParser() {
    Changed around line 17481: bernNode
    - return ` ${this.getFirstWord()}="${this.getContent()}"`
    + return ` ${this.firstWord}="${this.content}"`
    - class stumpExtendedAttributeNode extends htmlAttributeNode {
    + class stumpExtendedAttributeParser extends htmlAttributeParser {
    - class lineOfHtmlContentNode extends jtree.GrammarBackedNode {
    - createParser() {
    - return new jtree.TreeNode.Parser(lineOfHtmlContentNode, undefined, undefined)
    + class lineOfHtmlContentParser extends GrammarBackedNode {
    + createParserCombinator() {
    + return new TreeNode.ParserCombinator(lineOfHtmlContentParser, undefined, undefined)
    Changed around line 17506: bernNode
    - class bernNode extends jtree.GrammarBackedNode {
    - createParser() {
    - return new jtree.TreeNode.Parser(lineOfHtmlContentNode, undefined, undefined)
    + class bernParser extends GrammarBackedNode {
    + createParserCombinator() {
    + return new TreeNode.ParserCombinator(lineOfHtmlContentParser, undefined, undefined)
    Changed around line 17524: bernNode
    - window.stumpNode = stumpNode
    + window.stumpParser = stumpParser
    - class hakonNode extends jtree.GrammarBackedNode {
    - createParser() {
    - return new jtree.TreeNode.Parser(
    - selectorNode,
    - Object.assign(Object.assign({}, super.createParser()._getFirstWordMapAsObject()), { comment: commentNode }),
    + class hakonParser extends GrammarBackedNode {
    + createParserCombinator() {
    + return new TreeNode.ParserCombinator(
    + selectorParser,
    + Object.assign(Object.assign({}, super.createParserCombinator()._getFirstWordMapAsObject()), { comment: commentParser }),
    Changed around line 17541: bernNode
    - return this.getTopDownArray()
    - .filter(node => node.isSelectorNode)
    - .map(child => child.compile())
    + return this.topDownArray
    + .filter((node) => node.isSelectorParser)
    + .map((child) => child.compile())
    - static cachedHandGrammarProgramRoot = new jtree.HandGrammarProgram(`tooling onsave jtree build produceLang hakon
    + static cachedHandGrammarProgramRoot = new HandGrammarProgram(`// Cell Parsers
    Changed around line 17560: cssValueCell
    - todo add html tags, css and ids selector regexes, etc
    + // todo add html tags, css and ids selector regexes, etc
    Changed around line 17568: vendorPrefixPropertyKeywordCell
    - todo Where are these coming from? Can we add a url link
    + // todo Where are these coming from? Can we add a url link
    - hakonNode
    +
    + // Line Parsers
    + hakonParser
    - todo Add variables?
    + // todo Add variables?
    - inScope commentNode
    - catchAllNodeType selectorNode
    + inScope commentParser
    + catchAllParser selectorParser
    - return this.getTopDownArray()
    - .filter(node => node.isSelectorNode)
    + return this.topDownArray
    + .filter(node => node.isSelectorParser)
    Changed around line 17602: hakonNode
    - propertyNode
    + propertyParser
    - catchAllNodeType errorNode
    + catchAllParser errorParser
    - return \`\${spaces}\${this.getFirstWord()}: \${this.getContent()};\`
    + return \`\${spaces}\${this.firstWord}: \${this.content};\`
    - variableNode
    - extends propertyNode
    + variableParser
    + extends propertyParser
    - browserPrefixPropertyNode
    - extends propertyNode
    + browserPrefixPropertyParser
    + extends propertyParser
    - errorNode
    - catchAllNodeType errorNode
    + errorParser
    + catchAllParser errorParser
    - baseNodeType errorNode
    - commentNode
    + baseParser errorParser
    + commentParser
    - catchAllNodeType commentNode
    - selectorNode
    - inScope propertyNode variableNode commentNode
    - catchAllNodeType selectorNode
    - boolean isSelectorNode true
    + catchAllParser commentParser
    + selectorParser
    + inScope propertyParser variableParser commentParser
    + catchAllParser selectorParser
    + boolean isSelectorParser true
    - const parentSelector = this.getParent().getSelector()
    - return this.getFirstWord()
    + const parentSelector = this.parent.getSelector()
    + return this.firstWord
    Changed around line 17641: selectorNode
    - const propertyNodes = this.getChildren().filter(node => node.doesExtend("propertyNode"))
    - if (!propertyNodes.length) return ""
    + const propertyParsers = this.getChildren().filter(node => node.doesExtend("propertyParser"))
    + if (!propertyParsers.length) return ""
    - \${propertyNodes.map(child => child.compile(spaces)).join("\\n")}
    + \${propertyParsers.map(child => child.compile(spaces)).join("\\n")}
    - getHandGrammarProgram() {
    + get handGrammarProgram() {
    - static getNodeTypeMap() {
    - return {
    - hakonNode: hakonNode,
    - propertyNode: propertyNode,
    - variableNode: variableNode,
    - browserPrefixPropertyNode: browserPrefixPropertyNode,
    - errorNode: errorNode,
    - commentNode: commentNode,
    - selectorNode: selectorNode
    - }
    - }
    + static rootParser = hakonParser
    - class propertyNode extends jtree.GrammarBackedNode {
    - createParser() {
    - return new jtree.TreeNode.Parser(errorNode, undefined, undefined)
    + class propertyParser extends GrammarBackedNode {
    + createParserCombinator() {
    + return new TreeNode.ParserCombinator(errorParser, undefined, undefined)
    Changed around line 17666: selectorNode
    - return `${spaces}${this.getFirstWord()}: ${this.getContent()};`
    + return `${spaces}${this.firstWord}: ${this.content};`
    - class variableNode extends propertyNode {}
    + class variableParser extends propertyParser {}
    - class browserPrefixPropertyNode extends propertyNode {
    + class browserPrefixPropertyParser extends propertyParser {
    - class errorNode extends jtree.GrammarBackedNode {
    - createParser() {
    - return new jtree.TreeNode.Parser(errorNode, undefined, undefined)
    + class errorParser extends GrammarBackedNode {
    + createParserCombinator() {
    + return new TreeNode.ParserCombinator(errorParser, undefined, undefined)
    - return this._getErrorNodeErrors()
    + return this._getErrorParserErrors()
    - class commentNode extends jtree.GrammarBackedNode {
    - createParser() {
    - return new jtree.TreeNode.Parser(commentNode, undefined, undefined)
    + class commentParser extends GrammarBackedNode {
    + createParserCombinator() {
    + return new TreeNode.ParserCombinator(commentParser, undefined, undefined)
    Changed around line 17702: selectorNode
    - class selectorNode extends jtree.GrammarBackedNode {
    - createParser() {
    - return new jtree.TreeNode.Parser(
    - selectorNode,
    - Object.assign(Object.assign({}, super.createParser()._getFirstWordMapAsObject()), {
    - "border-bottom-right-radius": propertyNode,
    - "transition-timing-function": propertyNode,
    - "animation-iteration-count": propertyNode,
    - "animation-timing-function": propertyNode,
    - "border-bottom-left-radius": propertyNode,
    - "border-top-right-radius": propertyNode,
    - "border-top-left-radius": propertyNode,
    - "background-attachment": propertyNode,
    - "background-blend-mode": propertyNode,
    - "text-decoration-color": propertyNode,
    - "text-decoration-style": propertyNode,
    - "overscroll-behavior-x": propertyNode,
    - "-webkit-touch-callout": propertyNode,
    - "grid-template-columns": propertyNode,
    - "animation-play-state": propertyNode,
    - "text-decoration-line": propertyNode,
    - "animation-direction": propertyNode,
    - "animation-fill-mode": propertyNode,
    - "backface-visibility": propertyNode,
    - "background-position": propertyNode,
    - "border-bottom-color": propertyNode,
    - "border-bottom-style": propertyNode,
    - "border-bottom-width": propertyNode,
    - "border-image-outset": propertyNode,
    - "border-image-repeat": propertyNode,
    - "border-image-source": propertyNode,
    - "hanging-punctuation": propertyNode,
    - "list-style-position": propertyNode,
    - "transition-duration": propertyNode,
    - "transition-property": propertyNode,
    - "-webkit-user-select": propertyNode,
    - "animation-duration": propertyNode,
    - "border-image-slice": propertyNode,
    - "border-image-width": propertyNode,
    - "border-right-color": propertyNode,
    - "border-right-style": propertyNode,
    - "border-right-width": propertyNode,
    - "perspective-origin": propertyNode,
    - "-khtml-user-select": propertyNode,
    - "grid-template-rows": propertyNode,
    - "background-origin": propertyNode,
    - "background-repeat": propertyNode,
    - "border-left-color": propertyNode,
    - "border-left-style": propertyNode,
    - "border-left-width": propertyNode,
    - "column-rule-color": propertyNode,
    - "column-rule-style": propertyNode,
    - "column-rule-width": propertyNode,
    - "counter-increment": propertyNode,
    - "page-break-before": propertyNode,
    - "page-break-inside": propertyNode,
    - "grid-column-start": propertyNode,
    - "background-color": propertyNode,
    - "background-image": propertyNode,
    - "border-top-color": propertyNode,
    - "border-top-style": propertyNode,
    - "border-top-width": propertyNode,
    - "font-size-adjust": propertyNode,
    - "list-style-image": propertyNode,
    - "page-break-after": propertyNode,
    - "transform-origin": propertyNode,
    - "transition-delay": propertyNode,
    - "-ms-touch-action": propertyNode,
    - "-moz-user-select": propertyNode,
    - "animation-delay": propertyNode,
    - "background-clip": propertyNode,
    - "background-size": propertyNode,
    - "border-collapse": propertyNode,
    - "justify-content": propertyNode,
    - "list-style-type": propertyNode,
    - "text-align-last": propertyNode,
    - "text-decoration": propertyNode,
    - "transform-style": propertyNode,
    - "-ms-user-select": propertyNode,
    - "grid-column-end": propertyNode,
    - "grid-column-gap": propertyNode,
    - "animation-name": propertyNode,
    - "border-spacing": propertyNode,
    - "flex-direction": propertyNode,
    - "letter-spacing": propertyNode,
    - "outline-offset": propertyNode,
    - "padding-bottom": propertyNode,
    - "text-transform": propertyNode,
    - "vertical-align": propertyNode,
    - "grid-auto-flow": propertyNode,
    - "grid-row-start": propertyNode,
    - "align-content": propertyNode,
    - "border-bottom": propertyNode,
    - "border-radius": propertyNode,
    - "counter-reset": propertyNode,
    - "margin-bottom": propertyNode,
    - "outline-color": propertyNode,
    - "outline-style": propertyNode,
    - "outline-width": propertyNode,
    - "padding-right": propertyNode,
    - "text-overflow": propertyNode,
    - "justify-items": propertyNode,
    - "border-color": propertyNode,
    - "border-image": propertyNode,
    - "border-right": propertyNode,
    - "border-style": propertyNode,
    - "border-width": propertyNode,
    - "break-inside": propertyNode,
    - "caption-side": propertyNode,
    - "column-count": propertyNode,
    - "column-width": propertyNode,
    - "font-stretch": propertyNode,
    - "font-variant": propertyNode,
    - "margin-right": propertyNode,
    - "padding-left": propertyNode,
    - "table-layout": propertyNode,
    - "text-justify": propertyNode,
    - "unicode-bidi": propertyNode,
    - "word-spacing": propertyNode,
    - "touch-action": propertyNode,
    - "grid-row-end": propertyNode,
    - "grid-row-gap": propertyNode,
    - "justify-self": propertyNode,
    - "align-items": propertyNode,
    - "border-left": propertyNode,
    - "column-fill": propertyNode,
    - "column-rule": propertyNode,
    - "column-span": propertyNode,
    - "empty-cells": propertyNode,
    - "flex-shrink": propertyNode,
    - "font-family": propertyNode,
    - "font-weight": propertyNode,
    - "line-height": propertyNode,
    - "margin-left": propertyNode,
    - "padding-top": propertyNode,
    - perspective: propertyNode,
    - "text-indent": propertyNode,
    - "text-shadow": propertyNode,
    - "white-space": propertyNode,
    - "user-select": propertyNode,
    - "grid-column": propertyNode,
    - "align-self": propertyNode,
    - background: propertyNode,
    - "border-top": propertyNode,
    - "box-shadow": propertyNode,
    - "box-sizing": propertyNode,
    - "column-gap": propertyNode,
    - "flex-basis": propertyNode,
    - "@font-face": propertyNode,
    - "font-style": propertyNode,
    - "@keyframes": propertyNode,
    - "list-style": propertyNode,
    - "margin-top": propertyNode,
    - "max-height": propertyNode,
    - "min-height": propertyNode,
    - "overflow-x": propertyNode,
    - "overflow-y": propertyNode,
    - "text-align": propertyNode,
    - transition: propertyNode,
    - visibility: propertyNode,
    - "word-break": propertyNode,
    - animation: propertyNode,
    - direction: propertyNode,
    - "flex-flow": propertyNode,
    - "flex-grow": propertyNode,
    - "flex-wrap": propertyNode,
    - "font-size": propertyNode,
    - "max-width": propertyNode,
    - "min-width": propertyNode,
    - "nav-index": propertyNode,
    - "nav-right": propertyNode,
    - transform: propertyNode,
    - "word-wrap": propertyNode,
    - "nav-down": propertyNode,
    - "nav-left": propertyNode,
    - overflow: propertyNode,
    - position: propertyNode,
    - "tab-size": propertyNode,
    - "grid-gap": propertyNode,
    - "grid-row": propertyNode,
    - columns: propertyNode,
    - content: propertyNode,
    - display: propertyNode,
    - hyphens: propertyNode,
    - opacity: propertyNode,
    - outline: propertyNode,
    - padding: propertyNode,
    - "z-index": propertyNode,
    - border: propertyNode,
    - bottom: propertyNode,
    - cursor: propertyNode,
    - filter: propertyNode,
    - height: propertyNode,
    - margin: propertyNode,
    - "@media": propertyNode,
    - "nav-up": propertyNode,
    - quotes: propertyNode,
    - resize: propertyNode,
    - clear: propertyNode,
    - color: propertyNode,
    - float: propertyNode,
    - order: propertyNode,
    - right: propertyNode,
    - width: propertyNode,
    - clip: propertyNode,
    - fill: propertyNode,
    - flex: propertyNode,
    - font: propertyNode,
    - left: propertyNode,
    - all: propertyNode,
    - top: propertyNode,
    - gap: propertyNode,
    - "": propertyNode,
    - comment: commentNode
    + class selectorParser extends GrammarBackedNode {
    + createParserCombinator() {
    + return new TreeNode.ParserCombinator(
    + selectorParser,
    + Object.assign(Object.assign({}, super.createParserCombinator()._getFirstWordMapAsObject()), {
    + "border-bottom-right-radius": propertyParser,
    + "transition-timing-function": propertyParser,
    + "animation-iteration-count": propertyParser,
    + "animation-timing-function": propertyParser,
    + "border-bottom-left-radius": propertyParser,
    + "border-top-right-radius": propertyParser,
    + "border-top-left-radius": propertyParser,
    + "background-attachment": propertyParser,
    + "background-blend-mode": propertyParser,
    + "text-decoration-color": propertyParser,
    + "text-decoration-style": propertyParser,
    + "overscroll-behavior-x": propertyParser,
    + "-webkit-touch-callout": propertyParser,
    + "grid-template-columns": propertyParser,
    + "animation-play-state": propertyParser,
    + "text-decoration-line": propertyParser,
    + "animation-direction": propertyParser,
    + "animation-fill-mode": propertyParser,
    + "backface-visibility": propertyParser,
    + "background-position": propertyParser,
    + "border-bottom-color": propertyParser,
    + "border-bottom-style": propertyParser,
    + "border-bottom-width": propertyParser,
    + "border-image-outset": propertyParser,
    + "border-image-repeat": propertyParser,
    + "border-image-source": propertyParser,
    + "hanging-punctuation": propertyParser,
    + "list-style-position": propertyParser,
    + "transition-duration": propertyParser,
    + "transition-property": propertyParser,
    + "-webkit-user-select": propertyParser,
    + "animation-duration": propertyParser,
    + "border-image-slice": propertyParser,
    + "border-image-width": propertyParser,
    + "border-right-color": propertyParser,
    + "border-right-style": propertyParser,
    + "border-right-width": propertyParser,
    + "perspective-origin": propertyParser,
    + "-khtml-user-select": propertyParser,
    + "grid-template-rows": propertyParser,
    + "background-origin": propertyParser,
    + "background-repeat": propertyParser,
    + "border-left-color": propertyParser,
    + "border-left-style": propertyParser,
    + "border-left-width": propertyParser,
    + "column-rule-color": propertyParser,
    + "column-rule-style": propertyParser,
    + "column-rule-width": propertyParser,
    + "counter-increment": propertyParser,
    + "page-break-before": propertyParser,
    + "page-break-inside": propertyParser,
    + "grid-column-start": propertyParser,
    + "background-color": propertyParser,
    + "background-image": propertyParser,
    + "border-top-color": propertyParser,
    + "border-top-style": propertyParser,
    + "border-top-width": propertyParser,
    + "font-size-adjust": propertyParser,
    + "list-style-image": propertyParser,
    + "page-break-after": propertyParser,
    + "transform-origin": propertyParser,
    + "transition-delay": propertyParser,
    + "-ms-touch-action": propertyParser,
    + "-moz-user-select": propertyParser,
    + "animation-delay": propertyParser,
    + "background-clip": propertyParser,
    + "background-size": propertyParser,
    + "border-collapse": propertyParser,
    + "justify-content": propertyParser,
    + "list-style-type": propertyParser,
    + "text-align-last": propertyParser,
    + "text-decoration": propertyParser,
    + "transform-style": propertyParser,
    + "-ms-user-select": propertyParser,
    + "grid-column-end": propertyParser,
    + "grid-column-gap": propertyParser,
    + "animation-name": propertyParser,
    + "border-spacing": propertyParser,
    + "flex-direction": propertyParser,
    + "letter-spacing": propertyParser,
    + "outline-offset": propertyParser,
    + "padding-bottom": propertyParser,
    + "text-transform": propertyParser,
    + "vertical-align": propertyParser,
    + "grid-auto-flow": propertyParser,
    + "grid-row-start": propertyParser,
    + "align-content": propertyParser,
    + "border-bottom": propertyParser,
    + "border-radius": propertyParser,
    + "counter-reset": propertyParser,
    + "margin-bottom": propertyParser,
    + "outline-color": propertyParser,
    + "outline-style": propertyParser,
    + "outline-width": propertyParser,
    + "padding-right": propertyParser,
    + "text-overflow": propertyParser,
    + "justify-items": propertyParser,
    + "border-color": propertyParser,
    + "border-image": propertyParser,
    + "border-right": propertyParser,
    + "border-style": propertyParser,
    + "border-width": propertyParser,
    + "break-inside": propertyParser,
    + "caption-side": propertyParser,
    + "column-count": propertyParser,
    + "column-width": propertyParser,
    + "font-stretch": propertyParser,
    + "font-variant": propertyParser,
    + "margin-right": propertyParser,
    + "padding-left": propertyParser,
    + "table-layout": propertyParser,
    + "text-justify": propertyParser,
    + "unicode-bidi": propertyParser,
    + "word-spacing": propertyParser,
    + "touch-action": propertyParser,
    + "grid-row-end": propertyParser,
    + "grid-row-gap": propertyParser,
    + "justify-self": propertyParser,
    + "align-items": propertyParser,
    + "border-left": propertyParser,
    + "column-fill": propertyParser,
    + "column-rule": propertyParser,
    + "column-span": propertyParser,
    + "empty-cells": propertyParser,
    + "flex-shrink": propertyParser,
    + "font-family": propertyParser,
    + "font-weight": propertyParser,
    + "line-height": propertyParser,
    + "margin-left": propertyParser,
    + "padding-top": propertyParser,
    + perspective: propertyParser,
    + "text-indent": propertyParser,
    + "text-shadow": propertyParser,
    + "white-space": propertyParser,
    + "user-select": propertyParser,
    + "grid-column": propertyParser,
    + "align-self": propertyParser,
    + background: propertyParser,
    + "border-top": propertyParser,
    + "box-shadow": propertyParser,
    + "box-sizing": propertyParser,
    + "column-gap": propertyParser,
    + "flex-basis": propertyParser,
    + "@font-face": propertyParser,
    + "font-style": propertyParser,
    + "@keyframes": propertyParser,
    + "list-style": propertyParser,
    + "margin-top": propertyParser,
    + "max-height": propertyParser,
    + "min-height": propertyParser,
    + "overflow-x": propertyParser,
    + "overflow-y": propertyParser,
    + "text-align": propertyParser,
    + transition: propertyParser,
    + visibility: propertyParser,
    + "word-break": propertyParser,
    + animation: propertyParser,
    + direction: propertyParser,
    + "flex-flow": propertyParser,
    + "flex-grow": propertyParser,
    + "flex-wrap": propertyParser,
    + "font-size": propertyParser,
    + "max-width": propertyParser,
    + "min-width": propertyParser,
    + "nav-index": propertyParser,
    + "nav-right": propertyParser,
    + transform: propertyParser,
    + "word-wrap": propertyParser,
    + "nav-down": propertyParser,
    + "nav-left": propertyParser,
    + overflow: propertyParser,
    + position: propertyParser,
    + "tab-size": propertyParser,
    + "grid-gap": propertyParser,
    + "grid-row": propertyParser,
    + columns: propertyParser,
    + content: propertyParser,
    + display: propertyParser,
    + hyphens: propertyParser,
    + opacity: propertyParser,
    + outline: propertyParser,
    + padding: propertyParser,
    + "z-index": propertyParser,
    + border: propertyParser,
    + bottom: propertyParser,
    + cursor: propertyParser,
    + filter: propertyParser,
    + height: propertyParser,
    + margin: propertyParser,
    + "@media": propertyParser,
    + "nav-up": propertyParser,
    + quotes: propertyParser,
    + resize: propertyParser,
    + clear: propertyParser,
    + color: propertyParser,
    + float: propertyParser,
    + order: propertyParser,
    + right: propertyParser,
    + width: propertyParser,
    + clip: propertyParser,
    + fill: propertyParser,
    + flex: propertyParser,
    + font: propertyParser,
    + left: propertyParser,
    + all: propertyParser,
    + top: propertyParser,
    + gap: propertyParser,
    + "": propertyParser,
    + comment: commentParser,
    - [{ regex: /--/, nodeConstructor: variableNode }, { regex: /^\-\w.+/, nodeConstructor: browserPrefixPropertyNode }]
    + [
    + { regex: /--/, parser: variableParser },
    + { regex: /^\-\w.+/, parser: browserPrefixPropertyParser },
    + ]
    - get isSelectorNode() {
    + get isSelectorParser() {
    - const parentSelector = this.getParent().getSelector()
    - return this.getFirstWord()
    + const parentSelector = this.parent.getSelector()
    + return this.firstWord
    - .map(part => {
    + .map((part) => {
    - const propertyNodes = this.getChildren().filter(node => node.doesExtend("propertyNode"))
    - if (!propertyNodes.length) return ""
    + const propertyParsers = this.getChildren().filter((node) => node.doesExtend("propertyParser"))
    + if (!propertyParsers.length) return ""
    - ${propertyNodes.map(child => child.compile(spaces)).join("\n")}
    + ${propertyParsers.map((child) => child.compile(spaces)).join("\n")}
    - window.hakonNode = hakonNode
    + window.hakonParser = hakonParser
    Changed around line 18007: WillowConstants.checkedSelector = ":checked"
    - ;(function(CacheType) {
    + ;(function (CacheType) {
    Changed around line 18074: class AbstractWillowShadow {
    - return this.getShadowStumpNode()
    - .getParent()
    - .getShadow()
    + return this.getShadowStumpNode().parent.getShadow()
    Changed around line 18190: class WillowMousetrap {
    - class AbstractWillowBrowser extends stumpNode {
    + class AbstractWillowBrowser extends stumpParser {
    Changed around line 18294: class AbstractWillowBrowser extends stumpNode {
    - return jtree.Utils.getPathWithoutFileName(this._fullHtmlPageUrlIncludingProtocolAndFileName)
    + return Utils.getPathWithoutFileName(this._fullHtmlPageUrlIncludingProtocolAndFileName)
    Changed around line 18353: class AbstractWillowBrowser extends stumpNode {
    - const nodes = this.getTopDownArray()
    - const titleNode = nodes.find(node => node.getFirstWord() === WillowConstants.titleTag)
    - return titleNode ? titleNode.getContent() : ""
    + const nodes = this.topDownArray
    + const titleNode = nodes.find(node => node.firstWord === WillowConstants.titleTag)
    + return titleNode ? titleNode.content : ""
    - const nodes = this.getTopDownArray()
    - const headNode = nodes.find(node => node.getFirstWord() === WillowConstants.tags.head)
    + const nodes = this.topDownArray
    + const headNode = nodes.find(node => node.firstWord === WillowConstants.tags.head)
    Changed around line 18370: class AbstractWillowBrowser extends stumpNode {
    - return this.getHtmlStumpNode().toHtmlWithSuids()
    + return this.getHtmlStumpNode().asHtmlWithSuids()
    Changed around line 18535: class WillowBrowserShadow extends AbstractWillowShadow {
    - this.element.addEventListener(event, function(evt) {
    + this.element.addEventListener(event, function (evt) {
    Changed around line 18686: class RealWillowBrowser extends AbstractWillowBrowser {
    - return new Promise(function(resolve, reject) {
    + return new Promise(function (resolve, reject) {
    - scriptEl.onload = scriptEl.onreadystatechange = function() {
    + scriptEl.onload = scriptEl.onreadystatechange = function () {
    Changed around line 18773: class RealWillowBrowser extends AbstractWillowBrowser {
    - setTimeout(function() {
    + setTimeout(function () {
    Changed around line 18805: class RealWillowBrowser extends AbstractWillowBrowser {
    - bodyShadow.onShadowEvent(BrowserEvents.dragenter, function(event) {
    + bodyShadow.onShadowEvent(BrowserEvents.dragenter, function (event) {
    Changed around line 18848: class RealWillowBrowser extends AbstractWillowBrowser {
    - const hakonProgram = new hakonNode(str)
    + const hakonProgram = new hakonParser(str)
    - class AbstractTreeComponent extends jtree.GrammarBackedNode {
    + class AbstractTreeComponentParser extends GrammarBackedNode {
    Changed around line 18920: class AbstractTreeComponent extends jtree.GrammarBackedNode {
    - if (node.getFirstWord() === "styleTag" || (node.getContent() || "").startsWith("
    + if (node.firstWord === "styleTag" || (node.content || "").startsWith("
    - const clone = new jtree.TreeNode(this.willowBrowser.getHtmlStumpNode().toString())
    - clone.getTopDownArray().forEach(node => {
    - if (node.getFirstWord() === "styleTag" || (node.getContent() || "").startsWith("
    + const clone = new TreeNode(this.willowBrowser.getHtmlStumpNode().toString())
    + clone.topDownArray.forEach(node => {
    + if (node.firstWord === "styleTag" || (node.content || "").startsWith("
    Changed around line 18951: class AbstractTreeComponent extends jtree.GrammarBackedNode {
    - const parent = treeComponent.getParent()
    + const parent = treeComponent.parent
    Changed around line 18973: class AbstractTreeComponent extends jtree.GrammarBackedNode {
    - bodyShadow.onShadowEventWithSelector(BrowserEvents.contextmenu, `[${WillowConstants.contextMenuCommand}]`, function(target, evt) {
    + bodyShadow.onShadowEventWithSelector(BrowserEvents.contextmenu, `[${WillowConstants.contextMenuCommand}]`, function (target, evt) {
    - bodyShadow.onShadowEventWithSelector(BrowserEvents.click, `[${WillowConstants.clickCommand}]`, function(target, evt) {
    + bodyShadow.onShadowEventWithSelector(BrowserEvents.click, `[${WillowConstants.clickCommand}]`, function (target, evt) {
    - bodyShadow.onShadowEventWithSelector(BrowserEvents.dblclick, `[${WillowConstants.doubleClickCommand}]`, function(target, evt) {
    + bodyShadow.onShadowEventWithSelector(BrowserEvents.dblclick, `[${WillowConstants.doubleClickCommand}]`, function (target, evt) {
    - bodyShadow.onShadowEventWithSelector(BrowserEvents.blur, `[${WillowConstants.blurCommand}]`, function(target, evt) {
    + bodyShadow.onShadowEventWithSelector(BrowserEvents.blur, `[${WillowConstants.blurCommand}]`, function (target, evt) {
    - bodyShadow.onShadowEventWithSelector(BrowserEvents.keyup, `[${WillowConstants.keyUpCommand}]`, function(target, evt) {
    + bodyShadow.onShadowEventWithSelector(BrowserEvents.keyup, `[${WillowConstants.keyUpCommand}]`, function (target, evt) {
    - bodyShadow.onShadowEventWithSelector(BrowserEvents.change, `[${WillowConstants.changeCommand}]`, function(target, evt) {
    + bodyShadow.onShadowEventWithSelector(BrowserEvents.change, `[${WillowConstants.changeCommand}]`, function (target, evt) {
    Changed around line 19013: class AbstractTreeComponent extends jtree.GrammarBackedNode {
    - const app = this.getRootNode()
    + const app = this.root
    Changed around line 19029: class AbstractTreeComponent extends jtree.GrammarBackedNode {
    - if (!this.isRoot()) return this.getRootNode().getTheme()
    + if (!this.isRoot()) return this.root.getTheme()
    Changed around line 19044: class AbstractTreeComponent extends jtree.GrammarBackedNode {
    - if (!this._messageBuffer) this._messageBuffer = new jtree.TreeNode()
    + if (!this._messageBuffer) this._messageBuffer = new TreeNode()
    Changed around line 19058: class AbstractTreeComponent extends jtree.GrammarBackedNode {
    - bern${jtree.TreeNode.nest(errorMessage, 2)}`)
    + bern${TreeNode.nest(errorMessage, 2)}`)
    - bern${jtree.TreeNode.nest(message, 2)}`
    + bern${TreeNode.nest(message, 2)}`
    Changed around line 19086: class AbstractTreeComponent extends jtree.GrammarBackedNode {
    - return this._getJavascriptPrototypeChainUpTo("AbstractTreeComponent")
    + return this._getJavascriptPrototypeChainUpTo("AbstractTreeComponentParser")
    - AbstractTreeComponent._mountedTreeComponents++
    + AbstractTreeComponentParser._mountedTreeComponents++
    - AbstractTreeComponent._mountedTreeComponents--
    + AbstractTreeComponentParser._mountedTreeComponents--
    Changed around line 19105: class AbstractTreeComponent extends jtree.GrammarBackedNode {
    - return this.getChildrenByNodeConstructor(AbstractTreeComponent)
    + return this.getChildrenByParser(AbstractTreeComponentParser)
    Changed around line 19123: class AbstractTreeComponent extends jtree.GrammarBackedNode {
    - ${new stumpNode(this.toStumpCode()).compile()}
    + ${new stumpParser(this.toStumpCode()).compile()}
    Changed around line 19141: ${new stumpNode(this.toStumpCode()).compile()}
    - const stumpNodeToMountOn = this._htmlStumpNode.getParent()
    + const stumpNodeToMountOn = this._htmlStumpNode.parent
    Changed around line 19154: ${new stumpNode(this.toStumpCode()).compile()}
    - const currentContent = currentNode === undefined ? undefined : currentNode.getContent()
    + const currentContent = currentNode === undefined ? undefined : currentNode.content
    Changed around line 19166: ${new stumpNode(this.toStumpCode()).compile()}
    - this.getRootNode().renderAndGetRenderReport()
    + this.root.renderAndGetRenderReport()
    Changed around line 19213: ${new stumpNode(this.toStumpCode()).compile()}
    - return `div Loading ${this.getFirstWord()}...
    + return `div Loading ${this.firstWord}...
    Changed around line 19252: ${new stumpNode(this.toStumpCode()).compile()}
    - bern${jtree.TreeNode.nest(css, 2)}`)
    + bern${TreeNode.nest(css, 2)}`)
    - return this.getRootNode().willowBrowser.getHeadStumpNode()
    + return this.root.willowBrowser.getHeadStumpNode()
    Changed around line 19294: ${new stumpNode(this.toStumpCode()).compile()}
    - return new jtree.TreeNode(str)
    + return new TreeNode(str)
    - AbstractTreeComponent._mountedTreeComponents = 0
    - class TreeComponentFrameworkDebuggerComponent extends AbstractTreeComponent {
    + AbstractTreeComponentParser._mountedTreeComponents = 0
    + class TreeComponentFrameworkDebuggerComponent extends AbstractTreeComponentParser {
    Changed around line 19320: class TreeComponentFrameworkDebuggerComponent extends AbstractTreeComponent {
    - const app = this.getRootNode()
    + const app = this.root
    Changed around line 19330: class TreeComponentFrameworkDebuggerComponent extends AbstractTreeComponent {
    - p ${app.getNumberOfLines()} components loaded. ${WillowBrowser._stumpsOnPage} stumps on page.
    + p ${app.numberOfLines} components loaded. ${WillowBrowser._stumpsOnPage} stumps on page.
    - class AbstractGithubTriangleComponent extends AbstractTreeComponent {
    + class AbstractGithubTriangleComponent extends AbstractTreeComponentParser {
    Changed around line 19357: class AbstractGithubTriangleComponent extends AbstractTreeComponent {
    - window.AbstractTreeComponent = AbstractTreeComponent
    + window.AbstractTreeComponentParser = AbstractTreeComponentParser
    dist/simoji.js
    Changed around line 3: const yodash = {}
    +
    - const r1 = randomNumberGenerator()
    - const r2 = randomNumberGenerator()
    - if (r1 > 0.5) return r2 > 0.5 ? Directions.North : Directions.South
    - return r2 > 0.5 ? Directions.West : Directions.East
    + const r1 = randomNumberGenerator()
    + const r2 = randomNumberGenerator()
    + if (r1 > 0.5) return r2 > 0.5 ? Directions.North : Directions.South
    + return r2 > 0.5 ? Directions.West : Directions.East
    - let newAngle = ""
    - if (angle.includes(Directions.North)) newAngle += Directions.South
    - else if (angle.includes(Directions.South)) newAngle += Directions.North
    - if (angle.includes(Directions.East)) newAngle += Directions.West
    - else if (angle.includes(Directions.West)) newAngle += Directions.East
    - return newAngle
    + let newAngle = ""
    + if (angle.includes(Directions.North)) newAngle += Directions.South
    + else if (angle.includes(Directions.South)) newAngle += Directions.North
    + if (angle.includes(Directions.East)) newAngle += Directions.West
    + else if (angle.includes(Directions.West)) newAngle += Directions.East
    + return newAngle
    - if (operator === "=") return left == right
    - if (operator === "<") return left < right
    - if (operator === ">") return left > right
    - if (operator === "<=") return left <= right
    - if (operator === ">=") return left >= right
    + if (operator === "=") return left == right
    + if (operator === "<") return left < right
    + if (operator === ">") return left > right
    + if (operator === "<=") return left <= right
    + if (operator === ">=") return left >= right
    - return false
    + return false
    - const clone = program.clone()
    - clone.filter(node => node.getNodeTypeId() !== NodeTypes.agentDefinitionNode).forEach(node => node.destroy())
    - clone.agentKeywordMap = {}
    - clone.agentTypes.forEach((node, index) => (clone.agentKeywordMap[node.getWord(0)] = `simAgent${index}`))
    - const compiled = clone.compile()
    - const agentMap = Object.keys(clone.agentKeywordMap)
    - .map(key => `"${key}":${clone.agentKeywordMap[key]}`)
    - .join(",")
    - return `${compiled}
    + const clone = program.clone()
    + clone.filter(node => node.parserId !== ParserTypes.agentDefinitionParser).forEach(node => node.destroy())
    + clone.agentKeywordMap = {}
    + clone.agentTypes.forEach((node, index) => (clone.agentKeywordMap[node.firstWord] = `simAgent${index}`))
    + const compiled = clone.compile()
    + const agentMap = Object.keys(clone.agentKeywordMap)
    + .map(key => `"${key}":${clone.agentKeywordMap[key]}`)
    + .join(",")
    + return `${compiled}
    - const clone = program.clone()
    - // drop experiment nodes
    - clone.filter(node => node.getNodeTypeId() === NodeTypes.experimentNode).forEach(node => node.destroy())
    - // Append current experiment
    - if (experiment) clone.concat(experiment.childrenToString())
    - // Build symbol table
    - const symbolTable = {}
    - clone
    - .filter(node => node.getNodeTypeId() === NodeTypes.settingDefinitionNode)
    - .forEach(node => {
    - symbolTable[node.getWord(0)] = node.getContent()
    - node.destroy()
    - })
    - // Find and replace
    - let withVarsReplaced = clone.toString()
    - Object.keys(symbolTable).forEach(key => {
    - withVarsReplaced = withVarsReplaced.replaceAll(key, symbolTable[key])
    - })
    - return withVarsReplaced
    + const clone = program.clone()
    + // drop experiment nodes
    + clone.filter(node => node.parserId === ParserTypes.experimentParser).forEach(node => node.destroy())
    + // Append current experiment
    + if (experiment) clone.concat(experiment.childrenToString())
    + // Build symbol table
    + const symbolTable = {}
    + clone
    + .filter(node => node.parserId === ParserTypes.settingDefinitionParser)
    + .forEach(node => {
    + symbolTable[node.firstWord] = node.content
    + node.destroy()
    + })
    + // Find and replace
    + let withVarsReplaced = clone.toString()
    + Object.keys(symbolTable).forEach(key => {
    + withVarsReplaced = withVarsReplaced.replaceAll(key, symbolTable[key])
    + })
    + return withVarsReplaced
    - let closest = Infinity
    - let target
    - targets.forEach(candidate => {
    - const pos = candidate.position
    - const distance = math.distance([pos.down, pos.right], [position.down, position.right])
    - if (distance < closest) {
    - closest = distance
    - target = candidate
    - }
    - })
    - const heading = target.position
    - return yodash.angle(position.down, position.right, heading.down, heading.right)
    + let closest = Infinity
    + let target
    + targets.forEach(candidate => {
    + const pos = candidate.position
    + const distance = math.distance([pos.down, pos.right], [position.down, position.right])
    + if (distance < closest) {
    + closest = distance
    + target = candidate
    + }
    + })
    + const heading = target.position
    + return yodash.angle(position.down, position.right, heading.down, heading.right)
    - const dy = ey - cy
    - const dx = ex - cx
    - let theta = Math.atan2(dy, dx) // range (-PI, PI]
    - theta *= 180 / Math.PI // rads to degs, range (-180, 180]
    - //if (theta < 0) theta = 360 + theta; // range [0, 360)
    - let angle = ""
    -
    - if (Math.abs(theta) > 90) angle += Directions.North
    - else angle += Directions.South
    - if (theta < 0) angle += Directions.West
    - else angle += Directions.East
    - return angle
    + const dy = ey - cy
    + const dx = ex - cx
    + let theta = Math.atan2(dy, dx) // range (-PI, PI]
    + theta *= 180 / Math.PI // rads to degs, range (-180, 180]
    + //if (theta < 0) theta = 360 + theta; // range [0, 360)
    + let angle = ""
    +
    + if (Math.abs(theta) > 90) angle += Directions.North
    + else angle += Directions.South
    + if (theta < 0) angle += Directions.West
    + else angle += Directions.East
    + return angle
    - const maxRight = cols
    - const maxBottom = rows
    - const right = Math.round(randomNumberGenerator() * maxRight)
    - const down = Math.round(randomNumberGenerator() * maxBottom)
    - return { right, down }
    + const maxRight = cols
    + const maxBottom = rows
    + const right = Math.round(randomNumberGenerator() * maxRight)
    + const down = Math.round(randomNumberGenerator() * maxBottom)
    + return { right, down }
    - const { right, down } = yodash.getRandomLocation(rows, cols, randomNumberGenerator)
    - const hash = yodash.makePositionHash({ right, down })
    - if (occupiedSpots && occupiedSpots.has(hash))
    - return yodash.getRandomLocationHash(rows, cols, occupiedSpots, randomNumberGenerator)
    - return hash
    + const { right, down } = yodash.getRandomLocation(rows, cols, randomNumberGenerator)
    + const hash = yodash.makePositionHash({ right, down })
    + if (occupiedSpots && occupiedSpots.has(hash))
    + return yodash.getRandomLocationHash(rows, cols, occupiedSpots, randomNumberGenerator)
    + return hash
    - const board = []
    - while (rows >= 0) {
    - let col = cols
    - while (col >= 0) {
    - const hash = yodash.makePositionHash({ right: col, down: rows })
    - col--
    - if (occupiedSpots.has(hash)) continue
    - board.push(`${emoji} ${hash}`)
    - }
    - rows--
    - }
    - return board.join("\n")
    + const board = []
    + while (rows >= 0) {
    + let col = cols
    + while (col >= 0) {
    + const hash = yodash.makePositionHash({ right: col, down: rows })
    + col--
    + if (occupiedSpots.has(hash)) continue
    + board.push(`${emoji} ${hash}`)
    + }
    + rows--
    + }
    + return board.join("\n")
    - let { right, down } = position
    - const positions = []
    - down--
    - positions.push({ down, right })
    - right--
    - positions.push({ down, right })
    - right++
    - right++
    - positions.push({ down, right })
    - down++
    - positions.push({ down, right })
    - right--
    - right--
    - positions.push({ down, right })
    - down++
    - positions.push({ down, right })
    - right++
    - positions.push({ down, right })
    - right++
    - positions.push({ down, right })
    - return positions
    + let { right, down } = position
    + const positions = []
    + down--
    + positions.push({ down, right })
    + right--
    + positions.push({ down, right })
    + right++
    + right++
    + positions.push({ down, right })
    + down++
    + positions.push({ down, right })
    + right--
    + right--
    + positions.push({ down, right })
    + down++
    + positions.push({ down, right })
    + right++
    + positions.push({ down, right })
    + right++
    + positions.push({ down, right })
    + return positions
    - if (width < 1 || height < 1) {
    - return ""
    - }
    - const cells = []
    - let row = 0
    - while (row < height) {
    - let col = 0
    - while (col < width) {
    - const isPerimeter = row === 0 || row === height - 1 || col === 0 || col === width - 1
    - if (isPerimeter)
    - cells.push(
    - `${character} ${yodash.makePositionHash({
    - down: startDown + row,
    - right: startRight + col
    - })}`
    - )
    - col++
    - }
    - row++
    - }
    - return cells.join("\n")
    + if (width < 1 || height < 1) {
    + return ""
    + }
    + const cells = []
    + let row = 0
    + while (row < height) {
    + let col = 0
    + while (col < width) {
    + const isPerimeter = row === 0 || row === height - 1 || col === 0 || col === width - 1
    + if (isPerimeter)
    + cells.push(
    + `${character} ${yodash.makePositionHash({
    + down: startDown + row,
    + right: startRight + col
    + })}`
    + )
    + col++
    + }
    + row++
    + }
    + return cells.join("\n")
    - return {
    - down: parseInt(words.find(word => word.includes("⬇️")).slice(0, -1)),
    - right: parseInt(words.find(word => word.includes("➡️")).slice(0, -1))
    - }
    + return {
    + down: parseInt(words.find(word => word.includes("⬇️")).slice(0, -1)),
    + right: parseInt(words.find(word => word.includes("➡️")).slice(0, -1))
    + }
    - const lines = str.split("\n")
    - const output = []
    - for (let index = 0; index < lines.length; index++) {
    - const words = lines[index].split(" ")
    - for (let wordIndex = 0; wordIndex < words.length; wordIndex++) {
    - const word = words[wordIndex]
    - if (word !== "") output.push(`${word} ${yodash.makePositionHash({ down: index, right: wordIndex })}`)
    - }
    - }
    - return output.join("\n")
    + const lines = str.split("\n")
    + const output = []
    + for (let index = 0; index < lines.length; index++) {
    + const words = lines[index].split(" ")
    + for (let wordIndex = 0; wordIndex < words.length; wordIndex++) {
    + const word = words[wordIndex]
    + if (word !== "") output.push(`${word} ${yodash.makePositionHash({ down: index, right: wordIndex })}`)
    + }
    + }
    + return output.join("\n")
    - new TreeNode(board).forEach(line => {
    - occupiedSpots.add(yodash.makePositionHash(yodash.parsePosition(line.getWords())))
    - })
    + new TreeNode(board).forEach(line => {
    + occupiedSpots.add(yodash.makePositionHash(yodash.parsePosition(line.words)))
    + })
    - const availablePositions = []
    - let down = rows
    - while (down >= rowStart) {
    - let right = cols
    - while (right >= colStart) {
    - const hash = yodash.makePositionHash({ right, down })
    - if (!occupiedSpots.has(hash)) availablePositions.push({ right, down, hash })
    - right--
    - }
    - down--
    - }
    - return availablePositions
    + const availablePositions = []
    + let down = rows
    + while (down >= rowStart) {
    + let right = cols
    + while (right >= colStart) {
    + const hash = yodash.makePositionHash({ right, down })
    + if (!occupiedSpots.has(hash)) availablePositions.push({ right, down, hash })
    + right--
    + }
    + down--
    + }
    + return availablePositions
    - randomNumberGenerator,
    - amount,
    - char,
    - rows,
    - cols,
    - occupiedSpots,
    - originRow,
    - originColumn
    + randomNumberGenerator,
    + amount,
    + char,
    + rows,
    + cols,
    + occupiedSpots,
    + originRow,
    + originColumn
    - const availableSpots = yodash.getAllAvailableSpots(rows, cols, occupiedSpots)
    - const spots = yodash.sampleFrom(availableSpots, amount * 10, randomNumberGenerator)
    - const origin = originColumn
    - ? { down: parseInt(originRow), right: parseInt(originColumn) }
    - : yodash.getRandomLocation(rows, cols, randomNumberGenerator)
    - const sortedByDistance = lodash.sortBy(spots, spot =>
    - math.distance([origin.down, origin.right], [spot.down, spot.right])
    - )
    -
    - return sortedByDistance
    - .slice(0, amount)
    - .map(spot => {
    - const { hash } = spot
    - occupiedSpots.add(hash)
    - return `${char} ${hash}`
    - })
    - .join("\n")
    + const availableSpots = yodash.getAllAvailableSpots(rows, cols, occupiedSpots)
    + const spots = yodash.sampleFrom(availableSpots, amount * 10, randomNumberGenerator)
    + const origin = originColumn
    + ? { down: parseInt(originRow), right: parseInt(originColumn) }
    + : yodash.getRandomLocation(rows, cols, randomNumberGenerator)
    + const sortedByDistance = lodash.sortBy(spots, spot =>
    + math.distance([origin.down, origin.right], [spot.down, spot.right])
    + )
    +
    + return sortedByDistance
    + .slice(0, amount)
    + .map(spot => {
    + const { hash } = spot
    + occupiedSpots.add(hash)
    + return `${char} ${hash}`
    + })
    + .join("\n")
    - const semiRand = Math.sin(seed++) * 10000
    - return semiRand - Math.floor(semiRand)
    + const semiRand = Math.sin(seed++) * 10000
    + return semiRand - Math.floor(semiRand)
    - shuffleArray(collection, randomNumberGenerator).slice(0, howMany)
    + shuffleArray(collection, randomNumberGenerator).slice(0, howMany)
    - const clonedArr = array.slice()
    - for (let index = clonedArr.length - 1; index > 0; index--) {
    - const replacerIndex = Math.floor(randomNumberGenerator() * (index + 1))
    - ;[clonedArr[index], clonedArr[replacerIndex]] = [clonedArr[replacerIndex], clonedArr[index]]
    - }
    - return clonedArr
    + const clonedArr = array.slice()
    + for (let index = clonedArr.length - 1; index > 0; index--) {
    + const replacerIndex = Math.floor(randomNumberGenerator() * (index + 1))
    + ;[clonedArr[index], clonedArr[replacerIndex]] = [clonedArr[replacerIndex], clonedArr[index]]
    + }
    + return clonedArr
    - const newTree = tree.clone()
    - const map = TreeUtils.arrayToMap(fields)
    - newTree.forEach(node => {
    - if (!map[node.getWord(0)]) node.destroy()
    - })
    + const newTree = tree.clone()
    + const map = Utils.arrayToMap(fields)
    + newTree.forEach(node => {
    + if (!map[node.firstWord]) node.destroy()
    + })
    - return newTree
    + return newTree
    - const newTree = new jtree.TreeNode()
    - tree.forEach(node => node.forEach(child => newTree.appendNode(child)))
    - return newTree
    + const newTree = new TreeNode()
    + tree.forEach(node => node.forEach(child => newTree.appendNode(child)))
    + return newTree
    Changed around line 292: window.yodash = yodash
    - class AbstractContextMenuComponent extends AbstractTreeComponent {
    + class AbstractContextMenuComponent extends AbstractTreeComponentParser {
    Changed around line 315: class AbstractContextMenuComponent extends AbstractTreeComponent {
    - return new jtree.TreeNode(`div
    + return new TreeNode(`div
    - const app = this.getRootNode()
    + const app = this.root
    Changed around line 344: class AbstractContextMenuComponent extends AbstractTreeComponent {
    - return this.getRootNode().getMouseEvent().clientX
    + return this.root.getMouseEvent().clientX
    Changed around line 379: window.AbstractContextMenuComponent = AbstractContextMenuComponent
    - class Agent extends jtree.TreeNode {
    + class Agent extends TreeNode {
    Changed around line 391: class Agent extends jtree.TreeNode {
    - if (!this.behaviors.length) return this.board.simojiProgram.getNode(this.getWord(0))
    - const behaviors = yodash.flatten(yodash.pick(this.board.simojiProgram, [this.getWord(0), ...this.behaviors]))
    + if (!this.behaviors.length) return this.board.simojiProgram.getNode(this.firstWord)
    + const behaviors = yodash.flatten(yodash.pick(this.board.simojiProgram, [this.firstWord, ...this.behaviors]))
    Changed around line 413: class Agent extends jtree.TreeNode {
    - const [emoji, operator, count] = conditionAndCommandsBlock.getWords()
    + const [emoji, operator, count] = conditionAndCommandsBlock.words
    Changed around line 431: class Agent extends jtree.TreeNode {
    - const targetId = target.getWord(0)
    + const targetId = target.firstWord
    Changed around line 447: class Agent extends jtree.TreeNode {
    - const targetId = target.getWord(0)
    + const targetId = target.firstWord
    Changed around line 459: class Agent extends jtree.TreeNode {
    - const commandName = instruction.getWord(0)
    + const commandName = instruction.firstWord
    Changed around line 507: class Agent extends jtree.TreeNode {
    - this.getParent().appendLine(`${newObject} ${this.positionHash}`)
    + this.parent.appendLine(`${newObject} ${this.positionHash}`)
    Changed around line 557: class Agent extends jtree.TreeNode {
    - get root() {
    - return this.getRootNode()
    - }
    -
    Changed around line 567: class Agent extends jtree.TreeNode {
    - return this.getParent()
    + return this.parent
    Changed around line 593: class Agent extends jtree.TreeNode {
    - return yodash.parsePosition(this.getWords())
    + return yodash.parsePosition(this.words)
    Changed around line 601: class Agent extends jtree.TreeNode {
    - return this.getParent().gridSize
    + return this.parent.gridSize
    Changed around line 642: class Agent extends jtree.TreeNode {
    - return `top:${this.top * gridSize}px;left:${this.left *
    - gridSize}px;font-size:${gridSize}px;line-height: ${gridSize}px;${opacity};${this.style ?? ""}`
    + return `top:${this.top * gridSize}px;left:${
    + this.left * gridSize
    + }px;font-size:${gridSize}px;line-height: ${gridSize}px;${opacity};${this.style ?? ""}`
    Changed around line 680: class Agent extends jtree.TreeNode {
    - target.tickStack = new jtree.TreeNode(`1
    + target.tickStack = new TreeNode(`1
    Changed around line 713: class Agent extends jtree.TreeNode {
    - this.root.log(`${this.getWord(0)} ${command.getContent()}`)
    + this.root.log(`${this.firstWord} ${command.content}`)
    Changed around line 800: window.Agent = Agent
    - class AgentPaletteComponent extends AbstractTreeComponent {
    + class AgentPaletteComponent extends AbstractTreeComponentParser {
    - const root = this.getRootNode()
    + const root = this.root
    - .map(item => item.getWord(0))
    + .map(item => item.firstWord)
    Changed around line 818: ${items}`
    - return this.getRootNode().allAgentTypes.filter(item => !item.has("noPalette"))
    + return this.root.allAgentTypes.filter(item => !item.has("noPalette"))
    - this.getRootNode().changeAgentBrushCommand(x)
    + this.root.changeAgentBrushCommand(x)
    - return [this.getRootNode().board]
    + return [this.root.board]
    Changed around line 845: let nodeJsPrefix = ""
    - class BoardErrorNode extends AbstractTreeComponent {
    - _isErrorNodeType() {
    + class BoardErrorParser extends AbstractTreeComponentParser {
    + _isErrorParser() {
    Changed around line 856: class BoardErrorNode extends AbstractTreeComponent {
    - class leftStartPosition extends jtree.TreeNode {
    + class leftStartPosition extends TreeNode {
    - class BoardComponent extends AbstractTreeComponent {
    + class BoardComponent extends AbstractTreeComponentParser {
    - this._parser = new jtree.TreeNode.Parser(BoardErrorNode, {
    + this._parser = new TreeNode.ParserCombinator(BoardErrorParser, {
    Changed around line 907: class BoardComponent extends AbstractTreeComponent {
    - const csv = new TreeNode(this._populationCounts).toCsv()
    + const csv = new TreeNode(this._populationCounts).asCsv
    Changed around line 937: class BoardComponent extends AbstractTreeComponent {
    - .filter(node => node.doesExtend(NodeTypes.abstractInjectCommandNode))
    + .filter(node => node.doesExtend(ParserTypes.abstractInjectCommandParser))
    Changed around line 1003: class BoardComponent extends AbstractTreeComponent {
    - this.getRootNode().resetAllCommand()
    + this.root.resetAllCommand()
    Changed around line 1035: class BoardComponent extends AbstractTreeComponent {
    - return this.getParent()
    + return this.parent
    Changed around line 1046: class BoardComponent extends AbstractTreeComponent {
    - this[command.getNodeTypeId()](command)
    + this[command.parserId](command)
    - insertClusterNode(commandNode) {
    + insertClusterParser(commandNode) {
    Changed around line 1064: class BoardComponent extends AbstractTreeComponent {
    - insertAtNode(commandNode) {
    + insertAtParser(commandNode) {
    - rectangleDrawNode(commandNode) {
    - const newLines = yodash.makeRectangle(...yodash.parseInts(commandNode.getWords().slice(1), 1))
    + rectangleDrawParser(commandNode) {
    + const newLines = yodash.makeRectangle(...yodash.parseInts(commandNode.words.slice(1), 1))
    - pasteDrawNode(commandNode) {
    + pasteDrawParser(commandNode) {
    - fillNode(commandNode) {
    + fillParser(commandNode) {
    - drawNode(commandNode) {
    + drawParser(commandNode) {
    Changed around line 1103: class BoardComponent extends AbstractTreeComponent {
    - insertNode(commandNode) {
    + insertParser(commandNode) {
    Changed around line 1126: class BoardComponent extends AbstractTreeComponent {
    - this[instruction.getWord(0)](instruction)
    + this[instruction.firstWord](instruction)
    Changed around line 1136: class BoardComponent extends AbstractTreeComponent {
    - this[instruction.getWord(0)](instruction)
    + this[instruction.firstWord](instruction)
    Changed around line 1150: class BoardComponent extends AbstractTreeComponent {
    - return this.getTopDownArray().filter(node => node instanceof Agent)
    + return this.topDownArray.filter(node => node instanceof Agent)
    Changed around line 1242: class BoardComponent extends AbstractTreeComponent {
    - return this.root.mainExperiment.findNodes(Keywords.experiment)[this.boardIndex].getContent() ?? ""
    + return this.root.mainExperiment.findNodes(Keywords.experiment)[this.boardIndex].content ?? ""
    Changed around line 1289: class BoardComponent extends AbstractTreeComponent {
    - const message = command.getContent()
    + const message = command.content
    Changed around line 1307: class BoardComponent extends AbstractTreeComponent {
    - this.root.log(command.getContent())
    + this.root.log(command.content)
    - class BoardStyleComponent extends AbstractTreeComponent {
    - createParser() {
    - return new jtree.TreeNode.Parser(TreeNode)
    + class BoardStyleComponent extends AbstractTreeComponentParser {
    + createParserCombinator() {
    + return new TreeNode.ParserCombinator(TreeNode)
    Changed around line 1338: window.BoardComponent = BoardComponent
    - class BottomBarComponent extends AbstractTreeComponent {
    - createParser() {
    - return new jtree.TreeNode.Parser(undefined, {
    + class BottomBarComponent extends AbstractTreeComponentParser {
    + createParserCombinator() {
    + return new TreeNode.ParserCombinator(undefined, {
    Changed around line 1353: window.BottomBarComponent = BottomBarComponent
    - class EditorHandleComponent extends AbstractTreeComponent {
    + class EditorHandleComponent extends AbstractTreeComponentParser {
    - return this.getRootNode().editor.width
    + return this.root.editor.width
    - const root = this.getRootNode()
    + const root = this.root
    Changed around line 1390: class EditorHandleComponent extends AbstractTreeComponent {
    - return [this.getRootNode().editor]
    + return [this.root.editor]
    Changed around line 1399: window.EditorHandleComponent = EditorHandleComponent
    - const ExampleSims = new jtree.TreeNode()
    + const ExampleSims = new TreeNode()
    Changed around line 1412: window.ExampleSims = ExampleSims
    - const Categories = new jtree.TreeNode(`🦠 Epidemiology
    +
    + const Categories = new TreeNode(`🦠 Epidemiology
    Changed around line 1441: class ExampleMenuComponent extends AbstractContextMenuComponent {
    - const name = node.getFirstWord()
    + const name = node.firstWord
    - const properName = jtree.Utils.ucfirst(name)
    + const properName = Utils.ucfirst(name)
    Changed around line 1455: class ExampleMenuComponent extends AbstractContextMenuComponent {
    - const evt = this.getRootNode().getMouseEvent()
    + const evt = this.root.getMouseEvent()
    - class ExamplesComponent extends AbstractTreeComponent {
    + class ExamplesComponent extends AbstractTreeComponentParser {
    - const icon = category.getFirstWord()
    - const name = category.getContent()
    - const firstFile = category.nodeAt(0).getFirstWord()
    + const icon = category.firstWord
    + const name = category.content
    + const firstFile = category.nodeAt(0).firstWord
    Changed around line 1477: ${categories}`
    - const root = this.getRootNode()
    + const root = this.root
    - const firstFile = category.nodeAt(0).getFirstWord()
    - this.getRootNode().toggleAndRender(`${ExampleMenuComponent.name} ${icon}`)
    + const firstFile = category.nodeAt(0).firstWord
    + this.root.toggleAndRender(`${ExampleMenuComponent.name} ${icon}`)
    Changed around line 1492: window.ExampleMenuComponent = ExampleMenuComponent
    - class GridComponent extends AbstractTreeComponent {
    + class GridComponent extends AbstractTreeComponentParser {
    - return this.getParent().insertAgentAtCommand(right, down)
    + return this.parent.insertAgentAtCommand(right, down)
    Changed around line 1505: class GridComponent extends AbstractTreeComponent {
    - const { cols, rows, gridSize } = this.getParent()
    + const { cols, rows, gridSize } = this.parent
    Changed around line 1529: window.GridComponent = GridComponent
    - class AbstractModalTreeComponent extends AbstractTreeComponent {
    + class AbstractModalTreeComponent extends AbstractTreeComponentParser {
    Changed around line 1567: class AbstractModalTreeComponent extends AbstractTreeComponent {
    - return new jtree.TreeNode(`section
    + return new TreeNode(`section
    Changed around line 1594: window.HelpModalComponent = HelpModalComponent
    - class PlayButtonComponent extends AbstractTreeComponent {
    + class PlayButtonComponent extends AbstractTreeComponentParser {
    - return this.getRootNode().isRunning
    + return this.root.isRunning
    Changed around line 1611: window.PlayButtonComponent = PlayButtonComponent
    - class ReportButtonComponent extends AbstractTreeComponent {
    + class ReportButtonComponent extends AbstractTreeComponentParser {
    Changed around line 1625: window.ReportButtonComponent = ReportButtonComponent
    - class ResetButtonComponent extends AbstractTreeComponent {
    + class ResetButtonComponent extends AbstractTreeComponentParser {
    Changed around line 1634: class ResetButtonComponent extends AbstractTreeComponent {
    - this.getRootNode().pauseAllCommand()
    - this.getRootNode().resetAllCommand()
    + this.root.pauseAllCommand()
    + this.root.resetAllCommand()
    Changed around line 1646: window.ResetButtonComponent = ResetButtonComponent
    - class RightBarComponent extends AbstractTreeComponent {
    - createParser() {
    - return new jtree.TreeNode.Parser(undefined, {
    - AgentPaletteComponent
    - })
    - }
    + class RightBarComponent extends AbstractTreeComponentParser {
    + createParserCombinator() {
    + return new TreeNode.ParserCombinator(undefined, {
    + AgentPaletteComponent
    + })
    + }
    Changed around line 1659: window.RightBarComponent = RightBarComponent
    - class ShareComponent extends AbstractTreeComponent {
    + class ShareComponent extends AbstractTreeComponentParser {
    Changed around line 1670: class ShareComponent extends AbstractTreeComponent {
    - return [this.getRootNode().firstProgram]
    + return [this.root.firstProgram]
    - return url.toString() + this.getRootNode().urlHash
    + return url.toString() + this.root.urlHash
    Changed around line 1698: class CodeMirrorShim {
    - class SimEditorComponent extends AbstractTreeComponent {
    + class SimEditorComponent extends AbstractTreeComponentParser {
    Changed around line 1710: class SimEditorComponent extends AbstractTreeComponent {
    - createParser() {
    - return new jtree.TreeNode.Parser(undefined, {
    - value: jtree.TreeNode
    + createParserCombinator() {
    + return new TreeNode.ParserCombinator(undefined, {
    + value: TreeNode
    Changed around line 1727: class SimEditorComponent extends AbstractTreeComponent {
    - const root = this.getRootNode()
    + const root = this.root
    - this.program = new simojiCompiler(code)
    + this.program = new simojiParser(code)
    Changed around line 1754: class SimEditorComponent extends AbstractTreeComponent {
    - this.codeMirrorInstance.addLineWidget(err.getLineNumber() - 1, el, { coverGutter: false, noHScroll: false })
    + this.codeMirrorInstance.addLineWidget(err.lineNumber - 1, el, { coverGutter: false, noHScroll: false })
    Changed around line 1769: class SimEditorComponent extends AbstractTreeComponent {
    - this.getRootNode().loadNewSim(this._code)
    + this.root.loadNewSim(this._code)
    Changed around line 1800: class SimEditorComponent extends AbstractTreeComponent {
    - this.codeMirrorInstance = new jtree.TreeNotationCodeMirrorMode(
    - "custom",
    - () => simojiCompiler,
    - undefined,
    - CodeMirror
    - )
    + this.codeMirrorInstance = new GrammarCodeMirrorMode("custom", () => simojiParser, undefined, CodeMirror)
    Changed around line 1862: const MIN_GRID_ROWS = 10
    - class githubTriangleComponent extends AbstractTreeComponent {
    - githubLink = `https://github.com/publicdomaincompany/simoji`
    + class githubTriangleComponent extends AbstractTreeComponentParser {
    + githubLink = `https://github.com/breck7/simoji`
    Changed around line 1883: class githubTriangleComponent extends AbstractTreeComponent {
    - class ErrorNode extends AbstractTreeComponent {
    - _isErrorNodeType() {
    + class ErrorParser extends AbstractTreeComponentParser {
    + _isErrorParser() {
    Changed around line 1894: class ErrorNode extends AbstractTreeComponent {
    - class SimojiApp extends AbstractTreeComponent {
    - createParser() {
    - return new jtree.TreeNode.Parser(ErrorNode, {
    + class SimojiApp extends AbstractTreeComponentParser {
    + createParserCombinator() {
    + return new TreeNode.ParserCombinator(ErrorParser, {
    Changed around line 1953: class SimojiApp extends AbstractTreeComponent {
    - .filter(node => node.doesExtend(NodeTypes.abstractInjectCommandNode))
    + .filter(node => node.doesExtend(ParserTypes.abstractInjectCommandParser))
    Changed around line 2034: ${styleNode ? styleNode.toString().replace("style", BoardStyleComponent.name) :
    - const errs = new simojiCompiler(this.simCode).getAllErrors()
    - console.log(new jtree.TreeNode(errs.map(err => err.toObject())).toFormattedTable(200))
    + const errs = new simojiParser(this.simCode).getAllErrors()
    + console.log(new TreeNode(errs.map(err => err.toObject())).toFormattedTable(200))
    Changed around line 2047: ${styleNode ? styleNode.toString().replace("style", BoardStyleComponent.name) :
    - return new simojiCompiler(this.simCode)
    + return new simojiParser(this.simCode)
    Changed around line 2060: ${styleNode ? styleNode.toString().replace("style", BoardStyleComponent.name) :
    - this._simojiPrograms = this._simojiPrograms.map(program => new simojiCompiler(program.toString()))
    + this._simojiPrograms = this._simojiPrograms.map(program => new simojiParser(program.toString()))
    Changed around line 2104: ${styleNode ? styleNode.toString().replace("style", BoardStyleComponent.name) :
    - willowBrowser.getMousetrap().bind(key, function(evt) {
    + willowBrowser.getMousetrap().bind(key, function (evt) {
    Changed around line 2141: ${styleNode ? styleNode.toString().replace("style", BoardStyleComponent.name) :
    - const str = this.selection
    - .map(agent =>
    - agent
    - .getWords()
    - .slice(0, 3)
    - .join(" ")
    - )
    - .join("\n")
    + const str = this.selection.map(agent => agent.words.slice(0, 3).join(" ")).join("\n")
    Changed around line 2200: ${styleNode ? styleNode.toString().replace("style", BoardStyleComponent.name) :
    - const tree = new jtree.TreeNode()
    + const tree = new TreeNode()
    Changed around line 2279: ${styleNode ? styleNode.toString().replace("style", BoardStyleComponent.name) :
    - return new jtree.TreeNode(this.simCode).has(Keywords.seed)
    + return new TreeNode(this.simCode).has(Keywords.seed)
    - const newCode = new jtree.TreeNode(this.simCode)
    + const newCode = new TreeNode(this.simCode)
    Changed around line 2370: SimojiApp.setupApp = (simojiCode, windowWidth = 1000, windowHeight = 1000) => {
    - const startState = new jtree.TreeNode(`${githubTriangleComponent.name}
    + const startState = new TreeNode(`${githubTriangleComponent.name}
    Changed around line 2400: window.SimojiApp = SimojiApp
    - class TitleComponent extends AbstractTreeComponent {
    + class TitleComponent extends AbstractTreeComponentParser {
    - return this.getRootNode()
    + return this.root
    Changed around line 2430: window.TitleComponent = TitleComponent
    - class TopBarComponent extends AbstractTreeComponent {
    - createParser() {
    - return new jtree.TreeNode.Parser(undefined, {
    + class TopBarComponent extends AbstractTreeComponentParser {
    + createParserCombinator() {
    + return new TreeNode.ParserCombinator(undefined, {
    Changed around line 2440: class TopBarComponent extends AbstractTreeComponent {
    - class LogoComponent extends AbstractTreeComponent {
    + class LogoComponent extends AbstractTreeComponentParser {
    Changed around line 2449: class LogoComponent extends AbstractTreeComponent {
    - this.getRootNode().toggleHelpCommand()
    + this.root.toggleHelpCommand()
    Changed around line 2496: Directions.East = "East"
    - const NodeTypes = {}
    + const ParserTypes = {}
    - NodeTypes.agentDefinitionNode = "agentDefinitionNode"
    - NodeTypes.experimentNode = "experimentNode"
    - NodeTypes.settingDefinitionNode = "settingDefinitionNode"
    - NodeTypes.abstractInjectCommandNode = "abstractInjectCommandNode"
    + ParserTypes.agentDefinitionParser = "agentDefinitionParser"
    + ParserTypes.experimentParser = "experimentParser"
    + ParserTypes.settingDefinitionParser = "settingDefinitionParser"
    + ParserTypes.abstractInjectCommandParser = "abstractInjectCommandParser"
    Changed around line 2511: window.UrlKeys = UrlKeys
    - window.NodeTypes = NodeTypes
    + window.ParserTypes = ParserTypes
    Changed around line 2520: const DEFAULT_SIM = "fire"
    - class BrowserGlue extends AbstractTreeComponent {
    +
    + class BrowserGlue extends AbstractTreeComponentParser {
    Changed around line 2539: class BrowserGlue extends AbstractTreeComponent {
    - const deepLink = new jtree.TreeNode(decodeURIComponent(hash))
    + const deepLink = new TreeNode(decodeURIComponent(hash))
    Changed around line 2567: class BrowserGlue extends AbstractTreeComponent {
    - window.simojiCompiler = new jtree.HandGrammarProgram(grammarCode).compileAndReturnRootConstructor()
    + window.simojiParser = new HandGrammarProgram(grammarCode).compileAndReturnRootParser()
    package-lock.json
    Changed around line 9
    - "jtree": "^53.8.0",
    + "jtree": "^74.0.0",
    Changed around line 21
    - "node": ">=14.0.0"
    + "node": ">=16.0.0"
    Changed around line 409
    - "node_modules/@types/d3-format": {
    - "version": "1.4.2",
    - "resolved": "https://registry.npmjs.org/@types/d3-format/-/d3-format-1.4.2.tgz",
    - "integrity": "sha512-WeGCHAs7PHdZYq6lwl/+jsl+Nfc1J2W1kNcMeIMYzQsT6mtBDBgtJ/rcdjZ0k0rVIvqEZqhhuD5TK/v3P2gFHQ=="
    - },
    - "version": "1.3.7",
    - "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.7.tgz",
    - "integrity": "sha512-Il80Qs2WjYlJIBNzNkK6KYqlVMTbZLXgHx2oT0pU/fjRHyEp+PEfEPY0R3WCwAGVOtauxh1hOxNgIf5bv7dQpA==",
    + "version": "1.3.8",
    + "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz",
    + "integrity": "sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==",
    - "mime-types": "~2.1.24",
    - "negotiator": "0.6.2"
    + "mime-types": "~2.1.34",
    + "negotiator": "0.6.3"
    Changed around line 510
    - "integrity": "sha1-ml9pkFGx5wczKPKgCJaLZOopVdI="
    + "integrity": "sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg=="
    + },
    + "node_modules/asap": {
    + "version": "2.0.6",
    + "resolved": "https://registry.npmjs.org/asap/-/asap-2.0.6.tgz",
    + "integrity": "sha512-BSHWgDSAiKs50o2Re8ppvp3seVHXSRM44cdSsT9FfNEUUZLOGWVCsiWaRPWM1Znn+mqZ1OfVZ3z3DWEzSp7hRA=="
    Changed around line 597
    - "version": "1.19.0",
    - "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.19.0.tgz",
    - "integrity": "sha512-dhEPs72UPbDnAQJ9ZKMNTP6ptJaionhP5cBb541nXPlW60Jepo9RV/a4fX4XWW9CuFNK22krhrj1+rgzifNCsw==",
    + "version": "1.20.1",
    + "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.1.tgz",
    + "integrity": "sha512-jWi7abTbYwajOytWCQc37VulmWiRae5RyTpaCyDcS5/lMdtwSz5lOpDE67srw/HYe35f1z3fDQw+3txg7gNtWw==",
    - "bytes": "3.1.0",
    + "bytes": "3.1.2",
    - "depd": "~1.1.2",
    - "http-errors": "1.7.2",
    + "depd": "2.0.0",
    + "destroy": "1.2.0",
    + "http-errors": "2.0.0",
    - "on-finished": "~2.3.0",
    - "qs": "6.7.0",
    - "raw-body": "2.4.0",
    - "type-is": "~1.6.17"
    + "on-finished": "2.4.1",
    + "qs": "6.11.0",
    + "raw-body": "2.5.1",
    + "type-is": "~1.6.18",
    + "unpipe": "1.0.0"
    - "node": ">= 0.8"
    + "node": ">= 0.8",
    + "npm": "1.2.8000 || >= 1.4.16"
    + "dev": true,
    Changed around line 667
    - "version": "3.1.0",
    - "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.0.tgz",
    - "integrity": "sha512-zauLjrfCG+xvoyaqLoV8bLVXXNGC4JqlxFCutSDWA6fJrTo2ZuvLYTqZ7aHBLZSMOopbzwv8f+wZcVzfVTI2Dg==",
    + "version": "3.1.2",
    + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz",
    + "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==",
    Changed around line 696
    + },
    + "funding": {
    + "url": "https://github.com/sponsors/ljharb"
    Changed around line 858
    - "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s="
    + "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=",
    + "dev": true
    - "version": "0.5.3",
    - "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.3.tgz",
    - "integrity": "sha512-ExO0774ikEObIAEV9kDo50o+79VCUdEB6n6lzKgGwupcVeRlhrj3qGAfwq8G6uBJjkqLrhT0qEYFcWng8z1z0g==",
    + "version": "0.5.4",
    + "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.4.tgz",
    + "integrity": "sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ==",
    - "safe-buffer": "5.1.2"
    + "safe-buffer": "5.2.1"
    + "node_modules/content-disposition/node_modules/safe-buffer": {
    + "version": "5.2.1",
    + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz",
    + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==",
    + "funding": [
    + {
    + "type": "github",
    + "url": "https://github.com/sponsors/feross"
    + },
    + {
    + "type": "patreon",
    + "url": "https://www.patreon.com/feross"
    + },
    + {
    + "type": "consulting",
    + "url": "https://feross.org/support"
    + }
    + ]
    + },
    - "version": "1.0.4",
    - "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.4.tgz",
    - "integrity": "sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA==",
    + "version": "1.0.5",
    + "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.5.tgz",
    + "integrity": "sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==",
    Changed around line 909
    - "version": "0.4.0",
    - "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.4.0.tgz",
    - "integrity": "sha512-+Hp8fLp57wnUSt0tY0tHEXh4voZRDnoIrZPqlo3DPiI4y9lwg/jqx+1Om94/W6ZaPDOUbnjOt/99w66zk+l1Xg==",
    + "version": "0.5.0",
    + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.5.0.tgz",
    + "integrity": "sha512-YZ3GUyn/o8gfKJlnlX7g7xq4gyO6OSuhGPKaaGssGB2qgDUS0gPgtTvoyZLTt9Ab6dC4hfc9dV5arkvc/OCmrw==",
    Changed around line 919
    - "integrity": "sha1-4wOogrNCzD7oylE6eZmXNNqzriw="
    + "integrity": "sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ=="
    - "version": "2.1.2",
    - "resolved": "https://registry.npmjs.org/cookiejar/-/cookiejar-2.1.2.tgz",
    - "integrity": "sha512-Mw+adcfzPxcPeI+0WlvRrr/3lGVO0bD75SxX6811cxSh1Wbxx7xZBGK1eVtDf6si8rg2lhnUjsVLMFMfbRIuwA=="
    + "version": "2.1.4",
    + "resolved": "https://registry.npmjs.org/cookiejar/-/cookiejar-2.1.4.tgz",
    + "integrity": "sha512-LDx6oHrK+PhzLKJU9j5S7/Y3jM/mUHvD/DeI1WQmJn652iPC5Y4TBzC9l+5OMOXlyTTA+SmVUPm0HQUwpD5Jqw=="
    Changed around line 965
    - "node_modules/d3-format": {
    - "version": "1.4.5",
    - "resolved": "https://registry.npmjs.org/d3-format/-/d3-format-1.4.5.tgz",
    - "integrity": "sha512-J0piedu6Z8iB6TbIGfZgDzfXxUFN3qQRMofy2oPdXzQibYGqPB/9iMcxr/TGalU+2RsyDO+U4f33id8tbnSRMQ=="
    - },
    Changed around line 1020
    - "version": "1.1.2",
    - "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz",
    - "integrity": "sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak=",
    + "version": "2.0.0",
    + "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz",
    + "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==",
    - "node": ">= 0.6"
    + "node": ">= 0.8"
    + "version": "1.2.0",
    + "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.2.0.tgz",
    + "integrity": "sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg==",
    + "engines": {
    + "node": ">= 0.8",
    + "npm": "1.2.8000 || >= 1.4.16"
    + }
    + },
    + "node_modules/dezalgo": {
    - "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.0.4.tgz",
    - "integrity": "sha1-l4hXRCxEdJ5CBmE+N5RiBYJqvYA="
    + "resolved": "https://registry.npmjs.org/dezalgo/-/dezalgo-1.0.4.tgz",
    + "integrity": "sha512-rXSP0bf+5n0Qonsb+SVVfNfIsimO4HEtmnIpPHY8Q1UCzKlQrDMfdobr8nJOOsRgWCyMRqeSBQzmWUMq7zvVig==",
    + "dependencies": {
    + "asap": "^2.0.0",
    + "wrappy": "1"
    + }
    Changed around line 1067
    - "integrity": "sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0="
    + "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow=="
    Changed around line 1084
    - "integrity": "sha1-rT/0yG7C0CkyL1oCw6mmBslbP1k=",
    + "integrity": "sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==",
    Changed around line 1107
    - "integrity": "sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg="
    + "integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow=="
    Changed around line 1139
    - "integrity": "sha1-Qa4u62XvpiJorr/qg6x9eSmbCIc=",
    + "integrity": "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==",
    Changed around line 1151
    - "version": "4.17.1",
    - "resolved": "https://registry.npmjs.org/express/-/express-4.17.1.tgz",
    - "integrity": "sha512-mHJ9O79RqluphRrcw2X/GTh3k9tVv8YcoyY4Kkh4WDMUYKRZUq0h1o0w2rrrxBqM7VoeUVqgb27xlEMXTnYt4g==",
    + "version": "4.18.2",
    + "resolved": "https://registry.npmjs.org/express/-/express-4.18.2.tgz",
    + "integrity": "sha512-5/PsL6iGPdfQ/lKM1UuielYgv3BUoJfz1aUwU9vHZ+J7gyvwdQXFEBIEIaxeGf0GIcreATNyBExtalisDbuMqQ==",
    - "accepts": "~1.3.7",
    + "accepts": "~1.3.8",
    - "body-parser": "1.19.0",
    - "content-disposition": "0.5.3",
    + "body-parser": "1.20.1",
    + "content-disposition": "0.5.4",
    - "cookie": "0.4.0",
    + "cookie": "0.5.0",
    - "depd": "~1.1.2",
    + "depd": "2.0.0",
    - "finalhandler": "~1.1.2",
    + "finalhandler": "1.2.0",
    + "http-errors": "2.0.0",
    - "on-finished": "~2.3.0",
    + "on-finished": "2.4.1",
    - "proxy-addr": "~2.0.5",
    - "qs": "6.7.0",
    + "proxy-addr": "~2.0.7",
    + "qs": "6.11.0",
    - "safe-buffer": "5.1.2",
    - "send": "0.17.1",
    - "serve-static": "1.14.1",
    - "setprototypeof": "1.1.1",
    - "statuses": "~1.5.0",
    + "safe-buffer": "5.2.1",
    + "send": "0.18.0",
    + "serve-static": "1.15.0",
    + "setprototypeof": "1.2.0",
    + "statuses": "2.0.1",
    Changed around line 1191
    + "node_modules/express/node_modules/safe-buffer": {
    + "version": "5.2.1",
    + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz",
    + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==",
    + "funding": [
    + {
    + "type": "github",
    + "url": "https://github.com/sponsors/feross"
    + },
    + {
    + "type": "patreon",
    + "url": "https://www.patreon.com/feross"
    + },
    + {
    + "type": "consulting",
    + "url": "https://feross.org/support"
    + }
    + ]
    + },
    Changed around line 1238
    - "version": "2.0.8",
    - "resolved": "https://registry.npmjs.org/fast-safe-stringify/-/fast-safe-stringify-2.0.8.tgz",
    - "integrity": "sha512-lXatBjf3WPjmWD6DpIZxkeSsCOwqI0maYMpgDlx8g4U2qi4lbjA9oH/HD2a87G+KfsUmo5WbJFmqBZlPxtptag=="
    + "version": "2.1.1",
    + "resolved": "https://registry.npmjs.org/fast-safe-stringify/-/fast-safe-stringify-2.1.1.tgz",
    + "integrity": "sha512-W+KJc2dmILlPplD/H4K9l9LcAHAfPtP6BY84uVLXQ6Evcz9Lcg33Y2z1IVblT6xdY54PXYVHEv+0Wpq8Io6zkA=="
    Changed around line 1255
    - "version": "1.1.2",
    - "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.1.2.tgz",
    - "integrity": "sha512-aAWcW57uxVNrQZqFXjITpW3sIUQmHGG3qSb9mUah9MgMC4NeWhNOlNjXEYq3HjRAvL6arUviZGGJsBg6z0zsWA==",
    + "version": "1.2.0",
    + "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.2.0.tgz",
    + "integrity": "sha512-5uXcUVftlQMFnWC9qu/svkWv3GTd2PfUhK/3PLkYNAe7FbqJMt3515HaxE6eRL74GdsriiwujiawdaB1BpEISg==",
    - "on-finished": "~2.3.0",
    + "on-finished": "2.4.1",
    - "statuses": "~1.5.0",
    + "statuses": "2.0.1",
    Changed around line 1327
    - "version": "3.0.1",
    - "resolved": "https://registry.npmjs.org/form-data/-/form-data-3.0.1.tgz",
    - "integrity": "sha512-RHkBKtLWUVwd7SqRIvCZMEvAMoGUp0XU+seQiZejj0COz3RI3hWP4sCv3gZWWLjJTd7rGwcsF5eKZGii0r/hbg==",
    + "version": "4.0.0",
    + "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz",
    + "integrity": "sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==",
    Changed around line 1340
    - "version": "1.2.2",
    - "resolved": "https://registry.npmjs.org/formidable/-/formidable-1.2.2.tgz",
    - "integrity": "sha512-V8gLm+41I/8kguQ4/o1D3RIHRmhYFG4pnNyonvua+40rqcEmT4+V71yaZ3B457xbbgCsCfjSPi65u/W6vK1U5Q=="
    + "version": "2.1.2",
    + "resolved": "https://registry.npmjs.org/formidable/-/formidable-2.1.2.tgz",
    + "integrity": "sha512-CM3GuJ57US06mlpQ47YcunuUZ9jpm8Vx+P2CGt2j7HpgkKZO/DJYQ0Bobim8G6PFQmK5lOqOOdUXboU+h73A4g==",
    + "dependencies": {
    + "dezalgo": "^1.0.4",
    + "hexoid": "^1.0.0",
    + "once": "^1.4.0",
    + "qs": "^6.11.0"
    + },
    + "funding": {
    + "url": "https://ko-fi.com/tunnckoCore/commissions"
    + }
    Changed around line 1372
    - "integrity": "sha1-PYyt2Q2XZWn6g1qx+OSyOhBWBac=",
    + "integrity": "sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q==",
    Changed around line 1437
    - "version": "1.1.1",
    - "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.1.1.tgz",
    - "integrity": "sha512-kWZrnVM42QCiEA2Ig1bG8zjoIMOgxWwYCEeNdwY6Tv/cOSeGpcoX4pXHfKUxNKVoArnrEr2e9srnAxxGIraS9Q==",
    + "version": "1.2.0",
    + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.0.tgz",
    + "integrity": "sha512-L049y6nFOuom5wGyRc3/gdTLO94dySVKRACj1RmJZBQXlbTMhtNIgkWkUHq+jYmZvKf14EW1EoJnnjbmoHij0Q==",
    - "has-symbols": "^1.0.1"
    + "has-symbols": "^1.0.3"
    + },
    + "funding": {
    + "url": "https://github.com/sponsors/ljharb"
    Changed around line 1471
    + "dev": true,
    Changed around line 1554
    - "version": "1.0.2",
    - "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.2.tgz",
    - "integrity": "sha512-chXa79rL/UC2KlX17jo3vRGz0azaWEx5tGqZg5pO3NUyEJVB17dMruQlzCCOfUvElghKcm5194+BCRvi2Rv/Gw==",
    + "version": "1.0.3",
    + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz",
    + "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==",
    + },
    + "funding": {
    + "url": "https://github.com/sponsors/ljharb"
    Changed around line 1577
    + "node_modules/hexoid": {
    + "version": "1.0.0",
    + "resolved": "https://registry.npmjs.org/hexoid/-/hexoid-1.0.0.tgz",
    + "integrity": "sha512-QFLV0taWQOZtvIRIAdBChesmogZrtuXvVWsFHZTk2SU+anspqZ2vMnoLg7IE1+Uk16N19APic1BuF8bC8c2m5g==",
    + "engines": {
    + "node": ">=8"
    + }
    + },
    Changed around line 1592
    - "version": "1.7.2",
    - "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.7.2.tgz",
    - "integrity": "sha512-uUQBt3H/cSIVfch6i1EuPNy/YsRSOUBXTVfZ+yR7Zjez3qjBz6i9+i4zjNaoqcoFVI4lQJ5plg63TvGfRSDCRg==",
    + "version": "2.0.0",
    + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz",
    + "integrity": "sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==",
    - "depd": "~1.1.2",
    - "inherits": "2.0.3",
    - "setprototypeof": "1.1.1",
    - "statuses": ">= 1.5.0 < 2",
    - "toidentifier": "1.0.0"
    + "depd": "2.0.0",
    + "inherits": "2.0.4",
    + "setprototypeof": "1.2.0",
    + "statuses": "2.0.1",
    + "toidentifier": "1.0.1"
    - "node": ">= 0.6"
    + "node": ">= 0.8"
    Changed around line 1654
    + "dev": true,
    - "version": "2.0.3",
    - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz",
    - "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4="
    + "version": "2.0.4",
    + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz",
    + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ=="
    Changed around line 2011
    - "version": "53.8.0",
    - "resolved": "https://registry.npmjs.org/jtree/-/jtree-53.8.0.tgz",
    - "integrity": "sha512-HUtrF+0FMakMGbUktqGlwAkURkaRdSa9WBj1lek3T0INT+S2GdyPoZvtIdVZSBqYhqtTamXSMD7WsTt19x+xuA==",
    - "dependencies": {
    - "@types/d3-format": "^1.3.1",
    - "d3-format": "^1.3.2",
    - "express": "*",
    - "glob": "^7.1.4",
    - "mkdirp": "^0.5.6",
    - "moment": "^2.29.3",
    - "moment-parseformat": "^3.0.0",
    - "prettier": "^1.18.2",
    + "version": "74.0.0",
    + "resolved": "https://registry.npmjs.org/jtree/-/jtree-74.0.0.tgz",
    + "integrity": "sha512-jKyvI60geVzmtfqahfG4kszQp2zg50N7JvtLTxaRamZpqi3J+a+3UduSEZvzBN8k7qSvcR7rA0TBbXSBinCOPw==",
    + "dependencies": {
    + "express": "^4.18.2",
    + "glob": "^9.3.4",
    + "mkdirp": "^2.1.6",
    + "prettier": "^2.8.7",
    - "semver": "^6.1.1",
    - "superagent": "^5.1.0"
    + "superagent": "^8.0.9"
    - "bin": {
    - "jtree": "products/commandLineApp.node.js"
    + "engines": {
    + "node": ">=16.0"
    + }
    + },
    + "node_modules/jtree/node_modules/brace-expansion": {
    + "version": "2.0.1",
    + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz",
    + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==",
    + "dependencies": {
    + "balanced-match": "^1.0.0"
    + }
    + },
    + "node_modules/jtree/node_modules/glob": {
    + "version": "9.3.4",
    + "resolved": "https://registry.npmjs.org/glob/-/glob-9.3.4.tgz",
    + "integrity": "sha512-qaSc49hojMOv1EPM4EuyITjDSgSKI0rthoHnvE81tcOi1SCVndHko7auqxdQ14eiQG2NDBJBE86+2xIrbIvrbA==",
    + "dependencies": {
    + "fs.realpath": "^1.0.0",
    + "minimatch": "^8.0.2",
    + "minipass": "^4.2.4",
    + "path-scurry": "^1.6.1"
    + },
    + "engines": {
    + "node": ">=16 || 14 >=14.17"
    + },
    + "funding": {
    + "url": "https://github.com/sponsors/isaacs"
    + }
    + },
    + "node_modules/jtree/node_modules/minimatch": {
    + "version": "8.0.3",
    + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-8.0.3.tgz",
    + "integrity": "sha512-tEEvU9TkZgnFDCtpnrEYnPsjT7iUx42aXfs4bzmQ5sMA09/6hZY0jeZcGkXyDagiBOvkUjNo8Viom+Me6+2x7g==",
    + "dependencies": {
    + "brace-expansion": "^2.0.1"
    + },
    + "engines": {
    + "node": ">=16 || 14 >=14.17"
    + },
    + "funding": {
    + "url": "https://github.com/sponsors/isaacs"
    + }
    + },
    + "node_modules/jtree/node_modules/minipass": {
    + "version": "4.2.5",
    + "resolved": "https://registry.npmjs.org/minipass/-/minipass-4.2.5.tgz",
    + "integrity": "sha512-+yQl7SX3bIT83Lhb4BVorMAHVuqsskxRdlmO9kTpyukp8vsm2Sn/fUOV9xlnG8/a5JsypJzap21lz/y3FBMJ8Q==",
    + "engines": {
    + "node": ">=8"
    Changed around line 2152
    - "version": "6.0.0",
    - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz",
    - "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==",
    - "dependencies": {
    - "yallist": "^4.0.0"
    - },
    + "version": "7.18.3",
    + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-7.18.3.tgz",
    + "integrity": "sha512-jumlc0BIUrS3qJGgIkWZsyfAM7NCWiBcCDhnd+3NNM5KbBmLTgHVfWBcg6W+rLUsIpzpERPsvwUP7CckAQSOoA==",
    - "node": ">=10"
    + "node": ">=12"
    Changed around line 2196
    - "integrity": "sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g=",
    + "integrity": "sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ==",
    Changed around line 2204
    - "integrity": "sha1-sAqqVW3YtEVoFQ7J0blT8/kMu2E="
    + "integrity": "sha512-cCi6g3/Zr1iqQi6ySbseM1Xvooa98N0w31jzUYrXPX2xqObmFGHJ0tQ5u74H3mVh7wLouTseZyYIq39g8cNp1w=="
    - "integrity": "sha1-VSmk1nZUE07cxSZmVoNbD4Ua/O4=",
    + "integrity": "sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w==",
    Changed around line 2226
    - "version": "1.48.0",
    - "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.48.0.tgz",
    - "integrity": "sha512-FM3QwxV+TnZYQ2aRqhlKBMHxk10lTbMt3bBkMAp54ddrNeVSfcQYOOKuGuy3Ddrm38I04If834fOUSq1yzslJQ==",
    + "version": "1.52.0",
    + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz",
    + "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==",
    - "version": "2.1.31",
    - "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.31.tgz",
    - "integrity": "sha512-XGZnNzm3QvgKxa8dpzyhFTHmpP3l5YNusmne07VUOXxou9CqUqYa/HBy124RqtVh/O2pECas/MOcsDgpilPOPg==",
    + "version": "2.1.35",
    + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz",
    + "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==",
    - "mime-db": "1.48.0"
    + "mime-db": "1.52.0"
    Changed around line 2248
    + "dev": true,
    Changed around line 2274
    - "version": "0.5.6",
    - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.6.tgz",
    - "integrity": "sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==",
    - "dependencies": {
    - "minimist": "^1.2.6"
    - },
    + "version": "2.1.6",
    + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-2.1.6.tgz",
    + "integrity": "sha512-+hEnITedc8LAtIP9u3HJDFIdcLV2vXP33sqLLIzkv1Db1zO/1OxbvYf0Y1OC/S/Qo5dxHXepofhmxL02PsKe+A==",
    - "mkdirp": "bin/cmd.js"
    - }
    - },
    - "node_modules/moment": {
    - "version": "2.29.4",
    - "resolved": "https://registry.npmjs.org/moment/-/moment-2.29.4.tgz",
    - "integrity": "sha512-5LC9SOxjSc2HF6vO2CyuTDNivEdoz2IvyJJGj6X8DJ0eFyfszE0QiEd+iXmBvUP3WHxSjFH/vIsA0EN00cgr8w==",
    + "mkdirp": "dist/cjs/src/bin.js"
    + },
    - "node": "*"
    + "node": ">=10"
    + },
    + "funding": {
    + "url": "https://github.com/sponsors/isaacs"
    - "node_modules/moment-parseformat": {
    - "version": "3.1.1",
    - "resolved": "https://registry.npmjs.org/moment-parseformat/-/moment-parseformat-3.1.1.tgz",
    - "integrity": "sha512-uEkXh5w9WDM8xNksZYeGpbZgrcG9qlpTg+f4ftHyOIis4+U08p31zOUzk3YCv2n+c6MUpW+Nb3GLCpjoEuHqJw=="
    - },
    - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g="
    + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A=="
    - "version": "0.6.2",
    - "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.2.tgz",
    - "integrity": "sha512-hZXc7K2e+PgeI1eDBe/10Ard4ekbfrrqG8Ep+8Jmf4JID2bNg7NvCPOZN+kfF574pFQI7mum2AUqDidoKqcTOw==",
    + "version": "0.6.3",
    + "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz",
    + "integrity": "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==",
    Changed around line 2396
    - "version": "1.11.0",
    - "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.11.0.tgz",
    - "integrity": "sha512-jp7ikS6Sd3GxQfZJPyH3cjcbJF6GZPClgdV+EFygjFLQ5FmW/dRUnTd9PQ9k0JhoNDabWFbpF1yCdSWCC6gexg=="
    + "version": "1.12.3",
    + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.12.3.tgz",
    + "integrity": "sha512-geUvdk7c+eizMNUDkRpW1wJwgfOiOeHbxBR/hLXK1aT6zmVSO0jsQcs7fj6MGw89jC/cjGfLcNOrtMYtGqm81g==",
    + "funding": {
    + "url": "https://github.com/sponsors/ljharb"
    + }
    - "version": "2.3.0",
    - "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz",
    - "integrity": "sha1-IPEzZIGwg811M3mSoWlxqi2QaUc=",
    + "version": "2.4.1",
    + "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz",
    + "integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==",
    Changed around line 2527
    + "dev": true,
    Changed around line 2541
    + "node_modules/path-scurry": {
    + "version": "1.6.3",
    + "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-1.6.3.tgz",
    + "integrity": "sha512-RAmB+n30SlN+HnNx6EbcpoDy9nwdpcGPnEKrJnu6GZoDWBdIjo1UQMVtW2ybtC7LC2oKLcMq8y5g8WnKLiod9g==",
    + "dependencies": {
    + "lru-cache": "^7.14.1",
    + "minipass": "^4.0.2"
    + },
    + "engines": {
    + "node": ">=16 || 14 >=14.17"
    + },
    + "funding": {
    + "url": "https://github.com/sponsors/isaacs"
    + }
    + },
    + "node_modules/path-scurry/node_modules/minipass": {
    + "version": "4.2.5",
    + "resolved": "https://registry.npmjs.org/minipass/-/minipass-4.2.5.tgz",
    + "integrity": "sha512-+yQl7SX3bIT83Lhb4BVorMAHVuqsskxRdlmO9kTpyukp8vsm2Sn/fUOV9xlnG8/a5JsypJzap21lz/y3FBMJ8Q==",
    + "engines": {
    + "node": ">=8"
    + }
    + },
    - "integrity": "sha1-32BBeABfUi8V60SQ5yR6G/qmf4w="
    + "integrity": "sha512-5DFkuoqlv1uYQKxy8omFBeJPQcdoE07Kv2sferDCrAq1ohOU+MSDswDIbnx3YAM60qIOnYa53wBhXW0EbMonrQ=="
    Changed around line 2597
    - "version": "1.19.1",
    - "resolved": "https://registry.npmjs.org/prettier/-/prettier-1.19.1.tgz",
    - "integrity": "sha512-s7PoyDv/II1ObgQunCbB9PdLmUcBZcnWOcxDh7O0N/UwDEsHyqkW+Qh28jW+mVuCdx7gLB0BotYI1Y6uI9iyew==",
    + "version": "2.8.7",
    + "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.8.7.tgz",
    + "integrity": "sha512-yPngTo3aXUUmyuTjeTUT75txrf+aMh9FiD7q9ZE/i6r0bPb22g4FsE6Y338PQX1bmfy08i9QQCB7/rcUAVntfw==",
    - "node": ">=4"
    + "node": ">=10.13.0"
    + },
    + "funding": {
    + "url": "https://github.com/prettier/prettier?sponsor=1"
    Changed around line 2661
    - "version": "6.7.0",
    - "resolved": "https://registry.npmjs.org/qs/-/qs-6.7.0.tgz",
    - "integrity": "sha512-VCdBRNFTX1fyE7Nb6FYoURo/SPe62QCaAyzJvUjwRaIsc+NePBEniHlvxFmmX56+HZphIGtV0XeCirBtpDrTyQ==",
    + "version": "6.11.0",
    + "resolved": "https://registry.npmjs.org/qs/-/qs-6.11.0.tgz",
    + "integrity": "sha512-MvjoMCJwEarSbUYk5O+nmoSzSutSsTwF85zcHPQ9OrlFoZOYIjaqBAJIqIXjptyD5vThxGq52Xu/MaJzRkIk4Q==",
    + "dependencies": {
    + "side-channel": "^1.0.4"
    + },
    + },
    + "funding": {
    + "url": "https://github.com/sponsors/ljharb"
    Changed around line 2683
    - "version": "2.4.0",
    - "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.4.0.tgz",
    - "integrity": "sha512-4Oz8DUIwdvoa5qMJelxipzi/iJIi40O5cGV1wNYp5hvZP8ZN0T+jiNkL0QepXs+EsQ9XJ8ipEDoiH70ySUJP3Q==",
    + "version": "2.5.1",
    + "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.1.tgz",
    + "integrity": "sha512-qqJBtEyVgS0ZmPGdCFPWJ3FreoqvG4MVQln/kCgF7Olq95IbOp0/BWyMwbdtn4VTvkM8Y7khCQ2Xgk/tcrCXig==",
    - "bytes": "3.1.0",
    - "http-errors": "1.7.2",
    + "bytes": "3.1.2",
    + "http-errors": "2.0.0",
    Changed around line 2716
    - "node_modules/readable-stream": {
    - "version": "3.6.0",
    - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz",
    - "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==",
    - "dependencies": {
    - "inherits": "^2.0.3",
    - "string_decoder": "^1.1.1",
    - "util-deprecate": "^1.0.1"
    - },
    - "engines": {
    - "node": ">= 6"
    - }
    - },
    Changed around line 2843
    - "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g=="
    + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==",
    + "dev": true
    Changed around line 2860
    + "dev": true,
    - "version": "0.17.1",
    - "resolved": "https://registry.npmjs.org/send/-/send-0.17.1.tgz",
    - "integrity": "sha512-BsVKsiGcQMFwT8UxypobUKyv7irCNRHk1T0G680vk88yf6LBByGcZJOTJCrTP2xVN6yI+XjPJcNuE3V4fT9sAg==",
    + "version": "0.18.0",
    + "resolved": "https://registry.npmjs.org/send/-/send-0.18.0.tgz",
    + "integrity": "sha512-qqWzuOjSFOuqPjFe4NOsMLafToQQwBSOEpS+FwEt3A2V3vKubTquT3vmLTQpFgMXp8AlFWFuP1qKaJZOtPpVXg==",
    - "depd": "~1.1.2",
    - "destroy": "~1.0.4",
    + "depd": "2.0.0",
    + "destroy": "1.2.0",
    - "http-errors": "~1.7.2",
    + "http-errors": "2.0.0",
    - "ms": "2.1.1",
    - "on-finished": "~2.3.0",
    + "ms": "2.1.3",
    + "on-finished": "2.4.1",
    - "statuses": "~1.5.0"
    + "statuses": "2.0.1"
    - "version": "2.1.1",
    - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.1.tgz",
    - "integrity": "sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg=="
    + "version": "2.1.3",
    + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
    + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA=="
    - "version": "1.14.1",
    - "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.14.1.tgz",
    - "integrity": "sha512-JMrvUwE54emCYWlTI+hGrGv5I8dEwmco/00EvkzIIsR7MqrHonbD9pO2MOfFnpFntl7ecpZs+3mW+XbQZu9QCg==",
    + "version": "1.15.0",
    + "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.15.0.tgz",
    + "integrity": "sha512-XGuRDNjXUijsUL0vl6nSD7cwURuzEgglbOaFuZM9g3kwDXOWVTck0jLzjPzGD+TazWbboZYu52/9/XPdUgne9g==",
    - "send": "0.17.1"
    + "send": "0.18.0"
    Changed around line 2914
    - "version": "1.1.1",
    - "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.1.tgz",
    - "integrity": "sha512-JvdAWfbXeIGaZ9cILp38HntZSFSo3mWg6xGcJJsd+d4aRMOqauag1C63dJfDw7OaMYwEbHMOxEZ1lqVRYP2OAw=="
    + "version": "1.2.0",
    + "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz",
    + "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw=="
    Changed around line 2947
    + },
    + "funding": {
    + "url": "https://github.com/sponsors/ljharb"
    Changed around line 3042
    - "version": "1.5.0",
    - "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz",
    - "integrity": "sha1-Fhx9rBd2Wf2YEfQ3cfqZOBR4Yow=",
    + "version": "2.0.1",
    + "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz",
    + "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==",
    - "node": ">= 0.6"
    - }
    - },
    - "node_modules/string_decoder": {
    - "version": "1.3.0",
    - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz",
    - "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==",
    - "dependencies": {
    - "safe-buffer": "~5.2.0"
    + "node": ">= 0.8"
    - "node_modules/string_decoder/node_modules/safe-buffer": {
    - "version": "5.2.1",
    - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz",
    - "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ=="
    - },
    Changed around line 3084
    - "version": "5.3.1",
    - "resolved": "https://registry.npmjs.org/superagent/-/superagent-5.3.1.tgz",
    - "integrity": "sha512-wjJ/MoTid2/RuGCOFtlacyGNxN9QLMgcpYLDQlWFIhhdJ93kNscFonGvrpAHSCVjRVj++DGCglocF7Aej1KHvQ==",
    + "version": "8.0.9",
    + "resolved": "https://registry.npmjs.org/superagent/-/superagent-8.0.9.tgz",
    + "integrity": "sha512-4C7Bh5pyHTvU33KpZgwrNKh/VQnvgtCSqPRfJAUdmrtSYePVzVg4E4OzsrbkhJj9O7SO6Bnv75K/F8XVZT8YHA==",
    - "cookiejar": "^2.1.2",
    - "debug": "^4.1.1",
    - "fast-safe-stringify": "^2.0.7",
    - "form-data": "^3.0.0",
    - "formidable": "^1.2.2",
    + "cookiejar": "^2.1.4",
    + "debug": "^4.3.4",
    + "fast-safe-stringify": "^2.1.1",
    + "form-data": "^4.0.0",
    + "formidable": "^2.1.2",
    - "mime": "^2.4.6",
    - "qs": "^6.9.4",
    - "readable-stream": "^3.6.0",
    - "semver": "^7.3.2"
    + "mime": "2.6.0",
    + "qs": "^6.11.0",
    + "semver": "^7.3.8"
    - "node": ">= 7.0.0"
    + "node": ">=6.4.0 <13 || >=14"
    - "version": "4.3.2",
    - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.2.tgz",
    - "integrity": "sha512-mOp8wKcvj7XxC78zLgw/ZA+6TSgkoE2C/ienthhRD298T7UNwAg9diBpLRxC0mOezLl4B0xV7M0cCO6P/O0Xhw==",
    + "version": "4.3.4",
    + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz",
    + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==",
    + },
    + "peerDependenciesMeta": {
    + "supports-color": {
    + "optional": true
    + }
    + }
    + },
    + "node_modules/superagent/node_modules/lru-cache": {
    + "version": "6.0.0",
    + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz",
    + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==",
    + "dependencies": {
    + "yallist": "^4.0.0"
    + },
    + "engines": {
    + "node": ">=10"
    - "version": "2.5.2",
    - "resolved": "https://registry.npmjs.org/mime/-/mime-2.5.2.tgz",
    - "integrity": "sha512-tqkh47FzKeCPD2PUiPB6pkbMzsCasjxAfC62/Wap5qrUWcb+sFasXUC5I3gYM5iBM8v/Qpn4UK0x+j0iHyFPDg==",
    + "version": "2.6.0",
    + "resolved": "https://registry.npmjs.org/mime/-/mime-2.6.0.tgz",
    + "integrity": "sha512-USPkMeET31rOMiarsBNIHZKLGgvKc/LrjofAnBlOttf5ajRvqiRA8QsenbcooctK6d6Ts6aqZXBA+XbkKthiQg==",
    Changed around line 3146
    - "node_modules/superagent/node_modules/qs": {
    - "version": "6.10.1",
    - "resolved": "https://registry.npmjs.org/qs/-/qs-6.10.1.tgz",
    - "integrity": "sha512-M528Hph6wsSVOBiYUnGf+K/7w0hNshs/duGsNXPUCLH5XAqjEtiPGwNONLV0tBH8NoGb0mvD5JubnUTrujKDTg==",
    - "dependencies": {
    - "side-channel": "^1.0.4"
    - },
    - "engines": {
    - "node": ">=0.6"
    - }
    - },
    - "version": "7.3.5",
    - "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.5.tgz",
    - "integrity": "sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==",
    + "version": "7.3.8",
    + "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.8.tgz",
    + "integrity": "sha512-NB1ctGL5rlHrPJtFDVIVzTyQylMLu9N9VICA6HSFJo8MCGVTMW6gfpicwKmmK/dAjTOrqu5l63JJOpDSrAis3A==",
    Changed around line 5196
    - "version": "1.0.0",
    - "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.0.tgz",
    - "integrity": "sha512-yaOH/Pk/VEhBWWTlhI+qXxDFXlejDGcQipMlyxda9nthulaxLZUNcUqFxokp0vcYnvteJln5FNQDRrxj3YcbVw==",
    + "version": "1.0.1",
    + "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz",
    + "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==",
    Changed around line 5312
    - "integrity": "sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw=",
    + "integrity": "sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==",
    Changed around line 5326
    - "node_modules/util-deprecate": {
    - "version": "1.0.2",
    - "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz",
    - "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8="
    - },
    - "integrity": "sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM=",
    + "integrity": "sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA==",
    Changed around line 5346
    - "integrity": "sha1-IpnwLG3tMNSllhsLn3RSShj2NPw=",
    + "integrity": "sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==",
    Changed around line 5927
    - "@types/d3-format": {
    - "version": "1.4.2",
    - "resolved": "https://registry.npmjs.org/@types/d3-format/-/d3-format-1.4.2.tgz",
    - "integrity": "sha512-WeGCHAs7PHdZYq6lwl/+jsl+Nfc1J2W1kNcMeIMYzQsT6mtBDBgtJ/rcdjZ0k0rVIvqEZqhhuD5TK/v3P2gFHQ=="
    - },
    - "version": "1.3.7",
    - "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.7.tgz",
    - "integrity": "sha512-Il80Qs2WjYlJIBNzNkK6KYqlVMTbZLXgHx2oT0pU/fjRHyEp+PEfEPY0R3WCwAGVOtauxh1hOxNgIf5bv7dQpA==",
    + "version": "1.3.8",
    + "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz",
    + "integrity": "sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==",
    - "mime-types": "~2.1.24",
    - "negotiator": "0.6.2"
    + "mime-types": "~2.1.34",
    + "negotiator": "0.6.3"
    Changed around line 6010
    - "integrity": "sha1-ml9pkFGx5wczKPKgCJaLZOopVdI="
    + "integrity": "sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg=="
    + },
    + "asap": {
    + "version": "2.0.6",
    + "resolved": "https://registry.npmjs.org/asap/-/asap-2.0.6.tgz",
    + "integrity": "sha512-BSHWgDSAiKs50o2Re8ppvp3seVHXSRM44cdSsT9FfNEUUZLOGWVCsiWaRPWM1Znn+mqZ1OfVZ3z3DWEzSp7hRA=="
    Changed around line 6082
    - "version": "1.19.0",
    - "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.19.0.tgz",
    - "integrity": "sha512-dhEPs72UPbDnAQJ9ZKMNTP6ptJaionhP5cBb541nXPlW60Jepo9RV/a4fX4XWW9CuFNK22krhrj1+rgzifNCsw==",
    + "version": "1.20.1",
    + "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.1.tgz",
    + "integrity": "sha512-jWi7abTbYwajOytWCQc37VulmWiRae5RyTpaCyDcS5/lMdtwSz5lOpDE67srw/HYe35f1z3fDQw+3txg7gNtWw==",
    - "bytes": "3.1.0",
    + "bytes": "3.1.2",
    - "depd": "~1.1.2",
    - "http-errors": "1.7.2",
    + "depd": "2.0.0",
    + "destroy": "1.2.0",
    + "http-errors": "2.0.0",
    - "on-finished": "~2.3.0",
    - "qs": "6.7.0",
    - "raw-body": "2.4.0",
    - "type-is": "~1.6.17"
    + "on-finished": "2.4.1",
    + "qs": "6.11.0",
    + "raw-body": "2.5.1",
    + "type-is": "~1.6.18",
    + "unpipe": "1.0.0"
    + "dev": true,
    Changed around line 6139
    - "version": "3.1.0",
    - "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.0.tgz",
    - "integrity": "sha512-zauLjrfCG+xvoyaqLoV8bLVXXNGC4JqlxFCutSDWA6fJrTo2ZuvLYTqZ7aHBLZSMOopbzwv8f+wZcVzfVTI2Dg=="
    + "version": "3.1.2",
    + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz",
    + "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg=="
    Changed around line 6294
    - "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s="
    + "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=",
    + "dev": true
    - "version": "0.5.3",
    - "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.3.tgz",
    - "integrity": "sha512-ExO0774ikEObIAEV9kDo50o+79VCUdEB6n6lzKgGwupcVeRlhrj3qGAfwq8G6uBJjkqLrhT0qEYFcWng8z1z0g==",
    + "version": "0.5.4",
    + "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.4.tgz",
    + "integrity": "sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ==",
    - "safe-buffer": "5.1.2"
    + "safe-buffer": "5.2.1"
    + },
    + "dependencies": {
    + "safe-buffer": {
    + "version": "5.2.1",
    + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz",
    + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ=="
    + }
    - "version": "1.0.4",
    - "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.4.tgz",
    - "integrity": "sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA=="
    + "version": "1.0.5",
    + "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.5.tgz",
    + "integrity": "sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA=="
    Changed around line 6327
    - "version": "0.4.0",
    - "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.4.0.tgz",
    - "integrity": "sha512-+Hp8fLp57wnUSt0tY0tHEXh4voZRDnoIrZPqlo3DPiI4y9lwg/jqx+1Om94/W6ZaPDOUbnjOt/99w66zk+l1Xg=="
    + "version": "0.5.0",
    + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.5.0.tgz",
    + "integrity": "sha512-YZ3GUyn/o8gfKJlnlX7g7xq4gyO6OSuhGPKaaGssGB2qgDUS0gPgtTvoyZLTt9Ab6dC4hfc9dV5arkvc/OCmrw=="
    - "integrity": "sha1-4wOogrNCzD7oylE6eZmXNNqzriw="
    + "integrity": "sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ=="
    - "version": "2.1.2",
    - "resolved": "https://registry.npmjs.org/cookiejar/-/cookiejar-2.1.2.tgz",
    - "integrity": "sha512-Mw+adcfzPxcPeI+0WlvRrr/3lGVO0bD75SxX6811cxSh1Wbxx7xZBGK1eVtDf6si8rg2lhnUjsVLMFMfbRIuwA=="
    + "version": "2.1.4",
    + "resolved": "https://registry.npmjs.org/cookiejar/-/cookiejar-2.1.4.tgz",
    + "integrity": "sha512-LDx6oHrK+PhzLKJU9j5S7/Y3jM/mUHvD/DeI1WQmJn652iPC5Y4TBzC9l+5OMOXlyTTA+SmVUPm0HQUwpD5Jqw=="
    Changed around line 6371
    - "d3-format": {
    - "version": "1.4.5",
    - "resolved": "https://registry.npmjs.org/d3-format/-/d3-format-1.4.5.tgz",
    - "integrity": "sha512-J0piedu6Z8iB6TbIGfZgDzfXxUFN3qQRMofy2oPdXzQibYGqPB/9iMcxr/TGalU+2RsyDO+U4f33id8tbnSRMQ=="
    - },
    Changed around line 6414
    - "version": "1.1.2",
    - "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz",
    - "integrity": "sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak="
    + "version": "2.0.0",
    + "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz",
    + "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw=="
    + "version": "1.2.0",
    + "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.2.0.tgz",
    + "integrity": "sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg=="
    + },
    + "dezalgo": {
    - "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.0.4.tgz",
    - "integrity": "sha1-l4hXRCxEdJ5CBmE+N5RiBYJqvYA="
    + "resolved": "https://registry.npmjs.org/dezalgo/-/dezalgo-1.0.4.tgz",
    + "integrity": "sha512-rXSP0bf+5n0Qonsb+SVVfNfIsimO4HEtmnIpPHY8Q1UCzKlQrDMfdobr8nJOOsRgWCyMRqeSBQzmWUMq7zvVig==",
    + "requires": {
    + "asap": "^2.0.0",
    + "wrappy": "1"
    + }
    Changed around line 6451
    - "integrity": "sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0="
    + "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow=="
    Changed around line 6468
    - "integrity": "sha1-rT/0yG7C0CkyL1oCw6mmBslbP1k="
    + "integrity": "sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w=="
    Changed around line 6485
    - "integrity": "sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg="
    + "integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow=="
    Changed around line 6507
    - "integrity": "sha1-Qa4u62XvpiJorr/qg6x9eSmbCIc="
    + "integrity": "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg=="
    Changed around line 6516
    - "version": "4.17.1",
    - "resolved": "https://registry.npmjs.org/express/-/express-4.17.1.tgz",
    - "integrity": "sha512-mHJ9O79RqluphRrcw2X/GTh3k9tVv8YcoyY4Kkh4WDMUYKRZUq0h1o0w2rrrxBqM7VoeUVqgb27xlEMXTnYt4g==",
    + "version": "4.18.2",
    + "resolved": "https://registry.npmjs.org/express/-/express-4.18.2.tgz",
    + "integrity": "sha512-5/PsL6iGPdfQ/lKM1UuielYgv3BUoJfz1aUwU9vHZ+J7gyvwdQXFEBIEIaxeGf0GIcreATNyBExtalisDbuMqQ==",
    - "accepts": "~1.3.7",
    + "accepts": "~1.3.8",
    - "body-parser": "1.19.0",
    - "content-disposition": "0.5.3",
    + "body-parser": "1.20.1",
    + "content-disposition": "0.5.4",
    - "cookie": "0.4.0",
    + "cookie": "0.5.0",
    - "depd": "~1.1.2",
    + "depd": "2.0.0",
    - "finalhandler": "~1.1.2",
    + "finalhandler": "1.2.0",
    + "http-errors": "2.0.0",
    - "on-finished": "~2.3.0",
    + "on-finished": "2.4.1",
    - "proxy-addr": "~2.0.5",
    - "qs": "6.7.0",
    + "proxy-addr": "~2.0.7",
    + "qs": "6.11.0",
    - "safe-buffer": "5.1.2",
    - "send": "0.17.1",
    - "serve-static": "1.14.1",
    - "setprototypeof": "1.1.1",
    - "statuses": "~1.5.0",
    + "safe-buffer": "5.2.1",
    + "send": "0.18.0",
    + "serve-static": "1.15.0",
    + "setprototypeof": "1.2.0",
    + "statuses": "2.0.1",
    + },
    + "dependencies": {
    + "safe-buffer": {
    + "version": "5.2.1",
    + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz",
    + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ=="
    + }
    Changed around line 6585
    - "version": "2.0.8",
    - "resolved": "https://registry.npmjs.org/fast-safe-stringify/-/fast-safe-stringify-2.0.8.tgz",
    - "integrity": "sha512-lXatBjf3WPjmWD6DpIZxkeSsCOwqI0maYMpgDlx8g4U2qi4lbjA9oH/HD2a87G+KfsUmo5WbJFmqBZlPxtptag=="
    + "version": "2.1.1",
    + "resolved": "https://registry.npmjs.org/fast-safe-stringify/-/fast-safe-stringify-2.1.1.tgz",
    + "integrity": "sha512-W+KJc2dmILlPplD/H4K9l9LcAHAfPtP6BY84uVLXQ6Evcz9Lcg33Y2z1IVblT6xdY54PXYVHEv+0Wpq8Io6zkA=="
    Changed around line 6599
    - "version": "1.1.2",
    - "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.1.2.tgz",
    - "integrity": "sha512-aAWcW57uxVNrQZqFXjITpW3sIUQmHGG3qSb9mUah9MgMC4NeWhNOlNjXEYq3HjRAvL6arUviZGGJsBg6z0zsWA==",
    + "version": "1.2.0",
    + "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.2.0.tgz",
    + "integrity": "sha512-5uXcUVftlQMFnWC9qu/svkWv3GTd2PfUhK/3PLkYNAe7FbqJMt3515HaxE6eRL74GdsriiwujiawdaB1BpEISg==",
    - "on-finished": "~2.3.0",
    + "on-finished": "2.4.1",
    - "statuses": "~1.5.0",
    + "statuses": "2.0.1",
    Changed around line 6656
    - "version": "3.0.1",
    - "resolved": "https://registry.npmjs.org/form-data/-/form-data-3.0.1.tgz",
    - "integrity": "sha512-RHkBKtLWUVwd7SqRIvCZMEvAMoGUp0XU+seQiZejj0COz3RI3hWP4sCv3gZWWLjJTd7rGwcsF5eKZGii0r/hbg==",
    + "version": "4.0.0",
    + "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz",
    + "integrity": "sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==",
    Changed around line 6666
    - "version": "1.2.2",
    - "resolved": "https://registry.npmjs.org/formidable/-/formidable-1.2.2.tgz",
    - "integrity": "sha512-V8gLm+41I/8kguQ4/o1D3RIHRmhYFG4pnNyonvua+40rqcEmT4+V71yaZ3B457xbbgCsCfjSPi65u/W6vK1U5Q=="
    + "version": "2.1.2",
    + "resolved": "https://registry.npmjs.org/formidable/-/formidable-2.1.2.tgz",
    + "integrity": "sha512-CM3GuJ57US06mlpQ47YcunuUZ9jpm8Vx+P2CGt2j7HpgkKZO/DJYQ0Bobim8G6PFQmK5lOqOOdUXboU+h73A4g==",
    + "requires": {
    + "dezalgo": "^1.0.4",
    + "hexoid": "^1.0.0",
    + "once": "^1.4.0",
    + "qs": "^6.11.0"
    + }
    Changed around line 6689
    - "integrity": "sha1-PYyt2Q2XZWn6g1qx+OSyOhBWBac="
    + "integrity": "sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q=="
    Changed around line 6739
    - "version": "1.1.1",
    - "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.1.1.tgz",
    - "integrity": "sha512-kWZrnVM42QCiEA2Ig1bG8zjoIMOgxWwYCEeNdwY6Tv/cOSeGpcoX4pXHfKUxNKVoArnrEr2e9srnAxxGIraS9Q==",
    + "version": "1.2.0",
    + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.0.tgz",
    + "integrity": "sha512-L049y6nFOuom5wGyRc3/gdTLO94dySVKRACj1RmJZBQXlbTMhtNIgkWkUHq+jYmZvKf14EW1EoJnnjbmoHij0Q==",
    - "has-symbols": "^1.0.1"
    + "has-symbols": "^1.0.3"
    Changed around line 6767
    + "dev": true,
    Changed around line 6829
    - "version": "1.0.2",
    - "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.2.tgz",
    - "integrity": "sha512-chXa79rL/UC2KlX17jo3vRGz0azaWEx5tGqZg5pO3NUyEJVB17dMruQlzCCOfUvElghKcm5194+BCRvi2Rv/Gw=="
    + "version": "1.0.3",
    + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz",
    + "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A=="
    Changed around line 6843
    + "hexoid": {
    + "version": "1.0.0",
    + "resolved": "https://registry.npmjs.org/hexoid/-/hexoid-1.0.0.tgz",
    + "integrity": "sha512-QFLV0taWQOZtvIRIAdBChesmogZrtuXvVWsFHZTk2SU+anspqZ2vMnoLg7IE1+Uk16N19APic1BuF8bC8c2m5g=="
    + },
    Changed around line 6855
    - "version": "1.7.2",
    - "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.7.2.tgz",
    - "integrity": "sha512-uUQBt3H/cSIVfch6i1EuPNy/YsRSOUBXTVfZ+yR7Zjez3qjBz6i9+i4zjNaoqcoFVI4lQJ5plg63TvGfRSDCRg==",
    + "version": "2.0.0",
    + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz",
    + "integrity": "sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==",
    - "depd": "~1.1.2",
    - "inherits": "2.0.3",
    - "setprototypeof": "1.1.1",
    - "statuses": ">= 1.5.0 < 2",
    - "toidentifier": "1.0.0"
    + "depd": "2.0.0",
    + "inherits": "2.0.4",
    + "setprototypeof": "1.2.0",
    + "statuses": "2.0.1",
    + "toidentifier": "1.0.1"
    Changed around line 6901
    + "dev": true,
    - "version": "2.0.3",
    - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz",
    - "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4="
    + "version": "2.0.4",
    + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz",
    + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ=="
    Changed around line 7184
    - "version": "53.8.0",
    - "resolved": "https://registry.npmjs.org/jtree/-/jtree-53.8.0.tgz",
    - "integrity": "sha512-HUtrF+0FMakMGbUktqGlwAkURkaRdSa9WBj1lek3T0INT+S2GdyPoZvtIdVZSBqYhqtTamXSMD7WsTt19x+xuA==",
    - "requires": {
    - "@types/d3-format": "^1.3.1",
    - "d3-format": "^1.3.2",
    - "express": "*",
    - "glob": "^7.1.4",
    - "mkdirp": "^0.5.6",
    - "moment": "^2.29.3",
    - "moment-parseformat": "^3.0.0",
    - "prettier": "^1.18.2",
    + "version": "74.0.0",
    + "resolved": "https://registry.npmjs.org/jtree/-/jtree-74.0.0.tgz",
    + "integrity": "sha512-jKyvI60geVzmtfqahfG4kszQp2zg50N7JvtLTxaRamZpqi3J+a+3UduSEZvzBN8k7qSvcR7rA0TBbXSBinCOPw==",
    + "requires": {
    + "express": "^4.18.2",
    + "glob": "^9.3.4",
    + "mkdirp": "^2.1.6",
    + "prettier": "^2.8.7",
    - "semver": "^6.1.1",
    - "superagent": "^5.1.0"
    + "superagent": "^8.0.9"
    + },
    + "dependencies": {
    + "brace-expansion": {
    + "version": "2.0.1",
    + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz",
    + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==",
    + "requires": {
    + "balanced-match": "^1.0.0"
    + }
    + },
    + "glob": {
    + "version": "9.3.4",
    + "resolved": "https://registry.npmjs.org/glob/-/glob-9.3.4.tgz",
    + "integrity": "sha512-qaSc49hojMOv1EPM4EuyITjDSgSKI0rthoHnvE81tcOi1SCVndHko7auqxdQ14eiQG2NDBJBE86+2xIrbIvrbA==",
    + "requires": {
    + "fs.realpath": "^1.0.0",
    + "minimatch": "^8.0.2",
    + "minipass": "^4.2.4",
    + "path-scurry": "^1.6.1"
    + }
    + },
    + "minimatch": {
    + "version": "8.0.3",
    + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-8.0.3.tgz",
    + "integrity": "sha512-tEEvU9TkZgnFDCtpnrEYnPsjT7iUx42aXfs4bzmQ5sMA09/6hZY0jeZcGkXyDagiBOvkUjNo8Viom+Me6+2x7g==",
    + "requires": {
    + "brace-expansion": "^2.0.1"
    + }
    + },
    + "minipass": {
    + "version": "4.2.5",
    + "resolved": "https://registry.npmjs.org/minipass/-/minipass-4.2.5.tgz",
    + "integrity": "sha512-+yQl7SX3bIT83Lhb4BVorMAHVuqsskxRdlmO9kTpyukp8vsm2Sn/fUOV9xlnG8/a5JsypJzap21lz/y3FBMJ8Q=="
    + }
    Changed around line 7294
    - "version": "6.0.0",
    - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz",
    - "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==",
    - "requires": {
    - "yallist": "^4.0.0"
    - }
    + "version": "7.18.3",
    + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-7.18.3.tgz",
    + "integrity": "sha512-jumlc0BIUrS3qJGgIkWZsyfAM7NCWiBcCDhnd+3NNM5KbBmLTgHVfWBcg6W+rLUsIpzpERPsvwUP7CckAQSOoA=="
    Changed around line 7326
    - "integrity": "sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g="
    + "integrity": "sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ=="
    - "integrity": "sha1-sAqqVW3YtEVoFQ7J0blT8/kMu2E="
    + "integrity": "sha512-cCi6g3/Zr1iqQi6ySbseM1Xvooa98N0w31jzUYrXPX2xqObmFGHJ0tQ5u74H3mVh7wLouTseZyYIq39g8cNp1w=="
    - "integrity": "sha1-VSmk1nZUE07cxSZmVoNbD4Ua/O4="
    + "integrity": "sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w=="
    Changed around line 7344
    - "version": "1.48.0",
    - "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.48.0.tgz",
    - "integrity": "sha512-FM3QwxV+TnZYQ2aRqhlKBMHxk10lTbMt3bBkMAp54ddrNeVSfcQYOOKuGuy3Ddrm38I04If834fOUSq1yzslJQ=="
    + "version": "1.52.0",
    + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz",
    + "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg=="
    - "version": "2.1.31",
    - "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.31.tgz",
    - "integrity": "sha512-XGZnNzm3QvgKxa8dpzyhFTHmpP3l5YNusmne07VUOXxou9CqUqYa/HBy124RqtVh/O2pECas/MOcsDgpilPOPg==",
    + "version": "2.1.35",
    + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz",
    + "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==",
    - "mime-db": "1.48.0"
    + "mime-db": "1.52.0"
    + "dev": true,
    Changed around line 7380
    - "version": "0.5.6",
    - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.6.tgz",
    - "integrity": "sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==",
    - "requires": {
    - "minimist": "^1.2.6"
    - }
    - },
    - "moment": {
    - "version": "2.29.4",
    - "resolved": "https://registry.npmjs.org/moment/-/moment-2.29.4.tgz",
    - "integrity": "sha512-5LC9SOxjSc2HF6vO2CyuTDNivEdoz2IvyJJGj6X8DJ0eFyfszE0QiEd+iXmBvUP3WHxSjFH/vIsA0EN00cgr8w=="
    - },
    - "moment-parseformat": {
    - "version": "3.1.1",
    - "resolved": "https://registry.npmjs.org/moment-parseformat/-/moment-parseformat-3.1.1.tgz",
    - "integrity": "sha512-uEkXh5w9WDM8xNksZYeGpbZgrcG9qlpTg+f4ftHyOIis4+U08p31zOUzk3YCv2n+c6MUpW+Nb3GLCpjoEuHqJw=="
    + "version": "2.1.6",
    + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-2.1.6.tgz",
    + "integrity": "sha512-+hEnITedc8LAtIP9u3HJDFIdcLV2vXP33sqLLIzkv1Db1zO/1OxbvYf0Y1OC/S/Qo5dxHXepofhmxL02PsKe+A=="
    - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g="
    + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A=="
    - "version": "0.6.2",
    - "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.2.tgz",
    - "integrity": "sha512-hZXc7K2e+PgeI1eDBe/10Ard4ekbfrrqG8Ep+8Jmf4JID2bNg7NvCPOZN+kfF574pFQI7mum2AUqDidoKqcTOw=="
    + "version": "0.6.3",
    + "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz",
    + "integrity": "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg=="
    Changed around line 7469
    - "version": "1.11.0",
    - "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.11.0.tgz",
    - "integrity": "sha512-jp7ikS6Sd3GxQfZJPyH3cjcbJF6GZPClgdV+EFygjFLQ5FmW/dRUnTd9PQ9k0JhoNDabWFbpF1yCdSWCC6gexg=="
    + "version": "1.12.3",
    + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.12.3.tgz",
    + "integrity": "sha512-geUvdk7c+eizMNUDkRpW1wJwgfOiOeHbxBR/hLXK1aT6zmVSO0jsQcs7fj6MGw89jC/cjGfLcNOrtMYtGqm81g=="
    - "version": "2.3.0",
    - "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz",
    - "integrity": "sha1-IPEzZIGwg811M3mSoWlxqi2QaUc=",
    + "version": "2.4.1",
    + "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz",
    + "integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==",
    Changed around line 7569
    - "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18="
    + "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=",
    + "dev": true
    Changed around line 7578
    + "path-scurry": {
    + "version": "1.6.3",
    + "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-1.6.3.tgz",
    + "integrity": "sha512-RAmB+n30SlN+HnNx6EbcpoDy9nwdpcGPnEKrJnu6GZoDWBdIjo1UQMVtW2ybtC7LC2oKLcMq8y5g8WnKLiod9g==",
    + "requires": {
    + "lru-cache": "^7.14.1",
    + "minipass": "^4.0.2"
    + },
    + "dependencies": {
    + "minipass": {
    + "version": "4.2.5",
    + "resolved": "https://registry.npmjs.org/minipass/-/minipass-4.2.5.tgz",
    + "integrity": "sha512-+yQl7SX3bIT83Lhb4BVorMAHVuqsskxRdlmO9kTpyukp8vsm2Sn/fUOV9xlnG8/a5JsypJzap21lz/y3FBMJ8Q=="
    + }
    + }
    + },
    - "integrity": "sha1-32BBeABfUi8V60SQ5yR6G/qmf4w="
    + "integrity": "sha512-5DFkuoqlv1uYQKxy8omFBeJPQcdoE07Kv2sferDCrAq1ohOU+MSDswDIbnx3YAM60qIOnYa53wBhXW0EbMonrQ=="
    Changed around line 7621
    - "version": "1.19.1",
    - "resolved": "https://registry.npmjs.org/prettier/-/prettier-1.19.1.tgz",
    - "integrity": "sha512-s7PoyDv/II1ObgQunCbB9PdLmUcBZcnWOcxDh7O0N/UwDEsHyqkW+Qh28jW+mVuCdx7gLB0BotYI1Y6uI9iyew=="
    + "version": "2.8.7",
    + "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.8.7.tgz",
    + "integrity": "sha512-yPngTo3aXUUmyuTjeTUT75txrf+aMh9FiD7q9ZE/i6r0bPb22g4FsE6Y338PQX1bmfy08i9QQCB7/rcUAVntfw=="
    Changed around line 7667
    - "version": "6.7.0",
    - "resolved": "https://registry.npmjs.org/qs/-/qs-6.7.0.tgz",
    - "integrity": "sha512-VCdBRNFTX1fyE7Nb6FYoURo/SPe62QCaAyzJvUjwRaIsc+NePBEniHlvxFmmX56+HZphIGtV0XeCirBtpDrTyQ=="
    + "version": "6.11.0",
    + "resolved": "https://registry.npmjs.org/qs/-/qs-6.11.0.tgz",
    + "integrity": "sha512-MvjoMCJwEarSbUYk5O+nmoSzSutSsTwF85zcHPQ9OrlFoZOYIjaqBAJIqIXjptyD5vThxGq52Xu/MaJzRkIk4Q==",
    + "requires": {
    + "side-channel": "^1.0.4"
    + }
    Changed around line 7680
    - "version": "2.4.0",
    - "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.4.0.tgz",
    - "integrity": "sha512-4Oz8DUIwdvoa5qMJelxipzi/iJIi40O5cGV1wNYp5hvZP8ZN0T+jiNkL0QepXs+EsQ9XJ8ipEDoiH70ySUJP3Q==",
    + "version": "2.5.1",
    + "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.1.tgz",
    + "integrity": "sha512-qqJBtEyVgS0ZmPGdCFPWJ3FreoqvG4MVQln/kCgF7Olq95IbOp0/BWyMwbdtn4VTvkM8Y7khCQ2Xgk/tcrCXig==",
    - "bytes": "3.1.0",
    - "http-errors": "1.7.2",
    + "bytes": "3.1.2",
    + "http-errors": "2.0.0",
    Changed around line 7707
    - "readable-stream": {
    - "version": "3.6.0",
    - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz",
    - "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==",
    - "requires": {
    - "inherits": "^2.0.3",
    - "string_decoder": "^1.1.1",
    - "util-deprecate": "^1.0.1"
    - }
    - },
    Changed around line 7812
    - "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g=="
    + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==",
    + "dev": true
    Changed around line 7828
    - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw=="
    + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==",
    + "dev": true
    - "version": "0.17.1",
    - "resolved": "https://registry.npmjs.org/send/-/send-0.17.1.tgz",
    - "integrity": "sha512-BsVKsiGcQMFwT8UxypobUKyv7irCNRHk1T0G680vk88yf6LBByGcZJOTJCrTP2xVN6yI+XjPJcNuE3V4fT9sAg==",
    + "version": "0.18.0",
    + "resolved": "https://registry.npmjs.org/send/-/send-0.18.0.tgz",
    + "integrity": "sha512-qqWzuOjSFOuqPjFe4NOsMLafToQQwBSOEpS+FwEt3A2V3vKubTquT3vmLTQpFgMXp8AlFWFuP1qKaJZOtPpVXg==",
    - "depd": "~1.1.2",
    - "destroy": "~1.0.4",
    + "depd": "2.0.0",
    + "destroy": "1.2.0",
    - "http-errors": "~1.7.2",
    + "http-errors": "2.0.0",
    - "ms": "2.1.1",
    - "on-finished": "~2.3.0",
    + "ms": "2.1.3",
    + "on-finished": "2.4.1",
    - "statuses": "~1.5.0"
    + "statuses": "2.0.1"
    - "version": "2.1.1",
    - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.1.tgz",
    - "integrity": "sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg=="
    + "version": "2.1.3",
    + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
    + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA=="
    - "version": "1.14.1",
    - "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.14.1.tgz",
    - "integrity": "sha512-JMrvUwE54emCYWlTI+hGrGv5I8dEwmco/00EvkzIIsR7MqrHonbD9pO2MOfFnpFntl7ecpZs+3mW+XbQZu9QCg==",
    + "version": "1.15.0",
    + "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.15.0.tgz",
    + "integrity": "sha512-XGuRDNjXUijsUL0vl6nSD7cwURuzEgglbOaFuZM9g3kwDXOWVTck0jLzjPzGD+TazWbboZYu52/9/XPdUgne9g==",
    - "send": "0.17.1"
    + "send": "0.18.0"
    Changed around line 7876
    - "version": "1.1.1",
    - "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.1.tgz",
    - "integrity": "sha512-JvdAWfbXeIGaZ9cILp38HntZSFSo3mWg6xGcJJsd+d4aRMOqauag1C63dJfDw7OaMYwEbHMOxEZ1lqVRYP2OAw=="
    + "version": "1.2.0",
    + "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz",
    + "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw=="
    Changed around line 7982
    - "version": "1.5.0",
    - "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz",
    - "integrity": "sha1-Fhx9rBd2Wf2YEfQ3cfqZOBR4Yow="
    - },
    - "string_decoder": {
    - "version": "1.3.0",
    - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz",
    - "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==",
    - "requires": {
    - "safe-buffer": "~5.2.0"
    - },
    - "dependencies": {
    - "safe-buffer": {
    - "version": "5.2.1",
    - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz",
    - "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ=="
    - }
    - }
    + "version": "2.0.1",
    + "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz",
    + "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ=="
    Changed around line 8012
    - "version": "5.3.1",
    - "resolved": "https://registry.npmjs.org/superagent/-/superagent-5.3.1.tgz",
    - "integrity": "sha512-wjJ/MoTid2/RuGCOFtlacyGNxN9QLMgcpYLDQlWFIhhdJ93kNscFonGvrpAHSCVjRVj++DGCglocF7Aej1KHvQ==",
    + "version": "8.0.9",
    + "resolved": "https://registry.npmjs.org/superagent/-/superagent-8.0.9.tgz",
    + "integrity": "sha512-4C7Bh5pyHTvU33KpZgwrNKh/VQnvgtCSqPRfJAUdmrtSYePVzVg4E4OzsrbkhJj9O7SO6Bnv75K/F8XVZT8YHA==",
    - "cookiejar": "^2.1.2",
    - "debug": "^4.1.1",
    - "fast-safe-stringify": "^2.0.7",
    - "form-data": "^3.0.0",
    - "formidable": "^1.2.2",
    + "cookiejar": "^2.1.4",
    + "debug": "^4.3.4",
    + "fast-safe-stringify": "^2.1.1",
    + "form-data": "^4.0.0",
    + "formidable": "^2.1.2",
    - "mime": "^2.4.6",
    - "qs": "^6.9.4",
    - "readable-stream": "^3.6.0",
    - "semver": "^7.3.2"
    + "mime": "2.6.0",
    + "qs": "^6.11.0",
    + "semver": "^7.3.8"
    - "version": "4.3.2",
    - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.2.tgz",
    - "integrity": "sha512-mOp8wKcvj7XxC78zLgw/ZA+6TSgkoE2C/ienthhRD298T7UNwAg9diBpLRxC0mOezLl4B0xV7M0cCO6P/O0Xhw==",
    + "version": "4.3.4",
    + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz",
    + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==",
    + "lru-cache": {
    + "version": "6.0.0",
    + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz",
    + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==",
    + "requires": {
    + "yallist": "^4.0.0"
    + }
    + },
    - "version": "2.5.2",
    - "resolved": "https://registry.npmjs.org/mime/-/mime-2.5.2.tgz",
    - "integrity": "sha512-tqkh47FzKeCPD2PUiPB6pkbMzsCasjxAfC62/Wap5qrUWcb+sFasXUC5I3gYM5iBM8v/Qpn4UK0x+j0iHyFPDg=="
    + "version": "2.6.0",
    + "resolved": "https://registry.npmjs.org/mime/-/mime-2.6.0.tgz",
    + "integrity": "sha512-USPkMeET31rOMiarsBNIHZKLGgvKc/LrjofAnBlOttf5ajRvqiRA8QsenbcooctK6d6Ts6aqZXBA+XbkKthiQg=="
    - "qs": {
    - "version": "6.10.1",
    - "resolved": "https://registry.npmjs.org/qs/-/qs-6.10.1.tgz",
    - "integrity": "sha512-M528Hph6wsSVOBiYUnGf+K/7w0hNshs/duGsNXPUCLH5XAqjEtiPGwNONLV0tBH8NoGb0mvD5JubnUTrujKDTg==",
    - "requires": {
    - "side-channel": "^1.0.4"
    - }
    - },
    - "version": "7.3.5",
    - "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.5.tgz",
    - "integrity": "sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==",
    + "version": "7.3.8",
    + "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.8.tgz",
    + "integrity": "sha512-NB1ctGL5rlHrPJtFDVIVzTyQylMLu9N9VICA6HSFJo8MCGVTMW6gfpicwKmmK/dAjTOrqu5l63JJOpDSrAis3A==",
    Changed around line 9493
    - "version": "1.0.0",
    - "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.0.tgz",
    - "integrity": "sha512-yaOH/Pk/VEhBWWTlhI+qXxDFXlejDGcQipMlyxda9nthulaxLZUNcUqFxokp0vcYnvteJln5FNQDRrxj3YcbVw=="
    + "version": "1.0.1",
    + "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz",
    + "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA=="
    Changed around line 9587
    - "integrity": "sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw="
    + "integrity": "sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ=="
    Changed around line 9598
    - "util-deprecate": {
    - "version": "1.0.2",
    - "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz",
    - "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8="
    - },
    - "integrity": "sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM="
    + "integrity": "sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA=="
    Changed around line 9612
    - "integrity": "sha1-IpnwLG3tMNSllhsLn3RSShj2NPw="
    + "integrity": "sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg=="
    package.json
    Changed around line 23
    - "jtree": "^53.8.0",
    + "jtree": "^74.0.0",
    Changed around line 32
    + "build": "./build.js",
    + "local": "./server.js",
    readme.scroll
    Changed around line 54: startColumns 2
    - 1. Start the dev server with `node server.js`.
    + 1. Start the dev server with `npm run local`.
    server.js
    Changed around line 4: const express = require("express")
    - const { jtree } = require("jtree")
    + const { TreeNode } = require("jtree/products/TreeNode.js")
    simoji.grammar
    Changed around line 46: propertyNameCell
    - errorNode
    - baseNodeType errorNode
    - simojiNode
    + errorParser
    + baseParser errorParser
    + simojiParser
    - inScope abstractIgnoreNode abstractSetupNode abstractInjectCommandNode onTickNode onExtinctNode behaviorDefinitionNode experimentNode settingDefinitionNode
    - catchAllNodeType agentDefinitionNode
    + inScope abstractIgnoreParser abstractSetupParser abstractInjectCommandParser onTickParser onExtinctParser behaviorDefinitionParser experimentParser settingDefinitionParser
    + catchAllParser agentDefinitionParser
    Changed around line 69: simojiNode
    - return this.filter(node => node.getNodeTypeId() === "agentDefinitionNode")
    + return this.filter(node => node.parserId === "agentDefinitionParser")
    - experimentNode
    - crux experiment
    + experimentParser
    + cruxFromId
    - inScope abstractIgnoreNode abstractSetupNode abstractInjectCommandNode onTickNode onExtinctNode settingDefinitionNode
    + inScope abstractIgnoreParser abstractSetupParser abstractInjectCommandParser onTickParser onExtinctParser settingDefinitionParser
    - abstractSetupNode
    - atTimeNode
    - crux atTime
    + abstractSetupParser
    + atTimeParser
    + cruxFromId
    - extends abstractSetupNode
    - inScope abstractInjectCommandNode
    - abstractSetupNumberNode
    + extends abstractSetupParser
    + inScope abstractInjectCommandParser
    + abstractSetupNumberParser
    - extends abstractSetupNode
    + extends abstractSetupParser
    - sizeNode
    + sizeParser
    - extends abstractSetupNumberNode
    - crux size
    - rowsNode
    + extends abstractSetupNumberParser
    + cruxFromId
    + rowsParser
    - extends abstractSetupNumberNode
    - crux rows
    - columnsNode
    + extends abstractSetupNumberParser
    + cruxFromId
    + columnsParser
    - extends abstractSetupNumberNode
    - crux columns
    - seedNode
    + extends abstractSetupNumberParser
    + cruxFromId
    + seedParser
    - extends abstractSetupNumberNode
    - crux seed
    - ticksPerSecondNode
    + extends abstractSetupNumberParser
    + cruxFromId
    + ticksPerSecondParser
    - extends abstractSetupNumberNode
    - crux ticksPerSecond
    - reportNode
    - crux report
    + extends abstractSetupNumberParser
    + cruxFromId
    + reportParser
    + cruxFromId
    - catchAllNodeType ohayoLineNode
    - extends abstractSetupNode
    + catchAllParser ohayoLineParser
    + extends abstractSetupParser
    - styleNode
    + styleParser
    - extends abstractSetupNode
    + extends abstractSetupParser
    - crux style
    - catchAllNodeType styleLineNode
    + cruxFromId
    + catchAllParser styleLineParser
    - questionNode
    - crux question
    + questionParser
    + cruxFromId
    - extends abstractSetupNode
    - abstractInjectCommandNode
    - fillNode
    + extends abstractSetupParser
    + abstractInjectCommandParser
    + fillParser
    - extends abstractInjectCommandNode
    + extends abstractInjectCommandParser
    - crux fill
    - drawNode
    - extends abstractInjectCommandNode
    + cruxFromId
    + drawParser
    + extends abstractInjectCommandParser
    - crux draw
    - catchAllNodeType drawLineNode
    - insertNode
    - extends abstractInjectCommandNode
    + cruxFromId
    + catchAllParser drawLineParser
    + insertParser
    + extends abstractInjectCommandParser
    - crux insert
    - insertAtNode
    - extends insertNode
    + cruxFromId
    + insertAtParser
    + extends insertParser
    - crux insertAt
    - insertClusterNode
    - extends insertNode
    - crux insertCluster
    + cruxFromId
    + insertClusterParser
    + extends insertParser
    + cruxFromId
    - rectangleDrawNode
    - extends abstractInjectCommandNode
    + rectangleDrawParser
    + extends abstractInjectCommandParser
    - pasteDrawNode
    - extends abstractInjectCommandNode
    + pasteDrawParser
    + extends abstractInjectCommandParser
    - catchAllNodeType pasteLineNode
    - drawLineNode
    + catchAllParser pasteLineParser
    + drawLineParser
    - pasteLineNode
    + pasteLineParser
    - catchAllNodeType pasteLineNode
    - agentDefinitionNode
    - inScope abstractIgnoreNode abstractEventNode abstractAgentAttributeNode abstractBehaviorAttributeNode
    + catchAllParser pasteLineParser
    + agentDefinitionParser
    + inScope abstractIgnoreParser abstractEventParser abstractAgentAttributeParser behaviorAttributeParser
    - catchAllNodeType errorNode
    + catchAllParser errorParser
    - const root = this.getRootNode()
    - const name = root.agentKeywordMap[this.getWord(0)]
    + const root = this.root
    + const name = root.agentKeywordMap[this.firstWord]
    - const behaviors = this.filter(node => node.getNodeTypeId() === "abstractBehaviorAttributeNode")
    + const behaviors = this.filter(node => node.parserId === "behaviorAttributeParser")
    - icon = "${this.getWord(0)}"
    + icon = "${this.firstWord}"
    - abstractCommandNode
    + abstractCommandParser
    - abstractSubjectObjectCommandNode
    - extends abstractCommandNode
    - replaceWithCommandNode
    - extends abstractSubjectObjectCommandNode
    + abstractSubjectObjectCommandParser
    + extends abstractCommandParser
    + replaceWithCommandParser
    + extends abstractSubjectObjectCommandParser
    - kickItCommandNode
    - extends abstractSubjectObjectCommandNode
    + kickItCommandParser
    + extends abstractSubjectObjectCommandParser
    - shootCommandNode
    - extends abstractSubjectObjectCommandNode
    + shootCommandParser
    + extends abstractSubjectObjectCommandParser
    - pickItUpCommandNode
    - extends abstractSubjectObjectCommandNode
    + pickItUpCommandParser
    + extends abstractSubjectObjectCommandParser
    - spawnCommandNode
    + spawnCommandParser
    - extends abstractCommandNode
    + extends abstractCommandParser
    - moveToEmptySpotCommandNode
    + moveToEmptySpotCommandParser
    - extends abstractCommandNode
    + extends abstractCommandParser
    - removeCommandNode
    + removeCommandParser
    - extends abstractCommandNode
    + extends abstractCommandParser
    - javascriptCommandNode
    + javascriptCommandParser
    - extends abstractCommandNode
    + extends abstractCommandParser
    - catchAllNodeType javascriptLineNode
    + catchAllParser javascriptLineParser
    - alertCommandNode
    - extends abstractCommandNode
    + alertCommandParser
    + extends abstractCommandParser
    - logCommandNode
    - extends abstractCommandNode
    + logCommandParser
    + extends abstractCommandParser
    - narrateCommandNode
    - extends abstractCommandNode
    + narrateCommandParser
    + extends abstractCommandParser
    - pauseCommandNode
    - extends abstractCommandNode
    + pauseCommandParser
    + extends abstractCommandParser
    - decreaseCommandNode
    - extends abstractCommandNode
    + decreaseCommandParser
    + extends abstractCommandParser
    - increaseCommandNode
    - extends abstractCommandNode
    + increaseCommandParser
    + extends abstractCommandParser
    - moveCommandNode
    - extends abstractCommandNode
    + moveCommandParser
    + extends abstractCommandParser
    - turnRandomlyCommandNode
    - extends abstractCommandNode
    + turnRandomlyCommandParser
    + extends abstractCommandParser
    - jitterCommandNode
    - extends abstractCommandNode
    + jitterCommandParser
    + extends abstractCommandParser
    - turnTowardCommandNode
    + turnTowardCommandParser
    - extends abstractCommandNode
    + extends abstractCommandParser
    - turnFromCommandNode
    + turnFromCommandParser
    - extends abstractCommandNode
    + extends abstractCommandParser
    - learnCommandNode
    + learnCommandParser
    - extends abstractCommandNode
    + extends abstractCommandParser
    - unlearnCommandNode
    + unlearnCommandParser
    - extends abstractCommandNode
    + extends abstractCommandParser
    - abstractAgentAttributeNode
    + abstractAgentAttributeParser
    - abstractStringAttributeNode
    - extends abstractAgentAttributeNode
    + stringAttributeParser
    + extends abstractAgentAttributeParser
    - return `${this.getWord(0)} = "${this.getWord(1)}"`
    + return `${this.firstWord} = "${this.getWord(1)}"`
    - angleNode
    - extends abstractStringAttributeNode
    + angleParser
    + extends stringAttributeParser
    - crux angle
    - agentStyleNode
    + cruxFromId
    + agentStyleParser
    - extends abstractStringAttributeNode
    + extends stringAttributeParser
    - agentHtmlNode
    + agentHtmlParser
    - extends abstractStringAttributeNode
    + extends stringAttributeParser
    - abstractBooleanAttributeNode
    + abstractBooleanAttributeParser
    - extends abstractAgentAttributeNode
    + extends abstractAgentAttributeParser
    - return `${this.getWord(0)} = true`
    + return `${this.firstWord} = true`
    - noPaletteNode
    - extends abstractBooleanAttributeNode
    + noPaletteParser
    + extends abstractBooleanAttributeParser
    - solidTraitNode
    + solidTraitParser
    - extends abstractBooleanAttributeNode
    + extends abstractBooleanAttributeParser
    - bouncyTraitNode
    + bouncyTraitParser
    - extends abstractBooleanAttributeNode
    + extends abstractBooleanAttributeParser
    - abstractIntegerAttributeNode
    - extends abstractAgentAttributeNode
    + abstractIntegerAttributeParser
    + extends abstractAgentAttributeParser
    - return `${this.getWord(0)} = ${this.getWord(1)}`
    + return `${this.firstWord} = ${this.getWord(1)}`
    - customIntegerAttributeNode
    + customIntegerAttributeParser
    - extends abstractIntegerAttributeNode
    - healthNode
    - extends abstractIntegerAttributeNode
    - crux health
    - settingDefinitionNode
    + extends abstractIntegerAttributeParser
    + healthParser
    + extends abstractIntegerAttributeParser
    + cruxFromId
    + settingDefinitionParser
    - ohayoLineNode
    + ohayoLineParser
    - styleLineNode
    + styleLineParser
    - catchAllNodeType styleLineNode
    - targetEmojiNode
    - inScope abstractCommandNode
    + catchAllParser styleLineParser
    + targetEmojiParser
    + inScope abstractCommandParser
    - abstractEventNode
    + abstractEventParser
    - abstractInteractionEventNode
    - extends abstractEventNode
    - catchAllNodeType targetEmojiNode
    - onHitNode
    - extends abstractInteractionEventNode
    - crux onHit
    + abstractInteractionEventParser
    + extends abstractEventParser
    + catchAllParser targetEmojiParser
    + onHitParser
    + extends abstractInteractionEventParser
    + cruxFromId
    - onTouchNode
    - extends abstractInteractionEventNode
    - crux onTouch
    + onTouchParser
    + extends abstractInteractionEventParser
    + cruxFromId
    - onNeighborsNode
    + onNeighborsParser
    - extends abstractInteractionEventNode
    - inScope emojiAndNeighborConditionNode
    - crux onNeighbors
    - onDeathNode
    - extends abstractEventNode
    - crux onDeath
    - inScope abstractCommandNode
    + extends abstractInteractionEventParser
    + inScope emojiAndNeighborConditionParser
    + cruxFromId
    + onDeathParser
    + extends abstractEventParser
    + cruxFromId
    + inScope abstractCommandParser
    - onTickNode
    - extends abstractEventNode
    - crux onTick
    - inScope abstractCommandNode
    + onTickParser
    + extends abstractEventParser
    + cruxFromId
    + inScope abstractCommandParser
    - emojiAndNeighborConditionNode
    - inScope abstractCommandNode
    + emojiAndNeighborConditionParser
    + inScope abstractCommandParser
    - onExtinctNode
    - crux onExtinct
    - inScope abstractCommandNode
    + onExtinctParser
    + cruxFromId
    + inScope abstractCommandParser
    - abstractIgnoreNode
    + abstractIgnoreParser
    - commentNode
    - extends abstractIgnoreNode
    + commentParser
    + extends abstractIgnoreParser
    - crux comment
    - catchAllNodeType commentLineNode
    - commentAliasNode
    + cruxFromId
    + catchAllParser commentLineParser
    + commentAliasParser
    - extends commentNode
    - blankLineNode
    - extends abstractIgnoreNode
    + extends commentParser
    + blankLineParser
    + extends abstractIgnoreParser
    - commentLineNode
    + commentLineParser
    - javascriptLineNode
    + javascriptLineParser
    - abstractBehaviorAttributeNode
    + behaviorAttributeParser
    - behaviorDefinitionNode
    - inScope abstractIgnoreNode abstractEventNode
    + behaviorDefinitionParser
    + inScope abstractIgnoreParser abstractEventParser
    - catchAllNodeType errorNode
    + catchAllParser errorParser
    yodash.js
    Changed around line 1
    - const { Directions, NodeTypes } = require("./components/Types.js")
    + const { Utils } = require("jtree/products/Utils.js")
    + const { Directions, ParserTypes } = require("./components/Types.js")
    Changed around line 34: yodash.compare = (left, operator, right) => {
    - clone.filter(node => node.getNodeTypeId() !== NodeTypes.agentDefinitionNode).forEach(node => node.destroy())
    + clone.filter(node => node.parserId !== ParserTypes.agentDefinitionParser).forEach(node => node.destroy())
    - clone.agentTypes.forEach((node, index) => (clone.agentKeywordMap[node.getWord(0)] = `simAgent${index}`))
    + clone.agentTypes.forEach((node, index) => (clone.agentKeywordMap[node.firstWord] = `simAgent${index}`))
    Changed around line 49: yodash.compileAgentClassDeclarationsAndMap = program => {
    - clone.filter(node => node.getNodeTypeId() === NodeTypes.experimentNode).forEach(node => node.destroy())
    + clone.filter(node => node.parserId === ParserTypes.experimentParser).forEach(node => node.destroy())
    - .filter(node => node.getNodeTypeId() === NodeTypes.settingDefinitionNode)
    + .filter(node => node.parserId === ParserTypes.settingDefinitionParser)
    - symbolTable[node.getWord(0)] = node.getContent()
    + symbolTable[node.firstWord] = node.content
    Changed around line 201: yodash.draw = str => {
    - occupiedSpots.add(yodash.makePositionHash(yodash.parsePosition(line.getWords())))
    + occupiedSpots.add(yodash.makePositionHash(yodash.parsePosition(line.words)))
    Changed around line 270: const shuffleArray = (array, randomNumberGenerator) => {
    - const map = TreeUtils.arrayToMap(fields)
    + const map = Utils.arrayToMap(fields)
    - if (!map[node.getWord(0)]) node.destroy()
    + if (!map[node.firstWord]) node.destroy()
    - const newTree = new jtree.TreeNode()
    + const newTree = new TreeNode()
    Breck Yunits
    Breck Yunits
    1 year ago
    Link update
    cheatSheet.scroll
    Changed around line 5: title Simoji Quickstart Guide
    - https://github.com/publicdomaincompany/simoji open source
    + https://github.com/breck7/simoji open source
    Changed around line 120: pipeTable
    - https://github.com/publicdomaincompany/simoji Github
    + https://github.com/breck7/simoji Github
    components/SimojiApp.js
    Changed around line 32: const MIN_GRID_ROWS = 10
    - githubLink = `https://github.com/publicdomaincompany/simoji`
    + githubLink = `https://github.com/breck7/simoji`
    package.json
    Changed around line 17
    + "engineStrict": true,
    Changed around line 38
    - "url": "git+https://github.com/publicdomaincompany/simoji.git"
    + "url": "git+https://github.com/breck7/simoji.git"
    - "url": "https://github.com/publicdomaincompany/simoji/issues"
    + "url": "https://github.com/breck7/simoji/issues"
    - "homepage": "https://github.com/publicdomaincompany/simoji#readme"
    + "homepage": "https://github.com/breck7/simoji#readme"
    Breck Yunits
    Breck Yunits
    1 year ago
    Prettier
    build.js
    Changed around line 27: ourPaths.unshift(__dirname + "/yodash.js")
    - .map(path => {
    - const code = Disk.read(path)
    + .map(path => {
    + const code = Disk.read(path)
    - return new TypeScriptRewriter(code)
    - .removeRequires()
    - .removeNodeJsOnlyLines()
    - .changeNodeExportsToWindowExports()
    - .getString()
    - })
    - .join("\n\n")
    + return new TypeScriptRewriter(code)
    + .removeRequires()
    + .removeNodeJsOnlyLines()
    + .changeNodeExportsToWindowExports()
    + .getString()
    + })
    + .join("\n\n")
    - grammar: Disk.read(__dirname + "/simoji.grammar"),
    - examples: getExamples()
    + grammar: Disk.read(__dirname + "/simoji.grammar"),
    + examples: getExamples()
    cli.js
    Changed around line 9: const VERSION = packageJson.version
    - execute(args = []) {
    - this.log(`\n🧫🧫🧫 WELCOME TO SIMOJI (v${VERSION}) 🧫🧫🧫`)
    - const command = args[0]
    - const filename = args[1]
    - const commandName = `${command}${CommandFnDecoratorSuffix}`
    - const cwd = process.cwd()
    - if (this[commandName]) return this[commandName](cwd, filename)
    -
    - if (Disk.exists(cwd + "/" + command)) return this.runCommand(cwd, command)
    -
    - if (!command) this.log(`\nNo command provided. Running help command.`)
    - else this.log(`\nUnknown command or file '${commandName}' provided. Running help command.`)
    - return this.helpCommand()
    - }
    -
    - get _allCommands() {
    - return Object.getOwnPropertyNames(Object.getPrototypeOf(this))
    - .filter(word => word.endsWith(CommandFnDecoratorSuffix))
    - .sort()
    - }
    -
    - async runCommand(cwd, filename) {
    - const fullPath = cwd + "/" + filename
    - if (!Disk.exists(fullPath)) return this.log(`❌ file '${fullPath}' not found.`)
    - this.log(`\n⏳ Running '${fullPath}'...\n`)
    - const code = Disk.read(filename)
    - const app = SimojiApp.setupApp(code)
    - app.verbose = false
    - await app.runUntilPause()
    - }
    -
    - helpCommand() {
    - return this.log(
    - `\nThis is the Simoji help page.\n\nCommands you can run:\n\n${this._allCommands
    - .map(comm => `➡️ ` + comm.replace(CommandFnDecoratorSuffix, ""))
    - .join("\n")}\n`
    - )
    - }
    -
    - verbose = true
    - log(message) {
    - if (this.verbose) console.log(message)
    - return message
    - }
    + execute(args = []) {
    + this.log(`\n🧫🧫🧫 WELCOME TO SIMOJI (v${VERSION}) 🧫🧫🧫`)
    + const command = args[0]
    + const filename = args[1]
    + const commandName = `${command}${CommandFnDecoratorSuffix}`
    + const cwd = process.cwd()
    + if (this[commandName]) return this[commandName](cwd, filename)
    +
    + if (Disk.exists(cwd + "/" + command)) return this.runCommand(cwd, command)
    +
    + if (!command) this.log(`\nNo command provided. Running help command.`)
    + else this.log(`\nUnknown command or file '${commandName}' provided. Running help command.`)
    + return this.helpCommand()
    + }
    +
    + get _allCommands() {
    + return Object.getOwnPropertyNames(Object.getPrototypeOf(this))
    + .filter(word => word.endsWith(CommandFnDecoratorSuffix))
    + .sort()
    + }
    +
    + async runCommand(cwd, filename) {
    + const fullPath = cwd + "/" + filename
    + if (!Disk.exists(fullPath)) return this.log(`❌ file '${fullPath}' not found.`)
    + this.log(`\n⏳ Running '${fullPath}'...\n`)
    + const code = Disk.read(filename)
    + const app = SimojiApp.setupApp(code)
    + app.verbose = false
    + await app.runUntilPause()
    + }
    +
    + helpCommand() {
    + return this.log(
    + `\nThis is the Simoji help page.\n\nCommands you can run:\n\n${this._allCommands
    + .map(comm => `➡️ ` + comm.replace(CommandFnDecoratorSuffix, ""))
    + .join("\n")}\n`
    + )
    + }
    +
    + verbose = true
    + log(message) {
    + if (this.verbose) console.log(message)
    + return message
    + }
    components/RightBar.js
    Changed around line 3: const { jtree } = require("jtree")
    - createParser() {
    - return new jtree.TreeNode.Parser(undefined, {
    - AgentPaletteComponent
    - })
    - }
    + createParser() {
    + return new jtree.TreeNode.Parser(undefined, {
    + AgentPaletteComponent
    + })
    + }
    components/SimojiApp.test.node.js
    Changed around line 11: const simojiCompiler = jtree.compileGrammarFileAtPathAndReturnRootConstructor(gr
    - const errs = new grammarNode(Disk.read(grammarPath)).getAllErrors().map(err => err.toObject())
    - if (errs.length) console.log(new jtree.TreeNode(errs).toFormattedTable(60))
    - areEqual(errs.length, 0, "no grammar errors")
    + const errs = new grammarNode(Disk.read(grammarPath)).getAllErrors().map(err => err.toObject())
    + if (errs.length) console.log(new jtree.TreeNode(errs).toFormattedTable(60))
    + areEqual(errs.length, 0, "no grammar errors")
    - const errs = Disk.getFiles(examplesPath)
    - .map(path => {
    - const code = Disk.read(path)
    - const program = new simojiCompiler(code)
    - const errors = program.getAllErrors()
    - areEqual(errors.length, 0)
    - return errors.map(err => {
    - return { filename: path, ...err.toObject() }
    - })
    - })
    - .flat()
    - if (errs.length) console.log(new jtree.TreeNode(errs).toFormattedTable(60))
    + const errs = Disk.getFiles(examplesPath)
    + .map(path => {
    + const code = Disk.read(path)
    + const program = new simojiCompiler(code)
    + const errors = program.getAllErrors()
    + areEqual(errors.length, 0)
    + return errors.map(err => {
    + return { filename: path, ...err.toObject() }
    + })
    + })
    + .flat()
    + if (errs.length) console.log(new jtree.TreeNode(errs).toFormattedTable(60))
    - const app = SimojiApp.setupApp("")
    - areEqual(!!app, true)
    + const app = SimojiApp.setupApp("")
    + areEqual(!!app, true)
    - // Arrange
    - const app = SimojiApp.setupApp("")
    - app.verbose = false
    - await app.start()
    + // Arrange
    + const app = SimojiApp.setupApp("")
    + app.verbose = false
    + await app.start()
    - // Act
    - app.pasteCodeCommand(`😃
    + // Act
    + app.pasteCodeCommand(`😃
    - const boardState1 = app.board.toString()
    + const boardState1 = app.board.toString()
    - areEqual(app.board.populationCount["😃"], 200)
    + areEqual(app.board.populationCount["😃"], 200)
    - // Act
    - app.resetAllCommand()
    + // Act
    + app.resetAllCommand()
    - const boardState2 = app.board.toString()
    + const boardState2 = app.board.toString()
    - // Race condition is possible but pigs more likely to fly first.
    - areEqual(boardState1 === boardState2, false, "Boards should have changed")
    - areEqual(app.simojiPrograms[0].getAllErrors().length, 0, "program is valid")
    + // Race condition is possible but pigs more likely to fly first.
    + areEqual(boardState1 === boardState2, false, "Boards should have changed")
    + areEqual(app.simojiPrograms[0].getAllErrors().length, 0, "program is valid")
    - // Act
    - app.pasteCodeCommand(`😃
    + // Act
    + app.pasteCodeCommand(`😃
    - areEqual(app.simojiPrograms[0].getAllErrors().length, 2, "invalid programs dont crash")
    + areEqual(app.simojiPrograms[0].getAllErrors().length, 2, "invalid programs dont crash")
    - const tap = require("tap")
    - Object.keys(testTree).forEach(key => {
    - testTree[key](tap.equal)
    - })
    + const tap = require("tap")
    + Object.keys(testTree).forEach(key => {
    + testTree[key](tap.equal)
    + })
    examples.js
    Changed around line 2: const stamp = require("jtree/products/stamp.nodejs.js")
    - Disk.getFiles(__dirname + "/examples/")
    - .map(path => {
    - const name = Disk.getFileName(path.replace(".simoji", ""))
    - return name + `\n ` + Disk.read(path).replace(/\n/g, "\n ")
    - })
    - .filter(i => i)
    - .join("\n")
    - .trim()
    + Disk.getFiles(__dirname + "/examples/")
    + .map(path => {
    + const name = Disk.getFileName(path.replace(".simoji", ""))
    + return name + `\n ` + Disk.read(path).replace(/\n/g, "\n ")
    + })
    + .filter(i => i)
    + .join("\n")
    + .trim()
    package.json
    Changed around line 7
    + "useTabs": false,
    + "tabWidth": 2,
    + "semi": false,
    - "semi": false
    + "trailingComma": "none",
    + "arrowParens": "avoid"
    - "node": ">=14.0.0"
    + "node": ">=16.0.0"
    readme.scroll
    Changed around line 54: startColumns 2
    -
    server.js
    Changed around line 8: const { jtree } = require("jtree")
    - start(port = 80) {
    - const app = express()
    + start(port = 80) {
    + const app = express()
    - app.get("/*.js", (req, res) => {
    - const filename = req.path.substr(1)
    - readFile(__dirname + "/" + filename, "utf8", (err, code) => {
    - if (err) throw err
    - res.send(
    - new TypeScriptRewriter(code)
    - .removeRequires()
    - .removeNodeJsOnlyLines()
    - .changeNodeExportsToWindowExports()
    - .getString()
    - )
    - })
    - })
    + app.get("/*.js", (req, res) => {
    + const filename = req.path.substr(1)
    + readFile(__dirname + "/" + filename, "utf8", (err, code) => {
    + if (err) throw err
    + res.send(
    + new TypeScriptRewriter(code)
    + .removeRequires()
    + .removeNodeJsOnlyLines()
    + .changeNodeExportsToWindowExports()
    + .getString()
    + )
    + })
    + })
    - app.get("/examples", (req, res) => {
    - res.send(getExamples())
    - })
    + app.get("/examples", (req, res) => {
    + res.send(getExamples())
    + })
    - app.use(express.static(__dirname + "/"))
    + app.use(express.static(__dirname + "/"))
    - app.listen(port, () => {
    - console.log(`Running Simoji Dev Server. cmd+dblclick: http://localhost:${port}/dev.html`)
    - })
    - }
    + app.listen(port, () => {
    + console.log(`Running Simoji Dev Server. cmd+dblclick: http://localhost:${port}/dev.html`)
    + })
    + }
    testAll.js
    Changed around line 1
    - const tap = require("tap")
    - Object.keys(testTree).forEach(key => {
    - testTree[key](tap.equal)
    - })
    + const tap = require("tap")
    + Object.keys(testTree).forEach(key => {
    + testTree[key](tap.equal)
    + })
    yodash.js
    Changed around line 6: const { Directions, NodeTypes } = require("./components/Types.js")
    - const r1 = randomNumberGenerator()
    - const r2 = randomNumberGenerator()
    - if (r1 > 0.5) return r2 > 0.5 ? Directions.North : Directions.South
    - return r2 > 0.5 ? Directions.West : Directions.East
    + const r1 = randomNumberGenerator()
    + const r2 = randomNumberGenerator()
    + if (r1 > 0.5) return r2 > 0.5 ? Directions.North : Directions.South
    + return r2 > 0.5 ? Directions.West : Directions.East
    - let newAngle = ""
    - if (angle.includes(Directions.North)) newAngle += Directions.South
    - else if (angle.includes(Directions.South)) newAngle += Directions.North
    - if (angle.includes(Directions.East)) newAngle += Directions.West
    - else if (angle.includes(Directions.West)) newAngle += Directions.East
    - return newAngle
    + let newAngle = ""
    + if (angle.includes(Directions.North)) newAngle += Directions.South
    + else if (angle.includes(Directions.South)) newAngle += Directions.North
    + if (angle.includes(Directions.East)) newAngle += Directions.West
    + else if (angle.includes(Directions.West)) newAngle += Directions.East
    + return newAngle
    - if (operator === "=") return left == right
    - if (operator === "<") return left < right
    - if (operator === ">") return left > right
    - if (operator === "<=") return left <= right
    - if (operator === ">=") return left >= right
    + if (operator === "=") return left == right
    + if (operator === "<") return left < right
    + if (operator === ">") return left > right
    + if (operator === "<=") return left <= right
    + if (operator === ">=") return left >= right
    - return false
    + return false
    - const clone = program.clone()
    - clone.filter(node => node.getNodeTypeId() !== NodeTypes.agentDefinitionNode).forEach(node => node.destroy())
    - clone.agentKeywordMap = {}
    - clone.agentTypes.forEach((node, index) => (clone.agentKeywordMap[node.getWord(0)] = `simAgent${index}`))
    - const compiled = clone.compile()
    - const agentMap = Object.keys(clone.agentKeywordMap)
    - .map(key => `"${key}":${clone.agentKeywordMap[key]}`)
    - .join(",")
    - return `${compiled}
    + const clone = program.clone()
    + clone.filter(node => node.getNodeTypeId() !== NodeTypes.agentDefinitionNode).forEach(node => node.destroy())
    + clone.agentKeywordMap = {}
    + clone.agentTypes.forEach((node, index) => (clone.agentKeywordMap[node.getWord(0)] = `simAgent${index}`))
    + const compiled = clone.compile()
    + const agentMap = Object.keys(clone.agentKeywordMap)
    + .map(key => `"${key}":${clone.agentKeywordMap[key]}`)
    + .join(",")
    + return `${compiled}
    - const clone = program.clone()
    - // drop experiment nodes
    - clone.filter(node => node.getNodeTypeId() === NodeTypes.experimentNode).forEach(node => node.destroy())
    - // Append current experiment
    - if (experiment) clone.concat(experiment.childrenToString())
    - // Build symbol table
    - const symbolTable = {}
    - clone
    - .filter(node => node.getNodeTypeId() === NodeTypes.settingDefinitionNode)
    - .forEach(node => {
    - symbolTable[node.getWord(0)] = node.getContent()
    - node.destroy()
    - })
    - // Find and replace
    - let withVarsReplaced = clone.toString()
    - Object.keys(symbolTable).forEach(key => {
    - withVarsReplaced = withVarsReplaced.replaceAll(key, symbolTable[key])
    - })
    - return withVarsReplaced
    + const clone = program.clone()
    + // drop experiment nodes
    + clone.filter(node => node.getNodeTypeId() === NodeTypes.experimentNode).forEach(node => node.destroy())
    + // Append current experiment
    + if (experiment) clone.concat(experiment.childrenToString())
    + // Build symbol table
    + const symbolTable = {}
    + clone
    + .filter(node => node.getNodeTypeId() === NodeTypes.settingDefinitionNode)
    + .forEach(node => {
    + symbolTable[node.getWord(0)] = node.getContent()
    + node.destroy()
    + })
    + // Find and replace
    + let withVarsReplaced = clone.toString()
    + Object.keys(symbolTable).forEach(key => {
    + withVarsReplaced = withVarsReplaced.replaceAll(key, symbolTable[key])
    + })
    + return withVarsReplaced
    - let closest = Infinity
    - let target
    - targets.forEach(candidate => {
    - const pos = candidate.position
    - const distance = math.distance([pos.down, pos.right], [position.down, position.right])
    - if (distance < closest) {
    - closest = distance
    - target = candidate
    - }
    - })
    - const heading = target.position
    - return yodash.angle(position.down, position.right, heading.down, heading.right)
    + let closest = Infinity
    + let target
    + targets.forEach(candidate => {
    + const pos = candidate.position
    + const distance = math.distance([pos.down, pos.right], [position.down, position.right])
    + if (distance < closest) {
    + closest = distance
    + target = candidate
    + }
    + })
    + const heading = target.position
    + return yodash.angle(position.down, position.right, heading.down, heading.right)
    - const dy = ey - cy
    - const dx = ex - cx
    - let theta = Math.atan2(dy, dx) // range (-PI, PI]
    - theta *= 180 / Math.PI // rads to degs, range (-180, 180]
    - //if (theta < 0) theta = 360 + theta; // range [0, 360)
    - let angle = ""
    + const dy = ey - cy
    + const dx = ex - cx
    + let theta = Math.atan2(dy, dx) // range (-PI, PI]
    + theta *= 180 / Math.PI // rads to degs, range (-180, 180]
    + //if (theta < 0) theta = 360 + theta; // range [0, 360)
    + let angle = ""
    - if (Math.abs(theta) > 90) angle += Directions.North
    - else angle += Directions.South
    - if (theta < 0) angle += Directions.West
    - else angle += Directions.East
    - return angle
    + if (Math.abs(theta) > 90) angle += Directions.North
    + else angle += Directions.South
    + if (theta < 0) angle += Directions.West
    + else angle += Directions.East
    + return angle
    - const maxRight = cols
    - const maxBottom = rows
    - const right = Math.round(randomNumberGenerator() * maxRight)
    - const down = Math.round(randomNumberGenerator() * maxBottom)
    - return { right, down }
    + const maxRight = cols
    + const maxBottom = rows
    + const right = Math.round(randomNumberGenerator() * maxRight)
    + const down = Math.round(randomNumberGenerator() * maxBottom)
    + return { right, down }
    - const { right, down } = yodash.getRandomLocation(rows, cols, randomNumberGenerator)
    - const hash = yodash.makePositionHash({ right, down })
    - if (occupiedSpots && occupiedSpots.has(hash))
    - return yodash.getRandomLocationHash(rows, cols, occupiedSpots, randomNumberGenerator)
    - return hash
    + const { right, down } = yodash.getRandomLocation(rows, cols, randomNumberGenerator)
    + const hash = yodash.makePositionHash({ right, down })
    + if (occupiedSpots && occupiedSpots.has(hash))
    + return yodash.getRandomLocationHash(rows, cols, occupiedSpots, randomNumberGenerator)
    + return hash
    - const board = []
    - while (rows >= 0) {
    - let col = cols
    - while (col >= 0) {
    - const hash = yodash.makePositionHash({ right: col, down: rows })
    - col--
    - if (occupiedSpots.has(hash)) continue
    - board.push(`${emoji} ${hash}`)
    - }
    - rows--
    - }
    - return board.join("\n")
    + const board = []
    + while (rows >= 0) {
    + let col = cols
    + while (col >= 0) {
    + const hash = yodash.makePositionHash({ right: col, down: rows })
    + col--
    + if (occupiedSpots.has(hash)) continue
    + board.push(`${emoji} ${hash}`)
    + }
    + rows--
    + }
    + return board.join("\n")
    - let { right, down } = position
    - const positions = []
    - down--
    - positions.push({ down, right })
    - right--
    - positions.push({ down, right })
    - right++
    - right++
    - positions.push({ down, right })
    - down++
    - positions.push({ down, right })
    - right--
    - right--
    - positions.push({ down, right })
    - down++
    - positions.push({ down, right })
    - right++
    - positions.push({ down, right })
    - right++
    - positions.push({ down, right })
    - return positions
    + let { right, down } = position
    + const positions = []
    + down--
    + positions.push({ down, right })
    + right--
    + positions.push({ down, right })
    + right++
    + right++
    + positions.push({ down, right })
    + down++
    + positions.push({ down, right })
    + right--
    + right--
    + positions.push({ down, right })
    + down++
    + positions.push({ down, right })
    + right++
    + positions.push({ down, right })
    + right++
    + positions.push({ down, right })
    + return positions
    - if (width < 1 || height < 1) {
    - return ""
    - }
    - const cells = []
    - let row = 0
    - while (row < height) {
    - let col = 0
    - while (col < width) {
    - const isPerimeter = row === 0 || row === height - 1 || col === 0 || col === width - 1
    - if (isPerimeter)
    - cells.push(
    - `${character} ${yodash.makePositionHash({
    - down: startDown + row,
    - right: startRight + col
    - })}`
    - )
    - col++
    - }
    - row++
    - }
    - return cells.join("\n")
    + if (width < 1 || height < 1) {
    + return ""
    + }
    + const cells = []
    + let row = 0
    + while (row < height) {
    + let col = 0
    + while (col < width) {
    + const isPerimeter = row === 0 || row === height - 1 || col === 0 || col === width - 1
    + if (isPerimeter)
    + cells.push(
    + `${character} ${yodash.makePositionHash({
    + down: startDown + row,
    + right: startRight + col
    + })}`
    + )
    + col++
    + }
    + row++
    + }
    + return cells.join("\n")
    - return {
    - down: parseInt(words.find(word => word.includes("⬇️")).slice(0, -1)),
    - right: parseInt(words.find(word => word.includes("➡️")).slice(0, -1))
    - }
    + return {
    + down: parseInt(words.find(word => word.includes("⬇️")).slice(0, -1)),
    + right: parseInt(words.find(word => word.includes("➡️")).slice(0, -1))
    + }
    - const lines = str.split("\n")
    - const output = []
    - for (let index = 0; index < lines.length; index++) {
    - const words = lines[index].split(" ")
    - for (let wordIndex = 0; wordIndex < words.length; wordIndex++) {
    - const word = words[wordIndex]
    - if (word !== "") output.push(`${word} ${yodash.makePositionHash({ down: index, right: wordIndex })}`)
    - }
    - }
    - return output.join("\n")
    + const lines = str.split("\n")
    + const output = []
    + for (let index = 0; index < lines.length; index++) {
    + const words = lines[index].split(" ")
    + for (let wordIndex = 0; wordIndex < words.length; wordIndex++) {
    + const word = words[wordIndex]
    + if (word !== "") output.push(`${word} ${yodash.makePositionHash({ down: index, right: wordIndex })}`)
    + }
    + }
    + return output.join("\n")
    - new TreeNode(board).forEach(line => {
    - occupiedSpots.add(yodash.makePositionHash(yodash.parsePosition(line.getWords())))
    - })
    + new TreeNode(board).forEach(line => {
    + occupiedSpots.add(yodash.makePositionHash(yodash.parsePosition(line.getWords())))
    + })
    - const availablePositions = []
    - let down = rows
    - while (down >= rowStart) {
    - let right = cols
    - while (right >= colStart) {
    - const hash = yodash.makePositionHash({ right, down })
    - if (!occupiedSpots.has(hash)) availablePositions.push({ right, down, hash })
    - right--
    - }
    - down--
    - }
    - return availablePositions
    + const availablePositions = []
    + let down = rows
    + while (down >= rowStart) {
    + let right = cols
    + while (right >= colStart) {
    + const hash = yodash.makePositionHash({ right, down })
    + if (!occupiedSpots.has(hash)) availablePositions.push({ right, down, hash })
    + right--
    + }
    + down--
    + }
    + return availablePositions
    - randomNumberGenerator,
    - amount,
    - char,
    - rows,
    - cols,
    - occupiedSpots,
    - originRow,
    - originColumn
    + randomNumberGenerator,
    + amount,
    + char,
    + rows,
    + cols,
    + occupiedSpots,
    + originRow,
    + originColumn
    - const availableSpots = yodash.getAllAvailableSpots(rows, cols, occupiedSpots)
    - const spots = yodash.sampleFrom(availableSpots, amount * 10, randomNumberGenerator)
    - const origin = originColumn
    - ? { down: parseInt(originRow), right: parseInt(originColumn) }
    - : yodash.getRandomLocation(rows, cols, randomNumberGenerator)
    - const sortedByDistance = lodash.sortBy(spots, spot =>
    - math.distance([origin.down, origin.right], [spot.down, spot.right])
    - )
    + const availableSpots = yodash.getAllAvailableSpots(rows, cols, occupiedSpots)
    + const spots = yodash.sampleFrom(availableSpots, amount * 10, randomNumberGenerator)
    + const origin = originColumn
    + ? { down: parseInt(originRow), right: parseInt(originColumn) }
    + : yodash.getRandomLocation(rows, cols, randomNumberGenerator)
    + const sortedByDistance = lodash.sortBy(spots, spot =>
    + math.distance([origin.down, origin.right], [spot.down, spot.right])
    + )
    - return sortedByDistance
    - .slice(0, amount)
    - .map(spot => {
    - const { hash } = spot
    - occupiedSpots.add(hash)
    - return `${char} ${hash}`
    - })
    - .join("\n")
    + return sortedByDistance
    + .slice(0, amount)
    + .map(spot => {
    + const { hash } = spot
    + occupiedSpots.add(hash)
    + return `${char} ${hash}`
    + })
    + .join("\n")
    - const semiRand = Math.sin(seed++) * 10000
    - return semiRand - Math.floor(semiRand)
    + const semiRand = Math.sin(seed++) * 10000
    + return semiRand - Math.floor(semiRand)
    - shuffleArray(collection, randomNumberGenerator).slice(0, howMany)
    + shuffleArray(collection, randomNumberGenerator).slice(0, howMany)
    - const clonedArr = array.slice()
    - for (let index = clonedArr.length - 1; index > 0; index--) {
    - const replacerIndex = Math.floor(randomNumberGenerator() * (index + 1))
    - ;[clonedArr[index], clonedArr[replacerIndex]] = [clonedArr[replacerIndex], clonedArr[index]]
    - }
    - return clonedArr
    + const clonedArr = array.slice()
    + for (let index = clonedArr.length - 1; index > 0; index--) {
    + const replacerIndex = Math.floor(randomNumberGenerator() * (index + 1))
    + ;[clonedArr[index], clonedArr[replacerIndex]] = [clonedArr[replacerIndex], clonedArr[index]]
    + }
    + return clonedArr
    - const newTree = tree.clone()
    - const map = TreeUtils.arrayToMap(fields)
    - newTree.forEach(node => {
    - if (!map[node.getWord(0)]) node.destroy()
    - })
    + const newTree = tree.clone()
    + const map = TreeUtils.arrayToMap(fields)
    + newTree.forEach(node => {
    + if (!map[node.getWord(0)]) node.destroy()
    + })
    - return newTree
    + return newTree
    - const newTree = new jtree.TreeNode()
    - tree.forEach(node => node.forEach(child => newTree.appendNode(child)))
    - return newTree
    + const newTree = new jtree.TreeNode()
    + tree.forEach(node => node.forEach(child => newTree.appendNode(child)))
    + return newTree
    yodash.test.node.js
    Changed around line 5: const { yodash } = require("./yodash.js")
    - areEqual(yodash.getRandomAngle(Math.random).match(/(East|West|North|South)/).length, 2)
    + areEqual(yodash.getRandomAngle(Math.random).match(/(East|West|North|South)/).length, 2)
    - const expected = `😀 0⬇️ 0➡️
    + const expected = `😀 0⬇️ 0➡️
    - areEqual(yodash.makeRectangle("😀", 2, 2), expected)
    - areEqual(
    - yodash.makeRectangle("🚪", 2, 1, 1, 1),
    - `🚪 1⬇️ 1➡️
    + areEqual(yodash.makeRectangle("😀", 2, 2), expected)
    + areEqual(
    + yodash.makeRectangle("🚪", 2, 1, 1, 1),
    + `🚪 1⬇️ 1➡️
    - )
    + )
    - const tap = require("tap")
    - Object.keys(testTree).forEach(key => {
    - testTree[key](tap.equal)
    - })
    + const tap = require("tap")
    + Object.keys(testTree).forEach(key => {
    + testTree[key](tap.equal)
    + })
    Breck Yunits
    Breck Yunits
    1 year ago
    Update docs
    cheatSheet.html
    Changed around line 2
    -
    +
    -
    +
    -
    +
    Changed around line 303: h4.scrollQuestion {
    +
    + <
    +
    +
    + >
    +
    +
    +
    Changed around line 443: experiment
    +
    +
    +

    +

    cheatSheet.scroll
    Changed around line 1
    - metaTags
    - gazetteCss
    + import header.scroll
    + startColumns 3
    +
    Changed around line 124: pipeTable
    +
    + import footer.scroll
    footer.scroll
    Changed around line 1
    + keyboardNav
    header.scroll
    Changed around line 1
    - gazetteHeader
    + gazetteHeader
    + description Design quick simulations with Emojis
    + git https://github.com/breck7/simoji
    + baseUrl https://simoji.pub/
    + email breck7+simoji@gmail.com
    scroll.settings
    Changed around line 0
    - title Simoji
    - description Design quick simulations with Emojis
    - github https://github.com/publicdomaincompany/simoji
    - git https://github.com/publicdomaincompany/simoji/blob/main
    - twitter https://twitter.com/publicdomainpub
    - email simoji@publicdomaincompany.com
    - baseUrl https://simoji.pub/
    - ignoreGrammarFiles
    Breck Yunits
    Breck Yunits
    1 year ago
    Update Scroll docs
    cheatSheet.html
    Changed around line 1
    -
    -