$(function () {

  var setText = function (textarea, text) {
    var range;
    textarea.focus();
    if (typeof textarea.selectionStart === 'number') {
      textarea.value = text;
      textarea.selectionStart = textarea.selectionEnd = 3;
      return;
    }
    range = textarea.createTextRange();
    range.text = text
    range.select();
  }

  var $textarea = $('textarea').textcomplete({
    // emoji strategy
    emoji: {
      match: /(^|\s):([\-+\w]*)$/,
      search: function (term, callback) {
        var regexp = new RegExp('^' + term.replace(/\+/g, '\\+'));
        callback($.map(emojies, function (emoji) {
          return regexp.test(emoji) ? emoji : null;
        }));
      },
      template: function (value) {
        return '' + value;
      },
      replace: function (value) {
        return '$1:' + value + ': ';
      },
      maxCount: 5
    }
  });

  setText($textarea.get(0), ':a');
  $textarea.keyup();
});

$(function () {

  var setText = function (textarea, text) {
    var range;
    textarea.focus();
    if (typeof textarea.selectionStart === 'number') {
      textarea.value = text;
      textarea.selectionStart = textarea.selectionEnd = 3;
      return;
    }
    range = textarea.createTextRange();
    range.text = text
    range.select();
  }

  var startsWith = String.prototype.startsWith || function (str, position) {
    position = position || 0;
    return ('' + this).indexOf(str, position) === position;
  };

  var $textarea = $('textarea').textcomplete({
    // emoji strategy
    emoji: {
      match: /(^|\s):([\-+\w]*)$/,
      search: function (term, callback) {
        callback($.map(emojies, function (emoji) {
          return startsWith.call(emoji, term) ? emoji : null;
        }));
      },
      template: function (value) {
        return '' + value;
      },
      replace: function (value) {
        return '$1:' + value + ': ';
      },
      maxCount: 5
    }
  });

  setText($textarea.get(0), ':a');
  $textarea.keyup();
});

Use `String.prototype.startsWith` method instead of the regular expression


const assign = require('object-assign');
const find = require('array-find');
const drop = require('this-drop');

export default (tape) => {
  const tapeCss = (...args) => {
    // Determine arguments – based on
    // https://github.com/substack/tape/blob/aadcf4a9/lib/test.js .
    const name = find(args, (arg) => typeof arg === 'string');
    const options = find(args, (arg) => typeof arg === 'object') || {};
    const callback = find(args, (arg) => typeof arg === 'function');

    const {dom} = options;

    const document = (
      options.document ||
      (typeof window !== 'undefined' && window.document) ||
      null
    );

    // TODO: Throw if there’s no `document`;

    const wrappedCallback = (is) => {
      if (dom) document.body.appendChild(dom);
      callback(is);
      if (dom) document.body.removeChild(dom);
    };

    tape(
      name,
      options::drop(['dom']),
      wrappedCallback
    );
  };
  assign(tapeCss, tape);

  return tapeCss;
};

const assign = require('object-assign');
const find = require('array-find');
const drop = require('this-drop');

export default (tape) => {
  const tapeCss = (...args) => {
    // Determine arguments – based on
    // https://github.com/substack/tape/blob/aadcf4a9/lib/test.js .
    const name = find(args, (arg) => typeof arg === 'string');
    const options = find(args, (arg) => typeof arg === 'object') || {};
    const callback = find(args, (arg) => typeof arg === 'function');

    const {dom} = options;

    const document = (
      options.document ||
      (typeof window !== 'undefined' && window.document) ||
      null
    );

    // TODO: Throw if there’s no `document`;

    const wrappedCallback = (is) => {
      if (dom) {
        document.body.appendChild(dom);
        is.on('end', () => document.body.removeChild(dom));
      }

      callback(is);
    };

    tape(
      name,
      options::drop(['dom']),
      wrappedCallback
    );
  };
  assign(tapeCss, tape);

  return tapeCss;
};

Remove the DOM at the right time


var wrappy = require('wrappy')
var reqs = Object.create(null)
var once = require('once')

module.exports = wrappy(inflight)

function inflight (key, cb) {
  if (reqs[key]) {
    reqs[key].push(cb)
    return null
  } else {
    reqs[key] = [cb]
    return makeres(key)
  }
}

function makeres (key) {
  return once(function RES () {
    var cbs = reqs[key]
    var len = cbs.length
    var args = slice(arguments)
    try {
      for (var i = 0; i < len; i++) {
        cbs[i].apply(null, args)
      }
    } finally {
      if (cbs.length > len) {
        // added more in the interim.
        // de-zalgo, just in case, but don't call again.
        cbs.splice(0, len)
        process.nextTick(function () {
          RES.apply(null, args)
        })
      } else {
        delete reqs[key]
      }
    }
  })
}

function slice (args) {
  var length = args.length
  var array = []

  for (var i = 0; i < length; i++) array[i] = args[i]
  return array
}

var wrappy = require('wrappy')
var reqs = Object.create(null)
var once = require('once')

module.exports = wrappy(inflight)

function inflight (key, cb) {
  if (reqs[key]) {
    reqs[key].push(cb)
    return null
  } else {
    reqs[key] = [cb]
    return makeres(key)
  }
}

function makeres (key) {
  return once(function RES () {
    var cbs = reqs[key]
    var len = cbs.length
    var args = slice(arguments)

    // XXX It's somewhat ambiguous whether a new callback added in this
    // pass should be queued for later execution if something in the
    // list of callbacks throws, or if it should just be discarded.
    // However, it's such an edge case that it hardly matters, and either
    // choice is likely as surprising as the other.
    // As it happens, we do go ahead and schedule it for later execution.
    try {
      for (var i = 0; i < len; i++) {
        cbs[i].apply(null, args)
      }
    } finally {
      if (cbs.length > len) {
        // added more in the interim.
        // de-zalgo, just in case, but don't call again.
        cbs.splice(0, len)
        process.nextTick(function () {
          RES.apply(null, args)
        })
      } else {
        delete reqs[key]
      }
    }
  })
}

function slice (args) {
  var length = args.length
  var array = []

  for (var i = 0; i < length; i++) array[i] = args[i]
  return array
}

Add comment that zalgo cb's get re-queued even in the event of a throw


hqDefine("app_manager/js/settings/translations", function () {
    var appTranslationsModel = function (options) {
        hqImport("hqwebapp/js/assert_properties").assertRequired(options, ['baseUrl', 'lang']);
        var self = {};

        self.file = ko.observable();
        self.lang = ko.observable(options.lang);
        self.url = ko.computed(function () {
            return options.baseUrl + "?lang=" + self.lang();
        });

        return self;
    };

    $(function () {
        // Bulk CommCare translations
        var $commcareForm = $("#bulk_ui_translation_upload_form");
        if ($commcareForm.length) {
            $commcareForm.koApplyBindings({
                file: ko.observable(),
            });
        }

        // Bulk application translations
        var $translationsPanel = $("#bulk-application-translations");
        if ($translationsPanel.length) {
            $translationsPanel.koApplyBindings(appTranslationsModel({
                baseUrl: $translationsPanel.find("#download_link").attr("href"),
                lang: $translationsPanel.find("select").val() || '',
            }));
        }
    });
});

hqDefine("app_manager/js/settings/translations", function () {
    var appTranslationsModel = function (options) {
        hqImport("hqwebapp/js/assert_properties").assertRequired(options, ['baseUrl', 'lang', 'skipBlacklisted']);
        var self = {};

        self.file = ko.observable();
        self.lang = ko.observable(options.lang);
        self.skipBlacklisted = ko.observable(options.skipBlacklisted);
        self.url = ko.computed(function () {
            return options.baseUrl + "?lang=" + self.lang() + "&skipbl=" + self.skipBlacklisted();
        });

        return self;
    };

    $(function () {
        // Bulk CommCare translations
        var $commcareForm = $("#bulk_ui_translation_upload_form");
        if ($commcareForm.length) {
            $commcareForm.koApplyBindings({
                file: ko.observable(),
            });
        }

        // Bulk application translations
        var $translationsPanel = $("#bulk-application-translations");
        if ($translationsPanel.length) {
            $translationsPanel.koApplyBindings(appTranslationsModel({
                baseUrl: $translationsPanel.find("#download_link").attr("href"),
                lang: $translationsPanel.find("select").val() || '',
                skipBlacklisted: $translationsPanel.find("#skip_blacklisted").val() || '',
            }));
        }
    });
});

Add value to JS viewmodel


import React from 'react'
import PropTypes from 'prop-types'
import EntityDetailApp from 'tocco-entity-detail/src/main'

import Action from '../Action/'

const DocumentView = ({match, history, breadcrumbs, emitAction}) => {
  const handleEntityDeleted = () => {
    const lastList = breadcrumbs.slice().reverse()
      .find(breadcrumb => breadcrumb.type === 'list')
    const lastListUrl = `/docs/${lastList.path}`
    history.push(lastListUrl)
  }

  return (
    <EntityDetailApp
      entityName="Resource"
      entityId={match.params.key}
      formName="Resource"
      mode="update"
      actionAppComponent={Action}
      emitAction={emitAction}
      onEntityDeleted={handleEntityDeleted}
    />
  )
}

DocumentView.propTypes = {
  match: PropTypes.shape({
    params: PropTypes.shape({
      key: PropTypes.string.isRequired
    }).isRequired
  }).isRequired,
  history: PropTypes.shape({
    push: PropTypes.func.isRequired
  }).isRequired,
  breadcrumbs: PropTypes.arrayOf(PropTypes.shape({
    path: PropTypes.string.isRequired,
    type: PropTypes.string.isRequired
  })).isRequired,
  emitAction: PropTypes.func.isRequired
}

export default DocumentView

import React from 'react'
import PropTypes from 'prop-types'
import EntityDetailApp from 'tocco-entity-detail/src/main'

import Action from '../Action/'

const DocumentView = ({match, history, breadcrumbs, emitAction}) => {
  const handleEntityDeleted = () => {
    const lastList = breadcrumbs.slice().reverse()
      .find(breadcrumb => breadcrumb.type === 'list')
    const lastListUrl = `/docs/${lastList.path}`
    history.push(lastListUrl)
  }

  return (
    <EntityDetailApp
      entityName="Resource"
      entityId={match.params.key}
      formName="DmsResource"
      mode="update"
      actionAppComponent={Action}
      emitAction={emitAction}
      onEntityDeleted={handleEntityDeleted}
    />
  )
}

DocumentView.propTypes = {
  match: PropTypes.shape({
    params: PropTypes.shape({
      key: PropTypes.string.isRequired
    }).isRequired
  }).isRequired,
  history: PropTypes.shape({
    push: PropTypes.func.isRequired
  }).isRequired,
  breadcrumbs: PropTypes.arrayOf(PropTypes.shape({
    path: PropTypes.string.isRequired,
    type: PropTypes.string.isRequired
  })).isRequired,
  emitAction: PropTypes.func.isRequired
}

export default DocumentView

Add more information to docs detail form


var Webtail = {
  run: function(port) {
    var self = this;

    jQuery(function($) {
      var socket = new (WebSocket || MozWebSocket)('ws://localhost:' + port),
          body   = $('body');

      self.onmessages.push(function(message) {
        // To ignore serial empty lines
        if (message.data == '\n' && $('pre:last').text() == '\n') return;

        // Insert a new line
        $('<pre>').text(message.data).appendTo('body');

        // Scroll to bottom of the page
        $('html, body').scrollTop($(document).height());

        // Trigger onmessage event
        body.trigger('onmessage');
      });

      socket.onmessage = function(message) {
        $.each(self.onmessages, function() { this(message) });
      };
    });
  },

  onmessages: []
};

var Webtail = {
  run: function(port) {
    var self = this;
    jQuery(function($) {
      var socket = new (WebSocket || MozWebSocket)('ws://localhost:' + port);
      socket.onmessage = function(message) {
        $.each(self.onmessages, function() { this(message) });
      };
    });
  },

  onmessages: [
    function(message) {
      // To ignore serial empty lines
      if (message.data == '\n' && $('pre:last').text() == '\n') return;

      // Insert a new line
      $('<pre>').text(message.data).appendTo('body');

      // Scroll to bottom of the page
      $('html, body').scrollTop($(document).height());
    }
  ]
};

