<commit_before>(function (exports) {

if (typeof jDataView === 'undefined' && typeof require !== 'undefined') {
	jDataView = require('jDataView');
}

// Extend code from underscorejs (modified for fast inheritance using prototypes)
function inherit(obj) {
	if ('create' in Object) {
		obj = Object.create(obj);
	} else {
		function ClonedObject() {}
		ClonedObject.prototype = obj;
		obj = new ClonedObject();
	}
	for (var i = 1; i < arguments.length; ++i) {
		var source = arguments[i];
		for (var prop in source) {
			if (source[prop] !== undefined) {
				obj[prop] = source[prop];
			}
		}
	}
	return obj;
}

function jBinary(view, structure) {
	if (!(this instanceof arguments.callee)) {
		throw new Error("Constructor may not be called as a function");
	}
	if (!(view instanceof jDataView)) {
		view = new jDataView(view, undefined, undefined, true);
	}
	this.view = view;
	this.view.seek(0);
	this._bitShift = 0;
	this.structure = inherit(jBinary.prototype.structure, structure);
}

jBinary.Property = function (reader, writer, forceNew) {
	var property = forceNew ? function () { return reader.apply(this, arguments) } : reader;
	if (writer) {
		property.write = writer;
	}
	return property;
};

function toInt(val) {
	return val instanceof Function ? val.call(this) : val;
}

jBinary.prototype.structure = {
	string: jBinary.Property(
		function (length) { return this.view.getString(toInt.call(this, length)) },
		function (length, subString) {
			if (subString.length > length) {
				subString = subString.slice(0, length);
			} else
			if (subString.length < length) {
				subString += String.fromCharCode.apply(null, new Array(length - subString.length));
			}
			this.view.writeString(subString);
		}
	),
	array: jBinary.Property(
		function (type, length) {
			length = toInt.call(this, length);
			var results = new Array(length);
			for (var i = 0; i < length; ++i) {
				results[i] = this.parse(type);
			}
			return results;
		},
		function (type, length, values) {
			for (var i = 0; i < length; i++) {
				this.write(type, values[i]);
			}
		}
	),
	bitfield: jBinary.Property(
		function (bitSize) {
			var fieldValue = 0;

			if (this._bitShift < 0 || this._bitShift >= 8) {
				var byteShift = this._bitShift >> 3; // Math.floor(_bitShift / 8)
				this.skip(byteShift);
				this._bitShift &= 7; // _bitShift + 8 * Math.floor(_bitShift / 8)
			}
			if (this._bitShift > 0 && bitSize >= 8 - this._bitShift) {
				fieldValue = this.view.getUint8() & ~(-1 << (8 - this._bitShift));
				bitSize -= 8 - this._bitShift;
				this._bitShift = 0;
			}
			while (bitSize >= 8) {
				fieldValue = this.view.getUint8() | (fieldValue << 8);
				bitSize -= 8;
			}
			if (bitSize > 0) {
				fieldValue = ((this.view.getUint8() >>> (8 - (this._bitShift + bitSize))) & ~(-1 << bitSize)) | (fieldValue << bitSize);
				this._bitShift += bitSize - 8; // passing negative value for next pass
			}

			return fieldValue;
		},
		function (bitSize, value) {
			if (this._bitShift < 0 || this._bitShift >= 8) {
				var byteShift = this._bitShift >> 3; // Math.floor(_bitShift / 8)
				this.skip(byteShift);
				this._bitShift &= 7; // _bitShift + 8 * Math.floor(_bitShift / 8)
			}
			if (this._bitShift > 0 && bitSize >= 8 - this._bitShift) {
				var pos = this.tell();
				var byte = this.view.getUint8(pos) & (-1 << (8 - this._bitShift));
				byte |= value >>> (bitSize - (8 - this._bitShift));
				this.view.setUint8(pos, byte);
				bitSize -= 8 - this._bitShift;
				this._bitShift = 0;
			}
			while (bitSize >= 8) {
				this.view.writeUint8((value >>> (bitSize - 8)) & 0xff);
				bitSize -= 8;
			}
			if (bitSize > 0) {
				var pos = this.tell();
				var byte = this.view.getUint8(pos) & ~(~(-1 << bitSize) << (8 - (this._bitShift + bitSize)));
				byte |= (value & ~(-1 << bitSize)) << (8 - (this._bitShift + bitSize));
				this.view.setUint8(pos, byte);
				this._bitShift += bitSize - 8; // passing negative value for next pass
			}
		}
	),
	seek: function (position, block) {
		position = toInt.call(this, position);
		if (block instanceof Function) {
			var old_position = this.view.tell();
			this.view.seek(position);
			var result = block.call(this);
			this.view.seek(old_position);
			return result;
		} else {
			return this.view.seek(position);
		}
	},
	tell: function () {
		return this.view.tell();
	},
	skip: function (offset) {
		offset = toInt.call(this, offset);
		this.view.seek(this.view.tell() + offset);
		return offset;
	}
};

function conditionalMethod(method) {
	return function (predicate) {
		if (predicate instanceof Function ? predicate.call(this) : predicate) {
			return this[method].apply(this, Array.prototype.slice.call(arguments, 1));
		}
	};
}

jBinary.prototype.structure.if = jBinary.Property(
	conditionalMethod('parse'),
	conditionalMethod('write')
);

var dataTypes = [
	'Uint8',
	'Uint16',
	'Uint32',
	'Int8',
	'Int16',
	'Int32',
	'Float32',
	'Float64',
	'Char'
];

function dataMethod(method, type) {
	return function (value) {
		return this.view[method + type](value);
	};
}

for (var i = 0; i < dataTypes.length; i++) {
	var dataType = dataTypes[i];
	jBinary.prototype.structure[dataType.toLowerCase()] = jBinary.Property(
		dataMethod('get', dataType),
		dataMethod('write', dataType)
	);
}

jBinary.prototype.seek = jBinary.prototype.structure.seek;
jBinary.prototype.tell = jBinary.prototype.structure.tell;
jBinary.prototype.skip = jBinary.prototype.structure.skip;

jBinary.prototype.parse = function (structure) {
	if (typeof structure === 'number') {
		structure = ['bitfield', structure];
	}

	// f, 1, 2 means f(1, 2)
	if (structure instanceof Function) {
		return structure.apply(this, Array.prototype.slice.call(arguments, 1));
	}

	// 'int32', ... is a shortcut for ['int32', ...]
	if (typeof structure === 'string') {
		structure = Array.prototype.slice.call(arguments);
	}

	// ['string', 256] means structure['string'](256)
	if (structure instanceof Array) {
		var key = structure[0];
		if (!(key in this.structure)) {
			throw new Error("Missing structure for `" + key + "`");
		}
		return this.parse.apply(this, [this.structure[key]].concat(structure.slice(1)));
	}

	// {key: val} means {key: parse(val)}
	if (typeof structure === 'object') {
		var output = {},
			current = this.current;

		this.current = output;

		for (var key in structure) {
			var value = this.parse(structure[key]);
			// skipping undefined call results (useful for 'if' statement)
			if (value !== undefined) {
				output[key] = value;
			}
		}

		this.current = current;

		return output;
	}

	throw new Error("Unknown structure type `" + structure + "`");
};

jBinary.prototype.write = function (structure, data) {
	if (typeof structure === 'number') {
		structure = ['bitfield', structure];
	}

	// f, 1, 2, data means f(1, 2, data)
	if (structure instanceof Function) {
		(structure.write || structure).apply(this, Array.prototype.slice.call(arguments, 1));
		return;
	}

	// 'int32', ..., value is a shortcut for ['int32', ..., value]
	if (typeof structure === 'string') {
		structure = Array.prototype.slice.call(arguments);
	}

	// ['string', 256], data means structure['string'](256, data)
	if (structure instanceof Array) {
		var key = structure[0];
		if (!(key in this.structure)) {
			throw new Error("Missing structure for `" + key + "`");
		}
		this.write.apply(this, [this.structure[key]].concat(structure.slice(1)).concat([data]));
		return;
	}

	// {key: type}, {key: value} means write(type, value)
	if (typeof structure === 'object') {
		var current = this.current;

		this.current = data;

		for (var key in structure) {
			this.write(structure[key], data[key]);
		}

		this.current = current;

		return;
	}

	throw new Error("Unknown structure type `" + structure + "`");
};

jBinary.prototype.modify = function (structure, callback) {
	var data = this.seek(this.tell(), function () {
		return this.parse(structure);
	});
	var newData = callback(data);
	if (newData === undefined) {
		newData = data;
	}
	this.write(structure, newData);
	return newData;
};

if (typeof module !== 'undefined' && exports === module.exports) {
	module.exports = jBinary;
} else {
	exports.jBinary = jBinary;
}

})(this);
<commit_msg> - Changed context handling - now should be obtained via `context` property that is basically stack of contexts with additional `getCurrent`, `getParent` methods for quick obtaining of current & parent contexts and `in` method for executing function with arguments in new context.<commit_after>// https://github.com/davidchambers/Base64.js
(function(){var t="undefined"!=typeof window?window:exports,r="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=",n=function(){try{document.createElement("$")}catch(t){return t}}();t.btoa||(t.btoa=function(t){for(var o,e,a=0,c=r,f="";t.charAt(0|a)||(c="=",a%1);f+=c.charAt(63&o>>8-8*(a%1))){if(e=t.charCodeAt(a+=.75),e>255)throw n;o=o<<8|e}return f}),t.atob||(t.atob=function(t){if(t=t.replace(/=+$/,""),1==t.length%4)throw n;for(var o,e,a=0,c=0,f="";e=t.charAt(c++);~e&&(o=a%4?64*o+e:e,a++%4)?f+=String.fromCharCode(255&o>>(6&-2*a)):0)e=r.indexOf(e);return f})})();

