\n );\n }\n}\n\nexport default Toolbox;","import React from 'react';\nimport { ReactSVG } from 'react-svg';\n\nclass StepMenu extends React.Component {\n handleClick(event, step, disabled) {\n event.preventDefault();\n if (!disabled) {\n // Must update color before updating props to allow component to\n // render with the proper current color rather than the state before\n this.props.setStep(step);\n }\n }\n\n getColor(disabled) {\n return disabled ? \"rgb(136, 136, 136)\" : \"rgb(68, 68, 68)\";\n }\n\n render() {\n let { hide, currentStep, stepInfo } = this.props;\n if (hide) return ();\n let backEnabled = currentStep === (stepInfo.length - 1);\n let forwardEnabled = currentStep === 0;\n return (\n \n
\n \n );\n }\n}\n\nexport default StepMenu;","export default {\n gridSize: 1,\n cutPadding: {\n horizontal: 10,\n vertical: 5\n },\n cutCornerRadius: 10,\n initialSeparation: 50,\n}","import React from 'react';\nimport config from './config';\n\nclass EGVariable extends React.Component {\n constructor(props) {\n super(props);\n this.text = React.createRef()\n this.getCoords = this.props.getCoords\n this.handleClick = this.handleClick.bind(this);\n this.state = {\n x: props.x,\n y: props.y,\n cursorOver: false,\n dragging: false\n };\n\n this.panzoom = this.props.panzoom\n\n window.addEventListener('mousemove', this.onMouseMove.bind(this))\n window.addEventListener('mousedown', this.handleDragStart.bind(this))\n window.addEventListener('mouseup', this.handleDragEnd.bind(this))\n window.addEventListener('click', this.handleClick)\n }\n\n handleClick() {\n if (this.state.cursorOver \n && this.props.enableHighlight \n && this.props.selectedCallback) \n {\n this.props.selectedCallback(this.props.id);\n this.setState({ cursorOver: false });\n }\n }\n\n componentDidMount() { \n this.text.current.style.cursor = \"pointer\";\n }\n\n handleDragStart(evt) {\n if (this.state.cursorOver) {\n this.panzoom.pause()\n this.setState({ dragging: true })\n }\n }\n\n handleDragEnd(evt) {\n this.panzoom.resume()\n let { x, y } = this.state;\n this.props.setCoords(x, y);\n this.setState({ dragging: false })\n }\n\n onMouseMove(evt) {\n if (this.state.dragging) {\n let { x, y } = this.getCoords(evt.clientX, evt.clientY)\n x = Math.round(x/config.gridSize)*config.gridSize\n y = Math.round(y/config.gridSize)*config.gridSize\n this.props.setCoords(x, y);\n this.setState({ x: x, y: y })\n }\n }\n\n componentWillUnmount() {\n window.removeEventListener('click', this.handleClick);\n window.removeEventListener('mousemove', this.onMouseMove.bind(this))\n window.removeEventListener('mousedown', this.handleDragStart.bind(this))\n window.removeEventListener('mouseup', this.handleDragEnd.bind(this))\n }\n\n render() {\n let highlight = this.state.cursorOver && this.props.enableHighlight;\n return (\n this.setState({ cursorOver: true })}\n onMouseLeave={() => this.setState({ cursorOver: false })}\n ref={this.text}>\n {this.props.children}\n \n );\n }\n}\n\nexport default EGVariable;","import React from 'react';\nimport config from './config';\n\nclass EGCut extends React.Component {\n constructor(props) {\n super(props);\n this.cut = React.createRef();\n this.BB = React.createRef();\n this.getBBoxData = this.getBBoxData.bind(this);\n this.handleClick = this.handleClick.bind(this);\n this.update = this.update.bind(this);\n this.state = { highlight: false, bounding: {_x:0,_y:0,_w:0,_h:0} };\n\n window.addEventListener('click', this.handleClick)\n }\n\n handleClick() {\n if (this.state.highlight \n && this.props.enableHighlight \n && this.props.selectedCallback) \n {\n this.props.selectedCallback(this.props.id);\n this.setState({ highlight: false });\n }\n }\n\n getBBoxData() {\n if (this.cut.current) {\n let { x, y, width, height } = this.cut.current.getBBox();\n let _x = x - config.cutPadding.horizontal;\n let _y = y - config.cutPadding.vertical;\n let _w = width + config.cutPadding.horizontal * 2;\n let _h = height + config.cutPadding.vertical * 2;\n return { _x, _y, _w, _h };\n }\n return {};\n }\n\n update() {\n if (!this.interval) {\n this.interval = setInterval(() => {\n this.setState({ bounding: this.getBBoxData() });\n }, 1);\n setTimeout(() => {\n clearInterval(this.interval);\n this.interval = null;\n }, 100);\n }\n }\n\n componentDidMount() { \n this.update()\n }\n\n componentDidUpdate() {\n this.update()\n }\n\n componentWillUnmount() {\n window.removeEventListener('click', this.handleClick);\n if (this.interval)\n clearInterval(this.interval);\n }\n\n render() {\n let childEl = this.props.children;\n if (childEl.length < 1) {\n childEl = {\" \"}\n }\n let highlight = this.state.highlight && this.props.enableHighlight;\n let { _x, _y, _w, _h } = this.state.bounding;\n return (\n \n this.setState({ highlight: true })}\n onMouseLeave={() => this.setState({ highlight: false })}\n rx={config.cutCornerRadius.toString()} \n ry={config.cutCornerRadius.toString()}\n />\n \n {this.props.children}\n \n \n );\n }\n}\n\nexport default EGCut;","import React from 'react';\nimport { convertToArray } from '../converters';\nimport Toolbox from './Toolbox';\nimport StepMenu from './StepMenu';\nimport EGVariable from './EGVariable';\nimport EGCut from './EGCut';\nimport './Canvas.scss';\nimport Panzoom from 'panzoom';\nimport config from './config';\nimport { NotificationContainer, NotificationManager } from 'react-notifications';\nconst nanoid = require('nanoid').nanoid;\n\n// some defaults: \n// blocks are automatically 22px high\n\nconst TEXT_H = 22;\n\nfunction initXY(step, level) {\n let data = {}\n let currentX = 0\n let currentY = 0\n let maxX = 0\n let maxY = 0\n\n // gapSize should be equal to the number of level changes\n // in between two variables, so that we can evenly place \n // them initially across the screen\n function initXYRecurse(step, level, gapSize) {\n console.log(data)\n for (let s in step) {\n if (step[s] instanceof Array && step[s].length > 0) {\n let id = nanoid()\n step[s] = { data: initXYRecurse(step[s], level + 1), id: id, type: \"cut\" }\n data[id] = { type: \"cut\", level: level }\n } else {\n let X = currentX;\n let Y = currentY;\n let id = nanoid()\n data[id] = { \n type: \"var\",\n var: step[s], \n x: Math.round(X/config.gridSize)*config.gridSize, \n y: Math.round(Y/config.gridSize)*config.gridSize,\n level: level\n }\n step[s] = id\n maxY = Y > maxY ? Y : maxY;\n maxX = X > maxX ? X : maxX;\n currentX += config.initialSeparation\n }\n }\n return step\n }\n return { stepZero: { data: initXYRecurse(step, level), h: maxY + TEXT_H, w: maxX }, data: data }\n}\n\nclass Canvas extends React.Component {\n constructor(props) {\n super(props);\n this.canvas = React.createRef();\n this.canvasContainer = React.createRef();\n\n this.renderStep = this.renderStep.bind(this);\n this.changePos = this.changePos.bind(this);\n this.getSVGCoords = this.getSVGCoords.bind(this);\n this.highlightCut = this.highlightCut.bind(this);\n this.startSelection = this.startSelection.bind(this);\n\n let { premises, conclusion, steps, data } = this.props.proof;\n this.state = {\n proof: {\n premises: premises,\n conclusion: conclusion\n },\n steps: steps || [],\n data: data || {},\n currentStep: 0,\n moveListeners: [],\n highlights: {\n cut: 'none', // 'none', 'odd', 'even', 'all'\n var: 'none'\n },\n cbFunction: null,\n interaction: true,\n functions: {\n insert: (id) => {\n console.log(\"INSERTION\")\n },\n erase: (id) => {\n console.log(\"ERASURE\")\n return this.erasure(id);\n },\n iterate: (id) => {\n console.log(\"ITERATION\")\n return this.iteration(id, this.state.steps[this.state.currentStep].data[0].id);\n },\n dcRemove: (id) => {\n console.log(\"DOUBLE CUT Remove\")\n return this.doubleCutRemove(id);\n },\n dcAdd: (id) => {\n console.log(\"DOUBLE CUT Add\")\n return this.doubleCutAdd(id);\n \n }\n }\n }\n }\n\n startSelection(selectable, nameOfFunction) {\n let { steps, currentStep } = this.state;\n // only allow steps to be conducted at the end of a proof\n if (currentStep+1 !== steps.length) {\n return\n }\n this.setState({ \n highlights: selectable, \n interaction: false, \n cbFunction: (id) => {\n let successful = this.state.functions[nameOfFunction](id); \n if (successful) \n this.setState({ \n highlights: {\n cut: 'none', \n var: 'none'\n },\n interaction: true, \n cbFunction: null });\n }\n });\n }\n\n /* Given a copyID and insertID, the iteration function creates a new step,\n * and adds a copy of the data represented by copyID at the location of insertID\n * only if the location of insertID is a child of copyID\n */\n iteration(copyID, insertID) {\n let { steps, currentStep, data } = this.state;\n let step = this.copyStep(steps[currentStep]);\n // If the insertID data is not in a subgraph of the copID data, return\n if (!this.isInNestedGraph(step, insertID, copyID)) {\n console.log(\"Insert selection is not in a subgraph of Copy selection\");\n return false;\n }\n // use findID to find the data represented by the two IDs\n let copy = this.copyContents(this.findID(step, copyID));\n if (!copy) {\n console.log(\"Copy ID could not be found in Iterate\");\n return false;\n }\n let insert = this.findID(step, insertID);\n if (!insert) {\n console.log(\"Insert ID could not be found in Iterate\");\n return false;\n }\n insert.data = insert.data.concat(copy);\n // Change the levels of the copy data\n this.changeCutLevel(step, copy.id, data[insert.id].level + 1)\n // Update the state\n currentStep+=1;\n steps.push(step);\n this.setState({ steps: steps, currentStep: currentStep, data:data });\n return true;\n }\n\n erasure(id) {\n let { steps, currentStep, data } = this.state;\n // Create a new step\n let step = this.copyStep(steps[currentStep]);\n // Find the data that will be erased\n let erased = this.findID(step, id);\n if (!erased) {\n return false;\n }\n // Get the parent of the erased section\n let parent = this.findParent(step, id)\n if (!parent) {\n return false;\n }\n // Remove the erased data from the parent's data array\n const index = parent.data.indexOf(erased);\n if (index > -1)\n parent.data.splice(index, 1);\n else {\n return false;\n }\n // Update the state\n currentStep+=1;\n steps.push(step);\n this.setState({ steps: steps, currentStep: currentStep, data:data });\n return true;\n }\n\n /* Adds a double cut given the ID of the data that will be inside the cut.\n * Will only run if the current step is the last step.\n */\n doubleCutAdd(ID) {\n let { steps, currentStep, data } = this.state;\n // create a new step\n let step = this.copyStep(steps[currentStep]);\n // use findID to find the data represented by the id\n // this is the data that will be inside the two new cuts\n let inside = this.findID(step, ID);\n if (!inside) {\n return false;\n }\n // create a new cut with another one inside it\n let cut1_id = nanoid();\n let cut2_id = nanoid();\n let cut2 = {\n data: [inside],\n id: cut2_id,\n type: \"cut\"\n }\n let cut1 = {\n data: [cut2],\n id: cut1_id,\n type: \"cut\"\n }\n // Set the levels of the two cuts\n let level = data[ID].level\n data[cut2_id] = { type: \"cut\", level: level + 1};\n data[cut1_id] = { type: \"cut\", level: level};\n // increase the level of the inside cut along with all cuts inside of it by 2\n this.changeCutLevel(step, ID, 2)\n\n // get the parent of the selection\n let parent = this.findParent(step, ID)\n if (!parent) {\n return false;\n }\n // Add the contents of the new cuts to the data array\n // after removing the original contents\n const index = parent.data.indexOf(inside);\n if (index > -1) {\n parent.data.splice(index, 1);\n }\n parent.data = parent.data.concat(cut1);\n // Change the state data accordingly\n currentStep+=1;\n steps.push(step);\n this.setState({ steps: steps, currentStep: currentStep, data:data });\n return true;\n }\n\n /* Removes a double cut given the ID of the outside cut.\n * Will only run if the current step is the last step.\n * Creates a deep copy of the current step, and replaces the cut with\n * the given ID with the contents of the second cut, only if they exist.\n * Then adds the edited copy of the current step to the end of the step array.\n */\n doubleCutRemove(cutID) {\n let { steps, currentStep, data } = this.state;\n // Create a new step\n let step = this.copyStep(steps[currentStep]);\n\n // use findID to find the cut with the given ID\n let firstCut = this.findID(step, cutID);\n // If it is actually a cut and has another cut inside\n if (firstCut && firstCut.type === \"cut\") {\n let secondCut = firstCut.data;\n if (secondCut && secondCut.length === 1 && secondCut[0].type === \"cut\") {\n // Get the data inside the second cut\n let newContents = secondCut[0].data;\n // Get the parent of the original cut being removed\n let parent = this.findParent(step, cutID)\n if (!parent) {\n return false;\n }\n this.changeCutLevel(step, secondCut[0].id, -2)\n // Remove the first cut from the data array\n const index = parent.data.indexOf(firstCut);\n if (index > -1) {\n parent.data.splice(index, 1);\n }\n // Add the contents of the second cut to the data array\n parent.data = parent.data.concat(newContents);\n // Update the state\n currentStep+=1;\n steps.push(step);\n this.setState({ steps: steps, currentStep: currentStep, data:data });\n return true;\n }\n else return false;\n }\n else return false;\n }\n\n\n /* Given a step and two IDs, will return true if the data of ChildID is\n * in a nested graph of parentID in the current step.\n */\n isInNestedGraph(step, childID, parentID) {\n let parentStep = this.findParent(step, parentID);\n if (!parentStep) {\n console.log(\"Parent Data could not be found\");\n return false;\n }\n let childStep = this.findID(parentStep, childID);\n if (!childStep) {\n console.log(\"Child is not in nested graph of Parent\");\n return false;\n }\n return true;\n }\n\n /* Given a step or a cut, will copy the contents inside with new IDs\n * and return the new data. This permits inserting new data into the graph.\n * Levels for cuts will start at 0 and increase accordingly\n */\n copyContents(step) {\n let { data } = this.state;\n // Copies the data of a map and returns it\n // Also updates the state.data map according to new generated IDs\n function copyDataMap(map, level) {\n let newMap = {};\n for (let m in map) {\n // If an ID is found, generate a new one\n if (m === 'id') {\n let id = nanoid();\n newMap[m] = id;\n // Add the new data to state.data via a deep copy\n data[id] = {\n type: \"cut\",\n level: level\n }\n }\n // Otherwise, if not a data array, copy the contents\n else if (m !== 'data'){\n newMap[m] = map[m]\n }\n // If a data array, copy using helper function\n else {\n newMap[m] = copyDataArray(map[m], level+1)\n }\n }\n return newMap;\n }\n // Copies the data of an array and returns it\n // Also updates state.data according to new generated IDs\n function copyDataArray(arr, level) {\n let newArr = [];\n for (let a in arr) {\n // If an ID found, generate a new one\n if (typeof arr[a] === 'string') {\n let id = nanoid();\n newArr.push(id);\n // Add the new data to state.data via a deep copy\n data[id] = {\n type: \"var\",\n var: data[arr[a]].var,\n x: data[arr[a]].x,\n y: data[arr[a]].y,\n }\n }\n // otherwise, call the other helper function to copy contents\n else {\n newArr.push(copyDataMap(arr[a], level))\n }\n }\n return newArr;\n }\n let newStep = copyDataMap(step, 0);\n this.setState({ data: data })\n return newStep;\n }\n\n /* Given a step and the ID of a cut, will iterate through all cuts within\n * that cut and change their level by a specified amount.\n */\n changeCutLevel(step, id, change) {\n let { data } = this.state\n // If the ID is for a variable, only increase it's level\n if (data[id].type === \"var\") {\n data[id].level += change;\n return\n }\n // when true, the levels should change in the functions below\n let idFound = false\n // Changes the \n function changeLevelMap(map) {\n // get the id for the current map\n let mapID;\n if (map.id) {\n mapID = map.id\n // if it matches the id being searched, update the boolean\n if (mapID === id) {\n idFound = true;\n }\n }\n // If the ID has been found, update the level of the current cut\n if (idFound) {\n data[mapID].level += change;\n }\n // call the function of the data array if it exists\n if (map.data){\n changeLevelArray(map.data);\n }\n }\n function changeLevelArray(arr) {\n for (let a in arr) {\n // If a non-string is found (a cut)\n if (typeof arr[a] !== 'string') {\n // Change the level of the cut\n changeLevelMap(arr[a])\n }\n // If string is found, change the level of the variable\n else if (idFound){\n data[arr[a]].level += change;\n }\n }\n }\n changeLevelArray(step.data)\n this.setState({ data: data })\n }\n\n // Performs a deep copy of oldStep into newStep, used to not change previous steps\n // By allowing them to be copied without using a reference\n copyStep(oldStep) {\n let newStep = {};\n function copyDataMap(oldData) {\n let newData = {};\n for (let d in oldData) {\n // If an id or type if found, copy directly\n if(typeof oldData[d] === 'string') {\n newData[d] = oldData[d];\n }\n // Otherwise if an array is found, copy using helper function\n else {\n newData[d] = copyDataArray(oldData[d]);\n }\n }\n return newData;\n }\n function copyDataArray(oldData) {\n let newData = [];\n for (let d in oldData) {\n // If an ID is found (variable), copy directly\n if(typeof oldData[d] === 'string') {\n newData.push(oldData[d]);\n }\n // If a map was found (cut), copy using helper function\n else {\n newData.push(copyDataMap(oldData[d]));\n }\n }\n return newData;\n }\n // Copy the data, width, and height of the original into the new step\n newStep.data = copyDataArray(oldStep.data);\n newStep.h = oldStep.h;\n newStep.w = oldStep.w;\n return newStep;\n }\n\n /* Finds and returns the item that is the parent of the item\n * with the specified ID, given the step to search as well.\n */\n findParent(searchedStep, id) {\n // holds the parent of the id\n let parent = searchedStep\n // Searches an array for the ID, returns true if it is found\n function findInArray(arr) {\n for (let a in arr) {\n // If an ID is found, compare it\n if (typeof arr[a] === 'string') {\n if (arr[a] === id) {\n return true;\n }\n }\n // Otherwise if a datamap is found, check the ID\n else {\n // If ID matches, return true\n if (arr[a].id && arr[a].id === id) {\n return true;\n }\n // Otherwise, search the datamap\n else {\n findInMap(arr[a])\n }\n }\n }\n return false;\n }\n function findInMap(map) {\n // if the map contains data, search the data\n if (map.data) {\n // if found, set parent to this map\n if(findInArray(map.data)) {\n parent = map;\n }\n }\n }\n findInArray(searchedStep.data);\n return parent;\n }\n\n // finds and returns the item with the specified ID in a given step\n findID(searchedStep, id) {\n // Find the ID in an array\n function findIDArray(arr) {\n for (let a in arr) {\n // if a string, aka an ID\n if (typeof arr[a] === 'string') {\n // return the ID if found\n if (arr[a] === id) {\n return id;\n }\n }\n // if a data map is found with the correct id, return the data map\n else if (arr[a].id === id) {\n return arr[a];\n // otherwise, call findID step on the datamap that has the incorrect ID\n } else {\n let s = findIDMap(arr[a]);\n if (s)\n return s;\n }\n }\n }\n // Finds the ID in a data map representing a step\n function findIDMap(step) {\n for (let s in step) {\n // if an array is found, call findIDArray on each element\n if (step[s] instanceof Array) {\n return findIDArray(step[s]);\n // if an id is found, check if it matches and return the data if so\n } else if (s === \"id\") {\n if (step[s] === id)\n return step;\n }\n }\n }\n return findIDMap(searchedStep);\n }\n\n changePos(id, x, y) {\n let { data } = this.state;\n Object.assign(data[id], { x: x, y: y })\n this.setState(data)\n }\n\n highlightCut(level) {\n if (this.state.highlights.cut === 'all') return true;\n let odd = false;\n if (level % 2 === 1) odd = true;\n if (this.state.highlights.cut === 'odd' && odd) return true;\n else if (this.state.highlights.cut === 'even' && !odd) return true;\n return false;\n }\n\n highlightVar(level) {\n if (this.state.highlights.var === 'all') return true;\n let odd = false;\n if (level % 2 === 1) odd = true;\n if (this.state.highlights.var === 'odd' && odd) return true;\n else if (this.state.highlights.var === 'even' && !odd) return true;\n return false;\n }\n\n renderStep(stepIndex) {\n let { data } = this.state;\n let step = this.state.steps[stepIndex]\n if (step) {\n const setXY = (id,x,y) => {\n data[id].x = x;\n data[id].y = y;\n this.setState({ data: data })\n }\n\n const renderRecurse = (step) => {\n let jsx = [];\n for (let s in step) {\n if (step[s].type === \"cut\") {\n let level = data[step[s].id].level;\n let groupElement = (\n \n {renderRecurse(step[s].data)}\n \n );\n jsx.push(groupElement);\n } else {\n let el = this.state.data[step[s]];\n let level = data[step[s]].level;\n jsx.unshift(\n setXY(step[s],x,y)}\n key={step[s]}>\n {el.var}\n \n );\n }\n }\n return jsx;\n }\n renderRecurse.bind(this);\n return renderRecurse(step.data)\n }\n }\n\n componentDidMount() { \n this.panzoom = Panzoom(this.canvas.current, {\n maxZoom: 6,\n minZoom: 0.5\n });\n // this.canvasContainer.current.addEventListener('wheel', this.panzoom.zoomWithWheel);\n const vw = Math.max(document.documentElement.clientWidth, window.innerWidth || 0);\n const vh = Math.max(document.documentElement.clientHeight, window.innerHeight || 0);\n // if there are no existing steps, init first step\n let { steps } = this.state;\n if (steps.length === 0) {\n let { premises, conclusion } = this.state.proof;\n let { stepZero, data } = initXY(convertToArray(premises.join('')), 0);\n steps.push(stepZero);\n this.setState({ steps: steps, data: data });\n }\n // required to use setState to trigger re-render after creation of panzoom\n this.setState({ currentStep: 0 });\n let step = this.state.steps[this.state.currentStep];\n\n this.panzoom.moveTo(vw/2 - step.w, vh/2 - step.h);\n this.panzoom.zoomTo(vw/2 - step.w, vh/2 - step.h, 2);\n }\n\n componentWillUnmount() {\n window.removeEventListener('resize', this);\n }\n\n getSVGCoords(domX, domY) {\n var pt = this.canvasContainer.current.createSVGPoint();\n\n pt.x = domX;\n pt.y = domY;\n\n return pt.matrixTransform(this.canvas.current.getScreenCTM().inverse());\n }\n\n render() {\n let zoomWithWheel = () => {}\n let { steps, currentStep } = this.state;\n if (this.panzoom)\n zoomWithWheel = this.panzoom.zoomWithWheel\n return (\n
this.setState({ premises: premises.concat(['']) }) }>\n Add New Premise\n
\n
\n
\n
\n
Conclusion
\n
\n {this.getFormulaCell(conclusion)}\n
\n
\n );\n }\n}\n\nexport default CreateNew;","import React from 'react';\nimport CreateNew from './CreateNew';\nimport { ReactSVG } from 'react-svg';\nimport './intro.scss';\n\nconst IntroContent = () => (\n
\n
\n
Existential Graphs
\n
\n Using this tool, you can initialize proofs in the existential graph schema and then you can go through the process of solving them. You can save these proofs and look back at them later.\n
\n );\n }\n}\n\nexport default App;\n","// This optional code is used to register a service worker.\n// register() is not called by default.\n\n// This lets the app load faster on subsequent visits in production, and gives\n// it offline capabilities. However, it also means that developers (and users)\n// will only see deployed updates on subsequent visits to a page, after all the\n// existing tabs open on the page have been closed, since previously cached\n// resources are updated in the background.\n\n// To learn more about the benefits of this model and instructions on how to\n// opt-in, read https://bit.ly/CRA-PWA\n\nconst isLocalhost = Boolean(\n window.location.hostname === 'localhost' ||\n // [::1] is the IPv6 localhost address.\n window.location.hostname === '[::1]' ||\n // 127.0.0.0/8 are considered localhost for IPv4.\n window.location.hostname.match(\n /^127(?:\\.(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)){3}$/\n )\n);\n\nexport function register(config) {\n if (process.env.NODE_ENV === 'production' && 'serviceWorker' in navigator) {\n // The URL constructor is available in all browsers that support SW.\n const publicUrl = new URL(process.env.PUBLIC_URL, window.location.href);\n if (publicUrl.origin !== window.location.origin) {\n // Our service worker won't work if PUBLIC_URL is on a different origin\n // from what our page is served on. This might happen if a CDN is used to\n // serve assets; see https://github.com/facebook/create-react-app/issues/2374\n return;\n }\n\n window.addEventListener('load', () => {\n const swUrl = `${process.env.PUBLIC_URL}/service-worker.js`;\n\n if (isLocalhost) {\n // This is running on localhost. Let's check if a service worker still exists or not.\n checkValidServiceWorker(swUrl, config);\n\n // Add some additional logging to localhost, pointing developers to the\n // service worker/PWA documentation.\n navigator.serviceWorker.ready.then(() => {\n console.log(\n 'This web app is being served cache-first by a service ' +\n 'worker. To learn more, visit https://bit.ly/CRA-PWA'\n );\n });\n } else {\n // Is not localhost. Just register service worker\n registerValidSW(swUrl, config);\n }\n });\n }\n}\n\nfunction registerValidSW(swUrl, config) {\n navigator.serviceWorker\n .register(swUrl)\n .then(registration => {\n registration.onupdatefound = () => {\n const installingWorker = registration.installing;\n if (installingWorker == null) {\n return;\n }\n installingWorker.onstatechange = () => {\n if (installingWorker.state === 'installed') {\n if (navigator.serviceWorker.controller) {\n // At this point, the updated precached content has been fetched,\n // but the previous service worker will still serve the older\n // content until all client tabs are closed.\n console.log(\n 'New content is available and will be used when all ' +\n 'tabs for this page are closed. See https://bit.ly/CRA-PWA.'\n );\n\n // Execute callback\n if (config && config.onUpdate) {\n config.onUpdate(registration);\n }\n } else {\n // At this point, everything has been precached.\n // It's the perfect time to display a\n // \"Content is cached for offline use.\" message.\n console.log('Content is cached for offline use.');\n\n // Execute callback\n if (config && config.onSuccess) {\n config.onSuccess(registration);\n }\n }\n }\n };\n };\n })\n .catch(error => {\n console.error('Error during service worker registration:', error);\n });\n}\n\nfunction checkValidServiceWorker(swUrl, config) {\n // Check if the service worker can be found. If it can't reload the page.\n fetch(swUrl, {\n headers: { 'Service-Worker': 'script' }\n })\n .then(response => {\n // Ensure service worker exists, and that we really are getting a JS file.\n const contentType = response.headers.get('content-type');\n if (\n response.status === 404 ||\n (contentType != null && contentType.indexOf('javascript') === -1)\n ) {\n // No service worker found. Probably a different app. Reload the page.\n navigator.serviceWorker.ready.then(registration => {\n registration.unregister().then(() => {\n window.location.reload();\n });\n });\n } else {\n // Service worker found. Proceed as normal.\n registerValidSW(swUrl, config);\n }\n })\n .catch(() => {\n console.log(\n 'No internet connection found. App is running in offline mode.'\n );\n });\n}\n\nexport function unregister() {\n if ('serviceWorker' in navigator) {\n navigator.serviceWorker.ready\n .then(registration => {\n registration.unregister();\n })\n .catch(error => {\n console.error(error.message);\n });\n }\n}\n","import React from 'react';\nimport ReactDOM from 'react-dom';\nimport './index.scss';\nimport App from './App';\nimport * as serviceWorker from './serviceWorker';\n\nReactDOM.render(, document.getElementById('root'));\n\n// If you want your app to work offline and load faster, you can change\n// unregister() to register() below. Note this comes with some pitfalls.\n// Learn more about service workers: https://bit.ly/CRA-PWA\nserviceWorker.unregister();\n"],"sourceRoot":""}
\ No newline at end of file
diff --git a/static/js/main.f79f5540.chunk.js.map b/static/js/main.f79f5540.chunk.js.map
deleted file mode 100644
index ce5d258..0000000
--- a/static/js/main.f79f5540.chunk.js.map
+++ /dev/null
@@ -1 +0,0 @@
-{"version":3,"sources":["verifySentence.js","converters.js","canvas/Toolbox.js","canvas/StepMenu.js","canvas/config.js","canvas/EGVariable.js","canvas/EGCut.js","canvas/Canvas.js","intro/CreateNew.js","intro/IntroWindow.js","App.js","serviceWorker.js","index.js"],"names":["require","binary","unary","arrToRegex","arr","map","el","replace","join","uReg","Object","keys","regexStr","binaryRegex","RegExp","atomicRegex","parenthesisRegex","sentence","verifyRecursive","res","match","exec","operators","escapeRegExp","string","binaryOperators","binarySymbReplace","unaryOperators","countUnary","statement","matchesList","val","op","c","split","some","charAt","stripUnary","s","convertStatement","substr","convertToEG","repeat","formula","String","verifySentence","parenthesis","left","right","eg","getMatchingParen","start","parens","j","length","Toolbox","props","state","functions","str","func","highlight","this","hidden","Fragment","className","ref","canvas","onClick","setSelection","React","Component","StepMenu","event","step","disabled","preventDefault","setStep","hide","currentStep","stepInfo","backEnabled","forwardEnabled","style","color","getColor","handleClick","src","process","gridSize","cutPadding","horizontal","vertical","cutCornerRadius","initialSeparation","EGVariable","text","createRef","getCoords","bind","x","y","cursorOver","dragging","panzoom","window","addEventListener","onMouseMove","handleDragStart","handleDragEnd","enableHighlight","selectedCallback","id","setState","current","cursor","evt","pause","resume","setCoords","clientX","clientY","Math","round","config","removeEventListener","pointerEvents","interaction","fill","onMouseEnter","onMouseLeave","children","EGCut","cut","BB","getBBoxData","update","bounding","_x","_y","_w","_h","getBBox","width","height","interval","setInterval","setTimeout","clearInterval","childEl","fillOpacity","strokeOpacity","stroke","rx","toString","ry","nanoid","Canvas","canvasContainer","renderStep","changePos","getSVGCoords","highlightCut","startSelection","proof","premises","conclusion","steps","data","moveListeners","highlights","var","cbFunction","insert","console","log","erase","erasure","iterate","iteration","dcRemove","doubleCutRemove","dcAdd","doubleCutAdd","selectable","nameOfFunction","copyID","insertID","copyStep","isInNestedGraph","copy","copyContents","findID","concat","changeCutLevel","level","push","erased","parent","findParent","index","indexOf","splice","ID","inside","cut1_id","cut2_id","cut1","type","cutID","firstCut","secondCut","newContents","childID","parentID","parentStep","copyDataMap","newMap","m","copyDataArray","newArr","a","newStep","change","idFound","changeLevelArray","changeLevelMap","mapID","oldStep","oldData","newData","d","h","w","searchedStep","findInArray","findInMap","findIDArray","findIDMap","Array","assign","odd","stepIndex","renderRecurse","jsx","groupElement","unshift","highlightVar","setXY","key","Panzoom","maxZoom","minZoom","vw","max","document","documentElement","clientWidth","innerWidth","vh","clientHeight","innerHeight","currentX","maxX","maxY","stepZero","initXYRecurse","gapSize","X","initXY","convertToArray","i","subExp","moveTo","zoomTo","domX","domY","pt","createSVGPoint","matrixTransform","getScreenCTM","inverse","zoomWithWheel","onWheel","CreateNew","handleChange","removePremise","verify","create","e","target","value","setupFunc","tex","symbol","convertToTeX","closeBtn","formulaInput","onChange","math","getFormulaCell","IntroContent","IntroWindow","createView","callCreate","animateAway","createShown","floatingWindowCSS","App","createNewProof","setupProof","openCanvas","saveProof","introWindow","initialCSS","canvasOpen","popupOpen","Boolean","location","hostname","ReactDOM","render","getElementById","navigator","serviceWorker","ready","then","registration","unregister","catch","error","message"],"mappings":"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","file":"static/js/main.f79f5540.chunk.js","sourcesContent":["/* \r\n * Return a boolean indicating if the inputted sentence is \r\n * a correctly formatted. Utilizes a recursive technique,\r\n * evaluating each sentence as though it were an atomic\r\n * sentence or any phi and psi combined with a binary \r\n * operator. \r\n*/\r\n\r\nconst { binary, unary } = require('./operators.json')\r\n\r\nfunction escapeRegExp(string) {\r\n return string.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\$&'); // $& means the whole matched string\r\n}\r\n\r\nfunction arrToRegex(arr) {\r\n arr = arr.map(el => escapeRegExp(el));\r\n return '(?:' + arr.join('|') + ')'\r\n} \r\n\r\nconst uReg = arrToRegex(Object.keys(unary));\r\nconst regexStr = `^(${uReg}*[A-Za-z]+|${uReg}*\\\\((.*)\\\\))(${arrToRegex(Object.keys(binary))})(${uReg}*[A-Za-z]+|${uReg}*\\\\((.*)\\\\))$`\r\nlet binaryRegex = new RegExp(regexStr) // eslint-disable-line\r\nlet atomicRegex = new RegExp(`^${uReg}*[A-Za-z]+$`)\r\nlet parenthesisRegex = new RegExp(`^${uReg}*\\\\((.*)\\\\)$`)\r\n\r\nfunction verifyRecursive(sentence) {\r\n let res\r\n if (sentence.match(atomicRegex)) return true;\r\n else if ((res = binaryRegex.exec(sentence)) !== null) {\r\n if (res == null) return false;\r\n if (res[2] && res[5]) \r\n return verifyRecursive(res[2]) && verifyRecursive(res[5]);\r\n else if (res[2]) \r\n return verifyRecursive(res[2]);\r\n else if (res[5]) \r\n return verifyRecursive(res[5]);\r\n else return true;\r\n } else if ((res = parenthesisRegex.exec(sentence)) !== null)\r\n return verifyRecursive(res[1])\r\n}\r\n\r\nexport {\r\n binaryRegex,\r\n atomicRegex,\r\n parenthesisRegex\r\n}\r\n\r\nexport default (sentence) => {\r\n // filter out spaces\r\n sentence = sentence.replace(/\\s/g, '')\r\n return verifyRecursive(sentence);\r\n}","import verifySentence, { \r\n parenthesisRegex, \r\n binaryRegex,\r\n atomicRegex\r\n} from './verifySentence';\r\n\r\nconst operators = require('./operators.json')\r\n\r\nfunction escapeRegExp(string) {\r\n return string.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\$&'); // $& means the whole matched string\r\n}\r\n\r\nconst binaryOperators = operators.binary\r\nlet keys = Object.keys(binaryOperators);\r\nkeys = keys.map(el => escapeRegExp(el));\r\nconst binarySymbReplace = new RegExp('(?:' + keys.join('|') + ')', 'g')\r\n\r\nconst unaryOperators = operators.unary\r\n\r\nconst convertToTeX = (formula) => {\r\n if (typeof formula === 'string' || formula instanceof String) {\r\n // filter out spaces\r\n formula = formula.replace(/\\s/g, '')\r\n let symbol\r\n // replace all binary operators\r\n while ((symbol = binarySymbReplace.exec(formula)) !== null) {\r\n formula = formula.substr(0,symbol['index']) \r\n + binaryOperators[symbol[0]] + ' '\r\n + formula.substr(symbol['index'] + symbol[0].length);\r\n }\r\n // replace all unary operators\r\n for (let i in Object.keys(unaryOperators)) {\r\n symbol = Object.keys(unaryOperators)[i];\r\n formula = formula.replace(new RegExp(escapeRegExp(symbol), 'g'), unaryOperators[symbol] + ' ');\r\n }\r\n // filter out all other characters\r\n formula = formula.replace(/[^()A-Za-z\\\\\\s]/g, '')\r\n return formula\r\n }\r\n else return \"\"\r\n}\r\n\r\nfunction countUnary(statement) {\r\n const matchesList = (val) => (op) => op === val;\r\n let c = 0;\r\n for (c in statement.split(\"\"))\r\n if (!Object.keys(unaryOperators).some(matchesList(statement.charAt(c))))\r\n break;\r\n return c;\r\n}\r\n\r\nconst stripUnary = (s, convertStatement) => {\r\n if (convertStatement == null) \r\n convertStatement = true;\r\n let c = countUnary(s);\r\n let statement = s.substr(c)\r\n if (convertStatement) statement = convertToEG(statement)\r\n else statement = '{' + statement + '}'\r\n return \"(\".repeat(c) + statement + \")\".repeat(c)\r\n}\r\n\r\nconst convertToEG = (formula) => {\r\n if ((typeof formula === 'string' || formula instanceof String) && verifySentence(formula)) {\r\n // filter out spaces\r\n formula = formula.replace(/\\s/g, '')\r\n let binary = binaryRegex.exec(formula)\r\n let parenthesis = parenthesisRegex.exec(formula)\r\n let unary = atomicRegex.exec(formula)\r\n if (binary) {\r\n let left = convertToEG(binary[1])\r\n let right = convertToEG(binary[4])\r\n let symConversion = operators.eg[binary[3]];\r\n return symConversion.replace(/\\$1/g, left).replace(/\\$2/g, right)\r\n } else if (parenthesis) {\r\n if (countUnary(formula) != 0) {\r\n return stripUnary(formula)\r\n }\r\n return convertToEG(parenthesis[1]);\r\n } else if (unary) {\r\n return stripUnary(formula, false);\r\n } else return null;\r\n }\r\n else return null;\r\n}\r\n\r\n/* Given a string and the index of the open parenthesis, this\r\n * will return the index of the closed parenthesis\r\n */\r\nconst getMatchingParen = (formula, start) => {\r\n // hold the number of '(' minus the number of ')'\r\n let parens = 0\r\n let j = start\r\n while (j < formula.length) {\r\n if (formula[j] === '(') {\r\n parens++\r\n }\r\n else if (formula[j] === ')') {\r\n parens--\r\n // if parens is 0, then the current ')' matches the start parenthesis\r\n if (parens === 0)\r\n return j\r\n }\r\n j++\r\n }\r\n}\r\n\r\n/* Converts a string representing an Existential Graph into\r\n * a nested array. Acts recursively, calling iteslf again\r\n * When a pair of parentehses are found. If given an index i,\r\n * this will start from that index.\r\n * For example: \r\n * \"((({P})){Q}{R}){P}\" => [ [ [['P']],'Q','R' ],'P' ]\r\n */\r\nconst convertToArray = (formula, i = 0) => {\r\n if (typeof formula === 'string' || formula instanceof String) {\r\n // hold the array of the current level that will be returned\r\n let arr = []\r\n // loop through the string\r\n while (i < formula.length) {\r\n // if closing parenthesis, return the array for this subexpression\r\n if (formula[i] === '(') {\r\n // find the matching pair of parentheses of the subexpression\r\n let j = getMatchingParen(formula, i)\r\n // push the subexpression into the array\r\n let subExp = formula.substr(i+1, j-1)\r\n if (subExp)\r\n arr.push(convertToArray(formula.substr(i+1, j-1)))\r\n i = j\r\n }\r\n // if a variable is found, push it to the array\r\n else if (formula[i] === '{') {\r\n let text = formula[++i];\r\n if (text === '}') arr.push('\\u00A0')\r\n else arr.push(text)\r\n i++\r\n }\r\n i++\r\n }\r\n // return the array that values the current expression\r\n return arr\r\n }\r\n else return null\r\n}\r\n\r\nexport {\r\n convertToTeX,\r\n convertToEG,\r\n convertToArray,\r\n verifySentence\r\n}","import React from 'react';\r\n\r\nclass Toolbox extends React.Component {\r\n constructor(props) {\r\n super(props);\r\n this.state = {\r\n functions: [\r\n {\r\n str: \"Iterate/Deiterate\",\r\n func: 'iterate',\r\n highlight: { 'cut': 'all', 'var': 'all' }\r\n },\r\n {\r\n str: \"Remove Double Cut\",\r\n func: 'dcRemove',\r\n highlight: { 'cut': 'all' }\r\n },\r\n {\r\n str: \"Add Double Cut\",\r\n func: 'dcAdd',\r\n highlight: { 'cut': 'all', 'var': 'all' }\r\n },\r\n {\r\n str: \"Insertion\",\r\n func: 'insert',\r\n highlight: { 'cut': 'odd', 'var': 'odd' }\r\n },\r\n {\r\n str: \"Erasure\",\r\n func: 'erase',\r\n highlight: { 'cut': 'even', 'var': 'even' }\r\n }\r\n ]\r\n };\r\n }\r\n\r\n componentDidMount() { \r\n }\r\n\r\n render() {\r\n if (this.props.hidden) return ;\r\n return (\r\n
\r\n );\r\n }\r\n}\r\n\r\nexport default Toolbox;","import React from 'react';\r\nimport { ReactSVG } from 'react-svg';\r\n\r\nclass StepMenu extends React.Component {\r\n handleClick(event, step, disabled) {\r\n event.preventDefault();\r\n if (!disabled) {\r\n // Must update color before updating props to allow component to\r\n // render with the proper current color rather than the state before\r\n this.props.setStep(step);\r\n }\r\n }\r\n\r\n getColor(disabled) {\r\n return disabled ? \"rgb(136, 136, 136)\" : \"rgb(68, 68, 68)\";\r\n }\r\n\r\n render() {\r\n let { hide, currentStep, stepInfo } = this.props;\r\n if (hide) return ();\r\n let backEnabled = currentStep === (stepInfo.length - 1);\r\n let forwardEnabled = currentStep === 0;\r\n return (\r\n \r\n
\r\n Step {currentStep + 1} of {stepInfo.length}\r\n
\r\n \r\n );\r\n }\r\n}\r\n\r\nexport default StepMenu;","export default {\r\n gridSize: 1,\r\n cutPadding: {\r\n horizontal: 10,\r\n vertical: 5\r\n },\r\n cutCornerRadius: 10,\r\n initialSeparation: 50,\r\n}","import React from 'react';\r\nimport config from './config';\r\n\r\nclass EGVariable extends React.Component {\r\n constructor(props) {\r\n super(props);\r\n this.text = React.createRef()\r\n this.getCoords = this.props.getCoords\r\n this.handleClick = this.handleClick.bind(this);\r\n this.state = {\r\n x: props.x,\r\n y: props.y,\r\n cursorOver: false,\r\n dragging: false\r\n };\r\n\r\n this.panzoom = this.props.panzoom\r\n\r\n window.addEventListener('mousemove', this.onMouseMove.bind(this))\r\n window.addEventListener('mousedown', this.handleDragStart.bind(this))\r\n window.addEventListener('mouseup', this.handleDragEnd.bind(this))\r\n window.addEventListener('click', this.handleClick)\r\n }\r\n\r\n handleClick() {\r\n if (this.state.cursorOver \r\n && this.props.enableHighlight \r\n && this.props.selectedCallback) \r\n {\r\n this.props.selectedCallback(this.props.id);\r\n this.setState({ cursorOver: false });\r\n }\r\n }\r\n\r\n componentDidMount() { \r\n this.text.current.style.cursor = \"pointer\";\r\n }\r\n\r\n handleDragStart(evt) {\r\n if (this.state.cursorOver) {\r\n this.panzoom.pause()\r\n this.setState({ dragging: true })\r\n }\r\n }\r\n\r\n handleDragEnd(evt) {\r\n this.panzoom.resume()\r\n let { x, y } = this.state;\r\n this.props.setCoords(x, y);\r\n this.setState({ dragging: false })\r\n }\r\n\r\n onMouseMove(evt) {\r\n if (this.state.dragging) {\r\n let { x, y } = this.getCoords(evt.clientX, evt.clientY)\r\n x = Math.round(x/config.gridSize)*config.gridSize\r\n y = Math.round(y/config.gridSize)*config.gridSize\r\n this.props.setCoords(x, y);\r\n this.setState({ x: x, y: y })\r\n }\r\n }\r\n\r\n componentWillUnmount() {\r\n window.removeEventListener('click', this.handleClick);\r\n window.removeEventListener('mousemove', this.onMouseMove.bind(this))\r\n window.removeEventListener('mousedown', this.handleDragStart.bind(this))\r\n window.removeEventListener('mouseup', this.handleDragEnd.bind(this))\r\n }\r\n\r\n render() {\r\n let highlight = this.state.cursorOver && this.props.enableHighlight;\r\n return (\r\n this.setState({ cursorOver: true })}\r\n onMouseLeave={() => this.setState({ cursorOver: false })}\r\n ref={this.text}>\r\n {this.props.children}\r\n \r\n );\r\n }\r\n}\r\n\r\nexport default EGVariable;","import React from 'react';\r\nimport config from './config';\r\n\r\nclass EGCut extends React.Component {\r\n constructor(props) {\r\n super(props);\r\n this.cut = React.createRef();\r\n this.BB = React.createRef();\r\n this.getBBoxData = this.getBBoxData.bind(this);\r\n this.handleClick = this.handleClick.bind(this);\r\n this.update = this.update.bind(this);\r\n this.state = { highlight: false, bounding: {_x:0,_y:0,_w:0,_h:0} };\r\n\r\n window.addEventListener('click', this.handleClick)\r\n }\r\n\r\n handleClick() {\r\n if (this.state.highlight \r\n && this.props.enableHighlight \r\n && this.props.selectedCallback) \r\n {\r\n this.props.selectedCallback(this.props.id);\r\n this.setState({ highlight: false });\r\n }\r\n }\r\n\r\n getBBoxData() {\r\n if (this.cut.current) {\r\n let { x, y, width, height } = this.cut.current.getBBox();\r\n let _x = x - config.cutPadding.horizontal;\r\n let _y = y - config.cutPadding.vertical;\r\n let _w = width + config.cutPadding.horizontal * 2;\r\n let _h = height + config.cutPadding.vertical * 2;\r\n return { _x, _y, _w, _h };\r\n }\r\n return {};\r\n }\r\n\r\n update() {\r\n if (!this.interval) {\r\n this.interval = setInterval(() => {\r\n this.setState({ bounding: this.getBBoxData() });\r\n }, 1);\r\n setTimeout(() => {\r\n clearInterval(this.interval);\r\n this.interval = null;\r\n }, 100);\r\n }\r\n }\r\n\r\n componentDidMount() { \r\n this.update()\r\n }\r\n\r\n componentDidUpdate() {\r\n this.update()\r\n }\r\n\r\n componentWillUnmount() {\r\n window.removeEventListener('click', this.handleClick);\r\n if (this.interval)\r\n clearInterval(this.interval);\r\n }\r\n\r\n render() {\r\n let childEl = this.props.children;\r\n if (childEl.length < 1) {\r\n childEl = {\" \"}\r\n }\r\n let highlight = this.state.highlight && this.props.enableHighlight;\r\n let { _x, _y, _w, _h } = this.state.bounding;\r\n return (\r\n \r\n this.setState({ highlight: true })}\r\n onMouseLeave={() => this.setState({ highlight: false })}\r\n rx={config.cutCornerRadius.toString()} \r\n ry={config.cutCornerRadius.toString()}\r\n />\r\n \r\n {this.props.children}\r\n \r\n \r\n );\r\n }\r\n}\r\n\r\nexport default EGCut;","import React from 'react';\r\nimport { convertToArray } from '../converters';\r\nimport Toolbox from './Toolbox';\r\nimport StepMenu from './StepMenu';\r\nimport EGVariable from './EGVariable';\r\nimport EGCut from './EGCut';\r\nimport './Canvas.scss';\r\nimport Panzoom from 'panzoom';\r\nimport config from './config';\r\nimport { NotificationContainer, NotificationManager } from 'react-notifications';\r\nconst nanoid = require('nanoid').nanoid;\r\n\r\n// some defaults: \r\n// blocks are automatically 22px high\r\n\r\nconst TEXT_H = 22;\r\n\r\nfunction initXY(step, level) {\r\n let data = {}\r\n let currentX = 0\r\n let currentY = 0\r\n let maxX = 0\r\n let maxY = 0\r\n\r\n // gapSize should be equal to the number of level changes\r\n // in between two variables, so that we can evenly place \r\n // them initially across the screen\r\n function initXYRecurse(step, level, gapSize) {\r\n console.log(data)\r\n for (let s in step) {\r\n if (step[s] instanceof Array && step[s].length > 0) {\r\n let id = nanoid()\r\n step[s] = { data: initXYRecurse(step[s], level + 1), id: id, type: \"cut\" }\r\n data[id] = { type: \"cut\", level: level }\r\n } else {\r\n let X = currentX;\r\n let Y = currentY;\r\n let id = nanoid()\r\n data[id] = { \r\n type: \"var\",\r\n var: step[s], \r\n x: Math.round(X/config.gridSize)*config.gridSize, \r\n y: Math.round(Y/config.gridSize)*config.gridSize,\r\n level: level\r\n }\r\n step[s] = id\r\n maxY = Y > maxY ? Y : maxY;\r\n maxX = X > maxX ? X : maxX;\r\n currentX += config.initialSeparation\r\n }\r\n }\r\n return step\r\n }\r\n return { stepZero: { data: initXYRecurse(step, level), h: maxY + TEXT_H, w: maxX }, data: data }\r\n}\r\n\r\nclass Canvas extends React.Component {\r\n constructor(props) {\r\n super(props);\r\n this.canvas = React.createRef();\r\n this.canvasContainer = React.createRef();\r\n\r\n this.renderStep = this.renderStep.bind(this);\r\n this.changePos = this.changePos.bind(this);\r\n this.getSVGCoords = this.getSVGCoords.bind(this);\r\n this.highlightCut = this.highlightCut.bind(this);\r\n this.startSelection = this.startSelection.bind(this);\r\n\r\n let { premises, conclusion, steps, data } = this.props.proof;\r\n this.state = {\r\n proof: {\r\n premises: premises,\r\n conclusion: conclusion\r\n },\r\n steps: steps || [],\r\n data: data || {},\r\n currentStep: 0,\r\n moveListeners: [],\r\n highlights: {\r\n cut: 'none', // 'none', 'odd', 'even', 'all'\r\n var: 'none'\r\n },\r\n cbFunction: null,\r\n interaction: true,\r\n functions: {\r\n insert: (id) => {\r\n console.log(\"INSERTION\")\r\n },\r\n erase: (id) => {\r\n console.log(\"ERASURE\")\r\n return this.erasure(id);\r\n },\r\n iterate: (id) => {\r\n console.log(\"ITERATION\")\r\n return this.iteration(id, this.state.steps[this.state.currentStep].data[0].id);\r\n },\r\n dcRemove: (id) => {\r\n console.log(\"DOUBLE CUT Remove\")\r\n return this.doubleCutRemove(id);\r\n },\r\n dcAdd: (id) => {\r\n console.log(\"DOUBLE CUT Add\")\r\n return this.doubleCutAdd(id);\r\n \r\n }\r\n }\r\n }\r\n }\r\n\r\n startSelection(selectable, nameOfFunction) {\r\n let { steps, currentStep } = this.state;\r\n // only allow steps to be conducted at the end of a proof\r\n if (currentStep+1 !== steps.length) {\r\n return\r\n }\r\n this.setState({ \r\n highlights: selectable, \r\n interaction: false, \r\n cbFunction: (id) => {\r\n let successful = this.state.functions[nameOfFunction](id); \r\n if (successful) \r\n this.setState({ \r\n highlights: {\r\n cut: 'none', \r\n var: 'none'\r\n },\r\n interaction: true, \r\n cbFunction: null });\r\n }\r\n });\r\n }\r\n\r\n /* Given a copyID and insertID, the iteration function creates a new step,\r\n * and adds a copy of the data represented by copyID at the location of insertID\r\n * only if the location of insertID is a child of copyID\r\n */\r\n iteration(copyID, insertID) {\r\n let { steps, currentStep, data } = this.state;\r\n let step = this.copyStep(steps[currentStep]);\r\n // If the insertID data is not in a subgraph of the copID data, return\r\n if (!this.isInNestedGraph(step, insertID, copyID)) {\r\n console.log(\"Insert selection is not in a subgraph of Copy selection\");\r\n return false;\r\n }\r\n // use findID to find the data represented by the two IDs\r\n let copy = this.copyContents(this.findID(step, copyID));\r\n if (!copy) {\r\n console.log(\"Copy ID could not be found in Iterate\");\r\n return false;\r\n }\r\n let insert = this.findID(step, insertID);\r\n if (!insert) {\r\n console.log(\"Insert ID could not be found in Iterate\");\r\n return false;\r\n }\r\n insert.data = insert.data.concat(copy);\r\n // Change the levels of the copy data\r\n this.changeCutLevel(step, copy.id, data[insert.id].level + 1)\r\n // Update the state\r\n currentStep+=1;\r\n steps.push(step);\r\n this.setState({ steps: steps, currentStep: currentStep, data:data });\r\n return true;\r\n }\r\n\r\n erasure(id) {\r\n let { steps, currentStep, data } = this.state;\r\n // Create a new step\r\n let step = this.copyStep(steps[currentStep]);\r\n // Find the data that will be erased\r\n let erased = this.findID(step, id);\r\n if (!erased) {\r\n return false;\r\n }\r\n // Get the parent of the erased section\r\n let parent = this.findParent(step, id)\r\n if (!parent) {\r\n return false;\r\n }\r\n // Remove the erased data from the parent's data array\r\n const index = parent.data.indexOf(erased);\r\n if (index > -1)\r\n parent.data.splice(index, 1);\r\n else {\r\n return false;\r\n }\r\n // Update the state\r\n currentStep+=1;\r\n steps.push(step);\r\n this.setState({ steps: steps, currentStep: currentStep, data:data });\r\n return true;\r\n }\r\n\r\n /* Adds a double cut given the ID of the data that will be inside the cut.\r\n * Will only run if the current step is the last step.\r\n */\r\n doubleCutAdd(ID) {\r\n let { steps, currentStep, data } = this.state;\r\n // create a new step\r\n let step = this.copyStep(steps[currentStep]);\r\n // use findID to find the data represented by the id\r\n // this is the data that will be inside the two new cuts\r\n let inside = this.findID(step, ID);\r\n if (!inside) {\r\n return false;\r\n }\r\n // create a new cut with another one inside it\r\n let cut1_id = nanoid();\r\n let cut2_id = nanoid();\r\n let cut2 = {\r\n data: [inside],\r\n id: cut2_id,\r\n type: \"cut\"\r\n }\r\n let cut1 = {\r\n data: [cut2],\r\n id: cut1_id,\r\n type: \"cut\"\r\n }\r\n // Set the levels of the two cuts\r\n let level = data[ID].level\r\n data[cut2_id] = { type: \"cut\", level: level + 1};\r\n data[cut1_id] = { type: \"cut\", level: level};\r\n // increase the level of the inside cut along with all cuts inside of it by 2\r\n this.changeCutLevel(step, ID, 2)\r\n\r\n // get the parent of the selection\r\n let parent = this.findParent(step, ID)\r\n if (!parent) {\r\n return false;\r\n }\r\n // Add the contents of the new cuts to the data array\r\n // after removing the original contents\r\n const index = parent.data.indexOf(inside);\r\n if (index > -1) {\r\n parent.data.splice(index, 1);\r\n }\r\n parent.data = parent.data.concat(cut1);\r\n // Change the state data accordingly\r\n currentStep+=1;\r\n steps.push(step);\r\n this.setState({ steps: steps, currentStep: currentStep, data:data });\r\n return true;\r\n }\r\n\r\n /* Removes a double cut given the ID of the outside cut.\r\n * Will only run if the current step is the last step.\r\n * Creates a deep copy of the current step, and replaces the cut with\r\n * the given ID with the contents of the second cut, only if they exist.\r\n * Then adds the edited copy of the current step to the end of the step array.\r\n */\r\n doubleCutRemove(cutID) {\r\n let { steps, currentStep, data } = this.state;\r\n // Create a new step\r\n let step = this.copyStep(steps[currentStep]);\r\n\r\n // use findID to find the cut with the given ID\r\n let firstCut = this.findID(step, cutID);\r\n // If it is actually a cut and has another cut inside\r\n if (firstCut && firstCut.type === \"cut\") {\r\n let secondCut = firstCut.data;\r\n if (secondCut && secondCut.length === 1 && secondCut[0].type === \"cut\") {\r\n // Get the data inside the second cut\r\n let newContents = secondCut[0].data;\r\n // Get the parent of the original cut being removed\r\n let parent = this.findParent(step, cutID)\r\n if (!parent) {\r\n return false;\r\n }\r\n this.changeCutLevel(step, secondCut[0].id, -2)\r\n // Remove the first cut from the data array\r\n const index = parent.data.indexOf(firstCut);\r\n if (index > -1) {\r\n parent.data.splice(index, 1);\r\n }\r\n // Add the contents of the second cut to the data array\r\n parent.data = parent.data.concat(newContents);\r\n // Update the state\r\n currentStep+=1;\r\n steps.push(step);\r\n this.setState({ steps: steps, currentStep: currentStep, data:data });\r\n return true;\r\n }\r\n else return false;\r\n }\r\n else return false;\r\n }\r\n\r\n\r\n /* Given a step and two IDs, will return true if the data of ChildID is\r\n * in a nested graph of parentID in the current step.\r\n */\r\n isInNestedGraph(step, childID, parentID) {\r\n let parentStep = this.findParent(step, parentID);\r\n if (!parentStep) {\r\n console.log(\"Parent Data could not be found\");\r\n return false;\r\n }\r\n let childStep = this.findID(parentStep, childID);\r\n if (!childStep) {\r\n console.log(\"Child is not in nested graph of Parent\");\r\n return false;\r\n }\r\n return true;\r\n }\r\n\r\n /* Given a step or a cut, will copy the contents inside with new IDs\r\n * and return the new data. This permits inserting new data into the graph.\r\n * Levels for cuts will start at 0 and increase accordingly\r\n */\r\n copyContents(step) {\r\n let { data } = this.state;\r\n // Copies the data of a map and returns it\r\n // Also updates the state.data map according to new generated IDs\r\n function copyDataMap(map, level) {\r\n let newMap = {};\r\n for (let m in map) {\r\n // If an ID is found, generate a new one\r\n if (m === 'id') {\r\n let id = nanoid();\r\n newMap[m] = id;\r\n // Add the new data to state.data via a deep copy\r\n data[id] = {\r\n type: \"cut\",\r\n level: level\r\n }\r\n }\r\n // Otherwise, if not a data array, copy the contents\r\n else if (m !== 'data'){\r\n newMap[m] = map[m]\r\n }\r\n // If a data array, copy using helper function\r\n else {\r\n newMap[m] = copyDataArray(map[m], level+1)\r\n }\r\n }\r\n return newMap;\r\n }\r\n // Copies the data of an array and returns it\r\n // Also updates state.data according to new generated IDs\r\n function copyDataArray(arr, level) {\r\n let newArr = [];\r\n for (let a in arr) {\r\n // If an ID found, generate a new one\r\n if (typeof arr[a] === 'string') {\r\n let id = nanoid();\r\n newArr.push(id);\r\n // Add the new data to state.data via a deep copy\r\n data[id] = {\r\n type: \"var\",\r\n var: data[arr[a]].var,\r\n x: data[arr[a]].x,\r\n y: data[arr[a]].y,\r\n }\r\n }\r\n // otherwise, call the other helper function to copy contents\r\n else {\r\n newArr.push(copyDataMap(arr[a], level))\r\n }\r\n }\r\n return newArr;\r\n }\r\n let newStep = copyDataMap(step, 0);\r\n this.setState({ data: data })\r\n return newStep;\r\n }\r\n\r\n /* Given a step and the ID of a cut, will iterate through all cuts within\r\n * that cut and change their level by a specified amount.\r\n */\r\n changeCutLevel(step, id, change) {\r\n let { data } = this.state\r\n // If the ID is for a variable, only increase it's level\r\n if (data[id].type === \"var\") {\r\n data[id].level += change;\r\n return\r\n }\r\n // when true, the levels should change in the functions below\r\n let idFound = false\r\n // Changes the \r\n function changeLevelMap(map) {\r\n // get the id for the current map\r\n let mapID;\r\n if (map.id) {\r\n mapID = map.id\r\n // if it matches the id being searched, update the boolean\r\n if (mapID === id) {\r\n idFound = true;\r\n }\r\n }\r\n // If the ID has been found, update the level of the current cut\r\n if (idFound) {\r\n data[mapID].level += change;\r\n }\r\n // call the function of the data array if it exists\r\n if (map.data){\r\n changeLevelArray(map.data);\r\n }\r\n }\r\n function changeLevelArray(arr) {\r\n for (let a in arr) {\r\n // If a non-string is found (a cut)\r\n if (typeof arr[a] !== 'string') {\r\n // Change the level of the cut\r\n changeLevelMap(arr[a])\r\n }\r\n // If string is found, change the level of the variable\r\n else if (idFound){\r\n data[arr[a]].level += change;\r\n }\r\n }\r\n }\r\n changeLevelArray(step.data)\r\n this.setState({ data: data })\r\n }\r\n\r\n // Performs a deep copy of oldStep into newStep, used to not change previous steps\r\n // By allowing them to be copied without using a reference\r\n copyStep(oldStep) {\r\n let newStep = {};\r\n function copyDataMap(oldData) {\r\n let newData = {};\r\n for (let d in oldData) {\r\n // If an id or type if found, copy directly\r\n if(typeof oldData[d] === 'string') {\r\n newData[d] = oldData[d];\r\n }\r\n // Otherwise if an array is found, copy using helper function\r\n else {\r\n newData[d] = copyDataArray(oldData[d]);\r\n }\r\n }\r\n return newData;\r\n }\r\n function copyDataArray(oldData) {\r\n let newData = [];\r\n for (let d in oldData) {\r\n // If an ID is found (variable), copy directly\r\n if(typeof oldData[d] === 'string') {\r\n newData.push(oldData[d]);\r\n }\r\n // If a map was found (cut), copy using helper function\r\n else {\r\n newData.push(copyDataMap(oldData[d]));\r\n }\r\n }\r\n return newData;\r\n }\r\n // Copy the data, width, and height of the original into the new step\r\n newStep.data = copyDataArray(oldStep.data);\r\n newStep.h = oldStep.h;\r\n newStep.w = oldStep.w;\r\n return newStep;\r\n }\r\n\r\n /* Finds and returns the item that is the parent of the item\r\n * with the specified ID, given the step to search as well.\r\n */\r\n findParent(searchedStep, id) {\r\n // holds the parent of the id\r\n let parent = searchedStep\r\n // Searches an array for the ID, returns true if it is found\r\n function findInArray(arr) {\r\n for (let a in arr) {\r\n // If an ID is found, compare it\r\n if (typeof arr[a] === 'string') {\r\n if (arr[a] === id) {\r\n return true;\r\n }\r\n }\r\n // Otherwise if a datamap is found, check the ID\r\n else {\r\n // If ID matches, return true\r\n if (arr[a].id && arr[a].id === id) {\r\n return true;\r\n }\r\n // Otherwise, search the datamap\r\n else {\r\n findInMap(arr[a])\r\n }\r\n }\r\n }\r\n return false;\r\n }\r\n function findInMap(map) {\r\n // if the map contains data, search the data\r\n if (map.data) {\r\n // if found, set parent to this map\r\n if(findInArray(map.data)) {\r\n parent = map;\r\n }\r\n }\r\n }\r\n findInArray(searchedStep.data);\r\n return parent;\r\n }\r\n\r\n // finds and returns the item with the specified ID in a given step\r\n findID(searchedStep, id) {\r\n // Find the ID in an array\r\n function findIDArray(arr) {\r\n for (let a in arr) {\r\n // if a string, aka an ID\r\n if (typeof arr[a] === 'string') {\r\n // return the ID if found\r\n if (arr[a] === id) {\r\n return id;\r\n }\r\n }\r\n // if a data map is found with the correct id, return the data map\r\n else if (arr[a].id === id) {\r\n return arr[a];\r\n // otherwise, call findID step on the datamap that has the incorrect ID\r\n } else {\r\n let s = findIDMap(arr[a]);\r\n if (s)\r\n return s;\r\n }\r\n }\r\n }\r\n // Finds the ID in a data map representing a step\r\n function findIDMap(step) {\r\n for (let s in step) {\r\n // if an array is found, call findIDArray on each element\r\n if (step[s] instanceof Array) {\r\n return findIDArray(step[s]);\r\n // if an id is found, check if it matches and return the data if so\r\n } else if (s === \"id\") {\r\n if (step[s] === id)\r\n return step;\r\n }\r\n }\r\n }\r\n return findIDMap(searchedStep);\r\n }\r\n\r\n changePos(id, x, y) {\r\n let { data } = this.state;\r\n Object.assign(data[id], { x: x, y: y })\r\n this.setState(data)\r\n }\r\n\r\n highlightCut(level) {\r\n if (this.state.highlights.cut === 'all') return true;\r\n let odd = false;\r\n if (level % 2 === 1) odd = true;\r\n if (this.state.highlights.cut === 'odd' && odd) return true;\r\n else if (this.state.highlights.cut === 'even' && !odd) return true;\r\n return false;\r\n }\r\n\r\n highlightVar(level) {\r\n if (this.state.highlights.var === 'all') return true;\r\n let odd = false;\r\n if (level % 2 === 1) odd = true;\r\n if (this.state.highlights.var === 'odd' && odd) return true;\r\n else if (this.state.highlights.var === 'even' && !odd) return true;\r\n return false;\r\n }\r\n\r\n renderStep(stepIndex) {\r\n let { data } = this.state;\r\n let step = this.state.steps[stepIndex]\r\n if (step) {\r\n const setXY = (id,x,y) => {\r\n data[id].x = x;\r\n data[id].y = y;\r\n this.setState({ data: data })\r\n }\r\n\r\n const renderRecurse = (step) => {\r\n let jsx = [];\r\n for (let s in step) {\r\n if (step[s].type === \"cut\") {\r\n let level = data[step[s].id].level;\r\n let groupElement = (\r\n \r\n {renderRecurse(step[s].data)}\r\n \r\n );\r\n jsx.push(groupElement);\r\n } else {\r\n let el = this.state.data[step[s]];\r\n let level = data[step[s]].level;\r\n jsx.unshift(\r\n setXY(step[s],x,y)}\r\n key={step[s]}>\r\n {el.var}\r\n \r\n );\r\n }\r\n }\r\n return jsx;\r\n }\r\n renderRecurse.bind(this);\r\n return renderRecurse(step.data)\r\n }\r\n }\r\n\r\n componentDidMount() { \r\n this.panzoom = Panzoom(this.canvas.current, {\r\n maxZoom: 6,\r\n minZoom: 0.5\r\n });\r\n // this.canvasContainer.current.addEventListener('wheel', this.panzoom.zoomWithWheel);\r\n const vw = Math.max(document.documentElement.clientWidth, window.innerWidth || 0);\r\n const vh = Math.max(document.documentElement.clientHeight, window.innerHeight || 0);\r\n // if there are no existing steps, init first step\r\n let { steps } = this.state;\r\n if (steps.length === 0) {\r\n let { premises, conclusion } = this.state.proof;\r\n let { stepZero, data } = initXY(convertToArray(premises.join('')), 0);\r\n steps.push(stepZero);\r\n this.setState({ steps: steps, data: data });\r\n }\r\n // required to use setState to trigger re-render after creation of panzoom\r\n this.setState({ currentStep: 0 });\r\n let step = this.state.steps[this.state.currentStep];\r\n\r\n this.panzoom.moveTo(vw/2 - step.w, vh/2 - step.h);\r\n this.panzoom.zoomTo(vw/2 - step.w, vh/2 - step.h, 2);\r\n }\r\n\r\n componentWillUnmount() {\r\n window.removeEventListener('resize', this);\r\n }\r\n\r\n getSVGCoords(domX, domY) {\r\n var pt = this.canvasContainer.current.createSVGPoint();\r\n\r\n pt.x = domX;\r\n pt.y = domY;\r\n\r\n return pt.matrixTransform(this.canvas.current.getScreenCTM().inverse());\r\n }\r\n\r\n render() {\r\n let zoomWithWheel = () => {}\r\n let { steps, currentStep } = this.state;\r\n if (this.panzoom)\r\n zoomWithWheel = this.panzoom.zoomWithWheel\r\n return (\r\n
this.setState({ premises: premises.concat(['']) }) }>\r\n Add New Premise\r\n
\r\n
\r\n
\r\n
\r\n
Conclusion
\r\n
\r\n {this.getFormulaCell(conclusion)}\r\n
\r\n
\r\n );\r\n }\r\n}\r\n\r\nexport default CreateNew;","import React from 'react';\r\nimport CreateNew from './CreateNew';\r\nimport { ReactSVG } from 'react-svg';\r\nimport './intro.scss';\r\n\r\nconst IntroContent = () => (\r\n
\r\n
\r\n
Existential Graphs
\r\n
\r\n Using this tool, you can initialize proofs in the existential graph schema and then you can go through the process of solving them. You can save these proofs and look back at them later.\r\n
\r\n );\r\n }\r\n}\r\n\r\nexport default App;\r\n","// This optional code is used to register a service worker.\r\n// register() is not called by default.\r\n\r\n// This lets the app load faster on subsequent visits in production, and gives\r\n// it offline capabilities. However, it also means that developers (and users)\r\n// will only see deployed updates on subsequent visits to a page, after all the\r\n// existing tabs open on the page have been closed, since previously cached\r\n// resources are updated in the background.\r\n\r\n// To learn more about the benefits of this model and instructions on how to\r\n// opt-in, read https://bit.ly/CRA-PWA\r\n\r\nconst isLocalhost = Boolean(\r\n window.location.hostname === 'localhost' ||\r\n // [::1] is the IPv6 localhost address.\r\n window.location.hostname === '[::1]' ||\r\n // 127.0.0.0/8 are considered localhost for IPv4.\r\n window.location.hostname.match(\r\n /^127(?:\\.(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)){3}$/\r\n )\r\n);\r\n\r\nexport function register(config) {\r\n if (process.env.NODE_ENV === 'production' && 'serviceWorker' in navigator) {\r\n // The URL constructor is available in all browsers that support SW.\r\n const publicUrl = new URL(process.env.PUBLIC_URL, window.location.href);\r\n if (publicUrl.origin !== window.location.origin) {\r\n // Our service worker won't work if PUBLIC_URL is on a different origin\r\n // from what our page is served on. This might happen if a CDN is used to\r\n // serve assets; see https://github.com/facebook/create-react-app/issues/2374\r\n return;\r\n }\r\n\r\n window.addEventListener('load', () => {\r\n const swUrl = `${process.env.PUBLIC_URL}/service-worker.js`;\r\n\r\n if (isLocalhost) {\r\n // This is running on localhost. Let's check if a service worker still exists or not.\r\n checkValidServiceWorker(swUrl, config);\r\n\r\n // Add some additional logging to localhost, pointing developers to the\r\n // service worker/PWA documentation.\r\n navigator.serviceWorker.ready.then(() => {\r\n console.log(\r\n 'This web app is being served cache-first by a service ' +\r\n 'worker. To learn more, visit https://bit.ly/CRA-PWA'\r\n );\r\n });\r\n } else {\r\n // Is not localhost. Just register service worker\r\n registerValidSW(swUrl, config);\r\n }\r\n });\r\n }\r\n}\r\n\r\nfunction registerValidSW(swUrl, config) {\r\n navigator.serviceWorker\r\n .register(swUrl)\r\n .then(registration => {\r\n registration.onupdatefound = () => {\r\n const installingWorker = registration.installing;\r\n if (installingWorker == null) {\r\n return;\r\n }\r\n installingWorker.onstatechange = () => {\r\n if (installingWorker.state === 'installed') {\r\n if (navigator.serviceWorker.controller) {\r\n // At this point, the updated precached content has been fetched,\r\n // but the previous service worker will still serve the older\r\n // content until all client tabs are closed.\r\n console.log(\r\n 'New content is available and will be used when all ' +\r\n 'tabs for this page are closed. See https://bit.ly/CRA-PWA.'\r\n );\r\n\r\n // Execute callback\r\n if (config && config.onUpdate) {\r\n config.onUpdate(registration);\r\n }\r\n } else {\r\n // At this point, everything has been precached.\r\n // It's the perfect time to display a\r\n // \"Content is cached for offline use.\" message.\r\n console.log('Content is cached for offline use.');\r\n\r\n // Execute callback\r\n if (config && config.onSuccess) {\r\n config.onSuccess(registration);\r\n }\r\n }\r\n }\r\n };\r\n };\r\n })\r\n .catch(error => {\r\n console.error('Error during service worker registration:', error);\r\n });\r\n}\r\n\r\nfunction checkValidServiceWorker(swUrl, config) {\r\n // Check if the service worker can be found. If it can't reload the page.\r\n fetch(swUrl, {\r\n headers: { 'Service-Worker': 'script' }\r\n })\r\n .then(response => {\r\n // Ensure service worker exists, and that we really are getting a JS file.\r\n const contentType = response.headers.get('content-type');\r\n if (\r\n response.status === 404 ||\r\n (contentType != null && contentType.indexOf('javascript') === -1)\r\n ) {\r\n // No service worker found. Probably a different app. Reload the page.\r\n navigator.serviceWorker.ready.then(registration => {\r\n registration.unregister().then(() => {\r\n window.location.reload();\r\n });\r\n });\r\n } else {\r\n // Service worker found. Proceed as normal.\r\n registerValidSW(swUrl, config);\r\n }\r\n })\r\n .catch(() => {\r\n console.log(\r\n 'No internet connection found. App is running in offline mode.'\r\n );\r\n });\r\n}\r\n\r\nexport function unregister() {\r\n if ('serviceWorker' in navigator) {\r\n navigator.serviceWorker.ready\r\n .then(registration => {\r\n registration.unregister();\r\n })\r\n .catch(error => {\r\n console.error(error.message);\r\n });\r\n }\r\n}\r\n","import React from 'react';\r\nimport ReactDOM from 'react-dom';\r\nimport './index.scss';\r\nimport App from './App';\r\nimport * as serviceWorker from './serviceWorker';\r\n\r\nReactDOM.render(, document.getElementById('root'));\r\n\r\n// If you want your app to work offline and load faster, you can change\r\n// unregister() to register() below. Note this comes with some pitfalls.\r\n// Learn more about service workers: https://bit.ly/CRA-PWA\r\nserviceWorker.unregister();\r\n"],"sourceRoot":""}
\ No newline at end of file