<commit_before>import { CursiveFont, SansSerifFont, MonospaceFont } from './Fonts'
import { Vertex } from '../../common/Geometry'
import Shape, { shapeOptions } from '../Shape'

const options = {
  ...shapeOptions,
  ...{
    inputText: {
      title: 'Text',
      type: 'textarea',
    },
    inputFont: {
      title: 'Font',
      type: 'dropdown',
      choices: ['Cursive', 'Sans Serif', 'Monospace'],
    },
    rotateDir: {
      title: 'Rotate',
      type: 'dropdown',
      choices: ['None', 'Inside', 'Outside'],
    },
  }
}

export default class InputText extends Shape {
  constructor() {
    super('Text')
  }

  getInitialState() {
    return {
      ...super.getInitialState(),
      ...{
        type: 'inputText',
        inputText: 'Sandify',
        inputFont: 'Cursive',
        rotateDir: 'None',
        repeatEnabled: false,
        startingSize: 50
      }
    }
  }

  getVertices(state) {
    let points = []
    let prevLetter = ''
    let x = 0.0
    for (let chi = 0; chi < state.shape.inputText.length; chi++) {
      var letter = state.shape.inputText[chi]
      if (prevLetter === 'b' || prevLetter === 'v' || prevLetter === 'o' || prevLetter === 'w') {
        prevLetter = letter
        if (letter.search('/[a-z]/') === -1 && state.shape.inputFont === 'Cursive')
        {
          letter = letter + '*'
        }
      }
      else {
        prevLetter = letter
      }

      var shape = undefined
      if (state.shape.inputFont === 'Cursive') {
        shape = CursiveFont(letter)
      } else if (state.shape.inputFont === 'Sans Serif') {
        shape = SansSerifFont(letter)
      } else if (state.shape.inputFont === 'Monospace') {
        shape = MonospaceFont(letter)
      } else {
        // Internal error, but I'm going to just recover
        shape = CursiveFont(letter)
      }

      for (let vi = 0; vi < shape.vertices.length; vi++) {
        points.push(Vertex(shape.vertices[vi].x + x, shape.vertices[vi].y))
      }
      x += shape.vertices[shape.vertices.length-1].x
    }
    let widthOffset = x / 2.0
    return points.map( (point) => {
      return Vertex(point.x - widthOffset, point.y)
    })
  }

  getOptions() {
    return options
  }
}
<commit_msg>Rename the rotate choices.<commit_after>import { CursiveFont, SansSerifFont, MonospaceFont } from './Fonts'
import { Vertex } from '../../common/Geometry'
import Shape, { shapeOptions } from '../Shape'

const options = {
  ...shapeOptions,
  ...{
    inputText: {
      title: 'Text',
      type: 'textarea',
    },
    inputFont: {
      title: 'Font',
      type: 'dropdown',
      choices: ['Cursive', 'Sans Serif', 'Monospace'],
    },
    rotateDir: {
      title: 'Rotate',
      type: 'dropdown',
      choices: ['Top', 'Center', 'Bottom'],
    },
  }
}

export default class InputText extends Shape {
  constructor() {
    super('Text')
  }

  getInitialState() {
    return {
      ...super.getInitialState(),
      ...{
        type: 'inputText',
        inputText: 'Sandify',
        inputFont: 'Cursive',
        rotateDir: 'Center',
        repeatEnabled: false,
        startingSize: 50
      }
    }
  }

  getVertices(state) {
    let points = []
    let prevLetter = ''
    let x = 0.0
    for (let chi = 0; chi < state.shape.inputText.length; chi++) {
      var letter = state.shape.inputText[chi]
      if (prevLetter === 'b' || prevLetter === 'v' || prevLetter === 'o' || prevLetter === 'w') {
        prevLetter = letter
        if (letter.search('/[a-z]/') === -1 && state.shape.inputFont === 'Cursive')
        {
          letter = letter + '*'
        }
      }
      else {
        prevLetter = letter
      }

      var shape = undefined
      if (state.shape.inputFont === 'Cursive') {
        shape = CursiveFont(letter)
      } else if (state.shape.inputFont === 'Sans Serif') {
        shape = SansSerifFont(letter)
      } else if (state.shape.inputFont === 'Monospace') {
        shape = MonospaceFont(letter)
      } else {
        // Internal error, but I'm going to just recover
        shape = CursiveFont(letter)
      }

      for (let vi = 0; vi < shape.vertices.length; vi++) {
        points.push(Vertex(shape.vertices[vi].x + x, shape.vertices[vi].y))
      }
      x += shape.vertices[shape.vertices.length-1].x
    }
    let widthOffset = x / 2.0
    return points.map( (point) => {
      return Vertex(point.x - widthOffset, point.y)
    })
  }

  getOptions() {
    return options
  }
}
<|endoftext|>


<commit_before><commit_msg>forgot to add toJSON<commit_after><|endoftext|>


<commit_before>'use strict'
const app = require('app')
const BrowserWindow = require('browser-window')
const path = require('path')
const fs = require('fs')
const ipc = require('ipc')

// report crashes to the Electron project
require('crash-reporter').start()

// adds debug features like hotkeys for triggering dev tools and reload
require('electron-debug')()

// WHITELABELING OPTIONS
var options = {
	page_title: 'Aufbau' // What do you want to display in the menu bar?
}

// Return requested path location
function sendPath (mode) {
	function (event, arg) {
		var path = app.getPath(arg)
		if (mode == 'async') {
		  event.sender.send('asynchronous-reply', path)
		} else if (mode == 'sync') {
			event.returnValue = path
		}
	}
}

// Allow for messages to be sent from client
ipc.on('asynchronous-message', sendPath('async'))
ipc.on('synchronous-message', sendPath('sync'))

function createMainWindow () {
	const win = new BrowserWindow({
		width: 1280,
		height: 768,
		resizable: true,
		title: options.page_title
	})

	// Set the download directory to being off of the user's home folder
	var tilde_downloads = path.join(app.getHomeDir(), 'Downloads')
	win.webContents.session.setDownloadPath(tilde_downloads)

	// Whenever we finish loading a page, inject some javascript into it to add our back button
	// Don't do this if we're on the main page, though
	win.webContents.on('did-finish-load', function (webContents) {
		var page_title = webContents.sender.getTitle()
		var index_path
		var home_btn_css
		var home_btn_js
		if (page_title != 'Aufbau home') {
			// Add css
			home_btn_css = fs.readFileSync(path.join(__dirname, 'home-btn.css'), 'utf-8')
			webContents.sender.insertCSS(home_btn_css)

			// Add home button
			index_path = path.join(__dirname, 'www', 'index.html')
			home_btn_js = fs.readFileSync(path.join(__dirname, 'home-btn.jst'), 'utf-8').replace('{{index_path}}', index_path)
			webContents.sender.executeJavaScript(home_btn_js)
		}
	})

	win.loadUrl(`file://${__dirname}/www/index.html`)
	win.on('closed', onClosed)

	return win
}

function onClosed() {
	// deref the window
	// for multiple windows store them in an array
	mainWindow = null
}

// prevent window being GC'd
let mainWindow

app.on('window-all-closed', function () {
	if (process.platform !== 'darwin') {
		app.quit()
	}
})

app.on('activate-with-no-open-windows', function () {
	if (!mainWindow) {
		mainWindow = createMainWindow()
	}
})

app.on('ready', function () {
	var Menu = require('menu')
	var menu_template = require('./menus.js')(BrowserWindow)
	var menu = Menu.buildFromTemplate(menu_template)
	Menu.setApplicationMenu(menu)

	mainWindow = createMainWindow()
})
<commit_msg>Fix missing return statement<commit_after>'use strict'
const app = require('app')
const BrowserWindow = require('browser-window')
const path = require('path')
const fs = require('fs')
const ipc = require('ipc')

// report crashes to the Electron project
require('crash-reporter').start()

// adds debug features like hotkeys for triggering dev tools and reload
require('electron-debug')()

// WHITELABELING OPTIONS
var options = {
	page_title: 'Aufbau' // What do you want to display in the menu bar?
}

// Return requested path location
function sendPath (mode) {
	return function (event, arg) {
		var path = app.getPath(arg)
		if (mode == 'async') {
		  event.sender.send('asynchronous-reply', path)
		} else if (mode == 'sync') {
			event.returnValue = path
		}
	}
}

// Allow for messages to be sent from client
ipc.on('asynchronous-message', sendPath('async'))
ipc.on('synchronous-message', sendPath('sync'))

function createMainWindow () {
	const win = new BrowserWindow({
		width: 1280,
		height: 768,
		resizable: true,
		title: options.page_title
	})

	// Set the download directory to being off of the user's home folder
	var tilde_downloads = path.join(app.getHomeDir(), 'Downloads')
	win.webContents.session.setDownloadPath(tilde_downloads)

	// Whenever we finish loading a page, inject some javascript into it to add our back button
	// Don't do this if we're on the main page, though
	win.webContents.on('did-finish-load', function (webContents) {
		var page_title = webContents.sender.getTitle()
		var index_path
		var home_btn_css
		var home_btn_js
		if (page_title != 'Aufbau home') {
			// Add css
			home_btn_css = fs.readFileSync(path.join(__dirname, 'home-btn.css'), 'utf-8')
			webContents.sender.insertCSS(home_btn_css)

			// Add home button
			index_path = path.join(__dirname, 'www', 'index.html')
			home_btn_js = fs.readFileSync(path.join(__dirname, 'home-btn.jst'), 'utf-8').replace('{{index_path}}', index_path)
			webContents.sender.executeJavaScript(home_btn_js)
		}
	})

	win.loadUrl(`file://${__dirname}/www/index.html`)
	win.on('closed', onClosed)

	return win
}

function onClosed() {
	// deref the window
	// for multiple windows store them in an array
	mainWindow = null
}

// prevent window being GC'd
let mainWindow

app.on('window-all-closed', function () {
	if (process.platform !== 'darwin') {
		app.quit()
	}
})

app.on('activate-with-no-open-windows', function () {
	if (!mainWindow) {
		mainWindow = createMainWindow()
	}
})

