/**
 * https://github.com/Taranys/simplerating
 */
angular.module('SimpleRating', [])
    .directive('simpleRating', function () {
        return {
            restrict: 'A',
            template: '
' +
                '

' +
                '
',
            scope: {
                rating: "=",
                ratingMax: "=",
                readOnly: "="
            },
            link: function ($scope) {
                $scope.getStarClass = function (index) {
                    return ($scope.rating >= index) ? 'glyphicon-star' : 'glyphicon-star-empty';
                };

                $scope.$watch('rating', function () {
                    $scope.stars = [];
                    for (var i = 0; i < $scope.ratingMax; i++) {
                        $scope.stars.push({});
                    }
                });

                $scope.click = function (starRating) {
                    if (!$scope.readOnly) {
                        $scope.rating = starRating;
                    }
                };
            }
        };
    });

/**
 * https://github.com/Taranys/simplerating
 */
angular.module('SimpleRating', [])
    .directive('simpleRating', function () {
        return {
            restrict: 'A',
            template: '
' +
                '

' +
                '
',
            scope: {
                rating: "=",
                ratingMax: "=",
                readOnly: "="
            },
            link: function ($scope) {
                $scope.getStarClass = function (index) {
                    return ($scope.rating >= index) ? 'glyphicon-star' : 'glyphicon-star-empty';
                };

                $scope.getCursor = function() {
                    return { cursor : ($scope.readOnly?'not-allowed':'pointer') };
                };

                $scope.$watch('rating', function () {
                    $scope.stars = [];
                    for (var i = 0; i < $scope.ratingMax; i++) {
                        $scope.stars.push({});
                    }
                });

                $scope.click = function (starRating) {
                    if (!$scope.readOnly) {
                        $scope.rating = starRating;
                    }
                };
            }
        };
    });

Add cursor according to read only state


#!/usr/bin/env node
var commander = require('commander');
var proxy = require('./proxy.js');

commander
//  .version(meta.version)
  .usage('[options] <endpoint>')
  .option('-p, --port <n>', 'Local proxy port, default 9200', parseInt)
  .option('-p, --bindIf <ip>', 'Bind to interface, defaults to 127.0.0.1', /\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}/, '127.0.0.1')
  .parse(process.argv);

if (commander.args.length != 1) {
  console.error("Missing endpoint parameter");
  commander.outputHelp();
  process.exit(1);
}

var endpoint;
if (commander.args[0].startsWith('https://')) {
  endpoint = commander.args[0];
} else {
  endpoint = 'https://' + commander.args[0];
}

var region;
try {
  region = endpoint.match(/\.([^.]+)\.es\.amazonaws\.com\.?$/)[1];
} catch (e) {
  console.error('Region cannot be parsed from endpoint address');
  process.exit(1);
}

var config = {
  endpoint: endpoint,
  region: region,
  port: commander.port || 9200,
  bindAddress: commander.bindIf
}

proxy.run(config);

#!/usr/bin/env node
var commander = require('commander');
var proxy = require('./proxy.js');

commander
//  .version(meta.version)
  .usage('[options] <endpoint>')
  .option('-p, --port <n>', 'Local proxy port, default 9200', parseInt)
  .option('-b, --bindIf <ip>', 'Bind to interface, defaults to 127.0.0.1', /\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}/, '127.0.0.1')
  .parse(process.argv);

if (commander.args.length != 1) {
  console.error("Missing endpoint parameter");
  commander.outputHelp();
  process.exit(1);
}

var endpoint;
if (commander.args[0].startsWith('https://')) {
  endpoint = commander.args[0];
} else {
  endpoint = 'https://' + commander.args[0];
}

var region;
try {
  region = endpoint.match(/\.([^.]+)\.es\.amazonaws\.com\.?$/)[1];
} catch (e) {
  console.error('Region cannot be parsed from endpoint address');
  process.exit(1);
}

var config = {
  endpoint: endpoint,
  region: region,
  port: commander.port || 9200,
  bindAddress: commander.bindIf
}

proxy.run(config);

Rename short option to avoid conflicts


#!/usr/bin/env node
var colors = require('colors');
var ghlint = require('./index');
var util = require('util');

function printResults(repo, results) {
  console.log(repo + ':');
  results.forEach(function (result) {
    var mark = result.result ? '✓' : '✖';
    var output = util.format('  %s %s', mark, result.message);
    if (colors.enabled) {
      output = output[result.result ? 'green' : 'red'];
    }
    console.log(output);
  });
}

// Remove --no-color from the args if it is there.
process.argv = process.argv.filter(function (arg) {
  return arg !== '--no-color';
});

var repo = process.argv[2];
if (repo) {
  if (repo.indexOf('/') > -1) {
    ghlint.lintRepo(repo, function (err, linters) {
      if (err) {
        console.error(err);
      } else {
        printResults(repo, linters);
      }
    });
  } else {
    ghlint.lintUserRepos(repo, function (err, repos) {
      if (err) {
        console.error(err);
      } else {
        repos.forEach(function (repoResults) {
          printResults(repoResults.name, repoResults.results);
        });
      }
    });
  }
} else {
  console.error('Usage: ghlint <repo>');
}

#!/usr/bin/env node
var colors = require('colors');
var ghlint = require('./index');
var util = require('util');

function printResults(repo, results) {
  console.log(repo + ':');
  results.forEach(function (result) {
    var mark = result.result ? '✓' : '✖';
    var output = util.format('  %s %s', mark, result.message);
    if (colors.enabled) {
      output = output[result.result ? 'green' : 'red'];
    }
    console.log(output);
  });
}

// Remove --no-color from the args if it is there.
process.argv = process.argv.filter(function (arg) {
  return arg !== '--no-color';
});

var repo = process.argv[2];
if (repo) {
  if (repo.indexOf('/') > -1) {
    ghlint.lintRepo(repo, function (err, linters) {
      if (err) {
        console.error(err);
      } else {
        printResults(repo, linters);
      }
    });
  } else {
    ghlint.lintUserRepos(repo, function (err, repos) {
      if (err) {
        console.error(err);
      } else {
        repos.forEach(function (repoResults, index) {
          if (index !== 0) {
            console.log();
          }
          printResults(repoResults.name, repoResults.results);
        });
      }
    });
  }
} else {
  console.error('Usage: ghlint <repo>');
}

Add empty lines between repos in the results


// allow to require('riot')
var riot = module.exports = require(process.env.RIOT || require('path').resolve(__dirname, '../../riot'))

var compiler = require('riot-compiler')

// allow to require('riot').compile
riot.compile = compiler.compile
riot.parsers = compiler.parsers

// allow to require('some.tag')
require.extensions['.tag'] = function(module, filename) {
  var src = riot.compile(require('fs').readFileSync(filename, 'utf8'))
  module._compile(
    'var riot = require(process.env.RIOT || "riot/riot.js");module.exports =' + src
  , filename)
}

// simple-dom helper
var sdom = require('./sdom')

function createTag(tagName, opts) {
  var root = document.createElement(tagName),
    tag = riot.mount(root, opts)[0]
  return tag
}

riot.render = function(tagName, opts) {
  var tag = createTag(tagName, opts),
    html = sdom.serialize(tag.root)
  // unmount the tag avoiding memory leaks
  tag.unmount()
  return html
}

riot.render.dom = function(tagName, opts) {
  return createTag(tagName, opts).root
}

// allow to require('riot')
var riot = module.exports = require(process.env.RIOT || require('path').resolve(__dirname, '../../riot'))

var compiler = require('riot-compiler')

// allow to require('riot').compile
riot.compile = compiler.compile
riot.parsers = compiler.parsers

// allow to require('some.tag')
require.extensions['.tag'] = function(module, filename) {
  var src = riot.compile(require('fs').readFileSync(filename, 'utf8'))
  module._compile(
    'var riot = require(process.env.RIOT || "riot/riot.js");module.exports =' + src
  , filename)
}

// simple-dom helper
var sdom = require('./sdom')

riot.render = function(tagName, opts) {
  var tag = riot.render.tag(tagName, opts),
    html = sdom.serialize(tag.root)
  // unmount the tag avoiding memory leaks
  tag.unmount()
  return html
}

riot.render.dom = function(tagName, opts) {
  return riot.render.tag(tagName, opts).root
}

riot.render.tag = function(tagName, opts) {
  var root = document.createElement(tagName),
    tag = riot.mount(root, opts)[0]
  return tag
}

Add riot.render.tag function to create raw tag


import { Meteor } from 'meteor/meteor';
import { createGraphQLMethod } from './createGraphQLMethod';
import { createGraphQLPublication } from './createGraphQLPublication';
import {
  DEFAULT_METHOD,
  DEFAULT_CREATE_CONTEXT,
} from '../common/defaults';

export const DDP_APOLLO_SCHEMA_REQUIRED = 'DDP_APOLLO_SCHEMA_REQUIRED';

export function setup({
  schema,
  method = DEFAULT_METHOD,
  publication,
  context,
} = {}) {
  if (!schema) {
    throw new Error(DDP_APOLLO_SCHEMA_REQUIRED);
  }

  let createContext;

  switch (typeof context) {
    case 'object':
      createContext = defaultContext => ({ ...defaultContext, ...context });
      break;
    case 'function':
      createContext = context;
      break;
    default:
      createContext = DEFAULT_CREATE_CONTEXT;
  }

  Meteor.methods({
    [method]: createGraphQLMethod(schema, { createContext }),
  });

  createGraphQLPublication({
    schema,
    createContext,
    publication,
  });
}

import { Meteor } from 'meteor/meteor';
import { createGraphQLMethod } from './createGraphQLMethod';
import { createGraphQLPublication } from './createGraphQLPublication';
import {
  DEFAULT_METHOD,
  DEFAULT_CREATE_CONTEXT,
} from '../common/defaults';

export const DDP_APOLLO_SCHEMA_REQUIRED = 'DDP_APOLLO_SCHEMA_REQUIRED';

function contextToFunction(context) {
  switch (typeof context) {
    case 'object':
      return defaultContext => ({ ...defaultContext, ...context });
    case 'function':
      return context;
    default:
      return DEFAULT_CREATE_CONTEXT;
  }
}

export function setup({
  schema,
  method = DEFAULT_METHOD,
  publication,
  context,
} = {}) {
  if (!schema) {
    throw new Error(DDP_APOLLO_SCHEMA_REQUIRED);
  }

  const createContext = contextToFunction(context);

  Meteor.methods({
    [method]: createGraphQLMethod(schema, { createContext }),
  });

  createGraphQLPublication({
    schema,
    createContext,
    publication,
  });
}

Move context function creation to own function


import rp from 'request-promise';

import {Microservices} from '../../configs/microservices';
import {isEmpty, assignToAllById} from '../../common';

export default {

    // fetches the tags data
    fetchTagInfo(tags) {
        if (isEmpty(tags)) return Promise.resolve([]);

        return rp.get({
            uri: `${Microservices.tag.uri}/tags`,
            qs: {
                tagType: 'all',
                tagName: tags.map((t) => t.tagName),
                paging: false, // this allows for unpaged results
            },
            useQuerystring: true,
            json: true,
        });
    },

};

import rp from 'request-promise';

import {Microservices} from '../../configs/microservices';
import {isEmpty, assignToAllById} from '../../common';

export default {

    // fetches the tags data
    fetchTagInfo(tags) {
        if (isEmpty(tags)) return Promise.resolve([]);

        return rp.get({
            uri: `${Microservices.tag.uri}/tags`,
            qs: {
                tagType: 'any',
                tagName: tags.map((t) => t.tagName),
                paging: false, // this allows for unpaged results
            },
            useQuerystring: true,
            json: true,
        });
    },

};

Fix no topics shown when loading a deck (previous commit broke all)


'use strict';

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

