const pgp = require('pg-promise')()

const dbName = 'vinyl'
const connectionString = process.env.DATABASE_URL || `postgres://localhost:5432/${dbName}`
const db = pgp(connectionString)

const getAlbums = () => {
  return db.query('SELECT * FROM albums')
}

const getAlbumById = (albumId) => {
  return db.one(`
    SELECT * FROM albums
      WHERE id = $1
    `, [albumId])
}

const createUser = (name, email, password) => {
  return db.none(`
    INSERT INTO
      users (name, email, password)
    VALUES
      ($1, $2, $3)
    `, [name, email, password])
}

module.exports = {
  getAlbums,
  getAlbumById,
  createUser,
}

const pgp = require('pg-promise')()

const dbName = 'vinyl'
const connectionString = process.env.DATABASE_URL || `postgres://localhost:5432/${dbName}`
const db = pgp(connectionString)

const getAlbums = () => {
  return db.query('SELECT * FROM albums')
}

const getAlbumById = (albumId) => {
  return db.one(`
    SELECT * FROM albums
      WHERE id = $1
    `, [albumId])
}

const getUserByEmail = (email) => {
  return db.one(`
    SELECT * FROM users WHERE email = $1
    `, [email])
    .catch((error) => {
      console.error('\nError in queries.getUserByEmail\n')
      throw error
    })
}

const createUser = (name, email, password) => {
  return db.none(`
    INSERT INTO
      users (name, email, password)
    VALUES
      ($1, $2, $3)
    `, [name, email, password])
}

module.exports = {
  getAlbums,
  getAlbumById,
  createUser,
  getUserByEmail
}

Add query to get user by email


import { get } from '@ember/object';
import { merge } from '@ember/polyfills';

import computeFn from '../utils/helper-compute';
import BaseHelper from './-base';

export default BaseHelper.extend({
  compute: computeFn(function (params, formatHash = {}) {
    this._super(...arguments);

    if (!params || params && params.length > 3) {
      throw new TypeError('ember-moment: Invalid Number of arguments, at most 3');
    }

    const moment = get(this, 'moment');
    const { locale, timeZone } = formatHash;
    const [date, referenceTime, formats] = params;
    const clone = Object.create(formatHash);

    delete clone.locale;
    delete clone.timeZone;

    const mergedFormats = merge(clone, formats);

    return this.morphMoment(moment.moment(date), { locale, timeZone }).calendar(referenceTime, mergedFormats);
  })
});

import { get } from '@ember/object';
import { assign } from '@ember/polyfills';

import computeFn from '../utils/helper-compute';
import BaseHelper from './-base';

export default BaseHelper.extend({
  compute: computeFn(function (params, formatHash = {}) {
    this._super(...arguments);

    if (!params || params && params.length > 3) {
      throw new TypeError('ember-moment: Invalid Number of arguments, at most 3');
    }

    const moment = get(this, 'moment');
    const { locale, timeZone } = formatHash;
    const [date, referenceTime, formats] = params;
    const clone = Object.create(formatHash);

    delete clone.locale;
    delete clone.timeZone;

    const mergedFormats = assign(clone, formats);

    return this.morphMoment(moment.moment(date), { locale, timeZone }).calendar(referenceTime, mergedFormats);
  })
});

Substitute merge() with assign() - Ember deprecation


'use strict'

var ComposrError = require('composr-core').ComposrError
var logger = require('../../utils/composrLogger')
var tokenVerifier = require('corbel-token-verifier')

/**
 * Token Object Middleware
 */
module.exports = function () {
  return function tokenObjectHook (req, res, next) {
    var authHeader = req.header('Authorization') || ''
    var tokenObject = tokenVerifier(authHeader)

    if (authHeader && !tokenObject) {
      logger.debug('[CorbelAuthHook]', 'Malformed user token')
      return next(new ComposrError('error:malformed:token', 'Your token is malformed', 400))
    } else if (!tokenObject) {
      logger.debug('[CorbelAuthHook]', 'Request without token')
    } else {
      logger.debug('[CorbelAuthHook]', 'Request with token')
      req.tokenObject = tokenObject
    }

    return next()
  }
}

'use strict'

var ComposrError = require('composr-core').ComposrError
var logger = require('../../utils/composrLogger')
var tokenVerifier = require('corbel-token-verifier')

/**
 * Token Object Middleware
 */
module.exports = function () {
  return function tokenObjectHook (req, res, next) {
    var authHeader = req.header('Authorization') || ''

    if(!authHeader){
      return next()
    }

    var tokenObject = tokenVerifier(authHeader)

    if (authHeader && !tokenObject) {
      logger.debug('[CorbelAuthHook]', 'Malformed user token')
      return next(new ComposrError('error:malformed:token', 'Your token is malformed', 400))
    } else if (!tokenObject) {
      logger.debug('[CorbelAuthHook]', 'Request without token')
    } else {
      logger.debug('[CorbelAuthHook]', 'Request with token')
      req.tokenObject = tokenObject
    }

    return next()
  }
}

Fix error when auth not present


'use strict';

(function (document, CKEDITOR) {
    document.addEventListener('DOMContentLoaded', function () {
        // RTE
        Array.prototype.forEach.call(document.querySelectorAll('textarea[data-type=rte]'), function (item) {
            const cfg = {
                customConfig: '',
                disableNativeSpellChecker: true,
                extraAllowedContent: 'article section(*)',
                filebrowserBrowseUrl: '/file/browser',
                format_tags: 'p;h1;h2;h3',
                height: '30rem',
                removeButtons: 'Cut,Copy,Paste,Undo,Redo,Anchor,Strike,Indent,Outdent',
                removeDialogTabs: 'link:advanced;link:target',
                stylesSet: false,
                toolbarGroups: [
                    {name: 'document', groups: ['mode', 'document', 'doctools']},
                    {name: 'clipboard', groups: ['clipboard', 'undo']},
                    {name: 'editing', groups: ['find', 'selection', 'spellchecker']},
                    {name: 'forms'},
                    {name: 'basicstyles', groups: ['basicstyles', 'cleanup']},
                    {name: 'paragraph', groups: ['list', 'indent', 'blocks', 'align', 'bidi']},
                    {name: 'links'},
                    {name: 'insert'},
                    {name: 'styles'},
                    {name: 'colors'},
                    {name: 'tools'},
                    {name: 'others'},
                    {name: 'about'}
                ]
            };
            CKEDITOR.replace(item, cfg);
        });
    });
})(document, CKEDITOR);

'use strict';

(function (document, CKEDITOR) {
    document.addEventListener('DOMContentLoaded', function () {
        // RTE
        Array.prototype.forEach.call(document.querySelectorAll('textarea[data-type=rte]'), function (item) {
            const cfg = {
                customConfig: '',
                disableNativeSpellChecker: true,
                extraAllowedContent: 'article section(*)',
                filebrowserBrowseUrl: '/file/browser',
                format_tags: 'p;h1;h2;h3',
                height: '30rem',
                removeButtons: 'Cut,Copy,Paste,Anchor,Strike,Subscript,Superscript,Indent,Outdent',
                removeDialogTabs: 'link:advanced;link:target',
                stylesSet: false,
                toolbarGroups: [
                    {name: 'document', groups: ['mode', 'document', 'doctools']},
                    {name: 'clipboard', groups: ['clipboard', 'undo']},
                    {name: 'editing', groups: ['find', 'selection', 'spellchecker']},
                    {name: 'forms'},
                    {name: 'basicstyles', groups: ['basicstyles', 'cleanup']},
                    {name: 'paragraph', groups: ['list', 'indent', 'blocks', 'align', 'bidi']},
                    {name: 'links'},
                    {name: 'insert'},
                    {name: 'styles'},
                    {name: 'colors'},
                    {name: 'tools'},
                    {name: 'others'},
                    {name: 'about'}
                ]
            };
            CKEDITOR.replace(item, cfg);
        });
    });
})(document, CKEDITOR);

Add undo/redo buttons and remove sub-/superscript buttons


import ApplicationAdapter from 'ghost/adapters/application';

export default ApplicationAdapter.extend({
    find: function (store, type, id) {
        return this.findQuery(store, type, {id: id, status: 'all'});
    },

    findAll: function (store, type, id) {
        return this.query(store, type, {id: id, status: 'all'});
    }
});

import ApplicationAdapter from 'ghost/adapters/application';

export default ApplicationAdapter.extend({
    find: function (store, type, id) {
        return this.findQuery(store, type, {id: id, status: 'all'});
    },

    // TODO: This is needed because the API currently expects you to know the
    // status of the record before retrieving by ID. Quick fix is to always
    // include status=all in the query
    findRecord: function (store, type, id, snapshot) {
        let url = this.buildIncludeURL(store, type.modelName, id, snapshot, 'findRecord');

        url += '&status=all';

        return this.ajax(url, 'GET');
    },

    findAll: function (store, type, id) {
        return this.query(store, type, {id: id, status: 'all'});
    }
});

Fix "revoke invite" feature on /team page


module.exports = {
  sayHelloInEnglish: function() {
    return "HELLO";
  },

  sayHelloInSpanish: function() {
    return "Hola";
  }
};

function clickFunc(){
    document.getElementById('bgimg').style.display = none;
    document.getElementById('lv1').style.display = block;
}

module.exports = {
  sayHelloInEnglish: function() {
    return "HELLO";
  },

  sayHelloInSpanish: function() {
    return "Hola";
  }
};

function clickFunc(){
    document.getElementById('bgimg').style.visibility = none;
    document.getElementById('lv1').style.visibility = block;
}

Revert "change visibility to display"


/**
 * @class CM_FormField_Hidden
 * @extends CM_FormField_Abstract
 */
var CM_FormField_Hidden = CM_FormField_Abstract.extend({
	_class: 'CM_FormField_Hidden'
});

/**
 * @class CM_FormField_Hidden
 * @extends CM_FormField_Abstract
 */
var CM_FormField_Hidden = CM_FormField_Abstract.extend({
	_class: 'CM_FormField_Hidden',

	/**
	 * @return String
	 */
	getValue: function() {
		return this.$('input').val();
	},

	/**
	 * @param {String} value
	 */
	setValue: function(value) {
		this.$('input').val(value);
	}
});

Add value getter/setter for hidden form field


/*!
 * Ladda for jQuery
 * http://lab.hakim.se/ladda
 * MIT licensed
 *
 * Copyright (C) 2015 Hakim El Hattab, http://hakim.se
 */

(function( Ladda, $ ) {
	if ($ === undefined)
		return console.error( 'jQuery required for Ladda.jQuery' );

	var arr = [];

	$ = $.extend( $, {
		ladda: function( arg ) {
			if( arg === 'stopAll' )
				Ladda.stopAll();
		}
	});

	$.fn = $.extend( $.fn, {
		ladda: function( arg ) {
			var args = arr.slice.call( arguments, 1 );

			if( arg === 'bind' ) {
				args.unshift( $( this ).selector );
				Ladda.bind.apply( Ladda, args );
			}
			else {
				$( this ).each( function() {
					var $this = $( this ), ladda;

					if( arg === undefined )
						$this.data( 'ladda', Ladda.create( this ) );
					else {
						ladda = $this.data( 'ladda' );
						ladda[arg].apply( ladda, args );
					}
				});
			}

			return this;
		}
	});
}( this.Ladda, this.jQuery ));

/*!
 * Ladda for jQuery
 * http://lab.hakim.se/ladda
 * MIT licensed
 *
 * Copyright (C) 2015 Hakim El Hattab, http://hakim.se
 */