app.on('ready', function () {
	var Menu = require('menu')
	var menu_template = require('./menus.js')(BrowserWindow)
	var menu = Menu.buildFromTemplate(menu_template)
	Menu.setApplicationMenu(menu)

	mainWindow = createMainWindow()
})
<|endoftext|>


<commit_before><commit_msg>Remove redundant check for targets<commit_after><|endoftext|>


<commit_before><commit_msg>Remove `setTestGenerator` shenanigans.<commit_after><|endoftext|>


<commit_before><commit_msg>Added MVP nagios api<commit_after><|endoftext|>


<commit_before>exports.BattleMovedex = {
	"divingtalon": {
		num: 704,
		accuracy: 100,
		basePower: 40,
		category: "Physical",
		desc: "Deals damage to one adjacent target. Makes contact. Priority +1.",
		shortDesc: "Usually goes first.",
		id: "divingtalon",
		isViable: true,
		name: "Diving Talon",
		pp: 20,
		priority: 1,
		isContact: true,
		secondary: false,
		target: "normal",
		type: "Flying"
	},
	"firerocket": {
		num: 703,
		accuracy: 100,
		basePower: 40,
		category: "Physical",
		desc: "Deals damage to one adjacent target. Makes contact. Priority +1.",
		shortDesc: "Usually goes first.",
		id: "firerocket",
		isViable: true,
		name: "Fire Rocket",
		pp: 20,
		priority: 1,
		isContact: true,
		secondary: false,
		target: "normal",
		type: "Fire"
	},
	"rabidfrenzy": {
		num: 370,
		accuracy: 100,
		basePower: 120,
		category: "Physical",
		desc: "Deals damage to one adjacent target and lowers the user's Defense and Special Defense by 1 stage. Makes contact.",
		shortDesc: "Lowers the user's Defense and Sp. Def by 1.",
		id: "rapidfrenzy",
		isViable: true,
		name: "Rabid Frenzy",
		pp: 5,
		priority: 0,
		isContact: true,
		self: {
			boosts: {
				def: -1,
				spd: -1
			}
		},
		secondary: false,
		target: "normal",
		type: "Dark"
	},
	"rootbomb": {
		num: 510,
		accuracy: 100,
		basePower: 30,
		category: "Physical",
		desc: "Deals damage to all adjacent foes and changes type to Grass before hitting.",
		shortDesc: "Changes foes type to Grass before hitting.",
		id: "rootbomb",
		name: "Root Bomb",
		pp: 15,
		priority: 0,
		onHit: function(target) {
			this.add('-start', target, 'typechange', 'Grass');
			target.types = ['Grass'];
		},
		secondary: false,
		target: "normal",
		type: "Fire"
	},
	"shadowsword": {
		num: 610,
		accuracy: 100,
		basePower: 85,
		category: "Physical",
		desc: "Deals damage to one adjacent target with a 20% chance to lower its Defense by 1 stage. Makes contact.",
		shortDesc: "20% chance to lower the target's Defense by 1",
		id: "shadowsword",
		name: "Shadow Sword",
		pp: 20,
		priority: 0,
		isContact: true,
		secondary: {
			chance: 20,
			boosts: {
				def: -1
			}
		},
		target: "ghost",
		type: "Ghost"
	},
	"shortcircuit": {
		num: 705,
		accuracy: 100,
		basePower: 40,
		category: "Special",
		desc: "Deals damage to one adjacent target. Makes contact. Priority +1.",
		shortDesc: "Usually goes first.",
		id: "shortcircuit",
		isViable: true,
		name: "Short Circuit",
		pp: 20,
		priority: 1,
		isContact: true,
		secondary: false,
		target: "normal",
		type: "Electric"
	},
        "vendetta": {
                num: 702,
                accuracy: 85,
                basePower: 120,
                category: "Special",
                desc: "Deals damage to one adjacent target with a 20 chance to hit it with Spite.",
                shortDesc: "20% chance to spite the target.",
                id: "vendetta",
                isViable: true,
                name: "Vendetta",
                pp: 5,
                priority: 0,
                onHit: function(target) {
                        var spiteroll = this.random(100);
                        if (spiteroll > 80) {
                                if (target.deductPP(target.lastMove, 4)) {
                                        this.add("-activate", target, 'move: vendetta', target.lastMove, 4);
                                        return;
                                }
                        }
                        return false;
                },
                target: "normal",
                type: "Ghost"
        },
	"voidhorn": {
		num: 701,
		accuracy: 85,
		basePower: 120,
		category: "Physical",
		desc: "Deals damage to one adjacent target",
		shortDesc: "Strong Ghost-Type Move",
		id: "voidhorn",
		isViable: true,
		name: "Void Horn",
		pp: 10,
		priority: 0,
		isContact: true,
		secondary: false,
		target: "normal",
		type: "Ghost"
	},
};
<commit_msg>More Moves<commit_after>exports.BattleMovedex = {
	"distortion": {
		num: 701,
		accuracy: 100,
		basePower: 80,
		category: "Special",
		desc: "Blah Blah Blah",
		shortDesc: "Blah Blah Blah",
		id: "distortion",
		isViable: true,
		name: "Distortion",
		pp: 10,
		priority: -1,
		beforeTurnCallback: function(pokemon, target) {
			decision = this.willMove(target);
			if (decision.move.priority !== 0) {
				this.willMove(pokemon).move.priority = decision.move.priority + 1;
			}
		},
		secondary: false,
		target: "normal",
		type: "Psychic"
	}
	"divingtalon": {
		num: 702,
		accuracy: 100,
		basePower: 40,
		category: "Physical",
		desc: "Deals damage to one adjacent target. Makes contact. Priority +1.",
		shortDesc: "Usually goes first.",
		id: "divingtalon",
		isViable: true,
		name: "Diving Talon",
		pp: 20,
		priority: 1,
		isContact: true,
		secondary: false,
		target: "normal",
		type: "Flying"
	},
	"firerocket": {
		num: 703,
		accuracy: 100,
		basePower: 40,
		category: "Physical",
		desc: "Deals damage to one adjacent target. Makes contact. Priority +1.",
		shortDesc: "Usually goes first.",
		id: "firerocket",
		isViable: true,
		name: "Fire Rocket",
		pp: 20,
		priority: 1,
		isContact: true,
		secondary: false,
		target: "normal",
		type: "Fire"
	},
	"focusball": {
		num: 704,
		accuracy: 100,
		basePower: 80,
		category: "Special",
		desc: "Deals damage to one adjacent target with a 20% chance to lower its Special Defense by 1 stage.",
		shortDesc: "20% chance to lower the target's Sp. Def by 1.",
		id: "focusball",
		isViable: true,
		name: "Focus Ball",
		pp: 15,
		priority: 0,
		secondary: {
			chance: 20,
			boosts: {
				spd: -1
			}
		},
		target: "normal",
		type: "Fighting"
	},
	"mindforce": {
		num: 705,
		accuracy: 100,
		basePower: 80,
		category: "Special",
		desc: "Deals damage to one adjacent target. Fails if the target did not select a status move for use this turn, or if the target moves before the user. Priority +1.",
		shortDesc: "Usually goes first. Fails if target is not using a status move.",
		id: "mindforce",
		isViable: true,
		name: "Mind Force",
		pp: 5,
		priority: 1,
		onTryHit: function(target) {
			decision = this.willMove(target);
			if (!decision || decision.choice !== 'move' || (decision.move.category !== 'Status' && decision.move.id !== 'mefirst')) {
				return false;
			}
		},
		secondary: false,
		target: "normal",
		type: "Psychic"
	},
	"rabidfrenzy": {
		num: 706,
		accuracy: 100,
		basePower: 120,
		category: "Physical",
		desc: "Deals damage to one adjacent target and lowers the user's Defense and Special Defense by 1 stage. Makes contact.",
		shortDesc: "Lowers the user's Defense and Sp. Def by 1.",
		id: "rabidfrenzy",
		isViable: true,
		name: "Rabid Frenzy",
		pp: 5,
		priority: 0,
		isContact: true,
		self: {
			boosts: {
				def: -1,
				spd: -1
			}
		},
		secondary: false,
		target: "normal",
		type: "Dark"
	},
	"rootbomb": {
		num: 707,
		accuracy: 100,
		basePower: 30,
		category: "Physical",
		desc: "Deals damage to all adjacent foes and changes type to Grass before hitting.",
		shortDesc: "Changes foes type to Grass before hitting.",
		id: "rootbomb",
		name: "Root Bomb",
		pp: 15,
		priority: 0,
		onHit: function(target) {
			this.add('-start', target, 'typechange', 'Grass');
			target.types = ['Grass'];
		},
		secondary: false,
		target: "normal",
		type: "Fire"
	},
	"shadowsword": {
		num: 708,
		accuracy: 100,
		basePower: 85,
		category: "Physical",
		desc: "Deals damage to one adjacent target with a 20% chance to lower its Defense by 1 stage. Makes contact.",
		shortDesc: "20% chance to lower the target's Defense by 1",
		id: "shadowsword",
		name: "Shadow Sword",
		pp: 20,
		priority: 0,
		isContact: true,
		secondary: {
			chance: 20,
			boosts: {
				def: -1
			}
		},
		target: "ghost",
		type: "Ghost"
	},
	"shortcircuit": {
		num: 709,
		accuracy: 100,
		basePower: 40,
		category: "Special",
		desc: "Deals damage to one adjacent target. Makes contact. Priority +1.",
		shortDesc: "Usually goes first.",
		id: "shortcircuit",
		isViable: true,
		name: "Short Circuit",
		pp: 20,
		priority: 1,
		isContact: true,
		secondary: false,
		target: "normal",
		type: "Electric"
	},
        "vendetta": {
                num: 710,
                accuracy: 85,
                basePower: 120,
                category: "Special",
                desc: "Deals damage to one adjacent target with a 20 chance to hit it with Spite.",
                shortDesc: "20% chance to spite the target.",
                id: "vendetta",
                isViable: true,
                name: "Vendetta",
                pp: 5,
                priority: 0,
                onHit: function(target) {
                        var spiteroll = this.random(100);
                        if (spiteroll > 80) {
                                if (target.deductPP(target.lastMove, 4)) {
                                        this.add("-activate", target, 'move: vendetta', target.lastMove, 4);
                                        return;
                                }
                        }
                        return false;
                },
                target: "normal",
                type: "Ghost"
        },
	"voidhorn": {
		num: 711,
		accuracy: 85,
		basePower: 120,
		category: "Physical",
		desc: "Deals damage to one adjacent target",
		shortDesc: "Strong Ghost-Type Move",
		id: "voidhorn",
		isViable: true,
		name: "Void Horn",
		pp: 10,
		priority: 0,
		isContact: true,
		secondary: false,
		target: "normal",
		type: "Ghost"
	},
};
<|endoftext|>