(function (exports) {

if (typeof jDataView === 'undefined' && typeof require !== 'undefined') {
	jDataView = require('jDataView');
}

function extend(obj) {
    for (var i = 1; i < arguments.length; ++i) {
        var source = arguments[i];
        for (var prop in source) {
            if (source[prop] !== undefined) {
                obj[prop] = source[prop];
            }
        }
    }
    return obj;
}

function inherit(obj) {
	if ('create' in Object) {
		obj = Object.create(obj);
	} else {
		function ClonedObject() {}
		ClonedObject.prototype = obj;
		obj = new ClonedObject();
	}
	return extend.apply(this, arguments);
}

function jBinary(view, structure) {
    if (!(view instanceof jDataView)) {
        view = new jDataView(view);
    }
    if (!(this instanceof jBinary)) {
		return new jBinary(view, structure);
	}
	this.view = view;
	this.view.seek(0);
	this._bitShift = 0;
    var self = this;
    this.context = [self];
    this.context.in = function (newContext, callback) {
        this.unshift(newContext);
        var result = callback.apply(self, Array.prototype.slice.call(arguments, 2));
        this.shift();
        return result;
    };
    this.context.getCurrent = function () { return this[0] };
    this.context.getParent = function () { return this[1] };
	this.structure = inherit(jBinary.prototype.structure, structure);
}

jBinary.Property = function (reader, writer, forceNew) {
	var property = forceNew ? function () { return reader.apply(this, arguments) } : reader;
	if (writer) {
		property.write = writer;
	}
	return property;
};

function toInt(val) {
	return val instanceof Function ? val.call(this) : val;
}

function calcStringLength() {
    var begin = this.tell();
    var end = this.seek(begin, function () {
        while (this.view.getUint8());
        return this.tell();
    }) - 1;
    return end - begin;
}

jBinary.prototype.structure = {
    extend: jBinary.Property(
        function (baseType) {
            var obj = this.parse(baseType);
            var parts = arguments;
            this.context.in(obj, function () {
                for (var i = 1, length = parts.length; i < length; i++) {
                    extend(obj, this.parse(parts[i]));
                }
            });
            return obj;
        },
        function () {
            var obj = arguments[arguments.length - 1];
            var parts = arguments;
            this.context.in(obj, function () {
                for (var i = 0, length = parts.length - 1; i < length; i++) {
                    this.write(parts[i], obj);
                }
            });
        }
    ),
    string: jBinary.Property(
		function (length) {
            var string = this.view.getString(toInt.call(this, length !== undefined ? length : calcStringLength));
            if (length === undefined) {
                this.skip(1);
            }
            return string;
        },
		function (length, subString) {
            if (length !== undefined) {
                length = toInt.call(this, length);
                if (subString.length > length) {
                    subString = subString.slice(0, length);
                } else
                if (subString.length < length) {
                    subString += String.fromCharCode.apply(null, new Array(length - subString.length));
                }
            }

			this.view.writeString(subString);
		}
	),
	array: jBinary.Property(
		function (type, length) {
			length = toInt.call(this, length);
			var results = new Array(length);
			for (var i = 0; i < length; ++i) {
				results[i] = this.parse(type);
			}
			return results;
		},
		function (type, length, values) {
			for (var i = 0; i < length; i++) {
				this.write(type, values[i]);
			}
		}
	),
    object: jBinary.Property(
        function (structure) {
            var output = {};
            this.context.in(output, function () {
                for (var key in structure) {
                    var value = this.parse(structure[key]);
                    // skipping undefined call results (useful for 'if' statement)
                    if (value !== undefined) {
                        output[key] = value;
                    }
                }
            });
            return output;
        },
        function (structure, data) {
            this.context.in(data, function () {
                for (var key in structure) {
                    this.write(structure[key], data[key]);
                }
            });
        }
    ),
	bitfield: jBinary.Property(
		function (bitSize) {
			var fieldValue = 0;

			if (this._bitShift < 0 || this._bitShift >= 8) {
				var byteShift = this._bitShift >> 3; // Math.floor(_bitShift / 8)
				this.skip(byteShift);
				this._bitShift &= 7; // _bitShift + 8 * Math.floor(_bitShift / 8)
			}
			if (this._bitShift > 0 && bitSize >= 8 - this._bitShift) {
				fieldValue = this.view.getUint8() & ~(-1 << (8 - this._bitShift));
				bitSize -= 8 - this._bitShift;
				this._bitShift = 0;
			}
			while (bitSize >= 8) {
				fieldValue = this.view.getUint8() | (fieldValue << 8);
				bitSize -= 8;
			}
			if (bitSize > 0) {
				fieldValue = ((this.view.getUint8() >>> (8 - (this._bitShift + bitSize))) & ~(-1 << bitSize)) | (fieldValue << bitSize);
				this._bitShift += bitSize - 8; // passing negative value for next pass
			}

			return fieldValue;
		},
		function (bitSize, value) {
			if (this._bitShift < 0 || this._bitShift >= 8) {
				var byteShift = this._bitShift >> 3; // Math.floor(_bitShift / 8)
				this.skip(byteShift);
				this._bitShift &= 7; // _bitShift + 8 * Math.floor(_bitShift / 8)
			}
			if (this._bitShift > 0 && bitSize >= 8 - this._bitShift) {
				var pos = this.tell();
				var byte = this.view.getUint8(pos) & (-1 << (8 - this._bitShift));
				byte |= value >>> (bitSize - (8 - this._bitShift));
				this.view.setUint8(pos, byte);
				bitSize -= 8 - this._bitShift;
				this._bitShift = 0;
			}
			while (bitSize >= 8) {
				this.view.writeUint8((value >>> (bitSize - 8)) & 0xff);
				bitSize -= 8;
			}
			if (bitSize > 0) {
				var pos = this.tell();
				var byte = this.view.getUint8(pos) & ~(~(-1 << bitSize) << (8 - (this._bitShift + bitSize)));
				byte |= (value & ~(-1 << bitSize)) << (8 - (this._bitShift + bitSize));
				this.view.setUint8(pos, byte);
				this._bitShift += bitSize - 8; // passing negative value for next pass
			}
		}
	),
	seek: function (position, block) {
		position = toInt.call(this, position);
		if (block instanceof Function) {
			var old_position = this.view.tell();
			this.view.seek(position);
			var result = block.call(this);
			this.view.seek(old_position);
			return result;
		} else {
			return this.view.seek(position);
		}
	},
	tell: function () {
		return this.view.tell();
	},
	skip: function (offset) {
		offset = toInt.call(this, offset);
		this.view.seek(this.view.tell() + offset);
		return offset;
	}
};

function conditionalMethod(method) {
	return function (predicate) {
		if (predicate instanceof Function ? predicate.call(this) : predicate) {
			return this[method].apply(this, Array.prototype.slice.call(arguments, 1));
		}
	};
}

jBinary.prototype.structure.if = jBinary.Property(
	conditionalMethod('parse'),
	conditionalMethod('write')
);

var dataTypes = [
	'Uint8',
	'Uint16',
	'Uint32',
	'Int8',
	'Int16',
	'Int32',
	'Float32',
	'Float64',
	'Char'
];

function dataMethod(method, type) {
	return function (value) {
		return this.view[method + type](value);
	};
}

for (var i = 0; i < dataTypes.length; i++) {
	var dataType = dataTypes[i];
	jBinary.prototype.structure[dataType.toLowerCase()] = jBinary.Property(
		dataMethod('get', dataType),
		dataMethod('write', dataType)
	);
}

jBinary.prototype.seek = jBinary.prototype.structure.seek;
jBinary.prototype.tell = jBinary.prototype.structure.tell;
jBinary.prototype.skip = jBinary.prototype.structure.skip;

jBinary.prototype.parse = function (structure) {
    switch (typeof structure) {
        case 'string':
            structure = this.structure[structure];
            return this.parse.apply(this, arguments);

        case 'function':
            return structure.apply(this, Array.prototype.slice.call(arguments, 1));

        case 'number':
            structure = ['bitfield', structure];

        case 'object':
            if (!(structure instanceof Array)) {
                structure = ['object', structure];
            }
            return this.parse.apply(this, structure);

        default:
            throw new Error("Unknown structure type `" + structure + "`");
    }
};

jBinary.prototype.write = function (structure, data) {
    switch (typeof structure) {
        case 'string':
            structure = this.structure[structure];
            return this.write.apply(this, arguments);

        case 'function':
            return (structure.write || structure).apply(this, Array.prototype.slice.call(arguments, 1));

        case 'number':
            structure = ['bitfield', structure];

        case 'object':
            if (!(structure instanceof Array)) {
                structure = ['object', structure];
            }
            return this.write.apply(this, structure.concat([data]));

        default:
            throw new Error("Unknown structure type `" + structure + "`");
    }
};

jBinary.prototype.modify = function (structure, callback) {
	var data = this.seek(this.tell(), function () {
		return this.parse(structure);
	});
	var newData = callback(data);
	if (newData === undefined) {
		newData = data;
	}
	this.write(structure, newData);
	return newData;
};

jBinary.prototype.toURL = function (type) {
    type = type || 'application/octet-stream';
    if (!window.URL || !window.URL.createObjectURL) {
        return 'data:' + type + ';base64,' + btoa(this.seek(0, function () { return this.view.getString() }));
    } else {
        var data = this.seek(0, function () { return this.view._getBytes(undefined, undefined, true) });
        return URL.createObjectURL(new Blob([data], {type: type}));
    }
};

if (typeof module !== 'undefined' && exports === module.exports) {
	module.exports = jBinary;
} else {
	exports.jBinary = jBinary;
}

})(this);
<|endoftext|>