(function( Ladda, $ ) {
	if ($ === undefined)
		return console.error( 'jQuery required for Ladda.jQuery' );

	var arr = [];

	$ = $.extend( $, {
		ladda: function( arg ) {
			if( arg === 'stopAll' )
				Ladda.stopAll();
		}
	});

	$.fn = $.extend( $.fn, {
		ladda: function( arg ) {
			var args = arr.slice.call( arguments, 1 );

			if( arg === 'bind' ) {
				args.unshift( $( this ).selector );
				Ladda.bind.apply( Ladda, args );
			}
			else if ( arg === 'isLoading' ) {
				var ladda = $(this).data( 'ladda' );
				return ladda.isLoading();
			}
			else {
				$( this ).each( function() {
					var $this = $( this ), ladda;

					if( arg === undefined )
						$this.data( 'ladda', Ladda.create( this ) );
					else {
						ladda = $this.data( 'ladda' );
						ladda[arg].apply( ladda, args );
					}
				});
			}

			return this;
		}
	});
}( this.Ladda, this.jQuery ));

Fix for jQuery version of isLoading()


'use strict'

class EventIndex {
  get() {
    return this._index
  }

  updateIndex(oplog) {
    this._index = oplog.items
  }
}

module.exports = EventIndex

'use strict'

class EventIndex {
  constructor() {
    this._index = []
  }

  get() {
    return this._index
  }

  updateIndex(oplog) {
    this._index = oplog.items
  }
}

module.exports = EventIndex

Make sure there's always an index


CodeMirror.defineMode("roy", function(config, parserConfig) {
  return {
    token: function(stream, state) {
      var token;
      try {
        token = roy.lexer.tokenise(stream.string.slice(stream.pos))[0];
        if(!token[1].length) {
          stream.next();
          return;
        }
        stream.pos += token[1].length;
      } catch(e) {
        stream.next();
        return;
      }

      switch(token[0]) {
      case 'LET':
      case 'IF':
      case 'THEN':
      case 'ELSE':
      case 'DATA':
      case 'TYPE':
      case 'MATCH':
      case 'CASE':
      case 'DO':
      case 'RETURN':
      case 'MACRO':
      case 'WITH':
      case 'WHERE':
          return 'keyword';
      case 'BOOLEAN':
          return 'builtin';
      }
      return token[0].toLowerCase();
    }
  };
});

CodeMirror.defineMode("roy", function(config, parserConfig) {
  return {
    token: function(stream, state) {
      var token, sliced = stream.string.slice(stream.pos);
      try {
        token = roy.lexer.tokenise(sliced)[0];
        if(!token[1].length) {
          stream.next();
          return;
        }
        stream.pos += sliced.match(/\s*/)[0].length + token[1].length;
      } catch(e) {
        stream.next();
        return;
      }

      switch(token[0]) {
      case 'LET':
      case 'IF':
      case 'THEN':
      case 'ELSE':
      case 'DATA':
      case 'TYPE':
      case 'MATCH':
      case 'CASE':
      case 'DO':
      case 'RETURN':
      case 'MACRO':
      case 'WITH':
      case 'WHERE':
          return 'keyword';
      case 'BOOLEAN':
          return 'builtin';
      }
      return token[0].toLowerCase();
    }
  };
});

Fix problem with highlighting tokens after whitespace


/**
 * RequireJS configuration
 * @description Pass in options for RequireJS like paths, shims or the baseUrl
 */
require.config({
	paths: {
		"jquery" : "Libaries/jquery/jquery"
	},
	include: ["Modules/Main"], // Array of entry points which should be included in the optimized final build.

	// Append a date on each requested script to prevent caching issues.
	urlArgs: "bust=" + (new Date()).getDate()
});

/**
 * RequireJS calls
 * @description Call the needed AMD modules.
 */
require(["Modules/Main"], function(MainFn) {
	"use strict";

	new MainFn();
});

/**
 * RequireJS configuration
 * @description Pass in options for RequireJS like paths, shims or the baseUrl
 */
require.config({
	paths: {
		"main" : "Modules/Main"
	},
	include: ["main"], // Array of entry points which should be included in the optimized final build.

	// Append a date on each requested script to prevent caching issues.
	urlArgs: "bust=" + (new Date()).getDate()
});

/**
 * RequireJS calls
 * @description Call the needed AMD modules.
 */
require(["main"], function(MainFn) {
	"use strict";

	new MainFn();
});

Add a path key for the main requireJS module


import { resolve } from 'path';
import { BundleAnalyzerPlugin } from 'webpack-bundle-analyzer';

const config = {
  entry: {
    core: resolve('src', 'core', 'index.js'),
    react: resolve('src', 'react'),
  },

  output: {
    filename: '[name].js',
    path: resolve('dist'),
    library: 'Typewriter',
    libraryTarget: 'umd',
    libraryExport: 'default',
    umdNamedDefine: true,
  },

  externals: {
    react: 'React',
  },

  module: {
    rules: [
      {
        test: /\.js$/,
        exclude: /node_modules/,
        use: {
          loader: 'babel-loader',
          options: {
            presets: [
              [
                '@babel/preset-env',
                {
                  useBuiltIns: 'entry',
                  corejs: 3,
                  targets: {
                    browsers: [
                      'last 2 versions',
                      'ie >= 11',
                    ],
                  },
                },
            ],
              '@babel/preset-react',
            ],
            plugins: [
              '@babel/plugin-proposal-class-properties',
              'babel-plugin-transform-react-remove-prop-types',
            ]
          }
        }
      },
    ]
  },

  plugins: [
    new BundleAnalyzerPlugin()
  ]
};

export default config;

import { resolve } from 'path';
import { BundleAnalyzerPlugin } from 'webpack-bundle-analyzer';

const config = {
  entry: {
    core: resolve('src', 'core', 'index.js'),
    react: resolve('src', 'react'),
  },

  output: {
    filename: '[name].js',
    path: resolve('dist'),
    library: 'Typewriter',
    libraryTarget: 'umd',
    libraryExport: 'default',
    umdNamedDefine: true,
  },

  externals: {
    react: 'react',
    'react-dom': 'react-dom',
  },

  module: {
    rules: [
      {
        test: /\.js$/,
        exclude: /node_modules/,
        use: {
          loader: 'babel-loader',
          options: {
            presets: [
              [
                '@babel/preset-env',
                {
                  useBuiltIns: 'entry',
                  corejs: 3,
                  targets: {
                    browsers: [
                      'last 2 versions',
                      'ie >= 11',
                    ],
                  },
                },
            ],
              '@babel/preset-react',
            ],
            plugins: [
              '@babel/plugin-proposal-class-properties',
              'babel-plugin-transform-react-remove-prop-types',
            ]
          }
        }
      },
    ]
  },

  plugins: [
    new BundleAnalyzerPlugin()
  ]
};

export default config;

Update webpack externals to fix issue with React


import styled from 'styled-components';

const Wrapper = styled.footer`
  display: flex;
  justify-content: space-between;
  padding: 3em 0;
  border-top: 1px solid #666;
`;

export default Wrapper;

import styled from 'styled-components';

const Wrapper = styled.footer`
  display: flex;
  justify-content: space-between;
  padding: 3em 0;
  border-top: 0px solid #666;
`;

export default Wrapper;

Remove 1px black border at bottom


jsgvLoader.siteHandlers = [];

jsgvLoader.addSiteHandler = function(handler){
  this.siteHandlers[handler.length] = handler;
}

jsgvLoader.handleThis = function(){
  var handled = false;
  for (var i = 0; i < jsgvLoader.siteHandlers.length; i++){
    if (jsgvLoader.siteHandlers[i]()) {
      handled = true;
      break;
    }
  }
  if (!handled) {
    function defaultSiteHandler(){
      jsgvLoader.loadCss();
    }
    defaultSiteHandler();
  }
}

jsgvLoader.addOnloadHandler(jsgvLoader.handleThis);

// Directly access location.protocol, location.host, location.pathname
function localhostHandler(){
  if (location.host == 'localhost') {
    if (location.pathname == '/jsgameviewer/examples/load_sgf.html') {
      jsgvLoader.loadSgf();
      return true;
    }
  }
}

jsgvLoader.addSiteHandler(localhostHandler);

jsgvLoader.siteHandlers = [];

jsgvLoader.addSiteHandler = function(handler){
  this.siteHandlers[handler.length] = handler;
}

jsgvLoader.handleThis = function(){
  var handled = false;
  for (var i = 0; i < jsgvLoader.siteHandlers.length; i++){
    if (jsgvLoader.siteHandlers[i]()) {
      handled = true;
      break;
    }
  }
  if (!handled) {
    function defaultSiteHandler(){
      jsgvLoader.loadCss();
    }
    defaultSiteHandler();
  }
}

jsgvLoader.addOnloadHandler(jsgvLoader.handleThis);

// Directly access location.protocol, location.host, location.pathname
function localhostHandler(){
  if (location.host == 'localhost') {
    if (location.pathname == '/jsgameviewer/examples/load_sgf.html') {
      jsgvLoader.loadSgf();
      return true;
    } else if (location.pathname.match(/uploads/)) {
      jsgvLoader.loadGames();
      return true;
    }
  }
}

jsgvLoader.addSiteHandler(localhostHandler);

Integrate with localhost gocool application


// @flow

/*
 * Monkey-patch RN's URL global.
 *
 * A history: get-urls@8 requires normalize-url@2, which uses the new
 * window.URL global object for URL parsing.
 *
 * RN provides a global URL object… but only puts two things into it.
 *
 * The JSDOM project maintains a browser-compatible URL module.
 *
 * Thus, we stick that into the global namespace, and monkey-patch RN's
 * two non-standard methods onto it so as to not break either things that
 * expect web!URL or RN!URL objects.
 */

import {URL, URLSearchParams} from 'whatwg-url'

let RNURL = global.URL;

URL.createObjectURL = RNURL.createObjectURL;
URL.revokeObjectURL = RNURL.revokeObjectURL;

global.URL = URL;
global.URLSearchParams = URLSearchParams;

// @flow

/*
 * Monkey-patch RN's URL global.
 *
 * A history: get-urls@8 requires normalize-url@2, which uses the new
 * window.URL global object for URL parsing.
 *
 * RN provides a global URL object… but only puts two things into it.
 *
 * The JSDOM project maintains a browser-compatible URL module.
 *
 * Thus, we stick that into the global namespace, and monkey-patch RN's
 * two non-standard methods onto it so as to not break either things that
 * expect web!URL or RN!URL objects.
 */

import {URL, URLSearchParams} from 'whatwg-url'

let RNURL = global.URL

URL.createObjectURL = RNURL.createObjectURL
URL.revokeObjectURL = RNURL.revokeObjectURL

global.URL = URL
global.URLSearchParams = URLSearchParams

Fix code that slipped through the cracks


Chart.defaults.global.responsive = true;
var ctx = document.getElementById("showStats").getContext("2d");
var statsChart = new Chart(ctx).Bar(statsData, {});

Chart.defaults.global.responsive = true;
Chart.defaults.global.legend.display =false
var ctx = document.getElementById("showStats").getContext("2d");
var statsChart = new Chart(ctx, {type: 'bar', data: statsData, label: '', scaleStartValue: 0});

Fix chart on shows page, thanks to API changes.


import React from 'react';

const Component = React.createClass({
  render() {
    return
Component
;
  }
});

export default Component;

import React from 'react';

const Component = () =>
Component
;

export default Component;

Fix code for new ESLint rules


'use strict';

const chai = require('chai');
const crypto = require('crypto');
const lzo = require('../index');

const expect = chai.expect;

let data = crypto.randomBytes(Math.floor(Math.random() * 500)),
		compressed;

describe('Compression', () => {
	it('Should throw if nothing is passed', () =>
		expect(() => lzo.compress()).to.throw() );

	it('Should properly compress and not throw', () => {
		expect(() => {
			compressed = lzo.compress(data)
		}).to.not.throw();
	});
});

describe('Decompression', () => {
	it('Should throw if nothing is passed', () =>
		expect(() => lzo.decompress()).to.throw() );

	it('Should properly decompress and not throw', () =>
		expect( data.compare(lzo.decompress(compressed)) ).to.equal(0) );
});

describe('Properties', () => {
	it('Should have property \'version\'', () =>
		expect(lzo).to.have.ownProperty('version') );

	it('Should have property \'versionDate\'', () =>
		expect(lzo).to.have.ownProperty('versionDate') );

	it('Should have property \'errors\' (lzo error codes)', () =>
		expect(lzo).to.have.ownProperty('errors') );
});

