<commit_before>'use strict';
var path = require('path');
var os = require('os');
var dargs = require('dargs');
var async = require('async');
var chalk = require('chalk');
var spawn = require('cross-spawn');
var which = require('which');
var checkFilesSyntax = require('./lib/check');
var concurrencyCount = (os.cpus().length || 1) * 4;

module.exports = function (grunt) {
  var checkBinary = function (cmd, errMsg) {
    try {
      which.sync(cmd);
    } catch (err) {
      return grunt.warn(
        '\n' + errMsg + '\n' +
        'More info: https://github.com/gruntjs/grunt-contrib-sass\n'
      );
    }
  };

  grunt.registerMultiTask('sass', 'Compile Sass to CSS', function () {
    var cb = this.async();
    var options = this.options();

    if (options.bundleExec) {
      checkBinary('bundle',
        'bundleExec options set but no Bundler executable found in your PATH.'
      );
    } else {
      checkBinary('sass',
        'You need to have Ruby and Sass installed and in your PATH for this task to work.'
      );
    }

    if (options.check) {
      options.concurrencyCount = concurrencyCount;
      checkFilesSyntax(this.filesSrc, options, cb);
      return;
    }

    var passedArgs = dargs(options, {
      excludes: ['bundleExec'],
      ignoreFalse: true
    });

    async.eachLimit(this.files, concurrencyCount, function (file, next) {
      var src = file.src[0];

      if (path.basename(src)[0] === '_') {
        return next();
      }

      var args = [
        src,
        file.dest
      ].concat(passedArgs);

      if (options.update) {
        // When the source file hasn't yet been compiled SASS will write an empty file.
        // If this is the first time the file has been written we treat it as if `update` was not passed
        if (!grunt.file.exists(file.dest)) {
          // Find where the --update flag is and remove it
          args.splice(args.indexOf('--update'), 1);
        } else {
          // The first two elements in args are the source and destination files,
          // which are used to build a path that SASS recognizes, i.e. "source:destination"
          args.push(args.shift() + ':' + args.shift());
        }
      }

      var bin = 'sass';

      if (options.bundleExec) {
        bin = 'bundle';
        args.unshift('exec', 'sass');
      }

      // If we're compiling scss or css files
      if (path.extname(src) === '.css') {
        args.push('--scss');
      }

      // Make sure grunt creates the destination folders if they don't exist
      if (!grunt.file.exists(file.dest)) {
        grunt.file.write(file.dest, '');
      }

      grunt.verbose.writeln('Command: ' + bin + ' ' + args.join(' '));

      var cp = spawn(bin, args, {stdio: 'inherit'});

      cp.on('error', grunt.warn);

      cp.on('close', function (code) {
        if (code > 0) {
          grunt.warn('Exited with error code ' + code);
          next();
          return;
        }

        grunt.verbose.writeln('File ' + chalk.cyan(file.dest) + ' created');
        next();
      });
    }, cb);
  });
};
<commit_msg>remove the underscore hater lines<commit_after>'use strict';
var path = require('path');
var os = require('os');
var dargs = require('dargs');
var async = require('async');
var chalk = require('chalk');
var spawn = require('cross-spawn');
var which = require('which');
var checkFilesSyntax = require('./lib/check');
var concurrencyCount = (os.cpus().length || 1) * 4;

module.exports = function (grunt) {
  var checkBinary = function (cmd, errMsg) {
    try {
      which.sync(cmd);
    } catch (err) {
      return grunt.warn(
        '\n' + errMsg + '\n' +
        'More info: https://github.com/gruntjs/grunt-contrib-sass\n'
      );
    }
  };

  grunt.registerMultiTask('sass', 'Compile Sass to CSS', function () {
    var cb = this.async();
    var options = this.options();

    if (options.bundleExec) {
      checkBinary('bundle',
        'bundleExec options set but no Bundler executable found in your PATH.'
      );
    } else {
      checkBinary('sass',
        'You need to have Ruby and Sass installed and in your PATH for this task to work.'
      );
    }

    if (options.check) {
      options.concurrencyCount = concurrencyCount;
      checkFilesSyntax(this.filesSrc, options, cb);
      return;
    }

    var passedArgs = dargs(options, {
      excludes: ['bundleExec'],
      ignoreFalse: true
    });

    async.eachLimit(this.files, concurrencyCount, function (file, next) {
      var src = file.src[0];

      var args = [
        src,
        file.dest
      ].concat(passedArgs);

      if (options.update) {
        // When the source file hasn't yet been compiled SASS will write an empty file.
        // If this is the first time the file has been written we treat it as if `update` was not passed
        if (!grunt.file.exists(file.dest)) {
          // Find where the --update flag is and remove it
          args.splice(args.indexOf('--update'), 1);
        } else {
          // The first two elements in args are the source and destination files,
          // which are used to build a path that SASS recognizes, i.e. "source:destination"
          args.push(args.shift() + ':' + args.shift());
        }
      }

      var bin = 'sass';

      if (options.bundleExec) {
        bin = 'bundle';
        args.unshift('exec', 'sass');
      }

      // If we're compiling scss or css files
      if (path.extname(src) === '.css') {
        args.push('--scss');
      }

      // Make sure grunt creates the destination folders if they don't exist
      if (!grunt.file.exists(file.dest)) {
        grunt.file.write(file.dest, '');
      }

      grunt.verbose.writeln('Command: ' + bin + ' ' + args.join(' '));

      var cp = spawn(bin, args, {stdio: 'inherit'});

      cp.on('error', grunt.warn);

      cp.on('close', function (code) {
        if (code > 0) {
          grunt.warn('Exited with error code ' + code);
          next();
          return;
        }

        grunt.verbose.writeln('File ' + chalk.cyan(file.dest) + ' created');
        next();
      });
    }, cb);
  });
};
<|endoftext|>


<commit_before>var tempart = require('tempart');

module.exports = function(grunt) {
	grunt.registerMultiTask('vood', 'Concatenate files.', function() {
		// @TODO add sourcemap
		var target = this.target;
		var container = '';
		this.files.forEach(function(task) {
			task.src.forEach(function(file) {
				grunt.log.writeln('Working on: ' + file);

				if(target == 'templates') {
					var template = grunt.file.read(task.cwd + '/' + file);
					var parsedTemplate = tempart.parse(template);
					var path = file.split('/');
					path.pop();
					var containerTemplate = 'vood.Template("' + path.join('/') + '", ' + JSON.stringify( parsedTemplate ) + ');';
					container += containerTemplate + "\n";
				} else {
					container += grunt.file.read(task.cwd + '/' + file);
				}
			});

			grunt.file.write(task.dest, container);
		});

	});
};
<commit_msg>[vood] added lib property<commit_after>var tempart = require('tempart');

module.exports = function(grunt) {
	grunt.registerMultiTask('vood', 'Concatenate files.', function() {
		var lib = this.options().lib;
		if(lib) {
			var vood = grunt.file.read(__dirname + '/../node_modules/vood/dist/vood.js');
			grunt.file.write(lib, vood);
		} else {
			grunt.fail.warn('The options object should contain a lib property with the path to dest/vood.js');
		}

		// @TODO add sourcemap
		var target = this.target;
		var container = '';
		this.files.forEach(function(task) {
			task.src.forEach(function(file) {
				grunt.log.writeln('Working on: ' + file);

				if(target == 'templates') {
					var template = grunt.file.read(task.cwd + '/' + file);
					var parsedTemplate = tempart.parse(template);
					var path = file.split('/');
					path.pop();
					var containerTemplate = 'vood.Template("' + path.join('/') + '", ' + JSON.stringify( parsedTemplate ) + ');';
					container += containerTemplate + "\n";
				} else {
					container += grunt.file.read(task.cwd + '/' + file);
				}
			});

			grunt.file.write(task.dest, container);
		});

	});
};
<|endoftext|>


<commit_before>/**
 * Copyright 2014 Netsend.
 *
 * This file is part of Mastersync.
 *
 * Mastersync is free software: you can redistribute it and/or modify it under the
 * terms of the GNU Affero General Public License as published by the Free Software
 * Foundation, either version 3 of the License, or (at your option) any later
 * version.
 *
 * Mastersync is distributed in the hope that it will be useful, but WITHOUT ANY
 * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
 * PARTICULAR PURPOSE. See the GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License along
 * with Mastersync. If not, see <https://www.gnu.org/licenses/>.
 */

'use strict';

var Readable = require('stream').Readable;
var util = require('util');

var mongodb = require('mongodb');

/**
 * OplogReader
 *
 * Read oplog, scoped to a certain namespace.
 *
 * @param {mongodb.Collection} oplogColl  oplog collection
 * @param {String} ns  namespace to read
 * @param {Object} [opts]  object containing optional parameters
 *
 * opts:
 *   filter {Object}  extra filter to apply apart from namespace
 *   offset {mongodb.Timestamp}  timestamp to start at
 *   includeOffset {Boolean, default false}  whether to include or exclude offset
 *   tailable {Boolean, default false}  whether or not to keep the cursor open and follow the oplog
 *   tailableRetryInterval {Number}  overrule tailableRetryInterval
 *   debug {Boolean, default false}  whether to do extra console logging or not
 *   hide {Boolean, default false}  whether to suppress errors or not (used in tests)
 *
 * @class represents an OplogReader for a certain namespace
 */
function OplogReader(oplogColl, ns, opts) {
  /* jshint maxcomplexity: 23 */ /* lots of parameter type checking */

  if (!(oplogColl instanceof mongodb.Collection)) { throw new TypeError('oplogColl must be an instance of mongodb.Collection'); }
  if (typeof ns !== 'string') { throw new TypeError('ns must be a string'); }

  var nsParts = ns.split('.');
  if (nsParts.length < 2) { throw new TypeError('ns must contain at least two parts'); }
  if (!nsParts[0].length) { throw new TypeError('ns must contain a database name'); }
  if (!nsParts[1].length) { throw new TypeError('ns must contain a collection name'); }

  if (typeof opts !== 'undefined' && typeof opts !== 'object') { throw new TypeError('opts must be an object'); }
  opts = opts || {};

  if (typeof opts.filter !== 'undefined' && typeof opts.filter !== 'object') { throw new TypeError('opts.filter must be an object'); }
  if (typeof opts.offset !== 'undefined' && !(opts.offset instanceof mongodb.Timestamp)) { throw new TypeError('opts.offset must be an instance of mongodb.Timestamp'); }
  if (typeof opts.includeOffset !== 'undefined' && typeof opts.includeOffset !== 'boolean') { throw new TypeError('opts.includeOffset must be a boolean'); }
  if (typeof opts.tailable !== 'undefined' && typeof opts.tailable !== 'boolean') { throw new TypeError('opts.tailable must be a boolean'); }
  if (typeof opts.tailableRetryInterval !== 'undefined' && typeof opts.tailableRetryInterval !== 'number') { throw new TypeError('opts.tailableRetryInterval must be a number'); }
  if (typeof opts.debug !== 'undefined' && typeof opts.debug !== 'boolean') { throw new TypeError('opts.debug must be a boolean'); }
  if (typeof opts.hide !== 'undefined' && typeof opts.hide !== 'boolean') { throw new TypeError('opts.hide must be a boolean'); }

  Readable.call(this, opts);

  this._debug = opts.debug || false;
  this._hide = !!opts.hide;

  this._databaseName = nsParts.shift();
  this._collectionName = nsParts.join('.');

  // setup CursorStream
  if (this._debug) { console.log('or _read offset', opts.offset); }

  var selector = { ns: ns };
  if (opts.offset) {
    if (opts.includeOffset) {
      selector.ts = { $gte: opts.offset };
    } else {
      selector.ts = { $gt: opts.offset };
    }
  }
  if (opts.filter) {
    selector = { $and: [selector, opts.filter] };
  }

  var mongoOpts = {
    raw: true,
    sort: { '$natural': 1 },
    comment: 'oplog_reader'
  };
  if (opts.tailable) { mongoOpts.tailable = true; }
  if (opts.tailableRetryInterval) { mongoOpts.tailableRetryInterval = opts.tailableRetryInterval; }

  if (this._debug) { console.log('or _read stream options', JSON.stringify(mongoOpts)); }

  this._source = oplogColl.find(selector, mongoOpts).stream();

  var that = this;

  // proxy errors
  this._source.on('error', function(err) {
    if (!that._hide) { console.error('or _read cursor stream error', err); }
    that.emit('error', err);
  });

  this._source.on('data', function(chunk) {
    if (that._debug) { console.log('or _read cursor stream data'); }
    // if push() returns false, then we need to stop reading from source
    if (!that.push(chunk)) {
      that._source.pause();
    }
  });

  this._source.on('close', function() {
    if (that._debug) { console.log('or _read cursor stream closed'); }
    that.push(null);
  });
}
util.inherits(OplogReader, Readable);