<commit_before>/*
  Copyright (C) 2012 Mihai Bazon <mihai.bazon@gmail.com>
  Copyright (C) 2012 Yusuke Suzuki <utatane.tea@gmail.com>

  Redistribution and use in source and binary forms, with or without
  modification, are permitted provided that the following conditions are met:

    * Redistributions of source code must retain the above copyright
      notice, this list of conditions and the following disclaimer.
    * Redistributions in binary form must reproduce the above copyright
      notice, this list of conditions and the following disclaimer in the
      documentation and/or other materials provided with the distribution.

  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
  AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  ARE DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
  DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
  (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
  LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
  ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
  THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/

/*jslint bitwise:true */
/*global module:true, require:true*/
(function () {
    'use strict';

    var Syntax, common, modified;

    common = require('../common');
    Syntax = common.Syntax;

    function booleanTransformation(expr) {
        var consequent;
        do {
            if (expr.type === Syntax.UnaryExpression) {
                if (expr.operator === '!' &&
                    expr.argument.type === Syntax.UnaryExpression && expr.argument.operator === '!') {
                    modified = true;
                    expr = expr.argument.argument;
                    continue;
                }
            } else if (expr.type === Syntax.LogicalExpression) {
                if (expr.left.type === Syntax.UnaryExpression && expr.left.operator === '!' &&
                    expr.right.type === Syntax.UnaryExpression && expr.right.operator === '!') {
                    // !cond && !ok() => !(cond || ok())
                    // this introduces more optimizations
                    modified = true;
                    expr.left = expr.left.argument;
                    expr.right = expr.right.argument;
                    expr.operator = (expr.operator === '||') ? '&&' : '||';
                    expr = common.moveLocation(expr, {
                        type: Syntax.UnaryExpression,
                        operator: '!',
                        argument: expr
                    });
                    continue;
                }
            } else if (expr.type === Syntax.ConditionalExpression) {
                if (expr.test.type === Syntax.UnaryExpression && expr.test.operator === '!') {
                    modified = true;
                    expr.test = expr.test.argument;
                    consequent = expr.consequent;
                    expr.consequent = expr.alternate;
                    expr.alternate = consequent;
                }
            }
            break;
        } while (true);
        return expr;
    }

    function voidTransformation(expr) {
        do {
            expr = booleanTransformation(expr);
            if (expr.type === Syntax.UnaryExpression) {
                if (expr.operator === '!' || expr.operator === 'void') {
                    modified = true;
                    expr = expr.argument;
                    continue;
                }
            } else if (expr.type === Syntax.LogicalExpression) {
                if (expr.left.type === Syntax.UnaryExpression && expr.left.operator === '!') {
                    // !cond && ok() => cond || ok()
                    modified = true;
                    expr.left = expr.left.argument;
                    expr.operator = (expr.operator === '||') ? '&&' : '||';
                }
            }
            break;
        } while (true);
        return expr;
    }

    function apply(expr, trans, booleanFunction, voidFunction) {
        var prev;
        do {
            prev = expr;
            expr = trans(expr);
            if (prev !== expr) {
                continue;
            }

            if (expr.type === Syntax.LogicalExpression) {
                expr.left = booleanFunction(expr.left);
                expr.right = voidFunction(expr.right);
            } else if (expr.type === Syntax.ConditionalExpression) {
                expr.consequent = voidFunction(expr.consequent);
                expr.alternate = voidFunction(expr.alternate);
            } else if (expr.type === Syntax.SequenceExpression) {
                expr.expressions[expr.expressions.length - 1] = voidFunction(common.Array.last(expr.expressions));
            }
            break;
        } while (true);
        return expr;
    }

    function voidContext(expr) {
        return apply(expr, voidTransformation, booleanContext, voidContext);
    }

    function booleanContext(expr) {
        return apply(expr, booleanTransformation, booleanContext, booleanContext);
    }

    function removeContextSensitiveExpressions(tree, options) {
        var result, stack;

        if (options == null) {
            options = { destructive: false };
        }

        result = (options.destructive) ? tree : common.deepCopy(tree);
        modified = false;
        stack = [];

        result = common.replace(result, {
            enter: function enter(node) {
                var i, iz;
                if (node.type === Syntax.FunctionExpression || node.type === Syntax.FunctionDeclaration) {
                    stack.push(null);
                }

                switch (node.type) {
                case Syntax.AssignmentExpression:
                    break;

                case Syntax.ArrayExpression:
                    break;

                case Syntax.BlockStatement:
                    break;

                case Syntax.BinaryExpression:
                    break;

                case Syntax.BreakStatement:
                    break;

                case Syntax.CallExpression:
                    break;

                case Syntax.CatchClause:
                    break;

                case Syntax.ConditionalExpression:
                    node.test = booleanContext(node.test);
                    break;

                case Syntax.ContinueStatement:
                    break;

                case Syntax.DoWhileStatement:
                    node.test = booleanContext(node.test);
                    break;

                case Syntax.DebuggerStatement:
                    break;

                case Syntax.EmptyStatement:
                    break;

                case Syntax.ExpressionStatement:
                    if (stack.length !== 0) {
                        // not global context
                        node.expression = voidContext(node.expression);
                    }
                    break;

                case Syntax.ForStatement:
                    break;

                case Syntax.ForInStatement:
                    break;

                case Syntax.FunctionDeclaration:
                    break;

                case Syntax.FunctionExpression:
                    if (node.init && node.init.type !== Syntax.VariableDeclaration) {
                        node.init = voidContext(node.init);
                    }
                    if (node.test) {
                        node.test = booleanContext(node.test);
                    }
                    if (node.update) {
                        node.update = voidContext(node.update);
                    }
                    break;

                case Syntax.Identifier:
                    break;

                case Syntax.IfStatement:
                    node.test = booleanContext(node.test);
                    break;

                case Syntax.Literal:
                    break;

                case Syntax.LabeledStatement:
                    break;

                case Syntax.LogicalExpression:
                    break;

                case Syntax.MemberExpression:
                    break;

                case Syntax.NewExpression:
                    break;

                case Syntax.ObjectExpression:
                    break;

                case Syntax.Program:
                    break;

                case Syntax.Property:
                    break;

                case Syntax.ReturnStatement:
                    break;

                case Syntax.SequenceExpression:
                    for (i = 0, iz = node.expressions.length - 1; i < iz; ++i) {
                        node.expressions[i] = voidContext(node.expressions[i]);
                    }
                    break;

                case Syntax.SwitchStatement:
                    break;

                case Syntax.SwitchCase:
                    break;

                case Syntax.ThisExpression:
                    break;

                case Syntax.ThrowStatement:
                    break;

                case Syntax.TryStatement:
                    break;

                case Syntax.UnaryExpression:
                    if (node.operator === '!') {
                        node.argument = booleanContext(node.argument);
                    } else if (node.operator === 'void') {
                        node.argument = voidContext(node.argument);
                    }
                    break;

                case Syntax.UpdateExpression:
                    break;

                case Syntax.VariableDeclaration:
                    break;

                case Syntax.VariableDeclarator:
                    break;

                case Syntax.WhileStatement:
                    node.test = booleanContext(node.test);
                    break;

                case Syntax.WithStatement:
                    break;

                }
            },

            leave: function leave(node) {
                if (node.type === Syntax.FunctionExpression || node.type === Syntax.FunctionDeclaration) {
                    stack.pop();
                }
            }
        });

        return {
            result: result,
            modified: modified
        };
    }

    removeContextSensitiveExpressions.passName = 'remove-context-sensitive-expressions';
    module.exports = removeContextSensitiveExpressions;
}());
/* vim: set sw=4 ts=4 et tw=80 : */
<commit_msg>Change global recognition more efficient way<commit_after>/*
  Copyright (C) 2012 Mihai Bazon <mihai.bazon@gmail.com>
  Copyright (C) 2012 Yusuke Suzuki <utatane.tea@gmail.com>

  Redistribution and use in source and binary forms, with or without
  modification, are permitted provided that the following conditions are met:

    * Redistributions of source code must retain the above copyright
      notice, this list of conditions and the following disclaimer.
    * Redistributions in binary form must reproduce the above copyright
      notice, this list of conditions and the following disclaimer in the
      documentation and/or other materials provided with the distribution.

  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
  AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  ARE DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
  DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
  (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
  LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
  ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
  THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/

/*jslint bitwise:true */
/*global module:true, require:true*/
(function () {
    'use strict';

    var Syntax, common, modified;

    common = require('../common');
    Syntax = common.Syntax;

    function booleanTransformation(expr) {
        var consequent;
        do {
            if (expr.type === Syntax.UnaryExpression) {
                if (expr.operator === '!' &&
                    expr.argument.type === Syntax.UnaryExpression && expr.argument.operator === '!') {
                    modified = true;
                    expr = expr.argument.argument;
                    continue;
                }
            } else if (expr.type === Syntax.LogicalExpression) {
                if (expr.left.type === Syntax.UnaryExpression && expr.left.operator === '!' &&
                    expr.right.type === Syntax.UnaryExpression && expr.right.operator === '!') {
                    // !cond && !ok() => !(cond || ok())
                    // this introduces more optimizations
                    modified = true;
                    expr.left = expr.left.argument;
                    expr.right = expr.right.argument;
                    expr.operator = (expr.operator === '||') ? '&&' : '||';
                    expr = common.moveLocation(expr, {
                        type: Syntax.UnaryExpression,
                        operator: '!',
                        argument: expr
                    });
                    continue;
                }
            } else if (expr.type === Syntax.ConditionalExpression) {
                if (expr.test.type === Syntax.UnaryExpression && expr.test.operator === '!') {
                    modified = true;
                    expr.test = expr.test.argument;
                    consequent = expr.consequent;
                    expr.consequent = expr.alternate;
                    expr.alternate = consequent;
                }
            }
            break;
        } while (true);
        return expr;
    }

    function voidTransformation(expr) {
        do {
            expr = booleanTransformation(expr);
            if (expr.type === Syntax.UnaryExpression) {
                if (expr.operator === '!' || expr.operator === 'void') {
                    modified = true;
                    expr = expr.argument;
                    continue;
                }
            } else if (expr.type === Syntax.LogicalExpression) {
                if (expr.left.type === Syntax.UnaryExpression && expr.left.operator === '!') {
                    // !cond && ok() => cond || ok()
                    modified = true;
                    expr.left = expr.left.argument;
                    expr.operator = (expr.operator === '||') ? '&&' : '||';
                }
            }
            break;
        } while (true);
        return expr;
    }

    function apply(expr, trans, booleanFunction, voidFunction) {
        var prev;
        do {
            prev = expr;
            expr = trans(expr);
            if (prev !== expr) {
                continue;
            }

            if (expr.type === Syntax.LogicalExpression) {
                expr.left = booleanFunction(expr.left);
                expr.right = voidFunction(expr.right);
            } else if (expr.type === Syntax.ConditionalExpression) {
                expr.consequent = voidFunction(expr.consequent);
                expr.alternate = voidFunction(expr.alternate);
            } else if (expr.type === Syntax.SequenceExpression) {
                expr.expressions[expr.expressions.length - 1] = voidFunction(common.Array.last(expr.expressions));
            }
            break;
        } while (true);
        return expr;
    }

    function voidContext(expr) {
        return apply(expr, voidTransformation, booleanContext, voidContext);
    }

    function booleanContext(expr) {
        return apply(expr, booleanTransformation, booleanContext, booleanContext);
    }

    function removeContextSensitiveExpressions(tree, options) {
        var result, stackCount;

        if (options == null) {
            options = { destructive: false };
        }

        result = (options.destructive) ? tree : common.deepCopy(tree);
        modified = false;
        stackCount = 0;

        result = common.replace(result, {
            enter: function enter(node) {
                var i, iz;
                if (node.type === Syntax.FunctionExpression || node.type === Syntax.FunctionDeclaration) {
                    ++stackCount;
                }

                switch (node.type) {
                case Syntax.AssignmentExpression:
                    break;

                case Syntax.ArrayExpression:
                    break;

                case Syntax.BlockStatement:
                    break;

                case Syntax.BinaryExpression:
                    break;

                case Syntax.BreakStatement:
                    break;

                case Syntax.CallExpression:
                    break;

                case Syntax.CatchClause:
                    break;

                case Syntax.ConditionalExpression:
                    node.test = booleanContext(node.test);
                    break;

                case Syntax.ContinueStatement:
                    break;

                case Syntax.DoWhileStatement:
                    node.test = booleanContext(node.test);
                    break;

                case Syntax.DebuggerStatement:
                    break;

                case Syntax.EmptyStatement:
                    break;

                case Syntax.ExpressionStatement:
                    if (stackCount !== 0) {
                        // not global context
                        node.expression = voidContext(node.expression);
                    }
                    break;

                case Syntax.ForStatement:
                    break;

                case Syntax.ForInStatement:
                    break;

                case Syntax.FunctionDeclaration:
                    break;

                case Syntax.FunctionExpression:
                    if (node.init && node.init.type !== Syntax.VariableDeclaration) {
                        node.init = voidContext(node.init);
                    }
                    if (node.test) {
                        node.test = booleanContext(node.test);
                    }
                    if (node.update) {
                        node.update = voidContext(node.update);
                    }
                    break;

                case Syntax.Identifier:
                    break;

                case Syntax.IfStatement:
                    node.test = booleanContext(node.test);
                    break;

                case Syntax.Literal:
                    break;

                case Syntax.LabeledStatement:
                    break;

                case Syntax.LogicalExpression:
                    break;

                case Syntax.MemberExpression:
                    break;

                case Syntax.NewExpression:
                    break;

                case Syntax.ObjectExpression:
                    break;

                case Syntax.Program:
                    break;

                case Syntax.Property:
                    break;

                case Syntax.ReturnStatement:
                    break;

                case Syntax.SequenceExpression:
                    for (i = 0, iz = node.expressions.length - 1; i < iz; ++i) {
                        node.expressions[i] = voidContext(node.expressions[i]);
                    }
                    break;

                case Syntax.SwitchStatement:
                    break;

                case Syntax.SwitchCase:
                    break;

                case Syntax.ThisExpression:
                    break;

                case Syntax.ThrowStatement:
                    break;

                case Syntax.TryStatement:
                    break;

                case Syntax.UnaryExpression:
                    if (node.operator === '!') {
                        node.argument = booleanContext(node.argument);
                    } else if (node.operator === 'void') {
                        node.argument = voidContext(node.argument);
                    }
                    break;

                case Syntax.UpdateExpression:
                    break;

                case Syntax.VariableDeclaration:
                    break;

                case Syntax.VariableDeclarator:
                    break;

                case Syntax.WhileStatement:
                    node.test = booleanContext(node.test);
                    break;

                case Syntax.WithStatement:
                    break;

                }
            },

            leave: function leave(node) {
                if (node.type === Syntax.FunctionExpression || node.type === Syntax.FunctionDeclaration) {
                    --stackCount;
                }
            }
        });

        return {
            result: result,
            modified: modified
        };
    }

    removeContextSensitiveExpressions.passName = 'remove-context-sensitive-expressions';
    module.exports = removeContextSensitiveExpressions;
}());
/* vim: set sw=4 ts=4 et tw=80 : */
<|endoftext|>


