import React from 'react';
import { View } from 'react-native';

import { computePosition, styles } from './ContextMenu';

/**
Simplified version of ContextMenu without animation.
*/
export default class NotAnimatedContextMenu extends React.Component {

  render() {
    const { style, children, layouts, ...other } = this.props;
    const position = computePosition(layouts);
    return (
      <View {...other} style={[styles.options, style, position]}>
        {children}
      </View>
    );
  }

}

import React from 'react';
import { I18nManager, View } from 'react-native';

import { computePosition, styles } from './ContextMenu';

/**
Simplified version of ContextMenu without animation.
*/
export default class NotAnimatedContextMenu extends React.Component {

  render() {
    const { style, children, layouts, ...other } = this.props;
    const position = computePosition(layouts, I18nManager.isRTL);
    return (
      <View {...other} style={[styles.options, style, position]}>
        {children}
      </View>
    );
  }

}

Add RTL for not animated menu


module.exports = {
    extends: [
        'onelint'
    ],
    plugins: ['import'],
    rules: {
        'import/no-extraneous-dependencies': [
            'error', {
                devDependencies: [ '**/test/**/*.js' ],
                optionalDependencies: false,
                peerDependencies: false
            }
        ]
    }
};

module.exports = {
    extends: [
        'onelint'
    ],
    plugins: ['import'],
    rules: {
        'import/no-extraneous-dependencies': [
            'error', {
                devDependencies: [ '**/test/**/*.js', '**/bootstrap-unexpected-markdown.js' ],
                optionalDependencies: false,
                peerDependencies: false
            }
        ]
    }
};

Allow use of 'require' in the docs bootstrap


import React from 'react'
import Helmet from 'react-helmet'
import { graphql } from 'gatsby'
import Layout from '../components/Layout'
import PostTemplateDetails from '../components/PostTemplateDetails'

class PostTemplate extends React.Component {
  render() {
    const { title, subtitle } = this.props.data.site.siteMetadata
    const post = this.props.data.markdownRemark
    const { title: postTitle, description: postDescription } = post.frontmatter
    const description = postDescription !== null ? postDescription : subtitle

    return (
      <Layout>
        <div>
          <Helmet>
            <title>{`${postTitle} - ${title}`}</title>
            <meta name="description" content={description} />
          </Helmet>
          <PostTemplateDetails {...this.props} />
        </div>
      </Layout>
    )
  }
}

export default PostTemplate

export const pageQuery = graphql`
  query PostBySlug($slug: String!) {
    site {
      siteMetadata {
        title
        subtitle
        copyright
        author {
          name
          twitter
        }
        url
      }
    }
    markdownRemark(fields: { slug: { eq: $slug } }) {
      id
      html
      excerpt
      fields {
        tagSlugs
      }
      frontmatter {
        title
        tags
        date
      }
    }
  }
`

import React from 'react'
import Helmet from 'react-helmet'
import { graphql } from 'gatsby'
import Layout from '../components/Layout'
import PostTemplateDetails from '../components/PostTemplateDetails'

class PostTemplate extends React.Component {
  render() {
    const { title, subtitle } = this.props.data.site.siteMetadata
    const post = this.props.data.markdownRemark
    const { title: postTitle, description: postDescription } = post.frontmatter
    const description = postDescription !== null ? postDescription : subtitle

    return (
      <Layout>
        <div>
          <Helmet>
            <title>{`${postTitle} - ${title}`}</title>
            <meta name="description" content={description} />
          </Helmet>
          <PostTemplateDetails {...this.props} />
        </div>
      </Layout>
    )
  }
}

export default PostTemplate

export const pageQuery = graphql`
  query PostBySlug($slug: String!) {
    site {
      siteMetadata {
        title
        subtitle
        copyright
        author {
          name
          email
          twitter
          github
          linkedin
        }
        url
      }
    }
    markdownRemark(fields: { slug: { eq: $slug } }) {
      id
      html
      excerpt
      fields {
        tagSlugs
      }
      frontmatter {
        title
        tags
        date
      }
    }
  }
`

Fix social links at the bottom of posts


var walk = require('dom-walk')

var FormData = require('./index.js')

module.exports = getFormData

function buildElems(rootElem) {
    var hash = {}
    if (rootElem.name) {
    	hash[rootElem.name] = rootElem
    	return hash
    }

    walk(rootElem, function (child) {
        if (child.name) {
            hash[child.name] = child
        }
    })

    return hash
}

function getFormData(rootElem) {
    var elements = buildElems(rootElem)

    return FormData(elements)
}

var walk = require('dom-walk')

var FormData = require('./index.js')

module.exports = getFormData

function buildElems(rootElem) {
    var hash = {}
    if (rootElem.name) {
    	hash[rootElem.name] = rootElem
    }

    walk(rootElem, function (child) {
        if (child.name) {
            hash[child.name] = child
        }
    })

    return hash
}

function getFormData(rootElem) {
    var elements = buildElems(rootElem)

    return FormData(elements)
}

Remove return early from buildElems


var mongoose     = require('mongoose');
var Schema       = mongoose.Schema;

var Objectid = mongoose.Schema.Types.ObjectId;

var BookingSchema   = new Schema({
	room: Objectid,
	start_time: Date,
	end_time: Date,
	title: String,
	member: String,
	_owner_id: Objectid
});

BookingSchema.set("_perms", {
	admin: "crud",
	owner: "crud",
	user: "cr",
});

module.exports = mongoose.model('Booking', BookingSchema);

var mongoose     = require('mongoose');
var Schema       = mongoose.Schema;

var Objectid = mongoose.Schema.Types.ObjectId;

var BookingSchema   = new Schema({
	room: Objectid,
	start_time: Date,
	end_time: Date,
	title: String,
	member: String,
	cost: Number,
	_owner_id: Objectid
});

BookingSchema.set("_perms", {
	admin: "crud",
	owner: "crud",
	user: "cr",
});

BookingSchema.post("save", function(transaction) { //Keep our running total up to date
	try {
		var Reserve = require("./reserve_model");
		var reserve = Reserve({
			user_id: transaction._owner_id,
			description: "Booking",
			amount: transaction.cost * -1,
			cred_type: "space",
			source_type: "booking",
			source_id: transaction._id
		});
		reserve.save();
	} catch(err) {
		console.log("Error", err);
		// throw(err);
	}
});

BookingSchema.post("remove", function(transaction) { //Keep our running total up to date
	console.log("Going to remove reserve");
	console.log(transaction);
	try {
		var Reserve = require("./reserve_model");
		Reserve.findOne({
			source_type: "booking",
			source_id: transaction._id
		}, function(err, item) {
			if (err) {
				console.log("Error", err);
				return;
			}
			if (!item) {
				console.log("Could not find Reserve");
				return;
			}
			item.remove();
		});
	} catch(err) {
		console.log("Error", err);
		// throw(err);
	}
});

module.exports = mongoose.model('Booking', BookingSchema);

Handle Reserve from Booking Model


'use strict'

import * as types from '../constants/action-types'
import { REQUEST_PAGE_START_FROM } from '../constants/author-page'

import get from 'lodash/get'
import isArray from 'lodash/isArray'
import merge from 'lodash/merge'
import uniq from 'lodash/uniq'

const _ = {
  get,
  isArray,
  merge,
  uniq
}

const initialStates = {
  isFetching: false
}

export const author = (state = initialStates, action = {}) => {
  switch (action.type) {
    case types.FETCH_AUTHOR_COLLECTION_REQUEST:
      return Object.assign({}, state, {
        isFetching: true
      })
    case types.FETCH_AUTHOR_COLLECTION_SUCCESS:
      const {
        authorId,
        response,
        currentPage,
        totalResults,
        totalPages,
        receivedAt } = action
      const previousCollectionIdList = _.get(state, [ authorId, 'collectIndexList' ], [])
      const saveToState = {
        isFetching: false,
        [authorId]: {
          collectIndexList: _.uniq(previousCollectionIdList.concat(_.get(response, 'result', []))),
          currentPage,
          totalResults,
          receivedAt,
          isFinish: (currentPage - REQUEST_PAGE_START_FROM + 1 >= totalPages)
        }
      }
      return _.merge({}, state, saveToState)
    case types.FETCH_AUTHOR_COLLECTION_FAILURE:
      return Object.assign({}, state, {
        isFetching: false,
        error: action.error
      })
    default:
      return state
  }
}

'use strict'

import * as types from '../constants/action-types'
import { REQUEST_PAGE_START_FROM } from '../constants/author-page'

import get from 'lodash/get'
import isArray from 'lodash/isArray'
import uniq from 'lodash/uniq'

const _ = {
  get,
  isArray,
  uniq
}

const initialStates = {
  isFetching: false
}

export const author = (state = initialStates, action = {}) => {
  switch (action.type) {
    case types.FETCH_AUTHOR_COLLECTION_REQUEST:
      return Object.assign({}, state, {
        isFetching: true
      })
    case types.FETCH_AUTHOR_COLLECTION_SUCCESS:
      const {
        authorId,
        response,
        currentPage,
        totalResults,
        totalPages,
        receivedAt } = action
      const previousCollectionIdList = _.get(state, [ authorId, 'collectIndexList' ], [])
      const saveToState = {
        isFetching: false,
        [authorId]: {
          collectIndexList: _.uniq(previousCollectionIdList.concat(_.get(response, 'result', []))),
          currentPage,
          totalResults,
          receivedAt,
          isFinish: (currentPage - REQUEST_PAGE_START_FROM + 1 >= totalPages)
        }
      }
      return Object.assign({}, state, saveToState)
    case types.FETCH_AUTHOR_COLLECTION_FAILURE:
      return Object.assign({}, state, {
        isFetching: false,
        error: action.error
      })
    default:
      return state
  }
}

Use assign instead of merge


o_.capitaliseFirstLetter = function(string){
    return string.charAt(0).toUpperCase() + string.slice(1);
};

o_.lowerFirstLetter = function(string){
    if(!string) return;
    return string.charAt(0).toLowerCase() + string.slice(1);
};

o_.sanitizeObject = function(object){
    if(Meteor.isServer){
        var sanitizedObject = {};
        _.each(_.pairs(object), function(lonelyArray){
            sanitizedObject[lonelyArray[0]] = sanitizeHtml(lonelyArray[1], {allowedTags: [], allowedAttributes: {}});
        });

        return sanitizedObject
    }
};

o_.sanitizeArray = function(array){
    if(Meteor.isServer){
        var sanitizedArray = [];
        _.each(array, function(string){
            sanitizedArray.push(sanitizeHtml(string, {allowedTags: [], allowedAttributes: {}}));
        });

        return sanitizedArray;
    }
};

o_.sanitizeString = function(string){
    if(Meteor.isServer){
        return sanitizeHtml(string, {allowedTags: [], allowedAttributes: {}});
    }
}

o_.capitaliseFirstLetter = function(string){
    return string.charAt(0).toUpperCase() + string.slice(1);
};

o_.lowerFirstLetter = function(string){
    if(!string) return;
    return string.charAt(0).toLowerCase() + string.slice(1);
};

o_.sanitizeObject = function(object){
    if(Meteor.isServer){
        var sanitizedObject = {};
        _.each(_.pairs(object), function(lonelyArray){
            if(sanitizedObject[0] === "summary"){
                sanitizedObject[lonelyArray[0]] = sanitizeHtml(lonelyArray[1],
                    {allowedTags: ["a"], allowedAttributes: {"a": ["href"]}});
            } else {
                sanitizedObject[lonelyArray[0]] = sanitizeHtml(lonelyArray[1], {allowedTags: [], allowedAttributes: {}});
            }
        });

        return sanitizedObject
    }
};

o_.sanitizeArray = function(array){
    if(Meteor.isServer){
        var sanitizedArray = [];
        _.each(array, function(string){
            sanitizedArray.push(sanitizeHtml(string, {allowedTags: [], allowedAttributes: {}}));
        });

        return sanitizedArray;
    }
};

o_.sanitizeString = function(string){
    if(Meteor.isServer){
        return sanitizeHtml(string, {allowedTags: [], allowedAttributes: {}});
    }
}

Allow <a>-tags for policyAreas.summary and policies.summary


/* boilerUtils
 * This object holds functions that assist Boilerplate
 */

var boilerUtils = {}

