<commit_before>'use strict';

const ConfusionMatrix = require('ml-confusion-matrix');

const CV = {};
const combinations = require('ml-combinations');

/**
 * Performs a leave-one-out cross-validation (LOO-CV) of the given samples. In LOO-CV, 1 observation is used as the validation
 * set while the rest is used as the training set. This is repeated once for each observation. LOO-CV is a special case
 * of LPO-CV. @see leavePout
 * @param {function} Classifier - The classifier's constructor to use for the cross validation. Expect ml-classifier api.
 * @param {Array} features - The features for all samples of the data-set
 * @param {Array} labels - The classification class of all samples of the data-set
 * @param {object} classifierOptions - The classifier options with which the classifier should be instantiated.
 * @return {ConfusionMatrix} - The cross-validation confusion matrix
 */
CV.leaveOneOut = function (Classifier, features, labels, classifierOptions) {
    return CV.leavePOut(Classifier, features, labels, classifierOptions, 1);
};

/**
 * Performs a leave-p-out cross-validation (LPO-CV) of the given samples. In LPO-CV, p observations are used as the
 * validation set while the rest is used as the training set. This is repeated as many times as there are possible
 * ways to combine p observations from the set (unordered without replacement). Be aware that for relatively small
 * data-set size this can require a very large number of training and testing to do!
 * @param {function} Classifier - The classifier's constructor to use for the cross validation. Expect ml-classifier api.
 * @param {Array} features - The features for all samples of the data-set
 * @param {Array} labels - The classification class of all samples of the data-set
 * @param {object} classifierOptions - The classifier options with which the classifier should be instantiated.
 * @param {number} p - The size of the validation sub-samples' set
 * @return {ConfusionMatrix} - The cross-validation confusion matrix
 */
CV.leavePOut = function (Classifier, features, labels, classifierOptions, p) {
    check(features, labels);
    const distinct = getDistinct(labels);
    const confusionMatrix = initMatrix(distinct.length, distinct.length);

    var N = features.length;
    var gen = combinations(p, N);
    var allIdx = new Array(N);
    for (let i = 0; i < N; i++) {
        allIdx[i] = i;
    }
    for (const testIdx of gen) {
        var trainIdx = allIdx.slice();

        for (let i = testIdx.length - 1; i >= 0; i--) {
            trainIdx.splice(testIdx[i], 1);
        }

        validate(Classifier, features, labels, classifierOptions, testIdx, trainIdx, confusionMatrix, distinct);
    }

    return new ConfusionMatrix(confusionMatrix, distinct);
};

/**
 * Performs k-fold cross-validation (KF-CV). KF-CV separates the data-set into k random equally sized partitions, and
 * uses each as a validation set, with all other partitions used in the training set. Observations left over from if k
 * does not divide the number of observations are left out of the cross-validation process.
 * @param {function} Classifier - The classifier's to use for the cross validation. Expect ml-classifier api.
 * @param {Array} features - The features for all samples of the data-set
 * @param {Array} labels - The classification class of all samples of the data-set
 * @param {object} classifierOptions - The classifier options with which the classifier should be instantiated.
 * @param {number} k - The number of partitions to create
 * @return {ConfusionMatrix} - The cross-validation confusion matrix
 */
CV.kFold = function (Classifier, features, labels, classifierOptions, k) {
    check(features, labels);
    const distinct = getDistinct(labels);
    const confusionMatrix = initMatrix(distinct.length, distinct.length);
    var N = features.length;
    var allIdx = new Array(N);
    for (var i = 0; i < N; i++) {
        allIdx[i] = i;
    }

    var l = Math.floor(N / k);
    // create random k-folds
    var current = [];
    var folds = [];
    while (allIdx.length) {
        var randi = Math.floor(Math.random() * allIdx.length);
        current.push(allIdx[randi]);
        allIdx.splice(randi, 1);
        if (current.length === l) {
            folds.push(current);
            current = [];
        }
    }
    if (current.length) folds.push(current);
    folds = folds.slice(0, k);

    for (i = 0; i < folds.length; i++) {
        var testIdx = folds[i];
        var trainIdx = [];
        for (var j = 0; j < folds.length; j++) {
            if (j !== i) trainIdx = trainIdx.concat(folds[j]);
        }

        validate(Classifier, features, labels, classifierOptions, testIdx, trainIdx, confusionMatrix, distinct);
    }

    return new ConfusionMatrix(confusionMatrix, distinct);
};

function check(features, labels) {
    if (features.length !== labels.length) {
        throw new Error('features and labels should have the same length');
    }
}

function initMatrix(rows, columns) {
    return new Array(rows).fill(0).map(() => new Array(columns).fill(0));
}

function getDistinct(arr) {
    var s = new Set();
    for (let i = 0; i < arr.length; i++) {
        s.add(arr[i]);
    }
    return Array.from(s);
}

function validate(Classifier, features, labels, classifierOptions, testIdx, trainIdx, confusionMatrix, distinct) {
    var testFeatures = testIdx.map(function (index) {
        return features[index];
    });
    var trainFeatures = trainIdx.map(function (index) {
        return features[index];
    });
    var testLabels = testIdx.map(function (index) {
        return labels[index];
    });
    var trainLabels = trainIdx.map(function (index) {
        return labels[index];
    });

    var classifier = new Classifier(classifierOptions);
    classifier.train(trainFeatures, trainLabels);
    var predictedLabels = classifier.predict(testFeatures);
    for (var i = 0; i < predictedLabels.length; i++) {
        confusionMatrix[distinct.indexOf(testLabels[i])][distinct.indexOf(predictedLabels[i])]++;
    }
}

module.exports = CV;
<commit_msg>allow classifiers that do not have a train method<commit_after>'use strict';

const ConfusionMatrix = require('ml-confusion-matrix');

const CV = {};
const combinations = require('ml-combinations');

/**
 * Performs a leave-one-out cross-validation (LOO-CV) of the given samples. In LOO-CV, 1 observation is used as the validation
 * set while the rest is used as the training set. This is repeated once for each observation. LOO-CV is a special case
 * of LPO-CV. @see leavePout
 * @param {function} Classifier - The classifier's constructor to use for the cross validation. Expect ml-classifier api.
 * @param {Array} features - The features for all samples of the data-set
 * @param {Array} labels - The classification class of all samples of the data-set
 * @param {object} classifierOptions - The classifier options with which the classifier should be instantiated.
 * @return {ConfusionMatrix} - The cross-validation confusion matrix
 */
CV.leaveOneOut = function (Classifier, features, labels, classifierOptions) {
    return CV.leavePOut(Classifier, features, labels, classifierOptions, 1);
};

/**
 * Performs a leave-p-out cross-validation (LPO-CV) of the given samples. In LPO-CV, p observations are used as the
 * validation set while the rest is used as the training set. This is repeated as many times as there are possible
 * ways to combine p observations from the set (unordered without replacement). Be aware that for relatively small
 * data-set size this can require a very large number of training and testing to do!
 * @param {function} Classifier - The classifier's constructor to use for the cross validation. Expect ml-classifier api.
 * @param {Array} features - The features for all samples of the data-set
 * @param {Array} labels - The classification class of all samples of the data-set
 * @param {object} classifierOptions - The classifier options with which the classifier should be instantiated.
 * @param {number} p - The size of the validation sub-samples' set
 * @return {ConfusionMatrix} - The cross-validation confusion matrix
 */
CV.leavePOut = function (Classifier, features, labels, classifierOptions, p) {
    check(features, labels);
    const distinct = getDistinct(labels);
    const confusionMatrix = initMatrix(distinct.length, distinct.length);

    var N = features.length;
    var gen = combinations(p, N);
    var allIdx = new Array(N);
    for (let i = 0; i < N; i++) {
        allIdx[i] = i;
    }
    for (const testIdx of gen) {
        var trainIdx = allIdx.slice();

        for (let i = testIdx.length - 1; i >= 0; i--) {
            trainIdx.splice(testIdx[i], 1);
        }

        validate(Classifier, features, labels, classifierOptions, testIdx, trainIdx, confusionMatrix, distinct);
    }

    return new ConfusionMatrix(confusionMatrix, distinct);
};

/**
 * Performs k-fold cross-validation (KF-CV). KF-CV separates the data-set into k random equally sized partitions, and
 * uses each as a validation set, with all other partitions used in the training set. Observations left over from if k
 * does not divide the number of observations are left out of the cross-validation process.
 * @param {function} Classifier - The classifier's to use for the cross validation. Expect ml-classifier api.
 * @param {Array} features - The features for all samples of the data-set
 * @param {Array} labels - The classification class of all samples of the data-set
 * @param {object} classifierOptions - The classifier options with which the classifier should be instantiated.
 * @param {number} k - The number of partitions to create
 * @return {ConfusionMatrix} - The cross-validation confusion matrix
 */
CV.kFold = function (Classifier, features, labels, classifierOptions, k) {
    check(features, labels);
    const distinct = getDistinct(labels);
    const confusionMatrix = initMatrix(distinct.length, distinct.length);
    var N = features.length;
    var allIdx = new Array(N);
    for (var i = 0; i < N; i++) {
        allIdx[i] = i;
    }

    var l = Math.floor(N / k);
    // create random k-folds
    var current = [];
    var folds = [];
    while (allIdx.length) {
        var randi = Math.floor(Math.random() * allIdx.length);
        current.push(allIdx[randi]);
        allIdx.splice(randi, 1);
        if (current.length === l) {
            folds.push(current);
            current = [];
        }
    }
    if (current.length) folds.push(current);
    folds = folds.slice(0, k);

    for (i = 0; i < folds.length; i++) {
        var testIdx = folds[i];
        var trainIdx = [];
        for (var j = 0; j < folds.length; j++) {
            if (j !== i) trainIdx = trainIdx.concat(folds[j]);
        }

        validate(Classifier, features, labels, classifierOptions, testIdx, trainIdx, confusionMatrix, distinct);
    }

    return new ConfusionMatrix(confusionMatrix, distinct);
};

function check(features, labels) {
    if (features.length !== labels.length) {
        throw new Error('features and labels should have the same length');
    }
}

function initMatrix(rows, columns) {
    return new Array(rows).fill(0).map(() => new Array(columns).fill(0));
}

function getDistinct(arr) {
    var s = new Set();
    for (let i = 0; i < arr.length; i++) {
        s.add(arr[i]);
    }
    return Array.from(s);
}

function validate(Classifier, features, labels, classifierOptions, testIdx, trainIdx, confusionMatrix, distinct) {
    var testFeatures = testIdx.map(function (index) {
        return features[index];
    });
    var trainFeatures = trainIdx.map(function (index) {
        return features[index];
    });
    var testLabels = testIdx.map(function (index) {
        return labels[index];
    });
    var trainLabels = trainIdx.map(function (index) {
        return labels[index];
    });

    if(Classifier.prototype.train) {
        var classifier = new Classifier(classifierOptions);
        classifier.train(trainFeatures, trainLabels);
    } else {
        var classifier = new Classifier(trainFeatures, trainLabels, classifierOptions);
    }

    var predictedLabels = classifier.predict(testFeatures);
    for (var i = 0; i < predictedLabels.length; i++) {
        confusionMatrix[distinct.indexOf(testLabels[i])][distinct.indexOf(predictedLabels[i])]++;
    }
}

module.exports = CV;
<|endoftext|>