Fix the execution sequence of onmessage callbacks


/*
 * MODERNIZR: Modernizr builder
 */
module.exports = {
    /*
     * TARGET:  Build custom Modernizr
     */
    prepare: {
        devFile: 'remote',
        outputFile: '<%= path.tmp %>/modernizr-custom.js',
        extra: {
            touch: true,
            shiv: true,
            cssclasses: true,
            load: false
        },
        extensibility: {
            teststyles: true,
            prefixes: true
        },
        tests: [
            'cookies',
            'iframe-sandbox'
        ],
        uglify: false,
        matchCommunityTests: true,
        parseFiles: false
    }
};

/*
 * MODERNIZR: Modernizr builder
 */
module.exports = {
    /*
     * TARGET:  Build custom Modernizr
     */
    prepare: {
        devFile: 'remote',
        outputFile: '<%= path.tmp %>/modernizr-custom.js',
        extra: {
            touch: true,
            shiv: true,
            cssclasses: true,
            load: false
        },
        extensibility: {
            teststyles: true,
            prefixes: true
        },
        tests: [
            'cookies'
        ],
        uglify: false,
        matchCommunityTests: true,
        parseFiles: false
    }
};

Remove iFrame sandbox from Modernizr


module.exports = {
  extends: [
    `eslint-config-airbnb-base`,
  ].map(require.resolve),
  parserOptions: {
    ecmaVersion: 7,
    sourceType: `module`,
  },
  rules: {
    strict: 2,
    quotes: [2, `backtick`, { avoidEscape: true }],
    'import/no-extraneous-dependencies': [2, {
      devDependencies: true,
      optionalDependencies: true,
    }],
  },
};

module.exports = {
  extends: [
    `eslint-config-airbnb-base`,
  ].map(require.resolve),
  parserOptions: {
    ecmaVersion: 7,
    sourceType: `module`,
  },
  rules: {
    'comma-dangle': [2, {
      arrays: `always-multiline`,
      objects: `always-multiline`,
      imports: `always-multiline`,
      exports: `always-multiline`,
      functions: `never`,
    }],
    strict: 2,
    quotes: [2, `backtick`, { avoidEscape: true }],
    'import/no-extraneous-dependencies': [2, {
      devDependencies: true,
      optionalDependencies: true,
    }],
  },
};

Disable comma-dangle for function parameters


/* global db, ObjectId */

var addedActions = [];

db.cooperatives.find({}).forEach(function (cooperative) {
  var actions = [];

  if (cooperative.actions) {
    cooperative.actions.forEach(function (action) {
      if (action instanceof ObjectId) {
        addedActions.push(action);
        actions.push(action);
        return;
      }

      db.actions.insert({
        name: action.name,
        date: action.date,
        cost: action.cost,
        description: action.description,
        types: action.types,
        cooperative: cooperative._id,
        user: cooperative.editors[0].editorId,
        comments: action.comments.map(function (comment) {
          return {
            user: comment.user,
            author: db.users.find({ _id: ObjectId(comment.user) }).profile.name,
            comment: comment.comment,
            date: comment.date
          };
        })
      }, function (err, docs) {
        addedActions.push(docs[0]._id);
        actions.push(docs[0]._id);
      });
    });

    db.cooperatives.update({ _id: cooperative._id }, { $set: { actions: actions }});
  }
});

db.actions.find({}).forEach(function (action) {
  var isNew = addedActions.find(function (id) { return id === action._id; });

  if (!isNew) {
    db.actions.remove({ _id: action._id });
  }
});

/* global db, ObjectId */

var addedActions = [];

db.cooperatives.find({}).forEach(function (cooperative) {
  var actions = [];

  if (cooperative.actions) {
    cooperative.actions.forEach(function (action) {
      if (action instanceof ObjectId) {
        addedActions.push(action);
        actions.push(action);
        return;
      }

      db.actions.insert({
        name: action.name,
        date: action.date,
        cost: action.cost,
        description: action.description,
        types: action.types,
        cooperative: cooperative._id,
        user: cooperative.editors[0].editorId,
        comments: action.comments.map(function (comment) {
          return {
            user: comment.user,
            author: db.users.find({ _id: ObjectId(comment.user) }).profile.name,
            comment: comment.comment,
            date: comment.date
          };
        })
      }, function (err, docs) {
        addedActions.push(docs[0]._id);
        actions.push(docs[0]._id);
      });
    });

    db.cooperatives.update({ _id: cooperative._id }, { $set: { actions: actions }});
  }
});

db.actions.find({}).forEach(function (action) {
  var isNew = false;

  addedActions.forEach(function (id) {
    isNew = (isNew || id === action._id);
  });

  if (!isNew) {
    db.actions.remove({ _id: action._id });
  }
});

Fix even more legacy mongo compatability


/* Stub translate function for eventual i8n. */
function translate(text) {
    return text
};

/* Object instantiation convenience, from Douglas Crockford */
if (typeof Object.beget !== 'function') {
     Object.beget = function (o) {
        var F = function () {};
         F.prototype = o;
         return new F();
  };
}

/* Stub translate function for eventual i8n. */
function translate(text) {
    return text
};

$(document).ready(function() {
    /* Prevent "event.layerX and event.layerY are broken and deprecated ..."
       WebKit warning message, per:
      http://stackoverflow.com/questions/7825448/webkit-issues-with-event-layerx-and-event-layery
      */
    $.event.props = $.event.props.join('|').replace('layerX|layerY|', '').split('|');
})

/* Object instantiation convenience, from Douglas Crockford */
if (typeof Object.beget !== 'function') {
     Object.beget = function (o) {
        var F = function () {};
         F.prototype = o;
         return new F();
  };
}

Include in the document.ready function a workaround for browser console warnings produced by a bad interaction between webkit and JQuery versions less than 1.7 (and alleged by some to be present in 1.7, as well).


import m from 'mithril';
import GameComponent from './game.js';
import UpdateNotificationComponent from './update-notification.js';
import SWUpdateManager from 'sw-update-manager';

class AppComponent {

  constructor() {
    if (navigator.serviceWorker && !window.__karma__ && window.location.port !== '8080') {
      let serviceWorker = navigator.serviceWorker.register('service-worker.js');
      this.updateManager = new SWUpdateManager(serviceWorker);
      this.updateManager.on('updateAvailable', () => m.redraw());
      this.updateManager.checkForUpdates();
    }
  }

  view() {
    return m('div#app', [
      this.updateManager ? m(UpdateNotificationComponent, {
        updateManager: this.updateManager
      }) : null,
      m(GameComponent)
    ]);
  }

}

export default AppComponent;

import m from 'mithril';
import GameComponent from './game.js';
import UpdateNotificationComponent from './update-notification.js';
import SWUpdateManager from 'sw-update-manager';

class AppComponent {

  oninit() {
    if (navigator.serviceWorker && !window.__karma__ && window.location.port !== '8080') {
      let serviceWorker = navigator.serviceWorker.register('service-worker.js');
      this.updateManager = new SWUpdateManager(serviceWorker);
      this.updateManager.on('updateAvailable', () => m.redraw());
      this.updateManager.checkForUpdates();
    }
  }

  view() {
    return m('div#app', [
      this.updateManager ? m(UpdateNotificationComponent, {
        updateManager: this.updateManager
      }) : null,
      m(GameComponent)
    ]);
  }

}

export default AppComponent;

Convert AppComponent constructor to oninit


var asteroid = function(){
  id: 0;
  cell: 0;
  row: 0;
}

var generateAsteroid = function(){
  //generate an asteroid and return asteroid object
  new_asteroid = new asteroid();
  //test assignment
  var id = new Date();
  //new_asteroid.id = id.format( "yyyymmddhhmmtttt" );
  new_asteroid.id = id;
  return new_asteroid;
};

//console.log( generateAsteroid() );

Complete creation of Asteroids and generateAsteroid function


const eris = justcord.eris;
const config = justcord.config;
const chat = justcord.chat;

eris.on("ready", () => {
    console.log("Justcord ready!"); // TODO: Add logging utility functions
    eris.createMessage(config.eris.id, "Justcord connected to the guild successfully!")
});

eris.on("messageCreate", (message) => {
    if (message.channel.id == config.eris.id) {
        chat.broadcast(`${message.member.nick}: ${message.content}`);
        console.log(`Discord: ${message.member.nick}: ${message.content}`);
    }
});

const eris = justcord.eris;
const config = justcord.config;
const chat = justcord.chat;

eris.on("ready", () => {
    console.log("Justcord ready!"); // TODO: Add logging utility functions
    eris.createMessage(config.eris.id, "Server connected to the guild successfully!")
});

eris.on("messageCreate", (message) => {
    if (message.channel.id == config.eris.id) {
        chat.broadcast(`${message.member.nick}: ${message.content}`);
        console.log(`Discord: ${message.member.nick}: ${message.content}`);
    }
});

Change message sent to Discord on connect


module.exports = function(server) {
  var router = server.loopback.Router();
  router.get('/', (req, res) => res.render('index'));
  server.use(router);
};

module.exports = function(server) {
  var router = server.loopback.Router();
  // TODO: get pages list programmatically
  var pages = ['/', '/profile', '/storage'];
  router.get(pages, (req, res) => res.render('index'));
  server.use(router);
};

Support browser history on backend


import CoreMitigationCheck from 'parser/shared/modules/MitigationCheck';
import SPELLS from 'common/SPELLS';

class MitigationCheck extends CoreMitigationCheck {
  constructor(...args){
    super(...args);
    this.buffCheck = [SPELLS.SHIELD_BLOCK_BUFF.id,
                      SPELLS.IGNORE_PAIN.id,
                      SPELLS.LAST_STAND.id,
                      SPELLS.SHIELD_WALL.id,
                      SPELLS.SPELL_REFLECTION.id];
    this.debuffCheck = [SPELLS.DEMORALIZING_SHOUT.id];
  }
}

export default MitigationCheck;

import CoreMitigationCheck from 'parser/shared/modules/MitigationCheck';
import SPELLS from 'common/SPELLS';

class MitigationCheck extends CoreMitigationCheck {
  constructor(...args){
    super(...args);
    this.buffCheckPhysical = [
      SPELLS.SHIELD_BLOCK_BUFF.id,
    ];
    this.buffCheckMagical = [
      SPELLS.SPELL_REFLECTION,
    ];
    this.buffCheckPhysAndMag = [
      SPELLS.IGNORE_PAIN.id,
      SPELLS.LAST_STAND.id,
      SPELLS.SHIELD_WALL.id,
    ];

    this.debuffCheckPhysAndMag = [
      SPELLS.DEMORALIZING_SHOUT.id,
    ];
  }
}

export default MitigationCheck;

Update protection warrior for soft mitigation check damage schools.


Meteor.methods({
  'logKeyError': function (keyID, vCode, errorType, message) {
    Errors.update(
      { keyID: keyID },
      {
        $set: {
          keyID: keyID,
          vCode: vCode
        },
        $addToSet: {
          log: {
            errorType: errorType,
            message: message
          }
        }
      },
      {
        upsert: true,
        validate: false
      });
    console.log("Key " + keyID + " with vCode " + vCode + " threw the following error:");
    console.log("[" + errorType + "] " + message);
  }
});

Meteor.methods({
  'logKeyError': function (keyID, vCode, errorType, message) {
    Errors.update(
      { keyID: keyID },
      {
        $set: {
          keyID: keyID,
          vCode: vCode
        },
        $addToSet: {
          log: {
            errorType: errorType,
            message: message
          }
        }
      },
      {
        upsert: true,
        validate: false
      }
    );

    Errors.update(
      {keyID: keyID},
      {
        $push: {
          log:{
            $each: [],
            $slice: -6
          }
        }
      }
    );

    console.log("Key " + keyID + " with vCode " + vCode + " threw the following error:");
    console.log("[" + errorType + "] " + message);
  }
});

Add limit of 6(arbitrary) to each key in Active Errors


/*
 Configure nock interceptor for backend service
 */