'use strict';

const chai = require('chai');
const crypto = require('crypto');
const lzo = require('../index');

const expect = chai.expect;

let data = crypto.randomBytes(100),
		compressed;

describe('Compression', () => {
	it('Should throw if nothing is passed', () =>
		expect(() => lzo.compress()).to.throw() );

	it('Should properly compress and not throw', () => {
		expect(() => {
			compressed = lzo.compress(data)
		}).to.not.throw();
	});
});

describe('Decompression', () => {
	it('Should throw if nothing is passed', () =>
		expect(() => lzo.decompress()).to.throw() );

	it('Should properly decompress and not throw', () =>
		expect( data.compare(lzo.decompress(compressed)) ).to.equal(0) );
});

describe('Properties', () => {
	it('Should have property \'version\'', () =>
		expect(lzo).to.have.ownProperty('version') );

	it('Should have property \'versionDate\'', () =>
		expect(lzo).to.have.ownProperty('versionDate') );

	it('Should have property \'errors\' (lzo error codes)', () =>
		expect(lzo).to.have.ownProperty('errors') );
});

Use a fixed size of 100 bytes for the randomly generated data


class Sidebar {

    constructor() {
        const self = this;
        const doc = $(document);

        doc.on('click', 'a[href][data-open-sidebar]', function (e) {
            e.preventDefault();

            var sidebar = $('#' + $(this).data('open-sidebar')),
                href    = $(this).attr('href');

            self.load(sidebar, href);
        });

        doc.on('click', '.sidebar .cancel-button', function () {
            self.close($(this).closest('.sidebar'));
        });

        return this;
    }

    load(sidebar, url) {
        sidebar.addClass('sidebar--open');

        $.ajax(url)
            .done(response => sidebar.find('.content').html(response))
            .fail(response => {

                // It's possible that laravel forgot the site we were logged into.
                // So when the 'springboard' route returns a 401 unauthorized
                // status code, then we'll redirect to the site selector.
                if (response.status === 401) {
                    window.location.href = config.base_url;
                }
            });
    }

    close(sidebar) {
        sidebar.removeClass('sidebar--open').find('.content').html('');
    }
}

export default Sidebar;

class Sidebar {

    constructor() {
        const self = this;
        const doc = $(document);

        doc.on('click', 'a[href][data-open-sidebar]', function (e) {
            e.preventDefault();

            var sidebar = $('#' + $(this).data('open-sidebar')),
                href    = $(this).attr('href');

            self.load(sidebar, href);
        });

        doc.on('click', '.sidebar .cancel-button', function () {
            self.close($(this).closest('.sidebar'));
        });

        return this;
    }

    load(sidebar, url) {
        sidebar.addClass('sidebar--open');

        return $.ajax(url)
            .done(response => sidebar.find('.content').html(response))
            .fail(response => {

                // It's possible that laravel forgot the site we were logged into.
                // So when the 'springboard' route returns a 401 unauthorized
                // status code, then we'll redirect to the site selector.
                if (response.status === 401) {
                    window.location.href = config.base_url;
                }
            });
    }

    close(sidebar) {
        sidebar.removeClass('sidebar--open').find('.content').html('');
    }
}

export default Sidebar;

Return promise when loading sidebar


var request = require('supertest');
var express = require('express');
var ach = require('../index.js');

describe("using ach", function() {
  describe("with defaults", function() {
    var app = express();

    app.use(ach());
    app.get('/', function(req, res) {
      res.send(200);
    });

    describe('requests with no Origin', function() {
      it('should not receive Access-Control headers', function(done) {
        request(app)
          .get('/')
          .expect(200)
          .end(function(err, res) {
            if (err) throw err;

            Object.keys(res.header).forEach(function(header) {
              if (/^access\-control/.test(header)) {
                throw new Error (
                  header + ' header present for originless request');
              }
            });
            done();
          });
      });
    });

    describe('requests with Origin set', function() {
      it('should receive a wildcard Access-Control-Allow-Origin',
        function(done) {

        request(app)
          .get('/')
          .set('Origin','http://example.com')
          .expect(200)
          .expect('Access-Control-Allow-Origin','*')
          .end(function(err, res) {
            if (err) throw err;
            done();
          });
      });
    });
  });
});

var request = require('supertest');
var express = require('express');
var ach = require('../index.js');

describe("using ach", function() {
  describe("with defaults", function() {
    var app = express();

    app.use(ach());
    app.get('/', function(req, res) {
      res.send(200);
    });

    describe('requests with no Origin', function() {
      it('should not receive Access-Control headers', function(done) {
        request(app)
          .get('/')
          .expect(200)
          .end(function(err, res) {
            if (err) throw err;

            Object.keys(res.header).forEach(function(header) {
              if (/^access\-control/.test(header)) {
                throw new Error (
                  header + ' header present for originless request');
              }
            });
            done();
          });
      });
    });

    describe('requests with Origin set', function() {
      it('should receive a wildcard Access-Control-Allow-Origin',
        function(done) {

        request(app)
          .get('/')
          .set('Origin', 'http://example.com')
          .expect(200)
          .expect('Access-Control-Allow-Origin', '*')
          .end(function(err, res) {
            if (err) throw err;
            done();
          });
      });
    });

    describe('requests with Origin set', function() {
      it('should receive the default Access-Control-Allow-Headers',
        function(done) {

        request(app)
          .get('/')
          .set('Origin', 'http://example.com')
          .expect(200)
          .expect('Access-Control-Allow-Headers', 'X-Requested-With')
          .end(function(err, res) {
            if (err) throw err;
            done();
          });
      });
    });
  });
});

Add test for default allowHeaders


'use strict';

/**
 * @ngdoc directive
 * @name waxeApp.directive:editor
 * @description
 * # editor
 */
angular.module('waxeApp')
    .directive('editor', ['$interval', 'Session', 'FileUtils', function ($interval, Session, FileUtils) {
        return {
            template: '

',
            restrict: 'E',
            scope: {
                'html': '='
            },
            link: function postLink(scope, element) {
                element.append(scope.html);
                var listener = scope.$watch(function(){
                    if(element.text()) {
                        // Remove the watch since the form is fully loaded
                        listener();
                        waxe.form = new waxe.Form(scope.$parent.treeData);
                        Session.form = waxe.form;
                        angular.element(document).on('click', '.btn-external-editor', function() {
                            eval('scope.$parent.' + angular.element(this).attr('ng-click'));
                        });
                    }
                });

                Session.autosave_interval = $interval(function() {
                    if (Session.form && Session.form.filename && Session.form.status === 'updated'){
                        FileUtils.save();
                    }
                }, 1000 * 10);
            }
        };
    }]);

'use strict';

/**
 * @ngdoc directive
 * @name waxeApp.directive:editor
 * @description
 * # editor
 */
angular.module('waxeApp')
    .directive('editor', ['$interval', '$anchorScroll', '$location',  'Session', 'FileUtils', function ($interval, $anchorScroll, $location, Session, FileUtils) {
        return {
            template: '

',
            restrict: 'E',
            scope: {
                'html': '='
            },
            link: function postLink(scope, element) {
                element.append(scope.html);
                var listener = scope.$watch(function(){
                    if(element.text()) {
                        $anchorScroll($location.hash());
                        // Remove the watch since the form is fully loaded
                        listener();
                        waxe.form = new waxe.Form(scope.$parent.treeData);
                        Session.form = waxe.form;
                        angular.element(document).on('click', '.btn-external-editor', function() {
                            eval('scope.$parent.' + angular.element(this).attr('ng-click'));
                        });
                    }
                });

                Session.autosave_interval = $interval(function() {
                    if (Session.form && Session.form.filename && Session.form.status === 'updated'){
                        FileUtils.save();
                    }
                }, 1000 * 10);
            }
        };
    }]);

Make the anchor working when edit a XML file


#!/usr/bin/env node
'use strict'

const fs = require('fs')

const argv = require('yargs')
  .usage('Usage: $0 [<task to run> ...]')
  .example('$0', 'Runs task "default" from file "tasks.js". Will try "tasks.json" if JS file does not exist.')
  .example('$0 build test', 'Runs task "build" and then "test".')
  .help()
  .argv

const taskRunner = require('./index')
const loader = require('./loader')

const tasksToRun = argv._.length > 0 ? argv._ : [ 'default' ]
let taskFile

if (fileExists('tasks.js')) {
  taskFile = 'tasks.js'
} else if (fileExists('tasks.json')) {
  taskFile = 'tasks.json'
} else {
  throw new Error('Neither tasks.js nor tasks.json file found in current working directory.')
}

const tasks = loader.loadTasksFromFile(taskFile)
const filteredTasks = {}

tasksToRun.forEach((taskName) => {
  if (tasks[ taskName ]) {
    filteredTasks[ taskName ] = tasks[ taskName ]
  } else {
    throw new Error(`Task is not defined: ${taskName}`)
  }
})

taskRunner.runTasks(filteredTasks)

function fileExists (filePath) {
  let stat
  try {
    stat = fs.statSync(filePath)
  } catch (error) {
    return false
  }
  return stat.isFile()
}

#!/usr/bin/env node
'use strict'

const fs = require('fs')

const argv = require('yargs')
  .usage('Usage: $0 [<task to run> ...]')
  .example('$0', 'Runs task "default" from file "tasks.js". Will try "tasks.json" if JS file does not exist.')
  .example('$0 build test', 'Runs task "build" and then "test".')
  .help()
  .argv

const taskRunner = require('./index')
const loader = require('./loader')

const tasksToRun = argv._.length > 0 ? argv._ : [ 'default' ]
let taskFile

if (fileExists('tasks.js')) {
  taskFile = 'tasks.js'
} else if (fileExists('tasks.json')) {
  taskFile = 'tasks.json'
} else {
  throw new Error('Neither tasks.js nor tasks.json file found in current working directory.')
}

const tasks = loader.loadTasksFromFile(taskFile)
const filteredTasks = {}

tasksToRun.forEach((taskName) => {
  if (tasks[ taskName ]) {
    filteredTasks[ taskName ] = tasks[ taskName ]
  } else {
    throw new Error(`Task is not defined: ${taskName}`)
  }
})

taskRunner
  .runTasks(filteredTasks)
  .catch((error) => {
    if (error instanceof Error) {
      console.error(error.stack)
    } else {
      console.error(error)
    }
  })

function fileExists (filePath) {
  let stat
  try {
    stat = fs.statSync(filePath)
  } catch (error) {
    return false
  }
  return stat.isFile()
}

Implement basic in-task error handling


export function Cell(index, rowIndex, value) {
  this.index = index;
  this.rowIndex = rowIndex;
  this.value = value;
}

Cell.prototype.id = function() {
  return `${this.rowIndex}${this.index}`;
};

Cell.prototype.clone = function() {
  return new Cell(this.index, this.rowIndex, this.value);
};

export function ComputedCell(index, rowIndex, formula) {
  this.index = index;
  this.rowIndex = rowIndex;
  this.value = 0;
  this.formula = formula;
}

ComputedCell.prototype.clone = function() {
  return new ComputedCell(this.index, this.rowIndex, this.formula);
};

export function Row(index, cells) {
  this.index = index;
  this.cells = cells;
}

Row.prototype.clone = function() {
  return new Row(this.index, this.cells.map(c => c.clone()));
};

Row.prototype.findCell = function(cellIndex) {
  return this.cells.find(cell => cell.index === cellIndex);
};

Row.prototype.replaceCell = function(cellIndex, newCell) {
  for(let i = 0; i < this.cells.length; i++) {
    if(this.cells[i].index === cellIndex) {
      this.cells[i] = newCell;
      break;
    }
  }
};

export class Cell {
  constructor(index, rowIndex, value) {
    this.index = index;
    this.rowIndex = rowIndex;
    this.value = value;
  }

  id() {
    return `${this.rowIndex}${this.index}`;
  }

  clone() {
    return new Cell(this.index, this.rowIndex, this.value);
  }
}

