<commit_before>// Load modules

var Hoek = require('hoek');
var Boom = require('boom');
var MediaType = require('media-type');
var Pack = require('../package.json');

// Declare internals
var internals = {};

// Validates accept and content-type headers
internals.onPreHandler = function (request, reply) {

    if (request.method === 'options') {
        return reply.continue();
    };

    /**
     * Accept parsing is complicated and there wasn't a library I could
     * quickly find to parse them.  At the expense of missing out
     * on part of the spec, we're gonna skip this for now till
     * we can come back to it
     */
    //var acceptHeader = request.headers.accept;
    //var acceptMedia = MediaType.fromString(acceptHeader);

    //if (!acceptMedia.isValid() || acceptMedia.type !== 'application' || (acceptMedia.suffix !== 'json' && acceptMedia.subtype !== 'json') ) {

        //return reply(Boom.badRequest('Invalid `Accept` header. Must be able to accept `application/json` in some form'));
    //}

    //if (Object.keys(acceptMedia.parameters).length > 0) {

        //return reply(Boom.notAcceptable('Media type parameters not allowed'));
    //}

    var contentType = request.headers['content-type'];

    if (contentType) {
        var contentMedia = MediaType.fromString(contentType);

        //Hapi does not allow application/* w/o json suffix so we don't need to test for it
        if (contentMedia.type !== 'application' || contentMedia.subtype !== 'vnd.api' || Object.keys(contentMedia.parameters).length > 0) {

            return reply(Boom.unsupportedMediaType('Only `application/vnd.api+json` content-type supported'));
        }
    }
    return reply.continue();
};

// Converts Boom errors to json-api format, adds meta info, sets content-type
internals.onPreResponse = function (request, reply) {

    var response = request.response;

    if (request.method === 'options') {
        return reply.continue();
    }

    if (response.isBoom) {
        var error = {
            title: response.output.payload.error,
            status: response.output.statusCode,
            detail: response.output.payload.message
        };
        response.output.payload = {
            errors: [error],
            meta: Hoek.applyToDefaults({id: request.id}, internals.meta)
        };
        response.output.headers['content-type'] = 'application/vnd.api+json';
    } else {
        if (response.source) {
            response.source.meta = Hoek.applyToDefaults({id: request.id}, internals.meta);
        }
        response.headers['content-type'] = 'application/vnd.api+json';
    }
    return reply.continue();
};

// Exports

exports.register = function (plugin, options, done) {

    internals.meta = options.meta || {};

    plugin.ext('onPreHandler', internals.onPreHandler);
    plugin.ext('onPreResponse', internals.onPreResponse);

    return done();
};

exports.register.attributes = {
    name: Pack.name,
    version: Pack.version
};
<commit_msg>fix: ignore non-JSON API requests<commit_after>// Load modules

var Hoek = require('hoek');
var Boom = require('boom');
var MediaType = require('media-type');
var Pack = require('../package.json');

// Declare internals
var internals = {};

// Validates accept and content-type headers
internals.onPreHandler = function (request, reply) {

    if (request.method === 'options') {
        return reply.continue();
    };

    if(internals.isntJsonApiRequest(request)) {
      return reply.continue();
    }

    /**
     * Accept parsing is complicated and there wasn't a library I could
     * quickly find to parse them.  At the expense of missing out
     * on part of the spec, we're gonna skip this for now till
     * we can come back to it
     */
    //var acceptHeader = request.headers.accept;
    //var acceptMedia = MediaType.fromString(acceptHeader);

    //if (!acceptMedia.isValid() || acceptMedia.type !== 'application' || (acceptMedia.suffix !== 'json' && acceptMedia.subtype !== 'json') ) {

        //return reply(Boom.badRequest('Invalid `Accept` header. Must be able to accept `application/json` in some form'));
    //}

    //if (Object.keys(acceptMedia.parameters).length > 0) {

        //return reply(Boom.notAcceptable('Media type parameters not allowed'));
    //}

    var contentType = request.headers['content-type'];

    if (contentType) {
        var contentMedia = MediaType.fromString(contentType);

        //Hapi does not allow application/* w/o json suffix so we don't need to test for it
        if (contentMedia.type !== 'application' || contentMedia.subtype !== 'vnd.api' || Object.keys(contentMedia.parameters).length > 0) {

            return reply(Boom.unsupportedMediaType('Only `application/vnd.api+json` content-type supported'));
        }
    }
    return reply.continue();
};

// Converts Boom errors to json-api format, adds meta info, sets content-type
internals.onPreResponse = function (request, reply) {

    var response = request.response;

    if (request.method === 'options') {
        return reply.continue();
    }

    if(internals.isntJsonApiRequest(request)) {
      return reply.continue();
    }

    if (response.isBoom) {
        var error = {
            title: response.output.payload.error,
            status: response.output.statusCode,
            detail: response.output.payload.message
        };
        response.output.payload = {
            errors: [error],
            meta: Hoek.applyToDefaults({id: request.id}, internals.meta)
        };
        response.output.headers['content-type'] = 'application/vnd.api+json';
    } else {
        if (response.source) {
            response.source.meta = Hoek.applyToDefaults({id: request.id}, internals.meta);
        }
        response.headers['content-type'] = 'application/vnd.api+json';
    }
    return reply.continue();
};

internals.isntJsonApiRequest = function (request) {
  if(!request.headers.accept) {
    return true;
  }

  if (request.headers.accept.indexOf('application/vnd.api+json') === -1) {
    return true;
  }

  return false;
}

// Exports

exports.register = function (plugin, options, done) {

    internals.meta = options.meta || {};

    plugin.ext('onPreHandler', internals.onPreHandler);
    plugin.ext('onPreResponse', internals.onPreResponse);

    return done();
};

exports.register.attributes = {
    name: Pack.name,
    version: Pack.version
};
<|endoftext|>


<commit_before>/* @flow */
import React, { render, unmountComponentAtNode, createElement, createClass, DOM as e, PropTypes as t } from 'react'
import { calcBounds } from './utils'
import Debug from 'debug'
import merge from 'object.assign'
import * as resizeEvent from './on-resize'

let log = Debug('react-popover')

let coreStyle = {
  position: 'absolute',
  top: 0,
  left: 0,
  display: 'flex',
  WebkitTransitionProperty: 'top, left',
  WebkitTransitionDuration: '200ms',
  WebkitTransitionEasingFunction: 'ease-in'
}

let faces = { above: 'down', right: 'left', below: 'up', left: 'right' }

let tipTranslateFuncDict = { row: 'translateY', column: 'translateX' }

/* Axes system. This allows us to at-will work in a different orientation
without having to manually keep track of knowing if we should be using
x or y positions. */

let axes = {}

axes.row = {
  main: { start: 'x', end: 'x2', size: 'w' },
  cross: { start: 'y', end: 'y2', size: 'h' }
}

axes.column = {
  main: axes.row.cross,
  cross: axes.row.main
}