<commit_before>(function(root, name, make) {
  if (typeof module != 'undefined' && module.exports) module.exports = make();
  else root[name] = make();
}(this, 'lap', function() {
  var api = {}, slice = [].slice;

  /**
   * @param {string} name
   * @param {Function} fn
   */
  function expose(name, fn) {
    fn['sync'] = api[name] = fn;
    fn['async'] = async;
  }

  /**
   * @this {Function} sync function to run async
   */
  function async() {
    var fn = this, args = slice.call(arguments), cb = args.pop();
    setTimeout(function() {
      var err, result;
      try {
        result = fn.apply(api, args);
      } catch (e) {
        err = e;
      }
      cb.call(api, err, result);
    }, 0);
  }

  /**
   * @return {number} hi-res timestamp in milliseconds
   */
  expose('timestamp', typeof performance != 'undefined' && performance.now ? function() {
    return performance.now();
  } : typeof process != 'undefined' && process.hrtime ? function() {
    var a = process.hrtime(); // [seconds, nanoseconds]
    return 1e3*a[0] + a[1]/1e6;
  } : Date.now ? function() {
    return Date.now();
  } : function() {
    return (new Date).getTime();
  });

  /**
   * @param {number} laps
   * @param {Array|Function} racers
   * @return {Array} times (milliseconds) for each racer to run `laps` times
   */
  expose('time', function(laps, racers) {
    if (typeof racers == 'function') racers = [racers];
    var start, end, f, n, r = [], i = 0, l = racers.length, stamp = api['timestamp'];
    for (start = end || stamp(); i < l; end = stamp(), r[i++] = end - start) {
      for (f = racers[i], n = 0; n++ < laps;) {
        f.call(api);
      }
    }
    return r;
  });

  /**
   * @param {number} laps
   * @param {Array|Function} racers
   * @return {Array} speeds (operations/second) for each racer to run `laps` times
   */
  expose('speed', function(laps, racers) {
    for (var r = api['time'](laps, racers), i = r.length; i--;) r[i] = 1000*laps/r[i];
    return r;
  });

  return api;
}));<commit_msg>Fix time() loop.<commit_after>(function(root, name, make) {
  if (typeof module != 'undefined' && module.exports) module.exports = make();
  else root[name] = make();
}(this, 'lap', function() {
  var api = {}, slice = [].slice;

  /**
   * @param {string} name
   * @param {Function} fn
   */
  function expose(name, fn) {
    fn['sync'] = api[name] = fn;
    fn['async'] = async;
  }

  /**
   * @this {Function} sync function to run async
   */
  function async() {
    var fn = this, args = slice.call(arguments), cb = args.pop();
    setTimeout(function() {
      var err, result;
      try {
        result = fn.apply(api, args);
      } catch (e) {
        err = e;
      }
      cb.call(api, err, result);
    }, 0);
  }

  /**
   * @return {number} hi-res timestamp in milliseconds
   */
  expose('timestamp', typeof performance != 'undefined' && performance.now ? function() {
    return performance.now();
  } : typeof process != 'undefined' && process.hrtime ? function() {
    var a = process.hrtime(); // [seconds, nanoseconds]
    return 1e3*a[0] + a[1]/1e6;
  } : Date.now ? function() {
    return Date.now();
  } : function() {
    return (new Date).getTime();
  });

  /**
   * @param {number} laps
   * @param {Array|Function} racers
   * @return {Array} times (milliseconds) for each racer to run `laps` times
   */
  expose('time', function(laps, racers) {
    if (typeof racers == 'function') racers = [racers];
    var start, end, f, n, r = [], i = 0, l = racers.length, stamp = api['timestamp'];
    for (; i < l; end = stamp(), r[i++] = end - start) {
      for (start = end || stamp(), f = racers[i], n = 0; n++ < laps;) {
        f.call(api);
      }
    }
    return r;
  });

  /**
   * @param {number} laps
   * @param {Array|Function} racers
   * @return {Array} speeds (operations/second) for each racer to run `laps` times
   */
  expose('speed', function(laps, racers) {
    for (var r = api['time'](laps, racers), i = r.length; i--;) r[i] = 1000*laps/r[i];
    return r;
  });

  return api;
}));<|endoftext|>


<commit_before>import Matches from "./matches";

// Maps symbols to matches.
const SYMBOL_MATCHES = {
    "#": Matches.id,
    ".": Matches.className
};

// TODO: Use better variables names.
function ReactShallowQuery(object, query) {
    if (typeof query !== "string")
        throw new Error("You must provide a query.");

    var results = Array.isArray(object) ? object : [object];
    var fragments = query.split(" ");
    var recursive = true;

    // Loop through each fragement.
    // TODO: Use Array.reduce.
    fragments.forEach((fragment, index) => {
        var prefix = fragment.charAt(0);
        var newResults = [];
        var matcher;

        if (fragment == ">")
            return recursive = false;

        // Handle prefix symbols.
        if (SYMBOL_MATCHES[prefix]) {
            matcher = SYMBOL_MATCHES[prefix];
        } else {
            let upperCase = (prefix === prefix.toUpperCase());

            // Handle default and custom React component names.
            matcher = Matches[upperCase ? "displayName" : "type"];
        }

        results.forEach((result) => {
            var objects = (index ? result.props.children : result);
            var foundResults;

            if (!Array.isArray(objects))
                objects = [objects];

            foundResults = findResults(objects, matcher, fragment, recursive);

            // Append the newly found results to the 'newResults' array.
            newResults.push.apply(newResults, foundResults);
        });

        results = newResults;
    });

    return results;
};

function findResults(objects = [], matcher, fragment, recursive) {
    if (!Array.isArray(objects))
        objects = [objects];

    return objects.reduce((results, object) => {
        // Ignore objects that aren't components (e.g. text) or null values.
        if (!object || typeof object !== "object")
            return results;

        // This covers the case where array.map is used when composing components.
        if (Array.isArray(object))
            return results.concat(findResults(object, matcher, fragment, recursive));

        // Check if the object is valid and append it to our results if true.
        if (matcher(object, fragment))
            results.push(object);

        const {props} = object;

        if (!props || !props.children || !recursive)
            return results;

        // Append the newly found results onto the 'results' array.
        return results.concat(findResults(props.children, matcher, fragment, recursive));
    }, []);
}

export default ReactShallowQuery;
<commit_msg>Refactored to use reduce instead of forEach + accumulative array.<commit_after>import Matches from "./matches";

// Maps symbols to matches.
const SYMBOL_MATCHES = {
    "#": Matches.id,
    ".": Matches.className
};

// TODO: Use better variables names.
function ReactShallowQuery(object, query) {
    if (typeof query !== "string")
        throw new Error("You must provide a query.");

    var results = Array.isArray(object) ? object : [object];
    var fragments = query.split(" ");
    var recursive = true;

    // Loop through each fragement.
    // TODO: Use Array.reduce.
    fragments.forEach((fragment, index) => {
        var prefix = fragment.charAt(0);
        var matcher;

        if (fragment == ">")
            return recursive = false;

        // Handle prefix symbols.
        if (SYMBOL_MATCHES[prefix]) {
            matcher = SYMBOL_MATCHES[prefix];
        } else {
            let upperCase = (prefix === prefix.toUpperCase());

            // Handle default and custom React component names.
            matcher = Matches[upperCase ? "displayName" : "type"];
        }

        results = results.reduce((elements, element) => {
            var objects = (index ? element.props.children : element);

            if (!Array.isArray(objects))
                objects = [objects];

            // Append the newly found elements.
            return elements.concat(findResults(objects, matcher, fragment, recursive));
        }, []);
    });

    return results;
};

function findResults(objects = [], matcher, fragment, recursive) {
    if (!Array.isArray(objects))
        objects = [objects];

    return objects.reduce((results, object) => {
        // Ignore objects that aren't components (e.g. text) or null values.
        if (!object || typeof object !== "object")
            return results;

        // This covers the case where array.map is used when composing components.
        if (Array.isArray(object))
            return results.concat(findResults(object, matcher, fragment, recursive));

        // Check if the object is valid and append it to our results if true.
        if (matcher(object, fragment))
            results.push(object);

        const {props} = object;

        if (!props || !props.children || !recursive)
            return results;

        // Append the newly found results onto the 'results' array.
        return results.concat(findResults(props.children, matcher, fragment, recursive));
    }, []);
}

export default ReactShallowQuery;
<|endoftext|>


<commit_before>import { exec } from 'child_process';
import bs from 'browser-sync';
import { Server } from 'karma';
import del from 'del';
import runSequence from 'run-sequence';
import nib from 'nib';
import glob from 'glob';

/** Gulp plugins **/
import gulpHelp from 'gulp-help';
import gutil from 'gulp-util';
import git from 'gulp-git';
import eslint from 'gulp-eslint';
import bump from 'gulp-bump';
import stylus from 'gulp-stylus';
import sourcemaps from 'gulp-sourcemaps';
import autoprefixer from 'gulp-autoprefixer';

function deepAssign(target, ...rest) {
    let combined = target;
    rest.forEach(source => {
        combined = walkSource(combined, source);
    });

    return combined;
}

function walkSource(_target, _source) {
    Object.keys(_source).forEach(key => {
        const value = _source[key];

        if ( Array.isArray(value) ) {
            _target[key] = value.slice();
        } else if ( isObj(value) ) {
            _target[key] = deepAssign(_target[key] || {}, value);
        } else if ( value !== undefined ) {
            _target[key] = value;
        }
    });

    return _target;
}

function isObj(x) {
    const type = typeof x;
    return x !== null && (type === 'object' || type === 'function');
}

function setupConfig(_config) {
    const defaultConfig = {
        paths: {
            root: './',
            src: {
                root: 'src/',
                html: 'src/templates/',
                images: 'src/images/',
                javascript: 'src/javascript/',
                stylesheets: 'src/stylesheets/',
            },
            dist: {
                root: 'dist/',
                html: 'dist/templates/',
                images: 'dist/images/',
                javascript: 'dist/javascript/',
                stylesheets: 'dist/stylesheets/',
            },
            config: {
                karma: 'test/karma.conf.js',
            },
            test: {
                unit: 'test/unit/',
                e2e: 'test/e2e',
            },
            serve: 'demo/',
            lint: {
                js: ['src/**/*.js', 'test/**/*.js', 'demo/**/*.js'],
            },
            watch: {
                stylesheets: false,
                javascript: false,
            },
            stylusInclude: glob.sync(process.cwd() + '/jspm_packages/apsis/tenko*/'),
        },
        options: {
            'stylusTenkoTimeout': 500,
        },
    };

    return deepAssign({}, defaultConfig, _config);
}

class Apsis {
    constructor(_gulp, _config) {
        const gulp = gulpHelp(_gulp);
        this.config = setupConfig(_config);

        this.options = gutil.env;

        this.releaseFn(gulp, this.config);
        this.bumpFn(gulp, this.config);
        this.cleanFn(gulp, this.config);
        this.copyFn(gulp, this.config);
        this.defaultFn(gulp, this.config);
        this.eslintFn(gulp, this.config);
        this.gitFn(gulp, this.config);
        this.npmFn(gulp, this.config);
        this.serveFn(gulp, this.config);
        this.stylusFn(gulp, this.config);
        this.testFn(gulp, this.config);
        this.watchFn(gulp, this.config);
    }

    bumpFn(gulp, config) {
        gulp.task('bump', 'Bump the package version in package.json', () => {
            const type = gutil.env.bump || 'patch';

            gulp.src(config.paths.root + 'package.json')
                .pipe(bump({type}))
                .pipe(gulp.dest(config.paths.root));
        }, {
            options: {
                'bump [type]': 'what bump to perform. [patch, minor, major]',
            },
        });
    }

    cleanFn(gulp, config) {
        gulp.task('clean:dist', 'Delete the dist/ directory', () => {
            del([
                config.paths.dist.root,
            ]);
        });
    }

    copyFn(gulp, config) {
        gulp.task('copy:dist', 'Copy JS and HTML to dist/', () => {
            gulp.src([
                config.paths.src.root + '**/*.js',
                config.paths.src.root + '**/*.html',
            ])
                .pipe(gulp.dest(config.paths.dist.root));
        });
    }

    defaultFn(gulp) {
        gulp.task('default', 'Sets up the dev environment', () => {
            const taskArr = [
                [ 'stylus', 'eslint' ],
                'watch',
                'serve',
            ];

            if ( !this.options.skipinstall ) {
                taskArr.unshift('npm:install');
            } else {
                gutil.log(gutil.colors.red('Skipping npm installation process.'));
            }

            return runSequence.use(gulp).apply(gulp, taskArr);
        }, {
            options: {
                'skipinstall': 'add to skip npm install at the top of the task',
            },
        });
    }