function System() {
  var self = this;
  self.clearCache = clearCache;

  function clearCache(files) {
    if (files) {
      clearCacheForFiles(files);
    } else {
      clearAllCache();
    }
  }

  function clearCacheForFiles(files) {
    _.forEach(files, function (file) {
      delete require.cache[path.resolve(file)];
    });
  }

  function clearAllCache() {
    _.forOwn(require.cache, function (value, key) {
      delete require.cache[key];
    });
  }
}

module.exports = System;

'use strict';

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

function System() {
  var self = this;
  self.clearCache = clearCache;

  function clearCache(files) {
    if (files) {
      clearCacheForFiles(files);
    } else {
      clearAllCache();
    }
  }

  function clearCacheForFiles(files) {
    _.forEach(files, function (file) {
      delete require.cache[path.resolve(file)];
    });
  }

  function clearAllCache() {
    _.forOwn(require.cache, function (value, key) {
      if (/\.js$/.test(key)) {
        delete require.cache[key];
      }
    });
  }
}

module.exports = System;

Clear cache only clear JS files


(function() {
  function showLoading(ionicLoading, text) {
    ionicLoading.show({
      template: text,
      noBackdrop: true,
      duration: 2000
    });
  }

  angular.module("proBebe.controllers")
  .controller("AuthCtrl", function($scope, $ionicLoading, $state, $window, Constants, authentication, storage) {
    $scope.login_info = {};

    $scope.signUp = function() {
      $window.open(Constants.SIGN_UP_URL, '_system');
    };

    $scope.signIn = function() {
      var authPromise = authentication.authenticate($scope.login_info.email, $scope.login_info.password);
      $ionicLoading.show({
        templateUrl: 'templates/loading.html'
      });
      return authPromise.then(function(result) {
        if (result) {
          showLoading($ionicLoading, "Autenticado com sucesso");
          $state.go('messages');
        } else {
          showLoading($ionicLoading, "Credenciais inválidas");
        }
      }).catch(function(error) {
        showLoading($ionicLoading, "Ocorreu um erro na autenticação");
      });
    };

    $scope.signOut = function() {
      authentication.signOut();
      storage.clear();
      $state.go('signin');
    };

  });
})();

(function() {
  function showLoading(ionicLoading, text) {
    ionicLoading.show({
      template: text,
      noBackdrop: true,
      duration: 2000
    });
  }

  angular.module("proBebe.controllers")
  .controller("AuthCtrl", function($scope, $ionicLoading, $state, $window, Constants, authentication, storage) {
    $scope.login_info = {};

    $scope.signUp = function() {
      $window.open(Constants.SIGN_UP_URL, '_system');
    };

    $scope.signIn = function() {
      var authPromise = authentication.authenticate($scope.login_info.email, $scope.login_info.password);
      $ionicLoading.show({
        templateUrl: 'templates/loading.html'
      });
      return authPromise.then(function(result) {
        if (result) {
          showLoading($ionicLoading, "Autenticado com sucesso");
          $state.go('messages');
          location.reload();
        } else {
          showLoading($ionicLoading, "Credenciais inválidas");
        }
      }).catch(function(error) {
        showLoading($ionicLoading, "Ocorreu um erro na autenticação");
      });
    };

    $scope.signOut = function() {
      authentication.signOut();
      storage.clear();
      $state.go('signin');
    };

  });
})();

Fix layout rendering errors after login


import fs from 'fs';
import path from 'path';
import Sequelize from 'sequelize';
import dotenv from 'dotenv';
import dbConfig from '../config/config';

const basename = path.basename(module.filename);
const env = process.env.NODE_ENV || 'development';
const config = dbConfig[env];
const db = {};
dotenv.config();
let sequelize;
if (config.use_env_variable) {
  sequelize = new Sequelize(process.env.DATABASE_URL);
} else {
  sequelize = new Sequelize(config.database, config.username, config.password, config);
}

fs
  .readdirSync(__dirname)
  .filter(file =>
    (file.indexOf('.') !== 0) &&
    (file !== basename) &&
    (file.slice(-3) === '.js')).forEach((file) => {
    const model = sequelize.import(path.join(__dirname, file));
    db[model.name] = model;
  });

Object.keys(db).forEach((modelName) => {
  if (db[modelName].associate) {
    db[modelName].associate(db);
  }
});

db.sequelize = sequelize;
db.Sequelize = Sequelize;

export default db;

import fs from 'fs';
import path from 'path';
import Sequelize from 'sequelize';
import dotenv from 'dotenv';
import dbConfig from '../config/config';

const basename = path.basename(module.filename);
const env = process.env.NODE_ENV || 'development';
const config = dbConfig[env];
const db = {};
dotenv.config();
let sequelize;

if (process.env.DATABASE_URL) {
  sequelize = new Sequelize(process.env.DATABASE_URL);
} else if (process.env.DATABASE_TEST_URL) {
  sequelize = new Sequelize(process.env.DATABASE_TEST_URL);
} else {
  sequelize = new Sequelize(config.database, config.username, config.password, config);
}

fs
  .readdirSync(__dirname)
  .filter(file =>
    (file.indexOf('.') !== 0) &&
    (file !== basename) &&
    (file.slice(-3) === '.js')).forEach((file) => {
    const model = sequelize.import(path.join(__dirname, file));
    db[model.name] = model;
  });

Object.keys(db).forEach((modelName) => {
  if (db[modelName].associate) {
    db[modelName].associate(db);
  }
});

db.sequelize = sequelize;
db.Sequelize = Sequelize;

export default db;

Fix issue with travis configuration


var context = {
    name     : 'Eric',
    numPhotos: 1000,
    takenDate: Date.now()
};

var context = {
    name     : 'Annie',
    numPhotos: 1000,
    takenDate: Date.now()
};

Update photos Handlebars example to use "Annie"


const contractHelper = require('../contracts/contractHelpers.js');
const web3Connection = require('../web3.js');
const loggers = require('../loggers/events.js');

const web3 = web3Connection.web3;

const buySvc = {
  buyTicket: (req, res) => {
    const contractAddress = req.body.contractAddress; // address of deployed contract;
    const fromAddress = req.body.fromAddress;
    const name = req.body.name;
    const eventContractInstance = web3.eth.contract(contractHelper.contractObj).at(contractAddress);
    eventContractInstance.buyTicket(name, {
      from: fromAddress,
      value: req.body.price,
    }, (err) => {
      if (err) {
        console.log(err);
        loggers(eventContractInstance).ExceedQuota();
        loggers(eventContractInstance).InsufficientEther();
        res.sendStatus(500);
      } else {
        loggers(eventContractInstance).PurchaseTicket((error, result) => {
          res.status(200).send(`Number of attendees: ${result.args._numAttendees.toString()}`);
        });
      }
    });
  },
};

module.exports = buySvc;

const contractHelper = require('../contracts/contractHelpers.js');
const web3Connection = require('../web3.js');
const loggers = require('../loggers/events.js');

const web3 = web3Connection.web3;

const buySvc = {
  buyTicket: (req, res) => {
    const contractAddress = req.body.contractAddress; // address of deployed contract;
    const fromAddress = req.body.fromAddress;
    const name = req.body.name;
    const eventContractInstance = web3.eth.contract(contractHelper.contractObj).at(contractAddress);
    const opts = {
      from: fromAddress,
      value: req.body.price,
    };
    if (req.body.gas) {
      opts.gas = req.body.gas;
    }

    eventContractInstance.buyTicket(name, opts, (err) => {
      if (err) {
        console.log(err);
        loggers(eventContractInstance).ExceedQuota();
        loggers(eventContractInstance).InsufficientEther();
        res.sendStatus(500);
      } else {
        loggers(eventContractInstance).PurchaseTicket((error, result) => {
          res.status(200).send(`Number of attendees: ${result.args._numAttendees.toString()}`);
        });
      }
    });
  },
};

module.exports = buySvc;

Add option to define amount of gas sent in post request


import db, { normaliseFindResult } from 'src/pouchdb'
import { deleteDocs } from 'src/page-storage/deletion'
import { addToBlacklist } from '..'

/**
 * Handles confirmation and running of a quick blacklist request from the popup script.
 *
 * @param {string} url The URL being blacklisted.
 */
export default async function quickBlacklistConfirm(url) {
    const { rows } = await getURLMatchingDocs({ url })

    if (window.confirm(`Do you want to delete ${rows.length} matching records to ${url}?`)) {
        deleteDocs(rows)
    }

    addToBlacklist(url)
}

/**
 * Get all docs with matching URLs.
 *
 * @param {string} {url} Value to use to match against doc URLs.
 */
const getURLMatchingDocs = async ({ url, selector = {} }) => normaliseFindResult(
    await db.find({
        selector: {
            ...selector,
            url: { $regex: url }, // All docs whose URLs contain this value
        },
        fields: ['_id', '_rev'],
    })
)

import db, { normaliseFindResult } from 'src/pouchdb'
import { deleteDocs } from 'src/page-storage/deletion'
import { addToBlacklist } from '..'

/**
 * Handles confirmation and running of a quick blacklist request from the popup script.
 *
 * @param {string} url The URL being blacklisted.
 */
export default function quickBlacklistConfirm(url) {
    if (window.confirm(`Do you want to delete all data matching site:\n${url}`)) {
        getURLMatchingDocs({ url })
            .then(result => deleteDocs(result.rows))
            .catch(f => f) // Too bad
    }

    addToBlacklist(url)
}

/**
 * Get all docs with matching URLs.
 *
 * @param {string} {url} Value to use to match against doc URLs.
 */
const getURLMatchingDocs = async ({ url, selector = {} }) => normaliseFindResult(
    await db.find({
        selector: {
            ...selector,
            url: { $regex: url }, // All docs whose URLs contain this value
        },
        fields: ['_id', '_rev'],
    })
)

Remove docs count for user prompt


var fs   = require('fs')
var path = require('path')
var config = require('../lib/config')
var features = require('../lib/features')

module.exports = function(req, res) {
  fs.readFile(path.join(__dirname+'/../package.json'), function(error, packagejson) {
    fs.readFile(config.get('SSL_CERT'), function(error, certificate) {

      var properties = {
          documentation: "https://codius.org/docs/using-codius/getting-started",
          version: JSON.parse(packagejson.toString()).version,
          billing: [],
          public_key: certificate.toString()
      }

      if (features.isEnabled('RIPPLE_BILLING')) {
        properties.billing.push({
          network: 'ripple',
          cpu_per_xrp: parseFloat(config.get('compute_units_per_drop')) * 1000000
        })
      }

      if (features.isEnabled('BITCOIN_BILLING')) {
        properties.billing.push({
          network: 'bitcoin',
          cpu_per_bitcoin: config.get('compute_units_per_bitcoin')
        })
      }

      res.status(200).send({
        properties: properties
      })
    })
  })
}

var fs   = require('fs')
var path = require('path')
var config = require('../lib/config')
var features = require('../lib/features')

module.exports = function(req, res) {
  fs.readFile(path.join(__dirname+'/../package.json'), function(error, packagejson) {
    fs.readFile(config.get('ssl:cert'), function(error, certificate) {

      var properties = {
          documentation: "https://codius.org/docs/using-codius/getting-started",
          version: JSON.parse(packagejson.toString()).version,
          billing: [],
          public_key: certificate.toString()
      }

      if (features.isEnabled('RIPPLE_BILLING')) {
        properties.billing.push({
          network: 'ripple',
          cpu_per_xrp: parseFloat(config.get('compute_units_per_drop')) * 1000000
        })
      }

      if (features.isEnabled('BITCOIN_BILLING')) {
        properties.billing.push({
          network: 'bitcoin',
          cpu_per_bitcoin: config.get('compute_units_per_bitcoin')
        })
      }

      res.status(200).send({
        properties: properties
      })
    })
  })
}

