<commit_before>class BarChart {

    constructor(url, labelName, valueName, chartClassName) {
        this.url = url;
        this.labelName = (typeof labelName !== 'undefined') ? labelName : 'label';
        this.valueName = (typeof valueName !== 'undefined') ? valueName : 'value';
        this.chartClassName = (typeof chartClassName !== 'undefined') ? chartClassName : 'chart';
    }

    render() {
        var margin = {top: 20, right: 30, bottom: 30, left: 40},
            width = 900 - margin.left - margin.right,
            height = 300 - margin.top - margin.bottom;

        var x = d3.scale.ordinal()
            .rangeRoundBands([0, width], .1);
        var y = d3.scale.linear()
            .range([height, 0]);

        var xAxis = d3.svg.axis()
            .scale(x)
            .orient("bottom")
            .tickFormat(function(d) {
                return truncate(d, 14);
            });
        var yAxis = d3.svg.axis()
            .scale(y)
            .orient("left");

        var chart = d3.select('.' + this.chartClassName)
            .attr("width", width + margin.left + margin.right)
            .attr("height", height + margin.top + margin.bottom)
            .append("g")
            .attr("transform", "translate(" + margin.left + "," + margin.top + ")");

        d3.json(this.url, function(error, data) {
            var data = data.data;

            x.domain(data.map(function(d) { return d[this.labelName]; }));
            y.domain([0, d3.max(data, function(d) { return d[this.valueName]; })]);

            chart.append("g")
                .attr("class", "x axis")
                .attr("transform", "translate(0," + height + ")")
                .call(xAxis);

            chart.append("g")
                .attr("class", "y axis")
                .call(yAxis);

            chart.selectAll(".bar")
                .data(data)
                .enter().append("rect")
                .attr("class", "bar")
                .attr("x", function(d) { return x(d[this.labelName]); })
                .attr("y", function(d) { return y(d[this.valueName]); })
                .attr("height", function(d) { return height - y(d[this.valueName]); })
                .attr("width", x.rangeBand());
        });

        function truncate(d, l) {
             if(d.length > l)
                 return d.substring(0,l)+'...';
             else
                 return d;
        }
    }
}

var barChart1 = new BarChart('/weather_delay_histogram.json', 'label', 'value', 'chart');
console.log(barChart1);
barChart1.render();
<commit_msg>Working bar chart, about to move it to barchart.js<commit_after>class BarChart {

    constructor(url, labelName, valueName, chartClassName) {
        this.url = url;
        this.labelName = (typeof labelName !== 'undefined') ? labelName : 'label';
        this.valueName = (typeof valueName !== 'undefined') ? valueName : 'value';
        this.chartClassName = (typeof chartClassName !== 'undefined') ? chartClassName : 'chart';
    }

    render() {
        var margin = {top: 20, right: 30, bottom: 30, left: 40},
            width = 900 - margin.left - margin.right,
            height = 300 - margin.top - margin.bottom;

        var x = d3.scale.ordinal()
            .rangeRoundBands([0, width], .1);
        var y = d3.scale.linear()
            .range([height, 0]);

        var xAxis = d3.svg.axis()
            .scale(x)
            .orient("bottom")
            .tickFormat(function(d) {
                return truncate(d, 14);
            });
        var yAxis = d3.svg.axis()
            .scale(y)
            .orient("left");

        var chart = d3.select('.' + this.chartClassName)
            .attr("width", width + margin.left + margin.right)
            .attr("height", height + margin.top + margin.bottom)
            .append("g")
            .attr("transform", "translate(" + margin.left + "," + margin.top + ")");

        var labelName = this.labelName;
        var valueName = this.valueName;
        d3.json(this.url, function(error, data) {
            var data = data.data;

            x.domain(data.map(function(d) { return d[labelName]; }));
            y.domain([0, d3.max(data, function(d) { return d[valueName]; })]);

            chart.append("g")
                .attr("class", "x axis")
                .attr("transform", "translate(0," + height + ")")
                .call(xAxis);

            chart.append("g")
                .attr("class", "y axis")
                .call(yAxis);

            chart.selectAll(".bar")
                .data(data)
                .enter().append("rect")
                .attr("class", "bar")
                .attr("x", function(d) { return x(d[labelName]); })
                .attr("y", function(d) { return y(d[valueName]); })
                .attr("height", function(d) { return height - y(d[valueName]); })
                .attr("width", x.rangeBand());
        });

        function truncate(d, l) {
             if(d.length > l)
                 return d.substring(0,l)+'...';
             else
                 return d;
        }
    }
}
<|endoftext|>


<commit_before>(function ($) {

    var isCtrlPressed = false,

        isMac = navigator.platform.indexOf("Mac") > -1,

        UA = navigator.userAgent,

        browser = $.browser || {
            mozilla : UA.indexOf('Firefox') > -1,
            opera : !!window.opera,
            webkit : UA.indexOf('WebKit') > -1
        },

        isCtrl = function (e) {
            var is_ctrl = e.ctrlKey,
                keyCode = e.which;

            if (isMac && !is_ctrl) {
                if ($.browser.mozilla) {
                    is_ctrl = keyCode === 224;
                } else if ($.browser.webkit || $.browser.opera) {
                    is_ctrl = keyCode === 91 || keyCode === 93
                }
            }

            return is_ctrl;
        },

        checkKeyDownEvent = function (e) {

            isCtrlPressed = isCtrlPressed || isCtrl(e);

            $.isCtrlPressed = isCtrlPressed;
        },

        checkKeyUpEvent = function () {
            $.isCtrlPressed = isCtrlPressed = false;
        };

    $.isCtrlPressed = false;

    $.isCtrl = isCtrl;

    $(document)
        .on('keydown', checkKeyDownEvent)
        .on('keyup', checkKeyUpEvent);

})(jQuery);
<commit_msg>Update jquery.isctrlpressed.js<commit_after>(function ($) {

    var isCtrlPressed = false,

        isMac = navigator.platform.indexOf("Mac") > -1,

        UA = navigator.userAgent,

        browser = $.browser || {
            mozilla : UA.indexOf('Firefox') > -1,
            opera : !!window.opera,
            webkit : UA.indexOf('WebKit') > -1
        },

        isCtrl = function (e) {
            var is_ctrl = e.ctrlKey,
                keyCode = e.which;

            if (isMac && !is_ctrl) {
                if (browser.mozilla) {
                    is_ctrl = keyCode === 224;
                } else if (browser.webkit || browser.opera) {
                    is_ctrl = keyCode === 91 || keyCode === 93
                }
            }

            return is_ctrl;
        },

        checkKeyDownEvent = function (e) {

            isCtrlPressed = isCtrlPressed || isCtrl(e);

            $.isCtrlPressed = isCtrlPressed;
        },

        checkKeyUpEvent = function () {
            $.isCtrlPressed = isCtrlPressed = false;
        };

    $.isCtrlPressed = false;

    $.isCtrl = isCtrl;

    $(document)
        .on('keydown', checkKeyDownEvent)
        .on('keyup', checkKeyUpEvent);

})(jQuery);
<|endoftext|>


<commit_before>// TODO
// https://github.com/jrburke/almond
//
//
//      jam compile -i backbone -i d3 -o built.js
//
//
// - set up package paths for requirejs optimizer
// - run equivalent of:
//     node r.js -o baseUrl=. name=path/to/almond.js include=main
//     out=main-built.js wrap=true
//
//  (wrap is optional)
//
//
//  OR should this just be an extension of the optimize command?

var logger = require('../logger'),
    settings = require('../settings'),
    args = require('../args'),
    tar = require('../tar'),
    path = require('path'),
    requirejs = require('requirejs');

exports.summary = 'Combines modules and requirejs into a single file';

exports.usage = '' +
    'jam compile -i MODULE ... -o TARGET\n' +
    '\n' +
    'Options:\n' +
    '  -i, --include   Modules to optimize, combining them and their their\n' +
    '                  dependencies into a single file\n' +
    '  -o, --out       Output file for the compiled code\n' +
    '  --package-dir   Jam directory to use (defaults to "./jam")\n' +
    '  --wrap          Wraps the output in an anonymous function to avoid\n' +
    '                  require and define functions being added to the\n' +
    '                  global scope, this often makes sense when using the\n' +
    '                  almond option.\n' +
    '  --almond        Use the lighweight almond shim instead of RequireJS,\n' +
    '                  smaller filesize but can only load bundled resources\n' +
    '                  and cannot request additional modules.';

exports.run = function (settings, _args, commands) {
    var a = args.parse(_args, {
        includes: {match: ['-i', '--include'], multiple: true, value: true},
        pkgdir: {match: ['--package-dir'], value: true},
        outfile: {match: ['-o', '--out'], value: true},
        almond: {match: ['--almond']},
        wrap: {match: ['--wrap']}
    });

    if (!a.options.includes.length) {
        logger.error('You must include at least one module');
        console.log(exports.usage);
        logger.clean_exit = true;
        return;
    }
    if (!a.options.outfile) {
        logger.error('You must specify an output file');
        console.log(exports.usage);
        logger.clean_exit = true;
        return;
    }

    logger.info('compiling', a.options.outfile);
    if (a.options.includes.length) {
        logger.info('includes', a.options.includes.join(', '));
    }

    var source = '.';
    var configfile = path.resolve(
        source,
        a.options.pkgdir || 'jam',
        'require.config'
    );
    var packages = require(configfile).packages;

    var impl;
    if (a.options.almond) {
        logger.info('using almond.js');
        impl = path.relative(
            source,
            path.resolve(__dirname, '../../node_modules/almond/almond.js')
        );
    }
    else {
        var impl = path.relative(
            source,
            path.resolve(__dirname, '../../node_modules/requirejs/require.js')
        );
    }

    var includes;
    if (a.options.almond) {
        includes = a.options.includes;
    }
    else {
        includes = ['jam/require.config.js'].concat(a.options.includes);
    }

    var config = {
        baseUrl: source,
        packages: packages,
        name: impl,
        wrap: a.options.wrap,
        optimize: 'uglify',
        include: includes,
        out: a.options.outfile
    };
    requirejs.optimize(config, function (build_response) {
        logger.end(a.options.outfile);
    });
};
<commit_msg>update compile parameters so it compiles all installed modules by default<commit_after>// TODO
// https://github.com/jrburke/almond
//
//
//      jam compile -i backbone -i d3 -o built.js
//
//
// - set up package paths for requirejs optimizer
// - run equivalent of:
//     node r.js -o baseUrl=. name=path/to/almond.js include=main
//     out=main-built.js wrap=true
//
//  (wrap is optional)
//
//
//  OR should this just be an extension of the optimize command?