import features from '../fixtures/features.js';
import client from '../fixtures/client.js';
import productArea from '../fixtures/productarea.js';

/* Returns a regex that will match /api/endpoint
 with optional trailing slash or query parameters */
function collection(endpoint, base='') {
    return RegExp(base + `/api/${endpoint}/?(\\?([^0-9].*))*$`);
}

/* Return path part of url */
function strip(url) {
    return url.replace(/^http:\/\/localhost:8000/, '');
}

/*
 Mock api using fetch-mock
 */
export default function (fetchMock) {
    // Intercept all calls to fetch
    fetchMock.greed = 'bad';

    fetchMock.mock(collection('features'), features);
    fetchMock.mock(collection('client'), client);
    fetchMock.mock(collection('productarea'), productArea);

    features.results.forEach((feature) => {
        const url = strip(feature.url);

        fetchMock.mock(url, feature);
    });

    client.results.forEach((client) => {
        const url = strip(client.url);

        fetchMock.mock(url, client);
    });

    productArea.results.forEach((area) => {
        const url = strip(area.url);

        fetchMock.mock(url, area);
    });
}

/*
 Configure nock interceptor for backend service
 */

import features from '../fixtures/features.js';
import client from '../fixtures/client.js';
import productArea from '../fixtures/productarea.js';

/* Returns a regex that will match /api/endpoint
 with optional trailing slash or query parameters */
function collection(endpoint, base='') {
    return RegExp(base + `/api/${endpoint}/?(\\?([^0-9].*))*$`);
}

/* Return path part of url */
function strip(url) {
    return url.replace(/^http:\/\/localhost:8000/, '');
}

/*
 Mock api using fetch-mock
 */
export default function (fetchMock) {
    // Intercept all calls to fetch
    fetchMock.greed = 'bad';

    fetchMock.mock(collection('features'), features);
    fetchMock.mock(collection('client'), client);
    fetchMock.mock(collection('productarea'), productArea);

    const setup = (el) => fetchMock.mock(strip(el.url), el);

    features.results.forEach(setup);
    client.results.forEach(setup);
    productArea.results.forEach(setup);
}

Clean up test code a little more


// distance.js
// Finds the closest user match with n dimensions of compatability

// Expects a tag:count map from the user and a tag:count map from a blog
module.exports = {
	match: function(userTags, blogTags) {
		var counts = [];
		for (var tag in userTags) {
			if (tag in blogTags) {
				counts.push([userTags[tag], blogTags[tag]]);
			} else {
				counts.push([userTags[tag], 0]);
			}
		}

		var sum = 0;
		for (var i = counts.length - 1; i >= 0; i--) {
		 	sum += Math.pow((counts[i][0] - counts[i][1]), 2);
		};
		return Math.sqrt(sum);
	},
	normalize: function(distances) {
  		var min = distances.slice(0).sort()[0];
  		var max = distances.slice(0).sort().reverse()[0];
		for (var i = distances.length - 1; i >= 0; i--) {
			distances[i] = (distances[i] - min)/(max-min);
		};
		return distances;
	}
}

// distance.js
// Finds the closest user match with n dimensions of compatability

// Expects a tag:count map from the user and a tag:count map from a blog
module.exports = {
	match: function(userTags, blogTags) {
		var counts = [];
		for (var tag in userTags) {
			if (tag in blogTags) {
				counts.push([userTags[tag], blogTags[tag]]);
			} else {
				counts.push([userTags[tag], 0]);
			}
		}

		var sum = 0;
		for (var i = counts.length - 1; i >= 0; i--) {
		 	sum += Math.pow((counts[i][0] - counts[i][1]), 2);
		}
		return Math.sqrt(sum);
	},
	normalize: function(distances) {
		var values = [];
		for (var match in distances) {
			values.push(match.distance);
		}
  		var min = values.slice(0).sort()[0];
  		var max = values.slice(0).sort().reverse()[0];
		for (var i = distances.length - 1; i >= 0; i--) {
			distances[i].distance = (distances[i].distance - min)/(max-min);
		}
		return distances;
	}
}

Convert normalize to receive a set of maps


var path = require('path');
var yaml_config = require('node-yaml-config');
var _ = require('lodash');

function ymlHerokuConfigModule() {

  var HEROKU_VARS_SUPPORT = [
    'user', 'password', 'url', 'pipeline', 'jobs', 'key', 'secret', 'account'
  ];

  var create = function (configKey) {

    var config;
    var id = configKey;

    init();

    var get = function () {
      return config[id];
    };

    function init() {

      try {
        config = yaml_config.load('config.yml');
      } catch (err) {
        console.log('could not read yml, trying Heroku vars', err);

        config = {};
        config[id] = {};
        _.each(HEROKU_VARS_SUPPORT, function(varName) {
          config[id][varName] = process.env[id.toUpperCase() + '_' + varName.toUpperCase()];
        });

        if(config[id].jobs) {
          config[id].jobs = config[id].jobs.split(',');
        }

        if (!config[id].user || !config[id].password || !config[id].url) {
          console.log('ERROR: Not enough values in ' + id + ' config, cannot get data');
        }

      }

      config[id] = config[id] || { sample: true };

    }

    return {
      get: get
    };
  };

  return {
    create: create
  };
}

exports.create = ymlHerokuConfigModule().create;

var path = require('path');
var yaml_config = require('node-yaml-config');
var _ = require('lodash');

function ymlHerokuConfigModule() {

  var HEROKU_VARS_SUPPORT = [
    'user', 'password', 'url', 'pipeline', 'jobs', 'key', 'secret', 'account', 'debug'
  ];

  var create = function (configKey) {

    var config;
    var id = configKey;

    init();

    var get = function () {
      return config[id];
    };

    function init() {

      try {
        config = yaml_config.load('config.yml');
      } catch (err) {
        console.log('could not read yml, trying Heroku vars', err);

        config = {};
        config[id] = {};
        _.each(HEROKU_VARS_SUPPORT, function(varName) {
          config[id][varName] = process.env[id.toUpperCase() + '_' + varName.toUpperCase()];
        });

        if(config[id].jobs) {
          config[id].jobs = config[id].jobs.split(',');
        }

        if (!config[id].user || !config[id].password || !config[id].url) {
          console.log('ERROR: Not enough values in ' + id + ' config, cannot get data');
        }

      }

      config[id] = config[id] || { sample: true };

    }

    return {
      get: get
    };
  };

  return {
    create: create
  };
}

exports.create = ymlHerokuConfigModule().create;

Support debug logging for gocd


// ==UserScript==
// @name        Remove concourse elements
// @namespace   cloudpipeline.digital
// @description Strips away some of the cruft from the concourse pipeline view when showing it on monitoring screens.
// @include     https://deployer.*.cloudpipeline.digital/*
// @include     https://deployer.cloud.service.gov.uk/*
// @version     1
// @grant       none
// ==/UserScript==
var readyStateCheckInterval = setInterval(function() {
    if (document.readyState === "complete") {
        clearInterval(readyStateCheckInterval);

        console.log("Monitor mode is go");
        var element = document.getElementsByClassName("legend")[0];
        element.parentNode.removeChild(element);

        var element = document.getElementsByClassName("lower-right-info")[0];
        element.parentNode.removeChild(element);

        var hostname = location.hostname.replace("deployer.", "").replace(".cloudpipeline.digital","");

        var element = document.getElementById("top-bar-app");
        element.innerHTML = " " + hostname + "";
        // Move it to the bottom because there's more space there.
        element.style.position = "absolute";
        element.style.bottom = "0";

        var element = document.getElementsByClassName("bottom")[0];
        // Remove the padding because the top bar isn't there any more.
        element.style.paddingTop = "0";
    }
}, 10);

// ==UserScript==
// @name        Remove concourse elements
// @namespace   cloudpipeline.digital
// @description Strips away some of the cruft from the concourse pipeline view when showing it on monitoring screens.
// @include     https://deployer.*.cloudpipeline.digital/*
// @include     https://deployer.cloud.service.gov.uk/*
// @version     1
// @grant       none
// ==/UserScript==
var readyStateCheckInterval = setInterval(function() {
    if (document.readyState === "complete") {
        clearInterval(readyStateCheckInterval);

        console.log("Monitor mode is go");
        var element = document.getElementsByClassName("legend")[0];
        element.parentNode.removeChild(element);

        var element = document.getElementsByClassName("lower-right-info")[0];
        element.parentNode.removeChild(element);

        var hostname = location.hostname.replace("deployer.", "").replace(".cloudpipeline.digital","");

        var element = document.getElementById("top-bar-app");
        element.innerHTML = " " + hostname + "";
        // Move it to the bottom because there's more space there.
        element.style.position = "absolute";
        element.style.bottom = "0";

        var element = document.getElementsByClassName("bottom")[0];
        // Remove the padding because the top bar isn't there any more.
        element.style.paddingTop = "0";
    }
}, 2000);

Increase delay of clean_concourse plugin to 2s


import { includePaths } from '../config/utils';

export default () => ({
  test: /\.(mjs|tsx?|jsx?)$/,
  use: [
    {
      loader: 'babel-loader',
      options: {
        presets: [
          ['@babel/preset-env', { shippedProposals: true, useBuiltIns: 'usage', corejs: '3' }],
          '@babel/preset-typescript',
          '@babel/preset-react',
        ],
        plugins: [
          ['@babel/plugin-proposal-class-properties', { loose: true }],
          '@babel/plugin-proposal-export-default-from',
          '@babel/plugin-syntax-dynamic-import',
          ['@babel/plugin-proposal-object-rest-spread', { loose: true, useBuiltIns: true }],
          'babel-plugin-macros',
        ],
      },
    },
  ],
  include: includePaths,
  exclude: /\/node_module\/|\/dist\//,
});

import { includePaths } from '../config/utils';

export default () => ({
  test: /\.(mjs|tsx?|jsx?)$/,
  use: [
    {
      loader: 'babel-loader',
      options: {
        sourceType: 'unambiguous',
        presets: [
          ['@babel/preset-env', { shippedProposals: true, useBuiltIns: 'usage', corejs: '3' }],
          '@babel/preset-typescript',
          '@babel/preset-react',
        ],
        plugins: [
          ['@babel/plugin-proposal-class-properties', { loose: true }],
          '@babel/plugin-proposal-export-default-from',
          '@babel/plugin-syntax-dynamic-import',
          ['@babel/plugin-proposal-object-rest-spread', { loose: true, useBuiltIns: true }],
          'babel-plugin-macros',
        ],
      },
    },
  ],
  include: includePaths,
  exclude: [/node_module/, /dist/],
});

FIX compilation of node_modules & dist


// @ngInject
export default function expertRequestsService(baseServiceClass, $q, $http, ENV) {
  let ServiceClass = baseServiceClass.extend({
    filterByCustomer: false,

    init: function () {
      this._super();
      this.endpoint = '/expert-requests/';
    },

    create: function (expertRequest) {
      return $http.post(`${ENV.apiEndpoint}api${this.endpoint}`, expertRequest)
        .then(response => response.data);
    },

    cancel: function (expertRequest) {
      return $http.post(`${expertRequest.url}cancel/`)
        .then(response => response.data);
    },

    getConfiguration: function () {
      return $http.get(`${ENV.apiEndpoint}api${this.endpoint}configured`)
        .then(response => response.data);
    }
  });
  return new ServiceClass();
}

// @ngInject
export default function expertRequestsService(baseServiceClass, $q, $http, ENV) {
  let ServiceClass = baseServiceClass.extend({
    filterByCustomer: false,

    init: function () {
      this._super();
      this.endpoint = '/expert-requests/';
    },

    create: function (expertRequest) {
      return $http.post(`${ENV.apiEndpoint}api${this.endpoint}`, expertRequest)
        .then(response => response.data);
    },

    cancel: function (expertRequest) {
      return $http.post(`${expertRequest.url}cancel/`)
        .then(response => response.data);
    },

    getConfiguration: function () {
      return $http.get(`${ENV.apiEndpoint}api${this.endpoint}configured/`)
        .then(response => response.data);
    }
  });
  return new ServiceClass();
}

Append missing slash to fix expert request URL.