module.exports = OplogReader;

OplogReader.prototype._read = function _read() {
  this._source.resume();
};
<commit_msg>oplog_reader: debug info<commit_after>/**
 * Copyright 2014 Netsend.
 *
 * This file is part of Mastersync.
 *
 * Mastersync is free software: you can redistribute it and/or modify it under the
 * terms of the GNU Affero General Public License as published by the Free Software
 * Foundation, either version 3 of the License, or (at your option) any later
 * version.
 *
 * Mastersync is distributed in the hope that it will be useful, but WITHOUT ANY
 * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
 * PARTICULAR PURPOSE. See the GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License along
 * with Mastersync. If not, see <https://www.gnu.org/licenses/>.
 */

'use strict';

var Readable = require('stream').Readable;
var util = require('util');

var mongodb = require('mongodb');

/**
 * OplogReader
 *
 * Read oplog, scoped to a certain namespace.
 *
 * @param {mongodb.Collection} oplogColl  oplog collection
 * @param {String} ns  namespace to read
 * @param {Object} [opts]  object containing optional parameters
 *
 * opts:
 *   filter {Object}  extra filter to apply apart from namespace
 *   offset {mongodb.Timestamp}  timestamp to start at
 *   includeOffset {Boolean, default false}  whether to include or exclude offset
 *   tailable {Boolean, default false}  whether or not to keep the cursor open and follow the oplog
 *   tailableRetryInterval {Number}  overrule tailableRetryInterval
 *   debug {Boolean, default false}  whether to do extra console logging or not
 *   hide {Boolean, default false}  whether to suppress errors or not (used in tests)
 *
 * @class represents an OplogReader for a certain namespace
 */
function OplogReader(oplogColl, ns, opts) {
  /* jshint maxcomplexity: 23 */ /* lots of parameter type checking */

  if (!(oplogColl instanceof mongodb.Collection)) { throw new TypeError('oplogColl must be an instance of mongodb.Collection'); }
  if (typeof ns !== 'string') { throw new TypeError('ns must be a string'); }

  var nsParts = ns.split('.');
  if (nsParts.length < 2) { throw new TypeError('ns must contain at least two parts'); }
  if (!nsParts[0].length) { throw new TypeError('ns must contain a database name'); }
  if (!nsParts[1].length) { throw new TypeError('ns must contain a collection name'); }

  if (typeof opts !== 'undefined' && typeof opts !== 'object') { throw new TypeError('opts must be an object'); }
  opts = opts || {};

  if (typeof opts.filter !== 'undefined' && typeof opts.filter !== 'object') { throw new TypeError('opts.filter must be an object'); }
  if (typeof opts.offset !== 'undefined' && !(opts.offset instanceof mongodb.Timestamp)) { throw new TypeError('opts.offset must be an instance of mongodb.Timestamp'); }
  if (typeof opts.includeOffset !== 'undefined' && typeof opts.includeOffset !== 'boolean') { throw new TypeError('opts.includeOffset must be a boolean'); }
  if (typeof opts.tailable !== 'undefined' && typeof opts.tailable !== 'boolean') { throw new TypeError('opts.tailable must be a boolean'); }
  if (typeof opts.tailableRetryInterval !== 'undefined' && typeof opts.tailableRetryInterval !== 'number') { throw new TypeError('opts.tailableRetryInterval must be a number'); }
  if (typeof opts.debug !== 'undefined' && typeof opts.debug !== 'boolean') { throw new TypeError('opts.debug must be a boolean'); }
  if (typeof opts.hide !== 'undefined' && typeof opts.hide !== 'boolean') { throw new TypeError('opts.hide must be a boolean'); }

  Readable.call(this, opts);

  this._debug = opts.debug || false;
  this._hide = !!opts.hide;

  this._databaseName = nsParts.shift();
  this._collectionName = nsParts.join('.');

  // setup CursorStream
  var selector = { ns: ns };
  if (opts.offset) {
    if (opts.includeOffset) {
      selector.ts = { $gte: opts.offset };
    } else {
      selector.ts = { $gt: opts.offset };
    }
  }
  if (opts.filter) {
    selector = { $and: [selector, opts.filter] };
  }

  var mongoOpts = {
    raw: true,
    sort: { '$natural': 1 },
    comment: 'oplog_reader'
  };
  if (opts.tailable) { mongoOpts.tailable = true; }
  if (opts.tailableRetryInterval) { mongoOpts.tailableRetryInterval = opts.tailableRetryInterval; }

  if (this._debug) {
    console.log('or _read offset', opts.offset, opts.includeOffset ? 'include' : 'exclude');
    console.log('or _read query', JSON.stringify(selector), JSON.stringify(mongoOpts));
  }

  this._source = oplogColl.find(selector, mongoOpts).stream();

  var that = this;

  // proxy errors
  this._source.on('error', function(err) {
    if (!that._hide) { console.error('or _read cursor stream error', err); }
    that.emit('error', err);
  });

  this._source.on('data', function(chunk) {
    if (that._debug) { console.log('or _read cursor stream data'); }
    // if push() returns false, then we need to stop reading from source
    if (!that.push(chunk)) {
      that._source.pause();
    }
  });

  this._source.on('close', function() {
    if (that._debug) { console.log('or _read cursor stream closed'); }
    that.push(null);
  });
}
util.inherits(OplogReader, Readable);

module.exports = OplogReader;

OplogReader.prototype._read = function _read() {
  this._source.resume();
};
<|endoftext|>


<commit_before>'use strict';

var exec = require('child_process').exec;
var Fs = require('fs');
var Path = require('path');
var Promise = require('promise');

var DocumentDownloader = require('./document-downloader');
var JsonHttpService = require('./json-http-service');
var Publisher = require('./publisher');
var SpecberusWrapper = require('../functions.js').SpecberusWrapper;
var ThirdPartyChecker = require('../functions.js').ThirdPartyChecker;
var TokenChecker = require('../functions.js').TokenChecker;

var STATUS_ERROR = 'error';
var STATUS_SUCCESS = 'success';

// Configuration file
require('../config.js');

var argTempLocation = process.argv[2] || global.DEFAULT_TEMP_LOCATION;
var argHttpLocation  = process.argv[3] || global.DEFAULT_HTTP_LOCATION;
var argResultLocation = process.argv[5] || global.DEFAULT_RESULT_LOCATION;

function Job() {
  if (typeof this !== 'object') {
    throw new TypeError('Job must be constructed via new');
  }

  this.status = '';
  this.errors = [];
}

function dumpJobResult(dest, result) {
  Fs.writeFile(dest, JSON.stringify(result, null, 2) + '\n', function (err) {
    if (err) return console.error(err);
  });
}

function trInstaller(source, dest) {
  return new Promise(function (resolve, reject) {
    var cmd = global.TR_INSTALL_CMD + ' ' + source + ' ' + dest;
    exec(cmd, function (err) {
      if (err) reject(err);
      else resolve();
    });
  });
}

function updateTrShortlink(uri) {
  return new Promise(function (resolve, reject) {
    var cmd = global.UPDATE_TR_SHORTLINK_CMD + ' ' + uri;
    exec(cmd, function (err) {
      if (err) reject(err);
      else resolve();
    });
  });
}

var Orchestrator = function () {};

Orchestrator.prototype.runDocumentDownloader = function (url, tempLocation) {
  return function (state) {
    state.jobs['retrieve-resources'].status = 'pending';

    return DocumentDownloader.fetchAndInstall(url, tempLocation)
      .then(function () {
        state.jobs['retrieve-resources'].status = 'ok';
        state.history = state.history.add('The file has been retrieved.');

        return state;
      }).catch(function (error) {
        state.jobs['retrieve-resources'].status = 'error';
        state.jobs['retrieve-resources'].errors.push(error.toString());
        state.history = state.history.add(
          'The document could not be retrieved.'
        );

        return state;
      });
  };
};

Orchestrator.prototype.runSpecberus = function (httpLocation) {
  return function (state) {
    state.jobs['specberus'].status = 'pending';

    return SpecberusWrapper.validate(httpLocation)
      .then(function (report) {
        if (report.errors.isEmpty()) {
          state.jobs['specberus'].status = 'ok';
          state.history = state.history.add('The document passed specberus.');
          state.metadata = report.metadata;
        }
        else {
          state.jobs['specberus'].status = 'failure';
          state.jobs['specberus'].errors = report.errors;
          state.history = state.history.add('The document failed Specberus.');
        }

        return state;
      }).catch(function (error) {
        state.jobs['specberus'].status = 'error';
        state.jobs['specberus'].errors.push(error.toString());
        state.history = state.history.add(
          'An error occurred while running Specberus.'
        );

        return state;
      });
  };
};

Orchestrator.prototype.runTokenChecker = function (latestVersion, url, token) {
  return function (state) {
    state.jobs['token-checker'].status = 'pending';

    return TokenChecker.check(latestVersion, token)
      .then(function (authReport) {
        var simpleSource1 = authReport.source.replace(/^https:/i, 'http:');
        var simpleSource2 = authReport.source.replace(/^http:/i, 'https:');
        var matchSource = (
          url.indexOf(simpleSource1) === 0 ||
          url.indexOf(simpleSource2) === 0
        );

        if (authReport.authorized && matchSource) {
          state.jobs['token-checker'].status = 'ok';
          state.history = state.history.add('You are authorized to publish');

          return state;
        }
        else {
          state.jobs['token-checker'].status = 'failure';
          state.jobs['token-checker'].errors.push('Not authorized');
          state.history = state.history.add(
            'You are not authorized to publish'
          );

          return state;
        }
      }).catch(function (error) {
        state.jobs['token-checker'].status = 'error';
        state.jobs['token-checker'].errors.push(error.toString());
        state.history = state.history.add(
          'An error occurred while running the Token Checker.'
        );

        return state;
      });
  };
};

Orchestrator.prototype.runThirdPartyChecker = function (httpLocation) {
  return function (state) {
    state.jobs['third-party-checker'].status = 'pending';

    return ThirdPartyChecker.check(httpLocation)
      .then(function (extResources) {
        if (extResources.length === 0) {
          state.jobs['third-party-checker'].status = 'ok';
          state.history = state.history.add(
            'The document passed the third party checker.'
          );

          return state;
        }
        else {
          state.history = state.history.add(
            'The document contains non-authorized resources'
          );
          state.jobs['third-party-checker'].status = 'failure';
          state.jobs['third-party-checker'].errors = extResources;

          return state;
        }
      }).catch(function (error) {
        state.jobs['third-party-checker'].status = 'error';
        state.jobs['third-party-checker'].errors.push(error.toString());
        state.history = state.history.add(
          'An error occurred while running the Third Party Resources Checker.'
        );

        return state;
      });
  };
};