var logger = require('../logger'),
    settings = require('../settings'),
    args = require('../args'),
    tar = require('../tar'),
    path = require('path'),
    requirejs = require('requirejs'),
    project = require('../project');

exports.summary = 'Combines modules and requirejs into a single file';

exports.usage = '\n' +
    'jam compile TARGET\n' +
    'jam compile -i MODULE ... -o TARGET\n' +
    '\n' +
    'When called without -i parameters, all installed packages are included\n' +
    'in the compiled output. With -i parameters, only the specified\n' +
    'packages are compiled, this can also include modules from your own\n' +
    'project directory.\n' +
    '\n' +
    'Parameters:\n' +
    '  TARGET    The filename to save compiled output to\n' +
    '\n' +
    'Options:\n' +
    '  -i, --include   Specific modules to optimize, combining them and\n' +
    '                  their dependencies into a single file\n' +
    '  -o, --out       Output file for the compiled code\n' +
    '  --package-dir   Jam directory to use (defaults to "./jam")\n' +
    '  --wrap          Wraps the output in an anonymous function to avoid\n' +
    '                  require and define functions being added to the\n' +
    '                  global scope, this often makes sense when using the\n' +
    '                  almond option.\n' +
    '  --almond        Use the lighweight almond shim instead of RequireJS,\n' +
    '                  smaller filesize but can only load bundled resources\n' +
    '                  and cannot request additional modules.';

exports.run = function (settings, _args, commands) {
    var a = args.parse(_args, {
        includes: {match: ['-i', '--include'], multiple: true, value: true},
        pkgdir: {match: ['--package-dir'], value: true},
        outfile: {match: ['-o', '--out'], value: true},
        almond: {match: ['--almond']},
        wrap: {match: ['--wrap']}
    });

    a.options.pkgdir = a.options.pkgdir || 'jam';
    a.options.outfile = a.options.outfile || a.positional[0];

    project.load(a.options.pkgdir, function (err, meta) {
        if (err) {
            return logger.error(err);
        }
        if (!a.options.includes.length) {
            // compile all installed modules by default
            a.options.includes = Object.keys(meta.dependencies);
        }
        if (!a.options.outfile) {
            logger.error('You must specify an output file');
            console.log(exports.usage);
            logger.clean_exit = true;
            return;
        }

        logger.info('compiling', a.options.outfile);
        if (a.options.includes.length) {
            logger.info('includes', a.options.includes.join(', '));
        }

        var source = '.';
        var configfile = path.resolve(
            source,
            a.options.pkgdir,
            'require.config'
        );
        var packages = require(configfile).packages;

        var impl;
        if (a.options.almond) {
            logger.info('using almond.js');
            impl = path.relative(
                source,
                path.resolve(__dirname, '../../node_modules/almond/almond.js')
            );
        }
        else {
            var impl = path.relative(
                source,
                path.resolve(__dirname, '../../node_modules/requirejs/require.js')
            );
        }

        var includes;
        if (a.options.almond) {
            includes = a.options.includes;
        }
        else {
            includes = ['jam/require.config.js'].concat(a.options.includes);
        }

        var config = {
            baseUrl: source,
            packages: packages,
            name: impl,
            wrap: a.options.wrap,
            optimize: 'uglify',
            include: includes,
            out: a.options.outfile
        };
        requirejs.optimize(config, function (build_response) {
            logger.end(a.options.outfile);
        });
    });
};
<|endoftext|>


<commit_before>/* jshint node:true */

var GitRepo   = require('../utils/git');
var tagPrefix = require('../utils/tag-prefix');
var fs        = require('fs');
var path      = require('path');
var merge     = require('merge');
var chalk     = require('chalk');
var RSVP      = require('rsvp');

var resolve = RSVP.resolve;
var resolveAll = RSVP.all;

var manifestFiles = [
  'package.json',
  'bower.json'
];

module.exports = {
  name: 'release',
  description: 'Create a new git tag at HEAD',
  works: 'insideProject',

  strategies: {
    semver: require('../strategies/semver'),
    date: require('../strategies/date')
  },

  availableOptions: [
    {
      name: 'local',
      type: Boolean,
      aliases: [ 'l' ],
      default: false,
      description: "whether release commit and tags are locally or not (not pushed to a remote)"
    },
    {
      name: 'remote',
      type: String,
      aliases: [ 'r' ],
      default: 'origin',
      description: "the git origin to push tags to, ignored if the '--local' option is true"
    },
    {
      name: 'tag',
      type: String,
      aliases: [ 't' ],
      description: "the name of the git tag to create"
    },
    {
      name: 'annotation',
      type: String,
      aliases: [ 'a' ],
      description: "a message passed to the `--message` option of `git tag`, indicating that to the tag should be created with the `--annotated` option (defualt is lightweight), the string '%@' is replaced with the tag name"
    },
    {
      name: 'message',
      type: String,
      aliases: [ 'm' ],
      default: 'Released %@',
      description: "a message passed to the `--message` option of `git commit`, the string '%@' is replaced with the tag name"
    },
    // {
    //   name: 'build',
    //   type: Boolean,
    //   aliases: [ 'b' ],
    //   default: false,
    //   description: "whether to run `ember build` or not"
    // },
    // {
    //   name: 'publish',
    //   type: Boolean,
    //   aliases: [ 'p' ],
    //   default: false,
    //   description: "whether to run `npm publish` post-tagging or not"
    // },
    {
      name: 'yes',
      type: Boolean,
      aliases: [ 'y' ],
      default: false,
      description: "whether to skip confirmation prompts or not (answer 'yes' to all questions)"
    },
    {
      name: 'strategy',
      type: String,
      aliases: [ 's' ],
      default: 'semver',
      description: "strategy for auto-generating the tag name, either 'semver' or 'date', ignored if the 'name' option is specified"
    },
    {
      name: 'major',
      type: Boolean,
      aliases: [ 'j' ],
      description: "when strategy is 'semver', specifies that the major version number should be incremented"
    },
    {
      name: 'minor',
      type: Boolean,
      aliases: [ 'i' ],
      description: "when strategy is 'semver', specifies that the minor version number should be incremented, ignored if '--major' option is true"
    },
    {
      name: 'format',
      type: String,
      aliases: [ 'f' ],
      default: 'YYYY.MM.DD',
      description: "when strategy is 'date', the format used to generate the tag"
    },
    {
      name: 'timezone',
      type: String,
      aliases: [ 'z' ],
      default: 'UTC',
      description: "when strategy is 'date', the timezone to consider the current date in"
    }
  ],

  run: function(cliOptions) {
    var SilentError = this.project.require('ember-cli/lib/errors/silent');
    var ui = this.ui;
    var projectRoot = this.project.root;
    var repo = this.git();
    var strategies = this.strategies;
    var defaultOptions = this.availableOptions.map(function(option) {
      return option.default;
    });
    var options = {};
    var pushQueue = [];

    if (fs.existsSync(path.join(this.project.root, 'config/release'))) {
      options = this.project.require('config/release');
    }

    options = merge(options, removeDefaults(cliOptions, defaultOptions));

    function proceedPrompt(ui, message) {
      if (options.yes) {
        return resolve();
      }

      return ui.prompt({
        type: 'confirm',
        name: 'proceed',
        message: chalk.yellow(message + ", proceed?"),
        choices: [
          { key: 'y', value: true },
          { key: 'n', value: false }
        ]
      }).then(function(response) {
        if (!response.proceed) {
          throw new SilentError("Aborted.");
        }
      });
    }

    function getVersioningStrategy() {
      var strategyName = options.strategy;

      if (!(strategyName in strategies)) {
        throw new SilentError("Unknown versioning strategy: '" + strategyName + "'");
      }

      return strategies[strategyName];
    }

    function abortIfAtTag() {
      return repo.currentTag().then(function(currentTag) {
        if (currentTag) {
          throw new SilentError("Skipped tagging, HEAD already at tag: " + currentTag);
        }
      });
    }

    function propmtIfWorkingTreeDirty() {
      return repo.status().then(function(status) {
        if (status) {
          return proceedPrompt(ui, "Your working tree contains modifications that will be added to the release commit");
        }
      });
    }

    function getNextTag() {
      if (options.tag) {
        // Use tag name if specified
        return {
          next: options.tag
        };
      } else {
        // Otherwise fetch all tags to pass to the versioning strategy
        return repo.tags().then(function(tags) {
          var versioningStrategy = getVersioningStrategy();
          var tagNames = tags.map(function(tag) {
            return tag.name;
          });

          return versioningStrategy(tagNames, options);
        });
      }
    }

    function printLatestVersion(latestVersion) {
      if (latestVersion) {
        ui.writeLine(chalk.green('Latest version: ' + latestVersion));
      }
    }

    function replaceVersionsInManifests(nextVersion) {
      manifestFiles.forEach(function(file) {
        var filepath = path.join(projectRoot, file);

        if (fs.existsSync(filepath)) {
          var pkg = JSON.parse(fs.readFileSync(filepath, {
            encoding: 'utf8'
          }));

          // Skip replace if 'version' key does not exist
          if (pkg.version) {
            // Don't use the 'v' tag prefix for manifest file versions
            pkg.version = tagPrefix.strip(nextVersion);

            var contents = JSON.stringify(pkg, null, 2);

            fs.writeFileSync(filepath, contents, {
              encoding: 'utf8'
            });
          }
        }
      });
    }

    function createCommit(nextVersion) {
      return repo.status().then(function(status) {
        // Don't bother committing if for some reason the working tree is clean
        if (status) {
          return repo.currentBranch().then(function(branchName) {
            if (!branchName) {
              throw new SilentError("Must have a branch checked out to commit to");
            }

            // Allow the name to be in the message
            var message = options.message.replace(/%@/g, nextVersion);

            return repo.commitAll(message).then(function() {
              pushQueue.push(branchName);
            }).then(function() {
              ui.writeLine(chalk.green("Succesfully committed changes '" + message + "' locally."));
            });
          });
        }
      });
    }

    function promptToCreateTag(nextVersion) {
      return proceedPrompt(ui, "About to create tag '" + nextVersion + "'" + (options.local ? "" : " and push to remote '" + options.remote + "'"));
    }

    function createTag(tagName) {
      var message = null;

      if (options.annotation) {
        // Allow the tag name to be in the message
        message = options.annotation.replace(/%@/g, tagName);
      }

      return repo.createTag(tagName, message).then(function() {
        pushQueue.push(tagName);
      }).then(function() {
        ui.writeLine(chalk.green("Succesfully created git tag '" + tagName + "' locally."));
      });
    }

    function pushChanges() {
      if (options.local || !pushQueue.length) { return; }

      return resolveAll(pushQueue.map(function(treeish) {
        return repo.push(options.remote, treeish).then(function() {
          ui.writeLine(chalk.green("Succesfully pushed '" + treeish + "' to remote '" + options.remote + "'."));
        });
      }));
    }

    return resolve()
      .then(abortIfAtTag)
      .then(propmtIfWorkingTreeDirty)
      .then(getNextTag)
      .then(function(versions) {
        printLatestVersion(versions.latest);

        replaceVersionsInManifests(versions.next);

        return createCommit(versions.next)
          .then(function() {
            return promptToCreateTag(versions.next);
          })
          .then(function() {
            return createTag(versions.next);
          });
      })
      .then(pushChanges);
  },

  git: function() {
    if (this._repo) {
      return this._repo;
    }

    return this._repo = new GitRepo(this.project.root);
  }
};