export function ComputedCell(index, rowIndex, formula) {
  this.index = index;
  this.rowIndex = rowIndex;
  this.value = 0;
  this.formula = formula;
}

ComputedCell.prototype.clone = function() {
  return new ComputedCell(this.index, this.rowIndex, this.formula);
};

export function Row(index, cells) {
  this.index = index;
  this.cells = cells;
}

Row.prototype.clone = function() {
  return new Row(this.index, this.cells.map(c => c.clone()));
};

Row.prototype.findCell = function(cellIndex) {
  return this.cells.find(cell => cell.index === cellIndex);
};

Row.prototype.replaceCell = function(cellIndex, newCell) {
  for(let i = 0; i < this.cells.length; i++) {
    if(this.cells[i].index === cellIndex) {
      this.cells[i] = newCell;
      break;
    }
  }
};

Convert Cell to ES6 class syntax


// Copyright (c) 2017 The Regents of the University of Michigan.
// All Rights Reserved. Licensed according to the terms of the Revised
// BSD License. See LICENSE.txt for details.

const log_tree = require("../lib/log_tree");

describe("a log_tree object", function() {
  describe("when created from nothing", function() {
    it("has a length of 0", function() {
      var tree = log_tree();
      expect(tree.length()).toBe(0);
    });
  });

  it("can be created with a name", function() {
    var tree = log_tree("name");
  });
});

// Copyright (c) 2017 The Regents of the University of Michigan.
// All Rights Reserved. Licensed according to the terms of the Revised
// BSD License. See LICENSE.txt for details.

const log_tree = require("../lib/log_tree");

describe("a log_tree object", function() {
  var tree;

  describe("when created from nothing", function() {
    it("has a length of 0", function() {
      tree = log_tree();
      expect(tree.length()).toBe(0);
    });
  });

  it("can be created with a name", function() {
    tree = log_tree("name");
  });
});

Declare tree var in the root description


var spawn = require('child_process').spawn;

function Runner() {
}

Runner.prototype.init = function(bosco, next) {
  this.bosco = bosco;
  next();
};

Runner.prototype.list = function(options, next) {
  var installed = true;
  spawn('docker-compose', ['--version'], { cwd: options.cwd, stdio: 'ignore' })
  .on('error', function() {
    installed = false;
    return next(null, []);
  }).on('exit', function() {
    if (installed) { return next(null, ['docker-compose']); }
  });
};

Runner.prototype.stop = function(options, next) {
  spawn('docker-compose', ['stop'], { cwd: options.cwd, stdio: 'inherit' }).on('exit', next);
};

Runner.prototype.start = function(options, next) {
  spawn('docker-compose', ['up', '-d'], { cwd: options.cwd, stdio: 'inherit' }).on('exit', next);
};

module.exports = new Runner();

var spawn = require('child_process').spawn;
var path = require('path');

function Runner() {
}

Runner.prototype.init = function(bosco, next) {
  this.bosco = bosco;
  next();
};

Runner.prototype.hasConfig = function(cwd) {
  return this.bosco.exists(path.join(cwd, 'docker-compose.yml')) || this.bosco.exists(path.join(cwd, 'docker-compose.yaml'));
};

Runner.prototype.list = function(options, next) {
  var installed = true;
  spawn('docker-compose', ['--version'], { cwd: options.cwd, stdio: 'ignore' })
  .on('error', function() {
    installed = false;
    return next(null, []);
  }).on('exit', function() {
    if (installed) { return next(null, ['docker-compose']); }
  });
};

Runner.prototype.stop = function(options, next) {
  var hasConfigFile = this.hasConfig(options.cwd);
  if (!hasConfigFile) {
    this.bosco.error('Service ' + options.name.cyan + ' claims to be docker-compose but doesnt have a docker-compose.yaml file! Skipping ...');
    return next();
  }
  spawn('docker-compose', ['stop'], { cwd: options.cwd, stdio: 'inherit' }).on('exit', next);
};

Runner.prototype.start = function(options, next) {
  var hasConfigFile = this.hasConfig(options.cwd);
  if (!hasConfigFile) {
    this.bosco.error('Service ' + options.name.cyan + ' claims to be docker-compose but doesnt have a docker-compose.yaml file! Skipping ...');
    return next();
  }
  spawn('docker-compose', ['up', '-d'], { cwd: options.cwd, stdio: 'inherit' }).on('exit', next);
};

module.exports = new Runner();

Make docker-compose runner a little more robust


import { contentsRef, routesRef } from '@/admin/firebase_config/index'
import contentFetch from '@/admin/mixins/contentFetch'
import _ from 'lodash'

export default {
  mixins: [contentFetch],
  firebase: {
    routes: routesRef,
    contents: contentsRef
  },
  computed: {
    content () {
      const params = this.$route.params
      let path = this.$route.path
      if (params) {
        _.forIn(params, (value, key) => {
          path = path.replace(value, ':' + key)
        })
      }
      let currentRoute = this.routes.filter((route) => {
        return route.path === path
      })[0]
      let contentType = currentRoute.contentType
      let contentId = currentRoute.content || (_.has(params, 'id') ? params.id : 'none')
      return this.selectContentByTypeAndId(contentType, contentId)
    }
  }
}

import { contentsRef, routesRef } from '@/admin/firebase_config/index'
import contentFetch from '@/admin/mixins/contentFetch'
import _ from 'lodash'

export default {
  mixins: [contentFetch],
  firebase: {
    routes: routesRef,
    contents: contentsRef
  },
  computed: {
    content () {
      const params = this.$route.params
      let path = this.$route.path
      if (params) {
        _.forIn(params, (value, key) => {
          path = path.replace(value, ':' + key)
        })
      }
      let currentRoute = this.routes.filter((route) => {
        return route.path === path
      })[0]
      let contentType = currentRoute.contentType
      let contentId = currentRoute.content !== 'none' ? currentRoute.content : (_.has(params, 'id') ? params.id : 'none')
      return this.selectContentByTypeAndId(contentType, contentId)
    }
  }
}

Fix condition for fetching content


describe('lib/rules/disallow-computedany', function () {
    var checker = global.checker({
        plugins: ['./lib/index']
    });

    describe('not configured', function() {

      it('should report with undefined', function() {
        global.expect(function() {
          checker.configure({disallowComputedAny: undefined});
        }).to.throws(/requires a true value/i);
      });

      it('should report with an object', function() {
        global.expect(function() {
          checker.configure({disallowComputedAny: {}});
        }).to.throws(/requires a true value/i);
      });

    });

    describe('with true', function() {
      checker.rules({disallowComputedAny: true});

      checker.cases([
        /* jshint ignore:start */
        {
          it: 'should not report Ember.computed.or()',
          code: function() {
            var Hamster = Ember.Object.extend({
              hasClothes: Ember.computed.or('hat', 'shirt')
            });
          }
        }, {
          it: 'should report Ember.computed.any()',
          errors: 1,
          code: function() {
            var Hamster = Ember.Object.extend({
              hasClothes: Ember.computed.any('hat', 'shirt')
            });
          }
        }
        /* jshint ignore:end */
      ]);
    });
});

describe('lib/rules/disallow-computedany', function () {
    var checker = global.checker({
        plugins: ['./lib/index']
    });

    describe('not configured', function() {

      it('should report with undefined', function() {
        global.expect(function() {
          checker.configure({disallowComputedAny: undefined});
        }).to.throws(/requires a true value/i);
      });

      it('should report with an object', function() {
        global.expect(function() {
          checker.configure({disallowComputedAny: {}});
        }).to.throws(/requires a true value/i);
      });

    });

    describe('with true', function() {
      checker.rules({disallowComputedAny: true});

      checker.cases([
        /* jshint ignore:start */
        {
          it: 'should not report Ember.computed.or()',
          code: function() {
            var Hamster = Ember.Object.extend({
              hasClothes: Ember.computed.or('hat', 'shirt')
            });
          }
        }, {
          it: 'should not report Foo.any()',
          code: function() {
            var Hamster = Ember.Object.extend({
              hasClothes: Foo.any('hat', 'shirt')
            });
          }
        }, {
          it: 'should not report Ember.notathing.any()',
          code: function() {
            var Hamster = Ember.Object.extend({
              hasClothes: Ember.notathing.any('hat', 'shirt')
            });
          }
        }, {
          it: 'should report Ember.computed.any()',
          errors: 1,
          code: function() {
            var Hamster = Ember.Object.extend({
              hasClothes: Ember.computed.any('hat', 'shirt')
            });
          }
        }
        /* jshint ignore:end */
      ]);
    });
});

Add 2 more tests to cover cases where parent node isn't `computed`


(function ($) {

  $.fn.spin = function(opts) {
    this.each(function() {
      var $this = $(this),
      data = $this.data();

      if (data.spinner) {
        data.spinner.stop();
        delete data.spinner;
      }
      if (opts !== false) {
        data.spinner = new Spinner($.extend({color: $this.css('color')}, opts)).spin(this);
      }
    });
    return this;
  };

})(jQuery);

(function ($) {

  $.fn.spin = function(opts) {
    this.each(function() {
      var $this = $(this),
      data = $this.data();

      if (data.spinner) {
        data.spinner.stop();
        delete data.spinner;
      }
      if (opts !== false) {
        data.spinner = new Spinner($.extend({color: $this.css('color'), zIndex: 0}, opts)).spin(this);
      }
    });
    return this;
  };

})(jQuery);

Set z-index for spinner to 0


import {
  getAllSentenceFragmentConceptResults
} from './sentenceFragment';
import {
  getConceptResultsForSentenceCombining
} from './sentenceCombining';
import {
  getConceptResultsForFillInTheBlanks
} from './fillInTheBlanks';

export function getConceptResultsForQuestion(question) {
  if (question.type === 'SF') {
    return getAllSentenceFragmentConceptResults(question.data);
  } else if (question.type === 'SC') {
    return getConceptResultsForSentenceCombining(question.data);
  } else if (question.type === 'FB') {
    return getConceptResultsForFillInTheBlanks(question.data);
  }
}

export function getNestedConceptResultsForAllQuestions(questions) {
  return questions.map(question => getConceptResultsForQuestion(question));
}

export function embedQuestionNumbers(nestedConceptResultArray) {
  return nestedConceptResultArray.map((conceptResultArray, index) => conceptResultArray.map((conceptResult) => {
    conceptResult.metadata.questionNumber = index + 1;
    return conceptResult;
  }));
}

export function getConceptResultsForAllQuestions(questions) {
  const nested = getNestedConceptResultsForAllQuestions(questions);
  const withKeys = embedQuestionNumbers(nested);
  return [].concat.apply([], withKeys);
}

import {
  getAllSentenceFragmentConceptResults
} from './sentenceFragment';
import {
  getConceptResultsForSentenceCombining
} from './sentenceCombining';
import {
  getConceptResultsForFillInTheBlanks
} from './fillInTheBlanks';

export function getConceptResultsForQuestion(question) {
  if (question.type === 'SF') {
    return getAllSentenceFragmentConceptResults(question.data);
  } else if (question.type === 'SC') {
    return getConceptResultsForSentenceCombining(question.data);
  } else if (question.type === 'FB') {
    return getConceptResultsForFillInTheBlanks(question.data);
  }
}

export function getNestedConceptResultsForAllQuestions(questions) {
  return questions.filter(qs => qs.type !== 'TL').map(question => getConceptResultsForQuestion(question));
}

export function embedQuestionNumbers(nestedConceptResultArray) {
  return nestedConceptResultArray.map((conceptResultArray, index) => conceptResultArray.map((conceptResult) => {
    conceptResult.metadata.questionNumber = index + 1;
    return conceptResult;
  }));
}

export function getConceptResultsForAllQuestions(questions) {
  const nested = getNestedConceptResultsForAllQuestions(questions);
  const withKeys = embedQuestionNumbers(nested);
  return [].concat.apply([], withKeys);
}

Remove non gradable questions from the array.