Orchestrator.prototype.runPublisher = function (metadata) {
  return function (state) {
    state.jobs['publish'].status = 'pending';

    var pubsystemService = new JsonHttpService(
      global.W3C_PUBSYSTEM_URL,
      global.USERNAME,
      global.PASSWORD
    );

    return new Publisher(pubsystemService).publish(metadata)
      .then(function (errors) {
        if (errors.isEmpty()) {
          state.jobs['publish'].status = 'ok';

          return state;
        }
        else {
          state.jobs['publish'].status = 'failure';
          state.jobs['publish'].errors = errors;
          state.history = state.history.add(
            'The document could not be published: ' +
            errors.map(function (error) {
              return error.message;
            })
          );

          return state;
        }
      }).catch(function (error) {
        state.jobs['publish'].status = 'error';
        state.jobs['publish'].errors.push(error.toString());
        state.history = state.history.add(
          'The document could not be published: ' + error.message
        );

        return state;
      });
  };
};

Orchestrator.prototype.runTrInstaller = function (thisVersion, tempLocation) {
  return function (state) {
    state.jobs['tr-install'].status = 'pending';

    var finalTRpath = thisVersion.replace('http://www.w3.org', '');
    return trInstaller(tempLocation, finalTRpath)
      .then(function () {
        state.jobs['tr-install'].status = 'ok';

        return state;
      }).catch(function (error) {
        state.jobs['tr-install'].status = 'error';
        state.jobs['tr-install'].errors.push(error.toString());
        state.history = state.history.add(
          'An error occurred while installing the document in TR'
        );

        return state;
      });
  };
};

Orchestrator.prototype.runShortlink = function (thisVersion) {
  return function (state) {
    state.jobs['update-tr-shortlink'].status = 'pending';

    return updateTrShortlink(thisVersion)
      .then(function () {
        state.jobs['update-tr-shortlink'].status = 'ok';

        return state;
      }).catch(function (error) {
        state.jobs['update-tr-shortlink'].status = 'error';
        state.jobs['update-tr-shortlink'].errors.push(error.toString());
        state.history = state.history.add(
          'An error occurred while updating the shortlink.'
        );

        return state;
      });
  };
};

Orchestrator.prototype.finishTasks = function (thisVersion, resultLocation) {
  return function (state) {
    var cmd =
      global.SENDMAIL + ' SUCCESS ' + global.MAILING_LIST + ' ' + thisVersion;

    exec(cmd, function (err, stdout, stderr) {
      if (err) console.error(stderr);
    });

    state.history = state.history.add(
      'The document has been published at ' +
      '' + thisVersion + '.'
    );
    state.status = STATUS_SUCCESS;

    dumpJobResult(resultLocation, state);

    return state;
  };
};

Orchestrator.prototype.run = function (spec, token) {
  var self = this;

  spec.jobs['retrieve-resources'] = new Job();
  spec.jobs['specberus'] = new Job();
  spec.jobs['token-checker'] = new Job();
  spec.jobs['third-party-checker'] = new Job();
  spec.jobs['publish'] = new Job();
  spec.jobs['tr-install'] = new Job();
  spec.jobs['update-tr-shortlink'] = new Job();

  var tempLocation = argTempLocation + Path.sep + spec.id + Path.sep;
  var resultLocation = argResultLocation + Path.sep + spec.id + '.json';
  var httpLocation = argHttpLocation + '/' + spec.id + '/Overview.html';

  return self.runDocumentDownloader(spec.url, tempLocation)(spec)
    .then(self.runSpecberus(httpLocation))
    .then(function (state) {
      var metadata = state.metadata;

      return self.runTokenChecker(
        metadata.get('latestVersion'),
        spec.url,
        token
      )(state)
        .then(self.runThirdPartyChecker(httpLocation))
        .then(self.runPublisher(metadata))
        .then(self.runTrInstaller(metadata.get('thisVersion'), tempLocation))
        .then(self.runShortlink(metadata.get('thisVersion')))
        .then(self.finishTasks(metadata.get('thisVersion'), resultLocation));
    })
    .catch(function (err) {
      console.log(err.stack);

      spec.status = STATUS_ERROR;
      var cmd =
        global.SENDMAIL + ' ERROR ' + global.MAILING_LIST + ' ' + spec.url +
        ' \'' + JSON.stringify(spec, null, 2) + '\'';

      exec(cmd, function (err, stdout, stderr) {
        if (err) console.error(stderr);
      });

      spec.history = spec.history.add(
        'A system error occurred during the process.'
      );

      dumpJobResult(resultLocation, spec);
      return Promise.reject(new Error('Orchestrator has failed.'));
    });
};

module.exports = Orchestrator;
<commit_msg>Restore pending states<commit_after>'use strict';

var exec = require('child_process').exec;
var Fs = require('fs');
var Path = require('path');
var Promise = require('promise');

var DocumentDownloader = require('./document-downloader');
var JsonHttpService = require('./json-http-service');
var Publisher = require('./publisher');
var SpecberusWrapper = require('../functions.js').SpecberusWrapper;
var ThirdPartyChecker = require('../functions.js').ThirdPartyChecker;
var TokenChecker = require('../functions.js').TokenChecker;

var STATUS_ERROR = 'error';
var STATUS_SUCCESS = 'success';

// Configuration file
require('../config.js');

var argTempLocation = process.argv[2] || global.DEFAULT_TEMP_LOCATION;
var argHttpLocation  = process.argv[3] || global.DEFAULT_HTTP_LOCATION;
var argResultLocation = process.argv[5] || global.DEFAULT_RESULT_LOCATION;

function Job() {
  if (typeof this !== 'object') {
    throw new TypeError('Job must be constructed via new');
  }

  this.status = '';
  this.errors = [];
}

function dumpJobResult(dest, result) {
  Fs.writeFile(dest, JSON.stringify(result, null, 2) + '\n', function (err) {
    if (err) return console.error(err);
  });
}

function trInstaller(source, dest) {
  return new Promise(function (resolve, reject) {
    var cmd = global.TR_INSTALL_CMD + ' ' + source + ' ' + dest;
    exec(cmd, function (err) {
      if (err) reject(err);
      else resolve();
    });
  });
}

function updateTrShortlink(uri) {
  return new Promise(function (resolve, reject) {
    var cmd = global.UPDATE_TR_SHORTLINK_CMD + ' ' + uri;
    exec(cmd, function (err) {
      if (err) reject(err);
      else resolve();
    });
  });
}

var Orchestrator = function () {};

Orchestrator.prototype.runDocumentDownloader = function (url, tempLocation) {
  return function (state) {
    return DocumentDownloader.fetchAndInstall(url, tempLocation)
      .then(function () {
        state.jobs['retrieve-resources'].status = 'ok';
        state.history = state.history.add('The file has been retrieved.');

        return state;
      }).catch(function (error) {
        state.jobs['retrieve-resources'].status = 'error';
        state.jobs['retrieve-resources'].errors.push(error.toString());
        state.history = state.history.add(
          'The document could not be retrieved.'
        );

        return state;
      });
  };
};

Orchestrator.prototype.runSpecberus = function (httpLocation) {
  return function (state) {
    return SpecberusWrapper.validate(httpLocation)
      .then(function (report) {
        if (report.errors.isEmpty()) {
          state.jobs['specberus'].status = 'ok';
          state.history = state.history.add('The document passed specberus.');
          state.metadata = report.metadata;
        }
        else {
          state.jobs['specberus'].status = 'failure';
          state.jobs['specberus'].errors = report.errors;
          state.history = state.history.add('The document failed Specberus.');
        }

        return state;
      }).catch(function (error) {
        state.jobs['specberus'].status = 'error';
        state.jobs['specberus'].errors.push(error.toString());
        state.history = state.history.add(
          'An error occurred while running Specberus.'
        );

        return state;
      });
  };
};

Orchestrator.prototype.runTokenChecker = function (latestVersion, url, token) {
  return function (state) {
    return TokenChecker.check(latestVersion, token)
      .then(function (authReport) {
        var simpleSource1 = authReport.source.replace(/^https:/i, 'http:');
        var simpleSource2 = authReport.source.replace(/^http:/i, 'https:');
        var matchSource = (
          url.indexOf(simpleSource1) === 0 ||
          url.indexOf(simpleSource2) === 0
        );

        if (authReport.authorized && matchSource) {
          state.jobs['token-checker'].status = 'ok';
          state.history = state.history.add('You are authorized to publish');

          return state;
        }
        else {
          state.jobs['token-checker'].status = 'failure';
          state.jobs['token-checker'].errors.push('Not authorized');
          state.history = state.history.add(
            'You are not authorized to publish'
          );

          return state;
        }
      }).catch(function (error) {
        state.jobs['token-checker'].status = 'error';
        state.jobs['token-checker'].errors.push(error.toString());
        state.history = state.history.add(
          'An error occurred while running the Token Checker.'
        );

        return state;
      });
  };
};

Orchestrator.prototype.runThirdPartyChecker = function (httpLocation) {
  return function (state) {
    return ThirdPartyChecker.check(httpLocation)
      .then(function (extResources) {
        if (extResources.length === 0) {
          state.jobs['third-party-checker'].status = 'ok';
          state.history = state.history.add(
            'The document passed the third party checker.'
          );

          return state;
        }
        else {
          state.history = state.history.add(
            'The document contains non-authorized resources'
          );
          state.jobs['third-party-checker'].status = 'failure';
          state.jobs['third-party-checker'].errors = extResources;

          return state;
        }
      }).catch(function (error) {
        state.jobs['third-party-checker'].status = 'error';
        state.jobs['third-party-checker'].errors.push(error.toString());
        state.history = state.history.add(
          'An error occurred while running the Third Party Resources Checker.'
        );

        return state;
      });
  };
};

Orchestrator.prototype.runPublisher = function (metadata) {
  return function (state) {
    var pubsystemService = new JsonHttpService(
      global.W3C_PUBSYSTEM_URL,
      global.USERNAME,
      global.PASSWORD
    );

    return new Publisher(pubsystemService).publish(metadata)
      .then(function (errors) {
        if (errors.isEmpty()) {
          state.jobs['publish'].status = 'ok';

          return state;
        }
        else {
          state.jobs['publish'].status = 'failure';
          state.jobs['publish'].errors = errors;
          state.history = state.history.add(
            'The document could not be published: ' +
            errors.map(function (error) {
              return error.message;
            })
          );

          return state;
        }
      }).catch(function (error) {
        state.jobs['publish'].status = 'error';
        state.jobs['publish'].errors.push(error.toString());
        state.history = state.history.add(
          'The document could not be published: ' + error.message
        );

        return state;
      });
  };
};

Orchestrator.prototype.runTrInstaller = function (thisVersion, tempLocation) {
  return function (state) {
    var finalTRpath = thisVersion.replace('http://www.w3.org', '');
    return trInstaller(tempLocation, finalTRpath)
      .then(function () {
        state.jobs['tr-install'].status = 'ok';

        return state;
      }).catch(function (error) {
        state.jobs['tr-install'].status = 'error';
        state.jobs['tr-install'].errors.push(error.toString());
        state.history = state.history.add(
          'An error occurred while installing the document in TR'
        );

        return state;
      });
  };
};

Orchestrator.prototype.runShortlink = function (thisVersion) {
  return function (state) {
    return updateTrShortlink(thisVersion)
      .then(function () {
        state.jobs['update-tr-shortlink'].status = 'ok';

        return state;
      }).catch(function (error) {
        state.jobs['update-tr-shortlink'].status = 'error';
        state.jobs['update-tr-shortlink'].errors.push(error.toString());
        state.history = state.history.add(
          'An error occurred while updating the shortlink.'
        );

        return state;
      });
  };
};

Orchestrator.prototype.finishTasks = function (thisVersion, resultLocation) {
  return function (state) {
    var cmd =
      global.SENDMAIL + ' SUCCESS ' + global.MAILING_LIST + ' ' + thisVersion;

    exec(cmd, function (err, stdout, stderr) {
      if (err) console.error(stderr);
    });

    state.history = state.history.add(
      'The document has been published at ' +
      '' + thisVersion + '.'
    );
    state.status = STATUS_SUCCESS;

    dumpJobResult(resultLocation, state);

    return state;
  };
};

Orchestrator.prototype.markStarted = function (jobName) {
  return function (state) {
    state.jobs[jobName].status = 'pending';
    return state;
  };
};