Use ssl:cert isntead of SSL_CERT from nconf


var fs = require('fs');
var path = require('path');

module.exports = function(jobid, conf){

    var executionmethods = require('./executionserver.methods')(conf);

    var cwd = path.join(conf.storagedir, jobid);

    executionmethods.deleteFolderRecursive(cwd);
    var compressed = cwd + ".tar.gz";
    var compressedstat;
    try{
        compressedstat = fs.statSync(compressed);
    }catch(e){
        //does not exist
        compressedstat = undefined;
    }
    if(compressedstat){
        fs.unlinkSync(compressed);
    }

}

var fs = require('fs');
var path = require('path');

module.exports = function(jobid, conf, doc){

    var executionmethods = require('./executionserver.methods')(conf);

    var promdoc;

    if(doc){
        promdoc = Promise.resolve(doc);
    }else{
        promdoc = executionmethods.getDocument(jobid)
        .catch(function(err){
            console.error("Job not found before delete.", jobid)
        });
    }

    return promdoc
    .then(function(doc){
        return require(path.join(__dirname, "jobkill"))(doc, conf);
    })
    .then(function(){
        var cwd = path.join(conf.storagedir, jobid);

        try{
            executionmethods.deleteFolderRecursive(cwd);
            var compressed = cwd + ".tar.gz";
            var compressedstat;
            try{
                compressedstat = fs.statSync(compressed);
            }catch(e){
                //does not exist
                compressedstat = undefined;
            }
            if(compressedstat){
                fs.unlinkSync(compressed);
            }
        }catch(e){
            return {
                error: e
            }
        }

        return {
            status: "Folder deleted " + jobid
        }
    });

}

Check if the job is running.


import React from 'react';
import PropTypes from 'prop-types';
import cn from 'classnames';

import styles from './Base.module.css';

const renderLabel = label => {
  if (typeof label === 'undefined') {
    return null;
  }
  return
{label}
;
};

const renderCount = count => {
  if (typeof count === 'undefined') {
    return null;
  }
  return
{count}
;
};

const Base = ({ className, style, children, label, count, onClick }) => (

{children}

    {renderLabel(label)}
    {renderCount(count)}

);

Base.propTypes = {
  className: PropTypes.string,
  children: PropTypes.node.isRequired,
  label: PropTypes.string,
  count: PropTypes.number,
  style: PropTypes.object,
  onClick: PropTypes.func,
};

export default Base;

import React from 'react';
import PropTypes from 'prop-types';
import cn from 'classnames';

import styles from './Base.module.css';

const renderLabel = label => {
  if (typeof label === 'undefined') {
    return null;
  }
  return
{label}
;
};

const renderCount = count => {
  if (typeof count === 'undefined') {
    return null;
  }
  return
{count}
;
};

const Base = ({ className, style, children, label, count, onClick }) => (

{children}

    {renderLabel(label)}
    {renderCount(count)}

);

Base.propTypes = {
  className: PropTypes.string,
  children: PropTypes.node,
  label: PropTypes.string,
  count: PropTypes.number,
  style: PropTypes.object,
  onClick: PropTypes.func,
};

export default Base;

Fix warning if children is null


(function(global) {
  "use strict";

  // ulta-simple Object.create polyfill (only does half the job)
  var create = Object.create || (function() {
    var Maker = function(){};
    return function(prototype) {
      Maker.prototype = prototype;
      return new Maker();
    }
  }());

  var newless = function(constructor) {
    // in order to preserve constructor name, use the Function constructor
    var newlessConstructor = Function("constructor, create",
      "var newlessConstructor = function " + constructor.name + "() {" +
        "var obj = this;" +
        // don't create a new object if we've already got one
        // (e.g. we were called with `new`)
        "if (!(this instanceof newlessConstructor)) {" +
          "obj = create(newlessConstructor.prototype);" +
        "}" +
        // run the original constructor
        "var returnValue = constructor.apply(obj, arguments);" +
        // if we got back an object (and not null), use it as the return value
        "return (typeof returnValue === 'object' && returnValue) || obj;" +
      "};" +
      "return newlessConstructor;")(constructor, create);
    newlessConstructor.prototype = constructor.prototype;
    newlessConstructor.prototype.constructor = newlessConstructor;
    newlessConstructor.displayName = constructor.displayName;
    return newlessConstructor;
  };

  // support Node and browser
  if (typeof module !== "undefined") {
    module.exports = newless;
  }
  else {
    global.newless = newless;
  }

}(this));

(function(global) {
  "use strict";

  // ulta-simple Object.create polyfill (only does half the job)
  var create = Object.create || (function() {
    var Maker = function(){};
    return function(prototype) {
      Maker.prototype = prototype;
      return new Maker();
    }
  }());

  var newless = function(constructor) {
    // in order to preserve constructor name, use the Function constructor
    var name = constructor.name || "";
    var newlessConstructor = Function("constructor, create",
      "var newlessConstructor = function " + name + "() {" +
        "var obj = this;" +
        // don't create a new object if we've already got one
        // (e.g. we were called with `new`)
        "if (!(this instanceof newlessConstructor)) {" +
          "obj = create(newlessConstructor.prototype);" +
        "}" +
        // run the original constructor
        "var returnValue = constructor.apply(obj, arguments);" +
        // if we got back an object (and not null), use it as the return value
        "return (typeof returnValue === 'object' && returnValue) || obj;" +
      "};" +
      "return newlessConstructor;")(constructor, create);
    newlessConstructor.prototype = constructor.prototype;
    newlessConstructor.prototype.constructor = newlessConstructor;
    newlessConstructor.displayName = constructor.displayName;
    return newlessConstructor;
  };

  // support Node and browser
  if (typeof module !== "undefined") {
    module.exports = newless;
  }
  else {
    global.newless = newless;
  }

}(this));

Handle cases where [anonymous function].name is undefined instead of "".


import classNames from 'classnames/dedupe';
import {Link} from 'react-router';
import React from 'react';

class PageHeaderTabs extends React.Component {
  render() {
    let {props: {tabs}} = this;

    let tabElements = tabs.map(function (tab, index) {
      let {isActive, callback} = tab;
      let classes = classNames('menu-tabbed-item', {active: isActive});
      let linkClasses = classNames('menu-tabbed-item-label', {active: isActive});

      let innerLinkSpan = {tab.label};
      return (

          <Link className={linkClasses} to={tab.routePath}>

              {tab.label}

          </Link>

      );
    });

    return (

          {tabElements}

    );
  }
}

PageHeaderTabs.defaultProps = {
  tabs: []
};

PageHeaderTabs.propTypes = {
  tabs: React.PropTypes.arrayOf(
    React.PropTypes.shape({
      isActive: React.PropTypes.bool,
      label: React.PropTypes.node.isRequired,
      routePath: React.PropTypes.string.isRequired
    })
  )
};

module.exports = PageHeaderTabs;

import classNames from 'classnames/dedupe';
import {Link} from 'react-router';
import React from 'react';

class PageHeaderTabs extends React.Component {
  render() {
    let {props: {tabs}} = this;

    let tabElements = tabs.map(function (tab, index) {
      let {isActive, callback} = tab;
      let classes = classNames('menu-tabbed-item', {active: isActive});
      let linkClasses = classNames('menu-tabbed-item-label', {active: isActive});

      let innerLinkSpan = {tab.label};
      let link = tab.callback == null
          ? <Link className={linkClasses} to={tab.routePath}>{innerLinkSpan}</Link>
          : {innerLinkSpan};

      return (

          {link}

      );
    });

    return (

          {tabElements}

    );
  }
}

PageHeaderTabs.defaultProps = {
  tabs: []
};

PageHeaderTabs.propTypes = {
  tabs: React.PropTypes.arrayOf(
    React.PropTypes.shape({
      isActive: React.PropTypes.bool,
      label: React.PropTypes.node.isRequired,
      routePath: React.PropTypes.string,
      callback: React.PropTypes.func
    })
  )
};

module.exports = PageHeaderTabs;

Extend tabs to allow callbacks for unrouted tab navigation


(function() {
  'use strict';

  angular
  .module('dowser')
  .factory('AmChartGraph', AmChartGraphService);

  /** @ngInject */
  function AmChartGraphService() {
    function AmChartGraph(data, index) {
      return {
        "balloonText": "[[value]] " + (data.unit || 'un'),
        "bullet": "round",
        "dashLengthField": "dashLength",
        "id": "AmGraph-" + index,
        "lineAlpha": 1,
        "bulletSize": 10,
        "bulletBorderAlpha": 1,
        "bulletBorderColor": "#455A64",
        "lineThickness": 3,
        "markerType": "square",
        "title": data.category,
        "valueAxis": "ValueAxis-" + index,
        "valueField": data.category
      };
    }

    return AmChartGraph;
  }
})();

(function() {
  'use strict';

  angular
  .module('dowser')
  .factory('AmChartGraph', AmChartGraphService);

  /** @ngInject */
  function AmChartGraphService() {
    function AmChartGraph(data, index) {
      return {
        "balloonText": "[[value]] " + (data.unit || 'un'),
        "bullet": "round",
        "dashLengthField": "dashLength",
        "id": "AmGraph-" + index,
        "lineAlpha": !index ? 1 : 0.5,
        "bulletSize": !index ? 10 : 8,
        "bulletBorderAlpha": !index ? 1 : 0.5,
        "bulletBorderColor": "#455A64",
        "lineThickness": 3,
        "markerType": "square",
        "title": data.category,
        "valueAxis": "ValueAxis-" + index,
        "valueField": data.category
      };
    }

    return AmChartGraph;
  }
})();

Add alpha to other graphs


import { roundBalance } from '../../common/tools';
import { info } from '../broadcast';
import { observer as globalObserver } from '../../../common/utils/observer';

export default Engine =>
    class Balance extends Engine {
        observeBalance() {
            this.listen('balance', r => {
                const {
                    balance: { balance: b, currency },
                } = r;

                const balance = roundBalance({ currency, balance: b });
                const balanceStr = `${balance} ${currency}`;

                globalObserver.setState({ balance, currency });

                info({ accountID: this.accountInfo.loginid, balance: balanceStr });
            });
        }
        // eslint-disable-next-line class-methods-use-this
        getBalance(type) {
            const { scope } = this.store.getState();
            const currency = globalObserver.getState('currency');
            let balance = globalObserver.getState('balance');

            // Deduct trade `amount` in this scope for correct value in `balance`-block
            if (scope === 'BEFORE_PURCHASE') {
                balance = roundBalance({
                    balance: Number(balance) - this.tradeOptions.amount,
                    currency,
                });
            }

            const balanceStr = `${balance}`;

            return type === 'STR' ? balanceStr : Number(balance);
        }
    };

import { roundBalance } from '../../common/tools';
import { info } from '../broadcast';
import { observer as globalObserver } from '../../../common/utils/observer';

export default Engine =>
    class Balance extends Engine {
        observeBalance() {
            this.listen('balance', r => {
                const {
                    balance: { balance: b, currency },
                } = r;

                const balance = roundBalance({ currency, balance: b });
                const balanceStr = `${balance} ${currency}`;

                globalObserver.setState({ balance, currency });

                info({ accountID: this.accountInfo.loginid, balance: balanceStr });
            });
        }
        // eslint-disable-next-line class-methods-use-this
        getBalance(type) {
            const balance = globalObserver.getState('balance');
            const balanceStr = `${balance}`;
            return type === 'STR' ? balanceStr : Number(balance);
        }
    };

Remove deducting trade amount prematurely


angular.module('Mccy.routes', [
	'ngRoute'
])