<commit_before>user = "";
userTeam = "";
userJailed = "";
gameServerAddress = window.location.origin + "/";

function getAllStats() {
    if (document.getElementById("stats")) {
        var divContents = "";
        $.ajax({
            url: "stats.json?time="+Date.now()
        }).done(function(stats) {
            if (stats["roundName"] == null) {
                console.log("No active round");
                $("#stats").html("");
            } else {
                divContents += "

	Tabatud	Puude	Miinus	Skoor
";
                for(i in stats["teams"]) {
                    team = stats["teams"][i];
                    divContents += "
"+team["name"]+"	"+team["spotCount"]+"	"+team["touchCount"]+"	"+team["disloyality"]+"	"+team["score"]+"
";
                    for (i in team["players"]) {
                        player = team["players"][i];
                        divContents += "
"+player["name"]+"	"+player["spotCount"]+"	"+player["touchCount"]+"	"+player["disloyality"]+"	"+player["score"]+"
";
                    }
                }
                divContents += "
";
                divContents += "

";
                $("#stats").html(divContents);
            }
        });
    }
}

function getAllEvents() {
    if (document.getElementById("events")) {
        var divContents = "";
        $.ajax({
            url: "events.json?time="+Date.now()
        }).done(function(events) {
            if ("event" in events[0]) {
                console.log("No events to show");
                $("#events").html("");
            } else {
                for(i in events) {
                    event = events[i];
                    if (event["visible"] == "All") {
                        divContents += "
"+event["time"];
                        divContents += " "+event["text1"]["text"]+"";
                        divContents += " "+event["text2"]["text"]+"";
                        if (event["text3"]["text"] != null) {
                            divContents += " "+event["text3"]["text"]+"";
                        }
                        divContents += "
";
                    }
                }
                $("#events").html(divContents);
            }
        });
    }
}