export default createClass({
  name: 'popover',
  mixins: [ReactLayerMixin()],
  propTypes: {
    body: t.node.isRequired,
    children: t.element.isRequired,
    tipSize: t.number,
    isOpen: t.boolean
  },
  getInitialState() {
    return {
      standing: 'above'
    }
  },
  getDefaultProps() {
    return {
      tipSize: 7,
      offset: 4,
      isOpen: false
    }
  },
  checkTargetReposition() {
    if (this.measureTargetBounds()) this.resolvePopoverLayout()
  },
  resolvePopoverLayout() {

    let pos = { }

    /* Find the optimal zone to position self. Measure the size of each zone and use the one with
    the greatest area. */

    let zone = resolveZoneChoice(this.p2, this.frameBounds)

    this.setState({
      standing: zone.standing
    })

    let flexFlow = zone.orientation === 'landscape' ? 'row' : 'column'
    let isBefore = zone.order === 'before'
    let dir = isBefore ? -1 : 1
    let axis = axes[flexFlow]

    log('zone', zone)
    log('axes', axis)

    let mainLength = this.size[axis.main.size]
    let targetMainStart = this.p2[axis.main.start]
    let targetMainEnd = this.p2[axis.main.end]

    /* When positioning self on the cross-axis do not exceed frame bounds. The strategy to achieve
    this is thus: First position cross-axis self to the cross-axis-center of the the target. Then,
    offset self by the amount that self is past the boundaries of frame. */

    pos[axis.main.start] = (

      /* Unfortunately we cannot seem to get around the base fact that layout expands in a direction
      which happens to be leftward, and thus in the before-case requires an extra step of offsetting
      all the leftware-expansion (AKA the length of the element). TODO: We could potentially have
      helper functions like positionBefore / after etc. to abstract this complexity away. */
      (isBefore ? targetMainStart - mainLength : targetMainEnd)

      // offset allows users to control the distance betweent the tip and the target.
      + (this.props.offset * dir)
    )
    pos[axis.cross.start] = center('cross', flexFlow, this.p2) - (this.size[axis.cross.size] / 2)
    pos.x2 = pos.x + this.size.w
    pos.y2 = pos.y + this.size.h

    /* Constrain containerEl Position */

    if (pos[axis.cross.start] < this.frameBounds[axis.cross.start]) {
      pos[axis.cross.start] = this.frameBounds[axis.cross.start]
    } else if (pos[axis.cross.end] > this.frameBounds[axis.cross.end]) {
      pos[axis.cross.start] = pos[axis.cross.start] - (pos[axis.cross.end] - this.frameBounds[axis.cross.end])
    }

    /* Apply Layout */

    log('pos', pos)
    this.containerEl.style.top = `${pos.y}px`
    this.containerEl.style.left = `${pos.x}px`
    this.bodyEl.style.order = isBefore ? 0 : 1
    this.containerEl.style.flexFlow = flexFlow

    /* Calculate Tip Center */

    let tipCrossPos = (
      center('cross', flexFlow, this.p2)

      /* We do not have to calcualte half-of-tip-size since tip-size specifies
      the length from base to tip which is half of total length already. */

      - this.props.tipSize

      /* Because tip is positioned by the browser relative containerEl but
      targeting absolute center of target we need to cancel the containerEl
      positioning so as to hit our intended position. */

      - pos[axis.cross.start]
    )

    this.tipEl.style.transform = `${tipTranslateFuncDict[flexFlow]}(${tipCrossPos}px)`

    /* Record fact that repaint is synced. */

    this.p1 = this.p2
  },
  measurePopoverSize() {
    this.size = {
      w: this.containerEl.offsetWidth,
      h: this.containerEl.offsetHeight
    }
  },
  measureTargetBounds() {
    let np = calcBounds(this.targetEl)
    // log('doCheck: Current position:', p, this.p1, this.p2)
    if (!this.p1) {
      this.p2 = np
    } else if (!equalCoords(np, this.p2)) {
      this.p1 = this.p2
      this.p2 = np
    }
    return this.p1 !== this.p2
  },
  componentDidMount() {
    this.targetEl = findDOMNode(this)
    this.trackPopover()
  },
  componentDidUpdate() {
    console.log('Component did update!')
    this.trackPopover()
  },
  trackPopover() {
    let refreshIntervalMs = 200

    if (!this.layerReactComponent) {
      if (this.tracking) this.untrackPopover()
      return
    }
    if (this.tracking) return
    this.tracking = true

    /* Get references to DOM elements. */
    this.containerEl = findDOMNode(this.layerReactComponent)
    this.bodyEl = this.containerEl.querySelector('.Popover-body')
    this.tipEl = this.containerEl.querySelector('.Popover-tip')
    this.frameEl = window

    /* Update layout. */
    this.measurePopoverSize()
    this.measureFrameBounds()
    this.measureTargetBounds()
    this.resolvePopoverLayout()

    /* Continue to update layout if boundary deps change. */
    this.checkLayoutInterval = setInterval(this.checkTargetReposition, refreshIntervalMs)
    // TODO: When frame is not window use element-resize function instead.
    window.addEventListener('resize', this.onFrameBoundsChange)
    resizeEvent.on(this.containerEl, this.onPopoverSizeChange)
    resizeEvent.on(this.targetEl, this.onTargetResize)
  },
  untrackPopover() {
    if (!this.tracking) return
    this.tracking = false
    window.removeEventListener('resize', this.onFrameBoundsChange)
    clearInterval(this.checkLayoutInterval)
    resizeEvent.off(this.containerEl, this.onPopoverSizeChange)
    resizeEvent.off(this.targetEl, this.onTargetResize)
  },
  onTargetResize() {
    log('Recalculating layout because _target_ size changed!')
    this.measureTargetBounds()
    this.resolvePopoverLayout()
  },
  onPopoverSizeChange() {
    log('Recalculating layout because _popover_ size changed!')
    this.measurePopoverSize()
    this.resolvePopoverLayout()
  },
  onFrameBoundsChange() {
    log('Recalculating layout because _frame_ bounds changed!')
    this.measureFrameBounds()
    this.resolvePopoverLayout()
  },
  measureFrameBounds() {
    this.frameBounds = calcBounds(this.frameEl)
  },
  componentWillUnmount() {
    clearInterval(this.checkLayoutInterval)
  },
  renderLayer() {
    if (!this.props.isOpen) return null

    let { className = '', style = {} } = this.props

    let popoverProps = {
      className: `Popover ${className}`,
      style: merge({}, coreStyle, style)
    }

    let tipProps = {
      direction: faces[this.state.standing],
      size: this.props.tipSize
    }

    return (
      e.div(
        popoverProps,
        e.div({ className: 'Popover-body' }, this.props.body),
        createElement(PopoverTip, tipProps)
      )
    )
  },
  render() {
    return this.props.children
  }
})

let PopoverTip = createClass({
  name: 'tip',
  render() {
    let { direction } = this.props
    let size = this.props.size || 24
    let isPortrait = direction === 'up' || direction === 'down'
    let mainLength = size
    let crossLength = size * 2
    let points = (
      direction === 'up' ? `0,${mainLength} ${mainLength},0, ${crossLength},${mainLength}`
      : direction === 'down' ? `0,0 ${mainLength},${mainLength}, ${crossLength},0`
      : direction === 'left' ? `${mainLength},0 0,${mainLength}, ${mainLength},${crossLength}`
      : `0,0 ${mainLength},${mainLength}, 0,${crossLength}`
     )

    let triangle = e.svg({
      className: 'Popover-tip',
      width: isPortrait ? crossLength : mainLength,
      height: isPortrait ? mainLength : crossLength,
      style: {
        transition: 'transform 150ms ease-in'
      }
    },
      e.polygon({
        className: 'Popover-tipShape',
        points
      })
    )

    return (
      triangle
    )
  }
})

function ReactLayerMixin() {
  return {
    componentWillMount() {
      /* Create a DOM node for mounting the React Layer. */
      this.layerContainerNode = document.createElement('div')
    },
    componentDidMount() {
      /* Mount the mount. */
      document.body.appendChild(this.layerContainerNode)
      this._layerRender()
    },
    componentDidUpdate() {
      this._layerRender()
    },
    componentWillUnmount() {
      this._layerUnrender()
      /* Unmount the mount. */
      document.body.removeChild(this.layerContainerNode)
    },
    _layerRender() {
      let layerReactEl = this.renderLayer()
      if (!layerReactEl) {
        this.layerReactComponent = null
        render(e.noscript(), this.layerContainerNode)
      } else {
        this.layerReactComponent = render(layerReactEl, this.layerContainerNode)
      }
    },
    _layerUnrender() {
      if (this.layerWillUnmount) this.layerWillUnmount(this.layerContainerNode)
      unmountComponentAtNode(this.layerContainerNode)
    }
    // Must be implemented by consuming component:
    // renderLayer() {}
  }
}

function resolveZoneChoice (targetBounds, frameBounds) {
  let l = targetBounds, f = frameBounds
  return [
    { standing: 'above', orientation: 'portrait', order: 'before', w: f.x2, h: l.y },
    { standing: 'right', orientation: 'landscape', order: 'after', w: (f.x2 - l.x2), h: f.y2 },
    { standing: 'below', orientation: 'portrait', order: 'after', w: f.x2, h: (f.y2 - l.y2) },
    { standing: 'left', orientation: 'landscape', order: 'before', w: l.x, h: f.y2 }
  ]
  .reduce((b1, b2) => area(b1) > area(b2) ? b1 : b2)
}

function area (bounds) {
  return bounds.w * bounds.h
}

function equalCoords(c1, c2) {
  for (var key in c1) if (c1[key] !== c2[key]) return false
  return true
}

function center(axis, flowDirection, bounds) {
  return bounds[axes[flowDirection][axis].start] + (bounds[axes[flowDirection][axis].size] / 2)
}

/* React 12<= / >=13 compatible findDOMNode function. */

let supportsFindDOMNode = Number(React.version.split('.')[1]) >= 13 ? true : false

function findDOMNode(component) {
  return supportsFindDOMNode ? React.findDOMNode(component) : component.getDOMNode()
}

<commit_msg>Fix: Use correct prop type for Boolean contract.<commit_after>/* @flow */
import React, { render, unmountComponentAtNode, createElement, createClass, DOM as e, PropTypes as t } from 'react'
import { calcBounds } from './utils'
import Debug from 'debug'
import merge from 'object.assign'
import * as resizeEvent from './on-resize'

let log = Debug('react-popover')

let coreStyle = {
  position: 'absolute',
  top: 0,
  left: 0,
  display: 'flex',
  WebkitTransitionProperty: 'top, left',
  WebkitTransitionDuration: '200ms',
  WebkitTransitionEasingFunction: 'ease-in'
}

let faces = { above: 'down', right: 'left', below: 'up', left: 'right' }

let tipTranslateFuncDict = { row: 'translateY', column: 'translateX' }

/* Axes system. This allows us to at-will work in a different orientation
without having to manually keep track of knowing if we should be using
x or y positions. */

let axes = {}

axes.row = {
  main: { start: 'x', end: 'x2', size: 'w' },
  cross: { start: 'y', end: 'y2', size: 'h' }
}

axes.column = {
  main: axes.row.cross,
  cross: axes.row.main
}