<commit_before><commit_msg>deleted the dummy file<commit_after><|endoftext|>


<commit_before>/**
 * The UIAElement class is the superclass for all user interface elements in the context of the Automation instrument
 * for automating user interface testing of iOS apps.
 * @constructor
 */
var UIAElement = function () {

};

UIAElement.prototype = Object.prototype;

/**
 * Returns the screen position to tap for the specified element.
 * @returns {Point}
 */
UIAElement.prototype.hitpoint = function () {
    return new Point;
};
/**
 * Returns the position of the object on the main screen.
 * @returns {Rect}
 */
UIAElement.prototype.rect = function () {
    return new Rect;
};
/**
 * Returns an array of the activity indicators contained by the specified object.
 * @returns {UIAElementArray.<UIActivityIndicator>}
 */
UIAElement.prototype.activityIndicators = function () {
    return new UIAElementArray;
};
/**
 * Returns an object representing an activity view.
 * @returns {UIAActivityView}
 */
UIAElement.prototype.activityView = function () {
    return new UIAActivityView;
};
/**
 * Returns an array containing the parents of the specified object.
 * @returns {UIAElementArray.<UIAElement>}
 */
UIAElement.prototype.ancestry = function () {
    return new UIAElementArray;
};
/**
 * Returns an array of buttons contained by the specified object.
 * @returns {UIAElementArray.<UIAButton>}
 */
UIAElement.prototype.buttons = function () {
    return new UIAElementArray;
};
/**
 * Returns an array of collection views contained by the specified object.
 * @returns {UIAElementArray.<UIACollectionView>}
 */
UIAElement.prototype.collectionViews = function () {
    return new UIAElementArray;
};
/**
 * Returns an array of elements contained by the specified object.
 * @returns {UIAElementArray.<UIAElement>}
 */
UIAElement.prototype.elements = function () {
    return new UIAElementArray;
};
/**
 * Returns an array of images contained by the specified object.
 * @returns {UIAElementArray.<UIAElement>}
 */
UIAElement.prototype.images = function () {
    return new UIAElementArray;
};
/**
 * Returns an array of links contained by the specified object.
 * @returns {UIAElementArray.<UIALink>}
 */
UIAElement.prototype.links = function () {
    return new UIAElementArray;
};
/**
 * Returns the app’s navigation bar.
 * @returns {UIAElement}
 */
UIAElement.prototype.navigationBar = function () {
    return new UIAElement;
};
/**
 * Returns an array of navigation bar objects contained by this object.
 * @returns {UIAElementArray.<UIANavigationBar>}
 */
UIAElement.prototype.navigationBars = function () {
    return new UIAElementArray;
};
/**
 * Returns an array of page indicators contained by the specified object.
 * @returns {UIAElementArray.<UIAPageIndicator>}
 */
UIAElement.prototype.pageIndicators = function () {
    return new UIAElementArray;
};
/**
 * Returns the parent of the specified element.
 * @returns {UIAElement}
 */
UIAElement.prototype.parent = function () {
    return new UIAElement;
};
/**
 * Returns an array of picker objects contained by the specified object.
 * @returns {UIAElementArray.<UIAPicker>}
 */
UIAElement.prototype.pickers = function () {
    return new UIAElementArray;
};
/**
 * Returns the popover object associated with the specified object, if one exists.
 * @returns {UIAPopover}
 */
UIAElement.prototype.popover = function () {
    return new UIAPopover;
};
/**
 * Returns an array of progress indicators contained by the specified object.
 * @returns {UIAElementArray.<UIAProgressIndicator>}
 */
UIAElement.prototype.progressIndicators = function () {
    return new UIAElementArray;
};
/**
 * Returns an array of scroll views contained by the specified object.
 * @returns {UIAElementArray.<UIAScrollView>}
 */
UIAElement.prototype.scrollViews = function () {
    return new UIAElementArray;
};
/**
 * Returns an array of search bars contained by the specified object.
 * @returns {UIAElementArray.<UIASearchBar>}
 */
UIAElement.prototype.searchBars = function () {
    return new UIAElementArray;
};
/**
 * Returns an array of secure text fields contained by the specified object.
 * @returns {UIAElementArray.<UIASecureTextField>}
 */
UIAElement.prototype.secureTextFields = function () {
    return new UIAElementArray;
};
/**
 * Returns an array of segmented controls contained by the specified object.
 * @returns {UIAElementArray.<UIASegmentedControl>}
 */
UIAElement.prototype.segmentedControls = function () {
    return new UIAElementArray;
};
/**
 * Returns an array of sliders contained by the specified object.
 * @returns {UIAElementArray.<UIASlider>}
 */
UIAElement.prototype.sliders = function () {
    return new UIAElementArray;
};
/**
 * Returns an array of static texts contained by the specified object.
 * @returns {UIAElementArray.<UIAStaticText>}
 */
UIAElement.prototype.staticTexts = function () {
    return new UIAElementArray;
};
/**
 * Returns an array of switches contained by the specified object.
 * @returns {UIAElementArray.<UIASwitch>}
 */
UIAElement.prototype.switches = function () {
    return new UIAElementArray;
};
/**
 * Returns the specified tab bar.
 * @returns {UIAElement}
 */
UIAElement.prototype.tabBar = function () {
    return new UIAElement;
};
/**
 * Returns an array of tab bars contained by this object.
 * @returns {UIAElementArray.<UIATabBar>}
 */
UIAElement.prototype.tabBars = function () {
    return new UIAElementArray;
};
/**
 * Returns an array of table views contained by the specified object.
 * @returns {UIAElementArray.<UIATableView>}
 */
UIAElement.prototype.tableViews = function () {
    return new UIAElementArray;
};
/**
 * Returns an array of text fields contained by the specified object.
 * @returns {UIAElementArray.<UIATextField>}
 */
UIAElement.prototype.textFields = function () {
    return new UIAElementArray;
};
/**
 * Returns an array of text views contained by the specified object.
 * @returns {UIAElementArray.<UIATextView>}
 */
UIAElement.prototype.textViews = function () {
    return new UIAElementArray;
};
/**
 * Returns the specified toolbar.
 * @returns {UIAElement}
 */
UIAElement.prototype.toolbar = function () {
    return new UIAElement;
};
/**
 * Returns an array of toolbars contained by this object.
 * @returns {UIAElementArray.<UIAToolbar>}
 */
UIAElement.prototype.toolbars = function () {
    return new UIAElementArray;
};
/**
 * Returns an array of web views contained by the specified object.
 * @returns {UIAElementArray.<UIAWebView>}
 */
UIAElement.prototype.webViews = function () {
    return new UIAElementArray;
};
/**
 * Double-taps the specified element.
 */
UIAElement.prototype.doubleTap = function () {
};
/**
 * Drags within the bounds of an element.
 * @param {{
     *   UIAElement.prototype.touchCount = Number,
     *   UIAElement.prototype.duration = Number,
     *   UIAElement.prototype.startOffset = Point,
     *   UIAElement.prototype.endOffset = Point
     * }} options - A dictionary that specifies characteristics of the gesture. Valid keys are as UIAElement.prototype.follows =
 * * touchCount. The number of touches to use in the specified gesture. (Effectively, the number of fingers a user
 * would use to make the specified gesture.) The default touch count value is 1.
 * * duration. The length of hold time for the specified gesture. The default duration value for a tap is 0.
 * The default value for touch-and-hold gestures (such as drag, pinch open, and pinch close) is 1.
 * * startOffset. The first offset to use for a multiple-point gesture. The default value is {UIAElement.prototype.x =0.0, UIAElement.prototype.y =0.0}.
 * See the discussion for details.
 * * endOffset. The last offset to use for a multiple-point gesture. The default value is {UIAElement.prototype.x =0.0, UIAElement.prototype.y =0.0}.
 * See the discussion for details.
 */
UIAElement.prototype.dragInsideWithOptions = function (options) {
};
/**
 * Flicks within the bounds of an element.
 * @param {{
     *   UIAElement.prototype.touchCount = Number,
     *   UIAElement.prototype.startOffset = Point,
     *   UIAElement.prototype.endOffset = Point
     * }} options - A dictionary that specifies characteristics of the gesture. Valid keys are as UIAElement.prototype.follows =
 * * touchCount. The number of touches to use in the specified gesture. (Effectively, the number of fingers a user
 * would use to make the specified gesture.) The default touch count value is 1.
 * * startOffset. The first offset to use for a multiple-point gesture. The default value is {UIAElement.prototype.x =0.0, UIAElement.prototype.y =0.0}.
 * See the discussion for details.
 * * endOffset. The last offset to use for a multiple-point gesture. The default value is {UIAElement.prototype.x =0.0, UIAElement.prototype.y =0.0}.
 * See the discussion for details.
 */
UIAElement.prototype.flickInsideWithOptions = function (options) {
};
/**
 * Perform a rotation gesture centered on the specified element.
 * @param {{
     *   UIAElement.prototype.centerOffest = Point,
     *   UIAElement.prototype.duration = Number,
     *   UIAElement.prototype.radius = Number,
     *   UIAElement.prototype.roration = Number,
     *   UIAElement.prototype.touchCount = Number
     * }} options - A dictionary that specifies characteristics of the rotation gesture. Valid keys are as UIAElement.prototype.follows =
 * * centerOffset. The offset to use for the center of the rotate gesture. The default offset value is {UIAElement.prototype.x =0.0, UIAElement.prototype.y =0.0}.
 * * duration. The length of hold time for the specified gesture, in seconds. The default duration value is 1.
 * * radius. The distance in points from the center to the edge of the circular path.
 * * rotation. The length of rotation in radians. The default is pi (π).
 * * touchCount. The number of touches to use in the specified gesture. (Effectively, the number of fingers a user
 * would use to make the specified gesture.) Valid values are 1 to 5. The default is 2.
 */
