<commit_before>'use strict';

var i              = require('es5-ext/lib/Function/i')
  , d              = require('es5-ext/lib/Object/descriptor')
  , startsWith     = require('es5-ext/lib/String/prototype/starts-with')
  , endsWith       = require('es5-ext/lib/String/prototype/ends-with')
  , Plain          = require('./plain')
  , isNamespace    = require('./is-namespace')
  , nameRe         = require('./name-re')
  , RelSetReadOnly = require('./rel-set-read-only')
  , reverse        = require('./rel-reverse')
  , UniqueIndex    = require('./unique-index')
  , dummyNs        = require('./dummy-ns')

  , isArray = Array.isArray
  , defineProperty = Object.defineProperty
  , defineProperties = Object.defineProperties
  , getOwnPropertyNames = Object.getOwnPropertyNames
  , getPrototypeOf = Object.getPrototypeOf
  , isDigit = RegExp.prototype.test.bind(/\d/)

  , Relation, Item, Constructor, define, signal, history;

module.exports = Relation = Plain.create(function (obj, name, descriptor) {
	defineProperties(this, {
		obj: d('', obj),
		name: d.gs('', function () { return name; }),
		_id_: d('', obj._id_ + ':' + name),
		_foreign_: d('w', null),
		_descriptor_: d('', descriptor)
	});
});

Constructor = function (obj) {
	defineProperties(this, {
		obj: d('', obj),
		_id_: d('', obj._id_ + ':' + this.name),
		_foreign_: d('w', null)
	});
};

defineProperties(Relation.prototype, {
	_id_: d(''),
	_create_: d(function (obj) {
		var rel;
		// Avoid Object.create for performance reasons
		Constructor.prototype = this;
		rel = new Constructor(obj);
		if (!this.hasOwnProperty('_children_')) {
			defineProperty(this, '_children_', d('', []));
		}
		this._children_.push(rel);
		return rel;
	}),
	_onOld_: d(function (value) {
		if (this.unique) this._uniqIndex_.remove(this, value);
		if (value && value._id_ && value.ns) reverse.remove(this, value);
	}),
	_onNew_: d(function (value) {
		if (this.unique) this._uniqIndex_.add(this, value);
		if (value && value._id_ && value.ns) reverse.add(this, value);
	}),
	_setVisibility_: d(function (value) {
		if ((value !== undefined) &&
				(!this.obj.hasOwnProperty(this.name) || this._foreign_)) {
			defineProperty(this.obj, this.name, this._descriptor_);
		} else if (!this._foreign_) {
			delete this.obj[this.name];
		}
		if (this._foreign_) this._foreign_ = null;
	}),
	_forEachObject_: d('c', function (cb) {
		getOwnPropertyNames(this).forEach(function (name) {
			var value;
			if (startsWith.call(name, '__')) {
				value = this[name];
				if (!value._id_) return;
			} else if (isDigit(name[0]) && this.propertyIsEnumerable(name)) {
				value = this[name];
				if (!value || !value._id_ || !endsWith.call(value._id_, '"')) return;
			} else {
				return;
			}
			cb(value, value._id_, this);
		}, this);
	}),
	value: d.gs(function () {
		var value = this._value;
		if ((typeof value === 'function') && !value._id_) {
			if (value.length) return value;
			value = value.call(this.obj);
			if (this.multiple) return new RelSetReadOnly(this.ns, value);
			return (value == null) ? null : this.ns.normalize(value);
		}
		if (this.multiple) {
			if (!this.hasOwnProperty('_count_')) this._initSet_();
			return this;
		}
		if (value == null) return value;
		return this.ns.normalize(value);
	}, function self(value) {
		var error = this.validate(value);
		if (error) throw error;
		this.$setMultiValue(value);
	}),
	$setMultiValue: d(function (value) {
		if (this.hasOwnProperty('_count_')) {
			this._reset_(value);
			return;
		}
		if ((value == null) || ((typeof value === 'function') && !value._id_)) {
			this.$setValue(value);
			signal(this, value);
			return;
		}
		if (isArray(value)) {
			this._initSet_();
			this._reset_(value);
			return;
		}
		value = this.ns.is(value) ? value : this.ns.$construct(value);
		this.$setValue(value);
		signal(this, value);
	}),
	$setValue: d(function (value) {
		var oldValue;

		if (!this.hasOwnProperty('_descriptor_')) this._setVisibility_(value);

		oldValue = this.hasOwnProperty('_value') ? this._value : undefined;
		if (value === undefined) {
			delete this._value;
		} else if (!this.hasOwnProperty('_value')) {
			defineProperty(this, '_value', d('cw', value));
		} else {
			this._value = value;
		}

		if ((typeof oldValue === 'function') && !oldValue._id_) oldValue = null;
		if ((typeof value === 'function') && !value._id_) value = null;

		if (oldValue === value) return;
		if (oldValue !== null) this._onOld_(oldValue);
		if (value !== null) this._onNew_(value);
	}),
	find: d(function (value) {
		var obj;
		if (!this.hasOwnProperty('_children_')) return null;
		value = this.ns.normalize(value);
		if (value == null) return null;
		this._children_.some(function self(child) {
			if (child._value === value) {
				obj = child.obj;
				return true;
			}
			if (child.hasOwnProperty('_children_')) {
				return child._children_.some(self);
			}
		});
		return obj || null;
	}),
	_validate_: d(function (original) {
		var key, error, ns = this.ns, value;
		if ((typeof original === 'function') && !original._id_) {
			return new TypeError(original + " is not valid " + ns._id_);
		}
		value = ns.coerce(original);
		if (value == null) {
			return new TypeError(original + " is not valid " + ns._id_);
		}
		if ((error = ns.validate(value))) return error;
		if (!(key = ns._serialize_(value))) {
			return new TypeError(original + " is not valid dbjs value");
		}
		if (this.unique && (error = this._uniqIndex_.validate(this, key, value))) {
			return error;
		}
		return null;
	}),
	_validateValues_: d(function (values) {
		var error, errors;
		values.forEach(function (value) {
			if ((error = this._validate_(value))) {
				if (!errors) errors = [];
				errors.push(error);
			}
		}, this);
		return errors;
	}),
	validate: d(function (value) {
		var error, errors;
		if (this.writeOnce && (this._value != null)) {
			return new TypeError("Property is read-only");
		}
		if (value === undefined) {
			if (this.required && (getPrototypeOf(this)._value == null)) {
				return new TypeError((this.label || this.name) + " is required");
			}
			return null;
		}
		if (value === null) {
			if (this.required) {
				return new TypeError((this.label || this.name) + " is required");
			}
			return null;
		}
		if ((typeof value === 'function') && !value._id_) return null;

		if (isArray(value)) {
			if (!this.multiple) {
				return new TypeError(value + " is not valid " + this.ns._id_);
			}
			if (!value.length) {
				if (!this.required) return null;
				return new TypeError(value + " is not valid " + this.ns._id_);
			}
			if ((errors = this._validateValues_(value))) {
				error = new TypeError(value + " contains invalid values");
				error.errors = errors;
				return error;
			}
			return null;
		}
		return this._validate_(value);
	})
});

define = require('./define-basic');

define(Relation.prototype, 'required', false);
define(Relation.prototype, 'multiple', false);
define(Relation.prototype, 'writeOnce', false);

define(Relation.prototype, 'unique', false);
defineProperties(Relation.prototype.__unique, {
	$setValue: d(function (value) {
		if (value) {
			if (!this.hasOwnProperty('_value')) {
				defineProperty(this.obj, 'unique', this._descriptor_);
			}
			if (this._value) {
				this._value = true;
				return;
			}
			this._value = true;
			defineProperty(this.obj, '_uniqIndex_',
				d('c', new UniqueIndex(this.obj)));
		} else {
			if (!this._value) return;
			delete this._value;
			delete this.obj.unique;
			delete this.obj._uniqIndex_;
			if (this.obj.hasOwnProperty('_children_')) {
				this.obj._children_.forEach(function self(child) {
					if (child.unique) {
						defineProperty(child, '_uniqIndex_',
							d('c', new UniqueIndex(child)));
					} else if (child.hasOwnProperty('_children_')) {
						child._children_.forEach(self);
					}
				});
			}
		}
	}),
	validate: d(function (value) {
		if (!value && this._value && !this.hasOwnProperty('_value')) {
			return new Error("Cannot override unique on extended namespace.");
		}
		return null;
	})
});

define(Relation.prototype, 'reverse', null);
defineProperties(Relation.prototype.__reverse, {
	value: d.gs(function () {
		return this.hasOwnProperty('_value') ? this._value : null;
	}, function self(value) {
		var error;
		value = this._normalize(value);
		if ((error = this.validate(value))) throw error;
		this.$setValue(value);
		signal(this, value);
	}),
	_normalize: d(function (value) {
		if (value === true) {
			value = this.obj.obj.ns._id_;
			value = value[0].toLowerCase() + value.slice(1);
		} else if (value) {
			value = String(value);
		}
		return value;
	}),
	$setValue: d(function (name) {
		if (!name) {
			if (this.hasOwnProperty('_value')) {
				reverse.unset(this.obj, this._value);
				delete this.obj.reverse;
				delete this._value;
			}
			return;
		}
		name = String(name);
		if ((name !== this._value) && this.hasOwnProperty('_value')) {
			reverse.unset(this.obj, this._value);
		}
		reverse.set(this.obj, name);
		if (!this.hasOwnProperty('_value')) {
			defineProperty(this.obj, 'reverse', this._descriptor_);
		}
		this._value = name;
	}),
	validate: d(function (name) {
		if (!name) return null;
		if (name === true) {
			name = this.obj.obj.ns._id_;
			name = name[0].toLowerCase() + name.slice(1);
		} else {
			name = String(name);
		}
		if (name === this._value) return null;
		if (!nameRe.test(name)) return new TypeError(name + " is not a valid name");
		return null;
	})
});

define(Relation.prototype, 'ns', dummyNs);
defineProperties(Relation.prototype.__ns, {
	_normalize: d(i),
	$setValue: d(function (value) {
		var old = this._value, newValue, revName;
		if (value === null) value = Relation.prototype.ns;
		newValue = value;
		if (value === undefined) newValue = getPrototypeOf(this)._value;

		revName = this.obj.hasOwnProperty('reverse') && this.obj.reverse;
		if (revName && (old !== newValue)) reverse.unset(this.obj, revName);

		if (value === undefined) {
			delete this.obj.ns;
			delete this._value;
		} else {
			if (!this.hasOwnProperty('_value')) {
				defineProperty(this.obj, 'ns', this._descriptor_);
			}
			this._value = value;
		}

		if (old === newValue) return;
		if (revName) reverse.set(this.obj, revName);
		if (this.obj.unique) this.obj._uniqIndex_.updateNs(this.obj, old);
	}),
	validate: d(function (value) {
		if (value == null) return null;
		if (!isNamespace(value)) {
			return new TypeError(value + " is not a namespace object");
		}
		return null;
	})
});

require('./rel-set');
Item  = require('./rel-set-item');
signal = require('./signal');
history = signal.history;
<commit_msg>Fix circular dependency issue<commit_after>'use strict';

var i              = require('es5-ext/lib/Function/i')
  , d              = require('es5-ext/lib/Object/descriptor')
  , startsWith     = require('es5-ext/lib/String/prototype/starts-with')
  , endsWith       = require('es5-ext/lib/String/prototype/ends-with')
  , Plain          = require('./plain')
  , isNamespace    = require('./is-namespace')
  , nameRe         = require('./name-re')
  , RelSetReadOnly = require('./rel-set-read-only')
  , UniqueIndex    = require('./unique-index')
  , dummyNs        = require('./dummy-ns')

  , isArray = Array.isArray
  , defineProperty = Object.defineProperty
  , defineProperties = Object.defineProperties
  , getOwnPropertyNames = Object.getOwnPropertyNames
  , getPrototypeOf = Object.getPrototypeOf
  , isDigit = RegExp.prototype.test.bind(/\d/)

  , Relation, Item, Constructor, define, signal, history, reverse;