.config(function ($routeProvider) {
	$routeProvider
	.when('/view', {
		templateUrl: 'views/view-containers.html',
		controller: 'ViewContainersCtrl'
	})
	.when('/new-server', {
		templateUrl: 'views/create-container.html',
		controller: 'NewContainerCtrl'
	})
	.when('/upload-mod', {
		templateUrl: 'views/upload-mod.html',
		controller: 'UploadModCtrl'
	})
	.when('/manage-mods', {
		templateUrl: 'views/manage-mods.html',
		controller: 'ManageModsCtrl'
	})
	.otherwise('/view')
})

.constant('MccyViews', [
	{
		view: '/view',
		settings: {
			label: 'Current Containers',
			icon: 'icon fa fa-heartbeat'
		}
	},
	{
		view: '/new-server',
		settings: {
			label: 'Create Container',
			icon: 'icon fa fa-magic'
		}
	},
	{
		view: '/upload-mod',
		settings: {
			label: 'Upload Mods',
			icon: 'icon fa fa-upload'
		}
	},
	{
		view: '/manage-mods',
		settings: {
			label: 'Manage Mods',
			icon: 'icon fa fa-flask'
		}
	}
])
;

Revert tabs to spaces due to accidental change


import { connect } from './wsActions'
import {
    setDashboards,
    play,
} from './dashboardsActions'
import {
    notifySuccess,
    notifyError,
} from './notificationsActions'

export const FETCH_CONFIGURATION         = 'FETCH_CONFIGURATION'
export const FETCH_CONFIGURATION_SUCCESS = 'FETCH_CONFIGURATION_SUCCESS'
export const FETCH_CONFIGURATION_FAILURE = 'FETCH_CONFIGURATION_FAILURE'

export const fetchConfigurationSuccess = configuration => ({
    type: FETCH_CONFIGURATION_SUCCESS,
    configuration,
})

const fetchConfigurationFailure = error => ({
    type: FETCH_CONFIGURATION_FAILURE,
    error,
})

export const fetchConfiguration = () => {
    return dispatch => {
        dispatch({ type: FETCH_CONFIGURATION })

        // http://localhost:5000/config
        return fetch('/config')
            .then(res => {
                if (res.status !== 200) {
                    return Promise.reject(`Unable to fetch configuration: ${res.statusText} (${res.status})`)
                }

                return res.json()
            })
            .then(configuration => {
                dispatch(fetchConfigurationSuccess(configuration))
                dispatch(connect(configuration))
                dispatch(notifySuccess({
                    message: 'configuration loaded',
                    ttl:     2000,
                }))
                dispatch(setDashboards(configuration.dashboards))
                dispatch(play())
            })
            .catch(err => {
                dispatch(notifyError({
                    message: `An error occurred while fetching configuration: ${err.message}`,
                    ttl:     -1,
                }))
                dispatch(fetchConfigurationFailure(err.message))
            })
    }
}

import { connect } from './wsActions'
import {
    setDashboards,
    play,
} from './dashboardsActions'
import {
    notifySuccess,
    notifyError,
} from './notificationsActions'

export const FETCH_CONFIGURATION         = 'FETCH_CONFIGURATION'
export const FETCH_CONFIGURATION_SUCCESS = 'FETCH_CONFIGURATION_SUCCESS'
export const FETCH_CONFIGURATION_FAILURE = 'FETCH_CONFIGURATION_FAILURE'

export const fetchConfigurationSuccess = configuration => ({
    type: FETCH_CONFIGURATION_SUCCESS,
    configuration,
})

const fetchConfigurationFailure = error => ({
    type: FETCH_CONFIGURATION_FAILURE,
    error,
})

export const fetchConfiguration = () => {
    return dispatch => {
        dispatch({ type: FETCH_CONFIGURATION })

        // http://localhost:5000/config
        return fetch('/config')
            .then(res => {
                if (res.status !== 200) {
                    return Promise.reject(new Error(
                        `Unable to fetch configuration: ${res.statusText} (${res.status})`))
                }

                return res.json()
            })
            .then(configuration => {
                dispatch(fetchConfigurationSuccess(configuration))
                dispatch(connect(configuration))
                dispatch(notifySuccess({
                    message: 'configuration loaded',
                    ttl:     2000,
                }))
                dispatch(setDashboards(configuration.dashboards))
                dispatch(play())
            })
            .catch(err => {
                dispatch(notifyError({
                    message: `An error occurred while fetching configuration: ${err.message}`,
                    ttl:     -1,
                }))
                dispatch(fetchConfigurationFailure(err.message))
            })
    }
}

Fix undefined reported as error on fetch configuration


const Vec3 = require('vec3').Vec3
const rand = require('random-seed')

function generation ({ version, seed, level = 50 } = {}) {
  const Chunk = require('prismarine-chunk')(version)
  const mcData = require('minecraft-data')(version)

  function generateChunk (chunkX, chunkZ) {
    const seedRand = rand.create(seed + ':' + chunkX + ':' + chunkZ)
    const chunk = new Chunk()
    for (let x = 0; x < 16; x++) {
      for (let z = 0; z < 16; z++) {
        const bedrockheighttop = 1 + seedRand(4)
        const bedrockheightbottom = 1 + seedRand(4)
        for (let y = 0; y < 128; y++) { // Nether only goes up to 128
          let block
          let data

          if (y < bedrockheightbottom) block = 7
          else if (y < level) block = seedRand(50) === 0 ? mcData.blocksByName.glowstone.id : mcData.blocksByName.netherrack.id
          else if (y > 127 - bedrockheighttop) block = mcData.blocksByName.bedrock.id

          const pos = new Vec3(x, y, z)
          if (block) chunk.setBlockType(pos, block)
          if (data) chunk.setBlockData(pos, data)
          // Don't need to set light data in nether
        }
      }
    }
    return chunk
  }
  return generateChunk
}

module.exports = generation

const Vec3 = require('vec3').Vec3
const rand = require('random-seed')

function generation ({ version, seed, level = 50 } = {}) {
  const Chunk = require('prismarine-chunk')(version)
  const mcData = require('minecraft-data')(version)

  function generateChunk (chunkX, chunkZ) {
    const seedRand = rand.create(seed + ':' + chunkX + ':' + chunkZ)
    const chunk = new Chunk()
    for (let x = 0; x < 16; x++) {
      for (let z = 0; z < 16; z++) {
        const bedrockheighttop = 1 + seedRand(4)
        const bedrockheightbottom = 1 + seedRand(4)
        for (let y = 0; y < 128; y++) { // Nether only goes up to 128
          let block
          let data

          if (y < bedrockheightbottom) block = mcData.blocksByName.bedrock.id
          else if (y < level) block = seedRand(50) === 0 ? mcData.blocksByName.glowstone.id : mcData.blocksByName.netherrack.id
          else if (y > 127 - bedrockheighttop) block = mcData.blocksByName.bedrock.id

          const pos = new Vec3(x, y, z)
          if (block) chunk.setBlockType(pos, block)
          if (data) chunk.setBlockData(pos, data)
          // Don't need to set light data in nether
        }
      }
    }
    return chunk
  }
  return generateChunk
}

module.exports = generation

Use bedrock instead of polished andesite


module.exports = function(page, dataType, navigationData) {
  var re = /(.*)(-\d+)?$/
  var array = re.exec(page)
  if(array && array[1] && navigationData && navigationData[array[1]]) {
    return navigationData[array[1]][dataType];
  }
  return null;
}

module.exports = function(page, dataType, navigationData) {
  var re = /(.*?)(\-\d+)?$/
  var array = re.exec(page)
  if(array && array[1] && navigationData && navigationData[array[1]]) {
    return navigationData[array[1]][dataType];
  }
  return null;
}

Fix nav data and pagination bug


RegExp.escape = function(text) {
  if (!arguments.callee.sRE) {
    var specials = [
      '/', '.', '*', '+', '?', '|',
      '(', ')', '[', ']', '{', '}', '\\'
    ];
    arguments.callee.sRE = new RegExp(
      '(\\' + specials.join('|\\') + ')', 'g'
    );
  }
  return text.replace(arguments.callee.sRE, '\\$1');
}

var allLabels = inDocument.getElementsByTagName("label");
var regExp = new RegExp('^\\W*' + RegExp.escape(locator) + '(\\b|$)', 'i');

var candidateLabels = $A(allLabels).select(function(candidateLabel){
  var labelText = getText(candidateLabel).strip();
  return (labelText.search(regExp) >= 0);
});

if (candidateLabels.length == 0) {
  return null;
}

//reverse length sort
candidateLabels = candidateLabels.sortBy(function(s) {
  return s.length * -1;
});

var locatedLabel = candidateLabels.first();
var labelFor = locatedLabel.getAttribute('for');

if ((labelFor == null) && (locatedLabel.hasChildNodes())) {
  // TODO: should find the first form field, not just any node
  return locatedLabel.firstChild;
}

return selenium.browserbot.locationStrategies['id'].call(this, labelFor, inDocument, inWindow);

// Credit to: http://simonwillison.net/2006/Jan/20/escape/
RegExp.escape = function(text) {
  if (!arguments.callee.sRE) {
    var specials = [
      '/', '.', '*', '+', '?', '|',
      '(', ')', '[', ']', '{', '}', '\\'
    ];
    arguments.callee.sRE = new RegExp(
      '(\\' + specials.join('|\\') + ')', 'g'
    );
  }
  return text.replace(arguments.callee.sRE, '\\$1');
}

var allLabels = inDocument.getElementsByTagName("label");
var regExp = new RegExp('^\\W*' + RegExp.escape(locator) + '(\\b|$)', 'i');

var candidateLabels = $A(allLabels).select(function(candidateLabel){
  var labelText = getText(candidateLabel).strip();
  return (labelText.search(regExp) >= 0);
});

if (candidateLabels.length == 0) {
  return null;
}

//reverse length sort
candidateLabels = candidateLabels.sortBy(function(s) {
  return s.length * -1;
});

var locatedLabel = candidateLabels.first();
var labelFor = locatedLabel.getAttribute('for');

if ((labelFor == null) && (locatedLabel.hasChildNodes())) {
  return locatedLabel.getElementsByTagName('button')[0]
    || locatedLabel.getElementsByTagName('input')[0]
    || locatedLabel.getElementsByTagName('textarea')[0]
    || locatedLabel.getElementsByTagName('select')[0];
}

return selenium.browserbot.locationStrategies['id'].call(this, labelFor, inDocument, inWindow);

Fix "element.getAttribute is not a function" Selenium errors when filling in fields


// If you try printing the below you would see "[object Object]"" which is not that useful.

// Instead, you can click "Inspect it" to see the result in the JavaScript console where you can look inside the object.
// That result is not displayed in the editor window -- it is only displayed in the console.

// To open the console in various browsers, see:
// https://webmasters.stackexchange.com/questions/8525/how-do-i-open-the-javascript-console-in-different-browsers

// You can also try selecting just parts of the object (like the array) and use "Inspect It" or "Print it".

const myObject = {
    hello: "world",
    coding: "is fun!",
    todo: ["learn Mithril.js", "learn Tachyons.css"],
    snippetIndex: 3
}

myObject

// If you try printing the below you would see "[object Object]"" which is not that useful.
// Instead, you can click "Inspect it" to see the result in the JavaScript console where you can look inside the object.
// That result is not displayed in the editor window -- it is only displayed in the console.

// To open the console in various browsers, see:
// https://webmasters.stackexchange.com/questions/8525/how-do-i-open-the-javascript-console-in-different-browsers
// In most browsers, you can right-click on part of the web page and pick "Inspect" from the popup menu there
// and then when the developer tools open, pick the console tab.

// You can also try selecting just parts of the object (like the array) and use "Inspect It" or "Print it".

const myObject = {
    hello: "world",
    coding: "is fun!",
    todo: ["learn Mithril.js", "learn Tachyons.css"],
    snippetIndex: 3
}

myObject