/*
 * Copyright (c) 2013 Adobe Systems Incorporated. All rights reserved.
 *
 * Permission is hereby granted, free of charge, to any person obtaining a
 * copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation
 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
 * and/or sell copies of the Software, and to permit persons to whom the
 * Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
 * DEALINGS IN THE SOFTWARE.
 *
 */

(function () {
    "use strict";

    var resolve = require("path").resolve,
        spawn = require("child_process").spawn;

    var execpath = (__dirname, "../bin/convert");

    module.exports = function convert(args, psPath) {
        if (process.platform === "darwin")
          return spawn( psPath + "/Adobe Photoshop CC.app/Contents/MacOS/convert", args );
        else
          return spawn(execpath, args);
    };
}());

/*
 * Copyright (c) 2013 Adobe Systems Incorporated. All rights reserved.
 *
 * Permission is hereby granted, free of charge, to any person obtaining a
 * copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation
 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
 * and/or sell copies of the Software, and to permit persons to whom the
 * Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
 * DEALINGS IN THE SOFTWARE.
 *
 */

(function () {
    "use strict";

    var resolve = require("path").resolve,
        spawn = require("child_process").spawn;

    var execpath = (__dirname + "/../bin/convert");

    module.exports = function convert(args, psPath) {
        if (process.platform === "darwin")
          return spawn( psPath + "/Adobe Photoshop CC.app/Contents/MacOS/convert", args );
        else
          return spawn(execpath, args);
    };
}());

Fix path (just happened to work on Win7, fails on Win8)


"use strict";

var querystring = require("querystring");
var SdkException = require("./sdkexception.js");
var WebHelper = require("./webhelper.js");
var GettyApiRequest = require("./baseclasses/gettyApiRequest.js");

const _ids = new WeakMap();
const _fields = new WeakMap();

class Events extends GettyApiRequest {
    constructor(credentials, hostName) {
        super(credentials,hostName);
        this.page = 0;
        this.pageSize = 0;
    }
    withPage(page) {
        this.page = page;
        return this;
    }
    withPageSize(pageSize) {
        this.pageSize = pageSize;
        return this;
    }

    execute(next) {

        var path = "/v3/sets";

        var params = {};
        if (this.page > 0) {
            params.page = this.page;
        }
        if (this.pageSize > 0) {
            params.page_size = this.pageSize;
        }

        path += "?";
        path += querystring.stringify(params);

        var webHelper = new WebHelper(this.credentials, this.hostName);
        webHelper.get(path, function (err, response) {
            if (err) {
                next(err, null);
            } else {
                next(null, response);
            }
        });
    }
}

module.exports = Events;

"use strict";

var querystring = require("querystring");
var SdkException = require("./sdkexception.js");
var WebHelper = require("./webhelper.js");
var GettyApiRequest = require("./baseclasses/gettyApiRequest.js");

const _ids = new WeakMap();
const _fields = new WeakMap();

class Events extends GettyApiRequest {
    constructor(credentials, hostName) {
        super(credentials,hostName);
        this.setId = null;
        this.page = 0;
        this.pageSize = 0;
    }
    withSetId(setId) {
        this.setId = setId;
        return this;
    }
    withPage(page) {
        this.page = page;
        return this;
    }
    withPageSize(pageSize) {
        this.pageSize = pageSize;
        return this;
    }

    execute(next) {

        var path = "/v3/sets";

        if (this.setId) {
            path += "/" + this.setId;
        }
        else {
            var params = {};
            if (this.page > 0) {
                params.page = this.page;
            }
            if (this.pageSize > 0) {
                params.page_size = this.pageSize;
            }

            path += "?";
            path += querystring.stringify(params);
        }

        var webHelper = new WebHelper(this.credentials, this.hostName);
        webHelper.get(path, function (err, response) {
            if (err) {
                next(err, null);
            } else {
                next(null, response);
            }
        });
    }
}

module.exports = Events;

Add individual curated set lookup


const singletonTags = [
  'area',
  'base',
  'br',
  'col',
  'command',
  'embed',
  'hr',
  'img',
  'input',
  'keygen',
  'link',
  'meta',
  'param',
  'source',
  'track',
  'wbr'
];

const tagsWithValueAttributes = [
  'button',
  'input',
  'li',
  'meter',
  'option',
  'param',
  'progress'
];

module.exports = {
  tag: {
    render: (tagName, data) => {
      const isValueTag = tagsWithValueAttributes.includes(tagName);
      const attributes = Object.entries(data).reduce((attrs, [key, value]) => {
        if (value && ((key === 'value' && isValueTag) || !['content', 'value'].includes(key))) {
          attrs += value === true
            ? ` ${key}`
            : ` ${key}="${value}"`;
        }

        return attrs;
      }, '');

      const tag = `<${tagName}${attributes}>`;
      const tagContent = data.content || (!isValueTag && data.value ? data.value : '');

      return singletonTags.includes(tagName)
        ? tag
        : `${tag}${tagContent}</${tagName}>`;
    },
    firstArgIsResolvedPath: false,
    content: true
  }
};

const singletonTags = [
  'area',
  'base',
  'br',
  'col',
  'command',
  'embed',
  'hr',
  'img',
  'input',
  'keygen',
  'link',
  'meta',
  'param',
  'source',
  'track',
  'wbr'
];

const tagsWithValueAttributes = [
  'button',
  'input',
  'li',
  'meter',
  'option',
  'param',
  'progress'
];

module.exports = {
  tag: {
    render: (tagName, data) => {
      const isValueTag = tagsWithValueAttributes.includes(tagName);
      const attributes = Object.entries(data).reduce((attrs, [key, value]) => {
        if ((value || typeof value === 'string') && ((key === 'value' && isValueTag) || !['content', 'value'].includes(key))) {
          attrs += value === true
            ? ` ${key}`
            : ` ${key}="${value}"`;
        }

        return attrs;
      }, '');

      const tag = `<${tagName}${attributes}>`;
      const tagContent = data.content || (!isValueTag && data.value ? data.value : '');

      return singletonTags.includes(tagName)
        ? tag
        : `${tag}${tagContent}</${tagName}>`;
    },
    firstArgIsResolvedPath: false,
    content: true
  }
};

Enable the ability for a tag attribute value to be an empty string and get set on the html tag


var ACCEPTANCE_TESTS_ENDPOINT = 'http://localhost:9000/api/acceptance-tests',
	ACCEPTANCE_TESTS_GUI_URL = 'http://localhost:9000/tests/';

function createTest() {
	var formattedResults = Object.keys(window.lastResult).map(function(key) {
		return {
			code: key,
			expectedValue: window.lastResult[key]
		}
	});

	var data = {
		expectedResults: formattedResults,
		scenario: serialize(document.getElementsByTagName('form')[0])
	}

	var request = new XMLHttpRequest();

	request.open('POST', ACCEPTANCE_TESTS_ENDPOINT);

	request.onload = function() {
		if (request.status >= 300)
			throw request;

		var data = JSON.parse(request.responseText);

		document.location = [ ACCEPTANCE_TESTS_GUI_URL, data._id, 'edit' ].join('/');
	};

	request.onerror = function() {
		throw request;
	}

	request.setRequestHeader('Content-Type', 'application/json');
	request.send(JSON.stringify(data));
}

var ACCEPTANCE_TESTS_ENDPOINT = 'http://localhost:9000/api/acceptance-tests',
	ACCEPTANCE_TESTS_GUI_URL = 'http://localhost:9000/tests/';

function createTest() {
	var formattedResults = Object.keys(window.lastResult).map(function(key) {
		return {
			code: key,
			expectedValue: window.lastResult[key]
		}
	});

	var form = document.getElementsByTagName('form')[0];

	var data = {
		expectedResults: formattedResults,
		scenario: form.action + '?' + serialize(form)
	}

	var request = new XMLHttpRequest();

	request.open('POST', ACCEPTANCE_TESTS_ENDPOINT);

	request.onload = function() {
		if (request.status >= 300)
			throw request;

		var data = JSON.parse(request.responseText);

		document.location = [ ACCEPTANCE_TESTS_GUI_URL, data._id, 'edit' ].join('/');
	};

	request.onerror = function() {
		throw request;
	}

	request.setRequestHeader('Content-Type', 'application/json');
	request.send(JSON.stringify(data));
}

Send full target URL as scenario description


const repl = require("repl");

const Console = require('./console.js');

class REPL {
  constructor(options) {
    this.env = options.env;
    this.plugins = options.plugins;
    this.events = options.events;
    this.console = new Console({
      events: this.events,
      plugins: this.plugins,
      version: options.version
    });
  }

  enhancedEval(cmd, context, filename, callback) {
    this.console.executeCmd(cmd.trim(), (result) => {
      callback(null, result);
    });
  }

  start(done) {
    this.replServer = repl.start({
      prompt: "Embark (" + this.env + ") > ",
      useGlobal: true,
      eval: this.enhancedEval.bind(this)
    });

    this.replServer.on("exit", () => {
      process.exit();
    });

    done();
  }

}

module.exports = REPL;

const repl = require("repl");
const util = require("util");

const Console = require('./console.js');

class REPL {
  constructor(options) {
    this.env = options.env;
    this.plugins = options.plugins;
    this.events = options.events;
    this.console = new Console({
      events: this.events,
      plugins: this.plugins,
      version: options.version
    });
  }

  enhancedEval(cmd, context, filename, callback) {
    this.console.executeCmd(cmd.trim(), (result) => {
      callback(null, result);
    });
  }

  enhancedWriter(output) {
    if ((typeof output) === "string") {
      return output;
    } else {
      return util.inspect(output, {colors: true});
    }
  }

  start(done) {
    this.replServer = repl.start({
      prompt: "Embark (" + this.env + ") > ",
      useGlobal: true,
      eval: this.enhancedEval.bind(this),
      writer: this.enhancedWriter.bind(this)
    });

    this.replServer.on("exit", () => {
      process.exit();
    });

    done();
  }

}

module.exports = REPL;

Add dedicated writer for string result


;(function(Agent) {

  /**
   Some backbone and marionette objects don't have cids (gasp)
   When that happens we go in and add this property __marionette_inspector__cid
   with a stupid long and obscure name. We use Object.defineProperty so that we
   can effectively hide the property with enumerable and writable set to false.
  */

  Agent.addCidToComponent = function(object) {
    Agent.setHiddenProperty(object, 'cid',  _.uniqueId('c'));
  }

}(Agent));

;(function(Agent) {

  /**
   Some backbone and marionette objects don't have cids (gasp)
   When that happens we go in and add this property __marionette_inspector__cid
   with a stupid long and obscure name. We use Object.defineProperty so that we
   can effectively hide the property with enumerable and writable set to false.
  */

  Agent.addCidToComponent = function(object) {
    if (!object.cid) Agent.setHiddenProperty(object, 'cid',  _.uniqueId('c'));
  }

}(Agent));

Check cid before setting hidden cid property


'use strict';

var AutoprefixPlugin = require('less-plugin-autoprefix');
var CleanCSSPlugin = require('less-plugin-clean-css');
var extend = require('extend');
var path = require('path');
var rump = require('rump');

exports.rebuild = function() {
  var plugins = [];

  rump.configs.main.globs = extend(true, {
    build: {
      less: '*.less'
    },
    watch: {
      less: '**/*.less'
    }
  }, rump.configs.main.globs);

  rump.configs.main.paths = extend(true, {
    source: {
      less: 'styles'
    },
    destination: {
      less: 'styles'
    }
  }, rump.configs.main.paths);

  rump.configs.main.styles = extend(true, {
    minify: rump.configs.main.environment === 'production',
    sourceMap: rump.configs.main.environment === 'development'
  }, rump.configs.main.styles);

  // plugins.push(new AutoprefixPlugin(rump.configs.main.styles.autoprefixer));

  if(rump.configs.main.styles.minify) {
    plugins.push(new CleanCSSPlugin({advanced: true}));
  }

  exports.less = extend(true, {
    paths: [
      'node_modules',
      'bower_components',
      path.join(rump.configs.main.paths.source.root,
                rump.configs.main.paths.source.less)
    ],
    plugins: plugins
  }, rump.configs.main.styles.less);
};

