<commit_before>//deletes all references to a document from the search index

var docGetter = require('../mapreduce/docGetter.js');
var indexPeek = require('./indexPeek.js');

function decrementRIArray(docID, indexesMultiply, indexes, keys, callback) {
  var decrementKeys = [];
  indexesMultiply.get(keys, function(err, data) {
    for (var k in data) {
      var batchOperation = {};
      if (data[k] == null) {/*ghost key- do nothing*/}
//      console.log(data[k]);
      for (var j = 0; j < data[k].length; j++) {
        if (data[k][j][1] == docID) {
          if (data[k].length > 1) {
            data[k].splice(j, 1);
            batchOperation['type'] = 'put';
            batchOperation['key'] = k;
            batchOperation['value'] = data[k];
          }
          else {
            batchOperation['type'] = 'del';
            batchOperation['key'] = k;
          }
        }
      }
      decrementKeys.push(batchOperation);
    }
    indexes.batch(decrementKeys, function (err) {
      callback('[success] index recalibrated');
    })
  })
}

//recalibrate index after deleting all artifacts (remove or decrement TF entries)
function decrementTFArray(docID, indexesMultiply, indexes, keys, callback) {
  Array.prototype.removeEl = function() {
    var what, a = arguments, L = a.length, ax;
    while (L && this.length) {
      what = a[--L];
      while ((ax = this.indexOf(what)) !== -1) {
        this.splice(ax, 1);
      }
    }
    return this;
  };
  indexesMultiply.get(keys, function(err, data) {
    var decrementKeys = [];
    for (var k in data) {
      var batchOperation = {};
      if (data[k] == null) {/*ghost key- do nothing*/}
      else if (data[k].length > 1) {
        batchOperation['type'] = 'put';
        batchOperation['key'] = k;
        //Making sure the docID is handled as a string
        batchOperation['value'] = data[k].removeEl(docID + '');
      }
      else {
        batchOperation['type'] = 'del';
        batchOperation['key'] = k;
      }
      decrementKeys.push(batchOperation);
    }
    indexes.batch(decrementKeys, function (err) {
      if (err) console.log('AAAAARGH')
      else
        callback('[success] index recalibrated');
    })
  })
}

function deleteArtifacts(docID, indexes, indexesMultiply, callback) {
  //use docGetter to find out which artifacts must be removed
  docGetter.getDoc(indexes, indexesMultiply, docID, function(err, docArtifacts) {
    //remove all artifacts
    var deleteKeys = Object.keys(docArtifacts);
    var deleteIDsFromTheseArrayKeys = [];
    for (var k in docArtifacts) {
      deleteIDsFromTheseArrayKeys = deleteIDsFromTheseArrayKeys.concat(docArtifacts[k]);
    }
    var deleteIDsFromTheseTFArrayKeys = [];
    for (var i = 0; i < deleteIDsFromTheseArrayKeys.length; i++)
      deleteIDsFromTheseTFArrayKeys[i] = 'TF~' + deleteIDsFromTheseArrayKeys[i];
    var deleteIDsFromTheseRIArrayKeys = [];
    for (var i = 0; i < deleteIDsFromTheseArrayKeys.length; i++)
      deleteIDsFromTheseRIArrayKeys[i] = 'RI~' + deleteIDsFromTheseArrayKeys[i];
    decrementTFArray(docID, indexesMultiply, indexes, deleteIDsFromTheseTFArrayKeys, function(err){
      decrementRIArray(docID, indexesMultiply, indexes, deleteIDsFromTheseRIArrayKeys, function(err){
        indexesMultiply.del(deleteKeys, function (err, data) {
          // database no longer has 'foo', 'boom' or 'whoa' ('wha' was never there)
          callback(false);
        })
      });
    });
//    console.log(deleteIDsFromTheseArrayKeys);
  });
}

exports.doesDocExist = function(docID, indexes, callback) {
  var testKey = 'DOCUMENT~' + docID + '~';
  indexPeek.indexValue(testKey, indexes, function(msg){
//    console.log(msg);
    if (msg == '[warning] key not found') return callback(false);
    return callback(true);
  });
}

exports.deleteDoc = function(docID, indexes, indexesMultiply, callback) {
  this.doesDocExist(docID, indexes, function(docExists){
    if (docExists) {
      deleteArtifacts(docID, indexes, indexesMultiply, function(msg) {
        return callback(true);
      });
    }
    else {
      return callback({'notFound': docID + ' cannot be deleted because it is not in index'});
    }
  });
}
<commit_msg>prototype was causing weirdness in search, changing back to function<commit_after>//deletes all references to a document from the search index

var docGetter = require('../mapreduce/docGetter.js');
var indexPeek = require('./indexPeek.js');

function decrementRIArray(docID, indexesMultiply, indexes, keys, callback) {
  var decrementKeys = [];
  indexesMultiply.get(keys, function(err, data) {
    for (var k in data) {
      var batchOperation = {};
      if (data[k] == null) {/*ghost key- do nothing*/}
//      console.log(data[k]);
      for (var j = 0; j < data[k].length; j++) {
        if (data[k][j][1] == docID) {
          if (data[k].length > 1) {
            data[k].splice(j, 1);
            batchOperation['type'] = 'put';
            batchOperation['key'] = k;
            batchOperation['value'] = data[k];
          }
          else {
            batchOperation['type'] = 'del';
            batchOperation['key'] = k;
          }
        }
      }
      decrementKeys.push(batchOperation);
    }
    indexes.batch(decrementKeys, function (err) {
      callback('[success] index recalibrated');
    })
  })
}

//recalibrate index after deleting all artifacts (remove or decrement TF entries)
function decrementTFArray(docID, indexesMultiply, indexes, keys, callback) {
  function removeA(arr) {
    var what, a = arguments, L = a.length, ax;
    while (L > 1 && arr.length) {
      what = a[--L];
      while ((ax= arr.indexOf(what)) !== -1) {
        arr.splice(ax, 1);
      }
    }
    return arr;
  }

  indexesMultiply.get(keys, function(err, data) {
    var decrementKeys = [];
    for (var k in data) {
      var batchOperation = {};
      if (data[k] == null) {/*ghost key- do nothing*/}
      else if (data[k].length > 1) {
        batchOperation['type'] = 'put';
        batchOperation['key'] = k;
        //Making sure the docID is handled as a string
        batchOperation['value'] = removeA(data[k], docID + '');
      }
      else {
        batchOperation['type'] = 'del';
        batchOperation['key'] = k;
      }
      decrementKeys.push(batchOperation);
    }
    indexes.batch(decrementKeys, function (err) {
      if (err) console.log('AAAAARGH')
      else
        callback('[success] index recalibrated');
    })
  })
}

function deleteArtifacts(docID, indexes, indexesMultiply, callback) {
  //use docGetter to find out which artifacts must be removed
  docGetter.getDoc(indexes, indexesMultiply, docID, function(err, docArtifacts) {
    //remove all artifacts
    var deleteKeys = Object.keys(docArtifacts);
    var deleteIDsFromTheseArrayKeys = [];
    for (var k in docArtifacts) {
      deleteIDsFromTheseArrayKeys = deleteIDsFromTheseArrayKeys.concat(docArtifacts[k]);
    }
    var deleteIDsFromTheseTFArrayKeys = [];
    for (var i = 0; i < deleteIDsFromTheseArrayKeys.length; i++)
      deleteIDsFromTheseTFArrayKeys[i] = 'TF~' + deleteIDsFromTheseArrayKeys[i];
    var deleteIDsFromTheseRIArrayKeys = [];
    for (var i = 0; i < deleteIDsFromTheseArrayKeys.length; i++)
      deleteIDsFromTheseRIArrayKeys[i] = 'RI~' + deleteIDsFromTheseArrayKeys[i];
    decrementTFArray(docID, indexesMultiply, indexes, deleteIDsFromTheseTFArrayKeys, function(err){
      decrementRIArray(docID, indexesMultiply, indexes, deleteIDsFromTheseRIArrayKeys, function(err){
        indexesMultiply.del(deleteKeys, function (err, data) {
          // database no longer has 'foo', 'boom' or 'whoa' ('wha' was never there)
          callback(false);
        })
      });
    });
//    console.log(deleteIDsFromTheseArrayKeys);
  });
}

exports.doesDocExist = function(docID, indexes, callback) {
  var testKey = 'DOCUMENT~' + docID + '~';
  indexPeek.indexValue(testKey, indexes, function(msg){
//    console.log(msg);
    if (msg == '[warning] key not found') return callback(false);
    return callback(true);
  });
}

exports.deleteDoc = function(docID, indexes, indexesMultiply, callback) {
  this.doesDocExist(docID, indexes, function(docExists){
    if (docExists) {
      deleteArtifacts(docID, indexes, indexesMultiply, function(msg) {
        return callback(true);
      });
    }
    else {
      return callback({'notFound': docID + ' cannot be deleted because it is not in index'});
    }
  });
}
<|endoftext|>


<commit_before>'use strict';

import core from 'bower:metal/src/core';
import Ajax from 'bower:metal-ajax/src/Ajax';
import MultiMap from 'bower:metal-multimap/src/MultiMap';
import CancellablePromise from 'bower:metal-promise/src/promise/Promise';
import Screen from './Screen';

class RequestScreen extends Screen {

	/**
	 * Request screen abstract class to perform io operations on descendant
	 * screens.
	 * @constructor
	 * @extends {Screen}
	 */
	constructor() {
		super();

		/**
		 * @inheritDoc
		 * @default true
		 */
		this.cacheable = true;

		/**
		 * Holds default http headers to set on request.
		 * @type {?Object=}
		 * @default {
		 *   'X-PJAX': 'true',
		 *   'X-Requested-With': 'XMLHttpRequest'
		 * }
		 * @protected
		 */
		this.httpHeaders = {
			'X-PJAX': 'true',
			'X-Requested-With': 'XMLHttpRequest'
		};

		/**
		 * Holds default http method to perform the request.
		 * @type {!string}
		 * @default RequestScreen.GET
		 * @protected
		 */
		this.httpMethod = RequestScreen.GET;

		/**
		 * Holds the XHR object responsible for the request.
		 * @type {XMLHttpRequest}
		 * @default null
		 * @protected
		 */
		this.request = null;

		/**
		 * Holds the request timeout in milliseconds.
		 * @type {!number}
		 * @default 30000
		 * @protected
		 */
		this.timeout = 30000;
	}

	/**
	 * Gets the http headers.
	 * @return {?Object=}
	 */
	getHttpHeaders() {
		return this.httpHeaders;
	}

	/**
	 * Gets the http method.
	 * @return {!string}
	 */
	getHttpMethod() {
		return this.httpMethod;
	}

	/**
	 * Gets the request object.
	 * @return {?Object}
	 */
	getRequest() {
		return this.request;
	}

	/**
	 * Gets the request timeout.
	 * @return {!number}
	 */
	getTimeout() {
		return this.timeout;
	}

	/**
	 * @inheritDoc
	 */
	load(path) {
		var cache = this.getCache();
		if (core.isDefAndNotNull(cache)) {
			return CancellablePromise.resolve(cache);
		}

		var headers = new MultiMap();

		Object.keys(this.httpHeaders).forEach(header => headers.add(header, this.httpHeaders[header]));

		return Ajax
			.request(path, this.httpMethod, null, headers, null, this.timeout)
			.then(xhr => {
				this.setRequest(xhr);
				if (this.isCacheable()) {
					this.addCache(xhr.responseText);
				}
				return xhr.responseText;
			});
	}

	/**
	 * Sets the http headers.
	 * @param {?Object=} httpHeaders
	 */
	setHttpHeaders(httpHeaders) {
		this.httpHeaders = httpHeaders;
	}