UIAElement.prototype.rotateWithOptions = function (options) {
};
/**
 * Scrolls until the specified element is visible in a container view. Use this method with tables and web views.
 */
UIAElement.prototype.scrollToVisible = function () {
};
/**
 * Taps the specified element.
 */
UIAElement.prototype.tap = function () {
};
/**
 * Performs the specified gesture on the specified element using a dictionary to specify gesture attributes.
 * @param {{
     *   UIAElement.prototype.tapCount = Number,
     *   UIAElement.prototype.touchCount = Number,
     *   UIAElement.prototype.duration = Number,
     *   UIAElement.prototype.tapOffset = Point
     * }} options - A dictionary that specifies characteristics of the gesture. Valid keys are as UIAElement.prototype.follows =
 * * tapCount. The number of taps that compose the specified gesture. The default value is 1 (single tap).
 * * touchCount. The number of touches to use in the specified gesture. (Effectively, the number of fingers a user
 * would use to make the specified gesture.) The default touch count value is 1.
 * * duration. The length of hold time for the specified gesture. The default duration value for a tap is 0.
 * The default value for touch-and-hold gestures (such as drag, pinch open, and pinch close) is 1.
 * * tapOffset. The offset to use for the specified tap gesture. The default offset value is {UIAElement.prototype.x =0.0, UIAElement.prototype.y =0.0}.
 * See the discussion for details.
 */
UIAElement.prototype.tapWithOptions = function (options) {
};
/**
 * Touches the specified element and holds for the specified duration.
 * @param {Number} duration - The length of time to hold the touch on the element, in seconds.The default duration
 * value for a tap is 0. The default value for touch-and-hold gestures (such as drag, pinch open, and pinch close) is 1.
 */
UIAElement.prototype.touchAndHold = function (duration) {
};
/**
 * Performs a two-finger (two-touch) tap on this element.
 */
UIAElement.prototype.twoFingerTap = function () {
};
/**
 * Use these methods to determine whether an element is still valid.
 * @returns {Boolean}
 */
UIAElement.prototype.checkIsValid = function () {
    return false;
};
/**
 * Determines whether the specified element receives keyboard input.
 * @returns {Number} - Returns 1 if the specified element is the receiver of keyboard input, 0 if not.
 * If the status is not available, it returns null.
 */
UIAElement.prototype.hasKeyboardFocus = function () {
    return 0;
};
/**
 * Determines whether the specified element is enabled.
 * @returns {Number} - Returns 1 if the specified element is enabled, 0 if not. If the status is not available, it returns null.
 */
UIAElement.prototype.isEnabled = function () {
    return 0;
};
/**
 * Returns the specified element’s validity status as of the most recent access.
 * @returns {Boolean}
 */
UIAElement.prototype.isValid = function () {
    return false;
};
/**
 * Determines whether the specified element is visible on the screen.
 * @returns {Number} - Returns 1 if the user interface element represented by the specified element is visible on screen,
 * 0 if not. If the status is not available, it returns null.
 */
UIAElement.prototype.isVisible = function () {
    return 0;
};
/**
 * Waits for the specified element to become invalid.
 * @returns {Boolean}
 */
UIAElement.prototype.waitForInvalid = function () {
    return false;
};
/**
 * Returns a string containing the label attribute of the element.
 * @returns {String}
 */
UIAElement.prototype.lable = function () {
    return "";
};
/**
 * Returns a string containing the name attribute of the element.
 * @returns {String}
 */
UIAElement.prototype.name = function () {
    return "";
};
/**
 * Returns a string containing a value attribute specific to the type of element.
 * @returns {String}
 */
UIAElement.prototype.value = function () {
    return "";
};
/**
 * Returns an element whose name attribute matches a specified string.
 * @param {String} name - A string containing the name to test for.
 * @returns {UIAElement}
 */
UIAElement.prototype.withName = function (name) {
    return new UIAElement;
};
/**
 * Returns the element matching the specified criteria.
 * @param {String} predicateString - A string specifying the match criteria.
 * @returns {UIAElement}
 */
UIAElement.prototype.withPredicate = function (predicateString) {
    return new UIAElement;
};
/**
 * Returns the element containing the specified property with the specified value.
 * @param {Object} value - A string specifying the value that the specified property, if it exists, should match.
 * @param {String} key - A string specifying the property to test for.
 * @returns {UIAElement}
 */
UIAElement.prototype.withValueForKey = function (value, key) {
    return new UIAElement;
};
/**
 * Logs information about the specified element.
 */
UIAElement.prototype.logElement = function () {
};
/**
 * Logs information about the specified element and all of its subelements.
 */
UIAElement.prototype.logElementTree = function () {
};

<commit_msg>style: formatting<commit_after>/**
 * The UIAElement class is the superclass for all user interface elements in the context of the Automation instrument
 * for automating user interface testing of iOS apps.
 * @constructor
 */
var UIAElement = function () {

};

UIAElement.prototype = Object.prototype;

/**
 * Returns the screen position to tap for the specified element.
 * @returns {Point}
 */
UIAElement.prototype.hitpoint = function () {
    return new Point;
};
/**
 * Returns the position of the object on the main screen.
 * @returns {Rect}
 */
UIAElement.prototype.rect = function () {
    return new Rect;
};
/**
 * Returns an array of the activity indicators contained by the specified object.
 * @returns {UIAElementArray.<UIActivityIndicator>}
 */
UIAElement.prototype.activityIndicators = function () {
    return new UIAElementArray;
};
/**
 * Returns an object representing an activity view.
 * @returns {UIAActivityView}
 */
UIAElement.prototype.activityView = function () {
    return new UIAActivityView;
};
/**
 * Returns an array containing the parents of the specified object.
 * @returns {UIAElementArray.<UIAElement>}
 */
UIAElement.prototype.ancestry = function () {
    return new UIAElementArray;
};
/**
 * Returns an array of buttons contained by the specified object.
 * @returns {UIAElementArray.<UIAButton>}
 */
UIAElement.prototype.buttons = function () {
    return new UIAElementArray;
};
/**
 * Returns an array of collection views contained by the specified object.
 * @returns {UIAElementArray.<UIACollectionView>}
 */
UIAElement.prototype.collectionViews = function () {
    return new UIAElementArray;
};
/**
 * Returns an array of elements contained by the specified object.
 * @returns {UIAElementArray.<UIAElement>}
 */
UIAElement.prototype.elements = function () {
    return new UIAElementArray;
};
/**
 * Returns an array of images contained by the specified object.
 * @returns {UIAElementArray.<UIAElement>}
 */
UIAElement.prototype.images = function () {
    return new UIAElementArray;
};
/**
 * Returns an array of links contained by the specified object.
 * @returns {UIAElementArray.<UIALink>}
 */
UIAElement.prototype.links = function () {
    return new UIAElementArray;
};
/**
 * Returns the app’s navigation bar.
 * @returns {UIAElement}
 */
UIAElement.prototype.navigationBar = function () {
    return new UIAElement;
};
/**
 * Returns an array of navigation bar objects contained by this object.
 * @returns {UIAElementArray.<UIANavigationBar>}
 */
UIAElement.prototype.navigationBars = function () {
    return new UIAElementArray;
};
/**
 * Returns an array of page indicators contained by the specified object.
 * @returns {UIAElementArray.<UIAPageIndicator>}
 */
UIAElement.prototype.pageIndicators = function () {
    return new UIAElementArray;
};
/**
 * Returns the parent of the specified element.
 * @returns {UIAElement}
 */
UIAElement.prototype.parent = function () {
    return new UIAElement;
};
/**
 * Returns an array of picker objects contained by the specified object.
 * @returns {UIAElementArray.<UIAPicker>}
 */
UIAElement.prototype.pickers = function () {
    return new UIAElementArray;
};
/**
 * Returns the popover object associated with the specified object, if one exists.
 * @returns {UIAPopover}
 */
UIAElement.prototype.popover = function () {
    return new UIAPopover;
};
/**
 * Returns an array of progress indicators contained by the specified object.
 * @returns {UIAElementArray.<UIAProgressIndicator>}
 */
UIAElement.prototype.progressIndicators = function () {
    return new UIAElementArray;
};
/**
 * Returns an array of scroll views contained by the specified object.
 * @returns {UIAElementArray.<UIAScrollView>}
 */
UIAElement.prototype.scrollViews = function () {
    return new UIAElementArray;
};
/**
 * Returns an array of search bars contained by the specified object.
 * @returns {UIAElementArray.<UIASearchBar>}
 */
UIAElement.prototype.searchBars = function () {
    return new UIAElementArray;
};
/**
 * Returns an array of secure text fields contained by the specified object.
 * @returns {UIAElementArray.<UIASecureTextField>}
 */
UIAElement.prototype.secureTextFields = function () {
    return new UIAElementArray;
};
/**
 * Returns an array of segmented controls contained by the specified object.
 * @returns {UIAElementArray.<UIASegmentedControl>}
 */
UIAElement.prototype.segmentedControls = function () {
    return new UIAElementArray;
};
/**
 * Returns an array of sliders contained by the specified object.
 * @returns {UIAElementArray.<UIASlider>}
 */
UIAElement.prototype.sliders = function () {
    return new UIAElementArray;
};
/**
 * Returns an array of static texts contained by the specified object.
 * @returns {UIAElementArray.<UIAStaticText>}
 */
UIAElement.prototype.staticTexts = function () {
    return new UIAElementArray;
};
/**
 * Returns an array of switches contained by the specified object.
 * @returns {UIAElementArray.<UIASwitch>}
 */
UIAElement.prototype.switches = function () {
    return new UIAElementArray;
};
/**
 * Returns the specified tab bar.
 * @returns {UIAElement}
 */
UIAElement.prototype.tabBar = function () {
    return new UIAElement;
};
/**
 * Returns an array of tab bars contained by this object.
 * @returns {UIAElementArray.<UIATabBar>}
 */