function removeDefaults(obj, defaults) {
  return Object.keys(obj).reduce(function(result, key) {
    if (obj[key] !== defaults[key]) {
      result[key] = obj[key];
    }

    return result;
  }, {});
}
<commit_msg>Fix a typo<commit_after>/* jshint node:true */

var GitRepo   = require('../utils/git');
var tagPrefix = require('../utils/tag-prefix');
var fs        = require('fs');
var path      = require('path');
var merge     = require('merge');
var chalk     = require('chalk');
var RSVP      = require('rsvp');

var resolve = RSVP.resolve;
var resolveAll = RSVP.all;

var manifestFiles = [
  'package.json',
  'bower.json'
];

module.exports = {
  name: 'release',
  description: 'Create a new git tag at HEAD',
  works: 'insideProject',

  strategies: {
    semver: require('../strategies/semver'),
    date: require('../strategies/date')
  },

  availableOptions: [
    {
      name: 'local',
      type: Boolean,
      aliases: [ 'l' ],
      default: false,
      description: "whether release commit and tags are locally or not (not pushed to a remote)"
    },
    {
      name: 'remote',
      type: String,
      aliases: [ 'r' ],
      default: 'origin',
      description: "the git origin to push tags to, ignored if the '--local' option is true"
    },
    {
      name: 'tag',
      type: String,
      aliases: [ 't' ],
      description: "the name of the git tag to create"
    },
    {
      name: 'annotation',
      type: String,
      aliases: [ 'a' ],
      description: "a message passed to the `--message` option of `git tag`, indicating that to the tag should be created with the `--annotated` option (defualt is lightweight), the string '%@' is replaced with the tag name"
    },
    {
      name: 'message',
      type: String,
      aliases: [ 'm' ],
      default: 'Released %@',
      description: "a message passed to the `--message` option of `git commit`, the string '%@' is replaced with the tag name"
    },
    // {
    //   name: 'build',
    //   type: Boolean,
    //   aliases: [ 'b' ],
    //   default: false,
    //   description: "whether to run `ember build` or not"
    // },
    // {
    //   name: 'publish',
    //   type: Boolean,
    //   aliases: [ 'p' ],
    //   default: false,
    //   description: "whether to run `npm publish` post-tagging or not"
    // },
    {
      name: 'yes',
      type: Boolean,
      aliases: [ 'y' ],
      default: false,
      description: "whether to skip confirmation prompts or not (answer 'yes' to all questions)"
    },
    {
      name: 'strategy',
      type: String,
      aliases: [ 's' ],
      default: 'semver',
      description: "strategy for auto-generating the tag name, either 'semver' or 'date', ignored if the 'name' option is specified"
    },
    {
      name: 'major',
      type: Boolean,
      aliases: [ 'j' ],
      description: "when strategy is 'semver', specifies that the major version number should be incremented"
    },
    {
      name: 'minor',
      type: Boolean,
      aliases: [ 'i' ],
      description: "when strategy is 'semver', specifies that the minor version number should be incremented, ignored if '--major' option is true"
    },
    {
      name: 'format',
      type: String,
      aliases: [ 'f' ],
      default: 'YYYY.MM.DD',
      description: "when strategy is 'date', the format used to generate the tag"
    },
    {
      name: 'timezone',
      type: String,
      aliases: [ 'z' ],
      default: 'UTC',
      description: "when strategy is 'date', the timezone to consider the current date in"
    }
  ],

  run: function(cliOptions) {
    var SilentError = this.project.require('ember-cli/lib/errors/silent');
    var ui = this.ui;
    var projectRoot = this.project.root;
    var repo = this.git();
    var strategies = this.strategies;
    var defaultOptions = this.availableOptions.map(function(option) {
      return option.default;
    });
    var options = {};
    var pushQueue = [];

    if (fs.existsSync(path.join(this.project.root, 'config/release'))) {
      options = this.project.require('config/release');
    }

    options = merge(options, removeDefaults(cliOptions, defaultOptions));

    function proceedPrompt(ui, message) {
      if (options.yes) {
        return resolve();
      }

      return ui.prompt({
        type: 'confirm',
        name: 'proceed',
        message: chalk.yellow(message + ", proceed?"),
        choices: [
          { key: 'y', value: true },
          { key: 'n', value: false }
        ]
      }).then(function(response) {
        if (!response.proceed) {
          throw new SilentError("Aborted.");
        }
      });
    }

    function getVersioningStrategy() {
      var strategyName = options.strategy;

      if (!(strategyName in strategies)) {
        throw new SilentError("Unknown versioning strategy: '" + strategyName + "'");
      }

      return strategies[strategyName];
    }

    function abortIfAtTag() {
      return repo.currentTag().then(function(currentTag) {
        if (currentTag) {
          throw new SilentError("Skipped tagging, HEAD already at tag: " + currentTag);
        }
      });
    }

    function promptIfWorkingTreeDirty() {
      return repo.status().then(function(status) {
        if (status) {
          return proceedPrompt(ui, "Your working tree contains modifications that will be added to the release commit");
        }
      });
    }

    function getNextTag() {
      if (options.tag) {
        // Use tag name if specified
        return {
          next: options.tag
        };
      } else {
        // Otherwise fetch all tags to pass to the versioning strategy
        return repo.tags().then(function(tags) {
          var versioningStrategy = getVersioningStrategy();
          var tagNames = tags.map(function(tag) {
            return tag.name;
          });

          return versioningStrategy(tagNames, options);
        });
      }
    }

    function printLatestVersion(latestVersion) {
      if (latestVersion) {
        ui.writeLine(chalk.green('Latest version: ' + latestVersion));
      }
    }

    function replaceVersionsInManifests(nextVersion) {
      manifestFiles.forEach(function(file) {
        var filepath = path.join(projectRoot, file);

        if (fs.existsSync(filepath)) {
          var pkg = JSON.parse(fs.readFileSync(filepath, {
            encoding: 'utf8'
          }));

          // Skip replace if 'version' key does not exist
          if (pkg.version) {
            // Don't use the 'v' tag prefix for manifest file versions
            pkg.version = tagPrefix.strip(nextVersion);

            var contents = JSON.stringify(pkg, null, 2);

            fs.writeFileSync(filepath, contents, {
              encoding: 'utf8'
            });
          }
        }
      });
    }

    function createCommit(nextVersion) {
      return repo.status().then(function(status) {
        // Don't bother committing if for some reason the working tree is clean
        if (status) {
          return repo.currentBranch().then(function(branchName) {
            if (!branchName) {
              throw new SilentError("Must have a branch checked out to commit to");
            }

            // Allow the name to be in the message
            var message = options.message.replace(/%@/g, nextVersion);

            return repo.commitAll(message).then(function() {
              pushQueue.push(branchName);
            }).then(function() {
              ui.writeLine(chalk.green("Succesfully committed changes '" + message + "' locally."));
            });
          });
        }
      });
    }

    function promptToCreateTag(nextVersion) {
      return proceedPrompt(ui, "About to create tag '" + nextVersion + "'" + (options.local ? "" : " and push to remote '" + options.remote + "'"));
    }

    function createTag(tagName) {
      var message = null;

      if (options.annotation) {
        // Allow the tag name to be in the message
        message = options.annotation.replace(/%@/g, tagName);
      }

      return repo.createTag(tagName, message).then(function() {
        pushQueue.push(tagName);
      }).then(function() {
        ui.writeLine(chalk.green("Succesfully created git tag '" + tagName + "' locally."));
      });
    }

    function pushChanges() {
      if (options.local || !pushQueue.length) { return; }

      return resolveAll(pushQueue.map(function(treeish) {
        return repo.push(options.remote, treeish).then(function() {
          ui.writeLine(chalk.green("Succesfully pushed '" + treeish + "' to remote '" + options.remote + "'."));
        });
      }));
    }

    return resolve()
      .then(abortIfAtTag)
      .then(promptIfWorkingTreeDirty)
      .then(getNextTag)
      .then(function(versions) {
        printLatestVersion(versions.latest);

        replaceVersionsInManifests(versions.next);

        return createCommit(versions.next)
          .then(function() {
            return promptToCreateTag(versions.next);
          })
          .then(function() {
            return createTag(versions.next);
          });
      })
      .then(pushChanges);
  },

  git: function() {
    if (this._repo) {
      return this._repo;
    }

    return this._repo = new GitRepo(this.project.root);
  }
};