exports.rebuild();

'use strict';

// var AutoprefixPlugin = require('less-plugin-autoprefix');
var CleanCSSPlugin = require('less-plugin-clean-css');
var extend = require('extend');
var path = require('path');
var rump = require('rump');

exports.rebuild = function() {
  var plugins = [];

  rump.configs.main.globs = extend(true, {
    build: {
      less: '*.less'
    },
    watch: {
      less: '**/*.less'
    }
  }, rump.configs.main.globs);

  rump.configs.main.paths = extend(true, {
    source: {
      less: 'styles'
    },
    destination: {
      less: 'styles'
    }
  }, rump.configs.main.paths);

  rump.configs.main.styles = extend(true, {
    minify: rump.configs.main.environment === 'production',
    sourceMap: rump.configs.main.environment === 'development'
  }, rump.configs.main.styles);

  // plugins.push(new AutoprefixPlugin(rump.configs.main.styles.autoprefixer));

  if(rump.configs.main.styles.minify) {
    plugins.push(new CleanCSSPlugin({advanced: true}));
  }

  exports.less = extend(true, {
    paths: [
      'node_modules',
      'bower_components',
      path.join(rump.configs.main.paths.source.root,
                rump.configs.main.paths.source.less)
    ],
    plugins: plugins
  }, rump.configs.main.styles.less);
};

exports.rebuild();

Comment out dependency for now


$(function () {
    // We move the background image and class from data-stripe-wrapper up to the closest
    // div containing the special custom template class. Because it's this DIV that should
    // have the parallax image close to it.

    var $parallax = $('div[data-stripe-wrapper=parallax]');

    $parallax.each(function () {
        var $self = $(this);
            $wrapper = $self.closest('div.ccm-block-custom-template-parallax'),
            $children = $wrapper.children(),
            $inner = $children.first();

        $wrapper.attr('data-stripe', 'parallax').attr('data-background-image', $self.attr('data-background-image'));
        $inner.addClass('parallax-stripe-inner');

        $wrapper.parallaxize({
            variation: $wrapper.height()
        });

    });

});

$(function () {
    // We move the background image and class from data-stripe-wrapper up to the closest
    // div containing the special custom template class. Because it's this DIV that should
    // have the parallax image close to it.

    var $parallax = $('div[data-stripe-wrapper=parallax]');

    $parallax.each(function () {
        var $self = $(this);
            $wrapper = $self.closest('div.ccm-block-custom-template-parallax'),
            $children = $wrapper.children(),
            $inner = $children.first();

        $wrapper.attr('data-stripe', 'parallax').attr('data-background-image', $self.attr('data-background-image'));
        $inner.addClass('parallax-stripe-inner');

        $wrapper.parallaxize({
            speed: 0.2
        });

    });

});

Update template away from legacy variation setting


import { test } from '../lore-program.js';

test();

import { test } from '../lore-program.js';

function toMus(before, after) {
  return Math.round((after - before) * 1000);
}

const before = performance.now();
test();
const after = performance.now();
console.log('Running test took ~' + toMus(before, after) + 'µs.');

Add standard timing for test runs.


console.log('devtools.js');

chrome.devtools.panels.create('Backbase', 'backbase.png', 'panel.html', function(panel) {
    console.log('Panel created', panel);
});

chrome.devtools.panels.elements.createSidebarPane('Backbase Item Model', function(sidebar) {
    sidebar.setObject({
        lorem: 'ipsum'
    });
});

Add dummy sidebar pane for elements panel


// utility functions for generator-jhipster-db-helper

const chalk = require('chalk');

module.exports = {
    // use this as a DEBUG logger
    _dbhDebugLog : function (pString) {
        if (typeof pString === "string" && pString !== '') {
            console.log(chalk.bold.green("DEBUG : " + pString));
        } else {
			// log obvious, shameful mistake
            console.log(chalk.bold.red("_dbhDebugLog : bad parameter ! "));
            console.log(chalk.red("pString : type = " + typeof pString + ", value = " + pString));
        }
    }
};

// utility functions for generator-jhipster-db-helper

const chalk = require('chalk');

module.exports = {

    // use this as a DEBUG logger
    _dbhDebugLog : function (pString) {
        if (typeof pString === "string" && pString !== '') {
            console.log(chalk.bold.green("DEBUG : " + pString));
        } else {
            // log obvious, shameful mistake
            console.log(chalk.bold.red("_dbhDebugLog : bad parameter !"));
            console.log(chalk.red("pString : type = " + typeof pString + ", value = " + pString));
        }
    }
};

Fix typo (but who cares amirite?)


'use strict';

var Node = function(value){

	this.value = value;
	this.next = null;

	this.hasNext = function(){
		return this.next !== null;
	}

	this.getValue = function(){
		return this.value;
	}

	this.getNext = function(){
		return this.next;
	}

	this.setValue = function(value){
		this.value = value;
	}

	this.setNext = function(value){
		this.next = value;
	}
}

module.exports = Node;

'use strict';

var Node = function(value, next){

	this.value = value;
	this.next = next || null;

	this.hasNext = function(){
		return this.next !== null;
	}

	this.getValue = function(){
		return this.value;
	}

	this.getNext = function(){
		return this.next;
	}

	this.setValue = function(value){
		this.value = value;
	}

	this.setNext = function(value){
		this.next = value;
	}
}

module.exports = Node;

Allow declaring next value on Node constructor


var http = require('http');
var Navigation = require('../../../build/dist/Navigation');
var NavigateServer = require('./NavigateServer');

var server = http.createServer(function(req, res) {
	if (req.url !== '/favicon.ico') {
		Navigation.StateController.navigateLink(req.url);
		NavigateServer.getProps(function(props){
			res.write(NavigateServer.render(props));
			res.end();
		});
	} else {
		res.end();
	}
});

server.listen(8080);

var http = require('http');
var Navigation = require('../../../build/dist/Navigation');
var NavigateServer = require('./NavigateServer');

var server = http.createServer(function(req, res) {
	if (req.url !== '/favicon.ico') {
		Navigation.StateController.navigateLink(req.url);
		NavigateServer.getProps(function(props){
			Navigation.StateController.navigateLink(req.url);
			res.write(NavigateServer.render(props));
			res.end();
		});
	} else {
		res.end();
	}
});

server.listen(8080);

Reset State context after async returns


'use strict';

const sinon = require('sinon');
let _stub;
const stub = lib => {
  if (lib) {
    if (typeof lib.stub !== 'function') {
      throw new Error(`Could not set stub lib. Expected a "stub" method, found: ${typeof lib.stub}`);
    }
    if (typeof lib.spy !== 'function') {
      throw new Error(`Could not set stub lib. Expected a "spy" method, found: ${typeof lib.spy}`);
    }
    _stub = lib;
  }
  return _stub;
};

stub(sinon);

module.exports = stub;

Add use strict for node@<6


var gulp = require('gulp');
var eslint = require('gulp-eslint');
var runSequence = require('run-sequence');
var concat = require('gulp-concat');
var benchmark = require('gulp-bench');
var gulpShell = require('gulp-shell');

// Registers build tasks
require('./build/gulp-clean');
require('./build/gulp-build');
require('./build/gulp-test');
require('./build/gulp-perf');

var srcDir = 'lib';

gulp.task('lint', function() {
    return gulp.src(srcDir + '/**/*.js').
        pipe(eslint({
            globals: {
                'require': false,
                'module': false
            },
            reset: true, // dz: remove me after linting is finished, else i can't do one at the time
            useEslintrc: true
        })).
        pipe(eslint.format()).
        pipe(eslint.failOnError()); // dz: change back after finishing to failAfterError
});

gulp.task('doc', ['clean.doc', 'doc-d']);

gulp.task('doc-d', gulpShell.task([
    './node_modules/.bin/jsdoc lib -r -d doc -c ./build/jsdoc.json --verbose'
]));

// Run in serial to fail build if lint fails.
gulp.task('default', ['build-with-lint', 'lint']);

var gulp = require('gulp');
var eslint = require('gulp-eslint');
var runSequence = require('run-sequence');
var concat = require('gulp-concat');
var benchmark = require('gulp-bench');
var gulpShell = require('gulp-shell');

// Registers build tasks
require('./build/gulp-clean');
require('./build/gulp-build');
require('./build/gulp-test');
require('./build/gulp-perf');

var srcDir = 'lib';

gulp.task('lint', function() {
    return gulp.src(['*.js', srcDir + '/**/*.js']).
        pipe(eslint({
            globals: {
                'require': false,
                'module': false
            },
            reset: true, // dz: remove me after linting is finished, else i can't do one at the time
            useEslintrc: true
        })).
        pipe(eslint.format()).
        pipe(eslint.failOnError()); // dz: change back after finishing to failAfterError
});

gulp.task('doc', ['clean.doc', 'doc-d']);

gulp.task('doc-d', gulpShell.task([
    './node_modules/.bin/jsdoc lib -r -d doc -c ./build/jsdoc.json --verbose'
]));

// Run in serial to fail build if lint fails.
gulp.task('default', ['build-with-lint', 'lint']);

Add root level js files to eslint


/**
 * "Safe" utility methods.
 *
 * @package rodeo
 * @author Andrew Sliwinski <andrew@diy.org>
 */

/**
 * Constructor
 */
function Util () {};

/**
 * Prints input to stdout.
 *
 * @param {Object} Input
 *
 * @return {void}
 */
Util.prototype.stdout = function (input) {
    if (input) {
        console.log('Rodeo: ' + input.toString());
    }
};

/**
 * Safe object to JSON string encoder.
 *
 * @param {Object} Input
 *
 * @return {String}
 */
Util.prototype.stringify = function (obj, callback) {
    try {
        callback(null, JSON.stringify(obj));
    } catch (err) {
        callback(err);
    }
};

/**
 * Safe JSON string to object decoder.
 *
 * @param {String} Input
 *
 * @return {Object}
 */
Util.prototype.parse = function (obj, callback) {
    try {
        callback(null, JSON.parse(obj));
    } catch (err) {
        callback('Invalid JSON');
    }
};

/**
 * Export
 */
module.exports = new Util();

/**
 * "Safe" utility methods.
 *
 * @package rodeo
 * @author Andrew Sliwinski <andrew@diy.org>
 */

/**
 * Constructor
 */
function Util () {};

/**
 * Prints input to stdout.
 *
 * @param {Object} Input
 *
 * @return {void}
 */
Util.prototype.stdout = function (input) {
    if (input) {
        console.log('Rodeo: ' + input.toString());
    }
};

/**
 * Safe object to JSON string encoder.
 *
 * @param {Object} Input
 *
 * @return {String}
 */
Util.prototype.stringify = function (obj, callback) {
    try {
        callback(null, JSON.stringify(obj));
    } catch (err) {
        callback(err);
    }
};

/**
 * Safe JSON string to object decoder.
 *
 * @param {String} Input
 *
 * @return {Object}
 */
Util.prototype.parse = function (obj, callback) {
    try {
        callback(null, JSON.parse(obj));
    } catch (err) {
        if (typeof obj === 'object') {
            callback(null, obj);
        } else {
            callback('Invalid JSON');
        }
    }
};

/**
 * Export
 */
module.exports = new Util();

Allow objects to pass through the parse method


/**
 * Base class for over-segmentation algorithms.
 *
 * Copyright 2015  Kota Yamaguchi
 */
define(["../compat"],
function (compat) {
  function BaseSegmentation(imageData, options) {
    if (!imageData instanceof ImageData)
      throw "Invalid ImageData";
    this.imageData = compat.createImageData(imageData.width, imageData.height);
    this.imageData.data.set(imageData.data);
  }

  BaseSegmentation.prototype.finer = function () {};

  BaseSegmentation.prototype.coarser = function () {};

  return BaseSegmentation;
});

/**
 * Base class for over-segmentation algorithms.
 *
 * Copyright 2015  Kota Yamaguchi
 */