    eslintFn(gulp, config) {
        gulp.task('eslint', 'Lint your JavaScript with ESLint', () => {
            return gulp.src(config.paths.lint.js)
                .pipe(eslint())
                .pipe(eslint.format());
        });

        gulp.task('eslint:fail', false, () => {
            return gulp.src(config.paths.lint.js)
                .pipe(eslint())
                .pipe(eslint.format())
                .pipe(eslint.failOnError());
        });
    }

    gitFn(gulp) {
        gulp.task('commit:bump', false, () => {
            return gulp.src('.')
                .pipe(git.add())
                .pipe(git.commit('[Prerelease] Bump version number'));
        });

        gulp.task('commit:dist', false, () => {
            return gulp.src('.')
                .pipe(git.add())
                .pipe(git.commit('[Prerelease] Update dist/ files'));
        });
    }

    npmFn(gulp) {
        gulp.task('npm:install', 'Run npm install', (cb) => {
            Apsis.runExec('npm install', cb);
        });

        gulp.task('npm:update', 'Run npm install', (cb) => {
            Apsis.runExec('npm update', cb);
        });
    }

    releaseFn(gulp) {
        gulp.task('release', done => {
            runSequence.use(gulp)(
                'clean:dist',
                'eslint:fail',
                [ 'copy:dist', 'stylus:dist' ],
                'commit:dist',
                'bump',
                'commit:bump',
                error => {
                    if (error) {
                        gutil.log(error.message);
                    } else {
                        gutil.log('RELEASE FINISHED SUCCESSFULLY');
                    }
                    done(error);
                }
            );
        });
    }

    serveFn(gulp, config) {
        const browserSync = bs.create();

        gulp.task('serve', 'Create a server instance on localhost:9000', () => {
            const browserSyncOptions = {
                port: 9000,
                startPath: config.paths.serve,
                files: [
                    config.paths.serve + '*.html',
                    config.paths.serve + '*.js',
                    config.paths.src.javascript + 'src/javascript/**/*.js',
                    config.paths.src.images + '**/*',
                    config.paths.src.html + '*.html',
                    config.paths.src.stylesheets + '*.css',
                ],
                open: !!gutil.env.browser,
                server: {
                    baseDir: ['./'],
                    middleware: (req, res, next) => {
                        res.setHeader('Access-Control-Allow-Origin', '*');
                        next();
                    },
                },
            };

            if (!!gutil.env.browser ) {
                browserSyncOptions.browser = gutil.env.browser;
            }

            return browserSync.init(browserSyncOptions);
        }, {
            options: {
                'browser': 'Open the given browser on init',
            },
        });
    }

    stylusFn(gulp, config) {
        function getStylusOptions(_options = {}) {
            const defaultOptions = {
                use: nib(),
                compress: false,
            };

            if ( !!config.paths.stylusInclude ) {
                defaultOptions.include = config.paths.stylusInclude;
            }

            return Object.assign(defaultOptions, _options);
        }

        gulp.task('stylus', 'Compile stylus files into src/stylesheets.', () => {
            const options = getStylusOptions();

            return gulp.src(config.paths.src.stylesheets + '**/*.styl')
                .pipe(sourcemaps.init())
                .pipe(stylus(options))
                .pipe(autoprefixer())
                .pipe(sourcemaps.write())
                .pipe(gulp.dest(config.paths.src.stylesheets));
        }, {
            aliases: [ 'styles' ],
        });

        gulp.task('stylus:tenko', false, cb => {
            const options = getStylusOptions();

            setTimeout(() => {
                gulp.src(config.paths.src.stylesheets + '**/*.styl')
                    .pipe(sourcemaps.init())
                    .pipe(stylus(options))
                    .pipe(autoprefixer())
                    .pipe(sourcemaps.write())
                    .pipe(gulp.dest(config.paths.src.stylesheets))
                    .on('end', cb);
            }, config.options.stylusTenkoTimeout);
        });

        gulp.task('stylus:dist', false, () => {
            const options = getStylusOptions({
                compress: true,
            });

            return gulp.src(config.paths.src.stylesheets + '**/*.styl')
                .pipe(stylus(options))
                .pipe(autoprefixer())
                .pipe(gulp.dest(config.paths.dist.stylesheets));
        });
    }

    testFn(gulp, config) {
        gulp.task('test', 'Run Karma tests', done => {
            new Server({
                configFile: process.cwd() + '/' + config.paths.config.karma,
            }, done).start();
        });

        gulp.task('tdd', 'Run Karma tests', done => {
            new Server({
                configFile: process.cwd() + '/' + config.paths.config.karma,
            }, done).start();
        });
    }

    watchFn(gulp, config) {
        const stylusWatchPath = config.paths.watch.stylesheets || config.paths.src.stylesheets + '**/*.styl';
        let stylusTask = ['stylus'];

        if ( !!gutil.env.tenko ) {
            stylusTask = [ 'stylus:tenko' ];
        }

        gulp.task('watch', false, () => {
            gulp.watch(config.paths.lint.js, ['eslint']);
            gulp.watch(stylusWatchPath, stylusTask);
        }, {
            options: {
                'tenko': 'run a special tenko task, that makes it possible to used a linked Tenko package',
            },
        });
    }

    static runExec(cmd, cb) {
        exec(cmd, (err, stdout) => {
            gutil.log(stdout);

            cb(err);
        });
    }
}

function apsisGulpConfig(_gulp, _config) {
    return new Apsis(_gulp, _config);
}

export { apsisGulpConfig };
<commit_msg>fix: update path to browsersync js files watch<commit_after>import { exec } from 'child_process';
import bs from 'browser-sync';
import { Server } from 'karma';
import del from 'del';
import runSequence from 'run-sequence';
import nib from 'nib';
import glob from 'glob';

/** Gulp plugins **/
import gulpHelp from 'gulp-help';
import gutil from 'gulp-util';
import git from 'gulp-git';
import eslint from 'gulp-eslint';
import bump from 'gulp-bump';
import stylus from 'gulp-stylus';
import sourcemaps from 'gulp-sourcemaps';
import autoprefixer from 'gulp-autoprefixer';

function deepAssign(target, ...rest) {
    let combined = target;
    rest.forEach(source => {
        combined = walkSource(combined, source);
    });

    return combined;
}

function walkSource(_target, _source) {
    Object.keys(_source).forEach(key => {
        const value = _source[key];

        if ( Array.isArray(value) ) {
            _target[key] = value.slice();
        } else if ( isObj(value) ) {
            _target[key] = deepAssign(_target[key] || {}, value);
        } else if ( value !== undefined ) {
            _target[key] = value;
        }
    });

    return _target;
}

function isObj(x) {
    const type = typeof x;
    return x !== null && (type === 'object' || type === 'function');
}

function setupConfig(_config) {
    const defaultConfig = {
        paths: {
            root: './',
            src: {
                root: 'src/',
                html: 'src/templates/',
                images: 'src/images/',
                javascript: 'src/javascript/',
                stylesheets: 'src/stylesheets/',
            },
            dist: {
                root: 'dist/',
                html: 'dist/templates/',
                images: 'dist/images/',
                javascript: 'dist/javascript/',
                stylesheets: 'dist/stylesheets/',
            },
            config: {
                karma: 'test/karma.conf.js',
            },
            test: {
                unit: 'test/unit/',
                e2e: 'test/e2e',
            },
            serve: 'demo/',
            lint: {
                js: ['src/**/*.js', 'test/**/*.js', 'demo/**/*.js'],
            },
            watch: {
                stylesheets: false,
                javascript: false,
            },
            stylusInclude: glob.sync(process.cwd() + '/jspm_packages/apsis/tenko*/'),
        },
        options: {
            'stylusTenkoTimeout': 500,
        },
    };

    return deepAssign({}, defaultConfig, _config);
}

class Apsis {
    constructor(_gulp, _config) {
        const gulp = gulpHelp(_gulp);
        this.config = setupConfig(_config);

        this.options = gutil.env;

        this.releaseFn(gulp, this.config);
        this.bumpFn(gulp, this.config);
        this.cleanFn(gulp, this.config);
        this.copyFn(gulp, this.config);
        this.defaultFn(gulp, this.config);
        this.eslintFn(gulp, this.config);
        this.gitFn(gulp, this.config);
        this.npmFn(gulp, this.config);
        this.serveFn(gulp, this.config);
        this.stylusFn(gulp, this.config);
        this.testFn(gulp, this.config);
        this.watchFn(gulp, this.config);
    }

    bumpFn(gulp, config) {
        gulp.task('bump', 'Bump the package version in package.json', () => {
            const type = gutil.env.bump || 'patch';

            gulp.src(config.paths.root + 'package.json')
                .pipe(bump({type}))
                .pipe(gulp.dest(config.paths.root));
        }, {
            options: {
                'bump [type]': 'what bump to perform. [patch, minor, major]',
            },
        });
    }

    cleanFn(gulp, config) {
        gulp.task('clean:dist', 'Delete the dist/ directory', () => {
            del([
                config.paths.dist.root,
            ]);
        });
    }

    copyFn(gulp, config) {
        gulp.task('copy:dist', 'Copy JS and HTML to dist/', () => {
            gulp.src([
                config.paths.src.root + '**/*.js',
                config.paths.src.root + '**/*.html',
            ])
                .pipe(gulp.dest(config.paths.dist.root));
        });
    }

    defaultFn(gulp) {
        gulp.task('default', 'Sets up the dev environment', () => {
            const taskArr = [
                [ 'stylus', 'eslint' ],
                'watch',
                'serve',
            ];

            if ( !this.options.skipinstall ) {
                taskArr.unshift('npm:install');
            } else {
                gutil.log(gutil.colors.red('Skipping npm installation process.'));
            }

            return runSequence.use(gulp).apply(gulp, taskArr);
        }, {
            options: {
                'skipinstall': 'add to skip npm install at the top of the task',
            },
        });
    }

    eslintFn(gulp, config) {
        gulp.task('eslint', 'Lint your JavaScript with ESLint', () => {
            return gulp.src(config.paths.lint.js)
                .pipe(eslint())
                .pipe(eslint.format());
        });

        gulp.task('eslint:fail', false, () => {
            return gulp.src(config.paths.lint.js)
                .pipe(eslint())
                .pipe(eslint.format())
                .pipe(eslint.failOnError());
        });
    }

    gitFn(gulp) {
        gulp.task('commit:bump', false, () => {
            return gulp.src('.')
                .pipe(git.add())
                .pipe(git.commit('[Prerelease] Bump version number'));
        });

        gulp.task('commit:dist', false, () => {
            return gulp.src('.')
                .pipe(git.add())
                .pipe(git.commit('[Prerelease] Update dist/ files'));
        });
    }

    npmFn(gulp) {
        gulp.task('npm:install', 'Run npm install', (cb) => {
            Apsis.runExec('npm install', cb);
        });

        gulp.task('npm:update', 'Run npm install', (cb) => {
            Apsis.runExec('npm update', cb);
        });
    }

    releaseFn(gulp) {
        gulp.task('release', done => {
            runSequence.use(gulp)(
                'clean:dist',
                'eslint:fail',
                [ 'copy:dist', 'stylus:dist' ],
                'commit:dist',
                'bump',
                'commit:bump',
                error => {
                    if (error) {
                        gutil.log(error.message);
                    } else {
                        gutil.log('RELEASE FINISHED SUCCESSFULLY');
                    }
                    done(error);
                }
            );
        });
    }

