<commit_before>import Slider from 'react-slick';
import Button from '../SpaceButton';
import React, { Component } from 'react';

const NextArrow = React.createClass({
  render: function() {
    return

    			<button type="button" className="col-sm-offset-6"> </button>

  }
});

const PrevArrow = React.createClass({
  render: function() {
    return

       		<button type="button" className="col-sm-offset-6"> </button>

  }
});

export default class Carousel extends Component {

  render() {

    function spaceNotAvailable() {
      alert('This space is still being developed.\nCheck back soon!');
    }

    var settings = {
      dots: false,
      infinite: true,
      speed: 3000,
      slidesToScroll: 3, //normal computer
      slidesToShow: 4,
      nextArrow: <NextArrow />,
      prevArrow: <PrevArrow />,
      responsive: [{
        breakpoint: 1024, //tablet
        settings: {
          slidesToShow: 2,
          slidesToScroll: 1,
        }
      }, {
        breakpoint: 480, //mobile phone
        settings: {
          slidesToShow: 1,
          slidesToScroll: 1
        }
      }]
    };

    return (

        <Slider {...settings}>

              		<Button source='images/new_travel.jpg' link="/space/travel"/>

              		<Button source='images/Parenting.jpg' onClick={spaceNotAvailable()} link="/dashboard"/>

              		<Button source='images/insomnia.png' link="/dashboard"/>

              		<Button source='images/LGBT.jpg' link="/dashboard"/>

              		<Button source='images/workout.jpg' link="/dashboard"/>

              		<Button source='images/thrones.jpg' link="/dashboard"/>

        </Slider>

    );
  }
}
<commit_msg>after fixing conflicts from previous pull<commit_after>import Slider from 'react-slick';
import Button from '../SpaceButton';
import React, { Component } from 'react';

const NextArrow = React.createClass({
  render: function() {
    return

    			<button type="button" className="col-sm-offset-6"> </button>

  }
});

const PrevArrow = React.createClass({
  render: function() {
    return

       		<button type="button" className="col-sm-offset-6"> </button>

  }
});

export default class Carousel extends Component {

  render() {

    //Function to give alerts for buttons not yet made
    //And to incrememnt counters for fake doors
    function spaceNotAvailable() {
      alert('This space is still being developed.\nCheck back soon!');
    }

    var settings = {
      dots: false,
      infinite: true,
      speed: 3000,
      slidesToScroll: 3, //normal computer
      slidesToShow: 4,
      nextArrow: <NextArrow />,
      prevArrow: <PrevArrow />,
      responsive: [{
        breakpoint: 1024, //tablet
        settings: {
          slidesToShow: 2,
          slidesToScroll: 1,
        }
      }, {
        breakpoint: 480, //mobile phone
        settings: {
          slidesToShow: 1,
          slidesToScroll: 1
        }
      }]
    };

    return (

        <Slider {...settings}>

              		<Button source='images/new_travel.jpg' link="/space/travel"/>

              		<Button source='images/Parenting.jpg' onClick={spaceNotAvailable()} link="/dashboard"/>

              		<Button source='images/insomnia.png' link="/dashboard"/>

              		<Button source='images/LGBT.jpg' link="/dashboard"/>

              		<Button source='images/workout.jpg' link="/dashboard"/>

              		<Button source='images/thrones.jpg' link="/dashboard"/>

        </Slider>

    );
  }
}
<|endoftext|>


<commit_before>/*
 * Sozi - A presentation tool using the SVG standard
 *
 * Copyright (C) 2010-2012 Guillaume Savaton
 *
 * This program is dual licensed under the terms of the MIT license
 * or the GNU General Public License (GPL) version 3.
 * A copy of both licenses is provided in the doc/ folder of the
 * official release of Sozi.
 *
 * See http://sozi.baierouge.fr/wiki/en:license for details.
 *
 * @depend namespace.js
 * @depend player.js
 * @depend display.js
 */

/**
 * @name sozi.actions
 * @namespace Callback functions for DOM event handlers
 */
namespace(this, "sozi.actions", function (exports, window) {
    /** @lends sozi.actions */

    "use strict";

    // Module aliases
    var player = sozi.player;
    var display = sozi.display;

    // The global document object
    var document = window.document;

    // Constants: mouse button numbers
    var DRAG_BUTTON = 0;    // Left button
    var TOC_BUTTON = 1;     // Middle button

    // Constants: increments for zooming and rotating
    var SCALE_FACTOR = 1.05;
    var ROTATE_STEP = 5;

    /**
     * The status of the current drag operation.
     *
     * @type Boolean
     */
    var mouseDragged = false;

    /**
     * The X coordinate of the mouse on the latest "down" or "drag" event.
     *
     * @type Number
     */
    var mouseLastX = 0;

    /**
     * The Y coordinate of the mouse on the latest "down" or "drag" event.
     *
     * @type Number
     */
    var mouseLastY = 0;

    /**
     * Zooms the display in the given direction.
     *
     *
Only the sign of direction is used:

     *

     *
zoom in when direction > 0

     *
zoom out when direction <= 0

     *

     *
     *
The scaling is centered around point (x, y).

     *
     * @param {Number} direction The direction of the scaling operation
     * @param {Number} x The X coordinate of the scaling center
     * @param {Number} y The Y coordinate of the scaling center
     */
    function zoom(direction, x, y) {
        player.stop();
        display.viewPorts["player"].zoom(direction > 0 ? SCALE_FACTOR : 1 / SCALE_FACTOR, x, y);
    }

    /**
     * Rotate the display in the given direction.
     *
     *
Only the sign of direction is used:

     *

     *
rotate anticlockwise when direction > 0

     *
rotate clockwise when direction <= 0

     *

     *
     * @param {Number} direction The direction of the rotation
     */
    function rotate(direction) {
        player.stop();
        display.viewPorts["player"].rotate(direction > 0 ? ROTATE_STEP : -ROTATE_STEP);
    }

    /**
     * Show/hide the frame list.
     *
     *
The presentation stops when the frame list is showed,
     * and restarts when the frame list is hidden.

     */
    function toggleFrameList() {
        if (sozi.framelist.isVisible()) {
            sozi.framelist.hide();
            player.restart();
        } else {
            player.stop();
            sozi.framelist.show();
        }
    }

    function isPlayerEvent(evt) {
        return display.viewPorts["player"].contains(evt.clientX, evt.clientY);
    }

    /**
     * Event handler: mouse down.
     *
     *
When the left button is pressed, we register the current coordinates
     * in case the mouse will be dragged. Handler {@link sozi.actions-onMouseDrag} is set until
     * the button is released ({@link sozi.actions-onMouseUp}).

     *
     *
When the middle button is pressed, the table of contents is shown or hidden.

     *
     * @param {Event} evt The DOM event object
     */
    function onMouseDown(evt) {
        if (!isPlayerEvent(evt)) {
            return;
        }
        if (evt.button === DRAG_BUTTON) {
            document.documentElement.addEventListener("mousemove", onMouseDrag, false);
            mouseDragged = false;
            mouseLastX = evt.clientX;
            mouseLastY = evt.clientY;
        } else if (evt.button === TOC_BUTTON) {
            toggleFrameList();
        }
        evt.stopPropagation();
        evt.preventDefault();
    }

    /**
     * Event handler: mouse move.
     *
     *
If the left mouse button is down, then the mouse move is a drag action.
     * This method computes the displacement since the button was pressed or
     * since the last move, and updates the reference coordinates for the next move.

     *
     * @param {Event} evt The DOM event object
     */
    function onMouseDrag(evt) {
        if (!isPlayerEvent(evt)) {
            return;
        }
        player.stop();
        mouseDragged = true;
        sozi.events.fire("sozi.player.cleanup");
        display.viewPorts["player"].drag(evt.clientX - mouseLastX, evt.clientY - mouseLastY);
        mouseLastX = evt.clientX;
        mouseLastY = evt.clientY;
        evt.stopPropagation();
    }

    /**
     * Event handler: mouse up.
     *
     *
Releasing the left button removes the {@link sozi.actions-onMouseDrag} handler.

     *
     * @param {Event} evt The DOM event object
     */
    function onMouseUp(evt) {
        if (!isPlayerEvent(evt)) {
            return;
        }
        if (evt.button === DRAG_BUTTON) {
            document.documentElement.removeEventListener("mousemove", onMouseDrag, false);
        }
        evt.stopPropagation();
        evt.preventDefault();
    }

    /**
     * Event handler: context menu (i.e right click).
     *
     *
Right click goes one frame back.

     *
     *
There is no "click" event for the right mouse button and the menu
     * can't be disabled in {@link sozi.actions-onMouseDown}.

     *
     * @param {Event} evt The DOM event object
     */
    function onContextMenu(evt) {
        if (!isPlayerEvent(evt)) {
            return;
        }
        player.moveToPrevious();
        evt.stopPropagation();
        evt.preventDefault();
    }

    /**
     * Event handler: mouse click.
     *
     *
Left-click moves the presentation to the next frame.

     *
     *
No "click" event is generated for the middle button in Firefox.
     * See {@link sozi.actions-onMouseDown} for middle click handling.

     *
     *
Dragging the mouse produces a "click" event when the button is released.
     * If flag {@link sozi.actions-mouseDragged} was set by {@link sozi.actions-onMouseDrag},
     * then the click event is the result of a drag action.

     *
     * @param {Event} evt The DOM event object
     */
    function onClick(evt) {
        if (!isPlayerEvent(evt)) {
            return;
        }
        if (!mouseDragged && evt.button !== TOC_BUTTON) {
            player.moveToNext();
        }
        evt.stopPropagation();
        evt.preventDefault();
    }

    /**
     * Event handler: mouse wheel.
     *
     *
Rolling the mouse wheel stops the presentation and zooms the current display.

     *
     * FIXME shift key does not work in Opera
     *
     * @param {Event} evt The DOM event object
     */
    function onWheel(evt) {
        if (!isPlayerEvent(evt)) {
            return;
        }

        if (!evt) {
            evt = window.event;
        }

        var delta = 0;
        if (evt.wheelDelta) { // IE and Opera
            delta = evt.wheelDelta;
        }
        else if (evt.detail) { // Mozilla
            delta = -evt.detail;
        }

        if (delta !== 0) {
            if (evt.shiftKey) {
                rotate(delta);
            }
            else {
                zoom(delta, evt.clientX, evt.clientY);
            }
        }

        evt.stopPropagation();
        evt.preventDefault();
    }

    /**
     * Event handler: key press.
     *
     *
Keyboard handling is split into two methods:
     * {@link sozi.actions-onKeyPress} and {@link sozi.actions-onKeyDown}
     * in order to get the same behavior across browsers.

     *
     *
This method handles character keys "+", "-", "=", "F" and "T".

     *
     * @param {Event} evt The DOM event object
     */
    function onKeyPress(evt) {
        // Keys with modifiers are ignored
        if (evt.altKey || evt.ctrlKey || evt.metaKey) {
            return;
        }

        switch (evt.charCode || evt.keyCode) {
        case 43: // +
            zoom(1, window.innerWidth / 2, window.innerHeight / 2);
            break;
        case 45: // -
            zoom(-1, window.innerWidth / 2, window.innerHeight / 2);
            break;
        case 61: // =
            player.moveToCurrent();
            break;
        case 70: // F
        case 102: // f
            player.showAll();
            break;
        case 84: // T
        case 116: // t
            toggleFrameList();
            break;
        case 82: // R
            rotate(-1);
            break;
        case 114: // r
            rotate(1);
            break;
        }

        evt.stopPropagation();
        evt.preventDefault();
    }

    /**
     * Event handler: key down.
     *
     *
Keyboard handling is split into two methods:
     * {@link sozi.actions-onKeyPress} and {@link sozi.actions-onKeyDown}
     * in order to get the same behavior across browsers.

     *
     *
This method handles navigation keys (arrows, page up/down, home, end)
     * and the space and enter keys.

     *
     * @param {Event} evt The DOM event object
     */
    function onKeyDown(evt) {
        // Keys with modifiers are ignored
        if (evt.altKey || evt.ctrlKey || evt.metaKey) {
            return;
        }

        switch (evt.keyCode) {
        case 36: // Home
            player.moveToFirst();
            break;
        case 35: // End
            player.moveToLast();
            break;
        case 38: // Arrow up
            player.jumpToPrevious();
            break;
        case 33: // Page up
        case 37: // Arrow left
            player.moveToPrevious();
            break;
        case 40: // Arrow down
            player.jumpToNext();
            break;
        case 34: // Page down
        case 39: // Arrow right
        case 13: // Enter
        case 32: // Space
            player.moveToNext();
            break;
        }

        evt.stopPropagation();

        // In Chrome/Chromium, preventDefault() inhibits the "keypress" event
    }

    /**
     * Dummy event handler: stop event propagation.
     *
     * @param {Event} evt The DOM event object
     */
    function stopEvent(evt) {
        evt.stopPropagation();
    }

    /**
     * Event handler: document load.
     *
     *
This function sets up all other event handlers for the player.

     */
    function onDisplayReady() {
        // Prevent event propagation when clicking on a link
        // FIXME does not work in Firefox when the  is referenced through a <use>
        var links = document.getElementsByTagName("a");
        for (var i = 0; i < links.length; i += 1) {
            links[i].addEventListener("click", stopEvent, false);
            links[i].addEventListener("contextmenu", stopEvent, false);
        }

        // Mouse events are constrained to the player viewport
        // see isPlayerEvent()
        // TODO also use shift-click as an alternative for middle-click
        var svgRoot = document.documentElement;
        svgRoot.addEventListener("click", onClick, false);
        svgRoot.addEventListener("mousedown", onMouseDown, false);
        svgRoot.addEventListener("mouseup", onMouseUp, false);
        svgRoot.addEventListener("contextmenu", onContextMenu, false);
        svgRoot.addEventListener("DOMMouseScroll", onWheel, false); // Mozilla
        window.onmousewheel = onWheel;

        // Keyboard events are global to the SVG document
        svgRoot.addEventListener("keypress", onKeyPress, false);
        svgRoot.addEventListener("keydown", onKeyDown, false);
    }

    sozi.events.listen("sozi.display.ready", onDisplayReady);
});
<commit_msg>Player: bug fix, propagate key press events<commit_after>/*
 * Sozi - A presentation tool using the SVG standard
 *
 * Copyright (C) 2010-2012 Guillaume Savaton
 *
 * This program is dual licensed under the terms of the MIT license
 * or the GNU General Public License (GPL) version 3.
 * A copy of both licenses is provided in the doc/ folder of the
 * official release of Sozi.
 *
 * See http://sozi.baierouge.fr/wiki/en:license for details.
 *
 * @depend namespace.js
 * @depend player.js
 * @depend display.js
 */