Orchestrator.prototype.run = function (spec, token) {
  var self = this;

  spec.jobs['retrieve-resources'] = new Job();
  spec.jobs['specberus'] = new Job();
  spec.jobs['token-checker'] = new Job();
  spec.jobs['third-party-checker'] = new Job();
  spec.jobs['publish'] = new Job();
  spec.jobs['tr-install'] = new Job();
  spec.jobs['update-tr-shortlink'] = new Job();

  var tempLocation = argTempLocation + Path.sep + spec.id + Path.sep;
  var resultLocation = argResultLocation + Path.sep + spec.id + '.json';
  var httpLocation = argHttpLocation + '/' + spec.id + '/Overview.html';

  return Promise.resolve(self.markStarted('retrieve-resources')(spec))
    .then(self.runDocumentDownloader(spec.url, tempLocation))
    .then(self.markStarted('specberus'))
    .then(self.runSpecberus(httpLocation))
    .then(function (state) {
      var metadata = state.metadata;

      return Promise.resolve(self.markStarted('token-checker')(state))
        .then(self.runTokenChecker(
          metadata.get('latestVersion'),
          spec.url, token
        ))
        .then(self.markStarted('third-party-checker'))
        .then(self.runThirdPartyChecker(httpLocation))
        .then(self.markStarted('publish'))
        .then(self.runPublisher(metadata))
        .then(self.markStarted('tr-install'))
        .then(self.runTrInstaller(metadata.get('thisVersion'), tempLocation))
        .then(self.markStarted('update-tr-shortlink'))
        .then(self.runShortlink(metadata.get('thisVersion')))
        .then(self.finishTasks(metadata.get('thisVersion'), resultLocation));
    })
    .catch(function (err) {
      console.log(err.stack);

      spec.status = STATUS_ERROR;
      var cmd =
        global.SENDMAIL + ' ERROR ' + global.MAILING_LIST + ' ' + spec.url +
        ' \'' + JSON.stringify(spec, null, 2) + '\'';

      exec(cmd, function (err, stdout, stderr) {
        if (err) console.error(stderr);
      });

      spec.history = spec.history.add(
        'A system error occurred during the process.'
      );

      dumpJobResult(resultLocation, spec);
      return Promise.reject(new Error('Orchestrator has failed.'));
    });
};

module.exports = Orchestrator;
<|endoftext|>