boilerUtils.renderAction = function renderAction (action) {
  return {
    'string': altboiler.getTemplate,
    'function': action
  }[typeof action](action)
},

boilerUtils.getBoilerTemplateData = function getTemplateData (includes, content, options) {
  return {
    script: Assets.getText('assets/loader.js'),
    styles: Assets.getText('assets/styles.css'),
    content: content,
    head: '"' + encodeURIComponent(includes['head'].join('\n')) + '"',
    body: '"' + encodeURIComponent(includes['body'].join('\n')) + '"',
    jsIncludes: EJSON.stringify(includes['js']),
    onLoadHooks: '[' + boilerUtils.parseOnLoadHooks(options.onLoad).join(',') + ']',
    meteorRuntimeConfig: EJSON.stringify(__meteor_runtime_config__ || {})
  }
},

/* boilerUtils.parseOnLoadHooks(hooksArr)
 * `hooksArr` - An array of hooks to parse
 * Maps through the array;
 * simply executing and returning `toString`
 */
boilerUtils.parseOnLoadHooks = function parseOnLoadHooks (hooksArr) {
  return _.invoke(hooksArr, 'toString')
}

altboilerScope = altboilerScope || {}
altboilerScope._boilerUtils = boilerUtils

/* boilerUtils
 * This object holds functions that assist Boilerplate
 */

var boilerUtils = {}

boilerUtils.renderAction = function renderAction (action) {
  return {
    'string': altboiler.getTemplate,
    'function': action
  }[typeof action](action)
},

boilerUtils.getBoilerTemplateData = function getTemplateData (includes, content, onLoadHooks) {
  return {
    script: Assets.getText('assets/loader.js'),
    styles: Assets.getText('assets/styles.css'),
    content: content,
    head: '"' + encodeURIComponent(includes['head'].join('\n')) + '"',
    body: '"' + encodeURIComponent(includes['body'].join('\n')) + '"',
    jsIncludes: EJSON.stringify(includes['js']),
    onLoadHooks: '[' + boilerUtils.parseOnLoadHooks(onLoadHooks).join(',') + ']',
    meteorRuntimeConfig: EJSON.stringify(__meteor_runtime_config__ || {})
  }
},

/* boilerUtils.parseOnLoadHooks(hooksArr)
 * `hooksArr` - An array of hooks to parse
 * Maps through the array;
 * simply executing and returning `toString`
 */
boilerUtils.parseOnLoadHooks = function parseOnLoadHooks (hooksArr) {
  return _.invoke(hooksArr, 'toString')
}

altboilerScope = altboilerScope || {}
altboilerScope._boilerUtils = boilerUtils

Fix a small bug related to onLoadHooks


'use strict'

const fs = require('fs')
const { resolve } = require('url')
const escapeHTML = require('escape-html')

module.exports = createDustRenderer

function createDustRenderer () {
  const dust = require('dustjs-linkedin')
  dust.config.cache = false
  dust.helpers.component = component
  dust.onLoad = onLoad
  return function render (name, opts = {}) {
    return new Promise((resolve, reject) => {
      dust.render(name, opts, (err, content) => {
        if (err) return reject(err)
        resolve(content)
      })
    })
  }

  function component (chunk, context, bodies, params) {
    const props = params
    const name = props.name
    const tagName = props.tagName || 'div'
    delete props.name
    delete props.tagName
    chunk.write(
`<${tagName} \
data-component='${name}' \
data-props='${escapeHTML(JSON.stringify(props))}'></${tagName}>`
    )
  }

  function onLoad (templateName, opts, callback) {
    fs.readFile(templateName + '.html', 'utf8', (err, src) => {
      if (err) return callback(err)
      let compiled
      try {
        compiled = dust.compile(src, templateName)
      } catch (err) { return callback(err) }
      callback(null, dust.loadSource(compiled))
    })
  }
}

'use strict'

const fs = require('fs')
const escapeHTML = require('escape-html')

module.exports = createDustRenderer

function createDustRenderer () {
  const dust = require('dustjs-linkedin')
  dust.config.cache = false
  dust.helpers.component = component
  dust.onLoad = onLoad
  return function render (name, opts = {}) {
    return new Promise((resolve, reject) => {
      dust.render(name, opts, (err, content) => {
        if (err) return reject(err)
        resolve(content)
      })
    })
  }

  function component (chunk, context, bodies, params) {
    const props = params
    const name = props.name
    const tagName = props.tagName || 'div'
    delete props.name
    delete props.tagName
    chunk.write(
`<${tagName} \
data-component='${name}' \
data-props='${escapeHTML(JSON.stringify(props))}'>`
    )
    if (bodies.block) chunk.render(bodies.block, context)
    chunk.write(`</${tagName}>`)
  }

  function onLoad (templateName, opts, callback) {
    fs.readFile(templateName + '.html', 'utf8', (err, src) => {
      if (err) return callback(err)
      let compiled
      try {
        compiled = dust.compile(src, templateName)
      } catch (err) { return callback(err) }
      callback(null, dust.loadSource(compiled))
    })
  }
}

Fix dust driver to include innerHTML


phast.stylesLoading = 0;

var resourceLoader = new phast.ResourceLoader.make(phast.config.serviceUrl);

phast.forEachSelectedElement('style[data-phast-params]', function (style) {
    phast.stylesLoading++;
    retrieveFromBundler(style.getAttribute('data-phast-params'), function (css) {
        style.textContent = css;
        style.removeAttribute('data-phast-params');
    }, phast.once(function () {
        phast.stylesLoading--;
        if (phast.stylesLoading === 0 && phast.onStylesLoaded) {
            phast.onStylesLoaded();
        }
    }));
});

function retrieveFromBundler(textParams, done, always) {
    var params = phast.ResourceLoader.RequestParams.fromString(textParams);
    var request = resourceLoader.get(params);
    request.onsuccess = done;
    request.onend = always;
}

phast.stylesLoading = 0;

var resourceLoader = new phast.ResourceLoader.make(phast.config.serviceUrl);

phast.forEachSelectedElement('style[data-phast-params]', function (style) {
    phast.stylesLoading++;
    retrieveFromBundler(style.getAttribute('data-phast-params'), function (css) {
        style.textContent = css;
        style.removeAttribute('data-phast-params');
    }, phast.once(function () {
        phast.stylesLoading--;
        if (phast.stylesLoading === 0 && phast.onStylesLoaded) {
            phast.onStylesLoaded();
        }
    }));
});

function retrieveFromBundler(textParams, done, always) {
    var params = phast.ResourceLoader.RequestParams.fromString(textParams);
    resourceLoader.get(params)
        .then(done)
        .finally(always);
}

Make css loader work with promises


'use strict';

const baseUrl = 'http://www.spc.noaa.gov/climo/data/nglsr/data/rpts/';
const Promise = require('bluebird');
const request = Promise.promisifyAll(require('request'));
const co = require('co');

module.exports = function reportsRequest(date) {
    date = date.replace(/\d{2}(\d{2})-(\d{2})-(\d{2})/, '$1$2$3');

    return co(function* spcRequest() {
        let response = yield request.getAsync(`${baseUrl}${date}.log`);
        return Promise.resolve(response.body);
    }).catch(function errorHandler(err) {
        throw(err);
    });
};

'use strict';

const baseUrl = 'http://www.spc.noaa.gov/climo/data/nglsr/data/rpts/';
const Promise = require('bluebird');
const request = Promise.promisifyAll(require('request'));
const co = require('co');

module.exports = function reportsRequest(date) {
    date = date.replace(/\d{2}(\d{2})-(\d{2})-(\d{2})/, '$1$2$3');

    return co(function* spcRequest() {
        let response = yield request.getAsync(`${baseUrl}${date}.log`);
        return Promise.resolve(response);
    }).catch(function errorHandler(err) {
        throw(err);
    });
};

Return the response object, rather than body


var
  moment = require('moment'),
  sprintf = require('sprintf'),
  fsr = require('file-stream-rotator');

function create_logger (streamConfig) {

  streamConfig = streamConfig || {
      filename: './log/activity.log',
      frequency: 'daily',
      verbose: false
    };

  var stream = fsr.getStream(streamConfig);

  return function(msg) {
    stream.write(sprintf("%s %s\n", moment().toISOString(), msg));
  };
}

module.exports = create_logger;
module.exports.fileStreamRotator = fsr;

var
  moment = require('moment'),
  sprintf = require('sprintf'),
  fsr = require('file-stream-rotator');

function create_simple_config(name, frequency, verbosity) {
  var config = {}
  config.filename = name || './log/activity.log';
  config.frequency = frequency || 'daily';
  config.verbose = verbosity || false;
}

function create_logger (streamConfig) {

  if(!streamConfig) {
    streamConfig = create_simple_config();
  } else if(typeof streamConfig == 'string') {
    streamConfig = create_simple_config(streamConfig);
  }

  var stream = fsr.getStream(streamConfig);

  return function(msg) {
    stream.write(sprintf("%s %s\n", moment().toISOString(), msg));
  };
}

module.exports = create_logger;
module.exports.fileStreamRotator = fsr;

Make sure we can easily create new daily logs


import Ember from 'ember';
import preloadDataMixin from '../mixins/preload_data';

export default Ember.Route.extend(preloadDataMixin, {
  cordova: Ember.inject.service(),

  beforeModel() {
    Ember.run(() => this.controllerFor('application').send('logMeIn'));
    return this.preloadData().catch(error => {
      if (error.status === 0) {
        this.transitionTo("offline");
      } else {
        throw error;
      }
    }).finally(() => this.get("cordova").appLoad());
  },

  afterModel() {

    if (this.get("session.isAdminApp")) {
      this.loadStaticData().catch(error => {
        if (error.status === 0) {
          this.transitionTo("offline");
        } else {
          throw error;
        }
      });
    }

    // After everthying has been loaded, redirect user to requested url
    var attemptedTransition = this.controllerFor('login').get('attemptedTransition');
    if (attemptedTransition) {
      attemptedTransition.retry();
      this.set('attemptedTransition', null);
    } else {
      var currentUser = this.get('session.currentUser');
      if (this.get('session.isAdminApp')) {
        var myOffers = this.store.peekAll('offer').filterBy('reviewedBy.id', currentUser.get('id'));
        if (myOffers.get('length') > 0) {
          this.transitionTo('my_list');
        } else {
          this.transitionTo('offers');
        }
      } else {
        this.transitionTo('/offers');
      }
    }
  }

});

import Ember from 'ember';
import preloadDataMixin from '../mixins/preload_data';

export default Ember.Route.extend(preloadDataMixin, {
  cordova: Ember.inject.service(),

  beforeModel() {
    Ember.run(() => this.controllerFor('application').send('logMeIn'));
    return this.preloadData().catch(error => {
      if (error.status === 0) {
        this.transitionTo("offline");
      } else {
        throw error;
      }
    }).finally(() => this.get("cordova").appLoad());
  },

  afterModel() {

    if (this.get("session.isAdminApp")) {
      this.loadStaticData().catch(error => {
        if (error.status === 0) {
          this.transitionTo("offline");
        } else {
          throw error;
        }
      });
    }

    // After everthying has been loaded, redirect user to requested url
    var attemptedTransition = this.controllerFor('login').get('attemptedTransition');
    if (attemptedTransition) {
      attemptedTransition.retry();
      this.set('attemptedTransition', null);
    } else {
      var currentUser = this.get('session.currentUser');
      if (this.get('session.isAdminApp')) {
        this.transitionTo('dashboard');
      } else {
        this.transitionTo('/offers');
      }
    }
  }

});

Revert "Revert "GCW- 2473- Replace Admin Offers UI with Dashboard and Search Filters""


// window.checkAdLoad = function(){
//   var checkAdLoadfunction = function(){
//     var msg = "Ad unit is not present";
//     if($("._teraAdContainer")){
//       console.log("Ad unit is present")
//       msg = "Ad unit is present";
//     }
//     return msg;
//   }
//   checkAdLoadfunction()
//   console.log(checkAdLoadfunction);
//   var validateAd = new CustomEvent("trackAdLoad", { "detail": checkAdLoadfunction});
//   window.dispatchEvent(validateAd);
// }