function removeDefaults(obj, defaults) {
  return Object.keys(obj).reduce(function(result, key) {
    if (obj[key] !== defaults[key]) {
      result[key] = obj[key];
    }

    return result;
  }, {});
}
<|endoftext|>


<commit_before>import path from "path"

import webpack from "webpack"
import ExtractTextPlugin from "extract-text-webpack-plugin"

export default ({ config, pkg }) => ({
  ...config.dev && {
    devtool: "cheap-module-eval-source-map",
  },
  module: {
    loaders: [
      { // statinamic requirement
        test: /\.md$/,
        loader: "statinamic/lib/content-loader",
        query: {
          context: path.join(config.cwd, config.source),
          // renderer: (text) => html
          feedsOptions: {
            title: pkg.name,
            site_url: pkg.homepage,
          },
          feeds: {
            "feed.xml": {
              collectionOptions: {
                filter: { layout: "Post" },
                sort: "date",
                reverse: true,
                limit: 20,
              },
            },
          },
        },
      },
      {
        test: /\.css$/,
        loader: ExtractTextPlugin.extract(
          "style-loader",
          "css-loader" + (
            "?modules"+
            "&localIdentName=[path][name]--[local]--[hash:base64:5]"
          ) + "!" +
          "postcss-loader",
        ),
      },
      {
        test: /content(\/|\\).*\.(html|ico|jpe?g|png|gif)$/,
        loader: "file-loader" +
          "?name=[path][name].[ext]&context=" +
          path.join(config.cwd, config.source),
      },
      {
        test: /\.(html|ico|jpe?g|png|gif)$/,
        loader: "file-loader" +
          "?name=[path][name].[ext]&context=" +
          path.join(config.cwd, config.source),
      },
      {
        test: /\.svg$/,
        loader: "raw-loader",
      },
    ],
  },

  postcss: () => [
    require("stylelint")(),
    require("postcss-cssnext")({ browsers: "last 2 versions" }),
    require("postcss-browser-reporter")(),
    require("postcss-reporter")(),
  ],

  plugins: [
    new ExtractTextPlugin("[name].[hash].css", { disable: config.dev }),
    new webpack.DefinePlugin({ "process.env": {
      NODE_ENV: JSON.stringify(
        config.production ? "production" : process.env.NODE_ENV
      ),
      CLIENT: true,
      REDUX_DEVTOOLS: Boolean(process.env.REDUX_DEVTOOLS),
      STATINAMIC_PATHNAME: JSON.stringify(process.env.STATINAMIC_PATHNAME),
    } }),
    ...config.production && [
      new webpack.optimize.DedupePlugin(),
      new webpack.optimize.UglifyJsPlugin({
        compress: {
          warnings: false,
        },
      }),
    ],
  ],

  output: {
    path: path.join(config.cwd, config.destination),
    publicPath: config.baseUrl.pathname,
    filename: "[name].[hash].js",
  },

  resolve: {
    extensions: [ ".js", ".json", "" ],
    root: [ path.join(config.cwd, "node_modules") ],
  },
  resolveLoader: { root: [ path.join(config.cwd, "node_modules") ] },
})
<commit_msg>Update webpack config<commit_after>import path from "path"

import webpack from "webpack"
import ExtractTextPlugin from "extract-text-webpack-plugin"

export default ({ config, pkg }) => ({
  ...config.dev && {
    devtool: "cheap-module-eval-source-map",
  },
  module: {
    loaders: [
      { // statinamic requirement
        test: /\.md$/,
        loader: "statinamic/lib/content-loader",
        query: {
          context: path.join(config.cwd, config.source),
          // renderer: (text) => html
          feedsOptions: {
            title: pkg.name,
            site_url: pkg.homepage,
          },
          feeds: {
            "feed.xml": {
              collectionOptions: {
                filter: { layout: "Post" },
                sort: "date",
                reverse: true,
                limit: 20,
              },
            },
          },
        },
      },
      {
        test: /\.css$/,
        loader: ExtractTextPlugin.extract(
          "style-loader",
          "css-loader" + (
            "?modules"+
            "&localIdentName=[path][name]--[local]--[hash:base64:5]"
          ) + "!" +
          "postcss-loader",
        ),
      },
      {
        test: /content(\/|\\).*\.(html|ico|jpe?g|png|gif)$/,
        loader: "file-loader?name=[path][name].[ext]&context=./content",
      },
      {
        test: /web_modules(\/|\\).*\.(html|ico|jpe?g|png|gif)$/,
        loader: "file-loader?name=_/[path][name].[ext]&context=./web_modules",
      },
      {
        test: /\.svg$/,
        loader: "raw-loader",
      },
    ],
  },

  postcss: () => [
    require("stylelint")(),
    require("postcss-cssnext")({ browsers: "last 2 versions" }),
    require("postcss-browser-reporter")(),
    require("postcss-reporter")(),
  ],

  plugins: [
    new ExtractTextPlugin("[name].[hash].css", { disable: config.dev }),
    new webpack.DefinePlugin({ "process.env": {
      NODE_ENV: JSON.stringify(
        config.production ? "production" : process.env.NODE_ENV
      ),
      CLIENT: true,
      REDUX_DEVTOOLS: Boolean(process.env.REDUX_DEVTOOLS),
      STATINAMIC_PATHNAME: JSON.stringify(process.env.STATINAMIC_PATHNAME),
    } }),
    ...config.production && [
      new webpack.optimize.DedupePlugin(),
      new webpack.optimize.UglifyJsPlugin({
        compress: {
          warnings: false,
        },
      }),
    ],
  ],

  output: {
    path: path.join(config.cwd, config.destination),
    publicPath: config.baseUrl.pathname,
    filename: "[name].[hash].js",
  },

  resolve: {
    extensions: [ ".js", ".json", "" ],
    root: [ path.join(config.cwd, "node_modules") ],
  },
  resolveLoader: { root: [ path.join(config.cwd, "node_modules") ] },
})
<|endoftext|>