module.exports = Relation = Plain.create(function (obj, name, descriptor) {
	defineProperties(this, {
		obj: d('', obj),
		name: d.gs('', function () { return name; }),
		_id_: d('', obj._id_ + ':' + name),
		_foreign_: d('w', null),
		_descriptor_: d('', descriptor)
	});
});

Constructor = function (obj) {
	defineProperties(this, {
		obj: d('', obj),
		_id_: d('', obj._id_ + ':' + this.name),
		_foreign_: d('w', null)
	});
};

defineProperties(Relation.prototype, {
	_id_: d(''),
	_create_: d(function (obj) {
		var rel;
		// Avoid Object.create for performance reasons
		Constructor.prototype = this;
		rel = new Constructor(obj);
		if (!this.hasOwnProperty('_children_')) {
			defineProperty(this, '_children_', d('', []));
		}
		this._children_.push(rel);
		return rel;
	}),
	_onOld_: d(function (value) {
		if (this.unique) this._uniqIndex_.remove(this, value);
		if (value && value._id_ && value.ns) reverse.remove(this, value);
	}),
	_onNew_: d(function (value) {
		if (this.unique) this._uniqIndex_.add(this, value);
		if (value && value._id_ && value.ns) reverse.add(this, value);
	}),
	_setVisibility_: d(function (value) {
		if ((value !== undefined) &&
				(!this.obj.hasOwnProperty(this.name) || this._foreign_)) {
			defineProperty(this.obj, this.name, this._descriptor_);
		} else if (!this._foreign_) {
			delete this.obj[this.name];
		}
		if (this._foreign_) this._foreign_ = null;
	}),
	_forEachObject_: d('c', function (cb) {
		getOwnPropertyNames(this).forEach(function (name) {
			var value;
			if (startsWith.call(name, '__')) {
				value = this[name];
				if (!value._id_) return;
			} else if (isDigit(name[0]) && this.propertyIsEnumerable(name)) {
				value = this[name];
				if (!value || !value._id_ || !endsWith.call(value._id_, '"')) return;
			} else {
				return;
			}
			cb(value, value._id_, this);
		}, this);
	}),
	value: d.gs(function () {
		var value = this._value;
		if ((typeof value === 'function') && !value._id_) {
			if (value.length) return value;
			value = value.call(this.obj);
			if (this.multiple) return new RelSetReadOnly(this.ns, value);
			return (value == null) ? null : this.ns.normalize(value);
		}
		if (this.multiple) {
			if (!this.hasOwnProperty('_count_')) this._initSet_();
			return this;
		}
		if (value == null) return value;
		return this.ns.normalize(value);
	}, function self(value) {
		var error = this.validate(value);
		if (error) throw error;
		this.$setMultiValue(value);
	}),
	$setMultiValue: d(function (value) {
		if (this.hasOwnProperty('_count_')) {
			this._reset_(value);
			return;
		}
		if ((value == null) || ((typeof value === 'function') && !value._id_)) {
			this.$setValue(value);
			signal(this, value);
			return;
		}
		if (isArray(value)) {
			this._initSet_();
			this._reset_(value);
			return;
		}
		value = this.ns.is(value) ? value : this.ns.$construct(value);
		this.$setValue(value);
		signal(this, value);
	}),
	$setValue: d(function (value) {
		var oldValue;

		if (!this.hasOwnProperty('_descriptor_')) this._setVisibility_(value);

		oldValue = this.hasOwnProperty('_value') ? this._value : undefined;
		if (value === undefined) {
			delete this._value;
		} else if (!this.hasOwnProperty('_value')) {
			defineProperty(this, '_value', d('cw', value));
		} else {
			this._value = value;
		}

		if ((typeof oldValue === 'function') && !oldValue._id_) oldValue = null;
		if ((typeof value === 'function') && !value._id_) value = null;

		if (oldValue === value) return;
		if (oldValue !== null) this._onOld_(oldValue);
		if (value !== null) this._onNew_(value);
	}),
	find: d(function (value) {
		var obj;
		if (!this.hasOwnProperty('_children_')) return null;
		value = this.ns.normalize(value);
		if (value == null) return null;
		this._children_.some(function self(child) {
			if (child._value === value) {
				obj = child.obj;
				return true;
			}
			if (child.hasOwnProperty('_children_')) {
				return child._children_.some(self);
			}
		});
		return obj || null;
	}),
	_validate_: d(function (original) {
		var key, error, ns = this.ns, value;
		if ((typeof original === 'function') && !original._id_) {
			return new TypeError(original + " is not valid " + ns._id_);
		}
		value = ns.coerce(original);
		if (value == null) {
			return new TypeError(original + " is not valid " + ns._id_);
		}
		if ((error = ns.validate(value))) return error;
		if (!(key = ns._serialize_(value))) {
			return new TypeError(original + " is not valid dbjs value");
		}
		if (this.unique && (error = this._uniqIndex_.validate(this, key, value))) {
			return error;
		}
		return null;
	}),
	_validateValues_: d(function (values) {
		var error, errors;
		values.forEach(function (value) {
			if ((error = this._validate_(value))) {
				if (!errors) errors = [];
				errors.push(error);
			}
		}, this);
		return errors;
	}),
	validate: d(function (value) {
		var error, errors;
		if (this.writeOnce && (this._value != null)) {
			return new TypeError("Property is read-only");
		}
		if (value === undefined) {
			if (this.required && (getPrototypeOf(this)._value == null)) {
				return new TypeError((this.label || this.name) + " is required");
			}
			return null;
		}
		if (value === null) {
			if (this.required) {
				return new TypeError((this.label || this.name) + " is required");
			}
			return null;
		}
		if ((typeof value === 'function') && !value._id_) return null;

		if (isArray(value)) {
			if (!this.multiple) {
				return new TypeError(value + " is not valid " + this.ns._id_);
			}
			if (!value.length) {
				if (!this.required) return null;
				return new TypeError(value + " is not valid " + this.ns._id_);
			}
			if ((errors = this._validateValues_(value))) {
				error = new TypeError(value + " contains invalid values");
				error.errors = errors;
				return error;
			}
			return null;
		}
		return this._validate_(value);
	})
});

define = require('./define-basic');

define(Relation.prototype, 'required', false);
define(Relation.prototype, 'multiple', false);
define(Relation.prototype, 'writeOnce', false);

define(Relation.prototype, 'unique', false);
defineProperties(Relation.prototype.__unique, {
	$setValue: d(function (value) {
		if (value) {
			if (!this.hasOwnProperty('_value')) {
				defineProperty(this.obj, 'unique', this._descriptor_);
			}
			if (this._value) {
				this._value = true;
				return;
			}
			this._value = true;
			defineProperty(this.obj, '_uniqIndex_',
				d('c', new UniqueIndex(this.obj)));
		} else {
			if (!this._value) return;
			delete this._value;
			delete this.obj.unique;
			delete this.obj._uniqIndex_;
			if (this.obj.hasOwnProperty('_children_')) {
				this.obj._children_.forEach(function self(child) {
					if (child.unique) {
						defineProperty(child, '_uniqIndex_',
							d('c', new UniqueIndex(child)));
					} else if (child.hasOwnProperty('_children_')) {
						child._children_.forEach(self);
					}
				});
			}
		}
	}),
	validate: d(function (value) {
		if (!value && this._value && !this.hasOwnProperty('_value')) {
			return new Error("Cannot override unique on extended namespace.");
		}
		return null;
	})
});

define(Relation.prototype, 'reverse', null);
defineProperties(Relation.prototype.__reverse, {
	value: d.gs(function () {
		return this.hasOwnProperty('_value') ? this._value : null;
	}, function self(value) {
		var error;
		value = this._normalize(value);
		if ((error = this.validate(value))) throw error;
		this.$setValue(value);
		signal(this, value);
	}),
	_normalize: d(function (value) {
		if (value === true) {
			value = this.obj.obj.ns._id_;
			value = value[0].toLowerCase() + value.slice(1);
		} else if (value) {
			value = String(value);
		}
		return value;
	}),
	$setValue: d(function (name) {
		if (!name) {
			if (this.hasOwnProperty('_value')) {
				reverse.unset(this.obj, this._value);
				delete this.obj.reverse;
				delete this._value;
			}
			return;
		}
		name = String(name);
		if ((name !== this._value) && this.hasOwnProperty('_value')) {
			reverse.unset(this.obj, this._value);
		}
		reverse.set(this.obj, name);
		if (!this.hasOwnProperty('_value')) {
			defineProperty(this.obj, 'reverse', this._descriptor_);
		}
		this._value = name;
	}),
	validate: d(function (name) {
		if (!name) return null;
		if (name === true) {
			name = this.obj.obj.ns._id_;
			name = name[0].toLowerCase() + name.slice(1);
		} else {
			name = String(name);
		}
		if (name === this._value) return null;
		if (!nameRe.test(name)) return new TypeError(name + " is not a valid name");
		return null;
	})
});

define(Relation.prototype, 'ns', dummyNs);
defineProperties(Relation.prototype.__ns, {
	_normalize: d(i),
	$setValue: d(function (value) {
		var old = this._value, newValue, revName;
		if (value === null) value = Relation.prototype.ns;
		newValue = value;
		if (value === undefined) newValue = getPrototypeOf(this)._value;

		revName = this.obj.hasOwnProperty('reverse') && this.obj.reverse;
		if (revName && (old !== newValue)) reverse.unset(this.obj, revName);

		if (value === undefined) {
			delete this.obj.ns;
			delete this._value;
		} else {
			if (!this.hasOwnProperty('_value')) {
				defineProperty(this.obj, 'ns', this._descriptor_);
			}
			this._value = value;
		}

		if (old === newValue) return;
		if (revName) reverse.set(this.obj, revName);
		if (this.obj.unique) this.obj._uniqIndex_.updateNs(this.obj, old);
	}),
	validate: d(function (value) {
		if (value == null) return null;
		if (!isNamespace(value)) {
			return new TypeError(value + " is not a namespace object");
		}
		return null;
	})
});

require('./rel-set');
Item  = require('./rel-set-item');
reverse = require('./rel-reverse');
signal = require('./signal');
history = signal.history;
<|endoftext|>


<commit_before>function convertObjectToArray(obj) {
  var outputArray = [];

  Object.keys(obj).forEach(function (key) {
    var keyAsIndex = Number(key);
    if (!isNaN(keyAsIndex) && keyAsIndex > -1) {
      outputArray[keyAsIndex] = obj[key];
    } else {
      // attach it as a property
      outputArray[key] = obj[key];
    }
  });

  return outputArray;
}

function isArguments(x) {
  return Object.prototype.toString.call(x) === '[object Arguments]';
}

function isArrayOrArguments(x) {
  return Array.isArray(x) || isArguments(x);
}

function isComparingObjectAndArray(lhs, rhs) {
  var typeLhs = lhs && typeof lhs;
  var typeRhs = rhs && typeof rhs;

  return ((isArrayOrArguments(lhs) && isObject(rhs)) ||
          (isArrayOrArguments(rhs) && isObject(lhs)));
}

function isDate(x) {
  if (!x) {
    return false;
  }

  return Object.prototype.toString.call(x) === '[object Date]';
}

function isObject(x) {
  return typeof x === 'object';
}

function isRegExp(x) {
  return x instanceof RegExp;
}

function isString(x) {
  return typeof x === 'string';
}

