<commit_before>/* global PhotoSwipe */
/* global PhotoSwipeUI_Default */

import Em from 'ember';

var run = Em.run;

export default Em.Component.extend({

  onInsert: Em.on('didInsertElement', function() {

    Em.run.scheduleOnce('afterRender', this, function() {
      this.set('pswpEl', this.$('.pswp')[0]);
      this.set('pswpTheme', PhotoSwipeUI_Default);

      this._buildOptions();

      /**
       * DEPRECATED
       *
       * Code exists for backward compatability of block usage
       * up to ember-cli-photoswipe versions 1.0.1.
       */
      if (this.get('items')) {
        return this._initItemGallery();
      }
      console.log("WARNING: See https://github.com/poetic/ember-cli-photoswipe#usage");
      return this._calculateItems();
      /**
       * END DEPRECATED
       */
    });
  }),

  _buildOptions: function(getThumbBoundsFn) {
     var reqOpts = {
      history: false
    };

    if (Em.isPresent(getThumbBoundsFn)) {
      reqOpts.getThumbBoundsFn = getThumbBoundsFn;
    }

    var options = Em.merge(reqOpts, this.get('options') || {});
    this.set('options', options);
  },

  _initItemGallery: function() {
    this.set('gallery', new PhotoSwipe(
      this.get('pswpEl'),
      this.get('pswpTheme'),
      this.get('items'),
      this.get('options')
    ));
    this._reInitOnClose();
  },

  _reInitOnClose: function() {
    var component = this;
    this.get('gallery').listen('close', function() {
      run.next(function() {
        component._initItemGallery();
      });
    });
  },

  itemObserver: Em.observer('items', function(){
    var component = this;
    component._initItemGallery();
  }),

  /**
   * DEPRECATED
   *
   * Code exists for backward compatability of block usage
   * up to ember-cli-photoswipe versions 1.0.1.
   */
  click: function(evt) {

    if (this.get('items')) {
      return; // ignore - not using deprecated block form
    }

    var aElement = this.$(evt.target).parent();
    var index    = this.$("a.photo-item").index( aElement );

    if (!aElement.is('a')) { return; }

    evt.preventDefault();

    // setup options, such as index for index
    this._buildOptions(this._getBounds.bind(this));
    this.set('options.index', index);

    var pSwipe = new PhotoSwipe(
      this.get('pswpEl'),
      this.get('pswpTheme'),
      this.get('calculatedItems'),
      this.get('options')
    );
    this.set('gallery', pSwipe);
    this.get('gallery').init();
  },
  /**
   * END DEPRECATED
   */

  _getBounds: function(i) {
    var img      = this.$('img').get(i),
        position = this.$(img).position(),
        width    = this.$(img).width();
    return {x: position.left, y: position.top, w: width};
  },

  actions: {
    launchGallery(item) {
      this._buildOptions(this._getBounds.bind(this));
      if (item !== undefined) {
        var index = this.get('items').indexOf(item);
        this.set('options.index', index);
      }
      var pSwipe = new PhotoSwipe(
        this.get('pswpEl'),
        this.get('pswpTheme'),
        this.get('items'),
        this.get('options')
      );
      this.set('gallery', pSwipe);
      this.get('gallery').init();
    }
  },

  /**
   * DEPRECATED
   *
   * Code exists for backward compatability of block usage
   * up to ember-cli-photoswipe versions 1.0.1.
   */
  _calculateItems: function() {
    var items           = this.$().find('a');
    var calculatedItems = Em.A(items).map(function(i, item) {
      return {
        src:   Em.$(item).attr('href'),
        w:     Em.$(item).data('width'),
        h:     Em.$(item).data('height'),
        msrc:  Em.$(item).children('img').attr('src'),
        title: Em.$(item).children('img').attr('alt')
      };
    });
    this.set('calculatedItems', calculatedItems);
  }
  /**
   * END DEPRECATED
   */

});
<commit_msg>deprecate correctly<commit_after>/* global PhotoSwipe */
/* global PhotoSwipeUI_Default */

import Em from 'ember';

var run = Em.run;

export default Em.Component.extend({

  onInsert: Em.on('didInsertElement', function() {

    Em.run.scheduleOnce('afterRender', this, function() {
      this.set('pswpEl', this.$('.pswp')[0]);
      this.set('pswpTheme', PhotoSwipeUI_Default);

      this._buildOptions();

      if (this.get('items')) {
        return this._initItemGallery();
      }

      /**
       * DEPRECATED
       *
       * Code exists for backward compatibility of block usage
       * up to ember-cli-photoswipe versions 1.0.1.
       */
      return this._calculateItems();
      /**
       * END DEPRECATED
       */
    });
  }),

  _buildOptions: function(getThumbBoundsFn) {
     var reqOpts = {
      history: false
    };

    if (Em.isPresent(getThumbBoundsFn)) {
      reqOpts.getThumbBoundsFn = getThumbBoundsFn;
    }

    var options = Em.merge(reqOpts, this.get('options') || {});
    this.set('options', options);
  },

  _initItemGallery: function() {
    this.set('gallery', new PhotoSwipe(
      this.get('pswpEl'),
      this.get('pswpTheme'),
      this.get('items'),
      this.get('options')
    ));
    this._reInitOnClose();
  },

  _reInitOnClose: function() {
    var component = this;
    this.get('gallery').listen('close', function() {
      run.next(function() {
        component._initItemGallery();
      });
    });
  },

  itemObserver: Em.observer('items', function(){
    var component = this;
    component._initItemGallery();
  }),

  /**
   * DEPRECATED
   *
   * Code exists for backward compatibility of block usage
   * up to ember-cli-photoswipe versions 1.0.1.
   */
  click: function(evt) {

    if (this.get('items')) {
      return; // ignore - not using deprecated block form
    }

    var aElement = this.$(evt.target).parent();
    var index    = this.$("a.photo-item").index( aElement );

    if (!aElement.is('a')) { return; }

    evt.preventDefault();

    // setup options, such as index for index
    this._buildOptions(this._getBounds.bind(this));
    this.set('options.index', index);

    var pSwipe = new PhotoSwipe(
      this.get('pswpEl'),
      this.get('pswpTheme'),
      this.get('calculatedItems'),
      this.get('options')
    );
    this.set('gallery', pSwipe);
    this.get('gallery').init();
  },
  /**
   * END DEPRECATED
   */

  _getBounds: function(i) {
    var img      = this.$('img').get(i),
        position = this.$(img).position(),
        width    = this.$(img).width();
    return {x: position.left, y: position.top, w: width};
  },

  actions: {
    launchGallery(item) {
      this._buildOptions(this._getBounds.bind(this));
      if (item !== undefined) {
        var index = this.get('items').indexOf(item);
        this.set('options.index', index);
      }
      var pSwipe = new PhotoSwipe(
        this.get('pswpEl'),
        this.get('pswpTheme'),
        this.get('items'),
        this.get('options')
      );
      this.set('gallery', pSwipe);
      this.get('gallery').init();
    }
  },

  /**
   * DEPRECATED
   *
   * Code exists for backward compatibility of block usage
   * up to ember-cli-photoswipe versions 1.0.1.
   */
  _calculateItems: function() {
    Em.deprecate(
      "Using ember-cli-photoswipe without an items attribute is deprecated. "+
      "See https://github.com/poetic/ember-cli-photoswipe#usage",
      false,
      {id: 'ember-cli-photoswipe.didInsertElement', until: '1.13'}
    );

    var items           = this.$().find('a');
    var calculatedItems = Em.A(items).map(function(i, item) {
      return {
        src:   Em.$(item).attr('href'),
        w:     Em.$(item).data('width'),
        h:     Em.$(item).data('height'),
        msrc:  Em.$(item).children('img').attr('src'),
        title: Em.$(item).children('img').attr('alt')
      };
    });
    this.set('calculatedItems', calculatedItems);
  }
  /**
   * END DEPRECATED
   */

});
<|endoftext|>


<commit_before>import Ember from "ember";
import SelectMenuLabel from "../views/select-menu-label";
import nearestChild from "../computed/nearest-child";
import w from "../computed/w";

var get = Ember.get;
var next = Ember.run.next;
var cancel = Ember.run.cancel;
var later = Ember.run.later;
var set = Ember.set;

var guidFor = Ember.guidFor;

var filterBy = Ember.computed.filterBy;
var reads = Ember.computed.reads;
var alias = Ember.computed.alias;

var RSVP = Ember.RSVP;

// Key code mappings
var ESC              = 27,
    UP               = 38,
    DOWN             = 40,
    BACKSPACE        = 8,
    TAB              = 9,
    ENTER            = 13,
    SHIFT            = 16,
    CTRL             = 17,
    ALT              = 18,
    CAPS_LOCK        = 20,
    PAGE_DOWN        = 33,
    PAGE_UP          = 34,
    END              = 35,
    INSERT           = 36,
    DELETE           = 46,
    LEFT_WINDOW_KEY  = 91,
    RIGHT_WINDOW_KEY = 92,
    SELECT_KEY       = 93,
    NUM_LOCK         = 144,
    SCROLL_LOCK      = 145;