<commit_before>var City = function() {
  var COLOR_GROUND = 0xaaaaaa;

  var city = {};

  city.STREET_WIDTH = 3;
  city.STREET_DEPTH = 3;
  city.BLOCK_WIDTH = 8;
  city.BLOCK_DEPTH = 8;
  city.BLOCK_ROWS = 60;
  city.BLOCK_COLUMNS = 60;
  city.MIN_BUILDING_HEIGHT = 1.2;
  city.MAX_BUILDING_HEIGHT = 40;
  city.MAX_BUILDING_MATERIALS = 50;
  city.TOTAL_SCENE_WIDTH = (city.BLOCK_WIDTH * city.BLOCK_ROWS) + (city.STREET_WIDTH * (city.BLOCK_ROWS - 1));
  city.HALF_SCENE_WIDTH = city.TOTAL_SCENE_WIDTH / 2;
  city.TOTAL_SCENE_DEPTH = (city.BLOCK_DEPTH * city.BLOCK_COLUMNS) + (city.STREET_DEPTH * (city.BLOCK_COLUMNS - 1));
  city.HALF_SCENE_DEPTH = city.TOTAL_SCENE_DEPTH / 2;

  city.BLOCK_LAYOUTS = [
    [ { width:     1.0,  depth: 1.0,  offsetFromBlockCenterX:      0.0,  offsetFromBlockCenterZ:  0.0 } ],

    [ { width:     0.5,  depth: 1.0,  offsetFromBlockCenterX:     -0.5,  offsetFromBlockCenterZ:  0.0 },
      { width:     0.5,  depth: 1.0,  offsetFromBlockCenterX:      0.5,  offsetFromBlockCenterZ:  0.0 } ],

    [ { width:     1.0,  depth: 0.5,  offsetFromBlockCenterX:      0.0,  offsetFromBlockCenterZ: -0.5 },
      { width:     1.0,  depth: 0.5,  offsetFromBlockCenterX:      0.0,  offsetFromBlockCenterZ:  0.5 } ],

    [ { width:     0.5,  depth: 1.0,  offsetFromBlockCenterX:     -0.5,  offsetFromBlockCenterZ:  0.0 },
      { width:     0.5,  depth: 0.5,  offsetFromBlockCenterX:      0.5,  offsetFromBlockCenterZ: -0.5 },
      { width:     0.5,  depth: 0.5,  offsetFromBlockCenterX:      0.5,  offsetFromBlockCenterZ:  0.5 } ],

    [ { width:     0.5,  depth: 0.5,  offsetFromBlockCenterX:     -0.5,  offsetFromBlockCenterZ: -0.5 },
      { width:     0.5,  depth: 0.5,  offsetFromBlockCenterX:     -0.5,  offsetFromBlockCenterZ:  0.5 },
      { width:     0.5,  depth: 0.5,  offsetFromBlockCenterX:      0.5,  offsetFromBlockCenterZ: -0.5 },
      { width:     0.5,  depth: 0.5,  offsetFromBlockCenterX:      0.5,  offsetFromBlockCenterZ:  0.5 } ],

    [ { width: (1 / 3),  depth: 0.5,  offsetFromBlockCenterX: -(2 / 3),  offsetFromBlockCenterZ:  0.5 },
      { width: (1 / 3),  depth: 0.5,  offsetFromBlockCenterX:      0.0,  offsetFromBlockCenterZ:  0.5 },
      { width: (1 / 3),  depth: 0.5,  offsetFromBlockCenterX:  (2 / 3),  offsetFromBlockCenterZ:  0.5 },
      { width:     0.5,  depth: 0.5,  offsetFromBlockCenterX:     -0.5,  offsetFromBlockCenterZ: -0.5 },
      { width:     0.5,  depth: 0.5,  offsetFromBlockCenterX:      0.5,  offsetFromBlockCenterZ: -0.5 } ],
  ];

  city.buildScene = function() {
    var scene = new THREE.Scene();

    scene.add(buildGroundGeometry());

    var buildingMaterials = buildMaterials();
    var buildingGeometries = buildEmptyGeometriesForBuildings();

    // Loop through the lower left corner of each block
    var x, z;
    for (x = -(city.HALF_SCENE_WIDTH); x < city.HALF_SCENE_WIDTH; x += city.BLOCK_WIDTH + city.STREET_WIDTH) {
      for (z = -(city.HALF_SCENE_DEPTH); z < city.HALF_SCENE_DEPTH; z += city.BLOCK_DEPTH + city.STREET_DEPTH) {
        generateBlock(x, z, buildingGeometries);
      }
    }

    for (var i = 0; i < city.MAX_BUILDING_MATERIALS; i++) {
      scene.add(new THREE.Mesh(buildingGeometries[i], buildingMaterials[i]));
    }

    return scene;
  };

  var buildGroundGeometry = function() {
    var groundMaterial = new THREE.MeshBasicMaterial({ color: COLOR_GROUND, });
    var groundGeometry = new THREE.Mesh(new THREE.PlaneGeometry(city.TOTAL_SCENE_WIDTH * 25, city.TOTAL_SCENE_DEPTH * 25), groundMaterial);
    groundGeometry.rotation.x = -(Math.PI / 2);

    return groundGeometry;
  };

  var buildMaterials = function() {
    var buildingMaterials = [];

    for (var i = 0; i < city.MAX_BUILDING_MATERIALS; i++) {
      var random = Math.random() * 0.6;
      var r = random;
      var g = random;
      var b = random;

      buildingMaterials.push(new THREE.MeshLambertMaterial({ color: new THREE.Color(r, g, b), }));
    }

    return buildingMaterials;
  };

  var buildEmptyGeometriesForBuildings = function() {
    var buildingGeometries = [];

    for (var i = 0; i < city.MAX_BUILDING_MATERIALS; i++) {
      buildingGeometries.push(new THREE.Geometry());
    }

    return buildingGeometries;
  };

  var generateBlock = function(x, z, buildingGeometries) {
    var i, lotLayout, buildingHeight, building;
    var blockLayout = city.BLOCK_LAYOUTS[Math.floor(Math.random() * city.BLOCK_LAYOUTS.length)];

    for (i = 0; i < blockLayout.length; i++) {
      lotLayout = blockLayout[i];
      buildingHeight = calculateBuildingHeight(x, z);
      building = generateBuilding(x, buildingHeight, z, lotLayout);

      var materialIndex = Math.floor(Math.random() * city.MAX_BUILDING_MATERIALS);
      buildingGeometries[materialIndex].merge(building.geometry, building.matrix);
    }
  };

  var calculateBuildingHeight = function(x, z) {
    var squareRootOfMaxBuildingHeight = Math.sqrt(city.MAX_BUILDING_HEIGHT);

    var multiplierX = squareRootOfMaxBuildingHeight * ((city.HALF_SCENE_WIDTH - Math.abs(x)) / city.HALF_SCENE_WIDTH);
    var multiplierZ = squareRootOfMaxBuildingHeight * ((city.HALF_SCENE_DEPTH - Math.abs(z)) / city.HALF_SCENE_DEPTH);
    var multiplier = Math.min(multiplierX, multiplierZ);

    return multiplier * multiplier;
  };

  var generateBuilding = function(x, maxY, z, lotLayout) {
    var building = new THREE.Mesh(new THREE.BoxGeometry(lotLayout.width * city.BLOCK_WIDTH, 1, lotLayout.depth * city.BLOCK_WIDTH));

    building.position.x = x + city.BLOCK_WIDTH / 2 + ((city.BLOCK_WIDTH / 2) * lotLayout.offsetFromBlockCenterX);
    building.scale.y =  (Math.random() * maxY) + city.MIN_BUILDING_HEIGHT;
    building.position.y = building.scale.y / 2;
    building.position.z = z + city.BLOCK_DEPTH / 2 + ((city.BLOCK_DEPTH / 2) * lotLayout.offsetFromBlockCenterZ);
    building.updateMatrix();

    return building;
  };

  return city;
};
<commit_msg>First (very rough) pass at having variable height terrain<commit_after>var City = function() {
  var COLOR_GROUND = 0xaaaaaa;

  var city = {};

  city.STREET_WIDTH = 3;
  city.STREET_DEPTH = 3;
  city.BLOCK_WIDTH = 8;
  city.BLOCK_DEPTH = 8;
  city.BLOCK_ROWS = 60;
  city.BLOCK_COLUMNS = 60;
  city.MIN_BUILDING_HEIGHT = 1.2;
  city.MAX_BUILDING_HEIGHT = 40;
  city.MAX_BUILDING_MATERIALS = 50;
  city.TOTAL_SCENE_WIDTH = (city.BLOCK_WIDTH * city.BLOCK_ROWS) + (city.STREET_WIDTH * (city.BLOCK_ROWS - 1));
  city.HALF_SCENE_WIDTH = city.TOTAL_SCENE_WIDTH / 2;
  city.TOTAL_SCENE_DEPTH = (city.BLOCK_DEPTH * city.BLOCK_COLUMNS) + (city.STREET_DEPTH * (city.BLOCK_COLUMNS - 1));
  city.HALF_SCENE_DEPTH = city.TOTAL_SCENE_DEPTH / 2;

  city.BLOCK_LAYOUTS = [
    [ { width:     1.0,  depth: 1.0,  offsetFromBlockCenterX:      0.0,  offsetFromBlockCenterZ:  0.0 } ],

    [ { width:     0.5,  depth: 1.0,  offsetFromBlockCenterX:     -0.5,  offsetFromBlockCenterZ:  0.0 },
      { width:     0.5,  depth: 1.0,  offsetFromBlockCenterX:      0.5,  offsetFromBlockCenterZ:  0.0 } ],

    [ { width:     1.0,  depth: 0.5,  offsetFromBlockCenterX:      0.0,  offsetFromBlockCenterZ: -0.5 },
      { width:     1.0,  depth: 0.5,  offsetFromBlockCenterX:      0.0,  offsetFromBlockCenterZ:  0.5 } ],

    [ { width:     0.5,  depth: 1.0,  offsetFromBlockCenterX:     -0.5,  offsetFromBlockCenterZ:  0.0 },
      { width:     0.5,  depth: 0.5,  offsetFromBlockCenterX:      0.5,  offsetFromBlockCenterZ: -0.5 },
      { width:     0.5,  depth: 0.5,  offsetFromBlockCenterX:      0.5,  offsetFromBlockCenterZ:  0.5 } ],

    [ { width:     0.5,  depth: 0.5,  offsetFromBlockCenterX:     -0.5,  offsetFromBlockCenterZ: -0.5 },
      { width:     0.5,  depth: 0.5,  offsetFromBlockCenterX:     -0.5,  offsetFromBlockCenterZ:  0.5 },
      { width:     0.5,  depth: 0.5,  offsetFromBlockCenterX:      0.5,  offsetFromBlockCenterZ: -0.5 },
      { width:     0.5,  depth: 0.5,  offsetFromBlockCenterX:      0.5,  offsetFromBlockCenterZ:  0.5 } ],

    [ { width: (1 / 3),  depth: 0.5,  offsetFromBlockCenterX: -(2 / 3),  offsetFromBlockCenterZ:  0.5 },
      { width: (1 / 3),  depth: 0.5,  offsetFromBlockCenterX:      0.0,  offsetFromBlockCenterZ:  0.5 },
      { width: (1 / 3),  depth: 0.5,  offsetFromBlockCenterX:  (2 / 3),  offsetFromBlockCenterZ:  0.5 },
      { width:     0.5,  depth: 0.5,  offsetFromBlockCenterX:     -0.5,  offsetFromBlockCenterZ: -0.5 },
      { width:     0.5,  depth: 0.5,  offsetFromBlockCenterX:      0.5,  offsetFromBlockCenterZ: -0.5 } ],
  ];

  city.buildScene = function() {
    var scene = new THREE.Scene();

    scene.add(buildGroundGeometry());

    var buildingMaterials = buildMaterials();
    var buildingGeometries = buildEmptyGeometriesForBuildings();

    // Loop through the lower left corner of each block
    var x, z;
    for (x = -(city.HALF_SCENE_WIDTH); x < city.HALF_SCENE_WIDTH; x += city.BLOCK_WIDTH + city.STREET_WIDTH) {
      for (z = -(city.HALF_SCENE_DEPTH); z < city.HALF_SCENE_DEPTH; z += city.BLOCK_DEPTH + city.STREET_DEPTH) {
        generateBlock(x, z, buildingGeometries);
      }
    }

    for (var i = 0; i < city.MAX_BUILDING_MATERIALS; i++) {
      scene.add(new THREE.Mesh(buildingGeometries[i], buildingMaterials[i]));
    }

    var terrainMeshes = buildTerrainGeometry();
    terrainMeshes.forEach(function(terrainMesh) {
      scene.add(terrainMesh);
    });

    return scene;
  };

  var buildGroundGeometry = function() {
    var groundMaterial = new THREE.MeshBasicMaterial({ color: COLOR_GROUND, });
    var groundGeometry = new THREE.Mesh(new THREE.PlaneGeometry(city.TOTAL_SCENE_WIDTH * 25, city.TOTAL_SCENE_DEPTH * 25), groundMaterial);
    groundGeometry.rotation.x = -(Math.PI / 2);

    return groundGeometry;
  };

  var buildTerrainGeometry = function() {
    var terrainCoordinates = [];
    for (x = -(city.HALF_SCENE_WIDTH); x < city.HALF_SCENE_WIDTH; x += city.BLOCK_WIDTH + city.STREET_WIDTH) {
      for (z = -(city.HALF_SCENE_DEPTH); z < city.HALF_SCENE_DEPTH; z += city.BLOCK_DEPTH + city.STREET_DEPTH) {
        if (!terrainCoordinates[x]) {
          terrainCoordinates[x] = [];
        }

        terrainCoordinates[x][z] = Math.floor(Math.random() * 10);
      }
    }

    var terrainGeometry1 = new THREE.Geometry();
    var terrainGeometry2 = new THREE.Geometry();
    var terrainMaterial1 = new THREE.MeshLambertMaterial({ color: new THREE.Color(0, 200, 0) });
    var terrainMaterial2 = new THREE.MeshLambertMaterial({ color: new THREE.Color(255, 25, 0) });

    var triangle, v1, v2, v3;
    for (x = -(city.HALF_SCENE_WIDTH); x < city.HALF_SCENE_WIDTH - (city.BLOCK_WIDTH + city.STREET_WIDTH); x += city.BLOCK_WIDTH + city.STREET_WIDTH) {
      for (z = -(city.HALF_SCENE_DEPTH); z < city.HALF_SCENE_DEPTH; z += city.BLOCK_DEPTH + city.STREET_DEPTH) {
        triangle = new THREE.Geometry();
        v1 = new THREE.Vector3(x, terrainCoordinates[x][z], z);
        v2 = new THREE.Vector3(x, terrainCoordinates[x][z + city.BLOCK_DEPTH + city.STREET_DEPTH], z + city.BLOCK_DEPTH + city.STREET_DEPTH);
        v3 = new THREE.Vector3(x + city.BLOCK_WIDTH + city.STREET_WIDTH, terrainCoordinates[x + city.BLOCK_WIDTH + city.STREET_WIDTH][z], z);

        triangle.vertices.push(v1);
        triangle.vertices.push(v2);
        triangle.vertices.push(v3);

        triangle.faces.push(new THREE.Face3(0, 1, 2));
        triangle.computeFaceNormals();

        terrainGeometry1.merge(triangle);

        triangle = new THREE.Geometry();
        v1 = new THREE.Vector3(x, terrainCoordinates[x][z + city.BLOCK_DEPTH + city.STREET_DEPTH], z + city.BLOCK_DEPTH + city.STREET_DEPTH);
        v2 = new THREE.Vector3(x + city.BLOCK_WIDTH + city.STREET_WIDTH, terrainCoordinates[x + city.BLOCK_WIDTH + city.STREET_WIDTH][z + city.BLOCK_DEPTH + city.STREET_DEPTH], z + city.BLOCK_DEPTH + city.STREET_DEPTH);
        v3 = new THREE.Vector3(x + city.BLOCK_WIDTH + city.STREET_WIDTH, terrainCoordinates[x + city.BLOCK_WIDTH + city.STREET_WIDTH][z], z);

        triangle.vertices.push(v1);
        triangle.vertices.push(v2);
        triangle.vertices.push(v3);

        triangle.faces.push(new THREE.Face3(0, 1, 2));
        triangle.computeFaceNormals();

        terrainGeometry2.merge(triangle);
      }
    }

    var mesh1 = new THREE.Mesh(terrainGeometry1, terrainMaterial1);
    var mesh2 = new THREE.Mesh(terrainGeometry2, terrainMaterial2);

    return [mesh1, mesh2];
  };

  var buildMaterials = function() {
    var buildingMaterials = [];

    for (var i = 0; i < city.MAX_BUILDING_MATERIALS; i++) {
      var random = Math.random() * 0.6;
      var r = random;
      var g = random;
      var b = random;

      buildingMaterials.push(new THREE.MeshLambertMaterial({ color: new THREE.Color(r, g, b), }));
    }

    return buildingMaterials;
  };

  var buildEmptyGeometriesForBuildings = function() {
    var buildingGeometries = [];

    for (var i = 0; i < city.MAX_BUILDING_MATERIALS; i++) {
      buildingGeometries.push(new THREE.Geometry());
    }

    return buildingGeometries;
  };

  var generateBlock = function(x, z, buildingGeometries) {
    var i, lotLayout, buildingHeight, building;
    var blockLayout = city.BLOCK_LAYOUTS[Math.floor(Math.random() * city.BLOCK_LAYOUTS.length)];

    for (i = 0; i < blockLayout.length; i++) {
      lotLayout = blockLayout[i];
      buildingHeight = calculateBuildingHeight(x, z);
      building = generateBuilding(x, buildingHeight, z, lotLayout);

      var materialIndex = Math.floor(Math.random() * city.MAX_BUILDING_MATERIALS);
      buildingGeometries[materialIndex].merge(building.geometry, building.matrix);
    }
  };

  var calculateBuildingHeight = function(x, z) {
    var squareRootOfMaxBuildingHeight = Math.sqrt(city.MAX_BUILDING_HEIGHT);

    var multiplierX = squareRootOfMaxBuildingHeight * ((city.HALF_SCENE_WIDTH - Math.abs(x)) / city.HALF_SCENE_WIDTH);
    var multiplierZ = squareRootOfMaxBuildingHeight * ((city.HALF_SCENE_DEPTH - Math.abs(z)) / city.HALF_SCENE_DEPTH);
    var multiplier = Math.min(multiplierX, multiplierZ);

    return multiplier * multiplier;
  };

  var generateBuilding = function(x, maxY, z, lotLayout) {
    var building = new THREE.Mesh(new THREE.BoxGeometry(lotLayout.width * city.BLOCK_WIDTH, 1, lotLayout.depth * city.BLOCK_WIDTH));

    building.position.x = x + city.BLOCK_WIDTH / 2 + ((city.BLOCK_WIDTH / 2) * lotLayout.offsetFromBlockCenterX);
    building.scale.y =  (Math.random() * maxY) + city.MIN_BUILDING_HEIGHT;
    building.position.y = building.scale.y / 2;
    building.position.z = z + city.BLOCK_DEPTH / 2 + ((city.BLOCK_DEPTH / 2) * lotLayout.offsetFromBlockCenterZ);
    building.updateMatrix();

    return building;
  };

  return city;
};
<|endoftext|>


<commit_before>'use strict';

var bind = require('function-bind');
var ES = require('es-abstract/es7');
var slice = bind.call(Function.call, String.prototype.slice);

module.exports = function padLeft(maxLength) {
	var O = ES.RequireObjectCoercible(this);
	var S = ES.ToString(O);
	var stringLength = ES.ToLength(S.length);
	var fillString;
	if (arguments.length > 1) {
		fillString = arguments[1];
	}
	var F = typeof fillString === 'undefined' ? '' : ES.ToString(fillString);
	if (F === '') {
		F = ' ';
	}
	var intMaxLength = ES.ToLength(maxLength);
	if (intMaxLength <= stringLength) {
		return S;
	}
	var fillLen = intMaxLength - stringLength;
	while (F.length < fillLen) {
		var fLen = F.length;
		var remainingCodeUnits = fillLen - fLen;
		F += fLen > remainingCodeUnits ? slice(F, 0, remainingCodeUnits) : F;
	}

	var truncatedStringFiller = F.length > fillLen ? slice(F, 0, fillLen) : F;
	return truncatedStringFiller + S;
};
<commit_msg>Renaming var per https://github.com/tc39/proposal-string-pad-left-right/issues/13#issuecomment-151676376<commit_after>'use strict';

var bind = require('function-bind');
var ES = require('es-abstract/es7');
var slice = bind.call(Function.call, String.prototype.slice);

module.exports = function padLeft(maxLength) {
	var O = ES.RequireObjectCoercible(this);
	var S = ES.ToString(O);
	var stringLength = ES.ToLength(S.length);
	var fillString;
	if (arguments.length > 1) {
		fillString = arguments[1];
	}
	var filler = typeof fillString === 'undefined' ? '' : ES.ToString(fillString);
	if (filler === '') {
		filler = ' ';
	}
	var intMaxLength = ES.ToLength(maxLength);
	if (intMaxLength <= stringLength) {
		return S;
	}
	var fillLen = intMaxLength - stringLength;
	while (filler.length < fillLen) {
		var fLen = filler.length;
		var remainingCodeUnits = fillLen - fLen;
		filler += fLen > remainingCodeUnits ? slice(filler, 0, remainingCodeUnits) : filler;
	}

	var truncatedStringFiller = filler.length > fillLen ? slice(filler, 0, fillLen) : filler;
	return truncatedStringFiller + S;
};
<|endoftext|>