function assertTheUnexpected(expect) {
  function AssertionError(err, options) {
    if (!(this instanceof AssertionError)) {
      return null;
    }
    Error.call(this, '');
    err = err || {};
    options = options || {};

    this.name = 'AssertionError';

    var assertMessage = (options.message || err.message);

    this.stack = this.name + ': ' + assertMessage + '\n\n' + (err.stack || '');
    this.message = assertMessage;
  }

  AssertionError.prototype = Object.create(Error.prototype);

  function createWrappedExpect(localExpect) {
    return function wrappedExpect() {
      var args = Array.prototype.slice.apply(arguments);
      // convert UnexpectedError to AssertionError
      try {
        localExpect.apply(localExpect, args);
      } catch (err) {
        throw new AssertionError(err);
      }
    };
  }

  var wrappedExpect = createWrappedExpect(expect);

  function catchErrorAndThrowOriginal(block) {
    try {
      block();
   } catch (e) {
      if (e.originalError) {
        throw e.originalError;
      } else {
        throw new AssertionError(e, {
          message: 'Missing expected exception..'
        });
      }
    }
  }

  function checkNotThrow(block, errorConstraint) {
    try {
      expect(function () {
        block();
      }, 'not to error');
    } catch (e) {
      var blockError = e.originalError;

      try {
        expect(blockError, 'not to be a', errorConstraint);
      } catch (e2) {
        throw new AssertionError(blockError);
      }

      throw blockError;
    }
  }

  function checkThrows(block, errorConstraint) {
    function checkError(blockError) {
      if (isRegExp(errorConstraint)) {
        expect(blockError, 'to have message', errorConstraint).catch(function () {
          throw new AssertionError(blockError);
        });
      } else {
        try {
          expect(blockError, 'to be a', errorConstraint);
        } catch (e) {
          expect(errorConstraint(blockError), 'to be truthy').catch(function () {
            throw blockError;
          });
        }
      }
    }

    catchErrorAndThrowOriginal(function () {
      expect(function () {
        block();
      }, 'to error', function (blockError) {
        if (errorConstraint) {
          checkError(blockError);
        }
      });
    });
  }

  function checkTruthy(value) {
    wrappedExpect(value, 'to be truthy');
  }

  function prepareDeepEqual(actual, expected) {
    var a = actual;
    var b = expected;

    if (Array.isArray(a) && Array.isArray(b)) {
      a = a.slice(0);
      b = b.slice(0);

      for (var i = 0; i < a.length; i += 1) {
        var comparisonValues = prepareEqual(a[i], b[i]);
        a[i] = comparisonValues.a;
        b[i] = comparisonValues.b;
      }

      return {
        a: a,
        b: b
      };
    } else if (isComparingObjectAndArray(a, b)) {
      if (isArguments(a) || isArguments(b)) {
        return {
          a: a,
          b: b
        };
      }

      if (Array.isArray(a)) {
        return {
          a: a,
          b: convertObjectToArray(b)
        };
      } else {
        return {
          a: convertObjectToArray(a),
          b: b
        };
      }
    } else if (
        (isObject(a) && isObject(b)) &&
        !(isDate(a) && isDate(b)) &&
        !(isRegExp(a) && isRegExp(b)) &&
        !(a === null || b === null)
    ) {
      return {
        a: Object.assign({}, a),
        b: Object.assign({}, b)
      }
    }

    return null;
  }

  function prepareEqual(actual, expected) {
    var a = !actual;
    var b = !expected;

    // undo the null and undefined evaluate equal
    if (!(a && b) && !(typeof actual === 'boolean' || typeof expected === 'boolean')) {
      a = actual;
      b = expected;
    }

    if ((Number(a) || Number(b)) && (isString(a) || isString(b))) {
      a = String(a);
      b = String(b);
    }

    return {
      a: a,
      b: b
    };
  }

  return Object.assign(function (value) {
    checkTruthy(value);
  }, {
    AssertionError: AssertionError,
    deepEqual: function deepEqual(actual, expected) {
      var a = actual;
      var b = expected;
      var comparisonValues;

      // first type deep equal preparation
      comparisonValues = prepareDeepEqual(a, b);

      if (!comparisonValues && !(isObject(a) || isObject(b))) {
        comparisonValues = prepareEqual(a, b);
      }

      if (comparisonValues) {
        a = comparisonValues.a;
        b = comparisonValues.b;
      }

      wrappedExpect(a, 'to equal', b);

      // handle the lastIndex property
      if (actual instanceof RegExp && actual.hasOwnProperty('lastIndex')) {
        wrappedExpect(actual.lastIndex, 'to equal', expected.lastIndex);
      }
    },
    deepStrictEqual: function deepStrictEqual(actual, expected) {
      wrappedExpect(actual, 'to equal', expected);

      if (typeof actual === 'symbol') {
        wrappedExpect('symbol', 'to equal', typeof expected);
      }

      // handle the lastIndex property
      if (actual instanceof RegExp && actual.hasOwnProperty('lastIndex')) {
        wrappedExpect(actual.lastIndex, 'to equal', expected.lastIndex);
      }
    },
    doesNotThrow: function (block, expected) {
      checkNotThrow(block, expected);
    },
    equal: function equal(actual, expected) {
      var comarisonValues = prepareEqual(actual, expected);
      var a = comarisonValues.a;
      var b = comarisonValues.b;

      wrappedExpect(a, 'to be', b);
    },
    ifError: function ifError(value) {
      wrappedExpect(value, 'to be falsy').then(function () {
        throw value;
      });
    },
    notEqual: function notEqual(actual, expected) {
      wrappedExpect(actual, 'not to be', expected);
    },
    notDeepEqual: function notDeepEqual(actual, expected) {
      wrappedExpect(actual, 'not to equal', expected);
    },
    notDeepStrictEqual: function notDeepStrictEqual(actual, expected) {
      wrappedExpect(actual, 'not to equal', expected);
    },
    notStrictEqual: function notStrictEqual(actual, expected) {
      wrappedExpect(actual, 'not to be', expected);
    },
    ok: function (value) {
      checkTruthy(value);
    },
    strictEqual: function strictEqual(actual, expected) {
      wrappedExpect(actual, 'to be', expected);
    },
    throws: function (block, expected) {
      checkThrows(block, expected);
    }
  });
}

module.exports = assertTheUnexpected(require('unexpected'));
<commit_msg>Make our internally created errors inherit from AssertionError.<commit_after>var AssertionError = require('assert').AssertionError;

function convertObjectToArray(obj) {
  var outputArray = [];

  Object.keys(obj).forEach(function (key) {
    var keyAsIndex = Number(key);
    if (!isNaN(keyAsIndex) && keyAsIndex > -1) {
      outputArray[keyAsIndex] = obj[key];
    } else {
      // attach it as a property
      outputArray[key] = obj[key];
    }
  });

  return outputArray;
}

function isArguments(x) {
  return Object.prototype.toString.call(x) === '[object Arguments]';
}

function isArrayOrArguments(x) {
  return Array.isArray(x) || isArguments(x);
}

function isComparingObjectAndArray(lhs, rhs) {
  var typeLhs = lhs && typeof lhs;
  var typeRhs = rhs && typeof rhs;

  return ((isArrayOrArguments(lhs) && isObject(rhs)) ||
          (isArrayOrArguments(rhs) && isObject(lhs)));
}

function isDate(x) {
  if (!x) {
    return false;
  }

  return Object.prototype.toString.call(x) === '[object Date]';
}

function isObject(x) {
  return typeof x === 'object';
}

function isRegExp(x) {
  return x instanceof RegExp;
}

function isString(x) {
  return typeof x === 'string';
}

function assertTheUnexpected(expect) {
  function UnexpectedAssertError(err, options) {
    if (!(this instanceof UnexpectedAssertError)) {
      return null;
    }
    AssertionError.call(this, '');
    err = err || {};
    options = options || {};

    var assertMessage = (options.message || err.message);

    this.stack = this.name + ': ' + assertMessage + '\n\n' + (err.stack || '');
    this.message = assertMessage;
  }

  UnexpectedAssertError.prototype = Object.create(AssertionError.prototype);

  function createWrappedExpect(localExpect) {
    return function wrappedExpect() {
      var args = Array.prototype.slice.apply(arguments);
      // convert UnexpectedError to AssertionError
      try {
        localExpect.apply(localExpect, args);
      } catch (err) {
        throw new UnexpectedAssertError(err);
      }
    };
  }

  var wrappedExpect = createWrappedExpect(expect);

  function catchErrorAndThrowOriginal(block) {
    try {
      block();
   } catch (e) {
      if (e.originalError) {
        throw e.originalError;
      } else {
        throw new UnexpectedAssertError(e, {
          message: 'Missing expected exception..'
        });
      }
    }
  }

  function checkNotThrow(block, errorConstraint) {
    try {
      expect(function () {
        block();
      }, 'not to error');
    } catch (e) {
      var blockError = e.originalError;

      try {
        expect(blockError, 'not to be a', errorConstraint);
      } catch (e2) {
        throw new UnexpectedAssertError(blockError);
      }

      throw blockError;
    }
  }

  function checkThrows(block, errorConstraint) {
    function checkError(blockError) {
      if (isRegExp(errorConstraint)) {
        expect(blockError, 'to have message', errorConstraint).catch(function () {
          throw new UnexpectedAssertError(blockError);
        });
      } else {
        try {
          expect(blockError, 'to be a', errorConstraint);
        } catch (e) {
          expect(errorConstraint(blockError), 'to be truthy').catch(function () {
            throw blockError;
          });
        }
      }
    }

    catchErrorAndThrowOriginal(function () {
      expect(function () {
        block();
      }, 'to error', function (blockError) {
        if (errorConstraint) {
          checkError(blockError);
        }
      });
    });
  }

  function checkTruthy(value) {
    wrappedExpect(value, 'to be truthy');
  }

  function prepareDeepEqual(actual, expected) {
    var a = actual;
    var b = expected;

    if (Array.isArray(a) && Array.isArray(b)) {
      a = a.slice(0);
      b = b.slice(0);

      for (var i = 0; i < a.length; i += 1) {
        var comparisonValues = prepareEqual(a[i], b[i]);
        a[i] = comparisonValues.a;
        b[i] = comparisonValues.b;
      }

      return {
        a: a,
        b: b
      };
    } else if (isComparingObjectAndArray(a, b)) {
      if (isArguments(a) || isArguments(b)) {
        return {
          a: a,
          b: b
        };
      }

      if (Array.isArray(a)) {
        return {
          a: a,
          b: convertObjectToArray(b)
        };
      } else {
        return {
          a: convertObjectToArray(a),
          b: b
        };
      }
    } else if (
        (isObject(a) && isObject(b)) &&
        !(isDate(a) && isDate(b)) &&
        !(isRegExp(a) && isRegExp(b)) &&
        !(a === null || b === null)
    ) {
      return {
        a: Object.assign({}, a),
        b: Object.assign({}, b)
      }
    }

    return null;
  }

  function prepareEqual(actual, expected) {
    var a = !actual;
    var b = !expected;

    // undo the null and undefined evaluate equal
    if (!(a && b) && !(typeof actual === 'boolean' || typeof expected === 'boolean')) {
      a = actual;
      b = expected;
    }

    if ((Number(a) || Number(b)) && (isString(a) || isString(b))) {
      a = String(a);
      b = String(b);
    }

    return {
      a: a,
      b: b
    };
  }

  return Object.assign(function (value) {
    checkTruthy(value);
  }, {
    AssertionError: UnexpectedAssertError,
    deepEqual: function deepEqual(actual, expected) {
      var a = actual;
      var b = expected;
      var comparisonValues;

      // first type deep equal preparation
      comparisonValues = prepareDeepEqual(a, b);

      if (!comparisonValues && !(isObject(a) || isObject(b))) {
        comparisonValues = prepareEqual(a, b);
      }

      if (comparisonValues) {
        a = comparisonValues.a;
        b = comparisonValues.b;
      }

      wrappedExpect(a, 'to equal', b);

      // handle the lastIndex property
      if (actual instanceof RegExp && actual.hasOwnProperty('lastIndex')) {
        wrappedExpect(actual.lastIndex, 'to equal', expected.lastIndex);
      }
    },
    deepStrictEqual: function deepStrictEqual(actual, expected) {
      wrappedExpect(actual, 'to equal', expected);

      if (typeof actual === 'symbol') {
        wrappedExpect('symbol', 'to equal', typeof expected);
      }

      // handle the lastIndex property
      if (actual instanceof RegExp && actual.hasOwnProperty('lastIndex')) {
        wrappedExpect(actual.lastIndex, 'to equal', expected.lastIndex);
      }
    },
    doesNotThrow: function (block, expected) {
      checkNotThrow(block, expected);
    },
    equal: function equal(actual, expected) {
      var comarisonValues = prepareEqual(actual, expected);
      var a = comarisonValues.a;
      var b = comarisonValues.b;

      wrappedExpect(a, 'to be', b);
    },
    ifError: function ifError(value) {
      wrappedExpect(value, 'to be falsy').then(function () {
        throw value;
      });
    },
    notEqual: function notEqual(actual, expected) {
      wrappedExpect(actual, 'not to be', expected);
    },
    notDeepEqual: function notDeepEqual(actual, expected) {
      wrappedExpect(actual, 'not to equal', expected);
    },
    notDeepStrictEqual: function notDeepStrictEqual(actual, expected) {
      wrappedExpect(actual, 'not to equal', expected);
    },
    notStrictEqual: function notStrictEqual(actual, expected) {
      wrappedExpect(actual, 'not to be', expected);
    },
    ok: function (value) {
      checkTruthy(value);
    },
    strictEqual: function strictEqual(actual, expected) {
      wrappedExpect(actual, 'to be', expected);
    },
    throws: function (block, expected) {
      checkThrows(block, expected);
    }
  });
}