/*
 * Copyright (c) 2017, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
 *
 * WSO2 Inc. licenses this file to you 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 React from 'react'

const LifeCycle = (props) => {
    return (
        <h1>
            Life cycle Page
        </h1>
    );
};

export default LifeCycle

/*
 * Copyright (c) 2017, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
 *
 * WSO2 Inc. licenses this file to you 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 React, {Component} from 'react'
import Api from '../../../../data/SingleClient'

class LifeCycle extends Component {
    constructor(props) {
        super(props);
        this.api = new Api();
    }

    render() {
        return (
            <h1>
                Life cycle Page
            </h1>
        );
    }
}

export default LifeCycle

Make lifecycle component a React class component since it requires React-Lifecycle states


// Action Cable provides the framework to deal with WebSockets in Rails.
// You can generate new channels where WebSocket features live using the rails generate channel command.
//
//= require action_cable
//= require_self
//= require_tree ./channels

(function() {
  this.App || (this.App = {});

  App.cable = ActionCable.createConsumer();

}).call(this);

// Action Cable provides the framework to deal with WebSockets in Rails.
// You can generate new channels where WebSocket features live using the rails generate channel command.
//
//= require action_cable
//= require_self
//= require_tree ./channels

(function() {
  this.App || (this.App = {});

  window.App.cable = window.ActionCable.createConsumer();

}).call(this);

Fix `variable is not defined` issue


"use strict";

/**
MIME type definitions consisting of those in `mime-db` plus custom additions and
overrides.

See <https://github.com/jshttp/mime-db> for details on the format.
**/

var db = require('mime-db');

// If you add a new type here, make sure its extensions are also in the
// extension whitelist in ./index.js or RawGit won't proxy requests for that
// type. Please keep definitions in alphabetical order.
db['application/n-triples'] = {
    charset     : 'utf-8',
    compressible: true,
    extensions  : ['nt']
};

db['application/vnd.geo+json'] = {
    charset     : 'utf-8',
    compressible: true,
    extensions  : ['geojson']
};

module.exports = db;

"use strict";

/**
MIME type definitions consisting of those in `mime-db` plus custom additions and
overrides.

See <https://github.com/jshttp/mime-db> for details on the format.
**/

var db = require('mime-db');

// If you add a new type here, make sure its extensions are also in the
// extension whitelist in ./index.js or RawGit won't proxy requests for that
// type. Please keep definitions in alphabetical order.
db['application/n-triples'] = {
    charset     : 'utf-8',
    compressible: true,
    extensions  : ['nt']
};

db['application/vnd.geo+json'] = {
    charset     : 'utf-8',
    compressible: true,
    extensions  : ['geojson']
};

db['text/x-handlebars-template'] = {
    charset     : 'utf-8',
    compressible: true,
    extensions  : ['handlebars', 'hbs']
};

module.exports = db;

Add MIME type mapping for Handlebars files.


/**
 * Implement Gatsby's Node APIs in this file.
 *
 * See: https://www.gatsbyjs.org/docs/node-apis/
 */

// You can delete this file if you're not using it

exports.onCreateWebpackConfig = ({ stage, loaders, actions }) => {
  if (stage === 'build-html') {
    actions.setWebpackConfig({
      module: {
        rules: [
          {
            test: /two.js/,
            use: loaders.null(),
          },
        ],
      },
    })
  }
}

/**
 * Implement Gatsby's Node APIs in this file.
 *
 * See: https://www.gatsbyjs.org/docs/node-apis/
 */

// You can delete this file if you're not using it

const cssLoaderRe = /\/css-loader\//
const targetFile = `.module.css`

const processRule = rule => {
  if (rule.oneOf) {
    return {
      ...rule,
      oneOf: rule.oneOf.map(processRule),
    }
  }

  if (!rule.test.test(targetFile)) {
    return rule
  }

  if (Array.isArray(rule.use)) {
    return {
      ...rule,
      use: rule.use.map(use => {
        if (!cssLoaderRe.test(use.loader)) {
          return use
        }

        // adjust css-loader options
        return {
          ...use,
          options: {
            ...use.options,
            camelCase: false,
          },
        }
      }),
    }
  }

  return rule
}

exports.onCreateWebpackConfig = ({ getConfig, stage, loaders, actions }) => {
  const config = getConfig()

  const newConfig = {
    ...config,
    module: {
      ...config.module,
      rules: config.module.rules.map(processRule),
    },
  }
  actions.replaceWebpackConfig(newConfig)

  if (stage === 'build-html') {
    actions.setWebpackConfig({
      module: {
        rules: [
          {
            test: /two.js/,
            use: loaders.null(),
          },
        ],
      },
    })
  }
}

Allow kebab-cased CSS module selectors


var img;
var smallPoint, largePoint;

function preload() {
    var url = unescape(decodeURIComponent(window.urlParams.screenshot));
    img = loadImage(url);
}

function setup() {

    // figure out the screen dimensions
    var display_width, display_height;
    if ( typeof(window.urlParams) !== "undefined" ) {
        display_width = window.urlParams.width;
        display_height = window.urlParams.height;
    }
    else {
        display_width = screen.width;
        display_height = screen.height;
    }

    createCanvas(display_width, display_height);

    smallPoint = 4;
    largePoint = 20;

    imageMode(CENTER);
    noStroke();
    background(0);

    img.loadPixels();
}

function draw() {
    // original script was interactive and used the mouse position.
    //    let's try it with a random value instead
    //  var pointillize = map(mouseX, 0, width, smallPoint, largePoint);
    var pointillize = random(smallPoint, largePoint);

    var x = floor(random(img.width));
    var y = floor(random(img.height));
    var pix = img.get(x, y);

    fill(pix, 128);
    ellipse(x, y, pointillize, pointillize);
}

var img;
var smallPoint, largePoint;

function preload() {
    var url = unescape(decodeURIComponent(window.urlParams.screenshot));
    img = loadImage(url);
}

function setup() {

    // figure out the screen dimensions
    var display_width, display_height;
    if ( typeof(window.urlParams) !== "undefined" ) {
        display_width = window.urlParams.width;
        display_height = window.urlParams.height;
    }
    else {
        display_width = screen.width;
        display_height = screen.height;
    }

    createCanvas(display_width, display_height);

    smallPoint = 4;
    largePoint = 20;

    imageMode(CENTER);
    noStroke();
    background(0);

    img.loadPixels();
}

function draw() {
    // original script was interactive and used the mouse position.
    //    let's try it with a random value instead
    //  var pointillize = map(mouseX, 0, width, smallPoint, largePoint);
    var pointillize = random(smallPoint, largePoint);

    var x = floor(random(img.width));
    var y = floor(random(img.height));
    var pix = img.get(x, y);

    fill(pix, 128);
    ellipse(
        map(x, 0, img.width, 0, width),
        map(y, 0, img.height, 0, height),
        pointillize, pointillize);
}

Use map to make sure screen/image are in proportion


'use strict'

var test = require('tape')
var isURL = require('../../is/url')

var testCases = [
// ['url',expectedResult]
  ['boom', false],
  ['perdu.com', true],
  ['http://domain.ext/path?query=string', true],
  ['https://boom.com/path?query=string%20with%20spaces', true],
  ['https://boom.com/path?query=string%20with%20spaces#andThis', true]
]

test('isURL', function (t) {
  t.plan(testCases.length)
  testCases.map(function (item) {
    t.equals(isURL(item[0]), item[1])
  })
})

'use strict'

var test = require('tape')
var isURL = require('../../is/url')

var testCases = [
// ['url',expectedResult]
  ['boom', false, 'simple string'],
  ['perdu.com', true, 'domain.ext'],
  ['http://domain.ext/path?query=string', true, 'with query string'],
  ['https://boom.com/path?query=string%20with%20spaces', true, 'with (uri encoded) spaces (%20) in query string'],
  ['https://boom.com/path?query=string%20with%20spaces#andThis', true, 'with hash']
]

test('isURL', function (t) {
  t.plan(testCases.length)
  testCases.map(function (item) {
    t.equals(isURL(item[0]), item[1])
  })
})

Add messages to each assertion


import axios from '@/base/api/axios'
import { camelizeKeys } from '@/utils/utils'

export default {
  async activityHistory ({ group, user, dateAfter, dateBefore }) {
    return (await axios.get(
      '/api/stats/activity-history/',
      { params: camelizeKeys({ group, user, dateAfter, dateBefore }) },
    )).data
  },
}

import axios from '@/base/api/axios'
import { underscorizeKeys } from '@/utils/utils'

export default {
  async activityHistory ({ group, user, dateAfter, dateBefore }) {
    return (await axios.get(
      '/api/stats/activity-history/',
      { params: underscorizeKeys({ group, user, dateAfter, dateBefore }) },
    )).data
  },
}

Fix brain error camelize -> underscoreize


'use strict';

var assign = require('lodash').assign;
var del = require('del');

var defaults = {
  dest: 'dist'
};

module.exports = function (gulp, options) {
  var opts = assign(defaults, options);
  var dest = opts.dest;

  gulp.task('clean', function (done) {
    del(dest).then(done);
  });
};

'use strict';

var assign = require('lodash').assign;
var del = require('del');

var defaults = {
  dest: 'dist'
};

module.exports = function (gulp, options) {
  var opts = assign(defaults, options);
  var dest = opts.dest;

  gulp.task('clean', function (done) {
    del(dest).then(function () {
      done();
    });
  });
};

Fix the way in which the done callback was being fired


define([
  'lib/underscore',
  'lib/backbone',
  'component/grid/projection/base',
], function (_, Backbone, BaseProjection) {
  var Model = BaseProjection.extend({
    name: 'column-hovertext',
    update: function (options) {
      if (Model.__super__.update.call(this, options)) {
        var model = this.src.data;
        var columns = model.get('columns');

        _.each(columns, function(column) {
          _.extend(column, {
            $metadata: {
              'attr.head': {
                title: _.result(column.config, 'hoverText') || _.result(column.config, 'title') || '',
              },
            },
          });
        });

        this.patch({ columns: columns });
      }
    },
  });

  return Model;
});

define([
  'lib/underscore',
  'lib/backbone',
  'component/grid/projection/base',
], function (_, Backbone, BaseProjection) {
  var Model = BaseProjection.extend({
    name: 'column-hovertext',
    update: function (options) {
      if (Model.__super__.update.call(this, options)) {
        var model = this.src.data;
        var columns = model.get('columns');

        _.each(columns, function(column) {
          column.$metadata = _.result(column, '$metadata', {});
          column.$metadata['attr.head'] = _.result(column.$metadata, 'attr.head', {});
          column.$metadata['attr.head'].title = _.result(column.config, 'hoverText') || _.result(column.config, 'title') || '';
        });

        this.patch({ columns: columns });
      }
    },
  });

  return Model;
});

Use another way to set title.


window.Kpcc = Ember.Application.create();

Kpcc.Store = DS.Store.extend({
    adapter: DS.RESTAdapter.extend({
        url         : "http://localhost:3000",
        namespace   : "api/v3"
    })
});

DS.RESTAdapter.map('Kpcc.Article', {
        assets: { embedded: 'always' }
    }
);

DS.RESTAdapter.map('Kpcc.Asset', {
        thumbnail : { embedded: 'always' },
        small     : { embedded: 'always' }
    }
);

window.Kpcc = Ember.Application.create();

Kpcc.Store = DS.Store.extend({
    adapter: DS.RESTAdapter.extend({
        url         : "http://www.scpr.org",
        namespace   : "api/v3"
    })
});

DS.RESTAdapter.map('Kpcc.Article', {
        assets: { embedded: 'always' }
    }
);

DS.RESTAdapter.map('Kpcc.Asset', {
        thumbnail : { embedded: 'always' },
        small     : { embedded: 'always' }
    }
);

Update api root to use scpr.org


/**
 * Web3 Helper
 * Returns initialized web3 instance
 *
 * @author: U-Zyn Chua <chua@uzyn.com>
 */
var Web3 = require('web3');
var web3;
if (typeof window.web3 !== 'undefined') {
 web3 = new Web3(window.web3.currentProvider);
} else {
 web3 = new Web3(new Web3.providers.HttpProvider('__PROVIDER_URL__'));
}

