import { get } from '@ember/object';
import RSVP from 'rsvp';
import { task } from 'ember-concurrency';
import wait from 'nomad-ui/utils/wait';

export function watchRecord(modelName) {
  return task(function*(id) {
    id = get(id, 'id') || id;
    while (true) {
      try {
        yield RSVP.all([
          this.store.findRecord(modelName, id, { reload: true, adapterOptions: { watch: true } }),
          wait(2000),
        ]);
      } catch (e) {
        yield e;
        break;
      }
    }
  });
}

export function watchRelationship(staticRelationshipName) {
  return task(function*(model, throttle = 2000) {
    while (true) {
      try {
        yield RSVP.all([
          this.get('store')
            .adapterFor(model.constructor.modelName)
            .reloadRelationship(model, staticRelationshipName, true),
          wait(throttle),
        ]);
      } catch (e) {
        yield e;
        break;
      }
    }
  });
}

export function watchAll(modelName) {
  return task(function*(throttle = 2000) {
    while (true) {
      try {
        yield RSVP.all([
          this.get('store').findAll(modelName, { reload: true, adapterOptions: { watch: true } }),
          wait(throttle),
        ]);
      } catch (e) {
        yield e;
        break;
      }
    }
  });
}

import { get } from '@ember/object';
import RSVP from 'rsvp';
import { task } from 'ember-concurrency';
import wait from 'nomad-ui/utils/wait';

export function watchRecord(modelName) {
  return task(function*(id, throttle = 2000) {
    id = get(id, 'id') || id;
    while (true) {
      try {
        yield RSVP.all([
          this.get('store').findRecord(modelName, id, {
            reload: true,
            adapterOptions: { watch: true },
          }),
          wait(throttle),
        ]);
      } catch (e) {
        yield e;
        break;
      }
    }
  });
}

export function watchRelationship(staticRelationshipName) {
  return task(function*(model, throttle = 2000) {
    while (true) {
      try {
        yield RSVP.all([
          this.get('store')
            .adapterFor(model.constructor.modelName)
            .reloadRelationship(model, staticRelationshipName, true),
          wait(throttle),
        ]);
      } catch (e) {
        yield e;
        break;
      }
    }
  });
}

export function watchAll(modelName) {
  return task(function*(throttle = 2000) {
    while (true) {
      try {
        yield RSVP.all([
          this.get('store').findAll(modelName, { reload: true, adapterOptions: { watch: true } }),
          wait(throttle),
        ]);
      } catch (e) {
        yield e;
        break;
      }
    }
  });
}

Make the throttle time configurable


'use strict';

const request = require('request');
const { makeUrl } = require('../utils');

/**
 * GET /api
 * List of API examples.
 */
exports.getApi = (req, res) => {
  res.render('api/index', {
    title: 'API Examples'
  });
};

/**
 * GET /api/quotes
 * Yahoo quotes
 */