module.exports = assertTheUnexpected(require('unexpected'));
<|endoftext|>


<commit_before>import path from 'path';
import Promise from 'bluebird';
import { exec as execCallback, spawn } from 'child_process';
import sane from 'sane';
import nsp from 'nsp';
import ui from '../lib/ui';
import Command from '../lib/command';
import BuildCommand from './build';
import assign from 'lodash/assign';

const exec = Promise.promisify(execCallback);

export default class ServerCommand extends Command {

  static commandName = 'server';
  static description = 'Runs the denali server for local or production use.';
  static longDescription = `
Launches the Denali server running your application.

In a development environment, the server does several things:

 * watches your local filesystem for changes and automatically restarts for
   you.
 * comes bundled with node-inspector under the --debug flag to easily start a
   debugging environment
 * lint your code on startup
 * run a security audit of your package.json on startup (via nsp)
 * run a MailDev server to capture outgoing emails sent by your app

In production, the above features are disabled by default, and instead:

 * the server will fork worker processes to maximize CPU core usage
  `;

  params = [];

  flags = {
    environment: {
      description: 'The environment to run as, i.e. `production` (defaults to $DENALI_ENV, $NODE_ENV, or development)',
      defaultValue: process.env.DENALI_ENV || process.env.NODE_ENV || 'development',
      type: String
    },
    debug: {
      description: 'Run in debug mode (add the --debug flag to node, launch node-inspector)',
      defaultValue: false,
      type: Boolean
    },
    watch: {
      description: 'Restart the server when the source files change (default: true in development)',
      defaultValue: null,
      type: Boolean
    },
    port: {
      description: 'The port the HTTP server should bind to (default: 3000)',
      defaultValue: 3000,
      type: Number
    },
    lint: {
      description: 'Lint the app source files (default: true in development)',
      defaultValue: null,
      type: Boolean
    },
    mail: {
      description: 'Start MailDev to capture development emails for debugging (default: false)',
      defaultValue: false,
      type: Boolean
    },
    skipAudit: {
      description: 'Skip auditing your package.json for vulnerabilites (default: false)',
      defaultValue: false,
      type: Boolean
    }
  };

  runsInApp = true;

  run({ flags }) {
    if (flags.watch == null) {
      flags.watch = flags.environment === 'development';
    }
    if (flags.lint == null) {
      flags.lint = flags.environment !== 'production';
    }

    this.environment = assign({}, process.env);
    if (flags.port) {
      this.environment.PORT = flags.port;
    }
    if (flags.environment) {
      this.environment.DENALI_ENV = flags.environment;
      this.environment.NODE_ENV = flags.environment;
    }

    if (flags.debug) {
      this.debug = true;
    }

    if (flags.mail) {
      this.startMailDev();
    }

    if (!flags.skipAudit) {
      this.auditPackages();
    }

    if (flags.lint) {
      this.lint = true;
    }

    if (flags.watch) {
      this.startWatching();
    } else {
      this.startServer();
    }
  }

  startMailDev() {
    let maildevPath = path.join('node_modules', '.bin', 'maildev');
    spawn(maildevPath);
    ui.debug('Starting MailDev server, visit http://localhost:1080 to view sent emails');
  }

  startWatching() {
    this.watcher = sane('.', { glob: [ 'app/**/*.js', 'config/**/*.js' ] });
    this.watcher.on('ready', () => {
      this.startServer().then(() => {
        this.server.on('exit', (code) => {
          let result = code === 0 ? 'exited' : 'crashed';
          ui.error(`Server ${ result }. waiting for changes to restart ...`);
        });
      });
    });
    this.watcher.on('change', this.restartServer.bind(this));
    this.watcher.on('add', this.restartServer.bind(this));
    this.watcher.on('delete', this.restartServer.bind(this));
  }

  startServer() {
    return Promise.resolve().then(() => {
      if (this.lint) {
        return new Promise((resolve, reject) => {
          exec('./node_modules/.bin/eslint app/**/*.js config/**/*.js', (err, stdout, stderr) => {
            if (err) {
              ui.warn('Linting failed:');
              ui.raw('warn', stdout);
              ui.raw('warn', stderr);
              if (this.environment === 'test') {
                return reject(err);
              }
            }
            ui.raw('info', stdout);
            resolve();
          });
        });
      }
    }).finally(() => {
      return BuildCommand.prototype.build.call(this);
    }).then(() => {
      let args = [ 'index.js' ];
      if (this.debug) {
        args.unshift('--inspect=9229 --debug-brk');
      }
      this.server = spawn('node', args, {
        stdio: [ 'pipe', process.stdout, process.stderr ],
        env: this.environment
      });
    });
  }

  restartServer() {
    if (this.server) {
      this.server.removeAllListeners('exit');
      this.server.kill();
    }
    this.startServer();
  }

  auditPackages() {
    nsp.check({ package: path.resolve('package.json') }, (err, results) => {
      if (err && [ 'ENOTFOUND', 'ECONNRESET' ].includes(err.code)) {
        ui.warn('Error trying to scan package dependencies for vulnerabilities with nsp, skipping scan ...');
        ui.warn(err);
      }
      if (results && results.length > 0) {
        ui.warn('WARNING: Some packages in your package.json may have security vulnerabilities:');
        results.forEach((item) => {
          ui.warn(`${ item.module }: ${ item.recommendation }`);
        });
      }
    });
  }

}
<commit_msg>clean up security vulnerability reporting output<commit_after>import path from 'path';
import Promise from 'bluebird';
import { exec as execCallback, spawn } from 'child_process';
import sane from 'sane';
import nsp from 'nsp';
import ui from '../lib/ui';
import Command from '../lib/command';
import BuildCommand from './build';
import assign from 'lodash/assign';
import chalk from 'chalk';

const exec = Promise.promisify(execCallback);

export default class ServerCommand extends Command {

  static commandName = 'server';
  static description = 'Runs the denali server for local or production use.';
  static longDescription = `
Launches the Denali server running your application.

In a development environment, the server does several things:

 * watches your local filesystem for changes and automatically restarts for
   you.
 * comes bundled with node-inspector under the --debug flag to easily start a
   debugging environment
 * lint your code on startup
 * run a security audit of your package.json on startup (via nsp)
 * run a MailDev server to capture outgoing emails sent by your app

In production, the above features are disabled by default, and instead:

 * the server will fork worker processes to maximize CPU core usage
  `;

  params = [];

  flags = {
    environment: {
      description: 'The environment to run as, i.e. `production` (defaults to $DENALI_ENV, $NODE_ENV, or development)',
      defaultValue: process.env.DENALI_ENV || process.env.NODE_ENV || 'development',
      type: String
    },
    debug: {
      description: 'Run in debug mode (add the --debug flag to node, launch node-inspector)',
      defaultValue: false,
      type: Boolean
    },
    watch: {
      description: 'Restart the server when the source files change (default: true in development)',
      defaultValue: null,
      type: Boolean
    },
    port: {
      description: 'The port the HTTP server should bind to (default: 3000)',
      defaultValue: 3000,
      type: Number
    },
    lint: {
      description: 'Lint the app source files (default: true in development)',
      defaultValue: null,
      type: Boolean
    },
    mail: {
      description: 'Start MailDev to capture development emails for debugging (default: false)',
      defaultValue: false,
      type: Boolean
    },
    skipAudit: {
      description: 'Skip auditing your package.json for vulnerabilites (default: false)',
      defaultValue: false,
      type: Boolean
    }
  };

  runsInApp = true;

  run({ flags }) {
    if (flags.watch == null) {
      flags.watch = flags.environment === 'development';
    }
    if (flags.lint == null) {
      flags.lint = flags.environment !== 'production';
    }

    this.environment = assign({}, process.env);
    if (flags.port) {
      this.environment.PORT = flags.port;
    }
    if (flags.environment) {
      this.environment.DENALI_ENV = flags.environment;
      this.environment.NODE_ENV = flags.environment;
    }

    if (flags.debug) {
      this.debug = true;
    }

    if (flags.mail) {
      this.startMailDev();
    }

    if (!flags.skipAudit) {
      this.auditPackages();
    }

    if (flags.lint) {
      this.lint = true;
    }

    if (flags.watch) {
      this.startWatching();
    } else {
      this.startServer();
    }
  }

  startMailDev() {
    let maildevPath = path.join('node_modules', '.bin', 'maildev');
    spawn(maildevPath);
    ui.debug('Starting MailDev server, visit http://localhost:1080 to view sent emails');
  }

  startWatching() {
    this.watcher = sane('.', { glob: [ 'app/**/*.js', 'config/**/*.js' ] });
    this.watcher.on('ready', () => {
      this.startServer().then(() => {
        this.server.on('exit', (code) => {
          let result = code === 0 ? 'exited' : 'crashed';
          ui.error(`Server ${ result }. waiting for changes to restart ...`);
        });
      });
    });
    this.watcher.on('change', this.restartServer.bind(this));
    this.watcher.on('add', this.restartServer.bind(this));
    this.watcher.on('delete', this.restartServer.bind(this));
  }

  startServer() {
    return Promise.resolve().then(() => {
      if (this.lint) {
        return new Promise((resolve, reject) => {
          exec('./node_modules/.bin/eslint app/**/*.js config/**/*.js', (err, stdout, stderr) => {
            if (err) {
              ui.warn('Linting failed:');
              ui.raw('warn', stdout);
              ui.raw('warn', stderr);
              if (this.environment === 'test') {
                return reject(err);
              }
            }
            ui.raw('info', stdout);
            resolve();
          });
        });
      }
    }).finally(() => {
      return BuildCommand.prototype.build.call(this);
    }).then(() => {
      let args = [ 'index.js' ];
      if (this.debug) {
        args.unshift('--inspect=9229 --debug-brk');
      }
      this.server = spawn('node', args, {
        stdio: [ 'pipe', process.stdout, process.stderr ],
        env: this.environment
      });
    });
  }

  restartServer() {
    if (this.server) {
      this.server.removeAllListeners('exit');
      this.server.kill();
    }
    this.startServer();
  }

  auditPackages() {
    nsp.check({ package: path.resolve('package.json') }, (err, results) => {
      if (err && [ 'ENOTFOUND', 'ECONNRESET' ].includes(err.code)) {
        ui.warn('Error trying to scan package dependencies for vulnerabilities with nsp, skipping scan ...');
        ui.warn(err);
      }
      if (results && results.length > 0) {
        ui.warn('WARNING: Some packages in your package.json may have security vulnerabilities:');
        results.forEach((item) => {
          let module = `** ${ item.module }@${ item.version } **`;
          ui.warn(`${ chalk.bold(module) } ${ chalk.reset.cyan(item.recommendation.replace(/\n/g, ' ')) }`);
        });
      }
    });
  }

}
<|endoftext|>


<commit_before>/* ng-FitText.js v2.4.0
 * https://github.com/patrickmarabeas/ng-FitText.js
 *
 * Original jQuery project: https://github.com/davatron5000/FitText.js
 * Includes use of Underscore's debounce function
 *
 * Copyright 2014, Patrick Marabeas http://marabeas.io
 * Released under the MIT license
 * http://opensource.org/licenses/mit-license.php
 *
 * Date: 28/04/2014
 */

'use strict';