    serveFn(gulp, config) {
        const browserSync = bs.create();

        gulp.task('serve', 'Create a server instance on localhost:9000', () => {
            const browserSyncOptions = {
                port: 9000,
                startPath: config.paths.serve,
                files: [
                    config.paths.serve + '*.html',
                    config.paths.serve + '*.js',
                    config.paths.src.root + '**/*.js',
                    config.paths.src.images + '**/*',
                    config.paths.src.html + '*.html',
                    config.paths.src.stylesheets + '*.css',
                ],
                open: !!gutil.env.browser,
                server: {
                    baseDir: ['./'],
                    middleware: (req, res, next) => {
                        res.setHeader('Access-Control-Allow-Origin', '*');
                        next();
                    },
                },
            };

            if (!!gutil.env.browser ) {
                browserSyncOptions.browser = gutil.env.browser;
            }

            return browserSync.init(browserSyncOptions);
        }, {
            options: {
                'browser': 'Open the given browser on init',
            },
        });
    }

    stylusFn(gulp, config) {
        function getStylusOptions(_options = {}) {
            const defaultOptions = {
                use: nib(),
                compress: false,
            };

            if ( !!config.paths.stylusInclude ) {
                defaultOptions.include = config.paths.stylusInclude;
            }

            return Object.assign(defaultOptions, _options);
        }

        gulp.task('stylus', 'Compile stylus files into src/stylesheets.', () => {
            const options = getStylusOptions();

            return gulp.src(config.paths.src.stylesheets + '**/*.styl')
                .pipe(sourcemaps.init())
                .pipe(stylus(options))
                .pipe(autoprefixer())
                .pipe(sourcemaps.write())
                .pipe(gulp.dest(config.paths.src.stylesheets));
        }, {
            aliases: [ 'styles' ],
        });

        gulp.task('stylus:tenko', false, cb => {
            const options = getStylusOptions();

            setTimeout(() => {
                gulp.src(config.paths.src.stylesheets + '**/*.styl')
                    .pipe(sourcemaps.init())
                    .pipe(stylus(options))
                    .pipe(autoprefixer())
                    .pipe(sourcemaps.write())
                    .pipe(gulp.dest(config.paths.src.stylesheets))
                    .on('end', cb);
            }, config.options.stylusTenkoTimeout);
        });

        gulp.task('stylus:dist', false, () => {
            const options = getStylusOptions({
                compress: true,
            });

            return gulp.src(config.paths.src.stylesheets + '**/*.styl')
                .pipe(stylus(options))
                .pipe(autoprefixer())
                .pipe(gulp.dest(config.paths.dist.stylesheets));
        });
    }

    testFn(gulp, config) {
        gulp.task('test', 'Run Karma tests', done => {
            new Server({
                configFile: process.cwd() + '/' + config.paths.config.karma,
            }, done).start();
        });

        gulp.task('tdd', 'Run Karma tests', done => {
            new Server({
                configFile: process.cwd() + '/' + config.paths.config.karma,
            }, done).start();
        });
    }

    watchFn(gulp, config) {
        const stylusWatchPath = config.paths.watch.stylesheets || config.paths.src.stylesheets + '**/*.styl';
        let stylusTask = ['stylus'];

        if ( !!gutil.env.tenko ) {
            stylusTask = [ 'stylus:tenko' ];
        }

        gulp.task('watch', false, () => {
            gulp.watch(config.paths.lint.js, ['eslint']);
            gulp.watch(stylusWatchPath, stylusTask);
        }, {
            options: {
                'tenko': 'run a special tenko task, that makes it possible to used a linked Tenko package',
            },
        });
    }

    static runExec(cmd, cb) {
        exec(cmd, (err, stdout) => {
            gutil.log(stdout);

            cb(err);
        });
    }
}

function apsisGulpConfig(_gulp, _config) {
    return new Apsis(_gulp, _config);
}

export { apsisGulpConfig };
<|endoftext|>


<commit_before>#!/usr/bin/env node

var fs = require('fs');

var LintReporter = require('./js/lint-reporter');
var templateUtils = require('hairballs').templateUtils;

process.stdin.resume();
process.stdin.setEncoding('utf8');

var input = '';

process.stdin.on('data', function(chunk) {
  input += chunk;
});

process.stdin.on('end', function(foo) {
  console.log(foo);
  var lintReporter = new LintReporter(input);

  var data = lintReporter.runReport();

  if (lintReporter.generateHtml) {
    fs.writeFile(lintReporter.outputPath, templateUtils.applyTemplates(data), function(err) {
      if (err) {
        throw err;
      }
    });
  }
});
<commit_msg>removing console<commit_after>#!/usr/bin/env node

var fs = require('fs');

var LintReporter = require('./js/lint-reporter');
var templateUtils = require('hairballs').templateUtils;

process.stdin.resume();
process.stdin.setEncoding('utf8');

var input = '';

process.stdin.on('data', function(chunk) {
  input += chunk;
});

process.stdin.on('end', function() {
  var lintReporter = new LintReporter(input);

  var data = lintReporter.runReport();

  if (lintReporter.generateHtml) {
    fs.writeFile(lintReporter.outputPath, templateUtils.applyTemplates(data), function(err) {
      if (err) {
        throw err;
      }
    });
  }
});
<|endoftext|>


<commit_before>'use strict';

var assert = require('assert');
var async = require('async');
var log = require('loglevel');
var auth = require('./lib/auth.js');
var helpers = require('./lib/helpers.js');

function Meeseeks(opts) {
  var _this = this;
  opts = opts || {};
  this.opts = {};
  this.opts.name = opts.name || ('meeseeks:' + Math.random());
  this.opts.jwtSigningToken = opts.jwtSigningToken || '';
  this.opts.skipJwtValidation = opts.skipJwtValidation || (process.env.NODE_ENV === 'development');
  this.opts.logLevel = opts.logLevel || helpers.logLevelFromEnv();
  this.log = log.getLogger(this.opts.name);
  this.log.setLogLevel(this.opts.logLevel);
  Object.defineProperty(this, 'handler', {
    value: function(event, context) {
      this.debug('Event Received', JSON.stringify(event, null, 2));
      var meeseeksContext = _this.createContextFromEvent(event);
      var origin = { event: event, context: context };
      _this._invoke(meeseeksContext, origin);
    },
  });
  this._listeners = {};
  this.log.info('Handler "' + this.opts.name + '" Ready');
}

Meeseeks.prototype.define = function(name, definition) {
  if (this._listeners[name]) throw new Error('Meeseeks: Listener already exists for "' + name + '"');
  this.log.info('Defined "' + name + '"');
  this._listeners[name] = definition;
};

Meeseeks.prototype.createContextFromEvent = function(event) {
  var authorization = auth.verify(this.opts.jwtSigningToken, event.token, this.opts.skipJwtValidation);
  var meeseeksContext = {
    name: event.method,
    body: event.body || {},
    authorization: authorization,
    identity: authorization.sub,
    received: helpers.now(),
  };
  helpers.deepFreeze(meeseeksContext);
  return meeseeksContext;
};

Meeseeks.prototype._invoke = function(meeseeksContext, origin) {
  var _this = this;
  var listener = this._listeners[meeseeksContext.name];
  if (!listener) {
    origin.context.fail(new Error('invalid target "' + meeseeksContext.name + '"'));
    this.log.warn('No listener exists for "' + meeseeksContext.name + '"');
    return;
  }
  var done = this._callback.bind(this, meeseeksContext, origin.context);
  this.log.info('Invoking "' + meeseeksContext.name + '"');
  this.log.debug('Context', JSON.stringify(meeseeksContext, null, 2));
  if (typeof listener === 'function') {
    listener(meeseeksContext, done);
  }
  else {
    async.waterfall([
      function validate(next) {
        if (listener.validation) {
          _this.log.debug('Validating');
          listener.validation(meeseeksContext, function(err) {
            if (err) return next(err);
            next(null);
          });
        }
        else {
          next(null);
        }
      },
      function act(next) {
        if (listener.action) {
          _this.log.debug('Action');
          listener.action(meeseeksContext, next);
        }
        else {
          next(null);
        }
      },
      function respond() { // act args are designed to be dynamic
        if (listener.response) {
          _this.log.debug('Transforming response');
          listener.response.apply(listener, arguments);
        }
        else {
          arguments[arguments.length - 1](null); // next
        }
      },
    ], done);
  }
};

Meeseeks.prototype._callback = function(meeseeksContext, context, err, res) {
  if (err) {
    this.log.warn('Completed "' + meeseeksContext.name + '" with error');
    this.log.debug('Result: ', JSON.stringify(err, null, 2));
  }
  else {
    this.log.info('Completed "' + meeseeksContext.name + '"');
    this.log.debug('Result: ', JSON.stringify(res, null, 2));
  }
  context.done(err, res);
};

module.exports = Meeseeks;
<commit_msg>fix fn name<commit_after>'use strict';

var assert = require('assert');
var async = require('async');
var log = require('loglevel');
var auth = require('./lib/auth.js');
var helpers = require('./lib/helpers.js');

function Meeseeks(opts) {
  var _this = this;
  opts = opts || {};
  this.opts = {};
  this.opts.name = opts.name || ('meeseeks:' + Math.random());
  this.opts.jwtSigningToken = opts.jwtSigningToken || '';
  this.opts.skipJwtValidation = opts.skipJwtValidation || (process.env.NODE_ENV === 'development');
  this.opts.logLevel = opts.logLevel || helpers.logLevelFromEnv();
  this.log = log.getLogger(this.opts.name);
  this.log.setLevel(this.opts.logLevel);
  Object.defineProperty(this, 'handler', {
    value: function(event, context) {
      this.debug('Event Received', JSON.stringify(event, null, 2));
      var meeseeksContext = _this.createContextFromEvent(event);
      var origin = { event: event, context: context };
      _this._invoke(meeseeksContext, origin);
    },
  });
  this._listeners = {};
  this.log.info('Handler "' + this.opts.name + '" Ready');
}

Meeseeks.prototype.define = function(name, definition) {
  if (this._listeners[name]) throw new Error('Meeseeks: Listener already exists for "' + name + '"');
  this.log.info('Defined "' + name + '"');
  this._listeners[name] = definition;
};

Meeseeks.prototype.createContextFromEvent = function(event) {
  var authorization = auth.verify(this.opts.jwtSigningToken, event.token, this.opts.skipJwtValidation);
  var meeseeksContext = {
    name: event.method,
    body: event.body || {},
    authorization: authorization,
    identity: authorization.sub,
    received: helpers.now(),
  };
  helpers.deepFreeze(meeseeksContext);
  return meeseeksContext;
};

Meeseeks.prototype._invoke = function(meeseeksContext, origin) {
  var _this = this;
  var listener = this._listeners[meeseeksContext.name];
  if (!listener) {
    origin.context.fail(new Error('invalid target "' + meeseeksContext.name + '"'));
    this.log.warn('No listener exists for "' + meeseeksContext.name + '"');
    return;
  }
  var done = this._callback.bind(this, meeseeksContext, origin.context);
  this.log.info('Invoking "' + meeseeksContext.name + '"');
  this.log.debug('Context', JSON.stringify(meeseeksContext, null, 2));
  if (typeof listener === 'function') {
    listener(meeseeksContext, done);
  }
  else {
    async.waterfall([
      function validate(next) {
        if (listener.validation) {
          _this.log.debug('Validating');
          listener.validation(meeseeksContext, function(err) {
            if (err) return next(err);
            next(null);
          });
        }
        else {
          next(null);
        }
      },
      function act(next) {
        if (listener.action) {
          _this.log.debug('Action');
          listener.action(meeseeksContext, next);
        }
        else {
          next(null);
        }
      },
      function respond() { // act args are designed to be dynamic
        if (listener.response) {
          _this.log.debug('Transforming response');
          listener.response.apply(listener, arguments);
        }
        else {
          arguments[arguments.length - 1](null); // next
        }
      },
    ], done);
  }
};

Meeseeks.prototype._callback = function(meeseeksContext, context, err, res) {
  if (err) {
    this.log.warn('Completed "' + meeseeksContext.name + '" with error');
    this.log.debug('Result: ', JSON.stringify(err, null, 2));
  }
  else {
    this.log.info('Completed "' + meeseeksContext.name + '"');
    this.log.debug('Result: ', JSON.stringify(res, null, 2));
  }
  context.done(err, res);
};