/**
 * @name sozi.actions
 * @namespace Callback functions for DOM event handlers
 */
namespace(this, "sozi.actions", function (exports, window) {
    /** @lends sozi.actions */

    "use strict";

    // Module aliases
    var player = sozi.player;
    var display = sozi.display;

    // The global document object
    var document = window.document;

    // Constants: mouse button numbers
    var DRAG_BUTTON = 0;    // Left button
    var TOC_BUTTON = 1;     // Middle button

    // Constants: increments for zooming and rotating
    var SCALE_FACTOR = 1.05;
    var ROTATE_STEP = 5;

    /**
     * The status of the current drag operation.
     *
     * @type Boolean
     */
    var mouseDragged = false;

    /**
     * The X coordinate of the mouse on the latest "down" or "drag" event.
     *
     * @type Number
     */
    var mouseLastX = 0;

    /**
     * The Y coordinate of the mouse on the latest "down" or "drag" event.
     *
     * @type Number
     */
    var mouseLastY = 0;

    /**
     * Zooms the display in the given direction.
     *
     *
Only the sign of direction is used:

     *

     *
zoom in when direction > 0

     *
zoom out when direction <= 0

     *

     *
     *
The scaling is centered around point (x, y).

     *
     * @param {Number} direction The direction of the scaling operation
     * @param {Number} x The X coordinate of the scaling center
     * @param {Number} y The Y coordinate of the scaling center
     */
    function zoom(direction, x, y) {
        player.stop();
        display.viewPorts["player"].zoom(direction > 0 ? SCALE_FACTOR : 1 / SCALE_FACTOR, x, y);
    }

    /**
     * Rotate the display in the given direction.
     *
     *
Only the sign of direction is used:

     *

     *
rotate anticlockwise when direction > 0

     *
rotate clockwise when direction <= 0

     *

     *
     * @param {Number} direction The direction of the rotation
     */
    function rotate(direction) {
        player.stop();
        display.viewPorts["player"].rotate(direction > 0 ? ROTATE_STEP : -ROTATE_STEP);
    }

    /**
     * Show/hide the frame list.
     *
     *
The presentation stops when the frame list is showed,
     * and restarts when the frame list is hidden.

     */
    function toggleFrameList() {
        if (sozi.framelist.isVisible()) {
            sozi.framelist.hide();
            player.restart();
        } else {
            player.stop();
            sozi.framelist.show();
        }
    }

    function isPlayerEvent(evt) {
        return display.viewPorts["player"].contains(evt.clientX, evt.clientY);
    }

    /**
     * Event handler: mouse down.
     *
     *
When the left button is pressed, we register the current coordinates
     * in case the mouse will be dragged. Handler {@link sozi.actions-onMouseDrag} is set until
     * the button is released ({@link sozi.actions-onMouseUp}).

     *
     *
When the middle button is pressed, the table of contents is shown or hidden.

     *
     * @param {Event} evt The DOM event object
     */
    function onMouseDown(evt) {
        if (!isPlayerEvent(evt)) {
            return;
        }
        if (evt.button === DRAG_BUTTON) {
            document.documentElement.addEventListener("mousemove", onMouseDrag, false);
            mouseDragged = false;
            mouseLastX = evt.clientX;
            mouseLastY = evt.clientY;
        } else if (evt.button === TOC_BUTTON) {
            toggleFrameList();
        }
        evt.stopPropagation();
        evt.preventDefault();
    }

    /**
     * Event handler: mouse move.
     *
     *
If the left mouse button is down, then the mouse move is a drag action.
     * This method computes the displacement since the button was pressed or
     * since the last move, and updates the reference coordinates for the next move.

     *
     * @param {Event} evt The DOM event object
     */
    function onMouseDrag(evt) {
        if (!isPlayerEvent(evt)) {
            return;
        }
        player.stop();
        mouseDragged = true;
        sozi.events.fire("sozi.player.cleanup");
        display.viewPorts["player"].drag(evt.clientX - mouseLastX, evt.clientY - mouseLastY);
        mouseLastX = evt.clientX;
        mouseLastY = evt.clientY;
        evt.stopPropagation();
    }

    /**
     * Event handler: mouse up.
     *
     *
Releasing the left button removes the {@link sozi.actions-onMouseDrag} handler.

     *
     * @param {Event} evt The DOM event object
     */
    function onMouseUp(evt) {
        if (!isPlayerEvent(evt)) {
            return;
        }
        if (evt.button === DRAG_BUTTON) {
            document.documentElement.removeEventListener("mousemove", onMouseDrag, false);
        }
        evt.stopPropagation();
        evt.preventDefault();
    }

    /**
     * Event handler: context menu (i.e right click).
     *
     *
Right click goes one frame back.

     *
     *
There is no "click" event for the right mouse button and the menu
     * can't be disabled in {@link sozi.actions-onMouseDown}.

     *
     * @param {Event} evt The DOM event object
     */
    function onContextMenu(evt) {
        if (!isPlayerEvent(evt)) {
            return;
        }
        player.moveToPrevious();
        evt.stopPropagation();
        evt.preventDefault();
    }

    /**
     * Event handler: mouse click.
     *
     *
Left-click moves the presentation to the next frame.

     *
     *
No "click" event is generated for the middle button in Firefox.
     * See {@link sozi.actions-onMouseDown} for middle click handling.

     *
     *
Dragging the mouse produces a "click" event when the button is released.
     * If flag {@link sozi.actions-mouseDragged} was set by {@link sozi.actions-onMouseDrag},
     * then the click event is the result of a drag action.

     *
     * @param {Event} evt The DOM event object
     */
    function onClick(evt) {
        if (!isPlayerEvent(evt)) {
            return;
        }
        if (!mouseDragged && evt.button !== TOC_BUTTON) {
            player.moveToNext();
        }
        evt.stopPropagation();
        evt.preventDefault();
    }

    /**
     * Event handler: mouse wheel.
     *
     *
Rolling the mouse wheel stops the presentation and zooms the current display.

     *
     * FIXME shift key does not work in Opera
     *
     * @param {Event} evt The DOM event object
     */
    function onWheel(evt) {
        if (!isPlayerEvent(evt)) {
            return;
        }

        if (!evt) {
            evt = window.event;
        }

        var delta = 0;
        if (evt.wheelDelta) { // IE and Opera
            delta = evt.wheelDelta;
        }
        else if (evt.detail) { // Mozilla
            delta = -evt.detail;
        }

        if (delta !== 0) {
            if (evt.shiftKey) {
                rotate(delta);
            }
            else {
                zoom(delta, evt.clientX, evt.clientY);
            }
        }

        evt.stopPropagation();
        evt.preventDefault();
    }

    /**
     * Event handler: key press.
     *
     *
Keyboard handling is split into two methods:
     * {@link sozi.actions-onKeyPress} and {@link sozi.actions-onKeyDown}
     * in order to get the same behavior across browsers.

     *
     *
This method handles character keys "+", "-", "=", "F" and "T".

     *
     * @param {Event} evt The DOM event object
     */
    function onKeyPress(evt) {
        // Keys with modifiers are ignored
        if (evt.altKey || evt.ctrlKey || evt.metaKey) {
            return;
        }

        switch (evt.charCode || evt.keyCode) {
        case 43: // +
            zoom(1, window.innerWidth / 2, window.innerHeight / 2);
            break;
        case 45: // -
            zoom(-1, window.innerWidth / 2, window.innerHeight / 2);
            break;
        case 61: // =
            player.moveToCurrent();
            break;
        case 70: // F
        case 102: // f
            player.showAll();
            break;
        case 84: // T
        case 116: // t
            toggleFrameList();
            break;
        case 82: // R
            rotate(-1);
            break;
        case 114: // r
            rotate(1);
            break;
        default:
            return;
        }

        evt.stopPropagation();
        evt.preventDefault();
    }

    /**
     * Event handler: key down.
     *
     *
Keyboard handling is split into two methods:
     * {@link sozi.actions-onKeyPress} and {@link sozi.actions-onKeyDown}
     * in order to get the same behavior across browsers.

     *
     *
This method handles navigation keys (arrows, page up/down, home, end)
     * and the space and enter keys.

     *
     * @param {Event} evt The DOM event object
     */
    function onKeyDown(evt) {
        // Keys with modifiers are ignored
        if (evt.altKey || evt.ctrlKey || evt.metaKey) {
            return;
        }

        switch (evt.keyCode) {
        case 36: // Home
            player.moveToFirst();
            break;
        case 35: // End
            player.moveToLast();
            break;
        case 38: // Arrow up
            player.jumpToPrevious();
            break;
        case 33: // Page up
        case 37: // Arrow left
            player.moveToPrevious();
            break;
        case 40: // Arrow down
            player.jumpToNext();
            break;
        case 34: // Page down
        case 39: // Arrow right
        case 13: // Enter
        case 32: // Space
            player.moveToNext();
            break;
        default:
            return;
        }

        evt.stopPropagation();

        // In Chrome/Chromium, preventDefault() inhibits the "keypress" event
    }

    /**
     * Dummy event handler: stop event propagation.
     *
     * @param {Event} evt The DOM event object
     */
    function stopEvent(evt) {
        evt.stopPropagation();
    }

    /**
     * Event handler: document load.
     *
     *
This function sets up all other event handlers for the player.

     */
    function onDisplayReady() {
        // Prevent event propagation when clicking on a link
        // FIXME does not work in Firefox when the  is referenced through a <use>
        var links = document.getElementsByTagName("a");
        for (var i = 0; i < links.length; i += 1) {
            links[i].addEventListener("click", stopEvent, false);
            links[i].addEventListener("contextmenu", stopEvent, false);
        }

        // Mouse events are constrained to the player viewport
        // see isPlayerEvent()
        // TODO also use shift-click as an alternative for middle-click
        var svgRoot = document.documentElement;
        svgRoot.addEventListener("click", onClick, false);
        svgRoot.addEventListener("mousedown", onMouseDown, false);
        svgRoot.addEventListener("mouseup", onMouseUp, false);
        svgRoot.addEventListener("contextmenu", onContextMenu, false);
        svgRoot.addEventListener("DOMMouseScroll", onWheel, false); // Mozilla
        window.onmousewheel = onWheel;

        // Keyboard events are global to the SVG document
        svgRoot.addEventListener("keypress", onKeyPress, false);
        svgRoot.addEventListener("keydown", onKeyDown, false);
    }

    sozi.events.listen("sozi.display.ready", onDisplayReady);
});
<|endoftext|>