<commit_before>;(function(global) {
    var Spotify = function(selector, username, api_key, width, height) {
        return new Spotify.init(selector, username, api_key, width, height);
    }

    Spotify.prototype = {
        /*
         * Display the Spotify player
         */
        displayPlayer: function() {
            if(!this.selector) {
                throw 'Missing selector';
            }

            // Get the most recent track
            this.queryLastfm();

            console.log(this.lastfmTrack);

            // Get the track URI from Spotify
            // this.searchSpotify(lastfmTrack.title, lastfmTrack.artist, lastfmTrack.album);

            // TODO
            // Display the Spotify player using the selector and the track information
        },

        /*
         * Validate the supplied Last.FM username and api key
         */
        validateLastFM: function() {
            if(!this.username) {
                throw 'Missing username';
            }

            if(!this.api_key) {
                throw 'Missing api_key';
            }

            console.log('Validating Last.FM...');
            console.log('Username: ' + this.username);
            console.log('API Key: ' + this.api_key);

            // TODO
            // 1. Make an API call to see if the username and api_key work
            // 2. Throw an error if something goes wrong
        },

        /*
         * Get the most recently scrobbled track from Last.fm
         */
        queryLastfm: function() {
            console.log('Querying Last.FM...');

            // Set the request URL for Last.fm
            var lastfm_request_url = 'http://ws.audioscrobbler.com/2.0/?method=user.getrecenttracks&user='+this.username+'&api_key='+this.api_key+'&limit=1&format=json';

            // Make a request to the Last.fm API
            var request = new XMLHttpRequest();
            request.open('GET', lastfm_request_url, true);

            // Check for a successful response
            request.onload = function() {
                if(request.status >= 200 && request.status < 400) {
                    // Success!
                    var data = JSON.parse(request.responseText);
                    var the_track;

                    if(data.recenttracks.track[0]) {
                        the_track = data.recenttracks.track[0];
                    } else {
                        the_track = data.recenttracks.track;
                    }

                    this.lastfmTrack.title = the_track.name;
                    this.lastfmTrack.artist = the_track.artist['#text'];
                    this.lastfmTrack.album = the_track.album['#text'];
                } else {
                    // Error from the server
                    throw 'Some kind of error from the server';
                }
            };

            // Handle any errors
            request.onerror = function() {
                // Connection error
                throw 'Some kind of connection error';
            };

            // Send the request
            request.send();
        },

        /*
         * Search for track information on Spotify
         */
        searchSpotify: function(title, artist, album) {
            console.log('Searching Spotify...');

            // TODO
            // 1. Make an API call to look for the supplied track information
            // 2. Set the track URI if one was found, else throw an error

            this.spotifyURI = 'spotify-uri';
        }
    };

    Spotify.init = function(selector, username, api_key, width, height) {
        var self = this;

        self.selector = selector || '';
        self.username = username || '';
        self.api_key = api_key || '';
        self.width = width || '300';
        self.height = height || '400';
        self.lastfmTrack = {
            title: '',
            artist: '',
            album: ''
        };
        self.spotifyURI = '';

        // Validate the Last.fm username and api_key
        self.validateLastFM();

        // Display the Spotify player
        self.displayPlayer();
    }

    Spotify.init.prototype = Spotify.prototype;

    global.Spotify = Spotify;
}(window));
<commit_msg>Finish up queryLastfm method<commit_after>;(function(global) {
    var Spotify = function(selector, username, api_key, width, height) {
        return new Spotify.init(selector, username, api_key, width, height);
    }

    Spotify.prototype = {
        /*
         * Display the Spotify player
         */
        displayPlayer: function() {
            if(!this.selector) {
                throw 'Missing selector';
            }

            var self = this;
            // Get the most recent track
            this.queryLastfm(this.searchSpotify);

            // TODO
            // Display the Spotify player using the selector and the track information
        },

        /*
         * Validate the supplied Last.FM username and api key
         */
        validateLastFM: function() {
            if(!this.username) {
                throw 'Missing username';
            }

            if(!this.api_key) {
                throw 'Missing api_key';
            }

            console.log('Validating Last.FM...');
            console.log('Username: ' + this.username);
            console.log('API Key: ' + this.api_key);

            // TODO
            // 1. Make an API call to see if the username and api_key work
            // 2. Throw an error if something goes wrong
        },

        /*
         * Get the most recently scrobbled track from Last.fm
         */
        queryLastfm: function(callback) {
            console.log('Querying Last.FM...');
            var self = this;

            // Set the request URL for Last.fm
            var lastfm_request_url = 'http://ws.audioscrobbler.com/2.0/?method=user.getrecenttracks&user='+this.username+'&api_key='+this.api_key+'&limit=1&format=json';

            // Make a request to the Last.fm API
            var request = new XMLHttpRequest();
            request.open('GET', lastfm_request_url, true);

            // Check for a successful response
            request.onload = function() {
                if(request.status >= 200 && request.status < 400) {
                    // Success!
                    var data = JSON.parse(request.responseText);
                    var the_track;

                    if(data.recenttracks.track[0]) {
                        the_track = data.recenttracks.track[0];
                    } else {
                        the_track = data.recenttracks.track;
                    }

                    self.lastfmTrack = {
                        title: the_track.name,
                        artist: the_track.artist['#text'],
                        album: the_track.album['#text']
                    };

                    callback(self.lastfmTrack);
                } else {
                    // Error from the server
                    throw 'Some kind of error from the server';
                }
            };

            // Handle any errors
            request.onerror = function() {
                // Connection error
                throw 'Some kind of connection error';
            };

            // Send the request
            request.send();
        },

        /*
         * Search for track information on Spotify
         */
        searchSpotify: function(trackInfo) {
            console.log('Searching Spotify...');
            console.log(trackInfo);

            // TODO
            // 1. Make an API call to look for the supplied track information
            // 2. Set the track URI if one was found, else throw an error

            this.spotifyURI = 'spotify-uri';
        }
    };

    Spotify.init = function(selector, username, api_key, width, height) {
        var self = this;

        self.selector = selector || '';
        self.username = username || '';
        self.api_key = api_key || '';
        self.width = width || '300';
        self.height = height || '400';
        self.lastfmTrack = {
            title: '',
            artist: '',
            album: ''
        };
        self.spotifyURI = '';

        // Validate the Last.fm username and api_key
        self.validateLastFM();

        // Display the Spotify player
        self.displayPlayer();
    }

    Spotify.init.prototype = Spotify.prototype;

    global.Spotify = Spotify;
}(window));
<|endoftext|>


<commit_before>var chai = require('chai'),
  should = chai.should(),
  sinon = require('sinon'),
  sinonChai = require('sinon-chai'),
  DataAdapter = require('../../../server/data_adapter'),
  RestAdapter = require('../../../server/data_adapter/rest_adapter');

chai.use(sinonChai);

describe('RestAdapter', function() {
  var restAdapter,
    request;

  beforeEach(function () {
    request = sinon.stub();
    restAdapter = new RestAdapter({request: request});
  });

  it('should have a default user agent', function () {
    restAdapter.options.userAgent.should.equal('Rendr RestAdapter; Node.js');
  });

  it('should be an instance of DataAdapter', function () {
    restAdapter.should.be.an.instanceof(DataAdapter);
  });

  describe('request', function () {
    var api, getErrForResponse;

    beforeEach(function () {
      restAdapter.options.default = {
        host: 'example.com',
        protocol: 'http'
      };

      api = { method: 'PUT', path: '/listings/1', body: {} };

      getErrForResponse = sinon.spy(restAdapter, 'getErrForResponse');
    });

    afterEach(function () {
      getErrForResponse.restore();
    });

    it('should pass through the error object', function () {
      var error = new Error('some error'),
        callback = sinon.spy();

      request.yields(error);
      restAdapter.request({}, api, callback);

      callback.should.have.been.calledOnce;
      callback.should.have.been.calledWithMatch({ message: 'some error' });
    });

    it('should convert the error code by default', function () {
      request.yields(null, {statusCode: 404});
      restAdapter.request({}, api, sinon.spy());

      getErrForResponse.should.have.been.called;
      getErrForResponse.should.have.been.calledWithMatch({ statusCode: 404 }, { allow4xx: false })
    });

    it('should allow to set options as 3rd argument instead of the callback', function () {
      var callback = sinon.spy();

      request.yields(null, {statusCode: 404});
      restAdapter.request({}, api, { convertErrorCode: false }, callback);

      callback.should.have.been.calledOnce;
      getErrForResponse.should.not.have.been.called;
    });

    describe('json response', function () {
      var response,
        callback,
        payload = { foo: 'bar'};

      beforeEach(function () {
        response = {
          statusCode: 200,
          body: JSON.stringify(payload),
          headers: {
            'content-type': 'application/json'
          }
        };

        callback = sinon.spy();
      });

      it('should parse valid json', function () {
        request.yields(null, response, response.body);
        restAdapter.request({}, api, callback);

        callback.should.have.been.calledOnce;
        callback.should.have.been.calledWithMatch(null, response, payload);
      });

      it('should pass through the parse error for invalid json', function () {
        response.body = '{invalid json';
        request.yields(null, response, response.body);
        restAdapter.request({}, api, callback);

        callback.should.have.been.calledOnce;
        callback.should.have.been.calledWithMatch({message: 'Unexpected token i'});
      });
    });
  });

  describe('apiDefaults', function () {

    it('should set the url property if path contains a protocol', function () {
      var api = {
        path: 'http://www.example.com',
        query: { abc: 123 },
        body: {}
      };

      restAdapter.apiDefaults(api).should.have.property('url', 'http://www.example.com?abc=123');
    });

    it('should use the default api if no other is configured', function () {
      restAdapter.options.default = {
        host: 'example.com',
        protocol: 'https'
      };

      restAdapter.apiDefaults({body: {}}).should.have.property('url', 'https://example.com');
    });

    it('should handle hostname and port', function () {
      restAdapter.options.default = {
        protocol: 'https',
        hostname: 'google.org',
        port: 1337,
      };

      var api = {
        path: '/v1/dogs',
        query: {
          size: 'small'
        },
        body: {}
      };

      restAdapter.apiDefaults(api).should.have.property('url',
        'https://google.org:1337/v1/dogs?size=small');
    });

    it('should handle host and port', function () {
      restAdapter.options.default = {
        protocol: 'https',
        host: 'google.org:1337',
      };

      var api = {
        path: '/v1/dogs',
        query: {
          size: 'small'
        },
        body: {}
      };

      restAdapter.apiDefaults(api).should.have.property('url',
        'https://google.org:1337/v1/dogs?size=small');
    });

    it('should use the configured api', function () {
      var api = {
          api: 'myCustomApi',
          body: {}
        };

      restAdapter.options.myCustomApi = {
        host: 'myCustomHost',
        protocol: 'http'
      };

      restAdapter.apiDefaults(api).should.have.property('url', 'http://myCustomHost');
    });

    it('should be able to overwrite the port, protocol and query', function () {
      var api = {
          protocol: 'https',
          port: 3001,
          query: { foo: 'bar' },
          api: 'myCustomApi',
          body: {}
        },
        expectedUrl = 'https://myCustomHost:3001?foo=bar',
        result;

      restAdapter.options.myCustomApi = {
        hostname: 'myCustomHost',
        protocol: 'http',
        port: 3000
      };
      result = restAdapter.apiDefaults(api);

      result.should.have.property('url', expectedUrl);
      result.should.have.property('port', 3001);
    });

    it('should use bracketed array queries', function() {
      restAdapter.options.default = {
        protocol: 'http',
        host: 'example.com'
      };

      var api = {
        path: '/v1/cats',
        query: { q: [1, 3] },
        body: {}
      };

      restAdapter.apiDefaults(api).should.have.property('url',
        'http://example.com/v1/cats?q[]=1&q[]=3');
    });

    it('should use a custom user agent', function () {
      var api = { headers: { 'User-Agent': 'custom user agent' }, body: {} };

      restAdapter.apiDefaults(api).headers.should.be.have.property('User-Agent', 'custom user agent');
    });

    describe('JSON support', function () {
      var api = {
        headers: {},
        body: {foo: 'bar'}
      };

      it('should make it JSON if content-type is undefined', function () {
        restAdapter.apiDefaults(api).should.have.property('json', api.body);
      });

      it('should make it JSON if content-type is "application/json"', function () {
        api.headers['Content-Type'] = 'application/json';
        restAdapter.apiDefaults(api).should.have.property('json', api.body);
      });

      it('should not set the json property for a different content-type', function () {
        api.headers['Content-Type'] = 'image/jpeg';
        restAdapter.apiDefaults(api).should.not.have.property('json');
      })
    });

    it('should not set "body" and "json" for GET requests with empty body', function () {
      var api = { method: 'GET', body: {} },
        result;

      result = restAdapter.apiDefaults(api)

      result.should.not.have.property('body');
      result.should.not.have.property('json');
    });

    it('should set the defaults', function () {
      var expectedApi = {
        method: 'GET',
        url: '',
        headers: {'User-Agent': 'Rendr RestAdapter; Node.js'}
      };

      restAdapter.apiDefaults({body: {}}).should.be.deep.equal(expectedApi);
    });
  });

  describe('getErrForResponse', function () {
    it('should convert 4xx and 5xx http responses to errors', function () {
      var response = {
          statusCode: 404,
          body: 'foo'
        },
        error = restAdapter.getErrForResponse(response);

      error.should.be.an.instanceof(Error);
      error.should.have.a.property('message', response.statusCode + ' status');
      error.should.have.a.property('status', response.statusCode);
      error.should.have.a.property('body', response.body);
    });
  });

  describe('isJSONResponse', function () {
    it('should return true if the given response content-type is appliction/json', function () {
      var response = {
        headers: {
          'content-type': 'application/json'
        }
      };

      restAdapter.isJSONResponse(response).should.be.true;
    });

    it('should return false if no content-type is given', function () {
      var response = { headers: {} };

      restAdapter.isJSONResponse(response).should.be.false;
    })
  });

});
<commit_msg>test to make sure it doesn't add a ? if there is an empty object for the query parameter<commit_after>var chai = require('chai'),
  should = chai.should(),
  sinon = require('sinon'),
  sinonChai = require('sinon-chai'),
  DataAdapter = require('../../../server/data_adapter'),
  RestAdapter = require('../../../server/data_adapter/rest_adapter');