UIAElement.prototype.tabBars = function () {
    return new UIAElementArray;
};
/**
 * Returns an array of table views contained by the specified object.
 * @returns {UIAElementArray.<UIATableView>}
 */
UIAElement.prototype.tableViews = function () {
    return new UIAElementArray;
};
/**
 * Returns an array of text fields contained by the specified object.
 * @returns {UIAElementArray.<UIATextField>}
 */
UIAElement.prototype.textFields = function () {
    return new UIAElementArray;
};
/**
 * Returns an array of text views contained by the specified object.
 * @returns {UIAElementArray.<UIATextView>}
 */
UIAElement.prototype.textViews = function () {
    return new UIAElementArray;
};
/**
 * Returns the specified toolbar.
 * @returns {UIAElement}
 */
UIAElement.prototype.toolbar = function () {
    return new UIAElement;
};
/**
 * Returns an array of toolbars contained by this object.
 * @returns {UIAElementArray.<UIAToolbar>}
 */
UIAElement.prototype.toolbars = function () {
    return new UIAElementArray;
};
/**
 * Returns an array of web views contained by the specified object.
 * @returns {UIAElementArray.<UIAWebView>}
 */
UIAElement.prototype.webViews = function () {
    return new UIAElementArray;
};
/**
 * Double-taps the specified element.
 */
UIAElement.prototype.doubleTap = function () {
};
/**
 * Drags within the bounds of an element.
 * @param {{
 *   UIAElement.prototype.touchCount = Number,
 *   UIAElement.prototype.duration = Number,
 *   UIAElement.prototype.startOffset = Point,
 *   UIAElement.prototype.endOffset = Point
 * }} options - A dictionary that specifies characteristics of the gesture. Valid keys are as UIAElement.prototype.follows =
 * * touchCount. The number of touches to use in the specified gesture. (Effectively, the number of fingers a user
 * would use to make the specified gesture.) The default touch count value is 1.
 * * duration. The length of hold time for the specified gesture. The default duration value for a tap is 0.
 * The default value for touch-and-hold gestures (such as drag, pinch open, and pinch close) is 1.
 * * startOffset. The first offset to use for a multiple-point gesture. The default value is {UIAElement.prototype.x =0.0, UIAElement.prototype.y =0.0}.
 * See the discussion for details.
 * * endOffset. The last offset to use for a multiple-point gesture. The default value is {UIAElement.prototype.x =0.0, UIAElement.prototype.y =0.0}.
 * See the discussion for details.
 */
UIAElement.prototype.dragInsideWithOptions = function (options) {
};
/**
 * Flicks within the bounds of an element.
 * @param {{
 *   UIAElement.prototype.touchCount = Number,
 *   UIAElement.prototype.startOffset = Point,
 *   UIAElement.prototype.endOffset = Point
 * }} options - A dictionary that specifies characteristics of the gesture. Valid keys are as UIAElement.prototype.follows =
 * * touchCount. The number of touches to use in the specified gesture. (Effectively, the number of fingers a user
 * would use to make the specified gesture.) The default touch count value is 1.
 * * startOffset. The first offset to use for a multiple-point gesture. The default value is {UIAElement.prototype.x =0.0, UIAElement.prototype.y =0.0}.
 * See the discussion for details.
 * * endOffset. The last offset to use for a multiple-point gesture. The default value is {UIAElement.prototype.x =0.0, UIAElement.prototype.y =0.0}.
 * See the discussion for details.
 */
UIAElement.prototype.flickInsideWithOptions = function (options) {
};
/**
 * Perform a rotation gesture centered on the specified element.
 * @param {{
 *   UIAElement.prototype.centerOffest = Point,
 *   UIAElement.prototype.duration = Number,
 *   UIAElement.prototype.radius = Number,
 *   UIAElement.prototype.roration = Number,
 *   UIAElement.prototype.touchCount = Number
 * }} options - A dictionary that specifies characteristics of the rotation gesture. Valid keys are as UIAElement.prototype.follows =
 * * centerOffset. The offset to use for the center of the rotate gesture. The default offset value is {UIAElement.prototype.x =0.0, UIAElement.prototype.y =0.0}.
 * * duration. The length of hold time for the specified gesture, in seconds. The default duration value is 1.
 * * radius. The distance in points from the center to the edge of the circular path.
 * * rotation. The length of rotation in radians. The default is pi (π).
 * * touchCount. The number of touches to use in the specified gesture. (Effectively, the number of fingers a user
 * would use to make the specified gesture.) Valid values are 1 to 5. The default is 2.
 */
UIAElement.prototype.rotateWithOptions = function (options) {
};
/**
 * Scrolls until the specified element is visible in a container view. Use this method with tables and web views.
 */
UIAElement.prototype.scrollToVisible = function () {
};
/**
 * Taps the specified element.
 */
UIAElement.prototype.tap = function () {
};
/**
 * Performs the specified gesture on the specified element using a dictionary to specify gesture attributes.
 * @param {{
 *   UIAElement.prototype.tapCount = Number,
 *   UIAElement.prototype.touchCount = Number,
 *   UIAElement.prototype.duration = Number,
 *   UIAElement.prototype.tapOffset = Point
 * }} options - A dictionary that specifies characteristics of the gesture. Valid keys are as UIAElement.prototype.follows =
 * * tapCount. The number of taps that compose the specified gesture. The default value is 1 (single tap).
 * * touchCount. The number of touches to use in the specified gesture. (Effectively, the number of fingers a user
 * would use to make the specified gesture.) The default touch count value is 1.
 * * duration. The length of hold time for the specified gesture. The default duration value for a tap is 0.
 * The default value for touch-and-hold gestures (such as drag, pinch open, and pinch close) is 1.
 * * tapOffset. The offset to use for the specified tap gesture. The default offset value is {UIAElement.prototype.x =0.0, UIAElement.prototype.y =0.0}.
 * See the discussion for details.
 */
UIAElement.prototype.tapWithOptions = function (options) {
};
/**
 * Touches the specified element and holds for the specified duration.
 * @param {Number} duration - The length of time to hold the touch on the element, in seconds.The default duration
 * value for a tap is 0. The default value for touch-and-hold gestures (such as drag, pinch open, and pinch close) is 1.
 */
UIAElement.prototype.touchAndHold = function (duration) {
};
/**
 * Performs a two-finger (two-touch) tap on this element.
 */
UIAElement.prototype.twoFingerTap = function () {
};
/**
 * Use these methods to determine whether an element is still valid.
 * @returns {Boolean}
 */
UIAElement.prototype.checkIsValid = function () {
    return false;
};
/**
 * Determines whether the specified element receives keyboard input.
 * @returns {Number} - Returns 1 if the specified element is the receiver of keyboard input, 0 if not.
 * If the status is not available, it returns null.
 */
UIAElement.prototype.hasKeyboardFocus = function () {
    return 0;
};
/**
 * Determines whether the specified element is enabled.
 * @returns {Number} - Returns 1 if the specified element is enabled, 0 if not. If the status is not available, it returns null.
 */
UIAElement.prototype.isEnabled = function () {
    return 0;
};
/**
 * Returns the specified element’s validity status as of the most recent access.
 * @returns {Boolean}
 */
UIAElement.prototype.isValid = function () {
    return false;
};
/**
 * Determines whether the specified element is visible on the screen.
 * @returns {Number} - Returns 1 if the user interface element represented by the specified element is visible on screen,
 * 0 if not. If the status is not available, it returns null.
 */
UIAElement.prototype.isVisible = function () {
    return 0;
};
/**
 * Waits for the specified element to become invalid.
 * @returns {Boolean}
 */
UIAElement.prototype.waitForInvalid = function () {
    return false;
};
/**
 * Returns a string containing the label attribute of the element.
 * @returns {String}
 */
UIAElement.prototype.lable = function () {
    return "";
};
/**
 * Returns a string containing the name attribute of the element.
 * @returns {String}
 */
UIAElement.prototype.name = function () {
    return "";
};
/**
 * Returns a string containing a value attribute specific to the type of element.
 * @returns {String}
 */
UIAElement.prototype.value = function () {
    return "";
};
/**
 * Returns an element whose name attribute matches a specified string.
 * @param {String} name - A string containing the name to test for.
 * @returns {UIAElement}
 */
UIAElement.prototype.withName = function (name) {
    return new UIAElement;
};
/**
 * Returns the element matching the specified criteria.
 * @param {String} predicateString - A string specifying the match criteria.
 * @returns {UIAElement}
 */
UIAElement.prototype.withPredicate = function (predicateString) {
    return new UIAElement;
};
/**
 * Returns the element containing the specified property with the specified value.
 * @param {Object} value - A string specifying the value that the specified property, if it exists, should match.
 * @param {String} key - A string specifying the property to test for.
 * @returns {UIAElement}
 */
UIAElement.prototype.withValueForKey = function (value, key) {
    return new UIAElement;
};
/**
 * Logs information about the specified element.
 */
UIAElement.prototype.logElement = function () {
};
/**
 * Logs information about the specified element and all of its subelements.
 */
UIAElement.prototype.logElementTree = function () {
};

<|endoftext|>


<commit_before>function escRe(str) {
  return str.replace(/[^\w ]/g, ch => {
    if (ch == "\n") return "\\n"
    if (ch == "\t") return "\\t"
    return "\\" + ch
  })
}

const OP_SEQ = 0, OP_CHOICE = 1,
      OP_STAR = 2, OP_PLUS = 3, OP_MAYBE = 4,
      OP_LOOKAHEAD = 5, OP_NEG_LOOKAHEAD = 6,
      OP_PREDICATE = 7

class MatchExpr {
  constructor() {}

  get isNull() { return false }
  get simple() { return true }
  get isolated() { return false }

  toExpr() {
    let re = this.toRegexp()
    if (this instanceof SeqMatch) re = `(?:${re})`
    return `/^${re}/`
  }

  forEach(f) { f(this) }
}

class StringMatch extends MatchExpr {
  constructor(string) {
    super()
    this.string = string
  }

  get simple() { return this.string != "\n" }
  get isolated() { return !this.simple }