	/**
	 * Sets the http method.
	 * @param {!string} httpMethod
	 */
	setHttpMethod(httpMethod) {
		this.httpMethod = httpMethod.toLowerCase();
	}

	/**
	 * Sets the request object.
	 * @param {?Object} request
	 */
	setRequest(request) {
		this.request = request;
	}

	/**
	 * Sets the request timeout in milliseconds.
	 * @param {!number} timeout
	 */
	setTimeout(timeout) {
		this.timeout = timeout;
	}

}

/**
 * Holds value for method get.
 * @type {string}
 * @default 'get'
 * @static
 */
RequestScreen.GET = 'get';

/**
 * Holds value for method post.
 * @type {string}
 * @default 'post'
 * @static
 */
RequestScreen.POST = 'post';

export default RequestScreen;<commit_msg>RequestScreen should only cache GET requests<commit_after>'use strict';

import core from 'bower:metal/src/core';
import Ajax from 'bower:metal-ajax/src/Ajax';
import MultiMap from 'bower:metal-multimap/src/MultiMap';
import CancellablePromise from 'bower:metal-promise/src/promise/Promise';
import Screen from './Screen';

class RequestScreen extends Screen {

	/**
	 * Request screen abstract class to perform io operations on descendant
	 * screens.
	 * @constructor
	 * @extends {Screen}
	 */
	constructor() {
		super();

		/**
		 * @inheritDoc
		 * @default true
		 */
		this.cacheable = true;

		/**
		 * Holds default http headers to set on request.
		 * @type {?Object=}
		 * @default {
		 *   'X-PJAX': 'true',
		 *   'X-Requested-With': 'XMLHttpRequest'
		 * }
		 * @protected
		 */
		this.httpHeaders = {
			'X-PJAX': 'true',
			'X-Requested-With': 'XMLHttpRequest'
		};

		/**
		 * Holds default http method to perform the request.
		 * @type {!string}
		 * @default RequestScreen.GET
		 * @protected
		 */
		this.httpMethod = RequestScreen.GET;

		/**
		 * Holds the XHR object responsible for the request.
		 * @type {XMLHttpRequest}
		 * @default null
		 * @protected
		 */
		this.request = null;

		/**
		 * Holds the request timeout in milliseconds.
		 * @type {!number}
		 * @default 30000
		 * @protected
		 */
		this.timeout = 30000;
	}

	/**
	 * Gets the http headers.
	 * @return {?Object=}
	 */
	getHttpHeaders() {
		return this.httpHeaders;
	}

	/**
	 * Gets the http method.
	 * @return {!string}
	 */
	getHttpMethod() {
		return this.httpMethod;
	}

	/**
	 * Gets the request object.
	 * @return {?Object}
	 */
	getRequest() {
		return this.request;
	}

	/**
	 * Gets the request timeout.
	 * @return {!number}
	 */
	getTimeout() {
		return this.timeout;
	}

	/**
	 * @inheritDoc
	 */
	load(path) {
		var cache = this.getCache();
		if (core.isDefAndNotNull(cache)) {
			return CancellablePromise.resolve(cache);
		}

		var httpMethod = this.httpMethod;
		var headers = new MultiMap();

		Object.keys(this.httpHeaders).forEach(header => headers.add(header, this.httpHeaders[header]));

		return Ajax
			.request(path, this.httpMethod, null, headers, null, this.timeout)
			.then(xhr => {
				this.setRequest(xhr);
				if (httpMethod === RequestScreen.GET && this.isCacheable()) {
					this.addCache(xhr.responseText);
				}
				return xhr.responseText;
			});
	}

	/**
	 * Sets the http headers.
	 * @param {?Object=} httpHeaders
	 */
	setHttpHeaders(httpHeaders) {
		this.httpHeaders = httpHeaders;
	}

	/**
	 * Sets the http method.
	 * @param {!string} httpMethod
	 */
	setHttpMethod(httpMethod) {
		this.httpMethod = httpMethod.toLowerCase();
	}

	/**
	 * Sets the request object.
	 * @param {?Object} request
	 */
	setRequest(request) {
		this.request = request;
	}

	/**
	 * Sets the request timeout in milliseconds.
	 * @param {!number} timeout
	 */
	setTimeout(timeout) {
		this.timeout = timeout;
	}

}

/**
 * Holds value for method get.
 * @type {string}
 * @default 'get'
 * @static
 */
RequestScreen.GET = 'get';

/**
 * Holds value for method post.
 * @type {string}
 * @default 'post'
 * @static
 */
RequestScreen.POST = 'post';

export default RequestScreen;<|endoftext|>


<commit_before>"use strict";

/*global nodeca, _*/

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

// 3rd-party
var Mincer      = require('mincer');
var UglifyJS    = require('uglify-js');
var Csso        = require('csso');
var connect     = require('connect');
var nib         = require('nib');

// NLib
var HashTree    = require('nlib').Support.HashTree;

function needs_compilation(logicalPath, tests) {
  return _.any(tests, function (test) {
    if (_.isString(test)) {
      return test === logicalPath;
    }

    if (_.isRegExp(test)) {
      return test.test(logicalPath);
    }

    if (_.isFunction(test)) {
      return test(logicalPath);
    }

    return false;
  });
}

function get_compilable(files, env) {
  var result = [];

  env.eachLogicalPath(function (logicalPath) {
    if (needs_compilation(logicalPath, files)) {
      result.push(logicalPath);
    }
  });

  return result;
}

module.exports = function (next) {
  var files, env, manifest, assets_root;

  assets_root = path.resolve(__dirname, '../../public/assets');
  env         = new Mincer.Environment(nodeca.runtime.assets_path);
  manifest    = new Mincer.Manifest(env, assets_root);
  files       = ['app.js', 'app.css', 'modernizr.custom.js'];

  // function that mathces any non-js or non-css files
  files.push(function nonAsset(logicalPath) {
    var extname = path.extname(logicalPath);
    return (!/\.(js|css)$/.test(extname));
  });

  // Provide some helpers to EJS and Stylus
  env.registerHelper({
    asset_path: function (pathname) {
      var asset = this.environment.findAsset(pathname);
      return asset ? ("/assets/" + asset.digestPath) : null;
    },
    version: function () {
      return nodeca.runtime.version;
    },
    env: function () {
      return nodeca.runtime.env;
    },
    config: function (part) {
      return !part ? nodeca.config : HashTree.get(nodeca.config, part);
    }
  });

  // Add some funky stuff to Stylus
  Mincer.StylusEngine.registerConfigurator(function (style) {
    style.use(nib());
  });

  // fill in paths
  env.appendPath('assets/css');
  env.appendPath('assets/embedded_fonts');
  env.appendPath('assets/img');
  env.appendPath('assets/js');
  env.appendPath('assets/vendor');
  env.appendPath('system');

  // init JS compressor for non-dev setups only
  if ('development' !== nodeca.runtime.env) {
    env.jsCompressor = function (data, callback) {
      try {
        var ast = UglifyJS.parser.parse(data);

        ast = UglifyJS.uglify.ast_mangle(ast);
        ast = UglifyJS.uglify.ast_squeeze(ast);

        callback(null, UglifyJS.uglify.gen_code(ast));
      } catch (err) {
        callback(err);
      }
    };

    env.cssCompressor = function (data, callback) {
      try {
        callback(null, Csso.justDoIt(data));
      } catch (err) {
        callback(err);
      }
    };
  }

  // compile manifest
  manifest.compile(get_compilable(files, env), function (err, data) {
    if (err) {
      next(err);
      return;
    }

    nodeca.runtime.assets_mincer    = env;
    nodeca.runtime.assets_server    = Mincer.createServer(env, data);

    next();
  });
};
<commit_msg>Fix assets compile collector<commit_after>"use strict";

/*global nodeca, _*/

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

// 3rd-party
var Mincer      = require('mincer');
var UglifyJS    = require('uglify-js');
var Csso        = require('csso');
var connect     = require('connect');
var nib         = require('nib');

// NLib
var HashTree    = require('nlib').Support.HashTree;

function get_compilable(filters, env) {
  var result = [];

  env.eachLogicalPath(filters, function (logicalPath) {
    result.push(logicalPath);
  });

  return result;
}

module.exports = function (next) {
  var files, env, manifest, assets_root;

  assets_root = path.resolve(__dirname, '../../public/assets');
  env         = new Mincer.Environment(nodeca.runtime.assets_path);
  manifest    = new Mincer.Manifest(env, assets_root);
  files       = ['app.js', 'app.css', 'modernizr.custom.js'];

  // function that mathces any non-js or non-css files
  files.push(function nonAsset(logicalPath) {
    var extname = path.extname(logicalPath);
    return (!/\.(js|css)$/.test(extname));
  });

  // Provide some helpers to EJS and Stylus
  env.registerHelper({
    asset_path: function (pathname) {
      var asset = this.environment.findAsset(pathname);
      return asset ? ("/assets/" + asset.digestPath) : null;
    },
    version: function () {
      return nodeca.runtime.version;
    },
    env: function () {
      return nodeca.runtime.env;
    },
    config: function (part) {
      return !part ? nodeca.config : HashTree.get(nodeca.config, part);
    }
  });

  // Add some funky stuff to Stylus
  Mincer.StylusEngine.registerConfigurator(function (style) {
    style.use(nib());
  });

  // fill in paths
  env.appendPath('assets/css');
  env.appendPath('assets/embedded_fonts');
  env.appendPath('assets/img');
  env.appendPath('assets/js');
  env.appendPath('assets/vendor');
  env.appendPath('system');

  // init JS compressor for non-dev setups only
  if ('development' !== nodeca.runtime.env) {
    env.jsCompressor = function (data, callback) {
      try {
        var ast = UglifyJS.parser.parse(data);

        ast = UglifyJS.uglify.ast_mangle(ast);
        ast = UglifyJS.uglify.ast_squeeze(ast);

        callback(null, UglifyJS.uglify.gen_code(ast));
      } catch (err) {
        callback(err);
      }
    };

    env.cssCompressor = function (data, callback) {
      try {
        callback(null, Csso.justDoIt(data));
      } catch (err) {
        callback(err);
      }
    };
  }

  Mincer.logger.use(console);

  // compile manifest
  manifest.compile(get_compilable(files, env), function (err, data) {
    if (err) {
      next(err);
      return;
    }

    nodeca.runtime.assets_mincer    = env;
    nodeca.runtime.assets_server    = Mincer.createServer(env, data);

    next();
  });
};
<|endoftext|>


<commit_before>import hbs from 'htmlbars-inline-precompile';
import {click, find, render, settled, waitFor} from '@ember/test-helpers';
import {defineProperty} from '@ember/object';
import {describe, it} from 'mocha';
import {expect} from 'chai';
import {run} from '@ember/runloop';
import {setupRenderingTest} from 'ember-mocha';
import {task, timeout} from 'ember-concurrency';