export default createClass({
  name: 'popover',
  mixins: [ReactLayerMixin()],
  propTypes: {
    body: t.node.isRequired,
    children: t.element.isRequired,
    tipSize: t.number,
    isOpen: t.bool
  },
  getInitialState() {
    return {
      standing: 'above'
    }
  },
  getDefaultProps() {
    return {
      tipSize: 7,
      offset: 4,
      isOpen: false
    }
  },
  checkTargetReposition() {
    if (this.measureTargetBounds()) this.resolvePopoverLayout()
  },
  resolvePopoverLayout() {

    let pos = { }

    /* Find the optimal zone to position self. Measure the size of each zone and use the one with
    the greatest area. */

    let zone = resolveZoneChoice(this.p2, this.frameBounds)

    this.setState({
      standing: zone.standing
    })

    let flexFlow = zone.orientation === 'landscape' ? 'row' : 'column'
    let isBefore = zone.order === 'before'
    let dir = isBefore ? -1 : 1
    let axis = axes[flexFlow]

    log('zone', zone)
    log('axes', axis)

    let mainLength = this.size[axis.main.size]
    let targetMainStart = this.p2[axis.main.start]
    let targetMainEnd = this.p2[axis.main.end]

    /* When positioning self on the cross-axis do not exceed frame bounds. The strategy to achieve
    this is thus: First position cross-axis self to the cross-axis-center of the the target. Then,
    offset self by the amount that self is past the boundaries of frame. */

    pos[axis.main.start] = (

      /* Unfortunately we cannot seem to get around the base fact that layout expands in a direction
      which happens to be leftward, and thus in the before-case requires an extra step of offsetting
      all the leftware-expansion (AKA the length of the element). TODO: We could potentially have
      helper functions like positionBefore / after etc. to abstract this complexity away. */
      (isBefore ? targetMainStart - mainLength : targetMainEnd)

      // offset allows users to control the distance betweent the tip and the target.
      + (this.props.offset * dir)
    )
    pos[axis.cross.start] = center('cross', flexFlow, this.p2) - (this.size[axis.cross.size] / 2)
    pos.x2 = pos.x + this.size.w
    pos.y2 = pos.y + this.size.h

    /* Constrain containerEl Position */

    if (pos[axis.cross.start] < this.frameBounds[axis.cross.start]) {
      pos[axis.cross.start] = this.frameBounds[axis.cross.start]
    } else if (pos[axis.cross.end] > this.frameBounds[axis.cross.end]) {
      pos[axis.cross.start] = pos[axis.cross.start] - (pos[axis.cross.end] - this.frameBounds[axis.cross.end])
    }

    /* Apply Layout */

    log('pos', pos)
    this.containerEl.style.top = `${pos.y}px`
    this.containerEl.style.left = `${pos.x}px`
    this.bodyEl.style.order = isBefore ? 0 : 1
    this.containerEl.style.flexFlow = flexFlow

    /* Calculate Tip Center */

    let tipCrossPos = (
      center('cross', flexFlow, this.p2)

      /* We do not have to calcualte half-of-tip-size since tip-size specifies
      the length from base to tip which is half of total length already. */

      - this.props.tipSize

      /* Because tip is positioned by the browser relative containerEl but
      targeting absolute center of target we need to cancel the containerEl
      positioning so as to hit our intended position. */

      - pos[axis.cross.start]
    )

    this.tipEl.style.transform = `${tipTranslateFuncDict[flexFlow]}(${tipCrossPos}px)`

    /* Record fact that repaint is synced. */

    this.p1 = this.p2
  },
  measurePopoverSize() {
    this.size = {
      w: this.containerEl.offsetWidth,
      h: this.containerEl.offsetHeight
    }
  },
  measureTargetBounds() {
    let np = calcBounds(this.targetEl)
    // log('doCheck: Current position:', p, this.p1, this.p2)
    if (!this.p1) {
      this.p2 = np
    } else if (!equalCoords(np, this.p2)) {
      this.p1 = this.p2
      this.p2 = np
    }
    return this.p1 !== this.p2
  },
  componentDidMount() {
    this.targetEl = findDOMNode(this)
    this.trackPopover()
  },
  componentDidUpdate() {
    console.log('Component did update!')
    this.trackPopover()
  },
  trackPopover() {
    let refreshIntervalMs = 200

    if (!this.layerReactComponent) {
      if (this.tracking) this.untrackPopover()
      return
    }
    if (this.tracking) return
    this.tracking = true

    /* Get references to DOM elements. */
    this.containerEl = findDOMNode(this.layerReactComponent)
    this.bodyEl = this.containerEl.querySelector('.Popover-body')
    this.tipEl = this.containerEl.querySelector('.Popover-tip')
    this.frameEl = window

    /* Update layout. */
    this.measurePopoverSize()
    this.measureFrameBounds()
    this.measureTargetBounds()
    this.resolvePopoverLayout()

    /* Continue to update layout if boundary deps change. */
    this.checkLayoutInterval = setInterval(this.checkTargetReposition, refreshIntervalMs)
    // TODO: When frame is not window use element-resize function instead.
    window.addEventListener('resize', this.onFrameBoundsChange)
    resizeEvent.on(this.containerEl, this.onPopoverSizeChange)
    resizeEvent.on(this.targetEl, this.onTargetResize)
  },
  untrackPopover() {
    if (!this.tracking) return
    this.tracking = false
    window.removeEventListener('resize', this.onFrameBoundsChange)
    clearInterval(this.checkLayoutInterval)
    resizeEvent.off(this.containerEl, this.onPopoverSizeChange)
    resizeEvent.off(this.targetEl, this.onTargetResize)
  },
  onTargetResize() {
    log('Recalculating layout because _target_ size changed!')
    this.measureTargetBounds()
    this.resolvePopoverLayout()
  },
  onPopoverSizeChange() {
    log('Recalculating layout because _popover_ size changed!')
    this.measurePopoverSize()
    this.resolvePopoverLayout()
  },
  onFrameBoundsChange() {
    log('Recalculating layout because _frame_ bounds changed!')
    this.measureFrameBounds()
    this.resolvePopoverLayout()
  },
  measureFrameBounds() {
    this.frameBounds = calcBounds(this.frameEl)
  },
  componentWillUnmount() {
    clearInterval(this.checkLayoutInterval)
  },
  renderLayer() {
    if (!this.props.isOpen) return null

    let { className = '', style = {} } = this.props

    let popoverProps = {
      className: `Popover ${className}`,
      style: merge({}, coreStyle, style)
    }

    let tipProps = {
      direction: faces[this.state.standing],
      size: this.props.tipSize
    }

    return (
      e.div(
        popoverProps,
        e.div({ className: 'Popover-body' }, this.props.body),
        createElement(PopoverTip, tipProps)
      )
    )
  },
  render() {
    return this.props.children
  }
})

let PopoverTip = createClass({
  name: 'tip',
  render() {
    let { direction } = this.props
    let size = this.props.size || 24
    let isPortrait = direction === 'up' || direction === 'down'
    let mainLength = size
    let crossLength = size * 2
    let points = (
      direction === 'up' ? `0,${mainLength} ${mainLength},0, ${crossLength},${mainLength}`
      : direction === 'down' ? `0,0 ${mainLength},${mainLength}, ${crossLength},0`
      : direction === 'left' ? `${mainLength},0 0,${mainLength}, ${mainLength},${crossLength}`
      : `0,0 ${mainLength},${mainLength}, 0,${crossLength}`
     )

    let triangle = e.svg({
      className: 'Popover-tip',
      width: isPortrait ? crossLength : mainLength,
      height: isPortrait ? mainLength : crossLength,
      style: {
        transition: 'transform 150ms ease-in'
      }
    },
      e.polygon({
        className: 'Popover-tipShape',
        points
      })
    )

    return (
      triangle
    )
  }
})

function ReactLayerMixin() {
  return {
    componentWillMount() {
      /* Create a DOM node for mounting the React Layer. */
      this.layerContainerNode = document.createElement('div')
    },
    componentDidMount() {
      /* Mount the mount. */
      document.body.appendChild(this.layerContainerNode)
      this._layerRender()
    },
    componentDidUpdate() {
      this._layerRender()
    },
    componentWillUnmount() {
      this._layerUnrender()
      /* Unmount the mount. */
      document.body.removeChild(this.layerContainerNode)
    },
    _layerRender() {
      let layerReactEl = this.renderLayer()
      if (!layerReactEl) {
        this.layerReactComponent = null
        render(e.noscript(), this.layerContainerNode)
      } else {
        this.layerReactComponent = render(layerReactEl, this.layerContainerNode)
      }
    },
    _layerUnrender() {
      if (this.layerWillUnmount) this.layerWillUnmount(this.layerContainerNode)
      unmountComponentAtNode(this.layerContainerNode)
    }
    // Must be implemented by consuming component:
    // renderLayer() {}
  }
}

function resolveZoneChoice (targetBounds, frameBounds) {
  let l = targetBounds, f = frameBounds
  return [
    { standing: 'above', orientation: 'portrait', order: 'before', w: f.x2, h: l.y },
    { standing: 'right', orientation: 'landscape', order: 'after', w: (f.x2 - l.x2), h: f.y2 },
    { standing: 'below', orientation: 'portrait', order: 'after', w: f.x2, h: (f.y2 - l.y2) },
    { standing: 'left', orientation: 'landscape', order: 'before', w: l.x, h: f.y2 }
  ]
  .reduce((b1, b2) => area(b1) > area(b2) ? b1 : b2)
}

function area (bounds) {
  return bounds.w * bounds.h
}

function equalCoords(c1, c2) {
  for (var key in c1) if (c1[key] !== c2[key]) return false
  return true
}

function center(axis, flowDirection, bounds) {
  return bounds[axes[flowDirection][axis].start] + (bounds[axes[flowDirection][axis].size] / 2)
}

/* React 12<= / >=13 compatible findDOMNode function. */

let supportsFindDOMNode = Number(React.version.split('.')[1]) >= 13 ? true : false

function findDOMNode(component) {
  return supportsFindDOMNode ? React.findDOMNode(component) : component.getDOMNode()
}

<|endoftext|>


<commit_before>'use strict';

var _ = require('lodash');
var async = require('async');
var boom = require('boom');
var fs = require('fs');
var hoek = require('hoek');
var path = require('path');

var data = {
    names: [],
    pre: [],
    post: []
};

var runPolicies = function(policies, request, reply) {

    var policyNames = hoek.reach(request, 'route.settings.plugins.policies');
    if (!policyNames) {
        return reply.continue(); // continue as normal
    }

    var policiesToRun = _(policies) // begin a lodash chainable object
        .pick(policyNames) // just the policies included in this route
        .values() // we want the values (the functions), not the keys
        .value(); // convert to an array

    // BUG.  Don't silently drop on misspelled/missing policy.

    var checkPolicy = function(policy, callback) {

        policy(request, reply, function(err, canContinue, message) {

            if (err) {
                return callback(err); // you can provide a custom hapi error object here.
            }
            if (canContinue) {
                return callback(null, true);
            }
            return callback(boom.forbidden(message)); // if a message is passed in use it in the forbidden message
        });
    };

    // use eachSeries to get quick fails and ordering.
    async.eachSeries(policiesToRun, checkPolicy, function(err, result) {

        if (err) {
            return reply(err);
        }

        reply.continue();
    });
};

