<commit_before>import { transform } from 'babel-standalone';
import { kebabCase } from 'lodash';

class ComponentCodeBuilder {
  constructor(name, withEvents) {
    let definition;

    if (typeof name !== "string") {
      definition = name;
      name = definition.get('name');
    }

    // the name of the component
    this.name = name;

    // start building the code
    this.code = `<${name}`;

    // by default we do not have any props
    this.hasProps = false;

    // by default we do not have any children
    this.hasChildren = false;

    // tracks if the component has been closed
    this.isClosed = false;

    // determines if the component requires an action to open it (eg. dialog)
    this.openPreview = false;

    if (definition) {
      this.addProps(definition, withEvents);
    }
  }

  // adds multiple props to the code based on a definition
  addProps = (definition, withEvents) => {
    let props = definition.get('propValues'),
        children = props.get('children'),
        js = definition.get('js');

    this.openPreview = definition.get('openPreview');

    props.forEach((value, prop) => {
      if (prop !== "children") {
        if (withEvents || (prop !== "data-binding" && typeof value !== "function")) {
          this.addProp(prop, value);
        }
      }
    });

    if (children) {
      if (typeof children === "object") {
        children.forEach((child) => {
          let childCode = new ComponentCodeBuilder(child);
          this.addChild(childCode);
        });
      } else {
        this.addChild(children);
      }
    }

    if (js) {
      this.addJS(js);
    }
  }

  // adds a prop to the code
  addProp = (prop, value) => {
    if (this.hasChildren || this.isClosed) {
      throw new Error(`You cannot add props after you have added children or closed your component! See the ComponentCodeBuilder for '${this.name}'.\n\nCurrent markup:\n\n${this.code}`);
    }

    if (value || value === false) {
      this.hasProps = true;
      if (typeof value === "string") {
        this.code += `\n  ${prop}="${value.replace(/"/g, "'")}"`;
      } else {
        this.code += `\n  ${prop}={ ${value} }`;
      }
    }
  }

  // adds children to the component
  addChild = (child) => {
    if (this.isClosed) {
      throw new Error(`You cannot add children after you have closed your component! See the ComponentCodeBuilder for '${this.name}'.\n\nCurrent markup:\n\n${this.code}`);
    }

    let spaces = "  ";

    // add spaces to child with code
    if (child.code) {
      child.close();
      child.code = child.code.replace(/^/gm, spaces);
      spaces = "";
    }

    if (this.hasChildren) {
      this.code += `\n${spaces}${child}`;
    } else {
      if (this.hasProps) {
        this.code += `\n>\n`;
      } else {
        this.code += `>\n`;
      }
      this.code += `${spaces}${child}`;
      this.hasChildren = true;
    }
  }

  // adds javascript making it available before the JSX
  addJS = (js) => {
    this.code = js + "\n\n" + this.code
  }

  // closes the component tag
  close = () => {
    if (this.isClosed) { return; }

    if (this.hasChildren) {
      this.code += `\n</${this.name}>`;
    } else if (this.hasProps) {
      this.code += "\n/>";
    } else {
      this.code += " />";
    }

    this.isClosed = true;
  }

  // returns the code
  toString = () => {
    if (!this.isClosed) { this.close(); }

    return this.code;
  }

  // returns component
  toComponent = () => {
    let code = this.toString();

    if (this.openPreview) {
      code = this._addOpenPreview(code);
    }

    return eval(transform(code, { presets: ['es2015', 'react'] }).code);
  }

  // adds a button to open the preview of the component
  _addOpenPreview = (code) => {
    return `

          <Button onClick={ () => {
            Dispatcher.dispatch({
              actionType: ComponentConstants.UPDATE_DEFINITION,
              name: '${kebabCase(this.name)}',
              prop: 'open',
              value: true
            })
          } }>Open Preview</Button>

        ${code}

    `;
  }
}

export default ComponentCodeBuilder;
<commit_msg>do not render non-string props as strings<commit_after>import { transform } from 'babel-standalone';
import { kebabCase } from 'lodash';

class ComponentCodeBuilder {
  constructor(name, withEvents) {
    let definition;

    if (typeof name !== "string") {
      definition = name;
      name = definition.get('name');
    }

    // the name of the component
    this.name = name;

    // start building the code
    this.code = `<${name}`;

    // by default we do not have any props
    this.hasProps = false;

    // by default we do not have any children
    this.hasChildren = false;

    // tracks if the component has been closed
    this.isClosed = false;

    // determines if the component requires an action to open it (eg. dialog)
    this.openPreview = false;
    if (definition) {
      this.addProps(definition, withEvents);
    }
  }

  // adds multiple props to the code based on a definition
  addProps = (definition, withEvents) => {
    let props = definition.get('propValues'),
        propTypes = definition.get('propTypes'),
        children = props.get('children'),
        js = definition.get('js');

    this.openPreview = definition.get('openPreview');
    props.forEach((value, prop) => {
      if (prop !== "children") {
        if (withEvents || (prop !== "data-binding" && typeof value !== "function")) {
          this.addProp(prop, value, propTypes.get(prop));
        }
      }
    });

    if (children) {
      if (typeof children === "object") {
        children.forEach((child) => {
          let childCode = new ComponentCodeBuilder(child);
          this.addChild(childCode);
        });
      } else {
        this.addChild(children);
      }
    }

    if (js) {
      this.addJS(js);
    }
  }

  // adds a prop to the code
  addProp = (prop, value, type) => {
    if (this.hasChildren || this.isClosed) {
      throw new Error(`You cannot add props after you have added children or closed your component! See the ComponentCodeBuilder for '${this.name}'.\n\nCurrent markup:\n\n${this.code}`);
    }

    if (value || value === false) {
      this.hasProps = true;
      if (typeof value === 'string' && (type === 'String' || type === undefined)) {
        this.code += `\n  ${prop}="${value.replace(/"/g, "'")}"`;
      } else {
        this.code += `\n  ${prop}={ ${value} }`;
      }
    }
  }

  // adds children to the component
  addChild = (child) => {
    if (this.isClosed) {
      throw new Error(`You cannot add children after you have closed your component! See the ComponentCodeBuilder for '${this.name}'.\n\nCurrent markup:\n\n${this.code}`);
    }

    let spaces = "  ";

    // add spaces to child with code
    if (child.code) {
      child.close();
      child.code = child.code.replace(/^/gm, spaces);
      spaces = "";
    }

    if (this.hasChildren) {
      this.code += `\n${spaces}${child}`;
    } else {
      if (this.hasProps) {
        this.code += `\n>\n`;
      } else {
        this.code += `>\n`;
      }
      this.code += `${spaces}${child}`;
      this.hasChildren = true;
    }
  }

  // adds javascript making it available before the JSX
  addJS = (js) => {
    this.code = js + "\n\n" + this.code
  }

  // closes the component tag
  close = () => {
    if (this.isClosed) { return; }

    if (this.hasChildren) {
      this.code += `\n</${this.name}>`;
    } else if (this.hasProps) {
      this.code += "\n/>";
    } else {
      this.code += " />";
    }

    this.isClosed = true;
  }

  // returns the code
  toString = () => {
    if (!this.isClosed) { this.close(); }

    return this.code;
  }

  // returns component
  toComponent = () => {
    let code = this.toString();

    if (this.openPreview) {
      code = this._addOpenPreview(code);
    }

    return eval(transform(code, { presets: ['es2015', 'react'] }).code);
  }

  // adds a button to open the preview of the component
  _addOpenPreview = (code) => {
    return `

          <Button onClick={ () => {
            Dispatcher.dispatch({
              actionType: ComponentConstants.UPDATE_DEFINITION,
              name: '${kebabCase(this.name)}',
              prop: 'open',
              value: true
            })
          } }>Open Preview</Button>

        ${code}

    `;
  }
}

export default ComponentCodeBuilder;
<|endoftext|>


<commit_before>'use babel'

import {CompositeDisposable}	from 'atom'
import ElasticTabstopsBuilder	from './ElasticTabstopsBuilder'
import {queryAll, prepend, after, replaceWith}	from './dom'

const LINE	= 'div.line'
const TAB	= 'span.hard-tab:not(.trailing-whitespace)'

const LEADING	= 'leading-whitespace'
const INVISIBLE	= 'invisible-character'

const subscriptions = new CompositeDisposable()
export function activate(state) {
	// console.log('activate', state)
	subscriptions.add(
		atom.workspace.observeTextEditors(observeEditor)
	)
}
export function deactivate() {
	// console.log('deactivate')
	subscriptions.dispose()

	for (const editor of atom.workspace.getTextEditors()) {
		const editorElement = atom.views.getView(editor)
		editorElement.classList.remove('elastic-tabstops')

		// unpatch lines component
		const c = editorElement.component.linesComponent
		if (c._updateTileNodes) c.updateTileNodes = c._updateTileNodes
	}
}