chai.use(sinonChai);

describe('RestAdapter', function() {
  var restAdapter,
    request;

  beforeEach(function () {
    request = sinon.stub();
    restAdapter = new RestAdapter({request: request});
  });

  it('should have a default user agent', function () {
    restAdapter.options.userAgent.should.equal('Rendr RestAdapter; Node.js');
  });

  it('should be an instance of DataAdapter', function () {
    restAdapter.should.be.an.instanceof(DataAdapter);
  });

  describe('request', function () {
    var api, getErrForResponse;

    beforeEach(function () {
      restAdapter.options.default = {
        host: 'example.com',
        protocol: 'http'
      };

      api = { method: 'PUT', path: '/listings/1', body: {} };

      getErrForResponse = sinon.spy(restAdapter, 'getErrForResponse');
    });

    afterEach(function () {
      getErrForResponse.restore();
    });

    it('should pass through the error object', function () {
      var error = new Error('some error'),
        callback = sinon.spy();

      request.yields(error);
      restAdapter.request({}, api, callback);

      callback.should.have.been.calledOnce;
      callback.should.have.been.calledWithMatch({ message: 'some error' });
    });

    it('should convert the error code by default', function () {
      request.yields(null, {statusCode: 404});
      restAdapter.request({}, api, sinon.spy());

      getErrForResponse.should.have.been.called;
      getErrForResponse.should.have.been.calledWithMatch({ statusCode: 404 }, { allow4xx: false })
    });

    it('should allow to set options as 3rd argument instead of the callback', function () {
      var callback = sinon.spy();

      request.yields(null, {statusCode: 404});
      restAdapter.request({}, api, { convertErrorCode: false }, callback);

      callback.should.have.been.calledOnce;
      getErrForResponse.should.not.have.been.called;
    });

    describe('json response', function () {
      var response,
        callback,
        payload = { foo: 'bar'};

      beforeEach(function () {
        response = {
          statusCode: 200,
          body: JSON.stringify(payload),
          headers: {
            'content-type': 'application/json'
          }
        };

        callback = sinon.spy();
      });

      it('should parse valid json', function () {
        request.yields(null, response, response.body);
        restAdapter.request({}, api, callback);

        callback.should.have.been.calledOnce;
        callback.should.have.been.calledWithMatch(null, response, payload);
      });

      it('should pass through the parse error for invalid json', function () {
        response.body = '{invalid json';
        request.yields(null, response, response.body);
        restAdapter.request({}, api, callback);

        callback.should.have.been.calledOnce;
        callback.should.have.been.calledWithMatch({message: 'Unexpected token i'});
      });
    });
  });

  describe('apiDefaults', function () {

    it('should set the url property if path contains a protocol', function () {
      var api = {
        path: 'http://www.example.com',
        query: { abc: 123 },
        body: {}
      };

      restAdapter.apiDefaults(api).should.have.property('url', 'http://www.example.com?abc=123');
    });

    it('should use the default api if no other is configured', function () {
      restAdapter.options.default = {
        host: 'example.com',
        protocol: 'https'
      };

      restAdapter.apiDefaults({body: {}}).should.have.property('url', 'https://example.com');
    });

    it('should handle hostname and port', function () {
      restAdapter.options.default = {
        protocol: 'https',
        hostname: 'google.org',
        port: 1337,
      };

      var api = {
        path: '/v1/dogs',
        query: {
          size: 'small'
        },
        body: {}
      };

      restAdapter.apiDefaults(api).should.have.property('url',
        'https://google.org:1337/v1/dogs?size=small');
    });

    it('should handle host and port', function () {
      restAdapter.options.default = {
        protocol: 'https',
        host: 'google.org:1337',
      };

      var api = {
        path: '/v1/dogs',
        query: {
          size: 'small'
        },
        body: {}
      };

      restAdapter.apiDefaults(api).should.have.property('url',
        'https://google.org:1337/v1/dogs?size=small');
    });

    it('should use the configured api', function () {
      var api = {
          api: 'myCustomApi',
          body: {}
        };

      restAdapter.options.myCustomApi = {
        host: 'myCustomHost',
        protocol: 'http'
      };

      restAdapter.apiDefaults(api).should.have.property('url', 'http://myCustomHost');
    });

    it('should be able to overwrite the port, protocol and query', function () {
      var api = {
          protocol: 'https',
          port: 3001,
          query: { foo: 'bar' },
          api: 'myCustomApi',
          body: {}
        },
        expectedUrl = 'https://myCustomHost:3001?foo=bar',
        result;

      restAdapter.options.myCustomApi = {
        hostname: 'myCustomHost',
        protocol: 'http',
        port: 3000
      };
      result = restAdapter.apiDefaults(api);

      result.should.have.property('url', expectedUrl);
      result.should.have.property('port', 3001);
    });

    it('should use bracketed array queries', function() {
      restAdapter.options.default = {
        protocol: 'http',
        host: 'example.com'
      };

      var api = {
        path: '/v1/cats',
        query: { q: [1, 3] },
        body: {}
      };

      restAdapter.apiDefaults(api).should.have.property('url',
        'http://example.com/v1/cats?q[]=1&q[]=3');
    });

    it('should not add an extra ? if the query is an empty object', function () {
      restAdapter.options.default = {
        host: 'example.com',
        protocol: 'https',
        query: {}
      };

      restAdapter.apiDefaults({body: {}}).should.have.property('url', 'https://example.com');
    });

    it('should use a custom user agent', function () {
      var api = { headers: { 'User-Agent': 'custom user agent' }, body: {} };

      restAdapter.apiDefaults(api).headers.should.be.have.property('User-Agent', 'custom user agent');
    });

    describe('JSON support', function () {
      var api = {
        headers: {},
        body: {foo: 'bar'}
      };

      it('should make it JSON if content-type is undefined', function () {
        restAdapter.apiDefaults(api).should.have.property('json', api.body);
      });

      it('should make it JSON if content-type is "application/json"', function () {
        api.headers['Content-Type'] = 'application/json';
        restAdapter.apiDefaults(api).should.have.property('json', api.body);
      });

      it('should not set the json property for a different content-type', function () {
        api.headers['Content-Type'] = 'image/jpeg';
        restAdapter.apiDefaults(api).should.not.have.property('json');
      })
    });

    it('should not set "body" and "json" for GET requests with empty body', function () {
      var api = { method: 'GET', body: {} },
        result;

      result = restAdapter.apiDefaults(api)

      result.should.not.have.property('body');
      result.should.not.have.property('json');
    });

    it('should set the defaults', function () {
      var expectedApi = {
        method: 'GET',
        url: '',
        headers: {'User-Agent': 'Rendr RestAdapter; Node.js'}
      };

      restAdapter.apiDefaults({body: {}}).should.be.deep.equal(expectedApi);
    });
  });

  describe('getErrForResponse', function () {
    it('should convert 4xx and 5xx http responses to errors', function () {
      var response = {
          statusCode: 404,
          body: 'foo'
        },
        error = restAdapter.getErrForResponse(response);

      error.should.be.an.instanceof(Error);
      error.should.have.a.property('message', response.statusCode + ' status');
      error.should.have.a.property('status', response.statusCode);
      error.should.have.a.property('body', response.body);
    });
  });

  describe('isJSONResponse', function () {
    it('should return true if the given response content-type is appliction/json', function () {
      var response = {
        headers: {
          'content-type': 'application/json'
        }
      };

      restAdapter.isJSONResponse(response).should.be.true;
    });

    it('should return false if no content-type is given', function () {
      var response = { headers: {} };

      restAdapter.isJSONResponse(response).should.be.false;
    })
  });

});
<|endoftext|>