<commit_before>/*jslint node: true*/
"use strict";

var utils = require('../utils');

module.exports = function () {
    return function (irc) {
        irc.nick = function ircNick(nick, network, fn) {
            if (!network) network = '0';
            this.networked_me[network] = this.getUser(nick, network);
            this.me = this.networked_me[network];
            this.write('NICK ' + nick, network, fn);
        };

        irc.getMe = function ircGetMe(network) {
            if (!network) network = '0';
            var res = this.networked_me[network];
            res.client = null;
            utils.emit(irc, network, 'getme', {
              "me": res
            });
            return this.networked_me[network];
        };

        irc.on('data', function (err, msg) {
            var network = msg.network;
            if (msg.command === 'NICK') {
                var user = irc.getUser(utils.nick(msg), network);
                if (!user) user = irc.networked_me[network];
                var oldNick = user.nick;
                user.nick = msg.params;

                if (oldNick === irc.networked_me[network].getNick()) {
                    irc.networked_me[network].nick = user.getNick();
                }

                utils.emit(irc, network, 'nick', {
                    "user": user,
                    "oldNick": oldNick,
                    "tags": msg.tags ? msg.tags : []
                });
            }
            if (msg.command === 'ERR_NICKNAMEINUSE') {
                irc.nick(irc.getUser(undefined, network).getNick() + '_'); // FIXME: what is this
            }
        });
    };
};
<commit_msg>nick.js: check if networked_me exists<commit_after>/*jslint node: true*/
"use strict";

var utils = require('../utils');

module.exports = function () {
    return function (irc) {
        irc.nick = function ircNick(nick, network, fn) {
            if (!network) network = '0';
            this.networked_me[network] = this.getUser(nick, network);
            this.me = this.networked_me[network];
            this.write('NICK ' + nick, network, fn);
        };

        irc.getMe = function ircGetMe(network) {
            if (!network) network = '0';
            var res = this.networked_me[network];
            if (res) res.client = null;
            utils.emit(irc, network, 'getme', {
              "me": res
            });
            return this.networked_me[network];
        };

        irc.on('data', function (err, msg) {
            var network = msg.network;
            if (msg.command === 'NICK') {
                var user = irc.getUser(utils.nick(msg), network);
                if (!user) user = irc.networked_me[network];
                var oldNick = user.nick;
                user.nick = msg.params;

                if (oldNick === irc.networked_me[network].getNick()) {
                    irc.networked_me[network].nick = user.getNick();
                }

                utils.emit(irc, network, 'nick', {
                    "user": user,
                    "oldNick": oldNick,
                    "tags": msg.tags ? msg.tags : []
                });
            }
            if (msg.command === 'ERR_NICKNAMEINUSE') {
                irc.nick(irc.getUser(undefined, network).getNick() + '_'); // FIXME: what is this
            }
        });
    };
};
<|endoftext|>


<commit_before>
/*!
 * Engine - stats
 * Copyright (c) 2010 LearnBoost <dev@learnboost.com>
 * MIT Licensed
 */

/**
 * Module dependencies.
 */

var os = require('os')
  , net = require('net')
  , repl = require('repl');

/**
 * Enable REPL with all arguments passed to `net.Server#listen()`.
 *
 * Examples:
 *
 *    engine(server)
 *      .use(engine.stats())
 *      .use(engine.repl('/var/run/engine'))
 *      .listen();
 *
 * In the terminal:
 *
 *    $ sudo telnet /var/run/engine
 *
 * @return {Function}
 * @api public
 */

exports = module.exports = function(){
  var args = arguments;
  if (!args.length) throw new Error('repl() plugin requires port/host or path');
  return function(master){
    var server;

    // create server
    master.on('start', function(){
      // TCP or unix-domain socket repl
      server = net.createServer(function(sock){
        var ctx = repl.start('engine> ', sock).context;
        master.emit('repl socket', sock);

        // augment socket to provide some formatting methods
        sock.title = function(str){ this.write('\n  \033[36m' + str + '\033[0m\n'); }
        sock.row = function(key, val){ this.write('  \033[90m' + key + ':\033[0m ' + val + '\n'); }

        // merge commands into context
        // executing in context of master
        Object.keys(exports).forEach(function(cmd){
          ctx[cmd] = function(){
            var args = Array.prototype.slice.call(arguments);
            args.unshift(master, sock);
            return exports[cmd].apply(master, args);
          };
        });
      });

      // Apply all arguments given
      server.listen.apply(server, args);
    });

    // close
    master.on('closing', function(){
      server.close();
    });
  }
};

/**
 * Define function `name`, with the given callback
 * `fn(master, sock, ...)` and `description`.
 *
 * @param {String} name
 * @param {Function} fn
 * @param {String} desc
 * @return {Object} exports for chaining
 * @api public
 */

var define = exports.define = function(name, fn, desc){
  (exports[name] = fn).description = desc;
  return exports;
};

/**
 * Display commmand help.
 */

define('help', function(master, sock){
  sock.title('Commands');
  Object.keys(exports).forEach(function(cmd){
    if ('define' == cmd) return;

    var fn = exports[cmd]
      , params = fn.toString().match(/^function +\((.*?)\)/)[1]
      , params = params.split(/ *, */).slice(2);

    sock.row(
      cmd + '(' + params.join(', ') + ')'
      , fn.description);
  });
  sock.write('\n');
}, 'Display help information');

/**
 * Spawn `n` additional workers.
 */

define('spawn', function(master, sock, n){
  n = n || 1;
  sock.write('spawning ' + n + ' worker' + (n > 1 ? 's' : '') + '\n');
  master.spawn(n);
}, 'Spawn one or more additional workers');

/**
 * Output process ids.
 */

define('pids', function(master, sock){
  sock.title('pids');
  sock.row('master', process.pid);
  master.children.forEach(function(worker){
    sock.row('worker #' + worker.id, worker.proc.pid);
  });
  sock.write('\n');
}, 'Output process ids');

/**
 * Kill the given worker by `id` and `signal`.
 */

define('kill', function(master, sock, id, signal){
  var worker = master.children[id];
  if (worker) {
    worker.proc.kill(signal);
    sock.write('sent \033[36m' + (signal || 'SIGTERM') + '\033[0m to worker #' + id + '\n');
  } else {
    sock.write('invalid worker id\n');
  }
}, 'Send signal or SIGTERM to the given worker');
<commit_msg>Added restart() command<commit_after>
/*!
 * Engine - stats
 * Copyright (c) 2010 LearnBoost <dev@learnboost.com>
 * MIT Licensed
 */

/**
 * Module dependencies.
 */

var os = require('os')
  , net = require('net')
  , repl = require('repl');

/**
 * Enable REPL with all arguments passed to `net.Server#listen()`.
 *
 * Examples:
 *
 *    engine(server)
 *      .use(engine.stats())
 *      .use(engine.repl('/var/run/engine'))
 *      .listen();
 *
 * In the terminal:
 *
 *    $ sudo telnet /var/run/engine
 *
 * @return {Function}
 * @api public
 */

exports = module.exports = function(){
  var args = arguments;
  if (!args.length) throw new Error('repl() plugin requires port/host or path');
  return function(master){
    var server;

    // create server
    master.on('start', function(){
      // TCP or unix-domain socket repl
      server = net.createServer(function(sock){
        var ctx = repl.start('engine> ', sock).context;
        master.emit('repl socket', sock);

        // augment socket to provide some formatting methods
        sock.title = function(str){ this.write('\n  \033[36m' + str + '\033[0m\n'); }
        sock.row = function(key, val){ this.write('  \033[90m' + key + ':\033[0m ' + val + '\n'); }

        // merge commands into context
        // executing in context of master
        Object.keys(exports).forEach(function(cmd){
          ctx[cmd] = function(){
            var args = Array.prototype.slice.call(arguments);
            args.unshift(master, sock);
            return exports[cmd].apply(master, args);
          };
        });
      });

      // Apply all arguments given
      server.listen.apply(server, args);
    });

    // close
    master.on('closing', function(){
      server.close();
    });
  }
};

/**
 * Define function `name`, with the given callback
 * `fn(master, sock, ...)` and `description`.
 *
 * @param {String} name
 * @param {Function} fn
 * @param {String} desc
 * @return {Object} exports for chaining
 * @api public
 */

var define = exports.define = function(name, fn, desc){
  (exports[name] = fn).description = desc;
  return exports;
};

/**
 * Display commmand help.
 */

define('help', function(master, sock){
  sock.title('Commands');
  Object.keys(exports).forEach(function(cmd){
    if ('define' == cmd) return;

    var fn = exports[cmd]
      , params = fn.toString().match(/^function +\((.*?)\)/)[1]
      , params = params.split(/ *, */).slice(2);

    sock.row(
      cmd + '(' + params.join(', ') + ')'
      , fn.description);
  });
  sock.write('\n');
}, 'Display help information');

/**
 * Spawn `n` additional workers.
 */

define('spawn', function(master, sock, n){
  n = n || 1;
  sock.write('spawning ' + n + ' worker' + (n > 1 ? 's' : '') + '\n');
  master.spawn(n);
}, 'Spawn one or more additional workers');

/**
 * Output process ids.
 */

define('pids', function(master, sock){
  sock.title('pids');
  sock.row('master', process.pid);
  master.children.forEach(function(worker){
    sock.row('worker #' + worker.id, worker.proc.pid);
  });
  sock.write('\n');
}, 'Output process ids');

/**
 * Kill the given worker by `id` and `signal`.
 */

define('kill', function(master, sock, id, signal){
  var worker = master.children[id];
  if (worker) {
    worker.proc.kill(signal);
    sock.write('sent \033[36m' + (signal || 'SIGTERM') + '\033[0m to worker #' + id + '\n');
  } else {
    sock.write('invalid worker id\n');
  }
}, 'Send signal or SIGTERM to the given worker');

/**
 * Gracefully restart all workers.
 */

define('restart', function(master, sock){
  master.kill('SIGQUIT');
  sock.write('restarting ' + master.children.length + ' workers\n');
}, 'Gracefully restart all workers');<|endoftext|>


<commit_before>var redis = require("redis"),
url = require("url"),
client;

function setUp(app, options) {
  app.get('/priorities', retrieve);
  app.put('/priorities', update);
  app.post('/priorities', update);

    var redisUrl = url.parse(options.url);
    client = redis.createClient(redisUrl.port, redisUrl.hostname);

    client.on('error', function(event) {

      console.log('fail in connect with redis');
      client = undefined;

    });

    if(redisUrl.auth) {
      client.auth(redisUrl.auth.split(":")[1]);
    }

}

function retrieve(req, res) {
  var query = req.query;
  console.log(query.track)
  if(client){
    client.get("priority:" + query.track, function(err, reply) {
      if(err) {
        console.log(err);
      }
      console.log(reply)
      res
      .send({issues: JSON.parse(reply)})
      .status(200);
    });
  }
  else{
    res.send({}).status(503);
  }

}

function update(req, res) {
  var body = req.body;
  console.log(req.body);
  var priorities = body.issues || [];
  if(client){
    client.set("priority:" + body.track, JSON.stringify(priorities));
    res
    .send({})
    .status(201);
  } else {
    res.send({})
    .status(503);
  }
}

module.exports = setUp;<commit_msg>removing console.log in priorization lib<commit_after>var redis = require("redis"),
url = require("url"),
client;