module.exports = Meeseeks;
<|endoftext|>


<commit_before>import reducers from './reducers';
import sagas from './sagas';
import {
  getResource,
  listResource,
  allResource,
  updateResource,
  createResource,
  deleteResource
} from './actions';
import {
  selectItem,
  selectPage,
  selectCurrentPage,
  selectAllPages,
  selectPagination,
  selectAll
} from './selectors';

export {
  reducers,
  sagas,
  getResource,
  listResource,
  allResource,
  updateResource,
  createResource,
  deleteResource,

  selectItem,
  selectPage,
  selectCurrentPage,
  selectAllPages,
  selectPagination,
  selectAll
};

// ----------------------- //
//*
import { createStore, applyMiddleware, combineReducers } from 'redux'
import createSagaMiddleware from 'redux-saga'
const sagaMiddleware = createSagaMiddleware();
const store = createStore(
  combineReducers({...reducers}),
  window.__REDUX_DEVTOOLS_EXTENSION__
  && window.__REDUX_DEVTOOLS_EXTENSION__(),
  applyMiddleware(sagaMiddleware)
);
sagaMiddleware.run(sagas);

// store.dispatch(getResource('place_dossiers', 666666, {})); // 404
store.dispatch(getResource('dossiers', 10, {accommodation_dossiers: {primary_country: null, location: {country: null}}})); // 200
// store.dispatch(getResource('place_dossiers', 666, {place: {country: null}})); // 200

const handleChanges = () => {
  const state = store.getState();
  // const state = {"resources":{"dossiers":{"10":{"id":"10","href":"https://rest-orig.gadventures.com/dossiers/10","date_created":"2016-05-24T19:24:19.672769Z","date_last_modified":"2017-01-16T00:21:09.003375Z","dossier":{"id":"4546","schema":"accommodation_dossiers"},"stub":false,"fetching":false},"undefined":{}},"place_dossiers":{"666":{"id":"666","href":"https://rest-orig.gadventures.com/place_dossiers/666","name":"Hoi An","type":"place_dossiers","date_created":"2014-07-03T09:25:46","date_last_modified":"2017-01-12T16:15:17","publish_state":"unpublished","place":"8649090","images":[{"id":1655,"href":"https://rest-orig.gadventures.com/images/1655"}],"details":[{"id":"3744","body":"Hoi An’s preserved historic Old Town (and World Heritage Site) is a throwback to the days when the city was a major Southeast Asian trading port. Today, it’s also a shopping haven, with tailors whipping up customized clothing overnight and craftsmen designing lanterns on demand. Looking for adventure? Nothing beats travelling the Hai Van Pass, a scenic 21km (13 mi) mountain trail.\r\n","detail_type":{"label":"Summary","code":"COMMON__SUMMARY"}}],"stub":false,"fetching":false},"undefined":{}},"accommodation_dossiers":{"4546":{"id":"4546","href":"https://rest-orig.gadventures.com/accommodation_dossiers/4546","name":"Hotel Madares","type":"accommodation_dossiers","date_created":"2014-09-15T13:35:43","date_last_modified":"2017-01-16T18:41:22","publish_state":"published","address":{"address_line_1":"Loutro Village","address_line_2":"r","address_line_3":"r","postal_code":"73101","country":{"id":"GR","href":"https://rest-orig.gadventures.com/countries/GR","name":"Greece"},"city":{"id":"2516414","href":"https://rest-orig.gadventures.com/places/2516414","name":"Loutro"}},"location":{"id":"8897364","href":"https://rest-orig.gadventures.com/places/8897364","name":"Hotel Madares"},"phone_numbers":[{"id":"3160","phone":"2825091166","phone_type":{"id":"3","label":"work","code":"PHONE__WORK","parent":{"id":"1","label":"Phone","code":"PHONE"}}}],"emails":[{"id":"1621","email":"madareshotel@gmail.com","email_type":{"id":"8","label":"work","code":"EMAIL__WORK","parent":{"id":"2","label":"Email","code":"EMAIL"}}}],"property_type":{"code":"GITE","label":"Gîte"},"primary_country":"GR","website":"http://www.loutro.gr/en/accommodation/22-madares","rooms":[{"id":"4547","features":[{"id":"19","href":"https://rest-orig.gadventures.com/dossier_features/19","label":"Air Conditioning","code":"ROOM__AIR_CONDITIONING"},{"id":"22","href":"https://rest-orig.gadventures.com/dossier_features/22","label":"Heat","code":"ROOM__HEAT"},{"id":"24","href":"https://rest-orig.gadventures.com/dossier_features/24","label":"Private Bath","code":"ROOM__PRIVATE_BATH"}],"room_type":null,"service_level":{"code":"STANDARD","label":"Standard"},"sharing_level":{"code":"TWIN_SHARE","label":"Twin Share"},"quantity":null,"traveller_occupancy":null,"max_occupancy":null}],"dossier_segment":null,"features":[{"id":"10","href":"https://rest-orig.gadventures.com/dossier_features/10","label":"Restaurant","code":"ACCOMMODATION__RESTAURANT"},{"id":"12","href":"https://rest-orig.gadventures.com/dossier_features/12","label":"24-hour Front Desk","code":"ACCOMMODATION__24_HOUR_FRONT_DESK"}],"details":[],"stub":false,"fetching":false},"undefined":{}},"places":{"8649090":{"id":"8649090","href":"https://rest.gadventures.com/places/8649090","name":"Hoi An","ascii_name":"Hoi An","population":32757,"elevation":null,"latitude":"15.87944","longitude":"108.33500","bounding_box":[],"date_created":"2014-05-09T13:11:08Z","date_last_modified":"2014-12-03T21:05:11Z","country":"VN","state":{"id":"VN-27","href":"https://rest.gadventures.com/states/VN-27","name":"Quang Nam"},"admin_divisions":[{"id":"8663919","href":"https://rest.gadventures.com/places/8663919","name":"Tỉnh Quảng Nam","feature":{"id":"1","href":"https://rest.gadventures.com/features/1","name":"first-order administrative division"}}],"feature":"209","timezone":{"id":"238","href":"https://rest.gadventures.com/timezones/238","code":"Asia/Ho_Chi_Minh","gmt_offset":"7.0","dst_offset":"7.0"},"alternate_names":["Faifo","Faifoh","Faifoo","Feifu","Hoi An","Hôi An","Hội An","Khoj","hoian","Хой","ホイアン"],"place_dossier":null,"places_of_interest":[],"stub":false,"fetching":false},"undefined":{}},"countries":{"VN":{"id":"VN","href":"https://rest.gadventures.com/countries/VN","name":"Vietnam","states":{"href":"https://rest.gadventures.com/countries/VN/states"},"stub":false,"fetching":false},"undefined":{},"GR":{"stub":true,"fetching":false}},"features":{"209":{"stub":true,"fetching":false}}},"pagination":{}};
  const item = selectItem(state, 'dossiers', 10);
  // console.log(item)
};

store.subscribe(handleChanges);

// store.dispatch(listResource('place_dossiers', 'test', 1000000, {}, {}, 3)); // 500
// store.dispatch(listResource('place_dossiers', 'test', 1, {}, {}, 3)); // 200

// const p = new Promise((resolve, reject) => {
//
//   // store.dispatch(updateResource('place_dossiers', 666, {name: ''}, resolve, reject)); // 400
//   store.dispatch(updateResource('place_dossiers', 666, {publish_state: 'unpublished'})); // 200
//
//   // store.dispatch(createResource('place_dossiers', {"place": {"id": 8896463}, "publish_state": "unpublished"}, resolve, reject));
//   // store.dispatch(createResource('place_dossiers', {}, resolve, reject));
// });

// store.dispatch(createResource('place_dossiers', getTempId(), {"place": {"id": 8896463}, "publish_state": "unpublished"})); // Validation error
// store.dispatch(createResource('place_dossiers', 666, {publish_state: 'unpublished'})); // 200
//*/
<commit_msg>Include all functionality in the index file<commit_after>import reducers from './reducers';
import sagas from './sagas';
import {
  getResource,
  listResource,
  allResource,
  updateResource,
  createResource,
  deleteResource
} from './actions';
import {
  selectItem,
  selectPage,
  selectCurrentPage,
  selectAllPages,
  selectPagination,
  selectAll
} from './selectors';

export {
  reducers,
  sagas,
  getResource,
  listResource,
  allResource,
  updateResource,
  createResource,
  deleteResource,

  selectItem,
  selectPage,
  selectCurrentPage,
  selectAllPages,
  selectPagination,
  selectAll
};
<|endoftext|>


<commit_before>import {Observable as O} from "rx"
import dom from "./dom"
import {isVNode, VNode} from "./vnode"
import {zipObj, isPlainObj, isStr, isArray, isPrimitive, keys, extend} from "./util"
import {EventListener, EventSource} from "./events"

const htmlAttrs =
  "accept accept-charset accesskey action align alt async autocomplete autofocus " +
  "autoplay autosave bgcolor buffered challenge charset checked cite code " +
  "codebase color cols colspan content contenteditable contextmenu controls coords " +
  "data data- datetime default defer dir dirname disabled download draggable dropzone " +
  "enctype for form formaction headers height hidden high href hreflang http-equiv " +
  "icon id ismap itemprop keytype kind label lang language list loop low manifest " +
  "max maxlength media method min multiple muted name novalidate open optimum pattern " +
  "ping placeholder poster preload radiogroup readonly rel required reversed rows " +
  "rowspan sandbox scope scoped seamless selected shape size sizes span spellcheck " +
  "src srcdoc srclang srcset start step summary tabindex target title type " +
  "usemap width wrap"

const boolAttrs =
  "allowfullscreen async autofocus autoplay checked compact controls declare default " +
  "defaultchecked defaultmuted defaultselected defer disabled draggable enabled " +
  "formnovalidate hidden indeterminate inert ismap itemscope loop multiple muted " +
  "nohref noresize noshade novalidate nowrap open pauseonexit readonly required reversed " +
  "scoped seamless selected sortable spellcheck translate truespeed typemustmatch visible"

const htmlProps =
  "value"

const attrByName =
  zipObj(htmlAttrs.split(" ").map(a => [a.trim(), true]))

const boolAttrByName =
  zipObj(boolAttrs.split(" ").map(a => [a.trim(), true]))

const propsByName =
  zipObj(htmlProps.split(" ").map(a => [a.trim(), true]))

const isHtmlProp = key => propsByName[key]

const isAttr = attr => {
  return attrByName[attr] || (attr.indexOf("data-") === 0 && attr.length > 5)
}

const toClassObj = (klass) => {
  let i, list, c, res = {}
  for (i = 0, list = (klass || "").split(" "); i < list.length; i++) {
    if (c = list[i].trim()) res[c] = true   // eslint-disable-line
  }
  return res
}

function h(tag, props, children) {
  if (arguments.length === 1) {
    props = {}
    children = []
  } else if (arguments.length === 2) {
    if (isPlainObj(props)) {
      children = []
    } else {
      children = props
      props = {}
    }
  }

  if (!isStr(tag)) {
    throw new Error("Tag selector must be a string")
  }

  // parse children
  if (!isArray(children)) {
    children = [children]
  }
  let temp = []
  for (var i = 0; i < children.length; i++) {
    const child = children[i]
    if (isVNode(child)) {
      temp.push(child)
    } else if (isPrimitive(child)) {
      temp.push(VNode(undefined, undefined, undefined, `${child}`))
    } else {
      throw new Error(`Invalid virtual node: ${child}`)
    }
  }
  children = temp

  // parse props
  const key = props.key
  const attrs = {}, htmlProps = {}
  const style = props.style || {}
  const klass = toClassObj(props.class || props.className)
  keys(props).forEach(k => {
    isAttr(k) && (attrs[k] = props[k])
    isHtmlProp(k) && (htmlProps[k] = props[k])
  })

  const data = {
    key, attrs, style, klass, props: htmlProps
  }

  return VNode(tag, data, children)
}