var SelectMenu = Ember.Component.extend({

  init: function () {
    if (get(this, 'elementId') !== guidFor(this)) {
      set(this, 'inheritedId', get(this, 'elementId'));
      set(this, 'elementId', guidFor(this));
    }

    this._super();
  },

  createChildView: function (childView, options) {
    if (SelectMenuLabel.detect(childView)) {
      options.elementId = get(this, 'inheritedId');
    }
    return this._super(childView, options);
  },

  classNames: ['select-menu'],

  disabled: false,

  options: function () {
    return [];
  }.property(),

  activeOptions: filterBy('options', 'disabled', false),

  activeDescendants: filterBy('options', 'selected'),
  activeDescendant: reads('activeDescendants.firstObject'),

  searchString: null,
  isActive: alias('popup.isActive'),

  prompt: null,

  label: nearestChild('select-menu-label'),
  list: nearestChild('select-menu-list'),
  popup: nearestChild('popup-menu'),

  /**
    The item of the content that is currently selected.

    If the {{select-menu}} has a prompt, then the value
    will by default be null. Otherwise, the value will
    be the first item in the content.

    @property value
    @type Object
    @default null
   */
  value: function (key, value) {
    var hasPrompt = !!get(this, 'prompt');

    if (hasPrompt) {
      if (value && value.then) {
        var menu = this;
        RSVP.Promise.cast(value).then(function (unwrappedValue) {
          if (menu.isDestroyed) { return; }
          set(menu, 'value', unwrappedValue);
        });
      }
    } else if (value == null) {
      next(this, function () {
        if (this.isDestroyed || get(this, 'prompt')) { return; }
        var firstOption = get(this, 'options.firstObject.value');
        if (firstOption) {
          set(this, 'value', firstOption);
        }
      });
    }

    return value;
  }.property(),

  _shouldShowPrompt: function () {
    var hasPrompt = !!get(this, 'prompt');
    if (!hasPrompt && get(this, 'value') == null) {
      this.notifyPropertyChange('value');
    }
  }.observes('options.[]', 'prompt').on('init'),

  /**
    Interpret keyboard events
   */
  keyDown: function (evt) {
    var code = (evt.keyCode ? evt.keyCode : evt.which);
    var search = get(this, 'searchString');

    // If the meta key was held, don't do anything.
    if (evt.metaKey) {
      if (String.fromCharCode(code).toLowerCase() === 'a') {
        code = SELECT_KEY;
      } else {
        return;
      }
    }

    // Ignore all events if the select is disabled
    if (get(this, 'disabled')) { return; }

    switch (code) {
    case UP:
      if (get(this, 'isActive')) {
        this.selectPrevious();
      }
      set(this, 'isActive', true);

      break;
    case DOWN:
      if (get(this, 'isActive')) {
        this.selectNext();
      }
      set(this, 'isActive', true);

      break;
    case ESC:
      set(this, 'isActive', false);

      break;

    // Allow tabs to pass through
    case TAB:
    case ENTER:
      set(this, 'isActive', false);
      return;

    // A whitelist of characters to let the browser handle
    case SHIFT:
    case CTRL:
    case ALT:
    case CAPS_LOCK:
    case PAGE_DOWN:
    case PAGE_UP:
    case END:
    case INSERT:
    case DELETE:
    case LEFT_WINDOW_KEY:
    case RIGHT_WINDOW_KEY:
    case NUM_LOCK:
    case SCROLL_LOCK:
      return;

    case SELECT_KEY:
      break;

    case BACKSPACE:
      if (search) {
        set(this, 'searchString', search.slice(0, -1));
      }

      break;
    default:
      var chr = String.fromCharCode(code);

      // Append
      if (search) {
        set(this, 'searchString', search + chr);
      } else {
        if (chr === ' ') {
          this.toggleProperty('isActive');
        } else {
          set(this, 'isActive', true);
          set(this, 'searchString', chr);
        }
      }
    }

    evt.preventDefault();
  },

  /**
    Selects the next item in the option list.
   */
  selectNext: function () {
    var options = get(this, 'activeOptions');
    var activeDescendant = get(this, 'activeDescendant');
    var index;

    if (options) {
      if (activeDescendant) {
        index = options.indexOf(activeDescendant);
      } else {
        index = -1;
      }

      var option = options.objectAt(Math.min(index + 1, get(options, 'length') - 1));
      if (option !== activeDescendant) {
        set(this, 'activeDescendant', option);
        set(this, 'value', get(option, 'value'));
      }
    }
  },

  /**
    Selects the previous item in the option list.
   */
  selectPrevious: function () {
    var options = get(this, 'activeOptions');
    var activeDescendant = get(this, 'activeDescendant');
    var index;

    if (options) {
      if (activeDescendant) {
        index = options.indexOf(activeDescendant);
      } else {
        index = get(options, 'length');
      }

      var option = options.objectAt(Math.max(index - 1, 0));
      if (option !== activeDescendant) {
        set(this, 'activeDescendant', option);
        set(this, 'value', get(option, 'value'));
      }
    }
  },

  /**
    Search by value of the object
   */
  "search-by": alias('searchBy'),
  searchBy: w("this"),

  /**
    Locally iterate through options and find the
    best match. After 750 milliseconds of inactivity,
    the search is reset, allowing users to search again.
   */
  searchStringDidChange: function () {
    if (this.__timer) {
      cancel(this.__timer);
    }

    var options = get(this, 'activeOptions');
    var search = get(this, 'searchString');
    var searchBy = get(this, 'searchBy');

    if (options && search && searchBy) {
      var length = get(options, 'length'),
          match = null,
          start,
          matchIndex;

      search = search.toUpperCase();

      // Continue searching from the index of
      // the last search match
      if (this.__matchIndex) {
        start = Math.min(this.__matchIndex, length - 1);
      } else {
        start = 0;
      }

      var hasMatch;
      var compare = function (a, b) {
        return String(a || '').toUpperCase().indexOf(b) === 0;
      };

      // Search labels and values if the search-by is 'this'
      if (searchBy[0] === 'this') {
        hasMatch = function (value, label) {
          return compare(value, search) || compare(label, search);
        };
      } else {
        hasMatch = function (value) {
          for (var i = 0; i < searchBy.length; i++) {
            if (compare(get(value, searchBy[i], search) === 0) {
              return true;
            }
          }
          return false;
        };
      };

      // Search from the current value
      // for the next match
      for (var i = start; i < length; i++) {
        var option = options.objectAt(i);
        match = hasMatch(get(option, 'value'), get(option, 'label'));

        // Break on the first match,
        // if a user would like to match
        // a more specific entry, they should
        // continue typing
        if (match) {
          match = option;
          matchIndex = i;
          break;
        }
      }

      // Stash the last matched search item
      // so we can continue searching from that
      // index on consective searches
      if (match != null) {
        set(this, 'activeDescendant', match);
        set(this, 'value', get(match, 'value'));
        this.__matchIndex = matchIndex;
      }
    }

    if (search) {
      this.__timer = later(this, this.resetSearch, 750);
    }
  }.observes('searchString'),

  /**
    Reset the `searchString`.
   */
  resetSearch: function () {
    this.__timer = null;
    this.__matchIndex = null;
    set(this, 'searchString', null);
  }
});

export default SelectMenu;
<commit_msg>fix broken compilation<commit_after>import Ember from "ember";
import SelectMenuLabel from "../views/select-menu-label";
import nearestChild from "../computed/nearest-child";
import w from "../computed/w";

var get = Ember.get;
var next = Ember.run.next;
var cancel = Ember.run.cancel;
var later = Ember.run.later;
var set = Ember.set;

var guidFor = Ember.guidFor;

var filterBy = Ember.computed.filterBy;
var reads = Ember.computed.reads;
var alias = Ember.computed.alias;

var RSVP = Ember.RSVP;

// Key code mappings
var ESC              = 27,
    UP               = 38,
    DOWN             = 40,
    BACKSPACE        = 8,
    TAB              = 9,
    ENTER            = 13,
    SHIFT            = 16,
    CTRL             = 17,
    ALT              = 18,
    CAPS_LOCK        = 20,
    PAGE_DOWN        = 33,
    PAGE_UP          = 34,
    END              = 35,
    INSERT           = 36,
    DELETE           = 46,
    LEFT_WINDOW_KEY  = 91,
    RIGHT_WINDOW_KEY = 92,
    SELECT_KEY       = 93,
    NUM_LOCK         = 144,
    SCROLL_LOCK      = 145;

var SelectMenu = Ember.Component.extend({

  init: function () {
    if (get(this, 'elementId') !== guidFor(this)) {
      set(this, 'inheritedId', get(this, 'elementId'));
      set(this, 'elementId', guidFor(this));
    }

    this._super();
  },

  createChildView: function (childView, options) {
    if (SelectMenuLabel.detect(childView)) {
      options.elementId = get(this, 'inheritedId');
    }
    return this._super(childView, options);
  },

  classNames: ['select-menu'],

  disabled: false,

  options: function () {
    return [];
  }.property(),

  activeOptions: filterBy('options', 'disabled', false),

  activeDescendants: filterBy('options', 'selected'),
  activeDescendant: reads('activeDescendants.firstObject'),

  searchString: null,
  isActive: alias('popup.isActive'),

  prompt: null,

  label: nearestChild('select-menu-label'),
  list: nearestChild('select-menu-list'),
  popup: nearestChild('popup-menu'),

  /**
    The item of the content that is currently selected.

    If the {{select-menu}} has a prompt, then the value
    will by default be null. Otherwise, the value will
    be the first item in the content.

    @property value
    @type Object
    @default null
   */
  value: function (key, value) {
    var hasPrompt = !!get(this, 'prompt');

    if (hasPrompt) {
      if (value && value.then) {
        var menu = this;
        RSVP.Promise.cast(value).then(function (unwrappedValue) {
          if (menu.isDestroyed) { return; }
          set(menu, 'value', unwrappedValue);
        });
      }
    } else if (value == null) {
      next(this, function () {
        if (this.isDestroyed || get(this, 'prompt')) { return; }
        var firstOption = get(this, 'options.firstObject.value');
        if (firstOption) {
          set(this, 'value', firstOption);
        }
      });
    }

    return value;
  }.property(),

  _shouldShowPrompt: function () {
    var hasPrompt = !!get(this, 'prompt');
    if (!hasPrompt && get(this, 'value') == null) {
      this.notifyPropertyChange('value');
    }
  }.observes('options.[]', 'prompt').on('init'),

  /**
    Interpret keyboard events
   */
  keyDown: function (evt) {
    var code = (evt.keyCode ? evt.keyCode : evt.which);
    var search = get(this, 'searchString');

    // If the meta key was held, don't do anything.
    if (evt.metaKey) {
      if (String.fromCharCode(code).toLowerCase() === 'a') {
        code = SELECT_KEY;
      } else {
        return;
      }
    }

    // Ignore all events if the select is disabled
    if (get(this, 'disabled')) { return; }

    switch (code) {
    case UP:
      if (get(this, 'isActive')) {
        this.selectPrevious();
      }
      set(this, 'isActive', true);

      break;
    case DOWN:
      if (get(this, 'isActive')) {
        this.selectNext();
      }
      set(this, 'isActive', true);

      break;
    case ESC:
      set(this, 'isActive', false);

      break;

    // Allow tabs to pass through
    case TAB:
    case ENTER:
      set(this, 'isActive', false);
      return;

    // A whitelist of characters to let the browser handle
    case SHIFT:
    case CTRL:
    case ALT:
    case CAPS_LOCK:
    case PAGE_DOWN:
    case PAGE_UP:
    case END:
    case INSERT:
    case DELETE:
    case LEFT_WINDOW_KEY:
    case RIGHT_WINDOW_KEY:
    case NUM_LOCK:
    case SCROLL_LOCK:
      return;

    case SELECT_KEY:
      break;

    case BACKSPACE:
      if (search) {
        set(this, 'searchString', search.slice(0, -1));
      }

      break;
    default:
      var chr = String.fromCharCode(code);

      // Append
      if (search) {
        set(this, 'searchString', search + chr);
      } else {
        if (chr === ' ') {
          this.toggleProperty('isActive');
        } else {
          set(this, 'isActive', true);
          set(this, 'searchString', chr);
        }
      }
    }

    evt.preventDefault();
  },

  /**
    Selects the next item in the option list.
   */
  selectNext: function () {
    var options = get(this, 'activeOptions');
    var activeDescendant = get(this, 'activeDescendant');
    var index;

    if (options) {
      if (activeDescendant) {
        index = options.indexOf(activeDescendant);
      } else {
        index = -1;
      }

      var option = options.objectAt(Math.min(index + 1, get(options, 'length') - 1));
      if (option !== activeDescendant) {
        set(this, 'activeDescendant', option);
        set(this, 'value', get(option, 'value'));
      }
    }
  },

  /**
    Selects the previous item in the option list.
   */
  selectPrevious: function () {
    var options = get(this, 'activeOptions');
    var activeDescendant = get(this, 'activeDescendant');
    var index;

    if (options) {
      if (activeDescendant) {
        index = options.indexOf(activeDescendant);
      } else {
        index = get(options, 'length');
      }

      var option = options.objectAt(Math.max(index - 1, 0));
      if (option !== activeDescendant) {
        set(this, 'activeDescendant', option);
        set(this, 'value', get(option, 'value'));
      }
    }
  },

  /**
    Search by value of the object
   */
  "search-by": alias('searchBy'),
  searchBy: w("this"),

  /**
    Locally iterate through options and find the
    best match. After 750 milliseconds of inactivity,
    the search is reset, allowing users to search again.
   */
  searchStringDidChange: function () {
    if (this.__timer) {
      cancel(this.__timer);
    }

    var options = get(this, 'activeOptions');
    var search = get(this, 'searchString');
    var searchBy = get(this, 'searchBy');

    if (options && search && searchBy) {
      var length = get(options, 'length'),
          match = null,
          start,
          matchIndex;

      search = search.toUpperCase();

      // Continue searching from the index of
      // the last search match
      if (this.__matchIndex) {
        start = Math.min(this.__matchIndex, length - 1);
      } else {
        start = 0;
      }

      var hasMatch;
      var compare = function (a, b) {
        return String(a || '').toUpperCase().indexOf(b) === 0;
      };

      // Search labels and values if the search-by is 'this'
      if (searchBy[0] === 'this') {
        hasMatch = function (value, label) {
          return compare(value, search) || compare(label, search);
        };
      } else {
        hasMatch = function (value) {
          for (var i = 0; i < searchBy.length; i++) {
            if (compare(get(value, searchBy[i]), search) === 0) {
              return true;
            }
          }
          return false;
        };
      }

      // Search from the current value
      // for the next match
      for (var i = start; i < length; i++) {
        var option = options.objectAt(i);
        match = hasMatch(get(option, 'value'), get(option, 'label'));

        // Break on the first match,
        // if a user would like to match
        // a more specific entry, they should
        // continue typing
        if (match) {
          match = option;
          matchIndex = i;
          break;
        }
      }

      // Stash the last matched search item
      // so we can continue searching from that
      // index on consective searches
      if (match != null) {
        set(this, 'activeDescendant', match);
        set(this, 'value', get(match, 'value'));
        this.__matchIndex = matchIndex;
      }
    }

    if (search) {
      this.__timer = later(this, this.resetSearch, 750);
    }
  }.observes('searchString'),

  /**
    Reset the `searchString`.
   */
  resetSearch: function () {
    this.__timer = null;
    this.__matchIndex = null;
    set(this, 'searchString', null);
  }
});

export default SelectMenu;
<|endoftext|>


<commit_before>import Ember from 'ember';
import DS from 'ember-data';
import Firebase from 'firebase';
import FirebaseAdapter from '../adapters/firebase';
import FirebaseSerializer from '../serializers/firebase';

var VERSION = '0.0.0';

if (Ember.libraries) {
  if (Firebase.SDK_VERSION) {
    Ember.libraries.registerCoreLibrary('Firebase', Firebase.SDK_VERSION);
  }

  Ember.libraries.registerCoreLibrary('EmberFire', VERSION);
}

export default {
  name: 'emberfire',
  before: 'store',
  initialize: function (container, app) {
    app.register('adapter:-firebase', FirebaseAdapter);
    app.register('serializer:-firebase', FirebaseSerializer);

    // Monkeypatch the store until ED gives us a good way to listen to push events
    if (!DS.Store.prototype._emberfirePatched) {
      DS.Store.reopen({
        _emberfirePatched: true,
        push: function(typeName, data, _partial) {
          var record = this._super(typeName, data, _partial);
          var adapter = this.adapterFor(record.constructor);
          if (adapter.recordWasPushed) {
            adapter.recordWasPushed(this, typeName, record);
          }
          return record;
        },

        recordWillUnload: function(record) {
          var adapter = this.adapterFor(record.constructor);
          if (adapter.recordWillUnload) {
            adapter.recordWillUnload(this, record);
          }
        },

        recordWillDelete: function (record) {
          var adapter = this.adapterFor(record.constructor);
          if (adapter.recordWillDelete) {
            adapter.recordWillDelete(this, record);
          }
        }
      });
    }

    if (!DS.Model.prototype._emberfirePatched) {
      DS.Model.reopen({
        _emberfirePatched: true,
        unloadRecord: function() {
          this.store.recordWillUnload(this);
          return this._super();
        },
        deleteRecord: function () {
          this.store.recordWillDelete(this);
          this._super();
        }
      });
    }

    DS.FirebaseAdapter = FirebaseAdapter;
    DS.FirebaseSerializer = FirebaseSerializer;
  }
};
<commit_msg>Monkey patch store before it is initialized<commit_after>import Ember from 'ember';
import DS from 'ember-data';
import Firebase from 'firebase';
import FirebaseAdapter from '../adapters/firebase';
import FirebaseSerializer from '../serializers/firebase';

var VERSION = '0.0.0';

if (Ember.libraries) {
  if (Firebase.SDK_VERSION) {
    Ember.libraries.registerCoreLibrary('Firebase', Firebase.SDK_VERSION);
  }

  Ember.libraries.registerCoreLibrary('EmberFire', VERSION);
}

export default {
  name: 'emberfire',
  before: 'ember-data',
  initialize: function (container, app) {
    app.register('adapter:-firebase', FirebaseAdapter);
    app.register('serializer:-firebase', FirebaseSerializer);

    // Monkeypatch the store until ED gives us a good way to listen to push events
    if (!DS.Store.prototype._emberfirePatched) {
      DS.Store.reopen({
        _emberfirePatched: true,
        push: function(typeName, data, _partial) {
          var record = this._super(typeName, data, _partial);
          var adapter = this.adapterFor(record.constructor);
          if (adapter.recordWasPushed) {
            adapter.recordWasPushed(this, typeName, record);
          }
          return record;
        },

        recordWillUnload: function(record) {
          var adapter = this.adapterFor(record.constructor);
          if (adapter.recordWillUnload) {
            adapter.recordWillUnload(this, record);
          }
        },

        recordWillDelete: function (record) {
          var adapter = this.adapterFor(record.constructor);
          if (adapter.recordWillDelete) {
            adapter.recordWillDelete(this, record);
          }
        }
      });
    }

    if (!DS.Model.prototype._emberfirePatched) {
      DS.Model.reopen({
        _emberfirePatched: true,
        unloadRecord: function() {
          this.store.recordWillUnload(this);
          return this._super();
        },
        deleteRecord: function () {
          this.store.recordWillDelete(this);
          this._super();
        }
      });
    }

    DS.FirebaseAdapter = FirebaseAdapter;
    DS.FirebaseSerializer = FirebaseSerializer;
  }
};
<|endoftext|>


<commit_before>var express = require('express'),
  router = express.Router();

var PushApi = require('../services/push');

module.exports = function () {
  let service = new PushApi();

  return router
    .get('/create', service.createVapidKey)
    .post('/register', service.registerVapidKey)
    .post('/unregister', service.unregisterVapidKey)
    .post('/subscribe', service.subscribeUser)
    .post('/unsubscribe', service.unsubscribeUser)
    .post('/send', service.sendPushNotification)
}<commit_msg>changing to post for body<commit_after>var express = require('express'),
  router = express.Router();

var PushApi = require('../services/push');

module.exports = function () {
  let service = new PushApi();

  return router
    .post('/create', service.createVapidKey)
    .post('/register', service.registerVapidKey)
    .post('/unregister', service.unregisterVapidKey)
    .post('/subscribe', service.subscribeUser)
    .post('/unsubscribe', service.unsubscribeUser)
    .post('/send', service.sendPushNotification)
}<|endoftext|>


<commit_before>s4aTempDict = {

/*
    Special characters: (see <http://0xcc.net/jsescape/>)
    Ä, ä   \u00c4, \u00e4
    Ö, ö   \u00d6, \u00f6
    Ü, ü   \u00dc, \u00fc
    ß      \u00df
*/
    // primitive blocks:

    /*
        Attention Translators:
        ----------------------
        At this time your translation of block specs will only work
        correctly, if the order of formal parameters and their types
        are unchanged. Placeholders for inputs (formal parameters) are
        indicated by a preceding % prefix and followed by a type
        abbreviation.
        For example:
            'say %s for %n secs'
        can currently not be changed into
            'say %n secs long %s'
        and still work as intended.
        Similarly
            'point towards %dst'
        cannot be changed into
            'point towards %cst'
        without breaking its functionality.
    */

    // arduino:

    'digital input':
        'entrada dixital',

    'digital output':
        'saída dixital',

    'PWM':
        'PWM',

    'servo':
        'servo',

    'clockwise':
        'sentido horario',

    'clockwise (1500-1000)':
        'sentido horario (1500-1000)',

    'counter-clockwise':
        'sentido anti-horario',

    'counter-clockwise (1500-2000)':
        'sentido anti-horario (1500-2000)',

    'stopped':
        'parado',

    'stopped (1500)':
        'parado (1500)',

    'disconnected':
        'desconectado',

    'angle (0-180)':
        'ángulo (0-180)',

    'connect to Arduino':
        'conectar a Arduino',

    'disconnect Arduino':
        'desconectar Arduino',

    'Connect Arduino':
        'Conectar Arduino',

    'Disconnect Arduino':
        'Desconectar Arduino',

    'arduino connected?':
        'Arduino está conectado?',

    'analog reading %analogPin':
        'lectura analóxica %analogPin',

    'digital reading %digitalPin':
        'lectura dixital %digitalPin',

    'connect arduino at %s':
        'conectar Arduino ao porto %s',

    'disconnect arduino':
        'desconectar Arduino',

    'setup digital pin %digitalPin as %pinMode':
        'configurar pin %digitalPin como %pinMode',

    'set digital pin %digitalPin to %b':
        'fixar pin dixital %digitalPin en %b',

    'set servo %digitalPin to %servoValue':
        'fixar servo %digitalPin en %servoValue',

    'set pin %pwmPin to value %n':
        'fixar pin %pwmPin ao valor %n',

    'Connecting board at port\n':
        'Conectando tarxeta no porto\n',

    'An Arduino board has been connected. Happy prototyping!':
        'Conectouse satisfactoriamente unha tarxeta Arduino.\n¡Feliz prototipaxe!',

    'Board was disconnected from port\n':
        'Desconectouse a tarxeta do porto\n',

    'It seems that someone pulled the cable!':
        'Parece que alguén desconectou o cable!',

    'Error connecting the board.':
        'Produciuse un erro ao conectar a tarxeta',

    'There is already a board connected to this sprite':
        'Xa existe unha tarxeta conectada a este obxecto',

    'Could not connect an Arduino\nNo boards found':
        'Non se puido conectar un Arduino\nNon se atopou ningunha tarxeta',

    'Could not talk to Arduino in port\n':
        'Non se puido comunicar con Arduino no porto\n',

    'Check if firmata is loaded.':
        'Verifique se o firmware Firmata foi cargado.',

    'An error was detected on the board\n\n':
        'Detectouse un erro na tarxeta\n\n',

    'Board is not connected':
        'A tarxeta non está conectada',

    'New Arduino translatable project':
        'Novo proxecto traducible a Arduino',

    'select a port':
        'seleccione un porto',

    'Network port':
        'Porto de rede',

    'Enter hostname or ip address:':
        'Introduza o nome da máquina ou o seu enderezo IP',

    'Connecting to network port:\n':
        'Conectando ao porto de rede:\n',

    'This may take a few seconds...':
        'isto pode levar uns segundos...',

    'Network serial ports':
        'Portos serie sobre rede'

    'Open from URL...':
        'Abrir dende un URL...',

    'Save, share and get URL...':
        'Garda, comparte e amosa o URL...',

    'This project is now public at the following URL:':
        'Este proxecto é público, accesíbel dende o URL:',

    'About Snap4Arduino...':
        'Sobre Snap4Arduino...',

    'Snap4Arduino website':
        'Web do Snap4Arduino',

    'Snap4Arduino repository':
        'Repositoro do Snap4Arduino',

    'Start a Snap Jr. session':
        'Iniciar unha sesión de Snap Junior',

    'Start Snap4Arduino in an\nicon-based blocks mode\nfor the youngest programmers':
        'Inicia Snap4Arduino nun\nmodo de bloques con iconas\npara os/as programadores/as máis novos/as',

    'Loading Snap Jr.':
        'Snap Junior está a cargarse',

    'HTTP server':
        'Servidor HTTP',

    'uncheck to stop\nHTTP server':
        'desmarque para deter\no servidor HTTP',

    'check to start\nHTTP server, allowing\nremote control\nof Snap4Arduino':
        'márqueo para iniciar\no servidor HTTP, permitindo\no control remoto\nde Snap4Arduino',

    'Public stage':
        'Escenario público',

    'uncheck to prevent the stage\nfrom being viewed\nfrom the HTTP server':
        'desmarqueo para evitar que o escenario\nsexa visto dende o servidor HTTP',

    'check to allow the stage\nto be viewed\nfrom the HTTP server':
        'márqueo para permitir que o escenario\nsexa visto dende o servidor HTTP',
    'red':
        'vermello',
    'blue':
        'azul',
    'SnapJunior Blocks':
        'Bloques do Snap Junior',
    'SnapJuniorPlus Blocks':
        'Máis bloques para o Snap Junior',
    'Icon-based blocks for the youngest programmers.':
        'Bloques con iconas para os programadores e programadoras máis novos/as.',
    'Extra blocks for SnapJunior.':
        'Bloques para engadir funcionalidades ao Snap Junior',
    'Blocks for TdRSTEAM shield v1, using SA5Firmata firmware.':
        'Bloques para a TdRSTEAM v1, empregado o SA5Firmata.',
    'Blocks for TdRSTEAM shield v2, using SA5Firmata firmware.':
        'Bloques para a TdRSTEAM v2, empregando o SA5Firmata.',
    'Libraries below this point are specific to Snap4Arduino.':
        'As bibliotecas baixo este punto son específicas para Snap4Arduino.',
    'End of Snap4Arduino libraries.':
        'Final das bibliotecas do Snap4Arduino.'

};

// Add attributes to original SnapTranslator.dict.gl
for (var attrname in s4aTempDict) { SnapTranslator.dict.gl[attrname] = s4aTempDict[attrname]; }
<commit_msg>Galego locale issue fixed by Miguel Bouzada<commit_after>s4aTempDict = {

/*
    Special characters: (see <http://0xcc.net/jsescape/>)
    Ä, ä   \u00c4, \u00e4
    Ö, ö   \u00d6, \u00f6
    Ü, ü   \u00dc, \u00fc
    ß      \u00df
*/
    // primitive blocks:

    /*
        Attention Translators:
        ----------------------
        At this time your translation of block specs will only work
        correctly, if the order of formal parameters and their types
        are unchanged. Placeholders for inputs (formal parameters) are
        indicated by a preceding % prefix and followed by a type
        abbreviation.
        For example:
            'say %s for %n secs'
        can currently not be changed into
            'say %n secs long %s'
        and still work as intended.
        Similarly
            'point towards %dst'
        cannot be changed into
            'point towards %cst'
        without breaking its functionality.
    */

    // arduino:

    'digital input':
        'entrada dixital',

    'digital output':
        'saída dixital',

    'PWM':
        'PWM',

    'servo':
        'servo',

    'clockwise':
        'sentido horario',

    'clockwise (1500-1000)':
        'sentido horario (1500-1000)',

    'counter-clockwise':
        'sentido anti-horario',

    'counter-clockwise (1500-2000)':
        'sentido anti-horario (1500-2000)',

    'stopped':
        'parado',

    'stopped (1500)':
        'parado (1500)',

    'disconnected':
        'desconectado',

    'angle (0-180)':
        'ángulo (0-180)',

    'connect to Arduino':
        'conectar a Arduino',

    'disconnect Arduino':
        'desconectar Arduino',

    'Connect Arduino':
        'Conectar Arduino',

    'Disconnect Arduino':
        'Desconectar Arduino',

    'arduino connected?':
        'Arduino está conectado?',

    'analog reading %analogPin':
        'lectura analóxica %analogPin',

    'digital reading %digitalPin':
        'lectura dixital %digitalPin',

    'connect arduino at %s':
        'conectar Arduino ao porto %s',

    'disconnect arduino':
        'desconectar Arduino',

    'setup digital pin %digitalPin as %pinMode':
        'configurar pin %digitalPin como %pinMode',

    'set digital pin %digitalPin to %b':
        'fixar pin dixital %digitalPin en %b',

    'set servo %digitalPin to %servoValue':
        'fixar servo %digitalPin en %servoValue',

    'set pin %pwmPin to value %n':
        'fixar pin %pwmPin ao valor %n',

    'Connecting board at port\n':
        'Conectando tarxeta no porto\n',

    'An Arduino board has been connected. Happy prototyping!':
        'Conectouse satisfactoriamente unha tarxeta Arduino.\nFeliz prototipaxe!',

    'Board was disconnected from port\n':
        'Desconectouse a tarxeta do porto\n',

    'It seems that someone pulled the cable!':
        'Parece que alguén desconectou o cable!',

    'Error connecting the board.':
        'Produciuse un erro ao conectar a tarxeta',

    'There is already a board connected to this sprite':
        'Xa existe unha tarxeta conectada a este obxecto',

    'Could not connect an Arduino\nNo boards found':
        'Non se puido conectar un Arduino\nNon se atopou ningunha tarxeta',

    'Could not talk to Arduino in port\n':
        'Non se puido comunicar con Arduino no porto\n',

    'Check if firmata is loaded.':
        'Verifique se o firmware Firmata foi cargado.',

    'An error was detected on the board\n\n':
        'Detectouse un erro na tarxeta\n\n',

    'Board is not connected':
        'A tarxeta non está conectada',

    'New Arduino translatable project':
        'Novo proxecto traducible a Arduino',

    'select a port':
        'seleccione un porto',

    'Network port':
        'Porto de rede',

    'Enter hostname or ip address:':
        'Introduza o nome da máquina ou o seu enderezo IP',

    'Connecting to network port:\n':
        'Conectando ao porto de rede:\n',

    'This may take a few seconds...':
        'isto pode levar uns segundos...',

    'Network serial ports':
        'Portos serie sobre rede'

    'Open from URL...':
        'Abrir dende un URL...',

    'Save, share and get URL...':
        'Garda, comparte e amosa o URL...',

    'This project is now public at the following URL:':
        'Este proxecto é público, accesíbel dende o URL:',

    'About Snap4Arduino...':
        'Sobre Snap4Arduino...',

    'Snap4Arduino website':
        'Web do Snap4Arduino',

    'Snap4Arduino repository':
        'Repositoro do Snap4Arduino',

    'Start a Snap Jr. session':
        'Iniciar unha sesión de Snap Junior',

    'Start Snap4Arduino in an\nicon-based blocks mode\nfor the youngest programmers':
        'Inicia Snap4Arduino nun\nmodo de bloques con iconas\npara os/as programadores/as máis novos/as',

    'Loading Snap Jr.':
        'Snap Junior está a cargarse',

    'HTTP server':
        'Servidor HTTP',

    'uncheck to stop\nHTTP server':
        'desmarque para deter\no servidor HTTP',

    'check to start\nHTTP server, allowing\nremote control\nof Snap4Arduino':
        'márqueo para iniciar\no servidor HTTP, permitindo\no control remoto\nde Snap4Arduino',

    'Public stage':
        'Escenario público',

    'uncheck to prevent the stage\nfrom being viewed\nfrom the HTTP server':
        'desmarqueo para evitar que o escenario\nsexa visto dende o servidor HTTP',

    'check to allow the stage\nto be viewed\nfrom the HTTP server':
        'márqueo para permitir que o escenario\nsexa visto dende o servidor HTTP',
    'red':
        'vermello',
    'blue':
        'azul',
    'SnapJunior Blocks':
        'Bloques do Snap Junior',
    'SnapJuniorPlus Blocks':
        'Máis bloques para o Snap Junior',
    'Icon-based blocks for the youngest programmers.':
        'Bloques con iconas para os programadores e programadoras máis novos/as.',
    'Extra blocks for SnapJunior.':
        'Bloques para engadir funcionalidades ao Snap Junior',
    'Blocks for TdRSTEAM shield v1, using SA5Firmata firmware.':
        'Bloques para a TdRSTEAM v1, empregado o SA5Firmata.',
    'Blocks for TdRSTEAM shield v2, using SA5Firmata firmware.':
        'Bloques para a TdRSTEAM v2, empregando o SA5Firmata.',
    'Libraries below this point are specific to Snap4Arduino.':
        'As bibliotecas baixo este punto son específicas para Snap4Arduino.',
    'End of Snap4Arduino libraries.':
        'Final das bibliotecas do Snap4Arduino.'

};

// Add attributes to original SnapTranslator.dict.gl
for (var attrname in s4aTempDict) { SnapTranslator.dict.gl[attrname] = s4aTempDict[attrname]; }
<|endoftext|>


<commit_before>import {bindable, bindingMode} from 'aurelia-framework';

export class schemaFormCustomElement {

  @bindable schema

  @bindable({defaultBindingMode: bindingMode.twoWay})
  model

  // constructor(formElement) {
  //   this.element = formElement;
  // }

  // attached () {
  //   if (this.model.hasValidation && this.model.hasValidation()) {
  //     this.validation = this.model.getValidation();
  //   }
  // }

  // submit () {
  //   return this.onSubmit();
  // }

  // onSubmit () {
  //   if (this.model.hasValidation && !this.model.hasValidation()) {
  //     return this.element.dispatchEvent(new CustomEvent('complete', this.model.asObject()));
  //   }

  //   this.validation.validate()
  //     .then(() => {
  //       this.element.dispatchEvent(new CustomEvent('complete', this.model.asObject()));
  //     })
  //     .catch(error => {});
  // }

}
<commit_msg>fix(form): typo fix<commit_after>import {bindable, bindingMode} from 'aurelia-framework';

export class SchemaFormCustomElement {
  @bindable schema

  @bindable({defaultBindingMode: bindingMode.twoWay})
  model
}
<|endoftext|>


<commit_before>'use strict'

const express = require('express')
const exphbs = require('express-handlebars')
const app = express()
const _ = require('lodash')
const path = require('path')
const config = require('./../config')
const logger = require('./../infrastructure').logger
const diagramMetadata = require('./../infrastructure').diagramMetadata

const port = process.env.PORT || 3000

module.exports = () => {
  let viewData = _.cloneDeep(config)
  let directories = diagramMetadata.getDiagramDirectories()
  viewData.directories = _.filter(directories, (dir) => dir.serve)
  viewData.directories.forEach((directory) => {
    const fileDir = `${directory.path}/${config.assetDirectory}`
    const webDir = `/static/${directory.path}`
    logger.info(`Serving files from '${fileDir}' at '${webDir}'`)
    app.use(webDir, express.static(fileDir))
    app.use(express.static('static'))
  })

  app.engine('handlebars', exphbs({
    defaultLayout: 'main'
  }))
  const viewPath = path.resolve(`${__dirname}/../../views`)
  logger.info(`Serving views from: ${viewPath}`)
  app.set('views', viewPath)

  app.set('view engine', 'handlebars')

  app.get('/', function (req, res) {
    res.render('home', viewData)
  })

  app.listen(port, () => {
    logger.info(`Listening on port ${port}`)
  })
}
<commit_msg>Layout bug fixed<commit_after>'use strict'

const express = require('express')
const exphbs = require('express-handlebars')
const app = express()
const _ = require('lodash')
const path = require('path')
const config = require('./../config')
const logger = require('./../infrastructure').logger
const diagramMetadata = require('./../infrastructure').diagramMetadata

const port = process.env.PORT || 3000

module.exports = () => {
  let viewData = _.cloneDeep(config)
  let directories = diagramMetadata.getDiagramDirectories()
  viewData.directories = _.filter(directories, (dir) => dir.serve)
  viewData.directories.forEach((directory) => {
    const fileDir = `${directory.path}/${config.assetDirectory}`
    const webDir = `/static/${directory.path}`
    logger.info(`Serving files from '${fileDir}' at '${webDir}'`)
    app.use(webDir, express.static(fileDir))
    app.use(express.static('static'))
  })

  const viewPath = path.resolve(`${__dirname}/../../views`)
  logger.info(`Serving views from: ${viewPath}`)
  app.set('views', viewPath)

  app.engine('handlebars', exphbs({
    defaultLayout: 'main',
    layoutsDir: `${viewPath}/layouts`
  }))
  app.set('view engine', 'handlebars')

  app.get('/', function (req, res) {
    res.render('home', viewData)
  })

  app.listen(port, () => {
    logger.info(`Listening on port ${port}`)
  })
}
<|endoftext|>


<commit_before>import URL from 'url'
import http from 'http'
import child_process from "child_process"
import fs from 'fs'
import paths from 'path'
import {
    file_exists,
    getConfigDir,
    read_task_config,
    log,
    copy_object_props,
    checkTaskMissing
} from "./amx_common.js"

function ERROR(res,str) {
    log("ERROR",str);
    res.statusCode = 500;
    res.setHeader('Content-Type','application/json');
    res.write(JSON.stringify({status:'error','message':str}));
    res.end();
}

function SUCCESS(res,str) {
    log("SUCCESS",str);
    res.statusCode = 200;
    res.setHeader('Content-Type','application/json');
    res.write(JSON.stringify({status:'success','message':str}));
    res.end();
}

function listProcesses() {
    return new Promise((res,rej) => {
        child_process.exec('ps ax -o pid=',(err,stdout) => {
            let lines = stdout.split('\n');
            lines = lines.map((line) =>parseInt(line))
            lines = lines.filter((line) => !isNaN(line))
            res(lines)
        });
    })
}

const handle_status = async (req,res) => {
    res.statusCode = 200;
    res.setHeader('Content-Type','application/json');
    res.write(JSON.stringify({'status':'alive'}));
    res.end();
}

const handle_list = async (req, res) => {
    let pids = await listProcesses()
    res.statusCode = 200;
    const list = await fs.promises.readdir(getConfigDir())
    res.setHeader('Content-Type', 'application/json');
    let configs = await Promise.all(list.map(async (name) => await read_task_config(name)))
    let tasks = await Promise.all(configs.map(async config => {
        let running = false
        const pid = await getTaskPid(config.name)
        if (pids.indexOf(pid) >= 0) running = true;
        return {
            name: config.name,
            path: paths.join(getConfigDir(), config.name),
            running: running,
            pid: pid,
            archived: config.archived,
        }
    }))
    res.write(JSON.stringify({'count': tasks.length, tasks: tasks}));
    res.end();
}

function parseTaskName(req) {
    return URL.parse(req.url).query.split('=')[1]
}

async function taskExists(task) {
    if (!task) return false
    return await file_exists(paths.join(getConfigDir(), task))
}

async function getTaskPid(task) {
    const pidfile = paths.join(getConfigDir(),task,'pid');
    if(!(await file_exists(pidfile))) return -1
    let raw = await fs.promises.readFile(pidfile)
    return parseInt(raw.toString());
}

const task_map = {};
function getTaskRestartInfo(taskname) {
    if(!task_map[taskname]) { task_map[taskname] = { restart_times:[], enabled:true } }
    return task_map[taskname];
}

async function reallyStartTask(task, cb) {
    log("realling starting the task", task)
    const config = await read_task_config(task)
    const taskdir = paths.join(getConfigDir(), task)
    if (!(await file_exists(config.directory))) throw new Error("directory does not exist " + config.directory)
    let cargs = []
    let command = null
    if (config.type === 'npm') {
        cargs = ['run', config.script];
        command = 'npm';
    }
    if (config.type === 'node') {
        cargs = [config.script];
        command = 'node';
    }
    if (config.type === 'exe') {
        cargs = []
        if (config.args) cargs = config.args
        command = config.script
    }
    if (command === null) throw new Error("unknown script type " + config.type)
    const opts = {
        cwd: config.directory,
        detached: true,
        stdio: [
            'ignore',
            fs.openSync(paths.join(taskdir, 'stdout.log'), 'a'),  // Standard Out
            fs.openSync(paths.join(taskdir, 'stderr.log'), 'a'),  // Standard Error
        ],
        env: {}
    };
    copy_object_props(process.env, opts.env);
    if (config.env) copy_object_props(config.env, opts.env);
    const child = child_process.spawn(command, cargs, opts)
    child.on('error', err => log("error spawning ", command))
    await fs.promises.writeFile(paths.join(taskdir,'pid'), '' + child.pid);
    child.unref();
    log("done starting. returning pid")
    return child.pid
}

async function startTask(task) {
    const pid = await getTaskPid(task)
    log("trying to start", task, 'pid is',pid);
    getTaskRestartInfo(task).enabled = true;
    const info = await read_task_config(task)
    // log("task info is",info)
    if(info.archived === true) {
        log("the task is archived")
        getTaskRestartInfo(task).enabled = false;
        return -1
    }
    if('restart' in info && info.restart === false) {
        log("only run the task once")
        getTaskRestartInfo(task).enabled = false;
    }
    let pids = await listProcesses()
    if(pids.indexOf(pid)>=0)  throw new Error(`task is already running: ${task} ${pid}`);
    return reallyStartTask(task)
}

const handle_start = async (req,res) => {
    const task = parseTaskName(req);
    try {
        if (!(await taskExists(task))) return ERROR(res, "no such task " + task);
        let cpid = await startTask(task)
        SUCCESS(res, "started task " + task + ' ' + cpid)
    } catch (e) {
        console.error("ERROR!",e)
        ERROR(res, "error" + e)
    }
}

async function stopTask(task, cb) {
    getTaskRestartInfo(task).enabled = false;
    const pid = await getTaskPid(task);
    let pids = await listProcesses()
    if (pids.indexOf(pid) >= 0) {
        log("killing the pid", pid)
        process.kill(pid, 'SIGINT');
        return null
    } else {
        log("couldn't find the pid")
        return "process not running"
    }
}

const handle_stop = async (req,res) => {
    try {
        const task = parseTaskName(req);
        if (!(await taskExists(task))) return ERROR(res, "no such task " + task);
        await stopTask(task)
        SUCCESS(res, "successfully killed " + task)
    } catch(err) {
        ERROR(res,"error from killing " + err)
    }
}

const handle_stopserver = async (req,res) => {
    SUCCESS(res,"stopping the server");
    await setTimeout(() => process.exit(-1),100);
}
const handle_restart = async (req,res) => {
    const task = parseTaskName(req)
    if (!(await taskExists(task))) return ERROR(res, "no such task " + task);
    await stopTask(task)
    let cpid = await startTask(task)
    SUCCESS(res, "started task " + task + ' ' + cpid)
}

const handlers = {
    '/status': handle_status,
    '/list': handle_list,
    '/stop': handle_stop,
    '/start': handle_start,
    '/restart':handle_restart,
    '/stopserver':handle_stopserver,
    '/rescan':function(req,res) {
        const task = parseTaskName(req);
        if(!task) return ERROR(res,"no task specified");
    },
    '/webhook': async function (req, res) {
        log("got a webhook");
        const parts = URL.parse(req.url)
        log("path = ", parts.pathname);
        log("headers = ", req.headers);
        const taskname = parts.pathname.substring('/webhook/'.length)
        log("taskname = ", taskname);
        await checkTaskMissing(taskname)
        const config = await read_task_config(taskname)
        log("config is",config)
        if (!config.watch) return ERROR(res, "task not configured for watching");
        parsePost(req, function (err, payload) {
            if (!validateSecret(payload, config, req.headers)) return ERROR(res, "webhook validation failed")
            const task = taskname
            if (!taskExists(task)) return ERROR(res, "no such task " + taskname);
            log("got the webhook to refresh the process");
            stopTask(taskname).then(() => {
                log("task is stopped");
                updateTask(taskname, function () {
                    log("task is updated");
                    startTask(taskname).then(() => {
                        log("task is started");
                        return SUCCESS(res, "got the webhook");
                    });
                });
            });
        });
    }
};

export function make_server() {
    return http.createServer(function(req,res) {
        console.log("inside the request",req.url)
        const parts = URL.parse(req.url)
        let pathname = parts.pathname
        console.log("pathname is",pathname)
        // if(parts.pathname.indexOf('/webhook')>=0) pathname = '/webhook'
        if(handlers[pathname]) {
            try {
                return handlers[pathname](req, res)
                    .catch(e => {
                        log("ERROR with handler",pathname)
                        console.error(e)
                        ERROR(res, "error" + e)
                    })
            } catch (e) {
                try {
                    ERROR(res, "error" + e)
                } catch (ee) {
                    console.log("final error")
                    console.error(ee)
                    res.end()
                    return
                }
            }
        }
        log("no handler");
        res.statusCode = 200;
        res.setHeader('Content-Type','text/json');
        res.write(JSON.stringify({'status':'alive'}));
        res.end();
    })
}<commit_msg>code cleanup<commit_after>import URL from 'url'
import http from 'http'
import child_process from "child_process"
import fs from 'fs'
import paths from 'path'
import {
    file_exists,
    getConfigDir,
    read_task_config,
    log,
    copy_object_props,
    checkTaskMissing
} from "./amx_common.js"

function ERROR(res,str) {
    log("ERROR",str);
    res.statusCode = 500;
    res.setHeader('Content-Type','application/json');
    res.write(JSON.stringify({status:'error','message':str}));
    res.end();
}

function SUCCESS(res,str) {
    log("SUCCESS",str);
    res.statusCode = 200;
    res.setHeader('Content-Type','application/json');
    res.write(JSON.stringify({status:'success','message':str}));
    res.end();
}

function listProcesses() {
    return new Promise((res,rej) => {
        child_process.exec('ps ax -o pid=',(err,stdout) => {
            let lines = stdout.split('\n');
            lines = lines.map((line) =>parseInt(line))
            lines = lines.filter((line) => !isNaN(line))
            res(lines)
        });
    })
}

const handle_status = async (req,res) => {
    res.statusCode = 200;
    res.setHeader('Content-Type','application/json');
    res.write(JSON.stringify({'status':'alive'}));
    res.end();
}
const handle_list = async (req, res) => {
    let pids = await listProcesses()
    res.statusCode = 200;
    const list = await fs.promises.readdir(getConfigDir())
    res.setHeader('Content-Type', 'application/json');
    let configs = await Promise.all(list.map(async (name) => await read_task_config(name)))
    let tasks = await Promise.all(configs.map(async config => {
        let running = false
        const pid = await getTaskPid(config.name)
        if (pids.indexOf(pid) >= 0) running = true;
        return {
            name: config.name,
            path: paths.join(getConfigDir(), config.name),
            running: running,
            pid: pid,
            archived: config.archived,
        }
    }))
    res.write(JSON.stringify({'count': tasks.length, tasks: tasks}));
    res.end();
}
const handle_stopserver = async (req,res) => {
    SUCCESS(res,"stopping the server");
    await setTimeout(() => process.exit(-1),100);
}

const handle_start = async (req,res) => {
    const taskname = parseTaskName(req);
    await checkTaskMissing(taskname)
    let cpid = await startTask(taskname)
    SUCCESS(res, "started task " + taskname + ' ' + cpid)
}
const handle_stop = async (req,res) => {
    const taskname = parseTaskName(req);
    await checkTaskMissing(taskname)
    await stopTask(taskname)
    SUCCESS(res, "successfully killed " + taskname)
}
const handle_restart = async (req,res) => {
    const task = parseTaskName(req)
    await checkTaskMissing(taskname)
    await stopTask(task)
    let cpid = await startTask(task)
    SUCCESS(res, "started task " + task + ' ' + cpid)
}

const handle_rescan = async (req,res) => {
    const task = parseTaskName(req);
    if(!task) return ERROR(res,"no task specified");
}
const handle_webhook = async (req,res) => {
    log("got a webhook");
    const parts = URL.parse(req.url)
    log("path = ", parts.pathname);
    log("headers = ", req.headers);
    const taskname = parts.pathname.substring('/webhook/'.length)
    log("taskname = ", taskname);
    await checkTaskMissing(taskname)
    const config = await read_task_config(taskname)
    log("config is",config)
    if (!config.watch) return ERROR(res, "task not configured for watching");
    parsePost(req, function (err, payload) {
        if (!validateSecret(payload, config, req.headers)) return ERROR(res, "webhook validation failed")
        const task = taskname
        if (!taskExists(task)) return ERROR(res, "no such task " + taskname);
        log("got the webhook to refresh the process");
        stopTask(taskname).then(() => {
            log("task is stopped");
            updateTask(taskname, function () {
                log("task is updated");
                startTask(taskname).then(() => {
                    log("task is started");
                    return SUCCESS(res, "got the webhook");
                });
            });
        });
    })
}

function parseTaskName(req) {
    return URL.parse(req.url).query.split('=')[1]
}

async function taskExists(task) {
    if (!task) return false
    return await file_exists(paths.join(getConfigDir(), task))
}

async function getTaskPid(task) {
    const pidfile = paths.join(getConfigDir(),task,'pid');
    if(!(await file_exists(pidfile))) return -1
    let raw = await fs.promises.readFile(pidfile)
    return parseInt(raw.toString());
}

const task_map = {};
function getTaskRestartInfo(taskname) {
    if(!task_map[taskname]) { task_map[taskname] = { restart_times:[], enabled:true } }
    return task_map[taskname];
}

async function reallyStartTask(task, cb) {
    log("realling starting the task", task)
    const config = await read_task_config(task)
    const taskdir = paths.join(getConfigDir(), task)
    if (!(await file_exists(config.directory))) throw new Error("directory does not exist " + config.directory)
    let cargs = []
    let command = null
    if (config.type === 'npm') {
        cargs = ['run', config.script];
        command = 'npm';
    }
    if (config.type === 'node') {
        cargs = [config.script];
        command = 'node';
    }
    if (config.type === 'exe') {
        cargs = []
        if (config.args) cargs = config.args
        command = config.script
    }
    if (command === null) throw new Error("unknown script type " + config.type)
    const opts = {
        cwd: config.directory,
        detached: true,
        stdio: [
            'ignore',
            fs.openSync(paths.join(taskdir, 'stdout.log'), 'a'),  // Standard Out
            fs.openSync(paths.join(taskdir, 'stderr.log'), 'a'),  // Standard Error
        ],
        env: {}
    };
    copy_object_props(process.env, opts.env);
    if (config.env) copy_object_props(config.env, opts.env);
    const child = child_process.spawn(command, cargs, opts)
    child.on('error', err => log("error spawning ", command))
    await fs.promises.writeFile(paths.join(taskdir,'pid'), '' + child.pid);
    child.unref();
    log("done starting. returning pid")
    return child.pid
}

async function startTask(task) {
    const pid = await getTaskPid(task)
    log("trying to start", task, 'pid is',pid);
    getTaskRestartInfo(task).enabled = true;
    const info = await read_task_config(task)
    // log("task info is",info)
    if(info.archived === true) {
        log("the task is archived")
        getTaskRestartInfo(task).enabled = false;
        return -1
    }
    if('restart' in info && info.restart === false) {
        log("only run the task once")
        getTaskRestartInfo(task).enabled = false;
    }
    let pids = await listProcesses()
    if(pids.indexOf(pid)>=0)  throw new Error(`task is already running: ${task} ${pid}`);
    return reallyStartTask(task)
}

async function stopTask(task, cb) {
    getTaskRestartInfo(task).enabled = false;
    const pid = await getTaskPid(task);
    let pids = await listProcesses()
    if (pids.indexOf(pid) >= 0) {
        log("killing the pid", pid)
        process.kill(pid, 'SIGINT');
        return null
    } else {
        log("couldn't find the pid")
        return "process not running"
    }
}

const handlers = {
    '/status': handle_status,
    '/list': handle_list,
    '/stop': handle_stop,
    '/start': handle_start,
    '/restart':handle_restart,
    '/stopserver':handle_stopserver,
    '/rescan': handle_rescan,
    '/webhook': handle_webhook,
};

export function make_server() {
    return http.createServer(function(req,res) {
        console.log("inside the request",req.url)
        const parts = URL.parse(req.url)
        let pathname = parts.pathname
        console.log("pathname is",pathname)
        // if(parts.pathname.indexOf('/webhook')>=0) pathname = '/webhook'
        if(handlers[pathname]) {
            try {
                return handlers[pathname](req, res)
                    .catch(e => {
                        log("ERROR with handler",pathname)
                        console.error(e)
                        ERROR(res, "error" + e)
                    })
            } catch (e) {
                try {
                    ERROR(res, "error" + e)
                } catch (ee) {
                    console.log("final error")
                    console.error(ee)
                    res.end()
                    return
                }
            }
        }
        log("no handler");
        res.statusCode = 200;
        res.setHeader('Content-Type','text/json');
        res.write(JSON.stringify({'status':'alive'}));
        res.end();
    })
}<|endoftext|>


<commit_before>#! /usr/bin/env node

'use strict';

var config = require('../../twl.config.json')
var path = require('path')
var fs = require('fs-extra')
var tar = require('tar-fs')

function checkBackup(project, name) {
  return new Promise(function (resolve, reject) {
    var backup = path.join(__dirname, '../.temp/', name + '.tar.backup')
    fs.stat(backup, function (err, stats) {
      if (!err) {
        resolve({ project: project, backup: backup })
      } else {
        console.log('Could not find a backup file!')
        reject()
      }
    })
  })
}

function clearDir(args) {
  return new Promise(function (resolve, reject) {
    fs.emptyDir(args.project.path, function (e) {
      if (!e) {
        resolve(args)
      } else {
        reject()
      }
    })
  })
}

function restore(args) {
  fs.createReadStream(args.backup).pipe(tar.extract(args.project.path, { dmode: '0555', fmode: '0444' }))
  console.log('Rollback complete.')
}

function rollback(name) {
  var project = config.projects[name]
  if (!project) {
    console.log('Invalid project')
  } else {
    checkBackup(project, name)
      .then(clearDir)
      .then(restore)
  }
}

function list() {
  var projects = config['projects']
  for (var k in projects) {
    console.log(k, ' : ', projects[k])
  }
}

module.exports = {
  rollback: rollback,
  list: list
}

<commit_msg>fixed broken rollback<commit_after>#! /usr/bin/env node

'use strict';

var config = require('../../twl.config.json')
var path = require('path')
var fs = require('fs-extra')
var tar = require('tar-fs')
var Promise = require('promise')

function checkBackup(project, name) {
  return new Promise(function (resolve, reject) {
    var backup = path.join(__dirname, '../.temp/', name + '-artifact.tar.backup')
    fs.stat(backup, function (err, stats) {
      if (!err) {
        resolve({ project: project, backup: backup })
      } else {
        console.log('Could not find a backup file!')
        reject()
      }
    })
  })
}

function clearDir(args) {
  return new Promise(function (resolve, reject) {
    fs.emptyDir(args.project.path, function (e) {
      if (!e) {
        resolve(args)
      } else {
        reject()
      }
    })
  })
}

function restore(args) {
  fs.createReadStream(args.backup).pipe(tar.extract(args.project.path, { dmode: '0555', fmode: '0444' }))
  console.log('Rollback complete.')
}

function rollback(name) {
  var project = config.projects[name]
  if (!project) {
    console.log('Invalid project')
  } else {
    checkBackup(project, name)
      .then(clearDir)
      .then(restore)
  }
}

function list() {
  var projects = config['projects']
  for (var k in projects) {
    console.log(k, ' : ', projects[k])
  }
}

module.exports = {
  rollback: rollback,
  list: list
}

<|endoftext|>


<commit_before>/**
 * Creates a module that listens to the given form for a new location, adds it
 * to the map, and pans/zooms the map.
 * @constructor
 * @param {GEPlugin} plugin An instance of GoogleEarthExtensions
 * @param {HTMLFormElement} location A form with a single text input for a location to geocode
 */
lingcod.map.geocoder = function(gex, form){
    // Will need to have google maps api v3 already loaded
    this.geocoder = new google.maps.Geocoder();
    this.form = form;
    this.get = ge;
    var self = this;
    $(this.form).submit(function(e){
        e.preventDefault();
        var location = $(this).find('input:first').val();
        self.geocoder.geocode({ address: location, country: '.us'}, function(results, status){
            if(status == google.maps.GeocoderStatus.OK && results.length){
                if(status != google.maps.GeocoderStatus.ZERO_RESULTS){
                    var point = results[0].geometry.location;
                    var lookAt = ge.getView().copyAsLookAt(ge.ALTITUDE_RELATIVE_TO_GROUND);
                    lookAt.setLatitude(point.lat());
                    lookAt.setLongitude(point.lng());
                    ge.getView().setAbstractView(lookAt);
                    var p = gex.dom.addPointPlacemark([point.lat(), point.lng()], {
                      // stockIcon: 'pal3/icon60.png',
                      name: location,
                    });
                }else{
                    alert("geocoder didn't find any results.");
                }
            }else{
                alert("Geocoder failed due to: " + status);
            }
        });
    });
}

/**
 * Prepare instance for destruction by remove event listeners.
 */
lingcod.map.geocoder.prototype.destroy = function(){
    $(this.form).unbind('submit');
}<commit_msg>removed extra comma<commit_after>/**
 * Creates a module that listens to the given form for a new location, adds it
 * to the map, and pans/zooms the map.
 * @constructor
 * @param {GEPlugin} plugin An instance of GoogleEarthExtensions
 * @param {HTMLFormElement} location A form with a single text input for a location to geocode
 */
lingcod.map.geocoder = function(gex, form){
    // Will need to have google maps api v3 already loaded
    this.geocoder = new google.maps.Geocoder();
    this.form = form;
    this.get = ge;
    var self = this;
    $(this.form).submit(function(e){
        e.preventDefault();
        var location = $(this).find('input:first').val();
        self.geocoder.geocode({ address: location, country: '.us'}, function(results, status){
            if(status == google.maps.GeocoderStatus.OK && results.length){
                if(status != google.maps.GeocoderStatus.ZERO_RESULTS){
                    var point = results[0].geometry.location;
                    var lookAt = ge.getView().copyAsLookAt(ge.ALTITUDE_RELATIVE_TO_GROUND);
                    lookAt.setLatitude(point.lat());
                    lookAt.setLongitude(point.lng());
                    ge.getView().setAbstractView(lookAt);
                    var p = gex.dom.addPointPlacemark([point.lat(), point.lng()], {
                      // stockIcon: 'pal3/icon60.png',
                      name: location
                    });
                }else{
                    alert("geocoder didn't find any results.");
                }
            }else{
                alert("Geocoder failed due to: " + status);
            }
        });
    });
}

/**
 * Prepare instance for destruction by remove event listeners.
 */
lingcod.map.geocoder.prototype.destroy = function(){
    $(this.form).unbind('submit');
}<|endoftext|>


<commit_before>/* @flow */

import {Entity} from 'draft-js';
import {
  getEntityRanges,
  BLOCK_TYPE,
  ENTITY_TYPE,
  INLINE_STYLE,
} from 'draft-js-utils';

import type {ContentState, ContentBlock, EntityInstance} from 'draft-js';
import type {CharacterMetaList} from 'draft-js-utils';

type StringMap = {[key: string]: ?string};
type AttrMap = {[key: string]: StringMap};

const {
  BOLD,
  CODE,
  ITALIC,
  STRIKETHROUGH,
  UNDERLINE,
} = INLINE_STYLE;

const INDENT = '  ';
const BREAK = '
';

// Map entity data to element attributes.
const ENTITY_ATTR_MAP: AttrMap = {
  [ENTITY_TYPE.LINK]: {url: 'href', rel: 'rel', target: 'target', title: 'title', className: 'class'},
  [ENTITY_TYPE.IMAGE]: {src: 'src', height: 'height', width: 'width', alt: 'alt', className: 'class'},
};

// Map entity data to element attributes.
const DATA_TO_ATTR = {
  [ENTITY_TYPE.LINK](entityType: string, entity: EntityInstance): StringMap {
    let attrMap = ENTITY_ATTR_MAP.hasOwnProperty(entityType) ? ENTITY_ATTR_MAP[entityType] : {};
    let data = entity.getData();
    let attrs = {};
    for (let dataKey of Object.keys(data)) {
      let dataValue = data[dataKey];
      if (attrMap.hasOwnProperty(dataKey)) {
        let attrKey = attrMap[dataKey];
        attrs[attrKey] = dataValue;
      }
    }
    return attrs;
  },
  [ENTITY_TYPE.IMAGE](entityType: string, entity: EntityInstance): StringMap {
    let attrMap = ENTITY_ATTR_MAP.hasOwnProperty(entityType) ? ENTITY_ATTR_MAP[entityType] : {};
    let data = entity.getData();
    let attrs = {};
    for (let dataKey of Object.keys(data)) {
      let dataValue = data[dataKey];
      if (attrMap.hasOwnProperty(dataKey)) {
        let attrKey = attrMap[dataKey];
        attrs[attrKey] = dataValue;
      }
    }
    return attrs;
  },
};

// The reason this returns an array is because a single block might get wrapped
// in two tags.
function getTags(blockType: string): Array<string> {
  switch (blockType) {
    case BLOCK_TYPE.HEADER_ONE:
      return ['h1'];
    case BLOCK_TYPE.HEADER_TWO:
      return ['h2'];
    case BLOCK_TYPE.HEADER_THREE:
      return ['h3'];
    case BLOCK_TYPE.HEADER_FOUR:
      return ['h4'];
    case BLOCK_TYPE.HEADER_FIVE:
      return ['h5'];
    case BLOCK_TYPE.HEADER_SIX:
      return ['h6'];
    case BLOCK_TYPE.UNORDERED_LIST_ITEM:
    case BLOCK_TYPE.ORDERED_LIST_ITEM:
      return ['li'];
    case BLOCK_TYPE.BLOCKQUOTE:
      return ['blockquote'];
    case BLOCK_TYPE.CODE:
      return ['pre', 'code'];
    default:
      return ['p'];
  }
}

function getWrapperTag(blockType: string): ?string {
  switch (blockType) {
    case BLOCK_TYPE.UNORDERED_LIST_ITEM:
      return 'ul';
    case BLOCK_TYPE.ORDERED_LIST_ITEM:
      return 'ol';
    default:
      return null;
  }
}

class MarkupGenerator {
  blocks: Array<ContentBlock>;
  contentState: ContentState;
  currentBlock: number;
  indentLevel: number;
  output: Array<string>;
  totalBlocks: number;
  wrapperTag: ?string;

  constructor(contentState: ContentState) {
    this.contentState = contentState;
  }

  generate(): string {
    this.output = [];
    this.blocks = this.contentState.getBlocksAsArray();
    this.totalBlocks = this.blocks.length;
    this.currentBlock = 0;
    this.indentLevel = 0;
    this.wrapperTag = null;
    while (this.currentBlock < this.totalBlocks) {
      this.processBlock();
    }
    this.closeWrapperTag();
    return this.output.join('').trim();
  }

  processBlock() {
    let block = this.blocks[this.currentBlock];
    let blockType = block.getType();
    let newWrapperTag = getWrapperTag(blockType);
    if (this.wrapperTag !== newWrapperTag) {
      if (this.wrapperTag) {
        this.closeWrapperTag();
      }
      if (newWrapperTag) {
        this.openWrapperTag(newWrapperTag);
      }
    }
    this.indent();
    this.writeStartTag(blockType);
    this.output.push(this.renderBlockContent(block));
    // Look ahead and see if we will nest list.
    let nextBlock = this.getNextBlock();
    if (
      canHaveDepth(blockType) &&
      nextBlock &&
      nextBlock.getDepth() === block.getDepth() + 1
    ) {
      this.output.push(`\n`);
      // This is a litle hacky: temporarily stash our current wrapperTag and
      // render child list(s).
      let thisWrapperTag = this.wrapperTag;
      this.wrapperTag = null;
      this.indentLevel += 1;
      this.currentBlock += 1;
      this.processBlocksAtDepth(nextBlock.getDepth());
      this.wrapperTag = thisWrapperTag;
      this.indentLevel -= 1;
      this.indent();
    } else {
      this.currentBlock += 1;
    }
    this.writeEndTag(blockType);
  }

  processBlocksAtDepth(depth: number) {
    let block = this.blocks[this.currentBlock];
    while (block && block.getDepth() === depth) {
      this.processBlock();
      block = this.blocks[this.currentBlock];
    }
    this.closeWrapperTag();
  }

  getNextBlock(): ContentBlock {
    return this.blocks[this.currentBlock + 1];
  }

  writeStartTag(blockType) {
    let tags = getTags(blockType);
    for (let tag of tags) {
      this.output.push(`<${tag}>`);
    }
  }

  writeEndTag(blockType) {
    let tags = getTags(blockType);
    if (tags.length === 1) {
      this.output.push(`</${tags[0]}>\n`);
    } else {
      let output = [];
      for (let tag of tags) {
        output.unshift(`</${tag}>`);
      }
      this.output.push(output.join('') + '\n');
    }
  }

  openWrapperTag(wrapperTag: string) {
    this.wrapperTag = wrapperTag;
    this.indent();
    this.output.push(`<${wrapperTag}>\n`);
    this.indentLevel += 1;
  }

  closeWrapperTag() {
    if (this.wrapperTag) {
      this.indentLevel -= 1;
      this.indent();
      this.output.push(`</${this.wrapperTag}>\n`);
      this.wrapperTag = null;
    }
  }

  indent() {
    this.output.push(INDENT.repeat(this.indentLevel));
  }

  renderBlockContent(block: ContentBlock): string {
    let blockType = block.getType();
    let text = block.getText();
    if (text === '') {
      // Prevent element collapse if completely empty.
      return BREAK;
    }
    text = this.preserveWhitespace(text);
    let charMetaList: CharacterMetaList = block.getCharacterList();
    let entityPieces = getEntityRanges(text, charMetaList);
    return entityPieces.map(([entityKey, stylePieces]) => {
      let content = stylePieces.map(([text, style]) => {
        let content = encodeContent(text);
        // These are reverse alphabetical by tag name.
        if (style.has(BOLD)) {
          content = `<strong>${content}</strong>`;
        }
        if (style.has(UNDERLINE)) {
          content = `<ins>${content}</ins>`;
        }
        if (style.has(ITALIC)) {
          content = `<em>${content}</em>`;
        }
        if (style.has(STRIKETHROUGH)) {
          content = `<del>${content}</del>`;
        }
        if (style.has(CODE)) {
          // If our block type is CODE then we are already wrapping the whole
          // block in a `<code>` so don't wrap inline code elements.
          content = (blockType === BLOCK_TYPE.CODE) ? content : `<code>${content}</code>`;
        }
        return content;
      }).join('');
      let entity = entityKey ? Entity.get(entityKey) : null;
      let entityType = (entity == null) ? null : entity.getType();
      if (entityType != null && entityType === ENTITY_TYPE.LINK) {
        let attrs = DATA_TO_ATTR.hasOwnProperty(entityType) ? DATA_TO_ATTR[entityType](entityType, entity) : null;
        let strAttrs = stringifyAttrs(attrs);
        return `<a${strAttrs}>${content}</a>`;
      } else if (entityType != null && entityType === ENTITY_TYPE.IMAGE) {
        let attrs = DATA_TO_ATTR.hasOwnProperty(entityType) ? DATA_TO_ATTR[entityType](entityType, entity) : null;
        let strAttrs = stringifyAttrs(attrs);
        return `<img${strAttrs}/>`;
      } else {
        return content;
      }
    }).join('');
  }

  preserveWhitespace(text: string): string {
    let length = text.length;
    // Prevent leading/trailing/consecutive whitespace collapse.
    let newText = new Array(length);
    for (let i = 0; i < length; i++) {
      if (
        text[i] === ' ' &&
        (i === 0 || i === length - 1 || text[i - 1] === ' ')
      ) {
        newText[i] = '\xA0';
      } else {
        newText[i] = text[i];
      }
    }
    return newText.join('');
  }

}

function stringifyAttrs(attrs) {
  if (attrs == null) {
    return '';
  }
  let parts = [];
  for (let attrKey of Object.keys(attrs)) {
    let attrValue = attrs[attrKey];
    if (attrValue != null) {
      parts.push(` ${attrKey}="${encodeAttr(attrValue + '')}"`);
    }
  }
  return parts.join('');
}

function canHaveDepth(blockType: string): boolean {
  switch (blockType) {
    case BLOCK_TYPE.UNORDERED_LIST_ITEM:
    case BLOCK_TYPE.ORDERED_LIST_ITEM:
      return true;
    default:
      return false;
  }
}

function encodeContent(text: string): string {
  return text
    .split('&').join('&')
    .split('<').join('<')
    .split('>').join('>')
    .split('\xA0').join(' ')
    .split('\n').join(BREAK + '\n');
}

function encodeAttr(text: string): string {
  return text
    .split('&').join('&')
    .split('<').join('<')
    .split('>').join('>')
    .split('"').join('"');
}

export default function stateToHTML(content: ContentState): string {
  return new MarkupGenerator(content).generate();
}
<commit_msg>Don't self-close BREAK tag<commit_after>/* @flow */

import {Entity} from 'draft-js';
import {
  getEntityRanges,
  BLOCK_TYPE,
  ENTITY_TYPE,
  INLINE_STYLE,
} from 'draft-js-utils';

import type {ContentState, ContentBlock, EntityInstance} from 'draft-js';
import type {CharacterMetaList} from 'draft-js-utils';

type StringMap = {[key: string]: ?string};
type AttrMap = {[key: string]: StringMap};

const {
  BOLD,
  CODE,
  ITALIC,
  STRIKETHROUGH,
  UNDERLINE,
} = INLINE_STYLE;

const INDENT = '  ';
const BREAK = '
';

// Map entity data to element attributes.
const ENTITY_ATTR_MAP: AttrMap = {
  [ENTITY_TYPE.LINK]: {url: 'href', rel: 'rel', target: 'target', title: 'title', className: 'class'},
  [ENTITY_TYPE.IMAGE]: {src: 'src', height: 'height', width: 'width', alt: 'alt', className: 'class'},
};

// Map entity data to element attributes.
const DATA_TO_ATTR = {
  [ENTITY_TYPE.LINK](entityType: string, entity: EntityInstance): StringMap {
    let attrMap = ENTITY_ATTR_MAP.hasOwnProperty(entityType) ? ENTITY_ATTR_MAP[entityType] : {};
    let data = entity.getData();
    let attrs = {};
    for (let dataKey of Object.keys(data)) {
      let dataValue = data[dataKey];
      if (attrMap.hasOwnProperty(dataKey)) {
        let attrKey = attrMap[dataKey];
        attrs[attrKey] = dataValue;
      }
    }
    return attrs;
  },
  [ENTITY_TYPE.IMAGE](entityType: string, entity: EntityInstance): StringMap {
    let attrMap = ENTITY_ATTR_MAP.hasOwnProperty(entityType) ? ENTITY_ATTR_MAP[entityType] : {};
    let data = entity.getData();
    let attrs = {};
    for (let dataKey of Object.keys(data)) {
      let dataValue = data[dataKey];
      if (attrMap.hasOwnProperty(dataKey)) {
        let attrKey = attrMap[dataKey];
        attrs[attrKey] = dataValue;
      }
    }
    return attrs;
  },
};

// The reason this returns an array is because a single block might get wrapped
// in two tags.
function getTags(blockType: string): Array<string> {
  switch (blockType) {
    case BLOCK_TYPE.HEADER_ONE:
      return ['h1'];
    case BLOCK_TYPE.HEADER_TWO:
      return ['h2'];
    case BLOCK_TYPE.HEADER_THREE:
      return ['h3'];
    case BLOCK_TYPE.HEADER_FOUR:
      return ['h4'];
    case BLOCK_TYPE.HEADER_FIVE:
      return ['h5'];
    case BLOCK_TYPE.HEADER_SIX:
      return ['h6'];
    case BLOCK_TYPE.UNORDERED_LIST_ITEM:
    case BLOCK_TYPE.ORDERED_LIST_ITEM:
      return ['li'];
    case BLOCK_TYPE.BLOCKQUOTE:
      return ['blockquote'];
    case BLOCK_TYPE.CODE:
      return ['pre', 'code'];
    default:
      return ['p'];
  }
}

function getWrapperTag(blockType: string): ?string {
  switch (blockType) {
    case BLOCK_TYPE.UNORDERED_LIST_ITEM:
      return 'ul';
    case BLOCK_TYPE.ORDERED_LIST_ITEM:
      return 'ol';
    default:
      return null;
  }
}

class MarkupGenerator {
  blocks: Array<ContentBlock>;
  contentState: ContentState;
  currentBlock: number;
  indentLevel: number;
  output: Array<string>;
  totalBlocks: number;
  wrapperTag: ?string;

  constructor(contentState: ContentState) {
    this.contentState = contentState;
  }

  generate(): string {
    this.output = [];
    this.blocks = this.contentState.getBlocksAsArray();
    this.totalBlocks = this.blocks.length;
    this.currentBlock = 0;
    this.indentLevel = 0;
    this.wrapperTag = null;
    while (this.currentBlock < this.totalBlocks) {
      this.processBlock();
    }
    this.closeWrapperTag();
    return this.output.join('').trim();
  }

  processBlock() {
    let block = this.blocks[this.currentBlock];
    let blockType = block.getType();
    let newWrapperTag = getWrapperTag(blockType);
    if (this.wrapperTag !== newWrapperTag) {
      if (this.wrapperTag) {
        this.closeWrapperTag();
      }
      if (newWrapperTag) {
        this.openWrapperTag(newWrapperTag);
      }
    }
    this.indent();
    this.writeStartTag(blockType);
    this.output.push(this.renderBlockContent(block));
    // Look ahead and see if we will nest list.
    let nextBlock = this.getNextBlock();
    if (
      canHaveDepth(blockType) &&
      nextBlock &&
      nextBlock.getDepth() === block.getDepth() + 1
    ) {
      this.output.push(`\n`);
      // This is a litle hacky: temporarily stash our current wrapperTag and
      // render child list(s).
      let thisWrapperTag = this.wrapperTag;
      this.wrapperTag = null;
      this.indentLevel += 1;
      this.currentBlock += 1;
      this.processBlocksAtDepth(nextBlock.getDepth());
      this.wrapperTag = thisWrapperTag;
      this.indentLevel -= 1;
      this.indent();
    } else {
      this.currentBlock += 1;
    }
    this.writeEndTag(blockType);
  }

  processBlocksAtDepth(depth: number) {
    let block = this.blocks[this.currentBlock];
    while (block && block.getDepth() === depth) {
      this.processBlock();
      block = this.blocks[this.currentBlock];
    }
    this.closeWrapperTag();
  }

  getNextBlock(): ContentBlock {
    return this.blocks[this.currentBlock + 1];
  }

  writeStartTag(blockType) {
    let tags = getTags(blockType);
    for (let tag of tags) {
      this.output.push(`<${tag}>`);
    }
  }

  writeEndTag(blockType) {
    let tags = getTags(blockType);
    if (tags.length === 1) {
      this.output.push(`</${tags[0]}>\n`);
    } else {
      let output = [];
      for (let tag of tags) {
        output.unshift(`</${tag}>`);
      }
      this.output.push(output.join('') + '\n');
    }
  }

  openWrapperTag(wrapperTag: string) {
    this.wrapperTag = wrapperTag;
    this.indent();
    this.output.push(`<${wrapperTag}>\n`);
    this.indentLevel += 1;
  }

  closeWrapperTag() {
    if (this.wrapperTag) {
      this.indentLevel -= 1;
      this.indent();
      this.output.push(`</${this.wrapperTag}>\n`);
      this.wrapperTag = null;
    }
  }

  indent() {
    this.output.push(INDENT.repeat(this.indentLevel));
  }

  renderBlockContent(block: ContentBlock): string {
    let blockType = block.getType();
    let text = block.getText();
    if (text === '') {
      // Prevent element collapse if completely empty.
      return BREAK;
    }
    text = this.preserveWhitespace(text);
    let charMetaList: CharacterMetaList = block.getCharacterList();
    let entityPieces = getEntityRanges(text, charMetaList);
    return entityPieces.map(([entityKey, stylePieces]) => {
      let content = stylePieces.map(([text, style]) => {
        let content = encodeContent(text);
        // These are reverse alphabetical by tag name.
        if (style.has(BOLD)) {
          content = `<strong>${content}</strong>`;
        }
        if (style.has(UNDERLINE)) {
          content = `<ins>${content}</ins>`;
        }
        if (style.has(ITALIC)) {
          content = `<em>${content}</em>`;
        }
        if (style.has(STRIKETHROUGH)) {
          content = `<del>${content}</del>`;
        }
        if (style.has(CODE)) {
          // If our block type is CODE then we are already wrapping the whole
          // block in a `<code>` so don't wrap inline code elements.
          content = (blockType === BLOCK_TYPE.CODE) ? content : `<code>${content}</code>`;
        }
        return content;
      }).join('');
      let entity = entityKey ? Entity.get(entityKey) : null;
      let entityType = (entity == null) ? null : entity.getType();
      if (entityType != null && entityType === ENTITY_TYPE.LINK) {
        let attrs = DATA_TO_ATTR.hasOwnProperty(entityType) ? DATA_TO_ATTR[entityType](entityType, entity) : null;
        let strAttrs = stringifyAttrs(attrs);
        return `<a${strAttrs}>${content}</a>`;
      } else if (entityType != null && entityType === ENTITY_TYPE.IMAGE) {
        let attrs = DATA_TO_ATTR.hasOwnProperty(entityType) ? DATA_TO_ATTR[entityType](entityType, entity) : null;
        let strAttrs = stringifyAttrs(attrs);
        return `<img${strAttrs}/>`;
      } else {
        return content;
      }
    }).join('');
  }

  preserveWhitespace(text: string): string {
    let length = text.length;
    // Prevent leading/trailing/consecutive whitespace collapse.
    let newText = new Array(length);
    for (let i = 0; i < length; i++) {
      if (
        text[i] === ' ' &&
        (i === 0 || i === length - 1 || text[i - 1] === ' ')
      ) {
        newText[i] = '\xA0';
      } else {
        newText[i] = text[i];
      }
    }
    return newText.join('');
  }

}

function stringifyAttrs(attrs) {
  if (attrs == null) {
    return '';
  }
  let parts = [];
  for (let attrKey of Object.keys(attrs)) {
    let attrValue = attrs[attrKey];
    if (attrValue != null) {
      parts.push(` ${attrKey}="${encodeAttr(attrValue + '')}"`);
    }
  }
  return parts.join('');
}

function canHaveDepth(blockType: string): boolean {
  switch (blockType) {
    case BLOCK_TYPE.UNORDERED_LIST_ITEM:
    case BLOCK_TYPE.ORDERED_LIST_ITEM:
      return true;
    default:
      return false;
  }
}

function encodeContent(text: string): string {
  return text
    .split('&').join('&')
    .split('<').join('<')
    .split('>').join('>')
    .split('\xA0').join(' ')
    .split('\n').join(BREAK + '\n');
}

function encodeAttr(text: string): string {
  return text
    .split('&').join('&')
    .split('<').join('<')
    .split('>').join('>')
    .split('"').join('"');
}

export default function stateToHTML(content: ContentState): string {
  return new MarkupGenerator(content).generate();
}
<|endoftext|>


<commit_before>class Boot extends Phaser.State {

    constructor() {
	super();
    }

    preload() {
	this.load.image('preloader', 'assets/preloader.gif');

	// JSON
	this.game.load.json('assets', './assets.json');
    }

    create() {
	this.game.input.maxPointers = 1;

	this.game.scale.scaleMode = Phaser.ScaleManager.USER_SCALE;
	this.game.scale.pageAlignHorizontally = true;
	this.game.scale.pageAlignVertically = true;

	this.initGlobalVariables();

	// Setup resolution
	let settings = {
	    defaultWidth: 1280;
	    defaultHeight: 800;
	    useStretchThreshold: true;
	    stretchThresholdWidth: 1420;
	    stretchThresholdHeight: 960;
	};

	this.setupResolutionSettings(settings);

	this.game.state.start('preloader');
    }

    setupResolutionSettings(settings) {
	// Setup game screen resolution
	let defaultWidth = settings.defaultWidth;
	let defaultHeight = settings.defaultHeight;

	let windowWidth = window.innerWidth;
	let windowHeight = window.innerHeight;

	let defaultRatio = defaultWidth/defaultHeight;
	let windowRatio = windowWidth/windowHeight;

	let gameWidth = defaultWidth;
	let gameHeight = defaultHeight;

	if (windowRatio < defaultRatio) {
	    gameHeight = Math.ceil((gameWidth / windowRatio) / 2.0) * 2;
	    if(settings.useStretchThreshold)
		gameHeight = Math.min(gameHeight, settings.stretchThresholdHeight);
	} else {
	    gameWidth = Math.ceil((gameHeight * windowRatio) / 2.0) * 2;
	    if(settings.useStretchThreshold)
		gameWidth = Math.min(gameWidth, settings.stretchThresholdWidth);
	}

	let scaleX = windowWidth/gameWidth;
	let scaleY = windowHeight/gameHeight;

	this.game.scale.setGameSize(gameWidth,gameHeight);
	this.game.scale.setUserScale(scaleX,scaleY);

	this.game.screenSettings.defaultWidth = defaultWidth;
	this.game.screenSettings.defaultHeight = defaultHeight;
	this.game.screenSettings.gameWidth = gameWidth;
	this.game.screenSettings.gameHeight = gameHeight;
	this.game.screenSettings.scaleX = scaleX;
	this.game.screenSettings.scaleY = scaleY;
	this.game.screenSettings.offsetX = (gameWidth - defaultWidth)/2.0;
	this.game.screenSettings.offsetY = (gameHeight - defaultHeight)/2.0;
    }

    initGlobalVariables(){
	this.game.screenSettings = {
	    defaultWidth: 0,
	    defaultHeight: 0,
	    gameWidth: 0,
	    gameHeight: 0,
	    scaleX: 0,
	    scaleY: 0,
	    offsetX: 0,
	    offsetY: 0,
	};

	this.game.global = {

	};
    }
}

export default Boot;

<commit_msg>boot screen res correction<commit_after>class Boot extends Phaser.State {

    constructor() {
	super();
    }

    preload() {
	this.load.image('preloader', 'assets/preloader.gif');

	// JSON
	this.game.load.json('assets', './assets.json');
    }

    create() {
	this.game.input.maxPointers = 1;

	this.game.scale.scaleMode = Phaser.ScaleManager.USER_SCALE;
	this.game.scale.pageAlignHorizontally = true;
	this.game.scale.pageAlignVertically = true;

	this.initGlobalVariables();

	// Setup resolution
	let settings = {
	    defaultWidth: 1280,
	    defaultHeight: 800,
	    useStretchThreshold: true,
	    stretchThresholdWidth: 1420,
	    stretchThresholdHeight: 960
	};

	this.setupResolutionSettings(settings);

	this.game.state.start('preloader');
    }

    setupResolutionSettings(settings) {
	// Setup game screen resolution
	let defaultWidth = settings.defaultWidth;
	let defaultHeight = settings.defaultHeight;

	let windowWidth = window.innerWidth;
	let windowHeight = window.innerHeight;

	let defaultRatio = defaultWidth/defaultHeight;
	let windowRatio = windowWidth/windowHeight;

	let gameWidth = defaultWidth;
	let gameHeight = defaultHeight;

	if (windowRatio < defaultRatio) {
	    gameHeight = Math.ceil((gameWidth / windowRatio) / 2.0) * 2;
	    if(settings.useStretchThreshold)
		gameHeight = Math.min(gameHeight, settings.stretchThresholdHeight);
	} else {
	    gameWidth = Math.ceil((gameHeight * windowRatio) / 2.0) * 2;
	    if(settings.useStretchThreshold)
		gameWidth = Math.min(gameWidth, settings.stretchThresholdWidth);
	}

	let scaleX = windowWidth/gameWidth;
	let scaleY = windowHeight/gameHeight;

	this.game.scale.setGameSize(gameWidth,gameHeight);
	this.game.scale.setUserScale(scaleX,scaleY);

	this.game.screenSettings.defaultWidth = defaultWidth;
	this.game.screenSettings.defaultHeight = defaultHeight;
	this.game.screenSettings.gameWidth = gameWidth;
	this.game.screenSettings.gameHeight = gameHeight;
	this.game.screenSettings.scaleX = scaleX;
	this.game.screenSettings.scaleY = scaleY;
	this.game.screenSettings.offsetX = (gameWidth - defaultWidth)/2.0;
	this.game.screenSettings.offsetY = (gameHeight - defaultHeight)/2.0;
    }

    initGlobalVariables(){
	this.game.screenSettings = {
	    defaultWidth: 0,
	    defaultHeight: 0,
	    gameWidth: 0,
	    gameHeight: 0,
	    scaleX: 0,
	    scaleY: 0,
	    offsetX: 0,
	    offsetY: 0,
	};

	this.game.global = {

	};
    }
}

export default Boot;

<|endoftext|>