function setUp(app, options) {
  app.get('/priorities', retrieve);
  app.put('/priorities', update);
  app.post('/priorities', update);

    var redisUrl = url.parse(options.url);
    client = redis.createClient(redisUrl.port, redisUrl.hostname);

    client.on('error', function(event) {

      console.log('fail in connect with redis');
      client = undefined;

    });

    if(redisUrl.auth) {
      client.auth(redisUrl.auth.split(":")[1]);
    }

}

function retrieve(req, res) {
  var query = req.query;
  if(client){
    client.get("priority:" + query.track, function(err, reply) {
      if(err) {
        console.log(err);
      }
      res
      .send({issues: JSON.parse(reply)})
      .status(200);
    });
  }
  else{
    res.send({}).status(503);
  }

}

function update(req, res) {
  var body = req.body;
  var priorities = body.issues || [];
  if(client){
    client.set("priority:" + body.track, JSON.stringify(priorities));
    res
    .send({})
    .status(201);
  } else {
    res.send({})
    .status(503);
  }
}

module.exports = setUp;<|endoftext|>


<commit_before>'use strict';

//
// Gist-txt is a minimal text adventure engine that helps game designers to
// create text adventures from GitHub gists.
//
// To create a new text adventure just create a new public gist at
// https://gist.github.com/ with at least a markdown file named
// `index.markdown`. This will be the *main scene*: the starting point of the
// adventure.
//
// Get more info at https://github.com/potomak/gist-txt.
//
var gistId;
var currentScene;
var files;
var cache = {};
var loaded = false;
window.state = {};

var VERSION = require('./package.json').version;
var $ = require('jquery');
var mustache = require('mustache');
var marked = require('marked');
var yfm = require('yfm');
var q = require('q');

var initUI;
var applyStylesheet;
var loadAndRender;
var compileAndDisplayFooter;
var getFileContent;
var extractYFM;
var injectSceneStyle;
var cacheContent;
var renderMustache;
var renderMarkdown;
var outputContent;
var handleInternalLinks;
var runSceneInit;
var runScene;
var parse;
var toggleError;
var toggleLoading;
var isDev;

//
// ## Initialization
//
// During the initialization stage the hash portion of the path get parsed to
// extract two main information:
//
// 1. gist id
// 1. scene name
//
// Using the gist id a GET request to
// https://developer.github.com/v3/gists/#get-a-single-gist is made to get
// gist's data.
//
// If gist id is set to `DEV` the `files` variable is set to an arbitrary value
// and subsequent requests will be sent to the `/dev` path.
//
// A successful response triggers the loading and rendering of the selected
// scene.
//
var init = function () {
  loaded = true;
  var scene = parse(document.location.hash);

  if (isDev()) {
    files = {};
    initUI(scene);
    return;
  }

  return q($.getJSON('https://api.github.com/gists/' + gistId))
    .then(function (gist) {
      files = gist.files;
      return initUI(scene);
    }, function (xhr) {
      toggleLoading(false);
      toggleError(true, xhr.statusText);
    });
};

//
// UI initialization consists of three steps:
//
// 1. global stylesheet application
// 1. loading and rendering of the selected scene
// 1. compilation and display of site footer
//
initUI = function (scene) {
  return applyStylesheet()
    .then(loadAndRender.bind(this, scene))
    .then(compileAndDisplayFooter);
};

//
// If gist's files include a `style.css` its content is used to determine the
// overall CSS style for the story.
//
// The method returns a promise that is always resolved (the stylesheet is
// optional).
//
applyStylesheet = function () {
  var deferred = q.defer();
  if (files['style.css'] !== undefined) {
    q($.get(files['style.css'].raw_url))
      .then(function (content) {
        $('<style>')
          .attr('type', 'text/css')
          .html(content)
          .appendTo('head');
      })
      .fin(deferred.resolve)
  } else {
    deferred.resolve();
  }
  return deferred.promise;
};

//
// ## Loading and rendering scenes
//
// The `cache` object is inspected to retrieve an already compiled scene file,
// otherwise the *load and render* process include:
//
// 1. getting the raw content of the file sending a GET request to file's
//   `raw_url`
// 1. extracting YAML Front Matter and stores scene state in the `state` object
// 1. storing a copy of the Markdown content in the `cache` object
// 1. running a custom `init` function to initialize scene if present
// 1. rendering the Mustache content
// 1. rendering the Markdown content
// 1. output the rendered content to the HTML `div#content` element
//
// The process continues adding `click` handlers to link in the content, to
// handle navigation between scenes.
//
// If everything goes well current scene name is associated to the global
// variable `currentScene`, then previous scene's stylesheet is disactivated and
// current scene's stylesheet is activated.
//
loadAndRender = function (scene) {
  toggleError(false);
  toggleLoading(true);

  var promise;
  if (cache[scene] !== undefined) {
    promise = q.fcall(runSceneInit.bind(this, cache[scene]));
  } else {
    promise = getFileContent(scene)
      .then(extractYFM.bind(this, scene))
      .then(cacheContent.bind(this, scene))
      .then(runSceneInit);
  }

  return promise
    .then(renderMustache)
    .then(renderMarkdown)
    .then(outputContent)
    .then(handleInternalLinks)
    .then(function () {
      $('#' + currentScene + '-style').prop('disabled', true);
      $('#' + scene + '-style').prop('disabled', false);
      currentScene = scene;
    })
    .catch(toggleError.bind(this, true))
    .fin(toggleLoading.bind(this, false));
};

//
// If the gist response is successful the footer gets compiled and displayed to
// show:
//
// * a link to the original gist
// * current version of the engine
//
compileAndDisplayFooter = function () {
  $('a#source')
    .attr('href', 'https://gist.github.com/' + gistId)
    .html(gistId);
  $('span#version').html(VERSION);
  $('footer').show();
};

//
// Every scene is associated with a Markdown gist's file in the form:
//
//     scene + '.markdown'
//
// where `scene` is the name of the scene.
//
// A GET request to file's `raw_url` is made and if successful it resolves the
// deferred object with the result content as argument of the callback.
//
getFileContent = function (scene) {
  var deferred = q.defer();
  var fileName = scene + '.markdown';
  var file = files[fileName];

  if (!isDev() && file === undefined) {
    deferred.reject(new Error('Scene not found'));
    return deferred.promise;
  }

  var fileURL;

  if (isDev()) {
    fileURL = '/dev/' + fileName;
  } else {
    fileURL = file.raw_url;
  }

  q($.get(fileURL))
    .then(deferred.resolve)
    .catch(function (xhr) {
      throw new Error(xhr.statusText);
    });

  return deferred.promise;
};

//
// The YAML Front Matter is extracted from the original content. The resulting
// context is used to extend the global `state`.
//
// If context's `style` property is defined a `<style>` tag with the content of
// the property is injected to override global stylesheet rules.
//
extractYFM = function (scene, content) {
  var parsed = yfm(content);
  $.extend(window.state, parsed.context.state);
  if (parsed.context.style !== undefined) {
    injectSceneStyle(scene, parsed.context.style);
  }
  return parsed;
};

//
// To inject a scene's stylesheet a `<style>` element with the id attribute in
// the form:
//
//     scene + '-style'
//
// get appended into the `<head>` of the HTML document.
//
// Scene stylesheets are disabled on scene transitions and re-enabled on new
// visits of the scene.
//
injectSceneStyle = function (scene, content) {
  $('<style>')
    .attr('id', scene + '-style')
    .attr('type', 'text/css')
    .html(content)
    .appendTo('head');
};

//
// Mustache content is rendered.
//
renderMustache = function (content) {
  return mustache.render(content, window.state);
};

//
// Markdown content is rendered.
//
renderMarkdown = function (content) {
  return marked(content);
};

//
// The HTML rendered content is the main content of the scene. It gets appended
// to the `#content` element in the DOM.
//
// The returning promise fulfills after the `content` string has been inserted
// in the DOM.
//
outputContent = function (content) {
  return q($('#content').html(content).promise());
};

//
// Caching content prevents waste of API calls and band for slow connections.
//
// The cache consists of a simple JavaScript object that contains gist's files
// parsed content indexed by scene name.
//
cacheContent = function (scene, content) {
  cache[scene] = content;
  return content;
};

//
// ## Scene navigation
//
// Internal links click events are overridden to handle navigation between
// scenes of the text adventure.
//
// `<a>` elements' `href` attribute is used to rewrite location's hash in the
// form:
//
//     '#' + gistId + '/' + href
//
// At every internal link click event a new state get pushed in the
// `window.history` object to allow navigation using back and forward buttons.
//
handleInternalLinks = function (contentElement) {
  contentElement.find('a').click(function (event) {
    event.preventDefault();
    var hash = '#' + gistId + '/' + $(this).attr('href');
    runScene(hash);
    window.history.pushState(null, null, document.location.pathname + hash);
  });
};

//
// Run a scene initialization function.
//
runSceneInit = function (parsed) {
  if (parsed.context.init !== undefined) {
    parsed.context.init();
  }
  return parsed.content;
};

//
// A `popstate` event is dispatched to the window every time the active history
// entry changes between two history entries for the same document.
//
// If the `files` array is undefined we need to initialize the text adventure,
// otherwise we can just render the current scene.
//
window.onpopstate = function () {
  if (!loaded) {
    return init();
  }

  if (files !== undefined) {
    runScene(document.location.hash);
  }
};

//
// ## Parsing location hash and running a scene
//
// Running a scene includes:
//
// 1. parsing location's hash to get scene's name
// 1. load and render selected scene
//
runScene = function (hash) {
  var scene = parse(hash);
  loadAndRender(scene);
};

//
// A gist-txt location hash has the form:
//
//     #<gist-id>/<scene>
//
// To parse the hash:
//
// 1. remove the '#' refix
// 1. split the remaining string by '/'
// 1. assign the first *segment* to the global variable `gistId`
// 1. join the remaining segments with '/'
//
// Note: gists' files can't include the '/' character in the name so, even if
// the remaining portion of the segments array is joined by '/', that array
// should always contain at most one element.
//
// If the scene name is blank return 'index', the default name of the main
// scene, otherwise return the scene name found.
//
parse = function (hash) {
  var path = hash.slice(1);
  var segments = path.split('/');
  gistId = segments.shift();
  var scene = segments.join('/');

  if (scene === '') {
    return 'index';
  }

  return scene;
};

//
// `toggleError` and `toggleLoading` help showing error and loading messages.
//
toggleError = function (display, errorMessage) {
  $('#error').html('Error: ' + errorMessage).toggle(display);
};

toggleLoading = function (display) {
  $('#loading').toggle(display);
};

//
// During development you can use the `DEV` special gist id to bypass requests
// to the local development server to the `/dev` path.
//
isDev = function () {
  return gistId === 'DEV';
};

//
// ## It's time to play
//
// Let's play by starting the engine at `document.ready` event.
//
$(init);
<commit_msg>Fix missing semicolon<commit_after>'use strict';

//
// Gist-txt is a minimal text adventure engine that helps game designers to
// create text adventures from GitHub gists.
//
// To create a new text adventure just create a new public gist at
// https://gist.github.com/ with at least a markdown file named
// `index.markdown`. This will be the *main scene*: the starting point of the
// adventure.
//
// Get more info at https://github.com/potomak/gist-txt.
//
var gistId;
var currentScene;
var files;
var cache = {};
var loaded = false;
window.state = {};

var VERSION = require('./package.json').version;
var $ = require('jquery');
var mustache = require('mustache');
var marked = require('marked');
var yfm = require('yfm');
var q = require('q');

var initUI;
var applyStylesheet;
var loadAndRender;
var compileAndDisplayFooter;
var getFileContent;
var extractYFM;
var injectSceneStyle;
var cacheContent;
var renderMustache;
var renderMarkdown;
var outputContent;
var handleInternalLinks;
var runSceneInit;
var runScene;
var parse;
var toggleError;
var toggleLoading;
var isDev;