Improve instructions in inspecting an object for opening console


// Copyright (C) 2014 Domenic Denicola. All rights reserved.
// This code is governed by the BSD license found in the LICENSE file.

/*---
description: Array.prototype.contains skips holes, and does not treat them as undefined
author: Domenic Denicola
---*/

var arrayWithHoles = [,,,];

var result1 = Array.prototype.contains.call(arrayWithHoles, undefined);

if (result1 !== true) {
    $ERROR('Expected array with many holes to contain undefined');
}

var arrayWithASingleHole = ['a', 'b',, 'd'];

var result2 = arrayWithASingleHole.contains(undefined);

if (result2 !== true) {
    $ERROR('Expected array with a single hole to contain undefined');
}

// Copyright (C) 2014 Domenic Denicola. All rights reserved.
// This code is governed by the BSD license found in the LICENSE file.

/*---
description: Array.prototype.contains does not skip holes; instead it treates them as undefined
author: Domenic Denicola
---*/

var arrayWithHoles = [,,,];

var result1 = Array.prototype.contains.call(arrayWithHoles, undefined);

if (result1 !== true) {
    $ERROR('Expected array with many holes to contain undefined');
}

var arrayWithASingleHole = ['a', 'b',, 'd'];

var result2 = arrayWithASingleHole.contains(undefined);

if (result2 !== true) {
    $ERROR('Expected array with a single hole to contain undefined');
}

Update holes test description to reflect the actual test


'use strict';

/* global Connector */

Connector.playerSelector = '.page-station__bar';
Connector.trackArtImageSelector = '.slider__items > div:nth-child(3) .track__cover';
Connector.trackSelector = '.slider__items > div:nth-child(3) .track__title';
Connector.artistSelector = '.slider__items > div:nth-child(3) .track__artists';
Connector.isPlaying = function() {
	return $('body').hasClass('body_state_playing');
};

'use strict';

/* global Connector */

Connector.trackArtImageSelector = '.slider__items > div:nth-child(3) .track__cover';
Connector.trackSelector = '.slider__items > div:nth-child(3) .track__title';
Connector.artistSelector = '.slider__items > div:nth-child(3) .track__artists';

Connector.isPlaying = function() {
	return $('body').hasClass('body_state_playing');
};

(function() {
	var actualObserver;
	var playerObserver = new MutationObserver(function() {
		var playerSelector = document.querySelector('.page-station__bar');
		if (playerSelector !== null) {
			if (!actualObserver) {
				actualObserver = new MutationObserver(Connector.onStateChanged);
				actualObserver.observe(playerSelector, {
					subtree: true,
					childList: true,
					attributes: true,
					characterData: true
				});
			}
		} else {
			if (actualObserver) {
				actualObserver.disconnect();
				actualObserver = null;
			}
		}
	});

	playerObserver.observe(document.body, {
		subtree: true,
		childList: true,
		attributes: false,
		characterData: false
	});
})();

Fix non-proper work of Yandex radio connector


var asteroid = require('asteroid');

module.exports = asteroid.createDataSource({
    connector: require('asteroid-connector-rest'),
    debug: false,
    operations: [
        {
            name: 'geocode',
            parameters: ['street', 'city', 'zipcode'],
            request: {
                "method": "GET",
                "url": "http://maps.googleapis.com/maps/api/geocode/{format=json}",
                "headers": {
                    "accepts": "application/json",
                    "content-type": "application/json"
                },
                "query": {
                    "address": "{street},{city},{zipcode}",
                    "sensor": "{sensor=false}"
                },
                "responsePath": "$.results[0].geometry.location"
            }
        }
    ]});

var asteroid = require("asteroid");

module.exports = asteroid.createDataSource({
    connector: require("asteroid-connector-rest"),
    debug: false,
    operations: [
        {
            template: {
                "method": "GET",
                "url": "http://maps.googleapis.com/maps/api/geocode/{format=json}",
                "headers": {
                    "accepts": "application/json",
                    "content-type": "application/json"
                },
                "query": {
                    "address": "{street},{city},{zipcode}",
                    "sensor": "{sensor=false}"
                },
                "responsePath": "$.results[0].geometry.location"
            },
            functions: {
               "geocode": ["street", "city", "zipcode"]
            }
        }
    ]});

Update the rest connector config


/*
 * Copyright 2014-2015 Hewlett-Packard Development Company, L.P.
 * Licensed under the MIT License (the "License"); you may not use this file except in compliance with the License.
 */

require.config({
    baseUrl: 'src/main/webapp/static/js',
    paths: {
        'js-testing': '../lib/hp-autonomy-js-testing-utils/src/js',
        'mock': '../../../../test/js/mock'
    },
    map: {
        '*': {
            'find/lib/backbone/backbone-extensions': 'backbone'
        },
        'find/app/page/indexes/indexes-view': {
            'find/app/model/indexes-collection': 'mock/model/indexes-collection'
        }
    }
});

/*
 * Copyright 2014-2015 Hewlett-Packard Development Company, L.P.
 * Licensed under the MIT License (the "License"); you may not use this file except in compliance with the License.
 */

require.config({
    baseUrl: 'src/main/webapp/static/js',
    paths: {
        'js-testing': '../lib/hp-autonomy-js-testing-utils/src/js',
        'mock': '../../../../test/js/mock'
    },
    map: {
        '*': {
            'find/lib/backbone/backbone-extensions': 'backbone'
        },
        'find/app/page/service-view': {
            'find/app/model/indexes-collection': 'mock/model/indexes-collection'
        }
    }
});

Fix stubbing to prevent tests from trying to talk to server. [rev: daniel.grayling]


QUnit.config.urlConfig.push({
  id: "jquery",
  label: "jQuery version",
  value: ["3.1.1", "3.0.0", "2.2.4", "2.1.4", "2.0.3", "1.12.4", "1.11.3"],
  tooltip: "What jQuery Core version to test against"
});

/* Hijacks normal form submit; lets it submit to an iframe to prevent
 * navigating away from the test suite
 */
$(document).on('submit', function(e) {
  if (!e.isDefaultPrevented()) {
    var form = $(e.target), action = form.attr('action'),
        name = 'form-frame' + jQuery.guid++,
        iframe = $('<iframe name="' + name + '" />');

    if (action && action.indexOf('iframe') < 0) form.attr('action', action + '?iframe=true')
    form.attr('target', name);
    $('#qunit-fixture').append(iframe);
    form.trigger('iframe:loading');
  }
});

QUnit.config.urlConfig.push({
  id: "jquery",
  label: "jQuery version",
  value: ["3.2.1", "3.2.0", "3.1.1", "3.0.0", "2.2.4", "2.1.4", "2.0.3", "1.12.4", "1.11.3"],
  tooltip: "What jQuery Core version to test against"
});

/* Hijacks normal form submit; lets it submit to an iframe to prevent
 * navigating away from the test suite
 */
$(document).on('submit', function(e) {
  if (!e.isDefaultPrevented()) {
    var form = $(e.target), action = form.attr('action'),
        name = 'form-frame' + jQuery.guid++,
        iframe = $('<iframe name="' + name + '" />');

    if (action && action.indexOf('iframe') < 0) form.attr('action', action + '?iframe=true')
    form.attr('target', name);
    $('#qunit-fixture').append(iframe);
    form.trigger('iframe:loading');
  }
});

Test against jQuery 3.2.0 and 3.2.1


var ds18b20 = require('../services/ds18b20.js');
var logger = require('../services/logger.js');
var _ = require('lodash');

var sensors;
var config;

var init = function (cfg) {
    config = cfg || {};

    sensors = _.filter(config.sensors, function (sensor) {
        return sensor.isActive;
    });

    logger.init(config);
};

var run = function () {
    if (!config) {
        console.log('MONITOR', 'No configuration present');
        return;
    }

    sensors.forEach(function (sensor) {
        if (sensor.type == 'temperature') {
            ds18b20.read(sensor)
                .then(function (result) {
                    logger.log('MONITOR\tREADING\t' + result.sensor.displayName + '\t' + result.reading.F + '°F');

                    if (result.sensor.allowedRange) {
                        if (result.reading.F < result.sensor.allowedRange.low || result.reading.F > result.sensor.allowedRange.high) {
                            logger.warn(result.sensor.displayName + ' is out of allowed range: ' + result.reading.F + '°F');
                        }
                    }
                })
                .catch(function (error) {
                    logger.error('MONITOR\tERROR\t' + error);
                });
        }
    });
};

exports.init = init;
exports.run = run;

var ds18b20 = require('../services/ds18b20.js');
var logger = require('../services/logger.js');
var _ = require('lodash');

var sensors;
var config;

var init = function (cfg) {
    config = cfg || {};

    logger.init(config);
};

var run = function () {
    if (!config) {
        console.log('MONITOR', 'No configuration present');
        return;
    }

    config.sensors.forEach(function (sensor) {
        if (!sensor.isActive) return;

        if (sensor.type == 'temperature') {
            ds18b20.read(sensor)
                .then(function (result) {
                    logger.log('MONITOR\tREADING\t' + result.sensor.displayName + '\t' + result.reading.F.toFixed(2) + '°F');

                    if (result.sensor.allowedRange) {
                        if (result.reading.F < result.sensor.allowedRange.low || result.reading.F > result.sensor.allowedRange.high) {
                            logger.warn(result.sensor.displayName + ' is out of allowed range: ' + result.reading.F.toFixed(2) + '°F');
                        }
                    }
                })
                .catch(function (error) {
                    logger.error('MONITOR\tERROR\t' + error);
                });
        }
    });
};

exports.init = init;
exports.run = run;

Move filter and set fixed precision


import React, { Component } from 'react';
import { connect } from 'react-redux';
import RequestEditor from '../components/RequestEditor';
import ResponseViewer from '../components/ResponseViewer';
import { Request, addRequest, executeRequest } from '../actions/project';
import { selectRequest } from '../actions/ui';

class NewRequestPage extends Component {
  constructor(props) {
    super(props);
    this.state = {};
  }

  componentDidMount() {
    this.setState({request: new Request({method: 'GET'})});
  }

  addRequest(request) {
    const action = addRequest(request, this.props.params.projectId);

    this.props.dispatch(action);
    this.props.dispatch(selectRequest(action.request));
  }

  onRequestExecute(request) {
    this.setState({request: request});
    this.props.dispatch(executeRequest(request.method, request.url, request.headers.toJS(), request.body));
  }

  render() {
    if (!this.state.request)
      return null;

    return (
      <div className="new-request-page">
        <RequestEditor request={ this.state.request }
                       onRequestChange={ this.addRequest.bind(this) }
                       onRequestExecute={ this.onRequestExecute.bind(this) }/>

        <ResponseViewer response={ this.props.response }/>
      </div>
    );
  }
}

function mapStateToProps(state) {
  return {
    response: state.response
  }
}

export default connect(mapStateToProps)(NewRequestPage);

import React, { Component } from 'react';
import { connect } from 'react-redux';
import RequestEditor from '../components/RequestEditor';
import ResponseViewer from '../components/ResponseViewer';
import { Request, addRequest, executeRequest } from '../actions/project';
import { cancel } from '../actions/response';
import { selectRequest } from '../actions/ui';

class NewRequestPage extends Component {
  constructor(props) {
    super(props);
    this.state = {};
  }

  componentDidMount() {
    this.setState({request: new Request({method: 'GET'})});
  }

  addRequest(request) {
    const action = addRequest(request, this.props.params.projectId);

    this.props.dispatch(action);
    this.props.dispatch(selectRequest(action.request));
  }

  onRequestExecute(request) {
    this.setState({request: request});
    this.props.dispatch(executeRequest(request.method, request.url, request.headers.toJS(), request.body));
  }