function observeEditor(editor) {
	// console.log('observe editor')

	if (editor.getSoftTabs()) {
		console.log('Elastic tabstops require hard tabs')
		return
	}

	const editorElement = atom.views.getView(editor)
	editorElement.classList.add('elastic-tabstops')

	// monkey patch lines component
	const c = editorElement.component.linesComponent
	c._updateTileNodes = c.updateTileNodes
	c.updateTileNodes =	function () {
			this._updateTileNodes()
			update(this.getDomNode())
		}

	const handles = new Set
	function update(containerElement) {
		if (handles.size > 0) {
			// console.log('cancle old alignments', handles.size)
			for (const handle of handles) cancelAnimationFrame(handle)
			handles.clear()
		}

		// console.time('create column blocks')
		const tabstops = createTabstops(containerElement)
		// console.timeEnd('create column blocks')

		const cursorBlocks = new Set
		for (const position of editor.getCursorScreenPositions()) {
			const blocks = tabstops.getColumnBlocksOfLine(position.row)
			if (blocks) for (const block of blocks) cursorBlocks.add(block)
		}
		const lines = new Set
		for (const block of cursorBlocks) {
			for (let i = 0; i < block.cells.length; ++i) lines.add(block.line + i)
		}

		const presenter = editorElement.component.presenter
		const y = presenter.getLinesYardstick()
		const cache = y.leftPixelPositionCache
			|| y.pixelPositionsByLineIdAndColumn // Atom < 1.9
		for (const line of lines) {
			const id = presenter.lineIdForScreenRow(line)
			delete cache[id]
		}

		// console.time('align blocks at cursors')
		// for (const block of tabstops.columnBlocks) align(block.cells)
		for (const block of cursorBlocks) {
			align(block.cells)
		}
		// console.timeEnd('align blocks at cursors')

		for (const block of tabstops.columnBlocks) {
			const handle = requestAnimationFrame(now => {
				handles.delete(handle)
				if (!cursorBlocks.has(block)) align(block.cells)
			})
			handles.add(handle)
		}
		// console.log('delayed alignments', handles.size)
	}

	function createTabstops(containerElement) {
		const builder = new ElasticTabstopsBuilder()

		// builder.line(lineNumber) must be called with increasing lineNumbers,
		// but Atom may update lines tiles in any order, so we sort them first.
		const lines = containerElement::queryAll(LINE)
		lines.sort((a, b) => a.dataset.screenRow - b.dataset.screenRow)

		for (const line of lines) {
			builder.line(parseInt(line.dataset.screenRow))
			const space = findSpaceIn(line)
			let leadingSpace = space.atStart()	// for first cell

			for (const tab of line::queryAll(TAB)) {
				const tailingSpace = space.before(tab)
				const empty =
					!leadingSpace && !tailingSpace // non-empty if has space
					&&	(tab.classList.contains(LEADING)// empty if tab is leading (without spaces)
						||	tab.previousSibling
							&& tab.previousSibling.nodeType === Node.ELEMENT_NODE
							&& tab.previousSibling.matches(TAB))	// empty if tab follows another tab
				builder.cell({empty, leadingSpace, tailingSpace, tab})
				leadingSpace = space.after(tab)	// for next cell
			}
		}
		return builder.elasticTabstops
	}

	function isTab(node) {
		return node
	}

	function align(cells) {
		// Clear style, and exit if all cells are empty which means the
		// tabs in this column block are not used for alignments but only for
		// indentations.
		let allEmpty = true
		for (const {empty, tab} of cells) {
			tab.style.width = tab.style.paddingLeft = tab.style.paddingRight = null
			allEmpty = allEmpty && empty
		}
		if (allEmpty) return

		// Clear old styles and Unify width of tabs
		for (const cell of cells) {
			const {leadingSpace, tailingSpace, tab} = cell
			const fillStart = fill(leadingSpace)
			const fillEnd = fill(tailingSpace)
			cell.fillStart = fillStart
			cell.fillEnd = fillEnd
			if (fillStart) fillStart.style.paddingLeft = null
			if (fillEnd) fillEnd.style.paddingRight = null
			tab.style.width = '1ch'
		}

		// calculate rightmost position
		let rightmost = 0
		for (const {tab} of cells) {
			const r = tab.getBoundingClientRect().right
			if (r > rightmost) rightmost = r
		}

		for (const {fillStart, fillEnd, tab} of cells) {
			const w = () => Math.ceil(rightmost) - tab.getBoundingClientRect().right
			if (fillStart) {
				fillStart.style.paddingLeft = w() / (fillEnd ? 2 : 1) + 'px'
			}
			;(fillEnd || tab).style.paddingRight = w() + 'px'
			// tab.style.paddingLeft = w() + 'px'
		}
	}

	function fill(space) {
		if (space == null) return null
		const fill = do {
			if (space.nodeType === Node.ELEMENT_NODE) space
			else if (space.parentElement.childElementCount === 0) space.parentElement
			else {
				const e = space.ownerDocument.createElement('span')
				space::replaceWith(e)
				e.appendChild(space)
				e
			}
		}
		fill.classList.add('fill')
		fill.style.paddingLeft = fill.style.paddingRight = null
		return fill
	}

	function findSpaceIn(scopeNode) {
		return {
			before(n) {
				do {
					while (n.previousSibling == null) {
						n = n.parentNode
						if (n == null || n === scopeNode) return null
					}
					n = n.previousSibling
				} while (n.textContent === '')
				if (n.nodeType === Node.ELEMENT_NODE) {
					if (n.matches(TAB)) return null
					if (n.textContent.endsWith(invisibleSpace)) {
						while (n.lastChildElement) {
							n = n.lastChildElement
						}
						if (isInvisibleSpace(n)) return n
					}
				}
				if (n.textContent.endsWith(' ')) {
					while (n.lastChild) {
						n = n.lastChild
						while (n.textContent === '') n = n.previousSibling
					}
					return n
				}
				return null
			},
			after(n) {
				do {
					while (n.nextSibling == null) {
						n = n.parentNode
						if (n == null || n === scopeNode) return null
					}
					n = n.nextSibling
				} while (n.textContent === '')
				if (n.nodeType === Node.ELEMENT_NODE && n.matches(TAB)) return null
				if (n.textContent.startsWith(' ')) {
					while (n.firstChild) {
						n = n.firstChild
						while (n.textContent === '') n = n.nextSibling
					}
					return n
				}
				if (n.textContent.startsWith(invisibleSpace)) {
					while (n.firstChildElement) n = n.firstChildElement
					if (isInvisibleSpace(n)) return n
				}
				return null
			},
			atStart() {
				let n = scopeNode.firstChild
				while (n && n.textContent === '') n = n.nextSibling
				if (n == null) return null
				if (n.textContent.startsWith(' ')) {
					while (n.firstChild) {
						n = n.firstChild
						while (n.textContent === '') n = n.nextSibling
					}
					if (n.parentElement.matches(TAB)) return null
					return n
				}
				if (n.textContent.startsWith(invisibleSpace)) {
					while (n.firstChildElement) n = n.firstChildElement
					if (isInvisibleSpace(n)) return n
				}
				return null
			},
		}
	}

	const scope = editor.getRootScopeDescriptor()
	const invisibleSpace = atom.config.get('editor.invisibles.space', {scope})
	function isInvisibleSpace(element) {
		return element.classList.contains(INVISIBLE) && element.textContent === invisibleSpace
	}
}
<commit_msg>fix #3<commit_after>'use babel'

import {CompositeDisposable}	from 'atom'
import ElasticTabstopsBuilder	from './ElasticTabstopsBuilder'
import {queryAll, prepend, after, replaceWith}	from './dom'

const LINE	= 'div.line'
const TAB	= 'span.hard-tab:not(.trailing-whitespace)'

const LEADING	= 'leading-whitespace'
const INVISIBLE	= 'invisible-character'

const subscriptions = new CompositeDisposable()
export function activate(state) {
	// console.log('activate', state)
	subscriptions.add(
		atom.workspace.observeTextEditors(observeEditor)
	)
}
export function deactivate() {
	// console.log('deactivate')
	subscriptions.dispose()

	for (const editor of atom.workspace.getTextEditors()) {
		const editorElement = atom.views.getView(editor)
		editorElement.classList.remove('elastic-tabstops')

		// unpatch lines component
		const c = editorElement.component.linesComponent
		if (c._updateTileNodes) c.updateTileNodes = c._updateTileNodes
	}
}