define(["../compat"],
function (compat) {
  function BaseSegmentation(imageData, options) {
    if (!(imageData instanceof ImageData))
      throw "Invalid ImageData";
    this.imageData = compat.createImageData(imageData.width, imageData.height);
    this.imageData.data.set(imageData.data);
  }

  BaseSegmentation.prototype.finer = function () {};

  BaseSegmentation.prototype.coarser = function () {};

  return BaseSegmentation;
});

Fix the condition that use "instanceof"


var gulp        = require('gulp');
var browserSync = require('browser-sync');
var sass        = require('gulp-sass');
var prefix      = require('gulp-autoprefixer');

// Start Static Server with browserSync
gulp.task('browser-sync', ['sass', 'watch'], function() {
    browserSync({
        server: {
            baseDir: "./"
        }
    });
});

// Watch SCSS files for changes, recompile, compress, autoprefixed
gulp.task('sass', function () {
    return gulp.src('_sass/main.scss')
        .pipe(sass({outputStyle: 'compressed'}).on('error', sass.logError))
        .pipe(prefix(['last 2 versions'], { cascade: true }))
        .pipe(gulp.dest('assets/css'))
        .pipe(browserSync.reload({stream:true}));
});

// Watch SCSS & HTML files, run reload BrowserSync
gulp.task('watch', function () {
    gulp.watch('_sass/*/*.scss', ['sass']);
    gulp.watch("*.html").on('change', browserSync.reload);
});

// Default task, running just `gulp`
gulp.task('default', ['browser-sync', 'watch']);

var gulp        = require('gulp');
var browserSync = require('browser-sync');
var sass        = require('gulp-sass');
var prefix      = require('gulp-autoprefixer');

// Start Static Server with browserSync
gulp.task('server', function() {
    browserSync({
        server: {
            baseDir: "./"
        }
    });
});

// Watch SCSS files for changes, recompile, compress, autoprefixed
gulp.task('sass', function () {
    return gulp.src('./_sass/main.scss')
        .pipe(sass({outputStyle: 'compressed'}).on('error', sass.logError))
        .pipe(prefix(['last 2 versions'], { cascade: true }))
        .pipe(gulp.dest('./assets/css'))
        .pipe(browserSync.reload({stream:true}));
});

// Watch SCSS & HTML files, run reload BrowserSync
gulp.task('watch', function () {
    gulp.watch('./_sass/*/*.scss', ['sass']);
    gulp.watch("./*.html").on('change', browserSync.reload);
});

// Default task, running just `gulp`
gulp.task('default', ['server', 'watch']);

Update relative path, add ./ :metal:


import { BrowserWindow, globalShortcut } from 'electron';
import {
  INPUT_HEIGHT,
  WINDOW_WIDTH,
  RESULT_HEIGHT,
  MIN_VISIBLE_RESULTS
} from './constants/ui';

import buildMenu from './createWindow/buildMenu';

export default (url) => {
  const mainWindow = new BrowserWindow({
    alwaysOnTop: true,
    show: false,
    width: WINDOW_WIDTH,
    minWidth: WINDOW_WIDTH,
    maxWidth: WINDOW_WIDTH,
    height: INPUT_HEIGHT,
    minHeight: INPUT_HEIGHT + RESULT_HEIGHT * MIN_VISIBLE_RESULTS,
    frame: false,
    resizable: false
  });

  mainWindow.loadURL(url);

  if (process.env.NODE_ENV !== 'development') {
    // Hide window on blur in production move
    // In development we usually use developer tools
    mainWindow.on('blur', () => mainWindow.hide());
  }

  // const HOTKEY = 'Cmd+Alt+Shift+Control+Space';
  const HOTKEY = 'Control+Space';

  globalShortcut.register(HOTKEY, () => {
    mainWindow.show();
    mainWindow.focus();
  });

  buildMenu(mainWindow);
  return mainWindow;
}

import { BrowserWindow, globalShortcut } from 'electron';
import {
  INPUT_HEIGHT,
  WINDOW_WIDTH,
  RESULT_HEIGHT,
  MIN_VISIBLE_RESULTS
} from './constants/ui';

import buildMenu from './createWindow/buildMenu';

export default (url) => {
  const mainWindow = new BrowserWindow({
    alwaysOnTop: true,
    show: false,
    width: WINDOW_WIDTH,
    minWidth: WINDOW_WIDTH,
    maxWidth: WINDOW_WIDTH,
    height: INPUT_HEIGHT,
    minHeight: INPUT_HEIGHT + RESULT_HEIGHT * MIN_VISIBLE_RESULTS,
    frame: false,
    resizable: false
  });

  mainWindow.loadURL(url);

  if (process.env.NODE_ENV !== 'development') {
    // Hide window on blur in production move
    // In development we usually use developer tools
    mainWindow.on('blur', () => mainWindow.hide());
  }

  // const HOTKEY = 'Cmd+Alt+Shift+Control+Space';
  const HOTKEY = 'Control+Space';

  globalShortcut.register(HOTKEY, () => {
    if (mainWindow.isVisible()) {
      mainWindow.hide();
    } else {
      mainWindow.show();
      mainWindow.focus();
    }
  });

  buildMenu(mainWindow);
  return mainWindow;
}

Hide window by hotkey if it is visible


var express = require('express');
var app = express();

app.get('/', function(req, res){
    res.send('Hello World');
});

app.listen(3000);

var express = require('express'),
    enbMiddleware = require('enb/lib/server/server-middleware');

var app = express();

app.use(enbMiddleware.createMiddleware({
    cdir: process.cwd(),
    noLog: false
}));

app.get('/', function(req, res){
    res.send('Hello World');
});

app.listen(3000);

Add enb server-middleware to express


const http = require('http')

const url = 'http://ipecho.net/plain'
let req = http.get(url, (res) => {
  console.log('Status code:', res.statusCode)

  let body = []

  res.on('data', chunk => {
    body.push(chunk)
  })
  res.on('end', () => {
    console.log('Response body:', body.join(''))
  })
})

const http = require('http')

const url = 'http://ipecho.net/plain'
let req = http.get(url, (res) => {
  console.log('Status code:', res.statusCode)

  res.on('readable', () => {
    res.setEncoding('utf8')
    console.log(res.read())
  })
})

Use a more succinct way of printing out the response body


/**
 * @module ol/AssertionError
 */
import {VERSION} from './util.js';

/**
 * Error object thrown when an assertion failed. This is an ECMA-262 Error,
 * extended with a `code` property.
 * See https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Error.
 */
class AssertionError extends Error {

  /**
   * @param {number} code Error code.
   */
  constructor(code) {
    const path = VERSION.split('-')[0];
    const message = 'Assertion failed. See https://openlayers.org/en/' + path +
    '/doc/errors/#' + code + ' for details.';

    super(message);

    /**
     * Error code. The meaning of the code can be found on
     * https://openlayers.org/en/latest/doc/errors/ (replace `latest` with
     * the version found in the OpenLayers script's header comment if a version
     * other than the latest is used).
     * @type {number}
     * @api
     */
    this.code = code;

    /**
     * @type {string}
     */
    this.name = 'AssertionError';

    // Re-assign message, see https://github.com/Rich-Harris/buble/issues/40
    this.message = message;
  }

}

export default AssertionError;

/**
 * @module ol/AssertionError
 */
import {VERSION} from './util.js';

/**
 * Error object thrown when an assertion failed. This is an ECMA-262 Error,
 * extended with a `code` property.
 * See https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Error.
 */
class AssertionError extends Error {

  /**
   * @param {number} code Error code.
   */
  constructor(code) {
    const path = VERSION === 'latest' ? VERSION : 'v' + VERSION.split('-')[0];
    const message = 'Assertion failed. See https://openlayers.org/en/' + path +
    '/doc/errors/#' + code + ' for details.';

    super(message);

    /**
     * Error code. The meaning of the code can be found on
     * https://openlayers.org/en/latest/doc/errors/ (replace `latest` with
     * the version found in the OpenLayers script's header comment if a version
     * other than the latest is used).
     * @type {number}
     * @api
     */
    this.code = code;

    /**
     * @type {string}
     */
    this.name = 'AssertionError';

    // Re-assign message, see https://github.com/Rich-Harris/buble/issues/40
    this.message = message;
  }

}

export default AssertionError;

Fix assertion error documentation URL


const wrap = require('word-wrap');

function msgText(msg, charasMap) {
    if (msg.type === 'narrator') {
        return wrap(msg.content, { width: 72, indent: '', cut: true });
    } else if (msg.type === 'ooc') {
        return wrap(`(( OOC: ${msg.content} ))`, { width: 72, indent: '', cut: true });
    } else if (msg.type === 'chara') {
        const chara = charasMap.get(msg.charaId);
        const indentedContent = wrap(msg.content, { width: 70, indent: '  ', cut: true });
        return `${chara.name.toUpperCase()}:\n${indentedContent}`;
    } else if (msg.type === 'image') {
        return `--- IMAGE ---\n${msg.url}\n-------------`;
    }

    throw new Error(`Unexpected message type: ${msg.type}`);
}

module.exports = ({
    generateTextFile({ title, desc = null, msgs, charasMap, includeOOC }, writeRaw) {
        // Make sure to only write windows-compatible newlines
        const write = str => writeRaw(str.replace(/\n/g, '\r\n'));

        // header format
        write(`${title}\n${desc || ''}\n----------\n\n`);

        // Write each message
        msgs.forEach(msg => {
            console.log(msg)
            if (msg.type !== 'ooc' || includeOOC) {
                const msgBlock = msgText(msg, charasMap);
                write(msgBlock+'\n\n');
            }
        })
    },
});

const wrap = require('word-wrap');

function msgText(msg, charasMap) {
    if (msg.type === 'narrator') {
        return wrap(msg.content, { width: 72, indent: '', cut: true });
    } else if (msg.type === 'ooc') {
        return wrap(`(( OOC: ${msg.content} ))`, { width: 72, indent: '', cut: true });
    } else if (msg.type === 'chara') {
        const chara = charasMap.get(msg.charaId);
        const indentedContent = wrap(msg.content, { width: 70, indent: '  ', cut: true });
        return `${chara.name.toUpperCase()}:\n${indentedContent}`;
    } else if (msg.type === 'image') {
        return `--- IMAGE ---\n${msg.url}\n-------------`;
    }

    throw new Error(`Unexpected message type: ${msg.type}`);
}

module.exports = ({
    generateTextFile({ title, desc = null, msgs, charasMap, includeOOC }, writeRaw) {
        // Make sure to only write windows-compatible newlines
        const write = str => writeRaw(str.replace(/\n/g, '\r\n'));

        // header format
        write(`${title}\n${desc || ''}\n----------\n\n`);

        // Write each message
        msgs.forEach(msg => {
            if (msg.type !== 'ooc' || includeOOC) {
                const msgBlock = msgText(msg, charasMap);
                write(msgBlock+'\n\n');
            }
        })
    },
});

Remove console.log when exporting txt file


'use strict';

// Configuration for the New Relic Node.js agent

exports.config = {
    app_name: process.env.NEW_RELIC_APP_NAME || 'app',
    logging: {
        filepath: process.env.NEW_RELIC_LOG || 'stdout'
    }
};

'use strict';

// Configuration for the New Relic Node.js agent

module.exports.config = {
    app_name: process.env.NEW_RELIC_APP_NAME || 'app',
    logging: {
        filepath: process.env.NEW_RELIC_LOG || 'stdout'
    }
};

Use always "module.exports", not the alias "exports"


module.exports = {
    // Packet constants
    PLAYER_START: "1",
    PLAYER_ADD: "2",
    PLAYER_ANGLE: "2",
    PLAYER_UPDATE: "3",
    PLAYER_ATTACK :"4",
    LEADERBOAD: "5",
    PLAYER_MOVE: "3",
    PLAYER_REMOVE: "4",
    LEADERS_UPDATE: "5",
    LOAD_GAME_OBJ: "6",
    GATHER_ANIM: "7",
    AUTO_ATK: "7",
    WIGGLE: "8",
    CLAN_CREATE: "8",
    PLAYER_LEAVE_CLAN: "9",
    STAT_UPDATE: "9",
    CLAN_REQ_JOIN: "10",
    UPDATE_HEALTH: "10",
    CLAN_ACC_JOIN: "11",
    CLAN_KICK: "12",
    UPDATE_AGE: "15",
    CHAT: "ch",
    CLAN_DEL: "ad",
    PLAYER_SET_CLAN: "st",
    SET_CLAN_PLAYERS: "sa",
    CLAN_ADD: "ac",
    CLAN_NOTIFY: "an",
    MINIMAP: "mm",
    DISCONN: "d"
}