<commit_before>function Experience (opts) {
  for (keys in opts) {
    this[keys] = opts [keys];
  }
};

Experience.all = [];

Experience.prototype.toHtml = function(scriptTemplateId) {
  var template = Handlebars.compile($(scriptTemplateId).text());
  return template(this);;
};

Experience.loadAll = function(dataPassedIn) {
  Experience.all = dataPassedIn.map(function(ele) {
    return new Experience(ele);
  });
};

Experience.fetchAll = function () {
  if (localStorage.experienceFill){
    var jsData = JSON.parse(localStorage.experienceFill);
    Experience.loadAll(jsData);
  } else {
    $.ajax('data/experienceFill.json', {
      method:'GET',
      success: successHandler,
      error: errorHandler,
    });
    function successHandler(data) {
      console.log('success');
      Experience.loadAll(data);
      articleView.renderIndexPage();
      console.log(Experience.all);
      var dataString = JSON.stringify(data);
      localStorage.setItem('experience fill', dataString);
    };
    function errorHandler(error) {
      console.log('ERROR', error);
    };
  };
};
<commit_msg>fixing problmes<commit_after>function Experience (opts) {
  for (keys in opts) {
    this[keys] = opts [keys];
  }
};

Experience.all = [];

Experience.prototype.toHtml = function(scriptTemplateId) {
  var template = Handlebars.compile($(scriptTemplateId).text());
  return template(this);;
};

Experience.loadAll = function(dataPassedIn) {
  dataPassedIn.forEach(function(ele) {
    Experience.all.push(new Experience(ele));
  });
};

Experience.fetchAll = function () {
  if (localStorage.experienceFill){
    var jsData = JSON.parse(localStorage.experienceFill);
    Experience.loadAll(jsData);
  } else {
    $.ajax('data/experienceFill.json', {
      method:'GET',
      success: successHandler,
      error: errorHandler,
    });
    function successHandler(data) {
      console.log('success');
      Experience.loadAll(data);
      articleView.renderIndexPage();
      console.log(Experience.all);
      var dataString = JSON.stringify(data);
      localStorage.setItem('experience fill', dataString);
    };
    function errorHandler(error) {
      console.log('ERROR', error);
    };
  };
};
<|endoftext|>


<commit_before>/**
 * All Racials go in here.
 * You need to do this manually, usually an easy way to do this is by searching a racial or race on Wowhead. Here you can get the icon name by clicking the icon, copy the name of the spell and the ID is in the URL.
 * You can access these entries like other entries in the spells files by importing `common/SPELLS` and using the assigned property on the SPELLS object. Please try to avoid abbreviating properties.
 */

export default {
  // Blood Elf
  ARCANE_TORRENT_MANA: {
    id: 155145,
    name: 'Arcane Torrent',
    icon: 'spell_shadow_teleport',
  },
  ARCANE_TORRENT_RUNIC_POWER: {
    id: 50613,
    name: 'Arcane Torrent',
    icon: 'spell_shadow_teleport',
  },
  ARCANE_TORRENT_FOCUS: {
    id: 80483,
    name: 'Arcane Torrent',
    icon: 'spell_shadow_teleport',
  },
  ARCANE_TORRENT_ROGUE: {
    id: 25046,
    name: 'Arcane Torrent',
    icon: 'spell_shadow_teleport',
  },
  ARCANE_TORRENT_MONK: {
    id: 129597,
    name: 'Arcane Torrent',
    icon: 'spell_shadow_teleport',
  },
  ARCANE_TORRENT_DEMON_HUNTER: {
    id: 202719,
    name: 'Arcane Torrent',
    icon: 'spell_shadow_teleport',
  },
  // Troll
  BERSERKING: {
    id: 26297,
    name: 'Berserking',
    icon: 'racial_troll_berserk',
  },
  // Undead
  TOUCH_OF_THE_GRAVE: {
    id: 127802,
    name: 'Touch of the Grave',
    icon: 'spell_shadow_fingerofdeath',
  },
  WILL_OF_THE_FORSAKEN: {
    id: 7744,
    name: 'Will of the Forsaken',
    icon: 'spell_shadow_raisedead',
  },
  CANNIBALIZE: {
    id: 20577,
    name: 'Cannibalize',
    icon: 'ability_racial_cannibalize',
  },
  // Draenei
  GIFT_OF_THE_NAARU: {
    id: 121093,
    name: 'Gift of the Naaru',
    icon: 'spell_holy_holyprotection',
  },
  // Dwarf
  STONEFORM: {
    id: 20594,
    name: 'Stoneform',
    icon: 'spell_shadow_unholystrength',
  },
  // Gnome
  ESCAPE_ARTIST: {
    id: 20589,
    name: 'Escape Artist',
    icon: 'ability_rogue_trip',
  },
  // Human
  EVERY_MAN_FOR_HIMSELF: {
    id: 59752,
    name: 'Every Man for Himself',
    icon: 'spell_shadow_charm',
  },
  SHADOWMELD: {
    id: 58984,
    name: 'Shadowmeld',
    icon: 'ability_ambush',
  },
  // Pandaren
  QUAKING_PALM: {
    id: 107079,
    name: 'Quaking Palm',
    icon: 'pandarenracial_quiveringpain',
  },
  // Worgen
  DARKFLIGHT: {
    id: 68992,
    name: 'Darkflight',
    icon: 'ability_racial_darkflight',
  },
  TWO_FORMS: {
    id: 68996,
    name: 'Two Forms',
    icon: 'achievement_worganhead',
  },
  // Goblin
  ROCKET_JUMP: {
    id: 69070,
    name: 'Rocket Jump',
    icon: 'ability_racial_rocketjump',
  },
  ROCKET_BARRAGE: {
    id: 69041,
    name: 'Rocket Barrage',
    icon: 'inv_gizmo_rocketlauncher',
  },
  PACK_HOBGOBLIN: {
    id: 69046,
    name: 'Pack Hobgoblin',
    icon: 'ability_racial_packhobgoblin',
  },
  // Orc
  BLOOD_FURY_SPELL: {
    id: 33697,
    name: 'Blood Fury',
    icon: 'racial_orc_berserkerstrength',
  },
  BLOOD_FURY_PHYSICAL: {
    id: 20572,
    name: 'Blood Fury',
    icon: 'racial_orc_berserkerstrength',
  },
  // Tauren
  WAR_STOMP: {
    id: 20549,
    name: 'War Stomp',
    icon: 'ability_warstomp',
  },
  // High Mountain Tauren
  BULL_RUSH: {
    id: 255654,
    name: 'Bull Rush',
    icon: 'ability_racial_bullrush',
  },
  // Nightborne
  CANTRIPS: {
    id: 255661,
    name: 'Cantrips',
    icon: 'ability_racial_cantrips',
  },
  ARCANE_PULSE: {
    id: 260364,
    name: 'Arcane Pulse',
    icon: 'ability_racial_forceshield',
  },
  // Void Elf
  SPATIAL_RIFT_INITIAL: {
    id: 256948,
    name: 'Spatial Rift',
    icon: 'ability_racial_spatialrift',
  },
  SPATIAL_RIFT_TELEPORT: {
    id: 257040,
    name: 'Spatial Rift',
    icon: 'ability_racial_spatialrift',
  },
  ENTROPIC_EMBRACE_BUFF: {
    id: 256374,
    name: 'Entropic Embrace',
    icon: 'ability_racial_entropicembrace',
  },
  ENTROPIC_EMBRACE_DAMAGE: {
    id: 259756,
    name: 'Entropic Embrace',
    icon: 'ability_racial_entropicembrace',
  },
  // Lightforged Draenei
  LIGHTS_RECKONING: {
    id: 255652,
    name: 'Light\'s Reckoning',
    icon: 'ability_racial_finalverdict',
  },
  LIGHTS_JUDGMENT: {
    id: 255647,
    name: 'Light\'s Judgment',
    icon: 'ability_racial_orbitalstrike',
  },
  FORGE_OF_LIGHT: {
    id: 259930,
    name: 'Forge of Light',
    icon: 'ability_racial_forgeoflight',
  },
};
<commit_msg>add Mag'har Orc racial and buffs<commit_after>/**
 * All Racials go in here.
 * You need to do this manually, usually an easy way to do this is by searching a racial or race on Wowhead. Here you can get the icon name by clicking the icon, copy the name of the spell and the ID is in the URL.
 * You can access these entries like other entries in the spells files by importing `common/SPELLS` and using the assigned property on the SPELLS object. Please try to avoid abbreviating properties.
 */

export default {
  // Blood Elf
  ARCANE_TORRENT_MANA: {
    id: 155145,
    name: 'Arcane Torrent',
    icon: 'spell_shadow_teleport',
  },
  ARCANE_TORRENT_RUNIC_POWER: {
    id: 50613,
    name: 'Arcane Torrent',
    icon: 'spell_shadow_teleport',
  },
  ARCANE_TORRENT_FOCUS: {
    id: 80483,
    name: 'Arcane Torrent',
    icon: 'spell_shadow_teleport',
  },
  ARCANE_TORRENT_ROGUE: {
    id: 25046,
    name: 'Arcane Torrent',
    icon: 'spell_shadow_teleport',
  },
  ARCANE_TORRENT_MONK: {
    id: 129597,
    name: 'Arcane Torrent',
    icon: 'spell_shadow_teleport',
  },
  ARCANE_TORRENT_DEMON_HUNTER: {
    id: 202719,
    name: 'Arcane Torrent',
    icon: 'spell_shadow_teleport',
  },
  // Troll
  BERSERKING: {
    id: 26297,
    name: 'Berserking',
    icon: 'racial_troll_berserk',
  },
  // Undead
  TOUCH_OF_THE_GRAVE: {
    id: 127802,
    name: 'Touch of the Grave',
    icon: 'spell_shadow_fingerofdeath',
  },
  WILL_OF_THE_FORSAKEN: {
    id: 7744,
    name: 'Will of the Forsaken',
    icon: 'spell_shadow_raisedead',
  },
  CANNIBALIZE: {
    id: 20577,
    name: 'Cannibalize',
    icon: 'ability_racial_cannibalize',
  },
  // Draenei
  GIFT_OF_THE_NAARU: {
    id: 121093,
    name: 'Gift of the Naaru',
    icon: 'spell_holy_holyprotection',
  },
  // Dwarf
  STONEFORM: {
    id: 20594,
    name: 'Stoneform',
    icon: 'spell_shadow_unholystrength',
  },
  // Gnome
  ESCAPE_ARTIST: {
    id: 20589,
    name: 'Escape Artist',
    icon: 'ability_rogue_trip',
  },
  // Human
  EVERY_MAN_FOR_HIMSELF: {
    id: 59752,
    name: 'Every Man for Himself',
    icon: 'spell_shadow_charm',
  },
  SHADOWMELD: {
    id: 58984,
    name: 'Shadowmeld',
    icon: 'ability_ambush',
  },
  // Pandaren
  QUAKING_PALM: {
    id: 107079,
    name: 'Quaking Palm',
    icon: 'pandarenracial_quiveringpain',
  },
  // Worgen
  DARKFLIGHT: {
    id: 68992,
    name: 'Darkflight',
    icon: 'ability_racial_darkflight',
  },
  TWO_FORMS: {
    id: 68996,
    name: 'Two Forms',
    icon: 'achievement_worganhead',
  },
  // Goblin
  ROCKET_JUMP: {
    id: 69070,
    name: 'Rocket Jump',
    icon: 'ability_racial_rocketjump',
  },
  ROCKET_BARRAGE: {
    id: 69041,
    name: 'Rocket Barrage',
    icon: 'inv_gizmo_rocketlauncher',
  },
  PACK_HOBGOBLIN: {
    id: 69046,
    name: 'Pack Hobgoblin',
    icon: 'ability_racial_packhobgoblin',
  },
  // Orc
  BLOOD_FURY_SPELL: {
    id: 33697,
    name: 'Blood Fury',
    icon: 'racial_orc_berserkerstrength',
  },
  BLOOD_FURY_PHYSICAL: {
    id: 20572,
    name: 'Blood Fury',
    icon: 'racial_orc_berserkerstrength',
  },
  // Tauren
  WAR_STOMP: {
    id: 20549,
    name: 'War Stomp',
    icon: 'ability_warstomp',
  },
  // High Mountain Tauren
  BULL_RUSH: {
    id: 255654,
    name: 'Bull Rush',
    icon: 'ability_racial_bullrush',
  },
  // Nightborne
  CANTRIPS: {
    id: 255661,
    name: 'Cantrips',
    icon: 'ability_racial_cantrips',
  },
  ARCANE_PULSE: {
    id: 260364,
    name: 'Arcane Pulse',
    icon: 'ability_racial_forceshield',
  },
  // Void Elf
  SPATIAL_RIFT_INITIAL: {
    id: 256948,
    name: 'Spatial Rift',
    icon: 'ability_racial_spatialrift',
  },
  SPATIAL_RIFT_TELEPORT: {
    id: 257040,
    name: 'Spatial Rift',
    icon: 'ability_racial_spatialrift',
  },
  ENTROPIC_EMBRACE_BUFF: {
    id: 256374,
    name: 'Entropic Embrace',
    icon: 'ability_racial_entropicembrace',
  },
  ENTROPIC_EMBRACE_DAMAGE: {
    id: 259756,
    name: 'Entropic Embrace',
    icon: 'ability_racial_entropicembrace',
  },
  // Lightforged Draenei
  LIGHTS_RECKONING: {
    id: 255652,
    name: 'Light\'s Reckoning',
    icon: 'ability_racial_finalverdict',
  },
  LIGHTS_JUDGMENT: {
    id: 255647,
    name: 'Light\'s Judgment',
    icon: 'ability_racial_orbitalstrike',
  },
  FORGE_OF_LIGHT: {
    id: 259930,
    name: 'Forge of Light',
    icon: 'ability_racial_forgeoflight',
  },
  // Mag'har Orc
  ANCESTRAL_CALL: {
    id: 274738,
    name: 'Ancestral Call',
    icon: 'ability_racial_ancestralcall',
  },
  RICTUS_OF_THE_LAUGHING_SKULL: { // Crit Buff
    id: 274739,
    name: 'Rictus of the Laughing Skull',
    icon: 'ability_racial_ancestralcall',
  },
  ZEAL_OF_THE_BURNING_BLADE: { // Haste Buff
    id: 274740,
    name: 'Zeal of the Burning Blade',
    icon: 'ability_racial_ancestralcall',
  },
  FEROCITY_OF_THE_FROSTWOLF: { // Mastery Buff
    id: 274741,
    name: 'Ferocity of the Frostwolf',
    icon: 'ability_racial_ancestralcall',
  },
  MIGHT_OF_THE_BLACKROCK: { // Versatility Buff
    id: 274742,
    name: 'Might of the Blackrock',
    icon: 'ability_racial_ancestralcall',
  },
};
<|endoftext|>