//
// ## Initialization
//
// During the initialization stage the hash portion of the path get parsed to
// extract two main information:
//
// 1. gist id
// 1. scene name
//
// Using the gist id a GET request to
// https://developer.github.com/v3/gists/#get-a-single-gist is made to get
// gist's data.
//
// If gist id is set to `DEV` the `files` variable is set to an arbitrary value
// and subsequent requests will be sent to the `/dev` path.
//
// A successful response triggers the loading and rendering of the selected
// scene.
//
var init = function () {
  loaded = true;
  var scene = parse(document.location.hash);

  if (isDev()) {
    files = {};
    initUI(scene);
    return;
  }

  return q($.getJSON('https://api.github.com/gists/' + gistId))
    .then(function (gist) {
      files = gist.files;
      return initUI(scene);
    }, function (xhr) {
      toggleLoading(false);
      toggleError(true, xhr.statusText);
    });
};

//
// UI initialization consists of three steps:
//
// 1. global stylesheet application
// 1. loading and rendering of the selected scene
// 1. compilation and display of site footer
//
initUI = function (scene) {
  return applyStylesheet()
    .then(loadAndRender.bind(this, scene))
    .then(compileAndDisplayFooter);
};

//
// If gist's files include a `style.css` its content is used to determine the
// overall CSS style for the story.
//
// The method returns a promise that is always resolved (the stylesheet is
// optional).
//
applyStylesheet = function () {
  var deferred = q.defer();
  if (files['style.css'] !== undefined) {
    q($.get(files['style.css'].raw_url))
      .then(function (content) {
        $('<style>')
          .attr('type', 'text/css')
          .html(content)
          .appendTo('head');
      })
      .fin(deferred.resolve);
  } else {
    deferred.resolve();
  }
  return deferred.promise;
};

//
// ## Loading and rendering scenes
//
// The `cache` object is inspected to retrieve an already compiled scene file,
// otherwise the *load and render* process include:
//
// 1. getting the raw content of the file sending a GET request to file's
//   `raw_url`
// 1. extracting YAML Front Matter and stores scene state in the `state` object
// 1. storing a copy of the Markdown content in the `cache` object
// 1. running a custom `init` function to initialize scene if present
// 1. rendering the Mustache content
// 1. rendering the Markdown content
// 1. output the rendered content to the HTML `div#content` element
//
// The process continues adding `click` handlers to link in the content, to
// handle navigation between scenes.
//
// If everything goes well current scene name is associated to the global
// variable `currentScene`, then previous scene's stylesheet is disactivated and
// current scene's stylesheet is activated.
//
loadAndRender = function (scene) {
  toggleError(false);
  toggleLoading(true);

  var promise;
  if (cache[scene] !== undefined) {
    promise = q.fcall(runSceneInit.bind(this, cache[scene]));
  } else {
    promise = getFileContent(scene)
      .then(extractYFM.bind(this, scene))
      .then(cacheContent.bind(this, scene))
      .then(runSceneInit);
  }

  return promise
    .then(renderMustache)
    .then(renderMarkdown)
    .then(outputContent)
    .then(handleInternalLinks)
    .then(function () {
      $('#' + currentScene + '-style').prop('disabled', true);
      $('#' + scene + '-style').prop('disabled', false);
      currentScene = scene;
    })
    .catch(toggleError.bind(this, true))
    .fin(toggleLoading.bind(this, false));
};

//
// If the gist response is successful the footer gets compiled and displayed to
// show:
//
// * a link to the original gist
// * current version of the engine
//
compileAndDisplayFooter = function () {
  $('a#source')
    .attr('href', 'https://gist.github.com/' + gistId)
    .html(gistId);
  $('span#version').html(VERSION);
  $('footer').show();
};

//
// Every scene is associated with a Markdown gist's file in the form:
//
//     scene + '.markdown'
//
// where `scene` is the name of the scene.
//
// A GET request to file's `raw_url` is made and if successful it resolves the
// deferred object with the result content as argument of the callback.
//
getFileContent = function (scene) {
  var deferred = q.defer();
  var fileName = scene + '.markdown';
  var file = files[fileName];

  if (!isDev() && file === undefined) {
    deferred.reject(new Error('Scene not found'));
    return deferred.promise;
  }

  var fileURL;

  if (isDev()) {
    fileURL = '/dev/' + fileName;
  } else {
    fileURL = file.raw_url;
  }

  q($.get(fileURL))
    .then(deferred.resolve)
    .catch(function (xhr) {
      throw new Error(xhr.statusText);
    });

  return deferred.promise;
};

//
// The YAML Front Matter is extracted from the original content. The resulting
// context is used to extend the global `state`.
//
// If context's `style` property is defined a `<style>` tag with the content of
// the property is injected to override global stylesheet rules.
//
extractYFM = function (scene, content) {
  var parsed = yfm(content);
  $.extend(window.state, parsed.context.state);
  if (parsed.context.style !== undefined) {
    injectSceneStyle(scene, parsed.context.style);
  }
  return parsed;
};

//
// To inject a scene's stylesheet a `<style>` element with the id attribute in
// the form:
//
//     scene + '-style'
//
// get appended into the `<head>` of the HTML document.
//
// Scene stylesheets are disabled on scene transitions and re-enabled on new
// visits of the scene.
//
injectSceneStyle = function (scene, content) {
  $('<style>')
    .attr('id', scene + '-style')
    .attr('type', 'text/css')
    .html(content)
    .appendTo('head');
};

//
// Mustache content is rendered.
//
renderMustache = function (content) {
  return mustache.render(content, window.state);
};

//
// Markdown content is rendered.
//
renderMarkdown = function (content) {
  return marked(content);
};

//
// The HTML rendered content is the main content of the scene. It gets appended
// to the `#content` element in the DOM.
//
// The returning promise fulfills after the `content` string has been inserted
// in the DOM.
//
outputContent = function (content) {
  return q($('#content').html(content).promise());
};

//
// Caching content prevents waste of API calls and band for slow connections.
//
// The cache consists of a simple JavaScript object that contains gist's files
// parsed content indexed by scene name.
//
cacheContent = function (scene, content) {
  cache[scene] = content;
  return content;
};

//
// ## Scene navigation
//
// Internal links click events are overridden to handle navigation between
// scenes of the text adventure.
//
// `<a>` elements' `href` attribute is used to rewrite location's hash in the
// form:
//
//     '#' + gistId + '/' + href
//
// At every internal link click event a new state get pushed in the
// `window.history` object to allow navigation using back and forward buttons.
//
handleInternalLinks = function (contentElement) {
  contentElement.find('a').click(function (event) {
    event.preventDefault();
    var hash = '#' + gistId + '/' + $(this).attr('href');
    runScene(hash);
    window.history.pushState(null, null, document.location.pathname + hash);
  });
};

//
// Run a scene initialization function.
//
runSceneInit = function (parsed) {
  if (parsed.context.init !== undefined) {
    parsed.context.init();
  }
  return parsed.content;
};

//
// A `popstate` event is dispatched to the window every time the active history
// entry changes between two history entries for the same document.
//
// If the `files` array is undefined we need to initialize the text adventure,
// otherwise we can just render the current scene.
//
window.onpopstate = function () {
  if (!loaded) {
    return init();
  }

  if (files !== undefined) {
    runScene(document.location.hash);
  }
};

//
// ## Parsing location hash and running a scene
//
// Running a scene includes:
//
// 1. parsing location's hash to get scene's name
// 1. load and render selected scene
//
runScene = function (hash) {
  var scene = parse(hash);
  loadAndRender(scene);
};

//
// A gist-txt location hash has the form:
//
//     #<gist-id>/<scene>
//
// To parse the hash:
//
// 1. remove the '#' refix
// 1. split the remaining string by '/'
// 1. assign the first *segment* to the global variable `gistId`
// 1. join the remaining segments with '/'
//
// Note: gists' files can't include the '/' character in the name so, even if
// the remaining portion of the segments array is joined by '/', that array
// should always contain at most one element.
//
// If the scene name is blank return 'index', the default name of the main
// scene, otherwise return the scene name found.
//
parse = function (hash) {
  var path = hash.slice(1);
  var segments = path.split('/');
  gistId = segments.shift();
  var scene = segments.join('/');

  if (scene === '') {
    return 'index';
  }

  return scene;
};

//
// `toggleError` and `toggleLoading` help showing error and loading messages.
//
toggleError = function (display, errorMessage) {
  $('#error').html('Error: ' + errorMessage).toggle(display);
};

toggleLoading = function (display) {
  $('#loading').toggle(display);
};

//
// During development you can use the `DEV` special gist id to bypass requests
// to the local development server to the `/dev` path.
//
isDev = function () {
  return gistId === 'DEV';
};

//
// ## It's time to play
//
// Let's play by starting the engine at `document.ready` event.
//
$(init);
<|endoftext|>


<commit_before>'use strict'
var Property = require('./')
var remove = function (val, event) {
  var removed
  this.each(function () {}, function (property) {
    if (property instanceof Property) {
      if (property.parseValue() === val) {
        property.remove()
        removed = true
      }
    }
  })
  if (this.parseValue() === val) {
    this.set('', event)
    removed = true
  }
  return removed
}

exports.properties = {
  css: new Property({
    ChildConstructor: Property,
    render (node, event, element) {
      let key = element.key
      let val = this.parseValue()
      let str = typeof val === 'string' ? val : ''
      if (key) {
        str = key + ' ' + str
      }
      this.each(function () {}, function (property) {
        if (property instanceof Property) {
          let val = property.parseValue()
          if (typeof val === 'string') {
            str += ' ' + val
          }
        }
      })
      node.className = str
    },
    properties: {
      add (val, event) {
        var exists = this.each(function () {}, function (property) {
          if (property instanceof Property) {
            if (property.parseValue() === val) {
              return true
            }
          }
        })
        if (!exists) {
          let cnt = 0
          while (this[cnt]) {
            cnt += 1
          }
          this.setKey(cnt, val)
        }
      },
      remove,
      toggle (val, event) {
        if (!remove.call(this, val, event)) {
          let cnt = 0
          while (this[cnt]) {
            cnt += 1
          }
          this.setKey(cnt, val, event)
        }
        let element = this.parent
        let node = element.getNode()
        if (node) {
          this.render(node, event, element)
        }
      }
    }
  }).Constructor
}
<commit_msg>css cache<commit_after>'use strict'
var Property = require('./')
var render = function (self, event) {
  let element = self.parent
  let node = element.getNode()
  if (node) {
    element._csscache = null
    self.render(node, event, element)
  }
}
var remove = function (val, event) {
  var removed
  this.each(function () {}, function (property) {
    if (property instanceof Property) {
      if (property.parseValue() === val) {
        property.remove()
        removed = true
      }
    }
  })
  if (this.parseValue() === val) {
    this.set('', event)
    removed = true
  }
  return removed
}

exports.properties = {
  css: new Property({
    ChildConstructor: new Property({
      render (node, event, css) {
        css._parent._csscache = null
      }
    }),
    render (node, event, element) {
      if (element._csscache) {
        node.className = element._csscache
      } else {
        let key = element.key
        let val = this.parseValue()
        let str = typeof val === 'string' ? val : ''
        if (key) {
          str = key + ' ' + str
        }
        this.each(function () {}, function (property) {
          if (property instanceof Property) {
            let val = property.parseValue()
            if (typeof val === 'string') {
              str += ' ' + val
            }
          }
        })
        node.className = str
        element._csscache = str
      }
    },
    properties: {
      add (val, event) {
        var exists = this.each(function () {}, function (property) {
          if (property instanceof Property) {
            if (property.parseValue() === val) {
              return true
            }
          }
        })
        if (!exists) {
          let cnt = 0
          while (this[cnt]) {
            cnt += 1
          }
          this.setKey(cnt, val)
          render(this, event)
        }
      },
      remove (node, event) {
        if (remove.apply(this, arguments)) {
          render(this, event)
        }
      },
      toggle (val, event) {
        if (!remove.call(this, val, event)) {
          let cnt = 0
          while (this[cnt]) {
            cnt += 1
          }
          this.setKey(cnt, val, event)
        }
        render(this, event)
      }
    }
  }).Constructor
}
<|endoftext|>