/**
 * Web3 Helper
 * Returns initialized web3 instance
 *
 * @author: U-Zyn Chua <chua@uzyn.com>
 */
var Web3 = require('web3');
var web3;
if (typeof window !== 'undefined' && typeof window.web3 !== 'undefined') {
 web3 = new Web3(window.web3.currentProvider);
} else {
 web3 = new Web3(new Web3.providers.HttpProvider('__PROVIDER_URL__'));
}

Fix check for window, variable is not available in node context


'use strict';

module.exports = {

  // TODO: cache
  transpile(src, filename, babelConfig, tsCompilerOptions) {
    const babel = require('babel-core');
    const tsc = require('typescript');
    const gulpTsc = require('gulp-typescript');

    const transformWithBabel = content =>
      babel.transform(content, Object.assign({}, babelConfig, {
        filename,
        retainLines: true
      })).code;

    if (filename.indexOf('node_modules') !== -1) {
      // skip node_modules
      return src;
    } else if (/\.tsx?$/.test(filename)) {
      // use gulp-typescript to convert the settings for tsc
      const tsProject = gulpTsc.createProject(Object.assign({}, tsCompilerOptions, {
        inlineSourceMap: true,
        declaration: false
      }));

      return transformWithBabel(tsc.transpile(src, tsProject.options));
    } else if (!babel.util.canCompile(filename)) {
      // You might use a webpack loader in your project
      // that allows you to load custom files (e.g. css, less, scss).
      // Although it is working with webpack but jest
      // don't know how to handle these files.
      // You should never use these files unmocked
      // otherwise you might encounter unexpected behavior.
      // Changing the content of these files
      // to return the raw content.
      return `module.exports = ${JSON.stringify(src)}`;
    }

    return transformWithBabel(src);
  }
};

'use strict';

module.exports = {

  // TODO: cache
  transpile(src, filename, babelConfig, tsCompilerOptions) {
    const babel = require('babel-core');
    const tsc = require('typescript');
    const gulpTsc = require('gulp-typescript');

    const transformWithBabel = content =>
      babel.transform(content, Object.assign({}, babelConfig, {
        filename,
        retainLines: true
      })).code;

    if (filename.indexOf('node_modules') !== -1) {
      // skip node_modules
      return src;
    } else if (/\.tsx?$/.test(filename)) {
      // use gulp-typescript to convert the settings for tsc
      const tsProject = gulpTsc.createProject(Object.assign({}, tsCompilerOptions, {
        typescript: tsc,
        inlineSourceMap: true,
        declaration: false
      }));

      return transformWithBabel(tsc.transpile(src, tsProject.options));
    } else if (!babel.util.canCompile(filename)) {
      // You might use a webpack loader in your project
      // that allows you to load custom files (e.g. css, less, scss).
      // Although it is working with webpack but jest
      // don't know how to handle these files.
      // You should never use these files unmocked
      // otherwise you might encounter unexpected behavior.
      // Changing the content of these files
      // to return the raw content.
      return `module.exports = ${JSON.stringify(src)}`;
    }

    return transformWithBabel(src);
  }
};

Fix mocha test (ts support)


//= requires "editor"
//= requires <mootools/DomReady>
//= requires <mootools/Selectors>

// Replace all textreas with class 'richtexteditor' with ckeditor instances
window.addEvent('domready', function() {
	document.getElements('textarea.richtexteditor').each(function(el) {
		CKEDITOR.replace(el, {
			// Turn off custom config so it doesn't attempt to load config file
			customConfig : ''
		});
	});
});

//= requires "editor"
//= requires <mootools/DomReady>
//= requires <mootools/Selectors>
//= requires <mootools/Element.Dimensions>

// Replace all textreas with class 'richtexteditor' with ckeditor instances
window.addEvent('domready', function() {
	document.getElements('textarea.richtexteditor').each(function(el) {
		var size = el.getSize();
		CKEDITOR.replace(el, {
			// Turn off custom config so it doesn't attempt to load config file
			customConfig : '',
			height: size.y
		});
	});
});

Set editor height to original textarea height


import { jsdom } from 'jsdom';