  render() {
    if (!this.state.request)
      return null;

    return (
      <div className="new-request-page">
        <RequestEditor request={ this.state.request }
                       onRequestChange={ this.addRequest.bind(this) }
                       onRequestExecute={ this.onRequestExecute.bind(this) }/>

        <ResponseViewer response={ this.props.response } onCancel={() => this.props.dispatch(cancel())}/>
      </div>
    );
  }
}

function mapStateToProps(state) {
  return {
    response: state.response
  }
}

export default connect(mapStateToProps)(NewRequestPage);

Allow request cancellation on new request page as well


import Ember from 'ember';

export default Ember.Controller.extend({
  needs: ['application'],
  selectedPerson: Ember.computed.alias('controllers.application.attrs.person'),
  errorMessage: null,
  titleIsValid: function() {
    var title = this.get('model.title');

    return (!Ember.isEmpty(title) && title.length > 2);
  }.property('model.title'),
  emailIsValid: function() {
    var email = this.get('model.user.email'),
        re = new RegExp(/\S+@\S+\.\S+/);

    return (!Ember.isEmpty(email) && re.test(email));
  }.property('model.user.email'),
  isValid: function() {
    return (this.get('titleIsValid') && this.get('emailIsValid'));
  }.property('titleIsValid', 'emailIsValid')
});

import Ember from 'ember';

export default Ember.Controller.extend({
  needs: ['application'],
  selectedPerson: Ember.computed.alias('controllers.application.attrs.person'),
  errorMessage: null,
  titleIsValid: Ember.computed('model.title', function() {
    var title = this.get('model.title');

    return (!Ember.isEmpty(title) && title.length > 2);
  }),
  emailIsValid: Ember.computed('model.user.email', function() {
    var email = this.get('model.user.email'),
        re = new RegExp(/\S+@\S+\.\S+/);

    return (!Ember.isEmpty(email) && re.test(email));
  }),
  isValid: Ember.computed('titleIsValid', 'emailIsValid', function() {
    return (this.get('titleIsValid') && this.get('emailIsValid'));
  })
});

Switch computed property syntax via ember-watson


import React from 'react';

import PipelinesBanner from './pipelines';

class Banners extends React.Component {
  render() {
    return (
      <div className="container mb4">
        <PipelinesBanner id="pipelines" onHideClick={this.handleBannerHide} />
      </div>
    )
  }

  handleBannerHide = (id) => {
    console.log('removing ', id);
  };
}

export default Banners;

import React from 'react';

import PipelinesBanner from './pipelines';

class Banners extends React.Component {
  state = {
    hidden: {}
  };

  render() {
    let nodes = [];
    if(window._banners) {
      for(const id of window._banners) {
        if(!this.state.hidden[id]) {
          nodes.push(<PipelinesBanner id={id} key={id} onHideClick={this.handleBannerHide} />);
        }
      }
    }

    if(nodes.length) {
      return (
        <div className="container mb4">
          {nodes}
        </div>
      )
    } else {
      return null;
    }
  }

  handleBannerHide = (id) => {
    let hidden = this.state.hidden;
    hidden[id] = true;

    this.setState({ hidden: hidden });
  };
}

export default Banners;

Hide banners when you click the "close" button


import angular from 'angular';
import uiRouter from 'angular-ui-router';
import ngMaterial from 'angular-material';
import Common from './common/common';
import Components from './components/components';
import AppComponent from './app.component';
import AppMaterial from './app.material';
import 'normalize.css';
import '../../node_modules/angular-material/angular-material.css';

angular.module('app', [
    uiRouter,
    ngMaterial,
    Common,
    Components
]).config(($stateProvider, $locationProvider, $urlRouterProvider) => {
  "ngInject";
  $locationProvider.html5Mode(false).hashPrefix('!');
  $stateProvider
    .state('app', {
      abstract: true,
      url: '/'
    });
    $urlRouterProvider.otherwise('/login');
})
.config(AppMaterial)
.component('app', AppComponent);

import angular from 'angular';
import uiRouter from 'angular-ui-router';
import ngMaterial from 'angular-material';
import Common from './common/common';
import Components from './components/components';
import AppComponent from './app.component';
import AppMaterial from './app.material';
import 'normalize.css';
import '../../node_modules/angular-material/angular-material.css';

angular.module('app', [
    uiRouter,
    ngMaterial,
    Common,
    Components
]).config(($stateProvider, $locationProvider, $urlRouterProvider, $httpProvider) => {
  "ngInject";
  $locationProvider.html5Mode(false).hashPrefix('!');
  $stateProvider
    .state('app', {
      abstract: true,
      url: '/'
    });
  $urlRouterProvider.otherwise('/login');
  $httpProvider.defaults.xsrfCookieName = 'csrftoken';
  $httpProvider.defaults.xsrfHeaderName = 'X-CSRFToken';
})
.config(AppMaterial)
.component('app', AppComponent);

Configure angular to use django csrf token


$(function () {
  $('#search_movie').submit(function(){
    var $form     = $(this);
    var movieName = $form.children('#movie_name_input').val();
    var movieYear = $form.children('#movie_year_input').val();

    var apiUrl    = $form.attr('action') + "/" + movieYear + "/" + movieName;

    $.get(apiUrl, function(movie){
      var movie_html = "";

      movie_html += "
" + movie.name + "(" + movie.info.year + ")
";
      movie_html += '';
      movie_html += "
Combined Rating: " + movie.combined_rating + "
";

      var movie_ratings = "
Ratings:
";
      $.each(movie.ratings, function(rating_site, rating) {
        movie_ratings += "
" + rating_site + ":
";
        $.each(rating, function(key, value) {
          movie_ratings += "
";
          movie_ratings += "" + key + ": " + value;
        });
      });
      movie_html += movie_ratings;

      $('#result').html(movie_html);
    });
    return false;
  });
});

$(function () {
  $('#search_movie').submit(function(){
    var $form     = $(this);
    var movieName = $form.children('#movie_name_input').val();
    var movieYear = $form.children('#movie_year_input').val();

    var apiUrl    = $form.attr('action') + "/" + movieYear + "/" + movieName;

    $.get(apiUrl, function(movie){
      var movie_html = "";

      movie_html += "
" + movie.name + " (" + movie.info.year + ")
";
      movie_html += '';
      movie_html += "
Combined Rating: " + movie.combined_rating + "
";

      var movie_ratings = "
Ratings:
";
      $.each(movie.ratings, function(rating_site, rating) {
        movie_ratings += '
';
        movie_ratings += rating_site + ':
 ' + rating.score;
      });
      movie_html += movie_ratings;

      $('#result').html(movie_html);
    });
    return false;
  });
});

Modify output on index page


const ScheduleTweet = require('./ScheduleTweet');
const GearTweet = require('./GearTweet');
const SalmonRunTweet = require('./SalmonRunTweet');
const SalmonRunGearTweet = require('./SalmonRunGearTweet');
const NewWeaponTweet = require('./NewWeaponTweet');
const NewStageTweet = require('./NewStageTweet');
const SplatfestTweet = require('./SplatfestTweet');

module.exports = [
    new ScheduleTweet,
    new GearTweet,
    new SalmonRunTweet,
    new SalmonRunGearTweet,
    new NewWeaponTweet,
    new NewStageTweet,
    new SplatfestTweet('na'),
    new SplatfestTweet('eu'),
    new SplatfestTweet('jp'),
];

const ScheduleTweet = require('./ScheduleTweet');
const GearTweet = require('./GearTweet');
const SalmonRunTweet = require('./SalmonRunTweet');
// const SalmonRunGearTweet = require('./SalmonRunGearTweet');
const NewWeaponTweet = require('./NewWeaponTweet');
const NewStageTweet = require('./NewStageTweet');
const SplatfestTweet = require('./SplatfestTweet');

module.exports = [
    new ScheduleTweet,
    new GearTweet,
    new SalmonRunTweet,
    // new SalmonRunGearTweet,
    new NewWeaponTweet,
    new NewStageTweet,
    new SplatfestTweet('na'),
    new SplatfestTweet('eu'),
    new SplatfestTweet('jp'),
];

Disable the new Salmon Run gear tweet for now


/**
 * Error Screen
 *
    <Error text={'Server is down'} />
 *
 * React Native Starter App
 * https://github.com/mcnamee/react-native-starter-app
 */
import React, { PropTypes } from 'react';
import { View } from 'react-native';
import Icon from 'react-native-vector-icons/Ionicons';

// Consts and Libs
import { AppStyles } from '@theme/';

// Components
import { Spacer, Text } from '@ui/';

/* Component ==================================================================== */
const Error = ({ text }) => (
  <View style={[AppStyles.container, AppStyles.containerCentered]}>
    <Icon name={'ios-alert-outline'} size={50} color={'#CCC'} />

    <Spacer size={10} />

    <Text>{text}</Text>
  </View>
);

Error.propTypes = { text: PropTypes.string };
Error.defaultProps = { text: 'Woops, Something went wrong.' };
Error.componentName = 'Error';

/* Export Component ==================================================================== */
export default Error;

/**
 * Error Screen
 *
    <Error text={'Server is down'} />
 *
 * React Native Starter App
 * https://github.com/mcnamee/react-native-starter-app
 */
import React, { PropTypes } from 'react';
import { View } from 'react-native';
import Icon from 'react-native-vector-icons/Ionicons';

// Consts and Libs
import { AppStyles } from '@theme/';

// Components
import { Spacer, Text, Button } from '@ui/';

/* Component ==================================================================== */
const Error = ({ text, tryAgain }) => (
  <View style={[AppStyles.container, AppStyles.containerCentered]}>
    <Icon name={'ios-alert-outline'} size={50} color={'#CCC'} />

    <Spacer size={10} />

    <Text>{text}</Text>

    <Spacer size={20} />

    {!!tryAgain &&
      <Button
        small
        outlined
        title={'Try again'}
        onPress={() => tryAgain()}
      />
    }
  </View>
);

Error.propTypes = { text: PropTypes.string, tryAgain: PropTypes.func };
Error.defaultProps = { text: 'Woops, Something went wrong.' };
Error.componentName = 'Error';

/* Export Component ==================================================================== */
export default Error;

Add try again button to error screen


(function () {
    'use strict';

    var isMac = /Mac/i.test(navigator.platform),
        isIOS = /iPhone|iPad|iPod/i.test(navigator.userAgent),
        isAndroid = /Android/i.test(navigator.userAgent),
        isWindowsPhone = /Windows Phone/i.test(navigator.userAgent),
        isJavaInstalled = (deployJava.getJREs().length > 0) && deployJava.versionCheck("1.5+"),
        isMobile = isIOS || isAndroid || isWindowsPhone,
        canBeInstalled = isJavaInstalled && !isMobile;

    $('#install-java').toggle(!isJavaInstalled);
    $('#download-app').toggle(canBeInstalled);

    $('#install-java').on('click', function () {
        deployJava.installLatestJava();
    });

    $('#download-app').on('click', function () {
        if (isMac) {
            alert('You need to change your security preferences!');
            return;
        }

        if (isMobile) {
            alert('The charting app is not available on mobile devices!');
        }
    });
})();

(function () {
    'use strict';

    var isMac = /Mac/i.test(navigator.platform),
        isIOS = /iPhone|iPad|iPod/i.test(navigator.userAgent),
        isAndroid = /Android/i.test(navigator.userAgent),
        isWindowsPhone = /Windows Phone/i.test(navigator.userAgent),
        isJavaInstalled = (deployJava.getJREs().length > 0) && deployJava.versionCheck("1.5+"),
        isMobile = isIOS || isAndroid || isWindowsPhone,
        canBeInstalled = isJavaInstalled && !isMobile;

    $('#install-java').toggle(!isJavaInstalled);
    $('#download-app').toggle(canBeInstalled);

    $('#install-java').on('click', function () {
        deployJava.installLatestJRE();
    });

    $('#download-app').on('click', function () {
        if (isMac) {
            alert('You need to change your security preferences!');
            return;
        }

        if (isMobile) {
            alert('The charting app is not available on mobile devices!');
        }
    });
})();