<commit_before>module.exports = CacheStore;

var _ = require('lodash');

function CacheStore(store) {
    this.store = store;
    // Only stores sets that have been loaded
    // Contains map of key -> bool, where bool isn't important
    this.cache = Object.create(null);
}

CacheStore.prototype.addKey = function addKey(vnode, key, done) {
    if (!_.has(this.cache, vnode)) {
        // Hasn't been fully loaded into cache
        return this.store.addKey(vnode, key, done);
    }
    var set = this.cache[vnode];
    if (_.has(set, key)) {
        return done();
    }
    this.store.addKey(vnode, key, function(err) {
        if (!err) {
            set[key] = true;
        }
        done(err);
    });
};

CacheStore.prototype.removeKey = function removeKey(vnode, key, done) {
    // Set is loaded, key is not present.
    // TODO if you want to get really fancy, store a tombstone on remove and check that too.
    if (_.has(this.cache, vnode) && !_.has(this.cache[vnode], key)) {
        return done();
    }
    var set = this.cache[vnode];
    this.store.removeKey(vnode, key, function(err) {
        if (!err && set) {
            delete set[key];
        }
        done(err);
    });
};

CacheStore.prototype.loadKeys = function loadKeys(vnode, done) {
    var self = this;
    if (_.has(this.cache, vnode)) {
        return setImmediate(function() {
            done(null, Object.keys(self.cache[vnode] || {}));
        });
    }
    this.store.loadKeys(vnode, function(err, keys) {
        if (!err) {
            var set = self.cache[vnode] = Object.create(null);
            keys.forEach(function(key) {
                set[key] = true;
            });
        }
        done(err, keys);
    });
};

CacheStore.prototype.releaseFromCache = function releaseFromCache(vnode) {
    delete this.cache[vnode];
};
<commit_msg>wrap whole thing in setimmediate<commit_after>module.exports = CacheStore;

var _ = require('lodash');

function CacheStore(store) {
    this.store = store;
    // Only stores sets that have been loaded
    // Contains map of key -> bool, where bool isn't important
    this.cache = Object.create(null);
}

CacheStore.prototype.addKey = function addKey(vnode, key, done) {
    if (!_.has(this.cache, vnode)) {
        // Hasn't been fully loaded into cache
        return this.store.addKey(vnode, key, done);
    }
    var set = this.cache[vnode];
    if (_.has(set, key)) {
        return done();
    }
    this.store.addKey(vnode, key, function(err) {
        if (!err) {
            set[key] = true;
        }
        done(err);
    });
};

CacheStore.prototype.removeKey = function removeKey(vnode, key, done) {
    // Set is loaded, key is not present.
    // TODO if you want to get really fancy, store a tombstone on remove and check that too.
    if (_.has(this.cache, vnode) && !_.has(this.cache[vnode], key)) {
        return done();
    }
    var set = this.cache[vnode];
    this.store.removeKey(vnode, key, function(err) {
        if (!err && set) {
            delete set[key];
        }
        done(err);
    });
};

CacheStore.prototype.loadKeys = function loadKeys(vnode, done) {
    var self = this;
    setImmediate(function() {
        if (_.has(self.cache, vnode)) {
            return done(null, Object.keys(self.cache[vnode]));
        }
        self.store.loadKeys(vnode, function (err, keys) {
            if (!err) {
                var set = self.cache[vnode] = Object.create(null);
                keys.forEach(function (key) {
                    set[key] = true;
                });
            }
            done(err, keys);
        });
    });
};

CacheStore.prototype.releaseFromCache = function releaseFromCache(vnode) {
    delete this.cache[vnode];
};
<|endoftext|>


<commit_before>'use strict';

const fs = require('fs');
const test = require('supertape');
const fixture = {
    get: require(`${__dirname}/fixture/get`),
    getRaw: require(`${__dirname}/fixture/get-raw`),
};

const stub = require('@cloudcmd/stub');
const mockRequire = require('mock-require');
const {reRequire} = mockRequire;

const restafary = require('..');

const serveOnce = require('serve-once');
const {request} = serveOnce(restafary, {
    root: __dirname,
});

test('restafary: path traversal beyond root', async (t) => {
    const root = '/tmp';
    const {body} = await request.get('/fs..%2f..%2fetc/passwd', {
        options: {
            root,
        },
    });

    t.equal(body, 'Path /etc/passwd beyond root /tmp!', 'should return beyond root message');
    t.end();
});

test('restafary: path traversal', async (t) => {
    const {body} = await request.get('/fs/bin', {
        options: {
            root: '/',
        },
    });

    const fn = () => JSON.parse(body);

    t.doesNotThrow(fn, 'should not throw');
    t.end();
});

test('restafary: path traversal, not default root', async (t) => {
    const {body} = await request.get('/fs/local', {
        options: {
            root: '/usr',
        },
    });
    const fn = () => JSON.parse(body);

    t.doesNotThrow(fn, 'should not throw');
    t.end();
});

test('restafary: path traversal: "."', async (t) => {
    const notRoot = (_) => !/^\./.test(_);
    const path = fs.readdirSync(__dirname)
        .filter(notRoot)
        .pop();

    const {status} = await request.get(`/fs/${path}`);

    t.equal(status, 200, 'status code should be OK');
    t.end();
});

test('restafary: get: "raw": status', async (t) => {
    const {status} = await request.get('/fs/fixture/get-raw?raw');

    t.equal(status, 200, 'status code should be OK');
    t.end();
});

test('restafary: get: "raw": body: name', async (t) => {
    const {body} = await request.get('/fs/fixture/get-raw?raw');

    t.deepEqual(fixture.getRaw.name, JSON.parse(body).name, 'should return raw data');
    t.end();
});

test('restafary: get: "raw": body: size', async (t) => {
    const {body} = await request.get('/fs/fixture/get-raw?raw');

    t.deepEqual(fixture.getRaw.size, JSON.parse(body).size, 'should return raw data');
    t.end();
});

test('restafary: get: "raw": body: mode', async (t) => {
    const {body} = await request.get('/fs/fixture/get-raw?raw');

    t.deepEqual(fixture.getRaw.mode, JSON.parse(body).mode, 'should return raw data');
    t.end();
});

test('restafary: get: status', async (t) => {
    const {status} = await request.get('/fs/fixture/get');

    t.equal(status, 200, 'status code should be OK');
    t.end();
});

test('restafary: get: body: name', async (t) => {
    const {body} = await request.get('/fs/fixture/get', {
        type: 'json',
    });

    t.deepEqual(fixture.get.name, body.name, 'should return data');
    t.end();
});

test('restafary: get: body: size', async (t) => {
    const {body} = await request.get('/fs/fixture/get', {
        type: 'json',
    });

    t.deepEqual(fixture.get.size, body.size, 'should return data');
    t.end();
});

test('restafary: get: body: mode', async (t) => {
    const {body} = await request.get('/fs/fixture/get', {
        type: 'json',
    });

    t.deepEqual(fixture.get.mode, body.mode, 'should return data');
    t.end();
});

test('restafary: get: sort by name', async (t) => {
    const expected = {
        path: './',
        files: [{
            name: '.readify.js',
            size: '3.46kb',
            date: '12.01.2017',
            owner: 'root',
            mode: 'rw- rw- r--',
        }, {
            name: 'readdir.js',
            size: '1.59kb',
            date: '12.01.2017',
            owner: 'root',
            mode: 'rw- rw- r--',
        }],
    };

    const read = stub().returns(expected);

    mockRequire('flop', {
        read,
    });

    reRequire('../server/fs/get');

    const restafary = reRequire('..');
    const {request} = serveOnce(restafary, {
        root: '/',
    });

    await request.get('/fs/bin?sort=name');

    const order = 'asc';
    const sort = 'name';

    t.calledWith(read, ['/bin', {sort, order}], 'should call readify with sort "name"');
    t.end();
});

test('restafary: get: sort by size', async (t) => {
    const expected = {
        path: '',
        files: [],
    };

    const read = stub().returns(expected);

    mockRequire('flop', {
        read,
    });

    reRequire('../server/fs/get');

    const restafary = reRequire('..');
    const {request} = serveOnce(restafary, {
        root: '/',
    });

    await request.get('/fs/bin?sort=size');

    const order = 'asc';
    const sort = 'size';

    t.calledWith(read, ['/bin', {sort, order}], 'should call readify with sort "size"');
    t.end();
});

test('restafary: get: sort by order', async (t) => {
    const expected = {
        path: '',
        files: [],
    };

    const read = stub().returns(expected);

    mockRequire('flop', {
        read,
    });

    reRequire('../server/fs/get');

    const restafary = reRequire('..');
    const {request} = serveOnce(restafary, {
        root: '/',
    });

    await request.get('/fs/bin?order=desc&sort=time');

    const sort = 'time';
    const order = 'desc';

    t.calledWith(read, ['/bin', {sort, order}], 'should call readify with sort and order');
    t.end();
});

<commit_msg>test(restafary) doesNotThrow -> tryCatch<commit_after>'use strict';

const tryCatch = require('try-catch');

const fs = require('fs');
const test = require('supertape');
const fixture = {
    get: require(`${__dirname}/fixture/get`),
    getRaw: require(`${__dirname}/fixture/get-raw`),
};

const stub = require('@cloudcmd/stub');
const mockRequire = require('mock-require');
const {reRequire} = mockRequire;