var preHandler = function(request, reply) {

    runPolicies(data.pre, request, reply);
};

var postHandler = function(request, reply) {

    runPolicies(data.post, request, reply);
};

var loadPolicies = function(server, policyDirectory, next) {

    var match = null;
    var re = /(.+)\.js$/; // Only looking for .js files in the policies folder.

    var addPolicy = function(filename, callback) {

        match = filename.match(re);
        if (match) {
            // Does this policy already exist?
            if (data.names.indexOf(match[1]) !== -1) {
                server.log(['error'], 'Trying to add a duplicate policy: ' + match[1]);
                return callback(new Error('Trying to add a duplicate policy: ' + match[1]));
            }

            data.names.push(match[1]);

            // Add this policy function to the server.app.mrhorse object.
            var policy = require(path.join(policyDirectory, filename));
            if (policy.pre === undefined || policy.pre) {
                server.log(['info'], 'Adding a new PRE policy called ' + match[1]);
                data.pre[match[1]] = policy;

                // connect the prehandler if this is the first pre policy
                if (!data.setPreHandler) {
                    server.ext('onPreHandler', preHandler);
                    data.setPreHandler = true;
                }
            }
            if (policy.post) {
                server.log(['info'], 'Adding a new POST policy called ' + match[1]);
                data.post[match[1]] = policy;

                // connect the prehandler if this is the first post policy
                if (!data.setPostHandler) {
                    server.ext('onPostHandler', postHandler);
                    data.setPostHandler = true;
                }
            }
        }

        callback();
    };

    var policyFiles = fs.readdirSync(policyDirectory);
    if (policyFiles.length === 0) {
        return next();
    }
    async.eachSeries(policyFiles, addPolicy, function(err) {

        next(err);
    });
};

var reset = function() {

    data = {
        names: [],
        pre: [],
        post: []
    };
};

exports.register = function register(server, options, next) {

    server.expose('loadPolicies', loadPolicies);
    server.expose('data', data);
    server.expose('reset', reset);

    if (options.policyDirectory !== undefined) {
        loadPolicies(server, options.policyDirectory, function(err) {

            next(err);
        });
    } else {
        next();
    }
};

exports.register.attributes = {
    pkg: require('../package.json')
};<commit_msg>more style changes<commit_after>'use strict';

var _ = require('lodash');
var async = require('async');
var boom = require('boom');
var fs = require('fs');
var hoek = require('hoek');
var path = require('path');

var data = {
    names: [],
    pre: [],
    post: []
};

var runPolicies = function(policies, request, reply) {

    var policyNames = hoek.reach(request, 'route.settings.plugins.policies');
    if (!policyNames) {
        return reply.continue();
    }

    var policiesToRun = _(policies) // Begin a lodash chainable object
        .pick(policyNames) // Just the policies included in this route
        .values() // We want the values (the functions), not the keys
        .value(); // Convert to an array

    var checkPolicy = function(policy, callback) {

        policy(request, reply, function(err, canContinue, message) {

            if (err) {
                return callback(err); // You can provide a custom hapi error object here
            }
            if (canContinue) {
                return callback(null, true);
            }
            return callback(boom.forbidden(message)); // If a message is passed in use it in the forbidden message
        });
    };

    // Use eachSeries to get quick fails and ordering
    async.eachSeries(policiesToRun, checkPolicy, function(err, result) {

        if (err) {
            return reply(err);
        }

        reply.continue();
    });
};

var preHandler = function(request, reply) {

    runPolicies(data.pre, request, reply);
};

var postHandler = function(request, reply) {

    runPolicies(data.post, request, reply);
};

var loadPolicies = function(server, policyDirectory, next) {

    var match = null;
    var re = /(.+)\.js$/; // Only looking for .js files in the policies folder

    var addPolicy = function(filename, callback) {

        match = filename.match(re);
        if (match) {
            // Does this policy already exist
            if (data.names.indexOf(match[1]) !== -1) {
                server.log(['error'], 'Trying to add a duplicate policy: ' + match[1]);
                return callback(new Error('Trying to add a duplicate policy: ' + match[1]));
            }

            data.names.push(match[1]);

            // Add this policy function to the server.app.mrhorse object
            var policy = require(path.join(policyDirectory, filename));
            if (policy.pre === undefined || policy.pre) {
                server.log(['info'], 'Adding a new PRE policy called ' + match[1]);
                data.pre[match[1]] = policy;

                // connect the prehandler if this is the first pre policy
                if (!data.setPreHandler) {
                    server.ext('onPreHandler', preHandler);
                    data.setPreHandler = true;
                }
            }
            if (policy.post) {
                server.log(['info'], 'Adding a new POST policy called ' + match[1]);
                data.post[match[1]] = policy;

                // connect the posthandler if this is the first post policy
                if (!data.setPostHandler) {
                    server.ext('onPostHandler', postHandler);
                    data.setPostHandler = true;
                }
            }
        }

        callback();
    };

    var policyFiles = fs.readdirSync(policyDirectory);
    if (policyFiles.length === 0) {
        return next();
    }
    async.eachSeries(policyFiles, addPolicy, function(err) {

        next(err);
    });
};

var reset = function() {

    data = {
        names: [],
        pre: [],
        post: []
    };
};

exports.register = function register(server, options, next) {

    server.expose('loadPolicies', loadPolicies);
    server.expose('data', data);
    server.expose('reset', reset);

    if (options.policyDirectory !== undefined) {
        loadPolicies(server, options.policyDirectory, function(err) {

            next(err);
        });
    } else {
        next();
    }
};

exports.register.attributes = {
    pkg: require('../package.json')
};<|endoftext|>


<commit_before>var fs = require('fs'),
  http = require('http'),
  points = {};

function addFile(filename) {
  try {
    points[filename] = JSON.parse(fs.readFileSync('points/'+filename));
  } catch(e) {
    console.log(e, filename);
  }
}

function savePoint(filename) {
  fs.writeFileSync('points/'+filename, JSON.stringify(points[filename]));
}