Fix java chart install link broken issue


(function () {
    var loadingElement = document.getElementsByClassName("loading")[0];
    loadingElement.textContent = "Loading...";

    function start() {
        var scriptElement = document.createElement("script");
        scriptElement.src = "game.js";
        document.body.appendChild(scriptElement);
    }

    if (applicationCache) {
        function onProgress(event) {
            loadingElement.textContent = "Loading... " + event.loaded.toString() + "/" + event.total.toString();
        }

        function onUpdateReady() {
            window.location.reload();
        }

        applicationCache.addEventListener("progress", onProgress, true);
        applicationCache.addEventListener("noupdate", start, true);
        applicationCache.addEventListener("cached", start, true);
        applicationCache.addEventListener("updateready", onUpdateReady, true);
        applicationCache.addEventListener("obsolete", start, true);
        applicationCache.addEventListener("error", start, true);
    } else {
        start();
    }
}());

(function () {
    var loadingElement = document.getElementsByClassName("loading")[0];
    loadingElement.textContent = "Loading...";

    function start() {
        var scriptElement = document.createElement("script");
        scriptElement.src = "game.js";
        document.body.appendChild(scriptElement);
    }

    if (window.applicationCache) {
        function onProgress(event) {
            loadingElement.textContent = "Loading... " + event.loaded.toString() + "/" + event.total.toString();
        }

        function onUpdateReady() {
            window.location.reload();
        }

        applicationCache.addEventListener("progress", onProgress, true);
        applicationCache.addEventListener("noupdate", start, true);
        applicationCache.addEventListener("cached", start, true);
        applicationCache.addEventListener("updateready", onUpdateReady, true);
        applicationCache.addEventListener("obsolete", start, true);
        applicationCache.addEventListener("error", start, true);
    } else {
        start();
    }
}());

Fix for browsers that don't support application cache.


module.exports = {
    // output config
    dist: {
        min: '~/square.{type}.{ext}'
      , dev: '~/square.{type}.{ext}'
    }

    // plugin configuration
  , plugin: {}

    // hinting and linting
  , jshint: require('./jshint')
  , csslint: require('./csshint')
};

var path = require('path')
  , file = path.join(process.env.PWD, 'package.json')
  , pkg;

try { pkg = require(file); }
catch (e) { pkg = {}; }

module.exports = {
    // output config
    dist: {
        min: '~/square.{type}.{ext}'
      , dev: '~/square.{type}.{ext}'
    }

    // plugin configuration
  , plugin: {}

    // hinting and linting
  , jshint: require('./jshint')
  , csslint: require('./csshint')

    // add package.json if it exists
  , vars: pkg
};

Add package.json data as vars if it exists


//= require_self
//= require components
//= require turbolinks
//= require react_ujs

// Setup React in global scope
var React = window.React = global.React = require('react/addons');
var $ = window.JQuery = require('jquery-browserify');

//= require_self
//= require components
//= require react_ujs

// Setup React in global scope
var React = window.React = global.React = require('react/addons');
window.$ = window.jQuery = require('jquery')
require('jquery-ujs')
//= jquery_ujs

Add jquery and jquery_ujs -global


import React, { PropTypes } from 'react'

export default class Html extends React.Component {
  render () {
    return (
    <html>
    <head>
      <title>
        {this.props.title}
      </title>
      <link type='text/css' rel='stylesheet' href='/static/pure.min.css' />
      <link type='text/css' rel='stylesheet' href='/static/app.bundle.css' />
    </head>
    <body>
      <div id='root' dangerouslySetInnerHTML={{ __html: this.props.children }} />
      <script src='/static/init.bundle.js' onLoad='console.log("hovno")' />
      <script async src='/static/react.bundle.js' />
      <script async src='/static/app.bundle.js' />
    </body>
    </html>
    )
  }
}

Html.propTypes = {
  children: PropTypes.node.isRequired,
  title: PropTypes.string.isRequired
}

import React, { PropTypes } from 'react'

export default class Html extends React.Component {
  render () {
    return (
    <html>
    <head>
      <title>
        {this.props.title}
      </title>
      <meta name='viewport' content='width=device-width, initial-scale=1' />
      <link type='text/css' rel='stylesheet' href='/static/pure.min.css' />
      <link type='text/css' rel='stylesheet' href='/static/app.bundle.css' />
    </head>
    <body>
      <div id='root' dangerouslySetInnerHTML={{ __html: this.props.children }} />
      <script src='/static/init.bundle.js' />
      <script async src='/static/react.bundle.js' />
      <script async src='/static/app.bundle.js' />
    </body>
    </html>
    )
  }
}

Html.propTypes = {
  children: PropTypes.node.isRequired,
  title: PropTypes.string.isRequired
}

Add viewport meta tag for mobile sites


const mongoose = require('mongoose')
const shortId = require('shortid')
const Schema = mongoose.Schema

const assetSchema = Schema({
  _shortId: {type: String, unique: true, default: shortId.generate},
  tagId: { type: String, text: true },
  assignedTo: { type: String, text: true }
})

const specSchema = Schema({
  _shortId: {type: String, unique: true, default: shortId.generate},
  key: { type: String, text: true },
  value: { type: String, text: true }
})

const categorySchema = Schema({
  _shortId: {type: String, unique: true, default: shortId.generate},
  name: String,
  label: String,
  description: String,
  config: {
    faIcon: String,
    color: String,
    api: String,
    fallbackImage: String
  },
  models: [ { type: Schema.Types.ObjectId, ref: 'Model' } ]
})

const modelSchema = Schema({
  _parent: {type: String, ref: 'Category'},
  _shortId: {type: String, unique: true, default: shortId.generate},
  category: { type: String, text: true },
  vendor: { type: String, text: true },
  name: { type: String, text: true },
  version: { type: String, text: true },
  image: String,
  description: { type: String, text: true },
  active: Boolean,
  specs: [ specSchema ],
  assets: [ assetSchema ]
})

modelSchema.index({
  vendor: 'text',
  name: 'text',
  version: 'text',
  description: 'text'
})

module.exports = { assetSchema, modelSchema, categorySchema }

const mongoose = require('mongoose')
const shortId = require('shortid')
const Schema = mongoose.Schema

const assetSchema = Schema({
  _shortId: {type: String, unique: true, default: shortId.generate},
  tagId: String,
  assignedTo: String
})

const specSchema = Schema({
  _shortId: {type: String, unique: true, default: shortId.generate},
  key: String,
  value: String
})

const categorySchema = Schema({
  _shortId: {type: String, unique: true, default: shortId.generate},
  name: String,
  label: String,
  description: String,
  config: {
    faIcon: String,
    color: String,
    api: String,
    fallbackImage: String
  },
  models: [ { type: Schema.Types.ObjectId, ref: 'Model' } ]
})

const modelSchema = Schema({
  _parent: {type: String, ref: 'Category'},
  _shortId: {type: String, unique: true, default: shortId.generate},
  category: String,
  vendor: String,
  name: String,
  version: String,
  image: String,
  description: String,
  active: Boolean,
  specs: [ specSchema ],
  assets: [ assetSchema ]
})

modelSchema.index({
  vendor: 'text',
  name: 'text',
  version: 'text',
  description: 'text'
})

module.exports = { assetSchema, modelSchema, categorySchema }

Complete search functionality for models


exports = module.exports = function(parse, csrfProtection, loadState, authenticate, proceed) {

  // TODO: Move this file to "password/handlers/authenticate"

  return [
    parse('application/x-www-form-urlencoded'),
    csrfProtection(),
    loadState('login'),
    authenticate('local'),
    proceed
  ];
};

exports['@require'] = [
  'http://i.bixbyjs.org/http/middleware/parse',
  'http://i.bixbyjs.org/http/middleware/csrfProtection',
  'http://i.bixbyjs.org/http/middleware/loadState',
  'http://i.bixbyjs.org/http/middleware/authenticate',
  '../../workflow/login/resume'
];

exports = module.exports = function(parse, flow, csrfProtection, authenticate) {

  return [
    parse('application/x-www-form-urlencoded'),
    flow('authenticate-password',
      csrfProtection(),
      authenticate([ 'local' ]),
    { through: 'login' })
  ];
};

exports['@require'] = [
  'http://i.bixbyjs.org/http/middleware/parse',
  'http://i.bixbyjs.org/http/middleware/state/flow',
  'http://i.bixbyjs.org/http/middleware/csrfProtection',
  'http://i.bixbyjs.org/http/middleware/authenticate'
];

Switch to DSL for password authentication.


import { combineReducers } from 'redux';
import { fetchReducer } from 'controllers/fetch';
import { paginationReducer } from 'controllers/pagination';
import { loadingReducer } from 'controllers/loading';
import {
  NAMESPACE,
  FETCH_USER_FILTERS_SUCCESS,
  UPDATE_FILTER_CONDITIONS,
  ADD_FILTER,
  UPDATE_FILTER_SUCCESS,
  REMOVE_FILTER,
} from './constants';
import { updateFilter } from './utils';

const updateFilterConditions = (filters, filterId, conditions) => {
  const filter = filters.find((item) => item.id === filterId);
  return updateFilter(filters, { ...filter, conditions });
};

export const launchesFiltersReducer = (state = [], { type, payload, meta: { oldId } = {} }) => {
  switch (type) {
    case FETCH_USER_FILTERS_SUCCESS:
      return [...state, ...payload];
    case UPDATE_FILTER_CONDITIONS:
      return updateFilterConditions(state, payload.filterId, payload.conditions);
    case UPDATE_FILTER_SUCCESS:
      return updateFilter(state, payload, oldId);
    case ADD_FILTER:
      return [...state, payload];
    case REMOVE_FILTER:
      return state.filter((filter) => filter.id !== payload);
    default:
      return state;
  }
};

export const filterReducer = combineReducers({
  filters: fetchReducer(NAMESPACE, { contentPath: 'content' }),
  pagination: paginationReducer(NAMESPACE),
  loading: loadingReducer(NAMESPACE),
  launchesFilters: launchesFiltersReducer,
});

import { combineReducers } from 'redux';
import { fetchReducer } from 'controllers/fetch';
import { paginationReducer } from 'controllers/pagination';
import { loadingReducer } from 'controllers/loading';
import {
  NAMESPACE,
  FETCH_USER_FILTERS_SUCCESS,
  UPDATE_FILTER_CONDITIONS,
  ADD_FILTER,
  UPDATE_FILTER_SUCCESS,
  REMOVE_FILTER,
} from './constants';
import { updateFilter } from './utils';

const updateFilterConditions = (filters, filterId, conditions) => {
  const filter = filters.find((item) => item.id === filterId);
  return updateFilter(filters, { ...filter, conditions });
};

export const launchesFiltersReducer = (state = [], { type, payload, meta: { oldId } = {} }) => {
  switch (type) {
    case FETCH_USER_FILTERS_SUCCESS:
      return payload;
    case UPDATE_FILTER_CONDITIONS:
      return updateFilterConditions(state, payload.filterId, payload.conditions);
    case UPDATE_FILTER_SUCCESS:
      return updateFilter(state, payload, oldId);
    case ADD_FILTER:
      return [...state, payload];
    case REMOVE_FILTER:
      return state.filter((filter) => filter.id !== payload);
    default:
      return state;
  }
};

export const filterReducer = combineReducers({
  filters: fetchReducer(NAMESPACE, { contentPath: 'content' }),
  pagination: paginationReducer(NAMESPACE),
  loading: loadingReducer(NAMESPACE),
  launchesFilters: launchesFiltersReducer,
});