function observeEditor(editor) {
	// console.log('observe editor')

	const editorElement = atom.views.getView(editor)
	editorElement.classList.add('elastic-tabstops')

	// monkey patch lines component
	const c = editorElement.component.linesComponent
	c._updateTileNodes = c.updateTileNodes
	c.updateTileNodes =	function () {
			this._updateTileNodes()
			if (editor.getSoftTabs()) return
			update(this.getDomNode())
		}

	const handles = new Set
	function update(containerElement) {
		if (handles.size > 0) {
			// console.log('cancle old alignments', handles.size)
			for (const handle of handles) cancelAnimationFrame(handle)
			handles.clear()
		}

		// console.time('create column blocks')
		const tabstops = createTabstops(containerElement)
		// console.timeEnd('create column blocks')

		const cursorBlocks = new Set
		for (const position of editor.getCursorScreenPositions()) {
			const blocks = tabstops.getColumnBlocksOfLine(position.row)
			if (blocks) for (const block of blocks) cursorBlocks.add(block)
		}
		const lines = new Set
		for (const block of cursorBlocks) {
			for (let i = 0; i < block.cells.length; ++i) lines.add(block.line + i)
		}

		const presenter = editorElement.component.presenter
		const y = presenter.getLinesYardstick()
		const cache = y.leftPixelPositionCache
			|| y.pixelPositionsByLineIdAndColumn // Atom < 1.9
		for (const line of lines) {
			const id = presenter.lineIdForScreenRow(line)
			delete cache[id]
		}

		// console.time('align blocks at cursors')
		// for (const block of tabstops.columnBlocks) align(block.cells)
		for (const block of cursorBlocks) {
			align(block.cells)
		}
		// console.timeEnd('align blocks at cursors')

		for (const block of tabstops.columnBlocks) {
			const handle = requestAnimationFrame(now => {
				handles.delete(handle)
				if (!cursorBlocks.has(block)) align(block.cells)
			})
			handles.add(handle)
		}
		// console.log('delayed alignments', handles.size)
	}

	function createTabstops(containerElement) {
		const builder = new ElasticTabstopsBuilder()

		// builder.line(lineNumber) must be called with increasing lineNumbers,
		// but Atom may update lines tiles in any order, so we sort them first.
		const lines = containerElement::queryAll(LINE)
		lines.sort((a, b) => a.dataset.screenRow - b.dataset.screenRow)

		for (const line of lines) {
			builder.line(parseInt(line.dataset.screenRow))
			const space = findSpaceIn(line)
			let leadingSpace = space.atStart()	// for first cell

			for (const tab of line::queryAll(TAB)) {
				const tailingSpace = space.before(tab)
				const empty =
					!leadingSpace && !tailingSpace // non-empty if has space
					&&	(tab.classList.contains(LEADING)// empty if tab is leading (without spaces)
						||	tab.previousSibling
							&& tab.previousSibling.nodeType === Node.ELEMENT_NODE
							&& tab.previousSibling.matches(TAB))	// empty if tab follows another tab
				builder.cell({empty, leadingSpace, tailingSpace, tab})
				leadingSpace = space.after(tab)	// for next cell
			}
		}
		return builder.elasticTabstops
	}

	function isTab(node) {
		return node
	}

	function align(cells) {
		// Clear style, and exit if all cells are empty which means the
		// tabs in this column block are not used for alignments but only for
		// indentations.
		let allEmpty = true
		for (const {empty, tab} of cells) {
			tab.style.width = tab.style.paddingLeft = tab.style.paddingRight = null
			allEmpty = allEmpty && empty
		}
		if (allEmpty) return

		// Clear old styles and Unify width of tabs
		for (const cell of cells) {
			const {leadingSpace, tailingSpace, tab} = cell
			const fillStart = fill(leadingSpace)
			const fillEnd = fill(tailingSpace)
			cell.fillStart = fillStart
			cell.fillEnd = fillEnd
			if (fillStart) fillStart.style.paddingLeft = null
			if (fillEnd) fillEnd.style.paddingRight = null
			tab.style.width = '1ch'
		}

		// calculate rightmost position
		let rightmost = 0
		for (const {tab} of cells) {
			const r = tab.getBoundingClientRect().right
			if (r > rightmost) rightmost = r
		}

		for (const {fillStart, fillEnd, tab} of cells) {
			const w = () => Math.ceil(rightmost) - tab.getBoundingClientRect().right
			if (fillStart) {
				fillStart.style.paddingLeft = w() / (fillEnd ? 2 : 1) + 'px'
			}
			;(fillEnd || tab).style.paddingRight = w() + 'px'
			// tab.style.paddingLeft = w() + 'px'
		}
	}

	function fill(space) {
		if (space == null) return null
		const fill = do {
			if (space.nodeType === Node.ELEMENT_NODE) space
			else if (space.parentElement.childElementCount === 0) space.parentElement
			else {
				const e = space.ownerDocument.createElement('span')
				space::replaceWith(e)
				e.appendChild(space)
				e
			}
		}
		fill.classList.add('fill')
		fill.style.paddingLeft = fill.style.paddingRight = null
		return fill
	}

	function findSpaceIn(scopeNode) {
		return {
			before(n) {
				do {
					while (n.previousSibling == null) {
						n = n.parentNode
						if (n == null || n === scopeNode) return null
					}
					n = n.previousSibling
				} while (n.textContent === '')
				if (n.nodeType === Node.ELEMENT_NODE) {
					if (n.matches(TAB)) return null
					if (n.textContent.endsWith(invisibleSpace)) {
						while (n.lastChildElement) {
							n = n.lastChildElement
						}
						if (isInvisibleSpace(n)) return n
					}
				}
				if (n.textContent.endsWith(' ')) {
					while (n.lastChild) {
						n = n.lastChild
						while (n.textContent === '') n = n.previousSibling
					}
					return n
				}
				return null
			},
			after(n) {
				do {
					while (n.nextSibling == null) {
						n = n.parentNode
						if (n == null || n === scopeNode) return null
					}
					n = n.nextSibling
				} while (n.textContent === '')
				if (n.nodeType === Node.ELEMENT_NODE && n.matches(TAB)) return null
				if (n.textContent.startsWith(' ')) {
					while (n.firstChild) {
						n = n.firstChild
						while (n.textContent === '') n = n.nextSibling
					}
					return n
				}
				if (n.textContent.startsWith(invisibleSpace)) {
					while (n.firstChildElement) n = n.firstChildElement
					if (isInvisibleSpace(n)) return n
				}
				return null
			},
			atStart() {
				let n = scopeNode.firstChild
				while (n && n.textContent === '') n = n.nextSibling
				if (n == null) return null
				if (n.textContent.startsWith(' ')) {
					while (n.firstChild) {
						n = n.firstChild
						while (n.textContent === '') n = n.nextSibling
					}
					if (n.parentElement.matches(TAB)) return null
					return n
				}
				if (n.textContent.startsWith(invisibleSpace)) {
					while (n.firstChildElement) n = n.firstChildElement
					if (isInvisibleSpace(n)) return n
				}
				return null
			},
		}
	}

	const scope = editor.getRootScopeDescriptor()
	const invisibleSpace = atom.config.get('editor.invisibles.space', {scope})
	function isInvisibleSpace(element) {
		return element.classList.contains(INVISIBLE) && element.textContent === invisibleSpace
	}
}
<|endoftext|>


<commit_before>var spawn = require('child_process').spawn;

// Expose to the world
module.exports = SendmailTransport;

/**
 *
Generates a Transport object for Sendmail

 *
 * @constructor
 * @param {String} [config] path to the sendmail command
 */
function SendmailTransport(config){
    this.path = typeof config=="string"?config:"sendmail";
}

/**
 *
Spawns a 'sendmail -t' command and streams the outgoing
 * message to sendmail stdin. Return callback checks if the sendmail process
 * ended with 0 (no error) or not.

 *
 * @param {Object} emailMessage MailComposer object
 * @param {Function} callback Callback function to run when the sending is completed
 */
SendmailTransport.prototype.sendMail = function(emailMessage, callback) {

    // sendmail strips this header line by itself
    emailMessage.options.keepBcc = true;

    var sendmail = spawn(this.path, ["-t"]);

    sendmail.on('exit', function (code) {
        var msg = "Sendmail exited with "+code;
        if(typeof callback == "function"){
            callback(code?new Error(msg):null, {message: msg});
        }
    });

    emailMessage.pipe(sendmail.stdin);
    emailMessage.streamMessage();

};<commit_msg>Changed sendmail transport configuration: Now lets you add additional sendmail parameter (like ["-f sender@example.com"] to change the envelope sender address (Return-Path)).<commit_after>var spawn = require('child_process').spawn;

// Expose to the world
module.exports = SendmailTransport;

/**
 *
Generates a Transport object for Sendmail

 *
 * @constructor
 * @param {String} [config] path to the sendmail command
 */