const restafary = require('..');

const serveOnce = require('serve-once');
const {request} = serveOnce(restafary, {
    root: __dirname,
});

test('restafary: path traversal beyond root', async (t) => {
    const root = '/tmp';
    const {body} = await request.get('/fs..%2f..%2fetc/passwd', {
        options: {
            root,
        },
    });

    t.equal(body, 'Path /etc/passwd beyond root /tmp!', 'should return beyond root message');
    t.end();
});

test('restafary: path traversal', async (t) => {
    const {body} = await request.get('/fs/bin', {
        options: {
            root: '/',
        },
    });

    const [error] = tryCatch(JSON.parse, body);

    t.notOk(error, 'should not throw');
    t.end();
});

test('restafary: path traversal, not default root', async (t) => {
    const {body} = await request.get('/fs/local', {
        options: {
            root: '/usr',
        },
    });
    const [error] = tryCatch(JSON.parse, body);

    t.notOk(error, 'should not throw');
    t.end();
});

test('restafary: path traversal: "."', async (t) => {
    const notRoot = (_) => !/^\./.test(_);
    const path = fs.readdirSync(__dirname)
        .filter(notRoot)
        .pop();

    const {status} = await request.get(`/fs/${path}`);

    t.equal(status, 200, 'status code should be OK');
    t.end();
});

test('restafary: get: "raw": status', async (t) => {
    const {status} = await request.get('/fs/fixture/get-raw?raw');

    t.equal(status, 200, 'status code should be OK');
    t.end();
});

test('restafary: get: "raw": body: name', async (t) => {
    const {body} = await request.get('/fs/fixture/get-raw?raw');

    t.deepEqual(fixture.getRaw.name, JSON.parse(body).name, 'should return raw data');
    t.end();
});

test('restafary: get: "raw": body: size', async (t) => {
    const {body} = await request.get('/fs/fixture/get-raw?raw');

    t.deepEqual(fixture.getRaw.size, JSON.parse(body).size, 'should return raw data');
    t.end();
});

test('restafary: get: "raw": body: mode', async (t) => {
    const {body} = await request.get('/fs/fixture/get-raw?raw');

    t.deepEqual(fixture.getRaw.mode, JSON.parse(body).mode, 'should return raw data');
    t.end();
});

test('restafary: get: status', async (t) => {
    const {status} = await request.get('/fs/fixture/get');

    t.equal(status, 200, 'status code should be OK');
    t.end();
});

test('restafary: get: body: name', async (t) => {
    const {body} = await request.get('/fs/fixture/get', {
        type: 'json',
    });

    t.deepEqual(fixture.get.name, body.name, 'should return data');
    t.end();
});

test('restafary: get: body: size', async (t) => {
    const {body} = await request.get('/fs/fixture/get', {
        type: 'json',
    });

    t.deepEqual(fixture.get.size, body.size, 'should return data');
    t.end();
});

test('restafary: get: body: mode', async (t) => {
    const {body} = await request.get('/fs/fixture/get', {
        type: 'json',
    });

    t.deepEqual(fixture.get.mode, body.mode, 'should return data');
    t.end();
});

test('restafary: get: sort by name', async (t) => {
    const expected = {
        path: './',
        files: [{
            name: '.readify.js',
            size: '3.46kb',
            date: '12.01.2017',
            owner: 'root',
            mode: 'rw- rw- r--',
        }, {
            name: 'readdir.js',
            size: '1.59kb',
            date: '12.01.2017',
            owner: 'root',
            mode: 'rw- rw- r--',
        }],
    };

    const read = stub().returns(expected);

    mockRequire('flop', {
        read,
    });

    reRequire('../server/fs/get');

    const restafary = reRequire('..');
    const {request} = serveOnce(restafary, {
        root: '/',
    });

    await request.get('/fs/bin?sort=name');

    const order = 'asc';
    const sort = 'name';

    t.calledWith(read, ['/bin', {sort, order}], 'should call readify with sort "name"');
    t.end();
});

test('restafary: get: sort by size', async (t) => {
    const expected = {
        path: '',
        files: [],
    };

    const read = stub().returns(expected);

    mockRequire('flop', {
        read,
    });

    reRequire('../server/fs/get');

    const restafary = reRequire('..');
    const {request} = serveOnce(restafary, {
        root: '/',
    });

    await request.get('/fs/bin?sort=size');

    const order = 'asc';
    const sort = 'size';

    t.calledWith(read, ['/bin', {sort, order}], 'should call readify with sort "size"');
    t.end();
});

test('restafary: get: sort by order', async (t) => {
    const expected = {
        path: '',
        files: [],
    };

    const read = stub().returns(expected);

    mockRequire('flop', {
        read,
    });

    reRequire('../server/fs/get');

    const restafary = reRequire('..');
    const {request} = serveOnce(restafary, {
        root: '/',
    });

    await request.get('/fs/bin?order=desc&sort=time');

    const sort = 'time';
    const order = 'desc';

    t.calledWith(read, ['/bin', {sort, order}], 'should call readify with sort and order');
    t.end();
});

<|endoftext|>


<commit_before>'use strict';

var isOldIE = typeof navigator !== 'undefined' && /msie [6-9]\\b/.test(navigator.userAgent.toLowerCase());
function createInjector(context) {
  return function (id, style) {
    return addStyle(id, style);
  };
}
var HEAD;
var styles = {};

function addStyle(id, css) {
  var group = isOldIE ? css.media || 'default' : id;
  var style = styles[group] || (styles[group] = {
    ids: new Set(),
    styles: []
  });

  if (!style.ids.has(id)) {
    style.ids.add(id);
    var code = css.source;

    if (css.map) {
      // https://developer.chrome.com/devtools/docs/javascript-debugging
      // this makes source maps inside style tags work properly in Chrome
      code += '\n/*# sourceURL=' + css.map.sources[0] + ' */'; // http://stackoverflow.com/a/26603875

      code += '\n/*# sourceMappingURL=data:application/json;base64,' + btoa(unescape(encodeURIComponent(JSON.stringify(css.map)))) + ' */';
    }

    if (!style.element && typeof document !== 'undefined') {
      style.element = document.createElement('style');
      style.element.type = 'text/css';
      if (css.media) style.element.setAttribute('media', css.media);

      if (HEAD === undefined) {
        HEAD = document.head || document.getElementsByTagName('head')[0];
      }

      HEAD.appendChild(style.element);
    }

    if (style.element && 'styleSheet' in style.element) {
      style.styles.push(code);
      style.element.styleSheet.cssText = style.styles.filter(Boolean).join('\n');
    } else if (typeof document !== 'undefined') {
      var index = style.ids.size - 1;
      var textNode = document.createTextNode(code);
      var nodes = style.element.childNodes;
      if (nodes[index]) style.element.removeChild(nodes[index]);
      if (nodes.length) style.element.insertBefore(textNode, nodes[index]);else style.element.appendChild(textNode);
    }
  }
}

exports.createInjector = createInjector;<commit_msg>fix(ssr): revert to correct export for style-injector<commit_after>'use strict';

var isOldIE = typeof navigator !== 'undefined' && /msie [6-9]\\b/.test(navigator.userAgent.toLowerCase());
function createInjector(context) {
  return function (id, style) {
    return addStyle(id, style);
  };
}
var HEAD;
var styles = {};

function addStyle(id, css) {
  var group = isOldIE ? css.media || 'default' : id;
  var style = styles[group] || (styles[group] = {
    ids: new Set(),
    styles: []
  });

  if (!style.ids.has(id)) {
    style.ids.add(id);
    var code = css.source;

    if (css.map) {
      // https://developer.chrome.com/devtools/docs/javascript-debugging
      // this makes source maps inside style tags work properly in Chrome
      code += '\n/*# sourceURL=' + css.map.sources[0] + ' */'; // http://stackoverflow.com/a/26603875

      code += '\n/*# sourceMappingURL=data:application/json;base64,' + btoa(unescape(encodeURIComponent(JSON.stringify(css.map)))) + ' */';
    }

    if (!style.element && typeof document !== 'undefined') {
      style.element = document.createElement('style');
      style.element.type = 'text/css';
      if (css.media) style.element.setAttribute('media', css.media);

      if (HEAD === undefined) {
        HEAD = document.head || document.getElementsByTagName('head')[0];
      }

      HEAD.appendChild(style.element);
    }

    if (style.element && 'styleSheet' in style.element) {
      style.styles.push(code);
      style.element.styleSheet.cssText = style.styles.filter(Boolean).join('\n');
    } else if (typeof document !== 'undefined') {
      var index = style.ids.size - 1;
      var textNode = document.createTextNode(code);
      var nodes = style.element.childNodes;
      if (nodes[index]) style.element.removeChild(nodes[index]);
      if (nodes.length) style.element.insertBefore(textNode, nodes[index]);else style.element.appendChild(textNode);
    }
  }
}

module.exports = createInjector;<|endoftext|>


<commit_before>'use strict'

var processNodes = require('./process_nodes')
var bindKeys = require('./bind_keys')
var keyMap = require('./key_map')

var hasBindingsKey = keyMap.hasBindings
var hasDefinitionKey = keyMap.hasDefinition
var markerKey = keyMap.marker
var replaceAttributeKey = keyMap.replaceAttribute
var isBoundToParentKey = keyMap.isBoundToParent

// Node names which should have value replaced.
var replaceValue = [ 'INPUT', 'TEXTAREA', 'PROGRESS' ]

// Input types which use the "checked" attribute.
var replaceChecked = [ 'checkbox', 'radio' ]

var useCommentNode = false
var retainElement = '__retain__' +
  ('00000000' + Math.floor(Math.random() * Math.pow(2, 32)).toString(16))
  .slice(-8)

// Upgrade to Symbol if possible, it guarantees uniqueness.
if (typeof Symbol === 'function') retainElement = Symbol(retainElement)

// Symbol for retaining an element instead of removing it.
bindKeys.retainElement = retainElement
Object.defineProperty(simulacra, 'retainElement', {
  enumerable: true, value: retainElement
})

// Option to use comment nodes.
processNodes.useCommentNode = useCommentNode
Object.defineProperty(simulacra, 'useCommentNode', {
  get: function () { return useCommentNode },
  set: function (value) {
    processNodes.useCommentNode = useCommentNode = value
  },
  enumerable: true
})

// Main export.
module.exports = simulacra

/**
 * Bind an object to the DOM.
 *
 * @param {Object} obj
 * @param {Object} def
 * @return {Node}
 */
function simulacra (obj, def) {
  var document = this ? this.document : window.document
  var Node = this ? this.Node : window.Node
  var node, query, path = []

  if (typeof obj !== 'object' || Array.isArray(obj))
    throw new TypeError('First argument must be a singular object.')

  if (obj[hasBindingsKey])
    throw new Error('Can not bind an object that is already bound.')

  if (!Array.isArray(def))
    throw new TypeError('Second argument must be an array.')

  if (typeof def[0] === 'string') {
    query = def[0]
    def[0] = document.querySelector(query)
    if (!def[0]) throw new Error(
      'Top-level node "' + query + '" could not be found in the document.')
  }
  else if (!(def[0] instanceof Node)) throw new TypeError(
    'The first position of top-level must be a Node or a CSS selector string.')

  ensureNodes(this, def[0], def[1])

  node = processNodes(this, def[0].cloneNode(true), def[1])

  // Assign internal binding key to note that the object is already bound.
  Object.defineProperty(obj, hasBindingsKey, { value: true })

  // Assign root object.
  path.root = obj

  bindKeys(this, obj, def[1], node, path)

  return node
}

/**
 * Internal function to mutate string selectors into Nodes and validate that
 * they are allowed.
 *
 * @param {Object} scope
 * @param {Node} parentNode
 * @param {Object} def
 */