t$(document).ready(function(){
  console.log("Checking the AdInstances.");
  var checkAdLoadfunction = function(){
    if(t$("._teraAdContainer")){
      console.log("Ad unit is present");
      t$('._teraAdContainer').mouseover(function(){
        t$(this).focus();
        console.log('Hoverred mouseover tera ad unit')
      });
    }
  }
  checkAdLoadfunction();
});

// window.checkAdLoad = function(){
//   var checkAdLoadfunction = function(){
//     var msg = "Ad unit is not present";
//     if($("._teraAdContainer")){
//       console.log("Ad unit is present")
//       msg = "Ad unit is present";
//     }
//     return msg;
//   }
//   checkAdLoadfunction()
//   console.log(checkAdLoadfunction);
//   var validateAd = new CustomEvent("trackAdLoad", { "detail": checkAdLoadfunction});
//   window.dispatchEvent(validateAd);
// }

t$(document).ready(function(){
  console.log("Checking the AdInstances.");
  var checkAdLoadfunction = function(){
    if(t$("._abmMainAdContainer")){
      console.log("Ad unit is present");
      t$('._teraAdContainer').mouseover(function(){
        t$(this).find('._abmAdContainer').text("Mouse over tera ad unit")
        console.log('Hoverred mouse over tera ad unit')
      });
    }
  }
  checkAdLoadfunction();
});

Add changes to the js file


import AsyncQueue from '../utils/asyncQueueStructures';

let asyncQueue = new AsyncQueue();

const endAsync = () => ({ type: 'ASYNC_INACTIVE' });

const startAsync = () => ({ type: 'ASYNC_ACTIVE' });

const callAsync = (dispatchFn, newState) => (dispatch, getState) => {
  if (!asyncQueue.size) {
    asyncQueue.listenForEnd(dispatch.bind(null, endAsync()));
  }
  asyncQueue.add(dispatchFn, getState().async.delay, newState);
  dispatch(startAsync());
};

const setDelay = (newDelay) => {
  return {
    type: 'SET_DELAY',
    newDelay
  };
};

export default {
  callAsync,
  endAsync,
  setDelay,
  startAsync
};

import AsyncQueue from '../utils/asyncQueueStructures';

let asyncQueue = new AsyncQueue();

const endAsync = () => ({ type: 'ASYNC_INACTIVE' });

const startAsync = () => ({ type: 'ASYNC_ACTIVE' });

const callAsync = (dispatchFn, ...args) => (dispatch, getState) => {
  if (!asyncQueue.size) {
    asyncQueue.listenForEnd(dispatch.bind(null, endAsync()));
  }
  asyncQueue.add(dispatchFn, getState().async.delay, ...args);
  dispatch(startAsync());
};

const setDelay = (newDelay) => {
  return {
    type: 'SET_DELAY',
    newDelay
  };
};

export default {
  callAsync,
  endAsync,
  setDelay,
  startAsync
};

Allow multiple arguments for async actions


Error.stackTraceLimit = 100

try { require('source-map-support-2/register') } catch (_) {}

// Async stacks.
try { require('trace') } catch (_) {}

// Removes node_modules and internal modules.
try {
  var sep = require('path').sep
  var path = __dirname + sep + 'node_modules' + sep

  require('stack-chain').filter.attach(function (_, frames) {
    var filtered = frames.filter(function (frame) {
      var name = frame && frame.getFileName()

      return (
        // has a filename
        name &&

        // contains a separator (no internal modules)
        name.indexOf(sep) !== -1 &&

        // does not start with the current path followed by node_modules.
        name.lastIndexOf(path, 0) !== 0
      )
    })

    // depd (used amongst other by express requires at least 3 frames
    // in the stack.
    return filtered.length > 2
      ? filtered
      : frames
  })
} catch (_) {}

Augment stack traces limit to 100.


/**
 * Copyright (c) 2015-present, Joshua Hollenbeck
 * All rights reserved.
 *
 * This source code is licensed under the BSD-style license found in the
 * LICENSE file in the root directory of this source tree.
 */
const RefraxResourceBase = require('RefraxResourceBase');
const RefraxSchemaNodeAccessor = require('RefraxSchemaNodeAccessor');
const RefraxConstants = require('RefraxConstants');
const invokeDescriptor = require('invokeDescriptor');
const ACTION_CREATE = RefraxConstants.action.create;
const ACTION_UPDATE = RefraxConstants.action.update;
const ACTION_DELETE = RefraxConstants.action.delete;

/**
 * RefraxMutableResource is a public facing interface class to querying a Schema Node.
 */
class RefraxMutableResource extends RefraxResourceBase {
  static from(accessor, ...args) {
    return new RefraxMutableResource(accessor, ...args);
  }

  constructor(accessor, ...args) {
    if (!(accessor instanceof RefraxSchemaNodeAccessor)) {
      throw new TypeError(
        'RefraxMutableResource - Expected accessor of type RefraxSchemaNodeAccessor ' +
        'but found `' + typeof(accessor) + '`'
      );
    }

    super(accessor, ...args);
  }

  create(data) {
    return invokeDescriptor(this._generateDescriptor(ACTION_CREATE, data));
  }

  destroy(data) {
    return invokeDescriptor(this._generateDescriptor(ACTION_DELETE, data));
  }

  update(data) {
    return invokeDescriptor(this._generateDescriptor(ACTION_UPDATE, data));
  }
}

export default RefraxMutableResource;

/**
 * Copyright (c) 2015-present, Joshua Hollenbeck
 * All rights reserved.
 *
 * This source code is licensed under the BSD-style license found in the
 * LICENSE file in the root directory of this source tree.
 */
const RefraxResourceBase = require('RefraxResourceBase');
const RefraxSchemaNodeAccessor = require('RefraxSchemaNodeAccessor');
const RefraxConstants = require('RefraxConstants');
const invokeDescriptor = require('invokeDescriptor');
const ACTION_CREATE = RefraxConstants.action.create;
const ACTION_UPDATE = RefraxConstants.action.update;
const ACTION_DELETE = RefraxConstants.action.delete;

/**
 * RefraxMutableResource is a public facing interface class to querying a Schema Node.
 */
class RefraxMutableResource extends RefraxResourceBase {
  static from(accessor, ...args) {
    return new RefraxMutableResource(accessor, ...args);
  }

  constructor(accessor, ...args) {
    if (!(accessor instanceof RefraxSchemaNodeAccessor)) {
      throw new TypeError(
        'RefraxMutableResource - Expected accessor of type RefraxSchemaNodeAccessor ' +
        'but found `' + typeof(accessor) + '`'
      );
    }

    super(accessor, ...args);
  }

  create(...data) {
    return invokeDescriptor(this._generateDescriptor(ACTION_CREATE, data));
  }

  destroy(...data) {
    return invokeDescriptor(this._generateDescriptor(ACTION_DELETE, data));
  }

  update(...data) {
    return invokeDescriptor(this._generateDescriptor(ACTION_UPDATE, data));
  }
}

export default RefraxMutableResource;

Update mutable methods for arguments passing


"use strict";

/**
 *  to_tree(source[, root = null]) -> array
 *  - source (array): array of sections
 *  - root (mongodb.BSONPure.ObjectID|String): id of common root for result first level.
 *
 *  Build sections tree (nested) from flat sorted array.
 **/
module.exports = function (source, root) {
  var result = [];
  var nodes = {};

  source.forEach(function (node) {
    node.child_list = [];
    nodes[node._id.toString()] = node;
  });

  root = !!root ? root.toString() : null;

  // set children links for all nodes
  // and collect root children to result array
  source.forEach(function (node) {
    node.parent = !!node.parent ? node.parent.toString() : null;

    if (node.parent === root) {
      result.push(node);
    }
    else {
      if (node.parent !== null) {
        nodes[node.parent].child_list.push(node);
      }
    }
  });

  return result;
};

"use strict";

/**
 *  to_tree(source[, root = null]) -> array
 *  - source (array): array of sections
 *  - root (mongodb.BSONPure.ObjectID|String): id of common root for result first level.
 *
 *  Build sections tree (nested) from flat sorted array.
 **/
module.exports = function (source, root) {
  var result = [];
  var nodes = {};

  source.forEach(function (node) {
    node.child_list = [];
    nodes[node._id.toString()] = node;
  });

  root = !!root ? root.toString() : null;

  // set children links for all nodes
  // and collect root children to result array
  source.forEach(function (node) {
    node.parent = !!node.parent ? node.parent.toString() : null;

    if (node.parent === root) {
      result.push(node);

    } else if (node.parent !== null) {
      // Add child node if parent node actually exists.
      // It may not if we deal with nested forum sections where visible
      // section is a descendant of invisible section.
      if (nodes[node.parent]) {
        nodes[node.parent].child_list.push(node);
      }
    }
  });

  return result;
};

Fix fatal error when visible section is a descendant of invisible one.


import Vue from 'vue';
import Vuetify from 'vuetify';

Vue.use(Vuetify);

const csrf = global.document.createElement('input');
csrf.name = 'csrfmiddlewaretoken';
csrf.value = 'csrfmiddlewaretoken';
global.document.body.append(csrf);
global.document.body.setAttribute('data-app', true);
global.window.Urls = new Proxy(
  {},
  {
    get(obj, prop) {
      return () => prop;
    },
  }
);

import Vue from 'vue';
import Vuetify from 'vuetify';
import icons from 'shared/vuetify/icons';

Vue.use(Vuetify, {
  icons: icons(),
});

const csrf = global.document.createElement('input');
csrf.name = 'csrfmiddlewaretoken';
csrf.value = 'csrfmiddlewaretoken';
global.document.body.append(csrf);
global.document.body.setAttribute('data-app', true);
global.window.Urls = new Proxy(
  {},
  {
    get(obj, prop) {
      return () => prop;
    },
  }
);

Fix missing globally registered <Icon> in tests


module.exports = {
  name: 'Unit test',
  testMatch: ['**/packages/**/__tests__/?(*.)+(spec|test).js'],
  transform: {},
};

module.exports = {
  name: 'Unit test',
  testMatch: ['<rootDir>/packages/**/__tests__/?(*.)+(spec|test).js'],
  modulePathIgnorePatterns: ['.cache'],
  transform: {},
};

Fix jest hast map issue with .cache folder in examples


'use strict';

// Service for the spec config.
// We keep this separate so that changes are kept even if the spec changes.
angular.module('vlui')
  .factory('Config', function() {
    var Config = {};

    Config.data = {};
    Config.config = {};

    Config.getConfig = function() {
      return {};
    };

    Config.getData = function() {
      return Config.data;
    };

    Config.large = function() {
      return {
        cell: {
          width: 300,
          height: 300
        },
        facet: {
          cell: {
            width: 150,
            height: 150
          }
        },
        scale: {useRawDomain: false},
        mark: {
          tickThickness: 2
        }
      };
    };

    Config.small = function() {
      return {
        facet: {
          cell: {
            width: 150,
            height: 150
          }
        },
        mark: {
          tickThickness: 2
        }
      };
    };

    Config.updateDataset = function(dataset, type) {
      if (dataset.values) {
        Config.data.values = dataset.values;
        delete Config.data.url;
        Config.data.formatType = undefined;
      } else {
        Config.data.url = dataset.url;
        delete Config.data.values;
        Config.data.formatType = type;
      }
    };

    return Config;
  });

'use strict';

// Service for the spec config.
// We keep this separate so that changes are kept even if the spec changes.
angular.module('vlui')
  .factory('Config', function() {
    var Config = {};

    Config.data = {};
    Config.config = {};

    Config.getConfig = function() {
      return {};
    };

    Config.getData = function() {
      return Config.data;
    };

    Config.large = function() {
      return {
        cell: {
          width: 300,
          height: 300
        },
        facet: {
          cell: {
            width: 150,
            height: 150
          }
        },
        scale: {useRawDomain: false}
      };
    };

    Config.small = function() {
      return {
        facet: {
          cell: {
            width: 150,
            height: 150
          }
        }
      };
    };

    Config.updateDataset = function(dataset, type) {
      if (dataset.values) {
        Config.data.values = dataset.values;
        delete Config.data.url;
        Config.data.formatType = undefined;
      } else {
        Config.data.url = dataset.url;
        delete Config.data.values;
        Config.data.formatType = type;
      }
    };

    return Config;
  });

Revert "Make tick thicker to facilitate hovering"