angular.module( 'ngFitText', [] )
  .value( 'config', {
    'debounce': false,
    'delay': 250,
    'min': undefined,
    'max': undefined
  })

  .directive( 'fittext', [ 'config', 'fitTextConfig', function( config, fitTextConfig ) {
    return {
      restrict: 'A',
      scope: true,
      transclude: true,
      replace: true,
      template: function( element, attrs ) {
        var tag = element[0].nodeName;
        return "<" + tag + " data-ng-transclude data-ng-style='{fontSize:fontSize}'></" + tag + ">";
      },
      link: function( scope, element, attrs ) {
        angular.extend( config, fitTextConfig.config );

        scope.compressor = attrs.fittext || 1;
        scope.minFontSize = attrs.fittextMin || config.min || Number.NEGATIVE_INFINITY;
        scope.maxFontSize = attrs.fittextMax || config.max || Number.POSITIVE_INFINITY;
        scope.elementWidth = element[0].offsetWidth;

        ( scope.resizer = function() {
          scope.elementWidth = element[0].offsetWidth;
          scope.fontSize = Math.max(
            Math.min(
              scope.elementWidth / ( scope.compressor * 10 ),
              parseFloat( scope.maxFontSize )
            ),
            parseFloat( scope.minFontSize )
          ) + 'px';

        })();

        config.debounce == true
          ? angular.element( window ).bind( 'resize', _debounce( function(){ scope.$apply( scope.resizer )}, config.delay ))
          : angular.element( window ).bind( 'resize', function(){ scope.$apply( scope.resizer )});

        function _debounce(a,b,c){var d;return function(){var e=this,f=arguments;clearTimeout(d),d=setTimeout(function(){d=null,c||a.apply(e,f)},b),c&&!d&&a.apply(e,f)}}
      }
    }
  }])

  .provider( 'fitTextConfig', function() {
    var self = this;
    this.config = {};
    this.$get = function() {
      var extend = {};
      extend.config = self.config;
      return extend;
    };
    return this;
  });<commit_msg>Initial code for auto 100% width<commit_after>/* ng-FitText.js v2.4.0
 * https://github.com/patrickmarabeas/ng-FitText.js
 *
 * Original jQuery project: https://github.com/davatron5000/FitText.js
 * Includes use of Underscore's debounce function
 *
 * Copyright 2014, Patrick Marabeas http://marabeas.io
 * Released under the MIT license
 * http://opensource.org/licenses/mit-license.php
 *
 * Date: 28/04/2014
 */

'use strict';

angular.module( 'ngFitText', [] )
  .value( 'config', {
    'debounce': false,
    'delay': 250,
    'min': undefined,
    'max': undefined
  })

  .directive( 'fittext', [ '$timeout', 'config', 'fitTextConfig', function( $timeout, config, fitTextConfig ) {
    return {
      restrict: 'A',
      scope: true,
      transclude: true,
      replace: true,
      template: function( element, attrs ) {
        var tag = element[0].nodeName;
        return "<" + tag + " data-ng-transclude data-ng-style='{fontSize:fontSize}'></" + tag + ">";
      },
      link: function( scope, element, attrs ) {
        angular.extend( config, fitTextConfig.config );

        scope.compressor = attrs.fittext || 'width100';
        scope.minFontSize = attrs.fittextMin || config.min || Number.NEGATIVE_INFINITY;
        scope.maxFontSize = attrs.fittextMax || config.max || Number.POSITIVE_INFINITY;

        element.children()[0].style.display = 'inline-block';
        element.children()[0].style.lineHeight = '1';

        ( scope.resizer = function() {

          scope.fontSize = ( scope.compressor === 'width100' )
            ? (
              Math.max(
                Math.min(
                    element[0].offsetWidth * (element.children()[0].offsetHeight / element.children()[0].offsetWidth),
                  parseFloat( scope.maxFontSize )
                ),
                parseFloat( scope.minFontSize )
              ) + 'px'
            )
            : (
              Math.max(
                Math.min(
                    element[0].offsetWidth / ( scope.compressor * 10 ),
                  parseFloat( scope.maxFontSize )
                ),
                parseFloat( scope.minFontSize )
              ) + 'px'
            );
        })();

        config.debounce == true
          ? angular.element( window ).bind( 'resize', _debounce( function(){ scope.$apply( scope.resizer )}, config.delay ))
          : angular.element( window ).bind( 'resize', function(){ scope.$apply( scope.resizer )});

        function _debounce(a,b,c){var d;return function(){var e=this,f=arguments;clearTimeout(d),d=setTimeout(function(){d=null,c||a.apply(e,f)},b),c&&!d&&a.apply(e,f)}}
      }
    }
  }])

  .provider( 'fitTextConfig', function() {
    var self = this;
    this.config = {};
    this.$get = function() {
      var extend = {};
      extend.config = self.config;
      return extend;
    };
    return this;
  });<|endoftext|>