function ensureNodes (scope, parentNode, def) {
  var Element = scope ? scope.Element : window.Element
  var adjacentNodes = []
  var i, j, key, query, branch, boundNode, ancestorNode

  if (typeof def !== 'object') throw new TypeError(
    'The second position must be an object.')

  for (key in def) {
    if (!Array.isArray(def[key]))
      def[key] = [ def[key] ]

    branch = def[key]

    // Internal value used while processing nodes.
    Object.defineProperty(branch, markerKey, { value: null, writable: true })

    if (typeof branch[0] === 'string') {
      query = branch[0]

      // May need to get the node above the parent, in case of binding to
      // the parent node.
      ancestorNode = parentNode.parentNode || parentNode

      branch[0] = ancestorNode.querySelector(query)
      if (!branch[0]) throw new Error(
        'The element for selector "' + query + '" was not found.')
    }
    else if (!(branch[0] instanceof Element))
      throw new TypeError('The first position on key "' + key +
        '" must be a DOM element or a CSS selector string.')

    boundNode = branch[0]

    if (typeof branch[1] === 'object' && branch[1] !== null) {
      Object.defineProperty(branch, hasDefinitionKey, { value: true })
      if (branch[2] && typeof branch[2] !== 'function')
        throw new TypeError('The third position on key "' + key +
          '" must be a function.')
    }
    else if (branch[1] && typeof branch[1] !== 'function')
      throw new TypeError('The second position on key "' + key +
        '" must be an object or a function.')

    // Special case for binding to parent node.
    if (parentNode === boundNode) {
      Object.defineProperty(branch, isBoundToParentKey, { value: true })
      if (branch[hasDefinitionKey]) ensureNodes(scope, boundNode, branch[1])
      else if (typeof branch[1] !== 'function')
        console.warn( // eslint-disable-line
          'A change function was not defined on the key "' + key + '".')
      continue
    }
    else adjacentNodes.push([ key, boundNode ])

    if (!parentNode.contains(boundNode))
      throw new Error('The bound DOM element must be either ' +
        'contained in or equal to the element in its parent binding.')

    if (branch[hasDefinitionKey]) {
      ensureNodes(scope, boundNode, branch[1])
      continue
    }

    Object.defineProperty(branch, replaceAttributeKey, {
      value: ~replaceValue.indexOf(boundNode.nodeName) ?
        ~replaceChecked.indexOf(boundNode.type) ?
        'checked' : 'value' : 'textContent'
    })
  }

  // Need to invalidate containment in adjacent nodes, after the adjacent
  // nodes are found.
  for (key in def) {
    boundNode = def[key][0]
    for (i = 0, j = adjacentNodes.length; i < j; i++)
      if (adjacentNodes[i][1].contains(boundNode) &&
        adjacentNodes[i][1] !== boundNode)
        throw new Error(
          'The element for key "' + key + '" is contained in the ' +
          'element for the adjacent key "' + adjacentNodes[i][0] + '".')
  }
}
<commit_msg>remove whitespace<commit_after>'use strict'

var processNodes = require('./process_nodes')
var bindKeys = require('./bind_keys')
var keyMap = require('./key_map')

var hasBindingsKey = keyMap.hasBindings
var hasDefinitionKey = keyMap.hasDefinition
var markerKey = keyMap.marker
var replaceAttributeKey = keyMap.replaceAttribute
var isBoundToParentKey = keyMap.isBoundToParent

// Node names which should have value replaced.
var replaceValue = [ 'INPUT', 'TEXTAREA', 'PROGRESS' ]

// Input types which use the "checked" attribute.
var replaceChecked = [ 'checkbox', 'radio' ]

var useCommentNode = false
var retainElement = '__retain__' +
  ('00000000' + Math.floor(Math.random() * Math.pow(2, 32)).toString(16))
  .slice(-8)

// Upgrade to Symbol if possible, it guarantees uniqueness.
if (typeof Symbol === 'function') retainElement = Symbol(retainElement)

// Symbol for retaining an element instead of removing it.
bindKeys.retainElement = retainElement
Object.defineProperty(simulacra, 'retainElement', {
  enumerable: true, value: retainElement
})

// Option to use comment nodes.
processNodes.useCommentNode = useCommentNode
Object.defineProperty(simulacra, 'useCommentNode', {
  get: function () { return useCommentNode },
  set: function (value) {
    processNodes.useCommentNode = useCommentNode = value
  },
  enumerable: true
})

// Main export.
module.exports = simulacra

/**
 * Bind an object to the DOM.
 *
 * @param {Object} obj
 * @param {Object} def
 * @return {Node}
 */
function simulacra (obj, def) {
  var document = this ? this.document : window.document
  var Node = this ? this.Node : window.Node
  var node, query, path = []

  if (typeof obj !== 'object' || Array.isArray(obj))
    throw new TypeError('First argument must be a singular object.')

  if (obj[hasBindingsKey])
    throw new Error('Can not bind an object that is already bound.')

  if (!Array.isArray(def))
    throw new TypeError('Second argument must be an array.')

  if (typeof def[0] === 'string') {
    query = def[0]
    def[0] = document.querySelector(query)
    if (!def[0]) throw new Error(
      'Top-level node "' + query + '" could not be found in the document.')
  }
  else if (!(def[0] instanceof Node)) throw new TypeError(
    'The first position of top-level must be a Node or a CSS selector string.')

  ensureNodes(this, def[0], def[1])

  node = processNodes(this, def[0].cloneNode(true), def[1])

  // Assign internal binding key to note that the object is already bound.
  Object.defineProperty(obj, hasBindingsKey, { value: true })

  // Assign root object.
  path.root = obj

  bindKeys(this, obj, def[1], node, path)

  return node
}

/**
 * Internal function to mutate string selectors into Nodes and validate that
 * they are allowed.
 *
 * @param {Object} scope
 * @param {Node} parentNode
 * @param {Object} def
 */
function ensureNodes (scope, parentNode, def) {
  var Element = scope ? scope.Element : window.Element
  var adjacentNodes = []
  var i, j, key, query, branch, boundNode, ancestorNode

  if (typeof def !== 'object') throw new TypeError(
    'The second position must be an object.')

  for (key in def) {
    if (!Array.isArray(def[key]))
      def[key] = [ def[key] ]

    branch = def[key]

    // Internal value used while processing nodes.
    Object.defineProperty(branch, markerKey, { value: null, writable: true })

    if (typeof branch[0] === 'string') {
      query = branch[0]

      // May need to get the node above the parent, in case of binding to
      // the parent node.
      ancestorNode = parentNode.parentNode || parentNode

      branch[0] = ancestorNode.querySelector(query)
      if (!branch[0]) throw new Error(
        'The element for selector "' + query + '" was not found.')
    }
    else if (!(branch[0] instanceof Element))
      throw new TypeError('The first position on key "' + key +
        '" must be a DOM element or a CSS selector string.')

    boundNode = branch[0]

    if (typeof branch[1] === 'object' && branch[1] !== null) {
      Object.defineProperty(branch, hasDefinitionKey, { value: true })
      if (branch[2] && typeof branch[2] !== 'function')
        throw new TypeError('The third position on key "' + key +
          '" must be a function.')
    }
    else if (branch[1] && typeof branch[1] !== 'function')
      throw new TypeError('The second position on key "' + key +
        '" must be an object or a function.')

    // Special case for binding to parent node.
    if (parentNode === boundNode) {
      Object.defineProperty(branch, isBoundToParentKey, { value: true })
      if (branch[hasDefinitionKey]) ensureNodes(scope, boundNode, branch[1])
      else if (typeof branch[1] !== 'function')
        console.warn( // eslint-disable-line
          'A change function was not defined on the key "' + key + '".')
      continue
    }
    else adjacentNodes.push([ key, boundNode ])

    if (!parentNode.contains(boundNode))
      throw new Error('The bound DOM element must be either ' +
        'contained in or equal to the element in its parent binding.')

    if (branch[hasDefinitionKey]) {
      ensureNodes(scope, boundNode, branch[1])
      continue
    }

    Object.defineProperty(branch, replaceAttributeKey, {
      value: ~replaceValue.indexOf(boundNode.nodeName) ?
        ~replaceChecked.indexOf(boundNode.type) ?
        'checked' : 'value' : 'textContent'
    })
  }

  // Need to invalidate containment in adjacent nodes, after the adjacent
  // nodes are found.
  for (key in def) {
    boundNode = def[key][0]
    for (i = 0, j = adjacentNodes.length; i < j; i++)
      if (adjacentNodes[i][1].contains(boundNode) &&
        adjacentNodes[i][1] !== boundNode)
        throw new Error(
          'The element for key "' + key + '" is contained in the ' +
          'element for the adjacent key "' + adjacentNodes[i][0] + '".')
  }
}
<|endoftext|>


<commit_before>// Because dangerouslySetInnerHTML prop is required only if the string contains HTML tags

module.exports = {
	hasHTMLTags : function(s) {
		const doc = new DOMParser().parseFromString(s, 'text/html');
		const childNodes = [].slice.call(doc.body.childNodes)
		return this.hasElementNodeType(childNodes);
	},

	hasElementNodeType : function (nodes) {
		if(nodes === undefined) {
			return '';
		}
		return nodes.filter((node) => node.nodeType === 1).length > 0;
	}

}
<commit_msg>tests fail<commit_after>// Because dangerouslySetInnerHTML prop is required only if the string contains HTML tags

module.exports = {
	hasHTMLTags : function(s) {
		const doc = new DOMParser().parseFromString(s, 'text/html');
		const childNodes = doc && [].slice.call(doc.body.childNodes);
		return this.hasElementNodeType(childNodes);
	},

	hasElementNodeType : function (nodes) {
		return nodes && nodes.filter((node) => node.nodeType === 1).length > 0;
	}

}
<|endoftext|>


<commit_before>$(window).load(function () {
    Stripe.setPublishableKey($('#codesy-html').data('stripe_key'));
    let stripeResponse = function (csrf_token) {
        this.csrf_token = csrf_token
        return (function(_this){
            return function (status, response) {
                if (response.error) {
                    console.error("Stripe failed to tokenize");
                    $('#payment-errors').text(response.error.message);
                    document.location.reload();
                } else {
                    $.ajax({
                        method: "PATCH",
                        url: "/users/update/",
                        beforeSend: function(xhr, settings) {
                            xhr.setRequestHeader('X-CSRFToken', _this.csrf_token);
                        },
                        data: {['stripe_'+response.type]: response.id},
                        success: function(data, status, jqXHR) {
                            console.log("Updated user.");
                        },
                        error: function(err) {
                            console.error("Error updating user.");
                            console.error(err);
                        },
                        complete: function(){
                            document.location.reload();
                        }
                    });
                }
            }
        })(this)
    }

    let handleResponse = new stripeResponse($('form input[name="csrfmiddlewaretoken"]').val())
    let $form = $('#stripe-form')
    let account_type = $form.attr('stripe-account-type')

    $('#stripe-submit').click(function (e) {
        e.preventDefault();

        // add account_holder_type for bank account and identity forms
        let holder_type = $("input[name=form_holder_type]:checked").val()
        if (holder_type) {
            $('#account_holder_type').val(holder_type)
        }
        $('#stripe-submit').text('Encrypting ... ');
        Stripe[account_type].createToken($form, handleResponse);
    });

})
<commit_msg>fix #413: show Stripe error message on CC page<commit_after>$(window).load(function () {
    Stripe.setPublishableKey($('#codesy-html').data('stripe_key'));
    let stripeResponse = function (csrf_token) {
        this.csrf_token = csrf_token
        return (function(_this){
            return function (status, response) {
                if (response.error) {
                    console.error("Stripe failed to tokenize");
                    $('#stripe-form').prepend(
                      '
' +
                        '<button class="close-button" data-close>×</button>' +
                        '
' + response.error.message + '
' +
                      '
'
                    )
                    $('#stripe-submit').text('Ecrypt Credit Card Information');
                } else {
                    $.ajax({
                        method: "PATCH",
                        url: "/users/update/",
                        beforeSend: function(xhr, settings) {
                            xhr.setRequestHeader('X-CSRFToken', _this.csrf_token);
                        },
                        data: {['stripe_'+response.type]: response.id},
                        success: function(data, status, jqXHR) {
                            console.log("Updated user.");
                        },
                        error: function(err) {
                            console.error("Error updating user.");
                            console.error(err);
                        },
                        complete: function(){
                            document.location.reload();
                        }
                    });
                }
            }
        })(this)
    }

    let handleResponse = new stripeResponse($('form input[name="csrfmiddlewaretoken"]').val())
    let $form = $('#stripe-form')
    let account_type = $form.attr('stripe-account-type')

    $('#stripe-submit').click(function (e) {
        e.preventDefault();

        // add account_holder_type for bank account and identity forms
        let holder_type = $("input[name=form_holder_type]:checked").val()
        if (holder_type) {
            $('#account_holder_type').val(holder_type)
        }
        $('#stripe-submit').text('Encrypting ... ');
        Stripe[account_type].createToken($form, handleResponse);
    });

})
<|endoftext|>