function getRoundInfoBase(role) {
    if (document.getElementById("roundInfo")) {
        $.ajax({
            url: "stats.json?time="+Date.now()
        }).done(function(stats) {
            if(stats["roundName"] != null) {
                $("#roundInfo").html("
Lahing \"" + stats["roundName"] + "\", Kasutaja: " + role + "
");
            } else {
                $("#roundInfo").html("");
            }
        });
    }
}

function getStats() {
    if (document.getElementById("stats")) {
        var divContents = "";
        $.ajax({
            url: "stats.json?time="+Date.now()
        }).done(function(stats) {
            if(stats["roundName"] != null) {
                divContents += "

	Tabatud	Puude	Miinus	Skoor
";
                for(i in stats["teams"]) {
                    team = stats["teams"][i];
                    divContents += "
"+team["name"]+"	"+team["spotCount"]+"	"+team["touchCount"]+"	"+team["disloyality"]+"	"+team["score"]+"
";
                    for (i in team["players"]) {
                        player = team["players"][i];
                        if (player["name"] == user) {
                            divContents += "
"+player["name"]+"	"+player["spotCount"]+"	"+player["touchCount"]+"	"+player["disloyality"]+"	"+player["score"]+"
";
                        }
                    }
                }
                divContents += "
";
                divContents += "

";
                $("#stats").html(divContents);
            } else {
                $("#stats").html("");
            }
        });
    }
}

function getEvents() {
    if (document.getElementById("events")) {
        var divContents = "";
        $.ajax({
            url: "events.json?time="+Date.now()
        }).done(function(events) {
            if ("event" in events[0]) {
                console.log("No events to show");
                $("#events").html("");
            } else {
                for(i in events) {
                    event = events[i];
                    if (event["visible"] == "All" || (event["visible"] == "Sinised" && (userTeam % 2) == 1) || (event["visible"] == "Punased" && (userTeam % 2) == 0)) {
                        divContents += "
"+event["time"];
                        divContents += " "+event["text1"]["text"]+"";
                        divContents += " "+event["text2"]["text"]+"";
                        if (event["text3"]["text"] != null) {
                            divContents += " "+event["text3"]["text"]+"";
                        }
                        divContents += "
";
                    }
                }
                $("#events").html(divContents);
            }
        });
    }
}

function getRoundInfo() {
    if (document.getElementById("round-info")) {
        $.ajax({
            url: "stats.json?time="+Date.now()
        }).done(function(stats) {
            if(stats["roundName"] != null) {
                $("#round-info").html("
Lahing \"" + stats["roundName"] + "\", mängija: " + user + "
");
            } else {
                $("#round-info").html("");
            }
        });
    }
}

function timeToEnd() {
    currentDate = new Date();
    if (document.getElementById("round-info")) {
        $.ajax({
            url: "stats.json?time="+Date.now()
        }).done(function(stats) {
            if(stats["roundName"] != null) {
                var ending = stats["roundEnd"];
                endTime = new Date(ending.substring(0,4),ending.substring(5,7),ending.substring(8,10),ending.substring(11,13),ending.substring(14,16),ending.substring(17,19));
                var toEnd = new Date(endTime.getTime() - new Date(currentDate.getTime() + 21*60*60*1000));
                $("#toEnd").html("Aega vooru lõpuni " + addZerobefore(toEnd.getUTCHours()) + ":" + addZerobefore(toEnd.getUTCMinutes()) + ":" + addZerobefore(toEnd.getUTCSeconds()));
            } else {
                $("#toEnd").html("");
            }
        });
    }
}

function isJailed() {
    if (document.getElementById("isJailed")) {
        $.ajax({
            url: "isJailed"
        }).done(function(inJail) {
            userJailed = inJail;
        });
    }
}

function getUser() {
    $.ajax({
        url: "user"
    }).done(function(username) {
        user = username;
    });
}

function getUserTeam() {
    $.ajax({
        url: "userTeam"
    }).done(function(team) {
        userTeam = team;
    });
}

function getMessage() {
    $.ajax({
        url: "message"
    }).done(function(message) {
        if (message["message"] != null) {
            $("#messages").html(message["message"]);
        }
    });
}

function getBaseMessage() {
    $.ajax({
        url: "baseMessage"
    }).done(function(baseMessage) {
        if (!null) {
            $("#messages").html(baseMessage);
        }
    });
}

function addZerobefore(number) {
    if(parseInt(number) < 10 && parseInt(number) > -10) {
        number = "0" + parseInt(number);
    }
    return number;
}
<commit_msg>Events now showing correct time.<commit_after>user = "";
userTeam = "";
userJailed = "";
gameServerAddress = window.location.origin + "/";

function getAllStats() {
    if (document.getElementById("stats")) {
        var divContents = "";
        $.ajax({
            url: "stats.json?time="+Date.now()
        }).done(function(stats) {
            if (stats["roundName"] == null) {
                console.log("No active round");
                $("#stats").html("");
            } else {
                divContents += "

	Tabatud	Puude	Miinus	Skoor
";
                for(i in stats["teams"]) {
                    team = stats["teams"][i];
                    divContents += "
"+team["name"]+"	"+team["spotCount"]+"	"+team["touchCount"]+"	"+team["disloyality"]+"	"+team["score"]+"
";
                    for (i in team["players"]) {
                        player = team["players"][i];
                        divContents += "
"+player["name"]+"	"+player["spotCount"]+"	"+player["touchCount"]+"	"+player["disloyality"]+"	"+player["score"]+"
";
                    }
                }
                divContents += "
";
                divContents += "

";
                $("#stats").html(divContents);
            }
        });
    }
}

function getAllEvents() {
    if (document.getElementById("events")) {
        var divContents = "";
        $.ajax({
            url: "events.json?time="+Date.now()
        }).done(function(events) {
            if ("event" in events[0]) {
                console.log("No events to show");
                $("#events").html("");
            } else {
                for(i in events) {
                    event = events[i];
                    if (event["visible"] == "All") {
                        divContents += "
"+event["time"];
                        divContents += " "+event["text1"]["text"]+"";
                        divContents += " "+event["text2"]["text"]+"";
                        if (event["text3"]["text"] != null) {
                            divContents += " "+event["text3"]["text"]+"";
                        }
                        divContents += "
";
                    }
                }
                $("#events").html(divContents);
            }
        });
    }
}

function getRoundInfoBase(role) {
    if (document.getElementById("roundInfo")) {
        $.ajax({
            url: "stats.json?time="+Date.now()
        }).done(function(stats) {
            if(stats["roundName"] != null) {
                $("#roundInfo").html("
Lahing \"" + stats["roundName"] + "\", Kasutaja: " + role + "
");
            } else {
                $("#roundInfo").html("");
            }
        });
    }
}

function getStats() {
    if (document.getElementById("stats")) {
        var divContents = "";
        $.ajax({
            url: "stats.json?time="+Date.now()
        }).done(function(stats) {
            if(stats["roundName"] != null) {
                divContents += "

	Tabatud	Puude	Miinus	Skoor
";
                for(i in stats["teams"]) {
                    team = stats["teams"][i];
                    divContents += "
"+team["name"]+"	"+team["spotCount"]+"	"+team["touchCount"]+"	"+team["disloyality"]+"	"+team["score"]+"
";
                    for (i in team["players"]) {
                        player = team["players"][i];
                        if (player["name"] == user) {
                            divContents += "
"+player["name"]+"	"+player["spotCount"]+"	"+player["touchCount"]+"	"+player["disloyality"]+"	"+player["score"]+"
";
                        }
                    }
                }
                divContents += "
";
                divContents += "

";
                $("#stats").html(divContents);
            } else {
                $("#stats").html("");
            }
        });
    }
}

function getEvents() {
    if (document.getElementById("events")) {
        var divContents = "";
        $.ajax({
            url: "events.json?time="+Date.now()
        }).done(function(events) {
            if ("event" in events[0]) {
                console.log("No events to show");
                $("#events").html("");
            } else {
                for(i in events) {
                    event = events[i];
                    if (event["visible"] == "All" || (event["visible"] == "Sinised" && (userTeam % 2) == 1) || (event["visible"] == "Punased" && (userTeam % 2) == 0)) {
                        divContents += "
" + parseInt(event["time"].substring(0,2)) + 3 + event["time"].substring(2,5);
                        divContents += " "+event["text1"]["text"]+"";
                        divContents += " "+event["text2"]["text"]+"";
                        if (event["text3"]["text"] != null) {
                            divContents += " "+event["text3"]["text"]+"";
                        }
                        divContents += "
";
                    }
                }
                $("#events").html(divContents);
            }
        });
    }
}

function getRoundInfo() {
    if (document.getElementById("round-info")) {
        $.ajax({
            url: "stats.json?time="+Date.now()
        }).done(function(stats) {
            if(stats["roundName"] != null) {
                $("#round-info").html("
Lahing \"" + stats["roundName"] + "\", mängija: " + user + "
");
            } else {
                $("#round-info").html("");
            }
        });
    }
}

function timeToEnd() {
    currentDate = new Date();
    if (document.getElementById("round-info")) {
        $.ajax({
            url: "stats.json?time="+Date.now()
        }).done(function(stats) {
            if(stats["roundName"] != null) {
                var ending = stats["roundEnd"];
                endTime = new Date(ending.substring(0,4),ending.substring(5,7),ending.substring(8,10),ending.substring(11,13),ending.substring(14,16),ending.substring(17,19));
                var toEnd = new Date(endTime.getTime() - new Date(currentDate.getTime() + 21*60*60*1000));
                $("#toEnd").html("Aega vooru lõpuni " + addZerobefore(toEnd.getUTCHours()) + ":" + addZerobefore(toEnd.getUTCMinutes()) + ":" + addZerobefore(toEnd.getUTCSeconds()));
            } else {
                $("#toEnd").html("");
            }
        });
    }
}

function isJailed() {
    if (document.getElementById("isJailed")) {
        $.ajax({
            url: "isJailed"
        }).done(function(inJail) {
            userJailed = inJail;
        });
    }
}

function getUser() {
    $.ajax({
        url: "user"
    }).done(function(username) {
        user = username;
    });
}

function getUserTeam() {
    $.ajax({
        url: "userTeam"
    }).done(function(team) {
        userTeam = team;
    });
}

function getMessage() {
    $.ajax({
        url: "message"
    }).done(function(message) {
        if (message["message"] != null) {
            $("#messages").html(message["message"]);
        }
    });
}

function getBaseMessage() {
    $.ajax({
        url: "baseMessage"
    }).done(function(baseMessage) {
        if (!null) {
            $("#messages").html(baseMessage);
        }
    });
}

function addZerobefore(number) {
    if(parseInt(number) < 10 && parseInt(number) > -10) {
        number = "0" + parseInt(number);
    }
    return number;
}
<|endoftext|>


<commit_before>/**
* Scavenger hunts plugin. Only works in a room with the id 'scavengers'.
* This game shows a hint. Once a player submits the correct answer, they move on to the next hint.
* You finish upon correctly answering the third hint.
* In an official hunt, the first three to finish within 60 seconds achieve blitz.
*/

'use strict';

let scavengers = {
	status: 'off',
	blitz: null,
	hints: null,
	answers: null,
	participants: {},
	finished: [],
	result: null,
};

let scavengersRoom = Rooms.get('scavengers');
if (scavengersRoom) {
	if (scavengersRoom.plugin) {
		scavengers = scavengersRoom.plugin;
	} else {
		scavengersRoom.plugin = scavengers;
	}
}

exports.commands = {
	scavenger: 'scavengers',
	scavengers: function (target, room, user) {
		return this.parse('/join scavengers');
	},
	startofficialhunt: 'starthunt',
	starthunt: function (target, room, user, connection, cmd) {
		if (room.id !== 'scavengers') return this.errorReply('This command can only be used in the Scavengers room.');
		if (!this.can('mute', null, room)) return false;
		if (scavengers.status === 'on') return this.errorReply('There is already an active scavenger hunt.');
		let targets = target.split(target.includes('|') ? '|' : ',');
		if (!targets[0] || !targets[1] || !targets[2] || !targets[3] || !targets[4] || !targets[5] || targets[6]) {
			return this.errorReply('You must specify three hints and three answers.');
		}
		if (cmd === 'startofficialhunt') {
			scavengers.blitz = setTimeout(() => {
				scavengers.blitz = null;
			}, 60000);
		}
		scavengers.status = 'on';
		scavengers.hints = [targets[0].trim(), targets[2].trim(), targets[4].trim()];
		scavengers.answers = [toId(targets[1]), toId(targets[3]), toId(targets[5])];
		scavengers.startTime = Date.now();
		let result = (cmd === 'startofficialhunt' ? 'An official' : 'A new') + ' Scavenger Hunt has been started by  ' + Chat.escapeHTML(user.name) + '! The first hint is: ' + Chat.escapeHTML(scavengers.hints[0]);
		Rooms('scavengers').addRaw('
' + result + '
');
	},
	joinhunt: function (target, room, user) {
		if (room.id !== 'scavengers') return this.errorReply('This command can only be used in the Scavengers room.');
		if (scavengers.status !== 'on') return this.errorReply('There is no active scavenger hunt.');
		if (user.userid in scavengers.participants) return this.errorReply('You are already participating in the current scavenger hunt.');
		scavengers.participants[user.userid] = {room: 0};
		this.sendReply('You joined the scavenger hunt! Use the command /scavenge to answer. The first hint is: ' + scavengers.hints[0]);
	},
	scavenge: function (target, room, user) {
		if (room.id !== 'scavengers') return this.errorReply('This command can only be used in the Scavengers room.');
		if (scavengers.status !== 'on') return this.errorReply('There is no active scavenger hunt.');
		if (!scavengers.participants[user.userid]) return this.errorReply('You are not participating in the current scavenger hunt. Use the command /joinhunt to participate.');
		if (scavengers.participants[user.userid].room >= 3) return this.sendReply('You have already finished!');
		target = toId(target);
		let roomnum = scavengers.participants[user.userid].room;
		if (scavengers.answers[roomnum] === target) {
			scavengers.participants[user.userid].room++;
			roomnum++;
			if (roomnum < 3) {
				this.sendReply('Well done! Your ' + (roomnum === 1 ? 'second' : 'final') + ' hint is: ' + scavengers.hints[roomnum]);
			} else {
				scavengers.finished.push(user.name);
				let position = scavengers.finished.length;
				let result = '' + Chat.escapeHTML(user.name) + ' has finished the hunt ';
				result += (position === 1) ? 'and is the winner!' : (position === 2) ? 'in 2nd place!' : (position === 3) ? 'in 3rd place!' : 'in ' + position + 'th place!';
				result += (position < 4 && scavengers.blitz ? ' [BLITZ]' : '');
				result += ' (' + Chat.toDurationString(Date.now() - scavengers.startTime, {hhmmss: true}) + ')';
				Rooms('scavengers').addRaw('
' + result + '
');
			}
		} else {
			this.sendReply('That is not the answer - try again!');
		}
	},
	scavengerhint: 'scavengerstatus',
	scavengerstatus: function (target, room, user, connection, cmd) {
		if (room.id !== 'scavengers') return this.errorReply('This command can only be used in the Scavengers room.');
		if (scavengers.status !== 'on') return this.errorReply('There is no active scavenger hunt.');
		if (!scavengers.participants[user.userid]) {
			if (!this.can('mute', null, room) || cmd !== 'scavengerstatus') return this.errorReply('You are not participating in the current scavenger hunt. Use the command /joinhunt to participate.');
			let uptime = (Date.now() - scavengers.startTime) / 1000;
			let uptimeText;
			if (uptime > 24 * 60 * 60) {
				let uptimeDays = Math.floor(uptime / (24 * 60 * 60));
				uptimeText = uptimeDays + " " + (uptimeDays === 1 ? "day" : "days");
				let uptimeHours = Math.floor(uptime / (60 * 60)) - uptimeDays * 24;
				if (uptimeHours) uptimeText += ", " + uptimeHours + " " + (uptimeHours === 1 ? "hour" : "hours");
			} else {
				uptimeText = Chat.toDurationString(uptime * 1000);
			}
			this.sendReply('The current scavenger hunt has been up for: ' + uptimeText);
			if (scavengers.finished.length) {
				this.sendReply('The following users have completed it: ' + scavengers.finished.join(', '));
			} else {
				this.sendReply('No user has completed it.');
			}
			return;
		}
		if (scavengers.participants[user.userid].room >= 3) return this.sendReply('You have finished the current scavenger hunt.');
		let roomnum = scavengers.participants[user.userid].room;
		this.sendReply('You are on hint number ' + (roomnum + 1) + ': ' + scavengers.hints[roomnum]);
	},
	endhunt: function (target, room, user) {
		if (room.id !== 'scavengers') return this.errorReply('This command can only be used in the Scavengers room.');
		if (!this.can('mute', null, room)) return false;
		if (scavengers.status !== 'on') return this.errorReply('There is no active scavenger hunt.');
		let winner = scavengers.finished[0];
		let second = scavengers.finished[1];
		let third = scavengers.finished[2];
		let consolation = scavengers.finished.slice(3).join(', ');
		let msg = 'The Scavenger Hunt was ended by ' + Chat.escapeHTML(user.name) + '. ';
		if (winner) {
			msg += '
Winner: ' + Chat.escapeHTML(winner) + '.';
			if (second) msg += ' Second place: ' + Chat.escapeHTML(second) + '.';
			if (third) msg += ' Third place: ' + Chat.escapeHTML(third) + '.';
			if (consolation) msg += ' Consolation prize to: ' + Chat.escapeHTML(consolation) + '.';
		} else {
			msg += 'No user has completed the hunt.';
		}
		msg += '
Solution: ' + Chat.escapeHTML(scavengers.answers.join(', ')) + '.';
		scavengers.result = msg;
		this.parse('/resethunt');
	},
	resethunt: function (target, room, user) {
		if (room.id !== 'scavengers') return this.errorReply('This command can only be used in the Scavengers room.');
		if (!this.can('mute', null, room)) return false;
		if (scavengers.status !== 'on') return this.errorReply('There is no active scavenger hunt.');
		scavengers.status = 'off';
		if (scavengers.blitz) clearTimeout(scavengers.blitz);
		scavengers.blitz = null;
		scavengers.hints = null;
		scavengers.answers = null;
		scavengers.participants = {};
		scavengers.finished = [];
		if (scavengers.result) {
			Rooms('scavengers').addRaw('
' + scavengers.result + '
');
		} else {
			Rooms('scavengers').addRaw('
The Scavenger Hunt was reset by ' + Chat.escapeHTML(user.name) + '.
');
		}
		scavengers.result = null;
	},
	scavengershelp: 'scavengerhelp',
	scavengerhelp: function (target, room, user) {
		if (room.id !== 'scavengers') return this.errorReply('This command can only be used in the Scavengers room.');
		if (!this.runBroadcast()) return;
		this.sendReplyBox(
			'Player commands:
' +
			'- /scavengers - Join the scavengers room
' +
			'- /joinhunt - Join the current scavenger hunt
' +
			'- /scavenge guess - Attempt to answer the hint
' +
			'- /scavengerstatus - Get your current game status
' +
			'
' +
			'Staff commands:
' +
			'- /starthunt hint, answer, hint, answer, hint, answer - Start a new scavenger hunt (Requires: % @ * # & ~)
' +
			'- /startofficialhunt hint, answer, hint, answer, hint, answer - Start an official hunt with 60 seconds blitz period (Requires: % @ * # & ~)
' +
			'- /endhunt - Finish the current hunt and announce the winners (Requires: % @ * # & ~)
' +
			'- /resethunt - Reset the scavenger hunt to mint status (Requires: % @ * # & ~)'
		);
	},
};
<commit_msg>Change to /scavengerhelp (#3033)<commit_after>/**
* Scavenger hunts plugin. Only works in a room with the id 'scavengers'.
* This game shows a hint. Once a player submits the correct answer, they move on to the next hint.
* You finish upon correctly answering the third hint.
* In an official hunt, the first three to finish within 60 seconds achieve blitz.
*/

'use strict';

let scavengers = {
	status: 'off',
	blitz: null,
	hints: null,
	answers: null,
	participants: {},
	finished: [],
	result: null,
};

let scavengersRoom = Rooms.get('scavengers');
if (scavengersRoom) {
	if (scavengersRoom.plugin) {
		scavengers = scavengersRoom.plugin;
	} else {
		scavengersRoom.plugin = scavengers;
	}
}

exports.commands = {
	scavenger: 'scavengers',
	scavengers: function (target, room, user) {
		return this.parse('/join scavengers');
	},
	startofficialhunt: 'starthunt',
	starthunt: function (target, room, user, connection, cmd) {
		if (room.id !== 'scavengers') return this.errorReply('This command can only be used in the Scavengers room.');
		if (!this.can('mute', null, room)) return false;
		if (scavengers.status === 'on') return this.errorReply('There is already an active scavenger hunt.');
		let targets = target.split(target.includes('|') ? '|' : ',');
		if (!targets[0] || !targets[1] || !targets[2] || !targets[3] || !targets[4] || !targets[5] || targets[6]) {
			return this.errorReply('You must specify three hints and three answers.');
		}
		if (cmd === 'startofficialhunt') {
			scavengers.blitz = setTimeout(() => {
				scavengers.blitz = null;
			}, 60000);
		}
		scavengers.status = 'on';
		scavengers.hints = [targets[0].trim(), targets[2].trim(), targets[4].trim()];
		scavengers.answers = [toId(targets[1]), toId(targets[3]), toId(targets[5])];
		scavengers.startTime = Date.now();
		let result = (cmd === 'startofficialhunt' ? 'An official' : 'A new') + ' Scavenger Hunt has been started by  ' + Chat.escapeHTML(user.name) + '! The first hint is: ' + Chat.escapeHTML(scavengers.hints[0]);
		Rooms('scavengers').addRaw('
' + result + '
');
	},
	joinhunt: function (target, room, user) {
		if (room.id !== 'scavengers') return this.errorReply('This command can only be used in the Scavengers room.');
		if (scavengers.status !== 'on') return this.errorReply('There is no active scavenger hunt.');
		if (user.userid in scavengers.participants) return this.errorReply('You are already participating in the current scavenger hunt.');
		scavengers.participants[user.userid] = {room: 0};
		this.sendReply('You joined the scavenger hunt! Use the command /scavenge to answer. The first hint is: ' + scavengers.hints[0]);
	},
	scavenge: function (target, room, user) {
		if (room.id !== 'scavengers') return this.errorReply('This command can only be used in the Scavengers room.');
		if (scavengers.status !== 'on') return this.errorReply('There is no active scavenger hunt.');
		if (!scavengers.participants[user.userid]) return this.errorReply('You are not participating in the current scavenger hunt. Use the command /joinhunt to participate.');
		if (scavengers.participants[user.userid].room >= 3) return this.sendReply('You have already finished!');
		target = toId(target);
		let roomnum = scavengers.participants[user.userid].room;
		if (scavengers.answers[roomnum] === target) {
			scavengers.participants[user.userid].room++;
			roomnum++;
			if (roomnum < 3) {
				this.sendReply('Well done! Your ' + (roomnum === 1 ? 'second' : 'final') + ' hint is: ' + scavengers.hints[roomnum]);
			} else {
				scavengers.finished.push(user.name);
				let position = scavengers.finished.length;
				let result = '' + Chat.escapeHTML(user.name) + ' has finished the hunt ';
				result += (position === 1) ? 'and is the winner!' : (position === 2) ? 'in 2nd place!' : (position === 3) ? 'in 3rd place!' : 'in ' + position + 'th place!';
				result += (position < 4 && scavengers.blitz ? ' [BLITZ]' : '');
				result += ' (' + Chat.toDurationString(Date.now() - scavengers.startTime, {hhmmss: true}) + ')';
				Rooms('scavengers').addRaw('
' + result + '
');
			}
		} else {
			this.sendReply('That is not the answer - try again!');
		}
	},
	scavengerhint: 'scavengerstatus',
	scavengerstatus: function (target, room, user, connection, cmd) {
		if (room.id !== 'scavengers') return this.errorReply('This command can only be used in the Scavengers room.');
		if (scavengers.status !== 'on') return this.errorReply('There is no active scavenger hunt.');
		if (!scavengers.participants[user.userid]) {
			if (!this.can('mute', null, room) || cmd !== 'scavengerstatus') return this.errorReply('You are not participating in the current scavenger hunt. Use the command /joinhunt to participate.');
			let uptime = (Date.now() - scavengers.startTime) / 1000;
			let uptimeText;
			if (uptime > 24 * 60 * 60) {
				let uptimeDays = Math.floor(uptime / (24 * 60 * 60));
				uptimeText = uptimeDays + " " + (uptimeDays === 1 ? "day" : "days");
				let uptimeHours = Math.floor(uptime / (60 * 60)) - uptimeDays * 24;
				if (uptimeHours) uptimeText += ", " + uptimeHours + " " + (uptimeHours === 1 ? "hour" : "hours");
			} else {
				uptimeText = Chat.toDurationString(uptime * 1000);
			}
			this.sendReply('The current scavenger hunt has been up for: ' + uptimeText);
			if (scavengers.finished.length) {
				this.sendReply('The following users have completed it: ' + scavengers.finished.join(', '));
			} else {
				this.sendReply('No user has completed it.');
			}
			return;
		}
		if (scavengers.participants[user.userid].room >= 3) return this.sendReply('You have finished the current scavenger hunt.');
		let roomnum = scavengers.participants[user.userid].room;
		this.sendReply('You are on hint number ' + (roomnum + 1) + ': ' + scavengers.hints[roomnum]);
	},
	endhunt: function (target, room, user) {
		if (room.id !== 'scavengers') return this.errorReply('This command can only be used in the Scavengers room.');
		if (!this.can('mute', null, room)) return false;
		if (scavengers.status !== 'on') return this.errorReply('There is no active scavenger hunt.');
		let winner = scavengers.finished[0];
		let second = scavengers.finished[1];
		let third = scavengers.finished[2];
		let consolation = scavengers.finished.slice(3).join(', ');
		let msg = 'The Scavenger Hunt was ended by ' + Chat.escapeHTML(user.name) + '. ';
		if (winner) {
			msg += '
Winner: ' + Chat.escapeHTML(winner) + '.';
			if (second) msg += ' Second place: ' + Chat.escapeHTML(second) + '.';
			if (third) msg += ' Third place: ' + Chat.escapeHTML(third) + '.';
			if (consolation) msg += ' Consolation prize to: ' + Chat.escapeHTML(consolation) + '.';
		} else {
			msg += 'No user has completed the hunt.';
		}
		msg += '
Solution: ' + Chat.escapeHTML(scavengers.answers.join(', ')) + '.';
		scavengers.result = msg;
		this.parse('/resethunt');
	},
	resethunt: function (target, room, user) {
		if (room.id !== 'scavengers') return this.errorReply('This command can only be used in the Scavengers room.');
		if (!this.can('mute', null, room)) return false;
		if (scavengers.status !== 'on') return this.errorReply('There is no active scavenger hunt.');
		scavengers.status = 'off';
		if (scavengers.blitz) clearTimeout(scavengers.blitz);
		scavengers.blitz = null;
		scavengers.hints = null;
		scavengers.answers = null;
		scavengers.participants = {};
		scavengers.finished = [];
		if (scavengers.result) {
			Rooms('scavengers').addRaw('
' + scavengers.result + '
');
		} else {
			Rooms('scavengers').addRaw('
The Scavenger Hunt was reset by ' + Chat.escapeHTML(user.name) + '.
');
		}
		scavengers.result = null;
	},
	scavengershelp: 'scavengerhelp',
	scavengerhelp: function (target, room, user) {
		if (room.id !== 'scavengers') return this.errorReply('This command can only be used in the Scavengers room.');
		if (!this.runBroadcast()) return;
		this.sendReplyBox(
			'Player commands:
' +
			'- /scavengers - Join the scavengers room
' +
			'- /joinhunt - Join the current scavenger hunt
' +
			'- /scavenge _______ - Attempt to answer the hint
' +
			'- /scavengerstatus - Get your current game status
' +
			'
' +
			'Staff commands:
' +
			'- /starthunt hint, answer, hint, answer, hint, answer - Start a new scavenger hunt (Requires: % @ * # & ~)
' +
			'- /startofficialhunt hint, answer, hint, answer, hint, answer - Start an official hunt with 60 seconds blitz period (Requires: % @ * # & ~)
' +
			'- /endhunt - Finish the current hunt and announce the winners (Requires: % @ * # & ~)
' +
			'- /resethunt - Reset the scavenger hunt to mint status (Requires: % @ * # & ~)'
		);
	},
};
<|endoftext|>


<commit_before>(function($) {

$.widget('ui.sympalSlot', {

  options : {
    edit_mode : 'popup'
  },

  _init : function()
  {
    if (edit_mode = this.element.metadata().edit_mode)
    {
      this._setData('edit_mode', edit_mode);
    }

    if (slot_type = this.element.metadata().slot_type)
    {
      this._setData('slot_type', slot_type);
    }

    if (view_url = this.element.metadata().view_url)
    {
      this._setData('view_url', view_url);
    }

    this.initialize();
  },

  openEditor : function()
  {
    var self = this;

    // determine the editor object
    if (this._getData('edit_mode') == 'inline')
    {
      var editor = $('.sympal_slot_content', self.element);
    }
    else
    {
      var editor = $('#fancybox-inner');
    }

    // register the ajaxSuccess function on the editor
    editor.bind('ajaxResponseSuccess', function() {
      editor.trigger('block');

      // setup the ajax form submit
      $('form:not(.sympal_ajax_submit)', editor).submit(function() {
        editor.trigger('block');

        // make sure the event doesn't get re-registered
        $(this).addClass('sympal_ajax_submit');

        $(this).ajaxSubmit( {
          error: function(xhr, textStatus, errorThrown)
          {
            editor.trigger('unblock');
            // display some sort of error
          },
          success: function(responseText, statusText, xhr)
          {
            $('.form_body', editor).html(responseText);
            editor.trigger('ajaxResponseSuccess');
            editor.trigger('unblock');
          }
        });

        return false;
      }); // end ajax for submit

      // initialize any slot-specific functionality if it exists
      var formClass = 'sfSympalSlot'+self.element.metadata().type;
      if ($.isFunction(self.element[formClass]))
      {
        self.element[formClass](editor);
      }

      // Keep track of the currently focused editor
      $('input:text, textarea', $(this)).focus(function() {
        currentlyFocusedSympalEditor = $(this);
      });

      // hook up the cancel button
      $('form input.cancel', this).click(function() {
        editor.trigger('close');

        return false;
      });

      editor.trigger('unblock');
    }); // end ajaxResponseSuccess

    // bind the block and unblocks
    editor.bind('block', function() {
      // inline, we've gotta block the whole page
      if ($(this).css('display') == 'block')
      {
        // you actually want to block the parent, #facebox-wrapper
        $(this).parent().block();
      }
      else
      {
        $.blockUI();
      }
    });
    editor.bind('unblock', function() {
      if ($(this).css('display') == 'block')
      {
        $(this).parent().unblock();
      }
      else
      {
        $.unblockUI();
      }
    });

    // actually ajax in the data and trigger editor.ajaxResponseSuccess
    var href = $('.sympal_slot_button', this.element).attr('href');
    if (this._getData('edit_mode') == 'inline')
    {
      editor.load(href, function() {
        editor.trigger('ajaxResponseSuccess');
      });
    }
    else
    {
      $.fancybox(href, {
        'zoomSpeedIn': 300,
        'zoomSpeedOut': 300,
        'overlayShow': true,
        'height': 440,
        'autoDimensions': false,
        'hideOnContentClick': false,
        'type': 'ajax',
        'onComplete': function() {
          editor.trigger('ajaxResponseSuccess');
        },
        'onCleanup': function() {
          editor.trigger('close')
        },
      });
    }

    editor.bind('close', function() {
      if (editor.attr('id') == 'fancybox-inner')
      {
        $.fancybox.close();
      }
      else
      {
        editor.html('');
      }

      $.blockUI();

      $('.sympal_slot_content', self.element).load(
        self._getData('view_url'),
        function() {
          $.unblockUI();
        }
      );
    });
  },

  closeEditor : function()
  {
    if ($('form', this.element).eq(0).hasClass('popup'))
    {
      // popup closing
      $.fancybox.close();
    }
    else
    {
      // inline closing
      //sympal_toggle_inline_edit_slot(wrapperEle, false);
    }
  },

  initialize: function()
  {
    var self = this;

    // open up the editor
    $('a.sympal_slot_button', this.element).click(function() {
      self.openEditor()

      return false;
    });

    $('.sympal_slot_content', this.element).bind('dblclick', function() {
      self.openEditor()
    });

    // show the edit button when hovering over editable area
    this.element.hover(function() {
      $('.sympal_slot_button:not(.no-hover)', self.element).show();
    }, function() {
      $('.sympal_slot_button:not(.no-hover)', self.element).hide();
    });

    // highlight editable area on edit button hover
    $('a.sympal_slot_button', this.element).hover(function() {
      $('.sympal_slot_content', self.element)
        .css('opacity', .2)
        .children().css('opacity', .2);
    }, function() {
      $('.sympal_slot_content', self.element)
        .css('opacity', 1)
        .children().css('opacity', 1);
    });
  }
});

})(jQuery);

jQuery(document).ready(function(){

  $('.sympal_slot_wrapper').sympalSlot();

  $('.sympal_inline_edit_bar_edit_buttons').show();

  // globally save slots on the "save" edit button
  $('#inline-edit-bar-buttons-menu .sympal_save_content_slots').click(function(){
    $('form.sympal_slot_form').submit();
  });

  // globally hide slot formss on the "cancel" edit button
  $('#inline-edit-bar-buttons-menu .sympal_disable_edit_mode').click(function(){
    $('form.sympal_slot_form input.cancel').click();
  });
});<commit_msg>[1.0][sfEditorPlugin] Got more exact with the non-edit controls for frontend slot editing<commit_after>(function($) {

$.widget('ui.sympalSlot', {

  options : {
    edit_mode : 'popup'
  },

  _init : function()
  {
    if (edit_mode = this.element.metadata().edit_mode)
    {
      this._setData('edit_mode', edit_mode);
    }

    if (slot_type = this.element.metadata().slot_type)
    {
      this._setData('slot_type', slot_type);
    }

    if (view_url = this.element.metadata().view_url)
    {
      this._setData('view_url', view_url);
    }

    this.initialize();
  },

  openEditor : function()
  {
    var self = this;

    // disable the non-edit-mode controls
    this.disableNonEditControls();

    // make sure the edit button is hidden
    $('.sympal_slot_button', this.element).hide();

    // determine the editor object
    if (this._getData('edit_mode') == 'inline')
    {
      var editor = $('.sympal_slot_content', self.element);
    }
    else
    {
      var editor = $('#fancybox-inner');
    }
    this._setData('editor', editor);

    // register the ajaxSuccess function on the editor
    editor.bind('ajaxResponseSuccess', function() {
      editor.trigger('block');

      // setup the ajax form submit
      $('form:not(.sympal_ajax_submit)', editor).submit(function() {
        editor.trigger('block');

        // make sure the event doesn't get re-registered
        $(this).addClass('sympal_ajax_submit');

        $(this).ajaxSubmit( {
          error: function(xhr, textStatus, errorThrown)
          {
            editor.trigger('unblock');
            // display some sort of error
          },
          success: function(responseText, statusText, xhr)
          {
            $('.form_body', editor).html(responseText);
            editor.trigger('ajaxResponseSuccess');
            editor.trigger('unblock');
          }
        });

        return false;
      }); // end ajax for submit

      // initialize any slot-specific functionality if it exists
      var formClass = 'sfSympalSlot'+self.element.metadata().type;
      if ($.isFunction(self.element[formClass]))
      {
        self.element[formClass](editor);
      }

      // Keep track of the currently focused editor
      $('input:text, textarea', $(this)).focus(function() {
        currentlyFocusedSympalEditor = $(this);
      });

      // hook up the cancel button
      $('form input.cancel', this).click(function() {
        editor.trigger('close');

        return false;
      });

      editor.trigger('unblock');
    }); // end ajaxResponseSuccess

    // bind the block and unblocks
    editor.bind('block', function() {
      // inline, we've gotta block the whole page
      if ($(this).css('display') == 'block')
      {
        // you actually want to block the parent, #facebox-wrapper
        $(this).parent().block();
      }
      else
      {
        $.blockUI();
      }
    });
    editor.bind('unblock', function() {
      if ($(this).css('display') == 'block')
      {
        $(this).parent().unblock();
      }
      else
      {
        $.unblockUI();
      }
    });

    // actually ajax in the data and trigger editor.ajaxResponseSuccess
    var href = $('.sympal_slot_button', this.element).attr('href');
    if (this._getData('edit_mode') == 'inline')
    {
      editor.load(href, function() {
        editor.trigger('ajaxResponseSuccess');
      });
    }
    else
    {
      $.fancybox(href, {
        'zoomSpeedIn': 300,
        'zoomSpeedOut': 300,
        'overlayShow': true,
        'height': 440,
        'autoDimensions': false,
        'hideOnContentClick': false,
        'type': 'ajax',
        'onComplete': function() {
          editor.trigger('ajaxResponseSuccess');
        },
        'onCleanup': function() {
          editor.trigger('close')
        },
      });
    }

    editor.bind('close', function() {
      self.closeEditor();
    });
  },

  closeEditor : function()
  {
    self = this;
    var editor = this._getData('editor');

    $.blockUI();

    // ajax in the content, and then set things back up
    $('.sympal_slot_content', self.element).load(
      self._getData('view_url'),
      function() {
        // reinitialize the non-edit-mode controls
        self.enableNonEditControls();

        if (editor.attr('id') == 'fancybox-inner')
        {
          $.fancybox.close();
        }
        else
        {
          // nothing needs to be done inline, the ajax just repalced the content
        }

        $.unblockUI();
      }
    );
  },

  initialize: function()
  {
    var self = this;

    // register non-edit-handlers: effects for when the slot is not being edited
    nonEditHandlers = {};

    // enable editing on double-click
    nonEditHandlers['dblclick'] = function()
    {
      self.openEditor()
    }
    nonEditHandlers['mouseover'] = function()
    {
      $('.sympal_slot_button', self.element).show();
    }
    nonEditHandlers['mouseout'] = function()
    {
      $('.sympal_slot_button', self.element).hide();
    }
    this._setData('nonEditHandlers', nonEditHandlers);

    // attach the nonEditHandler events
    this.enableNonEditControls();

    // enable editing if the slot button is clicked
    $('a.sympal_slot_button', this.element).click(function() {
      self.openEditor()
      return false;
    });

    // highlight editable area on edit button hover
    $('a.sympal_slot_button', this.element).hover(function() {
      $('.sympal_slot_content', self.element)
        .css('opacity', .2)
        .children().css('opacity', .2);
    }, function() {
      $('.sympal_slot_content', self.element)
        .css('opacity', 1)
        .children().css('opacity', 1);
    });
  },

  enableNonEditControls : function()
  {
    self = this;

    // bind all of the non-edit-mode handlers
    $.each(this._getData('nonEditHandlers'), function(key, value) {
      self.element.bind(key, value);
    });
  },

  disableNonEditControls : function()
  {
    self = this;

    // disable all of the non-edit-mode handlers
    $.each(this._getData('nonEditHandlers'), function(key, value) {
      self.element.unbind(key, value);
    });
  }

});

})(jQuery);

jQuery(document).ready(function(){

  $('.sympal_slot_wrapper').sympalSlot();

  $('.sympal_inline_edit_bar_edit_buttons').show();

  // globally save slots on the "save" edit button
  $('#inline-edit-bar-buttons-menu .sympal_save_content_slots').click(function(){
    $('form.sympal_slot_form').submit();
  });

  // globally hide slot forms on the "cancel" edit button
  $('#inline-edit-bar-buttons-menu .sympal_disable_edit_mode').click(function(){
    $('form.sympal_slot_form input.cancel').click();
  });
});<|endoftext|>


<commit_before>define( [ "ember" ], function( Ember ) {

	var	get = Ember.get,
		set = Ember.set;

	var	CSSMediaRule		= window.CSSMediaRule,
		CSSStyleRule		= window.CSSStyleRule,
		reMinWidth			= /^(?:\(max-width:\s*\d+px\)\s*and\s*)?\(min-width:\s*(\d+)px\)$/,
		cachedMinWidths		= {},
		cssMinWidthRules	= [].filter.call( document.styleSheets[0].rules, function( rule ) {
			return	rule instanceof CSSMediaRule
				&&	rule.media.length === 1
				&&	reMinWidth.test( rule.media[0] )
				&&	rule.cssRules.length > 0;
		}),
		cachedMinHeights	= [].filter.call( document.styleSheets[0].rules, function( rule ) {
			return	rule instanceof CSSStyleRule
				&&	rule.style.minHeight !== "";
		}).reduce(function( cache, rule ) {
			cache[ rule.selectorText ] = parseInt( rule.style.minHeight );
			return cache;
		}, {} );

	/**
	 * Generate a list of all min-width media queries and their item widths for a specific selector.
	 * These media queries have been defined by the lesscss function .dynamic-elems-per-row()
	 */
	function readMinWidths( selector ) {
		if ( cachedMinWidths.hasOwnProperty( selector ) ) {
			return cachedMinWidths[ selector ];
		}

		var data = cssMinWidthRules
			.filter(function( rule ) {
				return rule.cssRules[0].selectorText === selector;
			})
			.map(function( rule ) {
				return {
					minWidth: Math.floor( reMinWidth.exec( rule.media[0] )[1] ),
					numItems: Math.floor( 100 / parseInt( rule.cssRules[0].style.width ) )
				};
			});

		if ( !data.length ) {
			throw new Error( "Invalid selector" );
		}

		return ( cachedMinWidths[ selector ] = data );
	}

	function readMinHeights( selector ) {
		if ( !cachedMinHeights.hasOwnProperty( selector ) ) {
			throw new Error( "Invalid selector" );
		}
		return cachedMinHeights[ selector ];
	}

	function getNeededColumns( selector ) {
		return readMinWidths( selector ).reduce(function( current, next ) {
			return window.innerWidth < next.minWidth
				? current
				: next;
		}).numItems;
	}

	function getNeededRows( selector ) {
		var minHeight = readMinHeights( selector );
		return 1 + Math.ceil( getItemContainer().clientHeight / minHeight );
	}

	function getItemContainer() {
		// the route's view hasn't been inserted yet: choose the parent element
		return	document.querySelector( "body > .wrapper" )
			||	document.body;
	}

	return Ember.Mixin.create({
		/**
		 * Define the content array location.
		 * Can't use a binding here!!!
		 */
		contentPath: "controller.model",

		/**
		 * Don't fetch infinitely.
		 */
		maxAutoFetches: 3,

		/**
		 * This is actually an ugly concept, but we need to set this data at the route, so we can
		 * control the fetch size before querying the data. The fetch size depends on the
		 * window size and css media queries containing this selector. We can't move this
		 * calculation to the view or to the controller, because they both aren't set up at the
		 * time where the size is being calculated...
		 */
		itemSelector: Ember.required(),

		/**
		 * Calculate how many items are needed to completely fill the container
		 */
		calcFetchSize: function() {
			var	itemSel	= get( this, "itemSelector" ),
				columns	= getNeededColumns( itemSel ),
				rows	= getNeededRows( itemSel ),
				offset	= get( this, "offset" ),
				uneven	= offset % columns,
				limit	= ( columns * rows ) + ( uneven > 0 ? columns - uneven : 0 );

			// fetch size + number of items to fill the last row after a window resize
			set( this, "limit", limit );
		},

		beforeModel: function() {
			this._super.apply( this, arguments );

			// reset on route change
			set( this, "offset", 0 );
			this.calcFetchSize();
		},

		setupController: function( controller ) {
			this._super.apply( this, arguments );

			// late bindings
			var binding = get( this, "_binding_offset" );
			if ( !binding ) {
				binding = Ember.Binding.from(
					"%@.length".fmt( get( this, "contentPath" ) )
				).to( "offset" );
				set( this, "_binding_offset", binding );
			}
			binding.connect( this );

			var	offset	= get( this, "offset" ),
				limit	= get( this, "limit" );

			set( controller, "isFetching", false );
			set( controller, "hasFetchedAll", offset < limit );
		},

		fetchContent: function() {
			return this.model();
		},

		actions: {
			"willTransition": function () {
				var binding = get( this, "_binding_offset" );
				if ( binding ) {
					binding.disconnect( this );
				}
			},

			"willFetchContent": function( force ) {
				var	controller	= get( this, "controller" ),
					isFetching	= get( controller, "isFetching" ),
					fetchedAll	= get( controller, "hasFetchedAll" );

				// we're already busy or finished fetching
				if ( isFetching || fetchedAll ) { return; }

				this.calcFetchSize();

				var	content	= get( this, get( this, "contentPath" ) ),
					offset	= get( this, "offset" ),
					limit	= get( this, "limit" ),
					max		= get( this, "maxAutoFetches" ),
					num		= offset / limit;

				// don't fetch infinitely
				if ( !force && num > max ) { return; }

				set( controller, "fetchError", false );
				set( controller, "isFetching", true );

				// fetch content
				this.fetchContent()
					.then(function( data ) {
						if ( !data || !data.length || data.length < limit ) {
							set( controller, "hasFetchedAll", true );
						}
						if ( data && data.length ) {
							content.pushObjects( data );
						}
						set( controller, "isFetching", false );
					})
					.catch(function( err ) {
						set( controller, "fetchError", true );
						set( controller, "isFetching", false );
						set( controller, "hasFetchedAll", false );
						return Promise.reject( err );
					});
			}
		}
	});

});
<commit_msg>Fix indentation of InfiniteScrollRouteMixin<commit_after>define( [ "ember" ], function( Ember ) {

	var get = Ember.get,
	    set = Ember.set;

	var CSSMediaRule     = window.CSSMediaRule,
	    CSSStyleRule     = window.CSSStyleRule,
	    reMinWidth       = /^(?:\(max-width:\s*\d+px\)\s*and\s*)?\(min-width:\s*(\d+)px\)$/,
	    cachedMinWidths  = {};

	var cssMinWidthRules = [].filter.call( document.styleSheets[0].rules, function( rule ) {
		return rule instanceof CSSMediaRule
		    && rule.media.length === 1
		    && reMinWidth.test( rule.media[0] )
		    && rule.cssRules.length > 0;
	});
	var cachedMinHeights = [].filter.call( document.styleSheets[0].rules, function( rule ) {
		return rule instanceof CSSStyleRule
		    && rule.style.minHeight !== "";
	}).reduce(function( cache, rule ) {
		cache[ rule.selectorText ] = parseInt( rule.style.minHeight );
		return cache;
	}, {} );

	/**
	 * Generate a list of all min-width media queries and their item widths for a specific selector.
	 * These media queries have been defined by the lesscss function .dynamic-elems-per-row()
	 */
	function readMinWidths( selector ) {
		if ( cachedMinWidths.hasOwnProperty( selector ) ) {
			return cachedMinWidths[ selector ];
		}

		var data = cssMinWidthRules.filter(function( rule ) {
			return rule.cssRules[0].selectorText === selector;
		});

		if ( !data.length ) {
			throw new Error( "Invalid selector" );
		}

		data = data.map( function( rule ) {
			return {
				minWidth: Math.floor( reMinWidth.exec( rule.media[0] )[1] ),
				numItems: Math.floor( 100 / parseInt( rule.cssRules[0].style.width ) )
			};
		});

		return ( cachedMinWidths[ selector ] = data );
	}

	function readMinHeights( selector ) {
		if ( !cachedMinHeights.hasOwnProperty( selector ) ) {
			throw new Error( "Invalid selector" );
		}
		return cachedMinHeights[ selector ];
	}

	function getNeededColumns( selector ) {
		return readMinWidths( selector ).reduce(function( current, next ) {
			return window.innerWidth < next.minWidth
				? current
				: next;
		}).numItems;
	}

	function getNeededRows( selector ) {
		var minHeight = readMinHeights( selector );
		return 1 + Math.ceil( getItemContainer().clientHeight / minHeight );
	}

	function getItemContainer() {
		// the route's view hasn't been inserted yet: choose the parent element
		return document.querySelector( "body > .wrapper" )
		    || document.body;
	}

	return Ember.Mixin.create({
		/**
		 * Define the content array location.
		 * Can't use a binding here!!!
		 */
		contentPath: "controller.model",

		/**
		 * Don't fetch infinitely.
		 */
		maxAutoFetches: 3,

		/**
		 * This is actually an ugly concept, but we need to set this data at the route, so we can
		 * control the fetch size before querying the data. The fetch size depends on the
		 * window size and css media queries containing this selector. We can't move this
		 * calculation to the view or to the controller, because they both aren't set up at the
		 * time where the size is being calculated...
		 */
		itemSelector: Ember.required(),

		/**
		 * Calculate how many items are needed to completely fill the container
		 */
		calcFetchSize: function() {
			var itemSel = get( this, "itemSelector" );
			var offset  = get( this, "offset" );
			var columns = getNeededColumns( itemSel );
			var rows    = getNeededRows( itemSel );
			var uneven  = offset % columns;
			var limit   = ( columns * rows ) + ( uneven > 0 ? columns - uneven : 0 );

			// fetch size + number of items to fill the last row after a window resize
			set( this, "limit", limit );
		},

		beforeModel: function() {
			this._super.apply( this, arguments );

			// reset on route change
			set( this, "offset", 0 );
			this.calcFetchSize();
		},

		setupController: function( controller ) {
			this._super.apply( this, arguments );

			// late bindings
			var binding = get( this, "_binding_offset" );
			if ( !binding ) {
				binding = Ember.Binding.from(
					"%@.length".fmt( get( this, "contentPath" ) )
				).to( "offset" );
				set( this, "_binding_offset", binding );
			}
			binding.connect( this );

			var offset = get( this, "offset" );
			var limit  = get( this, "limit" );

			set( controller, "isFetching", false );
			set( controller, "hasFetchedAll", offset < limit );
		},

		fetchContent: function() {
			return this.model();
		},

		actions: {
			"willTransition": function () {
				var binding = get( this, "_binding_offset" );
				if ( binding ) {
					binding.disconnect( this );
				}
			},

			"willFetchContent": function( force ) {
				var controller = get( this, "controller" );
				var isFetching = get( controller, "isFetching" );
				var fetchedAll = get( controller, "hasFetchedAll" );

				// we're already busy or finished fetching
				if ( isFetching || fetchedAll ) { return; }

				this.calcFetchSize();

				var content = get( this, get( this, "contentPath" ) );
				var offset  = get( this, "offset" );
				var limit   = get( this, "limit" );
				var max     = get( this, "maxAutoFetches" );
				var num     = offset / limit;

				// don't fetch infinitely
				if ( !force && num > max ) { return; }

				set( controller, "fetchError", false );
				set( controller, "isFetching", true );

				// fetch content
				this.fetchContent()
					.then(function( data ) {
						if ( !data || !data.length || data.length < limit ) {
							set( controller, "hasFetchedAll", true );
						}
						if ( data && data.length ) {
							content.pushObjects( data );
						}
						set( controller, "isFetching", false );
					})
					.catch(function( err ) {
						set( controller, "fetchError", true );
						set( controller, "isFetching", false );
						set( controller, "hasFetchedAll", false );
						return Promise.reject( err );
					});
			}
		}
	});

});
<|endoftext|>