global.document = jsdom('

');
global.window = document.defaultView;

Object.keys(document.defaultView).forEach((property) => {
  if (typeof global[property] === 'undefined') {
    global[property] = document.defaultView[property];
  }
});

global.navigator = {
  appName: 'other',
  userAgent: 'node.js',
  platform: 'node.js',
};

const { JSDOM } = require('jsdom');
const jsdom = new JSDOM('<!doctype html>');
const { window } = jsdom;

function copyProps(src, target) {
  const props = Object.getOwnPropertyNames(src)
    .filter(prop => typeof target[prop] === 'undefined')
    .map(prop => Object.getOwnPropertyDescriptor(src, prop));
  Object.defineProperties(target, props);
}

global.window = window;
global.document = window.document;
copyProps(window, global);

global.navigator = {
  appName: 'other',
  userAgent: 'node.js',
  platform: 'node.js',
};

Fix jsdom tests to support jsdom10


#!/usr/bin/env node

var path = require('path');
var async = require('async');
var strider = require('strider');
var logger = require('strider/lib/logging');

var user = require('./user');
var project = require('./project');

var extPath = path.join(__dirname, "node_modules");

var launchStrider = function (callback) {
  strider(extPath, {}, callback);
};

async.series([
  launchStrider,
  user.createSystemUser,
  project.createControlProject
], function (err) {
  if (err) {
    logger.error("Unable to initialize Strider.", err);
    process.exit(1);
  }

  logger.info("Deconst Strider server is initialized and running.");
});

#!/usr/bin/env node

var fs = require('fs');
var path = require('path');
var async = require('async');
var strider = require('strider');
var logger = require('strider/lib/logging');

var user = require('./user');
var project = require('./project');

var extPath = path.join(__dirname, "node_modules");

process.umask(02);
fs.chmodSync('/workspace', 06755);

var launchStrider = function (callback) {
  strider(extPath, {}, callback);
};

async.series([
  launchStrider,
  user.createSystemUser,
  project.createControlProject
], function (err) {
  if (err) {
    logger.error("Unable to initialize Strider.", err);
    process.exit(1);
  }

  logger.info("Deconst Strider server is initialized and running.");
});

Set the umask and chown the volume on launch.


/*
 * grunt-markdown
 * https://github.com/treasonx/grunt-markdown
 *
 * Copyright (c) 2012 James Morrin
 * Licensed under the MIT license.
 */

module.exports = function(grunt) {
  'use strict';

  var path = require('path');

  // Internal lib.
  var markdown = require('./lib/markdown').init(grunt);

  grunt.registerMultiTask('markdown', 'compiles markdown files into html', function() {
    var destPath = this.data.dest;
    var options = this.data.options || {};
    var extension = this.data.extenstion || 'html';
    var templateFn = this.data.template || path.join(__dirname, 'template.html');
    var template = grunt.file.read(templateFn);

    grunt.file.expand({filter:'isFile'}, this.data.files).forEach(function(filepath) {

      var file = grunt.file.read(filepath);

      var html = markdown.markdown(file, options, template);
      var ext = path.extname(filepath);
      var dest = path.join(destPath, path.basename(filepath, ext) +'.'+ extension);
      grunt.file.write(dest, html);

    });

  });

};

/*
 * grunt-markdown
 * https://github.com/treasonx/grunt-markdown
 *
 * Copyright (c) 2012 James Morrin
 * Licensed under the MIT license.
 */

module.exports = function(grunt) {
  'use strict';

  var path = require('path');

  // Internal lib.
  var markdown = require('./lib/markdown').init(grunt);

  grunt.registerMultiTask('markdown', 'Compiles markdown files into html.', function() {
    // Merge task-specific and/or target-specific options with these defaults.
    var options = this.options({
      htmlExtension: 'html',
      markdownExtension: 'md',
      markedOptions: {},
      template: grunt.file.read(path.join(__dirname, 'template.html'))
    });

    // Iterate over all specified file groups.
    this.files.forEach(function(f) {
      f.src.forEach(function(filepath) {
        var content;
        var destName;

        if (!grunt.file.exists(filepath)) {
          grunt.log.warn('Source file "' + filepath + '" not found.');
          return false;
        } else {
          destName = f.dest.replace(
            options.markdownExtension,
            options.htmlExtension
          );

          content = markdown.markdown(
            grunt.file.read(filepath),
            options.markedOptions,
            options.template
          );

          grunt.file.write(destName, content);
          grunt.log.writeln('File "' + destName + '" created.');
        }
      });
    });

  });

};

Use new grunt files API.


var expect = require('expect.js'),
    fs = require('fs'),
    helper = require('./helper')

describe('data copying', function() {
	before(function(done) {
		helper.nanodocHere(done);
	});

	it('should copy files from the root directory', function(done) {
		helper.isFile(helper.outfile('data-a.txt'), function(err, success) {
			if(err) return done(err);
			expect(success).to.be.ok();
			done();
		});
	});

	it('should copy files from subdirectories', function(done) {
		helper.isFile(helper.outfile('subdir/data-b.txt'), function(err, success) {
			if(err) return done(err);
			expect(success).to.be.ok();
			done();
		});
	});
});

var expect = require('expect.js'),
    fs = require('fs'),
    helper = require('./helper')

describe('data copying', function() {
	before(function(done) {
		helper.nanodocHere(done);
	});

	it('should copy files from the root directory', function(done) {
		helper.isFile(helper.outfile('data-a.txt'), function(err, success) {
			if(err) return done(err);
			expect(success).to.be.ok();
			done();
		});
	});

	it('should copy the contents of the root directory file', function(done) {
		fs.readFile(helper.outfile('data-a.txt'), 'utf8', function(err, data) {
			if(err) return done(err);
			expect(data).to.be('a-a-a');
			done();
		});
	});

	it('should copy files from subdirectories', function(done) {
		helper.isFile(helper.outfile('subdir/data-b.txt'), function(err, success) {
			if(err) return done(err);
			expect(success).to.be.ok();
			done();
		});
	});

	it('should copy the contents of the subdirectory file', function(done) {
		fs.readFile(helper.outfile('subdir/data-b.txt'), 'utf8', function(err, data) {
			if(err) return done(err);
			expect(data).to.be('b-b-b');
			done();
		});
	});
});

Test for matching file contents


var isArray = Array.isArray;

exports.emaNeurt = function emaNeurt(o) {
	return exports.trueName(o, '\u202e');
};

exports.trueName = function trueName(obj, salt) {
	var t = (typeof obj)[0];

	var out = salt ? salt : '';

	var o = obj;

	if (t === 'o' && obj !== null) {
		o = obj.valueOf();
	}

	t = (typeof o)[0];

	if (t !== 'o' || o === null) {
		return out.concat(t, o);
	}

	if (o instanceof Date) {
		return out.concat('d', o.toJSON());
	}

	if (o instanceof RegExp) {
		return out.concat('r', o.toString());
	}

	if (t === 'f') {
		throw new TypeError('Invalid type: function');
	}

	if (isArray(o)) {
		t = 'a';
	}

	var keys, key;
	keys = Object.keys(o);

	keys.sort();

	for (var i = 0; i < keys.length; i += 1) {
		key = keys[i];
		out = out.concat(t, key, trueName(o[key]));
	}

	return out;
};

var isArray = Array.isArray;

exports.emaNeurt = function emaNeurt(o) {
	return exports.trueName(o, '\u202e');
};

exports.trueName = function trueName(obj, salt) {
	var t = (typeof obj)[0];
	var out = '';

	if (salt) {
		if (typeof salt === 'object') {
			salt = salt.valueOf();
		}

		if (typeof salt !== 'string') {
			throw new TypeError('Invalid type for salt: must be a string');
		}

		out = salt;
	}

	var o = obj;

	if (t === 'o' && obj !== null) {
		o = obj.valueOf();
	}

	t = (typeof o)[0];

	if (t !== 'o' || o === null) {
		return out.concat(t, o);
	}

	if (o instanceof Date) {
		return out.concat('d', o.toJSON());
	}

	if (o instanceof RegExp) {
		return out.concat('r', o.toString());
	}

	if (t === 'f') {
		throw new TypeError('Invalid type: function');
	}

	if (isArray(o)) {
		t = 'a';
	}

	var keys, key;
	keys = Object.keys(o);

	keys.sort();

	for (var i = 0; i < keys.length; i += 1) {
		key = keys[i];
		out = out.concat(t, key, trueName(o[key]));
	}

	return out;
};

Allow salt to be an object with valueOf() -> string.


var lastField = null;
var currentFillColor = '';   // ???
var changeCounter = 0;       // ???

function setField(element) {
    // element contains the current html element
    if (element.style.backgroundColor !== currentFillColor) {
        element.style.backgroundColor = currentFillColor;
    } else {
        element.style.backgroundColor = '#eee';
    }
    if (++changeCounter === 10) {
        alert('You have clicked 10 times on the field!');
        // Should the counter be reset after the alert?
        // changeCounter = 0;
    }
}

function setFillColor(color) {
    // color should be a string
    currentFillColor = color;
    var logEntry = document.createElement('p');
    logEntry.appendChild(document.createTextNode('Color changed'));
    logEntry.style.color = currentFillColor;
    document.getElementById('Log').appendChild(logEntry);
}

var lastField = null;
var currentFillColor = '';   // ???
var changeCounter = 0;       // ???

function setField(element) {
    // element contains the current html element
    if (element.style.backgroundColor !== currentFillColor) {
        element.style.backgroundColor = currentFillColor;
    } else {
        element.style.backgroundColor = '#eee';
    }
    if (++changeCounter === 10) {
        alert('You have clicked 10 times on the field!');
        // Should the counter be reset after the alert?
        // changeCounter = 0;
    }
}

function setFillColor(color) {
    // color should be a string
    var logEntry = document.createElement('p');
    logEntry.appendChild(document.createTextNode('Color changed'));
    logEntry.style.color = currentFillColor = color;
    document.getElementById('Log').appendChild(logEntry);
}

Save one line of code


/**
 * Created by stas on 06.01.16.
 */
'use strict';

var playzoneApp = angular.module('playzoneApp', [
    'ngRoute',
    'ngCookies',
    'ngResource',
    'ngWebSocket',
    'playzoneControllers',
    'playzoneServices',
    'pascalprecht.translate',
    'LocalStorageModule'
]).run(['$http', '$rootScope', '$cookies', 'UserRest', 'WebsocketService', function ($http, $rootScope, $cookies, UserRest, WebsocketService) {

    $rootScope.user = new UserRest({
        login: $cookies.get("user_login"),
        token: $cookies.get("user_token"),
        password: $cookies.get("user_token")
    });

    $rootScope.user.$auth().then(
        function() {
            WebsocketService.introduction($rootScope.user);
        }
    );
}]);

var checkIfUnauthorized = function ($q, $rootScope, $location) {
    if ($rootScope.user && $rootScope.user.isAuth) {
        $location.path('/');
    }
};

var playzoneControllers = angular.module('playzoneControllers', []);

var playzoneServices = angular.module('playzoneServices', []);

/**
 * Created by stas on 06.01.16.
 */
'use strict';

var playzoneApp = angular.module('playzoneApp', [
    'ngRoute',
    'ngCookies',
    'ngResource',
    'ngWebSocket',
    'playzoneControllers',
    'playzoneServices',
    'pascalprecht.translate',
    'LocalStorageModule'
]).run(['$http', '$rootScope', '$cookies', 'UserRest', 'WebsocketService', function ($http, $rootScope, $cookies, UserRest, WebsocketService) {

    $rootScope.user = new UserRest({
        login: $rootScope.user ? $rootScope.user.login : $cookies.get("user_login"),
        token: $rootScope.user ? $rootScope.user.token : $cookies.get("user_token"),
        password: $rootScope.user ? $rootScope.user.token : $cookies.get("user_token")
    });

    $rootScope.user.$auth().then(
        function() {
            WebsocketService.introduction($rootScope.user);
        }
    );
}]);

var checkIfUnauthorized = function ($q, $rootScope, $location) {
    if ($rootScope.user && $rootScope.user.isAuth) {
        $location.path('/');
    }
};

var playzoneControllers = angular.module('playzoneControllers', []);

var playzoneServices = angular.module('playzoneServices', []);

Fix bug with games after first authorization.


Package.describe({
  name: 'angular-scss-compiler',
  version: '0.3.1_2',
  summary: 'Angular Scss Compiler Package',
  git: 'https://github.com/Urigo/angular-meteor/tree/master/atmosphere-packages/angular-scss-compiler',
  documentation: null
});

Npm.depends({
  'node-sass': '4.7.2'
});

Package.onUse(function(api) {
  api.versionsFrom('1.6');
  api.use([
    'ecmascript'
  ], 'server');
  api.mainModule('index.js', 'server');
});

Package.describe({
  name: 'angular-scss-compiler',
  version: '0.3.1_2',
  summary: 'Angular Scss Compiler Package',
  git: 'https://github.com/Urigo/angular-meteor/tree/master/atmosphere-packages/angular-scss-compiler',
  documentation: null
});

Npm.depends({
  'node-sass': '4.8.3'
});

Package.onUse(function(api) {
  api.versionsFrom('1.6');
  api.use([
    'ecmascript'
  ], 'server');
  api.mainModule('index.js', 'server');
});

Update dependency node-sass to v4.8.3


var vows = require('vows');
var assert = require('assert');
var url = require('url');
var util = require('util');
var ConsumerStrategy = require('passport-http-oauth/strategies/consumer');

vows.describe('ConsumerStrategy').addBatch({

  'strategy': {
    topic: function() {
      return new ConsumerStrategy(function() {}, function() {});
    },

    'should be named oauth': function(strategy) {
      assert.equal(strategy.name, 'oauth');
    },
  },

}).export(module);

var vows = require('vows');
var assert = require('assert');
var url = require('url');
var util = require('util');
var ConsumerStrategy = require('passport-http-oauth/strategies/consumer');

vows.describe('ConsumerStrategy').addBatch({

  'strategy': {
    topic: function() {
      return new ConsumerStrategy(function() {}, function() {});
    },

    'should be named oauth': function(strategy) {
      assert.equal(strategy.name, 'oauth');
    },
  },

  'strategy constructed without a consumer callback or token callback': {
    'should throw an error': function (strategy) {
      assert.throws(function() { new ConsumerStrategy() });
    },
  },

  'strategy constructed without a token callback': {
    'should throw an error': function (strategy) {
      assert.throws(function() { new ConsumerStrategy(function() {}) });
    },
  },

}).export(module);

Test cases for required callbacks.


module.exports = {
    users: [ // ADD YOUR USERNAME AT THE TOP
		'megamattron',
		'pents90',
		'michaelnovakjr',
		'markbao',
		'kalmi',
		'lablayers'
	]
};

module.exports = {
    users: [ // ADD YOUR USERNAME AT THE TOP
		'roryokane',
		'megamattron',
		'pents90',
		'michaelnovakjr',
		'markbao',
		'kalmi',
		'lablayers'
	]
};

Add myself (roryokane) to the authorized user list


'use strict';

var findup = require('findup-sync');
var spawnSync = require('child_process').spawnSync;
var win32 = process.platform === 'win32';
var gruntPath = findup('node_modules/{.,}bin/grunt' + win32 ? '.cmd' : '', {cwd: __dirname});

process.title = 'grunth';

var harmonyFlags = [
    '--harmony_scoping',
//    '--harmony_modules', // We have `require` and ES6 modules are still in flux
//    '--harmony_symbols', // `Symbol('s')` throws
//    '--harmony_proxies', // `new Proxy({}, {})` throws
//    '--harmony_collections', // `new Set([2]).size` should be `1`
    '--harmony_generators',
//    '--harmony_iteration', // no `for-of`, the description must be wrong
    '--harmony_numeric_literals',
    '--harmony_strings',
    '--harmony_arrays',
    '--harmony_maths',
];

module.exports = function cli(params) {
    spawnSync('node',
        harmonyFlags.concat([gruntPath]).concat(params),
        {
            cwd: process.cwd(),
            stdio: 'inherit',
        }
    );
};

'use strict';

var findup = require('findup-sync');
var spawnSync = require('child_process').spawnSync;
var win32 = process.platform === 'win32';
var gruntPath = findup('node_modules/{.,}bin/grunt' + (win32 ? '.cmd' : ''), {cwd: __dirname});

process.title = 'grunth';

var harmonyFlags = [
    '--harmony_scoping',
//    '--harmony_modules', // We have `require` and ES6 modules are still in flux
//    '--harmony_symbols', // `Symbol('s')` throws
//    '--harmony_proxies', // `new Proxy({}, {})` throws
//    '--harmony_collections', // `new Set([2]).size` should be `1`
    '--harmony_generators',
//    '--harmony_iteration', // no `for-of`, the description must be wrong
    '--harmony_numeric_literals',
    '--harmony_strings',
    '--harmony_arrays',
    '--harmony_maths',
];

module.exports = function cli(params) {
    spawnSync('node',
        harmonyFlags.concat([gruntPath]).concat(params),
        {
            cwd: process.cwd(),
            stdio: 'inherit',
        }
    );
};

Fix typo in ternary expression


if (document.location.hostname == "localhost") {
    var baseurl = "";
} else {
    var baseurl = "https://noconfidencevote.openup.org.za";
}

var initContactMPsPymParent = function() {
  var pymParent = new pym.Parent('contactmps-embed-parent', baseurl + '/campaign/newsmedia/', {});
};

var agent = navigator.userAgent.toLowerCase();
if (agent.includes("mobile") && agent.includes("android")) {
  // addEventListener only available in later chrome versions
  window.addEventListener("load",function(){
    window.addEventListener('error', function(e) {
      ga('send', 'event', 'JavaScript Error Parent', e.filename + ':  ' + e.lineno, e.message);
    });

  });
  // Don't initialise pymParent! we iframe it ourselves!
  document.write('
Loading...
');
} else {
  document.write('

');
  document.write('');
}

if (document.location.hostname == "localhost") {
    var baseurl = "";
} else {
    var baseurl = "https://noconfidencevote.openup.org.za";
}

var initContactMPsPymParent = function() {
  var pymParent = new pym.Parent('contactmps-embed-parent', baseurl + '/campaign/newsmedia/', {});
};

document.write('

');
document.write('');

Remove hack for news24 android app since loading pym async fixes it


import { LIFTED_ACTION, SELECT_INSTANCE } from 'remotedev-app/lib/constants/actionTypes';
import { getActiveInstance } from 'remotedev-app/lib/reducers/instances';

function panelDispatcher(bgConnection) {
  let autoselected = false;
  const tabId = chrome.devtools.inspectedWindow.tabId;

  return store => next => action => {
    const result = next(action);
    if (!autoselected) {
      autoselected = true;
      const connections = store.getState()
        .instances.connections[tabId];
      if (connections && connections.length === 1) {
        next({ type: SELECT_INSTANCE, selected: connections[0] });
      }
    }
    if (action.type === LIFTED_ACTION) {
      const instances = store.getState().instances;
      const instanceId = getActiveInstance(instances);
      bgConnection.postMessage({ ...action, instanceId, id: tabId });
    }
    return result;
  };
}

export default panelDispatcher;

import { LIFTED_ACTION, UPDATE_STATE, SELECT_INSTANCE } from 'remotedev-app/lib/constants/actionTypes';
import { getActiveInstance } from 'remotedev-app/lib/reducers/instances';

function panelDispatcher(bgConnection) {
  let autoselected = false;
  const tabId = chrome.devtools.inspectedWindow.tabId;

  return store => next => action => {
    const result = next(action);
    if (!autoselected && action.type === UPDATE_STATE) {
      autoselected = true;
      const connections = store.getState()
        .instances.connections[tabId];
      if (connections && connections.length === 1) {
        next({ type: SELECT_INSTANCE, selected: connections[0] });
      }
    }
    if (action.type === LIFTED_ACTION) {
      const instances = store.getState().instances;
      const instanceId = getActiveInstance(instances);
      bgConnection.postMessage({ ...action, instanceId, id: tabId });
    }
    return result;
  };
}

export default panelDispatcher;

Fix autoselecting the current window's instance


var express = require('express')
  , router = express.Router()
  , Qpv = require('../models/qpv.js')
  , geojson = require('../helpers/geojson.js')
  , isvalidgeo = require('../helpers/isvalidgeo')
  , turf = require('turf')

router.get('/layer', function(req, res) {
  if (req.query.bbox){
    var bbox = req.query.bbox.split(",");
    var geojsonbbox = turf.bboxPolygon(bbox);
    var isvalid = isvalidgeo(geojsonbbox);
  }
  if (isvalid || !req.bbox){
    var qpv = Qpv.getLayer(bbox);
    qpv.then( function (data){
      var featureCollection = geojson.rows_to_geojson(data, Qpv.properties);
      res.json(featureCollection);
    }).catch(function (err){
      console.error(err)
      res.status(500).send({error:'something bad happens'})
    })
  }
  else{
    res.status(500).send({error:'invalid GeoJSON'})
  }
})

router.post('/intersects', function(req, res) {

  var qpv = Qpv.intersects(req.query.geom);
  res.send();
})
module.exports = router

var express = require('express')
  , router = express.Router()
  , Qpv = require('../models/qpv.js')
  , geojson = require('../helpers/geojson.js')
  , isvalidgeo = require('../helpers/isvalidgeo')
  , turf = require('turf')

router.get('/layer', function(req, res) {
  if (req.query.bbox){
    var bbox = req.query.bbox.split(",");
    var geojsonbbox = turf.bboxPolygon(bbox);
    var isvalid = isvalidgeo(geojsonbbox);
  }
  if (isvalid || !req.query.bbox){
    var qpv = Qpv.getLayer(bbox);
    qpv.then( function (data){
      var featureCollection = geojson.rows_to_geojson(data, Qpv.properties);
      res.json(featureCollection);
    }).catch(function (err){
      console.error(err)
      res.status(500).send({error:'something bad happens'})
    })
  }
  else{
    res.status(500).send({error:'invalid bbox'})
  }
})

router.post('/intersects', function(req, res) {

  var qpv = Qpv.intersects(req.query.geom);
  res.send();
})
module.exports = router

Fix typo with the usage of req.query


import PostForm from './post_form';

$(function() {
  $(document.body).on('click', '#flash p', function(e) {
    e.preventDefault();
    $(this).fadeOut(200);
  });

  $('.site_nav__search, .site_nav__about').on(
    'click',
    '.site_nav__link',
    function(e) {
      e.preventDefault();
      $(this)
        .closest('li')
        .toggleClass('site_nav--open')
        .find(':input:visible')
        .eq(0)
        .focus();
    }
  );

  new PostForm({
    postBodyInput: $('textarea#post_body'),
    postBodyPreview: $('.content_preview'),
    wordCountContainer: $('.word_count'),
    bodyWordLimitContainer: $('.word_limit'),
    bodyWordLimit: $('.word_limit').data('limit'),
    titleInput: $('input#post_title'),
    titleCharacterLimitContainer: $('.character_limit'),
    titleCharacterLimit: $('.character_limit').data('limit'),
    previewTitleContainer: $('.title_preview'),
    loadingIndicator: document.querySelector('.loading-indicator'),
  }).init();
});

import PostForm from './post_form';

$(function() {
  $('#flash p').on(
    'load',
    (function() {
      setTimeout(function() {
        $('#flash p').fadeOut(200);
      }, 10000);
    })()
  );

  $(document.body).on('click', '#flash p', function(e) {
    e.preventDefault();
    $(this).fadeOut(200);
  });

  $('.site_nav__search, .site_nav__about').on(
    'click',
    '.site_nav__link',
    function(e) {
      e.preventDefault();
      $(this)
        .closest('li')
        .toggleClass('site_nav--open')
        .find(':input:visible')
        .eq(0)
        .focus();
    }
  );

  new PostForm({
    postBodyInput: $('textarea#post_body'),
    postBodyPreview: $('.content_preview'),
    wordCountContainer: $('.word_count'),
    bodyWordLimitContainer: $('.word_limit'),
    bodyWordLimit: $('.word_limit').data('limit'),
    titleInput: $('input#post_title'),
    titleCharacterLimitContainer: $('.character_limit'),
    titleCharacterLimit: $('.character_limit').data('limit'),
    previewTitleContainer: $('.title_preview'),
    loadingIndicator: document.querySelector('.loading-indicator'),
  }).init();
});

Hide the flashes after 10 seconds


/**
 * Created by jack on 16-8-27.
 */

import vue from 'vue';
import { mapState, mapActions } from 'vuex';

import template from './tags.html';
import tagsActions from 'vuexModule/tags/actions';

const Tags = vue.extend({
	template,
	computed: mapState({
		header: state => state.tags.header,
		tagsList: state => state.tags.list,
		isLoading: state => state.tags.isLoading,
		tagName: state => state.route.params.tagName
	}),
	methods: mapActions(['initTagsPage', 'queryTagsList']),
	watch: {
		'tagName': function() {
			this.queryTagsList({
				tagName: this.tagName,
				router: this.$router
			});
		}
	},
	created() {
		this.initTagsPage();
		this.queryTagsList({
			tagName: this.tagName,
			enableLoading: this.$root._isMounted,
			router: this.$router
		});
	},
	preFetch(store) {
		return tagsActions.queryTagsList(store, {
			postName: store.state.route.params.postName,
			enableLoading: false,
			router: this.$router
		});
	}
});

export default Tags;

/**
 * Created by jack on 16-8-27.
 */

import vue from 'vue';
import { mapState, mapActions } from 'vuex';

import template from './tags.html';
import tagsActions from 'vuexModule/tags/actions';

const Tags = vue.extend({
	template,
	computed: mapState({
		header: state => state.tags.header,
		tagsList: state => state.tags.list,
		isLoading: state => state.tags.isLoading,
		tagName: state => state.route.params.tagName
	}),
	methods: mapActions(['initTagsPage', 'queryTagsList']),
	watch: {
		'tagName': function() {
			this.queryTagsList({
				tagName: this.tagName,
				router: this.$router
			});
		}
	},
	created() {
		this.initTagsPage();
		this.queryTagsList({
			tagName: this.tagName,
			enableLoading: this.$root._isMounted,
			router: this.$router
		});
	},
	preFetch(store) {
		return tagsActions.queryTagsList(store, {
			tagName: store.state.route.params.tagName,
			enableLoading: false,
			router: this.$router
		});
	}
});

export default Tags;

Fix tag preFetch request param bug.


function build_url(host, command, node = "") {
  if( node == "local" ){
    return 'http://' + host + '/api/' + encodeURI(command).replace(/#/g, '%23');
  } else {
    return 'http://' + host + '/api/' + encodeURI(node) + "/" + encodeURI(command).replace(/#/g, '%23');
  }
}

class WobserverApiFallback {
  constructor(host, node = "local") {
    this.host = host;
    this.node = node;
  }

  command(command, data = null) {
    console.log('Send fallback command');
  }

  command_promise(command, data = null) {
    return fetch(build_url(this.host, command, this.node))
    .then(res => res.json())
    .then(data => { return {
      data: data,
      timestamp: Date.now() / 1000 | 0,
      type: command,
    } } )
    .catch( _ => {} );
  }

  set_node(node) {
    this.node = node;
  }
}

export{ WobserverApiFallback }

function build_url(host, command, node = "") {
  if( node == "local" ){
    return 'http://' + host + '/api/' + encodeURI(command).replace(/#/g, '%23');
  } else {
    return 'http://' + host + '/api/' + encodeURI(node) + "/" + encodeURI(command).replace(/#/g, '%23');
  }
}

class WobserverApiFallback {
  constructor(host, node = "local") {
    this.host = host;
    this.node = node;
    this.connected = true;
  }

  command(command, data = null) {
    fetch(build_url(this.host, command, this.node))
  }

  command_promise(command, data = null) {
    return fetch(build_url(this.host, command, this.node))
    .then(res => res.json())
    .then(data => { return {
      data: data,
      timestamp: Date.now() / 1000 | 0,
      type: command,
    } } )
    .then(e => {
      if( !this.connected ){
        this.connected = true;
        this.on_reconnect()
      }

      return e;
    })
    .catch(_ => {
      this.connected = false;
      this.on_disconnect();
    });
  }

  set_node(node) {
    this.node = node;
  }
}

export{ WobserverApiFallback }

Add reconnect/disconnect events to fallback connection.


import React from 'react';

const AssetImage = (
  ({ file }) => (
    <img src={file.src} style={file.computedStyle} />
  )
);

export default AssetImage;

import React from 'react';

const AssetImage = (
  ({ file }) => (
    <img src={file.src} style={file.computedStyle} onContextMenu={e => e.preventDefault()} />
  )
);

export default AssetImage;

Disable right click on images


import {isFunction, get} from "lodash";

export function combineReducers(stateReducerMap) {
  return function(state, action) {
    let changed = false;

    const nextState = {};
    Object.entries(stateReducerMap).forEach(([path, module]) => {
      if (isFunction(module.integrator)) {
        nextState[path] = module.integrator(path)(get(state, path), action, path);
      } else {
        nextState[path] = module(get(state, path), action);
      }

      if (nextState[path] !== get(state, path)) {
        changed = true;
      }
    });

    return changed ? nextState : state;
  };
}

import {isFunction, get} from "lodash";

export function combineReducers(stateReducerMap, rootPath) {
  return function(state, action) {
    let changed = false;

    const nextState = {};
    Object.entries(stateReducerMap).forEach(([path, module]) => {
      const fullPath = rootPath ? `${rootPath}.${path}` : path;
      const ownState = get(state, path);

      if (isFunction(module.integrator)) {
        nextState[path] = module.integrator(fullPath)(ownState, action, fullPath);
      } else {
        nextState[path] = module(ownState, action, fullPath);
      }

      if (nextState[path] !== get(state, path)) {
        changed = true;
      }
    });

    return changed ? nextState : state;
  };
}

Fix the combineReducers utility to correct handling full module path.


'use babel'

import { lint } from 'mixedindentlint'
import LinterHelpers from 'atom-linter'

export default {
	config: {},

	activate() {
	},

	deactivate() {
	},

	scanFile( textEditor ) {
		const text = textEditor.getText()
		const linesToDecorate = lint( text )
		return linesToDecorate.map( line => {
			return {
				type: 'Warning',
				text: 'Indentation different from rest of file',
				range: LinterHelpers.rangeFromLineNumber( textEditor, line - 1 ),
				filePath: textEditor.getPath()
			}
		} )
	},

	provideLinter() {
		return {
			name: 'MixedIndent',
			grammarScopes: [ '*' ],
			scope: 'file',
			lintOnFly: true,
			lint: this.scanFile
		}
	}
}

'use babel'
/*global atom*/

import { lint } from 'mixedindentlint'
import LinterHelpers from 'atom-linter'

export default {
	config: {
		ignoreComments: {
			type: 'boolean',
			default: false,
			title: 'Ignore Comments',
			description: 'Ignore comments entirely in code. Otherwise comment indentation will be scanned as well.'
		}
	},

	activate() {
	},

	deactivate() {
	},

	scanFile( textEditor ) {
		const options = {
			comments: atom.config.get( 'linter-mixed-indent.ignoreComments' )
		}
		const text = textEditor.getText()
		const linesToDecorate = lint( text, options )
		return linesToDecorate.map( line => {
			return {
				type: 'Warning',
				text: 'Indentation different from rest of file',
				range: LinterHelpers.rangeFromLineNumber( textEditor, line - 1 ),
				filePath: textEditor.getPath()
			}
		} )
	},

	provideLinter() {
		return {
			name: 'MixedIndent',
			grammarScopes: [ '*' ],
			scope: 'file',
			lintOnFly: true,
			lint: this.scanFile
		}
	}
}

Add option to Ignore Comments