Gittip.upgrade = {};

Gittip.upgrade.init = function () {

    var userAgent = navigator.userAgent.toLowerCase();
    var browser = (userAgent.indexOf('msie') != -1) ? parseInt(userAgent.split('msie')[1]) : -1;

    if(browser != -1 && browser < 9) {
        var message = '' +
            '
' +
            '
' +
            'This browser isn\'t supported by GitTip.com. ' +
            'We encourage You to upgrade or change browser. ' +
            'Learn more' +
            '
' +
            '
';
        $("body").prepend(message);
    }
};

$(document).ready(Gittip.upgrade.init);

Gittip.upgrade = {};

Gittip.upgrade.init = function () {

    var userAgent = navigator.userAgent.toLowerCase();
    var browser = (userAgent.indexOf('msie') != -1) ? parseInt(userAgent.split('msie')[1], 10) : -1;

    if(browser != -1 && browser < 9) {
        var message = '' +
            '
' +
            '
' +
            'This browser isn\'t supported by GitTip.com. ' +
            'We encourage You to upgrade or change browser. ' +
            'Learn more' +
            '
' +
            '
';
        $("body").prepend(message);
    }
};

$(document).ready(Gittip.upgrade.init);

Add radix to a parseInt()


// https://developer.mozilla.org/en-US/docs/Web/API/Document/cookie

console.log('Any cookies yet? ' + document.cookie);

console.log('Setting a cookie...');

document.cookie = 'something=somethingelse';

console.log('OK set one: ' + document.cookie);

// https://developer.mozilla.org/en-US/docs/Web/API/Document/cookie

$(document).on('ready', function() {

  allCookies = document.cookie;

  if (allCookies === '') {
    $('hi').append('Welcome for the first time!');
    document.cookie = 'something=somethingelse';
  } else {
    $('hi').append('Welcome back!');
  }

})

Change messaging based on cookie


$(function() {
    $.get("includes/header.html", function(data) {
        $('body').prepend(data);
    });
    $("#footer").load("includes/footer.html");
})

$(function() {
    $.get("includes/header.html", function(data) {
        $('body').prepend(data);
        $('.dropdown-item[href="' + window.location.pathname.split('/').pop() + '"]').addClass('active');
    });
    $("#footer").load("includes/footer.html");

})

Add active class to current page in drop down


/* eslint-disable no-param-reassign */

import Vue from 'vue';

export default {
    namespaced: true,

    state: {
        username: null,
    },

    mutations: {
        setUsername(state, username) {
            state.username = username;
        },
    },

    actions: {

        status({ commit }) {
            return Vue.http.get('api/session').then(
                (response) => {
                    commit('setUsername', (response.body && response.body.username) ? response.body.username : null);

                    return response.status;
                },
                (response) => {
                    commit('setUsername', null);

                    return response.status;
                },
            );
        },

        login({ commit }, { username, password }) {
            return Vue.http.post('api/session', { username, password }).then(
                (response) => {
                    commit('setUsername', response.username);

                    return true;
                },
                () => false,
            );
        },

        logout({ commit }) {
            return Vue.http.delete('api/session').then(
                () => {
                    commit('setUsername', null);

                    return true;
                },
                () => false,
            );
        },
    },
};

/* eslint-disable no-param-reassign */

import Vue from 'vue';

export default {
    namespaced: true,

    state: {
        username: null,
    },

    mutations: {
        setUsername(state, username) {
            state.username = username;
        },
    },

    actions: {

        status({ commit }) {
            return Vue.http.get('api/session').then(
                (response) => {
                    commit('setUsername', (response.body && response.body.username) ? response.body.username : null);

                    return response.status;
                },
                (response) => {
                    commit('setUsername', null);

                    return response.status;
                },
            );
        },

        login({ commit }, { username, password }) {
            return Vue.http.post('api/session', { username, password }).then(
                (response) => {
                    commit('setUsername', response.body.username);

                    return true;
                },
                () => false,
            );
        },

        logout({ commit }) {
            return Vue.http.delete('api/session').then(
                () => {
                    commit('setUsername', null);

                    return true;
                },
                () => false,
            );
        },
    },
};

Fix missing username in initial login session


require.config({
    paths: {
        "knockout": "ext/knockout-2.1.0",
        "jquery": "ext/jquery-1.7.2.min",
        "text": "ext/text",
        "codemirror": "ext/CodeMirror",
        "bootstrap": "ext/bootstrap.min"
    },
    shim: {
        "bootstrap": ["jquery"]
    }
});

require(["knockout", "app", "jquery", "bootstrap", "utilities", "stringTemplateEngine", "text", "codemirror"], function(ko, App, $) {
    var vm = new App();

    //simple client-side routing - update hash when current section is changed
    vm.currentSection.subscribe(function(newValue) {
        location.hash = newValue.name;
    });

    var updateSection = function() {
        vm.updateSection(location.hash.substr(1));
    };

    //respond to hashchange event
    window.onhashchange = updateSection;

    //initialize
    updateSection();

    //block alt navigation
    $(document).keydown(function(event) {
        if (event.altKey && (event.keyCode === 37 || event.keyCode === 38 || event.keyCode === 39 || event.keyCode === 40)) {
            return false;
        }
    });

    window.alert = function(text) {
      $("#alert .modal-body").html("<p>" + text + "</p>").parent().modal();
    };

    ko.applyBindings(vm);
});

require.config({
    paths: {
        "knockout": "ext/knockout-2.1.0",
        "jquery": "ext/jquery-1.7.2.min",
        "text": "ext/text",
        "codemirror": "ext/codemirror",
        "bootstrap": "ext/bootstrap.min"
    },
    shim: {
        "bootstrap": ["jquery"]
    }
});

require(["knockout", "app", "jquery", "bootstrap", "utilities", "stringTemplateEngine", "text", "codemirror"], function(ko, App, $) {
    var vm = new App();

    //simple client-side routing - update hash when current section is changed
    vm.currentSection.subscribe(function(newValue) {
        location.hash = newValue.name;
    });

    var updateSection = function() {
        vm.updateSection(location.hash.substr(1));
    };

    //respond to hashchange event
    window.onhashchange = updateSection;

    //initialize
    updateSection();

    //block alt navigation
    $(document).keydown(function(event) {
        if (event.altKey && (event.keyCode === 37 || event.keyCode === 38 || event.keyCode === 39 || event.keyCode === 40)) {
            return false;
        }
    });

    window.alert = function(text) {
      $("#alert .modal-body").html("<p>" + text + "</p>").parent().modal();
    };

    ko.applyBindings(vm);
});

Update case on CodeMirror require in case web server is case sensitive (like gh-pages)


'use strict';

let express = require('express');

let router = require('./router.js');
let createDatabaseManager = require('./models/dbManager.js');
let ClientError = require('./errors.js').ClientError;

const dbUrl = 'mongodb://localhost:27017/athenicpaste';

function logErrors(err, request, response, next) {
  console.error(err.stack);
  next();
}

function handleClientError(err, request, response, next) {
  if (err instanceof ClientError) {
    response.status(err.statusCode).send(err.message);
  } else {
    next();
  }
}

function createApplication() {
  return createDatabaseManager(dbUrl).then(function(dbManager) {
    let app = express();

    app.use(function(request, response, next) {
      request.db = dbManager;
      next();
    });

    app.use(router);

    app.use(logErrors);
    app.use(handleClientError);
    return app;
  });
}

exports.createApplication = createApplication;

'use strict';

let express = require('express');

let router = require('./router.js');
let createDatabaseManager = require('./models/dbManager.js');
let ClientError = require('./errors.js').ClientError;

const dbUrl = 'mongodb://localhost:27017/athenicpaste';

function createApplication() {
  return createDatabaseManager(dbUrl).then(function(dbManager) {
    let app = express();

    app.use(function(request, response, next) {
      request.db = dbManager;
      next();
    });

    app.use(router);

    app.use(function logErrors(err, request, response, next) {
      console.error(err.stack);
      next(err);
    });
    app.use(function handleClientError(err, request, response, next) {
      if (err instanceof ClientError) {
        response.status(err.statusCode).send(err.message);
      } else {
        next(err);
      }
    });
    return app;
  });
}

exports.createApplication = createApplication;

Fix error propagation in middleware


/**
 * Module dependencies.
 */

var Base = require('./base')
  , cursor = Base.cursor
  , color = Base.color;

/**
 * Expose `TAP`.
 */

exports = module.exports = TAP;

/**
 * Initialize a new `TAP` reporter.
 *
 * @param {Runner} runner
 * @api public
 */

function TAP(runner) {
  Base.call(this, runner);

  var self = this
    , stats = this.stats
    , total = runner.total
    , n = 1;

  runner.on('start', function(){
    console.log('%d..%d', 1, total);
  });

  runner.on('test end', function(){
    ++n;
  });

  runner.on('pass', function(test){
    console.log('ok %d %s', n, test.fullTitle());
  });

  runner.on('fail', function(test, err){
    console.log('not ok %d %s', n, test.fullTitle());
    console.log(err.stack.replace(/^/gm, '  '));
  });
}

/**
 * Module dependencies.
 */

var Base = require('./base')
  , cursor = Base.cursor
  , color = Base.color;

/**
 * Expose `TAP`.
 */

exports = module.exports = TAP;

/**
 * Initialize a new `TAP` reporter.
 *
 * @param {Runner} runner
 * @api public
 */

function TAP(runner) {
  Base.call(this, runner);

  var self = this
    , stats = this.stats
    , total = runner.total
    , n = 1;

  runner.on('start', function(){
    console.log('%d..%d', 1, total);
  });

  runner.on('test end', function(){
    ++n;
  });

  runner.on('pass', function(test){
    console.log('ok %d %s', n, title(test));
  });

  runner.on('fail', function(test, err){
    console.log('not ok %d %s', n, title(test));
    console.log(err.stack.replace(/^/gm, '  '));
  });
}

/**
 * Return a TAP-safe title of `test`
 *
 * @param {Object} test
 * @return {String}
 * @api private
 */