<commit_before>(function(window, angular, Math) {
  angular.module('tourcms.ng-tourcms', [])
 .factory('tourcmsApiService', function($http) {

    var baseUrl = 'https://api.tourcms.com';

    var apiKey = '';
    var marketplaceId = 0;
    var channelId = 0;

    var makeRequest = function(a) {
      // Sensible defaults
      if(typeof a.channelId == "undefined")
        a.channelId = 0;

      if(typeof a.verb == "undefined")
        a.verb = 'GET';

      //console.log(a.postData);

      if(typeof a.postData == "undefined") {
        var apiParams = "";
      } else {
        var s = new XMLSerializer();
        var apiParams = s.serializeToString(a.postData);
      }

      // Get the current time
      var outboundTime = generateTime();

      // Generate the signature
      var signature = generateSignature(a.path, a.channelId, a.verb, outboundTime);

      // Full URL to call
      var apiUrl = baseUrl + a.path;

      // Make the call using Angular $http
      return $http({
                method: a.verb,
                url: apiUrl,
                params: apiParams,
                headers: {
                  'x-tourcms-date': outboundTime,
                  'Authorization': 'TourCMS ' + a.channelId + ':' + marketplaceId + ':' + signature,
                  'Content-type': 'text/xml;charset="utf-8"'
                },
                transformResponse: function(data) {
                  if(typeof X2JS !== 'undefined') {
                    var x2js = new X2JS();
                    var json = x2js.xml_str2json( data );
                    return json;
                  } else {
                    return data;
                  }
                }
      });
    };

    // Generate the signature required to sign API calls
    var generateSignature = function(path, channelId, verb, outboundTime) {
      var stringToSign = channelId + "/" + marketplaceId + "/" + verb + "/" + outboundTime + path;
      var signature = rawurlencode(b64_hmac_sha256(apiKey, stringToSign) + "=");

      return signature;
    }

    // Generate the current Unix Timestamp (PHP style)
    var generateTime = function() {
      return Math.floor(new Date().getTime() / 1000);
    }

    var rawurlencode = function(str) {
    //From http://phpjs.org/functions/rawurlencode/
    str = (str + '')
      .toString();

      return encodeURIComponent(str)
        .replace(/!/g, '%21')
        .replace(/'/g, '%27')
        .replace(/\(/g, '%28')
        .
      replace(/\)/g, '%29')
        .replace(/\*/g, '%2A');
    }

    var toQueryString = function(obj) {
    var parts = [];
    for (var i in obj) {
        if (obj.hasOwnProperty(i)) {
            parts.push(encodeURIComponent(i) + "=" + encodeURIComponent(obj[i]));
        }
    }
        return parts.join("&");
    }

    // Return our singleton
    return {
        apiRateLimitStatus: function(a) {
                              // Channel ID
                                // If undefined, use object level channelId
                                if(typeof a.channelId === "undefined")
                                  a.channelId = channelId;

                                a.path = '/api/rate_limit_status.xml';
                                return makeRequest(a);
        },
        searchTours: function(a) {

                              // Convert/set search params
                                // If undefined
                            		if(typeof a.qs === "undefined") {
                            			a.qs = "";
                                // If array of key value pairs
                                } else if(typeof a.qs === 'object') {
                                  a.qs = toQueryString(a.qs);
                                }
                                // Otherwise leave alone (already a query string)

                              // Channel ID
                                // If undefined, use object level channelId
                            		if(typeof a.channelId === "undefined")
                            			a.channelId = channelId;

                              // Set API path
                            		if(a.channelId==0)
                            			a.path = '/p/tours/search.xml?' + a.qs;
                            		else
                            			a.path = '/c/tours/search.xml?' + a.qs;

                                return makeRequest(a);
        }
    };

});
})(this, this.angular, Math);
<commit_msg>Added 'Show Tour'<commit_after>(function(window, angular, Math) {
  angular.module('tourcms.ng-tourcms', [])
 .factory('tourcmsApiService', function($http) {

    var baseUrl = 'https://api.tourcms.com';

    var apiKey = '';
    var marketplaceId = 0;
    var channelId = 0;

    var makeRequest = function(a) {
      // Sensible defaults
      if(typeof a.channelId == "undefined")
        a.channelId = 0;

      if(typeof a.verb == "undefined")
        a.verb = 'GET';

      //console.log(a.postData);

      if(typeof a.postData == "undefined") {
        var apiParams = "";
      } else {
        var s = new XMLSerializer();
        var apiParams = s.serializeToString(a.postData);
      }

      // Get the current time
      var outboundTime = generateTime();

      // Generate the signature
      var signature = generateSignature(a.path, a.channelId, a.verb, outboundTime);

      // Full URL to call
      var apiUrl = baseUrl + a.path;

      // Make the call using Angular $http
      return $http({
                method: a.verb,
                url: apiUrl,
                params: apiParams,
                headers: {
                  'x-tourcms-date': outboundTime,
                  'Authorization': 'TourCMS ' + a.channelId + ':' + marketplaceId + ':' + signature,
                  'Content-type': 'text/xml;charset="utf-8"'
                },
                transformResponse: function(data) {
                  if(typeof X2JS !== 'undefined') {
                    var x2js = new X2JS();
                    var json = x2js.xml_str2json( data );
                    return json;
                  } else {
                    return data;
                  }
                }
      });
    };

    // Generate the signature required to sign API calls
    var generateSignature = function(path, channelId, verb, outboundTime) {
      var stringToSign = channelId + "/" + marketplaceId + "/" + verb + "/" + outboundTime + path;
      var signature = rawurlencode(b64_hmac_sha256(apiKey, stringToSign) + "=");

      return signature;
    }

    // Generate the current Unix Timestamp (PHP style)
    var generateTime = function() {
      return Math.floor(new Date().getTime() / 1000);
    }

    var rawurlencode = function(str) {
    //From http://phpjs.org/functions/rawurlencode/
    str = (str + '')
      .toString();

      return encodeURIComponent(str)
        .replace(/!/g, '%21')
        .replace(/'/g, '%27')
        .replace(/\(/g, '%28')
        .
      replace(/\)/g, '%29')
        .replace(/\*/g, '%2A');
    }

    var toQueryString = function(obj) {
    var parts = [];
    for (var i in obj) {
        if (obj.hasOwnProperty(i)) {
            parts.push(encodeURIComponent(i) + "=" + encodeURIComponent(obj[i]));
        }
    }
        return parts.join("&");
    }

    // Return our singleton
    return {
        apiRateLimitStatus: function(a) {
                              // Channel ID
                                // If undefined, use object level channelId
                                if(typeof a.channelId === "undefined")
                                  a.channelId = channelId;

                                a.path = '/api/rate_limit_status.xml';
                                return makeRequest(a);
        },
        searchTours: function(a) {

                              // Convert/set search params
                                // If undefined
                            		if(typeof a.qs === "undefined") {
                            			a.qs = "";
                                // If array of key value pairs
                                } else if(typeof a.qs === 'object') {
                                  a.qs = toQueryString(a.qs);
                                }
                                // Otherwise leave alone (already a query string)

                              // Channel ID
                                // If undefined, use object level channelId
                            		if(typeof a.channelId === "undefined")
                            			a.channelId = channelId;

                              // Set API path
                            		if(a.channelId==0)
                            			a.path = '/p/tours/search.xml?' + a.qs;
                            		else
                            			a.path = '/c/tours/search.xml?' + a.qs;

                                return makeRequest(a);
        },
        searchTours: function(a) {

                              // Convert/set search params
                                // If undefined
                                if(typeof a.qs === "undefined") {
                                  a.qs = {};
                                }

                                a.qs = toQueryString(a.qs);

                              // Channel ID
                                // If undefined, use object level channelId
                                if(typeof a.channelId === "undefined")
                                  a.channelId = channelId;

                              // Set API path
                                if(a.channelId==0)
                                  a.path = '/p/tours/search.xml?' + a.qs;
                                else
                                  a.path = '/c/tours/search.xml?' + a.qs;

                                return makeRequest(a);
        },
        showTour: function(a) {

                                // If QS undefined
                                if(typeof a.qs === "undefined") {
                                    a.qs = {};
                                }

                                // Add in the TourId in if provided separately
                                if(typeof a.tourId !== 'undefined') {
                                  a.qs['id'] = a.tourId;

                                }

                                // Fix id if passed in to qs directly as tourId
                                if(typeof a.qs.tourId !== 'undefined') {
                                  a.qs['id'] = a.qs.tourId;
                                  delete a.qs['tourId'];
                                }

                                a.qs = toQueryString(a.qs);

                              // Channel ID
                                // If undefined, use object level channelId
                                if(typeof a.channelId === "undefined")
                                  a.channelId = channelId;

                                a.path = '/c/tour/show.xml?' + a.qs;

                                return makeRequest(a);
        }
    };

});
})(this, this.angular, Math);
<|endoftext|>


<commit_before>const globby = require('globby');
const { getGitSha } = require('ci-utils');
const fetch = require('node-fetch');
const path = require('path');

const {
  NOW_URL,
  SAUCE_USERNAME,
  SAUCE_ACCESS_KEY,
  // for push builds, or builds not triggered by a pull request, this is the name of the branch.
  // for builds triggered by a pull request this is the name of the branch targeted by the pull request.
  // for builds triggered by a tag, this is the same as the name of the tag(TRAVIS_TAG).
  TRAVIS_BRANCH,
  // if the current job is a pull request, the name of the branch from which the PR originated
  // if the current job is a push build, this variable is empty("").
  TRAVIS_PULL_REQUEST_BRANCH,
  // The pull request number if the current job is a pull request, "false" if it’s not a pull request.
  TRAVIS_PULL_REQUEST,
  // The slug (in form: owner_name/repo_name) of the repository currently being built.
  TRAVIS_REPO_SLUG,
  // If the current build is for a git tag, this variable is set to the tag’s name
  TRAVIS_TAG,
  TRAVIS_BUILD_WEB_URL,
  TRAVIS_JOB_NUMBER,
} = process.env;

const gitSha = getGitSha(true);
const gitShaLong = getGitSha();

const testingUrl = NOW_URL ? NOW_URL : 'https://boltdesignsystem.com';
// const testingUrl = 'https://boltdesignsystem.com';
console.log(`Nightwatch testingUrl is ${testingUrl}`);

const auth = Buffer.from(`${SAUCE_USERNAME}:${SAUCE_ACCESS_KEY}`).toString(
  'base64',
);

let srcFolders = globby.sync([
  'docs-site/**/*.e2e.js',
  'packages/**/*.e2e.js',
  'apps/**/*.e2e.js',
  'test/*/*.e2e.js',
]);

srcFolders = srcFolders.map(function(folder) {
  return path.dirname(folder);
});

/**
 * @param {Object} client - Nightwatch instance @todo add link to API docs
 * @param {function} callback
 * @returns {void}
 */
function handleNightwatchResults(client, callback) {
  const currentTest = client.currentTest;
  const sessionId = client.capabilities['webdriver.remote.sessionid'];
  const { username, accessKey } = client.options;
  const {
    /** @type {string} - Name of test */
    name,
    /** @type {string} - Name of test file, ie `__tests__/bolt-video.e2e` */
    module: testFileName,
    /** @type {string} */
    group,
    /** @type {{ time: string, assertions: array, passed: number, errors: number, failed: number, skipped: number, tests: number, steps: array, timeMs: number}} */
    results,
  } = currentTest;

  if (!client.launch_url.match(/saucelabs/)) {
    console.log('Not saucelabs ...');
    callback();
    return;
  }

  if (!username || !accessKey || !sessionId) {
    console.log('No username, accessKey or sessionId');
    callback();
    return;
  }

  const passed = results.passed === results.tests - results.skipped;
  console.log(`Passed: ${passed ? 'Yes' : 'No'} - ${name}`);
  fetch(
    // https://wiki.saucelabs.com/display/DOCS/Job+Methods
    `https://saucelabs.com/rest/v1/${SAUCE_USERNAME}/jobs/${sessionId}`,
    {
      method: 'PUT',
      headers: {
        Authorization: `Basic ${auth}`,
        Accept: 'application/json',
        'Content-Type': 'application/json',
      },
      body: JSON.stringify({
        passed,
        build: `build-${process.env.TRAVIS_JOB_NUMBER}`,
        tags: ['CI'],
        'custom-data': {
          TRAVIS_JOB_NUMBER,
          TRAVIS_BRANCH,
          TRAVIS_PULL_REQUEST_BRANCH,
          TRAVIS_PULL_REQUEST,
          TRAVIS_REPO_SLUG,
          TRAVIS_TAG,
          TRAVIS_BUILD_WEB_URL,
          gitSha,
          gitShaLong,
        },
      }),
    },
  )
    .then(res => {
      if (res.ok) {
        console.log(`Set SauceLabs details ok`);
      } else {
        console.log(`Set SauceLabs details not ok`);
        throw new Error(`Set SauceLabs details not ok ${res.statusText}`);
      }
      return res.json();
    })
    .then(() => callback())
    .catch(err => {
      console.log(`Error setting SauceLabs details`, err);
      process.exit(1);
    });
}

module.exports = {
  globals: {
    testingUrl,
    results: [],
    testCount: 0,

    afterEach(browser, cb) {
      handleNightwatchResults(browser, cb);
    },

    reporter(results, cb) {
      // Might be used if nightwatch results reporting needs to be consolidated in Github Checks
      console.log('global reporter called');
      console.log(results);
      console.log(results.modules);
      cb();
    },
  },
  persist_globals: true,
  // selenium: {
  //   start_process: true,
  //   server_path: require('selenium-server').path,
  //   log_path: './reports',
  //   host: '127.0.0.1',
  //   port: 4444,
  //   cli_args: {
  //     'webdriver.chrome.driver': './node_modules/chromedriver/bin/chromedriver',
  //   },
  // },
  live_output: false, // set to `true` to see output as it happens; make appear interlaced if ran in parallel
  test_workers: { enabled: true, workers: 'auto' },
  test_settings: {
    compatible_testcase_support: true,
    default: {
      screenshots: {
        enabled: true,
        on_failure: true,
        on_error: true,
        path: 'reports/screenshots/',
      },
      filter: '**/*.e2e.js',
      launch_url: 'http://ondemand.saucelabs.com:80',
      selenium_port: 80,
      selenium_host: 'ondemand.saucelabs.com',
      silent: true,
      username: process.env.SAUCE_USERNAME,
      access_key: process.env.SAUCE_ACCESS_KEY,
    },
    local: {
      screenshots: {
        enabled: true,
        on_failure: true,
        on_error: true,
        path: 'reports/screenshots/',
      },
      filter: '**/*.e2e.js',
      selenium_port: 9515,
      selenium_host: 'localhost',
      default_path_prefix: '',
      desiredCapabilities: {
        browserName: 'chrome',
        chromeOptions: {
          args: ['headless'],
        },
      },
    },
    chrome: {
      desiredCapabilities: {
        browserName: 'chrome',
        platform: 'OS X 10.11',
        version: '70',
        javascriptEnabled: true,
        acceptSslCerts: true,
        //         chromeOptions: {
        //           args: ['headless'],
        //         },
      },
      build: `build-${process.env.TRAVIS_JOB_NUMBER}`,
      'tunnel-identifier': `${process.env.TRAVIS_JOB_NUMBER || ''}`,
    },
    ie11: {
      desiredCapabilities: {
        browserName: 'internet explorer',
        platform: 'Windows 10',
        version: '11.0',
      },
      build: `build-${process.env.TRAVIS_JOB_NUMBER}`,
      'tunnel-identifier': `${process.env.TRAVIS_JOB_NUMBER || ''}`,
    },
    firefox: {
      desiredCapabilities: {
        browserName: 'firefox',
        platform: 'OS X 10.11',
        version: '62',
      },
      build: `build-${process.env.TRAVIS_JOB_NUMBER}`,
      'tunnel-identifier': `${process.env.TRAVIS_JOB_NUMBER || ''}`,
    },
  },
  src_folders: srcFolders,
};
<commit_msg>test: re-testing nightwatch after increasing max timeout allowed for async tests<commit_after>const globby = require('globby');
const { getGitSha } = require('ci-utils');
const fetch = require('node-fetch');
const path = require('path');

const {
  NOW_URL,
  SAUCE_USERNAME,
  SAUCE_ACCESS_KEY,
  // for push builds, or builds not triggered by a pull request, this is the name of the branch.
  // for builds triggered by a pull request this is the name of the branch targeted by the pull request.
  // for builds triggered by a tag, this is the same as the name of the tag(TRAVIS_TAG).
  TRAVIS_BRANCH,
  // if the current job is a pull request, the name of the branch from which the PR originated
  // if the current job is a push build, this variable is empty("").
  TRAVIS_PULL_REQUEST_BRANCH,
  // The pull request number if the current job is a pull request, "false" if it’s not a pull request.
  TRAVIS_PULL_REQUEST,
  // The slug (in form: owner_name/repo_name) of the repository currently being built.
  TRAVIS_REPO_SLUG,
  // If the current build is for a git tag, this variable is set to the tag’s name
  TRAVIS_TAG,
  TRAVIS_BUILD_WEB_URL,
  TRAVIS_JOB_NUMBER,
} = process.env;

const gitSha = getGitSha(true);
const gitShaLong = getGitSha();

const testingUrl = NOW_URL ? NOW_URL : 'https://boltdesignsystem.com';
// const testingUrl = 'https://boltdesignsystem.com';
console.log(`Nightwatch testingUrl is ${testingUrl}`);

const auth = Buffer.from(`${SAUCE_USERNAME}:${SAUCE_ACCESS_KEY}`).toString(
  'base64',
);

let srcFolders = globby.sync([
  'docs-site/**/*.e2e.js',
  'packages/**/*.e2e.js',
  'apps/**/*.e2e.js',
  'test/*/*.e2e.js',
]);

srcFolders = srcFolders.map(function(folder) {
  return path.dirname(folder);
});

/**
 * @param {Object} client - Nightwatch instance @todo add link to API docs
 * @param {function} callback
 * @returns {void}
 */
function handleNightwatchResults(client, callback) {
  const currentTest = client.currentTest;
  const sessionId = client.capabilities['webdriver.remote.sessionid'];
  const { username, accessKey } = client.options;
  const {
    /** @type {string} - Name of test */
    name,
    /** @type {string} - Name of test file, ie `__tests__/bolt-video.e2e` */
    module: testFileName,
    /** @type {string} */
    group,
    /** @type {{ time: string, assertions: array, passed: number, errors: number, failed: number, skipped: number, tests: number, steps: array, timeMs: number}} */
    results,
  } = currentTest;

  if (!client.launch_url.match(/saucelabs/)) {
    console.log('Not saucelabs ...');
    callback();
    return;
  }

  if (!username || !accessKey || !sessionId) {
    console.log('No username, accessKey or sessionId');
    callback();
    return;
  }

  const passed = results.passed === results.tests - results.skipped;
  console.log(`Passed: ${passed ? 'Yes' : 'No'} - ${name}`);
  fetch(
    // https://wiki.saucelabs.com/display/DOCS/Job+Methods
    `https://saucelabs.com/rest/v1/${SAUCE_USERNAME}/jobs/${sessionId}`,
    {
      method: 'PUT',
      headers: {
        Authorization: `Basic ${auth}`,
        Accept: 'application/json',
        'Content-Type': 'application/json',
      },
      body: JSON.stringify({
        passed,
        build: `build-${process.env.TRAVIS_JOB_NUMBER}`,
        tags: ['CI'],
        'custom-data': {
          TRAVIS_JOB_NUMBER,
          TRAVIS_BRANCH,
          TRAVIS_PULL_REQUEST_BRANCH,
          TRAVIS_PULL_REQUEST,
          TRAVIS_REPO_SLUG,
          TRAVIS_TAG,
          TRAVIS_BUILD_WEB_URL,
          gitSha,
          gitShaLong,
        },
      }),
    },
  )
    .then(res => {
      if (res.ok) {
        console.log(`Set SauceLabs details ok`);
      } else {
        console.log(`Set SauceLabs details not ok`);
        throw new Error(`Set SauceLabs details not ok ${res.statusText}`);
      }
      return res.json();
    })
    .then(() => callback())
    .catch(err => {
      console.log(`Error setting SauceLabs details`, err);
      process.exit(1);
    });
}

module.exports = {
  globals: {
    asyncHookTimeout: 30000, // increasing timeout to prevent errors in Sauce Labs
    testingUrl,
    results: [],
    testCount: 0,

    afterEach(browser, cb) {
      handleNightwatchResults(browser, cb);
    },

    reporter(results, cb) {
      // Might be used if nightwatch results reporting needs to be consolidated in Github Checks
      console.log('global reporter called');
      console.log(results);
      console.log(results.modules);
      cb();
    },
  },
  persist_globals: true,
  // selenium: {
  //   start_process: true,
  //   server_path: require('selenium-server').path,
  //   log_path: './reports',
  //   host: '127.0.0.1',
  //   port: 4444,
  //   cli_args: {
  //     'webdriver.chrome.driver': './node_modules/chromedriver/bin/chromedriver',
  //   },
  // },
  live_output: false, // set to `true` to see output as it happens; make appear interlaced if ran in parallel
  test_workers: { enabled: true, workers: 'auto' },
  test_settings: {
    compatible_testcase_support: true,
    default: {
      screenshots: {
        enabled: true,
        on_failure: true,
        on_error: true,
        path: 'reports/screenshots/',
      },
      filter: '**/*.e2e.js',
      launch_url: 'http://ondemand.saucelabs.com:80',
      selenium_port: 80,
      selenium_host: 'ondemand.saucelabs.com',
      silent: true,
      username: process.env.SAUCE_USERNAME,
      access_key: process.env.SAUCE_ACCESS_KEY,
    },
    local: {
      screenshots: {
        enabled: true,
        on_failure: true,
        on_error: true,
        path: 'reports/screenshots/',
      },
      filter: '**/*.e2e.js',
      selenium_port: 9515,
      selenium_host: 'localhost',
      default_path_prefix: '',
      desiredCapabilities: {
        browserName: 'chrome',
        chromeOptions: {
          args: ['headless'],
        },
      },
    },
    chrome: {
      desiredCapabilities: {
        browserName: 'chrome',
        platform: 'OS X 10.11',
        version: '70',
        javascriptEnabled: true,
        acceptSslCerts: true,
        //         chromeOptions: {
        //           args: ['headless'],
        //         },
      },
      build: `build-${process.env.TRAVIS_JOB_NUMBER}`,
      'tunnel-identifier': `${process.env.TRAVIS_JOB_NUMBER || ''}`,
    },
    ie11: {
      desiredCapabilities: {
        browserName: 'internet explorer',
        platform: 'Windows 10',
        version: '11.0',
      },
      build: `build-${process.env.TRAVIS_JOB_NUMBER}`,
      'tunnel-identifier': `${process.env.TRAVIS_JOB_NUMBER || ''}`,
    },
    firefox: {
      desiredCapabilities: {
        browserName: 'firefox',
        platform: 'OS X 10.11',
        version: '62',
      },
      build: `build-${process.env.TRAVIS_JOB_NUMBER}`,
      'tunnel-identifier': `${process.env.TRAVIS_JOB_NUMBER || ''}`,
    },
  },
  src_folders: srcFolders,
};
<|endoftext|>


<commit_before>/*!
 *
 * Copyright (c) 2013 Sebastian Golasch
 *
 * Permission is hereby granted, free of charge, to any person obtaining a
 * copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation
 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
 * and/or sell copies of the Software, and to permit persons to whom the
 * Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included
 * in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
 * DEALINGS IN THE SOFTWARE.
 *
 */

'use strict';

// ext. libs
var Q = require('q');
var fs = require('fs');

/**
 * Screenshot related methods
 *
 * @module Driver
 * @class Screenshot
 * @namespace Dalek.DriverNative.Commands
 */

var Screenshot = {

  /**
   * Makes an screenshot of the current page
   *
   * @method screenshot
   * @param {string} path Root directory path
   * @param {string} pathname Pathname of the screenshot path
   * @param {string} hash Unique hash of that fn call
   * @param {string} uuid Unique hash of that fn call
   * @chainable
   */

  screenshot: function (path, pathname, hash, uuid) {
    this.actionQueue.push(this.webdriverClient.screenshot.bind(this.webdriverClient));
    this.actionQueue.push(this._screenshotCb.bind(this, path, pathname, hash, uuid));
    return this;
  },

  /**
   * Sends out an event with the results of the `screenshot` call
   * and stores the screenshot in the filesystem
   *
   * @method _screenshotCb
   * @param {string} path Root directory path
   * @param {string} pathname Pathname of the screenshot path
   * @param {string} hash Unique hash of that fn call
   * @param {string} uuid Unique hash of that fn call
   * @param {string} result Serialized JSON result of the screenshot call
   * @return {object} promise Screenshot promise
   * @private
   */

  _screenshotCb: function (path, pathname, hash, uuid, result) {
    var deferred = Q.defer();
    // replace base64 metadata
    var base64Data = JSON.parse(result).value.replace(/^data:image\/png;base64,/,'');
    // replace placeholders
    var realpath = this._replacePathPlaceholder(path + pathname);
    // check if we need to add a new directory
    this._recursiveMakeDirSync(realpath.substring(0, realpath.lastIndexOf('/')));
    // write the screenshot
    fs.writeFileSync(realpath, base64Data, 'base64');
    this.events.emit('driver:message', {key: 'screenshot', value: realpath, uuid: hash, hash: hash});
    deferred.resolve();
    return deferred.promise;
  },

  /**
   * Recursige mkdir helper
   *
   * @method _recursiveMakeDirSync
   * @param {string} path Path to create
   * @private
   */

  _recursiveMakeDirSync: function (path) {
    var pathSep = require('path').sep;
    var dirs = path.split(pathSep);
    var root = '';

    while (dirs.length > 0) {
      var dir = dirs.shift();
      if (dir === '') {
        root = pathSep;
      }
      if (!fs.existsSync(root + dir)) {
        fs.mkdirSync(root + dir);
      }
      root += dir + pathSep;
    }
  },

  /**
   * Return the formatted os name
   *
   * @method _parseOS
   * @param {string} Pathname
   * @return {string} Formatted pathname
   * @private
   */

  _replacePathPlaceholder: function (pathname) {
    pathname = pathname.replace(':browser', this.browserName);
    pathname = pathname.replace(':version', this._parseBrowserVersion(this.sessionStatus.version));
    pathname = pathname.replace(':timestamp', Math.round(new Date().getTime() / 1000));
    pathname = pathname.replace(':osVersion', this._parseOSVersion(this.driverStatus.os.version));
    pathname = pathname.replace(':os', this._parseOS(this.driverStatus.os.name));
    pathname = pathname.replace(':datetime', this._parseDatetime());
    pathname = pathname.replace(':date', this._parseDate());
    pathname = pathname.replace(':viewport', this._parseViewport());
    return pathname;
  },

  /**
   * Return the formatted os name
   *
   * @method _parseOS
   * @return {string} OS name
   * @private
   */

  _parseOS: function (os) {
    var mappings = {
      'mac': 'OSX',
      'Mac OS X': 'OSX'
    };
    return mappings[os] || 'unknown';
  },

  /**
   * Return the formatted os version
   *
   * @method _parseOSVersion
   * @return {string} OS version
   * @private
   */

  _parseOSVersion: function (version) {
    var vs = version.replace(/[^0-9\\.]/g, '');
    vs = vs.replace(/\./g, '_');
    return vs;
  },

  /**
   * Return the formatted browser version
   *
   * @method _parseBrowserVersion
   * @return {string} Browser version
   * @private
   */

  _parseBrowserVersion: function (version) {
    return version.replace(/\./g, '_');
  },

  /**
   * Return the ISO 8601 formatted date
   *
   * @method _parseDate
   * @param {object} optional A javascript date object. If undefined, the current date is used.
   * @return {string} Date
   * @private
   */

  _parseDate: function (date) {
    date = date ? date : new Date();
    var day = date.getDate();
    var month = date.getMonth() + 1;
    var year = date.getFullYear();

    month = ('0' + month).slice(-2);
    day = ('0' + day).slice(-2);

    return year + '-' + month + '-' + day;
  },

  /**
   * Return the ISO 8601 formatted datetime
   *
   * @method _parseDatetime
   * @param {object} optional A javascript date object. If undefined, the current date is used.
   * @return {string} Datetime
   * @private
   */

  _parseDatetime: function (date) {
    date = date ? date : new Date();
    var dateStr = this._parseDate();
    var timeStr = 'T#hours#:#minutes#:#seconds##formattedOffset#';
    var hours = date.getHours();
    var minutes = date.getMinutes();
    var seconds = date.getSeconds();
    var offsetHours = '' + Math.ceil(date.getTimezoneOffset() / 60);
    var offsetMinutes = '' + Math.abs(date.getTimezoneOffset() % 60);
    var formattedOffset;

    hours = ('0' + hours).slice(-2);
    minutes = ('0' + minutes).slice(-2);
    seconds = ('0' + seconds).slice(-2);

    if (offsetHours[0] === '-' && offsetHours.length < 3) {
      formattedOffset = offsetHours[0] + '0' + offsetHours[1];
    } else if (offsetHours.length < 2) {
      formattedOffset = '+0' + offsetHours;
    }

    if (offsetMinutes.length < 2) {
      formattedOffset += ':0' + offsetMinutes;
    } else {
      formattedOffset += ':' + offsetMinutes;
    }

    if (offsetHours === '0' && offsetMinutes === '0') {
      formattedOffset = 'Z';
    }

    timeStr = timeStr.replace('#hours#', hours);
    timeStr = timeStr.replace('#minutes#', minutes);
    timeStr = timeStr.replace('#seconds#', seconds);
    timeStr = timeStr.replace('#formattedOffset#', formattedOffset);

    return dateStr + timeStr;
  },

  /**
   * Return the formatted viewport
   *
   * @method _parseViewport
   * @return {string} Viewport
   * @private
   */

  _parseViewport: function () {
    var viewport = this.config.get('viewport');
    return 'w' + viewport.width + '_h' + viewport.height;
  }

};

/**
 * Mixes in screenshot methods
 *
 * @param {Dalek.DriverNative} DalekNative Native driver base class
 * @return {Dalek.DriverNative} DalekNative Native driver base class
 */

module.exports = function (DalekNative) {
  if ('undefined' === typeof DalekNative) {
    return Screenshot;
  }
  // mixin methods
  Object.keys(Screenshot).forEach(function (fn) {
    DalekNative.prototype[fn] = Screenshot[fn];
  });

  return DalekNative;
};
<commit_msg>Fix screenshot folder creation bug on windows<commit_after>/*!
 *
 * Copyright (c) 2013 Sebastian Golasch
 *
 * Permission is hereby granted, free of charge, to any person obtaining a
 * copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation
 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
 * and/or sell copies of the Software, and to permit persons to whom the
 * Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included
 * in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
 * DEALINGS IN THE SOFTWARE.
 *
 */

'use strict';

// ext. libs
var Q = require('q');
var fs = require('fs');

/**
 * Screenshot related methods
 *
 * @module Driver
 * @class Screenshot
 * @namespace Dalek.DriverNative.Commands
 */

var Screenshot = {

  /**
   * Makes an screenshot of the current page
   *
   * @method screenshot
   * @param {string} path Root directory path
   * @param {string} pathname Pathname of the screenshot path
   * @param {string} hash Unique hash of that fn call
   * @param {string} uuid Unique hash of that fn call
   * @chainable
   */

  screenshot: function (path, pathname, hash, uuid) {
    this.actionQueue.push(this.webdriverClient.screenshot.bind(this.webdriverClient));
    this.actionQueue.push(this._screenshotCb.bind(this, path, pathname, hash, uuid));
    return this;
  },

  /**
   * Sends out an event with the results of the `screenshot` call
   * and stores the screenshot in the filesystem
   *
   * @method _screenshotCb
   * @param {string} path Root directory path
   * @param {string} pathname Pathname of the screenshot path
   * @param {string} hash Unique hash of that fn call
   * @param {string} uuid Unique hash of that fn call
   * @param {string} result Serialized JSON result of the screenshot call
   * @return {object} promise Screenshot promise
   * @private
   */

  _screenshotCb: function (path, pathname, hash, uuid, result) {
    var deferred = Q.defer();
    // replace base64 metadata
    var base64Data = JSON.parse(result).value.replace(/^data:image\/png;base64,/,'');
    // replace placeholders
    var realpath = this._replacePathPlaceholder(path + pathname);
    // check if we need to add a new directory
    this._recursiveMakeDirSync(realpath.substring(0, realpath.lastIndexOf('/')));
    // write the screenshot
    fs.writeFileSync(realpath, base64Data, 'base64');
    this.events.emit('driver:message', {key: 'screenshot', value: realpath, uuid: hash, hash: hash});
    deferred.resolve();
    return deferred.promise;
  },

  /**
   * Recursige mkdir helper
   *
   * @method _recursiveMakeDirSync
   * @param {string} path Path to create
   * @private
   */

  _recursiveMakeDirSync: function (path) {
    var normalizedPath = require('path').normalize(path);
    var pathSep = require('path').sep;
    var dirs = normalizedPath.split(pathSep);
    var root = '';

    while (dirs.length > 0) {
      var dir = dirs.shift();
      if (dir === '') {
        root = pathSep;
      }
      if (!fs.existsSync(root + dir)) {
        fs.mkdirSync(root + dir);
      }
      root += dir + pathSep;
    }
  },

  /**
   * Return the formatted os name
   *
   * @method _parseOS
   * @param {string} Pathname
   * @return {string} Formatted pathname
   * @private
   */

  _replacePathPlaceholder: function (pathname) {
    pathname = pathname.replace(':browser', this.browserName);
    pathname = pathname.replace(':version', this._parseBrowserVersion(this.sessionStatus.version));
    pathname = pathname.replace(':timestamp', Math.round(new Date().getTime() / 1000));
    pathname = pathname.replace(':osVersion', this._parseOSVersion(this.driverStatus.os.version));
    pathname = pathname.replace(':os', this._parseOS(this.driverStatus.os.name));
    pathname = pathname.replace(':datetime', this._parseDatetime());
    pathname = pathname.replace(':date', this._parseDate());
    pathname = pathname.replace(':viewport', this._parseViewport());
    return pathname;
  },

  /**
   * Return the formatted os name
   *
   * @method _parseOS
   * @return {string} OS name
   * @private
   */

  _parseOS: function (os) {
    var mappings = {
      'mac': 'OSX',
      'Mac OS X': 'OSX'
    };
    return mappings[os] || 'unknown';
  },

  /**
   * Return the formatted os version
   *
   * @method _parseOSVersion
   * @return {string} OS version
   * @private
   */

  _parseOSVersion: function (version) {
    var vs = version.replace(/[^0-9\\.]/g, '');
    vs = vs.replace(/\./g, '_');
    return vs;
  },

  /**
   * Return the formatted browser version
   *
   * @method _parseBrowserVersion
   * @return {string} Browser version
   * @private
   */

  _parseBrowserVersion: function (version) {
    return version.replace(/\./g, '_');
  },

  /**
   * Return the ISO 8601 formatted date
   *
   * @method _parseDate
   * @param {object} optional A javascript date object. If undefined, the current date is used.
   * @return {string} Date
   * @private
   */

  _parseDate: function (date) {
    date = date ? date : new Date();
    var day = date.getDate();
    var month = date.getMonth() + 1;
    var year = date.getFullYear();

    month = ('0' + month).slice(-2);
    day = ('0' + day).slice(-2);

    return year + '-' + month + '-' + day;
  },

  /**
   * Return the ISO 8601 formatted datetime
   *
   * @method _parseDatetime
   * @param {object} optional A javascript date object. If undefined, the current date is used.
   * @return {string} Datetime
   * @private
   */

  _parseDatetime: function (date) {
    date = date ? date : new Date();
    var dateStr = this._parseDate();
    var timeStr = 'T#hours#:#minutes#:#seconds##formattedOffset#';
    var hours = date.getHours();
    var minutes = date.getMinutes();
    var seconds = date.getSeconds();
    var offsetHours = '' + Math.ceil(date.getTimezoneOffset() / 60);
    var offsetMinutes = '' + Math.abs(date.getTimezoneOffset() % 60);
    var formattedOffset;

    hours = ('0' + hours).slice(-2);
    minutes = ('0' + minutes).slice(-2);
    seconds = ('0' + seconds).slice(-2);

    if (offsetHours[0] === '-' && offsetHours.length < 3) {
      formattedOffset = offsetHours[0] + '0' + offsetHours[1];
    } else if (offsetHours.length < 2) {
      formattedOffset = '+0' + offsetHours;
    }

    if (offsetMinutes.length < 2) {
      formattedOffset += ':0' + offsetMinutes;
    } else {
      formattedOffset += ':' + offsetMinutes;
    }

    if (offsetHours === '0' && offsetMinutes === '0') {
      formattedOffset = 'Z';
    }

    timeStr = timeStr.replace('#hours#', hours);
    timeStr = timeStr.replace('#minutes#', minutes);
    timeStr = timeStr.replace('#seconds#', seconds);
    timeStr = timeStr.replace('#formattedOffset#', formattedOffset);

    return dateStr + timeStr;
  },

  /**
   * Return the formatted viewport
   *
   * @method _parseViewport
   * @return {string} Viewport
   * @private
   */

  _parseViewport: function () {
    var viewport = this.config.get('viewport');
    return 'w' + viewport.width + '_h' + viewport.height;
  }

};

/**
 * Mixes in screenshot methods
 *
 * @param {Dalek.DriverNative} DalekNative Native driver base class
 * @return {Dalek.DriverNative} DalekNative Native driver base class
 */

module.exports = function (DalekNative) {
  if ('undefined' === typeof DalekNative) {
    return Screenshot;
  }
  // mixin methods
  Object.keys(Screenshot).forEach(function (fn) {
    DalekNative.prototype[fn] = Screenshot[fn];
  });

  return DalekNative;
};
<|endoftext|>


<commit_before>var Promise = require('bluebird')
var rollbar = require('rollbar')
var sails = require('sails')

rollbar.init(process.env.ROLLBAR_SERVER_TOKEN)

var Solicitor = function (community, startTime, endTime, debug) {
  this.community = community
  this.communityName = community.get('name')
}

var mailtoLink = function (communityId, userId, type) {
  var address = Email.postCreationAddress(communityId, userId, Post.Type.OFFER)
  var subject
  var body = 'More details here...'

  switch (type) {
    case Post.Type.OFFER:
      subject = 'I\'d like to share [finish this sentence!]'
      break
    case Post.Type.REQUEST:
      subject = 'I\'m looking for [finish this sentence!]'
      break
    case Post.Type.INTENTION:
      subject = 'I\'d like to create [finish this sentence!]'
      break
  }
  return 'mailto:' + address + '?subject=' + subject + '&body=' + body
}

var unsubscribeLink = function (user, community) {
  return 'http://google.com'
}

var emailData = function (user, community) {
  return {
    email: user.get('email'),
    sender: {
      name: format('%s (via Hylo)', community.get('name')),
      reply_to: 'hello@hylo.com'
    },
    data: {
      community_name: community.get('name'),
      user_name: user.get('name'),
      community_url: Frontend.Route.community(community) + '?ctt=solicitation_email',
      community_avatar_url: community.get('avatar_url'),
      unsubscribe_link: unsubscribeLink(user, community),
      mailto_offer: mailtoLink(community.id, user.id, Post.Type.OFFER),
      mailto_request: mailtoLink(community.id, user.id, Post.Type.REQUEST),
      mailto_intention: mailtoLink(community.id, user.id, Post.Type.INTENTION)
    }
  }
}

var queueEmail = function (emailData) {
  return Queue.classMethod('Email', 'sendPostSolicitation', emailData)
}

Solicitor.sendToUser = function (user, community) {
  return queueEmail(emailData(user, community))
}

Solicitor.sendToCommunity = function (communityId) {
  return Community.find(communityId, {withRelated: ['users']})
  .then(community => {
    sails.log.debug('Solicitor - sending emails to ', community.get('name'))
    return Promise.map(community.relations.users.models, user =>
      Solicitor.sendToUser(user, community))
  })
}

Solicitor.sendWeekly = function () {
  return Community.query('whereRaw', "settings->>'email_solicitation' = 'true'")
  .fetchAll()
  .then(communities => Promise.map(communities.models, community =>
      Solicitor.sendToCommunity(community.get('id'))))
}

module.exports = Solicitor
<commit_msg>add unsubscribe link<commit_after>var Promise = require('bluebird')
var rollbar = require('rollbar')
var sails = require('sails')

rollbar.init(process.env.ROLLBAR_SERVER_TOKEN)

var Solicitor = function (community, startTime, endTime, debug) {
  this.community = community
  this.communityName = community.get('name')
}

var mailtoLink = function (communityId, userId, type) {
  var address = Email.postCreationAddress(communityId, userId, Post.Type.OFFER)
  var subject
  var body = 'More details here...'

  switch (type) {
    case Post.Type.OFFER:
      subject = 'I\'d like to share [finish this sentence!]'
      break
    case Post.Type.REQUEST:
      subject = 'I\'m looking for [finish this sentence!]'
      break
    case Post.Type.INTENTION:
      subject = 'I\'d like to create [finish this sentence!]'
      break
  }
  return 'mailto:' + address + '?subject=' + subject + '&body=' + body
}

var unsubscribeLink = function (user) {
  return Frontend.Route.tokenLogin(user, user.generateTokenSync(), Frontend.Route.userSettings() + '?expand=solicitation')
}

var emailData = function (user, community) {
  return {
    email: user.get('email'),
    sender: {
      name: format('%s (via Hylo)', community.get('name')),
      reply_to: 'hello@hylo.com'
    },
    data: {
      community_name: community.get('name'),
      user_name: user.get('name'),
      community_url: Frontend.Route.community(community) + '?ctt=solicitation_email',
      community_avatar_url: community.get('avatar_url'),
      unsubscribe_link: unsubscribeLink(user),
      mailto_offer: mailtoLink(community.id, user.id, Post.Type.OFFER),
      mailto_request: mailtoLink(community.id, user.id, Post.Type.REQUEST),
      mailto_intention: mailtoLink(community.id, user.id, Post.Type.INTENTION)
    }
  }
}

var queueEmail = function (emailData) {
  return Queue.classMethod('Email', 'sendPostSolicitation', emailData)
}

Solicitor.sendToUser = function (user, community) {
  if (user.get('settings').email_solicitation_preference) {
    return queueEmail(emailData(user, community))
  } else {
    return Promise.resolve()
  }
}

Solicitor.sendToCommunity = function (communityId) {
  return Community.find(communityId, {withRelated: ['users']})
  .then(community => {
    sails.log.debug('Solicitor - sending emails to', community.get('name'))
    return Promise.map(community.relations.users.models, user =>
      Solicitor.sendToUser(user, community))
  })
}

Solicitor.sendWeekly = function () {
  return Community.query('whereRaw', "settings->>'email_solicitation' = 'true'")
  .fetchAll()
  .then(communities => Promise.map(communities.models, community =>
      Solicitor.sendToCommunity(community.get('id'))))
}

module.exports = Solicitor
<|endoftext|>