describe('Integration: Component: gh-task-button', function () {
    setupRenderingTest();

    it('renders', async function () {
        // sets button text using positional param
        await render(hbs`{{gh-task-button "Test"}}`);
        expect(find('button')).to.exist;
        expect(find('button')).to.contain.text('Test');
        expect(find('button').disabled).to.be.false;

        await render(hbs`{{gh-task-button class="testing"}}`);
        expect(find('button')).to.have.class('testing');
        // default button text is "Save"
        expect(find('button')).to.contain.text('Save');

        // passes disabled attr
        await render(hbs`{{gh-task-button disabled=true buttonText="Test"}}`);
        expect(find('button').disabled).to.be.true;
        // allows button text to be set via hash param
        expect(find('button')).to.contain.text('Test');

        // passes type attr
        await render(hbs`{{gh-task-button type="submit"}}`);
        expect(find('button')).to.have.attr('type', 'submit');

        // passes tabindex attr
        await render(hbs`{{gh-task-button tabindex="-1"}}`);
        expect(find('button')).to.have.attr('tabindex', '-1');
    });

    it('shows spinner whilst running', async function () {
        defineProperty(this, 'myTask', task(function* () {
            yield timeout(50);
        }));

        await render(hbs`{{gh-task-button task=myTask}}`);

        this.myTask.perform();

        await waitFor('button svg', {timeout: 50});
        await settled();
    });

    it('shows running text when passed whilst running', async function () {
        defineProperty(this, 'myTask', task(function* () {
            yield timeout(50);
        }));

        await render(hbs`{{gh-task-button task=myTask runningText="Running"}}`);

        this.myTask.perform();

        await waitFor('button svg', {timeout: 50});
        expect(find('button')).to.contain.text('Running');

        await settled();
    });

    // skipped due to random failures on Travis - https://github.com/TryGhost/Ghost/issues/10308
    it('appears disabled whilst running', async function () {
        defineProperty(this, 'myTask', task(function* () {
            yield timeout(50);
        }));

        await render(hbs`{{gh-task-button task=myTask}}`);
        expect(find('button'), 'initial class').to.not.have.class('appear-disabled');

        this.myTask.perform();

        await waitFor('button.appear-disabled', {timeout: 50});
        await settled();

        expect(find('button'), 'ended class').to.not.have.class('appear-disabled');
    });

    it('shows success on success', async function () {
        defineProperty(this, 'myTask', task(function* () {
            yield timeout(50);
            return true;
        }));

        await render(hbs`{{gh-task-button task=myTask}}`);

        await this.myTask.perform();

        expect(find('button')).to.have.class('gh-btn-green');
        expect(find('button')).to.contain.text('Saved');
    });

    it('assigns specified success class on success', async function () {
        defineProperty(this, 'myTask', task(function* () {
            yield timeout(50);
            return true;
        }));

        await render(hbs`{{gh-task-button task=myTask successClass="im-a-success"}}`);

        await this.myTask.perform();

        expect(find('button')).to.not.have.class('gh-btn-green');
        expect(find('button')).to.have.class('im-a-success');
        expect(find('button')).to.contain.text('Saved');
    });

    it('shows failure when task errors', async function () {
        defineProperty(this, 'myTask', task(function* () {
            try {
                yield timeout(50);
                throw new ReferenceError('test error');
            } catch (error) {
                // noop, prevent mocha triggering unhandled error assert
            }
        }));

        await render(hbs`{{gh-task-button task=myTask failureClass="is-failed"}}`);

        this.myTask.perform();
        await waitFor('button.is-failed');

        expect(find('button')).to.contain.text('Retry');

        await settled();
    });

    it('shows failure on falsy response', async function () {
        defineProperty(this, 'myTask', task(function* () {
            yield timeout(50);
            return false;
        }));

        await render(hbs`{{gh-task-button task=myTask}}`);

        this.myTask.perform();
        await waitFor('button.gh-btn-red', {timeout: 50});

        expect(find('button')).to.contain.text('Retry');

        await settled();
    });

    it('assigns specified failure class on failure', async function () {
        defineProperty(this, 'myTask', task(function* () {
            yield timeout(50);
            return false;
        }));

        await render(hbs`{{gh-task-button task=myTask failureClass="im-a-failure"}}`);

        this.myTask.perform();

        await waitFor('button.im-a-failure', {timeout: 50});

        expect(find('button')).to.not.have.class('gh-btn-red');
        expect(find('button')).to.contain.text('Retry');

        await settled();
    });

    it('performs task on click', async function () {
        let taskCount = 0;

        defineProperty(this, 'myTask', task(function* () {
            yield timeout(50);
            taskCount = taskCount + 1;
        }));

        await render(hbs`{{gh-task-button task=myTask}}`);
        await click('button');
        await settled();

        expect(taskCount, 'taskCount').to.equal(1);
    });

    it.skip('keeps button size when showing spinner', async function () {
        defineProperty(this, 'myTask', task(function* () {
            yield timeout(50);
        }));

        await render(hbs`{{gh-task-button task=myTask}}`);
        let width = find('button').clientWidth;
        let height = find('button').clientHeight;
        expect(find('button')).to.not.have.attr('style');

        this.myTask.perform();

        run.later(this, function () {
            // we can't test exact width/height because Chrome/Firefox use different rounding methods
            // expect(find('button')).to.have.attr('style', `width: ${width}px; height: ${height}px;`);

            let [widthInt] = width.toString().split('.');
            let [heightInt] = height.toString().split('.');

            expect(find('button')).to.have.attr('style', `width: ${widthInt}`);
            expect(find('button')).to.have.attr('style', `height: ${heightInt}`);
        }, 20);

        run.later(this, function () {
            expect(find('button').getAttribute('style')).to.be.empty;
        }, 100);

        await settled();
    });
});
<commit_msg>Increased timeout for gh-task-button disabled assertion<commit_after>import hbs from 'htmlbars-inline-precompile';
import {click, find, render, settled, waitFor} from '@ember/test-helpers';
import {defineProperty} from '@ember/object';
import {describe, it} from 'mocha';
import {expect} from 'chai';
import {run} from '@ember/runloop';
import {setupRenderingTest} from 'ember-mocha';
import {task, timeout} from 'ember-concurrency';

describe('Integration: Component: gh-task-button', function () {
    setupRenderingTest();

    it('renders', async function () {
        // sets button text using positional param
        await render(hbs`{{gh-task-button "Test"}}`);
        expect(find('button')).to.exist;
        expect(find('button')).to.contain.text('Test');
        expect(find('button').disabled).to.be.false;

        await render(hbs`{{gh-task-button class="testing"}}`);
        expect(find('button')).to.have.class('testing');
        // default button text is "Save"
        expect(find('button')).to.contain.text('Save');

        // passes disabled attr
        await render(hbs`{{gh-task-button disabled=true buttonText="Test"}}`);
        expect(find('button').disabled).to.be.true;
        // allows button text to be set via hash param
        expect(find('button')).to.contain.text('Test');

        // passes type attr
        await render(hbs`{{gh-task-button type="submit"}}`);
        expect(find('button')).to.have.attr('type', 'submit');

        // passes tabindex attr
        await render(hbs`{{gh-task-button tabindex="-1"}}`);
        expect(find('button')).to.have.attr('tabindex', '-1');
    });

    it('shows spinner whilst running', async function () {
        defineProperty(this, 'myTask', task(function* () {
            yield timeout(50);
        }));

        await render(hbs`{{gh-task-button task=myTask}}`);

        this.myTask.perform();

        await waitFor('button svg', {timeout: 50});
        await settled();
    });

    it('shows running text when passed whilst running', async function () {
        defineProperty(this, 'myTask', task(function* () {
            yield timeout(50);
        }));

        await render(hbs`{{gh-task-button task=myTask runningText="Running"}}`);

        this.myTask.perform();

        await waitFor('button svg', {timeout: 50});
        expect(find('button')).to.contain.text('Running');

        await settled();
    });

    it('appears disabled whilst running', async function () {
        defineProperty(this, 'myTask', task(function* () {
            yield timeout(50);
        }));

        await render(hbs`{{gh-task-button task=myTask}}`);
        expect(find('button'), 'initial class').to.not.have.class('appear-disabled');

        this.myTask.perform();

        await waitFor('button.appear-disabled', {timeout: 100});
        await settled();

        expect(find('button'), 'ended class').to.not.have.class('appear-disabled');
    });

    it('shows success on success', async function () {
        defineProperty(this, 'myTask', task(function* () {
            yield timeout(50);
            return true;
        }));

        await render(hbs`{{gh-task-button task=myTask}}`);

        await this.myTask.perform();

        expect(find('button')).to.have.class('gh-btn-green');
        expect(find('button')).to.contain.text('Saved');
    });

    it('assigns specified success class on success', async function () {
        defineProperty(this, 'myTask', task(function* () {
            yield timeout(50);
            return true;
        }));

        await render(hbs`{{gh-task-button task=myTask successClass="im-a-success"}}`);

        await this.myTask.perform();

        expect(find('button')).to.not.have.class('gh-btn-green');
        expect(find('button')).to.have.class('im-a-success');
        expect(find('button')).to.contain.text('Saved');
    });

    it('shows failure when task errors', async function () {
        defineProperty(this, 'myTask', task(function* () {
            try {
                yield timeout(50);
                throw new ReferenceError('test error');
            } catch (error) {
                // noop, prevent mocha triggering unhandled error assert
            }
        }));

        await render(hbs`{{gh-task-button task=myTask failureClass="is-failed"}}`);

        this.myTask.perform();
        await waitFor('button.is-failed');

        expect(find('button')).to.contain.text('Retry');

        await settled();
    });

    it('shows failure on falsy response', async function () {
        defineProperty(this, 'myTask', task(function* () {
            yield timeout(50);
            return false;
        }));

        await render(hbs`{{gh-task-button task=myTask}}`);

        this.myTask.perform();
        await waitFor('button.gh-btn-red', {timeout: 50});

        expect(find('button')).to.contain.text('Retry');

        await settled();
    });

    it('assigns specified failure class on failure', async function () {
        defineProperty(this, 'myTask', task(function* () {
            yield timeout(50);
            return false;
        }));

        await render(hbs`{{gh-task-button task=myTask failureClass="im-a-failure"}}`);

        this.myTask.perform();

        await waitFor('button.im-a-failure', {timeout: 50});

        expect(find('button')).to.not.have.class('gh-btn-red');
        expect(find('button')).to.contain.text('Retry');

        await settled();
    });

    it('performs task on click', async function () {
        let taskCount = 0;

        defineProperty(this, 'myTask', task(function* () {
            yield timeout(50);
            taskCount = taskCount + 1;
        }));

        await render(hbs`{{gh-task-button task=myTask}}`);
        await click('button');
        await settled();

        expect(taskCount, 'taskCount').to.equal(1);
    });

    it.skip('keeps button size when showing spinner', async function () {
        defineProperty(this, 'myTask', task(function* () {
            yield timeout(50);
        }));

        await render(hbs`{{gh-task-button task=myTask}}`);
        let width = find('button').clientWidth;
        let height = find('button').clientHeight;
        expect(find('button')).to.not.have.attr('style');

        this.myTask.perform();

        run.later(this, function () {
            // we can't test exact width/height because Chrome/Firefox use different rounding methods
            // expect(find('button')).to.have.attr('style', `width: ${width}px; height: ${height}px;`);

            let [widthInt] = width.toString().split('.');
            let [heightInt] = height.toString().split('.');

            expect(find('button')).to.have.attr('style', `width: ${widthInt}`);
            expect(find('button')).to.have.attr('style', `height: ${heightInt}`);
        }, 20);

        run.later(this, function () {
            expect(find('button').getAttribute('style')).to.be.empty;
        }, 100);

        await settled();
    });
});
<|endoftext|>


<commit_before>var util = require('../../util');

module.exports = function(req, res, next) {
	var options = req.options;
	if (!req.options.proxy || options.protocol == 'http:') {
		return next();
	}
	delete options.protocol;
	util.proxyHttps(req, function(err, _res) {
		err ? res.emit('error', err) : res.response(_res);
	});
};<commit_msg>https-proxy<commit_after>var util = require('../../util');

module.exports = function(req, res, next) {
	var options = req.options;
	if (!req.options.proxy || options.protocol == 'http:') {
		return next();
	}
	options.protocol = null;
	util.proxyHttps(req, function(err, _res) {
		err ? res.emit('error', err) : res.response(_res);
	});
};<|endoftext|>


