var pingPong = function(i) {
  if ((i % 3 === 0) && (i % 5 != 0)) {
    return "ping";
  } else if ((i % 5 === 0) && (i % 6 != 0)) {
    return "pong";
  } else if ((i % 3 === 0) && (i % 5 === 0)) {
    return "ping pong";
  } else {
    return false;
  }
};

$(function() {
  $("#game").submit(function(event) {
    $('#outputList').empty();

    var number = parseInt($("#userNumber").val());

    for (var i = 1; i <= number; i += 1) {
      if (i % 15 === 0) {
        $('#outputList').append("
ping pong
");
      } else if ((winner) && (i % 5 != 0)) {
        $('#outputList').append("
ping
");
      } else if ((winner) && (i % 3 != 0)) {
        $('#outputList').append("
pong
");
      } else {
        $('#outputList').append("
" + i + "
");
      }
    }
    event.preventDefault();
  });
});

var pingPong = function(i) {
  if ((i % 5 === 0) || (i % 3 === 0)) {
    return true;
  } else {
    return false;
  }
};

$(function() {
  $("#game").submit(function(event) {
    $('#outputList').empty();

    var number = parseInt($("#userNumber").val());

    for (var i = 1; i <= number; i += 1) {
      if (i % 15 === 0) {
        $('#outputList').append("
ping pong
");
      } else if (i % 3 === 0) {
        $('#outputList').append("
ping
");
      } else if (i % 5 === 0) {
        $('#outputList').append("
pong
");
      } else {
        $('#outputList').append("
" + i + "
");
      }
    }
    event.preventDefault();
  });
});

Change spec test back to true/false, rewrite loop for better clarity of changes


var BATCH_API_ENDPOINT = 'http://127.0.0.1:8080/api/v1/sql/job';

module.exports = {
    db: {
        host: 'localhost',
        port: 5432,
        dbname: 'analysis_api_test_db',
        user: 'postgres',
        pass: ''
    },
    batch: {
        endpoint: BATCH_API_ENDPOINT,
        username: 'localhost',
        apiKey: 1234
    }
};

'use strict';

var BATCH_API_ENDPOINT = 'http://127.0.0.1:8080/api/v1/sql/job';

function create (override) {
    override = override || {
        db: {},
        batch: {}
    };
    override.db = override.db || {};
    override.batch = override.batch || {};
    return {
        db: defaults(override.db, {
            host: 'localhost',
            port: 5432,
            dbname: 'analysis_api_test_db',
            user: 'postgres',
            pass: ''
        }),
        batch: defaults(override.batch, {
            endpoint: BATCH_API_ENDPOINT,
            username: 'localhost',
            apiKey: 1234
        })
    };
}

function defaults (obj, def) {
    Object.keys(def).forEach(function(key) {
        if (!obj.hasOwnProperty(key)) {
            obj[key] = def[key];
        }
    });

    return obj;
}

module.exports = create();

module.exports.create = create;

Allow to create test config with overrided options


module.exports = function(config) {
    config.set({
        frameworks: ['mocha'],
        browsers: ['Firefox', 'PhantomJS'],
        files: [require.resolve('es5-shim'), 'build/test.js'],
        reporters: ['dots']
    });

    if (process.env.CI && process.env.SAUCE_ACCESS_KEY) {
        var customLaunchers = {
            sauceLabsFirefox: {
                base: 'SauceLabs',
                browserName: 'firefox'
            },
            sauceLabsChrome: {
                base: 'SauceLabs',
                browserName: 'chrome'
            },
            sauceLabsIE11: {
                base: 'SauceLabs',
                browserName: 'internet explorer',
                version: 11
            },
            sauceLabsIE10: {
                base: 'SauceLabs',
                browserName: 'internet explorer',
                version: 10
            },
            sauceLabsIE9: {
                base: 'SauceLabs',
                browserName: 'internet explorer',
                version: 9
            },
            sauceLabsIE8: {
                base: 'SauceLabs',
                browserName: 'internet explorer',
                version: 8
            }
        };

        config.set({
            browsers: Object.keys(customLaunchers),
            reporters: ['dots', 'saucelabs'],
            captureTimeout: 120000,
            sauceLabs: {
                testName: 'Loud'
            },
            customLaunchers: customLaunchers
        });
    }
};

module.exports = function(config) {
    config.set({
        frameworks: ['mocha'],
        browsers: ['Firefox', 'PhantomJS'],
        files: [require.resolve('es5-shim'), 'build/test.js'],
        reporters: ['dots']
    });

    if (process.env.CI && process.env.SAUCE_ACCESS_KEY) {
        var customLaunchers = {
            sauceLabsFirefox: {
                base: 'SauceLabs',
                browserName: 'firefox'
            },
            sauceLabsChrome: {
                base: 'SauceLabs',
                browserName: 'chrome'
            }
        };

        config.set({
            browsers: Object.keys(customLaunchers),
            reporters: ['dots', 'saucelabs'],
            captureTimeout: 120000,
            sauceLabs: {
                testName: 'Loud'
            },
            customLaunchers: customLaunchers
        });
    }
};

Revert "Test in Internet Explorer in SauceLabs"


import React from "react";
import moment from "moment";

class Record extends React.Component {
    render() {
        const {record} = this.props;

        return (

Id

{record.id}

First Name

{record.first_name}

Last Name

{record.last_name}

Email

<a href={`mailto:${record.email}`}>{record.email}

Date Joined

{moment(record.date_joined).format('dddd MMMM Do YYYY, h:mm A')}

Last Login

{moment(record.last_login).format('dddd MMMM Do YYYY, h:mm A')}

        );
    }
}

export default Record;

import React from "react";
import moment from "moment";

class Record extends React.Component {
    render() {
        const {record} = this.props;

        return (

Id

{record.id}

First Name

{record.first_name}

Last Name

{record.last_name}

Email

<a href={`mailto:${record.email}`}>{record.email}

Date Joined

{moment(record.date_joined).format('ddd. MMM. Do YYYY, h:mm A')}

Last Login

{moment(record.last_login).format('ddd. MMM. Do YYYY, h:mm A')}

        );
    }
}

export default Record;

Use short format when displaying dates on user record


var Spec02 = require("../../specs/spec_0_2.js");

const spec02 = new Spec02();

function JSONParser(_spec) {
  this.spec = (_spec) ? _spec : new Spec02();
}

/**
 * Level 0 of validation: is that string? is that JSON?
 */
function validate_and_parse_as_json(payload) {
  var json = payload;

  if(payload) {
    if( (typeof payload) == "string"){
      try {
        json = JSON.parse(payload);

      }catch(e) {
        throw {message: "invalid json payload", errors: e};
      }

    } else if( (typeof payload) != "object"){
      // anything else
      throw {message: "invalid payload type, allowed are: string or object"};
    }
  } else {
    throw {message: "null or undefined payload"};
  }

  return json;
}

/*
 * Level 1 of validation: is that follow a spec?
 */
function validate_spec(payload, spec) {

  // is that follow the spec?
  spec.check(payload);

  return payload;
}

JSONParser.prototype.parse = function(payload) {

  // Level 0 of validation: is that string? is that JSON?
  var valid0 = validate_and_parse_as_json(payload);

  // Level 1 of validation: is that follow a spec?
  var valid1 = validate_spec(valid0, this.spec);

  return valid1;
}

module.exports = JSONParser;

function JSONParser() {

}

/**
 * Level 0 of validation: is that string? is that JSON?
 */
function validate_and_parse_as_json(payload) {
  var json = payload;

  if(payload) {
    if( (typeof payload) == "string"){
      try {
        json = JSON.parse(payload);

      }catch(e) {
        throw {message: "invalid json payload", errors: e};
      }

    } else if( (typeof payload) != "object"){
      // anything else
      throw {message: "invalid payload type, allowed are: string or object"};
    }
  } else {
    throw {message: "null or undefined payload"};
  }

  return json;
}

/*
 * Level 1 of validation: is that follow a spec?
 */
function validate_spec(payload, spec) {

  // is that follow the spec?
  spec.check(payload);

  return payload;
}

JSONParser.prototype.parse = function(payload) {

  //is that string? is that JSON?
  var valid = validate_and_parse_as_json(payload);

  return valid;
}

module.exports = JSONParser;

Remove the responsability of spec checking


'use strict';

module.exports = function RouteFactory(options) {
  return ([
    require('./routes/credits'),
    require('./routes/debits'),
    require('./routes/users'),
    require('./routes/graphql'),
    require('./routes/referrals')
  ]).map(function(Router) {
    return Router({
      config: options.config,
      network: options.network,
      storage: options.storage,
      mailer: options.mailer,
      contracts: options.contracts
    }).getEndpointDefinitions();
  }).reduce(function(set1, set2) {
    return set1.concat(set2);
  }, []);
};

'use strict';

module.exports = function RouteFactory(options) {
  return ([
    require('./routes/credits'),
    require('./routes/debits'),
    require('./routes/users'),
    require('./routes/graphql'),
    require('./routes/referrals'),
    require('./routes/marketing')
  ]).map(function(Router) {
    return Router({
      config: options.config,
      network: options.network,
      storage: options.storage,
      mailer: options.mailer,
      contracts: options.contracts
    }).getEndpointDefinitions();
  }).reduce(function(set1, set2) {
    return set1.concat(set2);
  }, []);
};

Add marketing route to factory


(function( window, document, undefined ) {
  'use strict';

  var hslEl = document.createElement( 'div' );
  hslEl.classList.add( 'hsl' );
  document.body.appendChild( hslEl );

  window.addEventListener( 'mousemove', function( event ) {
    var x = event.pageX,
        y = event.pageY;

    var h = x / window.innerWidth * 360,
        s = ( window.innerHeight - y ) / window.innerHeight * 100,
        l = 50;

    var hsl = 'hsl(' +
      Math.round( h ) + ', ' +
      Math.round( s ) + '%, ' +
      Math.round( l ) + '%)';

    document.body.style.backgroundColor = hsl;
    hslEl.textContent = hsl;
  });
}) ( window, document );

(function( window, document, undefined ) {
  'use strict';

  function clamp( value, min, max ) {
    return Math.min( Math.max( value, min ), max );
  }

  var hslEl = document.createElement( 'div' );
  hslEl.classList.add( 'hsl' );
  document.body.appendChild( hslEl );

  var h = 0,
      s = 50,
      l = 50;

  function update() {
    var hsl = 'hsl(' +
      Math.round( h ) + ', ' +
      Math.round( s ) + '%, ' +
      Math.round( l ) + '%)';

    document.body.style.backgroundColor = hsl;
    hslEl.textContent = hsl;
  }

  window.addEventListener( 'mousemove', function( event ) {
    var x = event.pageX,
        y = event.pageY;

    h = x / window.innerWidth * 360;
    s = ( window.innerHeight - y ) / window.innerHeight * 100;

    update();
  });

  window.addEventListener( 'wheel', function( event ) {
    event.preventDefault();
    l = clamp( l - event.deltaY, 0, 100 );
    update();
  });

  update();
}) ( window, document );

Use mouse wheel to control HSL lightness.


var nconf = require('nconf')
  , path = require('path');

const defaults = {
    username: "",
    password: "",
    guardcode: "",
    twofactor: "",
    sentryauth: false,
    sentryfile: "",
    autojoin: [],
    "24hour": false,
    userlistwidth: 26,                  // 26 characters
    scrollback: 1000,                   // 1000 lines
    ghostcheck: 5*60*1000,              // 5 minutes
    max_reconnect: 5,                   // 5 attempts
    reconnect_timeout: 30*1000,         // 30 seconds
    reconnect_long_timeout: 10*60*1000  // 10 minutes
};

function setPath(configPath) {
    nconf.file(configPath);
    nconf.stores.file.store =
        Object.assign({}, defaults, nconf.stores.file.store);
}

setPath(path.join(__dirname, '..', 'config.json'));

module.exports = {
    set: (...args) => nconf.set(...args),
    get: (...args) => nconf.get(...args),
    save: (...args) => nconf.save(...args),
    reload: (...args) => nconf.load(...args),
    getPath: () => nconf.stores.file.file,
    setPath,
    isValidKey: (key) => Object.keys(defaults).includes(key)
};

var nconf = require('nconf')
  , path = require('path');

const defaults = {
    username: "",
    password: "",
    guardcode: "",
    twofactor: "",
    sentryauth: false,
    sentryfile: "",
    autojoin: [],
    "24hour": false,
    userlistwidth: 26,                  // 26 characters
    scrollback: 1000,                   // 1000 lines
    ghostcheck: 5*60*1000,              // 5 minutes
    max_reconnect: 5,                   // 5 attempts
    reconnect_timeout: 30*1000,         // 30 seconds
    reconnect_long_timeout: 10*60*1000  // 10 minutes
};

module.exports = {
    set: (...args) => nconf.set(...args),
    get: (...args) => nconf.get(...args),
    save: (...args) => nconf.save(...args),
    reload: (...args) => nconf.load(...args),
    getPath: () => nconf.stores.file.file,
    setPath: (configPath) => {
        nconf.file(configPath);
        nconf.stores.file.store =
            Object.assign({}, defaults, nconf.stores.file.store);
    },
    isValidKey: (key) => Object.keys(defaults).includes(key),
    checkType: (key) => module.exports.isValidKey(key)
                        && typeof(defaults[key])
};

module.exports.setPath(path.join(__dirname, '..', 'config.json'));

Add checkType method and prettify code


#!/usr/local/bin/node

var options = {},
	args = process.argv.slice( 0 ),
	spider = require( "../index.js" );

args.splice( 0, 2 );
args.forEach( function( value ) {
	var arg = value.match( /^(?:--)((?:[a-zA-Z])*)(?:=)((?:.)*)/ );
	options[ arg[ 1 ] ] = arg[ 2 ];
});

spider( options, function( statusCode ) {
	process.exit( statusCode );
} );

#!/usr/bin/env node

var options = {},
	args = process.argv.slice( 0 ),
	spider = require( "../index.js" );

args.splice( 0, 2 );
args.forEach( function( value ) {
	var arg = value.match( /^(?:--)((?:[a-zA-Z])*)(?:=)((?:.)*)/ );
	options[ arg[ 1 ] ] = arg[ 2 ];
});

spider( options, function( statusCode ) {
	process.exit( statusCode );
} );

Fix hardcoded path to node executable


'use strict';

/**
 * Module dependencies
 */

module.exports = mongoose => {
  var Decimal = require('mongoose-float').loadType(mongoose, 2);
  var Float = require('mongoose-float').loadType(mongoose, 20);

  return {
    convertType: mongooseType => {
      switch (mongooseType.toLowerCase()) {
        case 'array':
          return Array;
        case 'boolean':
          return 'Boolean';
        case 'binary':
          return 'Buffer';
        case 'date':
        case 'datetime':
        case 'time':
        case 'timestamp':
          return Date;
        case 'decimal':
          return Decimal;
        case 'float':
          return Float;
        case 'json':
          return 'Mixed';
        case 'biginteger':
        case 'integer':
          return 'Number';
        case 'uuid':
          return 'ObjectId';
        case 'email':
        case 'enumeration':
        case 'password':
        case 'string':
        case 'text':
          return 'String';
        default:
      }
    },
  };
};

'use strict';

/**
 * Module dependencies
 */

module.exports = mongoose => {
  mongoose.Schema.Types.Decimal = require('mongoose-float').loadType(mongoose, 2);
  mongoose.Schema.Types.Float = require('mongoose-float').loadType(mongoose, 20);

  return {
    convertType: mongooseType => {
      switch (mongooseType.toLowerCase()) {
        case 'array':
          return Array;
        case 'boolean':
          return 'Boolean';
        case 'binary':
          return 'Buffer';
        case 'date':
        case 'datetime':
        case 'time':
        case 'timestamp':
          return Date;
        case 'decimal':
          return 'Decimal';
        case 'float':
          return 'Float';
        case 'json':
          return 'Mixed';
        case 'biginteger':
        case 'integer':
          return 'Number';
        case 'uuid':
          return 'ObjectId';
        case 'email':
        case 'enumeration':
        case 'password':
        case 'string':
        case 'text':
          return 'String';
        default:
      }
    },
  };
};

Fix mongoose float and decimal problems


'use strict';

var aFrom   = require('es5-ext/array/from')
  , partial = require('es5-ext/function/#/partial')
  , extend  = require('es5-ext/object/extend-properties')
  , ee      = require('event-emitter')

  , o;

o = ee(exports = {
	init: function () {
		this.msg = [];
		this.passed = [];
		this.errored = [];
		this.failed = [];
		this.started = new Date();
		return this;
	},
	in: function (msg) {
		this.msg.push(msg);
	},
	out: function () {
		this.msg.pop();
	},
	log: function (type, data) {
		var o = { type: type, time: new Date(), data: data, msg: aFrom(this.msg) };
		this.push(o);
		this[type + 'ed'].push(o);
		this.emit('data', o);
	},
	end: function () {
		this.emit('end');
	}
});

o.log.partial = partial;
o.error = o.log.partial('error');
o.pass = o.log.partial('pass');
o.fail = o.log.partial('fail');

module.exports = function () {
	return extend([], o).init();
};

'use strict';

var aFrom   = require('es5-ext/array/from')
  , partial = require('es5-ext/function/#/partial')
  , mixin   = require('es5-ext/object/mixin')
  , ee      = require('event-emitter')

  , o;

o = ee(exports = {
	init: function () {
		this.msg = [];
		this.passed = [];
		this.errored = [];
		this.failed = [];
		this.started = new Date();
		return this;
	},
	in: function (msg) {
		this.msg.push(msg);
	},
	out: function () {
		this.msg.pop();
	},
	log: function (type, data) {
		var o = { type: type, time: new Date(), data: data, msg: aFrom(this.msg) };
		this.push(o);
		this[type + 'ed'].push(o);
		this.emit('data', o);
	},
	end: function () {
		this.emit('end');
	}
});

o.log.partial = partial;
o.error = o.log.partial('error');
o.pass = o.log.partial('pass');
o.fail = o.log.partial('fail');

module.exports = function () {
	return mixin([], o).init();
};

Update up to changes in es5-ext


'use strict';

const Winston = require('winston');

function Logger(level) {
  const logLevel = level || 'info';

  const logger = new Winston.Logger({
    level: logLevel,
    transports: [
      new Winston.transports.Console({
        colorize: true,
        timestamp: true,
        json: true,
        stringify: true
      })
    ]
  });

  return logger;
}

exports.attach = Logger;

'use strict';

const Winston = require('winston');

function Logger(level) {
  const logLevel = level || 'info';

  const logger = new Winston.Logger({
    level: logLevel,
    transports: [
      new Winston.transports.Console({
        colorize: false,
        timestamp: true,
        json: true,
        stringify: true
      })
    ]
  });

  return logger;
}

exports.attach = Logger;

Set colorize to false for downstream consumers


var RawnetAdmin = window.RawnetAdmin || {};

RawnetAdmin.menu = function(){

  function toggleNav(link) {
    var   active = $('#mainNav a.active'),
    target = $(link.attr('href')),
    activeMenu = $('#subNav nav.active');

    active.removeClass('active');
    activeMenu.removeClass('active');
    link.addClass('active');
    target.addClass('active');
  }

  function openSearch() {
    var search = $('#searchControl');

    search.fadeIn("fast").addClass('open');
    search.find('input').focus();
    $(document).keyup(function(e) {
      if (e.keyCode === 27) {
        search.fadeOut("fast").removeClass('open');
        $(document).unbind("keyup");
      }else if (e.keyCode === 13) {
        search.find('form').trigger('submit');
      }
    });
  }

  function init() {
    var activeLink = $('#subNav a.active'),
    activeMenu = activeLink.closest('nav'),
    activeSelector = $('#mainNav a[href="#' + activeMenu.attr('id') + '"]');

    activeMenu.addClass('active');
    activeSelector.addClass('active');

    $(document).on('click', '#mainNav a, #dashboardNav a', function(e) {
      e.preventDefault();
      toggleNav($(this));
    });
    $(document).on('click', '#subNav a.search', function(e) {
      e.preventDefault();
      openSearch();
    });
  }

  return {
    init: init
  };

}();

var RawnetAdmin = window.RawnetAdmin || {};

RawnetAdmin.menu = function(){

  function toggleNav(link) {
    var   active = $('#mainNav a.active'),
    target = $(link.attr('href')),
    activeMenu = $('#subNav nav.active');

    active.removeClass('active');
    activeMenu.removeClass('active');
    link.addClass('active');
    target.addClass('active');
  }

  function openSearch() {
    var search = $('#searchControl');

    search.fadeIn("fast").addClass('open');
    search.find('input').focus();
    $(document).keyup(function(e) {
      if (e.keyCode === 27) {
        search.fadeOut("fast").removeClass('open');
        $(document).unbind("keyup");
      }else if (e.keyCode === 13) {
        search.find('form').trigger('submit');
      }
    });
  }

  function init() {
    var activeLink = $('#subNav a.active'),
    activeMenu = activeLink.closest('nav'),
    activeSelector = $('#mainNav a[href="#' + activeMenu.attr('id') + '"]');

    activeMenu.addClass('active');
    activeSelector.addClass('active');

    $(document).on('click', '#mainNav a[href^="#"], #dashboardNav a[href^="#"]', function(e) {
      e.preventDefault();
      toggleNav($(this));
    });
    $(document).on('click', '#subNav a.search', function(e) {
      e.preventDefault();
      openSearch();
    });
  }

  return {
    init: init
  };

}();

Allow non-anchor links to click through normally


#!/usr/bin/env node

const path = require('path');
const proc = require('child_process');
const startCase = require('lodash.startcase');

const baseDir = process.argv[2];

const files = proc.execFileSync(
  'find', [baseDir, '-type', 'f'], { encoding: 'utf8' },
).split('\n').filter(s => s !== '');

console.log('.API');

const links = files.map((file) => {
  const doc = file.replace(baseDir, '');
  const title = path.parse(file).name;

  return {
    xref: `* xref:${doc}[${startCase(title)}]`,
    title,
  };
});

// Case-insensitive sort based on titles (so 'token/ERC20' gets sorted as 'erc20')
const sortedLinks = links.sort(function (a, b) {
  return a.title.toLowerCase().localeCompare(b.title.toLowerCase(), undefined, { numeric: true });
});

for (const link of sortedLinks) {
  console.log(link.xref);
}

#!/usr/bin/env node

const path = require('path');
const proc = require('child_process');
const startCase = require('lodash.startcase');

const baseDir = process.argv[2];

const files = proc.execFileSync(
  'find', [baseDir, '-type', 'f'], { encoding: 'utf8' },
).split('\n').filter(s => s !== '');

console.log('.API');

function getPageTitle (directory) {
  if (directory === 'metatx') {
    return 'Meta Transactions';
  } else {
    return startCase(directory);
  }
}

const links = files.map((file) => {
  const doc = file.replace(baseDir, '');
  const title = path.parse(file).name;

  return {
    xref: `* xref:${doc}[${getPageTitle(title)}]`,
    title,
  };
});

// Case-insensitive sort based on titles (so 'token/ERC20' gets sorted as 'erc20')
const sortedLinks = links.sort(function (a, b) {
  return a.title.toLowerCase().localeCompare(b.title.toLowerCase(), undefined, { numeric: true });
});

for (const link of sortedLinks) {
  console.log(link.xref);
}

Change title of meta transactions page in docs sidebar


const commonRules = require("./rules");

module.exports = {
    parser: "babel-eslint",
    plugins: ["react", "babel", "flowtype", "prettier", "import"],
    env: {
        browser: true,
        es6: true,
        jest: true,
        node: true,
    },
    parserOptions: {
        sourceType: "module",
        ecmaFeatures: {
            modules: true,
            jsx: true,
        },
    },
    settings: {
        flowtype: {
            onlyFilesWithFlowAnnotation: true,
        },
        react: {
            version: "detect",
        },
    },
    rules: Object.assign(
        {},
        {
            "prettier/prettier": [
                "error",
                {
                    printWidth: 120,
                    tabWidth: 4,
                    useTabs: false,
                    semi: true,
                    singleQuote: false,
                    trailingComma: "es5",
                    bracketSpacing: true,
                    jsxBracketSameLine: true,
                },
            ],
        },
        commonRules,
        { "flowtype/require-return-type": ["warn", "always", { excludeArrowFunctions: true }] }
    ),
};

const commonRules = require("./rules");

module.exports = {
    parser: "babel-eslint",
    plugins: ["react", "babel", "flowtype", "prettier", "import"],
    env: {
        browser: true,
        es6: true,
        jest: true,
        node: true,
    },
    parserOptions: {
        sourceType: "module",
        ecmaFeatures: {
            modules: true,
            jsx: true,
        },
    },
    settings: {
        flowtype: {
            onlyFilesWithFlowAnnotation: true,
        },
        react: {
            version: "detect",
        },
    },
    rules: Object.assign(
        {},
        {
            "prettier/prettier": [
                "error",
                {
                    printWidth: 120,
                    tabWidth: 4,
                    useTabs: false,
                    semi: true,
                    singleQuote: false,
                    trailingComma: "es5",
                    bracketSpacing: true,
                    jsxBracketSameLine: true,
                },
            ],
        },
        commonRules,
        { "flowtype/require-return-type": ["warn", "always", { excludeArrowFunctions: true }] },
        { "react/prop-types": "off" }
    ),
};

Disable prop-types rule because Flow


(function () {
    'use strict';

    var mds = angular.module('mds', [
        'motech-dashboard', 'entityService','instanceService', 'mdsSettingsService', 'ngCookies', 'ui.directives',
        'ngRoute', 'ui.directives'
    ]);

    $.get('../mds/available/mdsTabs').done(function(data) {
         mds.constant('AVAILABLE_TABS', data);
    });

    mds.run(function ($rootScope, AVAILABLE_TABS) {
        $rootScope.AVAILABLE_TABS = AVAILABLE_TABS;
    });

    mds.config(function ($routeProvider, AVAILABLE_TABS) {
        angular.forEach(AVAILABLE_TABS, function (tab) {
            $routeProvider.when(
                '/{0}'.format(tab),
                {
                    templateUrl: '../mds/resources/partials/{0}.html'.format(tab),
                    controller: '{0}Ctrl'.format(tab.capitalize())
                }
            );
        });

        $routeProvider.otherwise({
            redirectTo: '/{0}'.format(AVAILABLE_TABS[0])
        });
    });
}());

(function () {
    'use strict';

    var mds = angular.module('mds', [
        'motech-dashboard', 'entityService','instanceService', 'mdsSettingsService', 'ngCookies', 'ui.directives',
        'ngRoute', 'ui.directives'
    ]);

    $.ajax({
        url:      '../mds/available/mdsTabs',
        success:  function(data) {
            mds.constant('AVAILABLE_TABS', data);
        },
        async:    false
    });

    mds.run(function ($rootScope, AVAILABLE_TABS) {
        $rootScope.AVAILABLE_TABS = AVAILABLE_TABS;
    });

    mds.config(function ($routeProvider, AVAILABLE_TABS) {
        angular.forEach(AVAILABLE_TABS, function (tab) {
            $routeProvider.when(
                '/{0}'.format(tab),
                {
                    templateUrl: '../mds/resources/partials/{0}.html'.format(tab),
                    controller: '{0}Ctrl'.format(tab.capitalize())
                }
            );
        });

        $routeProvider.otherwise({
            redirectTo: '/{0}'.format(AVAILABLE_TABS[0])
        });
    });
}());

Fix ajax error while checking available tabs


/**
 * React-related utilities
 */

import React from 'react';

/**
 * Like React.Children.forEach(), but traverses through all descendant children.
 *
 * @param children Children of a React element, i.e. `elem.props.children`
 * @param callback {function} A function to be run for each child; parameters passed: (child, indexOfChildInImmediateParent)
 */
export function reactChildrenForEachDeep(children, callback) {
  React.Children.forEach(children, (child, i) => {
    callback(child, i);
    if (child.props.children) {
      reactChildrenForEachDeep(child.props.children, callback);
    }
  });
}

/**
 * React-related utilities
 */

import React from 'react';

/**
 * Like React.Children.forEach(), but traverses through all descendant children.
 *
 * @param children Children of a React element, i.e. `elem.props.children`
 * @param callback {forEachCallback} A function to be run for each child
 */
export function reactChildrenForEachDeep(children, callback) {
  React.Children.forEach(children, (child, i) => {
    callback(child, i);
    if (child.props.children) {
      reactChildrenForEachDeep(child.props.children, callback);
    }
  });
}

/**
 * This callback is displayed as part of the Requester class.
 *
 * @callback forEachCallback
 * @param {*} child The React child
 * @param {number} index The index of the child in its immediate parent
 * @param {number} depth The number of parents traversed to react this child (top-level children have depth === 1)
 */

Add inline documentation for reactChildrenForEachDeep


// Spanish

$.extend( $.fn.pickadate.defaults, {
    monthsFull: [ 'Enero', 'Febrero', 'Marzo', 'Abril', 'Mayo', 'Junio', 'Julio', 'Agosto', 'Septiembre', 'Octubre', 'Noviembre', 'Diciembre' ],
    monthsShort: [ 'Ene', 'Feb', 'Mar', 'Abr', 'May', 'Jun', 'Jul', 'Ago', 'Sep', 'Oct', 'Nov', 'Dic' ],
    weekdaysFull: [ 'domingo', 'lunes', 'martes', 'miércoles', 'jueves', 'viernes', 'sábado' ],
    weekdaysShort: [ 'dom', 'lun', 'mar', 'mié', 'jue', 'vie', 'sab' ],
    today: 'hoy',
    clear: 'borrar',
    firstDay: 1,
    format: 'dddd d de mmmm de yyyy',
    formatSubmit: 'yyyy/mm/dd'
});

// Spanish

$.extend( $.fn.pickadate.defaults, {
    monthsFull: [ 'Enero', 'Febrero', 'Marzo', 'Abril', 'Mayo', 'Junio', 'Julio', 'Agosto', 'Septiembre', 'Octubre', 'Noviembre', 'Diciembre' ],
    monthsShort: [ 'Ene', 'Feb', 'Mar', 'Abr', 'May', 'Jun', 'Jul', 'Ago', 'Sep', 'Oct', 'Nov', 'Dic' ],
    weekdaysFull: [ 'domingo', 'lunes', 'martes', 'miércoles', 'jueves', 'viernes', 'sábado' ],
    weekdaysShort: [ 'dom', 'lun', 'mar', 'mié', 'jue', 'vie', 'sab' ],
    today: 'hoy',
    clear: 'borrar',
    firstDay: 1,
    format: 'dddd d De mmmm De yyyy',
    formatSubmit: 'yyyy/mm/dd'
});

Fix 'd' problem on translation


import moment from 'moment';
import getServerList from './../../utils/getServerList';

function getInitialState() {
  return {
    time: undefined,
    servers: getServerList().map(server => Object.assign(server, {state: 'loading', delay: 0}))
  };
}

export default function serverReducer(state = getInitialState(), action) {
  switch (action.type) {
    case "server.current.time":
      return setCurrentTime(state);
    case "server.online":
      return modifyServerState(state, action, 'online');
    case "server.offline":
      return modifyServerState(state, action, 'offline');
    default:
      return state;
  }
}

function setCurrentTime(state) {
  return {
    ...state,
    time: moment().unix()
  };
}

function modifyServerState(state, {server, responseTime}, newStateValue) {
  return {
    ...state,
    servers: state.servers.map(server => {
      if (server.name === server.name) {
        server.state = newStateValue;
        server.delay = moment().unix() - state.time;
      }
      return server;
    })
  };
}

import moment from 'moment';
import getServerList from './../../utils/getServerList';

function getInitialState() {
  return {
    time: undefined,
    servers: getServerList().map(server => Object.assign(server, {state: 'loading', delay: 0}))
  };
}

export default function serverReducer(state = getInitialState(), action) {
  switch (action.type) {
    case "server.current.time":
      return setCurrentTime(state);
    case "server.online":
      return modifyServerState(state, action, 'online');
    case "server.offline":
      return modifyServerState(state, action, 'offline');
    default:
      return state;
  }
}

function setCurrentTime(state) {
  return {
    ...state,
    time: moment().unix()
  };
}

function modifyServerState(state, {server, responseTime}, newStateValue) {
  return {
    ...state,
    servers: state.servers.map(stateServer => {
      if (server.name === stateServer.name) {
        return {
          ...stateServer,
          state: newStateValue,
          delay: moment().unix() - state.time
        };
      }
      return stateServer;
    })
  };
}

Fix a bug in the reducer


/**
 * Copyright 2004-present Facebook. All Rights Reserved.
 *
 * @flow strict
 * @typechecks
 * @format
 */

/**
 * Retrieve an object's own values as an array. If you want the values in the
 * protoype chain, too, use getObjectValuesIncludingPrototype.
 *
 * If you are looking for a function that creates an Array instance based
 * on an "Array-like" object, use createArrayFrom instead.
 *
 * @param {object} obj An object.
 * @return {array}     The object's values.
 */
function getOwnObjectValues<TValue>(obj: {
  +[key: string]: TValue,
  ...,
}): Array<TValue> {
  return Object.keys(obj).map(key => obj[key]);
}

module.exports = getOwnObjectValues;

/**
 * Copyright 2004-present Facebook. All Rights Reserved.
 *
 * @flow strict
 * @typechecks
 * @format
 */

/**
 * Retrieve an object's own values as an array. If you want the values in the
 * protoype chain, too, use getObjectValuesIncludingPrototype.
 *
 * If you are looking for a function that creates an Array instance based
 * on an "Array-like" object, use createArrayFrom instead.
 *
 * @param {object} obj An object.
 * @return {array}     The object's values.
 */
function getOwnObjectValues<TValue>(obj: {
  +[key: string]: TValue,
  ...
}): Array<TValue> {
  return Object.keys(obj).map(key => obj[key]);
}

module.exports = getOwnObjectValues;

Format JavaScript files with Prettier: scripts/draft-js/__github__/src/util


(function(){
  'use strict';

  angular.module('app.states')
    .run(appRun);

  /** @ngInject */
  function appRun(routerHelper) {
    routerHelper.configureStates(getStates());
  }

  function getStates() {
    return {
      'orders.details': {
        url: '/details/:orderId',
        templateUrl: 'app/states/orders/details/details.html',
        controller: StateController,
        controllerAs: 'vm',
        title: 'Order Details',
        resolve: {
          order: resolveOrder
        }
      }
    };
  }

  /** @ngInject */
  function resolveOrder($stateParams, Order){
    return Order.get({
      id: $stateParams.orderId,
      'includes[]': ['product', 'project', 'service', 'staff']
    }).$promise;
  }

  /** @ngInject */
  function StateController(order) {
    var vm = this;

    vm.order = order;
    vm.staff = order.staff;
    vm.product = order.product;
    vm.service = order.service;
    vm.project = order.project;

    vm.activate = activate;

    activate();

    function activate() {
    }
  }
})();

(function() {
  'use strict';

  angular.module('app.states')
    .run(appRun);

  /** @ngInject */
  function appRun(routerHelper) {
    routerHelper.configureStates(getStates());
  }

  function getStates() {
    return {
      'orders.details': {
        url: '/details/:orderId',
        templateUrl: 'app/states/orders/details/details.html',
        controller: StateController,
        controllerAs: 'vm',
        title: 'Order Details',
        resolve: {
          order: resolveOrder
        }
      }
    };
  }

  /** @ngInject */
  function resolveOrder($stateParams, Order) {
    return Order.get({
      id: $stateParams.orderId,
      'includes[]': ['product', 'project', 'service', 'staff']
    }).$promise;
  }

  /** @ngInject */
  function StateController(order) {
    var vm = this;

    vm.order = order;
    vm.staff = order.staff;
    vm.product = order.product;
    vm.service = order.service;
    vm.project = order.project;

    vm.activate = activate;

    activate();

    function activate() {
    }
  }
})();

Fix JSCS violation that snuck in while the reporter was broken


import { connect } from 'react-redux'
import merge from 'lodash/merge'
import { setEntity } from '../../lib/actions/entityActions'
import { toggleSessionPopup } from '../../UserSession/actions/SessionActions'
import PledgeForm from '../components/PledgeForm'
import updateAction from '../../lib/Form/actions/updateAction'

const mapStateToProps = function(state, ownProps) {
  return {
    availableTags: assembleTags(ownProps.tags),
    currentUser: state.currentUser,
  }
}

function assembleTags(tags) {
  return tags.map(function(tag) {
    return {
      value: tag.id,
      label: tag.name,
    }
  })
}

const mapDispatchToProps = dispatch => ({
  onLinkClick: function(event) {
    event.preventDefault()

    dispatch(toggleSessionPopup())
    window.scrollTo(0, 0)
  },
})

export default connect(
  mapStateToProps,
  mapDispatchToProps
)(PledgeForm)

import { connect } from 'react-redux'
import merge from 'lodash/merge'
import I18n from 'i18n-js'
import { setEntity } from '../../lib/actions/entityActions'
import { toggleSessionPopup } from '../../UserSession/actions/SessionActions'
import PledgeForm from '../components/PledgeForm'
import updateAction from '../../lib/Form/actions/updateAction'

const mapStateToProps = function(state, ownProps) {
  return {
    availableTags: assembleTags(ownProps.tags),
    currentUser: state.currentUser,
  }
}

function assembleTags(tags) {
  return tags.map(function(tag) {
    return {
      value: tag.id,
      label: I18n.t(`tags.names.${tag.name}`),
    }
  })
}

const mapDispatchToProps = dispatch => ({
  onLinkClick: function(event) {
    event.preventDefault()

    dispatch(toggleSessionPopup())
    window.scrollTo(0, 0)
  },
})

export default connect(
  mapStateToProps,
  mapDispatchToProps
)(PledgeForm)

Use tag name translations in new pledge form


'use strict';

const parser = require('../parser');

function InMemory(partials) {
	this.partials = partials;
	this.compiledPartials = {};
}

InMemory.prototype.get = function (id) {
	if (this.compiledPartials.hasOwnProperty(id)) return this.compiledPartials[id];
	if (this.partials.hasOwnProperty(id)) {
		return this.compiledPartials[id] = parser(this.partials[id]);
	}
	return null;
};

module.exports = InMemory;

'use strict';

const parser = require('../parser');

function InMemory(partials) {
	this.partials = partials;
	this.compiledPartials = {};
}

InMemory.prototype.get = function (id) {
	const compileTemplate = require('../../').compileTemplate;

	if (this.compiledPartials.hasOwnProperty(id)) return this.compiledPartials[id];
	if (this.partials.hasOwnProperty(id)) {
		return this.compiledPartials[id] = compileTemplate(parser(this.partials[id]));
	}
	return null;
};

module.exports = InMemory;

Update InMemory partials resolved to resolve compiled templates. This makes unit tests work again


var page = require('webpage').create();
var _ = require('underscore');
var fs = require('fs');

function stdout(str) {
  fs.write('/dev/stdout', str, 'w')
}

function stderr(str) {
  fs.write('/dev/stderr', str, 'w')
}

page.onAlert = stdout;
page.onConsoleMessage = stdout;
page.onError = stderr;

page.onLoadFinished = function() {
  phantom.exit();
};

page.open(phantom.args[0]);

var page = require('webpage').create();
var _ = require('underscore');
var system = require('system');

page.onAlert = system.stdout.write;
page.onConsoleMessage = system.stdout.write;
page.onError = system.stderr.write;

page.onLoadFinished = function() {
  phantom.exit(0);
};

page.open(phantom.args[0]);

Use `system` module for phantom runner script stdout/stderr


$(document).ready(function () {
  $('#columns .tweets').empty();  // Remove dummy content.

  $('.not-signed-in #the-sign-in-menu').popover({
    placement: 'below',
    trigger: 'manual'
  }).popover('show');
});

// __END__  {{{1
// vim: expandtab shiftwidth=2 softtabstop=2
// vim: foldmethod=marker

$(document).ready(function () {
  $('#columns .tweets').empty();  // Remove dummy content.

  $('.not-signed-in #the-sign-in-menu').popover({
    placement: 'below',
    trigger: 'manual'
  }).popover('show');

  var update_character_count = function () {
    $('#character-count').text(140 - $(this).val().length);  // FIXME
  };
  $('#status')
    .keydown(update_character_count)
    .keyup(update_character_count);
});

// __END__  {{{1
// vim: expandtab shiftwidth=2 softtabstop=2
// vim: foldmethod=marker

Update character count for new tweet


import React from 'react';

import List from '@ichef/gypcrete/src/List';
import ListRow from '@ichef/gypcrete/src/ListRow';
import TextLabel from '@ichef/gypcrete/src/TextLabel';

function DemoList() {
    return (
        <List>
            <ListRow>
                <TextLabel basic="Row 1" />
            </ListRow>
            <ListRow>
                <TextLabel basic="Row 2" />
            </ListRow>
            <ListRow>
                <TextLabel basic="Row 3" />
            </ListRow>
        </List>
    );
}

export default DemoList;

import React from 'react';
import { action } from '@storybook/addon-actions';

import Button from '@ichef/gypcrete/src/Button';
import List from '@ichef/gypcrete/src/List';
import ListRow from '@ichef/gypcrete/src/ListRow';

function DemoButton(props) {
    return (
        <Button
            bold
            minified={false}
            color="black"
            {...props} />
    );
}

function DemoList() {
    return (
        <List>
            <ListRow>
                <DemoButton basic="Row 1" onClick={action('click.1')} />
            </ListRow>
            <ListRow>
                <DemoButton basic="Row 2" onClick={action('click.2')} />
            </ListRow>
            <ListRow>
                <DemoButton basic="Row 3" onClick={action('click.3')} />
            </ListRow>
        </List>
    );
}

export default DemoList;

Update example for <Popover> to verify behavior


var fixtures = require('node-require-directory')(__dirname);

exports.load = function(specificFixtures) {
  return exports.unload().then(function() {
    if (typeof specificFixtures === 'string') {
      specificFixtures = [specificFixtures];
    }
    var promises = [];
    Object.keys(fixtures).filter(function(key) {
      if (key === 'index') {
        return false;
      }
      if (specificFixtures && specificFixtures.indexOf(key) === -1) {
        return false;
      }
      return true;
    }).forEach(function(key) {
      var promise = fixtures[key].load().then(function(instances) {
        exports[key] = instances;
      });
      promises.push(promise);
    });
    return Promise.all(promises);
  }).catch(function(err) {
    console.error(err.stack);
  });
};

exports.unload = function() {
  return sequelize.query('SET FOREIGN_KEY_CHECKS = 0').then(function() {
    return sequelize.sync({ force: true });
  }).then(function() {
    return sequelize.query('SET FOREIGN_KEY_CHECKS = 1');
  });
};

var fixtures = require('node-require-directory')(__dirname);

exports.load = function(specificFixtures) {
  return exports.unload().then(function() {
    if (typeof specificFixtures === 'string') {
      specificFixtures = [specificFixtures];
    }
    var promises = [];
    Object.keys(fixtures).filter(function(key) {
      if (key === 'index') {
        return false;
      }
      if (specificFixtures && specificFixtures.indexOf(key) === -1) {
        return false;
      }
      return true;
    }).forEach(function(key) {
      var promise = fixtures[key].load().then(function(instances) {
        exports[key] = instances;
      });
      promises.push(promise);
    });
    return Promise.all(promises);
  }).catch(function(err) {
    console.error(err.stack);
  });
};

exports.unload = function() {
  if (sequelize.options.dialect === 'mysql') {
    return sequelize.query('SET FOREIGN_KEY_CHECKS = 0').then(function() {
      return sequelize.sync({ force: true });
    }).then(function() {
      return sequelize.query('SET FOREIGN_KEY_CHECKS = 1');
    });
  } else {
    return sequelize.sync({ force: true });
  }
};

Fix running SET command in sqlite


exports = module.exports = function(authenticate) {

  return function verify(req, token, cb) {
    authenticate(token, function(err, tkn, ctx) {
      if (err) { return cb(err); }

      // TODO: Check confirmation methods, etc

      var info = {};
      if (tkn.client) {
        info.client = tkn.client;
      }
      if (tkn.scope) {
        info.scope = tkn.scope;
      }

      if (!tkn.subject) {
        return cb(null, false);
      }
      return cb(null, tkn.subject, info);
    });
  };
};

exports['@require'] = [
  'http://i.bixbyjs.org/security/authentication/token/authenticate'
];

exports = module.exports = function(authenticate) {

  return function verify(req, token, cb) {
    authenticate(token, function(err, tkn, ctx) {
      if (err) { return cb(err); }

      // TODO: Check confirmation methods, etc

      var info = {};
      if (tkn.client) {
        info.client = tkn.client;
      }
      if (tkn.scope) {
        info.scope = tkn.scope;
      }

      if (!tkn.user) {
        return cb(null, false);
      }
      return cb(null, tkn.user, info);
    });
  };
};

exports['@require'] = [
  'http://i.bixbyjs.org/security/authentication/token/authenticate'
];

Switch from subject to user.


import React, {PropTypes} from 'react';

const puke = (obj) =>
{JSON.stringify(obj, 2, ' ')}

const Results = React.createClass({
    render() {
        return (

                Results: {puke(this.props)}

        );
    }
});

Results.propTypes = {
    isLoading: PropTypes.bool.isRequired,
    playersInfo: PropTypes.array.isRequired,
    scores: PropTypes.array.isRequired
}

export default Results;

import React, {PropTypes} from 'react';
import {Link} from 'react-router';

import UserDetails from './UserDetails';
import UserDetailsWrapper from './UserDetailsWrapper';

const StartOver = () => {
    return (

            <Link to="/playerOne">
                <button type="button" className="btn btn-lg btn-danger">
                    Start Over
                </button>
            </Link>

    )
}

const Results = React.createClass({
    render() {
        const winnerIndex = this.props.scores[0] > this.props.scores[1] ? 0 : 1;
        const loserIndex = 1 - winnerIndex; // 1 - [0] = 1 ; 1 - [1] = 0

        if (this.props.isLoading) {
            return (

LOADING...

            )
        }

        if (this.props.scores[0] === this.props.scores[1]) {
            return (

It's a tie

                    <StartOver />

            )
        }

        return (

Results

                    <UserDetailsWrapper header="Winner">
                        <UserDetails score={this.props.scores[winnerIndex]} info={this.props.playersInfo[winnerIndex]} />
                    </UserDetailsWrapper>

                    <UserDetailsWrapper header="Loser">
                        <UserDetails score={this.props.scores[loserIndex]} info={this.props.playersInfo[loserIndex]} />
                    </UserDetailsWrapper>

                <StartOver />

        );
    }
});

Results.propTypes = {
    isLoading: PropTypes.bool.isRequired,
    playersInfo: PropTypes.array.isRequired,
    scores: PropTypes.array.isRequired
}

export default Results;

Add the score result to the UI to show the battle's winner


var express = require('express');
var kue = require('kue');
var Bot = require('../models/bot');

var router = express.Router();

/* GET home page. */
router.get('/', function(req, res, next) {
  res.render('index');
});

router.post('/destroy_jobs', function(req, res, next) {
  kue.Job.rangeByState('delayed', 0, 10000, 'asc', function( err, jobs ) {
    jobs.forEach(function(job) {
      job.remove(function() {});
    });
    res.send();
  });
});

router.post('/destroy_all_the_things', function(req, res, next) {
  kue.Job.rangeByState('delayed', 0, 10000, 'asc', function( err, jobs ) {
    jobs.forEach(function(job) {
      job.remove()
      .then(function(res) {
      })
      .catch(function(err) {
        res.status(500).send(err);
      });
    });
  });
  Bot.remove({})
  .then(function(result) {
  })
  .catch(function(err) {
    res.status(500).send(err);
  });
  res.send();
});

module.exports = router;

var express = require('express');
var kue = require('kue');
var Bot = require('../models/bot');

var router = express.Router();

/* GET home page. */
router.get('/', function(req, res, next) {
  res.render('index');
});

router.post('/destroy_jobs', function(req, res, next) {
  kue.Job.rangeByState('delayed', 0, 10000, 'asc', function( err, jobs ) {
    jobs.forEach(function(job) {
      job.remove(function() {});
    });
    res.send();
  });
});

router.post('/destroy_all_the_things', function(req, res, next) {
  kue.Job.rangeByState('delayed', 0, 10000, 'asc', function( err, jobs ) {
    jobs.forEach(function(job) {
      job.remove(function(err) {
        if (err) console.log(err);
      });
    });
  });
  Bot.remove({})
  .then(function(result) {
  })
  .catch(function(err) {
    res.status(500).send(err);
  });
  res.send();
});

module.exports = router;

Fix error handler on remove job


var glimpse = require('glimpse');
var store = require('store.js');

var _storeSummaryKey = 'glimpse.data.summary',
    _storeDetailKey = 'glimpse.data.request';
// store Found Summary
(function() {
    function storeFoundSummary(data) {
      store.set(_storeSummaryKey, data);
    }

    glimpse.on('data.request.summary.found.remote', storeFoundSummary);
    glimpse.on('data.request.summary.found.stream', storeFoundSummary);
})();

// store Found Detail
(function() {
    function storeFoundDetail(data) {
      var key = _storeDetailKey + '.' + data.id;
      store.set(key, data);
    }

    glimpse.on('data.request.detail.found.remote', storeFoundDetail);
})();

module.exports = {
    triggerGetLastestSummaries: function() {
        var data = store.get(_storeSummaryKey);
        if(data && data.length > 0)
          glimpse.emit('data.request.summary.found.local', data);
    },
    triggerGetDetailsFor: function(requestId) {
        var data = store.get(_storeDetailKey + '.' + requestId);
        if(data && data.length > 0)
          glimpse.emit('data.request.detail.found.local', data);
    }
};

var glimpse = require('glimpse');
var store = require('store.js');

var _storeSummaryKey = 'glimpse.data.summary',
    _storeDetailKey = 'glimpse.data.request';
// store Found Summary
(function() {
    //TODO: Need to complete
    //Push into local storage
    //address error handling, flushing out old data
    function storeFoundSummary(data) {
      store.set(_storeSummaryKey, data);
    }

    glimpse.on('data.request.summary.found.remote', storeFoundSummary);
    glimpse.on('data.request.summary.found.stream', storeFoundSummary);
})();

// store Found Detail
(function() {
    //TODO: Need to complete
    //Push into local storage
    //address error handling, flushing out old data
    function storeFoundDetail(data) {
      var key = _storeDetailKey + '.' + data.id;
      store.set(key, data);
    }

    glimpse.on('data.request.detail.found.remote', storeFoundDetail);
})();

module.exports = {
    triggerGetLastestSummaries: function() {
      //TODO: Need to complete
      //Pull from local storage
      //address error handling
        var data = store.get(_storeSummaryKey);
        if(data && data.length > 0)
          glimpse.emit('data.request.summary.found.local', data);
    },
    triggerGetDetailsFor: function(requestId) {
      //TODO: Need to complete
      //Pull from local storage
      //address error handling
        var data = store.get(_storeDetailKey + '.' + requestId);
        if(data && data.length > 0)
          glimpse.emit('data.request.detail.found.local', data);
    }
};

Add todo comments for local storage request repository


/* global localStorage */
import axios from 'axios';

export const BASE_URL = process.env.REACT_APP_API_URL;

const request = (endpoint, { headers = {}, body, ...otherOptions }, method) => {
  return axios(`${BASE_URL}${endpoint}`, {
    ...otherOptions,
    headers: {
      ...headers,
      Authorization: `Bearer ${localStorage.getItem('jwt.token')}}`,
      Accept: 'application/json',
      'Content-Type': 'application/json',
    },
    data: body ? JSON.stringify(body) : undefined,
    method,
  });
};

export const api = {
  get(endpoint, options = {}) {
    return request(endpoint, options, 'get');
  },
  post(endpoint, options = {}) {
    return request(endpoint, options, 'post');
  },
};

export default api;

/* global window */
import axios from 'axios';

export const BASE_URL = process.env.REACT_APP_API_URL;

const getToken = () => {
  return window.localStorage.getItem('jwt.token');
};

const setToken = ({ newToken }) => {
  window.localStorage.setItem('jwt.token', newToken);
};

const abstractRequest = (endpoint, { headers = {}, body, ...otherOptions }, method) => {
  return axios(`${BASE_URL}${endpoint}`, {
    ...otherOptions,
    headers: {
      ...headers,
      Authorization: `Bearer ${getToken()}`,
      Accept: 'application/json',
      'Content-Type': 'application/json',
    },
    data: body ? JSON.stringify(body) : undefined,
    method,
  });
};

const checkForRefreshToken = (endpoint, content, method) => (error) => {
  if (error.response && error.response.status === 401) {
    return abstractRequest('/auth/refresh', {}, 'post').then(({ data }) => {
      setToken(data);

      return abstractRequest(endpoint, content, method);
    });
  }
  return Promise.reject(error);
};

const checkForRelogin = error => {
  if (!error.response || !error.response.data || window.location.pathname === '/login') {
    return Promise.reject(error);
  }

  const message = error.response.data.error;

  if (['token_expired', 'token_invalid', 'token_not_provided'].includes(message)) {
    window.location = '/login';
  }

  return Promise.reject(error);
};

const request = (endpoint, content, method) => {
  return abstractRequest(endpoint, content, method)
    .catch(checkForRefreshToken(endpoint, content, method))
    .catch(checkForRelogin);
};

export const api = {
  get(endpoint, options = {}) {
    return request(endpoint, options, 'get');
  },
  post(endpoint, options = {}) {
    return request(endpoint, options, 'post');
  },
};

export default api;

Refresh JWT token if expires


(function() {

	var rule = data.rules[parseInt(request.param.num, 10)] || null;

	if (rule === null) return response.error(404);

	switch (request.method) {
		case 'PUT':
			var cmd = '';

			switch (request.param.action) {
				case 'enable':
					cmd = 'node app-cli.js -mode rule --enable -n ' + request.param.num;
					break;
				case 'disable':
					cmd = 'node app-cli.js -mode rule --disable -n ' + request.param.num;
					break;
			}

			child_process.exec(cmd, function(err, stdout, stderr) {
				if (err) return response.error(500);

				response.head(200);
				response.end('{}');
			});
			return;
	}

})();

(function() {

	var num = parseInt(request.param.num, 10).toString(10);
	var rule = data.rules[num] || null;

	if (rule === null) return response.error(404);

	switch (request.method) {
		case 'PUT':
			var cmd = '';

			switch (request.param.action) {
				case 'enable':
					cmd = 'node app-cli.js -mode rule --enable -n ' + num;
					break;
				case 'disable':
					cmd = 'node app-cli.js -mode rule --disable -n ' + num;
					break;
			}

			child_process.exec(cmd, function(err, stdout, stderr) {
				if (err) return response.error(500);

				response.head(200);
				response.end('{}');
			});
			return;
	}

})();

Fix same rule parameter validation


SpreeStore.module('Checkout',function(Checkout, SpreeStore, Backbone,Marionette,$,_){
  Checkout.Controller = {
    show: function(state) {
      SpreeStore.noSidebar()
      order = new SpreeStore.Models.Order({ number: SpreeStore.current_order_id })
      order.fetch({
        data: $.param({ order_token: SpreeStore.current_order_token}),
        success: function(order) {
          if (order.attributes.state == "complete") {
            SpreeStore.navigate("/orders/" + order.attributes.number, true)
          } else {
            Checkout.Controller.renderFor(order, state)
          }
        }
      })
    },

    renderFor: function(order, state) {
      state = state || order.attributes.state
      SpreeStore.navigate("/checkout/" + state)
      orderView = Checkout[state + 'View']
      if (orderView != undefined) {
        SpreeStore.mainRegion.show(new orderView({model: order}))
      } else {
        SpreeStore.navigate("/checkout/" + order.attributes.state)
        this.renderFor(order, order.attributes.state)
      }
    }
  }
})

SpreeStore.module('Checkout',function(Checkout, SpreeStore, Backbone,Marionette,$,_){
  Checkout.Controller = {
    show: function(state) {
      SpreeStore.noSidebar()
      order = new SpreeStore.Models.Order({ number: SpreeStore.current_order_id })
      order.fetch({
        data: $.param({ order_token: SpreeStore.current_order_token}),
        success: function(order) {
          if (order.attributes.state == "complete") {
            window.localStorage.removeItem('current_order_id');
            window.localStorage.removeItem('current_order_token');
            SpreeStore.navigate("/orders/" + order.attributes.number, true)
          } else {
            Checkout.Controller.renderFor(order, state)
          }
        }
      })
    },

    renderFor: function(order, state) {
      state = state || order.attributes.state
      SpreeStore.navigate("/checkout/" + state)
      orderView = Checkout[state + 'View']
      if (orderView != undefined) {
        SpreeStore.mainRegion.show(new orderView({model: order}))
      } else {
        SpreeStore.navigate("/checkout/" + order.attributes.state)
        this.renderFor(order, order.attributes.state)
      }
    }
  }
})

Clear localStorage order variables when order is complete


/* All related comment actions will be managed here */
/* appending comment see views/comments/create.js.erb */

$(function(){

  // declare variables for link, button, form ids
  var viewCommentForm = '#view_comment_form';
  var commentForm = '#comment_form';
  var newComment = '#new_comment';

  toggleLink(commentForm);  // initially hide comment form

  // show/hide form when user clicks on comment
  $('h3').on('click', viewCommentForm, function(e) {
    e.preventDefault();
    toggleLink(commentForm);
  });

  // edit form text when user clicks on comment
  $('h3').on('click', viewCommentForm, function(e) {
    e.preventDefault();
    $(viewCommentForm).text(toggleLinkText($(viewCommentForm)));  // set text depending on current text
  });

  // remove comments form when user submits
  $(commentForm).on('submit', newComment, function(e) {
    e.preventDefault();
    toggleLink(commentForm);
    $(viewCommentForm).text(toggleLinkText($(viewCommentForm)));
  });

});

/*** Helper Methods Below ***/

// toggle between show and hidden
function toggleLink(selector) {
  $(selector).toggle("medium");
}

// toggle text on link/button depending on what is currently set
function toggleLinkText(linkText) {
  text = linkText.text();
  var text = text === "Add a comment" ? "Cancel comment" : "Add a comment";
  return text;
}

/* All related comment actions will be managed here */
/* appending comment see views/comments/create.js.erb */

$(function(){

  // declare variables for link, button, form ids
  var viewCommentForm = '#view_comment_form';
  var commentForm = '#comment_form';
  var newComment = '#new_comment';

  toggleLink(commentForm);  // initially hide comment form

  // show/hide form when user clicks on comment
  $('h3').on('click', viewCommentForm, function(e) {
    e.preventDefault();
    toggleLink(commentForm);
  });

  // edit form text when user clicks on comment
  $('h3').on('click', viewCommentForm, function(e) {
    e.preventDefault();
    changeFormText(viewCommentForm); // set text depending on current text
  });

  // remove comments form when user submits
  $(commentForm).on('submit', newComment, function(e) {
    e.preventDefault();
    clearFormText();                                      // clear form contents
    toggleLink(commentForm);                              // remove form from view
    changeFormText(viewCommentForm);                      // toggle link/button text
  });

});

/*** Helper Methods Below ***/

// toggle between show and hidden
function toggleLink(selector) {
  $(selector).toggle("medium");
}

// toggle text on link/button depending on what is currently set
function toggleLinkText(linkText) {
  text = linkText.text();
  var text = text === "Add a comment" ? "Cancel comment" : "Add a comment";
  return text;
}

// change text on comment form link/button
function changeFormText(form) {
  $(form).text(toggleLinkText($(form)));
}

// clear tiny mce form text after user submits
function clearFormText() {
  tinyMCE.activeEditor.setContent('');
}

Clean up file and remove editor text on submit


import React, { Component, PropTypes } from 'react';
import { openModal } from 'actions/uiActions';
import Icon from 'utils/icons';
import ConfirmModal from '../Modals/ConfirmModal';

export default class DeleteIcon extends Component {
  static propTypes = {
    onClick: PropTypes.func.isRequired,
    message: PropTypes.string.isRequired,
    dispatch: PropTypes.func.isRequired,
  };

  constructor(props) {
    super(props);
    this.onClick = this.onClick.bind(this);
  }

  onClick() {
    const { onClick, message, dispatch } = this.props;
    dispatch(openModal(
      <ConfirmModal
        confirm={onClick}
        message={message}
      />),
    );
  }

  render() {
    return (
      <button className="table__delete" onClick={this.onClick}><Icon icon="circleWithLine" /></button>
    );
  }
}

import React, { Component, PropTypes } from 'react';
import { openModal } from 'actions/uiActions';
import Icon from 'utils/icons';
import ConfirmModal from '../Modals/ConfirmModal';

export default class DeleteIcon extends Component {
  static propTypes = {
    onClick: PropTypes.func.isRequired,
    message: PropTypes.string,
    dispatch: PropTypes.func.isRequired,
  }

  static defaultProps = {
    message: undefined,
  }

  constructor(props) {
    super(props);
    this.onClick = this.onClick.bind(this);
  }

  onClick() {
    const { onClick, message, dispatch } = this.props;
    dispatch(openModal(
      <ConfirmModal
        confirm={onClick}
        message={message}
      />),
    );
  }

  render() {
    return (
      <button type="button" className="table__delete" onClick={this.onClick}><Icon icon="circleWithLine" /></button>
    );
  }
}

Fix defaults for DeleteIcon message


var express = require('express');
_ = require('underscore')._
var request = require('request');
var router = express.Router({mergeParams: true});
var exec = require('child_process').exec;
var path = require('path');
var parentDir = path.resolve(process.cwd());

var jsonStream = require('express-jsonstream');

router.get('/', function(req, res, next) {
    res.json({'info' : 'This is the ControCurator API v0.1'});
});

router.post('/',function(req,res) {
    req.jsonStream()
        .on('object',console.log);
    return;

    var input = req.body;
    var amountofitems = input.length;

    var gooditems = 0;
    var baditems = 0;

    for (var i=0; i < amountofitems; i++)
    {
        var currentitem = input[i];
        if (!currentitem.hasOwnProperty('id') || !currentitem.hasOwnProperty('text')) //Test for an id and an actual body
        {
            baditems++;
            continue;
        }
        gooditems++;
    }
    var controscore = Math.random();

    res.json({'controversy':controscore,'totalItems':amountofitems,'goodItems':gooditems,'badItems':baditems});

});
module.exports = router;

var express = require('express');
_ = require('underscore')._
var request = require('request');
var router = express.Router({mergeParams: true});
var exec = require('child_process').exec;
var path = require('path');
var parentDir = path.resolve(process.cwd());

router.get('/', function(req, res, next) {
    res.json({'info' : 'This is the ControCurator API v0.1'});
});

router.post('/',function(req,res) {
    var input = req.body;
    var amountofitems = input.length;

    var gooditems = 0;
    var baditems = 0;

    for (var i=0; i < amountofitems; i++)
    {
        var currentitem = input[i];
        if (!currentitem.hasOwnProperty('id') || !currentitem.hasOwnProperty('text')) //Test for an id and an actual body
        {
            baditems++;
            continue;
        }
        gooditems++;
    }
    var controscore = Math.random();

    res.json({'controversy':controscore,'totalItems':amountofitems,'goodItems':gooditems,'badItems':baditems});

});
module.exports = router;

Revert back to limited situation


var innerInitialize = function() {
    console.log("It's the editor, man");
}

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

var innerInitialize = function() {
    // Create the canvas and context
    initCanvas($(window).width(), $(window).height());
    // initialize the camera
    camera = new Camera();
}

Create the canvas on editor start


// node dependencies
var express = require('express');

var db = require('./db');
var passport = require('passport');
var morgan = require('morgan');
var parser = require('body-parser');

// custom dependencies
var db = require('../db/Listings.js');
var db = require('../db/Users.js');
var db = require('../db/Categories.js');

// use middleware
server.use(session({
  secret: 'hackyhackifiers',
  resave: false,
  saveUninitialized: true
}));
server.use(passport.initialize());
server.use(passport.session());

// Router

var app = express();

// configure passport
// passport.use(new LocalStrategy(User.authenticate()));
// passport.serializeUser(User.serializeUser());
// passport.deserializeUser(User.deserializeUser());

// Set what we are listening on.
app.set('port', 3000);

// Logging and parsing
app.use(morgan('dev'));
app.use(parser.json());

// Set up and use our routes
// app.use('/', router);
// var router = require('./routes.js');
// Serve the client files

app.use(express.static(__dirname + '/../client'));

// If we are being run directly, run the server.
if (!module.parent) {
  app.listen(app.get('port'));
  console.log('Listening on', app.get('port'));
}

module.exports.app = app;

// node dependencies
var express = require('express');
var session = require('express-session');
var passport = require('passport');
var morgan = require('morgan');
var parser = require('body-parser');

// custom dependencies
var db = require('../db/db.js');
// var db = require('../db/Listings.js');
// var db = require('../db/Users.js');
// var db = require('../db/Categories.js');

var app = express();

// use middleware
app.use(session({
  secret: 'hackyhackifiers',
  resave: false,
  saveUninitialized: true
}));
app.use(passport.initialize());
app.use(passport.session());

// Router

// configure passport
// passport.use(new LocalStrategy(User.authenticate()));
// passport.serializeUser(User.serializeUser());
// passport.deserializeUser(User.deserializeUser());

// Set what we are listening on.
app.set('port', 3000);

// Logging and parsing
app.use(morgan('dev'));
app.use(parser.json());

// Set up and use our routes
// app.use('/', router);
// var router = require('./routes.js');
// Serve the client files

app.use(express.static(__dirname + '/../client'));

// If we are being run directly, run the server.
if (!module.parent) {
  app.listen(app.get('port'));
  console.log('Listening on', app.get('port'));
}

module.exports.app = app;

Fix db-connect commit (to working server state!)


/* eslint no-console: 0 */

import webpack from 'webpack';
import WebpackDevServer from 'webpack-dev-server';
import config from './webpack.config.babel';
import open from 'open';

const webpackServer = new WebpackDevServer(webpack(config), config.devServer);

webpackServer.listen(config.port, 'localhost', (err) => {
  if (err) {
    console.log(err);
  }

  console.log(`Listening at localhost: ${config.devServer.port}`);
  console.log('Opening your system browser...');
  open(`http://localhost:${config.devServer.port}/webpack-dev-server/`);
});

Allow console.log statement in server


const i = require('itemDataRefresher.js');

fateBus.subscribe(module, 'fate.configurationLoaded', function(topic, configuration) {
  new i.ItemDataRefresher('roll', configuration.shaderDataTSV)
});

const i = require('itemDataRefresher.js');

fateBus.subscribe(module, 'fate.configurationLoaded', function(topic, configuration) {
  new i.ItemDataRefresher('roll', configuration.rollDataTSV)
});

Use the right TSV data source


var myApp = angular.module('CordovaAppHarness', ['ngRoute']);

myApp.config(['$routeProvider', function($routeProvider){
    $routeProvider.when('/', {
        templateUrl: 'views/list.html',
        controller: 'ListCtrl'
    });
    $routeProvider.when('/add', {
        templateUrl: 'views/add.html',
        controller: 'AddCtrl'
    });
    $routeProvider.when('/edit/:appId', {
        templateUrl: 'views/add.html',
        controller: 'AddCtrl'
    });
    $routeProvider.when('/details/:index', {
        templateUrl: 'views/details.html',
        controller: 'DetailsCtrl'
    });
}]);

// foo
document.addEventListener('deviceready', function() {
    cordova.plugins.fileextras.getDataDirectory(false, function(dirEntry) {
        var path = dirEntry.fullPath;
        myApp.value('INSTALL_DIRECTORY', path + '/apps');
        myApp.value('APPS_JSON', path + '/apps.json');

        myApp.factory('UrlCleanup', function() {
            return function(url) {
                url = url.replace(/\/$/, '').replace(new RegExp(cordova.platformId + '$'), '').replace(/\/$/, '');
                if (!/^[a-z]+:/.test(url)) {
                    url = 'http://' + url;
                }
                return url;
            };
        });

        angular.bootstrap(document, ['CordovaAppHarness']);
    });
}, false);

var myApp = angular.module('CordovaAppHarness', ['ngRoute']);

myApp.config(['$routeProvider', function($routeProvider){
    $routeProvider.when('/', {
        templateUrl: 'views/list.html',
        controller: 'ListCtrl'
    });
    $routeProvider.when('/add', {
        templateUrl: 'views/add.html',
        controller: 'AddCtrl'
    });
    $routeProvider.when('/edit/:appId', {
        templateUrl: 'views/add.html',
        controller: 'AddCtrl'
    });
    $routeProvider.when('/details/:index', {
        templateUrl: 'views/details.html',
        controller: 'DetailsCtrl'
    });
}]);

// foo
document.addEventListener('deviceready', function() {
    cordova.filesystem.getDataDirectory(false, function(dirEntry) {
        var path = dirEntry.fullPath;
        myApp.value('INSTALL_DIRECTORY', path + '/apps');
        myApp.value('APPS_JSON', path + '/apps.json');

        myApp.factory('UrlCleanup', function() {
            return function(url) {
                url = url.replace(/\/$/, '').replace(new RegExp(cordova.platformId + '$'), '').replace(/\/$/, '');
                if (!/^[a-z]+:/.test(url)) {
                    url = 'http://' + url;
                }
                return url;
            };
        });

        angular.bootstrap(document, ['CordovaAppHarness']);
    });
}, false);

Use updated symbol path for file-system-roots plugin


//electron entry-point

const REACT_DEVELOPER_TOOLS = require('electron-devtools-installer').REACT_DEVELOPER_TOOLS;
var installExtension = require('electron-devtools-installer').default;
var app = require('electron').app;
var BrowserWindow = require('electron').BrowserWindow;
var path = require( "path" );

if (process.env.NODE_ENV === 'development') {
  require('electron-debug')(); // eslint-disable-line global-require
}

app.on('ready',function() {

installExtension(REACT_DEVELOPER_TOOLS)
  .then((name) => console.log(`Added Extension:  ${name}`))
  .catch((err) => console.log('An error occurred: ', err));

  var mainWindow = new BrowserWindow({
    width: 1200,
    height: 600
  });
  mainWindow.loadURL('file://' + __dirname + '/src/index-electron.html');

  mainWindow.webContents.on('did-finish-load', () => {
    mainWindow.show();
    mainWindow.focus();
  });

  mainWindow.on('closed', () => {
    mainWindow = null;
  });

  if (process.env.NODE_ENV === 'development') {
    mainWindow.openDevTools();
  }

});

//electron entry-point
var app = require('electron').app;
var BrowserWindow = require('electron').BrowserWindow;
var path = require( "path" );

if (process.env.NODE_ENV === 'development') {
  require('electron-debug')(); // eslint-disable-line global-require
}

app.on('ready',function() {

if(process.env.NODE_ENV === 'development') {
  const REACT_DEVELOPER_TOOLS = require('electron-devtools-installer').REACT_DEVELOPER_TOOLS;
  var installExtension = require('electron-devtools-installer').default;
  installExtension(REACT_DEVELOPER_TOOLS)
  .then((name) => console.log(`Added Extension:  ${name}`))
  .catch((err) => console.log('An error occurred: ', err));
}

  var mainWindow = new BrowserWindow({
    width: 1200,
    height: 600
  });
  mainWindow.loadURL('file://' + __dirname + '/src/index-electron.html');

  mainWindow.webContents.on('did-finish-load', () => {
    mainWindow.show();
    mainWindow.focus();
  });

  mainWindow.on('closed', () => {
    mainWindow = null;
  });

  if (process.env.NODE_ENV === 'development') {
    mainWindow.openDevTools();
  }

});

Load react-devtools in dev env only


//
// See https://github.com/jenkinsci/js-builder
//
var builder = require('@jenkins-cd/js-builder');

// Disable js-builder based linting for now.
// Will get fixed with https://github.com/cloudbees/blueocean/pull/55
builder.lint('none');

//
// Create the main "App" bundle.
// generateNoImportsBundle makes it easier to test with zombie.
//
builder.bundle('src/main/js/blueocean.js')
    .withExternalModuleMapping('jquery-detached', 'jquery-detached:jquery2')
    .inDir('target/classes/io/jenkins/blueocean')
    .less('src/main/less/blueocean.less')
    .generateNoImportsBundle();

//
// See https://github.com/jenkinsci/js-builder
//
var builder = require('@jenkins-cd/js-builder');

// Disable js-builder based linting for now.
// Will get fixed with https://github.com/cloudbees/blueocean/pull/55
builder.lint('none');

// Explicitly setting the src paths in order to allow the rebundle task to
// watch for changes in the JDL (js, css, icons etc).
// See https://github.com/jenkinsci/js-builder#setting-src-and-test-spec-paths
builder.src(['src/main/js', 'src/main/less', 'node_modules/@jenkins-cd/design-language']);

//
// Create the main "App" bundle.
// generateNoImportsBundle makes it easier to test with zombie.
//
builder.bundle('src/main/js/blueocean.js')
    .withExternalModuleMapping('jquery-detached', 'jquery-detached:jquery2')
    .inDir('target/classes/io/jenkins/blueocean')
    .less('src/main/less/blueocean.less')
    .generateNoImportsBundle();

Watch for changes in the JDL package (rebundle)


import React, { Component } from 'react';
import PropTypes from 'prop-types';
import { View, StyleSheet, TouchableWithoutFeedback, Animated } from 'react-native';
import { OPEN_ANIM_DURATION, CLOSE_ANIM_DURATION } from './constants';

class Backdrop extends Component {

  constructor(...args) {
    super(...args);
    this.fadeAnim = new Animated.Value(0.001);
  }

  open() {
    return new Promise(resolve => {
      Animated.timing(this.fadeAnim, {
        duration: OPEN_ANIM_DURATION,
        toValue: 1,
        useNativeDriver: true,
      }).start(resolve);
    });
  }

  close() {
    return new Promise(resolve => {
      Animated.timing(this.fadeAnim, {
        duration: CLOSE_ANIM_DURATION,
        toValue: 0,
        useNativeDriver: true,
      }).start(resolve);
    });
  }

  render() {
    const { onPress, style } = this.props;
    return (
      <TouchableWithoutFeedback onPress={onPress}>
        <Animated.View style={[styles.fullscreen, { opacity: this.fadeAnim }]}>
          <View style={[styles.fullscreen, style]} />
        </Animated.View>
      </TouchableWithoutFeedback>
    );
  }

}

Backdrop.propTypes = {
  onPress: PropTypes.func.isRequired,
};

const styles = StyleSheet.create({
  fullscreen: {
    opacity: 0,
    position: 'absolute',
    top: 0,
    left: 0,
    bottom: 0,
    right: 0,
  },
});

export default Backdrop;

import React, { Component } from 'react';
import PropTypes from 'prop-types';
import { View, StyleSheet, TouchableWithoutFeedback, Animated, Platform } from 'react-native';
import { OPEN_ANIM_DURATION, CLOSE_ANIM_DURATION } from './constants';

class Backdrop extends Component {

  constructor(...args) {
    super(...args);
    this.fadeAnim = new Animated.Value(0.001);
  }

  open() {
    return new Promise(resolve => {
      Animated.timing(this.fadeAnim, {
        duration: OPEN_ANIM_DURATION,
        toValue: 1,
        useNativeDriver: (Platform.OS !== "web"),
      }).start(resolve);
    });
  }

  close() {
    return new Promise(resolve => {
      Animated.timing(this.fadeAnim, {
        duration: CLOSE_ANIM_DURATION,
        toValue: 0,
        useNativeDriver: (Platform.OS !== "web"),
      }).start(resolve);
    });
  }

  render() {
    const { onPress, style } = this.props;
    return (
      <TouchableWithoutFeedback onPress={onPress}>
        <Animated.View style={[styles.fullscreen, { opacity: this.fadeAnim }]}>
          <View style={[styles.fullscreen, style]} />
        </Animated.View>
      </TouchableWithoutFeedback>
    );
  }

}

Backdrop.propTypes = {
  onPress: PropTypes.func.isRequired,
};

const styles = StyleSheet.create({
  fullscreen: {
    opacity: 0,
    position: 'absolute',
    top: 0,
    left: 0,
    bottom: 0,
    right: 0,
  },
});

export default Backdrop;

Fix web warning about useNativeDriver


/* jshint node: true */

module.exports = function(environment) {
  var ENV = {
    modulePrefix: 'client',
    environment: environment,
    baseURL: '/',
    locationType: 'auto',

    'ember-simple-auth-token': {
      serverTokenEndpoint: 'http://localhost:8080/api-token-auth/',
      serverTokenRefreshEndpoint: 'http://localhost:8080/api-token-refresh/',
      refreshLeeway: 20
    },

    EmberENV: {
      FEATURES: {
        // Here you can enable experimental features on an ember canary build
        // e.g. 'with-controller': true
      }
    },

    APP: {
      // Here you can pass flags/options to your application instance
      // when it is created
    }
  };

  if (environment === 'development') {
    // ENV.APP.LOG_RESOLVER = true;
    // ENV.APP.LOG_ACTIVE_GENERATION = true;
    // ENV.APP.LOG_TRANSITIONS = true;
    // ENV.APP.LOG_TRANSITIONS_INTERNAL = true;
    // ENV.APP.LOG_VIEW_LOOKUPS = true;
  }

  if (environment === 'test') {
    // Testem prefers this...
    ENV.baseURL = '/';
    ENV.locationType = 'none';

    // keep test console output quieter
    ENV.APP.LOG_ACTIVE_GENERATION = false;
    ENV.APP.LOG_VIEW_LOOKUPS = false;

    ENV.APP.rootElement = '#ember-testing';
  }

  if (environment === 'production') {

  }

  return ENV;
};

/* jshint node: true */

module.exports = function(environment) {
  var ENV = {
    modulePrefix: 'client',
    environment: environment,
    baseURL: '/',
    locationType: 'auto',

    'ember-simple-auth-token': {
      serverTokenEndpoint: 'http://localhost:8080/api-token-auth/',
      serverTokenRefreshEndpoint: 'http://localhost:8080/api-token-refresh/',
      refreshLeeway: 20,
      timeFactor: 1000, // backend is in seconds and the frontend is in ms.
    },

    EmberENV: {
      FEATURES: {
        // Here you can enable experimental features on an ember canary build
        // e.g. 'with-controller': true
      }
    },

    APP: {
      // Here you can pass flags/options to your application instance
      // when it is created
    }
  };

  if (environment === 'development') {
    // ENV.APP.LOG_RESOLVER = true;
    // ENV.APP.LOG_ACTIVE_GENERATION = true;
    // ENV.APP.LOG_TRANSITIONS = true;
    // ENV.APP.LOG_TRANSITIONS_INTERNAL = true;
    // ENV.APP.LOG_VIEW_LOOKUPS = true;
  }

  if (environment === 'test') {
    // Testem prefers this...
    ENV.baseURL = '/';
    ENV.locationType = 'none';

    // keep test console output quieter
    ENV.APP.LOG_ACTIVE_GENERATION = false;
    ENV.APP.LOG_VIEW_LOOKUPS = false;

    ENV.APP.rootElement = '#ember-testing';
  }

  if (environment === 'production') {

  }

  return ENV;
};

Adjust the time factor to align frontent and backend auth.


/**
 * @depends MatrixStack.js
 */
var Camera = new Class({
    initialize: function() {
        this.projection = new MatrixStack();
        this.modelview = new MatrixStack();
    },

    perspective: function(fovy, aspect, near, far) {
        mat4.perspective(fovy, aspect, near, far, this.projection);
    },

    ortho: function(left, right, top, bottom, near, far) {
        mat4.ortho(left, right, top, bottom, near, far, this.projection);
    },

    lookAt: function(eye, center, up) {
        mat4.lookAt(eye, center, up, this.modelview);
    }
});

/**
 * @depends MatrixStack.js
 */
var Camera = new Class({
    initialize: function() {
        this.projection = new MatrixStack();
        this.modelview = new MatrixStack();
    },

    perspective: function(fovy, aspect, near, far) {
        mat4.perspective(fovy, aspect, near, far, this.projection.matrix);
    },

    ortho: function(left, right, top, bottom, near, far) {
        mat4.ortho(left, right, top, bottom, near, far, this.projection.matrix);
    },

    lookAt: function(eye, center, up) {
        mat4.lookAt(eye, center, up, this.modelview.matrix);
    }
});

Make camera function actually affect the matrices


/* Copyright (c) Royal Holloway, University of London | Contact Blake Loring (blake@parsed.uk), Duncan Mitchell (Duncan.Mitchell.2015@rhul.ac.uk), or Johannes Kinder (johannes.kinder@rhul.ac.uk) for details or support | LICENSE.md for license details */

"use strict";

/**
 * This is a function that detects whether we are using Electron and
 * if so does a remote call through IPC rather than a direct require.
 */

 const ELECTRON_PATH_MAGIC = '/electron/';

export default function (library) {
	let lrequire = require;

	if (process && process.execPath && process.execPath.indexOf(ELECTRON_PATH_MAGIC) != -1) {
		lrequire = require('electron').remote.require;
	}

	const result = lrequire(library);

	return result.default ? result.default : result;
}

/* Copyright (c) Royal Holloway, University of London | Contact Blake Loring (blake@parsed.uk), Duncan Mitchell (Duncan.Mitchell.2015@rhul.ac.uk), or Johannes Kinder (johannes.kinder@rhul.ac.uk) for details or support | LICENSE.md for license details */

"use strict";

export default function (library) {
	return require(library);
}

Remove external electron link as we're rethinking that for now


var injection = require('../services/injection.js');
var Q = require('q');
var mongoose = require('mongoose');

module.exports = function (test, fixtureName, testFn) {
    var dbUrl = 'mongodb://localhost:27017/' + fixtureName;

    var cleanUp = function () {
        return Q.nbind(mongoose.connect, mongoose)(dbUrl).then(function () {
            var db = mongoose.connection.db;
            return Q.nbind(db.dropDatabase, db)().then(function () {
                db.close();
            });
        });
    };

    cleanUp().then(function () {
        var allcountServer = require('../allcount-server.js');

        injection.resetInjection();
        injection.bindFactory('port', 9080);
        injection.bindFactory('dbUrl', dbUrl);
        injection.bindFactory('gitRepoUrl', 'test-fixtures/' + fixtureName);

        allcountServer.reconfigureAllcount();
        return allcountServer.inject('allcountServerStartup');
    }).then(function (server) {
        return Q.nbind(server.startup, server)().then(function (errors) {
            if (errors) {
                throw new Error(errors.join('\n'));
            }
            return Q(testFn()).then(function () {
                return server.stop().then(function () {
                    injection.resetInjection();
                });
            });
        });
    }).finally(cleanUp).done(function () {
        test.done();
    });
};

var injection = require('../services/injection.js');
var Q = require('q');
var mongoose = require('mongoose');

module.exports = function (test, fixtureName, testFn) {
    var dbUrl = 'mongodb://localhost:27017/' + fixtureName;

    var cleanUp = function () {
        return Q.nbind(mongoose.connect, mongoose)(dbUrl).then(function () {
            var db = mongoose.connection.db;
            return Q.nbind(db.dropDatabase, db)().then(function () {
                db.close();
            });
        });
    };

    cleanUp().then(function () {
        var allcountServer = require('../allcount-server.js');

        injection.resetInjection();
        injection.bindFactory('port', 9080);
        injection.bindFactory('dbUrl', dbUrl);
        injection.bindFactory('gitRepoUrl', 'test-fixtures/' + fixtureName);

        allcountServer.reconfigureAllcount();
        return allcountServer.inject('allcountServerStartup');
    }).then(function (server) {
        return Q.nbind(server.startup, server)().then(function (errors) {
            if (errors) {
                throw new Error(errors.join('\n'));
            }
            return Q(testFn()).then(function () {
                return server.stop().then(function () {
                    injection.resetInjection();
                });
            });
        });
    }).finally(cleanUp).finally(function () {
        test.done();
    }).done();
};

Fix endless execution of integration tests


const path = require( 'path' );

module.exports = {
	preset: 'jest-puppeteer',
	setupFilesAfterEnv: [
		'<rootDir>/config/bootstrap.js',
		'@wordpress/jest-console',
		'expect-puppeteer',
	],
	testMatch: [
		'<rootDir>/**/*.test.js',
		'<rootDir>/specs/**/__tests__/**/*.js',
		'<rootDir>/specs/**/?(*.)(spec|test).js',
		'<rootDir>/specs/**/test/*.js',
	],
	transform: {
		'^.+\\.[jt]sx?$': path.join( __dirname, 'babel-transform' ),
	},
	transformIgnorePatterns: [ 'node_modules' ],
	testPathIgnorePatterns: [ '.git', 'node_modules' ],
};

const path = require( 'path' );

module.exports = {
	preset: 'jest-puppeteer',
	setupFilesAfterEnv: [
		'<rootDir>/config/bootstrap.js',
		'@wordpress/jest-console',
		'expect-puppeteer',
	],
	testMatch: [
		'<rootDir>/**/*.test.js',
		'<rootDir>/specs/**/__tests__/**/*.js',
		'<rootDir>/specs/**/?(*.)(spec|test).js',
		'<rootDir>/specs/**/test/*.js',
	],
	transform: {
		'^.+\\.[jt]sx?$': path.join( __dirname, 'babel-transform' ),
	},
	transformIgnorePatterns: [ 'node_modules' ],
	testPathIgnorePatterns: [ '.git', 'node_modules' ],
	verbose: true,
};

Add verbose option to E2E tests.


/**
 * @license
 * Copyright 2016 Google Inc. All Rights Reserved.
 *
 * Licensed under the Apache License, Version 2.0 (the License);
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 */

foam.CLASS({
  package: 'foam.u2',
  name: 'HTMLValidator',
  extends: 'foam.u2.DefaultValidator',

  axioms: [ foam.pattern.Singleton.create() ],

  methods: [
    function sanitizeText(text) {
      // TODO: validate text
      return text;
    }
  ]
});

// An Element which does not escape HTML content
foam.CLASS({
  package: 'foam.u2',
  name: 'HTMLElement',
  extends: 'foam.u2.Element',

  exports: [ 'validator as elementValidator' ],

  properties: [
    {
      class: 'Proxy',
      of: 'foam.u2.DefaultValidator',
      name: 'validator',
      value: foam.u2.HTMLValidator.create()
    }
  ]
});

/**
 * @license
 * Copyright 2016 Google Inc. All Rights Reserved.
 *
 * Licensed under the Apache License, Version 2.0 (the License);
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 */

foam.CLASS({
  package: 'foam.u2',
  name: 'HTMLValidator',
  extends: 'foam.u2.DefaultValidator',

  axioms: [ foam.pattern.Singleton.create() ],

  methods: [
    function sanitizeText(text) {
      // TODO: validate text
      return text;
    }
  ]
});

// An Element which does not escape HTML content
foam.CLASS({
  package: 'foam.u2',
  name: 'HTMLElement',
  extends: 'foam.u2.Element',

  requires: [ 'foam.u2.HTMLValidator' ],

  exports: [ 'validator as elementValidator' ],

  properties: [
    {
      class: 'Proxy',
      of: 'foam.u2.DefaultValidator',
      name: 'validator',
      factory: function() { return this.HTMLValidator.create() }
    }
  ]
});

Use a factory instead of creating an HTMLValidator inline.


require("../scss/index.scss");

var React = require('react');
var Locale = require('grommet/utils/Locale');
var Cabler = require('./components/Cabler');

var locale = Locale.getCurrentLocale();
var localeData;
try {
  localeData = Locale.getLocaleData(require('../messages/' + locale));
} catch (e) {
  localeData = Locale.getLocaleData(require('../messages/en-US'));
}

var element = document.getElementById('content');
React.render(React.createElement(Cabler, {locales: localeData.locale, messages: localeData.messages}), element);

document.body.classList.remove('loading');

require("../scss/index.scss");

var React = require('react');
var ReactDOM = require('react-dom');
var Locale = require('grommet/utils/Locale');
var Cabler = require('./components/Cabler');

var locale = Locale.getCurrentLocale();
var localeData;
try {
  localeData = Locale.getLocaleData(require('../messages/' + locale));
} catch (e) {
  localeData = Locale.getLocaleData(require('../messages/en-US'));
}

var element = document.getElementById('content');
ReactDOM.render(React.createElement(Cabler, {locales: localeData.locale, messages: localeData.messages}), element);

document.body.classList.remove('loading');

Use react-dom package for rendering application


(function (){
  /* ADAPTER
   *
   * This blanket.js adapter is designed to autostart coverage
   * immediately. The other side of this is handled from Cucumber
   *
   * Required blanket commands:
   * blanket.setupCoverage(); // Do it ASAP
   * blanket.onTestStart(); // Do it ASAP
   * blanket.onTestDone(); // After Scenario Hook
   * blanket.onTestsDone(); // After Scenario Hook
   */

  blanket.beforeStartTestRunner({
    callback: function() {
      blanket.setupCoverage();
      blanket.onTestStart();
    }
  });

  /* REPORTER
   *
   * Blanket.js docs speak of blanket.customReporter but
   * that doesn't actually work so we'll override defaultReporter
   */
  blanket.defaultReporter = function(coverage_results){
    window.COVERAGE_RESULTS = coverage_results; // We'll grab this on selenium side
  };
})();

(function (){
  /* ADAPTER
   *
   * This blanket.js adapter is designed to autostart coverage
   * immediately. The other side of this is handled from Cucumber
   *
   * Required blanket commands:
   * blanket.setupCoverage(); // Do it ASAP
   * blanket.onTestStart(); // Do it ASAP
   * blanket.onTestDone(); // After Scenario Hook (Not necessary)
   * blanket.onTestsDone(); // After Scenario Hook
   */

  blanket.beforeStartTestRunner({
    callback: function() {
      blanket.setupCoverage();
      blanket.onTestStart();
      window.CUCUMBER_BLANKET = {
        files: {},
        sources: {},
        done: false,
        is_setup: true
      };
    }
  });

  /* REPORTER
   *
   * Blanket.js docs speak of blanket.customReporter but
   * that doesn't actually work so we'll override defaultReporter
   */
  blanket.defaultReporter = function(coverage_results){
    window.CUCUMBER_BLANKET.files = coverage_results.files;
    // Strangely enough it looks like we need to iterate in order to grab the `source`
    // data which is necessary to know which lines of code are being reported on.
    var files = Object.keys(coverage_results.files);
    for (var i = 0, l = files.length; i < l; i ++) {
      var file = files[i];
      window.CUCUMBER_BLANKET.sources[file] = window.CUCUMBER_BLANKET.files[file].source;
    }
    window.CUCUMBER_BLANKET.done = true;
    // Now we can grab all this on the selenium side through window.CUCUMBER_BLANKET
  };
})();

Update javascript blanket adapter to include sources data.


import storage from './storage';
import {SVGRenderer} from 'scratch-svg-renderer';

// Contains 'font-family', but doesn't only contain 'font-family="none"'
const HAS_FONT_REGEXP = 'font-family(?!="none")';

const getCostumeUrl = (function () {
    let cachedAssetId;
    let cachedUrl;

    return function (asset) {

        if (cachedAssetId === asset.assetId) {
            return cachedUrl;
        }

        cachedAssetId = asset.assetId;

        // If the SVG refers to fonts, they must be inlined in order to display correctly in the img tag.
        // Avoid parsing the SVG when possible, since it's expensive.
        if (asset.assetType === storage.AssetType.ImageVector) {
            const svgString = asset.decodeText();
            if (svgString.match(HAS_FONT_REGEXP)) {
                const svgRenderer = new SVGRenderer();
                svgRenderer.loadString(svgString);
                const svgText = svgRenderer.toString(true /* shouldInjectFonts */);
                cachedUrl = `data:image/svg+xml;utf8,${encodeURIComponent(svgText)}`;
            } else {
                cachedUrl = asset.encodeDataURI();
            }
        } else {
            cachedUrl = asset.encodeDataURI();
        }

        return cachedUrl;
    };
}());

export {
    getCostumeUrl as default,
    HAS_FONT_REGEXP
};

import storage from './storage';
import {inlineSvgFonts} from 'scratch-svg-renderer';

// Contains 'font-family', but doesn't only contain 'font-family="none"'
const HAS_FONT_REGEXP = 'font-family(?!="none")';

const getCostumeUrl = (function () {
    let cachedAssetId;
    let cachedUrl;

    return function (asset) {

        if (cachedAssetId === asset.assetId) {
            return cachedUrl;
        }

        cachedAssetId = asset.assetId;

        // If the SVG refers to fonts, they must be inlined in order to display correctly in the img tag.
        // Avoid parsing the SVG when possible, since it's expensive.
        if (asset.assetType === storage.AssetType.ImageVector) {
            const svgString = asset.decodeText();
            if (svgString.match(HAS_FONT_REGEXP)) {
                const svgText = inlineSvgFonts(svgString);
                cachedUrl = `data:image/svg+xml;utf8,${encodeURIComponent(svgText)}`;
            } else {
                cachedUrl = asset.encodeDataURI();
            }
        } else {
            cachedUrl = asset.encodeDataURI();
        }

        return cachedUrl;
    };
}());

export {
    getCostumeUrl as default,
    HAS_FONT_REGEXP
};

Use fontInliner instead of entire SVGRenderer for showing costume tiles.


function hide_covers() {
    // Remove covers
    $(".mix_element div.cover").remove()
    // Add class so cards can be restyled
    $(".mix_card.half_card").addClass("ext-coverless_card")

    // Remove covers on track page
    $("#cover_art").remove()
    // Remove covers in the sidebar of a track page
    $(".card.sidebar_mix .cover").remove()
    $(".card.sidebar_mix").addClass("ext-coverless_card")
}

function filter() {
    chrome.storage.local.get("state", function(result) {
        if(result["state"] == "on") {
            hide_covers()
        }
    });
}
// Make sure that when we navigate the site (which doesn't refresh the page), the filter is still run
$('#body_container').bind('DOMSubtreeModified',filter);
filter();

function hide_covers() {
    // Remove covers
    $(".mix_element div.cover").remove()
    // Add class so cards can be restyled
    $(".mix_card.half_card").addClass("ext-coverless_card")

    // Remove covers on track page
    $("#cover_art").remove()
    // Remove covers in the sidebar of a track page
    $(".card.sidebar_mix .cover").remove()
    $(".card.sidebar_mix").addClass("ext-coverless_card")
}

function filter() {
    chrome.storage.local.get("state", function(result) {
        if(result["state"] == "on") {
            hide_covers()
        }
    });
}
// Make sure that when we navigate the site (which doesn't refresh the page), the filter is still run
var observer = new MutationObserver(filter)
observer.observe(document.getElementById("main"), {childList: true, subtree: true})
filter();

Use MutationObserver API to catch dom updates


// JS Goes here - ES6 supported
if (window.netlifyIdentity) {
  window.netlifyIdentity.on('login', () => {
    document.location.href = '/admin/';
  });
}

// JS Goes here - ES6 supported
if (window.netlifyIdentity && !window.netlifyIdentity.currentUser()) {
  window.netlifyIdentity.on('login', () => {
    document.location.href = '/admin/';
  });
}

Fix issue with always redirecting to /admin when logged in


/**
 * Detects if only the primary button has been clicked in mouse events.
 * @param {MouseEvent} e Event instance (or Event-like, i.e. `SyntheticEvent`)
 * @return {Boolean}
 */
export const isPrimaryClick = e =>
  !(e.altKey || e.ctrlKey || e.metaKey || e.shiftKey) &&
  (("button" in e && e.button === 0) || ("buttons" in e && e.buttons === 1));

/**
 * Decorates a function so it calls if only the primary button has been
 * pressed in mouse events.
 * @param {Function} fn
 * @return {Function}
 */
export const onPrimaryClick = fn => e => (isPrimaryClick(e) ? fn(e) : true);

/**
 * Detects if only the primary button has been clicked in mouse events.
 * @param {MouseEvent} e Event instance (or Event-like, i.e. `SyntheticEvent`)
 * @return {Boolean}
 */
export const isPrimaryClick = e =>
  !(e.altKey || e.ctrlKey || e.metaKey || e.shiftKey) &&
  (("button" in e && e.button === 0) || ("buttons" in e && e.buttons === 1));

/**
 * Decorates a function so it calls if only the primary button has been
 * pressed in mouse events.
 * @param {Function} fn
 * @return {Function}
 */
export const onPrimaryClick = fn => (e, ...args) =>
  isPrimaryClick(e, ...args) ? fn(e) : true;

Update onPrimaryClick to pass down multiple args