Replace fetched user filters when switching project


import React from "react-native";
import Page from "./page";

const {
    StyleSheet,
    View,
    Text,
    Image,
    TouchableOpacity
} = React;

const styles = StyleSheet.create({
    failed: {
        fontSize: 18
    },
    button: {
        flexDirection: "row",
        alignItems: "center",
        padding: 16
    },
    label: {
        paddingHorizontal: 8,
        marginLeft: 8
    },
    icon: {
        height: 24,
        width: 24,
        opacity: 0.5
    }
});

export default class PageRetry extends React.Component {
    render() {
        return (
            <Page {...this.props}>
                <Text style={styles.failed}>Failed to load data</Text>
                {this.props.onRetry ?
                    <TouchableOpacity onPress={this.props.onRetry}>
                        <View style={styles.button}>
                            <Image style={styles.icon} source={require("image!ic_refresh_black")} />
                            <Text style={styles.label}>Retry</Text>
                        </View>
                    </TouchableOpacity> :
                    null
                }
            </Page>
        );
    }
}

PageRetry.propTypes = {
    onRetry: React.PropTypes.func
};

import React from "react-native";
import Page from "./page";

const {
    StyleSheet,
    View,
    Text,
    Image,
    TouchableOpacity
} = React;

const styles = StyleSheet.create({
    container: {
        flex: 1,
        alignItems: "center",
        justifyContent: "center"
    },
    failed: {
        fontSize: 18
    },
    button: {
        flexDirection: "row",
        alignItems: "center",
        padding: 16
    },
    label: {
        paddingHorizontal: 8,
        marginHorizontal: 8
    },
    icon: {
        height: 24,
        width: 24,
        opacity: 0.5
    }
});

export default class PageRetry extends React.Component {
    render() {
        return (
            <Page {...this.props}>
                <TouchableOpacity onPress={this.props.onRetry} style={styles.container}>
                    <Text style={styles.failed}>Failed to load data</Text>
                    {this.props.onRetry ?
                    <View style={styles.button}>
                        <Image style={styles.icon} source={require("image!ic_refresh_black")} />
                        <Text style={styles.label}>Retry</Text>
                    </View> :
                    null
                }
                </TouchableOpacity>
            </Page>
        );
    }
}

PageRetry.propTypes = {
    onRetry: React.PropTypes.func
};

Make the whole retry page tappable


import { connect } from "react-redux";
import EntriesPage from "../components/EntriesPage.js";
import { clearSearchResults } from "../library/messaging.js";
import { searchEntriesForTerm } from "../../shared/library/messaging.js";

export default connect(
    (state, ownProps) => ({}),
    {
        onPrepare: () => () => {
            clearSearchResults();
        },
        onSearchTermChange: searchTerm => () => {
            if (searchTerm.trim().length > 0) {
                searchEntriesForTerm(searchTerm);
            } else {
                clearSearchResults();
            }
        }
    }
)(EntriesPage);

import { connect } from "react-redux";
import EntriesPage from "../components/EntriesPage.js";
import { clearSearchResults } from "../library/messaging.js";
import { searchEntriesForTerm } from "../../shared/library/messaging.js";

export default connect(
    (state, ownProps) => ({}),
    {
        onPrepare: () => () => {},
        onSearchTermChange: searchTerm => () => {
            if (searchTerm.trim().length > 0) {
                searchEntriesForTerm(searchTerm);
            } else {
                clearSearchResults();
            }
        }
    }
)(EntriesPage);

Stop clearing search results on popup init


import { put, call, fork } from 'redux-saga/effects';
import { takeLatest } from 'redux-saga';
import { getBranches, register } from './resources';

import {
  BRANCH_LIST_REQUESTED, branchListUpdated,
  registerStart,
  REGISTER_REQUESTED, registerSuccess,
  clearPageError, pageError,
} from './actions';

export function* fetchBranchList() {
  try {
    yield put(clearPageError());
    const { branches } = yield call(getBranches);
    yield put(branchListUpdated(branches));
    yield put(registerStart());
  } catch (error) {
    yield put(pageError('There was an error loading the page content'));
  }
}

export function* registerMember({ payload }) {
  const { member, onSuccess, onFailure } = payload;
  try {
    yield put(clearPageError());
    yield call(register, member);
    yield put(registerSuccess());
    yield call(onSuccess);
  } catch (error) {
    console.log('ERROR', error);
    yield put(pageError('There was an error saving your changes'));
    yield call(onFailure);
  }
}

export function* watchBranchListRequest() {
  yield* takeLatest(BRANCH_LIST_REQUESTED, fetchBranchList);
}

export function* watchRegisterRequest() {
  yield* takeLatest(REGISTER_REQUESTED, registerMember);
}

export default function* rootSaga() {
  yield [
    fork(watchBranchListRequest),
    fork(watchRegisterRequest),
  ];
}

import { put, call, fork } from 'redux-saga/effects';
import { takeLatest } from 'redux-saga';
import { getBranches, register } from './resources';

import {
  BRANCH_LIST_REQUESTED, branchListUpdated,
  registerStart,
  REGISTER_REQUESTED, registerSuccess,
  clearPageError, pageError,
} from './actions';

export function* fetchBranchList() {
  try {
    yield put(clearPageError());
    const { branches } = yield call(getBranches);
    yield put(branchListUpdated(branches));
    yield put(registerStart());
  } catch (error) {
    yield put(pageError('There was an error loading the page content'));
  }
}

export function* registerMember({ payload }) {
  const { member, onSuccess, onFailure } = payload;
  try {
    yield put(clearPageError());
    yield call(register, member);
    yield put(registerSuccess());
    yield call(onSuccess);
  } catch (error) {
    yield put(pageError('There was an error saving your changes'));
    yield call(onFailure);
  }
}

export function* watchBranchListRequest() {
  yield* takeLatest(BRANCH_LIST_REQUESTED, fetchBranchList);
}

export function* watchRegisterRequest() {
  yield* takeLatest(REGISTER_REQUESTED, registerMember);
}

export default function* rootSaga() {
  yield [
    fork(watchBranchListRequest),
    fork(watchRegisterRequest),
  ];
}

Remove some debug logging from the frontend


var nconf = require('nconf');

var scheConf = new nconf.Provider();
var mainConf = new nconf.Provider();
var optConf = new nconf.Provider();
var name2Conf = {"sche" : scheConf, "main": mainConf, "opt": optConf};

scheConf.file({file: './app/schedules.json'});
mainConf.file({file: './app/schools.json'});
optConf.file({file: './app/options.json'});

function saveSettings(settingKey, settingValue, file) {
    var conf = name2Conf[file];
    conf.set(settingKey, settingValue);
    conf.save();
}

function readSettings(settingKey, file) {
    var conf = name2Conf[file];
    conf.load();
    return conf.get(settingKey);
}

function getSettings(file) {
    var conf = name2Conf[file];
    conf.load();
    return conf.get();
}

function clearSetting(key, file) {
    var conf = name2Conf[file];
    conf.load();
    conf.clear(key);
    conf.save();
}

module.exports = {
    saveSettings: saveSettings,
    readSettings: readSettings,
    getSettings: getSettings,
    clearSetting: clearSetting
};

var nconf = require('nconf');

var scheConf = new nconf.Provider();
var mainConf = new nconf.Provider();
var optConf = new nconf.Provider();
var name2Conf = {"sche" : scheConf, "main": mainConf, "opt": optConf};

scheConf.file({file: __dirname + '/app/schedules.json'});
mainConf.file({file: __dirname + '/app/schools.json'});
optConf.file({file: __dirname + '/app/options.json'});

function saveSettings(settingKey, settingValue, file) {
    var conf = name2Conf[file];
    conf.set(settingKey, settingValue);
    conf.save();
}

function readSettings(settingKey, file) {
    var conf = name2Conf[file];
    conf.load();
    return conf.get(settingKey);
}

function getSettings(file) {
    var conf = name2Conf[file];
    conf.load();
    return conf.get();
}

function clearSetting(key, file) {
    var conf = name2Conf[file];
    conf.load();
    conf.clear(key);
    conf.save();
}

module.exports = {
    saveSettings: saveSettings,
    readSettings: readSettings,
    getSettings: getSettings,
    clearSetting: clearSetting
};

Make .json config paths relative


"use strict";

angular.module("angular-mobile-docs")
    .factory("MockFetchService", function ($http, $q) {

        var config = {
            url: "http://localhost:8080/assets/code.angularjs.org/"
        };

        var getVersionList = function (version) {
            return $http.get(config.url+"versions.json");
        }

        var getFileList = function (version) {
            return $http.get(
                config.url
                    + version
                    + "/docs/partials/api/filelist.json");
        }

        var getPartial = function (version, name) {
            return $http.get(
                config.url
                    + version
                    + "/docs/partials/api/" + name);
        }

        var getAllPartials = function (version) {
            var promises = [];
            var fileNameList = getFileList(version);

            angular.forEach(fileNameList, function (fileName) {
                promises.push(getPartial(fileName, version));
            })

            return $q.all(promises);
        }

        return {
            getVersionList: function () {
                return getVersionList();
            },
            getFileList   : function (version) {
                return getFileList(version);
            },
            getPartial    : function (version, name) {
                return getPartial(version, name);
            },
            getAllPartials: function (version) {
                return getAllPartials(version);
            }

        };

    });

"use strict";

angular.module("angular-mobile-docs")
    .factory("MockFetchService", function ($http, $q) {

        var config = {
            url: "http://apidocs.angularjs.de/code.angularjs.org/"
        };

        var getVersionList = function (version) {
            return $http.get(config.url+"versions.json");
        }

        var getFileList = function (version) {
            return $http.get(
                config.url
                    + version
                    + "/docs/partials/api/filelist.json");
        }

        var getPartial = function (version, name) {
            return $http.get(
                config.url
                    + version
                    + "/docs/partials/api/" + name);
        }

        var getAllPartials = function (version) {
            var promises = [];
            var fileNameList = getFileList(version);

            angular.forEach(fileNameList, function (fileName) {
                promises.push(getPartial(fileName, version));
            })

            return $q.all(promises);
        }

        return {
            getVersionList: function () {
                return getVersionList();
            },
            getFileList   : function (version) {
                return getFileList(version);
            },
            getPartial    : function (version, name) {
                return getPartial(version, name);
            },
            getAllPartials: function (version) {
                return getAllPartials(version);
            }

        };

    });

Change URL to our online apidocs server


var importcss = require('rework-npm')
  , rework = require('rework')
  , vars = require('rework-vars')
  , path = require('path')
  , read = require('fs').readFileSync

module.exports = function (opts, cb) {
  opts = opts || {}

  var css = rework(read(opts.entry, 'utf8'))
  css.use(importcss(path.dirname(opts.entry)))

  // even if variables were not provided
  // use rework-vars to process default values
  css.use(vars(opts.variables))

  // utilize any custom rework plugins provided
  if (opts.plugins) {
    opts.plugins.forEach(function (plugin) {
      css.use(plugin)
    })
  }

  cb(null, css.toString())
}

var importcss = require('rework-npm')
  , rework = require('rework')
  , vars = require('rework-vars')
  , path = require('path')
  , read = require('fs').readFileSync

module.exports = function (opts, cb) {
  opts = opts || {}

  var css = rework(read(opts.entry, 'utf8'))
  css.use(importcss(path.dirname(opts.entry)))

  // even if variables were not provided
  // use rework-vars to process default values
  css.use(vars(opts.variables))

  // utilize any custom rework plugins provided
  if (opts.plugins) {
    opts.plugins.forEach(function (plugin) {
      if (typeof plugin === 'string') plugin = require(plugin)
      css.use(plugin)
    })
  }

  cb(null, css.toString())
}

Add support for passing plugin names as strings