function SendmailTransport(config){
    this.path = "sendmail";
    this.args = [];
    if(typeof config=="string") {
        this.path = config;
    } else if(typeof config=="object") {
        if(config.path) {
            this.path = config.path;
        }
        if(config.args instanceof Array) {
            this.args = config.args;
        }
    }
}

/**
 *
Spawns a 'sendmail -t' command and streams the outgoing
 * message to sendmail stdin. Return callback checks if the sendmail process
 * ended with 0 (no error) or not.

 *
 * @param {Object} emailMessage MailComposer object
 * @param {Function} callback Callback function to run when the sending is completed
 */
SendmailTransport.prototype.sendMail = function(emailMessage, callback) {

    // sendmail strips this header line by itself
    emailMessage.options.keepBcc = true;

    var sendmail = spawn(this.path, ["-t"].concat(this.args));

    sendmail.on('exit', function (code) {
        var msg = "Sendmail exited with "+code;
        if(typeof callback == "function"){
            callback(code?new Error(msg):null, {message: msg});
        }
    });

    emailMessage.pipe(sendmail.stdin);
    emailMessage.streamMessage();

};<|endoftext|>


<commit_before>var db = require('./frederickNorthDBRaw');

exports.connect = function(after) {
  db.connect(after);
}

exports.getWatching = function(googleId, after, leafletId) {
  console.log("Getting Watching for %s", googleId);
  db.Person.find({ GOOGLE_ID: googleId }, function (err, person) {
    if (err) {
      console.error("Error finding person");
      return after (err, null);
    }
    else if (person.length == 0) {
      return after ("No people found for " + googleId);
    }
    else {
      console.log("Found matching people %d", person.length);
      console.log("The person[0].ID = %s", person[0].ID);
      db.BoundedArea.find({ OWNER: person[0].ID }).where("PARENT IS NULL",
      function(err, boundedAreas) {
        console.log("Found %d BoundedAreas", boundedAreas.length);
        if (err) {
          return after(err, null);
        }
        return fillBoundedArea(boundedAreas, 0, function(err) {
          console.log("Executing final piece which should involve rendering the page");
          fillRouteSizes(boundedAreas, function(err) {
            if (leafletId) {
              return addLeafletMaps(boundedAreas, leafletId, after)
            }
            after(err, boundedAreas);
          });
        });
      });
    }
  });
}

addLeafletMaps = function(boundedAreas, leafletId, after) {
  var routeIds = getRouteIds(boundedAreas, []);
  db.LeafletMap.find({ROUTE: routeIds, LEAFLET: leafletId}, function(err, leafletMaps) {
    var leafletMapsByRouteMap = leafletMapsAsMap(leafletMaps);
    for (var index = 0; index < boundedAreas.length; index++) {
      matchLeafletMaps(boundedAreas[index], leafletMapsByRouteMap);
    }
    after(null, boundedAreas);
  });
}

function matchLeafletMaps(boundedArea, leafletMapByRoute) {
  var deliveryStatus = {complete: 0, remaining: 0};
  for (var index = 0; index < boundedArea.children.length; index++) {
    var childDeliveryStatus = matchLeafletMaps(boundedArea, leafletMapByRoute);
    if (childDeliveryStatus.complete + childDeliveryStatus.remaining == 0) {
      boundedArea.children.splice(index--,1);
    }
    else {
      deliveryStatus.complete += childDeliveryStatus.complete;
      deliveryStatus.remaining += childDeliveryStatus.remaining;
    }
  }
  for (var index = 0; index < boundedArea.routes.length; index++) {
    var route = boundedArea.routes[index];
    var leafletMap = leafletMapByRoute[route.ID];
    if (leafletMap) {
      if (leafletMap.DELIVERED) {
        deliveryStatus.complete += route.size;
      }
      else {
        deliveryStatus.remaining += route.size;
      }
      route.leafletMap = leafletMap;
    }
    else {
      boundedArea.routes.splice(index--, 1);
    }
  }
  return deliveryStatus;
}

function leafletMapsAsMap(leafletMaps) {
  var map = [];
  for (var index = 0; index < leafletMaps.length; index++) {
    var leafletMap = leafletMaps[index];
    map[leafletMap.ROUTE] = leafletMap;
  }
  return map;
}

exports.getLeaflets = function(googleId, after) {
  exports.getWatching(googleId, function(err, boundedAreas) {
    var routeIds = getRouteIds(boundedAreas, []);
    db.LeafletMap.aggregate(["LEAFLET"], {ROUTE: routeIds}).count().groupBy("LEAFLET").get(
      function(err, counts) {
        if (err) {
          return after(err);
        }
        var leaflets = [];
        for (var index = 0; index < counts.length; index++) {
          leaflets.push(counts[index].LEAFLET);
        }
        db.Leaflet.find({ID: leaflets}, after);
      });
  });
}

function fillRouteSizes(boundedAreas, after) {
  var routeIds = getRouteIds(boundedAreas, []);
  db.RouteMember.aggregate(["ROUTE"], {ROUTE: routeIds}).count().groupBy("ROUTE").get(
    function (err, stats) {
      if (err) {
        return after(err);
      }
      var routeSizes = [];
      for (var index = 0; index < stats.length; index++) {
        var stat = stats[index];
        routeSizes[stat.ROUTE] = stat.count;
      }
      matchRouteSizes(boundedAreas, routeSizes);
      after(err)
    });
}

function matchRouteSizes(boundedAreas, routeSizes) {
  for (var index = 0; index < boundedAreas.length; index++) {
    var boundedArea = boundedAreas[index];
    for (var routeIndex = 0; routeIndex < boundedArea.routes.length; routeIndex++) {
      var route = boundedArea.routes[routeIndex];
      route.size = routeSizes[route.ID];
    }
    matchRouteSizes(boundedArea.children, routeSizes);
  }
}

function getRouteIds(boundedAreas, routeIds) {
  for (var index = 0; index < boundedAreas.length; index++) {
    var boundedArea = boundedAreas[index];
    for (var routeIndex = 0; routeIndex < boundedArea.routes.length; routeIndex++) {
      routeIds.push(boundedArea.routes[routeIndex].ID);
    }
    getRouteIds(boundedArea.children, routeIds);
  }
  return routeIds
}

function fillBoundedArea(boundedAreas, index, after, err) {
  if (boundedAreas.length == index) {
    console.log("Ended with index: %d", index);
    return after(err);
  }
  console.log("BoundedArea: %d", index);
  boundedAreas[index].getRoutes(function(err, routes) {
    boundedAreas[index].routes = routes;
    boundedAreas[index].getChildren(function(err, children) {
      if (err) {
        return after(err);
      }
      console.log("%s has %d children", boundedAreas[index].NAME, children.length);
      boundedAreas[index].children = children;
      return fillBoundedArea(children, 0, function(err) {
        return fillBoundedArea(boundedAreas, index + 1, after, err);
      });
    });
  });
}
<commit_msg>Added ordered by functions to getting of routes and boundedAreas<commit_after>var db = require('./frederickNorthDBRaw');

exports.connect = function(after) {
  db.connect(after);
}

exports.getWatching = function(googleId, after, leafletId) {
  console.log("Getting Watching for %s", googleId);
  db.Person.find({ GOOGLE_ID: googleId }, function (err, person) {
    if (err) {
      console.error("Error finding person");
      return after (err, null);
    }
    else if (person.length == 0) {
      return after ("No people found for " + googleId);
    }
    else {
      console.log("Found matching people %d", person.length);
      console.log("The person[0].ID = %s", person[0].ID);
      db.BoundedArea.find({ OWNER: person[0].ID }).where("PARENT IS NULL",
      function(err, boundedAreas) {
        console.log("Found %d BoundedAreas", boundedAreas.length);
        if (err) {
          return after(err, null);
        }
        return fillBoundedArea(boundedAreas, 0, function(err) {
          console.log("Executing final piece which should involve rendering the page");
          fillRouteSizes(boundedAreas, function(err) {
            if (leafletId) {
              return addLeafletMaps(boundedAreas, leafletId, after)
            }
            after(err, boundedAreas);
          });
        });
      });
    }
  });
}

addLeafletMaps = function(boundedAreas, leafletId, after) {
  var routeIds = getRouteIds(boundedAreas, []);
  db.LeafletMap.find({ROUTE: routeIds, LEAFLET: leafletId}, function(err, leafletMaps) {
    var leafletMapsByRouteMap = leafletMapsAsMap(leafletMaps);
    for (var index = 0; index < boundedAreas.length; index++) {
      matchLeafletMaps(boundedAreas[index], leafletMapsByRouteMap);
    }
    after(null, boundedAreas);
  });
}