module.exports = {
    // Packet constants
    PLAYER_START: "1",
    PLAYER_ADD: "2",
    PLAYER_ANGLE: "2",
    PLAYER_UPDATE: "3",
    PLAYER_ATTACK :"4",
    LEADERBOAD: "5",
    PLAYER_MOVE: "3",
    PLAYER_REMOVE: "4",
    LEADERS_UPDATE: "5",
    LOAD_GAME_OBJ: "6",
    GATHER_ANIM: "7",
    AUTO_ATK: "7",
    WIGGLE: "8",
    CLAN_CREATE: "8",
    PLAYER_LEAVE_CLAN: "9",
    STAT_UPDATE: "9",
    CLAN_REQ_JOIN: "10",
    UPDATE_HEALTH: "10",
    CLAN_ACC_JOIN: "11",
    CLAN_KICK: "12",
    ITEM_BUY: "13",
    UPDATE_AGE: "15",
    CHAT: "ch",
    CLAN_DEL: "ad",
    PLAYER_SET_CLAN: "st",
    SET_CLAN_PLAYERS: "sa",
    CLAN_ADD: "ac",
    CLAN_NOTIFY: "an",
    MINIMAP: "mm",
    DISCONN: "d"
}

Add item buy packet code


// app.states.js

"use strict";

const appBlog = {
  name: "blog",
  url: "/blog",
  component: "blogComponent",
  lazyLoad: ($transition$) => {
    const $ocLazyLoad = $transition$.injector().get("$ocLazyLoad");

    return import(/* webpackChunkName: "blog.module" */ "./pages/blog/blog.module")
      .then(mod => $ocLazyLoad.load(mod.BLOG_MODULE));
  }
};

export { appBlog };

// app.states.js

"use strict";

const appBlog = {
  name: "blog",
  url: "/blog",
  component: "blogComponent",
  lazyLoad: ($transition$) => {
    const $ocLazyLoad = $transition$.injector().get("$ocLazyLoad");
    const blogModule = () => import(/* webpackChunkName: "blog.module" */ "./pages/blog/blog.module");

    return blogModule()
      .then(mod => $ocLazyLoad.load(mod.BLOG_MODULE))
      .catch(err => console.error("Ooops... ", err));
  }
};

export { appBlog };

Edit lazyLoad for appBlog state


import Vue from 'vue'
import VueI18n from 'vue-i18n'
import VeeValidate from 'vee-validate'

let en = require('../store/lang/en.json'),
    pl = require('../store/lang/pl.json'),
    de = require('../store/lang/de.json'),
    es = require('../store/lang/es.json');

Vue.use(VueI18n)
Vue.locale('en', en)
Vue.locale('pl', pl)
Vue.locale('de', de)
Vue.locale('es', es)

function toLambdas(obj) {
    let newObj = {}
    for (let key in obj) {
        newObj[key] = () => obj[key]
    }
    return newObj
}

Vue.use(VeeValidate, {
    locale: 'en',
    dictionary: {
        pl: {
            messages: toLambdas(pl.validation)
        },
        en: {
            messages: toLambdas(en.validation)
        },
        de: {
            messages: toLambdas(en.validation)
        },
        es: {
            messages: toLambdas(es.validation)
        }
    }
})

import Vue from 'vue'
import VueI18n from 'vue-i18n'
import VeeValidate from 'vee-validate'

let en = require('../store/lang/en.json'),
    pl = require('../store/lang/pl.json'),
    de = require('../store/lang/de.json'),
    es = require('../store/lang/es.json');

Vue.use(VueI18n)
Vue.locale('en', en)
Vue.locale('pl', pl)
Vue.locale('de', de)
Vue.locale('es', es)

function toLambdas(obj) {
    let newObj = {}
    for (let key in obj) {
        newObj[key] = () => obj[key]
    }
    return newObj
}

Vue.use(VeeValidate, {
    locale: 'en',
    dictionary: {
        pl: {
            messages: toLambdas(pl.validation)
        },
        en: {
            messages: toLambdas(en.validation)
        },
        de: {
            messages: toLambdas(en.validation)
        },
        es: {
            messages: toLambdas(es.validation)
        }
    },
    errorBagName: 'verrors'
})

Fix vee-validate collision with errors property of v-text-fields


'use strict';

// Send page content to update data live
browser.runtime.sendMessage({
    type: 'pontoon-page-loaded',
    url: document.location.toString(),
    value: document.documentElement.innerHTML
});

const unreadNotificationsIcon = document.querySelector('#notifications.unread .button .icon');

/**
 * Remove itself as a click listener and send message to the background to mark all notifications as read.
 */
function unreadNotificationsIconClick() {
    unreadNotificationsIcon.removeEventListener('click', unreadNotificationsIconClick);
    browser.runtime.sendMessage({type: 'mark-all-notifications-as-read-from-page'});
}

if (unreadNotificationsIcon !== null) {
    unreadNotificationsIcon.addEventListener('click', unreadNotificationsIconClick);

    // Listen to messages from background to mark all notifications as read (change the bell icon color)
    browser.runtime.onMessage.addListener((request, sender, sendResponse) => {
        if (request.type === 'mark-all-notifications-as-read-from-extension') {
            unreadNotificationsIcon.style.color = '#4D5967';
        }
    });
}

'use strict';

// Send page content to update data live
browser.runtime.sendMessage({
    type: 'pontoon-page-loaded',
    url: document.location.toString(),
    value: document.documentElement.innerHTML
});

const unreadNotificationsIcon = document.querySelector('#notifications.unread .button .icon');

/**
 * Remove itself as a click listener and send message to the background to mark all notifications as read.
 */
function unreadNotificationsIconClick() {
    unreadNotificationsIcon.removeEventListener('click', unreadNotificationsIconClick);
    browser.runtime.sendMessage({type: 'mark-all-notifications-as-read-from-page'});
}

if (unreadNotificationsIcon !== null) {
    unreadNotificationsIcon.addEventListener('click', unreadNotificationsIconClick);

    // Listen to messages from background to mark all notifications as read (change the bell icon color)
    browser.runtime.onMessage.addListener((request, sender, sendResponse) => {
        if (request.type === 'mark-all-notifications-as-read-from-extension') {
            document.getElementById('notifications').classList.remove('unread');
        }
    });
}

Remove unread class from the icon when notifications are marked as read


import $ from 'jquery';

import topInfoBar from './templates/topInfoBar.jade';
import VisComponent from '../../VisComponent';

class TopInfoBar extends VisComponent {
  constructor (el, settings) {
    super(el);
    this.$el = $(this.el);

    this.name = settings.name || 'Ground Truth';
    this.branch = settings.branch || 'No branch set';
    this.day = settings.day || this.getToday();
    this.submissionUuid = settings.submission_uuid;
    this.helpLink = settings.help_link || 'https://github.com/Trailmix/RedwoodInternal/wiki/Midas-for-Metrics-Based-Testing#performance-dashboards';
  }

  render () {
    this.$el.html(topInfoBar({
      name: this.name,
      branch: this.branch,
      day: this.day,
      uuid: this.submissionUuid,
      helpLink: this.helpLink
    }));
  }
}

export default TopInfoBar;

import $ from 'jquery';

import topInfoBar from './templates/topInfoBar.jade';
import VisComponent from '../../VisComponent';

class TopInfoBar extends VisComponent {
  constructor (el, settings) {
    super(el);
    this.$el = $(this.el);

    this.name = settings.name || 'Ground Truth';
    this.branch = settings.branch || 'No branch set';
    this.day = settings.day || this.getToday();
    this.submissionUuid = settings.submission_uuid;
    this.helpLink = settings.help_link;
  }

  render () {
    this.$el.html(topInfoBar({
      name: this.name,
      branch: this.branch,
      day: this.day,
      uuid: this.submissionUuid,
      helpLink: this.helpLink
    }));
  }
}

export default TopInfoBar;

Remove mention of private GitHub project


var util = require('util'),
    BaseHash = require('./BaseHash');

util.inherits(BitwiseHash, BaseHash);

/**
 * BitwiseHash class
 * @description :: Convert data to 32bit integer
 * @constructor
 */
function BitwiseHash(options) {
    BaseHash.apply(this, arguments);
}

/**
 * Hash data by bitwise function
 * @returns {String} Returns hashed data
 */
BitwiseHash.prototype.hash = function () {
    var data = this.getData(),
        hash = 0;

    for (var i = 0; i < data.length; i++) {
        var ch = data.charCodeAt(i);
        hash = ((hash << 5) - hash) + ch;
        hash = hash & hash;
    }

    return hash;
};

module.exports = BitwiseHash;

var util = require('util'),
    BaseHash = require('./BaseHash');

util.inherits(BitwiseHash, BaseHash);

/**
 * BitwiseHash class
 * @description :: Convert data to 32bit integer
 * @constructor
 */
function BitwiseHash(options) {
    BaseHash.apply(this, arguments);
}

/**
 * Hash data by bitwise function
 * @returns {Number} Returns hashed data
 */
BitwiseHash.prototype.hash = function () {
    var data = this.getData().toString(),
        hash = 0;

    for (var i = 0; i < data.length; i++) {
        hash = ((hash << 5) - hash) + data.charCodeAt(i);
        hash = hash & hash;
    }

    return hash;
};

module.exports = BitwiseHash;

Fix bug with string representation in bitwise hash


testFiles = [
  'graphics.js',
  'displayObject.js',
  'displayObjectContainer.js',
  // 'eventDispatcher.js',
  'broadcastEvents.js',
  'bitmap.js',
  'stage.js',
  'filters.js',
  'mouse.js',
  'matrix3D.js',
];

testFiles = [
  'graphics.js',
  'displayObject.js',
  'displayObjectContainer.js',
  // 'eventDispatcher.js',
  'broadcastEvents.js',
  'bitmap.js',
  'stage.js',
  'filters.js'
];

Remove tests that are not committed.


var CMS = require('../agents/cms');

module.exports = {
  displayCMSPage: function(request, reply) {
    CMS(request.params.slug).then(function(page) {
      reply.view('cms', {
        page: page,
        title: page.title
      });
    });
  }
}

var CMS = require('../agents/cms');

module.exports = {
  displayCMSPage: function(request, reply) {
    CMS(request.params.slug).then(function(page) {
      reply.view('cms', {
        page: page,
        title: page.title
      });
    }, function(err) {
      request.logger.error(err);
      if (err.statusCode == 404) {
        return reply.view('errors/not-found', err).code(404);
      } else {
        return reply.view('errors/internal', err).code(500);
      }
    }).catch(function(err) {
      request.logger.error(err);
    });
  }
}

Handle errors in CMS handler


'use strict';

var _ = require('lodash'),
    path = require('path');

_.extend(exports, {
  envOverrides: {},

  supervisordConfigPath: function() {
    var config = require('api-umbrella-config').global();
    return path.join(config.get('etc_dir'), 'supervisord.conf');
  },

  env: function() {
    return _.merge({
      'PATH': [
        path.resolve(__dirname, '../bin'),
        path.resolve(__dirname, '../node_modules/.bin'),
        '/opt/api-umbrella/embedded/elasticsearch/bin',
        '/opt/api-umbrella/embedded/sbin',
        '/opt/api-umbrella/embedded/bin',
        '/usr/local/sbin',
        '/usr/local/bin',
        '/usr/sbin',
        '/usr/bin',
        '/sbin',
        '/bin',
      ].join(':'),
    }, this.envOverrides);
  },

  overrideEnv: function(overrides) {
    this.envOverrides = overrides;
  },
});

'use strict';

var _ = require('lodash'),
    path = require('path');