<commit_before>const assert = require('assert');
const chai = require('chai');
const { BadRequest } = require('@feathersjs/errors');
const { getLesson, validateParams } = require('../../../src/services/lesson/hooks/addMaterial.js');
// todo: add more fulfilling tests
describe('lessons service', () => {
	it('registered the lessons service', () => {
		const context0 = {
			noData: 'my Data is missing',
		};
		const context1 = {
			data: 'Here is some data, but wrong type',
		};
		const context2 = {
			data: ['Foo', 'bar', 'baz'],
		};
		const [title, client, url] = [42, 24, null];
		const context3 = {
			data: [title, client, url],
		};

		const context4 = {
			data: ['title', 'client', 'url'],
		};
		const test0 = validateParams(context0); // expect to fail
		const test1 = validateParams(context1); // expect to fail
		const test2 = validateParams(context2); // expect to fail
		const test3 = validateParams(context3); // expect to fail
		const test4 = validateParams(context4); // expect to succeed

		expect(test0).to.be.instanceOf(BadRequest);
		expect(test1).to.be.instanceOf(BadRequest);
		expect(test2).to.be.instanceOf(BadRequest);
		expect(test4).not.to.be.instanceOf(BadRequest);
	});
});
<commit_msg>add test to lessons<commit_after>const assert = require('assert');
const chai = require('chai');
const { BadRequest } = require('@feathersjs/errors');
const { getLesson, validateParams } = require('../../../src/services/lesson/hooks/addMaterial.js');
// todo: add more fulfilling tests
describe.skip('lessons service', () => {
	it('registered the lessons service', () => {
		const context0 = {
			noData: 'my Data is missing',
		};
		const context1 = {
			data: 'Here is some data, but wrong type',
		};
		const context2 = {
			data: ['Foo', 'bar', 'baz'],
		};
		const [title, client, url] = [42, undefined, null];
		const context3 = {
			data: [title, client, url],
		};

		const context4 = {
			data: ['title', 'client', 'url'],
		};
		const test0 = validateParams(context0); // expect to fail
		const test1 = validateParams(context1);
		const test2 = validateParams(context2);
		const test3 = validateParams(context3);
		const test4 = validateParams(context4); // expect to succeed

		chai.expect(test0).to.be.instanceOf(BadRequest);
		chai.expect(test1).to.be.instanceOf(BadRequest);
		chai.expect(test2).to.be.instanceOf(BadRequest);
		chai.expect(test3).to.be.instanceOf(BadRequest);
		chai.expect(test4).not.to.be.instanceOf(BadRequest);
	});
});
<|endoftext|>


<commit_before>// Copyright 2017, University of Colorado Boulder

/**
 * Unit tests for PhetioObject
 *
 * @author Sam Reid (PhET Interactive Simulations)
 */
define( function( require ) {
  'use strict';

  // modules
  var PhetioObject = require( 'TANDEM/PhetioObject' );
  var Tandem = require( 'TANDEM/Tandem' );

  QUnit.module( 'PhetioObject' );

  QUnit.test( 'PhetioObject start/start', function( assert ) {
    assert.ok( true, 'initial test' );

    var obj = new PhetioObject( { tandem: Tandem.rootTandem } );
    obj.startEvent( 'model', 'hello' );
    window.assert && assert.throws( function() {
      obj.startEvent( 'model', 'hello' );
    }, 'Should throw an assertion error when starting event twice' );
  } );

  QUnit.test( 'PhetioObject start/end', function( assert ) {
    assert.ok( true, 'initial test' );

    var obj = new PhetioObject( { tandem: Tandem.rootTandem } );
    var id = obj.startEvent( 'model', 'hello' );
    obj.endEvent( id );
    assert.ok( id === undefined, 'id should be undefined' );
  } );

  QUnit.test( 'PhetioObject end without start', function( assert ) {
    assert.ok( true, 'initial test' );

    var obj = new PhetioObject( { tandem: Tandem.rootTandem } );
    window.assert && assert.throws( function() {
      obj.endEvent( 'model', 'hello' );
    }, 'Should throw an assertion error when Ending an unstarted event' );
  } );
} );<commit_msg>Removed id from start/end event, see https://github.com/phetsims/tandem/issues/52<commit_after>// Copyright 2017, University of Colorado Boulder

/**
 * Unit tests for PhetioObject
 *
 * @author Sam Reid (PhET Interactive Simulations)
 */
define( function( require ) {
  'use strict';

  // modules
  var PhetioObject = require( 'TANDEM/PhetioObject' );
  var Tandem = require( 'TANDEM/Tandem' );

  QUnit.module( 'PhetioObject' );

  QUnit.test( 'PhetioObject start/start', function( assert ) {
    assert.ok( true, 'initial test' );

    var obj = new PhetioObject( { tandem: Tandem.rootTandem } );
    obj.startEvent( 'model', 'hello' );
    window.assert && assert.throws( function() {
      obj.startEvent( 'model', 'hello' );
    }, 'Should throw an assertion error when starting event twice' );
  } );

  QUnit.test( 'PhetioObject start/end', function( assert ) {
    assert.ok( true, 'initial test' );

    var obj = new PhetioObject( { tandem: Tandem.rootTandem } );
    obj.startEvent( 'model', 'hello' );
    obj.endEvent();
  } );

  QUnit.test( 'PhetioObject end without start', function( assert ) {
    assert.ok( true, 'initial test' );

    var obj = new PhetioObject( { tandem: Tandem.rootTandem } );
    window.assert && assert.throws( function() {
      obj.endEvent( 'model', 'hello' );
    }, 'Should throw an assertion error when Ending an unstarted event' );
  } );
} );<|endoftext|>


<commit_before>import JoiBase from 'joi';
import JoiPostcodeExtension from 'joi-postcode';
import {postHandlerFactory, getHandlerFactory} from './common';

const Joi = JoiBase.extend(JoiPostcodeExtension);

const countries = [
	{ label: 'United Kingdom', value: 'United Kingdom' },
	{ label: 'Portugal', value: 'Portugal' },
	{ label: 'Palau', value: 'Palau' },
	{ label: 'Paraguay', value: 'Paraguay' },
	{ label: 'Yemen', value: 'Yemen' },
	{ label: 'Qatar', value: 'Qatar' },
	{ label: 'United Arab Emirates', value: 'United Arab Emirates' },
	{ label: 'South Africa', value: 'South Africa' },
	{ label: 'Zambia', value: 'Zambia' },
	{ label: 'Zimbabwe', value: 'Zimbabwe' },
	{ label: 'Romania', value: 'Romania' },
	{ label: 'Serbia', value: 'Serbia' },
	{ label: 'Russia', value: 'Russia' },
	{ label: 'Rwanda', value: 'Rwanda' },
	{ label: 'Saudi Arabia', value: 'Saudi Arabia' },
	{ label: 'Solomon Islands', value: 'Solomon Islands' },
	{ label: 'Seychelles', value: 'Seychelles' },
	{ label: 'The Bahamas', value: 'The Bahamas' },
	{ label: 'Sudan', value: 'Sudan' },
	{ label: 'Sweden', value: 'Sweden' },
	{ label: 'Singapore', value: 'Singapore' },
	{ label: 'Slovenia', value: 'Slovenia' },
	{ label: 'Slovakia', value: 'Slovakia' },
	{ label: 'Sierra Leone', value: 'Sierra Leone' },
	{ label: 'San Marino', value: 'San Marino' },
	{ label: 'Senegal', value: 'Senegal' },
	{ label: 'Somalia', value: 'Somalia' },
	{ label: 'Suriname', value: 'Suriname' },
	{ label: 'South Sudan', value: 'South Sudan' },
    { label: 'Sao Tome and Principe', value: 'Sao Tome and Principe' },
	{ label: 'St Kitts and Nevis', value: 'St Kitts and Nevis' },
	{ label: 'Switzerland', value: 'Switzerland' },
	{ label: 'Syria', value: 'Syria' },
	{ label: 'Swaziland', value: 'Swaziland' },
	{ label: 'Togo', value: 'Togo' },
	{ label: 'Thailand', value: 'Thailand' },
	{ label: 'Tajikistan', value: 'Tajikistan' },
	{ label: 'Lebanon', value: 'Lebanon' },
	{ label: 'Czechia', value: 'Czechia' },
	{ label: 'St Lucia', value: 'St Lucia' },
	{ label: 'Turkmenistan', value: 'Turkmenistan' },
	{ label: 'Tunisia', value: 'Tunisia' },
	{ label: 'Tonga', value: 'Tonga' },
	{ label: 'Liechtenstein', value: 'Liechtenstein' },
	{ label: 'Turkey', value: 'Turkey' },
	{ label: 'Sri Lanka', value: 'Sri Lanka' },
	{ label: 'Trinidad and Tobago', value: 'Trinidad and Tobago' },
	{ label: 'Tuvalu', value: 'Tuvalu' },
	{ label: 'Tanzania', value: 'Tanzania' },
	{ label: 'Liberia', value: 'Liberia' },
	{ label: 'Lesotho', value: 'Lesotho' },
	{ label: 'Lithuania', value: 'Lithuania' },
	{ label: 'Luxembourg', value: 'Luxembourg' },
	{ label: 'Ukraine', value: 'Ukraine' },
	{ label: 'Libya', value: 'Libya' },
	{ label: 'Uganda', value: 'Uganda' },
	{ label: 'Morocco', value: 'Morocco' },
	{ label: 'Monaco', value: 'Monaco' },
	{ label: 'Moldova', value: 'Moldova' },
	{ label: 'Montenegro', value: 'Montenegro' },
	{ label: 'Madagascar', value: 'Madagascar' },
	{ label: 'Marshall Islands', value: 'Marshall Islands' },
	{ label: 'United States', value: 'United States' },
	{ label: 'Macedonia', value: 'Macedonia' },
	{ label: 'Mali', value: 'Mali' },
	{ label: 'Mongolia', value: 'Mongolia' },
	{ label: 'Uruguay', value: 'Uruguay' },
	{ label: 'Uzbekistan', value: 'Uzbekistan' },
	{ label: 'Mauritania', value: 'Mauritania' },
	{ label: 'Malta', value: 'Malta' },
	{ label: 'Mauritius', value: 'Mauritius' },
	{ label: 'Maldives', value: 'Maldives' },
	{ label: 'Malawi', value: 'Malawi' },
	{ label: 'Vatican City', value: 'Vatican City' },
	{ label: 'Mexico', value: 'Mexico' },
	{ label: 'Malaysia', value: 'Malaysia' },
	{ label: 'St Vincent', value: 'St Vincent' },
	{ label: 'Mozambique', value: 'Mozambique' },
	{ label: 'Spain', value: 'Spain' },
	{ label: 'Venezuela', value: 'Venezuela' },
	{ label: 'Namibia', value: 'Namibia' },
	{ label: 'Niger', value: 'Niger' },
	{ label: 'Vietnam', value: 'Vietnam' },
	{ label: 'Nigeria', value: 'Nigeria' },
	{ label: 'Nicaragua', value: 'Nicaragua' },
	{ label: 'Netherlands', value: 'Netherlands' },
	{ label: 'Vanuatu', value: 'Vanuatu' },
	{ label: 'Norway', value: 'Norway' },
	{ label: 'Nepal', value: 'Nepal' },
	{ label: 'Nauru', value: 'Nauru' },
	{ label: 'Micronesia', value: 'Micronesia' },
	{ label: 'New Zealand', value: 'New Zealand' },
	{ label: 'Samoa', value: 'Samoa' },
	{ label: 'Oman', value: 'Oman' },
	{ label: 'The Gambia', value: 'The Gambia' },
	{ label: 'Panama', value: 'Panama' },
	{ label: 'Peru', value: 'Peru' },
	{ label: 'Papua New Guinea', value: 'Papua New Guinea' },
	{ label: 'Philippines', value: 'Philippines' },
	{ label: 'Pakistan', value: 'Pakistan' },
	{ label: 'Poland', value: 'Poland' }
];