function matchLeafletMaps(boundedArea, leafletMapByRoute) {
  var deliveryStatus = {complete: 0, remaining: 0};
  for (var index = 0; index < boundedArea.children.length; index++) {
    var childDeliveryStatus = matchLeafletMaps(boundedArea, leafletMapByRoute);
    if (childDeliveryStatus.complete + childDeliveryStatus.remaining == 0) {
      boundedArea.children.splice(index--,1);
    }
    else {
      deliveryStatus.complete += childDeliveryStatus.complete;
      deliveryStatus.remaining += childDeliveryStatus.remaining;
    }
  }
  for (var index = 0; index < boundedArea.routes.length; index++) {
    var route = boundedArea.routes[index];
    var leafletMap = leafletMapByRoute[route.ID];
    if (leafletMap) {
      if (leafletMap.DELIVERED) {
        deliveryStatus.complete += route.size;
      }
      else {
        deliveryStatus.remaining += route.size;
      }
      route.leafletMap = leafletMap;
    }
    else {
      boundedArea.routes.splice(index--, 1);
    }
  }
  return deliveryStatus;
}

function leafletMapsAsMap(leafletMaps) {
  var map = [];
  for (var index = 0; index < leafletMaps.length; index++) {
    var leafletMap = leafletMaps[index];
    map[leafletMap.ROUTE] = leafletMap;
  }
  return map;
}

exports.getLeaflets = function(googleId, after) {
  exports.getWatching(googleId, function(err, boundedAreas) {
    var routeIds = getRouteIds(boundedAreas, []);
    db.LeafletMap.aggregate(["LEAFLET"], {ROUTE: routeIds}).count().groupBy("LEAFLET").get(
      function(err, counts) {
        if (err) {
          return after(err);
        }
        var leaflets = [];
        for (var index = 0; index < counts.length; index++) {
          leaflets.push(counts[index].LEAFLET);
        }
        db.Leaflet.find({ID: leaflets}, after);
      });
  });
}

function fillRouteSizes(boundedAreas, after) {
  var routeIds = getRouteIds(boundedAreas, []);
  db.RouteMember.aggregate(["ROUTE"], {ROUTE: routeIds}).count().groupBy("ROUTE").get(
    function (err, stats) {
      if (err) {
        return after(err);
      }
      var routeSizes = [];
      for (var index = 0; index < stats.length; index++) {
        var stat = stats[index];
        routeSizes[stat.ROUTE] = stat.count;
      }
      matchRouteSizes(boundedAreas, routeSizes);
      after(err)
    });
}

function matchRouteSizes(boundedAreas, routeSizes) {
  for (var index = 0; index < boundedAreas.length; index++) {
    var boundedArea = boundedAreas[index];
    for (var routeIndex = 0; routeIndex < boundedArea.routes.length; routeIndex++) {
      var route = boundedArea.routes[routeIndex];
      route.size = routeSizes[route.ID];
    }
    matchRouteSizes(boundedArea.children, routeSizes);
  }
}

function getRouteIds(boundedAreas, routeIds) {
  for (var index = 0; index < boundedAreas.length; index++) {
    var boundedArea = boundedAreas[index];
    for (var routeIndex = 0; routeIndex < boundedArea.routes.length; routeIndex++) {
      routeIds.push(boundedArea.routes[routeIndex].ID);
    }
    getRouteIds(boundedArea.children, routeIds);
  }
  return routeIds
}

function fillBoundedArea(boundedAreas, index, after, err) {
  if (boundedAreas.length == index) {
    console.log("Ended with index: %d", index);
    return after(err);
  }
  console.log("BoundedArea: %d", index);
  boundedAreas[index].getRoutes().orderRaw("TRIM(NAME)").run(function(err, routes) {
    boundedAreas[index].routes = routes;
    boundedAreas[index].getChildren().order("NAME").run(function(err, children) {
      if (err) {
        return after(err);
      }
      console.log("%s has %d children", boundedAreas[index].NAME, children.length);
      boundedAreas[index].children = children;
      return fillBoundedArea(children, 0, function(err) {
        return fillBoundedArea(boundedAreas, index + 1, after, err);
      });
    });
  });
}
<|endoftext|>


<commit_before>var op_watch = null;
function op(city, tag, title, focii, architect, atype, body, x){
  var result = Resource.add_or_update(tag, {
    city_id: city,
    title: title,
    focii: focii,
    architect: architect,
    atype: atype,
    body: body
  }, x);
  if (tag == op_watch) {
    go('@' + tag);
    op_watch = null;
  }
  return result;
}

Ops = new Resource('Op', {
  enhancer: function(x){
    x.children = [];
    x.site = x.focii && x.focii.split(' ')[0];
    x.thumb_url = x.site && x.site.resource() && x.site.resource().thumb_url;
  }
});

Operation = {

  exec: function(script, players, location, callback) {
    var params = {
      channel: 'noho',
      script:  script,
      items:   players.replace(/Person__/g, '')
    };

    if (test) return alert("CEML exec: " + $.param(params));

    $.get('/api/exec', params, function(optag){
      op_watch = optag;
      Ajax.autoload(callback);
    }, 'text');
  },

  // demo mode stuff

  create: function(site, title, atype, body) {
    var optag = "Op__" + Ajax.uuid();
    var city_id = site.resource().city_id;
    op_watch = optag;
    return op(city_id, optag, title, site, This.user.tag, atype, body);
  },

  group_assign_demo: function(agents, what, callback) {
    // console.log(agents);
    var op = Operation.create(agents[0], "\""+what+"\"", 'assignment group', what);
    callback(op);

    $.each(agents, function(i, agent){
      var delay = 4000 + Math.rand(10000);
      setTimeout(function(){
        Event.create('accepted', agent, op, {latch: "latched 1-10000 " + op.id + " " + This.user.tag});
      }, delay);
    });
  },

  assign_demo: function(person, assignment, callback) {
    var op = Operation.create(person, "\""+assignment+"\"", 'assignment individual', assignment);
    callback(op);

    setTimeout(function(){
      Event.create('accepted', person, op, {latch: "latched 1-10000 " + op.id + " " + This.user.tag});
    }, 3000);

    setTimeout(function(){
      Event.create('completed', person, op, {latch: "unlatched"});
    }, 15000);

  },

  invite_demo: function(landmark, title, assignment, callback) {
    var op = Operation.create(landmark, "\""+title+"\"", 'assignment invite', title);
    callback(op);

    $.each(Agents.in_city(op.city_id).slice(0, 10), function(i, agent){
      var delay = 2000 + Math.rand(10000);
      setTimeout(function(){
        Event.create('accepted', agent.id, op, {latch: "latched 1-10000 " + op.id + " " + This.user.tag});
      }, delay);
    });
  }  ,

  question_demo: function(question, agents) {
    var op = Operation.create(agents[0], "question: " + question, 'assignment question', question);

    $.each(agents, function(i, agent){
      var delay = 1000 + Math.rand(500);
      setTimeout(function(){
        Event.create('responded', agent, op, {latch: "unlatched"}, {msg: "wow, you're a real cool cat"});
      }, delay);
    });
  }

};
<commit_msg>Fixed Event.create call for demo question<commit_after>var op_watch = null;
function op(city, tag, title, focii, architect, atype, body, x){
  var result = Resource.add_or_update(tag, {
    city_id: city,
    title: title,
    focii: focii,
    architect: architect,
    atype: atype,
    body: body
  }, x);
  if (tag == op_watch) {
    go('@' + tag);
    op_watch = null;
  }
  return result;
}

Ops = new Resource('Op', {
  enhancer: function(x){
    x.children = [];
    x.site = x.focii && x.focii.split(' ')[0];
    x.thumb_url = x.site && x.site.resource() && x.site.resource().thumb_url;
  }
});

Operation = {

  exec: function(script, players, location, callback) {
    var params = {
      channel: 'noho',
      script:  script,
      items:   players.replace(/Person__/g, '')
    };

    if (test) return alert("CEML exec: " + $.param(params));

    $.get('/api/exec', params, function(optag){
      op_watch = optag;
      Ajax.autoload(callback);
    }, 'text');
  },

  // demo mode stuff

  create: function(site, title, atype, body) {
    var optag = "Op__" + Ajax.uuid();
    var city_id = site.resource().city_id;
    op_watch = optag;
    return op(city_id, optag, title, site, This.user.tag, atype, body);
  },

  group_assign_demo: function(agents, what, callback) {
    // console.log(agents);
    var op = Operation.create(agents[0], "\""+what+"\"", 'assignment group', what);
    callback(op);

    $.each(agents, function(i, agent){
      var delay = 4000 + Math.rand(10000);
      setTimeout(function(){
        Event.create('accepted', agent, op, {latch: "latched 1-10000 " + op.id + " " + This.user.tag});
      }, delay);
    });
  },

  assign_demo: function(person, assignment, callback) {
    var op = Operation.create(person, "\""+assignment+"\"", 'assignment individual', assignment);
    callback(op);

    setTimeout(function(){
      Event.create('accepted', person, op, {latch: "latched 1-10000 " + op.id + " " + This.user.tag});
    }, 3000);

    setTimeout(function(){
      Event.create('completed', person, op, {latch: "unlatched"});
    }, 15000);

  },

  invite_demo: function(landmark, title, assignment, callback) {
    var op = Operation.create(landmark, "\""+title+"\"", 'assignment invite', title);
    callback(op);

    $.each(Agents.in_city(op.city_id).slice(0, 10), function(i, agent){
      var delay = 2000 + Math.rand(10000);
      setTimeout(function(){
        Event.create('accepted', agent.id, op, {latch: "latched 1-10000 " + op.id + " " + This.user.tag});
      }, delay);
    });
  }  ,

  question_demo: function(question, agents) {
    var op = Operation.create(agents[0], "question: " + question, 'assignment question', question);

    $.each(agents, function(i, agent){
      var delay = 1000 + Math.rand(500);
      setTimeout(function(){
        Event.create('answered', agent, op, {latch: "unlatched"}, {msg: "wow, you're a real cool cat"});
      }, delay);
    });
  }

};
<|endoftext|>