_.extend(exports, {
  envOverrides: {},

  supervisordConfigPath: function() {
    var config = require('api-umbrella-config').global();
    return path.join(config.get('etc_dir'), 'supervisord.conf');
  },

  env: function() {
    return _.merge({
      'PATH': [
        path.resolve(__dirname, '../bin'),
        path.resolve(__dirname, '../node_modules/.bin'),
        '/opt/api-umbrella/embedded/elasticsearch/bin',
        '/opt/api-umbrella/embedded/sbin',
        '/opt/api-umbrella/embedded/bin',
        '/opt/api-umbrella/embedded/jre/bin',
        '/usr/local/sbin',
        '/usr/local/bin',
        '/usr/sbin',
        '/usr/bin',
        '/sbin',
        '/bin',
      ].join(':'),
    }, this.envOverrides);
  },

  overrideEnv: function(overrides) {
    this.envOverrides = overrides;
  },
});

Fix missing embedded java path for starting elasticsearch.


// O3S - Deltascape 3.0 Savage
[{
  zoneRegex: /(The Unending Coil Of Bahamut \(Ultimate\)|Unknown Zone \(xyz\))/,
  triggers: [
    {
      id: 'UCU Something',
      regex: /:Boss starts using Thing/,
    },
  ]
}]

// UCU - The Unending Coil Of Bahamut (Ultimate)
[{
  zoneRegex: /(The Unending Coil Of Bahamut \(Ultimate\)|Unknown Zone \(.*?\))/,
  triggers: [
    { id: 'UCU Twisters',
      regex: /:Twintania starts using Twisters/,
      alertText: function(data) {
        return 'Twisters';
      },
    },
  ]
}]

Fix zone name comment, make UCU triggers work anywhere. Add twisters.


var through2 = require('through2');

function featureCodeToLayer(featureCode) {
  switch (featureCode) {
      case 'PCLI':
          return 'country';
      case 'ADM1':
          return 'region';
      case 'ADM2':
          return 'county';
      case 'ADMD':
          return 'localadmin';
      case 'PPL':
      case 'PPLA':
      case 'PPLA2':
      case 'PPLA3':
      case 'PPLA4':
      case 'PPLC':
      case 'PPLF':
      case 'PPLG':
      case 'PPLL':
      case 'PPLS':
      case 'STLMT':
          return 'locality';
      case 'ADM4':
      case 'ADM5':
      case 'PPLX':
          return 'neighborhood';
      default:
          return 'venue';
  }
}

function create() {
  return through2.obj(function(data, enc, next) {
    data.layer = featureCodeToLayer(data.feature_code);

    next(null, data);
  });
}

module.exports = {
  featureCodeToLayer: featureCodeToLayer,
  create: create
};

var through2 = require('through2');

function featureCodeToLayer(featureCode) {
  switch (featureCode) {
      case 'PCLI':
          return 'country';
      case 'ADM1':
          return 'region';
      case 'ADM2':
          return 'county';
      case 'ADMD':
          return 'localadmin';
      case 'PPL':
      case 'PPLA':
      case 'PPLA2':
      case 'PPLA3':
      case 'PPLA4':
      case 'PPLC':
      case 'PPLF':
      case 'PPLG':
      case 'PPLL':
      case 'PPLS':
      case 'LCTY':
      case 'STLMT':
          return 'locality';
      case 'ADM4':
      case 'ADM5':
      case 'PPLX':
          return 'neighborhood';
      default:
          return 'venue';
  }
}

function create() {
  return through2.obj(function(data, enc, next) {
    data.layer = featureCodeToLayer(data.feature_code);

    next(null, data);
  });
}

module.exports = {
  featureCodeToLayer: featureCodeToLayer,
  create: create
};

Add LCTY to locality 🎢


import React, { PropTypes } from 'react';

const ModuleTable = ({
  modules,
  removeModule,
}) => (

      {modules.map(module =>

          {module.ModuleCode}
          {module.ModuleTitle}

            <button
              className="btn btn-sm btn-danger"
              onClick={() => removeModule(module.ModuleCode)}
            >
              Remove
            </button>

      )}

);

ModuleTable.propTypes = {
  modules: PropTypes.array.isRequired,
  removeModule: PropTypes.func.isRequired,
};

export default ModuleTable;

import React, { PropTypes } from 'react';
import { Table, TableBody, TableRow, TableRowColumn } from 'material-ui/Table';

const ModuleTable = ({
  modules,
  removeModule,
}) => (
  <Table
    selectable={false}
    style={{ tableLayout: 'auto' }}
  >
    <TableBody
      displayRowCheckbox={false}
    >
      {modules.map(module =>
        <TableRow key={module.ModuleCode}>
          <TableRowColumn>{module.ModuleCode}</TableRowColumn>
          <TableRowColumn>{module.ModuleTitle}</TableRowColumn>
          <TableRowColumn>
            <button
              className="btn btn-sm btn-danger"
              onClick={() => removeModule(module.ModuleCode)}
            >
              Remove
            </button>
          </TableRowColumn>
        </TableRow>
      )}
    </TableBody>
  </Table>
);

ModuleTable.propTypes = {
  modules: PropTypes.array.isRequired,
  removeModule: PropTypes.func.isRequired,
};

export default ModuleTable;

Use material-ui Table for module table


var _ = require('./utils'),
    Reflux = require('../src'),
    Keep = require('./Keep'),
    allowed = {preEmit:1,shouldEmit:1};

/**
 * Creates an action functor object. It is mixed in with functions
 * from the `PublisherMethods` mixin. `preEmit` and `shouldEmit` may
 * be overridden in the definition object.
 *
 * @param {Object} definition The action object definition
 */
module.exports = function(definition) {

    definition = definition || {};

    for(var d in definition){
        if (!allowed[d] && Reflux.PublisherMethods[d]) {
            throw new Error("Cannot override API method " + d +
                " in action creation. Use another method name or override it on Reflux.PublisherMethods instead."
            );
        }
    }

    var context = _.extend({
        eventLabel: "action",
        emitter: new _.EventEmitter()
        _isAction: true
    },Reflux.PublisherMethods,definition);

    var functor = function() {
        functor[functor.sync?"trigger":"triggerAsync"].apply(functor, arguments);
    };

    _.extend(functor,context);

    Keep.createdActions.push(functor);

    return functor;

};

var _ = require('./utils'),
    Reflux = require('../src'),
    Keep = require('./Keep'),
    allowed = {preEmit:1,shouldEmit:1};

/**
 * Creates an action functor object. It is mixed in with functions
 * from the `PublisherMethods` mixin. `preEmit` and `shouldEmit` may
 * be overridden in the definition object.
 *
 * @param {Object} definition The action object definition
 */
module.exports = function(definition) {

    definition = definition || {};

    for(var d in definition){
        if (!allowed[d] && Reflux.PublisherMethods[d]) {
            throw new Error("Cannot override API method " + d +
                " in action creation. Use another method name or override it on Reflux.PublisherMethods instead."
            );
        }
    }

    var context = _.extend({
        eventLabel: "action",
        emitter: new _.EventEmitter(),
        _isAction: true
    },Reflux.PublisherMethods,definition);

    var functor = function() {
        functor[functor.sync?"trigger":"triggerAsync"].apply(functor, arguments);
    };

    _.extend(functor,context);

    Keep.createdActions.push(functor);

    return functor;

};

Fix missing comma after merge


import { get } from 'lodash/object';

export default (size = 0, attrs = {}) => (
  size ? {
    w: parseInt(size, 10),
    h: get(attrs, 'h', attrs.height)
      ? (parseInt(size, 10) / parseInt(get(attrs, 'w', attrs.width), 10)) * parseInt(get(attrs, 'h', attrs.height), 10)
      : ''
  } : {}
);

import { get } from 'lodash/object';
import { round } from 'lodash/math';

export default (size = 0, attrs = {}) => (
  size ? {
    w: parseInt(size, 10),
    h: get(attrs, 'h', attrs.height)
      ? round(parseInt(size, 10) / parseInt(get(attrs, 'w', attrs.width), 10)) * parseInt(get(attrs, 'h', attrs.height), 10)
      : ''
  } : {}
);

Fix decimal image with on request


//
// Load private chat history from the archive
//
(function () {
    var connection;

    $(document).on('connected.ditto.chat', function (e, conn) {
        var an_hour_ago = new Date();
        an_hour_ago.setHours(an_hour_ago.getHours() - 1);
        connection = conn;
	connection.mam.init(connection);
	connection.mam.query(
	    Strophe.getBareJidFromJid(DITTO.chat_name),
	    {
		'with': Strophe.getBareJidFromJid(DITTO.chatee),
                'start': an_hour_ago.toISOString(),
                // 'max': 10,
		onMessage: onArchivedPrivateMessage
	    }
	);
    });

    function onArchivedPrivateMessage(msg) {
	var msg = $(msg);
	var body = msg.find("body:first").text();
	var from = msg.find('message').attr("from").split('@')[0];
        var when = new Date(msg.find('delay').attr('stamp'));
	DITTO.chat.renderPrivateMessage(from, when, body);
	return true;
    }

})();

//
// Load private chat history from the archive
//
(function () {
    var connection;

    $(document).on('connected.ditto.chat', function (e, conn) {
        connection = conn;
	connection.mam.init(connection);
	connection.mam.query(
	    Strophe.getBareJidFromJid(DITTO.chat_name),
	    {
		'with': Strophe.getBareJidFromJid(DITTO.chatee),
                'before': "",
                'max': 20,
		onMessage: onArchivedPrivateMessage
	    }
	);
    });

    function onArchivedPrivateMessage(msg) {
        var msg = $(msg);
        var body = msg.find("body:first").text();
        var from = msg.find('message').attr("from").split('@')[0];
        var when = new Date(msg.find('delay').attr('stamp'));
        DITTO.chat.renderPrivateMessage(from, when, body);
        return true;
    }

})();

Load 20 most recent pchats


var _ = require("lodash");
var Q = require("q");
var fs = require("./fs");
var exec = require('child_process').exec;
var request = require("request");

var links = require("./links");

// Convert a svg file
var convertSVGFile = function(source, dest, options) {
	var d = Q.defer();

	options = _.defaults(options || {}, {

	});

	var command = "svgexport "+source+" "+dest;

    var child = exec(command, function (error, stdout, stderr) {
        if (error) {
        	if (error.code == "ENOENT") error = new Error("Need to install 'svgexport' using 'npm install svgexport -g'");
        	return d.reject(error);
        }
        d.resolve();
    });

	return d.promise;
};

// Convert a svg file or url
var convertSVG = function(source, dest, options) {
	if (!links.isExternal(source)) return convertSVGFile(source, dest, options);

	return fs.tmp.file({ postfix: '.svg' })

	// Download file
	.then(function(tmpfile) {
		return fs.writeStream(tmpfile, request(source))
		.thenResolve(tmpfile);
	})
	.then(function(tmpfile) {
		return convertSVGFile(tmpfile, dest, options);
	});
};

module.exports = {
	convertSVG: convertSVG,
	INVALID: [".svg"]
};

var _ = require("lodash");
var Q = require("q");
var fs = require("./fs");
var exec = require('child_process').exec;
var request = require("request");

var links = require("./links");

// Convert a svg file
var convertSVGFile = function(source, dest, options) {
	var d = Q.defer();

	options = _.defaults(options || {}, {

	});

	var command = "svgexport "+source+" "+dest;

    var child = exec(command, function (error, stdout, stderr) {
        if (error) {
        	if (error.code == 127) error = new Error("Need to install 'svgexport' using 'npm install svgexport -g'");
        	return d.reject(error);
        }
        d.resolve();
    });

	return d.promise;
};

// Convert a svg file or url
var convertSVG = function(source, dest, options) {
	if (!links.isExternal(source)) return convertSVGFile(source, dest, options);

	return fs.tmp.file({ postfix: '.svg' })

	// Download file
	.then(function(tmpfile) {
		return fs.writeStream(tmpfile, request(source))
		.thenResolve(tmpfile);
	})
	.then(function(tmpfile) {
		return convertSVGFile(tmpfile, dest, options);
	});
};

module.exports = {
	convertSVG: convertSVG,
	INVALID: [".svg"]
};

Fix error message when svgexport is not installed