const updateAttrs = (old, cur) => {
  const {elm} = cur
  let key, oldAttrs = old.data.attrs || {}, attrs = cur.data.attrs || {}
  for (key in attrs) {
    var c = attrs[key], o = oldAttrs[key]
    if (o !== c) {
      !c && boolAttrByName[key] ? elm.removeAttribute(key) : elm.setAttribute(key, c)
    }
  }
  for (key in oldAttrs) {
    if (!(key in attrs)) elm.removeAttribute(key)
  }
}

const updateProps = (old, cur) => {
  const {elm} = cur
  let key, oldProps = old.data.props || {}, props = cur.data.props || {}
  for (key in props) {
    var c = props[key], o = oldProps[key]
    o !== c && (elm[key] = c)
  }
  for (key in oldProps) {
    if (!(key in props)) delete elm[key]
  }
}

const updateKlass = (old, cur) => {
  const {elm} = cur
  let kl, oldKlass = old.data.klass || {}, klass = cur.data.klass || {}
  for (kl in oldKlass) {
    if (!(kl in klass)) elm.classList.remove(kl)
  }
  for (kl in klass) {
    if (!(kl in oldKlass)) elm.classList.add(kl)
  }
}

const updateStyle = (old, cur) => {
  const {elm} = cur
  let s, oldStyle = old.data.style || {}, style = cur.data.style || {}
  for (s in style) {
    var c = style[s], o = style[s]
    if (c !== o) elm.style[s] = c
  }
  for (s in oldStyle) {
    if (!(s in style)) elm.style[s] = ""
  }
}

const attachEvents = vnode => {
  if (vnode.data && vnode.data.eventSource) {
    vnode.data.eventSource.attach(vnode.elm)
  }
}

const reattachEvents = (old, cur) => {
  const curSrc = (cur.data || {}).eventSource
  const oldSrc = (old.data || {}).eventSource
  if (curSrc !== oldSrc) {
    oldSrc && oldSrc.detach(cur.elm)
    curSrc && curSrc.reattach(cur.elm)
  }
}
const detachEvents = vnode => {
  if (vnode.data && vnode.data.eventSource) {
    vnode.data.eventSource.detach(vnode.elm)
  }
}

export default function makeSnabbdom(rootElem) {
  return function snabbdom() {
    const patch = dom.init([
      {
        create(old, cur) {
          updateAttrs(old, cur)
          updateProps(old, cur)
          updateKlass(old, cur)
          updateStyle(old, cur)
          attachEvents(cur)
        },
        update(old, cur) {
          updateAttrs(old, cur)
          updateProps(old, cur)
          updateKlass(old, cur)
          updateStyle(old, cur)
        },
        postpatch(old, cur) {
          reattachEvents(old, cur)
        },
        destroy(vnode) {
          detachEvents(vnode)
        }
      }
    ])

    function cloneTree(vnode) {
      const cloned = extend({}, vnode)
      cloned.children = vnode.children && vnode.children.map(cloneTree)
      return cloned
    }

    function prepare(vdom$) {
      const newSource = () => new EventSource()
      const withSource = src => vdom$
        .merge(O.never())
        .map(vnode => (vnode.data.eventSource = vnode.data.eventSource || src) && vnode)
      return O.using(newSource, withSource).shareReplay(1)
    }

    function events(vdom$, selector, eventName) {
      const newListener = () => new EventListener(selector, eventName, false)
      const listen = listener => vdom$
        .distinctUntilChanged(vnode => vnode.data.eventSource)
        .map(vnode => {
          if (!vnode.data.eventSource) {
            console.warn(                                 // eslint-disable-line
              "DOM.events :: VDOM is not prepared for event listening.",
              "Perhaps you forgot to call DOM.prepare(vdom$)?"
            )
            return O.never()
          }
          return vnode.data.eventSource.listen(listener)
        })
      return O.using(newListener, listen).switch().share()
    }

    const Transforms = {
      h,
      events,
      prepare
    }

    function executor(vdom$) {
      const elm = isStr(rootElem) ? document.querySelector(rootElem) : rootElem
      let prev = elm
      const dispose = vdom$.subscribe(vnode => {
        vnode = cloneTree(vnode)
        patch(prev, vnode)
        prev = vnode
      })
      return {
        dispose: () => {
          dispose();
          prev = null
        }
      }
    }

    return [Transforms, executor]
  }
}
<commit_msg>Accept null values as vnodes <commit_after>import {Observable as O} from "rx"
import dom from "./dom"
import {isVNode, VNode} from "./vnode"
import {zipObj, isPlainObj, isStr, isArray, isPrimitive, keys, extend} from "./util"
import {EventListener, EventSource} from "./events"

const htmlAttrs =
  "accept accept-charset accesskey action align alt async autocomplete autofocus " +
  "autoplay autosave bgcolor buffered challenge charset checked cite code " +
  "codebase color cols colspan content contenteditable contextmenu controls coords " +
  "data data- datetime default defer dir dirname disabled download draggable dropzone " +
  "enctype for form formaction headers height hidden high href hreflang http-equiv " +
  "icon id ismap itemprop keytype kind label lang language list loop low manifest " +
  "max maxlength media method min multiple muted name novalidate open optimum pattern " +
  "ping placeholder poster preload radiogroup readonly rel required reversed rows " +
  "rowspan sandbox scope scoped seamless selected shape size sizes span spellcheck " +
  "src srcdoc srclang srcset start step summary tabindex target title type " +
  "usemap width wrap"

const boolAttrs =
  "allowfullscreen async autofocus autoplay checked compact controls declare default " +
  "defaultchecked defaultmuted defaultselected defer disabled draggable enabled " +
  "formnovalidate hidden indeterminate inert ismap itemscope loop multiple muted " +
  "nohref noresize noshade novalidate nowrap open pauseonexit readonly required reversed " +
  "scoped seamless selected sortable spellcheck translate truespeed typemustmatch visible"

const htmlProps =
  "value"

const attrByName =
  zipObj(htmlAttrs.split(" ").map(a => [a.trim(), true]))

const boolAttrByName =
  zipObj(boolAttrs.split(" ").map(a => [a.trim(), true]))

const propsByName =
  zipObj(htmlProps.split(" ").map(a => [a.trim(), true]))

const isHtmlProp = key => propsByName[key]

const isAttr = attr => {
  return attrByName[attr] || (attr.indexOf("data-") === 0 && attr.length > 5)
}

const toClassObj = (klass) => {
  let i, list, c, res = {}
  for (i = 0, list = (klass || "").split(" "); i < list.length; i++) {
    if (c = list[i].trim()) res[c] = true   // eslint-disable-line
  }
  return res
}

function h(tag, props, children) {
  if (arguments.length === 1) {
    props = {}
    children = []
  } else if (arguments.length === 2) {
    if (isPlainObj(props)) {
      children = []
    } else {
      children = props
      props = {}
    }
  }

  if (!isStr(tag)) {
    throw new Error("Tag selector must be a string")
  }

  // parse children
  if (!isArray(children)) {
    children = [children]
  }
  let temp = []
  for (var i = 0; i < children.length; i++) {
    const child = children[i]
    if (child === undefined || child === null || child === false) continue
    if (isVNode(child)) {
      temp.push(child)
    } else if (isPrimitive(child)) {
      temp.push(VNode(undefined, undefined, undefined, `${child}`))
    } else {
      throw new Error(`Invalid virtual node: ${child}`)
    }
  }
  children = temp

  // parse props
  const key = props.key
  const attrs = {}, htmlProps = {}
  const style = props.style || {}
  const klass = toClassObj(props.class || props.className)
  keys(props).forEach(k => {
    isAttr(k) && (attrs[k] = props[k])
    isHtmlProp(k) && (htmlProps[k] = props[k])
  })

  const data = {
    key, attrs, style, klass, props: htmlProps
  }

  return VNode(tag, data, children)
}

const updateAttrs = (old, cur) => {
  const {elm} = cur
  let key, oldAttrs = old.data.attrs || {}, attrs = cur.data.attrs || {}
  for (key in attrs) {
    var c = attrs[key], o = oldAttrs[key]
    if (o !== c) {
      !c && boolAttrByName[key] ? elm.removeAttribute(key) : elm.setAttribute(key, c)
    }
  }
  for (key in oldAttrs) {
    if (!(key in attrs)) elm.removeAttribute(key)
  }
}

const updateProps = (old, cur) => {
  const {elm} = cur
  let key, oldProps = old.data.props || {}, props = cur.data.props || {}
  for (key in props) {
    var c = props[key], o = oldProps[key]
    o !== c && (elm[key] = c)
  }
  for (key in oldProps) {
    if (!(key in props)) delete elm[key]
  }
}

const updateKlass = (old, cur) => {
  const {elm} = cur
  let kl, oldKlass = old.data.klass || {}, klass = cur.data.klass || {}
  for (kl in oldKlass) {
    if (!(kl in klass)) elm.classList.remove(kl)
  }
  for (kl in klass) {
    if (!(kl in oldKlass)) elm.classList.add(kl)
  }
}

const updateStyle = (old, cur) => {
  const {elm} = cur
  let s, oldStyle = old.data.style || {}, style = cur.data.style || {}
  for (s in style) {
    var c = style[s], o = style[s]
    if (c !== o) elm.style[s] = c
  }
  for (s in oldStyle) {
    if (!(s in style)) elm.style[s] = ""
  }
}

const attachEvents = vnode => {
  if (vnode.data && vnode.data.eventSource) {
    vnode.data.eventSource.attach(vnode.elm)
  }
}

const reattachEvents = (old, cur) => {
  const curSrc = (cur.data || {}).eventSource
  const oldSrc = (old.data || {}).eventSource
  if (curSrc !== oldSrc) {
    oldSrc && oldSrc.detach(cur.elm)
    curSrc && curSrc.reattach(cur.elm)
  }
}
const detachEvents = vnode => {
  if (vnode.data && vnode.data.eventSource) {
    vnode.data.eventSource.detach(vnode.elm)
  }
}

export default function makeSnabbdom(rootElem) {
  return function snabbdom() {
    const patch = dom.init([
      {
        create(old, cur) {
          updateAttrs(old, cur)
          updateProps(old, cur)
          updateKlass(old, cur)
          updateStyle(old, cur)
          attachEvents(cur)
        },
        update(old, cur) {
          updateAttrs(old, cur)
          updateProps(old, cur)
          updateKlass(old, cur)
          updateStyle(old, cur)
        },
        postpatch(old, cur) {
          reattachEvents(old, cur)
        },
        destroy(vnode) {
          detachEvents(vnode)
        }
      }
    ])

    function cloneTree(vnode) {
      const cloned = extend({}, vnode)
      cloned.children = vnode.children && vnode.children.map(cloneTree)
      return cloned
    }

    function prepare(vdom$) {
      const newSource = () => new EventSource()
      const withSource = src => vdom$
        .merge(O.never())
        .map(vnode => (vnode.data.eventSource = vnode.data.eventSource || src) && vnode)
      return O.using(newSource, withSource).shareReplay(1)
    }

    function events(vdom$, selector, eventName) {
      const newListener = () => new EventListener(selector, eventName, false)
      const listen = listener => vdom$
        .distinctUntilChanged(vnode => vnode.data.eventSource)
        .map(vnode => {
          if (!vnode.data.eventSource) {
            console.warn(                                 // eslint-disable-line
              "DOM.events :: VDOM is not prepared for event listening.",
              "Perhaps you forgot to call DOM.prepare(vdom$)?"
            )
            return O.never()
          }
          return vnode.data.eventSource.listen(listener)
        })
      return O.using(newListener, listen).switch().share()
    }

    const Transforms = {
      h,
      events,
      prepare
    }

    function executor(vdom$) {
      const elm = isStr(rootElem) ? document.querySelector(rootElem) : rootElem
      let prev = elm
      const dispose = vdom$.subscribe(vnode => {
        vnode = cloneTree(vnode)
        patch(prev, vnode)
        prev = vnode
      })
      return {
        dispose: () => {
          dispose();
          prev = null
        }
      }
    }

    return [Transforms, executor]
  }
}
<|endoftext|>