<commit_before>'use strict';

const BUF_SZ = 4096;

const Readable = require('stream').Readable;

function GeneratorStream(source) {
	if (!source.next) throw new TypeError('source must be an iterator');

	Readable.call(this, {objectMode: true});
	this._source = source;

	this._buf = [];
	this._sz = 0;

	this._outstandingPromise = false;
	this._resolvedPromise = undefined;
}
GeneratorStream.prototype = Object.create(Readable.prototype, {constructor: {value: GeneratorStream}});

GeneratorStream.prototype._flush = function() {
	if (!this._sz) return;
	const buf = this._buf.join('');
	this._buf.length = this._sz = 0;
	return this.push(buf);
};

GeneratorStream.prototype._read = function(size) {
	if (this._outstandingPromise) return;

	try {
		let chunk;

		while (this._sz < BUF_SZ) {
			chunk = this._source.next(this._resolvedPromise);
			this._resolvedPromise = undefined;

			if (chunk.done) break;
			if (chunk.value instanceof Promise) break;

			this._buf.push(chunk.value);
			this._sz += chunk.value.length;
		}

		if (this._sz >= BUF_SZ) this._flush();

		if (chunk.done) {
			this._flush();
			this.push(null);
		}

		if (chunk.value instanceof Promise) {
			this._outstandingPromise = true;
			chunk.value.then(result => {
				this._resolvedPromise = result;
				this._outstandingPromise = false;
				this._read();
			}).catch(err => {
				this.emit('error', err);
			});
		}
	} catch (e) {
		this.emit('error', e);
	}
};

module.exports = GeneratorStream;
<commit_msg>Remove erroneous objectMode:true from GeneratorStream<commit_after>'use strict';

const BUF_SZ = 4096;

const Readable = require('stream').Readable;

function GeneratorStream(source) {
	if (!source.next) throw new TypeError('source must be an iterator');

	Readable.call(this);
	this._source = source;

	this._buf = [];
	this._sz = 0;

	this._outstandingPromise = false;
	this._resolvedPromise = undefined;
}
GeneratorStream.prototype = Object.create(Readable.prototype, {constructor: {value: GeneratorStream}});

GeneratorStream.prototype._flush = function() {
	if (!this._sz) return;
	const buf = this._buf.join('');
	this._buf.length = this._sz = 0;
	return this.push(buf);
};

GeneratorStream.prototype._read = function(size) {
	if (this._outstandingPromise) return;

	try {
		let chunk;

		while (this._sz < BUF_SZ) {
			chunk = this._source.next(this._resolvedPromise);
			this._resolvedPromise = undefined;

			if (chunk.done) break;
			if (chunk.value instanceof Promise) break;

			this._buf.push(chunk.value);
			this._sz += chunk.value.length;
		}

		if (this._sz >= BUF_SZ) this._flush();

		if (chunk.done) {
			this._flush();
			this.push(null);
		}

		if (chunk.value instanceof Promise) {
			this._outstandingPromise = true;
			chunk.value.then(result => {
				this._resolvedPromise = result;
				this._outstandingPromise = false;
				this._read();
			}).catch(err => {
				this.emit('error', err);
			});
		}
	} catch (e) {
		this.emit('error', e);
	}
};

module.exports = GeneratorStream;
<|endoftext|>


<commit_before>var https = require('https'),
    _     = require('underscore'),
    url   = require('url');

var GoogleLocations = function(key, options) {
  // Set default options
  if (!options) options = {};
  options = _.defaults(options, {
    format: 'json',
    headers: { "User-Agent": 'Google-Locations (https://www.npmjs.org/package/google-locations)' },
    host: 'maps.googleapis.com',
    port: 443,
    path: '/maps/api/'
  });

  this.config = {
    key: key,
    format: options.format,
    headers: options.headers,
    host: options.host,
    port: options.port,
    path: options.path
  };

  return this;
};

//Google place search
GoogleLocations.prototype.search = function(options, cb) {
  options = _.defaults(options, {
    location: [37.42291810, -122.08542120],
    radius: 10,
    name: 'A',
    language: 'en',
    rankby: 'prominence',
    types: []
  });

  options.location = options.location.join(',');

  if (options.types.length > 0) {
    options.types = options.types.join('|');
  } else {
    delete options.types;
  }
  if (options.rankby == 'distance') options.radius = null;

  _makeRequest(_generateUrl(this, options, 'place', 'nearbysearch'), cb);
};

GoogleLocations.prototype.textsearch = function(options, cb) {
  options = _.defaults(options, {
    query: 'Google near Mountain View, CA'
  });

  _makeRequest(_generateUrl(this, options, 'place', 'textsearch'), cb);
};

GoogleLocations.prototype.autocomplete = function(options, cb) {
  options = _.defaults(options, {
    language: "en",
  });

  _makeRequest(_generateUrl(this, options, 'place', 'autocomplete'), cb);
};

// Goolge place details
GoogleLocations.prototype.details = function(options, cb) {
  if (!options.placeid) return cb({error: 'placeid string required'});
  options = _.defaults(options, {
    // placeid: options.placeid,
    language: 'en'
  });

  _makeRequest(_generateUrl(this, options, 'place', 'details'), cb);
};

GoogleLocations.prototype.geocodeAddress = function(options, cb) {
  if (!options.address) return cb({error: 'Address string required'});
  options = _.defaults(options, {
    language: 'en'
  });

  options.address = options.address.replace(/\s/g, '+');

  _makeRequest(_generateUrl(this, options, 'geocode', null), cb);
};

GoogleLocations.prototype.reverseGeocode = function(options, cb) {
  options = _.defaults(options, {
    latlng: [37.42291810, -122.08542120],
    language: 'en'
  });

  options.latlng = options.latlng.join(',');

  _makeRequest(_generateUrl(this, options, 'geocode', null), cb);
};

GoogleLocations.prototype.searchByAddress = function(config, cb) {
  if (!config.address) return cb({error: "Address string required"});
  var _self = this;
  var options = _generateOptions(config);
  _self.geocodeAddress(options.geocode, function(err, result){
    if (err) return cb({message: "Error geocoding address", error: err});
    var location;
    try {
      location = result.results[0].geometry.location;
    } catch (exp) {
      return cb({message: "Malformed results -- try a more specific address", error: exp});
    }
    var query = _searchQuery(location, options.search);
    _self.search(query, function(err, result){
      if (err) return cb({message: "Error searching for places near geocoded location", error: err});
      _batchDetails(_self, result, options.search.maxResults, cb);
    });
  });
};

GoogleLocations.prototype.searchByPhone = function(options, cb) {
  if (!options.phone) return cb({error: "Missing required parameter 'phone'"});
  options.maxResults = options.maxResults || 1;
  var _self = this;

  _self.textsearch({query: 'phone number ' + options.phone}, function(err, result){
    if (err) return cb({message: "Error from textsearch", error: err});
    _batchDetails(_self, result, options.maxResults, cb);
  });
};

/* Helper Functions */
function _batchDetails(context, result, maxResults, cb) {
  if (result.results.length === 0) return cb(null, {details: [], errors: []});
  var details = [];
  var errors = [];
  var j = (maxResults > result.results.length) ? result.results.length : maxResults;
  for (var i = 0; i < j; i++) {
    try {
      var placeid = result.results[i].place_id;
      context.details({placeid: placeid}, function(err, result){
        if (err) {
          errors.push({message: "Error requesting details for placeid " + placeid, error: err});
        } else {
          details.push(result);
        }
        if (details.length + errors.length == j) return cb(null, {details: details, errors: errors});
      });
    } catch (exp) {
      errors.push({message: "No place_id found", error: exp});
      if (details.length + errors.length == j) return cb(null, {details: details, errors: errors});
    }
  }
}