const schema = Joi.object().keys({
  'country': Joi.string().max(50).label('Country')
    .meta({
      componentType: 'dropdown' ,
      children: countries,
    }),
  'town': Joi.string().max(50).label('Town or City').meta({ componentType: 'textbox' }),
  'submit': Joi.any().optional().strip()
});

const title = 'What is your Country and Town?';
const key = 'countryAndTown';
const slug = 'country-and-town';

const handlers = {
  GET: (prevSteps) => getHandlerFactory(key, title, schema, prevSteps),
  POST: (prevSteps, nextSteps) => postHandlerFactory(key, title, schema, prevSteps, nextSteps),
};

/**
 * @type Step
 */
export default {
  key,
  slug,
  title,
  schema,
  handlers
};
<commit_msg>updated step title<commit_after>import JoiBase from 'joi';
import JoiPostcodeExtension from 'joi-postcode';
import {postHandlerFactory, getHandlerFactory} from './common';

const Joi = JoiBase.extend(JoiPostcodeExtension);

const countries = [
	{ label: 'United Kingdom', value: 'United Kingdom' },
	{ label: 'Portugal', value: 'Portugal' },
	{ label: 'Palau', value: 'Palau' },
	{ label: 'Paraguay', value: 'Paraguay' },
	{ label: 'Yemen', value: 'Yemen' },
	{ label: 'Qatar', value: 'Qatar' },
	{ label: 'United Arab Emirates', value: 'United Arab Emirates' },
	{ label: 'South Africa', value: 'South Africa' },
	{ label: 'Zambia', value: 'Zambia' },
	{ label: 'Zimbabwe', value: 'Zimbabwe' },
	{ label: 'Romania', value: 'Romania' },
	{ label: 'Serbia', value: 'Serbia' },
	{ label: 'Russia', value: 'Russia' },
	{ label: 'Rwanda', value: 'Rwanda' },
	{ label: 'Saudi Arabia', value: 'Saudi Arabia' },
	{ label: 'Solomon Islands', value: 'Solomon Islands' },
	{ label: 'Seychelles', value: 'Seychelles' },
	{ label: 'The Bahamas', value: 'The Bahamas' },
	{ label: 'Sudan', value: 'Sudan' },
	{ label: 'Sweden', value: 'Sweden' },
	{ label: 'Singapore', value: 'Singapore' },
	{ label: 'Slovenia', value: 'Slovenia' },
	{ label: 'Slovakia', value: 'Slovakia' },
	{ label: 'Sierra Leone', value: 'Sierra Leone' },
	{ label: 'San Marino', value: 'San Marino' },
	{ label: 'Senegal', value: 'Senegal' },
	{ label: 'Somalia', value: 'Somalia' },
	{ label: 'Suriname', value: 'Suriname' },
	{ label: 'South Sudan', value: 'South Sudan' },
    { label: 'Sao Tome and Principe', value: 'Sao Tome and Principe' },
	{ label: 'St Kitts and Nevis', value: 'St Kitts and Nevis' },
	{ label: 'Switzerland', value: 'Switzerland' },
	{ label: 'Syria', value: 'Syria' },
	{ label: 'Swaziland', value: 'Swaziland' },
	{ label: 'Togo', value: 'Togo' },
	{ label: 'Thailand', value: 'Thailand' },
	{ label: 'Tajikistan', value: 'Tajikistan' },
	{ label: 'Lebanon', value: 'Lebanon' },
	{ label: 'Czechia', value: 'Czechia' },
	{ label: 'St Lucia', value: 'St Lucia' },
	{ label: 'Turkmenistan', value: 'Turkmenistan' },
	{ label: 'Tunisia', value: 'Tunisia' },
	{ label: 'Tonga', value: 'Tonga' },
	{ label: 'Liechtenstein', value: 'Liechtenstein' },
	{ label: 'Turkey', value: 'Turkey' },
	{ label: 'Sri Lanka', value: 'Sri Lanka' },
	{ label: 'Trinidad and Tobago', value: 'Trinidad and Tobago' },
	{ label: 'Tuvalu', value: 'Tuvalu' },
	{ label: 'Tanzania', value: 'Tanzania' },
	{ label: 'Liberia', value: 'Liberia' },
	{ label: 'Lesotho', value: 'Lesotho' },
	{ label: 'Lithuania', value: 'Lithuania' },
	{ label: 'Luxembourg', value: 'Luxembourg' },
	{ label: 'Ukraine', value: 'Ukraine' },
	{ label: 'Libya', value: 'Libya' },
	{ label: 'Uganda', value: 'Uganda' },
	{ label: 'Morocco', value: 'Morocco' },
	{ label: 'Monaco', value: 'Monaco' },
	{ label: 'Moldova', value: 'Moldova' },
	{ label: 'Montenegro', value: 'Montenegro' },
	{ label: 'Madagascar', value: 'Madagascar' },
	{ label: 'Marshall Islands', value: 'Marshall Islands' },
	{ label: 'United States', value: 'United States' },
	{ label: 'Macedonia', value: 'Macedonia' },
	{ label: 'Mali', value: 'Mali' },
	{ label: 'Mongolia', value: 'Mongolia' },
	{ label: 'Uruguay', value: 'Uruguay' },
	{ label: 'Uzbekistan', value: 'Uzbekistan' },
	{ label: 'Mauritania', value: 'Mauritania' },
	{ label: 'Malta', value: 'Malta' },
	{ label: 'Mauritius', value: 'Mauritius' },
	{ label: 'Maldives', value: 'Maldives' },
	{ label: 'Malawi', value: 'Malawi' },
	{ label: 'Vatican City', value: 'Vatican City' },
	{ label: 'Mexico', value: 'Mexico' },
	{ label: 'Malaysia', value: 'Malaysia' },
	{ label: 'St Vincent', value: 'St Vincent' },
	{ label: 'Mozambique', value: 'Mozambique' },
	{ label: 'Spain', value: 'Spain' },
	{ label: 'Venezuela', value: 'Venezuela' },
	{ label: 'Namibia', value: 'Namibia' },
	{ label: 'Niger', value: 'Niger' },
	{ label: 'Vietnam', value: 'Vietnam' },
	{ label: 'Nigeria', value: 'Nigeria' },
	{ label: 'Nicaragua', value: 'Nicaragua' },
	{ label: 'Netherlands', value: 'Netherlands' },
	{ label: 'Vanuatu', value: 'Vanuatu' },
	{ label: 'Norway', value: 'Norway' },
	{ label: 'Nepal', value: 'Nepal' },
	{ label: 'Nauru', value: 'Nauru' },
	{ label: 'Micronesia', value: 'Micronesia' },
	{ label: 'New Zealand', value: 'New Zealand' },
	{ label: 'Samoa', value: 'Samoa' },
	{ label: 'Oman', value: 'Oman' },
	{ label: 'The Gambia', value: 'The Gambia' },
	{ label: 'Panama', value: 'Panama' },
	{ label: 'Peru', value: 'Peru' },
	{ label: 'Papua New Guinea', value: 'Papua New Guinea' },
	{ label: 'Philippines', value: 'Philippines' },
	{ label: 'Pakistan', value: 'Pakistan' },
	{ label: 'Poland', value: 'Poland' }
];

const schema = Joi.object().keys({
  'country': Joi.string().max(50).label('Country')
    .meta({
      componentType: 'dropdown' ,
      children: countries,
    }),
  'town': Joi.string().max(50).label('Town or City').meta({ componentType: 'textbox' }),
  'submit': Joi.any().optional().strip()
});

const title = 'Where were you born?';
const key = 'countryAndTown';
const slug = 'country-and-town';

const handlers = {
  GET: (prevSteps) => getHandlerFactory(key, title, schema, prevSteps),
  POST: (prevSteps, nextSteps) => postHandlerFactory(key, title, schema, prevSteps, nextSteps),
};

/**
 * @type Step
 */
export default {
  key,
  slug,
  title,
  schema,
  handlers
};
<|endoftext|>