  eq(other) { return other instanceof StringMatch && other.string == this.string }

  toRegexp() { return escRe(this.string) }

  toExpr() { return JSON.stringify(this.string) }
}
exports.StringMatch = StringMatch

class RangeMatch extends MatchExpr {
  constructor(from, to) {
    super()
    this.from = from
    this.to = to
  }

  get simple() { return this.from > "\n" || this.to < "\n" }
  get isolated() { return !this.simple }

  eq(other) { return other instanceof RangeMatch && other.from == this.from && other.to == this.to }

  toRegexp() { return "[" + escRe(this.from) + "-" + escRe(this.to) + "]" }
}
exports.RangeMatch = RangeMatch

const anyMatch = exports.anyMatch = new class AnyMatch extends MatchExpr {
  get simple() { return false }
  get isolated() { return true }
  eq(other) { return other == anyMatch }
  toRegexp() { return "[^]" }
}

const dotMatch = exports.dotMatch = new class DotMatch extends MatchExpr {
  eq(other) { return other == dotMatch }
  toRegexp() { return "." }
}

const nullMatch = exports.nullMatch = new class NullMatch extends MatchExpr {
  get isNull() { return true }
  eq(other) { return other == anyMatch }
  toRegexp() { return "" }
  toExpr() { return "null" }
}

class SeqMatch extends MatchExpr {
  constructor(matches) {
    super()
    this.matches = matches
  }

  eq(other) { return other instanceof SeqMatch && eqArray(other.matches, this.matches) }

  get simple() {
    return this.matches.every(m => m.simple)
  }
  get isolated() {
    return this.matches.some(m => m.isolated)
  }

  toRegexp() { return this.matches.map(m => m.toRegexp()).join("") }

  toExpr(nodeName) {
    if (this.simple) return super.toExpr()
    return `[${OP_SEQ}, ${this.matches.map(m => m.toExpr(nodeName)).join(", ")}]`
  }

  forEach(f) { f(this); this.matches.forEach(m => m.forEach(f)) }

  static create(left, right) {
    if (left == nullMatch) return right
    if (right == nullMatch) return left

    let before = left instanceof SeqMatch ? left.matches : [left]
    let after = right instanceof SeqMatch ? right.matches : [right]
    let last = before[before.length - 1], first = after[0]

    if (last instanceof StringMatch && first instanceof StringMatch) {
      after[0] = new StringMatch(last.string + right.string)
      before.pop()
    } else if (first instanceof RepeatMatch && first.type == "*") {
      if (last.eq(first.match)) {
        after[0] = new RepeatMatch(last, "+")
        before.pop()
      } else if (first.match instanceof StringMatch && last instanceof StringMatch &&
                 new RegExp(first.match.toRegexp() + "$").test(last.string)) {
        after[0] = new RepeatMatch(first.match, "+")
        before[before.length - 1] = new StringMatch(last.string.slice(0, last.string.length - first.match.string.length))
      }
    }
    let matches = before.concat(after)
    return matches.length == 1 ? matches[0] : new SeqMatch(matches)
  }

  static canCombine(left, right) {
    return left.isolated ? right.isNull : right.isolated ? left.isNull : true
  }
}
exports.SeqMatch = SeqMatch

class ChoiceMatch extends MatchExpr {
  constructor(matches) {
    super()
    this.matches = matches
  }

  get simple() { return this.matches.every(m => m.simple) }

  eq(other) { return other instanceof ChoiceMatch && eqArray(other.matches, this.matches) }

  toRegexp() {
    let set = ""
    for (let i = 0; i < this.matches.length; i++) {
      let match = this.matches[i]
      if (match instanceof StringMatch && match.string.length == 1) {
        set += escRe(match.string)
      } else if (match instanceof RangeMatch) {
        set += escRe(match.from) + "-" + escRe(match.to)
      } else {
        set = null
        break
      }
    }
    if (set != null) return "[" + set + "]"
    return "(?:" + this.matches.map(m => m.toRegexp()).join("|") + ")"
  }

  toExpr(nodeName) {
    if (this.simple) return super.toExpr()
    return `[${OP_CHOICE}, ${this.matches.map(m => m.toExpr(nodeName)).join(", ")}]`
  }

  forEach(f) { f(this); this.matches.forEach(m => m.forEach(f)) }

  static create(left, right) {
    let matches = []
    if (left instanceof ChoiceMatch) matches = matches.concat(left.matches)
    else matches.push(left)
    if (right instanceof ChoiceMatch) matches = matches.concat(right.matches)
    else matches.push(right)
    return new ChoiceMatch(matches)
  }
}
exports.ChoiceMatch = ChoiceMatch

class RepeatMatch extends MatchExpr {
  constructor(match, type) {
    super()
    this.match = match
    this.type = type
  }

  get simple() { return this.match.simple }

  eq(other) { return other instanceof RepeatMatch && this.match.eq(other.match) && this.type == other.type }

  toRegexp() {
    if (this.match instanceof SeqMatch) return "(?:" + this.match.toRegexp() + ")" + this.type
    else return this.match.toRegexp() + this.type
  }

  toExpr(nodeName) {
    if (this.simple) return super.toExpr()
    return `[${this.type == "*" ? OP_STAR : this.type == "+" ? OP_PLUS : OP_MAYBE}, ${this.match.toExpr(nodeName)}]`
  }

  forEach(f) { f(this); this.match.forEach(f) }
}
exports.RepeatMatch = RepeatMatch

class LookaheadMatch extends MatchExpr {
  constructor(start, positive) {
    super()
    this.start = start
    this.expr = null
    this.positive = positive
  }

  get isNull() { return true }

  get simple() { return !!this.expr }

  eq(other) {
    return other instanceof LookaheadMatch && other.start == this.start &&
      (this.expr ? other.expr && this.expr.eq(other.expr) : !other.expr) &&
      other.positive == this.positive
  }

  toRegexp() {
    if (this.expr)
      return `(?${this.positive ? "=" : "!"}${this.expr.toRegexp()})`
    else // Not actually a regexp, but used for graph output
      return "LOOKAHEAD(" + this.start + ")"
  }

  toExpr(nodeName) {
    if (this.expr) return super.toExpr()
    return `[${this.positive ? OP_LOOKAHEAD : OP_NEG_LOOKAHEAD}, ${nodeName(this.start)}]`
  }

  forEach(f) { f(this); if (this.expr) this.expr.forEach(f) }
}
exports.LookaheadMatch = LookaheadMatch

class PredicateMatch extends MatchExpr {
  constructor(name) {
    super()
    this.name = name
  }

  get isNull() { return true }

  get simple() { return false }

  eq(other) { return other instanceof PredicateMatch && other.name == this.name }

  toRegexp() { return "PRED(" + this.name + ")" }

  toExpr() {
    return `[${OP_PREDICATE}, ${JSON.stringify(this.name)}]`
  }
}
exports.PredicateMatch = PredicateMatch

let eqArray = exports.eqArray = function(a, b) {
  if (a.length != b.length) return false
  for (let i = 0; i < a.length; i++) if (!a[i].eq(b[i])) return false
  return true
}
<commit_msg>More robust regexp parenthesizing<commit_after>function escRe(str) {
  return str.replace(/[^\w ]/g, ch => {
    if (ch == "\n") return "\\n"
    if (ch == "\t") return "\\t"
    return "\\" + ch
  })
}

function toSubRegexp(expr, wrapExpr) {
  if (expr.regexpPrec <= wrapExpr.regexpPrec) return `(?:${expr.toRegexp()})`
  else return expr.toRegexp()
}

const OP_SEQ = 0, OP_CHOICE = 1,
      OP_STAR = 2, OP_PLUS = 3, OP_MAYBE = 4,
      OP_LOOKAHEAD = 5, OP_NEG_LOOKAHEAD = 6,
      OP_PREDICATE = 7

class MatchExpr {
  constructor() {}

  get isNull() { return false }
  get simple() { return true }
  get isolated() { return false }

  get regexpPrec() { return 4 }

  toExpr() {
    return `/^${toSubRegexp(this, SeqMatch.prototype)}/`
  }

  forEach(f) { f(this) }
}

class StringMatch extends MatchExpr {
  constructor(string) {
    super()
    this.string = string
  }

  get simple() { return this.string != "\n" }
  get isolated() { return !this.simple }

  eq(other) { return other instanceof StringMatch && other.string == this.string }

  toRegexp() { return escRe(this.string) }

  toExpr() { return JSON.stringify(this.string) }
}
exports.StringMatch = StringMatch

class RangeMatch extends MatchExpr {
  constructor(from, to) {
    super()
    this.from = from
    this.to = to
  }

  get simple() { return this.from > "\n" || this.to < "\n" }
  get isolated() { return !this.simple }

  eq(other) { return other instanceof RangeMatch && other.from == this.from && other.to == this.to }

  toRegexp() { return "[" + escRe(this.from) + "-" + escRe(this.to) + "]" }
}
exports.RangeMatch = RangeMatch

const anyMatch = exports.anyMatch = new class AnyMatch extends MatchExpr {
  get simple() { return false }
  get isolated() { return true }
  eq(other) { return other == anyMatch }
  toRegexp() { return "[^]" }
}

const dotMatch = exports.dotMatch = new class DotMatch extends MatchExpr {
  eq(other) { return other == dotMatch }
  toRegexp() { return "." }
}

const nullMatch = exports.nullMatch = new class NullMatch extends MatchExpr {
  get isNull() { return true }
  eq(other) { return other == anyMatch }
  toRegexp() { return "" }
  toExpr() { return "null" }
}

class SeqMatch extends MatchExpr {
  constructor(matches) {
    super()
    this.matches = matches
  }

  eq(other) { return other instanceof SeqMatch && eqArray(other.matches, this.matches) }

  get simple() {
    return this.matches.every(m => m.simple)
  }
  get isolated() {
    return this.matches.some(m => m.isolated)
  }

  get regexpPrec() { return 2 }

  toRegexp() { return this.matches.map(m => toSubRegexp(m, this)).join("") }

  toExpr(nodeName) {
    if (this.simple) return super.toExpr()
    return `[${OP_SEQ}, ${this.matches.map(m => m.toExpr(nodeName)).join(", ")}]`
  }