function _generateOptions(geocodeOptions) {
  var options = {geocode: geocodeOptions, search: {maxResults: 1, rankby: "distance"}};
  var keys = ['name', 'maxResults', 'rankby', 'radius'];
  for (var i = 0; i < keys.length; i++) {
    var key = keys[i];
    if (options.geocode[key]) {
      options.search[key] = options.geocode[key];
      delete options.geocode[key];
    }
  }
  // Ensure 'prominence' searches have a radius
  if (options.search.rankby === "prominence" && !options.search.radius) {
    options.search.radius = 250;
  }
  return options;
}

function _searchQuery(location, searchOptions) {
  var query = {location: [location.lat, location.lng], rankby: searchOptions.rankby};
  if (searchOptions.name) query.name = searchOptions.name;
  if (searchOptions.radius) query.radius = searchOptions.radius;
  return query;
}

/* Request Utility Functions */
function _makeRequest (request_query, cb) {
  https.get(request_query, function(res) {
      var data = [];
      res
      .on('data', function(chunk) { data.push(chunk); })
      .on('end', function() {
          var dataBuff = data.join('').trim();
          var result;
          try {
            result = JSON.parse(dataBuff);
          } catch (exp) {
            result = {'status_code': 500, 'status_text': 'JSON Parse Failed'};
          }
          cb(null, result);
      });
  })
  .on('error', function(e) {
      cb(e);
  });
}

function _generateUrl(context, query, type, method) {
  //https://maps.googleapis.com/maps/api/place/nearbysearch/json?
  //https://maps.googleapis.com/maps/api/geocode/json?
  _.compact(query);
  query.key = context.config.key;
  return url.parse(url.format({
    protocol: 'https',
    hostname: context.config.host,
    pathname: context.config.path + type + '/' + (method ? method + '/' : '') + context.config.format,
    query: query
  }));
}

module.exports = GoogleLocations;
<commit_msg>Condense these godawful try-catch blocks<commit_after>var https = require('https'),
    _     = require('underscore'),
    url   = require('url');

var GoogleLocations = function(key, options) {
  // Set default options
  if (!options) options = {};
  options = _.defaults(options, {
    format: 'json',
    headers: { "User-Agent": 'Google-Locations (https://www.npmjs.org/package/google-locations)' },
    host: 'maps.googleapis.com',
    port: 443,
    path: '/maps/api/'
  });

  this.config = {
    key: key,
    format: options.format,
    headers: options.headers,
    host: options.host,
    port: options.port,
    path: options.path
  };

  return this;
};

//Google place search
GoogleLocations.prototype.search = function(options, cb) {
  options = _.defaults(options, {
    location: [37.42291810, -122.08542120],
    radius: 10,
    name: 'A',
    language: 'en',
    rankby: 'prominence',
    types: []
  });

  options.location = options.location.join(',');

  if (options.types.length > 0) {
    options.types = options.types.join('|');
  } else {
    delete options.types;
  }
  if (options.rankby == 'distance') options.radius = null;

  _makeRequest(_generateUrl(this, options, 'place', 'nearbysearch'), cb);
};

GoogleLocations.prototype.textsearch = function(options, cb) {
  options = _.defaults(options, {
    query: 'Google near Mountain View, CA'
  });

  _makeRequest(_generateUrl(this, options, 'place', 'textsearch'), cb);
};

GoogleLocations.prototype.autocomplete = function(options, cb) {
  options = _.defaults(options, {
    language: "en",
  });

  _makeRequest(_generateUrl(this, options, 'place', 'autocomplete'), cb);
};

GoogleLocations.prototype.details = function(options, cb) {
  if (!options.placeid) return cb({error: 'placeid string required'});
  options = _.defaults(options, {
    language: 'en'
  });

  _makeRequest(_generateUrl(this, options, 'place', 'details'), cb);
};

GoogleLocations.prototype.geocodeAddress = function(options, cb) {
  if (!options.address) return cb({error: 'Address string required'});
  options = _.defaults(options, {
    language: 'en'
  });

  options.address = options.address.replace(/\s/g, '+');

  _makeRequest(_generateUrl(this, options, 'geocode', null), cb);
};

GoogleLocations.prototype.reverseGeocode = function(options, cb) {
  options = _.defaults(options, {
    latlng: [37.42291810, -122.08542120],
    language: 'en'
  });

  options.latlng = options.latlng.join(',');

  _makeRequest(_generateUrl(this, options, 'geocode', null), cb);
};

GoogleLocations.prototype.searchByAddress = function(config, cb) {
  if (!config.address) return cb({error: "Address string required"});
  var _self = this;
  var options = _generateOptions(config);
  _self.geocodeAddress(options.geocode, function(err, result){
    if (err) return cb({message: "Error geocoding address", error: err});
    try {
      var location = result.results[0].geometry.location;
      var query = _searchQuery(location, options.search);
      _self.search(query, function(err, result){
        if (err) return cb({message: "Error searching for places near geocoded location", error: err});
        _batchDetails(_self, result, options.search.maxResults, cb);
      });
    } catch (exp) {
      return cb({message: "Malformed results -- try a more specific address", error: exp});
    }
  });
};

GoogleLocations.prototype.searchByPhone = function(options, cb) {
  if (!options.phone) return cb({error: "Missing required parameter 'phone'"});
  options.maxResults = options.maxResults || 1;
  var _self = this;

  _self.textsearch({query: 'phone number ' + options.phone}, function(err, result){
    if (err) return cb({message: "Error from textsearch", error: err});
    _batchDetails(_self, result, options.maxResults, cb);
  });
};

/* Helper Functions */
function _batchDetails(context, result, maxResults, cb) {
  if (result.results.length === 0) return cb(null, {details: [], errors: []});
  var details = [];
  var errors = [];
  var j = (maxResults > result.results.length) ? result.results.length : maxResults;
  for (var i = 0; i < j; i++) {
    try {
      var placeid = result.results[i].place_id;
      context.details({placeid: placeid}, function(err, result){
        if (err) {
          errors.push({message: "Error requesting details for placeid " + placeid, error: err});
        } else {
          details.push(result);
        }
        if (details.length + errors.length == j) return cb(null, {details: details, errors: errors});
      });
    } catch (exp) {
      errors.push({message: "No place_id found", error: exp});
      if (details.length + errors.length == j) return cb(null, {details: details, errors: errors});
    }
  }
}

function _generateOptions(geocodeOptions) {
  var options = {geocode: geocodeOptions, search: {maxResults: 1, rankby: "distance"}};
  var keys = ['name', 'maxResults', 'rankby', 'radius'];
  for (var i = 0; i < keys.length; i++) {
    var key = keys[i];
    if (options.geocode[key]) {
      options.search[key] = options.geocode[key];
      delete options.geocode[key];
    }
  }
  // Ensure 'prominence' searches have a radius
  if (options.search.rankby === "prominence" && !options.search.radius) {
    options.search.radius = 250;
  }
  return options;
}

function _searchQuery(location, searchOptions) {
  var query = {location: [location.lat, location.lng], rankby: searchOptions.rankby};
  if (searchOptions.name) query.name = searchOptions.name;
  if (searchOptions.radius) query.radius = searchOptions.radius;
  return query;
}

/* Request Utility Functions */
function _makeRequest (request_query, cb) {
  https.get(request_query, function(res) {
      var data = [];
      res
      .on('data', function(chunk) { data.push(chunk); })
      .on('end', function() {
          var dataBuff = data.join('').trim();
          var result;
          try {
            result = JSON.parse(dataBuff);
          } catch (exp) {
            result = {'status_code': 500, 'status_text': 'JSON Parse Failed'};
          }
          cb(null, result);
      });
  })
  .on('error', function(e) {
      cb(e);
  });
}

function _generateUrl(context, query, type, method) {
  //https://maps.googleapis.com/maps/api/place/nearbysearch/json?
  //https://maps.googleapis.com/maps/api/geocode/json?
  _.compact(query);
  query.key = context.config.key;
  return url.parse(url.format({
    protocol: 'https',
    hostname: context.config.host,
    pathname: context.config.path + type + '/' + (method ? method + '/' : '') + context.config.format,
    query: query
  }));
}

module.exports = GoogleLocations;
<|endoftext|>


<commit_before>'use strict';

var
  fs = require('fs'),
  yaml = require('js-yaml'),

  src         = 'src',
  dist        = 'dist'
  ;