<commit_before>var fs = require('fs'),
    path = require('path'),
    parseUrl = require('url').parse,
    request = require('request'),
    argv = require('optimist').argv,
    prompt = require('prompt'),
    FormData = require('form-data'),
    IonicProject = require('./project'),
    IonicTask = require('./task').IonicTask,
    IonicStats = require('./stats').IonicStats;
    Task = require('./task').Task,
    IonicLoginTask = require('./login').IonicTask;

var IonicTask = function() {};

IonicTask.prototype = new Task();

IonicTask.prototype.run = function(ionic) {
  var self = this;

  self.ionic = ionic;
  self.inputValues = {};
  self.inputFiles = {};
  self.useCmdArgs = false;

  this.getCmdLineOptions();

  var login = new IonicLoginTask();
  login.get(ionic, function(jar) {
    self.jar = jar;

    if (argv._[1] && argv._[1].trim() == 'webhook_url') {
      if (argv._[2]) {
        self.set_webhook_url(self, argv._[2].trim());
      } else {
        console.log('You need to specify a webhook url!'.bold.red);
      }
    } else if (argv._[1] && argv._[1].trim() == 'google-api-key') {
      if (argv._[2]) {
        self.set_google_api_key(self, argv._[2].trim());
      } else {
        console.log('You need to specify a Google API Key!'.bold.red);
      }
    } else if (argv['send'] || argv.s) {
      // Dev wants to send a push notification
      self.send_push(self);
    } else if (argv['ios-dev-cert'] || argv['ios-prod-cert'] || argv.d || argv.p) {
      // Dev wants to upload an ios push cert
      self.upload_cert(self);
    } else if (argv['production-mode'] || argv.l) {
      // Dev wants to switch between test/live mode
      // this will look like --live-mode=[y/n]
      // where y will put into live and n will put into dev
      self.set_production_mode(self);
    }

  });
};

IonicTask.prototype.set_webhook_url = function(self, webhook_url) {
  var project = IonicProject.load();

  if (!project.get('app_id')) {
    console.log("You need to upload your app first!".bold.red);
    return false;
  }

  var url = self.ionic.IONIC_DASH + self.ionic.IONIC_API + 'app/' + project.get('app_id') + '/push/webhook-url';
  var params = parseUrl(url);

  var form = new FormData();
  form.append('csrfmiddlewaretoken', self.getCsrfToken(self.jar));
  form.append('webhook_url', webhook_url);

  form.submit({
      protocol: params.protocol,
      hostname: params.hostname,
      port: params.port,
      path: params.path,
      headers: form.getHeaders({
        cookie: self.jar.map(function(c) {
          return c.key + "=" + encodeURIComponent(c.value);
        }).join("; ")
      })
    },
    function (err, response) {
      response.on("data", function(data) {
        if (err) {
          return self.ionic.fail('Error setting Webhook URL: ' + err);
        }

        if (response.statusCode == '200') {
          console.log("Webhook URL set to", webhook_url);
        } else {
          return self.ionic.fail('App not found');
        }
      })
    }
  );

  return true;
};

IonicTask.prototype.set_google_api_key = function(self, google_api_key) {
  var project = IonicProject.load();

  if (!project.get('app_id')) {
    console.log("You need to upload your app first!".bold.red);
    return false;
  }

  var url = self.ionic.IONIC_DASH + self.ionic.IONIC_API + 'app/' + project.get('app_id') + '/push/google-api-key';
  var params = parseUrl(url);

  var form = new FormData();
  form.append('csrfmiddlewaretoken', self.getCsrfToken(self.jar));
  form.append('android_api_key', google_api_key);

  form.submit({
      protocol: params.protocol,
      hostname: params.hostname,
      port: params.port,
      path: params.path,
      headers: form.getHeaders({
        cookie: self.jar.map(function(c) {
          return c.key + "=" + encodeURIComponent(c.value);
        }).join("; ")
      })
    },
    function (err, response) {
      response.on("data", function(data) {
        if (err) {
          return self.ionic.fail('Error setting Google API Key: ' + err);
        }

        if (response.statusCode == '200') {
          console.log("Google API Key Saved".green);
        } else {
          return self.ionic.fail('App not found');
        }
      })
    }
  );

  return true;
};

IonicTask.prototype.send_push = function(self) {
  var project = IonicProject.load();

  if (!project.get('app_id')) {
    console.log("You need to upload your app first!".bold.red);
    return false;
  }

  // So, we need the push API key to send notifications.
  var promptProperties = {};

  promptProperties['push-api-key'] = {
    name: 'push-api-key',
    description: 'What is your push API key'.yellow.bold,
    required: true,
    isFile: false
  };

  promptProperties['device-token'] = {
    name: 'device-token',
    description: 'What device token do you want to send to'.yellow.bold,
    required: true,
    isFile: false
  }

  promptProperties['alert'] = {
    name: 'alert',
    description: 'Notification alert message'.yellow.bold,
    required: false,
    isFile: false
  };

  promptProperties['badge'] = {
    name: 'badge',
    description: 'Badge count'.yellow.bold,
    required: false,
    isFile: false
  }

  promptProperties['sound'] = {
    name: 'sound',
    description: 'Sound file name'.yellow.bold,
    required: false,
    isFile: false
  }

  prompt.start();

  prompt.get({properties: promptProperties}, function(err, promptResult) {
    if (err) {
      return self.ionic.fail('Error: ' + err);
    }

    var api_key = promptResult['push-api-key'];

    var notification = {
      platform: 'ios',
      tokens: [promptResult['device-token']],
      notification: {
        alert: promptResult['alert'],
        ios: {
          badge: promptResult['badge'],
          sound: promptResult['sound']
        }
      }
    }

    var options = {
      url: 'https://push.ionic.io/api/v1/push',
      method: 'POST',
      json: true,
      headers: {
        'X-Ionic-Application-Id': project.get('app_id'),
        'authorization': 'Basic ' + new Buffer(api_key + ':').toString('base64')
      },
      body: notification
    };

    request(options, function(err, response, body) {
      if (!err && response.statusCode == 202) {
        console.log("Successfully queued push notification");
      } else {
        console.log("Error queueing push notification", err);
      }
    });
  });

};

IonicTask.prototype.set_production_mode = function(self) {
  var project = IonicProject.load();

  if (!project.get('app_id')) {
    console.log("You need to upload your app first!".bold.red);
    return false;
  }

  if (self.inputValues['production-mode'] === true) {
    console.log("You need to specify a value [y/n] to set the production mode!".bold.red);
    return false;
  }

  self.inputValues['production-mode'] = self.inputValues['production-mode'].toLowerCase();

  if (self.inputValues['production-mode'] != 'y' && self.inputValues['production-mode'] != 'n') {
    console.log("You need to specify a value [y/n] to set the production mode!".bold.red);
    return false;
  }

  var url = self.ionic.IONIC_DASH + self.ionic.IONIC_API + 'app/' + project.get('app_id') + '/push/set-production-mode';
  var params = parseUrl(url);

  var form = new FormData();
  form.append('csrfmiddlewaretoken', self.getCsrfToken(self.jar));
  form.append('production_mode', self.inputValues['production-mode']);

  form.submit({
      protocol: params.protocol,
      hostname: params.hostname,
      port: params.port,
      path: params.path,
      headers: form.getHeaders({
        cookie: self.jar.map(function(c) {
          return c.key + "=" + encodeURIComponent(c.value);
        }).join("; ")
      })
    },
    function (err, response) {
      if (err) {
        return self.ionic.fail('Error uploading certificate: ' + err);
      }

      response.setEncoding('utf8');
      response.on("data", function(data) {
        if (err) {
          return self.ionic.fail('Error setting mode: ' + err);
        }

        try {
          var d = JSON.parse(data);
          if (d.errors && d.errors.length) {
            for (var j = 0; j < d.errors.length; j++) {
              console.log((d.errors[j]).bold.error);
            }
            return self.ionic.fail('Unable to set mode');
          }

          if (self.inputValues['production-mode'] == 'y') {
            console.log("Successfully set production mode");
          } else {
            console.log("Successfully set development mode");
          }

        } catch (parseEx) {
          return self.ionic.fail('Error response: ' + parseEx);
        }
      });
    }
  );
};

IonicTask.prototype.upload_cert = function(self) {
  var project = IonicProject.load();

  if (!project.get('app_id')) {
    console.log("You need to upload your app first!".bold.red);
    return false;
  }

  var promptProperties = {};
  var prodCert = '0';

  if (argv['ios-dev-cert']) {
    promptProperties['ios-push-cert'] = {
      name: 'ios-push-cert',
      description: 'iOS Dev Push Certificate File (.p12)'.yellow.bold,
      required: true,
      conform: fileExists,
      isFile: true
    };
  } else if (argv['ios-prod-cert']) {
    promptProperties['ios-push-cert'] = {
      name: 'ios-push-cert',
      description: 'iOS Prod Push Certificate File (.p12)'.yellow.bold,
      required: true,
      conform: fileExists,
      isFile: true
    };

    prodCert = '1';
  }

  prompt.start();

  prompt.get({properties: promptProperties}, function(err, promptResult) {
    if (err) {
      return self.ionic.fail('Error: ' + err);
    }

    var url = self.ionic.IONIC_DASH + self.ionic.IONIC_API + 'app/' + project.get('app_id') + '/push/upload-push-cert';
    var params = parseUrl(url);

    var form = new FormData();
    form.append('csrfmiddlewaretoken', self.getCsrfToken(self.jar));

    try {
      inputFile = promptResult['ios-push-cert'].replace(/\\ /g, ' ').trim();
      form.append('ios_push_cert', fs.createReadStream( resolvePath(inputFile) ) );
    } catch(e) {
      return self.ionic.fail("Error loading " + resolvePath(inputFile));
    }

    // Set the flag for if this is a production or dev cert
    form.append('prod_cert', prodCert);

    form.submit({
        protocol: params.protocol,
        hostname: params.hostname,
        port: params.port,
        path: params.path,
        headers: form.getHeaders({
          cookie: self.jar.map(function(c) {
            return c.key + "=" + encodeURIComponent(c.value);
          }).join("; ")
        })
      },
      function (err, response) {
        if (err) {
          return self.ionic.fail('Error uploading certificate: ' + err);
        }

        response.setEncoding('utf8');
        response.on("data", function(data) {
          if (err) {
            return self.ionic.fail('Error uploading certificate: ' + err);
          }

          try {
            var d = JSON.parse(data);
            if (d.errors && d.errors.length) {
              for (var j = 0; j < d.errors.length; j++) {
                console.log((d.errors[j]).bold.error);
              }
              return self.ionic.fail('Unable to upload certificate');
            }

            console.log("Successfully uploaded certificate");

          } catch (parseEx) {
            return self.ionic.fail('Error response: ' + parseEx);
          }
        });
      }
    );
  });
}

IonicTask.prototype.getCmdLineOptions = function() {
  var self = this;

  function getCmdArgValue(propertyName, shortName) {
    var value = argv[propertyName] || argv[shortName];
    if(value) {
      self.inputValues[propertyName] = value;
      self.useCmdArgs = true;
    }
  }

  function getCmdArgFile(propertyName, shortName) {
    var value = argv[propertyName] || argv[shortName];
    if(value) {
      if(!fileExists(value)) {
        return self.ionic.fail("Unable to find file: " + argv[propertyName]);
      }
      self.inputFiles[propertyName] = value;
      self.useCmdArgs = true;
    }
  }

  getCmdArgValue('production-mode', 'l');

  getCmdArgFile('ios-push-dev-cert', 'd');
  getCmdArgFile('ios-push-prod-cert', 'p');
};

IonicTask.prototype.getCsrfToken = function(jar) {
  for (var i = 0; i < jar.length; i++) {
    if (jar[i].key == 'csrftoken') {
      return jar[i].value;
    }
  }
  return '';
}

function fileExists(filePath) {
  // check if a file exists with a relative path or absolute path
  filePath = filePath.replace(/\\ /g, ' ').trim();
  return fs.existsSync(resolvePath(filePath));
}

function resolvePath (p) {
  if (p.substr(0, 1) === '~') {
    p = process.env.HOME + p.substr(1);
  }
  return path.resolve(p);
}