  forEach(f) { f(this); this.matches.forEach(m => m.forEach(f)) }

  static create(left, right) {
    if (left == nullMatch) return right
    if (right == nullMatch) return left

    let before = left instanceof SeqMatch ? left.matches : [left]
    let after = right instanceof SeqMatch ? right.matches : [right]
    let last = before[before.length - 1], first = after[0]

    if (last instanceof StringMatch && first instanceof StringMatch) {
      after[0] = new StringMatch(last.string + right.string)
      before.pop()
    } else if (first instanceof RepeatMatch && first.type == "*") {
      if (last.eq(first.match)) {
        after[0] = new RepeatMatch(last, "+")
        before.pop()
      } else if (first.match instanceof StringMatch && last instanceof StringMatch &&
                 new RegExp(first.match.toRegexp() + "$").test(last.string)) {
        after[0] = new RepeatMatch(first.match, "+")
        before[before.length - 1] = new StringMatch(last.string.slice(0, last.string.length - first.match.string.length))
      }
    }
    let matches = before.concat(after)
    return matches.length == 1 ? matches[0] : new SeqMatch(matches)
  }

  static canCombine(left, right) {
    return left.isolated ? right.isNull : right.isolated ? left.isNull : true
  }
}
exports.SeqMatch = SeqMatch

class ChoiceMatch extends MatchExpr {
  constructor(matches) {
    super()
    this.matches = matches
  }

  get simple() { return this.matches.every(m => m.simple) }

  eq(other) { return other instanceof ChoiceMatch && eqArray(other.matches, this.matches) }

  get regexpPrec() { return 1 }

  // FIXME reduce to \d, \w when appropriate
  toRegexp() {
    let set = ""
    for (let i = 0; i < this.matches.length; i++) {
      let match = this.matches[i]
      if (match instanceof StringMatch && match.string.length == 1) {
        set += escRe(match.string)
      } else if (match instanceof RangeMatch) {
        set += escRe(match.from) + "-" + escRe(match.to)
      } else {
        set = null
        break
      }
    }
    if (set != null) return "[" + set + "]"
    return this.matches.map(m => toSubRegexp(m, this)).join("|")
  }

  toExpr(nodeName) {
    if (this.simple) return super.toExpr()
    return `[${OP_CHOICE}, ${this.matches.map(m => m.toExpr(nodeName)).join(", ")}]`
  }

  forEach(f) { f(this); this.matches.forEach(m => m.forEach(f)) }

  static create(left, right) {
    let matches = []
    if (left instanceof ChoiceMatch) matches = matches.concat(left.matches)
    else matches.push(left)
    if (right instanceof ChoiceMatch) matches = matches.concat(right.matches)
    else matches.push(right)
    return new ChoiceMatch(matches)
  }
}
exports.ChoiceMatch = ChoiceMatch

class RepeatMatch extends MatchExpr {
  constructor(match, type) {
    super()
    this.match = match
    this.type = type
  }

  get simple() { return this.match.simple }

  eq(other) { return other instanceof RepeatMatch && this.match.eq(other.match) && this.type == other.type }

  get regexpPrec() { return 3 }

  toRegexp() {
    return toSubRegexp(this.match, this) + this.type
  }

  toExpr(nodeName) {
    if (this.simple) return super.toExpr()
    return `[${this.type == "*" ? OP_STAR : this.type == "+" ? OP_PLUS : OP_MAYBE}, ${this.match.toExpr(nodeName)}]`
  }

  forEach(f) { f(this); this.match.forEach(f) }
}
exports.RepeatMatch = RepeatMatch

class LookaheadMatch extends MatchExpr {
  constructor(start, positive) {
    super()
    this.start = start
    this.expr = null
    this.positive = positive
  }

  get isNull() { return true }

  get simple() { return !!this.expr }

  eq(other) {
    return other instanceof LookaheadMatch && other.start == this.start &&
      (this.expr ? other.expr && this.expr.eq(other.expr) : !other.expr) &&
      other.positive == this.positive
  }

  toRegexp() {
    if (this.expr)
      return `(?${this.positive ? "=" : "!"}${this.expr.toRegexp()})`
    else // Not actually a regexp, but used for graph output
      return "LOOKAHEAD(" + this.start + ")"
  }

  toExpr(nodeName) {
    if (this.expr) return super.toExpr()
    return `[${this.positive ? OP_LOOKAHEAD : OP_NEG_LOOKAHEAD}, ${nodeName(this.start)}]`
  }

  forEach(f) { f(this); if (this.expr) this.expr.forEach(f) }
}
exports.LookaheadMatch = LookaheadMatch

class PredicateMatch extends MatchExpr {
  constructor(name) {
    super()
    this.name = name
  }

  get isNull() { return true }

  get simple() { return false }

  eq(other) { return other instanceof PredicateMatch && other.name == this.name }

  toRegexp() { return "PRED(" + this.name + ")" }

  toExpr() {
    return `[${OP_PREDICATE}, ${JSON.stringify(this.name)}]`
  }
}
exports.PredicateMatch = PredicateMatch

let eqArray = exports.eqArray = function(a, b) {
  if (a.length != b.length) return false
  for (let i = 0; i < a.length; i++) if (!a[i].eq(b[i])) return false
  return true
}
<|endoftext|>


<commit_before>// Utilities
import React from 'react';
import { map, startCase, keyBy} from 'lodash';
import { RestApiClient } from '@dosomething/gateway';
import { calculateAge, displayName, displayCityState } from '../../helpers';

// Components
import Post from '../Post';
import Quantity from '../Quantity';
import TextBlock from '../TextBlock';
import HistoryModal from '../HistoryModal';
import UploaderModal from '../UploaderModal'
import ModalContainer from '../ModalContainer';
import MetaInformation from '../MetaInformation';
import UserInformation from '../Users/UserInformation';

class PostGroup extends React.Component {
  render() {
    return (

{startCase(this.props.groupType)}

        {
          map(this.props.posts, (post, key) => {
            if (post['status'] === this.props.groupType) {
              return <Post key={key} post={post} signup={this.props.signup} onUpdate={this.props.onUpdate} onTag={this.props.onTag} deletePost={this.props.deletePost} />;
            }
          })
        }

    )
  }
}

class Signup extends React.Component {
  constructor(props) {
    super(props);

    this.state = {
      signup: {},
      posts: {},
      displayHistoryModal: false,
      historyModalId: null,
      displayUploaderModal: false,
    };

    this.api = new RestApiClient;
    this.updatePost = this.updatePost.bind(this);
    this.updateTag = this.updateTag.bind(this);
    this.updateQuantity = this.updateQuantity.bind(this);
    this.showHistory = this.showHistory.bind(this);
    this.hideHistory = this.hideHistory.bind(this);
    this.deletePost = this.deletePost.bind(this);
    this.showUploader = this.showUploader.bind(this);
    this.hideUploader = this.hideUploader.bind(this);
    this.submitReportback = this.submitReportback.bind(this);
  }

  componentDidMount() {
    this.getUserActivity(this.props.signup_id);
  }

  /**
   * Gets the user activity for the specified user and update state.
   *
   * @param {String} id
   * @return {Object}
   */
  getUserActivity(id) {
    this.api.get('api/v2/activity', {
      filter: {
        id: id,
      }
    }).then(json => this.setState({
      signup: json.data[0],
      posts: keyBy(json.data[0].posts.data, 'id')
    }));
  }

  // Open the history modal of the given post
  showHistory(postId, event) {
    event.preventDefault();

    this.setState({
      displayHistoryModal: true,
      historyModalId: postId,
    });
  }

  // Close the open history modal
  hideHistory(event) {
    if (event) {
      event.preventDefault();
    }

    this.setState({
      displayHistoryModal: false,
      historyModalId: null,
    });
  }

  // Open the uploader modal to upload a new post
  showUploader(campaign, event) {
    event.preventDefault();

    this.setState({
      displayUploaderModal: true,
      campaign: campaign,
    });
  }

  // Close the open uploader modal
  hideUploader(event) {
    if (event) {
      event.preventDefault();
    }

    this.setState({
      displayUploaderModal: false,
      campaign: null,
    });
  }

  // Updates a post status.
  updatePost(postId, fields) {
    fields.post_id = postId;

    let request = this.api.put('reviews', fields);

    request.then((result) => {
      this.setState((previousState) => {
        const newState = {...previousState};

        newState.posts[postId].status = fields.status;

        return newState;
      });
    });
  }

  // Tag a post.
  updateTag(postId, tag) {
    const fields = {
      post_id: postId,
      tag_name: tag,
    };

    let response = this.api.post('tags', fields);

    return response.then((result) => {
      this.setState((previousState) => {
        const newState = {...previousState};

        newState.posts[postId] = result['data'];

        return newState;
      });
    });
  }

  // Update a signups quanity.
  updateQuantity(signup, newQuantity) {
    // Fields to send to /posts
    const fields = {
      northstar_id: signup.northstar_id,
      campaign_id: signup.campaign_id,
      campaign_run_id: signup.campaign_run_id,
      quantity: newQuantity,
    };

    // Make API request to Rogue to update the quantity on the backend
    let request = this.api.post('posts', fields);

    request.then((result) => {
      // Update the state
      this.setState((previousState) => {
        const newState = {...previousState};

        newState.signup.quantity = result.quantity;

        return newState;
      });
    });

    // Close the modal
    this.hideHistory();
  }

  // Delete a post.
  deletePost(postId, event) {
    event.preventDefault();
    const confirmed = confirm('🚨🔥🚨 Are you sure you want to delete this? 🚨🔥🚨');

    if (confirmed) {
      // Make API request to Rogue to update the quantity on the backend
      let response = this.api.delete('posts/'.concat(postId));

      response.then((result) => {
        // Update the state
        this.setState((previousState) => {
          var newState = {...previousState};

          // Remove the deleted post from the state
          delete(newState.posts[postId]);

          // Return the new state
          return newState;
        });
      });
    }
  }