function title(test) {
  return test.fullTitle().replace(/#/g, '');
}

Remove hasmark from TAP titles.


module.exports = function (karma) {
  let configuration = {
    basePath: '.',
    frameworks: ['mocha'],
    files: [
      { pattern: 'node_modules/chai/chai.js', include: true },
      'src/*.js',
      'spec/*.js'
    ],
    reporters: ['spec'],
    browsers: ['Chrome'],
    singleRun: true,
    client: {
      mocha: {
        reporter: 'html'
      }
    }
  };
  if (karma.tdd) {
    configuration = Object.assign(configuration, {
      browsers: ['Chrome'],
      reporters: ['dots'],
      singleRun: false,
      autoWatch: true
    });
  }
  karma.set(configuration);
}

module.exports = function (karma) {
  let configuration = {
    basePath: '.',
    frameworks: ['mocha'],
    files: [
      { pattern: 'node_modules/chai/chai.js', include: true },
      'src/*.js',
      'spec/*.js'
    ],
    reporters: ['spec'],
    browsers: ['ChromeHeadless'],
    singleRun: true,
    client: {
      mocha: {
        reporter: 'html'
      }
    }
  };
  if (karma.tdd) {
    configuration = Object.assign(configuration, {
      browsers: ['Chrome'],
      reporters: ['dots'],
      singleRun: false,
      autoWatch: true
    });
  }
  karma.set(configuration);
}

Use headless Chrome in non-tdd mode


'use strict';

module.exports =
{
	base_name		: 'sms',
	action_name		: 'sms/{id}',

	send: function() {
		return this.action(...arguments);
	},

	getResponses: function(/* dynamic */) {
		var params = this.parseBaseParams(arguments);
		return this.quiubas.network.get( [ this.action_name + '/responses', { 'id': params.id } ], params.params, params.success, params.error );
	},
};

'use strict';

module.exports =
{
	base_name		: 'sms',
	action_name		: 'sms/{id}',

	send: function() {
		return this.action.apply(this, arguments);
	},

	getResponses: function(/* dynamic */) {
		var params = this.parseBaseParams(arguments);
		return this.quiubas.network.get( [ this.action_name + '/responses', { 'id': params.id } ], params.params, params.success, params.error );
	},
};

Add Node <5 support by removing spread operator


function min(a, b) {
    return a < b ? a : b;
}

console.log(min(0, 10));
console.log(min(0, -10));

Add chapter 3, exercise 1


var background= __dirname+'/../background';
var map= {
  localhost: background
 ,'127.0.0.1': background
}

exports= module.exports= {
  lookup: function() {
      return map[this.host.name]
    }
  ,paths: [background]
}

var background= __dirname+'/../background';
var sample= __dirname+'/../sample.com';
var map= {
  localhost: background
 ,'127.0.0.1': background
 ,'sample.com': sample
}

exports= module.exports= {
  lookup: function() {
      return map[this.host.name]
    }
  ,paths: [background,sample]
}

Add sample.com site. Rerouting allows testing site routing, so here's a site.


import React, { Component } from 'react';
import { Route, Switch } from 'react-router-dom';
import Receipt from './Receipt';
import ReceiptsList from './ReceiptsList';
import './App.css';
import 'bootstrap/dist/css/bootstrap.min.css';

class App extends Component {

  render() {
    return (
      <div className="app container">
        <Switch>
          <Route path='/' component={ReceiptsList} />
          <Route path='/receipt/:year/:month' component={Receipt} />
        </Switch>
      </div>
    );
  }
}

export default App;

import React, { Component } from 'react';
import { Route, Switch } from 'react-router-dom';
import Receipt from './Receipt';
import ReceiptsList from './ReceiptsList';
import './App.css';
import 'bootstrap/dist/css/bootstrap.min.css';

class App extends Component {

  render() {
    return (
      <div className="app container">
        <Switch>
          <Route path='/' exact component={ReceiptsList} />
          <Route path='/receipt/:year/:month' component={Receipt} />
        </Switch>
      </div>
    );
  }
}

export default App;

Fix an issue with matching route


const RateLimit = require('express-rate-limit');
const RedisStore = require('rate-limit-redis');
const logger = require('../../logger').policy;

module.exports = (params) => {
  if (params.rateLimitBy) {
    params.keyGenerator = (req) => {
      try {
        return req.egContext.evaluateAsTemplateString(params.rateLimitBy);
      } catch (err) {
        logger.error('Failed to generate rate-limit key with config: %s; %s', params.rateLimitBy, err.message);
      }
    };
  }
  return new RateLimit(Object.assign(params, {
    store: new RedisStore({
      client: require('../../db')
    })
  }));
};

const RateLimit = require('express-rate-limit');
const RedisStore = require('rate-limit-redis');
const logger = require('../../logger').policy;

module.exports = (params) => {
  if (params.rateLimitBy) {
    params.keyGenerator = (req) => {
      try {
        return req.egContext.evaluateAsTemplateString(params.rateLimitBy);
      } catch (err) {
        logger.error('Failed to generate rate-limit key with config: %s; %s', params.rateLimitBy, err.message);
      }
    };
  }
  return new RateLimit(Object.assign(params, {
    store: new RedisStore({
      client: require('../../db'),
      expiry: params.windowMs / 1000
    })
  }));
};

Update rate limit policy to set redis expiry inline with windowMs


const xRegExp = require('xregexp');

/**
 * Wrapper for xRegExp to work around
 * https://github.com/slevithan/xregexp/issues/130
 */
module.exports = (regexp, flags) => {
  if (!flags || !flags.includes('x')) {
    // We aren't using the 'x' flag, so we don't need to remove comments and
    // whitespace as a workaround for
    // https://github.com/slevithan/xregexp/issues/130
    return xRegExp(regexp, flags);
  }

  const lines = regexp.split('\n');
  return xRegExp(
    lines.map((line) => line.replace(/\s+#.+/, ' ')).join('\n'),
    flags
  );
};

const originalXRegExp = require('xregexp');

/**
 * Wrapper for xRegExp to work around
 * https://github.com/slevithan/xregexp/issues/130
 */
function xRegExp(regexp, flags) {
  if (!flags || !flags.includes('x')) {
    // We aren't using the 'x' flag, so we don't need to remove comments and
    // whitespace as a workaround for
    // https://github.com/slevithan/xregexp/issues/130
    return originalXRegExp(regexp, flags);
  }

  const lines = regexp.split('\n');
  return originalXRegExp(
    lines.map((line) => line.replace(/\s+#.+/, ' ')).join('\n'),
    flags
  );
}

xRegExp.exec = originalXRegExp.exec;

module.exports = xRegExp;

Add exec() to xRegExp wrapper


import Joi from 'joi';
import jsonServerConfig from 'config/server.json';
import schema from './schema.js';

class ServerConfig {
  constructor() {
    this._jsonConfig = jsonServerConfig;

    /**
     * Validate the JSON config
     */
    try {
      Joi.validate(this._jsonConfig, schema);
    } catch (e) {
      console.error('The config in \'config/server.json\' is not a valid config configuration. Error: ', e);
    }
  }

  get (value) {
    return this._jsonConfig[value];
  }
}

export default new ServerConfig();

import Joi from 'joi';
import jsonServerConfig from 'config/server.json';
import schema from './schema.js';

class ServerConfig {
  constructor() {
    /**
     * Validate the JSON config
     */
    try {
      this._jsonConfig = Joi.validate(jsonServerConfig, schema).value;
    } catch (e) {
      console.error('The config in \'config/server.json\' is not a valid config configuration. Error: ', e);
    }
  }

  get (value) {
    return this._jsonConfig[value];
  }
}

export default new ServerConfig();

Update logger and add config


var fs = require('fs');

module.exports = function(opts) {
  this.options = opts;

  if (!opts.handlebars) this.options.handlebars = require('handlebars');

  if (opts.template) {
    var fileData = fs.readFileSync(this.options.template);
    this.template = this.options.handlebars.compile(fileData.toString(), {noEscape: true});
  }

  return this;
}

var fs = require('fs');

module.exports = function(opts) {
  var fileData;
  this.options = opts;

  if (!opts.handlebars) this.options.handlebars = require('handlebars');

  if (opts.template) {
    try {
      fileData = fs.readFileSync(this.options.template);
    }
    catch (e) {
      throw new Error('Error loading Supercollider template file: ' + e.message);
    }

    this.template = this.options.handlebars.compile(fileData.toString(), {noEscape: true});
  }
  else {
    throw new Error('No path to a template was set in Supercollider.config().');
  }

  return this;
}

Throw errors if a template is not set, or if a template can't be loaded


import Ember from 'ember';

export default Ember.Route.extend({
    setupController: function() {
        this.controllerFor( 'pagination' ).get( 'translateService' ).setDictionary( Ember.Object.create({
           'PAGINATION_DISPLAYING'           : 'Displaying',
           'DEVICE_LIST_PAGINATION_LABEL'    : 'Viewing {0} to {1} of {2} Devices',
           'DEVICE_LIST_PAGINATION_PER_PAGE' : ' per page',
           'HOSTNAME': 'Hostname',
           'IPADDRESS': 'Ip Address',
           'DEVICETYPE': 'DeviceType',
           'PROVISIONDATE': 'Provision Date',
           'ACTIONS': 'Actions',
           'COLUMNS': 'Columns',
           'RESETCOLUMNS':'Reset Columns',
           'TESTACTION': 'Test Action',
           'UNKNOWNDEVICE': '--Unknown Device--',
           'NOTES': 'Notes'
        }));
    }
});

import Ember from 'ember';

export default Ember.Route.extend({
    setupController: function() {
        this.controllerFor( 'pagination' ).get( 'translateService' ).setDictionary( Ember.Object.create({
           'PAGINATION_DISPLAYING'           : 'Displaying',
           'DEVICE_LIST_PAGINATION_LABEL'    : 'Viewing {0} to {1} of {2} Devices',
           'DEVICE_LIST_PAGINATION_PER_PAGE' : ' per page',
           'HOSTNAME': 'Hostname',
           'IPADDRESS': 'IP Address',
           'DEVICETYPE': 'Device Type',
           'PROVISIONDATE': 'Provision Date',
           'ACTIONS': 'Actions',
           'COLUMNS': 'Columns',
           'RESETCOLUMNS':'Reset Columns',
           'TESTACTION': 'Test Action',
           'UNKNOWNDEVICE': '--Unknown Device--',
           'NOTES': 'Notes'
        }));
    }
});

Tweak grid demo column header text


var h = require('html')
var Panel = require('panel')

function Editor() {
  this.layersPanel = new Panel(this, 215, h('.layers-panel'))
  this.inspectorPanel = new Panel(this, 215, h('.inspector-panel'))

  this.el = h('.editor', [
    this.layersPanel.el,
    h('.canvas'),
    this.inspectorPanel.el
  ])
}

Editor.prototype.start = function() {
  document.body.appendChild(this.el)
  return this
}

Editor.prototype.getData = function() {
  throw new Error("Unimplemented")
}

Editor.prototype.loadData = function() {
  throw new Error("Unimplemented")
}

exports = Editor

var h = require('html')
var Panel = require('panel')

function Editor() {
  this.layersPanel = new Panel(this, 215, h('.layers-panel'))
  this.inspectorPanel = new Panel(this, 215, h('.inspector-panel'))

  this.el = h('.editor', [
    this.layersPanel.el,
    h('.canvas'),
    this.inspectorPanel.el
  ])
}

Editor.prototype.start = function() {
  document.body.appendChild(this.el)
  return this
}

Editor.prototype.getData = function(type) {
  throw new Error("Unimplemented")
}

Editor.prototype.loadData = function(type, data) {
  throw new Error("Unimplemented")
}

exports = Editor

Add parameters to stub loading/saving methods


import React from 'react'

export const isRequired = (schema, fieldName) => {
    if (!schema.required) {
        return false
    }
    return (schema.required.indexOf(fieldName) != 1)
}

const renderField = (fieldSchema, fieldName, theme, prefix = '') => {
    const widget = fieldSchema.format || fieldSchema.type || 'object'
    if (!theme[widget]) {
        throw new Error('liform: ' + widget + ' is not defined in the theme')
    }

    return React.createElement(theme[widget], {
        key: fieldName,
        fieldName: prefix ? prefix + fieldName : fieldName,
        label: fieldSchema.showLabel === false ? '' : fieldSchema.title || fieldName,
        required: isRequired(fieldSchema, fieldName),
        schema: fieldSchema,
        theme: theme,
    })
}

export default renderField

import React from 'react'

export const isRequired = (schema, fieldName) => {
    if (!schema.required) {
        return false
    }
    return (schema.required.indexOf(fieldName) != 1)
}

const renderField = (fieldSchema, fieldName, theme, prefix = '') => {
    const widget = fieldSchema.widget || fieldSchema.type || 'object'
    if (!theme[widget]) {
        throw new Error('liform: ' + widget + ' is not defined in the theme')
    }

    return React.createElement(theme[widget], {
        key: fieldName,
        fieldName: prefix ? prefix + fieldName : fieldName,
        label: fieldSchema.showLabel === false ? '' : fieldSchema.title || fieldName,
        required: isRequired(fieldSchema, fieldName),
        schema: fieldSchema,
        theme: theme,
    })
}

export default renderField

Change format to widget to be more friendly with ajv


/* @flow */

import React from 'react'
import {TouchableOpacity, View, FlatList} from 'react-native'

export default class NodeView extends React.PureComponent {

  componentWillMount = () => {
    let rootChildren = this.props.getChildren(this.props.node)

    if (rootChildren) {
      rootChildren = rootChildren.map((child, index) => {
        return this.props.generateIds(rootChildren[index])
      })
    }

    this.setState({data: rootChildren})
  }

  onNodePressed = (node: any) => {
    const newState = rootChildren = this.state.data.map((child, index) => {
      return this.props.searchTree(this.state.data[index], node)
    })

    this.setState({data: newState})
    this.props.onNodePressed(node)
  }

  render() {
    const {getChildren, node, nodeStyle, onLayout, onNodePressed, renderNode, renderChildrenNode} = this.props
    const children = getChildren(node)

    return (
      <View onLayout={onLayout}>
        <TouchableOpacity onPress={() => onNodePressed(node)}>
          {renderNode()}
        </TouchableOpacity>
        {node.opened && this.state.data
          ? <FlatList
          data={this.state.data}
          renderItem={({item}) => renderChildrenNode(item)}
          keyExtractor={(item) => item.id}/> : null}
      </View>
    )
  }
}

/* @flow */

import React from 'react'
import {TouchableOpacity, View, FlatList} from 'react-native'

export default class NodeView extends React.PureComponent {

  componentWillMount = () => {
    let rootChildren = this.props.getChildren(this.props.node)

    if (rootChildren) {
      rootChildren = rootChildren.map((child, index) => {
        return this.props.generateIds(rootChildren[index])
      })
    }

    this.setState({data: rootChildren})
  }

  onNodePressed = (node: any) => {
    if (this.state.data) {
      const newState = rootChildren = this.state.data.map((child, index) => {
        return this.props.searchTree(this.state.data[index], node)
      })

      this.setState({data: newState})
    }

    this.props.onNodePressed(node)
  }

  render() {
    const {getChildren, node, nodeStyle, onLayout, onNodePressed, renderNode, renderChildrenNode} = this.props
    const children = getChildren(node)

    return (
      <View onLayout={onLayout}>
        <TouchableOpacity onPress={() => this.onNodePressed(node)}>
          {renderNode()}
        </TouchableOpacity>
        {node.opened && this.state.data
          ? <FlatList
          data={this.state.data}
          renderItem={({item}) => renderChildrenNode(item)}
          keyExtractor={(item) => item.id}/> : null}
      </View>
    )
  }
}

Fix issue in flat list


var express = require('express'),
	router = express.Router(),
	passport = require('passport');

module.exports = function (app) {
	app.use('/account', router);
};

router.get('/', function (req, res, next) {
	console.log('User: ', req);
	res.render('account', {
		title: 'Libbie: quickly add books to Goodreads!',
		userName: req.user.clientInfo.displayName,
		shelves: [
			{ name: 'Owned books', value: 'owned-books' },
		],
		conditions: [
			{ name: 'unspecified', value: 0 },
			{ name: 'brand new', value: 10 },
			{ name: 'like new', value: 20, default: true },
			{ name: 'very good', value: 30 },
			{ name: 'good', value: 40 },
			{ name: 'acceptable', value: 50 },
			{ name: 'poor', value: 60 },
		],
		helpers: {
			isSelected: function (input) {
				return typeof input !== 'undefined' && input === true ? 'selected' : '';
			}
		}
	});
});

var express = require('express'),
	router = express.Router(),
	passport = require('passport');

module.exports = function (app) {
	app.use('/account', router);
};

router.get('/', function (req, res, next) {
	console.log('User: ', req);
	res.render('account', {
		title: 'Libbie: quickly add books to Goodreads!',
		userName: req.user.displayName,
		shelves: [
			{ name: 'Owned books', value: 'owned-books' },
		],
		conditions: [
			{ name: 'unspecified', value: 0 },
			{ name: 'brand new', value: 10 },
			{ name: 'like new', value: 20, default: true },
			{ name: 'very good', value: 30 },
			{ name: 'good', value: 40 },
			{ name: 'acceptable', value: 50 },
			{ name: 'poor', value: 60 },
		],
		helpers: {
			isSelected: function (input) {
				return typeof input !== 'undefined' && input === true ? 'selected' : '';
			}
		}
	});
});

Fix due to removed clientInfo property


'use strict';

require.config({
    baseUrl: '../lib',
    paths: {
        'test': '..',
        'forge': 'forge.min',
        'stringencoding': 'stringencoding.min'
    },
    shim: {
        sinon: {
            exports: 'sinon',
        }
    }
});

// add function.bind polyfill
if (!Function.prototype.bind) {
    Function.prototype.bind = function(oThis) {
        if (typeof this !== "function") {
            // closest thing possible to the ECMAScript 5 internal IsCallable function
            throw new TypeError("Function.prototype.bind - what is trying to be bound is not callable");
        }

        var aArgs = Array.prototype.slice.call(arguments, 1),
            fToBind = this,
            FNOP = function() {},
            fBound = function() {
                return fToBind.apply(this instanceof FNOP && oThis ? this : oThis,
                    aArgs.concat(Array.prototype.slice.call(arguments)));
            };

        FNOP.prototype = this.prototype;
        fBound.prototype = new FNOP();

        return fBound;
    };
}

mocha.setup('bdd');
require(['../unit/smtpclient-test', '../unit/smtpclient-response-parser-test'], function() {
    (window.mochaPhantomJS || window.mocha).run();
});

'use strict';

require.config({
    baseUrl: '../lib',
    paths: {
        'test': '..',
        'forge': 'forge.min',
        'stringencoding': 'stringencoding.min'
    }
});

// add function.bind polyfill
if (!Function.prototype.bind) {
    Function.prototype.bind = function(oThis) {
        if (typeof this !== "function") {
            // closest thing possible to the ECMAScript 5 internal IsCallable function
            throw new TypeError("Function.prototype.bind - what is trying to be bound is not callable");
        }

        var aArgs = Array.prototype.slice.call(arguments, 1),
            fToBind = this,
            FNOP = function() {},
            fBound = function() {
                return fToBind.apply(this instanceof FNOP && oThis ? this : oThis,
                    aArgs.concat(Array.prototype.slice.call(arguments)));
            };

        FNOP.prototype = this.prototype;
        fBound.prototype = new FNOP();

        return fBound;
    };
}

mocha.setup('bdd');
require(['../unit/smtpclient-test', '../unit/smtpclient-response-parser-test'], function() {
    (window.mochaPhantomJS || window.mocha).run();
});

Remove useless sinon require shim


/*jslint eqeq: true, indent: 2, node: true, plusplus: true, regexp: true, unparam: true, vars: true, nomen: true */
'use strict';

var Schema = require('mongoose').Schema;

/**
 * The article schema.
 */
var PostSchema = new Schema({
  type: {type: Number, 'default': 0},
  authorId: String,
  catalogId: {type: String, ref: 'Catalog'},
  tags: [String],
  title: Number,
  content: String,
  date: {type: Date, 'default': Date.now}
});

var statics = PostSchema.statics;

statics.listLatestPosts = function (param, cb) {
  var q = this.find();
  if (param) {
    if (param.start) {
      q.skip(param.start);
    }
    if (param.limit) {
      q.limit(param.limit);
    }
  }
  q.sort({date: 'desc'});
  if (cb) {
    return q.exec(cb);
  } else {
    return q;
  }
};

module.exports = PostSchema;

/*jslint eqeq: true, indent: 2, node: true, plusplus: true, regexp: true, unparam: true, vars: true, nomen: true */
'use strict';

var Schema = require('mongoose').Schema;

/**
 * The article schema.
 */
var PostSchema = new Schema({
  type: {type: Number, 'default': 0},
  authorId: String,
  catalogId: {type: String, ref: 'Catalog'},
  tags: [String],
  title: String,
  content: String,
  date: {type: Date, 'default': Date.now}
});

var statics = PostSchema.statics;

statics.listLatestPosts = function (param, cb) {
  var q = this.find();
  if (param) {
    if (param.start) {
      q.skip(param.start);
    }
    if (param.limit) {
      q.limit(param.limit);
    }
  }
  q.sort({date: 'desc'});
  if (cb) {
    return q.exec(cb);
  } else {
    return q;
  }
};

module.exports = PostSchema;

Fix wrong type for title in post model.


module.exports = function(config) {
  config.set({
    frameworks: ['mocha'],

    exclude: ['build/test/external.spec.js'],

    files: [
      'vendor/es5-shim.js',
      'vendor/es5-sham.js',
      'vendor/rsvp.js',
      'vendor/unexpected-magicpen.min.js',
      'build/test/promisePolyfill.js',
      'unexpected.js',
      'build/test/common.js',
      'build/test/**/*.spec.js'
    ],

    browsers: ['ChromeHeadlessNoSandbox'],

    client: {
      mocha: {
        reporter: 'html'
      }
    },

    customLaunchers: {
      ChromeHeadlessNoSandbox: {
        base: 'ChromeHeadless',
        flags: ['--no-sandbox']
      }
    }
  });
};

module.exports = function(config) {
  config.set({
    frameworks: ['mocha'],

    exclude: ['build/test/external.spec.js'],

    files: [
      'vendor/es5-shim.js',
      'vendor/es5-sham.js',
      'vendor/rsvp.js',
      'vendor/unexpected-magicpen.min.js',
      'build/test/promisePolyfill.js',
      'unexpected.js',
      'build/test/common.js',
      'build/test/**/*.spec.js'
    ],

    browsers: ['ChromeHeadlessNoSandbox'],

    client: {
      mocha: {
        reporter: 'html'
      }
    },

    customLaunchers: {
      ChromeHeadlessNoSandbox: {
        base: 'ChromeHeadless',
        flags: ['--no-sandbox']
      }
    },

    reporters: ['progress']
  });
};

Use the progress reporter for karma


describe('Sock object', function() {
  var socket;
  var pong;
  var joinRoom;
  beforeEach(function() {
  });

  afterEach(function() {
  });

  it('should exist', function() {
    expect(window.Tilt.Sock).toBeDefined();
  });

  it('should connect and return a new sock object', function() {
    expect(window.Tilt.connect('10.0.0.1') instanceof window.Tilt.Sock).toBeTruthy();
  });

  describe('for games', function() {
    it('should emit messages', function() {
      var s = window.Tilt.connect('10.0.0.1');

      s.emit('cntID', 'msgname', 'argblah');
      var emits = io.mockGetFunctionCalls('emit');
      expect(emits[emits.length - 1]).toEqual(['msg', 'cntID', ['msgname', 'argblah']]);
    });
  });
});

describe('Sock object', function() {
  var socket;
  var pong;
  var joinRoom;
  beforeEach(function() {
  });

  afterEach(function() {
  });

  it('should exist', function() {
    expect(window.Tilt.Sock).toBeDefined();
  });

  it('should connect and return a new sock object', function() {
    expect(window.Tilt.connect('10.0.0.1') instanceof window.Tilt.Sock).toBeTruthy();
  });

  describe('for games', function() {
    it('should emit messages', function() {
      var s = window.Tilt.connect('10.0.0.1');

      s.emit('cntID', 'msgname', 'argblah');
      var emits = io.mockGetFunctionCalls('emit');
      expect(emits[emits.length - 1]).toEqual(['msg', 'cntID', ['msgname', 'argblah']]);
    });
  });

  describe('for controllers', function() {
    it('should emit messages', function() {
      var s = window.Tilt.connect('10.0.0.1', 'gameidhere');

      s.emit('msgname', 'argblah');
      var emits = io.mockGetFunctionCalls('emit');
      expect(emits[emits.length - 1]).toEqual(['msg', ['msgname', 'argblah']]);
    });
  });
});

Add a test for controllers


var feature_flags = (function () {

var exports = {};

exports.mark_read_at_bottom = true;
exports.summarize_read_while_narrowed = true;

exports.twenty_four_hour_time = _.contains([],
                                  page_params.email);
exports.dropbox_integration = page_params.staging || _.contains(['dropbox.com'], page_params.domain);
exports.email_forwarding = true;

exports.mandatory_topics = _.contains([
    'customer7.invalid'
    ],
    page_params.domain
);

exports.collapsible = page_params.staging;

exports.propagate_topic_edits = page_params.staging ||
  _.contains(['customer7.invalid'], page_params.domain);

exports.fade_users_when_composing = page_params.staging;

exports.alert_words =
  _.contains(['reddit.com', 'mit.edu', 'zulip.com'], page_params.domain);

exports.muting = page_params.staging;

exports.left_side_userlist = page_params.staging ||
  _.contains(['customer7.invalid'], page_params.domain);

return exports;

}());

var feature_flags = (function () {

var exports = {};

exports.mark_read_at_bottom = true;
exports.summarize_read_while_narrowed = true;

exports.twenty_four_hour_time = _.contains([],
                                  page_params.email);
exports.dropbox_integration = page_params.staging || _.contains(['dropbox.com'], page_params.domain);
exports.email_forwarding = true;

exports.mandatory_topics = _.contains([
    'customer7.invalid'
    ],
    page_params.domain
);

exports.collapsible = page_params.staging;

exports.propagate_topic_edits = page_params.staging ||
  _.contains(['customer7.invalid'], page_params.domain);

exports.fade_users_when_composing = page_params.staging;

exports.alert_words =
  _.contains(['reddit.com', 'mit.edu', 'zulip.com'], page_params.domain);

var zulip_mit_emails = [];

var is_zulip_mit_user = _.contains(zulip_mit_emails, page_params.email);

exports.muting = page_params.staging || is_zulip_mit_user;

exports.left_side_userlist = page_params.staging ||
  _.contains(['customer7.invalid'], page_params.domain);

return exports;

}());

Enable muting for internal MIT users.


module.exports = {
  env: {
    browser: true,
    es6: true,
  },
  globals: {
    afterEach: true,
    beforeEach: true,
    chrome: true,
    expect: true,
    jest: true,
    beforeEach: true,
    afterEach: true,
    describe: true,
    test: true,
  },
  extends: [
    'eslint:recommended',
    'plugin:flowtype/recommended',
    'plugin:react/recommended',
  ],
  parser: 'babel-eslint',
  parserOptions: {
    ecmaFeatures: {
      jsx: true,
    },
    ecmaVersion: 2015,
    sourceType: 'module',
  },
  plugins: [
    'flowtype',
    'react',
  ],
  rules: {
    // Rules included in ESLint
    'comma-dangle': [2, 'always-multiline'],
    'consistent-return': 2,
    'eqeqeq': [2, 'smart'],
    'indent': [2, 2],
    'max-len': [2, {'code': 100, 'ignoreUrls': true}],
    'no-console': 0,
    'no-multi-spaces': 2,
    'no-unused-expressions': 2,
    'no-var': 2,
    'object-shorthand': 2,
    'prefer-const': 2,
    'quotes': [2, 'single', {'avoidEscape': true}],
    'semi': 2,
    'sort-imports': 2,
  },
};

module.exports = {
  env: {
    browser: true,
    es6: true,
  },
  globals: {
    afterEach: true,
    beforeEach: true,
    chrome: true,
    describe: true,
    expect: true,
    jest: true,
    test: true,
  },
  extends: [
    'eslint:recommended',
    'plugin:flowtype/recommended',
    'plugin:react/recommended',
  ],
  parser: 'babel-eslint',
  parserOptions: {
    ecmaFeatures: {
      jsx: true,
    },
    ecmaVersion: 2015,
    sourceType: 'module',
  },
  plugins: [
    'flowtype',
    'react',
  ],
  rules: {
    // Rules included in ESLint
    'comma-dangle': [2, 'always-multiline'],
    'consistent-return': 2,
    'eqeqeq': [2, 'smart'],
    'indent': [2, 2],
    'max-len': [2, {'code': 100, 'ignoreUrls': true}],
    'no-console': 0,
    'no-multi-spaces': 2,
    'no-unused-expressions': 2,
    'no-var': 2,
    'object-shorthand': 2,
    'prefer-const': 2,
    'quotes': [2, 'single', {'avoidEscape': true}],
    'semi': 2,
    'sort-imports': 2,
  },
};

Remove duplicate keys in eslint `globals`


module.exports = {
  "env": {
    "node": true
  },
  "extends": "eslint:recommended",
  "rules": {
    "indent": [
      "error",
      2
    ],
    "linebreak-style": [
      "error",
      "unix"
    ],
    "quotes": [
      "error",
      "single"
    ],
    "semi": [
      "error",
      "always"
    ]
  }
};

module.exports = {
  "env": {
    "es6": true,
    "node": true
  },
  "extends": "eslint:recommended",
  "rules": {
    "indent": [
      "error",
      2
    ],
    "linebreak-style": [
      "error",
      "unix"
    ],
    "quotes": [
      "error",
      "single"
    ],
    "semi": [
      "error",
      "always"
    ]
  }
};

Enable ES6 support for const


module.exports = {
  'env': {
    'commonjs': true,
    'es6': true,
    'node': true,
    'browser': true,
    'jest': true,
    'mocha': true,
    'jasmine': true,
  },
  'extends': 'eslint:recommended',
  'parser': 'babel-eslint',
  'parserOptions': {
    'sourceType': 'module'
  },
  'rules': {
    'no-console': 0,
    'max-len': ['error', 80],
    'no-unused-vars': ['error', {
      'argsIgnorePattern': '^_',
      'varsIgnorePattern': '^_'
    }],
    quotes: ['error', 'single', {
      allowTemplateLiterals: true,
    }],
  }
};

module.exports = {
  plugins: [
    'html'
  ],
  'env': {
    'commonjs': true,
    'es6': true,
    'node': true,
    'browser': true,
    'jest': true,
    'mocha': true,
    'jasmine': true,
  },
  'extends': 'eslint:recommended',
  'parser': 'babel-eslint',
  'parserOptions': {
    'sourceType': 'module'
  },
  'rules': {
    'no-console': 0,
    'max-len': ['error', 80],
    'no-unused-vars': ['error', {
      'argsIgnorePattern': '^_',
      'varsIgnorePattern': '^_'
    }],
    quotes: ['error', 'single', {
      allowTemplateLiterals: true,
    }],
  }
};

Add eslint-plugin-html to config file


var langs = {
	'de':'deutsch',
	'en':'english',
	'es':'español',
	'fr':'français',
	'it':'italiano',
	'ja':'日本',
	'ko':'한국어',
	'pl':'polski',
	'pt':'português',
	'ru':'русский',
	'sv':'svenska',
	'tr':'türkçe',
	'uk':'українська',
	'zh_cn':'简体中文'
};

var langs = {
	'de':'deutsch',
	'en':'english',
	'es':'español',
	'fr':'français',
	'it':'italiano',
	'ja':'日本語',
	'ko':'한국어',
	'pl':'polski',
	'pt':'português',
	'ru':'русский',
	'sv':'svenska',
	'tr':'türkçe',
	'uk':'українська',
	'zh_cn':'简体中文'
};

Change language name 'Japan' to 'Japanese'.


/**
 * In-Memory configuration storage
 */
let Config = {
    isInitialized: false,
    debug: true,
    overridePublishFunction: true,
    mutationDefaults: {
        pushToRedis: true,
        optimistic: true,
    },
    passConfigDown: false,
    redis: {
        port: 6379,
        host: '127.0.0.1',
    },
    globalRedisPrefix: '',
    retryIntervalMs: 10000,
    externalRedisPublisher: false,
    redisExtras: {
        retry_strategy: function(options) {
            return Config.retryIntervalMs;
            // reconnect after
            // return Math.min(options.attempt * 100, 30000);
        },
        events: {
            end(err) {
                console.error('RedisOplog - Connection to redis ended');
            },
            error(err) {
                console.error(
                    `RedisOplog - An error occured: \n`,
                    JSON.stringify(err)
                );
            },
            connect(err) {
                if (!err) {
                    console.log(
                        'RedisOplog - Established connection to redis.'
                    );
                } else {
                    console.error(
                        'RedisOplog - There was an error when connecting to redis',
                        JSON.stringify(err)
                    );
                }
            },
            reconnecting(err) {
                if (err) {
                    console.error(
                        'RedisOplog - There was an error when re-connecting to redis',
                        JSON.stringify(err)
                    );
                }
            },
        },
    },
};

export default Config;

/**
 * In-Memory configuration storage
 */
let Config = {
    isInitialized: false,
    debug: false,
    overridePublishFunction: true,
    mutationDefaults: {
        pushToRedis: true,
        optimistic: true,
    },
    passConfigDown: false,
    redis: {
        port: 6379,
        host: '127.0.0.1',
    },
    globalRedisPrefix: '',
    retryIntervalMs: 10000,
    externalRedisPublisher: false,
    redisExtras: {
        retry_strategy: function(options) {
            return Config.retryIntervalMs;
            // reconnect after
            // return Math.min(options.attempt * 100, 30000);
        },
        events: {
            end(err) {
                console.error('RedisOplog - Connection to redis ended');
            },
            error(err) {
                console.error(
                    `RedisOplog - An error occured: \n`,
                    JSON.stringify(err)
                );
            },
            connect(err) {
                if (!err) {
                    console.log(
                        'RedisOplog - Established connection to redis.'
                    );
                } else {
                    console.error(
                        'RedisOplog - There was an error when connecting to redis',
                        JSON.stringify(err)
                    );
                }
            },
            reconnecting(err) {
                if (err) {
                    console.error(
                        'RedisOplog - There was an error when re-connecting to redis',
                        JSON.stringify(err)
                    );
                }
            },
        },
    },
};

export default Config;

Change default debug behavior back to false


var _ = require('underscore'),
  fs = require('fs');

function Writer() {

  function gen(templates, numSegments, params, outFile, cb) {
    var stream = fs.createWriteStream(outFile,
        { flags: 'w', encoding: 'utf-8' }),
      segmentId = 0;

    stream.on('error', function (err) {
      console.error('Error: ' + err);
    });

    stream.on('close', function () {
      cb();
    });

    stream.write(templates.header);

    function _writeSegment(segmentId) {
      var segment = templates.segment;
      params.segment_id = segmentId;

      function _apply(param) {
        segment = segment.replace(new RegExp('{' + param + '}', 'g'), params[param]);
      }

      _.keys(params).forEach(_apply);
      stream.write(segment);
    }

    while (segmentId++ < numSegments) {
      _writeSegment(segmentId);
    }

    stream.end(templates.footer);
  }

  return {
    gen: gen
  };
}

exports.Writer = Writer;

var _ = require('underscore'),
  fs = require('fs');

function Writer() {

  function gen(templates, numSegments, params, outFile, cb) {
    var stream = fs.createWriteStream(outFile,
        { flags: 'w', encoding: 'utf-8' }),
      segmentId = 0;

    stream.on('error', function (err) {
      console.error('Error: ' + err);
    });

    stream.on('close', function () {
      cb();
    });

    function _apply(text, params) {
      _.keys(params).forEach(function (param) {
        text = text.replace(new RegExp('{' + param + '}', 'g'), params[param]);
      });
      return text;
    }

    stream.write(_apply(templates.header, params));

    while (segmentId++ < numSegments) {
      var segmentParams = _.clone(params);
      segmentParams.segment_id = segmentId;
      stream.write(_apply(templates.segment, segmentParams));
    }

    stream.end(_apply(templates.footer, params));
  }

  return {
    gen: gen
  };
}

exports.Writer = Writer;

Apply params in header and footer.


/* eslint-env amd */
(function (name, definition) {
  if (typeof define === 'function') {
    // AMD
    define(definition)
  } else if (typeof module !== 'undefined' && module.exports) {
    // Node.js
    module.exports = definition()
  } else {
    // Browser
    window[name] = definition()
  }
})('nullPrune', function () {
  function hasOwnProperty (obj, property) {
    return Object.prototype.hasOwnProperty.call(obj, property)
  }

  function isObject (input) {
    return input && (typeof input === 'object')
  }

  function keys (obj) {
    var key
    var ownKeys = []

    for (key in obj) {
      if (hasOwnProperty(obj, key)) {
        ownKeys.push(key)
      }
    }

    return ownKeys
  }

  function nullPrune (inputObject, context) {
    var objectKey = context.objectKey
    var parentObject = context.parentObject

    keys(inputObject).forEach(function (key) {
      var node = inputObject[key]

      if (isObject(node)) {
        nullPrune(node, {
          objectKey: key,
          parentObject: inputObject
        })
      } else if (node == null) {
        delete inputObject[key]
      }
    })

    if (parentObject && keys(inputObject).length === 0) {
      delete parentObject[objectKey]
    }
  }

  return function (inputObject) {
    if (!isObject(inputObject)) {
      return inputObject
    }

    nullPrune(inputObject, {})
    return inputObject
  }
})

/* eslint-env amd */
(function (name, definition) {
  if (typeof define === 'function') {
    // AMD
    define(definition)
  } else if (typeof module !== 'undefined' && module.exports) {
    // Node.js
    module.exports = definition()
  } else {
    // Browser
    window[name] = definition()
  }
})('nullPrune', function () {
  function isObject (input) {
    return input && (typeof input === 'object')
  }

  function ownKeys (obj) {
    var key
    var ownKeys = []
    var hasOwnProperty = Object.prototype.hasOwnProperty

    for (key in obj) {
      if (hasOwnProperty.call(obj, key)) {
        ownKeys.push(key)
      }
    }

    return ownKeys
  }

  function nullPrune (inputObject, context) {
    var objectKey = context.objectKey
    var parentObject = context.parentObject
    var keys = ownKeys(inputObject)
    var k
    var key
    var node

    for (k in keys) {
      key = keys[k]
      node = inputObject[key]

      if (isObject(node)) {
        nullPrune(node, {
          objectKey: key,
          parentObject: inputObject
        })
      } else if (node == null) {
        delete inputObject[key]
      }
    }

    if (parentObject && ownKeys(inputObject).length === 0) {
      delete parentObject[objectKey]
    }
  }

  return function (inputObject) {
    if (!isObject(inputObject)) {
      return inputObject
    }

    nullPrune(inputObject, {})
    return inputObject
  }
})

Make it compatible with old browsers


steal('can/util/mvc.js')
.then('funcunit/qunit',
	  'can/util/fixture')
.then(function() {
	var oldmodule = window.module;

	// Set the test timeout to five minutes
	QUnit.config.hidepassed = true;
	QUnit.config.testTimeout = 300000;
	if ( console && console.log ) {
		QUnit.log(function( details ) {
			if ( ! details.result ) {
				console.log( "FAILURE: ", details.result, details.message );
			}
		});
	}

	if(window.TESTINGLIBRARY !== undefined) {
		window.module = function(name, testEnvironment) {
			oldmodule(TESTINGLIBRARY + '/' + name, testEnvironment);
		}
	}
})

steal('can/util/mvc.js')
.then('funcunit/qunit',
	  'can/util/fixture')
.then(function() {
	var oldmodule = window.module;

	// Set the test timeout to five minutes
	QUnit.config.hidepassed = true;
	QUnit.config.testTimeout = 300000;
	if ( typeof console !== "undefined" && console.log ) {
		QUnit.log(function( details ) {
			if ( ! details.result ) {
				console.log( "FAILURE: ", details.result, details.message );
			}
		});
	}

	if(window.TESTINGLIBRARY !== undefined) {
		window.module = function(name, testEnvironment) {
			oldmodule(TESTINGLIBRARY + '/' + name, testEnvironment);
		}
	}
})

Fix to console check causing breaks in IE.


var basename = require('path').basename;

module.exports = variationMatches;
function variationMatches(variations, path) {
    var result;
    variations.some(function(variation) {
        variation.chain.some(function(dir) {
            var parts = path.split(new RegExp("/"+dir+"/"));
            var found = parts.length > 1;
            if (found) result = {
                variation: variation,
                dir: basename(dir),
                file: parts[parts.length-1],
            };
            return found;
        });
    });
    return result;
}

module.exports = variationMatches;
function variationMatches(variations, path) {
    var result;
    variations.some(function(variation) {
        variation.chain.some(function(dir) {
            var parts = path.split(new RegExp("/"+dir+"/"));
            var found = parts.length > 1;
            if (found) result = {
                variation: variation,
                dir: dir,
                file: parts[parts.length-1],
            };
            return found;
        });
    });
    return result;
}

Fix variation matches with variations


const mongoose = require('mongoose')
const uniqueValidator = require('mongoose-unique-validator')
const paginate = require('mongoose-paginate')
const requiredValidationMessage = '{PATH} is required'

let movieSchema = mongoose.Schema({
  title: { type: String, required: requiredValidationMessage, trim: true },
  image: [{ path: String, alt: String, title: String }],
  year: { type: String },
  rating: { type: Number, default: 0 },
  description: { type: String, default: '' },
  cast: [{ type: String, default: [] }],
  categories: [{ type: mongoose.Schema.Types.ObjectId, ref: 'Category', required: requiredValidationMessage }],
  releaseDate: { type: Date, default: Date.now }
}, {
  timestamps: true
})

movieSchema.index({ title: 1, year: 1 })
movieSchema.plugin(uniqueValidator)
movieSchema.plugin(paginate)

mongoose.model('Movie', movieSchema)

const mongoose = require('mongoose')
const uniqueValidator = require('mongoose-unique-validator')
const paginate = require('mongoose-paginate')
const requiredValidationMessage = '{PATH} is required'

let movieSchema = mongoose.Schema({
  title: { type: String, required: requiredValidationMessage, trim: true },
  image: [{ path: String, alt: String, title: String }],
  rating: { type: Number, default: 0 },
  description: { type: String, default: '' },
  cast: [{ type: String, default: [] }],
  categories: [{ type: mongoose.Schema.Types.ObjectId, ref: 'Category', required: requiredValidationMessage }],
  releaseDate: { type: Date, default: Date.now }
}, {
  timestamps: true,
  toObject: { virtuals: true },
  toJSON: { virtuals: true }
})

movieSchema
  .virtual('year')
  .get(function () {
    return this.releaseDate.getFullYear()
  })

movieSchema.index({ title: 1, year: 1 })
movieSchema.plugin(uniqueValidator)
movieSchema.plugin(paginate)

mongoose.model('Movie', movieSchema)

Change 'year' from persistent to virtual and get from 'releaseDate'


const fs = require('fs')
const path = require('path')
const { compact, sortBy, concat, includes } = require('lodash')

const config = require('../config')
const urls = require('../lib/urls')

const subApps = fs.readdirSync(__dirname)

const APP_GLOBAL_NAV_ITEMS = compact(
  subApps.map((subAppDir) => {
    const constantsPath = path.join(__dirname, subAppDir, 'constants.js')

    if (
      !fs.existsSync(constantsPath) ||
      includes(constantsPath, 'propositions')
    ) {
      return null
    }

    return require(constantsPath).GLOBAL_NAV_ITEM
  })
)

const SORTED_APP_GLOBAL_NAV_ITEMS = sortBy(
  APP_GLOBAL_NAV_ITEMS,
  (globalNavItem) => globalNavItem.order
)
const GLOBAL_NAV_ITEMS = concat(
  SORTED_APP_GLOBAL_NAV_ITEMS,
  {
    path: config.performanceDashboardsUrl,
    label: 'MI dashboards',
    key: 'datahub-mi',
  },
  {
    path: urls.external.findExporters(),
    label: 'Find exporters',
    key: 'find-exporters',
  }
)

/**
 * Required for querying access to apps
 */

module.exports = GLOBAL_NAV_ITEMS

const fs = require('fs')
const path = require('path')
const { compact, sortBy, concat, includes } = require('lodash')

const urls = require('../lib/urls')

const subApps = fs.readdirSync(__dirname)

const APP_GLOBAL_NAV_ITEMS = compact(
  subApps.map((subAppDir) => {
    const constantsPath = path.join(__dirname, subAppDir, 'constants.js')

    if (
      !fs.existsSync(constantsPath) ||
      includes(constantsPath, 'propositions')
    ) {
      return null
    }

    return require(constantsPath).GLOBAL_NAV_ITEM
  })
)

const SORTED_APP_GLOBAL_NAV_ITEMS = sortBy(
  APP_GLOBAL_NAV_ITEMS,
  (globalNavItem) => globalNavItem.order
)
const GLOBAL_NAV_ITEMS = concat(SORTED_APP_GLOBAL_NAV_ITEMS, {
  path: urls.external.findExporters(),
  label: 'Find exporters',
  key: 'find-exporters',
})

/**
 * Required for querying access to apps
 */

module.exports = GLOBAL_NAV_ITEMS

Remove deprecated MI site from GLOBAL_NAV_ITEMS


import React from 'react';
import TestUtils from 'react-addons-test-utils';

export default {
  renderComponent(Component, props = {}, state = {}) {
    const component = TestUtils.renderIntoDocument(<Component {...props} />);
    if (state !== {}) { component.setState(state); }
    return component;
  },

  shallowRenderComponent(component, props, ...children) {
    const shallowRenderer = TestUtils.createRenderer();
    shallowRenderer.render(React.createElement(component, props, children.length > 1
      ? children
      : children[0],
    ));
    return shallowRenderer.getRenderOutput();
  },
};

import React from 'react';
import TestUtils from 'react-dom/test-utils';

export default {
  renderComponent(Component, props = {}, state = {}) {
    const component = TestUtils.renderIntoDocument(<Component {...props} />);
    if (state !== {}) { component.setState(state); }
    return component;
  },

  shallowRenderComponent(component, props, ...children) {
    const shallowRenderer = TestUtils.createRenderer();
    shallowRenderer.render(React.createElement(component, props, children.length > 1
      ? children
      : children[0],
    ));
    return shallowRenderer.getRenderOutput();
  },
};

Update tests to use react-dom/test-utils


'use strict';

/*
 * Number Filters
 *
 * In HTML Template Binding
 * {{ filter_expression | filter : expression : comparator}}
 *
 * In JavaScript
 * $filter('filter')(array, expression, comparator)
 *
 * https://docs.angularjs.org/api/ng/filter/filter
 */

var app = angular.module('app.filters.number', []);

app.filter("formatPrice", function () {
    return function (value) {
        if (!value) {
            return value;
        }
        return '$' + value;
    };
});

app.filter("formatMySQLDate", function () {
    return function (value) {
        if (!value) {
            return value;
        }
        return moment(value, 'YYYY-MM-DD HH:mm:ss').format('M/D/YYYY h:mm a');
    };
});

'use strict';

/*
 * Number Filters
 *
 * In HTML Template Binding
 * {{ filter_expression | filter : expression : comparator}}
 *
 * In JavaScript
 * $filter('filter')(array, expression, comparator)
 *
 * https://docs.angularjs.org/api/ng/filter/filter
 */

var app = angular.module('app.filters.number', []);

app.filter("formatPrice", function () {
    return function (value) {
        if (!value) {
            return value;
        }
        return '$' + value;
    };
});

app.filter("formatMySQLDate", function () {
    return function (value) {
        if (!value) {
            return value;
        }
        return moment(value, 'YYYY-MM-DD HH:mm:ss').tz('America/New_York').format('M/D/YYYY h:mm a');
    };
});

Set the timezone on MySQL formatted dates.


"use strict";

var zlib = require("zlib");

var cors = require("cors"),
    express = require("express");

var SyslogFilter = require("./syslog-filter");

module.exports = function(source) {
  var app = express();

  app.disable('x-powered-by');

  app.use(cors());

  app.get("/:ps(\\w*)?", function(req, res, next) {
    res.header("Content-Type", "text/plain");

    // compression
    var acceptEncoding = req.headers["accept-encoding"] || "",
        options = {
          flush: zlib.Z_PARTIAL_FLUSH
        };

    var src;

    if (req.params.ps) {
      // process name was provided
      src = source.pipe(new SyslogFilter(req.params.ps));
    } else {
      src = source;
    }

    if (acceptEncoding.indexOf("gzip") >= 0) {
      res.header("Content-Encoding", "gzip");
      return src.pipe(zlib.createGzip(options)).pipe(res);
    }

    if (acceptEncoding.indexOf("deflate") >= 0) {
      res.header("Content-Encoding", "deflate");
      return src.pipe(zlib.createDeflate(options)).pipe(res);
    }

    return source.pipe(res);
  });

  return app;
};

"use strict";

var stream = require("stream"),
    zlib = require("zlib");

var cors = require("cors"),
    express = require("express");

var SyslogFilter = require("./syslog-filter");

module.exports = function(nexus) {
  var app = express();

  app.disable('x-powered-by');

  app.use(cors());

  app.get("/:ps(\\w*)?", function(req, res, next) {
    res.header("Content-Type", "text/plain");

    // compression
    var acceptEncoding = req.headers["accept-encoding"] || "",
        options = {
          flush: zlib.Z_PARTIAL_FLUSH
        };

    var sink = new stream.PassThrough();

    if (req.params.ps) {
      // process name was provided
      console.log("Filtering for", req.params.ps);
      sink = sink.pipe(new SyslogFilter(req.params.ps));
    }

    var response;

    if (acceptEncoding.indexOf("gzip") >= 0) {
      res.header("Content-Encoding", "gzip");
      sink = sink.pipe(zlib.createGzip(options));
    } else if (acceptEncoding.indexOf("deflate") >= 0) {
      res.header("Content-Encoding", "deflate");
      sink = sink.pipe(zlib.createDeflate(options));
    }

    // don't reassign to sink--we need the stream that's actually plugged into
    // nexus
    nexus.pipe(sink).pipe(res);

    req.on("close", function() {
      nexus.unpipe(sink);
    });
  });

  return app;
};

Unplug client streams when requests end