exports.IonicTask = IonicTask;
<commit_msg>fix(push): shorten push labels<commit_after>var fs = require('fs'),
    path = require('path'),
    parseUrl = require('url').parse,
    request = require('request'),
    argv = require('optimist').argv,
    prompt = require('prompt'),
    FormData = require('form-data'),
    IonicProject = require('./project'),
    IonicTask = require('./task').IonicTask,
    IonicStats = require('./stats').IonicStats;
    Task = require('./task').Task,
    IonicLoginTask = require('./login').IonicTask;

var IonicTask = function() {};

IonicTask.prototype = new Task();

IonicTask.prototype.run = function(ionic) {
  var self = this;

  self.ionic = ionic;
  self.inputValues = {};
  self.inputFiles = {};
  self.useCmdArgs = false;

  this.getCmdLineOptions();

  var login = new IonicLoginTask();
  login.get(ionic, function(jar) {
    self.jar = jar;

    if (argv._[1] && argv._[1].trim() == 'webhook_url') {
      if (argv._[2]) {
        self.set_webhook_url(self, argv._[2].trim());
      } else {
        console.log('You need to specify a webhook url!'.bold.red);
      }
    } else if (argv._[1] && argv._[1].trim() == 'google-api-key') {
      if (argv._[2]) {
        self.set_google_api_key(self, argv._[2].trim());
      } else {
        console.log('You need to specify a Google API Key!'.bold.red);
      }
    } else if (argv['send'] || argv.s) {
      // Dev wants to send a push notification
      self.send_push(self);
    } else if (argv['ios-dev-cert'] || argv['ios-prod-cert'] || argv.d || argv.p) {
      // Dev wants to upload an ios push cert
      self.upload_cert(self);
    } else if (argv['production-mode'] || argv.l) {
      // Dev wants to switch between test/live mode
      // this will look like --live-mode=[y/n]
      // where y will put into live and n will put into dev
      self.set_production_mode(self);
    }

  });
};

IonicTask.prototype.set_webhook_url = function(self, webhook_url) {
  var project = IonicProject.load();

  if (!project.get('app_id')) {
    console.log("You need to upload your app first!".bold.red);
    return false;
  }

  var url = self.ionic.IONIC_DASH + self.ionic.IONIC_API + 'app/' + project.get('app_id') + '/push/webhook-url';
  var params = parseUrl(url);

  var form = new FormData();
  form.append('csrfmiddlewaretoken', self.getCsrfToken(self.jar));
  form.append('webhook_url', webhook_url);

  form.submit({
      protocol: params.protocol,
      hostname: params.hostname,
      port: params.port,
      path: params.path,
      headers: form.getHeaders({
        cookie: self.jar.map(function(c) {
          return c.key + "=" + encodeURIComponent(c.value);
        }).join("; ")
      })
    },
    function (err, response) {
      response.on("data", function(data) {
        if (err) {
          return self.ionic.fail('Error setting Webhook URL: ' + err);
        }

        if (response.statusCode == '200') {
          console.log("Webhook URL set to", webhook_url);
        } else {
          return self.ionic.fail('App not found');
        }
      })
    }
  );

  return true;
};

IonicTask.prototype.set_google_api_key = function(self, google_api_key) {
  var project = IonicProject.load();

  if (!project.get('app_id')) {
    console.log("You need to upload your app first!".bold.red);
    return false;
  }

  var url = self.ionic.IONIC_DASH + self.ionic.IONIC_API + 'app/' + project.get('app_id') + '/push/google-api-key';
  var params = parseUrl(url);

  var form = new FormData();
  form.append('csrfmiddlewaretoken', self.getCsrfToken(self.jar));
  form.append('android_api_key', google_api_key);

  form.submit({
      protocol: params.protocol,
      hostname: params.hostname,
      port: params.port,
      path: params.path,
      headers: form.getHeaders({
        cookie: self.jar.map(function(c) {
          return c.key + "=" + encodeURIComponent(c.value);
        }).join("; ")
      })
    },
    function (err, response) {
      response.on("data", function(data) {
        if (err) {
          return self.ionic.fail('Error setting Google API Key: ' + err);
        }

        if (response.statusCode == '200') {
          console.log("Google API Key Saved".green);
        } else {
          return self.ionic.fail('App not found');
        }
      })
    }
  );

  return true;
};

IonicTask.prototype.send_push = function(self) {
  var project = IonicProject.load();

  if (!project.get('app_id')) {
    console.log("You need to upload your app first!".bold.red);
    return false;
  }

  // So, we need the push API key to send notifications.
  var promptProperties = {};

  promptProperties['push-api-key'] = {
    name: 'push-api-key',
    description: 'Your private API key'.yellow.bold,
    required: true,
    isFile: false
  };

  promptProperties['device-token'] = {
    name: 'device-token',
    description: 'Device token'.yellow.bold,
    required: true,
    isFile: false
  }

  promptProperties['alert'] = {
    name: 'alert',
    description: 'Notification alert message'.yellow.bold,
    required: false,
    isFile: false
  };

  promptProperties['badge'] = {
    name: 'badge',
    description: 'Badge count'.yellow.bold,
    required: false,
    isFile: false
  }

  promptProperties['sound'] = {
    name: 'sound',
    description: 'Sound file name'.yellow.bold,
    required: false,
    isFile: false
  }

  prompt.start();

  prompt.get({properties: promptProperties}, function(err, promptResult) {
    if (err) {
      return self.ionic.fail('Error: ' + err);
    }

    var api_key = promptResult['push-api-key'];

    var notification = {
      platform: 'ios',
      tokens: [promptResult['device-token']],
      notification: {
        alert: promptResult['alert'],
        ios: {
          badge: promptResult['badge'],
          sound: promptResult['sound']
        }
      }
    }

    var options = {
      url: 'https://push.ionic.io/api/v1/push',
      method: 'POST',
      json: true,
      headers: {
        'X-Ionic-Application-Id': project.get('app_id'),
        'authorization': 'Basic ' + new Buffer(api_key + ':').toString('base64')
      },
      body: notification
    };

    request(options, function(err, response, body) {
      if (!err && response.statusCode == 202) {
        console.log("Successfully queued push notification");
      } else {
        console.log("Error queueing push notification", err);
      }
    });
  });

};

IonicTask.prototype.set_production_mode = function(self) {
  var project = IonicProject.load();

  if (!project.get('app_id')) {
    console.log("You need to upload your app first!".bold.red);
    return false;
  }

  if (self.inputValues['production-mode'] === true) {
    console.log("You need to specify a value [y/n] to set the production mode!".bold.red);
    return false;
  }

  self.inputValues['production-mode'] = self.inputValues['production-mode'].toLowerCase();

  if (self.inputValues['production-mode'] != 'y' && self.inputValues['production-mode'] != 'n') {
    console.log("You need to specify a value [y/n] to set the production mode!".bold.red);
    return false;
  }

  var url = self.ionic.IONIC_DASH + self.ionic.IONIC_API + 'app/' + project.get('app_id') + '/push/set-production-mode';
  var params = parseUrl(url);

  var form = new FormData();
  form.append('csrfmiddlewaretoken', self.getCsrfToken(self.jar));
  form.append('production_mode', self.inputValues['production-mode']);

  form.submit({
      protocol: params.protocol,
      hostname: params.hostname,
      port: params.port,
      path: params.path,
      headers: form.getHeaders({
        cookie: self.jar.map(function(c) {
          return c.key + "=" + encodeURIComponent(c.value);
        }).join("; ")
      })
    },
    function (err, response) {
      if (err) {
        return self.ionic.fail('Error uploading certificate: ' + err);
      }

      response.setEncoding('utf8');
      response.on("data", function(data) {
        if (err) {
          return self.ionic.fail('Error setting mode: ' + err);
        }

        try {
          var d = JSON.parse(data);
          if (d.errors && d.errors.length) {
            for (var j = 0; j < d.errors.length; j++) {
              console.log((d.errors[j]).bold.error);
            }
            return self.ionic.fail('Unable to set mode');
          }

          if (self.inputValues['production-mode'] == 'y') {
            console.log("Successfully set production mode");
          } else {
            console.log("Successfully set development mode");
          }

        } catch (parseEx) {
          return self.ionic.fail('Error response: ' + parseEx);
        }
      });
    }
  );
};

IonicTask.prototype.upload_cert = function(self) {
  var project = IonicProject.load();

  if (!project.get('app_id')) {
    console.log("You need to upload your app first!".bold.red);
    return false;
  }

  var promptProperties = {};
  var prodCert = '0';

  if (argv['ios-dev-cert']) {
    promptProperties['ios-push-cert'] = {
      name: 'ios-push-cert',
      description: 'iOS Dev Push Certificate File (.p12)'.yellow.bold,
      required: true,
      conform: fileExists,
      isFile: true
    };
  } else if (argv['ios-prod-cert']) {
    promptProperties['ios-push-cert'] = {
      name: 'ios-push-cert',
      description: 'iOS Prod Push Certificate File (.p12)'.yellow.bold,
      required: true,
      conform: fileExists,
      isFile: true
    };

    prodCert = '1';
  }

  prompt.start();

  prompt.get({properties: promptProperties}, function(err, promptResult) {
    if (err) {
      return self.ionic.fail('Error: ' + err);
    }

    var url = self.ionic.IONIC_DASH + self.ionic.IONIC_API + 'app/' + project.get('app_id') + '/push/upload-push-cert';
    var params = parseUrl(url);

    var form = new FormData();
    form.append('csrfmiddlewaretoken', self.getCsrfToken(self.jar));

    try {
      inputFile = promptResult['ios-push-cert'].replace(/\\ /g, ' ').trim();
      form.append('ios_push_cert', fs.createReadStream( resolvePath(inputFile) ) );
    } catch(e) {
      return self.ionic.fail("Error loading " + resolvePath(inputFile));
    }

    // Set the flag for if this is a production or dev cert
    form.append('prod_cert', prodCert);

    form.submit({
        protocol: params.protocol,
        hostname: params.hostname,
        port: params.port,
        path: params.path,
        headers: form.getHeaders({
          cookie: self.jar.map(function(c) {
            return c.key + "=" + encodeURIComponent(c.value);
          }).join("; ")
        })
      },
      function (err, response) {
        if (err) {
          return self.ionic.fail('Error uploading certificate: ' + err);
        }

        response.setEncoding('utf8');
        response.on("data", function(data) {
          if (err) {
            return self.ionic.fail('Error uploading certificate: ' + err);
          }

          try {
            var d = JSON.parse(data);
            if (d.errors && d.errors.length) {
              for (var j = 0; j < d.errors.length; j++) {
                console.log((d.errors[j]).bold.error);
              }
              return self.ionic.fail('Unable to upload certificate');
            }

            console.log("Successfully uploaded certificate");

          } catch (parseEx) {
            return self.ionic.fail('Error response: ' + parseEx);
          }
        });
      }
    );
  });
}

IonicTask.prototype.getCmdLineOptions = function() {
  var self = this;

  function getCmdArgValue(propertyName, shortName) {
    var value = argv[propertyName] || argv[shortName];
    if(value) {
      self.inputValues[propertyName] = value;
      self.useCmdArgs = true;
    }
  }

  function getCmdArgFile(propertyName, shortName) {
    var value = argv[propertyName] || argv[shortName];
    if(value) {
      if(!fileExists(value)) {
        return self.ionic.fail("Unable to find file: " + argv[propertyName]);
      }
      self.inputFiles[propertyName] = value;
      self.useCmdArgs = true;
    }
  }

  getCmdArgValue('production-mode', 'l');

  getCmdArgFile('ios-push-dev-cert', 'd');
  getCmdArgFile('ios-push-prod-cert', 'p');
};

IonicTask.prototype.getCsrfToken = function(jar) {
  for (var i = 0; i < jar.length; i++) {
    if (jar[i].key == 'csrftoken') {
      return jar[i].value;
    }
  }
  return '';
}

function fileExists(filePath) {
  // check if a file exists with a relative path or absolute path
  filePath = filePath.replace(/\\ /g, ' ').trim();
  return fs.existsSync(resolvePath(filePath));
}

function resolvePath (p) {
  if (p.substr(0, 1) === '~') {
    p = process.env.HOME + p.substr(1);
  }
  return path.resolve(p);
}

exports.IonicTask = IonicTask;
<|endoftext|>