function displayPoint(res, filename, reason, data) {
  res.write('
 '
    +'Make a point  '+data.title+' Dismiss
');
  console.log(filename);
}

function displayField(res, point, field, hidden) {
  console.log(point, field, hidden);
  if(typeof(point[field])=='string') {
    point[field]=point[field].split('"').join('"');
  }
  res.write((hidden?'<input hidden ':field+': <input ')+'value="'+point[field]+'" name="'+field+'"/>');
}
function displayForm(res, filename) {
  var point = points[filename];
  res.write('<form method="POST">');
  displayField(res, {filename: filename}, 'filename', true);
  displayField(res, point, 'topic');
  displayField(res, point, 'service');
  res.write('<input type="submit" value="set service and topic" name="set">
');

  res.write('discussion');
}

function displayPoints(res) {
  res.write(fs.readFileSync('curator-prefix.html'));
  for(var i in points) {
    if(!points[i].topic && points[i].tosdr && points[i].tosdr.topic) {
      points[i].topic=points[i].tosdr.topic;
      savePoint(i);
    }
    if(!points[i].discussion) {
      points[i].discussion='https://groups.google.com/forum/#!topic/tosdr/'+points[i].id;
      savePoint(i);
    }
    if(!points[i].id) {
      displayPoint(res, i, 'no id', points[i]);
    } else if(!points[i].title) {
      displayPoint(res, i, 'no title', points[i]);
    } else if(!points[i].irrelevant && !points[i].service) {
      displayPoint(res, i, 'no service', points[i]);
    } else if(!points[i].irrelevant && !points[i].topic) {
      displayPoint(res, i, 'no topic', points[i]);
    }
  }
  res.write(fs.readFileSync('curator-postfix.html'));
	//console.log(points);
}
function processPost(req) {
  var str='';
  req.on('data', function(chunk) {
    str += chunk;
  });
  req.on('end', function() {
    if(!str.length) {
      return;
    }
    var pairs = str.split('&');
    console.log(pairs);
    var incoming = {};
    for(var i=0; i<pairs.length; i++) {
      var parts = pairs[i].split('=');
      incoming[parts[0]]=parts[1];
    }
    for(var i in incoming) {
      if(i!='filename') {
        points[incoming.filename][i]=incoming[i];
      }
    }
    savePoint(incoming.filename);
  });
}
//...
files = fs.readdirSync('points/');
for(var i=0; i<files.length; i++) {
	if(files[i]!='README.md') {
		addFile(files[i]);
  }
}
var server = http.createServer(function(req, res) {
  var point = req.url.substring(2);
  processPost(req);
  if(point.length && req.url.substring(0,2)=='/?') {
    console.log('displaying form for '+point);
    res.writeHead(200, {});
    displayForm(res, point);
  } else if(req.url=='/') {
    res.writeHead(200, {});
    displayPoints(res);
  } else {
    res.writeHead(404, {});
  }
  res.end('
');
});
server.listen(21337);
console.log('see http://localhost:21337/');
<commit_msg>link back to index from form<commit_after>var fs = require('fs'),
  http = require('http'),
  points = {};

function addFile(filename) {
  try {
    points[filename] = JSON.parse(fs.readFileSync('points/'+filename));
  } catch(e) {
    console.log(e, filename);
  }
}

function savePoint(filename) {
  fs.writeFileSync('points/'+filename, JSON.stringify(points[filename]));
}

function displayPoint(res, filename, reason, data) {
  res.write('
 '
    +'Make a point  '+data.title+' Dismiss
');
  console.log(filename);
}

function displayField(res, point, field, hidden) {
  console.log(point, field, hidden);
  if(typeof(point[field])=='string') {
    point[field]=point[field].split('"').join('"');
  }
  res.write((hidden?'<input hidden ':field+': <input ')+'value="'+point[field]+'" name="'+field+'"/>');
}
function displayForm(res, filename) {
  var point = points[filename];
  res.write('<form method="POST">');
  displayField(res, {filename: filename}, 'filename', true);
  displayField(res, point, 'topic');
  displayField(res, point, 'service');
  res.write('<input type="submit" value="set service and topic" name="set">
');

  res.write('index');
  res.write('discussion');
}

function displayPoints(res) {
  res.write(fs.readFileSync('curator-prefix.html'));
  for(var i in points) {
    if(!points[i].topic && points[i].tosdr && points[i].tosdr.topic) {
      points[i].topic=points[i].tosdr.topic;
      savePoint(i);
    }
    if(!points[i].discussion) {
      points[i].discussion='https://groups.google.com/forum/#!topic/tosdr/'+points[i].id;
      savePoint(i);
    }
    if(!points[i].id) {
      displayPoint(res, i, 'no id', points[i]);
    } else if(!points[i].title) {
      displayPoint(res, i, 'no title', points[i]);
    } else if(!points[i].irrelevant && !points[i].service) {
      displayPoint(res, i, 'no service', points[i]);
    } else if(!points[i].irrelevant && !points[i].topic) {
      displayPoint(res, i, 'no topic', points[i]);
    }
  }
  res.write(fs.readFileSync('curator-postfix.html'));
	//console.log(points);
}
function processPost(req) {
  var str='';
  req.on('data', function(chunk) {
    str += chunk;
  });
  req.on('end', function() {
    if(!str.length) {
      return;
    }
    var pairs = str.split('&');
    console.log(pairs);
    var incoming = {};
    for(var i=0; i<pairs.length; i++) {
      var parts = pairs[i].split('=');
      incoming[parts[0]]=parts[1];
    }
    for(var i in incoming) {
      if(i!='filename') {
        points[incoming.filename][i]=incoming[i];
      }
    }
    savePoint(incoming.filename);
  });
}
//...
files = fs.readdirSync('points/');
for(var i=0; i<files.length; i++) {
	if(files[i]!='README.md') {
		addFile(files[i]);
  }
}
var server = http.createServer(function(req, res) {
  var point = req.url.substring(2);
  processPost(req);
  if(point.length && req.url.substring(0,2)=='/?') {
    console.log('displaying form for '+point);
    res.writeHead(200, {});
    displayForm(res, point);
  } else if(req.url=='/') {
    res.writeHead(200, {});
    displayPoints(res);
  } else {
    res.writeHead(404, {});
  }
  res.end('
');
});
server.listen(21337);
console.log('see http://localhost:21337/');
<|endoftext|>


<commit_before>var birdCanvas = document.getElementById("birdWindow")
var playerInput = document.getElementById("player-input")
var counter = 0;
var birdPoints = 0;
var indexCounter = 0;
var birdContext = birdCanvas.getContext("2d");

function bird() {
	this.x = 10;
	this.y= 150;

	this.width = 10;
	this.height = 10;
}

// function text(string){
// 	this.content = string;
// }

var myBird = new bird();

bird.prototype.draw = function(){
	birdContext.fillStyle = "black";
	birdContext.fillRect(this.x, this.y, this.width, this.height);
	return this;
}

bird.prototype.move = function(){
	this.x++;
}

playerInput.addEventListener('keyup', function(event){
	var challengeText = $('#challenge-text').text()
	var currentKey = event.key;

  if (currentKey === challengeText[indexCounter]) {
    birdPoints++;
    counter++;
		indexCounter++;
	}else if (currentKey === "Backspace"){
		counter--;
	} else {
			birdPoints--;
			counter++;
	}
	updateScore();
})

	function updateScore(){
		$("#score").text(birdPoints);
	}

window.addEventListener("keyup", function(event){
	myBird.draw();
	console.log(event.key);
	myBird.move();
	// console.log(myBird);
})
<commit_msg>Bird moves when player types the right letter<commit_after>var birdCanvas = document.getElementById("birdWindow")
var playerInput = document.getElementById("player-input")
var counter = 0;
var birdPoints = 0;
var indexCounter = 0;
var birdContext = birdCanvas.getContext("2d");

function bird() {
	this.x = 10;
	this.y= 150;
	this.width = 10;
	this.height = 10;
}

var myBird = new bird();

bird.prototype.draw = function(){
	birdContext.fillStyle = "black";
	birdContext.fillRect(this.x, this.y, this.width, this.height);
	return this;
}

bird.prototype.move = function(){
	this.x+=5;
	return this;
}

playerInput.addEventListener('keyup', function(event){
	var challengeText = $('#challenge-text').text()
	var currentKey = event.key;
	evaluateKey(currentKey, challengeText);
	updateScore();
})

function updateScore(){
	$("#score").text(birdPoints);
}

function evaluateKey(currentKey, challengeText) {
	if (currentKey === challengeText[indexCounter]) {
    birdPoints++;
    counter++;
		indexCounter++;
		myBird.move().draw();
	} else if (currentKey === "Backspace"){
		counter--;
	} else {
			birdPoints--;
			counter++;
	};
}

myBird.draw();
<|endoftext|>


<commit_before>'use strict'

const Ipinfo = require('ipinfo')
const RequestIp = require('request-ip')

/**
 * set the initial state for `location` decorator
 * @returns {{}}
 */
const getState = () => {
  return undefined
}

/**
 * Extract the IP address from request
 *
 * @param request
 * @returns {*} - client request IP address
 */
const getClientIP = request => {
  return RequestIp.getClientIp(request)
}

/**
 * Retrieve the actual location by IP geo location using ipinfo.io
 * @param ip
 * @param callback
 * @returns {*} - location object
 */
const getLocation = ip => {
  return new Promise((resolve, reject) => {
    Ipinfo(ip, (err, location) => {
      if (err) {
        // return without data -> results in "undefined" location
        return reject(err)
      }

      return resolve(location)
    })
  })
}

/**
 * The hapi plugin implementation
 * @param server
 * @param pluginOptions
 * @param next
 */
const register = async function register (server, pluginOptions, next) {
  const options = {
    enabledByDefault: true
  }

  Object.assign(options, pluginOptions)

  // decorate the request with a `location` property
  server.decorate('request', 'location', getState, { apply: true })

  // extend the request lifecycle at `onPreAuth` to fetch
  // the client’s location before authenticating the request
  server.ext('onPreAuth', (request, h) => {
    // get the configuration that is assigned to a route
    const settings = request.route.settings.plugins['hapi-geo-locate'] || {}

    // should use a defined fake IP address?
    // a fake IP might be used for debug purposes
    // to locate a request within a given country
    const fakeIP = settings.fakeIP && settings.fakeIP.length > 0 ? settings.fakeIP : undefined

    let geoLocate = options.enabledByDefault

    if (typeof settings.enabled !== 'undefined') {
      geoLocate = settings.enabled
    }

    if (!geoLocate) {
      return h.continue
    }

    const ip = fakeIP || getClientIP(request)

    return getLocation(ip).then(location => {
      request.location = location
      return h.continue
    })
  })
}

exports.plugin = {
  register,
  pkg: require('../package.json')
}
<commit_msg>use async/await in code instead of promise; minor code refactorings<commit_after>'use strict'

const Ipinfo = require('ipinfo')
const RequestIp = require('request-ip')

/**
 * Set the initial state for `location` decorator
 *
 * @returns {undefined}
 */
function getState () {
  return undefined
}

/**
 * Extract the IP address from request
 *
 * @param request
 *
 * @returns {String} - client request IP address
 */
function getClientIP (request) {
  return RequestIp.getClientIp(request)
}

/**
 * Retrieve the actual location by IP geo location using ipinfo.io
 *
 * @param ip
 * @param callback
 *
 * @returns {Object} - location object
 */
function getLocation (ip) {
  return new Promise((resolve, reject) => {
    Ipinfo(ip, (err, location) => {
      if (err) {
        // return without data -> results in "undefined" location
        return reject(err)
      }

      return resolve(location)
    })
  })
}

/**
 * The hapi plugin implementation
 *
 * @param server
 * @param pluginOptions
 * @param next
 */
async function register (server, pluginOptions, next) {
  const options = {
    enabledByDefault: true
  }

  Object.assign(options, pluginOptions)

  // decorate the request with a `location` property
  server.decorate('request', 'location', getState, { apply: true })

  // extend the request lifecycle at `onPreAuth` to fetch
  // the client’s location before authenticating the request
  server.ext('onPreAuth', async (request, h) => {
    // get the configuration that is assigned to a route
    const settings = request.route.settings.plugins['hapi-geo-locate'] || {}

    // should use a defined fake IP address?
    // a fake IP might be used for debug purposes
    // to locate a request within a given country
    const fakeIP = settings.fakeIP && settings.fakeIP.length > 0 ? settings.fakeIP : undefined

    let geoLocate = options.enabledByDefault

    if (typeof settings.enabled !== 'undefined') {
      geoLocate = settings.enabled
    }

    if (!geoLocate) {
      return h.continue
    }

    const ip = fakeIP || getClientIP(request)

    const location = await getLocation(ip)
    request.location = location

    return h.continue
  })
}

exports.plugin = {
  register,
  pkg: require('../package.json')
}
<|endoftext|>


<commit_before>module.exports = (function() {
  /**
   * **NodObjC** is the bridge between NodeJS and the Objective-C runtime and
   * frameworks, making it possible to write native Cocoa applications (both GUI and
   * command-line) using 100% NodeJS. Applications are written entirely in
   * JavaScript and interpreted at runtime.
   *
   * ## Getting Started
   *
   * Every **NodObjC** application begins with requiring the `NodObjC` module.
   * You can name the returned module variable anything you want, but the
   * "canonical" name for it is `$`. This is mostly because you're going to be using
   * the variable all over the place, and probably want to keep it short.
   *
   *     var $ = require('NodObjC')
   *
   * The next step is to [`import()`](import.html) a desired "Framework" that is
   * installed on the system. These frameworks are the APIs provided to Objective-C,
   * which could be the default frameworks (provided by Apple) or 3rd party
   * frameworks written by others (or you). The "Foundation" framework is the...
   * well.. foundation of these APIs, providing the most basic and important
   * classes like `NSString` and `NSArray`.
   *
   *     $.import('Foundation')
   *
   * [`import()`](import.html) doesn't return anything, however it will throw an
   * Error if anything goes wrong. What happens after the import call is that the
   * `$` variable now has a whole bunch of new properties attached to it, the
   * exports from the imported framework. At this point, you can fully interact
   * with these Objective-C classes, creating instances, subclassing, swizzling,
   * etc.
   *
   * A lot of core classes expect an `NSAutoreleasePool` instance on the stack, so
   * the first Objective-C object instance you create is usually one of those.
   *
   *     var pool = $.NSAutoreleasePool('alloc')('init')
   *
   * Pretty simple! You don't need to worry about the autorelease pool after this.
   * Now, for an example, try creating an `NSArray` instance, well, an
   * `NSMutableArray` technically, so we can also add an `NSString` to it.
   *
   *     var array = $.NSMutableArray('alloc')('init')
   *
   *     array('addObject', $('Hello World!'))
   *
   *     console.log(array)
   *     // (
   *     //     "Hello World!"
   *     // )
   *
   * So there's an `NSArray` instance with a `count` (Objective-C's version of
   * `Array#length`) of `1`, containing an `NSString` with the text "Hello World!".
   * From here on out, you will need to refer to your Cocoa documentation for the
   * rest of the available methods `NSArray` offers.
   *
   * ## Message Sending Syntax
   *
   * To send an Objective-C message to an Objective-C object using **NodObjC**, you
   * have to **invoke the object as a function**, where the **even number arguments
   * make up the message name** and the **odd numbered arguments are the arguments**
   * to send to the [object](id.html).
   *
   *     object('messageNameWithArg', someArg, 'andArg', anotherArg)
   *
   * This sounds and probably looks strange at first, but this is the cleanest
   * syntax while still being valid JS. It also maintains the "readabililty" of
   * typical Objective-C method names.
   *
   * ## Dynamic Object Introspection
   *
   * Since **NodObjC** runs in an interpreted environment, it is actually *very
   * easy* to dynamically inspect the defined methods, instance variables (ivars),
   * implemented protocols, and more of any given Objective-C object (a.k.a.
   * [`id`](id.html) instances).
   *
   * Using the same `array` instance as before, you can retreive a list of the
   * type of class, and it's subclasses, by calling the `.ancestors()` function.
   *
   *     array.ancestors()
   *     // [ '__NSArrayM',
   *     //   'NSMutableArray',
   *     //   'NSArray',
   *     //   'NSObject' ]
   *
   * Also commonly of interest are the given methods an object responds to. Use the
   * `.methods()` function for that.
   *
   *     array.methods()
   *     // [ 'addObject:',
   *     //   'copyWithZone:',
   *     //   'count',
   *     //   'dealloc',
   *     //   'finalize',
   *     //   'getObjects:range:',
   *     //   'indexOfObjectIdenticalTo:',
   *     //   'insertObject:atIndex:',
   *     //   'objectAtIndex:',
   *     //   'removeLastObject',
   *     //   'removeObjectAtIndex:',
   *     //   'replaceObjectAtIndex:withObject:' ]
   *
   * ## More Docs
   *
   * Check out the rest of the doc pages for some of the other important
   * **NodObjC** pieces.
   *
   *  * [Block](block.html) - How to use an Objective-C "block" function.
   *  * [Class](class.html) - Subclassing and adding methods at runtime.
   *  * [Exception](exception.html) - **NodObjC** exceptions *are* JavaScript `Error` objects.
   *  * [id](id.html) - The wrapper class for every Objective-C object.
   *  * [Import](import.html) - Importing "Frameworks" into the process.
   *  * [Ivars](ivar.html) - Instance variable definitions.
   *  * [Method](method.html) - Method definitions and swizzling.
   *  * [Structs](struct.html) - Using Structs and C functions in **NodObjC**.
   */

  /**
   * This function accepts native JS types (`String`, `Number`, `Date`) and converts
   * them to the proper Objective-C type (`NSString`, `NSNumber`, `NSDate`).
   *
   * Often times, you will use this function to cast a JS String into an NSString
   * for methods that accept NSStrings (since NodObjC doesn't automatically cast to
   * NSStrings in those instances).
   *
   *     var jsString = 'a javascript String'
   *     var nsString = $(jsString)
   *
   *     $.NSLog(nsString)
   *
   * @param {String|Number|Date} o the JS object to convert to a Cocoa equivalent type.
   * @return {id} The equivalent Cocoa type as the input object. Could be an `NSString`, `NSNumber` or `NSDate`.
   */

  function NodObjc(o) {
    var t = typeof o;
    if (t == 'string')
      return NodObjc.NSString('stringWithUTF8String', String(o));
    else if (t == 'number')
      return NodObjc.NSNumber('numberWithDouble', Number(o));
    else if ((o instanceof Date ) || (Object.prototype.toString.call(o) == '[object Date]'))
      return NodObjc.NSDate('dateWithTimeIntervalSince1970', o / 1000);
    else if (Object.prototype.toString.call(o) === '[object RegExp]')
    {
      var options = 0;
      //if (o.global) options |= NodObjc. ???
      if (o.ignoreCase) options |= NodObjc.NSRegularExpressionCaseInsensitive;
      if (o.multiline) options |= NodObjc.NSRegularExpressionAnchorsMatchLines;
      // TODO: add NSError support here
      var err = null;
      return NodObjc.NSRegularExpression(
        'regularExpressionWithPattern', NodObjc(o.source),
        'options', options,
        'error', err);
    }

    throw new Error('Unsupported object passed in to convert: ' + o);
  }

  var Import = require('./import');
  NodObjc.resolve = Import.resolve;
  NodObjc.import = NodObjc.framework = NodObjc.importFramework = function (p,q) {
    q = (typeof(q) == 'undefined') ? 99999999 : q;
    Import.import(p,false,NodObjc,q);
  };
  NodObjc.alloc = Import.allocReference;
  NodObjc.YES = '\x01';
  NodObjc.NO = '\x00';
  return NodObjc;
})();
<commit_msg>index: slight formatting fix<commit_after>module.exports = (function() {
  /**
   * **NodObjC** is the bridge between Node.js and the Objective-C runtime and
   * frameworks, making it possible to write native Cocoa applications (both GUI
   * and command-line) using 100% Node.js. Applications are written entirely in
   * JavaScript and interpreted at runtime.
   *
   * ## Getting Started
   *
   * Every **NodObjC** application begins with requiring the `NodObjC` module.
   * You can name the returned module variable anything you want, but the
   * "canonical" name for it is `$`. This is mostly because you're going to be using
   * the variable all over the place, and probably want to keep it short.
   *
   *     var $ = require('NodObjC')
   *
   * The next step is to [`import()`](import.html) a desired "Framework" that is
   * installed on the system. These frameworks are the APIs provided to Objective-C,
   * which could be the default frameworks (provided by Apple) or 3rd party
   * frameworks written by others (or you). The "Foundation" framework is the...
   * well.. foundation of these APIs, providing the most basic and important
   * classes like `NSString` and `NSArray`.
   *
   *     $.import('Foundation')
   *
   * [`import()`](import.html) doesn't return anything, however it will throw an
   * Error if anything goes wrong. What happens after the import call is that the
   * `$` variable now has a whole bunch of new properties attached to it, the
   * exports from the imported framework. At this point, you can fully interact
   * with these Objective-C classes, creating instances, subclassing, swizzling,
   * etc.
   *
   * A lot of core classes expect an `NSAutoreleasePool` instance on the stack, so
   * the first Objective-C object instance you create is usually one of those.
   *
   *     var pool = $.NSAutoreleasePool('alloc')('init')
   *
   * Pretty simple! You don't need to worry about the autorelease pool after this.
   * Now, for an example, try creating an `NSArray` instance, well, an
   * `NSMutableArray` technically, so we can also add an `NSString` to it.
   *
   *     var array = $.NSMutableArray('alloc')('init')
   *
   *     array('addObject', $('Hello World!'))
   *
   *     console.log(array)
   *     // (
   *     //     "Hello World!"
   *     // )
   *
   * So there's an `NSArray` instance with a `count` (Objective-C's version of
   * `Array#length`) of `1`, containing an `NSString` with the text "Hello World!".
   * From here on out, you will need to refer to your Cocoa documentation for the
   * rest of the available methods `NSArray` offers.
   *
   * ## Message Sending Syntax
   *
   * To send an Objective-C message to an Objective-C object using **NodObjC**, you
   * have to **invoke the object as a function**, where the **even number arguments
   * make up the message name** and the **odd numbered arguments are the arguments**
   * to send to the [object](id.html).
   *
   *     object('messageNameWithArg', someArg, 'andArg', anotherArg)
   *
   * This sounds and probably looks strange at first, but this is the cleanest
   * syntax while still being valid JS. It also maintains the "readabililty" of
   * typical Objective-C method names.
   *
   * ## Dynamic Object Introspection
   *
   * Since **NodObjC** runs in an interpreted environment, it is actually *very
   * easy* to dynamically inspect the defined methods, instance variables (ivars),
   * implemented protocols, and more of any given Objective-C object (a.k.a.
   * [`id`](id.html) instances).
   *
   * Using the same `array` instance as before, you can retreive a list of the
   * type of class, and it's subclasses, by calling the `.ancestors()` function.
   *
   *     array.ancestors()
   *     // [ '__NSArrayM',
   *     //   'NSMutableArray',
   *     //   'NSArray',
   *     //   'NSObject' ]
   *
   * Also commonly of interest are the given methods an object responds to. Use the
   * `.methods()` function for that.
   *
   *     array.methods()
   *     // [ 'addObject:',
   *     //   'copyWithZone:',
   *     //   'count',
   *     //   'dealloc',
   *     //   'finalize',
   *     //   'getObjects:range:',
   *     //   'indexOfObjectIdenticalTo:',
   *     //   'insertObject:atIndex:',
   *     //   'objectAtIndex:',
   *     //   'removeLastObject',
   *     //   'removeObjectAtIndex:',
   *     //   'replaceObjectAtIndex:withObject:' ]
   *
   * ## More Docs
   *
   * Check out the rest of the doc pages for some of the other important
   * **NodObjC** pieces.
   *
   *  * [Block](block.html) - How to use an Objective-C "block" function.
   *  * [Class](class.html) - Subclassing and adding methods at runtime.
   *  * [Exception](exception.html) - **NodObjC** exceptions *are* JavaScript `Error` objects.
   *  * [id](id.html) - The wrapper class for every Objective-C object.
   *  * [Import](import.html) - Importing "Frameworks" into the process.
   *  * [Ivars](ivar.html) - Instance variable definitions.
   *  * [Method](method.html) - Method definitions and swizzling.
   *  * [Structs](struct.html) - Using Structs and C functions in **NodObjC**.
   */

  /**
   * This function accepts native JS types (`String`, `Number`, `Date`) and converts
   * them to the proper Objective-C type (`NSString`, `NSNumber`, `NSDate`).
   *
   * Often times, you will use this function to cast a JS String into an NSString
   * for methods that accept NSStrings (since NodObjC doesn't automatically cast to
   * NSStrings in those instances).
   *
   *     var jsString = 'a javascript String'
   *     var nsString = $(jsString)
   *
   *     $.NSLog(nsString)
   *
   * @param {String|Number|Date} o the JS object to convert to a Cocoa equivalent type.
   * @return {id} The equivalent Cocoa type as the input object. Could be an `NSString`, `NSNumber` or `NSDate`.
   */

  function NodObjc(o) {
    var t = typeof o;
    if (t == 'string')
      return NodObjc.NSString('stringWithUTF8String', String(o));
    else if (t == 'number')
      return NodObjc.NSNumber('numberWithDouble', Number(o));
    else if ((o instanceof Date ) || (Object.prototype.toString.call(o) == '[object Date]'))
      return NodObjc.NSDate('dateWithTimeIntervalSince1970', o / 1000);
    else if (Object.prototype.toString.call(o) === '[object RegExp]')
    {
      var options = 0;
      //if (o.global) options |= NodObjc. ???
      if (o.ignoreCase) options |= NodObjc.NSRegularExpressionCaseInsensitive;
      if (o.multiline) options |= NodObjc.NSRegularExpressionAnchorsMatchLines;
      // TODO: add NSError support here
      var err = null;
      return NodObjc.NSRegularExpression(
        'regularExpressionWithPattern', NodObjc(o.source),
        'options', options,
        'error', err);
    }

    throw new Error('Unsupported object passed in to convert: ' + o);
  }

  var Import = require('./import');
  NodObjc.resolve = Import.resolve;

  NodObjc.import =
  NodObjc.framework =
  NodObjc.importFramework =
  function framework (p,q) {
    q = (typeof(q) == 'undefined') ? 99999999 : q;
    Import.import(p,false,NodObjc,q);
  };

  NodObjc.alloc = Import.allocReference;
  NodObjc.YES = '\x01';
  NodObjc.NO = '\x00';
  return NodObjc;
})();
<|endoftext|>


<commit_before>var ArtStack = module.exports = function () {
    var self = this;
    ArtStack.auth = require("./auth").login;
    ArtStack.tags = require("./api/tags");
    ArtStack.artworks = require("./api/artworks");
};
<commit_msg>Export an object instead<commit_after>var ArtStack = module.exports = {};

ArtStack.auth = require("./auth").login;
ArtStack.tags = require("./api/tags");
ArtStack.artworks = require("./api/artworks");
<|endoftext|>


<commit_before>export default {};
<commit_msg>testing<commit_after>export default {};

var test = 'test';
<|endoftext|>


<commit_before>'use strict'; // eslint-disable-line strict

const webpackDevMiddleware = require('webpack-dev-middleware');
const webpackHotMiddleware = require('webpack-hot-middleware');
const browserSync = require('browser-sync');
const url = require('url');

const mergeWithConcat = require('./util/mergeWithConcat');

module.exports = class {
  constructor(options) {
    this.watcher = null;
    this.compiler = null;
    this.options = mergeWithConcat({
      proxyUrl: 'https://localhost:3000',
      callback() {},
    }, options);
  }
  apply(compiler) {
    if (this.options.disable) {
      return;
    }
    this.compiler = compiler;
    compiler.plugin('done', this.doneCompiling);
  }
  doneCompiling() {
    if (!this.watcher) {
      this.watcher = browserSync.create();
      this.compiler.plugin('compilation', () => this.watcher.notify('Rebuilding...'));
      this.start();
    }
    // Optionally add logic for this.watcher.reload()
  }
  start() {
    const watcherConfig = mergeWithConcat({
      host: url.parse(this.options.proxyUrl).hostname,
      port: url.parse(this.options.proxyUrl).port,
      proxy: {
        target: this.options.target,
        middleware: this.middleware(),
      },
    }, this.options.browserSyncOptions);
    this.watcher.init(watcherConfig, this.options.callback.bind(this));
  }
  middleware() {
    this.webpackDevMiddleware = webpackDevMiddleware(this.compiler, {
      publicPath: this.options.publicPath,
      stats: { colors: true },
    });
    this.webpackHotMiddleware = webpackHotMiddleware(this.compiler, {
      log: this.watcher.notify.bind(this.watcher),
    });
    return [this.webpackDevMiddleware, this.webpackHotMiddleware];
  }
};
<commit_msg>Use closure instead of doneCompiling() method. Fixes #1717<commit_after>'use strict'; // eslint-disable-line strict

const webpackDevMiddleware = require('webpack-dev-middleware');
const webpackHotMiddleware = require('webpack-hot-middleware');
const browserSync = require('browser-sync');
const url = require('url');

const mergeWithConcat = require('./util/mergeWithConcat');

module.exports = class {
  constructor(options) {
    this.watcher = null;
    this.compiler = null;
    this.options = mergeWithConcat({
      proxyUrl: 'https://localhost:3000',
      callback() {},
    }, options);
  }
  apply(compiler) {
    if (this.options.disable) {
      return;
    }
    this.compiler = compiler;
    compiler.plugin('done', () => {
      if (!this.watcher) {
        this.watcher = browserSync.create();
        compiler.plugin('compilation', () => this.watcher.notify('Rebuilding...'));
        this.start();
      }
      // Optionally add logic for this.watcher.reload()
    });
  }
  start() {
    const watcherConfig = mergeWithConcat({
      host: url.parse(this.options.proxyUrl).hostname,
      port: url.parse(this.options.proxyUrl).port,
      proxy: {
        target: this.options.target,
        middleware: this.middleware(),
      },
    }, this.options.browserSyncOptions);
    this.watcher.init(watcherConfig, this.options.callback.bind(this));
  }
  middleware() {
    this.webpackDevMiddleware = webpackDevMiddleware(this.compiler, {
      publicPath: this.options.publicPath,
      stats: { colors: true },
    });
    this.webpackHotMiddleware = webpackHotMiddleware(this.compiler, {
      log: this.watcher.notify.bind(this.watcher),
    });
    return [this.webpackDevMiddleware, this.webpackHotMiddleware];
  }
};
<|endoftext|>


<commit_before>'use strict';

/**
 * Module dependencies.
 */

var each = require('@ndhoule/each');
var integration = require('@segment/analytics.js-integration');
var extend = require('@ndhoule/extend');

/**
 * Expose `AdWords`.
 */

var AdWords = module.exports = integration('AdWords')
  .option('conversionId', '')
  .option('remarketing', false)
  .tag('<script src="//www.googleadservices.com/pagead/conversion_async.js">')
  .mapping('events');

/**
 * Initialize.
 *
 * @api public
 */

AdWords.prototype.initialize = function() {
  this.load(this.ready);
};

/**
 * Loaded.
 *
 * @api private
 * @return {boolean}
 */

AdWords.prototype.loaded = function() {
  return !!(document.body && window.google_trackConversion);
};

/**
 * Page.
 *
 * https://support.google.com/adwords/answer/3111920#standard_parameters
 * https://support.google.com/adwords/answer/3103357
 * https://developers.google.com/adwords-remarketing-tag/asynchronous/
 * https://developers.google.com/adwords-remarketing-tag/parameters
 *
 * @api public
 * @param {Page} page
 */

AdWords.prototype.page = function(page) {
  // https://developers.google.com/adwords-remarketing-tag/asynchronous/
  var remarketing = this.options.remarketing;
  var id = this.options.conversionId;
  // it's okay to send custom props even if customers dont use dynamic remarketing
  // "if this variable is not provided, static remarketing rules can still be generated in AdWords by using URL-based rules."
  // customers may have custom instance of google params on the window
  var props = remarketing ? extend(page.properties(), window.google_custom_params) : {};
  window.google_trackConversion({
    google_conversion_id: id,
    google_custom_params: props,
    google_remarketing_only: remarketing
  });
};

/**
 * Track.
 *
 * @api public
 * @param {Track}
 */

AdWords.prototype.track = function(track) {
  var remarketing = this.options.remarketing;
  var id = this.options.conversionId;
  var events = this.events(track.event());
  var revenue = track.revenue() || 0;
  each(function(label) {
    var props = remarketing ? extend(track.properties(), window.google_custom_params) : {};
    delete props.revenue;
    window.google_trackConversion({
      google_conversion_id: id,
      google_custom_params: props,
      google_conversion_language: 'en',
      google_conversion_format: '3',
      google_conversion_color: 'ffffff',
      google_conversion_label: label,
      google_conversion_value: revenue,
      google_remarketing_only: remarketing
    });
  }, events);
};
<commit_msg>backward compat<commit_after>'use strict';

/**
 * Module dependencies.
 */

var each = require('@ndhoule/each');
var integration = require('@segment/analytics.js-integration');
var extend = require('@ndhoule/extend');

/**
 * Expose `AdWords`.
 */

var AdWords = module.exports = integration('AdWords')
  .option('conversionId', '')
  .option('remarketing', false)
  .tag('<script src="//www.googleadservices.com/pagead/conversion_async.js">')
  .mapping('events');

/**
 * Initialize.
 *
 * @api public
 */

AdWords.prototype.initialize = function() {
  this.load(this.ready);
};

/**
 * Loaded.
 *
 * @api private
 * @return {boolean}
 */

AdWords.prototype.loaded = function() {
  return !!(document.body && window.google_trackConversion);
};

/**
 * Page.
 *
 * https://support.google.com/adwords/answer/3111920#standard_parameters
 * https://support.google.com/adwords/answer/3103357
 * https://developers.google.com/adwords-remarketing-tag/asynchronous/
 * https://developers.google.com/adwords-remarketing-tag/parameters
 *
 * @api public
 * @param {Page} page
 */

AdWords.prototype.page = function(page) {
  // https://developers.google.com/adwords-remarketing-tag/asynchronous/
  var remarketing = this.options.remarketing;
  var id = this.options.conversionId;
  // it's okay to send custom props even if customers dont use dynamic remarketing
  // "if this variable is not provided, static remarketing rules can still be generated in AdWords by using URL-based rules."
  // customers may have custom instance of google params on the window
  var props = remarketing ? extend(page.properties(), window.google_custom_params) : {};
  window.google_trackConversion({
    google_conversion_id: id,
    google_custom_params: props,
    google_remarketing_only: remarketing
  });
};

/**
 * Track.
 *
 * @api public
 * @param {Track}
 */

AdWords.prototype.track = function(track) {
  var remarketing = this.options.remarketing;
  var id = this.options.conversionId;
  var events = this.events(track.event());
  var revenue = track.revenue() || 0;
  each(function(label) {
    // We technically don't need to send the props as far as GA docs
    // are concerned but to be safe in regards to backward compat (since
    // we always used to send props regardless of `remarketing` flag)
    // we'll keep sending the props
    var props = extend(track.properties(), remarketing ? window.google_custom_params : {});
    delete props.revenue;
    window.google_trackConversion({
      google_conversion_id: id,
      google_custom_params: props,
      google_conversion_language: 'en',
      google_conversion_format: '3',
      google_conversion_color: 'ffffff',
      google_conversion_label: label,
      google_conversion_value: revenue,
      google_remarketing_only: remarketing
    });
  }, events);
};
<|endoftext|>


<commit_before>var postcss = require('postcss');

var modDelim = '_';
var elemDelim = '__';

module.exports = postcss.plugin('bemcss', function() {
    return function(css) {
        css.walkRules(function(rule) {
            rule.selector = rule.selector
                .replace(/:block\(([\w-]+)\)/g, '.$1')
                .replace(/:elem\(([\w-]+)\)/g, elemDelim + '$1')
                .replace(/:mod\(([\w-]+)\s?([\w-]+)?\)/g, function(match, mod, val) {
                    if (val) {
                        return modDelim + mod + modDelim + val;
                    }

                    return modDelim + mod;
                });
        });
    };
});
<commit_msg>:lipstick:<commit_after>'use strict';

var postcss = require('postcss');

var modDelim = '_';
var elemDelim = '__';

module.exports = postcss.plugin('rebem-css', function() {
    return function(css) {
        css.walkRules(function(rule) {
            rule.selector = rule.selector
                // :block(block) → .block
                .replace(/:block\(([\w-]+)\)/g, '.$1')
                // :elem(elem) → __elem
                .replace(/:elem\(([\w-]+)\)/g, elemDelim + '$1')
                // :mod(mod) → _mod
                // :mod(mod val)  → _mod_val
                .replace(/:mod\(([\w-]+)\s?([\w-]+)?\)/g, function(match, mod, val) {
                    if (val) {
                        return modDelim + mod + modDelim + val;
                    }

                    return modDelim + mod;
                });
        });
    };
});
<|endoftext|>


<commit_before>'use strict'

const repl = require('repl')
const fs = require('fs')
const path = require('path')

const chalk = require('chalk')
const examples = require('node-examples')

const midi = require('./midi')
const piano = require('./piano')
const colors = require('./colors')
const instructions = require('./instructions')
const evaluator = require('./evaluator')
const mappers = require('./mappers')
const streams = require('./streams')

function getPrompt(greeting) {
    let lastColor
    const words = greeting.split('').map(c => {
        lastColor = colors.getRandom(lastColor)
        return chalk[lastColor](c)
    }).join('')

    return `${words}${chalk.gray('>')}`
}

piano.draw().on('end', () => {

    console.log(chalk.gray(`\nWelcome. Pipe ${chalk.green('midiIn.pipe(toAudio)')}, or map notes through ${chalk.green('play()')}`))
    console.log(chalk.gray(`Enter ${chalk.green('.keyboard')} to see a list of all commands`))

    const replServer = repl.start({ prompt: getPrompt('node-keyboard'), ignoreUndefined: true, eval: evaluator })

    const historyFile = path.join(__dirname, '/../', '.node_keyboard_repl_history')

    // load history
    fs.readFile(historyFile, (err, data) => {
        if (err && err.code !== 'ENOENT') {
            return console.error(err)
        } else if (err) {
            return fs.writeFile(err.path, '', 0, 0)
        }
        data.toString().split('\n').reverse().filter(line => line.trim()).map(line => replServer.history.push(line))
    })

    // append history on exit
    replServer.on('exit', () => {
        fs.appendFile(historyFile, replServer.lines.filter(l => l.replace(/\n/,'').length).join('\n') + '\n')
    })

    replServer.defineCommand('keyboard', {
        help: 'node-keyboard: See keyboard commands',
        action: function() {
            instructions.show()
            this.displayPrompt()
        }
    })

    // enable MIDI input if possible
    const midiIn = midi()
    if (midiIn) replServer.context.midiIn = midiIn

    // attach all stream factories to context (with getter contexts)
    Reflect
        .ownKeys(streams)
        .map(key => {
            return { pd: Reflect.getOwnPropertyDescriptor(streams, key), key }
        })
        .forEach(({ pd, key }) => Reflect.defineProperty(replServer.context, key, pd))

    // attach all mapping functions (flatten any getters)
    Object.assign(replServer.context, mappers)

    // load in examples into repl
    examples({ path: path.join(__dirname, '../examples') })

    // allow global imports
    replServer.context.requireg = name => require(path.join(__dirname, '..', '..', name))

    // On .break (CTRL+C), unpipe everything, just in case
    replServer.on('SIGINT', () => {
        if (midiIn) midiIn.unpipe()
        streams.unpipeAll()
    })
})
<commit_msg>Add support for module reloading<commit_after>'use strict'

const repl = require('repl')
const fs = require('fs')
const path = require('path')

const chalk = require('chalk')
const examples = require('node-examples')

const midi = require('./midi')
const piano = require('./piano')
const colors = require('./colors')
const instructions = require('./instructions')
const evaluator = require('./evaluator')
const mappers = require('./mappers')
const streams = require('./streams')

function getPrompt(greeting) {
    let lastColor
    const words = greeting.split('').map(c => {
        lastColor = colors.getRandom(lastColor)
        return chalk[lastColor](c)
    }).join('')

    return `${words}${chalk.gray('>')}`
}

piano.draw().on('end', () => {

    console.log(chalk.gray(`\nWelcome. Pipe ${chalk.green('midiIn.pipe(toAudio)')}, or map notes through ${chalk.green('play()')}`))
    console.log(chalk.gray(`Enter ${chalk.green('.keyboard')} to see a list of all commands`))

    const replServer = repl.start({ prompt: getPrompt('node-keyboard'), ignoreUndefined: true, eval: evaluator })

    const historyFile = path.join(__dirname, '/../', '.node_keyboard_repl_history')

    // load history
    fs.readFile(historyFile, (err, data) => {
        if (err && err.code !== 'ENOENT') {
            return console.error(err)
        } else if (err) {
            return fs.writeFile(err.path, '', 0, 0)
        }
        data.toString().split('\n').reverse().filter(line => line.trim()).map(line => replServer.history.push(line))
    })

    // append history on exit
    replServer.on('exit', () => {
        fs.appendFile(historyFile, replServer.lines.filter(l => l.replace(/\n/,'').length).join('\n') + '\n')
    })

    replServer.defineCommand('keyboard', {
        help: 'node-keyboard: See keyboard commands',
        action: function() {
            instructions.show()
            this.displayPrompt()
        }
    })

    // enable MIDI input if possible
    const midiIn = midi()
    if (midiIn) replServer.context.midiIn = midiIn

    // attach all stream factories to context (with getter contexts)
    Reflect
        .ownKeys(streams)
        .map(key => {
            return { pd: Reflect.getOwnPropertyDescriptor(streams, key), key }
        })
        .forEach(({ pd, key }) => Reflect.defineProperty(replServer.context, key, pd))

    // attach all mapping functions (flatten any getters)
    Object.assign(replServer.context, mappers)

    // load in examples into repl
    examples({ path: path.join(__dirname, '../examples') })

    // allow global imports
    replServer.context.requireg = name => require(path.join(__dirname, '..', '..', name))

    // allow module reloading
    replServer.context.reload = module => {
        delete require.cache[require.resolve(module)]
        return require(module)
    }

    // On .break (CTRL+C), unpipe everything, just in case
    replServer.on('SIGINT', () => {
        if (midiIn) midiIn.unpipe()
        streams.unpipeAll()
    })
})
<|endoftext|>