<commit_before>import './babel-maybefill';

import _ from 'lodash';
import spawn from './spawn-promise';
import asar from 'asar';
import path from 'path';
import temp from 'temp';
import jetpack from 'fs-jetpack';
import fs from 'fs';

const d = require('debug')('electron-windows-installer:main');

temp.track();
async function statNoException(file) {
  try {
    d(file);
    return await jetpack.inspectAsync(file);
  } catch (e) {
    d(e.message);
    return null;
  }
}

async function locateExecutableInPath(exe) {
  // NB: Windows won't search PATH looking for executables in spawn like
  // Posix does

  // Files with any directory path don't get this applied
  if (exe.match(/[\\\/]/)) {
    d('Path has slash in directory, bailing');
    return exe;
  }

  let target = path.join('.', exe);
  if (await statNoException(target)) {
    d(`Found executable in currect directory: ${target}`);
    return target;
  }

  let haystack = process.env.PATH.split(path.delimiter);
  for (let p of haystack) {
    let needle = path.join(p, exe);
    if (await statNoException(needle)) return needle;
  }

  d('Failed to find executable anywhere in path');
  return null;
}

export function convertVersion(version) {
  let parts = version.split('-');
  let mainVersion = parts.shift();
  if (parts.length > 0) {
    return [mainVersion, parts.join('-').replace(/\./g, '')].join('-');
  } else {
    return mainVersion;
  }
}

export async function createWindowsInstaller(options) {
  let useMono = false;
  let monoExe = await locateExecutableInPath('mono');
  let wineExe = await locateExecutableInPath('wine');

  if (process.platform !== 'win32') {
    useMono = true;
    if (!wineExe || !monoExe) {
      throw new Error('You must install both Mono and Wine on non-Windows');
    }

    d(`Using Mono: '${monoExe}'`);
    d(`Using Wine: '${wineExe}'`);
  }
  let { appDirectory, outputDirectory, loadingGif } = options;
  outputDirectory = path.resolve(outputDirectory || 'installer');

  const vendorPath = path.join(__dirname, '..', 'vendor');
  await jetpack.copyAsync(
    path.join(vendorPath, 'Update.exe'),
    path.join(appDirectory, 'Update.exe'),
    { overwrite: true });

  let defaultLoadingGif = path.join(__dirname, '..', 'resources', 'install-spinner.gif');
  loadingGif = loadingGif ? path.resolve(loadingGif) : defaultLoadingGif;

  let {certificateFile, certificatePassword, remoteReleases, signWithParams, githubToken} = options;

  let appMetadata = null;
  const appResources = path.join(appDirectory, 'resources');
  let asarFile = path.join(appResources, 'app.asar');
  if (await jetpack.existsAsync(asarFile)) {
    appMetadata = JSON.parse(asar.extractFile(asarFile, 'package.json'));
  } else {
    appMetadata = JSON.parse(await jetpack.readAsync(path.join(appResources, 'app', 'package.json'), 'utf8'));
  }

  let defaults = {
    description: appMetadata.description || '',
    exe: `${appMetadata.name}.exe`,
    iconUrl: 'https://raw.githubusercontent.com/atom/electron/master/atom/browser/resources/win/atom.ico',
    title: appMetadata.productName || appMetadata.name
  };

  let metadata = _.defaults({}, options, defaults, appMetadata);

  if (!metadata.authors) {
    if (typeof(metadata.author) === 'string') {
      metadata.authors = metadata.author;
    } else {
      metadata.authors = (metadata.author || {}).name || '';
    }
  }

  metadata.owners = metadata.owners || metadata.authors;
  metadata.version = convertVersion(metadata.version);
  metadata.copyright = metadata.copyright ||
    `Copyright © ${new Date().getFullYear()} ${metadata.authors || metadata.owners}`;

  let templateStamper = _.template(await jetpack.readAsync(path.join(__dirname, '..', 'template.nuspec')));
  let nuspecContent = templateStamper(metadata);

  d(`Created NuSpec file:\n${nuspecContent}`);

  let nugetOutput = temp.mkdirSync('si');
  let targetNuspecPath = path.join(nugetOutput, metadata.name + '.nuspec');
  await jetpack.writeAsync(targetNuspecPath, nuspecContent);

  let cmd = path.join(vendorPath, 'nuget.exe');
  let args = [
    'pack', targetNuspecPath,
    '-BasePath', appDirectory,
    '-OutputDirectory', nugetOutput,
    '-NoDefaultExcludes'
  ];

  if (useMono) {
    args.unshift(cmd);
    cmd = monoExe;
  }

  // Call NuGet to create our package
  d(await spawn(cmd, args));
  let nupkgPath = path.join(nugetOutput, `${metadata.name}.${metadata.version}.nupkg`);

  if (remoteReleases) {
    cmd = path.join(vendorPath, 'SyncReleases.exe');
    args = ['-u', remoteReleases, '-r', outputDirectory];

    if (useMono) {
      args.unshift(cmd);
      cmd = monoExe;
    }

    if (githubToken) {
      args.push('-t', githubToken);
    }

    d(await spawn(cmd, args));
  }

  cmd = path.join(vendorPath, 'Update.com');
  args = [
    '--releasify', nupkgPath,
    '--releaseDir', outputDirectory,
    '--loadingGif', loadingGif
  ];

  if (useMono) {
    args.unshift(path.join(vendorPath, 'Update-Mono.exe'));
    cmd = monoExe;
  }

  if (signWithParams) {
    args.push('--signWithParams');
    args.push(signWithParams);
  } else if (certificateFile && certificatePassword) {
    args.push('--signWithParams');
    args.push(`/a /f "${path.resolve(certificateFile)}" /p "${certificatePassword}"`);
  }

  if (options.setupIcon) {
    let setupIconPath = path.resolve(options.setupIcon);
    args.push('--setupIcon');
    args.push(setupIconPath);
  }

  if (options.noMsi) {
    args.push('--no-msi');
  }

  d(await spawn(cmd, args));

  if (metadata.productName) {
    d('Fixing up paths');
    const setupPath = path.join(outputDirectory, `${metadata.productName}Setup.exe`);
    const setupMsiPath = path.join(outputDirectory, `${metadata.productName}Setup.msi`);

    // NB: When you give jetpack two absolute paths, it acts as if './' is appended
    // to the target and mkdirps the entire path
    const unfixedSetupPath = path.join(outputDirectory, 'Setup.exe');
    d(`Renaming ${unfixedSetupPath} => ${setupPath}`);
    fs.renameSync(unfixedSetupPath, setupPath);

    const msiPath = path.join(outputDirectory, 'Setup.msi');
    if (jetpack.exists(msiPath)) {
      fs.renameSync(msiPath, setupMsiPath);
    }
  }
}
<commit_msg>githubToken -> remoteToken<commit_after>import './babel-maybefill';

import _ from 'lodash';
import spawn from './spawn-promise';
import asar from 'asar';
import path from 'path';
import temp from 'temp';
import jetpack from 'fs-jetpack';
import fs from 'fs';

const d = require('debug')('electron-windows-installer:main');

temp.track();
async function statNoException(file) {
  try {
    d(file);
    return await jetpack.inspectAsync(file);
  } catch (e) {
    d(e.message);
    return null;
  }
}

async function locateExecutableInPath(exe) {
  // NB: Windows won't search PATH looking for executables in spawn like
  // Posix does

  // Files with any directory path don't get this applied
  if (exe.match(/[\\\/]/)) {
    d('Path has slash in directory, bailing');
    return exe;
  }

  let target = path.join('.', exe);
  if (await statNoException(target)) {
    d(`Found executable in currect directory: ${target}`);
    return target;
  }

  let haystack = process.env.PATH.split(path.delimiter);
  for (let p of haystack) {
    let needle = path.join(p, exe);
    if (await statNoException(needle)) return needle;
  }

  d('Failed to find executable anywhere in path');
  return null;
}

export function convertVersion(version) {
  let parts = version.split('-');
  let mainVersion = parts.shift();
  if (parts.length > 0) {
    return [mainVersion, parts.join('-').replace(/\./g, '')].join('-');
  } else {
    return mainVersion;
  }
}

export async function createWindowsInstaller(options) {
  let useMono = false;
  let monoExe = await locateExecutableInPath('mono');
  let wineExe = await locateExecutableInPath('wine');

  if (process.platform !== 'win32') {
    useMono = true;
    if (!wineExe || !monoExe) {
      throw new Error('You must install both Mono and Wine on non-Windows');
    }

    d(`Using Mono: '${monoExe}'`);
    d(`Using Wine: '${wineExe}'`);
  }
  let { appDirectory, outputDirectory, loadingGif } = options;
  outputDirectory = path.resolve(outputDirectory || 'installer');

  const vendorPath = path.join(__dirname, '..', 'vendor');
  await jetpack.copyAsync(
    path.join(vendorPath, 'Update.exe'),
    path.join(appDirectory, 'Update.exe'),
    { overwrite: true });

  let defaultLoadingGif = path.join(__dirname, '..', 'resources', 'install-spinner.gif');
  loadingGif = loadingGif ? path.resolve(loadingGif) : defaultLoadingGif;

  let {certificateFile, certificatePassword, remoteReleases, signWithParams, remoteToken} = options;

  let appMetadata = null;
  const appResources = path.join(appDirectory, 'resources');
  let asarFile = path.join(appResources, 'app.asar');
  if (await jetpack.existsAsync(asarFile)) {
    appMetadata = JSON.parse(asar.extractFile(asarFile, 'package.json'));
  } else {
    appMetadata = JSON.parse(await jetpack.readAsync(path.join(appResources, 'app', 'package.json'), 'utf8'));
  }

  let defaults = {
    description: appMetadata.description || '',
    exe: `${appMetadata.name}.exe`,
    iconUrl: 'https://raw.githubusercontent.com/atom/electron/master/atom/browser/resources/win/atom.ico',
    title: appMetadata.productName || appMetadata.name
  };

  let metadata = _.defaults({}, options, defaults, appMetadata);

  if (!metadata.authors) {
    if (typeof(metadata.author) === 'string') {
      metadata.authors = metadata.author;
    } else {
      metadata.authors = (metadata.author || {}).name || '';
    }
  }

  metadata.owners = metadata.owners || metadata.authors;
  metadata.version = convertVersion(metadata.version);
  metadata.copyright = metadata.copyright ||
    `Copyright © ${new Date().getFullYear()} ${metadata.authors || metadata.owners}`;

  let templateStamper = _.template(await jetpack.readAsync(path.join(__dirname, '..', 'template.nuspec')));
  let nuspecContent = templateStamper(metadata);

  d(`Created NuSpec file:\n${nuspecContent}`);

  let nugetOutput = temp.mkdirSync('si');
  let targetNuspecPath = path.join(nugetOutput, metadata.name + '.nuspec');
  await jetpack.writeAsync(targetNuspecPath, nuspecContent);

  let cmd = path.join(vendorPath, 'nuget.exe');
  let args = [
    'pack', targetNuspecPath,
    '-BasePath', appDirectory,
    '-OutputDirectory', nugetOutput,
    '-NoDefaultExcludes'
  ];

  if (useMono) {
    args.unshift(cmd);
    cmd = monoExe;
  }

  // Call NuGet to create our package
  d(await spawn(cmd, args));
  let nupkgPath = path.join(nugetOutput, `${metadata.name}.${metadata.version}.nupkg`);

  if (remoteReleases) {
    cmd = path.join(vendorPath, 'SyncReleases.exe');
    args = ['-u', remoteReleases, '-r', outputDirectory];

    if (useMono) {
      args.unshift(cmd);
      cmd = monoExe;
    }

    if (remoteToken) {
      args.push('-t', remoteToken);
    }

    d(await spawn(cmd, args));
  }

  cmd = path.join(vendorPath, 'Update.com');
  args = [
    '--releasify', nupkgPath,
    '--releaseDir', outputDirectory,
    '--loadingGif', loadingGif
  ];

  if (useMono) {
    args.unshift(path.join(vendorPath, 'Update-Mono.exe'));
    cmd = monoExe;
  }

  if (signWithParams) {
    args.push('--signWithParams');
    args.push(signWithParams);
  } else if (certificateFile && certificatePassword) {
    args.push('--signWithParams');
    args.push(`/a /f "${path.resolve(certificateFile)}" /p "${certificatePassword}"`);
  }

  if (options.setupIcon) {
    let setupIconPath = path.resolve(options.setupIcon);
    args.push('--setupIcon');
    args.push(setupIconPath);
  }

  if (options.noMsi) {
    args.push('--no-msi');
  }

  d(await spawn(cmd, args));

  if (metadata.productName) {
    d('Fixing up paths');
    const setupPath = path.join(outputDirectory, `${metadata.productName}Setup.exe`);
    const setupMsiPath = path.join(outputDirectory, `${metadata.productName}Setup.msi`);

    // NB: When you give jetpack two absolute paths, it acts as if './' is appended
    // to the target and mkdirps the entire path
    const unfixedSetupPath = path.join(outputDirectory, 'Setup.exe');
    d(`Renaming ${unfixedSetupPath} => ${setupPath}`);
    fs.renameSync(unfixedSetupPath, setupPath);

    const msiPath = path.join(outputDirectory, 'Setup.msi');
    if (jetpack.exists(msiPath)) {
      fs.renameSync(msiPath, setupMsiPath);
    }
  }
}
<|endoftext|>