module.exports = {

  karma: {
    // list of files / patterns to load in the browser
    files: [
      'test/setup.js',
      'dist/js/app-dependencies.js',
      'test/**/*.spec.js'
    ],

    // list of files to exclude
    exclude: [
    ],

    // preprocess matching files before serving them to the browser
    // available preprocessors: https://npmjs.org/browse/keyword/karma-preprocessor
    preprocessors: {},

    // base path that will be used to resolve all patterns (eg. files, exclude)
    basePath: '',

    // frameworks to use
    // available frameworks: https://npmjs.org/browse/keyword/karma-adapter
    frameworks: ['mocha', 'chai', 'sinon', 'sinon-chai'],

    webpack: {
      output: {
        libraryTarget: 'umd'
      },
      module: {
        postLoaders: [
          {
            test: /\.js$/,
            exclude: /(node_modules|resources\/js\/vendor)/,
            loader: 'istanbul-instrumenter'
          }
        ]
      }
    },

    webpackMiddleware: {
      noInfo: true
    },

    // test results reporter to use
    // possible values: 'dots', 'progress'
    // available reporters: https://npmjs.org/browse/keyword/karma-reporter
    reporters: ['mocha', 'coverage'],

    coverageReporter: {
      dir: 'coverage',
      reporters: [
        {
          type: 'text-summary'
        },
        {
          type: 'lcov',
          subdir: '.'
        }
      ]
    },

    // web server port
    port: 9876,

    // enable / disable colors in the output (reporters and logs)
    colors: true,

    // enable / disable watching file and executing tests whenever any file changes
    autoWatch: true,

    // start these browsers
    // available browser launchers: https://npmjs.org/browse/keyword/karma-launcher
    browsers: ['Chrome', 'Firefox', 'PhantomJS'],

    // Continuous Integration mode
    // if true, Karma captures browsers, runs the tests and exits
    singleRun: true,

    plugins: [
      'karma-webpack',
      'karma-mocha',
      'karma-chai',
      'karma-sinon',
      'karma-sinon-chai',
      'karma-phantomjs-launcher',
      'karma-firefox-launcher',
      'karma-chrome-launcher',
      'karma-coverage',
      'karma-mocha-reporter'
    ]
  },

  clean: [dist, 'coverage'],
  base: src,
  app: yaml.load(fs.readFileSync('quasar.build.yml')),
  browser: require('browser-sync').create(),

  appManifest: {
    dir: dist,
    watch: src + '/pages/*/config.*.yml',
    dest: dist + '/app.json'
  },

  lint: {
    css: src + '/**/*.styl',
    js: src + '/**/*.js'
  },

  css: {
    watch: src + '/**/*.styl',
    src: [
      src + '/css/*.styl',
      src + '/pages/*/css/*.styl',
      src + '/pages/*/style.*.styl'
    ],
    dest: dist
  },

  js: {
    watch: [
      src + '/**/*.js',
      src + '/**/*.html',
    ],
    src: [
      src + '/js/*.js',
      src + '/pages/*/script.*.js',
      src + '/pages/*/js/*.js',
      src + '/layouts/*/layout.*.js'
    ],
    dest: dist
  },

  webpack: {
    cache: true,
    output: {
      libraryTarget: 'commonjs2'
    }
  },

  assets: {
    src: [
      src + '/index.html',
      src + '/assets/**',
      src + '/pages/*/assets/**'
    ],
    dest: dist
  },

  appAdditions: {
    base: 'node_modules/quasar-framework/dist/app-additions/',
    src: 'node_modules/quasar-framework/dist/app-additions/**/*',
    dest: dist
  },

  deps: {
    name: 'app-dependencies',
    js: {
      src: [
        'node_modules/quasar-framework/dist/deps/quasar-dependencies',
        'node_modules/quasar-framework/dist/lib/quasar'
      ],
      dest: dist + '/js'
    },
    css: {
      src: [
        'node_modules/quasar-framework/dist/deps/quasar-dependencies',
        'node_modules/quasar-framework/dist/lib/quasar'
      ],
      dest: dist + '/css'
    }
  },

  preview: {
    port: 3000,
    ui: {port: 3001},
    open: false,
    reloadOnRestart: true,
    server: {
      baseDir: dist
    }
  },

  previewResp: {
    port: 3100,
    ui: false,
    ghostMode: false,
    open: false,
    reloadOnRestart: true,
    server: {
      baseDir: [dist, __dirname + '/../../assets/responsive-preview/'],
      index: '___responsive-preview.html'
    }
  }

};
<commit_msg>chore: Updated Page Build to latest specs<commit_after>'use strict';

var
  fs = require('fs'),
  yaml = require('js-yaml'),

  src         = 'src',
  dist        = 'dist'
  ;

module.exports = {

  karma: {
    // list of files / patterns to load in the browser
    files: [
      'test/setup.js',
      'dist/js/app-dependencies.js',
      'test/**/*.spec.js'
    ],

    // list of files to exclude
    exclude: [
    ],

    // preprocess matching files before serving them to the browser
    // available preprocessors: https://npmjs.org/browse/keyword/karma-preprocessor
    preprocessors: {},

    // base path that will be used to resolve all patterns (eg. files, exclude)
    basePath: '',

    // frameworks to use
    // available frameworks: https://npmjs.org/browse/keyword/karma-adapter
    frameworks: ['mocha', 'chai', 'sinon', 'sinon-chai'],

    webpack: {
      output: {
        libraryTarget: 'umd'
      },
      module: {
        postLoaders: [
          {
            test: /\.js$/,
            exclude: /(node_modules|resources\/js\/vendor)/,
            loader: 'istanbul-instrumenter'
          }
        ]
      }
    },

    webpackMiddleware: {
      noInfo: true
    },

    // test results reporter to use
    // possible values: 'dots', 'progress'
    // available reporters: https://npmjs.org/browse/keyword/karma-reporter
    reporters: ['mocha', 'coverage'],

    coverageReporter: {
      dir: 'coverage',
      reporters: [
        {
          type: 'text-summary'
        },
        {
          type: 'lcov',
          subdir: '.'
        }
      ]
    },

    // web server port
    port: 9876,

    // enable / disable colors in the output (reporters and logs)
    colors: true,

    // enable / disable watching file and executing tests whenever any file changes
    autoWatch: true,

    // start these browsers
    // available browser launchers: https://npmjs.org/browse/keyword/karma-launcher
    browsers: ['Chrome', 'Firefox', 'PhantomJS'],

    // Continuous Integration mode
    // if true, Karma captures browsers, runs the tests and exits
    singleRun: true,

    plugins: [
      'karma-webpack',
      'karma-mocha',
      'karma-chai',
      'karma-sinon',
      'karma-sinon-chai',
      'karma-phantomjs-launcher',
      'karma-firefox-launcher',
      'karma-chrome-launcher',
      'karma-coverage',
      'karma-mocha-reporter'
    ]
  },

  clean: [dist, 'coverage'],
  base: src,
  app: yaml.load(fs.readFileSync('quasar.build.yml')),
  browser: require('browser-sync').create(),

  appManifest: {
    dir: dist,
    watch: src + '/pages/*/config.*.yml',
    dest: dist + '/app.json'
  },

  lint: {
    css: src + '/**/*.styl',
    js: src + '/**/*.js'
  },

  css: {
    watch: src + '/**/*.styl',
    src: [
      src + '/css/*.styl',
      src + '/pages/*/style.*.styl'
    ],
    dest: dist
  },

  js: {
    watch: [
      src + '/**/*.js',
      src + '/**/*.html',
    ],
    src: [
      src + '/js/*.js',
      src + '/pages/*/script.*.js',
      src + '/layouts/*/layout.*.js'
    ],
    dest: dist
  },

  webpack: {
    cache: true,
    output: {
      libraryTarget: 'commonjs2'
    }
  },

  assets: {
    src: [
      src + '/index.html',
      src + '/assets/**',
      src + '/pages/*/assets/**'
    ],
    dest: dist
  },

  appAdditions: {
    base: 'node_modules/quasar-framework/dist/app-additions/',
    src: 'node_modules/quasar-framework/dist/app-additions/**/*',
    dest: dist
  },

  deps: {
    name: 'app-dependencies',
    js: {
      src: [
        'node_modules/quasar-framework/dist/deps/quasar-dependencies',
        'node_modules/quasar-framework/dist/lib/quasar'
      ],
      dest: dist + '/js'
    },
    css: {
      src: [
        'node_modules/quasar-framework/dist/deps/quasar-dependencies',
        'node_modules/quasar-framework/dist/lib/quasar'
      ],
      dest: dist + '/css'
    }
  },

  preview: {
    port: 3000,
    ui: {port: 3001},
    open: false,
    reloadOnRestart: true,
    server: {
      baseDir: dist
    }
  },

  previewResp: {
    port: 3100,
    ui: false,
    ghostMode: false,
    open: false,
    reloadOnRestart: true,
    server: {
      baseDir: [dist, __dirname + '/../../assets/responsive-preview/'],
      index: '___responsive-preview.html'
    }
  }

};
<|endoftext|>