  // Submit a new reportback on behalf of the user.
  submitReportback(reportback) {
    // Fields to send to /posts
    const fields = {
      northstar_id: reportback.northstarId,
      campaign_id: reportback.campaignId,
      campaign_run_id: reportback.campaignRunId,
      quantity: reportback.impact,
      why_participated: reportback.whyParticipated,
      caption: reportback.caption,
      source: reportback.source,
      status: reportback.status,
      file: reportback.media.dataURL,
      remote_addr: '',
    };

    // Make API request to Rogue to upload post
    let request = this.api.post('posts', fields);

    request.then((result) => {
      // Update the state
      this.setState((previousState) => {
        const newState = {...previousState};
        const post = keyBy(result,'id');
        const key = Number(Object.keys(post));

        newState.successfulSubmission = {
          success: {
            message: "Thanks for the photo! It has been automatically approved.",
          }
        };

        newState.posts[key] = post[key];

        return newState;
      });
    })
    .catch(error => console.log(error));
  }

  render() {
    const user = this.props.user;
    const signup = this.state.signup;
    const campaign = this.props.campaign;
    const posts = this.state.posts;

    return (

            <UserInformation user={user}>
              <TextBlock title="Why Statement" content={signup.why_participated} />
            </UserInformation>

            <Quantity quantity={signup.quantity} noun={campaign.reportback_info.noun} verb={campaign.reportback_info.verb} />

               this.showHistory(signup['signup_id'], e)}>Edit | Show History

              <ModalContainer>
                {this.state.displayHistoryModal ?
                  <HistoryModal id={this.state.historyModalId}
                    onUpdate={this.updateQuantity}
                    onClose={e => this.hideHistory(e)}
                    signup={signup}
                    campaign={campaign}
                  />
                : null}
              </ModalContainer>

               this.showUploader(signup, e)}>Upload Photo

              <ModalContainer>
                {this.state.displayUploaderModal ?
                  <UploaderModal
                    onClose={e => this.hideUploader(e)}
                    signup={signup}
                    campaign={campaign}
                    submitReportback={this.submitReportback}
                    success={this.state.successfulSubmission}
                  />
                : null}
              </ModalContainer>

            <MetaInformation title="Meta" details={{
              "Signup ID": signup.signup_id,
              "Northstar ID": user.id,
              "Signup Source": signup.signup_source,
              "Created At": new Date(signup.created_at).toDateString()
            }} />

        {
          map(['pending', 'accepted', 'rejected'], (status, key) => {
            return <PostGroup key={key} groupType={status} posts={posts} signup={signup} onUpdate={this.updatePost} onTag={this.updateTag} deletePost={this.deletePost} />
          })
        }

    )
  }
}

export default Signup;
<commit_msg>adds error message<commit_after>// Utilities
import React from 'react';
import { map, startCase, keyBy} from 'lodash';
import { RestApiClient } from '@dosomething/gateway';
import { calculateAge, displayName, displayCityState } from '../../helpers';

// Components
import Post from '../Post';
import Quantity from '../Quantity';
import TextBlock from '../TextBlock';
import HistoryModal from '../HistoryModal';
import UploaderModal from '../UploaderModal'
import ModalContainer from '../ModalContainer';
import MetaInformation from '../MetaInformation';
import UserInformation from '../Users/UserInformation';

class PostGroup extends React.Component {
  render() {
    return (

{startCase(this.props.groupType)}

        {
          map(this.props.posts, (post, key) => {
            if (post['status'] === this.props.groupType) {
              return <Post key={key} post={post} signup={this.props.signup} onUpdate={this.props.onUpdate} onTag={this.props.onTag} deletePost={this.props.deletePost} />;
            }
          })
        }

    )
  }
}

class Signup extends React.Component {
  constructor(props) {
    super(props);

    this.state = {
      signup: {},
      posts: {},
      displayHistoryModal: false,
      historyModalId: null,
      displayUploaderModal: false,
    };

    this.api = new RestApiClient;
    this.updatePost = this.updatePost.bind(this);
    this.updateTag = this.updateTag.bind(this);
    this.updateQuantity = this.updateQuantity.bind(this);
    this.showHistory = this.showHistory.bind(this);
    this.hideHistory = this.hideHistory.bind(this);
    this.deletePost = this.deletePost.bind(this);
    this.showUploader = this.showUploader.bind(this);
    this.hideUploader = this.hideUploader.bind(this);
    this.submitReportback = this.submitReportback.bind(this);
  }

  componentDidMount() {
    this.getUserActivity(this.props.signup_id);
  }

  /**
   * Gets the user activity for the specified user and update state.
   *
   * @param {String} id
   * @return {Object}
   */
  getUserActivity(id) {
    this.api.get('api/v2/activity', {
      filter: {
        id: id,
      }
    }).then(json => this.setState({
      signup: json.data[0],
      posts: keyBy(json.data[0].posts.data, 'id')
    }));
  }

  // Open the history modal of the given post
  showHistory(postId, event) {
    event.preventDefault();

    this.setState({
      displayHistoryModal: true,
      historyModalId: postId,
    });
  }

  // Close the open history modal
  hideHistory(event) {
    if (event) {
      event.preventDefault();
    }

    this.setState({
      displayHistoryModal: false,
      historyModalId: null,
    });
  }

  // Open the uploader modal to upload a new post
  showUploader(campaign, event) {
    event.preventDefault();

    this.setState({
      displayUploaderModal: true,
      campaign: campaign,
    });
  }

  // Close the open uploader modal
  hideUploader(event) {
    if (event) {
      event.preventDefault();
    }

    this.setState({
      displayUploaderModal: false,
      campaign: null,
    });
  }

  // Updates a post status.
  updatePost(postId, fields) {
    fields.post_id = postId;

    let request = this.api.put('reviews', fields);

    request.then((result) => {
      this.setState((previousState) => {
        const newState = {...previousState};

        newState.posts[postId].status = fields.status;

        return newState;
      });
    });
  }

  // Tag a post.
  updateTag(postId, tag) {
    const fields = {
      post_id: postId,
      tag_name: tag,
    };

    let response = this.api.post('tags', fields);

    return response.then((result) => {
      this.setState((previousState) => {
        const newState = {...previousState};

        newState.posts[postId] = result['data'];

        return newState;
      });
    });
  }

  // Update a signups quanity.
  updateQuantity(signup, newQuantity) {
    // Fields to send to /posts
    const fields = {
      northstar_id: signup.northstar_id,
      campaign_id: signup.campaign_id,
      campaign_run_id: signup.campaign_run_id,
      quantity: newQuantity,
    };

    // Make API request to Rogue to update the quantity on the backend
    let request = this.api.post('posts', fields);

    request.then((result) => {
      // Update the state
      this.setState((previousState) => {
        const newState = {...previousState};

        newState.signup.quantity = result.quantity;

        return newState;
      });
    });

    // Close the modal
    this.hideHistory();
  }

  // Delete a post.
  deletePost(postId, event) {
    event.preventDefault();
    const confirmed = confirm('🚨🔥🚨 Are you sure you want to delete this? 🚨🔥🚨');

    if (confirmed) {
      // Make API request to Rogue to update the quantity on the backend
      let response = this.api.delete('posts/'.concat(postId));

      response.then((result) => {
        // Update the state
        this.setState((previousState) => {
          var newState = {...previousState};

          // Remove the deleted post from the state
          delete(newState.posts[postId]);

          // Return the new state
          return newState;
        });
      });
    }
  }

  // Submit a new reportback on behalf of the user.
  submitReportback(reportback) {
    // Fields to send to /posts
    const fields = {
      northstar_id: reportback.northstarId,
      campaign_id: reportback.campaignId,
      campaign_run_id: reportback.campaignRunId,
      quantity: reportback.impact,
      why_participated: reportback.whyParticipated,
      caption: reportback.caption,
      source: reportback.source,
      status: reportback.status,
      file: reportback.media.dataURL,
      remote_addr: '',
    };

    // Make API request to Rogue to upload post
    let request = this.api.post('posts', fields);

    request.then((result) => {
      // Update the state
      this.setState((previousState) => {
        const newState = {...previousState};
        const post = keyBy(result,'id');
        const key = Number(Object.keys(post));

        newState.successfulSubmission = {
          success: {
            message: "Thanks for the photo! It has been automatically approved.",
          }
        };

        newState.posts[key] = post[key];

        return newState;
      });
    })
    .catch(error =>
      this.setState((previousState) => {
        const newState = {...previousState};

        newState.successfulSubmission = {
          error: {
            message: "Oops, looks like something went wrong.",
          }
        };

        return newState;
      })
    );
  }

  render() {
    const user = this.props.user;
    const signup = this.state.signup;
    const campaign = this.props.campaign;
    const posts = this.state.posts;

    return (

            <UserInformation user={user}>
              <TextBlock title="Why Statement" content={signup.why_participated} />
            </UserInformation>

            <Quantity quantity={signup.quantity} noun={campaign.reportback_info.noun} verb={campaign.reportback_info.verb} />

               this.showHistory(signup['signup_id'], e)}>Edit | Show History

              <ModalContainer>
                {this.state.displayHistoryModal ?
                  <HistoryModal id={this.state.historyModalId}
                    onUpdate={this.updateQuantity}
                    onClose={e => this.hideHistory(e)}
                    signup={signup}
                    campaign={campaign}
                  />
                : null}
              </ModalContainer>

               this.showUploader(signup, e)}>Upload Photo

              <ModalContainer>
                {this.state.displayUploaderModal ?
                  <UploaderModal
                    onClose={e => this.hideUploader(e)}
                    signup={signup}
                    campaign={campaign}
                    submitReportback={this.submitReportback}
                    success={this.state.successfulSubmission}
                  />
                : null}
              </ModalContainer>

            <MetaInformation title="Meta" details={{
              "Signup ID": signup.signup_id,
              "Northstar ID": user.id,
              "Signup Source": signup.signup_source,
              "Created At": new Date(signup.created_at).toDateString()
            }} />

        {
          map(['pending', 'accepted', 'rejected'], (status, key) => {
            return <PostGroup key={key} groupType={status} posts={posts} signup={signup} onUpdate={this.updatePost} onTag={this.updateTag} deletePost={this.deletePost} />
          })
        }

    )
  }
}

export default Signup;
<|endoftext|>