<commit_before>// IE10+ Support
// inspired by zepto event https://github.com/madrobby/zepto/blob/master/src/event.js

const handlers = {};

const specialEvents = {};
specialEvents.click = specialEvents.mousedown = specialEvents.mouseup = specialEvents.mousemove = 'MouseEvents';

// every element and callback function will have an unique dtId
let _dtId = 1;

/**
 * Get dtId of Element or callback function
 * @param  {Object|Function} obj Element or callback function
 * @return {Number} unique dtId
 */
function getDtId(obj) {
  return obj._dtId || (obj._dtId = _dtId++);
}

/**
 * Get event object of event string, the first `.` is used to split event and namespace
 *
 * @param  {String} event Event type string with namespace or not
 * @return {Object} An Object with `e` and `ns` key
 */
function parse(event) {
  const dotIndex = event.indexOf('.');
  if (dotIndex > 0) {
    return {
      e: event.substring(0, event.indexOf('.')),
      ns: event.substring(dotIndex + 1, event.length)
    };
  }

  return { e: event };
}

/**
 * Find matched event handlers
 * @param  {Element} el the element to find
 * @param  {String} selector Used by event delegation, null if not
 * @param  {String} event Event string may with namespace
 * @param  {Function} callback the callback to find, optional
 * @return {Array} Array of handlers bind to el
 */
function findHandlers(el, selector, event, callback) {
  event = parse(event);
  return (handlers[getDtId(el)] || []).filter(handler => {
    return handler
      && (!event.e || handler.e === event.e)
      && (!event.ns || handler.ns === event.ns)
      && (!callback || handler.callback === callback)
      && (!selector || handler.selector === selector);
  });
}

function removeEvent(el, selector, event, callback) {
  const eventName = parse(event).e;

  const matchedHandlers = findHandlers(el, selector, event, callback);
  matchedHandlers.forEach(handler => {
    if (el.removeEventListener) {
      el.removeEventListener(eventName, handler.delegator || handler.callback);
    } else if (el.detachEvent) {
      el.detachEvent('on' + eventName, handler.delegator || handler.callback);
    }
    handler = null;
  });
}

// delegator 只用于 delegate 时有用。
function bindEvent(el, selector, event, callback, delegator) {
  const eventName = parse(event).e;
  const ns = parse(event).ns;

  if (el.addEventListener) {
    el.addEventListener(eventName, delegator || callback, false);
  } else if (el.attachEvent) {
    el.attachEvent('on' + eventName, delegator || callback);
  }

  // push events to handlers
  const id = getDtId(el);
  const elHandlers = (handlers[id] || (handlers[id] = []));
  elHandlers.push({
    delegator: delegator,
    callback: callback,
    e: eventName,
    ns: ns,
    selector: selector
  });
}

const Events = {
  /**
   * Register a callback
   *
   * @param  {Element} el the element to bind event to
   * @param  {String} eventType event type, can with namesapce
   * @param  {Function} callback callback to invoke
   * @return {Null} return null
   */
  on(el, eventType, callback) {
    bindEvent(el, null, eventType, callback);
  },

  /**
   * Unregister a callback
   *
   * @param  {Element} el the element to bind event to
   * @param  {String} eventType event type, can with namesapce
   * @param  {Function} callback optional, callback to invoke
   * @return {Null} return null
   */
  off(el, eventType, callback) {
    // find callbacks
    removeEvent(el, null, eventType, callback);
  },

  /**
   * Register a callback that will execute exactly once
   *
   * @param  {Element} el the element to bind event to
   * @param  {String} eventType event type, can with namesapce
   * @param  {Function} callback callback to invoke
   * @return {Null} return null
   */
  once(el, eventType, callback) {
    const recursiveFunction = e => {
      Events.off(e.currentTarget, e.type, recursiveFunction);
      return callback(e);
    };

    this.on(el, eventType, recursiveFunction);
  },

  // Delegate a callback to selector under el
  delegate(el, selector, eventType, callback) {
    // bind event to el. and check if selector match
    const delegator = e => {
      const els = el.querySelectorAll(selector);
      let matched = false;
      for (let i = 0; i < els.length; i++) {
        const _el = els[i];
        if (_el === e.target || _el.contains(e.target)) {
          matched = _el;
          break;
        }
      }
      if (matched) {
        callback.apply(matched, [].slice.call(arguments));
      }
    };

    bindEvent(el, selector, eventType, callback, delegator);
  },

  // Undelegate a callback to selector under el
  undelegate(el, selector, eventType, callback) {
    removeEvent(el, selector, eventType, callback);
  },

  // Dispatch an event with props to el
  trigger(el, eventType, props) {
    const event = document.createEvent(specialEvents[eventType] || 'Events');
    let bubbles = true;
    if (props) {
      for (const name in props) {
        if ({}.hasOwnProperty.call(props, name)) {
          (name === 'bubbles') ? (bubbles = !!props[name]) : (event[name] = props[name]);
        }
      }
    }
    event.initEvent(eventType, bubbles, true);
    el.dispatchEvent(event);
  }
};

export default Events;
<commit_msg>fix delegate arugments<commit_after>// IE10+ Support
// inspired by zepto event https://github.com/madrobby/zepto/blob/master/src/event.js

const handlers = {};

const specialEvents = {};
specialEvents.click = specialEvents.mousedown = specialEvents.mouseup = specialEvents.mousemove = 'MouseEvents';

// every element and callback function will have an unique dtId
let _dtId = 1;

/**
 * Get dtId of Element or callback function
 * @param  {Object|Function} obj Element or callback function
 * @return {Number} unique dtId
 */
function getDtId(obj) {
  return obj._dtId || (obj._dtId = _dtId++);
}

/**
 * Get event object of event string, the first `.` is used to split event and namespace
 *
 * @param  {String} event Event type string with namespace or not
 * @return {Object} An Object with `e` and `ns` key
 */
function parse(event) {
  const dotIndex = event.indexOf('.');
  if (dotIndex > 0) {
    return {
      e: event.substring(0, event.indexOf('.')),
      ns: event.substring(dotIndex + 1, event.length)
    };
  }

  return { e: event };
}

/**
 * Find matched event handlers
 * @param  {Element} el the element to find
 * @param  {String} selector Used by event delegation, null if not
 * @param  {String} event Event string may with namespace
 * @param  {Function} callback the callback to find, optional
 * @return {Array} Array of handlers bind to el
 */
function findHandlers(el, selector, event, callback) {
  event = parse(event);
  return (handlers[getDtId(el)] || []).filter(handler => {
    return handler
      && (!event.e || handler.e === event.e)
      && (!event.ns || handler.ns === event.ns)
      && (!callback || handler.callback === callback)
      && (!selector || handler.selector === selector);
  });
}

function removeEvent(el, selector, event, callback) {
  const eventName = parse(event).e;

  const matchedHandlers = findHandlers(el, selector, event, callback);
  matchedHandlers.forEach(handler => {
    if (el.removeEventListener) {
      el.removeEventListener(eventName, handler.delegator || handler.callback);
    } else if (el.detachEvent) {
      el.detachEvent('on' + eventName, handler.delegator || handler.callback);
    }
    handler = null;
  });
}

// delegator 只用于 delegate 时有用。
function bindEvent(el, selector, event, callback, delegator) {
  const eventName = parse(event).e;
  const ns = parse(event).ns;

  if (el.addEventListener) {
    el.addEventListener(eventName, delegator || callback, false);
  } else if (el.attachEvent) {
    el.attachEvent('on' + eventName, delegator || callback);
  }

  // push events to handlers
  const id = getDtId(el);
  const elHandlers = (handlers[id] || (handlers[id] = []));
  elHandlers.push({
    delegator: delegator,
    callback: callback,
    e: eventName,
    ns: ns,
    selector: selector
  });
}

const Events = {
  /**
   * Register a callback
   *
   * @param  {Element} el the element to bind event to
   * @param  {String} eventType event type, can with namesapce
   * @param  {Function} callback callback to invoke
   * @return {Null} return null
   */
  on(el, eventType, callback) {
    bindEvent(el, null, eventType, callback);
  },

  /**
   * Unregister a callback
   *
   * @param  {Element} el the element to bind event to
   * @param  {String} eventType event type, can with namesapce
   * @param  {Function} callback optional, callback to invoke
   * @return {Null} return null
   */
  off(el, eventType, callback) {
    // find callbacks
    removeEvent(el, null, eventType, callback);
  },

  /**
   * Register a callback that will execute exactly once
   *
   * @param  {Element} el the element to bind event to
   * @param  {String} eventType event type, can with namesapce
   * @param  {Function} callback callback to invoke
   * @return {Null} return null
   */
  once(el, eventType, callback) {
    const recursiveFunction = e => {
      Events.off(e.currentTarget, e.type, recursiveFunction);
      return callback(e);
    };

    this.on(el, eventType, recursiveFunction);
  },

  // Delegate a callback to selector under el
  delegate(el, selector, eventType, callback) {
    // bind event to el. and check if selector match
    const delegator = function(e) {
      const els = el.querySelectorAll(selector);
      let matched = false;
      for (let i = 0; i < els.length; i++) {
        const _el = els[i];
        if (_el === e.target || _el.contains(e.target)) {
          matched = _el;
          break;
        }
      }
      if (matched) {
        callback.apply(matched, [].slice.call(arguments));
      }
    };

    bindEvent(el, selector, eventType, callback, delegator);
  },

  // Undelegate a callback to selector under el
  undelegate(el, selector, eventType, callback) {
    removeEvent(el, selector, eventType, callback);
  },

  // Dispatch an event with props to el
  trigger(el, eventType, props) {
    const event = document.createEvent(specialEvents[eventType] || 'Events');
    let bubbles = true;
    if (props) {
      for (const name in props) {
        if ({}.hasOwnProperty.call(props, name)) {
          (name === 'bubbles') ? (bubbles = !!props[name]) : (event[name] = props[name]);
        }
      }
    }
    event.initEvent(eventType, bubbles, true);
    el.dispatchEvent(event);
  }
};

export default Events;
<|endoftext|>