exports.getQuotes = (req, res, next) => {
  const symbolsStr = req.query.q;
  const qs = {
    client: 'ig',
    q: symbolsStr
  };
  const baseUrl = 'http://finance.google.com/finance/info';
  const url = makeUrl(baseUrl, qs);
  console.log(url);
  request(url, (error, response, body) => {
    if (error) { return next(error); }
    // if (request.statusCode === 403) {
    //   return next(new Error('Error when getting quotes'));
    // }
    // Google returns string with //, chop it off.
    const result = JSON.parse(body.replace(/\/\//, ''));
    console.log(result);
    res.send({ response: JSON.stringify(result) });
  });
};

'use strict';

const request = require('request');
const { makeUrl } = require('../utils');

/**
 * GET /api
 * List of API examples.
 */
exports.getApi = (req, res) => {
  res.render('api/index', {
    title: 'API Examples'
  });
};

/**
 * GET /api/quotes
 * Yahoo quotes
 */
exports.getQuotes = (req, res, next) => {
  const symbolsStr = req.query.q;
  const qs = {
    client: 'ig',
    q: symbolsStr
  };
  const baseUrl = 'http://finance.google.com/finance/info';
  const url = makeUrl(baseUrl, qs);
  console.log(url);
  request(url, (error, response, body) => {
    if (error) { return next(error); }
    // if (request.statusCode === 403) {
    //   return next(new Error('Error when getting quotes'));
    // }
    // Google returns string with //, chop it off.
    const result = JSON.parse(body.replace(/\/\//, ''));
    res.send({ response: JSON.stringify(result) });
  });
};

Fix bug: heroku quote for VSB is 0


/*jslint browser: true, undef: true *//*global Ext*/
Ext.define('Jarvus.ace.field.KeyboardHandlerComboBox', {
    extend: 'Jarvus.ace.field.AceOptionComboBox',
    xtype: 'jarvus-ace-field-keyboardhandlercombobox',

    config: {
        option: 'keyboardHandler'
    },

    store: {
        fields:['value','text'],
        data: [
            {value: 'ace/keyboard/vim',  text: 'Vim'},
            {value: 'ace/keyboard/emacs',  text: 'Emacs'}
        ]
    }

});

/*jslint browser: true, undef: true *//*global Ext*/
/**
 *
 */
Ext.define('Jarvus.ace.field.KeyboardHandlerComboBox', {
    extend: 'Jarvus.ace.field.AceOptionComboBox',
    xtype: 'jarvus-ace-field-keyboardhandlercombobox',

    config: {
        option: 'keyboardHandler'
    },

    store: {
        fields:['value','text'],
        data: [
            {value: null,  text: 'Default'},
            {value: 'ace/keyboard/vim',  text: 'Vim'},
            {value: 'ace/keyboard/emacs',  text: 'Emacs'}
        ]
    }

});

Rework fields for new config changes


Vue.component('spark-kiosk-notify', {
    props: [
        'notifications',
        'users',
        'createNotification'
    ],
    ready(){
        this.getNotifications();
        this.getUsers();
    },
    methods: {
        /**
         * Get all of the announcements.
         */
        getNotifications: function(){
            this.$http.get('/skn/notifications')
                .then(response => {
                    this.notifications = response.data;
                });
        },

        /**
         * Get all of the users.
         */
        getUsers: function(){
            this.$http.get('/skn/users')
                .then(response => {
                    this.users = response.data;
                });
        },

        /**
         * Create Notification.
         */
        createNotification: function(){
            this.$http.get('/skn/notifications/create', this.createNotification)
                .then(response => {
                    this.createNotification = {};
                    this.getNotifications();
                });
        }

    }
});

Vue.component('spark-kiosk-notify', {
    props: [
    ],
    data: {
        'notifications': []
        'users': []
        'createNotification': {
            "user_id": null
        }
    }
    ready(){
        this.getNotifications();
        this.getUsers();
    },
    methods: {
        /**
         * Get all of the announcements.
         */
        getNotifications: function(){
            this.$http.get('/skn/notifications')
                .then(response => {
                    this.notifications = response.data;
                });
        },

        /**
         * Get all of the users.
         */
        getUsers: function(){
            this.$http.get('/skn/users')
                .then(response => {
                    this.users = response.data;
                });
        },

        /**
         * Create Notification.
         */
        createNotification: function(){
            this.$http.get('/skn/notifications/create', this.createNotification)
                .then(response => {
                    this.createNotification = {};
                    this.getNotifications();
                });
        }

    }
});

Switch props to data, as they aren't passed in


'use strict'

const _ = require('lodash')

const generateEnv = require('./generateEnv.js')

const features = {
  config: require('./config'),
  env: require('./env'),
  history: require('./history'),
  horrible: require('./horrible'),
  local: require('./local'),
  mal: require('./mal'),
  news: require('./news'),
  nyaa: require('./nyaa'),
  openExternal: require('./openExternal'),
  seasons: require('./seasons'),
  search: require('./search'),
  wl: require('./watchList')
}

let routes = []

const setup = (app) => {
  generateEnv()

  _.each(features, (feature) => {
    _.each(feature, (route) => routes.push(route))
  })

  // auto update
  /* istanbul ignore next */
  if (!['KawAnime-test', 'development'].includes(process.env.NODE_ENV)) {
    routes = require('./updater')(app, routes)
  }

  _.each(routes, (route) => route(app))
}

module.exports = setup

'use strict'

const _ = require('lodash')

const generateEnv = require('./generateEnv.js')

const setup = (app) => {
  generateEnv()

  let routes = []

  const features = {
    config: require('./config'),
    env: require('./env'),
    history: require('./history'),
    horrible: require('./horrible'),
    local: require('./local'),
    mal: require('./mal'),
    news: require('./news'),
    nyaa: require('./nyaa'),
    openExternal: require('./openExternal'),
    seasons: require('./seasons'),
    search: require('./search'),
    wl: require('./watchList')
  }

  _.each(features, (feature) => {
    _.each(feature, (route) => routes.push(route))
  })

  // auto update
  /* istanbul ignore next */
  if (!['KawAnime-test', 'development'].includes(process.env.NODE_ENV)) {
    routes = require('./updater')(app, routes)
  }

  _.each(routes, (route) => route(app))
}

module.exports = setup

Fix tests: logs needed config before it was created in first launch


const elements = document.querySelectorAll('bracket-less');

function expandBrackets() {
  this.innerHTML = this.dataset.bracketless;
  this.classList.toggle('bracket-less');
}
function collapseBrackets() {
  this.innerHTML = '...';
  this.classList.toggle('bracket-less');
}
elements.forEach(el => el.addEventListener('click', expandBrackets.bind(el)));
elements.forEach(el => el.addEventListener('dblclick', collapseBrackets.bind(el)));

function toggleCollapse(state) {
  if (state.collapse) { // play -> text collapsed
    elements.forEach(el => el.classList.add('bracket-less'));
  } else { // pause -> text displayed
    elements.forEach(el => el.classList.remove('bracket-less'));
  }
}

chrome.runtime.onMessage.addListener((state, sender, sendResponse) => {
  sendResponse(toggleCollapse(state));
});

const elements = document.querySelectorAll('bracket-less');
let clicks = 0;
let timer = null;

function expandBrackets(e) {
  e.innerHTML = e.dataset.bracketless;
  e.classList.toggle('bracket-less');
}
function collapseBrackets(e) {
  e.innerHTML = '...';
  e.classList.toggle('bracket-less');
}

function clicksHandler() {
  clicks += 1; // count clicks
  if (clicks === 1) {
    timer = setTimeout(() => {
      expandBrackets(this);
      clicks = 0;
    }, 322);
  } else {
    clearTimeout(timer); // prevent single-click action
    collapseBrackets(this);
    clicks = 0;
  }
}

elements.forEach(el => el.addEventListener('click', clicksHandler.bind(el)));

function toggleCollapse(state) {
  if (state.collapse) { // play -> text collapsed
    elements.forEach(el => el.classList.add('bracket-less'));
  } else { // pause -> text displayed
    elements.forEach(el => el.classList.remove('bracket-less'));
  }
}

chrome.runtime.onMessage.addListener((state, sender, sendResponse) => {
  sendResponse(toggleCollapse(state));
});

Fix dbl click firing single click evt


var ExtractTextPlugin = require('extract-text-webpack-plugin');
var webpack = require('webpack');

module.exports = {
  entry: './index.jsx',
  output: {
    path: 'assets',
    filename: 'bundle.js',
  },
  module: {
    loaders: [
      {
        test: /\.jsx?$/,
        loader: 'babel-loader'
      },
      {
        test: /\.css$/,
        loader: ExtractTextPlugin.extract('style-loader', 'css-loader')
      },
      {
        test: /\.(otf|eot|svg|ttf|woff)$/,
        loader: 'url-loader?limit=8192'
      }
    ]
  },
  resolve: {
    extensions: ['', '.js', '.jsx', '.json']
  },
  plugins: [
    new webpack.ProvidePlugin({
      $: "jquery",
      jQuery: "jquery",
      "window.jQuery": "jquery",
      "root.jQuery": "jquery"
    }),
    new ExtractTextPlugin('bundle.css')
  ]
};

var ExtractTextPlugin = require('extract-text-webpack-plugin');
var webpack = require('webpack');

module.exports = {
  entry: __dirname + '/index.jsx',
  output: {
    path: 'assets',
    filename: 'bundle.js',
  },
  module: {
    loaders: [
      {
        test: /\.jsx?$/,
        loader: 'babel-loader'
      },
      {
        test: /\.css$/,
        loader: ExtractTextPlugin.extract('style-loader', 'css-loader')
      },
      {
        test: /\.(otf|eot|svg|ttf|woff)$/,
        loader: 'url-loader?limit=8192'
      }
    ]
  },
  resolve: {
    extensions: ['', '.js', '.jsx', '.json']
  },
  plugins: [
    new webpack.ProvidePlugin({
      $: "jquery",
      jQuery: "jquery",
      "window.jQuery": "jquery",
      "root.jQuery": "jquery"
    }),
    new ExtractTextPlugin('bundle.css')
  ]
};

Fix `npm run-script example` compilation.


export default {
  sideMargin: '4rem',
  pageWidth: '960px'
};

export default {
  sideMargin: '4rem',
  pageWidth: '1024px'
};

Make page 1024px wide so table fits comfortably


/**
 * Filters the passed value and returns `undefined` if either:
 * – An [array] or an {object} is empty.
 * – `null` has been passed.
 * – `NaN` has been passed.
 *
 * @flow
 * @param {*} a – The passed data.
 * @return {*|undefined} – Either `undefined` or the passed data.
 */

import { isEmptyObject, numberIsNaN } from "./";

function filterEmpty(a: mixed): mixed {
  if (typeof a === "object") return !isEmptyObject(a) ? a : undefined;
  if (Number.isNaN(a)) return undefined;

  return a;
}

export { filterEmpty };

/**
 * Filters the passed value and returns `undefined` if either:
 * – An [array] or an {object} is empty.
 * – `null` has been passed.
 * – `NaN` has been passed.
 *
 * @flow
 * @param {*} a – The passed data.
 * @return {*|undefined} – Either `undefined` or the passed data.
 */

import { isEmptyObject, numberIsNaN } from "./";

function filterEmpty(a: mixed): mixed {
  if (typeof a === "object") return !isEmptyObject(a) ? a : undefined;
  if (numberIsNaN(a)) return undefined;

  return a;
}

export { filterEmpty };

Replace native method with a polyfill


import lost from 'lost'
import postcssImport from 'postcss-import'
import postcssCssnext from 'postcss-cssnext'
import resolveStyleImport from '../util/resolveStyleImport'

export default options => {
  const styleResolver = resolveStyleImport({
    from: options.basePath
  })

  return wp => {
    const importer = postcssImport({
      addDependencyTo: wp,
      resolve: styleResolver
    })

    return [
      importer,
      lost,
      postcssCssnext
    ]
  }
}

import lost from 'lost'
import postcssImport from 'postcss-import'
import postcssCssnext from 'postcss-cssnext'
import resolveStyleImport from '../util/resolveStyleImport'

export default options => {
  const styleResolver = resolveStyleImport({
    from: options.basePath
  })

  return wp => {
    const importer = postcssImport({
      addDependencyTo: wp,
      resolve: styleResolver
    })

    return [
      importer,
      postcssCssnext,
      lost
    ]
  }
}

Change order of PostCSS plugins to fix build error


import React from "react";
import ExperienceList from "../components/ExperienceList";
import ProjectsList from "../components/ProjectsList";
import OssList from "../components/OssList";
import About from "../components/Sidebar/About";
import Links from "../components/Sidebar/Links";
import Layout from "../components/layout";
import emojiSupport from "detect-emoji-support";

import "typeface-inter";
import "./style.scss";

const App = (props) => (
  <Layout location={props.location}>

          Hi!

              I'm

                Shriram Balaji{" "}

            {emojiSupport() && (

                 👋

            )}

          Software Engineer building tools for humans.

        <ExperienceList />
        <OssList />
        <ProjectsList />

          <About />

          <Links />

  </Layout>
);

export default App;

import React from "react";
import ExperienceList from "../components/ExperienceList";
import ProjectsList from "../components/ProjectsList";
import OssList from "../components/OssList";
import About from "../components/Sidebar/About";
import Links from "../components/Sidebar/Links";
import Layout from "../components/layout";
import emojiSupport from "detect-emoji-support";

import "typeface-inter";
import "./style.scss";

const App = (props) => (
  <Layout location={props.location}>

          Hi!

              I'm

                Shriram Balaji

            {emojiSupport() && (

                 👋

            )}

          Software Engineer building tools for humans.

        <ExperienceList />
        <OssList />
        <ProjectsList />

          <About />

          <Links />

  </Layout>
);

export default App;

Add a non-breaking space in front of name


module.exports = [
    {
        "type": "heading",
        "defaultValue": "Preferences" ,
        "size": 3
    },
    {
        "type": "section",
        "items": [
            {
                "type": "heading",
                "defaultValue": "Colors"
            },
            {
                "type": "text",
                "defaultValue": "Only available on compatible platforms."
            },
            {
                "type": "color",
                "allowGray": true,
                "label": "Background",
                "messageKey": "BACKGROUND_COLOR",
                "defaultValue": "000000"
            },
            {
                "type": "color",
                "allowGray": true,
                "label": "Foreground",
                "messageKey": "TIME_COLOR",
                "defaultValue": "FFFFFF"
            }
        ]
    },
    {
        "type": "section",
        "items": [
            {
                "type": "heading",
                "defaultValue": "Features"
            },
            {
                "type": "toggle",
                "label": "Vibrate on Bluetooth disconnect",
                "messageKey": "VIBRATE_ON_DISCONNECT",
                "defaultValue": false
            },
            {
                "type": "text",
                "defaultValue": "Will NOT vibrate during Quiet Time or if health monitoring detects sleeping."
            }
        ]
    },
    {
        "type": "submit",
        "defaultValue": "Save"
    }
];

module.exports = [
    {
        "type": "heading",
        "defaultValue": "Preferences" ,
        "size": 3
    },
    {
        "type": "section",
        "items": [
            {
                "type": "heading",
                "defaultValue": "Colors"
            },
            {
                "type": "text",
                "defaultValue": "Only available on compatible platforms."
            },
            {
                "type": "color",
                "allowGray": true,
                "label": "Background",
                "messageKey": "BACKGROUND_COLOR",
                "defaultValue": "000000"
            },
            {
                "type": "color",
                "allowGray": false,
                "label": "Foreground",
                "messageKey": "TIME_COLOR",
                "defaultValue": "FFFFFF"
            }
        ]
    },
    {
        "type": "section",
        "items": [
            {
                "type": "heading",
                "defaultValue": "Features"
            },
            {
                "type": "toggle",
                "label": "Vibrate on Bluetooth disconnect",
                "messageKey": "VIBRATE_ON_DISCONNECT",
                "defaultValue": false
            },
            {
                "type": "text",
                "defaultValue": "Will NOT vibrate during Quiet Time or if health monitoring detects sleeping."
            }
        ]
    },
    {
        "type": "submit",
        "defaultValue": "Save"
    }
];

Disable gray for foreground on BW devices


'use strict';

/**

GCM helper
----------

Usage:
let push = require('./helpers/push')('/messages');
push.send('create', message);

*/

let gcm = require('node-gcm');
let config = rootRequire('config/config');
let log = require('./logger');

module.exports = function (topic) {

  return {
    send: (action, doc) => {
      let message = new gcm.Message({action, data: {document: doc}});
      let sender = new gcm.Sender(config.gcm.apiKey);
      sender.send(message, {topic: `/topics${topic}`}, 10, (err, result) => {
        if (err) {
          log.error(`[GCM error]`);
          log.error(err);
        } else {
          log.info(`[GCM result]`);
          log.info(result);
        }
      });
    }
  };

};

'use strict';

/**

GCM helper
----------

Usage:
let push = require('./helpers/push')('/messages');
push.send('create', message);

*/

let gcm = require('node-gcm');
let config = rootRequire('config/config');
let log = require('./logger');

module.exports = function (topic) {

  return {
    send: (action, doc) => {
      let message = new gcm.Message({
        data: {
          action,
          document: doc
        }
      });
      let sender = new gcm.Sender(config.gcm.apiKey);
      sender.send(message, {topic: `/topics${topic}`}, 10, (err, result) => {
        if (err) {
          log.error(`[GCM error]`);
          log.error(err);
        } else {
          log.info(`[GCM result]`);
          log.info(result);
        }
      });
    }
  };

};

Move "action" field into "data" field


// @flow
import type { State } from 'types/store.types';

import { connect } from 'react-redux';
import { bindActionCreators } from 'redux';
import Dashboard from 'components/dashboard';
import { updateApp, setPristineCacheTooltip } from 'redux-modules/app';
import { createReport } from 'redux-modules/reports';
import { isOutdated } from 'helpers/date';
import { setAreasRefreshing, updateSelectedIndex } from 'redux-modules/areas';
import withSuccessNotification from 'components/toast-notification/with-notifications';

function mapStateToProps(state: State) {
  return {
    refreshing: state.areas.refreshing,
    isConnected: state.offline.online,
    areasOutdated: isOutdated(state.areas.syncDate),
    appSyncing: (state.areas.syncing || state.layers.syncing || state.alerts.queue.length > 0),
    pristine: state.app.pristineCacheTooltip
  };
}

function mapDispatchToProps(dispatch: *) {
  return bindActionCreators({
    updateApp,
    createReport,
    setAreasRefreshing,
    setPristine: setPristineCacheTooltip,
    updateSelectedIndex
  }, dispatch);
}

export default connect(
  mapStateToProps,
  mapDispatchToProps
)(withSuccessNotification(Dashboard));

// @flow
import type { State } from 'types/store.types';

import { connect } from 'react-redux';
import { bindActionCreators } from 'redux';
import Dashboard from 'components/dashboard';
import { updateApp, setPristineCacheTooltip } from 'redux-modules/app';
import { createReport } from 'redux-modules/reports';
import { isOutdated } from 'helpers/date';
import { setAreasRefreshing, updateSelectedIndex } from 'redux-modules/areas';
import withSuccessNotification from 'components/toast-notification/with-notifications';

function mapStateToProps(state: State) {
  return {
    refreshing: state.areas.refreshing,
    isConnected: state.offline.online,
    areasOutdated: !state.areas.synced || isOutdated(state.areas.syncDate),
    appSyncing: (state.areas.syncing || state.layers.syncing || state.alerts.queue.length > 0),
    pristine: state.app.pristineCacheTooltip
  };
}

function mapDispatchToProps(dispatch: *) {
  return bindActionCreators({
    updateApp,
    createReport,
    setAreasRefreshing,
    setPristine: setPristineCacheTooltip,
    updateSelectedIndex
  }, dispatch);
}

export default connect(
  mapStateToProps,
  mapDispatchToProps
)(withSuccessNotification(Dashboard));

Mark areas outdated when no synced


/* globals najax */

var nodeAjax = function(options) {
  najax(options);
};

export default {
  name: 'ajax-service',

  initialize: function(application) {
    application.register('ajax:node', nodeAjax, { instantiate: false });
    application.inject('adapter', '_ajaxRequest', 'ajax:node');
  }
};

/* globals najax */
import Ember from 'ember';

const { get } = Ember;

var nodeAjax = function(options) {
  let httpRegex = /^https?:\/\//

  if (!httpRegex.test(options.url)) {
    try {
      options.url = get(this, 'fastboot.host') + options.url
    } catch (fbError) {
      throw new Error('You are using Ember Data with no host defined in your adapter. This will attempt to use the host of the FastBoot request, which is not configured for the current host of this request. Please set the hostWhitelist property for in your environment.js. FastBoot Error: ' + fbError.message);
    }
  }

  najax(options);
};

export default {
  name: 'ajax-service',

  initialize: function(application) {
    application.register('ajax:node', nodeAjax, { instantiate: false });
    application.inject('adapter', '_ajaxRequest', 'ajax:node');
    application.inject('adapter', 'fastboot', 'service:fastboot');
  }
};

Allow ember-data to work when `host` is not defined


const knex = require('../../../knex').web
const orgUnitFinder = require('../helpers/org-unit-finder')
const ORGANISATION_UNIT = require('../../constants/organisation-unit')

module.exports = function (id, type) {
  var orgUnit = orgUnitFinder('name', type)
  var table = orgUnit.caseloadView

  var selectList = [
    'link_id AS linkId',
    'grade_code AS grade',
    'total_cases AS totalCases',
    'location AS caseType',
    'untiered',
    'd2',
    'd1',
    'c2',
    'c1',
    'b2',
    'b1',
    'a'
  ]

  var requiresWorkloadOwnerName = (type === ORGANISATION_UNIT.TEAM.name)

  if (requiresWorkloadOwnerName) {
    selectList.push('CONCAT(forename, \' \', surname) AS name')
  } else {
    selectList.push('name')
  }

  var whereString = ''

  if (id !== undefined && (!isNaN(parseInt(id, 10)))) {
    whereString += ' WHERE id = ' + id
  }

  var noExpandHint = ' WITH (NOEXPAND)'

  return knex.schema.raw('SELECT ' + selectList.join(', ') +
      ' FROM ' + table +
      noExpandHint +
      whereString)
}

const knex = require('../../../knex').web
const orgUnitFinder = require('../helpers/org-unit-finder')
const ORGANISATION_UNIT = require('../../constants/organisation-unit')

module.exports = function (id, type) {
  var orgUnit = orgUnitFinder('name', type)
  var table = orgUnit.caseloadView

  var selectList = [
    'link_id AS linkId',
    'grade_code AS grade',
    'total_cases AS totalCases',
    'location AS caseType',
    'untiered',
    'd2',
    'd1',
    'c2',
    'c1',
    'b2',
    'b1',
    'a'
  ]

  var requiresWorkloadOwnerName = (type === ORGANISATION_UNIT.TEAM.name)

  var whereString = ''

  if (requiresWorkloadOwnerName) {
    selectList.push('CONCAT(forename, \' \', surname) AS name')
  } else {
    selectList.push('name')
  }

  var displayAllRecords = (type === ORGANISATION_UNIT.NATIONAL.name)

  if (!displayAllRecords) {
    if (id !== undefined && (!isNaN(parseInt(id, 10)))) {
      whereString += ' WHERE id = ' + id
    }
  }

  var noExpandHint = ' WITH (NOEXPAND)'

  return knex.schema.raw('SELECT ' + selectList.join(', ') +
      ' FROM ' + table +
      noExpandHint +
      whereString)
}

Fix national caseload screen, ensure ID isn't used in query


$(function() {
  // Change 'title' to something else first
  $('tr[title]').each(function() {
    $(this).attr('xtitle', $(this).attr('title')).removeAttr('title');
  })
    .children().children(':input')
      // Set up event handlers
      .bt({trigger: ['helperon', 'helperoff'],
             titleSelector: "parent().parent().attr('xtitle')",
             killTitle: false,
             fill: 'rgba(135, 206, 250, .9)',
             positions: ['bottom', 'top', 'right'],
          })
      .bind('focus', function() {
                $(this).trigger('helperon');
              })
      .bind('blur', function() {
                $(this).trigger('helperoff');
              })
    .parent()
      .bind('mouseover', function() {
                $(this).children(':input').trigger('helperon');
              })
      .bind('mouseleave', function() {
                $(this).children(':input').trigger('helperoff');
              });
});

Make tooltips work when tabbing


module.exports = (sequelize, Sequelize) => {
  const Like = sequelize.define('likes', {
    id: {
      type: Sequelize.INTEGER,
      primaryKey: true,
      allowNull: false,
      autoIncrement: true
    },
    like: {
      type: Sequelize.BOOLEAN,
      defaultValue: false
    }
  });

  return Like;

};

//find user id and find like where user id is equal to user id

module.exports = (sequelize, Sequelize) => {
  const Like = sequelize.define('likes', {
    id: {
      type: Sequelize.INTEGER,
      primaryKey: true,
      allowNull: false,
      autoIncrement: true
    },
    like: {
      type: Sequelize.BOOLEAN,
      defaultValue: true
    }
  });

  return Like;

};

Set default value to true


(function(){
  'use strict';

  if (document.readyState === 'complete') {
    startCollect();
  } else {
    window.addEventListener('load', startCollect);
  }

  function startCollect() {
    const timing = performance.getEntriesByType('navigation')[0].toJSON();
    timing.start = performance.timing.requestStart;
    if (timing.duration > 0) {
      // fetchStart sometimes negative in FF, make an adjustment based on fetchStart
      var adjustment = timing.fetchStart < 0 ? -timing.fetchStart : 0;
      ['domainLookupStart',
        'domainLookupEnd',
        'connectStart',
        'connectEnd',
        'requestStart',
        'responseStart',
        'responseEnd',
        'domComplete',
        'domInteractive',
        'domContentLoadedEventStart',
        'domContentLoadedEventEnd',
        'loadEventStart',
        'loadEventEnd',
        'duration'
      ].forEach(i => {
        timing[i] +=adjustment;
      });

      // we have only 4 chars in our disposal including decimal point
      var time = (timing.duration / 1000).toFixed(2);
      browser.runtime.sendMessage({time: time, timing: timing});
    } else {
      setTimeout(startCollect, 100);
    }
  }
})();

(function(){
  'use strict';

  if (document.readyState === 'complete') {
    startCollect();
  } else {
    window.addEventListener('load', startCollect);
  }

  function startCollect() {
    const timing = performance.getEntriesByType('navigation')[0].toJSON();
    timing.start = performance.timing.requestStart;
    delete timing.serverTiming;
    if (timing.duration > 0) {
      // fetchStart sometimes negative in FF, make an adjustment based on fetchStart
      var adjustment = timing.fetchStart < 0 ? -timing.fetchStart : 0;
      ['domainLookupStart',
        'domainLookupEnd',
        'connectStart',
        'connectEnd',
        'requestStart',
        'responseStart',
        'responseEnd',
        'domComplete',
        'domInteractive',
        'domContentLoadedEventStart',
        'domContentLoadedEventEnd',
        'loadEventStart',
        'loadEventEnd',
        'duration'
      ].forEach(i => {
        timing[i] +=adjustment;
      });

      // we have only 4 chars in our disposal including decimal point
      var time = (timing.duration / 1000).toFixed(2);
      var promise = browser.runtime.sendMessage({time: time, timing: timing});
      promise.catch((reason) => console.log(reason));
    } else {
      setTimeout(startCollect, 100);
    }
  }
})();

Make it work with pages which use `serverTiming`


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

module.exports = (function () {

	var radius = 40;

	var o = function (graph) {
		RoundNode.apply(this, arguments);

		var that = this,
			superHoverHighlightingFunction = this.setHoverHighlighting,
			superPostDrawActions = this.postDrawActions;

		this.radius(radius);

		this.setHoverHighlighting = function (enable) {
			superHoverHighlightingFunction(enable);

			// Highlight connected links when hovering the set operator
			d3.selectAll(".link ." + that.cssClassOfNode()).classed("hovered", enable);
		};

		this.postDrawActions = function () {
			superPostDrawActions();

			that.textBlock().clear();
			that.textBlock().addInstanceCount(that.individuals().length);
			that.textBlock().setTranslation(0, that.radius() - 15);
		};
	};
	o.prototype = Object.create(RoundNode.prototype);
	o.prototype.constructor = o;

	return o;
}());

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

module.exports = (function () {

	var radius = 40;

	var o = function (graph) {
		RoundNode.apply(this, arguments);

		var that = this,
			superHoverHighlightingFunction = this.setHoverHighlighting,
			superPostDrawActions = this.postDrawActions;

		this.radius(radius);

		this.setHoverHighlighting = function (enable) {
			superHoverHighlightingFunction(enable);

			// Highlight connected links when hovering the set operator
			d3.selectAll(".link ." + that.cssClassOfNode()).classed("hovered", enable);
		};

		this.postDrawActions = function () {
			superPostDrawActions();

			that.textBlock().clear();
			that.textBlock().addInstanceCount(that.individuals().length);
			that.textBlock().setTranslation(0, 10);
		};
	};
	o.prototype = Object.create(RoundNode.prototype);
	o.prototype.constructor = o;

	return o;
}());

Move instance count closer to set operator symbol


(function () {

  'use strict';

  angular.module('drmc.directives').directive('arDigitalObjectViewerSidebar', function (SETTINGS, InformationObjectService, ModalDigitalObjectViewerService) {

    return {
      restrict: 'E',
      templateUrl: SETTINGS.viewsPath + '/partials/digital-object-viewer-sidebar.html',
      scope: {
        file: '=',
        _close: '&onClose'
      },
      replace: true,
      link: function (scope) {

        scope.showAipsArea = true;
        scope.showCharacterizationArea = true;
        scope.showMediaArea = false;

        scope.$watch('file', function (value) {
          InformationObjectService.getMets(value.id).then(function (response) {
            scope.mets = response.data;
          });
          if (angular.isDefined(value.media_type_id)) {
            var mt = ModalDigitalObjectViewerService.mediaTypes[value.media_type_id];
            if (angular.isDefined(mt) && angular.isDefined(mt.class)) {
              scope.mediaType = ModalDigitalObjectViewerService.mediaTypes[value.media_type_id].class;
            }
          }
        });

        scope.close = function () {
          scope._close();
        };

      }
    };

  });

})();

(function () {

  'use strict';

  angular.module('drmc.directives').directive('arDigitalObjectViewerSidebar', function (SETTINGS, InformationObjectService, ModalDigitalObjectViewerService) {

    return {
      restrict: 'E',
      templateUrl: SETTINGS.viewsPath + '/partials/digital-object-viewer-sidebar.html',
      scope: {
        file: '=',
        _close: '&onClose'
      },
      replace: true,
      link: function (scope) {

        scope.showAipsArea = true;
        scope.showCharacterizationArea = true;
        scope.showMediaArea = false;

        scope.$watch('file', function (value) {
          InformationObjectService.getMets(value.id).then(function (response) {
            scope.mets = response.data;
          }, function () {
            scope.mets = [];
          });
          if (angular.isDefined(value.media_type_id)) {
            var mt = ModalDigitalObjectViewerService.mediaTypes[value.media_type_id];
            if (angular.isDefined(mt) && angular.isDefined(mt.class)) {
              scope.mediaType = ModalDigitalObjectViewerService.mediaTypes[value.media_type_id].class;
            }
          }
        });

        scope.close = function () {
          scope._close();
        };

      }
    };

  });

})();

Clean DO sidebar METS data on failure


'use strict';
const Generator = require('yeoman-generator');

class ComponentGeneratorWrapper extends Generator {

  constructor(args, opts) {
    super(args, opts);
    this.argument('name', { type: String, required: true });
  }

  writing() {
    this.composeWith(
      'generator-react-webpack/generators/component',
      { options: this.options, arguments: this.arguments },
      { local: require.resolve('generator-react-webpack') }
    );
  }
};

module.exports = ComponentGeneratorWrapper;

'use strict';
const ReactWebpackGenerator = require('generator-react-webpack/generators/component');

class ComponentGenerator extends ReactWebpackGenerator {

  writing() {
    this.composeWith(
      'react-webpack',
      { options: this.options, arguments: this.arguments },
      { local: require.resolve('generator-react-webpack/generators/component') }
    );
  }

};

module.exports = ComponentGenerator;

Extend the component generator of the base generator


import debugLib from 'debug';

const BASE_SCOPE = 'cornerstoneTools';
const baseLogger = debugLib(BASE_SCOPE);

// TODO: Have webpack set this appropriately
const devMode = true;

/**
 * @method debug
 * Create's a scoped debuging logger
 */

export const getLogger = scope => {
  const log = baseLogger.extend(scope);

  return {
    log,
    // eslint-disable-next-line no-console
    warn: devMode ? console.warn.bind(console) : log,
    // eslint-disable-next-line no-console
    error: console.error.bind(console),
  };
};

/**
 * @method enable
 * @returns {void}
 */
export const enable = () => debugLib.enable(BASE_SCOPE);

/**
 * @method disable
 * @returns {void}
 */
export const disable = () => debugLib.disable(BASE_SCOPE);

import debugLib from 'debug';

const BASE_SCOPE = 'cornerstoneTools';
const baseLogger = debugLib(BASE_SCOPE);

// TODO: Have webpack set this appropriately
const devMode = true;

/**
 * @method debug
 * Create's a scoped debuging logger
 */

export const getLogger = scope => {
  const log = baseLogger.extend(scope);

  return {
    log,
    // eslint-disable-next-line no-console
    warn: devMode ? console.warn.bind(console) : log,
    // eslint-disable-next-line no-console
    error: console.error.bind(console),
  };
};

/**
 * @method enable
 * @param {string} scope
 * @returns {void}
 */
export const enable = scope => debugLib.enable(scope || BASE_SCOPE);

/**
 * @method disable
 * @param {string} scope
 * @returns {void}
 */
export const disable = scope => debugLib.disable(scope || BASE_SCOPE);

Allow passing a scope to enable/disable methods. Defaults to base scope


define(["backbone", "underscore" ], function(Backbone, _) {
    var UserProfile = Backbone.Model.extend({
    	//data attributes
      defaults: {
      	age: null,
      	gender: null,
      	address: null,
      	pricePerSMeter: null,
      	color: null,
      	extras: null,
      },

    	//converters
    	getMinMaxPrice: function(){
    		//setPricePerSMeter();
    		min = pricePerSMeter* 1000 * 0.7;
    		max = pricePerSMeter* 1000 * 1.3;

    		return {min: min, max: max};
    	},

    	setPricePerSMeter: function(){
    		//TODO get from location
    	}
    });

    return UserProfile;
});

define(["backbone", "underscore", "jquery"], function(Backbone, _, $) {
    var UserProfile = Backbone.Model.extend({
    	//data attributes
      defaults: {
      	age: null,
      	gender: null,
      	address: null,
      	pricePerSMeter: null,
      	color: null,
      	extras: null,
      },

      convertAddress: function(){
        var self = this;
        var url = "http://maps.googleapis.com/maps/api/geocode/json?address=" + this.address + "&sensor=false";
        var json = $.getJSON(url, function(json) { return json });

        return json.done(function(response) {
          var location = response.results[0].geometry.location;
          self.point = location.lat + ", " + location.lng;
        });
      },

    	//converters
    	getMinMaxPrice: function(){
    		//setPricePerSMeter();
    		min = pricePerSMeter* 1000 * 0.7;
    		max = pricePerSMeter* 1000 * 1.3;

    		return {min: min, max: max};
    	},

    	setPricePerSMeter: function(){
    		//TODO get from location
    	}
    });

    return UserProfile;
});

Add Adress to lat, lng converter


var mocha = require('mocha');
var chai = require('chai');
var assert = require('chai').assert;
var hello = require('../src/hello');

describe('hello', function() {
  it("Returns a string of hello plus the name that was passed.", function() {
    var output = hello.sayHello("Dave");
    assert.equal(output, "Hello Dave.");
  });
});

var mocha = require('mocha');
var chai = require('chai');
var assert = require('chai').assert;
var hello = require('../src/hello');

describe('hello', function() {
  it("Returns a string of hello plus the name that was passed.", function() {
    var output = hello.sayHello("Dave");
    assert.equal(output, "Hello Johnny.");
  });
});

Add a breaking change to hello_test to show example of Travis failure.


Application.Filters.filter('reviewFilter', function () {
    return function (reviews, status) {
        if (reviews) {
            var arr = [];
            for (var i = 0; i < reviews.length; i++) {
                if (reviews[i].status == status) {
                    arr.push(reviews[i])
                }
            }
            return arr
        }
    };
});

Application.Filters.filter('reviewFilter', function () {
    return function (reviews, status) {
        var matches = [];
        if (!reviews) {
            return matches;
        }

        for (var i = 0; i < reviews.length; i++) {
            if (reviews[i].status == status) {
                matches.push(reviews[i]);
            }
        }
        return matches;
    };
});

Fix up recent filter even though we should remove it.


var cmd = "node " + __dirname + "\\..\\bin\\kudusync";
var ignoredTestsMap = {};

exports.cmd = cmd;
exports.ignoredTestsMap = ignoredTestsMap;

var pathUtil = require("path");

var cmd = "node " + pathUtil.join(__dirname, "..", "bin", "kudusync");
var ignoredTestsMap = {};

exports.cmd = cmd;
exports.ignoredTestsMap = ignoredTestsMap;

Fix test to work on unix.


var trello = require('node-trello');
var t = new trello("appkey", "usertoken");

// Get a list of cards created today
var d = new Date();
d.setHours(0,0,0,0);
t.get("/1/boards/targetboard/actions", { filter: "createCard", since: d.toISOString(), format: "count" }, function(err, data) {
  if(err) throw err;
  console.log("Cards added today: " + data._value);
  //console.log(data.actions[0].data);
  var count = data._value;
  t.get("/1/boards/targetboard/actions", { filter: "updateCard:closed", since: d.toISOString(), format: "count" }, function(err, data) {
    if(err) throw err;
    console.log("Cards archived today: " + data._value);
  });
});

var trello = require('node-trello');
var t = new trello("appkey", "usertoken");

// Get a list of cards created today
var d = new Date();
d.setHours(0,0,0,0);
t.get("/1/boards/targetboard/actions", { filter: "createCard", since: d.toISOString(), format: "count" }, function(err, data) {
  if(err) throw err;
  console.log("Cards added today: " + data._value);
  //console.log(data.actions[0].data);
  var count = data._value;
  t.get("/1/lists/donelist/actions", { filter: "updateCard:closed", since: d.toISOString(), format: "count" }, function(err, data) {
    if(err) throw err;
    console.log("Cards archived today: " + data._value);
  });
});

Test now draws closed cards from rightnow


export default function parse(input) {
  let c = '';
  let i = 0;
  let temp = '';
  let result = {};
  let key = '';
  let value = '';
  while ((c = input[i++]) !== undefined) {
    if (c == ':') {
      key = temp;
      temp = '';
      continue;
    }
    if (c == ';') {
      value = temp;
      temp = '';
      if (key.length && value.length) {
        result[key] = value;
        key = value = '';
        continue;
      }
    }
    if (/\S/.test(c)) {
      temp += c;
    }
  }

  if (key.length && temp.length) {
    result[key] = temp;
  }

  return result;
}

export default function parse(input) {
  let c = '';
  let i = 0;
  let temp = '';
  let result = {};
  let key = '';
  let value = '';
  while ((c = input[i++]) !== undefined) {
    if (c == ':') {
      key = temp;
      temp = '';
      continue;
    }
    if (c == ';') {
      value = temp;
      temp = '';
      if (key.length && value.length) {
        result[key] = value;
      }
      key = value = '';
      continue;
    }
    if (/\S/.test(c)) {
      temp += c;
    }
  }

  if (key.length && temp.length) {
    result[key] = temp;
  }

  return result;
}

Handle empty values for shape commands


if (Meteor.isClient) {

  Accounts.ui.config({
     passwordSignupFields: 'USERNAME_ONLY'
  });

  Template.messages.helpers({
      messages: function() {
          return Messages.find({}, { sort: { time: 1}});
      }
  });

  var scrollPosition = function() {
    $('.messageBox').scrollTop($('.messageBox')[0].scrollHeight);
  };

  Template.input.events = {
    'keydown input#message' : function (event) {
      if (event.which == 13) {
        if (Meteor.user())
          var name = Meteor.user().username;
        else
          var name = 'Anonymous';
        var message = document.getElementById('message');

        if (message.value != '') {
          Messages.insert({
            name: name,
            message: message.value,
            time: Date.now(),
          });

          document.getElementById('message').value = '';
          message.value = '';
          scrollPosition();
        }
      }
    }
  };

$(document).ready(function(){
  scrollPosition();
});

if (Meteor.isServer) {
  Meteor.startup(function () {
    // code to run on server at startup
  });
}
}

if (Meteor.isClient) {

  Template.messages.rendered = function () {
    scrollPosition();
  };

  Accounts.ui.config({
     passwordSignupFields: 'USERNAME_ONLY'
  });

  Template.messages.helpers({
      messages: function() {
          return Messages.find({}, { sort: { time: 1}});
      }
  });

  var scrollPosition = function() {
    $('.messageBox').scrollTop($('.messageBox')[0].scrollHeight);
  };

  Template.input.events = {
    'keydown input#message' : function (event) {
      if (event.which == 13) {
        if (Meteor.user())
          var name = Meteor.user().username;
        else
          var name = 'Anonymous';
        var message = document.getElementById('message');

        if (message.value != '') {
          Messages.insert({
            name: name,
            message: message.value,
            time: Date.now(),
          });

          document.getElementById('message').value = '';
          message.value = '';
          scrollPosition();
        }
      }
    }
  };

$(document).ready(function(){
  scrollPosition();
});

if (Meteor.isServer) {
  Meteor.startup(function () {
    // code to run on server at startup
  });
}
}

Add scrollPosition function call on messages template ready


function getPosts() {
    const req = require.context("../posts", true, /^\.\/.*\.md$/);
    const dirtyFileNames = req.keys();

    return dirtyFileNames.map(f => {
        const spl = f.split('/');
        const filename = spl.slice(-1).pop();
        const category = spl.slice(1)[0];
        const title = filename.split('.md')[0];
        return { filename, category, title }
    })
}

export default getPosts;

import urlSlug from './urlSlug';

function getPosts() {
    const req = require.context("../posts", true, /^\.\/.*\.md$/);
    const dirtyFileNames = req.keys();

    return dirtyFileNames.map(f => {
        const spl = f.split('/');
        const filename = spl.slice(-1).pop();
        const category = spl.slice(1)[0];
        const title = filename.split('.md')[0];
        const slug = urlSlug(title);
        return { filename, category, title, slug }
    })
}

export default getPosts;

Add slug to post object


// Meteor package definition.
Package.describe({
  name: 'aramk:notifications',
  version: '0.2.0',
  summary: 'A notification widget.',
  git: 'https://github.com/aramk/meteor-notifications.git'
});

Package.onUse(function (api) {
  api.versionsFrom('METEOR@0.9.0');
  api.use([
    'coffeescript',
    'underscore',
    'templating',
    'less',
    'reactive-var@1.0.4',
    'tracker@1.0.5',
    'aramk:utility@0.8.6',
    'aldeed:simple-schema@1.3.2',
    'aldeed:collection2@2.3.3'
  ], 'client');
  api.use([
    'semantic:ui-css@2.0.8'
  ], {weak: true});
  api.imply('semantic:ui-css');
  api.export('Notifications', 'client');
  api.addFiles([
    'src/Notifications.coffee',
    'src/notification.html',
    'src/notification.coffee',
    'src/notificationBar.html',
    'src/notificationBar.coffee',
    'src/notificationBar.less'
  ], 'client');
});

// Meteor package definition.
Package.describe({
  name: 'aramk:notifications',
  version: '0.2.0',
  summary: 'A notification widget.',
  git: 'https://github.com/aramk/meteor-notifications.git'
});

Package.onUse(function (api) {
  api.versionsFrom('METEOR@0.9.0');
  api.use([
    'coffeescript',
    'underscore',
    'templating',
    'less',
    'reactive-var@1.0.4',
    'tracker@1.0.5',
    'aramk:utility@0.8.6',
    'aldeed:simple-schema@1.3.2',
    'aldeed:collection2@2.3.3'
  ], 'client');
  api.use([
    'semantic:ui-css@1.11.5'
  ], {weak: true});
  api.imply('semantic:ui-css');
  api.export('Notifications', 'client');
  api.addFiles([
    'src/Notifications.coffee',
    'src/notification.html',
    'src/notification.coffee',
    'src/notificationBar.html',
    'src/notificationBar.coffee',
    'src/notificationBar.less'
  ], 'client');
});

Revert "Updated semantic ui dependency."


'use strict';

const fs = require('fs');
const path = require('path');
const rimraf = require('rimraf');

const root = path.join(__dirname, '../temp');

function filePath(p) {
  return path.join(root, p);
}

try {
  fs.mkdirSync(root);
} catch (e) {
  // do nothing
}

module.exports = {
  createFile(p, initialContent) {
    fs.writeFileSync(filePath(p), initialContent);
  },
  makeDirectory(p) {
    fs.mkdirSync(filePath(p));
  },
  path(p) {
    return path.join(root, p);
  },
  clean() {
    rimraf.sync(path.join(root, '*'));
  },
  previewRegExp(pathname) {
    let basename = path.basename(pathname);
    let regexStr = `^<!DOCTYPE html><html><head><meta charset="UTF-8"><title>${basename}<\/title><style>(.|\n)*<\/style><\/head><body><div id="app"><\/div><script>(.|\n)*<\/script><\/body><\/html>$`;
    return new RegExp(regexStr);
  }
};

'use strict';

const fs = require('fs');
const path = require('path');
const rimraf = require('rimraf');

const root = path.join(__dirname, '../temp');

function filePath(p) {
  return path.join(root, p);
}

const helper = {
  createFile(p, initialContent) {
    fs.writeFileSync(filePath(p), initialContent);
  },
  makeDirectory(p) {
    try {
      fs.mkdirSync(filePath(p));
    } catch (e) {
      if (e.code !== 'EEXIST') {
        throw e;
      }
    }
  },
  path(p) {
    return path.join(root, p);
  },
  createRootDirectory() {
    try {
      fs.mkdirSync(root);
    } catch (e) {
      // do nothing
    }
  },
  clean() {
    rimraf.sync(path.join(root, '*'));
  },
  previewRegExp(pathname) {
    let basename = path.basename(pathname);
    let regexStr = `^<!DOCTYPE html><html><head><meta charset="UTF-8"><title>${basename}<\/title><style>(.|\n)*<\/style><\/head><body><div id="app"><\/div><script>(.|\n)*<\/script><\/body><\/html>$`;
    return new RegExp(regexStr);
  }
};

helper.createRootDirectory();
helper.clean();

module.exports = helper;

Create and clean the test root directory when starting test cases


process.env.BABEL_ENV = 'development';
process.env.NODE_ENV = 'development';

const WebpackServe = require('webpack-serve');
const config = require('../config/webpack.config.dev');

function createDevServer() {
  return WebpackServe({
    config,
    port: 3000,
    quiet: true,
    open: true,
    dev: {
      logLevel: 'silent',
    },
    hot: {
      logLevel: 'silent',
    },
  });
}

createDevServer();

process.env.BABEL_ENV = 'development';
process.env.NODE_ENV = 'development';

const WebpackServe = require('webpack-serve');
const config = require('../config/webpack.config.dev');

function createDevServer() {
  return WebpackServe({
    config,
    host: process.env.HOST || '0.0.0.0',
    port: process.env.PORT || 3000,
    quiet: true,
    open: true,
    dev: {
      logLevel: 'silent',
    },
    hot: {
      logLevel: 'silent',
    },
  });
}

createDevServer();

Use the enviroment ports and host if avaliable


angular
  .module('app', [
  ])
  .controller('ChatBoxController', ['$http', function($http) {
    const chat = this;
    chat.msgs = ['Welcome to Chat Bot!'];

    chat.submitMsg = function() {
      chat.msgs.push(chat.msg);
      $http.post('/users', {
      })
        .then(function(data) {
          console.log('success with post')
        });
    }
  }])
  .directive('chatBox', function() {
    return {
      template: `

        {{msg}}

      <form ng-submit="chatBox.submitMsg()" >
        <input class="user-input" ng-model="chatBox.msg" type="text">
      </form>
      `
    }
  })

angular
  .module('app', [
  ])
  .controller('ChatBoxController', ['services', function(services) {
    const chat = this;
    chat.msgs = ['Welcome to Chat Bot!'];

    chat.submitMsg = function() {
      chat.msgs.push(chat.msg);
      services.postMsg();
    }
  }])
  .service('services', function($http) {
    const services = this;
    services.postMsg = function() {
      $http.post('/users', {})
        .then(function(data) {
          console.log('success with post')
        });
    }
  })
  .directive('chatBox', function() {
    return {
      template: `

        {{msg}}

      <form ng-submit="chatBox.submitMsg()" >
        <input class="user-input" ng-model="chatBox.msg" type="text">
      </form>
      `
    }
  })

Move HTTP POST to service


function setCookie(cname,cvalue,exdays) {
  let d = new Date();
  d.setTime(d.getTime() + (exdays*24*60*60*1000));
  //toGTMString exists
  let expires = "expires=" + d.toGMTString();
  document.cookie = cname + "=" + cvalue + ";" + expires + ";path=/";
}

function getCookie(cname) {
  let name = cname + "=";
  let decodedCookie = decodeURIComponent(document.cookie);
  let ca = decodedCookie.split(';');
  for(let i = 0; i < ca.length; i++) {
    let c = ca[i];
    while (c.charAt(0) === ' ') {
      c = c.substring(1);
    }
    if (c.indexOf(name) === 0) {
      return c.substring(name.length, c.length);
    }
  }
  return "";
}

function checkCookie(value) {
  return (value !== "");
}

function deleteCookie(cname) {
  document.cookie = cname+ "=; expires=Thu, 01 Jan 1970 00:00:00 UTC; path=/;";
}

function setCookie(cname,cvalue,exdays) {
  let d = new Date();
  d.setTime(d.getTime() + (exdays*365*24*60*60*1000));
  //toGTMString exists
  let expires = "expires=" + d.toGMTString();
  document.cookie = cname + "=" + cvalue + ";" + expires + ";path=/";
}

function getCookie(cname) {
  let name = cname + "=";
  let decodedCookie = decodeURIComponent(document.cookie);
  let ca = decodedCookie.split(';');
  for(let i = 0; i < ca.length; i++) {
    let c = ca[i];
    while (c.charAt(0) === ' ') {
      c = c.substring(1);
    }
    if (c.indexOf(name) === 0) {
      return c.substring(name.length, c.length);
    }
  }
  return "";
}

function checkCookie(value) {
  return (value !== "");
}

function deleteCookie(cname) {
  document.cookie = cname+ "=; expires=Thu, 01 Jan 1970 00:00:00 UTC; path=/;";
}

Change cookie expire date to 10 years


"use strict";

/*
 * Configuration for the application
 * @type {
 *      npm: '',           // Absolute path to "node_modules" directory for NPM installed libraries and modules
 *      libraries: {
 *          nodejs: {},    // Node.js included libraries as "alias: name"
 *          npm: {}        // NPM installed libraries as "alias: name"
 *      },
 *      directory: '',     // Absolute path to directory with the application/bundle modules
 *      modules: {
 *          npm: {},       // NPM installed modules with the configuration as "name: config"
 *          directory: {}  // Modules of the directory with the configuration as "name: config"
 *      }
 * }
 */

module.exports = {
    npm: __dirname + '/node_modules/',
    libraries: {},
    directory: __dirname + '/modules/',
    modules: {
        directory: {
            example: {
                // Configuration for the module
            }
        }
    }
};

"use strict";

/*
 * Configuration for the application
 * @type {
 *      npm: '',           // Absolute path to "node_modules" directory for NPM installed libraries and modules
 *      libraries: {
 *          nodejs: {},    // Node.js included libraries as "alias: name"
 *          npm: {}        // NPM installed libraries as "alias: name"
 *      },
 *      directory: '',     // Absolute path to directory with the application/bundle modules
 *      modules: {
 *          npm: {},       // NPM installed modules with the configuration as "name: config"
 *          directory: {}  // Modules of the directory with the configuration as "name: config"
 *      }
 * }
 */

module.exports = {
    npm: __dirname + '/../node_modules/',
    libraries: {},
    directory: __dirname + '/modules/',
    modules: {
        directory: {
            example: {
                // Configuration for the module
            }
        }
    }
};

Correct path for the "node_modules" directory


'use babel'

import Opener from '../opener'

export default class AtomPdfOpener extends Opener {
  open (filePath, texPath, lineNumber, callback) {
    // Opens PDF in a new pane -- requires pdf-view module

    function forwardSync (pdfView) {
      if (pdfView != null && pdfView.forwardSync != null) {
        pdfView.forwardSync(texPath, lineNumber)
      }
    }

    const openPaneItems = atom.workspace.getPaneItems()
    for (const openPaneItem of openPaneItems) {
      // File is already open in another pane
      if (openPaneItem.filePath === filePath) {
        forwardSync(openPaneItem)
        return
      }
    }

    // TODO: Make this configurable?
    atom.workspace.open(filePath, {'split': 'right'}).done(forwardSync)

    // TODO: Check for actual success?
    if (callback) {
      callback(0)
    }
  }
}

'use babel'

import Opener from '../opener'

export default class AtomPdfOpener extends Opener {
  open (filePath, texPath, lineNumber, callback) {
    // Opens PDF in a new pane -- requires pdf-view module

    function forwardSync (pdfView) {
      if (pdfView != null && pdfView.forwardSync != null) {
        pdfView.forwardSync(texPath, lineNumber)
      }
    }

    const openPaneItems = atom.workspace.getPaneItems()
    for (const openPaneItem of openPaneItems) {
      // File is already open in another pane
      if (openPaneItem.filePath === filePath) {
        forwardSync(openPaneItem)
        return
      }
    }

    // TODO: Make this configurable?
    atom.workspace.open(filePath, {'split': 'right'}).then(forwardSync)

    // TODO: Check for actual success?
    if (callback) {
      callback(0)
    }
  }
}

Fix deprecated promise API call


'use strict';

export const AppConfigConstant = {
	debug: true,
	logLevel: 'INFO'
};

'use strict';

export const AppConfigConstant = {
	debug: true,
	logLevel: 'INFO',
	localhost: 'localhost'
};

Use 'localhost' for the server (default)


import path from "path";

import { ENTRY_PATH, OUTPUT_PATH } from "../constants";

import {
  isDevelopment,
  isProduction,
  isReact,
  resolveExternal,
  resolveInternal
} from "../utils";

export default (options, partials) => {
  const ENTRY = options.server ? [
    isReact(options.framework) && "react-hot-loader/patch",
    `webpack-dev-server/client?${options.serverURL}`,
    "webpack/hot/only-dev-server",
    ENTRY_PATH
  ].filter(Boolean) : ENTRY_PATH;

  const OUTPUT_FILENAME = `${isProduction(options.env) ? "[name]-[chunkhash:20]" : "[name]"}.js`;

  return {
    entry: { application: ENTRY },
    output: {
      path: resolveExternal(OUTPUT_PATH),
      publicPath: "/",
      filename: OUTPUT_FILENAME,
      chunkFilename: `chunks/${OUTPUT_FILENAME}`
    },
    resolve: {
      modules: [resolveExternal(ENTRY_PATH), resolveExternal("node_modules"), resolveInternal("node_modules")],
      extensions: ["", ".js", ".jsx", ".ts", ".tsx", ".json", ".css", ".scss"]
    },
    resolveLoader: {
      modules: [resolveExternal("node_modules"), resolveInternal("node_modules")]
    },
    module: { loaders: partials.loadersConfig },
    plugins: partials.pluginsConfig,
    devtool: isDevelopment(options.env) && "cheap-inline-module-source-map"
  };
}

import path from "path";

import { ENTRY_PATH, OUTPUT_PATH } from "../constants";

import {
  isDevelopment,
  isProduction,
  isReact,
  resolveExternal,
  resolveInternal
} from "../utils";

export default (options, partials) => {
  const ENTRY = options.server ? [
    isReact(options.framework) && "react-hot-loader/patch",
    `webpack-dev-server/client?${options.serverURL}`,
    "webpack/hot/only-dev-server",
    ENTRY_PATH
  ].filter(Boolean) : ENTRY_PATH;

  const OUTPUT_FILENAME = `${isProduction(options.env) ? "[name]-[chunkhash:20]" : "[name]"}.js`;

  return {
    entry: { application: ENTRY },
    output: {
      path: resolveExternal(OUTPUT_PATH),
      publicPath: options.server ? `${options.serverURL}/` : "/",
      filename: OUTPUT_FILENAME,
      chunkFilename: `chunks/${OUTPUT_FILENAME}`
    },
    resolve: {
      modules: [resolveExternal(ENTRY_PATH), resolveExternal("node_modules"), resolveInternal("node_modules")],
      extensions: ["", ".js", ".jsx", ".ts", ".tsx", ".json", ".css", ".scss"]
    },
    resolveLoader: {
      modules: [resolveExternal("node_modules"), resolveInternal("node_modules")]
    },
    module: { loaders: partials.loadersConfig },
    plugins: partials.pluginsConfig,
    devtool: isDevelopment(options.env) && "cheap-inline-module-source-map"
  };
}

Fix publicPath for development server


'use strict';

var should = require('should'),
    fs = require('fs'),
    xmlEmitter = require('../../lib/jslint_xml_emitter');

describe('jslint_xml', function () {
    var mockXMLResults;
    var xmlText;

    before(function (done) {
        fs.readFile('./test/jslint_xml/fixtures/mock.xml', function (err, data) {
            if (err) return done(err);
            mockXMLResults = data.toString('utf8');
            done();
        });
    });

    beforeEach(function () {
        var errors = require('./fixtures/errors');

        xmlText = xmlEmitter.getHeader();
        xmlText = xmlText.concat(xmlEmitter.formatContent(errors));
        xmlText = xmlText.concat(xmlEmitter.getFooter());
    });

    it('should transform JSHint results in checkstyle XML', function () {
        xmlText.should.equal(mockXMLResults);
    });
});

'use strict';

var should = require('should'),
    fs = require('fs'),
    xmlEmitter = require('../../lib/jslint_xml_emitter');

describe('jslint_xml', function () {
    var mockXMLResults;
    var xmlText;

    before(function (done) {
        fs.readFile('./test/jslint_xml/fixtures/mock.xml', function (err, data) {
            if (err) return done(err);
            mockXMLResults = data.toString('utf8');
            done();
        });
    });

    beforeEach(function () {
        var errors = require('./fixtures/errors');

        xmlText = xmlEmitter.getHeader();
        xmlText = xmlText.concat(xmlEmitter.formatContent(errors));
        xmlText = xmlText.concat(xmlEmitter.getFooter());
    });

    it('should transform JSHint results in jslint XML', function () {
        xmlText.should.equal(mockXMLResults);
    });
});

Test case rename from checkstyle to jslint


/*global require: false, exports: true, module: false */
var queries = require('./queries'),
    schemas = require('./schemas'),
    core = require('./coreworm')(queries),
    model = require('./model')(core);

module.exports.registerSchema = exports.registerSchema = schemas.registerSchema;
module.exports.clearSchema = exports.clearSchema = schemas.clearSchema;
module.exports.model = exports.model = model;

/*global require: false, exports: true, module: false */
var queries = require('./queries'),
    schemas = require('./schemas'),
    core = require('./coreworm')(queries),
    model = require('./model')(core),
    Connection = require('./connection);

module.exports.registerSchema = exports.registerSchema = schemas.registerSchema;
module.exports.clearSchema = exports.clearSchema = schemas.clearSchema;
module.exports.model = exports.model = model;
module.exports.Connection = exports.Connection = Connection;

Enable the model to be accessible


#!/usr/bin/env node
'use strict';
var program = require('commander'),
    colors = require('colors'),
    pkg = require('./package.json'),
    fs = require('fs');

program
    .version(pkg.version)
    .option('-t, --title [string]', 'specified the title')
    .option('-c, --check', 'check if there are an update')
    .parse(process.argv);

if (typeof program.title == 'undefined') {
    console.log('Please set a title with -t.'.red);
    program.title = 'Photos';
}

if (program.check) {
    require('check-update')({packageName: 'check-update-tester', packageVersion: pkg.version, isCLI: true}, function(err, latestVersion, defaultMessage){
        if(!err){
            console.log(defaultMessage);
        }
    });
}

require('./lib/template')(program.title, function(content){
    var time = Date.now();
    fs.writeFile(process.cwd() + '/' + time + '.html', content, function (err) {
        if (err) {
            console.log('There was an error.'.red);
            process.exit(1);
        }
        console.log(colors.green('Done! Generated in ' + time + '.html'));
    });
});

#!/usr/bin/env node
'use strict';
var program = require('commander'),
    colors = require('colors'),
    pkg = require('./package.json'),
    fs = require('fs');

program
    .version(pkg.version)
    .option('-t, --title [string]', 'specified the title')
    .option('-c, --check', 'check if there are an update')
    .parse(process.argv);

if (typeof program.title == 'undefined') {
    console.log('Please set a title with -t.'.red);
    program.title = 'Photos';
}

if (program.check) {
    require('check-update')({packageName: pkg.name, packageVersion: pkg.version, isCLI: true}, function(err, latestVersion, defaultMessage){
        if(!err){
            console.log(defaultMessage);
        }
    });
}

require('./lib/template')(program.title, function(content){
    var time = Date.now();
    fs.writeFile(process.cwd() + '/' + time + '.html', content, function (err) {
        if (err) {
            console.log('There was an error.'.red);
            process.exit(1);
        }
        console.log(colors.green('Done! Generated in ' + time + '.html'));
    });
});

Fix a bug in updater config


import React, { PropTypes } from 'react';

export default class MapLayersPicker extends React.Component {

	static propTypes = {
		title: PropTypes.string,
		layers: PropTypes.array.isRequired,
		onLayerChange: PropTypes.function
	};

	static defaultProps = {
		title: 'Map Layers'
	};

	constructor (props) {
		super(props);
	}

	render () {
		return (

{ this.props.title }

					{ this.props.layers.map(layer => this.renderCheckbox(layer.key, layer.name, layer.checked)) }

		);
	}

	handleChange (key, checked) {
		if (this.props.onLayerChange) {
			this.props.onLayerChange(key, checked);
		}
	}

	renderCheckbox (key, name, checked) {
		return (

				<input
					type="checkbox"
					id={ key }
					onChange={ e => this.handleChange(key, e.target.checked) }
					checked={ checked }
				/>
				{ name }

		);
	}
}

import React, { PropTypes } from 'react';

export default class MapLayersPicker extends React.Component {

	static propTypes = {
		title: PropTypes.string,
		layers: PropTypes.array.isRequired,
		onLayerChange: PropTypes.func
	};

	static defaultProps = {
		title: 'Map Layers'
	};

	constructor (props) {
		super(props);
	}

	render () {
		return (

{ this.props.title }

					{ this.props.layers.map(layer => this.renderCheckbox(layer.key, layer.name, layer.checked)) }

		);
	}

	handleChange (key, checked) {
		if (this.props.onLayerChange) {
			this.props.onLayerChange(key, checked);
		}
	}

	renderCheckbox (key, name, checked) {
		return (

				<input
					type="checkbox"
					id={ key }
					onChange={ e => this.handleChange(key, e.target.checked) }
					checked={ checked }
				/>
				{ name }

		);
	}
}

Correct PropType to shut up React


/*
 * Backpack - Skyscanner's Design System
 *
 * Copyright 2017 Skyscanner Ltd
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

import BpkSpinner from './src/BpkSpinner';
import SPINNER_TYPES from './src/spinnerTypes';
import BpkLargeSpinner from './src/BpkLargeSpinner';
import BpkExtraLargeSpinner from './src/BpkExtraLargeSpinner';
import { themeAttributes } from './src/themeAttributes';

export { BpkSpinner, BpkLargeSpinner, BpkExtraLargeSpinner, SPINNER_TYPES, themeAttributes };

/*
 * Backpack - Skyscanner's Design System
 *
 * Copyright 2017 Skyscanner Ltd
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

import BpkSpinner from './src/BpkSpinner';
import SPINNER_TYPES from './src/spinnerTypes';
import BpkLargeSpinner from './src/BpkLargeSpinner';
import BpkExtraLargeSpinner from './src/BpkExtraLargeSpinner';
import themeAttributes from './src/themeAttributes';

export { BpkSpinner, BpkLargeSpinner, BpkExtraLargeSpinner, SPINNER_TYPES, themeAttributes };

Fix spinner theme attributes export


(function() {
	'use strict';

	angular
		.module('app.matchday')
		.controller('UpdateRankMatchday', UpdateRankMatchday);

	function UpdateRankMatchday(initData, $scope, $rootScope, $modal) {
		$rootScope.$broadcast('state-btn', 'updaterank');
		$rootScope.$broadcast('show-phase-nav', false);

		var vm = this;
		vm.currWeek = null;
		vm.maxWeek =  0;
		vm.currWeek = 0;
		vm.modalInstance = null;

		vm.openModal = openModal;
		vm.closeModal = closeModal;
		vm.doUpdateRank = doUpdateRank;

		activate();
		function activate(){
			vm.maxWeek = initData.matchdayModelView.week.weekNumber;
			vm.maxWeek = parseInt(vm.maxWeek);
			vm.currWeek = vm.maxWeek;
		}

		function doUpdateRank() {
			vm.modalInstance.dismiss('cancel');
		}

		function closeModal() {
			vm.modalInstance.dismiss('cancel');
		}

		function openModal() {
			vm.modalInstance = $modal.open({
				templateUrl: 'editScore.html',
				size: 'sm',
				scope: $scope
			});
		}

	}
})();

(function() {
	'use strict';

	angular
		.module('app.matchday')
		.controller('UpdateRankMatchday', UpdateRankMatchday);

	function UpdateRankMatchday(initData, $scope, $rootScope, $modal) {
		$rootScope.$broadcast('state-btn', 'updaterank');
		$rootScope.$broadcast('show-phase-nav', false);

		var vm = this;
		vm.currWeek = null;
		vm.maxWeek =  0;
		vm.currWeek = 0;
		vm.modalInstance = null;

		vm.openModal = openModal;
		vm.closeModal = closeModal;
		vm.doUpdateRank = doUpdateRank;

		activate();
		function activate(){
			vm.maxWeek = initData.matchdayModelView.week.weekNumber - 1;
			vm.maxWeek = parseInt(vm.maxWeek);
			vm.currWeek = vm.maxWeek;
		}

		function doUpdateRank() {
			vm.modalInstance.dismiss('cancel');
		}

		function closeModal() {
			vm.modalInstance.dismiss('cancel');
		}

		function openModal() {
			vm.modalInstance = $modal.open({
				templateUrl: 'editScore.html',
				size: 'sm',
				scope: $scope
			});
		}

	}
})();

Change the order of the update matchday menu


var jsdom = require("jsdom");
var fs = require('fs');
var path = require('path');
var assert = require('assert');

fs.readdirSync(__dirname).filter(function(file) {
	if (path.extname(file) != ".html") return;
	var str = fs.readFileSync(path.join(__dirname, file)).toString();
	var doc = jsdom.jsdom(str, null, {features: {
		FetchExternalResources   : false,
		ProcessExternalResources : false
	}});
	var win = doc.createWindow();
	win.console = console;
	win.describe = describe;
	win.it = it;
	win.assert = assert;

	Array.prototype.forEach.call(doc.querySelectorAll('script'), function(script) {
		if (script.type == "text/template") return;
		try {
			if (script.textContent) {
				win.run(script.textContent);
			} else if (script.src) {
				win.run(fs.readFileSync(path.join(__dirname, script.src)).toString());
			}
		} catch(e) {
			console.error("Error while trying to execute script sourced by\n" + file);
			process.exit(1);
		}
	});
});

var jsdom = require("jsdom");
var fs = require('fs');
var path = require('path');
var assert = require('assert');

fs.readdirSync(__dirname).filter(function(file) {
	if (path.extname(file) != ".html") return;
	var str = fs.readFileSync(path.join(__dirname, file)).toString();
	var doc = jsdom.jsdom(str, null, {features: {
		FetchExternalResources   : false,
		ProcessExternalResources : false
	}});
	var win = doc.parentWindow;
	win.console = console;
	win.describe = describe;
	win.it = it;
	win.assert = assert;

	Array.prototype.forEach.call(doc.querySelectorAll('script'), function(script) {
		if (script.type == "text/template") return;
		try {
			if (script.textContent) {
				win.run(script.textContent);
			} else if (script.src) {
				win.run(fs.readFileSync(path.join(__dirname, script.src)).toString());
			}
		} catch(e) {
			console.error("Error while trying to execute script sourced by\n" + file);
			process.exit(1);
		}
	});
});

Test with latest jsdom, fix access to window


/*
  Ember can run in many different environments, including environments like
  Node.js where the DOM is unavailable. This object serves as an abstraction
  over the browser features that Ember relies on, so that code does not
  explode when trying to boot in an environment that doesn't have them.

  This is a private abstraction. In the future, we hope that other
  abstractions (like `Location`, `Renderer`, `dom-helper`) can fully abstract
  over the differences in environment.
*/
var environment;

// This code attempts to automatically detect an environment with DOM
// by searching for window and document.createElement. An environment
// with DOM may disable the DOM functionality of Ember explicitly by
// defining a `disableBrowserEnvironment` ENV.
var hasDOM = typeof window !== 'undefined' &&
             typeof document !== 'undefined' &&
             typeof document.createElement === 'function' &&
             !Ember.ENV.disableBrowserEnvironment;

if (hasDOM) {
  environment = {
    hasDOM: true,
    isChrome: !!window.chrome && !window.opera,
    location: window.location,
    history: window.history,
    userAgent: window.navigator.userAgent
  };
} else {
  environment = {
    hasDOM: false,
    isChrome: false,
    location: null,
    history: null,
    userAgent: "Lynx (textmode)"
  };
}

export default environment;

/*
  Ember can run in many different environments, including environments like
  Node.js where the DOM is unavailable. This object serves as an abstraction
  over the browser features that Ember relies on, so that code does not
  explode when trying to boot in an environment that doesn't have them.

  This is a private abstraction. In the future, we hope that other
  abstractions (like `Location`, `Renderer`, `dom-helper`) can fully abstract
  over the differences in environment.
*/
var environment;

// This code attempts to automatically detect an environment with DOM
// by searching for window and document.createElement. An environment
// with DOM may disable the DOM functionality of Ember explicitly by
// defining a `disableBrowserEnvironment` ENV.
var hasDOM = typeof window !== 'undefined' &&
             typeof document !== 'undefined' &&
             typeof document.createElement !== 'undefined' &&
             !Ember.ENV.disableBrowserEnvironment;

if (hasDOM) {
  environment = {
    hasDOM: true,
    isChrome: !!window.chrome && !window.opera,
    location: window.location,
    history: window.history,
    userAgent: window.navigator.userAgent
  };
} else {
  environment = {
    hasDOM: false,
    isChrome: false,
    location: null,
    history: null,
    userAgent: "Lynx (textmode)"
  };
}

export default environment;

Allow IE8 to pass hasDOM check.


angular.module('materialscommons').directive('processSettings', processSettingsDirective);
function processSettingsDirective() {
    return {
        restrict: 'E',
        scope: {
            settings: '=',
            taskId: '=',
            templateId: '=',
            attribute: '='
        },
        controller: ProcessSettingsDirectiveController,
        controllerAs: 'ctrl',
        bindToController: true,
        templateUrl: 'app/project/processes/process/create/components/process-settings.html'
    }
}

/*@ngInject*/
function ProcessSettingsDirectiveController(experimentsService, toast, $stateParams) {
    var ctrl = this;
    ctrl.datePickerOptions = {
        formatYear: 'yy',
        startingDay: 1
    };
    ctrl.openDatePicker = openDatePicker;

    ctrl.updateSettingProperty = (property) => {
        if (!property.value) {
            return;
        }

        property.setup_attribute = ctrl.attribute;
        let propertyArgs = {
            template_id: ctrl.templateId,
            properties: [property]
        };
        experimentsService.updateTaskTemplateProperties($stateParams.project_id, $stateParams.experiment_id, ctrl.taskId, propertyArgs)
            .then(
                () => null,
                () => toast.error('Unable to update property')
            );
    };

    ///////////////////////////////////////

    function openDatePicker($event, prop) {
        $event.preventDefault();
        $event.stopPropagation();
        prop.opened = true;
    }
}

angular.module('materialscommons').directive('processSettings', processSettingsDirective);
function processSettingsDirective() {
    return {
        restrict: 'E',
        scope: {
            settings: '=',
            taskId: '=',
            templateId: '=',
            attribute: '='
        },
        controller: ProcessSettingsDirectiveController,
        controllerAs: 'ctrl',
        bindToController: true,
        templateUrl: 'app/project/processes/process/create/components/process-settings.html'
    }
}

/*@ngInject*/
function ProcessSettingsDirectiveController(experimentsService, toast, $stateParams) {
    var ctrl = this;
    ctrl.datePickerOptions = {
        formatYear: 'yy',
        startingDay: 1
    };
    ctrl.openDatePicker = openDatePicker;

    ctrl.updateSettingProperty = (property) => {
        if (!property.value) {
            return;
        }

        if (property._type === "date") {
            console.dir(property);
            return;
        }

        property.setup_attribute = ctrl.attribute;
        let propertyArgs = {
            template_id: ctrl.templateId,
            properties: [property]
        };
        experimentsService.updateTaskTemplateProperties($stateParams.project_id, $stateParams.experiment_id, ctrl.taskId, propertyArgs)
            .then(
                () => null,
                () => toast.error('Unable to update property')
            );
    };

    ///////////////////////////////////////

    function openDatePicker($event, prop) {
        $event.preventDefault();
        $event.stopPropagation();
        prop.opened = true;
    }
}

Add debug to handle date case (need to test).


import fromPairs from 'lodash.frompairs';

export default class ArrayIndicesProxy {
  constructor(targetArray, handler) {
    const newHandler = fromPairs(Object.entries(handler).map(([name, trap]) => {
      const propertyAccessTraps = ['defineProperty', 'deleteProperty', 'get', 'getOwnPropertyDescriptor', 'has', 'set'];
      if (propertyAccessTraps.includes(name)) {
        return [name, (target, property, ...other) => {
          if (typeof property !== 'symbol') {
            const parsed = parseInt(property, 10);
            const maxArrayLength = 4294967295;
            if (parsed >= 0 && parsed <= maxArrayLength) {
              return trap(target, parsed, ...other);
            }
          }
          return Reflect[name](target, property, ...other);
        }];
      }
      return [name, trap];
    }));
    return new Proxy(targetArray, newHandler);
  }
}

import fromPairs from 'lodash.frompairs';

export default class ArrayIndicesProxy {
  constructor(targetArray, handler) {
    const newHandler = fromPairs(Object.entries(handler).map(([name, trap]) => {
      const propertyAccessTraps = ['defineProperty', 'deleteProperty', 'get', 'getOwnPropertyDescriptor', 'has', 'set'];
      if (propertyAccessTraps.includes(name)) {
        return [name, (target, property, ...other) => {
          if (typeof property !== 'symbol') {
            const parsed = parseInt(property, 10);
            if (parsed >= 0 && parsed <= Number.MAX_VALUE) {
              return trap(target, parsed, ...other);
            }
          }
          return Reflect[name](target, property, ...other);
        }];
      }
      return [name, trap];
    }));
    return new Proxy(targetArray, newHandler);
  }
}

Allow indices greater than standard array length


const {readFileSync} = require('fs')
const {resolve} = require('path')

function createRequestDecorator (stats) {
  return (req, res, next) => {
    res.locals = res.locals || Object.create(null)
    res.locals.webpackClientStats = stats

    next && next()
  }
}

function serveAssets (router, options = {}) {
  if (typeof options === 'string') {
    options = {outputPath: options}
  }

  if (typeof arguments[2] === 'function') {
    options.requestDecorator = arguments[2]
  }

  const {
    hideStats = true,
    outputPath,
    publicPath = '/',
    statsFilename = 'stats.json',
    serveStatic,
    requestDecorator = createRequestDecorator
  } = options

  const statsPath = resolve(outputPath, statsFilename)
  const stats = JSON.parse(readFileSync(statsPath, 'utf8'))

  const decorateRequest = requestDecorator(stats)
  const serve = serveStatic(outputPath)

  if (hideStats) {
    router.use(publicPath + statsFilename, (req, res) => {
      res.status(404)
      res.end()
    })
  }

  router.use(publicPath, serve)
  router.use(decorateRequest)
}

exports = module.exports = serveAssets.bind()
exports.createRequestDecorator = createRequestDecorator
exports.serveAssets = serveAssets

const {readFileSync} = require('fs')
const {resolve} = require('path')

function createRequestDecorator (stats) {
  return (req, res, next) => {
    res.locals = res.locals || Object.create(null)
    res.locals.webpackClientStats = stats

    next && next()
  }
}

function serveAssets (router, options = {}) {
  if (typeof options === 'string') {
    options = {outputPath: options}
  }

  if (typeof arguments[2] === 'function') {
    options.requestDecorator = arguments[2]
  }

  const {
    hideStats = true,
    outputPath,
    publicPath = '/',
    statsFilename = 'stats.json',
    serveStatic,
    requestDecorator = createRequestDecorator
  } = options

  const statsPath = resolve(outputPath, statsFilename)
  const stats = JSON.parse(readFileSync(statsPath, 'utf8'))

  const decorateRequest = requestDecorator(stats)
  const serve = serveStatic(outputPath)

  if (hideStats) {
    router.use(publicPath + statsFilename, (req, res) => {
      res.sendStatus(403)
    })
  }

  router.use(publicPath, serve)
  router.use(decorateRequest)
}

exports = module.exports = serveAssets.bind()
exports.createRequestDecorator = createRequestDecorator
exports.serveAssets = serveAssets

Send http status 403 when stats is hidden


'use strict';

var credentials = exports;
credentials.isNewAPI = true;

var utils = require('common/utils');

credentials.get = function (client, query) {
  return client.get({
    url: '/credentials',
    qs: query || {}
  }, credentials.isNewAPI).then(function (res) {
    return res.body;
  });
};

credentials.create = function (client, data) {
  return client.post({
    url: '/credentials',
    json: {
      id: utils.id('credential'),
      version: 1,
      body: {
        name: data.name,
        project_id: data.project_id,
        org_id: data.org_id,
        pathexp: data.pathexp,
        version: data.version,
        previous: data.previous,
        value: data.value
      }
    }
  }, credentials.isNewAPI).then(function (res) {
    return res.body;
  });
};

'use strict';

var credentials = exports;
credentials.isNewAPI = true;

credentials.get = function (client, query) {
  return client.get({
    url: '/credentials',
    qs: query || {}
  }, credentials.isNewAPI).then(function (res) {
    return res.body;
  });
};

credentials.create = function (client, data) {
  return client.post({
    url: '/credentials',
    json: {
      version: 1,
      body: {
        name: data.name,
        project_id: data.project_id,
        org_id: data.org_id,
        pathexp: data.pathexp,
        version: data.version,
        previous: data.previous,
        value: data.value
      }
    }
  }, credentials.isNewAPI).then(function (res) {
    return res.body;
  });
};

Fix bug preventing a credential from being set


var webpack = require('webpack');
var loaders = require('./webpack.loaders');
var autoprefixer = require('autoprefixer');
var path = require('path');

var outpath = path.join(__dirname, "..", "app")
var node_modules = path.join(outpath, "node_modules")

module.exports = {
	target: "electron",
	entry: {
        app: `./src/client/index.jsx`
	},
	output: {
		path: outpath,
		filename: '[name].bundle.js',
		sourceMapFilename: '[name].bundle.map'
	},
	resolve: {
		extensions: ['', '.js', '.jsx', '.css', '.scss', '.sass', '.json'],
		root: node_modules
	},
	module: {
		loaders: loaders
	},
	plugins: [
		new webpack.ProvidePlugin({
			$: "jquery",
			jQuery: "jquery",
			"window.jQuery": "jquery"
		}),
		new webpack.DefinePlugin({
			'process.env': {
				'NODE_ENV': JSON.stringify('production')
			}
		})
	],
	postcss: function () {
        return [autoprefixer];
    }
};

var webpack = require('webpack');
var loaders = require('./webpack.loaders');
var autoprefixer = require('autoprefixer');
var path = require('path');
var HtmlWebpackPlugin = require('html-webpack-plugin');

var outpath = path.join(__dirname, "..", "app")
var node_modules = path.join(outpath, "node_modules")

module.exports = {
	target: "electron",
	entry: {
        app: `./src/client/index.jsx`
	},
	output: {
		path: outpath,
		filename: '[name].bundle.js',
		sourceMapFilename: '[name].bundle.map'
	},
	resolve: {
		extensions: ['', '.js', '.jsx', '.css', '.scss', '.sass', '.json'],
		root: node_modules
	},
	module: {
		loaders: loaders
	},
	plugins: [
		new webpack.ProvidePlugin({
			$: "jquery",
			jQuery: "jquery",
			"window.jQuery": "jquery"
		}),
		new webpack.DefinePlugin({
			'process.env': {
				'NODE_ENV': JSON.stringify('production')
			}
		}),
		new HtmlWebpackPlugin({
            template: path.join(__dirname, '..', 'src', 'index.html')
        })
	],
	postcss: function () {
        return [autoprefixer];
    }
};

Add html plugin to production config


/**
 * Created by root on 9/19/17.
 */
'use strict';

$(document).ready(function () {
    $("#shl-item, #shl-price").addClass('text-center');
    $(".shl-input").addClass('text-center');
    $("#username, #password").addClass('form-control');
    $('#item_name').addClass('form-control').attr('placeholder', 'Item name');
    $('#quantity').addClass('form-control').attr('placeholder', 'Quantity');
    $('#price').addClass('form-control').attr('placeholder', 'Price per quantity');
    $('li.form-error').addClass('text-danger');
});

document.getElementById('username').placeholder = 'Username';
document.getElementById('password').placeholder = 'Password';

/**
 * Created by root on 9/19/17.
 */
'use strict';

$(document).ready(function () {
    $("#shl-item, #shl-price").addClass('text-center');
    $(".shl-input").addClass('text-center');
    $("#username, #password, #email, #password, #confirm, #name").addClass('form-control');
    $('#item_name').addClass('form-control').attr('placeholder', 'Item name');
    $('#quantity').addClass('form-control').attr('placeholder', 'Quantity');
    $('#price').addClass('form-control').attr('placeholder', 'Price per quantity');
    $('#email').addClass('form-control').attr('placeholder', 'Email');
    $('#confirm').addClass('form-control').attr('placeholder', 'Confirm Password');
    $('#name').addClass('form-control').attr('placeholder', 'Shopping list name');
    $('form ul').addClass('list-unstyled');
    $('form ul li').addClass('form-error');
    $('li.form-error').addClass('text-danger');
});

document.getElementById('username').placeholder = 'Username';
document.getElementById('password').placeholder = 'Password';

Update css styling using jquery


const Promise = require('bluebird');
const requireAll = require('require-all');
const policies = requireAll(__dirname+'/../../config/policies/');

function PolicyEngine() {
  this.policiesOrder = [
    'invoice_policy',
    'bridge_policy',
    'user_policy',
    'no_policy'
  ]

  this.policies = [];
  policiesOrder.forEach(function(name) {
    this.policies.push({
      name: name
      policy: policies[name]
    });
  });
}

PolicyEngine.prototype.determinePolicy = function determinePolicy(payment) {
  var match;
  var _this = this;
  return new Promise(function(resolve, reject) {
    var series = []
    var policyMatch;
    _this.policies.ForEach(function(policy) {
      var asyncPolicy = Promise.promisify(policy);
      series.push(function(next) {
        if (policyMatch) {
          return next();
        }
        asyncPolicy.doesApply(payment)
        .then(function() {
          policyMatch = policy;
        })
        .error(next);
      })
    })
    async.series(series, function(error) {
      if (error) {
        return
      } else {
        resolve(policy);
      }
    });
  });
}

module.exports = PolicyEngine;

const Promise = require('bluebird');
const requireAll = require('require-all');
const policies = requireAll(__dirname+'/../../config/policies/');

function PolicyEngine() {
  var _this = this;
  this.policiesOrder = [
    'invoice_policy',
    'bridge_policy',
    'user_policy',
    'no_policy'
  ]

  this.policies = [];
  this.policiesOrder.forEach(function(name) {
    _this.policies.push({
      name: name,
      policy: policies[name]
    });
  });
}

PolicyEngine.prototype.determinePolicy = function determinePolicy(payment) {
  var match;
  var _this = this;
  return new Promise(function(resolve, reject) {
    var series = []
    var policyMatch;
    _this.policies.ForEach(function(policy) {
      var asyncPolicy = Promise.promisify(policy);
      series.push(function(next) {
        if (policyMatch) {
          return next();
        }
        asyncPolicy.doesApply(payment)
        .then(function() {
          policyMatch = policy;
        })
        .error(next);
      })
    })
    async.series(series, function(error) {
      if (error) {
        return
      } else {
        resolve(policy);
      }
    });
  });
}

module.exports = PolicyEngine;

Correct scope in policy engine.


const sinon = require('sinon')
const chai = require('chai')
const sinonChai = require('sinon-chai')
const expect = chai.expect
chai.use(sinonChai)

describe('countryMapping', () => {
  const countryMapping = require('../../routes/countryMapping')

  beforeEach(() => {
    this.req = { }
    this.res = { send: sinon.spy(), status: sinon.stub().returns({ send: sinon.spy() })  }
  })

  it('should return configured country mappings', () => {
    countryMapping({ get: sinon.stub().withArgs('ctf.countryMapping').returns('TEST')})(this.req, this.res)

    expect(this.res.send).to.have.been.calledWith('TEST')
  })

  it('should return server error when configuration has no country mappings', () => {
    countryMapping({ get: sinon.stub().withArgs('ctf.countryMapping').returns(null)})(this.req, this.res)

    expect(this.res.status).to.have.been.calledWith(500)
  })

  it('should return server error for default configuration', () => {
    countryMapping()(this.req, this.res)

    expect(this.res.status).to.have.been.calledWith(500)
  })
})

const sinon = require('sinon')
const chai = require('chai')
const sinonChai = require('sinon-chai')
const expect = chai.expect
chai.use(sinonChai)

describe('countryMapping', () => {
  const countryMapping = require('../../routes/countryMapping')

  beforeEach(() => {
    this.req = {}
    this.res = { send: sinon.spy(), status: sinon.stub().returns({ send: sinon.spy() }) }
  })

  it('should return configured country mappings', () => {
    countryMapping({ get: sinon.stub().withArgs('ctf.countryMapping').returns('TEST') })(this.req, this.res)

    expect(this.res.send).to.have.been.calledWith('TEST')
  })

  it('should return server error when configuration has no country mappings', () => {
    countryMapping({ get: sinon.stub().withArgs('ctf.countryMapping').returns(null) })(this.req, this.res)

    expect(this.res.status).to.have.been.calledWith(500)
  })

  it('should return server error for default configuration', () => {
    countryMapping()(this.req, this.res)

    expect(this.res.status).to.have.been.calledWith(500)
  })
})

Fix spacing around curly brackets


app.controller('HomeController', ['$scope', 'stocks', function($scope, stocks) {
	stocks.success(function(data) {
		// if (data.query.count > 0) {
			// $scope.stocks = data.query.results.quote;
		// }

		// Used for no internet access only
		$scope.stocks = data;
		console.log(data);
	});
}]);

app.controller('HomeController', ['$scope', 'stocks', function($scope, stocks) {
	stocks.success(function(data) {
		// if (data.query.count > 0) {
			// $scope.stocks = data.query.results.quote;
		// }

		// Used for no internet access only
		$scope.stocks = data;
	});
}]);

Remove console logging from homecontroller


import React, { PureComponent } from 'react';
import PropTypes from 'prop-types';
import Box from '../box';
import { ButtonGroup } from '../button';
import cx from 'classnames';
import theme from './theme.css';

class Message extends PureComponent {
  render() {
    const { className, children, image, imagePositioning, button, link, ...others } = this.props;

    const classNames = cx(theme['message'], theme[`is-image-${imagePositioning}`], className);
    const hasAction = Boolean(button || link);

    return (
      <Box data-teamleader-ui="message" className={classNames} {...others}>
        {image &&
{image}
}

          {children}
          {hasAction && (
            <ButtonGroup justifyContent={imagePositioning === 'center' ? 'center' : 'flex-end'} marginTop={4}>
              {link}
              {button && React.cloneElement(button, { className: theme['button'] })}
            </ButtonGroup>
          )}

      </Box>
    );
  }
}

Message.propTypes = {
  className: PropTypes.string,
  children: PropTypes.any.isRequired,
  image: PropTypes.element,
  imagePositioning: PropTypes.oneOf(['center', 'left', 'right']),
  button: PropTypes.element,
  link: PropTypes.element,
};

Message.defaultProps = {
  imagePositioning: 'left',
};

export default Message;

import React, { PureComponent } from 'react';
import PropTypes from 'prop-types';
import Box from '../box';
import { ButtonGroup } from '../button';
import cx from 'classnames';
import theme from './theme.css';

class Message extends PureComponent {
  render() {
    const { className, children, image, imagePositioning, button, link, ...others } = this.props;

    const classNames = cx(theme['message'], theme[`is-image-${imagePositioning}`], className);
    const hasAction = Boolean(button || link);

    return (
      <Box data-teamleader-ui="message" className={classNames} {...others}>
        {image &&
{image}
}

          {children}
          {hasAction && (
            <ButtonGroup justifyContent={imagePositioning === 'center' ? 'center' : 'flex-end'} marginTop={4}>
              {link}
              {button}
            </ButtonGroup>
          )}

      </Box>
    );
  }
}

Message.propTypes = {
  className: PropTypes.string,
  children: PropTypes.any.isRequired,
  image: PropTypes.element,
  imagePositioning: PropTypes.oneOf(['center', 'left', 'right']),
  button: PropTypes.element,
  link: PropTypes.element,
};

Message.defaultProps = {
  imagePositioning: 'left',
};

export default Message;

Drop the 'button' class because we don't need it anymore