<commit_before>import hbs from 'htmlbars-inline-precompile';
import wait from 'ember-test-helpers/wait';
import {describe, it} from 'mocha';
import {expect} from 'chai';
import {run} from '@ember/runloop';
import {setupComponentTest} from 'ember-mocha';
import {task, timeout} from 'ember-concurrency';

describe('Integration: Component: gh-task-button', function () {
    setupComponentTest('gh-task-button', {
        integration: true
    });

    it('renders', function () {
        // sets button text using positional param
        this.render(hbs`{{gh-task-button "Test"}}`);
        expect(this.$('button')).to.exist;
        expect(this.$('button')).to.contain('Test');
        expect(this.$('button')).to.have.prop('disabled', false);

        this.render(hbs`{{gh-task-button class="testing"}}`);
        expect(this.$('button')).to.have.class('testing');
        // default button text is "Save"
        expect(this.$('button')).to.contain('Save');

        // passes disabled attr
        this.render(hbs`{{gh-task-button disabled=true buttonText="Test"}}`);
        expect(this.$('button')).to.have.prop('disabled', true);
        // allows button text to be set via hash param
        expect(this.$('button')).to.contain('Test');

        // passes type attr
        this.render(hbs`{{gh-task-button type="submit"}}`);
        expect(this.$('button')).to.have.attr('type', 'submit');

        // passes tabindex attr
        this.render(hbs`{{gh-task-button tabindex="-1"}}`);
        expect(this.$('button')).to.have.attr('tabindex', '-1');
    });

    it('shows spinner whilst running', function (done) {
        this.set('myTask', task(function* () {
            yield timeout(50);
        }));

        this.render(hbs`{{gh-task-button task=myTask}}`);

        this.get('myTask').perform();

        run.later(this, function () {
            expect(this.$('button')).to.have.descendants('svg');
        }, 20);

        wait().then(done);
    });

    it('shows running text when passed whilst running', function (done) {
        this.set('myTask', task(function* () {
            yield timeout(50);
        }));

        this.render(hbs`{{gh-task-button task=myTask runningText="Running"}}`);

        this.get('myTask').perform();

        run.later(this, function () {
            expect(this.$('button')).to.have.descendants('svg');
            expect(this.$('button')).to.contain('Running');
        }, 20);

        wait().then(done);
    });

    it('appears disabled whilst running', function (done) {
        this.set('myTask', task(function* () {
            yield timeout(50);
        }));

        this.render(hbs`{{gh-task-button task=myTask}}`);
        expect(this.$('button'), 'initial class').to.not.have.class('appear-disabled');

        this.get('myTask').perform();

        run.later(this, function () {
            expect(this.$('button'), 'running class').to.have.class('appear-disabled');
        }, 20);

        run.later(this, function () {
            expect(this.$('button'), 'ended class').to.not.have.class('appear-disabled');
        }, 100);

        wait().then(done);
    });

    it('shows success on success', function (done) {
        this.set('myTask', task(function* () {
            yield timeout(50);
            return true;
        }));

        this.render(hbs`{{gh-task-button task=myTask}}`);

        this.get('myTask').perform();

        run.later(this, function () {
            expect(this.$('button')).to.have.class('gh-btn-green');
            expect(this.$('button')).to.contain('Saved');
        }, 100);

        wait().then(done);
    });

    it('assigns specified success class on success', function (done) {
        this.set('myTask', task(function* () {
            yield timeout(50);
            return true;
        }));

        this.render(hbs`{{gh-task-button task=myTask successClass="im-a-success"}}`);

        this.get('myTask').perform();

        run.later(this, function () {
            expect(this.$('button')).to.not.have.class('gh-btn-green');
            expect(this.$('button')).to.have.class('im-a-success');
            expect(this.$('button')).to.contain('Saved');
        }, 100);

        wait().then(done);
    });

    it('shows failure when task errors', function (done) {
        this.set('myTask', task(function* () {
            try {
                yield timeout(50);
                throw new ReferenceError('test error');
            } catch (error) {
                // noop, prevent mocha triggering unhandled error assert
            }
        }));

        this.render(hbs`{{gh-task-button task=myTask}}`);

        this.get('myTask').perform();

        run.later(this, function () {
            expect(this.$('button')).to.have.class('gh-btn-red');
            expect(this.$('button')).to.contain('Retry');
        }, 100);

        wait().then(done);
    });

    it('shows failure on falsy response', function (done) {
        this.set('myTask', task(function* () {
            yield timeout(50);
            return false;
        }));

        this.render(hbs`{{gh-task-button task=myTask}}`);

        this.get('myTask').perform();

        run.later(this, function () {
            expect(this.$('button')).to.have.class('gh-btn-red');
            expect(this.$('button')).to.contain('Retry');
        }, 100);

        wait().then(done);
    });

    it('assigns specified failure class on failure', function (done) {
        this.set('myTask', task(function* () {
            yield timeout(50);
            return false;
        }));

        this.render(hbs`{{gh-task-button task=myTask failureClass="im-a-failure"}}`);

        this.get('myTask').perform();

        run.later(this, function () {
            expect(this.$('button')).to.not.have.class('gh-btn-red');
            expect(this.$('button')).to.have.class('im-a-failure');
            expect(this.$('button')).to.contain('Retry');
        }, 100);

        wait().then(done);
    });

    it('performs task on click', function (done) {
        let taskCount = 0;

        this.set('myTask', task(function* () {
            yield timeout(50);
            taskCount = taskCount + 1;
        }));

        this.render(hbs`{{gh-task-button task=myTask}}`);
        this.$('button').click();

        wait().then(() => {
            expect(taskCount, 'taskCount').to.equal(1);
            done();
        });
    });

    it.skip('keeps button size when showing spinner', function (done) {
        this.set('myTask', task(function* () {
            yield timeout(50);
        }));

        this.render(hbs`{{gh-task-button task=myTask}}`);
        let width = this.$('button').width();
        let height = this.$('button').height();
        expect(this.$('button')).to.not.have.attr('style');

        this.get('myTask').perform();

        run.later(this, function () {
            // we can't test exact width/height because Chrome/Firefox use different rounding methods
            // expect(this.$('button')).to.have.attr('style', `width: ${width}px; height: ${height}px;`);

            let [widthInt] = width.toString().split('.');
            let [heightInt] = height.toString().split('.');

            expect(this.$('button').attr('style')).to.have.string(`width: ${widthInt}`);
            expect(this.$('button').attr('style')).to.have.string(`height: ${heightInt}`);
        }, 20);

        run.later(this, function () {
            // chai-jquery test doesn't work because Firefox outputs blank string
            // expect(this.$('button')).to.not.have.attr('style');
            expect(this.$('button').attr('style')).to.be.blank;
        }, 100);

        wait().then(done);
    });
});
<commit_msg>tests/gh-task-button: Return Promises instead of using `done()` (#954)<commit_after>import hbs from 'htmlbars-inline-precompile';
import wait from 'ember-test-helpers/wait';
import {describe, it} from 'mocha';
import {expect} from 'chai';
import {run} from '@ember/runloop';
import {setupComponentTest} from 'ember-mocha';
import {task, timeout} from 'ember-concurrency';

describe('Integration: Component: gh-task-button', function () {
    setupComponentTest('gh-task-button', {
        integration: true
    });

    it('renders', function () {
        // sets button text using positional param
        this.render(hbs`{{gh-task-button "Test"}}`);
        expect(this.$('button')).to.exist;
        expect(this.$('button')).to.contain('Test');
        expect(this.$('button')).to.have.prop('disabled', false);

        this.render(hbs`{{gh-task-button class="testing"}}`);
        expect(this.$('button')).to.have.class('testing');
        // default button text is "Save"
        expect(this.$('button')).to.contain('Save');

        // passes disabled attr
        this.render(hbs`{{gh-task-button disabled=true buttonText="Test"}}`);
        expect(this.$('button')).to.have.prop('disabled', true);
        // allows button text to be set via hash param
        expect(this.$('button')).to.contain('Test');

        // passes type attr
        this.render(hbs`{{gh-task-button type="submit"}}`);
        expect(this.$('button')).to.have.attr('type', 'submit');

        // passes tabindex attr
        this.render(hbs`{{gh-task-button tabindex="-1"}}`);
        expect(this.$('button')).to.have.attr('tabindex', '-1');
    });

    it('shows spinner whilst running', function () {
        this.set('myTask', task(function* () {
            yield timeout(50);
        }));

        this.render(hbs`{{gh-task-button task=myTask}}`);

        this.get('myTask').perform();

        run.later(this, function () {
            expect(this.$('button')).to.have.descendants('svg');
        }, 20);

        return wait();
    });

    it('shows running text when passed whilst running', function () {
        this.set('myTask', task(function* () {
            yield timeout(50);
        }));

        this.render(hbs`{{gh-task-button task=myTask runningText="Running"}}`);

        this.get('myTask').perform();

        run.later(this, function () {
            expect(this.$('button')).to.have.descendants('svg');
            expect(this.$('button')).to.contain('Running');
        }, 20);

        return wait();
    });

    it('appears disabled whilst running', function () {
        this.set('myTask', task(function* () {
            yield timeout(50);
        }));

        this.render(hbs`{{gh-task-button task=myTask}}`);
        expect(this.$('button'), 'initial class').to.not.have.class('appear-disabled');

        this.get('myTask').perform();

        run.later(this, function () {
            expect(this.$('button'), 'running class').to.have.class('appear-disabled');
        }, 20);

        run.later(this, function () {
            expect(this.$('button'), 'ended class').to.not.have.class('appear-disabled');
        }, 100);

        return wait();
    });

    it('shows success on success', function () {
        this.set('myTask', task(function* () {
            yield timeout(50);
            return true;
        }));

        this.render(hbs`{{gh-task-button task=myTask}}`);

        this.get('myTask').perform();

        run.later(this, function () {
            expect(this.$('button')).to.have.class('gh-btn-green');
            expect(this.$('button')).to.contain('Saved');
        }, 100);

        return wait();
    });

    it('assigns specified success class on success', function () {
        this.set('myTask', task(function* () {
            yield timeout(50);
            return true;
        }));

        this.render(hbs`{{gh-task-button task=myTask successClass="im-a-success"}}`);

        this.get('myTask').perform();

        run.later(this, function () {
            expect(this.$('button')).to.not.have.class('gh-btn-green');
            expect(this.$('button')).to.have.class('im-a-success');
            expect(this.$('button')).to.contain('Saved');
        }, 100);

        return wait();
    });

    it('shows failure when task errors', function () {
        this.set('myTask', task(function* () {
            try {
                yield timeout(50);
                throw new ReferenceError('test error');
            } catch (error) {
                // noop, prevent mocha triggering unhandled error assert
            }
        }));

        this.render(hbs`{{gh-task-button task=myTask}}`);

        this.get('myTask').perform();

        run.later(this, function () {
            expect(this.$('button')).to.have.class('gh-btn-red');
            expect(this.$('button')).to.contain('Retry');
        }, 100);

        return wait();
    });

    it('shows failure on falsy response', function () {
        this.set('myTask', task(function* () {
            yield timeout(50);
            return false;
        }));

        this.render(hbs`{{gh-task-button task=myTask}}`);

        this.get('myTask').perform();

        run.later(this, function () {
            expect(this.$('button')).to.have.class('gh-btn-red');
            expect(this.$('button')).to.contain('Retry');
        }, 100);

        return wait();
    });

    it('assigns specified failure class on failure', function () {
        this.set('myTask', task(function* () {
            yield timeout(50);
            return false;
        }));

        this.render(hbs`{{gh-task-button task=myTask failureClass="im-a-failure"}}`);

        this.get('myTask').perform();

        run.later(this, function () {
            expect(this.$('button')).to.not.have.class('gh-btn-red');
            expect(this.$('button')).to.have.class('im-a-failure');
            expect(this.$('button')).to.contain('Retry');
        }, 100);

        return wait();
    });

    it('performs task on click', function () {
        let taskCount = 0;

        this.set('myTask', task(function* () {
            yield timeout(50);
            taskCount = taskCount + 1;
        }));

        this.render(hbs`{{gh-task-button task=myTask}}`);
        this.$('button').click();

        return wait().then(() => {
            expect(taskCount, 'taskCount').to.equal(1);
        });
    });

    it.skip('keeps button size when showing spinner', function () {
        this.set('myTask', task(function* () {
            yield timeout(50);
        }));

        this.render(hbs`{{gh-task-button task=myTask}}`);
        let width = this.$('button').width();
        let height = this.$('button').height();
        expect(this.$('button')).to.not.have.attr('style');

        this.get('myTask').perform();

        run.later(this, function () {
            // we can't test exact width/height because Chrome/Firefox use different rounding methods
            // expect(this.$('button')).to.have.attr('style', `width: ${width}px; height: ${height}px;`);

            let [widthInt] = width.toString().split('.');
            let [heightInt] = height.toString().split('.');

            expect(this.$('button').attr('style')).to.have.string(`width: ${widthInt}`);
            expect(this.$('button').attr('style')).to.have.string(`height: ${heightInt}`);
        }, 20);

        run.later(this, function () {
            // chai-jquery test doesn't work because Firefox outputs blank string
            // expect(this.$('button')).to.not.have.attr('style');
            expect(this.$('button').attr('style')).to.be.blank;
        }, 100);

        return wait();
    });
});
<|endoftext|>


<commit_before>"use strict";

const Utils = require("../core/Utils");

class IBase {
  static _inherit(proto, get) {
    var thisProto = this.prototype;
    thisProto._valueOverrides = thisProto._valueOverrides || {};
    thisProto._gettersByProperty = thisProto._gettersByProperty || {};
    thisProto._suppressErrors = false;
    Object.defineProperties(thisProto, {
      _valueOverrides: {enumerable: false},
      _gettersByProperty: {enumerable: false},
      _suppressErrors: {enumerable: false}
    });

    thisProto._gettersByProperty[this.name] =
      thisProto._gettersByProperty[this.name] || {};

    const interfacingProperties = new proto();
    for (let key in interfacingProperties) {
      thisProto._gettersByProperty[this.name][key] = get;

      Object.defineProperty(thisProto, key, {
        enumerable: true,
        configurable: true,
        get: function() {
          const __thisproto__ = Object.getPrototypeOf(this);
          try {
            const value = get.call(this, key);
            if (__thisproto__._valueOverrides[key]) {
              return __thisproto__._valueOverrides[key].call(this, value);
            }
            return value;
          } catch (e) {
            const __ctrproto__ = Object.getPrototypeOf(this.constructor);
            if (!__ctrproto__._suppressErrors) console.error(e.stack);
            return null;
          }
        }
      });
    }
  }
  static _setValueOverride(k, fn) {
    if (!this.prototype.hasOwnProperty(k)) {
      throw new Error(
        `Property '${k}' is not defined for ${this.constructor.name}`
      );
    }

    if (typeof fn !== "function") {
      return delete this._valueOverrides[k];
    }
    this.prototype._valueOverrides[k] = fn;
  }
  static _setSuppressErrors(value) {
    Object.getPrototypeOf(this)._suppressErrors = value;
  }

  // Get a copy of raw model data or property
  getRaw(property) {
    var allGetters = Object.getPrototypeOf(this)._gettersByProperty;
    var getters = allGetters[this.constructor.name];
    if (!getters) {
      // no own properties, lookup last inherited class
      var lastClass = Object.keys(allGetters).pop();
      getters = allGetters[lastClass];
    }

    getters = getters || {};

    if (property) {
      if (!getters.hasOwnProperty(property)) return;
      return getters[property].call(this, property);
    }

    var copy = {};
    for (var key in this) {
      try {
        if (getters.hasOwnProperty(key))
          copy[key] = getters[key].call(this, key);
      } catch (e) {
        copy[key] = null;
        console.error("Could not get key", key);
        console.error(e.stack);
      }
    }
    return copy;
  }

  // Get a copy of internal model data, including inherited properties
  toJSON() {
    var copy = {};
    const __thisproto__ = Object.getPrototypeOf(this);
    for (var classname in __thisproto__._gettersByProperty) {
      var getters = __thisproto__._gettersByProperty[classname];
      for (var key in this) {
        try {
          if (getters.hasOwnProperty(key))
            copy[key] = getters[key].call(this, key);
        } catch (e) {
          copy[key] = null;
          console.error("Could not get key ", key);
          console.error(e.stack);
        }
      }
      if (classname === this.constructor.name) break;
    }
    return copy;
  }

  // Custom inspect output (console.log, util.format, util.inspect)
  inspect() {
    var copy = new (
      // create fake object to preserve class name
      new Function("return function " + this.constructor.name + "(){}")()
    );
    for (var key in this) { copy[key] = this[key]; }
    return copy;
  }

  get _valid() {
    try {
      var allGetters = Object.getPrototypeOf(this)._gettersByProperty;
      for (var classname in allGetters) {
        if (allGetters[classname].hasOwnProperty("id"))
          return allGetters[classname]["id"].call(this, "id");
      }
    } catch (e) {
      return false;
    }
  }

  valueOf() {
    if (!this.id) return null;
    return this.id;
  }
  equals(b) {
    return this.valueOf() === b.valueOf();
  }

  /**
   * Gets date and time this object was created at.
   * @returns {Date}
   * @readonly
   */
  get createdAt() {
    return new Date(Utils.timestampFromSnowflake(this.id));
  }
}

module.exports = IBase;<commit_msg>Convert internal Set/Map to arrays in IBase.toJSON()<commit_after>"use strict";

const Utils = require("../core/Utils");

class IBase {
  static _inherit(proto, get) {
    var thisProto = this.prototype;
    thisProto._valueOverrides = thisProto._valueOverrides || {};
    thisProto._gettersByProperty = thisProto._gettersByProperty || {};
    thisProto._suppressErrors = false;
    Object.defineProperties(thisProto, {
      _valueOverrides: {enumerable: false},
      _gettersByProperty: {enumerable: false},
      _suppressErrors: {enumerable: false}
    });

    thisProto._gettersByProperty[this.name] =
      thisProto._gettersByProperty[this.name] || {};

    const interfacingProperties = new proto();
    for (let key in interfacingProperties) {
      thisProto._gettersByProperty[this.name][key] = get;

      Object.defineProperty(thisProto, key, {
        enumerable: true,
        configurable: true,
        get: function() {
          const __thisproto__ = Object.getPrototypeOf(this);
          try {
            const value = get.call(this, key);
            if (__thisproto__._valueOverrides[key]) {
              return __thisproto__._valueOverrides[key].call(this, value);
            }
            return value;
          } catch (e) {
            const __ctrproto__ = Object.getPrototypeOf(this.constructor);
            if (!__ctrproto__._suppressErrors) console.error(e.stack);
            return null;
          }
        }
      });
    }
  }
  static _setValueOverride(k, fn) {
    if (!this.prototype.hasOwnProperty(k)) {
      throw new Error(
        `Property '${k}' is not defined for ${this.constructor.name}`
      );
    }

    if (typeof fn !== "function") {
      return delete this._valueOverrides[k];
    }
    this.prototype._valueOverrides[k] = fn;
  }
  static _setSuppressErrors(value) {
    Object.getPrototypeOf(this)._suppressErrors = value;
  }

  // Get a copy of raw model data or property
  getRaw(property) {
    var allGetters = Object.getPrototypeOf(this)._gettersByProperty;
    var getters = allGetters[this.constructor.name];
    if (!getters) {
      // no own properties, lookup last inherited class
      var lastClass = Object.keys(allGetters).pop();
      getters = allGetters[lastClass];
    }

    getters = getters || {};

    if (property) {
      if (!getters.hasOwnProperty(property)) return;
      return getters[property].call(this, property);
    }

    var copy = {};
    for (var key in this) {
      try {
        if (getters.hasOwnProperty(key))
          copy[key] = getters[key].call(this, key);
      } catch (e) {
        copy[key] = null;
        console.error("Could not get key", key);
        console.error(e.stack);
      }
    }
    return copy;
  }

  // Get a copy of internal model data, including inherited properties
  toJSON() {
    var copy = {};
    const __thisproto__ = Object.getPrototypeOf(this);
    for (var classname in __thisproto__._gettersByProperty) {
      var getters = __thisproto__._gettersByProperty[classname];
      for (var key in this) {
        try {
          if (getters.hasOwnProperty(key)) {
            copy[key] = getters[key].call(this, key);
            const v = copy[key];
            const type = v && v.constructor && v.constructor.name;
            if (type === "Set") copy[key] = Array.from(v);
            if (type === "Map") copy[key] = Array.from(v.values());
          }
        } catch (e) {
          copy[key] = null;
          console.error("Could not get key ", key);
          console.error(e.stack);
        }
      }
      if (classname === this.constructor.name) break;
    }
    return copy;
  }

  // Custom inspect output (console.log, util.format, util.inspect)
  inspect() {
    var copy = new (
      // create fake object to preserve class name
      new Function("return function " + this.constructor.name + "(){}")()
    );
    for (var key in this) { copy[key] = this[key]; }
    return copy;
  }

  get _valid() {
    try {
      var allGetters = Object.getPrototypeOf(this)._gettersByProperty;
      for (var classname in allGetters) {
        if (allGetters[classname].hasOwnProperty("id"))
          return allGetters[classname]["id"].call(this, "id");
      }
    } catch (e) {
      return false;
    }
  }

  valueOf() {
    if (!this.id) return null;
    return this.id;
  }
  equals(b) {
    return this.valueOf() === b.valueOf();
  }

  /**
   * Gets date and time this object was created at.
   * @returns {Date}
   * @readonly
   */
  get createdAt() {
    return new Date(Utils.timestampFromSnowflake(this.id));
  }
}

module.exports = IBase;<|endoftext|>


<commit_before>"use strict";

const IBase = require("./IBase");
const IPermissions = require("./IPermissions");
const Utils = require("../core/Utils");
const Role = require("../models/Role");

const Constants = require("../Constants");
const PermissionSpecs = Constants.PermissionSpecs;

const rest = require("../networking/rest");

/**
 * @interface
 * @extends IBase
 */
class IRole extends IBase {
  constructor(discordie, roleId, guildId) {
    super();
    Utils.definePrivate(this, {
      _discordie: discordie,
      _roleId: roleId,
      _guildId: guildId
    });
    Utils.definePrivate(this, {
      _permissions: new IPermissions(
        this.getRaw("permissions"),
        PermissionSpecs.Role
      )
    });

    Object.freeze(this);
  }

  /**
   * Loads original permissions from cache and updates this object.
   */
  reload() {
    const rawPermissions = this.getRaw("permissions");
    if (!rawPermissions) return;
    this._permissions.raw = rawPermissions;
  }

  /**
   * Makes a request to commit changes made to this role object.
   * @param {String} [name]
   * @param {Number} [color] - RGB color number
   * @param {boolean} [hoist] - true if role should be displayed separately
   * @returns {Promise}
   */
  commit(name, color, hoist) {
    const everyone = (this.id == this._guildId);
    if (!name || everyone) name = this.name;
    if (hoist === undefined || hoist === null || everyone) hoist = this.hoist;
    if (color === undefined || color === null || everyone) color = this.color;

    return new Promise((rs, rj) => {
      rest(this._discordie).guilds.roles.patchRole(
        this._guildId, this.id,
        name, this.permissions.raw, color, hoist
      )
      .then(() => rs(this))
      .catch(err => {
        this.reload();
        return rj(err);
      });
    });
  }

  /**
   * Moves this role to `position` and makes a batch role update request.
   * @param {Number} position
   * @returns {Promise}
   */
  setPosition(position) {
    const guild = this._discordie.Guilds.get(this._guildId);
    if (!guild) return Promise.reject(new Error("Guild does not exist"));

    // maybe todo: disallow assigning position 0 (role @everyone)
    const changes = Utils.reorderObjects(guild.roles, this, position);
    if (!changes) return Promise.resolve();

    return rest(this._discordie)
      .guilds.roles.batchPatchRoles(this._guildId, changes);
  }

  /**
   * Makes a request to delete this role.
   * @returns {Promise}
   */
  delete() {
    return rest(this._discordie)
      .guilds.roles.deleteRole(this._guildId, this.id);
  }
}

IRole._inherit(Role, function modelPropertyGetter(key) {
  const guild = this._discordie._guilds.get(this._guildId);
  if (!guild) return null;
  const role = guild.roles.get(this._roleId);
  if (!role) return null;
  return role[key];
});

/**
 * @readonly
 * @instance
 * @memberOf IRole
 * @name permissions
 * @returns {IPermissions}
 */
IRole._setValueOverride("permissions", function(v) {
  return this._permissions;
});

module.exports = IRole;
<commit_msg>Update docs<commit_after>"use strict";

const IBase = require("./IBase");
const IPermissions = require("./IPermissions");
const Utils = require("../core/Utils");
const Role = require("../models/Role");

const Constants = require("../Constants");
const PermissionSpecs = Constants.PermissionSpecs;

const rest = require("../networking/rest");

/**
 * @interface
 * @extends IBase
 * @model Role
 */
class IRole extends IBase {
  constructor(discordie, roleId, guildId) {
    super();
    Utils.definePrivate(this, {
      _discordie: discordie,
      _roleId: roleId,
      _guildId: guildId
    });
    Utils.definePrivate(this, {
      _permissions: new IPermissions(
        this.getRaw("permissions"),
        PermissionSpecs.Role
      )
    });

    Object.freeze(this);
  }

  /**
   * Loads original permissions from cache and updates this object.
   */
  reload() {
    const rawPermissions = this.getRaw("permissions");
    if (!rawPermissions) return;
    this._permissions.raw = rawPermissions;
  }

  /**
   * Makes a request to commit changes made to this role object.
   * @param {String} [name]
   * @param {Number} [color] - RGB color number
   * @param {boolean} [hoist] - true if role should be displayed separately
   * @returns {Promise}
   */
  commit(name, color, hoist) {
    const everyone = (this.id == this._guildId);
    if (!name || everyone) name = this.name;
    if (hoist === undefined || hoist === null || everyone) hoist = this.hoist;
    if (color === undefined || color === null || everyone) color = this.color;

    return new Promise((rs, rj) => {
      rest(this._discordie).guilds.roles.patchRole(
        this._guildId, this.id,
        name, this.permissions.raw, color, hoist
      )
      .then(() => rs(this))
      .catch(err => {
        this.reload();
        return rj(err);
      });
    });
  }

  /**
   * Moves this role to `position` and makes a batch role update request.
   * @param {Number} position
   * @returns {Promise}
   */
  setPosition(position) {
    const guild = this._discordie.Guilds.get(this._guildId);
    if (!guild) return Promise.reject(new Error("Guild does not exist"));

    // maybe todo: disallow assigning position 0 (role @everyone)
    const changes = Utils.reorderObjects(guild.roles, this, position);
    if (!changes) return Promise.resolve();

    return rest(this._discordie)
      .guilds.roles.batchPatchRoles(this._guildId, changes);
  }

  /**
   * Makes a request to delete this role.
   * @returns {Promise}
   */
  delete() {
    return rest(this._discordie)
      .guilds.roles.deleteRole(this._guildId, this.id);
  }
}

IRole._inherit(Role, function modelPropertyGetter(key) {
  const guild = this._discordie._guilds.get(this._guildId);
  if (!guild) return null;
  const role = guild.roles.get(this._roleId);
  if (!role) return null;
  return role[key];
});

/**
 * @readonly
 * @instance
 * @memberOf IRole
 * @name permissions
 * @returns {IPermissions}
 */
IRole._setValueOverride("permissions", function(v) {
  return this._permissions;
});

module.exports = IRole;
<|endoftext|>


<commit_before>"use strict";
/* -------------------------------------------------------------------
 * Require Statements << Keep in alphabetical order >>
 * ---------------------------------------------------------------- */

var Exceptions = require('./Exceptions');
var ExpressionType = require('./ExpressionType');
var Lexer = require('./Lexer');
var Node = require('./Node');
var TokenType = require('./TokenType');

/* =============================================================================
 *
 * Parser
 *
 * ========================================================================== */

module.exports = Parser;

/**
 * @param input {string}
 * @constructor
 */
function Parser (input)
{
	// ParserBase init
	this._lexer = new Lexer(input);
}

/* -------------------------------------------------------------------
 * ParserBase Members
 * ---------------------------------------------------------------- */

Object.defineProperty(Parser.prototype, 'input', {
	get: function () { return this._lexer.input; }
});

/**
 * @return {Token}
 * @private
 */
Parser.prototype._peek = function ()
{
	return this._lexer.peek();
};

/**
 * @return {Token}
 * @private
 */
Parser.prototype._advance = function ()
{
	return this._lexer.advance();
};

/**
 * @param tokenType {number} From TokenType enum.
 * @return {Token}
 * @private
 */
Parser.prototype._expect = function (tokenType)
{
	if (!this._isNext(tokenType))
		throw this._wrongTokenException(tokenType);

	return this._advance();
};

/**
 * @param tokenType {number} From TokenType enum.
 * @return {boolean}
 * @private
 */
Parser.prototype._isNext = function (tokenType)
{
	return this._peek().type == tokenType;
};

Parser.prototype._wrongTokenException = function ()
{
	var expected = '';
	for (var i = 0; i < arguments.length; i++)
	{
		if (i > 0)
			expected += ', ';

		expected += TokenType.valueToName(arguments[i]);
	}

	var next = this._peek();
	var msg = "Unexpected token type " + TokenType.valueToName(next.type) + " at index " + this._index + ". Was expecting " + expected;
	return new Exceptions.SchyntaxParseError(msg, this.input, next.index);
};

/* -------------------------------------------------------------------
 * Parser Members
 * ---------------------------------------------------------------- */

/**
 * @return {Node.ProgramNode}
 */
Parser.prototype.parse = function ()
{
	return this._parseProgram();
};

/**
 * @return {Node.ProgramNode}
 */
Parser.prototype._parseProgram = function ()
{
	var program = new Node.ProgramNode();

	while (!this._isNext(TokenType.EndOfInput))
	{
		if (this._isNext(TokenType.OpenCurly))
		{
			program.addGroup(this._parseGroup());
		}
		else if (this._isNext(TokenType.ExpressionName))
		{
			program.addExpression(this._parseExpression());
		}
		else
		{
			throw this._wrongTokenException(TokenType.OpenCurly, TokenType.ExpressionName, TokenType.Comma);
		}

		if (this._isNext(TokenType.Comma)) // optional comma
		{
			program.addToken(this._advance());
		}
	}

	program.addToken(this._expect(TokenType.EndOfInput));
	return program;
};

/**
 * @return {Node.GroupNode}
 */
Parser.prototype._parseGroup = function ()
{
	var group = new Node.GroupNode();
	group.addToken(this._expect(TokenType.OpenCurly));

	while (!this._isNext(TokenType.CloseCurly))
	{
		group.addExpression(this._parseExpression());

		if (this._isNext(TokenType.Comma)) // optional comma
		{
			group.addToken(this._advance());
		}
	}

	group.addToken(this._expect(TokenType.CloseCurly));
	return group;
};

/**
 * @return {Node.ExpressionNode}
 */
Parser.prototype._parseExpression = function ()
{
	var nameTok = this._expect(TokenType.ExpressionName);
	var type = ExpressionType.nameToValue(nameTok.value);
	var exp = new Node.ExpressionNode(type);
	exp.addToken(this._expect(TokenType.OpenParen));

	while (true)
	{
		exp.addArgument(this._parseArgument(type));

		if (this._isNext(TokenType.CloseParen))
		{
			break;
		}

		if (this._isNext(TokenType.Comma)) // optional comma
		{
			exp.addToken(this._advance());
		}
	}

	exp.addToken(this._expect(TokenType.CloseParen));
	return exp;
};

/**
 * @return {Node.ArgumentNode}
 */
Parser.prototype._parseArgument = function (expressionType)
{
	var arg = new Node.ArgumentNode();

	if (this._isNext(TokenType.Not))
	{
		arg.isExclusion = true;
		arg.addToken(this._advance());
	}

	if (this._isNext(TokenType.Wildcard))
	{
		arg.isWildcard = true;
		arg.addToken(this._advance());
	}
	else
	{
		arg.range = this._parseRange(expressionType);
	}

	if (this._isNext(TokenType.Interval))
	{
		arg.addToken(this._advance());
		arg.interval = this._parseIntegerValue(ExpressionType.IntervalValue);
	}

	return arg;
};

/**
 * @return {Node.RangeNode}
 */
Parser.prototype._parseRange = function (expressionType)
{
	var range = new Node.RangeNode();
	range.start = expressionType == ExpressionType.Dates ? this._parseDate() : this._parseIntegerValue(expressionType);

	var isRange = false;
	if (this._isNext(TokenType.RangeInclusive))
	{
		isRange = true;
	}
	else if (this._isNext(TokenType.RangeHalfOpen))
	{
		isRange = true;
		range.isHalfOpen = true;
	}

	if (isRange)
	{
		range.addToken(this._advance());
		range.end = expressionType == ExpressionType.Dates ? this._parseDate() : this._parseIntegerValue(expressionType);
	}

	return range;
};

/**
 * @return {Node.IntegerValueNode}
 */
Parser.prototype._parseIntegerValue = function (expressionType)
{
	var val = new Node.IntegerValueNode();

	/** @type {Token} */
	var tok;
	if (this._isNext(TokenType.PositiveInteger))
	{
		// positive integer is valid for anything
		tok = this._advance();
		val.addToken(tok);
		val.value = Number(tok.value);
	}
	else if (this._isNext(TokenType.NegativeInteger))
	{
		if (expressionType != ExpressionType.DaysOfMonth)
		{
			throw new Exceptions.SchyntaxParseError("Negative values are only allowed in dayofmonth expressions.", this.input, this._peek().index);
		}

		tok = this._advance();
		val.addToken(tok);
		val.value = Number(tok.value);
	}
	else if (this._isNext(TokenType.DayLiteral))
	{
		tok = this._advance();
		val.addToken(tok);
		val.value = dayToInteger(tok.value);
	}
	else
	{
		switch (expressionType)
		{
			case ExpressionType.DaysOfMonth:
				throw this._wrongTokenException(TokenType.PositiveInteger, TokenType.NegativeInteger);
			case ExpressionType.DaysOfWeek:
				throw this._wrongTokenException(TokenType.PositiveInteger, TokenType.DayLiteral);
			default:
				throw this._wrongTokenException(TokenType.PositiveInteger);
		}
	}

	return val;
};

/**
 * @return {Node.DateValueNode}
 */
Parser.prototype._parseDate = function ()
{
	var date = new Node.DateValueNode();

	var tok = this._expect(TokenType.PositiveInteger);
	date.addToken(tok);
	var one = Number(tok.value);

	date.addToken(this._expect(TokenType.ForwardSlash));

	tok = this._expect(TokenType.PositiveInteger);
	date.addToken(tok);
	var two = Number(tok.value);

	var three = -1;
	if (this._isNext(TokenType.ForwardSlash))
	{
		date.addToken(this._expect(TokenType.ForwardSlash));

		tok = this._expect(TokenType.PositiveInteger);
		date.addToken(tok);
		three = Number(tok.value);
	}

	if (three != -1)
	{
		// date has a year
		date.year = one;
		date.month = two;
		date.day = three;
	}
	else
	{
		// no year
		date.month = one;
		date.day = two;
	}

	return date;
};

function dayToInteger (day)
{
	switch (day)
	{
		case "SUNDAY":
			return 1;
		case "MONDAY":
			return 2;
		case "TUESDAY":
			return 3;
		case "WEDNESDAY":
			return 4;
		case "THURSDAY":
			return 5;
		case "FRIDAY":
			return 6;
		case "SATURDAY":
			return 7;
		default:
			throw new Error(day + " is not a day");
	}
}
<commit_msg>Make trailing comma in argument lists optional.<commit_after>"use strict";
/* -------------------------------------------------------------------
 * Require Statements << Keep in alphabetical order >>
 * ---------------------------------------------------------------- */

var Exceptions = require('./Exceptions');
var ExpressionType = require('./ExpressionType');
var Lexer = require('./Lexer');
var Node = require('./Node');
var TokenType = require('./TokenType');

/* =============================================================================
 *
 * Parser
 *
 * ========================================================================== */

module.exports = Parser;

/**
 * @param input {string}
 * @constructor
 */
function Parser (input)
{
	// ParserBase init
	this._lexer = new Lexer(input);
}

/* -------------------------------------------------------------------
 * ParserBase Members
 * ---------------------------------------------------------------- */

Object.defineProperty(Parser.prototype, 'input', {
	get: function () { return this._lexer.input; }
});

/**
 * @return {Token}
 * @private
 */
Parser.prototype._peek = function ()
{
	return this._lexer.peek();
};

/**
 * @return {Token}
 * @private
 */
Parser.prototype._advance = function ()
{
	return this._lexer.advance();
};

/**
 * @param tokenType {number} From TokenType enum.
 * @return {Token}
 * @private
 */
Parser.prototype._expect = function (tokenType)
{
	if (!this._isNext(tokenType))
		throw this._wrongTokenException(tokenType);

	return this._advance();
};

/**
 * @param tokenType {number} From TokenType enum.
 * @return {boolean}
 * @private
 */
Parser.prototype._isNext = function (tokenType)
{
	return this._peek().type == tokenType;
};

Parser.prototype._wrongTokenException = function ()
{
	var expected = '';
	for (var i = 0; i < arguments.length; i++)
	{
		if (i > 0)
			expected += ', ';

		expected += TokenType.valueToName(arguments[i]);
	}

	var next = this._peek();
	var msg = "Unexpected token type " + TokenType.valueToName(next.type) + " at index " + this._index + ". Was expecting " + expected;
	return new Exceptions.SchyntaxParseError(msg, this.input, next.index);
};

/* -------------------------------------------------------------------
 * Parser Members
 * ---------------------------------------------------------------- */

/**
 * @return {Node.ProgramNode}
 */
Parser.prototype.parse = function ()
{
	return this._parseProgram();
};

/**
 * @return {Node.ProgramNode}
 */
Parser.prototype._parseProgram = function ()
{
	var program = new Node.ProgramNode();

	while (!this._isNext(TokenType.EndOfInput))
	{
		if (this._isNext(TokenType.OpenCurly))
		{
			program.addGroup(this._parseGroup());
		}
		else if (this._isNext(TokenType.ExpressionName))
		{
			program.addExpression(this._parseExpression());
		}
		else
		{
			throw this._wrongTokenException(TokenType.OpenCurly, TokenType.ExpressionName, TokenType.Comma);
		}

		if (this._isNext(TokenType.Comma)) // optional comma
		{
			program.addToken(this._advance());
		}
	}

	program.addToken(this._expect(TokenType.EndOfInput));
	return program;
};

/**
 * @return {Node.GroupNode}
 */
Parser.prototype._parseGroup = function ()
{
	var group = new Node.GroupNode();
	group.addToken(this._expect(TokenType.OpenCurly));

	while (!this._isNext(TokenType.CloseCurly))
	{
		group.addExpression(this._parseExpression());

		if (this._isNext(TokenType.Comma)) // optional comma
		{
			group.addToken(this._advance());
		}
	}

	group.addToken(this._expect(TokenType.CloseCurly));
	return group;
};

/**
 * @return {Node.ExpressionNode}
 */
Parser.prototype._parseExpression = function ()
{
	var nameTok = this._expect(TokenType.ExpressionName);
	var type = ExpressionType.nameToValue(nameTok.value);
	var exp = new Node.ExpressionNode(type);
	exp.addToken(this._expect(TokenType.OpenParen));

	while (true)
	{
		exp.addArgument(this._parseArgument(type));

		if (this._isNext(TokenType.Comma)) // optional comma
		{
			exp.addToken(this._advance());
		}

		if (this._isNext(TokenType.CloseParen))
		{
			break;
		}
	}

	exp.addToken(this._expect(TokenType.CloseParen));
	return exp;
};

/**
 * @return {Node.ArgumentNode}
 */
Parser.prototype._parseArgument = function (expressionType)
{
	var arg = new Node.ArgumentNode();

	if (this._isNext(TokenType.Not))
	{
		arg.isExclusion = true;
		arg.addToken(this._advance());
	}

	if (this._isNext(TokenType.Wildcard))
	{
		arg.isWildcard = true;
		arg.addToken(this._advance());
	}
	else
	{
		arg.range = this._parseRange(expressionType);
	}

	if (this._isNext(TokenType.Interval))
	{
		arg.addToken(this._advance());
		arg.interval = this._parseIntegerValue(ExpressionType.IntervalValue);
	}

	return arg;
};

/**
 * @return {Node.RangeNode}
 */
Parser.prototype._parseRange = function (expressionType)
{
	var range = new Node.RangeNode();
	range.start = expressionType == ExpressionType.Dates ? this._parseDate() : this._parseIntegerValue(expressionType);

	var isRange = false;
	if (this._isNext(TokenType.RangeInclusive))
	{
		isRange = true;
	}
	else if (this._isNext(TokenType.RangeHalfOpen))
	{
		isRange = true;
		range.isHalfOpen = true;
	}

	if (isRange)
	{
		range.addToken(this._advance());
		range.end = expressionType == ExpressionType.Dates ? this._parseDate() : this._parseIntegerValue(expressionType);
	}

	return range;
};

/**
 * @return {Node.IntegerValueNode}
 */
Parser.prototype._parseIntegerValue = function (expressionType)
{
	var val = new Node.IntegerValueNode();

	/** @type {Token} */
	var tok;
	if (this._isNext(TokenType.PositiveInteger))
	{
		// positive integer is valid for anything
		tok = this._advance();
		val.addToken(tok);
		val.value = Number(tok.value);
	}
	else if (this._isNext(TokenType.NegativeInteger))
	{
		if (expressionType != ExpressionType.DaysOfMonth)
		{
			throw new Exceptions.SchyntaxParseError("Negative values are only allowed in dayofmonth expressions.", this.input, this._peek().index);
		}

		tok = this._advance();
		val.addToken(tok);
		val.value = Number(tok.value);
	}
	else if (this._isNext(TokenType.DayLiteral))
	{
		tok = this._advance();
		val.addToken(tok);
		val.value = dayToInteger(tok.value);
	}
	else
	{
		switch (expressionType)
		{
			case ExpressionType.DaysOfMonth:
				throw this._wrongTokenException(TokenType.PositiveInteger, TokenType.NegativeInteger);
			case ExpressionType.DaysOfWeek:
				throw this._wrongTokenException(TokenType.PositiveInteger, TokenType.DayLiteral);
			default:
				throw this._wrongTokenException(TokenType.PositiveInteger);
		}
	}

	return val;
};

/**
 * @return {Node.DateValueNode}
 */
Parser.prototype._parseDate = function ()
{
	var date = new Node.DateValueNode();

	var tok = this._expect(TokenType.PositiveInteger);
	date.addToken(tok);
	var one = Number(tok.value);

	date.addToken(this._expect(TokenType.ForwardSlash));

	tok = this._expect(TokenType.PositiveInteger);
	date.addToken(tok);
	var two = Number(tok.value);

	var three = -1;
	if (this._isNext(TokenType.ForwardSlash))
	{
		date.addToken(this._expect(TokenType.ForwardSlash));

		tok = this._expect(TokenType.PositiveInteger);
		date.addToken(tok);
		three = Number(tok.value);
	}

	if (three != -1)
	{
		// date has a year
		date.year = one;
		date.month = two;
		date.day = three;
	}
	else
	{
		// no year
		date.month = one;
		date.day = two;
	}

	return date;
};

function dayToInteger (day)
{
	switch (day)
	{
		case "SUNDAY":
			return 1;
		case "MONDAY":
			return 2;
		case "TUESDAY":
			return 3;
		case "WEDNESDAY":
			return 4;
		case "THURSDAY":
			return 5;
		case "FRIDAY":
			return 6;
		case "SATURDAY":
			return 7;
		default:
			throw new Error(day + " is not a day");
	}
}
<|endoftext|>


<commit_before>/*
 * Licensed to Cloudkick, Inc ('Cloudkick') under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * Cloudkick licenses this file to You under the Apache License, Version 2.0
 * (the "License"); you may not use this file except in compliance with
 * the License.  You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

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

var test = require('util/test');
var extract = require('util/tarball');

var sprintf = require('extern/sprintf').sprintf;
var async = require('extern/async');
var assert = require('assert');

var cwd = process.cwd();
var dataPath = path.join(cwd, 'data');
var bundlePath = path.join(dataPath, 'test foo bar');

var tarballName1 = 'foo-bar-1.0.1.tar.gz';
var tarballPath1 = path.join(dataPath, tarballName1);

var tarballName2 = 'foo-bar-1.0.2.tar.gz';
var tarballPath2 = path.join(dataPath, tarballName2);

var tarballName3 = 'foo-bar-1.0.3.tar.gz';
var tarballPath3 = path.join(dataPath, tarballName3);

var tarballName4 = 'foo-bar-1.0.4.tar.gz';
var tarballPath4 = path.join(dataPath, tarballName4);

var tarballName5 = 'foo-bar-1.0.5.tar.gz';
var tarballPath5 = path.join(dataPath, tarballName5);

var tarballName6 = 'foo-bar-1.0.6.tar.gz';
var tarballPath6 = path.join(dataPath, tarballName6);

var tarballName7 = 'foo-bar-1.0.7.tar.gz';
var tarballPath7 = path.join(dataPath, tarballName7);

(function() {
  var completed = false;

  async.parallel([
    // Test invalid source path
    function(callback) {
      extract.createTarball('/invalid/source/path/', dataPath, tarballName1, {deleteIfExists: false}, function(error) {
        assert.ok(error);
        assert.match(error.message, /source path does not exist/i);
        callback();
      });
    },

    // Test invalid target path
    function(callback) {
      extract.createTarball(bundlePath, '/invalid/path', tarballName1, {deleteIfExists: false}, function(error) {
        assert.ok(error);
        assert.match(error.message, /target path does not exist/i);
        callback();
      });
    },

    // Test create tarball
    function(callback) {
      test.fileDelete(tarballPath1);
      assert.equal(test.fileExists(tarballPath1), false);

      extract.createTarball(bundlePath, dataPath, tarballName1, {deleteIfExists: false}, function(error) {
        assert.ifError(error);
        assert.equal(test.fileExists(tarballPath1), true);
        test.fileDelete(tarballPath1);
        callback();
      });
    },

    // Test create tarball throws error upon existing file
    function(callback) {
      test.fileDelete(tarballPath2);
      assert.equal(test.fileExists(tarballPath2), false);

      extract.createTarball(bundlePath, dataPath, tarballName2, {deleteIfExists: false}, function(error) {
        assert.ifError(error);
        assert.equal(test.fileExists(tarballPath2), true);

        extract.createTarball(bundlePath, dataPath, tarballName2, {deleteIfExists: false}, function(error) {
          assert.match(error, /tarball already exists/i);
          assert.equal(test.fileExists(tarballPath2), true);
          test.fileDelete(tarballPath2);
          callback();
        });
      });
    },

    // Test create tarball delete_if_exists option
    function(callback) {
      test.fileDelete(tarballPath3);
      assert.equal(test.fileExists(tarballPath3), false);

      extract.createTarball(bundlePath, dataPath, tarballName3, {deleteIfExists: false}, function(error) {
        assert.ifError(error);
        assert.equal(test.fileExists(tarballPath3), true);

        extract.createTarball(bundlePath, dataPath, tarballName3, {deleteIfExists: true}, function(error) {
          assert.ifError(error);
          assert.equal(test.fileExists(tarballPath3), true);
          test.fileDelete(tarballPath3);
          callback();
        });
      });
    },

    // Test store_in_tarball_name_directory=false
    function(callback) {
      test.fileDelete(tarballPath4);
      assert.equal(test.fileExists(tarballPath4), false);

      extract.createTarball(bundlePath, dataPath, tarballName4, {storeInTarballNameDirectory: false}, function(error) {
        assert.ifError(error);
        assert.equal(test.fileExists(tarballPath4), true);

        extract.getTarballFileList(tarballPath4, function(error, fileList) {
          assert.ifError(error);
          assert.length(fileList, 16);
          for (var i = 0; i < fileList.length; i++) {
            assert.match(fileList[i], /\.\//);
          }
          test.fileDelete(tarballPath4);
          callback();
        });
      });
    },

    // Test store_in_tarball_name_directory=true
    function(callback) {
      var rootDirectoryName = tarballName5.replace('.tar.gz', '');
      test.fileDelete(tarballPath5);
      assert.equal(test.fileExists(tarballPath5), false);

      extract.createTarball(bundlePath, dataPath, tarballName5, {storeInTarballNameDirectory: true}, function(error) {
        assert.ifError(error);
        assert.equal(test.fileExists(tarballPath5), true);

        extract.getTarballFileList(tarballPath5, function(error, fileList) {
          var regexp = new RegExp(sprintf('%s/', rootDirectoryName));
          assert.ifError(error);
          assert.length(fileList, 16);
          for (var i = 0; i < fileList.length; i++) {
            assert.match(fileList[i], regexp);
          }
          test.fileDelete(tarballPath5);
          callback();
        });
      });
    },

    // Test exclude_pattern
    function(callback) {
      test.fileDelete(tarballPath6);
      assert.equal(test.fileExists(tarballPath6), false);

      extract.createTarball(bundlePath, dataPath, tarballName6, {deleteIfExists: false, excludePattern: '*.sh'}, function(error) {
        assert.ifError(error);
        assert.equal(test.fileExists(tarballPath6), true);

        extract.getTarballFileList(tarballPath6, function(error, fileList) {
          assert.ifError(error);
          assert.length(fileList, 14);
          test.fileDelete(tarballPath6);
          callback();
        });
      });
    },

    // Test ignore_file_changed_error
    function(callback) {
      test.fileDelete(tarballPath7);
      assert.equal(test.fileExists(tarballPath7), false);
      extract.createTarball(dataPath, dataPath, tarballName7, {deleteIfExists: false, ignoreFileChangedError: true}, function(error) {
        assert.ifError(error);
        assert.equal(test.fileExists(tarballPath7), true);
        test.fileDelete(tarballPath7);
        callback();
      });
    }
  ],
  function(err) {
    completed = true;
    assert.ifError(err);
  });

  process.on('exit', function() {
    assert.ok(completed, 'Tests completed');
  });
})();
<commit_msg>Port tarball-create.js tests.<commit_after>/*
 * Licensed to Cloudkick, Inc ('Cloudkick') under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * Cloudkick licenses this file to You under the Apache License, Version 2.0
 * (the "License"); you may not use this file except in compliance with
 * the License.  You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

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

var test = require('util/test');
var extract = require('util/tarball');

var sprintf = require('extern/sprintf').sprintf;
var async = require('extern/async');
var assert = require('assert');

var cwd = process.cwd();
var dataPath = path.join(cwd, 'data');
var bundlePath = path.join(dataPath, 'test foo bar');

var tarballName1 = 'foo-bar-1.0.1.tar.gz';
var tarballPath1 = path.join(dataPath, tarballName1);

var tarballName2 = 'foo-bar-1.0.2.tar.gz';
var tarballPath2 = path.join(dataPath, tarballName2);

var tarballName3 = 'foo-bar-1.0.3.tar.gz';
var tarballPath3 = path.join(dataPath, tarballName3);

var tarballName4 = 'foo-bar-1.0.4.tar.gz';
var tarballPath4 = path.join(dataPath, tarballName4);

var tarballName5 = 'foo-bar-1.0.5.tar.gz';
var tarballPath5 = path.join(dataPath, tarballName5);

var tarballName6 = 'foo-bar-1.0.6.tar.gz';
var tarballPath6 = path.join(dataPath, tarballName6);

var tarballName7 = 'foo-bar-1.0.7.tar.gz';
var tarballPath7 = path.join(dataPath, tarballName7);

exports['test_invalid_source_path'] = function() {
  extract.createTarball('/invalid/source/path/', dataPath, tarballName1, {deleteIfExists: false}, function(error) {
    assert.ok(error);
    assert.match(error.message, /source path does not exist/i);
  });
};

exports['test_invalid_target_path'] = function() {
  extract.createTarball(bundlePath, '/invalid/path', tarballName1, {deleteIfExists: false}, function(error) {
    assert.ok(error);
    assert.match(error.message, /target path does not exist/i);
  });
};

exports['test_create_tarball_success'] = function() {
  test.fileDelete(tarballPath1);
  assert.equal(test.fileExists(tarballPath1), false);

  extract.createTarball(bundlePath, dataPath, tarballName1, {deleteIfExists: false}, function(error) {
    assert.ifError(error);
    assert.equal(test.fileExists(tarballPath1), true);
    test.fileDelete(tarballPath1);
  });
};

exports['test_create_tarball_throws_error_upon_existing_file'] = function() {
  test.fileDelete(tarballPath2);
  assert.equal(test.fileExists(tarballPath2), false);

  extract.createTarball(bundlePath, dataPath, tarballName2, {deleteIfExists: false}, function(error) {
    assert.ifError(error);
    assert.equal(test.fileExists(tarballPath2), true);

    extract.createTarball(bundlePath, dataPath, tarballName2, {deleteIfExists: false}, function(error) {
      assert.match(error, /tarball already exists/i);
      assert.equal(test.fileExists(tarballPath2), true);
      test.fileDelete(tarballPath2);
    });
  });
};

exports['test_dele_if_exists_option'] = function() {
  test.fileDelete(tarballPath3);
  assert.equal(test.fileExists(tarballPath3), false);

  extract.createTarball(bundlePath, dataPath, tarballName3, {deleteIfExists: false}, function(error) {
    assert.ifError(error);
    assert.equal(test.fileExists(tarballPath3), true);

    extract.createTarball(bundlePath, dataPath, tarballName3, {deleteIfExists: true}, function(error) {
      assert.ifError(error);
      assert.equal(test.fileExists(tarballPath3), true);
      test.fileDelete(tarballPath3);
    });
  });
};

exports['test_store_in_tarball_name_directory_is_false'] = function() {
  test.fileDelete(tarballPath4);
  assert.equal(test.fileExists(tarballPath4), false);

  extract.createTarball(bundlePath, dataPath, tarballName4, {storeInTarballNameDirectory: false}, function(error) {
    assert.ifError(error);
    assert.equal(test.fileExists(tarballPath4), true);

    extract.getTarballFileList(tarballPath4, function(error, fileList) {
      assert.ifError(error);
      assert.length(fileList, 16);
      for (var i = 0; i < fileList.length; i++) {
        assert.match(fileList[i], /\.\//);
      }
      test.fileDelete(tarballPath4);
    });
  });
};

exports['test_store_in_tarball_name_directory_is_true'] = function() {
  var rootDirectoryName = tarballName5.replace('.tar.gz', '');
  test.fileDelete(tarballPath5);
  assert.equal(test.fileExists(tarballPath5), false);

  extract.createTarball(bundlePath, dataPath, tarballName5, {storeInTarballNameDirectory: true}, function(error) {
    assert.ifError(error);
    assert.equal(test.fileExists(tarballPath5), true);

    extract.getTarballFileList(tarballPath5, function(error, fileList) {
      var regexp = new RegExp(sprintf('%s/', rootDirectoryName));
      assert.ifError(error);
      assert.length(fileList, 16);
      for (var i = 0; i < fileList.length; i++) {
        assert.match(fileList[i], regexp);
      }
      test.fileDelete(tarballPath5);
    });
  });
};

exports['test_exclude_pattern'] = function() {
  test.fileDelete(tarballPath6);
  assert.equal(test.fileExists(tarballPath6), false);

  extract.createTarball(bundlePath, dataPath, tarballName6, {deleteIfExists: false, excludePattern: '*.sh'}, function(error) {
    assert.ifError(error);
    assert.equal(test.fileExists(tarballPath6), true);

    extract.getTarballFileList(tarballPath6, function(error, fileList) {
      assert.ifError(error);
      assert.length(fileList, 14);
      test.fileDelete(tarballPath6);
    });
  });
};

exports['test_ignore_file_changed_error'] = function() {
  test.fileDelete(tarballPath7);
  assert.equal(test.fileExists(tarballPath7), false);
  extract.createTarball(dataPath, dataPath, tarballName7, {deleteIfExists: false, ignoreFileChangedError: true}, function(error) {
    assert.ifError(error);
    assert.equal(test.fileExists(tarballPath7), true);
    test.fileDelete(tarballPath7);
  });
};
<|endoftext|>


<commit_before>'use strict';

var $ = require('jquery');

var SelectivityDropdown = require('./selectivity-dropdown');

/**
 * Methods.
 */
$.extend(SelectivityDropdown.prototype, {

    /**
     * @inherit
     */
    removeCloseHandler: function() {

        if (this._$backdrop && !this.parentMenu) {
            this._$backdrop.remove();
            this._$backdrop = null;
        }
    },

    /**
     * @inherit
     */
    setupCloseHandler: function() {

        var $backdrop;
        if (this.parentMenu) {
            $backdrop = this.parentMenu._$backdrop;
        } else {
            $backdrop = $('<div>').addClass('selectivity-backdrop');

            $('body').append($backdrop);
        }

        $backdrop.on('click', this.close.bind(this));

        this._$backdrop = $backdrop;
    }

});
<commit_msg>Remove backdrop<commit_after><|endoftext|>